diff --git a/.gitignore b/.gitignore index 42fa0d5626a956..f4c0b091dcf4e6 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,6 @@ *.lst *.symtypes *.order -modules.builtin *.elf *.bin *.gz @@ -33,6 +32,8 @@ modules.builtin *.lzo *.patch *.gcno +modules.builtin +Module.symvers # # Top-level generic files @@ -44,7 +45,6 @@ modules.builtin /vmlinuz /System.map /Module.markers -/Module.symvers # # Debian directory (make deb-pkg) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 6e02c5029152ea..a9757dcf2e813a 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -114,14 +114,17 @@ What: /sys/bus/iio/devices/iio:deviceX/in_temp_raw What: /sys/bus/iio/devices/iio:deviceX/in_tempX_raw What: /sys/bus/iio/devices/iio:deviceX/in_temp_x_raw What: /sys/bus/iio/devices/iio:deviceX/in_temp_y_raw -What: /sys/bus/iio/devices/iio:deviceX/in_temp_z_raw +What: /sys/bus/iio/devices/iio:deviceX/in_temp_ambient_raw +What: /sys/bus/iio/devices/iio:deviceX/in_temp_object_raw KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: Raw (unscaled no bias removal etc.) temperature measurement. If an axis is specified it generally means that the temperature sensor is associated with one part of a compound device (e.g. - a gyroscope axis). Units after application of scale and offset + a gyroscope axis). The ambient and object modifiers distinguish + between ambient (reference) and distant temperature for contact- + less measurements. Units after application of scale and offset are milli degrees Celsius. What: /sys/bus/iio/devices/iio:deviceX/in_tempX_input @@ -210,6 +213,14 @@ Contact: linux-iio@vger.kernel.org Description: Scaled humidity measurement in milli percent. +What: /sys/bus/iio/devices/iio:deviceX/in_X_mean_raw +KernelVersion: 3.5 +Contact: linux-iio@vger.kernel.org +Description: + Averaged raw measurement from channel X. The number of values + used for averaging is device specific. The converting rules for + normal raw values also applies to the averaged raw values. + What: /sys/bus/iio/devices/iio:deviceX/in_accel_offset What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_offset What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset @@ -784,6 +795,7 @@ What: /sys/.../iio:deviceX/scan_elements/in_incli_x_en What: /sys/.../iio:deviceX/scan_elements/in_incli_y_en What: /sys/.../iio:deviceX/scan_elements/in_pressureY_en What: /sys/.../iio:deviceX/scan_elements/in_pressure_en +What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_en KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -799,6 +811,7 @@ What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_type What: /sys/.../iio:deviceX/scan_elements/in_timestamp_type What: /sys/.../iio:deviceX/scan_elements/in_pressureY_type What: /sys/.../iio:deviceX/scan_elements/in_pressure_type +What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_type KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -845,6 +858,7 @@ What: /sys/.../iio:deviceX/scan_elements/in_incli_y_index What: /sys/.../iio:deviceX/scan_elements/in_timestamp_index What: /sys/.../iio:deviceX/scan_elements/in_pressureY_index What: /sys/.../iio:deviceX/scan_elements/in_pressure_index +What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_index KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -881,6 +895,25 @@ Description: on-chip EEPROM. After power-up or chip reset the device will automatically load the saved configuration. +What: /sys/.../iio:deviceX/in_illuminanceY_input +What: /sys/.../iio:deviceX/in_illuminanceY_raw +What: /sys/.../iio:deviceX/in_illuminanceY_mean_raw +KernelVersion: 3.4 +Contact: linux-iio@vger.kernel.org +Description: + Illuminance measurement, units after application of scale + and offset are lux. + +What: /sys/.../iio:deviceX/in_intensityY_raw +What: /sys/.../iio:deviceX/in_intensityY_ir_raw +What: /sys/.../iio:deviceX/in_intensityY_both_raw +KernelVersion: 3.4 +Contact: linux-iio@vger.kernel.org +Description: + Unit-less light intensity. Modifiers both and ir indicate + that measurements contains visible and infrared light + components or just infrared light, respectively. + What: /sys/.../iio:deviceX/in_intensity_red_integration_time What: /sys/.../iio:deviceX/in_intensity_green_integration_time What: /sys/.../iio:deviceX/in_intensity_blue_integration_time @@ -891,3 +924,12 @@ Contact: linux-iio@vger.kernel.org Description: This attribute is used to get/set the integration time in seconds. + +What: /sys/bus/iio/devices/iio:deviceX/in_rot_quaternion_raw +KernelVersion: 3.15 +Contact: linux-iio@vger.kernel.org +Description: + Raw value of quaternion components using a format + x y z w. Here x, y, and z component represents the axis about + which a rotation will occur and w component represents the + amount of rotation. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 new file mode 100644 index 00000000000000..6708c5e264aa81 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 @@ -0,0 +1,16 @@ +What /sys/bus/iio/devices/iio:deviceX/in_proximity_raw +Date: March 2014 +KernelVersion: 3.15 +Contact: Matt Ranostay +Description: + Get the current distance in meters of storm (1km steps) + 1000-40000 = distance in meters + +What /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity +Date: March 2014 +KernelVersion: 3.15 +Contact: Matt Ranostay +Description: + Show or set the gain boost of the amp, from 0-31 range. + 18 = indoors (default) + 14 = outdoors diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index a3c5a668503610..ab8d76dfaa8096 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -117,7 +117,7 @@ Description: What: /sys/bus/pci/devices/.../vpd Date: February 2008 -Contact: Ben Hutchings +Contact: Ben Hutchings Description: A file named vpd in a device directory will be a binary file containing the Vital Product Data for the diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index d5a0d33c571f33..acb9bfc89b4879 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -128,7 +128,7 @@ Description: Discover cpuidle policy and mechanism What: /sys/devices/system/cpu/cpu#/cpufreq/* Date: pre-git history -Contact: cpufreq@vger.kernel.org +Contact: linux-pm@vger.kernel.org Description: Discover and change clock speed of CPUs Clock scaling allows you to change the clock speed of the @@ -146,7 +146,7 @@ Description: Discover and change clock speed of CPUs What: /sys/devices/system/cpu/cpu#/cpufreq/freqdomain_cpus Date: June 2013 -Contact: cpufreq@vger.kernel.org +Contact: linux-pm@vger.kernel.org Description: Discover CPUs in the same CPU frequency coordination domain freqdomain_cpus is the list of CPUs (online+offline) that share diff --git a/Documentation/ABI/testing/sysfs-driver-hid-thingm b/Documentation/ABI/testing/sysfs-driver-hid-thingm deleted file mode 100644 index abcffeedd20a36..00000000000000 --- a/Documentation/ABI/testing/sysfs-driver-hid-thingm +++ /dev/null @@ -1,23 +0,0 @@ -What: /sys/class/leds/blink1::/rgb -Date: January 2013 -Contact: Vivien Didelot -Description: The ThingM blink1 is an USB RGB LED. The color notation is - 3-byte hexadecimal. Read this attribute to get the last set - color. Write the 24-bit hexadecimal color to change the current - LED color. The default color is full white (0xFFFFFF). - For instance, set the color to green with: echo 00FF00 > rgb - -What: /sys/class/leds/blink1::/fade -Date: January 2013 -Contact: Vivien Didelot -Description: This attribute allows to set a fade time in milliseconds for - the next color change. Read the attribute to know the current - fade time. The default value is set to 0 (no fade time). For - instance, set a fade time of 2 seconds with: echo 2000 > fade - -What: /sys/class/leds/blink1::/play -Date: January 2013 -Contact: Vivien Didelot -Description: This attribute is used to play/pause the light patterns. Write 1 - to start playing, 0 to stop. Reading this attribute returns the - current playing status. diff --git a/Documentation/ABI/testing/sysfs-platform-chipidea-usb-otg b/Documentation/ABI/testing/sysfs-platform-chipidea-usb-otg new file mode 100644 index 00000000000000..151c59578db471 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-chipidea-usb-otg @@ -0,0 +1,56 @@ +What: /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req +Date: Feb 2014 +Contact: Li Jun +Description: + Can be set and read. + Set a_bus_req(A-device bus request) input to be 1 if + the application running on the A-device wants to use the bus, + and to be 0 when the application no longer wants to use + the bus(or wants to work as peripheral). a_bus_req can also + be set to 1 by kernel in response to remote wakeup signaling + from the B-device, the A-device should decide to resume the bus. + + Valid values are "1" and "0". + + Reading: returns 1 if the application running on the A-device + is using the bus as host role, otherwise 0. + +What: /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop +Date: Feb 2014 +Contact: Li Jun +Description: + Can be set and read + The a_bus_drop(A-device bus drop) input is 1 when the + application running on the A-device wants to power down + the bus, and is 0 otherwise, When a_bus_drop is 1, then + the a_bus_req shall be 0. + + Valid values are "1" and "0". + + Reading: returns 1 if the bus is off(vbus is turned off) by + A-device, otherwise 0. + +What: /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req +Date: Feb 2014 +Contact: Li Jun +Description: + Can be set and read. + The b_bus_req(B-device bus request) input is 1 during the time + that the application running on the B-device wants to use the + bus as host, and is 0 when the application no longer wants to + work as host and decides to switch back to be peripheral. + + Valid values are "1" and "0". + + Reading: returns if the application running on the B device + is using the bus as host role, otherwise 0. + +What: /sys/bus/platform/devices/ci_hdrc.0/inputs/a_clr_err +Date: Feb 2014 +Contact: Li Jun +Description: + Only can be set. + The a_clr_err(A-device Vbus error clear) input is used to clear + vbus error, then A-device will power down the bus. + + Valid value is "1" diff --git a/Documentation/DMA-attributes.txt b/Documentation/DMA-attributes.txt index cc2450d80310a5..18dc52c4f2a0b1 100644 --- a/Documentation/DMA-attributes.txt +++ b/Documentation/DMA-attributes.txt @@ -98,5 +98,5 @@ DMA_ATTR_FORCE_CONTIGUOUS By default DMA-mapping subsystem is allowed to assemble the buffer allocated by dma_alloc_attrs() function from individual pages if it can be mapped as contiguous chunk into device dma address space. By -specifing this attribute the allocated buffer is forced to be contiguous +specifying this attribute the allocated buffer is forced to be contiguous also in physical memory. diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index 044b76436e8373..d9b9416c989fd8 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl @@ -100,6 +100,7 @@ !Finclude/net/cfg80211.h wdev_priv !Finclude/net/cfg80211.h ieee80211_iface_limit !Finclude/net/cfg80211.h ieee80211_iface_combination +!Finclude/net/cfg80211.h cfg80211_check_combinations Actions and configuration diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 677a02553ec0cd..f4028c3a28a2dc 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -79,7 +79,7 @@ This first part of the DRM Developer's Guide documents core DRM code, - helper libraries for writting drivers and generic userspace interfaces + helper libraries for writing drivers and generic userspace interfaces exposed by DRM drivers. @@ -341,14 +341,6 @@ char *date; Managed IRQ Registration - - Both the drm_irq_install and - drm_irq_uninstall functions get the device IRQ by - calling drm_dev_to_irq. This inline function will - call a bus-specific operation to retrieve the IRQ number. For platform - devices, platform_get_irq(..., 0) is used to - retrieve the IRQ number. - drm_irq_install starts by calling the irq_preinstall driver operation. The operation @@ -356,7 +348,7 @@ char *date; clearing all pending interrupt flags or disabling the interrupt. - The IRQ will then be requested by a call to + The passed-in IRQ will then be requested by a call to request_irq. If the DRIVER_IRQ_SHARED driver feature flag is set, a shared (IRQF_SHARED) IRQ handler will be requested. @@ -459,7 +451,7 @@ char *date; providing a solution to every graphics memory-related problems, GEM identified common code between drivers and created a support library to share it. GEM has simpler initialization and execution requirements than - TTM, but has no video RAM management capabitilies and is thus limited to + TTM, but has no video RAM management capabilities and is thus limited to UMA devices. @@ -889,7 +881,7 @@ int (*prime_fd_to_handle)(struct drm_device *dev, vice versa. Drivers must use the kernel dma-buf buffer sharing framework to manage the PRIME file descriptors. Similar to the mode setting API PRIME is agnostic to the underlying buffer object manager, as - long as handles are 32bit unsinged integers. + long as handles are 32bit unsigned integers. While non-GEM drivers must implement the operations themselves, GEM @@ -2356,7 +2348,7 @@ void intel_crt_init(struct drm_device *dev) first create properties and then create and associate individual instances of those properties to objects. A property can be instantiated multiple times and associated with different objects. Values are stored in property - instances, and all other property information are stored in the propery + instances, and all other property information are stored in the property and shared between all instances of the property. @@ -2697,10 +2689,10 @@ int num_ioctls; Legacy Support Code - The section very brievely covers some of the old legacy support code which + The section very briefly covers some of the old legacy support code which is only used by old DRM drivers which have done a so-called shadow-attach to the underlying device instead of registering as a real driver. This - also includes some of the old generic buffer mangement and command + also includes some of the old generic buffer management and command submission code. Do not use any of this in new and modern drivers. @@ -2950,6 +2942,11 @@ int num_ioctls; This sections covers all things related to the GEM implementation in the i915 driver. + + Batchbuffer Parsing +!Pdrivers/gpu/drm/i915/i915_cmd_parser.c batch buffer command parser +!Idrivers/gpu/drm/i915/i915_cmd_parser.c + diff --git a/Documentation/RCU/00-INDEX b/Documentation/RCU/00-INDEX index fa57139f50bf77..f773a264ae0291 100644 --- a/Documentation/RCU/00-INDEX +++ b/Documentation/RCU/00-INDEX @@ -12,6 +12,8 @@ lockdep-splat.txt - RCU Lockdep splats explained. NMI-RCU.txt - Using RCU to Protect Dynamic NMI Handlers +rcu_dereference.txt + - Proper care and feeding of return values from rcu_dereference() rcubarrier.txt - RCU and Unloadable Modules rculist_nulls.txt diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt index 9d10d1db16a53f..877947130ebe63 100644 --- a/Documentation/RCU/checklist.txt +++ b/Documentation/RCU/checklist.txt @@ -114,12 +114,16 @@ over a rather long period of time, but improvements are always welcome! http://www.openvms.compaq.com/wizard/wiz_2637.html The rcu_dereference() primitive is also an excellent - documentation aid, letting the person reading the code - know exactly which pointers are protected by RCU. + documentation aid, letting the person reading the + code know exactly which pointers are protected by RCU. Please note that compilers can also reorder code, and they are becoming increasingly aggressive about doing - just that. The rcu_dereference() primitive therefore - also prevents destructive compiler optimizations. + just that. The rcu_dereference() primitive therefore also + prevents destructive compiler optimizations. However, + with a bit of devious creativity, it is possible to + mishandle the return value from rcu_dereference(). + Please see rcu_dereference.txt in this directory for + more information. The rcu_dereference() primitive is used by the various "_rcu()" list-traversal primitives, such diff --git a/Documentation/RCU/rcu_dereference.txt b/Documentation/RCU/rcu_dereference.txt new file mode 100644 index 00000000000000..ceb05da5a5acd3 --- /dev/null +++ b/Documentation/RCU/rcu_dereference.txt @@ -0,0 +1,371 @@ +PROPER CARE AND FEEDING OF RETURN VALUES FROM rcu_dereference() + +Most of the time, you can use values from rcu_dereference() or one of +the similar primitives without worries. Dereferencing (prefix "*"), +field selection ("->"), assignment ("="), address-of ("&"), addition and +subtraction of constants, and casts all work quite naturally and safely. + +It is nevertheless possible to get into trouble with other operations. +Follow these rules to keep your RCU code working properly: + +o You must use one of the rcu_dereference() family of primitives + to load an RCU-protected pointer, otherwise CONFIG_PROVE_RCU + will complain. Worse yet, your code can see random memory-corruption + bugs due to games that compilers and DEC Alpha can play. + Without one of the rcu_dereference() primitives, compilers + can reload the value, and won't your code have fun with two + different values for a single pointer! Without rcu_dereference(), + DEC Alpha can load a pointer, dereference that pointer, and + return data preceding initialization that preceded the store of + the pointer. + + In addition, the volatile cast in rcu_dereference() prevents the + compiler from deducing the resulting pointer value. Please see + the section entitled "EXAMPLE WHERE THE COMPILER KNOWS TOO MUCH" + for an example where the compiler can in fact deduce the exact + value of the pointer, and thus cause misordering. + +o Do not use single-element RCU-protected arrays. The compiler + is within its right to assume that the value of an index into + such an array must necessarily evaluate to zero. The compiler + could then substitute the constant zero for the computation, so + that the array index no longer depended on the value returned + by rcu_dereference(). If the array index no longer depends + on rcu_dereference(), then both the compiler and the CPU + are within their rights to order the array access before the + rcu_dereference(), which can cause the array access to return + garbage. + +o Avoid cancellation when using the "+" and "-" infix arithmetic + operators. For example, for a given variable "x", avoid + "(x-x)". There are similar arithmetic pitfalls from other + arithmetic operatiors, such as "(x*0)", "(x/(x+1))" or "(x%1)". + The compiler is within its rights to substitute zero for all of + these expressions, so that subsequent accesses no longer depend + on the rcu_dereference(), again possibly resulting in bugs due + to misordering. + + Of course, if "p" is a pointer from rcu_dereference(), and "a" + and "b" are integers that happen to be equal, the expression + "p+a-b" is safe because its value still necessarily depends on + the rcu_dereference(), thus maintaining proper ordering. + +o Avoid all-zero operands to the bitwise "&" operator, and + similarly avoid all-ones operands to the bitwise "|" operator. + If the compiler is able to deduce the value of such operands, + it is within its rights to substitute the corresponding constant + for the bitwise operation. Once again, this causes subsequent + accesses to no longer depend on the rcu_dereference(), causing + bugs due to misordering. + + Please note that single-bit operands to bitwise "&" can also + be dangerous. At this point, the compiler knows that the + resulting value can only take on one of two possible values. + Therefore, a very small amount of additional information will + allow the compiler to deduce the exact value, which again can + result in misordering. + +o If you are using RCU to protect JITed functions, so that the + "()" function-invocation operator is applied to a value obtained + (directly or indirectly) from rcu_dereference(), you may need to + interact directly with the hardware to flush instruction caches. + This issue arises on some systems when a newly JITed function is + using the same memory that was used by an earlier JITed function. + +o Do not use the results from the boolean "&&" and "||" when + dereferencing. For example, the following (rather improbable) + code is buggy: + + int a[2]; + int index; + int force_zero_index = 1; + + ... + + r1 = rcu_dereference(i1) + r2 = a[r1 && force_zero_index]; /* BUGGY!!! */ + + The reason this is buggy is that "&&" and "||" are often compiled + using branches. While weak-memory machines such as ARM or PowerPC + do order stores after such branches, they can speculate loads, + which can result in misordering bugs. + +o Do not use the results from relational operators ("==", "!=", + ">", ">=", "<", or "<=") when dereferencing. For example, + the following (quite strange) code is buggy: + + int a[2]; + int index; + int flip_index = 0; + + ... + + r1 = rcu_dereference(i1) + r2 = a[r1 != flip_index]; /* BUGGY!!! */ + + As before, the reason this is buggy is that relational operators + are often compiled using branches. And as before, although + weak-memory machines such as ARM or PowerPC do order stores + after such branches, but can speculate loads, which can again + result in misordering bugs. + +o Be very careful about comparing pointers obtained from + rcu_dereference() against non-NULL values. As Linus Torvalds + explained, if the two pointers are equal, the compiler could + substitute the pointer you are comparing against for the pointer + obtained from rcu_dereference(). For example: + + p = rcu_dereference(gp); + if (p == &default_struct) + do_default(p->a); + + Because the compiler now knows that the value of "p" is exactly + the address of the variable "default_struct", it is free to + transform this code into the following: + + p = rcu_dereference(gp); + if (p == &default_struct) + do_default(default_struct.a); + + On ARM and Power hardware, the load from "default_struct.a" + can now be speculated, such that it might happen before the + rcu_dereference(). This could result in bugs due to misordering. + + However, comparisons are OK in the following cases: + + o The comparison was against the NULL pointer. If the + compiler knows that the pointer is NULL, you had better + not be dereferencing it anyway. If the comparison is + non-equal, the compiler is none the wiser. Therefore, + it is safe to compare pointers from rcu_dereference() + against NULL pointers. + + o The pointer is never dereferenced after being compared. + Since there are no subsequent dereferences, the compiler + cannot use anything it learned from the comparison + to reorder the non-existent subsequent dereferences. + This sort of comparison occurs frequently when scanning + RCU-protected circular linked lists. + + o The comparison is against a pointer that references memory + that was initialized "a long time ago." The reason + this is safe is that even if misordering occurs, the + misordering will not affect the accesses that follow + the comparison. So exactly how long ago is "a long + time ago"? Here are some possibilities: + + o Compile time. + + o Boot time. + + o Module-init time for module code. + + o Prior to kthread creation for kthread code. + + o During some prior acquisition of the lock that + we now hold. + + o Before mod_timer() time for a timer handler. + + There are many other possibilities involving the Linux + kernel's wide array of primitives that cause code to + be invoked at a later time. + + o The pointer being compared against also came from + rcu_dereference(). In this case, both pointers depend + on one rcu_dereference() or another, so you get proper + ordering either way. + + That said, this situation can make certain RCU usage + bugs more likely to happen. Which can be a good thing, + at least if they happen during testing. An example + of such an RCU usage bug is shown in the section titled + "EXAMPLE OF AMPLIFIED RCU-USAGE BUG". + + o All of the accesses following the comparison are stores, + so that a control dependency preserves the needed ordering. + That said, it is easy to get control dependencies wrong. + Please see the "CONTROL DEPENDENCIES" section of + Documentation/memory-barriers.txt for more details. + + o The pointers are not equal -and- the compiler does + not have enough information to deduce the value of the + pointer. Note that the volatile cast in rcu_dereference() + will normally prevent the compiler from knowing too much. + +o Disable any value-speculation optimizations that your compiler + might provide, especially if you are making use of feedback-based + optimizations that take data collected from prior runs. Such + value-speculation optimizations reorder operations by design. + + There is one exception to this rule: Value-speculation + optimizations that leverage the branch-prediction hardware are + safe on strongly ordered systems (such as x86), but not on weakly + ordered systems (such as ARM or Power). Choose your compiler + command-line options wisely! + + +EXAMPLE OF AMPLIFIED RCU-USAGE BUG + +Because updaters can run concurrently with RCU readers, RCU readers can +see stale and/or inconsistent values. If RCU readers need fresh or +consistent values, which they sometimes do, they need to take proper +precautions. To see this, consider the following code fragment: + + struct foo { + int a; + int b; + int c; + }; + struct foo *gp1; + struct foo *gp2; + + void updater(void) + { + struct foo *p; + + p = kmalloc(...); + if (p == NULL) + deal_with_it(); + p->a = 42; /* Each field in its own cache line. */ + p->b = 43; + p->c = 44; + rcu_assign_pointer(gp1, p); + p->b = 143; + p->c = 144; + rcu_assign_pointer(gp2, p); + } + + void reader(void) + { + struct foo *p; + struct foo *q; + int r1, r2; + + p = rcu_dereference(gp2); + if (p == NULL) + return; + r1 = p->b; /* Guaranteed to get 143. */ + q = rcu_dereference(gp1); /* Guaranteed non-NULL. */ + if (p == q) { + /* The compiler decides that q->c is same as p->c. */ + r2 = p->c; /* Could get 44 on weakly order system. */ + } + do_something_with(r1, r2); + } + +You might be surprised that the outcome (r1 == 143 && r2 == 44) is possible, +but you should not be. After all, the updater might have been invoked +a second time between the time reader() loaded into "r1" and the time +that it loaded into "r2". The fact that this same result can occur due +to some reordering from the compiler and CPUs is beside the point. + +But suppose that the reader needs a consistent view? + +Then one approach is to use locking, for example, as follows: + + struct foo { + int a; + int b; + int c; + spinlock_t lock; + }; + struct foo *gp1; + struct foo *gp2; + + void updater(void) + { + struct foo *p; + + p = kmalloc(...); + if (p == NULL) + deal_with_it(); + spin_lock(&p->lock); + p->a = 42; /* Each field in its own cache line. */ + p->b = 43; + p->c = 44; + spin_unlock(&p->lock); + rcu_assign_pointer(gp1, p); + spin_lock(&p->lock); + p->b = 143; + p->c = 144; + spin_unlock(&p->lock); + rcu_assign_pointer(gp2, p); + } + + void reader(void) + { + struct foo *p; + struct foo *q; + int r1, r2; + + p = rcu_dereference(gp2); + if (p == NULL) + return; + spin_lock(&p->lock); + r1 = p->b; /* Guaranteed to get 143. */ + q = rcu_dereference(gp1); /* Guaranteed non-NULL. */ + if (p == q) { + /* The compiler decides that q->c is same as p->c. */ + r2 = p->c; /* Locking guarantees r2 == 144. */ + } + spin_unlock(&p->lock); + do_something_with(r1, r2); + } + +As always, use the right tool for the job! + + +EXAMPLE WHERE THE COMPILER KNOWS TOO MUCH + +If a pointer obtained from rcu_dereference() compares not-equal to some +other pointer, the compiler normally has no clue what the value of the +first pointer might be. This lack of knowledge prevents the compiler +from carrying out optimizations that otherwise might destroy the ordering +guarantees that RCU depends on. And the volatile cast in rcu_dereference() +should prevent the compiler from guessing the value. + +But without rcu_dereference(), the compiler knows more than you might +expect. Consider the following code fragment: + + struct foo { + int a; + int b; + }; + static struct foo variable1; + static struct foo variable2; + static struct foo *gp = &variable1; + + void updater(void) + { + initialize_foo(&variable2); + rcu_assign_pointer(gp, &variable2); + /* + * The above is the only store to gp in this translation unit, + * and the address of gp is not exported in any way. + */ + } + + int reader(void) + { + struct foo *p; + + p = gp; + barrier(); + if (p == &variable1) + return p->a; /* Must be variable1.a. */ + else + return p->b; /* Must be variable2.b. */ + } + +Because the compiler can see all stores to "gp", it knows that the only +possible values of "gp" are "variable1" on the one hand and "variable2" +on the other. The comparison in reader() therefore tells the compiler +the exact value of "p" even in the not-equals case. This allows the +compiler to make the return values independent of the load from "gp", +in turn destroying the ordering between this load and the loads of the +return values. This can result in "p->b" returning pre-initialization +garbage values. + +In short, rcu_dereference() is -not- optional when you are going to +dereference the resulting pointer. diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index 6f3a0057548ec0..68fe3ad2701592 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -24,7 +24,7 @@ CONFIG_RCU_CPU_STALL_TIMEOUT timing of the next warning for the current stall. Stall-warning messages may be enabled and disabled completely via - /sys/module/rcutree/parameters/rcu_cpu_stall_suppress. + /sys/module/rcupdate/parameters/rcu_cpu_stall_suppress. CONFIG_RCU_CPU_STALL_VERBOSE diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index 0f0fb7c432c2a3..49b8551a3b68e0 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -326,11 +326,11 @@ used as follows: a. synchronize_rcu() rcu_read_lock() / rcu_read_unlock() call_rcu() rcu_dereference() -b. call_rcu_bh() rcu_read_lock_bh() / rcu_read_unlock_bh() - rcu_dereference_bh() +b. synchronize_rcu_bh() rcu_read_lock_bh() / rcu_read_unlock_bh() + call_rcu_bh() rcu_dereference_bh() c. synchronize_sched() rcu_read_lock_sched() / rcu_read_unlock_sched() - preempt_disable() / preempt_enable() + call_rcu_sched() preempt_disable() / preempt_enable() local_irq_save() / local_irq_restore() hardirq enter / hardirq exit NMI enter / NMI exit @@ -794,10 +794,22 @@ in docbook. Here is the list, by category. RCU list traversal: + list_entry_rcu + list_first_entry_rcu + list_next_rcu list_for_each_entry_rcu + list_for_each_entry_continue_rcu + hlist_first_rcu + hlist_next_rcu + hlist_pprev_rcu hlist_for_each_entry_rcu + hlist_for_each_entry_rcu_bh + hlist_for_each_entry_continue_rcu + hlist_for_each_entry_continue_rcu_bh + hlist_nulls_first_rcu hlist_nulls_for_each_entry_rcu - list_for_each_entry_continue_rcu + hlist_bl_first_rcu + hlist_bl_for_each_entry_rcu RCU pointer/list update: @@ -806,28 +818,38 @@ RCU pointer/list update: list_add_tail_rcu list_del_rcu list_replace_rcu - hlist_del_rcu hlist_add_after_rcu hlist_add_before_rcu hlist_add_head_rcu + hlist_del_rcu + hlist_del_init_rcu hlist_replace_rcu list_splice_init_rcu() + hlist_nulls_del_init_rcu + hlist_nulls_del_rcu + hlist_nulls_add_head_rcu + hlist_bl_add_head_rcu + hlist_bl_del_init_rcu + hlist_bl_del_rcu + hlist_bl_set_first_rcu RCU: Critical sections Grace period Barrier rcu_read_lock synchronize_net rcu_barrier rcu_read_unlock synchronize_rcu rcu_dereference synchronize_rcu_expedited - call_rcu - kfree_rcu - + rcu_read_lock_held call_rcu + rcu_dereference_check kfree_rcu + rcu_dereference_protected bh: Critical sections Grace period Barrier rcu_read_lock_bh call_rcu_bh rcu_barrier_bh rcu_read_unlock_bh synchronize_rcu_bh rcu_dereference_bh synchronize_rcu_bh_expedited - + rcu_dereference_bh_check + rcu_dereference_bh_protected + rcu_read_lock_bh_held sched: Critical sections Grace period Barrier @@ -835,7 +857,12 @@ sched: Critical sections Grace period Barrier rcu_read_unlock_sched call_rcu_sched [preempt_disable] synchronize_sched_expedited [and friends] + rcu_read_lock_sched_notrace + rcu_read_unlock_sched_notrace rcu_dereference_sched + rcu_dereference_sched_check + rcu_dereference_sched_protected + rcu_read_lock_sched_held SRCU: Critical sections Grace period Barrier @@ -843,6 +870,8 @@ SRCU: Critical sections Grace period Barrier srcu_read_lock synchronize_srcu srcu_barrier srcu_read_unlock call_srcu srcu_dereference synchronize_srcu_expedited + srcu_dereference_check + srcu_read_lock_held SRCU: Initialization/cleanup init_srcu_struct @@ -850,9 +879,13 @@ SRCU: Initialization/cleanup All: lockdep-checked RCU-protected pointer access - rcu_dereference_check - rcu_dereference_protected + rcu_access_index rcu_access_pointer + rcu_dereference_index_check + rcu_dereference_raw + rcu_lockdep_assert + rcu_sleep_check + RCU_NONIDLE See the comment headers in the source code (or the docbook generated from them) for more information. diff --git a/Documentation/arm/Marvell/README b/Documentation/arm/Marvell/README index 963ec445e15a3a..2cce5401e323ff 100644 --- a/Documentation/arm/Marvell/README +++ b/Documentation/arm/Marvell/README @@ -234,6 +234,11 @@ Berlin family (Digital Entertainment) Core: Marvell PJ4B (ARMv7), Tauros3 L2CC Homepage: http://www.marvell.com/digital-entertainment/armada-1500/ Product Brief: http://www.marvell.com/digital-entertainment/armada-1500/assets/Marvell-ARMADA-1500-Product-Brief.pdf + 88DE3114, Armada 1500 Pro + Design name: BG2-Q + Core: Quad Core ARM Cortex-A9, PL310 L2CC + Homepage: http://www.marvell.com/digital-entertainment/armada-1500-pro/ + Product Brief: http://www.marvell.com/digital-entertainment/armada-1500-pro/assets/Marvell_ARMADA_1500_PRO-01_product_brief.pdf 88DE???? Design name: BG3 Core: ARM Cortex-A15, CA15 integrated L2CC diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt index 4bfb9ffbdbc1d2..256c5e067fb1e7 100644 --- a/Documentation/arm/memory.txt +++ b/Documentation/arm/memory.txt @@ -41,16 +41,9 @@ fffe8000 fffeffff DTCM mapping area for platforms with fffe0000 fffe7fff ITCM mapping area for platforms with ITCM mounted inside the CPU. -fff00000 fffdffff Fixmap mapping region. Addresses provided +fffc0000 ffdfffff Fixmap mapping region. Addresses provided by fix_to_virt() will be located here. -ffc00000 ffefffff DMA memory mapping region. Memory returned - by the dma_alloc_xxx functions will be - dynamically mapped here. - -ff000000 ffbfffff Reserved for future expansion of DMA - mapping region. - fee00000 feffffff Mapping of PCI I/O space. This is a static mapping within the vmalloc space. diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt index d9ca5be9b471d1..68542fe13b850e 100644 --- a/Documentation/atomic_ops.txt +++ b/Documentation/atomic_ops.txt @@ -285,15 +285,13 @@ If a caller requires memory barrier semantics around an atomic_t operation which does not return a value, a set of interfaces are defined which accomplish this: - void smp_mb__before_atomic_dec(void); - void smp_mb__after_atomic_dec(void); - void smp_mb__before_atomic_inc(void); - void smp_mb__after_atomic_inc(void); + void smp_mb__before_atomic(void); + void smp_mb__after_atomic(void); -For example, smp_mb__before_atomic_dec() can be used like so: +For example, smp_mb__before_atomic() can be used like so: obj->dead = 1; - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_dec(&obj->ref_count); It makes sure that all memory operations preceding the atomic_dec() @@ -302,15 +300,10 @@ operation. In the above example, it guarantees that the assignment of "1" to obj->dead will be globally visible to other cpus before the atomic counter decrement. -Without the explicit smp_mb__before_atomic_dec() call, the +Without the explicit smp_mb__before_atomic() call, the implementation could legally allow the atomic counter update visible to other cpus before the "obj->dead = 1;" assignment. -The other three interfaces listed are used to provide explicit -ordering with respect to memory operations after an atomic_dec() call -(smp_mb__after_atomic_dec()) and around atomic_inc() calls -(smp_mb__{before,after}_atomic_inc()). - A missing memory barrier in the cases where they are required by the atomic_t implementation above can have disastrous results. Here is an example, which follows a pattern occurring frequently in the Linux @@ -487,12 +480,12 @@ Finally there is the basic operation: Which returns a boolean indicating if bit "nr" is set in the bitmask pointed to by "addr". -If explicit memory barriers are required around clear_bit() (which -does not return a value, and thus does not need to provide memory -barrier semantics), two interfaces are provided: +If explicit memory barriers are required around {set,clear}_bit() (which do +not return a value, and thus does not need to provide memory barrier +semantics), two interfaces are provided: - void smp_mb__before_clear_bit(void); - void smp_mb__after_clear_bit(void); + void smp_mb__before_atomic(void); + void smp_mb__after_atomic(void); They are used as follows, and are akin to their atomic_t operation brothers: @@ -500,13 +493,13 @@ brothers: /* All memory operations before this call will * be globally visible before the clear_bit(). */ - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit( ... ); /* The clear_bit() will be visible before all * subsequent memory operations. */ - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); There are two special bitops with lock barrier semantics (acquire/release, same as spinlocks). These operate in the same way as their non-_lock/unlock diff --git a/Documentation/cgroups/unified-hierarchy.txt b/Documentation/cgroups/unified-hierarchy.txt new file mode 100644 index 00000000000000..324b182e600082 --- /dev/null +++ b/Documentation/cgroups/unified-hierarchy.txt @@ -0,0 +1,359 @@ + +Cgroup unified hierarchy + +April, 2014 Tejun Heo + +This document describes the changes made by unified hierarchy and +their rationales. It will eventually be merged into the main cgroup +documentation. + +CONTENTS + +1. Background +2. Basic Operation + 2-1. Mounting + 2-2. cgroup.subtree_control + 2-3. cgroup.controllers +3. Structural Constraints + 3-1. Top-down + 3-2. No internal tasks +4. Other Changes + 4-1. [Un]populated Notification + 4-2. Other Core Changes + 4-3. Per-Controller Changes + 4-3-1. blkio + 4-3-2. cpuset + 4-3-3. memory +5. Planned Changes + 5-1. CAP for resource control + + +1. Background + +cgroup allows an arbitrary number of hierarchies and each hierarchy +can host any number of controllers. While this seems to provide a +high level of flexibility, it isn't quite useful in practice. + +For example, as there is only one instance of each controller, utility +type controllers such as freezer which can be useful in all +hierarchies can only be used in one. The issue is exacerbated by the +fact that controllers can't be moved around once hierarchies are +populated. Another issue is that all controllers bound to a hierarchy +are forced to have exactly the same view of the hierarchy. It isn't +possible to vary the granularity depending on the specific controller. + +In practice, these issues heavily limit which controllers can be put +on the same hierarchy and most configurations resort to putting each +controller on its own hierarchy. Only closely related ones, such as +the cpu and cpuacct controllers, make sense to put on the same +hierarchy. This often means that userland ends up managing multiple +similar hierarchies repeating the same steps on each hierarchy +whenever a hierarchy management operation is necessary. + +Unfortunately, support for multiple hierarchies comes at a steep cost. +Internal implementation in cgroup core proper is dazzlingly +complicated but more importantly the support for multiple hierarchies +restricts how cgroup is used in general and what controllers can do. + +There's no limit on how many hierarchies there may be, which means +that a task's cgroup membership can't be described in finite length. +The key may contain any varying number of entries and is unlimited in +length, which makes it highly awkward to handle and leads to addition +of controllers which exist only to identify membership, which in turn +exacerbates the original problem. + +Also, as a controller can't have any expectation regarding what shape +of hierarchies other controllers would be on, each controller has to +assume that all other controllers are operating on completely +orthogonal hierarchies. This makes it impossible, or at least very +cumbersome, for controllers to cooperate with each other. + +In most use cases, putting controllers on hierarchies which are +completely orthogonal to each other isn't necessary. What usually is +called for is the ability to have differing levels of granularity +depending on the specific controller. In other words, hierarchy may +be collapsed from leaf towards root when viewed from specific +controllers. For example, a given configuration might not care about +how memory is distributed beyond a certain level while still wanting +to control how CPU cycles are distributed. + +Unified hierarchy is the next version of cgroup interface. It aims to +address the aforementioned issues by having more structure while +retaining enough flexibility for most use cases. Various other +general and controller-specific interface issues are also addressed in +the process. + + +2. Basic Operation + +2-1. Mounting + +Currently, unified hierarchy can be mounted with the following mount +command. Note that this is still under development and scheduled to +change soon. + + mount -t cgroup -o __DEVEL__sane_behavior cgroup $MOUNT_POINT + +All controllers which are not bound to other hierarchies are +automatically bound to unified hierarchy and show up at the root of +it. Controllers which are enabled only in the root of unified +hierarchy can be bound to other hierarchies at any time. This allows +mixing unified hierarchy with the traditional multiple hierarchies in +a fully backward compatible way. + + +2-2. cgroup.subtree_control + +All cgroups on unified hierarchy have a "cgroup.subtree_control" file +which governs which controllers are enabled on the children of the +cgroup. Let's assume a hierarchy like the following. + + root - A - B - C + \ D + +root's "cgroup.subtree_control" file determines which controllers are +enabled on A. A's on B. B's on C and D. This coincides with the +fact that controllers on the immediate sub-level are used to +distribute the resources of the parent. In fact, it's natural to +assume that resource control knobs of a child belong to its parent. +Enabling a controller in a "cgroup.subtree_control" file declares that +distribution of the respective resources of the cgroup will be +controlled. Note that this means that controller enable states are +shared among siblings. + +When read, the file contains a space-separated list of currently +enabled controllers. A write to the file should contain a +space-separated list of controllers with '+' or '-' prefixed (without +the quotes). Controllers prefixed with '+' are enabled and '-' +disabled. If a controller is listed multiple times, the last entry +wins. The specific operations are executed atomically - either all +succeed or fail. + + +2-3. cgroup.controllers + +Read-only "cgroup.controllers" file contains a space-separated list of +controllers which can be enabled in the cgroup's +"cgroup.subtree_control" file. + +In the root cgroup, this lists controllers which are not bound to +other hierarchies and the content changes as controllers are bound to +and unbound from other hierarchies. + +In non-root cgroups, the content of this file equals that of the +parent's "cgroup.subtree_control" file as only controllers enabled +from the parent can be used in its children. + + +3. Structural Constraints + +3-1. Top-down + +As it doesn't make sense to nest control of an uncontrolled resource, +all non-root "cgroup.subtree_control" files can only contain +controllers which are enabled in the parent's "cgroup.subtree_control" +file. A controller can be enabled only if the parent has the +controller enabled and a controller can't be disabled if one or more +children have it enabled. + + +3-2. No internal tasks + +One long-standing issue that cgroup faces is the competition between +tasks belonging to the parent cgroup and its children cgroups. This +is inherently nasty as two different types of entities compete and +there is no agreed-upon obvious way to handle it. Different +controllers are doing different things. + +The cpu controller considers tasks and cgroups as equivalents and maps +nice levels to cgroup weights. This works for some cases but falls +flat when children should be allocated specific ratios of CPU cycles +and the number of internal tasks fluctuates - the ratios constantly +change as the number of competing entities fluctuates. There also are +other issues. The mapping from nice level to weight isn't obvious or +universal, and there are various other knobs which simply aren't +available for tasks. + +The blkio controller implicitly creates a hidden leaf node for each +cgroup to host the tasks. The hidden leaf has its own copies of all +the knobs with "leaf_" prefixed. While this allows equivalent control +over internal tasks, it's with serious drawbacks. It always adds an +extra layer of nesting which may not be necessary, makes the interface +messy and significantly complicates the implementation. + +The memory controller currently doesn't have a way to control what +happens between internal tasks and child cgroups and the behavior is +not clearly defined. There have been attempts to add ad-hoc behaviors +and knobs to tailor the behavior to specific workloads. Continuing +this direction will lead to problems which will be extremely difficult +to resolve in the long term. + +Multiple controllers struggle with internal tasks and came up with +different ways to deal with it; unfortunately, all the approaches in +use now are severely flawed and, furthermore, the widely different +behaviors make cgroup as whole highly inconsistent. + +It is clear that this is something which needs to be addressed from +cgroup core proper in a uniform way so that controllers don't need to +worry about it and cgroup as a whole shows a consistent and logical +behavior. To achieve that, unified hierarchy enforces the following +structural constraint: + + Except for the root, only cgroups which don't contain any task may + have controllers enabled in their "cgroup.subtree_control" files. + +Combined with other properties, this guarantees that, when a +controller is looking at the part of the hierarchy which has it +enabled, tasks are always only on the leaves. This rules out +situations where child cgroups compete against internal tasks of the +parent. + +There are two things to note. Firstly, the root cgroup is exempt from +the restriction. Root contains tasks and anonymous resource +consumption which can't be associated with any other cgroup and +requires special treatment from most controllers. How resource +consumption in the root cgroup is governed is up to each controller. + +Secondly, the restriction doesn't take effect if there is no enabled +controller in the cgroup's "cgroup.subtree_control" file. This is +important as otherwise it wouldn't be possible to create children of a +populated cgroup. To control resource distribution of a cgroup, the +cgroup must create children and transfer all its tasks to the children +before enabling controllers in its "cgroup.subtree_control" file. + + +4. Other Changes + +4-1. [Un]populated Notification + +cgroup users often need a way to determine when a cgroup's +subhierarchy becomes empty so that it can be cleaned up. cgroup +currently provides release_agent for it; unfortunately, this mechanism +is riddled with issues. + +- It delivers events by forking and execing a userland binary + specified as the release_agent. This is a long deprecated method of + notification delivery. It's extremely heavy, slow and cumbersome to + integrate with larger infrastructure. + +- There is single monitoring point at the root. There's no way to + delegate management of a subtree. + +- The event isn't recursive. It triggers when a cgroup doesn't have + any tasks or child cgroups. Events for internal nodes trigger only + after all children are removed. This again makes it impossible to + delegate management of a subtree. + +- Events are filtered from the kernel side. A "notify_on_release" + file is used to subscribe to or suppress release events. This is + unnecessarily complicated and probably done this way because event + delivery itself was expensive. + +Unified hierarchy implements an interface file "cgroup.populated" +which can be used to monitor whether the cgroup's subhierarchy has +tasks in it or not. Its value is 0 if there is no task in the cgroup +and its descendants; otherwise, 1. poll and [id]notify events are +triggered when the value changes. + +This is significantly lighter and simpler and trivially allows +delegating management of subhierarchy - subhierarchy monitoring can +block further propagation simply by putting itself or another process +in the subhierarchy and monitor events that it's interested in from +there without interfering with monitoring higher in the tree. + +In unified hierarchy, the release_agent mechanism is no longer +supported and the interface files "release_agent" and +"notify_on_release" do not exist. + + +4-2. Other Core Changes + +- None of the mount options is allowed. + +- remount is disallowed. + +- rename(2) is disallowed. + +- The "tasks" file is removed. Everything should at process + granularity. Use the "cgroup.procs" file instead. + +- The "cgroup.procs" file is not sorted. pids will be unique unless + they got recycled in-between reads. + +- The "cgroup.clone_children" file is removed. + + +4-3. Per-Controller Changes + +4-3-1. blkio + +- blk-throttle becomes properly hierarchical. + + +4-3-2. cpuset + +- Tasks are kept in empty cpusets after hotplug and take on the masks + of the nearest non-empty ancestor, instead of being moved to it. + +- A task can be moved into an empty cpuset, and again it takes on the + masks of the nearest non-empty ancestor. + + +4-3-3. memory + +- use_hierarchy is on by default and the cgroup file for the flag is + not created. + + +5. Planned Changes + +5-1. CAP for resource control + +Unified hierarchy will require one of the capabilities(7), which is +yet to be decided, for all resource control related knobs. Process +organization operations - creation of sub-cgroups and migration of +processes in sub-hierarchies may be delegated by changing the +ownership and/or permissions on the cgroup directory and +"cgroup.procs" interface file; however, all operations which affect +resource control - writes to a "cgroup.subtree_control" file or any +controller-specific knobs - will require an explicit CAP privilege. + +This, in part, is to prevent the cgroup interface from being +inadvertently promoted to programmable API used by non-privileged +binaries. cgroup exposes various aspects of the system in ways which +aren't properly abstracted for direct consumption by regular programs. +This is an administration interface much closer to sysctl knobs than +system calls. Even the basic access model, being filesystem path +based, isn't suitable for direct consumption. There's no way to +access "my cgroup" in a race-free way or make multiple operations +atomic against migration to another cgroup. + +Another aspect is that, for better or for worse, the cgroup interface +goes through far less scrutiny than regular interfaces for +unprivileged userland. The upside is that cgroup is able to expose +useful features which may not be suitable for general consumption in a +reasonable time frame. It provides a relatively short path between +internal details and userland-visible interface. Of course, this +shortcut comes with high risk. We go through what we go through for +general kernel APIs for good reasons. It may end up leaking internal +details in a way which can exert significant pain by locking the +kernel into a contract that can't be maintained in a reasonable +manner. + +Also, due to the specific nature, cgroup and its controllers don't +tend to attract attention from a wide scope of developers. cgroup's +short history is already fraught with severely mis-designed +interfaces, unnecessary commitments to and exposing of internal +details, broken and dangerous implementations of various features. + +Keeping cgroup as an administration interface is both advantageous for +its role and imperative given its nature. Some of the cgroup features +may make sense for unprivileged access. If deemed justified, those +must be further abstracted and implemented as a different interface, +be it a system call or process-private filesystem, and survive through +the scrutiny that any interface for general consumption is required to +go through. + +Requiring CAP is not a complete solution but should serve as a +significant deterrent against spraying cgroup usages in non-privileged +programs. diff --git a/Documentation/cpu-freq/core.txt b/Documentation/cpu-freq/core.txt index 0060d76b445f3e..70933eadc308db 100644 --- a/Documentation/cpu-freq/core.txt +++ b/Documentation/cpu-freq/core.txt @@ -20,6 +20,7 @@ Contents: --------- 1. CPUFreq core and interfaces 2. CPUFreq notifiers +3. CPUFreq Table Generation with Operating Performance Point (OPP) 1. General Information ======================= @@ -92,3 +93,31 @@ values: cpu - number of the affected CPU old - old frequency new - new frequency + +3. CPUFreq Table Generation with Operating Performance Point (OPP) +================================================================== +For details about OPP, see Documentation/power/opp.txt + +dev_pm_opp_init_cpufreq_table - cpufreq framework typically is initialized with + cpufreq_frequency_table_cpuinfo which is provided with the list of + frequencies that are available for operation. This function provides + a ready to use conversion routine to translate the OPP layer's internal + information about the available frequencies into a format readily + providable to cpufreq. + + WARNING: Do not use this function in interrupt context. + + Example: + soc_pm_init() + { + /* Do things */ + r = dev_pm_opp_init_cpufreq_table(dev, &freq_table); + if (!r) + cpufreq_frequency_table_cpuinfo(policy, freq_table); + /* Do other things */ + } + + NOTE: This function is available only if CONFIG_CPU_FREQ is enabled in + addition to CONFIG_PM_OPP. + +dev_pm_opp_free_cpufreq_table - Free up the table allocated by dev_pm_opp_init_cpufreq_table diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt index 48da5fdcb9f11b..b045fe54986a07 100644 --- a/Documentation/cpu-freq/cpu-drivers.txt +++ b/Documentation/cpu-freq/cpu-drivers.txt @@ -228,3 +228,22 @@ is the corresponding frequency table helper for the ->target stage. Just pass the values to this function, and the unsigned int index returns the number of the frequency table entry which contains the frequency the CPU shall be set to. + +The following macros can be used as iterators over cpufreq_frequency_table: + +cpufreq_for_each_entry(pos, table) - iterates over all entries of frequency +table. + +cpufreq-for_each_valid_entry(pos, table) - iterates over all entries, +excluding CPUFREQ_ENTRY_INVALID frequencies. +Use arguments "pos" - a cpufreq_frequency_table * as a loop cursor and +"table" - the cpufreq_frequency_table * you want to iterate over. + +For example: + + struct cpufreq_frequency_table *pos, *driver_freq_table; + + cpufreq_for_each_entry(pos, driver_freq_table) { + /* Do something with pos */ + pos->frequency = ... + } diff --git a/Documentation/cpu-freq/index.txt b/Documentation/cpu-freq/index.txt index 3d0b915035b9f2..dc024ab4054fc9 100644 --- a/Documentation/cpu-freq/index.txt +++ b/Documentation/cpu-freq/index.txt @@ -35,8 +35,8 @@ Mailing List ------------ There is a CPU frequency changing CVS commit and general list where you can report bugs, problems or submit patches. To post a message, -send an email to cpufreq@vger.kernel.org, to subscribe go to -http://vger.kernel.org/vger-lists.html#cpufreq and follow the +send an email to linux-pm@vger.kernel.org, to subscribe go to +http://vger.kernel.org/vger-lists.html#linux-pm and follow the instructions there. Links diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt b/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt index 926b4d6aae7e0e..26799ef562df1a 100644 --- a/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt +++ b/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt @@ -1,20 +1,21 @@ Power Management Service Unit(PMSU) ----------------------------------- -Available on Marvell SOCs: Armada 370 and Armada XP +Available on Marvell SOCs: Armada 370, Armada 38x and Armada XP Required properties: -- compatible: "marvell,armada-370-xp-pmsu" +- compatible: should be one of: + - "marvell,armada-370-pmsu" for Armada 370 or Armada XP + - "marvell,armada-380-pmsu" for Armada 38x + - "marvell,armada-370-xp-pmsu" was used for Armada 370/XP but is now + deprecated and will be removed -- reg: Should contain PMSU registers location and length. First pair - for the per-CPU SW Reset Control registers, second pair for the - Power Management Service Unit. +- reg: Should contain PMSU registers location and length. Example: -armada-370-xp-pmsu@d0022000 { - compatible = "marvell,armada-370-xp-pmsu"; - reg = <0xd0022100 0x430>, - <0xd0020800 0x20>; +armada-370-xp-pmsu@22000 { + compatible = "marvell,armada-370-pmsu"; + reg = <0x22000 0x1000>; }; diff --git a/Documentation/devicetree/bindings/arm/armada-cpu-reset.txt b/Documentation/devicetree/bindings/arm/armada-cpu-reset.txt new file mode 100644 index 00000000000000..b63a7b6ab998e5 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/armada-cpu-reset.txt @@ -0,0 +1,14 @@ +Marvell Armada CPU reset controller +=================================== + +Required properties: + +- compatible: Should be "marvell,armada-370-cpu-reset". + +- reg: should be register base and length as documented in the + datasheet for the CPU reset registers + +cpurst: cpurst@20800 { + compatible = "marvell,armada-370-cpu-reset"; + reg = <0x20800 0x20>; +}; diff --git a/Documentation/devicetree/bindings/arm/coherency-fabric.txt b/Documentation/devicetree/bindings/arm/coherency-fabric.txt index 17d8cd10755998..8dd46617c889af 100644 --- a/Documentation/devicetree/bindings/arm/coherency-fabric.txt +++ b/Documentation/devicetree/bindings/arm/coherency-fabric.txt @@ -1,16 +1,33 @@ Coherency fabric ---------------- -Available on Marvell SOCs: Armada 370 and Armada XP +Available on Marvell SOCs: Armada 370, Armada 375, Armada 38x and Armada XP Required properties: -- compatible: "marvell,coherency-fabric" +- compatible: the possible values are: + + * "marvell,coherency-fabric", to be used for the coherency fabric of + the Armada 370 and Armada XP. + + * "marvell,armada-375-coherency-fabric", for the Armada 375 coherency + fabric. + + * "marvell,armada-380-coherency-fabric", for the Armada 38x coherency + fabric. - reg: Should contain coherency fabric registers location and - length. First pair for the coherency fabric registers, second pair - for the per-CPU fabric registers registers. + length. + + * For "marvell,coherency-fabric", the first pair for the coherency + fabric registers, second pair for the per-CPU fabric registers. -Example: + * For "marvell,armada-375-coherency-fabric", only one pair is needed + for the per-CPU fabric registers. + + * For "marvell,armada-380-coherency-fabric", only one pair is needed + for the per-CPU fabric registers. + +Examples: coherency-fabric@d0020200 { compatible = "marvell,coherency-fabric"; @@ -19,3 +36,8 @@ coherency-fabric@d0020200 { }; +coherency-fabric@21810 { + compatible = "marvell,armada-375-coherency-fabric"; + reg = <0x21810 0x1c>; +}; + diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index 333f4aea30291e..4bbcf4fb7583ab 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -185,6 +185,9 @@ nodes to be present and contain the properties described below. "qcom,gcc-msm8660" "qcom,kpss-acc-v1" "qcom,kpss-acc-v2" + "marvell,armada-375-smp" + "marvell,armada-380-smp" + "marvell,armada-xp-smp" - cpu-release-addr Usage: required for systems that have an "enable-method" diff --git a/Documentation/devicetree/bindings/arm/marvell,berlin.txt b/Documentation/devicetree/bindings/arm/marvell,berlin.txt index 737afa5f8148b9..0677003e147661 100644 --- a/Documentation/devicetree/bindings/arm/marvell,berlin.txt +++ b/Documentation/devicetree/bindings/arm/marvell,berlin.txt @@ -12,6 +12,7 @@ SoC and board used. Currently known SoC compatibles are: "marvell,berlin2" for Marvell Armada 1500 (BG2, 88DE3100), "marvell,berlin2cd" for Marvell Armada 1500-mini (BG2CD, 88DE3005) "marvell,berlin2ct" for Marvell Armada ? (BG2CT, 88DE????) + "marvell,berlin2q" for Marvell Armada 1500-pro (BG2Q, 88DE3114) "marvell,berlin3" for Marvell Armada ? (BG3, 88DE????) * Example: diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt index 36ede19a16304f..5aea9fc9b3a820 100644 --- a/Documentation/devicetree/bindings/arm/omap/omap.txt +++ b/Documentation/devicetree/bindings/arm/omap/omap.txt @@ -120,5 +120,5 @@ Boards: - AM437x GP EVM compatible = "ti,am437x-gp-evm", "ti,am4372", "ti,am43" -- DRA7 EVM: Software Developement Board for DRA7XX +- DRA7 EVM: Software Development Board for DRA7XX compatible = "ti,dra7-evm", "ti,dra7" diff --git a/Documentation/devicetree/bindings/arm/pmu.txt b/Documentation/devicetree/bindings/arm/pmu.txt index fe5cef8976cb07..75ef91d08f3bd2 100644 --- a/Documentation/devicetree/bindings/arm/pmu.txt +++ b/Documentation/devicetree/bindings/arm/pmu.txt @@ -8,6 +8,7 @@ Required properties: - compatible : should be one of "arm,armv8-pmuv3" + "arm,cortex-a17-pmu" "arm,cortex-a15-pmu" "arm,cortex-a12-pmu" "arm,cortex-a9-pmu" diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt index 48b285ffa3a650..d6b07e87aa936e 100644 --- a/Documentation/devicetree/bindings/ata/ahci-platform.txt +++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt @@ -4,10 +4,15 @@ SATA nodes are defined to describe on-chip Serial ATA controllers. Each SATA controller should have its own node. Required properties: -- compatible : compatible list, one of "snps,spear-ahci", - "snps,exynos5440-ahci", "ibm,476gtr-ahci", - "allwinner,sun4i-a10-ahci", "fsl,imx53-ahci" - "fsl,imx6q-ahci" or "snps,dwc-ahci" +- compatible : compatible string, one of: + - "allwinner,sun4i-a10-ahci" + - "fsl,imx53-ahci" + - "fsl,imx6q-ahci" + - "ibm,476gtr-ahci" + - "marvell,armada-380-ahci" + - "snps,dwc-ahci" + - "snps,exynos5440-ahci" + - "snps,spear-ahci" - interrupts : - reg : diff --git a/Documentation/devicetree/bindings/bus/mvebu-mbus.txt b/Documentation/devicetree/bindings/bus/mvebu-mbus.txt index 7586fb68c07265..5fa44f52a0b805 100644 --- a/Documentation/devicetree/bindings/bus/mvebu-mbus.txt +++ b/Documentation/devicetree/bindings/bus/mvebu-mbus.txt @@ -197,7 +197,7 @@ to be set by the operating system and that are guaranteed to be free of overlaps with one another or with the system memory ranges. Each entry in the property refers to exactly one window. If the operating system -choses to use a different set of mbus windows, it must ensure that any address +chooses to use a different set of mbus windows, it must ensure that any address translations performed from downstream devices are adapted accordingly. The operating system may insert additional mbus windows that do not conflict diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt index cd5e23912888cf..6794cdc96d8fdf 100644 --- a/Documentation/devicetree/bindings/clock/at91-clock.txt +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt @@ -62,7 +62,7 @@ Required properties for PMC node: - interrupt-controller : tell that the PMC is an interrupt controller. - #interrupt-cells : must be set to 1. The first cell encodes the interrupt id, and reflect the bit position in the PMC_ER/DR/SR registers. - You can use the dt macros defined in dt-bindings/clk/at91.h. + You can use the dt macros defined in dt-bindings/clock/at91.h. 0 (AT91_PMC_MOSCS) -> main oscillator ready 1 (AT91_PMC_LOCKA) -> PLL A ready 2 (AT91_PMC_LOCKB) -> PLL B ready diff --git a/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt b/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt index 56d1f4961075a5..5286e260fcae5e 100644 --- a/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt +++ b/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt @@ -10,12 +10,12 @@ This binding uses the common clock binding: Required properties: - compatible - Shall have one of the following values: - - "brcm,bcm11351-root-ccu" - - "brcm,bcm11351-aon-ccu" - - "brcm,bcm11351-hub-ccu" - - "brcm,bcm11351-master-ccu" - - "brcm,bcm11351-slave-ccu" + Shall have a value of the form "brcm,--ccu", + where is a Broadcom SoC model number and is + the name of a defined CCU. For example: + "brcm,bcm11351-root-ccu" + The compatible strings used for each supported SoC family + are defined below. - reg Shall define the base and range of the address space containing clock control registers @@ -26,12 +26,48 @@ Required properties: Shall be an ordered list of strings defining the names of the clocks provided by the CCU. +Device tree example: + + slave_ccu: slave_ccu { + compatible = "brcm,bcm11351-slave-ccu"; + reg = <0x3e011000 0x0f00>; + #clock-cells = <1>; + clock-output-names = "uartb", + "uartb2", + "uartb3", + "uartb4"; + }; + + ref_crystal_clk: ref_crystal { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + uart@3e002000 { + compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart"; + status = "disabled"; + reg = <0x3e002000 0x1000>; + clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + }; + +BCM281XX family +--------------- +CCU compatible string values for SoCs in the BCM281XX family are: + "brcm,bcm11351-root-ccu" + "brcm,bcm11351-aon-ccu" + "brcm,bcm11351-hub-ccu" + "brcm,bcm11351-master-ccu" + "brcm,bcm11351-slave-ccu" -BCM281XX family SoCs use Kona CCUs. The following table defines -the set of CCUs and clock specifiers for BCM281XX clocks. When -a clock consumer references a clocks, its symbolic specifier -(rather than its numeric index value) should be used. These -specifiers are defined in "include/dt-bindings/clock/bcm281xx.h". +The following table defines the set of CCUs and clock specifiers for +BCM281XX family clocks. When a clock consumer references a clocks, +its symbolic specifier (rather than its numeric index value) should +be used. These specifiers are defined in: + "include/dt-bindings/clock/bcm281xx.h" CCU Clock Type Index Specifier --- ----- ---- ----- --------- @@ -64,30 +100,40 @@ specifiers are defined in "include/dt-bindings/clock/bcm281xx.h". slave pwm peri 9 BCM281XX_SLAVE_CCU_PWM -Device tree example: +BCM21664 family +--------------- +CCU compatible string values for SoCs in the BCM21664 family are: + "brcm,bcm21664-root-ccu" + "brcm,bcm21664-aon-ccu" + "brcm,bcm21664-master-ccu" + "brcm,bcm21664-slave-ccu" - slave_ccu: slave_ccu { - compatible = "brcm,bcm11351-slave-ccu"; - reg = <0x3e011000 0x0f00>; - #clock-cells = <1>; - clock-output-names = "uartb", - "uartb2", - "uartb3", - "uartb4"; - }; +The following table defines the set of CCUs and clock specifiers for +BCM21664 family clocks. When a clock consumer references a clocks, +its symbolic specifier (rather than its numeric index value) should +be used. These specifiers are defined in: + "include/dt-bindings/clock/bcm21664.h" - ref_crystal_clk: ref_crystal { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <26000000>; - }; + CCU Clock Type Index Specifier + --- ----- ---- ----- --------- + root frac_1m peri 0 BCM21664_ROOT_CCU_FRAC_1M - uart@3e002000 { - compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart"; - status = "disabled"; - reg = <0x3e002000 0x1000>; - clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>; - interrupts = ; - reg-shift = <2>; - reg-io-width = <4>; - }; + aon hub_timer peri 0 BCM21664_AON_CCU_HUB_TIMER + + master sdio1 peri 0 BCM21664_MASTER_CCU_SDIO1 + master sdio2 peri 1 BCM21664_MASTER_CCU_SDIO2 + master sdio3 peri 2 BCM21664_MASTER_CCU_SDIO3 + master sdio4 peri 3 BCM21664_MASTER_CCU_SDIO4 + master sdio1_sleep peri 4 BCM21664_MASTER_CCU_SDIO1_SLEEP + master sdio2_sleep peri 5 BCM21664_MASTER_CCU_SDIO2_SLEEP + master sdio3_sleep peri 6 BCM21664_MASTER_CCU_SDIO3_SLEEP + master sdio4_sleep peri 7 BCM21664_MASTER_CCU_SDIO4_SLEEP + + slave uartb peri 0 BCM21664_SLAVE_CCU_UARTB + slave uartb2 peri 1 BCM21664_SLAVE_CCU_UARTB2 + slave uartb3 peri 2 BCM21664_SLAVE_CCU_UARTB3 + slave uartb4 peri 3 BCM21664_SLAVE_CCU_UARTB4 + slave bsc1 peri 4 BCM21664_SLAVE_CCU_BSC1 + slave bsc2 peri 5 BCM21664_SLAVE_CCU_BSC2 + slave bsc3 peri 6 BCM21664_SLAVE_CCU_BSC3 + slave bsc4 peri 7 BCM21664_SLAVE_CCU_BSC4 diff --git a/Documentation/devicetree/bindings/clock/imx25-clock.txt b/Documentation/devicetree/bindings/clock/imx25-clock.txt index db4f2f05c4d0f1..ceaf31346d5c0d 100644 --- a/Documentation/devicetree/bindings/clock/imx25-clock.txt +++ b/Documentation/devicetree/bindings/clock/imx25-clock.txt @@ -139,6 +139,9 @@ clocks and IDs. uart5_ipg 124 reserved 125 wdt_ipg 126 + cko_div 127 + cko_sel 128 + clo 129 Examples: diff --git a/Documentation/devicetree/bindings/clock/imx27-clock.txt b/Documentation/devicetree/bindings/clock/imx27-clock.txt index 7a2070393732aa..6bc9fd2c663143 100644 --- a/Documentation/devicetree/bindings/clock/imx27-clock.txt +++ b/Documentation/devicetree/bindings/clock/imx27-clock.txt @@ -98,7 +98,12 @@ clocks and IDs. fpm 83 mpll_osc_sel 84 mpll_sel 85 - spll_gate 86 + spll_gate 86 + mshc_div 87 + rtic_ipg_gate 88 + mshc_ipg_gate 89 + rtic_ahb_gate 90 + mshc_baud_gate 91 Examples: diff --git a/Documentation/devicetree/bindings/clock/imx6q-clock.txt b/Documentation/devicetree/bindings/clock/imx6q-clock.txt index 6aab72bf67ea96..90ec91fe5ce03a 100644 --- a/Documentation/devicetree/bindings/clock/imx6q-clock.txt +++ b/Documentation/devicetree/bindings/clock/imx6q-clock.txt @@ -220,6 +220,7 @@ clocks and IDs. lvds2_sel 205 lvds1_gate 206 lvds2_gate 207 + esai_ahb 208 Examples: diff --git a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt index 307a503c5db882..dc5ea5b22da90d 100644 --- a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt +++ b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt @@ -29,6 +29,11 @@ The following is a list of provided IDs and clock names on Kirkwood and Dove: 2 = l2clk (L2 Cache clock derived from CPU0 clock) 3 = ddrclk (DDR controller clock derived from CPU0 clock) +The following is a list of provided IDs and clock names on Orion5x: + 0 = tclk (Internal Bus clock) + 1 = cpuclk (CPU0 clock) + 2 = ddrclk (DDR controller clock derived from CPU0 clock) + Required properties: - compatible : shall be one of the following: "marvell,armada-370-core-clock" - For Armada 370 SoC core clocks @@ -38,6 +43,9 @@ Required properties: "marvell,dove-core-clock" - for Dove SoC core clocks "marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180) "marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC + "marvell,mv88f5182-core-clock" - for Orion MV88F5182 SoC + "marvell,mv88f5281-core-clock" - for Orion MV88F5281 SoC + "marvell,mv88f6183-core-clock" - for Orion MV88F6183 SoC - reg : shall be the register address of the Sample-At-Reset (SAR) register - #clock-cells : from common clock binding; shall be set to 1 diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 767401f4287183..7b7104e8cb1e67 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -4,6 +4,7 @@ Qualcomm Global Clock & Reset Controller Binding Required properties : - compatible : shall contain only one of the following: + "qcom,gcc-apq8064" "qcom,gcc-msm8660" "qcom,gcc-msm8960" "qcom,gcc-msm8974" diff --git a/Documentation/devicetree/bindings/clock/samsung,s3c2410-clock.txt b/Documentation/devicetree/bindings/clock/samsung,s3c2410-clock.txt new file mode 100644 index 00000000000000..0b64ad8dadf63b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/samsung,s3c2410-clock.txt @@ -0,0 +1,50 @@ +* Samsung S3C2410 Clock Controller + +The S3C2410 clock controller generates and supplies clock to various controllers +within the SoC. The clock binding described here is applicable to the s3c2410, +s3c2440 and s3c2442 SoCs in the s3c24x family. + +Required Properties: + +- compatible: should be one of the following. + - "samsung,s3c2410-clock" - controller compatible with S3C2410 SoC. + - "samsung,s3c2440-clock" - controller compatible with S3C2440 SoC. + - "samsung,s3c2442-clock" - controller compatible with S3C2442 SoC. +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. Some of the clocks are available only +on a particular SoC. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/samsung,s3c2410-clock.h header and can be used in device +tree sources. + +External clocks: + +The xti clock used as input for the plls is generated outside the SoC. It is +expected that is are defined using standard clock bindings with a +clock-output-names value of "xti". + +Example: Clock controller node: + + clocks: clock-controller@4c000000 { + compatible = "samsung,s3c2410-clock"; + reg = <0x4c000000 0x20>; + #clock-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller (refer to the standard clock bindings for information about + "clocks" and "clock-names" properties): + + serial@50004000 { + compatible = "samsung,s3c2440-uart"; + reg = <0x50004000 0x4000>; + interrupts = <1 23 3 4>, <1 23 4 4>; + clock-names = "uart", "clk_uart_baud2"; + clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>; + status = "disabled"; + }; diff --git a/Documentation/devicetree/bindings/clock/samsung,s3c2412-clock.txt b/Documentation/devicetree/bindings/clock/samsung,s3c2412-clock.txt new file mode 100644 index 00000000000000..2b430960ba4722 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/samsung,s3c2412-clock.txt @@ -0,0 +1,50 @@ +* Samsung S3C2412 Clock Controller + +The S3C2412 clock controller generates and supplies clock to various controllers +within the SoC. The clock binding described here is applicable to the s3c2412 +and s3c2413 SoCs in the s3c24x family. + +Required Properties: + +- compatible: should be "samsung,s3c2412-clock" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. Some of the clocks are available only +on a particular SoC. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/s3c2412.h header and can be used in device +tree sources. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xti" - crystal input - required, + - "ext" - external clock source - optional, + +Example: Clock controller node: + + clocks: clock-controller@4c000000 { + compatible = "samsung,s3c2412-clock"; + reg = <0x4c000000 0x20>; + #clock-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller (refer to the standard clock bindings for information about + "clocks" and "clock-names" properties): + + serial@50004000 { + compatible = "samsung,s3c2412-uart"; + reg = <0x50004000 0x4000>; + interrupts = <1 23 3 4>, <1 23 4 4>; + clock-names = "uart", "clk_uart_baud2", "clk_uart_baud3"; + clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>, + <&clocks SCLK_UART>; + status = "disabled"; + }; diff --git a/Documentation/devicetree/bindings/clock/samsung,s3c2443-clock.txt b/Documentation/devicetree/bindings/clock/samsung,s3c2443-clock.txt new file mode 100644 index 00000000000000..e67bb05478afd2 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/samsung,s3c2443-clock.txt @@ -0,0 +1,56 @@ +* Samsung S3C2443 Clock Controller + +The S3C2443 clock controller generates and supplies clock to various controllers +within the SoC. The clock binding described here is applicable to all SoCs in +the s3c24x family starting with the s3c2443. + +Required Properties: + +- compatible: should be one of the following. + - "samsung,s3c2416-clock" - controller compatible with S3C2416 SoC. + - "samsung,s3c2443-clock" - controller compatible with S3C2443 SoC. + - "samsung,s3c2450-clock" - controller compatible with S3C2450 SoC. +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. Some of the clocks are available only +on a particular SoC. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/s3c2443.h header and can be used in device +tree sources. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xti" - crystal input - required, + - "ext" - external clock source - optional, + - "ext_i2s" - external I2S clock - optional, + - "ext_uart" - external uart clock - optional, + +Example: Clock controller node: + + clocks: clock-controller@4c000000 { + compatible = "samsung,s3c2416-clock"; + reg = <0x4c000000 0x40>; + #clock-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller (refer to the standard clock bindings for information about + "clocks" and "clock-names" properties): + + serial@50004000 { + compatible = "samsung,s3c2440-uart"; + reg = <0x50004000 0x4000>; + interrupts = <1 23 3 4>, <1 23 4 4>; + clock-names = "uart", "clk_uart_baud2", + "clk_uart_baud3"; + clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>, + <&clocks SCLK_UART>; + status = "disabled"; + }; diff --git a/Documentation/devicetree/bindings/crypto/samsung-sss.txt b/Documentation/devicetree/bindings/crypto/samsung-sss.txt new file mode 100644 index 00000000000000..a6dafa83c6dfcf --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/samsung-sss.txt @@ -0,0 +1,34 @@ +Samsung SoC SSS (Security SubSystem) module + +The SSS module in S5PV210 SoC supports the following: +-- Feeder (FeedCtrl) +-- Advanced Encryption Standard (AES) +-- Data Encryption Standard (DES)/3DES +-- Public Key Accelerator (PKA) +-- SHA-1/SHA-256/MD5/HMAC (SHA-1/SHA-256/MD5)/PRNG +-- PRNG: Pseudo Random Number Generator + +The SSS module in Exynos4 (Exynos4210) and +Exynos5 (Exynos5420 and Exynos5250) SoCs +supports the following also: +-- ARCFOUR (ARC4) +-- True Random Number Generator (TRNG) +-- Secure Key Manager + +Required properties: + +- compatible : Should contain entries for this and backward compatible + SSS versions: + - "samsung,s5pv210-secss" for S5PV210 SoC. + - "samsung,exynos4210-secss" for Exynos4210, Exynos4212, Exynos4412, Exynos5250, + Exynos5260 and Exynos5420 SoCs. +- reg : Offset and length of the register set for the module +- interrupts : interrupt specifiers of SSS module interrupts, should contain + following entries: + - first : feed control interrupt (required for all variants), + - second : hash interrupt (required only for samsung,s5pv210-secss). + +- clocks : list of clock phandle and specifier pairs for all clocks listed in + clock-names property. +- clock-names : list of device clock input names; should contain one entry + "secss". diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt index ee9be9961524cd..e577196a12c057 100644 --- a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt +++ b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt @@ -8,7 +8,7 @@ Required properties: "fsl,imx51-sdma" "fsl,imx53-sdma" "fsl,imx6q-sdma" - The -to variants should be preferred since they allow to determnine the + The -to variants should be preferred since they allow to determine the correct ROM script addresses needed for the driver to work without additional firmware. - reg : Should contain SDMA registers location and length diff --git a/Documentation/devicetree/bindings/dma/mmp-dma.txt b/Documentation/devicetree/bindings/dma/mmp-dma.txt index a4fa4efa1d83a3..7a802f64e5bd8f 100644 --- a/Documentation/devicetree/bindings/dma/mmp-dma.txt +++ b/Documentation/devicetree/bindings/dma/mmp-dma.txt @@ -1,17 +1,20 @@ * MARVELL MMP DMA controller Marvell Peripheral DMA Controller -Used platfroms: pxa688, pxa910, pxa3xx, etc +Used platforms: pxa688, pxa910, pxa3xx, etc Required properties: - compatible: Should be "marvell,pdma-1.0" - reg: Should contain DMA registers location and length. - interrupts: Either contain all of the per-channel DMA interrupts or one irq for pdma device -- #dma-channels: Number of DMA channels supported by the controller. + +Optional properties: +- #dma-channels: Number of DMA channels supported by the controller (defaults + to 32 when not specified) "marvell,pdma-1.0" -Used platfroms: pxa25x, pxa27x, pxa3xx, pxa93x, pxa168, pxa910, pxa688. +Used platforms: pxa25x, pxa27x, pxa3xx, pxa93x, pxa168, pxa910, pxa688. Examples: @@ -45,7 +48,7 @@ pdma: dma-controller@d4000000 { Marvell Two Channel DMA Controller used specifically for audio -Used platfroms: pxa688, pxa910 +Used platforms: pxa688, pxa910 Required properties: - compatible: Should be "marvell,adma-1.0" or "marvell,pxa910-squ" diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt new file mode 100644 index 00000000000000..1405ed071bb4fd --- /dev/null +++ b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt @@ -0,0 +1,75 @@ +Xilinx AXI VDMA engine, it does transfers between memory and video devices. +It can be configured to have one channel or two channels. If configured +as two channels, one is to transmit to the video device and another is +to receive from the video device. + +Required properties: +- compatible: Should be "xlnx,axi-vdma-1.00.a" +- #dma-cells: Should be <1>, see "dmas" property below +- reg: Should contain VDMA registers location and length. +- xlnx,num-fstores: Should be the number of framebuffers as configured in h/w. +- dma-channel child node: Should have at least one channel and can have up to + two channels per device. This node specifies the properties of each + DMA channel (see child node properties below). + +Optional properties: +- xlnx,include-sg: Tells configured for Scatter-mode in + the hardware. +- xlnx,flush-fsync: Tells which channel to Flush on Frame sync. + It takes following values: + {1}, flush both channels + {2}, flush mm2s channel + {3}, flush s2mm channel + +Required child node properties: +- compatible: It should be either "xlnx,axi-vdma-mm2s-channel" or + "xlnx,axi-vdma-s2mm-channel". +- interrupts: Should contain per channel VDMA interrupts. +- xlnx,data-width: Should contain the stream data width, take values + {32,64...1024}. + +Optional child node properties: +- xlnx,include-dre: Tells hardware is configured for Data + Realignment Engine. +- xlnx,genlock-mode: Tells Genlock synchronization is + enabled/disabled in hardware. + +Example: +++++++++ + +axi_vdma_0: axivdma@40030000 { + compatible = "xlnx,axi-vdma-1.00.a"; + #dma_cells = <1>; + reg = < 0x40030000 0x10000 >; + xlnx,num-fstores = <0x8>; + xlnx,flush-fsync = <0x1>; + dma-channel@40030000 { + compatible = "xlnx,axi-vdma-mm2s-channel"; + interrupts = < 0 54 4 >; + xlnx,datawidth = <0x40>; + } ; + dma-channel@40030030 { + compatible = "xlnx,axi-vdma-s2mm-channel"; + interrupts = < 0 53 4 >; + xlnx,datawidth = <0x40>; + } ; +} ; + + +* DMA client + +Required properties: +- dmas: a list of <[Video DMA device phandle] [Channel ID]> pairs, + where Channel ID is '0' for write/tx and '1' for read/rx + channel. +- dma-names: a list of DMA channel names, one per "dmas" entry + +Example: +++++++++ + +vdmatest_0: vdmatest@0 { + compatible ="xlnx,axi-vdma-test-1.00.a"; + dmas = <&axi_vdma_0 0 + &axi_vdma_0 1>; + dma-names = "vdma0", "vdma1"; +} ; diff --git a/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt b/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt index 3ddc7ccfe5f307..c306a2d0f2b1fb 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt @@ -54,7 +54,7 @@ Optional device specific properties: IO 8-15 are bank 2. These chips have two different interrupt outputs: One for bank 1 and another for bank 2. If irq-mirror is set, both interrupts are generated regardless of the bank that an input change - occured on. If it is not set, the interrupt are only generated for the + occurred on. If it is not set, the interrupt are only generated for the bank they belong to. On devices with only one interrupt output this property is useless. diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt index f61cef74a2124c..941a26aa432286 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt @@ -21,6 +21,12 @@ Required Properties: GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported. - gpio-ranges: Range of pins managed by the GPIO controller. +Optional properties: + + - clocks: Must contain a reference to the functional clock. The property is + mandatory if the hardware implements a controllable functional clock for + the GPIO instance. + Please refer to gpio.txt in this directory for details of gpio-ranges property and the common GPIO bindings used by client devices. diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt index efa8b8451f93be..b48f4ef31d937f 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt @@ -136,6 +136,7 @@ of the following host1x client modules: - compatible: "nvidia,tegra-hdmi" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - hdmi-supply: supply for the +5V HDMI connector pin - vdd-supply: regulator for supply voltage - pll-supply: regulator for PLL - clocks: Must contain an entry for each entry in clock-names. @@ -180,6 +181,7 @@ of the following host1x client modules: See ../reset/reset.txt for details. - reset-names: Must include the following entries: - dsi + - avdd-dsi-supply: phandle of a supply that powers the DSI controller - nvidia,mipi-calibrate: Should contain a phandle and a specifier specifying which pads are used by this DSI output and need to be calibrated. See also ../mipi/nvidia,tegra114-mipi.txt. diff --git a/Documentation/devicetree/bindings/iio/proximity/as3935.txt b/Documentation/devicetree/bindings/iio/proximity/as3935.txt new file mode 100644 index 00000000000000..ae23dd8da7366f --- /dev/null +++ b/Documentation/devicetree/bindings/iio/proximity/as3935.txt @@ -0,0 +1,28 @@ +Austrian Microsystems AS3935 Franklin lightning sensor device driver + +Required properties: + - compatible: must be "ams,as3935" + - reg: SPI chip select number for the device + - spi-cpha: SPI Mode 1. Refer to spi/spi-bus.txt for generic SPI + slave node bindings. + - interrupt-parent : should be the phandle for the interrupt controller + - interrupts : the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic + interrupt client node bindings. + +Optional properties: + - ams,tuning-capacitor-pf: Calibration tuning capacitor stepping + value 0 - 120pF. This will require using the calibration data from + the manufacturer. + +Example: + +as3935@0 { + compatible = "ams,as3935"; + reg = <0>; + spi-cpha; + interrupt-parent = <&gpio1>; + interrupts = <16 1>; + ams,tuning-capacitor-pf = <80>; +}; diff --git a/Documentation/devicetree/bindings/input/st-keyscan.txt b/Documentation/devicetree/bindings/input/st-keyscan.txt new file mode 100644 index 00000000000000..51eb428e5c85aa --- /dev/null +++ b/Documentation/devicetree/bindings/input/st-keyscan.txt @@ -0,0 +1,60 @@ +* ST Keyscan controller Device Tree bindings + +The ST keyscan controller Device Tree binding is based on the +matrix-keymap. + +Required properties: +- compatible: "st,sti-keyscan" + +- reg: Register base address and size of st-keyscan controller. + +- interrupts: Interrupt number for the st-keyscan controller. + +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + +- pinctrl: Should specify pin control groups used for this controller. + See ../pinctrl/pinctrl-bindings.txt for details. + +- linux,keymap: The keymap for keys as described in the binding document + devicetree/bindings/input/matrix-keymap.txt. + +- keypad,num-rows: Number of row lines connected to the keypad controller. + +- keypad,num-columns: Number of column lines connected to the keypad + controller. + +Optional property: +- st,debounce_us: Debouncing interval time in microseconds + +Example: + +keyscan: keyscan@fe4b0000 { + compatible = "st,sti-keyscan"; + reg = <0xfe4b0000 0x2000>; + interrupts = ; + clocks = <&CLK_SYSIN>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_keyscan>; + + keypad,num-rows = <4>; + keypad,num-columns = <4>; + st,debounce_us = <5000>; + + linux,keymap = < MATRIX_KEY(0x00, 0x00, KEY_F13) + MATRIX_KEY(0x00, 0x01, KEY_F9) + MATRIX_KEY(0x00, 0x02, KEY_F5) + MATRIX_KEY(0x00, 0x03, KEY_F1) + MATRIX_KEY(0x01, 0x00, KEY_F14) + MATRIX_KEY(0x01, 0x01, KEY_F10) + MATRIX_KEY(0x01, 0x02, KEY_F6) + MATRIX_KEY(0x01, 0x03, KEY_F2) + MATRIX_KEY(0x02, 0x00, KEY_F15) + MATRIX_KEY(0x02, 0x01, KEY_F11) + MATRIX_KEY(0x02, 0x02, KEY_F7) + MATRIX_KEY(0x02, 0x03, KEY_F3) + MATRIX_KEY(0x03, 0x00, KEY_F16) + MATRIX_KEY(0x03, 0x01, KEY_F12) + MATRIX_KEY(0x03, 0x02, KEY_F8) + MATRIX_KEY(0x03, 0x03, KEY_F4) >; + }; diff --git a/Documentation/devicetree/bindings/leds/leds-lp55xx.txt b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt index c55b8c016a9e2b..1b66a413fb9dfe 100644 --- a/Documentation/devicetree/bindings/leds/leds-lp55xx.txt +++ b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt @@ -1,7 +1,13 @@ Binding for TI/National Semiconductor LP55xx Led Drivers Required properties: -- compatible: "national,lp5521" or "national,lp5523" or "ti,lp5562" or "ti,lp8501" +- compatible: one of + national,lp5521 + national,lp5523 + ti,lp55231 + ti,lp5562 + ti,lp8501 + - reg: I2C slave address - clock-mode: Input clock mode, (0: automode, 1: internal, 2: external) diff --git a/Documentation/devicetree/bindings/leds/leds-pwm.txt b/Documentation/devicetree/bindings/leds/leds-pwm.txt index 7297107cf83285..6c6583c35f2ff6 100644 --- a/Documentation/devicetree/bindings/leds/leds-pwm.txt +++ b/Documentation/devicetree/bindings/leds/leds-pwm.txt @@ -13,6 +13,8 @@ LED sub-node properties: For the pwms and pwm-names property please refer to: Documentation/devicetree/bindings/pwm/pwm.txt - max-brightness : Maximum brightness possible for the LED +- active-low : (optional) For PWMs where the LED is wired to supply + rather than ground. - label : (optional) see Documentation/devicetree/bindings/leds/common.txt - linux,default-trigger : (optional) diff --git a/Documentation/devicetree/bindings/memory-controllers/mvebu-devbus.txt b/Documentation/devicetree/bindings/memory-controllers/mvebu-devbus.txt index 653c90c34a71bd..1ee3bc09f31982 100644 --- a/Documentation/devicetree/bindings/memory-controllers/mvebu-devbus.txt +++ b/Documentation/devicetree/bindings/memory-controllers/mvebu-devbus.txt @@ -6,10 +6,11 @@ The actual devices are instantiated from the child nodes of a Device Bus node. Required properties: - - compatible: Currently only Armada 370/XP SoC are supported, - with this compatible string: + - compatible: Armada 370/XP SoC are supported using the + "marvell,mvebu-devbus" compatible string. - marvell,mvebu-devbus + Orion5x SoC are supported using the + "marvell,orion-devbus" compatible string. - reg: A resource specifier for the register space. This is the base address of a chip select within @@ -22,7 +23,14 @@ Required properties: integer values for each chip-select line in use: 0 -Mandatory timing properties for child nodes: +Optional properties: + + - devbus,keep-config This property can optionally be used to keep + using the timing parameters set by the + bootloader. It makes all the timing properties + described below unused. + +Timing properties for child nodes: Read parameters: @@ -30,21 +38,26 @@ Read parameters: drive the AD bus after the completion of a device read. This prevents contentions on the Device Bus after a read cycle from a slow device. + Mandatory, except if devbus,keep-config is used. - - devbus,bus-width: Defines the bus width (e.g. <16>) + - devbus,bus-width: Defines the bus width, in bits (e.g. <16>). + Mandatory, except if devbus,keep-config is used. - devbus,badr-skew-ps: Defines the time delay from from A[2:0] toggle, to read data sample. This parameter is useful for synchronous pipelined devices, where the address precedes the read data by one or two cycles. + Mandatory, except if devbus,keep-config is used. - devbus,acc-first-ps: Defines the time delay from the negation of ALE[0] to the cycle that the first read data is sampled by the controller. + Mandatory, except if devbus,keep-config is used. - devbus,acc-next-ps: Defines the time delay between the cycle that samples data N and the cycle that samples data N+1 (in burst accesses). + Mandatory, except if devbus,keep-config is used. - devbus,rd-setup-ps: Defines the time delay between DEV_CSn assertion to DEV_OEn assertion. If set to 0 (default), @@ -52,6 +65,8 @@ Read parameters: This parameter has no affect on parameter (no affect on first data sample). Set to a value smaller than . + Mandatory for "marvell,mvebu-devbus" compatible string, + except if devbus,keep-config is used. - devbus,rd-hold-ps: Defines the time between the last data sample to the de-assertion of DEV_CSn. If set to 0 (default), @@ -62,16 +77,20 @@ Read parameters: last data sampled. Also this parameter has no affect on parameter. Set to a value smaller than . + Mandatory for "marvell,mvebu-devbus" compatible string, + except if devbus,keep-config is used. Write parameters: - devbus,ale-wr-ps: Defines the time delay from the ALE[0] negation cycle to the DEV_WEn assertion. + Mandatory. - devbus,wr-low-ps: Defines the time during which DEV_WEn is active. A[2:0] and Data are kept valid as long as DEV_WEn is active. This parameter defines the setup time of address and data to DEV_WEn rise. + Mandatory. - devbus,wr-high-ps: Defines the time during which DEV_WEn is kept inactive (high) between data beats of a burst write. @@ -79,10 +98,13 @@ Write parameters: - ps. This parameter defines the hold time of address and data after DEV_WEn rise. + Mandatory. - devbus,sync-enable: Synchronous device enable. 1: True 0: False + Mandatory for "marvell,mvebu-devbus" compatible string, + except if devbus,keep-config is used. An example for an Armada XP GP board, with a 16 MiB NOR device as child is showed below. Note that the Device Bus driver is in charge of allocating diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt b/Documentation/devicetree/bindings/mfd/mc13xxx.txt index 1413f39912d3ac..8aba48821a85a3 100644 --- a/Documentation/devicetree/bindings/mfd/mc13xxx.txt +++ b/Documentation/devicetree/bindings/mfd/mc13xxx.txt @@ -10,6 +10,9 @@ Optional properties: - fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used Sub-nodes: +- codec: Contain the Audio Codec node. + - adc-port: Contain PMIC SSI port number used for ADC. + - dac-port: Contain PMIC SSI port number used for DAC. - leds : Contain the led nodes and initial register values in property "led-control". Number of register depends of used IC, for MC13783 is 6, for MC13892 is 4, for MC34708 is 1. See datasheet for bits definitions of diff --git a/Documentation/devicetree/bindings/mfd/s2mps11.txt b/Documentation/devicetree/bindings/mfd/s2mps11.txt index 802e839b08294f..d81ba30c0d8bd6 100644 --- a/Documentation/devicetree/bindings/mfd/s2mps11.txt +++ b/Documentation/devicetree/bindings/mfd/s2mps11.txt @@ -56,6 +56,20 @@ for a particular group of BUCKs. So provide same regulator-ramp-delay. Grouping of BUCKs sharing ramp rate setting is as follow : BUCK[1, 6], BUCK[3, 4], and BUCK[7, 8, 10] +On S2MPS14 the LDO10, LDO11 and LDO12 can be configured to external control +over GPIO. To turn this feature on this property must be added to the regulator +sub-node: + - samsung,ext-control-gpios: GPIO specifier for one GPIO + controlling this regulator (enable/disable); +Example: + LDO12 { + regulator-name = "V_EMMC_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + samsung,ext-control-gpios = <&gpk0 2 0>; + }; + + The regulator constraints inside the regulator nodes use the standard regulator bindings which are documented elsewhere. diff --git a/Documentation/devicetree/bindings/misc/arm-charlcd.txt b/Documentation/devicetree/bindings/misc/arm-charlcd.txt new file mode 100644 index 00000000000000..e28e2aac47f156 --- /dev/null +++ b/Documentation/devicetree/bindings/misc/arm-charlcd.txt @@ -0,0 +1,18 @@ +ARM Versatile Character LCD +----------------------------------------------------- +This binding defines the character LCD interface found on ARM Versatile AB +and PB reference platforms. + +Required properties: +- compatible : "arm,versatile-clcd" +- reg : Location and size of character LCD registers + +Optional properties: +- interrupts - single interrupt for character LCD. The character LCD can + operate in polled mode without an interrupt. + +Example: + lcd@10008000 { + compatible = "arm,versatile-lcd"; + reg = <0x10008000 0x1000>; + }; diff --git a/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt index b8653ea97957d0..e5bc49f764d10a 100644 --- a/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt @@ -12,7 +12,7 @@ extensions to the Synopsys Designware Mobile Storage Host Controller. Required Properties: * compatible: should be one of the following. - - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extentions. + - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extensions. Example: diff --git a/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt b/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt index 328e990d2546b3..42e0a9afa10011 100644 --- a/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt @@ -3,7 +3,7 @@ Samsung's SDHCI controller is used as a connectivity interface with external MMC, SD and eMMC storage mediums. This file documents differences between the core mmc properties described by mmc.txt and the properties used by the -Samsung implmentation of the SDHCI controller. +Samsung implementation of the SDHCI controller. Required SoC Specific Properties: - compatible: should be one of the following diff --git a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt index 8f3f1331535802..2d4a7258a10db9 100644 --- a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt @@ -69,10 +69,6 @@ Optional properties: * supports-highspeed: Enables support for high speed cards (up to 50MHz) -* caps2-mmc-hs200-1_8v: Supports mmc HS200 SDR 1.8V mode - -* caps2-mmc-hs200-1_2v: Supports mmc HS200 SDR 1.2V mode - * broken-cd: as documented in mmc core bindings. * vmmc-supply: The phandle to the regulator to use for vmmc. If this is @@ -103,7 +99,6 @@ board specific portions as listed below. clock-freq-min-max = <400000 200000000>; num-slots = <1>; supports-highspeed; - caps2-mmc-hs200-1_8v; broken-cd; fifo-depth = <0x80>; card-detect-delay = <200>; diff --git a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt new file mode 100644 index 00000000000000..823d1341219563 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt @@ -0,0 +1,35 @@ +* Freescale Quad Serial Peripheral Interface(QuadSPI) + +Required properties: + - compatible : Should be "fsl,vf610-qspi" + - reg : the first contains the register location and length, + the second contains the memory mapping address and length + - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" + - interrupts : Should contain the interrupt for the device + - clocks : The clocks needed by the QuadSPI controller + - clock-names : the name of the clocks + +Optional properties: + - fsl,qspi-has-second-chip: The controller has two buses, bus A and bus B. + Each bus can be connected with two NOR flashes. + Most of the time, each bus only has one NOR flash + connected, this is the default case. + But if there are two NOR flashes connected to the + bus, you should enable this property. + (Please check the board's schematic.) + +Example: + +qspi0: quadspi@40044000 { + compatible = "fsl,vf610-qspi"; + reg = <0x40044000 0x1000>, <0x20000000 0x10000000>; + reg-names = "QuadSPI", "QuadSPI-memory"; + interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks VF610_CLK_QSPI0_EN>, + <&clks VF610_CLK_QSPI0>; + clock-names = "qspi_en", "qspi"; + + flash0: s25fl128s@0 { + .... + }; +}; diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt index 5e1f31b5ff70d1..eb05255b6788e4 100644 --- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt @@ -43,7 +43,7 @@ Optional properties: ELM hardware engines should specify this device node in .dtsi Using ELM for ECC error correction frees some CPU cycles. -For inline partiton table parsing (optional): +For inline partition table parsing (optional): - #address-cells: should be set to 1 - #size-cells: should be set to 1 diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nor.txt b/Documentation/devicetree/bindings/mtd/gpmc-nor.txt index 420b3ab1889015..4828c17bb784bd 100644 --- a/Documentation/devicetree/bindings/mtd/gpmc-nor.txt +++ b/Documentation/devicetree/bindings/mtd/gpmc-nor.txt @@ -30,7 +30,7 @@ Optional properties: - gpmc,XXX Additional GPMC timings and settings parameters. See Documentation/devicetree/bindings/bus/ti-gpmc.txt -Optional properties for partiton table parsing: +Optional properties for partition table parsing: - #address-cells: should be set to 1 - #size-cells: should be set to 1 diff --git a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt index b7529424ac88e0..5d8fa527c496a1 100644 --- a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt @@ -17,7 +17,7 @@ Optional properties: - dma-channel: DMA Channel index -For inline partiton table parsing (optional): +For inline partition table parsing (optional): - #address-cells: should be set to 1 - #size-cells: should be set to 1 diff --git a/Documentation/devicetree/bindings/net/broadcom-systemport.txt b/Documentation/devicetree/bindings/net/broadcom-systemport.txt new file mode 100644 index 00000000000000..1b7600e022dd10 --- /dev/null +++ b/Documentation/devicetree/bindings/net/broadcom-systemport.txt @@ -0,0 +1,29 @@ +* Broadcom BCM7xxx Ethernet Systemport Controller (SYSTEMPORT) + +Required properties: +- compatible: should be one of "brcm,systemport-v1.00" or "brcm,systemport" +- reg: address and length of the register set for the device. +- interrupts: interrupts for the device, first cell must be for the the rx + interrupts, and the second cell should be for the transmit queues +- local-mac-address: Ethernet MAC address (48 bits) of this adapter +- phy-mode: Should be a string describing the PHY interface to the + Ethernet switch/PHY, see Documentation/devicetree/bindings/net/ethernet.txt +- fixed-link: see Documentation/devicetree/bindings/net/fsl-tsec-phy.txt for + the property specific details + +Optional properties: +- systemport,num-tier2-arb: number of tier 2 arbiters, an integer +- systemport,num-tier1-arb: number of tier 1 arbiters, an integer +- systemport,num-txq: number of HW transmit queues, an integer +- systemport,num-rxq: number of HW receive queues, an integer + +Example: +ethernet@f04a0000 { + compatible = "brcm,systemport-v1.00"; + reg = <0xf04a0000 0x4650>; + local-mac-address = [ 00 11 22 33 44 55 ]; + fixed-link = <0 1 1000 0 0>; + phy-mode = "gmii"; + interrupts = <0x0 0x16 0x0>, + <0x0 0x17 0x0>; +}; diff --git a/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt b/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt new file mode 100644 index 00000000000000..d3bbdded4cbe8d --- /dev/null +++ b/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt @@ -0,0 +1,23 @@ +* AT86RF230 IEEE 802.15.4 * + +Required properties: + - compatible: should be "atmel,at86rf230", "atmel,at86rf231", + "atmel,at86rf233" or "atmel,at86rf212" + - spi-max-frequency: maximal bus speed, should be set to 7500000 depends + sync or async operation mode + - reg: the chipselect index + - interrupts: the interrupt generated by the device + +Optional properties: + - reset-gpio: GPIO spec for the rstn pin + - sleep-gpio: GPIO spec for the slp_tr pin + +Example: + + at86rf231@0 { + compatible = "atmel,at86rf231"; + spi-max-frequency = <7500000>; + reg = <0>; + interrupts = <19 1>; + interrupt-parent = <&gpio3>; + }; diff --git a/Documentation/devicetree/bindings/net/micrel-ksz9021.txt b/Documentation/devicetree/bindings/net/micrel-ksz9021.txt deleted file mode 100644 index 997a63f1aea15e..00000000000000 --- a/Documentation/devicetree/bindings/net/micrel-ksz9021.txt +++ /dev/null @@ -1,49 +0,0 @@ -Micrel KSZ9021 Gigabit Ethernet PHY - -Some boards require special tuning values, particularly when it comes to -clock delays. You can specify clock delay values by adding -micrel-specific properties to an Ethernet OF device node. - -All skew control options are specified in picoseconds. The minimum -value is 0, and the maximum value is 3000. - -Optional properties: - - rxc-skew-ps : Skew control of RXC pad - - rxdv-skew-ps : Skew control of RX CTL pad - - txc-skew-ps : Skew control of TXC pad - - txen-skew-ps : Skew control of TX_CTL pad - - rxd0-skew-ps : Skew control of RX data 0 pad - - rxd1-skew-ps : Skew control of RX data 1 pad - - rxd2-skew-ps : Skew control of RX data 2 pad - - rxd3-skew-ps : Skew control of RX data 3 pad - - txd0-skew-ps : Skew control of TX data 0 pad - - txd1-skew-ps : Skew control of TX data 1 pad - - txd2-skew-ps : Skew control of TX data 2 pad - - txd3-skew-ps : Skew control of TX data 3 pad - -Examples: - - /* Attach to an Ethernet device with autodetected PHY */ - &enet { - rxc-skew-ps = <3000>; - rxdv-skew-ps = <0>; - txc-skew-ps = <3000>; - txen-skew-ps = <0>; - status = "okay"; - }; - - /* Attach to an explicitly-specified PHY */ - mdio { - phy0: ethernet-phy@0 { - rxc-skew-ps = <3000>; - rxdv-skew-ps = <0>; - txc-skew-ps = <3000>; - txen-skew-ps = <0>; - reg = <0>; - }; - }; - ethernet@70000 { - status = "okay"; - phy = <&phy0>; - phy-mode = "rgmii-id"; - }; diff --git a/Documentation/devicetree/bindings/net/micrel-ksz90x1.txt b/Documentation/devicetree/bindings/net/micrel-ksz90x1.txt new file mode 100644 index 00000000000000..692076fda0e589 --- /dev/null +++ b/Documentation/devicetree/bindings/net/micrel-ksz90x1.txt @@ -0,0 +1,83 @@ +Micrel KSZ9021/KSZ9031 Gigabit Ethernet PHY + +Some boards require special tuning values, particularly when it comes to +clock delays. You can specify clock delay values by adding +micrel-specific properties to an Ethernet OF device node. + +Note that these settings are applied after any phy-specific fixup from +phy_fixup_list (see phy_init_hw() from drivers/net/phy/phy_device.c), +and therefore may overwrite them. + +KSZ9021: + + All skew control options are specified in picoseconds. The minimum + value is 0, the maximum value is 3000, and it is incremented by 200ps + steps. + + Optional properties: + + - rxc-skew-ps : Skew control of RXC pad + - rxdv-skew-ps : Skew control of RX CTL pad + - txc-skew-ps : Skew control of TXC pad + - txen-skew-ps : Skew control of TX CTL pad + - rxd0-skew-ps : Skew control of RX data 0 pad + - rxd1-skew-ps : Skew control of RX data 1 pad + - rxd2-skew-ps : Skew control of RX data 2 pad + - rxd3-skew-ps : Skew control of RX data 3 pad + - txd0-skew-ps : Skew control of TX data 0 pad + - txd1-skew-ps : Skew control of TX data 1 pad + - txd2-skew-ps : Skew control of TX data 2 pad + - txd3-skew-ps : Skew control of TX data 3 pad + +KSZ9031: + + All skew control options are specified in picoseconds. The minimum + value is 0, and the maximum is property-dependent. The increment + step is 60ps. + + Optional properties: + + Maximum value of 1860: + + - rxc-skew-ps : Skew control of RX clock pad + - txc-skew-ps : Skew control of TX clock pad + + Maximum value of 900: + + - rxdv-skew-ps : Skew control of RX CTL pad + - txen-skew-ps : Skew control of TX CTL pad + - rxd0-skew-ps : Skew control of RX data 0 pad + - rxd1-skew-ps : Skew control of RX data 1 pad + - rxd2-skew-ps : Skew control of RX data 2 pad + - rxd3-skew-ps : Skew control of RX data 3 pad + - txd0-skew-ps : Skew control of TX data 0 pad + - txd1-skew-ps : Skew control of TX data 1 pad + - txd2-skew-ps : Skew control of TX data 2 pad + - txd3-skew-ps : Skew control of TX data 3 pad + +Examples: + + /* Attach to an Ethernet device with autodetected PHY */ + &enet { + rxc-skew-ps = <3000>; + rxdv-skew-ps = <0>; + txc-skew-ps = <3000>; + txen-skew-ps = <0>; + status = "okay"; + }; + + /* Attach to an explicitly-specified PHY */ + mdio { + phy0: ethernet-phy@0 { + rxc-skew-ps = <3000>; + rxdv-skew-ps = <0>; + txc-skew-ps = <3000>; + txen-skew-ps = <0>; + reg = <0>; + }; + }; + ethernet@70000 { + status = "okay"; + phy = <&phy0>; + phy-mode = "rgmii-id"; + }; diff --git a/Documentation/devicetree/bindings/net/via-rhine.txt b/Documentation/devicetree/bindings/net/via-rhine.txt new file mode 100644 index 00000000000000..334eca2bf937cc --- /dev/null +++ b/Documentation/devicetree/bindings/net/via-rhine.txt @@ -0,0 +1,17 @@ +* VIA Rhine 10/100 Network Controller + +Required properties: +- compatible : Should be "via,vt8500-rhine" for integrated + Rhine controllers found in VIA VT8500, WonderMedia WM8950 + and similar. These are listed as 1106:3106 rev. 0x84 on the + virtual PCI bus under vendor-provided kernels +- reg : Address and length of the io space +- interrupts : Should contain the controller interrupt line + +Examples: + +ethernet@d8004000 { + compatible = "via,vt8500-rhine"; + reg = <0xd8004000 0x100>; + interrupts = <10>; +}; diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt index dff0e5f995e2c1..d8d065608ec0a7 100644 --- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt @@ -6,8 +6,13 @@ the first two functions being GPIO in and out. The configuration on the pins includes drive strength and pull-up. Required properties: -- compatible: "allwinner,-pinctrl". Supported SoCs for now are: - sun5i-a13. +- compatible: Should be one of the followings (depending on you SoC): + "allwinner,sun4i-a10-pinctrl" + "allwinner,sun5i-a10s-pinctrl" + "allwinner,sun5i-a13-pinctrl" + "allwinner,sun6i-a31-pinctrl" + "allwinner,sun6i-a31-r-pinctrl" + "allwinner,sun7i-a20-pinctrl" - reg: Should contain the register physical address and length for the pin controller. diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt index 67a5db95f189b5..4eaae32821aead 100644 --- a/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt @@ -73,9 +73,9 @@ Optional Properties (for standard pins): Otherwise: 0: fast slew rate 1: normal slew rate -- input-enable: No arguements. Enable input (does not affect +- input-enable: No arguments. Enable input (does not affect output.) -- input-disable: No arguements. Disable input (does not affect +- input-disable: No arguments. Disable input (does not affect output.) - drive-strength: Integer. Drive strength in mA. Valid values are 2, 4, 6, 8, 10, 12, 14, 16 mA. @@ -99,9 +99,9 @@ Optional Properties (for I2C pins): Otherwise: 0: fast slew rate 1: normal slew rate -- input-enable: No arguements. Enable input (does not affect +- input-enable: No arguments. Enable input (does not affect output.) -- input-disable: No arguements. Disable input (does not affect +- input-disable: No arguments. Disable input (does not affect output.) Optional Properties (for HDMI pins): @@ -111,9 +111,9 @@ Optional Properties (for HDMI pins): - slew-rate: Integer. Controls slew rate. 0: Standard(100kbps)& Fast(400kbps) mode 1: Highspeed (3.4Mbps) mode -- input-enable: No arguements. Enable input (does not affect +- input-enable: No arguments. Enable input (does not affect output.) -- input-disable: No arguements. Disable input (does not affect +- input-disable: No arguments. Disable input (does not affect output.) Example: diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,orion-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,orion-pinctrl.txt new file mode 100644 index 00000000000000..27570a3a174160 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/marvell,orion-pinctrl.txt @@ -0,0 +1,91 @@ +* Marvell Orion SoC pinctrl driver for mpp + +Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding +part and usage. + +Required properties: +- compatible: "marvell,88f5181l-pinctrl", "marvell,88f5182-pinctrl", + "marvell,88f5281-pinctrl" + +- reg: two register areas, the first one describing the first two + contiguous MPP registers, and the second one describing the single + final MPP register, separated from the previous one. + +Available mpp pins/groups and functions: +Note: brackets (x) are not part of the mpp name for marvell,function and given +only for more detailed description in this document. + +* Marvell Orion 88f5181l + +name pins functions +================================================================================ +mpp0 0 pcie(rstout), pci(req2), gpio +mpp1 1 gpio, pci(gnt2) +mpp2 2 gpio, pci(req3), pci-1(pme) +mpp3 3 gpio, pci(gnt3) +mpp4 4 gpio, pci(req4) +mpp5 5 gpio, pci(gnt4) +mpp6 6 gpio, pci(req5), pci-1(clk) +mpp7 7 gpio, pci(gnt5), pci-1(clk) +mpp8 8 gpio, ge(col) +mpp9 9 gpio, ge(rxerr) +mpp10 10 gpio, ge(crs) +mpp11 11 gpio, ge(txerr) +mpp12 12 gpio, ge(txd4) +mpp13 13 gpio, ge(txd5) +mpp14 14 gpio, ge(txd6) +mpp15 15 gpio, ge(txd7) +mpp16 16 ge(rxd4) +mpp17 17 ge(rxd5) +mpp18 18 ge(rxd6) +mpp19 19 ge(rxd7) + +* Marvell Orion 88f5182 + +name pins functions +================================================================================ +mpp0 0 pcie(rstout), pci(req2), gpio +mpp1 1 gpio, pci(gnt2) +mpp2 2 gpio, pci(req3), pci-1(pme) +mpp3 3 gpio, pci(gnt3) +mpp4 4 gpio, pci(req4), bootnand(re), sata0(prsnt) +mpp5 5 gpio, pci(gnt4), bootnand(we), sata1(prsnt) +mpp6 6 gpio, pci(req5), nand(re0), sata0(act) +mpp7 7 gpio, pci(gnt5), nand(we0), sata1(act) +mpp8 8 gpio, ge(col) +mpp9 9 gpio, ge(rxerr) +mpp10 10 gpio, ge(crs) +mpp11 11 gpio, ge(txerr) +mpp12 12 gpio, ge(txd4), nand(re1), sata0(ledprsnt) +mpp13 13 gpio, ge(txd5), nand(we1), sata1(ledprsnt) +mpp14 14 gpio, ge(txd6), nand(re2), sata0(ledact) +mpp15 15 gpio, ge(txd7), nand(we2), sata1(ledact) +mpp16 16 uart1(rxd), ge(rxd4), gpio +mpp17 17 uart1(txd), ge(rxd5), gpio +mpp18 18 uart1(cts), ge(rxd6), gpio +mpp19 19 uart1(rts), ge(rxd7), gpio + +* Marvell Orion 88f5281 + +name pins functions +================================================================================ +mpp0 0 pcie(rstout), pci(req2), gpio +mpp1 1 gpio, pci(gnt2) +mpp2 2 gpio, pci(req3), pci(pme) +mpp3 3 gpio, pci(gnt3) +mpp4 4 gpio, pci(req4), bootnand(re) +mpp5 5 gpio, pci(gnt4), bootnand(we) +mpp6 6 gpio, pci(req5), nand(re0) +mpp7 7 gpio, pci(gnt5), nand(we0) +mpp8 8 gpio, ge(col) +mpp9 9 gpio, ge(rxerr) +mpp10 10 gpio, ge(crs) +mpp11 11 gpio, ge(txerr) +mpp12 12 gpio, ge(txd4), nand(re1) +mpp13 13 gpio, ge(txd5), nand(we1) +mpp14 14 gpio, ge(txd6), nand(re2) +mpp15 15 gpio, ge(txd7), nand(we2) +mpp16 16 uart1(rxd), ge(rxd4) +mpp17 17 uart1(txd), ge(rxd5) +mpp18 18 uart1(cts), ge(rxd6) +mpp19 19 uart1(rts), ge(rxd7) diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,apq8064-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,apq8064-pinctrl.txt new file mode 100644 index 00000000000000..7181f925acaaa8 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,apq8064-pinctrl.txt @@ -0,0 +1,88 @@ +Qualcomm APQ8064 TLMM block + +Required properties: +- compatible: "qcom,apq8064-pinctrl" +- reg: Should be the base address and length of the TLMM block. +- interrupts: Should be the parent IRQ of the TLMM block. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. + The first cell is the gpio pin number and the + second cell is used for optional parameters. + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Qualcomm's pin configuration nodes act as a container for an abitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + + pins, function, bias-disable, bias-pull-down, bias-pull,up, drive-strength, + output-low, output-high. + +Non-empty subnodes must specify the 'pins' property. + +Valid values for pins are: + gpio0-gpio89 + +Valid values for function are: + cam_mclk, codec_mic_i2s, codec_spkr_i2s, gsbi1, gsbi2, gsbi3, gsbi4, + gsbi4_cam_i2c, gsbi5, gsbi5_spi_cs1, gsbi5_spi_cs2, gsbi5_spi_cs3, gsbi6, + gsbi6_spi_cs1, gsbi6_spi_cs2, gsbi6_spi_cs3, gsbi7, gsbi7_spi_cs1, + gsbi7_spi_cs2, gsbi7_spi_cs3, gsbi_cam_i2c, hdmi, mi2s, riva_bt, riva_fm, + riva_wlan, sdc2, sdc4, slimbus, spkr_i2s, tsif1, tsif2, usb2_hsic, + +Example: + + msmgpio: pinctrl@800000 { + compatible = "qcom,apq8064-pinctrl"; + reg = <0x800000 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 32 0x4>; + + pinctrl-names = "default"; + pinctrl-0 = <&gsbi5_uart_default>; + + gsbi5_uart_default: gsbi5_uart_default { + mux { + pins = "gpio51", "gpio52"; + function = "gsbi5"; + }; + + tx { + pins = "gpio51"; + drive-strength = <4>; + bias-disable; + }; + + rx { + pins = "gpio52"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq8064-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,ipq8064-pinctrl.txt new file mode 100644 index 00000000000000..e0d35a40981be7 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq8064-pinctrl.txt @@ -0,0 +1,95 @@ +Qualcomm IPQ8064 TLMM block + +Required properties: +- compatible: "qcom,ipq8064-pinctrl" +- reg: Should be the base address and length of the TLMM block. +- interrupts: Should be the parent IRQ of the TLMM block. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. + The first cell is the gpio pin number and the + second cell is used for optional parameters. + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Qualcomm's pin configuration nodes act as a container for an abitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + + pins, function, bias-disable, bias-pull-down, bias-pull,up, drive-strength, + output-low, output-high. + +Non-empty subnodes must specify the 'pins' property. + +Valid values for qcom,pins are: + gpio0-gpio68 + Supports mux, bias, and drive-strength + + sdc3_clk, sdc3_cmd, sdc3_data + Supports bias and drive-strength + + +Valid values for function are: + mdio, mi2s, pdm, ssbi, spmi, audio_pcm, gsbi1, gsbi2, gsbi4, gsbi5, + gsbi5_spi_cs1, gsbi5_spi_cs2, gsbi5_spi_cs3, gsbi6, gsbi7, nss_spi, sdc1, + spdif, nand, tsif1, tsif2, usb_fs_n, usb_fs, usb2_hsic, rgmii2, sata, + pcie1_rst, pcie1_prsnt, pcie1_pwren_n, pcie1_pwren, pcie1_pwrflt, + pcie1_clk_req, pcie2_rst, pcie2_prsnt, pcie2_pwren_n, pcie2_pwren, + pcie2_pwrflt, pcie2_clk_req, pcie3_rst, pcie3_prsnt, pcie3_pwren_n, + pcie3_pwren, pcie3_pwrflt, pcie3_clk_req, ps_hold + +Example: + + pinmux: pinctrl@800000 { + compatible = "qcom,ipq8064-pinctrl"; + reg = <0x800000 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 32 0x4>; + + pinctrl-names = "default"; + pinctrl-0 = <&gsbi5_uart_default>; + + gsbi5_uart_default: gsbi5_uart_default { + mux { + pins = "gpio18", "gpio19"; + function = "gsbi5"; + }; + + tx { + pins = "gpio18"; + drive-strength = <4>; + bias-disable; + }; + + rx { + pins = "gpio19"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/powerpc/4xx/akebono.txt b/Documentation/devicetree/bindings/powerpc/4xx/akebono.txt new file mode 100644 index 00000000000000..db939210e29dac --- /dev/null +++ b/Documentation/devicetree/bindings/powerpc/4xx/akebono.txt @@ -0,0 +1,54 @@ + +IBM Akebono board device tree +============================= + +The IBM Akebono board is a development board for the PPC476GTR SoC. + +0) The root node + + Required properties: + + - model : "ibm,akebono". + - compatible : "ibm,akebono" , "ibm,476gtr". + +1.a) The Secure Digital Host Controller Interface (SDHCI) node + + Represent the Secure Digital Host Controller Interfaces. + + Required properties: + + - compatible : should be "ibm,476gtr-sdhci","generic-sdhci". + - reg : should contain the SDHCI registers location and length. + - interrupt-parent : a phandle for the interrupt controller. + - interrupts : should contain the SDHCI interrupt. + +1.b) The Advanced Host Controller Interface (AHCI) SATA node + + Represents the advanced host controller SATA interface. + + Required properties: + + - compatible : should be "ibm,476gtr-ahci". + - reg : should contain the AHCI registers location and length. + - interrupt-parent : a phandle for the interrupt controller. + - interrupts : should contain the AHCI interrupt. + +1.c) The FPGA node + + The Akebono board stores some board information such as the revision + number in an FPGA which is represented by this node. + + Required properties: + + - compatible : should be "ibm,akebono-fpga". + - reg : should contain the FPGA registers location and length. + +1.d) The AVR node + + The Akebono board has an Atmel AVR microprocessor attached to the I2C + bus as a power controller for the board. + + Required properties: + + - compatible : should be "ibm,akebono-avr". + - reg : should contain the I2C bus address for the AVR. diff --git a/Documentation/devicetree/bindings/powerpc/4xx/hsta.txt b/Documentation/devicetree/bindings/powerpc/4xx/hsta.txt new file mode 100644 index 00000000000000..c737c8338705c1 --- /dev/null +++ b/Documentation/devicetree/bindings/powerpc/4xx/hsta.txt @@ -0,0 +1,19 @@ + +ppc476gtr High Speed Serial Assist (HSTA) node +============================================== + +The 476gtr SoC contains a high speed serial assist module attached +between the plb4 and plb6 system buses to provide high speed data +transfer between memory and system peripherals as well as support for +PCI message signalled interrupts. + +Currently only the MSI support is used by Linux using the following +device tree entries: + +Require properties: +- compatible : "ibm,476gtr-hsta-msi", "ibm,hsta-msi" +- reg : register mapping for the HSTA MSI space +- interrupt-parent : parent controller for mapping interrupts +- interrupts : ordered interrupt mapping for each MSI in the register + space. The first interrupt should be associated with a + register offset of 0x00, the second to 0x10, etc. diff --git a/Documentation/devicetree/bindings/powerpc/4xx/reboot.txt b/Documentation/devicetree/bindings/powerpc/4xx/reboot.txt index d7217260589cdd..5bc63551319e66 100644 --- a/Documentation/devicetree/bindings/powerpc/4xx/reboot.txt +++ b/Documentation/devicetree/bindings/powerpc/4xx/reboot.txt @@ -1,7 +1,7 @@ Reboot property to control system reboot on PPC4xx systems: By setting "reset_type" to one of the following values, the default -software reset mechanism may be overidden. Here the possible values of +software reset mechanism may be overridden. Here the possible values of "reset_type": 1 - PPC4xx core reset diff --git a/Documentation/devicetree/bindings/powerpc/fsl/dcsr.txt b/Documentation/devicetree/bindings/powerpc/fsl/dcsr.txt index 9d54eb5a295fa8..18a88100af94ba 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/dcsr.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/dcsr.txt @@ -82,7 +82,7 @@ PROPERTIES Which event source asserted the interrupt is captured in an EPU Interrupt Status Register (EPISR0,EPISR1). - Interrupt numbers are lised in order (perfmon, event0, event1). + Interrupt numbers are listed in order (perfmon, event0, event1). - interrupt-parent Usage: required diff --git a/Documentation/devicetree/bindings/pwm/bcm-kona-pwm.txt b/Documentation/devicetree/bindings/pwm/bcm-kona-pwm.txt new file mode 100644 index 00000000000000..8eae9fe7841cf8 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/bcm-kona-pwm.txt @@ -0,0 +1,21 @@ +Broadcom Kona PWM controller device tree bindings + +This controller has 6 channels. + +Required Properties : +- compatible: should contain "brcm,kona-pwm" +- reg: physical base address and length of the controller's registers +- clocks: phandle + clock specifier pair for the external clock +- #pwm-cells: Should be 3. See pwm.txt in this directory for a + description of the cells format. + +Refer to clocks/clock-bindings.txt for generic clock consumer properties. + +Example: + +pwm: pwm@3e01a000 { + compatible = "brcm,bcm11351-pwm", "brcm,kona-pwm"; + reg = <0x3e01a000 0xc4>; + clocks = <&pwm_clk>; + #pwm-cells = <3>; +}; diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index e2c7f1e7251a3a..86074334e342cc 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -12,7 +12,7 @@ Optional properties: - regulator-allow-bypass: allow the regulator to go into bypass mode - -supply: phandle to the parent supply/regulator node - regulator-ramp-delay: ramp delay for regulator(in uV/uS) - For hardwares which support disabling ramp rate, it should be explicitly + For hardware which supports disabling ramp rate, it should be explicitly intialised to zero (regulator-ramp-delay = <0>) for disabling ramp delay. - regulator-enable-ramp-delay: The time taken, in microseconds, for the supply rail to reach the target voltage, plus/minus whatever tolerance the board diff --git a/Documentation/devicetree/bindings/regulator/tps65090.txt b/Documentation/devicetree/bindings/regulator/tps65090.txt index 313a60ba61d8e6..340980239ea9f7 100644 --- a/Documentation/devicetree/bindings/regulator/tps65090.txt +++ b/Documentation/devicetree/bindings/regulator/tps65090.txt @@ -21,6 +21,10 @@ Optional properties: number should be provided. If it is externally controlled and no GPIO entry then driver will just configure this rails as external control and will not provide any enable/disable APIs. +- ti,overcurrent-wait: This is applicable to FET registers, which have a + poorly defined "overcurrent wait" field. If this property is present it + should be between 0 - 3. If this property isn't present we won't touch the + "overcurrent wait" field and we'll leave it to the BIOS/EC to deal with. Each regulator is defined using the standard binding for regulators. diff --git a/Documentation/devicetree/bindings/serial/nxp,sc16is7xx.txt b/Documentation/devicetree/bindings/serial/nxp,sc16is7xx.txt new file mode 100644 index 00000000000000..246c795668dc37 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/nxp,sc16is7xx.txt @@ -0,0 +1,33 @@ +* NXP SC16IS7xx advanced Universal Asynchronous Receiver-Transmitter (UART) + +Required properties: +- compatible: Should be one of the following: + - "nxp,sc16is740" for NXP SC16IS740, + - "nxp,sc16is741" for NXP SC16IS741, + - "nxp,sc16is750" for NXP SC16IS750, + - "nxp,sc16is752" for NXP SC16IS752, + - "nxp,sc16is760" for NXP SC16IS760, + - "nxp,sc16is762" for NXP SC16IS762. +- reg: I2C address of the SC16IS7xx device. +- interrupt-parent: The phandle for the interrupt controller that + services interrupts for this IC. +- interrupts: Should contain the UART interrupt +- clocks: Reference to the IC source clock. + +Optional properties: +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Should be two. The first cell is the GPIO number and + the second cell is used to specify the GPIO polarity: + 0 = active high, + 1 = active low. + +Example: + sc16is750: sc16is750@51 { + compatible = "nxp,sc16is750"; + reg = <0x51>; + clocks = <&clk20m>; + interrupt-parent = <&gpio3>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/sound/ak4104.txt b/Documentation/devicetree/bindings/sound/ak4104.txt index b902ee39cf8973..deca5e18f304bd 100644 --- a/Documentation/devicetree/bindings/sound/ak4104.txt +++ b/Documentation/devicetree/bindings/sound/ak4104.txt @@ -8,6 +8,8 @@ Required properties: - reg : The chip select number on the SPI bus + - vdd-supply : A regulator node, providing 2.7V - 3.6V + Optional properties: - reset-gpio : a GPIO spec for the reset pin. If specified, it will be @@ -19,4 +21,5 @@ spdif: ak4104@0 { compatible = "asahi-kasei,ak4104"; reg = <0>; spi-max-frequency = <5000000>; + vdd-supply = <&vdd_3v3_reg>; }; diff --git a/Documentation/devicetree/bindings/sound/cs42l56.txt b/Documentation/devicetree/bindings/sound/cs42l56.txt new file mode 100644 index 00000000000000..4feb0eb27ea4b6 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs42l56.txt @@ -0,0 +1,63 @@ +CS42L52 audio CODEC + +Required properties: + + - compatible : "cirrus,cs42l56" + + - reg : the I2C address of the device for I2C + + - VA-supply, VCP-supply, VLDO-supply : power supplies for the device, + as covered in Documentation/devicetree/bindings/regulator/regulator.txt. + +Optional properties: + + - cirrus,gpio-nreset : GPIO controller's phandle and the number + of the GPIO used to reset the codec. + + - cirrus,chgfreq-divisor : Values used to set the Charge Pump Frequency. + Allowable values of 0x00 through 0x0F. These are raw values written to the + register, not the actual frequency. The frequency is determined by the following. + Frequency = MCLK / 4 * (N+2) + N = chgfreq_val + MCLK = Where MCLK is the frequency of the mclk signal after the MCLKDIV2 circuit. + + - cirrus,ain1a-ref-cfg, ain1b-ref-cfg : boolean, If present, AIN1A or AIN1B are configured + as a pseudo-differential input referenced to AIN1REF/AIN3A. + + - cirrus,ain2a-ref-cfg, ain2b-ref-cfg : boolean, If present, AIN2A or AIN2B are configured + as a pseudo-differential input referenced to AIN2REF/AIN3B. + + - cirrus,micbias-lvl: Set the output voltage level on the MICBIAS Pin. + 0 = 0.5 x VA + 1 = 0.6 x VA + 2 = 0.7 x VA + 3 = 0.8 x VA + 4 = 0.83 x VA + 5 = 0.91 x VA + + - cirrus,adaptive-pwr-cfg : Configures how the power to the Headphone and Lineout + Amplifiers adapt to the output signal levels. + 0 = Adapt to Volume Mode. Voltage level determined by the sum of the relevant volume settings. + 1 = Fixed - Headphone and Line Amp supply = + or - VCP/2. + 2 = Fixed - Headphone and Line Amp supply = + or - VCP. + 3 = Adapted to Signal; Voltage level is dynamically determined by the output signal. + + - cirrus,hpf-left-freq, hpf-right-freq : Sets the corner frequency (-3dB point) for the internal High-Pass + Filter. + 0 = 1.8Hz + 1 = 119Hz + 2 = 236Hz + 3 = 464Hz + + +Example: + +codec: codec@4b { + compatible = "cirrus,cs42l56"; + reg = <0x4b>; + gpio-reset = <&gpio 10 0>; + cirrus,chgfreq-divisor = <0x05>; + cirrus.ain1_ref_cfg; + cirrus,micbias-lvl = <5>; + VA-supply = <®_audio>; +}; diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 98611a6761c0ad..0f4e23828190f7 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -7,10 +7,11 @@ codec/DSP interfaces. Required properties: -- compatible: Compatible list, contains "fsl,vf610-sai". +- compatible: Compatible list, contains "fsl,vf610-sai" or "fsl,imx6sx-sai". - reg: Offset and length of the register set for the device. - clocks: Must contain an entry for each entry in clock-names. -- clock-names : Must include the "sai" entry. +- clock-names : Must include the "bus" for register access and "mclk1" "mclk2" + "mclk3" for bit clock and frame clock providing. - dmas : Generic dma devicetree binding as described in Documentation/devicetree/bindings/dma/dma.txt. - dma-names : Two dmas have to be defined, "tx" and "rx". @@ -30,8 +31,10 @@ sai2: sai@40031000 { reg = <0x40031000 0x1000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sai2_1>; - clocks = <&clks VF610_CLK_SAI2>; - clock-names = "sai"; + clocks = <&clks VF610_CLK_PLATFORM_BUS>, + <&clks VF610_CLK_SAI2>, + <&clks 0>, <&clks 0>; + clock-names = "bus", "mclk1", "mclk2", "mclk3"; dma-names = "tx", "rx"; dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>, <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>; diff --git a/Documentation/devicetree/bindings/sound/max98095.txt b/Documentation/devicetree/bindings/sound/max98095.txt new file mode 100644 index 00000000000000..bacbeaac72b5dc --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max98095.txt @@ -0,0 +1,16 @@ +MAX98095 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "maxim,max98095". + +- reg : The I2C address of the device. + +Example: + +max98095: codec@11 { + compatible = "maxim,max98095"; + reg = <0x11>; +}; diff --git a/Documentation/devicetree/bindings/sound/nokia,rx51.txt b/Documentation/devicetree/bindings/sound/nokia,rx51.txt new file mode 100644 index 00000000000000..72f93d99627363 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nokia,rx51.txt @@ -0,0 +1,27 @@ +* Nokia N900 audio setup + +Required properties: +- compatible: Should contain "nokia,n900-audio" +- nokia,cpu-dai: phandle for the McBSP node +- nokia,audio-codec: phandles for the main TLV320AIC3X node and the + auxiliary TLV320AIC3X node (in this order) +- nokia,headphone-amplifier: phandle for the TPA6130A2 node +- tvout-selection-gpios: GPIO for tvout selection +- jack-detection-gpios: GPIO for jack detection +- eci-switch-gpios: GPIO for ECI (Enhancement Control Interface) switch +- speaker-amplifier-gpios: GPIO for speaker amplifier + +Example: + +sound { + compatible = "nokia,n900-audio"; + + nokia,cpu-dai = <&mcbsp2>; + nokia,audio-codec = <&tlv320aic3x>, <&tlv320aic3x_aux>; + nokia,headphone-amplifier = <&tpa6130a2>; + + tvout-selection-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>; /* 40 */ + jack-detection-gpios = <&gpio6 17 GPIO_ACTIVE_HIGH>; /* 177 */ + eci-switch-gpios = <&gpio6 22 GPIO_ACTIVE_HIGH>; /* 182 */ + speaker-amplifier-gpios = <&twl_gpio 7 GPIO_ACTIVE_HIGH>; +}; diff --git a/Documentation/devicetree/bindings/sound/rt5640.txt b/Documentation/devicetree/bindings/sound/rt5640.txt index 068a1141b06f19..bac4d9ac1edc8c 100644 --- a/Documentation/devicetree/bindings/sound/rt5640.txt +++ b/Documentation/devicetree/bindings/sound/rt5640.txt @@ -1,10 +1,10 @@ -RT5640 audio CODEC +RT5640/RT5639 audio CODEC This device supports I2C only. Required properties: -- compatible : "realtek,rt5640". +- compatible : One of "realtek,rt5640" or "realtek,rt5639". - reg : The I2C address of the device. @@ -18,7 +18,7 @@ Optional properties: - realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. -Pins on the device (for linking into audio routes): +Pins on the device (for linking into audio routes) for RT5639/RT5640: * DMIC1 * DMIC2 @@ -31,13 +31,16 @@ Pins on the device (for linking into audio routes): * HPOR * LOUTL * LOUTR - * MONOP - * MONON * SPOLP * SPOLN * SPORP * SPORN +Additional pins on the device for RT5640: + + * MONOP + * MONON + Example: rt5640 { diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index 131aa2ad7f1a31..9b9df146fd1a52 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -1,6 +1,6 @@ Simple-Card: -Simple-Card specifies audio DAI connection of SoC <-> codec. +Simple-Card specifies audio DAI connections of SoC <-> codec. Required properties: @@ -10,26 +10,51 @@ Optional properties: - simple-audio-card,name : User specified audio sound card name, one string property. -- simple-audio-card,format : CPU/CODEC common audio format. - "i2s", "right_j", "left_j" , "dsp_a" - "dsp_b", "ac97", "pdm", "msb", "lsb" - simple-audio-card,widgets : Please refer to widgets.txt. - simple-audio-card,routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, the second being the connection's source. -- dai-tdm-slot-num : Please refer to tdm-slot.txt. -- dai-tdm-slot-width : Please refer to tdm-slot.txt. +Optional subnodes: + +- simple-audio-card,dai-link : Container for dai-link level + properties and the CPU and CODEC + sub-nodes. This container may be + omitted when the card has only one + DAI link. See the examples and the + section bellow. + +Dai-link subnode properties and subnodes: + +If dai-link subnode is omitted and the subnode properties are directly +under "sound"-node the subnode property and subnode names have to be +prefixed with "simple-audio-card,"-prefix. -Required subnodes: +Required dai-link subnodes: -- simple-audio-card,dai-link : container for the CPU and CODEC sub-nodes - This container may be omitted when the - card has only one DAI link. - See the examples. +- cpu : CPU sub-node +- codec : CODEC sub-node -- simple-audio-card,cpu : CPU sub-node -- simple-audio-card,codec : CODEC sub-node +Optional dai-link subnode properties: + +- format : CPU/CODEC common audio format. + "i2s", "right_j", "left_j" , "dsp_a" + "dsp_b", "ac97", "pdm", "msb", "lsb" +- frame-master : Indicates dai-link frame master. + phandle to a cpu or codec subnode. +- bitclock-master : Indicates dai-link bit clock master. + phandle to a cpu or codec subnode. +- bitclock-inversion : bool property. Add this if the + dai-link uses bit clock inversion. +- frame-inversion : bool property. Add this if the + dai-link uses frame clock inversion. + +For backward compatibility the frame-master and bitclock-master +properties can be used as booleans in codec subnode to indicate if the +codec is the dai-link frame or bit clock master. In this case there +should be no dai-link node, the same properties should not be present +at sound-node level, and the bitclock-inversion and frame-inversion +properties should also be placed in the codec node if needed. Required CPU/CODEC subnodes properties: @@ -37,29 +62,21 @@ Required CPU/CODEC subnodes properties: Optional CPU/CODEC subnodes properties: -- format : CPU/CODEC specific audio format if needed. - see simple-audio-card,format -- frame-master : bool property. add this if subnode is frame master -- bitclock-master : bool property. add this if subnode is bitclock master -- bitclock-inversion : bool property. add this if subnode has clock inversion -- frame-inversion : bool property. add this if subnode has frame inversion +- dai-tdm-slot-num : Please refer to tdm-slot.txt. +- dai-tdm-slot-width : Please refer to tdm-slot.txt. - clocks / system-clock-frequency : specify subnode's clock if needed. it can be specified via "clocks" if system has clock node (= common clock), or "system-clock-frequency" (if system doens't support common clock) -Note: - * For 'format', 'frame-master', 'bitclock-master', 'bitclock-inversion' and - 'frame-inversion', the simple card will use the settings of CODEC for both - CPU and CODEC sides as we need to keep the settings identical for both ends - of the link. - Example 1 - single DAI link: sound { compatible = "simple-audio-card"; simple-audio-card,name = "VF610-Tower-Sound-Card"; simple-audio-card,format = "left_j"; + simple-audio-card,bitclock-master = <&dailink0_master>; + simple-audio-card,frame-master = <&dailink0_master>; simple-audio-card,widgets = "Microphone", "Microphone Jack", "Headphone", "Headphone Jack", @@ -69,17 +86,12 @@ sound { "Headphone Jack", "HP_OUT", "External Speaker", "LINE_OUT"; - dai-tdm-slot-num = <2>; - dai-tdm-slot-width = <8>; - simple-audio-card,cpu { sound-dai = <&sh_fsi2 0>; }; - simple-audio-card,codec { + dailink0_master: simple-audio-card,codec { sound-dai = <&ak4648>; - bitclock-master; - frame-master; clocks = <&osc>; }; }; @@ -105,31 +117,31 @@ Example 2 - many DAI links: sound { compatible = "simple-audio-card"; simple-audio-card,name = "Cubox Audio"; - simple-audio-card,format = "i2s"; simple-audio-card,dai-link@0 { /* I2S - HDMI */ - simple-audio-card,cpu { + format = "i2s"; + cpu { sound-dai = <&audio1 0>; }; - simple-audio-card,codec { + codec { sound-dai = <&tda998x 0>; }; }; simple-audio-card,dai-link@1 { /* S/PDIF - HDMI */ - simple-audio-card,cpu { + cpu { sound-dai = <&audio1 1>; }; - simple-audio-card,codec { + codec { sound-dai = <&tda998x 1>; }; }; simple-audio-card,dai-link@2 { /* S/PDIF - S/PDIF */ - simple-audio-card,cpu { + cpu { sound-dai = <&audio1 1>; }; - simple-audio-card,codec { + codec { sound-dai = <&spdif_codec>; }; }; diff --git a/Documentation/devicetree/bindings/sound/snow.txt b/Documentation/devicetree/bindings/sound/snow.txt new file mode 100644 index 00000000000000..678b191c37b892 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/snow.txt @@ -0,0 +1,17 @@ +Audio Binding for Snow boards + +Required properties: +- compatible : Can be one of the following, + "google,snow-audio-max98090" or + "google,snow-audio-max98095" +- samsung,i2s-controller: The phandle of the Samsung I2S controller +- samsung,audio-codec: The phandle of the audio codec + +Example: + +sound { + compatible = "google,snow-audio-max98095"; + + samsung,i2s-controller = <&i2s0>; + samsung,audio-codec = <&max98095>; +}; diff --git a/Documentation/devicetree/bindings/sound/st,sta350.txt b/Documentation/devicetree/bindings/sound/st,sta350.txt new file mode 100644 index 00000000000000..b7e71bf5caf4f3 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,sta350.txt @@ -0,0 +1,131 @@ +STA350 audio CODEC + +The driver for this device only supports I2C. + +Required properties: + + - compatible: "st,sta350" + - reg: the I2C address of the device for I2C + - reset-gpios: a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + + - power-down-gpios: a GPIO spec for the power down pin. If specified, + it will be deasserted before communication to the codec + starts. + + - vdd-dig-supply: regulator spec, providing 3.3V + - vdd-pll-supply: regulator spec, providing 3.3V + - vcc-supply: regulator spec, providing 5V - 26V + +Optional properties: + + - st,output-conf: number, Selects the output configuration: + 0: 2-channel (full-bridge) power, 2-channel data-out + 1: 2 (half-bridge). 1 (full-bridge) on-board power + 2: 2 Channel (Full-Bridge) Power, 1 Channel FFX + 3: 1 Channel Mono-Parallel + If parameter is missing, mode 0 will be enabled. + This property has to be specified as '/bits/ 8' value. + + - st,ch1-output-mapping: Channel 1 output mapping + - st,ch2-output-mapping: Channel 2 output mapping + - st,ch3-output-mapping: Channel 3 output mapping + 0: Channel 1 + 1: Channel 2 + 2: Channel 3 + If parameter is missing, channel 1 is choosen. + This properties have to be specified as '/bits/ 8' values. + + - st,thermal-warning-recover: + If present, thermal warning recovery is enabled. + + - st,thermal-warning-adjustment: + If present, thermal warning adjustment is enabled. + + - st,fault-detect-recovery: + If present, then fault recovery will be enabled. + + - st,ffx-power-output-mode: string + The FFX power output mode selects how the FFX output timing is + configured. Must be one of these values: + - "drop-compensation" + - "tapered-compensation" + - "full-power-mode" + - "variable-drop-compensation" (default) + + - st,drop-compensation-ns: number + Only required for "st,ffx-power-output-mode" == + "variable-drop-compensation". + Specifies the drop compensation in nanoseconds. + The value must be in the range of 0..300, and only + multiples of 20 are allowed. Default is 140ns. + + - st,overcurrent-warning-adjustment: + If present, overcurrent warning adjustment is enabled. + + - st,max-power-use-mpcc: + If present, then MPCC bits are used for MPC coefficients, + otherwise standard MPC coefficients are used. + + - st,max-power-corr: + If present, power bridge correction for THD reduction near maximum + power output is enabled. + + - st,am-reduction-mode: + If present, FFX mode runs in AM reduction mode, otherwise normal + FFX mode is used. + + - st,odd-pwm-speed-mode: + If present, PWM speed mode run on odd speed mode (341.3 kHz) on all + channels. If not present, normal PWM spped mode (384 kHz) will be used. + + - st,distortion-compensation: + If present, distortion compensation variable uses DCC coefficient. + If not present, preset DC coefficient is used. + + - st,invalid-input-detect-mute: + If present, automatic invalid input detect mute is enabled. + + - st,activate-mute-output: + If present, a mute output will be activated in ase the volume will + reach a value lower than -76 dBFS. + + - st,bridge-immediate-off: + If present, the bridge will be switched off immediately after the + power-down-gpio goes low. Otherwise, the bridge will wait for 13 + million clock cycles to pass before shutting down. + + - st,noise-shape-dc-cut: + If present, the noise-shaping technique on the DC cutoff filter are + enabled. + + - st,powerdown-master-volume: + If present, the power-down pin and I2C power-down functions will + act on the master volume. Otherwise, the functions will act on the + mute commands. + + - st,powerdown-delay-divider: + If present, the bridge power-down time will be divided by the provided + value. If not specified, a divider of 1 will be used. Allowed values + are 1, 2, 4, 8, 16, 32, 64 and 128. + This property has to be specified as '/bits/ 8' value. + +Example: + +codec: sta350@38 { + compatible = "st,sta350"; + reg = <0x1c>; + reset-gpios = <&gpio1 19 0>; + power-down-gpios = <&gpio1 16 0>; + st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel + // (full-bridge) power, + // 2-channel data-out + st,ch1-output-mapping = /bits/ 8 <0>; // set channel 1 output ch 1 + st,ch2-output-mapping = /bits/ 8 <0>; // set channel 2 output ch 1 + st,ch3-output-mapping = /bits/ 8 <0>; // set channel 3 output ch 1 + st,max-power-correction; // enables power bridge + // correction for THD reduction + // near maximum power output + st,invalid-input-detect-mute; // mute if no valid digital + // audio signal is provided. +}; diff --git a/Documentation/devicetree/bindings/spi/fsl-spi.txt b/Documentation/devicetree/bindings/spi/fsl-spi.txt index b032dd76e9d200..a2331372068cec 100644 --- a/Documentation/devicetree/bindings/spi/fsl-spi.txt +++ b/Documentation/devicetree/bindings/spi/fsl-spi.txt @@ -42,6 +42,10 @@ Required properties: - interrupts : should contain eSPI interrupt, the device has one interrupt. - fsl,espi-num-chipselects : the number of the chipselect signals. +Optional properties: +- fsl,csbef: chip select assertion time in bits before frame starts +- fsl,csaft: chip select negation time in bits after frame ends + Example: spi@110000 { #address-cells = <1>; @@ -51,4 +55,6 @@ Example: interrupts = <53 0x2>; interrupt-parent = <&mpic>; fsl,espi-num-chipselects = <4>; + fsl,csbef = <1>; + fsl,csaft = <1>; }; diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt index e5a4d1b4acfe1e..bbaa857dd68fd9 100644 --- a/Documentation/devicetree/bindings/spi/spi-bus.txt +++ b/Documentation/devicetree/bindings/spi/spi-bus.txt @@ -55,13 +55,15 @@ contain the following properties. chip select active high - spi-3wire - (optional) Empty property indicating device requires 3-wire mode. +- spi-lsb-first - (optional) Empty property indicating device requires + LSB first mode. - spi-tx-bus-width - (optional) The bus width(number of data wires) that used for MOSI. Defaults to 1 if not present. - spi-rx-bus-width - (optional) The bus width(number of data wires) that used for MISO. Defaults to 1 if not present. Some SPI controllers and devices support Dual and Quad SPI transfer mode. -It allows data in SPI system transfered in 2 wires(DUAL) or 4 wires(QUAD). +It allows data in the SPI system to be transferred in 2 wires(DUAL) or 4 wires(QUAD). Now the value that spi-tx-bus-width and spi-rx-bus-width can receive is only 1(SINGLE), 2(DUAL) and 4(QUAD). Dual/Quad mode is not allowed when 3-wire mode is used. diff --git a/Documentation/devicetree/bindings/spi/spi-cadence.txt b/Documentation/devicetree/bindings/spi/spi-cadence.txt new file mode 100644 index 00000000000000..94f09141a4f083 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-cadence.txt @@ -0,0 +1,31 @@ +Cadence SPI controller Device Tree Bindings +------------------------------------------- + +Required properties: +- compatible : Should be "cdns,spi-r1p6" or "xlnx,zynq-spi-r1p6". +- reg : Physical base address and size of SPI registers map. +- interrupts : Property with a value describing the interrupt + number. +- interrupt-parent : Must be core interrupt controller +- clock-names : List of input clock names - "ref_clk", "pclk" + (See clock bindings for details). +- clocks : Clock phandles (see clock bindings for details). + +Optional properties: +- num-cs : Number of chip selects used. + If a decoder is used, this will be the number of + chip selects after the decoder. +- is-decoded-cs : Flag to indicate whether decoder is used or not. + +Example: + + spi@e0007000 { + compatible = "xlnx,zynq-spi-r1p6"; + clock-names = "ref_clk", "pclk"; + clocks = <&clkc 26>, <&clkc 35>; + interrupt-parent = <&intc>; + interrupts = <0 49 4>; + num-cs = <4>; + is-decoded-cs = <0>; + reg = <0xe0007000 0x1000>; + } ; diff --git a/Documentation/devicetree/bindings/spi/spi-dw.txt b/Documentation/devicetree/bindings/spi/spi-dw.txt new file mode 100644 index 00000000000000..7b63ed6019909b --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-dw.txt @@ -0,0 +1,24 @@ +Synopsys DesignWare SPI master + +Required properties: +- compatible: should be "snps,designware-spi" +- #address-cells: see spi-bus.txt +- #size-cells: see spi-bus.txt +- reg: address and length of the spi master registers +- interrupts: should contain one interrupt +- clocks: spi clock phandle +- num-cs: see spi-bus.txt + +Optional properties: +- cs-gpios: see spi-bus.txt + +Example: + +spi: spi@4020a000 { + compatible = "snps,designware-spi"; + interrupts = <11 1>; + reg = <0x4020a000 0x1000>; + clocks = <&pclk>; + num-cs = <2>; + cs-gpios = <&banka 0 0>; +}; diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt index 3be5ce7a965447..e75f0e549fff7c 100644 --- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt +++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt @@ -61,6 +61,7 @@ Required properties: Optional properties: - interface_pix_fmt: How this display is connected to the display interface. Currently supported types: "rgb24", "rgb565", "bgr666" + and "lvds666". - edid: verbatim EDID data block describing attached display. - ddc: phandle describing the i2c bus handling the display data channel diff --git a/Documentation/devicetree/bindings/usb/gr-udc.txt b/Documentation/devicetree/bindings/usb/gr-udc.txt index 0c5118f7a916b7..e9445224fabd97 100644 --- a/Documentation/devicetree/bindings/usb/gr-udc.txt +++ b/Documentation/devicetree/bindings/usb/gr-udc.txt @@ -12,17 +12,23 @@ Required properties: - reg : Address and length of the register set for the device -- interrupts : Interrupt numbers for this device +- interrupts : Interrupt numbers for this device. Either one interrupt number + for all interrupts, or one for status related interrupts, one for IN + endpoint related interrupts and one for OUT endpoint related interrupts. Optional properties: -- epobufsizes : An array of buffer sizes for OUT endpoints. If the property is - not present, or for endpoints outside of the array, 1024 is assumed by - the driver. - -- epibufsizes : An array of buffer sizes for IN endpoints. If the property is - not present, or for endpoints outside of the array, 1024 is assumed by - the driver. +- epobufsizes : Array of buffer sizes for OUT endpoints when they differ + from the default size of 1024. The array is indexed by the OUT endpoint + number. If the property is present it typically contains one entry for + each OUT endpoint of the core. Fewer entries overrides the default sizes + only for as many endpoints as the array contains. + +- epibufsizes : Array of buffer sizes for IN endpoints when they differ + from the default size of 1024. The array is indexed by the IN endpoint + number. If the property is present it typically contains one entry for + each IN endpoint of the core. Fewer entries overrides the default sizes + only for as many endpoints as the array contains. For further information look in the documentation for the GLIB IP core library: http://www.gaisler.com/products/grlib/grip.pdf diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt index 5ea26c631e3ac8..2826f2af503a2c 100644 --- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt @@ -15,3 +15,81 @@ Example EHCI controller device node: usb-phy = <&usb_otg>; }; +USB PHY with optional OTG: + +Required properties: +- compatible: Should contain: + "qcom,usb-otg-ci" for chipsets with ChipIdea 45nm PHY + "qcom,usb-otg-snps" for chipsets with Synopsys 28nm PHY + +- regs: Offset and length of the register set in the memory map +- interrupts: interrupt-specifier for the OTG interrupt. + +- clocks: A list of phandle + clock-specifier pairs for the + clocks listed in clock-names +- clock-names: Should contain the following: + "phy" USB PHY reference clock + "core" Protocol engine clock + "iface" Interface bus clock + "alt_core" Protocol engine clock for targets with asynchronous + reset methodology. (optional) + +- vdccx-supply: phandle to the regulator for the vdd supply for + digital circuit operation. +- v1p8-supply: phandle to the regulator for the 1.8V supply +- v3p3-supply: phandle to the regulator for the 3.3V supply + +- resets: A list of phandle + reset-specifier pairs for the + resets listed in reset-names +- reset-names: Should contain the following: + "phy" USB PHY controller reset + "link" USB LINK controller reset + +- qcom,otg-control: OTG control (VBUS and ID notifications) can be one of + 1 - PHY control + 2 - PMIC control + +Optional properties: +- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" + +- qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device + Mode Eye Diagram test. Start address at which these values will be + written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as + "do not overwrite default value at this address". + For example: qcom,phy-init-sequence = < -1 0x63 >; + Will update only value at address ULPI_EXT_VENDOR_SPECIFIC + 1. + +- qcom,phy-num: Select number of pyco-phy to use, can be one of + 0 - PHY one, default + 1 - Second PHY + Some platforms may have configuration to allow USB + controller work with any of the two HSPHYs present. + +- qcom,vdd-levels: This property must be a list of three integer values + (no, min, max) where each value represents either a voltage + in microvolts or a value corresponding to voltage corner. + +Example HSUSB OTG controller device node: + + usb@f9a55000 { + compatible = "qcom,usb-otg-snps"; + reg = <0xf9a55000 0x400>; + interrupts = <0 134 0>; + dr_mode = "peripheral"; + + clocks = <&gcc GCC_XO_CLK>, <&gcc GCC_USB_HS_SYSTEM_CLK>, + <&gcc GCC_USB_HS_AHB_CLK>; + + clock-names = "phy", "core", "iface"; + + vddcx-supply = <&pm8841_s2_corner>; + v1p8-supply = <&pm8941_l6>; + v3p3-supply = <&pm8941_l24>; + + resets = <&gcc GCC_USB2A_PHY_BCR>, <&gcc GCC_USB_HS_BCR>; + reset-names = "phy", "link"; + + qcom,otg-control = <1>; + qcom,phy-init-sequence = < -1 0x63 >; + qcom,vdd-levels = <1 5 7>; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index abc308083acb20..13fda7212ef28a 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -13,6 +13,7 @@ allwinner Allwinner Technology Co., Ltd. altr Altera Corp. amcc Applied Micro Circuits Corporation (APM, formally AMCC) amd Advanced Micro Devices (AMD), Inc. +ams AMS AG amstaos AMS-Taos Inc. apm Applied Micro Circuits Corporation (APM) arm ARM Ltd. @@ -123,6 +124,7 @@ stericsson ST-Ericsson synology Synology, Inc. ti Texas Instruments tlm Trusted Logic Mobility +toradex Toradex AG toshiba Toshiba Corporation toumaz Toumaz usi Universal Scientifc Industrial Co., Ltd. diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt index 505e71172ae7f1..67a4087d53f9c7 100644 --- a/Documentation/dma-buf-sharing.txt +++ b/Documentation/dma-buf-sharing.txt @@ -66,7 +66,7 @@ The dma_buf buffer sharing API usage contains the following steps: Exporting modules which do not wish to provide any specific name may use the helper define 'dma_buf_export()', with the same arguments as above, but - without the last argument; a __FILE__ pre-processor directive will be + without the last argument; a KBUILD_MODNAME pre-processor directive will be inserted in place of 'exp_name' instead. 2. Userspace gets a handle to pass around to potential buffer-users @@ -217,7 +217,7 @@ NOTES: and then allow further {map,unmap}_dma_buf operations from any buffer-user from the migrated backing-storage. - If the exporter cannot fulfil the backing-storage constraints of the new + If the exporter cannot fulfill the backing-storage constraints of the new buffer-user device as requested, dma_buf_attach() would return an error to denote non-compatibility of the new buffer-sharing request with the current buffer. @@ -352,7 +352,7 @@ Being able to mmap an export dma-buf buffer object has 2 main use-cases: No special interfaces, userspace simply calls mmap on the dma-buf fd. -2. Supporting existing mmap interfaces in exporters +2. Supporting existing mmap interfaces in importers Similar to the motivation for kernel cpu access it is again important that the userspace code of a given importing subsystem can use the same interfaces diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 4f7897e99cba8a..d483f2cf221ba5 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -236,6 +236,7 @@ certainly invest a bit more effort into libata core layer). MEM devm_kzalloc() devm_kfree() + devm_kmemdup() IIO devm_iio_device_alloc() @@ -308,3 +309,8 @@ SLAVE DMA ENGINE SPI devm_spi_register_master() + +MDIO + devm_mdiobus_alloc() + devm_mdiobus_alloc_size() + devm_mdiobus_free() diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt index 46325eb2ea766c..9417871b8758f2 100644 --- a/Documentation/dynamic-debug-howto.txt +++ b/Documentation/dynamic-debug-howto.txt @@ -321,7 +321,7 @@ nullarbor:~ # echo -n 'func svc_process -p' > nullarbor:~ # echo -n 'format "nfsd: READ" +p' > /dynamic_debug/control -// enable messages in files of which the pathes include string "usb" +// enable messages in files of which the paths include string "usb" nullarbor:~ # echo -n '*usb* +p' > /dynamic_debug/control // enable all messages diff --git a/Documentation/edac.txt b/Documentation/edac.txt index cb4c2cefd45a45..73fff13e848f42 100644 --- a/Documentation/edac.txt +++ b/Documentation/edac.txt @@ -550,7 +550,7 @@ installs itself as: /sys/devices/systm/edac/test-instance in this directory are various controls, a symlink and one or more 'instance' -directorys. +directories. The standard default controls are: diff --git a/Documentation/email-clients.txt b/Documentation/email-clients.txt index e9f5daccbd02e2..4e30ebaa9e5b26 100644 --- a/Documentation/email-clients.txt +++ b/Documentation/email-clients.txt @@ -201,20 +201,15 @@ To beat some sense out of the internal editor, do this: - Edit your Thunderbird config settings so that it won't use format=flowed. Go to "edit->preferences->advanced->config editor" to bring up the - thunderbird's registry editor, and set "mailnews.send_plaintext_flowed" to - "false". + thunderbird's registry editor. -- Disable HTML Format: Set "mail.identity.id1.compose_html" to "false". +- Set "mailnews.send_plaintext_flowed" to "false" -- Enable "preformat" mode: Set "editor.quotesPreformatted" to "true". +- Set "mailnews.wraplength" from "72" to "0" -- Enable UTF8: Set "prefs.converted-to-utf8" to "true". +- "View" > "Message Body As" > "Plain Text" -- Install the "toggle wordwrap" extension. Download the file from: - https://addons.mozilla.org/thunderbird/addon/2351/ - Then go to "tools->add ons", select "install" at the bottom of the screen, - and browse to where you saved the .xul file. This adds an "Enable - Wordwrap" entry under the Options menu of the message composer. +- "View" > "Character Encoding" > "Unicode (UTF-8)" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TkRat (GUI) diff --git a/Documentation/fb/sm501.txt b/Documentation/fb/sm501.txt index 8d17aebd26487c..187f3b3ccb6cdd 100644 --- a/Documentation/fb/sm501.txt +++ b/Documentation/fb/sm501.txt @@ -3,7 +3,7 @@ Configuration: You can pass the following kernel command line options to sm501 videoframebuffer: sm501fb.bpp= SM501 Display driver: - Specifiy bits-per-pixel if not specified by 'mode' + Specify bits-per-pixel if not specified by 'mode' sm501fb.mode= SM501 Display driver: Specify resolution as diff --git a/Documentation/fb/sstfb.txt b/Documentation/fb/sstfb.txt index 550ca775a4cbbe..13db1075e4a5cc 100644 --- a/Documentation/fb/sstfb.txt +++ b/Documentation/fb/sstfb.txt @@ -10,7 +10,7 @@ Introduction The main page is located at , and if you want the latest version, check out the CVS, as the driver is a work in progress, I feel uncomfortable with releasing tarballs of something - not completely working...Don't worry, it's still more than useable + not completely working...Don't worry, it's still more than usable (I eat my own dog food) Please read the Bug section, and report any success or failure to me diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index eba7901342531d..b18dd17790299d 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -196,8 +196,7 @@ prototypes: void (*invalidatepage) (struct page *, unsigned int, unsigned int); int (*releasepage) (struct page *, int); void (*freepage)(struct page *); - int (*direct_IO)(int, struct kiocb *, const struct iovec *iov, - loff_t offset, unsigned long nr_segs); + int (*direct_IO)(int, struct kiocb *, struct iov_iter *iter, loff_t offset); int (*get_xip_mem)(struct address_space *, pgoff_t, int, void **, unsigned long *); int (*migratepage)(struct address_space *, struct page *, struct page *); @@ -431,6 +430,8 @@ prototypes: ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); + ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); + ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 8b9cd8eb3f917e..fc34f50ba54aac 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -234,7 +234,7 @@ Table 1-2: Contents of the status files (as of 2.6.30-rc7) ShdPnd bitmap of shared pending signals for the process SigBlk bitmap of blocked signals SigIgn bitmap of ignored signals - SigCgt bitmap of catched signals + SigCgt bitmap of caught signals CapInh bitmap of inheritable capabilities CapPrm bitmap of permitted capabilities CapEff bitmap of effective capabilities @@ -300,7 +300,7 @@ Table 1-4: Contents of the stat files (as of 2.6.30-rc7) pending bitmap of pending signals blocked bitmap of blocked signals sigign bitmap of ignored signals - sigcatch bitmap of catched signals + sigcatch bitmap of caught signals wchan address where process went to sleep 0 (place holder) 0 (place holder) @@ -1245,8 +1245,9 @@ second). The meanings of the columns are as follows, from left to right: The "intr" line gives counts of interrupts serviced since boot time, for each of the possible system interrupts. The first column is the total of all -interrupts serviced; each subsequent column is the total for that particular -interrupt. +interrupts serviced including unnumbered architecture specific interrupts; +each subsequent column is the total for that particular numbered interrupt. +Unnumbered interrupts are not shown, only summed into the total. The "ctxt" line gives the total number of context switches across all CPUs. diff --git a/Documentation/filesystems/sharedsubtree.txt b/Documentation/filesystems/sharedsubtree.txt index 4ede421c9687a7..32a173dd315801 100644 --- a/Documentation/filesystems/sharedsubtree.txt +++ b/Documentation/filesystems/sharedsubtree.txt @@ -727,7 +727,7 @@ replicas continue to be exactly same. mkdir -p /tmp/m3 mount --rbind /root /tmp/m3 - I wont' draw the tree..but it has 24 vfsmounts + I won't draw the tree..but it has 24 vfsmounts at step i the number of vfsmounts is V[i] = i*V[i-1]. diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 617f6d70c0778c..a1d0d7a301657d 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -589,8 +589,7 @@ struct address_space_operations { void (*invalidatepage) (struct page *, unsigned int, unsigned int); int (*releasepage) (struct page *, int); void (*freepage)(struct page *); - ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov, - loff_t offset, unsigned long nr_segs); + ssize_t (*direct_IO)(int, struct kiocb *, struct iov_iter *iter, loff_t offset); struct page* (*get_xip_page)(struct address_space *, sector_t, int); /* migrate the contents of a page to the specified target */ @@ -807,6 +806,8 @@ struct file_operations { ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); + ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); + ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); @@ -837,11 +838,15 @@ otherwise noted. read: called by read(2) and related system calls - aio_read: called by io_submit(2) and other asynchronous I/O operations + aio_read: vectored, possibly asynchronous read + + read_iter: possibly asynchronous read with iov_iter as destination write: called by write(2) and related system calls - aio_write: called by io_submit(2) and other asynchronous I/O operations + aio_write: vectored, possibly asynchronous write + + write_iter: possibly asynchronous write with iov_iter as source iterate: called when the VFS needs to read the directory contents diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index 09854fe5930787..d8abfc31abbebf 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -41,7 +41,7 @@ Both functions return either a valid GPIO descriptor, or an error code checkable with IS_ERR() (they will never return a NULL pointer). -ENOENT will be returned if and only if no GPIO has been assigned to the device/function/index triplet, other error codes are used for cases where a GPIO has been assigned but an error -occured while trying to acquire it. This is useful to discriminate between mere +occurred while trying to acquire it. This is useful to discriminate between mere errors and an absence of GPIO for optional GPIO parameters. Device-managed variants of these functions are also defined: diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt index f73cc7b5dc853d..fa9a0a8b373482 100644 --- a/Documentation/gpio/driver.txt +++ b/Documentation/gpio/driver.txt @@ -73,6 +73,65 @@ The IRQ portions of the GPIO block are implemented using an irqchip, using the header . So basically such a driver is utilizing two sub- systems simultaneously: gpio and irq. +GPIO irqchips usually fall in one of two categories: + +* CHAINED GPIO irqchips: these are usually the type that is embedded on + an SoC. This means that there is a fast IRQ handler for the GPIOs that + gets called in a chain from the parent IRQ handler, most typically the + system interrupt controller. This means the GPIO irqchip is registered + using irq_set_chained_handler() or the corresponding + gpiochip_set_chained_irqchip() helper function, and the GPIO irqchip + handler will be called immediately from the parent irqchip, while + holding the IRQs disabled. The GPIO irqchip will then end up calling + something like this sequence in its interrupt handler: + + static irqreturn_t tc3589x_gpio_irq(int irq, void *data) + chained_irq_enter(...); + generic_handle_irq(...); + chained_irq_exit(...); + + Chained GPIO irqchips typically can NOT set the .can_sleep flag on + struct gpio_chip, as everything happens directly in the callbacks. + +* NESTED THREADED GPIO irqchips: these are off-chip GPIO expanders and any + other GPIO irqchip residing on the other side of a sleeping bus. Of course + such drivers that need slow bus traffic to read out IRQ status and similar, + traffic which may in turn incur other IRQs to happen, cannot be handled + in a quick IRQ handler with IRQs disabled. Instead they need to spawn a + thread and then mask the parent IRQ line until the interrupt is handled + by the driver. The hallmark of this driver is to call something like + this in its interrupt handler: + + static irqreturn_t tc3589x_gpio_irq(int irq, void *data) + ... + handle_nested_irq(irq); + + The hallmark of threaded GPIO irqchips is that they set the .can_sleep + flag on struct gpio_chip to true, indicating that this chip may sleep + when accessing the GPIOs. + +To help out in handling the set-up and management of GPIO irqchips and the +associated irqdomain and resource allocation callbacks, the gpiolib has +some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig +symbol: + +* gpiochip_irqchip_add(): adds an irqchip to a gpiochip. It will pass + the struct gpio_chip* for the chip to all IRQ callbacks, so the callbacks + need to embed the gpio_chip in its state container and obtain a pointer + to the container using container_of(). + (See Documentation/driver-model/design-patterns.txt) + +* gpiochip_set_chained_irqchip(): sets up a chained irq handler for a + gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler + data. (Notice handler data, since the irqchip data is likely used by the + parent irqchip!) This is for the chained type of chip. + +To use the helpers please keep the following in mind: + +- Make sure to assign all relevant members of the struct gpio_chip so that + the irqchip can initialize. E.g. .dev and .can_sleep shall be set up + properly. + It is legal for any IRQ consumer to request an IRQ from any irqchip no matter if that is a combined GPIO+IRQ driver. The basic premise is that gpio_chip and irq_chip are orthogonal, and offering their services independent of each diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt index ee6593608c8efd..54c8f9706a9526 100644 --- a/Documentation/hid/uhid.txt +++ b/Documentation/hid/uhid.txt @@ -125,7 +125,7 @@ the request was handled successfully. read() ------ -read() will return a queued ouput report. These output reports can be of type +read() will return a queued output report. These output reports can be of type UHID_START, UHID_STOP, UHID_OPEN, UHID_CLOSE, UHID_OUTPUT or UHID_OUTPUT_EV. No reaction is required to any of them but you should handle them according to your needs. Only UHID_OUTPUT and UHID_OUTPUT_EV have payloads. diff --git a/Documentation/hsi.txt b/Documentation/hsi.txt new file mode 100644 index 00000000000000..6ac6cd51852af5 --- /dev/null +++ b/Documentation/hsi.txt @@ -0,0 +1,75 @@ +HSI - High-speed Synchronous Serial Interface + +1. Introduction +~~~~~~~~~~~~~~~ + +High Speed Syncronous Interface (HSI) is a fullduplex, low latency protocol, +that is optimized for die-level interconnect between an Application Processor +and a Baseband chipset. It has been specified by the MIPI alliance in 2003 and +implemented by multiple vendors since then. + +The HSI interface supports full duplex communication over multiple channels +(typically 8) and is capable of reaching speeds up to 200 Mbit/s. + +The serial protocol uses two signals, DATA and FLAG as combined data and clock +signals and an additional READY signal for flow control. An additional WAKE +signal can be used to wakeup the chips from standby modes. The signals are +commonly prefixed by AC for signals going from the application die to the +cellular die and CA for signals going the other way around. + ++------------+ +---------------+ +| Cellular | | Application | +| Die | | Die | +| | - - - - - - CAWAKE - - - - - - >| | +| T|------------ CADATA ------------>|R | +| X|------------ CAFLAG ------------>|X | +| |<----------- ACREADY ------------| | +| | | | +| | | | +| |< - - - - - ACWAKE - - - - - - -| | +| R|<----------- ACDATA -------------|T | +| X|<----------- ACFLAG -------------|X | +| |------------ CAREADY ----------->| | +| | | | +| | | | ++------------+ +---------------+ + +2. HSI Subsystem in Linux +~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the Linux kernel the hsi subsystem is supposed to be used for HSI devices. +The hsi subsystem contains drivers for hsi controllers including support for +multi-port controllers and provides a generic API for using the HSI ports. + +It also contains HSI client drivers, which make use of the generic API to +implement a protocol used on the HSI interface. These client drivers can +use an arbitrary number of channels. + +3. hsi-char Device +~~~~~~~~~~~~~~~~~~ + +Each port automatically registers a generic client driver called hsi_char, +which provides a charecter device for userspace representing the HSI port. +It can be used to communicate via HSI from userspace. Userspace may +configure the hsi_char device using the following ioctl commands: + +* HSC_RESET: + - flush the HSI port + +* HSC_SET_PM + - enable or disable the client. + +* HSC_SEND_BREAK + - send break + +* HSC_SET_RX + - set RX configuration + +* HSC_GET_RX + - get RX configuration + +* HSC_SET_TX + - set TX configuration + +* HSC_GET_TX + - get TX configuration diff --git a/Documentation/hwmon/lm77 b/Documentation/hwmon/lm77 index 57c3a46d637096..bfc915fe3639e8 100644 --- a/Documentation/hwmon/lm77 +++ b/Documentation/hwmon/lm77 @@ -18,5 +18,21 @@ sensor incorporates a band-gap type temperature sensor, 10-bit ADC, and a digital comparator with user-programmable upper and lower limit values. -Limits can be set through the Overtemperature Shutdown register and -Hysteresis register. +The LM77 implements 3 limits: low (temp1_min), high (temp1_max) and +critical (temp1_crit.) It also implements an hysteresis mechanism which +applies to all 3 limits. The relative difference is stored in a single +register on the chip, which means that the relative difference between +the limit and its hysteresis is always the same for all 3 limits. + +This implementation detail implies the following: +* When setting a limit, its hysteresis will automatically follow, the + difference staying unchanged. For example, if the old critical limit + was 80 degrees C, and the hysteresis was 75 degrees C, and you change + the critical limit to 90 degrees C, then the hysteresis will + automatically change to 85 degrees C. +* All 3 hysteresis can't be set independently. We decided to make + temp1_crit_hyst writable, while temp1_min_hyst and temp1_max_hyst are + read-only. Setting temp1_crit_hyst writes the difference between + temp1_crit_hyst and temp1_crit into the chip, and the same relative + hysteresis applies automatically to the low and high limits. +* The limits should be set before the hysteresis. diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt index e544c7ff8cfa5c..90bca6f988e115 100644 --- a/Documentation/input/alps.txt +++ b/Documentation/input/alps.txt @@ -94,7 +94,7 @@ PS/2 packet format Note that the device never signals overflow condition. -ALPS Absolute Mode - Protocol Verion 1 +ALPS Absolute Mode - Protocol Version 1 -------------------------------------- byte 0: 1 0 0 0 1 x9 x8 x7 diff --git a/Documentation/input/input.txt b/Documentation/input/input.txt index 666c06c5ab0c22..0acfddbe202816 100644 --- a/Documentation/input/input.txt +++ b/Documentation/input/input.txt @@ -226,7 +226,7 @@ And so on up to js31. ~~~~~~~~~~~ evdev is the generic input event interface. It passes the events generated in the kernel straight to the program, with timestamps. The -API is still evolving, but should be useable now. It's described in +API is still evolving, but should be usable now. It's described in section 5. This should be the way for GPM and X to get keyboard and mouse diff --git a/Documentation/java.txt b/Documentation/java.txt index e6a72328154783..418020584ccc17 100644 --- a/Documentation/java.txt +++ b/Documentation/java.txt @@ -188,6 +188,9 @@ shift #define CP_METHODREF 10 #define CP_INTERFACEMETHODREF 11 #define CP_NAMEANDTYPE 12 +#define CP_METHODHANDLE 15 +#define CP_METHODTYPE 16 +#define CP_INVOKEDYNAMIC 18 /* Define some commonly used error messages */ @@ -242,14 +245,19 @@ void skip_constant(FILE *classfile, u_int16_t *cur) break; case CP_CLASS: case CP_STRING: + case CP_METHODTYPE: seekerr = fseek(classfile, 2, SEEK_CUR); break; + case CP_METHODHANDLE: + seekerr = fseek(classfile, 3, SEEK_CUR); + break; case CP_INTEGER: case CP_FLOAT: case CP_FIELDREF: case CP_METHODREF: case CP_INTERFACEMETHODREF: case CP_NAMEANDTYPE: + case CP_INVOKEDYNAMIC: seekerr = fseek(classfile, 4, SEEK_CUR); break; case CP_LONG: diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a07f0e1f6cdfef..9c5bc260aa231e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -237,7 +237,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. This feature is enabled by default. This option allows to turn off the feature. - acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT + acpi_no_static_ssdt [HW,ACPI] + Disable installation of static SSDTs at early boot time + By default, SSDTs contained in the RSDT/XSDT will be + installed automatically and they will appear under + /sys/firmware/acpi/tables. + This option turns off this feature. + Note that specifying this option does not affect + dynamic table installation which will install SSDT + tables to /sys/firmware/acpi/tables/dynamic. acpica_no_return_repair [HW, ACPI] Disable AML predefined validation mechanism @@ -886,6 +894,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. which are not unmapped. earlycon= [KNL] Output early console device and options. + uart[8250],io,[,options] uart[8250],mmio,[,options] uart[8250],mmio32,[,options] @@ -895,6 +904,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. (mmio) or 32-bit (mmio32). The options are the same as for ttyS, above. + pl011, + Start an early, polled-mode console on a pl011 serial + port at the specified address. The pl011 serial port + must already be setup and configured. Options are not + yet supported. + + smh Use ARM semihosting calls for early console. + earlyprintk= [X86,SH,BLACKFIN,ARM] earlyprintk=vga earlyprintk=efi @@ -3476,7 +3493,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. the allocated input device; If set to 0, video driver will only send out the event without touching backlight brightness level. - default: 1 + default: 0 virtio_mmio.device= [VMMIO] Memory mapped virtio (platform) device. diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt index 0cfb00fd86ffd7..4bbeca8483ed33 100644 --- a/Documentation/kprobes.txt +++ b/Documentation/kprobes.txt @@ -22,8 +22,9 @@ Appendix B: The kprobes sysctl interface Kprobes enables you to dynamically break into any kernel routine and collect debugging and performance information non-disruptively. You -can trap at almost any kernel code address, specifying a handler +can trap at almost any kernel code address(*), specifying a handler routine to be invoked when the breakpoint is hit. +(*: some parts of the kernel code can not be trapped, see 1.5 Blacklist) There are currently three types of probes: kprobes, jprobes, and kretprobes (also called return probes). A kprobe can be inserted @@ -273,6 +274,19 @@ using one of the following techniques: or - Execute 'sysctl -w debug.kprobes_optimization=n' +1.5 Blacklist + +Kprobes can probe most of the kernel except itself. This means +that there are some functions where kprobes cannot probe. Probing +(trapping) such functions can cause a recursive trap (e.g. double +fault) or the nested probe handler may never be called. +Kprobes manages such functions as a blacklist. +If you want to add a function into the blacklist, you just need +to (1) include linux/kprobes.h and (2) use NOKPROBE_SYMBOL() macro +to specify a blacklisted function. +Kprobes checks the given probe address against the blacklist and +rejects registering it, if the given address is in the blacklist. + 2. Architectures Supported Kprobes, jprobes, and return probes are implemented on the following diff --git a/Documentation/lto-build b/Documentation/lto-build new file mode 100644 index 00000000000000..5dcce1e9cc2563 --- /dev/null +++ b/Documentation/lto-build @@ -0,0 +1,173 @@ +Link time optimization (LTO) for the Linux kernel + +This is an experimental feature. + +Link Time Optimization allows the compiler to optimize the complete program +instead of just each file. LTO requires at least gcc 4.8 (but +works more efficiently with 4.9+) LTO requires Linux binutils (the normal FSF +releases used in many distributions do not work at the moment) + +The compiler can inline functions between files and do various other global +optimizations, like specializing functions for common parameters, +determing when global variables are clobbered, making functions pure/const, +propagating constants globally, removing unneeded data and others. + +It will also drop unused functions which can make the kernel +image smaller in some circumstances, in particular for small kernel +configurations. + +For small monolithic kernels it can throw away unused code very effectively +(especially when modules are disabled) and usually shrinks +the code size. + +Build time and memory consumption at build time will increase, depending +on the size of the largest binary. Modular kernels are less affected. +With LTO incremental builds are less incremental, as always the whole +binary needs to be re-optimized (but not re-parsed) + +Oops can be somewhat more difficult to read, due to the more aggressive +inlining. + +Normal "reasonable" builds work with less than 4GB of RAM, but very large +configurations like allyesconfig may need more memory. The actual +memory needed depends on the available memory (gcc sizes its garbage +collector pools based on that or on the ulimit -m limits) and +the compiler version. + +gcc 4.9+ has much better build performance and less memory consumption + +- A few kernel features are currently incompatible with LTO, in particular +function tracing, because they require special compiler flags for +specific files, which is not supported in LTO right now. +- Jobserver control for -j does not work correctly for the final +LTO phase due to some problems with the kernel's pipe code. +The makefiles hard codes -j for the final +LTO phase to work around for this + +Configuration: +- Enable CONFIG_LTO_MENU and then disable CONFIG_LTO_DISABLE. +This is mainly to not have allyesconfig default to LTO. +- FUNCTION_TRACER, STACK_TRACER, FUNCTION_GRAPH_TRACER, KALLSYMS_ALL, GCOV +have to disabled because they are currently incompatible with LTO. +- MODVERSIONS have to be disabled (may work with 4.9+) + +Requirements: +- Enough memory: 4GB for a standard build, more for allyesconfig +The peak memory usage happens single threaded (when lto-wpa merges types), +so dialing back -j options will not help much. + +A 32bit compiler is unlikely to work due to the memory requirements. +You can however build a kernel targeted at 32bit on a 64bit host. + +Example build procedure: + +Simplified procedure for distributions that have gcc 4.8, but not +the Linux binutils (for example openSUSE 13.1 or FC20): + +The LTO builds requires gcc-nm/gcc-ar. Some distributions ship +those in separate packages, which may need to be explicitely installed. + +- Get the latest Linux binutils from +http://www.kernel.org/pub/linux/devel/binutils/ +and unpack it. + +We install it in a separate directory to not overwrite the system binutils. + +# replace VERSION with respective version numbers + +cd binutils* +# don't forget the --enable-plugins! +./configure --prefix=/opt/binutils-VERSION --enable-plugins +make -j $(getconf _NPROCESSORS_ONLN) && sudo make install + +Fix up the kernel configuration to allow LTO: + + +./source/scripts/config --disable function_tracer \ + --disable function_graph_tracer \ + --disable stack_tracer --enable lto_menu \ + --disable lto_disable \ + --disable gcov \ + --disable kallsyms_all \ + --disable modversions +make oldconfig + +Then you can build with + +# The COMPILER_PATH is needed to let gcc use the new binutils +# as the LTO plugin linker +# if you installed gcc in a separate directory like below also +# add it to the PATH line below before the regular $PATH +# The COMPILER_PATH setting is only needed if the gcc was not built +# with --with-plugin-ld pointing to the Linux binutils ld +# The AR/NM setting works around a Makefile bug +COMPILER_PATH=/opt/binutils-VERSION/bin PATH=$COMPILER_PATH:$PATH \ +make -j$(getconf _NPROCESSORS_ONLN) AR=gcc-ar NM=gcc-nm + +If you don't have gcc 4.8+ as system compiler you would also need +to install that compiler. In this case I recommend getting +a gcc 4.9+ snapshot from http://gcc.gnu.org (or release when available), +as it builds much faster for LTO than 4.8. + +Here's an example build procedure: + +Assuming gcc is unpacked in gcc-VERSION + +cd gcc-VERSION +./contrib/download_preqrequisites +cd .. + +mkdir obj-gcc +# please don't skip this cd. the build will not work correctly in the +# source dir, you have to use the separate object dir +cd obj-gcc +../gcc-VERSION/configure --prefix=/opt/gcc-VERSION --enable-lto \ +--with-plugin-ld=/opt/binutils-VERSION/bin/ld +--disable-nls --enable-languages=c,c++ \ +--disable-libstdcxx-pch +make -j$(getconf _NPROCESSORS_ONLN) +sudo make install-no-fixedincludes + +FAQs: + +Q: I get a section type attribute conflict +A: Usually because of someone doing +const __initdata (should be const __initconst) or const __read_mostly +(should be just const). Check both symbols reported by gcc. + +Q: I see lots of undefined symbols for memcmp etc. +A: Usually because NM=gcc-nm AR=gcc-ar are missing. +The Makefile tries to set those automatically, but it doesn't always +work. Better to set it manually on the make command line. + +Q: It's quite slow / uses too much memory. +A: Consider a gcc 4.9 snapshot/release (not released yet) +The main problem in 4.8 is the type merging in the single threaded WPA pass, +which has been improved considerably in 4.9 by running it distributed. + +Q: It's still slow +A: It'll always be somewhat slower than non LTO sorry. + +Q: What's up with .XXXXX numeric post fixes +A: This is due LTO turning (near) all symbols to static +Use gcc 4.9, it avoids them in most cases. They are also filtered out +in kallsyms. + +References: + +Presentation on Kernel LTO +(note, performance numbers/details outdated. In particular gcc 4.9 fixed +most of the build time problems): +http://halobates.de/kernel-lto.pdf + +Generic gcc LTO: +http://www.ucw.cz/~hubicka/slides/labs2013.pdf +http://www.hipeac.net/system/files/barcelona.pdf + +Somewhat outdated too: +http://gcc.gnu.org/projects/lto/lto.pdf +http://gcc.gnu.org/projects/lto/whopr.pdf + +Happy Link-Time-Optimizing! + +Andi Kleen diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 556f951f862602..46412bded104ba 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -1583,20 +1583,21 @@ There are some more advanced barrier functions: insert anything more than a compiler barrier in a UP compilation. - (*) smp_mb__before_atomic_dec(); - (*) smp_mb__after_atomic_dec(); - (*) smp_mb__before_atomic_inc(); - (*) smp_mb__after_atomic_inc(); + (*) smp_mb__before_atomic(); + (*) smp_mb__after_atomic(); - These are for use with atomic add, subtract, increment and decrement - functions that don't return a value, especially when used for reference - counting. These functions do not imply memory barriers. + These are for use with atomic (such as add, subtract, increment and + decrement) functions that don't return a value, especially when used for + reference counting. These functions do not imply memory barriers. + + These are also used for atomic bitop functions that do not return a + value (such as set_bit and clear_bit). As an example, consider a piece of code that marks an object as being dead and then decrements the object's reference count: obj->dead = 1; - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_dec(&obj->ref_count); This makes sure that the death mark on the object is perceived to be set @@ -1606,27 +1607,6 @@ There are some more advanced barrier functions: operations" subsection for information on where to use these. - (*) smp_mb__before_clear_bit(void); - (*) smp_mb__after_clear_bit(void); - - These are for use similar to the atomic inc/dec barriers. These are - typically used for bitwise unlocking operations, so care must be taken as - there are no implicit memory barriers here either. - - Consider implementing an unlock operation of some nature by clearing a - locking bit. The clear_bit() would then need to be barriered like this: - - smp_mb__before_clear_bit(); - clear_bit( ... ); - - This prevents memory operations before the clear leaking to after it. See - the subsection on "Locking Functions" with reference to RELEASE operation - implications. - - See Documentation/atomic_ops.txt for more information. See the "Atomic - operations" subsection for information on where to use these. - - MMIO WRITE BARRIER ------------------ @@ -2283,11 +2263,11 @@ operations: change_bit(); With these the appropriate explicit memory barrier should be used if necessary -(smp_mb__before_clear_bit() for instance). +(smp_mb__before_atomic() for instance). The following also do _not_ imply memory barriers, and so may require explicit -memory barriers under some circumstances (smp_mb__before_atomic_dec() for +memory barriers under some circumstances (smp_mb__before_atomic() for instance): atomic_add(); diff --git a/Documentation/mtd/nand/pxa3xx-nand.txt b/Documentation/mtd/nand/pxa3xx-nand.txt index 840fd41c181b98..1074cbc67ec682 100644 --- a/Documentation/mtd/nand/pxa3xx-nand.txt +++ b/Documentation/mtd/nand/pxa3xx-nand.txt @@ -48,7 +48,7 @@ configurable between two modes: 1) Hamming, 2) BCH. Note that the actual BCH mode: BCH-4 or BCH-8 will depend on the way the controller is configured to transfer the data. -In the BCH mode the ECC code will be calculated for each transfered chunk +In the BCH mode the ECC code will be calculated for each transferred chunk and expected to be located (when reading/programming) right after the spare bytes as the figure above shows. diff --git a/Documentation/mtd/spi-nor.txt b/Documentation/mtd/spi-nor.txt new file mode 100644 index 00000000000000..548d6306ebcaeb --- /dev/null +++ b/Documentation/mtd/spi-nor.txt @@ -0,0 +1,62 @@ + SPI NOR framework + ============================================ + +Part I - Why do we need this framework? +--------------------------------------- + +SPI bus controllers (drivers/spi/) only deal with streams of bytes; the bus +controller operates agnostic of the specific device attached. However, some +controllers (such as Freescale's QuadSPI controller) cannot easily handle +arbitrary streams of bytes, but rather are designed specifically for SPI NOR. + +In particular, Freescale's QuadSPI controller must know the NOR commands to +find the right LUT sequence. Unfortunately, the SPI subsystem has no notion of +opcodes, addresses, or data payloads; a SPI controller simply knows to send or +receive bytes (Tx and Rx). Therefore, we must define a new layering scheme under +which the controller driver is aware of the opcodes, addressing, and other +details of the SPI NOR protocol. + +Part II - How does the framework work? +-------------------------------------- + +This framework just adds a new layer between the MTD and the SPI bus driver. +With this new layer, the SPI NOR controller driver does not depend on the +m25p80 code anymore. + + Before this framework, the layer is like: + + MTD + ------------------------ + m25p80 + ------------------------ + SPI bus driver + ------------------------ + SPI NOR chip + + After this framework, the layer is like: + MTD + ------------------------ + SPI NOR framework + ------------------------ + m25p80 + ------------------------ + SPI bus driver + ------------------------ + SPI NOR chip + + With the SPI NOR controller driver (Freescale QuadSPI), it looks like: + MTD + ------------------------ + SPI NOR framework + ------------------------ + fsl-quadSPI + ------------------------ + SPI NOR chip + +Part III - How can drivers use the framework? +--------------------------------------------- + +The main API is spi_nor_scan(). Before you call the hook, a driver should +initialize the necessary fields for spi_nor{}. Please see +drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c +when you want to write a new driver for a SPI NOR controller. diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index a383c00392d03f..9c723ecd002515 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -585,13 +585,19 @@ mode balance-tlb or 5 Adaptive transmit load balancing: channel bonding that - does not require any special switch support. The - outgoing traffic is distributed according to the - current load (computed relative to the speed) on each - slave. Incoming traffic is received by the current - slave. If the receiving slave fails, another slave - takes over the MAC address of the failed receiving - slave. + does not require any special switch support. + + In tlb_dynamic_lb=1 mode; the outgoing traffic is + distributed according to the current load (computed + relative to the speed) on each slave. + + In tlb_dynamic_lb=0 mode; the load balancing based on + current load is disabled and the load is distributed + only using the hash distribution. + + Incoming traffic is received by the current slave. + If the receiving slave fails, another slave takes over + the MAC address of the failed receiving slave. Prerequisite: @@ -736,6 +742,28 @@ primary_reselect This option was added for bonding version 3.6.0. +tlb_dynamic_lb + + Specifies if dynamic shuffling of flows is enabled in tlb + mode. The value has no effect on any other modes. + + The default behavior of tlb mode is to shuffle active flows across + slaves based on the load in that interval. This gives nice lb + characteristics but can cause packet reordering. If re-ordering is + a concern use this variable to disable flow shuffling and rely on + load balancing provided solely by the hash distribution. + xmit-hash-policy can be used to select the appropriate hashing for + the setup. + + The sysfs entry can be used to change the setting per bond device + and the initial value is derived from the module parameter. The + sysfs entry is allowed to be changed only if the bond device is + down. + + The default value is "1" that enables flow shuffling while value "0" + disables it. This option was added in bonding driver 3.7.1 + + updelay Specifies the time, in milliseconds, to wait before enabling a @@ -769,7 +797,7 @@ use_carrier xmit_hash_policy Selects the transmit hash policy to use for slave selection in - balance-xor and 802.3ad modes. Possible values are: + balance-xor, 802.3ad, and tlb modes. Possible values are: layer2 diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt index 2fa44cbe81b734..4f7ae5261364ac 100644 --- a/Documentation/networking/can.txt +++ b/Documentation/networking/can.txt @@ -706,7 +706,7 @@ solution for a couple of reasons: RX_NO_AUTOTIMER: Prevent automatically starting the timeout monitor. - RX_ANNOUNCE_RESUME: If passed at RX_SETUP and a receive timeout occured, a + RX_ANNOUNCE_RESUME: If passed at RX_SETUP and a receive timeout occurred, a RX_CHANGED message will be generated when the (cyclic) receive restarts. TX_RESET_MULTI_IDX: Reset the index for the multiple frame transmission. diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index bf5dbe3ab8c51e..55c575fcaf17d9 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -86,7 +86,7 @@ built-in CCIDs. DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same time, combining the operation of the next two socket options. This option is -preferrable over the latter two, since often applications will use the same +preferable over the latter two, since often applications will use the same type of CCID for both directions; and mixed use of CCIDs is not currently well understood. This socket option takes as argument at least one uint8_t value, or an array of uint8_t values, which must match available CCIDS (see above). CCIDs diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt index 81f940f4e88480..748fd385535d38 100644 --- a/Documentation/networking/filter.txt +++ b/Documentation/networking/filter.txt @@ -281,6 +281,7 @@ Possible BPF extensions are shown in the following table: cpu raw_smp_processor_id() vlan_tci vlan_tx_tag_get(skb) vlan_pr vlan_tx_tag_present(skb) + rand prandom_u32() These extensions can also be prefixed with '#'. Examples for low-level BPF: @@ -308,6 +309,18 @@ Examples for low-level BPF: ret #-1 drop: ret #0 +** icmp random packet sampling, 1 in 4 + ldh [12] + jne #0x800, drop + ldb [23] + jneq #1, drop + # get a random uint32 number + ld rand + mod #4 + jneq #1, drop + ret #-1 + drop: ret #0 + ** SECCOMP filter example: ld [4] /* offsetof(struct seccomp_data, arch) */ @@ -600,7 +613,7 @@ Some core changes of the new internal format: Therefore, BPF calling convention is defined as: - * R0 - return value from in-kernel function + * R0 - return value from in-kernel function, and exit value for BPF program * R1 - R5 - arguments from BPF program to in-kernel function * R6 - R9 - callee saved registers that in-kernel function will preserve * R10 - read-only frame pointer to access stack @@ -646,9 +659,140 @@ Some core changes of the new internal format: - Introduces bpf_call insn and register passing convention for zero overhead calls from/to other kernel functions: - After a kernel function call, R1 - R5 are reset to unreadable and R0 has a - return type of the function. Since R6 - R9 are callee saved, their state is - preserved across the call. + Before an in-kernel function call, the internal BPF program needs to + place function arguments into R1 to R5 registers to satisfy calling + convention, then the interpreter will take them from registers and pass + to in-kernel function. If R1 - R5 registers are mapped to CPU registers + that are used for argument passing on given architecture, the JIT compiler + doesn't need to emit extra moves. Function arguments will be in the correct + registers and BPF_CALL instruction will be JITed as single 'call' HW + instruction. This calling convention was picked to cover common call + situations without performance penalty. + + After an in-kernel function call, R1 - R5 are reset to unreadable and R0 has + a return value of the function. Since R6 - R9 are callee saved, their state + is preserved across the call. + + For example, consider three C functions: + + u64 f1() { return (*_f2)(1); } + u64 f2(u64 a) { return f3(a + 1, a); } + u64 f3(u64 a, u64 b) { return a - b; } + + GCC can compile f1, f3 into x86_64: + + f1: + movl $1, %edi + movq _f2(%rip), %rax + jmp *%rax + f3: + movq %rdi, %rax + subq %rsi, %rax + ret + + Function f2 in BPF may look like: + + f2: + bpf_mov R2, R1 + bpf_add R1, 1 + bpf_call f3 + bpf_exit + + If f2 is JITed and the pointer stored to '_f2'. The calls f1 -> f2 -> f3 and + returns will be seamless. Without JIT, __sk_run_filter() interpreter needs to + be used to call into f2. + + For practical reasons all BPF programs have only one argument 'ctx' which is + already placed into R1 (e.g. on __sk_run_filter() startup) and the programs + can call kernel functions with up to 5 arguments. Calls with 6 or more arguments + are currently not supported, but these restrictions can be lifted if necessary + in the future. + + On 64-bit architectures all register map to HW registers one to one. For + example, x86_64 JIT compiler can map them as ... + + R0 - rax + R1 - rdi + R2 - rsi + R3 - rdx + R4 - rcx + R5 - r8 + R6 - rbx + R7 - r13 + R8 - r14 + R9 - r15 + R10 - rbp + + ... since x86_64 ABI mandates rdi, rsi, rdx, rcx, r8, r9 for argument passing + and rbx, r12 - r15 are callee saved. + + Then the following internal BPF pseudo-program: + + bpf_mov R6, R1 /* save ctx */ + bpf_mov R2, 2 + bpf_mov R3, 3 + bpf_mov R4, 4 + bpf_mov R5, 5 + bpf_call foo + bpf_mov R7, R0 /* save foo() return value */ + bpf_mov R1, R6 /* restore ctx for next call */ + bpf_mov R2, 6 + bpf_mov R3, 7 + bpf_mov R4, 8 + bpf_mov R5, 9 + bpf_call bar + bpf_add R0, R7 + bpf_exit + + After JIT to x86_64 may look like: + + push %rbp + mov %rsp,%rbp + sub $0x228,%rsp + mov %rbx,-0x228(%rbp) + mov %r13,-0x220(%rbp) + mov %rdi,%rbx + mov $0x2,%esi + mov $0x3,%edx + mov $0x4,%ecx + mov $0x5,%r8d + callq foo + mov %rax,%r13 + mov %rbx,%rdi + mov $0x2,%esi + mov $0x3,%edx + mov $0x4,%ecx + mov $0x5,%r8d + callq bar + add %r13,%rax + mov -0x228(%rbp),%rbx + mov -0x220(%rbp),%r13 + leaveq + retq + + Which is in this example equivalent in C to: + + u64 bpf_filter(u64 ctx) + { + return foo(ctx, 2, 3, 4, 5) + bar(ctx, 6, 7, 8, 9); + } + + In-kernel functions foo() and bar() with prototype: u64 (*)(u64 arg1, u64 + arg2, u64 arg3, u64 arg4, u64 arg5); will receive arguments in proper + registers and place their return value into '%rax' which is R0 in BPF. + Prologue and epilogue are emitted by JIT and are implicit in the + interpreter. R0-R5 are scratch registers, so BPF program needs to preserve + them across the calls as defined by calling convention. + + For example the following program is invalid: + + bpf_mov R1, 1 + bpf_call foo + bpf_mov R0, R1 + bpf_exit + + After the call the registers R1-R5 contain junk values and cannot be read. + In the future a BPF verifier can be used to validate internal BPF programs. Also in the new design, BPF is limited to 4096 insns, which means that any program will terminate quickly and will only call a fixed number of kernel @@ -663,6 +807,25 @@ A program, that is translated internally consists of the following elements: op:16, jt:8, jf:8, k:32 ==> op:8, a_reg:4, x_reg:4, off:16, imm:32 +So far 87 internal BPF instructions were implemented. 8-bit 'op' opcode field +has room for new instructions. Some of them may use 16/24/32 byte encoding. New +instructions must be multiple of 8 bytes to preserve backward compatibility. + +Internal BPF is a general purpose RISC instruction set. Not every register and +every instruction are used during translation from original BPF to new format. +For example, socket filters are not using 'exclusive add' instruction, but +tracing filters may do to maintain counters of events, for example. Register R9 +is not used by socket filters either, but more complex filters may be running +out of registers and would have to resort to spill/fill to stack. + +Internal BPF can used as generic assembler for last step performance +optimizations, socket filters and seccomp are using it as assembler. Tracing +filters may use it as assembler to generate code from kernel. In kernel usage +may not be bounded by security considerations, since generated internal BPF code +may be optimizing internal code path and not being exposed to the user space. +Safety of internal BPF can come from a verifier (TBD). In such use cases as +described, it may be used as safe instruction set. + Just like the original BPF, the new format runs within a controlled environment, is deterministic and the kernel can easily prove that. The safety of the program can be determined in two steps: first step does depth-first-search to disallow diff --git a/Documentation/power/opp.txt b/Documentation/power/opp.txt index b8a907dc016978..a9adad828cdc45 100644 --- a/Documentation/power/opp.txt +++ b/Documentation/power/opp.txt @@ -10,8 +10,7 @@ Contents 3. OPP Search Functions 4. OPP Availability Control Functions 5. OPP Data Retrieval Functions -6. Cpufreq Table Generation -7. Data Structures +6. Data Structures 1. Introduction =============== @@ -72,7 +71,6 @@ operations until that OPP could be re-enabled if possible. OPP library facilitates this concept in it's implementation. The following operational functions operate only on available opps: opp_find_freq_{ceil, floor}, dev_pm_opp_get_voltage, dev_pm_opp_get_freq, dev_pm_opp_get_opp_count -and dev_pm_opp_init_cpufreq_table dev_pm_opp_find_freq_exact is meant to be used to find the opp pointer which can then be used for dev_pm_opp_enable/disable functions to make an opp available as required. @@ -96,10 +94,9 @@ using RCU read locks. The opp_find_freq_{exact,ceil,floor}, opp_get_{voltage, freq, opp_count} fall into this category. opp_{add,enable,disable} are updaters which use mutex and implement it's own -RCU locking mechanisms. dev_pm_opp_init_cpufreq_table acts as an updater and uses -mutex to implment RCU updater strategy. These functions should *NOT* be called -under RCU locks and other contexts that prevent blocking functions in RCU or -mutex operations from working. +RCU locking mechanisms. These functions should *NOT* be called under RCU locks +and other contexts that prevent blocking functions in RCU or mutex operations +from working. 2. Initial OPP List Registration ================================ @@ -311,34 +308,7 @@ dev_pm_opp_get_opp_count - Retrieve the number of available opps for a device /* Do other things */ } -6. Cpufreq Table Generation -=========================== -dev_pm_opp_init_cpufreq_table - cpufreq framework typically is initialized with - cpufreq_frequency_table_cpuinfo which is provided with the list of - frequencies that are available for operation. This function provides - a ready to use conversion routine to translate the OPP layer's internal - information about the available frequencies into a format readily - providable to cpufreq. - - WARNING: Do not use this function in interrupt context. - - Example: - soc_pm_init() - { - /* Do things */ - r = dev_pm_opp_init_cpufreq_table(dev, &freq_table); - if (!r) - cpufreq_frequency_table_cpuinfo(policy, freq_table); - /* Do other things */ - } - - NOTE: This function is available only if CONFIG_CPU_FREQ is enabled in - addition to CONFIG_PM as power management feature is required to - dynamically scale voltage and frequency in a system. - -dev_pm_opp_free_cpufreq_table - Free up the table allocated by dev_pm_opp_init_cpufreq_table - -7. Data Structures +6. Data Structures ================== Typically an SoC contains multiple voltage domains which are variable. Each domain is represented by a device pointer. The relationship to OPP can be diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt index 079160e22bcc0d..f732a8321e8a75 100644 --- a/Documentation/power/swsusp.txt +++ b/Documentation/power/swsusp.txt @@ -220,7 +220,10 @@ Q: After resuming, system is paging heavily, leading to very bad interactivity. A: Try running -cat `cat /proc/[0-9]*/maps | grep / | sed 's:.* /:/:' | sort -u` > /dev/null +cat /proc/[0-9]*/maps | grep / | sed 's:.* /:/:' | sort -u | while read file +do + test -f "$file" && cat "$file" > /dev/null +done after resume. swapoff -a; swapon -a may also be useful. diff --git a/Documentation/powerpc/transactional_memory.txt b/Documentation/powerpc/transactional_memory.txt index dc23e58ae2641a..9791e98ab49cf2 100644 --- a/Documentation/powerpc/transactional_memory.txt +++ b/Documentation/powerpc/transactional_memory.txt @@ -160,7 +160,7 @@ To avoid this, when taking a signal in an active transaction, we need to use the stack pointer from the checkpointed state, rather than the speculated state. This ensures that the signal context (written tm suspended) will be written below the stack required for the rollback. The transaction is aborted -becuase of the treclaim, so any memory written between the tbegin and the +because of the treclaim, so any memory written between the tbegin and the signal will be rolled back anyway. For signals taken in non-TM or suspended mode, we use the diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt index 94459b42e0abee..3b56a991f52ea1 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/printk-formats.txt @@ -205,11 +205,11 @@ struct va_format: Do not use this feature without some mechanism to verify the correctness of the format string and va_list arguments. -u64 SHOULD be printed with %llu/%llx, (unsigned long long): +u64 SHOULD be printed with %llu/%llx: printk("%llu", u64_var); -s64 SHOULD be printed with %lld/%llx, (long long): +s64 SHOULD be printed with %lld/%llx: printk("%lld", s64_var); diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt index 93cb979749860f..0527f615b115cb 100644 --- a/Documentation/pwm.txt +++ b/Documentation/pwm.txt @@ -97,6 +97,13 @@ pwm_chip as argument which provides a description of the PWM chip, the number of PWM devices provided by the chip and the chip-specific implementation of the supported PWM operations to the framework. +When implementing polarity support in a PWM driver, make sure to respect the +signal conventions in the PWM framework. By definition, normal polarity +characterizes a signal starts high for the duration of the duty cycle and +goes low for the remainder of the period. Conversely, a signal with inversed +polarity starts low for the duration of the duty cycle and goes high for the +remainder of the period. + Locking ------- diff --git a/Documentation/rbtree.txt b/Documentation/rbtree.txt index 61b6c48871a016..39873ef41bf9fc 100644 --- a/Documentation/rbtree.txt +++ b/Documentation/rbtree.txt @@ -255,7 +255,7 @@ However, rbtree can be augmented to store such interval ranges in a structured way making it possible to do efficient lookup and exact match. This "extra information" stored in each node is the maximum hi -(max_hi) value among all the nodes that are its descendents. This +(max_hi) value among all the nodes that are its descendants. This information can be maintained at each node just be looking at the node and its immediate children. And this will be used in O(log n) lookup for lowest match (lowest start address among all possible matches) diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index f430004df73c06..427e89712f4a27 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -21,7 +21,7 @@ aircraft. The rfkill subsystem has a concept of "hard" and "soft" block, which differ little in their meaning (block == transmitters off) but rather in whether they can be changed or not: - - hard block: read-only radio block that cannot be overriden by software + - hard block: read-only radio block that cannot be overridden by software - soft block: writable radio block (need not be readable) that is set by the system software. diff --git a/Documentation/robust-futexes.txt b/Documentation/robust-futexes.txt index 0a9446a53bd1cd..af6fce23e48477 100644 --- a/Documentation/robust-futexes.txt +++ b/Documentation/robust-futexes.txt @@ -210,7 +210,7 @@ i386 and x86_64 syscalls are wired up at the moment, and Ulrich has tested the new glibc code (on x86_64 and i386), and it works for his robust-mutex testcases. -All other architectures should build just fine too - but they wont have +All other architectures should build just fine too - but they won't have the new syscalls yet. Architectures need to implement the new futex_atomic_cmpxchg_inatomic() diff --git a/Documentation/s390/monreader.txt b/Documentation/s390/monreader.txt index beeaa4b244276f..d3729585fdb049 100644 --- a/Documentation/s390/monreader.txt +++ b/Documentation/s390/monreader.txt @@ -10,7 +10,7 @@ Author: Gerald Schaefer (geraldsc@de.ibm.com) Description =========== This item delivers a new Linux API in the form of a misc char device that is -useable from user space and allows read access to the z/VM Monitor Records +usable from user space and allows read access to the z/VM Monitor Records collected by the *MONITOR System Service of z/VM. diff --git a/Documentation/s390/zfcpdump.txt b/Documentation/s390/zfcpdump.txt index cf45d27c4608da..dc929be9601615 100644 --- a/Documentation/s390/zfcpdump.txt +++ b/Documentation/s390/zfcpdump.txt @@ -1,15 +1,15 @@ -s390 SCSI dump tool (zfcpdump) +The s390 SCSI dump tool (zfcpdump) System z machines (z900 or higher) provide hardware support for creating system dumps on SCSI disks. The dump process is initiated by booting a dump tool, which has to create a dump of the current (probably crashed) Linux image. In order to not overwrite memory of the crashed Linux with data of the dump tool, the -hardware saves some memory plus the register sets of the boot cpu before the +hardware saves some memory plus the register sets of the boot CPU before the dump tool is loaded. There exists an SCLP hardware interface to obtain the saved memory afterwards. Currently 32 MB are saved. This zfcpdump implementation consists of a Linux dump kernel together with -a userspace dump tool, which are loaded together into the saved memory region +a user space dump tool, which are loaded together into the saved memory region below 32 MB. zfcpdump is installed on a SCSI disk using zipl (as contained in the s390-tools package) to make the device bootable. The operator of a Linux system can then trigger a SCSI dump by booting the SCSI disk, where zfcpdump @@ -19,68 +19,33 @@ The kernel part of zfcpdump is implemented as a debugfs file under "zcore/mem", which exports memory and registers of the crashed Linux in an s390 standalone dump format. It can be used in the same way as e.g. /dev/mem. The dump format defines a 4K header followed by plain uncompressed memory. The -register sets are stored in the prefix pages of the respective cpus. To build a +register sets are stored in the prefix pages of the respective CPUs. To build a dump enabled kernel with the zcore driver, the kernel config option -CONFIG_ZFCPDUMP has to be set. When reading from "zcore/mem", the part of +CONFIG_CRASH_DUMP has to be set. When reading from "zcore/mem", the part of memory, which has been saved by hardware is read by the driver via the SCLP hardware interface. The second part is just copied from the non overwritten real memory. -The userspace application of zfcpdump can reside e.g. in an intitramfs or an -initrd. It reads from zcore/mem and writes the system dump to a file on a -SCSI disk. +Since kernel version 3.12 also the /proc/vmcore file can also be used to access +the dump. -To build a zfcpdump kernel use the following settings in your kernel -configuration: - * CONFIG_ZFCPDUMP=y - * Enable ZFCP driver - * Enable SCSI driver - * Enable ext2 and ext3 filesystems - * Disable as many features as possible to keep the kernel small. - E.g. network support is not needed at all. +To get a valid zfcpdump kernel configuration use "make zfcpdump_defconfig". -To use the zfcpdump userspace application in an initramfs you have to do the -following: +The s390 zipl tool looks for the zfcpdump kernel and optional initrd/initramfs +under the following locations: - * Copy the zfcpdump executable somewhere into your Linux tree. - E.g. to "arch/s390/boot/zfcpdump. If you do not want to include - shared libraries, compile the tool with the "-static" gcc option. - * If you want to include e2fsck, add it to your source tree, too. The zfcpdump - application attempts to start /sbin/e2fsck from the ramdisk. - * Use an initramfs config file like the following: +* kernel: /zfcpdump.image +* ramdisk: /zfcpdump.rd - dir /dev 755 0 0 - nod /dev/console 644 0 0 c 5 1 - nod /dev/null 644 0 0 c 1 3 - nod /dev/sda1 644 0 0 b 8 1 - nod /dev/sda2 644 0 0 b 8 2 - nod /dev/sda3 644 0 0 b 8 3 - nod /dev/sda4 644 0 0 b 8 4 - nod /dev/sda5 644 0 0 b 8 5 - nod /dev/sda6 644 0 0 b 8 6 - nod /dev/sda7 644 0 0 b 8 7 - nod /dev/sda8 644 0 0 b 8 8 - nod /dev/sda9 644 0 0 b 8 9 - nod /dev/sda10 644 0 0 b 8 10 - nod /dev/sda11 644 0 0 b 8 11 - nod /dev/sda12 644 0 0 b 8 12 - nod /dev/sda13 644 0 0 b 8 13 - nod /dev/sda14 644 0 0 b 8 14 - nod /dev/sda15 644 0 0 b 8 15 - file /init arch/s390/boot/zfcpdump 755 0 0 - file /sbin/e2fsck arch/s390/boot/e2fsck 755 0 0 - dir /proc 755 0 0 - dir /sys 755 0 0 - dir /mnt 755 0 0 - dir /sbin 755 0 0 +The zfcpdump directory is defined in the s390-tools package. - * Issue "make image" to build the zfcpdump image with initramfs. +The user space application of zfcpdump can reside in an intitramfs or an +initrd. It can also be included in a built-in kernel initramfs. The application +reads from /proc/vmcore or zcore/mem and writes the system dump to a SCSI disk. -In a Linux distribution the zfcpdump enabled kernel image must be copied to -/usr/share/zfcpdump/zfcpdump.image, where the s390 zipl tool is looking for the -dump kernel when preparing a SCSI dump disk. - -If you use a ramdisk copy it to "/usr/share/zfcpdump/zfcpdump.rd". +The s390-tools package version 1.24.0 and above builds an external zfcpdump +initramfs with a user space application that writes the dump to a SCSI +partition. For more information on how to use zfcpdump refer to the s390 'Using the Dump Tools book', which is available from diff --git a/Documentation/security/Yama.txt b/Documentation/security/Yama.txt index dd908cf64ecfcb..227a63f018a27d 100644 --- a/Documentation/security/Yama.txt +++ b/Documentation/security/Yama.txt @@ -37,7 +37,7 @@ still work as root). In mode 1, software that has defined application-specific relationships between a debugging process and its inferior (crash handlers, etc), prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which -other process (and its descendents) are allowed to call PTRACE_ATTACH +other process (and its descendants) are allowed to call PTRACE_ATTACH against it. Only one such declared debugging process can exists for each inferior at a time. For example, this is used by KDE, Chromium, and Firefox's crash handlers, and by Wine for allowing only Wine processes diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index b8dd0df7695207..7ccf933bfbe0df 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -948,7 +948,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. avoided as much as possible... MORE NOTES ON "azx_get_response timeout" PROBLEMS: - On some hardwares, you may need to add a proper probe_mask option + On some hardware, you may need to add a proper probe_mask option to avoid the "azx_get_response timeout" problem above, instead. This occurs when the access to non-existing or non-working codec slot (likely a modem one) causes a stall of the communication via HD-audio @@ -1124,7 +1124,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. buggy_irq - Enable workaround for buggy interrupts on some motherboards (default yes on nForce chips, otherwise off) - buggy_semaphore - Enable workaround for hardwares with buggy + buggy_semaphore - Enable workaround for hardware with buggy semaphores (e.g. on some ASUS laptops) (default off) spdif_aclink - Use S/PDIF over AC-link instead of direct connection diff --git a/Documentation/timers/timer_stats.txt b/Documentation/timers/timer_stats.txt index 8abd40b22b7fff..de835ee974550e 100644 --- a/Documentation/timers/timer_stats.txt +++ b/Documentation/timers/timer_stats.txt @@ -39,9 +39,9 @@ To stop a sample period issue: The statistics can be retrieved by: # cat /proc/timer_stats -The readout of /proc/timer_stats automatically disables sampling. The sampled -information is kept until a new sample period is started. This allows multiple -readouts. +While sampling is enabled, each readout from /proc/timer_stats will see +newly updated statistics. Once sampling is disabled, the sampled information +is kept until a new sample period is started. This allows multiple readouts. Sample output of /proc/timer_stats: diff --git a/Documentation/trace/events.txt b/Documentation/trace/events.txt index c94435df203774..75d25a1d6e42e7 100644 --- a/Documentation/trace/events.txt +++ b/Documentation/trace/events.txt @@ -443,7 +443,7 @@ The following commands are supported: The following command creates a snapshot every time a block request queue is unplugged with a depth > 1. If you were tracing a set of events or functions at the time, the snapshot trace buffer would - capture those events when the trigger event occured: + capture those events when the trigger event occurred: # echo 'snapshot if nr_rq > 1' > \ /sys/kernel/debug/tracing/events/block/block_unplug/trigger diff --git a/Documentation/usb/chipidea.txt b/Documentation/usb/chipidea.txt new file mode 100644 index 00000000000000..4c0e2eaa5b291b --- /dev/null +++ b/Documentation/usb/chipidea.txt @@ -0,0 +1,71 @@ +1. How to test OTG FSM(HNP and SRP) +----------------------------------- +To show how to demo OTG HNP and SRP functions via sys input files +with 2 Freescale i.MX6Q sabre SD boards. + +1.1 How to enable OTG FSM in menuconfig +--------------------------------------- +Select CONFIG_USB_OTG_FSM. +If you want to check some internal variables for otg fsm, +select CONFIG_USB_CHIPIDEA_DEBUG, there are 2 files which +can show otg fsm variables and some controller registers value: +cat /sys/kernel/debug/ci_hdrc.0/otg +cat /sys/kernel/debug/ci_hdrc.0/registers + +1.2 Test operations +------------------- +1) Power up 2 Freescale i.MX6Q sabre SD boards with gadget class driver loaded + (e.g. g_mass_storage). + +2) Connect 2 boards with usb cable with one end is micro A plug, the other end + is micro B plug. + + The A-device(with micro A plug inserted) should enumrate B-device. + +3) Role switch + On B-device: + echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req + + if HNP polling is not supported, also need: + On A-device: + echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req + + B-device should take host role and enumrate A-device. + +4) A-device switch back to host. + On B-device: + echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req + + A-device should switch back to host and enumrate B-device. + +5) Remove B-device(unplug micro B plug) and insert again in 10 seconds, + A-device should enumrate B-device again. + +6) Remove B-device(unplug micro B plug) and insert again after 10 seconds, + A-device should NOT enumrate B-device. + + if A-device wants to use bus: + On A-device: + echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop + echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req + + if B-device wants to use bus: + On B-device: + echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req + +7) A-device power down the bus. + On A-device: + echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop + + A-device should disconnect with B-device and power down the bus. + +8) B-device does data pulse for SRP. + On B-device: + echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req + + A-device should resume usb bus and enumrate B-device. + +1.3 Reference document +---------------------- +"On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification +July 27, 2012 Revision 2.0 version 1.1a" diff --git a/Documentation/usb/mass-storage.txt b/Documentation/usb/mass-storage.txt index 59063ad7a60d02..e89803a5a96099 100644 --- a/Documentation/usb/mass-storage.txt +++ b/Documentation/usb/mass-storage.txt @@ -13,7 +13,7 @@ operation. Note that the driver is slightly non-portable in that it assumes - a single memory/DMA buffer will be useable for bulk-in and bulk-out + a single memory/DMA buffer will be usable for bulk-in and bulk-out endpoints. With most device controllers this is not an issue, but there may be some with hardware restrictions that prevent a buffer from being used by more than one endpoint. diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index a9380ba54c8e98..6abdff82e0b031 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2066,7 +2066,7 @@ the "Server" class MMU emulation supported by KVM. This can in turn be used by userspace to generate the appropriate device-tree properties for the guest operating system. -The structure contains some global informations, followed by an +The structure contains some global information, followed by an array of supported segment page sizes: struct kvm_ppc_smmu_info { @@ -2314,8 +2314,8 @@ struct kvm_create_device { 4.80 KVM_SET_DEVICE_ATTR/KVM_GET_DEVICE_ATTR -Capability: KVM_CAP_DEVICE_CTRL -Type: device ioctl +Capability: KVM_CAP_DEVICE_CTRL, KVM_CAP_VM_ATTRIBUTES for vm device +Type: device ioctl, vm ioctl Parameters: struct kvm_device_attr Returns: 0 on success, -1 on error Errors: @@ -2340,8 +2340,8 @@ struct kvm_device_attr { 4.81 KVM_HAS_DEVICE_ATTR -Capability: KVM_CAP_DEVICE_CTRL -Type: device ioctl +Capability: KVM_CAP_DEVICE_CTRL, KVM_CAP_VM_ATTRIBUTES for vm device +Type: device ioctl, vm ioctl Parameters: struct kvm_device_attr Returns: 0 on success, -1 on error Errors: @@ -2376,6 +2376,8 @@ Possible features: Depends on KVM_CAP_ARM_PSCI. - KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode. Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only). + - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 for the CPU. + Depends on KVM_CAP_ARM_PSCI_0_2. 4.83 KVM_ARM_PREFERRED_TARGET @@ -2738,6 +2740,21 @@ It gets triggered whenever both KVM_CAP_PPC_EPR are enabled and an external interrupt has just been delivered into the guest. User space should put the acknowledged interrupt vector into the 'epr' field. + /* KVM_EXIT_SYSTEM_EVENT */ + struct { +#define KVM_SYSTEM_EVENT_SHUTDOWN 1 +#define KVM_SYSTEM_EVENT_RESET 2 + __u32 type; + __u64 flags; + } system_event; + +If exit_reason is KVM_EXIT_SYSTEM_EVENT then the vcpu has triggered +a system-level event using some architecture specific mechanism (hypercall +or some special instruction). In case of ARM/ARM64, this is triggered using +HVC instruction based PSCI call from the vcpu. The 'type' field describes +the system-level event type. The 'flags' field describes architecture +specific flags for the system-level event. + /* Fix the size of the union. */ char padding[256]; }; diff --git a/Documentation/virtual/kvm/devices/vm.txt b/Documentation/virtual/kvm/devices/vm.txt new file mode 100644 index 00000000000000..0d16f96c0eac96 --- /dev/null +++ b/Documentation/virtual/kvm/devices/vm.txt @@ -0,0 +1,26 @@ +Generic vm interface +==================================== + +The virtual machine "device" also accepts the ioctls KVM_SET_DEVICE_ATTR, +KVM_GET_DEVICE_ATTR, and KVM_HAS_DEVICE_ATTR. The interface uses the same +struct kvm_device_attr as other devices, but targets VM-wide settings +and controls. + +The groups and attributes per virtual machine, if any, are architecture +specific. + +1. GROUP: KVM_S390_VM_MEM_CTRL +Architectures: s390 + +1.1. ATTRIBUTE: KVM_S390_VM_MEM_CTRL +Parameters: none +Returns: -EBUSY if already a vcpus is defined, otherwise 0 + +Enables CMMA for the virtual machine + +1.2. ATTRIBUTE: KVM_S390_VM_CLR_CMMA +Parameteres: none +Returns: 0 + +Clear the CMMA status for all guest pages, so any pages the guest marked +as unused are again used any may not be reclaimed by the host. diff --git a/Documentation/virtual/kvm/s390-diag.txt b/Documentation/virtual/kvm/s390-diag.txt index f1de4fbade155b..48c4921794edf0 100644 --- a/Documentation/virtual/kvm/s390-diag.txt +++ b/Documentation/virtual/kvm/s390-diag.txt @@ -78,3 +78,5 @@ DIAGNOSE function code 'X'501 - KVM breakpoint If the function code specifies 0x501, breakpoint functions may be performed. This function code is handled by userspace. + +This diagnose function code has no subfunctions and uses no parameters. diff --git a/Documentation/vm/transhuge.txt b/Documentation/vm/transhuge.txt index 4a63953a41f170..6b31cfbe2a9a11 100644 --- a/Documentation/vm/transhuge.txt +++ b/Documentation/vm/transhuge.txt @@ -360,13 +360,13 @@ on any tail page, would mean having to split all hugepages upfront in get_user_pages which is unacceptable as too many gup users are performance critical and they must work natively on hugepages like they work natively on hugetlbfs already (hugetlbfs is simpler because -hugetlbfs pages cannot be splitted so there wouldn't be requirement of +hugetlbfs pages cannot be split so there wouldn't be requirement of accounting the pins on the tail pages for hugetlbfs). If we wouldn't account the gup refcounts on the tail pages during gup, we won't know anymore which tail page is pinned by gup and which is not while we run split_huge_page. But we still have to add the gup pin to the head page too, to know when we can free the compound page in case it's never -splitted during its lifetime. That requires changing not just +split during its lifetime. That requires changing not just get_page, but put_page as well so that when put_page runs on a tail page (and only on a tail page) it will find its respective head page, and then it will decrease the head page refcount in addition to the diff --git a/Documentation/x86/earlyprintk.txt b/Documentation/x86/earlyprintk.txt index f19802c0f48546..688e3eeed21dce 100644 --- a/Documentation/x86/earlyprintk.txt +++ b/Documentation/x86/earlyprintk.txt @@ -33,7 +33,7 @@ and two USB cables, connected like this: ... ( If your system does not list a debug port capability then you probably - wont be able to use the USB debug key. ) + won't be able to use the USB debug key. ) b.) You also need a Netchip USB debug cable/key: diff --git a/Documentation/x86/i386/IO-APIC.txt b/Documentation/x86/i386/IO-APIC.txt index 30b4c714fbe127..15f5baf7e1b681 100644 --- a/Documentation/x86/i386/IO-APIC.txt +++ b/Documentation/x86/i386/IO-APIC.txt @@ -87,7 +87,7 @@ your PCI configuration: echo -n pirq=; echo `scanpci | grep T_L | cut -c56-` | sed 's/ /,/g' -note that this script wont work if you have skipped a few slots or if your +note that this script won't work if you have skipped a few slots or if your board does not do default daisy-chaining. (or the IO-APIC has the PIRQ pins connected in some strange way). E.g. if in the above case you have your SCSI card (IRQ11) in Slot3, and have Slot1 empty: diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt index c584a51add15ad..afe68ddbe6a474 100644 --- a/Documentation/x86/x86_64/mm.txt +++ b/Documentation/x86/x86_64/mm.txt @@ -12,6 +12,8 @@ ffffc90000000000 - ffffe8ffffffffff (=45 bits) vmalloc/ioremap space ffffe90000000000 - ffffe9ffffffffff (=40 bits) hole ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB) ... unused hole ... +ffffff0000000000 - ffffff7fffffffff (=39 bits) %esp fixup stacks +... unused hole ... ffffffff80000000 - ffffffffa0000000 (=512 MB) kernel text mapping, from phys 0 ffffffffa0000000 - ffffffffff5fffff (=1525 MB) module mapping space ffffffffff600000 - ffffffffffdfffff (=8 MB) vsyscalls diff --git a/MAINTAINERS b/MAINTAINERS index 9b502fc28641f1..05904ab248f642 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1974,6 +1974,12 @@ S: Maintained F: drivers/bcma/ F: include/linux/bcma/ +BROADCOM SYSTEMPORT ETHERNET DRIVER +M: Florian Fainelli +L: netdev@vger.kernel.org +S: Supported +F: drivers/net/ethernet/broadcom/bcmsysport.* + BROCADE BFA FC SCSI DRIVER M: Anil Gurumurthy M: Sudarsana Kalluru @@ -2252,12 +2258,6 @@ L: linux-usb@vger.kernel.org S: Maintained F: drivers/usb/host/ohci-ep93xx.c -CIRRUS LOGIC CS4270 SOUND DRIVER -M: Timur Tabi -L: alsa-devel@alsa-project.org (moderated for non-subscribers) -S: Odd Fixes -F: sound/soc/codecs/cs4270* - CIRRUS LOGIC AUDIO CODEC DRIVERS M: Brian Austin M: Paul Handrigan @@ -2422,7 +2422,6 @@ F: drivers/net/ethernet/ti/cpmac.c CPU FREQUENCY DRIVERS M: Rafael J. Wysocki M: Viresh Kumar -L: cpufreq@vger.kernel.org L: linux-pm@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git @@ -2433,7 +2432,6 @@ F: include/linux/cpufreq.h CPU FREQUENCY DRIVERS - ARM BIG LITTLE M: Viresh Kumar M: Sudeep Holla -L: cpufreq@vger.kernel.org L: linux-pm@vger.kernel.org W: http://www.arm.com/products/processors/technologies/biglittleprocessing.php S: Maintained @@ -4215,9 +4213,11 @@ S: Maintained F: fs/hpfs/ HSI SUBSYSTEM -M: Sebastian Reichel +M: Sebastian Reichel +T: git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi.git S: Maintained F: Documentation/ABI/testing/sysfs-bus-hsi +F: Documentation/hsi.txt F: drivers/hsi/ F: include/linux/hsi/ F: include/uapi/linux/hsi/ @@ -6418,6 +6418,7 @@ F: drivers/usb/*/*omap* F: arch/arm/*omap*/usb* OMAP GPIO DRIVER +M: Javier Martinez Canillas M: Santosh Shilimkar M: Kevin Hilman L: linux-omap@vger.kernel.org @@ -6707,6 +6708,7 @@ F: Documentation/PCI/ F: drivers/pci/ F: include/linux/pci* F: arch/x86/pci/ +F: arch/x86/kernel/quirks.c PCI DRIVER FOR IMX6 M: Richard Zhu @@ -8491,6 +8493,13 @@ M: Florian Schilhabel . S: Odd Fixes F: drivers/staging/rtl8712/ +STAGING - REALTEK RTL8723U WIRELESS DRIVER +M: Larry Finger +M: Jes Sorensen +L: linux-wireless@vger.kernel.org +S: Maintained +F: drivers/staging/rtl8723au/ + STAGING - SILICON MOTION SM7XX FRAME BUFFER DRIVER M: Teddy Wang S: Odd Fixes @@ -9110,6 +9119,9 @@ F: arch/um/os-Linux/drivers/ TURBOCHANNEL SUBSYSTEM M: "Maciej W. Rozycki" +M: Ralf Baechle +L: linux-mips@linux-mips.org +Q: http://patchwork.linux-mips.org/project/linux-mips/list/ S: Maintained F: drivers/tc/ F: include/linux/tc.h diff --git a/Makefile b/Makefile index 48e5b285ef4537..16590410cc1f0a 100644 --- a/Makefile +++ b/Makefile @@ -105,10 +105,6 @@ ifeq ("$(origin O)", "command line") KBUILD_OUTPUT := $(O) endif -ifeq ("$(origin W)", "command line") - export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W) -endif - # That's our default target when none is given on the command line PHONY := _all _all: @@ -166,7 +162,7 @@ export srctree objtree VPATH # SUBARCH tells the usermode build what the underlying arch is. That is set # first, and if a usermode build is happening, the "ARCH=um" on the command # line overrides the setting of ARCH below. If a native build is happening, -# then ARCH is assigned, getting whatever value it gets normally, and +# then ARCH is assigned, getting whatever value it gets normally, and # SUBARCH is subsequently ignored. SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ @@ -259,18 +255,18 @@ endif KBUILD_MODULES := KBUILD_BUILTIN := 1 -# If we have only "make modules", don't compile built-in objects. -# When we're building modules with modversions, we need to consider -# the built-in objects during the descend as well, in order to -# make sure the checksums are up to date before we record them. +# If we have only "make modules", don't compile built-in objects. +# When we're building modules with modversions, we need to consider +# the built-in objects during the descend as well, in order to +# make sure the checksums are up to date before we record them. ifeq ($(MAKECMDGOALS),modules) KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1) endif -# If we have "make modules", compile modules -# in addition to whatever we do anyway. -# Just "make" or "make all" shall build modules as well +# If we have "make modules", compile modules +# in addition to whatever we do anyway. +# Just "make" or "make all" shall build modules as well ifneq ($(filter all _all modules,$(MAKECMDGOALS)),) KBUILD_MODULES := 1 @@ -294,7 +290,7 @@ export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD # cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< # # If $(quiet) is empty, the whole command will be printed. -# If it is set to "quiet_", only the short version will be printed. +# If it is set to "quiet_", only the short version will be printed. # If it is set to "silent_", nothing will be printed at all, since # the variable $(silent_cmd_cc_o_c) doesn't exist. # @@ -346,12 +342,16 @@ $(srctree)/scripts/Kbuild.include: ; include $(srctree)/scripts/Kbuild.include # Make variables (CC, etc...) - AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld +LDFINAL = $(LD) CC = $(CROSS_COMPILE)gcc CPP = $(CC) -E +ifdef CONFIG_LTO +AR = $(CROSS_COMPILE)gcc-ar +else AR = $(CROSS_COMPILE)ar +endif NM = $(CROSS_COMPILE)nm STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy @@ -410,7 +410,7 @@ KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(S export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC -export CPP AR NM STRIP OBJCOPY OBJDUMP +export CPP AR NM STRIP OBJCOPY OBJDUMP LDFINAL export MAKE AWK GENKSYMS INSTALLKERNEL PERL UTS_MACHINE export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS @@ -421,6 +421,17 @@ export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL export KBUILD_ARFLAGS +ifdef CONFIG_LTO +# LTO gcc creates a lot of files in TMPDIR, and with /tmp as tmpfs +# it's easy to drive the machine OOM. Use the object directory +# instead. +ifndef TMPDIR +TMPDIR ?= $(objtree) +export TMPDIR +$(info setting TMPDIR=$(objtree) for LTO build) +endif +endif + # When compiling out-of-tree modules, put MODVERDIR in the module # tree rather than in the kernel tree. The kernel tree might # even be read-only. @@ -504,8 +515,16 @@ ifeq ($(mixed-targets),1) # We're called with mixed targets (*config and build targets). # Handle them one by one. -%:: FORCE - $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= $@ +PHONY += $(MAKECMDGOALS) __build_one_by_one + +$(filter-out __build_one_by_one, $(MAKECMDGOALS)): __build_one_by_one + @: + +__build_one_by_one: + $(Q)set -e; \ + for i in $(MAKECMDGOALS); do \ + $(MAKE) -f $(srctree)/Makefile $$i; \ + done else ifeq ($(config-targets),1) @@ -671,7 +690,7 @@ endif ifdef CONFIG_DEBUG_INFO KBUILD_CFLAGS += -g -KBUILD_AFLAGS += -Wa,--gdwarf-2 +KBUILD_AFLAGS += -Wa,-gdwarf-2 endif ifdef CONFIG_DEBUG_INFO_REDUCED @@ -731,6 +750,9 @@ ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y) KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO endif +include $(srctree)/scripts/Makefile.extrawarn +include ${srctree}/scripts/Makefile.lto + # Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments KBUILD_CPPFLAGS += $(KCPPFLAGS) KBUILD_AFLAGS += $(KAFLAGS) @@ -775,10 +797,10 @@ MODLIB = $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) export MODLIB # -# INSTALL_MOD_STRIP, if defined, will cause modules to be -# stripped after they are installed. If INSTALL_MOD_STRIP is '1', then -# the default option --strip-debug will be used. Otherwise, -# INSTALL_MOD_STRIP value will be used as the options to the strip command. +# INSTALL_MOD_STRIP, if defined, will cause modules to be +# stripped after they are installed. If INSTALL_MOD_STRIP is '1', then +# the default option --strip-debug will be used. Otherwise, +# INSTALL_MOD_STRIP value will be used as the options to the strip command. ifdef INSTALL_MOD_STRIP ifeq ($(INSTALL_MOD_STRIP),1) @@ -863,7 +885,7 @@ ifdef CONFIG_BUILD_DOCSRC endif +$(call if_changed,link-vmlinux) -# The actual objects are generated when descending, +# The actual objects are generated when descending, # make sure no implicit rule kicks in $(sort $(vmlinux-deps)): $(vmlinux-dirs) ; @@ -1021,11 +1043,11 @@ ifdef CONFIG_MODULES all: modules -# Build modules +# Build modules # -# A module can be listed more than once in obj-m resulting in -# duplicate lines in modules.order files. Those are removed -# using awk while concatenating to the final file. +# A module can be listed more than once in obj-m resulting in +# duplicate lines in modules.order files. Those are removed +# using awk while concatenating to the final file. PHONY += modules modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin @@ -1104,7 +1126,7 @@ CLEAN_DIRS += $(MODVERDIR) # Directories & files removed with 'make mrproper' MRPROPER_DIRS += include/config usr/include include/generated \ - arch/*/include/generated .tmp_objdiff + arch/*/include/generated .tmp_objdiff MRPROPER_FILES += .config .config.old .version .old_version $(version_h) \ Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \ signing_key.priv signing_key.x509 x509.genkey \ @@ -1478,7 +1500,7 @@ endif $(build)=$(build-dir) $(@:.ko=.o) $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost -# FIXME Should go into a make.lib or something +# FIXME Should go into a make.lib or something # =========================================================================== quiet_cmd_rmdirs = $(if $(wildcard $(rm-dirs)),CLEAN $(wildcard $(rm-dirs))) diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index 78b03ef39f6f0c..ed60a1ee1ed381 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -292,9 +292,4 @@ static inline long atomic64_dec_if_positive(atomic64_t *v) #define atomic_dec(v) atomic_sub(1,(v)) #define atomic64_dec(v) atomic64_sub(1,(v)) -#define smp_mb__before_atomic_dec() smp_mb() -#define smp_mb__after_atomic_dec() smp_mb() -#define smp_mb__before_atomic_inc() smp_mb() -#define smp_mb__after_atomic_inc() smp_mb() - #endif /* _ALPHA_ATOMIC_H */ diff --git a/arch/alpha/include/asm/bitops.h b/arch/alpha/include/asm/bitops.h index a19ba5efea4ca7..4bdfbd444e632a 100644 --- a/arch/alpha/include/asm/bitops.h +++ b/arch/alpha/include/asm/bitops.h @@ -53,9 +53,6 @@ __set_bit(unsigned long nr, volatile void * addr) *m |= 1 << (nr & 31); } -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() - static inline void clear_bit(unsigned long nr, volatile void * addr) { diff --git a/arch/alpha/include/asm/syscall.h b/arch/alpha/include/asm/syscall.h new file mode 100644 index 00000000000000..88d28eb2a5662f --- /dev/null +++ b/arch/alpha/include/asm/syscall.h @@ -0,0 +1,11 @@ +#ifndef _ASM_ALPHA_SYSCALL_H +#define _ASM_ALPHA_SYSCALL_H + +#include + +static inline int syscall_get_arch(void) +{ + return AUDIT_ARCH_ALPHA; +} + +#endif /* _ASM_ALPHA_SYSCALL_H */ diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h index 3d6ce6d56fc9ee..48bbea6898b30c 100644 --- a/arch/alpha/include/asm/thread_info.h +++ b/arch/alpha/include/asm/thread_info.h @@ -73,12 +73,14 @@ register struct thread_info *__current_thread_info __asm__("$8"); #define TIF_SYSCALL_AUDIT 4 /* syscall audit active */ #define TIF_DIE_IF_KERNEL 9 /* dik recursion lock */ #define TIF_MEMDIE 13 /* is terminating due to OOM killer */ +#define TIF_POLLING_NRFLAG 14 /* idle is polling for TIF_NEED_RESCHED */ #define _TIF_SYSCALL_TRACE (1<r0, regs->r16, regs->r17, regs->r18, regs->r19); + audit_syscall_entry(regs->r0, regs->r16, regs->r17, regs->r18, regs->r19); return ret ?: current_pt_regs()->r0; } diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 03e494f695d1d1..83f03ca6caf6c7 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -190,11 +190,6 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) #endif /* !CONFIG_ARC_HAS_LLSC */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - /** * __atomic_add_unless - add unless the number is a given value * @v: pointer of type atomic_t diff --git a/arch/arc/include/asm/bitops.h b/arch/arc/include/asm/bitops.h index 647a83a8e756f8..ebc0cf3164dcc6 100644 --- a/arch/arc/include/asm/bitops.h +++ b/arch/arc/include/asm/bitops.h @@ -19,6 +19,7 @@ #include #include +#include /* * Hardware assisted read-modify-write using ARC700 LLOCK/SCOND insns. @@ -496,10 +497,6 @@ static inline __attribute__ ((const)) int __ffs(unsigned long word) */ #define ffz(x) __ffs(~(x)) -/* TODO does this affect uni-processor code */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() - #include #include #include diff --git a/arch/arc/include/asm/irq.h b/arch/arc/include/asm/irq.h index 291a70db68b8b0..781f57f25bd8d1 100644 --- a/arch/arc/include/asm/irq.h +++ b/arch/arc/include/asm/irq.h @@ -19,8 +19,6 @@ #include extern void arc_init_IRQ(void); -extern int get_hw_config_num_irq(void); - void arc_local_timer_setup(unsigned int cpu); #endif diff --git a/arch/arc/include/asm/processor.h b/arch/arc/include/asm/processor.h index 15334ab66b56e1..d99f9b37cd1540 100644 --- a/arch/arc/include/asm/processor.h +++ b/arch/arc/include/asm/processor.h @@ -18,7 +18,6 @@ #ifndef __ASSEMBLY__ -#include /* for STATUS_E1_MASK et all */ #include /* Arch specific stuff which needs to be saved per task. @@ -41,15 +40,13 @@ struct thread_struct { /* Forward declaration, a strange C thing */ struct task_struct; -/* - * Return saved PC of a blocked thread. - */ +/* Return saved PC of a blocked thread */ unsigned long thread_saved_pc(struct task_struct *t); #define task_pt_regs(p) \ ((struct pt_regs *)(THREAD_SIZE + (void *)task_stack_page(p)) - 1) -/* Free all resources held by a thread. */ +/* Free all resources held by a thread */ #define release_thread(thread) do { } while (0) /* Prepare to copy thread state - unlazy all lazy status */ @@ -82,26 +79,8 @@ unsigned long thread_saved_pc(struct task_struct *t); #define KSTK_BLINK(tsk) KSTK_REG(tsk, 4) #define KSTK_FP(tsk) KSTK_REG(tsk, 0) -/* - * Do necessary setup to start up a newly executed thread. - * - * E1,E2 so that Interrupts are enabled in user mode - * L set, so Loop inhibited to begin with - * lp_start and lp_end seeded with bogus non-zero values so to easily catch - * the ARC700 sr to lp_start hardware bug - */ -#define start_thread(_regs, _pc, _usp) \ -do { \ - set_fs(USER_DS); /* reads from user space */ \ - (_regs)->ret = (_pc); \ - /* Interrupts enabled in User Mode */ \ - (_regs)->status32 = STATUS_U_MASK | STATUS_L_MASK \ - | STATUS_E1_MASK | STATUS_E2_MASK; \ - (_regs)->sp = (_usp); \ - /* bogus seed values for debugging */ \ - (_regs)->lp_start = 0x10; \ - (_regs)->lp_end = 0x80; \ -} while (0) +extern void start_thread(struct pt_regs * regs, unsigned long pc, + unsigned long usp); extern unsigned int get_wchan(struct task_struct *p); diff --git a/arch/arc/include/asm/sections.h b/arch/arc/include/asm/sections.h index 764f1e3ba7523b..09db952e14bd73 100644 --- a/arch/arc/include/asm/sections.h +++ b/arch/arc/include/asm/sections.h @@ -12,6 +12,5 @@ #include extern char __arc_dccm_base[]; -extern char __dtb_start[]; #endif diff --git a/arch/arc/kernel/devtree.c b/arch/arc/kernel/devtree.c index b6dc4e21fd32e2..0b3ef4025d8954 100644 --- a/arch/arc/kernel/devtree.c +++ b/arch/arc/kernel/devtree.c @@ -42,7 +42,7 @@ const struct machine_desc * __init setup_machine_fdt(void *dt) const struct machine_desc *mdesc; unsigned long dt_root; void *clk; - unsigned long len; + int len; if (!early_init_dt_scan(dt)) return NULL; diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S index 29b82adbf0b401..83a046a7cd06c9 100644 --- a/arch/arc/kernel/entry.S +++ b/arch/arc/kernel/entry.S @@ -156,7 +156,7 @@ ARCFP_DATA int1_saved_reg int1_saved_reg: .zero 4 -/* Each Interrupt level needs it's own scratch */ +/* Each Interrupt level needs its own scratch */ #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS ARCFP_DATA int2_saved_reg @@ -473,7 +473,7 @@ trap_with_param: lr r0, [efa] mov r1, sp - ; Now that we have read EFA, its safe to do "fake" rtie + ; Now that we have read EFA, it is safe to do "fake" rtie ; and get out of CPU exception mode FAKE_RET_FROM_EXCPN r11 @@ -678,9 +678,9 @@ not_exception: brne r9, event_IRQ2, 149f ;------------------------------------------------------------------ - ; if L2 IRQ interrupted a L1 ISR, we'd disbaled preemption earlier - ; so that sched doesnt move to new task, causing L1 to be delayed - ; undeterministically. Now that we've achieved that, lets reset + ; if L2 IRQ interrupted an L1 ISR, we'd disabled preemption earlier + ; so that sched doesn't move to new task, causing L1 to be delayed + ; undeterministically. Now that we've achieved that, let's reset ; things to what they were, before returning from L2 context ;---------------------------------------------------------------- @@ -736,7 +736,7 @@ ENTRY(ret_from_fork) ; put last task in scheduler queue bl @schedule_tail - ; If kernel thread, jump to it's entry-point + ; If kernel thread, jump to its entry-point ld r9, [sp, PT_status32] brne r9, 0, 1f diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index a4b141ee9a6a19..7d653c0d077390 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c @@ -150,24 +150,6 @@ void arch_do_IRQ(unsigned int irq, struct pt_regs *regs) set_irq_regs(old_regs); } -int get_hw_config_num_irq(void) -{ - uint32_t val = read_aux_reg(ARC_REG_VECBASE_BCR); - - switch (val & 0x03) { - case 0: - return 16; - case 1: - return 32; - case 2: - return 8; - default: - return 0; - } - - return 0; -} - /* * arch_local_irq_enable - Enable interrupts. * diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index 07a3a968fe49a1..fdd89715d2d378 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -150,6 +150,29 @@ int copy_thread(unsigned long clone_flags, return 0; } +/* + * Do necessary setup to start up a new user task + */ +void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long usp) +{ + set_fs(USER_DS); /* user space */ + + regs->sp = usp; + regs->ret = pc; + + /* + * [U]ser Mode bit set + * [L] ZOL loop inhibited to begin with - cleared by a LP insn + * Interrupts enabled + */ + regs->status32 = STATUS_U_MASK | STATUS_L_MASK | + STATUS_E1_MASK | STATUS_E2_MASK; + + /* bogus seed values for debugging */ + regs->lp_start = 0x10; + regs->lp_end = 0x80; +} + /* * Some archs flush debug and FPU info here */ diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c index 89edf7961a2f74..23c3832e6d9faf 100644 --- a/arch/arc/mm/cache_arc700.c +++ b/arch/arc/mm/cache_arc700.c @@ -253,12 +253,16 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr, if (cacheop == OP_INV_IC) { aux_cmd = ARC_REG_IC_IVIL; +#if (CONFIG_ARC_MMU_VER > 2) aux_tag = ARC_REG_IC_PTAG; +#endif } else { /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */ aux_cmd = cacheop & OP_INV ? ARC_REG_DC_IVDL : ARC_REG_DC_FLDL; +#if (CONFIG_ARC_MMU_VER > 2) aux_tag = ARC_REG_DC_PTAG; +#endif } /* Ensure we properly floor/ceil the non-line aligned/sized requests diff --git a/arch/arc/plat-arcfpga/Makefile b/arch/arc/plat-arcfpga/Makefile index a44e22ebc1b777..4d1bddc34b5b53 100644 --- a/arch/arc/plat-arcfpga/Makefile +++ b/arch/arc/plat-arcfpga/Makefile @@ -9,4 +9,4 @@ KBUILD_CFLAGS += -Iarch/arc/plat-arcfpga/include obj-y := platform.o irq.o -obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_ISS_SMP_EXTN) += smp.o diff --git a/arch/arc/plat-arcfpga/platform.c b/arch/arc/plat-arcfpga/platform.c index 19b76b61f44bfc..213394a15cd234 100644 --- a/arch/arc/plat-arcfpga/platform.c +++ b/arch/arc/plat-arcfpga/platform.c @@ -169,7 +169,7 @@ static void __init plat_fpga_early_init(void) arc_fpga_serial_init(); -#ifdef CONFIG_SMP +#ifdef CONFIG_ISS_SMP_EXTN iss_model_init_early_smp(); #endif } @@ -211,7 +211,7 @@ MACHINE_START(ANGEL4, "angel4") .init_early = plat_fpga_early_init, .init_machine = plat_fpga_populate_dev, .init_irq = plat_fpga_init_IRQ, -#ifdef CONFIG_SMP +#ifdef CONFIG_ISS_SMP_EXTN .init_smp = iss_model_init_smp, #endif MACHINE_END diff --git a/arch/arc/plat-arcfpga/smp.c b/arch/arc/plat-arcfpga/smp.c index 8a12741f5f7ab7..92bad9122077dc 100644 --- a/arch/arc/plat-arcfpga/smp.c +++ b/arch/arc/plat-arcfpga/smp.c @@ -42,6 +42,24 @@ static void iss_model_smp_wakeup_cpu(int cpu, unsigned long pc) } +static inline int get_hw_config_num_irq(void) +{ + uint32_t val = read_aux_reg(ARC_REG_VECBASE_BCR); + + switch (val & 0x03) { + case 0: + return 16; + case 1: + return 32; + case 2: + return 8; + default: + return 0; + } + + return 0; +} + /* * Any SMP specific init any CPU does when it comes up. * Here we setup the CPU to enable Inter-Processor-Interrupts diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 8f4cd2262692c4..173df9b06d842d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1647,9 +1647,9 @@ config ARCH_NR_GPIO int default 1024 if ARCH_SHMOBILE || ARCH_TEGRA default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || SOC_DRA7XX || ARCH_S3C24XX || ARCH_S3C64XX + default 416 if ARCH_SUNXI default 392 if ARCH_U8500 default 352 if ARCH_VT8500 - default 288 if ARCH_SUNXI default 264 if MACH_H4700 default 0 help @@ -2296,6 +2296,11 @@ config ARCH_SUSPEND_POSSIBLE config ARM_CPU_SUSPEND def_bool PM_SLEEP +config ARCH_HIBERNATION_POSSIBLE + bool + depends on MMU + default y if ARCH_SUSPEND_POSSIBLE + endmenu source "net/Kconfig" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index eab8ecbe69c1d2..00c69503da22b5 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -942,6 +942,15 @@ config DEBUG_IMX_UART_PORT Choose UART port on which kernel low-level debug messages should be output. +config DEBUG_VF_UART_PORT + int "Vybrid Debug UART Port Selection" if DEBUG_VF_UART + default 1 + range 0 3 + depends on SOC_VF610 + help + Choose UART port on which kernel low-level debug messages + should be output. + config DEBUG_TEGRA_UART bool depends on ARCH_TEGRA diff --git a/arch/arm/arm-soc-for-next-contents.txt b/arch/arm/arm-soc-for-next-contents.txt new file mode 100644 index 00000000000000..5f3b929fac5963 --- /dev/null +++ b/arch/arm/arm-soc-for-next-contents.txt @@ -0,0 +1,40 @@ +next/fixes-non-critical + +next/cleanup + versatile/leds + git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator tags/versatile-leds + cleanup/kconfig + git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux tags/kconfig-cleanups + contains randconfig-fixes + renesas/cleanup + git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-cleanup-for-v3.16 + +next/soc + renesas/soc + git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-soc-for-v3.16 + renesas/clock + git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-clock-for-v3.16 + +next/boards + shmobile/defconfig + git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-defconfig-for-v3.16 + patch + ARM: multi_v7: enable AT24C EEPROM driver + ARM: multi_v7_defconfig: select CONFIG_GPIO_DWAPB + ARM: multi_v7_defconfig: Select CONFIG_MACH_BERLIN_BG2Q + renesas/clock + Merge branch 'renesas/clock' into next/boards + renesas/boards + git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-boards-for-v3.16 + patch + ARM: configs: add CONFIG_MMC_SDHCI_PXAV3 to the multi_v7_defconfig + +next/dt + at91/dt + git://github.com/at91linux/linux-at91 tags/at91-dt + renesas/dt + git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-dt-for-v3.16 + +next/drivers + socfpga/reset-driver + git://git.rocketboards.org/linux-socfpga-next tags/socfpga-driver-update-for-3.16 diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 377b7c3640337e..228011312b494f 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -56,7 +56,8 @@ dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm28155-ap.dtb \ bcm21664-garnet.dtb dtb-$(CONFIG_ARCH_BERLIN) += \ berlin2-sony-nsz-gs7.dtb \ - berlin2cd-google-chromecast.dtb + berlin2cd-google-chromecast.dtb \ + berlin2q-marvell-dmp.dtb dtb-$(CONFIG_ARCH_DAVINCI) += da850-enbw-cmc.dtb \ da850-evm.dtb dtb-$(CONFIG_ARCH_EFM32) += efm32gg-dk3750.dtb @@ -72,7 +73,9 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \ exynos5250-arndale.dtb \ exynos5250-smdk5250.dtb \ exynos5250-snow.dtb \ + exynos5260-xyref5260.dtb \ exynos5420-arndale-octa.dtb \ + exynos5420-peach-pit.dtb \ exynos5420-smdk5420.dtb \ exynos5440-sd5v1.dtb \ exynos5440-ssdk5440.dtb @@ -157,10 +160,12 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx27-phytec-phycard-s-rdk.dtb \ imx31-bug.dtb \ imx35-eukrea-mbimxsd35-baseboard.dtb \ + imx35-pdk.dtb \ imx50-evk.dtb \ imx51-apf51.dtb \ imx51-apf51dev.dtb \ imx51-babbage.dtb \ + imx51-digi-connectcore-jsk.dtb \ imx51-eukrea-mbimxsd51-baseboard.dtb \ imx53-ard.dtb \ imx53-m53evk.dtb \ @@ -179,6 +184,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx6dl-gw54xx.dtb \ imx6dl-hummingboard.dtb \ imx6dl-nitrogen6x.dtb \ + imx6dl-phytec-pbab01.dtb \ imx6dl-sabreauto.dtb \ imx6dl-sabrelite.dtb \ imx6dl-sabresd.dtb \ @@ -203,6 +209,7 @@ dtb-$(CONFIG_ARCH_MXC) += \ imx6q-udoo.dtb \ imx6q-wandboard.dtb \ imx6sl-evk.dtb \ + vf610-colibri.dtb \ vf610-cosmic.dtb \ vf610-twr.dtb dtb-$(CONFIG_ARCH_MXS) += imx23-evk.dtb \ @@ -289,7 +296,10 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \ am43x-epos-evm.dtb \ am437x-gp-evm.dtb \ dra7-evm.dtb -dtb-$(CONFIG_ARCH_ORION5X) += orion5x-lacie-ethernet-disk-mini-v2.dtb +dtb-$(CONFIG_ARCH_ORION5X) += orion5x-lacie-d2-network.dtb \ + orion5x-lacie-ethernet-disk-mini-v2.dtb \ + orion5x-maxtor-shared-storage-2.dtb \ + orion5x-rd88f5182-nas.dtb dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb dtb-$(CONFIG_ARCH_QCOM) += qcom-msm8660-surf.dtb \ qcom-msm8960-cdp.dtb \ @@ -297,8 +307,7 @@ dtb-$(CONFIG_ARCH_QCOM) += qcom-msm8660-surf.dtb \ dtb-$(CONFIG_ARCH_S3C24XX) += s3c2416-smdk2416.dtb dtb-$(CONFIG_ARCH_S3C64XX) += s3c6410-mini6410.dtb \ s3c6410-smdk6410.dtb -dtb-$(CONFIG_ARCH_SHMOBILE_LEGACY) += emev2-kzm9d.dtb \ - r7s72100-genmai.dtb \ +dtb-$(CONFIG_ARCH_SHMOBILE_LEGACY) += r7s72100-genmai.dtb \ r7s72100-genmai-reference.dtb \ r8a7740-armadillo800eva.dtb \ r8a7778-bockw.dtb \ @@ -315,6 +324,7 @@ dtb-$(CONFIG_ARCH_SHMOBILE_LEGACY) += emev2-kzm9d.dtb \ sh7372-mackerel.dtb dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += emev2-kzm9d.dtb \ r7s72100-genmai-reference.dtb \ + r8a7791-henninger.dtb \ r8a7791-koelsch.dtb \ r8a7790-lager.dtb dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_arria5_socdk.dtb \ @@ -361,6 +371,8 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \ tegra30-cardhu-a02.dtb \ tegra30-cardhu-a04.dtb \ tegra114-dalmore.dtb \ + tegra114-tn7.dtb \ + tegra124-jetson-tk1.dtb \ tegra124-venice2.dtb dtb-$(CONFIG_ARCH_U300) += ste-u300.dtb dtb-$(CONFIG_ARCH_U8500) += ste-snowball.dtb \ diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index cb6811e5ae5a9a..baf56cc92040ed 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -665,6 +665,8 @@ mac: ethernet@4a100000 { compatible = "ti,cpsw"; ti,hwmods = "cpgmac0"; + clocks = <&cpsw_125mhz_gclk>, <&cpsw_cpts_rft_clk>; + clock-names = "fck", "cpts"; cpdma_channels = <8>; ale_entries = <1024>; bd_ram_size = <0x2000>; diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi index 788391f9168441..5a452fdd7c5d97 100644 --- a/arch/arm/boot/dts/am3517.dtsi +++ b/arch/arm/boot/dts/am3517.dtsi @@ -62,5 +62,21 @@ }; }; +&iva { + status = "disabled"; +}; + +&mailbox { + status = "disabled"; +}; + +&mmu_isp { + status = "disabled"; +}; + +&smartreflex_mpu_iva { + status = "disabled"; +}; + /include/ "am35xx-clocks.dtsi" /include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi" diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index d1f8707ff1dfc4..03a2255051260c 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -489,6 +489,8 @@ #address-cells = <1>; #size-cells = <1>; ti,hwmods = "cpgmac0"; + clocks = <&cpsw_125mhz_gclk>, <&cpsw_cpts_rft_clk>; + clock-names = "fck", "cpts"; status = "disabled"; cpdma_channels = <8>; ale_entries = <1024>; diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index df8798e8bd255b..a055f7f0f14ae5 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -117,6 +117,11 @@ status = "okay"; }; +&gpio5 { + status = "okay"; + ti,no-reset-on-init; +}; + &mmc1 { status = "okay"; vmmc-supply = <&vmmcsd_fixed>; diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts index 82f238a9063ffe..416f4e5a69c154 100644 --- a/arch/arm/boot/dts/armada-370-db.dts +++ b/arch/arm/boot/dts/armada-370-db.dts @@ -35,7 +35,6 @@ internal-regs { serial@12000 { - clock-frequency = <200000000>; status = "okay"; }; sata@a0000 { @@ -67,6 +66,7 @@ i2c@11000 { pinctrl-0 = <&i2c0_pins>; pinctrl-names = "default"; + clock-frequency = <100000>; status = "okay"; audio_codec: audio-codec@4a { compatible = "cirrus,cs42l51"; diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts index 2354fe023ee01e..097df7d8f0f6c6 100644 --- a/arch/arm/boot/dts/armada-370-mirabox.dts +++ b/arch/arm/boot/dts/armada-370-mirabox.dts @@ -47,7 +47,6 @@ internal-regs { serial@12000 { - clock-frequency = <200000000>; status = "okay"; }; timer@20300 { diff --git a/arch/arm/boot/dts/armada-370-netgear-rn102.dts b/arch/arm/boot/dts/armada-370-netgear-rn102.dts index 651aeb5ef43956..d6d572e5af3214 100644 --- a/arch/arm/boot/dts/armada-370-netgear-rn102.dts +++ b/arch/arm/boot/dts/armada-370-netgear-rn102.dts @@ -50,7 +50,6 @@ internal-regs { serial@12000 { - clock-frequency = <200000000>; status = "okay"; }; diff --git a/arch/arm/boot/dts/armada-370-netgear-rn104.dts b/arch/arm/boot/dts/armada-370-netgear-rn104.dts index 4e27587667bf5d..c5fe8b5dcdc7da 100644 --- a/arch/arm/boot/dts/armada-370-netgear-rn104.dts +++ b/arch/arm/boot/dts/armada-370-netgear-rn104.dts @@ -50,7 +50,6 @@ internal-regs { serial@12000 { - clock-frequency = <200000000>; status = "okay"; }; diff --git a/arch/arm/boot/dts/armada-370-rd.dts b/arch/arm/boot/dts/armada-370-rd.dts index 3e2c857d600008..4169f4096ea3bd 100644 --- a/arch/arm/boot/dts/armada-370-rd.dts +++ b/arch/arm/boot/dts/armada-370-rd.dts @@ -51,7 +51,6 @@ internal-regs { serial@12000 { - clock-frequency = <200000000>; status = "okay"; }; sata@a0000 { diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi index bb77970c0b1223..23227e0027ec3f 100644 --- a/arch/arm/boot/dts/armada-370-xp.dtsi +++ b/arch/arm/boot/dts/armada-370-xp.dtsi @@ -157,6 +157,7 @@ reg-shift = <2>; interrupts = <41>; reg-io-width = <1>; + clocks = <&coreclk 0>; status = "disabled"; }; serial@12100 { @@ -165,6 +166,7 @@ reg-shift = <2>; interrupts = <42>; reg-io-width = <1>; + clocks = <&coreclk 0>; status = "disabled"; }; @@ -203,6 +205,11 @@ reg = <0x20300 0x34>, <0x20704 0x4>; }; + pmsu@22000 { + compatible = "marvell,armada-370-pmsu"; + reg = <0x22000 0x1000>; + }; + usb@50000 { compatible = "marvell,orion-ehci"; reg = <0x50000 0x500>; diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi index af1f11e9e5a011..21b588b6f6bd75 100644 --- a/arch/arm/boot/dts/armada-370.dtsi +++ b/arch/arm/boot/dts/armada-370.dtsi @@ -220,6 +220,11 @@ clocks = <&coreclk 2>; }; + cpurst@20800 { + compatible = "marvell,armada-370-cpu-reset"; + reg = <0x20800 0x8>; + }; + audio_controller: audio-controller@30000 { compatible = "marvell,armada370-audio"; reg = <0x30000 0x4000>; diff --git a/arch/arm/boot/dts/armada-375-db.dts b/arch/arm/boot/dts/armada-375-db.dts index 9378d3136b41d7..20f1f33c947d73 100644 --- a/arch/arm/boot/dts/armada-375-db.dts +++ b/arch/arm/boot/dts/armada-375-db.dts @@ -68,7 +68,6 @@ }; serial@12000 { - clock-frequency = <200000000>; status = "okay"; }; @@ -79,6 +78,11 @@ }; }; + sata@a0000 { + status = "okay"; + nr-ports = <2>; + }; + nand: nand@d0000 { pinctrl-0 = <&nand_pins>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/armada-375.dtsi b/arch/arm/boot/dts/armada-375.dtsi index 3877693fb2d875..3b6de4c0e37922 100644 --- a/arch/arm/boot/dts/armada-375.dtsi +++ b/arch/arm/boot/dts/armada-375.dtsi @@ -39,6 +39,8 @@ cpus { #address-cells = <1>; #size-cells = <0>; + enable-method = "marvell,armada-375-smp"; + cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a9"; @@ -128,6 +130,11 @@ cache-level = <2>; }; + scu@c000 { + compatible = "arm,cortex-a9-scu"; + reg = <0xc000 0x58>; + }; + timer@c600 { compatible = "arm,cortex-a9-twd-timer"; reg = <0xc600 0x20>; @@ -194,6 +201,7 @@ reg-shift = <2>; interrupts = ; reg-io-width = <1>; + clocks = <&coreclk 0>; status = "disabled"; }; @@ -203,6 +211,7 @@ reg-shift = <2>; interrupts = ; reg-io-width = <1>; + clocks = <&coreclk 0>; status = "disabled"; }; @@ -320,6 +329,22 @@ clocks = <&coreclk 0>; }; + watchdog@20300 { + compatible = "marvell,armada-375-wdt"; + reg = <0x20300 0x34>, <0x20704 0x4>, <0x18254 0x4>; + clocks = <&coreclk 0>; + }; + + cpurst@20800 { + compatible = "marvell,armada-370-cpu-reset"; + reg = <0x20800 0x10>; + }; + + coherency-fabric@21010 { + compatible = "marvell,armada-375-coherency-fabric"; + reg = <0x21010 0x1c>; + }; + xor@60800 { compatible = "marvell,orion-xor"; reg = <0x60800 0x100 @@ -391,6 +416,12 @@ status = "disabled"; }; + thermal@e8078 { + compatible = "marvell,armada375-thermal"; + reg = <0xe8078 0x4>, <0xe807c 0x8>; + status = "okay"; + }; + coreclk: mvebu-sar@e8204 { compatible = "marvell,armada-375-core-clock"; reg = <0xe8204 0x04>; diff --git a/arch/arm/boot/dts/armada-380.dtsi b/arch/arm/boot/dts/armada-380.dtsi index 068031f0f263ef..aa71718b549d0a 100644 --- a/arch/arm/boot/dts/armada-380.dtsi +++ b/arch/arm/boot/dts/armada-380.dtsi @@ -21,6 +21,8 @@ cpus { #address-cells = <1>; #size-cells = <0>; + enable-method = "marvell,armada-380-smp"; + cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a9"; diff --git a/arch/arm/boot/dts/armada-385-db.dts b/arch/arm/boot/dts/armada-385-db.dts index 6828d77696a676..7fcbc0d2a85ff8 100644 --- a/arch/arm/boot/dts/armada-385-db.dts +++ b/arch/arm/boot/dts/armada-385-db.dts @@ -55,7 +55,6 @@ }; serial@12000 { - clock-frequency = <200000000>; status = "okay"; }; @@ -81,6 +80,14 @@ }; }; + sata@a8000 { + status = "okay"; + }; + + sata@e0000 { + status = "okay"; + }; + flash@d0000 { status = "okay"; num-cs = <1>; @@ -101,6 +108,14 @@ reg = <0x1000000 0x3f000000>; }; }; + + sdhci@d8000 { + clock-frequency = <200000000>; + broken-cd; + wp-inverted; + bus-width = <8>; + status = "okay"; + }; }; pcie-controller { diff --git a/arch/arm/boot/dts/armada-385-rd.dts b/arch/arm/boot/dts/armada-385-rd.dts index 45250c88814b89..4b39bed4ed07d1 100644 --- a/arch/arm/boot/dts/armada-385-rd.dts +++ b/arch/arm/boot/dts/armada-385-rd.dts @@ -51,7 +51,6 @@ }; serial@12000 { - clock-frequency = <200000000>; status = "okay"; }; diff --git a/arch/arm/boot/dts/armada-385.dtsi b/arch/arm/boot/dts/armada-385.dtsi index e2919f02e1d476..2c7990d6efa220 100644 --- a/arch/arm/boot/dts/armada-385.dtsi +++ b/arch/arm/boot/dts/armada-385.dtsi @@ -21,6 +21,8 @@ cpus { #address-cells = <1>; #size-cells = <0>; + enable-method = "marvell,armada-380-smp"; + cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a9"; diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi index ca8813bb99ba62..6ee59a34408902 100644 --- a/arch/arm/boot/dts/armada-38x.dtsi +++ b/arch/arm/boot/dts/armada-38x.dtsi @@ -108,6 +108,11 @@ cache-level = <2>; }; + scu@c000 { + compatible = "arm,cortex-a9-scu"; + reg = <0xc000 0x58>; + }; + timer@c600 { compatible = "arm,cortex-a9-twd-timer"; reg = <0xc600 0x20>; @@ -174,6 +179,7 @@ reg-shift = <2>; interrupts = ; reg-io-width = <1>; + clocks = <&coreclk 0>; status = "disabled"; }; @@ -183,6 +189,7 @@ reg-shift = <2>; interrupts = ; reg-io-width = <1>; + clocks = <&coreclk 0>; status = "disabled"; }; @@ -267,6 +274,28 @@ clock-names = "nbclk", "fixed"; }; + watchdog@20300 { + compatible = "marvell,armada-380-wdt"; + reg = <0x20300 0x34>, <0x20704 0x4>, <0x18260 0x4>; + clocks = <&coreclk 2>, <&refclk>; + clock-names = "nbclk", "fixed"; + }; + + cpurst@20800 { + compatible = "marvell,armada-370-cpu-reset"; + reg = <0x20800 0x10>; + }; + + coherency-fabric@21010 { + compatible = "marvell,armada-380-coherency-fabric"; + reg = <0x21010 0x1c>; + }; + + pmsu@22000 { + compatible = "marvell,armada-380-pmsu"; + reg = <0x22000 0x1000>; + }; + eth1: ethernet@30000 { compatible = "marvell,armada-370-neta"; reg = <0x30000 0x4000>; @@ -339,6 +368,22 @@ clocks = <&gateclk 4>; }; + sata@a8000 { + compatible = "marvell,armada-380-ahci"; + reg = <0xa8000 0x2000>; + interrupts = ; + clocks = <&gateclk 15>; + status = "disabled"; + }; + + sata@e0000 { + compatible = "marvell,armada-380-ahci"; + reg = <0xe0000 0x2000>; + interrupts = ; + clocks = <&gateclk 30>; + status = "disabled"; + }; + coredivclk: clock@e4250 { compatible = "marvell,armada-380-corediv-clock"; reg = <0xe4250 0xc>; @@ -347,6 +392,12 @@ clock-output-names = "nand"; }; + thermal@e8078 { + compatible = "marvell,armada380-thermal"; + reg = <0xe4078 0x4>, <0xe4074 0x4>; + status = "okay"; + }; + flash@d0000 { compatible = "marvell,armada370-nand"; reg = <0xd0000 0x54>; @@ -356,6 +407,15 @@ clocks = <&coredivclk 0>; status = "disabled"; }; + + sdhci@d8000 { + compatible = "marvell,armada-380-sdhci"; + reg = <0xd8000 0x1000>, <0xdc000 0x100>; + interrupts = <0 25 0x4>; + clocks = <&gateclk 17>; + mrvl,clk-delay-cycles = <0x1F>; + status = "disabled"; + }; }; }; diff --git a/arch/arm/boot/dts/armada-xp-axpwifiap.dts b/arch/arm/boot/dts/armada-xp-axpwifiap.dts index d83d7d69ac01ff..a55a97a705056a 100644 --- a/arch/arm/boot/dts/armada-xp-axpwifiap.dts +++ b/arch/arm/boot/dts/armada-xp-axpwifiap.dts @@ -95,12 +95,10 @@ }; serial@12000 { - clock-frequency = <250000000>; status = "okay"; }; serial@12100 { - clock-frequency = <250000000>; status = "okay"; }; diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts index 448373c4b0e534..42ddb286436568 100644 --- a/arch/arm/boot/dts/armada-xp-db.dts +++ b/arch/arm/boot/dts/armada-xp-db.dts @@ -49,7 +49,7 @@ /* Device Bus parameters are required */ /* Read parameters */ - devbus,bus-width = <8>; + devbus,bus-width = <16>; devbus,turn-off-ps = <60000>; devbus,badr-skew-ps = <0>; devbus,acc-first-ps = <124000>; @@ -106,19 +106,15 @@ internal-regs { serial@12000 { - clock-frequency = <250000000>; status = "okay"; }; serial@12100 { - clock-frequency = <250000000>; status = "okay"; }; serial@12200 { - clock-frequency = <250000000>; status = "okay"; }; serial@12300 { - clock-frequency = <250000000>; status = "okay"; }; diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts index 61bda687f782f6..0478c55ca6567a 100644 --- a/arch/arm/boot/dts/armada-xp-gp.dts +++ b/arch/arm/boot/dts/armada-xp-gp.dts @@ -59,7 +59,7 @@ /* Device Bus parameters are required */ /* Read parameters */ - devbus,bus-width = <8>; + devbus,bus-width = <16>; devbus,turn-off-ps = <60000>; devbus,badr-skew-ps = <0>; devbus,acc-first-ps = <124000>; @@ -104,19 +104,15 @@ internal-regs { serial@12000 { - clock-frequency = <250000000>; status = "okay"; }; serial@12100 { - clock-frequency = <250000000>; status = "okay"; }; serial@12200 { - clock-frequency = <250000000>; status = "okay"; }; serial@12300 { - clock-frequency = <250000000>; status = "okay"; }; @@ -146,22 +142,22 @@ ethernet@70000 { status = "okay"; phy = <&phy0>; - phy-mode = "rgmii-id"; + phy-mode = "qsgmii"; }; ethernet@74000 { status = "okay"; phy = <&phy1>; - phy-mode = "rgmii-id"; + phy-mode = "qsgmii"; }; ethernet@30000 { status = "okay"; phy = <&phy2>; - phy-mode = "rgmii-id"; + phy-mode = "qsgmii"; }; ethernet@34000 { status = "okay"; phy = <&phy3>; - phy-mode = "rgmii-id"; + phy-mode = "qsgmii"; }; /* Front-side USB slot */ diff --git a/arch/arm/boot/dts/armada-xp-matrix.dts b/arch/arm/boot/dts/armada-xp-matrix.dts index c2242745b9b87a..25674fe81f703d 100644 --- a/arch/arm/boot/dts/armada-xp-matrix.dts +++ b/arch/arm/boot/dts/armada-xp-matrix.dts @@ -37,19 +37,15 @@ internal-regs { serial@12000 { - clock-frequency = <250000000>; status = "okay"; }; serial@12100 { - clock-frequency = <250000000>; status = "okay"; }; serial@12200 { - clock-frequency = <250000000>; status = "okay"; }; serial@12300 { - clock-frequency = <250000000>; status = "okay"; }; diff --git a/arch/arm/boot/dts/armada-xp-mv78230.dtsi b/arch/arm/boot/dts/armada-xp-mv78230.dtsi index 98335fb34b7ad5..1257ff1ed278e6 100644 --- a/arch/arm/boot/dts/armada-xp-mv78230.dtsi +++ b/arch/arm/boot/dts/armada-xp-mv78230.dtsi @@ -27,6 +27,7 @@ cpus { #address-cells = <1>; #size-cells = <0>; + enable-method = "marvell,armada-xp-smp"; cpu@0 { device_type = "cpu"; diff --git a/arch/arm/boot/dts/armada-xp-mv78260.dtsi b/arch/arm/boot/dts/armada-xp-mv78260.dtsi index 9480cf891f8cd0..3396b25b39e179 100644 --- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi +++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi @@ -29,6 +29,7 @@ cpus { #address-cells = <1>; #size-cells = <0>; + enable-method = "marvell,armada-xp-smp"; cpu@0 { device_type = "cpu"; diff --git a/arch/arm/boot/dts/armada-xp-mv78460.dtsi b/arch/arm/boot/dts/armada-xp-mv78460.dtsi index 31ba6d8fbadf88..6da84bf40aaf48 100644 --- a/arch/arm/boot/dts/armada-xp-mv78460.dtsi +++ b/arch/arm/boot/dts/armada-xp-mv78460.dtsi @@ -30,6 +30,7 @@ cpus { #address-cells = <1>; #size-cells = <0>; + enable-method = "marvell,armada-xp-smp"; cpu@0 { device_type = "cpu"; diff --git a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts index ff049ee862ebd2..0cf999abc4ed76 100644 --- a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts +++ b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts @@ -138,7 +138,6 @@ }; serial@12000 { - clocks = <&coreclk 0>; status = "okay"; }; diff --git a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts index 985948ce67b327..e5c6a0492ca00b 100644 --- a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts +++ b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts @@ -39,7 +39,7 @@ /* Device Bus parameters are required */ /* Read parameters */ - devbus,bus-width = <8>; + devbus,bus-width = <16>; devbus,turn-off-ps = <60000>; devbus,badr-skew-ps = <0>; devbus,acc-first-ps = <124000>; @@ -72,11 +72,9 @@ internal-regs { serial@12000 { - clock-frequency = <250000000>; status = "okay"; }; serial@12100 { - clock-frequency = <250000000>; status = "okay"; }; pinctrl { diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi index abb9f9dcc525a6..5902e8359c9165 100644 --- a/arch/arm/boot/dts/armada-xp.dtsi +++ b/arch/arm/boot/dts/armada-xp.dtsi @@ -58,6 +58,7 @@ reg-shift = <2>; interrupts = <43>; reg-io-width = <1>; + clocks = <&coreclk 0>; status = "disabled"; }; serial@12300 { @@ -66,6 +67,7 @@ reg-shift = <2>; interrupts = <44>; reg-io-width = <1>; + clocks = <&coreclk 0>; status = "disabled"; }; @@ -117,9 +119,9 @@ clock-names = "nbclk", "fixed"; }; - armada-370-xp-pmsu@22000 { - compatible = "marvell,armada-370-xp-pmsu"; - reg = <0x22100 0x400>, <0x20800 0x20>; + cpurst@20800 { + compatible = "marvell,armada-370-cpu-reset"; + reg = <0x20800 0x20>; }; eth2: ethernet@30000 { diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts index ce1375595e5f27..4537259ce5299b 100644 --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts @@ -34,7 +34,7 @@ }; spi0: spi@f0004000 { - cs-gpios = <&pioD 13 0>; + cs-gpios = <&pioD 13 0>, <0>, <0>, <&pioD 16 0>; status = "okay"; }; @@ -79,7 +79,7 @@ }; spi1: spi@f8008000 { - cs-gpios = <&pioC 25 0>, <0>, <0>, <&pioD 16 0>; + cs-gpios = <&pioC 25 0>; status = "okay"; }; diff --git a/arch/arm/boot/dts/at91sam9261.dtsi b/arch/arm/boot/dts/at91sam9261.dtsi index e21dda0e898657..3be973e9889a2b 100644 --- a/arch/arm/boot/dts/at91sam9261.dtsi +++ b/arch/arm/boot/dts/at91sam9261.dtsi @@ -10,7 +10,7 @@ #include #include #include -#include +#include / { model = "Atmel AT91SAM9261 family SoC"; diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index 9cdaecff13b399..ace6bf197b708d 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -136,6 +136,36 @@ >; /* shared pinctrl settings */ + adc0 { + pinctrl_adc0_adtrg: adc0_adtrg { + atmel,pins = ; + }; + pinctrl_adc0_ad0: adc0_ad0 { + atmel,pins = ; + }; + pinctrl_adc0_ad1: adc0_ad1 { + atmel,pins = ; + }; + pinctrl_adc0_ad2: adc0_ad2 { + atmel,pins = ; + }; + pinctrl_adc0_ad3: adc0_ad3 { + atmel,pins = ; + }; + pinctrl_adc0_ad4: adc0_ad4 { + atmel,pins = ; + }; + pinctrl_adc0_ad5: adc0_ad5 { + atmel,pins = ; + }; + pinctrl_adc0_ad6: adc0_ad6 { + atmel,pins = ; + }; + pinctrl_adc0_ad7: adc0_ad7 { + atmel,pins = ; + }; + }; + dbgu { pinctrl_dbgu: dbgu-0 { atmel,pins = @@ -634,10 +664,9 @@ adc0: adc@fffb0000 { #address-cells = <1>; #size-cells = <0>; - compatible = "atmel,at91sam9260-adc"; + compatible = "atmel,at91sam9g45-adc"; reg = <0xfffb0000 0x100>; interrupts = <20 IRQ_TYPE_LEVEL_HIGH 0>; - atmel,adc-use-external-triggers; atmel,adc-channels-used = <0xff>; atmel,adc-vref = <3300>; atmel,adc-startup-time = <40>; diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts index 7ff665a8c7080b..9f5b0a67499557 100644 --- a/arch/arm/boot/dts/at91sam9m10g45ek.dts +++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts @@ -8,6 +8,7 @@ */ /dts-v1/; #include "at91sam9g45.dtsi" +#include / { model = "Atmel AT91SAM9M10G45-EK"; @@ -130,6 +131,21 @@ status = "okay"; }; + adc0: adc@fffb0000 { + pinctrl-names = "default"; + pinctrl-0 = < + &pinctrl_adc0_ad0 + &pinctrl_adc0_ad1 + &pinctrl_adc0_ad2 + &pinctrl_adc0_ad3 + &pinctrl_adc0_ad4 + &pinctrl_adc0_ad5 + &pinctrl_adc0_ad6 + &pinctrl_adc0_ad7>; + atmel,adc-ts-wires = <4>; + status = "okay"; + }; + pwm0: pwm@fffb8000 { status = "okay"; @@ -216,14 +232,14 @@ d6 { label = "d6"; - pwms = <&pwm0 3 5000 0>; + pwms = <&pwm0 3 5000 PWM_POLARITY_INVERTED>; max-brightness = <255>; linux,default-trigger = "nand-disk"; }; d7 { label = "d7"; - pwms = <&pwm0 1 5000 0>; + pwms = <&pwm0 1 5000 PWM_POLARITY_INVERTED>; max-brightness = <255>; linux,default-trigger = "mmc0"; }; diff --git a/arch/arm/boot/dts/at91sam9rl.dtsi b/arch/arm/boot/dts/at91sam9rl.dtsi index 63e1784d272c55..b9714f5c61dcd5 100644 --- a/arch/arm/boot/dts/at91sam9rl.dtsi +++ b/arch/arm/boot/dts/at91sam9rl.dtsi @@ -8,9 +8,10 @@ #include "skeleton.dtsi" #include -#include +#include #include #include +#include / { model = "Atmel AT91SAM9RL family SoC"; @@ -32,6 +33,7 @@ i2c1 = &i2c1; ssc0 = &ssc0; ssc1 = &ssc1; + pwm0 = &pwm0; }; cpus { @@ -48,12 +50,31 @@ reg = <0x20000000 0x04000000>; }; + clocks { + adc_op_clk: adc_op_clk{ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000>; + }; + }; + ahb { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges; + fb0: fb@00500000 { + compatible = "atmel,at91sam9rl-lcdc"; + reg = <0x00500000 0x1000>; + interrupts = <23 IRQ_TYPE_LEVEL_HIGH 3>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fb>; + clocks = <&lcd_clk>, <&lcd_clk>; + clock-names = "hclk", "lcdc_clk"; + status = "disabled"; + }; + nand0: nand@40000000 { compatible = "atmel,at91rm9200-nand"; #address-cells = <1>; @@ -187,6 +208,16 @@ status = "disabled"; }; + pwm0: pwm@fffc8000 { + compatible = "atmel,at91sam9rl-pwm"; + reg = <0xfffc8000 0x300>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH 4>; + #pwm-cells = <3>; + clocks = <&pwm_clk>; + clock-names = "pwm_clk"; + status = "disabled"; + }; + spi0: spi@fffcc000 { #address-cells = <1>; #size-cells = <0>; @@ -200,6 +231,111 @@ status = "disabled"; }; + adc0: adc@fffd0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "atmel,at91sam9rl-adc"; + reg = <0xfffd0000 0x100>; + interrupts = <20 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&adc_clk>, <&adc_op_clk>; + clock-names = "adc_clk", "adc_op_clk"; + atmel,adc-use-external-triggers; + atmel,adc-channels-used = <0x3f>; + atmel,adc-vref = <3300>; + atmel,adc-startup-time = <40>; + atmel,adc-res = <8 10>; + atmel,adc-res-names = "lowres", "highres"; + atmel,adc-use-res = "highres"; + + trigger@0 { + reg = <0>; + trigger-name = "timer-counter-0"; + trigger-value = <0x1>; + }; + trigger@1 { + reg = <1>; + trigger-name = "timer-counter-1"; + trigger-value = <0x3>; + }; + + trigger@2 { + reg = <2>; + trigger-name = "timer-counter-2"; + trigger-value = <0x5>; + }; + + trigger@3 { + reg = <3>; + trigger-name = "external"; + trigger-value = <0x13>; + trigger-external; + }; + }; + + usb0: gadget@fffd4000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "atmel,at91sam9rl-udc"; + reg = <0x00600000 0x100000>, + <0xfffd4000 0x4000>; + interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>; + clocks = <&udphs_clk>, <&utmi>; + clock-names = "pclk", "hclk"; + status = "disabled"; + + ep0 { + reg = <0>; + atmel,fifo-size = <64>; + atmel,nb-banks = <1>; + }; + + ep1 { + reg = <1>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep2 { + reg = <2>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep3 { + reg = <3>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <3>; + atmel,can-dma; + }; + + ep4 { + reg = <4>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <3>; + atmel,can-dma; + }; + + ep5 { + reg = <5>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <3>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep6 { + reg = <6>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <3>; + atmel,can-dma; + atmel,can-isoc; + }; + }; + ramc0: ramc@ffffea00 { compatible = "atmel,at91sam9260-sdramc"; reg = <0xffffea00 0x200>; @@ -238,6 +374,44 @@ <0x003fffff 0x0001ff3c>; /* pioD */ /* shared pinctrl settings */ + adc0 { + pinctrl_adc0_ts: adc0_ts-0 { + atmel,pins = + , + , + , + ; + }; + + pinctrl_adc0_ad0: adc0_ad0-0 { + atmel,pins = ; + }; + + pinctrl_adc0_ad1: adc0_ad1-0 { + atmel,pins = ; + }; + + pinctrl_adc0_ad2: adc0_ad2-0 { + atmel,pins = ; + }; + + pinctrl_adc0_ad3: adc0_ad3-0 { + atmel,pins = ; + }; + + pinctrl_adc0_ad4: adc0_ad4-0 { + atmel,pins = ; + }; + + pinctrl_adc0_ad5: adc0_ad5-0 { + atmel,pins = ; + }; + + pinctrl_adc0_adtrg: adc0_adtrg-0 { + atmel,pins = ; + }; + }; + dbgu { pinctrl_dbgu: dbgu-0 { atmel,pins = @@ -246,6 +420,33 @@ }; }; + fb { + pinctrl_fb: fb-0 { + atmel,pins = + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + }; + i2c_gpio0 { pinctrl_i2c_gpio0: i2c_gpio0-0 { atmel,pins = @@ -307,6 +508,61 @@ }; }; + pwm0 { + pinctrl_pwm0_pwm0_0: pwm0_pwm0-0 { + atmel,pins = ; + }; + + pinctrl_pwm0_pwm0_1: pwm0_pwm0-1 { + atmel,pins = ; + }; + + pinctrl_pwm0_pwm0_2: pwm0_pwm0-2 { + atmel,pins = ; + }; + + pinctrl_pwm0_pwm1_0: pwm0_pwm1-0 { + atmel,pins = ; + }; + + pinctrl_pwm0_pwm1_1: pwm0_pwm1-1 { + atmel,pins = ; + }; + + pinctrl_pwm0_pwm1_2: pwm0_pwm1-2 { + atmel,pins = ; + }; + + pinctrl_pwm0_pwm2_0: pwm0_pwm2-0 { + atmel,pins = ; + }; + + pinctrl_pwm0_pwm2_1: pwm0_pwm2-1 { + atmel,pins = ; + }; + + pinctrl_pwm0_pwm2_2: pwm0_pwm2-2 { + atmel,pins = ; + }; + + pinctrl_pwm0_pwm3_0: pwm0_pwm3-0 { + atmel,pins = ; + }; + + pinctrl_pwm0_pwm3_1: pwm0_pwm3-1 { + atmel,pins = ; + }; + }; + + spi0 { + pinctrl_spi0: spi0-0 { + atmel,pins = + , + , + ; + }; + }; + ssc0 { pinctrl_ssc0_tx: ssc0_tx-0 { atmel,pins = @@ -339,15 +595,6 @@ }; }; - spi0 { - pinctrl_spi0: spi0-0 { - atmel,pins = - , - , - ; - }; - }; - tcb0 { pinctrl_tcb0_tclk0: tcb0_tclk0-0 { atmel,pins = ; diff --git a/arch/arm/boot/dts/at91sam9rlek.dts b/arch/arm/boot/dts/at91sam9rlek.dts index cddb37825fad5a..f148fa4b3ab98d 100644 --- a/arch/arm/boot/dts/at91sam9rlek.dts +++ b/arch/arm/boot/dts/at91sam9rlek.dts @@ -32,6 +32,37 @@ }; ahb { + fb0: fb@00500000 { + display = <&display0>; + status = "okay"; + + display0: display { + bits-per-pixel = <16>; + atmel,lcdcon-backlight; + atmel,dmacon = <0x1>; + atmel,lcdcon2 = <0x80008002>; + atmel,guard-time = <1>; + atmel,lcd-wiring-mode = "RGB"; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <4965000>; + hactive = <240>; + vactive = <320>; + hback-porch = <1>; + hfront-porch = <33>; + vback-porch = <1>; + vfront-porch = <0>; + hsync-len = <5>; + vsync-len = <1>; + hsync-active = <1>; + vsync-active = <1>; + }; + }; + }; + }; + nand0: nand@40000000 { nand-bus-width = <8>; nand-ecc-mode = "soft"; @@ -92,6 +123,43 @@ status = "okay"; }; + adc0: adc@fffd0000 { + pinctrl-names = "default"; + pinctrl-0 = < + &pinctrl_adc0_ad0 + &pinctrl_adc0_ad1 + &pinctrl_adc0_ad2 + &pinctrl_adc0_ad3 + &pinctrl_adc0_ad4 + &pinctrl_adc0_ad5 + &pinctrl_adc0_adtrg>; + atmel,adc-ts-wires = <4>; + status = "okay"; + }; + + usb0: gadget@fffd4000 { + atmel,vbus-gpio = <&pioA 8 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; + + spi0: spi@fffcc000 { + status = "okay"; + cs-gpios = <&pioA 28 0>, <0>, <0>, <0>; + mtd_dataflash@0 { + compatible = "atmel,at45", "atmel,dataflash"; + spi-max-frequency = <15000000>; + reg = <0>; + }; + }; + + pwm0: pwm@fffc8000 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_pwm1_2>, + <&pinctrl_pwm0_pwm2_2>; + }; + dbgu: serial@fffff200 { status = "okay"; }; @@ -117,18 +185,24 @@ }; }; - leds { - compatible = "gpio-leds"; + pwmleds { + compatible = "pwm-leds"; ds1 { label = "ds1"; - gpios = <&pioD 15 GPIO_ACTIVE_LOW>; + pwms = <&pwm0 1 5000 PWM_POLARITY_INVERTED>; + max-brightness = <255>; }; ds2 { label = "ds2"; - gpios = <&pioD 16 GPIO_ACTIVE_LOW>; + pwms = <&pwm0 2 5000 PWM_POLARITY_INVERTED>; + max-brightness = <255>; }; + }; + + leds { + compatible = "gpio-leds"; ds3 { label = "ds3"; @@ -154,4 +228,12 @@ gpio-key,wakeup; }; }; + + i2c@0 { + status = "okay"; + }; + + i2c@1 { + status = "okay"; + }; }; diff --git a/arch/arm/boot/dts/bcm21664.dtsi b/arch/arm/boot/dts/bcm21664.dtsi index 08a44d41b6723f..8b366822bb43bc 100644 --- a/arch/arm/boot/dts/bcm21664.dtsi +++ b/arch/arm/boot/dts/bcm21664.dtsi @@ -14,6 +14,8 @@ #include #include +#include "dt-bindings/clock/bcm21664.h" + #include "skeleton.dtsi" / { @@ -43,7 +45,7 @@ compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; status = "disabled"; reg = <0x3e000000 0x118>; - clocks = <&uartb_clk>; + clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB>; interrupts = ; reg-shift = <2>; reg-io-width = <4>; @@ -53,7 +55,7 @@ compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; status = "disabled"; reg = <0x3e001000 0x118>; - clocks = <&uartb2_clk>; + clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB2>; interrupts = ; reg-shift = <2>; reg-io-width = <4>; @@ -63,7 +65,7 @@ compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; status = "disabled"; reg = <0x3e002000 0x118>; - clocks = <&uartb3_clk>; + clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB3>; interrupts = ; reg-shift = <2>; reg-io-width = <4>; @@ -85,7 +87,7 @@ compatible = "brcm,kona-timer"; reg = <0x35006000 0x1c>; interrupts = ; - clocks = <&hub_timer_clk>; + clocks = <&aon_ccu BCM21664_AON_CCU_HUB_TIMER>; }; gpio: gpio@35003000 { @@ -106,7 +108,7 @@ compatible = "brcm,kona-sdhci"; reg = <0x3f180000 0x801c>; interrupts = ; - clocks = <&sdio1_clk>; + clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO1>; status = "disabled"; }; @@ -114,7 +116,7 @@ compatible = "brcm,kona-sdhci"; reg = <0x3f190000 0x801c>; interrupts = ; - clocks = <&sdio2_clk>; + clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO2>; status = "disabled"; }; @@ -122,7 +124,7 @@ compatible = "brcm,kona-sdhci"; reg = <0x3f1a0000 0x801c>; interrupts = ; - clocks = <&sdio3_clk>; + clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO3>; status = "disabled"; }; @@ -130,7 +132,7 @@ compatible = "brcm,kona-sdhci"; reg = <0x3f1b0000 0x801c>; interrupts = ; - clocks = <&sdio4_clk>; + clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO4>; status = "disabled"; }; @@ -140,7 +142,7 @@ interrupts = ; #address-cells = <1>; #size-cells = <0>; - clocks = <&bsc1_clk>; + clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC1>; status = "disabled"; }; @@ -150,7 +152,7 @@ interrupts = ; #address-cells = <1>; #size-cells = <0>; - clocks = <&bsc2_clk>; + clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC2>; status = "disabled"; }; @@ -160,7 +162,7 @@ interrupts = ; #address-cells = <1>; #size-cells = <0>; - clocks = <&bsc3_clk>; + clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC3>; status = "disabled"; }; @@ -170,105 +172,149 @@ interrupts = ; #address-cells = <1>; #size-cells = <0>; - clocks = <&bsc4_clk>; + clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC4>; status = "disabled"; }; clocks { - bsc1_clk: bsc1 { - compatible = "fixed-clock"; - clock-frequency = <13000000>; - #clock-cells = <0>; - }; + #address-cells = <1>; + #size-cells = <1>; + ranges; - bsc2_clk: bsc2 { - compatible = "fixed-clock"; - clock-frequency = <13000000>; + /* + * Fixed clocks are defined before CCUs whose + * clocks may depend on them. + */ + + ref_32k_clk: ref_32k { #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; }; - bsc3_clk: bsc3 { - compatible = "fixed-clock"; - clock-frequency = <13000000>; + bbl_32k_clk: bbl_32k { #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; }; - bsc4_clk: bsc4 { + ref_13m_clk: ref_13m { + #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <13000000>; - #clock-cells = <0>; }; - pmu_bsc_clk: pmu_bsc { + var_13m_clk: var_13m { + #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <13000000>; - #clock-cells = <0>; }; - hub_timer_clk: hub_timer { - compatible = "fixed-clock"; - clock-frequency = <32768>; + dft_19_5m_clk: dft_19_5m { #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <19500000>; }; - pwm_clk: pwm { + ref_crystal_clk: ref_crystal { + #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <26000000>; - #clock-cells = <0>; }; - sdio1_clk: sdio1 { - compatible = "fixed-clock"; - clock-frequency = <48000000>; + ref_52m_clk: ref_52m { #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <52000000>; }; - sdio2_clk: sdio2 { - compatible = "fixed-clock"; - clock-frequency = <48000000>; + var_52m_clk: var_52m { #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <52000000>; }; - sdio3_clk: sdio3 { - compatible = "fixed-clock"; - clock-frequency = <48000000>; + usb_otg_ahb_clk: usb_otg_ahb { #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <52000000>; }; - sdio4_clk: sdio4 { - compatible = "fixed-clock"; - clock-frequency = <48000000>; + ref_96m_clk: ref_96m { #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <96000000>; }; - tmon_1m_clk: tmon_1m { - compatible = "fixed-clock"; - clock-frequency = <1000000>; + var_96m_clk: var_96m { #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <96000000>; }; - uartb_clk: uartb { - compatible = "fixed-clock"; - clock-frequency = <13000000>; + ref_104m_clk: ref_104m { #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <104000000>; }; - uartb2_clk: uartb2 { - compatible = "fixed-clock"; - clock-frequency = <13000000>; + var_104m_clk: var_104m { #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <104000000>; }; - uartb3_clk: uartb3 { - compatible = "fixed-clock"; - clock-frequency = <13000000>; + ref_156m_clk: ref_156m { #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <156000000>; }; - usb_otg_ahb_clk: usb_otg_ahb { - compatible = "fixed-clock"; - clock-frequency = <52000000>; + var_156m_clk: var_156m { #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <156000000>; + }; + + root_ccu: root_ccu { + compatible = BCM21664_DT_ROOT_CCU_COMPAT; + reg = <0x35001000 0x0f00>; + #clock-cells = <1>; + clock-output-names = "frac_1m"; + }; + + aon_ccu: aon_ccu { + compatible = BCM21664_DT_AON_CCU_COMPAT; + reg = <0x35002000 0x0f00>; + #clock-cells = <1>; + clock-output-names = "hub_timer"; + }; + + master_ccu: master_ccu { + compatible = BCM21664_DT_MASTER_CCU_COMPAT; + reg = <0x3f001000 0x0f00>; + #clock-cells = <1>; + clock-output-names = "sdio1", + "sdio2", + "sdio3", + "sdio4", + "sdio1_sleep", + "sdio2_sleep", + "sdio3_sleep", + "sdio4_sleep"; + }; + + slave_ccu: slave_ccu { + compatible = BCM21664_DT_SLAVE_CCU_COMPAT; + reg = <0x3e011000 0x0f00>; + #clock-cells = <1>; + clock-output-names = "uartb", + "uartb2", + "uartb3", + "bsc1", + "bsc2", + "bsc3", + "bsc4"; }; }; diff --git a/arch/arm/boot/dts/berlin2.dtsi b/arch/arm/boot/dts/berlin2.dtsi index 56a1af2f10529b..74f7812a84b543 100644 --- a/arch/arm/boot/dts/berlin2.dtsi +++ b/arch/arm/boot/dts/berlin2.dtsi @@ -37,24 +37,24 @@ }; }; - clocks { - smclk: sysmgr-clock { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <25000000>; - }; + smclk: sysmgr-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; - cfgclk: cfg-clock { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <100000000>; - }; + cfgclk: cfg-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + }; - sysclk: system-clock { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <400000000>; - }; + twdclk: twdclk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + clocks = <&cpupll>; + clock-mult = <1>; + clock-div = <3>; }; soc { @@ -72,6 +72,11 @@ cache-level = <2>; }; + scu: snoop-control-unit@ad0000 { + compatible = "arm,cortex-a9-scu"; + reg = <0xad0000 0x58>; + }; + gic: interrupt-controller@ad1000 { compatible = "arm,cortex-a9-gic"; reg = <0xad1000 0x1000>, <0xad0100 0x0100>; @@ -83,7 +88,21 @@ compatible = "arm,cortex-a9-twd-timer"; reg = <0xad0600 0x20>; interrupts = ; - clocks = <&sysclk>; + clocks = <&twdclk>; + }; + + syspll: syspll@ea0014 { + compatible = "marvell,berlin2-pll"; + clocks = <&smclk>; + #clock-cells = <0>; + reg = <0xea0014 0x8>; + }; + + cpupll: cpupll@ea003c { + compatible = "marvell,berlin2-pll"; + clocks = <&smclk>; + #clock-cells = <0>; + reg = <0xea003c 0x8>; }; apb@e80000 { @@ -94,6 +113,78 @@ ranges = <0 0xe80000 0x10000>; interrupt-parent = <&aic>; + gpio0: gpio@0400 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0400 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + porta: gpio-port@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0>; + }; + }; + + gpio1: gpio@0800 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0800 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + portb: gpio-port@1 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <1>; + }; + }; + + gpio2: gpio@0c00 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0c00 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + portc: gpio-port@2 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <2>; + }; + }; + + gpio3: gpio@1000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x1000 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + portd: gpio-port@3 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <3>; + }; + }; + timer0: timer@2c00 { compatible = "snps,dw-apb-timer"; reg = <0x2c00 0x14>; @@ -176,6 +267,11 @@ }; }; + generic-regs@ea0184 { + compatible = "marvell,berlin-generic-regs", "syscon"; + reg = <0xea0184 0x10>; + }; + apb@fc0000 { compatible = "simple-bus"; #address-cells = <1>; @@ -184,6 +280,39 @@ ranges = <0 0xfc0000 0x10000>; interrupt-parent = <&sic>; + sm_gpio1: gpio@5000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x5000 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + portf: gpio-port@5 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + }; + }; + + sm_gpio0: gpio@c000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xc000 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + porte: gpio-port@4 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <11>; + }; + }; + uart0: serial@9000 { compatible = "snps,dw-apb-uart"; reg = <0x9000 0x100>; diff --git a/arch/arm/boot/dts/berlin2cd.dtsi b/arch/arm/boot/dts/berlin2cd.dtsi index 094968c275339b..b8163394b4c104 100644 --- a/arch/arm/boot/dts/berlin2cd.dtsi +++ b/arch/arm/boot/dts/berlin2cd.dtsi @@ -30,24 +30,24 @@ }; }; - clocks { - smclk: sysmgr-clock { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <25000000>; - }; + smclk: sysmgr-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; - cfgclk: cfg-clock { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <75000000>; - }; + cfgclk: cfg-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <75000000>; + }; - sysclk: system-clock { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <300000000>; - }; + twdclk: twdclk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + clocks = <&cpupll>; + clock-mult = <1>; + clock-div = <3>; }; soc { @@ -76,7 +76,21 @@ compatible = "arm,cortex-a9-twd-timer"; reg = <0xad0600 0x20>; interrupts = ; - clocks = <&sysclk>; + clocks = <&twdclk>; + }; + + syspll: syspll@ea0014 { + compatible = "marvell,berlin2-pll"; + clocks = <&smclk>; + #clock-cells = <0>; + reg = <0xea0014 0x8>; + }; + + cpupll: cpupll@ea003c { + compatible = "marvell,berlin2-pll"; + clocks = <&smclk>; + #clock-cells = <0>; + reg = <0xea003c 0x8>; }; apb@e80000 { @@ -87,6 +101,78 @@ ranges = <0 0xe80000 0x10000>; interrupt-parent = <&aic>; + gpio0: gpio@0400 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0400 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + porta: gpio-port@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0>; + }; + }; + + gpio1: gpio@0800 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0800 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + portb: gpio-port@1 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <1>; + }; + }; + + gpio2: gpio@0c00 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0c00 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + portc: gpio-port@2 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <2>; + }; + }; + + gpio3: gpio@1000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x1000 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + portd: gpio-port@3 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <3>; + }; + }; + timer0: timer@2c00 { compatible = "snps,dw-apb-timer"; reg = <0x2c00 0x14>; @@ -177,6 +263,36 @@ ranges = <0 0xfc0000 0x10000>; interrupt-parent = <&sic>; + sm_gpio1: gpio@5000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x5000 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + portf: gpio-port@5 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + }; + }; + + sm_gpio0: gpio@c000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xc000 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + porte: gpio-port@4 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + }; + }; + uart0: serial@9000 { compatible = "snps,dw-apb-uart"; reg = <0x9000 0x100>; diff --git a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts new file mode 100644 index 00000000000000..995150f93795ad --- /dev/null +++ b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 Antoine Ténart + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/dts-v1/; +#include "berlin2q.dtsi" + +/ { + model = "Marvell BG2-Q DMP"; + compatible = "marvell,berlin2q-dmp", "marvell,berlin2q", "marvell,berlin"; + + memory { + device_type = "memory"; + reg = <0x00000000 0x80000000>; + }; + + choosen { + bootargs = "console=ttyS0,115200 earlyprintk"; + }; +}; + +&sdhci1 { + broken-cd; + sdhci,wp-inverted; + status = "okay"; +}; + +&sdhci2 { + non-removable; + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi new file mode 100644 index 00000000000000..1a0caba79ad949 --- /dev/null +++ b/arch/arm/boot/dts/berlin2q.dtsi @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2014 Antoine Ténart + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include + +#include "skeleton.dtsi" + +/ { + model = "Marvell Armada 1500 pro (BG2-Q) SoC"; + compatible = "marvell,berlin2q", "marvell,berlin"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + next-level-cache = <&l2>; + reg = <0>; + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + next-level-cache = <&l2>; + reg = <1>; + }; + + cpu@2 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + next-level-cache = <&l2>; + reg = <2>; + }; + + cpu@3 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + next-level-cache = <&l2>; + reg = <3>; + }; + }; + + smclk: sysmgr-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; + + cfgclk: config-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + }; + + twdclk: twdclk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + clocks = <&cpupll>; + clock-mult = <1>; + clock-div = <3>; + }; + + sdio1clk: sdio1clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + clocks = <&syspll>; + clock-mult = <1>; + clock-div = <4>; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0 0xf7000000 0x1000000>; + interrupt-parent = <&gic>; + + sdhci0: sdhci@ab0000 { + compatible = "mrvl,pxav3-mmc"; + reg = <0xab0000 0x200>; + clocks = <&sdio1clk>; + interrupts = ; + status = "disabled"; + }; + + sdhci1: sdhci@ab0800 { + compatible = "mrvl,pxav3-mmc"; + reg = <0xab0800 0x200>; + clocks = <&sdio1clk>; + interrupts = ; + status = "disabled"; + }; + + sdhci2: sdhci@ab1000 { + compatible = "mrvl,pxav3-mmc"; + reg = <0xab1000 0x200>; + interrupts = ; + clocks = <&sdio1clk>; + status = "disabled"; + }; + + l2: l2-cache-controller@ac0000 { + compatible = "arm,pl310-cache"; + reg = <0xac0000 0x1000>; + cache-level = <2>; + }; + + scu: snoop-control-unit@ad0000 { + compatible = "arm,cortex-a9-scu"; + reg = <0xad0000 0x58>; + }; + + local-timer@ad0600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0xad0600 0x20>; + clocks = <&twdclk>; + interrupts = ; + }; + + gic: interrupt-controller@ad1000 { + compatible = "arm,cortex-a9-gic"; + reg = <0xad1000 0x1000>, <0xad0100 0x100>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + cpupll: cpupll@dd0170 { + compatible = "marvell,berlin2q-pll"; + clocks = <&smclk>; + #clock-cells = <0>; + reg = <0xdd0170 0x8>; + }; + + syspll: syspll@ea0030 { + compatible = "marvell,berlin2q-pll"; + clocks = <&smclk>; + #clock-cells = <0>; + reg = <0xea0030 0x8>; + }; + + apb@e80000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0 0xe80000 0x10000>; + interrupt-parent = <&aic>; + + gpio0: gpio@0400 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0400 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + porta: gpio-port@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0>; + }; + }; + + gpio1: gpio@0800 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0800 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + portb: gpio-port@1 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <1>; + }; + }; + + gpio2: gpio@0c00 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0c00 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + portc: gpio-port@2 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <2>; + }; + }; + + gpio3: gpio@1000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x1000 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + portd: gpio-port@3 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <3>; + }; + }; + + timer0: timer@2c00 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c00 0x14>; + clocks = <&cfgclk>; + clock-names = "timer"; + interrupts = <8>; + }; + + timer1: timer@2c14 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c14 0x14>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer2: timer@2c28 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c28 0x14>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer3: timer@2c3c { + compatible = "snps,dw-apb-timer"; + reg = <0x2c3c 0x14>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer4: timer@2c50 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c50 0x14>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer5: timer@2c64 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c64 0x14>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer6: timer@2c78 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c78 0x14>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer7: timer@2c8c { + compatible = "snps,dw-apb-timer"; + reg = <0x2c8c 0x14>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + aic: interrupt-controller@3800 { + compatible = "snps,dw-apb-ictl"; + reg = <0x3800 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = ; + }; + + gpio4: gpio@5000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x5000 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + porte: gpio-port@4 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <32>; + reg = <0>; + }; + }; + + gpio5: gpio@c000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xc000 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + portf: gpio-port@5 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <32>; + reg = <0>; + }; + }; + }; + + generic-regs@ea0110 { + compatible = "marvell,berlin-generic-regs", "syscon"; + reg = <0xea0110 0x10>; + }; + + apb@fc0000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0 0xfc0000 0x10000>; + interrupt-parent = <&sic>; + + uart0: uart@9000 { + compatible = "snps,dw-apb-uart"; + reg = <0x9000 0x100>; + interrupt-parent = <&sic>; + interrupts = <8>; + clocks = <&smclk>; + reg-shift = <2>; + status = "disabled"; + }; + + uart1: uart@a000 { + compatible = "snps,dw-apb-uart"; + reg = <0xa000 0x100>; + interrupt-parent = <&sic>; + interrupts = <9>; + clocks = <&smclk>; + reg-shift = <2>; + status = "disabled"; + }; + + sic: interrupt-controller@e000 { + compatible = "snps,dw-apb-ictl"; + reg = <0xe000 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = ; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index 2f8bcd068d1716..58ff8e28c74f3c 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -129,12 +129,10 @@ status = "disabled"; #address-cells = <1>; #size-cells = <1>; + #clock-cells = <1>; + clock-output-names = "cam_a_clkout", "cam_b_clkout"; ranges; - clock_cam: clock-controller { - #clock-cells = <1>; - }; - fimc_0: fimc@11800000 { compatible = "samsung,exynos4210-fimc"; reg = <0x11800000 0x1000>; @@ -371,6 +369,8 @@ interrupts = <0 60 0>; clocks = <&clock CLK_I2C2>; clock-names = "i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_bus>; status = "disabled"; }; @@ -382,6 +382,8 @@ interrupts = <0 61 0>; clocks = <&clock CLK_I2C3>; clock-names = "i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_bus>; status = "disabled"; }; @@ -393,6 +395,8 @@ interrupts = <0 62 0>; clocks = <&clock CLK_I2C4>; clock-names = "i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_bus>; status = "disabled"; }; @@ -404,6 +408,8 @@ interrupts = <0 63 0>; clocks = <&clock CLK_I2C5>; clock-names = "i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c5_bus>; status = "disabled"; }; @@ -415,6 +421,8 @@ interrupts = <0 64 0>; clocks = <&clock CLK_I2C6>; clock-names = "i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c6_bus>; status = "disabled"; }; @@ -426,6 +434,8 @@ interrupts = <0 65 0>; clocks = <&clock CLK_I2C7>; clock-names = "i2c"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c7_bus>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts index 9583563dd0ef7a..f621fd976815cf 100644 --- a/arch/arm/boot/dts/exynos4412-trats2.dts +++ b/arch/arm/boot/dts/exynos4412-trats2.dts @@ -20,7 +20,7 @@ compatible = "samsung,trats2", "samsung,exynos4412", "samsung,exynos4"; aliases { - i2c8 = &i2c_ak8975; + i2c9 = &i2c_ak8975; }; memory { @@ -80,7 +80,24 @@ enable-active-high; }; - /* More to come */ + cam_af_reg: voltage-regulator-3 { + compatible = "regulator-fixed"; + regulator-name = "CAM_AF"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + gpio = <&gpm0 4 0>; + enable-active-high; + }; + + cam_isp_core_reg: voltage-regulator-4 { + compatible = "regulator-fixed"; + regulator-name = "CAM_ISP_CORE_1.2V_EN"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + gpio = <&gpm0 3 0>; + enable-active-high; + regulator-always-on; + }; }; gpio-keys { @@ -140,6 +157,38 @@ }; }; + i2c_0: i2c@13860000 { + samsung,i2c-sda-delay = <100>; + samsung,i2c-slave-addr = <0x10>; + samsung,i2c-max-bus-freq = <400000>; + pinctrl-0 = <&i2c0_bus>; + pinctrl-names = "default"; + status = "okay"; + + s5c73m3@3c { + compatible = "samsung,s5c73m3"; + reg = <0x3c>; + standby-gpios = <&gpm0 1 1>; /* ISP_STANDBY */ + xshutdown-gpios = <&gpf1 3 1>; /* ISP_RESET */ + vdd-int-supply = <&buck9_reg>; + vddio-cis-supply = <&ldo9_reg>; + vdda-supply = <&ldo17_reg>; + vddio-host-supply = <&ldo18_reg>; + vdd-af-supply = <&cam_af_reg>; + vdd-reg-supply = <&cam_io_reg>; + clock-frequency = <24000000>; + /* CAM_A_CLKOUT */ + clocks = <&camera 0>; + clock-names = "cis_extclk"; + port { + s5c73m3_ep: endpoint { + remote-endpoint = <&csis0_ep>; + data-lanes = <1 2 3 4>; + }; + }; + }; + }; + i2c@138D0000 { samsung,i2c-sda-delay = <100>; samsung,i2c-slave-addr = <0x10>; @@ -586,8 +635,8 @@ status = "okay"; }; - camera { - pinctrl-0 = <&cam_port_b_clk_active>; + camera: camera { + pinctrl-0 = <&cam_port_a_clk_active &cam_port_b_clk_active>; pinctrl-names = "default"; status = "okay"; @@ -607,6 +656,23 @@ status = "okay"; }; + csis_0: csis@11880000 { + status = "okay"; + vddcore-supply = <&ldo8_reg>; + vddio-supply = <&ldo10_reg>; + clock-frequency = <176000000>; + + /* Camera C (3) MIPI CSI-2 (CSIS0) */ + port@3 { + reg = <3>; + csis0_ep: endpoint { + remote-endpoint = <&s5c73m3_ep>; + data-lanes = <1 2 3 4>; + samsung,csis-hs-settle = <12>; + }; + }; + }; + csis_1: csis@11890000 { vddcore-supply = <&ldo8_reg>; vddio-supply = <&ldo10_reg>; @@ -647,10 +713,11 @@ reg = <0x10>; svdda-supply = <&cam_io_reg>; svddio-supply = <&ldo19_reg>; + afvdd-supply = <&ldo19_reg>; clock-frequency = <24000000>; /* CAM_B_CLKOUT */ - clocks = <&clock_cam 1>; - clock-names = "mclk"; + clocks = <&camera 1>; + clock-names = "extclk"; samsung,camclk-out = <1>; gpios = <&gpm1 6 0>; diff --git a/arch/arm/boot/dts/exynos5260-pinctrl.dtsi b/arch/arm/boot/dts/exynos5260-pinctrl.dtsi new file mode 100644 index 00000000000000..f6ee55ea070855 --- /dev/null +++ b/arch/arm/boot/dts/exynos5260-pinctrl.dtsi @@ -0,0 +1,574 @@ +/* + * Samsung's Exynos5260 SoC pin-mux and pin-config device tree source + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung's Exynos5260 SoC pin-mux and pin-config options are listed as device + * tree nodes are listed in this file. + * + * 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. +*/ + +#define PIN_PULL_NONE 0 +#define PIN_PULL_DOWN 1 +#define PIN_PULL_UP 3 + +&pinctrl_0 { + gpa0: gpa0 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpa1: gpa1 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpa2: gpa2 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb0: gpb0 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb1: gpb1 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb2: gpb2 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb3: gpb3 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb4: gpb4 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb5: gpb5 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpd0: gpd0 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpd1: gpd1 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpd2: gpd2 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpe0: gpe0 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpe1: gpe1 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpf0: gpf0 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpf1: gpf1 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpk0: gpk0 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpx0: gpx0 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpx1: gpx1 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpx2: gpx2 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpx3: gpx3 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + uart0_data: uart0-data { + samsung,pins = "gpa0-0", "gpa0-1"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + uart0_fctl: uart0-fctl { + samsung,pins = "gpa0-2", "gpa0-3"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + uart1_data: uart1-data { + samsung,pins = "gpa1-0", "gpa1-1"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + uart1_fctl: uart1-fctl { + samsung,pins = "gpa1-2", "gpa1-3"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + uart2_data: uart2-data { + samsung,pins = "gpa1-4", "gpa1-5"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + spi0_bus: spi0-bus { + samsung,pins = "gpa2-0", "gpa2-2", "gpa2-3"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + spi1_bus: spi1-bus { + samsung,pins = "gpa2-4", "gpa2-6", "gpa2-7"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + usb3_vbus0_en: usb3-vbus0-en { + samsung,pins = "gpa2-4"; + samsung,pin-function = <1>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2s1_bus: i2s1-bus { + samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3", + "gpb0-4"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + pcm1_bus: pcm1-bus { + samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3", + "gpb0-4"; + samsung,pin-function = <3>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + spdif1_bus: spdif1-bus { + samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2"; + samsung,pin-function = <4>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + spi2_bus: spi2-bus { + samsung,pins = "gpb1-0", "gpb1-2", "gpb1-3"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2c0_hs_bus: i2c0-hs-bus { + samsung,pins = "gpb3-0", "gpb3-1"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2c1_hs_bus: i2c1-hs-bus { + samsung,pins = "gpb3-2", "gpb3-3"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2c2_hs_bus: i2c2-hs-bus { + samsung,pins = "gpb3-4", "gpb3-5"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2c3_hs_bus: i2c3-hs-bus { + samsung,pins = "gpb3-6", "gpb3-7"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2c4_bus: i2c4-bus { + samsung,pins = "gpb4-0", "gpb4-1"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2c5_bus: i2c5-bus { + samsung,pins = "gpb4-2", "gpb4-3"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2c6_bus: i2c6-bus { + samsung,pins = "gpb4-4", "gpb4-5"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2c7_bus: i2c7-bus { + samsung,pins = "gpb4-6", "gpb4-7"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2c8_bus: i2c8-bus { + samsung,pins = "gpb5-0", "gpb5-1"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2c9_bus: i2c9-bus { + samsung,pins = "gpb5-2", "gpb5-3"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2c10_bus: i2c10-bus { + samsung,pins = "gpb5-4", "gpb5-5"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + i2c11_bus: i2c11-bus { + samsung,pins = "gpb5-6", "gpb5-7"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + cam_gpio_a: cam-gpio-a { + samsung,pins = "gpe0-0", "gpe0-1", "gpe0-2", "gpe0-3", + "gpe0-4", "gpe0-5", "gpe0-6", "gpe0-7", + "gpe1-0", "gpe1-1"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + cam_gpio_b: cam-gpio-b { + samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3", + "gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3"; + samsung,pin-function = <3>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + cam_i2c1_bus: cam-i2c1-bus { + samsung,pins = "gpf0-2", "gpf0-3"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + cam_i2c0_bus: cam-i2c0-bus { + samsung,pins = "gpf0-0", "gpf0-1"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + cam_spi0_bus: cam-spi0-bus { + samsung,pins = "gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; + + cam_spi1_bus: cam-spi1-bus { + samsung,pins = "gpf1-4", "gpf1-5", "gpf1-6", "gpf1-7"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <0>; + }; +}; + +&pinctrl_1 { + gpc0: gpc0 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpc1: gpc1 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpc2: gpc2 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpc3: gpc3 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpc4: gpc4 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + sd0_clk: sd0-clk { + samsung,pins = "gpc0-0"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd0_cmd: sd0-cmd { + samsung,pins = "gpc0-1"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd0_bus1: sd0-bus-width1 { + samsung,pins = "gpc0-2"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd0_bus4: sd0-bus-width4 { + samsung,pins = "gpc0-3", "gpc0-4", "gpc0-5"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd0_bus8: sd0-bus-width8 { + samsung,pins = "gpc3-0", "gpc3-1", "gpc3-2", "gpc3-3"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd0_rdqs: sd0-rdqs { + samsung,pins = "gpc0-6"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd1_clk: sd1-clk { + samsung,pins = "gpc1-0"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd1_cmd: sd1-cmd { + samsung,pins = "gpc1-1"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd1_bus1: sd1-bus-width1 { + samsung,pins = "gpc1-2"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd1_bus4: sd1-bus-width4 { + samsung,pins = "gpc1-3", "gpc1-4", "gpc1-5"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd1_bus8: sd1-bus-width8 { + samsung,pins = "gpc4-0", "gpc4-1", "gpc4-2", "gpc4-3"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd2_clk: sd2-clk { + samsung,pins = "gpc2-0"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd2_cmd: sd2-cmd { + samsung,pins = "gpc2-1"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd2_cd: sd2-cd { + samsung,pins = "gpc2-2"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd2_bus1: sd2-bus-width1 { + samsung,pins = "gpc2-3"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; + + sd2_bus4: sd2-bus-width4 { + samsung,pins = "gpc2-4", "gpc2-5", "gpc2-6"; + samsung,pin-function = <2>; + samsung,pin-pud = ; + samsung,pin-drv = <3>; + }; +}; + +&pinctrl_2 { + gpz0: gpz0 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpz1: gpz1 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; diff --git a/arch/arm/boot/dts/exynos5260-xyref5260.dts b/arch/arm/boot/dts/exynos5260-xyref5260.dts new file mode 100644 index 00000000000000..8c84ab27c19b2c --- /dev/null +++ b/arch/arm/boot/dts/exynos5260-xyref5260.dts @@ -0,0 +1,103 @@ +/* + * SAMSUNG XYREF5260 board device tree source + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * 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. +*/ + +/dts-v1/; +#include "exynos5260.dtsi" + +/ { + model = "SAMSUNG XYREF5260 board based on EXYNOS5260"; + compatible = "samsung,xyref5260", "samsung,exynos5260", "samsung,exynos5"; + + memory { + reg = <0x20000000 0x80000000>; + }; + + chosen { + bootargs = "console=ttySAC2,115200"; + }; + + fin_pll: xxti { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "fin_pll"; + #clock-cells = <0>; + }; + + xrtcxti: xrtcxti { + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "xrtcxti"; + #clock-cells = <0>; + }; +}; + +&pinctrl_0 { + hdmi_hpd_irq: hdmi-hpd-irq { + samsung,pins = "gpx3-7"; + samsung,pin-function = <0>; + samsung,pin-pud = <1>; + samsung,pin-drv = <0>; + }; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&mmc_0 { + status = "okay"; + num-slots = <1>; + broken-cd; + bypass-smu; + supports-highspeed; + supports-hs200-mode; /* 200 Mhz */ + card-detect-delay = <200>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <0 4>; + samsung,dw-mshc-ddr-timing = <0 2>; + pinctrl-names = "default"; + pinctrl-0 = <&sd0_rdqs &sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>; + + slot@0 { + reg = <0>; + bus-width = <8>; + }; +}; + +&mmc_2 { + status = "okay"; + num-slots = <1>; + supports-highspeed; + card-detect-delay = <200>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <2 3>; + samsung,dw-mshc-ddr-timing = <1 2>; + pinctrl-names = "default"; + pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>; + + slot@0 { + reg = <0>; + bus-width = <4>; + disable-wp; + }; +}; diff --git a/arch/arm/boot/dts/exynos5260.dtsi b/arch/arm/boot/dts/exynos5260.dtsi new file mode 100644 index 00000000000000..5398a60207ca94 --- /dev/null +++ b/arch/arm/boot/dts/exynos5260.dtsi @@ -0,0 +1,304 @@ +/* + * SAMSUNG EXYNOS5260 SoC device tree source + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * 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 "skeleton.dtsi" + +#include + +/ { + compatible = "samsung,exynos5260", "samsung,exynos5"; + interrupt-parent = <&gic>; + + aliases { + pinctrl0 = &pinctrl_0; + pinctrl1 = &pinctrl_1; + pinctrl2 = &pinctrl_2; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x0>; + cci-control-port = <&cci_control1>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x1>; + cci-control-port = <&cci_control1>; + }; + + cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x100>; + cci-control-port = <&cci_control0>; + }; + + cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x101>; + cci-control-port = <&cci_control0>; + }; + + cpu@102 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x102>; + cci-control-port = <&cci_control0>; + }; + + cpu@103 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x103>; + cci-control-port = <&cci_control0>; + }; + }; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + clock_top: clock-controller@10010000 { + compatible = "samsung,exynos5260-clock-top"; + reg = <0x10010000 0x10000>; + #clock-cells = <1>; + }; + + clock_peri: clock-controller@10200000 { + compatible = "samsung,exynos5260-clock-peri"; + reg = <0x10200000 0x10000>; + #clock-cells = <1>; + }; + + clock_egl: clock-controller@10600000 { + compatible = "samsung,exynos5260-clock-egl"; + reg = <0x10600000 0x10000>; + #clock-cells = <1>; + }; + + clock_kfc: clock-controller@10700000 { + compatible = "samsung,exynos5260-clock-kfc"; + reg = <0x10700000 0x10000>; + #clock-cells = <1>; + }; + + clock_g2d: clock-controller@10A00000 { + compatible = "samsung,exynos5260-clock-g2d"; + reg = <0x10A00000 0x10000>; + #clock-cells = <1>; + }; + + clock_mif: clock-controller@10CE0000 { + compatible = "samsung,exynos5260-clock-mif"; + reg = <0x10CE0000 0x10000>; + #clock-cells = <1>; + }; + + clock_mfc: clock-controller@11090000 { + compatible = "samsung,exynos5260-clock-mfc"; + reg = <0x11090000 0x10000>; + #clock-cells = <1>; + }; + + clock_g3d: clock-controller@11830000 { + compatible = "samsung,exynos5260-clock-g3d"; + reg = <0x11830000 0x10000>; + #clock-cells = <1>; + }; + + clock_fsys: clock-controller@122E0000 { + compatible = "samsung,exynos5260-clock-fsys"; + reg = <0x122E0000 0x10000>; + #clock-cells = <1>; + }; + + clock_aud: clock-controller@128C0000 { + compatible = "samsung,exynos5260-clock-aud"; + reg = <0x128C0000 0x10000>; + #clock-cells = <1>; + }; + + clock_isp: clock-controller@133C0000 { + compatible = "samsung,exynos5260-clock-isp"; + reg = <0x133C0000 0x10000>; + #clock-cells = <1>; + }; + + clock_gscl: clock-controller@13F00000 { + compatible = "samsung,exynos5260-clock-gscl"; + reg = <0x13F00000 0x10000>; + #clock-cells = <1>; + }; + + clock_disp: clock-controller@14550000 { + compatible = "samsung,exynos5260-clock-disp"; + reg = <0x14550000 0x10000>; + #clock-cells = <1>; + }; + + gic: interrupt-controller@10481000 { + compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-controller; + reg = <0x10481000 0x1000>, + <0x10482000 0x1000>, + <0x10484000 0x2000>, + <0x10486000 0x2000>; + interrupts = <1 9 0xf04>; + }; + + chipid: chipid@10000000 { + compatible = "samsung,exynos4210-chipid"; + reg = <0x10000000 0x100>; + }; + + mct: mct@100B0000 { + compatible = "samsung,exynos4210-mct"; + reg = <0x100B0000 0x1000>; + clocks = <&fin_pll>, <&clock_peri PERI_CLK_MCT>; + clock-names = "fin_pll", "mct"; + interrupts = <0 104 0>, <0 105 0>, <0 106 0>, + <0 107 0>, <0 122 0>, <0 123 0>, + <0 124 0>, <0 125 0>, <0 126 0>, + <0 127 0>, <0 128 0>, <0 129 0>; + }; + + cci: cci@10F00000 { + compatible = "arm,cci-400"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x10F00000 0x1000>; + ranges = <0x0 0x10F00000 0x6000>; + + cci_control0: slave-if@4000 { + compatible = "arm,cci-400-ctrl-if"; + interface-type = "ace"; + reg = <0x4000 0x1000>; + }; + + cci_control1: slave-if@5000 { + compatible = "arm,cci-400-ctrl-if"; + interface-type = "ace"; + reg = <0x5000 0x1000>; + }; + }; + + pinctrl_0: pinctrl@11600000 { + compatible = "samsung,exynos5260-pinctrl"; + reg = <0x11600000 0x1000>; + interrupts = <0 79 0>; + + wakeup-interrupt-controller { + compatible = "samsung,exynos4210-wakeup-eint"; + interrupt-parent = <&gic>; + interrupts = <0 32 0>; + }; + }; + + pinctrl_1: pinctrl@12290000 { + compatible = "samsung,exynos5260-pinctrl"; + reg = <0x12290000 0x1000>; + interrupts = <0 157 0>; + }; + + pinctrl_2: pinctrl@128B0000 { + compatible = "samsung,exynos5260-pinctrl"; + reg = <0x128B0000 0x1000>; + interrupts = <0 243 0>; + }; + + uart0: serial@12C00000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x12C00000 0x100>; + interrupts = <0 146 0>; + clocks = <&clock_peri PERI_CLK_UART0>, <&clock_peri PERI_SCLK_UART0>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + uart1: serial@12C10000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x12C10000 0x100>; + interrupts = <0 147 0>; + clocks = <&clock_peri PERI_CLK_UART1>, <&clock_peri PERI_SCLK_UART1>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + uart2: serial@12C20000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x12C20000 0x100>; + interrupts = <0 148 0>; + clocks = <&clock_peri PERI_CLK_UART2>, <&clock_peri PERI_SCLK_UART2>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + uart3: serial@12860000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x12860000 0x100>; + interrupts = <0 145 0>; + clocks = <&clock_aud AUD_CLK_AUD_UART>, <&clock_aud AUD_SCLK_AUD_UART>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + mmc_0: mmc@12140000 { + compatible = "samsung,exynos5250-dw-mshc"; + reg = <0x12140000 0x2000>; + interrupts = <0 156 0>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clock_fsys FSYS_CLK_MMC0>, <&clock_top TOP_SCLK_MMC0>; + clock-names = "biu", "ciu"; + fifo-depth = <64>; + status = "disabled"; + }; + + mmc_1: mmc@12150000 { + compatible = "samsung,exynos5250-dw-mshc"; + reg = <0x12150000 0x2000>; + interrupts = <0 158 0>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clock_fsys FSYS_CLK_MMC1>, <&clock_top TOP_SCLK_MMC1>; + clock-names = "biu", "ciu"; + fifo-depth = <64>; + status = "disabled"; + }; + + mmc_2: mmc@12160000 { + compatible = "samsung,exynos5250-dw-mshc"; + reg = <0x12160000 0x2000>; + interrupts = <0 159 0>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clock_fsys FSYS_CLK_MMC2>, <&clock_top TOP_SCLK_MMC2>; + clock-names = "biu", "ciu"; + fifo-depth = <64>; + status = "disabled"; + }; + }; +}; + +#include "exynos5260-pinctrl.dtsi" diff --git a/arch/arm/boot/dts/exynos5420-arndale-octa.dts b/arch/arm/boot/dts/exynos5420-arndale-octa.dts index 80a3bf4c59865e..896a2a6619e0a7 100644 --- a/arch/arm/boot/dts/exynos5420-arndale-octa.dts +++ b/arch/arm/boot/dts/exynos5420-arndale-octa.dts @@ -364,16 +364,4 @@ gpio-key,wakeup; }; }; - - amba { - mdma1: mdma@11C10000 { - /* - * MDMA1 can support both secure and non-secure - * AXI transactions. When this is enabled in the kernel - * for boards that run in secure mode, we are getting - * imprecise external aborts causing the kernel to oops. - */ - status = "disabled"; - }; - }; }; diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts new file mode 100644 index 00000000000000..fae33dddac396c --- /dev/null +++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts @@ -0,0 +1,147 @@ +/* + * Google Peach Pit Rev 6+ board device tree source + * + * Copyright (c) 2014 Google, 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. + */ + +/dts-v1/; +#include +#include +#include "exynos5420.dtsi" + +/ { + model = "Google Peach Pit Rev 6+"; + + compatible = "google,pit-rev16", + "google,pit-rev15", "google,pit-rev14", + "google,pit-rev13", "google,pit-rev12", + "google,pit-rev11", "google,pit-rev10", + "google,pit-rev9", "google,pit-rev8", + "google,pit-rev7", "google,pit-rev6", + "google,pit", "google,peach","samsung,exynos5420", + "samsung,exynos5"; + + memory { + reg = <0x20000000 0x80000000>; + }; + + fixed-rate-clocks { + oscclk { + compatible = "samsung,exynos5420-oscclk"; + clock-frequency = <24000000>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&power_key_irq>; + + power { + label = "Power"; + gpios = <&gpx1 2 GPIO_ACTIVE_LOW>; + linux,code = ; + gpio-key,wakeup; + }; + }; + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 1000000 0>; + brightness-levels = <0 100 500 1000 1500 2000 2500 2800>; + default-brightness-level = <7>; + pinctrl-0 = <&pwm0_out>; + pinctrl-names = "default"; + }; +}; + +&pinctrl_0 { + tpm_irq: tpm-irq { + samsung,pins = "gpx1-0"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + power_key_irq: power-key-irq { + samsung,pins = "gpx1-2"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; +}; + +&rtc { + status = "okay"; +}; + +&uart_3 { + status = "okay"; +}; + +&mmc_0 { + status = "okay"; + num-slots = <1>; + broken-cd; + caps2-mmc-hs200-1_8v; + supports-highspeed; + non-removable; + card-detect-delay = <200>; + clock-frequency = <400000000>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <0 4>; + samsung,dw-mshc-ddr-timing = <0 2>; + pinctrl-names = "default"; + pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>; + + slot@0 { + reg = <0>; + bus-width = <8>; + }; +}; + +&mmc_2 { + status = "okay"; + num-slots = <1>; + supports-highspeed; + card-detect-delay = <200>; + clock-frequency = <400000000>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <2 3>; + samsung,dw-mshc-ddr-timing = <1 2>; + pinctrl-names = "default"; + pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; +}; + +&hsi2c_9 { + status = "okay"; + clock-frequency = <400000>; + + tpm@20 { + compatible = "infineon,slb9645tt"; + reg = <0x20>; + + /* Unused irq; but still need to configure the pins */ + pinctrl-names = "default"; + pinctrl-0 = <&tpm_irq>; + }; +}; + +/* + * Use longest HW watchdog in SoC (32 seconds) since the hardware + * watchdog provides no debugging information (compared to soft/hard + * lockup detectors) and so should be last resort. + */ +&watchdog { + timeout-sec = <32>; +}; diff --git a/arch/arm/boot/dts/exynos5420-pinctrl.dtsi b/arch/arm/boot/dts/exynos5420-pinctrl.dtsi index e62c8eb5743898..ba686e40eac796 100644 --- a/arch/arm/boot/dts/exynos5420-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5420-pinctrl.dtsi @@ -624,6 +624,34 @@ samsung,pin-drv = <0>; }; + pwm0_out: pwm0-out { + samsung,pins = "gpb2-0"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + pwm1_out: pwm1-out { + samsung,pins = "gpb2-1"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + pwm2_out: pwm2-out { + samsung,pins = "gpb2-2"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + pwm3_out: pwm3-out { + samsung,pins = "gpb2-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + i2c7_hs_bus: i2c7-hs-bus { samsung,pins = "gpb2-2", "gpb2-3"; samsung,pin-function = <3>; diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index c3a9a66c57678f..a802f747de249d 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -125,7 +125,7 @@ clock-names = "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in"; }; - codec@11000000 { + mfc: codec@11000000 { compatible = "samsung,mfc-v7"; reg = <0x11000000 0x10000>; interrupts = <0 96 0>; @@ -169,7 +169,7 @@ status = "disabled"; }; - mct@101C0000 { + mct: mct@101C0000 { compatible = "samsung,exynos4210-mct"; reg = <0x101C0000 0x800>; interrupt-controller; @@ -270,7 +270,7 @@ interrupts = <0 47 0>; }; - rtc@101E0000 { + rtc: rtc@101E0000 { clocks = <&clock CLK_RTC>; clock-names = "rtc"; status = "disabled"; @@ -336,6 +336,13 @@ #dma-cells = <1>; #dma-channels = <8>; #dma-requests = <1>; + /* + * MDMA1 can support both secure and non-secure + * AXI transactions. When this is enabled in the kernel + * for boards that run in secure mode, we are getting + * imprecise external aborts causing the kernel to oops. + */ + status = "disabled"; }; }; @@ -430,22 +437,22 @@ status = "disabled"; }; - serial@12C00000 { + uart_0: serial@12C00000 { clocks = <&clock CLK_UART0>, <&clock CLK_SCLK_UART0>; clock-names = "uart", "clk_uart_baud0"; }; - serial@12C10000 { + uart_1: serial@12C10000 { clocks = <&clock CLK_UART1>, <&clock CLK_SCLK_UART1>; clock-names = "uart", "clk_uart_baud0"; }; - serial@12C20000 { + uart_2: serial@12C20000 { clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>; clock-names = "uart", "clk_uart_baud0"; }; - serial@12C30000 { + uart_3: serial@12C30000 { clocks = <&clock CLK_UART3>, <&clock CLK_SCLK_UART3>; clock-names = "uart", "clk_uart_baud0"; }; @@ -465,14 +472,14 @@ #phy-cells = <0>; }; - dp-controller@145B0000 { + dp: dp-controller@145B0000 { clocks = <&clock CLK_DP1>; clock-names = "dp"; phys = <&dp_phy>; phy-names = "dp"; }; - fimd@14400000 { + fimd: fimd@14400000 { samsung,power-domain = <&disp_pd>; clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>; clock-names = "sclk_fimd", "fimd"; @@ -632,7 +639,7 @@ status = "disabled"; }; - hdmi@14530000 { + hdmi: hdmi@14530000 { compatible = "samsung,exynos4212-hdmi"; reg = <0x14530000 0x70000>; interrupts = <0 95 0>; @@ -644,7 +651,7 @@ status = "disabled"; }; - mixer@14450000 { + mixer: mixer@14450000 { compatible = "samsung,exynos5420-mixer"; reg = <0x14450000 0x10000>; interrupts = <0 94 0>; @@ -715,7 +722,7 @@ clock-names = "tmu_apbif", "tmu_triminfo_apbif"; }; - watchdog@101D0000 { + watchdog: watchdog@101D0000 { compatible = "samsung,exynos5420-wdt"; reg = <0x101D0000 0x100>; interrupts = <0 42 0>; @@ -724,7 +731,7 @@ samsung,syscon-phandle = <&pmu_system_controller>; }; - sss@10830000 { + sss: sss@10830000 { compatible = "samsung,exynos4210-secss"; reg = <0x10830000 0x10000>; interrupts = <0 112 0>; diff --git a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts index 62fb3da50bdbf7..ad12da38fc9228 100644 --- a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts +++ b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts @@ -172,3 +172,16 @@ fsl,uart-has-rtscts; status = "okay"; }; + +&usbhost1 { + phy_type = "serial"; + dr_mode = "host"; + status = "okay"; +}; + +&usbotg { + phy_type = "utmi"; + dr_mode = "otg"; + external-vbus-divider; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx25-pdk.dts b/arch/arm/boot/dts/imx25-pdk.dts index f607ce520edae5..c608942b8a3b65 100644 --- a/arch/arm/boot/dts/imx25-pdk.dts +++ b/arch/arm/boot/dts/imx25-pdk.dts @@ -10,6 +10,7 @@ */ /dts-v1/; +#include #include "imx25.dtsi" / { @@ -19,18 +20,232 @@ memory { reg = <0x80000000 0x4000000>; }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_fec_3v3: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "fec-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 3 0>; + enable-active-high; + }; + + reg_2p5v: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "2P5V"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + }; + + reg_3p3v: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_can_3v3: regulator@3 { + compatible = "regulator-fixed"; + reg = <3>; + regulator-name = "can-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio4 6 0>; + }; + }; + + sound { + compatible = "fsl,imx25-pdk-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx25-pdk-sgtl5000"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + mux-int-port = <1>; + mux-ext-port = <4>; + }; }; -&uart1 { +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; +}; + +&can1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_can1>; + xceiver-supply = <®_can_3v3>; + status = "okay"; +}; + +&esdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc1>; + cd-gpios = <&gpio2 1 0>; + wp-gpios = <&gpio2 0 0>; status = "okay"; }; &fec { phy-mode = "rmii"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + phy-supply = <®_fec_3v3>; + phy-reset-gpios = <&gpio4 8 0>; status = "okay"; }; +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + clocks = <&clks 129>; + VDDA-supply = <®_2p5v>; + VDDIO-supply = <®_3p3v>; + }; +}; + +&iomuxc { + imx25-pdk { + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX25_PAD_RW__AUD4_TXFS 0xe0 + MX25_PAD_OE__AUD4_TXC 0xe0 + MX25_PAD_EB0__AUD4_TXD 0xe0 + MX25_PAD_EB1__AUD4_RXD 0xe0 + >; + }; + + pinctrl_can1: can1grp { + fsl,pins = < + MX25_PAD_GPIO_A__CAN1_TX 0x0 + MX25_PAD_GPIO_B__CAN1_RX 0x0 + MX25_PAD_D14__GPIO_4_6 0x80000000 + >; + }; + + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX25_PAD_SD1_CMD__SD1_CMD 0x80000000 + MX25_PAD_SD1_CLK__SD1_CLK 0x80000000 + MX25_PAD_SD1_DATA0__SD1_DATA0 0x80000000 + MX25_PAD_SD1_DATA1__SD1_DATA1 0x80000000 + MX25_PAD_SD1_DATA2__SD1_DATA2 0x80000000 + MX25_PAD_SD1_DATA3__SD1_DATA3 0x80000000 + MX25_PAD_A14__GPIO_2_0 0x80000000 + MX25_PAD_A15__GPIO_2_1 0x80000000 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX25_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX25_PAD_FEC_MDIO__FEC_MDIO 0x400001e0 + MX25_PAD_FEC_TDATA0__FEC_TDATA0 0x80000000 + MX25_PAD_FEC_TDATA1__FEC_TDATA1 0x80000000 + MX25_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX25_PAD_FEC_RDATA0__FEC_RDATA0 0x80000000 + MX25_PAD_FEC_RDATA1__FEC_RDATA1 0x80000000 + MX25_PAD_FEC_RX_DV__FEC_RX_DV 0x80000000 + MX25_PAD_FEC_TX_CLK__FEC_TX_CLK 0x1c0 + MX25_PAD_A17__GPIO_2_3 0x80000000 + MX25_PAD_D12__GPIO_4_8 0x80000000 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX25_PAD_I2C1_CLK__I2C1_CLK 0x80000000 + MX25_PAD_I2C1_DAT__I2C1_DAT 0x80000000 + >; + }; + + pinctrl_kpp: kppgrp { + fsl,pins = < + MX25_PAD_KPP_ROW0__KPP_ROW0 0x80000000 + MX25_PAD_KPP_ROW1__KPP_ROW1 0x80000000 + MX25_PAD_KPP_ROW2__KPP_ROW2 0x80000000 + MX25_PAD_KPP_ROW3__KPP_ROW3 0x80000000 + MX25_PAD_KPP_COL0__KPP_COL0 0x80000000 + MX25_PAD_KPP_COL1__KPP_COL1 0x80000000 + MX25_PAD_KPP_COL2__KPP_COL2 0x80000000 + MX25_PAD_KPP_COL3__KPP_COL3 0x80000000 + >; + }; + + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX25_PAD_UART1_RTS__UART1_RTS 0xe0 + MX25_PAD_UART1_CTS__UART1_CTS 0xe0 + MX25_PAD_UART1_TXD__UART1_TXD 0x80000000 + MX25_PAD_UART1_RXD__UART1_RXD 0xc0 + >; + }; + }; +}; + &nfc { nand-on-flash-bbt; status = "okay"; }; + +&kpp { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_kpp>; + linux,keymap = < + MATRIX_KEY(0x0, 0x0, KEY_UP) + MATRIX_KEY(0x0, 0x1, KEY_DOWN) + MATRIX_KEY(0x0, 0x2, KEY_VOLUMEDOWN) + MATRIX_KEY(0x0, 0x3, KEY_HOME) + MATRIX_KEY(0x1, 0x0, KEY_RIGHT) + MATRIX_KEY(0x1, 0x1, KEY_LEFT) + MATRIX_KEY(0x1, 0x2, KEY_ENTER) + MATRIX_KEY(0x1, 0x3, KEY_VOLUMEUP) + MATRIX_KEY(0x2, 0x0, KEY_F6) + MATRIX_KEY(0x2, 0x1, KEY_F8) + MATRIX_KEY(0x2, 0x2, KEY_F9) + MATRIX_KEY(0x2, 0x3, KEY_F10) + MATRIX_KEY(0x3, 0x0, KEY_F1) + MATRIX_KEY(0x3, 0x1, KEY_F2) + MATRIX_KEY(0x3, 0x2, KEY_F3) + MATRIX_KEY(0x3, 0x2, KEY_POWER) + >; + status = "okay"; +}; + +&ssi1 { + codec-handle = <&codec>; + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + fsl,uart-has-rtscts; + status = "okay"; +}; + +&usbhost1 { + phy_type = "serial"; + dr_mode = "host"; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index ea323f09dc78f8..563e168c88a01a 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -14,6 +14,7 @@ / { aliases { + ethernet0 = &fec; gpio0 = &gpio1; gpio1 = &gpio2; gpio2 = &gpio3; @@ -165,9 +166,10 @@ status = "disabled"; }; - kpp@43fa8000 { + kpp: kpp@43fa8000 { #address-cells = <1>; #size-cells = <0>; + compatible = "fsl,imx25-kpp", "fsl,imx21-kpp"; reg = <0x43fa8000 0x4000>; clocks = <&clks 102>; clock-names = ""; @@ -482,23 +484,13 @@ clocks = <&clks 99>; }; - usbphy1: usbphy@1 { - compatible = "nop-usbphy"; - status = "disabled"; - }; - - usbphy2: usbphy@2 { - compatible = "nop-usbphy"; - status = "disabled"; - }; - usbotg: usb@53ff4000 { compatible = "fsl,imx25-usb", "fsl,imx27-usb"; reg = <0x53ff4000 0x0200>; interrupts = <37>; - clocks = <&clks 9>, <&clks 70>, <&clks 8>; - clock-names = "ipg", "ahb", "per"; + clocks = <&clks 70>; fsl,usbmisc = <&usbmisc 0>; + fsl,usbphy = <&usbphy0>; status = "disabled"; }; @@ -506,9 +498,9 @@ compatible = "fsl,imx25-usb", "fsl,imx27-usb"; reg = <0x53ff4400 0x0200>; interrupts = <35>; - clocks = <&clks 9>, <&clks 70>, <&clks 8>; - clock-names = "ipg", "ahb", "per"; + clocks = <&clks 70>; fsl,usbmisc = <&usbmisc 1>; + fsl,usbphy = <&usbphy1>; status = "disabled"; }; @@ -518,7 +510,6 @@ clocks = <&clks 9>, <&clks 70>, <&clks 8>; clock-names = "ipg", "ahb", "per"; reg = <0x53ff4600 0x00f>; - status = "disabled"; }; dryice@53ffc000 { @@ -550,4 +541,20 @@ }; }; }; + + usbphy { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + usbphy0: usb-phy@0 { + reg = <0>; + compatible = "usb-nop-xceiv"; + }; + + usbphy1: usb-phy@1 { + reg = <1>; + compatible = "usb-nop-xceiv"; + }; + }; }; diff --git a/arch/arm/boot/dts/imx27-pdk.dts b/arch/arm/boot/dts/imx27-pdk.dts index 5ce89aa275df17..4c317716b510ab 100644 --- a/arch/arm/boot/dts/imx27-pdk.dts +++ b/arch/arm/boot/dts/imx27-pdk.dts @@ -17,15 +17,181 @@ compatible = "fsl,imx27-pdk", "fsl,imx27"; memory { - reg = <0x0 0x0>; + reg = <0xa0000000 0x08000000>; }; + + usbphy { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + usbphy0: usbphy@0 { + compatible = "usb-nop-xceiv"; + reg = <0>; + clocks = <&clks 0>; + clock-names = "main_clk"; + }; + }; +}; + +&cspi2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cspi2>; + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio4 21 GPIO_ACTIVE_HIGH>; + status = "okay"; + + pmic: mc13783@0 { + compatible = "fsl,mc13783"; + reg = <0>; + spi-cs-high; + spi-max-frequency = <1000000>; + interrupt-parent = <&gpio3>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH>; + + regulators { + vgen_reg: vgen { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-boot-on; + }; + + vmmc1_reg: vmmc1 { + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <3000000>; + }; + + gpo1_reg: gpo1 { + regulator-always-on; + regulator-boot-on; + }; + + gpo3_reg: gpo3 { + regulator-always-on; + regulator-boot-on; + }; + }; + }; +}; + +&fec { + phy-mode = "mii"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + status = "okay"; +}; + +&kpp { + linux,keymap = < + MATRIX_KEY(0, 0, KEY_UP) + MATRIX_KEY(0, 1, KEY_DOWN) + MATRIX_KEY(1, 0, KEY_RIGHT) + MATRIX_KEY(1, 1, KEY_LEFT) + MATRIX_KEY(1, 2, KEY_ENTER) + MATRIX_KEY(2, 0, KEY_F6) + MATRIX_KEY(2, 1, KEY_F8) + MATRIX_KEY(2, 2, KEY_F9) + MATRIX_KEY(2, 3, KEY_F10) + >; + status = "okay"; +}; + +&nfc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_nand>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + status = "okay"; }; &uart1 { fsl,uart-has-rtscts; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; status = "okay"; }; -&fec { +&usbotg { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + dr_mode = "otg"; + fsl,usbphy = <&usbphy0>; + phy_type = "ulpi"; status = "okay"; }; + +&iomuxc { + imx27-pdk { + pinctrl_cspi2: cspi2grp { + fsl,pins = < + MX27_PAD_CSPI2_MISO__CSPI2_MISO 0x0 + MX27_PAD_CSPI2_MOSI__CSPI2_MOSI 0x0 + MX27_PAD_CSPI2_SCLK__CSPI2_SCLK 0x0 + MX27_PAD_CSPI2_SS0__GPIO4_21 0x0 /* SPI2 CS0 */ + MX27_PAD_TOUT__GPIO3_14 0x0 /* PMIC IRQ */ + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX27_PAD_SD3_CMD__FEC_TXD0 0x0 + MX27_PAD_SD3_CLK__FEC_TXD1 0x0 + MX27_PAD_ATA_DATA0__FEC_TXD2 0x0 + MX27_PAD_ATA_DATA1__FEC_TXD3 0x0 + MX27_PAD_ATA_DATA2__FEC_RX_ER 0x0 + MX27_PAD_ATA_DATA3__FEC_RXD1 0x0 + MX27_PAD_ATA_DATA4__FEC_RXD2 0x0 + MX27_PAD_ATA_DATA5__FEC_RXD3 0x0 + MX27_PAD_ATA_DATA6__FEC_MDIO 0x0 + MX27_PAD_ATA_DATA7__FEC_MDC 0x0 + MX27_PAD_ATA_DATA8__FEC_CRS 0x0 + MX27_PAD_ATA_DATA9__FEC_TX_CLK 0x0 + MX27_PAD_ATA_DATA10__FEC_RXD0 0x0 + MX27_PAD_ATA_DATA11__FEC_RX_DV 0x0 + MX27_PAD_ATA_DATA12__FEC_RX_CLK 0x0 + MX27_PAD_ATA_DATA13__FEC_COL 0x0 + MX27_PAD_ATA_DATA14__FEC_TX_ER 0x0 + MX27_PAD_ATA_DATA15__FEC_TX_EN 0x0 + >; + }; + + pinctrl_nand: nandgrp { + fsl,pins = < + MX27_PAD_NFRB__NFRB 0x0 + MX27_PAD_NFCLE__NFCLE 0x0 + MX27_PAD_NFWP_B__NFWP_B 0x0 + MX27_PAD_NFCE_B__NFCE_B 0x0 + MX27_PAD_NFALE__NFALE 0x0 + MX27_PAD_NFRE_B__NFRE_B 0x0 + MX27_PAD_NFWE_B__NFWE_B 0x0 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX27_PAD_UART1_TXD__UART1_TXD 0x0 + MX27_PAD_UART1_RXD__UART1_RXD 0x0 + MX27_PAD_UART1_CTS__UART1_CTS 0x0 + MX27_PAD_UART1_RTS__UART1_RTS 0x0 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX27_PAD_USBOTG_NXT__USBOTG_NXT 0x0 + MX27_PAD_USBOTG_STP__USBOTG_STP 0x0 + MX27_PAD_USBOTG_DIR__USBOTG_DIR 0x0 + MX27_PAD_USBOTG_CLK__USBOTG_CLK 0x0 + MX27_PAD_USBOTG_DATA0__USBOTG_DATA0 0x0 + MX27_PAD_USBOTG_DATA1__USBOTG_DATA1 0x0 + MX27_PAD_USBOTG_DATA2__USBOTG_DATA2 0x0 + MX27_PAD_USBOTG_DATA3__USBOTG_DATA3 0x0 + MX27_PAD_USBOTG_DATA4__USBOTG_DATA4 0x0 + MX27_PAD_USBOTG_DATA5__USBOTG_DATA5 0x0 + MX27_PAD_USBOTG_DATA6__USBOTG_DATA6 0x0 + MX27_PAD_USBOTG_DATA7__USBOTG_DATA7 0x0 + >; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts index df3b2e7318358e..d0b693f12cd2fa 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts @@ -12,14 +12,75 @@ / { model = "Phytec pcm970"; compatible = "phytec,imx27-pcm970", "phytec,imx27-pcm038", "fsl,imx27"; + + display0: LQ035Q7 { + model = "Sharp-LQ035Q7"; + native-mode = <&timing0>; + bits-per-pixel = <16>; + fsl,pcr = <0xf00080c0>; + + display-timings { + timing0: 240x320 { + clock-frequency = <5500000>; + hactive = <240>; + vactive = <320>; + hback-porch = <5>; + hsync-len = <7>; + hfront-porch = <16>; + vback-porch = <7>; + vsync-len = <1>; + vfront-porch = <9>; + pixelclk-active = <1>; + hsync-active = <1>; + vsync-active = <1>; + de-active = <0>; + }; + }; + }; + + regulators { + regulator@2 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_csien>; + reg = <2>; + regulator-name = "CSI_EN"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 24 GPIO_ACTIVE_LOW>; + regulator-always-on; + }; + }; + + usbphy { + usbphy2: usbphy@2 { + compatible = "usb-nop-xceiv"; + reg = <2>; + vcc-supply = <®_5v0>; + clocks = <&clks 0>; + clock-names = "main_clk"; + }; + }; }; &cspi1 { + pinctrl-0 = <&pinctrl_cspi1>, <&pinctrl_cspi1cs1>; fsl,spi-num-chipselects = <2>; cs-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>, <&gpio4 27 GPIO_ACTIVE_LOW>; }; +&fb { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_imxfb1>; + display = <&display0>; + lcd-supply = <®_5v0>; + fsl,dmacr = <0x00020010>; + fsl,lscr1 = <0x00120300>; + fsl,lpccr = <0x00a903ff>; + status = "okay"; +}; + &i2c1 { clock-frequency = <400000>; pinctrl-names = "default"; @@ -36,6 +97,50 @@ &iomuxc { imx27_phycore_rdk { + pinctrl_csien: csiengrp { + fsl,pins = < + MX27_PAD_USB_OC_B__GPIO2_24 0x0 + >; + }; + + pinctrl_cspi1cs1: cspi1cs1grp { + fsl,pins = < + MX27_PAD_CSPI1_SS1__GPIO4_27 0x0 + >; + }; + + pinctrl_imxfb1: imxfbgrp { + fsl,pins = < + MX27_PAD_LD0__LD0 0x0 + MX27_PAD_LD1__LD1 0x0 + MX27_PAD_LD2__LD2 0x0 + MX27_PAD_LD3__LD3 0x0 + MX27_PAD_LD4__LD4 0x0 + MX27_PAD_LD5__LD5 0x0 + MX27_PAD_LD6__LD6 0x0 + MX27_PAD_LD7__LD7 0x0 + MX27_PAD_LD8__LD8 0x0 + MX27_PAD_LD9__LD9 0x0 + MX27_PAD_LD10__LD10 0x0 + MX27_PAD_LD11__LD11 0x0 + MX27_PAD_LD12__LD12 0x0 + MX27_PAD_LD13__LD13 0x0 + MX27_PAD_LD14__LD14 0x0 + MX27_PAD_LD15__LD15 0x0 + MX27_PAD_LD16__LD16 0x0 + MX27_PAD_LD17__LD17 0x0 + MX27_PAD_CLS__CLS 0x0 + MX27_PAD_CONTRAST__CONTRAST 0x0 + MX27_PAD_LSCLK__LSCLK 0x0 + MX27_PAD_OE_ACD__OE_ACD 0x0 + MX27_PAD_PS__PS 0x0 + MX27_PAD_REV__REV 0x0 + MX27_PAD_SPL_SPR__SPL_SPR 0x0 + MX27_PAD_HSYNC__HSYNC 0x0 + MX27_PAD_VSYNC__VSYNC 0x0 + >; + }; + pinctrl_i2c1: i2c1grp { /* Add pullup to DATA line */ fsl,pins = < @@ -193,19 +298,16 @@ dr_mode = "host"; phy_type = "ulpi"; vbus-supply = <®_5v0>; + fsl,usbphy = <&usbphy2>; disable-over-current; status = "okay"; }; -&usbphy2 { - vcc-supply = <®_5v0>; -}; - &weim { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_weim>; - can@d4000000 { + can@4,0 { compatible = "nxp,sja1000"; reg = <4 0x00000000 0x00000100>; interrupt-parent = <&gpio5>; diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi b/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi index cefaa6994623f2..31e9f7049f7335 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi +++ b/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi @@ -41,6 +41,20 @@ regulator-max-microvolt = <5000000>; }; }; + + usbphy { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + usbphy0: usbphy@0 { + compatible = "usb-nop-xceiv"; + reg = <0>; + vcc-supply = <&sw3_reg>; + clocks = <&clks 0>; + clock-names = "main_clk"; + }; + }; }; &audmux { @@ -66,9 +80,9 @@ status = "okay"; pmic: mc13783@0 { - #address-cells = <1>; - #size-cells = <0>; compatible = "fsl,mc13783"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; reg = <0>; spi-cs-high; spi-max-frequency = <20000000>; @@ -166,7 +180,7 @@ &fec { phy-mode = "mii"; - phy-reset-gpios = <&gpio3 30 GPIO_ACTIVE_HIGH>; + phy-reset-gpios = <&gpio3 30 GPIO_ACTIVE_LOW>; phy-supply = <®_3v3>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec1>; @@ -204,7 +218,6 @@ MX27_PAD_CSPI1_MOSI__CSPI1_MOSI 0x0 MX27_PAD_CSPI1_SCLK__CSPI1_SCLK 0x0 MX27_PAD_CSPI1_SS0__GPIO4_28 0x0 /* SPI1 CS0 */ - MX27_PAD_USB_PWR__GPIO2_23 0x0 /* PMIC IRQ */ >; }; @@ -251,6 +264,21 @@ >; }; + pinctrl_pmic: pmicgrp { + fsl,pins = < + MX27_PAD_USB_PWR__GPIO2_23 0x0 /* PMIC IRQ */ + >; + }; + + pinctrl_ssi1: ssi1grp { + fsl,pins = < + MX27_PAD_SSI1_FS__SSI1_FS 0x0 + MX27_PAD_SSI1_RXDAT__SSI1_RXDAT 0x0 + MX27_PAD_SSI1_TXDAT__SSI1_TXDAT 0x0 + MX27_PAD_SSI1_CLK__SSI1_CLK 0x0 + >; + }; + pinctrl_usbotg: usbotggrp { fsl,pins = < MX27_PAD_USBOTG_CLK__USBOTG_CLK 0x0 @@ -279,23 +307,28 @@ status = "okay"; }; +&ssi1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ssi1>; + fsl,mode = "i2s-slave"; + status = "okay"; +}; + &usbotg { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usbotg>; dr_mode = "otg"; phy_type = "ulpi"; + fsl,usbphy = <&usbphy0>; vbus-supply = <&sw3_reg>; + disable-over-current; status = "okay"; }; -&usbphy0 { - vcc-supply = <&sw3_reg>; -}; - &weim { status = "okay"; - nor: nor@c0000000 { + nor: nor@0,0 { compatible = "cfi-flash"; reg = <0 0x00000000 0x02000000>; bank-width = <2>; @@ -305,7 +338,7 @@ #size-cells = <1>; }; - sram: sram@c8000000 { + sram: sram@1,0 { compatible = "mtd-ram"; reg = <1 0x00000000 0x00800000>; bank-width = <2>; diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi index 137e010eab35be..a75555c39533d7 100644 --- a/arch/arm/boot/dts/imx27.dtsi +++ b/arch/arm/boot/dts/imx27.dtsi @@ -11,11 +11,13 @@ #include "skeleton.dtsi" #include "imx27-pinfunc.h" +#include #include #include / { aliases { + ethernet0 = &fec; gpio0 = &gpio1; gpio1 = &gpio2; gpio2 = &gpio3; @@ -71,26 +73,6 @@ }; }; - usbphy { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - usbphy0: usbphy@0 { - compatible = "usb-nop-xceiv"; - reg = <0>; - clocks = <&clks 75>; - clock-names = "main_clk"; - }; - - usbphy2: usbphy@2 { - compatible = "usb-nop-xceiv"; - reg = <2>; - clocks = <&clks 75>; - clock-names = "main_clk"; - }; - }; - soc { #address-cells = <1>; #size-cells = <1>; @@ -464,9 +446,8 @@ compatible = "fsl,imx27-usb"; reg = <0x10024000 0x200>; interrupts = <56>; - clocks = <&clks 15>; + clocks = <&clks 75>; fsl,usbmisc = <&usbmisc 0>; - fsl,usbphy = <&usbphy0>; status = "disabled"; }; @@ -474,7 +455,7 @@ compatible = "fsl,imx27-usb"; reg = <0x10024200 0x200>; interrupts = <54>; - clocks = <&clks 15>; + clocks = <&clks 75>; fsl,usbmisc = <&usbmisc 1>; status = "disabled"; }; @@ -483,9 +464,8 @@ compatible = "fsl,imx27-usb"; reg = <0x10024400 0x200>; interrupts = <55>; - clocks = <&clks 15>; + clocks = <&clks 75>; fsl,usbmisc = <&usbmisc 2>; - fsl,usbphy = <&usbphy2>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx28-duckbill.dts b/arch/arm/boot/dts/imx28-duckbill.dts index 5f326c1c1850b3..ce1a7effba3770 100644 --- a/arch/arm/boot/dts/imx28-duckbill.dts +++ b/arch/arm/boot/dts/imx28-duckbill.dts @@ -25,9 +25,9 @@ ssp0: ssp@80010000 { compatible = "fsl,imx28-mmc"; pinctrl-names = "default"; - pinctrl-0 = <&mmc0_8bit_pins_a + pinctrl-0 = <&mmc0_4bit_pins_a &mmc0_cd_cfg &mmc0_sck_cfg>; - bus-width = <8>; + bus-width = <4>; vmmc-supply = <®_3p3v>; status = "okay"; }; @@ -39,7 +39,7 @@ hog_pins_a: hog@0 { reg = <0>; fsl,pinmux-ids = < - MX28_PAD_ENET0_RX_CLK__GPIO_4_13 /* PHY Reset */ + MX28_PAD_SSP0_DATA7__GPIO_2_7 /* PHY Reset */ >; fsl,drive-strength = ; fsl,voltage = ; @@ -82,7 +82,7 @@ pinctrl-names = "default"; pinctrl-0 = <&mac0_pins_a>; phy-supply = <®_3p3v>; - phy-reset-gpios = <&gpio4 13 0>; + phy-reset-gpios = <&gpio2 7 GPIO_ACTIVE_LOW>; phy-reset-duration = <100>; status = "okay"; }; @@ -110,12 +110,12 @@ status { label = "duckbill:green:status"; - gpios = <&gpio3 5 0>; + gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>; }; failure { label = "duckbill:red:status"; - gpios = <&gpio3 4 0>; + gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>; }; }; }; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 90a579532b8b76..a95cc5358ff460 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -9,6 +9,7 @@ * http://www.gnu.org/copyleft/gpl.html */ +#include #include "skeleton.dtsi" #include "imx28-pinfunc.h" diff --git a/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi b/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi index 906ae937b01366..9c2b715ab8bfd9 100644 --- a/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi +++ b/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi @@ -37,6 +37,17 @@ compatible = "nxp,pcf8563"; reg = <0x51>; }; + + tsc2007: tsc2007@48 { + compatible = "ti,tsc2007"; + gpios = <&gpio3 2 0>; + interrupt-parent = <&gpio3>; + interrupts = <0x2 0x8>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tsc2007_1>; + reg = <0x48>; + ti,x-plate-ohms = <180>; + }; }; &iomuxc { @@ -70,6 +81,10 @@ MX35_PAD_I2C1_DAT__I2C1_SDA 0x80000000 >; }; + + pinctrl_tsc2007_1: tsc2007grp-1 { + fsl,pins = ; + }; }; }; diff --git a/arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts b/arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts index 1bdec21f453325..f04ae91eea8908 100644 --- a/arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts +++ b/arch/arm/boot/dts/imx35-eukrea-mbimxsd35-baseboard.dts @@ -46,6 +46,14 @@ linux,default-trigger = "heartbeat"; }; }; + + sound { + compatible = "eukrea,asoc-tlv320"; + eukrea,model = "imx35-eukrea-tlv320aic23"; + ssi-controller = <&ssi1>; + fsl,mux-int-port = <1>; + fsl,mux-ext-port = <4>; + }; }; &audmux { @@ -124,6 +132,7 @@ }; &ssi1 { + codec-handle = <&tlv320aic23>; fsl,mode = "i2s-slave"; status = "okay"; }; @@ -141,3 +150,16 @@ fsl,uart-has-rtscts; status = "okay"; }; + +&usbhost1 { + phy_type = "serial"; + dr_mode = "host"; + status = "okay"; +}; + +&usbotg { + phy_type = "utmi"; + dr_mode = "otg"; + external-vbus-divider; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx35-pdk.dts b/arch/arm/boot/dts/imx35-pdk.dts new file mode 100644 index 00000000000000..db69ff085e27c6 --- /dev/null +++ b/arch/arm/boot/dts/imx35-pdk.dts @@ -0,0 +1,67 @@ +/* + * Copyright 2013 Eukréa Electromatique + * Copyright 2014 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx35.dtsi" + +/ { + model = "Freescale i.MX35 Product Development Kit"; + compatible = "fsl,imx35-pdk", "fsl,imx35"; + + memory { + reg = <0x80000000 0x8000000>; + }; +}; + +&esdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc1>; + status = "okay"; +}; + +&iomuxc { + imx35-pdk { + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX35_PAD_SD1_CMD__ESDHC1_CMD 0x80000000 + MX35_PAD_SD1_CLK__ESDHC1_CLK 0x80000000 + MX35_PAD_SD1_DATA0__ESDHC1_DAT0 0x80000000 + MX35_PAD_SD1_DATA1__ESDHC1_DAT1 0x80000000 + MX35_PAD_SD1_DATA2__ESDHC1_DAT2 0x80000000 + MX35_PAD_SD1_DATA3__ESDHC1_DAT3 0x80000000 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX35_PAD_TXD1__UART1_TXD_MUX 0x1c5 + MX35_PAD_RXD1__UART1_RXD_MUX 0x1c5 + MX35_PAD_CTS1__UART1_CTS 0x1c5 + MX35_PAD_RTS1__UART1_RTS 0x1c5 + >; + }; + }; +}; + +&nfc { + nand-bus-width = <16>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + fsl,uart-has-rtscts; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx35.dtsi b/arch/arm/boot/dts/imx35.dtsi index 88b218f8f81049..4759abb4943615 100644 --- a/arch/arm/boot/dts/imx35.dtsi +++ b/arch/arm/boot/dts/imx35.dtsi @@ -13,6 +13,7 @@ / { aliases { + ethernet0 = &fec; gpio0 = &gpio1; gpio1 = &gpio2; gpio2 = &gpio3; @@ -295,9 +296,9 @@ compatible = "fsl,imx35-usb", "fsl,imx27-usb"; reg = <0x53ff4000 0x0200>; interrupts = <37>; - clocks = <&clks 9>, <&clks 73>, <&clks 28>; - clock-names = "ipg", "ahb", "per"; + clocks = <&clks 73>; fsl,usbmisc = <&usbmisc 0>; + fsl,usbphy = <&usbphy0>; status = "disabled"; }; @@ -305,9 +306,9 @@ compatible = "fsl,imx35-usb", "fsl,imx27-usb"; reg = <0x53ff4400 0x0200>; interrupts = <35>; - clocks = <&clks 9>, <&clks 73>, <&clks 28>; - clock-names = "ipg", "ahb", "per"; + clocks = <&clks 73>; fsl,usbmisc = <&usbmisc 1>; + fsl,usbphy = <&usbphy1>; status = "disabled"; }; @@ -356,4 +357,20 @@ }; }; }; + + usbphy { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + usbphy0: usb-phy@0 { + reg = <0>; + compatible = "usb-nop-xceiv"; + }; + + usbphy1: usb-phy@1 { + reg = <1>; + compatible = "usb-nop-xceiv"; + }; + }; }; diff --git a/arch/arm/boot/dts/imx50.dtsi b/arch/arm/boot/dts/imx50.dtsi index 9c89d1ca97c2ce..6a201cf5436634 100644 --- a/arch/arm/boot/dts/imx50.dtsi +++ b/arch/arm/boot/dts/imx50.dtsi @@ -17,6 +17,7 @@ / { aliases { + ethernet0 = &fec; gpio0 = &gpio1; gpio1 = &gpio2; gpio2 = &gpio3; diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index 9e9deb244b76ff..89470bfca16075 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -21,6 +21,20 @@ reg = <0x90000000 0x20000000>; }; + clocks { + ckih1 { + clock-frequency = <22579200>; + }; + + clk_26M: codec_clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <26000000>; + gpios = <&gpio4 26 GPIO_ACTIVE_LOW>; + }; + }; + display0: display@di0 { compatible = "fsl,imx-parallel-display"; interface-pix-fmt = "rgb24"; @@ -82,11 +96,13 @@ gpio-keys { compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_keys>; power { label = "Power Button"; gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>; - linux,code = <116>; /* KEY_POWER */ + linux,code = ; gpio-key,wakeup; }; }; @@ -102,6 +118,36 @@ }; }; + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_usbh1_vbus: regulator@0 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbh1reg>; + reg = <0>; + regulator-name = "usbh1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio2 5 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_usbotg_vbus: regulator@1 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotgreg>; + reg = <1>; + regulator-name = "usbotg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 7 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + }; + sound { compatible = "fsl,imx51-babbage-sgtl5000", "fsl,imx-audio-sgtl5000"; @@ -116,41 +162,23 @@ mux-ext-port = <3>; }; - clocks { - ckih1 { - clock-frequency = <22579200>; - }; + usbphy { + #address-cells = <1>; + #size-cells = <0>; + compatible = "simple-bus"; - clk_26M: codec_clock { - compatible = "fixed-clock"; - reg=<0>; - #clock-cells = <0>; - clock-frequency = <26000000>; - gpios = <&gpio4 26 GPIO_ACTIVE_LOW>; + usbh1phy: usbh1phy@0 { + compatible = "usb-nop-xceiv"; + reg = <0>; + clocks = <&clks IMX5_CLK_DUMMY>; + clock-names = "main_clk"; }; }; }; -&esdhc1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc1>; - fsl,cd-controller; - fsl,wp-controller; - status = "okay"; -}; - -&esdhc2 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_esdhc2>; - cd-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; - wp-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; - status = "okay"; -}; - -&uart3 { +&audmux { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart3>; - fsl,uart-has-rtscts; + pinctrl-0 = <&pinctrl_audmux>; status = "okay"; }; @@ -163,9 +191,9 @@ status = "okay"; pmic: mc13892@0 { - #address-cells = <1>; - #size-cells = <0>; compatible = "fsl,mc13892"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; spi-max-frequency = <6000000>; spi-cs-high; reg = <0>; @@ -280,6 +308,53 @@ }; }; +&esdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc1>; + fsl,cd-controller; + fsl,wp-controller; + status = "okay"; +}; + +&esdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc2>; + cd-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + wp-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + phy-mode = "mii"; + phy-reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; + phy-reset-duration = <1>; + status = "okay"; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + sgtl5000: codec@0a { + compatible = "fsl,sgtl5000"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_clkcodec>; + reg = <0x0a>; + clocks = <&clk_26M>; + VDDA-supply = <&vdig_reg>; + VDDIO-supply = <&vvideo_reg>; + }; +}; + &ipu_di0_disp0 { remote-endpoint = <&display0_in>; }; @@ -288,29 +363,74 @@ remote-endpoint = <&display1_in>; }; +&kpp { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_kpp>; + linux,keymap = < + MATRIX_KEY(0, 0, KEY_UP) + MATRIX_KEY(0, 1, KEY_DOWN) + MATRIX_KEY(0, 2, KEY_VOLUMEDOWN) + MATRIX_KEY(0, 3, KEY_HOME) + MATRIX_KEY(1, 0, KEY_RIGHT) + MATRIX_KEY(1, 1, KEY_LEFT) + MATRIX_KEY(1, 2, KEY_ENTER) + MATRIX_KEY(1, 3, KEY_VOLUMEUP) + MATRIX_KEY(2, 0, KEY_F6) + MATRIX_KEY(2, 1, KEY_F8) + MATRIX_KEY(2, 2, KEY_F9) + MATRIX_KEY(2, 3, KEY_F10) + MATRIX_KEY(3, 0, KEY_F1) + MATRIX_KEY(3, 1, KEY_F2) + MATRIX_KEY(3, 2, KEY_F3) + MATRIX_KEY(3, 3, KEY_POWER) + >; + status = "okay"; +}; + &ssi2 { fsl,mode = "i2s-slave"; status = "okay"; }; -&iomuxc { +&uart1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hog>; + pinctrl-0 = <&pinctrl_uart1>; + fsl,uart-has-rtscts; + status = "okay"; +}; - imx51-babbage { - pinctrl_hog: hoggrp { - fsl,pins = < - MX51_PAD_GPIO1_0__SD1_CD 0x20d5 - MX51_PAD_GPIO1_1__SD1_WP 0x20d5 - MX51_PAD_GPIO1_5__GPIO1_5 0x100 - MX51_PAD_GPIO1_6__GPIO1_6 0x100 - MX51_PAD_EIM_A27__GPIO2_21 0x5 - MX51_PAD_CSPI1_SS0__GPIO4_24 0x85 - MX51_PAD_CSPI1_SS1__GPIO4_25 0x85 - MX51_PAD_CSPI1_RDY__GPIO4_26 0x80000000 - >; - }; +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + fsl,uart-has-rtscts; + status = "okay"; +}; + +&usbh1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbh1>; + vbus-supply = <®_usbh1_vbus>; + fsl,usbphy = <&usbh1phy>; + phy_type = "ulpi"; + status = "okay"; +}; + +&usbotg { + dr_mode = "otg"; + disable-over-current; + phy_type = "utmi_wide"; + vbus-supply = <®_usbotg_vbus>; + status = "okay"; +}; + +&iomuxc { + imx51-babbage { pinctrl_audmux: audmuxgrp { fsl,pins = < MX51_PAD_AUD3_BB_TXD__AUD3_TXD 0x80000000 @@ -320,11 +440,19 @@ >; }; + pinctrl_clkcodec: clkcodecgrp { + fsl,pins = < + MX51_PAD_CSPI1_RDY__GPIO4_26 0x80000000 + >; + }; + pinctrl_ecspi1: ecspi1grp { fsl,pins = < MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 + MX51_PAD_CSPI1_SS0__GPIO4_24 0x85 /* CS0 */ + MX51_PAD_CSPI1_SS1__GPIO4_25 0x85 /* CS1 */ >; }; @@ -336,6 +464,8 @@ MX51_PAD_SD1_DATA1__SD1_DATA1 0x20d5 MX51_PAD_SD1_DATA2__SD1_DATA2 0x20d5 MX51_PAD_SD1_DATA3__SD1_DATA3 0x20d5 + MX51_PAD_GPIO1_0__SD1_CD 0x20d5 + MX51_PAD_GPIO1_1__SD1_WP 0x20d5 >; }; @@ -347,6 +477,8 @@ MX51_PAD_SD2_DATA1__SD2_DATA1 0x20d5 MX51_PAD_SD2_DATA2__SD2_DATA2 0x20d5 MX51_PAD_SD2_DATA3__SD2_DATA3 0x20d5 + MX51_PAD_GPIO1_5__GPIO1_5 0x100 /* WP */ + MX51_PAD_GPIO1_6__GPIO1_6 0x100 /* CD */ >; }; @@ -369,7 +501,13 @@ MX51_PAD_NANDF_CS6__FEC_TDATA3 0x80000000 MX51_PAD_NANDF_CS7__FEC_TX_EN 0x80000000 MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK 0x80000000 - MX51_PAD_EIM_A20__GPIO2_14 0x85 /* Reset */ + MX51_PAD_EIM_A20__GPIO2_14 0x85 /* Reset */ + >; + }; + + pinctrl_gpio_keys: gpiokeysgrp { + fsl,pins = < + MX51_PAD_EIM_A27__GPIO2_21 0x5 >; }; @@ -379,6 +517,13 @@ >; }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX51_PAD_EIM_D19__I2C1_SCL 0x400001ed + MX51_PAD_EIM_D16__I2C1_SDA 0x400001ed + >; + }; + pinctrl_i2c2: i2c2grp { fsl,pins = < MX51_PAD_KEY_COL4__I2C2_SCL 0x400001ed @@ -455,6 +600,12 @@ >; }; + pinctrl_pmic: pmicgrp { + fsl,pins = < + MX51_PAD_GPIO1_8__GPIO1_8 0xe5 /* IRQ */ + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX51_PAD_UART1_RXD__UART1_RXD 0x1c5 @@ -479,71 +630,33 @@ MX51_PAD_EIM_D24__UART3_CTS 0x1c5 >; }; - }; -}; -&uart1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart1>; - fsl,uart-has-rtscts; - status = "okay"; -}; - -&uart2 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart2>; - status = "okay"; -}; + pinctrl_usbh1: usbh1grp { + fsl,pins = < + MX51_PAD_USBH1_CLK__USBH1_CLK 0x80000000 + MX51_PAD_USBH1_DIR__USBH1_DIR 0x80000000 + MX51_PAD_USBH1_NXT__USBH1_NXT 0x80000000 + MX51_PAD_USBH1_DATA0__USBH1_DATA0 0x80000000 + MX51_PAD_USBH1_DATA1__USBH1_DATA1 0x80000000 + MX51_PAD_USBH1_DATA2__USBH1_DATA2 0x80000000 + MX51_PAD_USBH1_DATA3__USBH1_DATA3 0x80000000 + MX51_PAD_USBH1_DATA4__USBH1_DATA4 0x80000000 + MX51_PAD_USBH1_DATA5__USBH1_DATA5 0x80000000 + MX51_PAD_USBH1_DATA6__USBH1_DATA6 0x80000000 + MX51_PAD_USBH1_DATA7__USBH1_DATA7 0x80000000 + >; + }; -&i2c2 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c2>; - status = "okay"; + pinctrl_usbh1reg: usbh1reggrp { + fsl,pins = < + MX51_PAD_EIM_D21__GPIO2_5 0x85 + >; + }; - sgtl5000: codec@0a { - compatible = "fsl,sgtl5000"; - reg = <0x0a>; - clocks = <&clk_26M>; - VDDA-supply = <&vdig_reg>; - VDDIO-supply = <&vvideo_reg>; + pinctrl_usbotgreg: usbotgreggrp { + fsl,pins = < + MX51_PAD_GPIO1_7__GPIO1_7 0x85 + >; + }; }; }; - -&audmux { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_audmux>; - status = "okay"; -}; - -&fec { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec>; - phy-mode = "mii"; - phy-reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; - phy-reset-duration = <1>; - status = "okay"; -}; - -&kpp { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_kpp>; - linux,keymap = < - MATRIX_KEY(0, 0, KEY_UP) - MATRIX_KEY(0, 1, KEY_DOWN) - MATRIX_KEY(0, 2, KEY_VOLUMEDOWN) - MATRIX_KEY(0, 3, KEY_HOME) - MATRIX_KEY(1, 0, KEY_RIGHT) - MATRIX_KEY(1, 1, KEY_LEFT) - MATRIX_KEY(1, 2, KEY_ENTER) - MATRIX_KEY(1, 3, KEY_VOLUMEUP) - MATRIX_KEY(2, 0, KEY_F6) - MATRIX_KEY(2, 1, KEY_F8) - MATRIX_KEY(2, 2, KEY_F9) - MATRIX_KEY(2, 3, KEY_F10) - MATRIX_KEY(3, 0, KEY_F1) - MATRIX_KEY(3, 1, KEY_F2) - MATRIX_KEY(3, 2, KEY_F3) - MATRIX_KEY(3, 3, KEY_POWER) - >; - status = "okay"; -}; diff --git a/arch/arm/boot/dts/imx51-digi-connectcore-jsk.dts b/arch/arm/boot/dts/imx51-digi-connectcore-jsk.dts new file mode 100644 index 00000000000000..1db517d3d497ff --- /dev/null +++ b/arch/arm/boot/dts/imx51-digi-connectcore-jsk.dts @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2014 Alexander Shiyan + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include "imx51-digi-connectcore-som.dtsi" + +/ { + model = "Digi ConnectCore CC(W)-MX51 JSK"; + compatible = "digi,connectcore-ccxmx51-jsk", + "digi,connectcore-ccxmx51-som", "fsl,imx51"; + + chosen { + linux,stdout-path = &uart1; + }; +}; + +&owire { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_owire>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + status = "okay"; +}; + +&usbotg { + dr_mode = "otg"; + status = "okay"; +}; + +&usbh1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbh1>; + dr_mode = "host"; + phy_type = "ulpi"; + disable-over-current; + status = "okay"; +}; + +&iomuxc { + imx51-digi-connectcore-jsk { + pinctrl_owire: owiregrp { + fsl,pins = < + MX51_PAD_OWIRE_LINE__OWIRE_LINE 0x40000000 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX51_PAD_UART1_RXD__UART1_RXD 0x1c5 + MX51_PAD_UART1_TXD__UART1_TXD 0x1c5 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX51_PAD_UART2_RXD__UART2_RXD 0x1c5 + MX51_PAD_UART2_TXD__UART2_TXD 0x1c5 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX51_PAD_UART3_RXD__UART3_RXD 0x1c5 + MX51_PAD_UART3_TXD__UART3_TXD 0x1c5 + >; + }; + + pinctrl_usbh1: usbh1grp { + fsl,pins = < + MX51_PAD_USBH1_DATA0__USBH1_DATA0 0x1e5 + MX51_PAD_USBH1_DATA1__USBH1_DATA1 0x1e5 + MX51_PAD_USBH1_DATA2__USBH1_DATA2 0x1e5 + MX51_PAD_USBH1_DATA3__USBH1_DATA3 0x1e5 + MX51_PAD_USBH1_DATA4__USBH1_DATA4 0x1e5 + MX51_PAD_USBH1_DATA5__USBH1_DATA5 0x1e5 + MX51_PAD_USBH1_DATA6__USBH1_DATA6 0x1e5 + MX51_PAD_USBH1_DATA7__USBH1_DATA7 0x1e5 + MX51_PAD_USBH1_CLK__USBH1_CLK 0x1e5 + MX51_PAD_USBH1_DIR__USBH1_DIR 0x1e5 + MX51_PAD_USBH1_NXT__USBH1_NXT 0x1e5 + MX51_PAD_USBH1_STP__USBH1_STP 0x1e5 + >; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi b/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi new file mode 100644 index 00000000000000..321662f53e3309 --- /dev/null +++ b/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2014 Alexander Shiyan + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx51.dtsi" + +/ { + model = "Digi ConnectCore CC(W)-MX51"; + compatible = "digi,connectcore-ccxmx51-som", "fsl,imx51"; + + memory { + reg = <0x90000000 0x08000000>; + }; +}; + +&ecspi1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>; + status = "okay"; + + pmic: mc13892@0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mc13892>; + compatible = "fsl,mc13892"; + spi-max-frequency = <16000000>; + spi-cs-high; + reg = <0>; + interrupt-parent = <&gpio1>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + fsl,mc13xxx-uses-rtc; + + regulators { + sw1_reg: sw1 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3_reg: sw3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { }; + + viohi_reg: viohi { + regulator-always-on; + }; + + vpll_reg: vpll { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + vdig_reg: vdig { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <1250000>; + regulator-always-on; + }; + + vsd_reg: vsd { + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + regulator-always-on; + }; + + vusb2_reg: vusb2 { + regulator-min-microvolt = <2600000>; + regulator-max-microvolt = <2600000>; + regulator-always-on; + }; + + vvideo_reg: vvideo { + regulator-min-microvolt = <2775000>; + regulator-max-microvolt = <2775000>; + regulator-always-on; + }; + + vaudio_reg: vaudio { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + }; + + vcam_reg: vcam { + regulator-min-microvolt = <2750000>; + regulator-max-microvolt = <2750000>; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + regulator-always-on; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + vusb_reg: vusb { + regulator-always-on; + }; + + gpo1_reg: gpo1 { }; + + gpo2_reg: gpo2 { }; + + gpo3_reg: gpo3 { }; + + gpo4_reg: gpo4 { }; + + pwgt2spi_reg: pwgt2spi { + regulator-always-on; + }; + + vcoincell_reg: vcoincell { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + }; + }; + }; +}; + +&esdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc2>; + cap-sdio-irq; + enable-sdio-wakeup; + keep-power-in-suspend; + max-frequency = <50000000>; + no-1-8-v; + non-removable; + vmmc-supply = <&gpo4_reg>; + status = "okay"; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + phy-mode = "mii"; + phy-supply = <&gpo3_reg>; + /* Pins shared with LCD2, keep status disabled */ +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + clock-frequency = <400000>; + status = "okay"; + + mma7455l@1d { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mma7455l>; + compatible = "fsl,mma7455l"; + reg = <0x1d>; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>, <6 IRQ_TYPE_LEVEL_HIGH>; + }; +}; + +&nfc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_nfc>; + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + status = "okay"; +}; + +&usbotg { + phy_type = "utmi_wide"; + disable-over-current; + /* Device role is not known, keep status disabled */ +}; + +&weim { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_weim>; + status = "okay"; + + lan9221: lan9221@5,0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lan9221>; + compatible = "smsc,lan9221", "smsc,lan9115"; + reg = <5 0x00000000 0x1000>; + fsl,weim-cs-timing = < + 0x00420081 0x00000000 + 0x32260000 0x00000000 + 0x72080f00 0x00000000 + >; + clocks = <&clks IMX5_CLK_DUMMY>; + interrupt-parent = <&gpio1>; + interrupts = <9 IRQ_TYPE_LEVEL_LOW>; + phy-mode = "mii"; + reg-io-width = <2>; + smsc,irq-push-pull; + vdd33a-supply = <&gpo2_reg>; + vddvario-supply = <&gpo2_reg>; + }; +}; + +&iomuxc { + imx51-digi-connectcore-som { + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 + MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 + MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 + MX51_PAD_CSPI1_SS0__GPIO4_24 0x85 /* CS0 */ + >; + }; + + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX51_PAD_SD2_CMD__SD2_CMD 0x400020d5 + MX51_PAD_SD2_CLK__SD2_CLK 0x20d5 + MX51_PAD_SD2_DATA0__SD2_DATA0 0x20d5 + MX51_PAD_SD2_DATA1__SD2_DATA1 0x20d5 + MX51_PAD_SD2_DATA2__SD2_DATA2 0x20d5 + MX51_PAD_SD2_DATA3__SD2_DATA3 0x20d5 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX51_PAD_DI_GP3__FEC_TX_ER 0x80000000 + MX51_PAD_DI2_PIN4__FEC_CRS 0x80000000 + MX51_PAD_DI2_PIN2__FEC_MDC 0x80000000 + MX51_PAD_DI2_PIN3__FEC_MDIO 0x80000000 + MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 0x80000000 + MX51_PAD_DI_GP4__FEC_RDATA2 0x80000000 + MX51_PAD_DISP2_DAT0__FEC_RDATA3 0x80000000 + MX51_PAD_DISP2_DAT1__FEC_RX_ER 0x80000000 + MX51_PAD_DISP2_DAT6__FEC_TDATA1 0x80000000 + MX51_PAD_DISP2_DAT7__FEC_TDATA2 0x80000000 + MX51_PAD_DISP2_DAT8__FEC_TDATA3 0x80000000 + MX51_PAD_DISP2_DAT9__FEC_TX_EN 0x80000000 + MX51_PAD_DISP2_DAT10__FEC_COL 0x80000000 + MX51_PAD_DISP2_DAT11__FEC_RX_CLK 0x80000000 + MX51_PAD_DISP2_DAT12__FEC_RX_DV 0x80000000 + MX51_PAD_DISP2_DAT13__FEC_TX_CLK 0x80000000 + MX51_PAD_DISP2_DAT14__FEC_RDATA0 0x80000000 + MX51_PAD_DISP2_DAT15__FEC_TDATA0 0x80000000 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX51_PAD_GPIO1_2__I2C2_SCL 0x400001ed + MX51_PAD_GPIO1_3__I2C2_SDA 0x400001ed + >; + }; + + pinctrl_nfc: nfcgrp { + fsl,pins = < + MX51_PAD_NANDF_D0__NANDF_D0 0x80000000 + MX51_PAD_NANDF_D1__NANDF_D1 0x80000000 + MX51_PAD_NANDF_D2__NANDF_D2 0x80000000 + MX51_PAD_NANDF_D3__NANDF_D3 0x80000000 + MX51_PAD_NANDF_D4__NANDF_D4 0x80000000 + MX51_PAD_NANDF_D5__NANDF_D5 0x80000000 + MX51_PAD_NANDF_D6__NANDF_D6 0x80000000 + MX51_PAD_NANDF_D7__NANDF_D7 0x80000000 + MX51_PAD_NANDF_ALE__NANDF_ALE 0x80000000 + MX51_PAD_NANDF_CLE__NANDF_CLE 0x80000000 + MX51_PAD_NANDF_RE_B__NANDF_RE_B 0x80000000 + MX51_PAD_NANDF_WE_B__NANDF_WE_B 0x80000000 + MX51_PAD_NANDF_WP_B__NANDF_WP_B 0x80000000 + MX51_PAD_NANDF_CS0__NANDF_CS0 0x80000000 + MX51_PAD_NANDF_RB0__NANDF_RB0 0x80000000 + >; + }; + + pinctrl_lan9221: lan9221grp { + fsl,pins = < + MX51_PAD_GPIO1_9__GPIO1_9 0xe5 /* IRQ */ + >; + }; + + pinctrl_mc13892: mc13892grp { + fsl,pins = < + MX51_PAD_GPIO1_5__GPIO1_5 0xe5 /* IRQ */ + >; + }; + + pinctrl_mma7455l: mma7455lgrp { + fsl,pins = < + MX51_PAD_GPIO1_7__GPIO1_7 0xe5 /* IRQ1 */ + MX51_PAD_GPIO1_6__GPIO1_6 0xe5 /* IRQ2 */ + >; + }; + + pinctrl_weim: weimgrp { + fsl,pins = < + MX51_PAD_EIM_DA0__EIM_DA0 0x80000000 + MX51_PAD_EIM_DA1__EIM_DA1 0x80000000 + MX51_PAD_EIM_DA2__EIM_DA2 0x80000000 + MX51_PAD_EIM_DA3__EIM_DA3 0x80000000 + MX51_PAD_EIM_DA4__EIM_DA4 0x80000000 + MX51_PAD_EIM_DA5__EIM_DA5 0x80000000 + MX51_PAD_EIM_DA6__EIM_DA6 0x80000000 + MX51_PAD_EIM_DA7__EIM_DA7 0x80000000 + MX51_PAD_EIM_DA8__EIM_DA8 0x80000000 + MX51_PAD_EIM_DA9__EIM_DA9 0x80000000 + MX51_PAD_EIM_DA10__EIM_DA10 0x80000000 + MX51_PAD_EIM_DA11__EIM_DA11 0x80000000 + MX51_PAD_EIM_DA12__EIM_DA12 0x80000000 + MX51_PAD_EIM_DA13__EIM_DA13 0x80000000 + MX51_PAD_EIM_DA14__EIM_DA14 0x80000000 + MX51_PAD_EIM_DA15__EIM_DA15 0x80000000 + MX51_PAD_EIM_A16__EIM_A16 0x80000000 + MX51_PAD_EIM_A17__EIM_A17 0x80000000 + MX51_PAD_EIM_A18__EIM_A18 0x80000000 + MX51_PAD_EIM_A19__EIM_A19 0x80000000 + MX51_PAD_EIM_A20__EIM_A20 0x80000000 + MX51_PAD_EIM_A21__EIM_A21 0x80000000 + MX51_PAD_EIM_A22__EIM_A22 0x80000000 + MX51_PAD_EIM_A23__EIM_A23 0x80000000 + MX51_PAD_EIM_A24__EIM_A24 0x80000000 + MX51_PAD_EIM_A25__EIM_A25 0x80000000 + MX51_PAD_EIM_A26__EIM_A26 0x80000000 + MX51_PAD_EIM_A27__EIM_A27 0x80000000 + MX51_PAD_EIM_D16__EIM_D16 0x80000000 + MX51_PAD_EIM_D17__EIM_D17 0x80000000 + MX51_PAD_EIM_D18__EIM_D18 0x80000000 + MX51_PAD_EIM_D19__EIM_D19 0x80000000 + MX51_PAD_EIM_D20__EIM_D20 0x80000000 + MX51_PAD_EIM_D21__EIM_D21 0x80000000 + MX51_PAD_EIM_D22__EIM_D22 0x80000000 + MX51_PAD_EIM_D23__EIM_D23 0x80000000 + MX51_PAD_EIM_D24__EIM_D24 0x80000000 + MX51_PAD_EIM_D25__EIM_D25 0x80000000 + MX51_PAD_EIM_D26__EIM_D26 0x80000000 + MX51_PAD_EIM_D27__EIM_D27 0x80000000 + MX51_PAD_EIM_D28__EIM_D28 0x80000000 + MX51_PAD_EIM_D29__EIM_D29 0x80000000 + MX51_PAD_EIM_D30__EIM_D30 0x80000000 + MX51_PAD_EIM_D31__EIM_D31 0x80000000 + MX51_PAD_EIM_OE__EIM_OE 0x80000000 + MX51_PAD_EIM_DTACK__EIM_DTACK 0x80000000 + MX51_PAD_EIM_LBA__EIM_LBA 0x80000000 + MX51_PAD_EIM_CS5__EIM_CS5 0x80000000 /* CS5 */ + >; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi b/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi index 9b3acf6e4282f3..63164266af8309 100644 --- a/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi +++ b/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi @@ -42,6 +42,17 @@ compatible = "nxp,pcf8563"; reg = <0x51>; }; + + tsc2007: tsc2007@49 { + compatible = "ti,tsc2007"; + gpios = <&gpio4 0 1>; + interrupt-parent = <&gpio4>; + interrupts = <0x0 0x8>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tsc2007_1>; + reg = <0x49>; + ti,x-plate-ohms = <180>; + }; }; &iomuxc { diff --git a/arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts b/arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts index 5cec4f32209608..8b1098ebaf7901 100644 --- a/arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts +++ b/arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts @@ -57,6 +57,20 @@ fsl,mux-int-port = <2>; fsl,mux-ext-port = <3>; }; + + usbphy { + #address-cells = <1>; + #size-cells = <0>; + compatible = "simple-bus"; + + usbh1phy: usbh1phy@0 { + compatible = "usb-nop-xceiv"; + reg = <0>; + clocks = <&clks IMX5_CLK_USB_PHY_GATE>; + clock-names = "main_clk"; + clock-frequency = <19200000>; + }; + }; }; &audmux { @@ -151,6 +165,29 @@ MX51_PAD_CSI1_D9__GPIO3_13 0x1f5 >; }; + + pinctrl_usbh1: usbh1grp { + fsl,pins = < + MX51_PAD_USBH1_CLK__USBH1_CLK 0x1e5 + MX51_PAD_USBH1_DIR__USBH1_DIR 0x1e5 + MX51_PAD_USBH1_NXT__USBH1_NXT 0x1e5 + MX51_PAD_USBH1_DATA0__USBH1_DATA0 0x1e5 + MX51_PAD_USBH1_DATA1__USBH1_DATA1 0x1e5 + MX51_PAD_USBH1_DATA2__USBH1_DATA2 0x1e5 + MX51_PAD_USBH1_DATA3__USBH1_DATA3 0x1e5 + MX51_PAD_USBH1_DATA4__USBH1_DATA4 0x1e5 + MX51_PAD_USBH1_DATA5__USBH1_DATA5 0x1e5 + MX51_PAD_USBH1_DATA6__USBH1_DATA6 0x1e5 + MX51_PAD_USBH1_DATA7__USBH1_DATA7 0x1e5 + MX51_PAD_USBH1_STP__USBH1_STP 0x1e5 + >; + }; + + pinctrl_usbh1_vbus: usbh1-vbusgrp { + fsl,pins = < + MX51_PAD_EIM_CS3__GPIO2_28 0x1f5 + >; + }; }; }; @@ -173,3 +210,24 @@ fsl,uart-has-rtscts; status = "okay"; }; + +&usbh1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbh1>; + fsl,usbphy = <&usbh1phy>; + dr_mode = "host"; + phy_type = "ulpi"; + status = "okay"; +}; + +&usbotg { + dr_mode = "otg"; + phy_type = "utmi_wide"; + status = "okay"; +}; + +&usbphy0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbh1_vbus>; + reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; +}; diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 150bb4e2f74437..bebbf3ba0d5e37 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -19,6 +19,7 @@ / { aliases { + ethernet0 = &fec; gpio0 = &gpio1; gpio1 = &gpio2; gpio2 = &gpio3; @@ -537,6 +538,8 @@ }; nfc: nand@83fdb000 { + #address-cells = <1>; + #size-cells = <1>; compatible = "fsl,imx51-nand"; reg = <0x83fdb000 0x1000 0xcfff0000 0x10000>; interrupts = <8>; diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts index 7c8c1296989291..a3431d7848709a 100644 --- a/arch/arm/boot/dts/imx53-mba53.dts +++ b/arch/arm/boot/dts/imx53-mba53.dts @@ -244,7 +244,7 @@ &tve { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_vga_sync_1>; - i2c-ddc-bus = <&i2c3>; + ddc-i2c-bus = <&i2c3>; fsl,tve-mode = "vga"; fsl,hsync-pin = <4>; fsl,vsync-pin = <6>; diff --git a/arch/arm/boot/dts/imx53-qsb-common.dtsi b/arch/arm/boot/dts/imx53-qsb-common.dtsi index ede04fa4161f63..df9cd9d41c4f80 100644 --- a/arch/arm/boot/dts/imx53-qsb-common.dtsi +++ b/arch/arm/boot/dts/imx53-qsb-common.dtsi @@ -272,6 +272,14 @@ >; }; + pinctrl_vga_sync: vgasync-grp { + fsl,pins = < + /* VGA_HSYNC, VSYNC with max drive strength */ + MX53_PAD_EIM_OE__IPU_DI1_PIN7 0xe6 + MX53_PAD_EIM_RW__IPU_DI1_PIN8 0xe6 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4 @@ -281,6 +289,15 @@ }; }; +&tve { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vga_sync>; + fsl,tve-mode = "vga"; + fsl,hsync-pin = <4>; + fsl,vsync-pin = <6>; + status = "okay"; +}; + &uart1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1>; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 9c2bff2252d0d0..375e66fad578e2 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -18,6 +18,7 @@ / { aliases { + ethernet0 = &fec; gpio0 = &gpio1; gpio1 = &gpio2; gpio2 = &gpio3; @@ -726,8 +727,8 @@ clocks = <&clks IMX5_CLK_VPU_GATE>, <&clks IMX5_CLK_VPU_GATE>; clock-names = "per", "ahb"; + resets = <&src 1>; iram = <&ocram>; - status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/imx6dl-phytec-pbab01.dts b/arch/arm/boot/dts/imx6dl-phytec-pbab01.dts new file mode 100644 index 00000000000000..08e97801494ec9 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-phytec-pbab01.dts @@ -0,0 +1,19 @@ +/* + * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx6dl-phytec-pfla02.dtsi" +#include "imx6qdl-phytec-pbab01.dtsi" + +/ { + model = "Phytec phyFLEX-i.MX6 DualLite/Solo Carrier-Board"; + compatible = "phytec,imx6dl-pbab01", "phytec,imx6dl-pfla02", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi new file mode 100644 index 00000000000000..964bc2ad3c5d5e --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include "imx6dl.dtsi" +#include "imx6qdl-phytec-pfla02.dtsi" + +/ { + model = "Phytec phyFLEX-i.MX6 DualLite/Solo"; + compatible = "phytec,imx6dl-pfla02", "fsl,imx6dl"; + + memory { + reg = <0x10000000 0x20000000>; + }; +}; diff --git a/arch/arm/boot/dts/imx6q-gk802.dts b/arch/arm/boot/dts/imx6q-gk802.dts index 4a9b4dc9afc0ab..0f0c50be8859c3 100644 --- a/arch/arm/boot/dts/imx6q-gk802.dts +++ b/arch/arm/boot/dts/imx6q-gk802.dts @@ -48,6 +48,11 @@ }; }; +&hdmi { + ddc-i2c-bus = <&i2c3>; + status = "okay"; +}; + /* Internal I2C */ &i2c2 { pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/imx6q-gw5400-a.dts b/arch/arm/boot/dts/imx6q-gw5400-a.dts index e51bb3f0fd560d..3689eaa58826ee 100644 --- a/arch/arm/boot/dts/imx6q-gw5400-a.dts +++ b/arch/arm/boot/dts/imx6q-gw5400-a.dts @@ -157,6 +157,11 @@ status = "okay"; }; +&hdmi { + ddc-i2c-bus = <&i2c3>; + status = "okay"; +}; + &i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/imx6q-phytec-pbab01.dts b/arch/arm/boot/dts/imx6q-phytec-pbab01.dts index 5607c331fca8f4..3a43dab728a820 100644 --- a/arch/arm/boot/dts/imx6q-phytec-pbab01.dts +++ b/arch/arm/boot/dts/imx6q-phytec-pbab01.dts @@ -11,40 +11,13 @@ /dts-v1/; #include "imx6q-phytec-pfla02.dtsi" +#include "imx6qdl-phytec-pbab01.dtsi" / { model = "Phytec phyFLEX-i.MX6 Quad Carrier-Board"; compatible = "phytec,imx6q-pbab01", "phytec,imx6q-pfla02", "fsl,imx6q"; }; -&fec { - status = "okay"; -}; - -&gpmi { - status = "okay"; -}; - &sata { - status = "okay"; -}; - -&uart4 { - status = "okay"; -}; - -&usbh1 { - status = "okay"; -}; - -&usbotg { - status = "okay"; -}; - -&usdhc2 { - status = "okay"; -}; - -&usdhc3 { - status = "okay"; + status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi index 324f1550976b65..cd20d0a948de4c 100644 --- a/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi +++ b/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi @@ -10,316 +10,13 @@ */ #include "imx6q.dtsi" +#include "imx6qdl-phytec-pfla02.dtsi" / { - model = "Phytec phyFLEX-i.MX6 Ouad"; + model = "Phytec phyFLEX-i.MX6 Quad"; compatible = "phytec,imx6q-pfla02", "fsl,imx6q"; memory { reg = <0x10000000 0x80000000>; }; - - regulators { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - reg_usb_otg_vbus: regulator@0 { - compatible = "regulator-fixed"; - reg = <0>; - regulator-name = "usb_otg_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio4 15 0>; - }; - - reg_usb_h1_vbus: regulator@1 { - compatible = "regulator-fixed"; - reg = <1>; - regulator-name = "usb_h1_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio1 0 0>; - }; - }; -}; - -&ecspi3 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ecspi3>; - status = "okay"; - fsl,spi-num-chipselects = <1>; - cs-gpios = <&gpio4 24 0>; - - flash@0 { - compatible = "m25p80"; - spi-max-frequency = <20000000>; - reg = <0>; - }; -}; - -&i2c1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c1>; - status = "okay"; - - eeprom@50 { - compatible = "atmel,24c32"; - reg = <0x50>; - }; - - pmic@58 { - compatible = "dialog,da9063"; - reg = <0x58>; - interrupt-parent = <&gpio4>; - interrupts = <17 0x8>; /* active-low GPIO4_17 */ - - regulators { - vddcore_reg: bcore1 { - regulator-min-microvolt = <730000>; - regulator-max-microvolt = <1380000>; - regulator-always-on; - }; - - vddsoc_reg: bcore2 { - regulator-min-microvolt = <730000>; - regulator-max-microvolt = <1380000>; - regulator-always-on; - }; - - vdd_ddr3_reg: bpro { - regulator-min-microvolt = <1500000>; - regulator-max-microvolt = <1500000>; - regulator-always-on; - }; - - vdd_3v3_reg: bperi { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - - vdd_buckmem_reg: bmem { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - - vdd_eth_reg: bio { - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - regulator-always-on; - }; - - vdd_eth_io_reg: ldo4 { - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <2500000>; - regulator-always-on; - }; - - vdd_mx6_snvs_reg: ldo5 { - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; - regulator-always-on; - }; - - vdd_3v3_pmic_io_reg: ldo6 { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - - vdd_sd0_reg: ldo9 { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; - - vdd_sd1_reg: ldo10 { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; - - vdd_mx6_high_reg: ldo11 { - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; - regulator-always-on; - }; - }; - }; -}; - -&iomuxc { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hog>; - - imx6q-phytec-pfla02 { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 - MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */ - MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x80000000 /* PMIC interrupt */ - >; - }; - - pinctrl_ecspi3: ecspi3grp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 - MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 - MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 - >; - }; - - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 - MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 - >; - }; - - pinctrl_gpmi_nand: gpminandgrp { - fsl,pins = < - MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 - MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 - MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 - MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 - MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 - MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 - MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 - MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 - MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 - MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 - MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 - MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 - MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 - MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 - MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 - MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 - MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 - >; - }; - - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; - - pinctrl_uart4: uart4grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 - MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 - >; - }; - - pinctrl_usbh1: usbh1grp { - fsl,pins = < - MX6QDL_PAD_GPIO_0__USB_H1_PWR 0x80000000 - >; - }; - - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 - MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 - >; - }; - - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - >; - }; - - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - >; - }; - - pinctrl_usdhc3_cdwp: usdhc3cdwp { - fsl,pins = < - MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 - MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 - >; - }; - }; -}; - -&fec { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet>; - phy-mode = "rgmii"; - phy-reset-gpios = <&gpio3 23 0>; - status = "disabled"; -}; - -&gpmi { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_gpmi_nand>; - nand-on-flash-bbt; - status = "disabled"; -}; - -&uart4 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart4>; - status = "disabled"; -}; - -&usbh1 { - vbus-supply = <®_usb_h1_vbus>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbh1>; - status = "disabled"; -}; - -&usbotg { - vbus-supply = <®_usb_otg_vbus>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbotg>; - disable-over-current; - status = "disabled"; -}; - -&usdhc2 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc2>; - cd-gpios = <&gpio1 4 0>; - wp-gpios = <&gpio1 2 0>; - status = "disabled"; -}; - -&usdhc3 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usdhc3 - &pinctrl_usdhc3_cdwp>; - cd-gpios = <&gpio1 27 0>; - wp-gpios = <&gpio1 29 0>; - status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi index 98a422153ce7b9..31665adcbf399e 100644 --- a/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi @@ -101,6 +101,11 @@ status = "okay"; }; +&hdmi { + ddc-i2c-bus = <&i2c3>; + status = "okay"; +}; + &i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi index 035d3a85c318b1..102219761b206e 100644 --- a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi @@ -148,6 +148,11 @@ status = "okay"; }; +&hdmi { + ddc-i2c-bus = <&i2c3>; + status = "okay"; +}; + &i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi index c8e5ae06deaf51..523f26f11eea43 100644 --- a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi @@ -157,6 +157,11 @@ status = "okay"; }; +&hdmi { + ddc-i2c-bus = <&i2c3>; + status = "okay"; +}; + &i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi index 2795dfc8c92632..cab94bfdf69191 100644 --- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi @@ -147,6 +147,11 @@ status = "okay"; }; +&hdmi { + ddc-i2c-bus = <&i2c3>; + status = "okay"; +}; + &i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi new file mode 100644 index 00000000000000..584721264121b2 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi @@ -0,0 +1,102 @@ +/* + * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/ { + chosen { + linux,stdout-path = &uart4; + }; +}; + +&fec { + status = "okay"; +}; + +&gpmi { + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + clock-frequency = <100000>; + status = "okay"; + + tlv320@18 { + compatible = "ti,tlv320aic3x"; + reg = <0x18>; + }; + + stmpe@41 { + compatible = "st,stmpe811"; + reg = <0x41>; + }; + + rtc@51 { + compatible = "nxp,rtc8564"; + reg = <0x51>; + }; + + adc@64 { + compatible = "maxim,max1037"; + reg = <0x64>; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + clock-frequency = <100000>; + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&uart4 { + status = "okay"; +}; + +&usbh1 { + status = "okay"; +}; + +&usbotg { + status = "okay"; +}; + +&usdhc2 { + status = "okay"; +}; + +&usdhc3 { + status = "okay"; +}; + +&iomuxc { + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi new file mode 100644 index 00000000000000..faa3494a69d4e3 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi @@ -0,0 +1,356 @@ +/* + * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include + +/ { + model = "Phytec phyFLEX-i.MX6 Ouad"; + compatible = "phytec,imx6q-pfla02", "fsl,imx6q"; + + memory { + reg = <0x10000000 0x80000000>; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_usb_otg_vbus: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio4 15 0>; + }; + + reg_usb_h1_vbus: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 0 0>; + }; + }; + + gpio_leds: leds { + compatible = "gpio-leds"; + + green { + label = "phyflex:green"; + gpios = <&gpio1 30 0>; + }; + + red { + label = "phyflex:red"; + gpios = <&gpio2 31 0>; + }; + }; +}; + +&ecspi3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi3>; + status = "okay"; + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio4 24 0>; + + flash@0 { + compatible = "m25p80"; + spi-max-frequency = <20000000>; + reg = <0>; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + eeprom@50 { + compatible = "atmel,24c32"; + reg = <0x50>; + }; + + pmic@58 { + compatible = "dialog,da9063"; + reg = <0x58>; + interrupt-parent = <&gpio4>; + interrupts = <17 0x8>; /* active-low GPIO4_17 */ + + regulators { + vddcore_reg: bcore1 { + regulator-min-microvolt = <730000>; + regulator-max-microvolt = <1380000>; + regulator-always-on; + }; + + vddsoc_reg: bcore2 { + regulator-min-microvolt = <730000>; + regulator-max-microvolt = <1380000>; + regulator-always-on; + }; + + vdd_ddr3_reg: bpro { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + }; + + vdd_3v3_reg: bperi { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_buckmem_reg: bmem { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_eth_reg: bio { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + vdd_eth_io_reg: ldo4 { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + + vdd_mx6_snvs_reg: ldo5 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + }; + + vdd_3v3_pmic_io_reg: ldo6 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_sd0_reg: ldo9 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + vdd_sd1_reg: ldo10 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + vdd_mx6_high_reg: ldo11 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + }; + }; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + imx6q-phytec-pfla02 { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 + MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */ + MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x80000000 /* PMIC interrupt */ + MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* Green LED */ + MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x80000000 /* Red LED */ + >; + }; + + pinctrl_ecspi3: ecspi3grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 + MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 + MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 + >; + }; + + pinctrl_gpmi_nand: gpminandgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D30__UART3_RTS_B 0x1b0b1 + MX6QDL_PAD_EIM_D31__UART3_CTS_B 0x1b0b1 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbh1: usbh1grp { + fsl,pins = < + MX6QDL_PAD_GPIO_0__USB_H1_PWR 0x80000000 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + + pinctrl_usdhc3_cdwp: usdhc3cdwp { + fsl,pins = < + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 + >; + }; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>; + status = "disabled"; +}; + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand>; + nand-on-flash-bbt; + status = "disabled"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + status = "disabled"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + status = "disabled"; +}; + +&usbh1 { + vbus-supply = <®_usb_h1_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbh1>; + status = "disabled"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "disabled"; +}; + +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + cd-gpios = <&gpio1 4 0>; + wp-gpios = <&gpio1 2 0>; + status = "disabled"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3 + &pinctrl_usdhc3_cdwp>; + cd-gpios = <&gpio1 27 0>; + wp-gpios = <&gpio1 29 0>; + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi index 0d816d3be4b697..dbbd35b899856c 100644 --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi @@ -105,6 +105,17 @@ default-brightness-level = <7>; status = "okay"; }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_leds>; + + red { + gpios = <&gpio1 2 0>; + default-state = "on"; + }; + }; }; &audmux { @@ -137,6 +148,11 @@ status = "okay"; }; +&hdmi { + ddc-i2c-bus = <&i2c2>; + status = "okay"; +}; + &i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; @@ -373,6 +389,13 @@ >; }; + pinctrl_pcie: pciegrp { + fsl,pins = < + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 + >; + }; + pinctrl_pwm1: pwm1grp { fsl,pins = < MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 @@ -422,6 +445,14 @@ >; }; }; + + gpio_leds { + pinctrl_gpio_leds: gpioledsgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 + >; + }; + }; }; &ldb { @@ -449,6 +480,14 @@ }; }; +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pcie>; + power-on-gpio = <&gpio3 19 0>; + reset-gpio = <&gpio7 12 0>; + status = "okay"; +}; + &pwm1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm1>; diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi index bdfdf89d405fcf..5c6f10c43f6564 100644 --- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi +++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi @@ -62,6 +62,18 @@ status = "okay"; }; +&hdmi { + ddc-i2c-bus = <&i2c1>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; +}; + &i2c2 { clock-frequency = <100000>; pinctrl-names = "default"; @@ -127,6 +139,13 @@ >; }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + pinctrl_i2c2: i2c2grp { fsl,pins = < MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index eca0971d4db1ae..ce0599134a699d 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -16,6 +16,7 @@ / { aliases { + ethernet0 = &fec; can0 = &can1; can1 = &can2; gpio0 = &gpio1; @@ -140,15 +141,16 @@ 0x81000000 0 0 0x01f80000 0 0x00010000 /* downstream I/O */ 0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */ num-lanes = <1>; - interrupts = <0 123 IRQ_TYPE_LEVEL_HIGH>; + interrupts = ; + interrupt-names = "msi"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, <0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>, <0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>, <0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clks 189>, <&clks 187>, <&clks 206>, <&clks 144>; - clock-names = "pcie_ref_125m", "sata_ref_100m", "lvds_gate", "pcie_axi"; + clocks = <&clks 144>, <&clks 206>, <&clks 189>; + clock-names = "pcie", "pcie_bus", "pcie_phy"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index d26b099260a35d..2d4e5285f3f365 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -14,6 +14,7 @@ / { aliases { + ethernet0 = &fec; gpio0 = &gpio1; gpio1 = &gpio2; gpio2 = &gpio3; diff --git a/arch/arm/boot/dts/k2e-evm.dts b/arch/arm/boot/dts/k2e-evm.dts index 74b3b63e94cf8c..fb7afab7eed54d 100644 --- a/arch/arm/boot/dts/k2e-evm.dts +++ b/arch/arm/boot/dts/k2e-evm.dts @@ -58,3 +58,62 @@ &usb1 { status = "okay"; }; + +&i2c0 { + dtt@50 { + compatible = "at,24c1024"; + reg = <0x50>; + }; +}; + +&aemif { + cs0 { + #address-cells = <2>; + #size-cells = <1>; + clock-ranges; + ranges; + + ti,cs-chipselect = <0>; + /* all timings in nanoseconds */ + ti,cs-min-turnaround-ns = <12>; + ti,cs-read-hold-ns = <6>; + ti,cs-read-strobe-ns = <23>; + ti,cs-read-setup-ns = <9>; + ti,cs-write-hold-ns = <8>; + ti,cs-write-strobe-ns = <23>; + ti,cs-write-setup-ns = <8>; + + nand@0,0 { + compatible = "ti,keystone-nand","ti,davinci-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0 0 0x4000000 + 1 0 0x0000100>; + + ti,davinci-chipselect = <0>; + ti,davinci-mask-ale = <0x2000>; + ti,davinci-mask-cle = <0x4000>; + ti,davinci-mask-chipsel = <0>; + nand-ecc-mode = "hw"; + ti,davinci-ecc-bits = <4>; + nand-on-flash-bbt; + + partition@0 { + label = "u-boot"; + reg = <0x0 0x100000>; + read-only; + }; + + partition@100000 { + label = "params"; + reg = <0x100000 0x80000>; + read-only; + }; + + partition@180000 { + label = "ubifs"; + reg = <0x180000 0x1FE80000>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/k2hk-evm.dts b/arch/arm/boot/dts/k2hk-evm.dts index c93d06f9f2a8db..d2aa1024ce32b7 100644 --- a/arch/arm/boot/dts/k2hk-evm.dts +++ b/arch/arm/boot/dts/k2hk-evm.dts @@ -138,3 +138,10 @@ }; }; }; + +&i2c0 { + dtt@50 { + compatible = "at,24c1024"; + reg = <0x50>; + }; +}; diff --git a/arch/arm/boot/dts/k2l-evm.dts b/arch/arm/boot/dts/k2l-evm.dts index 50a70132ac9e45..8ff2d330c2c51c 100644 --- a/arch/arm/boot/dts/k2l-evm.dts +++ b/arch/arm/boot/dts/k2l-evm.dts @@ -35,3 +35,62 @@ &usb { status = "okay"; }; + +&i2c0 { + dtt@50 { + compatible = "at,24c1024"; + reg = <0x50>; + }; +}; + +&aemif { + cs0 { + #address-cells = <2>; + #size-cells = <1>; + clock-ranges; + ranges; + + ti,cs-chipselect = <0>; + /* all timings in nanoseconds */ + ti,cs-min-turnaround-ns = <12>; + ti,cs-read-hold-ns = <6>; + ti,cs-read-strobe-ns = <23>; + ti,cs-read-setup-ns = <9>; + ti,cs-write-hold-ns = <8>; + ti,cs-write-strobe-ns = <23>; + ti,cs-write-setup-ns = <8>; + + nand@0,0 { + compatible = "ti,keystone-nand","ti,davinci-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0 0 0x4000000 + 1 0 0x0000100>; + + ti,davinci-chipselect = <0>; + ti,davinci-mask-ale = <0x2000>; + ti,davinci-mask-cle = <0x4000>; + ti,davinci-mask-chipsel = <0>; + nand-ecc-mode = "hw"; + ti,davinci-ecc-bits = <4>; + nand-on-flash-bbt; + + partition@0 { + label = "u-boot"; + reg = <0x0 0x100000>; + read-only; + }; + + partition@100000 { + label = "params"; + reg = <0x100000 0x80000>; + read-only; + }; + + partition@180000 { + label = "ubifs"; + reg = <0x180000 0x7FE80000>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi index 90823eb90c1b82..d9f99e7deb83d6 100644 --- a/arch/arm/boot/dts/keystone.dtsi +++ b/arch/arm/boot/dts/keystone.dtsi @@ -28,8 +28,6 @@ gic: interrupt-controller { compatible = "arm,cortex-a15-gic"; #interrupt-cells = <3>; - #size-cells = <0>; - #address-cells = <1>; interrupt-controller; reg = <0x0 0x02561000 0x0 0x1000>, <0x0 0x02562000 0x0 0x2000>, @@ -66,6 +64,7 @@ compatible = "ti,keystone","simple-bus"; interrupt-parent = <&gic>; ranges = <0x0 0x0 0x0 0xc0000000>; + dma-ranges = <0x80000000 0x8 0x00000000 0x80000000>; rstctrl: reset-controller { compatible = "ti,keystone-reset"; @@ -102,11 +101,6 @@ interrupts = ; #address-cells = <1>; #size-cells = <0>; - - dtt@50 { - compatible = "at,24c1024"; - reg = <0x50>; - }; }; i2c1: i2c@2530400 { @@ -115,6 +109,8 @@ clock-frequency = <100000>; clocks = <&clki2c>; interrupts = ; + #address-cells = <1>; + #size-cells = <0>; }; i2c2: i2c@2530800 { @@ -123,6 +119,8 @@ clock-frequency = <100000>; clocks = <&clki2c>; interrupts = ; + #address-cells = <1>; + #size-cells = <0>; }; spi0: spi@21000400 { @@ -132,6 +130,8 @@ ti,davinci-spi-intr-line = <0>; interrupts = ; clocks = <&clkspi>; + #address-cells = <1>; + #size-cells = <0>; }; spi1: spi@21000600 { @@ -141,6 +141,8 @@ ti,davinci-spi-intr-line = <0>; interrupts = ; clocks = <&clkspi>; + #address-cells = <1>; + #size-cells = <0>; }; spi2: spi@21000800 { @@ -150,6 +152,8 @@ ti,davinci-spi-intr-line = <0>; interrupts = ; clocks = <&clkspi>; + #address-cells = <1>; + #size-cells = <0>; }; usb_phy: usb_phy@2620738 { @@ -169,6 +173,8 @@ clock-names = "usb"; interrupts = ; ranges; + dma-coherent; + dma-ranges; status = "disabled"; dwc3@2690000 { diff --git a/arch/arm/boot/dts/kirkwood-6192.dtsi b/arch/arm/boot/dts/kirkwood-6192.dtsi index 3916937d681803..dd81508b919b87 100644 --- a/arch/arm/boot/dts/kirkwood-6192.dtsi +++ b/arch/arm/boot/dts/kirkwood-6192.dtsi @@ -1,6 +1,6 @@ / { mbus { - pcie-controller { + pciec: pcie-controller { compatible = "marvell,kirkwood-pcie"; status = "disabled"; device_type = "pci"; @@ -15,7 +15,7 @@ 0x82000000 0x1 0 MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 0.0 MEM */ 0x81000000 0x1 0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 IO */>; - pcie@1,0 { + pcie0: pcie@1,0 { device_type = "pci"; assigned-addresses = <0x82000800 0 0x00040000 0 0x2000>; reg = <0x0800 0 0 0 0>; @@ -35,16 +35,9 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { compatible = "marvell,88f6192-pinctrl"; - reg = <0x10000 0x20>; - pmx_nand: pmx-nand { - marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3", - "mpp4", "mpp5", "mpp18", - "mpp19"; - marvell,function = "nand"; - }; pmx_sata0: pmx-sata0 { marvell,pins = "mpp5", "mpp21", "mpp23"; marvell,function = "sata0"; @@ -53,22 +46,6 @@ marvell,pins = "mpp4", "mpp20", "mpp22"; marvell,function = "sata1"; }; - pmx_spi: pmx-spi { - marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3"; - marvell,function = "spi"; - }; - pmx_twsi0: pmx-twsi0 { - marvell,pins = "mpp8", "mpp9"; - marvell,function = "twsi0"; - }; - pmx_uart0: pmx-uart0 { - marvell,pins = "mpp10", "mpp11"; - marvell,function = "uart0"; - }; - pmx_uart1: pmx-uart1 { - marvell,pins = "mpp13", "mpp14"; - marvell,function = "uart1"; - }; pmx_sdio: pmx-sdio { marvell,pins = "mpp12", "mpp13", "mpp14", "mpp15", "mpp16", "mpp17"; @@ -76,14 +53,14 @@ }; }; - rtc@10300 { + rtc: rtc@10300 { compatible = "marvell,kirkwood-rtc", "marvell,orion-rtc"; reg = <0x10300 0x20>; interrupts = <53>; clocks = <&gate_clk 7>; }; - sata@80000 { + sata: sata@80000 { compatible = "marvell,orion-sata"; reg = <0x80000 0x5000>; interrupts = <21>; @@ -92,7 +69,7 @@ status = "disabled"; }; - mvsdio@90000 { + sdio: mvsdio@90000 { compatible = "marvell,orion-sdio"; reg = <0x90000 0x200>; interrupts = <28>; diff --git a/arch/arm/boot/dts/kirkwood-6281.dtsi b/arch/arm/boot/dts/kirkwood-6281.dtsi index 416d96e1302fab..7dc7d6782e8325 100644 --- a/arch/arm/boot/dts/kirkwood-6281.dtsi +++ b/arch/arm/boot/dts/kirkwood-6281.dtsi @@ -1,6 +1,6 @@ / { mbus { - pcie-controller { + pciec: pcie-controller { compatible = "marvell,kirkwood-pcie"; status = "disabled"; device_type = "pci"; @@ -15,7 +15,7 @@ 0x82000000 0x1 0 MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 0.0 MEM */ 0x81000000 0x1 0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 IO */>; - pcie@1,0 { + pcie0: pcie@1,0 { device_type = "pci"; assigned-addresses = <0x82000800 0 0x00040000 0 0x2000>; reg = <0x0800 0 0 0 0>; @@ -35,16 +35,9 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { compatible = "marvell,88f6281-pinctrl"; - reg = <0x10000 0x20>; - pmx_nand: pmx-nand { - marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3", - "mpp4", "mpp5", "mpp18", - "mpp19"; - marvell,function = "nand"; - }; pmx_sata0: pmx-sata0 { marvell,pins = "mpp5", "mpp21", "mpp23"; marvell,function = "sata0"; @@ -53,22 +46,6 @@ marvell,pins = "mpp4", "mpp20", "mpp22"; marvell,function = "sata1"; }; - pmx_spi: pmx-spi { - marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3"; - marvell,function = "spi"; - }; - pmx_twsi0: pmx-twsi0 { - marvell,pins = "mpp8", "mpp9"; - marvell,function = "twsi0"; - }; - pmx_uart0: pmx-uart0 { - marvell,pins = "mpp10", "mpp11"; - marvell,function = "uart0"; - }; - pmx_uart1: pmx-uart1 { - marvell,pins = "mpp13", "mpp14"; - marvell,function = "uart1"; - }; pmx_sdio: pmx-sdio { marvell,pins = "mpp12", "mpp13", "mpp14", "mpp15", "mpp16", "mpp17"; @@ -76,14 +53,14 @@ }; }; - rtc@10300 { + rtc: rtc@10300 { compatible = "marvell,kirkwood-rtc", "marvell,orion-rtc"; reg = <0x10300 0x20>; interrupts = <53>; clocks = <&gate_clk 7>; }; - sata@80000 { + sata: sata@80000 { compatible = "marvell,orion-sata"; reg = <0x80000 0x5000>; interrupts = <21>; @@ -94,7 +71,7 @@ status = "disabled"; }; - mvsdio@90000 { + sdio: mvsdio@90000 { compatible = "marvell,orion-sdio"; reg = <0x90000 0x200>; interrupts = <28>; diff --git a/arch/arm/boot/dts/kirkwood-6282.dtsi b/arch/arm/boot/dts/kirkwood-6282.dtsi index 2902e0d7971d06..4680eec990f0cd 100644 --- a/arch/arm/boot/dts/kirkwood-6282.dtsi +++ b/arch/arm/boot/dts/kirkwood-6282.dtsi @@ -1,6 +1,6 @@ / { mbus { - pcie-controller { + pciec: pcie-controller { compatible = "marvell,kirkwood-pcie"; status = "disabled"; device_type = "pci"; @@ -19,7 +19,7 @@ 0x82000000 0x2 0 MBUS_ID(0x04, 0xd8) 0 1 0 /* Port 1.0 MEM */ 0x81000000 0x2 0 MBUS_ID(0x04, 0xd0) 0 1 0 /* Port 1.0 IO */>; - pcie@1,0 { + pcie0: pcie@1,0 { device_type = "pci"; assigned-addresses = <0x82000800 0 0x00040000 0 0x2000>; reg = <0x0800 0 0 0 0>; @@ -36,7 +36,7 @@ status = "disabled"; }; - pcie@2,0 { + pcie1: pcie@2,0 { device_type = "pci"; assigned-addresses = <0x82001000 0 0x00044000 0 0x2000>; reg = <0x1000 0 0 0 0>; @@ -56,15 +56,8 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { compatible = "marvell,88f6282-pinctrl"; - reg = <0x10000 0x20>; - - pmx_nand: pmx-nand { - marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3", - "mpp4", "mpp5", "mpp18", "mpp19"; - marvell,function = "nand"; - }; pmx_sata0: pmx-sata0 { marvell,pins = "mpp5", "mpp21", "mpp23"; @@ -74,29 +67,16 @@ marvell,pins = "mpp4", "mpp20", "mpp22"; marvell,function = "sata1"; }; - pmx_spi: pmx-spi { - marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3"; - marvell,function = "spi"; - }; - pmx_twsi0: pmx-twsi0 { - marvell,pins = "mpp8", "mpp9"; - marvell,function = "twsi0"; - }; + /* + * Default I2C1 pinctrl setting on mpp36/mpp37, + * overwrite marvell,pins on board level if required. + */ pmx_twsi1: pmx-twsi1 { marvell,pins = "mpp36", "mpp37"; marvell,function = "twsi1"; }; - pmx_uart0: pmx-uart0 { - marvell,pins = "mpp10", "mpp11"; - marvell,function = "uart0"; - }; - - pmx_uart1: pmx-uart1 { - marvell,pins = "mpp13", "mpp14"; - marvell,function = "uart1"; - }; pmx_sdio: pmx-sdio { marvell,pins = "mpp12", "mpp13", "mpp14", "mpp15", "mpp16", "mpp17"; @@ -104,20 +84,20 @@ }; }; - thermal@10078 { + thermal: thermal@10078 { compatible = "marvell,kirkwood-thermal"; reg = <0x10078 0x4>; status = "okay"; }; - rtc@10300 { + rtc: rtc@10300 { compatible = "marvell,kirkwood-rtc", "marvell,orion-rtc"; reg = <0x10300 0x20>; interrupts = <53>; clocks = <&gate_clk 7>; }; - i2c@11100 { + i2c1: i2c@11100 { compatible = "marvell,mv64xxx-i2c"; reg = <0x11100 0x20>; #address-cells = <1>; @@ -125,10 +105,12 @@ interrupts = <32>; clock-frequency = <100000>; clocks = <&gate_clk 7>; + pinctrl-0 = <&pmx_twsi1>; + pinctrl-names = "default"; status = "disabled"; }; - sata@80000 { + sata: sata@80000 { compatible = "marvell,orion-sata"; reg = <0x80000 0x5000>; interrupts = <21>; @@ -139,7 +121,7 @@ status = "disabled"; }; - mvsdio@90000 { + sdio: mvsdio@90000 { compatible = "marvell,orion-sdio"; reg = <0x90000 0x200>; interrupts = <28>; diff --git a/arch/arm/boot/dts/kirkwood-98dx4122.dtsi b/arch/arm/boot/dts/kirkwood-98dx4122.dtsi index 3271e4c8ea07c6..2e8e412b9db0dd 100644 --- a/arch/arm/boot/dts/kirkwood-98dx4122.dtsi +++ b/arch/arm/boot/dts/kirkwood-98dx4122.dtsi @@ -1,31 +1,8 @@ / { ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { compatible = "marvell,98dx4122-pinctrl"; - reg = <0x10000 0x20>; - pmx_nand: pmx-nand { - marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3", - "mpp4", "mpp5", "mpp18", - "mpp19"; - marvell,function = "nand"; - }; - pmx_spi: pmx-spi { - marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3"; - marvell,function = "spi"; - }; - pmx_twsi0: pmx-twsi0 { - marvell,pins = "mpp8", "mpp9"; - marvell,function = "twsi0"; - }; - pmx_uart0: pmx-uart0 { - marvell,pins = "mpp10", "mpp11"; - marvell,function = "uart0"; - }; - pmx_uart1: pmx-uart1 { - marvell,pins = "mpp13", "mpp14"; - marvell,function = "uart1"; - }; }; }; }; diff --git a/arch/arm/boot/dts/kirkwood-b3.dts b/arch/arm/boot/dts/kirkwood-b3.dts index 6becedebaa4e94..c9247f8672ae14 100644 --- a/arch/arm/boot/dts/kirkwood-b3.dts +++ b/arch/arm/boot/dts/kirkwood-b3.dts @@ -30,6 +30,7 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; mbus { @@ -44,7 +45,7 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_button_power: pmx-button-power { marvell,pins = "mpp39"; marvell,function = "gpio"; @@ -69,8 +70,6 @@ spi@10600 { status = "okay"; - pinctrl-0 = <&pmx_spi>; - pinctrl-names = "default"; m25p16@0 { #address-cells = <1>; @@ -113,8 +112,6 @@ * UART0_TX = Testpoint 66 * See the Excito Wiki for more details. */ - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; status = "okay"; }; diff --git a/arch/arm/boot/dts/kirkwood-cloudbox.dts b/arch/arm/boot/dts/kirkwood-cloudbox.dts index 3b62aeeaa3a2fe..ab6ab4933e6bae 100644 --- a/arch/arm/boot/dts/kirkwood-cloudbox.dts +++ b/arch/arm/boot/dts/kirkwood-cloudbox.dts @@ -14,10 +14,11 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_cloudbox_sata0: pmx-cloudbox-sata0 { marvell,pins = "mpp15"; marvell,function = "sata0"; @@ -25,9 +26,6 @@ }; serial@12000 { - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; - clock-frequency = <166666667>; status = "okay"; }; @@ -39,8 +37,6 @@ }; spi@10600 { - pinctrl-0 = <&pmx_spi>; - pinctrl-names = "default"; status = "okay"; flash@0 { diff --git a/arch/arm/boot/dts/kirkwood-db.dtsi b/arch/arm/boot/dts/kirkwood-db.dtsi index 02d1225ef99f83..812df691ae3d11 100644 --- a/arch/arm/boot/dts/kirkwood-db.dtsi +++ b/arch/arm/boot/dts/kirkwood-db.dtsi @@ -22,10 +22,11 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl@10000 { + pin-controller@10000 { pmx_sdio_gpios: pmx-sdio-gpios { marvell,pins = "mpp37", "mpp38"; marvell,function = "gpio"; @@ -33,10 +34,7 @@ }; serial@12000 { - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; - clock-frequency = <200000000>; - status = "ok"; + status = "okay"; }; sata@80000 { @@ -59,8 +57,6 @@ }; &nand { - pinctrl-0 = <&pmx_nand>; - pinctrl-names = "default"; chip-delay = <25>; status = "okay"; diff --git a/arch/arm/boot/dts/kirkwood-dns320.dts b/arch/arm/boot/dts/kirkwood-dns320.dts index bf7fe8ab88f435..d85ef0a91b5019 100644 --- a/arch/arm/boot/dts/kirkwood-dns320.dts +++ b/arch/arm/boot/dts/kirkwood-dns320.dts @@ -13,6 +13,7 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; gpio-leds { @@ -51,8 +52,6 @@ }; serial@12100 { - pinctrl-0 = <&pmx_uart1>; - pinctrl-names = "default"; status = "okay"; }; }; diff --git a/arch/arm/boot/dts/kirkwood-dns325.dts b/arch/arm/boot/dts/kirkwood-dns325.dts index cb9978c652f2d1..5e586ed04c58a4 100644 --- a/arch/arm/boot/dts/kirkwood-dns325.dts +++ b/arch/arm/boot/dts/kirkwood-dns325.dts @@ -13,6 +13,7 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; gpio-leds { diff --git a/arch/arm/boot/dts/kirkwood-dnskw.dtsi b/arch/arm/boot/dts/kirkwood-dnskw.dtsi index d5aa9564a287ee..113dcf056dcfb7 100644 --- a/arch/arm/boot/dts/kirkwood-dnskw.dtsi +++ b/arch/arm/boot/dts/kirkwood-dnskw.dtsi @@ -50,7 +50,7 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-0 = <&pmx_power_back_on &pmx_present_sata0 &pmx_present_sata1 &pmx_fan_tacho @@ -183,8 +183,6 @@ }; &nand { - pinctrl-0 = <&pmx_nand>; - pinctrl-names = "default"; status = "okay"; chip-delay = <35>; diff --git a/arch/arm/boot/dts/kirkwood-dockstar.dts b/arch/arm/boot/dts/kirkwood-dockstar.dts index f31312ebd0d60b..84973634951143 100644 --- a/arch/arm/boot/dts/kirkwood-dockstar.dts +++ b/arch/arm/boot/dts/kirkwood-dockstar.dts @@ -14,10 +14,11 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk root=/dev/sda1 rootdelay=10"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_usb_power_enable: pmx-usb-power-enable { marvell,pins = "mpp29"; marvell,function = "gpio"; diff --git a/arch/arm/boot/dts/kirkwood-dreamplug.dts b/arch/arm/boot/dts/kirkwood-dreamplug.dts index 28b3ee369778f9..6467c792419590 100644 --- a/arch/arm/boot/dts/kirkwood-dreamplug.dts +++ b/arch/arm/boot/dts/kirkwood-dreamplug.dts @@ -14,10 +14,11 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_led_bluetooth: pmx-led-bluetooth { marvell,pins = "mpp47"; marvell,function = "gpio"; @@ -37,8 +38,6 @@ spi@10600 { status = "okay"; - pinctrl-0 = <&pmx_spi>; - pinctrl-names = "default"; m25p40@0 { #address-cells = <1>; diff --git a/arch/arm/boot/dts/kirkwood-ds109.dts b/arch/arm/boot/dts/kirkwood-ds109.dts index 772092c94ca34a..d4bcc1c7f6b31a 100644 --- a/arch/arm/boot/dts/kirkwood-ds109.dts +++ b/arch/arm/boot/dts/kirkwood-ds109.dts @@ -25,6 +25,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-150-32-35 { diff --git a/arch/arm/boot/dts/kirkwood-ds110jv10.dts b/arch/arm/boot/dts/kirkwood-ds110jv10.dts index aabafbe0da4c77..95bf83b91b4aca 100644 --- a/arch/arm/boot/dts/kirkwood-ds110jv10.dts +++ b/arch/arm/boot/dts/kirkwood-ds110jv10.dts @@ -25,6 +25,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-150-32-35 { diff --git a/arch/arm/boot/dts/kirkwood-ds111.dts b/arch/arm/boot/dts/kirkwood-ds111.dts index 16ec7fbab5734a..61f47fbe44d0d6 100644 --- a/arch/arm/boot/dts/kirkwood-ds111.dts +++ b/arch/arm/boot/dts/kirkwood-ds111.dts @@ -24,6 +24,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-100-15-35-1 { diff --git a/arch/arm/boot/dts/kirkwood-ds112.dts b/arch/arm/boot/dts/kirkwood-ds112.dts index cff1b2388765bb..bf4143c6cb8f10 100644 --- a/arch/arm/boot/dts/kirkwood-ds112.dts +++ b/arch/arm/boot/dts/kirkwood-ds112.dts @@ -24,6 +24,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-100-15-35-1 { diff --git a/arch/arm/boot/dts/kirkwood-ds209.dts b/arch/arm/boot/dts/kirkwood-ds209.dts index 330411993d3865..6d25093a9ac482 100644 --- a/arch/arm/boot/dts/kirkwood-ds209.dts +++ b/arch/arm/boot/dts/kirkwood-ds209.dts @@ -24,6 +24,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-150-32-35 { diff --git a/arch/arm/boot/dts/kirkwood-ds210.dts b/arch/arm/boot/dts/kirkwood-ds210.dts index 6052eaa37d4f31..2f1933efcac1f4 100644 --- a/arch/arm/boot/dts/kirkwood-ds210.dts +++ b/arch/arm/boot/dts/kirkwood-ds210.dts @@ -26,6 +26,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-150-32-35 { diff --git a/arch/arm/boot/dts/kirkwood-ds212.dts b/arch/arm/boot/dts/kirkwood-ds212.dts index 7f76cd30e84e73..99afd462f956ff 100644 --- a/arch/arm/boot/dts/kirkwood-ds212.dts +++ b/arch/arm/boot/dts/kirkwood-ds212.dts @@ -27,6 +27,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-100-15-35-1 { diff --git a/arch/arm/boot/dts/kirkwood-ds212j.dts b/arch/arm/boot/dts/kirkwood-ds212j.dts index 1f83a00f1f74e4..f5c4213fc67cc8 100644 --- a/arch/arm/boot/dts/kirkwood-ds212j.dts +++ b/arch/arm/boot/dts/kirkwood-ds212j.dts @@ -25,6 +25,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-100-32-35 { diff --git a/arch/arm/boot/dts/kirkwood-ds409.dts b/arch/arm/boot/dts/kirkwood-ds409.dts index 0a573add44a252..e80a962ebba0a5 100644 --- a/arch/arm/boot/dts/kirkwood-ds409.dts +++ b/arch/arm/boot/dts/kirkwood-ds409.dts @@ -24,6 +24,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-150-15-18 { diff --git a/arch/arm/boot/dts/kirkwood-ds409slim.dts b/arch/arm/boot/dts/kirkwood-ds409slim.dts index 1848a6245fd30a..cae5af4b88b561 100644 --- a/arch/arm/boot/dts/kirkwood-ds409slim.dts +++ b/arch/arm/boot/dts/kirkwood-ds409slim.dts @@ -24,6 +24,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-150-32-35 { diff --git a/arch/arm/boot/dts/kirkwood-ds411.dts b/arch/arm/boot/dts/kirkwood-ds411.dts index a1737b4311c628..623cd4a37d7171 100644 --- a/arch/arm/boot/dts/kirkwood-ds411.dts +++ b/arch/arm/boot/dts/kirkwood-ds411.dts @@ -24,6 +24,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-100-15-35-1 { diff --git a/arch/arm/boot/dts/kirkwood-ds411j.dts b/arch/arm/boot/dts/kirkwood-ds411j.dts index 0cde914eceaee4..3348e330f0742f 100644 --- a/arch/arm/boot/dts/kirkwood-ds411j.dts +++ b/arch/arm/boot/dts/kirkwood-ds411j.dts @@ -24,6 +24,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-150-15-18 { diff --git a/arch/arm/boot/dts/kirkwood-ds411slim.dts b/arch/arm/boot/dts/kirkwood-ds411slim.dts index aef0cadc2c781f..a0a1fad8b4de5f 100644 --- a/arch/arm/boot/dts/kirkwood-ds411slim.dts +++ b/arch/arm/boot/dts/kirkwood-ds411slim.dts @@ -24,6 +24,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-100-15-35-1 { diff --git a/arch/arm/boot/dts/kirkwood-goflexnet.dts b/arch/arm/boot/dts/kirkwood-goflexnet.dts index eb93294201070a..aa60a0b049a772 100644 --- a/arch/arm/boot/dts/kirkwood-goflexnet.dts +++ b/arch/arm/boot/dts/kirkwood-goflexnet.dts @@ -14,10 +14,11 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk root=/dev/sda1 rootdelay=10"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_usb_power_enable: pmx-usb-power-enable { marvell,pins = "mpp29"; marvell,function = "gpio"; diff --git a/arch/arm/boot/dts/kirkwood-guruplug-server-plus.dts b/arch/arm/boot/dts/kirkwood-guruplug-server-plus.dts index 2d51fce74a5ad1..c5a1fc75c7a3b4 100644 --- a/arch/arm/boot/dts/kirkwood-guruplug-server-plus.dts +++ b/arch/arm/boot/dts/kirkwood-guruplug-server-plus.dts @@ -14,10 +14,11 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_led_health_r: pmx-led-health-r { marvell,pins = "mpp46"; marvell,function = "gpio"; @@ -36,7 +37,6 @@ }; }; serial@12000 { - clock-frequency = <200000000>; status = "ok"; }; @@ -101,13 +101,19 @@ status = "okay"; ethphy0: ethernet-phy@0 { - compatible = "marvell,88e1121"; + /* Marvell 88E1121R */ + compatible = "ethernet-phy-id0141.0cb0", + "ethernet-phy-ieee802.3-c22"; reg = <0>; + phy-connection-type = "rgmii-id"; }; ethphy1: ethernet-phy@1 { - compatible = "marvell,88e1121"; + /* Marvell 88E1121R */ + compatible = "ethernet-phy-id0141.0cb0", + "ethernet-phy-ieee802.3-c22"; reg = <1>; + phy-connection-type = "rgmii-id"; }; }; diff --git a/arch/arm/boot/dts/kirkwood-ib62x0.dts b/arch/arm/boot/dts/kirkwood-ib62x0.dts index a1add3f215e394..bfa5edde179c30 100644 --- a/arch/arm/boot/dts/kirkwood-ib62x0.dts +++ b/arch/arm/boot/dts/kirkwood-ib62x0.dts @@ -14,10 +14,11 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_led_os_red: pmx-led-os-red { marvell,pins = "mpp22"; marvell,function = "gpio"; @@ -104,8 +105,6 @@ &nand { status = "okay"; - pinctrl-0 = <&pmx_nand>; - pinctrl-names = "default"; partition@0 { label = "u-boot"; diff --git a/arch/arm/boot/dts/kirkwood-iconnect.dts b/arch/arm/boot/dts/kirkwood-iconnect.dts index 8d8c80e3656d6e..38e31d15a62d3f 100644 --- a/arch/arm/boot/dts/kirkwood-iconnect.dts +++ b/arch/arm/boot/dts/kirkwood-iconnect.dts @@ -14,6 +14,7 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; linux,initrd-start = <0x4500040>; linux,initrd-end = <0x4800000>; }; @@ -29,7 +30,7 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_button_reset: pmx-button-reset { marvell,pins = "mpp12"; marvell,function = "gpio"; diff --git a/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts b/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts index 59e7a5adeedbcb..05291f3990d035 100644 --- a/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts +++ b/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts @@ -14,10 +14,11 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-0 = < &pmx_led_sata_brt_ctrl_1 &pmx_led_sata_brt_ctrl_2 &pmx_led_backup_brt_ctrl_1 diff --git a/arch/arm/boot/dts/kirkwood-km_kirkwood.dts b/arch/arm/boot/dts/kirkwood-km_kirkwood.dts index 04a1e44541b34b..61139bf309858c 100644 --- a/arch/arm/boot/dts/kirkwood-km_kirkwood.dts +++ b/arch/arm/boot/dts/kirkwood-km_kirkwood.dts @@ -14,10 +14,11 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-0 = < &pmx_i2c_gpio_sda &pmx_i2c_gpio_scl >; pinctrl-names = "default"; @@ -45,9 +46,7 @@ }; &nand { - pinctrl-0 = <&pmx_nand>; - pinctrl-names = "default"; - status = "ok"; + status = "okay"; chip-delay = <25>; }; diff --git a/arch/arm/boot/dts/kirkwood-laplug.dts b/arch/arm/boot/dts/kirkwood-laplug.dts index 6761ffa2c4ab7e..24425660e973c4 100644 --- a/arch/arm/boot/dts/kirkwood-laplug.dts +++ b/arch/arm/boot/dts/kirkwood-laplug.dts @@ -24,6 +24,7 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; mbus { @@ -37,14 +38,10 @@ ocp@f1000000 { serial@12000 { - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; status = "okay"; }; i2c@11000 { - pinctrl-0 = <&pmx_twsi0>; - pinctrl-names = "default"; status = "okay"; eeprom@50 { @@ -54,7 +51,7 @@ }; }; - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_usb_power_enable: pmx-usb-power-enable { marvell,pins = "mpp14"; marvell,function = "gpio"; @@ -139,7 +136,6 @@ &nand { /* Total size : 512MB */ status = "okay"; - pinctrl-0 = <&pmx_nand>; partition@0 { label = "u-boot"; diff --git a/arch/arm/boot/dts/kirkwood-lsxl.dtsi b/arch/arm/boot/dts/kirkwood-lsxl.dtsi index 1656653d339b55..53484474df1f46 100644 --- a/arch/arm/boot/dts/kirkwood-lsxl.dtsi +++ b/arch/arm/boot/dts/kirkwood-lsxl.dtsi @@ -4,10 +4,11 @@ / { chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_power_hdd: pmx-power-hdd { marvell,pins = "mpp10"; marvell,function = "gpo"; diff --git a/arch/arm/boot/dts/kirkwood-mplcec4.dts b/arch/arm/boot/dts/kirkwood-mplcec4.dts index 73722c06750182..f3a991837515d4 100644 --- a/arch/arm/boot/dts/kirkwood-mplcec4.dts +++ b/arch/arm/boot/dts/kirkwood-mplcec4.dts @@ -12,9 +12,10 @@ reg = <0x00000000 0x20000000>; }; - chosen { - bootargs = "console=ttyS0,115200n8 earlyprintk"; - }; + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; + }; mbus { pcie-controller { @@ -27,7 +28,7 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_led_health: pmx-led-health { marvell,pins = "mpp7"; marvell,function = "gpo"; @@ -89,11 +90,9 @@ }; - serial@12000 { - status = "ok"; - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; - }; + serial@12000 { + status = "okay"; + }; rtc@10300 { status = "disabled"; @@ -163,8 +162,6 @@ }; &nand { - pinctrl-0 = <&pmx_nand>; - pinctrl-names = "default"; status = "okay"; partition@0 { diff --git a/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts b/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts index 32c6fb4a11624c..8f76d28759a307 100644 --- a/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts +++ b/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts @@ -28,10 +28,21 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; + mbus { + pcie-controller { + status = "okay"; + + pcie@1,0 { + status = "okay"; + }; + }; + }; + ocp@f1000000 { - pinctrl@10000 { + pin-controller@10000 { pmx_usb_led: pmx-usb-led { marvell,pins = "mpp12"; marvell,function = "gpo"; @@ -49,8 +60,6 @@ }; spi@10600 { - pinctrl-0 = <&pmx_spi>; - pinctrl-names = "default"; status = "okay"; flash@0 { @@ -64,22 +73,11 @@ }; serial@12000 { - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; - clock-frequency = <200000000>; - status = "ok"; - }; - - ehci@50000 { status = "okay"; }; - pcie-controller { + ehci@50000 { status = "okay"; - - pcie@1,0 { - status = "okay"; - }; }; }; diff --git a/arch/arm/boot/dts/kirkwood-netgear_readynas_duo_v2.dts b/arch/arm/boot/dts/kirkwood-netgear_readynas_duo_v2.dts index 4838478019ccb9..fd733c63bc27da 100644 --- a/arch/arm/boot/dts/kirkwood-netgear_readynas_duo_v2.dts +++ b/arch/arm/boot/dts/kirkwood-netgear_readynas_duo_v2.dts @@ -25,6 +25,7 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; mbus { @@ -38,7 +39,7 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_button_power: pmx-button-power { marvell,pins = "mpp47"; marvell,function = "gpio"; @@ -112,8 +113,6 @@ }; serial@12000 { - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; status = "okay"; }; diff --git a/arch/arm/boot/dts/kirkwood-netgear_readynas_nv+_v2.dts b/arch/arm/boot/dts/kirkwood-netgear_readynas_nv+_v2.dts index 7c8a0d9d8d1fd0..b514d643fb6c54 100644 --- a/arch/arm/boot/dts/kirkwood-netgear_readynas_nv+_v2.dts +++ b/arch/arm/boot/dts/kirkwood-netgear_readynas_nv+_v2.dts @@ -25,6 +25,7 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; mbus { @@ -40,7 +41,7 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_button_power: pmx-button-power { marvell,pins = "mpp47"; marvell,function = "gpio"; @@ -119,8 +120,6 @@ }; serial@12000 { - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; status = "okay"; }; diff --git a/arch/arm/boot/dts/kirkwood-ns2-common.dtsi b/arch/arm/boot/dts/kirkwood-ns2-common.dtsi index e6e5ec4fe6b9e0..fe6c0246db1ab4 100644 --- a/arch/arm/boot/dts/kirkwood-ns2-common.dtsi +++ b/arch/arm/boot/dts/kirkwood-ns2-common.dtsi @@ -4,10 +4,11 @@ / { chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_ns2_sata0: pmx-ns2-sata0 { marvell,pins = "mpp21"; marvell,function = "sata0"; @@ -19,14 +20,10 @@ }; serial@12000 { - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; status = "okay"; }; spi@10600 { - pinctrl-0 = <&pmx_spi>; - pinctrl-names = "default"; status = "okay"; flash@0 { @@ -45,8 +42,6 @@ }; i2c@11000 { - pinctrl-0 = <&pmx_twsi0>; - pinctrl-names = "default"; status = "okay"; eeprom@50 { diff --git a/arch/arm/boot/dts/kirkwood-nsa310.dts b/arch/arm/boot/dts/kirkwood-nsa310.dts index 0a07af9d8e58d0..6139df0f376c91 100644 --- a/arch/arm/boot/dts/kirkwood-nsa310.dts +++ b/arch/arm/boot/dts/kirkwood-nsa310.dts @@ -1,6 +1,6 @@ /dts-v1/; -#include "kirkwood-nsa310-common.dtsi" +#include "kirkwood-nsa3x0-common.dtsi" / { compatible = "zyxel,nsa310", "marvell,kirkwood-88f6281", "marvell,kirkwood"; @@ -12,6 +12,7 @@ chosen { bootargs = "console=ttyS0,115200"; + stdout-path = &uart0; }; mbus { @@ -25,7 +26,7 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-0 = <&pmx_unknown>; pinctrl-names = "default"; @@ -59,26 +60,6 @@ marvell,function = "gpio"; }; - pmx_btn_reset: pmx-btn-reset { - marvell,pins = "mpp36"; - marvell,function = "gpio"; - }; - - pmx_btn_copy: pmx-btn-copy { - marvell,pins = "mpp37"; - marvell,function = "gpio"; - }; - - pmx_led_copy_green: pmx-led-copy-green { - marvell,pins = "mpp39"; - marvell,function = "gpio"; - }; - - pmx_led_copy_red: pmx-led-copy-red { - marvell,pins = "mpp40"; - marvell,function = "gpio"; - }; - pmx_led_hdd_green: pmx-led-hdd-green { marvell,pins = "mpp41"; marvell,function = "gpio"; @@ -94,10 +75,6 @@ marvell,function = "gpio"; }; - pmx_btn_power: pmx-btn-power { - marvell,pins = "mpp46"; - marvell,function = "gpio"; - }; }; i2c@11000 { @@ -110,30 +87,6 @@ }; }; - gpio_keys { - compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; - pinctrl-0 = <&pmx_btn_reset &pmx_btn_copy &pmx_btn_power>; - pinctrl-names = "default"; - - button@1 { - label = "Power Button"; - linux,code = ; - gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; - }; - button@2 { - label = "Copy Button"; - linux,code = ; - gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; - }; - button@3 { - label = "Reset Button"; - linux,code = ; - gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; - }; - }; - gpio-leds { compatible = "gpio-leds"; pinctrl-0 = <&pmx_led_esata_green &pmx_led_esata_red diff --git a/arch/arm/boot/dts/kirkwood-nsa310a.dts b/arch/arm/boot/dts/kirkwood-nsa310a.dts index 27ca6a79c48a47..3d2b3d494c1913 100644 --- a/arch/arm/boot/dts/kirkwood-nsa310a.dts +++ b/arch/arm/boot/dts/kirkwood-nsa310a.dts @@ -1,6 +1,6 @@ /dts-v1/; -#include "kirkwood-nsa310-common.dtsi" +#include "kirkwood-nsa3x0-common.dtsi" /* * There are at least two different NSA310 designs. This variant does @@ -17,10 +17,11 @@ chosen { bootargs = "console=ttyS0,115200"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-names = "default"; pmx_led_esata_green: pmx-led-esata-green { @@ -38,11 +39,6 @@ marvell,function = "gpio"; }; - pmx_usb_power_off: pmx-usb-power-off { - marvell,pins = "mpp21"; - marvell,function = "gpio"; - }; - pmx_led_sys_green: pmx-led-sys-green { marvell,pins = "mpp28"; marvell,function = "gpio"; @@ -53,26 +49,6 @@ marvell,function = "gpio"; }; - pmx_btn_reset: pmx-btn-reset { - marvell,pins = "mpp36"; - marvell,function = "gpio"; - }; - - pmx_btn_copy: pmx-btn-copy { - marvell,pins = "mpp37"; - marvell,function = "gpio"; - }; - - pmx_led_copy_green: pmx-led-copy-green { - marvell,pins = "mpp39"; - marvell,function = "gpio"; - }; - - pmx_led_copy_red: pmx-led-copy-red { - marvell,pins = "mpp40"; - marvell,function = "gpio"; - }; - pmx_led_hdd_green: pmx-led-hdd-green { marvell,pins = "mpp41"; marvell,function = "gpio"; @@ -83,11 +59,6 @@ marvell,function = "gpio"; }; - pmx_btn_power: pmx-btn-power { - marvell,pins = "mpp46"; - marvell,function = "gpio"; - }; - }; i2c@11000 { @@ -100,28 +71,6 @@ }; }; - gpio_keys { - compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; - - button@1 { - label = "Power Button"; - linux,code = ; - gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; - }; - button@2 { - label = "Copy Button"; - linux,code = ; - gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; - }; - button@3 { - label = "Reset Button"; - linux,code = ; - gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; - }; - }; - gpio-leds { compatible = "gpio-leds"; diff --git a/arch/arm/boot/dts/kirkwood-nsa320.dts b/arch/arm/boot/dts/kirkwood-nsa320.dts new file mode 100644 index 00000000000000..24f686d1044d9a --- /dev/null +++ b/arch/arm/boot/dts/kirkwood-nsa320.dts @@ -0,0 +1,215 @@ +/* Device tree file for the Zyxel NSA 320 NAS box. + * + * Copyright (c) 2014, Adam Baker + * + * 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. + * + * Based upon the board setup file created by Peter Schildmann */ + +/dts-v1/; + +#include "kirkwood-nsa3x0-common.dtsi" + +/ { + model = "Zyxel NSA320"; + compatible = "zyxel,nsa320", "marvell,kirkwood-88f6281", "marvell,kirkwood"; + + memory { + device_type = "memory"; + reg = <0x00000000 0x20000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200"; + stdout-path = &uart0; + }; + + mbus { + pcie-controller { + status = "okay"; + + pcie@1,0 { + status = "okay"; + }; + }; + }; + + ocp@f1000000 { + pinctrl: pin-controller@10000 { + pinctrl-names = "default"; + + /* SATA Activity and Present pins are not connected */ + pmx_sata0: pmx-sata0 { + marvell,pins ; + marvell,function = "sata0"; + }; + + pmx_sata1: pmx-sata1 { + marvell,pins ; + marvell,function = "sata1"; + }; + + pmx_led_hdd2_green: pmx-led-hdd2-green { + marvell,pins = "mpp12"; + marvell,function = "gpio"; + }; + + pmx_led_hdd2_red: pmx-led-hdd2-red { + marvell,pins = "mpp13"; + marvell,function = "gpio"; + }; + + pmx_mcu_data: pmx-mcu-data { + marvell,pins = "mpp14"; + marvell,function = "gpio"; + }; + + pmx_led_usb_green: pmx-led-usb-green { + marvell,pins = "mpp15"; + marvell,function = "gpio"; + }; + + pmx_mcu_clk: pmx-mcu-clk { + marvell,pins = "mpp16"; + marvell,function = "gpio"; + }; + + pmx_mcu_act: pmx-mcu-act { + marvell,pins = "mpp17"; + marvell,function = "gpio"; + }; + + pmx_led_sys_green: pmx-led-sys-green { + marvell,pins = "mpp28"; + marvell,function = "gpio"; + }; + + pmx_led_sys_orange: pmx-led-sys-orange { + marvell,pins = "mpp29"; + marvell,function = "gpio"; + }; + + pmx_led_hdd1_green: pmx-led-hdd1-green { + marvell,pins = "mpp41"; + marvell,function = "gpio"; + }; + + pmx_led_hdd1_red: pmx-led-hdd1-red { + marvell,pins = "mpp42"; + marvell,function = "gpio"; + }; + + pmx_htp: pmx-htp { + marvell,pins = "mpp43"; + marvell,function = "gpio"; + }; + + /* Buzzer needs to be switched at around 1kHz so is + not compatible with the gpio-beeper driver. */ + pmx_buzzer: pmx-buzzer { + marvell,pins = "mpp44"; + marvell,function = "gpio"; + }; + + pmx_vid_b1: pmx-vid-b1 { + marvell,pins = "mpp45"; + marvell,function = "gpio"; + }; + + pmx_power_resume_data: pmx-power-resume-data { + marvell,pins = "mpp47"; + marvell,function = "gpio"; + }; + + pmx_power_resume_clk: pmx-power-resume-clk { + marvell,pins = "mpp49"; + marvell,function = "gpio"; + }; + }; + + i2c@11000 { + status = "okay"; + + pcf8563: pcf8563@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + }; + }; + + regulators { + usb0_power: regulator@1 { + enable-active-high; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + pinctrl-0 = <&pmx_led_hdd2_green &pmx_led_hdd2_red + &pmx_led_usb_green + &pmx_led_sys_green &pmx_led_sys_orange + &pmx_led_copy_green &pmx_led_copy_red + &pmx_led_hdd1_green &pmx_led_hdd1_red>; + pinctrl-names = "default"; + + green-sys { + label = "nsa320:green:sys"; + gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + }; + orange-sys { + label = "nsa320:orange:sys"; + gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>; + }; + green-hdd1 { + label = "nsa320:green:hdd1"; + gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + }; + red-hdd1 { + label = "nsa320:red:hdd1"; + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + }; + green-hdd2 { + label = "nsa320:green:hdd2"; + gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; + }; + red-hdd2 { + label = "nsa320:red:hdd2"; + gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; + }; + green-usb { + label = "nsa320:green:usb"; + gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + }; + green-copy { + label = "nsa320:green:copy"; + gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + }; + red-copy { + label = "nsa320:red:copy"; + gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; + }; + }; + + /* The following pins are currently not assigned to a driver, + some of them should be configured as inputs. + pinctrl-0 = <&pmx_mcu_data &pmx_mcu_clk &pmx_mcu_act + &pmx_htp &pmx_vid_b1 + &pmx_power_resume_data &pmx_power_resume_clk>; */ +}; + +&mdio { + status = "okay"; + ethphy0: ethernet-phy@1 { + reg = <1>; + }; +}; + +ð0 { + status = "okay"; + ethernet0-port@0 { + phy-handle = <ðphy0>; + }; +}; diff --git a/arch/arm/boot/dts/kirkwood-nsa310-common.dtsi b/arch/arm/boot/dts/kirkwood-nsa3x0-common.dtsi similarity index 58% rename from arch/arm/boot/dts/kirkwood-nsa310-common.dtsi rename to arch/arm/boot/dts/kirkwood-nsa3x0-common.dtsi index aa78c2d11fe738..2075a2e828f17b 100644 --- a/arch/arm/boot/dts/kirkwood-nsa310-common.dtsi +++ b/arch/arm/boot/dts/kirkwood-nsa3x0-common.dtsi @@ -4,18 +4,53 @@ / { model = "ZyXEL NSA310"; + mbus { + pcie-controller { + status = "okay"; + + pcie@1,0 { + status = "okay"; + }; + }; + }; + ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { - pmx_usb_power_off: pmx-usb-power-off { + pmx_usb_power: pmx-usb-power { marvell,pins = "mpp21"; marvell,function = "gpio"; }; + pmx_pwr_off: pmx-pwr-off { marvell,pins = "mpp48"; marvell,function = "gpio"; }; + pmx_btn_reset: pmx-btn-reset { + marvell,pins = "mpp36"; + marvell,function = "gpio"; + }; + + pmx_btn_copy: pmx-btn-copy { + marvell,pins = "mpp37"; + marvell,function = "gpio"; + }; + + pmx_btn_power: pmx-btn-power { + marvell,pins = "mpp46"; + marvell,function = "gpio"; + }; + + pmx_led_copy_green: pmx-led-copy-green { + marvell,pins = "mpp39"; + marvell,function = "gpio"; + }; + + pmx_led_copy_red: pmx-led-copy-red { + marvell,pins = "mpp40"; + marvell,function = "gpio"; + }; }; serial@12000 { @@ -26,14 +61,6 @@ status = "okay"; nr-ports = <2>; }; - - pcie-controller { - status = "okay"; - - pcie@1,0 { - status = "okay"; - }; - }; }; gpio_poweroff { @@ -43,17 +70,42 @@ gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>; }; + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&pmx_btn_reset &pmx_btn_copy &pmx_btn_power>; + pinctrl-names = "default"; + + button@1 { + label = "Power Button"; + linux,code = ; + gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; + }; + button@2 { + label = "Copy Button"; + linux,code = ; + gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; + }; + button@3 { + label = "Reset Button"; + linux,code = ; + gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + }; + }; + + regulators { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <0>; - pinctrl-0 = <&pmx_usb_power_off>; + pinctrl-0 = <&pmx_usb_power>; pinctrl-names = "default"; - usb0_power_off: regulator@1 { + usb0_power: regulator@1 { compatible = "regulator-fixed"; reg = <1>; - regulator-name = "USB Power Off"; + regulator-name = "USB Power"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; regulator-always-on; diff --git a/arch/arm/boot/dts/kirkwood-openblocks_a6.dts b/arch/arm/boot/dts/kirkwood-openblocks_a6.dts index 0650beafc1de0a..fb9dc227255d91 100644 --- a/arch/arm/boot/dts/kirkwood-openblocks_a6.dts +++ b/arch/arm/boot/dts/kirkwood-openblocks_a6.dts @@ -14,19 +14,16 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; ocp@f1000000 { serial@12000 { - status = "ok"; - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; + status = "okay"; }; serial@12100 { - status = "ok"; - pinctrl-0 = <&pmx_uart1>; - pinctrl-names = "default"; + status = "okay"; }; sata@80000 { @@ -36,8 +33,6 @@ i2c@11100 { status = "okay"; - pinctrl-0 = <&pmx_twsi1>; - pinctrl-names = "default"; s35390a: s35390a@30 { compatible = "sii,s35390a"; @@ -45,7 +40,7 @@ }; }; - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header>; pinctrl-names = "default"; @@ -133,8 +128,6 @@ &nand { chip-delay = <25>; status = "okay"; - pinctrl-0 = <&pmx_nand>; - pinctrl-names = "default"; partition@0 { label = "uboot"; diff --git a/arch/arm/boot/dts/kirkwood-openblocks_a7.dts b/arch/arm/boot/dts/kirkwood-openblocks_a7.dts index 38520a2875146d..d5e3bc518968b4 100644 --- a/arch/arm/boot/dts/kirkwood-openblocks_a7.dts +++ b/arch/arm/boot/dts/kirkwood-openblocks_a7.dts @@ -26,19 +26,16 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; ocp@f1000000 { serial@12000 { - status = "ok"; - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; + status = "okay"; }; serial@12100 { - status = "ok"; - pinctrl-0 = <&pmx_uart1>; - pinctrl-names = "default"; + status = "okay"; }; sata@80000 { @@ -48,8 +45,6 @@ i2c@11100 { status = "okay"; - pinctrl-0 = <&pmx_twsi1>; - pinctrl-names = "default"; s24c02: s24c02@50 { compatible = "atmel,24c02"; @@ -57,7 +52,7 @@ }; }; - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header>; pinctrl-names = "default"; @@ -109,13 +104,6 @@ marvell,pins = "mpp41", "mpp42", "mpp43"; marvell,function = "gpio"; }; - - pmx_ge1: pmx-ge1 { - marvell,pins = "mpp20", "mpp21", "mpp22", "mpp23", - "mpp24", "mpp25", "mpp26", "mpp27", - "mpp30", "mpp31", "mpp32", "mpp33"; - marvell,function = "ge1"; - }; }; }; @@ -158,8 +146,6 @@ &nand { chip-delay = <25>; status = "okay"; - pinctrl-0 = <&pmx_nand>; - pinctrl-names = "default"; partition@0 { label = "uboot"; @@ -213,8 +199,6 @@ ð1 { status = "okay"; - pinctrl-0 = <&pmx_ge1>; - pinctrl-names = "default"; ethernet1-port@0 { phy-handle = <ðphy1>; }; diff --git a/arch/arm/boot/dts/kirkwood-rd88f6192.dts b/arch/arm/boot/dts/kirkwood-rd88f6192.dts index e9dd850492976c..35a29dee8dd864 100644 --- a/arch/arm/boot/dts/kirkwood-rd88f6192.dts +++ b/arch/arm/boot/dts/kirkwood-rd88f6192.dts @@ -26,6 +26,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; mbus { @@ -39,7 +40,7 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-0 = <&pmx_usb_power>; pinctrl-names = "default"; @@ -56,8 +57,6 @@ spi@10600 { status = "okay"; - pinctrl-0 = <&pmx_spi>; - pinctrl-names = "default"; m25p128@0 { #address-cells = <1>; diff --git a/arch/arm/boot/dts/kirkwood-rd88f6281.dtsi b/arch/arm/boot/dts/kirkwood-rd88f6281.dtsi index d6368c39102e74..26cf0e0ccefd37 100644 --- a/arch/arm/boot/dts/kirkwood-rd88f6281.dtsi +++ b/arch/arm/boot/dts/kirkwood-rd88f6281.dtsi @@ -22,6 +22,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; mbus { @@ -35,7 +36,7 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-0 = <&pmx_sdio_cd>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/kirkwood-rs212.dts b/arch/arm/boot/dts/kirkwood-rs212.dts index 93ec3d00c6ab90..3b19f1fd4caca9 100644 --- a/arch/arm/boot/dts/kirkwood-rs212.dts +++ b/arch/arm/boot/dts/kirkwood-rs212.dts @@ -24,6 +24,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-100-15-35-3 { diff --git a/arch/arm/boot/dts/kirkwood-rs409.dts b/arch/arm/boot/dts/kirkwood-rs409.dts index 311df4e5aa285e..921ca49e85a4da 100644 --- a/arch/arm/boot/dts/kirkwood-rs409.dts +++ b/arch/arm/boot/dts/kirkwood-rs409.dts @@ -24,6 +24,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-150-15-18 { diff --git a/arch/arm/boot/dts/kirkwood-rs411.dts b/arch/arm/boot/dts/kirkwood-rs411.dts index f90da850bb31bc..02852b0c809f00 100644 --- a/arch/arm/boot/dts/kirkwood-rs411.dts +++ b/arch/arm/boot/dts/kirkwood-rs411.dts @@ -24,6 +24,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; gpio-fan-100-15-35-3 { diff --git a/arch/arm/boot/dts/kirkwood-sheevaplug-common.dtsi b/arch/arm/boot/dts/kirkwood-sheevaplug-common.dtsi index 1ff848d570a9a0..7196c7f3e1096f 100644 --- a/arch/arm/boot/dts/kirkwood-sheevaplug-common.dtsi +++ b/arch/arm/boot/dts/kirkwood-sheevaplug-common.dtsi @@ -17,10 +17,11 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_usb_power_enable: pmx-usb-power-enable { marvell,pins = "mpp29"; @@ -44,8 +45,6 @@ }; }; serial@12000 { - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; status = "okay"; }; }; @@ -72,8 +71,6 @@ }; &nand { - pinctrl-0 = <&pmx_nand>; - pinctrl-names = "default"; status = "okay"; partition@0 { diff --git a/arch/arm/boot/dts/kirkwood-synology.dtsi b/arch/arm/boot/dts/kirkwood-synology.dtsi index 4227c974729d00..811e0971fc588a 100644 --- a/arch/arm/boot/dts/kirkwood-synology.dtsi +++ b/arch/arm/boot/dts/kirkwood-synology.dtsi @@ -25,7 +25,7 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pmx_alarmled_12: pmx-alarmled-12 { marvell,pins = "mpp12"; marvell,function = "gpio"; @@ -213,8 +213,6 @@ spi@10600 { status = "okay"; - pinctrl-0 = <&pmx_spi>; - pinctrl-names = "default"; m25p80@0 { #address-cells = <1>; @@ -259,8 +257,6 @@ i2c@11000 { status = "okay"; clock-frequency = <400000>; - pinctrl-0 = <&pmx_twsi0>; - pinctrl-names = "default"; rs5c372: rs5c372@32 { status = "disabled"; @@ -277,14 +273,10 @@ serial@12000 { status = "okay"; - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; }; serial@12100 { status = "okay"; - pinctrl-0 = <&pmx_uart1>; - pinctrl-names = "default"; }; poweroff@12100 { diff --git a/arch/arm/boot/dts/kirkwood-t5325.dts b/arch/arm/boot/dts/kirkwood-t5325.dts index 7d1c7677a18f18..610ec0f95858b4 100644 --- a/arch/arm/boot/dts/kirkwood-t5325.dts +++ b/arch/arm/boot/dts/kirkwood-t5325.dts @@ -27,6 +27,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; mbus { @@ -40,7 +41,7 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-0 = <&pmx_i2s &pmx_sysrst>; pinctrl-names = "default"; @@ -64,10 +65,6 @@ marvell,function = "gpio"; }; - /* - * Redefined from kirkwood-6281.dtsi, because - * we don't use SPI CS on MPP0, but on MPP7. - */ pmx_spi: pmx-spi { marvell,pins = "mpp1", "mpp2", "mpp3", "mpp7"; marvell,function = "spi"; @@ -86,8 +83,6 @@ }; spi@10600 { - pinctrl-0 = <&pmx_spi>; - pinctrl-names = "default"; status = "okay"; flash@0 { @@ -131,6 +126,9 @@ alc5621: alc5621@1a { compatible = "realtek,alc5621"; reg = <0x1a>; + #sound-dai-cells = <0>; + add-ctrl = <0x3700>; + jack-det-ctrl = <0x4810>; }; }; @@ -189,6 +187,31 @@ gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>; }; + sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,routing = + "Headphone Jack", "HPL", + "Headphone Jack", "HPR", + "Speaker", "SPKOUT", + "Speaker", "SPKOUTN", + "MIC1", "Mic Jack", + "MIC2", "Mic Jack"; + simple-audio-card,widgets = + "Headphone", "Headphone Jack", + "Speaker", "Speaker", + "Microphone", "Mic Jack"; + + simple-audio-card,mclk-fs = <256>; + + simple-audio-card,cpu { + sound-dai = <&audio>; + }; + + simple-audio-card,codec { + sound-dai = <&alc5621>; + }; + }; }; &mdio { diff --git a/arch/arm/boot/dts/kirkwood-topkick.dts b/arch/arm/boot/dts/kirkwood-topkick.dts index 5fc817c2cb8737..f5c8c0dd41dc82 100644 --- a/arch/arm/boot/dts/kirkwood-topkick.dts +++ b/arch/arm/boot/dts/kirkwood-topkick.dts @@ -14,10 +14,11 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { /* * Switch positions * @@ -85,9 +86,7 @@ }; serial@12000 { - status = "ok"; - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; + status = "okay"; }; sata@80000 { @@ -96,9 +95,7 @@ }; i2c@11000 { - status = "ok"; - pinctrl-0 = <&pmx_twsi0>; - pinctrl-names = "default"; + status = "okay"; }; mvsdio@90000 { @@ -175,8 +172,6 @@ &nand { status = "okay"; - pinctrl-0 = <&pmx_nand>; - pinctrl-names = "default"; partition@0 { label = "u-boot"; diff --git a/arch/arm/boot/dts/kirkwood-ts219-6281.dts b/arch/arm/boot/dts/kirkwood-ts219-6281.dts index c17ae45e19be3f..9767d73f3857f9 100644 --- a/arch/arm/boot/dts/kirkwood-ts219-6281.dts +++ b/arch/arm/boot/dts/kirkwood-ts219-6281.dts @@ -6,7 +6,7 @@ / { ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-0 = <&pmx_ram_size &pmx_board_id>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/kirkwood-ts219-6282.dts b/arch/arm/boot/dts/kirkwood-ts219-6282.dts index 0713d072758a1e..bfc1a32d4e422d 100644 --- a/arch/arm/boot/dts/kirkwood-ts219-6282.dts +++ b/arch/arm/boot/dts/kirkwood-ts219-6282.dts @@ -16,7 +16,7 @@ }; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-0 = <&pmx_ram_size &pmx_board_id>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/kirkwood-ts219.dtsi b/arch/arm/boot/dts/kirkwood-ts219.dtsi index 911f3a8cee23ec..df7f15276575ad 100644 --- a/arch/arm/boot/dts/kirkwood-ts219.dtsi +++ b/arch/arm/boot/dts/kirkwood-ts219.dtsi @@ -9,6 +9,7 @@ chosen { bootargs = "console=ttyS0,115200n8"; + stdout-path = &uart0; }; mbus { @@ -25,8 +26,6 @@ i2c@11000 { status = "okay"; clock-frequency = <400000>; - pinctrl-0 = <&pmx_twsi0>; - pinctrl-names = "default"; s35390a: s35390a@30 { compatible = "s35390a"; @@ -34,16 +33,10 @@ }; }; serial@12000 { - clock-frequency = <200000000>; status = "okay"; - pinctrl-0 = <&pmx_uart0>; - pinctrl-names = "default"; }; serial@12100 { - clock-frequency = <200000000>; status = "okay"; - pinctrl-0 = <&pmx_uart1>; - pinctrl-names = "default"; }; poweroff@12100 { compatible = "qnap,power-off"; @@ -52,8 +45,6 @@ }; spi@10600 { status = "okay"; - pinctrl-0 = <&pmx_spi>; - pinctrl-names = "default"; m25p128@0 { #address-cells = <1>; diff --git a/arch/arm/boot/dts/kirkwood-ts419.dtsi b/arch/arm/boot/dts/kirkwood-ts419.dtsi index 1a9c624c7a928f..30ab93bfb1e476 100644 --- a/arch/arm/boot/dts/kirkwood-ts419.dtsi +++ b/arch/arm/boot/dts/kirkwood-ts419.dtsi @@ -14,7 +14,7 @@ compatible = "qnap,ts419", "marvell,kirkwood"; ocp@f1000000 { - pinctrl: pinctrl@10000 { + pinctrl: pin-controller@10000 { pinctrl-names = "default"; pmx_USB_copy_button: pmx-USB-copy-button { diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi index 90384587c27843..afc640cd80c5f6 100644 --- a/arch/arm/boot/dts/kirkwood.dtsi +++ b/arch/arm/boot/dts/kirkwood.dtsi @@ -40,7 +40,7 @@ pcie-mem-aperture = <0xe0000000 0x10000000>; /* 256 MiB memory space */ pcie-io-aperture = <0xf2000000 0x100000>; /* 1 MiB I/O space */ - crypto@0301 { + cesa: crypto@0301 { compatible = "marvell,orion-crypto"; reg = , ; @@ -61,6 +61,8 @@ chip-delay = <25>; /* set partition map and/or chip-delay in board dts */ clocks = <&gate_clk 7>; + pinctrl-0 = <&pmx_nand>; + pinctrl-names = "default"; status = "disabled"; }; }; @@ -71,13 +73,59 @@ #address-cells = <1>; #size-cells = <1>; + pinctrl: pin-controller@10000 { + /* set compatible property in SoC file */ + reg = <0x10000 0x20>; + + pmx_ge1: pmx-ge1 { + marvell,pins = "mpp20", "mpp21", "mpp22", "mpp23", + "mpp24", "mpp25", "mpp26", "mpp27", + "mpp30", "mpp31", "mpp32", "mpp33"; + marvell,function = "ge1"; + }; + + pmx_nand: pmx-nand { + marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3", + "mpp4", "mpp5", "mpp18", "mpp19"; + marvell,function = "nand"; + }; + + /* + * Default SPI0 pinctrl setting with CSn on mpp0, + * overwrite marvell,pins on board level if required. + */ + pmx_spi: pmx-spi { + marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3"; + marvell,function = "spi"; + }; + + pmx_twsi0: pmx-twsi0 { + marvell,pins = "mpp8", "mpp9"; + marvell,function = "twsi0"; + }; + + /* + * Default UART pinctrl setting without RTS/CTS, + * overwrite marvell,pins on board level if required. + */ + pmx_uart0: pmx-uart0 { + marvell,pins = "mpp10", "mpp11"; + marvell,function = "uart0"; + }; + + pmx_uart1: pmx-uart1 { + marvell,pins = "mpp13", "mpp14"; + marvell,function = "uart1"; + }; + }; + core_clk: core-clocks@10030 { compatible = "marvell,kirkwood-core-clock"; reg = <0x10030 0x4>; #clock-cells = <1>; }; - spi@10600 { + spi0: spi@10600 { compatible = "marvell,orion-spi"; #address-cells = <1>; #size-cells = <0>; @@ -85,6 +133,8 @@ interrupts = <23>; reg = <0x10600 0x28>; clocks = <&gate_clk 7>; + pinctrl-0 = <&pmx_spi>; + pinctrl-names = "default"; status = "disabled"; }; @@ -120,24 +170,30 @@ interrupts = <29>; clock-frequency = <100000>; clocks = <&gate_clk 7>; + pinctrl-0 = <&pmx_twsi0>; + pinctrl-names = "default"; status = "disabled"; }; - serial@12000 { + uart0: serial@12000 { compatible = "ns16550a"; reg = <0x12000 0x100>; reg-shift = <2>; interrupts = <33>; clocks = <&gate_clk 7>; + pinctrl-0 = <&pmx_uart0>; + pinctrl-names = "default"; status = "disabled"; }; - serial@12100 { + uart1: serial@12100 { compatible = "ns16550a"; reg = <0x12100 0x100>; reg-shift = <2>; interrupts = <34>; clocks = <&gate_clk 7>; + pinctrl-0 = <&pmx_uart1>; + pinctrl-names = "default"; status = "disabled"; }; @@ -146,7 +202,7 @@ reg = <0x20000 0x80>, <0x1500 0x20>; }; - system-controller@20000 { + sysc: system-controller@20000 { compatible = "marvell,orion-system-controller"; reg = <0x20000 0x120>; }; @@ -196,7 +252,7 @@ status = "okay"; }; - ehci@50000 { + usb0: ehci@50000 { compatible = "marvell,orion-ehci"; reg = <0x50000 0x1000>; interrupts = <19>; @@ -204,7 +260,7 @@ status = "okay"; }; - xor@60800 { + dma0: xor@60800 { compatible = "marvell,orion-xor"; reg = <0x60800 0x100 0x60A00 0x100>; @@ -224,7 +280,7 @@ }; }; - xor@60900 { + dma1: xor@60900 { compatible = "marvell,orion-xor"; reg = <0x60900 0x100 0x60B00 0x100>; @@ -282,6 +338,8 @@ reg = <0x76000 0x4000>; clocks = <&gate_clk 19>; marvell,tx-checksum-limit = <1600>; + pinctrl-0 = <&pmx_ge1>; + pinctrl-names = "default"; status = "disabled"; ethernet1-port@0 { @@ -314,6 +372,7 @@ audio0: audio-controller@a0000 { compatible = "marvell,kirkwood-audio"; + #sound-dai-cells = <0>; reg = <0xa0000 0x2210>; interrupts = <24>; clocks = <&gate_clk 9>; diff --git a/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi b/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi index f577b7df9a29e4..521c587acaee9f 100644 --- a/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi +++ b/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi @@ -24,11 +24,10 @@ compatible = "smsc,lan9221", "smsc,lan9115"; bank-width = <2>; gpmc,mux-add-data; - gpmc,cs-on-ns = <0>; - gpmc,cs-rd-off-ns = <186>; - gpmc,cs-wr-off-ns = <186>; - gpmc,adv-on-ns = <12>; - gpmc,adv-rd-off-ns = <48>; + gpmc,cs-on-ns = <1>; + gpmc,cs-rd-off-ns = <180>; + gpmc,cs-wr-off-ns = <180>; + gpmc,adv-rd-off-ns = <18>; gpmc,adv-wr-off-ns = <48>; gpmc,oe-on-ns = <54>; gpmc,oe-off-ns = <168>; @@ -36,12 +35,10 @@ gpmc,we-off-ns = <168>; gpmc,rd-cycle-ns = <186>; gpmc,wr-cycle-ns = <186>; - gpmc,access-ns = <114>; - gpmc,page-burst-access-ns = <6>; - gpmc,bus-turnaround-ns = <12>; - gpmc,cycle2cycle-delay-ns = <18>; - gpmc,wr-data-mux-bus-ns = <90>; - gpmc,wr-access-ns = <186>; + gpmc,access-ns = <144>; + gpmc,page-burst-access-ns = <24>; + gpmc,bus-turnaround-ns = <90>; + gpmc,cycle2cycle-delay-ns = <90>; gpmc,cycle2cycle-samecsen; gpmc,cycle2cycle-diffcsen; vddvario-supply = <&vddvario>; diff --git a/arch/arm/boot/dts/omap2.dtsi b/arch/arm/boot/dts/omap2.dtsi index 22f35ea142c199..8f8c07da4ac148 100644 --- a/arch/arm/boot/dts/omap2.dtsi +++ b/arch/arm/boot/dts/omap2.dtsi @@ -71,13 +71,6 @@ interrupts = <58>; }; - mailbox: mailbox@48094000 { - compatible = "ti,omap2-mailbox"; - ti,hwmods = "mailbox"; - reg = <0x48094000 0x200>; - interrupts = <26>; - }; - intc: interrupt-controller@1 { compatible = "ti,omap2-intc"; interrupt-controller; diff --git a/arch/arm/boot/dts/omap2420.dtsi b/arch/arm/boot/dts/omap2420.dtsi index 85b1fb014c4314..2d9979835f241f 100644 --- a/arch/arm/boot/dts/omap2420.dtsi +++ b/arch/arm/boot/dts/omap2420.dtsi @@ -125,6 +125,14 @@ dma-names = "tx", "rx"; }; + mailbox: mailbox@48094000 { + compatible = "ti,omap2-mailbox"; + reg = <0x48094000 0x200>; + interrupts = <26>, <34>; + interrupt-names = "dsp", "iva"; + ti,hwmods = "mailbox"; + }; + timer1: timer@48028000 { compatible = "ti,omap2420-timer"; reg = <0x48028000 0x400>; diff --git a/arch/arm/boot/dts/omap2430.dtsi b/arch/arm/boot/dts/omap2430.dtsi index d09697dab55e80..42d2c61c9e2d7d 100644 --- a/arch/arm/boot/dts/omap2430.dtsi +++ b/arch/arm/boot/dts/omap2430.dtsi @@ -216,6 +216,13 @@ dma-names = "tx", "rx"; }; + mailbox: mailbox@48094000 { + compatible = "ti,omap2-mailbox"; + reg = <0x48094000 0x200>; + interrupts = <26>; + ti,hwmods = "mailbox"; + }; + timer1: timer@49018000 { compatible = "ti,omap2420-timer"; reg = <0x49018000 0x400>; diff --git a/arch/arm/boot/dts/omap3-cm-t3x30.dtsi b/arch/arm/boot/dts/omap3-cm-t3x30.dtsi index d00055809e31d7..25ba08331d8852 100644 --- a/arch/arm/boot/dts/omap3-cm-t3x30.dtsi +++ b/arch/arm/boot/dts/omap3-cm-t3x30.dtsi @@ -10,18 +10,6 @@ cpu0-supply = <&vcc>; }; }; - - vddvario: regulator-vddvario { - compatible = "regulator-fixed"; - regulator-name = "vddvario"; - regulator-always-on; - }; - - vdd33a: regulator-vdd33a { - compatible = "regulator-fixed"; - regulator-name = "vdd33a"; - regulator-always-on; - }; }; &omap3_pmx_core { @@ -35,58 +23,34 @@ hsusb0_pins: pinmux_hsusb0_pins { pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* hsusb0_clk.hsusb0_clk */ - OMAP3_CORE1_IOPAD(0x21a2, PIN_OUTPUT | MUX_MODE0) /* hsusb0_stp.hsusb0_stp */ - OMAP3_CORE1_IOPAD(0x21a4, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_dir.hsusb0_dir */ - OMAP3_CORE1_IOPAD(0x21a6, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_nxt.hsusb0_nxt */ - OMAP3_CORE1_IOPAD(0x21a8, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data0.hsusb2_data0 */ - OMAP3_CORE1_IOPAD(0x21aa, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data1.hsusb0_data1 */ - OMAP3_CORE1_IOPAD(0x21ac, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data2.hsusb0_data2 */ - OMAP3_CORE1_IOPAD(0x21ae, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data7.hsusb0_data3 */ - OMAP3_CORE1_IOPAD(0x21b0, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data7.hsusb0_data4 */ - OMAP3_CORE1_IOPAD(0x21b2, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data7.hsusb0_data5 */ - OMAP3_CORE1_IOPAD(0x21b4, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data7.hsusb0_data6 */ - OMAP3_CORE1_IOPAD(0x21b6, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data7.hsusb0_data7 */ + OMAP3_CORE1_IOPAD(0x21a2, PIN_OUTPUT | MUX_MODE0) /* hsusb0_clk.hsusb0_clk */ + OMAP3_CORE1_IOPAD(0x21a4, PIN_OUTPUT | MUX_MODE0) /* hsusb0_stp.hsusb0_stp */ + OMAP3_CORE1_IOPAD(0x21a6, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_dir.hsusb0_dir */ + OMAP3_CORE1_IOPAD(0x21a8, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_nxt.hsusb0_nxt */ + OMAP3_CORE1_IOPAD(0x21aa, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data0.hsusb2_data0 */ + OMAP3_CORE1_IOPAD(0x21ac, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data1.hsusb0_data1 */ + OMAP3_CORE1_IOPAD(0x21ae, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data2.hsusb0_data2 */ + OMAP3_CORE1_IOPAD(0x21b0, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data7.hsusb0_data3 */ + OMAP3_CORE1_IOPAD(0x21b2, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data7.hsusb0_data4 */ + OMAP3_CORE1_IOPAD(0x21b4, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data7.hsusb0_data5 */ + OMAP3_CORE1_IOPAD(0x21b6, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data7.hsusb0_data6 */ + OMAP3_CORE1_IOPAD(0x21b8, PIN_INPUT_PULLDOWN | MUX_MODE0) /* hsusb0_data7.hsusb0_data7 */ >; }; }; +#include "omap-gpmc-smsc911x.dtsi" + &gpmc { ranges = <5 0 0x2c000000 0x01000000>; - smsc1: ethernet@5,0 { + smsc1: ethernet@gpmc { compatible = "smsc,lan9221", "smsc,lan9115"; pinctrl-names = "default"; pinctrl-0 = <&smsc1_pins>; interrupt-parent = <&gpio6>; interrupts = <3 IRQ_TYPE_LEVEL_LOW>; reg = <5 0 0xff>; - bank-width = <2>; - gpmc,mux-add-data; - gpmc,cs-on-ns = <0>; - gpmc,cs-rd-off-ns = <186>; - gpmc,cs-wr-off-ns = <186>; - gpmc,adv-on-ns = <12>; - gpmc,adv-rd-off-ns = <48>; - gpmc,adv-wr-off-ns = <48>; - gpmc,oe-on-ns = <54>; - gpmc,oe-off-ns = <168>; - gpmc,we-on-ns = <54>; - gpmc,we-off-ns = <168>; - gpmc,rd-cycle-ns = <186>; - gpmc,wr-cycle-ns = <186>; - gpmc,access-ns = <114>; - gpmc,page-burst-access-ns = <6>; - gpmc,bus-turnaround-ns = <12>; - gpmc,cycle2cycle-delay-ns = <18>; - gpmc,wr-data-mux-bus-ns = <90>; - gpmc,wr-access-ns = <186>; - gpmc,cycle2cycle-samecsen; - gpmc,cycle2cycle-diffcsen; - vddvario-supply = <&vddvario>; - vdd33a-supply = <&vdd33a>; - reg-io-width = <4>; - smsc,save-mac-address; }; }; diff --git a/arch/arm/boot/dts/omap3-igep.dtsi b/arch/arm/boot/dts/omap3-igep.dtsi index b97736d98a6427..e2d163bf061975 100644 --- a/arch/arm/boot/dts/omap3-igep.dtsi +++ b/arch/arm/boot/dts/omap3-igep.dtsi @@ -107,7 +107,7 @@ >; }; - smsc911x_pins: pinmux_smsc911x_pins { + smsc9221_pins: pinmux_smsc9221_pins { pinctrl-single,pins = < 0x1a2 (PIN_INPUT | MUX_MODE4) /* mcspi1_cs2.gpio_176 */ >; diff --git a/arch/arm/boot/dts/omap3-igep0020.dts b/arch/arm/boot/dts/omap3-igep0020.dts index 7abd64f6ae2146..b22caaaf774ba7 100644 --- a/arch/arm/boot/dts/omap3-igep0020.dts +++ b/arch/arm/boot/dts/omap3-igep0020.dts @@ -10,7 +10,7 @@ */ #include "omap3-igep.dtsi" -#include "omap-gpmc-smsc911x.dtsi" +#include "omap-gpmc-smsc9221.dtsi" / { model = "IGEPv2 (TI OMAP AM/DM37x)"; @@ -248,7 +248,7 @@ ethernet@gpmc { pinctrl-names = "default"; - pinctrl-0 = <&smsc911x_pins>; + pinctrl-0 = <&smsc9221_pins>; reg = <5 0 0xff>; interrupt-parent = <&gpio6>; interrupts = <16 IRQ_TYPE_LEVEL_LOW>; diff --git a/arch/arm/boot/dts/omap3-sb-t35.dtsi b/arch/arm/boot/dts/omap3-sb-t35.dtsi index 7909c51b05a564..d59e3de1441e2f 100644 --- a/arch/arm/boot/dts/omap3-sb-t35.dtsi +++ b/arch/arm/boot/dts/omap3-sb-t35.dtsi @@ -2,20 +2,6 @@ * Common support for CompuLab SB-T35 used on SBC-T3530, SBC-T3517 and SBC-T3730 */ -/ { - vddvario_sb_t35: regulator-vddvario-sb-t35 { - compatible = "regulator-fixed"; - regulator-name = "vddvario"; - regulator-always-on; - }; - - vdd33a_sb_t35: regulator-vdd33a-sb-t35 { - compatible = "regulator-fixed"; - regulator-name = "vdd33a"; - regulator-always-on; - }; -}; - &omap3_pmx_core { smsc2_pins: pinmux_smsc2_pins { pinctrl-single,pins = < @@ -37,11 +23,10 @@ reg = <4 0 0xff>; bank-width = <2>; gpmc,mux-add-data; - gpmc,cs-on-ns = <0>; - gpmc,cs-rd-off-ns = <186>; - gpmc,cs-wr-off-ns = <186>; - gpmc,adv-on-ns = <12>; - gpmc,adv-rd-off-ns = <48>; + gpmc,cs-on-ns = <1>; + gpmc,cs-rd-off-ns = <180>; + gpmc,cs-wr-off-ns = <180>; + gpmc,adv-rd-off-ns = <18>; gpmc,adv-wr-off-ns = <48>; gpmc,oe-on-ns = <54>; gpmc,oe-off-ns = <168>; @@ -49,16 +34,14 @@ gpmc,we-off-ns = <168>; gpmc,rd-cycle-ns = <186>; gpmc,wr-cycle-ns = <186>; - gpmc,access-ns = <114>; - gpmc,page-burst-access-ns = <6>; - gpmc,bus-turnaround-ns = <12>; - gpmc,cycle2cycle-delay-ns = <18>; - gpmc,wr-data-mux-bus-ns = <90>; - gpmc,wr-access-ns = <186>; + gpmc,access-ns = <144>; + gpmc,page-burst-access-ns = <24>; + gpmc,bus-turnaround-ns = <90>; + gpmc,cycle2cycle-delay-ns = <90>; gpmc,cycle2cycle-samecsen; gpmc,cycle2cycle-diffcsen; - vddvario-supply = <&vddvario_sb_t35>; - vdd33a-supply = <&vdd33a_sb_t35>; + vddvario-supply = <&vddvario>; + vdd33a-supply = <&vdd33a>; reg-io-width = <4>; smsc,save-mac-address; }; diff --git a/arch/arm/boot/dts/omap3-sbc-t3517.dts b/arch/arm/boot/dts/omap3-sbc-t3517.dts index 024c9c6c682d7e..42189b65d393d2 100644 --- a/arch/arm/boot/dts/omap3-sbc-t3517.dts +++ b/arch/arm/boot/dts/omap3-sbc-t3517.dts @@ -8,6 +8,19 @@ / { model = "CompuLab SBC-T3517 with CM-T3517"; compatible = "compulab,omap3-sbc-t3517", "compulab,omap3-cm-t3517", "ti,am3517", "ti,omap3"; + + /* Only one GPMC smsc9220 on SBC-T3517, CM-T3517 uses am35x Ethernet */ + vddvario: regulator-vddvario-sb-t35 { + compatible = "regulator-fixed"; + regulator-name = "vddvario"; + regulator-always-on; + }; + + vdd33a: regulator-vdd33a-sb-t35 { + compatible = "regulator-fixed"; + regulator-name = "vdd33a"; + regulator-always-on; + }; }; &omap3_pmx_core { diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index acb9019dc437b6..4231191ade06ac 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -61,7 +61,7 @@ ti,hwmods = "mpu"; }; - iva { + iva: iva { compatible = "ti,iva2.2"; ti,hwmods = "iva"; diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index f8c9855ce587c1..36b4312a5e0d82 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -630,6 +630,13 @@ status = "disabled"; }; + mailbox: mailbox@4a0f4000 { + compatible = "ti,omap4-mailbox"; + reg = <0x4a0f4000 0x200>; + interrupts = ; + ti,hwmods = "mailbox"; + }; + timer1: timer@4ae18000 { compatible = "ti,omap5430-timer"; reg = <0x4ae18000 0x80>; diff --git a/arch/arm/boot/dts/orion5x-lacie-d2-network.dts b/arch/arm/boot/dts/orion5x-lacie-d2-network.dts new file mode 100644 index 00000000000000..c701e8d16bbb6d --- /dev/null +++ b/arch/arm/boot/dts/orion5x-lacie-d2-network.dts @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2014 Thomas Petazzoni + * Copyright (C) 2009 Simon Guinot + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/dts-v1/; + +#include +#include +#include +#include "orion5x-mv88f5182.dtsi" + +/ { + model = "LaCie d2 Network"; + compatible = "lacie,d2-network", "marvell,orion5x-88f5182", "marvell,orion5x"; + + memory { + reg = <0x00000000 0x4000000>; /* 64 MB */ + }; + + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk"; + linux,stdout-path = &uart0; + }; + + soc { + ranges = , + , + ; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-0 = <&pmx_buttons>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + front_button { + label = "Front Push Button"; + linux,code = ; + gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>; + }; + + power_rocker_sw_on { + label = "Power rocker switch (on|auto)"; + linux,input-type = <5>; /* EV_SW */ + linux,code = <1>; /* D2NET_SWITCH_POWER_ON */ + gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; + }; + + power_rocker_sw_off { + label = "Power rocker switch (auto|off)"; + linux,input-type = <5>; /* EV_SW */ + linux,code = <2>; /* D2NET_SWITCH_POWER_OFF */ + gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; + }; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&pmx_sata0_power &pmx_sata1_power>; + pinctrl-names = "default"; + + sata0_power: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "SATA0 Power"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + regulator-boot-on; + gpio = <&gpio0 3 GPIO_ACTIVE_HIGH>; + }; + + sata1_power: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "SATA1 Power"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + regulator-always-on; + regulator-boot-on; + gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&devbus_bootcs { + status = "okay"; + + devbus,keep-config; + + /* + * Currently the MTD code does not recognize the MX29LV400CBCT + * as a bottom-type device. This could cause risks of + * accidentally erasing critical flash sectors. We thus define + * a single, write-protected partition covering the whole + * flash. TODO: once the flash part TOP/BOTTOM detection + * issue is sorted out in the MTD code, break this into at + * least three partitions: 'u-boot code', 'u-boot environment' + * and 'whatever is left'. + */ + flash@0 { + compatible = "cfi-flash"; + reg = <0 0x80000>; + bank-width = <1>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "Full512Kb"; + reg = <0 0x80000>; + read-only; + }; + }; +}; + +&mdio { + status = "okay"; + + ethphy: ethernet-phy { + reg = <8>; + }; +}; + +&ehci0 { + status = "okay"; +}; + +ð { + status = "okay"; + + ethernet-port@0 { + phy-handle = <ðphy>; + }; +}; + +&i2c { + status = "okay"; + clock-frequency = <100000>; + #address-cells = <1>; + + rtc@32 { + compatible = "ricoh,rs5c372b"; + reg = <0x32>; + }; + + fan@3e { + compatible = "gmt,g762"; + reg = <0x3e>; + + /* Not enough HW info */ + status = "disabled"; + }; + + eeprom@50 { + compatible = "atmel,24c08"; + reg = <0x50>; + }; +}; + +&pinctrl { + pinctrl-0 = <&pmx_leds &pmx_board_id &pmx_fan_fail>; + pinctrl-names = "default"; + + pmx_board_id: pmx-board-id { + marvell,pins = "mpp0", "mpp1", "mpp2"; + marvell,function = "gpio"; + }; + + pmx_buttons: pmx-buttons { + marvell,pins = "mpp8", "mpp9", "mpp18"; + marvell,function = "gpio"; + }; + + pmx_fan_fail: pmx-fan-fail { + marvell,pins = "mpp5"; + marvell,function = "gpio"; + }; + + /* + * MPP6: Red front LED + * MPP16: Blue front LED blink control + */ + pmx_leds: pmx-leds { + marvell,pins = "mpp6", "mpp16"; + marvell,function = "gpio"; + }; + + pmx_sata0_led_active: pmx-sata0-led-active { + marvell,pins = "mpp14"; + marvell,function = "sata0"; + }; + + pmx_sata0_power: pmx-sata0-power { + marvell,pins = "mpp3"; + marvell,function = "gpio"; + }; + + pmx_sata1_led_active: pmx-sata1-led-active { + marvell,pins = "mpp15"; + marvell,function = "sata1"; + }; + + pmx_sata1_power: pmx-sata1-power { + marvell,pins = "mpp12"; + marvell,function = "gpio"; + }; + + /* + * Non MPP GPIOs: + * GPIO 22: USB port 1 fuse (0 = Fail, 1 = Ok) + * GPIO 23: Blue front LED off + * GPIO 24: Inhibit board power off (0 = Disabled, 1 = Enabled) + */ +}; + +&sata { + pinctrl-0 = <&pmx_sata0_led_active + &pmx_sata1_led_active>; + pinctrl-names = "default"; + status = "okay"; + nr-ports = <2>; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/orion5x-lacie-ethernet-disk-mini-v2.dts b/arch/arm/boot/dts/orion5x-lacie-ethernet-disk-mini-v2.dts index 5ed6c137690183..89ff404a528c74 100644 --- a/arch/arm/boot/dts/orion5x-lacie-ethernet-disk-mini-v2.dts +++ b/arch/arm/boot/dts/orion5x-lacie-ethernet-disk-mini-v2.dts @@ -6,8 +6,19 @@ * warranty of any kind, whether express or implied. */ +/* + * TODO: add Orion USB device port init when kernel.org support is added. + * TODO: add flash write support: see below. + * TODO: add power-off support. + * TODO: add I2C EEPROM support. + */ + /dts-v1/; -/include/ "orion5x.dtsi" + +#include +#include +#include +#include "orion5x-mv88f5182.dtsi" / { model = "LaCie Ethernet Disk mini V2"; @@ -19,49 +30,84 @@ chosen { bootargs = "console=ttyS0,115200n8 earlyprintk"; + linux,stdout-path = &uart0; }; - ocp@f1000000 { - serial@12000 { - clock-frequency = <166666667>; - status = "okay"; - }; - - sata@80000 { - status = "okay"; - nr-ports = <2>; - }; + soc { + ranges = , + , + ; }; - gpio_keys { + gpio-keys { compatible = "gpio-keys"; + pinctrl-0 = <&pmx_power_button>; + pinctrl-names = "default"; #address-cells = <1>; #size-cells = <0>; button@1 { label = "Power-on Switch"; - linux,code = <116>; /* KEY_POWER */ - gpios = <&gpio0 18 0>; + linux,code = ; + gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>; }; }; - gpio_leds { + gpio-leds { compatible = "gpio-leds"; + pinctrl-0 = <&pmx_power_led>; + pinctrl-names = "default"; led@1 { label = "power:blue"; - gpios = <&gpio0 16 1>; + gpios = <&gpio0 16 GPIO_ACTIVE_LOW>; }; }; }; -&mdio { +&devbus_bootcs { status = "okay"; - ethphy: ethernet-phy { - reg = <8>; + /* Read parameters */ + devbus,bus-width = <8>; + devbus,turn-off-ps = <90000>; + devbus,badr-skew-ps = <0>; + devbus,acc-first-ps = <186000>; + devbus,acc-next-ps = <186000>; + + /* Write parameters */ + devbus,wr-high-ps = <90000>; + devbus,wr-low-ps = <90000>; + devbus,ale-wr-ps = <90000>; + + /* + * Currently the MTD code does not recognize the MX29LV400CBCT + * as a bottom-type device. This could cause risks of + * accidentally erasing critical flash sectors. We thus define + * a single, write-protected partition covering the whole + * flash. TODO: once the flash part TOP/BOTTOM detection + * issue is sorted out in the MTD code, break this into at + * least three partitions: 'u-boot code', 'u-boot environment' + * and 'whatever is left'. + */ + flash@0 { + compatible = "cfi-flash"; + reg = <0 0x80000>; + bank-width = <1>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "Full512Kb"; + reg = <0 0x80000>; + read-only; + }; }; }; +&ehci0 { + status = "okay"; +}; + ð { status = "okay"; @@ -69,3 +115,60 @@ phy-handle = <ðphy>; }; }; + +&i2c { + status = "okay"; + clock-frequency = <100000>; + #address-cells = <1>; + + rtc@32 { + compatible = "ricoh,rs5c372a"; + reg = <0x32>; + interrupt-parent = <&gpio0>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +&mdio { + status = "okay"; + + ethphy: ethernet-phy { + reg = <8>; + }; +}; + +&pinctrl { + pinctrl-0 = <&pmx_rtc &pmx_power_led_ctrl>; + pinctrl-names = "default"; + + pmx_power_button: pmx-power-button { + marvell,pins = "mpp18"; + marvell,function = "gpio"; + }; + + pmx_power_led: pmx-power-led { + marvell,pins = "mpp16"; + marvell,function = "gpio"; + }; + + pmx_power_led_ctrl: pmx-power-led-ctrl { + marvell,pins = "mpp17"; + marvell,function = "gpio"; + }; + + pmx_rtc: pmx-rtc { + marvell,pins = "mpp3"; + marvell,function = "gpio"; + }; +}; + +&sata { + pinctrl-0 = <&pmx_sata0 &pmx_sata1>; + pinctrl-names = "default"; + status = "okay"; + nr-ports = <2>; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/orion5x-maxtor-shared-storage-2.dts b/arch/arm/boot/dts/orion5x-maxtor-shared-storage-2.dts new file mode 100644 index 00000000000000..ff348490429484 --- /dev/null +++ b/arch/arm/boot/dts/orion5x-maxtor-shared-storage-2.dts @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2014 Thomas Petazzoni + * Copyright (C) Sylver Bruneau + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/dts-v1/; + +#include +#include +#include +#include "orion5x-mv88f5182.dtsi" + +/ { + model = "Maxtor Shared Storage II"; + compatible = "maxtor,shared-storage-2", "marvell,orion5x-88f5182", "marvell,orion5x"; + + memory { + reg = <0x00000000 0x4000000>; /* 64 MB */ + }; + + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk"; + linux,stdout-path = &uart0; + }; + + soc { + ranges = , + , + ; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-0 = <&pmx_buttons>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + power { + label = "Power"; + linux,code = ; + gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; + }; + + reset { + label = "Reset"; + linux,code = ; + gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&devbus_bootcs { + status = "okay"; + + devbus,keep-config; + + /* + * Currently the MTD code does not recognize the MX29LV400CBCT + * as a bottom-type device. This could cause risks of + * accidentally erasing critical flash sectors. We thus define + * a single, write-protected partition covering the whole + * flash. TODO: once the flash part TOP/BOTTOM detection + * issue is sorted out in the MTD code, break this into at + * least three partitions: 'u-boot code', 'u-boot environment' + * and 'whatever is left'. + */ + flash@0 { + compatible = "cfi-flash"; + reg = <0 0x40000>; + bank-width = <1>; + #address-cells = <1>; + #size-cells = <1>; + }; +}; + +&mdio { + status = "okay"; + + ethphy: ethernet-phy { + reg = <8>; + }; +}; + +&ehci0 { + status = "okay"; +}; + +ð { + status = "okay"; + + ethernet-port@0 { + phy-handle = <ðphy>; + }; +}; + +&i2c { + status = "okay"; + clock-frequency = <100000>; + #address-cells = <1>; + + rtc@68 { + compatible = "st,m41t81"; + reg = <0x68>; + pinctrl-0 = <&pmx_rtc>; + pinctrl-names = "default"; + interrupt-parent = <&gpio0>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +&pinctrl { + pinctrl-0 = <&pmx_leds &pmx_misc>; + pinctrl-names = "default"; + + pmx_buttons: pmx-buttons { + marvell,pins = "mpp11", "mpp12"; + marvell,function = "gpio"; + }; + + /* + * MPP0: Power LED + * MPP1: Error LED + */ + pmx_leds: pmx-leds { + marvell,pins = "mpp0", "mpp1"; + marvell,function = "gpio"; + }; + + /* + * MPP4: HDD ind. (Single/Dual) + * MPP5: HD0 5V control + * MPP6: HD0 12V control + * MPP7: HD1 5V control + * MPP8: HD1 12V control + */ + pmx_misc: pmx-misc { + marvell,pins = "mpp4", "mpp5", "mpp6", "mpp7", "mpp8", "mpp10"; + marvell,function = "gpio"; + }; + + pmx_rtc: pmx-rtc { + marvell,pins = "mpp3"; + marvell,function = "gpio"; + }; + + pmx_sata0_led_active: pmx-sata0-led-active { + marvell,pins = "mpp14"; + marvell,function = "sata0"; + }; + + pmx_sata1_led_active: pmx-sata1-led-active { + marvell,pins = "mpp15"; + marvell,function = "sata1"; + }; + + /* + * Non MPP GPIOs: + * GPIO 22: USB port 1 fuse (0 = Fail, 1 = Ok) + * GPIO 23: Blue front LED off + * GPIO 24: Inhibit board power off (0 = Disabled, 1 = Enabled) + */ +}; + +&sata { + pinctrl-0 = <&pmx_sata0_led_active + &pmx_sata1_led_active>; + pinctrl-names = "default"; + status = "okay"; + nr-ports = <2>; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/orion5x-mv88f5182.dtsi b/arch/arm/boot/dts/orion5x-mv88f5182.dtsi new file mode 100644 index 00000000000000..d1ed71c6020962 --- /dev/null +++ b/arch/arm/boot/dts/orion5x-mv88f5182.dtsi @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014 Thomas Petazzoni + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include "orion5x.dtsi" + +/ { + compatible = "marvell,orion5x-88f5182", "marvell,orion5x"; + + soc { + compatible = "marvell,orion5x-88f5182-mbus", "simple-bus"; + + internal-regs { + pinctrl: pinctrl@10000 { + compatible = "marvell,88f5182-pinctrl"; + reg = <0x10000 0x8>, <0x10050 0x4>; + + pmx_sata0: pmx-sata0 { + marvell,pins = "mpp12", "mpp14"; + marvell,function = "sata0"; + }; + + pmx_sata1: pmx-sata1 { + marvell,pins = "mpp13", "mpp15"; + marvell,function = "sata1"; + }; + }; + + core_clk: core-clocks@10030 { + compatible = "marvell,mv88f5182-core-clock"; + reg = <0x10010 0x4>; + #clock-cells = <1>; + }; + + mbusc: mbus-controller@20000 { + compatible = "marvell,mbus-controller"; + reg = <0x20000 0x100>, <0x1500 0x20>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/orion5x-rd88f5182-nas.dts b/arch/arm/boot/dts/orion5x-rd88f5182-nas.dts new file mode 100644 index 00000000000000..6fb052507b369c --- /dev/null +++ b/arch/arm/boot/dts/orion5x-rd88f5182-nas.dts @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2014 Thomas Petazzoni + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/dts-v1/; + +#include +#include "orion5x-mv88f5182.dtsi" + +/ { + model = "Marvell Reference Design 88F5182 NAS"; + compatible = "marvell,rd-88f5182-nas", "marvell,orion5x-88f5182", "marvell,orion5x"; + + memory { + reg = <0x00000000 0x4000000>; /* 64 MB */ + }; + + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk"; + linux,stdout-path = &uart0; + }; + + soc { + ranges = , + , + , + ; + }; + + gpio-leds { + compatible = "gpio-leds"; + pinctrl-0 = <&pmx_debug_led>; + pinctrl-names = "default"; + + led@0 { + label = "rd88f5182:cpu"; + linux,default-trigger = "heartbeat"; + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&devbus_bootcs { + status = "okay"; + + /* Read parameters */ + devbus,bus-width = <8>; + devbus,turn-off-ps = <90000>; + devbus,badr-skew-ps = <0>; + devbus,acc-first-ps = <186000>; + devbus,acc-next-ps = <186000>; + + /* Write parameters */ + devbus,wr-high-ps = <90000>; + devbus,wr-low-ps = <90000>; + devbus,ale-wr-ps = <90000>; + + flash@0 { + compatible = "cfi-flash"; + reg = <0 0x80000>; + bank-width = <1>; + }; +}; + +&devbus_cs1 { + status = "okay"; + + /* Read parameters */ + devbus,bus-width = <8>; + devbus,turn-off-ps = <90000>; + devbus,badr-skew-ps = <0>; + devbus,acc-first-ps = <186000>; + devbus,acc-next-ps = <186000>; + + /* Write parameters */ + devbus,wr-high-ps = <90000>; + devbus,wr-low-ps = <90000>; + devbus,ale-wr-ps = <90000>; + + flash@0 { + compatible = "cfi-flash"; + reg = <0 0x1000000>; + bank-width = <1>; + }; +}; + +&ehci0 { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +ð { + status = "okay"; + + ethernet-port@0 { + phy-handle = <ðphy>; + }; +}; + +&i2c { + status = "okay"; + clock-frequency = <100000>; + #address-cells = <1>; + + rtc@68 { + pinctrl-0 = <&pmx_rtc>; + pinctrl-names = "default"; + compatible = "dallas,ds1338"; + reg = <0x68>; + }; +}; + +&mdio { + status = "okay"; + + ethphy: ethernet-phy { + reg = <8>; + }; +}; + +&pinctrl { + pinctrl-0 = <&pmx_reset_switch &pmx_misc_gpios + &pmx_pci_gpios>; + pinctrl-names = "default"; + + /* + * MPP[20] PCI Clock to MV88F5182 + * MPP[21] PCI Clock to mini PCI CON11 + * MPP[22] USB 0 over current indication + * MPP[23] USB 1 over current indication + * MPP[24] USB 1 over current enable + * MPP[25] USB 0 over current enable + */ + + pmx_debug_led: pmx-debug_led { + marvell,pins = "mpp0"; + marvell,function = "gpio"; + }; + + pmx_reset_switch: pmx-reset-switch { + marvell,pins = "mpp1"; + marvell,function = "gpio"; + }; + + pmx_rtc: pmx-rtc { + marvell,pins = "mpp3"; + marvell,function = "gpio"; + }; + + pmx_misc_gpios: pmx-misc-gpios { + marvell,pins = "mpp4", "mpp5"; + marvell,function = "gpio"; + }; + + pmx_pci_gpios: pmx-pci-gpios { + marvell,pins = "mpp6", "mpp7"; + marvell,function = "gpio"; + }; +}; + +&sata { + pinctrl-0 = <&pmx_sata0 &pmx_sata1>; + pinctrl-names = "default"; + status = "okay"; + nr-ports = <2>; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/orion5x.dtsi b/arch/arm/boot/dts/orion5x.dtsi index 174d89241f7002..75cd01bd60241d 100644 --- a/arch/arm/boot/dts/orion5x.dtsi +++ b/arch/arm/boot/dts/orion5x.dtsi @@ -6,7 +6,9 @@ * warranty of any kind, whether express or implied. */ -/include/ "skeleton.dtsi" +#include "skeleton.dtsi" + +#define MBUS_ID(target,attributes) (((target) << 24) | ((attributes) << 16)) / { model = "Marvell Orion5x SoC"; @@ -17,149 +19,214 @@ gpio0 = &gpio0; }; - intc: interrupt-controller { - compatible = "marvell,orion-intc"; - interrupt-controller; - #interrupt-cells = <1>; - reg = <0xf1020200 0x08>; - }; - - ocp@f1000000 { - compatible = "simple-bus"; - ranges = <0x00000000 0xf1000000 0x4000000 - 0xf2200000 0xf2200000 0x0000800>; - #address-cells = <1>; + soc { + #address-cells = <2>; #size-cells = <1>; + controller = <&mbusc>; - gpio0: gpio@10100 { - compatible = "marvell,orion-gpio"; - #gpio-cells = <2>; - gpio-controller; - reg = <0x10100 0x40>; - ngpios = <32>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = <6>, <7>, <8>, <9>; - }; - - spi@10600 { - compatible = "marvell,orion-spi"; + devbus_bootcs: devbus-bootcs { + compatible = "marvell,orion-devbus"; + reg = ; + ranges = <0 MBUS_ID(0x01, 0x0f) 0 0xffffffff>; #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - reg = <0x10600 0x28>; + #size-cells = <1>; + clocks = <&core_clk 0>; status = "disabled"; }; - i2c@11000 { - compatible = "marvell,mv64xxx-i2c"; - reg = <0x11000 0x20>; + devbus_cs0: devbus-cs0 { + compatible = "marvell,orion-devbus"; + reg = ; + ranges = <0 MBUS_ID(0x01, 0x1e) 0 0xffffffff>; #address-cells = <1>; - #size-cells = <0>; - interrupts = <5>; - clock-frequency = <100000>; + #size-cells = <1>; + clocks = <&core_clk 0>; status = "disabled"; }; - serial@12000 { - compatible = "ns16550a"; - reg = <0x12000 0x100>; - reg-shift = <2>; - interrupts = <3>; - /* set clock-frequency in board dts */ + devbus_cs1: devbus-cs1 { + compatible = "marvell,orion-devbus"; + reg = ; + ranges = <0 MBUS_ID(0x01, 0x1d) 0 0xffffffff>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&core_clk 0>; status = "disabled"; }; - serial@12100 { - compatible = "ns16550a"; - reg = <0x12100 0x100>; - reg-shift = <2>; - interrupts = <4>; - /* set clock-frequency in board dts */ + devbus_cs2: devbus-cs2 { + compatible = "marvell,orion-devbus"; + reg = ; + ranges = <0 MBUS_ID(0x01, 0x1b) 0 0xffffffff>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&core_clk 0>; status = "disabled"; }; - wdt@20300 { - compatible = "marvell,orion-wdt"; - reg = <0x20300 0x28>; - status = "okay"; - }; + internal-regs { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>; + + gpio0: gpio@10100 { + compatible = "marvell,orion-gpio"; + #gpio-cells = <2>; + gpio-controller; + reg = <0x10100 0x40>; + ngpios = <32>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <6>, <7>, <8>, <9>; + }; - ehci@50000 { - compatible = "marvell,orion-ehci"; - reg = <0x50000 0x1000>; - interrupts = <17>; - status = "disabled"; - }; + spi: spi@10600 { + compatible = "marvell,orion-spi"; + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + reg = <0x10600 0x28>; + status = "disabled"; + }; - xor@60900 { - compatible = "marvell,orion-xor"; - reg = <0x60900 0x100 - 0x60b00 0x100>; - status = "okay"; + i2c: i2c@11000 { + compatible = "marvell,mv64xxx-i2c"; + reg = <0x11000 0x20>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <5>; + clocks = <&core_clk 0>; + status = "disabled"; + }; - xor00 { - interrupts = <30>; - dmacap,memcpy; - dmacap,xor; + uart0: serial@12000 { + compatible = "ns16550a"; + reg = <0x12000 0x100>; + reg-shift = <2>; + interrupts = <3>; + clocks = <&core_clk 0>; + status = "disabled"; }; - xor01 { - interrupts = <31>; - dmacap,memcpy; - dmacap,xor; - dmacap,memset; + + uart1: serial@12100 { + compatible = "ns16550a"; + reg = <0x12100 0x100>; + reg-shift = <2>; + interrupts = <4>; + clocks = <&core_clk 0>; + status = "disabled"; }; - }; - eth: ethernet-controller@72000 { - compatible = "marvell,orion-eth"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x72000 0x4000>; - marvell,tx-checksum-limit = <1600>; - status = "disabled"; + bridge_intc: bridge-interrupt-ctrl@20110 { + compatible = "marvell,orion-bridge-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x20110 0x8>; + interrupts = <0>; + marvell,#interrupts = <4>; + }; - ethernet-port@0 { - compatible = "marvell,orion-eth-port"; - reg = <0>; - /* overwrite MAC address in bootloader */ - local-mac-address = [00 00 00 00 00 00]; - /* set phy-handle property in board file */ + intc: interrupt-controller@20200 { + compatible = "marvell,orion-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x20200 0x08>; }; - }; - mdio: mdio-bus@72004 { - compatible = "marvell,orion-mdio"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x72004 0x84>; - interrupts = <22>; - status = "disabled"; + timer: timer@20300 { + compatible = "marvell,orion-timer"; + reg = <0x20300 0x20>; + interrupt-parent = <&bridge_intc>; + interrupts = <1>, <2>; + clocks = <&core_clk 0>; + }; - /* add phy nodes in board file */ - }; + wdt: wdt@20300 { + compatible = "marvell,orion-wdt"; + reg = <0x20300 0x28>; + interrupt-parent = <&bridge_intc>; + interrupts = <3>; + status = "okay"; + }; - sata@80000 { - compatible = "marvell,orion-sata"; - reg = <0x80000 0x5000>; - interrupts = <29>; - status = "disabled"; + ehci0: ehci@50000 { + compatible = "marvell,orion-ehci"; + reg = <0x50000 0x1000>; + interrupts = <17>; + status = "disabled"; + }; + + xor: dma-controller@60900 { + compatible = "marvell,orion-xor"; + reg = <0x60900 0x100 + 0x60b00 0x100>; + status = "okay"; + + xor00 { + interrupts = <30>; + dmacap,memcpy; + dmacap,xor; + }; + xor01 { + interrupts = <31>; + dmacap,memcpy; + dmacap,xor; + dmacap,memset; + }; + }; + + eth: ethernet-controller@72000 { + compatible = "marvell,orion-eth"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x72000 0x4000>; + marvell,tx-checksum-limit = <1600>; + status = "disabled"; + + ethport: ethernet-port@0 { + compatible = "marvell,orion-eth-port"; + reg = <0>; + interrupts = <21>; + /* overwrite MAC address in bootloader */ + local-mac-address = [00 00 00 00 00 00]; + /* set phy-handle property in board file */ + }; + }; + + mdio: mdio-bus@72004 { + compatible = "marvell,orion-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x72004 0x84>; + interrupts = <22>; + status = "disabled"; + + /* add phy nodes in board file */ + }; + + sata: sata@80000 { + compatible = "marvell,orion-sata"; + reg = <0x80000 0x5000>; + interrupts = <29>; + status = "disabled"; + }; + + ehci1: ehci@a0000 { + compatible = "marvell,orion-ehci"; + reg = <0xa0000 0x1000>; + interrupts = <12>; + status = "disabled"; + }; }; - crypto@90000 { + cesa: crypto@90000 { compatible = "marvell,orion-crypto"; - reg = <0x90000 0x10000>, - <0xf2200000 0x800>; + reg = , + ; reg-names = "regs", "sram"; interrupts = <28>; status = "okay"; }; - - ehci@a0000 { - compatible = "marvell,orion-ehci"; - reg = <0xa0000 0x1000>; - interrupts = <12>; - status = "disabled"; - }; }; }; diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva-reference.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva-reference.dts index 95a849bf921f46..10344e6edd20a3 100644 --- a/arch/arm/boot/dts/r8a7740-armadillo800eva-reference.dts +++ b/arch/arm/boot/dts/r8a7740-armadillo800eva-reference.dts @@ -11,6 +11,7 @@ /dts-v1/; #include "r8a7740.dtsi" #include +#include #include #include @@ -77,26 +78,26 @@ power-key { gpios = <&pfc 99 GPIO_ACTIVE_LOW>; - linux,code = <116>; + linux,code = ; label = "SW3"; gpio-key,wakeup; }; back-key { gpios = <&pfc 100 GPIO_ACTIVE_LOW>; - linux,code = <158>; + linux,code = ; label = "SW4"; }; menu-key { gpios = <&pfc 97 GPIO_ACTIVE_LOW>; - linux,code = <139>; + linux,code = ; label = "SW5"; }; home-key { gpios = <&pfc 98 GPIO_ACTIVE_LOW>; - linux,code = <102>; + linux,code = ; label = "SW6"; }; }; @@ -117,6 +118,16 @@ }; }; + i2c2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "i2c-gpio"; + gpios = <&pfc 208 GPIO_ACTIVE_HIGH /* sda */ + &pfc 91 GPIO_ACTIVE_HIGH /* scl */ + >; + i2c-gpio,delay-us = <5>; + }; + backlight { compatible = "pwm-backlight"; pwms = <&tpu 2 33333 PWM_POLARITY_INVERTED>; @@ -166,6 +177,14 @@ }; }; +&i2c2 { + status = "okay"; + rtc@30 { + compatible = "sii,s35390a"; + reg = <0x30>; + }; +}; + &pfc { pinctrl-0 = <&scifa1_pins>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/r8a7740.dtsi b/arch/arm/boot/dts/r8a7740.dtsi index 2551e9438d358a..3834b94dc02ae2 100644 --- a/arch/arm/boot/dts/r8a7740.dtsi +++ b/arch/arm/boot/dts/r8a7740.dtsi @@ -125,7 +125,7 @@ i2c0: i2c@fff20000 { #address-cells = <1>; #size-cells = <0>; - compatible = "renesas,rmobile-iic"; + compatible = "renesas,iic-r8a7740", "renesas,rmobile-iic"; reg = <0xfff20000 0x425>; interrupt-parent = <&gic>; interrupts = <0 201 IRQ_TYPE_LEVEL_HIGH @@ -138,7 +138,7 @@ i2c1: i2c@e6c20000 { #address-cells = <1>; #size-cells = <0>; - compatible = "renesas,rmobile-iic"; + compatible = "renesas,iic-r8a7740", "renesas,rmobile-iic"; reg = <0xe6c20000 0x425>; interrupt-parent = <&gic>; interrupts = <0 70 IRQ_TYPE_LEVEL_HIGH @@ -173,7 +173,7 @@ }; mmcif0: mmc@e6bd0000 { - compatible = "renesas,sh-mmcif"; + compatible = "renesas,mmcif-r8a7740", "renesas,sh-mmcif"; reg = <0xe6bd0000 0x100>; interrupt-parent = <&gic>; interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH @@ -219,7 +219,7 @@ sh_fsi2: sound@fe1f0000 { #sound-dai-cells = <1>; - compatible = "renesas,sh_fsi2"; + compatible = "renesas,fsi2-r8a7740", "renesas,sh_fsi2"; reg = <0xfe1f0000 0x400>; interrupt-parent = <&gic>; interrupts = <0 9 0x4>; diff --git a/arch/arm/boot/dts/r8a7778-bockw-reference.dts b/arch/arm/boot/dts/r8a7778-bockw-reference.dts index 06cda19dac6a6d..f76f6ec01e194c 100644 --- a/arch/arm/boot/dts/r8a7778-bockw-reference.dts +++ b/arch/arm/boot/dts/r8a7778-bockw-reference.dts @@ -109,4 +109,18 @@ pinctrl-0 = <&hspi0_pins>; pinctrl-names = "default"; status = "okay"; + + flash: flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,s25fl008k"; + reg = <0>; + spi-max-frequency = <104000000>; + m25p,fast-read; + + partition@0 { + label = "data(spi)"; + reg = <0x00000000 0x00100000>; + }; + }; }; diff --git a/arch/arm/boot/dts/r8a7778.dtsi b/arch/arm/boot/dts/r8a7778.dtsi index 85c5b3b99f5e3b..3c6fab5c9702e4 100644 --- a/arch/arm/boot/dts/r8a7778.dtsi +++ b/arch/arm/boot/dts/r8a7778.dtsi @@ -204,26 +204,32 @@ }; hspi0: spi@fffc7000 { - compatible = "renesas,hspi"; + compatible = "renesas,hspi-r8a7778", "renesas,hspi"; reg = <0xfffc7000 0x18>; - interrupt-controller = <&gic>; + interrupt-parent = <&gic>; interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; hspi1: spi@fffc8000 { - compatible = "renesas,hspi"; + compatible = "renesas,hspi-r8a7778", "renesas,hspi"; reg = <0xfffc8000 0x18>; - interrupt-controller = <&gic>; + interrupt-parent = <&gic>; interrupts = <0 84 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; hspi2: spi@fffc6000 { - compatible = "renesas,hspi"; + compatible = "renesas,hspi-r8a7778", "renesas,hspi"; reg = <0xfffc6000 0x18>; - interrupt-controller = <&gic>; + interrupt-parent = <&gic>; interrupts = <0 85 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/r8a7779.dtsi b/arch/arm/boot/dts/r8a7779.dtsi index d0561d4c7c4660..8b1a336ee401be 100644 --- a/arch/arm/boot/dts/r8a7779.dtsi +++ b/arch/arm/boot/dts/r8a7779.dtsi @@ -256,26 +256,32 @@ }; hspi0: spi@fffc7000 { - compatible = "renesas,hspi"; + compatible = "renesas,hspi-r8a7779", "renesas,hspi"; reg = <0xfffc7000 0x18>; - interrupt-controller = <&gic>; + interrupt-parent = <&gic>; interrupts = <0 73 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; hspi1: spi@fffc8000 { - compatible = "renesas,hspi"; + compatible = "renesas,hspi-r8a7779", "renesas,hspi"; reg = <0xfffc8000 0x18>; - interrupt-controller = <&gic>; + interrupt-parent = <&gic>; interrupts = <0 74 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; hspi2: spi@fffc6000 { - compatible = "renesas,hspi"; + compatible = "renesas,hspi-r8a7779", "renesas,hspi"; reg = <0xfffc6000 0x18>; - interrupt-controller = <&gic>; + interrupt-parent = <&gic>; interrupts = <0 75 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts index d01048ab3e7775..86d676f629429a 100644 --- a/arch/arm/boot/dts/r8a7790-lager.dts +++ b/arch/arm/boot/dts/r8a7790-lager.dts @@ -12,6 +12,7 @@ /dts-v1/; #include "r8a7790.dtsi" #include +#include / { model = "Lager"; @@ -36,6 +37,39 @@ #size-cells = <1>; }; + gpio_keys { + compatible = "gpio-keys"; + + button@1 { + linux,code = ; + label = "SW2-1"; + gpio-key,wakeup; + debounce-interval = <20>; + gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; + }; + button@2 { + linux,code = ; + label = "SW2-2"; + gpio-key,wakeup; + debounce-interval = <20>; + gpios = <&gpio1 24 GPIO_ACTIVE_LOW>; + }; + button@3 { + linux,code = ; + label = "SW2-3"; + gpio-key,wakeup; + debounce-interval = <20>; + gpios = <&gpio1 26 GPIO_ACTIVE_LOW>; + }; + button@4 { + linux,code = ; + label = "SW2-4"; + gpio-key,wakeup; + debounce-interval = <20>; + gpios = <&gpio1 28 GPIO_ACTIVE_LOW>; + }; + }; + leds { compatible = "gpio-leds"; led6 { @@ -155,10 +189,16 @@ renesas,function = "mmc1"; }; - qspi_pins: spi { + qspi_pins: spi0 { renesas,groups = "qspi_ctrl", "qspi_data4"; renesas,function = "qspi"; }; + + msiof1_pins: spi2 { + renesas,groups = "msiof1_clk", "msiof1_sync", "msiof1_rx", + "msiof1_tx"; + renesas,function = "msiof1"; + }; }; ðer { @@ -173,6 +213,7 @@ reg = <1>; interrupt-parent = <&irqc0>; interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + micrel,led-mode = <1>; }; }; @@ -190,7 +231,7 @@ status = "okay"; }; -&spi { +&qspi { pinctrl-0 = <&qspi_pins>; pinctrl-names = "default"; @@ -202,6 +243,8 @@ compatible = "spansion,s25fl512s"; reg = <0>; spi-max-frequency = <30000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; m25p,fast-read; partition@0 { @@ -221,6 +264,22 @@ }; }; +&msiof1 { + pinctrl-0 = <&msiof1_pins>; + pinctrl-names = "default"; + + status = "okay"; + + pmic: pmic@0 { + compatible = "renesas,r2a11302ft"; + reg = <0>; + spi-max-frequency = <6000000>; + spi-cpol; + spi-cpha; + }; + +}; + &sdhi0 { pinctrl-0 = <&sdhi0_pins>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 618e5b537eaf9d..d38d703391490b 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -24,6 +24,15 @@ i2c1 = &i2c1; i2c2 = &i2c2; i2c3 = &i2c3; + i2c4 = &iic0; + i2c5 = &iic1; + i2c6 = &iic2; + i2c7 = &iic3; + spi0 = &qspi; + spi1 = &msiof0; + spi2 = &msiof1; + spi3 = &msiof2; + spi4 = &msiof3; }; cpus { @@ -231,6 +240,46 @@ status = "disabled"; }; + iic0: i2c@e6500000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-r8a7790", "renesas,rmobile-iic"; + reg = <0 0xe6500000 0 0x425>; + interrupts = <0 174 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7790_CLK_IIC0>; + status = "disabled"; + }; + + iic1: i2c@e6510000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-r8a7790", "renesas,rmobile-iic"; + reg = <0 0xe6510000 0 0x425>; + interrupts = <0 175 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7790_CLK_IIC1>; + status = "disabled"; + }; + + iic2: i2c@e6520000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-r8a7790", "renesas,rmobile-iic"; + reg = <0 0xe6520000 0 0x425>; + interrupts = <0 176 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7790_CLK_IIC2>; + status = "disabled"; + }; + + iic3: i2c@e60b0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-r8a7790", "renesas,rmobile-iic"; + reg = <0 0xe60b0000 0 0x425>; + interrupts = <0 173 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp9_clks R8A7790_CLK_IICDVFS>; + status = "disabled"; + }; + mmcif0: mmcif@ee200000 { compatible = "renesas,mmcif-r8a7790", "renesas,sh-mmcif"; reg = <0 0xee200000 0 0x80>; @@ -673,7 +722,7 @@ renesas,clock-indices = < R8A7790_CLK_TMU1 R8A7790_CLK_TMU3 R8A7790_CLK_TMU2 R8A7790_CLK_CMT0 R8A7790_CLK_TMU0 R8A7790_CLK_VSP1_DU1 - R8A7790_CLK_VSP1_DU0 R8A7790_CLK_VSP1_RT R8A7790_CLK_VSP1_SY + R8A7790_CLK_VSP1_DU0 R8A7790_CLK_VSP1_R R8A7790_CLK_VSP1_S >; clock-output-names = "tmu1", "tmu3", "tmu2", "cmt0", "tmu0", "vsp1-du1", @@ -697,18 +746,19 @@ mstp3_clks: mstp3_clks@e615013c { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>; - clocks = <&cp_clk>, <&mmc1_clk>, <&sd3_clk>, <&sd2_clk>, - <&cpg_clocks R8A7790_CLK_SD1>, <&cpg_clocks R8A7790_CLK_SD0>, - <&mmc0_clk>, <&rclk_clk>; + clocks = <&hp_clk>, <&cp_clk>, <&mmc1_clk>, <&sd3_clk>, + <&sd2_clk>, <&cpg_clocks R8A7790_CLK_SD1>, <&cpg_clocks R8A7790_CLK_SD0>, <&mmc0_clk>, + <&hp_clk>, <&hp_clk>, <&rclk_clk>; #clock-cells = <1>; renesas,clock-indices = < - R8A7790_CLK_TPU0 R8A7790_CLK_MMCIF1 R8A7790_CLK_SDHI3 - R8A7790_CLK_SDHI2 R8A7790_CLK_SDHI1 R8A7790_CLK_SDHI0 - R8A7790_CLK_MMCIF0 R8A7790_CLK_CMT1 + R8A7790_CLK_IIC2 R8A7790_CLK_TPU0 R8A7790_CLK_MMCIF1 R8A7790_CLK_SDHI3 + R8A7790_CLK_SDHI2 R8A7790_CLK_SDHI1 R8A7790_CLK_SDHI0 R8A7790_CLK_MMCIF0 + R8A7790_CLK_IIC0 R8A7790_CLK_IIC1 R8A7790_CLK_CMT1 >; clock-output-names = - "tpu0", "mmcif1", "sdhi3", "sdhi2", - "sdhi1", "sdhi0", "mmcif0", "cmt1"; + "iic2", "tpu0", "mmcif1", "sdhi3", + "sdhi2", "sdhi1", "sdhi0", "mmcif0", + "iic0", "iic1", "cmt1"; }; mstp5_clks: mstp5_clks@e6150144 { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; @@ -752,20 +802,20 @@ mstp9_clks: mstp9_clks@e6150994 { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150994 0 4>, <0 0xe61509a4 0 4>; - clocks = <&p_clk>, <&p_clk>, <&cpg_clocks R8A7790_CLK_QSPI>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>; + clocks = <&p_clk>, <&p_clk>, <&cpg_clocks R8A7790_CLK_QSPI>, <&cp_clk>, + <&hp_clk>, <&hp_clk>, <&hp_clk>, <&hp_clk>; #clock-cells = <1>; renesas,clock-indices = < - R8A7790_CLK_RCAN1 R8A7790_CLK_RCAN0 R8A7790_CLK_QSPI_MOD - R8A7790_CLK_I2C3 R8A7790_CLK_I2C2 R8A7790_CLK_I2C1 - R8A7790_CLK_I2C0 + R8A7790_CLK_RCAN1 R8A7790_CLK_RCAN0 R8A7790_CLK_QSPI_MOD R8A7790_CLK_IICDVFS + R8A7790_CLK_I2C3 R8A7790_CLK_I2C2 R8A7790_CLK_I2C1 R8A7790_CLK_I2C0 >; clock-output-names = - "rcan1", "rcan0", "qspi_mod", "i2c3", "i2c2", "i2c1", "i2c0"; + "rcan1", "rcan0", "qspi_mod", "iic3", + "i2c3", "i2c2", "i2c1", "i2c0"; }; }; - spi: spi@e6b10000 { + qspi: spi@e6b10000 { compatible = "renesas,qspi-r8a7790", "renesas,qspi"; reg = <0 0xe6b10000 0 0x2c>; interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>; @@ -775,4 +825,44 @@ #size-cells = <0>; status = "disabled"; }; + + msiof0: spi@e6e20000 { + compatible = "renesas,msiof-r8a7790"; + reg = <0 0xe6e20000 0 0x0064>; + interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp0_clks R8A7790_CLK_MSIOF0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + msiof1: spi@e6e10000 { + compatible = "renesas,msiof-r8a7790"; + reg = <0 0xe6e10000 0 0x0064>; + interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7790_CLK_MSIOF1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + msiof2: spi@e6e00000 { + compatible = "renesas,msiof-r8a7790"; + reg = <0 0xe6e00000 0 0x0064>; + interrupts = <0 158 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7790_CLK_MSIOF2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + msiof3: spi@e6c90000 { + compatible = "renesas,msiof-r8a7790"; + reg = <0 0xe6c90000 0 0x0064>; + interrupts = <0 159 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7790_CLK_MSIOF3>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; diff --git a/arch/arm/boot/dts/r8a7791-henninger.dts b/arch/arm/boot/dts/r8a7791-henninger.dts new file mode 100644 index 00000000000000..0a655231d53148 --- /dev/null +++ b/arch/arm/boot/dts/r8a7791-henninger.dts @@ -0,0 +1,84 @@ +/* + * Device Tree Source for the Henninger board + * + * Copyright (C) 2014 Renesas Solutions Corp. + * Copyright (C) 2014 Cogent Embedded, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/dts-v1/; +#include "r8a7791.dtsi" + +/ { + model = "Henninger"; + compatible = "renesas,henninger", "renesas,r8a7791"; + + aliases { + serial0 = &scif0; + }; + + chosen { + bootargs = "console=ttySC0,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp"; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0 0x40000000 0 0x40000000>; + }; + + memory@200000000 { + device_type = "memory"; + reg = <2 0x00000000 0 0x40000000>; + }; +}; + +&extal_clk { + clock-frequency = <20000000>; +}; + +&pfc { + scif0_pins: serial0 { + renesas,groups = "scif0_data_d"; + renesas,function = "scif0"; + }; + + ether_pins: ether { + renesas,groups = "eth_link", "eth_mdio", "eth_rmii"; + renesas,function = "eth"; + }; + + phy1_pins: phy1 { + renesas,groups = "intc_irq0"; + renesas,function = "intc"; + }; +}; + +&scif0 { + pinctrl-0 = <&scif0_pins>; + pinctrl-names = "default"; + + status = "okay"; +}; + +ðer { + pinctrl-0 = <ðer_pins &phy1_pins>; + pinctrl-names = "default"; + + phy-handle = <&phy1>; + renesas,ether-link-active-low; + status = "ok"; + + phy1: ethernet-phy@1 { + reg = <1>; + interrupt-parent = <&irqc0>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + micrel,led-mode = <1>; + }; +}; + +&sata0 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index de1b6977c69a4b..0d69813def859e 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -13,6 +13,7 @@ /dts-v1/; #include "r8a7791.dtsi" #include +#include / { model = "Koelsch"; @@ -40,51 +41,79 @@ gpio-keys { compatible = "gpio-keys"; + key-1 { + gpios = <&gpio5 0 GPIO_ACTIVE_LOW>; + linux,code = ; + label = "SW2-1"; + gpio-key,wakeup; + debounce-interval = <20>; + }; + key-2 { + gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + linux,code = ; + label = "SW2-2"; + gpio-key,wakeup; + debounce-interval = <20>; + }; + key-3 { + gpios = <&gpio5 2 GPIO_ACTIVE_LOW>; + linux,code = ; + label = "SW2-3"; + gpio-key,wakeup; + debounce-interval = <20>; + }; + key-4 { + gpios = <&gpio5 3 GPIO_ACTIVE_LOW>; + linux,code = ; + label = "SW2-4"; + gpio-key,wakeup; + debounce-interval = <20>; + }; key-a { gpios = <&gpio7 0 GPIO_ACTIVE_LOW>; - linux,code = <30>; + linux,code = ; label = "SW30"; gpio-key,wakeup; debounce-interval = <20>; }; key-b { gpios = <&gpio7 1 GPIO_ACTIVE_LOW>; - linux,code = <48>; + linux,code = ; label = "SW31"; gpio-key,wakeup; debounce-interval = <20>; }; key-c { gpios = <&gpio7 2 GPIO_ACTIVE_LOW>; - linux,code = <46>; + linux,code = ; label = "SW32"; gpio-key,wakeup; debounce-interval = <20>; }; key-d { gpios = <&gpio7 3 GPIO_ACTIVE_LOW>; - linux,code = <32>; + linux,code = ; label = "SW33"; gpio-key,wakeup; debounce-interval = <20>; }; key-e { gpios = <&gpio7 4 GPIO_ACTIVE_LOW>; - linux,code = <18>; + linux,code = ; label = "SW34"; gpio-key,wakeup; debounce-interval = <20>; }; key-f { gpios = <&gpio7 5 GPIO_ACTIVE_LOW>; - linux,code = <33>; + linux,code = ; label = "SW35"; gpio-key,wakeup; debounce-interval = <20>; }; key-g { gpios = <&gpio7 6 GPIO_ACTIVE_LOW>; - linux,code = <34>; + linux,code = ; label = "SW36"; gpio-key,wakeup; debounce-interval = <20>; @@ -195,11 +224,16 @@ }; }; +&i2c6 { + status = "okay"; + clock-frequency = <100000>; +}; + &pfc { pinctrl-0 = <&du_pins &scif0_pins &scif1_pins>; pinctrl-names = "default"; - i2c2_pins: i2c { + i2c2_pins: i2c2 { renesas,groups = "i2c2"; renesas,function = "i2c2"; }; @@ -244,10 +278,16 @@ renesas,function = "sdhi2"; }; - qspi_pins: spi { + qspi_pins: spi0 { renesas,groups = "qspi_ctrl", "qspi_data4"; renesas,function = "qspi"; }; + + msiof0_pins: spi1 { + renesas,groups = "msiof0_clk", "msiof0_sync", "msiof0_rx", + "msiof0_tx"; + renesas,function = "msiof0"; + }; }; ðer { @@ -262,6 +302,7 @@ reg = <1>; interrupt-parent = <&irqc0>; interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + micrel,led-mode = <1>; }; }; @@ -301,7 +342,7 @@ status = "okay"; }; -&spi { +&qspi { pinctrl-0 = <&qspi_pins>; pinctrl-names = "default"; @@ -313,6 +354,8 @@ compatible = "spansion,s25fl512s"; reg = <0>; spi-max-frequency = <30000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; m25p,fast-read; partition@0 { @@ -331,3 +374,18 @@ }; }; }; + +&msiof0 { + pinctrl-0 = <&msiof0_pins>; + pinctrl-names = "default"; + + status = "okay"; + + pmic: pmic@0 { + compatible = "renesas,r2a11302ft"; + reg = <0>; + spi-max-frequency = <6000000>; + spi-cpol; + spi-cpha; + }; +}; diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 46181708e59c5c..44f03444ef74e6 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -27,6 +27,13 @@ i2c3 = &i2c3; i2c4 = &i2c4; i2c5 = &i2c5; + i2c6 = &i2c6; + i2c7 = &i2c7; + i2c8 = &i2c8; + spi0 = &qspi; + spi1 = &msiof0; + spi2 = &msiof1; + spi3 = &msiof2; }; cpus { @@ -37,14 +44,14 @@ device_type = "cpu"; compatible = "arm,cortex-a15"; reg = <0>; - clock-frequency = <1300000000>; + clock-frequency = <1500000000>; }; cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a15"; reg = <1>; - clock-frequency = <1300000000>; + clock-frequency = <1500000000>; }; }; @@ -180,6 +187,7 @@ <0 17 IRQ_TYPE_LEVEL_HIGH>; }; + /* The memory map in the User's Manual maps the cores to bus numbers */ i2c0: i2c@e6508000 { #address-cells = <1>; #size-cells = <0>; @@ -231,6 +239,7 @@ }; i2c5: i2c@e6528000 { + /* doesn't need pinmux */ #address-cells = <1>; #size-cells = <0>; compatible = "renesas,i2c-r8a7791"; @@ -240,6 +249,37 @@ status = "disabled"; }; + i2c6: i2c@e60b0000 { + /* doesn't need pinmux */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-r8a7791", "renesas,rmobile-iic"; + reg = <0 0xe60b0000 0 0x425>; + interrupts = <0 173 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp9_clks R8A7791_CLK_IICDVFS>; + status = "disabled"; + }; + + i2c7: i2c@e6500000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-r8a7791", "renesas,rmobile-iic"; + reg = <0 0xe6500000 0 0x425>; + interrupts = <0 174 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7791_CLK_IIC0>; + status = "disabled"; + }; + + i2c8: i2c@e6510000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-r8a7791", "renesas,rmobile-iic"; + reg = <0 0xe6510000 0 0x425>; + interrupts = <0 175 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7791_CLK_IIC1>; + status = "disabled"; + }; + pfc: pfc@e6060000 { compatible = "renesas,pfc-r8a7791"; reg = <0 0xe6060000 0 0x250>; @@ -688,7 +728,7 @@ renesas,clock-indices = < R8A7791_CLK_TMU1 R8A7791_CLK_TMU3 R8A7791_CLK_TMU2 R8A7791_CLK_CMT0 R8A7791_CLK_TMU0 R8A7791_CLK_VSP1_DU1 - R8A7791_CLK_VSP1_DU0 R8A7791_CLK_VSP1_SY + R8A7791_CLK_VSP1_DU0 R8A7791_CLK_VSP1_S >; clock-output-names = "tmu1", "tmu3", "tmu2", "cmt0", "tmu0", "vsp1-du1", @@ -712,15 +752,16 @@ mstp3_clks: mstp3_clks@e615013c { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>; - clocks = <&cp_clk>, <&sd2_clk>, <&sd1_clk>, - <&cpg_clocks R8A7791_CLK_SD0>, <&mmc0_clk>, <&rclk_clk>; + clocks = <&cp_clk>, <&sd2_clk>, <&sd1_clk>, <&cpg_clocks R8A7791_CLK_SD0>, + <&mmc0_clk>, <&hp_clk>, <&hp_clk>, <&rclk_clk>; #clock-cells = <1>; renesas,clock-indices = < - R8A7791_CLK_TPU0 R8A7791_CLK_SDHI2 R8A7791_CLK_SDHI1 - R8A7791_CLK_SDHI0 R8A7791_CLK_MMCIF0 R8A7791_CLK_CMT1 + R8A7791_CLK_TPU0 R8A7791_CLK_SDHI2 R8A7791_CLK_SDHI1 R8A7791_CLK_SDHI0 + R8A7791_CLK_MMCIF0 R8A7791_CLK_IIC0 R8A7791_CLK_IIC1 R8A7791_CLK_CMT1 >; clock-output-names = - "tpu0", "sdhi2", "sdhi1", "sdhi0", "mmcif0", "cmt1"; + "tpu0", "sdhi2", "sdhi1", "sdhi0", + "mmcif0", "i2c7", "i2c8", "cmt1"; }; mstp5_clks: mstp5_clks@e6150144 { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; @@ -733,19 +774,19 @@ mstp7_clks: mstp7_clks@e615014c { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe615014c 0 4>, <0 0xe61501c4 0 4>; - clocks = <&mp_clk>, <&zs_clk>, <&p_clk>, <&p_clk>, <&zs_clk>, + clocks = <&mp_clk>, <&mp_clk>, <&zs_clk>, <&p_clk>, <&p_clk>, <&zs_clk>, <&zs_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&zx_clk>, <&zx_clk>, <&zx_clk>; #clock-cells = <1>; renesas,clock-indices = < - R8A7791_CLK_HSUSB R8A7791_CLK_HSCIF2 R8A7791_CLK_SCIF5 + R8A7791_CLK_EHCI R8A7791_CLK_HSUSB R8A7791_CLK_HSCIF2 R8A7791_CLK_SCIF5 R8A7791_CLK_SCIF4 R8A7791_CLK_HSCIF1 R8A7791_CLK_HSCIF0 R8A7791_CLK_SCIF3 R8A7791_CLK_SCIF2 R8A7791_CLK_SCIF1 R8A7791_CLK_SCIF0 R8A7791_CLK_DU1 R8A7791_CLK_DU0 R8A7791_CLK_LVDS0 >; clock-output-names = - "hsusb", "hscif2", "scif5", "scif4", "hscif1", "hscif0", + "ehci", "hsusb", "hscif2", "scif5", "scif4", "hscif1", "hscif0", "scif3", "scif2", "scif1", "scif0", "du1", "du0", "lvds0"; }; mstp8_clks: mstp8_clks@e6150990 { @@ -764,17 +805,17 @@ mstp9_clks: mstp9_clks@e6150994 { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150994 0 4>, <0 0xe61509a4 0 4>; - clocks = <&p_clk>, <&p_clk>, <&cpg_clocks R8A7791_CLK_QSPI>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, - <&p_clk>; + clocks = <&p_clk>, <&p_clk>, <&cpg_clocks R8A7791_CLK_QSPI>, <&hp_clk>, + <&cp_clk>, <&hp_clk>, <&hp_clk>, <&hp_clk>, + <&hp_clk>, <&hp_clk>; #clock-cells = <1>; renesas,clock-indices = < - R8A7791_CLK_RCAN1 R8A7791_CLK_RCAN0 R8A7791_CLK_QSPI_MOD - R8A7791_CLK_I2C5 R8A7791_CLK_I2C4 R8A7791_CLK_I2C3 - R8A7791_CLK_I2C2 R8A7791_CLK_I2C1 R8A7791_CLK_I2C0 + R8A7791_CLK_RCAN1 R8A7791_CLK_RCAN0 R8A7791_CLK_QSPI_MOD R8A7791_CLK_I2C5 + R8A7791_CLK_IICDVFS R8A7791_CLK_I2C4 R8A7791_CLK_I2C3 R8A7791_CLK_I2C2 + R8A7791_CLK_I2C1 R8A7791_CLK_I2C0 >; clock-output-names = - "rcan1", "rcan0", "qspi_mod", "i2c5", "i2c4", "i2c3", + "rcan1", "rcan0", "qspi_mod", "i2c5", "i2c6", "i2c4", "i2c3", "i2c2", "i2c1", "i2c0"; }; mstp11_clks: mstp11_clks@e615099c { @@ -789,7 +830,7 @@ }; }; - spi: spi@e6b10000 { + qspi: spi@e6b10000 { compatible = "renesas,qspi-r8a7791", "renesas,qspi"; reg = <0 0xe6b10000 0 0x2c>; interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>; @@ -799,4 +840,34 @@ #size-cells = <0>; status = "disabled"; }; + + msiof0: spi@e6e20000 { + compatible = "renesas,msiof-r8a7791"; + reg = <0 0xe6e20000 0 0x0064>; + interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + msiof1: spi@e6e10000 { + compatible = "renesas,msiof-r8a7791"; + reg = <0 0xe6e10000 0 0x0064>; + interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7791_CLK_MSIOF1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + msiof2: spi@e6e00000 { + compatible = "renesas,msiof-r8a7791"; + reg = <0 0xe6e00000 0 0x0064>; + interrupts = <0 158 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7791_CLK_MSIOF2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; diff --git a/arch/arm/boot/dts/s3c2416-smdk2416.dts b/arch/arm/boot/dts/s3c2416-smdk2416.dts index 59594cf15998bc..ea92fd69529a5b 100644 --- a/arch/arm/boot/dts/s3c2416-smdk2416.dts +++ b/arch/arm/boot/dts/s3c2416-smdk2416.dts @@ -19,6 +19,19 @@ reg = <0x30000000 0x4000000>; }; + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + xti: xti { + compatible = "fixed-clock"; + clock-frequency = <12000000>; + clock-output-names = "xti"; + #clock-cells = <0>; + }; + }; + serial@50000000 { status = "okay"; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/s3c2416.dtsi b/arch/arm/boot/dts/s3c2416.dtsi index e6555bdd81b887..955e4a4f8c31cc 100644 --- a/arch/arm/boot/dts/s3c2416.dtsi +++ b/arch/arm/boot/dts/s3c2416.dtsi @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ +#include #include "s3c24xx.dtsi" #include "s3c2416-pinctrl.dtsi" @@ -28,26 +29,53 @@ compatible = "samsung,s3c2416-irq"; }; + clocks: clock-controller@0x4c000000 { + compatible = "samsung,s3c2416-clock"; + reg = <0x4c000000 0x40>; + #clock-cells = <1>; + }; + pinctrl@56000000 { compatible = "samsung,s3c2416-pinctrl"; }; + timer@51000000 { + clocks = <&clocks PCLK_PWM>; + clock-names = "timers"; + }; + serial@50000000 { compatible = "samsung,s3c2440-uart"; + clock-names = "uart", "clk_uart_baud2", + "clk_uart_baud3"; + clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>, + <&clocks SCLK_UART>; }; serial@50004000 { compatible = "samsung,s3c2440-uart"; + clock-names = "uart", "clk_uart_baud2", + "clk_uart_baud3"; + clocks = <&clocks PCLK_UART1>, <&clocks PCLK_UART1>, + <&clocks SCLK_UART>; }; serial@50008000 { compatible = "samsung,s3c2440-uart"; + clock-names = "uart", "clk_uart_baud2", + "clk_uart_baud3"; + clocks = <&clocks PCLK_UART2>, <&clocks PCLK_UART2>, + <&clocks SCLK_UART>; }; serial@5000C000 { compatible = "samsung,s3c2440-uart"; reg = <0x5000C000 0x4000>; interrupts = <1 18 24 4>, <1 18 25 4>; + clock-names = "uart", "clk_uart_baud2", + "clk_uart_baud3"; + clocks = <&clocks PCLK_UART3>, <&clocks PCLK_UART3>, + <&clocks SCLK_UART>; status = "disabled"; }; @@ -55,6 +83,10 @@ compatible = "samsung,s3c6410-sdhci"; reg = <0x4AC00000 0x100>; interrupts = <0 0 21 3>; + clock-names = "hsmmc", "mmc_busclk.0", + "mmc_busclk.2"; + clocks = <&clocks HCLK_HSMMC0>, <&clocks HCLK_HSMMC0>, + <&clocks MUX_HSMMC0>; status = "disabled"; }; @@ -62,18 +94,28 @@ compatible = "samsung,s3c6410-sdhci"; reg = <0x4A800000 0x100>; interrupts = <0 0 20 3>; + clock-names = "hsmmc", "mmc_busclk.0", + "mmc_busclk.2"; + clocks = <&clocks HCLK_HSMMC1>, <&clocks HCLK_HSMMC1>, + <&clocks MUX_HSMMC1>; status = "disabled"; }; watchdog@53000000 { interrupts = <1 9 27 3>; + clocks = <&clocks PCLK_WDT>; + clock-names = "watchdog"; }; rtc@57000000 { compatible = "samsung,s3c2416-rtc"; + clocks = <&clocks PCLK_RTC>; + clock-names = "rtc"; }; i2c@54000000 { compatible = "samsung,s3c2440-i2c"; + clocks = <&clocks PCLK_I2C0>; + clock-names = "i2c"; }; }; diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index eabcfdbb403acc..1c7caeb87a9518 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -13,7 +13,7 @@ #include #include #include -#include +#include / { model = "Atmel SAMA5D3 family SoC"; @@ -113,6 +113,9 @@ compatible = "atmel,at91sam9g45-ssc"; reg = <0xf0008000 0x4000>; interrupts = <38 IRQ_TYPE_LEVEL_HIGH 4>; + dmas = <&dma0 2 AT91_DMA_CFG_PER_ID(13)>, + <&dma0 2 AT91_DMA_CFG_PER_ID(14)>; + dma-names = "tx", "rx"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>; clocks = <&ssc0_clk>; @@ -231,6 +234,9 @@ compatible = "atmel,at91sam9g45-ssc"; reg = <0xf800c000 0x4000>; interrupts = <39 IRQ_TYPE_LEVEL_HIGH 4>; + dmas = <&dma1 2 AT91_DMA_CFG_PER_ID(3)>, + <&dma1 2 AT91_DMA_CFG_PER_ID(4)>; + dma-names = "tx", "rx"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ssc1_tx &pinctrl_ssc1_rx>; clocks = <&ssc1_clk>; diff --git a/arch/arm/boot/dts/sama5d3_mci2.dtsi b/arch/arm/boot/dts/sama5d3_mci2.dtsi index b029fe7ef17a65..1b02208ea6ff2b 100644 --- a/arch/arm/boot/dts/sama5d3_mci2.dtsi +++ b/arch/arm/boot/dts/sama5d3_mci2.dtsi @@ -9,7 +9,7 @@ #include #include -#include +#include / { ahb { diff --git a/arch/arm/boot/dts/sama5d3_tcb1.dtsi b/arch/arm/boot/dts/sama5d3_tcb1.dtsi index 382b04431f66b6..02848453ca0cf5 100644 --- a/arch/arm/boot/dts/sama5d3_tcb1.dtsi +++ b/arch/arm/boot/dts/sama5d3_tcb1.dtsi @@ -9,7 +9,7 @@ #include #include -#include +#include / { aliases { diff --git a/arch/arm/boot/dts/sama5d3_uart.dtsi b/arch/arm/boot/dts/sama5d3_uart.dtsi index a9fa75e4165205..7a8d4c6115f72f 100644 --- a/arch/arm/boot/dts/sama5d3_uart.dtsi +++ b/arch/arm/boot/dts/sama5d3_uart.dtsi @@ -9,7 +9,7 @@ #include #include -#include +#include / { aliases { diff --git a/arch/arm/boot/dts/sama5d3xmb.dtsi b/arch/arm/boot/dts/sama5d3xmb.dtsi index dba739b6ef36fa..306eef0f97ef21 100644 --- a/arch/arm/boot/dts/sama5d3xmb.dtsi +++ b/arch/arm/boot/dts/sama5d3xmb.dtsi @@ -32,6 +32,10 @@ }; }; + ssc0: ssc@f0008000 { + atmel,clk-from-rk-pin; + }; + /* * i2c0 conflicts with ISI: * disable it to allow the use of ISI @@ -156,7 +160,7 @@ }; sound { - compatible = "atmel,sama5d3ek-wm8904"; + compatible = "atmel,asoc-wm8904"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pck0_as_audio_mck>; @@ -166,9 +170,12 @@ "Headphone Jack", "HPOUTR", "IN2L", "Line In Jack", "IN2R", "Line In Jack", + "MICBIAS", "IN1L", "IN1L", "Mic"; atmel,ssc-controller = <&ssc0>; atmel,audio-codec = <&wm8904>; + + status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts b/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts index eb8886b535e4a2..a99171c8a78222 100644 --- a/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts +++ b/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts @@ -14,6 +14,7 @@ /dts-v1/; #include "sh73a0.dtsi" #include +#include #include / { @@ -112,43 +113,43 @@ back-key { gpios = <&pcf8575 8 GPIO_ACTIVE_LOW>; - linux,code = <158>; + linux,code = ; label = "SW3"; }; right-key { gpios = <&pcf8575 9 GPIO_ACTIVE_LOW>; - linux,code = <106>; + linux,code = ; label = "SW2-R"; }; left-key { gpios = <&pcf8575 10 GPIO_ACTIVE_LOW>; - linux,code = <105>; + linux,code = ; label = "SW2-L"; }; enter-key { gpios = <&pcf8575 11 GPIO_ACTIVE_LOW>; - linux,code = <28>; + linux,code = ; label = "SW2-P"; }; up-key { gpios = <&pcf8575 12 GPIO_ACTIVE_LOW>; - linux,code = <103>; + linux,code = ; label = "SW2-U"; }; down-key { gpios = <&pcf8575 13 GPIO_ACTIVE_LOW>; - linux,code = <108>; + linux,code = ; label = "SW2-D"; }; home-key { gpios = <&pcf8575 14 GPIO_ACTIVE_LOW>; - linux,code = <102>; + linux,code = ; label = "SW1"; }; }; diff --git a/arch/arm/boot/dts/tegra114-dalmore.dts b/arch/arm/boot/dts/tegra114-dalmore.dts index a288a12823ed84..5c21d216515a3d 100644 --- a/arch/arm/boot/dts/tegra114-dalmore.dts +++ b/arch/arm/boot/dts/tegra114-dalmore.dts @@ -25,6 +25,7 @@ hdmi@54280000 { status = "okay"; + hdmi-supply = <&vdd_5v0_hdmi>; vdd-supply = <&vdd_hdmi_reg>; pll-supply = <&palmas_smps3_reg>; @@ -36,6 +37,8 @@ dsi@54300000 { status = "okay"; + avdd-dsi-csi-supply = <&avdd_1v2_reg>; + panel@0 { compatible = "panasonic,vvx10f004b00", "simple-panel"; @@ -982,12 +985,10 @@ regulator-max-microvolt = <2800000>; }; - ldo3 { + avdd_1v2_reg: ldo3 { regulator-name = "avdd-dsi-csi"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; - regulator-always-on; - regulator-boot-on; }; ldo4 { @@ -1105,6 +1106,7 @@ sdhci@78000400 { cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_HIGH>; bus-width = <4>; status = "okay"; }; @@ -1231,8 +1233,6 @@ regulator-name = "vdd_hdmi_5v0"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; - enable-active-high; - gpio = <&gpio TEGRA_GPIO(K, 1) GPIO_ACTIVE_HIGH>; vin-supply = <&tps65090_dcdc1_reg>; }; @@ -1245,6 +1245,17 @@ enable-active-high; gpio = <&palmas_gpio 6 0>; }; + + vdd_5v0_hdmi: regulator@7 { + compatible = "regulator-fixed"; + reg = <7>; + regulator-name = "VDD_5V0_HDMI_CON"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio TEGRA_GPIO(K, 1) GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&tps65090_dcdc1_reg>; + }; }; sound { diff --git a/arch/arm/boot/dts/tegra114-tn7.dts b/arch/arm/boot/dts/tegra114-tn7.dts new file mode 100644 index 00000000000000..96366214563542 --- /dev/null +++ b/arch/arm/boot/dts/tegra114-tn7.dts @@ -0,0 +1,348 @@ +/dts-v1/; + +#include +#include "tegra114.dtsi" + +/ { + model = "Tegra Note 7"; + compatible = "nvidia,tn7", "nvidia,tegra114"; + + chosen { + /* TN7's bootloader's arguments need to be overridden */ + bootargs = "console=ttyS0,115200n8 console=tty1 gpt fbcon=rotate:2"; + /* TN7's bootloader will place initrd at this address */ + linux,initrd-start = <0x82000000>; + linux,initrd-end = <0x82800000>; + }; + + firmware { + trusted-foundations { + compatible = "tlm,trusted-foundations"; + tlm,version-major = <2>; + tlm,version-minor = <8>; + }; + }; + + memory { + /* memory >= 0x37e00000 is reserved for firmware usage */ + reg = <0x80000000 0x37e00000>; + }; + + host1x@50000000 { + dsi@54300000 { + status = "okay"; + + vdd-supply = <&vdd_1v2_ap>; + + panel@0 { + compatible = "lg,ld070wx3-sl01"; + reg = <0>; + + power-supply = <&vdd_lcd>; + backlight = <&backlight>; + }; + }; + }; + + serial@70006300 { + status = "okay"; + }; + + pwm@7000a000 { + status = "okay"; + }; + + i2c@7000d000 { + status = "okay"; + clock-frequency = <400000>; + + palmas: pmic@58 { + compatible = "ti,palmas"; + reg = <0x58>; + interrupts = ; + + #interrupt-cells = <2>; + interrupt-controller; + + ti,system-power-controller; + + palmas_gpio: gpio { + compatible = "ti,palmas-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + pmic { + compatible = "ti,tps65913-pmic", "ti,palmas-pmic"; + + ldoln-in-supply = <&vdd_smps10_out2>; + + regulators { + smps123 { + regulator-name = "vd-cpu"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + }; + + smps45 { + regulator-name = "vd-soc"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + regulator-boot-on; + }; + + smps6 { + regulator-name = "va-lcd-hv"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + regulator-boot-on; + }; + + smps7 { + regulator-name = "vd-ddr"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_1v8: smps8 { + regulator-name = "vs-pmu-1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_2v9_sys: smps9 { + regulator-name = "vs-sys-2v9"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_smps10_out1: smps10_out1 { + regulator-name = "vd-smps10-out1"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_smps10_out2: smps10_out2 { + regulator-name = "vd-smps10-out2"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo1 { + regulator-name = "va-pllx"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_1v2_ap: ldo2 { + regulator-name = "va-ap-1v2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo3 { + regulator-name = "vd-fuse"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo4 { + regulator-name = "vd-ts-hv"; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3200000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo5 { + regulator-name = "va-cam2-hv"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2700000>; + }; + + ldo6 { + regulator-name = "va-sns-hv"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + ldo7 { + regulator-name = "va-cam1-hv"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2700000>; + }; + + ldo8 { + regulator-name = "va-ap-rtc"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + ti,enable-ldo8-tracking; + regulator-always-on; + regulator-boot-on; + }; + + ldo9 { + regulator-name = "vi-sdcard"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + }; + + ldousb { + regulator-name = "avdd-usb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + ldoln { + regulator-name = "va-hdmi"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; + + rtc { + compatible = "ti,palmas-rtc"; + interrupt-parent = <&palmas>; + interrupts = <8 0>; + }; + + }; + }; + + pmc@7000e400 { + nvidia,invert-interrupt; + }; + + /* eMMC */ + sdhci@78000600 { + status = "okay"; + bus-width = <8>; + vmmc-supply = <&vdd_1v8>; + non-removable; + }; + + usb@7d000000 { + status = "okay"; + }; + + usb-phy@7d000000 { + status = "okay"; + nvidia,xcvr-setup = <7>; + nvidia,xcvr-lsfslew = <2>; + nvidia,xcvr-lsrslew = <2>; + interrupts = ; + /* Should be changed to "otg" once we have vbus_supply */ + /* As of now, USB devices need to be powered externally */ + dr_mode = "host"; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 1 40000>; + + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + + power-supply = <&lcd_bl_en>; + }; + + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + power { + label = "Power"; + gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>; + linux,code = ; + gpio-key,wakeup; + }; + + volume_down { + label = "Volume Down"; + gpios = <&gpio TEGRA_GPIO(Q, 2) GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + volume_up { + label = "Volume Up"; + gpios = <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + /* FIXME: output of BQ24192 */ + vs_sys: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "VS_SYS"; + regulator-min-microvolt = <4200000>; + regulator-max-microvolt = <4200000>; + regulator-always-on; + regulator-boot-on; + }; + + lcd_bl_en: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "VDD_LCD_BL"; + regulator-min-microvolt = <16500000>; + regulator-max-microvolt = <16500000>; + gpio = <&gpio TEGRA_GPIO(H, 2) GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&vs_sys>; + regulator-boot-on; + }; + + vdd_lcd: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "VD_LCD_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&palmas_gpio 4 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&vdd_1v8>; + regulator-boot-on; + }; + }; +}; diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts new file mode 100644 index 00000000000000..e31fb61a81d33b --- /dev/null +++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts @@ -0,0 +1,1827 @@ +/dts-v1/; + +#include +#include "tegra124.dtsi" + +/ { + model = "NVIDIA Tegra124 Jetson TK1"; + compatible = "nvidia,jetson-tk1", "nvidia,tegra124"; + + aliases { + rtc0 = "/i2c@0,7000d000/pmic@40"; + rtc1 = "/rtc@0,7000e000"; + }; + + memory { + reg = <0x0 0x80000000 0x0 0x80000000>; + }; + + host1x@0,50000000 { + hdmi@0,54280000 { + status = "okay"; + + hdmi-supply = <&vdd_5v0_hdmi>; + pll-supply = <&vdd_hdmi_pll>; + vdd-supply = <&vdd_3v3_hdmi>; + + nvidia,ddc-i2c-bus = <&hdmi_ddc>; + nvidia,hpd-gpio = + <&gpio TEGRA_GPIO(N, 7) GPIO_ACTIVE_HIGH>; + }; + }; + + pinmux: pinmux@0,70000868 { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + clk_32k_out_pa0 { + nvidia,pins = "clk_32k_out_pa0"; + nvidia,function = "soc"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + uart3_cts_n_pa1 { + nvidia,pins = "uart3_cts_n_pa1"; + nvidia,function = "uartc"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap2_fs_pa2 { + nvidia,pins = "dap2_fs_pa2"; + nvidia,function = "i2s1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap2_sclk_pa3 { + nvidia,pins = "dap2_sclk_pa3"; + nvidia,function = "i2s1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap2_din_pa4 { + nvidia,pins = "dap2_din_pa4"; + nvidia,function = "i2s1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap2_dout_pa5 { + nvidia,pins = "dap2_dout_pa5"; + nvidia,function = "i2s1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc3_clk_pa6 { + nvidia,pins = "sdmmc3_clk_pa6"; + nvidia,function = "sdmmc3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc3_cmd_pa7 { + nvidia,pins = "sdmmc3_cmd_pa7"; + nvidia,function = "sdmmc3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pb0 { + nvidia,pins = "pb0"; + nvidia,function = "uartd"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pb1 { + nvidia,pins = "pb1"; + nvidia,function = "uartd"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc3_dat3_pb4 { + nvidia,pins = "sdmmc3_dat3_pb4"; + nvidia,function = "sdmmc3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc3_dat2_pb5 { + nvidia,pins = "sdmmc3_dat2_pb5"; + nvidia,function = "sdmmc3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc3_dat1_pb6 { + nvidia,pins = "sdmmc3_dat1_pb6"; + nvidia,function = "sdmmc3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc3_dat0_pb7 { + nvidia,pins = "sdmmc3_dat0_pb7"; + nvidia,function = "sdmmc3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + uart3_rts_n_pc0 { + nvidia,pins = "uart3_rts_n_pc0"; + nvidia,function = "uartc"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + uart2_txd_pc2 { + nvidia,pins = "uart2_txd_pc2"; + nvidia,function = "irda"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + uart2_rxd_pc3 { + nvidia,pins = "uart2_rxd_pc3"; + nvidia,function = "irda"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + gen1_i2c_scl_pc4 { + nvidia,pins = "gen1_i2c_scl_pc4"; + nvidia,function = "i2c1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + gen1_i2c_sda_pc5 { + nvidia,pins = "gen1_i2c_sda_pc5"; + nvidia,function = "i2c1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + pc7 { + nvidia,pins = "pc7"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pg0 { + nvidia,pins = "pg0"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pg1 { + nvidia,pins = "pg1"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pg2 { + nvidia,pins = "pg2"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pg3 { + nvidia,pins = "pg3"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pg4 { + nvidia,pins = "pg4"; + nvidia,function = "spi4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pg5 { + nvidia,pins = "pg5"; + nvidia,function = "spi4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pg6 { + nvidia,pins = "pg6"; + nvidia,function = "spi4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pg7 { + nvidia,pins = "pg7"; + nvidia,function = "spi4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ph0 { + nvidia,pins = "ph0"; + nvidia,function = "gmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ph1 { + nvidia,pins = "ph1"; + nvidia,function = "pwm1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ph2 { + nvidia,pins = "ph2"; + nvidia,function = "gmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ph3 { + nvidia,pins = "ph3"; + nvidia,function = "gmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ph4 { + nvidia,pins = "ph4"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ph5 { + nvidia,pins = "ph5"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ph6 { + nvidia,pins = "ph6"; + nvidia,function = "gmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ph7 { + nvidia,pins = "ph7"; + nvidia,function = "gmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pi0 { + nvidia,pins = "pi0"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pi1 { + nvidia,pins = "pi1"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pi2 { + nvidia,pins = "pi2"; + nvidia,function = "rsvd4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pi3 { + nvidia,pins = "pi3"; + nvidia,function = "spi4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pi4 { + nvidia,pins = "pi4"; + nvidia,function = "gmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pi5 { + nvidia,pins = "pi5"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pi6 { + nvidia,pins = "pi6"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pi7 { + nvidia,pins = "pi7"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pj0 { + nvidia,pins = "pj0"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pj2 { + nvidia,pins = "pj2"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + uart2_cts_n_pj5 { + nvidia,pins = "uart2_cts_n_pj5"; + nvidia,function = "uartb"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + uart2_rts_n_pj6 { + nvidia,pins = "uart2_rts_n_pj6"; + nvidia,function = "uartb"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pj7 { + nvidia,pins = "pj7"; + nvidia,function = "uartd"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pk0 { + nvidia,pins = "pk0"; + nvidia,function = "soc"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pk1 { + nvidia,pins = "pk1"; + nvidia,function = "rsvd4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pk2 { + nvidia,pins = "pk2"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pk3 { + nvidia,pins = "pk3"; + nvidia,function = "gmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pk4 { + nvidia,pins = "pk4"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + spdif_out_pk5 { + nvidia,pins = "spdif_out_pk5"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + spdif_in_pk6 { + nvidia,pins = "spdif_in_pk6"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pk7 { + nvidia,pins = "pk7"; + nvidia,function = "uartd"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap1_fs_pn0 { + nvidia,pins = "dap1_fs_pn0"; + nvidia,function = "i2s0"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap1_din_pn1 { + nvidia,pins = "dap1_din_pn1"; + nvidia,function = "i2s0"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap1_dout_pn2 { + nvidia,pins = "dap1_dout_pn2"; + nvidia,function = "sata"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap1_sclk_pn3 { + nvidia,pins = "dap1_sclk_pn3"; + nvidia,function = "i2s0"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + usb_vbus_en0_pn4 { + nvidia,pins = "usb_vbus_en0_pn4"; + nvidia,function = "usb"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + usb_vbus_en1_pn5 { + nvidia,pins = "usb_vbus_en1_pn5"; + nvidia,function = "usb"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + hdmi_int_pn7 { + nvidia,pins = "hdmi_int_pn7"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,rcv-sel = ; + }; + ulpi_data7_po0 { + nvidia,pins = "ulpi_data7_po0"; + nvidia,function = "ulpi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ulpi_data0_po1 { + nvidia,pins = "ulpi_data0_po1"; + nvidia,function = "ulpi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ulpi_data1_po2 { + nvidia,pins = "ulpi_data1_po2"; + nvidia,function = "ulpi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ulpi_data2_po3 { + nvidia,pins = "ulpi_data2_po3"; + nvidia,function = "ulpi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ulpi_data3_po4 { + nvidia,pins = "ulpi_data3_po4"; + nvidia,function = "ulpi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ulpi_data4_po5 { + nvidia,pins = "ulpi_data4_po5"; + nvidia,function = "ulpi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ulpi_data5_po6 { + nvidia,pins = "ulpi_data5_po6"; + nvidia,function = "ulpi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ulpi_data6_po7 { + nvidia,pins = "ulpi_data6_po7"; + nvidia,function = "ulpi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap3_fs_pp0 { + nvidia,pins = "dap3_fs_pp0"; + nvidia,function = "i2s2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap3_din_pp1 { + nvidia,pins = "dap3_din_pp1"; + nvidia,function = "i2s2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap3_dout_pp2 { + nvidia,pins = "dap3_dout_pp2"; + nvidia,function = "rsvd4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap3_sclk_pp3 { + nvidia,pins = "dap3_sclk_pp3"; + nvidia,function = "rsvd3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap4_fs_pp4 { + nvidia,pins = "dap4_fs_pp4"; + nvidia,function = "i2s3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap4_din_pp5 { + nvidia,pins = "dap4_din_pp5"; + nvidia,function = "i2s3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap4_dout_pp6 { + nvidia,pins = "dap4_dout_pp6"; + nvidia,function = "i2s3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap4_sclk_pp7 { + nvidia,pins = "dap4_sclk_pp7"; + nvidia,function = "i2s3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_col0_pq0 { + nvidia,pins = "kb_col0_pq0"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_col1_pq1 { + nvidia,pins = "kb_col1_pq1"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_col2_pq2 { + nvidia,pins = "kb_col2_pq2"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_col3_pq3 { + nvidia,pins = "kb_col3_pq3"; + nvidia,function = "kbc"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_col4_pq4 { + nvidia,pins = "kb_col4_pq4"; + nvidia,function = "sdmmc3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_col5_pq5 { + nvidia,pins = "kb_col5_pq5"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_col6_pq6 { + nvidia,pins = "kb_col6_pq6"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_col7_pq7 { + nvidia,pins = "kb_col7_pq7"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row0_pr0 { + nvidia,pins = "kb_row0_pr0"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row1_pr1 { + nvidia,pins = "kb_row1_pr1"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row2_pr2 { + nvidia,pins = "kb_row2_pr2"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row3_pr3 { + nvidia,pins = "kb_row3_pr3"; + nvidia,function = "sys"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row4_pr4 { + nvidia,pins = "kb_row4_pr4"; + nvidia,function = "rsvd3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row5_pr5 { + nvidia,pins = "kb_row5_pr5"; + nvidia,function = "rsvd3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row6_pr6 { + nvidia,pins = "kb_row6_pr6"; + nvidia,function = "displaya_alt"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row7_pr7 { + nvidia,pins = "kb_row7_pr7"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row8_ps0 { + nvidia,pins = "kb_row8_ps0"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row9_ps1 { + nvidia,pins = "kb_row9_ps1"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row10_ps2 { + nvidia,pins = "kb_row10_ps2"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row11_ps3 { + nvidia,pins = "kb_row11_ps3"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row12_ps4 { + nvidia,pins = "kb_row12_ps4"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row13_ps5 { + nvidia,pins = "kb_row13_ps5"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row14_ps6 { + nvidia,pins = "kb_row14_ps6"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row15_ps7 { + nvidia,pins = "kb_row15_ps7"; + nvidia,function = "soc"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row16_pt0 { + nvidia,pins = "kb_row16_pt0"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + kb_row17_pt1 { + nvidia,pins = "kb_row17_pt1"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + gen2_i2c_scl_pt5 { + nvidia,pins = "gen2_i2c_scl_pt5"; + nvidia,function = "i2c2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + gen2_i2c_sda_pt6 { + nvidia,pins = "gen2_i2c_sda_pt6"; + nvidia,function = "i2c2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + sdmmc4_cmd_pt7 { + nvidia,pins = "sdmmc4_cmd_pt7"; + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pu0 { + nvidia,pins = "pu0"; + nvidia,function = "rsvd4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pu1 { + nvidia,pins = "pu1"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pu2 { + nvidia,pins = "pu2"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pu3 { + nvidia,pins = "pu3"; + nvidia,function = "gmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pu4 { + nvidia,pins = "pu4"; + nvidia,function = "gmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pu5 { + nvidia,pins = "pu5"; + nvidia,function = "gmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pu6 { + nvidia,pins = "pu6"; + nvidia,function = "rsvd3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pv0 { + nvidia,pins = "pv0"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pv1 { + nvidia,pins = "pv1"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc3_cd_n_pv2 { + nvidia,pins = "sdmmc3_cd_n_pv2"; + nvidia,function = "sdmmc3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc1_wp_n_pv3 { + nvidia,pins = "sdmmc1_wp_n_pv3"; + nvidia,function = "sdmmc1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ddc_scl_pv4 { + nvidia,pins = "ddc_scl_pv4"; + nvidia,function = "i2c4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,rcv-sel = ; + }; + ddc_sda_pv5 { + nvidia,pins = "ddc_sda_pv5"; + nvidia,function = "i2c4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,rcv-sel = ; + }; + gpio_w2_aud_pw2 { + nvidia,pins = "gpio_w2_aud_pw2"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + gpio_w3_aud_pw3 { + nvidia,pins = "gpio_w3_aud_pw3"; + nvidia,function = "spi6"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap_mclk1_pw4 { + nvidia,pins = "dap_mclk1_pw4"; + nvidia,function = "extperiph1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + clk2_out_pw5 { + nvidia,pins = "clk2_out_pw5"; + nvidia,function = "extperiph2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + uart3_txd_pw6 { + nvidia,pins = "uart3_txd_pw6"; + nvidia,function = "uartc"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + uart3_rxd_pw7 { + nvidia,pins = "uart3_rxd_pw7"; + nvidia,function = "uartc"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dvfs_pwm_px0 { + nvidia,pins = "dvfs_pwm_px0"; + nvidia,function = "cldvfs"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + gpio_x1_aud_px1 { + nvidia,pins = "gpio_x1_aud_px1"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dvfs_clk_px2 { + nvidia,pins = "dvfs_clk_px2"; + nvidia,function = "cldvfs"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + gpio_x3_aud_px3 { + nvidia,pins = "gpio_x3_aud_px3"; + nvidia,function = "rsvd4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + gpio_x4_aud_px4 { + nvidia,pins = "gpio_x4_aud_px4"; + nvidia,function = "gmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + gpio_x5_aud_px5 { + nvidia,pins = "gpio_x5_aud_px5"; + nvidia,function = "rsvd4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + gpio_x6_aud_px6 { + nvidia,pins = "gpio_x6_aud_px6"; + nvidia,function = "gmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + gpio_x7_aud_px7 { + nvidia,pins = "gpio_x7_aud_px7"; + nvidia,function = "rsvd1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ulpi_clk_py0 { + nvidia,pins = "ulpi_clk_py0"; + nvidia,function = "spi1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ulpi_dir_py1 { + nvidia,pins = "ulpi_dir_py1"; + nvidia,function = "spi1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ulpi_nxt_py2 { + nvidia,pins = "ulpi_nxt_py2"; + nvidia,function = "spi1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + ulpi_stp_py3 { + nvidia,pins = "ulpi_stp_py3"; + nvidia,function = "spi1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc1_dat3_py4 { + nvidia,pins = "sdmmc1_dat3_py4"; + nvidia,function = "sdmmc1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc1_dat2_py5 { + nvidia,pins = "sdmmc1_dat2_py5"; + nvidia,function = "sdmmc1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc1_dat1_py6 { + nvidia,pins = "sdmmc1_dat1_py6"; + nvidia,function = "sdmmc1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc1_dat0_py7 { + nvidia,pins = "sdmmc1_dat0_py7"; + nvidia,function = "sdmmc1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc1_clk_pz0 { + nvidia,pins = "sdmmc1_clk_pz0"; + nvidia,function = "sdmmc1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc1_cmd_pz1 { + nvidia,pins = "sdmmc1_cmd_pz1"; + nvidia,function = "sdmmc1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pwr_i2c_scl_pz6 { + nvidia,pins = "pwr_i2c_scl_pz6"; + nvidia,function = "i2cpwr"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + pwr_i2c_sda_pz7 { + nvidia,pins = "pwr_i2c_sda_pz7"; + nvidia,function = "i2cpwr"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + sdmmc4_dat0_paa0 { + nvidia,pins = "sdmmc4_dat0_paa0"; + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc4_dat1_paa1 { + nvidia,pins = "sdmmc4_dat1_paa1"; + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc4_dat2_paa2 { + nvidia,pins = "sdmmc4_dat2_paa2"; + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc4_dat3_paa3 { + nvidia,pins = "sdmmc4_dat3_paa3"; + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc4_dat4_paa4 { + nvidia,pins = "sdmmc4_dat4_paa4"; + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc4_dat5_paa5 { + nvidia,pins = "sdmmc4_dat5_paa5"; + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc4_dat6_paa6 { + nvidia,pins = "sdmmc4_dat6_paa6"; + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc4_dat7_paa7 { + nvidia,pins = "sdmmc4_dat7_paa7"; + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pbb0 { + nvidia,pins = "pbb0"; + nvidia,function = "vimclk2_alt"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + cam_i2c_scl_pbb1 { + nvidia,pins = "cam_i2c_scl_pbb1"; + nvidia,function = "i2c3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + cam_i2c_sda_pbb2 { + nvidia,pins = "cam_i2c_sda_pbb2"; + nvidia,function = "i2c3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + pbb3 { + nvidia,pins = "pbb3"; + nvidia,function = "vgp3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pbb4 { + nvidia,pins = "pbb4"; + nvidia,function = "vgp4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pbb5 { + nvidia,pins = "pbb5"; + nvidia,function = "rsvd3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pbb6 { + nvidia,pins = "pbb6"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pbb7 { + nvidia,pins = "pbb7"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + cam_mclk_pcc0 { + nvidia,pins = "cam_mclk_pcc0"; + nvidia,function = "vi_alt3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pcc1 { + nvidia,pins = "pcc1"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pcc2 { + nvidia,pins = "pcc2"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc4_clk_pcc4 { + nvidia,pins = "sdmmc4_clk_pcc4"; + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + clk2_req_pcc5 { + nvidia,pins = "clk2_req_pcc5"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + clk3_out_pee0 { + nvidia,pins = "clk3_out_pee0"; + nvidia,function = "extperiph3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + clk3_req_pee1 { + nvidia,pins = "clk3_req_pee1"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dap_mclk1_req_pee2 { + nvidia,pins = "dap_mclk1_req_pee2"; + nvidia,function = "sata"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + hdmi_cec_pee3 { + nvidia,pins = "hdmi_cec_pee3"; + nvidia,function = "cec"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + sdmmc3_clk_lb_out_pee4 { + nvidia,pins = "sdmmc3_clk_lb_out_pee4"; + nvidia,function = "sdmmc3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + sdmmc3_clk_lb_in_pee5 { + nvidia,pins = "sdmmc3_clk_lb_in_pee5"; + nvidia,function = "sdmmc3"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + dp_hpd_pff0 { + nvidia,pins = "dp_hpd_pff0"; + nvidia,function = "dp"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + usb_vbus_en2_pff1 { + nvidia,pins = "usb_vbus_en2_pff1"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + pff2 { + nvidia,pins = "pff2"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + }; + core_pwr_req { + nvidia,pins = "core_pwr_req"; + nvidia,function = "pwron"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + cpu_pwr_req { + nvidia,pins = "cpu_pwr_req"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + pwr_int_n { + nvidia,pins = "pwr_int_n"; + nvidia,function = "pmi"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + reset_out_n { + nvidia,pins = "reset_out_n"; + nvidia,function = "reset_out_n"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + owr { + nvidia,pins = "owr"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,rcv-sel = ; + }; + clk_32k_in { + nvidia,pins = "clk_32k_in"; + nvidia,function = "rsvd2"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + jtag_rtck { + nvidia,pins = "jtag_rtck"; + nvidia,function = "rtck"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + }; + }; + + /* DB9 serial port */ + serial@0,70006300 { + status = "okay"; + }; + + /* Expansion GEN1_I2C_*, mini-PCIe I2C, on-board components */ + i2c@0,7000c000 { + status = "okay"; + clock-frequency = <100000>; + + rt5639: audio-codec@1c { + compatible = "realtek,rt5639"; + reg = <0x1c>; + interrupt-parent = <&gpio>; + interrupts = ; + realtek,ldo1-en-gpios = + <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_HIGH>; + }; + + temperature-sensor@4c { + compatible = "ti,tmp451"; + reg = <0x4c>; + interrupt-parent = <&gpio>; + interrupts = ; + }; + + eeprom@56 { + compatible = "atmel,24c02"; + reg = <0x56>; + pagesize = <8>; + }; + }; + + /* Expansion GEN2_I2C_* */ + i2c@0,7000c400 { + status = "okay"; + clock-frequency = <100000>; + }; + + /* Expansion CAM_I2C_* */ + i2c@0,7000c500 { + status = "okay"; + clock-frequency = <100000>; + }; + + /* HDMI DDC */ + hdmi_ddc: i2c@0,7000c700 { + status = "okay"; + clock-frequency = <100000>; + }; + + /* Expansion PWR_I2C_*, on-board components */ + i2c@0,7000d000 { + status = "okay"; + clock-frequency = <400000>; + + pmic: pmic@40 { + compatible = "ams,as3722"; + reg = <0x40>; + interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>; + + ams,system-power-controller; + + #interrupt-cells = <2>; + interrupt-controller; + + gpio-controller; + #gpio-cells = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&as3722_default>; + + as3722_default: pinmux { + gpio0 { + pins = "gpio0"; + function = "gpio"; + bias-pull-down; + }; + + gpio1_2_4_7 { + pins = "gpio1", "gpio2", "gpio4", "gpio7"; + function = "gpio"; + bias-pull-up; + }; + + gpio3_5_6 { + pins = "gpio3", "gpio5", "gpio6"; + bias-high-impedance; + }; + }; + + regulators { + vsup-sd2-supply = <&vdd_5v0_sys>; + vsup-sd3-supply = <&vdd_5v0_sys>; + vsup-sd4-supply = <&vdd_5v0_sys>; + vsup-sd5-supply = <&vdd_5v0_sys>; + vin-ldo0-supply = <&vdd_1v35_lp0>; + vin-ldo1-6-supply = <&vdd_3v3_run>; + vin-ldo2-5-7-supply = <&vddio_1v8>; + vin-ldo3-4-supply = <&vdd_3v3_sys>; + vin-ldo9-10-supply = <&vdd_5v0_sys>; + vin-ldo11-supply = <&vdd_3v3_run>; + + sd0 { + regulator-name = "+VDD_CPU_AP"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1400000>; + regulator-min-microamp = <3500000>; + regulator-max-microamp = <3500000>; + regulator-always-on; + regulator-boot-on; + ams,external-control = <2>; + }; + + sd1 { + regulator-name = "+VDD_CORE"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1350000>; + regulator-min-microamp = <2500000>; + regulator-max-microamp = <2500000>; + regulator-always-on; + regulator-boot-on; + ams,external-control = <1>; + }; + + vdd_1v35_lp0: sd2 { + regulator-name = "+1.35V_LP0(sd2)"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + + sd3 { + regulator-name = "+1.35V_LP0(sd3)"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_1v05_run: sd4 { + regulator-name = "+1.05V_RUN"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + }; + + vddio_1v8: sd5 { + regulator-name = "+1.8V_VDDIO"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + sd6 { + regulator-name = "+VDD_GPU_AP"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <1200000>; + regulator-min-microamp = <3500000>; + regulator-max-microamp = <3500000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo0 { + regulator-name = "+1.05V_RUN_AVDD"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-boot-on; + regulator-always-on; + ams,external-control = <1>; + }; + + ldo1 { + regulator-name = "+1.8V_RUN_CAM"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo2 { + regulator-name = "+1.2V_GEN_AVDD"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo3 { + regulator-name = "+1.05V_LP0_VDD_RTC"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-boot-on; + regulator-always-on; + ams,enable-tracking; + }; + + ldo4 { + regulator-name = "+2.8V_RUN_CAM"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + ldo5 { + regulator-name = "+1.2V_RUN_CAM_FRONT"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + vddio_sdmmc3: ldo6 { + regulator-name = "+VDDIO_SDMMC3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + ldo7 { + regulator-name = "+1.05V_RUN_CAM_REAR"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + }; + + ldo9 { + regulator-name = "+3.3V_RUN_TOUCH"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + ldo10 { + regulator-name = "+2.8V_RUN_CAM_AF"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + ldo11 { + regulator-name = "+1.8V_RUN_VPP_FUSE"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + }; + }; + }; + + /* Expansion TS_SPI_* */ + spi@0,7000d400 { + status = "okay"; + }; + + /* Internal SPI */ + spi@0,7000da00 { + status = "okay"; + spi-max-frequency = <25000000>; + spi-flash@0 { + compatible = "winbond,w25q32dw"; + reg = <0>; + spi-max-frequency = <20000000>; + }; + }; + + pmc@0,7000e400 { + nvidia,invert-interrupt; + nvidia,suspend-mode = <1>; + nvidia,cpu-pwr-good-time = <500>; + nvidia,cpu-pwr-off-time = <300>; + nvidia,core-pwr-good-time = <641 3845>; + nvidia,core-pwr-off-time = <61036>; + nvidia,core-power-req-active-high; + nvidia,sys-clock-req-active-high; + }; + + /* SD card */ + sdhci@0,700b0400 { + status = "okay"; + cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>; + power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>; + wp-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_HIGH>; + bus-width = <4>; + vqmmc-supply = <&vddio_sdmmc3>; + }; + + /* eMMC */ + sdhci@0,700b0600 { + status = "okay"; + bus-width = <8>; + }; + + ahub@0,70300000 { + i2s@0,70301100 { + status = "okay"; + }; + }; + + /* mini-PCIe USB */ + usb@0,7d004000 { + status = "okay"; + }; + + usb-phy@0,7d004000 { + status = "okay"; + }; + + /* USB A connector */ + usb@0,7d008000 { + status = "okay"; + }; + + usb-phy@0,7d008000 { + status = "okay"; + vbus-supply = <&vdd_usb3_vbus>; + }; + + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + power { + label = "Power"; + gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <10>; + gpio-key,wakeup; + }; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + vdd_mux: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "+VDD_MUX"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_5v0_sys: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "+5V_SYS"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vdd_mux>; + }; + + vdd_3v3_sys: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + regulator-name = "+3.3V_SYS"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vdd_mux>; + }; + + vdd_3v3_run: regulator@3 { + compatible = "regulator-fixed"; + reg = <3>; + regulator-name = "+3.3V_RUN"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + gpio = <&pmic 1 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&vdd_3v3_sys>; + }; + + vdd_3v3_hdmi: regulator@4 { + compatible = "regulator-fixed"; + reg = <4>; + regulator-name = "+3.3V_AVDD_HDMI_AP_GATED"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vdd_3v3_run>; + }; + + vdd_usb1_vbus: regulator@7 { + compatible = "regulator-fixed"; + reg = <7>; + regulator-name = "+USB0_VBUS_SW"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio TEGRA_GPIO(N, 4) GPIO_ACTIVE_HIGH>; + enable-active-high; + gpio-open-drain; + vin-supply = <&vdd_5v0_sys>; + }; + + vdd_usb3_vbus: regulator@8 { + compatible = "regulator-fixed"; + reg = <8>; + regulator-name = "+5V_USB_HS"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio TEGRA_GPIO(N, 5) GPIO_ACTIVE_HIGH>; + enable-active-high; + gpio-open-drain; + vin-supply = <&vdd_5v0_sys>; + }; + + vdd_3v3_lp0: regulator@10 { + compatible = "regulator-fixed"; + reg = <10>; + regulator-name = "+3.3V_LP0"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + gpio = <&pmic 2 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&vdd_3v3_sys>; + }; + + vdd_hdmi_pll: regulator@11 { + compatible = "regulator-fixed"; + reg = <11>; + regulator-name = "+1.05V_RUN_AVDD_HDMI_PLL"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + gpio = <&gpio TEGRA_GPIO(H, 7) GPIO_ACTIVE_LOW>; + vin-supply = <&vdd_1v05_run>; + }; + + vdd_5v0_hdmi: regulator@12 { + compatible = "regulator-fixed"; + reg = <12>; + regulator-name = "+5V_HDMI_CON"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio TEGRA_GPIO(K, 6) GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&vdd_5v0_sys>; + }; + }; + + sound { + compatible = "nvidia,tegra-audio-rt5640-jetson-tk1", + "nvidia,tegra-audio-rt5640"; + nvidia,model = "NVIDIA Tegra Jetson TK1"; + + nvidia,audio-routing = + "Headphones", "HPOR", + "Headphones", "HPOL", + "Mic Jack", "MICBIAS1", + "IN2P", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&rt5639>; + + nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_LOW>; + + clocks = <&tegra_car TEGRA124_CLK_PLL_A>, + <&tegra_car TEGRA124_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA124_CLK_EXTERN1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; +}; diff --git a/arch/arm/boot/dts/tegra124-venice2.dts b/arch/arm/boot/dts/tegra124-venice2.dts index c17283c0459807..f0bb8424402572 100644 --- a/arch/arm/boot/dts/tegra124-venice2.dts +++ b/arch/arm/boot/dts/tegra124-venice2.dts @@ -17,6 +17,18 @@ }; host1x@0,50000000 { + hdmi@0,54280000 { + status = "okay"; + + vdd-supply = <&vdd_3v3_hdmi>; + pll-supply = <&vdd_hdmi_pll>; + hdmi-supply = <&vdd_5v0_hdmi>; + + nvidia,ddc-i2c-bus = <&hdmi_ddc>; + nvidia,hpd-gpio = + <&gpio TEGRA_GPIO(N, 7) GPIO_ACTIVE_HIGH>; + }; + sor@0,54540000 { status = "okay"; @@ -601,7 +613,7 @@ clock-frequency = <100000>; }; - i2c@0,7000c700 { + hdmi_ddc: i2c@0,7000c700 { status = "okay"; clock-frequency = <100000>; }; @@ -700,7 +712,7 @@ regulator-boot-on; }; - sd4 { + vdd_1v05_run: sd4 { regulator-name = "+1.05V_RUN"; regulator-min-microvolt = <1050000>; regulator-max-microvolt = <1050000>; @@ -931,9 +943,10 @@ sdhci@0,700b0400 { cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>; power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>; + wp-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_LOW>; status = "okay"; bus-width = <4>; - vmmc-supply = <&vddio_sdmmc3>; + vqmmc-supply = <&vddio_sdmmc3>; }; sdhci@0,700b0600 { @@ -1060,6 +1073,8 @@ regulator-name = "+3.3V_RUN"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; gpio = <&pmic 1 GPIO_ACTIVE_HIGH>; enable-active-high; vin-supply = <&vdd_3v3_sys>; @@ -1145,6 +1160,27 @@ enable-active-high; vin-supply = <&vdd_3v3_sys>; }; + + vdd_hdmi_pll: regulator@11 { + compatible = "regulator-fixed"; + reg = <11>; + regulator-name = "+1.05V_RUN_AVDD_HDMI_PLL"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + gpio = <&gpio TEGRA_GPIO(H, 7) GPIO_ACTIVE_LOW>; + vin-supply = <&vdd_1v05_run>; + }; + + vdd_5v0_hdmi: regulator@12 { + compatible = "regulator-fixed"; + reg = <12>; + regulator-name = "+5V_HDMI_CON"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio TEGRA_GPIO(K, 6) GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&vdd_5v0_sys>; + }; }; sound { diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi index 6d540a02514886..6e6bc4e8185c3e 100644 --- a/arch/arm/boot/dts/tegra124.dtsi +++ b/arch/arm/boot/dts/tegra124.dtsi @@ -51,6 +51,18 @@ nvidia,head = <1>; }; + hdmi@0,54280000 { + compatible = "nvidia,tegra124-hdmi"; + reg = <0x0 0x54280000 0x0 0x00040000>; + interrupts = ; + clocks = <&tegra_car TEGRA124_CLK_HDMI>, + <&tegra_car TEGRA124_CLK_PLL_D2_OUT0>; + clock-names = "hdmi", "parent"; + resets = <&tegra_car 51>; + reset-names = "hdmi"; + status = "disabled"; + }; + sor@0,54540000 { compatible = "nvidia,tegra124-sor"; reg = <0x0 0x54540000 0x0 0x00040000>; diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts index 3fb1f50f6d4628..f45aad688d9b52 100644 --- a/arch/arm/boot/dts/tegra20-harmony.dts +++ b/arch/arm/boot/dts/tegra20-harmony.dts @@ -28,6 +28,7 @@ hdmi@54280000 { status = "okay"; + hdmi-supply = <&vdd_5v0_hdmi>; vdd-supply = <&hdmi_vdd_reg>; pll-supply = <&hdmi_pll_reg>; @@ -724,6 +725,17 @@ gpio = <&gpio TEGRA_GPIO(W, 0) GPIO_ACTIVE_HIGH>; enable-active-high; }; + + vdd_5v0_hdmi: regulator@6 { + compatible = "regulator-fixed"; + reg = <6>; + regulator-name = "VDDIO_HDMI"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio TEGRA_GPIO(T, 2) GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&vdd_5v0_reg>; + }; }; sound { diff --git a/arch/arm/boot/dts/tegra30-beaver.dts b/arch/arm/boot/dts/tegra30-beaver.dts index e93fe45b7803e7..3189791a928976 100644 --- a/arch/arm/boot/dts/tegra30-beaver.dts +++ b/arch/arm/boot/dts/tegra30-beaver.dts @@ -40,6 +40,7 @@ hdmi@54280000 { status = "okay"; + hdmi-supply = <&vdd_5v0_hdmi>; vdd-supply = <&sys_3v3_reg>; pll-supply = <&vio_reg>; @@ -478,6 +479,17 @@ gpio = <&gpio TEGRA_GPIO(L, 7) GPIO_ACTIVE_HIGH>; vin-supply = <&sys_3v3_reg>; }; + + vdd_5v0_hdmi: regulator@8 { + compatible = "regulator-fixed"; + reg = <8>; + regulator-name = "+VDD_5V_HDMI"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&sys_3v3_reg>; + }; }; sound { diff --git a/arch/arm/boot/dts/vf610-colibri.dts b/arch/arm/boot/dts/vf610-colibri.dts new file mode 100644 index 00000000000000..aecc7dbc65e845 --- /dev/null +++ b/arch/arm/boot/dts/vf610-colibri.dts @@ -0,0 +1,123 @@ +/* + * Copyright 2014 Toradex AG + * + * 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. + */ + +/dts-v1/; +#include "vf610.dtsi" + +/ { + model = "Toradex Colibri VF61 COM"; + compatible = "toradex,vf610-colibri", "fsl,vf610"; + + chosen { + bootargs = "console=ttyLP0,115200"; + }; + + memory { + reg = <0x80000000 0x10000000>; + }; + + clocks { + enet_ext { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + }; + }; + +}; + +&esdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc1>; + bus-width = <4>; + status = "okay"; +}; + +&fec1 { + phy-mode = "rmii"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; + status = "okay"; +}; + +&L2 { + arm,data-latency = <2 1 2>; + arm,tag-latency = <3 2 3>; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart0>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&iomuxc { + vf610-colibri { + pinctrl_esdhc1: esdhc1grp { + fsl,fsl,pins = < + VF610_PAD_PTA24__ESDHC1_CLK 0x31ef + VF610_PAD_PTA25__ESDHC1_CMD 0x31ef + VF610_PAD_PTA26__ESDHC1_DAT0 0x31ef + VF610_PAD_PTA27__ESDHC1_DAT1 0x31ef + VF610_PAD_PTA28__ESDHC1_DATA2 0x31ef + VF610_PAD_PTA29__ESDHC1_DAT3 0x31ef + VF610_PAD_PTB20__GPIO_42 0x219d + >; + }; + + pinctrl_fec1: fec1grp { + fsl,pins = < + VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2 + VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3 + VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1 + VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1 + VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1 + VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1 + VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2 + VF610_PAD_PTC16__ENET_RMII1_TXD0 0x30d2 + VF610_PAD_PTC17__ENET_RMII1_TXEN 0x30d2 + >; + }; + + pinctrl_uart0: uart0grp { + fsl,pins = < + VF610_PAD_PTB10__UART0_TX 0x21a2 + VF610_PAD_PTB11__UART0_RX 0x21a1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + VF610_PAD_PTB4__UART1_TX 0x21a2 + VF610_PAD_PTB5__UART1_RX 0x21a1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + VF610_PAD_PTD0__UART2_TX 0x21a2 + VF610_PAD_PTD1__UART2_RX 0x21a1 + VF610_PAD_PTD2__UART2_RTS 0x21a2 + VF610_PAD_PTD3__UART2_CTS 0x21a1 + >; + }; + }; +}; diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts index ded361075aab7a..11d733406c7ed5 100644 --- a/arch/arm/boot/dts/vf610-twr.dts +++ b/arch/arm/boot/dts/vf610-twr.dts @@ -113,6 +113,13 @@ }; }; +&esdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc1>; + bus-width = <4>; + status = "okay"; +}; + &fec0 { phy-mode = "rmii"; pinctrl-names = "default"; @@ -160,6 +167,18 @@ >; }; + pinctrl_esdhc1: esdhc1grp { + fsl,fsl,pins = < + VF610_PAD_PTA24__ESDHC1_CLK 0x31ef + VF610_PAD_PTA25__ESDHC1_CMD 0x31ef + VF610_PAD_PTA26__ESDHC1_DAT0 0x31ef + VF610_PAD_PTA27__ESDHC1_DAT1 0x31ef + VF610_PAD_PTA28__ESDHC1_DATA2 0x31ef + VF610_PAD_PTA29__ESDHC1_DAT3 0x31ef + VF610_PAD_PTA7__GPIO_134 0x219d + >; + }; + pinctrl_fec0: fec0grp { fsl,pins = < VF610_PAD_PTA6__RMII_CLKIN 0x30d1 @@ -196,6 +215,17 @@ >; }; + pinctrl_pwm0: pwm0grp { + fsl,pins = < + VF610_PAD_PTB0__FTM0_CH0 0x1582 + VF610_PAD_PTB1__FTM0_CH1 0x1582 + VF610_PAD_PTB2__FTM0_CH2 0x1582 + VF610_PAD_PTB3__FTM0_CH3 0x1582 + VF610_PAD_PTB6__FTM0_CH6 0x1582 + VF610_PAD_PTB7__FTM0_CH7 0x1582 + >; + }; + pinctrl_sai2: sai2grp { fsl,pins = < VF610_PAD_PTA16__SAI2_TX_BCLK 0x02ed @@ -217,6 +247,12 @@ }; }; +&pwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0>; + status = "okay"; +}; + &sai2 { #sound-dai-cells = <0>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi index b8ce0aa7b15790..73355ddc51861c 100644 --- a/arch/arm/boot/dts/vf610.dtsi +++ b/arch/arm/boot/dts/vf610.dtsi @@ -183,6 +183,19 @@ clock-names = "pit"; }; + pwm0: pwm@40038000 { + compatible = "fsl,vf610-ftm-pwm"; + #pwm-cells = <3>; + reg = <0x40038000 0x1000>; + clock-names = "ftm_sys", "ftm_ext", + "ftm_fix", "ftm_cnt_clk_en"; + clocks = <&clks VF610_CLK_FTM0>, + <&clks VF610_CLK_FTM0_EXT_SEL>, + <&clks VF610_CLK_FTM0_FIX_SEL>, + <&clks VF610_CLK_FTM0_EXT_FIX_EN>; + status = "disabled"; + }; + adc0: adc@4003b000 { compatible = "fsl,vf610-adc"; reg = <0x4003b000 0x1000>; @@ -347,6 +360,17 @@ status = "disabled"; }; + esdhc1: esdhc@400b2000 { + compatible = "fsl,imx53-esdhc"; + reg = <0x400b2000 0x4000>; + interrupts = <0 28 0x04>; + clocks = <&clks VF610_CLK_IPG_BUS>, + <&clks VF610_CLK_PLATFORM_BUS>, + <&clks VF610_CLK_ESDHC1>; + clock-names = "ipg", "ahb", "per"; + status = "disabled"; + }; + fec0: ethernet@400d0000 { compatible = "fsl,mvf600-fec"; reg = <0x400d0000 0x1000>; diff --git a/arch/arm/boot/dts/vt8500.dtsi b/arch/arm/boot/dts/vt8500.dtsi index 51d0e912c8f585..1929ad390d88fe 100644 --- a/arch/arm/boot/dts/vt8500.dtsi +++ b/arch/arm/boot/dts/vt8500.dtsi @@ -165,5 +165,11 @@ reg = <0xd8100000 0x10000>; interrupts = <48>; }; + + ethernet@d8004000 { + compatible = "via,vt8500-rhine"; + reg = <0xd8004000 0x100>; + interrupts = <10>; + }; }; }; diff --git a/arch/arm/boot/dts/wm8650.dtsi b/arch/arm/boot/dts/wm8650.dtsi index 7525982262ac98..b1c59a766a1338 100644 --- a/arch/arm/boot/dts/wm8650.dtsi +++ b/arch/arm/boot/dts/wm8650.dtsi @@ -218,5 +218,11 @@ reg = <0xd8100000 0x10000>; interrupts = <48>; }; + + ethernet@d8004000 { + compatible = "via,vt8500-rhine"; + reg = <0xd8004000 0x100>; + interrupts = <10>; + }; }; }; diff --git a/arch/arm/boot/dts/wm8850.dtsi b/arch/arm/boot/dts/wm8850.dtsi index d98386dd288250..8fbccfbe75f33d 100644 --- a/arch/arm/boot/dts/wm8850.dtsi +++ b/arch/arm/boot/dts/wm8850.dtsi @@ -298,5 +298,11 @@ bus-width = <4>; sdon-inverted; }; + + ethernet@d8004000 { + compatible = "via,vt8500-rhine"; + reg = <0xd8004000 0x100>; + interrupts = <10>; + }; }; }; diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c index 41bca32409fce8..25fa735abc6cb3 100644 --- a/arch/arm/common/edma.c +++ b/arch/arm/common/edma.c @@ -994,29 +994,23 @@ void edma_set_dest(unsigned slot, dma_addr_t dest_port, EXPORT_SYMBOL(edma_set_dest); /** - * edma_get_position - returns the current transfer points + * edma_get_position - returns the current transfer point * @slot: parameter RAM slot being examined - * @src: pointer to source port position - * @dst: pointer to destination port position + * @dst: true selects the dest position, false the source * - * Returns current source and destination addresses for a particular - * parameter RAM slot. Its channel should not be active when this is called. + * Returns the position of the current active slot */ -void edma_get_position(unsigned slot, dma_addr_t *src, dma_addr_t *dst) +dma_addr_t edma_get_position(unsigned slot, bool dst) { - struct edmacc_param temp; - unsigned ctlr; + u32 offs, ctlr = EDMA_CTLR(slot); - ctlr = EDMA_CTLR(slot); slot = EDMA_CHAN_SLOT(slot); - edma_read_slot(EDMA_CTLR_CHAN(ctlr, slot), &temp); - if (src != NULL) - *src = temp.src; - if (dst != NULL) - *dst = temp.dst; + offs = PARM_OFFSET(slot); + offs += dst ? PARM_DST : PARM_SRC; + + return edma_read(ctlr, offs); } -EXPORT_SYMBOL(edma_get_position); /** * edma_set_src_index - configure DMA source address indexing @@ -1574,6 +1568,7 @@ static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev, return ERR_PTR(ret); dma_cap_set(DMA_SLAVE, edma_filter_info.dma_cap); + dma_cap_set(DMA_CYCLIC, edma_filter_info.dma_cap); of_dma_controller_register(dev->of_node, of_dma_simple_xlate, &edma_filter_info); @@ -1768,6 +1763,9 @@ static int edma_probe(struct platform_device *pdev) map_queue_tc(j, queue_tc_mapping[i][0], queue_tc_mapping[i][1]); + /* Save the number of TCs */ + edma_cc[j]->num_tc = i; + /* Event queue priority mapping */ for (i = 0; queue_priority_mapping[i][0] != -1; i++) assign_priority_to_queue(j, diff --git a/arch/arm/configs/dove_defconfig b/arch/arm/configs/dove_defconfig index f1595514417560..701677f9248c2f 100644 --- a/arch/arm/configs/dove_defconfig +++ b/arch/arm/configs/dove_defconfig @@ -37,7 +37,6 @@ CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -48,6 +47,7 @@ CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_STAA=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_M25P80=y +CONFIG_MTD_SPI_NOR=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=1 diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig index f1aeb7d727125a..bada59d93b6753 100644 --- a/arch/arm/configs/imx_v4_v5_defconfig +++ b/arch/arm/configs/imx_v4_v5_defconfig @@ -80,6 +80,7 @@ CONFIG_MTD_UBI=y CONFIG_EEPROM_AT24=y CONFIG_EEPROM_AT25=y CONFIG_ATA=y +CONFIG_BLK_DEV_SD=y CONFIG_PATA_IMX=y CONFIG_NETDEVICES=y CONFIG_CS89x0=y @@ -153,8 +154,12 @@ CONFIG_USB_HID=m CONFIG_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MXC=y +CONFIG_USB_STORAGE=y +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_NOP_USB_XCEIV=y CONFIG_MMC=y -CONFIG_MMC_UNSAFE_RESUME=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_ESDHC_IMX=y @@ -177,7 +182,6 @@ CONFIG_RTC_DRV_MXC=y CONFIG_DMADEVICES=y CONFIG_IMX_SDMA=y CONFIG_IMX_DMA=y -CONFIG_COMMON_CLK_DEBUG=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 09e974392fa119..9fc30243ecfe65 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -1,4 +1,3 @@ -# CONFIG_LOCALVERSION_AUTO is not set CONFIG_KERNEL_LZO=y CONFIG_SYSVIPC=y CONFIG_NO_HZ=y @@ -46,7 +45,11 @@ CONFIG_VMSPLIT_2G=y CONFIG_PREEMPT_VOLUNTARY=y CONFIG_AEABI=y CONFIG_HIGHMEM=y +CONFIG_CMA=y CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_ARM_IMX6Q_CPUFREQ=y CONFIG_VFP=y CONFIG_NEON=y CONFIG_BINFMT_MISC=m @@ -72,6 +75,7 @@ CONFIG_RFKILL_INPUT=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set +CONFIG_DMA_CMA=y CONFIG_IMX_WEIM=y CONFIG_CONNECTOR=y CONFIG_MTD=y @@ -183,6 +187,7 @@ CONFIG_V4L_MEM2MEM_DRIVERS=y CONFIG_VIDEO_CODA=y CONFIG_SOC_CAMERA_OV2640=y CONFIG_DRM=y +CONFIG_DRM_PANEL_SIMPLE=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_L4F00242T03=y @@ -209,13 +214,14 @@ CONFIG_USB_STORAGE=y CONFIG_USB_CHIPIDEA=y CONFIG_USB_CHIPIDEA_UDC=y CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_OTG_FSM=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_MXS_PHY=y +CONFIG_USB_ULPI=y CONFIG_USB_GADGET=y CONFIG_USB_ETH=m CONFIG_USB_MASS_STORAGE=m CONFIG_MMC=y -CONFIG_MMC_UNSAFE_RESUME=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_ESDHC_IMX=y @@ -245,7 +251,7 @@ CONFIG_DRM_IMX_TVE=y CONFIG_DRM_IMX_LDB=y CONFIG_DRM_IMX_IPUV3_CORE=y CONFIG_DRM_IMX_IPUV3=y -CONFIG_COMMON_CLK_DEBUG=y +CONFIG_DRM_IMX_HDMI=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_PWM=y CONFIG_PWM_IMX=y diff --git a/arch/arm/configs/integrator_defconfig b/arch/arm/configs/integrator_defconfig index 5bae1955759125..c1f5adc5493e84 100644 --- a/arch/arm/configs/integrator_defconfig +++ b/arch/arm/configs/integrator_defconfig @@ -73,7 +73,6 @@ CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_LEDS_TRIGGER_CPU=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_PL030=y -CONFIG_COMMON_CLK_DEBUG=y CONFIG_EXT2_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig index ec9a41d506803e..07b43277ccd3a0 100644 --- a/arch/arm/configs/keystone_defconfig +++ b/arch/arm/configs/keystone_defconfig @@ -112,6 +112,7 @@ CONFIG_MTD_PLATRAM=y CONFIG_MTD_M25P80=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_DAVINCI=y +CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=y CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y @@ -146,7 +147,6 @@ CONFIG_USB_DWC3_VERBOSE=y CONFIG_KEYSTONE_USB_PHY=y CONFIG_DMADEVICES=y CONFIG_TI_EDMA=y -CONFIG_COMMON_CLK_DEBUG=y CONFIG_MEMORY=y CONFIG_TI_AEMIF=y CONFIG_EXT4_FS=y diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig index 2e762d94e94b31..b9e480c10b1088 100644 --- a/arch/arm/configs/kirkwood_defconfig +++ b/arch/arm/configs/kirkwood_defconfig @@ -61,6 +61,7 @@ CONFIG_MTD_PHYSMAP=y CONFIG_MTD_M25P80=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_ORION=y +CONFIG_MTD_SPI_NOR=y CONFIG_BLK_DEV_LOOP=y CONFIG_EEPROM_AT24=y # CONFIG_SCSI_PROC_FS is not set diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v5_defconfig index aa3dfb084fed6b..5ebfa8bf85094b 100644 --- a/arch/arm/configs/multi_v5_defconfig +++ b/arch/arm/configs/multi_v5_defconfig @@ -11,7 +11,6 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_MVEBU=y CONFIG_MACH_KIRKWOOD=y -CONFIG_MACH_T5325=y CONFIG_ARCH_MXC=y CONFIG_MACH_IMX25_DT=y CONFIG_MACH_IMX27_DT=y @@ -108,6 +107,8 @@ CONFIG_SND=y CONFIG_SND_SOC=y CONFIG_SND_KIRKWOOD_SOC=y CONFIG_SND_KIRKWOOD_SOC_T5325=y +CONFIG_SND_SOC_ALC5623=y +CONFIG_SND_SIMPLE_CARD=y # CONFIG_ABX500_CORE is not set CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index d4e8a47a2f7c8a..5039cc6cedc061 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -20,6 +20,7 @@ CONFIG_ARCH_BCM_MOBILE=y CONFIG_ARCH_BERLIN=y CONFIG_MACH_BERLIN_BG2=y CONFIG_MACH_BERLIN_BG2CD=y +CONFIG_MACH_BERLIN_BG2Q=y CONFIG_GPIO_PCA953X=y CONFIG_ARCH_HIGHBANK=y CONFIG_ARCH_HI3xxx=y @@ -112,6 +113,7 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_ICS932S401=y CONFIG_APDS9802ALS=y CONFIG_ISL29003=y +CONFIG_EEPROM_AT24=y CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y CONFIG_SCSI_MULTI_LUN=y @@ -191,6 +193,7 @@ CONFIG_PINCTRL_AS3722=y CONFIG_PINCTRL_PALMAS=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_GPIO_DWAPB=y CONFIG_GPIO_PCA953X_IRQ=y CONFIG_GPIO_TWL4030=y CONFIG_GPIO_PALMAS=y @@ -273,6 +276,7 @@ CONFIG_MMC_BLOCK_MINORS=16 CONFIG_MMC_ARMMMCI=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ESDHC_IMX=y +CONFIG_MMC_SDHCI_PXAV3=y CONFIG_MMC_SDHCI_TEGRA=y CONFIG_MMC_SDHCI_DOVE=y CONFIG_MMC_SDHCI_SPEAR=y diff --git a/arch/arm/configs/mvebu_v5_defconfig b/arch/arm/configs/mvebu_v5_defconfig index 36484a37a1ca19..27c732fdf21eae 100644 --- a/arch/arm/configs/mvebu_v5_defconfig +++ b/arch/arm/configs/mvebu_v5_defconfig @@ -1,4 +1,5 @@ CONFIG_SYSVIPC=y +CONFIG_FHANDLE=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=19 @@ -11,7 +12,6 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_MVEBU=y CONFIG_MACH_KIRKWOOD=y -CONFIG_MACH_T5325=y # CONFIG_CPU_FEROCEON_OLD_ID is not set CONFIG_PCI_MVEBU=y CONFIG_PREEMPT=y @@ -50,6 +50,7 @@ CONFIG_MTD_PHYSMAP=y CONFIG_MTD_M25P80=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_ORION=y +CONFIG_MTD_SPI_NOR=y CONFIG_BLK_DEV_LOOP=y CONFIG_EEPROM_AT24=y # CONFIG_SCSI_PROC_FS is not set @@ -100,6 +101,8 @@ CONFIG_SND=y CONFIG_SND_SOC=y CONFIG_SND_KIRKWOOD_SOC=y CONFIG_SND_KIRKWOOD_SOC_T5325=y +CONFIG_SND_SOC_ALC5623=y +CONFIG_SND_SIMPLE_CARD=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_HID_DRAGONRISE=y diff --git a/arch/arm/configs/mvebu_v7_defconfig b/arch/arm/configs/mvebu_v7_defconfig index a34713d8db9f6c..b52a6f5c52256a 100644 --- a/arch/arm/configs/mvebu_v7_defconfig +++ b/arch/arm/configs/mvebu_v7_defconfig @@ -1,5 +1,6 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_FHANDLE=y CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 @@ -29,6 +30,9 @@ CONFIG_ARM_ATAG_DTB_COMPAT=y CONFIG_VFP=y CONFIG_NET=y CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y CONFIG_BT=y CONFIG_BT_MRVL=y CONFIG_BT_MRVL_SDIO=y @@ -36,6 +40,7 @@ CONFIG_CFG80211=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_BLK_DEV_SD=y CONFIG_ATA=y +CONFIG_AHCI_MVEBU=y CONFIG_SATA_MV=y CONFIG_NETDEVICES=y CONFIG_MVNETA=y @@ -53,6 +58,7 @@ CONFIG_I2C_MV64XXX=y CONFIG_MTD=y CONFIG_MTD_CHAR=y CONFIG_MTD_M25P80=y +CONFIG_MTD_SPI_NOR=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y @@ -79,6 +85,7 @@ CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_STORAGE=y CONFIG_USB_XHCI_HCD=y CONFIG_MMC=y +CONFIG_MMC_SDHCI_PXAV3=y CONFIG_MMC_MVSDIO=y CONFIG_NEW_LEDS=y CONFIG_LEDS_GPIO=y @@ -103,6 +110,8 @@ CONFIG_UDF_FS=m CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y CONFIG_NLS_ISO8859_1=y diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index 6150108e15de85..51702398557d0b 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -26,7 +26,6 @@ CONFIG_ARCH_MXS=y # CONFIG_ARM_THUMB is not set CONFIG_PREEMPT_VOLUNTARY=y CONFIG_AEABI=y -CONFIG_FPE_NWFPE=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -51,7 +50,6 @@ CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_DATAFLASH=y CONFIG_MTD_M25P80=y -# CONFIG_M25PXX_USE_FAST_READ is not set CONFIG_MTD_SST25L=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_GPMI_NAND=y @@ -120,7 +118,6 @@ CONFIG_USB_GADGET=y CONFIG_USB_ETH=m CONFIG_USB_MASS_STORAGE=m CONFIG_MMC=y -CONFIG_MMC_UNSAFE_RESUME=y CONFIG_MMC_MXS=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -138,7 +135,6 @@ CONFIG_DMADEVICES=y CONFIG_MXS_DMA=y CONFIG_STAGING=y CONFIG_MXS_LRADC=y -CONFIG_COMMON_CLK_DEBUG=y CONFIG_IIO=y CONFIG_IIO_SYSFS_TRIGGER=y CONFIG_PWM=y @@ -180,7 +176,7 @@ CONFIG_BLK_DEV_IO_TRACE=y CONFIG_STRICT_DEVMEM=y CONFIG_DEBUG_USER=y # CONFIG_CRYPTO_ANSI_CPRNG is not set -# CONFIG_CRYPTO_HW is not set +CONFIG_CRYPTO_DEV_MXS_DCP=y CONFIG_CRC_ITU_T=m CONFIG_CRC7=m CONFIG_FONTS=y diff --git a/arch/arm/configs/realview-smp_defconfig b/arch/arm/configs/realview-smp_defconfig index abe61bf379d265..1da5d9e4822424 100644 --- a/arch/arm/configs/realview-smp_defconfig +++ b/arch/arm/configs/realview-smp_defconfig @@ -76,8 +76,10 @@ CONFIG_MMC=y CONFIG_MMC_ARMMMCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y +CONFIG_LEDS_VERSATILE=y CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y CONFIG_RTC_DRV_PL031=y diff --git a/arch/arm/configs/realview_defconfig b/arch/arm/configs/realview_defconfig index 7079cbe898a8c8..d02e9d911bb729 100644 --- a/arch/arm/configs/realview_defconfig +++ b/arch/arm/configs/realview_defconfig @@ -75,8 +75,10 @@ CONFIG_MMC=y CONFIG_MMC_ARMMMCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y +CONFIG_LEDS_VERSATILE=y CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y CONFIG_RTC_DRV_PL031=y diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig index 83b07258a385b4..6d6437cbbc523b 100644 --- a/arch/arm/configs/shmobile_defconfig +++ b/arch/arm/configs/shmobile_defconfig @@ -25,6 +25,7 @@ CONFIG_SCHED_MC=y CONFIG_HAVE_ARM_ARCH_TIMER=y CONFIG_NR_CPUS=8 CONFIG_AEABI=y +CONFIG_HIGHMEM=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_ARM_APPENDED_DTB=y @@ -43,6 +44,7 @@ CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y CONFIG_MTD_M25P80=y +CONFIG_EEPROM_AT24=y CONFIG_BLK_DEV_SD=y CONFIG_ATA=y CONFIG_SATA_RCAR=y @@ -75,9 +77,11 @@ CONFIG_SERIAL_SH_SCI=y CONFIG_SERIAL_SH_SCI_NR_UARTS=20 CONFIG_SERIAL_SH_SCI_CONSOLE=y CONFIG_I2C_GPIO=y +CONFIG_I2C_SH_MOBILE=y CONFIG_I2C_RCAR=y CONFIG_SPI=y CONFIG_SPI_RSPI=y +CONFIG_SPI_SH_MSIOF=y CONFIG_GPIO_EM=y CONFIG_GPIO_RCAR=y # CONFIG_HWMON is not set @@ -88,10 +92,14 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_GPIO=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_SOC_CAMERA=y CONFIG_SOC_CAMERA_PLATFORM=y CONFIG_VIDEO_RCAR_VIN=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_RENESAS_VSP1=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_VIDEO_ADV7180=y CONFIG_DRM=y @@ -100,7 +108,13 @@ CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SOC=y CONFIG_SND_SOC_RCAR=y +CONFIG_USB=y CONFIG_USB_RCAR_GEN2_PHY=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_RENESAS_USBHS=y +CONFIG_USB_GADGET=y +CONFIG_USB_RENESAS_USBHS_UDC=y CONFIG_MMC=y CONFIG_MMC_SDHI=y CONFIG_MMC_SH_MMCIF=y diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig index b5df4a511b0acd..28287aebdc15ca 100644 --- a/arch/arm/configs/sunxi_defconfig +++ b/arch/arm/configs/sunxi_defconfig @@ -62,7 +62,6 @@ CONFIG_LEDS_GPIO=y CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_COMMON_CLK_DEBUG=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_TMPFS=y CONFIG_NFS_FS=y diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig index 2926281368ab66..8c1625b78034f2 100644 --- a/arch/arm/configs/tegra_defconfig +++ b/arch/arm/configs/tegra_defconfig @@ -90,6 +90,7 @@ CONFIG_DMA_CMA=y CONFIG_CMA_SIZE_MBYTES=64 CONFIG_MTD=y CONFIG_MTD_M25P80=y +CONFIG_MTD_SPI_NOR=y CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_AD525X_DPOT=y @@ -97,6 +98,7 @@ CONFIG_AD525X_DPOT_I2C=y CONFIG_ICS932S401=y CONFIG_APDS9802ALS=y CONFIG_ISL29003=y +CONFIG_EEPROM_AT24=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y @@ -181,6 +183,7 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_BACKLIGHT_GENERIC is not set CONFIG_BACKLIGHT_PWM=y CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y CONFIG_LOGO=y CONFIG_SOUND=y CONFIG_SND=y diff --git a/arch/arm/configs/versatile_defconfig b/arch/arm/configs/versatile_defconfig index 073541a50e2313..d52b4ffe2012cc 100644 --- a/arch/arm/configs/versatile_defconfig +++ b/arch/arm/configs/versatile_defconfig @@ -61,6 +61,9 @@ CONFIG_SND_ARMAACI=m CONFIG_MMC=y CONFIG_MMC_ARMMMCI=m CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_VERSATILE=y +CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_LEDS_TRIGGER_CPU=y CONFIG_EXT2_FS=y diff --git a/arch/arm/configs/vt8500_v6_v7_defconfig b/arch/arm/configs/vt8500_v6_v7_defconfig index f0520176acd06d..9e7a256396904b 100644 --- a/arch/arm/configs/vt8500_v6_v7_defconfig +++ b/arch/arm/configs/vt8500_v6_v7_defconfig @@ -73,7 +73,6 @@ CONFIG_LEDS_TRIGGERS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_VT8500=y CONFIG_DMADEVICES=y -CONFIG_COMMON_CLK_DEBUG=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_PWM=y CONFIG_PWM_VT8500=y diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index b974184f994188..57f0584e8d97dc 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -312,7 +312,7 @@ * you cannot return to the original mode. */ .macro safe_svcmode_maskall reg:req -#if __LINUX_ARM_ARCH__ >= 6 +#if __LINUX_ARM_ARCH__ >= 6 && !defined(CONFIG_CPU_V7M) mrs \reg , cpsr eor \reg, \reg, #HYP_MODE tst \reg, #MODE_MASK diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index 9a92fd7864a841..3040359094d93a 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -241,11 +241,6 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0) -#define smp_mb__before_atomic_dec() smp_mb() -#define smp_mb__after_atomic_dec() smp_mb() -#define smp_mb__before_atomic_inc() smp_mb() -#define smp_mb__after_atomic_inc() smp_mb() - #ifndef CONFIG_GENERIC_ATOMIC64 typedef struct { long long counter; diff --git a/arch/arm/include/asm/barrier.h b/arch/arm/include/asm/barrier.h index 2f59f744339640..c6a3e73a6e2407 100644 --- a/arch/arm/include/asm/barrier.h +++ b/arch/arm/include/asm/barrier.h @@ -79,5 +79,8 @@ do { \ #define set_mb(var, value) do { var = value; smp_mb(); } while (0) +#define smp_mb__before_atomic() smp_mb() +#define smp_mb__after_atomic() smp_mb() + #endif /* !__ASSEMBLY__ */ #endif /* __ASM_BARRIER_H */ diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h index b2e298a90d76fa..56380995f4c383 100644 --- a/arch/arm/include/asm/bitops.h +++ b/arch/arm/include/asm/bitops.h @@ -25,9 +25,7 @@ #include #include - -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() +#include /* * These functions are the basis of our bit ops. diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index e701a4d9aa591f..c45b61a4b4a525 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -58,21 +58,37 @@ static inline int dma_set_mask(struct device *dev, u64 mask) #ifndef __arch_pfn_to_dma static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn) { + if (dev) + pfn -= dev->dma_pfn_offset; return (dma_addr_t)__pfn_to_bus(pfn); } static inline unsigned long dma_to_pfn(struct device *dev, dma_addr_t addr) { - return __bus_to_pfn(addr); + unsigned long pfn = __bus_to_pfn(addr); + + if (dev) + pfn += dev->dma_pfn_offset; + + return pfn; } static inline void *dma_to_virt(struct device *dev, dma_addr_t addr) { + if (dev) { + unsigned long pfn = dma_to_pfn(dev, addr); + + return phys_to_virt(__pfn_to_phys(pfn)); + } + return (void *)__bus_to_virt((unsigned long)addr); } static inline dma_addr_t virt_to_dma(struct device *dev, void *addr) { + if (dev) + return pfn_to_dma(dev, virt_to_pfn(addr)); + return (dma_addr_t)__virt_to_bus((unsigned long)(addr)); } @@ -105,6 +121,13 @@ static inline unsigned long dma_max_pfn(struct device *dev) } #define dma_max_pfn(dev) dma_max_pfn(dev) +static inline int set_arch_dma_coherent_ops(struct device *dev) +{ + set_dma_ops(dev, &arm_coherent_dma_ops); + return 0; +} +#define set_arch_dma_coherent_ops(dev) set_arch_dma_coherent_ops(dev) + static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) { unsigned int offset = paddr & ~PAGE_MASK; diff --git a/arch/arm/include/asm/fixmap.h b/arch/arm/include/asm/fixmap.h index bbae919bceb4b5..74124b0d0d7952 100644 --- a/arch/arm/include/asm/fixmap.h +++ b/arch/arm/include/asm/fixmap.h @@ -1,24 +1,11 @@ #ifndef _ASM_FIXMAP_H #define _ASM_FIXMAP_H -/* - * Nothing too fancy for now. - * - * On ARM we already have well known fixed virtual addresses imposed by - * the architecture such as the vector page which is located at 0xffff0000, - * therefore a second level page table is already allocated covering - * 0xfff00000 upwards. - * - * The cache flushing code in proc-xscale.S uses the virtual area between - * 0xfffe0000 and 0xfffeffff. - */ - -#define FIXADDR_START 0xfff00000UL -#define FIXADDR_TOP 0xfffe0000UL +#define FIXADDR_START 0xffc00000UL +#define FIXADDR_TOP 0xffe00000UL #define FIXADDR_SIZE (FIXADDR_TOP - FIXADDR_START) -#define FIX_KMAP_BEGIN 0 -#define FIX_KMAP_END (FIXADDR_SIZE >> PAGE_SHIFT) +#define FIX_KMAP_NR_PTES (FIXADDR_SIZE >> PAGE_SHIFT) #define __fix_to_virt(x) (FIXADDR_START + ((x) << PAGE_SHIFT)) #define __virt_to_fix(x) (((x) - FIXADDR_START) >> PAGE_SHIFT) @@ -27,7 +14,7 @@ extern void __this_fixmap_does_not_exist(void); static inline unsigned long fix_to_virt(const unsigned int idx) { - if (idx >= FIX_KMAP_END) + if (idx >= FIX_KMAP_NR_PTES) __this_fixmap_does_not_exist(); return __fix_to_virt(idx); } diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h index c81adc08b3fba5..a3c24cd5b7c8ee 100644 --- a/arch/arm/include/asm/glue-cache.h +++ b/arch/arm/include/asm/glue-cache.h @@ -130,22 +130,22 @@ #endif #ifndef __ASSEMBLER__ -extern inline void nop_flush_icache_all(void) { } -extern inline void nop_flush_kern_cache_all(void) { } -extern inline void nop_flush_kern_cache_louis(void) { } -extern inline void nop_flush_user_cache_all(void) { } -extern inline void nop_flush_user_cache_range(unsigned long a, +static inline void nop_flush_icache_all(void) { } +static inline void nop_flush_kern_cache_all(void) { } +static inline void nop_flush_kern_cache_louis(void) { } +static inline void nop_flush_user_cache_all(void) { } +static inline void nop_flush_user_cache_range(unsigned long a, unsigned long b, unsigned int c) { } -extern inline void nop_coherent_kern_range(unsigned long a, unsigned long b) { } -extern inline int nop_coherent_user_range(unsigned long a, +static inline void nop_coherent_kern_range(unsigned long a, unsigned long b) { } +static inline int nop_coherent_user_range(unsigned long a, unsigned long b) { return 0; } -extern inline void nop_flush_kern_dcache_area(void *a, size_t s) { } +static inline void nop_flush_kern_dcache_area(void *a, size_t s) { } -extern inline void nop_dma_flush_range(const void *a, const void *b) { } +static inline void nop_dma_flush_range(const void *a, const void *b) { } -extern inline void nop_dma_map_area(const void *s, size_t l, int f) { } -extern inline void nop_dma_unmap_area(const void *s, size_t l, int f) { } +static inline void nop_dma_map_area(const void *s, size_t l, int f) { } +static inline void nop_dma_unmap_area(const void *s, size_t l, int f) { } #endif #ifndef MULTI_CACHE diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h index 91b99abe7a95c1..535579511ed035 100644 --- a/arch/arm/include/asm/highmem.h +++ b/arch/arm/include/asm/highmem.h @@ -18,6 +18,7 @@ } while (0) extern pte_t *pkmap_page_table; +extern pte_t *fixmap_page_table; extern void *kmap_high(struct page *page); extern void kunmap_high(struct page *page); diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 09af14999c9b24..193ceaf01bfd00 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -36,7 +36,7 @@ #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 #define KVM_HAVE_ONE_REG -#define KVM_VCPU_MAX_FEATURES 1 +#define KVM_VCPU_MAX_FEATURES 2 #include diff --git a/arch/arm/include/asm/kvm_psci.h b/arch/arm/include/asm/kvm_psci.h index 9a83d98bf170c2..6bda945d31fa8e 100644 --- a/arch/arm/include/asm/kvm_psci.h +++ b/arch/arm/include/asm/kvm_psci.h @@ -18,6 +18,10 @@ #ifndef __ARM_KVM_PSCI_H__ #define __ARM_KVM_PSCI_H__ -bool kvm_psci_call(struct kvm_vcpu *vcpu); +#define KVM_ARM_PSCI_0_1 1 +#define KVM_ARM_PSCI_0_2 2 + +int kvm_psci_version(struct kvm_vcpu *vcpu); +int kvm_psci_call(struct kvm_vcpu *vcpu); #endif /* __ARM_KVM_PSCI_H__ */ diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 02fa2558f6626a..2b751464d6ff19 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -83,8 +83,6 @@ */ #define IOREMAP_MAX_ORDER 24 -#define CONSISTENT_END (0xffe00000UL) - #else /* CONFIG_MMU */ /* diff --git a/arch/arm/include/asm/prom.h b/arch/arm/include/asm/prom.h index b681575ad3de9c..cd94ef2ef283e1 100644 --- a/arch/arm/include/asm/prom.h +++ b/arch/arm/include/asm/prom.h @@ -14,7 +14,6 @@ #ifdef CONFIG_OF extern const struct machine_desc *setup_machine_fdt(unsigned int dt_phys); -extern void arm_dt_memblock_reserve(void); extern void __init arm_dt_init_cpu_maps(void); #else /* CONFIG_OF */ @@ -24,7 +23,6 @@ static inline const struct machine_desc *setup_machine_fdt(unsigned int dt_phys) return NULL; } -static inline void arm_dt_memblock_reserve(void) { } static inline void arm_dt_init_cpu_maps(void) { } #endif /* CONFIG_OF */ diff --git a/arch/arm/include/debug/vf.S b/arch/arm/include/debug/vf.S index ba12cc44b2cb52..b88933849a17e1 100644 --- a/arch/arm/include/debug/vf.S +++ b/arch/arm/include/debug/vf.S @@ -7,9 +7,20 @@ * */ +#define VF_UART0_BASE_ADDR 0x40027000 +#define VF_UART1_BASE_ADDR 0x40028000 +#define VF_UART2_BASE_ADDR 0x40029000 +#define VF_UART3_BASE_ADDR 0x4002a000 +#define VF_UART_BASE_ADDR(n) VF_UART##n##_BASE_ADDR +#define VF_UART_BASE(n) VF_UART_BASE_ADDR(n) +#define VF_UART_PHYSICAL_BASE VF_UART_BASE(CONFIG_DEBUG_VF_UART_PORT) + +#define VF_UART_VIRTUAL_BASE 0xfe000000 + .macro addruart, rp, rv, tmp - ldr \rp, =0x40028000 @ physical - ldr \rv, =0xfe028000 @ virtual + ldr \rp, =VF_UART_PHYSICAL_BASE @ physical + and \rv, \rp, #0xffffff @ offset within 16MB section + add \rv, \rv, #VF_UART_VIRTUAL_BASE .endm .macro senduart, rd, rx diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index ef0c8785ba165f..e6ebdd3471e566 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -20,6 +20,7 @@ #define __ARM_KVM_H__ #include +#include #include #define __KVM_HAVE_GUEST_DEBUG @@ -83,6 +84,7 @@ struct kvm_regs { #define KVM_VGIC_V2_CPU_SIZE 0x2000 #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ +#define KVM_ARM_VCPU_PSCI_0_2 1 /* CPU uses PSCI v0.2 */ struct kvm_vcpu_init { __u32 target; @@ -201,9 +203,9 @@ struct kvm_arch_memory_slot { #define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2) #define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3) -#define KVM_PSCI_RET_SUCCESS 0 -#define KVM_PSCI_RET_NI ((unsigned long)-1) -#define KVM_PSCI_RET_INVAL ((unsigned long)-2) -#define KVM_PSCI_RET_DENIED ((unsigned long)-3) +#define KVM_PSCI_RET_SUCCESS PSCI_RET_SUCCESS +#define KVM_PSCI_RET_NI PSCI_RET_NOT_SUPPORTED +#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS +#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED #endif /* __ARM_KVM_H__ */ diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 040619c32d68df..38ddd9f83d0e58 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o +obj-$(CONFIG_HIBERNATION) += hibernate.o obj-$(CONFIG_SMP) += smp.o ifdef CONFIG_MMU obj-$(CONFIG_SMP) += smp_tlb.o diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index c7419a585ddc6e..3e5a2056a466d5 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -32,38 +32,6 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) arm_add_memory(base, size); } -void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) -{ - return memblock_virt_alloc(size, align); -} - -void __init arm_dt_memblock_reserve(void) -{ - u64 *reserve_map, base, size; - - if (!initial_boot_params) - return; - - /* Reserve the dtb region */ - memblock_reserve(virt_to_phys(initial_boot_params), - be32_to_cpu(initial_boot_params->totalsize)); - - /* - * Process the reserve map. This will probably overlap the initrd - * and dtb locations which are already reserved, but overlaping - * doesn't hurt anything - */ - reserve_map = ((void*)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_mem_rsvmap); - while (1) { - base = be64_to_cpup(reserve_map++); - size = be64_to_cpup(reserve_map++); - if (!size) - break; - memblock_reserve(base, size); - } -} - #ifdef CONFIG_SMP extern struct of_cpu_method __cpu_method_of_table_begin[]; extern struct of_cpu_method __cpu_method_of_table_end[]; @@ -252,7 +220,7 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) if (!mdesc) { const char *prop; - long size; + int size; unsigned long dt_root; early_print("\nError: unrecognized/unsupported " diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 1879e8dd2acc18..5fc897cf409b21 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -413,6 +413,11 @@ __und_usr: @ adr r9, BSYM(ret_from_exception) + @ IRQs must be enabled before attempting to read the instruction from + @ user space since that could cause a page/translation fault if the + @ page table was modified by another CPU. + enable_irq + tst r3, #PSR_T_BIT @ Thumb mode? bne __und_usr_thumb sub r4, r2, #4 @ ARM instr at LR - 4 @@ -517,7 +522,7 @@ ENDPROC(__und_usr) * r9 = normal "successful" return address * r10 = this threads thread_info structure * lr = unrecognised instruction return address - * IRQs disabled, FIQs enabled. + * IRQs enabled, FIQs enabled. */ @ @ Fall-through from Thumb-2 __und_usr @@ -624,7 +629,6 @@ call_fpe: #endif do_fpe: - enable_irq ldr r4, .LCfp add r10, r10, #TI_FPSTATE @ r10 = workspace ldr pc, [r4] @ Call FP module USR entry point @@ -652,8 +656,7 @@ __und_usr_fault_32: b 1f __und_usr_fault_16: mov r1, #2 -1: enable_irq - mov r0, sp +1: mov r0, sp adr lr, BSYM(ret_from_exception) b __und_fault ENDPROC(__und_usr_fault_32) diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index c108ddcb9ba405..af9a8a927a4e96 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -63,6 +64,18 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) } #endif +int ftrace_arch_code_modify_prepare(void) +{ + set_all_modules_text_rw(); + return 0; +} + +int ftrace_arch_code_modify_post_process(void) +{ + set_all_modules_text_ro(); + return 0; +} + static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) { return arm_gen_branch_link(pc, addr); diff --git a/arch/arm/kernel/hibernate.c b/arch/arm/kernel/hibernate.c new file mode 100644 index 00000000000000..bb8b796486430d --- /dev/null +++ b/arch/arm/kernel/hibernate.c @@ -0,0 +1,107 @@ +/* + * Hibernation support specific for ARM + * + * Derived from work on ARM hibernation support by: + * + * Ubuntu project, hibernation support for mach-dove + * Copyright (C) 2010 Nokia Corporation (Hiroshi Doyu) + * Copyright (C) 2010 Texas Instruments, Inc. (Teerth Reddy et al.) + * https://lkml.org/lkml/2010/6/18/4 + * https://lists.linux-foundation.org/pipermail/linux-pm/2010-June/027422.html + * https://patchwork.kernel.org/patch/96442/ + * + * Copyright (C) 2006 Rafael J. Wysocki + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include + +extern const void __nosave_begin, __nosave_end; + +int pfn_is_nosave(unsigned long pfn) +{ + unsigned long nosave_begin_pfn = virt_to_pfn(&__nosave_begin); + unsigned long nosave_end_pfn = virt_to_pfn(&__nosave_end - 1); + + return (pfn >= nosave_begin_pfn) && (pfn <= nosave_end_pfn); +} + +void notrace save_processor_state(void) +{ + WARN_ON(num_online_cpus() != 1); + local_fiq_disable(); +} + +void notrace restore_processor_state(void) +{ + local_fiq_enable(); +} + +/* + * Snapshot kernel memory and reset the system. + * + * swsusp_save() is executed in the suspend finisher so that the CPU + * context pointer and memory are part of the saved image, which is + * required by the resume kernel image to restart execution from + * swsusp_arch_suspend(). + * + * soft_restart is not technically needed, but is used to get success + * returned from cpu_suspend. + * + * When soft reboot completes, the hibernation snapshot is written out. + */ +static int notrace arch_save_image(unsigned long unused) +{ + int ret; + + ret = swsusp_save(); + if (ret == 0) + soft_restart(virt_to_phys(cpu_resume)); + return ret; +} + +/* + * Save the current CPU state before suspend / poweroff. + */ +int notrace swsusp_arch_suspend(void) +{ + return cpu_suspend(0, arch_save_image); +} + +/* + * Restore page contents for physical pages that were in use during loading + * hibernation image. Switch to idmap_pgd so the physical page tables + * are overwritten with the same contents. + */ +static void notrace arch_restore_image(void *unused) +{ + struct pbe *pbe; + + cpu_switch_mm(idmap_pgd, &init_mm); + for (pbe = restore_pblist; pbe; pbe = pbe->next) + copy_page(pbe->orig_address, pbe->address); + + soft_restart(virt_to_phys(cpu_resume)); +} + +static u64 resume_stack[PAGE_SIZE/2/sizeof(u64)] __nosavedata; + +/* + * Resume from the hibernation image. + * Due to the kernel heap / data restore, stack contents change underneath + * and that would make function calls impossible; switch to a temporary + * stack within the nosave region to avoid that problem. + */ +int swsusp_arch_resume(void) +{ + extern void call_with_stack(void (*fn)(void *), void *arg, void *sp); + call_with_stack(arch_restore_image, 0, + resume_stack + ARRAY_SIZE(resume_stack)); + return 0; +} diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S index 2452dd1bef53b0..a5599cfc43cbb1 100644 --- a/arch/arm/kernel/iwmmxt.S +++ b/arch/arm/kernel/iwmmxt.S @@ -18,6 +18,7 @@ #include #include #include +#include #if defined(CONFIG_CPU_PJ4) || defined(CONFIG_CPU_PJ4B) #define PJ4(code...) code @@ -65,17 +66,18 @@ * r9 = ret_from_exception * lr = undefined instr exit * - * called from prefetch exception handler with interrupts disabled + * called from prefetch exception handler with interrupts enabled */ ENTRY(iwmmxt_task_enable) + inc_preempt_count r10, r3 XSC(mrc p15, 0, r2, c15, c1, 0) PJ4(mrc p15, 0, r2, c1, c0, 2) @ CP0 and CP1 accessible? XSC(tst r2, #0x3) PJ4(tst r2, #0xf) - movne pc, lr @ if so no business here + bne 4f @ if so no business here @ enable access to CP0 and CP1 XSC(orr r2, r2, #0x3) XSC(mcr p15, 0, r2, c15, c1, 0) @@ -136,7 +138,7 @@ concan_dump: wstrd wR15, [r1, #MMX_WR15] 2: teq r0, #0 @ anything to load? - moveq pc, lr + beq 3f concan_load: @@ -169,8 +171,14 @@ concan_load: @ clear CUP/MUP (only if r1 != 0) teq r1, #0 mov r2, #0 - moveq pc, lr + beq 3f tmcr wCon, r2 + +3: +#ifdef CONFIG_PREEMPT_COUNT + get_thread_info r10 +#endif +4: dec_preempt_count r10, r3 mov pc, lr /* diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index 51798d7854aca9..a71ae1523620af 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -221,6 +221,7 @@ static struct notifier_block cpu_pmu_hotplug_notifier = { * PMU platform driver and devicetree bindings. */ static struct of_device_id cpu_pmu_of_device_ids[] = { + {.compatible = "arm,cortex-a17-pmu", .data = armv7_a17_pmu_init}, {.compatible = "arm,cortex-a15-pmu", .data = armv7_a15_pmu_init}, {.compatible = "arm,cortex-a12-pmu", .data = armv7_a12_pmu_init}, {.compatible = "arm,cortex-a9-pmu", .data = armv7_a9_pmu_init}, diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index f4ef3981ed0293..2037f720598742 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -1599,6 +1599,13 @@ static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu) return 0; } +static int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu) +{ + armv7_a12_pmu_init(cpu_pmu); + cpu_pmu->name = "ARMv7 Cortex-A17"; + return 0; +} + /* * Krait Performance Monitor Region Event Selection Register (PMRESRn) * @@ -2021,6 +2028,11 @@ static inline int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu) return -ENODEV; } +static inline int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu) +{ + return -ENODEV; +} + static inline int krait_pmu_init(struct arm_pmu *cpu_pmu) { return -ENODEV; diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 0dd3b79b15c3d9..c9d2b34cb50a7b 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -943,8 +943,8 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno) if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_enter(regs, scno); - audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1, - regs->ARM_r2, regs->ARM_r3); + audit_syscall_entry(scno, regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, + regs->ARM_r3); return scno; } diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index b907d9b790ab72..1b880db2a0338f 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -127,6 +127,10 @@ ENDPROC(cpu_resume_after_mmu) .align ENTRY(cpu_resume) ARM_BE8(setend be) @ ensure we are in BE mode +#ifdef CONFIG_ARM_VIRT_EXT + bl __hyp_stub_install_secondary +#endif + safe_svcmode_maskall r1 mov r1, #0 ALT_SMP(mrc p15, 0, r0, c0, c0, 5) ALT_UP_B(1f) @@ -144,7 +148,6 @@ ARM_BE8(setend be) @ ensure we are in BE mode ldr r0, [r0, #SLEEP_SAVE_SP_PHYS] ldr r0, [r0, r1, lsl #2] - setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off @ load phys pgd, stack, resume fn ARM( ldmia r0!, {r1, sp, pc} ) THUMB( ldmia r0!, {r1, r2, r3} ) diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index 0bc94b1fd1ae9e..3997c411c14036 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -91,13 +91,13 @@ static void __init parse_dt_topology(void) { const struct cpu_efficiency *cpu_eff; struct device_node *cn = NULL; - unsigned long min_capacity = (unsigned long)(-1); + unsigned long min_capacity = ULONG_MAX; unsigned long max_capacity = 0; unsigned long capacity = 0; - int alloc_size, cpu = 0; + int cpu = 0; - alloc_size = nr_cpu_ids * sizeof(*__cpu_capacity); - __cpu_capacity = kzalloc(alloc_size, GFP_NOWAIT); + __cpu_capacity = kcalloc(nr_cpu_ids, sizeof(*__cpu_capacity), + GFP_NOWAIT); for_each_possible_cpu(cpu) { const u32 *rate; @@ -185,6 +185,15 @@ const struct cpumask *cpu_coregroup_mask(int cpu) return &cpu_topology[cpu].core_sibling; } +/* + * The current assumption is that we can power gate each core independently. + * This will be superseded by DT binding once available. + */ +const struct cpumask *cpu_corepower_mask(int cpu) +{ + return &cpu_topology[cpu].thread_sibling; +} + static void update_siblings_masks(unsigned int cpuid) { struct cputopo_arm *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; @@ -266,6 +275,20 @@ void store_cpu_topology(unsigned int cpuid) cpu_topology[cpuid].socket_id, mpidr); } +static inline const int cpu_corepower_flags(void) +{ + return SD_SHARE_PKG_RESOURCES | SD_SHARE_POWERDOMAIN; +} + +static struct sched_domain_topology_level arm_topology[] = { +#ifdef CONFIG_SCHED_MC + { cpu_corepower_mask, cpu_corepower_flags, SD_INIT_NAME(GMC) }, + { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, +#endif + { cpu_cpu_mask, SD_INIT_NAME(DIE) }, + { NULL, }, +}; + /* * init_cpu_topology is called at boot when only one cpu is running * which prevent simultaneous write access to cpu_topology array @@ -289,4 +312,7 @@ void __init init_cpu_topology(void) smp_wmb(); parse_dt_topology(); + + /* Set scheduler topology descriptor */ + set_sched_topology(arm_topology); } diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c index 3c217694ebecb1..ebb183a0a8bf43 100644 --- a/arch/arm/kernel/unwind.c +++ b/arch/arm/kernel/unwind.c @@ -31,7 +31,7 @@ #warning Your compiler does not have EABI support. #warning ARM unwind is known to compile only with EABI compilers. #warning Change compiler or disable ARM_UNWIND option. -#elif (__GNUC__ == 4 && __GNUC_MINOR__ <= 2) +#elif (__GNUC__ == 4 && __GNUC_MINOR__ <= 2) && !defined(__clang__) #warning Your compiler is too buggy; it is known to not compile ARM unwind support. #warning Change compiler or disable ARM_UNWIND option. #endif diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index f0e50a0f3a65b1..3c82b37c0f9edb 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -197,6 +197,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: case KVM_CAP_ONE_REG: case KVM_CAP_ARM_PSCI: + case KVM_CAP_ARM_PSCI_0_2: r = 1; break; case KVM_CAP_COALESCED_MMIO: diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c index 0de91fc6de0ff0..4c979d466cc168 100644 --- a/arch/arm/kvm/handle_exit.c +++ b/arch/arm/kvm/handle_exit.c @@ -38,14 +38,18 @@ static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run) static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) { + int ret; + trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0), kvm_vcpu_hvc_get_imm(vcpu)); - if (kvm_psci_call(vcpu)) + ret = kvm_psci_call(vcpu); + if (ret < 0) { + kvm_inject_undefined(vcpu); return 1; + } - kvm_inject_undefined(vcpu); - return 1; + return ret; } static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 448f60e8d23ca0..09cf37737ee2ad 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -27,6 +27,36 @@ * as described in ARM document number ARM DEN 0022A. */ +#define AFFINITY_MASK(level) ~((0x1UL << ((level) * MPIDR_LEVEL_BITS)) - 1) + +static unsigned long psci_affinity_mask(unsigned long affinity_level) +{ + if (affinity_level <= 3) + return MPIDR_HWID_BITMASK & AFFINITY_MASK(affinity_level); + + return 0; +} + +static unsigned long kvm_psci_vcpu_suspend(struct kvm_vcpu *vcpu) +{ + /* + * NOTE: For simplicity, we make VCPU suspend emulation to be + * same-as WFI (Wait-for-interrupt) emulation. + * + * This means for KVM the wakeup events are interrupts and + * this is consistent with intended use of StateID as described + * in section 5.4.1 of PSCI v0.2 specification (ARM DEN 0022A). + * + * Further, we also treat power-down request to be same as + * stand-by request as-per section 5.4.2 clause 3 of PSCI v0.2 + * specification (ARM DEN 0022A). This means all suspend states + * for KVM will preserve the register state. + */ + kvm_vcpu_block(vcpu); + + return PSCI_RET_SUCCESS; +} + static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu) { vcpu->arch.pause = true; @@ -38,6 +68,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) struct kvm_vcpu *vcpu = NULL, *tmp; wait_queue_head_t *wq; unsigned long cpu_id; + unsigned long context_id; unsigned long mpidr; phys_addr_t target_pc; int i; @@ -58,10 +89,17 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) * Make sure the caller requested a valid CPU and that the CPU is * turned off. */ - if (!vcpu || !vcpu->arch.pause) - return KVM_PSCI_RET_INVAL; + if (!vcpu) + return PSCI_RET_INVALID_PARAMS; + if (!vcpu->arch.pause) { + if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1) + return PSCI_RET_ALREADY_ON; + else + return PSCI_RET_INVALID_PARAMS; + } target_pc = *vcpu_reg(source_vcpu, 2); + context_id = *vcpu_reg(source_vcpu, 3); kvm_reset_vcpu(vcpu); @@ -76,26 +114,160 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) kvm_vcpu_set_be(vcpu); *vcpu_pc(vcpu) = target_pc; + /* + * NOTE: We always update r0 (or x0) because for PSCI v0.1 + * the general puspose registers are undefined upon CPU_ON. + */ + *vcpu_reg(vcpu, 0) = context_id; vcpu->arch.pause = false; smp_mb(); /* Make sure the above is visible */ wq = kvm_arch_vcpu_wq(vcpu); wake_up_interruptible(wq); - return KVM_PSCI_RET_SUCCESS; + return PSCI_RET_SUCCESS; } -/** - * kvm_psci_call - handle PSCI call if r0 value is in range - * @vcpu: Pointer to the VCPU struct - * - * Handle PSCI calls from guests through traps from HVC instructions. - * The calling convention is similar to SMC calls to the secure world where - * the function number is placed in r0 and this function returns true if the - * function number specified in r0 is withing the PSCI range, and false - * otherwise. - */ -bool kvm_psci_call(struct kvm_vcpu *vcpu) +static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu) +{ + int i; + unsigned long mpidr; + unsigned long target_affinity; + unsigned long target_affinity_mask; + unsigned long lowest_affinity_level; + struct kvm *kvm = vcpu->kvm; + struct kvm_vcpu *tmp; + + target_affinity = *vcpu_reg(vcpu, 1); + lowest_affinity_level = *vcpu_reg(vcpu, 2); + + /* Determine target affinity mask */ + target_affinity_mask = psci_affinity_mask(lowest_affinity_level); + if (!target_affinity_mask) + return PSCI_RET_INVALID_PARAMS; + + /* Ignore other bits of target affinity */ + target_affinity &= target_affinity_mask; + + /* + * If one or more VCPU matching target affinity are running + * then ON else OFF + */ + kvm_for_each_vcpu(i, tmp, kvm) { + mpidr = kvm_vcpu_get_mpidr(tmp); + if (((mpidr & target_affinity_mask) == target_affinity) && + !tmp->arch.pause) { + return PSCI_0_2_AFFINITY_LEVEL_ON; + } + } + + return PSCI_0_2_AFFINITY_LEVEL_OFF; +} + +static void kvm_prepare_system_event(struct kvm_vcpu *vcpu, u32 type) +{ + memset(&vcpu->run->system_event, 0, sizeof(vcpu->run->system_event)); + vcpu->run->system_event.type = type; + vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT; +} + +static void kvm_psci_system_off(struct kvm_vcpu *vcpu) +{ + kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN); +} + +static void kvm_psci_system_reset(struct kvm_vcpu *vcpu) +{ + kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET); +} + +int kvm_psci_version(struct kvm_vcpu *vcpu) +{ + if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) + return KVM_ARM_PSCI_0_2; + + return KVM_ARM_PSCI_0_1; +} + +static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) +{ + int ret = 1; + unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); + unsigned long val; + + switch (psci_fn) { + case PSCI_0_2_FN_PSCI_VERSION: + /* + * Bits[31:16] = Major Version = 0 + * Bits[15:0] = Minor Version = 2 + */ + val = 2; + break; + case PSCI_0_2_FN_CPU_SUSPEND: + case PSCI_0_2_FN64_CPU_SUSPEND: + val = kvm_psci_vcpu_suspend(vcpu); + break; + case PSCI_0_2_FN_CPU_OFF: + kvm_psci_vcpu_off(vcpu); + val = PSCI_RET_SUCCESS; + break; + case PSCI_0_2_FN_CPU_ON: + case PSCI_0_2_FN64_CPU_ON: + val = kvm_psci_vcpu_on(vcpu); + break; + case PSCI_0_2_FN_AFFINITY_INFO: + case PSCI_0_2_FN64_AFFINITY_INFO: + val = kvm_psci_vcpu_affinity_info(vcpu); + break; + case PSCI_0_2_FN_MIGRATE: + case PSCI_0_2_FN64_MIGRATE: + val = PSCI_RET_NOT_SUPPORTED; + break; + case PSCI_0_2_FN_MIGRATE_INFO_TYPE: + /* + * Trusted OS is MP hence does not require migration + * or + * Trusted OS is not present + */ + val = PSCI_0_2_TOS_MP; + break; + case PSCI_0_2_FN_MIGRATE_INFO_UP_CPU: + case PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU: + val = PSCI_RET_NOT_SUPPORTED; + break; + case PSCI_0_2_FN_SYSTEM_OFF: + kvm_psci_system_off(vcpu); + /* + * We should'nt be going back to guest VCPU after + * receiving SYSTEM_OFF request. + * + * If user space accidently/deliberately resumes + * guest VCPU after SYSTEM_OFF request then guest + * VCPU should see internal failure from PSCI return + * value. To achieve this, we preload r0 (or x0) with + * PSCI return value INTERNAL_FAILURE. + */ + val = PSCI_RET_INTERNAL_FAILURE; + ret = 0; + break; + case PSCI_0_2_FN_SYSTEM_RESET: + kvm_psci_system_reset(vcpu); + /* + * Same reason as SYSTEM_OFF for preloading r0 (or x0) + * with PSCI return value INTERNAL_FAILURE. + */ + val = PSCI_RET_INTERNAL_FAILURE; + ret = 0; + break; + default: + return -EINVAL; + } + + *vcpu_reg(vcpu, 0) = val; + return ret; +} + +static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) { unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); unsigned long val; @@ -103,20 +275,45 @@ bool kvm_psci_call(struct kvm_vcpu *vcpu) switch (psci_fn) { case KVM_PSCI_FN_CPU_OFF: kvm_psci_vcpu_off(vcpu); - val = KVM_PSCI_RET_SUCCESS; + val = PSCI_RET_SUCCESS; break; case KVM_PSCI_FN_CPU_ON: val = kvm_psci_vcpu_on(vcpu); break; case KVM_PSCI_FN_CPU_SUSPEND: case KVM_PSCI_FN_MIGRATE: - val = KVM_PSCI_RET_NI; + val = PSCI_RET_NOT_SUPPORTED; break; - default: - return false; + return -EINVAL; } *vcpu_reg(vcpu, 0) = val; - return true; + return 1; +} + +/** + * kvm_psci_call - handle PSCI call if r0 value is in range + * @vcpu: Pointer to the VCPU struct + * + * Handle PSCI calls from guests through traps from HVC instructions. + * The calling convention is similar to SMC calls to the secure world + * where the function number is placed in r0. + * + * This function returns: > 0 (success), 0 (success but exit to user + * space), and < 0 (errors) + * + * Errors: + * -EINVAL: Unrecognized PSCI function + */ +int kvm_psci_call(struct kvm_vcpu *vcpu) +{ + switch (kvm_psci_version(vcpu)) { + case KVM_ARM_PSCI_0_2: + return kvm_psci_0_2_call(vcpu); + case KVM_ARM_PSCI_0_1: + return kvm_psci_0_1_call(vcpu); + default: + return -EINVAL; + }; } diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 49c914cd9c7a9c..9f19636fea2f65 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -11,7 +11,6 @@ menu "Broadcom SoC Selection" config ARCH_BCM_MOBILE bool "Broadcom Mobile SoC" if ARCH_MULTI_V7 - depends on MMU select ARCH_REQUIRE_GPIOLIB select ARM_ERRATA_754322 select ARM_ERRATA_764369 if SMP @@ -33,10 +32,7 @@ config ARCH_BCM2835 select ARM_AMBA select ARM_ERRATA_411920 select ARM_TIMER_SP804 - select CLKDEV_LOOKUP select CLKSRC_OF - select CPU_V6 - select GENERIC_CLOCKEVENTS select PINCTRL select PINCTRL_BCM2835 help @@ -45,14 +41,10 @@ config ARCH_BCM2835 config ARCH_BCM_5301X bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7 - depends on MMU select ARM_GIC select CACHE_L2X0 select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP - select HAVE_SMP - select COMMON_CLK - select GENERIC_CLOCKEVENTS select ARM_GLOBAL_TIMER select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK select MIGHT_HAVE_PCI diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig index b0cb0722acd254..95c098f497b57a 100644 --- a/arch/arm/mach-berlin/Kconfig +++ b/arch/arm/mach-berlin/Kconfig @@ -1,5 +1,6 @@ config ARCH_BERLIN bool "Marvell Berlin SoCs" if ARCH_MULTI_V7 + select ARCH_REQUIRE_GPIOLIB select ARM_GIC select GENERIC_IRQ_CHIP select DW_APB_ICTL @@ -20,6 +21,11 @@ config MACH_BERLIN_BG2CD select CACHE_L2X0 select HAVE_ARM_TWD if SMP +config MACH_BERLIN_BG2Q + bool "Marvell Armada 1500 Pro (BG2-Q)" + select CACHE_L2X0 + select HAVE_ARM_TWD if SMP + endmenu endif diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 85399c98f84a7f..45ce065e7170f8 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -1092,20 +1092,21 @@ int da850_register_cpufreq(char *async_clk) static int da850_round_armrate(struct clk *clk, unsigned long rate) { - int i, ret = 0, diff; + int ret = 0, diff; unsigned int best = (unsigned int) -1; struct cpufreq_frequency_table *table = cpufreq_info.freq_table; + struct cpufreq_frequency_table *pos; rate /= 1000; /* convert to kHz */ - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - diff = table[i].frequency - rate; + cpufreq_for_each_entry(pos, table) { + diff = pos->frequency - rate; if (diff < 0) diff = -diff; if (diff < best) { best = diff; - ret = table[i].frequency; + ret = pos->frequency; } } diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c index bc4344aa10092d..4a5a7aedcb763e 100644 --- a/arch/arm/mach-dove/irq.c +++ b/arch/arm/mach-dove/irq.c @@ -108,6 +108,38 @@ static int __initdata gpio2_irqs[4] = { 0, }; +#ifdef CONFIG_MULTI_IRQ_HANDLER +/* + * Compiling with both non-DT and DT support enabled, will + * break asm irq handler used by non-DT boards. Therefore, + * we provide a C-style irq handler even for non-DT boards, + * if MULTI_IRQ_HANDLER is set. + */ + +static void __iomem *dove_irq_base = IRQ_VIRT_BASE; + +static asmlinkage void +__exception_irq_entry dove_legacy_handle_irq(struct pt_regs *regs) +{ + u32 stat; + + stat = readl_relaxed(dove_irq_base + IRQ_CAUSE_LOW_OFF); + stat &= readl_relaxed(dove_irq_base + IRQ_MASK_LOW_OFF); + if (stat) { + unsigned int hwirq = __fls(stat); + handle_IRQ(hwirq, regs); + return; + } + stat = readl_relaxed(dove_irq_base + IRQ_CAUSE_HIGH_OFF); + stat &= readl_relaxed(dove_irq_base + IRQ_MASK_HIGH_OFF); + if (stat) { + unsigned int hwirq = 32 + __fls(stat); + handle_IRQ(hwirq, regs); + return; + } +} +#endif + void __init dove_init_irq(void) { int i; @@ -115,6 +147,10 @@ void __init dove_init_irq(void) orion_irq_init(0, IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF); orion_irq_init(32, IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF); +#ifdef CONFIG_MULTI_IRQ_HANDLER + set_handle_irq(dove_legacy_handle_irq); +#endif + /* * Initialize gpiolib for GPIOs 0-71. */ diff --git a/arch/arm/mach-ep93xx/crunch-bits.S b/arch/arm/mach-ep93xx/crunch-bits.S index 0ec9bb48fab9cd..e96923a3017b16 100644 --- a/arch/arm/mach-ep93xx/crunch-bits.S +++ b/arch/arm/mach-ep93xx/crunch-bits.S @@ -16,6 +16,7 @@ #include #include #include +#include #include /* @@ -62,14 +63,16 @@ * r9 = ret_from_exception * lr = undefined instr exit * - * called from prefetch exception handler with interrupts disabled + * called from prefetch exception handler with interrupts enabled */ ENTRY(crunch_task_enable) + inc_preempt_count r10, r3 + ldr r8, =(EP93XX_APB_VIRT_BASE + 0x00130000) @ syscon addr ldr r1, [r8, #0x80] tst r1, #0x00800000 @ access to crunch enabled? - movne pc, lr @ if so no business here + bne 2f @ if so no business here mov r3, #0xaa @ unlock syscon swlock str r3, [r8, #0xc0] orr r1, r1, #0x00800000 @ enable access to crunch @@ -142,7 +145,7 @@ crunch_save: teq r0, #0 @ anything to load? cfldr64eq mvdx0, [r1, #CRUNCH_MVDX0] @ mvdx0 was clobbered - moveq pc, lr + beq 1f crunch_load: cfldr64 mvdx0, [r0, #CRUNCH_DSPSC] @ load status word @@ -190,6 +193,11 @@ crunch_load: cfldr64 mvdx14, [r0, #CRUNCH_MVDX14] cfldr64 mvdx15, [r0, #CRUNCH_MVDX15] +1: +#ifdef CONFIG_PREEMPT_COUNT + get_thread_info r10 +#endif +2: dec_preempt_count r10, r3 mov pc, lr /* diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index a656dbe3b78c87..21bd3642751ec6 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos.o obj-$(CONFIG_PM_SLEEP) += pm.o sleep.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o -obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ARCH_EXYNOS) += pmu.o diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 9ef3f83efaffa6..30123a0a9e6b35 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -62,5 +62,6 @@ struct exynos_pmu_conf { }; extern void exynos_sys_powerdown_conf(enum sys_powerdown mode); +extern void exynos_enter_aftr(void); #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */ diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c deleted file mode 100644 index c57cae0e877921..00000000000000 --- a/arch/arm/mach-exynos/cpuidle.c +++ /dev/null @@ -1,256 +0,0 @@ -/* linux/arch/arm/mach-exynos4/cpuidle.c - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * 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 -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "common.h" -#include "regs-pmu.h" - -#define REG_DIRECTGO_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \ - S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ - (S5P_VA_SYSRAM + 0x24) : S5P_INFORM0)) -#define REG_DIRECTGO_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ - S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ - (S5P_VA_SYSRAM + 0x20) : S5P_INFORM1)) - -#define S5P_CHECK_AFTR 0xFCBA0D10 - -#define EXYNOS5_PWR_CTRL1 (S5P_VA_CMU + 0x01020) -#define EXYNOS5_PWR_CTRL2 (S5P_VA_CMU + 0x01024) - -#define PWR_CTRL1_CORE2_DOWN_RATIO (7 << 28) -#define PWR_CTRL1_CORE1_DOWN_RATIO (7 << 16) -#define PWR_CTRL1_DIV2_DOWN_EN (1 << 9) -#define PWR_CTRL1_DIV1_DOWN_EN (1 << 8) -#define PWR_CTRL1_USE_CORE1_WFE (1 << 5) -#define PWR_CTRL1_USE_CORE0_WFE (1 << 4) -#define PWR_CTRL1_USE_CORE1_WFI (1 << 1) -#define PWR_CTRL1_USE_CORE0_WFI (1 << 0) - -#define PWR_CTRL2_DIV2_UP_EN (1 << 25) -#define PWR_CTRL2_DIV1_UP_EN (1 << 24) -#define PWR_CTRL2_DUR_STANDBY2_VAL (1 << 16) -#define PWR_CTRL2_DUR_STANDBY1_VAL (1 << 8) -#define PWR_CTRL2_CORE2_UP_RATIO (1 << 4) -#define PWR_CTRL2_CORE1_UP_RATIO (1 << 0) - -static int exynos4_enter_lowpower(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index); - -static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device); - -static struct cpuidle_driver exynos4_idle_driver = { - .name = "exynos4_idle", - .owner = THIS_MODULE, - .states = { - [0] = ARM_CPUIDLE_WFI_STATE, - [1] = { - .enter = exynos4_enter_lowpower, - .exit_latency = 300, - .target_residency = 100000, - .flags = CPUIDLE_FLAG_TIME_VALID, - .name = "C1", - .desc = "ARM power down", - }, - }, - .state_count = 2, - .safe_state_index = 0, -}; - -/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ -static void exynos4_set_wakeupmask(void) -{ - __raw_writel(0x0000ff3e, S5P_WAKEUP_MASK); -} - -static unsigned int g_pwr_ctrl, g_diag_reg; - -static void save_cpu_arch_register(void) -{ - /*read power control register*/ - asm("mrc p15, 0, %0, c15, c0, 0" : "=r"(g_pwr_ctrl) : : "cc"); - /*read diagnostic register*/ - asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc"); - return; -} - -static void restore_cpu_arch_register(void) -{ - /*write power control register*/ - asm("mcr p15, 0, %0, c15, c0, 0" : : "r"(g_pwr_ctrl) : "cc"); - /*write diagnostic register*/ - asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc"); - return; -} - -static int idle_finisher(unsigned long flags) -{ - cpu_do_idle(); - return 1; -} - -static int exynos4_enter_core0_aftr(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) -{ - unsigned long tmp; - - exynos4_set_wakeupmask(); - - /* Set value of power down register for aftr mode */ - exynos_sys_powerdown_conf(SYS_AFTR); - - __raw_writel(virt_to_phys(exynos_cpu_resume), REG_DIRECTGO_ADDR); - __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG); - - save_cpu_arch_register(); - - /* Setting Central Sequence Register for power down mode */ - tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); - tmp &= ~S5P_CENTRAL_LOWPWR_CFG; - __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); - - cpu_pm_enter(); - cpu_suspend(0, idle_finisher); - -#ifdef CONFIG_SMP - if (!soc_is_exynos5250()) - scu_enable(S5P_VA_SCU); -#endif - cpu_pm_exit(); - - restore_cpu_arch_register(); - - /* - * If PMU failed while entering sleep mode, WFI will be - * ignored by PMU and then exiting cpu_do_idle(). - * S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically - * in this situation. - */ - tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); - if (!(tmp & S5P_CENTRAL_LOWPWR_CFG)) { - tmp |= S5P_CENTRAL_LOWPWR_CFG; - __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); - } - - /* Clear wakeup state register */ - __raw_writel(0x0, S5P_WAKEUP_STAT); - - return index; -} - -static int exynos4_enter_lowpower(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) -{ - int new_index = index; - - /* AFTR can only be entered when cores other than CPU0 are offline */ - if (num_online_cpus() > 1 || dev->cpu != 0) - new_index = drv->safe_state_index; - - if (new_index == 0) - return arm_cpuidle_simple_enter(dev, drv, new_index); - else - return exynos4_enter_core0_aftr(dev, drv, new_index); -} - -static void __init exynos5_core_down_clk(void) -{ - unsigned int tmp; - - /* - * Enable arm clock down (in idle) and set arm divider - * ratios in WFI/WFE state. - */ - tmp = PWR_CTRL1_CORE2_DOWN_RATIO | \ - PWR_CTRL1_CORE1_DOWN_RATIO | \ - PWR_CTRL1_DIV2_DOWN_EN | \ - PWR_CTRL1_DIV1_DOWN_EN | \ - PWR_CTRL1_USE_CORE1_WFE | \ - PWR_CTRL1_USE_CORE0_WFE | \ - PWR_CTRL1_USE_CORE1_WFI | \ - PWR_CTRL1_USE_CORE0_WFI; - __raw_writel(tmp, EXYNOS5_PWR_CTRL1); - - /* - * Enable arm clock up (on exiting idle). Set arm divider - * ratios when not in idle along with the standby duration - * ratios. - */ - tmp = PWR_CTRL2_DIV2_UP_EN | \ - PWR_CTRL2_DIV1_UP_EN | \ - PWR_CTRL2_DUR_STANDBY2_VAL | \ - PWR_CTRL2_DUR_STANDBY1_VAL | \ - PWR_CTRL2_CORE2_UP_RATIO | \ - PWR_CTRL2_CORE1_UP_RATIO; - __raw_writel(tmp, EXYNOS5_PWR_CTRL2); -} - -static int exynos_cpuidle_probe(struct platform_device *pdev) -{ - int cpu_id, ret; - struct cpuidle_device *device; - - if (soc_is_exynos5250()) - exynos5_core_down_clk(); - - if (soc_is_exynos5440()) - exynos4_idle_driver.state_count = 1; - - ret = cpuidle_register_driver(&exynos4_idle_driver); - if (ret) { - dev_err(&pdev->dev, "failed to register cpuidle driver\n"); - return ret; - } - - for_each_online_cpu(cpu_id) { - device = &per_cpu(exynos4_cpuidle_device, cpu_id); - device->cpu = cpu_id; - - ret = cpuidle_register_device(device); - if (ret) { - dev_err(&pdev->dev, "failed to register cpuidle device\n"); - return ret; - } - } - - return 0; -} - -static struct platform_driver exynos_cpuidle_driver = { - .probe = exynos_cpuidle_probe, - .driver = { - .name = "exynos_cpuidle", - .owner = THIS_MODULE, - }, -}; - -module_platform_driver(exynos_cpuidle_driver); diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index b32a907d021d4a..a079136a4068a8 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -221,12 +221,16 @@ void exynos_restart(enum reboot_mode mode, const char *cmd) } static struct platform_device exynos_cpuidle = { - .name = "exynos_cpuidle", - .id = -1, + .name = "exynos_cpuidle", + .dev.platform_data = exynos_enter_aftr, + .id = -1, }; void __init exynos_cpuidle_init(void) { + if (soc_is_exynos5440()) + return; + platform_device_register(&exynos_cpuidle); } @@ -250,7 +254,7 @@ static int __init exynos_fdt_map_chipid(unsigned long node, const char *uname, { struct map_desc iodesc; __be32 *reg; - unsigned long len; + int len; if (!of_flat_dt_is_compatible(node, "samsung,exynos4210-chipid") && !of_flat_dt_is_compatible(node, "samsung,exynos5440-clock")) diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index 932129ef26c660..aa01c4222b4033 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -18,6 +18,8 @@ #include +#include + #include "smc.h" static int exynos_do_idle(void) @@ -28,13 +30,24 @@ static int exynos_do_idle(void) static int exynos_cpu_boot(int cpu) { + /* + * The second parameter of SMC_CMD_CPU1BOOT command means CPU id. + * But, Exynos4212 has only one secondary CPU so second parameter + * isn't used for informing secure firmware about CPU id. + */ + if (soc_is_exynos4212()) + cpu = 0; + exynos_smc(SMC_CMD_CPU1BOOT, cpu, 0, 0); return 0; } static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr) { - void __iomem *boot_reg = S5P_VA_SYSRAM_NS + 0x1c + 4*cpu; + void __iomem *boot_reg = S5P_VA_SYSRAM_NS + 0x1c; + + if (!soc_is_exynos4212()) + boot_reg += 4*cpu; __raw_writel(boot_addr, boot_reg); return 0; diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 15af0ceb0a66a0..b380d48885d208 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -100,9 +101,75 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) return -ENOENT; } +#define EXYNOS_BOOT_VECTOR_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \ + S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ + (S5P_VA_SYSRAM + 0x24) : S5P_INFORM0)) +#define EXYNOS_BOOT_VECTOR_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ + S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ + (S5P_VA_SYSRAM + 0x20) : S5P_INFORM1)) + +#define S5P_CHECK_AFTR 0xFCBA0D10 +#define S5P_CHECK_SLEEP 0x00000BAD + +/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ +static void exynos_set_wakeupmask(long mask) +{ + __raw_writel(mask, S5P_WAKEUP_MASK); +} + +static void exynos_cpu_set_boot_vector(long flags) +{ + __raw_writel(virt_to_phys(exynos_cpu_resume), EXYNOS_BOOT_VECTOR_ADDR); + __raw_writel(flags, EXYNOS_BOOT_VECTOR_FLAG); +} + +void exynos_enter_aftr(void) +{ + exynos_set_wakeupmask(0x0000ff3e); + exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); + /* Set value of power down register for aftr mode */ + exynos_sys_powerdown_conf(SYS_AFTR); +} + /* For Cortex-A9 Diagnostic and Power control register */ static unsigned int save_arm_register[2]; +static void exynos_cpu_save_register(void) +{ + unsigned long tmp; + + /* Save Power control register */ + asm ("mrc p15, 0, %0, c15, c0, 0" + : "=r" (tmp) : : "cc"); + + save_arm_register[0] = tmp; + + /* Save Diagnostic register */ + asm ("mrc p15, 0, %0, c15, c0, 1" + : "=r" (tmp) : : "cc"); + + save_arm_register[1] = tmp; +} + +static void exynos_cpu_restore_register(void) +{ + unsigned long tmp; + + /* Restore Power control register */ + tmp = save_arm_register[0]; + + asm volatile ("mcr p15, 0, %0, c15, c0, 0" + : : "r" (tmp) + : "cc"); + + /* Restore Diagnostic register */ + tmp = save_arm_register[1]; + + asm volatile ("mcr p15, 0, %0, c15, c0, 1" + : : "r" (tmp) + : "cc"); +} + static int exynos_cpu_suspend(unsigned long arg) { #ifdef CONFIG_CACHE_L2X0 @@ -147,37 +214,34 @@ static void exynos_pm_prepare(void) __raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); } -static int exynos_pm_suspend(void) +static void exynos_pm_central_suspend(void) { unsigned long tmp; /* Setting Central Sequence Register for power down mode */ - tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); tmp &= ~S5P_CENTRAL_LOWPWR_CFG; __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); +} + +static int exynos_pm_suspend(void) +{ + unsigned long tmp; + + exynos_pm_central_suspend(); /* Setting SEQ_OPTION register */ tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0); __raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); - if (!soc_is_exynos5250()) { - /* Save Power control register */ - asm ("mrc p15, 0, %0, c15, c0, 0" - : "=r" (tmp) : : "cc"); - save_arm_register[0] = tmp; - - /* Save Diagnostic register */ - asm ("mrc p15, 0, %0, c15, c0, 1" - : "=r" (tmp) : : "cc"); - save_arm_register[1] = tmp; - } + if (!soc_is_exynos5250()) + exynos_cpu_save_register(); return 0; } -static void exynos_pm_resume(void) +static int exynos_pm_central_resume(void) { unsigned long tmp; @@ -194,22 +258,20 @@ static void exynos_pm_resume(void) /* clear the wakeup state register */ __raw_writel(0x0, S5P_WAKEUP_STAT); /* No need to perform below restore code */ - goto early_wakeup; - } - if (!soc_is_exynos5250()) { - /* Restore Power control register */ - tmp = save_arm_register[0]; - asm volatile ("mcr p15, 0, %0, c15, c0, 0" - : : "r" (tmp) - : "cc"); - - /* Restore Diagnostic register */ - tmp = save_arm_register[1]; - asm volatile ("mcr p15, 0, %0, c15, c0, 1" - : : "r" (tmp) - : "cc"); + return -1; } + return 0; +} + +static void exynos_pm_resume(void) +{ + if (exynos_pm_central_resume()) + goto early_wakeup; + + if (!soc_is_exynos5250()) + exynos_cpu_restore_register(); + /* For release retention */ __raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION); @@ -226,7 +288,7 @@ static void exynos_pm_resume(void) s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); - if (IS_ENABLED(CONFIG_SMP) && !soc_is_exynos5250()) + if (!soc_is_exynos5250()) scu_enable(S5P_VA_SCU); early_wakeup: @@ -304,10 +366,42 @@ static const struct platform_suspend_ops exynos_suspend_ops = { .valid = suspend_valid_only_mem, }; +static int exynos_cpu_pm_notifier(struct notifier_block *self, + unsigned long cmd, void *v) +{ + int cpu = smp_processor_id(); + + switch (cmd) { + case CPU_PM_ENTER: + if (cpu == 0) { + exynos_pm_central_suspend(); + exynos_cpu_save_register(); + } + break; + + case CPU_PM_EXIT: + if (cpu == 0) { + if (!soc_is_exynos5250()) + scu_enable(S5P_VA_SCU); + exynos_cpu_restore_register(); + exynos_pm_central_resume(); + } + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block exynos_cpu_pm_notifier_block = { + .notifier_call = exynos_cpu_pm_notifier, +}; + void __init exynos_pm_init(void) { u32 tmp; + cpu_pm_register_notifier(&exynos_cpu_pm_notifier_block); + /* Platform-specific GIC callback */ gic_arch_extn.irq_set_wake = exynos_irq_set_wake; diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h index 4f6a2560d0220e..6c1d2db76715e6 100644 --- a/arch/arm/mach-exynos/regs-pmu.h +++ b/arch/arm/mach-exynos/regs-pmu.h @@ -119,8 +119,6 @@ #define S5P_CORE_LOCAL_PWR_EN 0x3 #define S5P_INT_LOCAL_PWR_EN 0x7 -#define S5P_CHECK_SLEEP 0x00000BAD - /* Only for EXYNOS4210 */ #define S5P_CMU_CLKSTOP_LCD1_LOWPWR S5P_PMUREG(0x1154) #define S5P_CMU_RESET_LCD1_LOWPWR S5P_PMUREG(0x1174) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 5740296dc42990..d56eb1a001d851 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -711,21 +711,6 @@ config MACH_IMX51_DT Include support for Freescale i.MX51 based platforms using the device tree for discovery -config MACH_MX51_BABBAGE - bool "Support MX51 BABBAGE platforms" - select IMX_HAVE_PLATFORM_FSL_USB2_UDC - select IMX_HAVE_PLATFORM_IMX2_WDT - select IMX_HAVE_PLATFORM_IMX_I2C - select IMX_HAVE_PLATFORM_IMX_UART - select IMX_HAVE_PLATFORM_MXC_EHCI - select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX - select IMX_HAVE_PLATFORM_SPI_IMX - select SOC_IMX51 - help - Include support for MX51 Babbage platform, also known as MX51EVK in - u-boot. This includes specific configurations for the board and its - peripherals. - config MACH_EUKREA_CPUIMX51SD bool "Support Eukrea CPUIMX51SD module" select IMX_HAVE_PLATFORM_FSL_USB2_UDC diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index f4ed83032dd0fc..8dd377be88a611 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -109,7 +109,6 @@ endif obj-$(CONFIG_SOC_IMX6) += pm-imx6.o # i.MX5 based machines -obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += mach-cpuimx51sd.o obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd51-baseboard.o diff --git a/arch/arm/mach-imx/clk-gate2.c b/arch/arm/mach-imx/clk-gate2.c index a2ecc006b322c2..4ba587da89d2ef 100644 --- a/arch/arm/mach-imx/clk-gate2.c +++ b/arch/arm/mach-imx/clk-gate2.c @@ -27,48 +27,61 @@ * parent - fixed parent. No clk_set_parent support */ -#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) +struct clk_gate2 { + struct clk_hw hw; + void __iomem *reg; + u8 bit_idx; + u8 flags; + spinlock_t *lock; + unsigned int *share_count; +}; + +#define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw) static int clk_gate2_enable(struct clk_hw *hw) { - struct clk_gate *gate = to_clk_gate(hw); + struct clk_gate2 *gate = to_clk_gate2(hw); u32 reg; unsigned long flags = 0; - if (gate->lock) - spin_lock_irqsave(gate->lock, flags); + spin_lock_irqsave(gate->lock, flags); + + if (gate->share_count && (*gate->share_count)++ > 0) + goto out; reg = readl(gate->reg); reg |= 3 << gate->bit_idx; writel(reg, gate->reg); - if (gate->lock) - spin_unlock_irqrestore(gate->lock, flags); +out: + spin_unlock_irqrestore(gate->lock, flags); return 0; } static void clk_gate2_disable(struct clk_hw *hw) { - struct clk_gate *gate = to_clk_gate(hw); + struct clk_gate2 *gate = to_clk_gate2(hw); u32 reg; unsigned long flags = 0; - if (gate->lock) - spin_lock_irqsave(gate->lock, flags); + spin_lock_irqsave(gate->lock, flags); + + if (gate->share_count && --(*gate->share_count) > 0) + goto out; reg = readl(gate->reg); reg &= ~(3 << gate->bit_idx); writel(reg, gate->reg); - if (gate->lock) - spin_unlock_irqrestore(gate->lock, flags); +out: + spin_unlock_irqrestore(gate->lock, flags); } static int clk_gate2_is_enabled(struct clk_hw *hw) { u32 reg; - struct clk_gate *gate = to_clk_gate(hw); + struct clk_gate2 *gate = to_clk_gate2(hw); reg = readl(gate->reg); @@ -87,21 +100,23 @@ static struct clk_ops clk_gate2_ops = { struct clk *clk_register_gate2(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, - u8 clk_gate2_flags, spinlock_t *lock) + u8 clk_gate2_flags, spinlock_t *lock, + unsigned int *share_count) { - struct clk_gate *gate; + struct clk_gate2 *gate; struct clk *clk; struct clk_init_data init; - gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); + gate = kzalloc(sizeof(struct clk_gate2), GFP_KERNEL); if (!gate) return ERR_PTR(-ENOMEM); - /* struct clk_gate assignments */ + /* struct clk_gate2 assignments */ gate->reg = reg; gate->bit_idx = bit_idx; gate->flags = clk_gate2_flags; gate->lock = lock; + gate->share_count = share_count; init.name = name; init.ops = &clk_gate2_ops; diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c index dc36e6c2f1da5b..ae578c096ad82e 100644 --- a/arch/arm/mach-imx/clk-imx25.c +++ b/arch/arm/mach-imx/clk-imx25.c @@ -62,6 +62,10 @@ static struct clk_onecell_data clk_data; static const char *cpu_sel_clks[] = { "mpll", "mpll_cpu_3_4", }; static const char *per_sel_clks[] = { "ahb", "upll", }; +static const char *cko_sel_clks[] = { "dummy", "osc", "cpu", "ahb", + "ipg", "dummy", "dummy", "dummy", + "dummy", "dummy", "per0", "per2", + "per13", "per14", "usbotg_ahb", "dummy",}; enum mx25_clks { dummy, osc, mpll, upll, mpll_cpu_3_4, cpu_sel, cpu, ahb, usb_div, ipg, @@ -82,7 +86,7 @@ enum mx25_clks { pwm2_ipg, pwm3_ipg, pwm4_ipg, rngb_ipg, reserved16, scc_ipg, sdma_ipg, sim1_ipg, sim2_ipg, slcdc_ipg, spba_ipg, ssi1_ipg, ssi2_ipg, tsc_ipg, uart1_ipg, uart2_ipg, uart3_ipg, uart4_ipg, uart5_ipg, reserved17, - wdt_ipg, clk_max + wdt_ipg, cko_div, cko_sel, cko, clk_max }; static struct clk *clk[clk_max]; @@ -117,6 +121,9 @@ static int __init __mx25_clocks_init(unsigned long osc_rate) clk[per13_sel] = imx_clk_mux("per13_sel", ccm(CCM_MCR), 13, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); clk[per14_sel] = imx_clk_mux("per14_sel", ccm(CCM_MCR), 14, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); clk[per15_sel] = imx_clk_mux("per15_sel", ccm(CCM_MCR), 15, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[cko_div] = imx_clk_divider("cko_div", "cko_sel", ccm(CCM_MCR), 24, 6); + clk[cko_sel] = imx_clk_mux("cko_sel", ccm(CCM_MCR), 20, 4, cko_sel_clks, ARRAY_SIZE(cko_sel_clks)); + clk[cko] = imx_clk_gate("cko", "cko_div", ccm(CCM_MCR), 30); clk[per0] = imx_clk_divider("per0", "per0_sel", ccm(CCM_PCDR0), 0, 6); clk[per1] = imx_clk_divider("per1", "per1_sel", ccm(CCM_PCDR0), 8, 6); clk[per2] = imx_clk_divider("per2", "per2_sel", ccm(CCM_PCDR0), 16, 6); @@ -230,6 +237,12 @@ static int __init __mx25_clocks_init(unsigned long osc_rate) clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0"); clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0"); + /* + * Let's initially set up CLKO parent as ipg, since this configuration + * is used on some imx25 board designs to clock the audio codec. + */ + clk_set_parent(clk[cko_sel], clk[ipg]); + return 0; } @@ -304,8 +317,6 @@ int __init mx25_clocks_init(void) int __init mx25_clocks_init_dt(void) { struct device_node *np; - void __iomem *base; - int irq; unsigned long osc_rate = 24000000; /* retrieve the freqency of fixed clocks from device tree */ @@ -325,12 +336,7 @@ int __init mx25_clocks_init_dt(void) __mx25_clocks_init(osc_rate); - np = of_find_compatible_node(NULL, NULL, "fsl,imx25-gpt"); - base = of_iomap(np, 0); - WARN_ON(!base); - irq = irq_of_parse_and_map(np, 0); - - mxc_timer_init(base, irq); + mxc_timer_init_dt(of_find_compatible_node(NULL, NULL, "fsl,imx25-gpt")); return 0; } diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index d2da8908b26859..317a662626d6ca 100644 --- a/arch/arm/mach-imx/clk-imx27.c +++ b/arch/arm/mach-imx/clk-imx27.c @@ -82,7 +82,8 @@ enum mx27_clks { csi_ahb_gate, brom_ahb_gate, ata_ahb_gate, wdog_ipg_gate, usb_ipg_gate, uart6_ipg_gate, uart5_ipg_gate, uart4_ipg_gate, uart3_ipg_gate, uart2_ipg_gate, uart1_ipg_gate, ckih_div1p5, fpm, mpll_osc_sel, - mpll_sel, spll_gate, clk_max + mpll_sel, spll_gate, mshc_div, rtic_ipg_gate, mshc_ipg_gate, + rtic_ahb_gate, mshc_baud_gate, clk_max }; static struct clk *clk[clk_max]; @@ -117,6 +118,7 @@ int __init mx27_clocks_init(unsigned long fref) clk[ipg] = imx_clk_divider("ipg", "ahb", CCM_CSCR, 8, 1); } + clk[mshc_div] = imx_clk_divider("mshc_div", "ahb", CCM_PCDR0, 0, 6); clk[nfc_div] = imx_clk_divider("nfc_div", "ahb", CCM_PCDR0, 6, 4); clk[per1_div] = imx_clk_divider("per1_div", "mpll_main2", CCM_PCDR1, 0, 6); clk[per2_div] = imx_clk_divider("per2_div", "mpll_main2", CCM_PCDR1, 8, 6); @@ -145,9 +147,11 @@ int __init mx27_clocks_init(unsigned long fref) clk[sdhc1_ipg_gate] = imx_clk_gate("sdhc1_ipg_gate", "ipg", CCM_PCCR0, 5); clk[scc_ipg_gate] = imx_clk_gate("scc_ipg_gate", "ipg", CCM_PCCR0, 6); clk[sahara_ipg_gate] = imx_clk_gate("sahara_ipg_gate", "ipg", CCM_PCCR0, 7); + clk[rtic_ipg_gate] = imx_clk_gate("rtic_ipg_gate", "ipg", CCM_PCCR0, 8); clk[rtc_ipg_gate] = imx_clk_gate("rtc_ipg_gate", "ipg", CCM_PCCR0, 9); clk[pwm_ipg_gate] = imx_clk_gate("pwm_ipg_gate", "ipg", CCM_PCCR0, 11); clk[owire_ipg_gate] = imx_clk_gate("owire_ipg_gate", "ipg", CCM_PCCR0, 12); + clk[mshc_ipg_gate] = imx_clk_gate("mshc_ipg_gate", "ipg", CCM_PCCR0, 13); clk[lcdc_ipg_gate] = imx_clk_gate("lcdc_ipg_gate", "ipg", CCM_PCCR0, 14); clk[kpp_ipg_gate] = imx_clk_gate("kpp_ipg_gate", "ipg", CCM_PCCR0, 15); clk[iim_ipg_gate] = imx_clk_gate("iim_ipg_gate", "ipg", CCM_PCCR0, 16); @@ -166,6 +170,7 @@ int __init mx27_clocks_init(unsigned long fref) clk[cspi3_ipg_gate] = imx_clk_gate("cspi3_ipg_gate", "ipg", CCM_PCCR0, 29); clk[cspi2_ipg_gate] = imx_clk_gate("cspi2_ipg_gate", "ipg", CCM_PCCR0, 30); clk[cspi1_ipg_gate] = imx_clk_gate("cspi1_ipg_gate", "ipg", CCM_PCCR0, 31); + clk[mshc_baud_gate] = imx_clk_gate("mshc_baud_gate", "mshc_div", CCM_PCCR1, 2); clk[nfc_baud_gate] = imx_clk_gate("nfc_baud_gate", "nfc_div", CCM_PCCR1, 3); clk[ssi2_baud_gate] = imx_clk_gate("ssi2_baud_gate", "ssi2_div", CCM_PCCR1, 4); clk[ssi1_baud_gate] = imx_clk_gate("ssi1_baud_gate", "ssi1_div", CCM_PCCR1, 5); @@ -177,6 +182,7 @@ int __init mx27_clocks_init(unsigned long fref) clk[usb_ahb_gate] = imx_clk_gate("usb_ahb_gate", "ahb", CCM_PCCR1, 11); clk[slcdc_ahb_gate] = imx_clk_gate("slcdc_ahb_gate", "ahb", CCM_PCCR1, 12); clk[sahara_ahb_gate] = imx_clk_gate("sahara_ahb_gate", "ahb", CCM_PCCR1, 13); + clk[rtic_ahb_gate] = imx_clk_gate("rtic_ahb_gate", "ahb", CCM_PCCR1, 14); clk[lcdc_ahb_gate] = imx_clk_gate("lcdc_ahb_gate", "ahb", CCM_PCCR1, 15); clk[vpu_ahb_gate] = imx_clk_gate("vpu_ahb_gate", "ahb", CCM_PCCR1, 16); clk[fec_ahb_gate] = imx_clk_gate("fec_ahb_gate", "ahb", CCM_PCCR1, 17); @@ -221,16 +227,6 @@ int __init mx27_clocks_init(unsigned long fref) clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.5"); clk_register_clkdev(clk[gpt1_ipg_gate], "ipg", "imx-gpt.0"); clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.0"); - clk_register_clkdev(clk[gpt2_ipg_gate], "ipg", "imx-gpt.1"); - clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.1"); - clk_register_clkdev(clk[gpt3_ipg_gate], "ipg", "imx-gpt.2"); - clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.2"); - clk_register_clkdev(clk[gpt4_ipg_gate], "ipg", "imx-gpt.3"); - clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.3"); - clk_register_clkdev(clk[gpt5_ipg_gate], "ipg", "imx-gpt.4"); - clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.4"); - clk_register_clkdev(clk[gpt6_ipg_gate], "ipg", "imx-gpt.5"); - clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.5"); clk_register_clkdev(clk[per2_gate], "per", "imx21-mmc.0"); clk_register_clkdev(clk[sdhc1_ipg_gate], "ipg", "imx21-mmc.0"); clk_register_clkdev(clk[per2_gate], "per", "imx21-mmc.1"); @@ -278,14 +274,7 @@ int __init mx27_clocks_init(unsigned long fref) clk_register_clkdev(clk[emma_ipg_gate], "emma-ipg", "imx27-camera.0"); clk_register_clkdev(clk[emma_ahb_gate], "ahb", "m2m-emmaprp.0"); clk_register_clkdev(clk[emma_ipg_gate], "ipg", "m2m-emmaprp.0"); - clk_register_clkdev(clk[iim_ipg_gate], "iim", NULL); - clk_register_clkdev(clk[gpio_ipg_gate], "gpio", NULL); - clk_register_clkdev(clk[brom_ahb_gate], "brom", NULL); - clk_register_clkdev(clk[ata_ahb_gate], "ata", NULL); - clk_register_clkdev(clk[rtc_ipg_gate], NULL, "imx21-rtc"); - clk_register_clkdev(clk[scc_ipg_gate], "scc", NULL); clk_register_clkdev(clk[cpu_div], NULL, "cpu0"); - clk_register_clkdev(clk[emi_ahb_gate], "emi_ahb" , NULL); mxc_timer_init(MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR), MX27_INT_GPT1); @@ -296,7 +285,6 @@ int __init mx27_clocks_init(unsigned long fref) return 0; } -#ifdef CONFIG_OF int __init mx27_clocks_init_dt(void) { struct device_node *np; @@ -312,4 +300,3 @@ int __init mx27_clocks_init_dt(void) return mx27_clocks_init(fref); } -#endif diff --git a/arch/arm/mach-imx/clk-imx31.c b/arch/arm/mach-imx/clk-imx31.c index b5b65f3efaf1c3..4a9de0835eb1d0 100644 --- a/arch/arm/mach-imx/clk-imx31.c +++ b/arch/arm/mach-imx/clk-imx31.c @@ -191,7 +191,6 @@ int __init mx31_clocks_init(unsigned long fref) return 0; } -#ifdef CONFIG_OF int __init mx31_clocks_init_dt(void) { struct device_node *np; @@ -207,4 +206,3 @@ int __init mx31_clocks_init_dt(void) return mx31_clocks_init(fref); } -#endif diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index 568ef0a4de84b8..21d2b111c83d5e 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -322,9 +322,8 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil, static void __init mx50_clocks_init(struct device_node *np) { - void __iomem *base; unsigned long r; - int i, irq; + int i; clk[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", MX53_DPLL1_BASE); clk[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", MX53_DPLL2_BASE); @@ -372,11 +371,7 @@ static void __init mx50_clocks_init(struct device_node *np) r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000); clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r); - np = of_find_compatible_node(NULL, NULL, "fsl,imx50-gpt"); - base = of_iomap(np, 0); - WARN_ON(!base); - irq = irq_of_parse_and_map(np, 0); - mxc_timer_init(base, irq); + mxc_timer_init_dt(of_find_compatible_node(NULL, NULL, "fsl,imx50-gpt")); } CLK_OF_DECLARE(imx50_ccm, "fsl,imx50-ccm", mx50_clocks_init); @@ -436,7 +431,6 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, clk_register_clkdev(clk[IMX5_CLK_HSI2C_GATE], NULL, "imx21-i2c.2"); clk_register_clkdev(clk[IMX5_CLK_MX51_MIPI], "mipi_hsp", NULL); - clk_register_clkdev(clk[IMX5_CLK_VPU_GATE], NULL, "imx51-vpu.0"); clk_register_clkdev(clk[IMX5_CLK_FEC_GATE], NULL, "imx27-fec.0"); clk_register_clkdev(clk[IMX5_CLK_USB_PHY_GATE], "phy", "mxc-ehci.0"); clk_register_clkdev(clk[IMX5_CLK_ESDHC1_IPG_GATE], "ipg", "sdhci-esdhc-imx51.0"); @@ -492,9 +486,8 @@ CLK_OF_DECLARE(imx51_ccm, "fsl,imx51-ccm", mx51_clocks_init_dt); static void __init mx53_clocks_init(struct device_node *np) { - int i, irq; + int i; unsigned long r; - void __iomem *base; clk[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", MX53_DPLL1_BASE); clk[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", MX53_DPLL2_BASE); @@ -561,7 +554,6 @@ static void __init mx53_clocks_init(struct device_node *np) mx5_clocks_common_init(0, 0, 0, 0); - clk_register_clkdev(clk[IMX5_CLK_VPU_GATE], NULL, "imx53-vpu.0"); clk_register_clkdev(clk[IMX5_CLK_I2C3_GATE], NULL, "imx21-i2c.2"); clk_register_clkdev(clk[IMX5_CLK_FEC_GATE], NULL, "imx25-fec.0"); clk_register_clkdev(clk[IMX5_CLK_USB_PHY1_GATE], "usb_phy1", "mxc-ehci.0"); @@ -592,10 +584,6 @@ static void __init mx53_clocks_init(struct device_node *np) r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000); clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r); - np = of_find_compatible_node(NULL, NULL, "fsl,imx53-gpt"); - base = of_iomap(np, 0); - WARN_ON(!base); - irq = irq_of_parse_and_map(np, 0); - mxc_timer_init(base, irq); + mxc_timer_init_dt(of_find_compatible_node(NULL, NULL, "fsl,imx53-gpt")); } CLK_OF_DECLARE(imx53_ccm, "fsl,imx53-ccm", mx53_clocks_init); diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 2b4d6acfa34abd..8e795dea02ece0 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -107,7 +107,7 @@ enum mx6q_clks { sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate, usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow, spdif, cko2_sel, cko2_podf, cko2, cko, vdoa, pll4_audio_div, - lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, clk_max + lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, esai_ahb, clk_max }; static struct clk *clk[clk_max]; @@ -140,11 +140,13 @@ static struct clk_div_table video_div_table[] = { { /* sentinel */ } }; +static unsigned int share_count_esai; + static void __init imx6q_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; - int i, irq; + int i; int ret; clk[dummy] = imx_clk_fixed("dummy", 0); @@ -352,9 +354,14 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[ecspi2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2); clk[ecspi3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4); clk[ecspi4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6); - clk[ecspi5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8); + if (cpu_is_imx6dl()) + /* ecspi5 is replaced with i2c4 on imx6dl & imx6s */ + clk[ecspi5] = imx_clk_gate2("i2c4", "ipg_per", base + 0x6c, 8); + else + clk[ecspi5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8); clk[enet] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10); - clk[esai] = imx_clk_gate2("esai", "esai_podf", base + 0x6c, 16); + clk[esai] = imx_clk_gate2_shared("esai", "esai_podf", base + 0x6c, 16, &share_count_esai); + clk[esai_ahb] = imx_clk_gate2_shared("esai_ahb", "ahb", base + 0x6c, 16, &share_count_esai); clk[gpt_ipg] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20); clk[gpt_ipg_per] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22); if (cpu_is_imx6dl()) @@ -489,10 +496,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) /* Set initial power mode */ imx6q_set_lpm(WAIT_CLOCKED); - np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); - base = of_iomap(np, 0); - WARN_ON(!base); - irq = irq_of_parse_and_map(np, 0); - mxc_timer_init(base, irq); + mxc_timer_init_dt(of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt")); } CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init); diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c index f7073c0782fb0f..21cf06cebade55 100644 --- a/arch/arm/mach-imx/clk-imx6sl.c +++ b/arch/arm/mach-imx/clk-imx6sl.c @@ -169,7 +169,6 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; - int irq; int i; int ret; @@ -385,9 +384,6 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) imx6q_set_lpm(WAIT_CLOCKED); np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-gpt"); - base = of_iomap(np, 0); - WARN_ON(!base); - irq = irq_of_parse_and_map(np, 0); - mxc_timer_init(base, irq); + mxc_timer_init_dt(np); } CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init); diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h index 048c5ad8a80b67..e29f6ebe9f39d0 100644 --- a/arch/arm/mach-imx/clk.h +++ b/arch/arm/mach-imx/clk.h @@ -28,7 +28,8 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, struct clk *clk_register_gate2(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, - u8 clk_gate_flags, spinlock_t *lock); + u8 clk_gate_flags, spinlock_t *lock, + unsigned int *share_count); struct clk * imx_obtain_fixed_clock( const char *name, unsigned long rate); @@ -37,7 +38,15 @@ static inline struct clk *imx_clk_gate2(const char *name, const char *parent, void __iomem *reg, u8 shift) { return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, - shift, 0, &imx_ccm_lock); + shift, 0, &imx_ccm_lock, NULL); +} + +static inline struct clk *imx_clk_gate2_shared(const char *name, + const char *parent, void __iomem *reg, u8 shift, + unsigned int *share_count) +{ + return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + shift, 0, &imx_ccm_lock, share_count); } struct clk *imx_clk_pfd(const char *name, const char *parent_name, diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index b5241ea7670642..4facd01d1c75f8 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -17,6 +17,7 @@ struct irq_data; struct platform_device; struct pt_regs; struct clk; +struct device_node; enum mxc_cpu_pwr_mode; void mx1_map_io(void); @@ -56,6 +57,7 @@ void imx51_init_late(void); void imx53_init_late(void); void epit_timer_init(void __iomem *base, int irq); void mxc_timer_init(void __iomem *, int); +void mxc_timer_init_dt(struct device_node *); int mx1_clocks_init(unsigned long fref); int mx21_clocks_init(unsigned long lref, unsigned long fref); int mx25_clocks_init(void); diff --git a/arch/arm/mach-imx/devices/platform-mx2-emma.c b/arch/arm/mach-imx/devices/platform-mx2-emma.c index 11bd01d402f290..0dc0651825b144 100644 --- a/arch/arm/mach-imx/devices/platform-mx2-emma.c +++ b/arch/arm/mach-imx/devices/platform-mx2-emma.c @@ -12,7 +12,7 @@ #define imx_mx2_emmaprp_data_entry_single(soc) \ { \ .iobase = soc ## _EMMAPRP_BASE_ADDR, \ - .iosize = SZ_32, \ + .iosize = SZ_256, \ .irq = soc ## _INT_EMMAPRP, \ } diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c index a06aa4dc37fc4f..30c30fdae53fe3 100644 --- a/arch/arm/mach-imx/mach-mx21ads.c +++ b/arch/arm/mach-imx/mach-mx21ads.c @@ -17,51 +17,46 @@ #include #include #include +#include #include +#include +#include #include #include -#include -#include #include "common.h" #include "devices-imx21.h" #include "hardware.h" #include "iomux-mx21.h" -/* - * Memory-mapped I/O on MX21ADS base board - */ -#define MX21ADS_MMIO_BASE_ADDR 0xf5000000 -#define MX21ADS_MMIO_SIZE 0xc00000 - -#define MX21ADS_REG_ADDR(offset) (void __force __iomem *) \ - (MX21ADS_MMIO_BASE_ADDR + (offset)) +#define MX21ADS_CS8900A_REG (MX21_CS1_BASE_ADDR + 0x000000) +#define MX21ADS_ST16C255_IOBASE_REG (MX21_CS1_BASE_ADDR + 0x200000) +#define MX21ADS_VERSION_REG (MX21_CS1_BASE_ADDR + 0x400000) +#define MX21ADS_IO_REG (MX21_CS1_BASE_ADDR + 0x800000) -#define MX21ADS_CS8900A_MMIO_SIZE 0x200000 -#define MX21ADS_CS8900A_IRQ_GPIO IMX_GPIO_NR(5, 11) -#define MX21ADS_ST16C255_IOBASE_REG MX21ADS_REG_ADDR(0x200000) -#define MX21ADS_VERSION_REG MX21ADS_REG_ADDR(0x400000) -#define MX21ADS_IO_REG MX21ADS_REG_ADDR(0x800000) +#define MX21ADS_MMC_CD IMX_GPIO_NR(4, 25) +#define MX21ADS_CS8900A_IRQ_GPIO IMX_GPIO_NR(5, 11) +#define MX21ADS_MMGPIO_BASE (6 * 32) /* MX21ADS_IO_REG bit definitions */ -#define MX21ADS_IO_SD_WP 0x0001 /* read */ -#define MX21ADS_IO_TP6 0x0001 /* write */ -#define MX21ADS_IO_SW_SEL 0x0002 /* read */ -#define MX21ADS_IO_TP7 0x0002 /* write */ -#define MX21ADS_IO_RESET_E_UART 0x0004 -#define MX21ADS_IO_RESET_BASE 0x0008 -#define MX21ADS_IO_CSI_CTL2 0x0010 -#define MX21ADS_IO_CSI_CTL1 0x0020 -#define MX21ADS_IO_CSI_CTL0 0x0040 -#define MX21ADS_IO_UART1_EN 0x0080 -#define MX21ADS_IO_UART4_EN 0x0100 -#define MX21ADS_IO_LCDON 0x0200 -#define MX21ADS_IO_IRDA_EN 0x0400 -#define MX21ADS_IO_IRDA_FIR_SEL 0x0800 -#define MX21ADS_IO_IRDA_MD0_B 0x1000 -#define MX21ADS_IO_IRDA_MD1 0x2000 -#define MX21ADS_IO_LED4_ON 0x4000 -#define MX21ADS_IO_LED3_ON 0x8000 +#define MX21ADS_IO_SD_WP (MX21ADS_MMGPIO_BASE + 0) +#define MX21ADS_IO_TP6 (MX21ADS_IO_SD_WP) +#define MX21ADS_IO_SW_SEL (MX21ADS_MMGPIO_BASE + 1) +#define MX21ADS_IO_TP7 (MX21ADS_IO_SW_SEL) +#define MX21ADS_IO_RESET_E_UART (MX21ADS_MMGPIO_BASE + 2) +#define MX21ADS_IO_RESET_BASE (MX21ADS_MMGPIO_BASE + 3) +#define MX21ADS_IO_CSI_CTL2 (MX21ADS_MMGPIO_BASE + 4) +#define MX21ADS_IO_CSI_CTL1 (MX21ADS_MMGPIO_BASE + 5) +#define MX21ADS_IO_CSI_CTL0 (MX21ADS_MMGPIO_BASE + 6) +#define MX21ADS_IO_UART1_EN (MX21ADS_MMGPIO_BASE + 7) +#define MX21ADS_IO_UART4_EN (MX21ADS_MMGPIO_BASE + 8) +#define MX21ADS_IO_LCDON (MX21ADS_MMGPIO_BASE + 9) +#define MX21ADS_IO_IRDA_EN (MX21ADS_MMGPIO_BASE + 10) +#define MX21ADS_IO_IRDA_FIR_SEL (MX21ADS_MMGPIO_BASE + 11) +#define MX21ADS_IO_IRDA_MD0_B (MX21ADS_MMGPIO_BASE + 12) +#define MX21ADS_IO_IRDA_MD1 (MX21ADS_MMGPIO_BASE + 13) +#define MX21ADS_IO_LED4_ON (MX21ADS_MMGPIO_BASE + 14) +#define MX21ADS_IO_LED3_ON (MX21ADS_MMGPIO_BASE + 15) static const int mx21ads_pins[] __initconst = { @@ -143,11 +138,8 @@ static struct physmap_flash_data mx21ads_flash_data = { .width = 4, }; -static struct resource mx21ads_flash_resource = { - .start = MX21_CS0_BASE_ADDR, - .end = MX21_CS0_BASE_ADDR + 0x02000000 - 1, - .flags = IORESOURCE_MEM, -}; +static struct resource mx21ads_flash_resource = + DEFINE_RES_MEM(MX21_CS0_BASE_ADDR, SZ_32M); static struct platform_device mx21ads_nor_mtd_device = { .name = "physmap-flash", @@ -160,7 +152,7 @@ static struct platform_device mx21ads_nor_mtd_device = { }; static struct resource mx21ads_cs8900_resources[] __initdata = { - DEFINE_RES_MEM(MX21_CS1_BASE_ADDR, MX21ADS_CS8900A_MMIO_SIZE), + DEFINE_RES_MEM(MX21ADS_CS8900A_REG, SZ_1K), /* irq number is run-time assigned */ DEFINE_RES_IRQ(-1), }; @@ -179,24 +171,50 @@ static const struct imxuart_platform_data uart_pdata_rts __initconst = { static const struct imxuart_platform_data uart_pdata_norts __initconst = { }; -static int mx21ads_fb_init(struct platform_device *pdev) -{ - u16 tmp; +static struct resource mx21ads_mmgpio_resource = + DEFINE_RES_MEM_NAMED(MX21ADS_IO_REG, SZ_2, "dat"); - tmp = __raw_readw(MX21ADS_IO_REG); - tmp |= MX21ADS_IO_LCDON; - __raw_writew(tmp, MX21ADS_IO_REG); - return 0; -} +static struct bgpio_pdata mx21ads_mmgpio_pdata = { + .base = MX21ADS_MMGPIO_BASE, + .ngpio = 16, +}; -static void mx21ads_fb_exit(struct platform_device *pdev) -{ - u16 tmp; +static struct platform_device mx21ads_mmgpio = { + .name = "basic-mmio-gpio", + .id = PLATFORM_DEVID_AUTO, + .resource = &mx21ads_mmgpio_resource, + .num_resources = 1, + .dev = { + .platform_data = &mx21ads_mmgpio_pdata, + }, +}; - tmp = __raw_readw(MX21ADS_IO_REG); - tmp &= ~MX21ADS_IO_LCDON; - __raw_writew(tmp, MX21ADS_IO_REG); -} +static struct regulator_consumer_supply mx21ads_lcd_regulator_consumer = + REGULATOR_SUPPLY("lcd", "imx-fb.0"); + +static struct regulator_init_data mx21ads_lcd_regulator_init_data = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = &mx21ads_lcd_regulator_consumer, + .num_consumer_supplies = 1, +}; + +static struct fixed_voltage_config mx21ads_lcd_regulator_pdata = { + .supply_name = "LCD", + .microvolts = 3300000, + .gpio = MX21ADS_IO_LCDON, + .enable_high = 1, + .init_data = &mx21ads_lcd_regulator_init_data, +}; + +static struct platform_device mx21ads_lcd_regulator = { + .name = "reg-fixed-voltage", + .id = PLATFORM_DEVID_AUTO, + .dev = { + .platform_data = &mx21ads_lcd_regulator_pdata, + }, +}; /* * Connected is a portrait Sharp-QVGA display @@ -229,26 +247,30 @@ static const struct imx_fb_platform_data mx21ads_fb_data __initconst = { .pwmr = 0x00a903ff, .lscr1 = 0x00120300, .dmacr = 0x00020008, - - .init = mx21ads_fb_init, - .exit = mx21ads_fb_exit, }; static int mx21ads_sdhc_get_ro(struct device *dev) { - return (__raw_readw(MX21ADS_IO_REG) & MX21ADS_IO_SD_WP) ? 1 : 0; + return gpio_get_value(MX21ADS_IO_SD_WP); } static int mx21ads_sdhc_init(struct device *dev, irq_handler_t detect_irq, void *data) { - return request_irq(gpio_to_irq(IMX_GPIO_NR(4, 25)), detect_irq, - IRQF_TRIGGER_FALLING, "mmc-detect", data); + int ret; + + ret = gpio_request(MX21ADS_IO_SD_WP, "mmc-ro"); + if (ret) + return ret; + + return request_irq(gpio_to_irq(MX21ADS_MMC_CD), detect_irq, + IRQF_TRIGGER_FALLING, "mmc-detect", data); } static void mx21ads_sdhc_exit(struct device *dev, void *data) { - free_irq(gpio_to_irq(IMX_GPIO_NR(4, 25)), data); + free_irq(gpio_to_irq(MX21ADS_MMC_CD), data); + gpio_free(MX21ADS_IO_SD_WP); } static const struct imxmmc_platform_data mx21ads_sdhc_pdata __initconst = { @@ -264,29 +286,9 @@ mx21ads_nand_board_info __initconst = { .hw_ecc = 1, }; -static struct map_desc mx21ads_io_desc[] __initdata = { - /* - * Memory-mapped I/O on MX21ADS Base board: - * - CS8900A Ethernet controller - * - ST16C2552CJ UART - * - CPU and Base board version - * - Base board I/O register - */ - { - .virtual = MX21ADS_MMIO_BASE_ADDR, - .pfn = __phys_to_pfn(MX21_CS1_BASE_ADDR), - .length = MX21ADS_MMIO_SIZE, - .type = MT_DEVICE, - }, -}; - -static void __init mx21ads_map_io(void) -{ - mx21_map_io(); - iotable_init(mx21ads_io_desc, ARRAY_SIZE(mx21ads_io_desc)); -} - static struct platform_device *platform_devices[] __initdata = { + &mx21ads_mmgpio, + &mx21ads_lcd_regulator, &mx21ads_nor_mtd_device, }; @@ -300,12 +302,13 @@ static void __init mx21ads_board_init(void) imx21_add_imx_uart0(&uart_pdata_rts); imx21_add_imx_uart2(&uart_pdata_norts); imx21_add_imx_uart3(&uart_pdata_rts); - imx21_add_imx_fb(&mx21ads_fb_data); imx21_add_mxc_mmc(0, &mx21ads_sdhc_pdata); imx21_add_mxc_nand(&mx21ads_nand_board_info); platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + imx21_add_imx_fb(&mx21ads_fb_data); + mx21ads_cs8900_resources[1].start = gpio_to_irq(MX21ADS_CS8900A_IRQ_GPIO); mx21ads_cs8900_resources[1].end = @@ -321,7 +324,7 @@ static void __init mx21ads_timer_init(void) MACHINE_START(MX21ADS, "Freescale i.MX21ADS") /* maintainer: Freescale Semiconductor, Inc. */ .atag_offset = 0x100, - .map_io = mx21ads_map_io, + .map_io = mx21_map_io, .init_early = imx21_init_early, .init_irq = mx21_init_irq, .handle_irq = imx21_handle_irq, diff --git a/arch/arm/mach-imx/mach-mx51_babbage.c b/arch/arm/mach-imx/mach-mx51_babbage.c deleted file mode 100644 index f3d264a636fa9b..00000000000000 --- a/arch/arm/mach-imx/mach-mx51_babbage.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright (C) 2009-2010 Amit Kucheria - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "common.h" -#include "devices-imx51.h" -#include "hardware.h" -#include "iomux-mx51.h" - -#define BABBAGE_USB_HUB_RESET IMX_GPIO_NR(1, 7) -#define BABBAGE_USBH1_STP IMX_GPIO_NR(1, 27) -#define BABBAGE_USB_PHY_RESET IMX_GPIO_NR(2, 5) -#define BABBAGE_FEC_PHY_RESET IMX_GPIO_NR(2, 14) -#define BABBAGE_POWER_KEY IMX_GPIO_NR(2, 21) -#define BABBAGE_ECSPI1_CS0 IMX_GPIO_NR(4, 24) -#define BABBAGE_ECSPI1_CS1 IMX_GPIO_NR(4, 25) -#define BABBAGE_SD2_CD IMX_GPIO_NR(1, 6) -#define BABBAGE_SD2_WP IMX_GPIO_NR(1, 5) - -/* USB_CTRL_1 */ -#define MX51_USB_CTRL_1_OFFSET 0x10 -#define MX51_USB_CTRL_UH1_EXT_CLK_EN (1 << 25) - -#define MX51_USB_PLLDIV_12_MHZ 0x00 -#define MX51_USB_PLL_DIV_19_2_MHZ 0x01 -#define MX51_USB_PLL_DIV_24_MHZ 0x02 - -static struct gpio_keys_button babbage_buttons[] = { - { - .gpio = BABBAGE_POWER_KEY, - .code = BTN_0, - .desc = "PWR", - .active_low = 1, - .wakeup = 1, - }, -}; - -static const struct gpio_keys_platform_data imx_button_data __initconst = { - .buttons = babbage_buttons, - .nbuttons = ARRAY_SIZE(babbage_buttons), -}; - -static iomux_v3_cfg_t mx51babbage_pads[] = { - /* UART1 */ - MX51_PAD_UART1_RXD__UART1_RXD, - MX51_PAD_UART1_TXD__UART1_TXD, - MX51_PAD_UART1_RTS__UART1_RTS, - MX51_PAD_UART1_CTS__UART1_CTS, - - /* UART2 */ - MX51_PAD_UART2_RXD__UART2_RXD, - MX51_PAD_UART2_TXD__UART2_TXD, - - /* UART3 */ - MX51_PAD_EIM_D25__UART3_RXD, - MX51_PAD_EIM_D26__UART3_TXD, - MX51_PAD_EIM_D27__UART3_RTS, - MX51_PAD_EIM_D24__UART3_CTS, - - /* I2C1 */ - MX51_PAD_EIM_D16__I2C1_SDA, - MX51_PAD_EIM_D19__I2C1_SCL, - - /* I2C2 */ - MX51_PAD_KEY_COL4__I2C2_SCL, - MX51_PAD_KEY_COL5__I2C2_SDA, - - /* HSI2C */ - MX51_PAD_I2C1_CLK__I2C1_CLK, - MX51_PAD_I2C1_DAT__I2C1_DAT, - - /* USB HOST1 */ - MX51_PAD_USBH1_CLK__USBH1_CLK, - MX51_PAD_USBH1_DIR__USBH1_DIR, - MX51_PAD_USBH1_NXT__USBH1_NXT, - MX51_PAD_USBH1_DATA0__USBH1_DATA0, - MX51_PAD_USBH1_DATA1__USBH1_DATA1, - MX51_PAD_USBH1_DATA2__USBH1_DATA2, - MX51_PAD_USBH1_DATA3__USBH1_DATA3, - MX51_PAD_USBH1_DATA4__USBH1_DATA4, - MX51_PAD_USBH1_DATA5__USBH1_DATA5, - MX51_PAD_USBH1_DATA6__USBH1_DATA6, - MX51_PAD_USBH1_DATA7__USBH1_DATA7, - - /* USB HUB reset line*/ - MX51_PAD_GPIO1_7__GPIO1_7, - - /* USB PHY reset line */ - MX51_PAD_EIM_D21__GPIO2_5, - - /* FEC */ - MX51_PAD_EIM_EB2__FEC_MDIO, - MX51_PAD_EIM_EB3__FEC_RDATA1, - MX51_PAD_EIM_CS2__FEC_RDATA2, - MX51_PAD_EIM_CS3__FEC_RDATA3, - MX51_PAD_EIM_CS4__FEC_RX_ER, - MX51_PAD_EIM_CS5__FEC_CRS, - MX51_PAD_NANDF_RB2__FEC_COL, - MX51_PAD_NANDF_RB3__FEC_RX_CLK, - MX51_PAD_NANDF_D9__FEC_RDATA0, - MX51_PAD_NANDF_D8__FEC_TDATA0, - MX51_PAD_NANDF_CS2__FEC_TX_ER, - MX51_PAD_NANDF_CS3__FEC_MDC, - MX51_PAD_NANDF_CS4__FEC_TDATA1, - MX51_PAD_NANDF_CS5__FEC_TDATA2, - MX51_PAD_NANDF_CS6__FEC_TDATA3, - MX51_PAD_NANDF_CS7__FEC_TX_EN, - MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK, - - /* FEC PHY reset line */ - MX51_PAD_EIM_A20__GPIO2_14, - - /* SD 1 */ - MX51_PAD_SD1_CMD__SD1_CMD, - MX51_PAD_SD1_CLK__SD1_CLK, - MX51_PAD_SD1_DATA0__SD1_DATA0, - MX51_PAD_SD1_DATA1__SD1_DATA1, - MX51_PAD_SD1_DATA2__SD1_DATA2, - MX51_PAD_SD1_DATA3__SD1_DATA3, - /* CD/WP from controller */ - MX51_PAD_GPIO1_0__SD1_CD, - MX51_PAD_GPIO1_1__SD1_WP, - - /* SD 2 */ - MX51_PAD_SD2_CMD__SD2_CMD, - MX51_PAD_SD2_CLK__SD2_CLK, - MX51_PAD_SD2_DATA0__SD2_DATA0, - MX51_PAD_SD2_DATA1__SD2_DATA1, - MX51_PAD_SD2_DATA2__SD2_DATA2, - MX51_PAD_SD2_DATA3__SD2_DATA3, - /* CD/WP gpio */ - MX51_PAD_GPIO1_6__GPIO1_6, - MX51_PAD_GPIO1_5__GPIO1_5, - - /* eCSPI1 */ - MX51_PAD_CSPI1_MISO__ECSPI1_MISO, - MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI, - MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK, - MX51_PAD_CSPI1_SS0__GPIO4_24, - MX51_PAD_CSPI1_SS1__GPIO4_25, - - /* Audio */ - MX51_PAD_AUD3_BB_TXD__AUD3_TXD, - MX51_PAD_AUD3_BB_RXD__AUD3_RXD, - MX51_PAD_AUD3_BB_CK__AUD3_TXC, - MX51_PAD_AUD3_BB_FS__AUD3_TXFS, -}; - -/* Serial ports */ -static const struct imxuart_platform_data uart_pdata __initconst = { - .flags = IMXUART_HAVE_RTSCTS, -}; - -static const struct imxi2c_platform_data babbage_i2c_data __initconst = { - .bitrate = 100000, -}; - -static const struct imxi2c_platform_data babbage_hsi2c_data __initconst = { - .bitrate = 400000, -}; - -static struct gpio mx51_babbage_usbh1_gpios[] = { - { BABBAGE_USBH1_STP, GPIOF_OUT_INIT_LOW, "usbh1_stp" }, - { BABBAGE_USB_PHY_RESET, GPIOF_OUT_INIT_LOW, "usbh1_phy_reset" }, -}; - -static int gpio_usbh1_active(void) -{ - iomux_v3_cfg_t usbh1stp_gpio = MX51_PAD_USBH1_STP__GPIO1_27; - int ret; - - /* Set USBH1_STP to GPIO and toggle it */ - mxc_iomux_v3_setup_pad(usbh1stp_gpio); - ret = gpio_request_array(mx51_babbage_usbh1_gpios, - ARRAY_SIZE(mx51_babbage_usbh1_gpios)); - - if (ret) { - pr_debug("failed to get USBH1 pins: %d\n", ret); - return ret; - } - - msleep(100); - gpio_set_value(BABBAGE_USBH1_STP, 1); - gpio_set_value(BABBAGE_USB_PHY_RESET, 1); - gpio_free_array(mx51_babbage_usbh1_gpios, - ARRAY_SIZE(mx51_babbage_usbh1_gpios)); - return 0; -} - -static inline void babbage_usbhub_reset(void) -{ - int ret; - - /* Reset USB hub */ - ret = gpio_request_one(BABBAGE_USB_HUB_RESET, - GPIOF_OUT_INIT_LOW, "GPIO1_7"); - if (ret) { - printk(KERN_ERR"failed to get GPIO_USB_HUB_RESET: %d\n", ret); - return; - } - - msleep(2); - /* Deassert reset */ - gpio_set_value(BABBAGE_USB_HUB_RESET, 1); -} - -static inline void babbage_fec_reset(void) -{ - int ret; - - /* reset FEC PHY */ - ret = gpio_request_one(BABBAGE_FEC_PHY_RESET, - GPIOF_OUT_INIT_LOW, "fec-phy-reset"); - if (ret) { - printk(KERN_ERR"failed to get GPIO_FEC_PHY_RESET: %d\n", ret); - return; - } - msleep(1); - gpio_set_value(BABBAGE_FEC_PHY_RESET, 1); -} - -/* This function is board specific as the bit mask for the plldiv will also -be different for other Freescale SoCs, thus a common bitmask is not -possible and cannot get place in /plat-mxc/ehci.c.*/ -static int initialize_otg_port(struct platform_device *pdev) -{ - u32 v; - void __iomem *usb_base; - void __iomem *usbother_base; - - usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K); - if (!usb_base) - return -ENOMEM; - usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; - - /* Set the PHY clock to 19.2MHz */ - v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET); - v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK; - v |= MX51_USB_PLL_DIV_19_2_MHZ; - __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET); - iounmap(usb_base); - - mdelay(10); - - return mx51_initialize_usb_hw(0, MXC_EHCI_INTERNAL_PHY); -} - -static int initialize_usbh1_port(struct platform_device *pdev) -{ - u32 v; - void __iomem *usb_base; - void __iomem *usbother_base; - - usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K); - if (!usb_base) - return -ENOMEM; - usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; - - /* The clock for the USBH1 ULPI port will come externally from the PHY. */ - v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET); - __raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + MX51_USB_CTRL_1_OFFSET); - iounmap(usb_base); - - mdelay(10); - - return mx51_initialize_usb_hw(1, MXC_EHCI_POWER_PINS_ENABLED | - MXC_EHCI_ITC_NO_THRESHOLD); -} - -static const struct mxc_usbh_platform_data dr_utmi_config __initconst = { - .init = initialize_otg_port, - .portsc = MXC_EHCI_UTMI_16BIT, -}; - -static const struct fsl_usb2_platform_data usb_pdata __initconst = { - .operating_mode = FSL_USB2_DR_DEVICE, - .phy_mode = FSL_USB2_PHY_UTMI_WIDE, -}; - -static const struct mxc_usbh_platform_data usbh1_config __initconst = { - .init = initialize_usbh1_port, - .portsc = MXC_EHCI_MODE_ULPI, -}; - -static bool otg_mode_host __initdata; - -static int __init babbage_otg_mode(char *options) -{ - if (!strcmp(options, "host")) - otg_mode_host = true; - else if (!strcmp(options, "device")) - otg_mode_host = false; - else - pr_info("otg_mode neither \"host\" nor \"device\". " - "Defaulting to device\n"); - return 1; -} -__setup("otg_mode=", babbage_otg_mode); - -static struct spi_board_info mx51_babbage_spi_board_info[] __initdata = { - { - .modalias = "mtd_dataflash", - .max_speed_hz = 25000000, - .bus_num = 0, - .chip_select = 1, - .mode = SPI_MODE_0, - .platform_data = NULL, - }, -}; - -static int mx51_babbage_spi_cs[] = { - BABBAGE_ECSPI1_CS0, - BABBAGE_ECSPI1_CS1, -}; - -static const struct spi_imx_master mx51_babbage_spi_pdata __initconst = { - .chipselect = mx51_babbage_spi_cs, - .num_chipselect = ARRAY_SIZE(mx51_babbage_spi_cs), -}; - -static const struct esdhc_platform_data mx51_babbage_sd1_data __initconst = { - .cd_type = ESDHC_CD_CONTROLLER, - .wp_type = ESDHC_WP_CONTROLLER, -}; - -static const struct esdhc_platform_data mx51_babbage_sd2_data __initconst = { - .cd_gpio = BABBAGE_SD2_CD, - .wp_gpio = BABBAGE_SD2_WP, - .cd_type = ESDHC_CD_GPIO, - .wp_type = ESDHC_WP_GPIO, -}; - -void __init imx51_babbage_common_init(void) -{ - mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads, - ARRAY_SIZE(mx51babbage_pads)); -} - -/* - * Board specific initialization. - */ -static void __init mx51_babbage_init(void) -{ - iomux_v3_cfg_t usbh1stp = MX51_PAD_USBH1_STP__USBH1_STP; - iomux_v3_cfg_t power_key = NEW_PAD_CTRL(MX51_PAD_EIM_A27__GPIO2_21, - PAD_CTL_SRE_FAST | PAD_CTL_DSE_HIGH); - - imx51_soc_init(); - - imx51_babbage_common_init(); - - imx51_add_imx_uart(0, &uart_pdata); - imx51_add_imx_uart(1, NULL); - imx51_add_imx_uart(2, &uart_pdata); - - babbage_fec_reset(); - imx51_add_fec(NULL); - - /* Set the PAD settings for the pwr key. */ - mxc_iomux_v3_setup_pad(power_key); - imx_add_gpio_keys(&imx_button_data); - - imx51_add_imx_i2c(0, &babbage_i2c_data); - imx51_add_imx_i2c(1, &babbage_i2c_data); - imx51_add_hsi2c(&babbage_hsi2c_data); - - if (otg_mode_host) - imx51_add_mxc_ehci_otg(&dr_utmi_config); - else { - initialize_otg_port(NULL); - imx51_add_fsl_usb2_udc(&usb_pdata); - } - - gpio_usbh1_active(); - imx51_add_mxc_ehci_hs(1, &usbh1_config); - /* setback USBH1_STP to be function */ - mxc_iomux_v3_setup_pad(usbh1stp); - babbage_usbhub_reset(); - - imx51_add_sdhci_esdhc_imx(0, &mx51_babbage_sd1_data); - imx51_add_sdhci_esdhc_imx(1, &mx51_babbage_sd2_data); - - spi_register_board_info(mx51_babbage_spi_board_info, - ARRAY_SIZE(mx51_babbage_spi_board_info)); - imx51_add_ecspi(0, &mx51_babbage_spi_pdata); - imx51_add_imx2_wdt(0); -} - -static void __init mx51_babbage_timer_init(void) -{ - mx51_clocks_init(32768, 24000000, 22579200, 0); -} - -MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board") - /* Maintainer: Amit Kucheria */ - .atag_offset = 0x100, - .map_io = mx51_map_io, - .init_early = imx51_init_early, - .init_irq = mx51_init_irq, - .handle_irq = imx51_handle_irq, - .init_time = mx51_babbage_timer_init, - .init_machine = mx51_babbage_init, - .init_late = imx51_init_late, - .restart = mxc_restart, -MACHINE_END diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c index 65222ea0df6d71..bed081e58262ed 100644 --- a/arch/arm/mach-imx/time.c +++ b/arch/arm/mach-imx/time.c @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include @@ -328,3 +331,15 @@ void __init mxc_timer_init(void __iomem *base, int irq) /* Make irqs happen */ setup_irq(irq, &mxc_timer_irq); } + +void __init mxc_timer_init_dt(struct device_node *np) +{ + void __iomem *base; + int irq; + + base = of_iomap(np, 0); + WARN_ON(!base); + irq = irq_of_parse_and_map(np, 0); + + mxc_timer_init(base, irq); +} diff --git a/arch/arm/mach-keystone/keystone.c b/arch/arm/mach-keystone/keystone.c index e0b9e1b9cf303f..59b8383cbdb076 100644 --- a/arch/arm/mach-keystone/keystone.c +++ b/arch/arm/mach-keystone/keystone.c @@ -20,6 +20,9 @@ #include #include #include +#include + +#include "memory.h" #include "keystone.h" @@ -28,6 +31,27 @@ #define PLL_RESET BIT(16) static void __iomem *keystone_rstctrl; +static struct notifier_block platform_nb; +static unsigned long keystone_dma_pfn_offset __read_mostly; + +static int keystone_platform_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct device *dev = data; + + if (event != BUS_NOTIFY_ADD_DEVICE) + return NOTIFY_DONE; + + if (!dev) + return NOTIFY_BAD; + + if (!dev->of_node) { + dev->dma_pfn_offset = keystone_dma_pfn_offset; + dev_err(dev, "set dma_pfn_offset%08lx\n", + dev->dma_pfn_offset); + } + return NOTIFY_OK; +} static void __init keystone_init(void) { @@ -42,9 +66,58 @@ static void __init keystone_init(void) pr_warn("ti,keystone-reset iomap error\n"); keystone_pm_runtime_init(); + if (platform_nb.notifier_call) + bus_register_notifier(&platform_bus_type, &platform_nb); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } +static phys_addr_t keystone_virt_to_idmap(unsigned long x) +{ + return (phys_addr_t)(x) - CONFIG_PAGE_OFFSET + KEYSTONE_LOW_PHYS_START; +} + +static void __init keystone_init_meminfo(void) +{ + bool lpae = IS_ENABLED(CONFIG_ARM_LPAE); + bool pvpatch = IS_ENABLED(CONFIG_ARM_PATCH_PHYS_VIRT); + phys_addr_t offset = PHYS_OFFSET - KEYSTONE_LOW_PHYS_START; + phys_addr_t mem_start, mem_end; + + BUG_ON(meminfo.nr_banks < 1); + mem_start = meminfo.bank[0].start; + mem_end = mem_start + meminfo.bank[0].size - 1; + + /* nothing to do if we are running out of the <32-bit space */ + if (mem_start >= KEYSTONE_LOW_PHYS_START && + mem_end <= KEYSTONE_LOW_PHYS_END) + return; + + if (!lpae || !pvpatch) { + pr_crit("Enable %s%s%s to run outside 32-bit space\n", + !lpae ? __stringify(CONFIG_ARM_LPAE) : "", + (!lpae && !pvpatch) ? " and " : "", + !pvpatch ? __stringify(CONFIG_ARM_PATCH_PHYS_VIRT) : ""); + } + + if (mem_start < KEYSTONE_HIGH_PHYS_START || + mem_end > KEYSTONE_HIGH_PHYS_END) { + pr_crit("Invalid address space for memory (%08llx-%08llx)\n", + (u64)mem_start, (u64)mem_end); + } + + offset += KEYSTONE_HIGH_PHYS_START; + __pv_phys_pfn_offset = PFN_DOWN(offset); + __pv_offset = (offset - PAGE_OFFSET); + + /* Populate the arch idmap hook */ + arch_virt_to_idmap = keystone_virt_to_idmap; + platform_nb.notifier_call = keystone_platform_notifier; + keystone_dma_pfn_offset = PFN_DOWN(KEYSTONE_HIGH_PHYS_START - + KEYSTONE_LOW_PHYS_START); + + pr_info("Switching to high address space at 0x%llx\n", (u64)offset); +} + static const char *keystone_match[] __initconst = { "ti,keystone", NULL, @@ -76,4 +149,5 @@ DT_MACHINE_START(KEYSTONE, "Keystone") .init_machine = keystone_init, .dt_compat = keystone_match, .restart = keystone_restart, + .init_meminfo = keystone_init_meminfo, MACHINE_END diff --git a/arch/arm/mach-keystone/memory.h b/arch/arm/mach-keystone/memory.h new file mode 100644 index 00000000000000..b854fb18eef1ca --- /dev/null +++ b/arch/arm/mach-keystone/memory.h @@ -0,0 +1,24 @@ +/* + * Copyright 2014 Texas Instruments, Inc. + * Santosh Shilimkar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ +#ifndef __MEMORY_H +#define __MEMORY_H + +#define MAX_PHYSMEM_BITS 36 +#define SECTION_SIZE_BITS 34 + +#define KEYSTONE_LOW_PHYS_START 0x80000000ULL +#define KEYSTONE_LOW_PHYS_SIZE 0x80000000ULL /* 2G */ +#define KEYSTONE_LOW_PHYS_END (KEYSTONE_LOW_PHYS_START + \ + KEYSTONE_LOW_PHYS_SIZE - 1) + +#define KEYSTONE_HIGH_PHYS_START 0x800000000ULL +#define KEYSTONE_HIGH_PHYS_SIZE 0x400000000ULL /* 16G */ +#define KEYSTONE_HIGH_PHYS_END (KEYSTONE_HIGH_PHYS_START + \ + KEYSTONE_HIGH_PHYS_SIZE - 1) +#endif /* __MEMORY_H */ diff --git a/arch/arm/mach-keystone/platsmp.c b/arch/arm/mach-keystone/platsmp.c index 5cf0683577ea83..5f46a7cf907b1f 100644 --- a/arch/arm/mach-keystone/platsmp.c +++ b/arch/arm/mach-keystone/platsmp.c @@ -17,13 +17,16 @@ #include #include +#include +#include +#include #include "keystone.h" static int keystone_smp_boot_secondary(unsigned int cpu, struct task_struct *idle) { - unsigned long start = virt_to_phys(&secondary_startup); + unsigned long start = virt_to_idmap(&secondary_startup); int error; pr_debug("keystone-smp: booting cpu %d, vector %08lx\n", @@ -36,6 +39,19 @@ static int keystone_smp_boot_secondary(unsigned int cpu, return error; } +#ifdef CONFIG_ARM_LPAE +static void __cpuinit keystone_smp_secondary_initmem(unsigned int cpu) +{ + pgd_t *pgd0 = pgd_offset_k(0); + cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET); + local_flush_tlb_all(); +} +#else +static inline void __cpuinit keystone_smp_secondary_initmem(unsigned int cpu) +{} +#endif + struct smp_operations keystone_smp_ops __initdata = { .smp_boot_secondary = keystone_smp_boot_secondary, + .smp_secondary_init = keystone_smp_secondary_initmem, }; diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c index 2801da49e2a36b..ff18ff20f71fe4 100644 --- a/arch/arm/mach-kirkwood/board-dt.c +++ b/arch/arm/mach-kirkwood/board-dt.c @@ -195,7 +195,7 @@ static void __init kirkwood_dt_init(void) { kirkwood_disable_mbus_error_propagation(); - BUG_ON(mvebu_mbus_dt_init()); + BUG_ON(mvebu_mbus_dt_init(false)); #ifdef CONFIG_CACHE_FEROCEON_L2 feroceon_of_init(); diff --git a/arch/arm/mach-kirkwood/irq.c b/arch/arm/mach-kirkwood/irq.c index 2a97a2e4163cdf..2c47a8ad0e27fb 100644 --- a/arch/arm/mach-kirkwood/irq.c +++ b/arch/arm/mach-kirkwood/irq.c @@ -7,6 +7,7 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#include #include #include #include @@ -30,11 +31,47 @@ static int __initdata gpio1_irqs[4] = { 0, }; +#ifdef CONFIG_MULTI_IRQ_HANDLER +/* + * Compiling with both non-DT and DT support enabled, will + * break asm irq handler used by non-DT boards. Therefore, + * we provide a C-style irq handler even for non-DT boards, + * if MULTI_IRQ_HANDLER is set. + */ + +static void __iomem *kirkwood_irq_base = IRQ_VIRT_BASE; + +asmlinkage void +__exception_irq_entry kirkwood_legacy_handle_irq(struct pt_regs *regs) +{ + u32 stat; + + stat = readl_relaxed(kirkwood_irq_base + IRQ_CAUSE_LOW_OFF); + stat &= readl_relaxed(kirkwood_irq_base + IRQ_MASK_LOW_OFF); + if (stat) { + unsigned int hwirq = __fls(stat); + handle_IRQ(hwirq, regs); + return; + } + stat = readl_relaxed(kirkwood_irq_base + IRQ_CAUSE_HIGH_OFF); + stat &= readl_relaxed(kirkwood_irq_base + IRQ_MASK_HIGH_OFF); + if (stat) { + unsigned int hwirq = 32 + __fls(stat); + handle_IRQ(hwirq, regs); + return; + } +} +#endif + void __init kirkwood_init_irq(void) { orion_irq_init(0, IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF); orion_irq_init(32, IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF); +#ifdef CONFIG_MULTI_IRQ_HANDLER + set_handle_irq(kirkwood_legacy_handle_irq); +#endif + /* * Initialize gpiolib for GPIOs 0-49. */ diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c index 46de789ad3ae8e..0c4c200e122125 100644 --- a/arch/arm/mach-msm/board-msm7x30.c +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -95,7 +95,7 @@ static int hsusb_phy_clk_reset(struct clk *phy_clk) static struct msm_otg_platform_data msm_otg_pdata = { .phy_init_seq = hsusb_phy_init_seq, - .mode = USB_PERIPHERAL, + .mode = USB_DR_MODE_PERIPHERAL, .otg_control = OTG_PHY_CONTROL, .link_clk_reset = hsusb_link_clk_reset, .phy_clk_reset = hsusb_phy_clk_reset, diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 9169ec324a43dc..4c748616ef47eb 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -116,7 +116,7 @@ static int hsusb_phy_clk_reset(struct clk *phy_clk) static struct msm_otg_platform_data msm_otg_pdata = { .phy_init_seq = hsusb_phy_init_seq, - .mode = USB_PERIPHERAL, + .mode = USB_DR_MODE_PERIPHERAL, .otg_control = OTG_PHY_CONTROL, .link_clk_reset = hsusb_link_clk_reset, .phy_clk_reset = hsusb_phy_clk_reset, diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 3f73eecbcfb033..199187e474ce52 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -3,15 +3,14 @@ config ARCH_MVEBU select ARCH_SUPPORTS_BIG_ENDIAN select CLKSRC_MMIO select GENERIC_IRQ_CHIP - select IRQ_DOMAIN select PINCTRL select PLAT_ORION + select SOC_BUS select MVEBU_MBUS select ZONE_DMA if ARM_LPAE select ARCH_REQUIRE_GPIOLIB select MIGHT_HAVE_PCI select PCI_QUIRKS if PCI - select OF_ADDRESS_PCI if ARCH_MVEBU @@ -38,7 +37,9 @@ config MACH_ARMADA_375 select ARM_ERRATA_753970 select ARM_GIC select ARMADA_375_CLK - select CPU_V7 + select HAVE_ARM_SCU + select HAVE_ARM_TWD if SMP + select HAVE_SMP select MACH_MVEBU_V7 select PINCTRL_ARMADA_375 help @@ -51,7 +52,9 @@ config MACH_ARMADA_38X select ARM_ERRATA_753970 select ARM_GIC select ARMADA_38X_CLK - select CPU_V7 + select HAVE_ARM_SCU + select HAVE_ARM_TWD if SMP + select HAVE_SMP select MACH_MVEBU_V7 select PINCTRL_ARMADA_38X help @@ -86,24 +89,15 @@ config MACH_KIRKWOOD select ARCH_REQUIRE_GPIOLIB select CPU_FEROCEON select KIRKWOOD_CLK - select OF_IRQ select ORION_IRQCHIP select ORION_TIMER select PCI select PCI_QUIRKS select PINCTRL_KIRKWOOD - select USE_OF help Say 'Y' here if you want your kernel to support boards based on the Marvell Kirkwood device tree. -config MACH_T5325 - bool "HP T5325 thin client" - depends on MACH_KIRKWOOD - help - Say 'Y' here if you want your kernel to support the - HP T5325 Thin client - endmenu endif diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index a63e43b6b451e2..2ecb828e4a8bd2 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -2,12 +2,15 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \ -I$(srctree)/arch/arm/plat-orion/include AFLAGS_coherency_ll.o := -Wa,-march=armv7-a +CFLAGS_pmsu.o := -march=armv7-a obj-y += system-controller.o mvebu-soc-id.o -obj-$(CONFIG_MACH_MVEBU_V7) += board-v7.o + +ifeq ($(CONFIG_MACH_MVEBU_V7),y) +obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +endif + obj-$(CONFIG_MACH_DOVE) += dove.o -obj-$(CONFIG_ARCH_MVEBU) += coherency.o coherency_ll.o pmsu.o -obj-$(CONFIG_SMP) += platsmp.o headsmp.o -obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_MACH_KIRKWOOD) += kirkwood.o kirkwood-pm.o -obj-$(CONFIG_MACH_T5325) += board-t5325.o diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h index 237c86b8339017..c3465f5b12500f 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.h +++ b/arch/arm/mach-mvebu/armada-370-xp.h @@ -20,8 +20,6 @@ #define ARMADA_XP_MAX_CPUS 4 -void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq); -void armada_xp_mpic_smp_cpu_init(void); void armada_xp_secondary_startup(void); extern struct smp_operations armada_xp_smp_ops; #endif diff --git a/arch/arm/mach-mvebu/board-t5325.c b/arch/arm/mach-mvebu/board-t5325.c deleted file mode 100644 index 65ace6db9f2894..00000000000000 --- a/arch/arm/mach-mvebu/board-t5325.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * HP T5325 Board Setup - * - * Copyright (C) 2014 - * - * Andrew Lunn - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include "board.h" - -static struct platform_device hp_t5325_audio_device = { - .name = "t5325-audio", - .id = -1, -}; - -static struct alc5623_platform_data alc5621_data = { - .add_ctrl = 0x3700, - .jack_det_ctrl = 0x4810, -}; - -static struct i2c_board_info i2c_board_info[] __initdata = { - { - I2C_BOARD_INFO("alc5621", 0x1a), - .platform_data = &alc5621_data, - }, -}; - -void __init t5325_init(void) -{ - i2c_register_board_info(0, i2c_board_info, ARRAY_SIZE(i2c_board_info)); - platform_device_register(&hp_t5325_audio_device); -} diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index 333fca8fdc41c2..01cfce6ac20b95 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c @@ -27,11 +27,29 @@ #include #include #include +#include #include "armada-370-xp.h" #include "common.h" #include "coherency.h" #include "mvebu-soc-id.h" +/* + * Enables the SCU when available. Obviously, this is only useful on + * Cortex-A based SOCs, not on PJ4B based ones. + */ +static void __init mvebu_scu_enable(void) +{ + void __iomem *scu_base; + + struct device_node *np = + of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); + if (np) { + scu_base = of_iomap(np, 0); + scu_enable(scu_base); + of_node_put(np); + } +} + /* * Early versions of Armada 375 SoC have a bug where the BootROM * leaves an external data abort pending. The kernel is hit by this @@ -57,11 +75,10 @@ static void __init mvebu_timer_and_clk_init(void) { of_clk_init(NULL); clocksource_of_init(); + mvebu_scu_enable(); coherency_init(); - BUG_ON(mvebu_mbus_dt_init()); -#ifdef CONFIG_CACHE_L2X0 + BUG_ON(mvebu_mbus_dt_init(coherency_available())); l2x0_of_init(0, ~0UL); -#endif if (of_machine_is_compatible("marvell,armada375")) hook_fault_code(16 + 6, armada_375_external_abort_wa, SIGBUS, 0, @@ -78,7 +95,7 @@ static void __init i2c_quirk(void) * mechanism. We can exit only if we are sure that we can * get the SoC revision and it is more recent than A0. */ - if (mvebu_get_soc_id(&rev, &dev) == 0 && dev > MV78XX0_A0_REV) + if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > MV78XX0_A0_REV) return; for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") { @@ -96,10 +113,66 @@ static void __init i2c_quirk(void) return; } +#define A375_Z1_THERMAL_FIXUP_OFFSET 0xc + +static void __init thermal_quirk(void) +{ + struct device_node *np; + u32 dev, rev; + + if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > ARMADA_375_Z1_REV) + return; + + for_each_compatible_node(np, NULL, "marvell,armada375-thermal") { + struct property *prop; + __be32 newval, *newprop, *oldprop; + int len; + + /* + * The register offset is at a wrong location. This quirk + * creates a new reg property as a clone of the previous + * one and corrects the offset. + */ + oldprop = (__be32 *)of_get_property(np, "reg", &len); + if (!oldprop) + continue; + + /* Create a duplicate of the 'reg' property */ + prop = kzalloc(sizeof(*prop), GFP_KERNEL); + prop->length = len; + prop->name = kstrdup("reg", GFP_KERNEL); + prop->value = kzalloc(len, GFP_KERNEL); + memcpy(prop->value, oldprop, len); + + /* Fixup the register offset of the second entry */ + oldprop += 2; + newprop = (__be32 *)prop->value + 2; + newval = cpu_to_be32(be32_to_cpu(*oldprop) - + A375_Z1_THERMAL_FIXUP_OFFSET); + *newprop = newval; + of_update_property(np, prop); + + /* + * The thermal controller needs some quirk too, so let's change + * the compatible string to reflect this. + */ + prop = kzalloc(sizeof(*prop), GFP_KERNEL); + prop->name = kstrdup("compatible", GFP_KERNEL); + prop->length = sizeof("marvell,armada375-z1-thermal"); + prop->value = kstrdup("marvell,armada375-z1-thermal", + GFP_KERNEL); + of_update_property(np, prop); + } + return; +} + static void __init mvebu_dt_init(void) { if (of_machine_is_compatible("plathome,openblocks-ax3-4")) i2c_quirk(); + if (of_machine_is_compatible("marvell,a375-db")) + thermal_quirk(); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } @@ -123,6 +196,7 @@ static const char * const armada_375_dt_compat[] = { DT_MACHINE_START(ARMADA_375_DT, "Marvell Armada 375 (Device Tree)") .init_time = mvebu_timer_and_clk_init, + .init_machine = mvebu_dt_init, .restart = mvebu_restart, .dt_compat = armada_375_dt_compat, MACHINE_END diff --git a/arch/arm/mach-mvebu/board.h b/arch/arm/mach-mvebu/board.h index de7f0a191394d7..9c7bb4386f8bc9 100644 --- a/arch/arm/mach-mvebu/board.h +++ b/arch/arm/mach-mvebu/board.h @@ -13,10 +13,4 @@ #ifndef __ARCH_MVEBU_BOARD_H #define __ARCH_MVEBU_BOARD_H -#ifdef CONFIG_MACH_T5325 -void t5325_init(void); -#else -static inline void t5325_init(void) {}; -#endif - #endif diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 4e9d58148ca7e3..d5a975b6a590aa 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -17,6 +17,8 @@ * supplies basic routines for configuring and controlling hardware coherency */ +#define pr_fmt(fmt) "mvebu-coherency: " fmt + #include #include #include @@ -24,13 +26,17 @@ #include #include #include +#include +#include +#include #include #include #include "armada-370-xp.h" #include "coherency.h" +#include "mvebu-soc-id.h" unsigned long coherency_phys_base; -static void __iomem *coherency_base; +void __iomem *coherency_base; static void __iomem *coherency_cpu_base; /* Coherency fabric registers */ @@ -38,27 +44,190 @@ static void __iomem *coherency_cpu_base; #define IO_SYNC_BARRIER_CTL_OFFSET 0x0 +enum { + COHERENCY_FABRIC_TYPE_NONE, + COHERENCY_FABRIC_TYPE_ARMADA_370_XP, + COHERENCY_FABRIC_TYPE_ARMADA_375, + COHERENCY_FABRIC_TYPE_ARMADA_380, +}; + static struct of_device_id of_coherency_table[] = { - {.compatible = "marvell,coherency-fabric"}, + {.compatible = "marvell,coherency-fabric", + .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_370_XP }, + {.compatible = "marvell,armada-375-coherency-fabric", + .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_375 }, + {.compatible = "marvell,armada-380-coherency-fabric", + .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_380 }, { /* end of list */ }, }; -/* Function defined in coherency_ll.S */ -int ll_set_cpu_coherent(void __iomem *base_addr, unsigned int hw_cpu_id); +/* Functions defined in coherency_ll.S */ +int ll_enable_coherency(void); +void ll_add_cpu_to_smp_group(void); -int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id) +int set_cpu_coherent(void) { if (!coherency_base) { - pr_warn("Can't make CPU %d cache coherent.\n", hw_cpu_id); + pr_warn("Can't make current CPU cache coherent.\n"); pr_warn("Coherency fabric is not initialized\n"); return 1; } - return ll_set_cpu_coherent(coherency_base, hw_cpu_id); + ll_add_cpu_to_smp_group(); + return ll_enable_coherency(); +} + +/* + * The below code implements the I/O coherency workaround on Armada + * 375. This workaround consists in using the two channels of the + * first XOR engine to trigger a XOR transaction that serves as the + * I/O coherency barrier. + */ + +static void __iomem *xor_base, *xor_high_base; +static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS]; +static void *coherency_wa_buf[CONFIG_NR_CPUS]; +static bool coherency_wa_enabled; + +#define XOR_CONFIG(chan) (0x10 + (chan * 4)) +#define XOR_ACTIVATION(chan) (0x20 + (chan * 4)) +#define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2)) +#define WINDOW_BASE(w) (0x250 + ((w) << 2)) +#define WINDOW_SIZE(w) (0x270 + ((w) << 2)) +#define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2)) +#define WINDOW_OVERRIDE_CTRL(chan) (0x2A0 + ((chan) << 2)) +#define XOR_DEST_POINTER(chan) (0x2B0 + (chan * 4)) +#define XOR_BLOCK_SIZE(chan) (0x2C0 + (chan * 4)) +#define XOR_INIT_VALUE_LOW 0x2E0 +#define XOR_INIT_VALUE_HIGH 0x2E4 + +static inline void mvebu_hwcc_armada375_sync_io_barrier_wa(void) +{ + int idx = smp_processor_id(); + + /* Write '1' to the first word of the buffer */ + writel(0x1, coherency_wa_buf[idx]); + + /* Wait until the engine is idle */ + while ((readl(xor_base + XOR_ACTIVATION(idx)) >> 4) & 0x3) + ; + + dmb(); + + /* Trigger channel */ + writel(0x1, xor_base + XOR_ACTIVATION(idx)); + + /* Poll the data until it is cleared by the XOR transaction */ + while (readl(coherency_wa_buf[idx])) + ; +} + +static void __init armada_375_coherency_init_wa(void) +{ + const struct mbus_dram_target_info *dram; + struct device_node *xor_node; + struct property *xor_status; + struct clk *xor_clk; + u32 win_enable = 0; + int i; + + pr_warn("enabling coherency workaround for Armada 375 Z1, one XOR engine disabled\n"); + + /* + * Since the workaround uses one XOR engine, we grab a + * reference to its Device Tree node first. + */ + xor_node = of_find_compatible_node(NULL, NULL, "marvell,orion-xor"); + BUG_ON(!xor_node); + + /* + * Then we mark it as disabled so that the real XOR driver + * will not use it. + */ + xor_status = kzalloc(sizeof(struct property), GFP_KERNEL); + BUG_ON(!xor_status); + + xor_status->value = kstrdup("disabled", GFP_KERNEL); + BUG_ON(!xor_status->value); + + xor_status->length = 8; + xor_status->name = kstrdup("status", GFP_KERNEL); + BUG_ON(!xor_status->name); + + of_update_property(xor_node, xor_status); + + /* + * And we remap the registers, get the clock, and do the + * initial configuration of the XOR engine. + */ + xor_base = of_iomap(xor_node, 0); + xor_high_base = of_iomap(xor_node, 1); + + xor_clk = of_clk_get_by_name(xor_node, NULL); + BUG_ON(!xor_clk); + + clk_prepare_enable(xor_clk); + + dram = mv_mbus_dram_info(); + + for (i = 0; i < 8; i++) { + writel(0, xor_base + WINDOW_BASE(i)); + writel(0, xor_base + WINDOW_SIZE(i)); + if (i < 4) + writel(0, xor_base + WINDOW_REMAP_HIGH(i)); + } + + for (i = 0; i < dram->num_cs; i++) { + const struct mbus_dram_window *cs = dram->cs + i; + writel((cs->base & 0xffff0000) | + (cs->mbus_attr << 8) | + dram->mbus_dram_target_id, xor_base + WINDOW_BASE(i)); + writel((cs->size - 1) & 0xffff0000, xor_base + WINDOW_SIZE(i)); + + win_enable |= (1 << i); + win_enable |= 3 << (16 + (2 * i)); + } + + writel(win_enable, xor_base + WINDOW_BAR_ENABLE(0)); + writel(win_enable, xor_base + WINDOW_BAR_ENABLE(1)); + writel(0, xor_base + WINDOW_OVERRIDE_CTRL(0)); + writel(0, xor_base + WINDOW_OVERRIDE_CTRL(1)); + + for (i = 0; i < CONFIG_NR_CPUS; i++) { + coherency_wa_buf[i] = kzalloc(PAGE_SIZE, GFP_KERNEL); + BUG_ON(!coherency_wa_buf[i]); + + /* + * We can't use the DMA mapping API, since we don't + * have a valid 'struct device' pointer + */ + coherency_wa_buf_phys[i] = + virt_to_phys(coherency_wa_buf[i]); + BUG_ON(!coherency_wa_buf_phys[i]); + + /* + * Configure the XOR engine for memset operation, with + * a 128 bytes block size + */ + writel(0x444, xor_base + XOR_CONFIG(i)); + writel(128, xor_base + XOR_BLOCK_SIZE(i)); + writel(coherency_wa_buf_phys[i], + xor_base + XOR_DEST_POINTER(i)); + } + + writel(0x0, xor_base + XOR_INIT_VALUE_LOW); + writel(0x0, xor_base + XOR_INIT_VALUE_HIGH); + + coherency_wa_enabled = true; } static inline void mvebu_hwcc_sync_io_barrier(void) { + if (coherency_wa_enabled) { + mvebu_hwcc_armada375_sync_io_barrier_wa(); + return; + } + writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET); while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1); } @@ -121,42 +290,93 @@ static struct notifier_block mvebu_hwcc_platform_nb = { .notifier_call = mvebu_hwcc_platform_notifier, }; -int __init coherency_init(void) +static void __init armada_370_coherency_init(struct device_node *np) +{ + struct resource res; + + of_address_to_resource(np, 0, &res); + coherency_phys_base = res.start; + /* + * Ensure secondary CPUs will see the updated value, + * which they read before they join the coherency + * fabric, and therefore before they are coherent with + * the boot CPU cache. + */ + sync_cache_w(&coherency_phys_base); + coherency_base = of_iomap(np, 0); + coherency_cpu_base = of_iomap(np, 1); + set_cpu_coherent(); +} + +static void __init armada_375_380_coherency_init(struct device_node *np) +{ + coherency_cpu_base = of_iomap(np, 0); +} + +static int coherency_type(void) { struct device_node *np; + const struct of_device_id *match; - np = of_find_matching_node(NULL, of_coherency_table); + np = of_find_matching_node_and_match(NULL, of_coherency_table, &match); if (np) { - struct resource res; - pr_info("Initializing Coherency fabric\n"); - of_address_to_resource(np, 0, &res); - coherency_phys_base = res.start; - /* - * Ensure secondary CPUs will see the updated value, - * which they read before they join the coherency - * fabric, and therefore before they are coherent with - * the boot CPU cache. - */ - sync_cache_w(&coherency_phys_base); - coherency_base = of_iomap(np, 0); - coherency_cpu_base = of_iomap(np, 1); - set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); - of_node_put(np); + int type = (int) match->data; + + /* Armada 370/XP coherency works in both UP and SMP */ + if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP) + return type; + + /* Armada 375 coherency works only on SMP */ + else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp()) + return type; + + /* Armada 380 coherency works only on SMP */ + else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380 && is_smp()) + return type; } - return 0; + return COHERENCY_FABRIC_TYPE_NONE; } -static int __init coherency_late_init(void) +int coherency_available(void) +{ + return coherency_type() != COHERENCY_FABRIC_TYPE_NONE; +} + +int __init coherency_init(void) { + int type = coherency_type(); struct device_node *np; np = of_find_matching_node(NULL, of_coherency_table); - if (np) { - bus_register_notifier(&platform_bus_type, - &mvebu_hwcc_platform_nb); - of_node_put(np); + + if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP) + armada_370_coherency_init(np); + else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 || + type == COHERENCY_FABRIC_TYPE_ARMADA_380) + armada_375_380_coherency_init(np); + + return 0; +} + +static int __init coherency_late_init(void) +{ + int type = coherency_type(); + + if (type == COHERENCY_FABRIC_TYPE_NONE) + return 0; + + if (type == COHERENCY_FABRIC_TYPE_ARMADA_375) { + u32 dev, rev; + + if (mvebu_get_soc_id(&dev, &rev) == 0 && + rev == ARMADA_375_Z1_REV) + armada_375_coherency_init_wa(); } + + bus_register_notifier(&platform_bus_type, + &mvebu_hwcc_platform_nb); + return 0; } diff --git a/arch/arm/mach-mvebu/coherency.h b/arch/arm/mach-mvebu/coherency.h index 760226c4135309..54cb7607b52669 100644 --- a/arch/arm/mach-mvebu/coherency.h +++ b/arch/arm/mach-mvebu/coherency.h @@ -15,8 +15,9 @@ #define __MACH_370_XP_COHERENCY_H extern unsigned long coherency_phys_base; +int set_cpu_coherent(void); -int set_cpu_coherent(unsigned int cpu_id, int smp_group_id); int coherency_init(void); +int coherency_available(void); #endif /* __MACH_370_XP_COHERENCY_H */ diff --git a/arch/arm/mach-mvebu/coherency_ll.S b/arch/arm/mach-mvebu/coherency_ll.S index ee7598fe75db87..6828f9f157b0b3 100644 --- a/arch/arm/mach-mvebu/coherency_ll.S +++ b/arch/arm/mach-mvebu/coherency_ll.S @@ -21,38 +21,108 @@ #define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4 #include +#include .text -/* - * r0: Coherency fabric base register address - * r1: HW CPU id - */ -ENTRY(ll_set_cpu_coherent) - /* Create bit by cpu index */ - mov r3, #(1 << 24) - lsl r1, r3, r1 -ARM_BE8(rev r1, r1) +/* Returns with the coherency address in r1 (r0 is untouched)*/ +ENTRY(ll_get_coherency_base) + mrc p15, 0, r1, c1, c0, 0 + tst r1, #CR_M @ Check MMU bit enabled + bne 1f - /* Add CPU to SMP group - Atomic */ - add r3, r0, #ARMADA_XP_CFB_CTL_REG_OFFSET + /* use physical address of the coherency register */ + adr r1, 3f + ldr r3, [r1] + ldr r1, [r1, r3] + b 2f 1: - ldrex r2, [r3] - orr r2, r2, r1 - strex r0, r2, [r3] - cmp r0, #0 - bne 1b - - /* Enable coherency on CPU - Atomic */ - add r3, r3, #ARMADA_XP_CFB_CFG_REG_OFFSET + /* use virtual address of the coherency register */ + ldr r1, =coherency_base + ldr r1, [r1] +2: + mov pc, lr +ENDPROC(ll_get_coherency_base) + +/* Returns with the CPU ID in r3 (r0 is untouched)*/ +ENTRY(ll_get_cpuid) + mrc 15, 0, r3, cr0, cr0, 5 + and r3, r3, #15 + mov r2, #(1 << 24) + lsl r3, r2, r3 +ARM_BE8(rev r1, r1) + mov pc, lr +ENDPROC(ll_get_cpuid) + +/* ll_add_cpu_to_smp_group, ll_enable_coherency and + * ll_disable_coherency use strex/ldrex whereas MMU can be off. The + * Armada XP SoC has an exclusive monitor that can track transactions + * to Device and/or SO and as such also when MMU is disabled the + * exclusive transactions will be functional + */ + +ENTRY(ll_add_cpu_to_smp_group) + /* + * r0 being untouched in ll_get_coherency_base and + * ll_get_cpuid, we can use it to save lr modifing it with the + * following bl + */ + mov r0, lr + bl ll_get_coherency_base + bl ll_get_cpuid + mov lr, r0 + add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET 1: - ldrex r2, [r3] - orr r2, r2, r1 - strex r0, r2, [r3] - cmp r0, #0 - bne 1b + ldrex r2, [r0] + orr r2, r2, r3 + strex r1, r2, [r0] + cmp r1, #0 + bne 1b + mov pc, lr +ENDPROC(ll_add_cpu_to_smp_group) +ENTRY(ll_enable_coherency) + /* + * r0 being untouched in ll_get_coherency_base and + * ll_get_cpuid, we can use it to save lr modifing it with the + * following bl + */ + mov r0, lr + bl ll_get_coherency_base + bl ll_get_cpuid + mov lr, r0 + add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET +1: + ldrex r2, [r0] + orr r2, r2, r3 + strex r1, r2, [r0] + cmp r1, #0 + bne 1b dsb - mov r0, #0 mov pc, lr -ENDPROC(ll_set_cpu_coherent) +ENDPROC(ll_enable_coherency) + +ENTRY(ll_disable_coherency) + /* + * r0 being untouched in ll_get_coherency_base and + * ll_get_cpuid, we can use it to save lr modifing it with the + * following bl + */ + mov r0, lr + bl ll_get_coherency_base + bl ll_get_cpuid + mov lr, r0 + add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET +1: + ldrex r2, [r0] + bic r2, r2, r3 + strex r1, r2, [r0] + cmp r1, #0 + bne 1b + dsb + mov pc, lr +ENDPROC(ll_disable_coherency) + + .align 2 +3: + .long coherency_phys_base - . diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h index 55449c487c9e9d..b67fb7a10d8b46 100644 --- a/arch/arm/mach-mvebu/common.h +++ b/arch/arm/mach-mvebu/common.h @@ -18,6 +18,9 @@ #include void mvebu_restart(enum reboot_mode mode, const char *cmd); +int mvebu_cpu_reset_deassert(int cpu); +void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr); +void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr); void armada_xp_cpu_die(unsigned int cpu); diff --git a/arch/arm/mach-mvebu/cpu-reset.c b/arch/arm/mach-mvebu/cpu-reset.c new file mode 100644 index 00000000000000..4a8f9eebebead5 --- /dev/null +++ b/arch/arm/mach-mvebu/cpu-reset.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2014 Marvell + * + * Thomas Petazzoni + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#define pr_fmt(fmt) "mvebu-cpureset: " fmt + +#include +#include +#include +#include +#include +#include "armada-370-xp.h" + +static void __iomem *cpu_reset_base; +static size_t cpu_reset_size; + +#define CPU_RESET_OFFSET(cpu) (cpu * 0x8) +#define CPU_RESET_ASSERT BIT(0) + +int mvebu_cpu_reset_deassert(int cpu) +{ + u32 reg; + + if (!cpu_reset_base) + return -ENODEV; + + if (CPU_RESET_OFFSET(cpu) >= cpu_reset_size) + return -EINVAL; + + reg = readl(cpu_reset_base + CPU_RESET_OFFSET(cpu)); + reg &= ~CPU_RESET_ASSERT; + writel(reg, cpu_reset_base + CPU_RESET_OFFSET(cpu)); + + return 0; +} + +static int mvebu_cpu_reset_map(struct device_node *np, int res_idx) +{ + struct resource res; + + if (of_address_to_resource(np, res_idx, &res)) { + pr_err("unable to get resource\n"); + return -ENOENT; + } + + if (!request_mem_region(res.start, resource_size(&res), + np->full_name)) { + pr_err("unable to request region\n"); + return -EBUSY; + } + + cpu_reset_base = ioremap(res.start, resource_size(&res)); + if (!cpu_reset_base) { + pr_err("unable to map registers\n"); + release_mem_region(res.start, resource_size(&res)); + return -ENOMEM; + } + + cpu_reset_size = resource_size(&res); + + return 0; +} + +int __init mvebu_cpu_reset_init(void) +{ + struct device_node *np; + int res_idx; + int ret; + + np = of_find_compatible_node(NULL, NULL, + "marvell,armada-370-cpu-reset"); + if (np) { + res_idx = 0; + } else { + /* + * This code is kept for backward compatibility with + * old Device Trees. + */ + np = of_find_compatible_node(NULL, NULL, + "marvell,armada-370-xp-pmsu"); + if (np) { + pr_warn(FW_WARN "deprecated pmsu binding\n"); + res_idx = 1; + } + } + + /* No reset node found */ + if (!np) + return -ENODEV; + + ret = mvebu_cpu_reset_map(np, res_idx); + of_node_put(np); + + return ret; +} + +early_initcall(mvebu_cpu_reset_init); diff --git a/arch/arm/mach-mvebu/dove.c b/arch/arm/mach-mvebu/dove.c index 5e5a4362423768..b50464ec1130ff 100644 --- a/arch/arm/mach-mvebu/dove.c +++ b/arch/arm/mach-mvebu/dove.c @@ -23,7 +23,7 @@ static void __init dove_init(void) #ifdef CONFIG_CACHE_TAUROS2 tauros2_init(0); #endif - BUG_ON(mvebu_mbus_dt_init()); + BUG_ON(mvebu_mbus_dt_init(false)); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } diff --git a/arch/arm/mach-mvebu/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S new file mode 100644 index 00000000000000..5925366bc03ccc --- /dev/null +++ b/arch/arm/mach-mvebu/headsmp-a9.S @@ -0,0 +1,34 @@ +/* + * SMP support: Entry point for secondary CPUs of Marvell EBU + * Cortex-A9 based SOCs (Armada 375 and Armada 38x). + * + * Copyright (C) 2014 Marvell + * + * Gregory CLEMENT + * Thomas Petazzoni + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include + + __CPUINIT +#define CPU_RESUME_ADDR_REG 0xf10182d4 + +.global armada_375_smp_cpu1_enable_code_start +.global armada_375_smp_cpu1_enable_code_end + +armada_375_smp_cpu1_enable_code_start: + ldr r0, [pc, #4] + ldr r1, [r0] + mov pc, r1 + .word CPU_RESUME_ADDR_REG +armada_375_smp_cpu1_enable_code_end: + +ENTRY(mvebu_cortex_a9_secondary_startup) + bl v7_invalidate_l1 + b secondary_startup +ENDPROC(mvebu_cortex_a9_secondary_startup) diff --git a/arch/arm/mach-mvebu/headsmp.S b/arch/arm/mach-mvebu/headsmp.S index 3dd80df428f7ed..2c4032e368bada 100644 --- a/arch/arm/mach-mvebu/headsmp.S +++ b/arch/arm/mach-mvebu/headsmp.S @@ -31,21 +31,10 @@ ENTRY(armada_xp_secondary_startup) ARM_BE8(setend be ) @ go BE8 if entered LE - /* Get coherency fabric base physical address */ - adr r0, 1f - ldr r1, [r0] - ldr r0, [r0, r1] + bl ll_add_cpu_to_smp_group - /* Read CPU id */ - mrc p15, 0, r1, c0, c0, 5 - and r1, r1, #0xF + bl ll_enable_coherency - /* Add CPU to coherency fabric */ - bl ll_set_cpu_coherent b secondary_startup ENDPROC(armada_xp_secondary_startup) - - .align 2 -1: - .long coherency_phys_base - . diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c index 120207fc36f1f8..46f105913c84b7 100644 --- a/arch/arm/mach-mvebu/kirkwood.c +++ b/arch/arm/mach-mvebu/kirkwood.c @@ -169,7 +169,7 @@ static void __init kirkwood_dt_init(void) { kirkwood_disable_mbus_error_propagation(); - BUG_ON(mvebu_mbus_dt_init()); + BUG_ON(mvebu_mbus_dt_init(false)); #ifdef CONFIG_CACHE_FEROCEON_L2 feroceon_of_init(); @@ -180,9 +180,6 @@ static void __init kirkwood_dt_init(void) kirkwood_pm_init(); kirkwood_dt_eth_fixup(); - if (of_machine_is_compatible("hp,t5325")) - t5325_init(); - of_platform_populate(NULL, of_default_bus_match_table, auxdata, NULL); } diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.c b/arch/arm/mach-mvebu/mvebu-soc-id.c index f3d4cf53f7466b..e9119a99a5f377 100644 --- a/arch/arm/mach-mvebu/mvebu-soc-id.c +++ b/arch/arm/mach-mvebu/mvebu-soc-id.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "mvebu-soc-id.h" #define PCIE_DEV_ID_OFF 0x0 @@ -116,5 +118,33 @@ static int __init mvebu_soc_id_init(void) return ret; } -core_initcall(mvebu_soc_id_init); +early_initcall(mvebu_soc_id_init); +static int __init mvebu_soc_device(void) +{ + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + + /* Also protects against running on non-mvebu systems */ + if (!is_id_valid) + return 0; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = kasprintf(GFP_KERNEL, "Marvell"); + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X", soc_rev); + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%X", soc_dev_id); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->family); + kfree(soc_dev_attr->revision); + kfree(soc_dev_attr->soc_id); + kfree(soc_dev_attr); + } + + return 0; +} +postcore_initcall(mvebu_soc_device); diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.h b/arch/arm/mach-mvebu/mvebu-soc-id.h index 31654252fe35ca..c16bb68ca81fd9 100644 --- a/arch/arm/mach-mvebu/mvebu-soc-id.h +++ b/arch/arm/mach-mvebu/mvebu-soc-id.h @@ -20,6 +20,10 @@ #define MV78XX0_A0_REV 0x1 #define MV78XX0_B0_REV 0x2 +/* Armada 375 */ +#define ARMADA_375_Z1_REV 0x0 +#define ARMADA_375_A0_REV 0x3 + #ifdef CONFIG_ARCH_MVEBU int mvebu_get_soc_id(u32 *dev, u32 *rev); #else diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c new file mode 100644 index 00000000000000..96c2c59e34b67b --- /dev/null +++ b/arch/arm/mach-mvebu/platsmp-a9.c @@ -0,0 +1,102 @@ +/* + * Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9 + * based SOCs (Armada 375/38x). + * + * Copyright (C) 2014 Marvell + * + * Gregory CLEMENT + * Thomas Petazzoni + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "mvebu-soc-id.h" +#include "pmsu.h" + +#define CRYPT0_ENG_ID 41 +#define CRYPT0_ENG_ATTR 0x1 +#define SRAM_PHYS_BASE 0xFFFF0000 + +#define BOOTROM_BASE 0xFFF00000 +#define BOOTROM_SIZE 0x100000 + +extern unsigned char armada_375_smp_cpu1_enable_code_end; +extern unsigned char armada_375_smp_cpu1_enable_code_start; + +void armada_375_smp_cpu1_enable_wa(void) +{ + void __iomem *sram_virt_base; + + mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE); + mvebu_mbus_add_window_by_id(CRYPT0_ENG_ID, CRYPT0_ENG_ATTR, + SRAM_PHYS_BASE, SZ_64K); + sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K); + + memcpy(sram_virt_base, &armada_375_smp_cpu1_enable_code_start, + &armada_375_smp_cpu1_enable_code_end + - &armada_375_smp_cpu1_enable_code_start); +} + +extern void mvebu_cortex_a9_secondary_startup(void); + +static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu, + struct task_struct *idle) +{ + int ret, hw_cpu; + + pr_info("Booting CPU %d\n", cpu); + + /* + * Write the address of secondary startup into the system-wide + * flags register. The boot monitor waits until it receives a + * soft interrupt, and then the secondary CPU branches to this + * address. + */ + hw_cpu = cpu_logical_map(cpu); + + if (of_machine_is_compatible("marvell,armada375")) { + u32 dev, rev; + + if (mvebu_get_soc_id(&dev, &rev) == 0 && + rev == ARMADA_375_Z1_REV) + armada_375_smp_cpu1_enable_wa(); + + mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup); + } + else { + mvebu_pmsu_set_cpu_boot_addr(hw_cpu, + mvebu_cortex_a9_secondary_startup); + } + + smp_wmb(); + ret = mvebu_cpu_reset_deassert(hw_cpu); + if (ret) { + pr_err("Could not start the secondary CPU: %d\n", ret); + return ret; + } + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + + return 0; +} + +static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = { + .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = armada_xp_cpu_die, +#endif +}; + +CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", + &mvebu_cortex_a9_smp_ops); +CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp", + &mvebu_cortex_a9_smp_ops); diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index a6da03f5b24ec9..88b976b317198f 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c @@ -70,16 +70,19 @@ static void __init set_secondary_cpus_clock(void) } } -static void armada_xp_secondary_init(unsigned int cpu) -{ - armada_xp_mpic_smp_cpu_init(); -} - static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle) { + int ret, hw_cpu; + pr_info("Booting CPU %d\n", cpu); - armada_xp_boot_cpu(cpu, armada_xp_secondary_startup); + hw_cpu = cpu_logical_map(cpu); + mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup); + ret = mvebu_cpu_reset_deassert(hw_cpu); + if (ret) { + pr_warn("unable to boot CPU: %d\n", ret); + return ret; + } return 0; } @@ -90,8 +93,6 @@ static void __init armada_xp_smp_init_cpus(void) if (ncores == 0 || ncores > ARMADA_XP_MAX_CPUS) panic("Invalid number of CPUs in DT\n"); - - set_smp_cross_call(armada_mpic_send_doorbell); } static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus) @@ -102,7 +103,7 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus) set_secondary_cpus_clock(); flush_cache_all(); - set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); + set_cpu_coherent(); /* * In order to boot the secondary CPUs we need to ensure @@ -124,9 +125,11 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus) struct smp_operations armada_xp_smp_ops __initdata = { .smp_init_cpus = armada_xp_smp_init_cpus, .smp_prepare_cpus = armada_xp_smp_prepare_cpus, - .smp_secondary_init = armada_xp_secondary_init, .smp_boot_secondary = armada_xp_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU .cpu_die = armada_xp_cpu_die, #endif }; + +CPU_METHOD_OF_DECLARE(armada_xp_smp, "marvell,armada-xp-smp", + &armada_xp_smp_ops); diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index d71ef53107c4e9..53a55c8520bf9a 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -16,62 +16,283 @@ * other SOC units */ +#define pr_fmt(fmt) "mvebu-pmsu: " fmt + +#include #include #include #include #include +#include #include +#include +#include +#include #include -#include "pmsu.h" +#include +#include +#include "common.h" static void __iomem *pmsu_mp_base; -static void __iomem *pmsu_reset_base; -#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x24) -#define PMSU_RESET_CTL_OFFSET(cpu) (cpu * 0x8) +#define PMSU_BASE_OFFSET 0x100 +#define PMSU_REG_SIZE 0x1000 + +/* PMSU MP registers */ +#define PMSU_CONTROL_AND_CONFIG(cpu) ((cpu * 0x100) + 0x104) +#define PMSU_CONTROL_AND_CONFIG_DFS_REQ BIT(18) +#define PMSU_CONTROL_AND_CONFIG_PWDDN_REQ BIT(16) +#define PMSU_CONTROL_AND_CONFIG_L2_PWDDN BIT(20) + +#define PMSU_CPU_POWER_DOWN_CONTROL(cpu) ((cpu * 0x100) + 0x108) + +#define PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP BIT(0) + +#define PMSU_STATUS_AND_MASK(cpu) ((cpu * 0x100) + 0x10c) +#define PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT BIT(16) +#define PMSU_STATUS_AND_MASK_SNP_Q_EMPTY_WAIT BIT(17) +#define PMSU_STATUS_AND_MASK_IRQ_WAKEUP BIT(20) +#define PMSU_STATUS_AND_MASK_FIQ_WAKEUP BIT(21) +#define PMSU_STATUS_AND_MASK_DBG_WAKEUP BIT(22) +#define PMSU_STATUS_AND_MASK_IRQ_MASK BIT(24) +#define PMSU_STATUS_AND_MASK_FIQ_MASK BIT(25) + +#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x124) + +/* PMSU fabric registers */ +#define L2C_NFABRIC_PM_CTL 0x4 +#define L2C_NFABRIC_PM_CTL_PWR_DOWN BIT(20) + +extern void ll_disable_coherency(void); +extern void ll_enable_coherency(void); + +static struct platform_device armada_xp_cpuidle_device = { + .name = "cpuidle-armada-370-xp", +}; static struct of_device_id of_pmsu_table[] = { - {.compatible = "marvell,armada-370-xp-pmsu"}, + { .compatible = "marvell,armada-370-pmsu", }, + { .compatible = "marvell,armada-370-xp-pmsu", }, + { .compatible = "marvell,armada-380-pmsu", }, { /* end of list */ }, }; -#ifdef CONFIG_SMP -int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr) +void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) { - int reg, hw_cpu; + writel(virt_to_phys(boot_addr), pmsu_mp_base + + PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)); +} + +static int __init armada_370_xp_pmsu_init(void) +{ + struct device_node *np; + struct resource res; + int ret = 0; + + np = of_find_matching_node(NULL, of_pmsu_table); + if (!np) + return 0; + + pr_info("Initializing Power Management Service Unit\n"); - if (!pmsu_mp_base || !pmsu_reset_base) { - pr_warn("Can't boot CPU. PMSU is uninitialized\n"); - return 1; + if (of_address_to_resource(np, 0, &res)) { + pr_err("unable to get resource\n"); + ret = -ENOENT; + goto out; } - hw_cpu = cpu_logical_map(cpu_id); + if (of_device_is_compatible(np, "marvell,armada-370-xp-pmsu")) { + pr_warn(FW_WARN "deprecated pmsu binding\n"); + res.start = res.start - PMSU_BASE_OFFSET; + res.end = res.start + PMSU_REG_SIZE - 1; + } - writel(virt_to_phys(boot_addr), pmsu_mp_base + - PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)); + if (!request_mem_region(res.start, resource_size(&res), + np->full_name)) { + pr_err("unable to request region\n"); + ret = -EBUSY; + goto out; + } + + pmsu_mp_base = ioremap(res.start, resource_size(&res)); + if (!pmsu_mp_base) { + pr_err("unable to map registers\n"); + release_mem_region(res.start, resource_size(&res)); + ret = -ENOMEM; + goto out; + } + + out: + of_node_put(np); + return ret; +} + +static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void) +{ + u32 reg; + + if (pmsu_mp_base == NULL) + return; + + /* Enable L2 & Fabric powerdown in Deep-Idle mode - Fabric */ + reg = readl(pmsu_mp_base + L2C_NFABRIC_PM_CTL); + reg |= L2C_NFABRIC_PM_CTL_PWR_DOWN; + writel(reg, pmsu_mp_base + L2C_NFABRIC_PM_CTL); +} + +static void armada_370_xp_cpu_resume(void) +{ + asm volatile("bl ll_add_cpu_to_smp_group\n\t" + "bl ll_enable_coherency\n\t" + "b cpu_resume\n\t"); +} + +/* No locking is needed because we only access per-CPU registers */ +void armada_370_xp_pmsu_idle_prepare(bool deepidle) +{ + unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); + u32 reg; + + if (pmsu_mp_base == NULL) + return; - /* Release CPU from reset by clearing reset bit*/ - reg = readl(pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu)); - reg &= (~0x1); - writel(reg, pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu)); + /* + * Adjust the PMSU configuration to wait for WFI signal, enable + * IRQ and FIQ as wakeup events, set wait for snoop queue empty + * indication and mask IRQ and FIQ from CPU + */ + reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu)); + reg |= PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT | + PMSU_STATUS_AND_MASK_IRQ_WAKEUP | + PMSU_STATUS_AND_MASK_FIQ_WAKEUP | + PMSU_STATUS_AND_MASK_SNP_Q_EMPTY_WAIT | + PMSU_STATUS_AND_MASK_IRQ_MASK | + PMSU_STATUS_AND_MASK_FIQ_MASK; + writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu)); + + reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); + /* ask HW to power down the L2 Cache if needed */ + if (deepidle) + reg |= PMSU_CONTROL_AND_CONFIG_L2_PWDDN; + + /* request power down */ + reg |= PMSU_CONTROL_AND_CONFIG_PWDDN_REQ; + writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); + + /* Disable snoop disable by HW - SW is taking care of it */ + reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); + reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP; + writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); +} + +static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle) +{ + armada_370_xp_pmsu_idle_prepare(deepidle); + + v7_exit_coherency_flush(all); + + ll_disable_coherency(); + + dsb(); + + wfi(); + + /* If we are here, wfi failed. As processors run out of + * coherency for some time, tlbs might be stale, so flush them + */ + local_flush_tlb_all(); + + ll_enable_coherency(); + + /* Test the CR_C bit and set it if it was cleared */ + asm volatile( + "mrc p15, 0, %0, c1, c0, 0 \n\t" + "tst %0, #(1 << 2) \n\t" + "orreq %0, %0, #(1 << 2) \n\t" + "mcreq p15, 0, %0, c1, c0, 0 \n\t" + "isb " + : : "r" (0)); + + pr_warn("Failed to suspend the system\n"); return 0; } -#endif -static int __init armada_370_xp_pmsu_init(void) +static int armada_370_xp_cpu_suspend(unsigned long deepidle) +{ + return cpu_suspend(deepidle, do_armada_370_xp_cpu_suspend); +} + +/* No locking is needed because we only access per-CPU registers */ +static noinline void armada_370_xp_pmsu_idle_restore(void) +{ + unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); + u32 reg; + + if (pmsu_mp_base == NULL) + return; + + /* cancel ask HW to power down the L2 Cache if possible */ + reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); + reg &= ~PMSU_CONTROL_AND_CONFIG_L2_PWDDN; + writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); + + /* cancel Enable wakeup events and mask interrupts */ + reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu)); + reg &= ~(PMSU_STATUS_AND_MASK_IRQ_WAKEUP | PMSU_STATUS_AND_MASK_FIQ_WAKEUP); + reg &= ~PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT; + reg &= ~PMSU_STATUS_AND_MASK_SNP_Q_EMPTY_WAIT; + reg &= ~(PMSU_STATUS_AND_MASK_IRQ_MASK | PMSU_STATUS_AND_MASK_FIQ_MASK); + writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu)); +} + +static int armada_370_xp_cpu_pm_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + if (action == CPU_PM_ENTER) { + unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); + mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume); + } else if (action == CPU_PM_EXIT) { + armada_370_xp_pmsu_idle_restore(); + } + + return NOTIFY_OK; +} + +static struct notifier_block armada_370_xp_cpu_pm_notifier = { + .notifier_call = armada_370_xp_cpu_pm_notify, +}; + +int __init armada_370_xp_cpu_pm_init(void) { struct device_node *np; + /* + * Check that all the requirements are available to enable + * cpuidle. So far, it is only supported on Armada XP, cpuidle + * needs the coherency fabric and the PMSU enabled + */ + + if (!of_machine_is_compatible("marvell,armadaxp")) + return 0; + + np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"); + if (!np) + return 0; + of_node_put(np); + np = of_find_matching_node(NULL, of_pmsu_table); - if (np) { - pr_info("Initializing Power Management Service Unit\n"); - pmsu_mp_base = of_iomap(np, 0); - pmsu_reset_base = of_iomap(np, 1); - of_node_put(np); - } + if (!np) + return 0; + of_node_put(np); + + armada_370_xp_pmsu_enable_l2_powerdown_onidle(); + armada_xp_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; + platform_device_register(&armada_xp_cpuidle_device); + cpu_pm_register_notifier(&armada_370_xp_cpu_pm_notifier); return 0; } +arch_initcall(armada_370_xp_cpu_pm_init); early_initcall(armada_370_xp_pmsu_init); diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c index 614ba6832ff3ae..0c5524ac75b75c 100644 --- a/arch/arm/mach-mvebu/system-controller.c +++ b/arch/arm/mach-mvebu/system-controller.c @@ -37,6 +37,8 @@ struct mvebu_system_controller { u32 rstoutn_mask_reset_out_en; u32 system_soft_reset; + + u32 resume_boot_addr; }; static struct mvebu_system_controller *mvebu_sc; @@ -52,6 +54,7 @@ static const struct mvebu_system_controller armada_375_system_controller = { .system_soft_reset_offset = 0x58, .rstoutn_mask_reset_out_en = 0x1, .system_soft_reset = 0x1, + .resume_boot_addr = 0xd4, }; static const struct mvebu_system_controller orion_system_controller = { @@ -98,6 +101,16 @@ void mvebu_restart(enum reboot_mode mode, const char *cmd) ; } +#ifdef CONFIG_SMP +void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr) +{ + BUG_ON(system_controller_base == NULL); + BUG_ON(mvebu_sc->resume_boot_addr == 0); + writel(virt_to_phys(boot_addr), system_controller_base + + mvebu_sc->resume_boot_addr); +} +#endif + static int __init mvebu_system_controller_init(void) { const struct of_device_id *match; @@ -114,4 +127,4 @@ static int __init mvebu_system_controller_init(void) return 0; } -arch_initcall(mvebu_system_controller_init); +early_initcall(mvebu_system_controller_init); diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index d6ed819ff15ce1..660bfc5a70d7e2 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-omap2/omap-headsmp.S b/arch/arm/mach-omap2/omap-headsmp.S index 75e92952c18efe..40c5d5f1451cd3 100644 --- a/arch/arm/mach-omap2/omap-headsmp.S +++ b/arch/arm/mach-omap2/omap-headsmp.S @@ -1,7 +1,7 @@ /* * Secondary CPU startup routine source file. * - * Copyright (C) 2009 Texas Instruments, Inc. + * Copyright (C) 2009-2014 Texas Instruments, Inc. * * Author: * Santosh Shilimkar @@ -28,9 +28,13 @@ * code. This routine also provides a holding flag into which * secondary core is held until we're ready for it to initialise. * The primary core will update this flag using a hardware -+ * register AuxCoreBoot0. + * register AuxCoreBoot0. */ ENTRY(omap5_secondary_startup) +.arm +THUMB( adr r9, BSYM(wait) ) @ CPU may be entered in ARM mode. +THUMB( bx r9 ) @ If this is a Thumb-2 kernel, +THUMB( .thumb ) @ switch to Thumb now. wait: ldr r2, =AUX_CORE_BOOT0_PA @ read from AuxCoreBoot0 ldr r0, [r2] mov r0, r0, lsr #5 diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index 615e5b1fb025dd..6bf6267005571b 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -46,15 +46,8 @@ static bool is_offset_valid; static u8 smps_offset; -/* - * Flag to ensure Smartreflex bit in TWL - * being cleared in board file is not overwritten. - */ -static bool __initdata twl_sr_enable_autoinit; -#define TWL4030_DCDC_GLOBAL_CFG 0x06 #define REG_SMPS_OFFSET 0xE0 -#define SMARTREFLEX_ENABLE BIT(3) static unsigned long twl4030_vsel_to_uv(const u8 vsel) { @@ -251,18 +244,6 @@ int __init omap3_twl_init(void) if (!cpu_is_omap34xx()) return -ENODEV; - /* - * The smartreflex bit on twl4030 specifies if the setting of voltage - * is done over the I2C_SR path. Since this setting is independent of - * the actual usage of smartreflex AVS module, we enable TWL SR bit - * by default irrespective of whether smartreflex AVS module is enabled - * on the OMAP side or not. This is because without this bit enabled, - * the voltage scaling through vp forceupdate/bypass mechanism of - * voltage scaling will not function on TWL over I2C_SR. - */ - if (!twl_sr_enable_autoinit) - omap3_twl_set_sr_bit(true); - voltdm = voltdm_lookup("mpu_iva"); omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic); @@ -271,44 +252,3 @@ int __init omap3_twl_init(void) return 0; } - -/** - * omap3_twl_set_sr_bit() - Set/Clear SR bit on TWL - * @enable: enable SR mode in twl or not - * - * If 'enable' is true, enables Smartreflex bit on TWL 4030 to make sure - * voltage scaling through OMAP SR works. Else, the smartreflex bit - * on twl4030 is cleared as there are platforms which use OMAP3 and T2 but - * use Synchronized Scaling Hardware Strategy (ENABLE_VMODE=1) and Direct - * Strategy Software Scaling Mode (ENABLE_VMODE=0), for setting the voltages, - * in those scenarios this bit is to be cleared (enable = false). - * - * Returns 0 on success, error is returned if I2C read/write fails. - */ -int __init omap3_twl_set_sr_bit(bool enable) -{ - u8 temp; - int ret; - if (twl_sr_enable_autoinit) - pr_warning("%s: unexpected multiple calls\n", __func__); - - ret = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp, - TWL4030_DCDC_GLOBAL_CFG); - if (ret) - goto err; - - if (enable) - temp |= SMARTREFLEX_ENABLE; - else - temp &= ~SMARTREFLEX_ENABLE; - - ret = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp, - TWL4030_DCDC_GLOBAL_CFG); - if (!ret) { - twl_sr_enable_autoinit = true; - return 0; - } -err: - pr_err("%s: Error access to TWL4030 (%d)\n", __func__, ret); - return ret; -} diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index 10855eb4ccc1c7..745367c0c2bb34 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include "soc.h" #include "omap_device.h" @@ -349,7 +349,7 @@ static struct fixed_voltage_config hsusb_reg_config = { /* .init_data filled later */ }; -static const char *nop_name = "usb_phy_gen_xceiv"; /* NOP PHY driver */ +static const char *nop_name = "usb_phy_generic"; /* NOP PHY driver */ static const char *reg_name = "reg-fixed-voltage"; /* Regulator driver */ /** @@ -435,7 +435,7 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys) struct platform_device *pdev; char *phy_id; struct platform_device_info pdevinfo; - struct usb_phy_gen_xceiv_platform_data nop_pdata; + struct usb_phy_generic_platform_data nop_pdata; for (i = 0; i < num_phys; i++) { @@ -469,8 +469,8 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys) pdevinfo.id = phy->port; pdevinfo.data = &nop_pdata; pdevinfo.size_data = - sizeof(struct usb_phy_gen_xceiv_platform_data); - scnprintf(phy_id, MAX_STR, "usb_phy_gen_xceiv.%d", + sizeof(struct usb_phy_generic_platform_data); + scnprintf(phy_id, MAX_STR, "usb_phy_generic.%d", phy->port); pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) { diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig index 14f2cae4109ca1..2412efb6cdd963 100644 --- a/arch/arm/mach-orion5x/Kconfig +++ b/arch/arm/mach-orion5x/Kconfig @@ -5,6 +5,11 @@ menu "Orion Implementations" config ARCH_ORION5X_DT bool "Marvell Orion5x Flattened Device Tree" select USE_OF + select ORION_CLK + select ORION_IRQCHIP + select ORION_TIMER + select PINCTRL + select PINCTRL_ORION help Say 'Y' here if you want your kernel to support the Marvell Orion5x using flattened device tree. @@ -23,6 +28,14 @@ config MACH_RD88F5182 Say 'Y' here if you want your kernel to support the Marvell Orion-NAS (88F5182) RD2 +config MACH_RD88F5182_DT + bool "Marvell Orion-NAS Reference Design (Flattened Device Tree)" + select ARCH_ORION5X_DT + select I2C_BOARDINFO + help + Say 'Y' here if you want your kernel to support the Marvell + Orion-NAS (88F5182) RD2, Flattened Device Tree. + config MACH_KUROBOX_PRO bool "KuroBox Pro" select I2C_BOARDINFO @@ -102,28 +115,13 @@ config MACH_MV2120 Say 'Y' here if you want your kernel to support the HP Media Vault mv2120 or mv5100. -config MACH_EDMINI_V2_DT - bool "LaCie Ethernet Disk mini V2 (Flattened Device Tree)" - select I2C_BOARDINFO +config MACH_D2NET_DT + bool "LaCie d2 Network / Big Disk Network (Flattened Device Tree)" select ARCH_ORION5X_DT - help - Say 'Y' here if you want your kernel to support the - LaCie Ethernet Disk mini V2 (Flattened Device Tree). - -config MACH_D2NET - bool "LaCie d2 Network" - select I2C_BOARDINFO help Say 'Y' here if you want your kernel to support the LaCie d2 Network NAS. -config MACH_BIGDISK - bool "LaCie Big Disk Network" - select I2C_BOARDINFO - help - Say 'Y' here if you want your kernel to support the - LaCie Big Disk Network NAS. - config MACH_NET2BIG bool "LaCie 2Big Network" select I2C_BOARDINFO @@ -131,8 +129,9 @@ config MACH_NET2BIG Say 'Y' here if you want your kernel to support the LaCie 2Big Network NAS. -config MACH_MSS2 - bool "Maxtor Shared Storage II" +config MACH_MSS2_DT + bool "Maxtor Shared Storage II (Flattened Device Tree)" + select ARCH_ORION5X_DT help Say 'Y' here if you want your kernel to support the Maxtor Shared Storage II platform. diff --git a/arch/arm/mach-orion5x/Makefile b/arch/arm/mach-orion5x/Makefile index 45da805fb23692..a40b5c9a58c4fb 100644 --- a/arch/arm/mach-orion5x/Makefile +++ b/arch/arm/mach-orion5x/Makefile @@ -12,10 +12,7 @@ obj-$(CONFIG_MACH_TS409) += ts409-setup.o tsx09-common.o obj-$(CONFIG_MACH_WRT350N_V2) += wrt350n-v2-setup.o obj-$(CONFIG_MACH_TS78XX) += ts78xx-setup.o obj-$(CONFIG_MACH_MV2120) += mv2120-setup.o -obj-$(CONFIG_MACH_D2NET) += d2net-setup.o -obj-$(CONFIG_MACH_BIGDISK) += d2net-setup.o obj-$(CONFIG_MACH_NET2BIG) += net2big-setup.o -obj-$(CONFIG_MACH_MSS2) += mss2-setup.o obj-$(CONFIG_MACH_WNR854T) += wnr854t-setup.o obj-$(CONFIG_MACH_RD88F5181L_GE) += rd88f5181l-ge-setup.o obj-$(CONFIG_MACH_RD88F5181L_FXO) += rd88f5181l-fxo-setup.o @@ -23,4 +20,6 @@ obj-$(CONFIG_MACH_RD88F6183AP_GE) += rd88f6183ap-ge-setup.o obj-$(CONFIG_MACH_LINKSTATION_LSCHL) += ls-chl-setup.o obj-$(CONFIG_ARCH_ORION5X_DT) += board-dt.o -obj-$(CONFIG_MACH_EDMINI_V2_DT) += edmini_v2-setup.o +obj-$(CONFIG_MACH_D2NET_DT) += board-d2net.o +obj-$(CONFIG_MACH_MSS2_DT) += board-mss2.o +obj-$(CONFIG_MACH_RD88F5182_DT) += board-rd88f5182.o diff --git a/arch/arm/mach-orion5x/board-d2net.c b/arch/arm/mach-orion5x/board-d2net.c new file mode 100644 index 00000000000000..8a7284124153b6 --- /dev/null +++ b/arch/arm/mach-orion5x/board-d2net.c @@ -0,0 +1,109 @@ +/* + * arch/arm/mach-orion5x/board-d2net.c + * + * LaCie d2Network and Big Disk Network NAS setup + * + * Copyright (C) 2009 Simon Guinot + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +/***************************************************************************** + * LaCie d2 Network Info + ****************************************************************************/ + +/***************************************************************************** + * GPIO LED's + ****************************************************************************/ + +/* + * The blue front LED is wired to the CPLD and can blink in relation with the + * SATA activity. + * + * The following array detail the different LED registers and the combination + * of their possible values: + * + * led_off | blink_ctrl | SATA active | LED state + * | | | + * 1 | x | x | off + * 0 | 0 | 0 | off + * 0 | 1 | 0 | blink (rate 300ms) + * 0 | x | 1 | on + * + * Notes: The blue and the red front LED's can't be on at the same time. + * Red LED have priority. + */ + +#define D2NET_GPIO_RED_LED 6 +#define D2NET_GPIO_BLUE_LED_BLINK_CTRL 16 +#define D2NET_GPIO_BLUE_LED_OFF 23 + +static struct gpio_led d2net_leds[] = { + { + .name = "d2net:blue:sata", + .default_trigger = "default-on", + .gpio = D2NET_GPIO_BLUE_LED_OFF, + .active_low = 1, + }, + { + .name = "d2net:red:fail", + .gpio = D2NET_GPIO_RED_LED, + }, +}; + +static struct gpio_led_platform_data d2net_led_data = { + .num_leds = ARRAY_SIZE(d2net_leds), + .leds = d2net_leds, +}; + +static struct platform_device d2net_gpio_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &d2net_led_data, + }, +}; + +static void __init d2net_gpio_leds_init(void) +{ + int err; + + /* Configure register blink_ctrl to allow SATA activity LED blinking. */ + err = gpio_request(D2NET_GPIO_BLUE_LED_BLINK_CTRL, "blue LED blink"); + if (err == 0) { + err = gpio_direction_output(D2NET_GPIO_BLUE_LED_BLINK_CTRL, 1); + if (err) + gpio_free(D2NET_GPIO_BLUE_LED_BLINK_CTRL); + } + if (err) + pr_err("d2net: failed to configure blue LED blink GPIO\n"); + + platform_device_register(&d2net_gpio_leds); +} + +/***************************************************************************** + * General Setup + ****************************************************************************/ + +void __init d2net_init(void) +{ + d2net_gpio_leds_init(); + + pr_notice("d2net: Flash write are not yet supported.\n"); +} diff --git a/arch/arm/mach-orion5x/board-dt.c b/arch/arm/mach-orion5x/board-dt.c index c134a826070a14..35d418faf8f1b8 100644 --- a/arch/arm/mach-orion5x/board-dt.c +++ b/arch/arm/mach-orion5x/board-dt.c @@ -15,10 +15,16 @@ #include #include #include +#include +#include +#include #include #include +#include #include +#include #include +#include #include "common.h" static struct of_dev_auxdata orion5x_auxdata_lookup[] __initdata = { @@ -39,14 +45,13 @@ static void __init orion5x_dt_init(void) orion5x_id(&dev, &rev, &dev_name); printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, orion5x_tclk); + BUG_ON(mvebu_mbus_dt_init()); + /* * Setup Orion address map */ orion5x_setup_wins(); - /* Setup root of clk tree */ - clk_init(); - /* * Don't issue "Wait for Interrupt" instruction if we are * running on D0 5281 silicon. @@ -56,8 +61,8 @@ static void __init orion5x_dt_init(void) cpu_idle_poll_ctrl(true); } - if (of_machine_is_compatible("lacie,ethernet-disk-mini-v2")) - edmini_v2_init(); + if (of_machine_is_compatible("maxtor,shared-storage-2")) + mss2_init(); of_platform_populate(NULL, of_default_bus_match_table, orion5x_auxdata_lookup, NULL); @@ -71,9 +76,6 @@ static const char *orion5x_dt_compat[] = { DT_MACHINE_START(ORION5X_DT, "Marvell Orion5x (Flattened Device Tree)") /* Maintainer: Thomas Petazzoni */ .map_io = orion5x_map_io, - .init_early = orion5x_init_early, - .init_irq = orion_dt_init_irq, - .init_time = orion5x_timer_init, .init_machine = orion5x_dt_init, .restart = orion5x_restart, .dt_compat = orion5x_dt_compat, diff --git a/arch/arm/mach-orion5x/board-mss2.c b/arch/arm/mach-orion5x/board-mss2.c new file mode 100644 index 00000000000000..66f9c3ba86ccd3 --- /dev/null +++ b/arch/arm/mach-orion5x/board-mss2.c @@ -0,0 +1,90 @@ +/* + * Maxtor Shared Storage II Board Setup + * + * Maintainer: Sylver Bruneau + * + * 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 +#include +#include "common.h" + +/***************************************************************************** + * Maxtor Shared Storage II Info + ****************************************************************************/ + +/**************************************************************************** + * PCI setup + ****************************************************************************/ +static int __init mss2_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq; + + /* + * Check for devices with hard-wired IRQs. + */ + irq = orion5x_pci_map_irq(dev, slot, pin); + if (irq != -1) + return irq; + + return -1; +} + +static struct hw_pci mss2_pci __initdata = { + .nr_controllers = 2, + .setup = orion5x_pci_sys_setup, + .scan = orion5x_pci_sys_scan_bus, + .map_irq = mss2_pci_map_irq, +}; + +static int __init mss2_pci_init(void) +{ + if (machine_is_mss2()) + pci_common_init(&mss2_pci); + + return 0; +} +subsys_initcall(mss2_pci_init); + +/***************************************************************************** + * MSS2 power off method + ****************************************************************************/ +/* + * On the Maxtor Shared Storage II, the shutdown process is the following : + * - Userland modifies U-boot env to tell U-boot to go idle at next boot + * - The board reboots + * - U-boot starts and go into an idle mode until the user press "power" + */ +static void mss2_power_off(void) +{ + u32 reg; + + /* + * Enable and issue soft reset + */ + reg = readl(RSTOUTn_MASK); + reg |= 1 << 2; + writel(reg, RSTOUTn_MASK); + + reg = readl(CPU_SOFT_RESET); + reg |= 1; + writel(reg, CPU_SOFT_RESET); +} + +void __init mss2_init(void) +{ + /* register mss2 specific power-off method */ + pm_power_off = mss2_power_off; +} diff --git a/arch/arm/mach-orion5x/board-rd88f5182.c b/arch/arm/mach-orion5x/board-rd88f5182.c new file mode 100644 index 00000000000000..270824b0e50fcc --- /dev/null +++ b/arch/arm/mach-orion5x/board-rd88f5182.c @@ -0,0 +1,116 @@ +/* + * arch/arm/mach-orion5x/rd88f5182-setup.c + * + * Marvell Orion-NAS Reference Design Setup + * + * Maintainer: Ronen Shitrit + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +/***************************************************************************** + * RD-88F5182 Info + ****************************************************************************/ + +/* + * PCI + */ + +#define RD88F5182_PCI_SLOT0_OFFS 7 +#define RD88F5182_PCI_SLOT0_IRQ_A_PIN 7 +#define RD88F5182_PCI_SLOT0_IRQ_B_PIN 6 + +/***************************************************************************** + * PCI + ****************************************************************************/ + +static void __init rd88f5182_pci_preinit(void) +{ + int pin; + + /* + * Configure PCI GPIO IRQ pins + */ + pin = RD88F5182_PCI_SLOT0_IRQ_A_PIN; + if (gpio_request(pin, "PCI IntA") == 0) { + if (gpio_direction_input(pin) == 0) { + irq_set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW); + } else { + printk(KERN_ERR "rd88f5182_pci_preinit failed to " + "set_irq_type pin %d\n", pin); + gpio_free(pin); + } + } else { + printk(KERN_ERR "rd88f5182_pci_preinit failed to request gpio %d\n", pin); + } + + pin = RD88F5182_PCI_SLOT0_IRQ_B_PIN; + if (gpio_request(pin, "PCI IntB") == 0) { + if (gpio_direction_input(pin) == 0) { + irq_set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW); + } else { + printk(KERN_ERR "rd88f5182_pci_preinit failed to " + "set_irq_type pin %d\n", pin); + gpio_free(pin); + } + } else { + printk(KERN_ERR "rd88f5182_pci_preinit failed to gpio_request %d\n", pin); + } +} + +static int __init rd88f5182_pci_map_irq(const struct pci_dev *dev, u8 slot, + u8 pin) +{ + int irq; + + /* + * Check for devices with hard-wired IRQs. + */ + irq = orion5x_pci_map_irq(dev, slot, pin); + if (irq != -1) + return irq; + + /* + * PCI IRQs are connected via GPIOs + */ + switch (slot - RD88F5182_PCI_SLOT0_OFFS) { + case 0: + if (pin == 1) + return gpio_to_irq(RD88F5182_PCI_SLOT0_IRQ_A_PIN); + else + return gpio_to_irq(RD88F5182_PCI_SLOT0_IRQ_B_PIN); + default: + return -1; + } +} + +static struct hw_pci rd88f5182_pci __initdata = { + .nr_controllers = 2, + .preinit = rd88f5182_pci_preinit, + .setup = orion5x_pci_sys_setup, + .scan = orion5x_pci_sys_scan_bus, + .map_irq = rd88f5182_pci_map_irq, +}; + +static int __init rd88f5182_pci_init(void) +{ + if (of_machine_is_compatible("marvell,rd-88f5182-nas")) + pci_common_init(&rd88f5182_pci); + + return 0; +} + +subsys_initcall(rd88f5182_pci_init); diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h index f565f9944af2ee..26d6f34b6027e4 100644 --- a/arch/arm/mach-orion5x/common.h +++ b/arch/arm/mach-orion5x/common.h @@ -21,7 +21,7 @@ struct mv_sata_platform_data; #define ORION_MBUS_DEVBUS_BOOT_ATTR 0x0f #define ORION_MBUS_DEVBUS_TARGET(cs) 0x01 #define ORION_MBUS_DEVBUS_ATTR(cs) (~(1 << cs)) -#define ORION_MBUS_SRAM_TARGET 0x00 +#define ORION_MBUS_SRAM_TARGET 0x09 #define ORION_MBUS_SRAM_ATTR 0x00 /* @@ -64,17 +64,16 @@ int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys); struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys); int orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); -/* board init functions for boards not fully converted to fdt */ -#ifdef CONFIG_MACH_EDMINI_V2_DT -void edmini_v2_init(void); -#else -static inline void edmini_v2_init(void) {}; -#endif - struct meminfo; struct tag; extern void __init tag_fixup_mem32(struct tag *, char **, struct meminfo *); +#ifdef CONFIG_MACH_MSS2_DT +extern void mss2_init(void); +#else +static inline void mss2_init(void) {} +#endif + /***************************************************************************** * Helpers to access Orion registers ****************************************************************************/ diff --git a/arch/arm/mach-orion5x/d2net-setup.c b/arch/arm/mach-orion5x/d2net-setup.c deleted file mode 100644 index 8f68b745c1d5f5..00000000000000 --- a/arch/arm/mach-orion5x/d2net-setup.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * arch/arm/mach-orion5x/d2net-setup.c - * - * LaCie d2Network and Big Disk Network NAS setup - * - * Copyright (C) 2009 Simon Guinot - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" -#include "mpp.h" - -/***************************************************************************** - * LaCie d2 Network Info - ****************************************************************************/ - -/* - * 512KB NOR flash Device bus boot chip select - */ - -#define D2NET_NOR_BOOT_BASE 0xfff80000 -#define D2NET_NOR_BOOT_SIZE SZ_512K - -/***************************************************************************** - * 512KB NOR Flash on Boot Device - ****************************************************************************/ - -/* - * TODO: Check write support on flash MX29LV400CBTC-70G - */ - -static struct mtd_partition d2net_partitions[] = { - { - .name = "Full512kb", - .size = MTDPART_SIZ_FULL, - .offset = 0, - .mask_flags = MTD_WRITEABLE, - }, -}; - -static struct physmap_flash_data d2net_nor_flash_data = { - .width = 1, - .parts = d2net_partitions, - .nr_parts = ARRAY_SIZE(d2net_partitions), -}; - -static struct resource d2net_nor_flash_resource = { - .flags = IORESOURCE_MEM, - .start = D2NET_NOR_BOOT_BASE, - .end = D2NET_NOR_BOOT_BASE - + D2NET_NOR_BOOT_SIZE - 1, -}; - -static struct platform_device d2net_nor_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &d2net_nor_flash_data, - }, - .num_resources = 1, - .resource = &d2net_nor_flash_resource, -}; - -/***************************************************************************** - * Ethernet - ****************************************************************************/ - -static struct mv643xx_eth_platform_data d2net_eth_data = { - .phy_addr = MV643XX_ETH_PHY_ADDR(8), -}; - -/***************************************************************************** - * I2C devices - ****************************************************************************/ - -/* - * i2c addr | chip | description - * 0x32 | Ricoh 5C372b | RTC - * 0x3e | GMT G762 | PWM fan controller - * 0x50 | HT24LC08 | eeprom (1kB) - * - * TODO: Add G762 support to the g760a driver. - */ -static struct i2c_board_info __initdata d2net_i2c_devices[] = { - { - I2C_BOARD_INFO("rs5c372b", 0x32), - }, { - I2C_BOARD_INFO("24c08", 0x50), - }, -}; - -/***************************************************************************** - * SATA - ****************************************************************************/ - -static struct mv_sata_platform_data d2net_sata_data = { - .n_ports = 2, -}; - -#define D2NET_GPIO_SATA0_POWER 3 -#define D2NET_GPIO_SATA1_POWER 12 - -static void __init d2net_sata_power_init(void) -{ - int err; - - err = gpio_request(D2NET_GPIO_SATA0_POWER, "SATA0 power"); - if (err == 0) { - err = gpio_direction_output(D2NET_GPIO_SATA0_POWER, 1); - if (err) - gpio_free(D2NET_GPIO_SATA0_POWER); - } - if (err) - pr_err("d2net: failed to configure SATA0 power GPIO\n"); - - err = gpio_request(D2NET_GPIO_SATA1_POWER, "SATA1 power"); - if (err == 0) { - err = gpio_direction_output(D2NET_GPIO_SATA1_POWER, 1); - if (err) - gpio_free(D2NET_GPIO_SATA1_POWER); - } - if (err) - pr_err("d2net: failed to configure SATA1 power GPIO\n"); -} - -/***************************************************************************** - * GPIO LED's - ****************************************************************************/ - -/* - * The blue front LED is wired to the CPLD and can blink in relation with the - * SATA activity. - * - * The following array detail the different LED registers and the combination - * of their possible values: - * - * led_off | blink_ctrl | SATA active | LED state - * | | | - * 1 | x | x | off - * 0 | 0 | 0 | off - * 0 | 1 | 0 | blink (rate 300ms) - * 0 | x | 1 | on - * - * Notes: The blue and the red front LED's can't be on at the same time. - * Red LED have priority. - */ - -#define D2NET_GPIO_RED_LED 6 -#define D2NET_GPIO_BLUE_LED_BLINK_CTRL 16 -#define D2NET_GPIO_BLUE_LED_OFF 23 - -static struct gpio_led d2net_leds[] = { - { - .name = "d2net:blue:sata", - .default_trigger = "default-on", - .gpio = D2NET_GPIO_BLUE_LED_OFF, - .active_low = 1, - }, - { - .name = "d2net:red:fail", - .gpio = D2NET_GPIO_RED_LED, - }, -}; - -static struct gpio_led_platform_data d2net_led_data = { - .num_leds = ARRAY_SIZE(d2net_leds), - .leds = d2net_leds, -}; - -static struct platform_device d2net_gpio_leds = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &d2net_led_data, - }, -}; - -static void __init d2net_gpio_leds_init(void) -{ - int err; - - /* Configure GPIO over MPP max number. */ - orion_gpio_set_valid(D2NET_GPIO_BLUE_LED_OFF, 1); - - /* Configure register blink_ctrl to allow SATA activity LED blinking. */ - err = gpio_request(D2NET_GPIO_BLUE_LED_BLINK_CTRL, "blue LED blink"); - if (err == 0) { - err = gpio_direction_output(D2NET_GPIO_BLUE_LED_BLINK_CTRL, 1); - if (err) - gpio_free(D2NET_GPIO_BLUE_LED_BLINK_CTRL); - } - if (err) - pr_err("d2net: failed to configure blue LED blink GPIO\n"); - - platform_device_register(&d2net_gpio_leds); -} - -/**************************************************************************** - * GPIO keys - ****************************************************************************/ - -#define D2NET_GPIO_PUSH_BUTTON 18 -#define D2NET_GPIO_POWER_SWITCH_ON 8 -#define D2NET_GPIO_POWER_SWITCH_OFF 9 - -#define D2NET_SWITCH_POWER_ON 0x1 -#define D2NET_SWITCH_POWER_OFF 0x2 - -static struct gpio_keys_button d2net_buttons[] = { - { - .type = EV_SW, - .code = D2NET_SWITCH_POWER_OFF, - .gpio = D2NET_GPIO_POWER_SWITCH_OFF, - .desc = "Power rocker switch (auto|off)", - .active_low = 0, - }, - { - .type = EV_SW, - .code = D2NET_SWITCH_POWER_ON, - .gpio = D2NET_GPIO_POWER_SWITCH_ON, - .desc = "Power rocker switch (on|auto)", - .active_low = 0, - }, - { - .type = EV_KEY, - .code = KEY_POWER, - .gpio = D2NET_GPIO_PUSH_BUTTON, - .desc = "Front Push Button", - .active_low = 0, - }, -}; - -static struct gpio_keys_platform_data d2net_button_data = { - .buttons = d2net_buttons, - .nbuttons = ARRAY_SIZE(d2net_buttons), -}; - -static struct platform_device d2net_gpio_buttons = { - .name = "gpio-keys", - .id = -1, - .dev = { - .platform_data = &d2net_button_data, - }, -}; - -/***************************************************************************** - * General Setup - ****************************************************************************/ - -static unsigned int d2net_mpp_modes[] __initdata = { - MPP0_GPIO, /* Board ID (bit 0) */ - MPP1_GPIO, /* Board ID (bit 1) */ - MPP2_GPIO, /* Board ID (bit 2) */ - MPP3_GPIO, /* SATA 0 power */ - MPP4_UNUSED, - MPP5_GPIO, /* Fan fail detection */ - MPP6_GPIO, /* Red front LED */ - MPP7_UNUSED, - MPP8_GPIO, /* Rear power switch (on|auto) */ - MPP9_GPIO, /* Rear power switch (auto|off) */ - MPP10_UNUSED, - MPP11_UNUSED, - MPP12_GPIO, /* SATA 1 power */ - MPP13_UNUSED, - MPP14_SATA_LED, /* SATA 0 active */ - MPP15_SATA_LED, /* SATA 1 active */ - MPP16_GPIO, /* Blue front LED blink control */ - MPP17_UNUSED, - MPP18_GPIO, /* Front button (0 = Released, 1 = Pushed ) */ - MPP19_UNUSED, - 0, - /* 22: USB port 1 fuse (0 = Fail, 1 = Ok) */ - /* 23: Blue front LED off */ - /* 24: Inhibit board power off (0 = Disabled, 1 = Enabled) */ -}; - -#define D2NET_GPIO_INHIBIT_POWER_OFF 24 - -static void __init d2net_init(void) -{ - /* - * Setup basic Orion functions. Need to be called early. - */ - orion5x_init(); - - orion5x_mpp_conf(d2net_mpp_modes); - - /* - * Configure peripherals. - */ - orion5x_ehci0_init(); - orion5x_eth_init(&d2net_eth_data); - orion5x_i2c_init(); - orion5x_uart0_init(); - - d2net_sata_power_init(); - orion5x_sata_init(&d2net_sata_data); - - mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET, - ORION_MBUS_DEVBUS_BOOT_ATTR, - D2NET_NOR_BOOT_BASE, - D2NET_NOR_BOOT_SIZE); - platform_device_register(&d2net_nor_flash); - - platform_device_register(&d2net_gpio_buttons); - - d2net_gpio_leds_init(); - - pr_notice("d2net: Flash write are not yet supported.\n"); - - i2c_register_board_info(0, d2net_i2c_devices, - ARRAY_SIZE(d2net_i2c_devices)); - - orion_gpio_set_valid(D2NET_GPIO_INHIBIT_POWER_OFF, 1); -} - -/* Warning: LaCie use a wrong mach-type (0x20e=526) in their bootloader. */ - -#ifdef CONFIG_MACH_D2NET -MACHINE_START(D2NET, "LaCie d2 Network") - .atag_offset = 0x100, - .init_machine = d2net_init, - .map_io = orion5x_map_io, - .init_early = orion5x_init_early, - .init_irq = orion5x_init_irq, - .init_time = orion5x_timer_init, - .fixup = tag_fixup_mem32, - .restart = orion5x_restart, -MACHINE_END -#endif - -#ifdef CONFIG_MACH_BIGDISK -MACHINE_START(BIGDISK, "LaCie Big Disk Network") - .atag_offset = 0x100, - .init_machine = d2net_init, - .map_io = orion5x_map_io, - .init_early = orion5x_init_early, - .init_irq = orion5x_init_irq, - .init_time = orion5x_timer_init, - .fixup = tag_fixup_mem32, - .restart = orion5x_restart, -MACHINE_END -#endif - diff --git a/arch/arm/mach-orion5x/edmini_v2-setup.c b/arch/arm/mach-orion5x/edmini_v2-setup.c deleted file mode 100644 index f66c1b2ee8c1fe..00000000000000 --- a/arch/arm/mach-orion5x/edmini_v2-setup.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * arch/arm/mach-orion5x/edmini_v2-setup.c - * - * LaCie Ethernet Disk mini V2 Setup - * - * Copyright (C) 2008 Christopher Moore - * Copyright (C) 2008 Albert Aribaud - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -/* - * TODO: add Orion USB device port init when kernel.org support is added. - * TODO: add flash write support: see below. - * TODO: add power-off support. - * TODO: add I2C EEPROM support. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" -#include "mpp.h" - -/***************************************************************************** - * EDMINI_V2 Info - ****************************************************************************/ - -/* - * 512KB NOR flash Device bus boot chip select - */ - -#define EDMINI_V2_NOR_BOOT_BASE 0xfff80000 -#define EDMINI_V2_NOR_BOOT_SIZE SZ_512K - -/***************************************************************************** - * 512KB NOR Flash on BOOT Device - ****************************************************************************/ - -/* - * Currently the MTD code does not recognize the MX29LV400CBCT as a bottom - * -type device. This could cause risks of accidentally erasing critical - * flash sectors. We thus define a single, write-protected partition covering - * the whole flash. - * TODO: once the flash part TOP/BOTTOM detection issue is sorted out in the MTD - * code, break this into at least three partitions: 'u-boot code', 'u-boot - * environment' and 'whatever is left'. - */ - -static struct mtd_partition edmini_v2_partitions[] = { - { - .name = "Full512kb", - .size = 0x00080000, - .offset = 0x00000000, - .mask_flags = MTD_WRITEABLE, - }, -}; - -static struct physmap_flash_data edmini_v2_nor_flash_data = { - .width = 1, - .parts = edmini_v2_partitions, - .nr_parts = ARRAY_SIZE(edmini_v2_partitions), -}; - -static struct resource edmini_v2_nor_flash_resource = { - .flags = IORESOURCE_MEM, - .start = EDMINI_V2_NOR_BOOT_BASE, - .end = EDMINI_V2_NOR_BOOT_BASE - + EDMINI_V2_NOR_BOOT_SIZE - 1, -}; - -static struct platform_device edmini_v2_nor_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edmini_v2_nor_flash_data, - }, - .num_resources = 1, - .resource = &edmini_v2_nor_flash_resource, -}; - -/***************************************************************************** - * RTC 5C372a on I2C bus - ****************************************************************************/ - -#define EDMINIV2_RTC_GPIO 3 - -static struct i2c_board_info __initdata edmini_v2_i2c_rtc = { - I2C_BOARD_INFO("rs5c372a", 0x32), - .irq = 0, -}; - -/***************************************************************************** - * General Setup - ****************************************************************************/ -static unsigned int edminiv2_mpp_modes[] __initdata = { - MPP0_UNUSED, - MPP1_UNUSED, - MPP2_UNUSED, - MPP3_GPIO, /* RTC interrupt */ - MPP4_UNUSED, - MPP5_UNUSED, - MPP6_UNUSED, - MPP7_UNUSED, - MPP8_UNUSED, - MPP9_UNUSED, - MPP10_UNUSED, - MPP11_UNUSED, - MPP12_SATA_LED, /* SATA 0 presence */ - MPP13_SATA_LED, /* SATA 1 presence */ - MPP14_SATA_LED, /* SATA 0 active */ - MPP15_SATA_LED, /* SATA 1 active */ - /* 16: Power LED control (0 = On, 1 = Off) */ - MPP16_GPIO, - /* 17: Power LED control select (0 = CPLD, 1 = GPIO16) */ - MPP17_GPIO, - /* 18: Power button status (0 = Released, 1 = Pressed) */ - MPP18_GPIO, - MPP19_UNUSED, - 0, -}; - -void __init edmini_v2_init(void) -{ - orion5x_mpp_conf(edminiv2_mpp_modes); - - /* - * Configure peripherals. - */ - orion5x_ehci0_init(); - - mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET, - ORION_MBUS_DEVBUS_BOOT_ATTR, - EDMINI_V2_NOR_BOOT_BASE, - EDMINI_V2_NOR_BOOT_SIZE); - platform_device_register(&edmini_v2_nor_flash); - - pr_notice("edmini_v2: USB device port, flash write and power-off " - "are not yet supported.\n"); - - /* Get RTC IRQ and register the chip */ - if (gpio_request(EDMINIV2_RTC_GPIO, "rtc") == 0) { - if (gpio_direction_input(EDMINIV2_RTC_GPIO) == 0) - edmini_v2_i2c_rtc.irq = gpio_to_irq(EDMINIV2_RTC_GPIO); - else - gpio_free(EDMINIV2_RTC_GPIO); - } - - if (edmini_v2_i2c_rtc.irq == 0) - pr_warning("edmini_v2: failed to get RTC IRQ\n"); - - i2c_register_board_info(0, &edmini_v2_i2c_rtc, 1); -} diff --git a/arch/arm/mach-orion5x/irq.c b/arch/arm/mach-orion5x/irq.c index 9654b0cc589287..cd4bac4d7e43f1 100644 --- a/arch/arm/mach-orion5x/irq.c +++ b/arch/arm/mach-orion5x/irq.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "common.h" static int __initdata gpio0_irqs[4] = { @@ -25,10 +26,37 @@ static int __initdata gpio0_irqs[4] = { IRQ_ORION5X_GPIO_24_31, }; +#ifdef CONFIG_MULTI_IRQ_HANDLER +/* + * Compiling with both non-DT and DT support enabled, will + * break asm irq handler used by non-DT boards. Therefore, + * we provide a C-style irq handler even for non-DT boards, + * if MULTI_IRQ_HANDLER is set. + */ + +asmlinkage void +__exception_irq_entry orion5x_legacy_handle_irq(struct pt_regs *regs) +{ + u32 stat; + + stat = readl_relaxed(MAIN_IRQ_CAUSE); + stat &= readl_relaxed(MAIN_IRQ_MASK); + if (stat) { + unsigned int hwirq = __fls(stat); + handle_IRQ(hwirq, regs); + return; + } +} +#endif + void __init orion5x_init_irq(void) { orion_irq_init(0, MAIN_IRQ_MASK); +#ifdef CONFIG_MULTI_IRQ_HANDLER + set_handle_irq(orion5x_legacy_handle_irq); +#endif + /* * Initialize gpiolib for GPIOs 0-31. */ diff --git a/arch/arm/mach-orion5x/mss2-setup.c b/arch/arm/mach-orion5x/mss2-setup.c deleted file mode 100644 index e105130ba51c36..00000000000000 --- a/arch/arm/mach-orion5x/mss2-setup.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Maxtor Shared Storage II Board Setup - * - * Maintainer: Sylver Bruneau - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" -#include "mpp.h" - -#define MSS2_NOR_BOOT_BASE 0xff800000 -#define MSS2_NOR_BOOT_SIZE SZ_256K - -/***************************************************************************** - * Maxtor Shared Storage II Info - ****************************************************************************/ - -/* - * Maxtor Shared Storage II hardware : - * - Marvell 88F5182-A2 C500 - * - Marvell 88E1111 Gigabit Ethernet PHY - * - RTC M41T81 (@0x68) on I2C bus - * - 256KB NOR flash - * - 64MB of RAM - */ - -/***************************************************************************** - * 256KB NOR Flash on BOOT Device - ****************************************************************************/ - -static struct physmap_flash_data mss2_nor_flash_data = { - .width = 1, -}; - -static struct resource mss2_nor_flash_resource = { - .flags = IORESOURCE_MEM, - .start = MSS2_NOR_BOOT_BASE, - .end = MSS2_NOR_BOOT_BASE + MSS2_NOR_BOOT_SIZE - 1, -}; - -static struct platform_device mss2_nor_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &mss2_nor_flash_data, - }, - .resource = &mss2_nor_flash_resource, - .num_resources = 1, -}; - -/**************************************************************************** - * PCI setup - ****************************************************************************/ -static int __init mss2_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - int irq; - - /* - * Check for devices with hard-wired IRQs. - */ - irq = orion5x_pci_map_irq(dev, slot, pin); - if (irq != -1) - return irq; - - return -1; -} - -static struct hw_pci mss2_pci __initdata = { - .nr_controllers = 2, - .setup = orion5x_pci_sys_setup, - .scan = orion5x_pci_sys_scan_bus, - .map_irq = mss2_pci_map_irq, -}; - -static int __init mss2_pci_init(void) -{ - if (machine_is_mss2()) - pci_common_init(&mss2_pci); - - return 0; -} -subsys_initcall(mss2_pci_init); - - -/***************************************************************************** - * Ethernet - ****************************************************************************/ - -static struct mv643xx_eth_platform_data mss2_eth_data = { - .phy_addr = MV643XX_ETH_PHY_ADDR(8), -}; - -/***************************************************************************** - * SATA - ****************************************************************************/ - -static struct mv_sata_platform_data mss2_sata_data = { - .n_ports = 2, -}; - -/***************************************************************************** - * GPIO buttons - ****************************************************************************/ - -#define MSS2_GPIO_KEY_RESET 12 -#define MSS2_GPIO_KEY_POWER 11 - -static struct gpio_keys_button mss2_buttons[] = { - { - .code = KEY_POWER, - .gpio = MSS2_GPIO_KEY_POWER, - .desc = "Power", - .active_low = 1, - }, { - .code = KEY_RESTART, - .gpio = MSS2_GPIO_KEY_RESET, - .desc = "Reset", - .active_low = 1, - }, -}; - -static struct gpio_keys_platform_data mss2_button_data = { - .buttons = mss2_buttons, - .nbuttons = ARRAY_SIZE(mss2_buttons), -}; - -static struct platform_device mss2_button_device = { - .name = "gpio-keys", - .id = -1, - .dev = { - .platform_data = &mss2_button_data, - }, -}; - -/***************************************************************************** - * RTC m41t81 on I2C bus - ****************************************************************************/ - -#define MSS2_GPIO_RTC_IRQ 3 - -static struct i2c_board_info __initdata mss2_i2c_rtc = { - I2C_BOARD_INFO("m41t81", 0x68), -}; - -/***************************************************************************** - * MSS2 power off method - ****************************************************************************/ -/* - * On the Maxtor Shared Storage II, the shutdown process is the following : - * - Userland modifies U-boot env to tell U-boot to go idle at next boot - * - The board reboots - * - U-boot starts and go into an idle mode until the user press "power" - */ -static void mss2_power_off(void) -{ - u32 reg; - - /* - * Enable and issue soft reset - */ - reg = readl(RSTOUTn_MASK); - reg |= 1 << 2; - writel(reg, RSTOUTn_MASK); - - reg = readl(CPU_SOFT_RESET); - reg |= 1; - writel(reg, CPU_SOFT_RESET); -} - -/**************************************************************************** - * General Setup - ****************************************************************************/ -static unsigned int mss2_mpp_modes[] __initdata = { - MPP0_GPIO, /* Power LED */ - MPP1_GPIO, /* Error LED */ - MPP2_UNUSED, - MPP3_GPIO, /* RTC interrupt */ - MPP4_GPIO, /* HDD ind. (Single/Dual)*/ - MPP5_GPIO, /* HD0 5V control */ - MPP6_GPIO, /* HD0 12V control */ - MPP7_GPIO, /* HD1 5V control */ - MPP8_GPIO, /* HD1 12V control */ - MPP9_UNUSED, - MPP10_GPIO, /* Fan control */ - MPP11_GPIO, /* Power button */ - MPP12_GPIO, /* Reset button */ - MPP13_UNUSED, - MPP14_SATA_LED, /* SATA 0 active */ - MPP15_SATA_LED, /* SATA 1 active */ - MPP16_UNUSED, - MPP17_UNUSED, - MPP18_UNUSED, - MPP19_UNUSED, - 0, -}; - -static void __init mss2_init(void) -{ - /* Setup basic Orion functions. Need to be called early. */ - orion5x_init(); - - orion5x_mpp_conf(mss2_mpp_modes); - - /* - * MPP[20] Unused - * MPP[21] PCI clock - * MPP[22] USB 0 over current - * MPP[23] USB 1 over current - */ - - /* - * Configure peripherals. - */ - orion5x_ehci0_init(); - orion5x_ehci1_init(); - orion5x_eth_init(&mss2_eth_data); - orion5x_i2c_init(); - orion5x_sata_init(&mss2_sata_data); - orion5x_uart0_init(); - orion5x_xor_init(); - - mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET, - ORION_MBUS_DEVBUS_BOOT_ATTR, - MSS2_NOR_BOOT_BASE, - MSS2_NOR_BOOT_SIZE); - platform_device_register(&mss2_nor_flash); - - platform_device_register(&mss2_button_device); - - if (gpio_request(MSS2_GPIO_RTC_IRQ, "rtc") == 0) { - if (gpio_direction_input(MSS2_GPIO_RTC_IRQ) == 0) - mss2_i2c_rtc.irq = gpio_to_irq(MSS2_GPIO_RTC_IRQ); - else - gpio_free(MSS2_GPIO_RTC_IRQ); - } - i2c_register_board_info(0, &mss2_i2c_rtc, 1); - - /* register mss2 specific power-off method */ - pm_power_off = mss2_power_off; -} - -MACHINE_START(MSS2, "Maxtor Shared Storage II") - /* Maintainer: Sylver Bruneau */ - .atag_offset = 0x100, - .init_machine = mss2_init, - .map_io = orion5x_map_io, - .init_early = orion5x_init_early, - .init_irq = orion5x_init_irq, - .init_time = orion5x_timer_init, - .fixup = tag_fixup_mem32, - .restart = orion5x_restart, -MACHINE_END diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index b19d1c361cab51..205f9bf3821e30 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -413,7 +413,7 @@ static struct fixed_voltage_config can_regulator_pdata = { static struct platform_device can_regulator_device = { .name = "reg-fixed-volage", - .id = -1, + .id = 0, .dev = { .platform_data = &can_regulator_pdata, }, @@ -510,18 +510,6 @@ struct platform_device zeus_max6369_device = { .num_resources = 1, }; -static struct platform_device *zeus_devices[] __initdata = { - &zeus_serial_device, - &zeus_mtd_devices[0], - &zeus_dm9k0_device, - &zeus_dm9k1_device, - &zeus_sram_device, - &zeus_leds_device, - &zeus_pcmcia_device, - &zeus_max6369_device, - &can_regulator_device, -}; - /* AC'97 */ static pxa2xx_audio_ops_t zeus_ac97_info = { .reset_gpio = 95, @@ -532,44 +520,50 @@ static pxa2xx_audio_ops_t zeus_ac97_info = { * USB host */ -static int zeus_ohci_init(struct device *dev) -{ - int err; - - /* Switch on port 2. */ - if ((err = gpio_request(ZEUS_USB2_PWREN_GPIO, "USB2_PWREN"))) { - dev_err(dev, "Can't request USB2_PWREN\n"); - return err; - } - - if ((err = gpio_direction_output(ZEUS_USB2_PWREN_GPIO, 1))) { - gpio_free(ZEUS_USB2_PWREN_GPIO); - dev_err(dev, "Can't enable USB2_PWREN\n"); - return err; - } +static struct regulator_consumer_supply zeus_ohci_regulator_supplies[] = { + REGULATOR_SUPPLY("vbus2", "pxa27x-ohci"), +}; - /* Port 2 is shared between host and client interface. */ - UP2OCR = UP2OCR_HXOE | UP2OCR_HXS | UP2OCR_DMPDE | UP2OCR_DPPDE; +static struct regulator_init_data zeus_ohci_regulator_data = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(zeus_ohci_regulator_supplies), + .consumer_supplies = zeus_ohci_regulator_supplies, +}; - return 0; -} +static struct fixed_voltage_config zeus_ohci_regulator_config = { + .supply_name = "vbus2", + .microvolts = 5000000, /* 5.0V */ + .gpio = ZEUS_USB2_PWREN_GPIO, + .enable_high = 1, + .startup_delay = 0, + .init_data = &zeus_ohci_regulator_data, +}; -static void zeus_ohci_exit(struct device *dev) -{ - /* Power-off port 2 */ - gpio_direction_output(ZEUS_USB2_PWREN_GPIO, 0); - gpio_free(ZEUS_USB2_PWREN_GPIO); -} +static struct platform_device zeus_ohci_regulator_device = { + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &zeus_ohci_regulator_config, + }, +}; static struct pxaohci_platform_data zeus_ohci_platform_data = { .port_mode = PMM_NPS_MODE, /* Clear Power Control Polarity Low and set Power Sense * Polarity Low. Supply power to USB ports. */ .flags = ENABLE_PORT_ALL | POWER_SENSE_LOW, - .init = zeus_ohci_init, - .exit = zeus_ohci_exit, }; +static void zeus_register_ohci(void) +{ + /* Port 2 is shared between host and client interface. */ + UP2OCR = UP2OCR_HXOE | UP2OCR_HXS | UP2OCR_DMPDE | UP2OCR_DPPDE; + + pxa_set_ohci_info(&zeus_ohci_platform_data); +} + /* * Flat Panel */ @@ -677,6 +671,19 @@ static struct pxa2xx_udc_mach_info zeus_udc_info = { .udc_command = zeus_udc_command, }; +static struct platform_device *zeus_devices[] __initdata = { + &zeus_serial_device, + &zeus_mtd_devices[0], + &zeus_dm9k0_device, + &zeus_dm9k1_device, + &zeus_sram_device, + &zeus_leds_device, + &zeus_pcmcia_device, + &zeus_max6369_device, + &can_regulator_device, + &zeus_ohci_regulator_device, +}; + #ifdef CONFIG_PM static void zeus_power_off(void) { @@ -847,7 +854,7 @@ static void __init zeus_init(void) platform_add_devices(zeus_devices, ARRAY_SIZE(zeus_devices)); - pxa_set_ohci_info(&zeus_ohci_platform_data); + zeus_register_ohci(); if (zeus_setup_fb_gpios()) pr_err("Failed to setup fb gpios\n"); diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index a028be23433453..6aa22147cace9c 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -3,8 +3,6 @@ config ARCH_QCOM select ARCH_REQUIRE_GPIOLIB select ARM_GIC select CLKSRC_OF - select GENERIC_CLOCKEVENTS - select HAVE_SMP select QCOM_SCM if SMP help Support for Qualcomm's devicetree based systems. diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 1d5ee5c9a1dcd3..960b8dd78c4498 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -148,6 +148,21 @@ struct platform_device realview_cf_device = { }, }; +static struct resource realview_leds_resources[] = { + { + .start = REALVIEW_SYS_BASE + REALVIEW_SYS_LED_OFFSET, + .end = REALVIEW_SYS_BASE + REALVIEW_SYS_LED_OFFSET + 4, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device realview_leds_device = { + .name = "versatile-leds", + .id = -1, + .num_resources = ARRAY_SIZE(realview_leds_resources), + .resource = realview_leds_resources, +}; + static struct resource realview_i2c_resource = { .start = REALVIEW_I2C_BASE, .end = REALVIEW_I2C_BASE + SZ_4K - 1, diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h index 602ca5ec52c53a..13dc830ef469a3 100644 --- a/arch/arm/mach-realview/core.h +++ b/arch/arm/mach-realview/core.h @@ -37,6 +37,7 @@ struct machine_desc; extern struct platform_device realview_flash_device; extern struct platform_device realview_cf_device; +extern struct platform_device realview_leds_device; extern struct platform_device realview_i2c_device; extern struct mmci_platform_data realview_mmc0_plat_data; extern struct mmci_platform_data realview_mmc1_plat_data; diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index c85ddb2a0ad090..6bb070e8012876 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -452,6 +452,7 @@ static void __init realview_eb_init(void) realview_flash_register(&realview_eb_flash_resource, 1); platform_device_register(&realview_i2c_device); platform_device_register(&char_lcd_device); + platform_device_register(&realview_leds_device); eth_device_register(); realview_usb_register(realview_eb_isp1761_resources); diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c index c5eade76461be3..173f2c15de49ac 100644 --- a/arch/arm/mach-realview/realview_pb1176.c +++ b/arch/arm/mach-realview/realview_pb1176.c @@ -367,6 +367,7 @@ static void __init realview_pb1176_init(void) realview_usb_register(realview_pb1176_isp1761_resources); platform_device_register(&pmu_device); platform_device_register(&char_lcd_device); + platform_device_register(&realview_leds_device); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c index f4b0962578feb9..bde7e6b1fd44dd 100644 --- a/arch/arm/mach-realview/realview_pb11mp.c +++ b/arch/arm/mach-realview/realview_pb11mp.c @@ -347,6 +347,7 @@ static void __init realview_pb11mp_init(void) realview_eth_register(NULL, realview_pb11mp_smsc911x_resources); platform_device_register(&realview_i2c_device); platform_device_register(&realview_cf_device); + platform_device_register(&realview_leds_device); realview_usb_register(realview_pb11mp_isp1761_resources); platform_device_register(&pmu_device); diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c index 10a3e1d7689131..4e57a8599265b6 100644 --- a/arch/arm/mach-realview/realview_pba8.c +++ b/arch/arm/mach-realview/realview_pba8.c @@ -289,6 +289,7 @@ static void __init realview_pba8_init(void) realview_eth_register(NULL, realview_pba8_smsc911x_resources); platform_device_register(&realview_i2c_device); platform_device_register(&realview_cf_device); + platform_device_register(&realview_leds_device); realview_usb_register(realview_pba8_isp1761_resources); platform_device_register(&pmu_device); diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c index 9d75493e3f0cc1..72c96caebefa92 100644 --- a/arch/arm/mach-realview/realview_pbx.c +++ b/arch/arm/mach-realview/realview_pbx.c @@ -385,6 +385,7 @@ static void __init realview_pbx_init(void) realview_eth_register(NULL, realview_pbx_smsc911x_resources); platform_device_register(&realview_i2c_device); platform_device_register(&realview_cf_device); + platform_device_register(&realview_leds_device); realview_usb_register(realview_pbx_isp1761_resources); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig index 40cf50b9940cb1..4500802679e74b 100644 --- a/arch/arm/mach-s3c24xx/Kconfig +++ b/arch/arm/mach-s3c24xx/Kconfig @@ -18,6 +18,18 @@ config PLAT_S3C24XX help Base platform code for any Samsung S3C24XX device +config S3C2410_COMMON_CLK + bool + help + Build the s3c2410 clock driver based on the common clock framework. + +config S3C2410_COMMON_DCLK + bool + select REGMAP_MMIO + help + Temporary symbol to build the dclk driver based on the common clock + framework. + menu "SAMSUNG S3C24XX SoCs Support" comment "S3C24XX SoCs" @@ -25,9 +37,10 @@ comment "S3C24XX SoCs" config CPU_S3C2410 bool "SAMSUNG S3C2410" default y + select COMMON_CLK select CPU_ARM920T select CPU_LLSERIAL_S3C2410 - select S3C2410_CLOCK + select S3C2410_COMMON_CLK select S3C2410_DMA if S3C24XX_DMA select ARM_S3C2410_CPUFREQ if ARM_S3C24XX_CPUFREQ select S3C2410_PM if PM @@ -38,8 +51,10 @@ config CPU_S3C2410 config CPU_S3C2412 bool "SAMSUNG S3C2412" + select COMMON_CLK select CPU_ARM926T select CPU_LLSERIAL_S3C2440 + select S3C2412_COMMON_CLK select S3C2412_DMA if S3C24XX_DMA select S3C2412_PM if PM help @@ -47,20 +62,21 @@ config CPU_S3C2412 config CPU_S3C2416 bool "SAMSUNG S3C2416/S3C2450" + select COMMON_CLK select CPU_ARM926T select CPU_LLSERIAL_S3C2440 select S3C2416_PM if PM - select S3C2443_COMMON + select S3C2443_COMMON_CLK select S3C2443_DMA if S3C24XX_DMA - select SAMSUNG_CLKSRC help Support for the S3C2416 SoC from the S3C24XX line config CPU_S3C2440 bool "SAMSUNG S3C2440" + select COMMON_CLK select CPU_ARM920T select CPU_LLSERIAL_S3C2440 - select S3C2410_CLOCK + select S3C2410_COMMON_CLK select S3C2410_PM if PM select S3C2440_DMA if S3C24XX_DMA help @@ -68,9 +84,10 @@ config CPU_S3C2440 config CPU_S3C2442 bool "SAMSUNG S3C2442" + select COMMON_CLK select CPU_ARM920T select CPU_LLSERIAL_S3C2440 - select S3C2410_CLOCK + select S3C2410_COMMON_CLK select S3C2410_DMA if S3C24XX_DMA select S3C2410_PM if PM help @@ -83,27 +100,16 @@ config CPU_S3C244X config CPU_S3C2443 bool "SAMSUNG S3C2443" + select COMMON_CLK select CPU_ARM920T select CPU_LLSERIAL_S3C2440 - select S3C2443_COMMON + select S3C2443_COMMON_CLK select S3C2443_DMA if S3C24XX_DMA - select SAMSUNG_CLKSRC help Support for the S3C2443 SoC from the S3C24XX line # common code -config S3C2410_CLOCK - bool - help - Clock code for the S3C2410, and similar processors which - is currently includes the S3C2410, S3C2440, S3C2442. - -config S3C24XX_DCLK - bool - help - Clock code for supporting DCLK/CLKOUT on S3C24XX architectures - config S3C24XX_SMDK bool help @@ -259,7 +265,7 @@ config ARCH_BAST select ISA select MACH_BAST_IDE select S3C2410_IOTIMING if ARM_S3C2410_CPUFREQ - select S3C24XX_DCLK + select S3C2410_COMMON_DCLK if COMMON_CLK select S3C24XX_SIMTEC_NOR select S3C24XX_SIMTEC_PM if PM select S3C24XX_SIMTEC_USB @@ -340,7 +346,7 @@ config MACH_TCT_HAMMER config MACH_VR1000 bool "Thorcom VR1000" select MACH_BAST_IDE - select S3C24XX_DCLK + select S3C2410_COMMON_DCLK if COMMON_CLK select S3C24XX_SIMTEC_NOR select S3C24XX_SIMTEC_PM if PM select S3C24XX_SIMTEC_USB @@ -359,6 +365,11 @@ config S3C2412_PM_SLEEP if CPU_S3C2412 +config S3C2412_COMMON_CLK + bool + help + Build the s3c2412 clock driver based on the common clock framework. + config CPU_S3C2412_ONLY bool depends on !CPU_S3C2410 && !CPU_S3C2416 && !CPU_S3C2440 && \ @@ -520,7 +531,7 @@ config MACH_ANUBIS bool "Simtec Electronics ANUBIS" select HAVE_PATA_PLATFORM select S3C2440_XTAL_12000000 - select S3C24XX_DCLK + select S3C2410_COMMON_DCLK if COMMON_CLK select S3C24XX_SIMTEC_PM if PM select S3C_DEV_USB_HOST help @@ -560,7 +571,7 @@ config MACH_OSIRIS bool "Simtec IM2440D20 (OSIRIS) module" select S3C2410_IOTIMING if ARM_S3C2440_CPUFREQ select S3C2440_XTAL_12000000 - select S3C24XX_DCLK + select S3C2410_COMMON_DCLK if COMMON_CLK select S3C24XX_SIMTEC_PM if PM select S3C_DEV_NAND select S3C_DEV_USB_HOST @@ -631,7 +642,7 @@ config MACH_RX1950 select PM_H1940 if PM select S3C2410_IOTIMING if ARM_S3C2440_CPUFREQ select S3C2440_XTAL_16934400 - select S3C24XX_DCLK + select S3C24XX_COMMON_DCLK if COMMON_CLK select S3C24XX_PWM select S3C_DEV_NAND help @@ -641,11 +652,11 @@ endif # CPU_S3C2442 if CPU_S3C2443 || CPU_S3C2416 -config S3C2443_COMMON +config S3C2443_COMMON_CLK bool help - Common code for the S3C2443 and similar processors, which includes - the S3C2416 and S3C2450. + Temporary symbol to build the clock driver based on the common clock + framework. config S3C2443_DMA bool diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile index 7f54e5b954ca8c..2235d0d3b38dd9 100644 --- a/arch/arm/mach-s3c24xx/Makefile +++ b/arch/arm/mach-s3c24xx/Makefile @@ -21,22 +21,22 @@ obj-$(CONFIG_S3C2410_DMA) += dma-s3c2410.o obj-$(CONFIG_S3C2410_PLL) += pll-s3c2410.o obj-$(CONFIG_S3C2410_PM) += pm-s3c2410.o sleep-s3c2410.o -obj-$(CONFIG_CPU_S3C2412) += s3c2412.o clock-s3c2412.o +obj-$(CONFIG_CPU_S3C2412) += s3c2412.o obj-$(CONFIG_S3C2412_DMA) += dma-s3c2412.o obj-$(CONFIG_S3C2412_PM) += pm-s3c2412.o obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep-s3c2412.o -obj-$(CONFIG_CPU_S3C2416) += s3c2416.o clock-s3c2416.o +obj-$(CONFIG_CPU_S3C2416) += s3c2416.o obj-$(CONFIG_S3C2416_PM) += pm-s3c2416.o -obj-$(CONFIG_CPU_S3C2440) += s3c2440.o clock-s3c2440.o +obj-$(CONFIG_CPU_S3C2440) += s3c2440.o obj-$(CONFIG_CPU_S3C2442) += s3c2442.o -obj-$(CONFIG_CPU_S3C244X) += s3c244x.o clock-s3c244x.o +obj-$(CONFIG_CPU_S3C244X) += s3c244x.o obj-$(CONFIG_S3C2440_DMA) += dma-s3c2440.o obj-$(CONFIG_S3C2440_PLL_12000000) += pll-s3c2440-12000000.o obj-$(CONFIG_S3C2440_PLL_16934400) += pll-s3c2440-16934400.o -obj-$(CONFIG_CPU_S3C2443) += s3c2443.o clock-s3c2443.o +obj-$(CONFIG_CPU_S3C2443) += s3c2443.o # PM @@ -44,16 +44,13 @@ obj-$(CONFIG_PM) += pm.o irq-pm.o sleep.o # common code -obj-$(CONFIG_S3C24XX_DCLK) += clock-dclk.o obj-$(CONFIG_S3C24XX_DMA) += dma.o -obj-$(CONFIG_S3C2410_CLOCK) += clock-s3c2410.o obj-$(CONFIG_S3C2410_CPUFREQ_UTILS) += cpufreq-utils.o obj-$(CONFIG_S3C2410_IOTIMING) += iotiming-s3c2410.o obj-$(CONFIG_S3C2412_IOTIMING) += iotiming-s3c2412.o -obj-$(CONFIG_S3C2443_COMMON) += common-s3c2443.o obj-$(CONFIG_S3C2443_DMA) += dma-s3c2443.o # diff --git a/arch/arm/mach-s3c24xx/clock-dclk.c b/arch/arm/mach-s3c24xx/clock-dclk.c deleted file mode 100644 index 1edd9b2369c560..00000000000000 --- a/arch/arm/mach-s3c24xx/clock-dclk.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2004-2008 Simtec Electronics - * Ben Dooks - * http://armlinux.simtec.co.uk/ - * - * 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. - * - * S3C24XX - definitions for DCLK and CLKOUT registers - */ - -#include -#include -#include -#include - -#include -#include - -#include -#include - -/* clocks that could be registered by external code */ - -static int s3c24xx_dclk_enable(struct clk *clk, int enable) -{ - unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON); - - if (enable) - dclkcon |= clk->ctrlbit; - else - dclkcon &= ~clk->ctrlbit; - - __raw_writel(dclkcon, S3C24XX_DCLKCON); - - return 0; -} - -static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) -{ - unsigned long dclkcon; - unsigned int uclk; - - if (parent == &clk_upll) - uclk = 1; - else if (parent == &clk_p) - uclk = 0; - else - return -EINVAL; - - clk->parent = parent; - - dclkcon = __raw_readl(S3C24XX_DCLKCON); - - if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) { - if (uclk) - dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK; - else - dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK; - } else { - if (uclk) - dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK; - else - dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK; - } - - __raw_writel(dclkcon, S3C24XX_DCLKCON); - - return 0; -} -static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate) -{ - unsigned long div; - - if ((rate == 0) || !clk->parent) - return 0; - - div = clk_get_rate(clk->parent) / rate; - if (div < 2) - div = 2; - else if (div > 16) - div = 16; - - return div; -} - -static unsigned long s3c24xx_round_dclk_rate(struct clk *clk, - unsigned long rate) -{ - unsigned long div = s3c24xx_calc_div(clk, rate); - - if (div == 0) - return 0; - - return clk_get_rate(clk->parent) / div; -} - -static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate) -{ - unsigned long mask, data, div = s3c24xx_calc_div(clk, rate); - - if (div == 0) - return -EINVAL; - - if (clk == &s3c24xx_dclk0) { - mask = S3C2410_DCLKCON_DCLK0_DIV_MASK | - S3C2410_DCLKCON_DCLK0_CMP_MASK; - data = S3C2410_DCLKCON_DCLK0_DIV(div) | - S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2); - } else if (clk == &s3c24xx_dclk1) { - mask = S3C2410_DCLKCON_DCLK1_DIV_MASK | - S3C2410_DCLKCON_DCLK1_CMP_MASK; - data = S3C2410_DCLKCON_DCLK1_DIV(div) | - S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2); - } else - return -EINVAL; - - clk->rate = clk_get_rate(clk->parent) / div; - __raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data), - S3C24XX_DCLKCON); - return clk->rate; -} -static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent) -{ - unsigned long mask; - unsigned long source; - - /* calculate the MISCCR setting for the clock */ - - if (parent == &clk_mpll) - source = S3C2410_MISCCR_CLK0_MPLL; - else if (parent == &clk_upll) - source = S3C2410_MISCCR_CLK0_UPLL; - else if (parent == &clk_f) - source = S3C2410_MISCCR_CLK0_FCLK; - else if (parent == &clk_h) - source = S3C2410_MISCCR_CLK0_HCLK; - else if (parent == &clk_p) - source = S3C2410_MISCCR_CLK0_PCLK; - else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0) - source = S3C2410_MISCCR_CLK0_DCLK0; - else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1) - source = S3C2410_MISCCR_CLK0_DCLK0; - else - return -EINVAL; - - clk->parent = parent; - - if (clk == &s3c24xx_clkout0) - mask = S3C2410_MISCCR_CLK0_MASK; - else { - source <<= 4; - mask = S3C2410_MISCCR_CLK1_MASK; - } - - s3c2410_modify_misccr(mask, source); - return 0; -} - -/* external clock definitions */ - -static struct clk_ops dclk_ops = { - .set_parent = s3c24xx_dclk_setparent, - .set_rate = s3c24xx_set_dclk_rate, - .round_rate = s3c24xx_round_dclk_rate, -}; - -struct clk s3c24xx_dclk0 = { - .name = "dclk0", - .ctrlbit = S3C2410_DCLKCON_DCLK0EN, - .enable = s3c24xx_dclk_enable, - .ops = &dclk_ops, -}; - -struct clk s3c24xx_dclk1 = { - .name = "dclk1", - .ctrlbit = S3C2410_DCLKCON_DCLK1EN, - .enable = s3c24xx_dclk_enable, - .ops = &dclk_ops, -}; - -static struct clk_ops clkout_ops = { - .set_parent = s3c24xx_clkout_setparent, -}; - -struct clk s3c24xx_clkout0 = { - .name = "clkout0", - .ops = &clkout_ops, -}; - -struct clk s3c24xx_clkout1 = { - .name = "clkout1", - .ops = &clkout_ops, -}; diff --git a/arch/arm/mach-s3c24xx/clock-s3c2410.c b/arch/arm/mach-s3c24xx/clock-s3c2410.c deleted file mode 100644 index d1afcf9252d18a..00000000000000 --- a/arch/arm/mach-s3c24xx/clock-s3c2410.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2006 Simtec Electronics - * Ben Dooks - * - * S3C2410,S3C2440,S3C2442 Clock control support - * - * 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 - -int s3c2410_clkcon_enable(struct clk *clk, int enable) -{ - unsigned int clocks = clk->ctrlbit; - unsigned long clkcon; - - clkcon = __raw_readl(S3C2410_CLKCON); - - if (enable) - clkcon |= clocks; - else - clkcon &= ~clocks; - - /* ensure none of the special function bits set */ - clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER); - - __raw_writel(clkcon, S3C2410_CLKCON); - - return 0; -} - -static int s3c2410_upll_enable(struct clk *clk, int enable) -{ - unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); - unsigned long orig = clkslow; - - if (enable) - clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF; - else - clkslow |= S3C2410_CLKSLOW_UCLK_OFF; - - __raw_writel(clkslow, S3C2410_CLKSLOW); - - /* if we started the UPLL, then allow to settle */ - - if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF)) - udelay(200); - - return 0; -} - -/* standard clock definitions */ - -static struct clk init_clocks_off[] = { - { - .name = "nand", - .parent = &clk_h, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_NAND, - }, { - .name = "sdi", - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_SDI, - }, { - .name = "adc", - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_ADC, - }, { - .name = "i2c", - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_IIC, - }, { - .name = "iis", - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_IIS, - }, { - .name = "spi", - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_SPI, - } -}; - -static struct clk clk_lcd = { - .name = "lcd", - .parent = &clk_h, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_LCDC, -}; - -static struct clk clk_gpio = { - .name = "gpio", - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_GPIO, -}; - -static struct clk clk_usb_host = { - .name = "usb-host", - .parent = &clk_h, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_USBH, -}; - -static struct clk clk_usb_device = { - .name = "usb-device", - .parent = &clk_h, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_USBD, -}; - -static struct clk clk_timers = { - .name = "timers", - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_PWMT, -}; - -struct clk s3c24xx_clk_uart0 = { - .name = "uart", - .devname = "s3c2410-uart.0", - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_UART0, -}; - -struct clk s3c24xx_clk_uart1 = { - .name = "uart", - .devname = "s3c2410-uart.1", - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_UART1, -}; - -struct clk s3c24xx_clk_uart2 = { - .name = "uart", - .devname = "s3c2410-uart.2", - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_UART2, -}; - -static struct clk clk_rtc = { - .name = "rtc", - .parent = &clk_p, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2410_CLKCON_RTC, -}; - -static struct clk clk_watchdog = { - .name = "watchdog", - .parent = &clk_p, - .ctrlbit = 0, -}; - -static struct clk clk_usb_bus_host = { - .name = "usb-bus-host", - .parent = &clk_usb_bus, -}; - -static struct clk clk_usb_bus_gadget = { - .name = "usb-bus-gadget", - .parent = &clk_usb_bus, -}; - -static struct clk *init_clocks[] = { - &clk_lcd, - &clk_gpio, - &clk_usb_host, - &clk_usb_device, - &clk_timers, - &s3c24xx_clk_uart0, - &s3c24xx_clk_uart1, - &s3c24xx_clk_uart2, - &clk_rtc, - &clk_watchdog, - &clk_usb_bus_host, - &clk_usb_bus_gadget, -}; - -/* s3c2410_baseclk_add() - * - * Add all the clocks used by the s3c2410 or compatible CPUs - * such as the S3C2440 and S3C2442. - * - * We cannot use a system device as we are needed before any - * of the init-calls that initialise the devices are actually - * done. -*/ - -int __init s3c2410_baseclk_add(void) -{ - unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); - unsigned long clkcon = __raw_readl(S3C2410_CLKCON); - struct clk *xtal; - int ret; - int ptr; - - clk_upll.enable = s3c2410_upll_enable; - - if (s3c24xx_register_clock(&clk_usb_bus) < 0) - printk(KERN_ERR "failed to register usb bus clock\n"); - - /* register clocks from clock array */ - - for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++) { - struct clk *clkp = init_clocks[ptr]; - - /* ensure that we note the clock state */ - - clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0; - - ret = s3c24xx_register_clock(clkp); - if (ret < 0) { - printk(KERN_ERR "Failed to register clock %s (%d)\n", - clkp->name, ret); - } - } - - /* We must be careful disabling the clocks we are not intending to - * be using at boot time, as subsystems such as the LCD which do - * their own DMA requests to the bus can cause the system to lockup - * if they where in the middle of requesting bus access. - * - * Disabling the LCD clock if the LCD is active is very dangerous, - * and therefore the bootloader should be careful to not enable - * the LCD clock if it is not needed. - */ - - /* install (and disable) the clocks we do not need immediately */ - - s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); - s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); - - /* show the clock-slow value */ - - xtal = clk_get(NULL, "xtal"); - - printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n", - print_mhz(clk_get_rate(xtal) / - ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))), - (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast", - (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on", - (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on"); - - return 0; -} diff --git a/arch/arm/mach-s3c24xx/clock-s3c2412.c b/arch/arm/mach-s3c24xx/clock-s3c2412.c deleted file mode 100644 index 192a5b2550b04a..00000000000000 --- a/arch/arm/mach-s3c24xx/clock-s3c2412.c +++ /dev/null @@ -1,760 +0,0 @@ -/* linux/arch/arm/mach-s3c2412/clock.c - * - * Copyright (c) 2006 Simtec Electronics - * Ben Dooks - * - * S3C2412,S3C2413 Clock control support - * - * 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 - -/* We currently have to assume that the system is running - * from the XTPll input, and that all ***REFCLKs are being - * fed from it, as we cannot read the state of OM[4] from - * software. - * - * It would be possible for each board initialisation to - * set the correct muxing at initialisation -*/ - -static int s3c2412_clkcon_enable(struct clk *clk, int enable) -{ - unsigned int clocks = clk->ctrlbit; - unsigned long clkcon; - - clkcon = __raw_readl(S3C2410_CLKCON); - - if (enable) - clkcon |= clocks; - else - clkcon &= ~clocks; - - __raw_writel(clkcon, S3C2410_CLKCON); - - return 0; -} - -static int s3c2412_upll_enable(struct clk *clk, int enable) -{ - unsigned long upllcon = __raw_readl(S3C2410_UPLLCON); - unsigned long orig = upllcon; - - if (!enable) - upllcon |= S3C2412_PLLCON_OFF; - else - upllcon &= ~S3C2412_PLLCON_OFF; - - __raw_writel(upllcon, S3C2410_UPLLCON); - - /* allow ~150uS for the PLL to settle and lock */ - - if (enable && (orig & S3C2412_PLLCON_OFF)) - udelay(150); - - return 0; -} - -/* clock selections */ - -static struct clk clk_erefclk = { - .name = "erefclk", -}; - -static struct clk clk_urefclk = { - .name = "urefclk", -}; - -static int s3c2412_setparent_usysclk(struct clk *clk, struct clk *parent) -{ - unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); - - if (parent == &clk_urefclk) - clksrc &= ~S3C2412_CLKSRC_USYSCLK_UPLL; - else if (parent == &clk_upll) - clksrc |= S3C2412_CLKSRC_USYSCLK_UPLL; - else - return -EINVAL; - - clk->parent = parent; - - __raw_writel(clksrc, S3C2412_CLKSRC); - return 0; -} - -static struct clk clk_usysclk = { - .name = "usysclk", - .parent = &clk_xtal, - .ops = &(struct clk_ops) { - .set_parent = s3c2412_setparent_usysclk, - }, -}; - -static struct clk clk_mrefclk = { - .name = "mrefclk", - .parent = &clk_xtal, -}; - -static struct clk clk_mdivclk = { - .name = "mdivclk", - .parent = &clk_xtal, -}; - -static int s3c2412_setparent_usbsrc(struct clk *clk, struct clk *parent) -{ - unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); - - if (parent == &clk_usysclk) - clksrc &= ~S3C2412_CLKSRC_USBCLK_HCLK; - else if (parent == &clk_h) - clksrc |= S3C2412_CLKSRC_USBCLK_HCLK; - else - return -EINVAL; - - clk->parent = parent; - - __raw_writel(clksrc, S3C2412_CLKSRC); - return 0; -} - -static unsigned long s3c2412_roundrate_usbsrc(struct clk *clk, - unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - int div; - - if (rate > parent_rate) - return parent_rate; - - div = parent_rate / rate; - if (div > 2) - div = 2; - - return parent_rate / div; -} - -static unsigned long s3c2412_getrate_usbsrc(struct clk *clk) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - unsigned long div = __raw_readl(S3C2410_CLKDIVN); - - return parent_rate / ((div & S3C2412_CLKDIVN_USB48DIV) ? 2 : 1); -} - -static int s3c2412_setrate_usbsrc(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); - - rate = s3c2412_roundrate_usbsrc(clk, rate); - - if ((parent_rate / rate) == 2) - clkdivn |= S3C2412_CLKDIVN_USB48DIV; - else - clkdivn &= ~S3C2412_CLKDIVN_USB48DIV; - - __raw_writel(clkdivn, S3C2410_CLKDIVN); - return 0; -} - -static struct clk clk_usbsrc = { - .name = "usbsrc", - .ops = &(struct clk_ops) { - .get_rate = s3c2412_getrate_usbsrc, - .set_rate = s3c2412_setrate_usbsrc, - .round_rate = s3c2412_roundrate_usbsrc, - .set_parent = s3c2412_setparent_usbsrc, - }, -}; - -static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent) -{ - unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); - - if (parent == &clk_mdivclk) - clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL; - else if (parent == &clk_mpll) - clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL; - else - return -EINVAL; - - clk->parent = parent; - - __raw_writel(clksrc, S3C2412_CLKSRC); - return 0; -} - -static struct clk clk_msysclk = { - .name = "msysclk", - .ops = &(struct clk_ops) { - .set_parent = s3c2412_setparent_msysclk, - }, -}; - -static int s3c2412_setparent_armclk(struct clk *clk, struct clk *parent) -{ - unsigned long flags; - unsigned long clkdiv; - unsigned long dvs; - - /* Note, we current equate fclk andf msysclk for S3C2412 */ - - if (parent == &clk_msysclk || parent == &clk_f) - dvs = 0; - else if (parent == &clk_h) - dvs = S3C2412_CLKDIVN_DVSEN; - else - return -EINVAL; - - clk->parent = parent; - - /* update this under irq lockdown, clkdivn is not protected - * by the clock system. */ - - local_irq_save(flags); - - clkdiv = __raw_readl(S3C2410_CLKDIVN); - clkdiv &= ~S3C2412_CLKDIVN_DVSEN; - clkdiv |= dvs; - __raw_writel(clkdiv, S3C2410_CLKDIVN); - - local_irq_restore(flags); - - return 0; -} - -static struct clk clk_armclk = { - .name = "armclk", - .parent = &clk_msysclk, - .ops = &(struct clk_ops) { - .set_parent = s3c2412_setparent_armclk, - }, -}; - -/* these next clocks have an divider immediately after them, - * so we can register them with their divider and leave out the - * intermediate clock stage -*/ -static unsigned long s3c2412_roundrate_clksrc(struct clk *clk, - unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - int div; - - if (rate > parent_rate) - return parent_rate; - - /* note, we remove the +/- 1 calculations as they cancel out */ - - div = (rate / parent_rate); - - if (div < 1) - div = 1; - else if (div > 16) - div = 16; - - return parent_rate / div; -} - -static int s3c2412_setparent_uart(struct clk *clk, struct clk *parent) -{ - unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); - - if (parent == &clk_erefclk) - clksrc &= ~S3C2412_CLKSRC_UARTCLK_MPLL; - else if (parent == &clk_mpll) - clksrc |= S3C2412_CLKSRC_UARTCLK_MPLL; - else - return -EINVAL; - - clk->parent = parent; - - __raw_writel(clksrc, S3C2412_CLKSRC); - return 0; -} - -static unsigned long s3c2412_getrate_uart(struct clk *clk) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - unsigned long div = __raw_readl(S3C2410_CLKDIVN); - - div &= S3C2412_CLKDIVN_UARTDIV_MASK; - div >>= S3C2412_CLKDIVN_UARTDIV_SHIFT; - - return parent_rate / (div + 1); -} - -static int s3c2412_setrate_uart(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); - - rate = s3c2412_roundrate_clksrc(clk, rate); - - clkdivn &= ~S3C2412_CLKDIVN_UARTDIV_MASK; - clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_UARTDIV_SHIFT; - - __raw_writel(clkdivn, S3C2410_CLKDIVN); - return 0; -} - -static struct clk clk_uart = { - .name = "uartclk", - .ops = &(struct clk_ops) { - .get_rate = s3c2412_getrate_uart, - .set_rate = s3c2412_setrate_uart, - .set_parent = s3c2412_setparent_uart, - .round_rate = s3c2412_roundrate_clksrc, - }, -}; - -static int s3c2412_setparent_i2s(struct clk *clk, struct clk *parent) -{ - unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); - - if (parent == &clk_erefclk) - clksrc &= ~S3C2412_CLKSRC_I2SCLK_MPLL; - else if (parent == &clk_mpll) - clksrc |= S3C2412_CLKSRC_I2SCLK_MPLL; - else - return -EINVAL; - - clk->parent = parent; - - __raw_writel(clksrc, S3C2412_CLKSRC); - return 0; -} - -static unsigned long s3c2412_getrate_i2s(struct clk *clk) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - unsigned long div = __raw_readl(S3C2410_CLKDIVN); - - div &= S3C2412_CLKDIVN_I2SDIV_MASK; - div >>= S3C2412_CLKDIVN_I2SDIV_SHIFT; - - return parent_rate / (div + 1); -} - -static int s3c2412_setrate_i2s(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); - - rate = s3c2412_roundrate_clksrc(clk, rate); - - clkdivn &= ~S3C2412_CLKDIVN_I2SDIV_MASK; - clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_I2SDIV_SHIFT; - - __raw_writel(clkdivn, S3C2410_CLKDIVN); - return 0; -} - -static struct clk clk_i2s = { - .name = "i2sclk", - .ops = &(struct clk_ops) { - .get_rate = s3c2412_getrate_i2s, - .set_rate = s3c2412_setrate_i2s, - .set_parent = s3c2412_setparent_i2s, - .round_rate = s3c2412_roundrate_clksrc, - }, -}; - -static int s3c2412_setparent_cam(struct clk *clk, struct clk *parent) -{ - unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); - - if (parent == &clk_usysclk) - clksrc &= ~S3C2412_CLKSRC_CAMCLK_HCLK; - else if (parent == &clk_h) - clksrc |= S3C2412_CLKSRC_CAMCLK_HCLK; - else - return -EINVAL; - - clk->parent = parent; - - __raw_writel(clksrc, S3C2412_CLKSRC); - return 0; -} -static unsigned long s3c2412_getrate_cam(struct clk *clk) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - unsigned long div = __raw_readl(S3C2410_CLKDIVN); - - div &= S3C2412_CLKDIVN_CAMDIV_MASK; - div >>= S3C2412_CLKDIVN_CAMDIV_SHIFT; - - return parent_rate / (div + 1); -} - -static int s3c2412_setrate_cam(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); - - rate = s3c2412_roundrate_clksrc(clk, rate); - - clkdivn &= ~S3C2412_CLKDIVN_CAMDIV_MASK; - clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_CAMDIV_SHIFT; - - __raw_writel(clkdivn, S3C2410_CLKDIVN); - return 0; -} - -static struct clk clk_cam = { - .name = "camif-upll", /* same as 2440 name */ - .ops = &(struct clk_ops) { - .get_rate = s3c2412_getrate_cam, - .set_rate = s3c2412_setrate_cam, - .set_parent = s3c2412_setparent_cam, - .round_rate = s3c2412_roundrate_clksrc, - }, -}; - -/* standard clock definitions */ - -static struct clk init_clocks_disable[] = { - { - .name = "nand", - .parent = &clk_h, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_NAND, - }, { - .name = "sdi", - .parent = &clk_p, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_SDI, - }, { - .name = "adc", - .parent = &clk_p, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_ADC, - }, { - .name = "i2c", - .parent = &clk_p, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_IIC, - }, { - .name = "iis", - .parent = &clk_p, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_IIS, - }, { - .name = "spi", - .parent = &clk_p, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_SPI, - } -}; - -static struct clk init_clocks[] = { - { - .name = "dma.0", - .parent = &clk_h, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_DMA0, - }, { - .name = "dma.1", - .parent = &clk_h, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_DMA1, - }, { - .name = "dma.2", - .parent = &clk_h, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_DMA2, - }, { - .name = "dma.3", - .parent = &clk_h, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_DMA3, - }, { - .name = "lcd", - .parent = &clk_h, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_LCDC, - }, { - .name = "gpio", - .parent = &clk_p, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_GPIO, - }, { - .name = "usb-host", - .parent = &clk_h, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_USBH, - }, { - .name = "usb-device", - .parent = &clk_h, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_USBD, - }, { - .name = "timers", - .parent = &clk_p, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_PWMT, - }, { - .name = "uart", - .devname = "s3c2412-uart.0", - .parent = &clk_p, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_UART0, - }, { - .name = "uart", - .devname = "s3c2412-uart.1", - .parent = &clk_p, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_UART1, - }, { - .name = "uart", - .devname = "s3c2412-uart.2", - .parent = &clk_p, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_UART2, - }, { - .name = "rtc", - .parent = &clk_p, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_RTC, - }, { - .name = "watchdog", - .parent = &clk_p, - .ctrlbit = 0, - }, { - .name = "usb-bus-gadget", - .parent = &clk_usb_bus, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_USB_DEV48, - }, { - .name = "usb-bus-host", - .parent = &clk_usb_bus, - .enable = s3c2412_clkcon_enable, - .ctrlbit = S3C2412_CLKCON_USB_HOST48, - } -}; - -/* clocks to add where we need to check their parentage */ - -struct clk_init { - struct clk *clk; - unsigned int bit; - struct clk *src_0; - struct clk *src_1; -}; - -static struct clk_init clks_src[] __initdata = { - { - .clk = &clk_usysclk, - .bit = S3C2412_CLKSRC_USBCLK_HCLK, - .src_0 = &clk_urefclk, - .src_1 = &clk_upll, - }, { - .clk = &clk_i2s, - .bit = S3C2412_CLKSRC_I2SCLK_MPLL, - .src_0 = &clk_erefclk, - .src_1 = &clk_mpll, - }, { - .clk = &clk_cam, - .bit = S3C2412_CLKSRC_CAMCLK_HCLK, - .src_0 = &clk_usysclk, - .src_1 = &clk_h, - }, { - .clk = &clk_msysclk, - .bit = S3C2412_CLKSRC_MSYSCLK_MPLL, - .src_0 = &clk_mdivclk, - .src_1 = &clk_mpll, - }, { - .clk = &clk_uart, - .bit = S3C2412_CLKSRC_UARTCLK_MPLL, - .src_0 = &clk_erefclk, - .src_1 = &clk_mpll, - }, { - .clk = &clk_usbsrc, - .bit = S3C2412_CLKSRC_USBCLK_HCLK, - .src_0 = &clk_usysclk, - .src_1 = &clk_h, - /* here we assume OM[4] select xtal */ - }, { - .clk = &clk_erefclk, - .bit = S3C2412_CLKSRC_EREFCLK_EXTCLK, - .src_0 = &clk_xtal, - .src_1 = &clk_ext, - }, { - .clk = &clk_urefclk, - .bit = S3C2412_CLKSRC_UREFCLK_EXTCLK, - .src_0 = &clk_xtal, - .src_1 = &clk_ext, - }, -}; - -/* s3c2412_clk_initparents - * - * Initialise the parents for the clocks that we get at start-time -*/ - -static void __init s3c2412_clk_initparents(void) -{ - unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); - struct clk_init *cip = clks_src; - struct clk *src; - int ptr; - int ret; - - for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++, cip++) { - ret = s3c24xx_register_clock(cip->clk); - if (ret < 0) { - printk(KERN_ERR "Failed to register clock %s (%d)\n", - cip->clk->name, ret); - } - - src = (clksrc & cip->bit) ? cip->src_1 : cip->src_0; - - printk(KERN_INFO "%s: parent %s\n", cip->clk->name, src->name); - clk_set_parent(cip->clk, src); - } -} - -/* clocks to add straight away */ - -static struct clk *clks[] __initdata = { - &clk_ext, - &clk_usb_bus, - &clk_mrefclk, - &clk_armclk, -}; - -static struct clk_lookup s3c2412_clk_lookup[] = { - CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk), - CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p), - CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_usysclk), -}; - -int __init s3c2412_baseclk_add(void) -{ - unsigned long clkcon = __raw_readl(S3C2410_CLKCON); - unsigned int dvs; - struct clk *clkp; - int ret; - int ptr; - - clk_upll.enable = s3c2412_upll_enable; - clk_usb_bus.parent = &clk_usbsrc; - clk_usb_bus.rate = 0x0; - - clk_f.parent = &clk_msysclk; - - s3c2412_clk_initparents(); - - for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { - clkp = clks[ptr]; - - ret = s3c24xx_register_clock(clkp); - if (ret < 0) { - printk(KERN_ERR "Failed to register clock %s (%d)\n", - clkp->name, ret); - } - } - - /* set the dvs state according to what we got at boot time */ - - dvs = __raw_readl(S3C2410_CLKDIVN) & S3C2412_CLKDIVN_DVSEN; - - if (dvs) - clk_armclk.parent = &clk_h; - - printk(KERN_INFO "S3C2412: DVS is %s\n", dvs ? "on" : "off"); - - /* ensure usb bus clock is within correct rate of 48MHz */ - - if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) { - printk(KERN_INFO "Warning: USB bus clock not at 48MHz\n"); - - /* for the moment, let's use the UPLL, and see if we can - * get 48MHz */ - - clk_set_parent(&clk_usysclk, &clk_upll); - clk_set_parent(&clk_usbsrc, &clk_usysclk); - clk_set_rate(&clk_usbsrc, 48*1000*1000); - } - - printk("S3C2412: upll %s, %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", - (__raw_readl(S3C2410_UPLLCON) & S3C2412_PLLCON_OFF) ? "off":"on", - print_mhz(clk_get_rate(&clk_upll)), - print_mhz(clk_get_rate(&clk_usb_bus))); - - /* register clocks from clock array */ - - clkp = init_clocks; - for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { - /* ensure that we note the clock state */ - - clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0; - - ret = s3c24xx_register_clock(clkp); - if (ret < 0) { - printk(KERN_ERR "Failed to register clock %s (%d)\n", - clkp->name, ret); - } - } - - /* We must be careful disabling the clocks we are not intending to - * be using at boot time, as subsystems such as the LCD which do - * their own DMA requests to the bus can cause the system to lockup - * if they where in the middle of requesting bus access. - * - * Disabling the LCD clock if the LCD is active is very dangerous, - * and therefore the bootloader should be careful to not enable - * the LCD clock if it is not needed. - */ - - /* install (and disable) the clocks we do not need immediately */ - - clkp = init_clocks_disable; - for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { - - ret = s3c24xx_register_clock(clkp); - if (ret < 0) { - printk(KERN_ERR "Failed to register clock %s (%d)\n", - clkp->name, ret); - } - - s3c2412_clkcon_enable(clkp, 0); - } - - clkdev_add_table(s3c2412_clk_lookup, ARRAY_SIZE(s3c2412_clk_lookup)); - return 0; -} diff --git a/arch/arm/mach-s3c24xx/clock-s3c2416.c b/arch/arm/mach-s3c24xx/clock-s3c2416.c deleted file mode 100644 index d421a72920a572..00000000000000 --- a/arch/arm/mach-s3c24xx/clock-s3c2416.c +++ /dev/null @@ -1,171 +0,0 @@ -/* linux/arch/arm/mach-s3c2416/clock.c - * - * Copyright (c) 2010 Simtec Electronics - * Copyright (c) 2010 Ben Dooks - * - * S3C2416 Clock control support - * - * 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 -#include - -/* armdiv - * - * this clock is sourced from msysclk and can have a number of - * divider values applied to it to then be fed into armclk. - * The real clock definition is done in s3c2443-clock.c, - * only the armdiv divisor table must be defined here. -*/ - -static unsigned int armdiv[8] = { - [0] = 1, - [1] = 2, - [2] = 3, - [3] = 4, - [5] = 6, - [7] = 8, -}; - -static struct clksrc_clk hsspi_eplldiv = { - .clk = { - .name = "hsspi-eplldiv", - .parent = &clk_esysclk.clk, - .ctrlbit = (1 << 14), - .enable = s3c2443_clkcon_enable_s, - }, - .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 24 }, -}; - -static struct clk *hsspi_sources[] = { - [0] = &hsspi_eplldiv.clk, - [1] = NULL, /* to fix */ -}; - -static struct clksrc_clk hsspi_mux = { - .clk = { - .name = "hsspi-if", - }, - .sources = &(struct clksrc_sources) { - .sources = hsspi_sources, - .nr_sources = ARRAY_SIZE(hsspi_sources), - }, - .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 18 }, -}; - -static struct clksrc_clk hsmmc_div[] = { - [0] = { - .clk = { - .name = "hsmmc-div", - .devname = "s3c-sdhci.0", - .parent = &clk_esysclk.clk, - }, - .reg_div = { .reg = S3C2416_CLKDIV2, .size = 2, .shift = 6 }, - }, - [1] = { - .clk = { - .name = "hsmmc-div", - .devname = "s3c-sdhci.1", - .parent = &clk_esysclk.clk, - }, - .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 }, - }, -}; - -static struct clksrc_clk hsmmc_mux0 = { - .clk = { - .name = "hsmmc-if", - .devname = "s3c-sdhci.0", - .ctrlbit = (1 << 6), - .enable = s3c2443_clkcon_enable_s, - }, - .sources = &(struct clksrc_sources) { - .nr_sources = 2, - .sources = (struct clk * []) { - [0] = &hsmmc_div[0].clk, - [1] = NULL, /* to fix */ - }, - }, - .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 16 }, -}; - -static struct clksrc_clk hsmmc_mux1 = { - .clk = { - .name = "hsmmc-if", - .devname = "s3c-sdhci.1", - .ctrlbit = (1 << 12), - .enable = s3c2443_clkcon_enable_s, - }, - .sources = &(struct clksrc_sources) { - .nr_sources = 2, - .sources = (struct clk * []) { - [0] = &hsmmc_div[1].clk, - [1] = NULL, /* to fix */ - }, - }, - .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 17 }, -}; - -static struct clk hsmmc0_clk = { - .name = "hsmmc", - .devname = "s3c-sdhci.0", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2416_HCLKCON_HSMMC0, -}; - -static struct clksrc_clk *clksrcs[] __initdata = { - &hsspi_eplldiv, - &hsspi_mux, - &hsmmc_div[0], - &hsmmc_div[1], - &hsmmc_mux0, - &hsmmc_mux1, -}; - -static struct clk_lookup s3c2416_clk_lookup[] = { - CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &hsmmc0_clk), - CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &hsmmc_mux0.clk), - CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &hsmmc_mux1.clk), - /* s3c2443-spi.0 is used on s3c2416 and s3c2450 as well */ - CLKDEV_INIT("s3c2443-spi.0", "spi_busclk2", &hsspi_mux.clk), -}; - -void __init s3c2416_init_clocks(int xtal) -{ - u32 epllcon = __raw_readl(S3C2443_EPLLCON); - u32 epllcon1 = __raw_readl(S3C2443_EPLLCON+4); - int ptr; - - /* s3c2416 EPLL compatible with s3c64xx */ - clk_epll.rate = s3c_get_pll6553x(xtal, epllcon, epllcon1); - - clk_epll.parent = &clk_epllref.clk; - - s3c2443_common_init_clocks(xtal, s3c2416_get_pll, - armdiv, ARRAY_SIZE(armdiv), - S3C2416_CLKDIV0_ARMDIV_MASK); - - for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) - s3c_register_clksrc(clksrcs[ptr], 1); - - s3c24xx_register_clock(&hsmmc0_clk); - clkdev_add_table(s3c2416_clk_lookup, ARRAY_SIZE(s3c2416_clk_lookup)); - -} diff --git a/arch/arm/mach-s3c24xx/clock-s3c2440.c b/arch/arm/mach-s3c24xx/clock-s3c2440.c deleted file mode 100644 index 5527226fd61f30..00000000000000 --- a/arch/arm/mach-s3c24xx/clock-s3c2440.c +++ /dev/null @@ -1,217 +0,0 @@ -/* linux/arch/arm/mach-s3c2440/clock.c - * - * Copyright (c) 2004-2005 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * S3C2440 Clock support - * - * 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 - -/* S3C2440 extended clock support */ - -static unsigned long s3c2440_camif_upll_round(struct clk *clk, - unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - int div; - - if (rate > parent_rate) - return parent_rate; - - /* note, we remove the +/- 1 calculations for the divisor */ - - div = (parent_rate / rate) / 2; - - if (div < 1) - div = 1; - else if (div > 16) - div = 16; - - return parent_rate / (div * 2); -} - -static int s3c2440_camif_upll_setrate(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN); - - rate = s3c2440_camif_upll_round(clk, rate); - - camdivn &= ~(S3C2440_CAMDIVN_CAMCLK_SEL | S3C2440_CAMDIVN_CAMCLK_MASK); - - if (rate != parent_rate) { - camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL; - camdivn |= (((parent_rate / rate) / 2) - 1); - } - - __raw_writel(camdivn, S3C2440_CAMDIVN); - - return 0; -} - -static unsigned long s3c2440_camif_upll_getrate(struct clk *clk) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN); - - if (!(camdivn & S3C2440_CAMDIVN_CAMCLK_SEL)) - return parent_rate; - - camdivn &= S3C2440_CAMDIVN_CAMCLK_MASK; - - return parent_rate / (camdivn + 1) / 2; -} - -/* Extra S3C2440 clocks */ - -static struct clk s3c2440_clk_cam = { - .name = "camif", - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2440_CLKCON_CAMERA, -}; - -static struct clk s3c2440_clk_cam_upll = { - .name = "camif-upll", - .ops = &(struct clk_ops) { - .set_rate = s3c2440_camif_upll_setrate, - .get_rate = s3c2440_camif_upll_getrate, - .round_rate = s3c2440_camif_upll_round, - }, -}; - -static struct clk s3c2440_clk_ac97 = { - .name = "ac97", - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2440_CLKCON_AC97, -}; - -#define S3C24XX_VA_UART0 (S3C_VA_UART) -#define S3C24XX_VA_UART1 (S3C_VA_UART + 0x4000 ) -#define S3C24XX_VA_UART2 (S3C_VA_UART + 0x8000 ) -#define S3C24XX_VA_UART3 (S3C_VA_UART + 0xC000 ) - -static unsigned long s3c2440_fclk_n_getrate(struct clk *clk) -{ - unsigned long ucon0, ucon1, ucon2, divisor; - - /* the fun of calculating the uart divisors on the s3c2440 */ - ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON); - ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON); - ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON); - - ucon0 &= S3C2440_UCON0_DIVMASK; - ucon1 &= S3C2440_UCON1_DIVMASK; - ucon2 &= S3C2440_UCON2_DIVMASK; - - if (ucon0 != 0) - divisor = (ucon0 >> S3C2440_UCON_DIVSHIFT) + 6; - else if (ucon1 != 0) - divisor = (ucon1 >> S3C2440_UCON_DIVSHIFT) + 21; - else if (ucon2 != 0) - divisor = (ucon2 >> S3C2440_UCON_DIVSHIFT) + 36; - else - /* manual calims 44, seems to be 9 */ - divisor = 9; - - return clk_get_rate(clk->parent) / divisor; -} - -static struct clk s3c2440_clk_fclk_n = { - .name = "fclk_n", - .parent = &clk_f, - .ops = &(struct clk_ops) { - .get_rate = s3c2440_fclk_n_getrate, - }, -}; - -static struct clk_lookup s3c2440_clk_lookup[] = { - CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk), - CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p), - CLKDEV_INIT(NULL, "clk_uart_baud3", &s3c2440_clk_fclk_n), - CLKDEV_INIT("s3c2440-uart.0", "uart", &s3c24xx_clk_uart0), - CLKDEV_INIT("s3c2440-uart.1", "uart", &s3c24xx_clk_uart1), - CLKDEV_INIT("s3c2440-uart.2", "uart", &s3c24xx_clk_uart2), - CLKDEV_INIT("s3c2440-camif", "camera", &s3c2440_clk_cam_upll), -}; - -static int __init_refok s3c2440_clk_add(struct device *dev, struct subsys_interface *sif) -{ - struct clk *clock_upll; - struct clk *clock_h; - struct clk *clock_p; - - clock_p = clk_get(NULL, "pclk"); - clock_h = clk_get(NULL, "hclk"); - clock_upll = clk_get(NULL, "upll"); - - if (IS_ERR(clock_p) || IS_ERR(clock_h) || IS_ERR(clock_upll)) { - printk(KERN_ERR "S3C2440: Failed to get parent clocks\n"); - return -EINVAL; - } - - s3c2440_clk_cam.parent = clock_h; - s3c2440_clk_ac97.parent = clock_p; - s3c2440_clk_cam_upll.parent = clock_upll; - s3c24xx_register_clock(&s3c2440_clk_fclk_n); - - s3c24xx_register_clock(&s3c2440_clk_ac97); - s3c24xx_register_clock(&s3c2440_clk_cam); - s3c24xx_register_clock(&s3c2440_clk_cam_upll); - clkdev_add_table(s3c2440_clk_lookup, ARRAY_SIZE(s3c2440_clk_lookup)); - - clk_disable(&s3c2440_clk_ac97); - clk_disable(&s3c2440_clk_cam); - - return 0; -} - -static struct subsys_interface s3c2440_clk_interface = { - .name = "s3c2440_clk", - .subsys = &s3c2440_subsys, - .add_dev = s3c2440_clk_add, -}; - -static __init int s3c24xx_clk_init(void) -{ - return subsys_interface_register(&s3c2440_clk_interface); -} - -arch_initcall(s3c24xx_clk_init); diff --git a/arch/arm/mach-s3c24xx/clock-s3c2443.c b/arch/arm/mach-s3c24xx/clock-s3c2443.c deleted file mode 100644 index 76cd31f7804e45..00000000000000 --- a/arch/arm/mach-s3c24xx/clock-s3c2443.c +++ /dev/null @@ -1,212 +0,0 @@ -/* linux/arch/arm/mach-s3c2443/clock.c - * - * Copyright (c) 2007, 2010 Simtec Electronics - * Ben Dooks - * - * S3C2443 Clock control support - * - * 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 - -/* We currently have to assume that the system is running - * from the XTPll input, and that all ***REFCLKs are being - * fed from it, as we cannot read the state of OM[4] from - * software. - * - * It would be possible for each board initialisation to - * set the correct muxing at initialisation -*/ - -/* clock selections */ - -/* armdiv - * - * this clock is sourced from msysclk and can have a number of - * divider values applied to it to then be fed into armclk. - * The real clock definition is done in s3c2443-clock.c, - * only the armdiv divisor table must be defined here. -*/ - -static unsigned int armdiv[16] = { - [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1, - [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2, - [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3, - [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4, - [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6, - [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8, - [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12, - [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16, -}; - -/* hsspi - * - * high-speed spi clock, sourced from esysclk -*/ - -static struct clksrc_clk clk_hsspi = { - .clk = { - .name = "hsspi-if", - .parent = &clk_esysclk.clk, - .ctrlbit = S3C2443_SCLKCON_HSSPICLK, - .enable = s3c2443_clkcon_enable_s, - }, - .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 }, -}; - - -/* clk_hsmcc_div - * - * this clock is sourced from epll, and is fed through a divider, - * to a mux controlled by sclkcon where either it or a extclk can - * be fed to the hsmmc block -*/ - -static struct clksrc_clk clk_hsmmc_div = { - .clk = { - .name = "hsmmc-div", - .devname = "s3c-sdhci.1", - .parent = &clk_esysclk.clk, - }, - .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 }, -}; - -static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent) -{ - unsigned long clksrc = __raw_readl(S3C2443_SCLKCON); - - clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT | - S3C2443_SCLKCON_HSMMCCLK_EPLL); - - if (parent == &clk_epll) - clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL; - else if (parent == &clk_ext) - clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT; - else - return -EINVAL; - - if (clk->usage > 0) { - __raw_writel(clksrc, S3C2443_SCLKCON); - } - - clk->parent = parent; - return 0; -} - -static int s3c2443_enable_hsmmc(struct clk *clk, int enable) -{ - return s3c2443_setparent_hsmmc(clk, clk->parent); -} - -static struct clk clk_hsmmc = { - .name = "hsmmc-if", - .devname = "s3c-sdhci.1", - .parent = &clk_hsmmc_div.clk, - .enable = s3c2443_enable_hsmmc, - .ops = &(struct clk_ops) { - .set_parent = s3c2443_setparent_hsmmc, - }, -}; - -/* standard clock definitions */ - -static struct clk init_clocks_off[] = { - { - .name = "sdi", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_SDI, - }, { - .name = "spi", - .devname = "s3c2410-spi.0", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_SPI1, - } -}; - -/* clocks to add straight away */ - -static struct clksrc_clk *clksrcs[] __initdata = { - &clk_hsspi, - &clk_hsmmc_div, -}; - -static struct clk *clks[] __initdata = { - &clk_hsmmc, -}; - -static struct clk_lookup s3c2443_clk_lookup[] = { - CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_hsmmc), - CLKDEV_INIT("s3c2443-spi.0", "spi_busclk2", &clk_hsspi.clk), -}; - -void __init s3c2443_init_clocks(int xtal) -{ - unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); - int ptr; - - clk_epll.rate = s3c2443_get_epll(epllcon, xtal); - clk_epll.parent = &clk_epllref.clk; - - s3c2443_common_init_clocks(xtal, s3c2443_get_mpll, - armdiv, ARRAY_SIZE(armdiv), - S3C2443_CLKDIV0_ARMDIV_MASK); - - s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); - - for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) - s3c_register_clksrc(clksrcs[ptr], 1); - - /* We must be careful disabling the clocks we are not intending to - * be using at boot time, as subsystems such as the LCD which do - * their own DMA requests to the bus can cause the system to lockup - * if they where in the middle of requesting bus access. - * - * Disabling the LCD clock if the LCD is active is very dangerous, - * and therefore the bootloader should be careful to not enable - * the LCD clock if it is not needed. - */ - - /* install (and disable) the clocks we do not need immediately */ - - s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); - s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); - clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup)); -} diff --git a/arch/arm/mach-s3c24xx/clock-s3c244x.c b/arch/arm/mach-s3c24xx/clock-s3c244x.c deleted file mode 100644 index 6d9b688c442bd6..00000000000000 --- a/arch/arm/mach-s3c24xx/clock-s3c244x.c +++ /dev/null @@ -1,141 +0,0 @@ -/* linux/arch/arm/plat-s3c24xx/s3c24xx-clock.c - * - * Copyright (c) 2004-2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * S3C2440/S3C2442 Common clock support - * - * 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 - -static int s3c2440_setparent_armclk(struct clk *clk, struct clk *parent) -{ - unsigned long camdivn; - unsigned long dvs; - - if (parent == &clk_f) - dvs = 0; - else if (parent == &clk_h) - dvs = S3C2440_CAMDIVN_DVSEN; - else - return -EINVAL; - - clk->parent = parent; - - camdivn = __raw_readl(S3C2440_CAMDIVN); - camdivn &= ~S3C2440_CAMDIVN_DVSEN; - camdivn |= dvs; - __raw_writel(camdivn, S3C2440_CAMDIVN); - - return 0; -} - -static struct clk clk_arm = { - .name = "armclk", - .id = -1, - .ops = &(struct clk_ops) { - .set_parent = s3c2440_setparent_armclk, - }, -}; - -static int s3c244x_clk_add(struct device *dev, struct subsys_interface *sif) -{ - unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN); - unsigned long clkdivn; - struct clk *clock_upll; - int ret; - - printk("S3C244X: Clock Support, DVS %s\n", - (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off"); - - clk_arm.parent = (camdivn & S3C2440_CAMDIVN_DVSEN) ? &clk_h : &clk_f; - - ret = s3c24xx_register_clock(&clk_arm); - if (ret < 0) { - printk(KERN_ERR "S3C24XX: Failed to add armclk (%d)\n", ret); - return ret; - } - - clock_upll = clk_get(NULL, "upll"); - if (IS_ERR(clock_upll)) { - printk(KERN_ERR "S3C244X: Failed to get upll clock\n"); - return -ENOENT; - } - - /* check rate of UPLL, and if it is near 96MHz, then change - * to using half the UPLL rate for the system */ - - if (clk_get_rate(clock_upll) > (94 * MHZ)) { - clk_usb_bus.rate = clk_get_rate(clock_upll) / 2; - - spin_lock(&clocks_lock); - - clkdivn = __raw_readl(S3C2410_CLKDIVN); - clkdivn |= S3C2440_CLKDIVN_UCLK; - __raw_writel(clkdivn, S3C2410_CLKDIVN); - - spin_unlock(&clocks_lock); - } - - return 0; -} - -static struct subsys_interface s3c2440_clk_interface = { - .name = "s3c2440_clk", - .subsys = &s3c2440_subsys, - .add_dev = s3c244x_clk_add, -}; - -static int s3c2440_clk_init(void) -{ - return subsys_interface_register(&s3c2440_clk_interface); -} - -arch_initcall(s3c2440_clk_init); - -static struct subsys_interface s3c2442_clk_interface = { - .name = "s3c2442_clk", - .subsys = &s3c2442_subsys, - .add_dev = s3c244x_clk_add, -}; - -static int s3c2442_clk_init(void) -{ - return subsys_interface_register(&s3c2442_clk_interface); -} - -arch_initcall(s3c2442_clk_init); diff --git a/arch/arm/mach-s3c24xx/common-s3c2443.c b/arch/arm/mach-s3c24xx/common-s3c2443.c deleted file mode 100644 index 65d3eef7309040..00000000000000 --- a/arch/arm/mach-s3c24xx/common-s3c2443.c +++ /dev/null @@ -1,675 +0,0 @@ -/* - * Common code for SoCs starting with the S3C2443 - * - * Copyright (c) 2007, 2010 Simtec Electronics - * Ben Dooks - * - * 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. - */ - -#include -#include -#include - -#include - -#include -#include -#include - -#include - - -static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable) -{ - u32 ctrlbit = clk->ctrlbit; - u32 con = __raw_readl(reg); - - if (enable) - con |= ctrlbit; - else - con &= ~ctrlbit; - - __raw_writel(con, reg); - return 0; -} - -int s3c2443_clkcon_enable_h(struct clk *clk, int enable) -{ - return s3c2443_gate(S3C2443_HCLKCON, clk, enable); -} - -int s3c2443_clkcon_enable_p(struct clk *clk, int enable) -{ - return s3c2443_gate(S3C2443_PCLKCON, clk, enable); -} - -int s3c2443_clkcon_enable_s(struct clk *clk, int enable) -{ - return s3c2443_gate(S3C2443_SCLKCON, clk, enable); -} - -/* mpllref is a direct descendant of clk_xtal by default, but it is not - * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as - * such directly equating the two source clocks is impossible. - */ -static struct clk clk_mpllref = { - .name = "mpllref", - .parent = &clk_xtal, -}; - -static struct clk *clk_epllref_sources[] = { - [0] = &clk_mpllref, - [1] = &clk_mpllref, - [2] = &clk_xtal, - [3] = &clk_ext, -}; - -struct clksrc_clk clk_epllref = { - .clk = { - .name = "epllref", - }, - .sources = &(struct clksrc_sources) { - .sources = clk_epllref_sources, - .nr_sources = ARRAY_SIZE(clk_epllref_sources), - }, - .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 }, -}; - -/* esysclk - * - * this is sourced from either the EPLL or the EPLLref clock -*/ - -static struct clk *clk_sysclk_sources[] = { - [0] = &clk_epllref.clk, - [1] = &clk_epll, -}; - -struct clksrc_clk clk_esysclk = { - .clk = { - .name = "esysclk", - .parent = &clk_epll, - }, - .sources = &(struct clksrc_sources) { - .sources = clk_sysclk_sources, - .nr_sources = ARRAY_SIZE(clk_sysclk_sources), - }, - .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 }, -}; - -static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - unsigned long div = __raw_readl(S3C2443_CLKDIV0); - - div &= S3C2443_CLKDIV0_EXTDIV_MASK; - div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */ - - return parent_rate / (div + 1); -} - -static struct clk clk_mdivclk = { - .name = "mdivclk", - .parent = &clk_mpllref, - .ops = &(struct clk_ops) { - .get_rate = s3c2443_getrate_mdivclk, - }, -}; - -static struct clk *clk_msysclk_sources[] = { - [0] = &clk_mpllref, - [1] = &clk_mpll, - [2] = &clk_mdivclk, - [3] = &clk_mpllref, -}; - -static struct clksrc_clk clk_msysclk = { - .clk = { - .name = "msysclk", - .parent = &clk_xtal, - }, - .sources = &(struct clksrc_sources) { - .sources = clk_msysclk_sources, - .nr_sources = ARRAY_SIZE(clk_msysclk_sources), - }, - .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 }, -}; - -/* prediv - * - * this divides the msysclk down to pass to h/p/etc. - */ - -static unsigned long s3c2443_prediv_getrate(struct clk *clk) -{ - unsigned long rate = clk_get_rate(clk->parent); - unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); - - clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK; - clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT; - - return rate / (clkdiv0 + 1); -} - -static struct clk clk_prediv = { - .name = "prediv", - .parent = &clk_msysclk.clk, - .ops = &(struct clk_ops) { - .get_rate = s3c2443_prediv_getrate, - }, -}; - -/* hclk divider - * - * divides the prediv and provides the hclk. - */ - -static unsigned long s3c2443_hclkdiv_getrate(struct clk *clk) -{ - unsigned long rate = clk_get_rate(clk->parent); - unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); - - clkdiv0 &= S3C2443_CLKDIV0_HCLKDIV_MASK; - - return rate / (clkdiv0 + 1); -} - -static struct clk_ops clk_h_ops = { - .get_rate = s3c2443_hclkdiv_getrate, -}; - -/* pclk divider - * - * divides the hclk and provides the pclk. - */ - -static unsigned long s3c2443_pclkdiv_getrate(struct clk *clk) -{ - unsigned long rate = clk_get_rate(clk->parent); - unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); - - clkdiv0 = ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 1 : 0); - - return rate / (clkdiv0 + 1); -} - -static struct clk_ops clk_p_ops = { - .get_rate = s3c2443_pclkdiv_getrate, -}; - -/* armdiv - * - * this clock is sourced from msysclk and can have a number of - * divider values applied to it to then be fed into armclk. -*/ - -static unsigned int *armdiv; -static int nr_armdiv; -static int armdivmask; - -static unsigned long s3c2443_armclk_roundrate(struct clk *clk, - unsigned long rate) -{ - unsigned long parent = clk_get_rate(clk->parent); - unsigned long calc; - unsigned best = 256; /* bigger than any value */ - unsigned div; - int ptr; - - if (!nr_armdiv) - return -EINVAL; - - for (ptr = 0; ptr < nr_armdiv; ptr++) { - div = armdiv[ptr]; - if (div) { - /* cpufreq provides 266mhz as 266666000 not 266666666 */ - calc = (parent / div / 1000) * 1000; - if (calc <= rate && div < best) - best = div; - } - } - - return parent / best; -} - -static unsigned long s3c2443_armclk_getrate(struct clk *clk) -{ - unsigned long rate = clk_get_rate(clk->parent); - unsigned long clkcon0; - int val; - - if (!nr_armdiv || !armdivmask) - return -EINVAL; - - clkcon0 = __raw_readl(S3C2443_CLKDIV0); - clkcon0 &= armdivmask; - val = clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT; - - return rate / armdiv[val]; -} - -static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate) -{ - unsigned long parent = clk_get_rate(clk->parent); - unsigned long calc; - unsigned div; - unsigned best = 256; /* bigger than any value */ - int ptr; - int val = -1; - - if (!nr_armdiv || !armdivmask) - return -EINVAL; - - for (ptr = 0; ptr < nr_armdiv; ptr++) { - div = armdiv[ptr]; - if (div) { - /* cpufreq provides 266mhz as 266666000 not 266666666 */ - calc = (parent / div / 1000) * 1000; - if (calc <= rate && div < best) { - best = div; - val = ptr; - } - } - } - - if (val >= 0) { - unsigned long clkcon0; - - clkcon0 = __raw_readl(S3C2443_CLKDIV0); - clkcon0 &= ~armdivmask; - clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT; - __raw_writel(clkcon0, S3C2443_CLKDIV0); - } - - return (val == -1) ? -EINVAL : 0; -} - -static struct clk clk_armdiv = { - .name = "armdiv", - .parent = &clk_msysclk.clk, - .ops = &(struct clk_ops) { - .round_rate = s3c2443_armclk_roundrate, - .get_rate = s3c2443_armclk_getrate, - .set_rate = s3c2443_armclk_setrate, - }, -}; - -/* armclk - * - * this is the clock fed into the ARM core itself, from armdiv or from hclk. - */ - -static struct clk *clk_arm_sources[] = { - [0] = &clk_armdiv, - [1] = &clk_h, -}; - -static struct clksrc_clk clk_arm = { - .clk = { - .name = "armclk", - }, - .sources = &(struct clksrc_sources) { - .sources = clk_arm_sources, - .nr_sources = ARRAY_SIZE(clk_arm_sources), - }, - .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 }, -}; - -/* usbhost - * - * usb host bus-clock, usually 48MHz to provide USB bus clock timing -*/ - -static struct clksrc_clk clk_usb_bus_host = { - .clk = { - .name = "usb-bus-host-parent", - .parent = &clk_esysclk.clk, - .ctrlbit = S3C2443_SCLKCON_USBHOST, - .enable = s3c2443_clkcon_enable_s, - }, - .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 }, -}; - -/* common clksrc clocks */ - -static struct clksrc_clk clksrc_clks[] = { - { - /* camera interface bus-clock, divided down from esysclk */ - .clk = { - .name = "camif-upll", /* same as 2440 name */ - .parent = &clk_esysclk.clk, - .ctrlbit = S3C2443_SCLKCON_CAMCLK, - .enable = s3c2443_clkcon_enable_s, - }, - .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 }, - }, { - .clk = { - .name = "display-if", - .parent = &clk_esysclk.clk, - .ctrlbit = S3C2443_SCLKCON_DISPCLK, - .enable = s3c2443_clkcon_enable_s, - }, - .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 }, - }, -}; - -static struct clksrc_clk clk_esys_uart = { - /* ART baud-rate clock sourced from esysclk via a divisor */ - .clk = { - .name = "uartclk", - .parent = &clk_esysclk.clk, - }, - .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 }, -}; - -static struct clk clk_i2s_ext = { - .name = "i2s-ext", -}; - -/* i2s_eplldiv - * - * This clock is the output from the I2S divisor of ESYSCLK, and is separate - * from the mux that comes after it (cannot merge into one single clock) -*/ - -static struct clksrc_clk clk_i2s_eplldiv = { - .clk = { - .name = "i2s-eplldiv", - .parent = &clk_esysclk.clk, - }, - .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, }, -}; - -/* i2s-ref - * - * i2s bus reference clock, selectable from external, esysclk or epllref - * - * Note, this used to be two clocks, but was compressed into one. -*/ - -static struct clk *clk_i2s_srclist[] = { - [0] = &clk_i2s_eplldiv.clk, - [1] = &clk_i2s_ext, - [2] = &clk_epllref.clk, - [3] = &clk_epllref.clk, -}; - -static struct clksrc_clk clk_i2s = { - .clk = { - .name = "i2s-if", - .ctrlbit = S3C2443_SCLKCON_I2SCLK, - .enable = s3c2443_clkcon_enable_s, - - }, - .sources = &(struct clksrc_sources) { - .sources = clk_i2s_srclist, - .nr_sources = ARRAY_SIZE(clk_i2s_srclist), - }, - .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 }, -}; - -static struct clk init_clocks_off[] = { - { - .name = "iis", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_IIS, - }, { - .name = "adc", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_ADC, - }, { - .name = "i2c", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_IIC, - } -}; - -static struct clk init_clocks[] = { - { - .name = "dma.0", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2443_HCLKCON_DMA0, - }, { - .name = "dma.1", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2443_HCLKCON_DMA1, - }, { - .name = "dma.2", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2443_HCLKCON_DMA2, - }, { - .name = "dma.3", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2443_HCLKCON_DMA3, - }, { - .name = "dma.4", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2443_HCLKCON_DMA4, - }, { - .name = "dma.5", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2443_HCLKCON_DMA5, - }, { - .name = "gpio", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_GPIO, - }, { - .name = "usb-host", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2443_HCLKCON_USBH, - }, { - .name = "usb-device", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2443_HCLKCON_USBD, - }, { - .name = "lcd", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2443_HCLKCON_LCDC, - - }, { - .name = "timers", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_PWMT, - }, { - .name = "cfc", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2443_HCLKCON_CFC, - }, { - .name = "ssmc", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2443_HCLKCON_SSMC, - }, { - .name = "uart", - .devname = "s3c2440-uart.0", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_UART0, - }, { - .name = "uart", - .devname = "s3c2440-uart.1", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_UART1, - }, { - .name = "uart", - .devname = "s3c2440-uart.2", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_UART2, - }, { - .name = "uart", - .devname = "s3c2440-uart.3", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_UART3, - }, { - .name = "rtc", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_RTC, - }, { - .name = "watchdog", - .parent = &clk_p, - .ctrlbit = S3C2443_PCLKCON_WDT, - }, { - .name = "ac97", - .parent = &clk_p, - .ctrlbit = S3C2443_PCLKCON_AC97, - }, { - .name = "nand", - .parent = &clk_h, - }, { - .name = "usb-bus-host", - .parent = &clk_usb_bus_host.clk, - } -}; - -static struct clk hsmmc1_clk = { - .name = "hsmmc", - .devname = "s3c-sdhci.1", - .parent = &clk_h, - .enable = s3c2443_clkcon_enable_h, - .ctrlbit = S3C2443_HCLKCON_HSMMC, -}; - -static struct clk hsspi_clk = { - .name = "spi", - .devname = "s3c2443-spi.0", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_HSSPI, -}; - -/* EPLLCON compatible enough to get on/off information */ - -void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll) -{ - unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); - unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON); - struct clk *xtal_clk; - unsigned long xtal; - unsigned long pll; - int ptr; - - xtal_clk = clk_get(NULL, "xtal"); - xtal = clk_get_rate(xtal_clk); - clk_put(xtal_clk); - - pll = get_mpll(mpllcon, xtal); - clk_msysclk.clk.rate = pll; - clk_mpll.rate = pll; - - printk("CPU: MPLL %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n", - (mpllcon & S3C2443_PLLCON_OFF) ? "off" : "on", - print_mhz(pll), print_mhz(clk_get_rate(&clk_armdiv)), - print_mhz(clk_get_rate(&clk_h)), - print_mhz(clk_get_rate(&clk_p))); - - for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++) - s3c_set_clksrc(&clksrc_clks[ptr], true); - - /* ensure usb bus clock is within correct rate of 48MHz */ - - if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) { - printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); - clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000); - } - - printk("CPU: EPLL %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", - (epllcon & S3C2443_PLLCON_OFF) ? "off" : "on", - print_mhz(clk_get_rate(&clk_epll)), - print_mhz(clk_get_rate(&clk_usb_bus))); -} - -static struct clk *clks[] __initdata = { - &clk_prediv, - &clk_mpllref, - &clk_mdivclk, - &clk_ext, - &clk_epll, - &clk_usb_bus, - &clk_armdiv, - &hsmmc1_clk, - &hsspi_clk, -}; - -static struct clksrc_clk *clksrcs[] __initdata = { - &clk_i2s_eplldiv, - &clk_i2s, - &clk_usb_bus_host, - &clk_epllref, - &clk_esysclk, - &clk_msysclk, - &clk_arm, -}; - -static struct clk_lookup s3c2443_clk_lookup[] = { - CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk), - CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p), - CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_esys_uart.clk), - CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &hsmmc1_clk), - CLKDEV_INIT("s3c2443-spi.0", "spi_busclk0", &hsspi_clk), -}; - -void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll, - unsigned int *divs, int nr_divs, - int divmask) -{ - int ptr; - - armdiv = divs; - nr_armdiv = nr_divs; - armdivmask = divmask; - - /* s3c2443 parents h clock from prediv */ - clk_h.parent = &clk_prediv; - clk_h.ops = &clk_h_ops; - - /* and p clock from h clock */ - clk_p.parent = &clk_h; - clk_p.ops = &clk_p_ops; - - clk_usb_bus.parent = &clk_usb_bus_host.clk; - clk_epll.parent = &clk_epllref.clk; - - s3c24xx_register_baseclocks(xtal); - s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); - - for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) - s3c_register_clksrc(clksrcs[ptr], 1); - - s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks)); - s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); - - /* See s3c2443/etc notes on disabling clocks at init time */ - s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); - s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); - clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup)); - - s3c2443_common_setup_clocks(get_mpll); -} diff --git a/arch/arm/mach-s3c24xx/common.c b/arch/arm/mach-s3c24xx/common.c index 1bc8e73c94f986..c0763b8377455f 100644 --- a/arch/arm/mach-s3c24xx/common.c +++ b/arch/arm/mach-s3c24xx/common.c @@ -53,6 +53,7 @@ #include #include #include +#include #include "common.h" @@ -73,7 +74,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = 0x32410000, .idmask = 0xffffffff, .map_io = s3c2410_map_io, - .init_clocks = s3c2410_init_clocks, .init_uarts = s3c2410_init_uarts, .init = s3c2410_init, .name = name_s3c2410 @@ -82,7 +82,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = 0x32410002, .idmask = 0xffffffff, .map_io = s3c2410_map_io, - .init_clocks = s3c2410_init_clocks, .init_uarts = s3c2410_init_uarts, .init = s3c2410a_init, .name = name_s3c2410a @@ -91,7 +90,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = 0x32440000, .idmask = 0xffffffff, .map_io = s3c2440_map_io, - .init_clocks = s3c244x_init_clocks, .init_uarts = s3c244x_init_uarts, .init = s3c2440_init, .name = name_s3c2440 @@ -100,7 +98,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = 0x32440001, .idmask = 0xffffffff, .map_io = s3c2440_map_io, - .init_clocks = s3c244x_init_clocks, .init_uarts = s3c244x_init_uarts, .init = s3c2440_init, .name = name_s3c2440a @@ -109,7 +106,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = 0x32440aaa, .idmask = 0xffffffff, .map_io = s3c2442_map_io, - .init_clocks = s3c244x_init_clocks, .init_uarts = s3c244x_init_uarts, .init = s3c2442_init, .name = name_s3c2442 @@ -118,7 +114,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = 0x32440aab, .idmask = 0xffffffff, .map_io = s3c2442_map_io, - .init_clocks = s3c244x_init_clocks, .init_uarts = s3c244x_init_uarts, .init = s3c2442_init, .name = name_s3c2442b @@ -127,7 +122,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = 0x32412001, .idmask = 0xffffffff, .map_io = s3c2412_map_io, - .init_clocks = s3c2412_init_clocks, .init_uarts = s3c2412_init_uarts, .init = s3c2412_init, .name = name_s3c2412, @@ -136,7 +130,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = 0x32412003, .idmask = 0xffffffff, .map_io = s3c2412_map_io, - .init_clocks = s3c2412_init_clocks, .init_uarts = s3c2412_init_uarts, .init = s3c2412_init, .name = name_s3c2412, @@ -145,7 +138,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = 0x32450003, .idmask = 0xffffffff, .map_io = s3c2416_map_io, - .init_clocks = s3c2416_init_clocks, .init_uarts = s3c2416_init_uarts, .init = s3c2416_init, .name = name_s3c2416, @@ -154,7 +146,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = 0x32443001, .idmask = 0xffffffff, .map_io = s3c2443_map_io, - .init_clocks = s3c2443_init_clocks, .init_uarts = s3c2443_init_uarts, .init = s3c2443_init, .name = name_s3c2443, @@ -316,21 +307,6 @@ struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = { }, }; -/* initialise all the clocks */ - -void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk, - unsigned long hclk, - unsigned long pclk) -{ - clk_upll.rate = s3c24xx_get_pll(__raw_readl(S3C2410_UPLLCON), - clk_xtal.rate); - - clk_mpll.rate = fclk; - clk_h.rate = hclk; - clk_p.rate = pclk; - clk_f.rate = fclk; -} - #if defined(CONFIG_CPU_S3C2410) || defined(CONFIG_CPU_S3C2412) || \ defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442) static struct resource s3c2410_dma_resource[] = { @@ -534,3 +510,62 @@ struct platform_device s3c2443_device_dma = { }, }; #endif + +#if defined(CONFIG_COMMON_CLK) && defined(CONFIG_CPU_S3C2410) +void __init s3c2410_init_clocks(int xtal) +{ + s3c2410_common_clk_init(NULL, xtal, 0, S3C24XX_VA_CLKPWR); + samsung_wdt_reset_init(S3C24XX_VA_WATCHDOG); +} +#endif + +#ifdef CONFIG_CPU_S3C2412 +void __init s3c2412_init_clocks(int xtal) +{ + s3c2412_common_clk_init(NULL, xtal, 0, S3C24XX_VA_CLKPWR); +} +#endif + +#ifdef CONFIG_CPU_S3C2416 +void __init s3c2416_init_clocks(int xtal) +{ + s3c2443_common_clk_init(NULL, xtal, 0, S3C24XX_VA_CLKPWR); +} +#endif + +#if defined(CONFIG_COMMON_CLK) && defined(CONFIG_CPU_S3C2440) +void __init s3c2440_init_clocks(int xtal) +{ + s3c2410_common_clk_init(NULL, xtal, 1, S3C24XX_VA_CLKPWR); + samsung_wdt_reset_init(S3C24XX_VA_WATCHDOG); +} +#endif + +#if defined(CONFIG_COMMON_CLK) && defined(CONFIG_CPU_S3C2442) +void __init s3c2442_init_clocks(int xtal) +{ + s3c2410_common_clk_init(NULL, xtal, 2, S3C24XX_VA_CLKPWR); + samsung_wdt_reset_init(S3C24XX_VA_WATCHDOG); +} +#endif + +#ifdef CONFIG_CPU_S3C2443 +void __init s3c2443_init_clocks(int xtal) +{ + s3c2443_common_clk_init(NULL, xtal, 1, S3C24XX_VA_CLKPWR); +} +#endif + +#if defined(CONFIG_CPU_S3C2410) || defined(CONFIG_CPU_S3C2440) || \ + defined(CONFIG_CPU_S3C2442) +static struct resource s3c2410_dclk_resource[] = { + [0] = DEFINE_RES_MEM(0x56000084, 0x4), +}; + +struct platform_device s3c2410_device_dclk = { + .name = "s3c2410-dclk", + .id = 0, + .num_resources = ARRAY_SIZE(s3c2410_dclk_resource), + .resource = s3c2410_dclk_resource, +}; +#endif diff --git a/arch/arm/mach-s3c24xx/common.h b/arch/arm/mach-s3c24xx/common.h index e46c1041721669..ac3ff12a060165 100644 --- a/arch/arm/mach-s3c24xx/common.h +++ b/arch/arm/mach-s3c24xx/common.h @@ -67,16 +67,15 @@ extern struct syscore_ops s3c2416_irq_syscore_ops; #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442) extern void s3c244x_map_io(void); extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no); -extern void s3c244x_init_clocks(int xtal); extern void s3c244x_restart(enum reboot_mode mode, const char *cmd); #else -#define s3c244x_init_clocks NULL #define s3c244x_init_uarts NULL #endif #ifdef CONFIG_CPU_S3C2440 extern int s3c2440_init(void); extern void s3c2440_map_io(void); +extern void s3c2440_init_clocks(int xtal); extern void s3c2440_init_irq(void); #else #define s3c2440_init NULL @@ -86,6 +85,7 @@ extern void s3c2440_init_irq(void); #ifdef CONFIG_CPU_S3C2442 extern int s3c2442_init(void); extern void s3c2442_map_io(void); +extern void s3c2442_init_clocks(int xtal); extern void s3c2442_init_irq(void); #else #define s3c2442_init NULL @@ -114,4 +114,21 @@ extern struct platform_device s3c2412_device_dma; extern struct platform_device s3c2440_device_dma; extern struct platform_device s3c2443_device_dma; +extern struct platform_device s3c2410_device_dclk; + +#ifdef CONFIG_S3C2410_COMMON_CLK +void __init s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f, + int current_soc, + void __iomem *reg_base); +#endif +#ifdef CONFIG_S3C2412_COMMON_CLK +void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, + unsigned long ext_f, void __iomem *reg_base); +#endif +#ifdef CONFIG_S3C2443_COMMON_CLK +void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, + int current_soc, + void __iomem *reg_base); +#endif + #endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */ diff --git a/arch/arm/mach-s3c24xx/cpufreq-utils.c b/arch/arm/mach-s3c24xx/cpufreq-utils.c index 2a0aa5684e725f..d4d9514335f497 100644 --- a/arch/arm/mach-s3c24xx/cpufreq-utils.c +++ b/arch/arm/mach-s3c24xx/cpufreq-utils.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -60,5 +61,6 @@ void s3c2410_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg) */ void s3c2410_set_fvco(struct s3c_cpufreq_config *cfg) { - __raw_writel(cfg->pll.driver_data, S3C2410_MPLLCON); + if (!IS_ERR(cfg->mpll)) + clk_set_rate(cfg->mpll, cfg->pll.frequency); } diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-clock.h b/arch/arm/mach-s3c24xx/include/mach/regs-clock.h index 3415b60082d762..3db6c10de023f4 100644 --- a/arch/arm/mach-s3c24xx/include/mach/regs-clock.h +++ b/arch/arm/mach-s3c24xx/include/mach/regs-clock.h @@ -42,24 +42,6 @@ #define S3C2410_CLKCON_IIS (1<<17) #define S3C2410_CLKCON_SPI (1<<18) -/* DCLKCON register addresses in gpio.h */ - -#define S3C2410_DCLKCON_DCLK0EN (1<<0) -#define S3C2410_DCLKCON_DCLK0_PCLK (0<<1) -#define S3C2410_DCLKCON_DCLK0_UCLK (1<<1) -#define S3C2410_DCLKCON_DCLK0_DIV(x) (((x) - 1 )<<4) -#define S3C2410_DCLKCON_DCLK0_CMP(x) (((x) - 1 )<<8) -#define S3C2410_DCLKCON_DCLK0_DIV_MASK ((0xf)<<4) -#define S3C2410_DCLKCON_DCLK0_CMP_MASK ((0xf)<<8) - -#define S3C2410_DCLKCON_DCLK1EN (1<<16) -#define S3C2410_DCLKCON_DCLK1_PCLK (0<<17) -#define S3C2410_DCLKCON_DCLK1_UCLK (1<<17) -#define S3C2410_DCLKCON_DCLK1_DIV(x) (((x) - 1) <<20) -#define S3C2410_DCLKCON_DCLK1_CMP(x) (((x) - 1) <<24) -#define S3C2410_DCLKCON_DCLK1_DIV_MASK ((0xf) <<20) -#define S3C2410_DCLKCON_DCLK1_CMP_MASK ((0xf) <<24) - #define S3C2410_CLKDIVN_PDIVN (1<<0) #define S3C2410_CLKDIVN_HDIVN (1<<1) diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h b/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h index c2ef016032ab46..c6583cfa58359b 100644 --- a/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h +++ b/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h @@ -457,9 +457,6 @@ /* miscellaneous control */ #define S3C2410_MISCCR S3C2410_GPIOREG(0x80) -#define S3C2410_DCLKCON S3C2410_GPIOREG(0x84) - -#define S3C24XX_DCLKCON S3C24XX_GPIOREG2(0x84) /* see clock.h for dclk definitions */ diff --git a/arch/arm/mach-s3c24xx/mach-amlm5900.c b/arch/arm/mach-s3c24xx/mach-amlm5900.c index 8ac9554aa996c7..5157e250dd133c 100644 --- a/arch/arm/mach-s3c24xx/mach-amlm5900.c +++ b/arch/arm/mach-s3c24xx/mach-amlm5900.c @@ -161,11 +161,16 @@ static struct platform_device *amlm5900_devices[] __initdata = { static void __init amlm5900_map_io(void) { s3c24xx_init_io(amlm5900_iodesc, ARRAY_SIZE(amlm5900_iodesc)); - s3c24xx_init_clocks(0); s3c24xx_init_uarts(amlm5900_uartcfgs, ARRAY_SIZE(amlm5900_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init amlm5900_init_time(void) +{ + s3c2410_init_clocks(12000000); + samsung_timer_init(); +} + #ifdef CONFIG_FB_S3C2410 static struct s3c2410fb_display __initdata amlm5900_lcd_info = { .width = 160, @@ -241,6 +246,6 @@ MACHINE_START(AML_M5900, "AML_M5900") .map_io = amlm5900_map_io, .init_irq = s3c2410_init_irq, .init_machine = amlm5900_init, - .init_time = samsung_timer_init, + .init_time = amlm5900_init_time, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c index 81a270af2336f9..e053581cab0b53 100644 --- a/arch/arm/mach-s3c24xx/mach-anubis.c +++ b/arch/arm/mach-s3c24xx/mach-anubis.c @@ -46,7 +46,6 @@ #include -#include #include #include #include @@ -352,6 +351,7 @@ static struct platform_device anubis_device_sm501 = { /* Standard Anubis devices */ static struct platform_device *anubis_devices[] __initdata = { + &s3c2410_device_dclk, &s3c_device_ohci, &s3c_device_wdt, &s3c_device_adc, @@ -364,14 +364,6 @@ static struct platform_device *anubis_devices[] __initdata = { &anubis_device_sm501, }; -static struct clk *anubis_clocks[] __initdata = { - &s3c24xx_dclk0, - &s3c24xx_dclk1, - &s3c24xx_clkout0, - &s3c24xx_clkout1, - &s3c24xx_uclk, -}; - /* I2C devices. */ static struct i2c_board_info anubis_i2c_devs[] __initdata = { @@ -394,23 +386,7 @@ static struct s3c24xx_audio_simtec_pdata __initdata anubis_audio = { static void __init anubis_map_io(void) { - /* initialise the clocks */ - - s3c24xx_dclk0.parent = &clk_upll; - s3c24xx_dclk0.rate = 12*1000*1000; - - s3c24xx_dclk1.parent = &clk_upll; - s3c24xx_dclk1.rate = 24*1000*1000; - - s3c24xx_clkout0.parent = &s3c24xx_dclk0; - s3c24xx_clkout1.parent = &s3c24xx_dclk1; - - s3c24xx_uclk.parent = &s3c24xx_clkout1; - - s3c24xx_register_clocks(anubis_clocks, ARRAY_SIZE(anubis_clocks)); - s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc)); - s3c24xx_init_clocks(0); s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); @@ -428,6 +404,12 @@ static void __init anubis_map_io(void) } } +static void __init anubis_init_time(void) +{ + s3c2440_init_clocks(12000000); + samsung_timer_init(); +} + static void __init anubis_init(void) { s3c_i2c0_set_platdata(NULL); @@ -447,6 +429,6 @@ MACHINE_START(ANUBIS, "Simtec-Anubis") .map_io = anubis_map_io, .init_machine = anubis_init, .init_irq = s3c2440_init_irq, - .init_time = samsung_timer_init, + .init_time = anubis_init_time, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c index d8f6bb1096cb3b..9db768f448a508 100644 --- a/arch/arm/mach-s3c24xx/mach-at2440evb.c +++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c @@ -45,7 +45,6 @@ #include #include -#include #include #include #include @@ -192,11 +191,16 @@ static struct platform_device *at2440evb_devices[] __initdata = { static void __init at2440evb_map_io(void) { s3c24xx_init_io(at2440evb_iodesc, ARRAY_SIZE(at2440evb_iodesc)); - s3c24xx_init_clocks(16934400); s3c24xx_init_uarts(at2440evb_uartcfgs, ARRAY_SIZE(at2440evb_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init at2440evb_init_time(void) +{ + s3c2440_init_clocks(16934400); + samsung_timer_init(); +} + static void __init at2440evb_init(void) { s3c24xx_fb_set_platdata(&at2440evb_fb_info); @@ -213,6 +217,6 @@ MACHINE_START(AT2440EVB, "AT2440EVB") .map_io = at2440evb_map_io, .init_machine = at2440evb_init, .init_irq = s3c2440_init_irq, - .init_time = samsung_timer_init, + .init_time = at2440evb_init_time, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c index e371ff53a40820..f9112b801a33c4 100644 --- a/arch/arm/mach-s3c24xx/mach-bast.c +++ b/arch/arm/mach-s3c24xx/mach-bast.c @@ -51,7 +51,6 @@ #include #include -#include #include #include #include @@ -523,6 +522,7 @@ static struct s3c_hwmon_pdata bast_hwmon_info = { // cat /sys/devices/platform/s3c24xx-adc/s3c-hwmon/in_0 static struct platform_device *bast_devices[] __initdata = { + &s3c2410_device_dclk, &s3c_device_ohci, &s3c_device_lcd, &s3c_device_wdt, @@ -537,14 +537,6 @@ static struct platform_device *bast_devices[] __initdata = { &bast_sio, }; -static struct clk *bast_clocks[] __initdata = { - &s3c24xx_dclk0, - &s3c24xx_dclk1, - &s3c24xx_clkout0, - &s3c24xx_clkout1, - &s3c24xx_uclk, -}; - static struct s3c_cpufreq_board __initdata bast_cpufreq = { .refresh = 7800, /* 7.8usec */ .auto_io = 1, @@ -558,29 +550,19 @@ static struct s3c24xx_audio_simtec_pdata __initdata bast_audio = { static void __init bast_map_io(void) { - /* initialise the clocks */ - - s3c24xx_dclk0.parent = &clk_upll; - s3c24xx_dclk0.rate = 12*1000*1000; - - s3c24xx_dclk1.parent = &clk_upll; - s3c24xx_dclk1.rate = 24*1000*1000; - - s3c24xx_clkout0.parent = &s3c24xx_dclk0; - s3c24xx_clkout1.parent = &s3c24xx_dclk1; - - s3c24xx_uclk.parent = &s3c24xx_clkout1; - - s3c24xx_register_clocks(bast_clocks, ARRAY_SIZE(bast_clocks)); - s3c_hwmon_set_platdata(&bast_hwmon_info); s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc)); - s3c24xx_init_clocks(0); s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init bast_init_time(void) +{ + s3c2410_init_clocks(12000000); + samsung_timer_init(); +} + static void __init bast_init(void) { register_syscore_ops(&bast_pm_syscore_ops); @@ -608,6 +590,6 @@ MACHINE_START(BAST, "Simtec-BAST") .map_io = bast_map_io, .init_irq = s3c2410_init_irq, .init_machine = bast_init, - .init_time = samsung_timer_init, + .init_time = bast_init_time, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c index dc4db849f0fda5..fc3a08d0cb3f5f 100644 --- a/arch/arm/mach-s3c24xx/mach-gta02.c +++ b/arch/arm/mach-s3c24xx/mach-gta02.c @@ -501,7 +501,6 @@ static struct platform_device gta02_buttons_device = { static void __init gta02_map_io(void) { s3c24xx_init_io(gta02_iodesc, ARRAY_SIZE(gta02_iodesc)); - s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(gta02_uartcfgs, ARRAY_SIZE(gta02_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } @@ -585,6 +584,11 @@ static void __init gta02_machine_init(void) regulator_has_full_constraints(); } +static void __init gta02_init_time(void) +{ + s3c2442_init_clocks(12000000); + samsung_timer_init(); +} MACHINE_START(NEO1973_GTA02, "GTA02") /* Maintainer: Nelson Castillo */ @@ -592,6 +596,6 @@ MACHINE_START(NEO1973_GTA02, "GTA02") .map_io = gta02_map_io, .init_irq = s3c2442_init_irq, .init_machine = gta02_machine_init, - .init_time = samsung_timer_init, + .init_time = gta02_init_time, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c index e453acd92cbf5c..fbf5487ae5d199 100644 --- a/arch/arm/mach-s3c24xx/mach-h1940.c +++ b/arch/arm/mach-s3c24xx/mach-h1940.c @@ -57,7 +57,6 @@ #include #include -#include #include #include #include @@ -646,7 +645,6 @@ static struct platform_device *h1940_devices[] __initdata = { static void __init h1940_map_io(void) { s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc)); - s3c24xx_init_clocks(0); s3c24xx_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); @@ -662,6 +660,12 @@ static void __init h1940_map_io(void) WARN_ON(gpiochip_add(&h1940_latch_gpiochip)); } +static void __init h1940_init_time(void) +{ + s3c2410_init_clocks(12000000); + samsung_timer_init(); +} + /* H1940 and RX3715 need to reserve this for suspend */ static void __init h1940_reserve(void) { @@ -739,6 +743,6 @@ MACHINE_START(H1940, "IPAQ-H1940") .reserve = h1940_reserve, .init_irq = s3c2410_init_irq, .init_machine = h1940_init, - .init_time = samsung_timer_init, + .init_time = h1940_init_time, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c index 5faa7239e7d6d9..e81ea82c55f9de 100644 --- a/arch/arm/mach-s3c24xx/mach-jive.c +++ b/arch/arm/mach-s3c24xx/mach-jive.c @@ -507,11 +507,16 @@ static struct syscore_ops jive_pm_syscore_ops = { static void __init jive_map_io(void) { s3c24xx_init_io(jive_iodesc, ARRAY_SIZE(jive_iodesc)); - s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(jive_uartcfgs, ARRAY_SIZE(jive_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init jive_init_time(void) +{ + s3c2412_init_clocks(12000000); + samsung_timer_init(); +} + static void jive_power_off(void) { printk(KERN_INFO "powering system down...\n"); @@ -665,6 +670,6 @@ MACHINE_START(JIVE, "JIVE") .init_irq = s3c2412_init_irq, .map_io = jive_map_io, .init_machine = jive_machine_init, - .init_time = samsung_timer_init, + .init_time = jive_init_time, .restart = s3c2412_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c index 9e57fd9f4f3bcb..5cc40ec1d2541f 100644 --- a/arch/arm/mach-s3c24xx/mach-mini2440.c +++ b/arch/arm/mach-s3c24xx/mach-mini2440.c @@ -54,7 +54,6 @@ #include #include -#include #include #include #include @@ -525,11 +524,16 @@ static struct platform_device *mini2440_devices[] __initdata = { static void __init mini2440_map_io(void) { s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc)); - s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init mini2440_init_time(void) +{ + s3c2440_init_clocks(12000000); + samsung_timer_init(); +} + /* * mini2440_features string * @@ -690,6 +694,6 @@ MACHINE_START(MINI2440, "MINI2440") .map_io = mini2440_map_io, .init_machine = mini2440_init, .init_irq = s3c2440_init_irq, - .init_time = samsung_timer_init, + .init_time = mini2440_init_time, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-n30.c b/arch/arm/mach-s3c24xx/mach-n30.c index 4cccaad34847d6..3ac2a54348d6f1 100644 --- a/arch/arm/mach-s3c24xx/mach-n30.c +++ b/arch/arm/mach-s3c24xx/mach-n30.c @@ -45,7 +45,6 @@ #include -#include #include #include #include @@ -535,11 +534,16 @@ static void __init n30_map_io(void) { s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc)); n30_hwinit(); - s3c24xx_init_clocks(0); s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init n30_init_time(void) +{ + s3c2410_init_clocks(12000000); + samsung_timer_init(); +} + /* GPB3 is the line that controls the pull-up for the USB D+ line */ static void __init n30_init(void) @@ -591,7 +595,7 @@ MACHINE_START(N30, "Acer-N30") Ben Dooks */ .atag_offset = 0x100, - .init_time = samsung_timer_init, + .init_time = n30_init_time, .init_machine = n30_init, .init_irq = s3c2410_init_irq, .map_io = n30_map_io, @@ -602,7 +606,7 @@ MACHINE_START(N35, "Acer-N35") /* Maintainer: Christer Weinigel */ .atag_offset = 0x100, - .init_time = samsung_timer_init, + .init_time = n30_init_time, .init_machine = n30_init, .init_irq = s3c2410_init_irq, .map_io = n30_map_io, diff --git a/arch/arm/mach-s3c24xx/mach-nexcoder.c b/arch/arm/mach-s3c24xx/mach-nexcoder.c index 3066851f584d4c..c82c281ce351fa 100644 --- a/arch/arm/mach-s3c24xx/mach-nexcoder.c +++ b/arch/arm/mach-s3c24xx/mach-nexcoder.c @@ -42,7 +42,6 @@ #include #include -#include #include #include #include @@ -135,13 +134,18 @@ static void __init nexcoder_sensorboard_init(void) static void __init nexcoder_map_io(void) { s3c24xx_init_io(nexcoder_iodesc, ARRAY_SIZE(nexcoder_iodesc)); - s3c24xx_init_clocks(0); s3c24xx_init_uarts(nexcoder_uartcfgs, ARRAY_SIZE(nexcoder_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); nexcoder_sensorboard_init(); } +static void __init nexcoder_init_time(void) +{ + s3c2440_init_clocks(12000000); + samsung_timer_init(); +} + static void __init nexcoder_init(void) { s3c_i2c0_set_platdata(NULL); @@ -154,6 +158,6 @@ MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440") .map_io = nexcoder_map_io, .init_machine = nexcoder_init, .init_irq = s3c2440_init_irq, - .init_time = samsung_timer_init, + .init_time = nexcoder_init_time, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c index a4ae4bb3666da1..189147b80ecae6 100644 --- a/arch/arm/mach-s3c24xx/mach-osiris.c +++ b/arch/arm/mach-s3c24xx/mach-osiris.c @@ -40,7 +40,6 @@ #include #include -#include #include #include #include @@ -344,20 +343,13 @@ static struct i2c_board_info osiris_i2c_devs[] __initdata = { /* Standard Osiris devices */ static struct platform_device *osiris_devices[] __initdata = { + &s3c2410_device_dclk, &s3c_device_i2c0, &s3c_device_wdt, &s3c_device_nand, &osiris_pcmcia, }; -static struct clk *osiris_clocks[] __initdata = { - &s3c24xx_dclk0, - &s3c24xx_dclk1, - &s3c24xx_clkout0, - &s3c24xx_clkout1, - &s3c24xx_uclk, -}; - static struct s3c_cpufreq_board __initdata osiris_cpufreq = { .refresh = 7800, /* refresh period is 7.8usec */ .auto_io = 1, @@ -368,23 +360,7 @@ static void __init osiris_map_io(void) { unsigned long flags; - /* initialise the clocks */ - - s3c24xx_dclk0.parent = &clk_upll; - s3c24xx_dclk0.rate = 12*1000*1000; - - s3c24xx_dclk1.parent = &clk_upll; - s3c24xx_dclk1.rate = 24*1000*1000; - - s3c24xx_clkout0.parent = &s3c24xx_dclk0; - s3c24xx_clkout1.parent = &s3c24xx_dclk1; - - s3c24xx_uclk.parent = &s3c24xx_clkout1; - - s3c24xx_register_clocks(osiris_clocks, ARRAY_SIZE(osiris_clocks)); - s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc)); - s3c24xx_init_clocks(0); s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); @@ -408,6 +384,12 @@ static void __init osiris_map_io(void) local_irq_restore(flags); } +static void __init osiris_init_time(void) +{ + s3c2440_init_clocks(12000000); + samsung_timer_init(); +} + static void __init osiris_init(void) { register_syscore_ops(&osiris_pm_syscore_ops); @@ -429,6 +411,6 @@ MACHINE_START(OSIRIS, "Simtec-OSIRIS") .map_io = osiris_map_io, .init_irq = s3c2440_init_irq, .init_machine = osiris_init, - .init_time = samsung_timer_init, + .init_time = osiris_init_time, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-otom.c b/arch/arm/mach-s3c24xx/mach-otom.c index bdb3faac2d9b44..45833001186dfe 100644 --- a/arch/arm/mach-s3c24xx/mach-otom.c +++ b/arch/arm/mach-s3c24xx/mach-otom.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -100,11 +99,16 @@ static struct platform_device *otom11_devices[] __initdata = { static void __init otom11_map_io(void) { s3c24xx_init_io(otom11_iodesc, ARRAY_SIZE(otom11_iodesc)); - s3c24xx_init_clocks(0); s3c24xx_init_uarts(otom11_uartcfgs, ARRAY_SIZE(otom11_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init otom11_init_time(void) +{ + s3c2410_init_clocks(12000000); + samsung_timer_init(); +} + static void __init otom11_init(void) { s3c_i2c0_set_platdata(NULL); @@ -117,6 +121,6 @@ MACHINE_START(OTOM, "Nex Vision - Otom 1.1") .map_io = otom11_map_io, .init_machine = otom11_init, .init_irq = s3c2410_init_irq, - .init_time = samsung_timer_init, + .init_time = otom11_init_time, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c index 8c12787a8fd385..228c9094519d82 100644 --- a/arch/arm/mach-s3c24xx/mach-qt2410.c +++ b/arch/arm/mach-s3c24xx/mach-qt2410.c @@ -304,11 +304,16 @@ __setup("tft=", qt2410_tft_setup); static void __init qt2410_map_io(void) { s3c24xx_init_io(qt2410_iodesc, ARRAY_SIZE(qt2410_iodesc)); - s3c24xx_init_clocks(12*1000*1000); s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init qt2410_init_time(void) +{ + s3c2410_init_clocks(12000000); + samsung_timer_init(); +} + static void __init qt2410_machine_init(void) { s3c_nand_set_platdata(&qt2410_nand_info); @@ -346,6 +351,6 @@ MACHINE_START(QT2410, "QT2410") .map_io = qt2410_map_io, .init_irq = s3c2410_init_irq, .init_machine = qt2410_machine_init, - .init_time = samsung_timer_init, + .init_time = qt2410_init_time, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c index afb784e934c8b9..e2c6541909c1de 100644 --- a/arch/arm/mach-s3c24xx/mach-rx1950.c +++ b/arch/arm/mach-s3c24xx/mach-rx1950.c @@ -54,7 +54,6 @@ #include #include -#include #include #include #include @@ -710,6 +709,7 @@ static struct i2c_board_info rx1950_i2c_devices[] = { }; static struct platform_device *rx1950_devices[] __initdata = { + &s3c2410_device_dclk, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, @@ -728,20 +728,9 @@ static struct platform_device *rx1950_devices[] __initdata = { &rx1950_leds, }; -static struct clk *rx1950_clocks[] __initdata = { - &s3c24xx_clkout0, - &s3c24xx_clkout1, -}; - static void __init rx1950_map_io(void) { - s3c24xx_clkout0.parent = &clk_h; - s3c24xx_clkout1.parent = &clk_f; - - s3c24xx_register_clocks(rx1950_clocks, ARRAY_SIZE(rx1950_clocks)); - s3c24xx_init_io(rx1950_iodesc, ARRAY_SIZE(rx1950_iodesc)); - s3c24xx_init_clocks(16934000); s3c24xx_init_uarts(rx1950_uartcfgs, ARRAY_SIZE(rx1950_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); @@ -754,6 +743,12 @@ static void __init rx1950_map_io(void) s3c_pm_init(); } +static void __init rx1950_init_time(void) +{ + s3c2442_init_clocks(16934000); + samsung_timer_init(); +} + static void __init rx1950_init_machine(void) { int i; @@ -816,6 +811,6 @@ MACHINE_START(RX1950, "HP iPAQ RX1950") .reserve = rx1950_reserve, .init_irq = s3c2442_init_irq, .init_machine = rx1950_init_machine, - .init_time = samsung_timer_init, + .init_time = rx1950_init_time, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c index e6535ce1bc5ce4..6e749ec3a2ea53 100644 --- a/arch/arm/mach-s3c24xx/mach-rx3715.c +++ b/arch/arm/mach-s3c24xx/mach-rx3715.c @@ -46,7 +46,6 @@ #include #include -#include #include #include #include @@ -179,11 +178,16 @@ static struct platform_device *rx3715_devices[] __initdata = { static void __init rx3715_map_io(void) { s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc)); - s3c24xx_init_clocks(16934000); s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init rx3715_init_time(void) +{ + s3c2440_init_clocks(16934000); + samsung_timer_init(); +} + /* H1940 and RX3715 need to reserve this for suspend */ static void __init rx3715_reserve(void) { @@ -210,6 +214,6 @@ MACHINE_START(RX3715, "IPAQ-RX3715") .reserve = rx3715_reserve, .init_irq = s3c2440_init_irq, .init_machine = rx3715_init_machine, - .init_time = samsung_timer_init, + .init_time = rx3715_init_time, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-s3c2416-dt.c b/arch/arm/mach-s3c24xx/mach-s3c2416-dt.c index 70f0900d4bcac2..e4dcb9aa2ca29e 100644 --- a/arch/arm/mach-s3c24xx/mach-s3c2416-dt.c +++ b/arch/arm/mach-s3c24xx/mach-s3c2416-dt.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -29,48 +28,14 @@ #include "common.h" -/* - * The following lookup table is used to override device names when devices - * are registered from device tree. This is temporarily added to enable - * device tree support addition for the S3C2416 architecture. - * - * For drivers that require platform data to be provided from the machine - * file, a platform data pointer can also be supplied along with the - * devices names. Usually, the platform data elements that cannot be parsed - * from the device tree by the drivers (example: function pointers) are - * supplied. But it should be noted that this is a temporary mechanism and - * at some point, the drivers should be capable of parsing all the platform - * data from the device tree. - */ -static const struct of_dev_auxdata s3c2416_auxdata_lookup[] __initconst = { - OF_DEV_AUXDATA("samsung,s3c2440-uart", S3C24XX_PA_UART, - "s3c2440-uart.0", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-uart", S3C24XX_PA_UART + 0x4000, - "s3c2440-uart.1", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-uart", S3C24XX_PA_UART + 0x8000, - "s3c2440-uart.2", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-uart", S3C24XX_PA_UART + 0xC000, - "s3c2440-uart.3", NULL), - OF_DEV_AUXDATA("samsung,s3c6410-sdhci", S3C_PA_HSMMC0, - "s3c-sdhci.0", NULL), - OF_DEV_AUXDATA("samsung,s3c6410-sdhci", S3C_PA_HSMMC1, - "s3c-sdhci.1", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", S3C_PA_IIC, - "s3c2440-i2c.0", NULL), - {}, -}; - static void __init s3c2416_dt_map_io(void) { s3c24xx_init_io(NULL, 0); - s3c24xx_init_clocks(12000000); } static void __init s3c2416_dt_machine_init(void) { - of_platform_populate(NULL, of_default_bus_match_table, - s3c2416_auxdata_lookup, NULL); - + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); s3c_pm_init(); } @@ -86,6 +51,5 @@ DT_MACHINE_START(S3C2416_DT, "Samsung S3C2416 (Flattened Device Tree)") .map_io = s3c2416_dt_map_io, .init_irq = irqchip_init, .init_machine = s3c2416_dt_machine_init, - .init_time = clocksource_of_init, .restart = s3c2416_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2410.c b/arch/arm/mach-s3c24xx/mach-smdk2410.c index f32924ee0e9f67..419fadd6e44684 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2410.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2410.c @@ -99,11 +99,16 @@ static struct platform_device *smdk2410_devices[] __initdata = { static void __init smdk2410_map_io(void) { s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc)); - s3c24xx_init_clocks(0); s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init smdk2410_init_time(void) +{ + s3c2410_init_clocks(12000000); + samsung_timer_init(); +} + static void __init smdk2410_init(void) { s3c_i2c0_set_platdata(NULL); @@ -118,6 +123,6 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switc .map_io = smdk2410_map_io, .init_irq = s3c2410_init_irq, .init_machine = smdk2410_init, - .init_time = samsung_timer_init, + .init_time = smdk2410_init_time, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2413.c b/arch/arm/mach-s3c24xx/mach-smdk2413.c index 233fe52d2015a5..a38f8a049e2268 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2413.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2413.c @@ -106,11 +106,16 @@ static void __init smdk2413_fixup(struct tag *tags, char **cmdline, static void __init smdk2413_map_io(void) { s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc)); - s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init smdk2413_init_time(void) +{ + s3c2412_init_clocks(12000000); + samsung_timer_init(); +} + static void __init smdk2413_machine_init(void) { /* Turn off suspend on both USB ports, and switch the * selectable USB port to USB device mode. */ @@ -159,6 +164,6 @@ MACHINE_START(SMDK2413, "SMDK2413") .init_irq = s3c2412_init_irq, .map_io = smdk2413_map_io, .init_machine = smdk2413_machine_init, - .init_time = samsung_timer_init, + .init_time = smdk2413_init_time, .restart = s3c2412_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c index b3b54d8e1410dc..fa6f30d23601d2 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2416.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c @@ -219,10 +219,15 @@ static struct platform_device *smdk2416_devices[] __initdata = { &s3c2443_device_dma, }; +static void __init smdk2416_init_time(void) +{ + s3c2416_init_clocks(12000000); + samsung_timer_init(); +} + static void __init smdk2416_map_io(void) { s3c24xx_init_io(smdk2416_iodesc, ARRAY_SIZE(smdk2416_iodesc)); - s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smdk2416_uartcfgs, ARRAY_SIZE(smdk2416_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } @@ -257,6 +262,6 @@ MACHINE_START(SMDK2416, "SMDK2416") .init_irq = s3c2416_init_irq, .map_io = smdk2416_map_io, .init_machine = smdk2416_machine_init, - .init_time = samsung_timer_init, + .init_time = smdk2416_init_time, .restart = s3c2416_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2440.c b/arch/arm/mach-s3c24xx/mach-smdk2440.c index d071dcfea5480d..5fb89c0ae17aaa 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2440.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2440.c @@ -38,7 +38,6 @@ #include #include -#include #include #include #include @@ -159,11 +158,16 @@ static struct platform_device *smdk2440_devices[] __initdata = { static void __init smdk2440_map_io(void) { s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc)); - s3c24xx_init_clocks(16934400); s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init smdk2440_init_time(void) +{ + s3c2440_init_clocks(16934400); + samsung_timer_init(); +} + static void __init smdk2440_machine_init(void) { s3c24xx_fb_set_platdata(&smdk2440_fb_info); @@ -180,6 +184,6 @@ MACHINE_START(S3C2440, "SMDK2440") .init_irq = s3c2440_init_irq, .map_io = smdk2440_map_io, .init_machine = smdk2440_machine_init, - .init_time = samsung_timer_init, + .init_time = smdk2440_init_time, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2443.c b/arch/arm/mach-s3c24xx/mach-smdk2443.c index 06c4d77de3a557..ef5d5ea33182f7 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2443.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2443.c @@ -121,11 +121,16 @@ static struct platform_device *smdk2443_devices[] __initdata = { static void __init smdk2443_map_io(void) { s3c24xx_init_io(smdk2443_iodesc, ARRAY_SIZE(smdk2443_iodesc)); - s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smdk2443_uartcfgs, ARRAY_SIZE(smdk2443_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init smdk2443_init_time(void) +{ + s3c2443_init_clocks(12000000); + samsung_timer_init(); +} + static void __init smdk2443_machine_init(void) { s3c_i2c0_set_platdata(NULL); @@ -145,6 +150,6 @@ MACHINE_START(SMDK2443, "SMDK2443") .init_irq = s3c2443_init_irq, .map_io = smdk2443_map_io, .init_machine = smdk2443_machine_init, - .init_time = samsung_timer_init, + .init_time = smdk2443_init_time, .restart = s3c2443_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-tct_hammer.c b/arch/arm/mach-s3c24xx/mach-tct_hammer.c index 4108b2f0cede26..c616ca2d409e93 100644 --- a/arch/arm/mach-s3c24xx/mach-tct_hammer.c +++ b/arch/arm/mach-s3c24xx/mach-tct_hammer.c @@ -135,11 +135,16 @@ static struct platform_device *tct_hammer_devices[] __initdata = { static void __init tct_hammer_map_io(void) { s3c24xx_init_io(tct_hammer_iodesc, ARRAY_SIZE(tct_hammer_iodesc)); - s3c24xx_init_clocks(0); s3c24xx_init_uarts(tct_hammer_uartcfgs, ARRAY_SIZE(tct_hammer_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init tct_hammer_init_time(void) +{ + s3c2410_init_clocks(12000000); + samsung_timer_init(); +} + static void __init tct_hammer_init(void) { s3c_i2c0_set_platdata(NULL); @@ -151,6 +156,6 @@ MACHINE_START(TCT_HAMMER, "TCT_HAMMER") .map_io = tct_hammer_map_io, .init_irq = s3c2410_init_irq, .init_machine = tct_hammer_init, - .init_time = samsung_timer_init, + .init_time = tct_hammer_init_time, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-vr1000.c b/arch/arm/mach-s3c24xx/mach-vr1000.c index 1cc5b1bd51cd0f..f88c584c30017a 100644 --- a/arch/arm/mach-s3c24xx/mach-vr1000.c +++ b/arch/arm/mach-s3c24xx/mach-vr1000.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include @@ -286,6 +285,7 @@ static struct i2c_board_info vr1000_i2c_devs[] __initdata = { /* devices for this board */ static struct platform_device *vr1000_devices[] __initdata = { + &s3c2410_device_dclk, &s3c_device_ohci, &s3c_device_lcd, &s3c_device_wdt, @@ -299,14 +299,6 @@ static struct platform_device *vr1000_devices[] __initdata = { &vr1000_led3, }; -static struct clk *vr1000_clocks[] __initdata = { - &s3c24xx_dclk0, - &s3c24xx_dclk1, - &s3c24xx_clkout0, - &s3c24xx_clkout1, - &s3c24xx_uclk, -}; - static void vr1000_power_off(void) { gpio_direction_output(S3C2410_GPB(9), 1); @@ -314,29 +306,19 @@ static void vr1000_power_off(void) static void __init vr1000_map_io(void) { - /* initialise clock sources */ - - s3c24xx_dclk0.parent = &clk_upll; - s3c24xx_dclk0.rate = 12*1000*1000; - - s3c24xx_dclk1.parent = NULL; - s3c24xx_dclk1.rate = 3692307; - - s3c24xx_clkout0.parent = &s3c24xx_dclk0; - s3c24xx_clkout1.parent = &s3c24xx_dclk1; - - s3c24xx_uclk.parent = &s3c24xx_clkout1; - - s3c24xx_register_clocks(vr1000_clocks, ARRAY_SIZE(vr1000_clocks)); - pm_power_off = vr1000_power_off; s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc)); - s3c24xx_init_clocks(0); s3c24xx_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init vr1000_init_time(void) +{ + s3c2410_init_clocks(12000000); + samsung_timer_init(); +} + static void __init vr1000_init(void) { s3c_i2c0_set_platdata(NULL); @@ -357,6 +339,6 @@ MACHINE_START(VR1000, "Thorcom-VR1000") .map_io = vr1000_map_io, .init_machine = vr1000_init, .init_irq = s3c2410_init_irq, - .init_time = samsung_timer_init, + .init_time = vr1000_init_time, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c index 40868c0e0a683e..6b706c915387b9 100644 --- a/arch/arm/mach-s3c24xx/mach-vstms.c +++ b/arch/arm/mach-s3c24xx/mach-vstms.c @@ -142,11 +142,16 @@ static void __init vstms_fixup(struct tag *tags, char **cmdline, static void __init vstms_map_io(void) { s3c24xx_init_io(vstms_iodesc, ARRAY_SIZE(vstms_iodesc)); - s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(vstms_uartcfgs, ARRAY_SIZE(vstms_uartcfgs)); samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } +static void __init vstms_init_time(void) +{ + s3c2412_init_clocks(12000000); + samsung_timer_init(); +} + static void __init vstms_init(void) { s3c_i2c0_set_platdata(NULL); @@ -162,6 +167,6 @@ MACHINE_START(VSTMS, "VSTMS") .init_irq = s3c2412_init_irq, .init_machine = vstms_init, .map_io = vstms_map_io, - .init_time = samsung_timer_init, + .init_time = vstms_init_time, .restart = s3c2412_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/pm.c b/arch/arm/mach-s3c24xx/pm.c index 68ea5b7e5dc7d5..b19256ec8d407c 100644 --- a/arch/arm/mach-s3c24xx/pm.c +++ b/arch/arm/mach-s3c24xx/pm.c @@ -51,9 +51,6 @@ #define PFX "s3c24xx-pm: " static struct sleep_save core_save[] = { - SAVE_ITEM(S3C2410_LOCKTIME), - SAVE_ITEM(S3C2410_CLKCON), - /* we restore the timings here, with the proviso that the board * brings the system up in an slower, or equal frequency setting * to the original system. @@ -69,18 +66,6 @@ static struct sleep_save core_save[] = { SAVE_ITEM(S3C2410_BANKCON3), SAVE_ITEM(S3C2410_BANKCON4), SAVE_ITEM(S3C2410_BANKCON5), - -#ifndef CONFIG_CPU_FREQ - SAVE_ITEM(S3C2410_CLKDIVN), - SAVE_ITEM(S3C2410_MPLLCON), - SAVE_ITEM(S3C2410_REFRESH), -#endif - SAVE_ITEM(S3C2410_UPLLCON), - SAVE_ITEM(S3C2410_CLKSLOW), -}; - -static struct sleep_save misc_save[] = { - SAVE_ITEM(S3C2410_DCLKCON), }; /* s3c_pm_check_resume_pin @@ -140,12 +125,10 @@ void s3c_pm_configure_extint(void) void s3c_pm_restore_core(void) { s3c_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); - s3c_pm_do_restore(misc_save, ARRAY_SIZE(misc_save)); } void s3c_pm_save_core(void) { - s3c_pm_do_save(misc_save, ARRAY_SIZE(misc_save)); s3c_pm_do_save(core_save, ARRAY_SIZE(core_save)); } diff --git a/arch/arm/mach-s3c24xx/s3c2410.c b/arch/arm/mach-s3c24xx/s3c2410.c index 04b58cb4988860..7eab888298836e 100644 --- a/arch/arm/mach-s3c24xx/s3c2410.c +++ b/arch/arm/mach-s3c24xx/s3c2410.c @@ -85,62 +85,6 @@ void __init s3c2410_map_io(void) void __init_or_cpufreq s3c2410_setup_clocks(void) { - struct clk *xtal_clk; - unsigned long tmp; - unsigned long xtal; - unsigned long fclk; - unsigned long hclk; - unsigned long pclk; - - xtal_clk = clk_get(NULL, "xtal"); - xtal = clk_get_rate(xtal_clk); - clk_put(xtal_clk); - - /* now we've got our machine bits initialised, work out what - * clocks we've got */ - - fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal); - - tmp = __raw_readl(S3C2410_CLKDIVN); - - /* work out clock scalings */ - - hclk = fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1); - pclk = hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1); - - /* print brieft summary of clocks, etc */ - - printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", - print_mhz(fclk), print_mhz(hclk), print_mhz(pclk)); - - /* initialise the clocks here, to allow other things like the - * console to use them - */ - - s3c24xx_setup_clocks(fclk, hclk, pclk); -} - -/* fake ARMCLK for use with cpufreq, etc. */ - -static struct clk s3c2410_armclk = { - .name = "armclk", - .parent = &clk_f, - .id = -1, -}; - -static struct clk_lookup s3c2410_clk_lookup[] = { - CLKDEV_INIT(NULL, "clk_uart_baud0", &clk_p), - CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk), -}; - -void __init s3c2410_init_clocks(int xtal) -{ - s3c24xx_register_baseclocks(xtal); - s3c2410_setup_clocks(); - s3c2410_baseclk_add(); - s3c24xx_register_clock(&s3c2410_armclk); - clkdev_add_table(s3c2410_clk_lookup, ARRAY_SIZE(s3c2410_clk_lookup)); - samsung_wdt_reset_init(S3C24XX_VA_WATCHDOG); } struct bus_type s3c2410_subsys = { diff --git a/arch/arm/mach-s3c24xx/s3c2412.c b/arch/arm/mach-s3c24xx/s3c2412.c index 657cbaca80ac46..d49f52fbc842d1 100644 --- a/arch/arm/mach-s3c24xx/s3c2412.c +++ b/arch/arm/mach-s3c24xx/s3c2412.c @@ -173,49 +173,6 @@ void __init s3c2412_map_io(void) void __init_or_cpufreq s3c2412_setup_clocks(void) { - struct clk *xtal_clk; - unsigned long tmp; - unsigned long xtal; - unsigned long fclk; - unsigned long hclk; - unsigned long pclk; - - xtal_clk = clk_get(NULL, "xtal"); - xtal = clk_get_rate(xtal_clk); - clk_put(xtal_clk); - - /* now we've got our machine bits initialised, work out what - * clocks we've got */ - - fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal * 2); - - clk_mpll.rate = fclk; - - tmp = __raw_readl(S3C2410_CLKDIVN); - - /* work out clock scalings */ - - hclk = fclk / ((tmp & S3C2412_CLKDIVN_HDIVN_MASK) + 1); - hclk /= ((tmp & S3C2412_CLKDIVN_ARMDIVN) ? 2 : 1); - pclk = hclk / ((tmp & S3C2412_CLKDIVN_PDIVN) ? 2 : 1); - - /* print brieft summary of clocks, etc */ - - printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", - print_mhz(fclk), print_mhz(hclk), print_mhz(pclk)); - - s3c24xx_setup_clocks(fclk, hclk, pclk); -} - -void __init s3c2412_init_clocks(int xtal) -{ - /* initialise the clocks here, to allow other things like the - * console to use them - */ - - s3c24xx_register_baseclocks(xtal); - s3c2412_setup_clocks(); - s3c2412_baseclk_add(); } /* need to register the subsystem before we actually register the device, and diff --git a/arch/arm/mach-s3c24xx/s3c2442.c b/arch/arm/mach-s3c24xx/s3c2442.c index 2c8adc02853861..fb9da2b603a2d2 100644 --- a/arch/arm/mach-s3c24xx/s3c2442.c +++ b/arch/arm/mach-s3c24xx/s3c2442.c @@ -53,117 +53,6 @@ #include "common.h" -/* S3C2442 extended clock support */ - -static unsigned long s3c2442_camif_upll_round(struct clk *clk, - unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - int div; - - if (rate > parent_rate) - return parent_rate; - - div = parent_rate / rate; - - if (div == 3) - return parent_rate / 3; - - /* note, we remove the +/- 1 calculations for the divisor */ - - div /= 2; - - if (div < 1) - div = 1; - else if (div > 16) - div = 16; - - return parent_rate / (div * 2); -} - -static int s3c2442_camif_upll_setrate(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN); - - rate = s3c2442_camif_upll_round(clk, rate); - - camdivn &= ~S3C2442_CAMDIVN_CAMCLK_DIV3; - - if (rate == parent_rate) { - camdivn &= ~S3C2440_CAMDIVN_CAMCLK_SEL; - } else if ((parent_rate / rate) == 3) { - camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL; - camdivn |= S3C2442_CAMDIVN_CAMCLK_DIV3; - } else { - camdivn &= ~S3C2440_CAMDIVN_CAMCLK_MASK; - camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL; - camdivn |= (((parent_rate / rate) / 2) - 1); - } - - __raw_writel(camdivn, S3C2440_CAMDIVN); - - return 0; -} - -/* Extra S3C2442 clocks */ - -static struct clk s3c2442_clk_cam = { - .name = "camif", - .id = -1, - .enable = s3c2410_clkcon_enable, - .ctrlbit = S3C2440_CLKCON_CAMERA, -}; - -static struct clk s3c2442_clk_cam_upll = { - .name = "camif-upll", - .id = -1, - .ops = &(struct clk_ops) { - .set_rate = s3c2442_camif_upll_setrate, - .round_rate = s3c2442_camif_upll_round, - }, -}; - -static int s3c2442_clk_add(struct device *dev, struct subsys_interface *sif) -{ - struct clk *clock_upll; - struct clk *clock_h; - struct clk *clock_p; - - clock_p = clk_get(NULL, "pclk"); - clock_h = clk_get(NULL, "hclk"); - clock_upll = clk_get(NULL, "upll"); - - if (IS_ERR(clock_p) || IS_ERR(clock_h) || IS_ERR(clock_upll)) { - printk(KERN_ERR "S3C2442: Failed to get parent clocks\n"); - return -EINVAL; - } - - s3c2442_clk_cam.parent = clock_h; - s3c2442_clk_cam_upll.parent = clock_upll; - - s3c24xx_register_clock(&s3c2442_clk_cam); - s3c24xx_register_clock(&s3c2442_clk_cam_upll); - - clk_disable(&s3c2442_clk_cam); - - return 0; -} - -static struct subsys_interface s3c2442_clk_interface = { - .name = "s3c2442_clk", - .subsys = &s3c2442_subsys, - .add_dev = s3c2442_clk_add, -}; - -static __init int s3c2442_clk_init(void) -{ - return subsys_interface_register(&s3c2442_clk_interface); -} - -arch_initcall(s3c2442_clk_init); - - static struct device s3c2442_dev = { .bus = &s3c2442_subsys, }; diff --git a/arch/arm/mach-s3c24xx/s3c244x.c b/arch/arm/mach-s3c24xx/s3c244x.c index fe30ebb234d282..4a64bcc9eb515e 100644 --- a/arch/arm/mach-s3c24xx/s3c244x.c +++ b/arch/arm/mach-s3c24xx/s3c244x.c @@ -46,6 +46,7 @@ #include #include +#include "common.h" #include "regs-dsc.h" static struct map_desc s3c244x_iodesc[] __initdata = { @@ -74,67 +75,11 @@ void __init s3c244x_map_io(void) s3c_nand_setname("s3c2440-nand"); s3c_device_ts.name = "s3c2440-ts"; s3c_device_usbgadget.name = "s3c2440-usbgadget"; + s3c2410_device_dclk.name = "s3c2440-dclk"; } void __init_or_cpufreq s3c244x_setup_clocks(void) { - struct clk *xtal_clk; - unsigned long clkdiv; - unsigned long camdiv; - unsigned long xtal; - unsigned long hclk, fclk, pclk; - int hdiv = 1; - - xtal_clk = clk_get(NULL, "xtal"); - xtal = clk_get_rate(xtal_clk); - clk_put(xtal_clk); - - fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2; - - clkdiv = __raw_readl(S3C2410_CLKDIVN); - camdiv = __raw_readl(S3C2440_CAMDIVN); - - /* work out clock scalings */ - - switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) { - case S3C2440_CLKDIVN_HDIVN_1: - hdiv = 1; - break; - - case S3C2440_CLKDIVN_HDIVN_2: - hdiv = 2; - break; - - case S3C2440_CLKDIVN_HDIVN_4_8: - hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4; - break; - - case S3C2440_CLKDIVN_HDIVN_3_6: - hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3; - break; - } - - hclk = fclk / hdiv; - pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1); - - /* print brief summary of clocks, etc */ - - printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", - print_mhz(fclk), print_mhz(hclk), print_mhz(pclk)); - - s3c24xx_setup_clocks(fclk, hclk, pclk); -} - -void __init s3c244x_init_clocks(int xtal) -{ - /* initialise the clocks here, to allow other things like the - * console to use them, and to add new ones after the initialisation - */ - - s3c24xx_register_baseclocks(xtal); - s3c244x_setup_clocks(); - s3c2410_baseclk_add(); - samsung_wdt_reset_init(S3C24XX_VA_WATCHDOG); } /* Since the S3C2442 and S3C2440 share items, put both subsystems here */ diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 0f92ba8e788415..037c00622de69f 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -108,6 +108,7 @@ config ARCH_R8A7778 select SH_CLK_CPG select ARM_GIC select SYS_SUPPORTS_SH_TMU + select RENESAS_INTC_IRQPIN config ARCH_R8A7779 bool "R-Car H1 (R8A77790)" @@ -140,16 +141,6 @@ config ARCH_R8A7791 select SYS_SUPPORTS_SH_CMT select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE -config ARCH_EMEV2 - bool "Emma Mobile EV2" - select ARCH_WANT_OPTIONAL_GPIOLIB - select ARM_GIC - select CPU_V7 - select MIGHT_HAVE_PCI - select USE_OF - select AUTO_ZRELADDR - select SYS_SUPPORTS_EM_STI - config ARCH_R7S72100 bool "RZ/A1H (R7S72100)" select ARCH_WANT_OPTIONAL_GPIOLIB @@ -205,8 +196,8 @@ config MACH_ARMADILLO800EVA_REFERENCE select SND_SOC_WM8978 if SND_SIMPLE_CARD select USE_OF ---help--- - Use reference implementation of Aramdillo800 EVA board support - which makes a greater use of device tree at the expense + Use reference implementation of Armadillo800 EVA board support + which makes greater use of device tree at the expense of not supporting a number of devices. This is intended to aid developers @@ -216,7 +207,6 @@ config MACH_BOCKW depends on ARCH_R8A7778 select ARCH_REQUIRE_GPIOLIB select REGULATOR_FIXED_VOLTAGE if REGULATOR - select RENESAS_INTC_IRQPIN select SND_SOC_AK4554 if SND_SIMPLE_CARD select SND_SOC_AK4642 if SND_SIMPLE_CARD select USE_OF @@ -225,7 +215,6 @@ config MACH_BOCKW_REFERENCE bool "BOCK-W - Reference Device Tree Implementation" depends on ARCH_R8A7778 select ARCH_REQUIRE_GPIOLIB - select RENESAS_INTC_IRQPIN select REGULATOR_FIXED_VOLTAGE if REGULATOR select USE_OF ---help--- diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 4caffc912a81cc..9c5cd8c53a8568 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -21,8 +21,8 @@ obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o obj-$(CONFIG_ARCH_R7S72100) += setup-r7s72100.o # Clock objects -ifndef CONFIG_COMMON_CLK obj-y += clock.o +ifndef CONFIG_COMMON_CLK obj-$(CONFIG_ARCH_SH7372) += clock-sh7372.o obj-$(CONFIG_ARCH_SH73A0) += clock-sh73a0.o obj-$(CONFIG_ARCH_R8A73A4) += clock-r8a73a4.o @@ -31,7 +31,6 @@ obj-$(CONFIG_ARCH_R8A7778) += clock-r8a7778.o obj-$(CONFIG_ARCH_R8A7779) += clock-r8a7779.o obj-$(CONFIG_ARCH_R8A7790) += clock-r8a7790.o obj-$(CONFIG_ARCH_R8A7791) += clock-r8a7791.o -obj-$(CONFIG_ARCH_EMEV2) += clock-emev2.o obj-$(CONFIG_ARCH_R7S72100) += clock-r7s72100.o endif diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c index b4122f8cb8d9ff..f444be2f241ed5 100644 --- a/arch/arm/mach-shmobile/board-bockw.c +++ b/arch/arm/mach-shmobile/board-bockw.c @@ -345,24 +345,39 @@ static struct rsnd_ssi_platform_info rsnd_ssi[] = { RSND_SSI_UNUSED, /* SSI 0 */ RSND_SSI_UNUSED, /* SSI 1 */ RSND_SSI_UNUSED, /* SSI 2 */ - RSND_SSI_SET(1, HPBDMA_SLAVE_HPBIF3_TX, gic_iid(0x85), RSND_SSI_PLAY), - RSND_SSI_SET(2, HPBDMA_SLAVE_HPBIF4_RX, gic_iid(0x85), RSND_SSI_CLK_PIN_SHARE), - RSND_SSI_SET(0, HPBDMA_SLAVE_HPBIF5_TX, gic_iid(0x86), RSND_SSI_PLAY), - RSND_SSI_SET(0, HPBDMA_SLAVE_HPBIF6_RX, gic_iid(0x86), 0), - RSND_SSI_SET(3, HPBDMA_SLAVE_HPBIF7_TX, gic_iid(0x86), RSND_SSI_PLAY), - RSND_SSI_SET(4, HPBDMA_SLAVE_HPBIF8_RX, gic_iid(0x86), RSND_SSI_CLK_PIN_SHARE), + RSND_SSI(HPBDMA_SLAVE_HPBIF3_TX, gic_iid(0x85), 0), + RSND_SSI(HPBDMA_SLAVE_HPBIF4_RX, gic_iid(0x85), RSND_SSI_CLK_PIN_SHARE), + RSND_SSI(HPBDMA_SLAVE_HPBIF5_TX, gic_iid(0x86), 0), + RSND_SSI(HPBDMA_SLAVE_HPBIF6_RX, gic_iid(0x86), 0), + RSND_SSI(HPBDMA_SLAVE_HPBIF7_TX, gic_iid(0x86), 0), + RSND_SSI(HPBDMA_SLAVE_HPBIF8_RX, gic_iid(0x86), RSND_SSI_CLK_PIN_SHARE), }; -static struct rsnd_scu_platform_info rsnd_scu[9] = { - { .flags = 0, }, /* SRU 0 */ - { .flags = 0, }, /* SRU 1 */ - { .flags = 0, }, /* SRU 2 */ - { .flags = RSND_SCU_USE_HPBIF, }, - { .flags = RSND_SCU_USE_HPBIF, }, - { .flags = RSND_SCU_USE_HPBIF, }, - { .flags = RSND_SCU_USE_HPBIF, }, - { .flags = RSND_SCU_USE_HPBIF, }, - { .flags = RSND_SCU_USE_HPBIF, }, +static struct rsnd_src_platform_info rsnd_src[9] = { + RSND_SRC_UNUSED, /* SRU 0 */ + RSND_SRC_UNUSED, /* SRU 1 */ + RSND_SRC_UNUSED, /* SRU 2 */ + RSND_SRC(0, 0), + RSND_SRC(0, 0), + RSND_SRC(0, 0), + RSND_SRC(0, 0), + RSND_SRC(0, 0), + RSND_SRC(0, 0), +}; + +static struct rsnd_dai_platform_info rsnd_dai[] = { + { + .playback = { .ssi = &rsnd_ssi[5], .src = &rsnd_src[5] }, + .capture = { .ssi = &rsnd_ssi[6], .src = &rsnd_src[6] }, + }, { + .playback = { .ssi = &rsnd_ssi[3], .src = &rsnd_src[3] }, + }, { + .capture = { .ssi = &rsnd_ssi[4], .src = &rsnd_src[4] }, + }, { + .playback = { .ssi = &rsnd_ssi[7], .src = &rsnd_src[7] }, + }, { + .capture = { .ssi = &rsnd_ssi[8], .src = &rsnd_src[8] }, + }, }; enum { @@ -437,8 +452,10 @@ static struct rcar_snd_info rsnd_info = { .flags = RSND_GEN1, .ssi_info = rsnd_ssi, .ssi_info_nr = ARRAY_SIZE(rsnd_ssi), - .scu_info = rsnd_scu, - .scu_info_nr = ARRAY_SIZE(rsnd_scu), + .src_info = rsnd_src, + .src_info_nr = ARRAY_SIZE(rsnd_src), + .dai_info = rsnd_dai, + .dai_info_nr = ARRAY_SIZE(rsnd_dai), .start = rsnd_start, .stop = rsnd_stop, }; @@ -591,6 +608,7 @@ static void __init bockw_init(void) { void __iomem *base; struct clk *clk; + struct platform_device *pdev; int i; r8a7778_clock_init(); @@ -673,9 +691,6 @@ static void __init bockw_init(void) } /* for Audio */ - clk = clk_get(NULL, "audio_clk_b"); - clk_set_rate(clk, 24576000); - clk_put(clk); rsnd_codec_power(5, 1); /* enable ak4642 */ platform_device_register_simple( @@ -684,11 +699,15 @@ static void __init bockw_init(void) platform_device_register_simple( "ak4554-adc-dac", 1, NULL, 0); - platform_device_register_resndata( + pdev = platform_device_register_resndata( &platform_bus, "rcar_sound", -1, rsnd_resources, ARRAY_SIZE(rsnd_resources), &rsnd_info, sizeof(rsnd_info)); + clk = clk_get(&pdev->dev, "clk_b"); + clk_set_rate(clk, 24576000); + clk_put(clk); + for (i = 0; i < ARRAY_SIZE(rsnd_card_info); i++) { struct platform_device_info cardinfo = { .parent = &platform_bus, diff --git a/arch/arm/mach-shmobile/board-koelsch-reference.c b/arch/arm/mach-shmobile/board-koelsch-reference.c index a3fd30242bd87d..941f8b394e84c2 100644 --- a/arch/arm/mach-shmobile/board-koelsch-reference.c +++ b/arch/arm/mach-shmobile/board-koelsch-reference.c @@ -19,12 +19,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include #include #include #include #include +#include #include #include #include @@ -82,49 +81,50 @@ static void __init koelsch_add_du_device(void) platform_device_register_full(&info); } -static void __init koelsch_add_standard_devices(void) -{ - /* - * This is a really crude hack to provide clkdev support to the CMT and - * DU devices until they get moved to DT. - */ - static const struct clk_name { - const char *clk; - const char *con_id; - const char *dev_id; - } clk_names[] = { - { "cmt0", NULL, "sh_cmt.0" }, - { "scifa0", NULL, "sh-sci.0" }, - { "scifa1", NULL, "sh-sci.1" }, - { "scifb0", NULL, "sh-sci.2" }, - { "scifb1", NULL, "sh-sci.3" }, - { "scifb2", NULL, "sh-sci.4" }, - { "scifa2", NULL, "sh-sci.5" }, - { "scif0", NULL, "sh-sci.6" }, - { "scif1", NULL, "sh-sci.7" }, - { "scif2", NULL, "sh-sci.8" }, - { "scif3", NULL, "sh-sci.9" }, - { "scif4", NULL, "sh-sci.10" }, - { "scif5", NULL, "sh-sci.11" }, - { "scifa3", NULL, "sh-sci.12" }, - { "scifa4", NULL, "sh-sci.13" }, - { "scifa5", NULL, "sh-sci.14" }, - { "du0", "du.0", "rcar-du-r8a7791" }, - { "du1", "du.1", "rcar-du-r8a7791" }, - { "lvds0", "lvds.0", "rcar-du-r8a7791" }, - }; - struct clk *clk; - unsigned int i; +/* + * This is a really crude hack to provide clkdev support to platform + * devices until they get moved to DT. + */ +static const struct clk_name clk_names[] __initconst = { + { "cmt0", NULL, "sh_cmt.0" }, + { "scifa0", NULL, "sh-sci.0" }, + { "scifa1", NULL, "sh-sci.1" }, + { "scifb0", NULL, "sh-sci.2" }, + { "scifb1", NULL, "sh-sci.3" }, + { "scifb2", NULL, "sh-sci.4" }, + { "scifa2", NULL, "sh-sci.5" }, + { "scif0", NULL, "sh-sci.6" }, + { "scif1", NULL, "sh-sci.7" }, + { "scif2", NULL, "sh-sci.8" }, + { "scif3", NULL, "sh-sci.9" }, + { "scif4", NULL, "sh-sci.10" }, + { "scif5", NULL, "sh-sci.11" }, + { "scifa3", NULL, "sh-sci.12" }, + { "scifa4", NULL, "sh-sci.13" }, + { "scifa5", NULL, "sh-sci.14" }, + { "du0", "du.0", "rcar-du-r8a7791" }, + { "du1", "du.1", "rcar-du-r8a7791" }, + { "lvds0", "lvds.0", "rcar-du-r8a7791" }, +}; - for (i = 0; i < ARRAY_SIZE(clk_names); ++i) { - clk = clk_get(NULL, clk_names[i].clk); - if (!IS_ERR(clk)) { - clk_register_clkdev(clk, clk_names[i].con_id, - clk_names[i].dev_id); - clk_put(clk); - } - } +/* + * This is a really crude hack to work around core platform clock issues + */ +static const struct clk_name clk_enables[] __initconst = { + { "ether", NULL, "ee700000.ethernet" }, + { "i2c2", NULL, "e6530000.i2c" }, + { "msiof0", NULL, "e6e20000.spi" }, + { "qspi_mod", NULL, "e6b10000.spi" }, + { "sdhi0", NULL, "ee100000.sd" }, + { "sdhi1", NULL, "ee140000.sd" }, + { "sdhi2", NULL, "ee160000.sd" }, + { "thermal", NULL, "e61f0000.thermal" }, +}; +static void __init koelsch_add_standard_devices(void) +{ + shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false); + shmobile_clk_workaround(clk_enables, ARRAY_SIZE(clk_enables), true); r8a7791_add_dt_devices(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); diff --git a/arch/arm/mach-shmobile/board-koelsch.c b/arch/arm/mach-shmobile/board-koelsch.c index 5a034ff405d001..a12a9d3b4b6e3c 100644 --- a/arch/arm/mach-shmobile/board-koelsch.c +++ b/arch/arm/mach-shmobile/board-koelsch.c @@ -216,7 +216,7 @@ static const struct spi_board_info spi_info[] __initconst = { { .modalias = "m25p80", .platform_data = &spi_flash_data, - .mode = SPI_MODE_0, + .mode = SPI_MODE_0 | SPI_TX_QUAD | SPI_RX_QUAD, .max_speed_hz = 30000000, .bus_num = 0, .chip_select = 0, diff --git a/arch/arm/mach-shmobile/board-lager-reference.c b/arch/arm/mach-shmobile/board-lager-reference.c index 440aac36d6938d..1eb48cffb4c583 100644 --- a/arch/arm/mach-shmobile/board-lager-reference.c +++ b/arch/arm/mach-shmobile/board-lager-reference.c @@ -18,12 +18,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include #include #include #include #include +#include #include #include #include @@ -86,46 +85,46 @@ static void __init lager_add_du_device(void) platform_device_register_full(&info); } -static void __init lager_add_standard_devices(void) -{ - /* - * This is a really crude hack to provide clkdev support to platform - * devices until they get moved to DT. - */ - static const struct clk_name { - const char *clk; - const char *con_id; - const char *dev_id; - } clk_names[] = { - { "cmt0", NULL, "sh_cmt.0" }, - { "scifa0", NULL, "sh-sci.0" }, - { "scifa1", NULL, "sh-sci.1" }, - { "scifb0", NULL, "sh-sci.2" }, - { "scifb1", NULL, "sh-sci.3" }, - { "scifb2", NULL, "sh-sci.4" }, - { "scifa2", NULL, "sh-sci.5" }, - { "scif0", NULL, "sh-sci.6" }, - { "scif1", NULL, "sh-sci.7" }, - { "hscif0", NULL, "sh-sci.8" }, - { "hscif1", NULL, "sh-sci.9" }, - { "du0", "du.0", "rcar-du-r8a7790" }, - { "du1", "du.1", "rcar-du-r8a7790" }, - { "du2", "du.2", "rcar-du-r8a7790" }, - { "lvds0", "lvds.0", "rcar-du-r8a7790" }, - { "lvds1", "lvds.1", "rcar-du-r8a7790" }, - }; - struct clk *clk; - unsigned int i; +/* + * This is a really crude hack to provide clkdev support to platform + * devices until they get moved to DT. + */ +static const struct clk_name clk_names[] __initconst = { + { "cmt0", NULL, "sh_cmt.0" }, + { "scifa0", NULL, "sh-sci.0" }, + { "scifa1", NULL, "sh-sci.1" }, + { "scifb0", NULL, "sh-sci.2" }, + { "scifb1", NULL, "sh-sci.3" }, + { "scifb2", NULL, "sh-sci.4" }, + { "scifa2", NULL, "sh-sci.5" }, + { "scif0", NULL, "sh-sci.6" }, + { "scif1", NULL, "sh-sci.7" }, + { "hscif0", NULL, "sh-sci.8" }, + { "hscif1", NULL, "sh-sci.9" }, + { "du0", "du.0", "rcar-du-r8a7790" }, + { "du1", "du.1", "rcar-du-r8a7790" }, + { "du2", "du.2", "rcar-du-r8a7790" }, + { "lvds0", "lvds.0", "rcar-du-r8a7790" }, + { "lvds1", "lvds.1", "rcar-du-r8a7790" }, +}; - for (i = 0; i < ARRAY_SIZE(clk_names); ++i) { - clk = clk_get(NULL, clk_names[i].clk); - if (!IS_ERR(clk)) { - clk_register_clkdev(clk, clk_names[i].con_id, - clk_names[i].dev_id); - clk_put(clk); - } - } +/* + * This is a really crude hack to work around core platform clock issues + */ +static const struct clk_name clk_enables[] __initconst = { + { "ether", NULL, "ee700000.ethernet" }, + { "msiof1", NULL, "e6e10000.spi" }, + { "mmcif1", NULL, "ee220000.mmc" }, + { "qspi_mod", NULL, "e6b10000.spi" }, + { "sdhi0", NULL, "ee100000.sd" }, + { "sdhi2", NULL, "ee140000.sd" }, + { "thermal", NULL, "e61f0000.thermal" }, +}; +static void __init lager_add_standard_devices(void) +{ + shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false); + shmobile_clk_workaround(clk_enables, ARRAY_SIZE(clk_enables), true); r8a7790_add_dt_devices(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index 18c7e0311aa679..f8b1e05463ccde 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -325,12 +325,12 @@ static const struct rspi_plat_data qspi_pdata __initconst = { static const struct spi_board_info spi_info[] __initconst = { { - .modalias = "m25p80", - .platform_data = &spi_flash_data, - .mode = SPI_MODE_0, - .max_speed_hz = 30000000, - .bus_num = 0, - .chip_select = 0, + .modalias = "m25p80", + .platform_data = &spi_flash_data, + .mode = SPI_MODE_0 | SPI_TX_QUAD | SPI_RX_QUAD, + .max_speed_hz = 30000000, + .bus_num = 0, + .chip_select = 0, }, }; @@ -567,20 +567,27 @@ static struct resource rsnd_resources[] __initdata = { }; static struct rsnd_ssi_platform_info rsnd_ssi[] = { - RSND_SSI_SET(0, 0, gic_spi(370), RSND_SSI_PLAY), - RSND_SSI_SET(0, 0, gic_spi(371), RSND_SSI_CLK_PIN_SHARE), + RSND_SSI(0, gic_spi(370), 0), + RSND_SSI(0, gic_spi(371), RSND_SSI_CLK_PIN_SHARE), }; -static struct rsnd_scu_platform_info rsnd_scu[2] = { +static struct rsnd_src_platform_info rsnd_src[2] = { /* no member at this point */ }; +static struct rsnd_dai_platform_info rsnd_dai = { + .playback = { .ssi = &rsnd_ssi[0], }, + .capture = { .ssi = &rsnd_ssi[1], }, +}; + static struct rcar_snd_info rsnd_info = { .flags = RSND_GEN2, .ssi_info = rsnd_ssi, .ssi_info_nr = ARRAY_SIZE(rsnd_ssi), - .scu_info = rsnd_scu, - .scu_info_nr = ARRAY_SIZE(rsnd_scu), + .src_info = rsnd_src, + .src_info_nr = ARRAY_SIZE(rsnd_src), + .dai_info = &rsnd_dai, + .dai_info_nr = 1, }; static struct asoc_simple_card_info rsnd_card_info = { diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c deleted file mode 100644 index 5ac13ba71d54c2..00000000000000 --- a/arch/arm/mach-shmobile/clock-emev2.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Emma Mobile EV2 clock framework support - * - * Copyright (C) 2012 Magnus Damm - * - * 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. - * - * 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 - -#define EMEV2_SMU_BASE 0xe0110000 - -/* EMEV2 SMU registers */ -#define USIAU0_RSTCTRL 0x094 -#define USIBU1_RSTCTRL 0x0ac -#define USIBU2_RSTCTRL 0x0b0 -#define USIBU3_RSTCTRL 0x0b4 -#define STI_RSTCTRL 0x124 -#define USIAU0GCLKCTRL 0x4a0 -#define USIBU1GCLKCTRL 0x4b8 -#define USIBU2GCLKCTRL 0x4bc -#define USIBU3GCLKCTRL 0x04c0 -#define STIGCLKCTRL 0x528 -#define USIAU0SCLKDIV 0x61c -#define USIB2SCLKDIV 0x65c -#define USIB3SCLKDIV 0x660 -#define STI_CLKSEL 0x688 - -/* not pretty, but hey */ -static void __iomem *smu_base; - -static void emev2_smu_write(unsigned long value, int offs) -{ - BUG_ON(!smu_base || (offs >= PAGE_SIZE)); - iowrite32(value, smu_base + offs); -} - -static struct clk_mapping smu_mapping = { - .phys = EMEV2_SMU_BASE, - .len = PAGE_SIZE, -}; - -/* Fixed 32 KHz root clock from C32K pin */ -static struct clk c32k_clk = { - .rate = 32768, - .mapping = &smu_mapping, -}; - -/* PLL3 multiplies C32K with 7000 */ -static unsigned long pll3_recalc(struct clk *clk) -{ - return clk->parent->rate * 7000; -} - -static struct sh_clk_ops pll3_clk_ops = { - .recalc = pll3_recalc, -}; - -static struct clk pll3_clk = { - .ops = &pll3_clk_ops, - .parent = &c32k_clk, -}; - -static struct clk *main_clks[] = { - &c32k_clk, - &pll3_clk, -}; - -enum { SCLKDIV_USIAU0, SCLKDIV_USIBU2, SCLKDIV_USIBU1, SCLKDIV_USIBU3, - SCLKDIV_NR }; - -#define SCLKDIV(_reg, _shift) \ -{ \ - .parent = &pll3_clk, \ - .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \ - .enable_bit = _shift, \ -} - -static struct clk sclkdiv_clks[SCLKDIV_NR] = { - [SCLKDIV_USIAU0] = SCLKDIV(USIAU0SCLKDIV, 0), - [SCLKDIV_USIBU2] = SCLKDIV(USIB2SCLKDIV, 16), - [SCLKDIV_USIBU1] = SCLKDIV(USIB2SCLKDIV, 0), - [SCLKDIV_USIBU3] = SCLKDIV(USIB3SCLKDIV, 0), -}; - -enum { GCLK_USIAU0_SCLK, GCLK_USIBU1_SCLK, GCLK_USIBU2_SCLK, GCLK_USIBU3_SCLK, - GCLK_STI_SCLK, - GCLK_NR }; - -#define GCLK_SCLK(_parent, _reg) \ -{ \ - .parent = _parent, \ - .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \ - .enable_bit = 1, /* SCLK_GCC */ \ -} - -static struct clk gclk_clks[GCLK_NR] = { - [GCLK_USIAU0_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIAU0], - USIAU0GCLKCTRL), - [GCLK_USIBU1_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU1], - USIBU1GCLKCTRL), - [GCLK_USIBU2_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU2], - USIBU2GCLKCTRL), - [GCLK_USIBU3_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU3], - USIBU3GCLKCTRL), - [GCLK_STI_SCLK] = GCLK_SCLK(&c32k_clk, STIGCLKCTRL), -}; - -static int emev2_gclk_enable(struct clk *clk) -{ - iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit), - clk->mapped_reg); - return 0; -} - -static void emev2_gclk_disable(struct clk *clk) -{ - iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit), - clk->mapped_reg); -} - -static struct sh_clk_ops emev2_gclk_clk_ops = { - .enable = emev2_gclk_enable, - .disable = emev2_gclk_disable, - .recalc = followparent_recalc, -}; - -static int __init emev2_gclk_register(struct clk *clks, int nr) -{ - struct clk *clkp; - int ret = 0; - int k; - - for (k = 0; !ret && (k < nr); k++) { - clkp = clks + k; - clkp->ops = &emev2_gclk_clk_ops; - ret |= clk_register(clkp); - } - - return ret; -} - -static unsigned long emev2_sclkdiv_recalc(struct clk *clk) -{ - unsigned int sclk_div; - - sclk_div = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0xff; - - return clk->parent->rate / (sclk_div + 1); -} - -static struct sh_clk_ops emev2_sclkdiv_clk_ops = { - .recalc = emev2_sclkdiv_recalc, -}; - -static int __init emev2_sclkdiv_register(struct clk *clks, int nr) -{ - struct clk *clkp; - int ret = 0; - int k; - - for (k = 0; !ret && (k < nr); k++) { - clkp = clks + k; - clkp->ops = &emev2_sclkdiv_clk_ops; - ret |= clk_register(clkp); - } - - return ret; -} - -static struct clk_lookup lookups[] = { - CLKDEV_DEV_ID("serial8250-em.0", &gclk_clks[GCLK_USIAU0_SCLK]), - CLKDEV_DEV_ID("e1020000.uart", &gclk_clks[GCLK_USIAU0_SCLK]), - CLKDEV_DEV_ID("serial8250-em.1", &gclk_clks[GCLK_USIBU1_SCLK]), - CLKDEV_DEV_ID("e1030000.uart", &gclk_clks[GCLK_USIBU1_SCLK]), - CLKDEV_DEV_ID("serial8250-em.2", &gclk_clks[GCLK_USIBU2_SCLK]), - CLKDEV_DEV_ID("e1040000.uart", &gclk_clks[GCLK_USIBU2_SCLK]), - CLKDEV_DEV_ID("serial8250-em.3", &gclk_clks[GCLK_USIBU3_SCLK]), - CLKDEV_DEV_ID("e1050000.uart", &gclk_clks[GCLK_USIBU3_SCLK]), - CLKDEV_DEV_ID("em_sti.0", &gclk_clks[GCLK_STI_SCLK]), - CLKDEV_DEV_ID("e0180000.sti", &gclk_clks[GCLK_STI_SCLK]), -}; - -void __init emev2_clock_init(void) -{ - int k, ret = 0; - - smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE); - BUG_ON(!smu_base); - - /* setup STI timer to run on 32.768 kHz and deassert reset */ - emev2_smu_write(0, STI_CLKSEL); - emev2_smu_write(1, STI_RSTCTRL); - - /* deassert reset for UART0->UART3 */ - emev2_smu_write(2, USIAU0_RSTCTRL); - emev2_smu_write(2, USIBU1_RSTCTRL); - emev2_smu_write(2, USIBU2_RSTCTRL); - emev2_smu_write(2, USIBU3_RSTCTRL); - - for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) - ret = clk_register(main_clks[k]); - - if (!ret) - ret = emev2_sclkdiv_register(sclkdiv_clks, SCLKDIV_NR); - - if (!ret) - ret = emev2_gclk_register(gclk_clks, GCLK_NR); - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - if (!ret) - shmobile_clk_init(); - else - panic("failed to setup emev2 clocks\n"); -} diff --git a/arch/arm/mach-shmobile/clock-r8a7778.c b/arch/arm/mach-shmobile/clock-r8a7778.c index 9989b1b06ffd7d..6609beb9b9b4d6 100644 --- a/arch/arm/mach-shmobile/clock-r8a7778.c +++ b/arch/arm/mach-shmobile/clock-r8a7778.c @@ -175,10 +175,6 @@ static struct clk mstp_clks[MSTP_NR] = { static struct clk_lookup lookups[] = { /* main */ - CLKDEV_CON_ID("audio_clk_a", &audio_clk_a), - CLKDEV_CON_ID("audio_clk_b", &audio_clk_b), - CLKDEV_CON_ID("audio_clk_c", &audio_clk_c), - CLKDEV_CON_ID("audio_clk_internal", &s1_clk), CLKDEV_CON_ID("shyway_clk", &s_clk), CLKDEV_CON_ID("peripheral_clk", &p_clk), @@ -234,15 +230,15 @@ static struct clk_lookup lookups[] = { CLKDEV_ICK_ID("ssi.6", "rcar_sound", &mstp_clks[MSTP309]), CLKDEV_ICK_ID("ssi.7", "rcar_sound", &mstp_clks[MSTP308]), CLKDEV_ICK_ID("ssi.8", "rcar_sound", &mstp_clks[MSTP307]), - CLKDEV_ICK_ID("scu.0", "rcar_sound", &mstp_clks[MSTP531]), - CLKDEV_ICK_ID("scu.1", "rcar_sound", &mstp_clks[MSTP530]), - CLKDEV_ICK_ID("scu.2", "rcar_sound", &mstp_clks[MSTP529]), - CLKDEV_ICK_ID("scu.3", "rcar_sound", &mstp_clks[MSTP528]), - CLKDEV_ICK_ID("scu.4", "rcar_sound", &mstp_clks[MSTP527]), - CLKDEV_ICK_ID("scu.5", "rcar_sound", &mstp_clks[MSTP526]), - CLKDEV_ICK_ID("scu.6", "rcar_sound", &mstp_clks[MSTP525]), - CLKDEV_ICK_ID("scu.7", "rcar_sound", &mstp_clks[MSTP524]), - CLKDEV_ICK_ID("scu.8", "rcar_sound", &mstp_clks[MSTP523]), + CLKDEV_ICK_ID("src.0", "rcar_sound", &mstp_clks[MSTP531]), + CLKDEV_ICK_ID("src.1", "rcar_sound", &mstp_clks[MSTP530]), + CLKDEV_ICK_ID("src.2", "rcar_sound", &mstp_clks[MSTP529]), + CLKDEV_ICK_ID("src.3", "rcar_sound", &mstp_clks[MSTP528]), + CLKDEV_ICK_ID("src.4", "rcar_sound", &mstp_clks[MSTP527]), + CLKDEV_ICK_ID("src.5", "rcar_sound", &mstp_clks[MSTP526]), + CLKDEV_ICK_ID("src.6", "rcar_sound", &mstp_clks[MSTP525]), + CLKDEV_ICK_ID("src.7", "rcar_sound", &mstp_clks[MSTP524]), + CLKDEV_ICK_ID("src.8", "rcar_sound", &mstp_clks[MSTP523]), }; void __init r8a7778_clock_init(void) diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c index 3f93503f5b96f1..a936ae7de08386 100644 --- a/arch/arm/mach-shmobile/clock-r8a7790.c +++ b/arch/arm/mach-shmobile/clock-r8a7790.c @@ -249,10 +249,10 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP1007] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 7, MSTPSR10, 0), /* SSI8 */ [MSTP1006] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 6, MSTPSR10, 0), /* SSI9 */ [MSTP1005] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 5, MSTPSR10, 0), /* SSI ALL */ - [MSTP931] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */ - [MSTP930] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */ - [MSTP929] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */ - [MSTP928] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */ + [MSTP931] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */ + [MSTP930] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */ + [MSTP929] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */ + [MSTP928] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */ [MSTP917] = SH_CLK_MSTP32_STS(&qspi_clk, SMSTPCR9, 17, MSTPSR9, 0), /* QSPI */ [MSTP815] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 15, MSTPSR8, 0), /* SATA0 */ [MSTP814] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 14, MSTPSR8, 0), /* SATA1 */ @@ -294,10 +294,6 @@ static struct clk mstp_clks[MSTP_NR] = { static struct clk_lookup lookups[] = { /* main clocks */ - CLKDEV_CON_ID("audio_clk_a", &audio_clk_a), - CLKDEV_CON_ID("audio_clk_b", &audio_clk_b), - CLKDEV_CON_ID("audio_clk_c", &audio_clk_c), - CLKDEV_CON_ID("audio_clk_internal", &m2_clk), CLKDEV_CON_ID("extal", &extal_clk), CLKDEV_CON_ID("extal_div2", &extal_div2_clk), CLKDEV_CON_ID("main", &main_clk), @@ -381,16 +377,16 @@ static struct clk_lookup lookups[] = { CLKDEV_ICK_ID("clk_b", "rcar_sound", &audio_clk_b), CLKDEV_ICK_ID("clk_c", "rcar_sound", &audio_clk_c), CLKDEV_ICK_ID("clk_i", "rcar_sound", &m2_clk), - CLKDEV_ICK_ID("scu.0", "rcar_sound", &mstp_clks[MSTP1031]), - CLKDEV_ICK_ID("scu.1", "rcar_sound", &mstp_clks[MSTP1030]), - CLKDEV_ICK_ID("scu.2", "rcar_sound", &mstp_clks[MSTP1029]), - CLKDEV_ICK_ID("scu.3", "rcar_sound", &mstp_clks[MSTP1028]), - CLKDEV_ICK_ID("scu.4", "rcar_sound", &mstp_clks[MSTP1027]), - CLKDEV_ICK_ID("scu.5", "rcar_sound", &mstp_clks[MSTP1026]), - CLKDEV_ICK_ID("scu.6", "rcar_sound", &mstp_clks[MSTP1025]), - CLKDEV_ICK_ID("scu.7", "rcar_sound", &mstp_clks[MSTP1024]), - CLKDEV_ICK_ID("scu.8", "rcar_sound", &mstp_clks[MSTP1023]), - CLKDEV_ICK_ID("scu.9", "rcar_sound", &mstp_clks[MSTP1022]), + CLKDEV_ICK_ID("src.0", "rcar_sound", &mstp_clks[MSTP1031]), + CLKDEV_ICK_ID("src.1", "rcar_sound", &mstp_clks[MSTP1030]), + CLKDEV_ICK_ID("src.2", "rcar_sound", &mstp_clks[MSTP1029]), + CLKDEV_ICK_ID("src.3", "rcar_sound", &mstp_clks[MSTP1028]), + CLKDEV_ICK_ID("src.4", "rcar_sound", &mstp_clks[MSTP1027]), + CLKDEV_ICK_ID("src.5", "rcar_sound", &mstp_clks[MSTP1026]), + CLKDEV_ICK_ID("src.6", "rcar_sound", &mstp_clks[MSTP1025]), + CLKDEV_ICK_ID("src.7", "rcar_sound", &mstp_clks[MSTP1024]), + CLKDEV_ICK_ID("src.8", "rcar_sound", &mstp_clks[MSTP1023]), + CLKDEV_ICK_ID("src.9", "rcar_sound", &mstp_clks[MSTP1022]), CLKDEV_ICK_ID("ssi.0", "rcar_sound", &mstp_clks[MSTP1015]), CLKDEV_ICK_ID("ssi.1", "rcar_sound", &mstp_clks[MSTP1014]), CLKDEV_ICK_ID("ssi.2", "rcar_sound", &mstp_clks[MSTP1013]), diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c index 701383fe326741..3b26c7eee873fb 100644 --- a/arch/arm/mach-shmobile/clock-r8a7791.c +++ b/arch/arm/mach-shmobile/clock-r8a7791.c @@ -25,6 +25,7 @@ #include #include #include +#include /* * MD EXTAL PLL0 PLL1 PLL3 @@ -43,8 +44,6 @@ * see "p1 / 2" on R8A7791_CLOCK_ROOT() below */ -#define MD(nr) (1 << nr) - #define CPG_BASE 0xe6150000 #define CPG_LEN 0x1000 @@ -68,7 +67,6 @@ #define MSTPSR9 IOMEM(0xe61509a4) #define MSTPSR11 IOMEM(0xe61509ac) -#define MODEMR 0xE6160060 #define SDCKCR 0xE6150074 #define SD1CKCR 0xE6150078 #define SD2CKCR 0xE615026c @@ -190,12 +188,12 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP1108] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 8, MSTPSR11, 0), /* SCIFA5 */ [MSTP1107] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 7, MSTPSR11, 0), /* SCIFA4 */ [MSTP1106] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 6, MSTPSR11, 0), /* SCIFA3 */ - [MSTP931] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */ - [MSTP930] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */ - [MSTP929] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */ - [MSTP928] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */ - [MSTP927] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 27, MSTPSR9, 0), /* I2C4 */ - [MSTP925] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 25, MSTPSR9, 0), /* I2C5 */ + [MSTP931] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */ + [MSTP930] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */ + [MSTP929] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */ + [MSTP928] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */ + [MSTP927] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 27, MSTPSR9, 0), /* I2C4 */ + [MSTP925] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 25, MSTPSR9, 0), /* I2C5 */ [MSTP917] = SH_CLK_MSTP32_STS(&qspi_clk, SMSTPCR9, 17, MSTPSR9, 0), /* QSPI */ [MSTP815] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 15, MSTPSR8, 0), /* SATA0 */ [MSTP814] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 14, MSTPSR8, 0), /* SATA1 */ @@ -295,14 +293,9 @@ static struct clk_lookup lookups[] = { void __init r8a7791_clock_init(void) { - void __iomem *modemr = ioremap_nocache(MODEMR, PAGE_SIZE); - u32 mode; + u32 mode = rcar_gen2_read_mode_pins(); int k, ret = 0; - BUG_ON(!modemr); - mode = ioread32(modemr); - iounmap(modemr); - switch (mode & (MD(14) | MD(13))) { case 0: R8A7791_CLOCK_ROOT(15, &extal_clk, 172, 208, 106, 88); diff --git a/arch/arm/mach-shmobile/clock.c b/arch/arm/mach-shmobile/clock.c index ad7df629d99541..e7232a0373b9f5 100644 --- a/arch/arm/mach-shmobile/clock.c +++ b/arch/arm/mach-shmobile/clock.c @@ -21,6 +21,32 @@ */ #include #include + +#ifdef CONFIG_COMMON_CLK +#include +#include +#include + +void __init shmobile_clk_workaround(const struct clk_name *clks, + int nr_clks, bool enable) +{ + const struct clk_name *clkn; + struct clk *clk; + unsigned int i; + + for (i = 0; i < nr_clks; ++i) { + clkn = clks + i; + clk = clk_get(NULL, clkn->clk); + if (!IS_ERR(clk)) { + clk_register_clkdev(clk, clkn->con_id, clkn->dev_id); + if (enable) + clk_prepare_enable(clk); + clk_put(clk); + } + } +} + +#else /* CONFIG_COMMON_CLK */ #include #include #include @@ -58,3 +84,5 @@ void __clk_put(struct clk *clk) { } EXPORT_SYMBOL(__clk_put); + +#endif /* CONFIG_COMMON_CLK */ diff --git a/arch/arm/mach-shmobile/include/mach/clock.h b/arch/arm/mach-shmobile/include/mach/clock.h index 03e56074928c23..9a93cf924b9cf0 100644 --- a/arch/arm/mach-shmobile/include/mach/clock.h +++ b/arch/arm/mach-shmobile/include/mach/clock.h @@ -1,6 +1,21 @@ #ifndef CLOCK_H #define CLOCK_H +#ifdef CONFIG_COMMON_CLK +/* temporary clock configuration helper for platform devices */ + +struct clk_name { + const char *clk; + const char *con_id; + const char *dev_id; +}; + +void shmobile_clk_workaround(const struct clk_name *clks, int nr_clks, + bool enable); + +#else /* CONFIG_COMMON_CLK */ +/* legacy clock implementation */ + unsigned long shmobile_fixed_ratio_clk_recalc(struct clk *clk); extern struct sh_clk_ops shmobile_fixed_ratio_clk_ops; @@ -36,4 +51,5 @@ do { \ (p)->div = d; \ } while (0) +#endif /* CONFIG_COMMON_CLK */ #endif diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index cb8e32deb2a3c6..f7a360edcc3531 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -4,6 +4,7 @@ extern void shmobile_earlytimer_init(void); extern void shmobile_setup_delay(unsigned int max_cpu_core_mhz, unsigned int mult, unsigned int div); +extern void shmobile_init_delay(void); struct twd_local_timer; extern void shmobile_setup_console(void); extern void shmobile_boot_vector(void); diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h deleted file mode 100644 index fcb142a14e0756..00000000000000 --- a/arch/arm/mach-shmobile/include/mach/emev2.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __ASM_EMEV2_H__ -#define __ASM_EMEV2_H__ - -extern void emev2_map_io(void); -extern void emev2_init_delay(void); -extern void emev2_clock_init(void); -extern struct smp_operations emev2_smp_ops; - -#endif /* __ASM_EMEV2_H__ */ diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c index 1fc05d9453d026..f710235aff2fad 100644 --- a/arch/arm/mach-shmobile/pm-rmobile.c +++ b/arch/arm/mach-shmobile/pm-rmobile.c @@ -99,39 +99,7 @@ static int rmobile_pd_power_up(struct generic_pm_domain *genpd) static bool rmobile_pd_active_wakeup(struct device *dev) { - bool (*active_wakeup)(struct device *dev); - - active_wakeup = dev_gpd_data(dev)->ops.active_wakeup; - return active_wakeup ? active_wakeup(dev) : true; -} - -static int rmobile_pd_stop_dev(struct device *dev) -{ - int (*stop)(struct device *dev); - - stop = dev_gpd_data(dev)->ops.stop; - if (stop) { - int ret = stop(dev); - if (ret) - return ret; - } - return pm_clk_suspend(dev); -} - -static int rmobile_pd_start_dev(struct device *dev) -{ - int (*start)(struct device *dev); - int ret; - - ret = pm_clk_resume(dev); - if (ret) - return ret; - - start = dev_gpd_data(dev)->ops.start; - if (start) - ret = start(dev); - - return ret; + return true; } static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd) @@ -140,8 +108,8 @@ static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd) struct dev_power_governor *gov = rmobile_pd->gov; pm_genpd_init(genpd, gov ? : &simple_qos_governor, false); - genpd->dev_ops.stop = rmobile_pd_stop_dev; - genpd->dev_ops.start = rmobile_pd_start_dev; + genpd->dev_ops.stop = pm_clk_suspend; + genpd->dev_ops.start = pm_clk_resume; genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup; genpd->dev_irq_safe = true; genpd->power_off = rmobile_pd_power_down; diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c index c71d667007b8e4..d953ff6e78a29d 100644 --- a/arch/arm/mach-shmobile/setup-emev2.c +++ b/arch/arm/mach-shmobile/setup-emev2.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -38,23 +37,19 @@ static struct map_desc emev2_io_desc[] __initdata = { #endif }; -void __init emev2_map_io(void) +static void __init emev2_map_io(void) { iotable_init(emev2_io_desc, ARRAY_SIZE(emev2_io_desc)); } -void __init emev2_init_delay(void) +static void __init emev2_init_delay(void) { shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */ } static void __init emev2_add_standard_devices_dt(void) { -#ifdef CONFIG_COMMON_CLK of_clk_init(NULL); -#else - emev2_clock_init(); -#endif of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } @@ -63,6 +58,8 @@ static const char *emev2_boards_compat_dt[] __initconst = { NULL, }; +extern struct smp_operations emev2_smp_ops; + DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)") .smp = smp_ops(emev2_smp_ops), .map_io = emev2_map_io, diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 8f3c68101d59d7..a177a7b3bdbd9b 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -765,7 +765,7 @@ static struct platform_device *r8a7740_late_devices[] __initdata = { * "Media RAM (MERAM)" on r8a7740 documentation */ #define MEBUFCNTR 0xFE950098 -void r8a7740_meram_workaround(void) +void __init r8a7740_meram_workaround(void) { void __iomem *reg; @@ -869,17 +869,6 @@ void __init r8a7740_add_early_devices(void) #ifdef CONFIG_USE_OF -void __init r8a7740_add_early_devices_dt(void) -{ - shmobile_setup_delay(800, 1, 3); /* Cortex-A9 @ 800MHz */ - - early_platform_add_devices(r8a7740_early_devices, - ARRAY_SIZE(r8a7740_early_devices)); - - /* setup early console here as well */ - shmobile_setup_console(); -} - void __init r8a7740_add_standard_devices_dt(void) { platform_add_devices(r8a7740_devices_dt, diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c b/arch/arm/mach-shmobile/setup-r8a7790.c index c4616f0698c6dc..a901d9ef53f61c 100644 --- a/arch/arm/mach-shmobile/setup-r8a7790.c +++ b/arch/arm/mach-shmobile/setup-r8a7790.c @@ -185,12 +185,6 @@ void __init r8a7790_pinmux_init(void) r8a7790_register_gpio(3); r8a7790_register_gpio(4); r8a7790_register_gpio(5); - r8a7790_register_i2c(0); - r8a7790_register_i2c(1); - r8a7790_register_i2c(2); - r8a7790_register_i2c(3); - r8a7790_register_audio_dmac(0); - r8a7790_register_audio_dmac(1); } #define __R8A7790_SCIF(scif_type, _scscr, index, baseaddr, irq) \ @@ -308,6 +302,12 @@ void __init r8a7790_add_standard_devices(void) r8a7790_add_dt_devices(); r8a7790_register_irqc(0); r8a7790_register_thermal(); + r8a7790_register_i2c(0); + r8a7790_register_i2c(1); + r8a7790_register_i2c(2); + r8a7790_register_i2c(3); + r8a7790_register_audio_dmac(0); + r8a7790_register_audio_dmac(1); } void __init r8a7790_init_early(void) diff --git a/arch/arm/mach-shmobile/setup-r8a7791.c b/arch/arm/mach-shmobile/setup-r8a7791.c index e28404e43860ac..a7e4966f5e189e 100644 --- a/arch/arm/mach-shmobile/setup-r8a7791.c +++ b/arch/arm/mach-shmobile/setup-r8a7791.c @@ -213,7 +213,7 @@ void __init r8a7791_add_standard_devices(void) void __init r8a7791_init_early(void) { #ifndef CONFIG_ARM_ARCH_TIMER - shmobile_setup_delay(1300, 2, 4); /* Cortex-A15 @ 1300MHz */ + shmobile_setup_delay(1500, 2, 4); /* Cortex-A15 @ 1500MHz */ #endif } diff --git a/arch/arm/mach-shmobile/setup-rcar-gen2.c b/arch/arm/mach-shmobile/setup-rcar-gen2.c index 10604480f32529..542c5a47173f9e 100644 --- a/arch/arm/mach-shmobile/setup-rcar-gen2.c +++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c @@ -30,12 +30,16 @@ u32 rcar_gen2_read_mode_pins(void) { - void __iomem *modemr = ioremap_nocache(MODEMR, 4); - u32 mode; - - BUG_ON(!modemr); - mode = ioread32(modemr); - iounmap(modemr); + static u32 mode; + static bool mode_valid; + + if (!mode_valid) { + void __iomem *modemr = ioremap_nocache(MODEMR, 4); + BUG_ON(!modemr); + mode = ioread32(modemr); + iounmap(modemr); + mode_valid = true; + } return mode; } diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 27301278c20840..f8176b051be485 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -1037,11 +1037,7 @@ void __init sh7372_add_early_devices_dt(void) { shmobile_setup_delay(800, 1, 3); /* Cortex-A8 @ 800MHz */ - early_platform_add_devices(sh7372_early_devices, - ARRAY_SIZE(sh7372_early_devices)); - - /* setup early console here as well */ - shmobile_setup_console(); + sh7372_add_early_devices(); } void __init sh7372_add_standard_devices_dt(void) diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c index f2ca92308f7568..2dfd748da7f374 100644 --- a/arch/arm/mach-shmobile/smp-emev2.c +++ b/arch/arm/mach-shmobile/smp-emev2.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-shmobile/smp-r8a7791.c b/arch/arm/mach-shmobile/smp-r8a7791.c index 2df5bd190fe4ce..ec979529f30f5b 100644 --- a/arch/arm/mach-shmobile/smp-r8a7791.c +++ b/arch/arm/mach-shmobile/smp-r8a7791.c @@ -20,6 +20,7 @@ #include #include #include +#include #define RST 0xe6160000 #define CA15BAR 0x0020 @@ -51,9 +52,21 @@ static void __init r8a7791_smp_prepare_cpus(unsigned int max_cpus) iounmap(p); } +static int r8a7791_smp_boot_secondary(unsigned int cpu, + struct task_struct *idle) +{ + /* Error out when hardware debug mode is enabled */ + if (rcar_gen2_read_mode_pins() & BIT(21)) { + pr_warn("Unable to boot CPU%u when MD21 is set\n", cpu); + return -ENOTSUPP; + } + + return shmobile_smp_apmu_boot_secondary(cpu, idle); +} + struct smp_operations r8a7791_smp_ops __initdata = { .smp_prepare_cpus = r8a7791_smp_prepare_cpus, - .smp_boot_secondary = shmobile_smp_apmu_boot_secondary, + .smp_boot_secondary = r8a7791_smp_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU .cpu_disable = shmobile_smp_cpu_disable, .cpu_die = shmobile_smp_apmu_cpu_die, diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index 62d7052d6f215f..ccecde9a3362e4 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c @@ -21,6 +21,7 @@ #include #include #include +#include void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz, unsigned int mult, unsigned int div) @@ -39,6 +40,33 @@ void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz, preset_lpj = max_cpu_core_mhz * value; } +void __init shmobile_init_delay(void) +{ + struct device_node *np, *parent; + u32 max_freq, freq; + + max_freq = 0; + + parent = of_find_node_by_path("/cpus"); + if (parent) { + for_each_child_of_node(parent, np) { + if (!of_property_read_u32(np, "clock-frequency", &freq)) + max_freq = max(max_freq, freq); + } + of_node_put(parent); + } + + if (max_freq) { + if (of_find_compatible_node(NULL, NULL, "arm,cortex-a8")) + shmobile_setup_delay(max_freq, 1, 3); + else if (of_find_compatible_node(NULL, NULL, "arm,cortex-a9")) + shmobile_setup_delay(max_freq, 1, 3); + else if (of_find_compatible_node(NULL, NULL, "arm,cortex-a15")) + if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) + shmobile_setup_delay(max_freq, 2, 4); + } +} + static void __init shmobile_late_time_init(void) { /* diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c index e4dec9fcb084af..9c6029ba526fff 100644 --- a/arch/arm/mach-tegra/board-paz00.c +++ b/arch/arm/mach-tegra/board-paz00.c @@ -23,9 +23,7 @@ #include "board.h" static struct rfkill_gpio_platform_data wifi_rfkill_platform_data = { - .name = "wifi_rfkill", - .reset_gpio = 25, /* PD1 */ - .shutdown_gpio = 85, /* PK5 */ + .name = "wifi_rfkill", .type = RFKILL_TYPE_WLAN, }; diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c index fb7920201ab4de..7c7123e7557bef 100644 --- a/arch/arm/mach-tegra/pmc.c +++ b/arch/arm/mach-tegra/pmc.c @@ -41,6 +41,14 @@ #define PMC_REMOVE_CLAMPING 0x34 #define PMC_PWRGATE_STATUS 0x38 +#define PMC_SCRATCH0 0x50 +#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31) +#define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30) +#define PMC_SCRATCH0_MODE_RCM (1 << 1) +#define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \ + PMC_SCRATCH0_MODE_BOOTLOADER | \ + PMC_SCRATCH0_MODE_RCM) + #define PMC_CPUPWRGOOD_TIMER 0xc8 #define PMC_CPUPWROFF_TIMER 0xcc @@ -165,6 +173,22 @@ void tegra_pmc_restart(enum reboot_mode mode, const char *cmd) { u32 val; + val = tegra_pmc_readl(PMC_SCRATCH0); + val &= ~PMC_SCRATCH0_MODE_MASK; + + if (cmd) { + if (strcmp(cmd, "recovery") == 0) + val |= PMC_SCRATCH0_MODE_RECOVERY; + + if (strcmp(cmd, "bootloader") == 0) + val |= PMC_SCRATCH0_MODE_BOOTLOADER; + + if (strcmp(cmd, "forced-recovery") == 0) + val |= PMC_SCRATCH0_MODE_RCM; + } + + tegra_pmc_writel(val, PMC_SCRATCH0); + val = tegra_pmc_readl(0); val |= 0x10; tegra_pmc_writel(val, 0); diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index f2c89fb8fca9d6..be83ba25f81b7e 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -310,6 +310,21 @@ static struct platform_device char_lcd_device = { .resource = char_lcd_resources, }; +static struct resource leds_resources[] = { + { + .start = VERSATILE_SYS_BASE + VERSATILE_SYS_LED_OFFSET, + .end = VERSATILE_SYS_BASE + VERSATILE_SYS_LED_OFFSET + 4, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device leds_device = { + .name = "versatile-leds", + .id = -1, + .num_resources = ARRAY_SIZE(leds_resources), + .resource = leds_resources, +}; + /* * Clock handling */ @@ -795,6 +810,7 @@ void __init versatile_init(void) platform_device_register(&versatile_i2c_device); platform_device_register(&smc91x_device); platform_device_register(&char_lcd_device); + platform_device_register(&leds_device); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index 993c9ae5dc5e16..b4a5f0d8390dcc 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -53,7 +53,7 @@ static int __init vexpress_dt_find_scu(unsigned long node, { if (of_flat_dt_match(node, vexpress_dt_cortex_a9_match)) { phys_addr_t phys_addr; - __be32 *reg = of_get_flat_dt_prop(node, "reg", NULL); + const __be32 *reg = of_get_flat_dt_prop(node, "reg", NULL); if (WARN_ON(!reg)) return -EINVAL; diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 6b00be1f971e15..18e98dfb73fc19 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -885,7 +885,7 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset, static void __dma_page_cpu_to_dev(struct page *page, unsigned long off, size_t size, enum dma_data_direction dir) { - unsigned long paddr; + phys_addr_t paddr; dma_cache_maint_page(page, off, size, dir, dmac_map_area); @@ -901,7 +901,7 @@ static void __dma_page_cpu_to_dev(struct page *page, unsigned long off, static void __dma_page_dev_to_cpu(struct page *page, unsigned long off, size_t size, enum dma_data_direction dir) { - unsigned long paddr = page_to_phys(page) + off; + phys_addr_t paddr = page_to_phys(page) + off; /* FIXME: non-speculating: not required */ /* don't bother invalidating if DMA to device */ diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index 21b9e1bf9b7714..45aeaaca9052f2 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -18,6 +18,21 @@ #include #include "mm.h" +pte_t *fixmap_page_table; + +static inline void set_fixmap_pte(int idx, pte_t pte) +{ + unsigned long vaddr = __fix_to_virt(idx); + set_pte_ext(fixmap_page_table + idx, pte, 0); + local_flush_tlb_kernel_page(vaddr); +} + +static inline pte_t get_fixmap_pte(unsigned long vaddr) +{ + unsigned long idx = __virt_to_fix(vaddr); + return *(fixmap_page_table + idx); +} + void *kmap(struct page *page) { might_sleep(); @@ -63,20 +78,20 @@ void *kmap_atomic(struct page *page) type = kmap_atomic_idx_push(); idx = type + KM_TYPE_NR * smp_processor_id(); - vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + vaddr = __fix_to_virt(idx); #ifdef CONFIG_DEBUG_HIGHMEM /* * With debugging enabled, kunmap_atomic forces that entry to 0. * Make sure it was indeed properly unmapped. */ - BUG_ON(!pte_none(get_top_pte(vaddr))); + BUG_ON(!pte_none(*(fixmap_page_table + idx))); #endif /* * When debugging is off, kunmap_atomic leaves the previous mapping * in place, so the contained TLB flush ensures the TLB is updated * with the new mapping. */ - set_top_pte(vaddr, mk_pte(page, kmap_prot)); + set_fixmap_pte(idx, mk_pte(page, kmap_prot)); return (void *)vaddr; } @@ -94,8 +109,8 @@ void __kunmap_atomic(void *kvaddr) if (cache_is_vivt()) __cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE); #ifdef CONFIG_DEBUG_HIGHMEM - BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx)); - set_top_pte(vaddr, __pte(0)); + BUG_ON(vaddr != __fix_to_virt(idx)); + set_fixmap_pte(idx, __pte(0)); #else (void) idx; /* to kill a warning */ #endif @@ -117,11 +132,11 @@ void *kmap_atomic_pfn(unsigned long pfn) type = kmap_atomic_idx_push(); idx = type + KM_TYPE_NR * smp_processor_id(); - vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + vaddr = __fix_to_virt(idx); #ifdef CONFIG_DEBUG_HIGHMEM - BUG_ON(!pte_none(get_top_pte(vaddr))); + BUG_ON(!pte_none(*(fixmap_page_table + idx))); #endif - set_top_pte(vaddr, pfn_pte(pfn, kmap_prot)); + set_fixmap_pte(idx, pfn_pte(pfn, kmap_prot)); return (void *)vaddr; } @@ -133,5 +148,5 @@ struct page *kmap_atomic_to_page(const void *ptr) if (vaddr < FIXADDR_START) return virt_to_page(ptr); - return pte_page(get_top_pte(vaddr)); + return pte_page(get_fixmap_pte(vaddr)); } diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 2a77ba8796aeed..928d596d9ab4fa 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -317,7 +317,6 @@ void __init arm_memblock_init(struct meminfo *mi, #endif arm_mm_memblock_reserve(); - arm_dt_memblock_reserve(); /* reserve any platform specific memblock areas */ if (mdesc->reserve) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index b68c6b22e1c80f..09c0a16165dcd6 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "mm.h" #include "tcm.h" @@ -1359,6 +1360,9 @@ static void __init kmap_init(void) #ifdef CONFIG_HIGHMEM pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE), PKMAP_BASE, _PAGE_KERNEL_TABLE); + + fixmap_page_table = early_pte_alloc(pmd_off_k(FIXADDR_START), + FIXADDR_START, _PAGE_KERNEL_TABLE); #endif } diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S index 01a719e18bb047..22e3ad63500c0e 100644 --- a/arch/arm/mm/proc-v7-3level.S +++ b/arch/arm/mm/proc-v7-3level.S @@ -64,6 +64,14 @@ ENTRY(cpu_v7_switch_mm) mov pc, lr ENDPROC(cpu_v7_switch_mm) +#ifdef __ARMEB__ +#define rl r3 +#define rh r2 +#else +#define rl r2 +#define rh r3 +#endif + /* * cpu_v7_set_pte_ext(ptep, pte) * @@ -73,13 +81,13 @@ ENDPROC(cpu_v7_switch_mm) */ ENTRY(cpu_v7_set_pte_ext) #ifdef CONFIG_MMU - tst r2, #L_PTE_VALID + tst rl, #L_PTE_VALID beq 1f - tst r3, #1 << (57 - 32) @ L_PTE_NONE - bicne r2, #L_PTE_VALID + tst rh, #1 << (57 - 32) @ L_PTE_NONE + bicne rl, #L_PTE_VALID bne 1f - tst r3, #1 << (55 - 32) @ L_PTE_DIRTY - orreq r2, #L_PTE_RDONLY + tst rh, #1 << (55 - 32) @ L_PTE_DIRTY + orreq rl, #L_PTE_RDONLY 1: strd r2, r3, [r0] ALT_SMP(W(nop)) ALT_UP (mcr p15, 0, r0, c7, c10, 1) @ flush_pte diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 195731d3813bb5..b74ea60891d501 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -169,9 +169,31 @@ ENDPROC(cpu_pj4b_do_idle) globl_equ cpu_pj4b_do_idle, cpu_v7_do_idle #endif globl_equ cpu_pj4b_dcache_clean_area, cpu_v7_dcache_clean_area - globl_equ cpu_pj4b_do_suspend, cpu_v7_do_suspend - globl_equ cpu_pj4b_do_resume, cpu_v7_do_resume - globl_equ cpu_pj4b_suspend_size, cpu_v7_suspend_size +#ifdef CONFIG_ARM_CPU_SUSPEND +ENTRY(cpu_pj4b_do_suspend) + stmfd sp!, {r6 - r10} + mrc p15, 1, r6, c15, c1, 0 @ save CP15 - extra features + mrc p15, 1, r7, c15, c2, 0 @ save CP15 - Aux Func Modes Ctrl 0 + mrc p15, 1, r8, c15, c1, 2 @ save CP15 - Aux Debug Modes Ctrl 2 + mrc p15, 1, r9, c15, c1, 1 @ save CP15 - Aux Debug Modes Ctrl 1 + mrc p15, 0, r10, c9, c14, 0 @ save CP15 - PMC + stmia r0!, {r6 - r10} + ldmfd sp!, {r6 - r10} + b cpu_v7_do_suspend +ENDPROC(cpu_pj4b_do_suspend) + +ENTRY(cpu_pj4b_do_resume) + ldmia r0!, {r6 - r10} + mcr p15, 1, r6, c15, c1, 0 @ save CP15 - extra features + mcr p15, 1, r7, c15, c2, 0 @ save CP15 - Aux Func Modes Ctrl 0 + mcr p15, 1, r8, c15, c1, 2 @ save CP15 - Aux Debug Modes Ctrl 2 + mcr p15, 1, r9, c15, c1, 1 @ save CP15 - Aux Debug Modes Ctrl 1 + mcr p15, 0, r10, c9, c14, 0 @ save CP15 - PMC + b cpu_v7_do_resume +ENDPROC(cpu_pj4b_do_resume) +#endif +.globl cpu_pj4b_suspend_size +.equ cpu_pj4b_suspend_size, 4 * 14 #endif diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c index 6816192a7561b4..b61a3bcc2fa83b 100644 --- a/arch/arm/plat-orion/gpio.c +++ b/arch/arm/plat-orion/gpio.c @@ -597,51 +597,3 @@ void __init orion_gpio_init(struct device_node *np, orion_gpio_chip_count++; } - -#ifdef CONFIG_OF -static void __init orion_gpio_of_init_one(struct device_node *np, - int irq_gpio_base) -{ - int ngpio, gpio_base, mask_offset; - void __iomem *base; - int ret, i; - int irqs[4]; - int secondary_irq_base; - - ret = of_property_read_u32(np, "ngpio", &ngpio); - if (ret) - goto out; - ret = of_property_read_u32(np, "mask-offset", &mask_offset); - if (ret == -EINVAL) - mask_offset = 0; - else - goto out; - base = of_iomap(np, 0); - if (!base) - goto out; - - secondary_irq_base = irq_gpio_base + (32 * orion_gpio_chip_count); - gpio_base = 32 * orion_gpio_chip_count; - - /* Get the interrupt numbers. Each chip can have up to 4 - * interrupt handlers, with each handler dealing with 8 GPIO - * pins. */ - - for (i = 0; i < 4; i++) - irqs[i] = irq_of_parse_and_map(np, i); - - orion_gpio_init(np, gpio_base, ngpio, base, mask_offset, - secondary_irq_base, irqs); - return; -out: - pr_err("%s: %s: missing mandatory property\n", __func__, np->name); -} - -void __init orion_gpio_of_init(int irq_gpio_base) -{ - struct device_node *np; - - for_each_compatible_node(np, NULL, "marvell,orion-gpio") - orion_gpio_of_init_one(np, irq_gpio_base); -} -#endif diff --git a/arch/arm/plat-orion/include/plat/irq.h b/arch/arm/plat-orion/include/plat/irq.h index 50547e41793601..96be19e9bd93df 100644 --- a/arch/arm/plat-orion/include/plat/irq.h +++ b/arch/arm/plat-orion/include/plat/irq.h @@ -12,5 +12,4 @@ #define __PLAT_IRQ_H void orion_irq_init(unsigned int irq_start, void __iomem *maskaddr); -void __init orion_dt_init_irq(void); #endif diff --git a/arch/arm/plat-orion/include/plat/orion-gpio.h b/arch/arm/plat-orion/include/plat/orion-gpio.h index 614dcac9dc5298..e763988b04b9cb 100644 --- a/arch/arm/plat-orion/include/plat/orion-gpio.h +++ b/arch/arm/plat-orion/include/plat/orion-gpio.h @@ -33,5 +33,4 @@ void __init orion_gpio_init(struct device_node *np, int secondary_irq_base, int irq[4]); -void __init orion_gpio_of_init(int irq_gpio_base); #endif diff --git a/arch/arm/plat-orion/irq.c b/arch/arm/plat-orion/irq.c index 807df142444b4f..8c1fc06007c0c3 100644 --- a/arch/arm/plat-orion/irq.c +++ b/arch/arm/plat-orion/irq.c @@ -20,47 +20,6 @@ #include #include -#ifdef CONFIG_MULTI_IRQ_HANDLER -/* - * Compiling with both non-DT and DT support enabled, will - * break asm irq handler used by non-DT boards. Therefore, - * we provide a C-style irq handler even for non-DT boards, - * if MULTI_IRQ_HANDLER is set. - * - * Notes: - * - this is prepared for Kirkwood and Dove only, update - * accordingly if you add Orion5x or MV78x00. - * - Orion5x uses different macro names and has only one - * set of CAUSE/MASK registers. - * - MV78x00 uses the same macro names but has a third - * set of CAUSE/MASK registers. - * - */ - -static void __iomem *orion_irq_base = IRQ_VIRT_BASE; - -asmlinkage void -__exception_irq_entry orion_legacy_handle_irq(struct pt_regs *regs) -{ - u32 stat; - - stat = readl_relaxed(orion_irq_base + IRQ_CAUSE_LOW_OFF); - stat &= readl_relaxed(orion_irq_base + IRQ_MASK_LOW_OFF); - if (stat) { - unsigned int hwirq = __fls(stat); - handle_IRQ(hwirq, regs); - return; - } - stat = readl_relaxed(orion_irq_base + IRQ_CAUSE_HIGH_OFF); - stat &= readl_relaxed(orion_irq_base + IRQ_MASK_HIGH_OFF); - if (stat) { - unsigned int hwirq = 32 + __fls(stat); - handle_IRQ(hwirq, regs); - return; - } -} -#endif - void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr) { struct irq_chip_generic *gc; @@ -78,40 +37,4 @@ void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr) ct->chip.irq_unmask = irq_gc_mask_set_bit; irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); - -#ifdef CONFIG_MULTI_IRQ_HANDLER - set_handle_irq(orion_legacy_handle_irq); -#endif -} - -#ifdef CONFIG_OF -static int __init orion_add_irq_domain(struct device_node *np, - struct device_node *interrupt_parent) -{ - int i = 0; - void __iomem *base; - - do { - base = of_iomap(np, i); - if (base) { - orion_irq_init(i * 32, base + 0x04); - i++; - } - } while (base); - - irq_domain_add_legacy(np, i * 32, 0, 0, - &irq_domain_simple_ops, NULL); - return 0; -} - -static const struct of_device_id orion_irq_match[] = { - { .compatible = "marvell,orion-intc", - .data = orion_add_irq_domain, }, - {}, -}; - -void __init orion_dt_init_irq(void) -{ - of_irq_init(orion_irq_match); } -#endif diff --git a/arch/arm/plat-samsung/dev-backlight.c b/arch/arm/plat-samsung/dev-backlight.c index be4ad0b21c082a..2157c5b539e6c9 100644 --- a/arch/arm/plat-samsung/dev-backlight.c +++ b/arch/arm/plat-samsung/dev-backlight.c @@ -124,8 +124,6 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info, samsung_bl_data->pwm_period_ns = bl_data->pwm_period_ns; if (bl_data->enable_gpio >= 0) samsung_bl_data->enable_gpio = bl_data->enable_gpio; - if (bl_data->enable_gpio_flags) - samsung_bl_data->enable_gpio_flags = bl_data->enable_gpio_flags; if (bl_data->init) samsung_bl_data->init = bl_data->init; if (bl_data->notify) diff --git a/arch/arm/plat-samsung/include/plat/cpu-freq-core.h b/arch/arm/plat-samsung/include/plat/cpu-freq-core.h index 7231c8e4975e5e..72d4178ad23b1d 100644 --- a/arch/arm/plat-samsung/include/plat/cpu-freq-core.h +++ b/arch/arm/plat-samsung/include/plat/cpu-freq-core.h @@ -119,6 +119,7 @@ struct s3c_plltab { struct s3c_cpufreq_config { struct s3c_freq freq; struct s3c_freq max; + struct clk *mpll; struct cpufreq_frequency_table pll; struct s3c_clkdivs divs; struct s3c_cpufreq_info *info; /* for core, not drivers */ diff --git a/arch/arm/plat-samsung/s5p-dev-mfc.c b/arch/arm/plat-samsung/s5p-dev-mfc.c index 98087b655df0af..469b86260fe3f7 100644 --- a/arch/arm/plat-samsung/s5p-dev-mfc.c +++ b/arch/arm/plat-samsung/s5p-dev-mfc.c @@ -125,8 +125,8 @@ device_initcall(s5p_mfc_memory_init); int __init s5p_fdt_alloc_mfc_mem(unsigned long node, const char *uname, int depth, void *data) { - __be32 *prop; - unsigned long len; + const __be32 *prop; + int len; struct s5p_mfc_dt_meminfo mfc_mem; if (!data) diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig index 2c4332b9f94848..fce41e93b6a4e7 100644 --- a/arch/arm/plat-versatile/Kconfig +++ b/arch/arm/plat-versatile/Kconfig @@ -6,12 +6,6 @@ config PLAT_VERSATILE_CLOCK config PLAT_VERSATILE_CLCD bool -config PLAT_VERSATILE_LEDS - def_bool y if NEW_LEDS - depends on ARCH_REALVIEW || ARCH_VERSATILE - select LEDS_CLASS - select LEDS_TRIGGERS - config PLAT_VERSATILE_SCHED_CLOCK def_bool y diff --git a/arch/arm/plat-versatile/Makefile b/arch/arm/plat-versatile/Makefile index f88d448b629caa..2e0c472958ae42 100644 --- a/arch/arm/plat-versatile/Makefile +++ b/arch/arm/plat-versatile/Makefile @@ -2,6 +2,5 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include obj-$(CONFIG_PLAT_VERSATILE_CLOCK) += clock.o obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o -obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o obj-$(CONFIG_PLAT_VERSATILE_SCHED_CLOCK) += sched-clock.o obj-$(CONFIG_SMP) += headsmp.o platsmp.o diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index f0759e70fb865b..fe6ca574d0931d 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -22,11 +22,10 @@ @ r9 = normal "successful" return address @ r10 = this threads thread_info structure @ lr = unrecognised instruction return address -@ IRQs disabled. +@ IRQs enabled. @ ENTRY(do_vfp) inc_preempt_count r10, r4 - enable_irq ldr r4, .LCvfp ldr r11, [r10, #TI_CPU] @ CPU number add r10, r10, #TI_VFPSTATE @ r10 = workspace diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 71036b6286f7b7..8ccdd2646ae3be 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -113,6 +113,9 @@ config IOMMU_HELPER config KERNEL_MODE_NEON def_bool y +config FIX_EARLYCON_MEM + def_bool y + source "init/Kconfig" source "kernel/Kconfig.freezer" diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug index d10ec334c93b4a..1c1b7562984292 100644 --- a/arch/arm64/Kconfig.debug +++ b/arch/arm64/Kconfig.debug @@ -20,15 +20,6 @@ config STRICT_DEVMEM If in doubt, say Y. -config EARLY_PRINTK - bool "Early printk support" - default y - help - Say Y here if you want to have an early console using the - earlyprintk=[,][,] kernel parameter. It - is assumed that the early console device has been initialised - by the boot loader prior to starting the Linux kernel. - config PID_IN_CONTEXTIDR bool "Write the current PID to the CONTEXTIDR register" help diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 0237f0867e377a..57e8cb49824c47 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -152,11 +152,6 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0) -#define smp_mb__before_atomic_dec() smp_mb() -#define smp_mb__after_atomic_dec() smp_mb() -#define smp_mb__before_atomic_inc() smp_mb() -#define smp_mb__after_atomic_inc() smp_mb() - /* * 64-bit atomic operations. */ diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h index 66eb7648043bc9..48b9e704af7c10 100644 --- a/arch/arm64/include/asm/barrier.h +++ b/arch/arm64/include/asm/barrier.h @@ -98,6 +98,9 @@ do { \ #define set_mb(var, value) do { var = value; smp_mb(); } while (0) #define nop() asm volatile("nop"); +#define smp_mb__before_atomic() smp_mb() +#define smp_mb__after_atomic() smp_mb() + #endif /* __ASSEMBLY__ */ #endif /* __ASM_BARRIER_H */ diff --git a/arch/arm64/include/asm/bitops.h b/arch/arm64/include/asm/bitops.h index aa5b59d6ba43a1..9c19594ce7cb99 100644 --- a/arch/arm64/include/asm/bitops.h +++ b/arch/arm64/include/asm/bitops.h @@ -17,17 +17,8 @@ #define __ASM_BITOPS_H #include - #include -/* - * clear_bit may not imply a memory barrier - */ -#ifndef smp_mb__before_clear_bit -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() -#endif - #ifndef _LINUX_BITOPS_H #error only can be included directly #endif diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 0a1d69751562d1..92242ce06309c7 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -39,7 +39,7 @@ #include #include -#define KVM_VCPU_MAX_FEATURES 2 +#define KVM_VCPU_MAX_FEATURES 3 struct kvm_vcpu; int kvm_target_cpu(void); diff --git a/arch/arm64/include/asm/kvm_psci.h b/arch/arm64/include/asm/kvm_psci.h index e301a48163553c..bc39e557c56c83 100644 --- a/arch/arm64/include/asm/kvm_psci.h +++ b/arch/arm64/include/asm/kvm_psci.h @@ -18,6 +18,10 @@ #ifndef __ARM64_KVM_PSCI_H__ #define __ARM64_KVM_PSCI_H__ -bool kvm_psci_call(struct kvm_vcpu *vcpu); +#define KVM_ARM_PSCI_0_1 1 +#define KVM_ARM_PSCI_0_2 2 + +int kvm_psci_version(struct kvm_vcpu *vcpu); +int kvm_psci_call(struct kvm_vcpu *vcpu); #endif /* __ARM64_KVM_PSCI_H__ */ diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 90c811f05a2e32..97c39bab06be68 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -406,7 +406,7 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; /* * Ensure that there are not more swap files than can be encoded in the kernel - * the PTEs. + * PTEs. */ #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index eaf54a30bedcef..e6471daf3fb5dd 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -31,6 +31,7 @@ #define KVM_NR_SPSR 5 #ifndef __ASSEMBLY__ +#include #include #include @@ -77,6 +78,7 @@ struct kvm_regs { #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ #define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */ +#define KVM_ARM_VCPU_PSCI_0_2 2 /* CPU uses PSCI v0.2 */ struct kvm_vcpu_init { __u32 target; @@ -186,10 +188,10 @@ struct kvm_arch_memory_slot { #define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2) #define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3) -#define KVM_PSCI_RET_SUCCESS 0 -#define KVM_PSCI_RET_NI ((unsigned long)-1) -#define KVM_PSCI_RET_INVAL ((unsigned long)-2) -#define KVM_PSCI_RET_DENIED ((unsigned long)-3) +#define KVM_PSCI_RET_SUCCESS PSCI_RET_SUCCESS +#define KVM_PSCI_RET_NI PSCI_RET_NOT_SUPPORTED +#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS +#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED #endif diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 7d811d9522bc4f..7a6fce5167e9d1 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -18,7 +18,6 @@ arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o -arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o arm64-obj-$(CONFIG_KGDB) += kgdb.o diff --git a/arch/arm64/kernel/early_printk.c b/arch/arm64/kernel/early_printk.c deleted file mode 100644 index 2dc36d00addffa..00000000000000 --- a/arch/arm64/kernel/early_printk.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Earlyprintk support. - * - * Copyright (C) 2012 ARM Ltd. - * Author: Catalin Marinas - * - * 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, see . - */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -static void __iomem *early_base; -static void (*printch)(char ch); - -/* - * PL011 single character TX. - */ -static void pl011_printch(char ch) -{ - while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_TXFF) - ; - writeb_relaxed(ch, early_base + UART01x_DR); - while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_BUSY) - ; -} - -/* - * Semihosting-based debug console - */ -static void smh_printch(char ch) -{ - asm volatile("mov x1, %0\n" - "mov x0, #3\n" - "hlt 0xf000\n" - : : "r" (&ch) : "x0", "x1", "memory"); -} - -/* - * 8250/16550 (8-bit aligned registers) single character TX. - */ -static void uart8250_8bit_printch(char ch) -{ - while (!(readb_relaxed(early_base + UART_LSR) & UART_LSR_THRE)) - ; - writeb_relaxed(ch, early_base + UART_TX); -} - -/* - * 8250/16550 (32-bit aligned registers) single character TX. - */ -static void uart8250_32bit_printch(char ch) -{ - while (!(readl_relaxed(early_base + (UART_LSR << 2)) & UART_LSR_THRE)) - ; - writel_relaxed(ch, early_base + (UART_TX << 2)); -} - -struct earlycon_match { - const char *name; - void (*printch)(char ch); -}; - -static const struct earlycon_match earlycon_match[] __initconst = { - { .name = "pl011", .printch = pl011_printch, }, - { .name = "smh", .printch = smh_printch, }, - { .name = "uart8250-8bit", .printch = uart8250_8bit_printch, }, - { .name = "uart8250-32bit", .printch = uart8250_32bit_printch, }, - {} -}; - -static void early_write(struct console *con, const char *s, unsigned n) -{ - while (n-- > 0) { - if (*s == '\n') - printch('\r'); - printch(*s); - s++; - } -} - -static struct console early_console_dev = { - .name = "earlycon", - .write = early_write, - .flags = CON_PRINTBUFFER | CON_BOOT, - .index = -1, -}; - -/* - * Parse earlyprintk=... parameter in the format: - * - * [,][,] - * - * and register the early console. It is assumed that the UART has been - * initialised by the bootloader already. - */ -static int __init setup_early_printk(char *buf) -{ - const struct earlycon_match *match = earlycon_match; - phys_addr_t paddr = 0; - - if (!buf) { - pr_warning("No earlyprintk arguments passed.\n"); - return 0; - } - - while (match->name) { - size_t len = strlen(match->name); - if (!strncmp(buf, match->name, len)) { - buf += len; - break; - } - match++; - } - if (!match->name) { - pr_warning("Unknown earlyprintk arguments: %s\n", buf); - return 0; - } - - /* I/O address */ - if (!strncmp(buf, ",0x", 3)) { - char *e; - paddr = simple_strtoul(buf + 1, &e, 16); - buf = e; - } - /* no options parsing yet */ - - if (paddr) - early_base = (void __iomem *)set_fixmap_offset_io(FIX_EARLYCON_MEM_BASE, paddr); - - printch = match->printch; - early_console = &early_console_dev; - register_console(&early_console_dev); - - return 0; -} - -early_param("earlyprintk", setup_early_printk); diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 7bc41eab4c649b..182415e1a952bf 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -30,11 +30,15 @@ typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *); static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) { - if (kvm_psci_call(vcpu)) + int ret; + + ret = kvm_psci_call(vcpu); + if (ret < 0) { + kvm_inject_undefined(vcpu); return 1; + } - kvm_inject_undefined(vcpu); - return 1; + return ret; } static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 51d5352e6ad5b2..091d428d64aca3 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -126,8 +126,6 @@ static void arm64_memory_present(void) void __init arm64_memblock_init(void) { - u64 *reserve_map, base, size; - /* Register the kernel text, kernel data and initrd with memblock */ memblock_reserve(__pa(_text), _end - _text); #ifdef CONFIG_BLK_DEV_INITRD @@ -142,25 +140,6 @@ void __init arm64_memblock_init(void) memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE); memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE); - /* Reserve the dtb region */ - memblock_reserve(virt_to_phys(initial_boot_params), - be32_to_cpu(initial_boot_params->totalsize)); - - /* - * Process the reserve map. This will probably overlap the initrd - * and dtb locations which are already reserved, but overlapping - * doesn't hurt anything - */ - reserve_map = ((void*)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_mem_rsvmap); - while (1) { - base = be64_to_cpup(reserve_map++); - size = be64_to_cpup(reserve_map++); - if (!size) - break; - memblock_reserve(base, size); - } - early_init_fdt_scan_reserved_mem(); dma_contiguous_reserve(0); diff --git a/arch/avr32/include/asm/atomic.h b/arch/avr32/include/asm/atomic.h index 61407279208ab4..0780f3f2415bec 100644 --- a/arch/avr32/include/asm/atomic.h +++ b/arch/avr32/include/asm/atomic.h @@ -183,9 +183,4 @@ static inline int atomic_sub_if_positive(int i, atomic_t *v) #define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v) -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif /* __ASM_AVR32_ATOMIC_H */ diff --git a/arch/avr32/include/asm/bitops.h b/arch/avr32/include/asm/bitops.h index ebe7ad3f490b3e..910d5374ce59fb 100644 --- a/arch/avr32/include/asm/bitops.h +++ b/arch/avr32/include/asm/bitops.h @@ -13,12 +13,7 @@ #endif #include - -/* - * clear_bit() doesn't provide any barrier for the compiler - */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() +#include /* * set_bit - Atomically set a bit in memory @@ -67,7 +62,7 @@ static inline void set_bit(int nr, volatile void * addr) * * clear_bit() is atomic and may not be reordered. However, it does * not contain a memory barrier, so if it is used for locking purposes, - * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic() * in order to ensure changes are visible on other processors. */ static inline void clear_bit(int nr, volatile void * addr) diff --git a/arch/blackfin/include/asm/barrier.h b/arch/blackfin/include/asm/barrier.h index 19283a16ac0806..420006877998ff 100644 --- a/arch/blackfin/include/asm/barrier.h +++ b/arch/blackfin/include/asm/barrier.h @@ -27,6 +27,9 @@ #endif /* !CONFIG_SMP */ +#define smp_mb__before_atomic() barrier() +#define smp_mb__after_atomic() barrier() + #include #endif /* _BLACKFIN_BARRIER_H */ diff --git a/arch/blackfin/include/asm/bitops.h b/arch/blackfin/include/asm/bitops.h index 0ca40dd4472420..b298b654a26f35 100644 --- a/arch/blackfin/include/asm/bitops.h +++ b/arch/blackfin/include/asm/bitops.h @@ -27,21 +27,17 @@ #include +#include + #ifndef CONFIG_SMP #include - /* * clear_bit may not imply a memory barrier */ -#ifndef smp_mb__before_clear_bit -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() -#endif #include #include #else -#include #include /* swab32 */ #include @@ -101,12 +97,6 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr) return __raw_bit_test_toggle_asm(a, nr & 0x1f); } -/* - * clear_bit() doesn't provide any barrier for the compiler. - */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() - #define test_bit __skip_test_bit #include #undef test_bit diff --git a/arch/blackfin/mach-bf609/boards/ezkit.c b/arch/blackfin/mach-bf609/boards/ezkit.c index 943f7e95ec15a6..1ba4600de69f72 100644 --- a/arch/blackfin/mach-bf609/boards/ezkit.c +++ b/arch/blackfin/mach-bf609/boards/ezkit.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -767,13 +767,13 @@ static struct flash_platform_data bfin_spi_flash_data = { .type = "w25q32", }; -static struct bfin_spi3_chip spi_flash_chip_info = { +static struct adi_spi3_chip spi_flash_chip_info = { .enable_dma = true, /* use dma transfer with this chip*/ }; #endif #if IS_ENABLED(CONFIG_SPI_SPIDEV) -static struct bfin_spi3_chip spidev_chip_info = { +static struct adi_spi3_chip spidev_chip_info = { .enable_dma = true, }; #endif @@ -1736,7 +1736,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, #endif }; -#if IS_ENABLED(CONFIG_SPI_BFIN_V3) +#if IS_ENABLED(CONFIG_SPI_ADI_V3) /* SPI (0) */ static struct resource bfin_spi0_resource[] = { { @@ -1777,13 +1777,13 @@ static struct resource bfin_spi1_resource[] = { }; /* SPI controller data */ -static struct bfin_spi3_master bf60x_spi_master_info0 = { +static struct adi_spi3_master bf60x_spi_master_info0 = { .num_chipselect = MAX_CTRL_CS + MAX_BLACKFIN_GPIOS, .pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0}, }; static struct platform_device bf60x_spi_master0 = { - .name = "bfin-spi3", + .name = "adi-spi3", .id = 0, /* Bus number */ .num_resources = ARRAY_SIZE(bfin_spi0_resource), .resource = bfin_spi0_resource, @@ -1792,13 +1792,13 @@ static struct platform_device bf60x_spi_master0 = { }, }; -static struct bfin_spi3_master bf60x_spi_master_info1 = { +static struct adi_spi3_master bf60x_spi_master_info1 = { .num_chipselect = MAX_CTRL_CS + MAX_BLACKFIN_GPIOS, .pin_req = {P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0}, }; static struct platform_device bf60x_spi_master1 = { - .name = "bfin-spi3", + .name = "adi-spi3", .id = 1, /* Bus number */ .num_resources = ARRAY_SIZE(bfin_spi1_resource), .resource = bfin_spi1_resource, @@ -1990,7 +1990,7 @@ static struct platform_device *ezkit_devices[] __initdata = { &bfin_sdh_device, #endif -#if IS_ENABLED(CONFIG_SPI_BFIN_V3) +#if IS_ENABLED(CONFIG_SPI_ADI_V3) &bf60x_spi_master0, &bf60x_spi_master1, #endif @@ -2051,8 +2051,8 @@ static struct pinctrl_map __initdata bfin_pinmux_map[] = { PIN_MAP_MUX_GROUP_DEFAULT("bfin_sir.1", "pinctrl-adi2.0", NULL, "uart1"), PIN_MAP_MUX_GROUP_DEFAULT("bfin-sdh.0", "pinctrl-adi2.0", NULL, "rsi0"), PIN_MAP_MUX_GROUP_DEFAULT("stmmaceth.0", "pinctrl-adi2.0", NULL, "eth0"), - PIN_MAP_MUX_GROUP_DEFAULT("bfin-spi3.0", "pinctrl-adi2.0", NULL, "spi0"), - PIN_MAP_MUX_GROUP_DEFAULT("bfin-spi3.1", "pinctrl-adi2.0", NULL, "spi1"), + PIN_MAP_MUX_GROUP_DEFAULT("adi-spi3.0", "pinctrl-adi2.0", NULL, "spi0"), + PIN_MAP_MUX_GROUP_DEFAULT("adi-spi3.1", "pinctrl-adi2.0", NULL, "spi1"), PIN_MAP_MUX_GROUP_DEFAULT("i2c-bfin-twi.0", "pinctrl-adi2.0", NULL, "twi0"), PIN_MAP_MUX_GROUP_DEFAULT("i2c-bfin-twi.1", "pinctrl-adi2.0", NULL, "twi1"), PIN_MAP_MUX_GROUP_DEFAULT("bfin-rotary", "pinctrl-adi2.0", NULL, "rotary"), diff --git a/arch/blackfin/mach-bf609/clock.c b/arch/blackfin/mach-bf609/clock.c index 56200f37cfc8cf..244fa4ab4c56b8 100644 --- a/arch/blackfin/mach-bf609/clock.c +++ b/arch/blackfin/mach-bf609/clock.c @@ -363,6 +363,12 @@ static struct clk ethclk = { .ops = &dummy_clk_ops, }; +static struct clk spiclk = { + .name = "spi", + .parent = &sclk1, + .ops = &dummy_clk_ops, +}; + static struct clk_lookup bf609_clks[] = { CLK(sys_clkin, NULL, "SYS_CLKIN"), CLK(pll_clk, NULL, "PLLCLK"), @@ -375,6 +381,7 @@ static struct clk_lookup bf609_clks[] = { CLK(dclk, NULL, "DCLK"), CLK(oclk, NULL, "OCLK"), CLK(ethclk, NULL, "stmmaceth"), + CLK(spiclk, NULL, "spi"), }; int __init clk_init(void) diff --git a/arch/c6x/include/asm/bitops.h b/arch/c6x/include/asm/bitops.h index 0bec7e5036a853..f0ab012401b67c 100644 --- a/arch/c6x/include/asm/bitops.h +++ b/arch/c6x/include/asm/bitops.h @@ -14,14 +14,8 @@ #ifdef __KERNEL__ #include - #include - -/* - * clear_bit() doesn't provide any barrier for the compiler. - */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() +#include /* * We are lucky, DSP is perfect for bitops: do it in 3 cycles diff --git a/arch/c6x/kernel/setup.c b/arch/c6x/kernel/setup.c index 731db4b9014dfa..757128868d4324 100644 --- a/arch/c6x/kernel/setup.c +++ b/arch/c6x/kernel/setup.c @@ -265,8 +265,8 @@ int __init c6x_add_memory(phys_addr_t start, unsigned long size) */ notrace void __init machine_init(unsigned long dt_ptr) { - struct boot_param_header *dtb = __va(dt_ptr); - struct boot_param_header *fdt = (struct boot_param_header *)_fdt_start; + const void *dtb = __va(dt_ptr); + const void *fdt = _fdt_start; /* interrupts must be masked */ set_creg(IER, 2); diff --git a/arch/cris/include/asm/atomic.h b/arch/cris/include/asm/atomic.h index 1056a5dfe04f31..aa429baebaf91a 100644 --- a/arch/cris/include/asm/atomic.h +++ b/arch/cris/include/asm/atomic.h @@ -7,6 +7,8 @@ #include #include #include +#include +#include /* * Atomic operations that C can't guarantee us. Useful for @@ -151,10 +153,4 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) return ret; } -/* Atomic operations are already serializing */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif diff --git a/arch/cris/include/asm/bitops.h b/arch/cris/include/asm/bitops.h index 053c17b3655926..bd49a546f4f5f6 100644 --- a/arch/cris/include/asm/bitops.h +++ b/arch/cris/include/asm/bitops.h @@ -21,6 +21,7 @@ #include #include #include +#include /* * set_bit - Atomically set a bit in memory @@ -42,7 +43,7 @@ * * clear_bit() is atomic and may not be reordered. However, it does * not contain a memory barrier, so if it is used for locking purposes, - * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic() * in order to ensure changes are visible on other processors. */ @@ -84,12 +85,6 @@ static inline int test_and_set_bit(int nr, volatile unsigned long *addr) return retval; } -/* - * clear_bit() doesn't provide any barrier for the compiler. - */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() - /** * test_and_clear_bit - Clear a bit and return its old value * @nr: Bit to clear diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index b86329d0e31656..f6c3a16901011b 100644 --- a/arch/frv/include/asm/atomic.h +++ b/arch/frv/include/asm/atomic.h @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_SMP #error not SMP safe @@ -29,12 +30,6 @@ * We do not have SMP systems, so we don't have to deal with that. */ -/* Atomic operations are already serializing */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #define ATOMIC_INIT(i) { (i) } #define atomic_read(v) (*(volatile int *)&(v)->counter) #define atomic_set(v, i) (((v)->counter) = (i)) diff --git a/arch/frv/include/asm/bitops.h b/arch/frv/include/asm/bitops.h index 57bf85db893f16..96de220ef131ed 100644 --- a/arch/frv/include/asm/bitops.h +++ b/arch/frv/include/asm/bitops.h @@ -25,12 +25,6 @@ #include -/* - * clear_bit() doesn't provide any barrier for the compiler. - */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() - #ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS static inline unsigned long atomic_test_and_ANDNOT_mask(unsigned long mask, volatile unsigned long *v) diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h index 17dc63780c0695..de916b11bff520 100644 --- a/arch/hexagon/include/asm/atomic.h +++ b/arch/hexagon/include/asm/atomic.h @@ -24,6 +24,7 @@ #include #include +#include #define ATOMIC_INIT(i) { (i) } @@ -176,9 +177,4 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #define atomic_inc_return(v) (atomic_add_return(1, v)) #define atomic_dec_return(v) (atomic_sub_return(1, v)) -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif diff --git a/arch/hexagon/include/asm/bitops.h b/arch/hexagon/include/asm/bitops.h index 9b1e4afbab3c65..5e4a59b3ec1bb0 100644 --- a/arch/hexagon/include/asm/bitops.h +++ b/arch/hexagon/include/asm/bitops.h @@ -25,12 +25,10 @@ #include #include #include +#include #ifdef __KERNEL__ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() - /* * The offset calculations for these are based on BITS_PER_LONG == 32 * (i.e. I get to shift by #5-2 (32 bits per long, 4 bytes per access), diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h index d651102a4d4579..97cb16086314b6 100644 --- a/arch/ia64/include/asm/acpi.h +++ b/arch/ia64/include/asm/acpi.h @@ -92,7 +92,6 @@ ia64_acpi_release_global_lock (unsigned int *lock) #endif #define acpi_processor_cstate_check(x) (x) /* no idle limits on IA64 :) */ static inline void disable_acpi(void) { } -static inline void pci_acpi_crs_quirks(void) { } #ifdef CONFIG_IA64_GENERIC const char *acpi_get_sysname (void); diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h index 6e6fe1839f5d57..0f8bf48dadf3ce 100644 --- a/arch/ia64/include/asm/atomic.h +++ b/arch/ia64/include/asm/atomic.h @@ -15,6 +15,7 @@ #include #include +#include #define ATOMIC_INIT(i) { (i) } @@ -208,10 +209,4 @@ atomic64_add_negative (__s64 i, atomic64_t *v) #define atomic64_inc(v) atomic64_add(1, (v)) #define atomic64_dec(v) atomic64_sub(1, (v)) -/* Atomic operations are already serializing */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif /* _ASM_IA64_ATOMIC_H */ diff --git a/arch/ia64/include/asm/barrier.h b/arch/ia64/include/asm/barrier.h index d0a69aa35e27de..a48957c7b445a2 100644 --- a/arch/ia64/include/asm/barrier.h +++ b/arch/ia64/include/asm/barrier.h @@ -55,6 +55,9 @@ #endif +#define smp_mb__before_atomic() barrier() +#define smp_mb__after_atomic() barrier() + /* * IA64 GCC turns volatile stores into st.rel and volatile loads into ld.acq no * need for asm trickery! diff --git a/arch/ia64/include/asm/bitops.h b/arch/ia64/include/asm/bitops.h index c27eccd333495a..71e8145243ee88 100644 --- a/arch/ia64/include/asm/bitops.h +++ b/arch/ia64/include/asm/bitops.h @@ -16,6 +16,7 @@ #include #include #include +#include /** * set_bit - Atomically set a bit in memory @@ -65,12 +66,6 @@ __set_bit (int nr, volatile void *addr) *((__u32 *) addr + (nr >> 5)) |= (1 << (nr & 31)); } -/* - * clear_bit() has "acquire" semantics. - */ -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() do { /* skip */; } while (0) - /** * clear_bit - Clears a bit in memory * @nr: Bit to clear @@ -78,7 +73,7 @@ __set_bit (int nr, volatile void *addr) * * clear_bit() is atomic and may not be reordered. However, it does * not contain a memory barrier, so if it is used for locking purposes, - * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic() * in order to ensure changes are visible on other processors. */ static __inline__ void diff --git a/arch/ia64/include/asm/syscall.h b/arch/ia64/include/asm/syscall.h index a7ff1c6ab0689a..1d0b875fec44fc 100644 --- a/arch/ia64/include/asm/syscall.h +++ b/arch/ia64/include/asm/syscall.h @@ -13,6 +13,7 @@ #ifndef _ASM_SYSCALL_H #define _ASM_SYSCALL_H 1 +#include #include #include @@ -79,4 +80,9 @@ static inline void syscall_set_arguments(struct task_struct *task, ia64_syscall_get_set_arguments(task, regs, i, n, args, 1); } + +static inline int syscall_get_arch(void) +{ + return AUDIT_ARCH_IA64; +} #endif /* _ASM_SYSCALL_H */ diff --git a/arch/ia64/include/asm/thread_info.h b/arch/ia64/include/asm/thread_info.h index 5957cf61f89806..5b17418b42239b 100644 --- a/arch/ia64/include/asm/thread_info.h +++ b/arch/ia64/include/asm/thread_info.h @@ -107,6 +107,7 @@ struct thread_info { #define TIF_MCA_INIT 18 /* this task is processing MCA or INIT */ #define TIF_DB_DISABLED 19 /* debug trap disabled for fsyscall */ #define TIF_RESTORE_RSE 21 /* user RBS is newer than kernel RBS */ +#define TIF_POLLING_NRFLAG 22 /* idle is polling for TIF_NEED_RESCHED */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) @@ -118,6 +119,7 @@ struct thread_info { #define _TIF_MCA_INIT (1 << TIF_MCA_INIT) #define _TIF_DB_DISABLED (1 << TIF_DB_DISABLED) #define _TIF_RESTORE_RSE (1 << TIF_RESTORE_RSE) +#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) /* "work to do on user-return" bits */ #define TIF_ALLWORK_MASK (_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SYSCALL_AUDIT|\ @@ -125,7 +127,6 @@ struct thread_info { /* like TIF_ALLWORK_BITS but sans TIF_SYSCALL_TRACE or TIF_SYSCALL_AUDIT */ #define TIF_WORK_MASK (TIF_ALLWORK_MASK&~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)) -#define TS_POLLING 1 /* true if in idle loop and not sleeping */ #define TS_RESTORE_SIGMASK 2 /* restore signal mask in do_signal() */ #ifndef __ASSEMBLY__ diff --git a/arch/ia64/include/asm/topology.h b/arch/ia64/include/asm/topology.h index 3555fddc1cf58e..6437ca21f61b49 100644 --- a/arch/ia64/include/asm/topology.h +++ b/arch/ia64/include/asm/topology.h @@ -47,30 +47,6 @@ void build_cpu_to_node_map(void); -#define SD_CPU_INIT (struct sched_domain) { \ - .parent = NULL, \ - .child = NULL, \ - .groups = NULL, \ - .min_interval = 1, \ - .max_interval = 4, \ - .busy_factor = 64, \ - .imbalance_pct = 125, \ - .cache_nice_tries = 2, \ - .busy_idx = 2, \ - .idle_idx = 1, \ - .newidle_idx = 0, \ - .wake_idx = 0, \ - .forkexec_idx = 0, \ - .flags = SD_LOAD_BALANCE \ - | SD_BALANCE_NEWIDLE \ - | SD_BALANCE_EXEC \ - | SD_BALANCE_FORK \ - | SD_WAKE_AFFINE, \ - .last_balance = jiffies, \ - .balance_interval = 1, \ - .nr_balance_failed = 0, \ -} - #endif /* CONFIG_NUMA */ #ifdef CONFIG_SMP diff --git a/arch/ia64/include/uapi/asm/cmpxchg.h b/arch/ia64/include/uapi/asm/cmpxchg.h index 4f37dbbb864081..f35109b1d9076c 100644 --- a/arch/ia64/include/uapi/asm/cmpxchg.h +++ b/arch/ia64/include/uapi/asm/cmpxchg.h @@ -118,6 +118,15 @@ extern long ia64_cmpxchg_called_with_bad_pointer(void); #define cmpxchg_rel(ptr, o, n) \ ia64_cmpxchg(rel, (ptr), (o), (n), sizeof(*(ptr))) +/* + * Worse still - early processor implementations actually just ignored + * the acquire/release and did a full fence all the time. Unfortunately + * this meant a lot of badly written code that used .acq when they really + * wanted .rel became legacy out in the wild - so when we made a cpu + * that strictly did the .acq or .rel ... all that code started breaking - so + * we had to back-pedal and keep the "legacy" behavior of a full fence :-( + */ + /* for compatibility with other platforms: */ #define cmpxchg(ptr, o, n) cmpxchg_acq((ptr), (o), (n)) #define cmpxchg64(ptr, o, n) cmpxchg_acq((ptr), (o), (n)) diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index b7a5fffe0924e0..6f54d511cc509a 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1219,7 +1219,7 @@ syscall_trace_enter (long arg0, long arg1, long arg2, long arg3, ia64_sync_krbs(); - audit_syscall_entry(AUDIT_ARCH_IA64, regs.r15, arg0, arg1, arg2, arg3); + audit_syscall_entry(regs.r15, arg0, arg1, arg2, arg3); return 0; } diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h index 0d81697c326c26..8ad0ed4182a540 100644 --- a/arch/m32r/include/asm/atomic.h +++ b/arch/m32r/include/asm/atomic.h @@ -13,6 +13,7 @@ #include #include #include +#include /* * Atomic operations that C can't guarantee us. Useful for @@ -308,10 +309,4 @@ static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *addr) local_irq_restore(flags); } -/* Atomic operations are already serializing on m32r */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif /* _ASM_M32R_ATOMIC_H */ diff --git a/arch/m32r/include/asm/bitops.h b/arch/m32r/include/asm/bitops.h index d3dea9ac7d4e38..86ba2b42a6cfa0 100644 --- a/arch/m32r/include/asm/bitops.h +++ b/arch/m32r/include/asm/bitops.h @@ -21,6 +21,7 @@ #include #include #include +#include /* * These have to be done with inline assembly: that way the bit-setting @@ -73,7 +74,7 @@ static __inline__ void set_bit(int nr, volatile void * addr) * * clear_bit() is atomic and may not be reordered. However, it does * not contain a memory barrier, so if it is used for locking purposes, - * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic() * in order to ensure changes are visible on other processors. */ static __inline__ void clear_bit(int nr, volatile void * addr) @@ -103,9 +104,6 @@ static __inline__ void clear_bit(int nr, volatile void * addr) local_irq_restore(flags); } -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() - /** * change_bit - Toggle a bit in memory * @nr: Bit to clear diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h index f4e32de263a7ce..55695212a2ae98 100644 --- a/arch/m68k/include/asm/atomic.h +++ b/arch/m68k/include/asm/atomic.h @@ -4,6 +4,7 @@ #include #include #include +#include /* * Atomic operations that C can't guarantee us. Useful for @@ -209,11 +210,4 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) return c; } - -/* Atomic operations are already serializing */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif /* __ARCH_M68K_ATOMIC __ */ diff --git a/arch/m68k/include/asm/bitops.h b/arch/m68k/include/asm/bitops.h index c6baa913592a84..b4a9b0d5928dfb 100644 --- a/arch/m68k/include/asm/bitops.h +++ b/arch/m68k/include/asm/bitops.h @@ -13,6 +13,7 @@ #endif #include +#include /* * Bit access functions vary across the ColdFire and 68k families. @@ -67,12 +68,6 @@ static inline void bfset_mem_set_bit(int nr, volatile unsigned long *vaddr) #define __set_bit(nr, vaddr) set_bit(nr, vaddr) -/* - * clear_bit() doesn't provide any barrier for the compiler. - */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() - static inline void bclr_reg_clear_bit(int nr, volatile unsigned long *vaddr) { char *p = (char *)vaddr + (nr ^ 31) / 8; diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c index 5b16f5d61b44cb..88c27d94a7214c 100644 --- a/arch/m68k/kernel/setup_no.c +++ b/arch/m68k/kernel/setup_no.c @@ -58,17 +58,16 @@ void (*mach_halt)(void); void (*mach_power_off)(void); #ifdef CONFIG_M68000 -#define CPU_NAME "MC68000" -#endif -#ifdef CONFIG_M68328 +#if defined(CONFIG_M68328) #define CPU_NAME "MC68328" -#endif -#ifdef CONFIG_M68EZ328 +#elif defined(CONFIG_M68EZ328) #define CPU_NAME "MC68EZ328" -#endif -#ifdef CONFIG_M68VZ328 +#elif defined(CONFIG_M68VZ328) #define CPU_NAME "MC68VZ328" +#else +#define CPU_NAME "MC68000" #endif +#endif /* CONFIG_M68000 */ #ifdef CONFIG_M68360 #define CPU_NAME "MC68360" #endif diff --git a/arch/m68k/platform/68000/m68EZ328.c b/arch/m68k/platform/68000/m68EZ328.c index 332b5e8605fcdf..21952906e9e218 100644 --- a/arch/m68k/platform/68000/m68EZ328.c +++ b/arch/m68k/platform/68000/m68EZ328.c @@ -69,7 +69,8 @@ void __init config_BSP(char *command, int len) if (p) strcpy(p,command); else command[0] = 0; #endif - + + mach_sched_init = hw_timer_init; mach_hwclk = m68328_hwclk; mach_reset = m68ez328_reset; } diff --git a/arch/m68k/platform/68000/m68VZ328.c b/arch/m68k/platform/68000/m68VZ328.c index fd6658358af1aa..0e5e5a10a02126 100644 --- a/arch/m68k/platform/68000/m68VZ328.c +++ b/arch/m68k/platform/68000/m68VZ328.c @@ -182,6 +182,7 @@ void __init config_BSP(char *command, int size) init_hardware(command, size); + mach_sched_init = hw_timer_init; mach_hwclk = m68328_hwclk; mach_reset = m68vz328_reset; } diff --git a/arch/metag/include/asm/atomic.h b/arch/metag/include/asm/atomic.h index 307ecd2bd9a171..470e365f04ea4e 100644 --- a/arch/metag/include/asm/atomic.h +++ b/arch/metag/include/asm/atomic.h @@ -4,6 +4,7 @@ #include #include #include +#include #if defined(CONFIG_METAG_ATOMICITY_IRQSOFF) /* The simple UP case. */ @@ -39,11 +40,6 @@ #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif #define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v) diff --git a/arch/metag/include/asm/barrier.h b/arch/metag/include/asm/barrier.h index 5d6b4b407ddab2..d1768c6f5b1824 100644 --- a/arch/metag/include/asm/barrier.h +++ b/arch/metag/include/asm/barrier.h @@ -97,4 +97,7 @@ do { \ ___p1; \ }) +#define smp_mb__before_atomic() barrier() +#define smp_mb__after_atomic() barrier() + #endif /* _ASM_METAG_BARRIER_H */ diff --git a/arch/metag/include/asm/bitops.h b/arch/metag/include/asm/bitops.h index c0d0df0d13786a..2671134ee74593 100644 --- a/arch/metag/include/asm/bitops.h +++ b/arch/metag/include/asm/bitops.h @@ -5,12 +5,6 @@ #include #include -/* - * clear_bit() doesn't provide any barrier for the compiler. - */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() - #ifdef CONFIG_SMP /* * These functions are the basis of our bit ops. diff --git a/arch/metag/kernel/setup.c b/arch/metag/kernel/setup.c index 129c7cdda1ced1..31cf53d0eba263 100644 --- a/arch/metag/kernel/setup.c +++ b/arch/metag/kernel/setup.c @@ -105,10 +105,6 @@ extern char _heap_start[]; -#ifdef CONFIG_METAG_BUILTIN_DTB -extern u32 __dtb_start[]; -#endif - #ifdef CONFIG_DA_CONSOLE /* Our early channel based console driver */ extern struct console dash_console; diff --git a/arch/microblaze/include/asm/syscall.h b/arch/microblaze/include/asm/syscall.h index 9bc431783105ca..53cfaf34c34330 100644 --- a/arch/microblaze/include/asm/syscall.h +++ b/arch/microblaze/include/asm/syscall.h @@ -1,6 +1,7 @@ #ifndef __ASM_MICROBLAZE_SYSCALL_H #define __ASM_MICROBLAZE_SYSCALL_H +#include #include #include #include @@ -99,4 +100,8 @@ static inline void syscall_set_arguments(struct task_struct *task, asmlinkage long do_syscall_trace_enter(struct pt_regs *regs); asmlinkage void do_syscall_trace_leave(struct pt_regs *regs); +static inline int syscall_get_arch(void) +{ + return AUDIT_ARCH_MICROBLAZE; +} #endif /* __ASM_MICROBLAZE_SYSCALL_H */ diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index abdfb10e7eca32..68f099960ebc92 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -43,13 +43,13 @@ #include #ifdef CONFIG_EARLY_PRINTK -static char *stdout; +static const char *stdout; static int __init early_init_dt_scan_chosen_serial(unsigned long node, const char *uname, int depth, void *data) { - unsigned long l; - char *p; + int l; + const char *p; pr_debug("%s: depth: %d, uname: %s\n", __func__, depth, uname); @@ -80,7 +80,7 @@ static int __init early_init_dt_scan_chosen_serial(unsigned long node, (strncmp(p, "xlnx,opb-uartlite", 17) == 0) || (strncmp(p, "xlnx,axi-uartlite", 17) == 0) || (strncmp(p, "xlnx,mdm", 8) == 0)) { - unsigned int *addrp; + const unsigned int *addrp; *(u32 *)data = UARTLITE; @@ -114,34 +114,3 @@ void __init early_init_devtree(void *params) pr_debug(" <- early_init_devtree()\n"); } - -/******* - * - * New implementation of the OF "find" APIs, return a refcounted - * object, call of_node_put() when done. The device tree and list - * are protected by a rw_lock. - * - * Note that property management will need some locking as well, - * this isn't dealt with yet. - * - *******/ - -#if defined(CONFIG_DEBUG_FS) && defined(DEBUG) -static struct debugfs_blob_wrapper flat_dt_blob; - -static int __init export_flat_device_tree(void) -{ - struct dentry *d; - - flat_dt_blob.data = initial_boot_params; - flat_dt_blob.size = initial_boot_params->totalsize; - - d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR, - of_debugfs_root, &flat_dt_blob); - if (!d) - return 1; - - return 0; -} -device_initcall(export_flat_device_tree); -#endif diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c index 39cf50841f6d57..bb10637ce688b3 100644 --- a/arch/microblaze/kernel/ptrace.c +++ b/arch/microblaze/kernel/ptrace.c @@ -147,8 +147,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) */ ret = -1L; - audit_syscall_entry(EM_MICROBLAZE, regs->r12, regs->r5, regs->r6, - regs->r7, regs->r8); + audit_syscall_entry(regs->r12, regs->r5, regs->r6, regs->r7, regs->r8); return ret ?: regs->r12; } diff --git a/arch/mips/Kbuild b/arch/mips/Kbuild index d2cfe45f332b41..cc39966ca63d55 100644 --- a/arch/mips/Kbuild +++ b/arch/mips/Kbuild @@ -16,7 +16,6 @@ obj- := $(platform-) obj-y += kernel/ obj-y += mm/ -obj-y += math-emu/ ifdef CONFIG_KVM obj-y += kvm/ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5cd695f905a1c4..45e75b6173b5c5 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -83,6 +83,7 @@ config AR7 select SYS_HAS_EARLY_PRINTK select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_MIPS16 select SYS_SUPPORTS_ZBOOT_UART16550 select ARCH_REQUIRE_GPIOLIB select VLYNQ @@ -106,6 +107,7 @@ config ATH79 select SYS_HAS_EARLY_PRINTK select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_MIPS16 help Support for the Atheros AR71XX/AR724X/AR913X SoCs. @@ -122,6 +124,7 @@ config BCM47XX select NO_EXCEPT_FILL select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_MIPS16 select SYS_HAS_EARLY_PRINTK select USE_GENERIC_EARLY_PRINTK_8250 help @@ -248,6 +251,7 @@ config LANTIQ select SYS_HAS_CPU_MIPS32_R2 select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_MIPS16 select SYS_SUPPORTS_MULTITHREADING select SYS_HAS_EARLY_PRINTK select ARCH_REQUIRE_GPIOLIB @@ -330,6 +334,7 @@ config MIPS_MALTA select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_MIPS_CMP select SYS_SUPPORTS_MIPS_CPS + select SYS_SUPPORTS_MIPS16 select SYS_SUPPORTS_MULTITHREADING select SYS_SUPPORTS_SMARTMIPS select SYS_SUPPORTS_ZBOOT @@ -361,6 +366,7 @@ config MIPS_SEAD3 select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_SMARTMIPS select SYS_SUPPORTS_MICROMIPS + select SYS_SUPPORTS_MIPS16 select USB_EHCI_BIG_ENDIAN_DESC select USB_EHCI_BIG_ENDIAN_MMIO select USE_OF @@ -380,6 +386,7 @@ config MACH_VR41XX select CEVT_R4K select CSRC_R4K select SYS_HAS_CPU_VR41XX + select SYS_SUPPORTS_MIPS16 select ARCH_REQUIRE_GPIOLIB config NXP_STB220 @@ -407,6 +414,7 @@ config PMC_MSP select SYS_HAS_CPU_MIPS32_R2 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_MIPS16 select IRQ_CPU select SERIAL_8250 select SERIAL_8250_CONSOLE @@ -430,6 +438,7 @@ config RALINK select SYS_HAS_CPU_MIPS32_R2 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_MIPS16 select SYS_HAS_EARLY_PRINTK select HAVE_MACH_CLKDEV select CLKDEV_LOOKUP @@ -1059,6 +1068,7 @@ config SOC_PNX833X select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_MIPS16 select CPU_MIPSR2_IRQ_VI config SOC_PNX8335 @@ -2199,6 +2209,13 @@ config SYS_SUPPORTS_SMARTMIPS config SYS_SUPPORTS_MICROMIPS bool +config SYS_SUPPORTS_MIPS16 + bool + help + This option must be set if a kernel might be executed on a MIPS16- + enabled CPU even if MIPS16 is not actually being used. In other + words, it makes the kernel MIPS16-tolerant. + config CPU_SUPPORTS_MSA bool diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 1a5b4032cb662b..4852ae97e7df1a 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -251,6 +251,7 @@ OBJCOPYFLAGS += --remove-section=.reginfo head-y := arch/mips/kernel/head.o libs-y += arch/mips/lib/ +libs-y += arch/mips/math-emu/ # See arch/mips/Kbuild for content of core part of the kernel core-y += arch/mips/ diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 331b837cec57d2..f1bec00d5a85dd 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -1053,36 +1053,26 @@ void prom_free_prom_memory(void) int octeon_prune_device_tree(void); extern const char __dtb_octeon_3xxx_begin; -extern const char __dtb_octeon_3xxx_end; extern const char __dtb_octeon_68xx_begin; -extern const char __dtb_octeon_68xx_end; void __init device_tree_init(void) { - int dt_size; - struct boot_param_header *fdt; + const void *fdt; bool do_prune; if (octeon_bootinfo->minor_version >= 3 && octeon_bootinfo->fdt_addr) { fdt = phys_to_virt(octeon_bootinfo->fdt_addr); if (fdt_check_header(fdt)) panic("Corrupt Device Tree passed to kernel."); - dt_size = be32_to_cpu(fdt->totalsize); do_prune = false; } else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { - fdt = (struct boot_param_header *)&__dtb_octeon_68xx_begin; - dt_size = &__dtb_octeon_68xx_end - &__dtb_octeon_68xx_begin; + fdt = &__dtb_octeon_68xx_begin; do_prune = true; } else { - fdt = (struct boot_param_header *)&__dtb_octeon_3xxx_begin; - dt_size = &__dtb_octeon_3xxx_end - &__dtb_octeon_3xxx_begin; + fdt = &__dtb_octeon_3xxx_begin; do_prune = true; } - /* Copy the default tree from init memory. */ - initial_boot_params = early_init_dt_alloc_memory_arch(dt_size, 8); - if (initial_boot_params == NULL) - panic("Could not allocate initial_boot_params"); - memcpy(initial_boot_params, fdt, dt_size); + initial_boot_params = (void *)fdt; if (do_prune) { octeon_prune_device_tree(); @@ -1090,7 +1080,7 @@ void __init device_tree_init(void) } else { pr_info("Using passed Device Tree.\n"); } - unflatten_device_tree(); + unflatten_and_copy_device_tree(); } static int __initdata disable_octeon_edac_p; diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c index 5abf4e894216ac..2a66e908f6a9d9 100644 --- a/arch/mips/dec/ecc-berr.c +++ b/arch/mips/dec/ecc-berr.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/mips/dec/kn02xa-berr.c b/arch/mips/dec/kn02xa-berr.c index f434b759e3b9aa..ec606363b80677 100644 --- a/arch/mips/dec/kn02xa-berr.c +++ b/arch/mips/dec/kn02xa-berr.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile index 064ae7a76bdc20..ae73e42ac20b16 100644 --- a/arch/mips/dec/prom/Makefile +++ b/arch/mips/dec/prom/Makefile @@ -6,4 +6,3 @@ lib-y += init.o memory.o cmdline.o identify.o console.o lib-$(CONFIG_32BIT) += locore.o -lib-$(CONFIG_64BIT) += call_o32.o diff --git a/arch/mips/dec/prom/call_o32.S b/arch/mips/dec/prom/call_o32.S deleted file mode 100644 index 8c8498159e434f..00000000000000 --- a/arch/mips/dec/prom/call_o32.S +++ /dev/null @@ -1,89 +0,0 @@ -/* - * O32 interface for the 64 (or N32) ABI. - * - * Copyright (C) 2002 Maciej W. Rozycki - * - * 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 - -/* Maximum number of arguments supported. Must be even! */ -#define O32_ARGC 32 -/* Number of static registers we save. */ -#define O32_STATC 11 -/* Frame size for both of the above. */ -#define O32_FRAMESZ (4 * O32_ARGC + SZREG * O32_STATC) - - .text - -/* - * O32 function call dispatcher, for interfacing 32-bit ROM routines. - * - * The standard 64 (N32) calling sequence is supported, with a0 - * holding a function pointer, a1-a7 -- its first seven arguments - * and the stack -- remaining ones (up to O32_ARGC, including a1-a7). - * Static registers, gp and fp are preserved, v0 holds a result. - * This code relies on the called o32 function for sp and ra - * restoration and thus both this dispatcher and the current stack - * have to be placed in a KSEGx (or KUSEG) address space. Any - * pointers passed have to point to addresses within one of these - * spaces as well. - */ -NESTED(call_o32, O32_FRAMESZ, ra) - REG_SUBU sp,O32_FRAMESZ - - REG_S ra,O32_FRAMESZ-1*SZREG(sp) - REG_S fp,O32_FRAMESZ-2*SZREG(sp) - REG_S gp,O32_FRAMESZ-3*SZREG(sp) - REG_S s7,O32_FRAMESZ-4*SZREG(sp) - REG_S s6,O32_FRAMESZ-5*SZREG(sp) - REG_S s5,O32_FRAMESZ-6*SZREG(sp) - REG_S s4,O32_FRAMESZ-7*SZREG(sp) - REG_S s3,O32_FRAMESZ-8*SZREG(sp) - REG_S s2,O32_FRAMESZ-9*SZREG(sp) - REG_S s1,O32_FRAMESZ-10*SZREG(sp) - REG_S s0,O32_FRAMESZ-11*SZREG(sp) - - move jp,a0 - - sll a0,a1,zero - sll a1,a2,zero - sll a2,a3,zero - sll a3,a4,zero - sw a5,0x10(sp) - sw a6,0x14(sp) - sw a7,0x18(sp) - - PTR_LA t0,O32_FRAMESZ(sp) - PTR_LA t1,0x1c(sp) - li t2,O32_ARGC-7 -1: - lw t3,(t0) - REG_ADDU t0,SZREG - sw t3,(t1) - REG_SUBU t2,1 - REG_ADDU t1,4 - bnez t2,1b - - jalr jp - - REG_L s0,O32_FRAMESZ-11*SZREG(sp) - REG_L s1,O32_FRAMESZ-10*SZREG(sp) - REG_L s2,O32_FRAMESZ-9*SZREG(sp) - REG_L s3,O32_FRAMESZ-8*SZREG(sp) - REG_L s4,O32_FRAMESZ-7*SZREG(sp) - REG_L s5,O32_FRAMESZ-6*SZREG(sp) - REG_L s6,O32_FRAMESZ-5*SZREG(sp) - REG_L s7,O32_FRAMESZ-4*SZREG(sp) - REG_L gp,O32_FRAMESZ-3*SZREG(sp) - REG_L fp,O32_FRAMESZ-2*SZREG(sp) - REG_L ra,O32_FRAMESZ-1*SZREG(sp) - - REG_ADDU sp,O32_FRAMESZ - jr ra -END(call_o32) diff --git a/arch/mips/fw/lib/call_o32.S b/arch/mips/fw/lib/call_o32.S index b308b2a0613e21..4703fe4dbd9a7b 100644 --- a/arch/mips/fw/lib/call_o32.S +++ b/arch/mips/fw/lib/call_o32.S @@ -1,7 +1,7 @@ /* * O32 interface for the 64 (or N32) ABI. * - * Copyright (C) 2002 Maciej W. Rozycki + * Copyright (C) 2002, 2014 Maciej W. Rozycki * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -12,28 +12,37 @@ #include #include +/* O32 register size. */ +#define O32_SZREG 4 /* Maximum number of arguments supported. Must be even! */ #define O32_ARGC 32 -/* Number of static registers we save. */ +/* Number of static registers we save. */ #define O32_STATC 11 -/* Frame size for static register */ -#define O32_FRAMESZ (SZREG * O32_STATC) -/* Frame size on new stack */ -#define O32_FRAMESZ_NEW (SZREG + 4 * O32_ARGC) +/* Argument area frame size. */ +#define O32_ARGSZ (O32_SZREG * O32_ARGC) +/* Static register save area frame size. */ +#define O32_STATSZ (SZREG * O32_STATC) +/* Stack pointer register save area frame size. */ +#define O32_SPSZ SZREG +/* Combined area frame size. */ +#define O32_FRAMESZ (O32_ARGSZ + O32_SPSZ + O32_STATSZ) +/* Switched stack frame size. */ +#define O32_NFRAMESZ (O32_ARGSZ + O32_SPSZ) .text /* * O32 function call dispatcher, for interfacing 32-bit ROM routines. * - * The standard 64 (N32) calling sequence is supported, with a0 - * holding a function pointer, a1 a new stack pointer, a2-a7 -- its - * first six arguments and the stack -- remaining ones (up to O32_ARGC, - * including a2-a7). Static registers, gp and fp are preserved, v0 holds - * a result. This code relies on the called o32 function for sp and ra - * restoration and this dispatcher has to be placed in a KSEGx (or KUSEG) - * address space. Any pointers passed have to point to addresses within - * one of these spaces as well. + * The standard 64 (N32) calling sequence is supported, with a0 holding + * a function pointer, a1 a pointer to the new stack to call the + * function with or 0 if no stack switching is requested, a2-a7 -- the + * function call's first six arguments, and the stack -- the remaining + * arguments (up to O32_ARGC, including a2-a7). Static registers, gp + * and fp are preserved, v0 holds the result. This code relies on the + * called o32 function for sp and ra restoration and this dispatcher has + * to be placed in a KSEGx (or KUSEG) address space. Any pointers + * passed have to point to addresses within one of these spaces as well. */ NESTED(call_o32, O32_FRAMESZ, ra) REG_SUBU sp,O32_FRAMESZ @@ -51,32 +60,36 @@ NESTED(call_o32, O32_FRAMESZ, ra) REG_S s0,O32_FRAMESZ-11*SZREG(sp) move jp,a0 - REG_SUBU s0,a1,O32_FRAMESZ_NEW - REG_S sp,O32_FRAMESZ_NEW-1*SZREG(s0) + + move fp,sp + beqz a1,0f + REG_SUBU fp,a1,O32_NFRAMESZ +0: + REG_S sp,O32_NFRAMESZ-1*SZREG(fp) sll a0,a2,zero sll a1,a3,zero sll a2,a4,zero sll a3,a5,zero - sw a6,0x10(s0) - sw a7,0x14(s0) + sw a6,4*O32_SZREG(fp) + sw a7,5*O32_SZREG(fp) PTR_LA t0,O32_FRAMESZ(sp) - PTR_LA t1,0x18(s0) + PTR_LA t1,6*O32_SZREG(fp) li t2,O32_ARGC-6 1: lw t3,(t0) REG_ADDU t0,SZREG sw t3,(t1) REG_SUBU t2,1 - REG_ADDU t1,4 + REG_ADDU t1,O32_SZREG bnez t2,1b - move sp,s0 + move sp,fp jalr jp - REG_L sp,O32_FRAMESZ_NEW-1*SZREG(sp) + REG_L sp,O32_NFRAMESZ-1*SZREG(sp) REG_L s0,O32_FRAMESZ-11*SZREG(sp) REG_L s1,O32_FRAMESZ-10*SZREG(sp) diff --git a/arch/mips/fw/sni/sniprom.c b/arch/mips/fw/sni/sniprom.c index 2c2cb182af4edd..6aa264b9856ac9 100644 --- a/arch/mips/fw/sni/sniprom.c +++ b/arch/mips/fw/sni/sniprom.c @@ -40,7 +40,8 @@ #ifdef CONFIG_64BIT -static u8 o32_stk[16384]; +/* O32 stack has to be 8-byte aligned. */ +static u64 o32_stk[4096]; #define O32_STK &o32_stk[sizeof(o32_stk)] #define __PROM_O32(fun, arg) fun arg __asm__(#fun); \ diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index e8eb3d53a24161..37b2befe651a5e 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -761,13 +761,4 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) #endif /* CONFIG_64BIT */ -/* - * atomic*_return operations are serializing but not the non-*_return - * versions. - */ -#define smp_mb__before_atomic_dec() smp_mb__before_llsc() -#define smp_mb__after_atomic_dec() smp_llsc_mb() -#define smp_mb__before_atomic_inc() smp_mb__before_llsc() -#define smp_mb__after_atomic_inc() smp_llsc_mb() - #endif /* _ASM_ATOMIC_H */ diff --git a/arch/mips/include/asm/barrier.h b/arch/mips/include/asm/barrier.h index e1aa4e4c298423..d0101dd0575eec 100644 --- a/arch/mips/include/asm/barrier.h +++ b/arch/mips/include/asm/barrier.h @@ -195,4 +195,7 @@ do { \ ___p1; \ }) +#define smp_mb__before_atomic() smp_mb__before_llsc() +#define smp_mb__after_atomic() smp_llsc_mb() + #endif /* __ASM_BARRIER_H */ diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h index 6a65d49e2c0d4e..7c8816f7b7c4a8 100644 --- a/arch/mips/include/asm/bitops.h +++ b/arch/mips/include/asm/bitops.h @@ -37,13 +37,6 @@ #define __EXT "dext " #endif -/* - * clear_bit() doesn't provide any barrier for the compiler. - */ -#define smp_mb__before_clear_bit() smp_mb__before_llsc() -#define smp_mb__after_clear_bit() smp_llsc_mb() - - /* * These are the "slower" versions of the functions and are in bitops.c. * These functions call raw_local_irq_{save,restore}(). @@ -120,7 +113,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) * * clear_bit() is atomic and may not be reordered. However, it does * not contain a memory barrier, so if it is used for locking purposes, - * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic() * in order to ensure changes are visible on other processors. */ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) @@ -175,7 +168,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) */ static inline void clear_bit_unlock(unsigned long nr, volatile unsigned long *addr) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(nr, addr); } diff --git a/arch/mips/include/asm/branch.h b/arch/mips/include/asm/branch.h index e28a3e0eb3cb64..0171ffc80eb01e 100644 --- a/arch/mips/include/asm/branch.h +++ b/arch/mips/include/asm/branch.h @@ -8,6 +8,8 @@ #ifndef _ASM_BRANCH_H #define _ASM_BRANCH_H +#include +#include #include #include @@ -18,12 +20,40 @@ extern int __compute_return_epc_for_insn(struct pt_regs *regs, extern int __microMIPS_compute_return_epc(struct pt_regs *regs); extern int __MIPS16e_compute_return_epc(struct pt_regs *regs); +/* + * microMIPS bitfields + */ +#define MM_POOL32A_MINOR_MASK 0x3f +#define MM_POOL32A_MINOR_SHIFT 0x6 +#define MM_MIPS32_COND_FC 0x30 + +extern int __mm_isBranchInstr(struct pt_regs *regs, + const struct mm_decoded_insn * const dec_insn, unsigned long *contpc); + +static inline int mm_isBranchInstr(struct pt_regs *regs, + const struct mm_decoded_insn * const dec_insn, unsigned long *contpc) +{ + if (!cpu_has_mmips) + return 0; + + return __mm_isBranchInstr(regs, dec_insn, contpc); +} static inline int delay_slot(struct pt_regs *regs) { return regs->cp0_cause & CAUSEF_BD; } +static inline void clear_delay_slot(struct pt_regs *regs) +{ + regs->cp0_cause &= ~CAUSEF_BD; +} + +static inline void set_delay_slot(struct pt_regs *regs) +{ + regs->cp0_cause |= CAUSEF_BD; +} + static inline unsigned long exception_epc(struct pt_regs *regs) { if (likely(!delay_slot(regs))) diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index f56cc975b92f85..f75dd70555081f 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -183,6 +183,17 @@ /* * Shortcuts ... */ +#define cpu_has_mips_2_3_4_5 (cpu_has_mips_2 | cpu_has_mips_3_4_5) +#define cpu_has_mips_3_4_5 (cpu_has_mips_3 | cpu_has_mips_4_5) +#define cpu_has_mips_4_5 (cpu_has_mips_4 | cpu_has_mips_5) + +#define cpu_has_mips_2_3_4_5_r (cpu_has_mips_2 | cpu_has_mips_3_4_5_r) +#define cpu_has_mips_3_4_5_r (cpu_has_mips_3 | cpu_has_mips_4_5_r) +#define cpu_has_mips_4_5_r (cpu_has_mips_4 | cpu_has_mips_5_r) +#define cpu_has_mips_5_r (cpu_has_mips_5 | cpu_has_mips_r) + +#define cpu_has_mips_4_5_r2 (cpu_has_mips_4_5 | cpu_has_mips_r2) + #define cpu_has_mips32 (cpu_has_mips32r1 | cpu_has_mips32r2) #define cpu_has_mips64 (cpu_has_mips64r1 | cpu_has_mips64r2) #define cpu_has_mips_r1 (cpu_has_mips32r1 | cpu_has_mips64r1) diff --git a/arch/mips/include/asm/dec/prom.h b/arch/mips/include/asm/dec/prom.h index c0ead63138453c..b59a2103b61a3f 100644 --- a/arch/mips/include/asm/dec/prom.h +++ b/arch/mips/include/asm/dec/prom.h @@ -113,31 +113,31 @@ extern int (*__pmax_close)(int); #define __DEC_PROM_O32(fun, arg) fun arg __asm__(#fun); \ __asm__(#fun " = call_o32") -int __DEC_PROM_O32(_rex_bootinit, (int (*)(void))); -int __DEC_PROM_O32(_rex_bootread, (int (*)(void))); -int __DEC_PROM_O32(_rex_getbitmap, (int (*)(memmap *), memmap *)); +int __DEC_PROM_O32(_rex_bootinit, (int (*)(void), void *)); +int __DEC_PROM_O32(_rex_bootread, (int (*)(void), void *)); +int __DEC_PROM_O32(_rex_getbitmap, (int (*)(memmap *), void *, memmap *)); unsigned long *__DEC_PROM_O32(_rex_slot_address, - (unsigned long *(*)(int), int)); -void *__DEC_PROM_O32(_rex_gettcinfo, (void *(*)(void))); -int __DEC_PROM_O32(_rex_getsysid, (int (*)(void))); -void __DEC_PROM_O32(_rex_clear_cache, (void (*)(void))); - -int __DEC_PROM_O32(_prom_getchar, (int (*)(void))); -char *__DEC_PROM_O32(_prom_getenv, (char *(*)(char *), char *)); -int __DEC_PROM_O32(_prom_printf, (int (*)(char *, ...), char *, ...)); - - -#define rex_bootinit() _rex_bootinit(__rex_bootinit) -#define rex_bootread() _rex_bootread(__rex_bootread) -#define rex_getbitmap(x) _rex_getbitmap(__rex_getbitmap, x) -#define rex_slot_address(x) _rex_slot_address(__rex_slot_address, x) -#define rex_gettcinfo() _rex_gettcinfo(__rex_gettcinfo) -#define rex_getsysid() _rex_getsysid(__rex_getsysid) -#define rex_clear_cache() _rex_clear_cache(__rex_clear_cache) - -#define prom_getchar() _prom_getchar(__prom_getchar) -#define prom_getenv(x) _prom_getenv(__prom_getenv, x) -#define prom_printf(x...) _prom_printf(__prom_printf, x) + (unsigned long *(*)(int), void *, int)); +void *__DEC_PROM_O32(_rex_gettcinfo, (void *(*)(void), void *)); +int __DEC_PROM_O32(_rex_getsysid, (int (*)(void), void *)); +void __DEC_PROM_O32(_rex_clear_cache, (void (*)(void), void *)); + +int __DEC_PROM_O32(_prom_getchar, (int (*)(void), void *)); +char *__DEC_PROM_O32(_prom_getenv, (char *(*)(char *), void *, char *)); +int __DEC_PROM_O32(_prom_printf, (int (*)(char *, ...), void *, char *, ...)); + + +#define rex_bootinit() _rex_bootinit(__rex_bootinit, NULL) +#define rex_bootread() _rex_bootread(__rex_bootread, NULL) +#define rex_getbitmap(x) _rex_getbitmap(__rex_getbitmap, NULL, x) +#define rex_slot_address(x) _rex_slot_address(__rex_slot_address, NULL, x) +#define rex_gettcinfo() _rex_gettcinfo(__rex_gettcinfo, NULL) +#define rex_getsysid() _rex_getsysid(__rex_getsysid, NULL) +#define rex_clear_cache() _rex_clear_cache(__rex_clear_cache, NULL) + +#define prom_getchar() _prom_getchar(__prom_getchar, NULL) +#define prom_getenv(x) _prom_getenv(__prom_getenv, NULL, x) +#define prom_printf(x...) _prom_printf(__prom_printf, NULL, x) #else /* !CONFIG_64BIT */ diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h index 4d86b72750c701..a939574f829387 100644 --- a/arch/mips/include/asm/fpu.h +++ b/arch/mips/include/asm/fpu.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +29,6 @@ struct sigcontext; struct sigcontext32; -extern void fpu_emulator_init_fpu(void); extern void _init_fpu(void); extern void _save_fp(struct task_struct *); extern void _restore_fp(struct task_struct *); @@ -156,15 +156,16 @@ static inline int init_fpu(void) int ret = 0; preempt_disable(); + if (cpu_has_fpu) { ret = __own_fpu(); if (!ret) _init_fpu(); - } else { + } else fpu_emulator_init_fpu(); - } preempt_enable(); + return ret; } diff --git a/arch/mips/include/asm/fpu_emulator.h b/arch/mips/include/asm/fpu_emulator.h index 2abb587d5ab40f..0a7e76d4ba67a8 100644 --- a/arch/mips/include/asm/fpu_emulator.h +++ b/arch/mips/include/asm/fpu_emulator.h @@ -23,9 +23,12 @@ #ifndef _ASM_FPU_EMULATOR_H #define _ASM_FPU_EMULATOR_H +#include #include +#include #include #include +#include #ifdef CONFIG_DEBUG_FS @@ -58,8 +61,6 @@ extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, int has_fpu, void *__user *fault_addr); int process_fpemu_return(int sig, void __user *fault_addr); -int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, - unsigned long *contpc); /* * Instruction inserted following the badinst to further tag the sequence @@ -71,4 +72,19 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, */ #define BREAK_MATH (0x0000000d | (BRK_MEMU << 16)) +#define SIGNALLING_NAN 0x7ff800007ff80000LL + +static inline void fpu_emulator_init_fpu(void) +{ + struct task_struct *t = current; + int i; + + t->thread.fpu.fcr31 = 0; + + for (i = 0; i < 32; i++) + set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN); +} + +extern int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr); + #endif /* _ASM_FPU_EMULATOR_H */ diff --git a/arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h index 1bcb6421205e3d..1dfe47453ea413 100644 --- a/arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h @@ -39,6 +39,10 @@ #define cpu_has_nofpuex 0 #define cpu_has_64bits 1 +#define cpu_has_mips_2 1 +#define cpu_has_mips_3 1 +#define cpu_has_mips_5 0 + #define cpu_has_mips32r1 0 #define cpu_has_mips32r2 0 #define cpu_has_mips64r1 0 diff --git a/arch/mips/include/asm/mach-jz4740/dma.h b/arch/mips/include/asm/mach-jz4740/dma.h index 509cd58280444d..14ecc5313d2d32 100644 --- a/arch/mips/include/asm/mach-jz4740/dma.h +++ b/arch/mips/include/asm/mach-jz4740/dma.h @@ -22,8 +22,6 @@ enum jz4740_dma_request_type { JZ4740_DMA_TYPE_UART_RECEIVE = 21, JZ4740_DMA_TYPE_SPI_TRANSMIT = 22, JZ4740_DMA_TYPE_SPI_RECEIVE = 23, - JZ4740_DMA_TYPE_AIC_TRANSMIT = 24, - JZ4740_DMA_TYPE_AIC_RECEIVE = 25, JZ4740_DMA_TYPE_MMC_TRANSMIT = 26, JZ4740_DMA_TYPE_MMC_RECEIVE = 27, JZ4740_DMA_TYPE_TCU = 28, diff --git a/arch/mips/include/asm/mips-boards/generic.h b/arch/mips/include/asm/mips-boards/generic.h index 48616816bcbc90..c904c24550f619 100644 --- a/arch/mips/include/asm/mips-boards/generic.h +++ b/arch/mips/include/asm/mips-boards/generic.h @@ -67,10 +67,6 @@ extern int mips_revision_sconid; -#ifdef CONFIG_OF -extern struct boot_param_header __dtb_start; -#endif - #ifdef CONFIG_PCI extern void mips_pcibios_init(void); #else diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 3e025b5311db72..2e48a680426314 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -709,11 +709,17 @@ #ifndef __ASSEMBLY__ /* - * Macros for handling the ISA mode bit for microMIPS. + * Macros for handling the ISA mode bit for MIPS16 and microMIPS. */ +#if defined(CONFIG_SYS_SUPPORTS_MIPS16) || defined(SYS_SUPPORTS_MICROMIPS) #define get_isa16_mode(x) ((x) & 0x1) #define msk_isa16_mode(x) ((x) & ~0x1) #define set_isa16_mode(x) do { (x) |= 0x1; } while(0) +#else +#define get_isa16_mode(x) 0 +#define msk_isa16_mode(x) (x) +#define set_isa16_mode(x) do { } while(0) +#endif /* * microMIPS instructions can be 16-bit or 32-bit in length. This diff --git a/arch/mips/include/asm/prom.h b/arch/mips/include/asm/prom.h index ccd2b75f152cce..a9494c0141fbce 100644 --- a/arch/mips/include/asm/prom.h +++ b/arch/mips/include/asm/prom.h @@ -21,13 +21,13 @@ extern void device_tree_init(void); struct boot_param_header; -extern void __dt_setup_arch(struct boot_param_header *bph); +extern void __dt_setup_arch(void *bph); #define dt_setup_arch(sym) \ ({ \ - extern struct boot_param_header __dtb_##sym##_begin; \ + extern char __dtb_##sym##_begin[]; \ \ - __dt_setup_arch(&__dtb_##sym##_begin); \ + __dt_setup_arch(__dtb_##sym##_begin); \ }) #else /* CONFIG_OF */ diff --git a/arch/mips/include/asm/rm9k-ocd.h b/arch/mips/include/asm/rm9k-ocd.h deleted file mode 100644 index b0b80d9ecf961f..00000000000000 --- a/arch/mips/include/asm/rm9k-ocd.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2004 by Basler Vision Technologies AG - * Author: Thomas Koeller - * - * 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 - */ - -#if !defined(_ASM_RM9K_OCD_H) -#define _ASM_RM9K_OCD_H - -#include -#include -#include - -extern volatile void __iomem * const ocd_base; -extern volatile void __iomem * const titan_base; - -#define ocd_addr(__x__) (ocd_base + (__x__)) -#define titan_addr(__x__) (titan_base + (__x__)) -#define scram_addr(__x__) (scram_base + (__x__)) - -/* OCD register access */ -#define ocd_readl(__offs__) __raw_readl(ocd_addr(__offs__)) -#define ocd_readw(__offs__) __raw_readw(ocd_addr(__offs__)) -#define ocd_readb(__offs__) __raw_readb(ocd_addr(__offs__)) -#define ocd_writel(__val__, __offs__) \ - __raw_writel((__val__), ocd_addr(__offs__)) -#define ocd_writew(__val__, __offs__) \ - __raw_writew((__val__), ocd_addr(__offs__)) -#define ocd_writeb(__val__, __offs__) \ - __raw_writeb((__val__), ocd_addr(__offs__)) - -/* TITAN register access - 32 bit-wide only */ -#define titan_readl(__offs__) __raw_readl(titan_addr(__offs__)) -#define titan_writel(__val__, __offs__) \ - __raw_writel((__val__), titan_addr(__offs__)) - -/* Protect access to shared TITAN registers */ -extern spinlock_t titan_lock; -extern int titan_irqflags; -#define lock_titan_regs() spin_lock_irqsave(&titan_lock, titan_irqflags) -#define unlock_titan_regs() spin_unlock_irqrestore(&titan_lock, titan_irqflags) - -#endif /* !defined(_ASM_RM9K_OCD_H) */ diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h index c6e9cd2bca8dbf..c2e5a79fdea0c2 100644 --- a/arch/mips/include/asm/syscall.h +++ b/arch/mips/include/asm/syscall.h @@ -129,7 +129,7 @@ extern const unsigned long sysn32_call_table[]; static inline int syscall_get_arch(void) { - int arch = EM_MIPS; + int arch = AUDIT_ARCH_MIPS; #ifdef CONFIG_64BIT if (!test_thread_flag(TIF_32BIT_REGS)) arch |= __AUDIT_ARCH_64BIT; diff --git a/arch/mips/include/uapi/asm/Kbuild b/arch/mips/include/uapi/asm/Kbuild index be7196eacb8890..96fe7395ed8dc8 100644 --- a/arch/mips/include/uapi/asm/Kbuild +++ b/arch/mips/include/uapi/asm/Kbuild @@ -4,6 +4,7 @@ include include/uapi/asm-generic/Kbuild.asm generic-y += auxvec.h generic-y += ipcbuf.h +header-y += bitfield.h header-y += bitsperlong.h header-y += break.h header-y += byteorder.h diff --git a/arch/mips/include/uapi/asm/bitfield.h b/arch/mips/include/uapi/asm/bitfield.h new file mode 100644 index 00000000000000..ad9861359cea7f --- /dev/null +++ b/arch/mips/include/uapi/asm/bitfield.h @@ -0,0 +1,29 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2014 by Ralf Baechle + */ +#ifndef __UAPI_ASM_BITFIELD_H +#define __UAPI_ASM_BITFIELD_H + +/* + * * Damn ... bitfields depend from byteorder :-( + * */ +#ifdef __MIPSEB__ +#define __BITFIELD_FIELD(field, more) \ + field; \ + more + +#elif defined(__MIPSEL__) + +#define __BITFIELD_FIELD(field, more) \ + more \ + field; + +#else /* !defined (__MIPSEB__) && !defined (__MIPSEL__) */ +#error "MIPS but neither __MIPSEL__ nor __MIPSEB__?" +#endif + +#endif /* __UAPI_ASM_BITFIELD_H */ diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index df6e775f3fef52..fce8367da245eb 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -13,6 +13,8 @@ #ifndef _UAPI_ASM_INST_H #define _UAPI_ASM_INST_H +#include + /* * Major opcodes; before MIPS IV cop1x was called cop3. */ @@ -480,131 +482,113 @@ enum MIPS6e_i8_func { */ #define MM_NOP16 0x0c00 -/* - * Damn ... bitfields depend from byteorder :-( - */ -#ifdef __MIPSEB__ -#define BITFIELD_FIELD(field, more) \ - field; \ - more - -#elif defined(__MIPSEL__) - -#define BITFIELD_FIELD(field, more) \ - more \ - field; - -#else /* !defined (__MIPSEB__) && !defined (__MIPSEL__) */ -#error "MIPS but neither __MIPSEL__ nor __MIPSEB__?" -#endif - struct j_format { - BITFIELD_FIELD(unsigned int opcode : 6, /* Jump format */ - BITFIELD_FIELD(unsigned int target : 26, + __BITFIELD_FIELD(unsigned int opcode : 6, /* Jump format */ + __BITFIELD_FIELD(unsigned int target : 26, ;)) }; struct i_format { /* signed immediate format */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rs : 5, - BITFIELD_FIELD(unsigned int rt : 5, - BITFIELD_FIELD(signed int simmediate : 16, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rs : 5, + __BITFIELD_FIELD(unsigned int rt : 5, + __BITFIELD_FIELD(signed int simmediate : 16, ;)))) }; struct u_format { /* unsigned immediate format */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rs : 5, - BITFIELD_FIELD(unsigned int rt : 5, - BITFIELD_FIELD(unsigned int uimmediate : 16, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rs : 5, + __BITFIELD_FIELD(unsigned int rt : 5, + __BITFIELD_FIELD(unsigned int uimmediate : 16, ;)))) }; struct c_format { /* Cache (>= R6000) format */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rs : 5, - BITFIELD_FIELD(unsigned int c_op : 3, - BITFIELD_FIELD(unsigned int cache : 2, - BITFIELD_FIELD(unsigned int simmediate : 16, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rs : 5, + __BITFIELD_FIELD(unsigned int c_op : 3, + __BITFIELD_FIELD(unsigned int cache : 2, + __BITFIELD_FIELD(unsigned int simmediate : 16, ;))))) }; struct r_format { /* Register format */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rs : 5, - BITFIELD_FIELD(unsigned int rt : 5, - BITFIELD_FIELD(unsigned int rd : 5, - BITFIELD_FIELD(unsigned int re : 5, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rs : 5, + __BITFIELD_FIELD(unsigned int rt : 5, + __BITFIELD_FIELD(unsigned int rd : 5, + __BITFIELD_FIELD(unsigned int re : 5, + __BITFIELD_FIELD(unsigned int func : 6, ;)))))) }; struct p_format { /* Performance counter format (R10000) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rs : 5, - BITFIELD_FIELD(unsigned int rt : 5, - BITFIELD_FIELD(unsigned int rd : 5, - BITFIELD_FIELD(unsigned int re : 5, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rs : 5, + __BITFIELD_FIELD(unsigned int rt : 5, + __BITFIELD_FIELD(unsigned int rd : 5, + __BITFIELD_FIELD(unsigned int re : 5, + __BITFIELD_FIELD(unsigned int func : 6, ;)))))) }; struct f_format { /* FPU register format */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int : 1, - BITFIELD_FIELD(unsigned int fmt : 4, - BITFIELD_FIELD(unsigned int rt : 5, - BITFIELD_FIELD(unsigned int rd : 5, - BITFIELD_FIELD(unsigned int re : 5, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int : 1, + __BITFIELD_FIELD(unsigned int fmt : 4, + __BITFIELD_FIELD(unsigned int rt : 5, + __BITFIELD_FIELD(unsigned int rd : 5, + __BITFIELD_FIELD(unsigned int re : 5, + __BITFIELD_FIELD(unsigned int func : 6, ;))))))) }; struct ma_format { /* FPU multiply and add format (MIPS IV) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int fr : 5, - BITFIELD_FIELD(unsigned int ft : 5, - BITFIELD_FIELD(unsigned int fs : 5, - BITFIELD_FIELD(unsigned int fd : 5, - BITFIELD_FIELD(unsigned int func : 4, - BITFIELD_FIELD(unsigned int fmt : 2, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int fr : 5, + __BITFIELD_FIELD(unsigned int ft : 5, + __BITFIELD_FIELD(unsigned int fs : 5, + __BITFIELD_FIELD(unsigned int fd : 5, + __BITFIELD_FIELD(unsigned int func : 4, + __BITFIELD_FIELD(unsigned int fmt : 2, ;))))))) }; struct b_format { /* BREAK and SYSCALL */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int code : 20, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int code : 20, + __BITFIELD_FIELD(unsigned int func : 6, ;))) }; struct ps_format { /* MIPS-3D / paired single format */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rs : 5, - BITFIELD_FIELD(unsigned int ft : 5, - BITFIELD_FIELD(unsigned int fs : 5, - BITFIELD_FIELD(unsigned int fd : 5, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rs : 5, + __BITFIELD_FIELD(unsigned int ft : 5, + __BITFIELD_FIELD(unsigned int fs : 5, + __BITFIELD_FIELD(unsigned int fd : 5, + __BITFIELD_FIELD(unsigned int func : 6, ;)))))) }; struct v_format { /* MDMX vector format */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int sel : 4, - BITFIELD_FIELD(unsigned int fmt : 1, - BITFIELD_FIELD(unsigned int vt : 5, - BITFIELD_FIELD(unsigned int vs : 5, - BITFIELD_FIELD(unsigned int vd : 5, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int sel : 4, + __BITFIELD_FIELD(unsigned int fmt : 1, + __BITFIELD_FIELD(unsigned int vt : 5, + __BITFIELD_FIELD(unsigned int vs : 5, + __BITFIELD_FIELD(unsigned int vd : 5, + __BITFIELD_FIELD(unsigned int func : 6, ;))))))) }; struct spec3_format { /* SPEC3 */ - BITFIELD_FIELD(unsigned int opcode:6, - BITFIELD_FIELD(unsigned int rs:5, - BITFIELD_FIELD(unsigned int rt:5, - BITFIELD_FIELD(signed int simmediate:9, - BITFIELD_FIELD(unsigned int func:7, + __BITFIELD_FIELD(unsigned int opcode:6, + __BITFIELD_FIELD(unsigned int rs:5, + __BITFIELD_FIELD(unsigned int rt:5, + __BITFIELD_FIELD(signed int simmediate:9, + __BITFIELD_FIELD(unsigned int func:7, ;))))) }; @@ -616,141 +600,141 @@ struct spec3_format { /* SPEC3 */ * if it is MIPS32 instruction re-encoded for use in the microMIPS ASE. */ struct fb_format { /* FPU branch format (MIPS32) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int bc : 5, - BITFIELD_FIELD(unsigned int cc : 3, - BITFIELD_FIELD(unsigned int flag : 2, - BITFIELD_FIELD(signed int simmediate : 16, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int bc : 5, + __BITFIELD_FIELD(unsigned int cc : 3, + __BITFIELD_FIELD(unsigned int flag : 2, + __BITFIELD_FIELD(signed int simmediate : 16, ;))))) }; struct fp0_format { /* FPU multiply and add format (MIPS32) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int fmt : 5, - BITFIELD_FIELD(unsigned int ft : 5, - BITFIELD_FIELD(unsigned int fs : 5, - BITFIELD_FIELD(unsigned int fd : 5, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int fmt : 5, + __BITFIELD_FIELD(unsigned int ft : 5, + __BITFIELD_FIELD(unsigned int fs : 5, + __BITFIELD_FIELD(unsigned int fd : 5, + __BITFIELD_FIELD(unsigned int func : 6, ;)))))) }; struct mm_fp0_format { /* FPU multipy and add format (microMIPS) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int ft : 5, - BITFIELD_FIELD(unsigned int fs : 5, - BITFIELD_FIELD(unsigned int fd : 5, - BITFIELD_FIELD(unsigned int fmt : 3, - BITFIELD_FIELD(unsigned int op : 2, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int ft : 5, + __BITFIELD_FIELD(unsigned int fs : 5, + __BITFIELD_FIELD(unsigned int fd : 5, + __BITFIELD_FIELD(unsigned int fmt : 3, + __BITFIELD_FIELD(unsigned int op : 2, + __BITFIELD_FIELD(unsigned int func : 6, ;))))))) }; struct fp1_format { /* FPU mfc1 and cfc1 format (MIPS32) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int op : 5, - BITFIELD_FIELD(unsigned int rt : 5, - BITFIELD_FIELD(unsigned int fs : 5, - BITFIELD_FIELD(unsigned int fd : 5, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int op : 5, + __BITFIELD_FIELD(unsigned int rt : 5, + __BITFIELD_FIELD(unsigned int fs : 5, + __BITFIELD_FIELD(unsigned int fd : 5, + __BITFIELD_FIELD(unsigned int func : 6, ;)))))) }; struct mm_fp1_format { /* FPU mfc1 and cfc1 format (microMIPS) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rt : 5, - BITFIELD_FIELD(unsigned int fs : 5, - BITFIELD_FIELD(unsigned int fmt : 2, - BITFIELD_FIELD(unsigned int op : 8, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rt : 5, + __BITFIELD_FIELD(unsigned int fs : 5, + __BITFIELD_FIELD(unsigned int fmt : 2, + __BITFIELD_FIELD(unsigned int op : 8, + __BITFIELD_FIELD(unsigned int func : 6, ;)))))) }; struct mm_fp2_format { /* FPU movt and movf format (microMIPS) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int fd : 5, - BITFIELD_FIELD(unsigned int fs : 5, - BITFIELD_FIELD(unsigned int cc : 3, - BITFIELD_FIELD(unsigned int zero : 2, - BITFIELD_FIELD(unsigned int fmt : 2, - BITFIELD_FIELD(unsigned int op : 3, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int fd : 5, + __BITFIELD_FIELD(unsigned int fs : 5, + __BITFIELD_FIELD(unsigned int cc : 3, + __BITFIELD_FIELD(unsigned int zero : 2, + __BITFIELD_FIELD(unsigned int fmt : 2, + __BITFIELD_FIELD(unsigned int op : 3, + __BITFIELD_FIELD(unsigned int func : 6, ;)))))))) }; struct mm_fp3_format { /* FPU abs and neg format (microMIPS) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rt : 5, - BITFIELD_FIELD(unsigned int fs : 5, - BITFIELD_FIELD(unsigned int fmt : 3, - BITFIELD_FIELD(unsigned int op : 7, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rt : 5, + __BITFIELD_FIELD(unsigned int fs : 5, + __BITFIELD_FIELD(unsigned int fmt : 3, + __BITFIELD_FIELD(unsigned int op : 7, + __BITFIELD_FIELD(unsigned int func : 6, ;)))))) }; struct mm_fp4_format { /* FPU c.cond format (microMIPS) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rt : 5, - BITFIELD_FIELD(unsigned int fs : 5, - BITFIELD_FIELD(unsigned int cc : 3, - BITFIELD_FIELD(unsigned int fmt : 3, - BITFIELD_FIELD(unsigned int cond : 4, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rt : 5, + __BITFIELD_FIELD(unsigned int fs : 5, + __BITFIELD_FIELD(unsigned int cc : 3, + __BITFIELD_FIELD(unsigned int fmt : 3, + __BITFIELD_FIELD(unsigned int cond : 4, + __BITFIELD_FIELD(unsigned int func : 6, ;))))))) }; struct mm_fp5_format { /* FPU lwxc1 and swxc1 format (microMIPS) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int index : 5, - BITFIELD_FIELD(unsigned int base : 5, - BITFIELD_FIELD(unsigned int fd : 5, - BITFIELD_FIELD(unsigned int op : 5, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int index : 5, + __BITFIELD_FIELD(unsigned int base : 5, + __BITFIELD_FIELD(unsigned int fd : 5, + __BITFIELD_FIELD(unsigned int op : 5, + __BITFIELD_FIELD(unsigned int func : 6, ;)))))) }; struct fp6_format { /* FPU madd and msub format (MIPS IV) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int fr : 5, - BITFIELD_FIELD(unsigned int ft : 5, - BITFIELD_FIELD(unsigned int fs : 5, - BITFIELD_FIELD(unsigned int fd : 5, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int fr : 5, + __BITFIELD_FIELD(unsigned int ft : 5, + __BITFIELD_FIELD(unsigned int fs : 5, + __BITFIELD_FIELD(unsigned int fd : 5, + __BITFIELD_FIELD(unsigned int func : 6, ;)))))) }; struct mm_fp6_format { /* FPU madd and msub format (microMIPS) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int ft : 5, - BITFIELD_FIELD(unsigned int fs : 5, - BITFIELD_FIELD(unsigned int fd : 5, - BITFIELD_FIELD(unsigned int fr : 5, - BITFIELD_FIELD(unsigned int func : 6, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int ft : 5, + __BITFIELD_FIELD(unsigned int fs : 5, + __BITFIELD_FIELD(unsigned int fd : 5, + __BITFIELD_FIELD(unsigned int fr : 5, + __BITFIELD_FIELD(unsigned int func : 6, ;)))))) }; struct mm_i_format { /* Immediate format (microMIPS) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rt : 5, - BITFIELD_FIELD(unsigned int rs : 5, - BITFIELD_FIELD(signed int simmediate : 16, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rt : 5, + __BITFIELD_FIELD(unsigned int rs : 5, + __BITFIELD_FIELD(signed int simmediate : 16, ;)))) }; struct mm_m_format { /* Multi-word load/store format (microMIPS) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rd : 5, - BITFIELD_FIELD(unsigned int base : 5, - BITFIELD_FIELD(unsigned int func : 4, - BITFIELD_FIELD(signed int simmediate : 12, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rd : 5, + __BITFIELD_FIELD(unsigned int base : 5, + __BITFIELD_FIELD(unsigned int func : 4, + __BITFIELD_FIELD(signed int simmediate : 12, ;))))) }; struct mm_x_format { /* Scaled indexed load format (microMIPS) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int index : 5, - BITFIELD_FIELD(unsigned int base : 5, - BITFIELD_FIELD(unsigned int rd : 5, - BITFIELD_FIELD(unsigned int func : 11, + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int index : 5, + __BITFIELD_FIELD(unsigned int base : 5, + __BITFIELD_FIELD(unsigned int rd : 5, + __BITFIELD_FIELD(unsigned int func : 11, ;))))) }; @@ -758,51 +742,51 @@ struct mm_x_format { /* Scaled indexed load format (microMIPS) */ * microMIPS instruction formats (16-bit length) */ struct mm_b0_format { /* Unconditional branch format (microMIPS) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(signed int simmediate : 10, - BITFIELD_FIELD(unsigned int : 16, /* Ignored */ + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(signed int simmediate : 10, + __BITFIELD_FIELD(unsigned int : 16, /* Ignored */ ;))) }; struct mm_b1_format { /* Conditional branch format (microMIPS) */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rs : 3, - BITFIELD_FIELD(signed int simmediate : 7, - BITFIELD_FIELD(unsigned int : 16, /* Ignored */ + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rs : 3, + __BITFIELD_FIELD(signed int simmediate : 7, + __BITFIELD_FIELD(unsigned int : 16, /* Ignored */ ;)))) }; struct mm16_m_format { /* Multi-word load/store format */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int func : 4, - BITFIELD_FIELD(unsigned int rlist : 2, - BITFIELD_FIELD(unsigned int imm : 4, - BITFIELD_FIELD(unsigned int : 16, /* Ignored */ + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int func : 4, + __BITFIELD_FIELD(unsigned int rlist : 2, + __BITFIELD_FIELD(unsigned int imm : 4, + __BITFIELD_FIELD(unsigned int : 16, /* Ignored */ ;))))) }; struct mm16_rb_format { /* Signed immediate format */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rt : 3, - BITFIELD_FIELD(unsigned int base : 3, - BITFIELD_FIELD(signed int simmediate : 4, - BITFIELD_FIELD(unsigned int : 16, /* Ignored */ + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rt : 3, + __BITFIELD_FIELD(unsigned int base : 3, + __BITFIELD_FIELD(signed int simmediate : 4, + __BITFIELD_FIELD(unsigned int : 16, /* Ignored */ ;))))) }; struct mm16_r3_format { /* Load from global pointer format */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rt : 3, - BITFIELD_FIELD(signed int simmediate : 7, - BITFIELD_FIELD(unsigned int : 16, /* Ignored */ + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rt : 3, + __BITFIELD_FIELD(signed int simmediate : 7, + __BITFIELD_FIELD(unsigned int : 16, /* Ignored */ ;)))) }; struct mm16_r5_format { /* Load/store from stack pointer format */ - BITFIELD_FIELD(unsigned int opcode : 6, - BITFIELD_FIELD(unsigned int rt : 5, - BITFIELD_FIELD(signed int simmediate : 5, - BITFIELD_FIELD(unsigned int : 16, /* Ignored */ + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rt : 5, + __BITFIELD_FIELD(signed int simmediate : 5, + __BITFIELD_FIELD(unsigned int : 16, /* Ignored */ ;)))) }; @@ -810,57 +794,57 @@ struct mm16_r5_format { /* Load/store from stack pointer format */ * MIPS16e instruction formats (16-bit length) */ struct m16e_rr { - BITFIELD_FIELD(unsigned int opcode : 5, - BITFIELD_FIELD(unsigned int rx : 3, - BITFIELD_FIELD(unsigned int nd : 1, - BITFIELD_FIELD(unsigned int l : 1, - BITFIELD_FIELD(unsigned int ra : 1, - BITFIELD_FIELD(unsigned int func : 5, + __BITFIELD_FIELD(unsigned int opcode : 5, + __BITFIELD_FIELD(unsigned int rx : 3, + __BITFIELD_FIELD(unsigned int nd : 1, + __BITFIELD_FIELD(unsigned int l : 1, + __BITFIELD_FIELD(unsigned int ra : 1, + __BITFIELD_FIELD(unsigned int func : 5, ;)))))) }; struct m16e_jal { - BITFIELD_FIELD(unsigned int opcode : 5, - BITFIELD_FIELD(unsigned int x : 1, - BITFIELD_FIELD(unsigned int imm20_16 : 5, - BITFIELD_FIELD(signed int imm25_21 : 5, + __BITFIELD_FIELD(unsigned int opcode : 5, + __BITFIELD_FIELD(unsigned int x : 1, + __BITFIELD_FIELD(unsigned int imm20_16 : 5, + __BITFIELD_FIELD(signed int imm25_21 : 5, ;)))) }; struct m16e_i64 { - BITFIELD_FIELD(unsigned int opcode : 5, - BITFIELD_FIELD(unsigned int func : 3, - BITFIELD_FIELD(unsigned int imm : 8, + __BITFIELD_FIELD(unsigned int opcode : 5, + __BITFIELD_FIELD(unsigned int func : 3, + __BITFIELD_FIELD(unsigned int imm : 8, ;))) }; struct m16e_ri64 { - BITFIELD_FIELD(unsigned int opcode : 5, - BITFIELD_FIELD(unsigned int func : 3, - BITFIELD_FIELD(unsigned int ry : 3, - BITFIELD_FIELD(unsigned int imm : 5, + __BITFIELD_FIELD(unsigned int opcode : 5, + __BITFIELD_FIELD(unsigned int func : 3, + __BITFIELD_FIELD(unsigned int ry : 3, + __BITFIELD_FIELD(unsigned int imm : 5, ;)))) }; struct m16e_ri { - BITFIELD_FIELD(unsigned int opcode : 5, - BITFIELD_FIELD(unsigned int rx : 3, - BITFIELD_FIELD(unsigned int imm : 8, + __BITFIELD_FIELD(unsigned int opcode : 5, + __BITFIELD_FIELD(unsigned int rx : 3, + __BITFIELD_FIELD(unsigned int imm : 8, ;))) }; struct m16e_rri { - BITFIELD_FIELD(unsigned int opcode : 5, - BITFIELD_FIELD(unsigned int rx : 3, - BITFIELD_FIELD(unsigned int ry : 3, - BITFIELD_FIELD(unsigned int imm : 5, + __BITFIELD_FIELD(unsigned int opcode : 5, + __BITFIELD_FIELD(unsigned int rx : 3, + __BITFIELD_FIELD(unsigned int ry : 3, + __BITFIELD_FIELD(unsigned int imm : 5, ;)))) }; struct m16e_i8 { - BITFIELD_FIELD(unsigned int opcode : 5, - BITFIELD_FIELD(unsigned int func : 3, - BITFIELD_FIELD(unsigned int imm : 8, + __BITFIELD_FIELD(unsigned int opcode : 5, + __BITFIELD_FIELD(unsigned int func : 3, + __BITFIELD_FIELD(unsigned int imm : 8, ;))) }; diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index c01900e5d07886..088e92a79ae600 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -425,6 +425,15 @@ static struct platform_device qi_lb60_audio_device = { .id = -1, }; +static struct gpiod_lookup_table qi_lb60_audio_gpio_table = { + .dev_id = "qi-lb60-audio", + .table = { + GPIO_LOOKUP("Bank B", 29, "snd", 0), + GPIO_LOOKUP("Bank D", 4, "amp", 0), + { }, + }, +}; + static struct platform_device *jz_platform_devices[] __initdata = { &jz4740_udc_device, &jz4740_udc_xceiv_device, @@ -461,6 +470,8 @@ static int __init qi_lb60_init_platform_devices(void) jz4740_adc_device.dev.platform_data = &qi_lb60_battery_pdata; jz4740_mmc_device.dev.platform_data = &qi_lb60_mmc_pdata; + gpiod_add_lookup_table(&qi_lb60_audio_gpio_table); + jz4740_serial_device_register(); spi_register_board_info(qi_lb60_spi_board_info, diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 4d78bf445a9cd2..8af8b7769e597d 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -48,6 +48,202 @@ int __isa_exception_epc(struct pt_regs *regs) return epc; } +/* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */ +static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7}; + +int __mm_isBranchInstr(struct pt_regs *regs, + const struct mm_decoded_insn * const dec_insn, unsigned long *contpc) +{ + union mips_instruction insn = (union mips_instruction)dec_insn->insn; + int bc_false = 0; + unsigned int fcr31; + unsigned int bit; + + if (!cpu_has_mmips) + return 0; + + switch (insn.mm_i_format.opcode) { + case mm_pool32a_op: + if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) == + mm_pool32axf_op) { + switch (insn.mm_i_format.simmediate >> + MM_POOL32A_MINOR_SHIFT) { + case mm_jalr_op: + case mm_jalrhb_op: + case mm_jalrs_op: + case mm_jalrshb_op: + if (insn.mm_i_format.rt != 0) /* Not mm_jr */ + regs->regs[insn.mm_i_format.rt] = + regs->cp0_epc + + dec_insn->pc_inc + + dec_insn->next_pc_inc; + *contpc = regs->regs[insn.mm_i_format.rs]; + return 1; + } + } + break; + case mm_pool32i_op: + switch (insn.mm_i_format.rt) { + case mm_bltzals_op: + case mm_bltzal_op: + regs->regs[31] = regs->cp0_epc + + dec_insn->pc_inc + + dec_insn->next_pc_inc; + /* Fall through */ + case mm_bltz_op: + if ((long)regs->regs[insn.mm_i_format.rs] < 0) + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + (insn.mm_i_format.simmediate << 1); + else + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + dec_insn->next_pc_inc; + return 1; + case mm_bgezals_op: + case mm_bgezal_op: + regs->regs[31] = regs->cp0_epc + + dec_insn->pc_inc + + dec_insn->next_pc_inc; + /* Fall through */ + case mm_bgez_op: + if ((long)regs->regs[insn.mm_i_format.rs] >= 0) + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + (insn.mm_i_format.simmediate << 1); + else + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + dec_insn->next_pc_inc; + return 1; + case mm_blez_op: + if ((long)regs->regs[insn.mm_i_format.rs] <= 0) + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + (insn.mm_i_format.simmediate << 1); + else + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + dec_insn->next_pc_inc; + return 1; + case mm_bgtz_op: + if ((long)regs->regs[insn.mm_i_format.rs] <= 0) + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + (insn.mm_i_format.simmediate << 1); + else + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + dec_insn->next_pc_inc; + return 1; + case mm_bc2f_op: + case mm_bc1f_op: + bc_false = 1; + /* Fall through */ + case mm_bc2t_op: + case mm_bc1t_op: + preempt_disable(); + if (is_fpu_owner()) + asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); + else + fcr31 = current->thread.fpu.fcr31; + preempt_enable(); + + if (bc_false) + fcr31 = ~fcr31; + + bit = (insn.mm_i_format.rs >> 2); + bit += (bit != 0); + bit += 23; + if (fcr31 & (1 << bit)) + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + (insn.mm_i_format.simmediate << 1); + else + *contpc = regs->cp0_epc + + dec_insn->pc_inc + dec_insn->next_pc_inc; + return 1; + } + break; + case mm_pool16c_op: + switch (insn.mm_i_format.rt) { + case mm_jalr16_op: + case mm_jalrs16_op: + regs->regs[31] = regs->cp0_epc + + dec_insn->pc_inc + dec_insn->next_pc_inc; + /* Fall through */ + case mm_jr16_op: + *contpc = regs->regs[insn.mm_i_format.rs]; + return 1; + } + break; + case mm_beqz16_op: + if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0) + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + (insn.mm_b1_format.simmediate << 1); + else + *contpc = regs->cp0_epc + + dec_insn->pc_inc + dec_insn->next_pc_inc; + return 1; + case mm_bnez16_op: + if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0) + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + (insn.mm_b1_format.simmediate << 1); + else + *contpc = regs->cp0_epc + + dec_insn->pc_inc + dec_insn->next_pc_inc; + return 1; + case mm_b16_op: + *contpc = regs->cp0_epc + dec_insn->pc_inc + + (insn.mm_b0_format.simmediate << 1); + return 1; + case mm_beq32_op: + if (regs->regs[insn.mm_i_format.rs] == + regs->regs[insn.mm_i_format.rt]) + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + (insn.mm_i_format.simmediate << 1); + else + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + dec_insn->next_pc_inc; + return 1; + case mm_bne32_op: + if (regs->regs[insn.mm_i_format.rs] != + regs->regs[insn.mm_i_format.rt]) + *contpc = regs->cp0_epc + + dec_insn->pc_inc + + (insn.mm_i_format.simmediate << 1); + else + *contpc = regs->cp0_epc + + dec_insn->pc_inc + dec_insn->next_pc_inc; + return 1; + case mm_jalx32_op: + regs->regs[31] = regs->cp0_epc + + dec_insn->pc_inc + dec_insn->next_pc_inc; + *contpc = regs->cp0_epc + dec_insn->pc_inc; + *contpc >>= 28; + *contpc <<= 28; + *contpc |= (insn.j_format.target << 2); + return 1; + case mm_jals32_op: + case mm_jal32_op: + regs->regs[31] = regs->cp0_epc + + dec_insn->pc_inc + dec_insn->next_pc_inc; + /* Fall through */ + case mm_j32_op: + *contpc = regs->cp0_epc + dec_insn->pc_inc; + *contpc >>= 27; + *contpc <<= 27; + *contpc |= (insn.j_format.target << 1); + set_isa16_mode(*contpc); + return 1; + } + return 0; +} + /* * Compute return address and emulate branch in microMIPS mode after an * exception only. It does not handle compact branches/jumps and cannot @@ -95,7 +291,7 @@ int __microMIPS_compute_return_epc(struct pt_regs *regs) } mminsn.next_insn = word; - mm_isBranchInstr(regs, mminsn, &contpc); + mm_isBranchInstr(regs, &mminsn, &contpc); regs->cp0_epc = contpc; diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index d1fea7a054be6b..1818da4dbb8556 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -62,9 +62,9 @@ void __init alloc_legacy_irqno(void) void free_irqno(unsigned int irq) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(irq, irq_map); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } /* diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index e40971b51d2f0b..037a44d962f37e 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -124,14 +124,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "kscratch registers\t: %d\n", hweight8(cpu_data[n].kscratch_mask)); seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); -#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) - if (cpu_has_mipsmt) { - seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id); -#if defined(CONFIG_MIPS_MT_SMTC) - seq_printf(m, "TC\t\t\t: %d\n", cpu_data[n].tc_id); -#endif - } -#endif + sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", cpu_has_vce ? "%u" : "not available"); seq_printf(m, fmt, 'D', vced_count); diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index 3c3b0df8f48d89..5d39bb85bf35a7 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -47,7 +47,7 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS)); } -void __init __dt_setup_arch(struct boot_param_header *bph) +void __init __dt_setup_arch(void *bph) { if (!early_init_dt_scan(bph)) return; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 71f85f42703412..6187caa0caac9b 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -649,9 +649,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall) if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->regs[2]); - audit_syscall_entry(syscall_get_arch(), - syscall, - regs->regs[4], regs->regs[5], + audit_syscall_entry(syscall, regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); return syscall; } diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 2b3517214d6d8c..27ceff224805a1 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -825,7 +825,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs, mminsn.next_insn = word; insn = (union mips_instruction)(mminsn.insn); - if (mm_isBranchInstr(regs, mminsn, &contpc)) + if (mm_isBranchInstr(regs, &mminsn, &contpc)) insn = (union mips_instruction)(mminsn.next_insn); /* Parse instruction to find what to do */ diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c index 19686c5bc5ed03..7447d322d14ef6 100644 --- a/arch/mips/lantiq/prom.c +++ b/arch/mips/lantiq/prom.c @@ -71,23 +71,12 @@ void __init plat_mem_setup(void) * Load the builtin devicetree. This causes the chosen node to be * parsed resulting in our memory appearing */ - __dt_setup_arch(&__dtb_start); + __dt_setup_arch(__dtb_start); } void __init device_tree_init(void) { - unsigned long base, size; - - if (!initial_boot_params) - return; - - base = virt_to_phys((void *)initial_boot_params); - size = be32_to_cpu(initial_boot_params->totalsize); - - /* Before we do anything, lets reserve the dt blob */ - reserve_bootmem(base, size, BOOTMEM_DEFAULT); - - unflatten_device_tree(); + unflatten_and_copy_device_tree(); } void __init prom_init(void) diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h index 8e07b5f28ef194..bfd2d58c1d69fa 100644 --- a/arch/mips/lantiq/prom.h +++ b/arch/mips/lantiq/prom.h @@ -26,6 +26,4 @@ struct ltq_soc_info { extern void ltq_soc_detect(struct ltq_soc_info *i); extern void ltq_soc_init(void); -extern struct boot_param_header __dtb_start; - #endif diff --git a/arch/mips/lib/csum_partial.S b/arch/mips/lib/csum_partial.S index 2e4825e483882b..9901237563c589 100644 --- a/arch/mips/lib/csum_partial.S +++ b/arch/mips/lib/csum_partial.S @@ -56,14 +56,20 @@ #define UNIT(unit) ((unit)*NBYTES) #define ADDC(sum,reg) \ + .set push; \ + .set noat; \ ADD sum, reg; \ sltu v1, sum, reg; \ ADD sum, v1; \ + .set pop #define ADDC32(sum,reg) \ + .set push; \ + .set noat; \ addu sum, reg; \ sltu v1, sum, reg; \ addu sum, v1; \ + .set pop #define CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3) \ LOAD _t0, (offset + UNIT(0))(src); \ @@ -710,6 +716,8 @@ LEAF(csum_partial) ADDC(sum, t2) .Ldone\@: /* fold checksum */ + .set push + .set noat #ifdef USE_DOUBLE dsll32 v1, sum, 0 daddu sum, v1 @@ -732,6 +740,7 @@ LEAF(csum_partial) or sum, sum, t0 1: #endif + .set pop .set reorder ADDC32(sum, psum) jr ra diff --git a/arch/mips/lib/delay.c b/arch/mips/lib/delay.c index 44713af15a62bc..705cfb7c1a74e0 100644 --- a/arch/mips/lib/delay.c +++ b/arch/mips/lib/delay.c @@ -6,7 +6,7 @@ * Copyright (C) 1994 by Waldorf Electronics * Copyright (C) 1995 - 2000, 01, 03 by Ralf Baechle * Copyright (C) 1999, 2000 Silicon Graphics, Inc. - * Copyright (C) 2007 Maciej W. Rozycki + * Copyright (C) 2007, 2014 Maciej W. Rozycki */ #include #include @@ -15,6 +15,12 @@ #include #include +#ifndef CONFIG_CPU_DADDI_WORKAROUNDS +#define GCC_DADDI_IMM_ASM() "I" +#else +#define GCC_DADDI_IMM_ASM() "r" +#endif + void __delay(unsigned long loops) { __asm__ __volatile__ ( @@ -22,13 +28,13 @@ void __delay(unsigned long loops) " .align 3 \n" "1: bnez %0, 1b \n" #if BITS_PER_LONG == 32 - " subu %0, 1 \n" + " subu %0, %1 \n" #else - " dsubu %0, 1 \n" + " dsubu %0, %1 \n" #endif " .set reorder \n" : "=r" (loops) - : "0" (loops)); + : GCC_DADDI_IMM_ASM() (1), "0" (loops)); } EXPORT_SYMBOL(__delay); diff --git a/arch/mips/lib/strncpy_user.S b/arch/mips/lib/strncpy_user.S index d3301cd1e9a51b..3c32baf8b49447 100644 --- a/arch/mips/lib/strncpy_user.S +++ b/arch/mips/lib/strncpy_user.S @@ -35,7 +35,6 @@ LEAF(__strncpy_from_\func\()_asm) bnez v0, .Lfault\@ FEXPORT(__strncpy_from_\func\()_nocheck_asm) - .set noreorder move t0, zero move v1, a1 .ifeqs "\func","kernel" @@ -45,21 +44,21 @@ FEXPORT(__strncpy_from_\func\()_nocheck_asm) .endif PTR_ADDIU v1, 1 R10KCBARRIER(0(ra)) + sb v0, (a0) beqz v0, 2f - sb v0, (a0) PTR_ADDIU t0, 1 + PTR_ADDIU a0, 1 bne t0, a2, 1b - PTR_ADDIU a0, 1 2: PTR_ADDU v0, a1, t0 xor v0, a1 bltz v0, .Lfault\@ - nop + move v0, t0 jr ra # return n - move v0, t0 END(__strncpy_from_\func\()_asm) -.Lfault\@: jr ra - li v0, -EFAULT +.Lfault\@: + li v0, -EFAULT + jr ra .section __ex_table,"a" PTR 1b, .Lfault\@ diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig index 7397be226a06a2..603d79a95f4778 100644 --- a/arch/mips/loongson/Kconfig +++ b/arch/mips/loongson/Kconfig @@ -64,7 +64,6 @@ config LEMOTE_MACH3A bool "Lemote Loongson 3A family machines" select ARCH_SPARSEMEM_ENABLE select GENERIC_ISA_DMA_SUPPORT_BROKEN - select GENERIC_HARDIRQS_NO__DO_IRQ select BOOT_ELF32 select BOARD_SCACHE select CSRC_R4K diff --git a/arch/mips/loongson/lemote-2f/clock.c b/arch/mips/loongson/lemote-2f/clock.c index e1f427f4f5f3fe..ebfb9cd71ca1b9 100644 --- a/arch/mips/loongson/lemote-2f/clock.c +++ b/arch/mips/loongson/lemote-2f/clock.c @@ -91,9 +91,10 @@ EXPORT_SYMBOL(clk_put); int clk_set_rate(struct clk *clk, unsigned long rate) { + unsigned int rate_khz = rate / 1000; + struct cpufreq_frequency_table *pos; int ret = 0; int regval; - int i; if (likely(clk->ops && clk->ops->set_rate)) { unsigned long flags; @@ -106,22 +107,16 @@ int clk_set_rate(struct clk *clk, unsigned long rate) if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) propagate_rate(clk); - for (i = 0; loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END; - i++) { - if (loongson2_clockmod_table[i].frequency == - CPUFREQ_ENTRY_INVALID) - continue; - if (rate == loongson2_clockmod_table[i].frequency) + cpufreq_for_each_valid_entry(pos, loongson2_clockmod_table) + if (rate_khz == pos->frequency) break; - } - if (rate != loongson2_clockmod_table[i].frequency) + if (rate_khz != pos->frequency) return -ENOTSUPP; clk->rate = rate; regval = LOONGSON_CHIPCFG0; - regval = (regval & ~0x7) | - (loongson2_clockmod_table[i].driver_data - 1); + regval = (regval & ~0x7) | (pos->driver_data - 1); LOONGSON_CHIPCFG0 = regval; return ret; diff --git a/arch/mips/loongson1/Kconfig b/arch/mips/loongson1/Kconfig index fbf75f635798cd..e23c25d0996318 100644 --- a/arch/mips/loongson1/Kconfig +++ b/arch/mips/loongson1/Kconfig @@ -14,6 +14,7 @@ config LOONGSON1_LS1B select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_HIGHMEM + select SYS_SUPPORTS_MIPS16 select SYS_HAS_EARLY_PRINTK select COMMON_CLK diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index 121a848a35945d..e068c5e8a3f2f6 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -2,10 +2,14 @@ # Makefile for the Linux/MIPS kernel FPU emulation. # -obj-y := cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \ - ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \ - dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \ - dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \ - sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \ - sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \ - dp_sqrt.o sp_sqrt.o kernel_linkage.o dsemul.o +obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o dp_div.o dp_mul.o \ + dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o dp_tint.o \ + dp_fint.o dp_tlong.o dp_flong.o sp_div.o sp_mul.o sp_sub.o \ + sp_add.o sp_fdp.o sp_cmp.o sp_simple.o sp_tint.o sp_fint.o \ + sp_tlong.o sp_flong.o dsemul.o + +obj-$(CONFIG_SYS_SUPPORTS_MICROMIPS) += me-micromips.o + +lib-y += ieee754d.o dp_sqrt.o sp_sqrt.o + +obj-$(CONFIG_DEBUG_FS) += me-debugfs.o diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 7b3c9acae68951..4d784dc393cf26 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1,5 +1,5 @@ /* - * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator + * cp1emu.c: a MIPS coprocessor 1 (FPU) instruction emulator * * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. @@ -18,61 +18,46 @@ * * 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. + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * A complete emulator for MIPS coprocessor 1 instructions. This is * required for #float(switch) or #float(trap), where it catches all * COP1 instructions via the "CoProcessor Unusable" exception. * * More surprisingly it is also required for #float(ieee), to help out - * the hardware fpu at the boundaries of the IEEE-754 representation + * the hardware FPU at the boundaries of the IEEE-754 representation * (denormalised values, infinities, underflow, etc). It is made * quite nasty because emulation of some non-COP1 instructions is * required, e.g. in branch delay slots. * - * Note if you know that you won't have an fpu, then you'll get much + * Note if you know that you won't have an FPU, then you'll get much * better performance by compiling with -msoft-float! */ #include -#include #include +#include +#include #include +#include #include -#include -#include #include #include -#include +#include + +#include #include #include -#include -#include #include "ieee754.h" -/* Strap kernel emulator for full MIPS IV emulation */ - -#ifdef __mips -#undef __mips -#endif -#define __mips 4 - /* Function which emulates a floating point instruction. */ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, mips_instruction); -#if __mips >= 4 && __mips != 32 static int fpux_emu(struct pt_regs *, struct mips_fpu_struct *, mips_instruction, void *__user *); -#endif - -/* Further private data for which no space exists in mips_fpu_struct */ - -#ifdef CONFIG_DEBUG_FS -DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); -#endif /* Control registers */ @@ -82,27 +67,6 @@ DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); /* Determine rounding mode from the RM bits of the FCSR */ #define modeindex(v) ((v) & FPU_CSR_RM) -/* microMIPS bitfields */ -#define MM_POOL32A_MINOR_MASK 0x3f -#define MM_POOL32A_MINOR_SHIFT 0x6 -#define MM_MIPS32_COND_FC 0x30 - -/* Convert Mips rounding mode (0..3) to IEEE library modes. */ -static const unsigned char ieee_rm[4] = { - [FPU_CSR_RN] = IEEE754_RN, - [FPU_CSR_RZ] = IEEE754_RZ, - [FPU_CSR_RU] = IEEE754_RU, - [FPU_CSR_RD] = IEEE754_RD, -}; -/* Convert IEEE library modes to Mips rounding mode (0..3). */ -static const unsigned char mips_rm[4] = { - [IEEE754_RN] = FPU_CSR_RN, - [IEEE754_RZ] = FPU_CSR_RZ, - [IEEE754_RD] = FPU_CSR_RD, - [IEEE754_RU] = FPU_CSR_RU, -}; - -#if __mips >= 4 /* convert condition code register number to csr bit */ static const unsigned int fpucondbit[8] = { FPU_CSR_COND0, @@ -114,550 +78,6 @@ static const unsigned int fpucondbit[8] = { FPU_CSR_COND6, FPU_CSR_COND7 }; -#endif - -/* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */ -static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7}; - -/* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */ -static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0}; -static const int sdps_format[] = {16, 17, 22, 0, 0, 0, 0, 0}; -static const int dwl_format[] = {17, 20, 21, 0, 0, 0, 0, 0}; -static const int swl_format[] = {16, 20, 21, 0, 0, 0, 0, 0}; - -/* - * This functions translates a 32-bit microMIPS instruction - * into a 32-bit MIPS32 instruction. Returns 0 on success - * and SIGILL otherwise. - */ -static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr) -{ - union mips_instruction insn = *insn_ptr; - union mips_instruction mips32_insn = insn; - int func, fmt, op; - - switch (insn.mm_i_format.opcode) { - case mm_ldc132_op: - mips32_insn.mm_i_format.opcode = ldc1_op; - mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; - mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; - break; - case mm_lwc132_op: - mips32_insn.mm_i_format.opcode = lwc1_op; - mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; - mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; - break; - case mm_sdc132_op: - mips32_insn.mm_i_format.opcode = sdc1_op; - mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; - mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; - break; - case mm_swc132_op: - mips32_insn.mm_i_format.opcode = swc1_op; - mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; - mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; - break; - case mm_pool32i_op: - /* NOTE: offset is << by 1 if in microMIPS mode. */ - if ((insn.mm_i_format.rt == mm_bc1f_op) || - (insn.mm_i_format.rt == mm_bc1t_op)) { - mips32_insn.fb_format.opcode = cop1_op; - mips32_insn.fb_format.bc = bc_op; - mips32_insn.fb_format.flag = - (insn.mm_i_format.rt == mm_bc1t_op) ? 1 : 0; - } else - return SIGILL; - break; - case mm_pool32f_op: - switch (insn.mm_fp0_format.func) { - case mm_32f_01_op: - case mm_32f_11_op: - case mm_32f_02_op: - case mm_32f_12_op: - case mm_32f_41_op: - case mm_32f_51_op: - case mm_32f_42_op: - case mm_32f_52_op: - op = insn.mm_fp0_format.func; - if (op == mm_32f_01_op) - func = madd_s_op; - else if (op == mm_32f_11_op) - func = madd_d_op; - else if (op == mm_32f_02_op) - func = nmadd_s_op; - else if (op == mm_32f_12_op) - func = nmadd_d_op; - else if (op == mm_32f_41_op) - func = msub_s_op; - else if (op == mm_32f_51_op) - func = msub_d_op; - else if (op == mm_32f_42_op) - func = nmsub_s_op; - else - func = nmsub_d_op; - mips32_insn.fp6_format.opcode = cop1x_op; - mips32_insn.fp6_format.fr = insn.mm_fp6_format.fr; - mips32_insn.fp6_format.ft = insn.mm_fp6_format.ft; - mips32_insn.fp6_format.fs = insn.mm_fp6_format.fs; - mips32_insn.fp6_format.fd = insn.mm_fp6_format.fd; - mips32_insn.fp6_format.func = func; - break; - case mm_32f_10_op: - func = -1; /* Invalid */ - op = insn.mm_fp5_format.op & 0x7; - if (op == mm_ldxc1_op) - func = ldxc1_op; - else if (op == mm_sdxc1_op) - func = sdxc1_op; - else if (op == mm_lwxc1_op) - func = lwxc1_op; - else if (op == mm_swxc1_op) - func = swxc1_op; - - if (func != -1) { - mips32_insn.r_format.opcode = cop1x_op; - mips32_insn.r_format.rs = - insn.mm_fp5_format.base; - mips32_insn.r_format.rt = - insn.mm_fp5_format.index; - mips32_insn.r_format.rd = 0; - mips32_insn.r_format.re = insn.mm_fp5_format.fd; - mips32_insn.r_format.func = func; - } else - return SIGILL; - break; - case mm_32f_40_op: - op = -1; /* Invalid */ - if (insn.mm_fp2_format.op == mm_fmovt_op) - op = 1; - else if (insn.mm_fp2_format.op == mm_fmovf_op) - op = 0; - if (op != -1) { - mips32_insn.fp0_format.opcode = cop1_op; - mips32_insn.fp0_format.fmt = - sdps_format[insn.mm_fp2_format.fmt]; - mips32_insn.fp0_format.ft = - (insn.mm_fp2_format.cc<<2) + op; - mips32_insn.fp0_format.fs = - insn.mm_fp2_format.fs; - mips32_insn.fp0_format.fd = - insn.mm_fp2_format.fd; - mips32_insn.fp0_format.func = fmovc_op; - } else - return SIGILL; - break; - case mm_32f_60_op: - func = -1; /* Invalid */ - if (insn.mm_fp0_format.op == mm_fadd_op) - func = fadd_op; - else if (insn.mm_fp0_format.op == mm_fsub_op) - func = fsub_op; - else if (insn.mm_fp0_format.op == mm_fmul_op) - func = fmul_op; - else if (insn.mm_fp0_format.op == mm_fdiv_op) - func = fdiv_op; - if (func != -1) { - mips32_insn.fp0_format.opcode = cop1_op; - mips32_insn.fp0_format.fmt = - sdps_format[insn.mm_fp0_format.fmt]; - mips32_insn.fp0_format.ft = - insn.mm_fp0_format.ft; - mips32_insn.fp0_format.fs = - insn.mm_fp0_format.fs; - mips32_insn.fp0_format.fd = - insn.mm_fp0_format.fd; - mips32_insn.fp0_format.func = func; - } else - return SIGILL; - break; - case mm_32f_70_op: - func = -1; /* Invalid */ - if (insn.mm_fp0_format.op == mm_fmovn_op) - func = fmovn_op; - else if (insn.mm_fp0_format.op == mm_fmovz_op) - func = fmovz_op; - if (func != -1) { - mips32_insn.fp0_format.opcode = cop1_op; - mips32_insn.fp0_format.fmt = - sdps_format[insn.mm_fp0_format.fmt]; - mips32_insn.fp0_format.ft = - insn.mm_fp0_format.ft; - mips32_insn.fp0_format.fs = - insn.mm_fp0_format.fs; - mips32_insn.fp0_format.fd = - insn.mm_fp0_format.fd; - mips32_insn.fp0_format.func = func; - } else - return SIGILL; - break; - case mm_32f_73_op: /* POOL32FXF */ - switch (insn.mm_fp1_format.op) { - case mm_movf0_op: - case mm_movf1_op: - case mm_movt0_op: - case mm_movt1_op: - if ((insn.mm_fp1_format.op & 0x7f) == - mm_movf0_op) - op = 0; - else - op = 1; - mips32_insn.r_format.opcode = spec_op; - mips32_insn.r_format.rs = insn.mm_fp4_format.fs; - mips32_insn.r_format.rt = - (insn.mm_fp4_format.cc << 2) + op; - mips32_insn.r_format.rd = insn.mm_fp4_format.rt; - mips32_insn.r_format.re = 0; - mips32_insn.r_format.func = movc_op; - break; - case mm_fcvtd0_op: - case mm_fcvtd1_op: - case mm_fcvts0_op: - case mm_fcvts1_op: - if ((insn.mm_fp1_format.op & 0x7f) == - mm_fcvtd0_op) { - func = fcvtd_op; - fmt = swl_format[insn.mm_fp3_format.fmt]; - } else { - func = fcvts_op; - fmt = dwl_format[insn.mm_fp3_format.fmt]; - } - mips32_insn.fp0_format.opcode = cop1_op; - mips32_insn.fp0_format.fmt = fmt; - mips32_insn.fp0_format.ft = 0; - mips32_insn.fp0_format.fs = - insn.mm_fp3_format.fs; - mips32_insn.fp0_format.fd = - insn.mm_fp3_format.rt; - mips32_insn.fp0_format.func = func; - break; - case mm_fmov0_op: - case mm_fmov1_op: - case mm_fabs0_op: - case mm_fabs1_op: - case mm_fneg0_op: - case mm_fneg1_op: - if ((insn.mm_fp1_format.op & 0x7f) == - mm_fmov0_op) - func = fmov_op; - else if ((insn.mm_fp1_format.op & 0x7f) == - mm_fabs0_op) - func = fabs_op; - else - func = fneg_op; - mips32_insn.fp0_format.opcode = cop1_op; - mips32_insn.fp0_format.fmt = - sdps_format[insn.mm_fp3_format.fmt]; - mips32_insn.fp0_format.ft = 0; - mips32_insn.fp0_format.fs = - insn.mm_fp3_format.fs; - mips32_insn.fp0_format.fd = - insn.mm_fp3_format.rt; - mips32_insn.fp0_format.func = func; - break; - case mm_ffloorl_op: - case mm_ffloorw_op: - case mm_fceill_op: - case mm_fceilw_op: - case mm_ftruncl_op: - case mm_ftruncw_op: - case mm_froundl_op: - case mm_froundw_op: - case mm_fcvtl_op: - case mm_fcvtw_op: - if (insn.mm_fp1_format.op == mm_ffloorl_op) - func = ffloorl_op; - else if (insn.mm_fp1_format.op == mm_ffloorw_op) - func = ffloor_op; - else if (insn.mm_fp1_format.op == mm_fceill_op) - func = fceill_op; - else if (insn.mm_fp1_format.op == mm_fceilw_op) - func = fceil_op; - else if (insn.mm_fp1_format.op == mm_ftruncl_op) - func = ftruncl_op; - else if (insn.mm_fp1_format.op == mm_ftruncw_op) - func = ftrunc_op; - else if (insn.mm_fp1_format.op == mm_froundl_op) - func = froundl_op; - else if (insn.mm_fp1_format.op == mm_froundw_op) - func = fround_op; - else if (insn.mm_fp1_format.op == mm_fcvtl_op) - func = fcvtl_op; - else - func = fcvtw_op; - mips32_insn.fp0_format.opcode = cop1_op; - mips32_insn.fp0_format.fmt = - sd_format[insn.mm_fp1_format.fmt]; - mips32_insn.fp0_format.ft = 0; - mips32_insn.fp0_format.fs = - insn.mm_fp1_format.fs; - mips32_insn.fp0_format.fd = - insn.mm_fp1_format.rt; - mips32_insn.fp0_format.func = func; - break; - case mm_frsqrt_op: - case mm_fsqrt_op: - case mm_frecip_op: - if (insn.mm_fp1_format.op == mm_frsqrt_op) - func = frsqrt_op; - else if (insn.mm_fp1_format.op == mm_fsqrt_op) - func = fsqrt_op; - else - func = frecip_op; - mips32_insn.fp0_format.opcode = cop1_op; - mips32_insn.fp0_format.fmt = - sdps_format[insn.mm_fp1_format.fmt]; - mips32_insn.fp0_format.ft = 0; - mips32_insn.fp0_format.fs = - insn.mm_fp1_format.fs; - mips32_insn.fp0_format.fd = - insn.mm_fp1_format.rt; - mips32_insn.fp0_format.func = func; - break; - case mm_mfc1_op: - case mm_mtc1_op: - case mm_cfc1_op: - case mm_ctc1_op: - case mm_mfhc1_op: - case mm_mthc1_op: - if (insn.mm_fp1_format.op == mm_mfc1_op) - op = mfc_op; - else if (insn.mm_fp1_format.op == mm_mtc1_op) - op = mtc_op; - else if (insn.mm_fp1_format.op == mm_cfc1_op) - op = cfc_op; - else if (insn.mm_fp1_format.op == mm_ctc1_op) - op = ctc_op; - else if (insn.mm_fp1_format.op == mm_mfhc1_op) - op = mfhc_op; - else - op = mthc_op; - mips32_insn.fp1_format.opcode = cop1_op; - mips32_insn.fp1_format.op = op; - mips32_insn.fp1_format.rt = - insn.mm_fp1_format.rt; - mips32_insn.fp1_format.fs = - insn.mm_fp1_format.fs; - mips32_insn.fp1_format.fd = 0; - mips32_insn.fp1_format.func = 0; - break; - default: - return SIGILL; - } - break; - case mm_32f_74_op: /* c.cond.fmt */ - mips32_insn.fp0_format.opcode = cop1_op; - mips32_insn.fp0_format.fmt = - sdps_format[insn.mm_fp4_format.fmt]; - mips32_insn.fp0_format.ft = insn.mm_fp4_format.rt; - mips32_insn.fp0_format.fs = insn.mm_fp4_format.fs; - mips32_insn.fp0_format.fd = insn.mm_fp4_format.cc << 2; - mips32_insn.fp0_format.func = - insn.mm_fp4_format.cond | MM_MIPS32_COND_FC; - break; - default: - return SIGILL; - } - break; - default: - return SIGILL; - } - - *insn_ptr = mips32_insn; - return 0; -} - -int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, - unsigned long *contpc) -{ - union mips_instruction insn = (union mips_instruction)dec_insn.insn; - int bc_false = 0; - unsigned int fcr31; - unsigned int bit; - - if (!cpu_has_mmips) - return 0; - - switch (insn.mm_i_format.opcode) { - case mm_pool32a_op: - if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) == - mm_pool32axf_op) { - switch (insn.mm_i_format.simmediate >> - MM_POOL32A_MINOR_SHIFT) { - case mm_jalr_op: - case mm_jalrhb_op: - case mm_jalrs_op: - case mm_jalrshb_op: - if (insn.mm_i_format.rt != 0) /* Not mm_jr */ - regs->regs[insn.mm_i_format.rt] = - regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; - *contpc = regs->regs[insn.mm_i_format.rs]; - return 1; - } - } - break; - case mm_pool32i_op: - switch (insn.mm_i_format.rt) { - case mm_bltzals_op: - case mm_bltzal_op: - regs->regs[31] = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; - /* Fall through */ - case mm_bltz_op: - if ((long)regs->regs[insn.mm_i_format.rs] < 0) - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - (insn.mm_i_format.simmediate << 1); - else - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; - return 1; - case mm_bgezals_op: - case mm_bgezal_op: - regs->regs[31] = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; - /* Fall through */ - case mm_bgez_op: - if ((long)regs->regs[insn.mm_i_format.rs] >= 0) - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - (insn.mm_i_format.simmediate << 1); - else - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; - return 1; - case mm_blez_op: - if ((long)regs->regs[insn.mm_i_format.rs] <= 0) - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - (insn.mm_i_format.simmediate << 1); - else - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; - return 1; - case mm_bgtz_op: - if ((long)regs->regs[insn.mm_i_format.rs] <= 0) - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - (insn.mm_i_format.simmediate << 1); - else - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; - return 1; - case mm_bc2f_op: - case mm_bc1f_op: - bc_false = 1; - /* Fall through */ - case mm_bc2t_op: - case mm_bc1t_op: - preempt_disable(); - if (is_fpu_owner()) - asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); - else - fcr31 = current->thread.fpu.fcr31; - preempt_enable(); - - if (bc_false) - fcr31 = ~fcr31; - - bit = (insn.mm_i_format.rs >> 2); - bit += (bit != 0); - bit += 23; - if (fcr31 & (1 << bit)) - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - (insn.mm_i_format.simmediate << 1); - else - *contpc = regs->cp0_epc + - dec_insn.pc_inc + dec_insn.next_pc_inc; - return 1; - } - break; - case mm_pool16c_op: - switch (insn.mm_i_format.rt) { - case mm_jalr16_op: - case mm_jalrs16_op: - regs->regs[31] = regs->cp0_epc + - dec_insn.pc_inc + dec_insn.next_pc_inc; - /* Fall through */ - case mm_jr16_op: - *contpc = regs->regs[insn.mm_i_format.rs]; - return 1; - } - break; - case mm_beqz16_op: - if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0) - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - (insn.mm_b1_format.simmediate << 1); - else - *contpc = regs->cp0_epc + - dec_insn.pc_inc + dec_insn.next_pc_inc; - return 1; - case mm_bnez16_op: - if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0) - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - (insn.mm_b1_format.simmediate << 1); - else - *contpc = regs->cp0_epc + - dec_insn.pc_inc + dec_insn.next_pc_inc; - return 1; - case mm_b16_op: - *contpc = regs->cp0_epc + dec_insn.pc_inc + - (insn.mm_b0_format.simmediate << 1); - return 1; - case mm_beq32_op: - if (regs->regs[insn.mm_i_format.rs] == - regs->regs[insn.mm_i_format.rt]) - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - (insn.mm_i_format.simmediate << 1); - else - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; - return 1; - case mm_bne32_op: - if (regs->regs[insn.mm_i_format.rs] != - regs->regs[insn.mm_i_format.rt]) - *contpc = regs->cp0_epc + - dec_insn.pc_inc + - (insn.mm_i_format.simmediate << 1); - else - *contpc = regs->cp0_epc + - dec_insn.pc_inc + dec_insn.next_pc_inc; - return 1; - case mm_jalx32_op: - regs->regs[31] = regs->cp0_epc + - dec_insn.pc_inc + dec_insn.next_pc_inc; - *contpc = regs->cp0_epc + dec_insn.pc_inc; - *contpc >>= 28; - *contpc <<= 28; - *contpc |= (insn.j_format.target << 2); - return 1; - case mm_jals32_op: - case mm_jal32_op: - regs->regs[31] = regs->cp0_epc + - dec_insn.pc_inc + dec_insn.next_pc_inc; - /* Fall through */ - case mm_j32_op: - *contpc = regs->cp0_epc + dec_insn.pc_inc; - *contpc >>= 27; - *contpc <<= 27; - *contpc |= (insn.j_format.target << 1); - set_isa16_mode(*contpc); - return 1; - } - return 0; -} /* * Redundant with logic already in kernel/branch.c, @@ -665,10 +85,10 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, * a single subroutine should be used across both * modules. */ -static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, - unsigned long *contpc) +static int isBranchInstr(struct pt_regs *regs, + const struct mm_decoded_insn * const dec_insn, unsigned long *contpc) { - union mips_instruction insn = (union mips_instruction)dec_insn.insn; + union mips_instruction insn = (union mips_instruction)dec_insn->insn; unsigned int fcr31; unsigned int bit = 0; @@ -677,8 +97,8 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, switch (insn.r_format.func) { case jalr_op: regs->regs[insn.r_format.rd] = - regs->cp0_epc + dec_insn.pc_inc + - dec_insn.next_pc_inc; + regs->cp0_epc + dec_insn->pc_inc + + dec_insn->next_pc_inc; /* Fall through */ case jr_op: *contpc = regs->regs[insn.r_format.rs]; @@ -690,36 +110,36 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, case bltzal_op: case bltzall_op: regs->regs[31] = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; + dec_insn->pc_inc + + dec_insn->next_pc_inc; /* Fall through */ case bltz_op: case bltzl_op: if ((long)regs->regs[insn.i_format.rs] < 0) *contpc = regs->cp0_epc + - dec_insn.pc_inc + + dec_insn->pc_inc + (insn.i_format.simmediate << 2); else *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; + dec_insn->pc_inc + + dec_insn->next_pc_inc; return 1; case bgezal_op: case bgezall_op: regs->regs[31] = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; + dec_insn->pc_inc + + dec_insn->next_pc_inc; /* Fall through */ case bgez_op: case bgezl_op: if ((long)regs->regs[insn.i_format.rs] >= 0) *contpc = regs->cp0_epc + - dec_insn.pc_inc + + dec_insn->pc_inc + (insn.i_format.simmediate << 2); else *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; + dec_insn->pc_inc + + dec_insn->next_pc_inc; return 1; } break; @@ -727,11 +147,11 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, set_isa16_mode(bit); case jal_op: regs->regs[31] = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; + dec_insn->pc_inc + + dec_insn->next_pc_inc; /* Fall through */ case j_op: - *contpc = regs->cp0_epc + dec_insn.pc_inc; + *contpc = regs->cp0_epc + dec_insn->pc_inc; *contpc >>= 28; *contpc <<= 28; *contpc |= (insn.j_format.target << 2); @@ -743,46 +163,46 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, if (regs->regs[insn.i_format.rs] == regs->regs[insn.i_format.rt]) *contpc = regs->cp0_epc + - dec_insn.pc_inc + + dec_insn->pc_inc + (insn.i_format.simmediate << 2); else *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; + dec_insn->pc_inc + + dec_insn->next_pc_inc; return 1; case bne_op: case bnel_op: if (regs->regs[insn.i_format.rs] != regs->regs[insn.i_format.rt]) *contpc = regs->cp0_epc + - dec_insn.pc_inc + + dec_insn->pc_inc + (insn.i_format.simmediate << 2); else *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; + dec_insn->pc_inc + + dec_insn->next_pc_inc; return 1; case blez_op: case blezl_op: if ((long)regs->regs[insn.i_format.rs] <= 0) *contpc = regs->cp0_epc + - dec_insn.pc_inc + + dec_insn->pc_inc + (insn.i_format.simmediate << 2); else *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; + dec_insn->pc_inc + + dec_insn->next_pc_inc; return 1; case bgtz_op: case bgtzl_op: if ((long)regs->regs[insn.i_format.rs] > 0) *contpc = regs->cp0_epc + - dec_insn.pc_inc + + dec_insn->pc_inc + (insn.i_format.simmediate << 2); else *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; + dec_insn->pc_inc + + dec_insn->next_pc_inc; return 1; #ifdef CONFIG_CPU_CAVIUM_OCTEON case lwc2_op: /* This is bbit0 on Octeon */ @@ -830,23 +250,23 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, case 2: /* bc1fl */ if (~fcr31 & (1 << bit)) *contpc = regs->cp0_epc + - dec_insn.pc_inc + + dec_insn->pc_inc + (insn.i_format.simmediate << 2); else *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; + dec_insn->pc_inc + + dec_insn->next_pc_inc; return 1; case 1: /* bc1t */ case 3: /* bc1tl */ if (fcr31 & (1 << bit)) *contpc = regs->cp0_epc + - dec_insn.pc_inc + + dec_insn->pc_inc + (insn.i_format.simmediate << 2); else *contpc = regs->cp0_epc + - dec_insn.pc_inc + - dec_insn.next_pc_inc; + dec_insn->pc_inc + + dec_insn->next_pc_inc; return 1; } } @@ -867,23 +287,25 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, */ static inline int cop1_64bit(struct pt_regs *xcp) { -#if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32) - return 1; -#elif defined(CONFIG_32BIT) && !defined(CONFIG_MIPS_O32_FP64_SUPPORT) - return 0; -#else + if (config_enabled(CONFIG_64BIT) && !config_enabled(CONFIG_MIPS32_O32)) + return 1; + else if (config_enabled(CONFIG_32BIT) && + !config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) + return 0; + return !test_thread_flag(TIF_32BIT_FPREGS); -#endif } -#define SIFROMREG(si, x) do { \ +#define SIFROMREG(si, x) \ +do { \ if (cop1_64bit(xcp)) \ (si) = get_fpr32(&ctx->fpr[x], 0); \ else \ (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ } while (0) -#define SITOREG(si, x) do { \ +#define SITOREG(si, x) \ +do { \ if (cop1_64bit(xcp)) { \ unsigned i; \ set_fpr32(&ctx->fpr[x], 0, si); \ @@ -896,17 +318,19 @@ static inline int cop1_64bit(struct pt_regs *xcp) #define SIFROMHREG(si, x) ((si) = get_fpr32(&ctx->fpr[x], 1)) -#define SITOHREG(si, x) do { \ +#define SITOHREG(si, x) \ +do { \ unsigned i; \ set_fpr32(&ctx->fpr[x], 1, si); \ for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ set_fpr32(&ctx->fpr[x], i, 0); \ } while (0) -#define DIFROMREG(di, x) \ +#define DIFROMREG(di, x) \ ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0)) -#define DITOREG(di, x) do { \ +#define DITOREG(di, x) \ +do { \ unsigned fpr, i; \ fpr = (x) & ~(cop1_64bit(xcp) == 0); \ set_fpr64(&ctx->fpr[fpr], 0, di); \ @@ -927,23 +351,29 @@ static inline int cop1_64bit(struct pt_regs *xcp) static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, struct mm_decoded_insn dec_insn, void *__user *fault_addr) { - mips_instruction ir; unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc; - unsigned int cond; - int pc_inc; + unsigned int cond, cbit; + mips_instruction ir; + int likely, pc_inc; + u32 __user *wva; + u64 __user *dva; + u32 value; + u32 wval; + u64 dval; + int sig; /* XXX NEC Vr54xx bug workaround */ - if (xcp->cp0_cause & CAUSEF_BD) { + if (delay_slot(xcp)) { if (dec_insn.micro_mips_mode) { - if (!mm_isBranchInstr(xcp, dec_insn, &contpc)) - xcp->cp0_cause &= ~CAUSEF_BD; + if (!mm_isBranchInstr(xcp, &dec_insn, &contpc)) + clear_delay_slot(xcp); } else { - if (!isBranchInstr(xcp, dec_insn, &contpc)) - xcp->cp0_cause &= ~CAUSEF_BD; + if (!isBranchInstr(xcp, &dec_insn, &contpc)) + clear_delay_slot(xcp); } } - if (xcp->cp0_cause & CAUSEF_BD) { + if (delay_slot(xcp)) { /* * The instruction to be emulated is in a branch delay slot * which means that we have to emulate the branch instruction @@ -985,96 +415,85 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, return SIGILL; } - emul: +emul: perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, xcp, 0); MIPS_FPU_EMU_INC_STATS(emulated); switch (MIPSInst_OPCODE(ir)) { - case ldc1_op:{ - u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + - MIPSInst_SIMM(ir)); - u64 val; - + case ldc1_op: + dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + + MIPSInst_SIMM(ir)); MIPS_FPU_EMU_INC_STATS(loads); - if (!access_ok(VERIFY_READ, va, sizeof(u64))) { + if (!access_ok(VERIFY_READ, dva, sizeof(u64))) { MIPS_FPU_EMU_INC_STATS(errors); - *fault_addr = va; + *fault_addr = dva; return SIGBUS; } - if (__get_user(val, va)) { + if (__get_user(dval, dva)) { MIPS_FPU_EMU_INC_STATS(errors); - *fault_addr = va; + *fault_addr = dva; return SIGSEGV; } - DITOREG(val, MIPSInst_RT(ir)); + DITOREG(dval, MIPSInst_RT(ir)); break; - } - - case sdc1_op:{ - u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + - MIPSInst_SIMM(ir)); - u64 val; + case sdc1_op: + dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + + MIPSInst_SIMM(ir)); MIPS_FPU_EMU_INC_STATS(stores); - DIFROMREG(val, MIPSInst_RT(ir)); - if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) { + DIFROMREG(dval, MIPSInst_RT(ir)); + if (!access_ok(VERIFY_WRITE, dva, sizeof(u64))) { MIPS_FPU_EMU_INC_STATS(errors); - *fault_addr = va; + *fault_addr = dva; return SIGBUS; } - if (__put_user(val, va)) { + if (__put_user(dval, dva)) { MIPS_FPU_EMU_INC_STATS(errors); - *fault_addr = va; + *fault_addr = dva; return SIGSEGV; } break; - } - - case lwc1_op:{ - u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + - MIPSInst_SIMM(ir)); - u32 val; + case lwc1_op: + wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + + MIPSInst_SIMM(ir)); MIPS_FPU_EMU_INC_STATS(loads); - if (!access_ok(VERIFY_READ, va, sizeof(u32))) { + if (!access_ok(VERIFY_READ, wva, sizeof(u32))) { MIPS_FPU_EMU_INC_STATS(errors); - *fault_addr = va; + *fault_addr = wva; return SIGBUS; } - if (__get_user(val, va)) { + if (__get_user(wval, wva)) { MIPS_FPU_EMU_INC_STATS(errors); - *fault_addr = va; + *fault_addr = wva; return SIGSEGV; } - SITOREG(val, MIPSInst_RT(ir)); + SITOREG(wval, MIPSInst_RT(ir)); break; - } - - case swc1_op:{ - u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + - MIPSInst_SIMM(ir)); - u32 val; + case swc1_op: + wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + + MIPSInst_SIMM(ir)); MIPS_FPU_EMU_INC_STATS(stores); - SIFROMREG(val, MIPSInst_RT(ir)); - if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) { + SIFROMREG(wval, MIPSInst_RT(ir)); + if (!access_ok(VERIFY_WRITE, wva, sizeof(u32))) { MIPS_FPU_EMU_INC_STATS(errors); - *fault_addr = va; + *fault_addr = wva; return SIGBUS; } - if (__put_user(val, va)) { + if (__put_user(wval, wva)) { MIPS_FPU_EMU_INC_STATS(errors); - *fault_addr = va; + *fault_addr = wva; return SIGSEGV; } break; - } case cop1_op: switch (MIPSInst_RS(ir)) { - -#if defined(__mips64) case dmfc_op: + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + /* copregister fs -> gpr[rt] */ if (MIPSInst_RT(ir) != 0) { DIFROMREG(xcp->regs[MIPSInst_RT(ir)], @@ -1083,10 +502,12 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; case dmtc_op: + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + /* copregister fs <- rt */ DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); break; -#endif case mfhc_op: if (!cpu_has_mips_r2) @@ -1120,19 +541,14 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); break; - case cfc_op:{ + case cfc_op: /* cop control register rd -> gpr[rt] */ - u32 value; - if (MIPSInst_RD(ir) == FPCREG_CSR) { value = ctx->fcr31; - value = (value & ~FPU_CSR_RM) | - mips_rm[modeindex(value)]; -#ifdef CSRTRACE - printk("%p gpr[%d]<-csr=%08x\n", - (void *) (xcp->cp0_epc), - MIPSInst_RT(ir), value); -#endif + value = (value & ~FPU_CSR_RM) | modeindex(value); + pr_debug("%p gpr[%d]<-csr=%08x\n", + (void *) (xcp->cp0_epc), + MIPSInst_RT(ir), value); } else if (MIPSInst_RD(ir) == FPCREG_RID) value = 0; @@ -1141,12 +557,9 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (MIPSInst_RT(ir)) xcp->regs[MIPSInst_RT(ir)] = value; break; - } - case ctc_op:{ + case ctc_op: /* copregister rd <- rt */ - u32 value; - if (MIPSInst_RT(ir) == 0) value = 0; else @@ -1155,37 +568,33 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, /* we only have one writable control reg */ if (MIPSInst_RD(ir) == FPCREG_CSR) { -#ifdef CSRTRACE - printk("%p gpr[%d]->csr=%08x\n", - (void *) (xcp->cp0_epc), - MIPSInst_RT(ir), value); -#endif + pr_debug("%p gpr[%d]->csr=%08x\n", + (void *) (xcp->cp0_epc), + MIPSInst_RT(ir), value); /* * Don't write reserved bits, * and convert to ieee library modes */ - ctx->fcr31 = (value & - ~(FPU_CSR_RSVD | FPU_CSR_RM)) | - ieee_rm[modeindex(value)]; + ctx->fcr31 = (value & ~(FPU_CSR_RSVD | FPU_CSR_RM)) | + modeindex(value); } if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { return SIGFPE; } break; - } - - case bc_op:{ - int likely = 0; - if (xcp->cp0_cause & CAUSEF_BD) + case bc_op: + if (delay_slot(xcp)) return SIGILL; -#if __mips >= 4 - cond = ctx->fcr31 & fpucondbit[MIPSInst_RT(ir) >> 2]; -#else - cond = ctx->fcr31 & FPU_CSR_COND; -#endif + if (cpu_has_mips_4_5_r) + cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; + else + cbit = FPU_CSR_COND; + cond = ctx->fcr31 & cbit; + + likely = 0; switch (MIPSInst_RT(ir) & 3) { case bcfl_op: likely = 1; @@ -1201,10 +610,10 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, return SIGILL; } - xcp->cp0_cause |= CAUSEF_BD; + set_delay_slot(xcp); if (cond) { - /* branch taken: emulate dslot - * instruction + /* + * Branch taken: emulate dslot instruction */ xcp->cp0_epc += dec_insn.pc_inc; @@ -1238,23 +647,37 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, switch (MIPSInst_OPCODE(ir)) { case lwc1_op: + goto emul; + case swc1_op: -#if (__mips >= 2 || defined(__mips64)) + goto emul; + case ldc1_op: case sdc1_op: -#endif + if (cpu_has_mips_2_3_4_5 || + cpu_has_mips64) + goto emul; + + return SIGILL; + goto emul; + case cop1_op: -#if __mips >= 4 && __mips != 32 - case cop1x_op: -#endif - /* its one of ours */ goto emul; -#if __mips >= 4 + + case cop1x_op: + if (cpu_has_mips_4_5 || cpu_has_mips64) + /* its one of ours */ + goto emul; + + return SIGILL; + case spec_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + if (MIPSInst_FUNC(ir) == movc_op) goto emul; break; -#endif } /* @@ -1262,10 +685,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, * instruction in the dslot */ return mips_dsemul(xcp, ir, contpc); - } - else { - /* branch not taken */ - if (likely) { + } else if (likely) { /* branch not taken */ /* * branch likely nullifies * dslot if not taken @@ -1277,34 +697,31 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, * dslot as normal insn */ } - } break; - } default: if (!(MIPSInst_RS(ir) & 0x10)) return SIGILL; - { - int sig; - /* a real fpu computation instruction */ - if ((sig = fpu_emu(xcp, ctx, ir))) - return sig; - } + /* a real fpu computation instruction */ + if ((sig = fpu_emu(xcp, ctx, ir))) + return sig; } break; -#if __mips >= 4 && __mips != 32 - case cop1x_op:{ - int sig = fpux_emu(xcp, ctx, ir, fault_addr); + case cop1x_op: + if (!cpu_has_mips_4_5 && !cpu_has_mips64) + return SIGILL; + + sig = fpux_emu(xcp, ctx, ir, fault_addr); if (sig) return sig; break; - } -#endif -#if __mips >= 4 case spec_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + if (MIPSInst_FUNC(ir) != movc_op) return SIGILL; cond = fpucondbit[MIPSInst_RT(ir) >> 2]; @@ -1312,8 +729,6 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)]; break; -#endif - default: sigill: return SIGILL; @@ -1321,7 +736,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, /* we did it !! */ xcp->cp0_epc = contpc; - xcp->cp0_cause &= ~CAUSEF_BD; + clear_delay_slot(xcp); return 0; } @@ -1342,44 +757,42 @@ static const unsigned char cmptab[8] = { }; -#if __mips >= 4 && __mips != 32 - /* * Additional MIPS4 instructions */ -#define DEF3OP(name, p, f1, f2, f3) \ -static ieee754##p fpemu_##p##_##name(ieee754##p r, ieee754##p s, \ - ieee754##p t) \ -{ \ - struct _ieee754_csr ieee754_csr_save; \ - s = f1(s, t); \ - ieee754_csr_save = ieee754_csr; \ - s = f2(s, r); \ - ieee754_csr_save.cx |= ieee754_csr.cx; \ - ieee754_csr_save.sx |= ieee754_csr.sx; \ - s = f3(s); \ - ieee754_csr.cx |= ieee754_csr_save.cx; \ - ieee754_csr.sx |= ieee754_csr_save.sx; \ - return s; \ +#define DEF3OP(name, p, f1, f2, f3) \ +static union ieee754##p fpemu_##p##_##name(union ieee754##p r, \ + union ieee754##p s, union ieee754##p t) \ +{ \ + struct _ieee754_csr ieee754_csr_save; \ + s = f1(s, t); \ + ieee754_csr_save = ieee754_csr; \ + s = f2(s, r); \ + ieee754_csr_save.cx |= ieee754_csr.cx; \ + ieee754_csr_save.sx |= ieee754_csr.sx; \ + s = f3(s); \ + ieee754_csr.cx |= ieee754_csr_save.cx; \ + ieee754_csr.sx |= ieee754_csr_save.sx; \ + return s; \ } -static ieee754dp fpemu_dp_recip(ieee754dp d) +static union ieee754dp fpemu_dp_recip(union ieee754dp d) { return ieee754dp_div(ieee754dp_one(0), d); } -static ieee754dp fpemu_dp_rsqrt(ieee754dp d) +static union ieee754dp fpemu_dp_rsqrt(union ieee754dp d) { return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d)); } -static ieee754sp fpemu_sp_recip(ieee754sp s) +static union ieee754sp fpemu_sp_recip(union ieee754sp s) { return ieee754sp_div(ieee754sp_one(0), s); } -static ieee754sp fpemu_sp_rsqrt(ieee754sp s) +static union ieee754sp fpemu_sp_rsqrt(union ieee754sp s) { return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); } @@ -1403,8 +816,8 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, switch (MIPSInst_FMA_FFMT(ir)) { case s_fmt:{ /* 0 */ - ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp); - ieee754sp fd, fr, fs, ft; + union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); + union ieee754sp fd, fr, fs, ft; u32 __user *va; u32 val; @@ -1478,7 +891,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { - /*printk ("SIGFPE: fpu csr = %08x\n", + /*printk ("SIGFPE: FPU csr = %08x\n", ctx->fcr31); */ return SIGFPE; } @@ -1492,8 +905,8 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, } case d_fmt:{ /* 1 */ - ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp); - ieee754dp fd, fr, fs, ft; + union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); + union ieee754dp fd, fr, fs, ft; u64 __user *va; u64 val; @@ -1574,7 +987,6 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, return 0; } -#endif @@ -1586,23 +998,25 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, { int rfmt; /* resulting format */ unsigned rcsr = 0; /* resulting csr */ + unsigned int oldrm; + unsigned int cbit; unsigned cond; union { - ieee754dp d; - ieee754sp s; + union ieee754dp d; + union ieee754sp s; int w; -#ifdef __mips64 s64 l; -#endif } rv; /* resulting value */ + u64 bits; MIPS_FPU_EMU_INC_STATS(cp1ops); switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { - case s_fmt:{ /* 0 */ + case s_fmt: { /* 0 */ union { - ieee754sp(*b) (ieee754sp, ieee754sp); - ieee754sp(*u) (ieee754sp); + union ieee754sp(*b) (union ieee754sp, union ieee754sp); + union ieee754sp(*u) (union ieee754sp); } handler; + union ieee754sp fs, ft; switch (MIPSInst_FUNC(ir)) { /* binary ops */ @@ -1620,69 +1034,86 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, goto scopbop; /* unary ops */ -#if __mips >= 2 || defined(__mips64) case fsqrt_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + handler.u = ieee754sp_sqrt; goto scopuop; -#endif -#if __mips >= 4 && __mips != 32 + + /* + * Note that on some MIPS IV implementations such as the + * R5000 and R8000 the FSQRT and FRECIP instructions do not + * achieve full IEEE-754 accuracy - however this emulator does. + */ case frsqrt_op: + if (!cpu_has_mips_4_5_r2) + return SIGILL; + handler.u = fpemu_sp_rsqrt; goto scopuop; + case frecip_op: + if (!cpu_has_mips_4_5_r2) + return SIGILL; + handler.u = fpemu_sp_recip; goto scopuop; -#endif -#if __mips >= 4 + case fmovc_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + cond = fpucondbit[MIPSInst_FT(ir) >> 2]; if (((ctx->fcr31 & cond) != 0) != ((MIPSInst_FT(ir) & 1) != 0)) return 0; SPFROMREG(rv.s, MIPSInst_FS(ir)); break; + case fmovz_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + if (xcp->regs[MIPSInst_FT(ir)] != 0) return 0; SPFROMREG(rv.s, MIPSInst_FS(ir)); break; + case fmovn_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + if (xcp->regs[MIPSInst_FT(ir)] == 0) return 0; SPFROMREG(rv.s, MIPSInst_FS(ir)); break; -#endif + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; + case fneg_op: handler.u = ieee754sp_neg; goto scopuop; + case fmov_op: /* an easy one */ SPFROMREG(rv.s, MIPSInst_FS(ir)); goto copcsr; /* binary op on handler */ - scopbop: - { - ieee754sp fs, ft; - - SPFROMREG(fs, MIPSInst_FS(ir)); - SPFROMREG(ft, MIPSInst_FT(ir)); - - rv.s = (*handler.b) (fs, ft); - goto copcsr; - } - scopuop: - { - ieee754sp fs; +scopbop: + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(ft, MIPSInst_FT(ir)); - SPFROMREG(fs, MIPSInst_FS(ir)); - rv.s = (*handler.u) (fs); - goto copcsr; - } - copcsr: + rv.s = (*handler.b) (fs, ft); + goto copcsr; +scopuop: + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = (*handler.u) (fs); + goto copcsr; +copcsr: if (ieee754_cxtest(IEEE754_INEXACT)) rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; if (ieee754_cxtest(IEEE754_UNDERFLOW)) @@ -1698,70 +1129,62 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, /* unary conv ops */ case fcvts_op: return SIGILL; /* not defined */ - case fcvtd_op:{ - ieee754sp fs; + case fcvtd_op: SPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fsp(fs); rfmt = d_fmt; goto copcsr; - } - case fcvtw_op:{ - ieee754sp fs; + case fcvtw_op: SPFROMREG(fs, MIPSInst_FS(ir)); rv.w = ieee754sp_tint(fs); rfmt = w_fmt; goto copcsr; - } -#if __mips >= 2 || defined(__mips64) case fround_op: case ftrunc_op: case fceil_op: - case ffloor_op:{ - unsigned int oldrm = ieee754_csr.rm; - ieee754sp fs; + case ffloor_op: + if (!cpu_has_mips_2_3_4_5 && !cpu_has_mips64) + return SIGILL; + oldrm = ieee754_csr.rm; SPFROMREG(fs, MIPSInst_FS(ir)); - ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; + ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir)); rv.w = ieee754sp_tint(fs); ieee754_csr.rm = oldrm; rfmt = w_fmt; goto copcsr; - } -#endif /* __mips >= 2 */ -#if defined(__mips64) - case fcvtl_op:{ - ieee754sp fs; + case fcvtl_op: + if (!cpu_has_mips_3_4_5 && cpu_has_mips64) + return SIGILL; SPFROMREG(fs, MIPSInst_FS(ir)); rv.l = ieee754sp_tlong(fs); rfmt = l_fmt; goto copcsr; - } case froundl_op: case ftruncl_op: case fceill_op: - case ffloorl_op:{ - unsigned int oldrm = ieee754_csr.rm; - ieee754sp fs; + case ffloorl_op: + if (!cpu_has_mips_3_4_5 && cpu_has_mips64) + return SIGILL; + oldrm = ieee754_csr.rm; SPFROMREG(fs, MIPSInst_FS(ir)); - ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; + ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir)); rv.l = ieee754sp_tlong(fs); ieee754_csr.rm = oldrm; rfmt = l_fmt; goto copcsr; - } -#endif /* defined(__mips64) */ default: if (MIPSInst_FUNC(ir) >= fcmp_op) { unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; - ieee754sp fs, ft; + union ieee754sp fs, ft; SPFROMREG(fs, MIPSInst_FS(ir)); SPFROMREG(ft, MIPSInst_FT(ir)); @@ -1774,19 +1197,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, else goto copcsr; - } - else { + } else return SIGILL; - } break; } break; } - case d_fmt:{ + case d_fmt: { + union ieee754dp fs, ft; union { - ieee754dp(*b) (ieee754dp, ieee754dp); - ieee754dp(*u) (ieee754dp); + union ieee754dp(*b) (union ieee754dp, union ieee754dp); + union ieee754dp(*u) (union ieee754dp); } handler; switch (MIPSInst_FUNC(ir)) { @@ -1805,21 +1227,33 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, goto dcopbop; /* unary ops */ -#if __mips >= 2 || defined(__mips64) case fsqrt_op: + if (!cpu_has_mips_2_3_4_5_r) + return SIGILL; + handler.u = ieee754dp_sqrt; goto dcopuop; -#endif -#if __mips >= 4 && __mips != 32 + /* + * Note that on some MIPS IV implementations such as the + * R5000 and R8000 the FSQRT and FRECIP instructions do not + * achieve full IEEE-754 accuracy - however this emulator does. + */ case frsqrt_op: + if (!cpu_has_mips_4_5_r2) + return SIGILL; + handler.u = fpemu_dp_rsqrt; goto dcopuop; case frecip_op: + if (!cpu_has_mips_4_5_r2) + return SIGILL; + handler.u = fpemu_dp_recip; goto dcopuop; -#endif -#if __mips >= 4 case fmovc_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + cond = fpucondbit[MIPSInst_FT(ir) >> 2]; if (((ctx->fcr31 & cond) != 0) != ((MIPSInst_FT(ir) & 1) != 0)) @@ -1827,16 +1261,21 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(rv.d, MIPSInst_FS(ir)); break; case fmovz_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + if (xcp->regs[MIPSInst_FT(ir)] != 0) return 0; DPFROMREG(rv.d, MIPSInst_FS(ir)); break; case fmovn_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + if (xcp->regs[MIPSInst_FT(ir)] == 0) return 0; DPFROMREG(rv.d, MIPSInst_FS(ir)); break; -#endif case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; @@ -1851,91 +1290,78 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, goto copcsr; /* binary op on handler */ - dcopbop:{ - ieee754dp fs, ft; - - DPFROMREG(fs, MIPSInst_FS(ir)); - DPFROMREG(ft, MIPSInst_FT(ir)); - - rv.d = (*handler.b) (fs, ft); - goto copcsr; - } - dcopuop:{ - ieee754dp fs; - - DPFROMREG(fs, MIPSInst_FS(ir)); - rv.d = (*handler.u) (fs); - goto copcsr; - } +dcopbop: + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(ft, MIPSInst_FT(ir)); - /* unary conv ops */ - case fcvts_op:{ - ieee754dp fs; + rv.d = (*handler.b) (fs, ft); + goto copcsr; +dcopuop: + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = (*handler.u) (fs); + goto copcsr; + /* + * unary conv ops + */ + case fcvts_op: DPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fdp(fs); rfmt = s_fmt; goto copcsr; - } + case fcvtd_op: return SIGILL; /* not defined */ - case fcvtw_op:{ - ieee754dp fs; - + case fcvtw_op: DPFROMREG(fs, MIPSInst_FS(ir)); rv.w = ieee754dp_tint(fs); /* wrong */ rfmt = w_fmt; goto copcsr; - } -#if __mips >= 2 || defined(__mips64) case fround_op: case ftrunc_op: case fceil_op: - case ffloor_op:{ - unsigned int oldrm = ieee754_csr.rm; - ieee754dp fs; + case ffloor_op: + if (!cpu_has_mips_2_3_4_5_r) + return SIGILL; + oldrm = ieee754_csr.rm; DPFROMREG(fs, MIPSInst_FS(ir)); - ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; + ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir)); rv.w = ieee754dp_tint(fs); ieee754_csr.rm = oldrm; rfmt = w_fmt; goto copcsr; - } -#endif -#if defined(__mips64) - case fcvtl_op:{ - ieee754dp fs; + case fcvtl_op: + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; DPFROMREG(fs, MIPSInst_FS(ir)); rv.l = ieee754dp_tlong(fs); rfmt = l_fmt; goto copcsr; - } case froundl_op: case ftruncl_op: case fceill_op: - case ffloorl_op:{ - unsigned int oldrm = ieee754_csr.rm; - ieee754dp fs; + case ffloorl_op: + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + oldrm = ieee754_csr.rm; DPFROMREG(fs, MIPSInst_FS(ir)); - ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; + ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir)); rv.l = ieee754dp_tlong(fs); ieee754_csr.rm = oldrm; rfmt = l_fmt; goto copcsr; - } -#endif /* __mips >= 3 */ default: if (MIPSInst_FUNC(ir) >= fcmp_op) { unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; - ieee754dp fs, ft; + union ieee754dp fs, ft; DPFROMREG(fs, MIPSInst_FS(ir)); DPFROMREG(ft, MIPSInst_FT(ir)); @@ -1957,11 +1383,8 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; } break; - } - - case w_fmt:{ - ieee754sp fs; + case w_fmt: switch (MIPSInst_FUNC(ir)) { case fcvts_op: /* convert word to single precision real */ @@ -1981,9 +1404,11 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; } -#if defined(__mips64) - case l_fmt:{ - u64 bits; + case l_fmt: + + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + DIFROMREG(bits, MIPSInst_FS(ir)); switch (MIPSInst_FUNC(ir)) { @@ -2001,8 +1426,6 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, return SIGILL; } break; - } -#endif default: return SIGILL; @@ -2017,7 +1440,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, */ ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { - /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */ + /*printk ("SIGFPE: FPU csr = %08x\n",ctx->fcr31); */ return SIGFPE; } @@ -2025,18 +1448,19 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, * Now we can safely write the result back to the register file. */ switch (rfmt) { - case -1:{ -#if __mips >= 4 - cond = fpucondbit[MIPSInst_FD(ir) >> 2]; -#else - cond = FPU_CSR_COND; -#endif + case -1: + + if (cpu_has_mips_4_5_r) + cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; + else + cbit = FPU_CSR_COND; + cond = ctx->fcr31 & cbit; if (rv.w) ctx->fcr31 |= cond; else ctx->fcr31 &= ~cond; break; - } + case d_fmt: DPTOREG(rv.d, MIPSInst_FD(ir)); break; @@ -2046,11 +1470,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, case w_fmt: SITOREG(rv.w, MIPSInst_FD(ir)); break; -#if defined(__mips64) case l_fmt: + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + DITOREG(rv.l, MIPSInst_FD(ir)); break; -#endif default: return SIGILL; } @@ -2138,11 +1563,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, * ieee754_csr. But ieee754_csr.rm is ieee * library modes. (not mips rounding mode) */ - /* convert to ieee library modes */ - ieee754_csr.rm = ieee_rm[ieee754_csr.rm]; sig = cop1Emulate(xcp, ctx, dec_insn, fault_addr); - /* revert to mips rounding mode */ - ieee754_csr.rm = mips_rm[ieee754_csr.rm]; } if (has_fpu) @@ -2155,58 +1576,8 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, /* SIGILL indicates a non-fpu instruction */ if (sig == SIGILL && xcp->cp0_epc != oldepc) - /* but if epc has advanced, then ignore it */ + /* but if EPC has advanced, then ignore it */ sig = 0; return sig; } - -#ifdef CONFIG_DEBUG_FS - -static int fpuemu_stat_get(void *data, u64 *val) -{ - int cpu; - unsigned long sum = 0; - for_each_online_cpu(cpu) { - struct mips_fpu_emulator_stats *ps; - local_t *pv; - ps = &per_cpu(fpuemustats, cpu); - pv = (void *)ps + (unsigned long)data; - sum += local_read(pv); - } - *val = sum; - return 0; -} -DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n"); - -extern struct dentry *mips_debugfs_dir; -static int __init debugfs_fpuemu(void) -{ - struct dentry *d, *dir; - - if (!mips_debugfs_dir) - return -ENODEV; - dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir); - if (!dir) - return -ENOMEM; - -#define FPU_STAT_CREATE(M) \ - do { \ - d = debugfs_create_file(#M , S_IRUGO, dir, \ - (void *)offsetof(struct mips_fpu_emulator_stats, M), \ - &fops_fpuemu_stat); \ - if (!d) \ - return -ENOMEM; \ - } while (0) - - FPU_STAT_CREATE(emulated); - FPU_STAT_CREATE(loads); - FPU_STAT_CREATE(stores); - FPU_STAT_CREATE(cp1ops); - FPU_STAT_CREATE(cp1xops); - FPU_STAT_CREATE(errors); - - return 0; -} -__initcall(debugfs_fpuemu); -#endif diff --git a/arch/mips/math-emu/dp_add.c b/arch/mips/math-emu/dp_add.c index c57c8adc42c46a..7f64577df98492 100644 --- a/arch/mips/math-emu/dp_add.c +++ b/arch/mips/math-emu/dp_add.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,24 +16,22 @@ * * 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. - * - * ######################################################################## - * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754dp.h" -ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) +union ieee754dp ieee754dp_add(union ieee754dp x, union ieee754dp y) { + int s; + COMPXDP; COMPYDP; EXPLODEXDP; EXPLODEYDP; - CLEARCX; + ieee754_clearcx(); FLUSHXDP; FLUSHYDP; @@ -52,8 +48,8 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_nanxcpt(ieee754dp_indef(), "add", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef()); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -69,14 +65,14 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) return x; - /* Infinity handling - */ - + /* + * Infinity handling + */ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): if (xs == ys) return x; - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_xcpt(ieee754dp_indef(), "add", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_indef(); case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): @@ -88,15 +84,14 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): return x; - /* Zero handling - */ - + /* + * Zero handling + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): if (xs == ys) return x; else - return ieee754dp_zero(ieee754_csr.rm == - IEEE754_RD); + return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): @@ -125,20 +120,24 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) assert(xm & DP_HIDDEN_BIT); assert(ym & DP_HIDDEN_BIT); - /* provide guard,round and stick bit space */ + /* + * Provide guard,round and stick bit space. + */ xm <<= 3; ym <<= 3; if (xe > ye) { - /* have to shift y fraction right to align + /* + * Have to shift y fraction right to align. */ - int s = xe - ye; + s = xe - ye; ym = XDPSRS(ym, s); ye += s; } else if (ye > xe) { - /* have to shift x fraction right to align + /* + * Have to shift x fraction right to align. */ - int s = ye - xe; + s = ye - xe; xm = XDPSRS(xm, s); xe += s; } @@ -146,14 +145,15 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) assert(xe <= DP_EMAX); if (xs == ys) { - /* generate 28 bit result of adding two 27 bit numbers - * leaving result in xm,xs,xe + /* + * Generate 28 bit result of adding two 27 bit numbers + * leaving result in xm, xs and xe. */ xm = xm + ym; xe = xe; xs = xs; - if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ + if (xm >> (DP_FBITS + 1 + 3)) { /* carry out */ xm = XDPSRS1(xm); xe++; } @@ -168,15 +168,16 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) xs = ys; } if (xm == 0) - return ieee754dp_zero(ieee754_csr.rm == - IEEE754_RD); + return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); - /* normalize to rounding precision */ - while ((xm >> (DP_MBITS + 3)) == 0) { + /* + * Normalize to rounding precision. + */ + while ((xm >> (DP_FBITS + 3)) == 0) { xm <<= 1; xe--; } - } - DPNORMRET2(xs, xe, xm, "add", x, y); + + return ieee754dp_format(xs, xe, xm); } diff --git a/arch/mips/math-emu/dp_cmp.c b/arch/mips/math-emu/dp_cmp.c index 0f32486b0ed9f0..30f95f6e9ac443 100644 --- a/arch/mips/math-emu/dp_cmp.c +++ b/arch/mips/math-emu/dp_cmp.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,16 +16,16 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754dp.h" -int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp, int sig) +int ieee754dp_cmp(union ieee754dp x, union ieee754dp y, int cmp, int sig) { + s64 vx; + s64 vy; + COMPXDP; COMPYDP; @@ -35,21 +33,21 @@ int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp, int sig) EXPLODEYDP; FLUSHXDP; FLUSHYDP; - CLEARCX; /* Even clear inexact flag here */ + ieee754_clearcx(); /* Even clear inexact flag here */ if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) { if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN) - SETCX(IEEE754_INVALID_OPERATION); + ieee754_setcx(IEEE754_INVALID_OPERATION); if (cmp & IEEE754_CUN) return 1; if (cmp & (IEEE754_CLT | IEEE754_CGT)) { - if (sig && SETANDTESTCX(IEEE754_INVALID_OPERATION)) - return ieee754si_xcpt(0, "fcmpf", x); + if (sig && ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) + return 0; } return 0; } else { - s64 vx = x.bits; - s64 vy = y.bits; + vx = x.bits; + vy = y.bits; if (vx < 0) vx = -vx ^ DP_SIGN_BIT; diff --git a/arch/mips/math-emu/dp_div.c b/arch/mips/math-emu/dp_div.c index a1bce1b7c09c8a..bef0e55e59381e 100644 --- a/arch/mips/math-emu/dp_div.c +++ b/arch/mips/math-emu/dp_div.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,23 +16,24 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754dp.h" -ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) +union ieee754dp ieee754dp_div(union ieee754dp x, union ieee754dp y) { + u64 rm; + int re; + u64 bm; + COMPXDP; COMPYDP; EXPLODEXDP; EXPLODEYDP; - CLEARCX; + ieee754_clearcx(); FLUSHXDP; FLUSHYDP; @@ -51,8 +50,8 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_nanxcpt(ieee754dp_indef(), "div", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef()); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -68,12 +67,12 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) return x; - /* Infinity handling - */ - + /* + * Infinity handling + */ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_indef(); case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): @@ -85,17 +84,17 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): return ieee754dp_inf(xs ^ ys); - /* Zero handling - */ - + /* + * Zero handling + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_indef(); case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): - SETCX(IEEE754_ZERO_DIVIDE); - return ieee754dp_xcpt(ieee754dp_inf(xs ^ ys), "div", x, y); + ieee754_setcx(IEEE754_ZERO_DIVIDE); + return ieee754dp_inf(xs ^ ys); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): @@ -122,35 +121,34 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) xm <<= 3; ym <<= 3; - { - /* now the dirty work */ - - u64 rm = 0; - int re = xe - ye; - u64 bm; - - for (bm = DP_MBIT(DP_MBITS + 2); bm; bm >>= 1) { - if (xm >= ym) { - xm -= ym; - rm |= bm; - if (xm == 0) - break; - } - xm <<= 1; - } - rm <<= 1; - if (xm) - rm |= 1; /* have remainder, set sticky */ + /* now the dirty work */ - assert(rm); + rm = 0; + re = xe - ye; - /* normalise rm to rounding precision ? - */ - while ((rm >> (DP_MBITS + 3)) == 0) { - rm <<= 1; - re--; + for (bm = DP_MBIT(DP_FBITS + 2); bm; bm >>= 1) { + if (xm >= ym) { + xm -= ym; + rm |= bm; + if (xm == 0) + break; } + xm <<= 1; + } + + rm <<= 1; + if (xm) + rm |= 1; /* have remainder, set sticky */ - DPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y); + assert(rm); + + /* + * Normalise rm to rounding precision ? + */ + while ((rm >> (DP_FBITS + 3)) == 0) { + rm <<= 1; + re--; } + + return ieee754dp_format(xs == ys ? 0 : 1, re, rm); } diff --git a/arch/mips/math-emu/dp_fint.c b/arch/mips/math-emu/dp_fint.c index 88571288c9e004..10258f0afd698f 100644 --- a/arch/mips/math-emu/dp_fint.c +++ b/arch/mips/math-emu/dp_fint.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,21 +16,18 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754dp.h" -ieee754dp ieee754dp_fint(int x) +union ieee754dp ieee754dp_fint(int x) { u64 xm; int xe; int xs; - CLEARCX; + ieee754_clearcx(); if (x == 0) return ieee754dp_zero(0); @@ -51,29 +46,11 @@ ieee754dp ieee754dp_fint(int x) xm = x; } -#if 1 /* normalize - result can never be inexact or overflow */ - xe = DP_MBITS; - while ((xm >> DP_MBITS) == 0) { + xe = DP_FBITS; + while ((xm >> DP_FBITS) == 0) { xm <<= 1; xe--; } return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); -#else - /* normalize */ - xe = DP_MBITS + 3; - while ((xm >> (DP_MBITS + 3)) == 0) { - xm <<= 1; - xe--; - } - DPNORMRET1(xs, xe, xm, "fint", x); -#endif -} - -ieee754dp ieee754dp_funs(unsigned int u) -{ - if ((int) u < 0) - return ieee754dp_add(ieee754dp_1e31(), - ieee754dp_fint(u & ~(1 << 31))); - return ieee754dp_fint(u); } diff --git a/arch/mips/math-emu/dp_flong.c b/arch/mips/math-emu/dp_flong.c index 14fc01ec742d2c..a267c2e39d7832 100644 --- a/arch/mips/math-emu/dp_flong.c +++ b/arch/mips/math-emu/dp_flong.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,21 +16,18 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754dp.h" -ieee754dp ieee754dp_flong(s64 x) +union ieee754dp ieee754dp_flong(s64 x) { u64 xm; int xe; int xs; - CLEARCX; + ieee754_clearcx(); if (x == 0) return ieee754dp_zero(0); @@ -52,26 +47,19 @@ ieee754dp ieee754dp_flong(s64 x) } /* normalize */ - xe = DP_MBITS + 3; - if (xm >> (DP_MBITS + 1 + 3)) { + xe = DP_FBITS + 3; + if (xm >> (DP_FBITS + 1 + 3)) { /* shunt out overflow bits */ - while (xm >> (DP_MBITS + 1 + 3)) { + while (xm >> (DP_FBITS + 1 + 3)) { XDPSRSX1(); } } else { /* normalize in grs extended double precision */ - while ((xm >> (DP_MBITS + 3)) == 0) { + while ((xm >> (DP_FBITS + 3)) == 0) { xm <<= 1; xe--; } } - DPNORMRET1(xs, xe, xm, "dp_flong", x); -} -ieee754dp ieee754dp_fulong(u64 u) -{ - if ((s64) u < 0) - return ieee754dp_add(ieee754dp_1e63(), - ieee754dp_flong(u & ~(1ULL << 63))); - return ieee754dp_flong(u); + return ieee754dp_format(xs, xe, xm); } diff --git a/arch/mips/math-emu/dp_frexp.c b/arch/mips/math-emu/dp_frexp.c deleted file mode 100644 index cb15a5eaecbb29..00000000000000 --- a/arch/mips/math-emu/dp_frexp.c +++ /dev/null @@ -1,52 +0,0 @@ -/* IEEE754 floating point arithmetic - * double precision: common utilities - */ -/* - * MIPS floating point support - * Copyright (C) 1994-2000 Algorithmics Ltd. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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 "ieee754dp.h" - -/* close to ieeep754dp_logb -*/ -ieee754dp ieee754dp_frexp(ieee754dp x, int *eptr) -{ - COMPXDP; - CLEARCX; - EXPLODEXDP; - - switch (xc) { - case IEEE754_CLASS_SNAN: - case IEEE754_CLASS_QNAN: - case IEEE754_CLASS_INF: - case IEEE754_CLASS_ZERO: - *eptr = 0; - return x; - case IEEE754_CLASS_DNORM: - DPDNORMX; - break; - case IEEE754_CLASS_NORM: - break; - } - *eptr = xe + 1; - return builddp(xs, -1 + DP_EBIAS, xm & ~DP_HIDDEN_BIT); -} diff --git a/arch/mips/math-emu/dp_fsp.c b/arch/mips/math-emu/dp_fsp.c index daed6834dc153b..ffb69c5830b044 100644 --- a/arch/mips/math-emu/dp_fsp.c +++ b/arch/mips/math-emu/dp_fsp.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,56 +16,58 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - +#include "ieee754sp.h" #include "ieee754dp.h" -ieee754dp ieee754dp_fsp(ieee754sp x) +union ieee754dp ieee754dp_fsp(union ieee754sp x) { COMPXSP; EXPLODEXSP; - CLEARCX; + ieee754_clearcx(); FLUSHXSP; switch (xc) { case IEEE754_CLASS_SNAN: - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_nanxcpt(ieee754dp_indef(), "fsp"); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef()); + case IEEE754_CLASS_QNAN: return ieee754dp_nanxcpt(builddp(xs, DP_EMAX + 1 + DP_EBIAS, ((u64) xm - << (DP_MBITS - - SP_MBITS))), "fsp", - x); + << (DP_FBITS - + SP_FBITS)))); case IEEE754_CLASS_INF: return ieee754dp_inf(xs); + case IEEE754_CLASS_ZERO: return ieee754dp_zero(xs); + case IEEE754_CLASS_DNORM: /* normalize */ - while ((xm >> SP_MBITS) == 0) { + while ((xm >> SP_FBITS) == 0) { xm <<= 1; xe--; } break; + case IEEE754_CLASS_NORM: break; } - /* CAN'T possibly overflow,underflow, or need rounding + /* + * Can't possibly overflow,underflow, or need rounding */ /* drop the hidden bit */ xm &= ~SP_HIDDEN_BIT; return builddp(xs, xe + DP_EBIAS, - (u64) xm << (DP_MBITS - SP_MBITS)); + (u64) xm << (DP_FBITS - SP_FBITS)); } diff --git a/arch/mips/math-emu/dp_logb.c b/arch/mips/math-emu/dp_logb.c deleted file mode 100644 index 151127e59f5c47..00000000000000 --- a/arch/mips/math-emu/dp_logb.c +++ /dev/null @@ -1,53 +0,0 @@ -/* IEEE754 floating point arithmetic - * double precision: common utilities - */ -/* - * MIPS floating point support - * Copyright (C) 1994-2000 Algorithmics Ltd. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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 "ieee754dp.h" - -ieee754dp ieee754dp_logb(ieee754dp x) -{ - COMPXDP; - - CLEARCX; - - EXPLODEXDP; - - switch (xc) { - case IEEE754_CLASS_SNAN: - return ieee754dp_nanxcpt(x, "logb", x); - case IEEE754_CLASS_QNAN: - return x; - case IEEE754_CLASS_INF: - return ieee754dp_inf(0); - case IEEE754_CLASS_ZERO: - return ieee754dp_inf(1); - case IEEE754_CLASS_DNORM: - DPDNORMX; - break; - case IEEE754_CLASS_NORM: - break; - } - return ieee754dp_fint(xe); -} diff --git a/arch/mips/math-emu/dp_modf.c b/arch/mips/math-emu/dp_modf.c deleted file mode 100644 index b01f9cf6d40275..00000000000000 --- a/arch/mips/math-emu/dp_modf.c +++ /dev/null @@ -1,79 +0,0 @@ -/* IEEE754 floating point arithmetic - * double precision: common utilities - */ -/* - * MIPS floating point support - * Copyright (C) 1994-2000 Algorithmics Ltd. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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 "ieee754dp.h" - -/* modf function is always exact for a finite number -*/ -ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp *ip) -{ - COMPXDP; - - CLEARCX; - - EXPLODEXDP; - - switch (xc) { - case IEEE754_CLASS_SNAN: - case IEEE754_CLASS_QNAN: - case IEEE754_CLASS_INF: - case IEEE754_CLASS_ZERO: - *ip = x; - return x; - case IEEE754_CLASS_DNORM: - /* far to small */ - *ip = ieee754dp_zero(xs); - return x; - case IEEE754_CLASS_NORM: - break; - } - if (xe < 0) { - *ip = ieee754dp_zero(xs); - return x; - } - if (xe >= DP_MBITS) { - *ip = x; - return ieee754dp_zero(xs); - } - /* generate ipart mantissa by clearing bottom bits - */ - *ip = builddp(xs, xe + DP_EBIAS, - ((xm >> (DP_MBITS - xe)) << (DP_MBITS - xe)) & - ~DP_HIDDEN_BIT); - - /* generate fpart mantissa by clearing top bits - * and normalizing (must be able to normalize) - */ - xm = (xm << (64 - (DP_MBITS - xe))) >> (64 - (DP_MBITS - xe)); - if (xm == 0) - return ieee754dp_zero(xs); - - while ((xm >> DP_MBITS) == 0) { - xm <<= 1; - xe--; - } - return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); -} diff --git a/arch/mips/math-emu/dp_mul.c b/arch/mips/math-emu/dp_mul.c index 09175f461920c0..d3acdedb5b9dd3 100644 --- a/arch/mips/math-emu/dp_mul.c +++ b/arch/mips/math-emu/dp_mul.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,23 +16,32 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754dp.h" -ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) +union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y) { + int re; + int rs; + u64 rm; + unsigned lxm; + unsigned hxm; + unsigned lym; + unsigned hym; + u64 lrm; + u64 hrm; + u64 t; + u64 at; + COMPXDP; COMPYDP; EXPLODEXDP; EXPLODEYDP; - CLEARCX; + ieee754_clearcx(); FLUSHXDP; FLUSHYDP; @@ -51,8 +58,8 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_nanxcpt(ieee754dp_indef(), "mul", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef()); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -68,12 +75,13 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) return x; - /* Infinity handling */ - + /* + * Infinity handling + */ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_xcpt(ieee754dp_indef(), "mul", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_indef(); case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): @@ -107,70 +115,59 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) /* rm = xm * ym, re = xe+ye basically */ assert(xm & DP_HIDDEN_BIT); assert(ym & DP_HIDDEN_BIT); - { - int re = xe + ye; - int rs = xs ^ ys; - u64 rm; - /* shunt to top of word */ - xm <<= 64 - (DP_MBITS + 1); - ym <<= 64 - (DP_MBITS + 1); + re = xe + ye; + rs = xs ^ ys; + + /* shunt to top of word */ + xm <<= 64 - (DP_FBITS + 1); + ym <<= 64 - (DP_FBITS + 1); - /* multiply 32bits xm,ym to give high 32bits rm with stickness - */ + /* + * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + */ - /* 32 * 32 => 64 */ + /* 32 * 32 => 64 */ #define DPXMULT(x, y) ((u64)(x) * (u64)y) - { - unsigned lxm = xm; - unsigned hxm = xm >> 32; - unsigned lym = ym; - unsigned hym = ym >> 32; - u64 lrm; - u64 hrm; - - lrm = DPXMULT(lxm, lym); - hrm = DPXMULT(hxm, hym); - - { - u64 t = DPXMULT(lxm, hym); - { - u64 at = - lrm + (t << 32); - hrm += at < lrm; - lrm = at; - } - hrm = hrm + (t >> 32); - } - - { - u64 t = DPXMULT(hxm, lym); - { - u64 at = - lrm + (t << 32); - hrm += at < lrm; - lrm = at; - } - hrm = hrm + (t >> 32); - } - rm = hrm | (lrm != 0); - } - - /* - * sticky shift down to normal rounding precision - */ - if ((s64) rm < 0) { - rm = - (rm >> (64 - (DP_MBITS + 1 + 3))) | - ((rm << (DP_MBITS + 1 + 3)) != 0); + lxm = xm; + hxm = xm >> 32; + lym = ym; + hym = ym >> 32; + + lrm = DPXMULT(lxm, lym); + hrm = DPXMULT(hxm, hym); + + t = DPXMULT(lxm, hym); + + at = lrm + (t << 32); + hrm += at < lrm; + lrm = at; + + hrm = hrm + (t >> 32); + + t = DPXMULT(hxm, lym); + + at = lrm + (t << 32); + hrm += at < lrm; + lrm = at; + + hrm = hrm + (t >> 32); + + rm = hrm | (lrm != 0); + + /* + * Sticky shift down to normal rounding precision. + */ + if ((s64) rm < 0) { + rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | + ((rm << (DP_FBITS + 1 + 3)) != 0); re++; - } else { - rm = - (rm >> (64 - (DP_MBITS + 1 + 3 + 1))) | - ((rm << (DP_MBITS + 1 + 3 + 1)) != 0); - } - assert(rm & (DP_HIDDEN_BIT << 3)); - DPNORMRET2(rs, re, rm, "mul", x, y); + } else { + rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | + ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); } + assert(rm & (DP_HIDDEN_BIT << 3)); + + return ieee754dp_format(rs, re, rm); } diff --git a/arch/mips/math-emu/dp_scalb.c b/arch/mips/math-emu/dp_scalb.c deleted file mode 100644 index 6f5df438dda83f..00000000000000 --- a/arch/mips/math-emu/dp_scalb.c +++ /dev/null @@ -1,57 +0,0 @@ -/* IEEE754 floating point arithmetic - * double precision: common utilities - */ -/* - * MIPS floating point support - * Copyright (C) 1994-2000 Algorithmics Ltd. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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 "ieee754dp.h" - -ieee754dp ieee754dp_scalb(ieee754dp x, int n) -{ - COMPXDP; - - CLEARCX; - - EXPLODEXDP; - - switch (xc) { - case IEEE754_CLASS_SNAN: - return ieee754dp_nanxcpt(x, "scalb", x, n); - case IEEE754_CLASS_QNAN: - case IEEE754_CLASS_INF: - case IEEE754_CLASS_ZERO: - return x; - case IEEE754_CLASS_DNORM: - DPDNORMX; - break; - case IEEE754_CLASS_NORM: - break; - } - DPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n); -} - - -ieee754dp ieee754dp_ldexp(ieee754dp x, int n) -{ - return ieee754dp_scalb(x, n); -} diff --git a/arch/mips/math-emu/dp_simple.c b/arch/mips/math-emu/dp_simple.c index 79ce2673a71418..bccbe90efceb9a 100644 --- a/arch/mips/math-emu/dp_simple.c +++ b/arch/mips/math-emu/dp_simple.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,33 +16,17 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754dp.h" -int ieee754dp_finite(ieee754dp x) -{ - return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS; -} - -ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y) -{ - CLEARCX; - DPSIGN(x) = DPSIGN(y); - return x; -} - - -ieee754dp ieee754dp_neg(ieee754dp x) +union ieee754dp ieee754dp_neg(union ieee754dp x) { COMPXDP; EXPLODEXDP; - CLEARCX; + ieee754_clearcx(); FLUSHXDP; /* @@ -55,30 +37,29 @@ ieee754dp ieee754dp_neg(ieee754dp x) DPSIGN(x) ^= 1; if (xc == IEEE754_CLASS_SNAN) { - ieee754dp y = ieee754dp_indef(); - SETCX(IEEE754_INVALID_OPERATION); + union ieee754dp y = ieee754dp_indef(); + ieee754_setcx(IEEE754_INVALID_OPERATION); DPSIGN(y) = DPSIGN(x); - return ieee754dp_nanxcpt(y, "neg"); + return ieee754dp_nanxcpt(y); } return x; } - -ieee754dp ieee754dp_abs(ieee754dp x) +union ieee754dp ieee754dp_abs(union ieee754dp x) { COMPXDP; EXPLODEXDP; - CLEARCX; + ieee754_clearcx(); FLUSHXDP; /* Clear sign ALWAYS, irrespective of NaN */ DPSIGN(x) = 0; if (xc == IEEE754_CLASS_SNAN) { - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_nanxcpt(ieee754dp_indef(), "abs"); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef()); } return x; diff --git a/arch/mips/math-emu/dp_sqrt.c b/arch/mips/math-emu/dp_sqrt.c index b874d60a942bd0..041bbb6124bbde 100644 --- a/arch/mips/math-emu/dp_sqrt.c +++ b/arch/mips/math-emu/dp_sqrt.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,12 +16,9 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754dp.h" static const unsigned table[] = { @@ -34,44 +29,49 @@ static const unsigned table[] = { 1742, 661, 130 }; -ieee754dp ieee754dp_sqrt(ieee754dp x) +union ieee754dp ieee754dp_sqrt(union ieee754dp x) { struct _ieee754_csr oldcsr; - ieee754dp y, z, t; + union ieee754dp y, z, t; unsigned scalx, yh; COMPXDP; EXPLODEXDP; - CLEARCX; + ieee754_clearcx(); FLUSHXDP; /* x == INF or NAN? */ switch (xc) { case IEEE754_CLASS_QNAN: /* sqrt(Nan) = Nan */ - return ieee754dp_nanxcpt(x, "sqrt"); + return ieee754dp_nanxcpt(x); + case IEEE754_CLASS_SNAN: - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef()); + case IEEE754_CLASS_ZERO: /* sqrt(0) = 0 */ return x; + case IEEE754_CLASS_INF: if (xs) { /* sqrt(-Inf) = Nan */ - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef()); } /* sqrt(+Inf) = Inf */ return x; + case IEEE754_CLASS_DNORM: DPDNORMX; /* fall through */ + case IEEE754_CLASS_NORM: if (xs) { /* sqrt(-x) = Nan */ - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef()); } break; } @@ -80,7 +80,7 @@ ieee754dp ieee754dp_sqrt(ieee754dp x) oldcsr = ieee754_csr; ieee754_csr.mx &= ~IEEE754_INEXACT; ieee754_csr.sx &= ~IEEE754_INEXACT; - ieee754_csr.rm = IEEE754_RN; + ieee754_csr.rm = FPU_CSR_RN; /* adjust exponent to prevent overflow */ scalx = 0; @@ -110,19 +110,19 @@ ieee754dp ieee754dp_sqrt(ieee754dp x) /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */ /* t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */ z = t = ieee754dp_mul(y, y); - t.parts.bexp += 0x001; + t.bexp += 0x001; t = ieee754dp_add(t, z); z = ieee754dp_mul(ieee754dp_sub(x, z), y); /* t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; */ t = ieee754dp_div(z, ieee754dp_add(t, x)); - t.parts.bexp += 0x001; + t.bexp += 0x001; y = ieee754dp_add(y, t); /* twiddle last bit to force y correctly rounded */ /* set RZ, clear INEX flag */ - ieee754_csr.rm = IEEE754_RZ; + ieee754_csr.rm = FPU_CSR_RZ; ieee754_csr.sx &= ~IEEE754_INEXACT; /* t=x/y; ...chopped quotient, possibly inexact */ @@ -139,10 +139,10 @@ ieee754dp ieee754dp_sqrt(ieee754dp x) oldcsr.sx |= IEEE754_INEXACT; switch (oldcsr.rm) { - case IEEE754_RP: + case FPU_CSR_RU: y.bits += 1; /* drop through */ - case IEEE754_RN: + case FPU_CSR_RN: t.bits += 1; break; } @@ -155,7 +155,7 @@ ieee754dp ieee754dp_sqrt(ieee754dp x) } /* py[n0]=py[n0]+scalx; ...scale back y */ - y.parts.bexp += scalx; + y.bexp += scalx; /* restore rounding mode, possibly set inexact */ ieee754_csr = oldcsr; diff --git a/arch/mips/math-emu/dp_sub.c b/arch/mips/math-emu/dp_sub.c index 91e0a4b5cbc76e..7a174029043a67 100644 --- a/arch/mips/math-emu/dp_sub.c +++ b/arch/mips/math-emu/dp_sub.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,23 +16,22 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754dp.h" -ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) +union ieee754dp ieee754dp_sub(union ieee754dp x, union ieee754dp y) { + int s; + COMPXDP; COMPYDP; EXPLODEXDP; EXPLODEYDP; - CLEARCX; + ieee754_clearcx(); FLUSHXDP; FLUSHYDP; @@ -51,8 +48,8 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_nanxcpt(ieee754dp_indef(), "sub", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef()); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -68,14 +65,14 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) return x; - /* Infinity handling - */ - + /* + * Infinity handling + */ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): if (xs != ys) return x; - SETCX(IEEE754_INVALID_OPERATION); - return ieee754dp_xcpt(ieee754dp_indef(), "sub", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_indef(); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): @@ -87,15 +84,14 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): return x; - /* Zero handling - */ - + /* + * Zero handling + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): if (xs != ys) return x; else - return ieee754dp_zero(ieee754_csr.rm == - IEEE754_RD); + return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): @@ -136,15 +132,17 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) ym <<= 3; if (xe > ye) { - /* have to shift y fraction right to align + /* + * Have to shift y fraction right to align */ - int s = xe - ye; + s = xe - ye; ym = XDPSRS(ym, s); ye += s; } else if (ye > xe) { - /* have to shift x fraction right to align + /* + * Have to shift x fraction right to align */ - int s = ye - xe; + s = ye - xe; xm = XDPSRS(xm, s); xe += s; } @@ -158,7 +156,7 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) xe = xe; xs = xs; - if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ + if (xm >> (DP_FBITS + 1 + 3)) { /* carry out */ xm = XDPSRS1(xm); /* shift preserving sticky */ xe++; } @@ -173,7 +171,7 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) xs = ys; } if (xm == 0) { - if (ieee754_csr.rm == IEEE754_RD) + if (ieee754_csr.rm == FPU_CSR_RD) return ieee754dp_zero(1); /* round negative inf. => sign = -1 */ else return ieee754dp_zero(0); /* other round modes => sign = 1 */ @@ -181,10 +179,11 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) /* normalize to rounding precision */ - while ((xm >> (DP_MBITS + 3)) == 0) { + while ((xm >> (DP_FBITS + 3)) == 0) { xm <<= 1; xe--; } } - DPNORMRET2(xs, xe, xm, "sub", x, y); + + return ieee754dp_format(xs, xe, xm); } diff --git a/arch/mips/math-emu/dp_tint.c b/arch/mips/math-emu/dp_tint.c index 0ebe8598b94ae6..6ffc336c530e3e 100644 --- a/arch/mips/math-emu/dp_tint.c +++ b/arch/mips/math-emu/dp_tint.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,20 +16,21 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - -#include #include "ieee754dp.h" -int ieee754dp_tint(ieee754dp x) +int ieee754dp_tint(union ieee754dp x) { + u64 residue; + int round; + int sticky; + int odd; + COMPXDP; - CLEARCX; + ieee754_clearcx(); EXPLODEXDP; FLUSHXDP; @@ -40,10 +39,12 @@ int ieee754dp_tint(ieee754dp x) case IEEE754_CLASS_SNAN: case IEEE754_CLASS_QNAN: case IEEE754_CLASS_INF: - SETCX(IEEE754_INVALID_OPERATION); - return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754si_indef(); + case IEEE754_CLASS_ZERO: return 0; + case IEEE754_CLASS_DNORM: case IEEE754_CLASS_NORM: break; @@ -51,44 +52,39 @@ int ieee754dp_tint(ieee754dp x) if (xe > 31) { /* Set invalid. We will only use overflow for floating point overflow */ - SETCX(IEEE754_INVALID_OPERATION); - return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754si_indef(); } /* oh gawd */ - if (xe > DP_MBITS) { - xm <<= xe - DP_MBITS; - } else if (xe < DP_MBITS) { - u64 residue; - int round; - int sticky; - int odd; - + if (xe > DP_FBITS) { + xm <<= xe - DP_FBITS; + } else if (xe < DP_FBITS) { if (xe < -1) { residue = xm; round = 0; sticky = residue != 0; xm = 0; } else { - residue = xm << (64 - DP_MBITS + xe); + residue = xm << (64 - DP_FBITS + xe); round = (residue >> 63) != 0; sticky = (residue << 1) != 0; - xm >>= DP_MBITS - xe; + xm >>= DP_FBITS - xe; } /* Note: At this point upper 32 bits of xm are guaranteed to be zero */ odd = (xm & 0x1) != 0x0; switch (ieee754_csr.rm) { - case IEEE754_RN: + case FPU_CSR_RN: if (round && (sticky || odd)) xm++; break; - case IEEE754_RZ: + case FPU_CSR_RZ: break; - case IEEE754_RU: /* toward +Infinity */ + case FPU_CSR_RU: /* toward +Infinity */ if ((round || sticky) && !xs) xm++; break; - case IEEE754_RD: /* toward -Infinity */ + case FPU_CSR_RD: /* toward -Infinity */ if ((round || sticky) && xs) xm++; break; @@ -96,27 +92,14 @@ int ieee754dp_tint(ieee754dp x) /* look for valid corner case 0x80000000 */ if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) { /* This can happen after rounding */ - SETCX(IEEE754_INVALID_OPERATION); - return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754si_indef(); } if (round || sticky) - SETCX(IEEE754_INEXACT); + ieee754_setcx(IEEE754_INEXACT); } if (xs) return -xm; else return xm; } - - -unsigned int ieee754dp_tuns(ieee754dp x) -{ - ieee754dp hb = ieee754dp_1e31(); - - /* what if x < 0 ?? */ - if (ieee754dp_lt(x, hb)) - return (unsigned) ieee754dp_tint(x); - - return (unsigned) ieee754dp_tint(ieee754dp_sub(x, hb)) | - ((unsigned) 1 << 31); -} diff --git a/arch/mips/math-emu/dp_tlong.c b/arch/mips/math-emu/dp_tlong.c index 133ce2ba0012eb..9cdc145b75e012 100644 --- a/arch/mips/math-emu/dp_tlong.c +++ b/arch/mips/math-emu/dp_tlong.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,19 +16,21 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754dp.h" -s64 ieee754dp_tlong(ieee754dp x) +s64 ieee754dp_tlong(union ieee754dp x) { + u64 residue; + int round; + int sticky; + int odd; + COMPXDP; - CLEARCX; + ieee754_clearcx(); EXPLODEXDP; FLUSHXDP; @@ -39,10 +39,12 @@ s64 ieee754dp_tlong(ieee754dp x) case IEEE754_CLASS_SNAN: case IEEE754_CLASS_QNAN: case IEEE754_CLASS_INF: - SETCX(IEEE754_INVALID_OPERATION); - return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754di_indef(); + case IEEE754_CLASS_ZERO: return 0; + case IEEE754_CLASS_DNORM: case IEEE754_CLASS_NORM: break; @@ -53,18 +55,13 @@ s64 ieee754dp_tlong(ieee754dp x) return -0x8000000000000000LL; /* Set invalid. We will only use overflow for floating point overflow */ - SETCX(IEEE754_INVALID_OPERATION); - return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754di_indef(); } /* oh gawd */ - if (xe > DP_MBITS) { - xm <<= xe - DP_MBITS; - } else if (xe < DP_MBITS) { - u64 residue; - int round; - int sticky; - int odd; - + if (xe > DP_FBITS) { + xm <<= xe - DP_FBITS; + } else if (xe < DP_FBITS) { if (xe < -1) { residue = xm; round = 0; @@ -75,51 +72,38 @@ s64 ieee754dp_tlong(ieee754dp x) * so we do it in two steps. Be aware that xe * may be -1 */ residue = xm << (xe + 1); - residue <<= 63 - DP_MBITS; + residue <<= 63 - DP_FBITS; round = (residue >> 63) != 0; sticky = (residue << 1) != 0; - xm >>= DP_MBITS - xe; + xm >>= DP_FBITS - xe; } odd = (xm & 0x1) != 0x0; switch (ieee754_csr.rm) { - case IEEE754_RN: + case FPU_CSR_RN: if (round && (sticky || odd)) xm++; break; - case IEEE754_RZ: + case FPU_CSR_RZ: break; - case IEEE754_RU: /* toward +Infinity */ + case FPU_CSR_RU: /* toward +Infinity */ if ((round || sticky) && !xs) xm++; break; - case IEEE754_RD: /* toward -Infinity */ + case FPU_CSR_RD: /* toward -Infinity */ if ((round || sticky) && xs) xm++; break; } if ((xm >> 63) != 0) { /* This can happen after rounding */ - SETCX(IEEE754_INVALID_OPERATION); - return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754di_indef(); } if (round || sticky) - SETCX(IEEE754_INEXACT); + ieee754_setcx(IEEE754_INEXACT); } if (xs) return -xm; else return xm; } - - -u64 ieee754dp_tulong(ieee754dp x) -{ - ieee754dp hb = ieee754dp_1e63(); - - /* what if x < 0 ?? */ - if (ieee754dp_lt(x, hb)) - return (u64) ieee754dp_tlong(x); - - return (u64) ieee754dp_tlong(ieee754dp_sub(x, hb)) | - (1ULL << 63); -} diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 7ea622ab8dad32..4f514f3724cb9e 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -1,30 +1,12 @@ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include #include -#include #include - #include +#include +#include +#include #include "ieee754.h" -/* Strap kernel emulator for full MIPS IV emulation */ - -#ifdef __mips -#undef __mips -#endif -#define __mips 4 - /* * Emulate the arbritrary instruction ir at xcp->cp0_epc. Required when * we have to emulate the instruction in a COP1 branch delay slot. Do @@ -59,13 +41,11 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) (ir == 0)) { /* NOP is easy */ regs->cp0_epc = cpc; - regs->cp0_cause &= ~CAUSEF_BD; + clear_delay_slot(regs); return 0; } -#ifdef DSEMUL_TRACE - printk("dsemul %lx %lx\n", regs->cp0_epc, cpc); -#endif + pr_debug("dsemul %lx %lx\n", regs->cp0_epc, cpc); /* * The strategy is to push the instruction onto the user stack @@ -167,9 +147,8 @@ int do_dsemulret(struct pt_regs *xcp) * emulating the branch delay instruction. */ -#ifdef DSEMUL_TRACE - printk("dsemulret\n"); -#endif + pr_debug("dsemulret\n"); + if (__get_user(epc, &fr->epc)) { /* Saved EPC */ /* This is not a good situation to be in */ force_sig(SIGBUS, current); diff --git a/arch/mips/math-emu/ieee754.c b/arch/mips/math-emu/ieee754.c index 0015cf1989dad3..53f1d228708409 100644 --- a/arch/mips/math-emu/ieee754.c +++ b/arch/mips/math-emu/ieee754.c @@ -10,8 +10,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -23,105 +21,69 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include -#include "ieee754int.h" +#include "ieee754.h" #include "ieee754sp.h" #include "ieee754dp.h" -#define DP_EBIAS 1023 -#define DP_EMIN (-1022) -#define DP_EMAX 1023 - -#define SP_EBIAS 127 -#define SP_EMIN (-126) -#define SP_EMAX 127 - -/* special constants -*/ - - -#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) -#define SPSTR(s, b, m) {m, b, s} -#define DPSTR(s, b, mh, ml) {ml, mh, b, s} -#endif - -#ifdef __MIPSEB__ -#define SPSTR(s, b, m) {s, b, m} -#define DPSTR(s, b, mh, ml) {s, b, mh, ml} -#endif +/* + * Special constants + */ -const struct ieee754dp_konst __ieee754dp_spcvals[] = { - DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* + zero */ - DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* - zero */ - DPSTR(0, DP_EBIAS, 0, 0), /* + 1.0 */ - DPSTR(1, DP_EBIAS, 0, 0), /* - 1.0 */ - DPSTR(0, 3 + DP_EBIAS, 0x40000, 0), /* + 10.0 */ - DPSTR(1, 3 + DP_EBIAS, 0x40000, 0), /* - 10.0 */ - DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* + infinity */ - DPSTR(1, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* - infinity */ - DPSTR(0, DP_EMAX+1+DP_EBIAS, 0x7FFFF, 0xFFFFFFFF), /* + indef quiet Nan */ - DPSTR(0, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* + max */ - DPSTR(1, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* - max */ - DPSTR(0, DP_EMIN + DP_EBIAS, 0, 0), /* + min normal */ - DPSTR(1, DP_EMIN + DP_EBIAS, 0, 0), /* - min normal */ - DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* + min denormal */ - DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* - min denormal */ - DPSTR(0, 31 + DP_EBIAS, 0, 0), /* + 1.0e31 */ - DPSTR(0, 63 + DP_EBIAS, 0, 0), /* + 1.0e63 */ -}; +#define DPCNST(s, b, m) \ +{ \ + .sign = (s), \ + .bexp = (b) + DP_EBIAS, \ + .mant = (m) \ +} -const struct ieee754sp_konst __ieee754sp_spcvals[] = { - SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 0), /* + zero */ - SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 0), /* - zero */ - SPSTR(0, SP_EBIAS, 0), /* + 1.0 */ - SPSTR(1, SP_EBIAS, 0), /* - 1.0 */ - SPSTR(0, 3 + SP_EBIAS, 0x200000), /* + 10.0 */ - SPSTR(1, 3 + SP_EBIAS, 0x200000), /* - 10.0 */ - SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0), /* + infinity */ - SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0), /* - infinity */ - SPSTR(0, SP_EMAX+1+SP_EBIAS, 0x3FFFFF), /* + indef quiet Nan */ - SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* + max normal */ - SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* - max normal */ - SPSTR(0, SP_EMIN + SP_EBIAS, 0), /* + min normal */ - SPSTR(1, SP_EMIN + SP_EBIAS, 0), /* - min normal */ - SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 1), /* + min denormal */ - SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 1), /* - min denormal */ - SPSTR(0, 31 + SP_EBIAS, 0), /* + 1.0e31 */ - SPSTR(0, 63 + SP_EBIAS, 0), /* + 1.0e63 */ +const union ieee754dp __ieee754dp_spcvals[] = { + DPCNST(0, DP_EMIN - 1, 0x0000000000000ULL), /* + zero */ + DPCNST(1, DP_EMIN - 1, 0x0000000000000ULL), /* - zero */ + DPCNST(0, 0, 0x0000000000000ULL), /* + 1.0 */ + DPCNST(1, 0, 0x0000000000000ULL), /* - 1.0 */ + DPCNST(0, 3, 0x4000000000000ULL), /* + 10.0 */ + DPCNST(1, 3, 0x4000000000000ULL), /* - 10.0 */ + DPCNST(0, DP_EMAX + 1, 0x0000000000000ULL), /* + infinity */ + DPCNST(1, DP_EMAX + 1, 0x0000000000000ULL), /* - infinity */ + DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL), /* + indef quiet Nan */ + DPCNST(0, DP_EMAX, 0xFFFFFFFFFFFFFULL), /* + max */ + DPCNST(1, DP_EMAX, 0xFFFFFFFFFFFFFULL), /* - max */ + DPCNST(0, DP_EMIN, 0x0000000000000ULL), /* + min normal */ + DPCNST(1, DP_EMIN, 0x0000000000000ULL), /* - min normal */ + DPCNST(0, DP_EMIN - 1, 0x0000000000001ULL), /* + min denormal */ + DPCNST(1, DP_EMIN - 1, 0x0000000000001ULL), /* - min denormal */ + DPCNST(0, 31, 0x0000000000000ULL), /* + 1.0e31 */ + DPCNST(0, 63, 0x0000000000000ULL), /* + 1.0e63 */ }; - -int ieee754si_xcpt(int r, const char *op, ...) -{ - struct ieee754xctx ax; - - if (!TSTX()) - return r; - ax.op = op; - ax.rt = IEEE754_RT_SI; - ax.rv.si = r; - va_start(ax.ap, op); - ieee754_xcpt(&ax); - va_end(ax.ap); - return ax.rv.si; +#define SPCNST(s, b, m) \ +{ \ + .sign = (s), \ + .bexp = (b) + SP_EBIAS, \ + .mant = (m) \ } -s64 ieee754di_xcpt(s64 r, const char *op, ...) -{ - struct ieee754xctx ax; - - if (!TSTX()) - return r; - ax.op = op; - ax.rt = IEEE754_RT_DI; - ax.rv.di = r; - va_start(ax.ap, op); - ieee754_xcpt(&ax); - va_end(ax.ap); - return ax.rv.di; -} +const union ieee754sp __ieee754sp_spcvals[] = { + SPCNST(0, SP_EMIN - 1, 0x000000), /* + zero */ + SPCNST(1, SP_EMIN - 1, 0x000000), /* - zero */ + SPCNST(0, 0, 0x000000), /* + 1.0 */ + SPCNST(1, 0, 0x000000), /* - 1.0 */ + SPCNST(0, 3, 0x200000), /* + 10.0 */ + SPCNST(1, 3, 0x200000), /* - 10.0 */ + SPCNST(0, SP_EMAX + 1, 0x000000), /* + infinity */ + SPCNST(1, SP_EMAX + 1, 0x000000), /* - infinity */ + SPCNST(0, SP_EMAX + 1, 0x3FFFFF), /* + indef quiet Nan */ + SPCNST(0, SP_EMAX, 0x7FFFFF), /* + max normal */ + SPCNST(1, SP_EMAX, 0x7FFFFF), /* - max normal */ + SPCNST(0, SP_EMIN, 0x000000), /* + min normal */ + SPCNST(1, SP_EMIN, 0x000000), /* - min normal */ + SPCNST(0, SP_EMIN - 1, 0x000001), /* + min denormal */ + SPCNST(1, SP_EMIN - 1, 0x000001), /* - min denormal */ + SPCNST(0, 31, 0x000000), /* + 1.0e31 */ + SPCNST(0, 63, 0x000000), /* + 1.0e63 */ +}; diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index 22796e01206071..43c4fb522ac2d4 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -13,7 +13,7 @@ * * 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. + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Nov 7, 2000 * Modification to allow integration with Linux kernel @@ -24,186 +24,93 @@ #ifndef __ARCH_MIPS_MATH_EMU_IEEE754_H #define __ARCH_MIPS_MATH_EMU_IEEE754_H +#include #include +#include #include #include +#include -/* - * Not very pretty, but the Linux kernel's normal va_list definition - * does not allow it to be used as a structure element, as it is here. - */ -#ifndef _STDARG_H -#include -#endif - -#ifdef __LITTLE_ENDIAN -struct ieee754dp_konst { - unsigned mantlo:32; - unsigned manthi:20; - unsigned bexp:11; - unsigned sign:1; -}; -struct ieee754sp_konst { - unsigned mant:23; - unsigned bexp:8; - unsigned sign:1; -}; - -typedef union _ieee754dp { - struct ieee754dp_konst oparts; +union ieee754dp { struct { - u64 mant:52; - unsigned int bexp:11; - unsigned int sign:1; - } parts; + __BITFIELD_FIELD(unsigned int sign:1, + __BITFIELD_FIELD(unsigned int bexp:11, + __BITFIELD_FIELD(u64 mant:52, + ;))) + }; u64 bits; - double d; -} ieee754dp; - -typedef union _ieee754sp { - struct ieee754sp_konst parts; - float f; - u32 bits; -} ieee754sp; -#endif - -#ifdef __BIG_ENDIAN -struct ieee754dp_konst { - unsigned sign:1; - unsigned bexp:11; - unsigned manthi:20; - unsigned mantlo:32; }; -typedef union _ieee754dp { - struct ieee754dp_konst oparts; +union ieee754sp { struct { - unsigned int sign:1; - unsigned int bexp:11; - u64 mant:52; - } parts; - double d; - u64 bits; -} ieee754dp; - -struct ieee754sp_konst { - unsigned sign:1; - unsigned bexp:8; - unsigned mant:23; -}; - -typedef union _ieee754sp { - struct ieee754sp_konst parts; - float f; + __BITFIELD_FIELD(unsigned sign:1, + __BITFIELD_FIELD(unsigned bexp:8, + __BITFIELD_FIELD(unsigned mant:23, + ;))) + }; u32 bits; -} ieee754sp; -#endif +}; /* * single precision (often aka float) */ -int ieee754sp_finite(ieee754sp x); -int ieee754sp_class(ieee754sp x); - -ieee754sp ieee754sp_abs(ieee754sp x); -ieee754sp ieee754sp_neg(ieee754sp x); -ieee754sp ieee754sp_scalb(ieee754sp x, int); -ieee754sp ieee754sp_logb(ieee754sp x); - -/* x with sign of y */ -ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y); - -ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y); -ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y); -ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y); -ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y); - -ieee754sp ieee754sp_fint(int x); -ieee754sp ieee754sp_funs(unsigned x); -ieee754sp ieee754sp_flong(s64 x); -ieee754sp ieee754sp_fulong(u64 x); -ieee754sp ieee754sp_fdp(ieee754dp x); - -int ieee754sp_tint(ieee754sp x); -unsigned int ieee754sp_tuns(ieee754sp x); -s64 ieee754sp_tlong(ieee754sp x); -u64 ieee754sp_tulong(ieee754sp x); - -int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop, int sig); -/* - * basic sp math - */ -ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip); -ieee754sp ieee754sp_frexp(ieee754sp x, int *exp); -ieee754sp ieee754sp_ldexp(ieee754sp x, int exp); +int ieee754sp_class(union ieee754sp x); -ieee754sp ieee754sp_ceil(ieee754sp x); -ieee754sp ieee754sp_floor(ieee754sp x); -ieee754sp ieee754sp_trunc(ieee754sp x); +union ieee754sp ieee754sp_abs(union ieee754sp x); +union ieee754sp ieee754sp_neg(union ieee754sp x); -ieee754sp ieee754sp_sqrt(ieee754sp x); +union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y); +union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y); +union ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y); +union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y); -/* - * double precision (often aka double) -*/ -int ieee754dp_finite(ieee754dp x); -int ieee754dp_class(ieee754dp x); +union ieee754sp ieee754sp_fint(int x); +union ieee754sp ieee754sp_flong(s64 x); +union ieee754sp ieee754sp_fdp(union ieee754dp x); -/* x with sign of y */ -ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y); +int ieee754sp_tint(union ieee754sp x); +s64 ieee754sp_tlong(union ieee754sp x); -ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y); -ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y); -ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y); -ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y); +int ieee754sp_cmp(union ieee754sp x, union ieee754sp y, int cop, int sig); -ieee754dp ieee754dp_abs(ieee754dp x); -ieee754dp ieee754dp_neg(ieee754dp x); -ieee754dp ieee754dp_scalb(ieee754dp x, int); +union ieee754sp ieee754sp_sqrt(union ieee754sp x); -/* return exponent as integer in floating point format - */ -ieee754dp ieee754dp_logb(ieee754dp x); +/* + * double precision (often aka double) +*/ +int ieee754dp_class(union ieee754dp x); -ieee754dp ieee754dp_fint(int x); -ieee754dp ieee754dp_funs(unsigned x); -ieee754dp ieee754dp_flong(s64 x); -ieee754dp ieee754dp_fulong(u64 x); -ieee754dp ieee754dp_fsp(ieee754sp x); +union ieee754dp ieee754dp_add(union ieee754dp x, union ieee754dp y); +union ieee754dp ieee754dp_sub(union ieee754dp x, union ieee754dp y); +union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y); +union ieee754dp ieee754dp_div(union ieee754dp x, union ieee754dp y); -ieee754dp ieee754dp_ceil(ieee754dp x); -ieee754dp ieee754dp_floor(ieee754dp x); -ieee754dp ieee754dp_trunc(ieee754dp x); +union ieee754dp ieee754dp_abs(union ieee754dp x); +union ieee754dp ieee754dp_neg(union ieee754dp x); -int ieee754dp_tint(ieee754dp x); -unsigned int ieee754dp_tuns(ieee754dp x); -s64 ieee754dp_tlong(ieee754dp x); -u64 ieee754dp_tulong(ieee754dp x); +union ieee754dp ieee754dp_fint(int x); +union ieee754dp ieee754dp_flong(s64 x); +union ieee754dp ieee754dp_fsp(union ieee754sp x); -int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop, int sig); -/* - * basic sp math - */ -ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip); -ieee754dp ieee754dp_frexp(ieee754dp x, int *exp); -ieee754dp ieee754dp_ldexp(ieee754dp x, int exp); +int ieee754dp_tint(union ieee754dp x); +s64 ieee754dp_tlong(union ieee754dp x); -ieee754dp ieee754dp_ceil(ieee754dp x); -ieee754dp ieee754dp_floor(ieee754dp x); -ieee754dp ieee754dp_trunc(ieee754dp x); +int ieee754dp_cmp(union ieee754dp x, union ieee754dp y, int cop, int sig); -ieee754dp ieee754dp_sqrt(ieee754dp x); +union ieee754dp ieee754dp_sqrt(union ieee754dp x); /* 5 types of floating point number */ -#define IEEE754_CLASS_NORM 0x00 -#define IEEE754_CLASS_ZERO 0x01 -#define IEEE754_CLASS_DNORM 0x02 -#define IEEE754_CLASS_INF 0x03 -#define IEEE754_CLASS_SNAN 0x04 -#define IEEE754_CLASS_QNAN 0x05 +enum { + IEEE754_CLASS_NORM = 0x00, + IEEE754_CLASS_ZERO = 0x01, + IEEE754_CLASS_DNORM = 0x02, + IEEE754_CLASS_INF = 0x03, + IEEE754_CLASS_SNAN = 0x04, + IEEE754_CLASS_QNAN = 0x05, +}; /* exception numbers */ #define IEEE754_INEXACT 0x01 @@ -219,114 +126,84 @@ ieee754dp ieee754dp_sqrt(ieee754dp x); #define IEEE754_CGT 0x04 #define IEEE754_CUN 0x08 -/* rounding mode -*/ -#define IEEE754_RN 0 /* round to nearest */ -#define IEEE754_RZ 1 /* round toward zero */ -#define IEEE754_RD 2 /* round toward -Infinity */ -#define IEEE754_RU 3 /* round toward +Infinity */ - -/* other naming */ -#define IEEE754_RM IEEE754_RD -#define IEEE754_RP IEEE754_RU - /* "normal" comparisons */ -static inline int ieee754sp_eq(ieee754sp x, ieee754sp y) +static inline int ieee754sp_eq(union ieee754sp x, union ieee754sp y) { return ieee754sp_cmp(x, y, IEEE754_CEQ, 0); } -static inline int ieee754sp_ne(ieee754sp x, ieee754sp y) +static inline int ieee754sp_ne(union ieee754sp x, union ieee754sp y) { return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0); } -static inline int ieee754sp_lt(ieee754sp x, ieee754sp y) +static inline int ieee754sp_lt(union ieee754sp x, union ieee754sp y) { return ieee754sp_cmp(x, y, IEEE754_CLT, 0); } -static inline int ieee754sp_le(ieee754sp x, ieee754sp y) +static inline int ieee754sp_le(union ieee754sp x, union ieee754sp y) { return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0); } -static inline int ieee754sp_gt(ieee754sp x, ieee754sp y) +static inline int ieee754sp_gt(union ieee754sp x, union ieee754sp y) { return ieee754sp_cmp(x, y, IEEE754_CGT, 0); } -static inline int ieee754sp_ge(ieee754sp x, ieee754sp y) +static inline int ieee754sp_ge(union ieee754sp x, union ieee754sp y) { return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0); } -static inline int ieee754dp_eq(ieee754dp x, ieee754dp y) +static inline int ieee754dp_eq(union ieee754dp x, union ieee754dp y) { return ieee754dp_cmp(x, y, IEEE754_CEQ, 0); } -static inline int ieee754dp_ne(ieee754dp x, ieee754dp y) +static inline int ieee754dp_ne(union ieee754dp x, union ieee754dp y) { return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0); } -static inline int ieee754dp_lt(ieee754dp x, ieee754dp y) +static inline int ieee754dp_lt(union ieee754dp x, union ieee754dp y) { return ieee754dp_cmp(x, y, IEEE754_CLT, 0); } -static inline int ieee754dp_le(ieee754dp x, ieee754dp y) +static inline int ieee754dp_le(union ieee754dp x, union ieee754dp y) { return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0); } -static inline int ieee754dp_gt(ieee754dp x, ieee754dp y) +static inline int ieee754dp_gt(union ieee754dp x, union ieee754dp y) { return ieee754dp_cmp(x, y, IEEE754_CGT, 0); } -static inline int ieee754dp_ge(ieee754dp x, ieee754dp y) +static inline int ieee754dp_ge(union ieee754dp x, union ieee754dp y) { return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0); } - -/* - * Like strtod - */ -ieee754dp ieee754dp_fstr(const char *s, char **endp); -char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af); - - /* * The control status register */ struct _ieee754_csr { -#ifdef __BIG_ENDIAN - unsigned pad0:7; - unsigned nod:1; /* set 1 for no denormalised numbers */ - unsigned c:1; /* condition */ - unsigned pad1:5; - unsigned cx:6; /* exceptions this operation */ - unsigned mx:5; /* exception enable mask */ - unsigned sx:5; /* exceptions total */ - unsigned rm:2; /* current rounding mode */ -#endif -#ifdef __LITTLE_ENDIAN - unsigned rm:2; /* current rounding mode */ - unsigned sx:5; /* exceptions total */ - unsigned mx:5; /* exception enable mask */ - unsigned cx:6; /* exceptions this operation */ - unsigned pad1:5; - unsigned c:1; /* condition */ - unsigned nod:1; /* set 1 for no denormalised numbers */ - unsigned pad0:7; -#endif + __BITFIELD_FIELD(unsigned pad0:7, + __BITFIELD_FIELD(unsigned nod:1, /* set 1 for no denormalised numbers */ + __BITFIELD_FIELD(unsigned c:1, /* condition */ + __BITFIELD_FIELD(unsigned pad1:5, + __BITFIELD_FIELD(unsigned cx:6, /* exceptions this operation */ + __BITFIELD_FIELD(unsigned mx:5, /* exception enable mask */ + __BITFIELD_FIELD(unsigned sx:5, /* exceptions total */ + __BITFIELD_FIELD(unsigned rm:2, /* current rounding mode */ + ;)))))))) }; #define ieee754_csr (*(struct _ieee754_csr *)(¤t->thread.fpu.fcr31)) @@ -377,8 +254,8 @@ static inline int ieee754_sxtest(unsigned n) } /* debugging */ -ieee754sp ieee754sp_dump(char *s, ieee754sp x); -ieee754dp ieee754dp_dump(char *s, ieee754dp x); +union ieee754sp ieee754sp_dump(char *s, union ieee754sp x); +union ieee754dp ieee754dp_dump(char *s, union ieee754dp x); #define IEEE754_SPCVAL_PZERO 0 #define IEEE754_SPCVAL_NZERO 1 @@ -398,10 +275,10 @@ ieee754dp ieee754dp_dump(char *s, ieee754dp x); #define IEEE754_SPCVAL_P1E31 15 /* + 1.0e31 */ #define IEEE754_SPCVAL_P1E63 16 /* + 1.0e63 */ -extern const struct ieee754dp_konst __ieee754dp_spcvals[]; -extern const struct ieee754sp_konst __ieee754sp_spcvals[]; -#define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals) -#define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals) +extern const union ieee754dp __ieee754dp_spcvals[]; +extern const union ieee754sp __ieee754sp_spcvals[]; +#define ieee754dp_spcvals ((const union ieee754dp *)__ieee754dp_spcvals) +#define ieee754sp_spcvals ((const union ieee754sp *)__ieee754sp_spcvals) /* * Return infinity with given sign @@ -431,28 +308,15 @@ extern const struct ieee754sp_konst __ieee754sp_spcvals[]; /* * Indefinite integer value */ -#define ieee754si_indef() INT_MAX -#ifdef LONG_LONG_MAX -#define ieee754di_indef() LONG_LONG_MAX -#else -#define ieee754di_indef() ((s64)(~0ULL>>1)) -#endif - -/* IEEE exception context, passed to handler */ -struct ieee754xctx { - const char *op; /* operation name */ - int rt; /* result type */ - union { - ieee754sp sp; /* single precision */ - ieee754dp dp; /* double precision */ -#ifdef IEEE854_XP - ieee754xp xp; /* extended precision */ -#endif - int si; /* standard signed integer (32bits) */ - s64 di; /* extended signed integer (64bits) */ - } rv; /* default result format implied by op */ - va_list ap; -}; +static inline int ieee754si_indef(void) +{ + return INT_MAX; +} + +static inline s64 ieee754di_indef(void) +{ + return S64_MAX; +} /* result types for xctx.rt */ #define IEEE754_RT_SP 0 @@ -461,8 +325,6 @@ struct ieee754xctx { #define IEEE754_RT_SI 3 #define IEEE754_RT_DI 4 -extern void ieee754_xcpt(struct ieee754xctx *xcp); - /* compat */ #define ieee754dp_fix(x) ieee754dp_tint(x) #define ieee754sp_fix(x) ieee754sp_tint(x) diff --git a/arch/mips/math-emu/ieee754d.c b/arch/mips/math-emu/ieee754d.c index 9599bdd32585c2..a04e8a7e5ac37b 100644 --- a/arch/mips/math-emu/ieee754d.c +++ b/arch/mips/math-emu/ieee754d.c @@ -16,7 +16,7 @@ * * 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. + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Nov 7, 2000 * Modified to build and operate in Linux kernel environment. @@ -25,38 +25,13 @@ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. */ -#include +#include +#include #include "ieee754.h" +#include "ieee754sp.h" +#include "ieee754dp.h" -#define DP_EBIAS 1023 -#define DP_EMIN (-1022) -#define DP_EMAX 1023 -#define DP_FBITS 52 - -#define SP_EBIAS 127 -#define SP_EMIN (-126) -#define SP_EMAX 127 -#define SP_FBITS 23 - -#define DP_MBIT(x) ((u64)1 << (x)) -#define DP_HIDDEN_BIT DP_MBIT(DP_FBITS) -#define DP_SIGN_BIT DP_MBIT(63) - - -#define SP_MBIT(x) ((u32)1 << (x)) -#define SP_HIDDEN_BIT SP_MBIT(SP_FBITS) -#define SP_SIGN_BIT SP_MBIT(31) - - -#define SPSIGN(sp) (sp.parts.sign) -#define SPBEXP(sp) (sp.parts.bexp) -#define SPMANT(sp) (sp.parts.mant) - -#define DPSIGN(dp) (dp.parts.sign) -#define DPBEXP(dp) (dp.parts.bexp) -#define DPMANT(dp) (dp.parts.mant) - -ieee754dp ieee754dp_dump(char *m, ieee754dp x) +union ieee754dp ieee754dp_dump(char *m, union ieee754dp x) { int i; @@ -96,7 +71,7 @@ ieee754dp ieee754dp_dump(char *m, ieee754dp x) return x; } -ieee754sp ieee754sp_dump(char *m, ieee754sp x) +union ieee754sp ieee754sp_dump(char *m, union ieee754sp x) { int i; diff --git a/arch/mips/math-emu/ieee754dp.c b/arch/mips/math-emu/ieee754dp.c index 068e56be8de912..fd134675fc2e84 100644 --- a/arch/mips/math-emu/ieee754dp.c +++ b/arch/mips/math-emu/ieee754dp.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,104 +16,68 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include "ieee754dp.h" -int ieee754dp_class(ieee754dp x) +int ieee754dp_class(union ieee754dp x) { COMPXDP; EXPLODEXDP; return xc; } -int ieee754dp_isnan(ieee754dp x) +int ieee754dp_isnan(union ieee754dp x) { return ieee754dp_class(x) >= IEEE754_CLASS_SNAN; } -int ieee754dp_issnan(ieee754dp x) +static inline int ieee754dp_issnan(union ieee754dp x) { assert(ieee754dp_isnan(x)); - return ((DPMANT(x) & DP_MBIT(DP_MBITS-1)) == DP_MBIT(DP_MBITS-1)); + return ((DPMANT(x) & DP_MBIT(DP_FBITS-1)) == DP_MBIT(DP_FBITS-1)); } -ieee754dp ieee754dp_xcpt(ieee754dp r, const char *op, ...) -{ - struct ieee754xctx ax; - if (!TSTX()) - return r; - - ax.op = op; - ax.rt = IEEE754_RT_DP; - ax.rv.dp = r; - va_start(ax.ap, op); - ieee754_xcpt(&ax); - va_end(ax.ap); - return ax.rv.dp; -} - -ieee754dp ieee754dp_nanxcpt(ieee754dp r, const char *op, ...) +union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r) { - struct ieee754xctx ax; - assert(ieee754dp_isnan(r)); if (!ieee754dp_issnan(r)) /* QNAN does not cause invalid op !! */ return r; - if (!SETANDTESTCX(IEEE754_INVALID_OPERATION)) { + if (!ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) { /* not enabled convert to a quiet NaN */ - DPMANT(r) &= (~DP_MBIT(DP_MBITS-1)); + DPMANT(r) &= (~DP_MBIT(DP_FBITS-1)); if (ieee754dp_isnan(r)) return r; else return ieee754dp_indef(); } - ax.op = op; - ax.rt = 0; - ax.rv.dp = r; - va_start(ax.ap, op); - ieee754_xcpt(&ax); - va_end(ax.ap); - return ax.rv.dp; + return r; } -ieee754dp ieee754dp_bestnan(ieee754dp x, ieee754dp y) -{ - assert(ieee754dp_isnan(x)); - assert(ieee754dp_isnan(y)); - - if (DPMANT(x) > DPMANT(y)) - return x; - else - return y; -} - - -static u64 get_rounding(int sn, u64 xm) +static u64 ieee754dp_get_rounding(int sn, u64 xm) { /* inexact must round of 3 bits */ if (xm & (DP_MBIT(3) - 1)) { switch (ieee754_csr.rm) { - case IEEE754_RZ: + case FPU_CSR_RZ: break; - case IEEE754_RN: + case FPU_CSR_RN: xm += 0x3 + ((xm >> 3) & 1); /* xm += (xm&0x8)?0x4:0x3 */ break; - case IEEE754_RU: /* toward +Infinity */ + case FPU_CSR_RU: /* toward +Infinity */ if (!sn) /* ?? */ xm += 0x8; break; - case IEEE754_RD: /* toward -Infinity */ + case FPU_CSR_RD: /* toward -Infinity */ if (sn) /* ?? */ xm += 0x8; break; @@ -130,11 +92,11 @@ static u64 get_rounding(int sn, u64 xm) * xe is an unbiased exponent * xm is 3bit extended precision value. */ -ieee754dp ieee754dp_format(int sn, int xe, u64 xm) +union ieee754dp ieee754dp_format(int sn, int xe, u64 xm) { assert(xm); /* we don't gen exact zeros (probably should) */ - assert((xm >> (DP_MBITS + 1 + 3)) == 0); /* no execess */ + assert((xm >> (DP_FBITS + 1 + 3)) == 0); /* no execess */ assert(xm & (DP_HIDDEN_BIT << 3)); if (xe < DP_EMIN) { @@ -142,32 +104,32 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm) int es = DP_EMIN - xe; if (ieee754_csr.nod) { - SETCX(IEEE754_UNDERFLOW); - SETCX(IEEE754_INEXACT); + ieee754_setcx(IEEE754_UNDERFLOW); + ieee754_setcx(IEEE754_INEXACT); switch(ieee754_csr.rm) { - case IEEE754_RN: - case IEEE754_RZ: + case FPU_CSR_RN: + case FPU_CSR_RZ: return ieee754dp_zero(sn); - case IEEE754_RU: /* toward +Infinity */ - if(sn == 0) + case FPU_CSR_RU: /* toward +Infinity */ + if (sn == 0) return ieee754dp_min(0); else return ieee754dp_zero(1); - case IEEE754_RD: /* toward -Infinity */ - if(sn == 0) + case FPU_CSR_RD: /* toward -Infinity */ + if (sn == 0) return ieee754dp_zero(0); else return ieee754dp_min(1); } } - if (xe == DP_EMIN - 1 - && get_rounding(sn, xm) >> (DP_MBITS + 1 + 3)) + if (xe == DP_EMIN - 1 && + ieee754dp_get_rounding(sn, xm) >> (DP_FBITS + 1 + 3)) { /* Not tiny after rounding */ - SETCX(IEEE754_INEXACT); - xm = get_rounding(sn, xm); + ieee754_setcx(IEEE754_INEXACT); + xm = ieee754dp_get_rounding(sn, xm); xm >>= 1; /* Clear grs bits */ xm &= ~(DP_MBIT(3) - 1); @@ -183,17 +145,17 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm) } } if (xm & (DP_MBIT(3) - 1)) { - SETCX(IEEE754_INEXACT); + ieee754_setcx(IEEE754_INEXACT); if ((xm & (DP_HIDDEN_BIT << 3)) == 0) { - SETCX(IEEE754_UNDERFLOW); + ieee754_setcx(IEEE754_UNDERFLOW); } /* inexact must round of 3 bits */ - xm = get_rounding(sn, xm); + xm = ieee754dp_get_rounding(sn, xm); /* adjust exponent for rounding add overflowing */ - if (xm >> (DP_MBITS + 3 + 1)) { + if (xm >> (DP_FBITS + 3 + 1)) { /* add causes mantissa overflow */ xm >>= 1; xe++; @@ -202,24 +164,24 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm) /* strip grs bits */ xm >>= 3; - assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ + assert((xm >> (DP_FBITS + 1)) == 0); /* no execess */ assert(xe >= DP_EMIN); if (xe > DP_EMAX) { - SETCX(IEEE754_OVERFLOW); - SETCX(IEEE754_INEXACT); + ieee754_setcx(IEEE754_OVERFLOW); + ieee754_setcx(IEEE754_INEXACT); /* -O can be table indexed by (rm,sn) */ switch (ieee754_csr.rm) { - case IEEE754_RN: + case FPU_CSR_RN: return ieee754dp_inf(sn); - case IEEE754_RZ: + case FPU_CSR_RZ: return ieee754dp_max(sn); - case IEEE754_RU: /* toward +Infinity */ + case FPU_CSR_RU: /* toward +Infinity */ if (sn == 0) return ieee754dp_inf(0); else return ieee754dp_max(1); - case IEEE754_RD: /* toward -Infinity */ + case FPU_CSR_RD: /* toward -Infinity */ if (sn == 0) return ieee754dp_max(0); else @@ -232,10 +194,10 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm) /* we underflow (tiny/zero) */ assert(xe == DP_EMIN); if (ieee754_csr.mx & IEEE754_UNDERFLOW) - SETCX(IEEE754_UNDERFLOW); + ieee754_setcx(IEEE754_UNDERFLOW); return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm); } else { - assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ + assert((xm >> (DP_FBITS + 1)) == 0); /* no execess */ assert(xm & DP_HIDDEN_BIT); return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); diff --git a/arch/mips/math-emu/ieee754dp.h b/arch/mips/math-emu/ieee754dp.h index f139c724c59afd..61fd6fd31350f6 100644 --- a/arch/mips/math-emu/ieee754dp.h +++ b/arch/mips/math-emu/ieee754dp.h @@ -6,8 +6,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -19,64 +17,66 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include "ieee754int.h" #define assert(expr) ((void)0) +#define DP_EBIAS 1023 +#define DP_EMIN (-1022) +#define DP_EMAX 1023 +#define DP_FBITS 52 +#define DP_MBITS 52 + +#define DP_MBIT(x) ((u64)1 << (x)) +#define DP_HIDDEN_BIT DP_MBIT(DP_FBITS) +#define DP_SIGN_BIT DP_MBIT(63) + +#define DPSIGN(dp) (dp.sign) +#define DPBEXP(dp) (dp.bexp) +#define DPMANT(dp) (dp.mant) + +static inline int ieee754dp_finite(union ieee754dp x) +{ + return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS; +} + /* 3bit extended double precision sticky right shift */ #define XDPSRS(v,rs) \ - ((rs > (DP_MBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0)) + ((rs > (DP_FBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0)) #define XDPSRSX1() \ - (xe++, (xm = (xm >> 1) | (xm & 1))) + (xe++, (xm = (xm >> 1) | (xm & 1))) #define XDPSRS1(v) \ - (((v) >> 1) | ((v) & 1)) + (((v) >> 1) | ((v) & 1)) /* convert denormal to normalized with extended exponent */ #define DPDNORMx(m,e) \ - while( (m >> DP_MBITS) == 0) { m <<= 1; e--; } + while ((m >> DP_FBITS) == 0) { m <<= 1; e--; } #define DPDNORMX DPDNORMx(xm, xe) #define DPDNORMY DPDNORMx(ym, ye) -static inline ieee754dp builddp(int s, int bx, u64 m) +static inline union ieee754dp builddp(int s, int bx, u64 m) { - ieee754dp r; + union ieee754dp r; assert((s) == 0 || (s) == 1); assert((bx) >= DP_EMIN - 1 + DP_EBIAS && (bx) <= DP_EMAX + 1 + DP_EBIAS); - assert(((m) >> DP_MBITS) == 0); + assert(((m) >> DP_FBITS) == 0); - r.parts.sign = s; - r.parts.bexp = bx; - r.parts.mant = m; - return r; -} + r.sign = s; + r.bexp = bx; + r.mant = m; -extern int ieee754dp_isnan(ieee754dp); -extern int ieee754dp_issnan(ieee754dp); -extern int ieee754si_xcpt(int, const char *, ...); -extern s64 ieee754di_xcpt(s64, const char *, ...); -extern ieee754dp ieee754dp_xcpt(ieee754dp, const char *, ...); -extern ieee754dp ieee754dp_nanxcpt(ieee754dp, const char *, ...); -extern ieee754dp ieee754dp_bestnan(ieee754dp, ieee754dp); -extern ieee754dp ieee754dp_format(int, int, u64); - - -#define DPNORMRET2(s, e, m, name, a0, a1) \ -{ \ - ieee754dp V = ieee754dp_format(s, e, m); \ - if(TSTX()) \ - return ieee754dp_xcpt(V, name, a0, a1); \ - else \ - return V; \ + return r; } -#define DPNORMRET1(s, e, m, name, a0) DPNORMRET2(s, e, m, name, a0, a0) +extern int ieee754dp_isnan(union ieee754dp); +extern union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp); +extern union ieee754dp ieee754dp_format(int, int, u64); diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h index 4b6c6fb353047e..f0365bb86747db 100644 --- a/arch/mips/math-emu/ieee754int.h +++ b/arch/mips/math-emu/ieee754int.h @@ -6,8 +6,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -19,146 +17,125 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - +#ifndef __IEEE754INT_H +#define __IEEE754INT_H #include "ieee754.h" -#define DP_EBIAS 1023 -#define DP_EMIN (-1022) -#define DP_EMAX 1023 -#define DP_MBITS 52 - -#define SP_EBIAS 127 -#define SP_EMIN (-126) -#define SP_EMAX 127 -#define SP_MBITS 23 - -#define DP_MBIT(x) ((u64)1 << (x)) -#define DP_HIDDEN_BIT DP_MBIT(DP_MBITS) -#define DP_SIGN_BIT DP_MBIT(63) - -#define SP_MBIT(x) ((u32)1 << (x)) -#define SP_HIDDEN_BIT SP_MBIT(SP_MBITS) -#define SP_SIGN_BIT SP_MBIT(31) - - -#define SPSIGN(sp) (sp.parts.sign) -#define SPBEXP(sp) (sp.parts.bexp) -#define SPMANT(sp) (sp.parts.mant) - -#define DPSIGN(dp) (dp.parts.sign) -#define DPBEXP(dp) (dp.parts.bexp) -#define DPMANT(dp) (dp.parts.mant) - #define CLPAIR(x, y) ((x)*6+(y)) -#define CLEARCX \ - (ieee754_csr.cx = 0) - -#define SETCX(x) \ - (ieee754_csr.cx |= (x), ieee754_csr.sx |= (x)) +static inline void ieee754_clearcx(void) +{ + ieee754_csr.cx = 0; +} -#define SETANDTESTCX(x) \ - (SETCX(x), ieee754_csr.mx & (x)) +static inline void ieee754_setcx(const unsigned int flags) +{ + ieee754_csr.cx |= flags; + ieee754_csr.sx |= flags; +} -#define TSTX() \ - (ieee754_csr.cx & ieee754_csr.mx) +static inline int ieee754_setandtestcx(const unsigned int x) +{ + ieee754_setcx(x); + return ieee754_csr.mx & x; +} #define COMPXSP \ - unsigned xm; int xe; int xs __maybe_unused; int xc + unsigned xm; int xe; int xs __maybe_unused; int xc #define COMPYSP \ - unsigned ym; int ye; int ys; int yc - -#define EXPLODESP(v, vc, vs, ve, vm) \ -{\ - vs = SPSIGN(v);\ - ve = SPBEXP(v);\ - vm = SPMANT(v);\ - if(ve == SP_EMAX+1+SP_EBIAS){\ - if(vm == 0)\ - vc = IEEE754_CLASS_INF;\ - else if(vm & SP_MBIT(SP_MBITS-1)) \ - vc = IEEE754_CLASS_SNAN;\ - else \ - vc = IEEE754_CLASS_QNAN;\ - } else if(ve == SP_EMIN-1+SP_EBIAS) {\ - if(vm) {\ - ve = SP_EMIN;\ - vc = IEEE754_CLASS_DNORM;\ - } else\ - vc = IEEE754_CLASS_ZERO;\ - } else {\ - ve -= SP_EBIAS;\ - vm |= SP_HIDDEN_BIT;\ - vc = IEEE754_CLASS_NORM;\ - }\ + unsigned ym; int ye; int ys; int yc + +#define EXPLODESP(v, vc, vs, ve, vm) \ +{ \ + vs = SPSIGN(v); \ + ve = SPBEXP(v); \ + vm = SPMANT(v); \ + if (ve == SP_EMAX+1+SP_EBIAS) { \ + if (vm == 0) \ + vc = IEEE754_CLASS_INF; \ + else if (vm & SP_MBIT(SP_FBITS-1)) \ + vc = IEEE754_CLASS_SNAN; \ + else \ + vc = IEEE754_CLASS_QNAN; \ + } else if (ve == SP_EMIN-1+SP_EBIAS) { \ + if (vm) { \ + ve = SP_EMIN; \ + vc = IEEE754_CLASS_DNORM; \ + } else \ + vc = IEEE754_CLASS_ZERO; \ + } else { \ + ve -= SP_EBIAS; \ + vm |= SP_HIDDEN_BIT; \ + vc = IEEE754_CLASS_NORM; \ + } \ } #define EXPLODEXSP EXPLODESP(x, xc, xs, xe, xm) #define EXPLODEYSP EXPLODESP(y, yc, ys, ye, ym) #define COMPXDP \ -u64 xm; int xe; int xs __maybe_unused; int xc + u64 xm; int xe; int xs __maybe_unused; int xc #define COMPYDP \ -u64 ym; int ye; int ys; int yc - -#define EXPLODEDP(v, vc, vs, ve, vm) \ -{\ - vm = DPMANT(v);\ - vs = DPSIGN(v);\ - ve = DPBEXP(v);\ - if(ve == DP_EMAX+1+DP_EBIAS){\ - if(vm == 0)\ - vc = IEEE754_CLASS_INF;\ - else if(vm & DP_MBIT(DP_MBITS-1)) \ - vc = IEEE754_CLASS_SNAN;\ - else \ - vc = IEEE754_CLASS_QNAN;\ - } else if(ve == DP_EMIN-1+DP_EBIAS) {\ - if(vm) {\ - ve = DP_EMIN;\ - vc = IEEE754_CLASS_DNORM;\ - } else\ - vc = IEEE754_CLASS_ZERO;\ - } else {\ - ve -= DP_EBIAS;\ - vm |= DP_HIDDEN_BIT;\ - vc = IEEE754_CLASS_NORM;\ - }\ + u64 ym; int ye; int ys; int yc + +#define EXPLODEDP(v, vc, vs, ve, vm) \ +{ \ + vm = DPMANT(v); \ + vs = DPSIGN(v); \ + ve = DPBEXP(v); \ + if (ve == DP_EMAX+1+DP_EBIAS) { \ + if (vm == 0) \ + vc = IEEE754_CLASS_INF; \ + else if (vm & DP_MBIT(DP_FBITS-1)) \ + vc = IEEE754_CLASS_SNAN; \ + else \ + vc = IEEE754_CLASS_QNAN; \ + } else if (ve == DP_EMIN-1+DP_EBIAS) { \ + if (vm) { \ + ve = DP_EMIN; \ + vc = IEEE754_CLASS_DNORM; \ + } else \ + vc = IEEE754_CLASS_ZERO; \ + } else { \ + ve -= DP_EBIAS; \ + vm |= DP_HIDDEN_BIT; \ + vc = IEEE754_CLASS_NORM; \ + } \ } #define EXPLODEXDP EXPLODEDP(x, xc, xs, xe, xm) #define EXPLODEYDP EXPLODEDP(y, yc, ys, ye, ym) -#define FLUSHDP(v, vc, vs, ve, vm) \ - if(vc==IEEE754_CLASS_DNORM) {\ - if(ieee754_csr.nod) {\ - SETCX(IEEE754_INEXACT);\ - vc = IEEE754_CLASS_ZERO;\ - ve = DP_EMIN-1+DP_EBIAS;\ - vm = 0;\ - v = ieee754dp_zero(vs);\ - }\ +#define FLUSHDP(v, vc, vs, ve, vm) \ + if (vc==IEEE754_CLASS_DNORM) { \ + if (ieee754_csr.nod) { \ + ieee754_setcx(IEEE754_INEXACT); \ + vc = IEEE754_CLASS_ZERO; \ + ve = DP_EMIN-1+DP_EBIAS; \ + vm = 0; \ + v = ieee754dp_zero(vs); \ + } \ } -#define FLUSHSP(v, vc, vs, ve, vm) \ - if(vc==IEEE754_CLASS_DNORM) {\ - if(ieee754_csr.nod) {\ - SETCX(IEEE754_INEXACT);\ - vc = IEEE754_CLASS_ZERO;\ - ve = SP_EMIN-1+SP_EBIAS;\ - vm = 0;\ - v = ieee754sp_zero(vs);\ - }\ +#define FLUSHSP(v, vc, vs, ve, vm) \ + if (vc==IEEE754_CLASS_DNORM) { \ + if (ieee754_csr.nod) { \ + ieee754_setcx(IEEE754_INEXACT); \ + vc = IEEE754_CLASS_ZERO; \ + ve = SP_EMIN-1+SP_EBIAS; \ + vm = 0; \ + v = ieee754sp_zero(vs); \ + } \ } #define FLUSHXDP FLUSHDP(x, xc, xs, xe, xm) #define FLUSHYDP FLUSHDP(y, yc, ys, ye, ym) #define FLUSHXSP FLUSHSP(x, xc, xs, xe, xm) #define FLUSHYSP FLUSHSP(y, yc, ys, ye, ym) + +#endif /* __IEEE754INT_H */ diff --git a/arch/mips/math-emu/ieee754m.c b/arch/mips/math-emu/ieee754m.c deleted file mode 100644 index 24190f3c9dd63d..00000000000000 --- a/arch/mips/math-emu/ieee754m.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * floor, trunc, ceil - */ -/* - * MIPS floating point support - * Copyright (C) 1994-2000 Algorithmics Ltd. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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 "ieee754.h" - -ieee754dp ieee754dp_floor(ieee754dp x) -{ - ieee754dp i; - - if (ieee754dp_lt(ieee754dp_modf(x, &i), ieee754dp_zero(0))) - return ieee754dp_sub(i, ieee754dp_one(0)); - else - return i; -} - -ieee754dp ieee754dp_ceil(ieee754dp x) -{ - ieee754dp i; - - if (ieee754dp_gt(ieee754dp_modf(x, &i), ieee754dp_zero(0))) - return ieee754dp_add(i, ieee754dp_one(0)); - else - return i; -} - -ieee754dp ieee754dp_trunc(ieee754dp x) -{ - ieee754dp i; - - (void) ieee754dp_modf(x, &i); - return i; -} diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c index 15d1e36cfe64a2..d348efe9144547 100644 --- a/arch/mips/math-emu/ieee754sp.c +++ b/arch/mips/math-emu/ieee754sp.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,105 +16,68 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include "ieee754sp.h" -int ieee754sp_class(ieee754sp x) +int ieee754sp_class(union ieee754sp x) { COMPXSP; EXPLODEXSP; return xc; } -int ieee754sp_isnan(ieee754sp x) +int ieee754sp_isnan(union ieee754sp x) { return ieee754sp_class(x) >= IEEE754_CLASS_SNAN; } -int ieee754sp_issnan(ieee754sp x) +static inline int ieee754sp_issnan(union ieee754sp x) { assert(ieee754sp_isnan(x)); - return (SPMANT(x) & SP_MBIT(SP_MBITS-1)); + return (SPMANT(x) & SP_MBIT(SP_FBITS-1)); } -ieee754sp ieee754sp_xcpt(ieee754sp r, const char *op, ...) -{ - struct ieee754xctx ax; - - if (!TSTX()) - return r; - - ax.op = op; - ax.rt = IEEE754_RT_SP; - ax.rv.sp = r; - va_start(ax.ap, op); - ieee754_xcpt(&ax); - va_end(ax.ap); - return ax.rv.sp; -} - -ieee754sp ieee754sp_nanxcpt(ieee754sp r, const char *op, ...) +union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r) { - struct ieee754xctx ax; - assert(ieee754sp_isnan(r)); if (!ieee754sp_issnan(r)) /* QNAN does not cause invalid op !! */ return r; - if (!SETANDTESTCX(IEEE754_INVALID_OPERATION)) { + if (!ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) { /* not enabled convert to a quiet NaN */ - SPMANT(r) &= (~SP_MBIT(SP_MBITS-1)); + SPMANT(r) &= (~SP_MBIT(SP_FBITS-1)); if (ieee754sp_isnan(r)) return r; else return ieee754sp_indef(); } - ax.op = op; - ax.rt = 0; - ax.rv.sp = r; - va_start(ax.ap, op); - ieee754_xcpt(&ax); - va_end(ax.ap); - return ax.rv.sp; -} - -ieee754sp ieee754sp_bestnan(ieee754sp x, ieee754sp y) -{ - assert(ieee754sp_isnan(x)); - assert(ieee754sp_isnan(y)); - - if (SPMANT(x) > SPMANT(y)) - return x; - else - return y; + return r; } - -static unsigned get_rounding(int sn, unsigned xm) +static unsigned ieee754sp_get_rounding(int sn, unsigned xm) { /* inexact must round of 3 bits */ if (xm & (SP_MBIT(3) - 1)) { switch (ieee754_csr.rm) { - case IEEE754_RZ: + case FPU_CSR_RZ: break; - case IEEE754_RN: + case FPU_CSR_RN: xm += 0x3 + ((xm >> 3) & 1); /* xm += (xm&0x8)?0x4:0x3 */ break; - case IEEE754_RU: /* toward +Infinity */ + case FPU_CSR_RU: /* toward +Infinity */ if (!sn) /* ?? */ xm += 0x8; break; - case IEEE754_RD: /* toward -Infinity */ + case FPU_CSR_RD: /* toward -Infinity */ if (sn) /* ?? */ xm += 0x8; break; @@ -131,11 +92,11 @@ static unsigned get_rounding(int sn, unsigned xm) * xe is an unbiased exponent * xm is 3bit extended precision value. */ -ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) +union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) { assert(xm); /* we don't gen exact zeros (probably should) */ - assert((xm >> (SP_MBITS + 1 + 3)) == 0); /* no execess */ + assert((xm >> (SP_FBITS + 1 + 3)) == 0); /* no execess */ assert(xm & (SP_HIDDEN_BIT << 3)); if (xe < SP_EMIN) { @@ -143,38 +104,37 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) int es = SP_EMIN - xe; if (ieee754_csr.nod) { - SETCX(IEEE754_UNDERFLOW); - SETCX(IEEE754_INEXACT); + ieee754_setcx(IEEE754_UNDERFLOW); + ieee754_setcx(IEEE754_INEXACT); switch(ieee754_csr.rm) { - case IEEE754_RN: - case IEEE754_RZ: + case FPU_CSR_RN: + case FPU_CSR_RZ: return ieee754sp_zero(sn); - case IEEE754_RU: /* toward +Infinity */ - if(sn == 0) + case FPU_CSR_RU: /* toward +Infinity */ + if (sn == 0) return ieee754sp_min(0); else return ieee754sp_zero(1); - case IEEE754_RD: /* toward -Infinity */ - if(sn == 0) + case FPU_CSR_RD: /* toward -Infinity */ + if (sn == 0) return ieee754sp_zero(0); else return ieee754sp_min(1); } } - if (xe == SP_EMIN - 1 - && get_rounding(sn, xm) >> (SP_MBITS + 1 + 3)) + if (xe == SP_EMIN - 1 && + ieee754sp_get_rounding(sn, xm) >> (SP_FBITS + 1 + 3)) { /* Not tiny after rounding */ - SETCX(IEEE754_INEXACT); - xm = get_rounding(sn, xm); + ieee754_setcx(IEEE754_INEXACT); + xm = ieee754sp_get_rounding(sn, xm); xm >>= 1; /* Clear grs bits */ xm &= ~(SP_MBIT(3) - 1); xe++; - } - else { + } else { /* sticky right shift es bits */ SPXSRSXn(es); @@ -183,17 +143,17 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) } } if (xm & (SP_MBIT(3) - 1)) { - SETCX(IEEE754_INEXACT); + ieee754_setcx(IEEE754_INEXACT); if ((xm & (SP_HIDDEN_BIT << 3)) == 0) { - SETCX(IEEE754_UNDERFLOW); + ieee754_setcx(IEEE754_UNDERFLOW); } /* inexact must round of 3 bits */ - xm = get_rounding(sn, xm); + xm = ieee754sp_get_rounding(sn, xm); /* adjust exponent for rounding add overflowing */ - if (xm >> (SP_MBITS + 1 + 3)) { + if (xm >> (SP_FBITS + 1 + 3)) { /* add causes mantissa overflow */ xm >>= 1; xe++; @@ -202,24 +162,24 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) /* strip grs bits */ xm >>= 3; - assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ + assert((xm >> (SP_FBITS + 1)) == 0); /* no execess */ assert(xe >= SP_EMIN); if (xe > SP_EMAX) { - SETCX(IEEE754_OVERFLOW); - SETCX(IEEE754_INEXACT); + ieee754_setcx(IEEE754_OVERFLOW); + ieee754_setcx(IEEE754_INEXACT); /* -O can be table indexed by (rm,sn) */ switch (ieee754_csr.rm) { - case IEEE754_RN: + case FPU_CSR_RN: return ieee754sp_inf(sn); - case IEEE754_RZ: + case FPU_CSR_RZ: return ieee754sp_max(sn); - case IEEE754_RU: /* toward +Infinity */ + case FPU_CSR_RU: /* toward +Infinity */ if (sn == 0) return ieee754sp_inf(0); else return ieee754sp_max(1); - case IEEE754_RD: /* toward -Infinity */ + case FPU_CSR_RD: /* toward -Infinity */ if (sn == 0) return ieee754sp_max(0); else @@ -232,10 +192,10 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) /* we underflow (tiny/zero) */ assert(xe == SP_EMIN); if (ieee754_csr.mx & IEEE754_UNDERFLOW) - SETCX(IEEE754_UNDERFLOW); + ieee754_setcx(IEEE754_UNDERFLOW); return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm); } else { - assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ + assert((xm >> (SP_FBITS + 1)) == 0); /* no execess */ assert(xm & SP_HIDDEN_BIT); return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h index 754fd54649b517..ad268e3323183a 100644 --- a/arch/mips/math-emu/ieee754sp.h +++ b/arch/mips/math-emu/ieee754sp.h @@ -6,8 +6,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -19,70 +17,71 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include "ieee754int.h" #define assert(expr) ((void)0) +#define SP_EBIAS 127 +#define SP_EMIN (-126) +#define SP_EMAX 127 +#define SP_FBITS 23 +#define SP_MBITS 23 + +#define SP_MBIT(x) ((u32)1 << (x)) +#define SP_HIDDEN_BIT SP_MBIT(SP_FBITS) +#define SP_SIGN_BIT SP_MBIT(31) + +#define SPSIGN(sp) (sp.sign) +#define SPBEXP(sp) (sp.bexp) +#define SPMANT(sp) (sp.mant) + +static inline int ieee754sp_finite(union ieee754sp x) +{ + return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS; +} + /* 3bit extended single precision sticky right shift */ -#define SPXSRSXn(rs) \ - (xe += rs, \ - xm = (rs > (SP_MBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) +#define SPXSRSXn(rs) \ + (xe += rs, \ + xm = (rs > (SP_FBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) #define SPXSRSX1() \ - (xe++, (xm = (xm >> 1) | (xm & 1))) + (xe++, (xm = (xm >> 1) | (xm & 1))) -#define SPXSRSYn(rs) \ - (ye+=rs, \ - ym = (rs > (SP_MBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) +#define SPXSRSYn(rs) \ + (ye+=rs, \ + ym = (rs > (SP_FBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) #define SPXSRSY1() \ - (ye++, (ym = (ym >> 1) | (ym & 1))) + (ye++, (ym = (ym >> 1) | (ym & 1))) /* convert denormal to normalized with extended exponent */ #define SPDNORMx(m,e) \ - while( (m >> SP_MBITS) == 0) { m <<= 1; e--; } + while ((m >> SP_FBITS) == 0) { m <<= 1; e--; } #define SPDNORMX SPDNORMx(xm, xe) #define SPDNORMY SPDNORMx(ym, ye) -static inline ieee754sp buildsp(int s, int bx, unsigned m) +static inline union ieee754sp buildsp(int s, int bx, unsigned m) { - ieee754sp r; + union ieee754sp r; assert((s) == 0 || (s) == 1); assert((bx) >= SP_EMIN - 1 + SP_EBIAS && (bx) <= SP_EMAX + 1 + SP_EBIAS); - assert(((m) >> SP_MBITS) == 0); + assert(((m) >> SP_FBITS) == 0); - r.parts.sign = s; - r.parts.bexp = bx; - r.parts.mant = m; + r.sign = s; + r.bexp = bx; + r.mant = m; return r; } -extern int ieee754sp_isnan(ieee754sp); -extern int ieee754sp_issnan(ieee754sp); -extern int ieee754si_xcpt(int, const char *, ...); -extern s64 ieee754di_xcpt(s64, const char *, ...); -extern ieee754sp ieee754sp_xcpt(ieee754sp, const char *, ...); -extern ieee754sp ieee754sp_nanxcpt(ieee754sp, const char *, ...); -extern ieee754sp ieee754sp_bestnan(ieee754sp, ieee754sp); -extern ieee754sp ieee754sp_format(int, int, unsigned); - - -#define SPNORMRET2(s, e, m, name, a0, a1) \ -{ \ - ieee754sp V = ieee754sp_format(s, e, m); \ - if(TSTX()) \ - return ieee754sp_xcpt(V, name, a0, a1); \ - else \ - return V; \ -} - -#define SPNORMRET1(s, e, m, name, a0) SPNORMRET2(s, e, m, name, a0, a0) +extern int ieee754sp_isnan(union ieee754sp); +extern union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp); +extern union ieee754sp ieee754sp_format(int, int, unsigned); diff --git a/arch/mips/math-emu/ieee754xcpt.c b/arch/mips/math-emu/ieee754xcpt.c deleted file mode 100644 index 967167116ae811..00000000000000 --- a/arch/mips/math-emu/ieee754xcpt.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * MIPS floating point support - * Copyright (C) 1994-2000 Algorithmics Ltd. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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. - * - * ######################################################################## - */ - -/************************************************************************** - * Nov 7, 2000 - * Added preprocessor hacks to map to Linux kernel diagnostics. - * - * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - *************************************************************************/ - -#include -#include "ieee754.h" - -/* - * Very naff exception handler (you can plug in your own and - * override this). - */ - -static const char *const rtnames[] = { - "sp", "dp", "xp", "si", "di" -}; - -void ieee754_xcpt(struct ieee754xctx *xcp) -{ - printk(KERN_DEBUG "floating point exception in \"%s\", type=%s\n", - xcp->op, rtnames[xcp->rt]); -} diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c deleted file mode 100644 index eb58a85b315758..00000000000000 --- a/arch/mips/math-emu/kernel_linkage.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Kevin D. Kissell, kevink@mips and Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can distribute 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 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. - * - * Routines corresponding to Linux kernel FP context - * manipulation primitives for the Algorithmics MIPS - * FPU Emulator - */ -#include -#include -#include -#include - -#include -#include - -#define SIGNALLING_NAN 0x7ff800007ff80000LL - -void fpu_emulator_init_fpu(void) -{ - static int first = 1; - int i; - - if (first) { - first = 0; - printk("Algorithmics/MIPS FPU Emulator v1.5\n"); - } - - current->thread.fpu.fcr31 = 0; - for (i = 0; i < 32; i++) - set_fpr64(¤t->thread.fpu.fpr[i], 0, SIGNALLING_NAN); -} diff --git a/arch/mips/math-emu/me-debugfs.c b/arch/mips/math-emu/me-debugfs.c new file mode 100644 index 00000000000000..95ed9f9bd2b074 --- /dev/null +++ b/arch/mips/math-emu/me-debugfs.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); + +static int fpuemu_stat_get(void *data, u64 *val) +{ + int cpu; + unsigned long sum = 0; + + for_each_online_cpu(cpu) { + struct mips_fpu_emulator_stats *ps; + local_t *pv; + + ps = &per_cpu(fpuemustats, cpu); + pv = (void *)ps + (unsigned long)data; + sum += local_read(pv); + } + *val = sum; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n"); + +extern struct dentry *mips_debugfs_dir; +static int __init debugfs_fpuemu(void) +{ + struct dentry *d, *dir; + + if (!mips_debugfs_dir) + return -ENODEV; + dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir); + if (!dir) + return -ENOMEM; + +#define FPU_EMU_STAT_OFFSET(m) \ + offsetof(struct mips_fpu_emulator_stats, m) + +#define FPU_STAT_CREATE(m) \ +do { \ + d = debugfs_create_file(#m , S_IRUGO, dir, \ + (void *)FPU_EMU_STAT_OFFSET(m), \ + &fops_fpuemu_stat); \ + if (!d) \ + return -ENOMEM; \ +} while (0) + + FPU_STAT_CREATE(emulated); + FPU_STAT_CREATE(loads); + FPU_STAT_CREATE(stores); + FPU_STAT_CREATE(cp1ops); + FPU_STAT_CREATE(cp1xops); + FPU_STAT_CREATE(errors); + + return 0; +} +__initcall(debugfs_fpuemu); diff --git a/arch/mips/math-emu/me-micromips.c b/arch/mips/math-emu/me-micromips.c new file mode 100644 index 00000000000000..b0e6e41054d413 --- /dev/null +++ b/arch/mips/math-emu/me-micromips.c @@ -0,0 +1,348 @@ +#include + +/* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */ +static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0}; +static const int sdps_format[] = {16, 17, 22, 0, 0, 0, 0, 0}; +static const int dwl_format[] = {17, 20, 21, 0, 0, 0, 0, 0}; +static const int swl_format[] = {16, 20, 21, 0, 0, 0, 0, 0}; + +/* + * This functions translates a 32-bit microMIPS instruction + * into a 32-bit MIPS32 instruction. Returns 0 on success + * and SIGILL otherwise. + */ +int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr) +{ + union mips_instruction insn = *insn_ptr; + union mips_instruction mips32_insn = insn; + int func, fmt, op; + + switch (insn.mm_i_format.opcode) { + case mm_ldc132_op: + mips32_insn.mm_i_format.opcode = ldc1_op; + mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; + mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; + break; + case mm_lwc132_op: + mips32_insn.mm_i_format.opcode = lwc1_op; + mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; + mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; + break; + case mm_sdc132_op: + mips32_insn.mm_i_format.opcode = sdc1_op; + mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; + mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; + break; + case mm_swc132_op: + mips32_insn.mm_i_format.opcode = swc1_op; + mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; + mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; + break; + case mm_pool32i_op: + /* NOTE: offset is << by 1 if in microMIPS mode. */ + if ((insn.mm_i_format.rt == mm_bc1f_op) || + (insn.mm_i_format.rt == mm_bc1t_op)) { + mips32_insn.fb_format.opcode = cop1_op; + mips32_insn.fb_format.bc = bc_op; + mips32_insn.fb_format.flag = + (insn.mm_i_format.rt == mm_bc1t_op) ? 1 : 0; + } else + return SIGILL; + break; + case mm_pool32f_op: + switch (insn.mm_fp0_format.func) { + case mm_32f_01_op: + case mm_32f_11_op: + case mm_32f_02_op: + case mm_32f_12_op: + case mm_32f_41_op: + case mm_32f_51_op: + case mm_32f_42_op: + case mm_32f_52_op: + op = insn.mm_fp0_format.func; + if (op == mm_32f_01_op) + func = madd_s_op; + else if (op == mm_32f_11_op) + func = madd_d_op; + else if (op == mm_32f_02_op) + func = nmadd_s_op; + else if (op == mm_32f_12_op) + func = nmadd_d_op; + else if (op == mm_32f_41_op) + func = msub_s_op; + else if (op == mm_32f_51_op) + func = msub_d_op; + else if (op == mm_32f_42_op) + func = nmsub_s_op; + else + func = nmsub_d_op; + mips32_insn.fp6_format.opcode = cop1x_op; + mips32_insn.fp6_format.fr = insn.mm_fp6_format.fr; + mips32_insn.fp6_format.ft = insn.mm_fp6_format.ft; + mips32_insn.fp6_format.fs = insn.mm_fp6_format.fs; + mips32_insn.fp6_format.fd = insn.mm_fp6_format.fd; + mips32_insn.fp6_format.func = func; + break; + case mm_32f_10_op: + func = -1; /* Invalid */ + op = insn.mm_fp5_format.op & 0x7; + if (op == mm_ldxc1_op) + func = ldxc1_op; + else if (op == mm_sdxc1_op) + func = sdxc1_op; + else if (op == mm_lwxc1_op) + func = lwxc1_op; + else if (op == mm_swxc1_op) + func = swxc1_op; + + if (func != -1) { + mips32_insn.r_format.opcode = cop1x_op; + mips32_insn.r_format.rs = + insn.mm_fp5_format.base; + mips32_insn.r_format.rt = + insn.mm_fp5_format.index; + mips32_insn.r_format.rd = 0; + mips32_insn.r_format.re = insn.mm_fp5_format.fd; + mips32_insn.r_format.func = func; + } else + return SIGILL; + break; + case mm_32f_40_op: + op = -1; /* Invalid */ + if (insn.mm_fp2_format.op == mm_fmovt_op) + op = 1; + else if (insn.mm_fp2_format.op == mm_fmovf_op) + op = 0; + if (op != -1) { + mips32_insn.fp0_format.opcode = cop1_op; + mips32_insn.fp0_format.fmt = + sdps_format[insn.mm_fp2_format.fmt]; + mips32_insn.fp0_format.ft = + (insn.mm_fp2_format.cc<<2) + op; + mips32_insn.fp0_format.fs = + insn.mm_fp2_format.fs; + mips32_insn.fp0_format.fd = + insn.mm_fp2_format.fd; + mips32_insn.fp0_format.func = fmovc_op; + } else + return SIGILL; + break; + case mm_32f_60_op: + func = -1; /* Invalid */ + if (insn.mm_fp0_format.op == mm_fadd_op) + func = fadd_op; + else if (insn.mm_fp0_format.op == mm_fsub_op) + func = fsub_op; + else if (insn.mm_fp0_format.op == mm_fmul_op) + func = fmul_op; + else if (insn.mm_fp0_format.op == mm_fdiv_op) + func = fdiv_op; + if (func != -1) { + mips32_insn.fp0_format.opcode = cop1_op; + mips32_insn.fp0_format.fmt = + sdps_format[insn.mm_fp0_format.fmt]; + mips32_insn.fp0_format.ft = + insn.mm_fp0_format.ft; + mips32_insn.fp0_format.fs = + insn.mm_fp0_format.fs; + mips32_insn.fp0_format.fd = + insn.mm_fp0_format.fd; + mips32_insn.fp0_format.func = func; + } else + return SIGILL; + break; + case mm_32f_70_op: + func = -1; /* Invalid */ + if (insn.mm_fp0_format.op == mm_fmovn_op) + func = fmovn_op; + else if (insn.mm_fp0_format.op == mm_fmovz_op) + func = fmovz_op; + if (func != -1) { + mips32_insn.fp0_format.opcode = cop1_op; + mips32_insn.fp0_format.fmt = + sdps_format[insn.mm_fp0_format.fmt]; + mips32_insn.fp0_format.ft = + insn.mm_fp0_format.ft; + mips32_insn.fp0_format.fs = + insn.mm_fp0_format.fs; + mips32_insn.fp0_format.fd = + insn.mm_fp0_format.fd; + mips32_insn.fp0_format.func = func; + } else + return SIGILL; + break; + case mm_32f_73_op: /* POOL32FXF */ + switch (insn.mm_fp1_format.op) { + case mm_movf0_op: + case mm_movf1_op: + case mm_movt0_op: + case mm_movt1_op: + if ((insn.mm_fp1_format.op & 0x7f) == + mm_movf0_op) + op = 0; + else + op = 1; + mips32_insn.r_format.opcode = spec_op; + mips32_insn.r_format.rs = insn.mm_fp4_format.fs; + mips32_insn.r_format.rt = + (insn.mm_fp4_format.cc << 2) + op; + mips32_insn.r_format.rd = insn.mm_fp4_format.rt; + mips32_insn.r_format.re = 0; + mips32_insn.r_format.func = movc_op; + break; + case mm_fcvtd0_op: + case mm_fcvtd1_op: + case mm_fcvts0_op: + case mm_fcvts1_op: + if ((insn.mm_fp1_format.op & 0x7f) == + mm_fcvtd0_op) { + func = fcvtd_op; + fmt = swl_format[insn.mm_fp3_format.fmt]; + } else { + func = fcvts_op; + fmt = dwl_format[insn.mm_fp3_format.fmt]; + } + mips32_insn.fp0_format.opcode = cop1_op; + mips32_insn.fp0_format.fmt = fmt; + mips32_insn.fp0_format.ft = 0; + mips32_insn.fp0_format.fs = + insn.mm_fp3_format.fs; + mips32_insn.fp0_format.fd = + insn.mm_fp3_format.rt; + mips32_insn.fp0_format.func = func; + break; + case mm_fmov0_op: + case mm_fmov1_op: + case mm_fabs0_op: + case mm_fabs1_op: + case mm_fneg0_op: + case mm_fneg1_op: + if ((insn.mm_fp1_format.op & 0x7f) == + mm_fmov0_op) + func = fmov_op; + else if ((insn.mm_fp1_format.op & 0x7f) == + mm_fabs0_op) + func = fabs_op; + else + func = fneg_op; + mips32_insn.fp0_format.opcode = cop1_op; + mips32_insn.fp0_format.fmt = + sdps_format[insn.mm_fp3_format.fmt]; + mips32_insn.fp0_format.ft = 0; + mips32_insn.fp0_format.fs = + insn.mm_fp3_format.fs; + mips32_insn.fp0_format.fd = + insn.mm_fp3_format.rt; + mips32_insn.fp0_format.func = func; + break; + case mm_ffloorl_op: + case mm_ffloorw_op: + case mm_fceill_op: + case mm_fceilw_op: + case mm_ftruncl_op: + case mm_ftruncw_op: + case mm_froundl_op: + case mm_froundw_op: + case mm_fcvtl_op: + case mm_fcvtw_op: + if (insn.mm_fp1_format.op == mm_ffloorl_op) + func = ffloorl_op; + else if (insn.mm_fp1_format.op == mm_ffloorw_op) + func = ffloor_op; + else if (insn.mm_fp1_format.op == mm_fceill_op) + func = fceill_op; + else if (insn.mm_fp1_format.op == mm_fceilw_op) + func = fceil_op; + else if (insn.mm_fp1_format.op == mm_ftruncl_op) + func = ftruncl_op; + else if (insn.mm_fp1_format.op == mm_ftruncw_op) + func = ftrunc_op; + else if (insn.mm_fp1_format.op == mm_froundl_op) + func = froundl_op; + else if (insn.mm_fp1_format.op == mm_froundw_op) + func = fround_op; + else if (insn.mm_fp1_format.op == mm_fcvtl_op) + func = fcvtl_op; + else + func = fcvtw_op; + mips32_insn.fp0_format.opcode = cop1_op; + mips32_insn.fp0_format.fmt = + sd_format[insn.mm_fp1_format.fmt]; + mips32_insn.fp0_format.ft = 0; + mips32_insn.fp0_format.fs = + insn.mm_fp1_format.fs; + mips32_insn.fp0_format.fd = + insn.mm_fp1_format.rt; + mips32_insn.fp0_format.func = func; + break; + case mm_frsqrt_op: + case mm_fsqrt_op: + case mm_frecip_op: + if (insn.mm_fp1_format.op == mm_frsqrt_op) + func = frsqrt_op; + else if (insn.mm_fp1_format.op == mm_fsqrt_op) + func = fsqrt_op; + else + func = frecip_op; + mips32_insn.fp0_format.opcode = cop1_op; + mips32_insn.fp0_format.fmt = + sdps_format[insn.mm_fp1_format.fmt]; + mips32_insn.fp0_format.ft = 0; + mips32_insn.fp0_format.fs = + insn.mm_fp1_format.fs; + mips32_insn.fp0_format.fd = + insn.mm_fp1_format.rt; + mips32_insn.fp0_format.func = func; + break; + case mm_mfc1_op: + case mm_mtc1_op: + case mm_cfc1_op: + case mm_ctc1_op: + case mm_mfhc1_op: + case mm_mthc1_op: + if (insn.mm_fp1_format.op == mm_mfc1_op) + op = mfc_op; + else if (insn.mm_fp1_format.op == mm_mtc1_op) + op = mtc_op; + else if (insn.mm_fp1_format.op == mm_cfc1_op) + op = cfc_op; + else if (insn.mm_fp1_format.op == mm_ctc1_op) + op = ctc_op; + else if (insn.mm_fp1_format.op == mm_mfhc1_op) + op = mfhc_op; + else + op = mthc_op; + mips32_insn.fp1_format.opcode = cop1_op; + mips32_insn.fp1_format.op = op; + mips32_insn.fp1_format.rt = + insn.mm_fp1_format.rt; + mips32_insn.fp1_format.fs = + insn.mm_fp1_format.fs; + mips32_insn.fp1_format.fd = 0; + mips32_insn.fp1_format.func = 0; + break; + default: + return SIGILL; + } + break; + case mm_32f_74_op: /* c.cond.fmt */ + mips32_insn.fp0_format.opcode = cop1_op; + mips32_insn.fp0_format.fmt = + sdps_format[insn.mm_fp4_format.fmt]; + mips32_insn.fp0_format.ft = insn.mm_fp4_format.rt; + mips32_insn.fp0_format.fs = insn.mm_fp4_format.fs; + mips32_insn.fp0_format.fd = insn.mm_fp4_format.cc << 2; + mips32_insn.fp0_format.func = + insn.mm_fp4_format.cond | MM_MIPS32_COND_FC; + break; + default: + return SIGILL; + } + break; + default: + return SIGILL; + } + + *insn_ptr = mips32_insn; + return 0; +} diff --git a/arch/mips/math-emu/sp_add.c b/arch/mips/math-emu/sp_add.c index c446e64637e212..2d84d460cb677e 100644 --- a/arch/mips/math-emu/sp_add.c +++ b/arch/mips/math-emu/sp_add.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,23 +16,22 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754sp.h" -ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) +union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y) { + int s; + COMPXSP; COMPYSP; EXPLODEXSP; EXPLODEYSP; - CLEARCX; + ieee754_clearcx(); FLUSHXSP; FLUSHYSP; @@ -51,8 +48,8 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_nanxcpt(ieee754sp_indef(), "add", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef()); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -68,14 +65,14 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) return x; - /* Infinity handling - */ - + /* + * Infinity handling + */ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): if (xs == ys) return x; - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_xcpt(ieee754sp_indef(), "add", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_indef(); case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): @@ -87,15 +84,14 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): return x; - /* Zero handling - */ - + /* + * Zero handling + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): if (xs == ys) return x; else - return ieee754sp_zero(ieee754_csr.rm == - IEEE754_RD); + return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): @@ -108,6 +104,8 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; + /* FALL THROUGH */ + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): SPDNORMY; break; @@ -122,33 +120,38 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) assert(xm & SP_HIDDEN_BIT); assert(ym & SP_HIDDEN_BIT); - /* provide guard,round and stick bit space */ + /* + * Provide guard, round and stick bit space. + */ xm <<= 3; ym <<= 3; if (xe > ye) { - /* have to shift y fraction right to align + /* + * Have to shift y fraction right to align. */ - int s = xe - ye; + s = xe - ye; SPXSRSYn(s); } else if (ye > xe) { - /* have to shift x fraction right to align + /* + * Have to shift x fraction right to align. */ - int s = ye - xe; + s = ye - xe; SPXSRSXn(s); } assert(xe == ye); assert(xe <= SP_EMAX); if (xs == ys) { - /* generate 28 bit result of adding two 27 bit numbers - * leaving result in xm,xs,xe + /* + * Generate 28 bit result of adding two 27 bit numbers + * leaving result in xm, xs and xe. */ xm = xm + ym; xe = xe; xs = xs; - if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ + if (xm >> (SP_FBITS + 1 + 3)) { /* carry out */ SPXSRSX1(); } } else { @@ -162,15 +165,16 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) xs = ys; } if (xm == 0) - return ieee754sp_zero(ieee754_csr.rm == - IEEE754_RD); + return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); - /* normalize in extended single precision */ - while ((xm >> (SP_MBITS + 3)) == 0) { + /* + * Normalize in extended single precision + */ + while ((xm >> (SP_FBITS + 3)) == 0) { xm <<= 1; xe--; } - } - SPNORMRET2(xs, xe, xm, "add", x, y); + + return ieee754sp_format(xs, xe, xm); } diff --git a/arch/mips/math-emu/sp_cmp.c b/arch/mips/math-emu/sp_cmp.c index 716cf37e24653b..addbccb2f556c4 100644 --- a/arch/mips/math-emu/sp_cmp.c +++ b/arch/mips/math-emu/sp_cmp.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,16 +16,16 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754sp.h" -int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp, int sig) +int ieee754sp_cmp(union ieee754sp x, union ieee754sp y, int cmp, int sig) { + int vx; + int vy; + COMPXSP; COMPYSP; @@ -35,21 +33,21 @@ int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp, int sig) EXPLODEYSP; FLUSHXSP; FLUSHYSP; - CLEARCX; /* Even clear inexact flag here */ + ieee754_clearcx(); /* Even clear inexact flag here */ if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) { if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN) - SETCX(IEEE754_INVALID_OPERATION); + ieee754_setcx(IEEE754_INVALID_OPERATION); if (cmp & IEEE754_CUN) return 1; if (cmp & (IEEE754_CLT | IEEE754_CGT)) { - if (sig && SETANDTESTCX(IEEE754_INVALID_OPERATION)) - return ieee754si_xcpt(0, "fcmpf", x); + if (sig && ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) + return 0; } return 0; } else { - int vx = x.bits; - int vy = y.bits; + vx = x.bits; + vy = y.bits; if (vx < 0) vx = -vx ^ SP_SIGN_BIT; diff --git a/arch/mips/math-emu/sp_div.c b/arch/mips/math-emu/sp_div.c index d7747928c95492..721f317aa8778b 100644 --- a/arch/mips/math-emu/sp_div.c +++ b/arch/mips/math-emu/sp_div.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,23 +16,24 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754sp.h" -ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) +union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y) { + unsigned rm; + int re; + unsigned bm; + COMPXSP; COMPYSP; EXPLODEXSP; EXPLODEYSP; - CLEARCX; + ieee754_clearcx(); FLUSHXSP; FLUSHYSP; @@ -51,8 +50,8 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_nanxcpt(ieee754sp_indef(), "div", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef()); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -68,12 +67,12 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) return x; - /* Infinity handling - */ - + /* + * Infinity handling + */ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_indef(); case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): @@ -85,17 +84,17 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): return ieee754sp_inf(xs ^ ys); - /* Zero handling - */ - + /* + * Zero handling + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_indef(); case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): - SETCX(IEEE754_ZERO_DIVIDE); - return ieee754sp_xcpt(ieee754sp_inf(xs ^ ys), "div", x, y); + ieee754_setcx(IEEE754_ZERO_DIVIDE); + return ieee754sp_inf(xs ^ ys); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): @@ -122,35 +121,33 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) xm <<= 3; ym <<= 3; - { - /* now the dirty work */ - - unsigned rm = 0; - int re = xe - ye; - unsigned bm; - - for (bm = SP_MBIT(SP_MBITS + 2); bm; bm >>= 1) { - if (xm >= ym) { - xm -= ym; - rm |= bm; - if (xm == 0) - break; - } - xm <<= 1; - } - rm <<= 1; - if (xm) - rm |= 1; /* have remainder, set sticky */ + /* now the dirty work */ - assert(rm); + rm = 0; + re = xe - ye; - /* normalise rm to rounding precision ? - */ - while ((rm >> (SP_MBITS + 3)) == 0) { - rm <<= 1; - re--; + for (bm = SP_MBIT(SP_FBITS + 2); bm; bm >>= 1) { + if (xm >= ym) { + xm -= ym; + rm |= bm; + if (xm == 0) + break; } + xm <<= 1; + } + + rm <<= 1; + if (xm) + rm |= 1; /* have remainder, set sticky */ - SPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y); + assert(rm); + + /* normalise rm to rounding precision ? + */ + while ((rm >> (SP_FBITS + 3)) == 0) { + rm <<= 1; + re--; } + + return ieee754sp_format(xs == ys ? 0 : 1, re, rm); } diff --git a/arch/mips/math-emu/sp_fdp.c b/arch/mips/math-emu/sp_fdp.c index e1515aae0166d4..1b266fb1697309 100644 --- a/arch/mips/math-emu/sp_fdp.c +++ b/arch/mips/math-emu/sp_fdp.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,59 +16,61 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754sp.h" +#include "ieee754dp.h" -ieee754sp ieee754sp_fdp(ieee754dp x) +union ieee754sp ieee754sp_fdp(union ieee754dp x) { + u32 rm; + COMPXDP; - ieee754sp nan; + union ieee754sp nan; EXPLODEXDP; - CLEARCX; + ieee754_clearcx(); FLUSHXDP; switch (xc) { case IEEE754_CLASS_SNAN: - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_nanxcpt(ieee754sp_indef(), "fdp"); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef()); + case IEEE754_CLASS_QNAN: nan = buildsp(xs, SP_EMAX + 1 + SP_EBIAS, (u32) - (xm >> (DP_MBITS - SP_MBITS))); + (xm >> (DP_FBITS - SP_FBITS))); if (!ieee754sp_isnan(nan)) nan = ieee754sp_indef(); - return ieee754sp_nanxcpt(nan, "fdp", x); + return ieee754sp_nanxcpt(nan); + case IEEE754_CLASS_INF: return ieee754sp_inf(xs); + case IEEE754_CLASS_ZERO: return ieee754sp_zero(xs); + case IEEE754_CLASS_DNORM: /* can't possibly be sp representable */ - SETCX(IEEE754_UNDERFLOW); - SETCX(IEEE754_INEXACT); - if ((ieee754_csr.rm == IEEE754_RU && !xs) || - (ieee754_csr.rm == IEEE754_RD && xs)) - return ieee754sp_xcpt(ieee754sp_mind(xs), "fdp", x); - return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x); + ieee754_setcx(IEEE754_UNDERFLOW); + ieee754_setcx(IEEE754_INEXACT); + if ((ieee754_csr.rm == FPU_CSR_RU && !xs) || + (ieee754_csr.rm == FPU_CSR_RD && xs)) + return ieee754sp_mind(xs); + return ieee754sp_zero(xs); + case IEEE754_CLASS_NORM: break; } - { - u32 rm; - - /* convert from DP_MBITS to SP_MBITS+3 with sticky right shift - */ - rm = (xm >> (DP_MBITS - (SP_MBITS + 3))) | - ((xm << (64 - (DP_MBITS - (SP_MBITS + 3)))) != 0); + /* + * Convert from DP_FBITS to SP_FBITS+3 with sticky right shift. + */ + rm = (xm >> (DP_FBITS - (SP_FBITS + 3))) | + ((xm << (64 - (DP_FBITS - (SP_FBITS + 3)))) != 0); - SPNORMRET1(xs, xe, rm, "fdp", x); - } + return ieee754sp_format(xs, xe, rm); } diff --git a/arch/mips/math-emu/sp_fint.c b/arch/mips/math-emu/sp_fint.c index 9694d6c016cb12..d5d8495b2cc4d1 100644 --- a/arch/mips/math-emu/sp_fint.c +++ b/arch/mips/math-emu/sp_fint.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,21 +16,18 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754sp.h" -ieee754sp ieee754sp_fint(int x) +union ieee754sp ieee754sp_fint(int x) { unsigned xm; int xe; int xs; - CLEARCX; + ieee754_clearcx(); if (x == 0) return ieee754sp_zero(0); @@ -50,30 +45,21 @@ ieee754sp ieee754sp_fint(int x) } else { xm = x; } - xe = SP_MBITS + 3; + xe = SP_FBITS + 3; - if (xm >> (SP_MBITS + 1 + 3)) { + if (xm >> (SP_FBITS + 1 + 3)) { /* shunt out overflow bits */ - while (xm >> (SP_MBITS + 1 + 3)) { + while (xm >> (SP_FBITS + 1 + 3)) { SPXSRSX1(); } } else { /* normalize in grs extended single precision */ - while ((xm >> (SP_MBITS + 3)) == 0) { + while ((xm >> (SP_FBITS + 3)) == 0) { xm <<= 1; xe--; } } - SPNORMRET1(xs, xe, xm, "fint", x); -} - - -ieee754sp ieee754sp_funs(unsigned int u) -{ - if ((int) u < 0) - return ieee754sp_add(ieee754sp_1e31(), - ieee754sp_fint(u & ~(1 << 31))); - return ieee754sp_fint(u); + return ieee754sp_format(xs, xe, xm); } diff --git a/arch/mips/math-emu/sp_flong.c b/arch/mips/math-emu/sp_flong.c index 16a651f2986544..012e30ce7589fe 100644 --- a/arch/mips/math-emu/sp_flong.c +++ b/arch/mips/math-emu/sp_flong.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,21 +16,18 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754sp.h" -ieee754sp ieee754sp_flong(s64 x) +union ieee754sp ieee754sp_flong(s64 x) { u64 xm; /* <--- need 64-bit mantissa temp */ int xe; int xs; - CLEARCX; + ieee754_clearcx(); if (x == 0) return ieee754sp_zero(0); @@ -50,29 +45,20 @@ ieee754sp ieee754sp_flong(s64 x) } else { xm = x; } - xe = SP_MBITS + 3; + xe = SP_FBITS + 3; - if (xm >> (SP_MBITS + 1 + 3)) { + if (xm >> (SP_FBITS + 1 + 3)) { /* shunt out overflow bits */ - while (xm >> (SP_MBITS + 1 + 3)) { + while (xm >> (SP_FBITS + 1 + 3)) { SPXSRSX1(); } } else { /* normalize in grs extended single precision */ - while ((xm >> (SP_MBITS + 3)) == 0) { + while ((xm >> (SP_FBITS + 3)) == 0) { xm <<= 1; xe--; } } - SPNORMRET1(xs, xe, xm, "sp_flong", x); -} - - -ieee754sp ieee754sp_fulong(u64 u) -{ - if ((s64) u < 0) - return ieee754sp_add(ieee754sp_1e63(), - ieee754sp_flong(u & ~(1ULL << 63))); - return ieee754sp_flong(u); + return ieee754sp_format(xs, xe, xm); } diff --git a/arch/mips/math-emu/sp_frexp.c b/arch/mips/math-emu/sp_frexp.c deleted file mode 100644 index 5bc993c300447f..00000000000000 --- a/arch/mips/math-emu/sp_frexp.c +++ /dev/null @@ -1,52 +0,0 @@ -/* IEEE754 floating point arithmetic - * single precision - */ -/* - * MIPS floating point support - * Copyright (C) 1994-2000 Algorithmics Ltd. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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 "ieee754sp.h" - -/* close to ieeep754sp_logb -*/ -ieee754sp ieee754sp_frexp(ieee754sp x, int *eptr) -{ - COMPXSP; - CLEARCX; - EXPLODEXSP; - - switch (xc) { - case IEEE754_CLASS_SNAN: - case IEEE754_CLASS_QNAN: - case IEEE754_CLASS_INF: - case IEEE754_CLASS_ZERO: - *eptr = 0; - return x; - case IEEE754_CLASS_DNORM: - SPDNORMX; - break; - case IEEE754_CLASS_NORM: - break; - } - *eptr = xe + 1; - return buildsp(xs, -1 + SP_EBIAS, xm & ~SP_HIDDEN_BIT); -} diff --git a/arch/mips/math-emu/sp_logb.c b/arch/mips/math-emu/sp_logb.c deleted file mode 100644 index 9c14e0c75bd2bc..00000000000000 --- a/arch/mips/math-emu/sp_logb.c +++ /dev/null @@ -1,53 +0,0 @@ -/* IEEE754 floating point arithmetic - * single precision - */ -/* - * MIPS floating point support - * Copyright (C) 1994-2000 Algorithmics Ltd. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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 "ieee754sp.h" - -ieee754sp ieee754sp_logb(ieee754sp x) -{ - COMPXSP; - - CLEARCX; - - EXPLODEXSP; - - switch (xc) { - case IEEE754_CLASS_SNAN: - return ieee754sp_nanxcpt(x, "logb", x); - case IEEE754_CLASS_QNAN: - return x; - case IEEE754_CLASS_INF: - return ieee754sp_inf(0); - case IEEE754_CLASS_ZERO: - return ieee754sp_inf(1); - case IEEE754_CLASS_DNORM: - SPDNORMX; - break; - case IEEE754_CLASS_NORM: - break; - } - return ieee754sp_fint(xe); -} diff --git a/arch/mips/math-emu/sp_modf.c b/arch/mips/math-emu/sp_modf.c deleted file mode 100644 index 25a0fbaa0556ce..00000000000000 --- a/arch/mips/math-emu/sp_modf.c +++ /dev/null @@ -1,79 +0,0 @@ -/* IEEE754 floating point arithmetic - * single precision - */ -/* - * MIPS floating point support - * Copyright (C) 1994-2000 Algorithmics Ltd. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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 "ieee754sp.h" - -/* modf function is always exact for a finite number -*/ -ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp *ip) -{ - COMPXSP; - - CLEARCX; - - EXPLODEXSP; - - switch (xc) { - case IEEE754_CLASS_SNAN: - case IEEE754_CLASS_QNAN: - case IEEE754_CLASS_INF: - case IEEE754_CLASS_ZERO: - *ip = x; - return x; - case IEEE754_CLASS_DNORM: - /* far to small */ - *ip = ieee754sp_zero(xs); - return x; - case IEEE754_CLASS_NORM: - break; - } - if (xe < 0) { - *ip = ieee754sp_zero(xs); - return x; - } - if (xe >= SP_MBITS) { - *ip = x; - return ieee754sp_zero(xs); - } - /* generate ipart mantissa by clearing bottom bits - */ - *ip = buildsp(xs, xe + SP_EBIAS, - ((xm >> (SP_MBITS - xe)) << (SP_MBITS - xe)) & - ~SP_HIDDEN_BIT); - - /* generate fpart mantissa by clearing top bits - * and normalizing (must be able to normalize) - */ - xm = (xm << (32 - (SP_MBITS - xe))) >> (32 - (SP_MBITS - xe)); - if (xm == 0) - return ieee754sp_zero(xs); - - while ((xm >> SP_MBITS) == 0) { - xm <<= 1; - xe--; - } - return buildsp(xs, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); -} diff --git a/arch/mips/math-emu/sp_mul.c b/arch/mips/math-emu/sp_mul.c index fa4675cf2aad13..890c13a2965e78 100644 --- a/arch/mips/math-emu/sp_mul.c +++ b/arch/mips/math-emu/sp_mul.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,23 +16,32 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754sp.h" -ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) +union ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y) { + int re; + int rs; + unsigned rm; + unsigned short lxm; + unsigned short hxm; + unsigned short lym; + unsigned short hym; + unsigned lrm; + unsigned hrm; + unsigned t; + unsigned at; + COMPXSP; COMPYSP; EXPLODEXSP; EXPLODEYSP; - CLEARCX; + ieee754_clearcx(); FLUSHXSP; FLUSHYSP; @@ -51,8 +58,8 @@ ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_nanxcpt(ieee754sp_indef(), "mul", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef()); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -68,12 +75,13 @@ ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) return x; - /* Infinity handling */ - + /* + * Infinity handling + */ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_xcpt(ieee754sp_indef(), "mul", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_indef(); case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): @@ -108,63 +116,50 @@ ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) assert(xm & SP_HIDDEN_BIT); assert(ym & SP_HIDDEN_BIT); - { - int re = xe + ye; - int rs = xs ^ ys; - unsigned rm; - - /* shunt to top of word */ - xm <<= 32 - (SP_MBITS + 1); - ym <<= 32 - (SP_MBITS + 1); - - /* multiply 32bits xm,ym to give high 32bits rm with stickness - */ - { - unsigned short lxm = xm & 0xffff; - unsigned short hxm = xm >> 16; - unsigned short lym = ym & 0xffff; - unsigned short hym = ym >> 16; - unsigned lrm; - unsigned hrm; - - lrm = lxm * lym; /* 16 * 16 => 32 */ - hrm = hxm * hym; /* 16 * 16 => 32 */ - - { - unsigned t = lxm * hym; /* 16 * 16 => 32 */ - { - unsigned at = lrm + (t << 16); - hrm += at < lrm; - lrm = at; - } - hrm = hrm + (t >> 16); - } - - { - unsigned t = hxm * lym; /* 16 * 16 => 32 */ - { - unsigned at = lrm + (t << 16); - hrm += at < lrm; - lrm = at; - } - hrm = hrm + (t >> 16); - } - rm = hrm | (lrm != 0); - } - - /* - * sticky shift down to normal rounding precision - */ - if ((int) rm < 0) { - rm = (rm >> (32 - (SP_MBITS + 1 + 3))) | - ((rm << (SP_MBITS + 1 + 3)) != 0); - re++; - } else { - rm = (rm >> (32 - (SP_MBITS + 1 + 3 + 1))) | - ((rm << (SP_MBITS + 1 + 3 + 1)) != 0); - } - assert(rm & (SP_HIDDEN_BIT << 3)); - - SPNORMRET2(rs, re, rm, "mul", x, y); + re = xe + ye; + rs = xs ^ ys; + + /* shunt to top of word */ + xm <<= 32 - (SP_FBITS + 1); + ym <<= 32 - (SP_FBITS + 1); + + /* + * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + */ + lxm = xm & 0xffff; + hxm = xm >> 16; + lym = ym & 0xffff; + hym = ym >> 16; + + lrm = lxm * lym; /* 16 * 16 => 32 */ + hrm = hxm * hym; /* 16 * 16 => 32 */ + + t = lxm * hym; /* 16 * 16 => 32 */ + at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + hrm = hrm + (t >> 16); + + t = hxm * lym; /* 16 * 16 => 32 */ + at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + hrm = hrm + (t >> 16); + + rm = hrm | (lrm != 0); + + /* + * Sticky shift down to normal rounding precision. + */ + if ((int) rm < 0) { + rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | + ((rm << (SP_FBITS + 1 + 3)) != 0); + re++; + } else { + rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | + ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); } + assert(rm & (SP_HIDDEN_BIT << 3)); + + return ieee754sp_format(rs, re, rm); } diff --git a/arch/mips/math-emu/sp_scalb.c b/arch/mips/math-emu/sp_scalb.c deleted file mode 100644 index dd76196984c876..00000000000000 --- a/arch/mips/math-emu/sp_scalb.c +++ /dev/null @@ -1,57 +0,0 @@ -/* IEEE754 floating point arithmetic - * single precision - */ -/* - * MIPS floating point support - * Copyright (C) 1994-2000 Algorithmics Ltd. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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 "ieee754sp.h" - -ieee754sp ieee754sp_scalb(ieee754sp x, int n) -{ - COMPXSP; - - CLEARCX; - - EXPLODEXSP; - - switch (xc) { - case IEEE754_CLASS_SNAN: - return ieee754sp_nanxcpt(x, "scalb", x, n); - case IEEE754_CLASS_QNAN: - case IEEE754_CLASS_INF: - case IEEE754_CLASS_ZERO: - return x; - case IEEE754_CLASS_DNORM: - SPDNORMX; - break; - case IEEE754_CLASS_NORM: - break; - } - SPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n); -} - - -ieee754sp ieee754sp_ldexp(ieee754sp x, int n) -{ - return ieee754sp_scalb(x, n); -} diff --git a/arch/mips/math-emu/sp_simple.c b/arch/mips/math-emu/sp_simple.c index ae4fcfafd85335..f1ffaa9a17e042 100644 --- a/arch/mips/math-emu/sp_simple.c +++ b/arch/mips/math-emu/sp_simple.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,33 +16,17 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754sp.h" -int ieee754sp_finite(ieee754sp x) -{ - return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS; -} - -ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y) -{ - CLEARCX; - SPSIGN(x) = SPSIGN(y); - return x; -} - - -ieee754sp ieee754sp_neg(ieee754sp x) +union ieee754sp ieee754sp_neg(union ieee754sp x) { COMPXSP; EXPLODEXSP; - CLEARCX; + ieee754_clearcx(); FLUSHXSP; /* @@ -55,30 +37,29 @@ ieee754sp ieee754sp_neg(ieee754sp x) SPSIGN(x) ^= 1; if (xc == IEEE754_CLASS_SNAN) { - ieee754sp y = ieee754sp_indef(); - SETCX(IEEE754_INVALID_OPERATION); + union ieee754sp y = ieee754sp_indef(); + ieee754_setcx(IEEE754_INVALID_OPERATION); SPSIGN(y) = SPSIGN(x); - return ieee754sp_nanxcpt(y, "neg"); + return ieee754sp_nanxcpt(y); } return x; } - -ieee754sp ieee754sp_abs(ieee754sp x) +union ieee754sp ieee754sp_abs(union ieee754sp x) { COMPXSP; EXPLODEXSP; - CLEARCX; + ieee754_clearcx(); FLUSHXSP; /* Clear sign ALWAYS, irrespective of NaN */ SPSIGN(x) = 0; if (xc == IEEE754_CLASS_SNAN) { - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_nanxcpt(ieee754sp_indef(), "abs"); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef()); } return x; diff --git a/arch/mips/math-emu/sp_sqrt.c b/arch/mips/math-emu/sp_sqrt.c index fed20175f5fb5f..b7c098a86f9510 100644 --- a/arch/mips/math-emu/sp_sqrt.c +++ b/arch/mips/math-emu/sp_sqrt.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,15 +16,12 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754sp.h" -ieee754sp ieee754sp_sqrt(ieee754sp x) +union ieee754sp ieee754sp_sqrt(union ieee754sp x) { int ix, s, q, m, t, i; unsigned int r; @@ -35,34 +30,38 @@ ieee754sp ieee754sp_sqrt(ieee754sp x) /* take care of Inf and NaN */ EXPLODEXSP; - CLEARCX; + ieee754_clearcx(); FLUSHXSP; /* x == INF or NAN? */ switch (xc) { case IEEE754_CLASS_QNAN: /* sqrt(Nan) = Nan */ - return ieee754sp_nanxcpt(x, "sqrt"); + return ieee754sp_nanxcpt(x); + case IEEE754_CLASS_SNAN: - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef()); + case IEEE754_CLASS_ZERO: /* sqrt(0) = 0 */ return x; + case IEEE754_CLASS_INF: if (xs) { /* sqrt(-Inf) = Nan */ - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef()); } /* sqrt(+Inf) = Inf */ return x; + case IEEE754_CLASS_DNORM: case IEEE754_CLASS_NORM: if (xs) { /* sqrt(-x) = Nan */ - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef()); } break; } @@ -99,12 +98,12 @@ ieee754sp ieee754sp_sqrt(ieee754sp x) } if (ix != 0) { - SETCX(IEEE754_INEXACT); + ieee754_setcx(IEEE754_INEXACT); switch (ieee754_csr.rm) { - case IEEE754_RP: + case FPU_CSR_RU: q += 2; break; - case IEEE754_RN: + case FPU_CSR_RN: q += (q & 1); break; } diff --git a/arch/mips/math-emu/sp_sub.c b/arch/mips/math-emu/sp_sub.c index e595c6f3d0bb9d..8592e49032b876 100644 --- a/arch/mips/math-emu/sp_sub.c +++ b/arch/mips/math-emu/sp_sub.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,23 +16,22 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754sp.h" -ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) +union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y) { + int s; + COMPXSP; COMPYSP; EXPLODEXSP; EXPLODEYSP; - CLEARCX; + ieee754_clearcx(); FLUSHXSP; FLUSHYSP; @@ -51,8 +48,8 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_nanxcpt(ieee754sp_indef(), "sub", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef()); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -68,14 +65,14 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) return x; - /* Infinity handling - */ - + /* + * Infinity handling + */ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): if (xs != ys) return x; - SETCX(IEEE754_INVALID_OPERATION); - return ieee754sp_xcpt(ieee754sp_indef(), "sub", x, y); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_indef(); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): @@ -87,15 +84,14 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): return x; - /* Zero handling - */ - + /* + * Zero handling + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): if (xs != ys) return x; else - return ieee754sp_zero(ieee754_csr.rm == - IEEE754_RD); + return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): @@ -104,7 +100,7 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): /* quick fix up */ - DPSIGN(y) ^= 1; + SPSIGN(y) ^= 1; return y; case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): @@ -133,14 +129,16 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) ym <<= 3; if (xe > ye) { - /* have to shift y fraction right to align + /* + * have to shift y fraction right to align */ - int s = xe - ye; + s = xe - ye; SPXSRSYn(s); } else if (ye > xe) { - /* have to shift x fraction right to align + /* + * have to shift x fraction right to align */ - int s = ye - xe; + s = ye - xe; SPXSRSXn(s); } assert(xe == ye); @@ -153,7 +151,7 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) xe = xe; xs = xs; - if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ + if (xm >> (SP_FBITS + 1 + 3)) { /* carry out */ SPXSRSX1(); /* shift preserving sticky */ } } else { @@ -167,17 +165,18 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) xs = ys; } if (xm == 0) { - if (ieee754_csr.rm == IEEE754_RD) + if (ieee754_csr.rm == FPU_CSR_RD) return ieee754sp_zero(1); /* round negative inf. => sign = -1 */ else return ieee754sp_zero(0); /* other round modes => sign = 1 */ } /* normalize to rounding precision */ - while ((xm >> (SP_MBITS + 3)) == 0) { + while ((xm >> (SP_FBITS + 3)) == 0) { xm <<= 1; xe--; } } - SPNORMRET2(xs, xe, xm, "sub", x, y); + + return ieee754sp_format(xs, xe, xm); } diff --git a/arch/mips/math-emu/sp_tint.c b/arch/mips/math-emu/sp_tint.c index 0fe9acc7716ede..091299a317980b 100644 --- a/arch/mips/math-emu/sp_tint.c +++ b/arch/mips/math-emu/sp_tint.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,20 +16,21 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - -#include #include "ieee754sp.h" -int ieee754sp_tint(ieee754sp x) +int ieee754sp_tint(union ieee754sp x) { + u32 residue; + int round; + int sticky; + int odd; + COMPXSP; - CLEARCX; + ieee754_clearcx(); EXPLODEXSP; FLUSHXSP; @@ -40,10 +39,12 @@ int ieee754sp_tint(ieee754sp x) case IEEE754_CLASS_SNAN: case IEEE754_CLASS_QNAN: case IEEE754_CLASS_INF: - SETCX(IEEE754_INVALID_OPERATION); - return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754si_indef(); + case IEEE754_CLASS_ZERO: return 0; + case IEEE754_CLASS_DNORM: case IEEE754_CLASS_NORM: break; @@ -54,18 +55,13 @@ int ieee754sp_tint(ieee754sp x) return -0x80000000; /* Set invalid. We will only use overflow for floating point overflow */ - SETCX(IEEE754_INVALID_OPERATION); - return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754si_indef(); } /* oh gawd */ - if (xe > SP_MBITS) { - xm <<= xe - SP_MBITS; + if (xe > SP_FBITS) { + xm <<= xe - SP_FBITS; } else { - u32 residue; - int round; - int sticky; - int odd; - if (xe < -1) { residue = xm; round = 0; @@ -76,51 +72,38 @@ int ieee754sp_tint(ieee754sp x) * so we do it in two steps. Be aware that xe * may be -1 */ residue = xm << (xe + 1); - residue <<= 31 - SP_MBITS; + residue <<= 31 - SP_FBITS; round = (residue >> 31) != 0; sticky = (residue << 1) != 0; - xm >>= SP_MBITS - xe; + xm >>= SP_FBITS - xe; } odd = (xm & 0x1) != 0x0; switch (ieee754_csr.rm) { - case IEEE754_RN: + case FPU_CSR_RN: if (round && (sticky || odd)) xm++; break; - case IEEE754_RZ: + case FPU_CSR_RZ: break; - case IEEE754_RU: /* toward +Infinity */ + case FPU_CSR_RU: /* toward +Infinity */ if ((round || sticky) && !xs) xm++; break; - case IEEE754_RD: /* toward -Infinity */ + case FPU_CSR_RD: /* toward -Infinity */ if ((round || sticky) && xs) xm++; break; } if ((xm >> 31) != 0) { /* This can happen after rounding */ - SETCX(IEEE754_INVALID_OPERATION); - return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754si_indef(); } if (round || sticky) - SETCX(IEEE754_INEXACT); + ieee754_setcx(IEEE754_INEXACT); } if (xs) return -xm; else return xm; } - - -unsigned int ieee754sp_tuns(ieee754sp x) -{ - ieee754sp hb = ieee754sp_1e31(); - - /* what if x < 0 ?? */ - if (ieee754sp_lt(x, hb)) - return (unsigned) ieee754sp_tint(x); - - return (unsigned) ieee754sp_tint(ieee754sp_sub(x, hb)) | - ((unsigned) 1 << 31); -} diff --git a/arch/mips/math-emu/sp_tlong.c b/arch/mips/math-emu/sp_tlong.c index d0ca6e22be2927..9f3c742c1cea6a 100644 --- a/arch/mips/math-emu/sp_tlong.c +++ b/arch/mips/math-emu/sp_tlong.c @@ -5,8 +5,6 @@ * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -18,19 +16,22 @@ * * 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. - * - * ######################################################################## + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "ieee754sp.h" +#include "ieee754dp.h" -s64 ieee754sp_tlong(ieee754sp x) +s64 ieee754sp_tlong(union ieee754sp x) { + u32 residue; + int round; + int sticky; + int odd; + COMPXDP; /* <-- need 64-bit mantissa tmp */ - CLEARCX; + ieee754_clearcx(); EXPLODEXSP; FLUSHXSP; @@ -39,10 +40,12 @@ s64 ieee754sp_tlong(ieee754sp x) case IEEE754_CLASS_SNAN: case IEEE754_CLASS_QNAN: case IEEE754_CLASS_INF: - SETCX(IEEE754_INVALID_OPERATION); - return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754di_indef(); + case IEEE754_CLASS_ZERO: return 0; + case IEEE754_CLASS_DNORM: case IEEE754_CLASS_NORM: break; @@ -53,69 +56,51 @@ s64 ieee754sp_tlong(ieee754sp x) return -0x8000000000000000LL; /* Set invalid. We will only use overflow for floating point overflow */ - SETCX(IEEE754_INVALID_OPERATION); - return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754di_indef(); } /* oh gawd */ - if (xe > SP_MBITS) { - xm <<= xe - SP_MBITS; - } else if (xe < SP_MBITS) { - u32 residue; - int round; - int sticky; - int odd; - + if (xe > SP_FBITS) { + xm <<= xe - SP_FBITS; + } else if (xe < SP_FBITS) { if (xe < -1) { residue = xm; round = 0; sticky = residue != 0; xm = 0; } else { - residue = xm << (32 - SP_MBITS + xe); + residue = xm << (32 - SP_FBITS + xe); round = (residue >> 31) != 0; sticky = (residue << 1) != 0; - xm >>= SP_MBITS - xe; + xm >>= SP_FBITS - xe; } odd = (xm & 0x1) != 0x0; switch (ieee754_csr.rm) { - case IEEE754_RN: + case FPU_CSR_RN: if (round && (sticky || odd)) xm++; break; - case IEEE754_RZ: + case FPU_CSR_RZ: break; - case IEEE754_RU: /* toward +Infinity */ + case FPU_CSR_RU: /* toward +Infinity */ if ((round || sticky) && !xs) xm++; break; - case IEEE754_RD: /* toward -Infinity */ + case FPU_CSR_RD: /* toward -Infinity */ if ((round || sticky) && xs) xm++; break; } if ((xm >> 63) != 0) { /* This can happen after rounding */ - SETCX(IEEE754_INVALID_OPERATION); - return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754di_indef(); } if (round || sticky) - SETCX(IEEE754_INEXACT); + ieee754_setcx(IEEE754_INEXACT); } if (xs) return -xm; else return xm; } - - -u64 ieee754sp_tulong(ieee754sp x) -{ - ieee754sp hb = ieee754sp_1e63(); - - /* what if x < 0 ?? */ - if (ieee754sp_lt(x, hb)) - return (u64) ieee754sp_tlong(x); - - return (u64) ieee754sp_tlong(ieee754sp_sub(x, hb)) | - (1ULL << 63); -} diff --git a/arch/mips/mti-sead3/sead3-setup.c b/arch/mips/mti-sead3/sead3-setup.c index bf7fe48bf2f927..e43f4801a2455d 100644 --- a/arch/mips/mti-sead3/sead3-setup.c +++ b/arch/mips/mti-sead3/sead3-setup.c @@ -69,17 +69,17 @@ static void __init parse_memsize_param(void) if (!memsize) return; - offset = fdt_path_offset(&__dtb_start, "/memory"); + offset = fdt_path_offset(__dtb_start, "/memory"); if (offset > 0) { uint64_t new_value; /* * reg contains 2 32-bits BE values, offset and size. We just * want to replace the size value without affecting the offset */ - prop_value = fdt_getprop(&__dtb_start, offset, "reg", &prop_len); + prop_value = fdt_getprop(__dtb_start, offset, "reg", &prop_len); new_value = be64_to_cpu(*prop_value); new_value = (new_value & ~0xffffffffllu) | memsize; - fdt_setprop_inplace_u64(&__dtb_start, offset, "reg", new_value); + fdt_setprop_inplace_u64(__dtb_start, offset, "reg", new_value); } } @@ -92,7 +92,7 @@ void __init plat_mem_setup(void) * Load the builtin devicetree. This causes the chosen node to be * parsed resulting in our memory appearing */ - __dt_setup_arch(&__dtb_start); + __dt_setup_arch(__dtb_start); } void __init device_tree_init(void) diff --git a/arch/mips/netlogic/xlp/dt.c b/arch/mips/netlogic/xlp/dt.c index 5754097b9cde83..bdde33147bce2e 100644 --- a/arch/mips/netlogic/xlp/dt.c +++ b/arch/mips/netlogic/xlp/dt.c @@ -42,7 +42,7 @@ #include extern u32 __dtb_xlp_evp_begin[], __dtb_xlp_svp_begin[], - __dtb_xlp_fvp_begin[], __dtb_xlp_gvp_begin[], __dtb_start[]; + __dtb_xlp_fvp_begin[], __dtb_xlp_gvp_begin[]; static void *xlp_fdt_blob; void __init *xlp_dt_init(void *fdtp) @@ -87,22 +87,7 @@ void __init xlp_early_init_devtree(void) void __init device_tree_init(void) { - unsigned long base, size; - struct boot_param_header *fdtp = xlp_fdt_blob; - - if (!fdtp) - return; - - base = virt_to_phys(fdtp); - size = be32_to_cpu(fdtp->totalsize); - - /* Before we do anything, lets reserve the dt blob */ - reserve_bootmem(base, size, BOOTMEM_DEFAULT); - - unflatten_device_tree(); - - /* free the space reserved for the dt blob */ - free_bootmem(base, size); + unflatten_and_copy_device_tree(); } static struct of_device_id __initdata xlp_ids[] = { diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c index eccc5526155e1b..251395210e236e 100644 --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c @@ -28,8 +28,6 @@ __iomem void *rt_sysc_membase; __iomem void *rt_memc_membase; -extern struct boot_param_header __dtb_start; - __iomem void *plat_of_remap_node(const char *node) { struct resource res; @@ -52,30 +50,7 @@ __iomem void *plat_of_remap_node(const char *node) void __init device_tree_init(void) { - unsigned long base, size; - void *fdt_copy; - - if (!initial_boot_params) - return; - - base = virt_to_phys((void *)initial_boot_params); - size = be32_to_cpu(initial_boot_params->totalsize); - - /* Before we do anything, lets reserve the dt blob */ - reserve_bootmem(base, size, BOOTMEM_DEFAULT); - - /* The strings in the flattened tree are referenced directly by the - * device tree, so copy the flattened device tree from init memory - * to regular memory. - */ - fdt_copy = alloc_bootmem(size); - memcpy(fdt_copy, initial_boot_params, size); - initial_boot_params = fdt_copy; - - unflatten_device_tree(); - - /* free the space reserved for the dt blob */ - free_bootmem(base, size); + unflatten_and_copy_device_tree(); } void __init plat_mem_setup(void) @@ -86,7 +61,7 @@ void __init plat_mem_setup(void) * Load the builtin devicetree. This causes the chosen node to be * parsed resulting in our memory appearing */ - __dt_setup_arch(&__dtb_start); + __dt_setup_arch(__dtb_start); if (soc_info.mem_size) add_memory_region(soc_info.mem_base, soc_info.mem_size * SZ_1M, diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h index 975e1841ca6470..cadeb1e2cdfcfa 100644 --- a/arch/mn10300/include/asm/atomic.h +++ b/arch/mn10300/include/asm/atomic.h @@ -13,6 +13,7 @@ #include #include +#include #ifndef CONFIG_SMP #include @@ -234,12 +235,6 @@ static inline void atomic_set_mask(unsigned long mask, unsigned long *addr) #endif } -/* Atomic operations are already serializing on MN10300??? */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif /* __KERNEL__ */ #endif /* CONFIG_SMP */ #endif /* _ASM_ATOMIC_H */ diff --git a/arch/mn10300/include/asm/bitops.h b/arch/mn10300/include/asm/bitops.h index 596bb2706d81af..fe6f8e2c3617de 100644 --- a/arch/mn10300/include/asm/bitops.h +++ b/arch/mn10300/include/asm/bitops.h @@ -18,9 +18,7 @@ #define __ASM_BITOPS_H #include - -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() +#include /* * set bit diff --git a/arch/mn10300/mm/tlb-smp.c b/arch/mn10300/mm/tlb-smp.c index 3e57faf04083bc..e5d0ef722bfa86 100644 --- a/arch/mn10300/mm/tlb-smp.c +++ b/arch/mn10300/mm/tlb-smp.c @@ -78,9 +78,9 @@ void smp_flush_tlb(void *unused) else local_flush_tlb_page(flush_mm, flush_va); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); cpumask_clear_cpu(cpu_id, &flush_cpumask); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); out: put_cpu(); } diff --git a/arch/openrisc/include/asm/bitops.h b/arch/openrisc/include/asm/bitops.h index 2c64f2228dc7c3..3003cdad561bda 100644 --- a/arch/openrisc/include/asm/bitops.h +++ b/arch/openrisc/include/asm/bitops.h @@ -27,14 +27,7 @@ #include #include - -/* - * clear_bit may not imply a memory barrier - */ -#ifndef smp_mb__before_clear_bit -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() -#endif +#include #include #include diff --git a/arch/openrisc/include/asm/syscall.h b/arch/openrisc/include/asm/syscall.h index b752bb67891db2..2db9f1cf0694c0 100644 --- a/arch/openrisc/include/asm/syscall.h +++ b/arch/openrisc/include/asm/syscall.h @@ -19,6 +19,7 @@ #ifndef __ASM_OPENRISC_SYSCALL_H__ #define __ASM_OPENRISC_SYSCALL_H__ +#include #include #include @@ -71,4 +72,8 @@ syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, memcpy(®s->gpr[3 + i], args, n * sizeof(args[0])); } +static inline int syscall_get_arch(void) +{ + return AUDIT_ARCH_OPENRISC; +} #endif diff --git a/arch/openrisc/kernel/ptrace.c b/arch/openrisc/kernel/ptrace.c index 71a2a0c34c65b0..4f59fa4e34e5f2 100644 --- a/arch/openrisc/kernel/ptrace.c +++ b/arch/openrisc/kernel/ptrace.c @@ -187,8 +187,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) */ ret = -1L; - audit_syscall_entry(AUDIT_ARCH_OPENRISC, regs->gpr[11], - regs->gpr[3], regs->gpr[4], + audit_syscall_entry(regs->gpr[11], regs->gpr[3], regs->gpr[4], regs->gpr[5], regs->gpr[6]); return ret ? : regs->gpr[11]; diff --git a/arch/openrisc/kernel/vmlinux.h b/arch/openrisc/kernel/vmlinux.h index 70b9ce41835cdf..bbcdf21b0b3514 100644 --- a/arch/openrisc/kernel/vmlinux.h +++ b/arch/openrisc/kernel/vmlinux.h @@ -5,6 +5,4 @@ extern char __initrd_start, __initrd_end; #endif -extern u32 __dtb_start[]; - #endif diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 472886ceab1dde..0be2db2c7d44ba 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h @@ -7,6 +7,7 @@ #include #include +#include /* * Atomic operations that C can't guarantee us. Useful for @@ -143,11 +144,6 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) #define ATOMIC_INIT(i) { (i) } -#define smp_mb__before_atomic_dec() smp_mb() -#define smp_mb__after_atomic_dec() smp_mb() -#define smp_mb__before_atomic_inc() smp_mb() -#define smp_mb__after_atomic_inc() smp_mb() - #ifdef CONFIG_64BIT #define ATOMIC64_INIT(i) { (i) } diff --git a/arch/parisc/include/asm/bitops.h b/arch/parisc/include/asm/bitops.h index 8c9b631d2a783e..3f9406d9b9d675 100644 --- a/arch/parisc/include/asm/bitops.h +++ b/arch/parisc/include/asm/bitops.h @@ -8,6 +8,7 @@ #include #include /* for BITS_PER_LONG/SHIFT_PER_LONG */ #include +#include #include /* @@ -19,9 +20,6 @@ #define CHOP_SHIFTCOUNT(x) (((unsigned long) (x)) & (BITS_PER_LONG - 1)) -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() - /* See http://marc.theaimsgroup.com/?t=108826637900003 for discussion * on use of volatile and __*_bit() (set/clear/change): * *_bit() want use of volatile. diff --git a/arch/parisc/include/asm/syscall.h b/arch/parisc/include/asm/syscall.h index 8bdfd2c8c39f7c..a5eba95d87feb4 100644 --- a/arch/parisc/include/asm/syscall.h +++ b/arch/parisc/include/asm/syscall.h @@ -3,6 +3,8 @@ #ifndef _ASM_PARISC_SYSCALL_H_ #define _ASM_PARISC_SYSCALL_H_ +#include +#include #include #include @@ -37,4 +39,13 @@ static inline void syscall_get_arguments(struct task_struct *tsk, } } +static inline int syscall_get_arch(void) +{ + int arch = AUDIT_ARCH_PARISC; +#ifdef CONFIG_64BIT + if (!is_compat_task()) + arch = AUDIT_ARCH_PARISC64; +#endif + return arch; +} #endif /*_ASM_PARISC_SYSCALL_H_*/ diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index e842ee233db44e..74814577e4b8a1 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -276,14 +276,11 @@ long do_syscall_trace_enter(struct pt_regs *regs) #ifdef CONFIG_64BIT if (!is_compat_task()) - audit_syscall_entry(AUDIT_ARCH_PARISC64, - regs->gr[20], - regs->gr[26], regs->gr[25], - regs->gr[24], regs->gr[23]); + audit_syscall_entry(regs->gr[20], regs->gr[26], regs->gr[25], + regs->gr[24], regs->gr[23]); else #endif - audit_syscall_entry(AUDIT_ARCH_PARISC, - regs->gr[20] & 0xffffffff, + audit_syscall_entry(regs->gr[20] & 0xffffffff, regs->gr[26] & 0xffffffff, regs->gr[25] & 0xffffffff, regs->gr[24] & 0xffffffff, diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 4c0cedf4e2c7dd..68cde2f8a12c52 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -113,8 +113,13 @@ else endif endif -CFLAGS-$(CONFIG_PPC64) := -mtraceback=no -mcall-aixdesc -CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv1) +CFLAGS-$(CONFIG_PPC64) := -mtraceback=no +ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y) +CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2,-mcall-aixdesc) +AFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2) +else +CFLAGS-$(CONFIG_PPC64) += -mcall-aixdesc +endif CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcmodel=medium,-mminimal-toc) CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mno-pointers-to-nested-functions) CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 $(MULTIPLEWORD) @@ -151,7 +156,7 @@ endif CFLAGS-$(CONFIG_TUNE_CELL) += $(call cc-option,-mtune=cell) KBUILD_CPPFLAGS += -Iarch/$(ARCH) -KBUILD_AFLAGS += -Iarch/$(ARCH) +KBUILD_AFLAGS += -Iarch/$(ARCH) $(AFLAGS-y) KBUILD_CFLAGS += -msoft-float -pipe -Iarch/$(ARCH) $(CFLAGS-y) CPP = $(CC) -E $(KBUILD_CFLAGS) @@ -159,6 +164,11 @@ CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE) KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o +ifeq ($(CONFIG_476FPE_ERR46),y) + KBUILD_LDFLAGS_MODULE += --ppc476-workaround \ + -T $(srctree)/arch/powerpc/platforms/44x/ppc476_modules.lds +endif + # No AltiVec or VSX instructions when building kernel KBUILD_CFLAGS += $(call cc-option,-mno-altivec) KBUILD_CFLAGS += $(call cc-option,-mno-vsx) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index a1f8c7f1ec6013..426dce7ae7c497 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -22,8 +22,14 @@ all: $(obj)/zImage BOOTCFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -fno-strict-aliasing -Os -msoft-float -pipe \ -fomit-frame-pointer -fno-builtin -fPIC -nostdinc \ - -isystem $(shell $(CROSS32CC) -print-file-name=include) \ - -mbig-endian + -isystem $(shell $(CROSS32CC) -print-file-name=include) +ifdef CONFIG_PPC64_BOOT_WRAPPER +BOOTCFLAGS += -m64 +endif +ifdef CONFIG_CPU_BIG_ENDIAN +BOOTCFLAGS += -mbig-endian +endif + BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc ifdef CONFIG_DEBUG_INFO @@ -47,6 +53,7 @@ $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405 $(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405 $(obj)/treeboot-iss4xx.o: BOOTCFLAGS += -mcpu=405 $(obj)/treeboot-currituck.o: BOOTCFLAGS += -mcpu=405 +$(obj)/treeboot-akebono.o: BOOTCFLAGS += -mcpu=405 $(obj)/virtex405-head.o: BOOTAFLAGS += -mcpu=405 @@ -86,6 +93,7 @@ src-plat-$(CONFIG_44x) += treeboot-ebony.c cuboot-ebony.c treeboot-bamboo.c \ cuboot-taishan.c cuboot-katmai.c \ cuboot-warp.c cuboot-yosemite.c \ treeboot-iss4xx.c treeboot-currituck.c \ + treeboot-akebono.c \ simpleboot.c fixed-head.S virtex.c src-plat-$(CONFIG_8xx) += cuboot-8xx.c fixed-head.S ep88xc.c redboot-8xx.c src-plat-$(CONFIG_PPC_MPC52xx) += cuboot-52xx.c @@ -99,6 +107,11 @@ src-plat-$(CONFIG_EMBEDDED6xx) += cuboot-pq2.c cuboot-mpc7448hpc2.c \ src-plat-$(CONFIG_AMIGAONE) += cuboot-amigaone.c src-plat-$(CONFIG_PPC_PS3) += ps3-head.S ps3-hvcall.S ps3.c src-plat-$(CONFIG_EPAPR_BOOT) += epapr.c epapr-wrapper.c +src-plat-$(CONFIG_PPC_PSERIES) += pseries-head.S +src-plat-$(CONFIG_PPC_POWERNV) += pseries-head.S +src-plat-$(CONFIG_PPC_IBM_CELL_BLADE) += pseries-head.S +src-plat-$(CONFIG_PPC_CELLEB) += pseries-head.S +src-plat-$(CONFIG_PPC_CELL_QPACE) += pseries-head.S src-wlib := $(sort $(src-wlib-y)) src-plat := $(sort $(src-plat-y)) @@ -137,7 +150,11 @@ $(addprefix $(obj)/,$(libfdt) $(libfdtheader)): $(obj)/%: $(srctree)/scripts/dtc $(obj)/empty.c: @touch $@ -$(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds: $(obj)/%: $(srctree)/$(src)/%.S +$(obj)/zImage.lds: $(obj)/%: $(srctree)/$(src)/%.S + $(CROSS32CC) $(cpp_flags) -E -Wp,-MD,$(depfile) -P -Upowerpc \ + -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $< + +$(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds : $(obj)/%: $(srctree)/$(src)/%.S @cp $< $@ clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \ @@ -235,6 +252,7 @@ image-$(CONFIG_YOSEMITE) += cuImage.yosemite image-$(CONFIG_ISS4xx) += treeImage.iss4xx \ treeImage.iss4xx-mpic image-$(CONFIG_CURRITUCK) += treeImage.currituck +image-$(CONFIG_AKEBONO) += treeImage.akebono # Board ports in arch/powerpc/platform/8xx/Kconfig image-$(CONFIG_MPC86XADS) += cuImage.mpc866ads diff --git a/arch/powerpc/boot/addnote.c b/arch/powerpc/boot/addnote.c index 349b5530d2c4c3..9d9f6f334d3cc0 100644 --- a/arch/powerpc/boot/addnote.c +++ b/arch/powerpc/boot/addnote.c @@ -6,6 +6,8 @@ * * Copyright 2000 Paul Mackerras. * + * Adapted for 64 bit little endian images by Andrew Tauferner. + * * 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 @@ -55,36 +57,61 @@ unsigned int rpanote[N_RPA_DESCR] = { #define ROUNDUP(len) (((len) + 3) & ~3) -unsigned char buf[512]; +unsigned char buf[1024]; +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 +static int e_data = ELFDATA2MSB; +#define ELFCLASS32 1 +#define ELFCLASS64 2 +static int e_class = ELFCLASS32; #define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) -#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2)) - -#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \ - buf[(off) + 1] = (v) & 0xff) -#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \ - PUT_16BE((off) + 2, (v))) +#define GET_32BE(off) ((GET_16BE(off) << 16U) + GET_16BE((off)+2U)) +#define GET_64BE(off) ((((unsigned long long)GET_32BE(off)) << 32ULL) + \ + ((unsigned long long)GET_32BE((off)+4ULL))) +#define PUT_16BE(off, v)(buf[off] = ((v) >> 8) & 0xff, \ + buf[(off) + 1] = (v) & 0xff) +#define PUT_32BE(off, v)(PUT_16BE((off), (v) >> 16L), PUT_16BE((off) + 2, (v))) +#define PUT_64BE(off, v)((PUT_32BE((off), (v) >> 32L), \ + PUT_32BE((off) + 4, (v)))) + +#define GET_16LE(off) ((buf[off]) + (buf[(off)+1] << 8)) +#define GET_32LE(off) (GET_16LE(off) + (GET_16LE((off)+2U) << 16U)) +#define GET_64LE(off) ((unsigned long long)GET_32LE(off) + \ + (((unsigned long long)GET_32LE((off)+4ULL)) << 32ULL)) +#define PUT_16LE(off, v) (buf[off] = (v) & 0xff, \ + buf[(off) + 1] = ((v) >> 8) & 0xff) +#define PUT_32LE(off, v) (PUT_16LE((off), (v)), PUT_16LE((off) + 2, (v) >> 16L)) +#define PUT_64LE(off, v) (PUT_32LE((off), (v)), PUT_32LE((off) + 4, (v) >> 32L)) + +#define GET_16(off) (e_data == ELFDATA2MSB ? GET_16BE(off) : GET_16LE(off)) +#define GET_32(off) (e_data == ELFDATA2MSB ? GET_32BE(off) : GET_32LE(off)) +#define GET_64(off) (e_data == ELFDATA2MSB ? GET_64BE(off) : GET_64LE(off)) +#define PUT_16(off, v) (e_data == ELFDATA2MSB ? PUT_16BE(off, v) : \ + PUT_16LE(off, v)) +#define PUT_32(off, v) (e_data == ELFDATA2MSB ? PUT_32BE(off, v) : \ + PUT_32LE(off, v)) +#define PUT_64(off, v) (e_data == ELFDATA2MSB ? PUT_64BE(off, v) : \ + PUT_64LE(off, v)) /* Structure of an ELF file */ #define E_IDENT 0 /* ELF header */ -#define E_PHOFF 28 -#define E_PHENTSIZE 42 -#define E_PHNUM 44 -#define E_HSIZE 52 /* size of ELF header */ +#define E_PHOFF (e_class == ELFCLASS32 ? 28 : 32) +#define E_PHENTSIZE (e_class == ELFCLASS32 ? 42 : 54) +#define E_PHNUM (e_class == ELFCLASS32 ? 44 : 56) +#define E_HSIZE (e_class == ELFCLASS32 ? 52 : 64) #define EI_MAGIC 0 /* offsets in E_IDENT area */ #define EI_CLASS 4 #define EI_DATA 5 #define PH_TYPE 0 /* ELF program header */ -#define PH_OFFSET 4 -#define PH_FILESZ 16 -#define PH_HSIZE 32 /* size of program header */ +#define PH_OFFSET (e_class == ELFCLASS32 ? 4 : 8) +#define PH_FILESZ (e_class == ELFCLASS32 ? 16 : 32) +#define PH_HSIZE (e_class == ELFCLASS32 ? 32 : 56) #define PT_NOTE 4 /* Program header type = note */ -#define ELFCLASS32 1 -#define ELFDATA2MSB 2 unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; @@ -92,8 +119,8 @@ int main(int ac, char **av) { int fd, n, i; - int ph, ps, np; - int nnote, nnote2, ns; + unsigned long ph, ps, np; + long nnote, nnote2, ns; if (ac != 2) { fprintf(stderr, "Usage: %s elf-file\n", av[0]); @@ -114,26 +141,27 @@ main(int ac, char **av) exit(1); } - if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0) + if (memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0) + goto notelf; + e_class = buf[E_IDENT+EI_CLASS]; + if (e_class != ELFCLASS32 && e_class != ELFCLASS64) + goto notelf; + e_data = buf[E_IDENT+EI_DATA]; + if (e_data != ELFDATA2MSB && e_data != ELFDATA2LSB) + goto notelf; + if (n < E_HSIZE) goto notelf; - if (buf[E_IDENT+EI_CLASS] != ELFCLASS32 - || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) { - fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", - av[1]); - exit(1); - } - - ph = GET_32BE(E_PHOFF); - ps = GET_16BE(E_PHENTSIZE); - np = GET_16BE(E_PHNUM); + ph = (e_class == ELFCLASS32 ? GET_32(E_PHOFF) : GET_64(E_PHOFF)); + ps = GET_16(E_PHENTSIZE); + np = GET_16(E_PHNUM); if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) goto notelf; if (ph + (np + 2) * ps + nnote + nnote2 > n) goto nospace; for (i = 0; i < np; ++i) { - if (GET_32BE(ph + PH_TYPE) == PT_NOTE) { + if (GET_32(ph + PH_TYPE) == PT_NOTE) { fprintf(stderr, "%s already has a note entry\n", av[1]); exit(0); @@ -148,15 +176,22 @@ main(int ac, char **av) /* fill in the program header entry */ ns = ph + 2 * ps; - PUT_32BE(ph + PH_TYPE, PT_NOTE); - PUT_32BE(ph + PH_OFFSET, ns); - PUT_32BE(ph + PH_FILESZ, nnote); + PUT_32(ph + PH_TYPE, PT_NOTE); + if (e_class == ELFCLASS32) + PUT_32(ph + PH_OFFSET, ns); + else + PUT_64(ph + PH_OFFSET, ns); + + if (e_class == ELFCLASS32) + PUT_32(ph + PH_FILESZ, nnote); + else + PUT_64(ph + PH_FILESZ, nnote); /* fill in the note area we point to */ /* XXX we should probably make this a proper section */ - PUT_32BE(ns, strlen(arch) + 1); - PUT_32BE(ns + 4, N_DESCR * 4); - PUT_32BE(ns + 8, 0x1275); + PUT_32(ns, strlen(arch) + 1); + PUT_32(ns + 4, N_DESCR * 4); + PUT_32(ns + 8, 0x1275); strcpy((char *) &buf[ns + 12], arch); ns += 12 + strlen(arch) + 1; for (i = 0; i < N_DESCR; ++i, ns += 4) @@ -164,21 +199,28 @@ main(int ac, char **av) /* fill in the second program header entry and the RPA note area */ ph += ps; - PUT_32BE(ph + PH_TYPE, PT_NOTE); - PUT_32BE(ph + PH_OFFSET, ns); - PUT_32BE(ph + PH_FILESZ, nnote2); + PUT_32(ph + PH_TYPE, PT_NOTE); + if (e_class == ELFCLASS32) + PUT_32(ph + PH_OFFSET, ns); + else + PUT_64(ph + PH_OFFSET, ns); + + if (e_class == ELFCLASS32) + PUT_32(ph + PH_FILESZ, nnote); + else + PUT_64(ph + PH_FILESZ, nnote2); /* fill in the note area we point to */ - PUT_32BE(ns, strlen(rpaname) + 1); - PUT_32BE(ns + 4, sizeof(rpanote)); - PUT_32BE(ns + 8, 0x12759999); + PUT_32(ns, strlen(rpaname) + 1); + PUT_32(ns + 4, sizeof(rpanote)); + PUT_32(ns + 8, 0x12759999); strcpy((char *) &buf[ns + 12], rpaname); ns += 12 + ROUNDUP(strlen(rpaname) + 1); for (i = 0; i < N_RPA_DESCR; ++i, ns += 4) PUT_32BE(ns, rpanote[i]); /* Update the number of program headers */ - PUT_16BE(E_PHNUM, np + 2); + PUT_16(E_PHNUM, np + 2); /* write back */ lseek(fd, (long) 0, SEEK_SET); diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S index 0f7428a37efbeb..14de4f8778a7fa 100644 --- a/arch/powerpc/boot/crt0.S +++ b/arch/powerpc/boot/crt0.S @@ -1,17 +1,20 @@ /* * Copyright (C) Paul Mackerras 1997. * + * Adapted for 64 bit LE PowerPC by Andrew Tauferner + * * 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. * - * NOTE: this code runs in 32 bit mode, is position-independent, - * and is packaged as ELF32. */ #include "ppc_asm.h" +RELA = 7 +RELACOUNT = 0x6ffffff9 + .text /* A procedure descriptor used when booting this as a COFF file. * When making COFF, this comes first in the link and we're @@ -21,6 +24,20 @@ _zimage_start_opd: .long 0x500000, 0, 0, 0 +#ifdef __powerpc64__ +.balign 8 +p_start: .llong _start +p_etext: .llong _etext +p_bss_start: .llong __bss_start +p_end: .llong _end + +p_toc: .llong __toc_start + 0x8000 - p_base +p_dyn: .llong __dynamic_start - p_base +p_rela: .llong __rela_dyn_start - p_base +p_prom: .llong 0 + .weak _platform_stack_top +p_pstack: .llong _platform_stack_top +#else p_start: .long _start p_etext: .long _etext p_bss_start: .long __bss_start @@ -28,6 +45,7 @@ p_end: .long _end .weak _platform_stack_top p_pstack: .long _platform_stack_top +#endif .weak _zimage_start .globl _zimage_start @@ -38,6 +56,7 @@ _zimage_start_lib: and the address where we're running. */ bl .+4 p_base: mflr r10 /* r10 now points to runtime addr of p_base */ +#ifndef __powerpc64__ /* grab the link address of the dynamic section in r11 */ addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11) @@ -51,8 +70,6 @@ p_base: mflr r10 /* r10 now points to runtime addr of p_base */ /* The dynamic section contains a series of tagged entries. * We need the RELA and RELACOUNT entries. */ -RELA = 7 -RELACOUNT = 0x6ffffff9 li r9,0 li r0,0 9: lwz r8,0(r12) /* get tag */ @@ -120,9 +137,164 @@ RELACOUNT = 0x6ffffff9 li r0,0 stwu r0,-16(r1) /* establish a stack frame */ 6: +#else /* __powerpc64__ */ + /* Save the prom pointer at p_prom. */ + std r5,(p_prom-p_base)(r10) + + /* Set r2 to the TOC. */ + ld r2,(p_toc-p_base)(r10) + add r2,r2,r10 + + /* Grab the link address of the dynamic section in r11. */ + ld r11,-32768(r2) + cmpwi r11,0 + beq 3f /* if not linked -pie then no dynamic section */ + + ld r11,(p_dyn-p_base)(r10) + add r11,r11,r10 + ld r9,(p_rela-p_base)(r10) + add r9,r9,r10 + li r7,0 + li r8,0 +9: ld r6,0(r11) /* get tag */ + cmpdi r6,0 + beq 12f /* end of list */ + cmpdi r6,RELA + bne 10f + ld r7,8(r11) /* get RELA pointer in r7 */ + b 11f +10: addis r6,r6,(-RELACOUNT)@ha + cmpdi r6,RELACOUNT@l + bne 11f + ld r8,8(r11) /* get RELACOUNT value in r8 */ +11: addi r11,r11,16 + b 9b +12: + cmpdi r7,0 /* check we have both RELA and RELACOUNT */ + cmpdi cr1,r8,0 + beq 3f + beq cr1,3f + + /* Calcuate the runtime offset. */ + subf r7,r7,r9 + + /* Run through the list of relocations and process the + * R_PPC64_RELATIVE ones. */ + mtctr r8 +13: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */ + cmpdi r0,22 /* R_PPC64_RELATIVE */ + bne 3f + ld r6,0(r9) /* reloc->r_offset */ + ld r0,16(r9) /* reloc->r_addend */ + add r0,r0,r7 + stdx r0,r7,r6 + addi r9,r9,24 + bdnz 13b + + /* Do a cache flush for our text, in case the loader didn't */ +3: ld r9,p_start-p_base(r10) /* note: these are relocated now */ + ld r8,p_etext-p_base(r10) +4: dcbf r0,r9 + icbi r0,r9 + addi r9,r9,0x20 + cmpld cr0,r9,r8 + blt 4b + sync + isync + + /* Clear the BSS */ + ld r9,p_bss_start-p_base(r10) + ld r8,p_end-p_base(r10) + li r0,0 +5: std r0,0(r9) + addi r9,r9,8 + cmpld cr0,r9,r8 + blt 5b + + /* Possibly set up a custom stack */ + ld r8,p_pstack-p_base(r10) + cmpdi r8,0 + beq 6f + ld r1,0(r8) + li r0,0 + stdu r0,-16(r1) /* establish a stack frame */ +6: +#endif /* __powerpc64__ */ /* Call platform_init() */ bl platform_init /* Call start */ b start + +#ifdef __powerpc64__ + +#define PROM_FRAME_SIZE 512 +#define SAVE_GPR(n, base) std n,8*(n)(base) +#define REST_GPR(n, base) ld n,8*(n)(base) +#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) +#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) +#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) +#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) +#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) +#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) +#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) +#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) + +/* prom handles the jump into and return from firmware. The prom args pointer + is loaded in r3. */ +.globl prom +prom: + mflr r0 + std r0,16(r1) + stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ + + SAVE_GPR(2, r1) + SAVE_GPR(13, r1) + SAVE_8GPRS(14, r1) + SAVE_10GPRS(22, r1) + mfcr r10 + std r10,8*32(r1) + mfmsr r10 + std r10,8*33(r1) + + /* remove MSR_LE from msr but keep MSR_SF */ + mfmsr r10 + rldicr r10,r10,0,62 + mtsrr1 r10 + + /* Load FW address, set LR to label 1, and jump to FW */ + bl 0f +0: mflr r10 + addi r11,r10,(1f-0b) + mtlr r11 + + ld r10,(p_prom-0b)(r10) + mtsrr0 r10 + + rfid + +1: /* Return from OF */ + FIXUP_ENDIAN + + /* Restore registers and return. */ + rldicl r1,r1,0,32 + + /* Restore the MSR (back to 64 bits) */ + ld r10,8*(33)(r1) + mtmsr r10 + isync + + /* Restore other registers */ + REST_GPR(2, r1) + REST_GPR(13, r1) + REST_8GPRS(14, r1) + REST_10GPRS(22, r1) + ld r10,8*32(r1) + mtcr r10 + + addi r1,r1,PROM_FRAME_SIZE + ld r0,16(r1) + mtlr r0 + blr +#endif diff --git a/arch/powerpc/boot/dcr.h b/arch/powerpc/boot/dcr.h index cc73f7a95e26c4..bf8f4ede192851 100644 --- a/arch/powerpc/boot/dcr.h +++ b/arch/powerpc/boot/dcr.h @@ -15,6 +15,10 @@ asm volatile("mfdcrx %0,%1" : "=r"(rval) : "r"(rn)); \ rval; \ }) +#define mtdcrx(rn, val) \ + ({ \ + asm volatile("mtdcrx %0,%1" : : "r"(rn), "r" (val)); \ + }) /* 440GP/440GX SDRAM controller DCRs */ #define DCRN_SDRAM0_CFGADDR 0x010 diff --git a/arch/powerpc/boot/dts/akebono.dts b/arch/powerpc/boot/dts/akebono.dts new file mode 100644 index 00000000000000..f92ecfed3d2f6c --- /dev/null +++ b/arch/powerpc/boot/dts/akebono.dts @@ -0,0 +1,415 @@ +/* + * Device Tree Source for IBM Embedded PPC 476 Platform + * + * Copyright © 2013 Tony Breeds IBM Corporation + * Copyright © 2013 Alistair Popple IBM Corporation + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + */ + +/dts-v1/; + +/memreserve/ 0x01f00000 0x00100000; // spin table + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "ibm,akebono"; + compatible = "ibm,akebono", "ibm,476gtr"; + dcr-parent = <&{/cpus/cpu@0}>; + + aliases { + serial0 = &UART0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + model = "PowerPC,476"; + reg = <0>; + clock-frequency = <1600000000>; // 1.6 GHz + timebase-frequency = <100000000>; // 100Mhz + i-cache-line-size = <32>; + d-cache-line-size = <32>; + i-cache-size = <32768>; + d-cache-size = <32768>; + dcr-controller; + dcr-access-method = "native"; + status = "ok"; + }; + cpu@1 { + device_type = "cpu"; + model = "PowerPC,476"; + reg = <1>; + clock-frequency = <1600000000>; // 1.6 GHz + timebase-frequency = <100000000>; // 100Mhz + i-cache-line-size = <32>; + d-cache-line-size = <32>; + i-cache-size = <32768>; + d-cache-size = <32768>; + dcr-controller; + dcr-access-method = "native"; + status = "disabled"; + enable-method = "spin-table"; + cpu-release-addr = <0x0 0x01f00000>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x0>; // filled in by zImage + }; + + MPIC: interrupt-controller { + compatible = "chrp,open-pic"; + interrupt-controller; + dcr-reg = <0xffc00000 0x00040000>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + single-cpu-affinity; + }; + + plb { + compatible = "ibm,plb6"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + clock-frequency = <200000000>; // 200Mhz + + HSTA0: hsta@310000e0000 { + compatible = "ibm,476gtr-hsta-msi", "ibm,hsta-msi"; + reg = <0x310 0x000e0000 0x0 0xf0>; + interrupt-parent = <&MPIC>; + interrupts = <108 0 + 109 0 + 110 0 + 111 0 + 112 0 + 113 0 + 114 0 + 115 0 + 116 0 + 117 0 + 118 0 + 119 0 + 120 0 + 121 0 + 122 0 + 123 0>; + }; + + MAL0: mcmal { + compatible = "ibm,mcmal-476gtr", "ibm,mcmal2"; + dcr-reg = <0xc0000000 0x062>; + num-tx-chans = <1>; + num-rx-chans = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-parent = <&MPIC>; + interrupts = < /*TXEOB*/ 77 0x4 + /*RXEOB*/ 78 0x4 + /*SERR*/ 76 0x4 + /*TXDE*/ 79 0x4 + /*RXDE*/ 80 0x4>; + }; + + SATA0: sata@30000010000 { + compatible = "ibm,476gtr-ahci"; + reg = <0x300 0x00010000 0x0 0x10000>; + interrupt-parent = <&MPIC>; + interrupts = <93 2>; + }; + + EHCI0: ehci@30010000000 { + compatible = "ibm,476gtr-ehci", "generic-ehci"; + reg = <0x300 0x10000000 0x0 0x10000>; + interrupt-parent = <&MPIC>; + interrupts = <85 2>; + }; + + SD0: sd@30000000000 { + compatible = "ibm,476gtr-sdhci", "generic-sdhci"; + reg = <0x300 0x00000000 0x0 0x10000>; + interrupts = <91 2>; + interrupt-parent = <&MPIC>; + }; + + OHCI0: ohci@30010010000 { + compatible = "ibm,476gtr-ohci", "generic-ohci"; + reg = <0x300 0x10010000 0x0 0x10000>; + interrupt-parent = <&MPIC>; + interrupts = <89 1>; + }; + + OHCI1: ohci@30010020000 { + compatible = "ibm,476gtr-ohci", "generic-ohci"; + reg = <0x300 0x10020000 0x0 0x10000>; + interrupt-parent = <&MPIC>; + interrupts = <88 1>; + }; + + POB0: opb { + compatible = "ibm,opb-4xx", "ibm,opb"; + #address-cells = <1>; + #size-cells = <1>; + /* Wish there was a nicer way of specifying a full + * 32-bit range + */ + ranges = <0x00000000 0x0000033f 0x00000000 0x80000000 + 0x80000000 0x0000033f 0x80000000 0x80000000>; + clock-frequency = <100000000>; + + RGMII0: emac-rgmii-wol@50004 { + compatible = "ibm,rgmii-wol-476gtr", "ibm,rgmii-wol"; + reg = <0x50004 0x00000008>; + has-mdio; + }; + + EMAC0: ethernet@30000 { + device_type = "network"; + compatible = "ibm,emac-476gtr", "ibm,emac4sync"; + interrupt-parent = <&EMAC0>; + interrupts = <0x0 0x1>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = ; + reg = <0x30000 0x78>; + + /* local-mac-address will normally be added by + * the wrapper. If your device doesn't support + * passing data to the wrapper (in the form + * local-mac-addr=) then you will need + * to set it manually here. */ + //local-mac-address = [000000000000]; + + mal-device = <&MAL0>; + mal-tx-channel = <0>; + mal-rx-channel = <0>; + cell-index = <0>; + max-frame-size = <9000>; + rx-fifo-size = <4096>; + tx-fifo-size = <2048>; + rx-fifo-size-gige = <16384>; + phy-mode = "rgmii"; + phy-map = <0x00000000>; + rgmii-wol-device = <&RGMII0>; + has-inverted-stacr-oc; + has-new-stacr-staopc; + }; + + UART0: serial@10000 { + device_type = "serial"; + compatible = "ns16750", "ns16550"; + reg = <0x10000 0x00000008>; + virtual-reg = <0xe8010000>; + clock-frequency = <1851851>; + current-speed = <38400>; + interrupt-parent = <&MPIC>; + interrupts = <39 2>; + }; + + IIC0: i2c@00000000 { + compatible = "ibm,iic-476gtr", "ibm,iic"; + reg = <0x0 0x00000020>; + interrupt-parent = <&MPIC>; + interrupts = <37 2>; + #address-cells = <1>; + #size-cells = <0>; + rtc@68 { + compatible = "stm,m41t80", "m41st85"; + reg = <0x68>; + }; + }; + + IIC1: i2c@00000100 { + compatible = "ibm,iic-476gtr", "ibm,iic"; + reg = <0x100 0x00000020>; + interrupt-parent = <&MPIC>; + interrupts = <38 2>; + #address-cells = <1>; + #size-cells = <0>; + avr@58 { + compatible = "ibm,akebono-avr"; + reg = <0x58>; + }; + }; + + FPGA0: fpga@ebc00000 { + compatible = "ibm,akebono-fpga"; + reg = <0xebc00000 0x8>; + }; + }; + + PCIE0: pciex@10100000000 { + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "ibm,plb-pciex-476fpe", "ibm,plb-pciex"; + primary; + port = <0x0>; /* port number */ + reg = <0x00000101 0x00000000 0x0 0x10000000 /* Config space access */ + 0x00000100 0x00000000 0x0 0x00001000>; /* UTL Registers space access */ + dcr-reg = <0xc0 0x20>; + +// pci_space < pci_addr > < cpu_addr > < size > + ranges = <0x02000000 0x00000000 0x80000000 0x00000110 0x80000000 0x0 0x80000000 + 0x01000000 0x0 0x0 0x00000140 0x0 0x0 0x00010000>; + + /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI + * PCI devices must be able to write to the HSTA module. + */ + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>; + + /* This drives busses 0 to 0xf */ + bus-range = <0x0 0xf>; + + /* Legacy interrupts (note the weird polarity, the bridge seems + * to invert PCIe legacy interrupts). + * We are de-swizzling here because the numbers are actually for + * port of the root complex virtual P2P bridge. But I want + * to avoid putting a node for it in the tree, so the numbers + * below are basically de-swizzled numbers. + * The real slot is on idsel 0, so the swizzling is 1:1 + */ + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = < + 0x0 0x0 0x0 0x1 &MPIC 45 0x2 /* int A */ + 0x0 0x0 0x0 0x2 &MPIC 46 0x2 /* int B */ + 0x0 0x0 0x0 0x3 &MPIC 47 0x2 /* int C */ + 0x0 0x0 0x0 0x4 &MPIC 48 0x2 /* int D */>; + }; + + PCIE1: pciex@20100000000 { + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "ibm,plb-pciex-476fpe", "ibm,plb-pciex"; + primary; + port = <0x1>; /* port number */ + reg = <0x00000201 0x00000000 0x0 0x10000000 /* Config space access */ + 0x00000200 0x00000000 0x0 0x00001000>; /* UTL Registers space access */ + dcr-reg = <0x100 0x20>; + +// pci_space < pci_addr > < cpu_addr > < size > + ranges = <0x02000000 0x00000000 0x80000000 0x00000210 0x80000000 0x0 0x80000000 + 0x01000000 0x0 0x0 0x00000240 0x0 0x0 0x00010000>; + + /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI + * PCI devices must be able to write to the HSTA module. + */ + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>; + + /* This drives busses 0 to 0xf */ + bus-range = <0x0 0xf>; + + /* Legacy interrupts (note the weird polarity, the bridge seems + * to invert PCIe legacy interrupts). + * We are de-swizzling here because the numbers are actually for + * port of the root complex virtual P2P bridge. But I want + * to avoid putting a node for it in the tree, so the numbers + * below are basically de-swizzled numbers. + * The real slot is on idsel 0, so the swizzling is 1:1 + */ + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = < + 0x0 0x0 0x0 0x1 &MPIC 53 0x2 /* int A */ + 0x0 0x0 0x0 0x2 &MPIC 54 0x2 /* int B */ + 0x0 0x0 0x0 0x3 &MPIC 55 0x2 /* int C */ + 0x0 0x0 0x0 0x4 &MPIC 56 0x2 /* int D */>; + }; + + PCIE2: pciex@18100000000 { + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "ibm,plb-pciex-476fpe", "ibm,plb-pciex"; + primary; + port = <0x2>; /* port number */ + reg = <0x00000181 0x00000000 0x0 0x10000000 /* Config space access */ + 0x00000180 0x00000000 0x0 0x00001000>; /* UTL Registers space access */ + dcr-reg = <0xe0 0x20>; + +// pci_space < pci_addr > < cpu_addr > < size > + ranges = <0x02000000 0x00000000 0x80000000 0x00000190 0x80000000 0x0 0x80000000 + 0x01000000 0x0 0x0 0x000001c0 0x0 0x0 0x00010000>; + + /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI + * PCI devices must be able to write to the HSTA module. + */ + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>; + + /* This drives busses 0 to 0xf */ + bus-range = <0x0 0xf>; + + /* Legacy interrupts (note the weird polarity, the bridge seems + * to invert PCIe legacy interrupts). + * We are de-swizzling here because the numbers are actually for + * port of the root complex virtual P2P bridge. But I want + * to avoid putting a node for it in the tree, so the numbers + * below are basically de-swizzled numbers. + * The real slot is on idsel 0, so the swizzling is 1:1 + */ + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = < + 0x0 0x0 0x0 0x1 &MPIC 61 0x2 /* int A */ + 0x0 0x0 0x0 0x2 &MPIC 62 0x2 /* int B */ + 0x0 0x0 0x0 0x3 &MPIC 63 0x2 /* int C */ + 0x0 0x0 0x0 0x4 &MPIC 64 0x2 /* int D */>; + }; + + PCIE3: pciex@28100000000 { + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "ibm,plb-pciex-476fpe", "ibm,plb-pciex"; + primary; + port = <0x3>; /* port number */ + reg = <0x00000281 0x00000000 0x0 0x10000000 /* Config space access */ + 0x00000280 0x00000000 0x0 0x00001000>; /* UTL Registers space access */ + dcr-reg = <0x120 0x20>; + +// pci_space < pci_addr > < cpu_addr > < size > + ranges = <0x02000000 0x00000000 0x80000000 0x00000290 0x80000000 0x0 0x80000000 + 0x01000000 0x0 0x0 0x000002c0 0x0 0x0 0x00010000>; + + /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI + * PCI devices must be able to write to the HSTA module. + */ + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>; + + /* This drives busses 0 to 0xf */ + bus-range = <0x0 0xf>; + + /* Legacy interrupts (note the weird polarity, the bridge seems + * to invert PCIe legacy interrupts). + * We are de-swizzling here because the numbers are actually for + * port of the root complex virtual P2P bridge. But I want + * to avoid putting a node for it in the tree, so the numbers + * below are basically de-swizzled numbers. + * The real slot is on idsel 0, so the swizzling is 1:1 + */ + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = < + 0x0 0x0 0x0 0x1 &MPIC 69 0x2 /* int A */ + 0x0 0x0 0x0 0x2 &MPIC 70 0x2 /* int B */ + 0x0 0x0 0x0 0x3 &MPIC 71 0x2 /* int C */ + 0x0 0x0 0x0 0x4 &MPIC 72 0x2 /* int D */>; + }; + }; + + chosen { + linux,stdout-path = &UART0; + }; +}; diff --git a/arch/powerpc/boot/dts/mpc8308_p1m.dts b/arch/powerpc/boot/dts/mpc8308_p1m.dts index 651e4f55acdbf6..57f86cdf9f36e4 100644 --- a/arch/powerpc/boot/dts/mpc8308_p1m.dts +++ b/arch/powerpc/boot/dts/mpc8308_p1m.dts @@ -296,7 +296,7 @@ }; dma@2c000 { - compatible = "fsl,mpc8308-dma", "fsl,mpc5121-dma"; + compatible = "fsl,mpc8308-dma"; reg = <0x2c000 0x1800>; interrupts = <3 0x8 94 0x8>; diff --git a/arch/powerpc/boot/dts/mpc8308rdb.dts b/arch/powerpc/boot/dts/mpc8308rdb.dts index 9ce45f2efd3490..d0211f0413c646 100644 --- a/arch/powerpc/boot/dts/mpc8308rdb.dts +++ b/arch/powerpc/boot/dts/mpc8308rdb.dts @@ -265,7 +265,7 @@ }; dma@2c000 { - compatible = "fsl,mpc8308-dma", "fsl,mpc5121-dma"; + compatible = "fsl,mpc8308-dma"; reg = <0x2c000 0x1800>; interrupts = <3 0x8 94 0x8>; diff --git a/arch/powerpc/boot/elf_util.c b/arch/powerpc/boot/elf_util.c index 1567a0c0f05c66..316552dea4d8c2 100644 --- a/arch/powerpc/boot/elf_util.c +++ b/arch/powerpc/boot/elf_util.c @@ -26,7 +26,11 @@ int parse_elf64(void *hdr, struct elf_info *info) elf64->e_ident[EI_MAG2] == ELFMAG2 && elf64->e_ident[EI_MAG3] == ELFMAG3 && elf64->e_ident[EI_CLASS] == ELFCLASS64 && +#ifdef __LITTLE_ENDIAN__ + elf64->e_ident[EI_DATA] == ELFDATA2LSB && +#else elf64->e_ident[EI_DATA] == ELFDATA2MSB && +#endif (elf64->e_type == ET_EXEC || elf64->e_type == ET_DYN) && elf64->e_machine == EM_PPC64)) diff --git a/arch/powerpc/boot/of.c b/arch/powerpc/boot/of.c index 62e2f43ec1df11..7ca910cb2fc64f 100644 --- a/arch/powerpc/boot/of.c +++ b/arch/powerpc/boot/of.c @@ -40,8 +40,8 @@ static void *of_try_claim(unsigned long size) #ifdef DEBUG printf(" trying: 0x%08lx\n\r", claim_base); #endif - addr = (unsigned long)of_claim(claim_base, size, 0); - if ((void *)addr != (void *)-1) + addr = (unsigned long) of_claim(claim_base, size, 0); + if (addr != PROM_ERROR) break; } if (addr == 0) diff --git a/arch/powerpc/boot/of.h b/arch/powerpc/boot/of.h index e4c68f7391c5c4..c8c1750aba0cc2 100644 --- a/arch/powerpc/boot/of.h +++ b/arch/powerpc/boot/of.h @@ -1,12 +1,15 @@ #ifndef _PPC_BOOT_OF_H_ #define _PPC_BOOT_OF_H_ +#include "swab.h" + typedef void *phandle; -typedef void *ihandle; +typedef u32 ihandle; void of_init(void *promptr); int of_call_prom(const char *service, int nargs, int nret, ...); -void *of_claim(unsigned long virt, unsigned long size, unsigned long align); +unsigned int of_claim(unsigned long virt, unsigned long size, + unsigned long align); void *of_vmlinux_alloc(unsigned long size); void of_exit(void); void *of_finddevice(const char *name); @@ -18,4 +21,16 @@ int of_setprop(const void *phandle, const char *name, const void *buf, /* Console functions */ void of_console_init(void); +typedef u32 __be32; + +#ifdef __LITTLE_ENDIAN__ +#define cpu_to_be32(x) swab32(x) +#define be32_to_cpu(x) swab32(x) +#else +#define cpu_to_be32(x) (x) +#define be32_to_cpu(x) (x) +#endif + +#define PROM_ERROR (-1u) + #endif /* _PPC_BOOT_OF_H_ */ diff --git a/arch/powerpc/boot/ofconsole.c b/arch/powerpc/boot/ofconsole.c index ce0e0242445325..8b754702460aee 100644 --- a/arch/powerpc/boot/ofconsole.c +++ b/arch/powerpc/boot/ofconsole.c @@ -18,7 +18,7 @@ #include "of.h" -static void *of_stdout_handle; +static unsigned int of_stdout_handle; static int of_console_open(void) { @@ -27,8 +27,10 @@ static int of_console_open(void) if (((devp = of_finddevice("/chosen")) != NULL) && (of_getprop(devp, "stdout", &of_stdout_handle, sizeof(of_stdout_handle)) - == sizeof(of_stdout_handle))) + == sizeof(of_stdout_handle))) { + of_stdout_handle = be32_to_cpu(of_stdout_handle); return 0; + } return -1; } diff --git a/arch/powerpc/boot/oflib.c b/arch/powerpc/boot/oflib.c index b0ec9cf3eaaf6e..46c98a47d9493a 100644 --- a/arch/powerpc/boot/oflib.c +++ b/arch/powerpc/boot/oflib.c @@ -16,74 +16,83 @@ #include "of.h" +typedef u32 prom_arg_t; + +/* The following structure is used to communicate with open firmware. + * All arguments in and out are in big endian format. */ +struct prom_args { + __be32 service; /* Address of service name string. */ + __be32 nargs; /* Number of input arguments. */ + __be32 nret; /* Number of output arguments. */ + __be32 args[10]; /* Input/output arguments. */ +}; + +#ifdef __powerpc64__ +extern int prom(void *); +#else static int (*prom) (void *); +#endif void of_init(void *promptr) { +#ifndef __powerpc64__ prom = (int (*)(void *))promptr; +#endif } +#define ADDR(x) (u32)(unsigned long)(x) + int of_call_prom(const char *service, int nargs, int nret, ...) { int i; - struct prom_args { - const char *service; - int nargs; - int nret; - unsigned int args[12]; - } args; + struct prom_args args; va_list list; - args.service = service; - args.nargs = nargs; - args.nret = nret; + args.service = cpu_to_be32(ADDR(service)); + args.nargs = cpu_to_be32(nargs); + args.nret = cpu_to_be32(nret); va_start(list, nret); for (i = 0; i < nargs; i++) - args.args[i] = va_arg(list, unsigned int); + args.args[i] = cpu_to_be32(va_arg(list, prom_arg_t)); va_end(list); for (i = 0; i < nret; i++) args.args[nargs+i] = 0; if (prom(&args) < 0) - return -1; + return PROM_ERROR; - return (nret > 0)? args.args[nargs]: 0; + return (nret > 0) ? be32_to_cpu(args.args[nargs]) : 0; } static int of_call_prom_ret(const char *service, int nargs, int nret, - unsigned int *rets, ...) + prom_arg_t *rets, ...) { int i; - struct prom_args { - const char *service; - int nargs; - int nret; - unsigned int args[12]; - } args; + struct prom_args args; va_list list; - args.service = service; - args.nargs = nargs; - args.nret = nret; + args.service = cpu_to_be32(ADDR(service)); + args.nargs = cpu_to_be32(nargs); + args.nret = cpu_to_be32(nret); va_start(list, rets); for (i = 0; i < nargs; i++) - args.args[i] = va_arg(list, unsigned int); + args.args[i] = cpu_to_be32(va_arg(list, prom_arg_t)); va_end(list); for (i = 0; i < nret; i++) args.args[nargs+i] = 0; if (prom(&args) < 0) - return -1; + return PROM_ERROR; - if (rets != (void *) 0) + if (rets != NULL) for (i = 1; i < nret; ++i) - rets[i-1] = args.args[nargs+i]; + rets[i-1] = be32_to_cpu(args.args[nargs+i]); - return (nret > 0)? args.args[nargs]: 0; + return (nret > 0) ? be32_to_cpu(args.args[nargs]) : 0; } /* returns true if s2 is a prefix of s1 */ @@ -103,7 +112,7 @@ static int string_match(const char *s1, const char *s2) */ static int need_map = -1; static ihandle chosen_mmu; -static phandle memory; +static ihandle memory; static int check_of_version(void) { @@ -132,10 +141,10 @@ static int check_of_version(void) printf("no mmu\n"); return 0; } - memory = (ihandle) of_call_prom("open", 1, 1, "/memory"); - if (memory == (ihandle) -1) { - memory = (ihandle) of_call_prom("open", 1, 1, "/memory@0"); - if (memory == (ihandle) -1) { + memory = of_call_prom("open", 1, 1, "/memory"); + if (memory == PROM_ERROR) { + memory = of_call_prom("open", 1, 1, "/memory@0"); + if (memory == PROM_ERROR) { printf("no memory node\n"); return 0; } @@ -144,40 +153,41 @@ static int check_of_version(void) return 1; } -void *of_claim(unsigned long virt, unsigned long size, unsigned long align) +unsigned int of_claim(unsigned long virt, unsigned long size, + unsigned long align) { int ret; - unsigned int result; + prom_arg_t result; if (need_map < 0) need_map = check_of_version(); if (align || !need_map) - return (void *) of_call_prom("claim", 3, 1, virt, size, align); + return of_call_prom("claim", 3, 1, virt, size, align); ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", memory, align, size, virt); if (ret != 0 || result == -1) - return (void *) -1; + return -1; ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu, align, size, virt); /* 0x12 == coherent + read/write */ ret = of_call_prom("call-method", 6, 1, "map", chosen_mmu, 0x12, size, virt, virt); - return (void *) virt; + return virt; } void *of_vmlinux_alloc(unsigned long size) { unsigned long start = (unsigned long)_start, end = (unsigned long)_end; - void *addr; + unsigned long addr; void *p; /* With some older POWER4 firmware we need to claim the area the kernel * will reside in. Newer firmwares don't need this so we just ignore * the return value. */ - addr = of_claim(start, end - start, 0); - printf("Trying to claim from 0x%lx to 0x%lx (0x%lx) got %p\r\n", + addr = (unsigned long) of_claim(start, end - start, 0); + printf("Trying to claim from 0x%lx to 0x%lx (0x%lx) got %lx\r\n", start, end, end - start, addr); p = malloc(size); @@ -197,7 +207,7 @@ void of_exit(void) */ void *of_finddevice(const char *name) { - return (phandle) of_call_prom("finddevice", 1, 1, name); + return (void *) (unsigned long) of_call_prom("finddevice", 1, 1, name); } int of_getprop(const void *phandle, const char *name, void *buf, diff --git a/arch/powerpc/boot/ppc_asm.h b/arch/powerpc/boot/ppc_asm.h index eb0e98be69e0bc..35ea60c1f07020 100644 --- a/arch/powerpc/boot/ppc_asm.h +++ b/arch/powerpc/boot/ppc_asm.h @@ -62,4 +62,16 @@ #define SPRN_TBRL 268 #define SPRN_TBRU 269 +#define FIXUP_ENDIAN \ + tdi 0, 0, 0x48; /* Reverse endian of b . + 8 */ \ + b $+36; /* Skip trampoline if endian is good */ \ + .long 0x05009f42; /* bcl 20,31,$+4 */ \ + .long 0xa602487d; /* mflr r10 */ \ + .long 0x1c004a39; /* addi r10,r10,28 */ \ + .long 0xa600607d; /* mfmsr r11 */ \ + .long 0x01006b69; /* xori r11,r11,1 */ \ + .long 0xa6035a7d; /* mtsrr0 r10 */ \ + .long 0xa6037b7d; /* mtsrr1 r11 */ \ + .long 0x2400004c /* rfid */ + #endif /* _PPC64_PPC_ASM_H */ diff --git a/arch/powerpc/boot/pseries-head.S b/arch/powerpc/boot/pseries-head.S new file mode 100644 index 00000000000000..6ef6e02e80f92c --- /dev/null +++ b/arch/powerpc/boot/pseries-head.S @@ -0,0 +1,8 @@ +#include "ppc_asm.h" + + .text + + .globl _zimage_start +_zimage_start: + FIXUP_ENDIAN + b _zimage_start_lib diff --git a/arch/powerpc/boot/stdio.c b/arch/powerpc/boot/stdio.c index 5b57800bbc675e..a701261b178181 100644 --- a/arch/powerpc/boot/stdio.c +++ b/arch/powerpc/boot/stdio.c @@ -21,6 +21,18 @@ size_t strnlen(const char * s, size_t count) return sc - s; } +#ifdef __powerpc64__ + +# define do_div(n, base) ({ \ + unsigned int __base = (base); \ + unsigned int __rem; \ + __rem = ((unsigned long long)(n)) % __base; \ + (n) = ((unsigned long long)(n)) / __base; \ + __rem; \ +}) + +#else + extern unsigned int __div64_32(unsigned long long *dividend, unsigned int divisor); @@ -39,6 +51,8 @@ extern unsigned int __div64_32(unsigned long long *dividend, __rem; \ }) +#endif /* __powerpc64__ */ + static int skip_atoi(const char **s) { int i, c; diff --git a/arch/powerpc/boot/swab.h b/arch/powerpc/boot/swab.h new file mode 100644 index 00000000000000..d0e1431084cae0 --- /dev/null +++ b/arch/powerpc/boot/swab.h @@ -0,0 +1,29 @@ +#ifndef _PPC_BOOT_SWAB_H_ +#define _PPC_BOOT_SWAB_H_ + +static inline u16 swab16(u16 x) +{ + return ((x & (u16)0x00ffU) << 8) | + ((x & (u16)0xff00U) >> 8); +} + +static inline u32 swab32(u32 x) +{ + return ((x & (u32)0x000000ffUL) << 24) | + ((x & (u32)0x0000ff00UL) << 8) | + ((x & (u32)0x00ff0000UL) >> 8) | + ((x & (u32)0xff000000UL) >> 24); +} + +static inline u64 swab64(u64 x) +{ + return (u64)((x & (u64)0x00000000000000ffULL) << 56) | + (u64)((x & (u64)0x000000000000ff00ULL) << 40) | + (u64)((x & (u64)0x0000000000ff0000ULL) << 24) | + (u64)((x & (u64)0x00000000ff000000ULL) << 8) | + (u64)((x & (u64)0x000000ff00000000ULL) >> 8) | + (u64)((x & (u64)0x0000ff0000000000ULL) >> 24) | + (u64)((x & (u64)0x00ff000000000000ULL) >> 40) | + (u64)((x & (u64)0xff00000000000000ULL) >> 56); +} +#endif /* _PPC_BOOT_SWAB_H_ */ diff --git a/arch/powerpc/boot/treeboot-akebono.c b/arch/powerpc/boot/treeboot-akebono.c new file mode 100644 index 00000000000000..b73174c34fe45f --- /dev/null +++ b/arch/powerpc/boot/treeboot-akebono.c @@ -0,0 +1,163 @@ +/* + * Copyright © 2013 Tony Breeds IBM Corporation + * Copyright © 2013 Alistair Popple IBM Corporation + * + * Based on earlier code: + * Copyright (C) Paul Mackerras 1997. + * + * Matt Porter + * Copyright 2002-2005 MontaVista Software Inc. + * + * Eugene Surovegin or + * Copyright (c) 2003, 2004 Zultys Technologies + * + * Copyright 2007 David Gibson, IBM Corporation. + * Copyright 2010 Ben. Herrenschmidt, IBM Corporation. + * Copyright © 2011 David Kleikamp IBM 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. + */ +#include +#include +#include "types.h" +#include "elf.h" +#include "string.h" +#include "stdlib.h" +#include "stdio.h" +#include "page.h" +#include "ops.h" +#include "reg.h" +#include "io.h" +#include "dcr.h" +#include "4xx.h" +#include "44x.h" +#include "libfdt.h" + +BSS_STACK(4096); + +#define SPRN_PIR 0x11E /* Processor Indentification Register */ +#define USERDATA_LEN 256 /* Length of userdata passed in by PIBS */ +#define MAX_RANKS 0x4 +#define DDR3_MR0CF 0x80010011U +#define CCTL0_MCO2 0x8000080FU +#define CCTL0_MCO3 0x80000810U +#define CCTL0_MCO4 0x80000811U +#define CCTL0_MCO5 0x80000812U +#define CCTL0_MCO6 0x80000813U + +static unsigned long long ibm_akebono_memsize; +static long long unsigned mac_addr; + +static unsigned long long ibm_akebono_detect_memsize(void) +{ + u32 reg; + unsigned i; + unsigned long long memsize = 0; + + for (i = 0; i < MAX_RANKS; i++) { + reg = mfdcrx(DDR3_MR0CF + i); + + if (!(reg & 1)) + continue; + + reg &= 0x0000f000; + reg >>= 12; + memsize += (0x800000ULL << reg); + } + + return memsize; +} + +static void ibm_akebono_fixups(void) +{ + void *emac; + u32 reg; + + dt_fixup_memory(0x0ULL, ibm_akebono_memsize); + + /* Fixup the SD timeout frequency */ + mtdcrx(CCTL0_MCO4, 0x1); + + /* Disable SD high-speed mode (which seems to be broken) */ + reg = mfdcrx(CCTL0_MCO2) & ~0x2; + mtdcrx(CCTL0_MCO2, reg); + + /* Set the MAC address */ + emac = finddevice("/plb/opb/ethernet"); + if (emac > 0) { + if (mac_addr) + setprop(emac, "local-mac-address", + ((u8 *) &mac_addr) + 2 , 6); + } +} + +void platform_init(char *userdata) +{ + unsigned long end_of_ram, avail_ram; + u32 pir_reg; + int node, size; + const u32 *timebase; + int len, i, userdata_len; + char *end; + + userdata[USERDATA_LEN - 1] = '\0'; + userdata_len = strlen(userdata); + for (i = 0; i < userdata_len - 15; i++) { + if (strncmp(&userdata[i], "local-mac-addr=", 15) == 0) { + if (i > 0 && userdata[i - 1] != ' ') { + /* We've only found a substring ending + * with local-mac-addr so this isn't + * our mac address. */ + continue; + } + + mac_addr = strtoull(&userdata[i + 15], &end, 16); + + /* Remove the "local-mac-addr=<...>" from the kernel + * command line, including the tailing space if + * present. */ + if (*end == ' ') + end++; + + len = ((int) end) - ((int) &userdata[i]); + memmove(&userdata[i], end, + userdata_len - (len + i) + 1); + break; + } + } + + loader_info.cmdline = userdata; + loader_info.cmdline_len = 256; + + ibm_akebono_memsize = ibm_akebono_detect_memsize(); + if (ibm_akebono_memsize >> 32) + end_of_ram = ~0UL; + else + end_of_ram = ibm_akebono_memsize; + avail_ram = end_of_ram - (unsigned long)_end; + + simple_alloc_init(_end, avail_ram, 128, 64); + platform_ops.fixups = ibm_akebono_fixups; + platform_ops.exit = ibm44x_dbcr_reset; + pir_reg = mfspr(SPRN_PIR); + + /* Make sure FDT blob is sane */ + if (fdt_check_header(_dtb_start) != 0) + fatal("Invalid device tree blob\n"); + + node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", + "cpu", sizeof("cpu")); + if (!node) + fatal("Cannot find cpu node\n"); + timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size); + if (timebase && (size == 4)) + timebase_period_ns = 1000000000 / *timebase; + + fdt_set_boot_cpuid_phys(_dtb_start, pir_reg); + fdt_init(_dtb_start); + + serial_console_init(); +} diff --git a/arch/powerpc/boot/util.S b/arch/powerpc/boot/util.S index 6636b1d7821b6e..243b8497d58b84 100644 --- a/arch/powerpc/boot/util.S +++ b/arch/powerpc/boot/util.S @@ -45,7 +45,7 @@ udelay: mfspr r4,SPRN_PVR srwi r4,r4,16 cmpwi 0,r4,1 /* 601 ? */ - bne .udelay_not_601 + bne .Ludelay_not_601 00: li r0,86 /* Instructions / microsecond? */ mtctr r0 10: addi r0,r0,0 /* NOP */ @@ -54,7 +54,7 @@ udelay: bne 00b blr -.udelay_not_601: +.Ludelay_not_601: mulli r4,r3,1000 /* nanoseconds */ /* Change r4 to be the number of ticks using: * (nanoseconds + (timebase_period_ns - 1 )) / timebase_period_ns diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index d27a25518b018b..ae0f88ec4a3295 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -40,6 +40,7 @@ cacheit= binary= gzip=.gz pie= +format= # cross-compilation prefix CROSS= @@ -136,6 +137,14 @@ if [ -z "$kernel" ]; then kernel=vmlinux fi +elfformat="`${CROSS}objdump -p "$kernel" | grep 'file format' | awk '{print $4}'`" +case "$elfformat" in + elf64-powerpcle) format=elf64lppc ;; + elf64-powerpc) format=elf32ppc ;; + elf32-powerpc) format=elf32ppc ;; +esac + + platformo=$object/"$platform".o lds=$object/zImage.lds ext=strip @@ -152,8 +161,12 @@ of) make_space=n ;; pseries) - platformo="$object/of.o $object/epapr.o" + platformo="$object/pseries-head.o $object/of.o $object/epapr.o" link_address='0x4000000' + if [ "$format" != "elf32ppc" ]; then + link_address= + pie=-pie + fi make_space=n ;; maple) @@ -257,6 +270,9 @@ gamecube|wii) treeboot-currituck) link_address='0x1000000' ;; +treeboot-akebono) + link_address='0x1000000' + ;; treeboot-iss4xx-mpic) platformo="$object/treeboot-iss4xx.o" ;; @@ -379,7 +395,7 @@ if [ "$platform" != "miboot" ]; then if [ -n "$link_address" ] ; then text_start="-Ttext $link_address" fi - ${CROSS}ld -m elf32ppc -T $lds $text_start $pie -o "$ofile" \ + ${CROSS}ld -m $format -T $lds $text_start $pie -o "$ofile" \ $platformo $tmp $object/wrapper.a rm $tmp fi diff --git a/arch/powerpc/boot/zImage.lds.S b/arch/powerpc/boot/zImage.lds.S index 2bd8731f13655a..861e72109df2da 100644 --- a/arch/powerpc/boot/zImage.lds.S +++ b/arch/powerpc/boot/zImage.lds.S @@ -1,4 +1,10 @@ +#include + +#ifdef CONFIG_PPC64_BOOT_WRAPPER +OUTPUT_ARCH(powerpc:common64) +#else OUTPUT_ARCH(powerpc:common) +#endif ENTRY(_zimage_start) EXTERN(_zimage_start) SECTIONS @@ -16,7 +22,9 @@ SECTIONS *(.rodata*) *(.data*) *(.sdata*) +#ifndef CONFIG_PPC64_BOOT_WRAPPER *(.got2) +#endif } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } @@ -27,7 +35,13 @@ SECTIONS } .hash : { *(.hash) } .interp : { *(.interp) } - .rela.dyn : { *(.rela*) } + .rela.dyn : + { +#ifdef CONFIG_PPC64_BOOT_WRAPPER + __rela_dyn_start = .; +#endif + *(.rela*) + } . = ALIGN(8); .kernel:dtb : @@ -53,6 +67,15 @@ SECTIONS _initrd_end = .; } +#ifdef CONFIG_PPC64_BOOT_WRAPPER + .got : + { + __toc_start = .; + *(.got) + *(.toc) + } +#endif + . = ALIGN(4096); .bss : { diff --git a/arch/powerpc/configs/44x/akebono_defconfig b/arch/powerpc/configs/44x/akebono_defconfig new file mode 100644 index 00000000000000..7e2530cd9d3070 --- /dev/null +++ b/arch/powerpc/configs/44x/akebono_defconfig @@ -0,0 +1,148 @@ +CONFIG_44x=y +CONFIG_SMP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_BLK_DEV_INITRD=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_RD_XZ=y +CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_POWERNV_MSI is not set +CONFIG_PPC_47x=y +# CONFIG_EBONY is not set +CONFIG_AKEBONO=y +CONFIG_HIGHMEM=y +CONFIG_HZ_100=y +CONFIG_IRQ_ALL_CPUS=y +# CONFIG_COMPACTION is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="" +# CONFIG_SUSPEND is not set +CONFIG_PCI_MSI=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_PROC_DEVICETREE=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=35000 +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=y +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SATA_PMP is not set +# CONFIG_ATA_SFF is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EXAR is not set +# CONFIG_NET_VENDOR_HP is not set +CONFIG_IBM_EMAC=y +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_REALTEK is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_MOUSE_PS2 is not set +# CONFIG_SERIO is not set +# CONFIG_VT is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C_CHARDEV=y +# CONFIG_HWMON is not set +CONFIG_THERMAL=y +# CONFIG_USB_DEFAULT_PERSIST is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_HCD_PCI is not set +CONFIG_USB_STORAGE=y +CONFIG_MMC=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_M41T80=y +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_DNOTIFY is not set +# CONFIG_INOTIFY_USER is not set +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_CRAMFS=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_DEFAULT="n" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_XMON=y +CONFIG_XMON_DEFAULT=y +CONFIG_PPC_EARLY_DEBUG=y +CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0x00010000 +CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH=0x33f +CONFIG_CRYPTO_PCBC=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1_PPC=y +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index e3b1d41c89be73..28992d01292633 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -8,6 +8,7 @@ #ifdef __KERNEL__ #include #include +#include #define ATOMIC_INIT(i) { (i) } @@ -270,11 +271,6 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v) } #define atomic_dec_if_positive atomic_dec_if_positive -#define smp_mb__before_atomic_dec() smp_mb() -#define smp_mb__after_atomic_dec() smp_mb() -#define smp_mb__before_atomic_inc() smp_mb() -#define smp_mb__after_atomic_inc() smp_mb() - #ifdef __powerpc64__ #define ATOMIC64_INIT(i) { (i) } diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h index f89da808ce310e..bab79a110c7b05 100644 --- a/arch/powerpc/include/asm/barrier.h +++ b/arch/powerpc/include/asm/barrier.h @@ -84,4 +84,7 @@ do { \ ___p1; \ }) +#define smp_mb__before_atomic() smp_mb() +#define smp_mb__after_atomic() smp_mb() + #endif /* _ASM_POWERPC_BARRIER_H */ diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h index a5e9a7d494d8bd..bd3bd573d0aeef 100644 --- a/arch/powerpc/include/asm/bitops.h +++ b/arch/powerpc/include/asm/bitops.h @@ -51,11 +51,7 @@ #define PPC_BIT(bit) (1UL << PPC_BITLSHIFT(bit)) #define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs)) -/* - * clear_bit doesn't imply a memory barrier - */ -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() +#include /* Macro for generating the ***_bits() functions */ #define DEFINE_BITOP(fn, op, prefix) \ diff --git a/arch/powerpc/include/asm/code-patching.h b/arch/powerpc/include/asm/code-patching.h index 97e02f985df8e4..37991e154ef88f 100644 --- a/arch/powerpc/include/asm/code-patching.h +++ b/arch/powerpc/include/asm/code-patching.h @@ -42,15 +42,47 @@ void __patch_exception(int exc, unsigned long addr); } while (0) #endif +#define OP_RT_RA_MASK 0xffff0000UL +#define LIS_R2 0x3c020000UL +#define ADDIS_R2_R12 0x3c4c0000UL +#define ADDI_R2_R2 0x38420000UL + static inline unsigned long ppc_function_entry(void *func) { -#ifdef CONFIG_PPC64 +#if defined(CONFIG_PPC64) +#if defined(_CALL_ELF) && _CALL_ELF == 2 + u32 *insn = func; + + /* + * A PPC64 ABIv2 function may have a local and a global entry + * point. We need to use the local entry point when patching + * functions, so identify and step over the global entry point + * sequence. + * + * The global entry point sequence is always of the form: + * + * addis r2,r12,XXXX + * addi r2,r2,XXXX + * + * A linker optimisation may convert the addis to lis: + * + * lis r2,XXXX + * addi r2,r2,XXXX + */ + if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) || + ((*insn & OP_RT_RA_MASK) == LIS_R2)) && + ((*(insn+1) & OP_RT_RA_MASK) == ADDI_R2_R2)) + return (unsigned long)(insn + 2); + else + return (unsigned long)func; +#else /* - * On PPC64 the function pointer actually points to the function's - * descriptor. The first entry in the descriptor is the address - * of the function text. + * On PPC64 ABIv1 the function pointer actually points to the + * function's descriptor. The first entry in the descriptor is the + * address of the function text. */ return ((func_descr_t *)func)->entry; +#endif #else return (unsigned long)func; #endif diff --git a/arch/powerpc/include/asm/context_tracking.h b/arch/powerpc/include/asm/context_tracking.h index b6f5a33b8ee2d8..40014921ffff23 100644 --- a/arch/powerpc/include/asm/context_tracking.h +++ b/arch/powerpc/include/asm/context_tracking.h @@ -2,9 +2,9 @@ #define _ASM_POWERPC_CONTEXT_TRACKING_H #ifdef CONFIG_CONTEXT_TRACKING -#define SCHEDULE_USER bl .schedule_user +#define SCHEDULE_USER bl schedule_user #else -#define SCHEDULE_USER bl .schedule +#define SCHEDULE_USER bl schedule #endif #endif diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index d4dd41fb951b34..d12529f34524f1 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -32,6 +32,22 @@ struct device_node; #ifdef CONFIG_EEH +/* EEH subsystem flags */ +#define EEH_ENABLED 0x1 /* EEH enabled */ +#define EEH_FORCE_DISABLED 0x2 /* EEH disabled */ +#define EEH_PROBE_MODE_DEV 0x4 /* From PCI device */ +#define EEH_PROBE_MODE_DEVTREE 0x8 /* From device tree */ + +/* + * Delay for PE reset, all in ms + * + * PCI specification has reset hold time of 100 milliseconds. + * We have 250 milliseconds here. The PCI bus settlement time + * is specified as 1.5 seconds and we have 1.8 seconds. + */ +#define EEH_PE_RST_HOLD_TIME 250 +#define EEH_PE_RST_SETTLE_TIME 1800 + /* * The struct is used to trace PE related EEH functionality. * In theory, there will have one instance of the struct to @@ -53,7 +69,7 @@ struct device_node; #define EEH_PE_ISOLATED (1 << 0) /* Isolated PE */ #define EEH_PE_RECOVERING (1 << 1) /* Recovering PE */ -#define EEH_PE_PHB_DEAD (1 << 2) /* Dead PHB */ +#define EEH_PE_RESET (1 << 2) /* PE reset in progress */ #define EEH_PE_KEEP (1 << 8) /* Keep PE on hotplug */ @@ -92,6 +108,8 @@ struct eeh_pe { #define EEH_DEV_NO_HANDLER (1 << 8) /* No error handler */ #define EEH_DEV_SYSFS (1 << 9) /* Sysfs created */ +#define EEH_DEV_REMOVED (1 << 10) /* Removed permanently */ +#define EEH_DEV_FRESET (1 << 11) /* Fundamental reset */ struct eeh_dev { int mode; /* EEH mode */ @@ -99,7 +117,9 @@ struct eeh_dev { int config_addr; /* Config address */ int pe_config_addr; /* PE config address */ u32 config_space[16]; /* Saved PCI config space */ - u8 pcie_cap; /* Saved PCIe capability */ + int pcix_cap; /* Saved PCIx capability */ + int pcie_cap; /* Saved PCIe capability */ + int aer_cap; /* Saved AER capability */ struct eeh_pe *pe; /* Associated PE */ struct list_head list; /* Form link list in the PE */ struct pci_controller *phb; /* Associated PHB */ @@ -171,37 +191,40 @@ struct eeh_ops { int (*restore_config)(struct device_node *dn); }; +extern int eeh_subsystem_flags; extern struct eeh_ops *eeh_ops; -extern bool eeh_subsystem_enabled; extern raw_spinlock_t confirm_error_lock; -extern int eeh_probe_mode; static inline bool eeh_enabled(void) { - return eeh_subsystem_enabled; + if ((eeh_subsystem_flags & EEH_FORCE_DISABLED) || + !(eeh_subsystem_flags & EEH_ENABLED)) + return false; + + return true; } static inline void eeh_set_enable(bool mode) { - eeh_subsystem_enabled = mode; + if (mode) + eeh_subsystem_flags |= EEH_ENABLED; + else + eeh_subsystem_flags &= ~EEH_ENABLED; } -#define EEH_PROBE_MODE_DEV (1<<0) /* From PCI device */ -#define EEH_PROBE_MODE_DEVTREE (1<<1) /* From device tree */ - static inline void eeh_probe_mode_set(int flag) { - eeh_probe_mode = flag; + eeh_subsystem_flags |= flag; } static inline int eeh_probe_mode_devtree(void) { - return (eeh_probe_mode == EEH_PROBE_MODE_DEVTREE); + return (eeh_subsystem_flags & EEH_PROBE_MODE_DEVTREE); } static inline int eeh_probe_mode_dev(void) { - return (eeh_probe_mode == EEH_PROBE_MODE_DEV); + return (eeh_subsystem_flags & EEH_PROBE_MODE_DEV); } static inline void eeh_serialize_lock(unsigned long *flags) diff --git a/arch/powerpc/include/asm/exception-64e.h b/arch/powerpc/include/asm/exception-64e.h index a563d9afd179f3..a8b52b61043f57 100644 --- a/arch/powerpc/include/asm/exception-64e.h +++ b/arch/powerpc/include/asm/exception-64e.h @@ -174,10 +174,10 @@ exc_##label##_book3e: mtlr r16; #define TLB_MISS_STATS_D(name) \ addi r9,r13,MMSTAT_DSTATS+name; \ - bl .tlb_stat_inc; + bl tlb_stat_inc; #define TLB_MISS_STATS_I(name) \ addi r9,r13,MMSTAT_ISTATS+name; \ - bl .tlb_stat_inc; + bl tlb_stat_inc; #define TLB_MISS_STATS_X(name) \ ld r8,PACA_EXTLB+EX_TLB_ESR(r13); \ cmpdi cr2,r8,-1; \ @@ -185,7 +185,7 @@ exc_##label##_book3e: addi r9,r13,MMSTAT_DSTATS+name; \ b 62f; \ 61: addi r9,r13,MMSTAT_ISTATS+name; \ -62: bl .tlb_stat_inc; +62: bl tlb_stat_inc; #define TLB_MISS_STATS_SAVE_INFO \ std r14,EX_TLB_ESR(r12); /* save ESR */ #define TLB_MISS_STATS_SAVE_INFO_BOLTED \ diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index aeaa56cd9b5465..8f35cd7d59cc65 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -517,7 +517,7 @@ label##_relon_hv: \ #define DISABLE_INTS RECONCILE_IRQ_STATE(r10,r11) #define ADD_NVGPRS \ - bl .save_nvgprs + bl save_nvgprs #define RUNLATCH_ON \ BEGIN_FTR_SECTION \ diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h index 169d039ed40208..e3661872fbea5b 100644 --- a/arch/powerpc/include/asm/ftrace.h +++ b/arch/powerpc/include/asm/ftrace.h @@ -61,6 +61,7 @@ struct dyn_arch_ftrace { #endif #if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64) && !defined(__ASSEMBLY__) +#if !defined(_CALL_ELF) || _CALL_ELF != 2 #define ARCH_HAS_SYSCALL_MATCH_SYM_NAME static inline bool arch_syscall_match_sym_name(const char *sym, const char *name) { @@ -72,6 +73,7 @@ static inline bool arch_syscall_match_sym_name(const char *sym, const char *name */ return !strcmp(sym + 4, name + 3); } +#endif #endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_PPC64 && !__ASSEMBLY__ */ #endif /* _ASM_POWERPC_FTRACE */ diff --git a/arch/powerpc/include/asm/irqflags.h b/arch/powerpc/include/asm/irqflags.h index f51a5580bfd0b2..e20eb95429a823 100644 --- a/arch/powerpc/include/asm/irqflags.h +++ b/arch/powerpc/include/asm/irqflags.h @@ -20,9 +20,9 @@ */ #define TRACE_WITH_FRAME_BUFFER(func) \ mflr r0; \ - stdu r1, -32(r1); \ + stdu r1, -STACK_FRAME_OVERHEAD(r1); \ std r0, 16(r1); \ - stdu r1, -32(r1); \ + stdu r1, -STACK_FRAME_OVERHEAD(r1); \ bl func; \ ld r1, 0(r1); \ ld r1, 0(r1); @@ -36,8 +36,8 @@ * have to call a C function so call a wrapper that saves all the * C-clobbered registers. */ -#define TRACE_ENABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on) -#define TRACE_DISABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off) +#define TRACE_ENABLE_INTS TRACE_WITH_FRAME_BUFFER(trace_hardirqs_on) +#define TRACE_DISABLE_INTS TRACE_WITH_FRAME_BUFFER(trace_hardirqs_off) /* * This is used by assembly code to soft-disable interrupts first and diff --git a/arch/powerpc/include/asm/kprobes.h b/arch/powerpc/include/asm/kprobes.h index 7b6feab6fd26f2..af15d4d8d604c7 100644 --- a/arch/powerpc/include/asm/kprobes.h +++ b/arch/powerpc/include/asm/kprobes.h @@ -30,6 +30,7 @@ #include #include #include +#include #define __ARCH_WANT_KPROBES_INSN_SLOT @@ -56,9 +57,9 @@ typedef ppc_opcode_t kprobe_opcode_t; if ((colon = strchr(name, ':')) != NULL) { \ colon++; \ if (*colon != '\0' && *colon != '.') \ - addr = *(kprobe_opcode_t **)addr; \ + addr = (kprobe_opcode_t *)ppc_function_entry(addr); \ } else if (name[0] != '.') \ - addr = *(kprobe_opcode_t **)addr; \ + addr = (kprobe_opcode_t *)ppc_function_entry(addr); \ } else { \ char dot_name[KSYM_NAME_LEN]; \ dot_name[0] = '.'; \ diff --git a/arch/powerpc/include/asm/linkage.h b/arch/powerpc/include/asm/linkage.h index b36f650a13fff8..e3ad5c72724afd 100644 --- a/arch/powerpc/include/asm/linkage.h +++ b/arch/powerpc/include/asm/linkage.h @@ -2,6 +2,7 @@ #define _ASM_POWERPC_LINKAGE_H #ifdef CONFIG_PPC64 +#if !defined(_CALL_ELF) || _CALL_ELF != 2 #define cond_syscall(x) \ asm ("\t.weak " #x "\n\t.set " #x ", sys_ni_syscall\n" \ "\t.weak ." #x "\n\t.set ." #x ", .sys_ni_syscall\n") @@ -9,5 +10,6 @@ asm ("\t.globl " #alias "\n\t.set " #alias ", " #name "\n" \ "\t.globl ." #alias "\n\t.set ." #alias ", ." #name) #endif +#endif #endif /* _ASM_POWERPC_LINKAGE_H */ diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 5b6c03f1058f21..374abc2e41d731 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -113,6 +113,8 @@ struct machdep_calls { /* Optional, may be NULL. */ void (*show_cpuinfo)(struct seq_file *m); void (*show_percpuinfo)(struct seq_file *m, int i); + /* Returns the current operating frequency of "cpu" in Hz */ + unsigned long (*get_proc_freq)(unsigned int cpu); void (*init_IRQ)(void); @@ -241,6 +243,9 @@ struct machdep_calls { /* Called during PCI resource reassignment */ resource_size_t (*pcibios_window_alignment)(struct pci_bus *, unsigned long type); + /* Reset the secondary bus of bridge */ + void (*pcibios_reset_secondary_bus)(struct pci_dev *dev); + /* Called to shutdown machine specific hardware not already controlled * by other drivers. */ diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h index 49fa55bfbac4fb..dcfcad139bccc0 100644 --- a/arch/powerpc/include/asm/module.h +++ b/arch/powerpc/include/asm/module.h @@ -35,6 +35,7 @@ struct mod_arch_specific { #ifdef __powerpc64__ unsigned int stubs_section; /* Index of stubs section in module */ unsigned int toc_section; /* What section is the TOC? */ + bool toc_fixed; /* Have we fixed up .TOC.? */ #ifdef CONFIG_DYNAMIC_FTRACE unsigned long toc; unsigned long tramp; @@ -77,6 +78,9 @@ struct mod_arch_specific { # endif /* MODULE */ #endif +bool is_module_trampoline(u32 *insns); +int module_trampoline_target(struct module *mod, u32 *trampoline, + unsigned long *target); struct exception_table_entry; void sort_ex_table(struct exception_table_entry *start, diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 66ad7a74116f15..81720ff59a106e 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -916,6 +916,7 @@ extern void opal_get_rtc_time(struct rtc_time *tm); extern unsigned long opal_get_boot_time(void); extern void opal_nvram_init(void); extern void opal_flash_init(void); +extern void opal_flash_term_callback(void); extern int opal_elog_init(void); extern void opal_platform_dump_init(void); extern void opal_sys_param_init(void); diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h index ed57fa7920c88d..db1e2b8eff3c4e 100644 --- a/arch/powerpc/include/asm/ppc-pci.h +++ b/arch/powerpc/include/asm/ppc-pci.h @@ -58,6 +58,7 @@ int rtas_write_config(struct pci_dn *, int where, int size, u32 val); int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); void eeh_pe_state_mark(struct eeh_pe *pe, int state); void eeh_pe_state_clear(struct eeh_pe *pe, int state); +void eeh_pe_dev_mode_mark(struct eeh_pe *pe, int mode); void eeh_sysfs_add_device(struct pci_dev *pdev); void eeh_sysfs_remove_device(struct pci_dev *pdev); diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index 6586a40a46ce16..6400f1814fe823 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -57,7 +57,7 @@ BEGIN_FW_FTR_SECTION; \ LDX_BE r10,0,r10; /* get log write index */ \ cmpd cr1,r11,r10; \ beq+ cr1,33f; \ - bl .accumulate_stolen_time; \ + bl accumulate_stolen_time; \ ld r12,_MSR(r1); \ andi. r10,r12,MSR_PR; /* Restore cr0 (coming from user) */ \ 33: \ @@ -189,57 +189,53 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) #define __STK_REG(i) (112 + ((i)-14)*8) #define STK_REG(i) __STK_REG(__REG_##i) +#if defined(_CALL_ELF) && _CALL_ELF == 2 +#define STK_GOT 24 +#define __STK_PARAM(i) (32 + ((i)-3)*8) +#else +#define STK_GOT 40 #define __STK_PARAM(i) (48 + ((i)-3)*8) +#endif #define STK_PARAM(i) __STK_PARAM(__REG_##i) -#define XGLUE(a,b) a##b -#define GLUE(a,b) XGLUE(a,b) +#if defined(_CALL_ELF) && _CALL_ELF == 2 #define _GLOBAL(name) \ .section ".text"; \ .align 2 ; \ + .type name,@function; \ .globl name; \ - .globl GLUE(.,name); \ - .section ".opd","aw"; \ -name: \ - .quad GLUE(.,name); \ - .quad .TOC.@tocbase; \ - .quad 0; \ - .previous; \ - .type GLUE(.,name),@function; \ -GLUE(.,name): +name: -#define _INIT_GLOBAL(name) \ - __REF; \ +#define _GLOBAL_TOC(name) \ + .section ".text"; \ .align 2 ; \ + .type name,@function; \ .globl name; \ - .globl GLUE(.,name); \ - .section ".opd","aw"; \ name: \ - .quad GLUE(.,name); \ - .quad .TOC.@tocbase; \ - .quad 0; \ - .previous; \ - .type GLUE(.,name),@function; \ -GLUE(.,name): +0: addis r2,r12,(.TOC.-0b)@ha; \ + addi r2,r2,(.TOC.-0b)@l; \ + .localentry name,.-name #define _KPROBE(name) \ .section ".kprobes.text","a"; \ .align 2 ; \ + .type name,@function; \ .globl name; \ - .globl GLUE(.,name); \ - .section ".opd","aw"; \ -name: \ - .quad GLUE(.,name); \ - .quad .TOC.@tocbase; \ - .quad 0; \ - .previous; \ - .type GLUE(.,name),@function; \ -GLUE(.,name): +name: + +#define DOTSYM(a) a + +#else + +#define XGLUE(a,b) a##b +#define GLUE(a,b) XGLUE(a,b) -#define _STATIC(name) \ +#define _GLOBAL(name) \ .section ".text"; \ .align 2 ; \ + .globl name; \ + .globl GLUE(.,name); \ .section ".opd","aw"; \ name: \ .quad GLUE(.,name); \ @@ -249,9 +245,13 @@ name: \ .type GLUE(.,name),@function; \ GLUE(.,name): -#define _INIT_STATIC(name) \ - __REF; \ +#define _GLOBAL_TOC(name) _GLOBAL(name) + +#define _KPROBE(name) \ + .section ".kprobes.text","a"; \ .align 2 ; \ + .globl name; \ + .globl GLUE(.,name); \ .section ".opd","aw"; \ name: \ .quad GLUE(.,name); \ @@ -261,6 +261,10 @@ name: \ .type GLUE(.,name),@function; \ GLUE(.,name): +#define DOTSYM(a) GLUE(.,a) + +#endif + #else /* 32-bit */ #define _ENTRY(n) \ diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index d977b9b7869683..74b79f07f0412b 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -26,6 +26,45 @@ #include #include +#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ +#define OF_DT_END_NODE 0x2 /* End node */ +#define OF_DT_PROP 0x3 /* Property: name off, size, + * content */ +#define OF_DT_NOP 0x4 /* nop */ +#define OF_DT_END 0x9 + +#define OF_DT_VERSION 0x10 + +/* + * This is what gets passed to the kernel by prom_init or kexec + * + * The dt struct contains the device tree structure, full pathes and + * property contents. The dt strings contain a separate block with just + * the strings for the property names, and is fully page aligned and + * self contained in a page, so that it can be kept around by the kernel, + * each property name appears only once in this page (cheap compression) + * + * the mem_rsvmap contains a map of reserved ranges of physical memory, + * passing it here instead of in the device-tree itself greatly simplifies + * the job of everybody. It's just a list of u64 pairs (base/size) that + * ends when size is 0 + */ +struct boot_param_header { + __be32 magic; /* magic word OF_DT_HEADER */ + __be32 totalsize; /* total size of DT block */ + __be32 off_dt_struct; /* offset to structure */ + __be32 off_dt_strings; /* offset to strings */ + __be32 off_mem_rsvmap; /* offset to memory reserve map */ + __be32 version; /* format version */ + __be32 last_comp_version; /* last compatible version */ + /* version 2 fields below */ + __be32 boot_cpuid_phys; /* Physical CPU id we're booting on */ + /* version 3 fields below */ + __be32 dt_strings_size; /* size of the DT strings block */ + /* version 17 fields below */ + __be32 dt_struct_size; /* size of the DT structure block */ +}; + /* * OF address retreival & translation */ diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index e5d2e0bc7e032b..29de0152878fc5 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -215,6 +215,7 @@ #define SPRN_TEXASR 0x82 /* Transaction EXception & Summary */ #define TEXASR_FS __MASK(63-36) /* Transaction Failure Summary */ #define SPRN_TEXASRU 0x83 /* '' '' '' Upper 32 */ +#define TEXASR_FS __MASK(63-36) /* TEXASR Failure Summary */ #define SPRN_TFHAR 0x80 /* Transaction Failure Handler Addr */ #define SPRN_CTRLF 0x088 #define SPRN_CTRLT 0x098 diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h index d0e784e0ff484f..d1bb96d5a298b3 100644 --- a/arch/powerpc/include/asm/sections.h +++ b/arch/powerpc/include/asm/sections.h @@ -39,6 +39,7 @@ static inline int overlaps_kernel_text(unsigned long start, unsigned long end) (unsigned long)_stext < end; } +#if !defined(_CALL_ELF) || _CALL_ELF != 2 #undef dereference_function_descriptor static inline void *dereference_function_descriptor(void *ptr) { @@ -49,6 +50,7 @@ static inline void *dereference_function_descriptor(void *ptr) ptr = p; return ptr; } +#endif #endif diff --git a/arch/powerpc/include/asm/string.h b/arch/powerpc/include/asm/string.h index 0dffad6bcc8467..e40010abcaf134 100644 --- a/arch/powerpc/include/asm/string.h +++ b/arch/powerpc/include/asm/string.h @@ -10,9 +10,7 @@ #define __HAVE_ARCH_STRNCMP #define __HAVE_ARCH_STRCAT #define __HAVE_ARCH_MEMSET -#ifdef __BIG_ENDIAN__ #define __HAVE_ARCH_MEMCPY -#endif #define __HAVE_ARCH_MEMMOVE #define __HAVE_ARCH_MEMCMP #define __HAVE_ARCH_MEMCHR @@ -24,9 +22,7 @@ extern int strcmp(const char *,const char *); extern int strncmp(const char *, const char *, __kernel_size_t); extern char * strcat(char *, const char *); extern void * memset(void *,int,__kernel_size_t); -#ifdef __BIG_ENDIAN__ extern void * memcpy(void *,const void *,__kernel_size_t); -#endif extern void * memmove(void *,const void *,__kernel_size_t); extern int memcmp(const void *,const void *,__kernel_size_t); extern void * memchr(const void *,int,__kernel_size_t); diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h index b54b2add07be99..6fa2708da15304 100644 --- a/arch/powerpc/include/asm/syscall.h +++ b/arch/powerpc/include/asm/syscall.h @@ -13,7 +13,9 @@ #ifndef _ASM_SYSCALL_H #define _ASM_SYSCALL_H 1 +#include #include +#include /* ftrace syscalls requires exporting the sys_call_table */ #ifdef CONFIG_FTRACE_SYSCALLS @@ -86,4 +88,8 @@ static inline void syscall_set_arguments(struct task_struct *task, memcpy(®s->gpr[3 + i], args, n * sizeof(args[0])); } +static inline int syscall_get_arch(void) +{ + return is_32bit_task() ? AUDIT_ARCH_PPC : AUDIT_ARCH_PPC64; +} #endif /* _ASM_SYSCALL_H */ diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index 3ddf7027670642..ac062f50473605 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -62,7 +62,7 @@ COMPAT_SYS_SPU(fcntl) SYSCALL(ni_syscall) SYSCALL_SPU(setpgid) SYSCALL(ni_syscall) -SYSX(sys_ni_syscall,sys_olduname, sys_olduname) +SYSX(sys_ni_syscall,sys_olduname,sys_olduname) SYSCALL_SPU(umask) SYSCALL_SPU(chroot) COMPAT_SYS(ustat) @@ -258,7 +258,7 @@ SYSCALL_SPU(tgkill) COMPAT_SYS_SPU(utimes) COMPAT_SYS_SPU(statfs64) COMPAT_SYS_SPU(fstatfs64) -SYSX(sys_ni_syscall, ppc_fadvise64_64, ppc_fadvise64_64) +SYSX(sys_ni_syscall,ppc_fadvise64_64,ppc_fadvise64_64) PPC_SYS_SPU(rtas) OLDSYS(debug_setcontext) SYSCALL(ni_syscall) @@ -295,7 +295,7 @@ SYSCALL_SPU(mkdirat) SYSCALL_SPU(mknodat) SYSCALL_SPU(fchownat) COMPAT_SYS_SPU(futimesat) -SYSX_SPU(sys_newfstatat, sys_fstatat64, sys_fstatat64) +SYSX_SPU(sys_newfstatat,sys_fstatat64,sys_fstatat64) SYSCALL_SPU(unlinkat) SYSCALL_SPU(renameat) SYSCALL_SPU(linkat) diff --git a/arch/powerpc/include/uapi/asm/elf.h b/arch/powerpc/include/uapi/asm/elf.h index 7e39c9146a71f6..59dad113897b0b 100644 --- a/arch/powerpc/include/uapi/asm/elf.h +++ b/arch/powerpc/include/uapi/asm/elf.h @@ -291,9 +291,17 @@ do { \ #define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ #define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ #define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ +#define R_PPC64_TLSGD 107 +#define R_PPC64_TLSLD 108 +#define R_PPC64_TOCSAVE 109 + +#define R_PPC64_REL16 249 +#define R_PPC64_REL16_LO 250 +#define R_PPC64_REL16_HI 251 +#define R_PPC64_REL16_HA 252 /* Keep this the last entry. */ -#define R_PPC64_NUM 107 +#define R_PPC64_NUM 253 /* There's actually a third entry here, but it's unused */ struct ppc64_opd_entry diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index fcc9a89a469508..fab19ec25597c0 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -2,6 +2,7 @@ # Makefile for the linux kernel. # +CFLAGS_prom.o = -I$(src)/../../../scripts/dtc/libfdt CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S index cc2d8962e0906b..4f1393d2007929 100644 --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S @@ -94,12 +94,12 @@ _GLOBAL(setup_altivec_idle) _GLOBAL(__setup_cpu_e6500) mflr r6 #ifdef CONFIG_PPC64 - bl .setup_altivec_ivors + bl setup_altivec_ivors /* Touch IVOR42 only if the CPU supports E.HV category */ mfspr r10,SPRN_MMUCFG rlwinm. r10,r10,0,MMUCFG_LPIDSIZE beq 1f - bl .setup_lrat_ivor + bl setup_lrat_ivor 1: #endif bl setup_pw20_idle @@ -164,15 +164,15 @@ _GLOBAL(__setup_cpu_e5500) #ifdef CONFIG_PPC_BOOK3E_64 _GLOBAL(__restore_cpu_e6500) mflr r5 - bl .setup_altivec_ivors + bl setup_altivec_ivors /* Touch IVOR42 only if the CPU supports E.HV category */ mfspr r10,SPRN_MMUCFG rlwinm. r10,r10,0,MMUCFG_LPIDSIZE beq 1f - bl .setup_lrat_ivor + bl setup_lrat_ivor 1: - bl .setup_pw20_idle - bl .setup_altivec_idle + bl setup_pw20_idle + bl setup_altivec_idle bl __restore_cpu_e5500 mtlr r5 blr @@ -181,9 +181,9 @@ _GLOBAL(__restore_cpu_e5500) mflr r4 bl __e500_icache_setup bl __e500_dcache_setup - bl .__setup_base_ivors - bl .setup_perfmon_ivor - bl .setup_doorbell_ivors + bl __setup_base_ivors + bl setup_perfmon_ivor + bl setup_doorbell_ivors /* * We only want to touch IVOR38-41 if we're running on hardware * that supports category E.HV. The architectural way to determine @@ -192,7 +192,7 @@ _GLOBAL(__restore_cpu_e5500) mfspr r10,SPRN_MMUCFG rlwinm. r10,r10,0,MMUCFG_LPIDSIZE beq 1f - bl .setup_ehv_ivors + bl setup_ehv_ivors 1: mtlr r4 blr @@ -201,9 +201,9 @@ _GLOBAL(__setup_cpu_e5500) mflr r5 bl __e500_icache_setup bl __e500_dcache_setup - bl .__setup_base_ivors - bl .setup_perfmon_ivor - bl .setup_doorbell_ivors + bl __setup_base_ivors + bl setup_perfmon_ivor + bl setup_doorbell_ivors /* * We only want to touch IVOR38-41 if we're running on hardware * that supports category E.HV. The architectural way to determine @@ -212,7 +212,7 @@ _GLOBAL(__setup_cpu_e5500) mfspr r10,SPRN_MMUCFG rlwinm. r10,r10,0,MMUCFG_LPIDSIZE beq 1f - bl .setup_ehv_ivors + bl setup_ehv_ivors b 2f 1: ld r10,CPU_SPEC_FEATURES(r4) diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 18d7c80ddeb98c..51dbace3269bef 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -81,7 +81,7 @@ void crash_ipi_callback(struct pt_regs *regs) } atomic_inc(&cpus_in_crash); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); /* * Starting the kdump boot. diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index e7b76a6bf15083..3764fb788d6c56 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -87,22 +88,21 @@ /* Time to wait for a PCI slot to report status, in milliseconds */ #define PCI_BUS_RESET_WAIT_MSEC (5*60*1000) -/* Platform dependent EEH operations */ -struct eeh_ops *eeh_ops = NULL; - -bool eeh_subsystem_enabled = false; -EXPORT_SYMBOL(eeh_subsystem_enabled); - /* - * EEH probe mode support. The intention is to support multiple - * platforms for EEH. Some platforms like pSeries do PCI emunation - * based on device tree. However, other platforms like powernv probe - * PCI devices from hardware. The flag is used to distinguish that. - * In addition, struct eeh_ops::probe would be invoked for particular - * OF node or PCI device so that the corresponding PE would be created - * there. + * EEH probe mode support, which is part of the flags, + * is to support multiple platforms for EEH. Some platforms + * like pSeries do PCI emunation based on device tree. + * However, other platforms like powernv probe PCI devices + * from hardware. The flag is used to distinguish that. + * In addition, struct eeh_ops::probe would be invoked for + * particular OF node or PCI device so that the corresponding + * PE would be created there. */ -int eeh_probe_mode; +int eeh_subsystem_flags; +EXPORT_SYMBOL(eeh_subsystem_flags); + +/* Platform dependent EEH operations */ +struct eeh_ops *eeh_ops = NULL; /* Lock to avoid races due to multiple reports of an error */ DEFINE_RAW_SPINLOCK(confirm_error_lock); @@ -133,6 +133,15 @@ static struct eeh_stats eeh_stats; #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) +static int __init eeh_setup(char *str) +{ + if (!strcmp(str, "off")) + eeh_subsystem_flags |= EEH_FORCE_DISABLED; + + return 1; +} +__setup("eeh=", eeh_setup); + /** * eeh_gather_pci_data - Copy assorted PCI config space registers to buff * @edev: device to report data for @@ -145,73 +154,67 @@ static struct eeh_stats eeh_stats; static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) { struct device_node *dn = eeh_dev_to_of_node(edev); - struct pci_dev *dev = eeh_dev_to_pci_dev(edev); u32 cfg; int cap, i; int n = 0; n += scnprintf(buf+n, len-n, "%s\n", dn->full_name); - printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name); + pr_warn("EEH: of node=%s\n", dn->full_name); eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg); n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg); - printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg); + pr_warn("EEH: PCI device/vendor: %08x\n", cfg); eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg); n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg); - printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); - - if (!dev) { - printk(KERN_WARNING "EEH: no PCI device for this of node\n"); - return n; - } + pr_warn("EEH: PCI cmd/status register: %08x\n", cfg); /* Gather bridge-specific registers */ - if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { + if (edev->mode & EEH_DEV_BRIDGE) { eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg); n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg); - printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg); + pr_warn("EEH: Bridge secondary status: %04x\n", cfg); eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg); n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg); - printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg); + pr_warn("EEH: Bridge control: %04x\n", cfg); } /* Dump out the PCI-X command and status regs */ - cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); + cap = edev->pcix_cap; if (cap) { eeh_ops->read_config(dn, cap, 4, &cfg); n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg); - printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg); + pr_warn("EEH: PCI-X cmd: %08x\n", cfg); eeh_ops->read_config(dn, cap+4, 4, &cfg); n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg); - printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg); + pr_warn("EEH: PCI-X status: %08x\n", cfg); } - /* If PCI-E capable, dump PCI-E cap 10, and the AER */ - if (pci_is_pcie(dev)) { + /* If PCI-E capable, dump PCI-E cap 10 */ + cap = edev->pcie_cap; + if (cap) { n += scnprintf(buf+n, len-n, "pci-e cap10:\n"); - printk(KERN_WARNING - "EEH: PCI-E capabilities and status follow:\n"); + pr_warn("EEH: PCI-E capabilities and status follow:\n"); for (i=0; i<=8; i++) { - eeh_ops->read_config(dn, dev->pcie_cap+4*i, 4, &cfg); + eeh_ops->read_config(dn, cap+4*i, 4, &cfg); n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); - printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg); + pr_warn("EEH: PCI-E %02x: %08x\n", i, cfg); } + } - cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); - if (cap) { - n += scnprintf(buf+n, len-n, "pci-e AER:\n"); - printk(KERN_WARNING - "EEH: PCI-E AER capability register set follows:\n"); - - for (i=0; i<14; i++) { - eeh_ops->read_config(dn, cap+4*i, 4, &cfg); - n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); - printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg); - } + /* If AER capable, dump it */ + cap = edev->aer_cap; + if (cap) { + n += scnprintf(buf+n, len-n, "pci-e AER:\n"); + pr_warn("EEH: PCI-E AER capability register set follows:\n"); + + for (i=0; i<14; i++) { + eeh_ops->read_config(dn, cap+4*i, 4, &cfg); + n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); + pr_warn("EEH: PCI-E AER %02x: %08x\n", i, cfg); } } @@ -232,21 +235,19 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity) { size_t loglen = 0; struct eeh_dev *edev, *tmp; - bool valid_cfg_log = true; /* * When the PHB is fenced or dead, it's pointless to collect * the data from PCI config space because it should return * 0xFF's. For ER, we still retrieve the data from the PCI * config space. + * + * For pHyp, we have to enable IO for log retrieval. Otherwise, + * 0xFF's is always returned from PCI config space. */ - if (eeh_probe_mode_dev() && - (pe->type & EEH_PE_PHB) && - (pe->state & (EEH_PE_ISOLATED | EEH_PE_PHB_DEAD))) - valid_cfg_log = false; - - if (valid_cfg_log) { - eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); + if (!(pe->type & EEH_PE_PHB)) { + if (eeh_probe_mode_devtree()) + eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); eeh_ops->configure_bridge(pe); eeh_pe_restore_bars(pe); @@ -309,7 +310,7 @@ static int eeh_phb_check_failure(struct eeh_pe *pe) /* If the PHB has been in problematic state */ eeh_serialize_lock(&flags); - if (phb_pe->state & (EEH_PE_ISOLATED | EEH_PE_PHB_DEAD)) { + if (phb_pe->state & EEH_PE_ISOLATED) { ret = 0; goto out; } @@ -515,16 +516,42 @@ EXPORT_SYMBOL(eeh_check_failure); */ int eeh_pci_enable(struct eeh_pe *pe, int function) { - int rc; + int rc, flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE); + + /* + * pHyp doesn't allow to enable IO or DMA on unfrozen PE. + * Also, it's pointless to enable them on unfrozen PE. So + * we have the check here. + */ + if (function == EEH_OPT_THAW_MMIO || + function == EEH_OPT_THAW_DMA) { + rc = eeh_ops->get_state(pe, NULL); + if (rc < 0) + return rc; + + /* Needn't to enable or already enabled */ + if ((rc == EEH_STATE_NOT_SUPPORT) || + ((rc & flags) == flags)) + return 0; + } rc = eeh_ops->set_option(pe, function); if (rc) - pr_warning("%s: Unexpected state change %d on PHB#%d-PE#%x, err=%d\n", - __func__, function, pe->phb->global_number, pe->addr, rc); + pr_warn("%s: Unexpected state change %d on " + "PHB#%d-PE#%x, err=%d\n", + __func__, function, pe->phb->global_number, + pe->addr, rc); rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); - if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) && - (function == EEH_OPT_THAW_MMIO)) + if (rc <= 0) + return rc; + + if ((function == EEH_OPT_THAW_MMIO) && + (rc & EEH_STATE_MMIO_ENABLED)) + return 0; + + if ((function == EEH_OPT_THAW_DMA) && + (rc & EEH_STATE_DMA_ENABLED)) return 0; return rc; @@ -612,26 +639,7 @@ static void eeh_reset_pe_once(struct eeh_pe *pe) else eeh_ops->reset(pe, EEH_RESET_HOT); - /* The PCI bus requires that the reset be held high for at least - * a 100 milliseconds. We wait a bit longer 'just in case'. - */ -#define PCI_BUS_RST_HOLD_TIME_MSEC 250 - msleep(PCI_BUS_RST_HOLD_TIME_MSEC); - - /* We might get hit with another EEH freeze as soon as the - * pci slot reset line is dropped. Make sure we don't miss - * these, and clear the flag now. - */ - eeh_pe_state_clear(pe, EEH_PE_ISOLATED); - eeh_ops->reset(pe, EEH_RESET_DEACTIVATE); - - /* After a PCI slot has been reset, the PCI Express spec requires - * a 1.5 second idle time for the bus to stabilize, before starting - * up traffic. - */ -#define PCI_BUS_SETTLE_TIME_MSEC 1800 - msleep(PCI_BUS_SETTLE_TIME_MSEC); } /** @@ -651,6 +659,10 @@ int eeh_reset_pe(struct eeh_pe *pe) for (i=0; i<3; i++) { eeh_reset_pe_once(pe); + /* + * EEH_PE_ISOLATED is expected to be removed after + * BAR restore. + */ rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); if ((rc & flags) == flags) return 0; @@ -826,8 +838,8 @@ int eeh_init(void) &hose_list, list_node) pci_walk_bus(hose->bus, eeh_ops->dev_probe, NULL); } else { - pr_warning("%s: Invalid probe mode %d\n", - __func__, eeh_probe_mode); + pr_warn("%s: Invalid probe mode %x", + __func__, eeh_subsystem_flags); return -EINVAL; } @@ -1102,10 +1114,45 @@ static const struct file_operations proc_eeh_operations = { .release = single_release, }; +#ifdef CONFIG_DEBUG_FS +static int eeh_enable_dbgfs_set(void *data, u64 val) +{ + if (val) + eeh_subsystem_flags &= ~EEH_FORCE_DISABLED; + else + eeh_subsystem_flags |= EEH_FORCE_DISABLED; + + /* Notify the backend */ + if (eeh_ops->post_init) + eeh_ops->post_init(); + + return 0; +} + +static int eeh_enable_dbgfs_get(void *data, u64 *val) +{ + if (eeh_enabled()) + *val = 0x1ul; + else + *val = 0x0ul; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(eeh_enable_dbgfs_ops, eeh_enable_dbgfs_get, + eeh_enable_dbgfs_set, "0x%llx\n"); +#endif + static int __init eeh_init_proc(void) { - if (machine_is(pseries) || machine_is(powernv)) + if (machine_is(pseries) || machine_is(powernv)) { proc_create("powerpc/eeh", 0, NULL, &proc_eeh_operations); +#ifdef CONFIG_DEBUG_FS + debugfs_create_file("eeh_enable", 0600, + powerpc_debugfs_root, NULL, + &eeh_enable_dbgfs_ops); +#endif + } + return 0; } __initcall(eeh_init_proc); diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index bb61ca58ca6d82..7100a5b96e7059 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -171,6 +171,15 @@ static void eeh_enable_irq(struct pci_dev *dev) } } +static bool eeh_dev_removed(struct eeh_dev *edev) +{ + /* EEH device removed ? */ + if (!edev || (edev->mode & EEH_DEV_REMOVED)) + return true; + + return false; +} + /** * eeh_report_error - Report pci error to each device driver * @data: eeh device @@ -187,10 +196,8 @@ static void *eeh_report_error(void *data, void *userdata) enum pci_ers_result rc, *res = userdata; struct pci_driver *driver; - /* We might not have the associated PCI device, - * then we should continue for next one. - */ - if (!dev) return NULL; + if (!dev || eeh_dev_removed(edev)) + return NULL; dev->error_state = pci_channel_io_frozen; driver = eeh_pcid_get(dev); @@ -230,6 +237,9 @@ static void *eeh_report_mmio_enabled(void *data, void *userdata) enum pci_ers_result rc, *res = userdata; struct pci_driver *driver; + if (!dev || eeh_dev_removed(edev)) + return NULL; + driver = eeh_pcid_get(dev); if (!driver) return NULL; @@ -267,7 +277,8 @@ static void *eeh_report_reset(void *data, void *userdata) enum pci_ers_result rc, *res = userdata; struct pci_driver *driver; - if (!dev) return NULL; + if (!dev || eeh_dev_removed(edev)) + return NULL; dev->error_state = pci_channel_io_normal; driver = eeh_pcid_get(dev); @@ -307,7 +318,8 @@ static void *eeh_report_resume(void *data, void *userdata) struct pci_dev *dev = eeh_dev_to_pci_dev(edev); struct pci_driver *driver; - if (!dev) return NULL; + if (!dev || eeh_dev_removed(edev)) + return NULL; dev->error_state = pci_channel_io_normal; driver = eeh_pcid_get(dev); @@ -343,7 +355,8 @@ static void *eeh_report_failure(void *data, void *userdata) struct pci_dev *dev = eeh_dev_to_pci_dev(edev); struct pci_driver *driver; - if (!dev) return NULL; + if (!dev || eeh_dev_removed(edev)) + return NULL; dev->error_state = pci_channel_io_perm_failure; driver = eeh_pcid_get(dev); @@ -380,6 +393,16 @@ static void *eeh_rmv_device(void *data, void *userdata) if (!dev || (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) return NULL; + /* + * We rely on count-based pcibios_release_device() to + * detach permanently offlined PEs. Unfortunately, that's + * not reliable enough. We might have the permanently + * offlined PEs attached, but we needn't take care of + * them and their child devices. + */ + if (eeh_dev_removed(edev)) + return NULL; + driver = eeh_pcid_get(dev); if (driver) { eeh_pcid_put(dev); @@ -417,6 +440,36 @@ static void *eeh_pe_detach_dev(void *data, void *userdata) return NULL; } +/* + * Explicitly clear PE's frozen state for PowerNV where + * we have frozen PE until BAR restore is completed. It's + * harmless to clear it for pSeries. To be consistent with + * PE reset (for 3 times), we try to clear the frozen state + * for 3 times as well. + */ +static int eeh_clear_pe_frozen_state(struct eeh_pe *pe) +{ + int i, rc; + + for (i = 0; i < 3; i++) { + rc = eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); + if (rc) + continue; + rc = eeh_pci_enable(pe, EEH_OPT_THAW_DMA); + if (!rc) + break; + } + + /* The PE has been isolated, clear it */ + if (rc) + pr_warn("%s: Can't clear frozen PHB#%x-PE#%x (%d)\n", + __func__, pe->phb->global_number, pe->addr, rc); + else + eeh_pe_state_clear(pe, EEH_PE_ISOLATED); + + return rc; +} + /** * eeh_reset_device - Perform actual reset of a pci slot * @pe: EEH PE @@ -451,19 +504,33 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed); } - /* Reset the pci controller. (Asserts RST#; resets config space). + /* + * Reset the pci controller. (Asserts RST#; resets config space). * Reconfigure bridges and devices. Don't try to bring the system * up if the reset failed for some reason. + * + * During the reset, it's very dangerous to have uncontrolled PCI + * config accesses. So we prefer to block them. However, controlled + * PCI config accesses initiated from EEH itself are allowed. */ + eeh_pe_state_mark(pe, EEH_PE_RESET); rc = eeh_reset_pe(pe); - if (rc) + if (rc) { + eeh_pe_state_clear(pe, EEH_PE_RESET); return rc; + } pci_lock_rescan_remove(); /* Restore PE */ eeh_ops->configure_bridge(pe); eeh_pe_restore_bars(pe); + eeh_pe_state_clear(pe, EEH_PE_RESET); + + /* Clear frozen state */ + rc = eeh_clear_pe_frozen_state(pe); + if (rc) + return rc; /* Give the system 5 seconds to finish running the user-space * hotplug shutdown scripts, e.g. ifdown for ethernet. Yes, @@ -573,7 +640,6 @@ static void eeh_handle_normal_event(struct eeh_pe *pe) result = PCI_ERS_RESULT_NEED_RESET; } else { pr_info("EEH: Notify device drivers to resume I/O\n"); - result = PCI_ERS_RESULT_NONE; eeh_pe_dev_traverse(pe, eeh_report_mmio_enabled, &result); } } @@ -585,10 +651,17 @@ static void eeh_handle_normal_event(struct eeh_pe *pe) if (rc < 0) goto hard_fail; - if (rc) + if (rc) { result = PCI_ERS_RESULT_NEED_RESET; - else + } else { + /* + * We didn't do PE reset for the case. The PE + * is still in frozen state. Clear it before + * resuming the PE. + */ + eeh_pe_state_clear(pe, EEH_PE_ISOLATED); result = PCI_ERS_RESULT_RECOVERED; + } } /* If any device has a hard failure, then shut off everything. */ @@ -650,8 +723,17 @@ static void eeh_handle_normal_event(struct eeh_pe *pe) /* Notify all devices that they're about to go down. */ eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); - /* Shut down the device drivers for good. */ + /* Mark the PE to be removed permanently */ + pe->freeze_count = EEH_MAX_ALLOWED_FREEZES + 1; + + /* + * Shut down the device drivers for good. We mark + * all removed devices correctly to avoid access + * the their PCI config any more. + */ if (frozen_bus) { + eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); + pci_lock_rescan_remove(); pcibios_remove_pci_devices(frozen_bus); pci_unlock_rescan_remove(); @@ -682,8 +764,7 @@ static void eeh_handle_special_event(void) phb_pe = eeh_phb_pe_get(hose); if (!phb_pe) continue; - eeh_pe_state_mark(phb_pe, - EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); + eeh_pe_state_mark(phb_pe, EEH_PE_ISOLATED); } eeh_serialize_unlock(flags); @@ -699,8 +780,7 @@ static void eeh_handle_special_event(void) eeh_remove_event(pe); if (rc == EEH_NEXT_ERR_DEAD_PHB) - eeh_pe_state_mark(pe, - EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); + eeh_pe_state_mark(pe, EEH_PE_ISOLATED); else eeh_pe_state_mark(pe, EEH_PE_ISOLATED | EEH_PE_RECOVERING); @@ -724,12 +804,14 @@ static void eeh_handle_special_event(void) if (rc == EEH_NEXT_ERR_FROZEN_PE || rc == EEH_NEXT_ERR_FENCED_PHB) { eeh_handle_normal_event(pe); + eeh_pe_state_clear(pe, EEH_PE_RECOVERING); } else { pci_lock_rescan_remove(); list_for_each_entry(hose, &hose_list, list_node) { phb_pe = eeh_phb_pe_get(hose); if (!phb_pe || - !(phb_pe->state & EEH_PE_PHB_DEAD)) + !(phb_pe->state & EEH_PE_ISOLATED) || + (phb_pe->state & EEH_PE_RECOVERING)) continue; /* Notify all devices to be down */ diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index f0c353fa655a3a..995c2a2846303d 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c @@ -503,13 +503,17 @@ static void *__eeh_pe_state_mark(void *data, void *flag) struct eeh_dev *edev, *tmp; struct pci_dev *pdev; - /* - * Mark the PE with the indicated state. Also, - * the associated PCI device will be put into - * I/O frozen state to avoid I/O accesses from - * the PCI device driver. - */ + /* Keep the state of permanently removed PE intact */ + if ((pe->freeze_count > EEH_MAX_ALLOWED_FREEZES) && + (state & (EEH_PE_ISOLATED | EEH_PE_RECOVERING))) + return NULL; + pe->state |= state; + + /* Offline PCI devices if applicable */ + if (state != EEH_PE_ISOLATED) + return NULL; + eeh_pe_for_each_dev(pe, edev, tmp) { pdev = eeh_dev_to_pci_dev(edev); if (pdev) @@ -532,6 +536,27 @@ void eeh_pe_state_mark(struct eeh_pe *pe, int state) eeh_pe_traverse(pe, __eeh_pe_state_mark, &state); } +static void *__eeh_pe_dev_mode_mark(void *data, void *flag) +{ + struct eeh_dev *edev = data; + int mode = *((int *)flag); + + edev->mode |= mode; + + return NULL; +} + +/** + * eeh_pe_dev_state_mark - Mark state for all device under the PE + * @pe: EEH PE + * + * Mark specific state for all child devices of the PE. + */ +void eeh_pe_dev_mode_mark(struct eeh_pe *pe, int mode) +{ + eeh_pe_dev_traverse(pe, __eeh_pe_dev_mode_mark, &mode); +} + /** * __eeh_pe_state_clear - Clear state for the PE * @data: EEH PE @@ -546,8 +571,16 @@ static void *__eeh_pe_state_clear(void *data, void *flag) struct eeh_pe *pe = (struct eeh_pe *)data; int state = *((int *)flag); + /* Keep the state of permanently removed PE intact */ + if ((pe->freeze_count > EEH_MAX_ALLOWED_FREEZES) && + (state & EEH_PE_ISOLATED)) + return NULL; + pe->state &= ~state; - pe->check_count = 0; + + /* Clear check count since last isolation */ + if (state & EEH_PE_ISOLATED) + pe->check_count = 0; return NULL; } diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 662c6dd98072e7..9fde8a1bf1e14d 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -39,8 +39,8 @@ * System calls. */ .section ".toc","aw" -.SYS_CALL_TABLE: - .tc .sys_call_table[TC],.sys_call_table +SYS_CALL_TABLE: + .tc sys_call_table[TC],sys_call_table /* This value is used to mark exception frames on the stack. */ exception_marker: @@ -106,7 +106,7 @@ BEGIN_FW_FTR_SECTION LDX_BE r10,0,r10 /* get log write index */ cmpd cr1,r11,r10 beq+ cr1,33f - bl .accumulate_stolen_time + bl accumulate_stolen_time REST_GPR(0,r1) REST_4GPRS(3,r1) REST_2GPRS(7,r1) @@ -143,7 +143,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) std r10,SOFTE(r1) #ifdef SHOW_SYSCALLS - bl .do_show_syscall + bl do_show_syscall REST_GPR(0,r1) REST_4GPRS(3,r1) REST_2GPRS(7,r1) @@ -162,7 +162,7 @@ system_call: /* label this so stack traces look sane */ * Need to vector to 32 Bit or default sys_call_table here, * based on caller's run-mode / personality. */ - ld r11,.SYS_CALL_TABLE@toc(2) + ld r11,SYS_CALL_TABLE@toc(2) andi. r10,r10,_TIF_32BIT beq 15f addi r11,r11,8 /* use 32-bit syscall entries */ @@ -174,14 +174,14 @@ system_call: /* label this so stack traces look sane */ clrldi r8,r8,32 15: slwi r0,r0,4 - ldx r10,r11,r0 /* Fetch system call handler [ptr] */ - mtctr r10 + ldx r12,r11,r0 /* Fetch system call handler [ptr] */ + mtctr r12 bctrl /* Call handler */ syscall_exit: std r3,RESULT(r1) #ifdef SHOW_SYSCALLS - bl .do_show_syscall_exit + bl do_show_syscall_exit ld r3,RESULT(r1) #endif CURRENT_THREAD_INFO(r12, r1) @@ -248,9 +248,9 @@ syscall_error: /* Traced system call support */ syscall_dotrace: - bl .save_nvgprs + bl save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_syscall_trace_enter + bl do_syscall_trace_enter /* * Restore argument registers possibly just changed. * We use the return value of do_syscall_trace_enter @@ -308,7 +308,7 @@ syscall_exit_work: 4: /* Anything else left to do? */ SET_DEFAULT_THREAD_PPR(r3, r10) /* Set thread.ppr = 3 */ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) - beq .ret_from_except_lite + beq ret_from_except_lite /* Re-enable interrupts */ #ifdef CONFIG_PPC_BOOK3E @@ -319,10 +319,10 @@ syscall_exit_work: mtmsrd r10,1 #endif /* CONFIG_PPC_BOOK3E */ - bl .save_nvgprs + bl save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_syscall_trace_leave - b .ret_from_except + bl do_syscall_trace_leave + b ret_from_except /* Save non-volatile GPRs, if not already saved. */ _GLOBAL(save_nvgprs) @@ -345,42 +345,44 @@ _GLOBAL(save_nvgprs) */ _GLOBAL(ppc_fork) - bl .save_nvgprs - bl .sys_fork + bl save_nvgprs + bl sys_fork b syscall_exit _GLOBAL(ppc_vfork) - bl .save_nvgprs - bl .sys_vfork + bl save_nvgprs + bl sys_vfork b syscall_exit _GLOBAL(ppc_clone) - bl .save_nvgprs - bl .sys_clone + bl save_nvgprs + bl sys_clone b syscall_exit _GLOBAL(ppc32_swapcontext) - bl .save_nvgprs - bl .compat_sys_swapcontext + bl save_nvgprs + bl compat_sys_swapcontext b syscall_exit _GLOBAL(ppc64_swapcontext) - bl .save_nvgprs - bl .sys_swapcontext + bl save_nvgprs + bl sys_swapcontext b syscall_exit _GLOBAL(ret_from_fork) - bl .schedule_tail + bl schedule_tail REST_NVGPRS(r1) li r3,0 b syscall_exit _GLOBAL(ret_from_kernel_thread) - bl .schedule_tail + bl schedule_tail REST_NVGPRS(r1) - ld r14, 0(r14) mtlr r14 mr r3,r15 +#if defined(_CALL_ELF) && _CALL_ELF == 2 + mr r12,r14 +#endif blrl li r3,0 b syscall_exit @@ -611,7 +613,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_DSCR) _GLOBAL(ret_from_except) ld r11,_TRAP(r1) andi. r0,r11,1 - bne .ret_from_except_lite + bne ret_from_except_lite REST_NVGPRS(r1) _GLOBAL(ret_from_except_lite) @@ -661,23 +663,23 @@ _GLOBAL(ret_from_except_lite) #endif 1: andi. r0,r4,_TIF_NEED_RESCHED beq 2f - bl .restore_interrupts + bl restore_interrupts SCHEDULE_USER - b .ret_from_except_lite + b ret_from_except_lite 2: #ifdef CONFIG_PPC_TRANSACTIONAL_MEM andi. r0,r4,_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM bne 3f /* only restore TM if nothing else to do */ addi r3,r1,STACK_FRAME_OVERHEAD - bl .restore_tm_state + bl restore_tm_state b restore 3: #endif - bl .save_nvgprs - bl .restore_interrupts + bl save_nvgprs + bl restore_interrupts addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_notify_resume - b .ret_from_except + bl do_notify_resume + b ret_from_except resume_kernel: /* check current_thread_info, _TIF_EMULATE_STACK_STORE */ @@ -730,7 +732,7 @@ resume_kernel: * sure we are soft-disabled first and reconcile irq state. */ RECONCILE_IRQ_STATE(r3,r4) -1: bl .preempt_schedule_irq +1: bl preempt_schedule_irq /* Re-test flags and eventually loop */ CURRENT_THREAD_INFO(r9, r1) @@ -792,7 +794,7 @@ restore_no_replay: */ do_restore: #ifdef CONFIG_PPC_BOOK3E - b .exception_return_book3e + b exception_return_book3e #else /* * Clear the reservation. If we know the CPU tracks the address of @@ -907,7 +909,7 @@ restore_check_irq_replay: * * Still, this might be useful for things like hash_page */ - bl .__check_irq_replay + bl __check_irq_replay cmpwi cr0,r3,0 beq restore_no_replay @@ -928,13 +930,13 @@ restore_check_irq_replay: cmpwi cr0,r3,0x500 bne 1f addi r3,r1,STACK_FRAME_OVERHEAD; - bl .do_IRQ - b .ret_from_except + bl do_IRQ + b ret_from_except 1: cmpwi cr0,r3,0x900 bne 1f addi r3,r1,STACK_FRAME_OVERHEAD; - bl .timer_interrupt - b .ret_from_except + bl timer_interrupt + b ret_from_except #ifdef CONFIG_PPC_DOORBELL 1: #ifdef CONFIG_PPC_BOOK3E @@ -948,14 +950,14 @@ restore_check_irq_replay: #endif /* CONFIG_PPC_BOOK3E */ bne 1f addi r3,r1,STACK_FRAME_OVERHEAD; - bl .doorbell_exception - b .ret_from_except + bl doorbell_exception + b ret_from_except #endif /* CONFIG_PPC_DOORBELL */ -1: b .ret_from_except /* What else to do here ? */ +1: b ret_from_except /* What else to do here ? */ unrecov_restore: addi r3,r1,STACK_FRAME_OVERHEAD - bl .unrecoverable_exception + bl unrecoverable_exception b unrecov_restore #ifdef CONFIG_PPC_RTAS @@ -1021,7 +1023,7 @@ _GLOBAL(enter_rtas) std r6,PACASAVEDMSR(r13) /* Setup our real return addr */ - LOAD_REG_ADDR(r4,.rtas_return_loc) + LOAD_REG_ADDR(r4,rtas_return_loc) clrldi r4,r4,2 /* convert to realmode address */ mtlr r4 @@ -1045,7 +1047,7 @@ _GLOBAL(enter_rtas) rfid b . /* prevent speculative execution */ -_STATIC(rtas_return_loc) +rtas_return_loc: FIXUP_ENDIAN /* relocation is off at this point */ @@ -1054,7 +1056,7 @@ _STATIC(rtas_return_loc) bcl 20,31,$+4 0: mflr r3 - ld r3,(1f-0b)(r3) /* get &.rtas_restore_regs */ + ld r3,(1f-0b)(r3) /* get &rtas_restore_regs */ mfmsr r6 li r0,MSR_RI @@ -1071,9 +1073,9 @@ _STATIC(rtas_return_loc) b . /* prevent speculative execution */ .align 3 -1: .llong .rtas_restore_regs +1: .llong rtas_restore_regs -_STATIC(rtas_restore_regs) +rtas_restore_regs: /* relocation is on at this point */ REST_GPR(2, r1) /* Restore the TOC */ REST_GPR(13, r1) /* Restore paca */ @@ -1173,7 +1175,7 @@ _GLOBAL(mcount) _GLOBAL(_mcount) blr -_GLOBAL(ftrace_caller) +_GLOBAL_TOC(ftrace_caller) /* Taken from output of objdump from lib64/glibc */ mflr r3 ld r11, 0(r1) @@ -1197,10 +1199,7 @@ _GLOBAL(ftrace_graph_stub) _GLOBAL(ftrace_stub) blr #else -_GLOBAL(mcount) - blr - -_GLOBAL(_mcount) +_GLOBAL_TOC(_mcount) /* Taken from output of objdump from lib64/glibc */ mflr r3 ld r11, 0(r1) @@ -1238,7 +1237,7 @@ _GLOBAL(ftrace_graph_caller) ld r11, 112(r1) addi r3, r11, 16 - bl .prepare_ftrace_return + bl prepare_ftrace_return nop ld r0, 128(r1) @@ -1254,7 +1253,7 @@ _GLOBAL(return_to_handler) mr r31, r1 stdu r1, -112(r1) - bl .ftrace_return_to_handler + bl ftrace_return_to_handler nop /* return value has real return address */ @@ -1284,7 +1283,7 @@ _GLOBAL(mod_return_to_handler) */ ld r2, PACATOC(r13) - bl .ftrace_return_to_handler + bl ftrace_return_to_handler nop /* return value has real return address */ diff --git a/arch/powerpc/kernel/epapr_paravirt.c b/arch/powerpc/kernel/epapr_paravirt.c index 7898be90f2dcd0..d64e92b22dd84b 100644 --- a/arch/powerpc/kernel/epapr_paravirt.c +++ b/arch/powerpc/kernel/epapr_paravirt.c @@ -36,7 +36,7 @@ static int __init early_init_dt_scan_epapr(unsigned long node, int depth, void *data) { const u32 *insts; - unsigned long len; + int len; int i; insts = of_get_flat_dt_prop(node, "hcall-instructions", &len); diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index c1bee3ce9d1fb6..771b4e92e5d9c0 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -499,7 +499,7 @@ exc_##n##_bad_stack: \ CHECK_NAPPING(); \ addi r3,r1,STACK_FRAME_OVERHEAD; \ bl hdlr; \ - b .ret_from_except_lite; + b ret_from_except_lite; /* This value is used to mark exception frames on the stack. */ .section ".toc","aw" @@ -550,11 +550,11 @@ interrupt_end_book3e: CRIT_EXCEPTION_PROLOG(0x100, BOOKE_INTERRUPT_CRITICAL, PROLOG_ADDITION_NONE) EXCEPTION_COMMON_CRIT(0x100) - bl .save_nvgprs + bl save_nvgprs bl special_reg_save CHECK_NAPPING(); addi r3,r1,STACK_FRAME_OVERHEAD - bl .unknown_exception + bl unknown_exception b ret_from_crit_except /* Machine Check Interrupt */ @@ -562,11 +562,11 @@ interrupt_end_book3e: MC_EXCEPTION_PROLOG(0x000, BOOKE_INTERRUPT_MACHINE_CHECK, PROLOG_ADDITION_NONE) EXCEPTION_COMMON_MC(0x000) - bl .save_nvgprs + bl save_nvgprs bl special_reg_save CHECK_NAPPING(); addi r3,r1,STACK_FRAME_OVERHEAD - bl .machine_check_exception + bl machine_check_exception b ret_from_mc_except /* Data Storage Interrupt */ @@ -591,7 +591,7 @@ interrupt_end_book3e: /* External Input Interrupt */ MASKABLE_EXCEPTION(0x500, BOOKE_INTERRUPT_EXTERNAL, - external_input, .do_IRQ, ACK_NONE) + external_input, do_IRQ, ACK_NONE) /* Alignment */ START_EXCEPTION(alignment); @@ -612,9 +612,9 @@ interrupt_end_book3e: std r14,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD ld r14,PACA_EXGEN+EX_R14(r13) - bl .save_nvgprs - bl .program_check_exception - b .ret_from_except + bl save_nvgprs + bl program_check_exception + b ret_from_except /* Floating Point Unavailable Interrupt */ START_EXCEPTION(fp_unavailable); @@ -625,13 +625,13 @@ interrupt_end_book3e: ld r12,_MSR(r1) andi. r0,r12,MSR_PR; beq- 1f - bl .load_up_fpu + bl load_up_fpu b fast_exception_return 1: INTS_DISABLE - bl .save_nvgprs + bl save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD - bl .kernel_fp_unavailable_exception - b .ret_from_except + bl kernel_fp_unavailable_exception + b ret_from_except /* Altivec Unavailable Interrupt */ START_EXCEPTION(altivec_unavailable); @@ -644,16 +644,16 @@ BEGIN_FTR_SECTION ld r12,_MSR(r1) andi. r0,r12,MSR_PR; beq- 1f - bl .load_up_altivec + bl load_up_altivec b fast_exception_return 1: END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif INTS_DISABLE - bl .save_nvgprs + bl save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD - bl .altivec_unavailable_exception - b .ret_from_except + bl altivec_unavailable_exception + b ret_from_except /* AltiVec Assist */ START_EXCEPTION(altivec_assist); @@ -662,39 +662,39 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) PROLOG_ADDITION_NONE) EXCEPTION_COMMON(0x220) INTS_DISABLE - bl .save_nvgprs + bl save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD #ifdef CONFIG_ALTIVEC BEGIN_FTR_SECTION - bl .altivec_assist_exception + bl altivec_assist_exception END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #else - bl .unknown_exception + bl unknown_exception #endif - b .ret_from_except + b ret_from_except /* Decrementer Interrupt */ MASKABLE_EXCEPTION(0x900, BOOKE_INTERRUPT_DECREMENTER, - decrementer, .timer_interrupt, ACK_DEC) + decrementer, timer_interrupt, ACK_DEC) /* Fixed Interval Timer Interrupt */ MASKABLE_EXCEPTION(0x980, BOOKE_INTERRUPT_FIT, - fixed_interval, .unknown_exception, ACK_FIT) + fixed_interval, unknown_exception, ACK_FIT) /* Watchdog Timer Interrupt */ START_EXCEPTION(watchdog); CRIT_EXCEPTION_PROLOG(0x9f0, BOOKE_INTERRUPT_WATCHDOG, PROLOG_ADDITION_NONE) EXCEPTION_COMMON_CRIT(0x9f0) - bl .save_nvgprs + bl save_nvgprs bl special_reg_save CHECK_NAPPING(); addi r3,r1,STACK_FRAME_OVERHEAD #ifdef CONFIG_BOOKE_WDT - bl .WatchdogException + bl WatchdogException #else - bl .unknown_exception + bl unknown_exception #endif b ret_from_crit_except @@ -712,10 +712,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) PROLOG_ADDITION_NONE) EXCEPTION_COMMON(0xf20) INTS_DISABLE - bl .save_nvgprs + bl save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD - bl .unknown_exception - b .ret_from_except + bl unknown_exception + b ret_from_except /* Debug exception as a critical interrupt*/ START_EXCEPTION(debug_crit); @@ -774,9 +774,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) mr r4,r14 ld r14,PACA_EXCRIT+EX_R14(r13) ld r15,PACA_EXCRIT+EX_R15(r13) - bl .save_nvgprs - bl .DebugException - b .ret_from_except + bl save_nvgprs + bl DebugException + b ret_from_except kernel_dbg_exc: b . /* NYI */ @@ -839,9 +839,9 @@ kernel_dbg_exc: mr r4,r14 ld r14,PACA_EXDBG+EX_R14(r13) ld r15,PACA_EXDBG+EX_R15(r13) - bl .save_nvgprs - bl .DebugException - b .ret_from_except + bl save_nvgprs + bl DebugException + b ret_from_except START_EXCEPTION(perfmon); NORMAL_EXCEPTION_PROLOG(0x260, BOOKE_INTERRUPT_PERFORMANCE_MONITOR, @@ -850,23 +850,23 @@ kernel_dbg_exc: INTS_DISABLE CHECK_NAPPING() addi r3,r1,STACK_FRAME_OVERHEAD - bl .performance_monitor_exception - b .ret_from_except_lite + bl performance_monitor_exception + b ret_from_except_lite /* Doorbell interrupt */ MASKABLE_EXCEPTION(0x280, BOOKE_INTERRUPT_DOORBELL, - doorbell, .doorbell_exception, ACK_NONE) + doorbell, doorbell_exception, ACK_NONE) /* Doorbell critical Interrupt */ START_EXCEPTION(doorbell_crit); CRIT_EXCEPTION_PROLOG(0x2a0, BOOKE_INTERRUPT_DOORBELL_CRITICAL, PROLOG_ADDITION_NONE) EXCEPTION_COMMON_CRIT(0x2a0) - bl .save_nvgprs + bl save_nvgprs bl special_reg_save CHECK_NAPPING(); addi r3,r1,STACK_FRAME_OVERHEAD - bl .unknown_exception + bl unknown_exception b ret_from_crit_except /* @@ -878,21 +878,21 @@ kernel_dbg_exc: PROLOG_ADDITION_NONE) EXCEPTION_COMMON(0x2c0) addi r3,r1,STACK_FRAME_OVERHEAD - bl .save_nvgprs + bl save_nvgprs INTS_RESTORE_HARD - bl .unknown_exception - b .ret_from_except + bl unknown_exception + b ret_from_except /* Guest Doorbell critical Interrupt */ START_EXCEPTION(guest_doorbell_crit); CRIT_EXCEPTION_PROLOG(0x2e0, BOOKE_INTERRUPT_GUEST_DBELL_CRIT, PROLOG_ADDITION_NONE) EXCEPTION_COMMON_CRIT(0x2e0) - bl .save_nvgprs + bl save_nvgprs bl special_reg_save CHECK_NAPPING(); addi r3,r1,STACK_FRAME_OVERHEAD - bl .unknown_exception + bl unknown_exception b ret_from_crit_except /* Hypervisor call */ @@ -901,10 +901,10 @@ kernel_dbg_exc: PROLOG_ADDITION_NONE) EXCEPTION_COMMON(0x310) addi r3,r1,STACK_FRAME_OVERHEAD - bl .save_nvgprs + bl save_nvgprs INTS_RESTORE_HARD - bl .unknown_exception - b .ret_from_except + bl unknown_exception + b ret_from_except /* Embedded Hypervisor priviledged */ START_EXCEPTION(ehpriv); @@ -912,10 +912,10 @@ kernel_dbg_exc: PROLOG_ADDITION_NONE) EXCEPTION_COMMON(0x320) addi r3,r1,STACK_FRAME_OVERHEAD - bl .save_nvgprs + bl save_nvgprs INTS_RESTORE_HARD - bl .unknown_exception - b .ret_from_except + bl unknown_exception + b ret_from_except /* LRAT Error interrupt */ START_EXCEPTION(lrat_error); @@ -1014,16 +1014,16 @@ storage_fault_common: mr r5,r15 ld r14,PACA_EXGEN+EX_R14(r13) ld r15,PACA_EXGEN+EX_R15(r13) - bl .do_page_fault + bl do_page_fault cmpdi r3,0 bne- 1f - b .ret_from_except_lite -1: bl .save_nvgprs + b ret_from_except_lite +1: bl save_nvgprs mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD ld r4,_DAR(r1) - bl .bad_page_fault - b .ret_from_except + bl bad_page_fault + b ret_from_except /* * Alignment exception doesn't fit entirely in the 0x100 bytes so it @@ -1035,10 +1035,10 @@ alignment_more: addi r3,r1,STACK_FRAME_OVERHEAD ld r14,PACA_EXGEN+EX_R14(r13) ld r15,PACA_EXGEN+EX_R15(r13) - bl .save_nvgprs + bl save_nvgprs INTS_RESTORE_HARD - bl .alignment_exception - b .ret_from_except + bl alignment_exception + b ret_from_except /* * We branch here from entry_64.S for the last stage of the exception @@ -1172,7 +1172,7 @@ bad_stack_book3e: std r12,0(r11) ld r2,PACATOC(r13) 1: addi r3,r1,STACK_FRAME_OVERHEAD - bl .kernel_bad_stack + bl kernel_bad_stack b 1b /* @@ -1521,13 +1521,13 @@ _GLOBAL(start_initialization_book3e) * and always use AS 0, so we just set it up to match our link * address and never use 0 based addresses. */ - bl .initial_tlb_book3e + bl initial_tlb_book3e /* Init global core bits */ - bl .init_core_book3e + bl init_core_book3e /* Init per-thread bits */ - bl .init_thread_book3e + bl init_thread_book3e /* Return to common init code */ tovirt(r28,r28) @@ -1548,7 +1548,7 @@ _GLOBAL(start_initialization_book3e) */ _GLOBAL(book3e_secondary_core_init_tlb_set) li r4,1 - b .generic_secondary_smp_init + b generic_secondary_smp_init _GLOBAL(book3e_secondary_core_init) mflr r28 @@ -1558,18 +1558,18 @@ _GLOBAL(book3e_secondary_core_init) bne 2f /* Setup TLB for this core */ - bl .initial_tlb_book3e + bl initial_tlb_book3e /* We can return from the above running at a different * address, so recalculate r2 (TOC) */ - bl .relative_toc + bl relative_toc /* Init global core bits */ -2: bl .init_core_book3e +2: bl init_core_book3e /* Init per-thread bits */ -3: bl .init_thread_book3e +3: bl init_thread_book3e /* Return to common init code at proper virtual address. * @@ -1596,14 +1596,14 @@ _GLOBAL(book3e_secondary_thread_init) mflr r28 b 3b -_STATIC(init_core_book3e) +init_core_book3e: /* Establish the interrupt vector base */ LOAD_REG_IMMEDIATE(r3, interrupt_base_book3e) mtspr SPRN_IVPR,r3 sync blr -_STATIC(init_thread_book3e) +init_thread_book3e: lis r3,(SPRN_EPCR_ICM | SPRN_EPCR_GICM)@h mtspr SPRN_EPCR,r3 diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 3afd3915921a26..20f11eb4dff7ee 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -132,12 +132,12 @@ BEGIN_FTR_SECTION #endif beq cr1,2f - b .power7_wakeup_noloss -2: b .power7_wakeup_loss + b power7_wakeup_noloss +2: b power7_wakeup_loss /* Fast Sleep wakeup on PowerNV */ 8: GET_PACA(r13) - b .power7_wakeup_tb_loss + b power7_wakeup_tb_loss 9: END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) @@ -211,16 +211,16 @@ data_access_slb_pSeries: #endif /* __DISABLED__ */ mfspr r12,SPRN_SRR1 #ifndef CONFIG_RELOCATABLE - b .slb_miss_realmode + b slb_miss_realmode #else /* - * We can't just use a direct branch to .slb_miss_realmode + * We can't just use a direct branch to slb_miss_realmode * because the distance from here to there depends on where * the kernel ends up being put. */ mfctr r11 ld r10,PACAKBASE(r13) - LOAD_HANDLER(r10, .slb_miss_realmode) + LOAD_HANDLER(r10, slb_miss_realmode) mtctr r10 bctr #endif @@ -243,11 +243,11 @@ instruction_access_slb_pSeries: #endif /* __DISABLED__ */ mfspr r12,SPRN_SRR1 #ifndef CONFIG_RELOCATABLE - b .slb_miss_realmode + b slb_miss_realmode #else mfctr r11 ld r10,PACAKBASE(r13) - LOAD_HANDLER(r10, .slb_miss_realmode) + LOAD_HANDLER(r10, slb_miss_realmode) mtctr r10 bctr #endif @@ -524,7 +524,7 @@ do_stab_bolted_pSeries: std r12,PACA_EXSLB+EX_R12(r13) GET_SCRATCH0(r10) std r10,PACA_EXSLB+EX_R13(r13) - EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD) + EXCEPTION_PROLOG_PSERIES_1(do_stab_bolted, EXC_STD) KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300) KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380) @@ -769,38 +769,38 @@ kvmppc_skip_Hinterrupt: /*** Common interrupt handlers ***/ - STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception) + STD_EXCEPTION_COMMON(0x100, system_reset, system_reset_exception) STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ) - STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt) - STD_EXCEPTION_COMMON(0x980, hdecrementer, .hdec_interrupt) + STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, timer_interrupt) + STD_EXCEPTION_COMMON(0x980, hdecrementer, hdec_interrupt) #ifdef CONFIG_PPC_DOORBELL - STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, .doorbell_exception) + STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, doorbell_exception) #else - STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, .unknown_exception) + STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, unknown_exception) #endif - STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) - STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) - STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception) - STD_EXCEPTION_COMMON(0xe40, emulation_assist, .emulation_assist_interrupt) - STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception) + STD_EXCEPTION_COMMON(0xb00, trap_0b, unknown_exception) + STD_EXCEPTION_COMMON(0xd00, single_step, single_step_exception) + STD_EXCEPTION_COMMON(0xe00, trap_0e, unknown_exception) + STD_EXCEPTION_COMMON(0xe40, emulation_assist, emulation_assist_interrupt) + STD_EXCEPTION_COMMON(0xe60, hmi_exception, unknown_exception) #ifdef CONFIG_PPC_DOORBELL - STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, .doorbell_exception) + STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, doorbell_exception) #else - STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, .unknown_exception) + STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, unknown_exception) #endif - STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception) - STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) - STD_EXCEPTION_COMMON(0x1502, denorm, .unknown_exception) + STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, performance_monitor_exception) + STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, instruction_breakpoint_exception) + STD_EXCEPTION_COMMON(0x1502, denorm, unknown_exception) #ifdef CONFIG_ALTIVEC - STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception) + STD_EXCEPTION_COMMON(0x1700, altivec_assist, altivec_assist_exception) #else - STD_EXCEPTION_COMMON(0x1700, altivec_assist, .unknown_exception) + STD_EXCEPTION_COMMON(0x1700, altivec_assist, unknown_exception) #endif #ifdef CONFIG_CBE_RAS - STD_EXCEPTION_COMMON(0x1200, cbe_system_error, .cbe_system_error_exception) - STD_EXCEPTION_COMMON(0x1600, cbe_maintenance, .cbe_maintenance_exception) - STD_EXCEPTION_COMMON(0x1800, cbe_thermal, .cbe_thermal_exception) + STD_EXCEPTION_COMMON(0x1200, cbe_system_error, cbe_system_error_exception) + STD_EXCEPTION_COMMON(0x1600, cbe_maintenance, cbe_maintenance_exception) + STD_EXCEPTION_COMMON(0x1800, cbe_thermal, cbe_thermal_exception) #endif /* CONFIG_CBE_RAS */ /* @@ -829,16 +829,16 @@ data_access_slb_relon_pSeries: mfspr r3,SPRN_DAR mfspr r12,SPRN_SRR1 #ifndef CONFIG_RELOCATABLE - b .slb_miss_realmode + b slb_miss_realmode #else /* - * We can't just use a direct branch to .slb_miss_realmode + * We can't just use a direct branch to slb_miss_realmode * because the distance from here to there depends on where * the kernel ends up being put. */ mfctr r11 ld r10,PACAKBASE(r13) - LOAD_HANDLER(r10, .slb_miss_realmode) + LOAD_HANDLER(r10, slb_miss_realmode) mtctr r10 bctr #endif @@ -854,11 +854,11 @@ instruction_access_slb_relon_pSeries: mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ mfspr r12,SPRN_SRR1 #ifndef CONFIG_RELOCATABLE - b .slb_miss_realmode + b slb_miss_realmode #else mfctr r11 ld r10,PACAKBASE(r13) - LOAD_HANDLER(r10, .slb_miss_realmode) + LOAD_HANDLER(r10, slb_miss_realmode) mtctr r10 bctr #endif @@ -966,7 +966,7 @@ system_call_entry: b system_call_common ppc64_runlatch_on_trampoline: - b .__ppc64_runlatch_on + b __ppc64_runlatch_on /* * Here we have detected that the kernel stack pointer is bad. @@ -1025,7 +1025,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR) std r12,RESULT(r1) std r11,STACK_FRAME_OVERHEAD-16(r1) 1: addi r3,r1,STACK_FRAME_OVERHEAD - bl .kernel_bad_stack + bl kernel_bad_stack b 1b /* @@ -1046,7 +1046,7 @@ data_access_common: ld r3,PACA_EXGEN+EX_DAR(r13) lwz r4,PACA_EXGEN+EX_DSISR(r13) li r5,0x300 - b .do_hash_page /* Try to handle as hpte fault */ + b do_hash_page /* Try to handle as hpte fault */ .align 7 .globl h_data_storage_common @@ -1056,11 +1056,11 @@ h_data_storage_common: mfspr r10,SPRN_HDSISR stw r10,PACA_EXGEN+EX_DSISR(r13) EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN) - bl .save_nvgprs + bl save_nvgprs DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD - bl .unknown_exception - b .ret_from_except + bl unknown_exception + b ret_from_except .align 7 .globl instruction_access_common @@ -1071,9 +1071,9 @@ instruction_access_common: ld r3,_NIP(r1) andis. r4,r12,0x5820 li r5,0x400 - b .do_hash_page /* Try to handle as hpte fault */ + b do_hash_page /* Try to handle as hpte fault */ - STD_EXCEPTION_COMMON(0xe20, h_instr_storage, .unknown_exception) + STD_EXCEPTION_COMMON(0xe20, h_instr_storage, unknown_exception) /* * Here is the common SLB miss user that is used when going to virtual @@ -1088,7 +1088,7 @@ slb_miss_user_common: stw r9,PACA_EXGEN+EX_CCR(r13) std r10,PACA_EXGEN+EX_LR(r13) std r11,PACA_EXGEN+EX_SRR0(r13) - bl .slb_allocate_user + bl slb_allocate_user ld r10,PACA_EXGEN+EX_LR(r13) ld r3,PACA_EXGEN+EX_R3(r13) @@ -1131,9 +1131,9 @@ slb_miss_fault: unrecov_user_slb: EXCEPTION_PROLOG_COMMON(0x4200, PACA_EXGEN) DISABLE_INTS - bl .save_nvgprs + bl save_nvgprs 1: addi r3,r1,STACK_FRAME_OVERHEAD - bl .unrecoverable_exception + bl unrecoverable_exception b 1b #endif /* __DISABLED__ */ @@ -1158,10 +1158,10 @@ machine_check_common: lwz r4,PACA_EXGEN+EX_DSISR(r13) std r3,_DAR(r1) std r4,_DSISR(r1) - bl .save_nvgprs + bl save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD - bl .machine_check_exception - b .ret_from_except + bl machine_check_exception + b ret_from_except .align 7 .globl alignment_common @@ -1175,31 +1175,31 @@ alignment_common: lwz r4,PACA_EXGEN+EX_DSISR(r13) std r3,_DAR(r1) std r4,_DSISR(r1) - bl .save_nvgprs + bl save_nvgprs DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD - bl .alignment_exception - b .ret_from_except + bl alignment_exception + b ret_from_except .align 7 .globl program_check_common program_check_common: EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN) - bl .save_nvgprs + bl save_nvgprs DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD - bl .program_check_exception - b .ret_from_except + bl program_check_exception + b ret_from_except .align 7 .globl fp_unavailable_common fp_unavailable_common: EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) bne 1f /* if from user, just load it up */ - bl .save_nvgprs + bl save_nvgprs DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD - bl .kernel_fp_unavailable_exception + bl kernel_fp_unavailable_exception BUG_OPCODE 1: #ifdef CONFIG_PPC_TRANSACTIONAL_MEM @@ -1211,15 +1211,15 @@ BEGIN_FTR_SECTION bne- 2f END_FTR_SECTION_IFSET(CPU_FTR_TM) #endif - bl .load_up_fpu + bl load_up_fpu b fast_exception_return #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 2: /* User process was in a transaction */ - bl .save_nvgprs + bl save_nvgprs DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD - bl .fp_unavailable_tm - b .ret_from_except + bl fp_unavailable_tm + b ret_from_except #endif .align 7 .globl altivec_unavailable_common @@ -1237,24 +1237,24 @@ BEGIN_FTR_SECTION bne- 2f END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69) #endif - bl .load_up_altivec + bl load_up_altivec b fast_exception_return #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 2: /* User process was in a transaction */ - bl .save_nvgprs + bl save_nvgprs DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD - bl .altivec_unavailable_tm - b .ret_from_except + bl altivec_unavailable_tm + b ret_from_except #endif 1: END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif - bl .save_nvgprs + bl save_nvgprs DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD - bl .altivec_unavailable_exception - b .ret_from_except + bl altivec_unavailable_exception + b ret_from_except .align 7 .globl vsx_unavailable_common @@ -1272,26 +1272,26 @@ BEGIN_FTR_SECTION bne- 2f END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69) #endif - b .load_up_vsx + b load_up_vsx #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 2: /* User process was in a transaction */ - bl .save_nvgprs + bl save_nvgprs DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD - bl .vsx_unavailable_tm - b .ret_from_except + bl vsx_unavailable_tm + b ret_from_except #endif 1: END_FTR_SECTION_IFSET(CPU_FTR_VSX) #endif - bl .save_nvgprs + bl save_nvgprs DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD - bl .vsx_unavailable_exception - b .ret_from_except + bl vsx_unavailable_exception + b ret_from_except - STD_EXCEPTION_COMMON(0xf60, facility_unavailable, .facility_unavailable_exception) - STD_EXCEPTION_COMMON(0xf80, hv_facility_unavailable, .facility_unavailable_exception) + STD_EXCEPTION_COMMON(0xf60, facility_unavailable, facility_unavailable_exception) + STD_EXCEPTION_COMMON(0xf80, hv_facility_unavailable, facility_unavailable_exception) .align 7 .globl __end_handlers @@ -1386,9 +1386,9 @@ _GLOBAL(opal_mc_secondary_handler) machine_check_handle_early: std r0,GPR0(r1) /* Save r0 */ EXCEPTION_PROLOG_COMMON_3(0x200) - bl .save_nvgprs + bl save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD - bl .machine_check_early + bl machine_check_early ld r12,_MSR(r1) #ifdef CONFIG_PPC_P7_NAP /* @@ -1408,11 +1408,11 @@ machine_check_handle_early: /* Supervisor state loss */ li r0,1 stb r0,PACA_NAPSTATELOST(r13) -3: bl .machine_check_queue_event +3: bl machine_check_queue_event MACHINE_CHECK_HANDLER_WINDUP GET_PACA(r13) ld r1,PACAR1(r13) - b .power7_enter_nap_mode + b power7_enter_nap_mode 4: #endif /* @@ -1444,7 +1444,7 @@ machine_check_handle_early: andi. r11,r12,MSR_RI bne 2f 1: addi r3,r1,STACK_FRAME_OVERHEAD - bl .unrecoverable_exception + bl unrecoverable_exception b 1b 2: /* @@ -1452,7 +1452,7 @@ machine_check_handle_early: * Queue up the MCE event so that we can log it later, while * returning from kernel or opal call. */ - bl .machine_check_queue_event + bl machine_check_queue_event MACHINE_CHECK_HANDLER_WINDUP rfid 9: @@ -1468,7 +1468,7 @@ machine_check_handle_early: * r3 is saved in paca->slb_r3 * We assume we aren't going to take any exceptions during this procedure. */ -_GLOBAL(slb_miss_realmode) +slb_miss_realmode: mflr r10 #ifdef CONFIG_RELOCATABLE mtctr r11 @@ -1477,7 +1477,7 @@ _GLOBAL(slb_miss_realmode) stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ - bl .slb_allocate_realmode + bl slb_allocate_realmode /* All done -- return from exception. */ @@ -1517,9 +1517,9 @@ _GLOBAL(slb_miss_realmode) unrecov_slb: EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB) DISABLE_INTS - bl .save_nvgprs + bl save_nvgprs 1: addi r3,r1,STACK_FRAME_OVERHEAD - bl .unrecoverable_exception + bl unrecoverable_exception b 1b @@ -1536,7 +1536,7 @@ power4_fixup_nap: * Hash table stuff */ .align 7 -_STATIC(do_hash_page) +do_hash_page: std r3,_DAR(r1) std r4,_DSISR(r1) @@ -1573,7 +1573,7 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB) * * at return r3 = 0 for success, 1 for page fault, negative for error */ - bl .hash_page /* build HPTE if possible */ + bl hash_page /* build HPTE if possible */ cmpdi r3,0 /* see if hash_page succeeded */ /* Success */ @@ -1587,35 +1587,35 @@ handle_page_fault: 11: ld r4,_DAR(r1) ld r5,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_page_fault + bl do_page_fault cmpdi r3,0 beq+ 12f - bl .save_nvgprs + bl save_nvgprs mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD lwz r4,_DAR(r1) - bl .bad_page_fault - b .ret_from_except + bl bad_page_fault + b ret_from_except /* We have a data breakpoint exception - handle it */ handle_dabr_fault: - bl .save_nvgprs + bl save_nvgprs ld r4,_DAR(r1) ld r5,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_break -12: b .ret_from_except_lite + bl do_break +12: b ret_from_except_lite /* We have a page fault that hash_page could handle but HV refused * the PTE insertion */ -13: bl .save_nvgprs +13: bl save_nvgprs mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD ld r4,_DAR(r1) - bl .low_hash_fault - b .ret_from_except + bl low_hash_fault + b ret_from_except /* * We come here as a result of a DSI at a point where we don't want @@ -1624,16 +1624,16 @@ handle_dabr_fault: * were soft-disabled. We want to invoke the exception handler for * the access, or panic if there isn't a handler. */ -77: bl .save_nvgprs +77: bl save_nvgprs mr r4,r3 addi r3,r1,STACK_FRAME_OVERHEAD li r5,SIGSEGV - bl .bad_page_fault - b .ret_from_except + bl bad_page_fault + b ret_from_except /* here we have a segment miss */ do_ste_alloc: - bl .ste_allocate /* try to insert stab entry */ + bl ste_allocate /* try to insert stab entry */ cmpdi r3,0 bne- handle_page_fault b fast_exception_return @@ -1646,7 +1646,7 @@ do_ste_alloc: * We assume (DAR >> 60) == 0xc. */ .align 7 -_GLOBAL(do_stab_bolted) +do_stab_bolted: stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ std r11,PACA_EXSLB+EX_SRR0(r13) /* save SRR0 in exc. frame */ mfspr r11,SPRN_DAR /* ea */ diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 2230fd0ca3e4fc..20bed22556fb48 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -55,9 +55,9 @@ int crash_mem_ranges; int __init early_init_dt_scan_fw_dump(unsigned long node, const char *uname, int depth, void *data) { - __be32 *sections; + const __be32 *sections; int i, num_sections; - unsigned long size; + int size; const int *token; if (depth != 1 || strcmp(uname, "rtas") != 0) @@ -69,7 +69,7 @@ int __init early_init_dt_scan_fw_dump(unsigned long node, */ token = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL); if (!token) - return 0; + return 1; fw_dump.fadump_supported = 1; fw_dump.ibm_configure_kernel_dump = *token; @@ -92,7 +92,7 @@ int __init early_init_dt_scan_fw_dump(unsigned long node, &size); if (!sections) - return 0; + return 1; num_sections = size / (3 * sizeof(u32)); @@ -110,6 +110,7 @@ int __init early_init_dt_scan_fw_dump(unsigned long node, break; } } + return 1; } diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c index 6a014c763cc71d..f202d0731b0654 100644 --- a/arch/powerpc/kernel/ftrace.c +++ b/arch/powerpc/kernel/ftrace.c @@ -105,11 +105,9 @@ __ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { unsigned int op; - unsigned int jmp[5]; unsigned long ptr; unsigned long ip = rec->ip; - unsigned long tramp; - int offset; + void *tramp; /* read where this goes */ if (probe_kernel_read(&op, (void *)ip, sizeof(int))) @@ -122,96 +120,41 @@ __ftrace_make_nop(struct module *mod, } /* lets find where the pointer goes */ - tramp = find_bl_target(ip, op); - - /* - * On PPC64 the trampoline looks like: - * 0x3d, 0x82, 0x00, 0x00, addis r12,r2, - * 0x39, 0x8c, 0x00, 0x00, addi r12,r12, - * Where the bytes 2,3,6 and 7 make up the 32bit offset - * to the TOC that holds the pointer. - * to jump to. - * 0xf8, 0x41, 0x00, 0x28, std r2,40(r1) - * 0xe9, 0x6c, 0x00, 0x20, ld r11,32(r12) - * The actually address is 32 bytes from the offset - * into the TOC. - * 0xe8, 0x4c, 0x00, 0x28, ld r2,40(r12) - */ - - pr_devel("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc); - - /* Find where the trampoline jumps to */ - if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) { - printk(KERN_ERR "Failed to read %lx\n", tramp); - return -EFAULT; - } + tramp = (void *)find_bl_target(ip, op); - pr_devel(" %08x %08x", jmp[0], jmp[1]); + pr_devel("ip:%lx jumps to %p", ip, tramp); - /* verify that this is what we expect it to be */ - if (((jmp[0] & 0xffff0000) != 0x3d820000) || - ((jmp[1] & 0xffff0000) != 0x398c0000) || - (jmp[2] != 0xf8410028) || - (jmp[3] != 0xe96c0020) || - (jmp[4] != 0xe84c0028)) { + if (!is_module_trampoline(tramp)) { printk(KERN_ERR "Not a trampoline\n"); return -EINVAL; } - /* The bottom half is signed extended */ - offset = ((unsigned)((unsigned short)jmp[0]) << 16) + - (int)((short)jmp[1]); - - pr_devel(" %x ", offset); - - /* get the address this jumps too */ - tramp = mod->arch.toc + offset + 32; - pr_devel("toc: %lx", tramp); - - if (probe_kernel_read(jmp, (void *)tramp, 8)) { - printk(KERN_ERR "Failed to read %lx\n", tramp); + if (module_trampoline_target(mod, tramp, &ptr)) { + printk(KERN_ERR "Failed to get trampoline target\n"); return -EFAULT; } - pr_devel(" %08x %08x\n", jmp[0], jmp[1]); - -#ifdef __LITTLE_ENDIAN__ - ptr = ((unsigned long)jmp[1] << 32) + jmp[0]; -#else - ptr = ((unsigned long)jmp[0] << 32) + jmp[1]; -#endif + pr_devel("trampoline target %lx", ptr); /* This should match what was called */ if (ptr != ppc_function_entry((void *)addr)) { - printk(KERN_ERR "addr does not match %lx\n", ptr); + printk(KERN_ERR "addr %lx does not match expected %lx\n", + ptr, ppc_function_entry((void *)addr)); return -EINVAL; } /* - * We want to nop the line, but the next line is - * 0xe8, 0x41, 0x00, 0x28 ld r2,40(r1) - * This needs to be turned to a nop too. - */ - if (probe_kernel_read(&op, (void *)(ip+4), MCOUNT_INSN_SIZE)) - return -EFAULT; - - if (op != 0xe8410028) { - printk(KERN_ERR "Next line is not ld! (%08x)\n", op); - return -EINVAL; - } - - /* - * Milton Miller pointed out that we can not blindly do nops. - * If a task was preempted when calling a trace function, - * the nops will remove the way to restore the TOC in r2 - * and the r2 TOC will get corrupted. - */ - - /* - * Replace: - * bl <==== will be replaced with "b 1f" - * ld r2,40(r1) - * 1: + * Our original call site looks like: + * + * bl + * ld r2,XX(r1) + * + * Milton Miller pointed out that we can not simply nop the branch. + * If a task was preempted when calling a trace function, the nops + * will remove the way to restore the TOC in r2 and the r2 TOC will + * get corrupted. + * + * Use a b +8 to jump over the load. */ op = 0x48000008; /* b +8 */ @@ -349,19 +292,24 @@ static int __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { unsigned int op[2]; - unsigned long ip = rec->ip; + void *ip = (void *)rec->ip; /* read where this goes */ - if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2)) + if (probe_kernel_read(op, ip, sizeof(op))) return -EFAULT; /* - * It should be pointing to two nops or - * b +8; ld r2,40(r1) + * We expect to see: + * + * b +8 + * ld r2,XX(r1) + * + * The load offset is different depending on the ABI. For simplicity + * just mask it out when doing the compare. */ - if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) && - ((op[0] != PPC_INST_NOP) || (op[1] != PPC_INST_NOP))) { - printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]); + if ((op[0] != 0x48000008) || ((op[1] & 0xffff00000) != 0xe8410000)) { + printk(KERN_ERR "Unexpected call sequence: %x %x\n", + op[0], op[1]); return -EINVAL; } @@ -371,23 +319,16 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) return -EINVAL; } - /* create the branch to the trampoline */ - op[0] = create_branch((unsigned int *)ip, - rec->arch.mod->arch.tramp, BRANCH_SET_LINK); - if (!op[0]) { - printk(KERN_ERR "REL24 out of range!\n"); + /* Ensure branch is within 24 bits */ + if (create_branch(ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK)) { + printk(KERN_ERR "Branch out of range"); return -EINVAL; } - /* ld r2,40(r1) */ - op[1] = 0xe8410028; - - pr_devel("write to %lx\n", rec->ip); - - if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2)) - return -EPERM; - - flush_icache_range(ip, ip + 8); + if (patch_branch(ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK)) { + printk(KERN_ERR "REL24 out of range!\n"); + return -EINVAL; + } return 0; } diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index b7363bd4245284..a95145d7f61bff 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -70,16 +70,15 @@ _GLOBAL(__start) /* NOP this out unconditionally */ BEGIN_FTR_SECTION FIXUP_ENDIAN - b .__start_initialization_multiplatform + b __start_initialization_multiplatform END_FTR_SECTION(0, 1) /* Catch branch to 0 in real mode */ trap - /* Secondary processors spin on this value until it becomes nonzero. - * When it does it contains the real address of the descriptor - * of the function that the cpu should jump to to continue - * initialization. + /* Secondary processors spin on this value until it becomes non-zero. + * When non-zero, it contains the real address of the function the cpu + * should jump to. */ .balign 8 .globl __secondary_hold_spinloop @@ -140,16 +139,15 @@ __secondary_hold: tovirt(r26,r26) #endif /* All secondary cpus wait here until told to start. */ -100: ld r4,__secondary_hold_spinloop-_stext(r26) - cmpdi 0,r4,0 +100: ld r12,__secondary_hold_spinloop-_stext(r26) + cmpdi 0,r12,0 beq 100b #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC) #ifdef CONFIG_PPC_BOOK3E - tovirt(r4,r4) + tovirt(r12,r12) #endif - ld r4,0(r4) /* deref function descriptor */ - mtctr r4 + mtctr r12 mr r3,r24 /* * it may be the case that other platforms have r4 right to @@ -186,16 +184,16 @@ _GLOBAL(generic_secondary_thread_init) mr r24,r3 /* turn on 64-bit mode */ - bl .enable_64b_mode + bl enable_64b_mode /* get a valid TOC pointer, wherever we're mapped at */ - bl .relative_toc + bl relative_toc tovirt(r2,r2) #ifdef CONFIG_PPC_BOOK3E /* Book3E initialization */ mr r3,r24 - bl .book3e_secondary_thread_init + bl book3e_secondary_thread_init #endif b generic_secondary_common_init @@ -214,17 +212,17 @@ _GLOBAL(generic_secondary_smp_init) mr r25,r4 /* turn on 64-bit mode */ - bl .enable_64b_mode + bl enable_64b_mode /* get a valid TOC pointer, wherever we're mapped at */ - bl .relative_toc + bl relative_toc tovirt(r2,r2) #ifdef CONFIG_PPC_BOOK3E /* Book3E initialization */ mr r3,r24 mr r4,r25 - bl .book3e_secondary_core_init + bl book3e_secondary_core_init #endif generic_secondary_common_init: @@ -236,7 +234,7 @@ generic_secondary_common_init: ld r13,0(r13) /* Get base vaddr of paca array */ #ifndef CONFIG_SMP addi r13,r13,PACA_SIZE /* know r13 if used accidentally */ - b .kexec_wait /* wait for next kernel if !SMP */ + b kexec_wait /* wait for next kernel if !SMP */ #else LOAD_REG_ADDR(r7, nr_cpu_ids) /* Load nr_cpu_ids address */ lwz r7,0(r7) /* also the max paca allocated */ @@ -250,7 +248,7 @@ generic_secondary_common_init: blt 1b mr r3,r24 /* not found, copy phys to r3 */ - b .kexec_wait /* next kernel might do better */ + b kexec_wait /* next kernel might do better */ 2: SET_PACA(r13) #ifdef CONFIG_PPC_BOOK3E @@ -264,11 +262,13 @@ generic_secondary_common_init: /* See if we need to call a cpu state restore handler */ LOAD_REG_ADDR(r23, cur_cpu_spec) ld r23,0(r23) - ld r23,CPU_SPEC_RESTORE(r23) - cmpdi 0,r23,0 + ld r12,CPU_SPEC_RESTORE(r23) + cmpdi 0,r12,0 beq 3f - ld r23,0(r23) - mtctr r23 +#if !defined(_CALL_ELF) || _CALL_ELF != 2 + ld r12,0(r12) +#endif + mtctr r12 bctrl 3: LOAD_REG_ADDR(r3, spinning_secondaries) /* Decrement spinning_secondaries */ @@ -299,7 +299,7 @@ generic_secondary_common_init: * Assumes we're mapped EA == RA if the MMU is on. */ #ifdef CONFIG_PPC_BOOK3S -_STATIC(__mmu_off) +__mmu_off: mfmsr r3 andi. r0,r3,MSR_IR|MSR_DR beqlr @@ -324,12 +324,12 @@ _STATIC(__mmu_off) * DT block, r4 is a physical pointer to the kernel itself * */ -_GLOBAL(__start_initialization_multiplatform) +__start_initialization_multiplatform: /* Make sure we are running in 64 bits mode */ - bl .enable_64b_mode + bl enable_64b_mode /* Get TOC pointer (current runtime address) */ - bl .relative_toc + bl relative_toc /* find out where we are now */ bcl 20,31,$+4 @@ -342,7 +342,7 @@ _GLOBAL(__start_initialization_multiplatform) */ cmpldi cr0,r5,0 beq 1f - b .__boot_from_prom /* yes -> prom */ + b __boot_from_prom /* yes -> prom */ 1: /* Save parameters */ mr r31,r3 @@ -354,8 +354,8 @@ _GLOBAL(__start_initialization_multiplatform) #endif #ifdef CONFIG_PPC_BOOK3E - bl .start_initialization_book3e - b .__after_prom_start + bl start_initialization_book3e + b __after_prom_start #else /* Setup some critical 970 SPRs before switching MMU off */ mfspr r0,SPRN_PVR @@ -368,15 +368,15 @@ _GLOBAL(__start_initialization_multiplatform) beq 1f cmpwi r0,0x45 /* 970GX */ bne 2f -1: bl .__cpu_preinit_ppc970 +1: bl __cpu_preinit_ppc970 2: /* Switch off MMU if not already off */ - bl .__mmu_off - b .__after_prom_start + bl __mmu_off + b __after_prom_start #endif /* CONFIG_PPC_BOOK3E */ -_INIT_STATIC(__boot_from_prom) +__boot_from_prom: #ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE /* Save parameters */ mr r31,r3 @@ -395,7 +395,7 @@ _INIT_STATIC(__boot_from_prom) #ifdef CONFIG_RELOCATABLE /* Relocate code for where we are now */ mr r3,r26 - bl .relocate + bl relocate #endif /* Restore parameters */ @@ -407,14 +407,14 @@ _INIT_STATIC(__boot_from_prom) /* Do all of the interaction with OF client interface */ mr r8,r26 - bl .prom_init + bl prom_init #endif /* #CONFIG_PPC_OF_BOOT_TRAMPOLINE */ /* We never return. We also hit that trap if trying to boot * from OF while CONFIG_PPC_OF_BOOT_TRAMPOLINE isn't selected */ trap -_STATIC(__after_prom_start) +__after_prom_start: #ifdef CONFIG_RELOCATABLE /* process relocations for the final address of the kernel */ lis r25,PAGE_OFFSET@highest /* compute virtual base of kernel */ @@ -424,7 +424,7 @@ _STATIC(__after_prom_start) bne 1f add r25,r25,r26 1: mr r3,r25 - bl .relocate + bl relocate #endif /* @@ -464,12 +464,12 @@ _STATIC(__after_prom_start) lis r5,(copy_to_here - _stext)@ha addi r5,r5,(copy_to_here - _stext)@l /* # bytes of memory to copy */ - bl .copy_and_flush /* copy the first n bytes */ + bl copy_and_flush /* copy the first n bytes */ /* this includes the code being */ /* executed here. */ addis r8,r3,(4f - _stext)@ha /* Jump to the copy of this code */ - addi r8,r8,(4f - _stext)@l /* that we just made */ - mtctr r8 + addi r12,r8,(4f - _stext)@l /* that we just made */ + mtctr r12 bctr .balign 8 @@ -478,9 +478,9 @@ p_end: .llong _end - _stext 4: /* Now copy the rest of the kernel up to _end */ addis r5,r26,(p_end - _stext)@ha ld r5,(p_end - _stext)@l(r5) /* get _end */ -5: bl .copy_and_flush /* copy the rest */ +5: bl copy_and_flush /* copy the rest */ -9: b .start_here_multiplatform +9: b start_here_multiplatform /* * Copy routine used to copy the kernel to start at physical address 0 @@ -544,7 +544,7 @@ __secondary_start_pmac_0: _GLOBAL(pmac_secondary_start) /* turn on 64-bit mode */ - bl .enable_64b_mode + bl enable_64b_mode li r0,0 mfspr r3,SPRN_HID4 @@ -556,11 +556,11 @@ _GLOBAL(pmac_secondary_start) slbia /* get TOC pointer (real address) */ - bl .relative_toc + bl relative_toc tovirt(r2,r2) /* Copy some CPU settings from CPU 0 */ - bl .__restore_cpu_ppc970 + bl __restore_cpu_ppc970 /* pSeries do that early though I don't think we really need it */ mfmsr r3 @@ -619,7 +619,7 @@ __secondary_start: std r14,PACAKSAVE(r13) /* Do early setup for that CPU (stab, slb, hash table pointer) */ - bl .early_setup_secondary + bl early_setup_secondary /* * setup the new stack pointer, but *don't* use this until @@ -639,7 +639,7 @@ __secondary_start: stb r0,PACAIRQHAPPENED(r13) /* enable MMU and jump to start_secondary */ - LOAD_REG_ADDR(r3, .start_secondary_prolog) + LOAD_REG_ADDR(r3, start_secondary_prolog) LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) mtspr SPRN_SRR0,r3 @@ -652,11 +652,11 @@ __secondary_start: * zero the stack back-chain pointer and get the TOC virtual address * before going into C code. */ -_GLOBAL(start_secondary_prolog) +start_secondary_prolog: ld r2,PACATOC(r13) li r3,0 std r3,0(r1) /* Zero the stack frame pointer */ - bl .start_secondary + bl start_secondary b . /* * Reset stack pointer and call start_secondary @@ -667,14 +667,14 @@ _GLOBAL(start_secondary_resume) ld r1,PACAKSAVE(r13) /* Reload kernel stack pointer */ li r3,0 std r3,0(r1) /* Zero the stack frame pointer */ - bl .start_secondary + bl start_secondary b . #endif /* * This subroutine clobbers r11 and r12 */ -_GLOBAL(enable_64b_mode) +enable_64b_mode: mfmsr r11 /* grab the current MSR */ #ifdef CONFIG_PPC_BOOK3E oris r11,r11,0x8000 /* CM bit set, we'll set ICM later */ @@ -715,9 +715,9 @@ p_toc: .llong __toc_start + 0x8000 - 0b /* * This is where the main kernel code starts. */ -_INIT_STATIC(start_here_multiplatform) +start_here_multiplatform: /* set up the TOC */ - bl .relative_toc + bl relative_toc tovirt(r2,r2) /* Clear out the BSS. It may have been done in prom_init, @@ -776,9 +776,9 @@ _INIT_STATIC(start_here_multiplatform) /* Restore parameters passed from prom_init/kexec */ mr r3,r31 - bl .early_setup /* also sets r13 and SPRG_PACA */ + bl early_setup /* also sets r13 and SPRG_PACA */ - LOAD_REG_ADDR(r3, .start_here_common) + LOAD_REG_ADDR(r3, start_here_common) ld r4,PACAKMSR(r13) mtspr SPRN_SRR0,r3 mtspr SPRN_SRR1,r4 @@ -786,7 +786,8 @@ _INIT_STATIC(start_here_multiplatform) b . /* prevent speculative execution */ /* This is where all platforms converge execution */ -_INIT_GLOBAL(start_here_common) + +start_here_common: /* relocation is on at this point */ std r1,PACAKSAVE(r13) @@ -794,7 +795,7 @@ _INIT_GLOBAL(start_here_common) ld r2,PACATOC(r13) /* Do more system initializations in virtual mode */ - bl .setup_system + bl setup_system /* Mark interrupts soft and hard disabled (they might be enabled * in the PACA when doing hotplug) @@ -805,7 +806,7 @@ _INIT_GLOBAL(start_here_common) stb r0,PACAIRQHAPPENED(r13) /* Generic kernel entry */ - bl .start_kernel + bl start_kernel /* Not reached */ BUG_OPCODE diff --git a/arch/powerpc/kernel/idle_book3e.S b/arch/powerpc/kernel/idle_book3e.S index bfb73cc209ceb3..48c21acef91588 100644 --- a/arch/powerpc/kernel/idle_book3e.S +++ b/arch/powerpc/kernel/idle_book3e.S @@ -43,7 +43,7 @@ _GLOBAL(\name) */ #ifdef CONFIG_TRACE_IRQFLAGS stdu r1,-128(r1) - bl .trace_hardirqs_on + bl trace_hardirqs_on addi r1,r1,128 #endif li r0,1 diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S index e3edaa189911b8..f57a19348bddb4 100644 --- a/arch/powerpc/kernel/idle_power4.S +++ b/arch/powerpc/kernel/idle_power4.S @@ -46,7 +46,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) mflr r0 std r0,16(r1) stdu r1,-128(r1) - bl .trace_hardirqs_on + bl trace_hardirqs_on addi r1,r1,128 ld r0,16(r1) mtlr r0 diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S index c3ab86975614a4..dca6e16c2436d7 100644 --- a/arch/powerpc/kernel/idle_power7.S +++ b/arch/powerpc/kernel/idle_power7.S @@ -58,7 +58,7 @@ _GLOBAL(power7_powersave_common) /* Make sure FPU, VSX etc... are flushed as we may lose * state when going to nap mode */ - bl .discard_lazy_cpu_state + bl discard_lazy_cpu_state #endif /* CONFIG_SMP */ /* Hard disable interrupts */ @@ -168,7 +168,7 @@ _GLOBAL(power7_wakeup_loss) _GLOBAL(power7_wakeup_noloss) lbz r0,PACA_NAPSTATELOST(r13) cmpwi r0,0 - bne .power7_wakeup_loss + bne power7_wakeup_loss ld r1,PACAR1(r13) ld r4,_MSR(r1) ld r5,_NIP(r1) diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 40bd7bd4e19a88..85fb16e64cef3e 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -71,8 +71,9 @@ static int __init add_legacy_port(struct device_node *np, int want_index, phys_addr_t taddr, unsigned long irq, upf_t flags, int irq_check_parent) { - const __be32 *clk, *spd; + const __be32 *clk, *spd, *rs; u32 clock = BASE_BAUD * 16; + u32 shift = 0; int index; /* get clock freq. if present */ @@ -83,6 +84,11 @@ static int __init add_legacy_port(struct device_node *np, int want_index, /* get default speed if present */ spd = of_get_property(np, "current-speed", NULL); + /* get register shift if present */ + rs = of_get_property(np, "reg-shift", NULL); + if (rs && *rs) + shift = be32_to_cpup(rs); + /* If we have a location index, then try to use it */ if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS) index = want_index; @@ -126,6 +132,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index, legacy_serial_ports[index].uartclk = clock; legacy_serial_ports[index].irq = irq; legacy_serial_ports[index].flags = flags; + legacy_serial_ports[index].regshift = shift; legacy_serial_infos[index].taddr = taddr; legacy_serial_infos[index].np = of_node_get(np); legacy_serial_infos[index].clock = clock; @@ -163,9 +170,8 @@ static int __init add_legacy_soc_port(struct device_node *np, if (of_get_property(np, "clock-frequency", NULL) == NULL) return -1; - /* if reg-shift or offset, don't try to use it */ - if ((of_get_property(np, "reg-shift", NULL) != NULL) || - (of_get_property(np, "reg-offset", NULL) != NULL)) + /* if reg-offset don't try to use it */ + if ((of_get_property(np, "reg-offset", NULL) != NULL)) return -1; /* if rtas uses this device, don't try to use it as well */ @@ -315,17 +321,20 @@ static void __init setup_legacy_serial_console(int console) struct legacy_serial_info *info = &legacy_serial_infos[console]; struct plat_serial8250_port *port = &legacy_serial_ports[console]; void __iomem *addr; + unsigned int stride; + + stride = 1 << port->regshift; /* Check if a translated MMIO address has been found */ if (info->taddr) { addr = ioremap(info->taddr, 0x1000); if (addr == NULL) return; - udbg_uart_init_mmio(addr, 1); + udbg_uart_init_mmio(addr, stride); } else { /* Check if it's PIO and we support untranslated PIO */ if (port->iotype == UPIO_PORT && isa_io_special) - udbg_uart_init_pio(port->iobase, 1); + udbg_uart_init_pio(port->iobase, stride); else return; } diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 3d0249599d524a..4e314b90c75d69 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -34,7 +34,7 @@ _GLOBAL(call_do_softirq) std r0,16(r1) stdu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3) mr r1,r3 - bl .__do_softirq + bl __do_softirq ld r1,0(r1) ld r0,16(r1) mtlr r0 @@ -45,7 +45,7 @@ _GLOBAL(call_do_irq) std r0,16(r1) stdu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4) mr r1,r4 - bl .__do_irq + bl __do_irq ld r1,0(r1) ld r0,16(r1) mtlr r0 @@ -506,7 +506,7 @@ _GLOBAL(kexec_smp_wait) stb r4,PACAKEXECSTATE(r13) SYNC - b .kexec_wait + b kexec_wait /* * switch to real mode (turn mmu off) @@ -576,7 +576,7 @@ _GLOBAL(kexec_sequence) /* copy dest pages, flush whole dest image */ mr r3,r29 - bl .kexec_copy_flush /* (image) */ + bl kexec_copy_flush /* (image) */ /* turn off mmu */ bl real_mode @@ -586,7 +586,7 @@ _GLOBAL(kexec_sequence) mr r4,r30 /* start, aka phys mem offset */ li r5,0x100 li r6,0 - bl .copy_and_flush /* (dest, src, copy limit, start offset) */ + bl copy_and_flush /* (dest, src, copy limit, start offset) */ 1: /* assume normal blr return */ /* release other cpus to the new kernel secondary start at 0x60 */ @@ -595,8 +595,12 @@ _GLOBAL(kexec_sequence) stw r6,kexec_flag-1b(5) /* clear out hardware hash page table and tlb */ - ld r5,0(r27) /* deref function descriptor */ - mtctr r5 +#if !defined(_CALL_ELF) || _CALL_ELF != 2 + ld r12,0(r27) /* deref function descriptor */ +#else + mr r12,r27 +#endif + mtctr r12 bctrl /* ppc_md.hpte_clear_all(void); */ /* @@ -630,3 +634,31 @@ _GLOBAL(kexec_sequence) li r5,0 blr /* image->start(physid, image->start, 0); */ #endif /* CONFIG_KEXEC */ + +#ifdef CONFIG_MODULES +#if defined(_CALL_ELF) && _CALL_ELF == 2 + +#ifdef CONFIG_MODVERSIONS +.weak __crc_TOC. +.section "___kcrctab+TOC.","a" +.globl __kcrctab_TOC. +__kcrctab_TOC.: + .llong __crc_TOC. +#endif + +/* + * Export a fake .TOC. since both modpost and depmod will complain otherwise. + * Both modpost and depmod strip the leading . so we do the same here. + */ +.section "__ksymtab_strings","a" +__kstrtab_TOC.: + .asciz "TOC." + +.section "___ksymtab+TOC.","a" +/* This symbol name is important: it's used by modpost to find exported syms */ +.globl __ksymtab_TOC. +__ksymtab_TOC.: + .llong 0 /* .value */ + .llong __kstrtab_TOC. +#endif /* ELFv2 */ +#endif /* MODULES */ diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 12664c130d73dd..ef349d07712971 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -41,46 +42,170 @@ #define DEBUGP(fmt , ...) #endif +#if defined(_CALL_ELF) && _CALL_ELF == 2 +#define R2_STACK_OFFSET 24 + +/* An address is simply the address of the function. */ +typedef unsigned long func_desc_t; + +static func_desc_t func_desc(unsigned long addr) +{ + return addr; +} +static unsigned long func_addr(unsigned long addr) +{ + return addr; +} +static unsigned long stub_func_addr(func_desc_t func) +{ + return func; +} + +/* PowerPC64 specific values for the Elf64_Sym st_other field. */ +#define STO_PPC64_LOCAL_BIT 5 +#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT) +#define PPC64_LOCAL_ENTRY_OFFSET(other) \ + (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2) + +static unsigned int local_entry_offset(const Elf64_Sym *sym) +{ + /* sym->st_other indicates offset to local entry point + * (otherwise it will assume r12 is the address of the start + * of function and try to derive r2 from it). */ + return PPC64_LOCAL_ENTRY_OFFSET(sym->st_other); +} +#else +#define R2_STACK_OFFSET 40 + +/* An address is address of the OPD entry, which contains address of fn. */ +typedef struct ppc64_opd_entry func_desc_t; + +static func_desc_t func_desc(unsigned long addr) +{ + return *(struct ppc64_opd_entry *)addr; +} +static unsigned long func_addr(unsigned long addr) +{ + return func_desc(addr).funcaddr; +} +static unsigned long stub_func_addr(func_desc_t func) +{ + return func.funcaddr; +} +static unsigned int local_entry_offset(const Elf64_Sym *sym) +{ + return 0; +} +#endif + /* Like PPC32, we need little trampolines to do > 24-bit jumps (into the kernel itself). But on PPC64, these need to be used for every jump, actually, to reset r2 (TOC+0x8000). */ struct ppc64_stub_entry { - /* 28 byte jump instruction sequence (7 instructions) */ - unsigned char jump[28]; - unsigned char unused[4]; + /* 28 byte jump instruction sequence (7 instructions). We only + * need 6 instructions on ABIv2 but we always allocate 7 so + * so we don't have to modify the trampoline load instruction. */ + u32 jump[7]; + u32 unused; /* Data for the above code */ - struct ppc64_opd_entry opd; + func_desc_t funcdata; }; -/* We use a stub to fix up r2 (TOC ptr) and to jump to the (external) - function which may be more than 24-bits away. We could simply - patch the new r2 value and function pointer into the stub, but it's - significantly shorter to put these values at the end of the stub - code, and patch the stub address (32-bits relative to the TOC ptr, - r2) into the stub. */ -static struct ppc64_stub_entry ppc64_stub = -{ .jump = { -#ifdef __LITTLE_ENDIAN__ - 0x00, 0x00, 0x82, 0x3d, /* addis r12,r2, */ - 0x00, 0x00, 0x8c, 0x39, /* addi r12,r12, */ - /* Save current r2 value in magic place on the stack. */ - 0x28, 0x00, 0x41, 0xf8, /* std r2,40(r1) */ - 0x20, 0x00, 0x6c, 0xe9, /* ld r11,32(r12) */ - 0x28, 0x00, 0x4c, 0xe8, /* ld r2,40(r12) */ - 0xa6, 0x03, 0x69, 0x7d, /* mtctr r11 */ - 0x20, 0x04, 0x80, 0x4e /* bctr */ -#else - 0x3d, 0x82, 0x00, 0x00, /* addis r12,r2, */ - 0x39, 0x8c, 0x00, 0x00, /* addi r12,r12, */ +/* + * PPC64 uses 24 bit jumps, but we need to jump into other modules or + * the kernel which may be further. So we jump to a stub. + * + * For ELFv1 we need to use this to set up the new r2 value (aka TOC + * pointer). For ELFv2 it's the callee's responsibility to set up the + * new r2, but for both we need to save the old r2. + * + * We could simply patch the new r2 value and function pointer into + * the stub, but it's significantly shorter to put these values at the + * end of the stub code, and patch the stub address (32-bits relative + * to the TOC ptr, r2) into the stub. + */ + +static u32 ppc64_stub_insns[] = { + 0x3d620000, /* addis r11,r2, */ + 0x396b0000, /* addi r11,r11, */ /* Save current r2 value in magic place on the stack. */ - 0xf8, 0x41, 0x00, 0x28, /* std r2,40(r1) */ - 0xe9, 0x6c, 0x00, 0x20, /* ld r11,32(r12) */ - 0xe8, 0x4c, 0x00, 0x28, /* ld r2,40(r12) */ - 0x7d, 0x69, 0x03, 0xa6, /* mtctr r11 */ - 0x4e, 0x80, 0x04, 0x20 /* bctr */ + 0xf8410000|R2_STACK_OFFSET, /* std r2,R2_STACK_OFFSET(r1) */ + 0xe98b0020, /* ld r12,32(r11) */ +#if !defined(_CALL_ELF) || _CALL_ELF != 2 + /* Set up new r2 from function descriptor */ + 0xe84b0026, /* ld r2,40(r11) */ +#endif + 0x7d8903a6, /* mtctr r12 */ + 0x4e800420 /* bctr */ +}; + +#ifdef CONFIG_DYNAMIC_FTRACE + +static u32 ppc64_stub_mask[] = { + 0xffff0000, + 0xffff0000, + 0xffffffff, + 0xffffffff, +#if !defined(_CALL_ELF) || _CALL_ELF != 2 + 0xffffffff, +#endif + 0xffffffff, + 0xffffffff +}; + +bool is_module_trampoline(u32 *p) +{ + unsigned int i; + u32 insns[ARRAY_SIZE(ppc64_stub_insns)]; + + BUILD_BUG_ON(sizeof(ppc64_stub_insns) != sizeof(ppc64_stub_mask)); + + if (probe_kernel_read(insns, p, sizeof(insns))) + return -EFAULT; + + for (i = 0; i < ARRAY_SIZE(ppc64_stub_insns); i++) { + u32 insna = insns[i]; + u32 insnb = ppc64_stub_insns[i]; + u32 mask = ppc64_stub_mask[i]; + + if ((insna & mask) != (insnb & mask)) + return false; + } + + return true; +} + +int module_trampoline_target(struct module *mod, u32 *trampoline, + unsigned long *target) +{ + u32 buf[2]; + u16 upper, lower; + long offset; + void *toc_entry; + + if (probe_kernel_read(buf, trampoline, sizeof(buf))) + return -EFAULT; + + upper = buf[0] & 0xffff; + lower = buf[1] & 0xffff; + + /* perform the addis/addi, both signed */ + offset = ((short)upper << 16) + (short)lower; + + /* + * Now get the address this trampoline jumps to. This + * is always 32 bytes into our trampoline stub. + */ + toc_entry = (void *)mod->arch.toc + offset + 32; + + if (probe_kernel_read(target, toc_entry, sizeof(*target))) + return -EFAULT; + + return 0; +} + #endif -} }; /* Count how many different 24-bit relocations (different symbol, different addend) */ @@ -183,6 +308,7 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr, return relocs * sizeof(struct ppc64_stub_entry); } +/* Still needed for ELFv2, for .TOC. */ static void dedotify_versions(struct modversion_info *vers, unsigned long size) { @@ -193,7 +319,7 @@ static void dedotify_versions(struct modversion_info *vers, memmove(vers->name, vers->name+1, strlen(vers->name)); } -/* Undefined symbols which refer to .funcname, hack to funcname */ +/* Undefined symbols which refer to .funcname, hack to funcname (or .TOC.) */ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab) { unsigned int i; @@ -207,6 +333,24 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab) } } +static Elf64_Sym *find_dot_toc(Elf64_Shdr *sechdrs, + const char *strtab, + unsigned int symindex) +{ + unsigned int i, numsyms; + Elf64_Sym *syms; + + syms = (Elf64_Sym *)sechdrs[symindex].sh_addr; + numsyms = sechdrs[symindex].sh_size / sizeof(Elf64_Sym); + + for (i = 1; i < numsyms; i++) { + if (syms[i].st_shndx == SHN_UNDEF + && strcmp(strtab + syms[i].st_name, "TOC.") == 0) + return &syms[i]; + } + return NULL; +} + int module_frob_arch_sections(Elf64_Ehdr *hdr, Elf64_Shdr *sechdrs, char *secstrings, @@ -271,21 +415,12 @@ static inline unsigned long my_r2(Elf64_Shdr *sechdrs, struct module *me) /* Patch stub to reference function and correct r2 value. */ static inline int create_stub(Elf64_Shdr *sechdrs, struct ppc64_stub_entry *entry, - struct ppc64_opd_entry *opd, + unsigned long addr, struct module *me) { - Elf64_Half *loc1, *loc2; long reladdr; - *entry = ppc64_stub; - -#ifdef __LITTLE_ENDIAN__ - loc1 = (Elf64_Half *)&entry->jump[0]; - loc2 = (Elf64_Half *)&entry->jump[4]; -#else - loc1 = (Elf64_Half *)&entry->jump[2]; - loc2 = (Elf64_Half *)&entry->jump[6]; -#endif + memcpy(entry->jump, ppc64_stub_insns, sizeof(ppc64_stub_insns)); /* Stub uses address relative to r2. */ reladdr = (unsigned long)entry - my_r2(sechdrs, me); @@ -296,35 +431,33 @@ static inline int create_stub(Elf64_Shdr *sechdrs, } DEBUGP("Stub %p get data from reladdr %li\n", entry, reladdr); - *loc1 = PPC_HA(reladdr); - *loc2 = PPC_LO(reladdr); - entry->opd.funcaddr = opd->funcaddr; - entry->opd.r2 = opd->r2; + entry->jump[0] |= PPC_HA(reladdr); + entry->jump[1] |= PPC_LO(reladdr); + entry->funcdata = func_desc(addr); return 1; } -/* Create stub to jump to function described in this OPD: we need the +/* Create stub to jump to function described in this OPD/ptr: we need the stub to set up the TOC ptr (r2) for the function. */ static unsigned long stub_for_addr(Elf64_Shdr *sechdrs, - unsigned long opdaddr, + unsigned long addr, struct module *me) { struct ppc64_stub_entry *stubs; - struct ppc64_opd_entry *opd = (void *)opdaddr; unsigned int i, num_stubs; num_stubs = sechdrs[me->arch.stubs_section].sh_size / sizeof(*stubs); /* Find this stub, or if that fails, the next avail. entry */ stubs = (void *)sechdrs[me->arch.stubs_section].sh_addr; - for (i = 0; stubs[i].opd.funcaddr; i++) { + for (i = 0; stub_func_addr(stubs[i].funcdata); i++) { BUG_ON(i >= num_stubs); - if (stubs[i].opd.funcaddr == opd->funcaddr) + if (stub_func_addr(stubs[i].funcdata) == func_addr(addr)) return (unsigned long)&stubs[i]; } - if (!create_stub(sechdrs, &stubs[i], opd, me)) + if (!create_stub(sechdrs, &stubs[i], addr, me)) return 0; return (unsigned long)&stubs[i]; @@ -339,7 +472,8 @@ static int restore_r2(u32 *instruction, struct module *me) me->name, *instruction); return 0; } - *instruction = 0xe8410028; /* ld r2,40(r1) */ + /* ld r2,R2_STACK_OFFSET(r1) */ + *instruction = 0xe8410000 | R2_STACK_OFFSET; return 1; } @@ -357,6 +491,17 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, DEBUGP("Applying ADD relocate section %u to %u\n", relsec, sechdrs[relsec].sh_info); + + /* First time we're called, we can fix up .TOC. */ + if (!me->arch.toc_fixed) { + sym = find_dot_toc(sechdrs, strtab, symindex); + /* It's theoretically possible that a module doesn't want a + * .TOC. so don't fail it just for that. */ + if (sym) + sym->st_value = my_r2(sechdrs, me); + me->arch.toc_fixed = true; + } + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { /* This is where to make the change */ location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr @@ -453,7 +598,8 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, return -ENOENT; if (!restore_r2((u32 *)location + 1, me)) return -ENOEXEC; - } + } else + value += local_entry_offset(sym); /* Convert value to relative */ value -= (unsigned long)location; @@ -474,6 +620,31 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, *location = value - (unsigned long)location; break; + case R_PPC64_TOCSAVE: + /* + * Marker reloc indicates we don't have to save r2. + * That would only save us one instruction, so ignore + * it. + */ + break; + + case R_PPC64_REL16_HA: + /* Subtract location pointer */ + value -= (unsigned long)location; + value = ((value + 0x8000) >> 16); + *((uint16_t *) location) + = (*((uint16_t *) location) & ~0xffff) + | (value & 0xffff); + break; + + case R_PPC64_REL16_LO: + /* Subtract location pointer */ + value -= (unsigned long)location; + *((uint16_t *) location) + = (*((uint16_t *) location) & ~0xffff) + | (value & 0xffff); + break; + default: printk("%s: Unknown ADD relocation: %lu\n", me->name, diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index d9476c1fc95961..add166aa806a13 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,25 @@ resource_size_t pcibios_window_alignment(struct pci_bus *bus, return 1; } +void pcibios_reset_secondary_bus(struct pci_dev *dev) +{ + u16 ctrl; + + if (ppc_md.pcibios_reset_secondary_bus) { + ppc_md.pcibios_reset_secondary_bus(dev); + return; + } + + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl); + ctrl |= PCI_BRIDGE_CTL_BUS_RESET; + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl); + msleep(2); + + ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl); + ssleep(1); +} + static resource_size_t pcibios_io_size(const struct pci_controller *hose) { #ifdef CONFIG_PPC64 @@ -666,60 +686,36 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar, void pci_process_bridge_OF_ranges(struct pci_controller *hose, struct device_node *dev, int primary) { - const __be32 *ranges; - int rlen; - int pna = of_n_addr_cells(dev); - int np = pna + 5; int memno = 0; - u32 pci_space; - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size; struct resource *res; + struct of_pci_range range; + struct of_pci_range_parser parser; printk(KERN_INFO "PCI host bridge %s %s ranges:\n", dev->full_name, primary ? "(primary)" : ""); - /* Get ranges property */ - ranges = of_get_property(dev, "ranges", &rlen); - if (ranges == NULL) + /* Check for ranges property */ + if (of_pci_range_parser_init(&parser, dev)) return; /* Parse it */ - while ((rlen -= np * 4) >= 0) { - /* Read next ranges element */ - pci_space = of_read_number(ranges, 1); - pci_addr = of_read_number(ranges + 1, 2); - cpu_addr = of_translate_address(dev, ranges + 3); - size = of_read_number(ranges + pna + 3, 2); - ranges += np; - + for_each_of_pci_range(&parser, &range) { /* If we failed translation or got a zero-sized region * (some FW try to feed us with non sensical zero sized regions * such as power3 which look like some kind of attempt at exposing * the VGA memory hole) */ - if (cpu_addr == OF_BAD_ADDR || size == 0) + if (range.cpu_addr == OF_BAD_ADDR || range.size == 0) continue; - /* Now consume following elements while they are contiguous */ - for (; rlen >= np * sizeof(u32); - ranges += np, rlen -= np * 4) { - if (of_read_number(ranges, 1) != pci_space) - break; - pci_next = of_read_number(ranges + 1, 2); - cpu_next = of_translate_address(dev, ranges + 3); - if (pci_next != pci_addr + size || - cpu_next != cpu_addr + size) - break; - size += of_read_number(ranges + pna + 3, 2); - } - /* Act based on address space type */ res = NULL; - switch ((pci_space >> 24) & 0x3) { - case 1: /* PCI IO space */ + switch (range.flags & IORESOURCE_TYPE_BITS) { + case IORESOURCE_IO: printk(KERN_INFO " IO 0x%016llx..0x%016llx -> 0x%016llx\n", - cpu_addr, cpu_addr + size - 1, pci_addr); + range.cpu_addr, range.cpu_addr + range.size - 1, + range.pci_addr); /* We support only one IO range */ if (hose->pci_io_size) { @@ -729,11 +725,12 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, } #ifdef CONFIG_PPC32 /* On 32 bits, limit I/O space to 16MB */ - if (size > 0x01000000) - size = 0x01000000; + if (range.size > 0x01000000) + range.size = 0x01000000; /* 32 bits needs to map IOs here */ - hose->io_base_virt = ioremap(cpu_addr, size); + hose->io_base_virt = ioremap(range.cpu_addr, + range.size); /* Expect trouble if pci_addr is not 0 */ if (primary) @@ -743,20 +740,20 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, /* pci_io_size and io_base_phys always represent IO * space starting at 0 so we factor in pci_addr */ - hose->pci_io_size = pci_addr + size; - hose->io_base_phys = cpu_addr - pci_addr; + hose->pci_io_size = range.pci_addr + range.size; + hose->io_base_phys = range.cpu_addr - range.pci_addr; /* Build resource */ res = &hose->io_resource; - res->flags = IORESOURCE_IO; - res->start = pci_addr; + range.cpu_addr = range.pci_addr; break; - case 2: /* PCI Memory space */ - case 3: /* PCI 64 bits Memory space */ + case IORESOURCE_MEM: printk(KERN_INFO " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n", - cpu_addr, cpu_addr + size - 1, pci_addr, - (pci_space & 0x40000000) ? "Prefetch" : ""); + range.cpu_addr, range.cpu_addr + range.size - 1, + range.pci_addr, + (range.pci_space & 0x40000000) ? + "Prefetch" : ""); /* We support only 3 memory ranges */ if (memno >= 3) { @@ -765,28 +762,21 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, continue; } /* Handles ISA memory hole space here */ - if (pci_addr == 0) { + if (range.pci_addr == 0) { if (primary || isa_mem_base == 0) - isa_mem_base = cpu_addr; - hose->isa_mem_phys = cpu_addr; - hose->isa_mem_size = size; + isa_mem_base = range.cpu_addr; + hose->isa_mem_phys = range.cpu_addr; + hose->isa_mem_size = range.size; } /* Build resource */ - hose->mem_offset[memno] = cpu_addr - pci_addr; + hose->mem_offset[memno] = range.cpu_addr - + range.pci_addr; res = &hose->mem_resources[memno++]; - res->flags = IORESOURCE_MEM; - if (pci_space & 0x40000000) - res->flags |= IORESOURCE_PREFETCH; - res->start = cpu_addr; break; } if (res != NULL) { - res->name = dev->full_name; - res->end = res->start + size - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; + of_pci_range_to_resource(&range, dev, res); } } } diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index 83c26d829991e8..ea6470c21f4e4e 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c @@ -304,6 +304,9 @@ static struct pci_dev *of_scan_pci_dev(struct pci_bus *bus, struct pci_dev *dev = NULL; const __be32 *reg; int reglen, devfn; +#ifdef CONFIG_EEH + struct eeh_dev *edev = of_node_to_eeh_dev(dn); +#endif pr_debug(" * %s\n", dn->full_name); if (!of_device_is_available(dn)) @@ -321,6 +324,12 @@ static struct pci_dev *of_scan_pci_dev(struct pci_bus *bus, return dev; } + /* Device removed permanently ? */ +#ifdef CONFIG_EEH + if (edev && (edev->mode & EEH_DEV_REMOVED)) + return NULL; +#endif + /* create a new pci_dev for this device */ dev = of_create_pci_dev(dn, bus, devfn); if (!dev) diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 450850a49dced7..48d17d6fca5b6e 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -155,9 +155,7 @@ EXPORT_SYMBOL(__cmpdi2); #endif long long __bswapdi2(long long); EXPORT_SYMBOL(__bswapdi2); -#ifdef __BIG_ENDIAN__ EXPORT_SYMBOL(memcpy); -#endif EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(memcmp); diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 31d021506d210e..2ae1b99166c638 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -54,6 +54,7 @@ #ifdef CONFIG_PPC64 #include #endif +#include #include #include @@ -1108,7 +1109,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, struct thread_info *ti = (void *)task_stack_page(p); memset(childregs, 0, sizeof(struct pt_regs)); childregs->gpr[1] = sp + sizeof(struct pt_regs); - childregs->gpr[14] = usp; /* function */ + /* function */ + if (usp) + childregs->gpr[14] = ppc_function_entry((void *)usp); #ifdef CONFIG_PPC64 clear_tsk_thread_flag(p, TIF_32BIT); childregs->softe = 1; @@ -1187,17 +1190,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, if (cpu_has_feature(CPU_FTR_HAS_PPR)) p->thread.ppr = INIT_PPR; #endif - /* - * The PPC64 ABI makes use of a TOC to contain function - * pointers. The function (ret_from_except) is actually a pointer - * to the TOC entry. The first entry is a pointer to the actual - * function. - */ -#ifdef CONFIG_PPC64 - kregs->nip = *((unsigned long *)f); -#else - kregs->nip = (unsigned long)f; -#endif + kregs->nip = ppc_function_entry(f); return 0; } diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 668aa4791fd753..613a860a203c96 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -29,11 +29,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include @@ -118,14 +118,14 @@ static void __init move_device_tree(void) DBG("-> move_device_tree\n"); start = __pa(initial_boot_params); - size = be32_to_cpu(initial_boot_params->totalsize); + size = fdt_totalsize(initial_boot_params); if ((memory_limit && (start + size) > PHYSICAL_START + memory_limit) || overlaps_crashkernel(start, size) || overlaps_initrd(start, size)) { p = __va(memblock_alloc(size, PAGE_SIZE)); memcpy(p, initial_boot_params, size); - initial_boot_params = (struct boot_param_header *)p; + initial_boot_params = p; DBG("Moved device tree to 0x%p\n", p); } @@ -163,7 +163,7 @@ static struct ibm_pa_feature { {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0}, }; -static void __init scan_features(unsigned long node, unsigned char *ftrs, +static void __init scan_features(unsigned long node, const unsigned char *ftrs, unsigned long tablelen, struct ibm_pa_feature *fp, unsigned long ft_size) @@ -202,8 +202,8 @@ static void __init scan_features(unsigned long node, unsigned char *ftrs, static void __init check_cpu_pa_features(unsigned long node) { - unsigned char *pa_ftrs; - unsigned long tablelen; + const unsigned char *pa_ftrs; + int tablelen; pa_ftrs = of_get_flat_dt_prop(node, "ibm,pa-features", &tablelen); if (pa_ftrs == NULL) @@ -216,7 +216,7 @@ static void __init check_cpu_pa_features(unsigned long node) #ifdef CONFIG_PPC_STD_MMU_64 static void __init check_cpu_slb_size(unsigned long node) { - __be32 *slb_size_ptr; + const __be32 *slb_size_ptr; slb_size_ptr = of_get_flat_dt_prop(node, "slb-size", NULL); if (slb_size_ptr != NULL) { @@ -257,7 +257,7 @@ static struct feature_property { static inline void identical_pvr_fixup(unsigned long node) { unsigned int pvr; - char *model = of_get_flat_dt_prop(node, "model", NULL); + const char *model = of_get_flat_dt_prop(node, "model", NULL); /* * Since 440GR(x)/440EP(x) processors have the same pvr, @@ -295,11 +295,11 @@ static int __init early_init_dt_scan_cpus(unsigned long node, const char *uname, int depth, void *data) { - char *type = of_get_flat_dt_prop(node, "device_type", NULL); + const char *type = of_get_flat_dt_prop(node, "device_type", NULL); const __be32 *prop; const __be32 *intserv; int i, nthreads; - unsigned long len; + int len; int found = -1; int found_thread = 0; @@ -325,9 +325,9 @@ static int __init early_init_dt_scan_cpus(unsigned long node, * version 2 of the kexec param format adds the phys cpuid of * booted proc. */ - if (be32_to_cpu(initial_boot_params->version) >= 2) { + if (fdt_version(initial_boot_params) >= 2) { if (be32_to_cpu(intserv[i]) == - be32_to_cpu(initial_boot_params->boot_cpuid_phys)) { + fdt_boot_cpuid_phys(initial_boot_params)) { found = boot_cpu_count; found_thread = i; } @@ -392,7 +392,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, int __init early_init_dt_scan_chosen_ppc(unsigned long node, const char *uname, int depth, void *data) { - unsigned long *lprop; /* All these set by kernel, so no need to convert endian */ + const unsigned long *lprop; /* All these set by kernel, so no need to convert endian */ /* Use common scan routine to determine if this is the chosen node */ if (early_init_dt_scan_chosen(node, uname, depth, data) == 0) @@ -443,8 +443,9 @@ int __init early_init_dt_scan_chosen_ppc(unsigned long node, const char *uname, */ static int __init early_init_dt_scan_drconf_memory(unsigned long node) { - __be32 *dm, *ls, *usm; - unsigned long l, n, flags; + const __be32 *dm, *ls, *usm; + int l; + unsigned long n, flags; u64 base, size, memblock_size; unsigned int is_kexec_kdump = 0, rngs; @@ -564,9 +565,12 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) static void __init early_reserve_mem_dt(void) { - unsigned long i, len, dt_root; + unsigned long i, dt_root; + int len; const __be32 *prop; + early_init_fdt_scan_reserved_mem(); + dt_root = of_get_flat_dt_root(); prop = of_get_flat_dt_prop(dt_root, "reserved-ranges", &len); @@ -589,24 +593,14 @@ static void __init early_reserve_mem_dt(void) memblock_reserve(base, size); } } - - early_init_fdt_scan_reserved_mem(); } static void __init early_reserve_mem(void) { - u64 base, size; __be64 *reserve_map; - unsigned long self_base; - unsigned long self_size; reserve_map = (__be64 *)(((unsigned long)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_mem_rsvmap)); - - /* before we do anything, lets reserve the dt blob */ - self_base = __pa((unsigned long)initial_boot_params); - self_size = be32_to_cpu(initial_boot_params->totalsize); - memblock_reserve(self_base, self_size); + fdt_off_mem_rsvmap(initial_boot_params)); /* Look for the new "reserved-regions" property in the DT */ early_reserve_mem_dt(); @@ -636,26 +630,12 @@ static void __init early_reserve_mem(void) size_32 = be32_to_cpup(reserve_map_32++); if (size_32 == 0) break; - /* skip if the reservation is for the blob */ - if (base_32 == self_base && size_32 == self_size) - continue; DBG("reserving: %x -> %x\n", base_32, size_32); memblock_reserve(base_32, size_32); } return; } #endif - DBG("Processing reserve map\n"); - - /* Handle the reserve map in the fdt blob if it exists */ - while (1) { - base = be64_to_cpup(reserve_map++); - size = be64_to_cpup(reserve_map++); - if (size == 0) - break; - DBG("reserving: %llx -> %llx\n", base, size); - memblock_reserve(base, size); - } } void __init early_init_devtree(void *params) @@ -922,23 +902,3 @@ bool arch_match_cpu_phys_id(int cpu, u64 phys_id) { return (int)phys_id == get_hard_smp_processor_id(cpu); } - -#if defined(CONFIG_DEBUG_FS) && defined(DEBUG) -static struct debugfs_blob_wrapper flat_dt_blob; - -static int __init export_flat_device_tree(void) -{ - struct dentry *d; - - flat_dt_blob.data = initial_boot_params; - flat_dt_blob.size = be32_to_cpu(initial_boot_params->totalsize); - - d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR, - powerpc_debugfs_root, &flat_dt_blob); - if (!d) - return 1; - - return 0; -} -__initcall(export_flat_device_tree); -#endif diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh index b0c263da219a2b..77aa1e95e9046d 100644 --- a/arch/powerpc/kernel/prom_init_check.sh +++ b/arch/powerpc/kernel/prom_init_check.sh @@ -23,7 +23,7 @@ strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224 reloc_got2 kernstart_addr memstart_addr linux_banner _stext opal_query_takeover opal_do_takeover opal_enter_rtas opal_secondary_entry boot_command_line __prom_init_toc_start __prom_init_toc_end -btext_setup_display" +btext_setup_display TOC." NM="$1" OBJ="$2" diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 2e3d2bf536c566..524a943a33bb24 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1788,14 +1788,11 @@ long do_syscall_trace_enter(struct pt_regs *regs) #ifdef CONFIG_PPC64 if (!is_32bit_task()) - audit_syscall_entry(AUDIT_ARCH_PPC64, - regs->gpr[0], - regs->gpr[3], regs->gpr[4], + audit_syscall_entry(regs->gpr[0], regs->gpr[3], regs->gpr[4], regs->gpr[5], regs->gpr[6]); else #endif - audit_syscall_entry(AUDIT_ARCH_PPC, - regs->gpr[0], + audit_syscall_entry(regs->gpr[0], regs->gpr[3] & 0xffffffff, regs->gpr[4] & 0xffffffff, regs->gpr[5] & 0xffffffff, diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 8cd5ed049b5db0..8b4c857c142176 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -1142,7 +1142,7 @@ void __init rtas_initialize(void) int __init early_init_dt_scan_rtas(unsigned long node, const char *uname, int depth, void *data) { - u32 *basep, *entryp, *sizep; + const u32 *basep, *entryp, *sizep; if (depth != 1 || strcmp(uname, "rtas") != 0) return 0; diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index 7d4c7172f38ed4..c168337aef9dd3 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c @@ -80,10 +80,6 @@ int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val) if (ret) return PCIBIOS_DEVICE_NOT_FOUND; - if (returnval == EEH_IO_ERROR_VALUE(size) && - eeh_dev_check_failure(of_node_to_eeh_dev(pdn->node))) - return PCIBIOS_DEVICE_NOT_FOUND; - return PCIBIOS_SUCCESSFUL; } @@ -92,18 +88,39 @@ static int rtas_pci_read_config(struct pci_bus *bus, int where, int size, u32 *val) { struct device_node *busdn, *dn; - - busdn = pci_bus_to_OF_node(bus); + struct pci_dn *pdn; + bool found = false; +#ifdef CONFIG_EEH + struct eeh_dev *edev; +#endif + int ret; /* Search only direct children of the bus */ + *val = 0xFFFFFFFF; + busdn = pci_bus_to_OF_node(bus); for (dn = busdn->child; dn; dn = dn->sibling) { - struct pci_dn *pdn = PCI_DN(dn); + pdn = PCI_DN(dn); if (pdn && pdn->devfn == devfn - && of_device_is_available(dn)) - return rtas_read_config(pdn, where, size, val); + && of_device_is_available(dn)) { + found = true; + break; + } } - return PCIBIOS_DEVICE_NOT_FOUND; + if (!found) + return PCIBIOS_DEVICE_NOT_FOUND; +#ifdef CONFIG_EEH + edev = of_node_to_eeh_dev(dn); + if (edev && edev->pe && edev->pe->state & EEH_PE_RESET) + return PCIBIOS_DEVICE_NOT_FOUND; +#endif + + ret = rtas_read_config(pdn, where, size, val); + if (*val == EEH_IO_ERROR_VALUE(size) && + eeh_dev_check_failure(of_node_to_eeh_dev(dn))) + return PCIBIOS_DEVICE_NOT_FOUND; + + return ret; } int rtas_write_config(struct pci_dn *pdn, int where, int size, u32 val) @@ -136,17 +153,34 @@ static int rtas_pci_write_config(struct pci_bus *bus, int where, int size, u32 val) { struct device_node *busdn, *dn; - - busdn = pci_bus_to_OF_node(bus); + struct pci_dn *pdn; + bool found = false; +#ifdef CONFIG_EEH + struct eeh_dev *edev; +#endif + int ret; /* Search only direct children of the bus */ + busdn = pci_bus_to_OF_node(bus); for (dn = busdn->child; dn; dn = dn->sibling) { - struct pci_dn *pdn = PCI_DN(dn); + pdn = PCI_DN(dn); if (pdn && pdn->devfn == devfn - && of_device_is_available(dn)) - return rtas_write_config(pdn, where, size, val); + && of_device_is_available(dn)) { + found = true; + break; + } } - return PCIBIOS_DEVICE_NOT_FOUND; + + if (!found) + return PCIBIOS_DEVICE_NOT_FOUND; +#ifdef CONFIG_EEH + edev = of_node_to_eeh_dev(dn); + if (edev && edev->pe && (edev->pe->state & EEH_PE_RESET)) + return PCIBIOS_DEVICE_NOT_FOUND; +#endif + ret = rtas_write_config(pdn, where, size, val); + + return ret; } static struct pci_ops rtas_pci_ops = { diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 79b7612ac6fa34..3cf25c89469dbb 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -212,6 +212,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) { unsigned long cpu_id = (unsigned long)v - 1; unsigned int pvr; + unsigned long proc_freq; unsigned short maj; unsigned short min; @@ -263,12 +264,19 @@ static int show_cpuinfo(struct seq_file *m, void *v) #endif /* CONFIG_TAU */ /* - * Assume here that all clock rates are the same in a - * smp system. -- Cort + * Platforms that have variable clock rates, should implement + * the method ppc_md.get_proc_freq() that reports the clock + * rate of a given cpu. The rest can use ppc_proc_freq to + * report the clock rate that is same across all cpus. */ - if (ppc_proc_freq) + if (ppc_md.get_proc_freq) + proc_freq = ppc_md.get_proc_freq(cpu_id); + else + proc_freq = ppc_proc_freq; + + if (proc_freq) seq_printf(m, "clock\t\t: %lu.%06luMHz\n", - ppc_proc_freq / 1000000, ppc_proc_freq % 1000000); + proc_freq / 1000000, proc_freq % 1000000); if (ppc_md.show_percpuinfo != NULL) ppc_md.show_percpuinfo(m, cpu_id); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index fbe24377eda3e4..90b532ace0d580 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -341,7 +341,7 @@ void smp_release_cpus(void) ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop - PHYSICAL_START); - *ptr = __pa(generic_secondary_smp_init); + *ptr = ppc_function_entry(generic_secondary_smp_init); /* And wait a bit for them to catch up */ for (i = 0; i < 100000; i++) { diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index e2a4232c5871a1..10ffffef041413 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -766,6 +766,28 @@ int setup_profiling_timer(unsigned int multiplier) return 0; } +#ifdef CONFIG_SCHED_SMT +/* cpumask of CPUs with asymetric SMT dependancy */ +static const int powerpc_smt_flags(void) +{ + int flags = SD_SHARE_CPUPOWER | SD_SHARE_PKG_RESOURCES; + + if (cpu_has_feature(CPU_FTR_ASYM_SMT)) { + printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n"); + flags |= SD_ASYM_PACKING; + } + return flags; +} +#endif + +static struct sched_domain_topology_level powerpc_topology[] = { +#ifdef CONFIG_SCHED_SMT + { cpu_smt_mask, powerpc_smt_flags, SD_INIT_NAME(SMT) }, +#endif + { cpu_cpu_mask, SD_INIT_NAME(DIE) }, + { NULL, }, +}; + void __init smp_cpus_done(unsigned int max_cpus) { cpumask_var_t old_mask; @@ -790,15 +812,8 @@ void __init smp_cpus_done(unsigned int max_cpus) dump_numa_cpu_topology(); -} + set_sched_topology(powerpc_topology); -int arch_sd_sibling_asym_packing(void) -{ - if (cpu_has_feature(CPU_FTR_ASYM_SMT)) { - printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n"); - return SD_ASYM_PACKING; - } - return 0; } #ifdef CONFIG_HOTPLUG_CPU diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 93219c34af327b..895c50ca943c95 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -17,12 +17,12 @@ #include #ifdef CONFIG_PPC64 -#define SYSCALL(func) .llong .sys_##func,.sys_##func -#define COMPAT_SYS(func) .llong .sys_##func,.compat_sys_##func -#define PPC_SYS(func) .llong .ppc_##func,.ppc_##func -#define OLDSYS(func) .llong .sys_ni_syscall,.sys_ni_syscall -#define SYS32ONLY(func) .llong .sys_ni_syscall,.compat_sys_##func -#define SYSX(f, f3264, f32) .llong .f,.f3264 +#define SYSCALL(func) .llong DOTSYM(sys_##func),DOTSYM(sys_##func) +#define COMPAT_SYS(func) .llong DOTSYM(sys_##func),DOTSYM(compat_sys_##func) +#define PPC_SYS(func) .llong DOTSYM(ppc_##func),DOTSYM(ppc_##func) +#define OLDSYS(func) .llong DOTSYM(sys_ni_syscall),DOTSYM(sys_ni_syscall) +#define SYS32ONLY(func) .llong DOTSYM(sys_ni_syscall),DOTSYM(compat_sys_##func) +#define SYSX(f, f3264, f32) .llong DOTSYM(f),DOTSYM(f3264) #else #define SYSCALL(func) .long sys_##func #define COMPAT_SYS(func) .long sys_##func @@ -36,6 +36,8 @@ #define PPC_SYS_SPU(func) PPC_SYS(func) #define SYSX_SPU(f, f3264, f32) SYSX(f, f3264, f32) +.section .rodata,"a" + #ifdef CONFIG_PPC64 #define sys_sigpending sys_ni_syscall #define sys_old_getrlimit sys_ni_syscall @@ -43,5 +45,7 @@ .p2align 3 #endif -_GLOBAL(sys_call_table) +.globl sys_call_table +sys_call_table: + #include diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S index 03567c05950a3c..ee061c3715deb0 100644 --- a/arch/powerpc/kernel/tm.S +++ b/arch/powerpc/kernel/tm.S @@ -10,6 +10,7 @@ #include #include #include +#include #ifdef CONFIG_VSX /* See fpu.S, this is borrowed from there */ @@ -41,7 +42,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX); \ /* Stack frame offsets for local variables. */ #define TM_FRAME_L0 TM_FRAME_SIZE-16 #define TM_FRAME_L1 TM_FRAME_SIZE-8 -#define STACK_PARAM(x) (48+((x)*8)) /* In order to access the TM SPRs, TM must be enabled. So, do so: */ @@ -108,12 +108,12 @@ _GLOBAL(tm_reclaim) mflr r0 stw r6, 8(r1) std r0, 16(r1) - std r2, 40(r1) + std r2, STK_GOT(r1) stdu r1, -TM_FRAME_SIZE(r1) /* We've a struct pt_regs at [r1+STACK_FRAME_OVERHEAD]. */ - std r3, STACK_PARAM(0)(r1) + std r3, STK_PARAM(R3)(r1) SAVE_NVGPRS(r1) /* We need to setup MSR for VSX register save instructions. Here we @@ -175,6 +175,13 @@ dont_backup_vec: stfd fr0,FPSTATE_FPSCR(r7) dont_backup_fp: + /* Do sanity check on MSR to make sure we are suspended */ + li r7, (MSR_TS_S)@higher + srdi r6, r14, 32 + and r6, r6, r7 +1: tdeqi r6, 0 + EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0 + /* The moment we treclaim, ALL of our GPRs will switch * to user register state. (FPRs, CCR etc. also!) * Use an sprg and a tm_scratch in the PACA to shuffle. @@ -202,7 +209,7 @@ dont_backup_fp: /* Now get some more GPRS free */ std r7, GPR7(r1) /* Temporary stash */ std r12, GPR12(r1) /* '' '' '' */ - ld r12, STACK_PARAM(0)(r1) /* Param 0, thread_struct * */ + ld r12, STK_PARAM(R3)(r1) /* Param 0, thread_struct * */ std r11, THREAD_TM_PPR(r12) /* Store PPR and free r11 */ @@ -289,7 +296,7 @@ dont_backup_fp: ld r0, 16(r1) mtcr r4 mtlr r0 - ld r2, 40(r1) + ld r2, STK_GOT(r1) /* Load system default DSCR */ ld r4, DSCR_DEFAULT@toc(r2) @@ -312,7 +319,7 @@ _GLOBAL(__tm_recheckpoint) mflr r0 stw r5, 8(r1) std r0, 16(r1) - std r2, 40(r1) + std r2, STK_GOT(r1) stdu r1, -TM_FRAME_SIZE(r1) /* We've a struct pt_regs at [r1+STACK_FRAME_OVERHEAD]. @@ -320,8 +327,6 @@ _GLOBAL(__tm_recheckpoint) */ SAVE_NVGPRS(r1) - std r1, PACAR1(r13) - /* Load complete register state from ts_ckpt* registers */ addi r7, r3, PT_CKPT_REGS /* Thread's ckpt_regs */ @@ -385,12 +390,10 @@ restore_gprs: /* ******************** CR,LR,CCR,MSR ********** */ ld r4, _CTR(r7) ld r5, _LINK(r7) - ld r6, _CCR(r7) ld r8, _XER(r7) mtctr r4 mtlr r5 - mtcr r6 mtxer r8 /* ******************** TAR ******************** */ @@ -406,7 +409,8 @@ restore_gprs: li r4, 0 mtmsrd r4, 1 - REST_4GPRS(0, r7) /* GPR0-3 */ + REST_GPR(0, r7) /* GPR0 */ + REST_2GPRS(2, r7) /* GPR2-3 */ REST_GPR(4, r7) /* GPR4 */ REST_4GPRS(8, r7) /* GPR8-11 */ REST_2GPRS(12, r7) /* GPR12-13 */ @@ -418,6 +422,31 @@ restore_gprs: mtspr SPRN_DSCR, r5 mtspr SPRN_PPR, r6 + /* Do final sanity check on TEXASR to make sure FS is set. Do this + * here before we load up the userspace r1 so any bugs we hit will get + * a call chain */ + mfspr r5, SPRN_TEXASR + srdi r5, r5, 16 + li r6, (TEXASR_FS)@h + and r6, r6, r5 +1: tdeqi r6, 0 + EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0 + + /* Do final sanity check on MSR to make sure we are not transactional + * or suspended + */ + mfmsr r6 + li r5, (MSR_TS_MASK)@higher + srdi r6, r6, 32 + and r6, r6, r5 +1: tdnei r6, 0 + EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0 + + /* Restore CR */ + ld r6, _CCR(r7) + mtcr r6 + + REST_GPR(1, r7) /* GPR1 */ REST_GPR(5, r7) /* GPR5-7 */ REST_GPR(6, r7) ld r7, GPR7(r7) @@ -448,7 +477,7 @@ restore_gprs: ld r0, 16(r1) mtcr r4 mtlr r0 - ld r2, 40(r1) + ld r2, STK_GOT(r1) /* Load system default DSCR */ ld r4, DSCR_DEFAULT@toc(r2) diff --git a/arch/powerpc/kvm/book3s_hv_interrupts.S b/arch/powerpc/kvm/book3s_hv_interrupts.S index e18e3cfc32debe..8c86422a1e37a7 100644 --- a/arch/powerpc/kvm/book3s_hv_interrupts.S +++ b/arch/powerpc/kvm/book3s_hv_interrupts.S @@ -171,7 +171,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) #endif /* CONFIG_SMP */ /* Jump to partition switch code */ - bl .kvmppc_hv_entry_trampoline + bl kvmppc_hv_entry_trampoline nop /* diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index b031f932c0cc3d..9f0ad718e4766b 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1658,7 +1658,7 @@ kvmppc_hdsi: /* Search the hash table. */ mr r3, r9 /* vcpu pointer */ li r7, 1 /* data fault */ - bl .kvmppc_hpte_hv_fault + bl kvmppc_hpte_hv_fault ld r9, HSTATE_KVM_VCPU(r13) ld r10, VCPU_PC(r9) ld r11, VCPU_MSR(r9) @@ -1732,7 +1732,7 @@ kvmppc_hisi: mr r4, r10 mr r6, r11 li r7, 0 /* instruction fault */ - bl .kvmppc_hpte_hv_fault + bl kvmppc_hpte_hv_fault ld r9, HSTATE_KVM_VCPU(r13) ld r10, VCPU_PC(r9) ld r11, VCPU_MSR(r9) @@ -1806,16 +1806,16 @@ hcall_real_fallback: .globl hcall_real_table hcall_real_table: .long 0 /* 0 - unused */ - .long .kvmppc_h_remove - hcall_real_table - .long .kvmppc_h_enter - hcall_real_table - .long .kvmppc_h_read - hcall_real_table + .long DOTSYM(kvmppc_h_remove) - hcall_real_table + .long DOTSYM(kvmppc_h_enter) - hcall_real_table + .long DOTSYM(kvmppc_h_read) - hcall_real_table .long 0 /* 0x10 - H_CLEAR_MOD */ .long 0 /* 0x14 - H_CLEAR_REF */ - .long .kvmppc_h_protect - hcall_real_table - .long .kvmppc_h_get_tce - hcall_real_table - .long .kvmppc_h_put_tce - hcall_real_table + .long DOTSYM(kvmppc_h_protect) - hcall_real_table + .long DOTSYM(kvmppc_h_get_tce) - hcall_real_table + .long DOTSYM(kvmppc_h_put_tce) - hcall_real_table .long 0 /* 0x24 - H_SET_SPRG0 */ - .long .kvmppc_h_set_dabr - hcall_real_table + .long DOTSYM(kvmppc_h_set_dabr) - hcall_real_table .long 0 /* 0x2c */ .long 0 /* 0x30 */ .long 0 /* 0x34 */ @@ -1831,11 +1831,11 @@ hcall_real_table: .long 0 /* 0x5c */ .long 0 /* 0x60 */ #ifdef CONFIG_KVM_XICS - .long .kvmppc_rm_h_eoi - hcall_real_table - .long .kvmppc_rm_h_cppr - hcall_real_table - .long .kvmppc_rm_h_ipi - hcall_real_table + .long DOTSYM(kvmppc_rm_h_eoi) - hcall_real_table + .long DOTSYM(kvmppc_rm_h_cppr) - hcall_real_table + .long DOTSYM(kvmppc_rm_h_ipi) - hcall_real_table .long 0 /* 0x70 - H_IPOLL */ - .long .kvmppc_rm_h_xirr - hcall_real_table + .long DOTSYM(kvmppc_rm_h_xirr) - hcall_real_table #else .long 0 /* 0x64 - H_EOI */ .long 0 /* 0x68 - H_CPPR */ @@ -1869,7 +1869,7 @@ hcall_real_table: .long 0 /* 0xd4 */ .long 0 /* 0xd8 */ .long 0 /* 0xdc */ - .long .kvmppc_h_cede - hcall_real_table + .long DOTSYM(kvmppc_h_cede) - hcall_real_table .long 0 /* 0xe4 */ .long 0 /* 0xe8 */ .long 0 /* 0xec */ @@ -1886,11 +1886,11 @@ hcall_real_table: .long 0 /* 0x118 */ .long 0 /* 0x11c */ .long 0 /* 0x120 */ - .long .kvmppc_h_bulk_remove - hcall_real_table + .long DOTSYM(kvmppc_h_bulk_remove) - hcall_real_table .long 0 /* 0x128 */ .long 0 /* 0x12c */ .long 0 /* 0x130 */ - .long .kvmppc_h_set_xdabr - hcall_real_table + .long DOTSYM(kvmppc_h_set_xdabr) - hcall_real_table hcall_real_table_end: ignore_hdec: @@ -2115,7 +2115,7 @@ kvm_cede_exit: /* Try to handle a machine check in real mode */ machine_check_realmode: mr r3, r9 /* get vcpu pointer */ - bl .kvmppc_realmode_machine_check + bl kvmppc_realmode_machine_check nop cmpdi r3, 0 /* continue exiting from guest? */ ld r9, HSTATE_KVM_VCPU(r13) diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 95a20e17dbff2c..59fa2de9546d7f 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -23,9 +23,7 @@ obj-y += checksum_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_PPC64) += checksum_wrappers_64.o endif -ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),) obj-$(CONFIG_PPC64) += memcpy_power7.o memcpy_64.o -endif obj-$(CONFIG_PPC_EMULATE_SSTEP) += sstep.o ldstfp.o diff --git a/arch/powerpc/lib/copypage_64.S b/arch/powerpc/lib/copypage_64.S index 9f9434a8526443..e59c9c2ebe98dd 100644 --- a/arch/powerpc/lib/copypage_64.S +++ b/arch/powerpc/lib/copypage_64.S @@ -20,7 +20,7 @@ _GLOBAL(copy_page) BEGIN_FTR_SECTION lis r5,PAGE_SIZE@h FTR_SECTION_ELSE - b .copypage_power7 + b copypage_power7 ALT_FTR_SECTION_END_IFCLR(CPU_FTR_VMX_COPY) ori r5,r5,PAGE_SIZE@l BEGIN_FTR_SECTION diff --git a/arch/powerpc/lib/copypage_power7.S b/arch/powerpc/lib/copypage_power7.S index 395c594722a223..d7dafb3777acc6 100644 --- a/arch/powerpc/lib/copypage_power7.S +++ b/arch/powerpc/lib/copypage_power7.S @@ -56,15 +56,15 @@ _GLOBAL(copypage_power7) #ifdef CONFIG_ALTIVEC mflr r0 - std r3,48(r1) - std r4,56(r1) + std r3,-STACKFRAMESIZE+STK_REG(R31)(r1) + std r4,-STACKFRAMESIZE+STK_REG(R30)(r1) std r0,16(r1) stdu r1,-STACKFRAMESIZE(r1) - bl .enter_vmx_copy + bl enter_vmx_copy cmpwi r3,0 ld r0,STACKFRAMESIZE+16(r1) - ld r3,STACKFRAMESIZE+48(r1) - ld r4,STACKFRAMESIZE+56(r1) + ld r3,STK_REG(R31)(r1) + ld r4,STK_REG(R30)(r1) mtlr r0 li r0,(PAGE_SIZE/128) @@ -103,7 +103,7 @@ _GLOBAL(copypage_power7) addi r3,r3,128 bdnz 1b - b .exit_vmx_copy /* tail call optimise */ + b exit_vmx_copy /* tail call optimise */ #else li r0,(PAGE_SIZE/128) diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S index 596a285c07554d..0860ee46013c93 100644 --- a/arch/powerpc/lib/copyuser_64.S +++ b/arch/powerpc/lib/copyuser_64.S @@ -18,7 +18,7 @@ #endif .align 7 -_GLOBAL(__copy_tofrom_user) +_GLOBAL_TOC(__copy_tofrom_user) BEGIN_FTR_SECTION nop FTR_SECTION_ELSE diff --git a/arch/powerpc/lib/copyuser_power7.S b/arch/powerpc/lib/copyuser_power7.S index e8e9c36dc78444..c46c876ac96af6 100644 --- a/arch/powerpc/lib/copyuser_power7.S +++ b/arch/powerpc/lib/copyuser_power7.S @@ -66,7 +66,7 @@ ld r15,STK_REG(R15)(r1) ld r14,STK_REG(R14)(r1) .Ldo_err3: - bl .exit_vmx_usercopy + bl exit_vmx_usercopy ld r0,STACKFRAMESIZE+16(r1) mtlr r0 b .Lexit @@ -85,9 +85,9 @@ .Lexit: addi r1,r1,STACKFRAMESIZE .Ldo_err1: - ld r3,48(r1) - ld r4,56(r1) - ld r5,64(r1) + ld r3,-STACKFRAMESIZE+STK_REG(R31)(r1) + ld r4,-STACKFRAMESIZE+STK_REG(R30)(r1) + ld r5,-STACKFRAMESIZE+STK_REG(R29)(r1) b __copy_tofrom_user_base @@ -96,18 +96,18 @@ _GLOBAL(__copy_tofrom_user_power7) cmpldi r5,16 cmpldi cr1,r5,4096 - std r3,48(r1) - std r4,56(r1) - std r5,64(r1) + std r3,-STACKFRAMESIZE+STK_REG(R31)(r1) + std r4,-STACKFRAMESIZE+STK_REG(R30)(r1) + std r5,-STACKFRAMESIZE+STK_REG(R29)(r1) blt .Lshort_copy bgt cr1,.Lvmx_copy #else cmpldi r5,16 - std r3,48(r1) - std r4,56(r1) - std r5,64(r1) + std r3,-STACKFRAMESIZE+STK_REG(R31)(r1) + std r4,-STACKFRAMESIZE+STK_REG(R30)(r1) + std r5,-STACKFRAMESIZE+STK_REG(R29)(r1) blt .Lshort_copy #endif @@ -295,12 +295,12 @@ err1; stb r0,0(r3) mflr r0 std r0,16(r1) stdu r1,-STACKFRAMESIZE(r1) - bl .enter_vmx_usercopy + bl enter_vmx_usercopy cmpwi cr1,r3,0 ld r0,STACKFRAMESIZE+16(r1) - ld r3,STACKFRAMESIZE+48(r1) - ld r4,STACKFRAMESIZE+56(r1) - ld r5,STACKFRAMESIZE+64(r1) + ld r3,STK_REG(R31)(r1) + ld r4,STK_REG(R30)(r1) + ld r5,STK_REG(R29)(r1) mtlr r0 /* @@ -514,7 +514,7 @@ err3; lbz r0,0(r4) err3; stb r0,0(r3) 15: addi r1,r1,STACKFRAMESIZE - b .exit_vmx_usercopy /* tail call optimise */ + b exit_vmx_usercopy /* tail call optimise */ .Lvmx_unaligned_copy: /* Get the destination 16B aligned */ @@ -717,5 +717,5 @@ err3; lbz r0,0(r4) err3; stb r0,0(r3) 15: addi r1,r1,STACKFRAMESIZE - b .exit_vmx_usercopy /* tail call optimise */ + b exit_vmx_usercopy /* tail call optimise */ #endif /* CONFiG_ALTIVEC */ diff --git a/arch/powerpc/lib/hweight_64.S b/arch/powerpc/lib/hweight_64.S index 9b96ff2ecd4dad..19e66001a4f9d5 100644 --- a/arch/powerpc/lib/hweight_64.S +++ b/arch/powerpc/lib/hweight_64.S @@ -24,7 +24,7 @@ _GLOBAL(__arch_hweight8) BEGIN_FTR_SECTION - b .__sw_hweight8 + b __sw_hweight8 nop nop FTR_SECTION_ELSE @@ -35,7 +35,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_POPCNTB) _GLOBAL(__arch_hweight16) BEGIN_FTR_SECTION - b .__sw_hweight16 + b __sw_hweight16 nop nop nop @@ -57,7 +57,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_POPCNTB) _GLOBAL(__arch_hweight32) BEGIN_FTR_SECTION - b .__sw_hweight32 + b __sw_hweight32 nop nop nop @@ -82,7 +82,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_POPCNTB) _GLOBAL(__arch_hweight64) BEGIN_FTR_SECTION - b .__sw_hweight64 + b __sw_hweight64 nop nop nop diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S index f4fcb0bc656392..0738f96befbff7 100644 --- a/arch/powerpc/lib/mem_64.S +++ b/arch/powerpc/lib/mem_64.S @@ -79,8 +79,8 @@ _GLOBAL(memset) _GLOBAL(memmove) cmplw 0,r3,r4 - bgt .backwards_memcpy - b .memcpy + bgt backwards_memcpy + b memcpy _GLOBAL(backwards_memcpy) rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S index 72ad055168a333..32a06ec395d210 100644 --- a/arch/powerpc/lib/memcpy_64.S +++ b/arch/powerpc/lib/memcpy_64.S @@ -10,14 +10,29 @@ #include .align 7 -_GLOBAL(memcpy) +_GLOBAL_TOC(memcpy) BEGIN_FTR_SECTION - std r3,48(r1) /* save destination pointer for return value */ +#ifdef __LITTLE_ENDIAN__ + cmpdi cr7,r5,0 +#else + std r3,-STACKFRAMESIZE+STK_REG(R31)(r1) /* save destination pointer for return value */ +#endif FTR_SECTION_ELSE #ifndef SELFTEST b memcpy_power7 #endif ALT_FTR_SECTION_END_IFCLR(CPU_FTR_VMX_COPY) +#ifdef __LITTLE_ENDIAN__ + /* dumb little-endian memcpy that will get replaced at runtime */ + addi r9,r3,-1 + addi r4,r4,-1 + beqlr cr7 + mtctr r5 +1: lbzu r10,1(r4) + stbu r10,1(r9) + bdnz 1b + blr +#else PPC_MTOCRF(0x01,r5) cmpldi cr1,r5,16 neg r6,r3 # LS 3 bits = # bytes to 8-byte dest bdry @@ -73,7 +88,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) 2: bf cr7*4+3,3f lbz r9,8(r4) stb r9,0(r3) -3: ld r3,48(r1) /* return dest pointer */ +3: ld r3,-STACKFRAMESIZE+STK_REG(R31)(r1) /* return dest pointer */ blr .Lsrc_unaligned: @@ -156,7 +171,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) 2: bf cr7*4+3,3f rotldi r9,r9,8 stb r9,0(r3) -3: ld r3,48(r1) /* return dest pointer */ +3: ld r3,-STACKFRAMESIZE+STK_REG(R31)(r1) /* return dest pointer */ blr .Ldst_unaligned: @@ -201,5 +216,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) 3: bf cr7*4+3,4f lbz r0,0(r4) stb r0,0(r3) -4: ld r3,48(r1) /* return dest pointer */ +4: ld r3,-STACKFRAMESIZE+STK_REG(R31)(r1) /* return dest pointer */ blr +#endif diff --git a/arch/powerpc/lib/memcpy_power7.S b/arch/powerpc/lib/memcpy_power7.S index e4177dbea6bd6a..2ff5c142f87ba0 100644 --- a/arch/powerpc/lib/memcpy_power7.S +++ b/arch/powerpc/lib/memcpy_power7.S @@ -33,14 +33,14 @@ _GLOBAL(memcpy_power7) cmpldi r5,16 cmpldi cr1,r5,4096 - std r3,48(r1) + std r3,-STACKFRAMESIZE+STK_REG(R31)(r1) blt .Lshort_copy bgt cr1,.Lvmx_copy #else cmpldi r5,16 - std r3,48(r1) + std r3,-STACKFRAMESIZE+STK_REG(R31)(r1) blt .Lshort_copy #endif @@ -216,7 +216,7 @@ _GLOBAL(memcpy_power7) lbz r0,0(r4) stb r0,0(r3) -15: ld r3,48(r1) +15: ld r3,-STACKFRAMESIZE+STK_REG(R31)(r1) blr .Lunwind_stack_nonvmx_copy: @@ -226,16 +226,16 @@ _GLOBAL(memcpy_power7) #ifdef CONFIG_ALTIVEC .Lvmx_copy: mflr r0 - std r4,56(r1) - std r5,64(r1) + std r4,-STACKFRAMESIZE+STK_REG(R30)(r1) + std r5,-STACKFRAMESIZE+STK_REG(R29)(r1) std r0,16(r1) stdu r1,-STACKFRAMESIZE(r1) - bl .enter_vmx_copy + bl enter_vmx_copy cmpwi cr1,r3,0 ld r0,STACKFRAMESIZE+16(r1) - ld r3,STACKFRAMESIZE+48(r1) - ld r4,STACKFRAMESIZE+56(r1) - ld r5,STACKFRAMESIZE+64(r1) + ld r3,STK_REG(R31)(r1) + ld r4,STK_REG(R30)(r1) + ld r5,STK_REG(R29)(r1) mtlr r0 /* @@ -447,8 +447,8 @@ _GLOBAL(memcpy_power7) stb r0,0(r3) 15: addi r1,r1,STACKFRAMESIZE - ld r3,48(r1) - b .exit_vmx_copy /* tail call optimise */ + ld r3,-STACKFRAMESIZE+STK_REG(R31)(r1) + b exit_vmx_copy /* tail call optimise */ .Lvmx_unaligned_copy: /* Get the destination 16B aligned */ @@ -651,6 +651,6 @@ _GLOBAL(memcpy_power7) stb r0,0(r3) 15: addi r1,r1,STACKFRAMESIZE - ld r3,48(r1) - b .exit_vmx_copy /* tail call optimise */ + ld r3,-STACKFRAMESIZE+STK_REG(R31)(r1) + b exit_vmx_copy /* tail call optimise */ #endif /* CONFiG_ALTIVEC */ diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index 1136d26a95ae02..057cbbb4c576d3 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S @@ -159,7 +159,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) BEGIN_FTR_SECTION mr r4,r30 mr r5,r7 - bl .hash_page_do_lazy_icache + bl hash_page_do_lazy_icache END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE) /* At this point, r3 contains new PP bits, save them in @@ -201,7 +201,8 @@ htab_insert_pte: li r8,MMU_PAGE_4K /* page size */ li r9,MMU_PAGE_4K /* actual page size */ ld r10,STK_PARAM(R9)(r1) /* segment size */ -_GLOBAL(htab_call_hpte_insert1) +.globl htab_call_hpte_insert1 +htab_call_hpte_insert1: bl . /* Patched by htab_finish_init() */ cmpdi 0,r3,0 bge htab_pte_insert_ok /* Insertion successful */ @@ -225,7 +226,8 @@ _GLOBAL(htab_call_hpte_insert1) li r8,MMU_PAGE_4K /* page size */ li r9,MMU_PAGE_4K /* actual page size */ ld r10,STK_PARAM(R9)(r1) /* segment size */ -_GLOBAL(htab_call_hpte_insert2) +.globl htab_call_hpte_insert2 +htab_call_hpte_insert2: bl . /* Patched by htab_finish_init() */ cmpdi 0,r3,0 bge+ htab_pte_insert_ok /* Insertion successful */ @@ -242,7 +244,8 @@ _GLOBAL(htab_call_hpte_insert2) 2: and r0,r5,r27 rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */ /* Call ppc_md.hpte_remove */ -_GLOBAL(htab_call_hpte_remove) +.globl htab_call_hpte_remove +htab_call_hpte_remove: bl . /* Patched by htab_finish_init() */ /* Try all again */ @@ -296,7 +299,8 @@ htab_modify_pte: li r7,MMU_PAGE_4K /* actual page size */ ld r8,STK_PARAM(R9)(r1) /* segment size */ ld r9,STK_PARAM(R8)(r1) /* get "local" param */ -_GLOBAL(htab_call_hpte_updatepp) +.globl htab_call_hpte_updatepp +htab_call_hpte_updatepp: bl . /* Patched by htab_finish_init() */ /* if we failed because typically the HPTE wasn't really here @@ -471,7 +475,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) BEGIN_FTR_SECTION mr r4,r30 mr r5,r7 - bl .hash_page_do_lazy_icache + bl hash_page_do_lazy_icache END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE) /* At this point, r3 contains new PP bits, save them in @@ -526,7 +530,8 @@ htab_special_pfn: li r8,MMU_PAGE_4K /* page size */ li r9,MMU_PAGE_4K /* actual page size */ ld r10,STK_PARAM(R9)(r1) /* segment size */ -_GLOBAL(htab_call_hpte_insert1) +.globl htab_call_hpte_insert1 +htab_call_hpte_insert1: bl . /* patched by htab_finish_init() */ cmpdi 0,r3,0 bge htab_pte_insert_ok /* Insertion successful */ @@ -554,7 +559,8 @@ _GLOBAL(htab_call_hpte_insert1) li r8,MMU_PAGE_4K /* page size */ li r9,MMU_PAGE_4K /* actual page size */ ld r10,STK_PARAM(R9)(r1) /* segment size */ -_GLOBAL(htab_call_hpte_insert2) +.globl htab_call_hpte_insert2 +htab_call_hpte_insert2: bl . /* patched by htab_finish_init() */ cmpdi 0,r3,0 bge+ htab_pte_insert_ok /* Insertion successful */ @@ -571,7 +577,8 @@ _GLOBAL(htab_call_hpte_insert2) 2: and r0,r5,r27 rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */ /* Call ppc_md.hpte_remove */ -_GLOBAL(htab_call_hpte_remove) +.globl htab_call_hpte_remove +htab_call_hpte_remove: bl . /* patched by htab_finish_init() */ /* Try all again */ @@ -588,7 +595,7 @@ htab_inval_old_hpte: li r6,MMU_PAGE_64K /* psize */ ld r7,STK_PARAM(R9)(r1) /* ssize */ ld r8,STK_PARAM(R8)(r1) /* local */ - bl .flush_hash_page + bl flush_hash_page /* Clear out _PAGE_HPTE_SUB bits in the new linux PTE */ lis r0,_PAGE_HPTE_SUB@h ori r0,r0,_PAGE_HPTE_SUB@l @@ -660,7 +667,8 @@ htab_modify_pte: li r7,MMU_PAGE_4K /* actual page size */ ld r8,STK_PARAM(R9)(r1) /* segment size */ ld r9,STK_PARAM(R8)(r1) /* get "local" param */ -_GLOBAL(htab_call_hpte_updatepp) +.globl htab_call_hpte_updatepp +htab_call_hpte_updatepp: bl . /* patched by htab_finish_init() */ /* if we failed because typically the HPTE wasn't really here @@ -812,7 +820,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) BEGIN_FTR_SECTION mr r4,r30 mr r5,r7 - bl .hash_page_do_lazy_icache + bl hash_page_do_lazy_icache END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE) /* At this point, r3 contains new PP bits, save them in @@ -857,7 +865,8 @@ ht64_insert_pte: li r8,MMU_PAGE_64K li r9,MMU_PAGE_64K /* actual page size */ ld r10,STK_PARAM(R9)(r1) /* segment size */ -_GLOBAL(ht64_call_hpte_insert1) +.globl ht64_call_hpte_insert1 +ht64_call_hpte_insert1: bl . /* patched by htab_finish_init() */ cmpdi 0,r3,0 bge ht64_pte_insert_ok /* Insertion successful */ @@ -881,7 +890,8 @@ _GLOBAL(ht64_call_hpte_insert1) li r8,MMU_PAGE_64K li r9,MMU_PAGE_64K /* actual page size */ ld r10,STK_PARAM(R9)(r1) /* segment size */ -_GLOBAL(ht64_call_hpte_insert2) +.globl ht64_call_hpte_insert2 +ht64_call_hpte_insert2: bl . /* patched by htab_finish_init() */ cmpdi 0,r3,0 bge+ ht64_pte_insert_ok /* Insertion successful */ @@ -898,7 +908,8 @@ _GLOBAL(ht64_call_hpte_insert2) 2: and r0,r5,r27 rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */ /* Call ppc_md.hpte_remove */ -_GLOBAL(ht64_call_hpte_remove) +.globl ht64_call_hpte_remove +ht64_call_hpte_remove: bl . /* patched by htab_finish_init() */ /* Try all again */ @@ -952,7 +963,8 @@ ht64_modify_pte: li r7,MMU_PAGE_64K /* actual page size */ ld r8,STK_PARAM(R9)(r1) /* segment size */ ld r9,STK_PARAM(R8)(r1) /* get "local" param */ -_GLOBAL(ht64_call_hpte_updatepp) +.globl ht64_call_hpte_updatepp +ht64_call_hpte_updatepp: bl . /* patched by htab_finish_init() */ /* if we failed because typically the HPTE wasn't really here diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index d766d6ee33fe68..26913d0c0bb0b4 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -265,9 +265,9 @@ static int __init htab_dt_scan_seg_sizes(unsigned long node, const char *uname, int depth, void *data) { - char *type = of_get_flat_dt_prop(node, "device_type", NULL); - __be32 *prop; - unsigned long size = 0; + const char *type = of_get_flat_dt_prop(node, "device_type", NULL); + const __be32 *prop; + int size = 0; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) @@ -320,9 +320,9 @@ static int __init htab_dt_scan_page_sizes(unsigned long node, const char *uname, int depth, void *data) { - char *type = of_get_flat_dt_prop(node, "device_type", NULL); - __be32 *prop; - unsigned long size = 0; + const char *type = of_get_flat_dt_prop(node, "device_type", NULL); + const __be32 *prop; + int size = 0; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) @@ -402,9 +402,9 @@ static int __init htab_dt_scan_page_sizes(unsigned long node, static int __init htab_dt_scan_hugepage_blocks(unsigned long node, const char *uname, int depth, void *data) { - char *type = of_get_flat_dt_prop(node, "device_type", NULL); - __be64 *addr_prop; - __be32 *page_count_prop; + const char *type = of_get_flat_dt_prop(node, "device_type", NULL); + const __be64 *addr_prop; + const __be32 *page_count_prop; unsigned int expected_pages; long unsigned int phys_addr; long unsigned int block_size; @@ -445,6 +445,24 @@ static void mmu_psize_set_default_penc(void) mmu_psize_defs[bpsize].penc[apsize] = -1; } +#ifdef CONFIG_PPC_64K_PAGES + +static bool might_have_hea(void) +{ + /* + * The HEA ethernet adapter requires awareness of the + * GX bus. Without that awareness we can easily assume + * we will never see an HEA ethernet device. + */ +#ifdef CONFIG_IBMEBUS + return !cpu_has_feature(CPU_FTR_ARCH_207S); +#else + return false; +#endif +} + +#endif /* #ifdef CONFIG_PPC_64K_PAGES */ + static void __init htab_init_page_sizes(void) { int rc; @@ -499,10 +517,11 @@ static void __init htab_init_page_sizes(void) mmu_linear_psize = MMU_PAGE_64K; if (mmu_has_feature(MMU_FTR_CI_LARGE_PAGE)) { /* - * Don't use 64k pages for ioremap on pSeries, since - * that would stop us accessing the HEA ethernet. + * When running on pSeries using 64k pages for ioremap + * would stop us accessing the HEA ethernet. So if we + * have the chance of ever seeing one, stay at 4k. */ - if (!machine_is(pseries)) + if (!might_have_hea() || !machine_is(pseries)) mmu_io_psize = MMU_PAGE_64K; } else mmu_ci_restrictions = 1; @@ -546,8 +565,8 @@ static int __init htab_dt_scan_pftsize(unsigned long node, const char *uname, int depth, void *data) { - char *type = of_get_flat_dt_prop(node, "device_type", NULL); - __be32 *prop; + const char *type = of_get_flat_dt_prop(node, "device_type", NULL); + const __be32 *prop; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) @@ -603,47 +622,43 @@ int remove_section_mapping(unsigned long start, unsigned long end) } #endif /* CONFIG_MEMORY_HOTPLUG */ -#define FUNCTION_TEXT(A) ((*(unsigned long *)(A))) +extern u32 htab_call_hpte_insert1[]; +extern u32 htab_call_hpte_insert2[]; +extern u32 htab_call_hpte_remove[]; +extern u32 htab_call_hpte_updatepp[]; +extern u32 ht64_call_hpte_insert1[]; +extern u32 ht64_call_hpte_insert2[]; +extern u32 ht64_call_hpte_remove[]; +extern u32 ht64_call_hpte_updatepp[]; static void __init htab_finish_init(void) { - extern unsigned int *htab_call_hpte_insert1; - extern unsigned int *htab_call_hpte_insert2; - extern unsigned int *htab_call_hpte_remove; - extern unsigned int *htab_call_hpte_updatepp; - #ifdef CONFIG_PPC_HAS_HASH_64K - extern unsigned int *ht64_call_hpte_insert1; - extern unsigned int *ht64_call_hpte_insert2; - extern unsigned int *ht64_call_hpte_remove; - extern unsigned int *ht64_call_hpte_updatepp; - patch_branch(ht64_call_hpte_insert1, - FUNCTION_TEXT(ppc_md.hpte_insert), + ppc_function_entry(ppc_md.hpte_insert), BRANCH_SET_LINK); patch_branch(ht64_call_hpte_insert2, - FUNCTION_TEXT(ppc_md.hpte_insert), + ppc_function_entry(ppc_md.hpte_insert), BRANCH_SET_LINK); patch_branch(ht64_call_hpte_remove, - FUNCTION_TEXT(ppc_md.hpte_remove), + ppc_function_entry(ppc_md.hpte_remove), BRANCH_SET_LINK); patch_branch(ht64_call_hpte_updatepp, - FUNCTION_TEXT(ppc_md.hpte_updatepp), + ppc_function_entry(ppc_md.hpte_updatepp), BRANCH_SET_LINK); - #endif /* CONFIG_PPC_HAS_HASH_64K */ patch_branch(htab_call_hpte_insert1, - FUNCTION_TEXT(ppc_md.hpte_insert), + ppc_function_entry(ppc_md.hpte_insert), BRANCH_SET_LINK); patch_branch(htab_call_hpte_insert2, - FUNCTION_TEXT(ppc_md.hpte_insert), + ppc_function_entry(ppc_md.hpte_insert), BRANCH_SET_LINK); patch_branch(htab_call_hpte_remove, - FUNCTION_TEXT(ppc_md.hpte_remove), + ppc_function_entry(ppc_md.hpte_remove), BRANCH_SET_LINK); patch_branch(htab_call_hpte_updatepp, - FUNCTION_TEXT(ppc_md.hpte_updatepp), + ppc_function_entry(ppc_md.hpte_updatepp), BRANCH_SET_LINK); } diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 9d1d33cd2be528..4623366f82e93c 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -256,10 +256,14 @@ static inline void patch_slb_encoding(unsigned int *insn_addr, patch_instruction(insn_addr, insn); } +extern u32 slb_compare_rr_to_size[]; +extern u32 slb_miss_kernel_load_linear[]; +extern u32 slb_miss_kernel_load_io[]; +extern u32 slb_compare_rr_to_size[]; +extern u32 slb_miss_kernel_load_vmemmap[]; + void slb_set_size(u16 size) { - extern unsigned int *slb_compare_rr_to_size; - if (mmu_slb_size == size) return; @@ -272,11 +276,7 @@ void slb_initialize(void) unsigned long linear_llp, vmalloc_llp, io_llp; unsigned long lflags, vflags; static int slb_encoding_inited; - extern unsigned int *slb_miss_kernel_load_linear; - extern unsigned int *slb_miss_kernel_load_io; - extern unsigned int *slb_compare_rr_to_size; #ifdef CONFIG_SPARSEMEM_VMEMMAP - extern unsigned int *slb_miss_kernel_load_vmemmap; unsigned long vmemmap_llp; #endif diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index 17aa6dfceb3498..736d18b3cefd3b 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -35,7 +35,7 @@ _GLOBAL(slb_allocate_realmode) * check for bad kernel/user address * (ea & ~REGION_MASK) >= PGTABLE_RANGE */ - rldicr. r9,r3,4,(63 - 46 - 4) + rldicr. r9,r3,4,(63 - PGTABLE_EADDR_SIZE - 4) bne- 8f srdi r9,r3,60 /* get region */ @@ -59,7 +59,8 @@ _GLOBAL(slb_allocate_realmode) /* Linear mapping encoding bits, the "li" instruction below will * be patched by the kernel at boot */ -_GLOBAL(slb_miss_kernel_load_linear) +.globl slb_miss_kernel_load_linear +slb_miss_kernel_load_linear: li r11,0 /* * context = (MAX_USER_CONTEXT) + ((ea >> 60) - 0xc) + 1 @@ -79,7 +80,8 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) /* Check virtual memmap region. To be patches at kernel boot */ cmpldi cr0,r9,0xf bne 1f -_GLOBAL(slb_miss_kernel_load_vmemmap) +.globl slb_miss_kernel_load_vmemmap +slb_miss_kernel_load_vmemmap: li r11,0 b 6f 1: @@ -95,7 +97,8 @@ _GLOBAL(slb_miss_kernel_load_vmemmap) b 6f 5: /* IO mapping */ - _GLOBAL(slb_miss_kernel_load_io) +.globl slb_miss_kernel_load_io +slb_miss_kernel_load_io: li r11,0 6: /* @@ -250,7 +253,8 @@ slb_finish_load: 7: ld r10,PACASTABRR(r13) addi r10,r10,1 /* This gets soft patched on boot. */ -_GLOBAL(slb_compare_rr_to_size) +.globl slb_compare_rr_to_size +slb_compare_rr_to_size: cmpldi r10,0 blt+ 4f diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index dc1a264ec6e6da..4d88f6a19058cc 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -199,6 +199,34 @@ config CURRITUCK help This option enables support for the IBM Currituck (476fpe) evaluation board +config AKEBONO + bool "IBM Akebono (476gtr) Support" + depends on PPC_47x + default n + select SWIOTLB + select 476FPE + select PPC4xx_PCI_EXPRESS + select PCI_MSI + select PPC4xx_HSTA_MSI + select I2C + select I2C_IBM_IIC + select NETDEVICES + select ETHERNET + select NET_VENDOR_IBM + select IBM_EMAC_EMAC4 + select IBM_EMAC_RGMII_WOL + select USB + select USB_OHCI_HCD_PLATFORM + select USB_EHCI_HCD_PLATFORM + select MMC_SDHCI + select MMC_SDHCI_PLTFM + select MMC_SDHCI_OF_476GTR + select ATA + select SATA_AHCI_PLATFORM + help + This option enables support for the IBM Akebono (476gtr) evaluation board + + config ICON bool "Icon" depends on 44x @@ -323,6 +351,20 @@ config APM821xx select IBM_EMAC_EMAC4 select IBM_EMAC_TAH +config 476FPE_ERR46 + depends on 476FPE + bool "Enable linker work around for PPC476FPE errata #46" + help + This option enables a work around for an icache bug on 476 + that can cause execution of stale instructions when falling + through pages (IBM errata #46). It requires a recent version + of binutils which supports the --ppc476-workaround option. + + The work around enables the appropriate linker options and + ensures that all module output sections are aligned to 4K + page boundaries. The work around is only required when + building modules. + # 44x errata/workaround config symbols, selected by the CPU models above config IBM440EP_ERR42 bool diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile index d03833abec0929..26d35b5941f798 100644 --- a/arch/powerpc/platforms/44x/Makefile +++ b/arch/powerpc/platforms/44x/Makefile @@ -10,4 +10,5 @@ obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o obj-$(CONFIG_XILINX_ML510) += virtex_ml510.o obj-$(CONFIG_ISS4xx) += iss4xx.o obj-$(CONFIG_CANYONLANDS)+= canyonlands.o -obj-$(CONFIG_CURRITUCK) += currituck.o +obj-$(CONFIG_CURRITUCK) += ppc476.o +obj-$(CONFIG_AKEBONO) += ppc476.o diff --git a/arch/powerpc/platforms/44x/currituck.c b/arch/powerpc/platforms/44x/ppc476.c similarity index 72% rename from arch/powerpc/platforms/44x/currituck.c rename to arch/powerpc/platforms/44x/ppc476.c index 7f1b71a01c6a4e..33986c1a05da2e 100644 --- a/arch/powerpc/platforms/44x/currituck.c +++ b/arch/powerpc/platforms/44x/ppc476.c @@ -1,7 +1,8 @@ /* - * Currituck board specific routines + * PowerPC 476FPE board specific routines * - * Copyright © 2011 Tony Breeds IBM Corporation + * Copyright © 2013 Tony Breeds IBM Corporation + * Copyright © 2013 Alistair Popple IBM Corporation * * Based on earlier code: * Matt Porter @@ -35,8 +36,9 @@ #include #include +#include -static __initdata struct of_device_id ppc47x_of_bus[] = { +static struct of_device_id ppc47x_of_bus[] __initdata = { { .compatible = "ibm,plb4", }, { .compatible = "ibm,plb6", }, { .compatible = "ibm,opb", }, @@ -55,15 +57,69 @@ static void quirk_ppc_currituck_usb_fixup(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(0x1033, 0x0035, quirk_ppc_currituck_usb_fixup); +/* Akebono has an AVR microcontroller attached to the I2C bus + * which is used to power off/reset the system. */ + +/* AVR I2C Commands */ +#define AVR_PWRCTL_CMD (0x26) + +/* Flags for the power control I2C commands */ +#define AVR_PWRCTL_PWROFF (0x01) +#define AVR_PWRCTL_RESET (0x02) + +static struct i2c_client *avr_i2c_client; +static void avr_halt_system(int pwrctl_flags) +{ + /* Request the AVR to reset the system */ + i2c_smbus_write_byte_data(avr_i2c_client, + AVR_PWRCTL_CMD, pwrctl_flags); + + /* Wait for system to be reset */ + while (1) + ; +} + +static void avr_power_off_system(void) +{ + avr_halt_system(AVR_PWRCTL_PWROFF); +} + +static void avr_reset_system(char *cmd) +{ + avr_halt_system(AVR_PWRCTL_RESET); +} + +static int avr_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + avr_i2c_client = client; + ppc_md.restart = avr_reset_system; + ppc_md.power_off = avr_power_off_system; + return 0; +} + +static const struct i2c_device_id avr_id[] = { + { "akebono-avr", 0 }, + { } +}; + +static struct i2c_driver avr_driver = { + .driver = { + .name = "akebono-avr", + }, + .probe = avr_probe, + .id_table = avr_id, +}; + static int __init ppc47x_device_probe(void) { + i2c_add_driver(&avr_driver); of_platform_bus_probe(NULL, ppc47x_of_bus, NULL); return 0; } machine_device_initcall(ppc47x, ppc47x_device_probe); -/* We can have either UICs or MPICs */ static void __init ppc47x_init_irq(void) { struct device_node *np; @@ -157,43 +213,36 @@ static void __init ppc47x_setup_arch(void) { /* No need to check the DMA config as we /know/ our windows are all of - * RAM. Lets hope that doesn't change */ + * RAM. Lets hope that doesn't change */ swiotlb_detect_4g(); ppc47x_smp_init(); } -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init ppc47x_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - - if (!of_flat_dt_is_compatible(root, "ibm,currituck")) - return 0; - - return 1; -} - static int board_rev = -1; static int __init ppc47x_get_board_rev(void) { - u8 fpga_reg0; - void *fpga; - struct device_node *np; + int reg; + u8 *fpga; + struct device_node *np = NULL; + + if (of_machine_is_compatible("ibm,currituck")) { + np = of_find_compatible_node(NULL, NULL, "ibm,currituck-fpga"); + reg = 0; + } else if (of_machine_is_compatible("ibm,akebono")) { + np = of_find_compatible_node(NULL, NULL, "ibm,akebono-fpga"); + reg = 2; + } - np = of_find_compatible_node(NULL, NULL, "ibm,currituck-fpga"); if (!np) goto fail; - fpga = of_iomap(np, 0); + fpga = (u8 *) of_iomap(np, 0); of_node_put(np); if (!fpga) goto fail; - fpga_reg0 = ioread8(fpga); - board_rev = fpga_reg0 & 0x03; + board_rev = ioread8(fpga + reg) & 0x03; pr_info("%s: Found board revision %d\n", __func__, board_rev); iounmap(fpga); return 0; @@ -208,7 +257,7 @@ machine_arch_initcall(ppc47x, ppc47x_get_board_rev); static void ppc47x_pci_irq_fixup(struct pci_dev *dev) { if (dev->vendor == 0x1033 && (dev->device == 0x0035 || - dev->device == 0x00e0)) { + dev->device == 0x00e0)) { if (board_rev == 0) { dev->irq = irq_create_mapping(NULL, 47); pr_info("%s: Mapping irq %d\n", __func__, dev->irq); @@ -221,13 +270,30 @@ static void ppc47x_pci_irq_fixup(struct pci_dev *dev) } } +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init ppc47x_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "ibm,akebono")) + return 1; + + if (of_flat_dt_is_compatible(root, "ibm,currituck")) { + ppc_md.pci_irq_fixup = ppc47x_pci_irq_fixup; + return 1; + } + + return 0; +} + define_machine(ppc47x) { .name = "PowerPC 47x", .probe = ppc47x_probe, .progress = udbg_progress, .init_IRQ = ppc47x_init_irq, .setup_arch = ppc47x_setup_arch, - .pci_irq_fixup = ppc47x_pci_irq_fixup, .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/ppc476_modules.lds b/arch/powerpc/platforms/44x/ppc476_modules.lds new file mode 100644 index 00000000000000..9fec5d34ba8efd --- /dev/null +++ b/arch/powerpc/platforms/44x/ppc476_modules.lds @@ -0,0 +1,15 @@ +SECTIONS +{ + .text : ALIGN(4096) + { + *(.text .text.* .fixup) + } + .init.text : ALIGN(4096) + { + *(.init.text .init.text.*) + } + .exit.text : ALIGN(4096) + { + *(.exit.text .exit.text.*) + } +} diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 47d66794cf3e0e..3feffde9128d11 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -200,8 +200,8 @@ static void __init efika_setup_arch(void) static int __init efika_probe(void) { - char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), - "model", NULL); + const char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), + "model", NULL); if (model == NULL) return 0; diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 6382098d6f8d88..ba093f55367894 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -267,7 +268,7 @@ static int smp_85xx_kick_cpu(int nr) flush_spin_table(spin_table); out_be32(&spin_table->pir, hw_cpu); out_be64((u64 *)(&spin_table->addr_h), - __pa((u64)*((unsigned long long *)generic_secondary_smp_init))); + __pa(ppc_function_entry(generic_secondary_smp_init))); flush_spin_table(spin_table); #endif diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index d9e2b19b7c8deb..43b65ad1970a1a 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -422,6 +422,7 @@ config CPU_BIG_ENDIAN config CPU_LITTLE_ENDIAN bool "Build little endian kernel" + select PPC64_BOOT_WRAPPER help Build a little endian kernel. @@ -430,3 +431,7 @@ config CPU_LITTLE_ENDIAN little endian powerpc. endchoice + +config PPC64_BOOT_WRAPPER + def_bool n + depends on CPU_LITTLE_ENDIAN diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c index 90745eaa45fe95..c8017a7bcabd2b 100644 --- a/arch/powerpc/platforms/cell/smp.c +++ b/arch/powerpc/platforms/cell/smp.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "interrupt.h" #include @@ -70,8 +71,8 @@ static cpumask_t of_spin_map; static inline int smp_startup_cpu(unsigned int lcpu) { int status; - unsigned long start_here = __pa((u32)*((unsigned long *) - generic_secondary_smp_init)); + unsigned long start_here = + __pa(ppc_function_entry(generic_secondary_smp_init)); unsigned int pcpu; int start_cpu; diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index c665d7de6c9985..7044fd36197b90 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -574,8 +574,8 @@ chrp_init2(void) static int __init chrp_probe(void) { - char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(), - "device_type", NULL); + const char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(), + "device_type", NULL); if (dtype == NULL) return 0; if (strcmp(dtype, "chrp")) diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 2a7024d8d8b133..a25f496c2ef906 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -65,6 +65,7 @@ config MVME5100 select PPC_INDIRECT_PCI select PPC_I8259 select PPC_NATIVE + select PPC_UDBG_16550 help This option enables support for the Motorola (now Emerson) MVME5100 board. diff --git a/arch/powerpc/platforms/pasemi/powersave.S b/arch/powerpc/platforms/pasemi/powersave.S index 56f45adcd0895a..81ab555aa491ed 100644 --- a/arch/powerpc/platforms/pasemi/powersave.S +++ b/arch/powerpc/platforms/pasemi/powersave.S @@ -66,7 +66,7 @@ sleep_common: std r3, 48(r1) /* Only do power savings when in astate 0 */ - bl .check_astate + bl check_astate cmpwi r3,0 bne 1f diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index 253fefe3d1a0e7..79d0cdf786d021 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -42,11 +42,19 @@ static int ioda_eeh_event(struct notifier_block *nb, { uint64_t changed_evts = (uint64_t)change; - /* We simply send special EEH event */ - if ((changed_evts & OPAL_EVENT_PCI_ERROR) && - (events & OPAL_EVENT_PCI_ERROR) && - eeh_enabled()) + /* + * We simply send special EEH event if EEH has + * been enabled, or clear pending events in + * case that we enable EEH soon + */ + if (!(changed_evts & OPAL_EVENT_PCI_ERROR) || + !(events & OPAL_EVENT_PCI_ERROR)) + return 0; + + if (eeh_enabled()) eeh_send_failure_event(NULL); + else + opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul); return 0; } @@ -141,7 +149,9 @@ static int ioda_eeh_post_init(struct pci_controller *hose) } #ifdef CONFIG_DEBUG_FS - if (phb->dbgfs) { + if (!phb->has_dbgfs && phb->dbgfs) { + phb->has_dbgfs = 1; + debugfs_create_file("err_injct_outbound", 0600, phb->dbgfs, hose, &ioda_eeh_outb_dbgfs_ops); @@ -154,7 +164,14 @@ static int ioda_eeh_post_init(struct pci_controller *hose) } #endif - phb->eeh_state |= PNV_EEH_STATE_ENABLED; + /* If EEH is enabled, we're going to rely on that. + * Otherwise, we restore to conventional mechanism + * to clear frozen PE during PCI config access. + */ + if (eeh_enabled()) + phb->flags |= PNV_PHB_FLAG_EEH; + else + phb->flags &= ~PNV_PHB_FLAG_EEH; return 0; } @@ -268,6 +285,21 @@ static int ioda_eeh_get_state(struct eeh_pe *pe) return EEH_STATE_NOT_SUPPORT; } + /* + * If we're in middle of PE reset, return normal + * state to keep EEH core going. For PHB reset, we + * still expect to have fenced PHB cleared with + * PHB reset. + */ + if (!(pe->type & EEH_PE_PHB) && + (pe->state & EEH_PE_RESET)) { + result = (EEH_STATE_MMIO_ACTIVE | + EEH_STATE_DMA_ACTIVE | + EEH_STATE_MMIO_ENABLED | + EEH_STATE_DMA_ENABLED); + return result; + } + /* Retrieve PE status through OPAL */ pe_no = pe->addr; ret = opal_pci_eeh_freeze_status(phb->opal_id, pe_no, @@ -347,52 +379,6 @@ static int ioda_eeh_get_state(struct eeh_pe *pe) return result; } -static int ioda_eeh_pe_clear(struct eeh_pe *pe) -{ - struct pci_controller *hose; - struct pnv_phb *phb; - u32 pe_no; - u8 fstate; - u16 pcierr; - s64 ret; - - pe_no = pe->addr; - hose = pe->phb; - phb = pe->phb->private_data; - - /* Clear the EEH error on the PE */ - ret = opal_pci_eeh_freeze_clear(phb->opal_id, - pe_no, OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); - if (ret) { - pr_err("%s: Failed to clear EEH error for " - "PHB#%x-PE#%x, err=%lld\n", - __func__, hose->global_number, pe_no, ret); - return -EIO; - } - - /* - * Read the PE state back and verify that the frozen - * state has been removed. - */ - ret = opal_pci_eeh_freeze_status(phb->opal_id, pe_no, - &fstate, &pcierr, NULL); - if (ret) { - pr_err("%s: Failed to get EEH status on " - "PHB#%x-PE#%x\n, err=%lld\n", - __func__, hose->global_number, pe_no, ret); - return -EIO; - } - - if (fstate != OPAL_EEH_STOPPED_NOT_FROZEN) { - pr_err("%s: Frozen state not cleared on " - "PHB#%x-PE#%x, sts=%x\n", - __func__, hose->global_number, pe_no, fstate); - return -EIO; - } - - return 0; -} - static s64 ioda_eeh_phb_poll(struct pnv_phb *phb) { s64 rc = OPAL_HARDWARE; @@ -402,13 +388,16 @@ static s64 ioda_eeh_phb_poll(struct pnv_phb *phb) if (rc <= 0) break; - msleep(rc); + if (system_state < SYSTEM_RUNNING) + udelay(1000 * rc); + else + msleep(rc); } return rc; } -static int ioda_eeh_phb_reset(struct pci_controller *hose, int option) +int ioda_eeh_phb_reset(struct pci_controller *hose, int option) { struct pnv_phb *phb = hose->private_data; s64 rc = OPAL_HARDWARE; @@ -431,9 +420,17 @@ static int ioda_eeh_phb_reset(struct pci_controller *hose, int option) /* * Poll state of the PHB until the request is done - * successfully. + * successfully. The PHB reset is usually PHB complete + * reset followed by hot reset on root bus. So we also + * need the PCI bus settlement delay. */ rc = ioda_eeh_phb_poll(phb); + if (option == EEH_RESET_DEACTIVATE) { + if (system_state < SYSTEM_RUNNING) + udelay(1000 * EEH_PE_RST_SETTLE_TIME); + else + msleep(EEH_PE_RST_SETTLE_TIME); + } out: if (rc != OPAL_SUCCESS) return -EIO; @@ -471,6 +468,8 @@ static int ioda_eeh_root_reset(struct pci_controller *hose, int option) /* Poll state of the PHB until the request is done */ rc = ioda_eeh_phb_poll(phb); + if (option == EEH_RESET_DEACTIVATE) + msleep(EEH_PE_RST_SETTLE_TIME); out: if (rc != OPAL_SUCCESS) return -EIO; @@ -478,32 +477,149 @@ static int ioda_eeh_root_reset(struct pci_controller *hose, int option) return 0; } -static int ioda_eeh_bridge_reset(struct pci_controller *hose, - struct pci_dev *dev, int option) +static bool ioda_eeh_is_plx_dnport(struct pci_dev *dev, int *reg, + int *mask, int *len) { - u16 ctrl; + unsigned short *pid; + unsigned short ids[] = { + 0x10b5, 0x8748, 0x0080, 0x0400, /* PLX#8748 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* End flag */ + }; + + if (!pci_is_pcie(dev)) + return false; + if (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM) + return false; + + pid = &ids[0]; + while (!reg) { + if (pid[0] == 0x0) + break; - pr_debug("%s: Reset device %04x:%02x:%02x.%01x with option %d\n", - __func__, hose->global_number, dev->bus->number, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), option); + if (dev->vendor == pid[0] && + dev->device == pid[1]) { + *reg = pid[2]; + *mask = pid[3]; + *len = 2; + return true; + } + } + + *reg = PCI_BRIDGE_CONTROL; + *mask = PCI_BRIDGE_CTL_BUS_RESET; + *len = 2; + return false; +} + +static int ioda_eeh_bridge_reset(struct pci_dev *dev, int option) + +{ + struct device_node *dn = pci_device_to_OF_node(dev); + struct eeh_dev *edev = of_node_to_eeh_dev(dn); + int aer = edev ? edev->aer_cap : 0; + int reg, mask, val, len; + bool is_plx_dnport; + + pr_debug("%s: Reset PCI bus %04x:%02x with option %d\n", + __func__, pci_domain_nr(dev->bus), + dev->bus->number, option); + + + is_plx_dnport = ioda_eeh_is_plx_dnport(dev, ®, &mask, &len); + if (option == EEH_RESET_FUNDAMENTAL) + if (!is_plx_dnport || !edev) + option = EEH_RESET_HOT; + + if (option == EEH_RESET_HOT) { + reg = PCI_BRIDGE_CONTROL; + mask = PCI_BRIDGE_CTL_BUS_RESET; + len = 2; + } + + if (option == EEH_RESET_DEACTIVATE) { + if (!is_plx_dnport || !edev || + !(edev->mode & EEH_DEV_FRESET)) { + reg = PCI_BRIDGE_CONTROL; + mask = PCI_BRIDGE_CTL_BUS_RESET; + len = 2; + } + } switch (option) { case EEH_RESET_FUNDAMENTAL: + edev->mode |= EEH_DEV_FRESET; + /* Fall through */ case EEH_RESET_HOT: - pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl); - ctrl |= PCI_BRIDGE_CTL_BUS_RESET; - pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl); + if (aer) { + /* Mask receiver error */ + eeh_ops->read_config(dn, aer + PCI_ERR_COR_MASK, + 4, &val); + val |= PCI_ERR_COR_RCVR; + eeh_ops->write_config(dn, aer + PCI_ERR_COR_MASK, + 4, val); + + /* Mask linkDown */ + eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK, + 4, &val); + val |= PCI_ERR_UNC_SURPDN; + eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK, + 4, val); + } + + eeh_ops->read_config(dn, reg, len, &val); + val |= mask; + eeh_ops->write_config(dn, reg, len, val); + msleep(EEH_PE_RST_HOLD_TIME); + break; case EEH_RESET_DEACTIVATE: - pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl); - ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; - pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl); + eeh_ops->read_config(dn, reg, len, &val); + val &= ~mask; + eeh_ops->write_config(dn, reg, len, val); + msleep(EEH_PE_RST_SETTLE_TIME); + + if (edev) + edev->mode &= ~EEH_DEV_FRESET; + if (aer) { + /* Clear receive error and enable it */ + eeh_ops->write_config(dn, aer + PCI_ERR_COR_STATUS, + 4, PCI_ERR_COR_RCVR); + eeh_ops->read_config(dn, aer + PCI_ERR_COR_MASK, + 4, &val); + val &= ~PCI_ERR_COR_RCVR; + eeh_ops->write_config(dn, aer + PCI_ERR_COR_MASK, + 4, val); + + /* Clear linkDown and enable it */ + eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_STATUS, + 4, PCI_ERR_UNC_SURPDN); + eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK, + 4, &val); + val &= ~PCI_ERR_UNC_SURPDN; + eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK, + 4, val); + } + break; } return 0; } +void pnv_pci_reset_secondary_bus(struct pci_dev *dev) +{ + struct pci_controller *hose; + + if (pci_is_root_bus(dev->bus)) { + hose = pci_bus_to_host(dev->bus); + ioda_eeh_root_reset(hose, EEH_RESET_HOT); + ioda_eeh_root_reset(hose, EEH_RESET_DEACTIVATE); + } else { + ioda_eeh_bridge_reset(dev, EEH_RESET_HOT); + ioda_eeh_bridge_reset(dev, EEH_RESET_DEACTIVATE); + } +} + /** * ioda_eeh_reset - Reset the indicated PE * @pe: EEH PE @@ -523,36 +639,28 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option) int ret; /* - * Anyway, we have to clear the problematic state for the - * corresponding PE. However, we needn't do it if the PE - * is PHB associated. That means the PHB is having fatal - * errors and it needs reset. Further more, the AIB interface - * isn't reliable any more. - */ - if (!(pe->type & EEH_PE_PHB) && - (option == EEH_RESET_HOT || - option == EEH_RESET_FUNDAMENTAL)) { - ret = ioda_eeh_pe_clear(pe); - if (ret) - return -EIO; - } - - /* - * The rules applied to reset, either fundamental or hot reset: + * For PHB reset, we always have complete reset. For those PEs whose + * primary bus derived from root complex (root bus) or root port + * (usually bus#1), we apply hot or fundamental reset on the root port. + * For other PEs, we always have hot reset on the PE primary bus. * - * We always reset the direct upstream bridge of the PE. If the - * direct upstream bridge isn't root bridge, we always take hot - * reset no matter what option (fundamental or hot) is. Otherwise, - * we should do the reset according to the required option. + * Here, we have different design to pHyp, which always clear the + * frozen state during PE reset. However, the good idea here from + * benh is to keep frozen state before we get PE reset done completely + * (until BAR restore). With the frozen state, HW drops illegal IO + * or MMIO access, which can incur recrusive frozen PE during PE + * reset. The side effect is that EEH core has to clear the frozen + * state explicitly after BAR restore. */ if (pe->type & EEH_PE_PHB) { ret = ioda_eeh_phb_reset(hose, option); } else { bus = eeh_pe_bus_get(pe); - if (pci_is_root_bus(bus)) + if (pci_is_root_bus(bus) || + pci_is_root_bus(bus->parent)) ret = ioda_eeh_root_reset(hose, option); else - ret = ioda_eeh_bridge_reset(hose, bus->self, option); + ret = ioda_eeh_bridge_reset(bus->self, option); } return ret; @@ -639,22 +747,6 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose) } } -static int ioda_eeh_get_phb_pe(struct pci_controller *hose, - struct eeh_pe **pe) -{ - struct eeh_pe *phb_pe; - - phb_pe = eeh_phb_pe_get(hose); - if (!phb_pe) { - pr_warning("%s Can't find PE for PHB#%d\n", - __func__, hose->global_number); - return -EEXIST; - } - - *pe = phb_pe; - return 0; -} - static int ioda_eeh_get_pe(struct pci_controller *hose, u16 pe_no, struct eeh_pe **pe) { @@ -662,7 +754,8 @@ static int ioda_eeh_get_pe(struct pci_controller *hose, struct eeh_dev dev; /* Find the PHB PE */ - if (ioda_eeh_get_phb_pe(hose, &phb_pe)) + phb_pe = eeh_phb_pe_get(hose); + if (!phb_pe) return -EEXIST; /* Find the PE according to PE# */ @@ -690,6 +783,7 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) { struct pci_controller *hose; struct pnv_phb *phb; + struct eeh_pe *phb_pe; u64 frozen_pe_no; u16 err_type, severity; long rc; @@ -706,10 +800,12 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) list_for_each_entry(hose, &hose_list, list_node) { /* * If the subordinate PCI buses of the PHB has been - * removed, we needn't take care of it any more. + * removed or is exactly under error recovery, we + * needn't take care of it any more. */ phb = hose->private_data; - if (phb->eeh_state & PNV_EEH_STATE_REMOVED) + phb_pe = eeh_phb_pe_get(hose); + if (!phb_pe || (phb_pe->state & EEH_PE_ISOLATED)) continue; rc = opal_pci_next_error(phb->opal_id, @@ -742,12 +838,6 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) switch (err_type) { case OPAL_EEH_IOC_ERROR: if (severity == OPAL_EEH_SEV_IOC_DEAD) { - list_for_each_entry(hose, &hose_list, - list_node) { - phb = hose->private_data; - phb->eeh_state |= PNV_EEH_STATE_REMOVED; - } - pr_err("EEH: dead IOC detected\n"); ret = EEH_NEXT_ERR_DEAD_IOC; } else if (severity == OPAL_EEH_SEV_INF) { @@ -760,17 +850,12 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) break; case OPAL_EEH_PHB_ERROR: if (severity == OPAL_EEH_SEV_PHB_DEAD) { - if (ioda_eeh_get_phb_pe(hose, pe)) - break; - + *pe = phb_pe; pr_err("EEH: dead PHB#%x detected\n", hose->global_number); - phb->eeh_state |= PNV_EEH_STATE_REMOVED; ret = EEH_NEXT_ERR_DEAD_PHB; } else if (severity == OPAL_EEH_SEV_PHB_FENCED) { - if (ioda_eeh_get_phb_pe(hose, pe)) - break; - + *pe = phb_pe; pr_err("EEH: fenced PHB#%x detected\n", hose->global_number); ret = EEH_NEXT_ERR_FENCED_PHB; @@ -788,17 +873,21 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) * If we can't find the corresponding PE, the * PEEV / PEST would be messy. So we force an * fenced PHB so that it can be recovered. + * + * If the PE has been marked as isolated, that + * should have been removed permanently or in + * progress with recovery. We needn't report + * it again. */ if (ioda_eeh_get_pe(hose, frozen_pe_no, pe)) { - if (!ioda_eeh_get_phb_pe(hose, pe)) { - pr_err("EEH: Escalated fenced PHB#%x " - "detected for PE#%llx\n", - hose->global_number, - frozen_pe_no); - ret = EEH_NEXT_ERR_FENCED_PHB; - } else { - ret = EEH_NEXT_ERR_NONE; - } + *pe = phb_pe; + pr_err("EEH: Escalated fenced PHB#%x " + "detected for PE#%llx\n", + hose->global_number, + frozen_pe_no); + ret = EEH_NEXT_ERR_FENCED_PHB; + } else if ((*pe)->state & EEH_PE_ISOLATED) { + ret = EEH_NEXT_ERR_NONE; } else { pr_err("EEH: Frozen PE#%x on PHB#%x detected\n", (*pe)->addr, (*pe)->phb->global_number); diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index a59788e83b8b37..56a206f32f77e7 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -126,6 +126,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) edev->mode &= 0xFFFFFF00; if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) edev->mode |= EEH_DEV_BRIDGE; + edev->pcix_cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (pci_is_pcie(dev)) { edev->pcie_cap = pci_pcie_cap(dev); @@ -133,6 +134,9 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) edev->mode |= EEH_DEV_ROOT_PORT; else if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) edev->mode |= EEH_DEV_DS_PORT; + + edev->aer_cap = pci_find_ext_capability(dev, + PCI_EXT_CAP_ID_ERR); } edev->config_addr = ((dev->bus->number << 8) | dev->devfn); diff --git a/arch/powerpc/platforms/powernv/opal-flash.c b/arch/powerpc/platforms/powernv/opal-flash.c index dc487ff0470401..145a80bc535492 100644 --- a/arch/powerpc/platforms/powernv/opal-flash.c +++ b/arch/powerpc/platforms/powernv/opal-flash.c @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -290,11 +291,6 @@ static int opal_flash_update(int op) /* First entry address */ addr = __pa(list); - pr_alert("FLASH: Image is %u bytes\n", image_data.size); - pr_alert("FLASH: Image update requested\n"); - pr_alert("FLASH: Image will be updated during system reboot\n"); - pr_alert("FLASH: This will take several minutes. Do not power off!\n"); - flash: rc = opal_update_flash(addr); @@ -302,6 +298,47 @@ static int opal_flash_update(int op) return rc; } +/* Return CPUs to OPAL before starting FW update */ +static void flash_return_cpu(void *info) +{ + int cpu = smp_processor_id(); + + if (!cpu_online(cpu)) + return; + + /* Disable IRQ */ + hard_irq_disable(); + + /* Return the CPU to OPAL */ + opal_return_cpu(); +} + +/* This gets called just before system reboots */ +void opal_flash_term_callback(void) +{ + struct cpumask mask; + + if (update_flash_data.status != FLASH_IMG_READY) + return; + + pr_alert("FLASH: Flashing new firmware\n"); + pr_alert("FLASH: Image is %u bytes\n", image_data.size); + pr_alert("FLASH: Performing flash and reboot/shutdown\n"); + pr_alert("FLASH: This will take several minutes. Do not power off!\n"); + + /* Small delay to help getting the above message out */ + msleep(500); + + /* Return secondary CPUs to firmware */ + cpumask_copy(&mask, cpu_online_mask); + cpumask_clear_cpu(smp_processor_id(), &mask); + if (!cpumask_empty(&mask)) + smp_call_function_many(&mask, + flash_return_cpu, NULL, false); + /* Hard disable interrupts */ + hard_irq_disable(); +} + /* * Show candidate image status */ diff --git a/arch/powerpc/platforms/powernv/opal-takeover.S b/arch/powerpc/platforms/powernv/opal-takeover.S index 3cd262897c272c..11a3169ee58363 100644 --- a/arch/powerpc/platforms/powernv/opal-takeover.S +++ b/arch/powerpc/platforms/powernv/opal-takeover.S @@ -21,11 +21,13 @@ _GLOBAL(opal_query_takeover) mfcr r0 stw r0,8(r1) + stdu r1,-STACKFRAMESIZE(r1) std r3,STK_PARAM(R3)(r1) std r4,STK_PARAM(R4)(r1) li r3,H_HAL_TAKEOVER li r4,H_HAL_TAKEOVER_QUERY_MAGIC HVSC + addi r1,r1,STACKFRAMESIZE ld r10,STK_PARAM(R3)(r1) std r4,0(r10) ld r10,STK_PARAM(R4)(r1) diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index f531ffe35b3e05..b5ebc545a373c9 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -32,7 +32,7 @@ std r12,PACASAVEDMSR(r13); \ andc r12,r12,r0; \ mtmsrd r12,1; \ - LOAD_REG_ADDR(r0,.opal_return); \ + LOAD_REG_ADDR(r0,opal_return); \ mtlr r0; \ li r0,MSR_DR|MSR_IR|MSR_LE;\ andc r12,r12,r0; \ @@ -44,7 +44,7 @@ mtspr SPRN_HSRR0,r12; \ hrfid -_STATIC(opal_return) +opal_return: /* * Fixup endian on OPAL return... we should be able to simplify * this by instead converting the below trampoline to a set of diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 360ad80c754ce3..f343183add07c1 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -61,7 +61,7 @@ int __init early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data) { const void *basep, *entryp, *sizep; - unsigned long basesz, entrysz, runtimesz; + int basesz, entrysz, runtimesz; if (depth != 1 || strcmp(uname, "ibm,opal") != 0) return 0; @@ -77,11 +77,11 @@ int __init early_init_dt_scan_opal(unsigned long node, opal.entry = of_read_number(entryp, entrysz/4); opal.size = of_read_number(sizep, runtimesz/4); - pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%ld)\n", + pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%d)\n", opal.base, basep, basesz); - pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%ld)\n", + pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%d)\n", opal.entry, entryp, entrysz); - pr_debug("OPAL Entry = 0x%llx (sizep=%p runtimesz=%ld)\n", + pr_debug("OPAL Entry = 0x%llx (sizep=%p runtimesz=%d)\n", opal.size, sizep, runtimesz); powerpc_firmware_features |= FW_FEATURE_OPAL; @@ -102,7 +102,7 @@ int __init early_init_dt_scan_opal(unsigned long node, int __init early_init_dt_scan_recoverable_ranges(unsigned long node, const char *uname, int depth, void *data) { - unsigned long i, psize, size; + int i, psize, size; const __be32 *prop; if (depth != 1 || strcmp(uname, "ibm,opal") != 0) @@ -359,7 +359,7 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count) if ((be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_INPUT) == 0) return 0; len = cpu_to_be64(count); - rc = opal_console_read(vtermno, &len, buf); + rc = opal_console_read(vtermno, &len, buf); if (rc == OPAL_SUCCESS) return be64_to_cpu(len); return 0; diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 98824aa9917318..de19edeaa7a75f 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -663,15 +664,15 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, * errors, and on the first pass the data will be a relative * bus number, print that out instead. */ - tbl->it_busno = 0; pe->tce_inval_reg_phys = be64_to_cpup(swinvp); tbl->it_index = (unsigned long)ioremap(pe->tce_inval_reg_phys, 8); - tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE | - TCE_PCI_SWINV_PAIR; + tbl->it_type |= (TCE_PCI_SWINV_CREATE | + TCE_PCI_SWINV_FREE | + TCE_PCI_SWINV_PAIR); } iommu_init_table(tbl, phb->hose->node); - iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number); + iommu_register_group(tbl, phb->hose->global_number, pe->pe_number); if (pe->pdev) set_iommu_table_base_and_group(&pe->pdev->dev, tbl); @@ -793,14 +794,13 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, * errors, and on the first pass the data will be a relative * bus number, print that out instead. */ - tbl->it_busno = 0; pe->tce_inval_reg_phys = be64_to_cpup(swinvp); tbl->it_index = (unsigned long)ioremap(pe->tce_inval_reg_phys, 8); - tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE; + tbl->it_type |= (TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE); } iommu_init_table(tbl, phb->hose->node); - iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number); + iommu_register_group(tbl, phb->hose->global_number, pe->pe_number); if (pe->pdev) set_iommu_table_base_and_group(&pe->pdev->dev, tbl); @@ -1386,12 +1386,24 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, ppc_md.pcibios_fixup = pnv_pci_ioda_fixup; ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook; ppc_md.pcibios_window_alignment = pnv_pci_window_alignment; + ppc_md.pcibios_reset_secondary_bus = pnv_pci_reset_secondary_bus; pci_add_flags(PCI_REASSIGN_ALL_RSRC); /* Reset IODA tables to a clean state */ rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET); if (rc) pr_warning(" OPAL Error %ld performing IODA table reset !\n", rc); + + /* If we're running in kdump kerenl, the previous kerenl never + * shutdown PCI devices correctly. We already got IODA table + * cleaned out. So we have to issue PHB reset to stop all PCI + * transactions from previous kerenl. + */ + if (is_kdump_kernel()) { + pr_info(" Issue PHB reset ...\n"); + ioda_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL); + ioda_eeh_phb_reset(hose, OPAL_DEASSERT_RESET); + } } void __init pnv_pci_init_ioda2_phb(struct device_node *np) diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 8518817dcdfdc9..eefbfcc3fd8c40 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -131,65 +131,60 @@ static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose, int i; data = (struct OpalIoP7IOCPhbErrorData *)common; - pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n\n", + pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n", hose->global_number, common->version); if (data->brdgCtl) - pr_info(" brdgCtl: %08x\n", + pr_info("brdgCtl: %08x\n", data->brdgCtl); if (data->portStatusReg || data->rootCmplxStatus || data->busAgentStatus) - pr_info(" UtlSts: %08x %08x %08x\n", + pr_info("UtlSts: %08x %08x %08x\n", data->portStatusReg, data->rootCmplxStatus, data->busAgentStatus); if (data->deviceStatus || data->slotStatus || data->linkStatus || data->devCmdStatus || data->devSecStatus) - pr_info(" RootSts: %08x %08x %08x %08x %08x\n", + pr_info("RootSts: %08x %08x %08x %08x %08x\n", data->deviceStatus, data->slotStatus, data->linkStatus, data->devCmdStatus, data->devSecStatus); if (data->rootErrorStatus || data->uncorrErrorStatus || data->corrErrorStatus) - pr_info(" RootErrSts: %08x %08x %08x\n", + pr_info("RootErrSts: %08x %08x %08x\n", data->rootErrorStatus, data->uncorrErrorStatus, data->corrErrorStatus); if (data->tlpHdr1 || data->tlpHdr2 || data->tlpHdr3 || data->tlpHdr4) - pr_info(" RootErrLog: %08x %08x %08x %08x\n", + pr_info("RootErrLog: %08x %08x %08x %08x\n", data->tlpHdr1, data->tlpHdr2, data->tlpHdr3, data->tlpHdr4); if (data->sourceId || data->errorClass || data->correlator) - pr_info(" RootErrLog1: %08x %016llx %016llx\n", + pr_info("RootErrLog1: %08x %016llx %016llx\n", data->sourceId, data->errorClass, data->correlator); if (data->p7iocPlssr || data->p7iocCsr) - pr_info(" PhbSts: %016llx %016llx\n", + pr_info("PhbSts: %016llx %016llx\n", data->p7iocPlssr, data->p7iocCsr); - if (data->lemFir || data->lemErrorMask || - data->lemWOF) - pr_info(" Lem: %016llx %016llx %016llx\n", + if (data->lemFir) + pr_info("Lem: %016llx %016llx %016llx\n", data->lemFir, data->lemErrorMask, data->lemWOF); - if (data->phbErrorStatus || data->phbFirstErrorStatus || - data->phbErrorLog0 || data->phbErrorLog1) - pr_info(" PhbErr: %016llx %016llx %016llx %016llx\n", + if (data->phbErrorStatus) + pr_info("PhbErr: %016llx %016llx %016llx %016llx\n", data->phbErrorStatus, data->phbFirstErrorStatus, data->phbErrorLog0, data->phbErrorLog1); - if (data->mmioErrorStatus || data->mmioFirstErrorStatus || - data->mmioErrorLog0 || data->mmioErrorLog1) - pr_info(" OutErr: %016llx %016llx %016llx %016llx\n", + if (data->mmioErrorStatus) + pr_info("OutErr: %016llx %016llx %016llx %016llx\n", data->mmioErrorStatus, data->mmioFirstErrorStatus, data->mmioErrorLog0, data->mmioErrorLog1); - if (data->dma0ErrorStatus || data->dma0FirstErrorStatus || - data->dma0ErrorLog0 || data->dma0ErrorLog1) - pr_info(" InAErr: %016llx %016llx %016llx %016llx\n", + if (data->dma0ErrorStatus) + pr_info("InAErr: %016llx %016llx %016llx %016llx\n", data->dma0ErrorStatus, data->dma0FirstErrorStatus, data->dma0ErrorLog0, data->dma0ErrorLog1); - if (data->dma1ErrorStatus || data->dma1FirstErrorStatus || - data->dma1ErrorLog0 || data->dma1ErrorLog1) - pr_info(" InBErr: %016llx %016llx %016llx %016llx\n", + if (data->dma1ErrorStatus) + pr_info("InBErr: %016llx %016llx %016llx %016llx\n", data->dma1ErrorStatus, data->dma1FirstErrorStatus, data->dma1ErrorLog0, data->dma1ErrorLog1); @@ -198,7 +193,7 @@ static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose, (data->pestB[i] >> 63) == 0) continue; - pr_info(" PE[%3d] A/B: %016llx %016llx\n", + pr_info("PE[%3d] A/B: %016llx %016llx\n", i, data->pestA[i], data->pestB[i]); } } @@ -210,69 +205,63 @@ static void pnv_pci_dump_phb3_diag_data(struct pci_controller *hose, int i; data = (struct OpalIoPhb3ErrorData*)common; - pr_info("PHB3 PHB#%d Diag-data (Version: %d)\n\n", + pr_info("PHB3 PHB#%d Diag-data (Version: %d)\n", hose->global_number, common->version); if (data->brdgCtl) - pr_info(" brdgCtl: %08x\n", + pr_info("brdgCtl: %08x\n", data->brdgCtl); if (data->portStatusReg || data->rootCmplxStatus || data->busAgentStatus) - pr_info(" UtlSts: %08x %08x %08x\n", + pr_info("UtlSts: %08x %08x %08x\n", data->portStatusReg, data->rootCmplxStatus, data->busAgentStatus); if (data->deviceStatus || data->slotStatus || data->linkStatus || data->devCmdStatus || data->devSecStatus) - pr_info(" RootSts: %08x %08x %08x %08x %08x\n", + pr_info("RootSts: %08x %08x %08x %08x %08x\n", data->deviceStatus, data->slotStatus, data->linkStatus, data->devCmdStatus, data->devSecStatus); if (data->rootErrorStatus || data->uncorrErrorStatus || data->corrErrorStatus) - pr_info(" RootErrSts: %08x %08x %08x\n", + pr_info("RootErrSts: %08x %08x %08x\n", data->rootErrorStatus, data->uncorrErrorStatus, data->corrErrorStatus); if (data->tlpHdr1 || data->tlpHdr2 || data->tlpHdr3 || data->tlpHdr4) - pr_info(" RootErrLog: %08x %08x %08x %08x\n", + pr_info("RootErrLog: %08x %08x %08x %08x\n", data->tlpHdr1, data->tlpHdr2, data->tlpHdr3, data->tlpHdr4); if (data->sourceId || data->errorClass || data->correlator) - pr_info(" RootErrLog1: %08x %016llx %016llx\n", + pr_info("RootErrLog1: %08x %016llx %016llx\n", data->sourceId, data->errorClass, data->correlator); - if (data->nFir || data->nFirMask || - data->nFirWOF) - pr_info(" nFir: %016llx %016llx %016llx\n", + if (data->nFir) + pr_info("nFir: %016llx %016llx %016llx\n", data->nFir, data->nFirMask, data->nFirWOF); if (data->phbPlssr || data->phbCsr) - pr_info(" PhbSts: %016llx %016llx\n", + pr_info("PhbSts: %016llx %016llx\n", data->phbPlssr, data->phbCsr); - if (data->lemFir || data->lemErrorMask || - data->lemWOF) - pr_info(" Lem: %016llx %016llx %016llx\n", + if (data->lemFir) + pr_info("Lem: %016llx %016llx %016llx\n", data->lemFir, data->lemErrorMask, data->lemWOF); - if (data->phbErrorStatus || data->phbFirstErrorStatus || - data->phbErrorLog0 || data->phbErrorLog1) - pr_info(" PhbErr: %016llx %016llx %016llx %016llx\n", + if (data->phbErrorStatus) + pr_info("PhbErr: %016llx %016llx %016llx %016llx\n", data->phbErrorStatus, data->phbFirstErrorStatus, data->phbErrorLog0, data->phbErrorLog1); - if (data->mmioErrorStatus || data->mmioFirstErrorStatus || - data->mmioErrorLog0 || data->mmioErrorLog1) - pr_info(" OutErr: %016llx %016llx %016llx %016llx\n", + if (data->mmioErrorStatus) + pr_info("OutErr: %016llx %016llx %016llx %016llx\n", data->mmioErrorStatus, data->mmioFirstErrorStatus, data->mmioErrorLog0, data->mmioErrorLog1); - if (data->dma0ErrorStatus || data->dma0FirstErrorStatus || - data->dma0ErrorLog0 || data->dma0ErrorLog1) - pr_info(" InAErr: %016llx %016llx %016llx %016llx\n", + if (data->dma0ErrorStatus) + pr_info("InAErr: %016llx %016llx %016llx %016llx\n", data->dma0ErrorStatus, data->dma0FirstErrorStatus, data->dma0ErrorLog0, data->dma0ErrorLog1); - if (data->dma1ErrorStatus || data->dma1FirstErrorStatus || - data->dma1ErrorLog0 || data->dma1ErrorLog1) - pr_info(" InBErr: %016llx %016llx %016llx %016llx\n", + if (data->dma1ErrorStatus) + pr_info("InBErr: %016llx %016llx %016llx %016llx\n", data->dma1ErrorStatus, data->dma1FirstErrorStatus, data->dma1ErrorLog0, data->dma1ErrorLog1); @@ -281,7 +270,7 @@ static void pnv_pci_dump_phb3_diag_data(struct pci_controller *hose, (data->pestB[i] >> 63) == 0) continue; - pr_info(" PE[%3d] A/B: %016llx %016llx\n", + pr_info("PE[%3d] A/B: %016llx %016llx\n", i, data->pestA[i], data->pestB[i]); } } @@ -384,9 +373,6 @@ int pnv_pci_cfg_read(struct device_node *dn, struct pci_dn *pdn = PCI_DN(dn); struct pnv_phb *phb = pdn->phb->private_data; u32 bdfn = (pdn->busno << 8) | pdn->devfn; -#ifdef CONFIG_EEH - struct eeh_pe *phb_pe = NULL; -#endif s64 rc; switch (size) { @@ -412,31 +398,9 @@ int pnv_pci_cfg_read(struct device_node *dn, default: return PCIBIOS_FUNC_NOT_SUPPORTED; } + cfg_dbg("%s: bus: %x devfn: %x +%x/%x -> %08x\n", __func__, pdn->busno, pdn->devfn, where, size, *val); - - /* - * Check if the specified PE has been put into frozen - * state. On the other hand, we needn't do that while - * the PHB has been put into frozen state because of - * PHB-fatal errors. - */ -#ifdef CONFIG_EEH - phb_pe = eeh_phb_pe_get(pdn->phb); - if (phb_pe && (phb_pe->state & EEH_PE_ISOLATED)) - return PCIBIOS_SUCCESSFUL; - - if (phb->eeh_state & PNV_EEH_STATE_ENABLED) { - if (*val == EEH_IO_ERROR_VALUE(size) && - eeh_dev_check_failure(of_node_to_eeh_dev(dn))) - return PCIBIOS_DEVICE_NOT_FOUND; - } else { - pnv_pci_config_check_eeh(phb, dn); - } -#else - pnv_pci_config_check_eeh(phb, dn); -#endif - return PCIBIOS_SUCCESSFUL; } @@ -463,33 +427,74 @@ int pnv_pci_cfg_write(struct device_node *dn, return PCIBIOS_FUNC_NOT_SUPPORTED; } - /* Check if the PHB got frozen due to an error (no response) */ -#ifdef CONFIG_EEH - if (!(phb->eeh_state & PNV_EEH_STATE_ENABLED)) - pnv_pci_config_check_eeh(phb, dn); -#else - pnv_pci_config_check_eeh(phb, dn); -#endif - return PCIBIOS_SUCCESSFUL; } +#if CONFIG_EEH +static bool pnv_pci_cfg_check(struct pci_controller *hose, + struct device_node *dn) +{ + struct eeh_dev *edev = NULL; + struct pnv_phb *phb = hose->private_data; + + /* EEH not enabled ? */ + if (!(phb->flags & PNV_PHB_FLAG_EEH)) + return true; + + /* PE reset or device removed ? */ + edev = of_node_to_eeh_dev(dn); + if (edev) { + if (edev->pe && + (edev->pe->state & EEH_PE_RESET)) + return false; + + if (edev->mode & EEH_DEV_REMOVED) + return false; + } + + return true; +} +#else +static inline pnv_pci_cfg_check(struct pci_controller *hose, + struct device_node *dn) +{ + return true; +} +#endif /* CONFIG_EEH */ + static int pnv_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { struct device_node *dn, *busdn = pci_bus_to_OF_node(bus); struct pci_dn *pdn; + struct pnv_phb *phb; + bool found = false; + int ret; + *val = 0xFFFFFFFF; for (dn = busdn->child; dn; dn = dn->sibling) { pdn = PCI_DN(dn); - if (pdn && pdn->devfn == devfn) - return pnv_pci_cfg_read(dn, where, size, val); + if (pdn && pdn->devfn == devfn) { + phb = pdn->phb->private_data; + found = true; + break; + } } - *val = 0xFFFFFFFF; - return PCIBIOS_DEVICE_NOT_FOUND; + if (!found || !pnv_pci_cfg_check(pdn->phb, dn)) + return PCIBIOS_DEVICE_NOT_FOUND; + ret = pnv_pci_cfg_read(dn, where, size, val); + if (phb->flags & PNV_PHB_FLAG_EEH) { + if (*val == EEH_IO_ERROR_VALUE(size) && + eeh_dev_check_failure(of_node_to_eeh_dev(dn))) + return PCIBIOS_DEVICE_NOT_FOUND; + } else { + pnv_pci_config_check_eeh(phb, dn); + } + + return ret; } static int pnv_pci_write_config(struct pci_bus *bus, @@ -498,14 +503,27 @@ static int pnv_pci_write_config(struct pci_bus *bus, { struct device_node *dn, *busdn = pci_bus_to_OF_node(bus); struct pci_dn *pdn; + struct pnv_phb *phb; + bool found = false; + int ret; for (dn = busdn->child; dn; dn = dn->sibling) { pdn = PCI_DN(dn); - if (pdn && pdn->devfn == devfn) - return pnv_pci_cfg_write(dn, where, size, val); + if (pdn && pdn->devfn == devfn) { + phb = pdn->phb->private_data; + found = true; + break; + } } - return PCIBIOS_DEVICE_NOT_FOUND; + if (!found || !pnv_pci_cfg_check(pdn->phb, dn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + ret = pnv_pci_cfg_write(dn, where, size, val); + if (!(phb->flags & PNV_PHB_FLAG_EEH)) + pnv_pci_config_check_eeh(phb, dn); + + return ret; } struct pci_ops pnv_pci_ops = { diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index cde169442775c1..676232c3432814 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -81,28 +81,27 @@ struct pnv_eeh_ops { int (*configure_bridge)(struct eeh_pe *pe); int (*next_error)(struct eeh_pe **pe); }; - -#define PNV_EEH_STATE_ENABLED (1 << 0) /* EEH enabled */ -#define PNV_EEH_STATE_REMOVED (1 << 1) /* PHB removed */ - #endif /* CONFIG_EEH */ +#define PNV_PHB_FLAG_EEH (1 << 0) + struct pnv_phb { struct pci_controller *hose; enum pnv_phb_type type; enum pnv_phb_model model; u64 hub_id; u64 opal_id; + int flags; void __iomem *regs; int initialized; spinlock_t lock; #ifdef CONFIG_EEH struct pnv_eeh_ops *eeh_ops; - int eeh_state; #endif #ifdef CONFIG_DEBUG_FS + int has_dbgfs; struct dentry *dbgfs; #endif @@ -205,5 +204,7 @@ extern void pnv_pci_init_ioda_hub(struct device_node *np); extern void pnv_pci_init_ioda2_phb(struct device_node *np); extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl, __be64 *startp, __be64 *endp, bool rm); +extern void pnv_pci_reset_secondary_bus(struct pci_dev *dev); +extern int ioda_eeh_phb_reset(struct pci_controller *hose, int option); #endif /* __POWERNV_PCI_H */ diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 8723d32632f55b..865aab40ded700 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -98,11 +99,32 @@ static void pnv_show_cpuinfo(struct seq_file *m) of_node_put(root); } +static void pnv_prepare_going_down(void) +{ + /* + * Disable all notifiers from OPAL, we can't + * service interrupts anymore anyway + */ + opal_notifier_disable(); + + /* Soft disable interrupts */ + local_irq_disable(); + + /* + * Return secondary CPUs to firwmare if a flash update + * is pending otherwise we will get all sort of error + * messages about CPU being stuck etc.. This will also + * have the side effect of hard disabling interrupts so + * past this point, the kernel is effectively dead. + */ + opal_flash_term_callback(); +} + static void __noreturn pnv_restart(char *cmd) { long rc = OPAL_BUSY; - opal_notifier_disable(); + pnv_prepare_going_down(); while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_cec_reboot(); @@ -119,7 +141,7 @@ static void __noreturn pnv_power_off(void) { long rc = OPAL_BUSY; - opal_notifier_disable(); + pnv_prepare_going_down(); while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_cec_power_down(0); @@ -269,6 +291,25 @@ static int __init pnv_probe(void) return 1; } +/* + * Returns the cpu frequency for 'cpu' in Hz. This is used by + * /proc/cpuinfo + */ +unsigned long pnv_get_proc_freq(unsigned int cpu) +{ + unsigned long ret_freq; + + ret_freq = cpufreq_quick_get(cpu) * 1000ul; + + /* + * If the backend cpufreq driver does not exist, + * then fallback to old way of reporting the clockrate. + */ + if (!ret_freq) + ret_freq = ppc_proc_freq; + return ret_freq; +} + define_machine(powernv) { .name = "PowerNV", .probe = pnv_probe, @@ -276,6 +317,7 @@ define_machine(powernv) { .setup_arch = pnv_setup_arch, .init_IRQ = pnv_init_IRQ, .show_cpuinfo = pnv_show_cpuinfo, + .get_proc_freq = pnv_get_proc_freq, .progress = pnv_progress, .machine_shutdown = pnv_shutdown, .power_save = power7_idle, diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index bf5fcd452168c6..1601a1ea02c432 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "powernv.h" @@ -50,8 +51,8 @@ static void pnv_smp_setup_cpu(int cpu) int pnv_smp_kick_cpu(int nr) { unsigned int pcpu = get_hard_smp_processor_id(nr); - unsigned long start_here = __pa(*((unsigned long *) - generic_secondary_smp_init)); + unsigned long start_here = + __pa(ppc_function_entry(generic_secondary_smp_init)); long rc; BUG_ON(nr < 0 || nr >= NR_CPUS); diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index 8a8f0472d98fd0..0bec0c02c5e718 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -175,6 +175,36 @@ static int pseries_eeh_find_cap(struct device_node *dn, int cap) return 0; } +static int pseries_eeh_find_ecap(struct device_node *dn, int cap) +{ + struct pci_dn *pdn = PCI_DN(dn); + struct eeh_dev *edev = of_node_to_eeh_dev(dn); + u32 header; + int pos = 256; + int ttl = (4096 - 256) / 8; + + if (!edev || !edev->pcie_cap) + return 0; + if (rtas_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL) + return 0; + else if (!header) + return 0; + + while (ttl-- > 0) { + if (PCI_EXT_CAP_ID(header) == cap && pos) + return pos; + + pos = PCI_EXT_CAP_NEXT(header); + if (pos < 256) + break; + + if (rtas_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL) + break; + } + + return 0; +} + /** * pseries_eeh_of_probe - EEH probe on the given device * @dn: OF node @@ -220,7 +250,9 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) * or PCIe switch downstream port. */ edev->class_code = class_code; + edev->pcix_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_PCIX); edev->pcie_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_EXP); + edev->aer_cap = pseries_eeh_find_ecap(dn, PCI_EXT_CAP_ID_ERR); edev->mode &= 0xFFFFFF00; if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) { edev->mode |= EEH_DEV_BRIDGE; @@ -464,6 +496,7 @@ static int pseries_eeh_get_state(struct eeh_pe *pe, int *state) } else { result = EEH_STATE_NOT_SUPPORT; } + break; default: result = EEH_STATE_NOT_SUPPORT; } @@ -499,11 +532,19 @@ static int pseries_eeh_reset(struct eeh_pe *pe, int option) /* If fundamental-reset not supported, try hot-reset */ if (option == EEH_RESET_FUNDAMENTAL && ret == -8) { + option = EEH_RESET_HOT; ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, config_addr, BUID_HI(pe->phb->buid), - BUID_LO(pe->phb->buid), EEH_RESET_HOT); + BUID_LO(pe->phb->buid), option); } + /* We need reset hold or settlement delay */ + if (option == EEH_RESET_FUNDAMENTAL || + option == EEH_RESET_HOT) + msleep(EEH_PE_RST_HOLD_TIME); + else + msleep(EEH_PE_RST_SETTLE_TIME); + return ret; } diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S index 444fe7759e5509..7891a86066e82d 100644 --- a/arch/powerpc/platforms/pseries/hvCall.S +++ b/arch/powerpc/platforms/pseries/hvCall.S @@ -49,7 +49,7 @@ END_FTR_SECTION(0, 1); \ std r0,16(r1); \ addi r4,r1,STK_PARAM(FIRST_REG); \ stdu r1,-STACK_FRAME_OVERHEAD(r1); \ - bl .__trace_hcall_entry; \ + bl __trace_hcall_entry; \ addi r1,r1,STACK_FRAME_OVERHEAD; \ ld r0,16(r1); \ ld r3,STK_PARAM(R3)(r1); \ @@ -83,7 +83,7 @@ END_FTR_SECTION(0, 1); \ mr r3,r6; \ std r0,16(r1); \ stdu r1,-STACK_FRAME_OVERHEAD(r1); \ - bl .__trace_hcall_exit; \ + bl __trace_hcall_exit; \ addi r1,r1,STACK_FRAME_OVERHEAD; \ ld r0,16(r1); \ ld r3,STK_PARAM(R3)(r1); \ diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 2db8cc691bf49d..ef7779cfe3716c 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -510,7 +510,11 @@ static void __init pSeries_setup_arch(void) static int __init pSeries_init_panel(void) { /* Manually leave the kernel version on the panel. */ +#ifdef __BIG_ENDIAN__ ppc_md.progress("Linux ppc64\n", 0); +#else + ppc_md.progress("Linux ppc64le\n", 0); +#endif ppc_md.progress(init_utsname()->version, 0); return 0; @@ -665,7 +669,7 @@ static int __init pseries_probe_fw_features(unsigned long node, void *data) { const char *prop; - unsigned long len; + int len; static int hypertas_found; static int vec5_found; @@ -698,7 +702,7 @@ static int __init pseries_probe_fw_features(unsigned long node, static int __init pSeries_probe(void) { unsigned long root = of_get_flat_dt_root(); - char *dtype = of_get_flat_dt_prop(root, "device_type", NULL); + const char *dtype = of_get_flat_dt_prop(root, "device_type", NULL); if (dtype == NULL) return 0; diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 24f58cb0a543ec..a3555b10c1a54d 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "pseries.h" #include "offline_states.h" @@ -96,8 +97,8 @@ int smp_query_cpu_stopped(unsigned int pcpu) static inline int smp_startup_cpu(unsigned int lcpu) { int status; - unsigned long start_here = __pa((u32)*((unsigned long *) - generic_secondary_smp_init)); + unsigned long start_here = + __pa(ppc_function_entry(generic_secondary_smp_init)); unsigned int pcpu; int start_cpu; diff --git a/arch/powerpc/platforms/wsp/scom_smp.c b/arch/powerpc/platforms/wsp/scom_smp.c index 268bc899c1f716..8c79ce016cf10a 100644 --- a/arch/powerpc/platforms/wsp/scom_smp.c +++ b/arch/powerpc/platforms/wsp/scom_smp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "wsp.h" @@ -405,7 +406,7 @@ int a2_scom_startup_cpu(unsigned int lcpu, int thr_idx, struct device_node *np) goto fail; } - start_here = *(unsigned long *)(core_setup ? generic_secondary_smp_init + start_here = ppc_function_entry(core_setup ? generic_secondary_smp_init : generic_secondary_thread_init); pr_devel("CPU%d entry point at 0x%lx...\n", lcpu, start_here); diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 7baa70d6dc016c..a19332a3871551 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -7,6 +7,12 @@ config PPC4xx_PCI_EXPRESS depends on PCI && 4xx default n +config PPC4xx_HSTA_MSI + bool + depends on PCI_MSI + depends on PCI && 4xx + default n + config PPC4xx_MSI bool depends on PCI_MSI diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index afbcc37aa09455..f7cb2a1b01fa05 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_OF_RTC) += of_rtc.o ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_4xx) += ppc4xx_pci.o endif +obj-$(CONFIG_PPC4xx_HSTA_MSI) += ppc4xx_hsta_msi.o obj-$(CONFIG_PPC4xx_MSI) += ppc4xx_msi.o obj-$(CONFIG_PPC4xx_CPM) += ppc4xx_cpm.o obj-$(CONFIG_PPC4xx_GPIO) += ppc4xx_gpio.o diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c new file mode 100644 index 00000000000000..11c888416f0a88 --- /dev/null +++ b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c @@ -0,0 +1,215 @@ +/* + * MSI support for PPC4xx SoCs using High Speed Transfer Assist (HSTA) for + * generation of the interrupt. + * + * Copyright © 2013 Alistair Popple IBM 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct ppc4xx_hsta_msi { + struct device *dev; + + /* The ioremapped HSTA MSI IO space */ + u32 __iomem *data; + + /* Physical address of HSTA MSI IO space */ + u64 address; + struct msi_bitmap bmp; + + /* An array mapping offsets to hardware IRQs */ + int *irq_map; + + /* Number of hwirqs supported */ + int irq_count; +}; +static struct ppc4xx_hsta_msi ppc4xx_hsta_msi; + +static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +{ + struct msi_msg msg; + struct msi_desc *entry; + int irq, hwirq; + u64 addr; + + list_for_each_entry(entry, &dev->msi_list, list) { + irq = msi_bitmap_alloc_hwirqs(&ppc4xx_hsta_msi.bmp, 1); + if (irq < 0) { + pr_debug("%s: Failed to allocate msi interrupt\n", + __func__); + return irq; + } + + hwirq = ppc4xx_hsta_msi.irq_map[irq]; + if (hwirq == NO_IRQ) { + pr_err("%s: Failed mapping irq %d\n", __func__, irq); + return -EINVAL; + } + + /* + * HSTA generates interrupts on writes to 128-bit aligned + * addresses. + */ + addr = ppc4xx_hsta_msi.address + irq*0x10; + msg.address_hi = upper_32_bits(addr); + msg.address_lo = lower_32_bits(addr); + + /* Data is not used by the HSTA. */ + msg.data = 0; + + pr_debug("%s: Setup irq %d (0x%0llx)\n", __func__, hwirq, + (((u64) msg.address_hi) << 32) | msg.address_lo); + + if (irq_set_msi_desc(hwirq, entry)) { + pr_err( + "%s: Invalid hwirq %d specified in device tree\n", + __func__, hwirq); + msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1); + return -EINVAL; + } + write_msi_msg(hwirq, &msg); + } + + return 0; +} + +static int hsta_find_hwirq_offset(int hwirq) +{ + int irq; + + /* Find the offset given the hwirq */ + for (irq = 0; irq < ppc4xx_hsta_msi.irq_count; irq++) + if (ppc4xx_hsta_msi.irq_map[irq] == hwirq) + return irq; + + return -EINVAL; +} + +static void hsta_teardown_msi_irqs(struct pci_dev *dev) +{ + struct msi_desc *entry; + int irq; + + list_for_each_entry(entry, &dev->msi_list, list) { + if (entry->irq == NO_IRQ) + continue; + + irq = hsta_find_hwirq_offset(entry->irq); + + /* entry->irq should always be in irq_map */ + BUG_ON(irq < 0); + irq_set_msi_desc(entry->irq, NULL); + msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1); + pr_debug("%s: Teardown IRQ %u (index %u)\n", __func__, + entry->irq, irq); + } +} + +static int hsta_msi_check_device(struct pci_dev *pdev, int nvec, int type) +{ + /* We don't support MSI-X */ + if (type == PCI_CAP_ID_MSIX) { + pr_debug("%s: MSI-X not supported.\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int hsta_msi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *mem; + int irq, ret, irq_count; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (IS_ERR(mem)) { + dev_err(dev, "Unable to get mmio space\n"); + return -EINVAL; + } + + irq_count = of_irq_count(dev->of_node); + if (!irq_count) { + dev_err(dev, "Unable to find IRQ range\n"); + return -EINVAL; + } + + ppc4xx_hsta_msi.dev = dev; + ppc4xx_hsta_msi.address = mem->start; + ppc4xx_hsta_msi.data = ioremap(mem->start, resource_size(mem)); + ppc4xx_hsta_msi.irq_count = irq_count; + if (IS_ERR(ppc4xx_hsta_msi.data)) { + dev_err(dev, "Unable to map memory\n"); + return -ENOMEM; + } + + ret = msi_bitmap_alloc(&ppc4xx_hsta_msi.bmp, irq_count, dev->of_node); + if (ret) + goto out; + + ppc4xx_hsta_msi.irq_map = kmalloc(sizeof(int) * irq_count, GFP_KERNEL); + if (IS_ERR(ppc4xx_hsta_msi.irq_map)) { + ret = -ENOMEM; + goto out1; + } + + /* Setup a mapping from irq offsets to hardware irq numbers */ + for (irq = 0; irq < irq_count; irq++) { + ppc4xx_hsta_msi.irq_map[irq] = + irq_of_parse_and_map(dev->of_node, irq); + if (ppc4xx_hsta_msi.irq_map[irq] == NO_IRQ) { + dev_err(dev, "Unable to map IRQ\n"); + ret = -EINVAL; + goto out2; + } + } + + ppc_md.setup_msi_irqs = hsta_setup_msi_irqs; + ppc_md.teardown_msi_irqs = hsta_teardown_msi_irqs; + ppc_md.msi_check_device = hsta_msi_check_device; + return 0; + +out2: + kfree(ppc4xx_hsta_msi.irq_map); + +out1: + msi_bitmap_free(&ppc4xx_hsta_msi.bmp); + +out: + iounmap(ppc4xx_hsta_msi.data); + return ret; +} + +static const struct of_device_id hsta_msi_ids[] = { + { + .compatible = "ibm,hsta-msi", + }, + {} +}; + +static struct platform_driver hsta_msi_driver = { + .probe = hsta_msi_probe, + .driver = { + .name = "hsta-msi", + .owner = THIS_MODULE, + .of_match_table = hsta_msi_ids, + }, +}; + +static int hsta_msi_init(void) +{ + return platform_driver_register(&hsta_msi_driver); +} +subsys_initcall(hsta_msi_init); diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 4914fd3f41eca7..df6e2fc4ff926c 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -176,8 +176,12 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, return -ENXIO; } - /* Check that we are fully contained within 32 bits space */ - if (res->end > 0xffffffff) { + /* Check that we are fully contained within 32 bits space if we are not + * running on a 460sx or 476fpe which have 64 bit bus addresses. + */ + if (res->end > 0xffffffff && + !(of_device_is_compatible(hose->dn, "ibm,plb-pciex-460sx") + || of_device_is_compatible(hose->dn, "ibm,plb-pciex-476fpe"))) { printk(KERN_ERR "%s: dma-ranges outside of 32 bits space\n", hose->dn->full_name); return -ENXIO; @@ -1440,7 +1444,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np) ppc4xx_pciex_hwops = &ppc405ex_pcie_hwops; #endif #ifdef CONFIG_476FPE - if (of_device_is_compatible(np, "ibm,plb-pciex-476fpe")) + if (of_device_is_compatible(np, "ibm,plb-pciex-476fpe") + || of_device_is_compatible(np, "ibm,plb-pciex-476gtr")) ppc4xx_pciex_hwops = &ppc_476fpe_pcie_hwops; #endif if (ppc4xx_pciex_hwops == NULL) { @@ -1751,7 +1756,10 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | DCRO_PEGPL_460SX_OMR1MSKL_UOT | DCRO_PEGPL_OMRxMSKL_VAL); - else if (of_device_is_compatible(port->node, "ibm,plb-pciex-476fpe")) + else if (of_device_is_compatible( + port->node, "ibm,plb-pciex-476fpe") || + of_device_is_compatible( + port->node, "ibm,plb-pciex-476gtr")) dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | DCRO_PEGPL_476FPE_OMR1MSKL_UOT | DCRO_PEGPL_OMRxMSKL_VAL); @@ -1881,7 +1889,10 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, sa |= PCI_BASE_ADDRESS_MEM_PREFETCH; if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx") || - of_device_is_compatible(port->node, "ibm,plb-pciex-476fpe")) + of_device_is_compatible( + port->node, "ibm,plb-pciex-476fpe") || + of_device_is_compatible( + port->node, "ibm,plb-pciex-476gtr")) sa |= PCI_BASE_ADDRESS_MEM_TYPE_64; out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 54cb543470d023..f357d8e7ddce4c 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -60,7 +60,6 @@ config PCI_QUIRKS config S390 def_bool y - select ARCH_DISCARD_MEMBLOCK select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS select ARCH_HAVE_NMI_SAFE_CMPXCHG @@ -130,6 +129,7 @@ config S390 select HAVE_KVM if 64BIT select HAVE_MEMBLOCK select HAVE_MEMBLOCK_NODE_MAP + select HAVE_MEMBLOCK_PHYS_MAP select HAVE_MOD_ARCH_SPECIFIC select HAVE_OPROFILE select HAVE_PERF_EVENTS @@ -139,6 +139,7 @@ config S390 select HAVE_VIRT_CPU_ACCOUNTING select KTIME_SCALAR if 32BIT select MODULES_USE_ELF_RELA + select NO_BOOTMEM select OLD_SIGACTION select OLD_SIGSUSPEND3 select SYSCTL_EXCEPTION_TRACE @@ -330,6 +331,16 @@ config SYSVIPC_COMPAT config KEYS_COMPAT def_bool y if COMPAT && KEYS +config S390_TICKET_SPINLOCK + bool "Use ticket spinlocks" + depends on S390 && SMP + default n + help + This enables support for ticket spinlocks. Ticket spinlocks + are more fair by means that waiting CPUs will get the lock + in the order they tried to obtain it. + The tradeoff is more complex code that could impact performance. + config SMP def_bool y prompt "Symmetric multi-processing support" @@ -593,21 +604,14 @@ config CRASH_DUMP bool "kernel crash dumps" depends on 64BIT && SMP select KEXEC - select ZFCPDUMP help Generate crash dump after being started by kexec. Crash dump kernels are loaded in the main kernel with kexec-tools into a specially reserved region and then later executed after a crash by kdump/kexec. - For more details see Documentation/kdump/kdump.txt - -config ZFCPDUMP - def_bool n - prompt "zfcpdump support" - depends on 64BIT && SMP - help - Select this option if you want to build an zfcpdump enabled kernel. Refer to for more details on this. + This option also enables s390 zfcpdump. + See also endmenu diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c index 42be537431338b..edcf2a70694204 100644 --- a/arch/s390/appldata/appldata_mem.c +++ b/arch/s390/appldata/appldata_mem.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "appldata.h" diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index cf3c0089bef253..23223cd63e5481 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -820,6 +820,9 @@ static int ctr_aes_crypt(struct blkcipher_desc *desc, long func, else memcpy(walk->iv, ctrptr, AES_BLOCK_SIZE); spin_unlock(&ctrblk_lock); + } else { + if (!nbytes) + memcpy(walk->iv, ctrptr, AES_BLOCK_SIZE); } /* * final block may be < AES_BLOCK_SIZE, copy only nbytes diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index 0a5aac8a9412b6..7acb77f7ef1ada 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -429,6 +429,9 @@ static int ctr_desall_crypt(struct blkcipher_desc *desc, long func, else memcpy(walk->iv, ctrptr, DES_BLOCK_SIZE); spin_unlock(&ctrblk_lock); + } else { + if (!nbytes) + memcpy(walk->iv, ctrptr, DES_BLOCK_SIZE); } /* final block may be < DES_BLOCK_SIZE, copy only nbytes */ if (nbytes) { diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h index 1d4706114a454a..fa934fe080c17b 100644 --- a/arch/s390/include/asm/atomic.h +++ b/arch/s390/include/asm/atomic.h @@ -412,9 +412,4 @@ static inline long long atomic64_dec_if_positive(atomic64_t *v) #define atomic64_dec_and_test(_v) (atomic64_sub_return(1, _v) == 0) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) -#define smp_mb__before_atomic_dec() smp_mb() -#define smp_mb__after_atomic_dec() smp_mb() -#define smp_mb__before_atomic_inc() smp_mb() -#define smp_mb__after_atomic_inc() smp_mb() - #endif /* __ARCH_S390_ATOMIC__ */ diff --git a/arch/s390/include/asm/barrier.h b/arch/s390/include/asm/barrier.h index 578680f6207acb..19ff956b752baf 100644 --- a/arch/s390/include/asm/barrier.h +++ b/arch/s390/include/asm/barrier.h @@ -27,8 +27,9 @@ #define smp_rmb() rmb() #define smp_wmb() wmb() #define smp_read_barrier_depends() read_barrier_depends() -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() + +#define smp_mb__before_atomic() smp_mb() +#define smp_mb__after_atomic() smp_mb() #define set_mb(var, value) do { var = value; mb(); } while (0) diff --git a/arch/s390/include/asm/ccwgroup.h b/arch/s390/include/asm/ccwgroup.h index ebc2913f9ee0bd..057ce0ca6377dc 100644 --- a/arch/s390/include/asm/ccwgroup.h +++ b/arch/s390/include/asm/ccwgroup.h @@ -10,6 +10,8 @@ struct ccw_driver; * @count: number of attached slave devices * @dev: embedded device structure * @cdev: variable number of slave devices, allocated as needed + * @ungroup_work: work to be done when a ccwgroup notifier has action + * type %BUS_NOTIFY_UNBIND_DRIVER */ struct ccwgroup_device { enum { diff --git a/arch/s390/include/asm/ctl_reg.h b/arch/s390/include/asm/ctl_reg.h index 4e63f1a13600a4..31ab9f346d7e37 100644 --- a/arch/s390/include/asm/ctl_reg.h +++ b/arch/s390/include/asm/ctl_reg.h @@ -57,6 +57,20 @@ static inline void __ctl_clear_bit(unsigned int cr, unsigned int bit) void smp_ctl_set_bit(int cr, int bit); void smp_ctl_clear_bit(int cr, int bit); +union ctlreg0 { + unsigned long val; + struct { +#ifdef CONFIG_64BIT + unsigned long : 32; +#endif + unsigned long : 3; + unsigned long lap : 1; /* Low-address-protection control */ + unsigned long : 4; + unsigned long edat : 1; /* Enhanced-DAT-enablement control */ + unsigned long : 23; + }; +}; + #ifdef CONFIG_SMP # define ctl_set_bit(cr, bit) smp_ctl_set_bit(cr, bit) # define ctl_clear_bit(cr, bit) smp_ctl_clear_bit(cr, bit) diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h index 69cf5b5eddc95d..a4811aa0304d03 100644 --- a/arch/s390/include/asm/futex.h +++ b/arch/s390/include/asm/futex.h @@ -29,7 +29,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) int cmparg = (encoded_op << 20) >> 20; int oldval = 0, newval, ret; - update_primary_asce(current); + load_kernel_asce(); if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; @@ -79,7 +79,7 @@ static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, { int ret; - update_primary_asce(current); + load_kernel_asce(); asm volatile( " sacf 256\n" "0: cs %1,%4,0(%5)\n" diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 154b60089be996..f0a1dc5e5d1fd5 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -39,9 +39,17 @@ struct sca_entry { __u64 reserved2[2]; } __attribute__((packed)); +union ipte_control { + unsigned long val; + struct { + unsigned long k : 1; + unsigned long kh : 31; + unsigned long kg : 32; + }; +}; struct sca_block { - __u64 ipte_control; + union ipte_control ipte_control; __u64 reserved[5]; __u64 mcn; __u64 reserved2; @@ -64,6 +72,7 @@ struct sca_block { #define CPUSTAT_ZARCH 0x00000800 #define CPUSTAT_MCDS 0x00000100 #define CPUSTAT_SM 0x00000080 +#define CPUSTAT_IBS 0x00000040 #define CPUSTAT_G 0x00000008 #define CPUSTAT_GED 0x00000004 #define CPUSTAT_J 0x00000002 @@ -85,12 +94,26 @@ struct kvm_s390_sie_block { __u8 reserved40[4]; /* 0x0040 */ #define LCTL_CR0 0x8000 #define LCTL_CR6 0x0200 +#define LCTL_CR9 0x0040 +#define LCTL_CR10 0x0020 +#define LCTL_CR11 0x0010 #define LCTL_CR14 0x0002 __u16 lctl; /* 0x0044 */ __s16 icpua; /* 0x0046 */ -#define ICTL_LPSW 0x00400000 +#define ICTL_PINT 0x20000000 +#define ICTL_LPSW 0x00400000 +#define ICTL_STCTL 0x00040000 +#define ICTL_ISKE 0x00004000 +#define ICTL_SSKE 0x00002000 +#define ICTL_RRBE 0x00001000 __u32 ictl; /* 0x0048 */ __u32 eca; /* 0x004c */ +#define ICPT_INST 0x04 +#define ICPT_PROGI 0x08 +#define ICPT_INSTPROGI 0x0C +#define ICPT_OPEREXC 0x2C +#define ICPT_PARTEXEC 0x38 +#define ICPT_IOINST 0x40 __u8 icptcode; /* 0x0050 */ __u8 reserved51; /* 0x0051 */ __u16 ihcpu; /* 0x0052 */ @@ -109,9 +132,21 @@ struct kvm_s390_sie_block { psw_t gpsw; /* 0x0090 */ __u64 gg14; /* 0x00a0 */ __u64 gg15; /* 0x00a8 */ - __u8 reservedb0[30]; /* 0x00b0 */ - __u16 iprcc; /* 0x00ce */ - __u8 reservedd0[48]; /* 0x00d0 */ + __u8 reservedb0[28]; /* 0x00b0 */ + __u16 pgmilc; /* 0x00cc */ + __u16 iprcc; /* 0x00ce */ + __u32 dxc; /* 0x00d0 */ + __u16 mcn; /* 0x00d4 */ + __u8 perc; /* 0x00d6 */ + __u8 peratmid; /* 0x00d7 */ + __u64 peraddr; /* 0x00d8 */ + __u8 eai; /* 0x00e0 */ + __u8 peraid; /* 0x00e1 */ + __u8 oai; /* 0x00e2 */ + __u8 armid; /* 0x00e3 */ + __u8 reservede4[4]; /* 0x00e4 */ + __u64 tecmc; /* 0x00e8 */ + __u8 reservedf0[16]; /* 0x00f0 */ __u64 gcr[16]; /* 0x0100 */ __u64 gbea; /* 0x0180 */ __u8 reserved188[24]; /* 0x0188 */ @@ -146,6 +181,8 @@ struct kvm_vcpu_stat { u32 exit_instruction; u32 instruction_lctl; u32 instruction_lctlg; + u32 instruction_stctl; + u32 instruction_stctg; u32 exit_program_interruption; u32 exit_instr_and_program; u32 deliver_external_call; @@ -164,6 +201,7 @@ struct kvm_vcpu_stat { u32 instruction_stpx; u32 instruction_stap; u32 instruction_storage_key; + u32 instruction_ipte_interlock; u32 instruction_stsch; u32 instruction_chsc; u32 instruction_stsi; @@ -183,13 +221,58 @@ struct kvm_vcpu_stat { u32 diagnose_9c; }; -#define PGM_OPERATION 0x01 -#define PGM_PRIVILEGED_OP 0x02 -#define PGM_EXECUTE 0x03 -#define PGM_PROTECTION 0x04 -#define PGM_ADDRESSING 0x05 -#define PGM_SPECIFICATION 0x06 -#define PGM_DATA 0x07 +#define PGM_OPERATION 0x01 +#define PGM_PRIVILEGED_OP 0x02 +#define PGM_EXECUTE 0x03 +#define PGM_PROTECTION 0x04 +#define PGM_ADDRESSING 0x05 +#define PGM_SPECIFICATION 0x06 +#define PGM_DATA 0x07 +#define PGM_FIXED_POINT_OVERFLOW 0x08 +#define PGM_FIXED_POINT_DIVIDE 0x09 +#define PGM_DECIMAL_OVERFLOW 0x0a +#define PGM_DECIMAL_DIVIDE 0x0b +#define PGM_HFP_EXPONENT_OVERFLOW 0x0c +#define PGM_HFP_EXPONENT_UNDERFLOW 0x0d +#define PGM_HFP_SIGNIFICANCE 0x0e +#define PGM_HFP_DIVIDE 0x0f +#define PGM_SEGMENT_TRANSLATION 0x10 +#define PGM_PAGE_TRANSLATION 0x11 +#define PGM_TRANSLATION_SPEC 0x12 +#define PGM_SPECIAL_OPERATION 0x13 +#define PGM_OPERAND 0x15 +#define PGM_TRACE_TABEL 0x16 +#define PGM_SPACE_SWITCH 0x1c +#define PGM_HFP_SQUARE_ROOT 0x1d +#define PGM_PC_TRANSLATION_SPEC 0x1f +#define PGM_AFX_TRANSLATION 0x20 +#define PGM_ASX_TRANSLATION 0x21 +#define PGM_LX_TRANSLATION 0x22 +#define PGM_EX_TRANSLATION 0x23 +#define PGM_PRIMARY_AUTHORITY 0x24 +#define PGM_SECONDARY_AUTHORITY 0x25 +#define PGM_LFX_TRANSLATION 0x26 +#define PGM_LSX_TRANSLATION 0x27 +#define PGM_ALET_SPECIFICATION 0x28 +#define PGM_ALEN_TRANSLATION 0x29 +#define PGM_ALE_SEQUENCE 0x2a +#define PGM_ASTE_VALIDITY 0x2b +#define PGM_ASTE_SEQUENCE 0x2c +#define PGM_EXTENDED_AUTHORITY 0x2d +#define PGM_LSTE_SEQUENCE 0x2e +#define PGM_ASTE_INSTANCE 0x2f +#define PGM_STACK_FULL 0x30 +#define PGM_STACK_EMPTY 0x31 +#define PGM_STACK_SPECIFICATION 0x32 +#define PGM_STACK_TYPE 0x33 +#define PGM_STACK_OPERATION 0x34 +#define PGM_ASCE_TYPE 0x38 +#define PGM_REGION_FIRST_TRANS 0x39 +#define PGM_REGION_SECOND_TRANS 0x3a +#define PGM_REGION_THIRD_TRANS 0x3b +#define PGM_MONITOR 0x40 +#define PGM_PER 0x80 +#define PGM_CRYPTO_OPERATION 0x119 struct kvm_s390_interrupt_info { struct list_head list; @@ -229,6 +312,45 @@ struct kvm_s390_float_interrupt { unsigned int irq_count; }; +struct kvm_hw_wp_info_arch { + unsigned long addr; + unsigned long phys_addr; + int len; + char *old_data; +}; + +struct kvm_hw_bp_info_arch { + unsigned long addr; + int len; +}; + +/* + * Only the upper 16 bits of kvm_guest_debug->control are arch specific. + * Further KVM_GUESTDBG flags which an be used from userspace can be found in + * arch/s390/include/uapi/asm/kvm.h + */ +#define KVM_GUESTDBG_EXIT_PENDING 0x10000000 + +#define guestdbg_enabled(vcpu) \ + (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) +#define guestdbg_sstep_enabled(vcpu) \ + (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) +#define guestdbg_hw_bp_enabled(vcpu) \ + (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) +#define guestdbg_exit_pending(vcpu) (guestdbg_enabled(vcpu) && \ + (vcpu->guest_debug & KVM_GUESTDBG_EXIT_PENDING)) + +struct kvm_guestdbg_info_arch { + unsigned long cr0; + unsigned long cr9; + unsigned long cr10; + unsigned long cr11; + struct kvm_hw_bp_info_arch *hw_bp_info; + struct kvm_hw_wp_info_arch *hw_wp_info; + int nr_hw_bp; + int nr_hw_wp; + unsigned long last_bp; +}; struct kvm_vcpu_arch { struct kvm_s390_sie_block *sie_block; @@ -238,11 +360,13 @@ struct kvm_vcpu_arch { struct kvm_s390_local_interrupt local_int; struct hrtimer ckc_timer; struct tasklet_struct tasklet; + struct kvm_s390_pgm_info pgm; union { struct cpuid cpu_id; u64 stidp_data; }; struct gmap *gmap; + struct kvm_guestdbg_info_arch guestdbg; #define KVM_S390_PFAULT_TOKEN_INVALID (-1UL) unsigned long pfault_token; unsigned long pfault_select; @@ -285,7 +409,10 @@ struct kvm_arch{ struct gmap *gmap; int css_support; int use_irqchip; + int use_cmma; struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS]; + wait_queue_head_t ipte_wq; + spinlock_t start_stop_lock; }; #define KVM_HVA_ERR_BAD (-1UL) diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index bbf8141408cdad..ecc121d2b5bf85 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -56,13 +56,14 @@ struct _lowcore { __u16 pgm_code; /* 0x008e */ __u32 trans_exc_code; /* 0x0090 */ __u16 mon_class_num; /* 0x0094 */ - __u16 per_perc_atmid; /* 0x0096 */ + __u8 per_code; /* 0x0096 */ + __u8 per_atmid; /* 0x0097 */ __u32 per_address; /* 0x0098 */ __u32 monitor_code; /* 0x009c */ __u8 exc_access_id; /* 0x00a0 */ __u8 per_access_id; /* 0x00a1 */ __u8 op_access_id; /* 0x00a2 */ - __u8 ar_access_id; /* 0x00a3 */ + __u8 ar_mode_id; /* 0x00a3 */ __u8 pad_0x00a4[0x00b8-0x00a4]; /* 0x00a4 */ __u16 subchannel_id; /* 0x00b8 */ __u16 subchannel_nr; /* 0x00ba */ @@ -93,7 +94,9 @@ struct _lowcore { __u32 save_area_sync[8]; /* 0x0200 */ __u32 save_area_async[8]; /* 0x0220 */ __u32 save_area_restart[1]; /* 0x0240 */ - __u8 pad_0x0244[0x0248-0x0244]; /* 0x0244 */ + + /* CPU flags. */ + __u32 cpu_flags; /* 0x0244 */ /* Return psws. */ psw_t return_psw; /* 0x0248 */ @@ -139,7 +142,7 @@ struct _lowcore { __u32 percpu_offset; /* 0x02f0 */ __u32 machine_flags; /* 0x02f4 */ __u32 ftrace_func; /* 0x02f8 */ - __u8 pad_0x02fc[0x0300-0x02fc]; /* 0x02fc */ + __u32 spinlock_lockval; /* 0x02fc */ /* Interrupt response block */ __u8 irb[64]; /* 0x0300 */ @@ -196,12 +199,13 @@ struct _lowcore { __u16 pgm_code; /* 0x008e */ __u32 data_exc_code; /* 0x0090 */ __u16 mon_class_num; /* 0x0094 */ - __u16 per_perc_atmid; /* 0x0096 */ + __u8 per_code; /* 0x0096 */ + __u8 per_atmid; /* 0x0097 */ __u64 per_address; /* 0x0098 */ __u8 exc_access_id; /* 0x00a0 */ __u8 per_access_id; /* 0x00a1 */ __u8 op_access_id; /* 0x00a2 */ - __u8 ar_access_id; /* 0x00a3 */ + __u8 ar_mode_id; /* 0x00a3 */ __u8 pad_0x00a4[0x00a8-0x00a4]; /* 0x00a4 */ __u64 trans_exc_code; /* 0x00a8 */ __u64 monitor_code; /* 0x00b0 */ @@ -237,7 +241,9 @@ struct _lowcore { __u64 save_area_sync[8]; /* 0x0200 */ __u64 save_area_async[8]; /* 0x0240 */ __u64 save_area_restart[1]; /* 0x0280 */ - __u8 pad_0x0288[0x0290-0x0288]; /* 0x0288 */ + + /* CPU flags. */ + __u64 cpu_flags; /* 0x0288 */ /* Return psws. */ psw_t return_psw; /* 0x0290 */ @@ -285,7 +291,8 @@ struct _lowcore { __u64 machine_flags; /* 0x0388 */ __u64 ftrace_func; /* 0x0390 */ __u64 gmap; /* 0x0398 */ - __u8 pad_0x03a0[0x0400-0x03a0]; /* 0x03a0 */ + __u32 spinlock_lockval; /* 0x03a0 */ + __u8 pad_0x03a0[0x0400-0x03a4]; /* 0x03a4 */ /* Interrupt response block. */ __u8 irb[64]; /* 0x0400 */ diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h index f77695a82f647d..a5e656260a7018 100644 --- a/arch/s390/include/asm/mmu.h +++ b/arch/s390/include/asm/mmu.h @@ -16,6 +16,8 @@ typedef struct { unsigned long vdso_base; /* The mmu context has extended page tables. */ unsigned int has_pgste:1; + /* The mmu context uses storage keys. */ + unsigned int use_skey:1; } mm_context_t; #define INIT_MM_CONTEXT(name) \ diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index 71be346d0e3c80..c28f32a45af5d9 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -23,6 +23,7 @@ static inline int init_new_context(struct task_struct *tsk, mm->context.asce_bits |= _ASCE_TYPE_REGION3; #endif mm->context.has_pgste = 0; + mm->context.use_skey = 0; mm->context.asce_limit = STACK_TOP_MAX; crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm)); return 0; @@ -30,33 +31,31 @@ static inline int init_new_context(struct task_struct *tsk, #define destroy_context(mm) do { } while (0) -static inline void update_user_asce(struct mm_struct *mm, int load_primary) +static inline void set_user_asce(struct mm_struct *mm) { pgd_t *pgd = mm->pgd; S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd); - if (load_primary) - __ctl_load(S390_lowcore.user_asce, 1, 1); set_fs(current->thread.mm_segment); + set_cpu_flag(CIF_ASCE); } -static inline void clear_user_asce(struct mm_struct *mm, int load_primary) +static inline void clear_user_asce(void) { S390_lowcore.user_asce = S390_lowcore.kernel_asce; - if (load_primary) - __ctl_load(S390_lowcore.user_asce, 1, 1); + __ctl_load(S390_lowcore.user_asce, 1, 1); __ctl_load(S390_lowcore.user_asce, 7, 7); } -static inline void update_primary_asce(struct task_struct *tsk) +static inline void load_kernel_asce(void) { unsigned long asce; __ctl_store(asce, 1, 1); if (asce != S390_lowcore.kernel_asce) __ctl_load(S390_lowcore.kernel_asce, 1, 1); - set_tsk_thread_flag(tsk, TIF_ASCE); + set_cpu_flag(CIF_ASCE); } static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, @@ -64,25 +63,17 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, { int cpu = smp_processor_id(); - update_primary_asce(tsk); if (prev == next) return; if (MACHINE_HAS_TLB_LC) cpumask_set_cpu(cpu, &next->context.cpu_attach_mask); - if (atomic_inc_return(&next->context.attach_count) >> 16) { - /* Delay update_user_asce until all TLB flushes are done. */ - set_tsk_thread_flag(tsk, TIF_TLB_WAIT); - /* Clear old ASCE by loading the kernel ASCE. */ - clear_user_asce(next, 0); - } else { - cpumask_set_cpu(cpu, mm_cpumask(next)); - update_user_asce(next, 0); - if (next->context.flush_mm) - /* Flush pending TLBs */ - __tlb_flush_mm(next); - } + /* Clear old ASCE by loading the kernel ASCE. */ + __ctl_load(S390_lowcore.kernel_asce, 1, 1); + __ctl_load(S390_lowcore.kernel_asce, 7, 7); + /* Delay loading of the new ASCE to control registers CR1 & CR7 */ + set_cpu_flag(CIF_ASCE); + atomic_inc(&next->context.attach_count); atomic_dec(&prev->context.attach_count); - WARN_ON(atomic_read(&prev->context.attach_count) < 0); if (MACHINE_HAS_TLB_LC) cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask); } @@ -93,15 +84,14 @@ static inline void finish_arch_post_lock_switch(void) struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; - if (!test_tsk_thread_flag(tsk, TIF_TLB_WAIT)) + if (!mm) return; preempt_disable(); - clear_tsk_thread_flag(tsk, TIF_TLB_WAIT); while (atomic_read(&mm->context.attach_count) >> 16) cpu_relax(); cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm)); - update_user_asce(mm, 0); + set_user_asce(mm); if (mm->context.flush_mm) __tlb_flush_mm(mm); preempt_enable(); @@ -113,7 +103,9 @@ static inline void finish_arch_post_lock_switch(void) static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) { - switch_mm(prev, next, current); + switch_mm(prev, next, current); + cpumask_set_cpu(smp_processor_id(), mm_cpumask(next)); + set_user_asce(next); } static inline void arch_dup_mmap(struct mm_struct *oldmm, diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 2583466f576b61..c030900320e0ba 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -78,10 +78,16 @@ struct zpci_dev { enum zpci_state state; u32 fid; /* function ID, used by sclp */ u32 fh; /* function handle, used by insn's */ + u16 vfn; /* virtual function number */ u16 pchid; /* physical channel ID */ u8 pfgid; /* function group ID */ + u8 pft; /* pci function type */ u16 domain; + u8 pfip[CLP_PFIP_NR_SEGMENTS]; /* pci function internal path */ + u32 uid; /* user defined id */ + u8 util_str[CLP_UTIL_STR_LEN]; /* utility string */ + /* IRQ stuff */ u64 msi_addr; /* MSI address */ struct airq_iv *aibv; /* adapter interrupt bit vector */ @@ -120,6 +126,8 @@ static inline bool zdev_enabled(struct zpci_dev *zdev) return (zdev->fh & (1UL << 31)) ? true : false; } +extern const struct attribute_group *zpci_attr_groups[]; + /* ----------------------------------------------------------------------------- Prototypes ----------------------------------------------------------------------------- */ @@ -166,10 +174,6 @@ static inline void zpci_exit_slot(struct zpci_dev *zdev) {} struct zpci_dev *get_zdev(struct pci_dev *); struct zpci_dev *get_zdev_by_fid(u32); -/* sysfs */ -int zpci_sysfs_add_device(struct device *); -void zpci_sysfs_remove_device(struct device *); - /* DMA */ int zpci_dma_init(void); void zpci_dma_exit(void); diff --git a/arch/s390/include/asm/pci_clp.h b/arch/s390/include/asm/pci_clp.h index d31d739f8689e2..dd78f92f1cce5f 100644 --- a/arch/s390/include/asm/pci_clp.h +++ b/arch/s390/include/asm/pci_clp.h @@ -44,6 +44,7 @@ struct clp_fh_list_entry { #define CLP_SET_DISABLE_PCI_FN 1 /* Yes, 1 disables it */ #define CLP_UTIL_STR_LEN 64 +#define CLP_PFIP_NR_SEGMENTS 4 /* List PCI functions request */ struct clp_req_list_pci { @@ -85,7 +86,7 @@ struct clp_rsp_query_pci { struct clp_rsp_hdr hdr; u32 fmt : 4; /* cmd request block format */ u32 : 28; - u64 reserved1; + u64 : 64; u16 vfn; /* virtual fn number */ u16 : 7; u16 util_str_avail : 1; /* utility string available? */ @@ -94,10 +95,13 @@ struct clp_rsp_query_pci { u8 bar_size[PCI_BAR_COUNT]; u16 pchid; u32 bar[PCI_BAR_COUNT]; - u64 reserved2; + u8 pfip[CLP_PFIP_NR_SEGMENTS]; /* pci function internal path */ + u32 : 24; + u8 pft; /* pci function type */ u64 sdma; /* start dma as */ u64 edma; /* end dma as */ - u64 reserved3[6]; + u32 reserved[11]; + u32 uid; /* user defined id */ u8 util_str[CLP_UTIL_STR_LEN]; /* utility string */ } __packed; diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index 884017cbfa9fad..9e18a61d3df39c 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h @@ -22,7 +22,8 @@ unsigned long *page_table_alloc(struct mm_struct *, unsigned long); void page_table_free(struct mm_struct *, unsigned long *); void page_table_free_rcu(struct mmu_gather *, unsigned long *); -void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long); +void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long, + bool init_skey); int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, unsigned long key, bool nq); diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 12f75313e086d4..fcba5e03839f56 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -309,7 +309,8 @@ extern unsigned long MODULES_END; #define PGSTE_HC_BIT 0x00200000UL #define PGSTE_GR_BIT 0x00040000UL #define PGSTE_GC_BIT 0x00020000UL -#define PGSTE_IN_BIT 0x00008000UL /* IPTE notify bit */ +#define PGSTE_UC_BIT 0x00008000UL /* user dirty (migration) */ +#define PGSTE_IN_BIT 0x00004000UL /* IPTE notify bit */ #else /* CONFIG_64BIT */ @@ -391,7 +392,8 @@ extern unsigned long MODULES_END; #define PGSTE_HC_BIT 0x0020000000000000UL #define PGSTE_GR_BIT 0x0004000000000000UL #define PGSTE_GC_BIT 0x0002000000000000UL -#define PGSTE_IN_BIT 0x0000800000000000UL /* IPTE notify bit */ +#define PGSTE_UC_BIT 0x0000800000000000UL /* user dirty (migration) */ +#define PGSTE_IN_BIT 0x0000400000000000UL /* IPTE notify bit */ #endif /* CONFIG_64BIT */ @@ -466,6 +468,16 @@ static inline int mm_has_pgste(struct mm_struct *mm) #endif return 0; } + +static inline int mm_use_skey(struct mm_struct *mm) +{ +#ifdef CONFIG_PGSTE + if (mm->context.use_skey) + return 1; +#endif + return 0; +} + /* * pgd/pmd/pte query functions */ @@ -699,26 +711,17 @@ static inline void pgste_set(pte_t *ptep, pgste_t pgste) #endif } -static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste) +static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste, + struct mm_struct *mm) { #ifdef CONFIG_PGSTE unsigned long address, bits, skey; - if (pte_val(*ptep) & _PAGE_INVALID) + if (!mm_use_skey(mm) || pte_val(*ptep) & _PAGE_INVALID) return pgste; address = pte_val(*ptep) & PAGE_MASK; skey = (unsigned long) page_get_storage_key(address); bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); - if (!(pgste_val(pgste) & PGSTE_HC_BIT) && (bits & _PAGE_CHANGED)) { - /* Transfer dirty + referenced bit to host bits in pgste */ - pgste_val(pgste) |= bits << 52; - page_set_storage_key(address, skey ^ bits, 0); - } else if (!(pgste_val(pgste) & PGSTE_HR_BIT) && - (bits & _PAGE_REFERENCED)) { - /* Transfer referenced bit to host bit in pgste */ - pgste_val(pgste) |= PGSTE_HR_BIT; - page_reset_referenced(address); - } /* Transfer page changed & referenced bit to guest bits in pgste */ pgste_val(pgste) |= bits << 48; /* GR bit & GC bit */ /* Copy page access key and fetch protection bit to pgste */ @@ -729,25 +732,14 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste) } -static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste) -{ -#ifdef CONFIG_PGSTE - if (pte_val(*ptep) & _PAGE_INVALID) - return pgste; - /* Get referenced bit from storage key */ - if (page_reset_referenced(pte_val(*ptep) & PAGE_MASK)) - pgste_val(pgste) |= PGSTE_HR_BIT | PGSTE_GR_BIT; -#endif - return pgste; -} - -static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry) +static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry, + struct mm_struct *mm) { #ifdef CONFIG_PGSTE unsigned long address; unsigned long nkey; - if (pte_val(entry) & _PAGE_INVALID) + if (!mm_use_skey(mm) || pte_val(entry) & _PAGE_INVALID) return; VM_BUG_ON(!(pte_val(*ptep) & _PAGE_INVALID)); address = pte_val(entry) & PAGE_MASK; @@ -757,23 +749,30 @@ static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry) * key C/R to 0. */ nkey = (pgste_val(pgste) & (PGSTE_ACC_BITS | PGSTE_FP_BIT)) >> 56; + nkey |= (pgste_val(pgste) & (PGSTE_GR_BIT | PGSTE_GC_BIT)) >> 48; page_set_storage_key(address, nkey, 0); #endif } -static inline void pgste_set_pte(pte_t *ptep, pte_t entry) +static inline pgste_t pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry) { - if (!MACHINE_HAS_ESOP && - (pte_val(entry) & _PAGE_PRESENT) && - (pte_val(entry) & _PAGE_WRITE)) { - /* - * Without enhanced suppression-on-protection force - * the dirty bit on for all writable ptes. - */ - pte_val(entry) |= _PAGE_DIRTY; - pte_val(entry) &= ~_PAGE_PROTECT; + if ((pte_val(entry) & _PAGE_PRESENT) && + (pte_val(entry) & _PAGE_WRITE) && + !(pte_val(entry) & _PAGE_INVALID)) { + if (!MACHINE_HAS_ESOP) { + /* + * Without enhanced suppression-on-protection force + * the dirty bit on for all writable ptes. + */ + pte_val(entry) |= _PAGE_DIRTY; + pte_val(entry) &= ~_PAGE_PROTECT; + } + if (!(pte_val(entry) & _PAGE_PROTECT)) + /* This pte allows write access, set user-dirty */ + pgste_val(pgste) |= PGSTE_UC_BIT; } *ptep = entry; + return pgste; } /** @@ -839,6 +838,8 @@ unsigned long __gmap_fault(unsigned long address, struct gmap *); unsigned long gmap_fault(unsigned long address, struct gmap *); void gmap_discard(unsigned long from, unsigned long to, struct gmap *); void __gmap_zap(unsigned long address, struct gmap *); +bool gmap_test_and_clear_dirty(unsigned long address, struct gmap *); + void gmap_register_ipte_notifier(struct gmap_notifier *); void gmap_unregister_ipte_notifier(struct gmap_notifier *); @@ -870,8 +871,8 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, if (mm_has_pgste(mm)) { pgste = pgste_get_lock(ptep); pgste_val(pgste) &= ~_PGSTE_GPS_ZERO; - pgste_set_key(ptep, pgste, entry); - pgste_set_pte(ptep, entry); + pgste_set_key(ptep, pgste, entry, mm); + pgste = pgste_set_pte(ptep, pgste, entry); pgste_set_unlock(ptep, pgste); } else { if (!(pte_val(entry) & _PAGE_INVALID) && MACHINE_HAS_EDAT1) @@ -1017,45 +1018,6 @@ static inline pte_t pte_mkhuge(pte_t pte) } #endif -/* - * Get (and clear) the user dirty bit for a pte. - */ -static inline int ptep_test_and_clear_user_dirty(struct mm_struct *mm, - pte_t *ptep) -{ - pgste_t pgste; - int dirty = 0; - - if (mm_has_pgste(mm)) { - pgste = pgste_get_lock(ptep); - pgste = pgste_update_all(ptep, pgste); - dirty = !!(pgste_val(pgste) & PGSTE_HC_BIT); - pgste_val(pgste) &= ~PGSTE_HC_BIT; - pgste_set_unlock(ptep, pgste); - return dirty; - } - return dirty; -} - -/* - * Get (and clear) the user referenced bit for a pte. - */ -static inline int ptep_test_and_clear_user_young(struct mm_struct *mm, - pte_t *ptep) -{ - pgste_t pgste; - int young = 0; - - if (mm_has_pgste(mm)) { - pgste = pgste_get_lock(ptep); - pgste = pgste_update_young(ptep, pgste); - young = !!(pgste_val(pgste) & PGSTE_HR_BIT); - pgste_val(pgste) &= ~PGSTE_HR_BIT; - pgste_set_unlock(ptep, pgste); - } - return young; -} - static inline void __ptep_ipte(unsigned long address, pte_t *ptep) { unsigned long pto = (unsigned long) ptep; @@ -1118,6 +1080,36 @@ static inline void ptep_flush_lazy(struct mm_struct *mm, atomic_sub(0x10000, &mm->context.attach_count); } +/* + * Get (and clear) the user dirty bit for a pte. + */ +static inline int ptep_test_and_clear_user_dirty(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep) +{ + pgste_t pgste; + pte_t pte; + int dirty; + + if (!mm_has_pgste(mm)) + return 0; + pgste = pgste_get_lock(ptep); + dirty = !!(pgste_val(pgste) & PGSTE_UC_BIT); + pgste_val(pgste) &= ~PGSTE_UC_BIT; + pte = *ptep; + if (dirty && (pte_val(pte) & _PAGE_PRESENT)) { + pgste = pgste_ipte_notify(mm, ptep, pgste); + __ptep_ipte(addr, ptep); + if (MACHINE_HAS_ESOP || !(pte_val(pte) & _PAGE_WRITE)) + pte_val(pte) |= _PAGE_PROTECT; + else + pte_val(pte) |= _PAGE_INVALID; + *ptep = pte; + } + pgste_set_unlock(ptep, pgste); + return dirty; +} + #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) @@ -1137,7 +1129,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, pte = pte_mkold(pte); if (mm_has_pgste(vma->vm_mm)) { - pgste_set_pte(ptep, pte); + pgste = pgste_set_pte(ptep, pgste, pte); pgste_set_unlock(ptep, pgste); } else *ptep = pte; @@ -1182,7 +1174,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, pte_val(*ptep) = _PAGE_INVALID; if (mm_has_pgste(mm)) { - pgste = pgste_update_all(&pte, pgste); + pgste = pgste_update_all(&pte, pgste, mm); pgste_set_unlock(ptep, pgste); } return pte; @@ -1205,7 +1197,7 @@ static inline pte_t ptep_modify_prot_start(struct mm_struct *mm, ptep_flush_lazy(mm, address, ptep); if (mm_has_pgste(mm)) { - pgste = pgste_update_all(&pte, pgste); + pgste = pgste_update_all(&pte, pgste, mm); pgste_set(ptep, pgste); } return pte; @@ -1219,8 +1211,8 @@ static inline void ptep_modify_prot_commit(struct mm_struct *mm, if (mm_has_pgste(mm)) { pgste = pgste_get(ptep); - pgste_set_key(ptep, pgste, pte); - pgste_set_pte(ptep, pte); + pgste_set_key(ptep, pgste, pte, mm); + pgste = pgste_set_pte(ptep, pgste, pte); pgste_set_unlock(ptep, pgste); } else *ptep = pte; @@ -1246,7 +1238,7 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, if ((pgste_val(pgste) & _PGSTE_GPS_USAGE_MASK) == _PGSTE_GPS_USAGE_UNUSED) pte_val(pte) |= _PAGE_UNUSED; - pgste = pgste_update_all(&pte, pgste); + pgste = pgste_update_all(&pte, pgste, vma->vm_mm); pgste_set_unlock(ptep, pgste); } return pte; @@ -1278,7 +1270,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, pte_val(*ptep) = _PAGE_INVALID; if (!full && mm_has_pgste(mm)) { - pgste = pgste_update_all(&pte, pgste); + pgste = pgste_update_all(&pte, pgste, mm); pgste_set_unlock(ptep, pgste); } return pte; @@ -1301,7 +1293,7 @@ static inline pte_t ptep_set_wrprotect(struct mm_struct *mm, pte = pte_wrprotect(pte); if (mm_has_pgste(mm)) { - pgste_set_pte(ptep, pte); + pgste = pgste_set_pte(ptep, pgste, pte); pgste_set_unlock(ptep, pgste); } else *ptep = pte; @@ -1326,7 +1318,7 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma, ptep_flush_direct(vma->vm_mm, address, ptep); if (mm_has_pgste(vma->vm_mm)) { - pgste_set_pte(ptep, entry); + pgste = pgste_set_pte(ptep, pgste, entry); pgste_set_unlock(ptep, pgste); } else *ptep = entry; @@ -1734,6 +1726,7 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) extern int vmem_add_mapping(unsigned long start, unsigned long size); extern int vmem_remove_mapping(unsigned long start, unsigned long size); extern int s390_enable_sie(void); +extern void s390_enable_skey(void); /* * No page table caches to initialise diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index dc5fc4f90e52b8..6f02d452bbee37 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -11,6 +11,13 @@ #ifndef __ASM_S390_PROCESSOR_H #define __ASM_S390_PROCESSOR_H +#define CIF_MCCK_PENDING 0 /* machine check handling is pending */ +#define CIF_ASCE 1 /* user asce needs fixup / uaccess */ + +#define _CIF_MCCK_PENDING (1< @@ -21,6 +28,21 @@ #include #include +static inline void set_cpu_flag(int flag) +{ + S390_lowcore.cpu_flags |= (1U << flag); +} + +static inline void clear_cpu_flag(int flag) +{ + S390_lowcore.cpu_flags &= ~(1U << flag); +} + +static inline int test_cpu_flag(int flag) +{ + return !!(S390_lowcore.cpu_flags & (1U << flag)); +} + /* * Default implementation of macro that returns current * instruction pointer ("program counter"). diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index f4783c0b7b43cf..55d69dd7473c82 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -8,6 +8,12 @@ #include +#define PIF_SYSCALL 0 /* inside a system call */ +#define PIF_PER_TRAP 1 /* deliver sigtrap on return to user */ + +#define _PIF_SYSCALL (1<flags |= (1U << flag); +} + +static inline void clear_pt_regs_flag(struct pt_regs *regs, int flag) +{ + regs->flags &= ~(1U << flag); +} + +static inline int test_pt_regs_flag(struct pt_regs *regs, int flag) +{ + return !!(regs->flags & (1U << flag)); +} + /* * These are defined as per linux/ptrace.h, which see. */ diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 2f5e9932b4defd..943d4345111655 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -28,7 +28,11 @@ struct sclp_ipl_info { struct sclp_cpu_entry { u8 address; - u8 reserved0[13]; + u8 reserved0[2]; + u8 : 3; + u8 siif : 1; + u8 : 4; + u8 reserved2[10]; u8 type; u8 reserved1; } __attribute__((packed)); @@ -61,5 +65,6 @@ int sclp_pci_deconfigure(u32 fid); int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode); unsigned long sclp_get_hsa_size(void); void sclp_early_detect(void); +int sclp_has_siif(void); #endif /* _ASM_S390_SCLP_H */ diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index b31b22dba94859..089a49814c505b 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -9,7 +9,6 @@ #define PARMAREA 0x10400 -#define MEMORY_CHUNKS 256 #ifndef __ASSEMBLY__ @@ -31,22 +30,11 @@ #endif /* CONFIG_64BIT */ #define COMMAND_LINE ((char *) (0x10480)) -#define CHUNK_READ_WRITE 0 -#define CHUNK_READ_ONLY 1 - -struct mem_chunk { - unsigned long addr; - unsigned long size; - int type; -}; - -extern struct mem_chunk memory_chunk[]; extern int memory_end_set; extern unsigned long memory_end; +extern unsigned long max_physmem_end; -void detect_memory_layout(struct mem_chunk chunk[], unsigned long maxsize); -void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr, - unsigned long size); +extern void detect_memory_memblock(void); /* * Machine features detected in head.S diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index 21703f85b48d8d..4f1307962a95a3 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h @@ -30,7 +30,6 @@ extern int smp_store_status(int cpu); extern int smp_vcpu_scheduled(int cpu); extern void smp_yield_cpu(int cpu); extern void smp_yield(void); -extern void smp_stop_cpu(void); extern void smp_cpu_set_polarization(int cpu, int val); extern int smp_cpu_get_polarization(int cpu); extern void smp_fill_possible_mask(void); @@ -54,6 +53,8 @@ static inline void smp_yield_cpu(int cpu) { } static inline void smp_yield(void) { } static inline void smp_fill_possible_mask(void) { } +#endif /* CONFIG_SMP */ + static inline void smp_stop_cpu(void) { u16 pcpu = stap(); @@ -64,8 +65,6 @@ static inline void smp_stop_cpu(void) } } -#endif /* CONFIG_SMP */ - #ifdef CONFIG_HOTPLUG_CPU extern int smp_rescan_cpus(void); extern void __noreturn cpu_die(void); diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h index 83e5d216105e86..84faa13aa7aeb6 100644 --- a/arch/s390/include/asm/spinlock.h +++ b/arch/s390/include/asm/spinlock.h @@ -1,7 +1,8 @@ /* * S390 version - * Copyright IBM Corp. 1999 + * Copyright IBM Corp. 1999, 2014 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * Philipp Hachtmann (phacht@linux.vnet.ibm.com) * * Derived from "include/asm-i386/spinlock.h" */ @@ -11,80 +12,121 @@ #include +#define SPINLOCK_LOCKVAL (S390_lowcore.spinlock_lockval) + extern int spin_retry; static inline int -_raw_compare_and_swap(volatile unsigned int *lock, - unsigned int old, unsigned int new) +_raw_compare_and_swap(unsigned int *lock, unsigned int old, unsigned int new) { + unsigned int old_expected = old; + asm volatile( " cs %0,%3,%1" : "=d" (old), "=Q" (*lock) : "0" (old), "d" (new), "Q" (*lock) : "cc", "memory" ); - return old; + return old == old_expected; } /* * Simple spin lock operations. There are two variants, one clears IRQ's * on the local processor, one does not. * - * We make no fairness assumptions. They have a cost. - * * (the type definitions are in asm/spinlock_types.h) */ -#define arch_spin_is_locked(x) ((x)->owner_cpu != 0) -#define arch_spin_unlock_wait(lock) \ - do { while (arch_spin_is_locked(lock)) \ - arch_spin_relax(lock); } while (0) +void arch_spin_lock_wait(arch_spinlock_t *); +int arch_spin_trylock_retry(arch_spinlock_t *); +void arch_spin_relax(arch_spinlock_t *); + +#ifdef CONFIG_S390_TICKET_SPINLOCK + +void arch_spin_unlock_slow(arch_spinlock_t *lp); + +static inline u32 arch_spin_lockval(u32 cpu) +{ + arch_spinlock_t new; + + new.tickets.owner = ~cpu; + new.tickets.head = 0; + new.tickets.tail = 0; + return new.lock; +} + +static inline void arch_spin_lock_wait_flags(arch_spinlock_t *lp, + unsigned long flags) +{ + arch_spin_lock_wait(lp); +} + +#else /* CONFIG_S390_TICKET_SPINLOCK */ + +void arch_spin_lock_wait_flags(arch_spinlock_t *, unsigned long flags); + +static inline u32 arch_spin_lockval(int cpu) +{ + return ~cpu; +} + +static inline void arch_spin_unlock_slow(arch_spinlock_t *lp) +{ +} -extern void arch_spin_lock_wait(arch_spinlock_t *); -extern void arch_spin_lock_wait_flags(arch_spinlock_t *, unsigned long flags); -extern int arch_spin_trylock_retry(arch_spinlock_t *); -extern void arch_spin_relax(arch_spinlock_t *lock); +#endif /* CONFIG_S390_TICKET_SPINLOCK */ static inline int arch_spin_value_unlocked(arch_spinlock_t lock) { - return lock.owner_cpu == 0; + return lock.lock == 0; } -static inline void arch_spin_lock(arch_spinlock_t *lp) +static inline int arch_spin_is_locked(arch_spinlock_t *lp) { - int old; + return ACCESS_ONCE(lp->lock) != 0; +} - old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id()); - if (likely(old == 0)) - return; - arch_spin_lock_wait(lp); +static inline int arch_spin_trylock_once(arch_spinlock_t *lp) +{ + return _raw_compare_and_swap(&lp->lock, 0, SPINLOCK_LOCKVAL); } -static inline void arch_spin_lock_flags(arch_spinlock_t *lp, - unsigned long flags) +static inline int arch_spin_tryrelease_once(arch_spinlock_t *lp) { - int old; + return _raw_compare_and_swap(&lp->lock, SPINLOCK_LOCKVAL, 0); +} - old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id()); - if (likely(old == 0)) - return; - arch_spin_lock_wait_flags(lp, flags); +static inline void arch_spin_lock(arch_spinlock_t *lp) +{ + if (unlikely(!arch_spin_trylock_once(lp))) + arch_spin_lock_wait(lp); } -static inline int arch_spin_trylock(arch_spinlock_t *lp) +static inline void arch_spin_lock_flags(arch_spinlock_t *lp, + unsigned long flags) { - int old; + if (unlikely(!arch_spin_trylock_once(lp))) + arch_spin_lock_wait_flags(lp, flags); +} - old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id()); - if (likely(old == 0)) - return 1; - return arch_spin_trylock_retry(lp); +static inline int arch_spin_trylock(arch_spinlock_t *lp) +{ + if (unlikely(!arch_spin_trylock_once(lp))) + return arch_spin_trylock_retry(lp); + return 1; } static inline void arch_spin_unlock(arch_spinlock_t *lp) { - _raw_compare_and_swap(&lp->owner_cpu, lp->owner_cpu, 0); + if (unlikely(!arch_spin_tryrelease_once(lp))) + arch_spin_unlock_slow(lp); } - + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + while (arch_spin_is_locked(lock)) + arch_spin_relax(lock); +} + /* * Read-write spinlocks, allowing multiple readers * but only one writer. @@ -119,7 +161,7 @@ static inline void arch_read_lock(arch_rwlock_t *rw) { unsigned int old; old = rw->lock & 0x7fffffffU; - if (_raw_compare_and_swap(&rw->lock, old, old + 1) != old) + if (!_raw_compare_and_swap(&rw->lock, old, old + 1)) _raw_read_lock_wait(rw); } @@ -127,30 +169,28 @@ static inline void arch_read_lock_flags(arch_rwlock_t *rw, unsigned long flags) { unsigned int old; old = rw->lock & 0x7fffffffU; - if (_raw_compare_and_swap(&rw->lock, old, old + 1) != old) + if (!_raw_compare_and_swap(&rw->lock, old, old + 1)) _raw_read_lock_wait_flags(rw, flags); } static inline void arch_read_unlock(arch_rwlock_t *rw) { - unsigned int old, cmp; + unsigned int old; - old = rw->lock; do { - cmp = old; - old = _raw_compare_and_swap(&rw->lock, old, old - 1); - } while (cmp != old); + old = ACCESS_ONCE(rw->lock); + } while (!_raw_compare_and_swap(&rw->lock, old, old - 1)); } static inline void arch_write_lock(arch_rwlock_t *rw) { - if (unlikely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000) != 0)) + if (unlikely(!_raw_compare_and_swap(&rw->lock, 0, 0x80000000))) _raw_write_lock_wait(rw); } static inline void arch_write_lock_flags(arch_rwlock_t *rw, unsigned long flags) { - if (unlikely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000) != 0)) + if (unlikely(!_raw_compare_and_swap(&rw->lock, 0, 0x80000000))) _raw_write_lock_wait_flags(rw, flags); } @@ -163,14 +203,14 @@ static inline int arch_read_trylock(arch_rwlock_t *rw) { unsigned int old; old = rw->lock & 0x7fffffffU; - if (likely(_raw_compare_and_swap(&rw->lock, old, old + 1) == old)) + if (likely(_raw_compare_and_swap(&rw->lock, old, old + 1))) return 1; return _raw_read_trylock_retry(rw); } static inline int arch_write_trylock(arch_rwlock_t *rw) { - if (likely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)) + if (likely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000))) return 1; return _raw_write_trylock_retry(rw); } diff --git a/arch/s390/include/asm/spinlock_types.h b/arch/s390/include/asm/spinlock_types.h index 9c76656a0af035..472e12254a5150 100644 --- a/arch/s390/include/asm/spinlock_types.h +++ b/arch/s390/include/asm/spinlock_types.h @@ -5,14 +5,31 @@ # error "please don't include this file directly" #endif +#ifdef CONFIG_S390_TICKET_SPINLOCK + +typedef struct arch_spinlock { + union { + unsigned int lock; + struct __raw_tickets { + u16 owner; + u8 tail; + u8 head; + } tickets; + }; +} arch_spinlock_t; + +#else /* CONFIG_S390_TICKET_SPINLOCK */ + typedef struct { - volatile unsigned int owner_cpu; + unsigned int lock; } __attribute__ ((aligned (4))) arch_spinlock_t; -#define __ARCH_SPIN_LOCK_UNLOCKED { 0 } +#endif /* CONFIG_S390_TICKET_SPINLOCK */ + +#define __ARCH_SPIN_LOCK_UNLOCKED { .lock = 0, } typedef struct { - volatile unsigned int lock; + unsigned int lock; } arch_rwlock_t; #define __ARCH_RW_LOCK_UNLOCKED { 0 } diff --git a/arch/s390/include/asm/switch_to.h b/arch/s390/include/asm/switch_to.h index e759181357fc58..29c81f82705e13 100644 --- a/arch/s390/include/asm/switch_to.h +++ b/arch/s390/include/asm/switch_to.h @@ -132,7 +132,6 @@ static inline void restore_access_regs(unsigned int *acrs) update_cr_regs(next); \ } \ prev = __switch_to(prev,next); \ - update_primary_asce(current); \ } while (0) #define finish_arch_switch(prev) do { \ diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index 777687055e7be5..abad78d5b10c7e 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h @@ -28,7 +28,7 @@ extern const unsigned int sys_call_table_emu[]; static inline long syscall_get_nr(struct task_struct *task, struct pt_regs *regs) { - return test_tsk_thread_flag(task, TIF_SYSCALL) ? + return test_pt_regs_flag(regs, PIF_SYSCALL) ? (regs->int_code & 0xffff) : -1; } diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h index 50630e6a35de39..b833e9c0bfbf2f 100644 --- a/arch/s390/include/asm/thread_info.h +++ b/arch/s390/include/asm/thread_info.h @@ -77,32 +77,22 @@ static inline struct thread_info *current_thread_info(void) /* * thread information flags bit numbers */ -#define TIF_SYSCALL 0 /* inside a system call */ -#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ -#define TIF_SIGPENDING 2 /* signal pending */ -#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ -#define TIF_TLB_WAIT 4 /* wait for TLB flush completion */ -#define TIF_ASCE 5 /* primary asce needs fixup / uaccess */ -#define TIF_PER_TRAP 6 /* deliver sigtrap on return to user */ -#define TIF_MCCK_PENDING 7 /* machine check handling is pending */ -#define TIF_SYSCALL_TRACE 8 /* syscall trace active */ -#define TIF_SYSCALL_AUDIT 9 /* syscall auditing active */ -#define TIF_SECCOMP 10 /* secure computing */ -#define TIF_SYSCALL_TRACEPOINT 11 /* syscall tracepoint instrumentation */ -#define TIF_31BIT 17 /* 32bit process */ -#define TIF_MEMDIE 18 /* is terminating due to OOM killer */ -#define TIF_RESTORE_SIGMASK 19 /* restore signal mask in do_signal() */ -#define TIF_SINGLE_STEP 20 /* This task is single stepped */ -#define TIF_BLOCK_STEP 21 /* This task is block stepped */ +#define TIF_NOTIFY_RESUME 0 /* callback before returning to user */ +#define TIF_SIGPENDING 1 /* signal pending */ +#define TIF_NEED_RESCHED 2 /* rescheduling necessary */ +#define TIF_SYSCALL_TRACE 3 /* syscall trace active */ +#define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */ +#define TIF_SECCOMP 5 /* secure computing */ +#define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */ +#define TIF_31BIT 16 /* 32bit process */ +#define TIF_MEMDIE 17 /* is terminating due to OOM killer */ +#define TIF_RESTORE_SIGMASK 18 /* restore signal mask in do_signal() */ +#define TIF_SINGLE_STEP 19 /* This task is single stepped */ +#define TIF_BLOCK_STEP 20 /* This task is block stepped */ -#define _TIF_SYSCALL (1< #endif /* _ASM_S390_TOPOLOGY_H */ diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index 1be64a1506d016..cd4c68e0398dd9 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h @@ -132,6 +132,34 @@ unsigned long __must_check __copy_to_user(void __user *to, const void *from, #define __copy_to_user_inatomic __copy_to_user #define __copy_from_user_inatomic __copy_from_user +#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES + +#define __put_get_user_asm(to, from, size, spec) \ +({ \ + register unsigned long __reg0 asm("0") = spec; \ + int __rc; \ + \ + asm volatile( \ + "0: mvcos %1,%3,%2\n" \ + "1: xr %0,%0\n" \ + "2:\n" \ + ".pushsection .fixup, \"ax\"\n" \ + "3: lhi %0,%5\n" \ + " jg 2b\n" \ + ".popsection\n" \ + EX_TABLE(0b,3b) EX_TABLE(1b,3b) \ + : "=d" (__rc), "=Q" (*(to)) \ + : "d" (size), "Q" (*(from)), \ + "d" (__reg0), "K" (-EFAULT) \ + : "cc"); \ + __rc; \ +}) + +#define __put_user_fn(x, ptr, size) __put_get_user_asm(ptr, x, size, 0x810000UL) +#define __get_user_fn(x, ptr, size) __put_get_user_asm(x, ptr, size, 0x81UL) + +#else /* CONFIG_HAVE_MARCH_Z10_FEATURES */ + static inline int __put_user_fn(void *x, void __user *ptr, unsigned long size) { size = __copy_to_user(ptr, x, size); @@ -144,6 +172,8 @@ static inline int __get_user_fn(void *x, const void __user *ptr, unsigned long s return size ? -EFAULT : 0; } +#endif /* CONFIG_HAVE_MARCH_Z10_FEATURES */ + /* * These are the main single-value transfer routines. They automatically * use the right size if we just have the right pointer type. diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index c003c6a73b1e3e..0fc26430a1e5e6 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -15,6 +15,7 @@ #include #define __KVM_S390 +#define __KVM_HAVE_GUEST_DEBUG /* Device control API: s390-specific devices */ #define KVM_DEV_FLIC_GET_ALL_IRQS 1 @@ -54,6 +55,13 @@ struct kvm_s390_io_adapter_req { __u64 addr; }; +/* kvm attr_group on vm fd */ +#define KVM_S390_VM_MEM_CTRL 0 + +/* kvm attributes for mem_ctrl */ +#define KVM_S390_VM_MEM_ENABLE_CMMA 0 +#define KVM_S390_VM_MEM_CLR_CMMA 1 + /* for KVM_GET_REGS and KVM_SET_REGS */ struct kvm_regs { /* general purpose regs for s390 */ @@ -72,11 +80,31 @@ struct kvm_fpu { __u64 fprs[16]; }; +#define KVM_GUESTDBG_USE_HW_BP 0x00010000 + +#define KVM_HW_BP 1 +#define KVM_HW_WP_WRITE 2 +#define KVM_SINGLESTEP 4 + struct kvm_debug_exit_arch { + __u64 addr; + __u8 type; + __u8 pad[7]; /* Should be set to 0 */ +}; + +struct kvm_hw_breakpoint { + __u64 addr; + __u64 phys_addr; + __u64 len; + __u8 type; + __u8 pad[7]; /* Should be set to 0 */ }; /* for KVM_SET_GUEST_DEBUG */ struct kvm_guest_debug_arch { + __u32 nr_hw_bp; + __u32 pad; /* Should be set to 0 */ + struct kvm_hw_breakpoint __user *hw_bp; }; #define KVM_SYNC_PREFIX (1UL << 0) diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index cc10cdd4d6a24c..1d90005d6e461a 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -50,6 +50,7 @@ int main(void) DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code)); DEFINE(__PT_INT_PARM, offsetof(struct pt_regs, int_parm)); DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long)); + DEFINE(__PT_FLAGS, offsetof(struct pt_regs, flags)); DEFINE(__PT_SIZE, sizeof(struct pt_regs)); BLANK(); DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain)); @@ -89,16 +90,22 @@ int main(void) DEFINE(__LC_PGM_ILC, offsetof(struct _lowcore, pgm_ilc)); DEFINE(__LC_PGM_INT_CODE, offsetof(struct _lowcore, pgm_code)); DEFINE(__LC_TRANS_EXC_CODE, offsetof(struct _lowcore, trans_exc_code)); - DEFINE(__LC_PER_CAUSE, offsetof(struct _lowcore, per_perc_atmid)); + DEFINE(__LC_MON_CLASS_NR, offsetof(struct _lowcore, mon_class_num)); + DEFINE(__LC_PER_CODE, offsetof(struct _lowcore, per_code)); + DEFINE(__LC_PER_ATMID, offsetof(struct _lowcore, per_atmid)); DEFINE(__LC_PER_ADDRESS, offsetof(struct _lowcore, per_address)); - DEFINE(__LC_PER_PAID, offsetof(struct _lowcore, per_access_id)); - DEFINE(__LC_AR_MODE_ID, offsetof(struct _lowcore, ar_access_id)); + DEFINE(__LC_EXC_ACCESS_ID, offsetof(struct _lowcore, exc_access_id)); + DEFINE(__LC_PER_ACCESS_ID, offsetof(struct _lowcore, per_access_id)); + DEFINE(__LC_OP_ACCESS_ID, offsetof(struct _lowcore, op_access_id)); + DEFINE(__LC_AR_MODE_ID, offsetof(struct _lowcore, ar_mode_id)); + DEFINE(__LC_MON_CODE, offsetof(struct _lowcore, monitor_code)); DEFINE(__LC_SUBCHANNEL_ID, offsetof(struct _lowcore, subchannel_id)); DEFINE(__LC_SUBCHANNEL_NR, offsetof(struct _lowcore, subchannel_nr)); DEFINE(__LC_IO_INT_PARM, offsetof(struct _lowcore, io_int_parm)); DEFINE(__LC_IO_INT_WORD, offsetof(struct _lowcore, io_int_word)); DEFINE(__LC_STFL_FAC_LIST, offsetof(struct _lowcore, stfl_fac_list)); DEFINE(__LC_MCCK_CODE, offsetof(struct _lowcore, mcck_interruption_code)); + DEFINE(__LC_MCCK_EXT_DAM_CODE, offsetof(struct _lowcore, external_damage_code)); DEFINE(__LC_RST_OLD_PSW, offsetof(struct _lowcore, restart_old_psw)); DEFINE(__LC_EXT_OLD_PSW, offsetof(struct _lowcore, external_old_psw)); DEFINE(__LC_SVC_OLD_PSW, offsetof(struct _lowcore, svc_old_psw)); @@ -115,6 +122,7 @@ int main(void) DEFINE(__LC_SAVE_AREA_SYNC, offsetof(struct _lowcore, save_area_sync)); DEFINE(__LC_SAVE_AREA_ASYNC, offsetof(struct _lowcore, save_area_async)); DEFINE(__LC_SAVE_AREA_RESTART, offsetof(struct _lowcore, save_area_restart)); + DEFINE(__LC_CPU_FLAGS, offsetof(struct _lowcore, cpu_flags)); DEFINE(__LC_RETURN_PSW, offsetof(struct _lowcore, return_psw)); DEFINE(__LC_RETURN_MCCK_PSW, offsetof(struct _lowcore, return_mcck_psw)); DEFINE(__LC_SYNC_ENTER_TIMER, offsetof(struct _lowcore, sync_enter_timer)); @@ -156,6 +164,8 @@ int main(void) #ifdef CONFIG_32BIT DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr)); #else /* CONFIG_32BIT */ + DEFINE(__LC_DATA_EXC_CODE, offsetof(struct _lowcore, data_exc_code)); + DEFINE(__LC_MCCK_FAIL_STOR_ADDR, offsetof(struct _lowcore, failing_storage_address)); DEFINE(__LC_EXT_PARAMS2, offsetof(struct _lowcore, ext_params2)); DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, floating_pt_save_area)); DEFINE(__LC_PASTE, offsetof(struct _lowcore, paste)); diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 7df5ed9f44d7c2..f204d692036836 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -213,7 +213,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs) sizeof(current->thread.fp_regs)); restore_fp_regs(current->thread.fp_regs.fprs); - clear_thread_flag(TIF_SYSCALL); /* No longer in a system call */ + clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */ return 0; } diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index d7658c4b2ed581..a3b9150e680297 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,24 @@ #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) #define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y)))) +static struct memblock_region oldmem_region; + +static struct memblock_type oldmem_type = { + .cnt = 1, + .max = 1, + .total_size = 0, + .regions = &oldmem_region, +}; + +#define for_each_dump_mem_range(i, nid, p_start, p_end, p_nid) \ + for (i = 0, __next_mem_range(&i, nid, &memblock.physmem, \ + &oldmem_type, p_start, \ + p_end, p_nid); \ + i != (u64)ULLONG_MAX; \ + __next_mem_range(&i, nid, &memblock.physmem, \ + &oldmem_type, \ + p_start, p_end, p_nid)) + struct dump_save_areas dump_save_areas; /* @@ -263,19 +282,6 @@ static void *kzalloc_panic(int len) return rc; } -/* - * Get memory layout and create hole for oldmem - */ -static struct mem_chunk *get_memory_layout(void) -{ - struct mem_chunk *chunk_array; - - chunk_array = kzalloc_panic(MEMORY_CHUNKS * sizeof(struct mem_chunk)); - detect_memory_layout(chunk_array, 0); - create_mem_hole(chunk_array, OLDMEM_BASE, OLDMEM_SIZE); - return chunk_array; -} - /* * Initialize ELF note */ @@ -490,52 +496,33 @@ static int get_cpu_cnt(void) */ static int get_mem_chunk_cnt(void) { - struct mem_chunk *chunk_array, *mem_chunk; - int i, cnt = 0; + int cnt = 0; + u64 idx; - chunk_array = get_memory_layout(); - for (i = 0; i < MEMORY_CHUNKS; i++) { - mem_chunk = &chunk_array[i]; - if (chunk_array[i].type != CHUNK_READ_WRITE && - chunk_array[i].type != CHUNK_READ_ONLY) - continue; - if (mem_chunk->size == 0) - continue; + for_each_dump_mem_range(idx, NUMA_NO_NODE, NULL, NULL, NULL) cnt++; - } - kfree(chunk_array); return cnt; } /* * Initialize ELF loads (new kernel) */ -static int loads_init(Elf64_Phdr *phdr, u64 loads_offset) +static void loads_init(Elf64_Phdr *phdr, u64 loads_offset) { - struct mem_chunk *chunk_array, *mem_chunk; - int i; + phys_addr_t start, end; + u64 idx; - chunk_array = get_memory_layout(); - for (i = 0; i < MEMORY_CHUNKS; i++) { - mem_chunk = &chunk_array[i]; - if (mem_chunk->size == 0) - continue; - if (chunk_array[i].type != CHUNK_READ_WRITE && - chunk_array[i].type != CHUNK_READ_ONLY) - continue; - else - phdr->p_filesz = mem_chunk->size; + for_each_dump_mem_range(idx, NUMA_NO_NODE, &start, &end, NULL) { + phdr->p_filesz = end - start; phdr->p_type = PT_LOAD; - phdr->p_offset = mem_chunk->addr; - phdr->p_vaddr = mem_chunk->addr; - phdr->p_paddr = mem_chunk->addr; - phdr->p_memsz = mem_chunk->size; + phdr->p_offset = start; + phdr->p_vaddr = start; + phdr->p_paddr = start; + phdr->p_memsz = end - start; phdr->p_flags = PF_R | PF_W | PF_X; phdr->p_align = PAGE_SIZE; phdr++; } - kfree(chunk_array); - return i; } /* @@ -584,6 +571,14 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size) /* If we cannot get HSA size for zfcpdump return error */ if (ipl_info.type == IPL_TYPE_FCP_DUMP && !sclp_get_hsa_size()) return -ENODEV; + + /* For kdump, exclude previous crashkernel memory */ + if (OLDMEM_BASE) { + oldmem_region.base = OLDMEM_BASE; + oldmem_region.size = OLDMEM_SIZE; + oldmem_type.total_size = OLDMEM_SIZE; + } + mem_chunk_cnt = get_mem_chunk_cnt(); alloc_size = 0x1000 + get_cpu_cnt() * 0x300 + diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index a734f3585cebdd..0dff972a169c16 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -258,13 +258,19 @@ static __init void setup_topology(void) static void early_pgm_check_handler(void) { const struct exception_table_entry *fixup; + unsigned long cr0, cr0_new; unsigned long addr; addr = S390_lowcore.program_old_psw.addr; fixup = search_exception_tables(addr & PSW_ADDR_INSN); if (!fixup) disabled_wait(0); + /* Disable low address protection before storing into lowcore. */ + __ctl_store(cr0, 0, 0); + cr0_new = cr0 & ~(1UL << 28); + __ctl_load(cr0_new, 0, 0); S390_lowcore.program_old_psw.addr = extable_fixup(fixup)|PSW_ADDR_AMODE; + __ctl_load(cr0, 0, 0); } static noinline __init void setup_lowcore_early(void) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 1662038516c0db..70203265196fa7 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -37,18 +38,16 @@ __PT_R13 = __PT_GPRS + 524 __PT_R14 = __PT_GPRS + 56 __PT_R15 = __PT_GPRS + 60 -_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ - _TIF_MCCK_PENDING | _TIF_PER_TRAP | _TIF_ASCE) -_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ - _TIF_MCCK_PENDING | _TIF_ASCE) -_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ - _TIF_SYSCALL_TRACEPOINT) -_TIF_TRANSFER = (_TIF_MCCK_PENDING | _TIF_TLB_WAIT) - STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER STACK_SIZE = 1 << STACK_SHIFT STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE +_TIF_WORK = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED) +_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ + _TIF_SYSCALL_TRACEPOINT) +_CIF_WORK = (_CIF_MCCK_PENDING | _CIF_ASCE) +_PIF_WORK = (_PIF_PER_TRAP) + #define BASED(name) name-system_call(%r13) .macro TRACE_IRQS_ON @@ -160,13 +159,7 @@ ENTRY(__switch_to) lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next l %r15,__THREAD_ksp(%r3) # load kernel stack of next - lhi %r6,_TIF_TRANSFER # transfer TIF bits - n %r6,__TI_flags(%r4) # isolate TIF bits - jz 0f - o %r6,__TI_flags(%r5) # set TIF bits of next - st %r6,__TI_flags(%r5) - ni __TI_flags+3(%r4),255-_TIF_TRANSFER # clear TIF bits of prev -0: lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task + lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task br %r14 __critical_start: @@ -181,6 +174,7 @@ sysc_stm: stm %r8,%r15,__LC_SAVE_AREA_SYNC l %r12,__LC_THREAD_INFO l %r13,__LC_SVC_NEW_PSW+4 + lhi %r14,_PIF_SYSCALL sysc_per: l %r15,__LC_KERNEL_STACK la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs @@ -190,8 +184,8 @@ sysc_vtime: mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC mvc __PT_PSW(8,%r11),__LC_SVC_OLD_PSW mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC + st %r14,__PT_FLAGS(%r11) sysc_do_svc: - oi __TI_flags+3(%r12),_TIF_SYSCALL l %r10,__TI_sysc_table(%r12) # 31 bit system call table lh %r8,__PT_INT_CODE+2(%r11) sla %r8,2 # shift and test for svc0 @@ -207,7 +201,7 @@ sysc_nr_ok: st %r2,__PT_ORIG_GPR2(%r11) st %r7,STACK_FRAME_OVERHEAD(%r15) l %r9,0(%r8,%r10) # get system call addr. - tm __TI_flags+2(%r12),_TIF_TRACE >> 8 + tm __TI_flags+3(%r12),_TIF_TRACE jnz sysc_tracesys basr %r14,%r9 # call sys_xxxx st %r2,__PT_R2(%r11) # store return value @@ -217,9 +211,12 @@ sysc_return: sysc_tif: tm __PT_PSW+1(%r11),0x01 # returning to user ? jno sysc_restore - tm __TI_flags+3(%r12),_TIF_WORK_SVC - jnz sysc_work # check for work - ni __TI_flags+3(%r12),255-_TIF_SYSCALL + tm __PT_FLAGS+3(%r11),_PIF_WORK + jnz sysc_work + tm __TI_flags+3(%r12),_TIF_WORK + jnz sysc_work # check for thread work + tm __LC_CPU_FLAGS+3,_CIF_WORK + jnz sysc_work sysc_restore: mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) stpt __LC_EXIT_TIMER @@ -231,17 +228,17 @@ sysc_done: # One of the work bits is on. Find out which one. # sysc_work: - tm __TI_flags+3(%r12),_TIF_MCCK_PENDING + tm __LC_CPU_FLAGS+3,_CIF_MCCK_PENDING jo sysc_mcck_pending tm __TI_flags+3(%r12),_TIF_NEED_RESCHED jo sysc_reschedule - tm __TI_flags+3(%r12),_TIF_PER_TRAP + tm __PT_FLAGS+3(%r11),_PIF_PER_TRAP jo sysc_singlestep tm __TI_flags+3(%r12),_TIF_SIGPENDING jo sysc_sigpending tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME jo sysc_notify_resume - tm __TI_flags+3(%r12),_TIF_ASCE + tm __LC_CPU_FLAGS+3,_CIF_ASCE jo sysc_uaccess j sysc_return # beware of critical section cleanup @@ -254,7 +251,7 @@ sysc_reschedule: br %r1 # call schedule # -# _TIF_MCCK_PENDING is set, call handler +# _CIF_MCCK_PENDING is set, call handler # sysc_mcck_pending: l %r1,BASED(.Lhandle_mcck) @@ -262,10 +259,10 @@ sysc_mcck_pending: br %r1 # TIF bit will be cleared by handler # -# _TIF_ASCE is set, load user space asce +# _CIF_ASCE is set, load user space asce # sysc_uaccess: - ni __TI_flags+3(%r12),255-_TIF_ASCE + ni __LC_CPU_FLAGS+3,255-_CIF_ASCE lctl %c1,%c1,__LC_USER_ASCE # load primary asce j sysc_return @@ -276,7 +273,7 @@ sysc_sigpending: lr %r2,%r11 # pass pointer to pt_regs l %r1,BASED(.Ldo_signal) basr %r14,%r1 # call do_signal - tm __TI_flags+3(%r12),_TIF_SYSCALL + tm __PT_FLAGS+3(%r11),_PIF_SYSCALL jno sysc_return lm %r2,%r7,__PT_R2(%r11) # load svc arguments l %r10,__TI_sysc_table(%r12) # 31 bit system call table @@ -297,10 +294,10 @@ sysc_notify_resume: br %r1 # call do_notify_resume # -# _TIF_PER_TRAP is set, call do_per_trap +# _PIF_PER_TRAP is set, call do_per_trap # sysc_singlestep: - ni __TI_flags+3(%r12),255-_TIF_PER_TRAP + ni __PT_FLAGS+3(%r11),255-_PIF_PER_TRAP lr %r2,%r11 # pass pointer to pt_regs l %r1,BASED(.Ldo_per_trap) la %r14,BASED(sysc_return) @@ -330,7 +327,7 @@ sysc_tracego: basr %r14,%r9 # call sys_xxx st %r2,__PT_R2(%r11) # store return value sysc_tracenogo: - tm __TI_flags+2(%r12),_TIF_TRACE >> 8 + tm __TI_flags+3(%r12),_TIF_TRACE jz sysc_return l %r1,BASED(.Ltrace_exit) lr %r2,%r11 # pass pointer to pt_regs @@ -384,15 +381,16 @@ ENTRY(pgm_check_handler) stm %r8,%r9,__PT_PSW(%r11) mvc __PT_INT_CODE(4,%r11),__LC_PGM_ILC mvc __PT_INT_PARM_LONG(4,%r11),__LC_TRANS_EXC_CODE + xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) tm __LC_PGM_ILC+3,0x80 # check for per exception jz 0f l %r1,__TI_task(%r12) tmh %r8,0x0001 # kernel per event ? jz pgm_kprobe - oi __TI_flags+3(%r12),_TIF_PER_TRAP + oi __PT_FLAGS+3(%r11),_PIF_PER_TRAP mvc __THREAD_per_address(4,%r1),__LC_PER_ADDRESS - mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE - mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID + mvc __THREAD_per_cause(2,%r1),__LC_PER_CODE + mvc __THREAD_per_paid(1,%r1),__LC_PER_ACCESS_ID 0: REENABLE_IRQS xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) l %r1,BASED(.Ljump_table) @@ -420,9 +418,9 @@ pgm_kprobe: # single stepped system call # pgm_svcper: - oi __TI_flags+3(%r12),_TIF_PER_TRAP mvc __LC_RETURN_PSW(4),__LC_SVC_NEW_PSW mvc __LC_RETURN_PSW+4(4),BASED(.Lsysc_per) + lhi %r14,_PIF_SYSCALL | _PIF_PER_TRAP lpsw __LC_RETURN_PSW # branch to sysc_per and enable irqs /* @@ -445,6 +443,7 @@ io_skip: mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC stm %r8,%r9,__PT_PSW(%r11) mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID + xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) TRACE_IRQS_OFF xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) io_loop: @@ -466,8 +465,10 @@ io_return: LOCKDEP_SYS_EXIT TRACE_IRQS_ON io_tif: - tm __TI_flags+3(%r12),_TIF_WORK_INT + tm __TI_flags+3(%r12),_TIF_WORK jnz io_work # there is work to do (signals etc.) + tm __LC_CPU_FLAGS+3,_CIF_WORK + jnz io_work io_restore: mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) stpt __LC_EXIT_TIMER @@ -477,7 +478,7 @@ io_done: # # There is work todo, find out in which context we have been interrupted: -# 1) if we return to user space we can do all _TIF_WORK_INT work +# 1) if we return to user space we can do all _TIF_WORK work # 2) if we return to kernel code and preemptive scheduling is enabled check # the preemption counter and if it is zero call preempt_schedule_irq # Before any work can be done, a switch to the kernel stack is required. @@ -520,11 +521,9 @@ io_work_user: # # One of the work bits is on. Find out which one. -# Checked are: _TIF_SIGPENDING, _TIF_NOTIFY_RESUME, _TIF_NEED_RESCHED -# and _TIF_MCCK_PENDING # io_work_tif: - tm __TI_flags+3(%r12),_TIF_MCCK_PENDING + tm __LC_CPU_FLAGS+3(%r12),_CIF_MCCK_PENDING jo io_mcck_pending tm __TI_flags+3(%r12),_TIF_NEED_RESCHED jo io_reschedule @@ -532,12 +531,12 @@ io_work_tif: jo io_sigpending tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME jo io_notify_resume - tm __TI_flags+3(%r12),_TIF_ASCE + tm __LC_CPU_FLAGS+3,_CIF_ASCE jo io_uaccess j io_return # beware of critical section cleanup # -# _TIF_MCCK_PENDING is set, call handler +# _CIF_MCCK_PENDING is set, call handler # io_mcck_pending: # TRACE_IRQS_ON already done at io_return @@ -547,10 +546,10 @@ io_mcck_pending: j io_return # -# _TIF_ASCE is set, load user space asce +# _CIF_ASCE is set, load user space asce # io_uaccess: - ni __TI_flags+3(%r12),255-_TIF_ASCE + ni __LC_CPU_FLAGS+3,255-_CIF_ASCE lctl %c1,%c1,__LC_USER_ASCE # load primary asce j io_return @@ -613,6 +612,7 @@ ext_skip: stm %r8,%r9,__PT_PSW(%r11) mvc __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS + xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) TRACE_IRQS_OFF l %r1,BASED(.Ldo_IRQ) lr %r2,%r11 # pass pointer to pt_regs @@ -677,6 +677,7 @@ mcck_skip: stm %r0,%r7,__PT_R0(%r11) mvc __PT_R8(32,%r11),__LC_GPREGS_SAVE_AREA+32 stm %r8,%r9,__PT_PSW(%r11) + xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) l %r1,BASED(.Ldo_machine_check) lr %r2,%r11 # pass pointer to pt_regs @@ -689,7 +690,7 @@ mcck_skip: la %r11,STACK_FRAME_OVERHEAD(%r15) lr %r15,%r1 ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off - tm __TI_flags+3(%r12),_TIF_MCCK_PENDING + tm __LC_CPU_FLAGS+3,_CIF_MCCK_PENDING jno mcck_return TRACE_IRQS_OFF l %r1,BASED(.Lhandle_mcck) @@ -842,6 +843,8 @@ cleanup_system_call: stm %r0,%r7,__PT_R0(%r9) mvc __PT_PSW(8,%r9),__LC_SVC_OLD_PSW mvc __PT_INT_CODE(4,%r9),__LC_SVC_ILC + xc __PT_FLAGS(4,%r9),__PT_FLAGS(%r9) + mvi __PT_FLAGS+3(%r9),_PIF_SYSCALL # setup saved register 15 st %r15,28(%r11) # r15 stack pointer # set new psw address and exit diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 5963e43618bb0d..f2e674c702e1f9 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -42,13 +42,11 @@ STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER STACK_SIZE = 1 << STACK_SHIFT STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE -_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ - _TIF_MCCK_PENDING | _TIF_PER_TRAP | _TIF_ASCE) -_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ - _TIF_MCCK_PENDING | _TIF_ASCE) -_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ - _TIF_SYSCALL_TRACEPOINT) -_TIF_TRANSFER = (_TIF_MCCK_PENDING | _TIF_TLB_WAIT) +_TIF_WORK = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED) +_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ + _TIF_SYSCALL_TRACEPOINT) +_CIF_WORK = (_CIF_MCCK_PENDING | _CIF_ASCE) +_PIF_WORK = (_PIF_PER_TRAP) #define BASED(name) name-system_call(%r13) @@ -190,13 +188,7 @@ ENTRY(__switch_to) lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 mvc __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next lg %r15,__THREAD_ksp(%r3) # load kernel stack of next - llill %r6,_TIF_TRANSFER # transfer TIF bits - ng %r6,__TI_flags(%r4) # isolate TIF bits - jz 0f - og %r6,__TI_flags(%r5) # set TIF bits of next - stg %r6,__TI_flags(%r5) - ni __TI_flags+7(%r4),255-_TIF_TRANSFER # clear TIF bits of prev -0: lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task + lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task br %r14 __critical_start: @@ -211,6 +203,7 @@ sysc_stmg: stmg %r8,%r15,__LC_SAVE_AREA_SYNC lg %r10,__LC_LAST_BREAK lg %r12,__LC_THREAD_INFO + lghi %r14,_PIF_SYSCALL sysc_per: lg %r15,__LC_KERNEL_STACK la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs @@ -221,8 +214,8 @@ sysc_vtime: mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC + stg %r14,__PT_FLAGS(%r11) sysc_do_svc: - oi __TI_flags+7(%r12),_TIF_SYSCALL lg %r10,__TI_sysc_table(%r12) # address of system call table llgh %r8,__PT_INT_CODE+2(%r11) slag %r8,%r8,2 # shift and test for svc 0 @@ -238,7 +231,7 @@ sysc_nr_ok: stg %r2,__PT_ORIG_GPR2(%r11) stg %r7,STACK_FRAME_OVERHEAD(%r15) lgf %r9,0(%r8,%r10) # get system call add. - tm __TI_flags+6(%r12),_TIF_TRACE >> 8 + tm __TI_flags+7(%r12),_TIF_TRACE jnz sysc_tracesys basr %r14,%r9 # call sys_xxxx stg %r2,__PT_R2(%r11) # store return value @@ -248,9 +241,12 @@ sysc_return: sysc_tif: tm __PT_PSW+1(%r11),0x01 # returning to user ? jno sysc_restore - tm __TI_flags+7(%r12),_TIF_WORK_SVC + tm __PT_FLAGS+7(%r11),_PIF_WORK + jnz sysc_work + tm __TI_flags+7(%r12),_TIF_WORK jnz sysc_work # check for work - ni __TI_flags+7(%r12),255-_TIF_SYSCALL + tm __LC_CPU_FLAGS+7,_CIF_WORK + jnz sysc_work sysc_restore: lg %r14,__LC_VDSO_PER_CPU lmg %r0,%r10,__PT_R0(%r11) @@ -265,17 +261,17 @@ sysc_done: # One of the work bits is on. Find out which one. # sysc_work: - tm __TI_flags+7(%r12),_TIF_MCCK_PENDING + tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING jo sysc_mcck_pending tm __TI_flags+7(%r12),_TIF_NEED_RESCHED jo sysc_reschedule - tm __TI_flags+7(%r12),_TIF_PER_TRAP + tm __PT_FLAGS+7(%r11),_PIF_PER_TRAP jo sysc_singlestep tm __TI_flags+7(%r12),_TIF_SIGPENDING jo sysc_sigpending tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME jo sysc_notify_resume - tm __TI_flags+7(%r12),_TIF_ASCE + tm __LC_CPU_FLAGS+7,_CIF_ASCE jo sysc_uaccess j sysc_return # beware of critical section cleanup @@ -287,17 +283,17 @@ sysc_reschedule: jg schedule # -# _TIF_MCCK_PENDING is set, call handler +# _CIF_MCCK_PENDING is set, call handler # sysc_mcck_pending: larl %r14,sysc_return jg s390_handle_mcck # TIF bit will be cleared by handler # -# _TIF_ASCE is set, load user space asce +# _CIF_ASCE is set, load user space asce # sysc_uaccess: - ni __TI_flags+7(%r12),255-_TIF_ASCE + ni __LC_CPU_FLAGS+7,255-_CIF_ASCE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce j sysc_return @@ -307,7 +303,7 @@ sysc_uaccess: sysc_sigpending: lgr %r2,%r11 # pass pointer to pt_regs brasl %r14,do_signal - tm __TI_flags+7(%r12),_TIF_SYSCALL + tm __PT_FLAGS+7(%r11),_PIF_SYSCALL jno sysc_return lmg %r2,%r7,__PT_R2(%r11) # load svc arguments lg %r10,__TI_sysc_table(%r12) # address of system call table @@ -327,10 +323,10 @@ sysc_notify_resume: jg do_notify_resume # -# _TIF_PER_TRAP is set, call do_per_trap +# _PIF_PER_TRAP is set, call do_per_trap # sysc_singlestep: - ni __TI_flags+7(%r12),255-_TIF_PER_TRAP + ni __PT_FLAGS+7(%r11),255-_PIF_PER_TRAP lgr %r2,%r11 # pass pointer to pt_regs larl %r14,sysc_return jg do_per_trap @@ -357,7 +353,7 @@ sysc_tracego: basr %r14,%r9 # call sys_xxx stg %r2,__PT_R2(%r11) # store return value sysc_tracenogo: - tm __TI_flags+6(%r12),_TIF_TRACE >> 8 + tm __TI_flags+7(%r12),_TIF_TRACE jz sysc_return lgr %r2,%r11 # pass pointer to pt_regs larl %r14,sysc_return @@ -416,15 +412,16 @@ ENTRY(pgm_check_handler) stmg %r8,%r9,__PT_PSW(%r11) mvc __PT_INT_CODE(4,%r11),__LC_PGM_ILC mvc __PT_INT_PARM_LONG(8,%r11),__LC_TRANS_EXC_CODE + xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) stg %r10,__PT_ARGS(%r11) tm __LC_PGM_ILC+3,0x80 # check for per exception jz 0f tmhh %r8,0x0001 # kernel per event ? jz pgm_kprobe - oi __TI_flags+7(%r12),_TIF_PER_TRAP + oi __PT_FLAGS+7(%r11),_PIF_PER_TRAP mvc __THREAD_per_address(8,%r14),__LC_PER_ADDRESS - mvc __THREAD_per_cause(2,%r14),__LC_PER_CAUSE - mvc __THREAD_per_paid(1,%r14),__LC_PER_PAID + mvc __THREAD_per_cause(2,%r14),__LC_PER_CODE + mvc __THREAD_per_paid(1,%r14),__LC_PER_ACCESS_ID 0: REENABLE_IRQS xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) larl %r1,pgm_check_table @@ -451,10 +448,10 @@ pgm_kprobe: # single stepped system call # pgm_svcper: - oi __TI_flags+7(%r12),_TIF_PER_TRAP mvc __LC_RETURN_PSW(8),__LC_SVC_NEW_PSW larl %r14,sysc_per stg %r14,__LC_RETURN_PSW+8 + lghi %r14,_PIF_SYSCALL | _PIF_PER_TRAP lpswe __LC_RETURN_PSW # branch to sysc_per and enable irqs /* @@ -479,6 +476,7 @@ io_skip: mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC stmg %r8,%r9,__PT_PSW(%r11) mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID + xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) TRACE_IRQS_OFF xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) io_loop: @@ -499,8 +497,10 @@ io_return: LOCKDEP_SYS_EXIT TRACE_IRQS_ON io_tif: - tm __TI_flags+7(%r12),_TIF_WORK_INT + tm __TI_flags+7(%r12),_TIF_WORK jnz io_work # there is work to do (signals etc.) + tm __LC_CPU_FLAGS+7,_CIF_WORK + jnz io_work io_restore: lg %r14,__LC_VDSO_PER_CPU lmg %r0,%r10,__PT_R0(%r11) @@ -513,7 +513,7 @@ io_done: # # There is work todo, find out in which context we have been interrupted: -# 1) if we return to user space we can do all _TIF_WORK_INT work +# 1) if we return to user space we can do all _TIF_WORK work # 2) if we return to kernel code and kvm is enabled check if we need to # modify the psw to leave SIE # 3) if we return to kernel code and preemptive scheduling is enabled check @@ -557,11 +557,9 @@ io_work_user: # # One of the work bits is on. Find out which one. -# Checked are: _TIF_SIGPENDING, _TIF_NOTIFY_RESUME, _TIF_NEED_RESCHED -# and _TIF_MCCK_PENDING # io_work_tif: - tm __TI_flags+7(%r12),_TIF_MCCK_PENDING + tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING jo io_mcck_pending tm __TI_flags+7(%r12),_TIF_NEED_RESCHED jo io_reschedule @@ -569,12 +567,12 @@ io_work_tif: jo io_sigpending tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME jo io_notify_resume - tm __TI_flags+7(%r12),_TIF_ASCE + tm __LC_CPU_FLAGS+7,_CIF_ASCE jo io_uaccess j io_return # beware of critical section cleanup # -# _TIF_MCCK_PENDING is set, call handler +# _CIF_MCCK_PENDING is set, call handler # io_mcck_pending: # TRACE_IRQS_ON already done at io_return @@ -583,10 +581,10 @@ io_mcck_pending: j io_return # -# _TIF_ASCE is set, load user space asce +# _CIF_ASCE is set, load user space asce # io_uaccess: - ni __TI_flags+7(%r12),255-_TIF_ASCE + ni __LC_CPU_FLAGS+7,255-_CIF_ASCE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce j io_return @@ -650,6 +648,7 @@ ext_skip: mvc __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS mvc __PT_INT_PARM_LONG(8,%r11),0(%r1) + xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) TRACE_IRQS_OFF xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) lgr %r2,%r11 # pass pointer to pt_regs @@ -716,6 +715,7 @@ mcck_skip: stmg %r0,%r7,__PT_R0(%r11) mvc __PT_R8(64,%r11),0(%r14) stmg %r8,%r9,__PT_PSW(%r11) + xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) lgr %r2,%r11 # pass pointer to pt_regs brasl %r14,s390_do_machine_check @@ -727,7 +727,7 @@ mcck_skip: la %r11,STACK_FRAME_OVERHEAD(%r1) lgr %r15,%r1 ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off - tm __TI_flags+7(%r12),_TIF_MCCK_PENDING + tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING jno mcck_return TRACE_IRQS_OFF brasl %r14,s390_handle_mcck @@ -884,6 +884,8 @@ cleanup_system_call: stmg %r0,%r7,__PT_R0(%r9) mvc __PT_PSW(16,%r9),__LC_SVC_OLD_PSW mvc __PT_INT_CODE(4,%r9),__LC_SVC_ILC + xc __PT_FLAGS(8,%r9),__PT_FLAGS(%r9) + mvi __PT_FLAGS+7(%r9),_PIF_SYSCALL # setup saved register r15 stg %r15,56(%r11) # r15 stack pointer # set new psw address and exit diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index 9a99856df1c93e..6dbe80983a24fc 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -59,7 +59,6 @@ ENTRY(startup_continue) .long 0 # cr13: home space segment table .long 0xc0000000 # cr14: machine check handling off .long 0 # cr15: linkage stack operations -.Lmchunk:.long memory_chunk .Lbss_bgn: .long __bss_start .Lbss_end: .long _end .Lparmaddr: .long PARMAREA diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index c4c0338198791d..210e1285f75a44 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -55,7 +55,7 @@ void s390_handle_mcck(void) local_mcck_disable(); mcck = __get_cpu_var(cpu_mcck); memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct)); - clear_thread_flag(TIF_MCCK_PENDING); + clear_cpu_flag(CIF_MCCK_PENDING); local_mcck_enable(); local_irq_restore(flags); @@ -313,7 +313,7 @@ void notrace s390_do_machine_check(struct pt_regs *regs) */ mcck->kill_task = 1; mcck->mcck_code = *(unsigned long long *) mci; - set_thread_flag(TIF_MCCK_PENDING); + set_cpu_flag(CIF_MCCK_PENDING); } else { /* * Couldn't restore all register contents while in @@ -352,12 +352,12 @@ void notrace s390_do_machine_check(struct pt_regs *regs) if (mci->cp) { /* Channel report word pending */ mcck->channel_report = 1; - set_thread_flag(TIF_MCCK_PENDING); + set_cpu_flag(CIF_MCCK_PENDING); } if (mci->w) { /* Warning pending */ mcck->warning = 1; - set_thread_flag(TIF_MCCK_PENDING); + set_cpu_flag(CIF_MCCK_PENDING); } nmi_exit(); } diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index dd145321d2151d..93b9ca42e5c0ac 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -64,7 +64,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk) void arch_cpu_idle(void) { local_mcck_disable(); - if (test_thread_flag(TIF_MCCK_PENDING)) { + if (test_cpu_flag(CIF_MCCK_PENDING)) { local_mcck_enable(); local_irq_enable(); return; @@ -76,7 +76,7 @@ void arch_cpu_idle(void) void arch_cpu_idle_exit(void) { - if (test_thread_flag(TIF_MCCK_PENDING)) + if (test_cpu_flag(CIF_MCCK_PENDING)) s390_handle_mcck(); } @@ -123,7 +123,6 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, memset(&p->thread.per_user, 0, sizeof(p->thread.per_user)); memset(&p->thread.per_event, 0, sizeof(p->thread.per_event)); clear_tsk_thread_flag(p, TIF_SINGLE_STEP); - clear_tsk_thread_flag(p, TIF_PER_TRAP); /* Initialize per thread user and system timer values */ ti = task_thread_info(p); ti->user_timer = 0; @@ -152,6 +151,7 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, } frame->childregs = *current_pt_regs(); frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */ + frame->childregs.flags = 0; if (new_stackp) frame->childregs.gprs[15] = new_stackp; diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 1c82619eb4f768..8c3f72dfc54d58 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -136,7 +136,7 @@ void ptrace_disable(struct task_struct *task) memset(&task->thread.per_user, 0, sizeof(task->thread.per_user)); memset(&task->thread.per_event, 0, sizeof(task->thread.per_event)); clear_tsk_thread_flag(task, TIF_SINGLE_STEP); - clear_tsk_thread_flag(task, TIF_PER_TRAP); + clear_pt_regs_flag(task_pt_regs(task), PIF_PER_TRAP); task->thread.per_flags = 0; } @@ -813,16 +813,14 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) * debugger stored an invalid system call number. Skip * the system call and the system call restart handling. */ - clear_thread_flag(TIF_SYSCALL); + clear_pt_regs_flag(regs, PIF_SYSCALL); ret = -1; } if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->gprs[2]); - audit_syscall_entry(is_compat_task() ? - AUDIT_ARCH_S390 : AUDIT_ARCH_S390X, - regs->gprs[2], regs->orig_gpr2, + audit_syscall_entry(regs->gprs[2], regs->orig_gpr2, regs->gprs[3], regs->gprs[4], regs->gprs[5]); out: diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 88d1ca81e2dd7f..1e2264b46e4c1d 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -78,10 +78,9 @@ EXPORT_SYMBOL(console_irq); unsigned long elf_hwcap = 0; char elf_platform[ELF_PLATFORM_SIZE]; -struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; - int __initdata memory_end_set; unsigned long __initdata memory_end; +unsigned long __initdata max_physmem_end; unsigned long VMALLOC_START; EXPORT_SYMBOL(VMALLOC_START); @@ -212,7 +211,7 @@ static void __init conmode_default(void) } } -#ifdef CONFIG_ZFCPDUMP +#ifdef CONFIG_CRASH_DUMP static void __init setup_zfcpdump(void) { if (ipl_info.type != IPL_TYPE_FCP_DUMP) @@ -224,7 +223,7 @@ static void __init setup_zfcpdump(void) } #else static inline void setup_zfcpdump(void) {} -#endif /* CONFIG_ZFCPDUMP */ +#endif /* CONFIG_CRASH_DUMP */ /* * Reboot, halt and power_off stubs. They just call _machine_restart, @@ -273,6 +272,7 @@ EXPORT_SYMBOL_GPL(pm_power_off); static int __init early_parse_mem(char *p) { memory_end = memparse(p, &p); + memory_end &= PAGE_MASK; memory_end_set = 1; return 0; } @@ -373,6 +373,10 @@ static void __init setup_lowcore(void) mem_assign_absolute(S390_lowcore.restart_source, lc->restart_source); mem_assign_absolute(S390_lowcore.restart_psw, lc->restart_psw); +#ifdef CONFIG_SMP + lc->spinlock_lockval = arch_spin_lockval(0); +#endif + set_prefix((u32)(unsigned long) lc); lowcore_ptr[0] = lc; } @@ -401,7 +405,8 @@ static struct resource __initdata *standard_resources[] = { static void __init setup_resources(void) { struct resource *res, *std_res, *sub_res; - int i, j; + struct memblock_region *reg; + int j; code_resource.start = (unsigned long) &_text; code_resource.end = (unsigned long) &_etext - 1; @@ -410,24 +415,13 @@ static void __init setup_resources(void) bss_resource.start = (unsigned long) &__bss_start; bss_resource.end = (unsigned long) &__bss_stop - 1; - for (i = 0; i < MEMORY_CHUNKS; i++) { - if (!memory_chunk[i].size) - continue; + for_each_memblock(memory, reg) { res = alloc_bootmem_low(sizeof(*res)); res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; - switch (memory_chunk[i].type) { - case CHUNK_READ_WRITE: - res->name = "System RAM"; - break; - case CHUNK_READ_ONLY: - res->name = "System ROM"; - res->flags |= IORESOURCE_READONLY; - break; - default: - res->name = "reserved"; - } - res->start = memory_chunk[i].addr; - res->end = res->start + memory_chunk[i].size - 1; + + res->name = "System RAM"; + res->start = reg->base; + res->end = reg->base + reg->size - 1; request_resource(&iomem_resource, res); for (j = 0; j < ARRAY_SIZE(standard_resources); j++) { @@ -451,48 +445,11 @@ static void __init setup_resources(void) static void __init setup_memory_end(void) { unsigned long vmax, vmalloc_size, tmp; - unsigned long real_memory_size = 0; - int i; - - -#ifdef CONFIG_ZFCPDUMP - if (ipl_info.type == IPL_TYPE_FCP_DUMP && - !OLDMEM_BASE && sclp_get_hsa_size()) { - memory_end = sclp_get_hsa_size(); - memory_end_set = 1; - } -#endif - memory_end &= PAGE_MASK; - - /* - * Make sure all chunks are MAX_ORDER aligned so we don't need the - * extra checks that HOLES_IN_ZONE would require. - */ - for (i = 0; i < MEMORY_CHUNKS; i++) { - unsigned long start, end; - struct mem_chunk *chunk; - unsigned long align; - - chunk = &memory_chunk[i]; - if (!chunk->size) - continue; - align = 1UL << (MAX_ORDER + PAGE_SHIFT - 1); - start = (chunk->addr + align - 1) & ~(align - 1); - end = (chunk->addr + chunk->size) & ~(align - 1); - if (start >= end) - memset(chunk, 0, sizeof(*chunk)); - else { - chunk->addr = start; - chunk->size = end - start; - } - real_memory_size = max(real_memory_size, - chunk->addr + chunk->size); - } /* Choose kernel address space layout: 2, 3, or 4 levels. */ #ifdef CONFIG_64BIT vmalloc_size = VMALLOC_END ?: (128UL << 30) - MODULES_LEN; - tmp = (memory_end ?: real_memory_size) / PAGE_SIZE; + tmp = (memory_end ?: max_physmem_end) / PAGE_SIZE; tmp = tmp * (sizeof(struct page) + PAGE_SIZE) + vmalloc_size; if (tmp <= (1UL << 42)) vmax = 1UL << 42; /* 3-level kernel page table */ @@ -520,21 +477,11 @@ static void __init setup_memory_end(void) vmemmap = (struct page *) tmp; /* Take care that memory_end is set and <= vmemmap */ - memory_end = min(memory_end ?: real_memory_size, tmp); - - /* Fixup memory chunk array to fit into 0..memory_end */ - for (i = 0; i < MEMORY_CHUNKS; i++) { - struct mem_chunk *chunk = &memory_chunk[i]; + memory_end = min(memory_end ?: max_physmem_end, tmp); + max_pfn = max_low_pfn = PFN_DOWN(memory_end); + memblock_remove(memory_end, ULONG_MAX); - if (!chunk->size) - continue; - if (chunk->addr >= memory_end) { - memset(chunk, 0, sizeof(*chunk)); - continue; - } - if (chunk->addr + chunk->size > memory_end) - chunk->size = memory_end - chunk->addr; - } + pr_notice("Max memory size: %luMB\n", memory_end >> 20); } static void __init setup_vmcoreinfo(void) @@ -544,89 +491,6 @@ static void __init setup_vmcoreinfo(void) #ifdef CONFIG_CRASH_DUMP -/* - * Find suitable location for crashkernel memory - */ -static unsigned long __init find_crash_base(unsigned long crash_size, - char **msg) -{ - unsigned long crash_base; - struct mem_chunk *chunk; - int i; - - if (memory_chunk[0].size < crash_size) { - *msg = "first memory chunk must be at least crashkernel size"; - return 0; - } - if (OLDMEM_BASE && crash_size == OLDMEM_SIZE) - return OLDMEM_BASE; - - for (i = MEMORY_CHUNKS - 1; i >= 0; i--) { - chunk = &memory_chunk[i]; - if (chunk->size == 0) - continue; - if (chunk->type != CHUNK_READ_WRITE) - continue; - if (chunk->size < crash_size) - continue; - crash_base = (chunk->addr + chunk->size) - crash_size; - if (crash_base < crash_size) - continue; - if (crash_base < sclp_get_hsa_size()) - continue; - if (crash_base < (unsigned long) INITRD_START + INITRD_SIZE) - continue; - return crash_base; - } - *msg = "no suitable area found"; - return 0; -} - -/* - * Check if crash_base and crash_size is valid - */ -static int __init verify_crash_base(unsigned long crash_base, - unsigned long crash_size, - char **msg) -{ - struct mem_chunk *chunk; - int i; - - /* - * Because we do the swap to zero, we must have at least 'crash_size' - * bytes free space before crash_base - */ - if (crash_size > crash_base) { - *msg = "crashkernel offset must be greater than size"; - return -EINVAL; - } - - /* First memory chunk must be at least crash_size */ - if (memory_chunk[0].size < crash_size) { - *msg = "first memory chunk must be at least crashkernel size"; - return -EINVAL; - } - /* Check if we fit into the respective memory chunk */ - for (i = 0; i < MEMORY_CHUNKS; i++) { - chunk = &memory_chunk[i]; - if (chunk->size == 0) - continue; - if (crash_base < chunk->addr) - continue; - if (crash_base >= chunk->addr + chunk->size) - continue; - /* we have found the memory chunk */ - if (crash_base + crash_size > chunk->addr + chunk->size) { - *msg = "selected memory chunk is too small for " - "crashkernel memory"; - return -EINVAL; - } - return 0; - } - *msg = "invalid memory range specified"; - return -EINVAL; -} - /* * When kdump is enabled, we have to ensure that no memory from * the area [0 - crashkernel memory size] and @@ -652,24 +516,45 @@ static struct notifier_block kdump_mem_nb = { #endif +/* + * Make sure that the area behind memory_end is protected + */ +static void reserve_memory_end(void) +{ +#ifdef CONFIG_CRASH_DUMP + if (ipl_info.type == IPL_TYPE_FCP_DUMP && + !OLDMEM_BASE && sclp_get_hsa_size()) { + memory_end = sclp_get_hsa_size(); + memory_end &= PAGE_MASK; + memory_end_set = 1; + } +#endif + if (!memory_end_set) + return; + memblock_reserve(memory_end, ULONG_MAX); +} + /* * Make sure that oldmem, where the dump is stored, is protected */ static void reserve_oldmem(void) { #ifdef CONFIG_CRASH_DUMP - unsigned long real_size = 0; - int i; - - if (!OLDMEM_BASE) - return; - for (i = 0; i < MEMORY_CHUNKS; i++) { - struct mem_chunk *chunk = &memory_chunk[i]; + if (OLDMEM_BASE) + /* Forget all memory above the running kdump system */ + memblock_reserve(OLDMEM_SIZE, (phys_addr_t)ULONG_MAX); +#endif +} - real_size = max(real_size, chunk->addr + chunk->size); - } - create_mem_hole(memory_chunk, OLDMEM_BASE, OLDMEM_SIZE); - create_mem_hole(memory_chunk, OLDMEM_SIZE, real_size - OLDMEM_SIZE); +/* + * Make sure that oldmem, where the dump is stored, is protected + */ +static void remove_oldmem(void) +{ +#ifdef CONFIG_CRASH_DUMP + if (OLDMEM_BASE) + /* Forget all memory above the running kdump system */ + memblock_remove(OLDMEM_SIZE, (phys_addr_t)ULONG_MAX); #endif } @@ -680,167 +565,132 @@ static void __init reserve_crashkernel(void) { #ifdef CONFIG_CRASH_DUMP unsigned long long crash_base, crash_size; - char *msg = NULL; + phys_addr_t low, high; int rc; rc = parse_crashkernel(boot_command_line, memory_end, &crash_size, &crash_base); - if (rc || crash_size == 0) - return; + crash_base = ALIGN(crash_base, KEXEC_CRASH_MEM_ALIGN); crash_size = ALIGN(crash_size, KEXEC_CRASH_MEM_ALIGN); - if (register_memory_notifier(&kdump_mem_nb)) + if (rc || crash_size == 0) return; - if (!crash_base) - crash_base = find_crash_base(crash_size, &msg); - if (!crash_base) { - pr_info("crashkernel reservation failed: %s\n", msg); - unregister_memory_notifier(&kdump_mem_nb); + + if (memblock.memory.regions[0].size < crash_size) { + pr_info("crashkernel reservation failed: %s\n", + "first memory chunk must be at least crashkernel size"); return; } - if (verify_crash_base(crash_base, crash_size, &msg)) { - pr_info("crashkernel reservation failed: %s\n", msg); - unregister_memory_notifier(&kdump_mem_nb); + + low = crash_base ?: OLDMEM_BASE; + high = low + crash_size; + if (low >= OLDMEM_BASE && high <= OLDMEM_BASE + OLDMEM_SIZE) { + /* The crashkernel fits into OLDMEM, reuse OLDMEM */ + crash_base = low; + } else { + /* Find suitable area in free memory */ + low = max_t(unsigned long, crash_size, sclp_get_hsa_size()); + high = crash_base ? crash_base + crash_size : ULONG_MAX; + + if (crash_base && crash_base < low) { + pr_info("crashkernel reservation failed: %s\n", + "crash_base too low"); + return; + } + low = crash_base ?: low; + crash_base = memblock_find_in_range(low, high, crash_size, + KEXEC_CRASH_MEM_ALIGN); + } + + if (!crash_base) { + pr_info("crashkernel reservation failed: %s\n", + "no suitable area found"); return; } + + if (register_memory_notifier(&kdump_mem_nb)) + return; + if (!OLDMEM_BASE && MACHINE_IS_VM) diag10_range(PFN_DOWN(crash_base), PFN_DOWN(crash_size)); crashk_res.start = crash_base; crashk_res.end = crash_base + crash_size - 1; insert_resource(&iomem_resource, &crashk_res); - create_mem_hole(memory_chunk, crash_base, crash_size); + memblock_remove(crash_base, crash_size); pr_info("Reserving %lluMB of memory at %lluMB " "for crashkernel (System RAM: %luMB)\n", - crash_size >> 20, crash_base >> 20, memory_end >> 20); + crash_size >> 20, crash_base >> 20, + (unsigned long)memblock.memory.total_size >> 20); os_info_crashkernel_add(crash_base, crash_size); #endif } -static void __init setup_memory(void) +/* + * Reserve the initrd from being used by memblock + */ +static void __init reserve_initrd(void) { - unsigned long bootmap_size; - unsigned long start_pfn, end_pfn; - int i; +#ifdef CONFIG_BLK_DEV_INITRD + initrd_start = INITRD_START; + initrd_end = initrd_start + INITRD_SIZE; + memblock_reserve(INITRD_START, INITRD_SIZE); +#endif +} - /* - * partially used pages are not usable - thus - * we are rounding upwards: - */ +/* + * Check for initrd being in usable memory + */ +static void __init check_initrd(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + if (INITRD_START && INITRD_SIZE && + !memblock_is_region_memory(INITRD_START, INITRD_SIZE)) { + pr_err("initrd does not fit memory.\n"); + memblock_free(INITRD_START, INITRD_SIZE); + initrd_start = initrd_end = 0; + } +#endif +} + +/* + * Reserve all kernel text + */ +static void __init reserve_kernel(void) +{ + unsigned long start_pfn; start_pfn = PFN_UP(__pa(&_end)); - end_pfn = max_pfn = PFN_DOWN(memory_end); -#ifdef CONFIG_BLK_DEV_INITRD /* - * Move the initrd in case the bitmap of the bootmem allocater - * would overwrite it. + * Reserve memory used for lowcore/command line/kernel image. */ + memblock_reserve(0, (unsigned long)_ehead); + memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn) + - (unsigned long)_stext); +} - if (INITRD_START && INITRD_SIZE) { - unsigned long bmap_size; - unsigned long start; - - bmap_size = bootmem_bootmap_pages(end_pfn - start_pfn + 1); - bmap_size = PFN_PHYS(bmap_size); - - if (PFN_PHYS(start_pfn) + bmap_size > INITRD_START) { - start = PFN_PHYS(start_pfn) + bmap_size + PAGE_SIZE; - +static void __init reserve_elfcorehdr(void) +{ #ifdef CONFIG_CRASH_DUMP - if (OLDMEM_BASE) { - /* Move initrd behind kdump oldmem */ - if (start + INITRD_SIZE > OLDMEM_BASE && - start < OLDMEM_BASE + OLDMEM_SIZE) - start = OLDMEM_BASE + OLDMEM_SIZE; - } -#endif - if (start + INITRD_SIZE > memory_end) { - pr_err("initrd extends beyond end of " - "memory (0x%08lx > 0x%08lx) " - "disabling initrd\n", - start + INITRD_SIZE, memory_end); - INITRD_START = INITRD_SIZE = 0; - } else { - pr_info("Moving initrd (0x%08lx -> " - "0x%08lx, size: %ld)\n", - INITRD_START, start, INITRD_SIZE); - memmove((void *) start, (void *) INITRD_START, - INITRD_SIZE); - INITRD_START = start; - } - } - } + if (is_kdump_kernel()) + memblock_reserve(elfcorehdr_addr - OLDMEM_BASE, + PAGE_ALIGN(elfcorehdr_size)); #endif +} - /* - * Initialize the boot-time allocator - */ - bootmap_size = init_bootmem(start_pfn, end_pfn); +static void __init setup_memory(void) +{ + struct memblock_region *reg; /* - * Register RAM areas with the bootmem allocator. + * Init storage key for present memory */ - - for (i = 0; i < MEMORY_CHUNKS; i++) { - unsigned long start_chunk, end_chunk, pfn; - - if (!memory_chunk[i].size) - continue; - start_chunk = PFN_DOWN(memory_chunk[i].addr); - end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size); - end_chunk = min(end_chunk, end_pfn); - if (start_chunk >= end_chunk) - continue; - memblock_add_node(PFN_PHYS(start_chunk), - PFN_PHYS(end_chunk - start_chunk), 0); - pfn = max(start_chunk, start_pfn); - storage_key_init_range(PFN_PHYS(pfn), PFN_PHYS(end_chunk)); + for_each_memblock(memory, reg) { + storage_key_init_range(reg->base, reg->base + reg->size); } - psw_set_key(PAGE_DEFAULT_KEY); - free_bootmem_with_active_regions(0, max_pfn); - - /* - * Reserve memory used for lowcore/command line/kernel image. - */ - reserve_bootmem(0, (unsigned long)_ehead, BOOTMEM_DEFAULT); - reserve_bootmem((unsigned long)_stext, - PFN_PHYS(start_pfn) - (unsigned long)_stext, - BOOTMEM_DEFAULT); - /* - * Reserve the bootmem bitmap itself as well. We do this in two - * steps (first step was init_bootmem()) because this catches - * the (very unlikely) case of us accidentally initializing the - * bootmem allocator with an invalid RAM area. - */ - reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size, - BOOTMEM_DEFAULT); - -#ifdef CONFIG_CRASH_DUMP - if (crashk_res.start) - reserve_bootmem(crashk_res.start, - crashk_res.end - crashk_res.start + 1, - BOOTMEM_DEFAULT); - if (is_kdump_kernel()) - reserve_bootmem(elfcorehdr_addr - OLDMEM_BASE, - PAGE_ALIGN(elfcorehdr_size), BOOTMEM_DEFAULT); -#endif -#ifdef CONFIG_BLK_DEV_INITRD - if (INITRD_START && INITRD_SIZE) { - if (INITRD_START + INITRD_SIZE <= memory_end) { - reserve_bootmem(INITRD_START, INITRD_SIZE, - BOOTMEM_DEFAULT); - initrd_start = INITRD_START; - initrd_end = initrd_start + INITRD_SIZE; - } else { - pr_err("initrd extends beyond end of " - "memory (0x%08lx > 0x%08lx) " - "disabling initrd\n", - initrd_start + INITRD_SIZE, memory_end); - initrd_start = initrd_end = 0; - } - } -#endif + /* Only cosmetics */ + memblock_enforce_memory_limit(memblock_end_of_DRAM()); } /* @@ -989,23 +839,46 @@ void __init setup_arch(char **cmdline_p) ROOT_DEV = Root_RAM0; + /* Is init_mm really needed? */ init_mm.start_code = PAGE_OFFSET; init_mm.end_code = (unsigned long) &_etext; init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; parse_early_param(); - detect_memory_layout(memory_chunk, memory_end); os_info_init(); setup_ipl(); + + /* Do some memory reservations *before* memory is added to memblock */ + reserve_memory_end(); reserve_oldmem(); + reserve_kernel(); + reserve_initrd(); + reserve_elfcorehdr(); + memblock_allow_resize(); + + /* Get information about *all* installed memory */ + detect_memory_memblock(); + + remove_oldmem(); + + /* + * Make sure all chunks are MAX_ORDER aligned so we don't need the + * extra checks that HOLES_IN_ZONE would require. + * + * Is this still required? + */ + memblock_trim_memory(1UL << (MAX_ORDER - 1 + PAGE_SHIFT)); + setup_memory_end(); - reserve_crashkernel(); setup_memory(); + + check_initrd(); + reserve_crashkernel(); + setup_resources(); setup_vmcoreinfo(); setup_lowcore(); - smp_fill_possible_mask(); cpu_init(); s390_init_cpu_topology(); diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index d8fd508ccd1e18..42b49f9e19bf84 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -113,7 +113,7 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) sizeof(current->thread.fp_regs)); restore_fp_regs(current->thread.fp_regs.fprs); - clear_thread_flag(TIF_SYSCALL); /* No longer in a system call */ + clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */ return 0; } @@ -356,7 +356,7 @@ void do_signal(struct pt_regs *regs) * call information. */ current_thread_info()->system_call = - test_thread_flag(TIF_SYSCALL) ? regs->int_code : 0; + test_pt_regs_flag(regs, PIF_SYSCALL) ? regs->int_code : 0; signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { @@ -384,7 +384,7 @@ void do_signal(struct pt_regs *regs) } } /* No longer in a system call */ - clear_thread_flag(TIF_SYSCALL); + clear_pt_regs_flag(regs, PIF_SYSCALL); if (is_compat_task()) handle_signal32(signr, &ka, &info, oldset, regs); @@ -394,7 +394,7 @@ void do_signal(struct pt_regs *regs) } /* No handlers present - check for system call restart */ - clear_thread_flag(TIF_SYSCALL); + clear_pt_regs_flag(regs, PIF_SYSCALL); if (current_thread_info()->system_call) { regs->int_code = current_thread_info()->system_call; switch (regs->gprs[2]) { @@ -407,9 +407,9 @@ void do_signal(struct pt_regs *regs) case -ERESTARTNOINTR: /* Restart system call with magic TIF bit. */ regs->gprs[2] = regs->orig_gpr2; - set_thread_flag(TIF_SYSCALL); + set_pt_regs_flag(regs, PIF_SYSCALL); if (test_thread_flag(TIF_SINGLE_STEP)) - set_thread_flag(TIF_PER_TRAP); + clear_pt_regs_flag(regs, PIF_PER_TRAP); break; } } diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 86e65ec3422b95..243c7e51260055 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -170,6 +170,7 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) lc->panic_stack = pcpu->panic_stack + PAGE_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs); lc->cpu_nr = cpu; + lc->spinlock_lockval = arch_spin_lockval(cpu); #ifndef CONFIG_64BIT if (MACHINE_HAS_IEEE) { lc->extended_save_area_addr = get_zeroed_page(GFP_KERNEL); @@ -226,6 +227,7 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) cpumask_set_cpu(cpu, mm_cpumask(&init_mm)); atomic_inc(&init_mm.context.attach_count); lc->cpu_nr = cpu; + lc->spinlock_lockval = arch_spin_lockval(cpu); lc->percpu_offset = __per_cpu_offset[cpu]; lc->kernel_asce = S390_lowcore.kernel_asce; lc->machine_flags = S390_lowcore.machine_flags; @@ -402,15 +404,6 @@ void smp_send_stop(void) } } -/* - * Stop the current cpu. - */ -void smp_stop_cpu(void) -{ - pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0); - for (;;) ; -} - /* * This is the main routine where commands issued by other * cpus are handled. @@ -519,7 +512,7 @@ void smp_ctl_clear_bit(int cr, int bit) } EXPORT_SYMBOL(smp_ctl_clear_bit); -#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_CRASH_DUMP) +#ifdef CONFIG_CRASH_DUMP static void __init smp_get_save_area(int cpu, u16 address) { @@ -534,14 +527,12 @@ static void __init smp_get_save_area(int cpu, u16 address) save_area = dump_save_area_create(cpu); if (!save_area) panic("could not allocate memory for save area\n"); -#ifdef CONFIG_CRASH_DUMP if (address == boot_cpu_address) { /* Copy the registers of the boot cpu. */ copy_oldmem_page(1, (void *) save_area, sizeof(*save_area), SAVE_AREA_BASE - PAGE_SIZE, 0); return; } -#endif /* Get the registers of a non-boot cpu. */ __pcpu_sigp_relax(address, SIGP_STOP_AND_STORE_STATUS, 0, NULL); memcpy_real(save_area, lc + SAVE_AREA_BASE, sizeof(*save_area)); @@ -558,11 +549,11 @@ int smp_store_status(int cpu) return 0; } -#else /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */ +#else /* CONFIG_CRASH_DUMP */ static inline void smp_get_save_area(int cpu, u16 address) { } -#endif /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */ +#endif /* CONFIG_CRASH_DUMP */ void smp_cpu_set_polarization(int cpu, int val) { @@ -809,6 +800,7 @@ void __init smp_cpus_done(unsigned int max_cpus) void __init smp_setup_processor_id(void) { S390_lowcore.cpu_nr = 0; + S390_lowcore.spinlock_lockval = arch_spin_lockval(0); } /* diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 6298fed11cedf8..355a16c557026a 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -333,7 +333,9 @@ static void __init alloc_masks(struct sysinfo_15_1_x *info, nr_masks *= info->mag[TOPOLOGY_NR_MAG - offset - 1 - i]; nr_masks = max(nr_masks, 1); for (i = 0; i < nr_masks; i++) { - mask->next = alloc_bootmem(sizeof(struct mask_info)); + mask->next = alloc_bootmem_align( + roundup_pow_of_two(sizeof(struct mask_info)), + roundup_pow_of_two(sizeof(struct mask_info))); mask = mask->next; } } @@ -443,6 +445,23 @@ int topology_cpu_init(struct cpu *cpu) return sysfs_create_group(&cpu->dev.kobj, &topology_cpu_attr_group); } +const struct cpumask *cpu_coregroup_mask(int cpu) +{ + return &cpu_topology[cpu].core_mask; +} + +static const struct cpumask *cpu_book_mask(int cpu) +{ + return &cpu_topology[cpu].book_mask; +} + +static struct sched_domain_topology_level s390_topology[] = { + { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, + { cpu_book_mask, SD_INIT_NAME(BOOK) }, + { cpu_cpu_mask, SD_INIT_NAME(DIE) }, + { NULL, }, +}; + static int __init topology_init(void) { if (!MACHINE_HAS_TOPOLOGY) { @@ -451,6 +470,9 @@ static int __init topology_init(void) } set_topology_timer(); out: + + set_sched_topology(s390_topology); + return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching); } device_initcall(topology_init); diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile index d3adb37e93a4c9..b3b55346965088 100644 --- a/arch/s390/kvm/Makefile +++ b/arch/s390/kvm/Makefile @@ -11,5 +11,7 @@ common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/async_pf.o $(KVM)/irqch ccflags-y := -Ivirt/kvm -Iarch/s390/kvm -kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o diag.o +kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o +kvm-objs += diag.o gaccess.o guestdbg.o + obj-$(CONFIG_KVM) += kvm.o diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index 08dfc839a6cfee..004d385d9519e3 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c @@ -64,12 +64,12 @@ static int __diag_page_ref_service(struct kvm_vcpu *vcpu) int rc; u16 rx = (vcpu->arch.sie_block->ipa & 0xf0) >> 4; u16 ry = (vcpu->arch.sie_block->ipa & 0x0f); - unsigned long hva_token = KVM_HVA_ERR_BAD; if (vcpu->run->s.regs.gprs[rx] & 7) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - if (copy_from_guest(vcpu, &parm, vcpu->run->s.regs.gprs[rx], sizeof(parm))) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + rc = read_guest(vcpu, vcpu->run->s.regs.gprs[rx], &parm, sizeof(parm)); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); if (parm.parm_version != 2 || parm.parm_len < 5 || parm.code != 0x258) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); @@ -89,8 +89,7 @@ static int __diag_page_ref_service(struct kvm_vcpu *vcpu) parm.token_addr & 7 || parm.zarch != 0x8000000000000000ULL) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - hva_token = gfn_to_hva(vcpu->kvm, gpa_to_gfn(parm.token_addr)); - if (kvm_is_error_hva(hva_token)) + if (kvm_is_error_gpa(vcpu->kvm, parm.token_addr)) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); vcpu->arch.pfault_token = parm.token_addr; @@ -167,23 +166,17 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode); switch (subcode) { - case 0: - case 1: - page_table_reset_pgste(current->mm, 0, TASK_SIZE); - return -EOPNOTSUPP; case 3: vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR; - page_table_reset_pgste(current->mm, 0, TASK_SIZE); break; case 4: vcpu->run->s390_reset_flags = 0; - page_table_reset_pgste(current->mm, 0, TASK_SIZE); break; default: return -EOPNOTSUPP; } - atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); + kvm_s390_vcpu_stop(vcpu); vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM; vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL; vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT; diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c new file mode 100644 index 00000000000000..db608c3f9303e5 --- /dev/null +++ b/arch/s390/kvm/gaccess.c @@ -0,0 +1,673 @@ +/* + * guest access functions + * + * Copyright IBM Corp. 2014 + * + */ + +#include +#include +#include +#include "kvm-s390.h" +#include "gaccess.h" + +union asce { + unsigned long val; + struct { + unsigned long origin : 52; /* Region- or Segment-Table Origin */ + unsigned long : 2; + unsigned long g : 1; /* Subspace Group Control */ + unsigned long p : 1; /* Private Space Control */ + unsigned long s : 1; /* Storage-Alteration-Event Control */ + unsigned long x : 1; /* Space-Switch-Event Control */ + unsigned long r : 1; /* Real-Space Control */ + unsigned long : 1; + unsigned long dt : 2; /* Designation-Type Control */ + unsigned long tl : 2; /* Region- or Segment-Table Length */ + }; +}; + +enum { + ASCE_TYPE_SEGMENT = 0, + ASCE_TYPE_REGION3 = 1, + ASCE_TYPE_REGION2 = 2, + ASCE_TYPE_REGION1 = 3 +}; + +union region1_table_entry { + unsigned long val; + struct { + unsigned long rto: 52;/* Region-Table Origin */ + unsigned long : 2; + unsigned long p : 1; /* DAT-Protection Bit */ + unsigned long : 1; + unsigned long tf : 2; /* Region-Second-Table Offset */ + unsigned long i : 1; /* Region-Invalid Bit */ + unsigned long : 1; + unsigned long tt : 2; /* Table-Type Bits */ + unsigned long tl : 2; /* Region-Second-Table Length */ + }; +}; + +union region2_table_entry { + unsigned long val; + struct { + unsigned long rto: 52;/* Region-Table Origin */ + unsigned long : 2; + unsigned long p : 1; /* DAT-Protection Bit */ + unsigned long : 1; + unsigned long tf : 2; /* Region-Third-Table Offset */ + unsigned long i : 1; /* Region-Invalid Bit */ + unsigned long : 1; + unsigned long tt : 2; /* Table-Type Bits */ + unsigned long tl : 2; /* Region-Third-Table Length */ + }; +}; + +struct region3_table_entry_fc0 { + unsigned long sto: 52;/* Segment-Table Origin */ + unsigned long : 1; + unsigned long fc : 1; /* Format-Control */ + unsigned long p : 1; /* DAT-Protection Bit */ + unsigned long : 1; + unsigned long tf : 2; /* Segment-Table Offset */ + unsigned long i : 1; /* Region-Invalid Bit */ + unsigned long cr : 1; /* Common-Region Bit */ + unsigned long tt : 2; /* Table-Type Bits */ + unsigned long tl : 2; /* Segment-Table Length */ +}; + +struct region3_table_entry_fc1 { + unsigned long rfaa : 33; /* Region-Frame Absolute Address */ + unsigned long : 14; + unsigned long av : 1; /* ACCF-Validity Control */ + unsigned long acc: 4; /* Access-Control Bits */ + unsigned long f : 1; /* Fetch-Protection Bit */ + unsigned long fc : 1; /* Format-Control */ + unsigned long p : 1; /* DAT-Protection Bit */ + unsigned long co : 1; /* Change-Recording Override */ + unsigned long : 2; + unsigned long i : 1; /* Region-Invalid Bit */ + unsigned long cr : 1; /* Common-Region Bit */ + unsigned long tt : 2; /* Table-Type Bits */ + unsigned long : 2; +}; + +union region3_table_entry { + unsigned long val; + struct region3_table_entry_fc0 fc0; + struct region3_table_entry_fc1 fc1; + struct { + unsigned long : 53; + unsigned long fc : 1; /* Format-Control */ + unsigned long : 4; + unsigned long i : 1; /* Region-Invalid Bit */ + unsigned long cr : 1; /* Common-Region Bit */ + unsigned long tt : 2; /* Table-Type Bits */ + unsigned long : 2; + }; +}; + +struct segment_entry_fc0 { + unsigned long pto: 53;/* Page-Table Origin */ + unsigned long fc : 1; /* Format-Control */ + unsigned long p : 1; /* DAT-Protection Bit */ + unsigned long : 3; + unsigned long i : 1; /* Segment-Invalid Bit */ + unsigned long cs : 1; /* Common-Segment Bit */ + unsigned long tt : 2; /* Table-Type Bits */ + unsigned long : 2; +}; + +struct segment_entry_fc1 { + unsigned long sfaa : 44; /* Segment-Frame Absolute Address */ + unsigned long : 3; + unsigned long av : 1; /* ACCF-Validity Control */ + unsigned long acc: 4; /* Access-Control Bits */ + unsigned long f : 1; /* Fetch-Protection Bit */ + unsigned long fc : 1; /* Format-Control */ + unsigned long p : 1; /* DAT-Protection Bit */ + unsigned long co : 1; /* Change-Recording Override */ + unsigned long : 2; + unsigned long i : 1; /* Segment-Invalid Bit */ + unsigned long cs : 1; /* Common-Segment Bit */ + unsigned long tt : 2; /* Table-Type Bits */ + unsigned long : 2; +}; + +union segment_table_entry { + unsigned long val; + struct segment_entry_fc0 fc0; + struct segment_entry_fc1 fc1; + struct { + unsigned long : 53; + unsigned long fc : 1; /* Format-Control */ + unsigned long : 4; + unsigned long i : 1; /* Segment-Invalid Bit */ + unsigned long cs : 1; /* Common-Segment Bit */ + unsigned long tt : 2; /* Table-Type Bits */ + unsigned long : 2; + }; +}; + +enum { + TABLE_TYPE_SEGMENT = 0, + TABLE_TYPE_REGION3 = 1, + TABLE_TYPE_REGION2 = 2, + TABLE_TYPE_REGION1 = 3 +}; + +union page_table_entry { + unsigned long val; + struct { + unsigned long pfra : 52; /* Page-Frame Real Address */ + unsigned long z : 1; /* Zero Bit */ + unsigned long i : 1; /* Page-Invalid Bit */ + unsigned long p : 1; /* DAT-Protection Bit */ + unsigned long co : 1; /* Change-Recording Override */ + unsigned long : 8; + }; +}; + +/* + * vaddress union in order to easily decode a virtual address into its + * region first index, region second index etc. parts. + */ +union vaddress { + unsigned long addr; + struct { + unsigned long rfx : 11; + unsigned long rsx : 11; + unsigned long rtx : 11; + unsigned long sx : 11; + unsigned long px : 8; + unsigned long bx : 12; + }; + struct { + unsigned long rfx01 : 2; + unsigned long : 9; + unsigned long rsx01 : 2; + unsigned long : 9; + unsigned long rtx01 : 2; + unsigned long : 9; + unsigned long sx01 : 2; + unsigned long : 29; + }; +}; + +/* + * raddress union which will contain the result (real or absolute address) + * after a page table walk. The rfaa, sfaa and pfra members are used to + * simply assign them the value of a region, segment or page table entry. + */ +union raddress { + unsigned long addr; + unsigned long rfaa : 33; /* Region-Frame Absolute Address */ + unsigned long sfaa : 44; /* Segment-Frame Absolute Address */ + unsigned long pfra : 52; /* Page-Frame Real Address */ +}; + +static int ipte_lock_count; +static DEFINE_MUTEX(ipte_mutex); + +int ipte_lock_held(struct kvm_vcpu *vcpu) +{ + union ipte_control *ic = &vcpu->kvm->arch.sca->ipte_control; + + if (vcpu->arch.sie_block->eca & 1) + return ic->kh != 0; + return ipte_lock_count != 0; +} + +static void ipte_lock_simple(struct kvm_vcpu *vcpu) +{ + union ipte_control old, new, *ic; + + mutex_lock(&ipte_mutex); + ipte_lock_count++; + if (ipte_lock_count > 1) + goto out; + ic = &vcpu->kvm->arch.sca->ipte_control; + do { + old = ACCESS_ONCE(*ic); + while (old.k) { + cond_resched(); + old = ACCESS_ONCE(*ic); + } + new = old; + new.k = 1; + } while (cmpxchg(&ic->val, old.val, new.val) != old.val); +out: + mutex_unlock(&ipte_mutex); +} + +static void ipte_unlock_simple(struct kvm_vcpu *vcpu) +{ + union ipte_control old, new, *ic; + + mutex_lock(&ipte_mutex); + ipte_lock_count--; + if (ipte_lock_count) + goto out; + ic = &vcpu->kvm->arch.sca->ipte_control; + do { + new = old = ACCESS_ONCE(*ic); + new.k = 0; + } while (cmpxchg(&ic->val, old.val, new.val) != old.val); + if (!ipte_lock_count) + wake_up(&vcpu->kvm->arch.ipte_wq); +out: + mutex_unlock(&ipte_mutex); +} + +static void ipte_lock_siif(struct kvm_vcpu *vcpu) +{ + union ipte_control old, new, *ic; + + ic = &vcpu->kvm->arch.sca->ipte_control; + do { + old = ACCESS_ONCE(*ic); + while (old.kg) { + cond_resched(); + old = ACCESS_ONCE(*ic); + } + new = old; + new.k = 1; + new.kh++; + } while (cmpxchg(&ic->val, old.val, new.val) != old.val); +} + +static void ipte_unlock_siif(struct kvm_vcpu *vcpu) +{ + union ipte_control old, new, *ic; + + ic = &vcpu->kvm->arch.sca->ipte_control; + do { + new = old = ACCESS_ONCE(*ic); + new.kh--; + if (!new.kh) + new.k = 0; + } while (cmpxchg(&ic->val, old.val, new.val) != old.val); + if (!new.kh) + wake_up(&vcpu->kvm->arch.ipte_wq); +} + +static void ipte_lock(struct kvm_vcpu *vcpu) +{ + if (vcpu->arch.sie_block->eca & 1) + ipte_lock_siif(vcpu); + else + ipte_lock_simple(vcpu); +} + +static void ipte_unlock(struct kvm_vcpu *vcpu) +{ + if (vcpu->arch.sie_block->eca & 1) + ipte_unlock_siif(vcpu); + else + ipte_unlock_simple(vcpu); +} + +static unsigned long get_vcpu_asce(struct kvm_vcpu *vcpu) +{ + switch (psw_bits(vcpu->arch.sie_block->gpsw).as) { + case PSW_AS_PRIMARY: + return vcpu->arch.sie_block->gcr[1]; + case PSW_AS_SECONDARY: + return vcpu->arch.sie_block->gcr[7]; + case PSW_AS_HOME: + return vcpu->arch.sie_block->gcr[13]; + } + return 0; +} + +static int deref_table(struct kvm *kvm, unsigned long gpa, unsigned long *val) +{ + return kvm_read_guest(kvm, gpa, val, sizeof(*val)); +} + +/** + * guest_translate - translate a guest virtual into a guest absolute address + * @vcpu: virtual cpu + * @gva: guest virtual address + * @gpa: points to where guest physical (absolute) address should be stored + * @write: indicates if access is a write access + * + * Translate a guest virtual address into a guest absolute address by means + * of dynamic address translation as specified by the architecuture. + * If the resulting absolute address is not available in the configuration + * an addressing exception is indicated and @gpa will not be changed. + * + * Returns: - zero on success; @gpa contains the resulting absolute address + * - a negative value if guest access failed due to e.g. broken + * guest mapping + * - a positve value if an access exception happened. In this case + * the returned value is the program interruption code as defined + * by the architecture + */ +static unsigned long guest_translate(struct kvm_vcpu *vcpu, unsigned long gva, + unsigned long *gpa, int write) +{ + union vaddress vaddr = {.addr = gva}; + union raddress raddr = {.addr = gva}; + union page_table_entry pte; + int dat_protection = 0; + union ctlreg0 ctlreg0; + unsigned long ptr; + int edat1, edat2; + union asce asce; + + ctlreg0.val = vcpu->arch.sie_block->gcr[0]; + edat1 = ctlreg0.edat && test_vfacility(8); + edat2 = edat1 && test_vfacility(78); + asce.val = get_vcpu_asce(vcpu); + if (asce.r) + goto real_address; + ptr = asce.origin * 4096; + switch (asce.dt) { + case ASCE_TYPE_REGION1: + if (vaddr.rfx01 > asce.tl) + return PGM_REGION_FIRST_TRANS; + ptr += vaddr.rfx * 8; + break; + case ASCE_TYPE_REGION2: + if (vaddr.rfx) + return PGM_ASCE_TYPE; + if (vaddr.rsx01 > asce.tl) + return PGM_REGION_SECOND_TRANS; + ptr += vaddr.rsx * 8; + break; + case ASCE_TYPE_REGION3: + if (vaddr.rfx || vaddr.rsx) + return PGM_ASCE_TYPE; + if (vaddr.rtx01 > asce.tl) + return PGM_REGION_THIRD_TRANS; + ptr += vaddr.rtx * 8; + break; + case ASCE_TYPE_SEGMENT: + if (vaddr.rfx || vaddr.rsx || vaddr.rtx) + return PGM_ASCE_TYPE; + if (vaddr.sx01 > asce.tl) + return PGM_SEGMENT_TRANSLATION; + ptr += vaddr.sx * 8; + break; + } + switch (asce.dt) { + case ASCE_TYPE_REGION1: { + union region1_table_entry rfte; + + if (kvm_is_error_gpa(vcpu->kvm, ptr)) + return PGM_ADDRESSING; + if (deref_table(vcpu->kvm, ptr, &rfte.val)) + return -EFAULT; + if (rfte.i) + return PGM_REGION_FIRST_TRANS; + if (rfte.tt != TABLE_TYPE_REGION1) + return PGM_TRANSLATION_SPEC; + if (vaddr.rsx01 < rfte.tf || vaddr.rsx01 > rfte.tl) + return PGM_REGION_SECOND_TRANS; + if (edat1) + dat_protection |= rfte.p; + ptr = rfte.rto * 4096 + vaddr.rsx * 8; + } + /* fallthrough */ + case ASCE_TYPE_REGION2: { + union region2_table_entry rste; + + if (kvm_is_error_gpa(vcpu->kvm, ptr)) + return PGM_ADDRESSING; + if (deref_table(vcpu->kvm, ptr, &rste.val)) + return -EFAULT; + if (rste.i) + return PGM_REGION_SECOND_TRANS; + if (rste.tt != TABLE_TYPE_REGION2) + return PGM_TRANSLATION_SPEC; + if (vaddr.rtx01 < rste.tf || vaddr.rtx01 > rste.tl) + return PGM_REGION_THIRD_TRANS; + if (edat1) + dat_protection |= rste.p; + ptr = rste.rto * 4096 + vaddr.rtx * 8; + } + /* fallthrough */ + case ASCE_TYPE_REGION3: { + union region3_table_entry rtte; + + if (kvm_is_error_gpa(vcpu->kvm, ptr)) + return PGM_ADDRESSING; + if (deref_table(vcpu->kvm, ptr, &rtte.val)) + return -EFAULT; + if (rtte.i) + return PGM_REGION_THIRD_TRANS; + if (rtte.tt != TABLE_TYPE_REGION3) + return PGM_TRANSLATION_SPEC; + if (rtte.cr && asce.p && edat2) + return PGM_TRANSLATION_SPEC; + if (rtte.fc && edat2) { + dat_protection |= rtte.fc1.p; + raddr.rfaa = rtte.fc1.rfaa; + goto absolute_address; + } + if (vaddr.sx01 < rtte.fc0.tf) + return PGM_SEGMENT_TRANSLATION; + if (vaddr.sx01 > rtte.fc0.tl) + return PGM_SEGMENT_TRANSLATION; + if (edat1) + dat_protection |= rtte.fc0.p; + ptr = rtte.fc0.sto * 4096 + vaddr.sx * 8; + } + /* fallthrough */ + case ASCE_TYPE_SEGMENT: { + union segment_table_entry ste; + + if (kvm_is_error_gpa(vcpu->kvm, ptr)) + return PGM_ADDRESSING; + if (deref_table(vcpu->kvm, ptr, &ste.val)) + return -EFAULT; + if (ste.i) + return PGM_SEGMENT_TRANSLATION; + if (ste.tt != TABLE_TYPE_SEGMENT) + return PGM_TRANSLATION_SPEC; + if (ste.cs && asce.p) + return PGM_TRANSLATION_SPEC; + if (ste.fc && edat1) { + dat_protection |= ste.fc1.p; + raddr.sfaa = ste.fc1.sfaa; + goto absolute_address; + } + dat_protection |= ste.fc0.p; + ptr = ste.fc0.pto * 2048 + vaddr.px * 8; + } + } + if (kvm_is_error_gpa(vcpu->kvm, ptr)) + return PGM_ADDRESSING; + if (deref_table(vcpu->kvm, ptr, &pte.val)) + return -EFAULT; + if (pte.i) + return PGM_PAGE_TRANSLATION; + if (pte.z) + return PGM_TRANSLATION_SPEC; + if (pte.co && !edat1) + return PGM_TRANSLATION_SPEC; + dat_protection |= pte.p; + raddr.pfra = pte.pfra; +real_address: + raddr.addr = kvm_s390_real_to_abs(vcpu, raddr.addr); +absolute_address: + if (write && dat_protection) + return PGM_PROTECTION; + if (kvm_is_error_gpa(vcpu->kvm, raddr.addr)) + return PGM_ADDRESSING; + *gpa = raddr.addr; + return 0; +} + +static inline int is_low_address(unsigned long ga) +{ + /* Check for address ranges 0..511 and 4096..4607 */ + return (ga & ~0x11fful) == 0; +} + +static int low_address_protection_enabled(struct kvm_vcpu *vcpu) +{ + union ctlreg0 ctlreg0 = {.val = vcpu->arch.sie_block->gcr[0]}; + psw_t *psw = &vcpu->arch.sie_block->gpsw; + union asce asce; + + if (!ctlreg0.lap) + return 0; + asce.val = get_vcpu_asce(vcpu); + if (psw_bits(*psw).t && asce.p) + return 0; + return 1; +} + +struct trans_exc_code_bits { + unsigned long addr : 52; /* Translation-exception Address */ + unsigned long fsi : 2; /* Access Exception Fetch/Store Indication */ + unsigned long : 7; + unsigned long b61 : 1; + unsigned long as : 2; /* ASCE Identifier */ +}; + +enum { + FSI_UNKNOWN = 0, /* Unknown wether fetch or store */ + FSI_STORE = 1, /* Exception was due to store operation */ + FSI_FETCH = 2 /* Exception was due to fetch operation */ +}; + +static int guest_page_range(struct kvm_vcpu *vcpu, unsigned long ga, + unsigned long *pages, unsigned long nr_pages, + int write) +{ + struct kvm_s390_pgm_info *pgm = &vcpu->arch.pgm; + psw_t *psw = &vcpu->arch.sie_block->gpsw; + struct trans_exc_code_bits *tec_bits; + int lap_enabled, rc; + + memset(pgm, 0, sizeof(*pgm)); + tec_bits = (struct trans_exc_code_bits *)&pgm->trans_exc_code; + tec_bits->fsi = write ? FSI_STORE : FSI_FETCH; + tec_bits->as = psw_bits(*psw).as; + lap_enabled = low_address_protection_enabled(vcpu); + while (nr_pages) { + ga = kvm_s390_logical_to_effective(vcpu, ga); + tec_bits->addr = ga >> PAGE_SHIFT; + if (write && lap_enabled && is_low_address(ga)) { + pgm->code = PGM_PROTECTION; + return pgm->code; + } + ga &= PAGE_MASK; + if (psw_bits(*psw).t) { + rc = guest_translate(vcpu, ga, pages, write); + if (rc < 0) + return rc; + if (rc == PGM_PROTECTION) + tec_bits->b61 = 1; + if (rc) + pgm->code = rc; + } else { + *pages = kvm_s390_real_to_abs(vcpu, ga); + if (kvm_is_error_gpa(vcpu->kvm, *pages)) + pgm->code = PGM_ADDRESSING; + } + if (pgm->code) + return pgm->code; + ga += PAGE_SIZE; + pages++; + nr_pages--; + } + return 0; +} + +int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, void *data, + unsigned long len, int write) +{ + psw_t *psw = &vcpu->arch.sie_block->gpsw; + unsigned long _len, nr_pages, gpa, idx; + unsigned long pages_array[2]; + unsigned long *pages; + int need_ipte_lock; + union asce asce; + int rc; + + if (!len) + return 0; + /* Access register mode is not supported yet. */ + if (psw_bits(*psw).t && psw_bits(*psw).as == PSW_AS_ACCREG) + return -EOPNOTSUPP; + nr_pages = (((ga & ~PAGE_MASK) + len - 1) >> PAGE_SHIFT) + 1; + pages = pages_array; + if (nr_pages > ARRAY_SIZE(pages_array)) + pages = vmalloc(nr_pages * sizeof(unsigned long)); + if (!pages) + return -ENOMEM; + asce.val = get_vcpu_asce(vcpu); + need_ipte_lock = psw_bits(*psw).t && !asce.r; + if (need_ipte_lock) + ipte_lock(vcpu); + rc = guest_page_range(vcpu, ga, pages, nr_pages, write); + for (idx = 0; idx < nr_pages && !rc; idx++) { + gpa = *(pages + idx) + (ga & ~PAGE_MASK); + _len = min(PAGE_SIZE - (gpa & ~PAGE_MASK), len); + if (write) + rc = kvm_write_guest(vcpu->kvm, gpa, data, _len); + else + rc = kvm_read_guest(vcpu->kvm, gpa, data, _len); + len -= _len; + ga += _len; + data += _len; + } + if (need_ipte_lock) + ipte_unlock(vcpu); + if (nr_pages > ARRAY_SIZE(pages_array)) + vfree(pages); + return rc; +} + +int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra, + void *data, unsigned long len, int write) +{ + unsigned long _len, gpa; + int rc = 0; + + while (len && !rc) { + gpa = kvm_s390_real_to_abs(vcpu, gra); + _len = min(PAGE_SIZE - (gpa & ~PAGE_MASK), len); + if (write) + rc = write_guest_abs(vcpu, gpa, data, _len); + else + rc = read_guest_abs(vcpu, gpa, data, _len); + len -= _len; + gra += _len; + data += _len; + } + return rc; +} + +/** + * kvm_s390_check_low_addr_protection - check for low-address protection + * @ga: Guest address + * + * Checks whether an address is subject to low-address protection and set + * up vcpu->arch.pgm accordingly if necessary. + * + * Return: 0 if no protection exception, or PGM_PROTECTION if protected. + */ +int kvm_s390_check_low_addr_protection(struct kvm_vcpu *vcpu, unsigned long ga) +{ + struct kvm_s390_pgm_info *pgm = &vcpu->arch.pgm; + psw_t *psw = &vcpu->arch.sie_block->gpsw; + struct trans_exc_code_bits *tec_bits; + + if (!is_low_address(ga) || !low_address_protection_enabled(vcpu)) + return 0; + + memset(pgm, 0, sizeof(*pgm)); + tec_bits = (struct trans_exc_code_bits *)&pgm->trans_exc_code; + tec_bits->fsi = FSI_STORE; + tec_bits->as = psw_bits(*psw).as; + tec_bits->addr = ga >> PAGE_SHIFT; + pgm->code = PGM_PROTECTION; + + return pgm->code; +} diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h index 374a439ccc6080..68db43e4254f50 100644 --- a/arch/s390/kvm/gaccess.h +++ b/arch/s390/kvm/gaccess.h @@ -1,7 +1,7 @@ /* * access guest memory * - * Copyright IBM Corp. 2008, 2009 + * Copyright IBM Corp. 2008, 2014 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License (version 2 only) @@ -15,100 +15,316 @@ #include #include -#include +#include +#include #include "kvm-s390.h" -/* Convert real to absolute address by applying the prefix of the CPU */ +/** + * kvm_s390_real_to_abs - convert guest real address to guest absolute address + * @vcpu - guest virtual cpu + * @gra - guest real address + * + * Returns the guest absolute address that corresponds to the passed guest real + * address @gra of a virtual guest cpu by applying its prefix. + */ static inline unsigned long kvm_s390_real_to_abs(struct kvm_vcpu *vcpu, - unsigned long gaddr) + unsigned long gra) { - unsigned long prefix = vcpu->arch.sie_block->prefix; - if (gaddr < 2 * PAGE_SIZE) - gaddr += prefix; - else if (gaddr >= prefix && gaddr < prefix + 2 * PAGE_SIZE) - gaddr -= prefix; - return gaddr; + unsigned long prefix = vcpu->arch.sie_block->prefix; + + if (gra < 2 * PAGE_SIZE) + gra += prefix; + else if (gra >= prefix && gra < prefix + 2 * PAGE_SIZE) + gra -= prefix; + return gra; } -static inline void __user *__gptr_to_uptr(struct kvm_vcpu *vcpu, - void __user *gptr, - int prefixing) +/** + * kvm_s390_logical_to_effective - convert guest logical to effective address + * @vcpu: guest virtual cpu + * @ga: guest logical address + * + * Convert a guest vcpu logical address to a guest vcpu effective address by + * applying the rules of the vcpu's addressing mode defined by PSW bits 31 + * and 32 (extendended/basic addressing mode). + * + * Depending on the vcpu's addressing mode the upper 40 bits (24 bit addressing + * mode), 33 bits (31 bit addressing mode) or no bits (64 bit addressing mode) + * of @ga will be zeroed and the remaining bits will be returned. + */ +static inline unsigned long kvm_s390_logical_to_effective(struct kvm_vcpu *vcpu, + unsigned long ga) { - unsigned long gaddr = (unsigned long) gptr; - unsigned long uaddr; - - if (prefixing) - gaddr = kvm_s390_real_to_abs(vcpu, gaddr); - uaddr = gmap_fault(gaddr, vcpu->arch.gmap); - if (IS_ERR_VALUE(uaddr)) - uaddr = -EFAULT; - return (void __user *)uaddr; + psw_t *psw = &vcpu->arch.sie_block->gpsw; + + if (psw_bits(*psw).eaba == PSW_AMODE_64BIT) + return ga; + if (psw_bits(*psw).eaba == PSW_AMODE_31BIT) + return ga & ((1UL << 31) - 1); + return ga & ((1UL << 24) - 1); } -#define get_guest(vcpu, x, gptr) \ -({ \ - __typeof__(gptr) __uptr = __gptr_to_uptr(vcpu, gptr, 1);\ - int __mask = sizeof(__typeof__(*(gptr))) - 1; \ - int __ret; \ - \ - if (IS_ERR((void __force *)__uptr)) { \ - __ret = PTR_ERR((void __force *)__uptr); \ - } else { \ - BUG_ON((unsigned long)__uptr & __mask); \ - __ret = get_user(x, __uptr); \ - } \ - __ret; \ -}) +/* + * put_guest_lc, read_guest_lc and write_guest_lc are guest access functions + * which shall only be used to access the lowcore of a vcpu. + * These functions should be used for e.g. interrupt handlers where no + * guest memory access protection facilities, like key or low address + * protection, are applicable. + * At a later point guest vcpu lowcore access should happen via pinned + * prefix pages, so that these pages can be accessed directly via the + * kernel mapping. All of these *_lc functions can be removed then. + */ -#define put_guest(vcpu, x, gptr) \ +/** + * put_guest_lc - write a simple variable to a guest vcpu's lowcore + * @vcpu: virtual cpu + * @x: value to copy to guest + * @gra: vcpu's destination guest real address + * + * Copies a simple value from kernel space to a guest vcpu's lowcore. + * The size of the variable may be 1, 2, 4 or 8 bytes. The destination + * must be located in the vcpu's lowcore. Otherwise the result is undefined. + * + * Returns zero on success or -EFAULT on error. + * + * Note: an error indicates that either the kernel is out of memory or + * the guest memory mapping is broken. In any case the best solution + * would be to terminate the guest. + * It is wrong to inject a guest exception. + */ +#define put_guest_lc(vcpu, x, gra) \ ({ \ - __typeof__(gptr) __uptr = __gptr_to_uptr(vcpu, gptr, 1);\ - int __mask = sizeof(__typeof__(*(gptr))) - 1; \ - int __ret; \ + struct kvm_vcpu *__vcpu = (vcpu); \ + __typeof__(*(gra)) __x = (x); \ + unsigned long __gpa; \ \ - if (IS_ERR((void __force *)__uptr)) { \ - __ret = PTR_ERR((void __force *)__uptr); \ - } else { \ - BUG_ON((unsigned long)__uptr & __mask); \ - __ret = put_user(x, __uptr); \ - } \ - __ret; \ + __gpa = (unsigned long)(gra); \ + __gpa += __vcpu->arch.sie_block->prefix; \ + kvm_write_guest(__vcpu->kvm, __gpa, &__x, sizeof(__x)); \ }) -static inline int __copy_guest(struct kvm_vcpu *vcpu, unsigned long to, - unsigned long from, unsigned long len, - int to_guest, int prefixing) +/** + * write_guest_lc - copy data from kernel space to guest vcpu's lowcore + * @vcpu: virtual cpu + * @gra: vcpu's source guest real address + * @data: source address in kernel space + * @len: number of bytes to copy + * + * Copy data from kernel space to guest vcpu's lowcore. The entire range must + * be located within the vcpu's lowcore, otherwise the result is undefined. + * + * Returns zero on success or -EFAULT on error. + * + * Note: an error indicates that either the kernel is out of memory or + * the guest memory mapping is broken. In any case the best solution + * would be to terminate the guest. + * It is wrong to inject a guest exception. + */ +static inline __must_check +int write_guest_lc(struct kvm_vcpu *vcpu, unsigned long gra, void *data, + unsigned long len) +{ + unsigned long gpa = gra + vcpu->arch.sie_block->prefix; + + return kvm_write_guest(vcpu->kvm, gpa, data, len); +} + +/** + * read_guest_lc - copy data from guest vcpu's lowcore to kernel space + * @vcpu: virtual cpu + * @gra: vcpu's source guest real address + * @data: destination address in kernel space + * @len: number of bytes to copy + * + * Copy data from guest vcpu's lowcore to kernel space. The entire range must + * be located within the vcpu's lowcore, otherwise the result is undefined. + * + * Returns zero on success or -EFAULT on error. + * + * Note: an error indicates that either the kernel is out of memory or + * the guest memory mapping is broken. In any case the best solution + * would be to terminate the guest. + * It is wrong to inject a guest exception. + */ +static inline __must_check +int read_guest_lc(struct kvm_vcpu *vcpu, unsigned long gra, void *data, + unsigned long len) +{ + unsigned long gpa = gra + vcpu->arch.sie_block->prefix; + + return kvm_read_guest(vcpu->kvm, gpa, data, len); +} + +int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, void *data, + unsigned long len, int write); + +int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra, + void *data, unsigned long len, int write); + +/** + * write_guest - copy data from kernel space to guest space + * @vcpu: virtual cpu + * @ga: guest address + * @data: source address in kernel space + * @len: number of bytes to copy + * + * Copy @len bytes from @data (kernel space) to @ga (guest address). + * In order to copy data to guest space the PSW of the vcpu is inspected: + * If DAT is off data will be copied to guest real or absolute memory. + * If DAT is on data will be copied to the address space as specified by + * the address space bits of the PSW: + * Primary, secondory or home space (access register mode is currently not + * implemented). + * The addressing mode of the PSW is also inspected, so that address wrap + * around is taken into account for 24-, 31- and 64-bit addressing mode, + * if the to be copied data crosses page boundaries in guest address space. + * In addition also low address and DAT protection are inspected before + * copying any data (key protection is currently not implemented). + * + * This function modifies the 'struct kvm_s390_pgm_info pgm' member of @vcpu. + * In case of an access exception (e.g. protection exception) pgm will contain + * all data necessary so that a subsequent call to 'kvm_s390_inject_prog_vcpu()' + * will inject a correct exception into the guest. + * If no access exception happened, the contents of pgm are undefined when + * this function returns. + * + * Returns: - zero on success + * - a negative value if e.g. the guest mapping is broken or in + * case of out-of-memory. In this case the contents of pgm are + * undefined. Also parts of @data may have been copied to guest + * space. + * - a positive value if an access exception happened. In this case + * the returned value is the program interruption code and the + * contents of pgm may be used to inject an exception into the + * guest. No data has been copied to guest space. + * + * Note: in case an access exception is recognized no data has been copied to + * guest space (this is also true, if the to be copied data would cross + * one or more page boundaries in guest space). + * Therefore this function may be used for nullifying and suppressing + * instruction emulation. + * It may also be used for terminating instructions, if it is undefined + * if data has been changed in guest space in case of an exception. + */ +static inline __must_check +int write_guest(struct kvm_vcpu *vcpu, unsigned long ga, void *data, + unsigned long len) +{ + return access_guest(vcpu, ga, data, len, 1); +} + +/** + * read_guest - copy data from guest space to kernel space + * @vcpu: virtual cpu + * @ga: guest address + * @data: destination address in kernel space + * @len: number of bytes to copy + * + * Copy @len bytes from @ga (guest address) to @data (kernel space). + * + * The behaviour of read_guest is identical to write_guest, except that + * data will be copied from guest space to kernel space. + */ +static inline __must_check +int read_guest(struct kvm_vcpu *vcpu, unsigned long ga, void *data, + unsigned long len) +{ + return access_guest(vcpu, ga, data, len, 0); +} + +/** + * write_guest_abs - copy data from kernel space to guest space absolute + * @vcpu: virtual cpu + * @gpa: guest physical (absolute) address + * @data: source address in kernel space + * @len: number of bytes to copy + * + * Copy @len bytes from @data (kernel space) to @gpa (guest absolute address). + * It is up to the caller to ensure that the entire guest memory range is + * valid memory before calling this function. + * Guest low address and key protection are not checked. + * + * Returns zero on success or -EFAULT on error. + * + * If an error occurs data may have been copied partially to guest memory. + */ +static inline __must_check +int write_guest_abs(struct kvm_vcpu *vcpu, unsigned long gpa, void *data, + unsigned long len) +{ + return kvm_write_guest(vcpu->kvm, gpa, data, len); +} + +/** + * read_guest_abs - copy data from guest space absolute to kernel space + * @vcpu: virtual cpu + * @gpa: guest physical (absolute) address + * @data: destination address in kernel space + * @len: number of bytes to copy + * + * Copy @len bytes from @gpa (guest absolute address) to @data (kernel space). + * It is up to the caller to ensure that the entire guest memory range is + * valid memory before calling this function. + * Guest key protection is not checked. + * + * Returns zero on success or -EFAULT on error. + * + * If an error occurs data may have been copied partially to kernel space. + */ +static inline __must_check +int read_guest_abs(struct kvm_vcpu *vcpu, unsigned long gpa, void *data, + unsigned long len) +{ + return kvm_read_guest(vcpu->kvm, gpa, data, len); +} + +/** + * write_guest_real - copy data from kernel space to guest space real + * @vcpu: virtual cpu + * @gra: guest real address + * @data: source address in kernel space + * @len: number of bytes to copy + * + * Copy @len bytes from @data (kernel space) to @gra (guest real address). + * It is up to the caller to ensure that the entire guest memory range is + * valid memory before calling this function. + * Guest low address and key protection are not checked. + * + * Returns zero on success or -EFAULT on error. + * + * If an error occurs data may have been copied partially to guest memory. + */ +static inline __must_check +int write_guest_real(struct kvm_vcpu *vcpu, unsigned long gra, void *data, + unsigned long len) +{ + return access_guest_real(vcpu, gra, data, len, 1); +} + +/** + * read_guest_real - copy data from guest space real to kernel space + * @vcpu: virtual cpu + * @gra: guest real address + * @data: destination address in kernel space + * @len: number of bytes to copy + * + * Copy @len bytes from @gra (guest real address) to @data (kernel space). + * It is up to the caller to ensure that the entire guest memory range is + * valid memory before calling this function. + * Guest key protection is not checked. + * + * Returns zero on success or -EFAULT on error. + * + * If an error occurs data may have been copied partially to kernel space. + */ +static inline __must_check +int read_guest_real(struct kvm_vcpu *vcpu, unsigned long gra, void *data, + unsigned long len) { - unsigned long _len, rc; - void __user *uptr; - - while (len) { - uptr = to_guest ? (void __user *)to : (void __user *)from; - uptr = __gptr_to_uptr(vcpu, uptr, prefixing); - if (IS_ERR((void __force *)uptr)) - return -EFAULT; - _len = PAGE_SIZE - ((unsigned long)uptr & (PAGE_SIZE - 1)); - _len = min(_len, len); - if (to_guest) - rc = copy_to_user((void __user *) uptr, (void *)from, _len); - else - rc = copy_from_user((void *)to, (void __user *)uptr, _len); - if (rc) - return -EFAULT; - len -= _len; - from += _len; - to += _len; - } - return 0; + return access_guest_real(vcpu, gra, data, len, 0); } -#define copy_to_guest(vcpu, to, from, size) \ - __copy_guest(vcpu, to, (unsigned long)from, size, 1, 1) -#define copy_from_guest(vcpu, to, from, size) \ - __copy_guest(vcpu, (unsigned long)to, from, size, 0, 1) -#define copy_to_guest_absolute(vcpu, to, from, size) \ - __copy_guest(vcpu, to, (unsigned long)from, size, 1, 0) -#define copy_from_guest_absolute(vcpu, to, from, size) \ - __copy_guest(vcpu, (unsigned long)to, from, size, 0, 0) +int ipte_lock_held(struct kvm_vcpu *vcpu); +int kvm_s390_check_low_addr_protection(struct kvm_vcpu *vcpu, unsigned long ga); #endif /* __KVM_S390_GACCESS_H */ diff --git a/arch/s390/kvm/guestdbg.c b/arch/s390/kvm/guestdbg.c new file mode 100644 index 00000000000000..757ccef62fd592 --- /dev/null +++ b/arch/s390/kvm/guestdbg.c @@ -0,0 +1,481 @@ +/* + * kvm guest debug support + * + * Copyright IBM Corp. 2014 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + * + * Author(s): David Hildenbrand + */ +#include +#include +#include "kvm-s390.h" +#include "gaccess.h" + +/* + * Extends the address range given by *start and *stop to include the address + * range starting with estart and the length len. Takes care of overflowing + * intervals and tries to minimize the overall intervall size. + */ +static void extend_address_range(u64 *start, u64 *stop, u64 estart, int len) +{ + u64 estop; + + if (len > 0) + len--; + else + len = 0; + + estop = estart + len; + + /* 0-0 range represents "not set" */ + if ((*start == 0) && (*stop == 0)) { + *start = estart; + *stop = estop; + } else if (*start <= *stop) { + /* increase the existing range */ + if (estart < *start) + *start = estart; + if (estop > *stop) + *stop = estop; + } else { + /* "overflowing" interval, whereby *stop > *start */ + if (estart <= *stop) { + if (estop > *stop) + *stop = estop; + } else if (estop > *start) { + if (estart < *start) + *start = estart; + } + /* minimize the range */ + else if ((estop - *stop) < (*start - estart)) + *stop = estop; + else + *start = estart; + } +} + +#define MAX_INST_SIZE 6 + +static void enable_all_hw_bp(struct kvm_vcpu *vcpu) +{ + unsigned long start, len; + u64 *cr9 = &vcpu->arch.sie_block->gcr[9]; + u64 *cr10 = &vcpu->arch.sie_block->gcr[10]; + u64 *cr11 = &vcpu->arch.sie_block->gcr[11]; + int i; + + if (vcpu->arch.guestdbg.nr_hw_bp <= 0 || + vcpu->arch.guestdbg.hw_bp_info == NULL) + return; + + /* + * If the guest is not interrested in branching events, we can savely + * limit them to the PER address range. + */ + if (!(*cr9 & PER_EVENT_BRANCH)) + *cr9 |= PER_CONTROL_BRANCH_ADDRESS; + *cr9 |= PER_EVENT_IFETCH | PER_EVENT_BRANCH; + + for (i = 0; i < vcpu->arch.guestdbg.nr_hw_bp; i++) { + start = vcpu->arch.guestdbg.hw_bp_info[i].addr; + len = vcpu->arch.guestdbg.hw_bp_info[i].len; + + /* + * The instruction in front of the desired bp has to + * report instruction-fetching events + */ + if (start < MAX_INST_SIZE) { + len += start; + start = 0; + } else { + start -= MAX_INST_SIZE; + len += MAX_INST_SIZE; + } + + extend_address_range(cr10, cr11, start, len); + } +} + +static void enable_all_hw_wp(struct kvm_vcpu *vcpu) +{ + unsigned long start, len; + u64 *cr9 = &vcpu->arch.sie_block->gcr[9]; + u64 *cr10 = &vcpu->arch.sie_block->gcr[10]; + u64 *cr11 = &vcpu->arch.sie_block->gcr[11]; + int i; + + if (vcpu->arch.guestdbg.nr_hw_wp <= 0 || + vcpu->arch.guestdbg.hw_wp_info == NULL) + return; + + /* if host uses storage alternation for special address + * spaces, enable all events and give all to the guest */ + if (*cr9 & PER_EVENT_STORE && *cr9 & PER_CONTROL_ALTERATION) { + *cr9 &= ~PER_CONTROL_ALTERATION; + *cr10 = 0; + *cr11 = PSW_ADDR_INSN; + } else { + *cr9 &= ~PER_CONTROL_ALTERATION; + *cr9 |= PER_EVENT_STORE; + + for (i = 0; i < vcpu->arch.guestdbg.nr_hw_wp; i++) { + start = vcpu->arch.guestdbg.hw_wp_info[i].addr; + len = vcpu->arch.guestdbg.hw_wp_info[i].len; + + extend_address_range(cr10, cr11, start, len); + } + } +} + +void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu) +{ + vcpu->arch.guestdbg.cr0 = vcpu->arch.sie_block->gcr[0]; + vcpu->arch.guestdbg.cr9 = vcpu->arch.sie_block->gcr[9]; + vcpu->arch.guestdbg.cr10 = vcpu->arch.sie_block->gcr[10]; + vcpu->arch.guestdbg.cr11 = vcpu->arch.sie_block->gcr[11]; +} + +void kvm_s390_restore_guest_per_regs(struct kvm_vcpu *vcpu) +{ + vcpu->arch.sie_block->gcr[0] = vcpu->arch.guestdbg.cr0; + vcpu->arch.sie_block->gcr[9] = vcpu->arch.guestdbg.cr9; + vcpu->arch.sie_block->gcr[10] = vcpu->arch.guestdbg.cr10; + vcpu->arch.sie_block->gcr[11] = vcpu->arch.guestdbg.cr11; +} + +void kvm_s390_patch_guest_per_regs(struct kvm_vcpu *vcpu) +{ + /* + * TODO: if guest psw has per enabled, otherwise 0s! + * This reduces the amount of reported events. + * Need to intercept all psw changes! + */ + + if (guestdbg_sstep_enabled(vcpu)) { + /* disable timer (clock-comparator) interrupts */ + vcpu->arch.sie_block->gcr[0] &= ~0x800ul; + vcpu->arch.sie_block->gcr[9] |= PER_EVENT_IFETCH; + vcpu->arch.sie_block->gcr[10] = 0; + vcpu->arch.sie_block->gcr[11] = PSW_ADDR_INSN; + } + + if (guestdbg_hw_bp_enabled(vcpu)) { + enable_all_hw_bp(vcpu); + enable_all_hw_wp(vcpu); + } + + /* TODO: Instruction-fetching-nullification not allowed for now */ + if (vcpu->arch.sie_block->gcr[9] & PER_EVENT_NULLIFICATION) + vcpu->arch.sie_block->gcr[9] &= ~PER_EVENT_NULLIFICATION; +} + +#define MAX_WP_SIZE 100 + +static int __import_wp_info(struct kvm_vcpu *vcpu, + struct kvm_hw_breakpoint *bp_data, + struct kvm_hw_wp_info_arch *wp_info) +{ + int ret = 0; + wp_info->len = bp_data->len; + wp_info->addr = bp_data->addr; + wp_info->phys_addr = bp_data->phys_addr; + wp_info->old_data = NULL; + + if (wp_info->len < 0 || wp_info->len > MAX_WP_SIZE) + return -EINVAL; + + wp_info->old_data = kmalloc(bp_data->len, GFP_KERNEL); + if (!wp_info->old_data) + return -ENOMEM; + /* try to backup the original value */ + ret = read_guest(vcpu, wp_info->phys_addr, wp_info->old_data, + wp_info->len); + if (ret) { + kfree(wp_info->old_data); + wp_info->old_data = NULL; + } + + return ret; +} + +#define MAX_BP_COUNT 50 + +int kvm_s390_import_bp_data(struct kvm_vcpu *vcpu, + struct kvm_guest_debug *dbg) +{ + int ret = 0, nr_wp = 0, nr_bp = 0, i, size; + struct kvm_hw_breakpoint *bp_data = NULL; + struct kvm_hw_wp_info_arch *wp_info = NULL; + struct kvm_hw_bp_info_arch *bp_info = NULL; + + if (dbg->arch.nr_hw_bp <= 0 || !dbg->arch.hw_bp) + return 0; + else if (dbg->arch.nr_hw_bp > MAX_BP_COUNT) + return -EINVAL; + + size = dbg->arch.nr_hw_bp * sizeof(struct kvm_hw_breakpoint); + bp_data = kmalloc(size, GFP_KERNEL); + if (!bp_data) { + ret = -ENOMEM; + goto error; + } + + ret = copy_from_user(bp_data, dbg->arch.hw_bp, size); + if (ret) + goto error; + + for (i = 0; i < dbg->arch.nr_hw_bp; i++) { + switch (bp_data[i].type) { + case KVM_HW_WP_WRITE: + nr_wp++; + break; + case KVM_HW_BP: + nr_bp++; + break; + default: + break; + } + } + + size = nr_wp * sizeof(struct kvm_hw_wp_info_arch); + if (size > 0) { + wp_info = kmalloc(size, GFP_KERNEL); + if (!wp_info) { + ret = -ENOMEM; + goto error; + } + } + size = nr_bp * sizeof(struct kvm_hw_bp_info_arch); + if (size > 0) { + bp_info = kmalloc(size, GFP_KERNEL); + if (!bp_info) { + ret = -ENOMEM; + goto error; + } + } + + for (nr_wp = 0, nr_bp = 0, i = 0; i < dbg->arch.nr_hw_bp; i++) { + switch (bp_data[i].type) { + case KVM_HW_WP_WRITE: + ret = __import_wp_info(vcpu, &bp_data[i], + &wp_info[nr_wp]); + if (ret) + goto error; + nr_wp++; + break; + case KVM_HW_BP: + bp_info[nr_bp].len = bp_data[i].len; + bp_info[nr_bp].addr = bp_data[i].addr; + nr_bp++; + break; + } + } + + vcpu->arch.guestdbg.nr_hw_bp = nr_bp; + vcpu->arch.guestdbg.hw_bp_info = bp_info; + vcpu->arch.guestdbg.nr_hw_wp = nr_wp; + vcpu->arch.guestdbg.hw_wp_info = wp_info; + return 0; +error: + kfree(bp_data); + kfree(wp_info); + kfree(bp_info); + return ret; +} + +void kvm_s390_clear_bp_data(struct kvm_vcpu *vcpu) +{ + int i; + struct kvm_hw_wp_info_arch *hw_wp_info = NULL; + + for (i = 0; i < vcpu->arch.guestdbg.nr_hw_wp; i++) { + hw_wp_info = &vcpu->arch.guestdbg.hw_wp_info[i]; + kfree(hw_wp_info->old_data); + hw_wp_info->old_data = NULL; + } + kfree(vcpu->arch.guestdbg.hw_wp_info); + vcpu->arch.guestdbg.hw_wp_info = NULL; + + kfree(vcpu->arch.guestdbg.hw_bp_info); + vcpu->arch.guestdbg.hw_bp_info = NULL; + + vcpu->arch.guestdbg.nr_hw_wp = 0; + vcpu->arch.guestdbg.nr_hw_bp = 0; +} + +static inline int in_addr_range(u64 addr, u64 a, u64 b) +{ + if (a <= b) + return (addr >= a) && (addr <= b); + else + /* "overflowing" interval */ + return (addr <= a) && (addr >= b); +} + +#define end_of_range(bp_info) (bp_info->addr + bp_info->len - 1) + +static struct kvm_hw_bp_info_arch *find_hw_bp(struct kvm_vcpu *vcpu, + unsigned long addr) +{ + struct kvm_hw_bp_info_arch *bp_info = vcpu->arch.guestdbg.hw_bp_info; + int i; + + if (vcpu->arch.guestdbg.nr_hw_bp == 0) + return NULL; + + for (i = 0; i < vcpu->arch.guestdbg.nr_hw_bp; i++) { + /* addr is directly the start or in the range of a bp */ + if (addr == bp_info->addr) + goto found; + if (bp_info->len > 0 && + in_addr_range(addr, bp_info->addr, end_of_range(bp_info))) + goto found; + + bp_info++; + } + + return NULL; +found: + return bp_info; +} + +static struct kvm_hw_wp_info_arch *any_wp_changed(struct kvm_vcpu *vcpu) +{ + int i; + struct kvm_hw_wp_info_arch *wp_info = NULL; + void *temp = NULL; + + if (vcpu->arch.guestdbg.nr_hw_wp == 0) + return NULL; + + for (i = 0; i < vcpu->arch.guestdbg.nr_hw_wp; i++) { + wp_info = &vcpu->arch.guestdbg.hw_wp_info[i]; + if (!wp_info || !wp_info->old_data || wp_info->len <= 0) + continue; + + temp = kmalloc(wp_info->len, GFP_KERNEL); + if (!temp) + continue; + + /* refetch the wp data and compare it to the old value */ + if (!read_guest(vcpu, wp_info->phys_addr, temp, + wp_info->len)) { + if (memcmp(temp, wp_info->old_data, wp_info->len)) { + kfree(temp); + return wp_info; + } + } + kfree(temp); + temp = NULL; + } + + return NULL; +} + +void kvm_s390_prepare_debug_exit(struct kvm_vcpu *vcpu) +{ + vcpu->run->exit_reason = KVM_EXIT_DEBUG; + vcpu->guest_debug &= ~KVM_GUESTDBG_EXIT_PENDING; +} + +#define per_bp_event(code) \ + (code & (PER_EVENT_IFETCH | PER_EVENT_BRANCH)) +#define per_write_wp_event(code) \ + (code & (PER_EVENT_STORE | PER_EVENT_STORE_REAL)) + +static int debug_exit_required(struct kvm_vcpu *vcpu) +{ + u32 perc = (vcpu->arch.sie_block->perc << 24); + struct kvm_debug_exit_arch *debug_exit = &vcpu->run->debug.arch; + struct kvm_hw_wp_info_arch *wp_info = NULL; + struct kvm_hw_bp_info_arch *bp_info = NULL; + unsigned long addr = vcpu->arch.sie_block->gpsw.addr; + unsigned long peraddr = vcpu->arch.sie_block->peraddr; + + if (guestdbg_hw_bp_enabled(vcpu)) { + if (per_write_wp_event(perc) && + vcpu->arch.guestdbg.nr_hw_wp > 0) { + wp_info = any_wp_changed(vcpu); + if (wp_info) { + debug_exit->addr = wp_info->addr; + debug_exit->type = KVM_HW_WP_WRITE; + goto exit_required; + } + } + if (per_bp_event(perc) && + vcpu->arch.guestdbg.nr_hw_bp > 0) { + bp_info = find_hw_bp(vcpu, addr); + /* remove duplicate events if PC==PER address */ + if (bp_info && (addr != peraddr)) { + debug_exit->addr = addr; + debug_exit->type = KVM_HW_BP; + vcpu->arch.guestdbg.last_bp = addr; + goto exit_required; + } + /* breakpoint missed */ + bp_info = find_hw_bp(vcpu, peraddr); + if (bp_info && vcpu->arch.guestdbg.last_bp != peraddr) { + debug_exit->addr = peraddr; + debug_exit->type = KVM_HW_BP; + goto exit_required; + } + } + } + if (guestdbg_sstep_enabled(vcpu) && per_bp_event(perc)) { + debug_exit->addr = addr; + debug_exit->type = KVM_SINGLESTEP; + goto exit_required; + } + + return 0; +exit_required: + return 1; +} + +#define guest_per_enabled(vcpu) \ + (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) + +static void filter_guest_per_event(struct kvm_vcpu *vcpu) +{ + u32 perc = vcpu->arch.sie_block->perc << 24; + u64 peraddr = vcpu->arch.sie_block->peraddr; + u64 addr = vcpu->arch.sie_block->gpsw.addr; + u64 cr9 = vcpu->arch.sie_block->gcr[9]; + u64 cr10 = vcpu->arch.sie_block->gcr[10]; + u64 cr11 = vcpu->arch.sie_block->gcr[11]; + /* filter all events, demanded by the guest */ + u32 guest_perc = perc & cr9 & PER_EVENT_MASK; + + if (!guest_per_enabled(vcpu)) + guest_perc = 0; + + /* filter "successful-branching" events */ + if (guest_perc & PER_EVENT_BRANCH && + cr9 & PER_CONTROL_BRANCH_ADDRESS && + !in_addr_range(addr, cr10, cr11)) + guest_perc &= ~PER_EVENT_BRANCH; + + /* filter "instruction-fetching" events */ + if (guest_perc & PER_EVENT_IFETCH && + !in_addr_range(peraddr, cr10, cr11)) + guest_perc &= ~PER_EVENT_IFETCH; + + /* All other PER events will be given to the guest */ + /* TODO: Check alterated address/address space */ + + vcpu->arch.sie_block->perc = guest_perc >> 24; + + if (!guest_perc) + vcpu->arch.sie_block->iprcc &= ~PGM_PER; +} + +void kvm_s390_handle_per_event(struct kvm_vcpu *vcpu) +{ + if (debug_exit_required(vcpu)) + vcpu->guest_debug |= KVM_GUESTDBG_EXIT_PENDING; + + filter_guest_per_event(vcpu); +} diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index eeb1ac7d8fa487..99e4b76e3487b5 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -1,7 +1,7 @@ /* * in-kernel handling for sie intercepts * - * Copyright IBM Corp. 2008, 2009 + * Copyright IBM Corp. 2008, 2014 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License (version 2 only) @@ -16,6 +16,7 @@ #include #include +#include #include "kvm-s390.h" #include "gaccess.h" @@ -29,6 +30,7 @@ static const intercept_handler_t instruction_handlers[256] = { [0x83] = kvm_s390_handle_diag, [0xae] = kvm_s390_handle_sigp, [0xb2] = kvm_s390_handle_b2, + [0xb6] = kvm_s390_handle_stctl, [0xb7] = kvm_s390_handle_lctl, [0xb9] = kvm_s390_handle_b9, [0xe5] = kvm_s390_handle_e5, @@ -63,8 +65,7 @@ static int handle_stop(struct kvm_vcpu *vcpu) trace_kvm_s390_stop_request(vcpu->arch.local_int.action_bits); if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) { - atomic_set_mask(CPUSTAT_STOPPED, - &vcpu->arch.sie_block->cpuflags); + kvm_s390_vcpu_stop(vcpu); vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP; VCPU_EVENT(vcpu, 3, "%s", "cpu stopped"); rc = -EOPNOTSUPP; @@ -109,22 +110,112 @@ static int handle_instruction(struct kvm_vcpu *vcpu) return -EOPNOTSUPP; } +static void __extract_prog_irq(struct kvm_vcpu *vcpu, + struct kvm_s390_pgm_info *pgm_info) +{ + memset(pgm_info, 0, sizeof(struct kvm_s390_pgm_info)); + pgm_info->code = vcpu->arch.sie_block->iprcc; + + switch (vcpu->arch.sie_block->iprcc & ~PGM_PER) { + case PGM_AFX_TRANSLATION: + case PGM_ASX_TRANSLATION: + case PGM_EX_TRANSLATION: + case PGM_LFX_TRANSLATION: + case PGM_LSTE_SEQUENCE: + case PGM_LSX_TRANSLATION: + case PGM_LX_TRANSLATION: + case PGM_PRIMARY_AUTHORITY: + case PGM_SECONDARY_AUTHORITY: + case PGM_SPACE_SWITCH: + pgm_info->trans_exc_code = vcpu->arch.sie_block->tecmc; + break; + case PGM_ALEN_TRANSLATION: + case PGM_ALE_SEQUENCE: + case PGM_ASTE_INSTANCE: + case PGM_ASTE_SEQUENCE: + case PGM_ASTE_VALIDITY: + case PGM_EXTENDED_AUTHORITY: + pgm_info->exc_access_id = vcpu->arch.sie_block->eai; + break; + case PGM_ASCE_TYPE: + case PGM_PAGE_TRANSLATION: + case PGM_REGION_FIRST_TRANS: + case PGM_REGION_SECOND_TRANS: + case PGM_REGION_THIRD_TRANS: + case PGM_SEGMENT_TRANSLATION: + pgm_info->trans_exc_code = vcpu->arch.sie_block->tecmc; + pgm_info->exc_access_id = vcpu->arch.sie_block->eai; + pgm_info->op_access_id = vcpu->arch.sie_block->oai; + break; + case PGM_MONITOR: + pgm_info->mon_class_nr = vcpu->arch.sie_block->mcn; + pgm_info->mon_code = vcpu->arch.sie_block->tecmc; + break; + case PGM_DATA: + pgm_info->data_exc_code = vcpu->arch.sie_block->dxc; + break; + case PGM_PROTECTION: + pgm_info->trans_exc_code = vcpu->arch.sie_block->tecmc; + pgm_info->exc_access_id = vcpu->arch.sie_block->eai; + break; + default: + break; + } + + if (vcpu->arch.sie_block->iprcc & PGM_PER) { + pgm_info->per_code = vcpu->arch.sie_block->perc; + pgm_info->per_atmid = vcpu->arch.sie_block->peratmid; + pgm_info->per_address = vcpu->arch.sie_block->peraddr; + pgm_info->per_access_id = vcpu->arch.sie_block->peraid; + } +} + +/* + * restore ITDB to program-interruption TDB in guest lowcore + * and set TX abort indication if required +*/ +static int handle_itdb(struct kvm_vcpu *vcpu) +{ + struct kvm_s390_itdb *itdb; + int rc; + + if (!IS_TE_ENABLED(vcpu) || !IS_ITDB_VALID(vcpu)) + return 0; + if (current->thread.per_flags & PER_FLAG_NO_TE) + return 0; + itdb = (struct kvm_s390_itdb *)vcpu->arch.sie_block->itdba; + rc = write_guest_lc(vcpu, __LC_PGM_TDB, itdb, sizeof(*itdb)); + if (rc) + return rc; + memset(itdb, 0, sizeof(*itdb)); + + return 0; +} + +#define per_event(vcpu) (vcpu->arch.sie_block->iprcc & PGM_PER) + static int handle_prog(struct kvm_vcpu *vcpu) { + struct kvm_s390_pgm_info pgm_info; + int rc; + vcpu->stat.exit_program_interruption++; - /* Restore ITDB to Program-Interruption TDB in guest memory */ - if (IS_TE_ENABLED(vcpu) && - !(current->thread.per_flags & PER_FLAG_NO_TE) && - IS_ITDB_VALID(vcpu)) { - copy_to_guest(vcpu, TDB_ADDR, vcpu->arch.sie_block->itdba, - sizeof(struct kvm_s390_itdb)); - memset((void *) vcpu->arch.sie_block->itdba, 0, - sizeof(struct kvm_s390_itdb)); + if (guestdbg_enabled(vcpu) && per_event(vcpu)) { + kvm_s390_handle_per_event(vcpu); + /* the interrupt might have been filtered out completely */ + if (vcpu->arch.sie_block->iprcc == 0) + return 0; } trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc); - return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc); + + rc = handle_itdb(vcpu); + if (rc) + return rc; + + __extract_prog_irq(vcpu, &pgm_info); + return kvm_s390_inject_prog_irq(vcpu, &pgm_info); } static int handle_instruction_and_prog(struct kvm_vcpu *vcpu) @@ -142,6 +233,58 @@ static int handle_instruction_and_prog(struct kvm_vcpu *vcpu) return rc2; } +/** + * Handle MOVE PAGE partial execution interception. + * + * This interception can only happen for guests with DAT disabled and + * addresses that are currently not mapped in the host. Thus we try to + * set up the mappings for the corresponding user pages here (or throw + * addressing exceptions in case of illegal guest addresses). + */ +static int handle_mvpg_pei(struct kvm_vcpu *vcpu) +{ + unsigned long hostaddr, srcaddr, dstaddr; + psw_t *psw = &vcpu->arch.sie_block->gpsw; + struct mm_struct *mm = current->mm; + int reg1, reg2, rc; + + kvm_s390_get_regs_rre(vcpu, ®1, ®2); + srcaddr = kvm_s390_real_to_abs(vcpu, vcpu->run->s.regs.gprs[reg2]); + dstaddr = kvm_s390_real_to_abs(vcpu, vcpu->run->s.regs.gprs[reg1]); + + /* Make sure that the source is paged-in */ + hostaddr = gmap_fault(srcaddr, vcpu->arch.gmap); + if (IS_ERR_VALUE(hostaddr)) + return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + down_read(&mm->mmap_sem); + rc = get_user_pages(current, mm, hostaddr, 1, 0, 0, NULL, NULL); + up_read(&mm->mmap_sem); + if (rc < 0) + return rc; + + /* Make sure that the destination is paged-in */ + hostaddr = gmap_fault(dstaddr, vcpu->arch.gmap); + if (IS_ERR_VALUE(hostaddr)) + return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + down_read(&mm->mmap_sem); + rc = get_user_pages(current, mm, hostaddr, 1, 1, 0, NULL, NULL); + up_read(&mm->mmap_sem); + if (rc < 0) + return rc; + + psw->addr = __rewind_psw(*psw, 4); + + return 0; +} + +static int handle_partial_execution(struct kvm_vcpu *vcpu) +{ + if (vcpu->arch.sie_block->ipa == 0xb254) /* MVPG */ + return handle_mvpg_pei(vcpu); + + return -EOPNOTSUPP; +} + static const intercept_handler_t intercept_funcs[] = { [0x00 >> 2] = handle_noop, [0x04 >> 2] = handle_instruction, @@ -153,6 +296,7 @@ static const intercept_handler_t intercept_funcs[] = { [0x1C >> 2] = kvm_s390_handle_wait, [0x20 >> 2] = handle_validity, [0x28 >> 2] = handle_stop, + [0x38 >> 2] = handle_partial_execution, }; int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu) diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 200a8f9390b68c..d9526bb291945c 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -56,6 +56,17 @@ static int psw_interrupts_disabled(struct kvm_vcpu *vcpu) return 1; } +static int ckc_interrupts_enabled(struct kvm_vcpu *vcpu) +{ + if (psw_extint_disabled(vcpu) || + !(vcpu->arch.sie_block->gcr[0] & 0x800ul)) + return 0; + if (guestdbg_enabled(vcpu) && guestdbg_sstep_enabled(vcpu)) + /* No timer interrupts when single stepping */ + return 0; + return 1; +} + static u64 int_word_to_isc_bits(u32 int_word) { u8 isc = (int_word & 0x38000000) >> 27; @@ -131,7 +142,13 @@ static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, &vcpu->arch.sie_block->cpuflags); vcpu->arch.sie_block->lctl = 0x0000; - vcpu->arch.sie_block->ictl &= ~ICTL_LPSW; + vcpu->arch.sie_block->ictl &= ~(ICTL_LPSW | ICTL_STCTL | ICTL_PINT); + + if (guestdbg_enabled(vcpu)) { + vcpu->arch.sie_block->lctl |= (LCTL_CR0 | LCTL_CR9 | + LCTL_CR10 | LCTL_CR11); + vcpu->arch.sie_block->ictl |= (ICTL_STCTL | ICTL_PINT); + } } static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag) @@ -174,6 +191,106 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu, } } +static int __deliver_prog_irq(struct kvm_vcpu *vcpu, + struct kvm_s390_pgm_info *pgm_info) +{ + const unsigned short table[] = { 2, 4, 4, 6 }; + int rc = 0; + + switch (pgm_info->code & ~PGM_PER) { + case PGM_AFX_TRANSLATION: + case PGM_ASX_TRANSLATION: + case PGM_EX_TRANSLATION: + case PGM_LFX_TRANSLATION: + case PGM_LSTE_SEQUENCE: + case PGM_LSX_TRANSLATION: + case PGM_LX_TRANSLATION: + case PGM_PRIMARY_AUTHORITY: + case PGM_SECONDARY_AUTHORITY: + case PGM_SPACE_SWITCH: + rc = put_guest_lc(vcpu, pgm_info->trans_exc_code, + (u64 *)__LC_TRANS_EXC_CODE); + break; + case PGM_ALEN_TRANSLATION: + case PGM_ALE_SEQUENCE: + case PGM_ASTE_INSTANCE: + case PGM_ASTE_SEQUENCE: + case PGM_ASTE_VALIDITY: + case PGM_EXTENDED_AUTHORITY: + rc = put_guest_lc(vcpu, pgm_info->exc_access_id, + (u8 *)__LC_EXC_ACCESS_ID); + break; + case PGM_ASCE_TYPE: + case PGM_PAGE_TRANSLATION: + case PGM_REGION_FIRST_TRANS: + case PGM_REGION_SECOND_TRANS: + case PGM_REGION_THIRD_TRANS: + case PGM_SEGMENT_TRANSLATION: + rc = put_guest_lc(vcpu, pgm_info->trans_exc_code, + (u64 *)__LC_TRANS_EXC_CODE); + rc |= put_guest_lc(vcpu, pgm_info->exc_access_id, + (u8 *)__LC_EXC_ACCESS_ID); + rc |= put_guest_lc(vcpu, pgm_info->op_access_id, + (u8 *)__LC_OP_ACCESS_ID); + break; + case PGM_MONITOR: + rc = put_guest_lc(vcpu, pgm_info->mon_class_nr, + (u64 *)__LC_MON_CLASS_NR); + rc |= put_guest_lc(vcpu, pgm_info->mon_code, + (u64 *)__LC_MON_CODE); + break; + case PGM_DATA: + rc = put_guest_lc(vcpu, pgm_info->data_exc_code, + (u32 *)__LC_DATA_EXC_CODE); + break; + case PGM_PROTECTION: + rc = put_guest_lc(vcpu, pgm_info->trans_exc_code, + (u64 *)__LC_TRANS_EXC_CODE); + rc |= put_guest_lc(vcpu, pgm_info->exc_access_id, + (u8 *)__LC_EXC_ACCESS_ID); + break; + } + + if (pgm_info->code & PGM_PER) { + rc |= put_guest_lc(vcpu, pgm_info->per_code, + (u8 *) __LC_PER_CODE); + rc |= put_guest_lc(vcpu, pgm_info->per_atmid, + (u8 *)__LC_PER_ATMID); + rc |= put_guest_lc(vcpu, pgm_info->per_address, + (u64 *) __LC_PER_ADDRESS); + rc |= put_guest_lc(vcpu, pgm_info->per_access_id, + (u8 *) __LC_PER_ACCESS_ID); + } + + switch (vcpu->arch.sie_block->icptcode) { + case ICPT_INST: + case ICPT_INSTPROGI: + case ICPT_OPEREXC: + case ICPT_PARTEXEC: + case ICPT_IOINST: + /* last instruction only stored for these icptcodes */ + rc |= put_guest_lc(vcpu, table[vcpu->arch.sie_block->ipa >> 14], + (u16 *) __LC_PGM_ILC); + break; + case ICPT_PROGI: + rc |= put_guest_lc(vcpu, vcpu->arch.sie_block->pgmilc, + (u16 *) __LC_PGM_ILC); + break; + default: + rc |= put_guest_lc(vcpu, 0, + (u16 *) __LC_PGM_ILC); + } + + rc |= put_guest_lc(vcpu, pgm_info->code, + (u16 *)__LC_PGM_INT_CODE); + rc |= write_guest_lc(vcpu, __LC_PGM_OLD_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + rc |= read_guest_lc(vcpu, __LC_PGM_NEW_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + + return rc; +} + static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, struct kvm_s390_interrupt_info *inti) { @@ -186,26 +303,28 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, vcpu->stat.deliver_emergency_signal++; trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, inti->emerg.code, 0); - rc = put_guest(vcpu, 0x1201, (u16 __user *)__LC_EXT_INT_CODE); - rc |= put_guest(vcpu, inti->emerg.code, - (u16 __user *)__LC_EXT_CPU_ADDR); - rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, + rc = put_guest_lc(vcpu, 0x1201, (u16 *)__LC_EXT_INT_CODE); + rc |= put_guest_lc(vcpu, inti->emerg.code, + (u16 *)__LC_EXT_CPU_ADDR); + rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); break; case KVM_S390_INT_EXTERNAL_CALL: VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call"); vcpu->stat.deliver_external_call++; trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, inti->extcall.code, 0); - rc = put_guest(vcpu, 0x1202, (u16 __user *)__LC_EXT_INT_CODE); - rc |= put_guest(vcpu, inti->extcall.code, - (u16 __user *)__LC_EXT_CPU_ADDR); - rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); + rc = put_guest_lc(vcpu, 0x1202, (u16 *)__LC_EXT_INT_CODE); + rc |= put_guest_lc(vcpu, inti->extcall.code, + (u16 *)__LC_EXT_CPU_ADDR); + rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, + &vcpu->arch.sie_block->gpsw, + sizeof(psw_t)); + rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, + &vcpu->arch.sie_block->gpsw, + sizeof(psw_t)); break; case KVM_S390_INT_SERVICE: VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", @@ -213,37 +332,39 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, vcpu->stat.deliver_service_signal++; trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, inti->ext.ext_params, 0); - rc = put_guest(vcpu, 0x2401, (u16 __user *)__LC_EXT_INT_CODE); - rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, + rc = put_guest_lc(vcpu, 0x2401, (u16 *)__LC_EXT_INT_CODE); + rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, + &vcpu->arch.sie_block->gpsw, + sizeof(psw_t)); + rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); - rc |= put_guest(vcpu, inti->ext.ext_params, - (u32 __user *)__LC_EXT_PARAMS); + rc |= put_guest_lc(vcpu, inti->ext.ext_params, + (u32 *)__LC_EXT_PARAMS); break; case KVM_S390_INT_PFAULT_INIT: trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, 0, inti->ext.ext_params2); - rc = put_guest(vcpu, 0x2603, (u16 __user *) __LC_EXT_INT_CODE); - rc |= put_guest(vcpu, 0x0600, (u16 __user *) __LC_EXT_CPU_ADDR); - rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, + rc = put_guest_lc(vcpu, 0x2603, (u16 *) __LC_EXT_INT_CODE); + rc |= put_guest_lc(vcpu, 0x0600, (u16 *) __LC_EXT_CPU_ADDR); + rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); - rc |= put_guest(vcpu, inti->ext.ext_params2, - (u64 __user *) __LC_EXT_PARAMS2); + rc |= put_guest_lc(vcpu, inti->ext.ext_params2, + (u64 *) __LC_EXT_PARAMS2); break; case KVM_S390_INT_PFAULT_DONE: trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, 0, inti->ext.ext_params2); - rc = put_guest(vcpu, 0x2603, (u16 __user *) __LC_EXT_INT_CODE); - rc |= put_guest(vcpu, 0x0680, (u16 __user *) __LC_EXT_CPU_ADDR); - rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, + rc = put_guest_lc(vcpu, 0x2603, (u16 *)__LC_EXT_INT_CODE); + rc |= put_guest_lc(vcpu, 0x0680, (u16 *)__LC_EXT_CPU_ADDR); + rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, + &vcpu->arch.sie_block->gpsw, + sizeof(psw_t)); + rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); - rc |= put_guest(vcpu, inti->ext.ext_params2, - (u64 __user *) __LC_EXT_PARAMS2); + rc |= put_guest_lc(vcpu, inti->ext.ext_params2, + (u64 *)__LC_EXT_PARAMS2); break; case KVM_S390_INT_VIRTIO: VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx", @@ -252,16 +373,17 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, inti->ext.ext_params, inti->ext.ext_params2); - rc = put_guest(vcpu, 0x2603, (u16 __user *)__LC_EXT_INT_CODE); - rc |= put_guest(vcpu, 0x0d00, (u16 __user *)__LC_EXT_CPU_ADDR); - rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, + rc = put_guest_lc(vcpu, 0x2603, (u16 *)__LC_EXT_INT_CODE); + rc |= put_guest_lc(vcpu, 0x0d00, (u16 *)__LC_EXT_CPU_ADDR); + rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, + &vcpu->arch.sie_block->gpsw, + sizeof(psw_t)); + rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); - rc |= put_guest(vcpu, inti->ext.ext_params, - (u32 __user *)__LC_EXT_PARAMS); - rc |= put_guest(vcpu, inti->ext.ext_params2, - (u64 __user *)__LC_EXT_PARAMS2); + rc |= put_guest_lc(vcpu, inti->ext.ext_params, + (u32 *)__LC_EXT_PARAMS); + rc |= put_guest_lc(vcpu, inti->ext.ext_params2, + (u64 *)__LC_EXT_PARAMS2); break; case KVM_S390_SIGP_STOP: VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop"); @@ -285,13 +407,13 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, vcpu->stat.deliver_restart_signal++; trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, 0, 0); - rc = copy_to_guest(vcpu, - offsetof(struct _lowcore, restart_old_psw), - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - offsetof(struct _lowcore, restart_psw), - sizeof(psw_t)); - atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); + rc = write_guest_lc(vcpu, + offsetof(struct _lowcore, restart_old_psw), + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + rc |= read_guest_lc(vcpu, offsetof(struct _lowcore, restart_psw), + &vcpu->arch.sie_block->gpsw, + sizeof(psw_t)); + kvm_s390_vcpu_start(vcpu); break; case KVM_S390_PROGRAM_INT: VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x", @@ -300,13 +422,7 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, vcpu->stat.deliver_program_int++; trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, inti->pgm.code, 0); - rc = put_guest(vcpu, inti->pgm.code, (u16 __user *)__LC_PGM_INT_CODE); - rc |= put_guest(vcpu, table[vcpu->arch.sie_block->ipa >> 14], - (u16 __user *)__LC_PGM_ILC); - rc |= copy_to_guest(vcpu, __LC_PGM_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_PGM_NEW_PSW, sizeof(psw_t)); + rc = __deliver_prog_irq(vcpu, &inti->pgm); break; case KVM_S390_MCHK: @@ -317,11 +433,12 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, inti->mchk.mcic); rc = kvm_s390_vcpu_store_status(vcpu, KVM_S390_STORE_STATUS_PREFIXED); - rc |= put_guest(vcpu, inti->mchk.mcic, (u64 __user *) __LC_MCCK_CODE); - rc |= copy_to_guest(vcpu, __LC_MCK_OLD_PSW, + rc |= put_guest_lc(vcpu, inti->mchk.mcic, (u64 *)__LC_MCCK_CODE); + rc |= write_guest_lc(vcpu, __LC_MCK_OLD_PSW, + &vcpu->arch.sie_block->gpsw, + sizeof(psw_t)); + rc |= read_guest_lc(vcpu, __LC_MCK_NEW_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_MCK_NEW_PSW, sizeof(psw_t)); break; case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: @@ -334,18 +451,20 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, vcpu->stat.deliver_io_int++; trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, param0, param1); - rc = put_guest(vcpu, inti->io.subchannel_id, - (u16 __user *) __LC_SUBCHANNEL_ID); - rc |= put_guest(vcpu, inti->io.subchannel_nr, - (u16 __user *) __LC_SUBCHANNEL_NR); - rc |= put_guest(vcpu, inti->io.io_int_parm, - (u32 __user *) __LC_IO_INT_PARM); - rc |= put_guest(vcpu, inti->io.io_int_word, - (u32 __user *) __LC_IO_INT_WORD); - rc |= copy_to_guest(vcpu, __LC_IO_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_IO_NEW_PSW, sizeof(psw_t)); + rc = put_guest_lc(vcpu, inti->io.subchannel_id, + (u16 *)__LC_SUBCHANNEL_ID); + rc |= put_guest_lc(vcpu, inti->io.subchannel_nr, + (u16 *)__LC_SUBCHANNEL_NR); + rc |= put_guest_lc(vcpu, inti->io.io_int_parm, + (u32 *)__LC_IO_INT_PARM); + rc |= put_guest_lc(vcpu, inti->io.io_int_word, + (u32 *)__LC_IO_INT_WORD); + rc |= write_guest_lc(vcpu, __LC_IO_OLD_PSW, + &vcpu->arch.sie_block->gpsw, + sizeof(psw_t)); + rc |= read_guest_lc(vcpu, __LC_IO_NEW_PSW, + &vcpu->arch.sie_block->gpsw, + sizeof(psw_t)); break; } default: @@ -358,25 +477,21 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, } } -static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu) +static void deliver_ckc_interrupt(struct kvm_vcpu *vcpu) { int rc; - if (psw_extint_disabled(vcpu)) - return 0; - if (!(vcpu->arch.sie_block->gcr[0] & 0x800ul)) - return 0; - rc = put_guest(vcpu, 0x1004, (u16 __user *)__LC_EXT_INT_CODE); - rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); + rc = put_guest_lc(vcpu, 0x1004, (u16 __user *)__LC_EXT_INT_CODE); + rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, + &vcpu->arch.sie_block->gpsw, + sizeof(psw_t)); if (rc) { printk("kvm: The guest lowcore is not mapped during interrupt " "delivery, killing userspace\n"); do_exit(SIGKILL); } - return 1; } int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu) @@ -406,19 +521,20 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu) spin_unlock(&fi->lock); } - if ((!rc) && (vcpu->arch.sie_block->ckc < - get_tod_clock_fast() + vcpu->arch.sie_block->epoch)) { - if ((!psw_extint_disabled(vcpu)) && - (vcpu->arch.sie_block->gcr[0] & 0x800ul)) - rc = 1; - } + if (!rc && kvm_cpu_has_pending_timer(vcpu)) + rc = 1; return rc; } int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) { - return 0; + if (!(vcpu->arch.sie_block->ckc < + get_tod_clock_fast() + vcpu->arch.sie_block->epoch)) + return 0; + if (!ckc_interrupts_enabled(vcpu)) + return 0; + return 1; } int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) @@ -441,8 +557,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) return -EOPNOTSUPP; /* disabled wait */ } - if (psw_extint_disabled(vcpu) || - (!(vcpu->arch.sie_block->gcr[0] & 0x800ul))) { + if (!ckc_interrupts_enabled(vcpu)) { VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer"); goto no_timer; } @@ -554,9 +669,8 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) } while (deliver); } - if ((vcpu->arch.sie_block->ckc < - get_tod_clock_fast() + vcpu->arch.sie_block->epoch)) - __try_deliver_ckc_interrupt(vcpu); + if (kvm_cpu_has_pending_timer(vcpu)) + deliver_ckc_interrupt(vcpu); if (atomic_read(&fi->active)) { do { @@ -660,6 +774,31 @@ int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) return 0; } +int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu, + struct kvm_s390_pgm_info *pgm_info) +{ + struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; + struct kvm_s390_interrupt_info *inti; + + inti = kzalloc(sizeof(*inti), GFP_KERNEL); + if (!inti) + return -ENOMEM; + + VCPU_EVENT(vcpu, 3, "inject: prog irq %d (from kernel)", + pgm_info->code); + trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_PROGRAM_INT, + pgm_info->code, 0, 1); + + inti->type = KVM_S390_PROGRAM_INT; + memcpy(&inti->pgm, pgm_info, sizeof(inti->pgm)); + spin_lock_bh(&li->lock); + list_add(&inti->list, &li->list); + atomic_set(&li->active, 1); + BUG_ON(waitqueue_active(li->wq)); + spin_unlock_bh(&li->lock); + return 0; +} + struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, u64 cr6, u64 schid) { @@ -810,6 +949,12 @@ int kvm_s390_inject_vm(struct kvm *kvm, return __inject_vm(kvm, inti); } +void kvm_s390_reinject_io_int(struct kvm *kvm, + struct kvm_s390_interrupt_info *inti) +{ + __inject_vm(kvm, inti); +} + int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, struct kvm_s390_interrupt *s390int) { @@ -900,7 +1045,7 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, return 0; } -static void clear_floating_interrupts(struct kvm *kvm) +void kvm_s390_clear_float_irqs(struct kvm *kvm) { struct kvm_s390_float_interrupt *fi; struct kvm_s390_interrupt_info *n, *inti = NULL; @@ -1246,7 +1391,7 @@ static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) break; case KVM_DEV_FLIC_CLEAR_IRQS: r = 0; - clear_floating_interrupts(dev->kvm); + kvm_s390_clear_float_irqs(dev->kvm); break; case KVM_DEV_FLIC_APF_ENABLE: dev->kvm->arch.gmap->pfault_enabled = 1; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index b3ecb8f5b6ce2b..05fc1e17ddce20 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -11,6 +11,7 @@ * Christian Borntraeger * Heiko Carstens * Christian Ehrhardt + * Jason J. Herne */ #include @@ -51,6 +52,8 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) }, { "instruction_lctlg", VCPU_STAT(instruction_lctlg) }, { "instruction_lctl", VCPU_STAT(instruction_lctl) }, + { "instruction_stctl", VCPU_STAT(instruction_stctl) }, + { "instruction_stctg", VCPU_STAT(instruction_stctg) }, { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) }, { "deliver_external_call", VCPU_STAT(deliver_external_call) }, { "deliver_service_signal", VCPU_STAT(deliver_service_signal) }, @@ -66,6 +69,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "instruction_stpx", VCPU_STAT(instruction_stpx) }, { "instruction_stap", VCPU_STAT(instruction_stap) }, { "instruction_storage_key", VCPU_STAT(instruction_storage_key) }, + { "instruction_ipte_interlock", VCPU_STAT(instruction_ipte_interlock) }, { "instruction_stsch", VCPU_STAT(instruction_stsch) }, { "instruction_chsc", VCPU_STAT(instruction_chsc) }, { "instruction_essa", VCPU_STAT(instruction_essa) }, @@ -90,7 +94,7 @@ unsigned long *vfacilities; static struct gmap_notifier gmap_notifier; /* test availability of vfacility */ -static inline int test_vfacility(unsigned long nr) +int test_vfacility(unsigned long nr) { return __test_facility(nr, (void *) vfacilities); } @@ -161,6 +165,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_IOEVENTFD: case KVM_CAP_DEVICE_CTRL: case KVM_CAP_ENABLE_CAP_VM: + case KVM_CAP_VM_ATTRIBUTES: r = 1; break; case KVM_CAP_NR_VCPUS: @@ -179,6 +184,25 @@ int kvm_dev_ioctl_check_extension(long ext) return r; } +static void kvm_s390_sync_dirty_log(struct kvm *kvm, + struct kvm_memory_slot *memslot) +{ + gfn_t cur_gfn, last_gfn; + unsigned long address; + struct gmap *gmap = kvm->arch.gmap; + + down_read(&gmap->mm->mmap_sem); + /* Loop over all guest pages */ + last_gfn = memslot->base_gfn + memslot->npages; + for (cur_gfn = memslot->base_gfn; cur_gfn <= last_gfn; cur_gfn++) { + address = gfn_to_hva_memslot(memslot, cur_gfn); + + if (gmap_test_and_clear_dirty(address, gmap)) + mark_page_dirty(kvm, cur_gfn); + } + up_read(&gmap->mm->mmap_sem); +} + /* Section: vm related */ /* * Get (and clear) the dirty memory log for a memory slot. @@ -186,7 +210,36 @@ int kvm_dev_ioctl_check_extension(long ext) int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) { - return 0; + int r; + unsigned long n; + struct kvm_memory_slot *memslot; + int is_dirty = 0; + + mutex_lock(&kvm->slots_lock); + + r = -EINVAL; + if (log->slot >= KVM_USER_MEM_SLOTS) + goto out; + + memslot = id_to_memslot(kvm->memslots, log->slot); + r = -ENOENT; + if (!memslot->dirty_bitmap) + goto out; + + kvm_s390_sync_dirty_log(kvm, memslot); + r = kvm_get_dirty_log(kvm, log, &is_dirty); + if (r) + goto out; + + /* Clear the dirty log */ + if (is_dirty) { + n = kvm_dirty_bitmap_bytes(memslot); + memset(memslot->dirty_bitmap, 0, n); + } + r = 0; +out: + mutex_unlock(&kvm->slots_lock); + return r; } static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) @@ -208,11 +261,86 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) return r; } +static int kvm_s390_mem_control(struct kvm *kvm, struct kvm_device_attr *attr) +{ + int ret; + unsigned int idx; + switch (attr->attr) { + case KVM_S390_VM_MEM_ENABLE_CMMA: + ret = -EBUSY; + mutex_lock(&kvm->lock); + if (atomic_read(&kvm->online_vcpus) == 0) { + kvm->arch.use_cmma = 1; + ret = 0; + } + mutex_unlock(&kvm->lock); + break; + case KVM_S390_VM_MEM_CLR_CMMA: + mutex_lock(&kvm->lock); + idx = srcu_read_lock(&kvm->srcu); + page_table_reset_pgste(kvm->arch.gmap->mm, 0, TASK_SIZE, false); + srcu_read_unlock(&kvm->srcu, idx); + mutex_unlock(&kvm->lock); + ret = 0; + break; + default: + ret = -ENXIO; + break; + } + return ret; +} + +static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) +{ + int ret; + + switch (attr->group) { + case KVM_S390_VM_MEM_CTRL: + ret = kvm_s390_mem_control(kvm, attr); + break; + default: + ret = -ENXIO; + break; + } + + return ret; +} + +static int kvm_s390_vm_get_attr(struct kvm *kvm, struct kvm_device_attr *attr) +{ + return -ENXIO; +} + +static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) +{ + int ret; + + switch (attr->group) { + case KVM_S390_VM_MEM_CTRL: + switch (attr->attr) { + case KVM_S390_VM_MEM_ENABLE_CMMA: + case KVM_S390_VM_MEM_CLR_CMMA: + ret = 0; + break; + default: + ret = -ENXIO; + break; + } + break; + default: + ret = -ENXIO; + break; + } + + return ret; +} + long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { struct kvm *kvm = filp->private_data; void __user *argp = (void __user *)arg; + struct kvm_device_attr attr; int r; switch (ioctl) { @@ -245,6 +373,27 @@ long kvm_arch_vm_ioctl(struct file *filp, } break; } + case KVM_SET_DEVICE_ATTR: { + r = -EFAULT; + if (copy_from_user(&attr, (void __user *)arg, sizeof(attr))) + break; + r = kvm_s390_vm_set_attr(kvm, &attr); + break; + } + case KVM_GET_DEVICE_ATTR: { + r = -EFAULT; + if (copy_from_user(&attr, (void __user *)arg, sizeof(attr))) + break; + r = kvm_s390_vm_get_attr(kvm, &attr); + break; + } + case KVM_HAS_DEVICE_ATTR: { + r = -EFAULT; + if (copy_from_user(&attr, (void __user *)arg, sizeof(attr))) + break; + r = kvm_s390_vm_has_attr(kvm, &attr); + break; + } default: r = -ENOTTY; } @@ -291,6 +440,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) spin_lock_init(&kvm->arch.float_int.lock); INIT_LIST_HEAD(&kvm->arch.float_int.list); + init_waitqueue_head(&kvm->arch.ipte_wq); debug_register_view(kvm->arch.dbf, &debug_sprintf_view); VM_EVENT(kvm, 3, "%s", "vm created"); @@ -308,6 +458,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) kvm->arch.css_support = 0; kvm->arch.use_irqchip = 0; + spin_lock_init(&kvm->arch.start_stop_lock); + return 0; out_nogmap: debug_unregister(kvm->arch.dbf); @@ -321,6 +473,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) { VCPU_EVENT(vcpu, 3, "%s", "free cpu"); trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id); + kvm_s390_clear_local_irqs(vcpu); kvm_clear_async_pf_completion_queue(vcpu); if (!kvm_is_ucontrol(vcpu->kvm)) { clear_bit(63 - vcpu->vcpu_id, @@ -334,9 +487,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) if (kvm_is_ucontrol(vcpu->kvm)) gmap_free(vcpu->arch.gmap); - if (vcpu->arch.sie_block->cbrlo) - __free_page(__pfn_to_page( - vcpu->arch.sie_block->cbrlo >> PAGE_SHIFT)); + if (kvm_s390_cmma_enabled(vcpu->kvm)) + kvm_s390_vcpu_unsetup_cmma(vcpu); free_page((unsigned long)(vcpu->arch.sie_block)); kvm_vcpu_uninit(vcpu); @@ -371,6 +523,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) if (!kvm_is_ucontrol(kvm)) gmap_free(kvm->arch.gmap); kvm_s390_destroy_adapters(kvm); + kvm_s390_clear_float_irqs(kvm); } /* Section: vcpu related */ @@ -441,7 +594,7 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) vcpu->arch.sie_block->pp = 0; vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; kvm_clear_async_pf_completion_queue(vcpu); - atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); + kvm_s390_vcpu_stop(vcpu); kvm_s390_clear_local_irqs(vcpu); } @@ -450,9 +603,26 @@ int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) return 0; } +void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu) +{ + free_page(vcpu->arch.sie_block->cbrlo); + vcpu->arch.sie_block->cbrlo = 0; +} + +int kvm_s390_vcpu_setup_cmma(struct kvm_vcpu *vcpu) +{ + vcpu->arch.sie_block->cbrlo = get_zeroed_page(GFP_KERNEL); + if (!vcpu->arch.sie_block->cbrlo) + return -ENOMEM; + + vcpu->arch.sie_block->ecb2 |= 0x80; + vcpu->arch.sie_block->ecb2 &= ~0x08; + return 0; +} + int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) { - struct page *cbrl; + int rc = 0; atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH | CPUSTAT_SM | @@ -463,15 +633,15 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) vcpu->arch.sie_block->ecb |= 0x10; vcpu->arch.sie_block->ecb2 = 8; - vcpu->arch.sie_block->eca = 0xC1002001U; + vcpu->arch.sie_block->eca = 0xC1002000U; + if (sclp_has_siif()) + vcpu->arch.sie_block->eca |= 1; vcpu->arch.sie_block->fac = (int) (long) vfacilities; - if (kvm_enabled_cmma()) { - cbrl = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (cbrl) { - vcpu->arch.sie_block->ecb2 |= 0x80; - vcpu->arch.sie_block->ecb2 &= ~0x08; - vcpu->arch.sie_block->cbrlo = page_to_phys(cbrl); - } + vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE; + if (kvm_s390_cmma_enabled(vcpu->kvm)) { + rc = kvm_s390_vcpu_setup_cmma(vcpu); + if (rc) + return rc; } hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet, @@ -479,7 +649,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) vcpu->arch.ckc_timer.function = kvm_s390_idle_wakeup; get_cpu_id(&vcpu->arch.cpu_id); vcpu->arch.cpu_id.version = 0xff; - return 0; + return rc; } struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, @@ -768,10 +938,40 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, return -EINVAL; /* not implemented yet */ } +#define VALID_GUESTDBG_FLAGS (KVM_GUESTDBG_SINGLESTEP | \ + KVM_GUESTDBG_USE_HW_BP | \ + KVM_GUESTDBG_ENABLE) + int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) { - return -EINVAL; /* not implemented yet */ + int rc = 0; + + vcpu->guest_debug = 0; + kvm_s390_clear_bp_data(vcpu); + + if (vcpu->guest_debug & ~VALID_GUESTDBG_FLAGS) + return -EINVAL; + + if (dbg->control & KVM_GUESTDBG_ENABLE) { + vcpu->guest_debug = dbg->control; + /* enforce guest PER */ + atomic_set_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); + + if (dbg->control & KVM_GUESTDBG_USE_HW_BP) + rc = kvm_s390_import_bp_data(vcpu, dbg); + } else { + atomic_clear_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); + vcpu->arch.guestdbg.last_bp = 0; + } + + if (rc) { + vcpu->guest_debug = 0; + kvm_s390_clear_bp_data(vcpu); + atomic_clear_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); + } + + return rc; } int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, @@ -786,8 +986,27 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, return -EINVAL; /* not implemented yet */ } +bool kvm_s390_cmma_enabled(struct kvm *kvm) +{ + if (!MACHINE_IS_LPAR) + return false; + /* only enable for z10 and later */ + if (!MACHINE_HAS_EDAT1) + return false; + if (!kvm->arch.use_cmma) + return false; + return true; +} + +static bool ibs_enabled(struct kvm_vcpu *vcpu) +{ + return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_IBS; +} + static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) { +retry: + s390_vcpu_unblock(vcpu); /* * We use MMU_RELOAD just to re-arm the ipte notifier for the * guest prefix page. gmap_ipte_notify will wait on the ptl lock. @@ -795,15 +1014,34 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) * already finished. We might race against a second unmapper that * wants to set the blocking bit. Lets just retry the request loop. */ - while (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu)) { + if (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu)) { int rc; rc = gmap_ipte_notify(vcpu->arch.gmap, vcpu->arch.sie_block->prefix, PAGE_SIZE * 2); if (rc) return rc; - s390_vcpu_unblock(vcpu); + goto retry; + } + + if (kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu)) { + if (!ibs_enabled(vcpu)) { + trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 1); + atomic_set_mask(CPUSTAT_IBS, + &vcpu->arch.sie_block->cpuflags); + } + goto retry; } + + if (kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu)) { + if (ibs_enabled(vcpu)) { + trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 0); + atomic_clear_mask(CPUSTAT_IBS, + &vcpu->arch.sie_block->cpuflags); + } + goto retry; + } + return 0; } @@ -882,8 +1120,9 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu) if (!vcpu->arch.gmap->pfault_enabled) return 0; - hva = gmap_fault(current->thread.gmap_addr, vcpu->arch.gmap); - if (copy_from_guest(vcpu, &arch.pfault_token, vcpu->arch.pfault_token, 8)) + hva = gfn_to_hva(vcpu->kvm, gpa_to_gfn(current->thread.gmap_addr)); + hva += current->thread.gmap_addr & ~PAGE_MASK; + if (read_guest_real(vcpu, vcpu->arch.pfault_token, &arch.pfault_token, 8)) return 0; rc = kvm_setup_async_pf(vcpu, current->thread.gmap_addr, hva, &arch); @@ -906,7 +1145,7 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu) if (need_resched()) schedule(); - if (test_thread_flag(TIF_MCCK_PENDING)) + if (test_cpu_flag(CIF_MCCK_PENDING)) s390_handle_mcck(); if (!kvm_is_ucontrol(vcpu->kvm)) @@ -916,6 +1155,11 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu) if (rc) return rc; + if (guestdbg_enabled(vcpu)) { + kvm_s390_backup_guest_per_regs(vcpu); + kvm_s390_patch_guest_per_regs(vcpu); + } + vcpu->arch.sie_block->icptcode = 0; cpuflags = atomic_read(&vcpu->arch.sie_block->cpuflags); VCPU_EVENT(vcpu, 6, "entering sie flags %x", cpuflags); @@ -932,6 +1176,9 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason) vcpu->arch.sie_block->icptcode); trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode); + if (guestdbg_enabled(vcpu)) + kvm_s390_restore_guest_per_regs(vcpu); + if (exit_reason >= 0) { rc = 0; } else if (kvm_is_ucontrol(vcpu->kvm)) { @@ -968,16 +1215,6 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason) return rc; } -bool kvm_enabled_cmma(void) -{ - if (!MACHINE_IS_LPAR) - return false; - /* only enable for z10 and later */ - if (!MACHINE_HAS_EDAT1) - return false; - return true; -} - static int __vcpu_run(struct kvm_vcpu *vcpu) { int rc, exit_reason; @@ -1007,7 +1244,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); rc = vcpu_post_run(vcpu, exit_reason); - } while (!signal_pending(current) && !rc); + } while (!signal_pending(current) && !guestdbg_exit_pending(vcpu) && !rc); srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); return rc; @@ -1018,10 +1255,15 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) int rc; sigset_t sigsaved; + if (guestdbg_exit_pending(vcpu)) { + kvm_s390_prepare_debug_exit(vcpu); + return 0; + } + if (vcpu->sigset_active) sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); - atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); + kvm_s390_vcpu_start(vcpu); switch (kvm_run->exit_reason) { case KVM_EXIT_S390_SIEIC: @@ -1030,6 +1272,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) case KVM_EXIT_S390_RESET: case KVM_EXIT_S390_UCONTROL: case KVM_EXIT_S390_TSCH: + case KVM_EXIT_DEBUG: break; default: BUG(); @@ -1055,6 +1298,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) rc = -EINTR; } + if (guestdbg_exit_pending(vcpu) && !rc) { + kvm_s390_prepare_debug_exit(vcpu); + rc = 0; + } + if (rc == -EOPNOTSUPP) { /* intercept cannot be handled in-kernel, prepare kvm-run */ kvm_run->exit_reason = KVM_EXIT_S390_SIEIC; @@ -1082,83 +1330,50 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return rc; } -static int __guestcopy(struct kvm_vcpu *vcpu, u64 guestdest, void *from, - unsigned long n, int prefix) -{ - if (prefix) - return copy_to_guest(vcpu, guestdest, from, n); - else - return copy_to_guest_absolute(vcpu, guestdest, from, n); -} - /* * store status at address * we use have two special cases: * KVM_S390_STORE_STATUS_NOADDR: -> 0x1200 on 64 bit * KVM_S390_STORE_STATUS_PREFIXED: -> prefix */ -int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr) +int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long gpa) { unsigned char archmode = 1; - int prefix; u64 clkcomp; + int rc; - if (addr == KVM_S390_STORE_STATUS_NOADDR) { - if (copy_to_guest_absolute(vcpu, 163ul, &archmode, 1)) + if (gpa == KVM_S390_STORE_STATUS_NOADDR) { + if (write_guest_abs(vcpu, 163, &archmode, 1)) return -EFAULT; - addr = SAVE_AREA_BASE; - prefix = 0; - } else if (addr == KVM_S390_STORE_STATUS_PREFIXED) { - if (copy_to_guest(vcpu, 163ul, &archmode, 1)) + gpa = SAVE_AREA_BASE; + } else if (gpa == KVM_S390_STORE_STATUS_PREFIXED) { + if (write_guest_real(vcpu, 163, &archmode, 1)) return -EFAULT; - addr = SAVE_AREA_BASE; - prefix = 1; - } else - prefix = 0; - - if (__guestcopy(vcpu, addr + offsetof(struct save_area, fp_regs), - vcpu->arch.guest_fpregs.fprs, 128, prefix)) - return -EFAULT; - - if (__guestcopy(vcpu, addr + offsetof(struct save_area, gp_regs), - vcpu->run->s.regs.gprs, 128, prefix)) - return -EFAULT; - - if (__guestcopy(vcpu, addr + offsetof(struct save_area, psw), - &vcpu->arch.sie_block->gpsw, 16, prefix)) - return -EFAULT; - - if (__guestcopy(vcpu, addr + offsetof(struct save_area, pref_reg), - &vcpu->arch.sie_block->prefix, 4, prefix)) - return -EFAULT; - - if (__guestcopy(vcpu, - addr + offsetof(struct save_area, fp_ctrl_reg), - &vcpu->arch.guest_fpregs.fpc, 4, prefix)) - return -EFAULT; - - if (__guestcopy(vcpu, addr + offsetof(struct save_area, tod_reg), - &vcpu->arch.sie_block->todpr, 4, prefix)) - return -EFAULT; - - if (__guestcopy(vcpu, addr + offsetof(struct save_area, timer), - &vcpu->arch.sie_block->cputm, 8, prefix)) - return -EFAULT; - + gpa = kvm_s390_real_to_abs(vcpu, SAVE_AREA_BASE); + } + rc = write_guest_abs(vcpu, gpa + offsetof(struct save_area, fp_regs), + vcpu->arch.guest_fpregs.fprs, 128); + rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, gp_regs), + vcpu->run->s.regs.gprs, 128); + rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, psw), + &vcpu->arch.sie_block->gpsw, 16); + rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, pref_reg), + &vcpu->arch.sie_block->prefix, 4); + rc |= write_guest_abs(vcpu, + gpa + offsetof(struct save_area, fp_ctrl_reg), + &vcpu->arch.guest_fpregs.fpc, 4); + rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, tod_reg), + &vcpu->arch.sie_block->todpr, 4); + rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, timer), + &vcpu->arch.sie_block->cputm, 8); clkcomp = vcpu->arch.sie_block->ckc >> 8; - if (__guestcopy(vcpu, addr + offsetof(struct save_area, clk_cmp), - &clkcomp, 8, prefix)) - return -EFAULT; - - if (__guestcopy(vcpu, addr + offsetof(struct save_area, acc_regs), - &vcpu->run->s.regs.acrs, 64, prefix)) - return -EFAULT; - - if (__guestcopy(vcpu, - addr + offsetof(struct save_area, ctrl_regs), - &vcpu->arch.sie_block->gcr, 128, prefix)) - return -EFAULT; - return 0; + rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, clk_cmp), + &clkcomp, 8); + rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, acc_regs), + &vcpu->run->s.regs.acrs, 64); + rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, ctrl_regs), + &vcpu->arch.sie_block->gcr, 128); + return rc ? -EFAULT : 0; } int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) @@ -1175,6 +1390,109 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) return kvm_s390_store_status_unloaded(vcpu, addr); } +static inline int is_vcpu_stopped(struct kvm_vcpu *vcpu) +{ + return atomic_read(&(vcpu)->arch.sie_block->cpuflags) & CPUSTAT_STOPPED; +} + +static void __disable_ibs_on_vcpu(struct kvm_vcpu *vcpu) +{ + kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu); + kvm_make_request(KVM_REQ_DISABLE_IBS, vcpu); + exit_sie_sync(vcpu); +} + +static void __disable_ibs_on_all_vcpus(struct kvm *kvm) +{ + unsigned int i; + struct kvm_vcpu *vcpu; + + kvm_for_each_vcpu(i, vcpu, kvm) { + __disable_ibs_on_vcpu(vcpu); + } +} + +static void __enable_ibs_on_vcpu(struct kvm_vcpu *vcpu) +{ + kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu); + kvm_make_request(KVM_REQ_ENABLE_IBS, vcpu); + exit_sie_sync(vcpu); +} + +void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu) +{ + int i, online_vcpus, started_vcpus = 0; + + if (!is_vcpu_stopped(vcpu)) + return; + + trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 1); + /* Only one cpu at a time may enter/leave the STOPPED state. */ + spin_lock_bh(&vcpu->kvm->arch.start_stop_lock); + online_vcpus = atomic_read(&vcpu->kvm->online_vcpus); + + for (i = 0; i < online_vcpus; i++) { + if (!is_vcpu_stopped(vcpu->kvm->vcpus[i])) + started_vcpus++; + } + + if (started_vcpus == 0) { + /* we're the only active VCPU -> speed it up */ + __enable_ibs_on_vcpu(vcpu); + } else if (started_vcpus == 1) { + /* + * As we are starting a second VCPU, we have to disable + * the IBS facility on all VCPUs to remove potentially + * oustanding ENABLE requests. + */ + __disable_ibs_on_all_vcpus(vcpu->kvm); + } + + atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); + /* + * Another VCPU might have used IBS while we were offline. + * Let's play safe and flush the VCPU at startup. + */ + vcpu->arch.sie_block->ihcpu = 0xffff; + spin_unlock_bh(&vcpu->kvm->arch.start_stop_lock); + return; +} + +void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu) +{ + int i, online_vcpus, started_vcpus = 0; + struct kvm_vcpu *started_vcpu = NULL; + + if (is_vcpu_stopped(vcpu)) + return; + + trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 0); + /* Only one cpu at a time may enter/leave the STOPPED state. */ + spin_lock_bh(&vcpu->kvm->arch.start_stop_lock); + online_vcpus = atomic_read(&vcpu->kvm->online_vcpus); + + atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); + __disable_ibs_on_vcpu(vcpu); + + for (i = 0; i < online_vcpus; i++) { + if (!is_vcpu_stopped(vcpu->kvm->vcpus[i])) { + started_vcpus++; + started_vcpu = vcpu->kvm->vcpus[i]; + } + } + + if (started_vcpus == 1) { + /* + * As we only have one VCPU left, we want to enable the + * IBS facility for that VCPU to speed it up. + */ + __enable_ibs_on_vcpu(started_vcpu); + } + + spin_unlock_bh(&vcpu->kvm->arch.start_stop_lock); + return; +} + static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, struct kvm_enable_cap *cap) { diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 3c1e2274d9eae8..c28423a3acc086 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -28,7 +28,6 @@ int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu); /* Transactional Memory Execution related macros */ #define IS_TE_ENABLED(vcpu) ((vcpu->arch.sie_block->ecb & 0x10)) -#define TDB_ADDR 0x1800UL #define TDB_FORMAT1 1 #define IS_ITDB_VALID(vcpu) ((*(char *)vcpu->arch.sie_block->itdba == TDB_FORMAT1)) @@ -130,6 +129,7 @@ void kvm_s390_tasklet(unsigned long parm); void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu); void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu); void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu); +void kvm_s390_clear_float_irqs(struct kvm *kvm); int __must_check kvm_s390_inject_vm(struct kvm *kvm, struct kvm_s390_interrupt *s390int); int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, @@ -137,6 +137,8 @@ int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, u64 cr6, u64 schid); +void kvm_s390_reinject_io_int(struct kvm *kvm, + struct kvm_s390_interrupt_info *inti); int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked); /* implemented in priv.c */ @@ -145,6 +147,7 @@ int kvm_s390_handle_e5(struct kvm_vcpu *vcpu); int kvm_s390_handle_01(struct kvm_vcpu *vcpu); int kvm_s390_handle_b9(struct kvm_vcpu *vcpu); int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu); +int kvm_s390_handle_stctl(struct kvm_vcpu *vcpu); int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu); int kvm_s390_handle_eb(struct kvm_vcpu *vcpu); @@ -154,18 +157,70 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); /* implemented in kvm-s390.c */ int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr); int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr); +void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu); +void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu); void s390_vcpu_block(struct kvm_vcpu *vcpu); void s390_vcpu_unblock(struct kvm_vcpu *vcpu); void exit_sie(struct kvm_vcpu *vcpu); void exit_sie_sync(struct kvm_vcpu *vcpu); -/* are we going to support cmma? */ -bool kvm_enabled_cmma(void); +int kvm_s390_vcpu_setup_cmma(struct kvm_vcpu *vcpu); +void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu); +/* is cmma enabled */ +bool kvm_s390_cmma_enabled(struct kvm *kvm); +int test_vfacility(unsigned long nr); + /* implemented in diag.c */ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu); +/* implemented in interrupt.c */ +int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu, + struct kvm_s390_pgm_info *pgm_info); + +/** + * kvm_s390_inject_prog_cond - conditionally inject a program check + * @vcpu: virtual cpu + * @rc: original return/error code + * + * This function is supposed to be used after regular guest access functions + * failed, to conditionally inject a program check to a vcpu. The typical + * pattern would look like + * + * rc = write_guest(vcpu, addr, data, len); + * if (rc) + * return kvm_s390_inject_prog_cond(vcpu, rc); + * + * A negative return code from guest access functions implies an internal error + * like e.g. out of memory. In these cases no program check should be injected + * to the guest. + * A positive value implies that an exception happened while accessing a guest's + * memory. In this case all data belonging to the corresponding program check + * has been stored in vcpu->arch.pgm and can be injected with + * kvm_s390_inject_prog_irq(). + * + * Returns: - the original @rc value if @rc was negative (internal error) + * - zero if @rc was already zero + * - zero or error code from injecting if @rc was positive + * (program check injected to @vcpu) + */ +static inline int kvm_s390_inject_prog_cond(struct kvm_vcpu *vcpu, int rc) +{ + if (rc <= 0) + return rc; + return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm); +} /* implemented in interrupt.c */ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); int psw_extint_disabled(struct kvm_vcpu *vcpu); void kvm_s390_destroy_adapters(struct kvm *kvm); +/* implemented in guestdbg.c */ +void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu); +void kvm_s390_restore_guest_per_regs(struct kvm_vcpu *vcpu); +void kvm_s390_patch_guest_per_regs(struct kvm_vcpu *vcpu); +int kvm_s390_import_bp_data(struct kvm_vcpu *vcpu, + struct kvm_guest_debug *dbg); +void kvm_s390_clear_bp_data(struct kvm_vcpu *vcpu); +void kvm_s390_prepare_debug_exit(struct kvm_vcpu *vcpu); +void kvm_s390_handle_per_event(struct kvm_vcpu *vcpu); + #endif diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 476e9e218f43ee..07d0c1025cb9de 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -35,8 +35,8 @@ static int handle_set_clock(struct kvm_vcpu *vcpu) { struct kvm_vcpu *cpup; s64 hostclk, val; + int i, rc; u64 op2; - int i; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); @@ -44,8 +44,9 @@ static int handle_set_clock(struct kvm_vcpu *vcpu) op2 = kvm_s390_get_base_disp_s(vcpu); if (op2 & 7) /* Operand must be on a doubleword boundary */ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - if (get_guest(vcpu, val, (u64 __user *) op2)) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + rc = read_guest(vcpu, op2, &val, sizeof(val)); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); if (store_tod_clock(&hostclk)) { kvm_s390_set_psw_cc(vcpu, 3); @@ -65,8 +66,8 @@ static int handle_set_clock(struct kvm_vcpu *vcpu) static int handle_set_prefix(struct kvm_vcpu *vcpu) { u64 operand2; - u32 address = 0; - u8 tmp; + u32 address; + int rc; vcpu->stat.instruction_spx++; @@ -80,14 +81,18 @@ static int handle_set_prefix(struct kvm_vcpu *vcpu) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); /* get the value */ - if (get_guest(vcpu, address, (u32 __user *) operand2)) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + rc = read_guest(vcpu, operand2, &address, sizeof(address)); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); - address = address & 0x7fffe000u; + address &= 0x7fffe000u; - /* make sure that the new value is valid memory */ - if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || - (copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1))) + /* + * Make sure the new value is valid memory. We only need to check the + * first page, since address is 8k aligned and memory pieces are always + * at least 1MB aligned and have at least a size of 1MB. + */ + if (kvm_is_error_gpa(vcpu->kvm, address)) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); kvm_s390_set_prefix(vcpu, address); @@ -101,6 +106,7 @@ static int handle_store_prefix(struct kvm_vcpu *vcpu) { u64 operand2; u32 address; + int rc; vcpu->stat.instruction_stpx++; @@ -117,8 +123,9 @@ static int handle_store_prefix(struct kvm_vcpu *vcpu) address = address & 0x7fffe000u; /* get the value */ - if (put_guest(vcpu, address, (u32 __user *)operand2)) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + rc = write_guest(vcpu, operand2, &address, sizeof(address)); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); VCPU_EVENT(vcpu, 5, "storing prefix to %x", address); trace_kvm_s390_handle_prefix(vcpu, 0, address); @@ -127,28 +134,44 @@ static int handle_store_prefix(struct kvm_vcpu *vcpu) static int handle_store_cpu_address(struct kvm_vcpu *vcpu) { - u64 useraddr; + u16 vcpu_id = vcpu->vcpu_id; + u64 ga; + int rc; vcpu->stat.instruction_stap++; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); - useraddr = kvm_s390_get_base_disp_s(vcpu); + ga = kvm_s390_get_base_disp_s(vcpu); - if (useraddr & 1) + if (ga & 1) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - if (put_guest(vcpu, vcpu->vcpu_id, (u16 __user *)useraddr)) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + rc = write_guest(vcpu, ga, &vcpu_id, sizeof(vcpu_id)); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); - VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr); - trace_kvm_s390_handle_stap(vcpu, useraddr); + VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", ga); + trace_kvm_s390_handle_stap(vcpu, ga); return 0; } +static void __skey_check_enable(struct kvm_vcpu *vcpu) +{ + if (!(vcpu->arch.sie_block->ictl & (ICTL_ISKE | ICTL_SSKE | ICTL_RRBE))) + return; + + s390_enable_skey(); + trace_kvm_s390_skey_related_inst(vcpu); + vcpu->arch.sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE); +} + + static int handle_skey(struct kvm_vcpu *vcpu) { + __skey_check_enable(vcpu); + vcpu->stat.instruction_storage_key++; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) @@ -160,9 +183,21 @@ static int handle_skey(struct kvm_vcpu *vcpu) return 0; } +static int handle_ipte_interlock(struct kvm_vcpu *vcpu) +{ + psw_t *psw = &vcpu->arch.sie_block->gpsw; + + vcpu->stat.instruction_ipte_interlock++; + if (psw_bits(*psw).p) + return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); + wait_event(vcpu->kvm->arch.ipte_wq, !ipte_lock_held(vcpu)); + psw->addr = __rewind_psw(*psw, 4); + VCPU_EVENT(vcpu, 4, "%s", "retrying ipte interlock operation"); + return 0; +} + static int handle_test_block(struct kvm_vcpu *vcpu) { - unsigned long hva; gpa_t addr; int reg2; @@ -171,16 +206,18 @@ static int handle_test_block(struct kvm_vcpu *vcpu) kvm_s390_get_regs_rre(vcpu, NULL, ®2); addr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK; + addr = kvm_s390_logical_to_effective(vcpu, addr); + if (kvm_s390_check_low_addr_protection(vcpu, addr)) + return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm); addr = kvm_s390_real_to_abs(vcpu, addr); - hva = gfn_to_hva(vcpu->kvm, gpa_to_gfn(addr)); - if (kvm_is_error_hva(hva)) + if (kvm_is_error_gpa(vcpu->kvm, addr)) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); /* * We don't expect errors on modern systems, and do not care * about storage keys (yet), so let's just clear the page. */ - if (clear_user((void __user *)hva, PAGE_SIZE) != 0) + if (kvm_clear_guest(vcpu->kvm, addr, PAGE_SIZE)) return -EFAULT; kvm_s390_set_psw_cc(vcpu, 0); vcpu->run->s.regs.gprs[0] = 0; @@ -190,9 +227,12 @@ static int handle_test_block(struct kvm_vcpu *vcpu) static int handle_tpi(struct kvm_vcpu *vcpu) { struct kvm_s390_interrupt_info *inti; + unsigned long len; + u32 tpi_data[3]; + int cc, rc; u64 addr; - int cc; + rc = 0; addr = kvm_s390_get_base_disp_s(vcpu); if (addr & 3) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); @@ -201,30 +241,41 @@ static int handle_tpi(struct kvm_vcpu *vcpu) if (!inti) goto no_interrupt; cc = 1; + tpi_data[0] = inti->io.subchannel_id << 16 | inti->io.subchannel_nr; + tpi_data[1] = inti->io.io_int_parm; + tpi_data[2] = inti->io.io_int_word; if (addr) { /* * Store the two-word I/O interruption code into the * provided area. */ - if (put_guest(vcpu, inti->io.subchannel_id, (u16 __user *)addr) - || put_guest(vcpu, inti->io.subchannel_nr, (u16 __user *)(addr + 2)) - || put_guest(vcpu, inti->io.io_int_parm, (u32 __user *)(addr + 4))) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + len = sizeof(tpi_data) - 4; + rc = write_guest(vcpu, addr, &tpi_data, len); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); } else { /* * Store the three-word I/O interruption code into * the appropriate lowcore area. */ - put_guest(vcpu, inti->io.subchannel_id, (u16 __user *) __LC_SUBCHANNEL_ID); - put_guest(vcpu, inti->io.subchannel_nr, (u16 __user *) __LC_SUBCHANNEL_NR); - put_guest(vcpu, inti->io.io_int_parm, (u32 __user *) __LC_IO_INT_PARM); - put_guest(vcpu, inti->io.io_int_word, (u32 __user *) __LC_IO_INT_WORD); + len = sizeof(tpi_data); + if (write_guest_lc(vcpu, __LC_SUBCHANNEL_ID, &tpi_data, len)) + rc = -EFAULT; } - kfree(inti); + /* + * If we encounter a problem storing the interruption code, the + * instruction is suppressed from the guest's view: reinject the + * interrupt. + */ + if (!rc) + kfree(inti); + else + kvm_s390_reinject_io_int(vcpu->kvm, inti); no_interrupt: /* Set condition code and we're done. */ - kvm_s390_set_psw_cc(vcpu, cc); - return 0; + if (!rc) + kvm_s390_set_psw_cc(vcpu, cc); + return rc ? -EFAULT : 0; } static int handle_tsch(struct kvm_vcpu *vcpu) @@ -292,10 +343,10 @@ static int handle_stfl(struct kvm_vcpu *vcpu) if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); - rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list), - vfacilities, 4); + rc = write_guest_lc(vcpu, offsetof(struct _lowcore, stfl_fac_list), + vfacilities, 4); if (rc) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + return rc; VCPU_EVENT(vcpu, 5, "store facility list value %x", *(unsigned int *) vfacilities); trace_kvm_s390_handle_stfl(vcpu, *(unsigned int *) vfacilities); @@ -333,6 +384,7 @@ int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu) psw_t *gpsw = &vcpu->arch.sie_block->gpsw; psw_compat_t new_psw; u64 addr; + int rc; if (gpsw->mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); @@ -340,8 +392,10 @@ int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu) addr = kvm_s390_get_base_disp_s(vcpu); if (addr & 7) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - if (copy_from_guest(vcpu, &new_psw, addr, sizeof(new_psw))) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + + rc = read_guest(vcpu, addr, &new_psw, sizeof(new_psw)); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); if (!(new_psw.mask & PSW32_MASK_BASE)) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); gpsw->mask = (new_psw.mask & ~PSW32_MASK_BASE) << 32; @@ -357,6 +411,7 @@ static int handle_lpswe(struct kvm_vcpu *vcpu) { psw_t new_psw; u64 addr; + int rc; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); @@ -364,8 +419,9 @@ static int handle_lpswe(struct kvm_vcpu *vcpu) addr = kvm_s390_get_base_disp_s(vcpu); if (addr & 7) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - if (copy_from_guest(vcpu, &new_psw, addr, sizeof(new_psw))) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + rc = read_guest(vcpu, addr, &new_psw, sizeof(new_psw)); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); vcpu->arch.sie_block->gpsw = new_psw; if (!is_valid_psw(&vcpu->arch.sie_block->gpsw)) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); @@ -375,7 +431,9 @@ static int handle_lpswe(struct kvm_vcpu *vcpu) static int handle_stidp(struct kvm_vcpu *vcpu) { + u64 stidp_data = vcpu->arch.stidp_data; u64 operand2; + int rc; vcpu->stat.instruction_stidp++; @@ -387,8 +445,9 @@ static int handle_stidp(struct kvm_vcpu *vcpu) if (operand2 & 7) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - if (put_guest(vcpu, vcpu->arch.stidp_data, (u64 __user *)operand2)) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + rc = write_guest(vcpu, operand2, &stidp_data, sizeof(stidp_data)); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); VCPU_EVENT(vcpu, 5, "%s", "store cpu id"); return 0; @@ -474,9 +533,10 @@ static int handle_stsi(struct kvm_vcpu *vcpu) break; } - if (copy_to_guest_absolute(vcpu, operand2, (void *) mem, PAGE_SIZE)) { - rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - goto out_exception; + rc = write_guest(vcpu, operand2, (void *)mem, PAGE_SIZE); + if (rc) { + rc = kvm_s390_inject_prog_cond(vcpu, rc); + goto out; } trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2); free_page(mem); @@ -485,7 +545,7 @@ static int handle_stsi(struct kvm_vcpu *vcpu) return 0; out_no_data: kvm_s390_set_psw_cc(vcpu, 3); -out_exception: +out: free_page(mem); return rc; } @@ -496,6 +556,7 @@ static const intercept_handler_t b2_handlers[256] = { [0x10] = handle_set_prefix, [0x11] = handle_store_prefix, [0x12] = handle_store_cpu_address, + [0x21] = handle_ipte_interlock, [0x29] = handle_skey, [0x2a] = handle_skey, [0x2b] = handle_skey, @@ -513,6 +574,7 @@ static const intercept_handler_t b2_handlers[256] = { [0x3a] = handle_io_inst, [0x3b] = handle_io_inst, [0x3c] = handle_io_inst, + [0x50] = handle_ipte_interlock, [0x5f] = handle_io_inst, [0x74] = handle_io_inst, [0x76] = handle_io_inst, @@ -591,6 +653,11 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK; + if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) { + if (kvm_s390_check_low_addr_protection(vcpu, start)) + return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm); + } + switch (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) { case 0x00000000: end = (start + (1UL << 12)) & ~((1UL << 12) - 1); @@ -606,10 +673,15 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); } while (start < end) { - unsigned long useraddr; - - useraddr = gmap_translate(start, vcpu->arch.gmap); - if (IS_ERR((void *)useraddr)) + unsigned long useraddr, abs_addr; + + /* Translate guest address to host address */ + if ((vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) == 0) + abs_addr = kvm_s390_real_to_abs(vcpu, start); + else + abs_addr = start; + useraddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(abs_addr)); + if (kvm_is_error_hva(useraddr)) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) { @@ -618,6 +690,7 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) } if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK) { + __skey_check_enable(vcpu); if (set_guest_storage_key(current->mm, useraddr, vcpu->run->s.regs.gprs[reg1] & PFMF_KEY, vcpu->run->s.regs.gprs[reg1] & PFMF_NQ)) @@ -642,7 +715,7 @@ static int handle_essa(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 5, "cmma release %d pages", entries); gmap = vcpu->arch.gmap; vcpu->stat.instruction_essa++; - if (!kvm_enabled_cmma() || !vcpu->arch.sie_block->cbrlo) + if (!kvm_s390_cmma_enabled(vcpu->kvm)) return kvm_s390_inject_program_int(vcpu, PGM_OPERATION); if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) @@ -672,7 +745,10 @@ static int handle_essa(struct kvm_vcpu *vcpu) } static const intercept_handler_t b9_handlers[256] = { + [0x8a] = handle_ipte_interlock, [0x8d] = handle_epsw, + [0x8e] = handle_ipte_interlock, + [0x8f] = handle_ipte_interlock, [0xab] = handle_essa, [0xaf] = handle_pfmf, }; @@ -693,32 +769,67 @@ int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu) { int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; int reg3 = vcpu->arch.sie_block->ipa & 0x000f; - u64 useraddr; u32 val = 0; int reg, rc; + u64 ga; vcpu->stat.instruction_lctl++; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); - useraddr = kvm_s390_get_base_disp_rs(vcpu); + ga = kvm_s390_get_base_disp_rs(vcpu); - if (useraddr & 3) + if (ga & 3) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3, - useraddr); - trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr); + VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3, ga); + trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, ga); reg = reg1; do { - rc = get_guest(vcpu, val, (u32 __user *) useraddr); + rc = read_guest(vcpu, ga, &val, sizeof(val)); if (rc) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + return kvm_s390_inject_prog_cond(vcpu, rc); vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; vcpu->arch.sie_block->gcr[reg] |= val; - useraddr += 4; + ga += 4; + if (reg == reg3) + break; + reg = (reg + 1) % 16; + } while (1); + + return 0; +} + +int kvm_s390_handle_stctl(struct kvm_vcpu *vcpu) +{ + int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; + int reg3 = vcpu->arch.sie_block->ipa & 0x000f; + u64 ga; + u32 val; + int reg, rc; + + vcpu->stat.instruction_stctl++; + + if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) + return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); + + ga = kvm_s390_get_base_disp_rs(vcpu); + + if (ga & 3) + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + + VCPU_EVENT(vcpu, 5, "stctl r1:%x, r3:%x, addr:%llx", reg1, reg3, ga); + trace_kvm_s390_handle_stctl(vcpu, 0, reg1, reg3, ga); + + reg = reg1; + do { + val = vcpu->arch.sie_block->gcr[reg] & 0x00000000fffffffful; + rc = write_guest(vcpu, ga, &val, sizeof(val)); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); + ga += 4; if (reg == reg3) break; reg = (reg + 1) % 16; @@ -731,7 +842,7 @@ static int handle_lctlg(struct kvm_vcpu *vcpu) { int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; int reg3 = vcpu->arch.sie_block->ipa & 0x000f; - u64 useraddr; + u64 ga, val; int reg, rc; vcpu->stat.instruction_lctlg++; @@ -739,23 +850,58 @@ static int handle_lctlg(struct kvm_vcpu *vcpu) if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); - useraddr = kvm_s390_get_base_disp_rsy(vcpu); + ga = kvm_s390_get_base_disp_rsy(vcpu); - if (useraddr & 7) + if (ga & 7) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); reg = reg1; - VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3, - useraddr); - trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr); + VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3, ga); + trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, ga); do { - rc = get_guest(vcpu, vcpu->arch.sie_block->gcr[reg], - (u64 __user *) useraddr); + rc = read_guest(vcpu, ga, &val, sizeof(val)); if (rc) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - useraddr += 8; + return kvm_s390_inject_prog_cond(vcpu, rc); + vcpu->arch.sie_block->gcr[reg] = val; + ga += 8; + if (reg == reg3) + break; + reg = (reg + 1) % 16; + } while (1); + + return 0; +} + +static int handle_stctg(struct kvm_vcpu *vcpu) +{ + int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; + int reg3 = vcpu->arch.sie_block->ipa & 0x000f; + u64 ga, val; + int reg, rc; + + vcpu->stat.instruction_stctg++; + + if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) + return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); + + ga = kvm_s390_get_base_disp_rsy(vcpu); + + if (ga & 7) + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + + reg = reg1; + + VCPU_EVENT(vcpu, 5, "stctg r1:%x, r3:%x, addr:%llx", reg1, reg3, ga); + trace_kvm_s390_handle_stctl(vcpu, 1, reg1, reg3, ga); + + do { + val = vcpu->arch.sie_block->gcr[reg]; + rc = write_guest(vcpu, ga, &val, sizeof(val)); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); + ga += 8; if (reg == reg3) break; reg = (reg + 1) % 16; @@ -766,6 +912,7 @@ static int handle_lctlg(struct kvm_vcpu *vcpu) static const intercept_handler_t eb_handlers[256] = { [0x2f] = handle_lctlg, + [0x25] = handle_stctg, }; int kvm_s390_handle_eb(struct kvm_vcpu *vcpu) diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index 26caeb530a7829..c0b99e0f6b63a5 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -235,7 +235,6 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, struct kvm_vcpu *dst_vcpu = NULL; struct kvm_s390_interrupt_info *inti; int rc; - u8 tmp; if (cpu_addr < KVM_MAX_VCPUS) dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr); @@ -243,10 +242,13 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, return SIGP_CC_NOT_OPERATIONAL; li = &dst_vcpu->arch.local_int; - /* make sure that the new value is valid memory */ - address = address & 0x7fffe000u; - if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || - copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1)) { + /* + * Make sure the new value is valid memory. We only need to check the + * first page, since address is 8k aligned and memory pieces are always + * at least 1MB aligned and have at least a size of 1MB. + */ + address &= 0x7fffe000u; + if (kvm_is_error_gpa(vcpu->kvm, address)) { *reg &= 0xffffffff00000000UL; *reg |= SIGP_STATUS_INVALID_PARAMETER; return SIGP_CC_STATUS_STORED; diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/trace-s390.h index 13f30f58a2df7d..647e9d6a4818ec 100644 --- a/arch/s390/kvm/trace-s390.h +++ b/arch/s390/kvm/trace-s390.h @@ -67,6 +67,27 @@ TRACE_EVENT(kvm_s390_destroy_vcpu, TP_printk("destroy cpu %d", __entry->id) ); +/* + * Trace point for start and stop of vpcus. + */ +TRACE_EVENT(kvm_s390_vcpu_start_stop, + TP_PROTO(unsigned int id, int state), + TP_ARGS(id, state), + + TP_STRUCT__entry( + __field(unsigned int, id) + __field(int, state) + ), + + TP_fast_assign( + __entry->id = id; + __entry->state = state; + ), + + TP_printk("%s cpu %d", __entry->state ? "starting" : "stopping", + __entry->id) + ); + /* * Trace points for injection of interrupts, either per machine or * per vcpu. @@ -223,6 +244,28 @@ TRACE_EVENT(kvm_s390_enable_css, __entry->kvm) ); +/* + * Trace point for enabling and disabling interlocking-and-broadcasting + * suppression. + */ +TRACE_EVENT(kvm_s390_enable_disable_ibs, + TP_PROTO(unsigned int id, int state), + TP_ARGS(id, state), + + TP_STRUCT__entry( + __field(unsigned int, id) + __field(int, state) + ), + + TP_fast_assign( + __entry->id = id; + __entry->state = state; + ), + + TP_printk("%s ibs on cpu %d", + __entry->state ? "enabling" : "disabling", __entry->id) + ); + #endif /* _TRACE_KVMS390_H */ diff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/trace.h index e8e7213d4cc53a..abf6ba52769e98 100644 --- a/arch/s390/kvm/trace.h +++ b/arch/s390/kvm/trace.h @@ -30,6 +30,20 @@ TP_printk("%02d[%016lx-%016lx]: " p_str, __entry->id, \ __entry->pswmask, __entry->pswaddr, p_args) +TRACE_EVENT(kvm_s390_skey_related_inst, + TP_PROTO(VCPU_PROTO_COMMON), + TP_ARGS(VCPU_ARGS_COMMON), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + ), + VCPU_TP_PRINTK("%s", "first instruction related to skeys on vcpu") + ); + TRACE_EVENT(kvm_s390_major_guest_pfault, TP_PROTO(VCPU_PROTO_COMMON), TP_ARGS(VCPU_ARGS_COMMON), @@ -301,6 +315,31 @@ TRACE_EVENT(kvm_s390_handle_lctl, __entry->reg1, __entry->reg3, __entry->addr) ); +TRACE_EVENT(kvm_s390_handle_stctl, + TP_PROTO(VCPU_PROTO_COMMON, int g, int reg1, int reg3, u64 addr), + TP_ARGS(VCPU_ARGS_COMMON, g, reg1, reg3, addr), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(int, g) + __field(int, reg1) + __field(int, reg3) + __field(u64, addr) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->g = g; + __entry->reg1 = reg1; + __entry->reg3 = reg3; + __entry->addr = addr; + ), + + VCPU_TP_PRINTK("%s: storing cr %x-%x to %016llx", + __entry->g ? "stctg" : "stctl", + __entry->reg1, __entry->reg3, __entry->addr) + ); + TRACE_EVENT(kvm_s390_handle_prefix, TP_PROTO(VCPU_PROTO_COMMON, int set, u32 address), TP_ARGS(VCPU_ARGS_COMMON, set, address), diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index f709983f41f883..827f42aa256276 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c @@ -1,8 +1,9 @@ /* * Out of line spinlock code. * - * Copyright IBM Corp. 2004, 2006 + * Copyright IBM Corp. 2004, 2014 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * Philipp Hachtmann (phacht@linux.vnet.ibm.com) */ #include @@ -24,29 +25,112 @@ static int __init spin_retry_setup(char *str) } __setup("spin_retry=", spin_retry_setup); +#ifdef CONFIG_S390_TICKET_SPINLOCK + void arch_spin_lock_wait(arch_spinlock_t *lp) { - int count = spin_retry; - unsigned int cpu = ~smp_processor_id(); + arch_spinlock_t cur, new; + int cpu, owner, count; + u8 ticket = 0; + + cpu = smp_processor_id(); + count = spin_retry; + while (1) { + new.lock = cur.lock = ACCESS_ONCE(lp->lock); + if (new.lock == 0) { + /* The lock is free with no waiter, try to get it. */ + new.tickets.owner = (u16) ~cpu; + } else if (!ticket) { + /* Try to get a ticket. */ + new.tickets.tail = (u8)(new.tickets.tail + 1) ? : 1; + if (new.tickets.tail == new.tickets.head) + /* Overflow, can't get a ticket. */ + new.tickets.tail = cur.tickets.tail; + } else if (new.tickets.head == ticket) + new.tickets.owner = (u16) ~cpu; + /* Do the atomic update. */ + if (cur.lock != new.lock && + _raw_compare_and_swap(&lp->lock, cur.lock, new.lock)) { + /* Update successful. */ + if (new.tickets.owner == (u16) ~cpu) + return; /* Got the lock. */ + ticket = new.tickets.tail; /* Got a ticket. */ + count = 0; + } + /* Lock could not be acquired yet. */ + if (count--) + continue; + count = spin_retry; + owner = cur.tickets.owner; + if (ticket) { + if (owner && smp_vcpu_scheduled(~owner)) { + if (MACHINE_IS_LPAR) + continue; + } else + count = 0; + } + /* Yield the cpu. */ + if (owner) + smp_yield_cpu(~owner); + else + smp_yield(); + } +} +EXPORT_SYMBOL(arch_spin_lock_wait); + +void arch_spin_unlock_slow(arch_spinlock_t *lp) +{ + arch_spinlock_t cur, new; + + do { + cur.lock = ACCESS_ONCE(lp->lock); + new.lock = 0; + if (cur.tickets.head != cur.tickets.tail) { + new.tickets.tail = cur.tickets.tail; + new.tickets.head = (u8)(cur.tickets.head + 1) ? : 1; + new.tickets.owner = 0; + } + } while (!_raw_compare_and_swap(&lp->lock, cur.lock, new.lock)); +} +EXPORT_SYMBOL(arch_spin_unlock_slow); + +void arch_spin_relax(arch_spinlock_t *lp) +{ + unsigned int cpu = lp->tickets.owner; + + if (cpu != 0) { + if (MACHINE_IS_VM || MACHINE_IS_KVM || + !smp_vcpu_scheduled(~cpu)) + smp_yield_cpu(~cpu); + } +} +EXPORT_SYMBOL(arch_spin_relax); + +#else /* CONFIG_S390_TICKET_SPINLOCK */ + +void arch_spin_lock_wait(arch_spinlock_t *lp) +{ + unsigned int cpu = SPINLOCK_LOCKVAL; unsigned int owner; + int count; while (1) { - owner = lp->owner_cpu; + owner = lp->lock; if (!owner || smp_vcpu_scheduled(~owner)) { - for (count = spin_retry; count > 0; count--) { + count = spin_retry; + do { if (arch_spin_is_locked(lp)) continue; - if (_raw_compare_and_swap(&lp->owner_cpu, 0, - cpu) == 0) + if (_raw_compare_and_swap(&lp->lock, 0, cpu)) return; - } + } while (count-- > 0); if (MACHINE_IS_LPAR) continue; } - owner = lp->owner_cpu; + owner = lp->lock; if (owner) smp_yield_cpu(~owner); - if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) + if (_raw_compare_and_swap(&lp->lock, 0, cpu)) return; } } @@ -54,63 +138,64 @@ EXPORT_SYMBOL(arch_spin_lock_wait); void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags) { - int count = spin_retry; - unsigned int cpu = ~smp_processor_id(); + unsigned int cpu = SPINLOCK_LOCKVAL; unsigned int owner; + int count; local_irq_restore(flags); while (1) { - owner = lp->owner_cpu; + owner = lp->lock; if (!owner || smp_vcpu_scheduled(~owner)) { - for (count = spin_retry; count > 0; count--) { + count = spin_retry; + do { if (arch_spin_is_locked(lp)) continue; local_irq_disable(); - if (_raw_compare_and_swap(&lp->owner_cpu, 0, - cpu) == 0) + if (_raw_compare_and_swap(&lp->lock, 0, cpu)) return; local_irq_restore(flags); - } + } while (count-- > 0); if (MACHINE_IS_LPAR) continue; } - owner = lp->owner_cpu; + owner = lp->lock; if (owner) smp_yield_cpu(~owner); local_irq_disable(); - if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) + if (_raw_compare_and_swap(&lp->lock, 0, cpu)) return; local_irq_restore(flags); } } EXPORT_SYMBOL(arch_spin_lock_wait_flags); +void arch_spin_relax(arch_spinlock_t *lp) +{ + unsigned int cpu = lp->lock; + if (cpu != 0) { + if (MACHINE_IS_VM || MACHINE_IS_KVM || + !smp_vcpu_scheduled(~cpu)) + smp_yield_cpu(~cpu); + } +} +EXPORT_SYMBOL(arch_spin_relax); + +#endif /* CONFIG_S390_TICKET_SPINLOCK */ + int arch_spin_trylock_retry(arch_spinlock_t *lp) { - unsigned int cpu = ~smp_processor_id(); int count; for (count = spin_retry; count > 0; count--) { if (arch_spin_is_locked(lp)) continue; - if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) + if (arch_spin_trylock_once(lp)) return 1; } return 0; } EXPORT_SYMBOL(arch_spin_trylock_retry); -void arch_spin_relax(arch_spinlock_t *lock) -{ - unsigned int cpu = lock->owner_cpu; - if (cpu != 0) { - if (MACHINE_IS_VM || MACHINE_IS_KVM || - !smp_vcpu_scheduled(~cpu)) - smp_yield_cpu(~cpu); - } -} -EXPORT_SYMBOL(arch_spin_relax); - void _raw_read_lock_wait(arch_rwlock_t *rw) { unsigned int old; @@ -124,7 +209,7 @@ void _raw_read_lock_wait(arch_rwlock_t *rw) if (!arch_read_can_lock(rw)) continue; old = rw->lock & 0x7fffffffU; - if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old) + if (_raw_compare_and_swap(&rw->lock, old, old + 1)) return; } } @@ -145,7 +230,7 @@ void _raw_read_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags) continue; old = rw->lock & 0x7fffffffU; local_irq_disable(); - if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old) + if (_raw_compare_and_swap(&rw->lock, old, old + 1)) return; } } @@ -160,7 +245,7 @@ int _raw_read_trylock_retry(arch_rwlock_t *rw) if (!arch_read_can_lock(rw)) continue; old = rw->lock & 0x7fffffffU; - if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old) + if (_raw_compare_and_swap(&rw->lock, old, old + 1)) return 1; } return 0; @@ -178,7 +263,7 @@ void _raw_write_lock_wait(arch_rwlock_t *rw) } if (!arch_write_can_lock(rw)) continue; - if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0) + if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) return; } } @@ -197,7 +282,7 @@ void _raw_write_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags) if (!arch_write_can_lock(rw)) continue; local_irq_disable(); - if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0) + if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) return; } } @@ -210,7 +295,7 @@ int _raw_write_trylock_retry(arch_rwlock_t *rw) while (count-- > 0) { if (!arch_write_can_lock(rw)) continue; - if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0) + if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) return 1; } return 0; diff --git a/arch/s390/lib/uaccess.c b/arch/s390/lib/uaccess.c index 7416efe8eae419..53dd5d7a0c964f 100644 --- a/arch/s390/lib/uaccess.c +++ b/arch/s390/lib/uaccess.c @@ -76,7 +76,7 @@ static inline unsigned long copy_from_user_mvcp(void *x, const void __user *ptr, { unsigned long tmp1, tmp2; - update_primary_asce(current); + load_kernel_asce(); tmp1 = -256UL; asm volatile( " sacf 0\n" @@ -159,7 +159,7 @@ static inline unsigned long copy_to_user_mvcs(void __user *ptr, const void *x, { unsigned long tmp1, tmp2; - update_primary_asce(current); + load_kernel_asce(); tmp1 = -256UL; asm volatile( " sacf 0\n" @@ -225,7 +225,7 @@ static inline unsigned long copy_in_user_mvc(void __user *to, const void __user { unsigned long tmp1; - update_primary_asce(current); + load_kernel_asce(); asm volatile( " sacf 256\n" " "AHI" %0,-1\n" @@ -292,7 +292,7 @@ static inline unsigned long clear_user_xc(void __user *to, unsigned long size) { unsigned long tmp1, tmp2; - update_primary_asce(current); + load_kernel_asce(); asm volatile( " sacf 256\n" " "AHI" %0,-1\n" @@ -358,7 +358,7 @@ unsigned long __strnlen_user(const char __user *src, unsigned long size) { if (unlikely(!size)) return 0; - update_primary_asce(current); + load_kernel_asce(); return strnlen_user_srst(src, size); } EXPORT_SYMBOL(__strnlen_user); diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 2f51a998a67e38..3f3b35403d0a41 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -415,7 +415,7 @@ static inline int do_exception(struct pt_regs *regs, int access) * The instruction that caused the program check has * been nullified. Don't signal single step via SIGTRAP. */ - clear_tsk_thread_flag(tsk, TIF_PER_TRAP); + clear_pt_regs_flag(regs, PIF_PER_TRAP); if (notify_page_fault(regs)) return 0; diff --git a/arch/s390/mm/mem_detect.c b/arch/s390/mm/mem_detect.c index cca388253a39f5..5535cfe0ee115f 100644 --- a/arch/s390/mm/mem_detect.c +++ b/arch/s390/mm/mem_detect.c @@ -6,130 +6,60 @@ #include #include +#include +#include +#include +#include #include #include #include #define ADDR2G (1ULL << 31) -static void find_memory_chunks(struct mem_chunk chunk[], unsigned long maxsize) +#define CHUNK_READ_WRITE 0 +#define CHUNK_READ_ONLY 1 + +static inline void memblock_physmem_add(phys_addr_t start, phys_addr_t size) +{ + memblock_add_range(&memblock.memory, start, size, 0, 0); + memblock_add_range(&memblock.physmem, start, size, 0, 0); +} + +void __init detect_memory_memblock(void) { unsigned long long memsize, rnmax, rzm; - unsigned long addr = 0, size; - int i = 0, type; + unsigned long addr, size; + int type; rzm = sclp_get_rzm(); rnmax = sclp_get_rnmax(); memsize = rzm * rnmax; if (!rzm) rzm = 1ULL << 17; - if (sizeof(long) == 4) { + if (IS_ENABLED(CONFIG_32BIT)) { rzm = min(ADDR2G, rzm); - memsize = memsize ? min(ADDR2G, memsize) : ADDR2G; + memsize = min(ADDR2G, memsize); } - if (maxsize) - memsize = memsize ? min((unsigned long)memsize, maxsize) : maxsize; + max_physmem_end = memsize; + addr = 0; + /* keep memblock lists close to the kernel */ + memblock_set_bottom_up(true); do { size = 0; type = tprot(addr); do { size += rzm; - if (memsize && addr + size >= memsize) + if (max_physmem_end && addr + size >= max_physmem_end) break; } while (type == tprot(addr + size)); if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) { - if (memsize && (addr + size > memsize)) - size = memsize - addr; - chunk[i].addr = addr; - chunk[i].size = size; - chunk[i].type = type; - i++; + if (max_physmem_end && (addr + size > max_physmem_end)) + size = max_physmem_end - addr; + memblock_physmem_add(addr, size); } addr += size; - } while (addr < memsize && i < MEMORY_CHUNKS); -} - -/** - * detect_memory_layout - fill mem_chunk array with memory layout data - * @chunk: mem_chunk array to be filled - * @maxsize: maximum address where memory detection should stop - * - * Fills the passed in memory chunk array with the memory layout of the - * machine. The array must have a size of at least MEMORY_CHUNKS and will - * be fully initialized afterwards. - * If the maxsize paramater has a value > 0 memory detection will stop at - * that address. It is guaranteed that all chunks have an ending address - * that is smaller than maxsize. - * If maxsize is 0 all memory will be detected. - */ -void detect_memory_layout(struct mem_chunk chunk[], unsigned long maxsize) -{ - unsigned long flags, flags_dat, cr0; - - memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk)); - /* - * Disable IRQs, DAT and low address protection so tprot does the - * right thing and we don't get scheduled away with low address - * protection disabled. - */ - local_irq_save(flags); - flags_dat = __arch_local_irq_stnsm(0xfb); - /* - * In case DAT was enabled, make sure chunk doesn't reside in vmalloc - * space. We have disabled DAT and any access to vmalloc area will - * cause an exception. - * If DAT was disabled we are called from early ipl code. - */ - if (test_bit(5, &flags_dat)) { - if (WARN_ON_ONCE(is_vmalloc_or_module_addr(chunk))) - goto out; - } - __ctl_store(cr0, 0, 0); - __ctl_clear_bit(0, 28); - find_memory_chunks(chunk, maxsize); - __ctl_load(cr0, 0, 0); -out: - __arch_local_irq_ssm(flags_dat); - local_irq_restore(flags); -} -EXPORT_SYMBOL(detect_memory_layout); - -/* - * Create memory hole with given address and size. - */ -void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr, - unsigned long size) -{ - int i; - - for (i = 0; i < MEMORY_CHUNKS; i++) { - struct mem_chunk *chunk = &mem_chunk[i]; - - if (chunk->size == 0) - continue; - if (addr > chunk->addr + chunk->size) - continue; - if (addr + size <= chunk->addr) - continue; - /* Split */ - if ((addr > chunk->addr) && - (addr + size < chunk->addr + chunk->size)) { - struct mem_chunk *new = chunk + 1; - - memmove(new, chunk, (MEMORY_CHUNKS-i-1) * sizeof(*new)); - new->addr = addr + size; - new->size = chunk->addr + chunk->size - new->addr; - chunk->size = addr - chunk->addr; - continue; - } else if ((addr <= chunk->addr) && - (addr + size >= chunk->addr + chunk->size)) { - memmove(chunk, chunk + 1, (MEMORY_CHUNKS-i-1) * sizeof(*chunk)); - memset(&mem_chunk[MEMORY_CHUNKS-1], 0, sizeof(*chunk)); - } else if (addr + size < chunk->addr + chunk->size) { - chunk->size = chunk->addr + chunk->size - addr - size; - chunk->addr = addr + size; - } else if (addr > chunk->addr) { - chunk->size = addr - chunk->addr; - } - } + } while (addr < max_physmem_end); + memblock_set_bottom_up(false); + if (!max_physmem_end) + max_physmem_end = memblock_end_of_DRAM(); } diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c index 27c50f4d90cb32..a90d45e9dfb0cb 100644 --- a/arch/s390/mm/page-states.c +++ b/arch/s390/mm/page-states.c @@ -12,8 +12,6 @@ #include #include #include -#include -#include #define ESSA_SET_STABLE 1 #define ESSA_SET_UNUSED 2 @@ -43,14 +41,6 @@ void __init cmma_init(void) if (!cmma_flag) return; - /* - * Disable CMM for dump, otherwise the tprot based memory - * detection can fail because of unstable pages. - */ - if (OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP) { - cmma_flag = 0; - return; - } asm volatile( " .insn rrf,0xb9ab0000,%1,%1,0,0\n" "0: la %0,0\n" diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index d7cfd57815fbe4..23b44ef4637997 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -53,8 +53,10 @@ static void __crst_table_upgrade(void *arg) { struct mm_struct *mm = arg; - if (current->active_mm == mm) - update_user_asce(mm, 1); + if (current->active_mm == mm) { + clear_user_asce(); + set_user_asce(mm); + } __tlb_flush_local(); } @@ -108,7 +110,7 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) pgd_t *pgd; if (current->active_mm == mm) { - clear_user_asce(mm, 1); + clear_user_asce(); __tlb_flush_mm(mm); } while (mm->context.asce_limit > limit) { @@ -134,7 +136,7 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) crst_table_free(mm, (unsigned long *) pgd); } if (current->active_mm == mm) - update_user_asce(mm, 1); + set_user_asce(mm); } #endif @@ -832,6 +834,7 @@ void gmap_do_ipte_notify(struct mm_struct *mm, pte_t *pte) } spin_unlock(&gmap_notifier_lock); } +EXPORT_SYMBOL_GPL(gmap_do_ipte_notify); static inline int page_table_with_pgste(struct page *page) { @@ -864,8 +867,7 @@ static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm, atomic_set(&page->_mapcount, 0); table = (unsigned long *) page_to_phys(page); clear_table(table, _PAGE_INVALID, PAGE_SIZE/2); - clear_table(table + PTRS_PER_PTE, PGSTE_HR_BIT | PGSTE_HC_BIT, - PAGE_SIZE/2); + clear_table(table + PTRS_PER_PTE, 0, PAGE_SIZE/2); return table; } @@ -883,8 +885,8 @@ static inline void page_table_free_pgste(unsigned long *table) __free_page(page); } -static inline unsigned long page_table_reset_pte(struct mm_struct *mm, - pmd_t *pmd, unsigned long addr, unsigned long end) +static inline unsigned long page_table_reset_pte(struct mm_struct *mm, pmd_t *pmd, + unsigned long addr, unsigned long end, bool init_skey) { pte_t *start_pte, *pte; spinlock_t *ptl; @@ -895,6 +897,22 @@ static inline unsigned long page_table_reset_pte(struct mm_struct *mm, do { pgste = pgste_get_lock(pte); pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK; + if (init_skey) { + unsigned long address; + + pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT | + PGSTE_GR_BIT | PGSTE_GC_BIT); + + /* skip invalid and not writable pages */ + if (pte_val(*pte) & _PAGE_INVALID || + !(pte_val(*pte) & _PAGE_WRITE)) { + pgste_set_unlock(pte, pgste); + continue; + } + + address = pte_val(*pte) & PAGE_MASK; + page_set_storage_key(address, PAGE_DEFAULT_KEY, 1); + } pgste_set_unlock(pte, pgste); } while (pte++, addr += PAGE_SIZE, addr != end); pte_unmap_unlock(start_pte, ptl); @@ -902,8 +920,8 @@ static inline unsigned long page_table_reset_pte(struct mm_struct *mm, return addr; } -static inline unsigned long page_table_reset_pmd(struct mm_struct *mm, - pud_t *pud, unsigned long addr, unsigned long end) +static inline unsigned long page_table_reset_pmd(struct mm_struct *mm, pud_t *pud, + unsigned long addr, unsigned long end, bool init_skey) { unsigned long next; pmd_t *pmd; @@ -913,14 +931,14 @@ static inline unsigned long page_table_reset_pmd(struct mm_struct *mm, next = pmd_addr_end(addr, end); if (pmd_none_or_clear_bad(pmd)) continue; - next = page_table_reset_pte(mm, pmd, addr, next); + next = page_table_reset_pte(mm, pmd, addr, next, init_skey); } while (pmd++, addr = next, addr != end); return addr; } -static inline unsigned long page_table_reset_pud(struct mm_struct *mm, - pgd_t *pgd, unsigned long addr, unsigned long end) +static inline unsigned long page_table_reset_pud(struct mm_struct *mm, pgd_t *pgd, + unsigned long addr, unsigned long end, bool init_skey) { unsigned long next; pud_t *pud; @@ -930,14 +948,14 @@ static inline unsigned long page_table_reset_pud(struct mm_struct *mm, next = pud_addr_end(addr, end); if (pud_none_or_clear_bad(pud)) continue; - next = page_table_reset_pmd(mm, pud, addr, next); + next = page_table_reset_pmd(mm, pud, addr, next, init_skey); } while (pud++, addr = next, addr != end); return addr; } -void page_table_reset_pgste(struct mm_struct *mm, - unsigned long start, unsigned long end) +void page_table_reset_pgste(struct mm_struct *mm, unsigned long start, + unsigned long end, bool init_skey) { unsigned long addr, next; pgd_t *pgd; @@ -949,7 +967,7 @@ void page_table_reset_pgste(struct mm_struct *mm, next = pgd_addr_end(addr, end); if (pgd_none_or_clear_bad(pgd)) continue; - next = page_table_reset_pud(mm, pgd, addr, next); + next = page_table_reset_pud(mm, pgd, addr, next, init_skey); } while (pgd++, addr = next, addr != end); up_read(&mm->mmap_sem); } @@ -989,7 +1007,7 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, /* changing the guest storage key is considered a change of the page */ if ((pgste_val(new) ^ pgste_val(old)) & (PGSTE_ACC_BITS | PGSTE_FP_BIT | PGSTE_GR_BIT | PGSTE_GC_BIT)) - pgste_val(new) |= PGSTE_HC_BIT; + pgste_val(new) |= PGSTE_UC_BIT; pgste_set_unlock(ptep, new); pte_unmap_unlock(*ptep, ptl); @@ -1011,6 +1029,11 @@ static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm, return NULL; } +void page_table_reset_pgste(struct mm_struct *mm, unsigned long start, + unsigned long end, bool init_skey) +{ +} + static inline void page_table_free_pgste(unsigned long *table) { } @@ -1357,6 +1380,50 @@ int s390_enable_sie(void) } EXPORT_SYMBOL_GPL(s390_enable_sie); +/* + * Enable storage key handling from now on and initialize the storage + * keys with the default key. + */ +void s390_enable_skey(void) +{ + /* + * To avoid races between multiple vcpus, ending in calling + * page_table_reset twice or more, + * the page_table_lock is taken for serialization. + */ + spin_lock(¤t->mm->page_table_lock); + if (mm_use_skey(current->mm)) { + spin_unlock(¤t->mm->page_table_lock); + return; + } + + current->mm->context.use_skey = 1; + spin_unlock(¤t->mm->page_table_lock); + page_table_reset_pgste(current->mm, 0, TASK_SIZE, true); +} +EXPORT_SYMBOL_GPL(s390_enable_skey); + +/* + * Test and reset if a guest page is dirty + */ +bool gmap_test_and_clear_dirty(unsigned long address, struct gmap *gmap) +{ + pte_t *pte; + spinlock_t *ptl; + bool dirty = false; + + pte = get_locked_pte(gmap->mm, address, &ptl); + if (unlikely(!pte)) + return false; + + if (ptep_test_and_clear_user_dirty(gmap->mm, address, pte)) + dirty = true; + + spin_unlock(ptl); + return dirty; +} +EXPORT_SYMBOL_GPL(gmap_test_and_clear_dirty); + #ifdef CONFIG_TRANSPARENT_HUGEPAGE int pmdp_clear_flush_young(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp) diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 72b04de182838f..fe9012a49aa5ab 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -66,7 +67,8 @@ static pte_t __ref *vmem_pte_alloc(unsigned long address) if (slab_is_available()) pte = (pte_t *) page_table_alloc(&init_mm, address); else - pte = alloc_bootmem(PTRS_PER_PTE * sizeof(pte_t)); + pte = alloc_bootmem_align(PTRS_PER_PTE * sizeof(pte_t), + PTRS_PER_PTE * sizeof(pte_t)); if (!pte) return NULL; clear_table((unsigned long *) pte, _PAGE_INVALID, @@ -371,16 +373,14 @@ int vmem_add_mapping(unsigned long start, unsigned long size) void __init vmem_map_init(void) { unsigned long ro_start, ro_end; - unsigned long start, end; - int i; + struct memblock_region *reg; + phys_addr_t start, end; ro_start = PFN_ALIGN((unsigned long)&_stext); ro_end = (unsigned long)&_eshared & PAGE_MASK; - for (i = 0; i < MEMORY_CHUNKS; i++) { - if (!memory_chunk[i].size) - continue; - start = memory_chunk[i].addr; - end = memory_chunk[i].addr + memory_chunk[i].size; + for_each_memblock(memory, reg) { + start = reg->base; + end = reg->base + reg->size - 1; if (start >= ro_end || end <= ro_start) vmem_add_mem(start, end - start, 0); else if (start >= ro_start && end <= ro_end) @@ -400,23 +400,21 @@ void __init vmem_map_init(void) } /* - * Convert memory chunk array to a memory segment list so there is a single - * list that contains both r/w memory and shared memory segments. + * Convert memblock.memory to a memory segment list so there is a single + * list that contains all memory segments. */ static int __init vmem_convert_memory_chunk(void) { + struct memblock_region *reg; struct memory_segment *seg; - int i; mutex_lock(&vmem_mutex); - for (i = 0; i < MEMORY_CHUNKS; i++) { - if (!memory_chunk[i].size) - continue; + for_each_memblock(memory, reg) { seg = kzalloc(sizeof(*seg), GFP_KERNEL); if (!seg) panic("Out of memory...\n"); - seg->start = memory_chunk[i].addr; - seg->size = memory_chunk[i].size; + seg->start = reg->base; + seg->size = reg->size; insert_memory_segment(seg); } mutex_unlock(&vmem_mutex); diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 1df1d29ac81d37..bdf02570d1dfab 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -530,11 +530,6 @@ static void zpci_unmap_resources(struct zpci_dev *zdev) } } -int pcibios_add_platform_entries(struct pci_dev *pdev) -{ - return zpci_sysfs_add_device(&pdev->dev); -} - static int __init zpci_irq_init(void) { int rc; @@ -671,6 +666,7 @@ int pcibios_add_device(struct pci_dev *pdev) int i; zdev->pdev = pdev; + pdev->dev.groups = zpci_attr_groups; zpci_map_resources(zdev); for (i = 0; i < PCI_BAR_COUNT; i++) { diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index c747394029eec1..96545d7659fd0d 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c @@ -114,6 +114,16 @@ static int clp_store_query_pci_fn(struct zpci_dev *zdev, zdev->end_dma = response->edma; zdev->pchid = response->pchid; zdev->pfgid = response->pfgid; + zdev->pft = response->pft; + zdev->vfn = response->vfn; + zdev->uid = response->uid; + + memcpy(zdev->pfip, response->pfip, sizeof(zdev->pfip)); + if (response->util_str_avail) { + memcpy(zdev->util_str, response->util_str, + sizeof(zdev->util_str)); + } + return 0; } diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index 01e251b1da0cb8..6d7f5a3016ca17 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c @@ -76,7 +76,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) switch (ccdf->pec) { case 0x0301: /* Standby -> Configured */ - if (!zdev || zdev->state == ZPCI_FN_STATE_CONFIGURED) + if (!zdev || zdev->state != ZPCI_FN_STATE_STANDBY) break; zdev->state = ZPCI_FN_STATE_CONFIGURED; zdev->fh = ccdf->fh; @@ -86,7 +86,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) pci_rescan_bus(zdev->bus); break; case 0x0302: /* Reserved -> Standby */ - clp_add_pci_device(ccdf->fid, ccdf->fh, 0); + if (!zdev) + clp_add_pci_device(ccdf->fid, ccdf->fh, 0); break; case 0x0303: /* Deconfiguration requested */ if (pdev) diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c index ab4a91393005a9..9190214b8702f9 100644 --- a/arch/s390/pci/pci_sysfs.c +++ b/arch/s390/pci/pci_sysfs.c @@ -12,43 +12,29 @@ #include #include -static ssize_t show_fid(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); - - return sprintf(buf, "0x%08x\n", zdev->fid); -} -static DEVICE_ATTR(function_id, S_IRUGO, show_fid, NULL); - -static ssize_t show_fh(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); - - return sprintf(buf, "0x%08x\n", zdev->fh); -} -static DEVICE_ATTR(function_handle, S_IRUGO, show_fh, NULL); - -static ssize_t show_pchid(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); - - return sprintf(buf, "0x%04x\n", zdev->pchid); -} -static DEVICE_ATTR(pchid, S_IRUGO, show_pchid, NULL); - -static ssize_t show_pfgid(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); - - return sprintf(buf, "0x%02x\n", zdev->pfgid); -} -static DEVICE_ATTR(pfgid, S_IRUGO, show_pfgid, NULL); - -static ssize_t store_recover(struct device *dev, struct device_attribute *attr, +#define zpci_attr(name, fmt, member) \ +static ssize_t name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); \ + \ + return sprintf(buf, fmt, zdev->member); \ +} \ +static DEVICE_ATTR_RO(name) + +zpci_attr(function_id, "0x%08x\n", fid); +zpci_attr(function_handle, "0x%08x\n", fh); +zpci_attr(pchid, "0x%04x\n", pchid); +zpci_attr(pfgid, "0x%02x\n", pfgid); +zpci_attr(vfn, "0x%04x\n", vfn); +zpci_attr(pft, "0x%02x\n", pft); +zpci_attr(uid, "0x%x\n", uid); +zpci_attr(segment0, "0x%02x\n", pfip[0]); +zpci_attr(segment1, "0x%02x\n", pfip[1]); +zpci_attr(segment2, "0x%02x\n", pfip[2]); +zpci_attr(segment3, "0x%02x\n", pfip[3]); + +static ssize_t recover_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); @@ -70,38 +56,55 @@ static ssize_t store_recover(struct device *dev, struct device_attribute *attr, pci_rescan_bus(zdev->bus); return count; } -static DEVICE_ATTR(recover, S_IWUSR, NULL, store_recover); +static DEVICE_ATTR_WO(recover); -static struct device_attribute *zpci_dev_attrs[] = { - &dev_attr_function_id, - &dev_attr_function_handle, - &dev_attr_pchid, - &dev_attr_pfgid, - &dev_attr_recover, - NULL, -}; - -int zpci_sysfs_add_device(struct device *dev) +static ssize_t util_string_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) { - int i, rc = 0; - - for (i = 0; zpci_dev_attrs[i]; i++) { - rc = device_create_file(dev, zpci_dev_attrs[i]); - if (rc) - goto error; - } - return 0; + struct device *dev = kobj_to_dev(kobj); + struct pci_dev *pdev = to_pci_dev(dev); + struct zpci_dev *zdev = get_zdev(pdev); -error: - while (--i >= 0) - device_remove_file(dev, zpci_dev_attrs[i]); - return rc; + return memory_read_from_buffer(buf, count, &off, zdev->util_str, + sizeof(zdev->util_str)); } +static BIN_ATTR_RO(util_string, CLP_UTIL_STR_LEN); +static struct bin_attribute *zpci_bin_attrs[] = { + &bin_attr_util_string, + NULL, +}; -void zpci_sysfs_remove_device(struct device *dev) -{ - int i; +static struct attribute *zpci_dev_attrs[] = { + &dev_attr_function_id.attr, + &dev_attr_function_handle.attr, + &dev_attr_pchid.attr, + &dev_attr_pfgid.attr, + &dev_attr_pft.attr, + &dev_attr_vfn.attr, + &dev_attr_uid.attr, + &dev_attr_recover.attr, + NULL, +}; +static struct attribute_group zpci_attr_group = { + .attrs = zpci_dev_attrs, + .bin_attrs = zpci_bin_attrs, +}; - for (i = 0; zpci_dev_attrs[i]; i++) - device_remove_file(dev, zpci_dev_attrs[i]); -} +static struct attribute *pfip_attrs[] = { + &dev_attr_segment0.attr, + &dev_attr_segment1.attr, + &dev_attr_segment2.attr, + &dev_attr_segment3.attr, + NULL, +}; +static struct attribute_group pfip_attr_group = { + .name = "pfip", + .attrs = pfip_attrs, +}; + +const struct attribute_group *zpci_attr_groups[] = { + &zpci_attr_group, + &pfip_attr_group, + NULL, +}; diff --git a/arch/score/include/asm/bitops.h b/arch/score/include/asm/bitops.h index a304096b189437..c1bf8d6d0fb08e 100644 --- a/arch/score/include/asm/bitops.h +++ b/arch/score/include/asm/bitops.h @@ -2,12 +2,7 @@ #define _ASM_SCORE_BITOPS_H #include /* swab32 */ - -/* - * clear_bit() doesn't provide any barrier for the compiler. - */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() +#include #include #include diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h index f4c1c20bcdf632..f57b8a6743b30a 100644 --- a/arch/sh/include/asm/atomic.h +++ b/arch/sh/include/asm/atomic.h @@ -10,6 +10,7 @@ #include #include #include +#include #define ATOMIC_INIT(i) { (i) } @@ -62,9 +63,4 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) return c; } -#define smp_mb__before_atomic_dec() smp_mb() -#define smp_mb__after_atomic_dec() smp_mb() -#define smp_mb__before_atomic_inc() smp_mb() -#define smp_mb__after_atomic_inc() smp_mb() - #endif /* __ASM_SH_ATOMIC_H */ diff --git a/arch/sh/include/asm/bitops.h b/arch/sh/include/asm/bitops.h index ea8706d94f08d3..fc8e652cf173f2 100644 --- a/arch/sh/include/asm/bitops.h +++ b/arch/sh/include/asm/bitops.h @@ -9,6 +9,7 @@ /* For __swab32 */ #include +#include #ifdef CONFIG_GUSA_RB #include @@ -22,12 +23,6 @@ #include #endif -/* - * clear_bit() doesn't provide any barrier for the compiler. - */ -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() - #ifdef CONFIG_SUPERH32 static inline unsigned long ffz(unsigned long word) { diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h index 7d80df4f09cb63..95be3b0ce0acd5 100644 --- a/arch/sh/include/asm/syscall_32.h +++ b/arch/sh/include/asm/syscall_32.h @@ -1,6 +1,7 @@ #ifndef __ASM_SH_SYSCALL_32_H #define __ASM_SH_SYSCALL_32_H +#include #include #include #include @@ -93,4 +94,13 @@ static inline void syscall_set_arguments(struct task_struct *task, } } +static inline int syscall_get_arch(void) +{ + int arch = AUDIT_ARCH_SH; + +#ifdef CONFIG_CPU_LITTLE_ENDIAN + arch |= __AUDIT_ARCH_LE; +#endif + return arch; +} #endif /* __ASM_SH_SYSCALL_32_H */ diff --git a/arch/sh/include/asm/syscall_64.h b/arch/sh/include/asm/syscall_64.h index c3561ca72bee9f..c6a797b90b8052 100644 --- a/arch/sh/include/asm/syscall_64.h +++ b/arch/sh/include/asm/syscall_64.h @@ -1,6 +1,7 @@ #ifndef __ASM_SH_SYSCALL_64_H #define __ASM_SH_SYSCALL_64_H +#include #include #include #include @@ -61,4 +62,17 @@ static inline void syscall_set_arguments(struct task_struct *task, memcpy(®s->regs[2 + i], args, n * sizeof(args[0])); } +static inline int syscall_get_arch(void) +{ + int arch = AUDIT_ARCH_SH; + +#ifdef CONFIG_64BIT + arch |= __AUDIT_ARCH_64BIT; +#endif +#ifdef CONFIG_CPU_LITTLE_ENDIAN + arch |= __AUDIT_ARCH_LE; +#endif + + return arch; +} #endif /* __ASM_SH_SYSCALL_64_H */ diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 668c81631c083d..c1a6b89bfe70d5 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -484,17 +484,6 @@ long arch_ptrace(struct task_struct *child, long request, return ret; } -static inline int audit_arch(void) -{ - int arch = EM_SH; - -#ifdef CONFIG_CPU_LITTLE_ENDIAN - arch |= __AUDIT_ARCH_LE; -#endif - - return arch; -} - asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) { long ret = 0; @@ -513,8 +502,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->regs[0]); - audit_syscall_entry(audit_arch(), regs->regs[3], - regs->regs[4], regs->regs[5], + audit_syscall_entry(regs->regs[3], regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); return ret ?: regs->regs[0]; diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index af90339dadcd7a..5cea973a65b256 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c @@ -504,20 +504,6 @@ asmlinkage int sh64_ptrace(long request, long pid, return sys_ptrace(request, pid, addr, data); } -static inline int audit_arch(void) -{ - int arch = EM_SH; - -#ifdef CONFIG_64BIT - arch |= __AUDIT_ARCH_64BIT; -#endif -#ifdef CONFIG_CPU_LITTLE_ENDIAN - arch |= __AUDIT_ARCH_LE; -#endif - - return arch; -} - asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs) { long long ret = 0; @@ -536,8 +522,7 @@ asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs) if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->regs[9]); - audit_syscall_entry(audit_arch(), regs->regs[1], - regs->regs[2], regs->regs[3], + audit_syscall_entry(regs->regs[1], regs->regs[2], regs->regs[3], regs->regs[4], regs->regs[5]); return ret ?: regs->regs[9]; diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h index 905832aa9e9ec0..f08fe51b264df4 100644 --- a/arch/sparc/include/asm/atomic_32.h +++ b/arch/sparc/include/asm/atomic_32.h @@ -14,6 +14,7 @@ #include #include +#include #include @@ -52,10 +53,4 @@ extern void atomic_set(atomic_t *, int); #define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) -/* Atomic operations are already serializing */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif /* !(__ARCH_SPARC_ATOMIC__) */ diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index be56a244c9cf00..8b2f1bde2889be 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -9,6 +9,7 @@ #include #include +#include #define ATOMIC_INIT(i) { (i) } #define ATOMIC64_INIT(i) { (i) } @@ -108,10 +109,4 @@ static inline long atomic64_add_unless(atomic64_t *v, long a, long u) extern long atomic64_dec_if_positive(atomic64_t *v); -/* Atomic operations are already serializing */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif /* !(__ARCH_SPARC64_ATOMIC__) */ diff --git a/arch/sparc/include/asm/auxio.h b/arch/sparc/include/asm/auxio.h index 13dc67f03011ea..3e09a07b77e913 100644 --- a/arch/sparc/include/asm/auxio.h +++ b/arch/sparc/include/asm/auxio.h @@ -1,5 +1,12 @@ #ifndef ___ASM_SPARC_AUXIO_H #define ___ASM_SPARC_AUXIO_H + +#ifndef __ASSEMBLY__ + +extern void __iomem *auxio_register; + +#endif /* ifndef __ASSEMBLY__ */ + #if defined(__sparc__) && defined(__arch64__) #include #else diff --git a/arch/sparc/include/asm/auxio_64.h b/arch/sparc/include/asm/auxio_64.h index f61cd1e3e3957c..7af9766a1c35d4 100644 --- a/arch/sparc/include/asm/auxio_64.h +++ b/arch/sparc/include/asm/auxio_64.h @@ -75,8 +75,6 @@ #ifndef __ASSEMBLY__ -extern void __iomem *auxio_register; - #define AUXIO_LTE_ON 1 #define AUXIO_LTE_OFF 0 diff --git a/arch/sparc/include/asm/barrier_64.h b/arch/sparc/include/asm/barrier_64.h index b5aad964558e75..305dcc3dc72126 100644 --- a/arch/sparc/include/asm/barrier_64.h +++ b/arch/sparc/include/asm/barrier_64.h @@ -68,4 +68,7 @@ do { \ ___p1; \ }) +#define smp_mb__before_atomic() barrier() +#define smp_mb__after_atomic() barrier() + #endif /* !(__SPARC64_BARRIER_H) */ diff --git a/arch/sparc/include/asm/bitops_32.h b/arch/sparc/include/asm/bitops_32.h index 25a676653d45d2..88c9a962502c31 100644 --- a/arch/sparc/include/asm/bitops_32.h +++ b/arch/sparc/include/asm/bitops_32.h @@ -90,9 +90,6 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr) #include -#define smp_mb__before_clear_bit() do { } while(0) -#define smp_mb__after_clear_bit() do { } while(0) - #include #include #include diff --git a/arch/sparc/include/asm/bitops_64.h b/arch/sparc/include/asm/bitops_64.h index 29011cc0e4be2e..f1a051ca301a47 100644 --- a/arch/sparc/include/asm/bitops_64.h +++ b/arch/sparc/include/asm/bitops_64.h @@ -13,6 +13,7 @@ #include #include +#include extern int test_and_set_bit(unsigned long nr, volatile unsigned long *addr); extern int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr); @@ -23,9 +24,6 @@ extern void change_bit(unsigned long nr, volatile unsigned long *addr); #include -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() - #include #include #include diff --git a/arch/sparc/include/asm/bug.h b/arch/sparc/include/asm/bug.h index 6bd9f43cb5a547..a24cbb16d0eb90 100644 --- a/arch/sparc/include/asm/bug.h +++ b/arch/sparc/include/asm/bug.h @@ -20,6 +20,6 @@ extern void do_BUG(const char *file, int line); #include struct pt_regs; -extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn)); +void __noreturn die_if_kernel(char *str, struct pt_regs *regs); #endif diff --git a/arch/sparc/include/asm/checksum_32.h b/arch/sparc/include/asm/checksum_32.h index bdbda1453aa9f1..04471dc6484726 100644 --- a/arch/sparc/include/asm/checksum_32.h +++ b/arch/sparc/include/asm/checksum_32.h @@ -238,4 +238,16 @@ static inline __sum16 ip_compute_csum(const void *buff, int len) return csum_fold(csum_partial(buff, len, 0)); } +#define HAVE_ARCH_CSUM_ADD +static inline __wsum csum_add(__wsum csum, __wsum addend) +{ + __asm__ __volatile__( + "addcc %0, %1, %0\n" + "addx %0, %%g0, %0" + : "=r" (csum) + : "r" (addend), "0" (csum)); + + return csum; +} + #endif /* !(__SPARC_CHECKSUM_H) */ diff --git a/arch/sparc/include/asm/checksum_64.h b/arch/sparc/include/asm/checksum_64.h index 019b9615e43c16..2ff81ae8f3afa1 100644 --- a/arch/sparc/include/asm/checksum_64.h +++ b/arch/sparc/include/asm/checksum_64.h @@ -164,4 +164,16 @@ static inline __sum16 ip_compute_csum(const void *buff, int len) return csum_fold(csum_partial(buff, len, 0)); } +#define HAVE_ARCH_CSUM_ADD +static inline __wsum csum_add(__wsum csum, __wsum addend) +{ + __asm__ __volatile__( + "addcc %0, %1, %0\n" + "addx %0, %%g0, %0" + : "=r" (csum) + : "r" (addend), "0" (csum)); + + return csum; +} + #endif /* !(__SPARC64_CHECKSUM_H) */ diff --git a/arch/sparc/include/asm/cpudata.h b/arch/sparc/include/asm/cpudata.h index b5976de7cacdb3..128b56b0867605 100644 --- a/arch/sparc/include/asm/cpudata.h +++ b/arch/sparc/include/asm/cpudata.h @@ -1,5 +1,15 @@ #ifndef ___ASM_SPARC_CPUDATA_H #define ___ASM_SPARC_CPUDATA_H + +#ifndef __ASSEMBLY__ + +#include +#include + +extern const struct seq_operations cpuinfo_op; + +#endif /* !(__ASSEMBLY__) */ + #if defined(__sparc__) && defined(__arch64__) #include #else diff --git a/arch/sparc/include/asm/cpudata_64.h b/arch/sparc/include/asm/cpudata_64.h index 050ef35b9dcf52..0e594076912c07 100644 --- a/arch/sparc/include/asm/cpudata_64.h +++ b/arch/sparc/include/asm/cpudata_64.h @@ -8,9 +8,6 @@ #ifndef __ASSEMBLY__ -#include -#include - typedef struct { /* Dcache line 1 */ unsigned int __softirq_pending; /* must be 1st, see rtrap.S */ @@ -35,8 +32,6 @@ DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); #define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu)) #define local_cpu_data() __get_cpu_var(__cpu_data) -extern const struct seq_operations cpuinfo_op; - #endif /* !(__ASSEMBLY__) */ #include diff --git a/arch/sparc/include/asm/floppy_32.h b/arch/sparc/include/asm/floppy_32.h index fb3f16954c6946..a8af6f00d76da4 100644 --- a/arch/sparc/include/asm/floppy_32.h +++ b/arch/sparc/include/asm/floppy_32.h @@ -9,11 +9,12 @@ #include #include -#include #include #include #include #include +#include +#include #include /* We don't need no stinkin' I/O port allocation crap. */ @@ -49,7 +50,6 @@ struct sun_flpy_controller { /* You'll only ever find one controller on a SparcStation anyways. */ static struct sun_flpy_controller *sun_fdc = NULL; -extern volatile unsigned char *fdc_status; struct sun_floppy_ops { unsigned char (*fd_inb)(int port); @@ -212,13 +212,6 @@ static void sun_82077_fd_outb(unsigned char value, int port) * underruns. If non-zero, doing_pdma encodes the direction of * the transfer for debugging. 1=read 2=write */ -extern char *pdma_vaddr; -extern unsigned long pdma_size; -extern volatile int doing_pdma; - -/* This is software state */ -extern char *pdma_base; -extern unsigned long pdma_areasize; /* Common routines to all controller types on the Sparc. */ static inline void virtual_dma_init(void) diff --git a/arch/sparc/include/asm/io_32.h b/arch/sparc/include/asm/io_32.h index c1acbd891cbcce..383f513be66ac2 100644 --- a/arch/sparc/include/asm/io_32.h +++ b/arch/sparc/include/asm/io_32.h @@ -2,191 +2,94 @@ #define __SPARC_IO_H #include -#include #include /* struct resource */ -#include /* IO address mapping routines need this */ -#include - -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) - -static inline u32 flip_dword (u32 l) -{ - return ((l&0xff)<<24) | (((l>>8)&0xff)<<16) | (((l>>16)&0xff)<<8)| ((l>>24)&0xff); -} - -static inline u16 flip_word (u16 w) -{ - return ((w&0xff) << 8) | ((w>>8)&0xff); -} - -#define mmiowb() - -/* - * Memory mapped I/O to PCI - */ - -static inline u8 __raw_readb(const volatile void __iomem *addr) -{ - return *(__force volatile u8 *)addr; -} - -static inline u16 __raw_readw(const volatile void __iomem *addr) -{ - return *(__force volatile u16 *)addr; -} - -static inline u32 __raw_readl(const volatile void __iomem *addr) -{ - return *(__force volatile u32 *)addr; -} +#define readb_relaxed(__addr) readb(__addr) +#define readw_relaxed(__addr) readw(__addr) +#define readl_relaxed(__addr) readl(__addr) -static inline void __raw_writeb(u8 b, volatile void __iomem *addr) -{ - *(__force volatile u8 *)addr = b; -} +#define IO_SPACE_LIMIT 0xffffffff -static inline void __raw_writew(u16 w, volatile void __iomem *addr) -{ - *(__force volatile u16 *)addr = w; -} +#define memset_io(d,c,sz) _memset_io(d,c,sz) +#define memcpy_fromio(d,s,sz) _memcpy_fromio(d,s,sz) +#define memcpy_toio(d,s,sz) _memcpy_toio(d,s,sz) -static inline void __raw_writel(u32 l, volatile void __iomem *addr) -{ - *(__force volatile u32 *)addr = l; -} +#include -static inline u8 __readb(const volatile void __iomem *addr) +static inline void _memset_io(volatile void __iomem *dst, + int c, __kernel_size_t n) { - return *(__force volatile u8 *)addr; -} + volatile void __iomem *d = dst; -static inline u16 __readw(const volatile void __iomem *addr) -{ - return flip_word(*(__force volatile u16 *)addr); + while (n--) { + writeb(c, d); + d++; + } } -static inline u32 __readl(const volatile void __iomem *addr) +static inline void _memcpy_fromio(void *dst, const volatile void __iomem *src, + __kernel_size_t n) { - return flip_dword(*(__force volatile u32 *)addr); -} + char *d = dst; -static inline void __writeb(u8 b, volatile void __iomem *addr) -{ - *(__force volatile u8 *)addr = b; + while (n--) { + char tmp = readb(src); + *d++ = tmp; + src++; + } } -static inline void __writew(u16 w, volatile void __iomem *addr) +static inline void _memcpy_toio(volatile void __iomem *dst, const void *src, + __kernel_size_t n) { - *(__force volatile u16 *)addr = flip_word(w); -} + const char *s = src; + volatile void __iomem *d = dst; -static inline void __writel(u32 l, volatile void __iomem *addr) -{ - *(__force volatile u32 *)addr = flip_dword(l); + while (n--) { + char tmp = *s++; + writeb(tmp, d); + d++; + } } -#define readb(__addr) __readb(__addr) -#define readw(__addr) __readw(__addr) -#define readl(__addr) __readl(__addr) -#define readb_relaxed(__addr) readb(__addr) -#define readw_relaxed(__addr) readw(__addr) -#define readl_relaxed(__addr) readl(__addr) - -#define writeb(__b, __addr) __writeb((__b),(__addr)) -#define writew(__w, __addr) __writew((__w),(__addr)) -#define writel(__l, __addr) __writel((__l),(__addr)) - -/* - * I/O space operations - * - * Arrangement on a Sun is somewhat complicated. - * - * First of all, we want to use standard Linux drivers - * for keyboard, PC serial, etc. These drivers think - * they access I/O space and use inb/outb. - * On the other hand, EBus bridge accepts PCI *memory* - * cycles and converts them into ISA *I/O* cycles. - * Ergo, we want inb & outb to generate PCI memory cycles. - * - * If we want to issue PCI *I/O* cycles, we do this - * with a low 64K fixed window in PCIC. This window gets - * mapped somewhere into virtual kernel space and we - * can use inb/outb again. - */ -#define inb_local(__addr) __readb((void __iomem *)(unsigned long)(__addr)) -#define inb(__addr) __readb((void __iomem *)(unsigned long)(__addr)) -#define inw(__addr) __readw((void __iomem *)(unsigned long)(__addr)) -#define inl(__addr) __readl((void __iomem *)(unsigned long)(__addr)) - -#define outb_local(__b, __addr) __writeb(__b, (void __iomem *)(unsigned long)(__addr)) -#define outb(__b, __addr) __writeb(__b, (void __iomem *)(unsigned long)(__addr)) -#define outw(__w, __addr) __writew(__w, (void __iomem *)(unsigned long)(__addr)) -#define outl(__l, __addr) __writel(__l, (void __iomem *)(unsigned long)(__addr)) - -#define inb_p(__addr) inb(__addr) -#define outb_p(__b, __addr) outb(__b, __addr) -#define inw_p(__addr) inw(__addr) -#define outw_p(__w, __addr) outw(__w, __addr) -#define inl_p(__addr) inl(__addr) -#define outl_p(__l, __addr) outl(__l, __addr) - -void outsb(unsigned long addr, const void *src, unsigned long cnt); -void outsw(unsigned long addr, const void *src, unsigned long cnt); -void outsl(unsigned long addr, const void *src, unsigned long cnt); -void insb(unsigned long addr, void *dst, unsigned long count); -void insw(unsigned long addr, void *dst, unsigned long count); -void insl(unsigned long addr, void *dst, unsigned long count); - -#define IO_SPACE_LIMIT 0xffffffff - /* * SBus accessors. * * SBus has only one, memory mapped, I/O space. * We do not need to flip bytes for SBus of course. */ -static inline u8 _sbus_readb(const volatile void __iomem *addr) +static inline u8 sbus_readb(const volatile void __iomem *addr) { return *(__force volatile u8 *)addr; } -static inline u16 _sbus_readw(const volatile void __iomem *addr) +static inline u16 sbus_readw(const volatile void __iomem *addr) { return *(__force volatile u16 *)addr; } -static inline u32 _sbus_readl(const volatile void __iomem *addr) +static inline u32 sbus_readl(const volatile void __iomem *addr) { return *(__force volatile u32 *)addr; } -static inline void _sbus_writeb(u8 b, volatile void __iomem *addr) +static inline void sbus_writeb(u8 b, volatile void __iomem *addr) { *(__force volatile u8 *)addr = b; } -static inline void _sbus_writew(u16 w, volatile void __iomem *addr) +static inline void sbus_writew(u16 w, volatile void __iomem *addr) { *(__force volatile u16 *)addr = w; } -static inline void _sbus_writel(u32 l, volatile void __iomem *addr) +static inline void sbus_writel(u32 l, volatile void __iomem *addr) { *(__force volatile u32 *)addr = l; } -/* - * The only reason for #define's is to hide casts to unsigned long. - */ -#define sbus_readb(__addr) _sbus_readb(__addr) -#define sbus_readw(__addr) _sbus_readw(__addr) -#define sbus_readl(__addr) _sbus_readl(__addr) -#define sbus_writeb(__b, __addr) _sbus_writeb(__b, __addr) -#define sbus_writew(__w, __addr) _sbus_writew(__w, __addr) -#define sbus_writel(__l, __addr) _sbus_writel(__l, __addr) - -static inline void sbus_memset_io(volatile void __iomem *__dst, int c, __kernel_size_t n) +static inline void sbus_memset_io(volatile void __iomem *__dst, int c, + __kernel_size_t n) { while(n--) { sbus_writeb(c, __dst); @@ -194,22 +97,9 @@ static inline void sbus_memset_io(volatile void __iomem *__dst, int c, __kernel_ } } -static inline void -_memset_io(volatile void __iomem *dst, int c, __kernel_size_t n) -{ - volatile void __iomem *d = dst; - - while (n--) { - writeb(c, d); - d++; - } -} - -#define memset_io(d,c,sz) _memset_io(d,c,sz) - -static inline void -_sbus_memcpy_fromio(void *dst, const volatile void __iomem *src, - __kernel_size_t n) +static inline void sbus_memcpy_fromio(void *dst, + const volatile void __iomem *src, + __kernel_size_t n) { char *d = dst; @@ -220,25 +110,9 @@ _sbus_memcpy_fromio(void *dst, const volatile void __iomem *src, } } -#define sbus_memcpy_fromio(d, s, sz) _sbus_memcpy_fromio(d, s, sz) - -static inline void -_memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n) -{ - char *d = dst; - - while (n--) { - char tmp = readb(src); - *d++ = tmp; - src++; - } -} - -#define memcpy_fromio(d,s,sz) _memcpy_fromio(d,s,sz) - -static inline void -_sbus_memcpy_toio(volatile void __iomem *dst, const void *src, - __kernel_size_t n) +static inline void sbus_memcpy_toio(volatile void __iomem *dst, + const void *src, + __kernel_size_t n) { const char *s = src; volatile void __iomem *d = dst; @@ -250,23 +124,6 @@ _sbus_memcpy_toio(volatile void __iomem *dst, const void *src, } } -#define sbus_memcpy_toio(d, s, sz) _sbus_memcpy_toio(d, s, sz) - -static inline void -_memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n) -{ - const char *s = src; - volatile void __iomem *d = dst; - - while (n--) { - char tmp = *s++; - writeb(tmp, d); - d++; - } -} - -#define memcpy_toio(d,s,sz) _memcpy_toio(d,s,sz) - #ifdef __KERNEL__ /* @@ -278,46 +135,6 @@ extern void __iomem *ioremap(unsigned long offset, unsigned long size); #define ioremap_wc(X,Y) ioremap((X),(Y)) extern void iounmap(volatile void __iomem *addr); -#define ioread8(X) readb(X) -#define ioread16(X) readw(X) -#define ioread16be(X) __raw_readw(X) -#define ioread32(X) readl(X) -#define ioread32be(X) __raw_readl(X) -#define iowrite8(val,X) writeb(val,X) -#define iowrite16(val,X) writew(val,X) -#define iowrite16be(val,X) __raw_writew(val,X) -#define iowrite32(val,X) writel(val,X) -#define iowrite32be(val,X) __raw_writel(val,X) - -static inline void ioread8_rep(void __iomem *port, void *buf, unsigned long count) -{ - insb((unsigned long __force)port, buf, count); -} -static inline void ioread16_rep(void __iomem *port, void *buf, unsigned long count) -{ - insw((unsigned long __force)port, buf, count); -} - -static inline void ioread32_rep(void __iomem *port, void *buf, unsigned long count) -{ - insl((unsigned long __force)port, buf, count); -} - -static inline void iowrite8_rep(void __iomem *port, const void *buf, unsigned long count) -{ - outsb((unsigned long __force)port, buf, count); -} - -static inline void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count) -{ - outsw((unsigned long __force)port, buf, count); -} - -static inline void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count) -{ - outsl((unsigned long __force)port, buf, count); -} - /* Create a virtual mapping cookie for an IO port range */ extern void __iomem *ioport_map(unsigned long port, unsigned int nr); extern void ioport_unmap(void __iomem *); @@ -326,6 +143,8 @@ extern void ioport_unmap(void __iomem *); struct pci_dev; extern void pci_iounmap(struct pci_dev *dev, void __iomem *); + + /* * At the moment, we do not use CMOS_READ anywhere outside of rtc.c, * so rtc_port is static in it. This should not change unless a new @@ -349,15 +168,5 @@ extern void sbus_set_sbus64(struct device *, int); #define __ARCH_HAS_NO_PAGE_ZERO_MAPPED 1 -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - -/* - * Convert a virtual cached pointer to an uncached pointer - */ -#define xlate_dev_kmem_ptr(p) p #endif /* !(__SPARC_IO_H) */ diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h index 09b0b88aeb2a42..44845632e983b4 100644 --- a/arch/sparc/include/asm/io_64.h +++ b/arch/sparc/include/asm/io_64.h @@ -15,7 +15,6 @@ /* BIO layer definitions. */ extern unsigned long kern_base, kern_size; -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) static inline u8 _inb(unsigned long addr) { diff --git a/arch/sparc/include/asm/irq_32.h b/arch/sparc/include/asm/irq_32.h index 2ae3acaeb1b319..9277e519468daa 100644 --- a/arch/sparc/include/asm/irq_32.h +++ b/arch/sparc/include/asm/irq_32.h @@ -17,6 +17,7 @@ #define irq_canonicalize(irq) (irq) extern void __init init_IRQ(void); +void __init sun4d_init_sbi_irq(void); #define NO_IRQ 0xffffffff diff --git a/arch/sparc/include/asm/page.h b/arch/sparc/include/asm/page.h index f21de034902596..1be2fdec626896 100644 --- a/arch/sparc/include/asm/page.h +++ b/arch/sparc/include/asm/page.h @@ -1,5 +1,8 @@ #ifndef ___ASM_SPARC_PAGE_H #define ___ASM_SPARC_PAGE_H + +#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) + #if defined(__sparc__) && defined(__arch64__) #include #else diff --git a/arch/sparc/include/asm/pgalloc_32.h b/arch/sparc/include/asm/pgalloc_32.h index 9b1c36de0f183f..a3890da9442892 100644 --- a/arch/sparc/include/asm/pgalloc_32.h +++ b/arch/sparc/include/asm/pgalloc_32.h @@ -14,6 +14,8 @@ struct page; void *srmmu_get_nocache(int size, int align); void srmmu_free_nocache(void *addr, int size); +extern struct resource sparc_iomap; + #define check_pgt_cache() do { } while (0) pgd_t *get_pgd_fast(void); diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index 502f632f6cc73e..16629e7cb09e67 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h @@ -27,6 +27,7 @@ struct page; extern void load_mmu(void); extern unsigned long calc_highpages(void); +unsigned long __init bootmem_init(unsigned long *pages_avail); #define pte_ERROR(e) __builtin_trap() #define pmd_ERROR(e) __builtin_trap() diff --git a/arch/sparc/include/asm/setup.h b/arch/sparc/include/asm/setup.h index 5e35e051731887..fb54505e008ec2 100644 --- a/arch/sparc/include/asm/setup.h +++ b/arch/sparc/include/asm/setup.h @@ -4,8 +4,9 @@ #ifndef _SPARC_SETUP_H #define _SPARC_SETUP_H -#include +#include +#include extern char reboot_command[]; @@ -22,6 +23,28 @@ static inline int con_is_present(void) { return serial_console ? 0 : 1; } + +/* from irq_32.c */ +extern volatile unsigned char *fdc_status; +extern char *pdma_vaddr; +extern unsigned long pdma_size; +extern volatile int doing_pdma; + +/* This is software state */ +extern char *pdma_base; +extern unsigned long pdma_areasize; + +int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler); + +/* setup_32.c */ +extern unsigned long cmdline_memory_size; + +/* devices.c */ +void __init device_scan(void); + +/* unaligned_32.c */ +unsigned long safe_compute_effective_address(struct pt_regs *, unsigned int); + #endif extern void sun_do_break(void); diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h index 025a02ad2e31c9..49f71fd5b56ee8 100644 --- a/arch/sparc/include/asm/syscall.h +++ b/arch/sparc/include/asm/syscall.h @@ -1,9 +1,11 @@ #ifndef __ASM_SPARC_SYSCALL_H #define __ASM_SPARC_SYSCALL_H +#include #include #include #include +#include /* * The syscall table always contains 32 bit pointers since we know that the @@ -124,4 +126,9 @@ static inline void syscall_set_arguments(struct task_struct *task, regs->u_regs[UREG_I0 + i + j] = args[j]; } +static inline int syscall_get_arch(void) +{ + return is_32bit_task() ? AUDIT_ARCH_SPARC : AUDIT_ARCH_SPARC64; +} + #endif /* __ASM_SPARC_SYSCALL_H */ diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h index 96efa7adc22330..025c98446b1ee1 100644 --- a/arch/sparc/include/asm/thread_info_32.h +++ b/arch/sparc/include/asm/thread_info_32.h @@ -130,6 +130,8 @@ register struct thread_info *current_thread_info_reg asm("g6"); #define _TIF_DO_NOTIFY_RESUME_MASK (_TIF_NOTIFY_RESUME | \ _TIF_SIGPENDING) +#define is_32bit_task() (1) + #endif /* __KERNEL__ */ #endif /* _ASM_THREAD_INFO_H */ diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h index a5f01ac6d0f1a2..5a4f6600e62482 100644 --- a/arch/sparc/include/asm/thread_info_64.h +++ b/arch/sparc/include/asm/thread_info_64.h @@ -219,6 +219,8 @@ register struct thread_info *current_thread_info_reg asm("g6"); _TIF_NEED_RESCHED) #define _TIF_DO_NOTIFY_RESUME_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING) +#define is_32bit_task() (test_thread_flag(TIF_32BIT)) + /* * Thread-synchronous status. * diff --git a/arch/sparc/include/asm/timer_32.h b/arch/sparc/include/asm/timer_32.h index 72f40a546de35e..93476f8d7fea42 100644 --- a/arch/sparc/include/asm/timer_32.h +++ b/arch/sparc/include/asm/timer_32.h @@ -32,7 +32,7 @@ static inline unsigned int timer_value(unsigned int value) return (value + 1) << TIMER_VALUE_SHIFT; } -extern __volatile__ unsigned int *master_l10_counter; +extern volatile unsigned int __iomem *master_l10_counter; extern irqreturn_t notrace timer_interrupt(int dummy, void *dev_id); diff --git a/arch/sparc/kernel/auxio_32.c b/arch/sparc/kernel/auxio_32.c index e20cc55fb768f3..c6fc1d451407ce 100644 --- a/arch/sparc/kernel/auxio_32.c +++ b/arch/sparc/kernel/auxio_32.c @@ -9,12 +9,15 @@ #include #include #include + #include #include #include #include /* memset(), Linux has no bzero() */ #include +#include "kernel.h" + /* Probe and map in the Auxiliary I/O register */ /* auxio_register is not static because it is referenced diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c index 5c5125895db86e..82a3a71c451e43 100644 --- a/arch/sparc/kernel/cpu.c +++ b/arch/sparc/kernel/cpu.c @@ -22,6 +22,7 @@ #include #include "kernel.h" +#include "entry.h" DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 }; EXPORT_PER_CPU_SYMBOL(__cpu_data); diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c index 3d465e87f7e247..6f39916dc6e869 100644 --- a/arch/sparc/kernel/devices.c +++ b/arch/sparc/kernel/devices.c @@ -19,8 +19,9 @@ #include #include #include +#include -extern void clock_stop_probe(void); /* tadpole.c */ +#include "kernel.h" static char *cpu_mid_prop(void) { @@ -131,11 +132,7 @@ void __init device_scan(void) } #endif /* !CONFIG_SMP */ - { - extern void auxio_probe(void); - extern void auxio_power_probe(void); - auxio_probe(); - auxio_power_probe(); - } + auxio_probe(); + auxio_power_probe(); clock_stop_probe(); } diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index e7e215dfa86668..7f08ec8a7c6823 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -186,7 +186,7 @@ static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys, if (name == NULL) name = "???"; - if ((xres = xres_alloc()) != 0) { + if ((xres = xres_alloc()) != NULL) { tack = xres->xname; res = &xres->xres; } else { @@ -400,7 +400,7 @@ static void sbus_sync_sg_for_device(struct device *dev, struct scatterlist *sg, BUG(); } -struct dma_map_ops sbus_dma_ops = { +static struct dma_map_ops sbus_dma_ops = { .alloc = sbus_alloc_coherent, .free = sbus_free_coherent, .map_page = sbus_map_page, @@ -681,7 +681,7 @@ static int sparc_io_proc_show(struct seq_file *m, void *v) const char *nm; for (r = root->child; r != NULL; r = r->sibling) { - if ((nm = r->name) == 0) nm = "???"; + if ((nm = r->name) == NULL) nm = "???"; seq_printf(m, "%016llx-%016llx: %s\n", (unsigned long long)r->start, (unsigned long long)r->end, nm); diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h index b66b6aad1d6d7f..7c7540a6236268 100644 --- a/arch/sparc/kernel/irq.h +++ b/arch/sparc/kernel/irq.h @@ -82,6 +82,15 @@ void handler_irq(unsigned int pil, struct pt_regs *regs); unsigned long leon_get_irqmask(unsigned int irq); +/* irq_32.c */ +void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs); + +/* sun4m_irq.c */ +void sun4m_nmi(struct pt_regs *regs); + +/* sun4d_irq.c */ +void sun4d_handler_irq(unsigned int pil, struct pt_regs *regs); + #ifdef CONFIG_SMP /* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */ diff --git a/arch/sparc/kernel/irq_32.c b/arch/sparc/kernel/irq_32.c index c145f6fd123b88..a979e99f8751cd 100644 --- a/arch/sparc/kernel/irq_32.c +++ b/arch/sparc/kernel/irq_32.c @@ -17,6 +17,7 @@ #include #include +#include #include #include diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index a702d9ab019c23..de9ac1aa25e83c 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h @@ -51,6 +51,11 @@ extern void sun4m_clear_profile_irq(int cpu); /* sun4m_smp.c */ void sun4m_cpu_pre_starting(void *arg); void sun4m_cpu_pre_online(void *arg); +void __init smp4m_boot_cpus(void); +int smp4m_boot_one_cpu(int i, struct task_struct *idle); +void __init smp4m_smp_done(void); +void smp4m_cross_call_irq(void); +void smp4m_percpu_timer_interrupt(struct pt_regs *regs); /* sun4d_irq.c */ extern spinlock_t sun4d_imsk_lock; @@ -67,10 +72,17 @@ extern void sun4d_free_irq(unsigned int irq, void *dev_id); /* sun4d_smp.c */ void sun4d_cpu_pre_starting(void *arg); void sun4d_cpu_pre_online(void *arg); +void __init smp4d_boot_cpus(void); +int smp4d_boot_one_cpu(int i, struct task_struct *idle); +void __init smp4d_smp_done(void); +void smp4d_cross_call_irq(void); +void smp4d_percpu_timer_interrupt(struct pt_regs *regs); /* leon_smp.c */ void leon_cpu_pre_starting(void *arg); void leon_cpu_pre_online(void *arg); +void leonsmp_ipi_interrupt(void); +void leon_cross_call_irq(void); /* head_32.S */ extern unsigned int t_nmi[]; @@ -95,6 +107,38 @@ extern void floppy_hardint(void); extern unsigned long sun4m_cpu_startup; extern unsigned long sun4d_cpu_startup; +/* process_32.c */ +asmlinkage int sparc_do_fork(unsigned long clone_flags, + unsigned long stack_start, + struct pt_regs *regs, + unsigned long stack_size); + +/* signal_32.c */ +asmlinkage void do_sigreturn(struct pt_regs *regs); +asmlinkage void do_rt_sigreturn(struct pt_regs *regs); +void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, + unsigned long thread_info_flags); +asmlinkage int do_sys_sigstack(struct sigstack __user *ssptr, + struct sigstack __user *ossptr, + unsigned long sp); + +/* ptrace_32.c */ +asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p); + +/* unaligned_32.c */ +asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn); +asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn); + +/* windows.c */ +void try_to_clear_window_buffer(struct pt_regs *regs, int who); + +/* tadpole.c */ +void __init clock_stop_probe(void); + +/* auxio_32.c */ +void __init auxio_probe(void); +void __init auxio_power_probe(void); + #else /* CONFIG_SPARC32 */ #endif /* CONFIG_SPARC32 */ #endif /* !(__SPARC_KERNEL_H) */ diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index b7c68976cbc756..d9397088893ac1 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -32,12 +32,12 @@ struct leon3_gptimer_regs_map *leon3_gptimer_regs; /* timer controller base addr int leondebug_irq_disable; int leon_debug_irqout; -static int dummy_master_l10_counter; +static volatile unsigned int dummy_master_l10_counter; unsigned long amba_system_id; static DEFINE_SPINLOCK(leon_irq_lock); +static unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ unsigned long leon3_gptimer_irq; /* interrupt controller irq number */ -unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ unsigned int sparc_leon_eirq; #define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu]) #define LEON_IACK (&leon3_irqctrl_regs->iclear) @@ -65,7 +65,7 @@ static void leon_handle_ext_irq(unsigned int irq, struct irq_desc *desc) } /* The extended IRQ controller has been found, this function registers it */ -void leon_eirq_setup(unsigned int eirq) +static void leon_eirq_setup(unsigned int eirq) { unsigned long mask, oldmask; unsigned int veirq; @@ -270,7 +270,7 @@ static u32 leon_cycles_offset(void) #ifdef CONFIG_SMP /* smp clockevent irq */ -irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused) +static irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused) { struct clock_event_device *ce; int cpu = smp_processor_id(); @@ -313,7 +313,8 @@ void __init leon_init_timers(void) leondebug_irq_disable = 0; leon_debug_irqout = 0; - master_l10_counter = (unsigned int *)&dummy_master_l10_counter; + master_l10_counter = + (unsigned int __iomem *)&dummy_master_l10_counter; dummy_master_l10_counter = 0; rootnp = of_find_node_by_path("/ambapp0"); diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c index e16c4157e1ae1a..899b7203a4e4a2 100644 --- a/arch/sparc/kernel/leon_pci.c +++ b/arch/sparc/kernel/leon_pci.c @@ -98,82 +98,3 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, { return res->start; } - -/* in/out routines taken from pcic.c - * - * This probably belongs here rather than ioport.c because - * we do not want this crud linked into SBus kernels. - * Also, think for a moment about likes of floppy.c that - * include architecture specific parts. They may want to redefine ins/outs. - * - * We do not use horrible macros here because we want to - * advance pointer by sizeof(size). - */ -void outsb(unsigned long addr, const void *src, unsigned long count) -{ - while (count) { - count -= 1; - outb(*(const char *)src, addr); - src += 1; - /* addr += 1; */ - } -} -EXPORT_SYMBOL(outsb); - -void outsw(unsigned long addr, const void *src, unsigned long count) -{ - while (count) { - count -= 2; - outw(*(const short *)src, addr); - src += 2; - /* addr += 2; */ - } -} -EXPORT_SYMBOL(outsw); - -void outsl(unsigned long addr, const void *src, unsigned long count) -{ - while (count) { - count -= 4; - outl(*(const long *)src, addr); - src += 4; - /* addr += 4; */ - } -} -EXPORT_SYMBOL(outsl); - -void insb(unsigned long addr, void *dst, unsigned long count) -{ - while (count) { - count -= 1; - *(unsigned char *)dst = inb(addr); - dst += 1; - /* addr += 1; */ - } -} -EXPORT_SYMBOL(insb); - -void insw(unsigned long addr, void *dst, unsigned long count) -{ - while (count) { - count -= 2; - *(unsigned short *)dst = inw(addr); - dst += 2; - /* addr += 2; */ - } -} -EXPORT_SYMBOL(insw); - -void insl(unsigned long addr, void *dst, unsigned long count) -{ - while (count) { - count -= 4; - /* - * XXX I am sure we are in for an unaligned trap here. - */ - *(unsigned long *)dst = inl(addr); - dst += 4; - /* addr += 4; */ - } -} -EXPORT_SYMBOL(insl); diff --git a/arch/sparc/kernel/leon_pci_grpci1.c b/arch/sparc/kernel/leon_pci_grpci1.c index 6df26e37f8790c..c8bf26edfa7cf5 100644 --- a/arch/sparc/kernel/leon_pci_grpci1.c +++ b/arch/sparc/kernel/leon_pci_grpci1.c @@ -80,7 +80,7 @@ struct grpci1_regs { struct grpci1_priv { struct leon_pci_info info; /* must be on top of this structure */ - struct grpci1_regs *regs; /* GRPCI register map */ + struct grpci1_regs __iomem *regs; /* GRPCI register map */ struct device *dev; int pci_err_mask; /* STATUS register error mask */ int irq; /* LEON irqctrl GRPCI IRQ */ @@ -101,7 +101,7 @@ static struct grpci1_priv *grpci1priv; static int grpci1_cfg_w32(struct grpci1_priv *priv, unsigned int bus, unsigned int devfn, int where, u32 val); -int grpci1_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +static int grpci1_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { struct grpci1_priv *priv = dev->bus->sysdata; int irq_group; @@ -144,7 +144,7 @@ static int grpci1_cfg_r32(struct grpci1_priv *priv, unsigned int bus, grpci1_cfg_w32(priv, TGT, 0, PCI_COMMAND, tmp); } else { /* Bus always little endian (unaffected by byte-swapping) */ - *val = flip_dword(tmp); + *val = swab32(tmp); } return 0; @@ -197,7 +197,7 @@ static int grpci1_cfg_w32(struct grpci1_priv *priv, unsigned int bus, pci_conf = (unsigned int *) (priv->pci_conf | (devfn << 8) | (where & 0xfc)); - LEON3_BYPASS_STORE_PA(pci_conf, flip_dword(val)); + LEON3_BYPASS_STORE_PA(pci_conf, swab32(val)); return 0; } @@ -417,10 +417,10 @@ static unsigned int grpci1_build_device_irq(unsigned int irq) * BAR1: peripheral DMA to host's memory (size at least 256MByte) * BAR2..BAR5: not implemented in hardware */ -void grpci1_hw_init(struct grpci1_priv *priv) +static void grpci1_hw_init(struct grpci1_priv *priv) { u32 ahbadr, bar_sz, data, pciadr; - struct grpci1_regs *regs = priv->regs; + struct grpci1_regs __iomem *regs = priv->regs; /* set 1:1 mapping between AHB -> PCI memory space */ REGSTORE(regs->cfg_stat, priv->pci_area & 0xf0000000); @@ -509,7 +509,7 @@ static irqreturn_t grpci1_err_interrupt(int irq, void *arg) static int grpci1_of_probe(struct platform_device *ofdev) { - struct grpci1_regs *regs; + struct grpci1_regs __iomem *regs; struct grpci1_priv *priv; int err, len; const int *tmp; @@ -690,7 +690,7 @@ static int grpci1_of_probe(struct platform_device *ofdev) err2: release_resource(&priv->info.mem_space); err1: - iounmap((void *)priv->pci_io_va); + iounmap((void __iomem *)priv->pci_io_va); grpci1priv = NULL; return err; } diff --git a/arch/sparc/kernel/leon_pci_grpci2.c b/arch/sparc/kernel/leon_pci_grpci2.c index 24d6a44463494e..e433a4d69fe092 100644 --- a/arch/sparc/kernel/leon_pci_grpci2.c +++ b/arch/sparc/kernel/leon_pci_grpci2.c @@ -191,7 +191,7 @@ struct grpci2_cap_first { struct grpci2_priv { struct leon_pci_info info; /* must be on top of this structure */ - struct grpci2_regs *regs; + struct grpci2_regs __iomem *regs; char irq; char irq_mode; /* IRQ Mode from CAPSTS REG */ char bt_enabled; @@ -215,10 +215,10 @@ struct grpci2_priv { struct grpci2_barcfg tgtbars[6]; }; -DEFINE_SPINLOCK(grpci2_dev_lock); -struct grpci2_priv *grpci2priv; +static DEFINE_SPINLOCK(grpci2_dev_lock); +static struct grpci2_priv *grpci2priv; -int grpci2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +static int grpci2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { struct grpci2_priv *priv = dev->bus->sysdata; int irq_group; @@ -270,7 +270,7 @@ static int grpci2_cfg_r32(struct grpci2_priv *priv, unsigned int bus, *val = 0xffffffff; } else { /* Bus always little endian (unaffected by byte-swapping) */ - *val = flip_dword(tmp); + *val = swab32(tmp); } return 0; @@ -328,7 +328,7 @@ static int grpci2_cfg_w32(struct grpci2_priv *priv, unsigned int bus, pci_conf = (unsigned int *) (priv->pci_conf | (devfn << 8) | (where & 0xfc)); - LEON3_BYPASS_STORE_PA(pci_conf, flip_dword(val)); + LEON3_BYPASS_STORE_PA(pci_conf, swab32(val)); /* Wait until GRPCI2 signals that CFG access is done, it should be * done instantaneously unless a DMA operation is ongoing... @@ -561,10 +561,10 @@ static unsigned int grpci2_build_device_irq(unsigned int irq) return virq; } -void grpci2_hw_init(struct grpci2_priv *priv) +static void grpci2_hw_init(struct grpci2_priv *priv) { u32 ahbadr, pciadr, bar_sz, capptr, io_map, data; - struct grpci2_regs *regs = priv->regs; + struct grpci2_regs __iomem *regs = priv->regs; int i; struct grpci2_barcfg *barcfg = priv->tgtbars; @@ -655,7 +655,7 @@ static irqreturn_t grpci2_jump_interrupt(int irq, void *arg) static irqreturn_t grpci2_err_interrupt(int irq, void *arg) { struct grpci2_priv *priv = arg; - struct grpci2_regs *regs = priv->regs; + struct grpci2_regs __iomem *regs = priv->regs; unsigned int status; status = REGLOAD(regs->sts_cap); @@ -682,7 +682,7 @@ static irqreturn_t grpci2_err_interrupt(int irq, void *arg) static int grpci2_of_probe(struct platform_device *ofdev) { - struct grpci2_regs *regs; + struct grpci2_regs __iomem *regs; struct grpci2_priv *priv; int err, i, len; const int *tmp; @@ -878,7 +878,7 @@ static int grpci2_of_probe(struct platform_device *ofdev) release_resource(&priv->info.mem_space); err3: err = -ENOMEM; - iounmap((void *)priv->pci_io_va); + iounmap((void __iomem *)priv->pci_io_va); err2: kfree(priv); err1: diff --git a/arch/sparc/kernel/leon_pmc.c b/arch/sparc/kernel/leon_pmc.c index b0b3967a2dd2d1..ddcf950282ed67 100644 --- a/arch/sparc/kernel/leon_pmc.c +++ b/arch/sparc/kernel/leon_pmc.c @@ -12,14 +12,14 @@ #include /* List of Systems that need fixup instructions around power-down instruction */ -unsigned int pmc_leon_fixup_ids[] = { +static unsigned int pmc_leon_fixup_ids[] = { AEROFLEX_UT699, GAISLER_GR712RC, LEON4_NEXTREME1, 0 }; -int pmc_leon_need_fixup(void) +static int pmc_leon_need_fixup(void) { unsigned int systemid = amba_system_id >> 16; unsigned int *id; @@ -38,7 +38,7 @@ int pmc_leon_need_fixup(void) * CPU idle callback function for systems that need some extra handling * See .../arch/sparc/kernel/process.c */ -void pmc_leon_idle_fixup(void) +static void pmc_leon_idle_fixup(void) { /* Prepare an address to a non-cachable region. APB is always * none-cachable. One instruction is executed after the Sleep @@ -62,7 +62,7 @@ void pmc_leon_idle_fixup(void) * CPU idle callback function * See .../arch/sparc/kernel/process.c */ -void pmc_leon_idle(void) +static void pmc_leon_idle(void) { /* Interrupts need to be enabled to not hang the CPU */ local_irq_enable(); diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c index 6edf955f987caa..018ef11f57df70 100644 --- a/arch/sparc/kernel/leon_smp.c +++ b/arch/sparc/kernel/leon_smp.c @@ -130,7 +130,7 @@ void leon_configure_cache_smp(void) local_ops->tlb_all(); } -void leon_smp_setbroadcast(unsigned int mask) +static void leon_smp_setbroadcast(unsigned int mask) { int broadcast = ((LEON3_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpstatus)) >> @@ -148,13 +148,6 @@ void leon_smp_setbroadcast(unsigned int mask) LEON_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mpbroadcast), mask); } -unsigned int leon_smp_getbroadcast(void) -{ - unsigned int mask; - mask = LEON_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpbroadcast)); - return mask; -} - int leon_smp_nrcpus(void) { int nrcpu = @@ -266,10 +259,6 @@ void __init leon_smp_done(void) } -void leon_irq_rotate(int cpu) -{ -} - struct leon_ipi_work { int single; int msk; diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c index 3241f56331c2ac..de0ee3971f00ec 100644 --- a/arch/sparc/kernel/of_device_common.c +++ b/arch/sparc/kernel/of_device_common.c @@ -5,8 +5,10 @@ #include #include #include -#include #include +#include +#include +#include #include "of_device_common.h" diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 09f4fdd8d8080f..aabfcab9432524 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -783,7 +783,7 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask) void pcic_nmi(unsigned int pend, struct pt_regs *regs) { - pend = flip_dword(pend); + pend = swab32(pend); if (!pcic_speculative || (pend & PCI_SYS_INT_PENDING_PIO) == 0) { /* @@ -875,82 +875,4 @@ void __init sun4m_pci_init_IRQ(void) sparc_config.load_profile_irq = pcic_load_profile_irq; } -/* - * This probably belongs here rather than ioport.c because - * we do not want this crud linked into SBus kernels. - * Also, think for a moment about likes of floppy.c that - * include architecture specific parts. They may want to redefine ins/outs. - * - * We do not use horrible macros here because we want to - * advance pointer by sizeof(size). - */ -void outsb(unsigned long addr, const void *src, unsigned long count) -{ - while (count) { - count -= 1; - outb(*(const char *)src, addr); - src += 1; - /* addr += 1; */ - } -} -EXPORT_SYMBOL(outsb); - -void outsw(unsigned long addr, const void *src, unsigned long count) -{ - while (count) { - count -= 2; - outw(*(const short *)src, addr); - src += 2; - /* addr += 2; */ - } -} -EXPORT_SYMBOL(outsw); - -void outsl(unsigned long addr, const void *src, unsigned long count) -{ - while (count) { - count -= 4; - outl(*(const long *)src, addr); - src += 4; - /* addr += 4; */ - } -} -EXPORT_SYMBOL(outsl); - -void insb(unsigned long addr, void *dst, unsigned long count) -{ - while (count) { - count -= 1; - *(unsigned char *)dst = inb(addr); - dst += 1; - /* addr += 1; */ - } -} -EXPORT_SYMBOL(insb); - -void insw(unsigned long addr, void *dst, unsigned long count) -{ - while (count) { - count -= 2; - *(unsigned short *)dst = inw(addr); - dst += 2; - /* addr += 2; */ - } -} -EXPORT_SYMBOL(insw); - -void insl(unsigned long addr, void *dst, unsigned long count) -{ - while (count) { - count -= 4; - /* - * XXX I am sure we are in for an unaligned trap here. - */ - *(unsigned long *)dst = inl(addr); - dst += 4; - /* addr += 4; */ - } -} -EXPORT_SYMBOL(insl); - subsys_initcall(pcic_init); diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index 510baec1b69b2c..61f810b0a9d92c 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -10,6 +10,7 @@ #include +#include #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #include #include @@ -38,6 +40,8 @@ #include #include +#include "kernel.h" + /* * Power management idle function * Set in pm platform drivers (apc.c and pmc.c) diff --git a/arch/sparc/kernel/ptrace_32.c b/arch/sparc/kernel/ptrace_32.c index 896ba7c5cd8eb9..a331fdc11a2cc0 100644 --- a/arch/sparc/kernel/ptrace_32.c +++ b/arch/sparc/kernel/ptrace_32.c @@ -26,6 +26,8 @@ #include #include +#include "kernel.h" + /* #define ALLOW_INIT_TRACING */ /* diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c index c13c9f25d83a0b..9ddc4928a089b5 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c @@ -1076,13 +1076,8 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->u_regs[UREG_G1]); - audit_syscall_entry((test_thread_flag(TIF_32BIT) ? - AUDIT_ARCH_SPARC : - AUDIT_ARCH_SPARC64), - regs->u_regs[UREG_G1], - regs->u_regs[UREG_I0], - regs->u_regs[UREG_I1], - regs->u_regs[UREG_I2], + audit_syscall_entry(regs->u_regs[UREG_G1], regs->u_regs[UREG_I0], + regs->u_regs[UREG_I1], regs->u_regs[UREG_I2], regs->u_regs[UREG_I3]); return ret; diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index 1434526970a6bf..baef495c06bdb0 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c @@ -267,7 +267,7 @@ static __init void leon_patch(void) } struct tt_entry *sparc_ttable; -struct pt_regs fake_swapper_regs; +static struct pt_regs fake_swapper_regs; /* Called from head_32.S - before we have setup anything * in the kernel. Be very careful with what you do here. @@ -365,7 +365,7 @@ void __init setup_arch(char **cmdline_p) prom_setsync(prom_sync_me); - if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && + if((boot_flags & BOOTME_DEBUG) && (linux_dbvec != NULL) && ((*(short *)linux_dbvec) != -1)) { printk("Booted under KADB. Syncing trap table.\n"); (*(linux_dbvec->teach_debugger))(); diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 7d5d8e1f841569..9ee72fc8e0e496 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -28,6 +28,7 @@ #include #include "sigutil.h" +#include "kernel.h" extern void fpsave(unsigned long *fpregs, unsigned long *fsr, void *fpqueue, unsigned long *fpqdepth); @@ -341,7 +342,7 @@ static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, err |= __put_user(0, &sf->extra_size); if (psr & PSR_EF) { - __siginfo_fpu_t *fp = tail; + __siginfo_fpu_t __user *fp = tail; tail += sizeof(*fp); err |= save_fpu_state(regs, fp); err |= __put_user(fp, &sf->fpu_save); @@ -349,7 +350,7 @@ static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, err |= __put_user(0, &sf->fpu_save); } if (wsaved) { - __siginfo_rwin_t *rwp = tail; + __siginfo_rwin_t __user *rwp = tail; tail += sizeof(*rwp); err |= save_rwin_state(wsaved, rwp); err |= __put_user(rwp, &sf->rwin_save); @@ -517,9 +518,9 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, } } -asmlinkage int -do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr, - unsigned long sp) +asmlinkage int do_sys_sigstack(struct sigstack __user *ssptr, + struct sigstack __user *ossptr, + unsigned long sp) { int ret = -EFAULT; diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c index a102bfba6ea866..9d3297d8d7308a 100644 --- a/arch/sparc/kernel/smp_32.c +++ b/arch/sparc/kernel/smp_32.c @@ -75,8 +75,6 @@ void smp_store_cpu_info(int id) void __init smp_cpus_done(unsigned int max_cpus) { - extern void smp4m_smp_done(void); - extern void smp4d_smp_done(void); unsigned long bogosum = 0; int cpu, num = 0; @@ -183,8 +181,6 @@ int setup_profiling_timer(unsigned int multiplier) void __init smp_prepare_cpus(unsigned int max_cpus) { - extern void __init smp4m_boot_cpus(void); - extern void __init smp4d_boot_cpus(void); int i, cpuid, extra; printk("Entering SMP Mode...\n"); @@ -261,8 +257,6 @@ void __init smp_prepare_boot_cpu(void) int __cpu_up(unsigned int cpu, struct task_struct *tidle) { - extern int smp4m_boot_one_cpu(int, struct task_struct *); - extern int smp4d_boot_one_cpu(int, struct task_struct *); int ret=0; switch(sparc_cpu_model) { @@ -297,7 +291,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) return ret; } -void arch_cpu_pre_starting(void *arg) +static void arch_cpu_pre_starting(void *arg) { local_ops->cache_all(); local_ops->tlb_all(); @@ -317,7 +311,7 @@ void arch_cpu_pre_starting(void *arg) } } -void arch_cpu_pre_online(void *arg) +static void arch_cpu_pre_online(void *arg) { unsigned int cpuid = hard_smp_processor_id(); @@ -344,7 +338,7 @@ void arch_cpu_pre_online(void *arg) } } -void sparc_start_secondary(void *arg) +static void sparc_start_secondary(void *arg) { unsigned int cpu; diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index f8933be3ca8b21..a1bb2675b2801a 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -143,7 +143,7 @@ static void sun4d_sbus_handler_irq(int sbusl) } } -void sun4d_handler_irq(int pil, struct pt_regs *regs) +void sun4d_handler_irq(unsigned int pil, struct pt_regs *regs) { struct pt_regs *old_regs; /* SBUS IRQ level (1 - 7) */ @@ -236,7 +236,7 @@ static void sun4d_shutdown_irq(struct irq_data *data) irq_unlink(data->irq); } -struct irq_chip sun4d_irq = { +static struct irq_chip sun4d_irq = { .name = "sun4d", .irq_startup = sun4d_startup_irq, .irq_shutdown = sun4d_shutdown_irq, @@ -285,9 +285,9 @@ static void __init sun4d_load_profile_irqs(void) } } -unsigned int _sun4d_build_device_irq(unsigned int real_irq, - unsigned int pil, - unsigned int board) +static unsigned int _sun4d_build_device_irq(unsigned int real_irq, + unsigned int pil, + unsigned int board) { struct sun4d_handler_data *handler_data; unsigned int irq; @@ -320,8 +320,8 @@ unsigned int _sun4d_build_device_irq(unsigned int real_irq, -unsigned int sun4d_build_device_irq(struct platform_device *op, - unsigned int real_irq) +static unsigned int sun4d_build_device_irq(struct platform_device *op, + unsigned int real_irq) { struct device_node *dp = op->dev.of_node; struct device_node *board_parent, *bus = dp->parent; @@ -383,7 +383,8 @@ unsigned int sun4d_build_device_irq(struct platform_device *op, return irq; } -unsigned int sun4d_build_timer_irq(unsigned int board, unsigned int real_irq) +static unsigned int sun4d_build_timer_irq(unsigned int board, + unsigned int real_irq) { return _sun4d_build_device_irq(real_irq, real_irq, board); } diff --git a/arch/sparc/kernel/tadpole.c b/arch/sparc/kernel/tadpole.c index 9aba8bd5a78b56..4bbfe4e2676de0 100644 --- a/arch/sparc/kernel/tadpole.c +++ b/arch/sparc/kernel/tadpole.c @@ -12,13 +12,17 @@ #include #include +#include "kernel.h" + #define MACIO_SCSI_CSR_ADDR 0x78400000 #define MACIO_EN_DMA 0x00000200 #define CLOCK_INIT_DONE 1 static int clk_state; static volatile unsigned char *clk_ctrl; -void (*cpu_pwr_save)(void); + +/* TODO - cpu_pwr_save is only assigned - cleanup potential. */ +static void (*cpu_pwr_save)(void); static inline unsigned int ldphys(unsigned int addr) { diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c index c4c27b0f9063d7..772b37986a9cc4 100644 --- a/arch/sparc/kernel/time_32.c +++ b/arch/sparc/kernel/time_32.c @@ -83,7 +83,7 @@ unsigned long profile_pc(struct pt_regs *regs) EXPORT_SYMBOL(profile_pc); -__volatile__ unsigned int *master_l10_counter; +volatile unsigned int __iomem *master_l10_counter; int update_persistent_clock(struct timespec now) { diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c index 662982946a8918..a655e5bf92a707 100644 --- a/arch/sparc/kernel/traps_32.c +++ b/arch/sparc/kernel/traps_32.c @@ -44,7 +44,7 @@ static void instruction_dump(unsigned long *pc) #define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t") #define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t") -void die_if_kernel(char *str, struct pt_regs *regs) +void __noreturn die_if_kernel(char *str, struct pt_regs *regs) { static int die_counter; int count = 0; diff --git a/arch/sparc/kernel/unaligned_32.c b/arch/sparc/kernel/unaligned_32.c index c0ec897861934f..c5c61b3c6b56f3 100644 --- a/arch/sparc/kernel/unaligned_32.c +++ b/arch/sparc/kernel/unaligned_32.c @@ -16,6 +16,10 @@ #include #include +#include + +#include "kernel.h" + enum direction { load, /* ld, ldd, ldh, ldsh */ store, /* st, std, sth, stsh */ diff --git a/arch/sparc/kernel/windows.c b/arch/sparc/kernel/windows.c index 3107381e576d6f..87bab0a3857a52 100644 --- a/arch/sparc/kernel/windows.c +++ b/arch/sparc/kernel/windows.c @@ -10,8 +10,11 @@ #include #include +#include #include +#include "kernel.h" + /* Do save's until all user register windows are out of the cpu. */ void flush_user_windows(void) { diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index dbe119b63b48ba..3269b0234093bf 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -41,7 +41,7 @@ lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o -obj-y += iomap.o +obj-$(CONFIG_SPARC64) += iomap.o obj-$(CONFIG_SPARC32) += atomic32.o ucmpdi2.o obj-y += ksyms.o obj-$(CONFIG_SPARC64) += PeeCeeI.o diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index 59dbd46457250b..908e8c17c902be 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c @@ -26,14 +26,14 @@ #include #include #include +#include #include #include #include -int show_unhandled_signals = 1; +#include "mm_32.h" -static void unhandled_fault(unsigned long, struct task_struct *, - struct pt_regs *) __attribute__ ((noreturn)); +int show_unhandled_signals = 1; static void __noreturn unhandled_fault(unsigned long address, struct task_struct *tsk, @@ -141,9 +141,6 @@ static void __do_fault_siginfo(int code, int sig, struct pt_regs *regs, force_sig_info (sig, &info, current); } -extern unsigned long safe_compute_effective_address(struct pt_regs *, - unsigned int); - static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault) { unsigned int insn; diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index a8ff0d1a3b6999..4ced3fc66130c3 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c @@ -281,18 +281,6 @@ static void noinline __kprobes bogus_32bit_fault_tpc(struct pt_regs *regs) show_regs(regs); } -static void noinline __kprobes bogus_32bit_fault_address(struct pt_regs *regs, - unsigned long addr) -{ - static int times; - - if (times++ < 10) - printk(KERN_ERR "FAULT[%s:%d]: 32-bit process " - "reports 64-bit fault address [%lx]\n", - current->comm, current->pid, addr); - show_regs(regs); -} - asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) { enum ctx_state prev_state = exception_enter(); @@ -322,10 +310,8 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) goto intr_or_no_mm; } } - if (unlikely((address >> 32) != 0)) { - bogus_32bit_fault_address(regs, address); + if (unlikely((address >> 32) != 0)) goto intr_or_no_mm; - } } if (regs->tstate & TSTATE_PRIV) { diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c index db69870828058d..eb828715527971 100644 --- a/arch/sparc/mm/init_32.c +++ b/arch/sparc/mm/init_32.c @@ -31,10 +31,13 @@ #include #include #include /* bug in asm-generic/tlb.h: check_pgt_cache */ +#include #include #include #include +#include "mm_32.h" + unsigned long *sparc_valid_addr_bitmap; EXPORT_SYMBOL(sparc_valid_addr_bitmap); @@ -63,7 +66,6 @@ void show_mem(unsigned int filter) } -extern unsigned long cmdline_memory_size; unsigned long last_valid_pfn; unsigned long calc_highpages(void) @@ -246,9 +248,6 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) * init routine based upon the Sun model type on the Sparc. * */ -extern void srmmu_paging_init(void); -extern void device_scan(void); - void __init paging_init(void) { srmmu_paging_init(); diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index 28f96f27c7683e..35384cb60b2101 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -27,6 +27,8 @@ #include #include +#include "mm_32.h" + /* * This can be sized dynamically, but we will do this * only when we have a guidance about actual I/O pressures. @@ -37,9 +39,6 @@ #define IOMMU_NPTES (IOMMU_WINSIZE/PAGE_SIZE) /* 64K PTEs, 256KB */ #define IOMMU_ORDER 6 /* 4096 * (1<<6) */ -/* srmmu.c */ -extern int viking_mxcc_present; -extern int flush_page_for_dma_global; static int viking_flush; /* viking.S */ extern void viking_flush_page(unsigned long page); diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c index 5bed085a2c1798..3b17b6f7895ac4 100644 --- a/arch/sparc/mm/leon_mm.c +++ b/arch/sparc/mm/leon_mm.c @@ -15,10 +15,10 @@ #include #include -#include "srmmu.h" +#include "mm_32.h" int leon_flush_during_switch = 1; -int srmmu_swprobe_trace; +static int srmmu_swprobe_trace; static inline unsigned long leon_get_ctable_ptr(void) { diff --git a/arch/sparc/mm/mm_32.h b/arch/sparc/mm/mm_32.h new file mode 100644 index 00000000000000..a6c27ca9a72197 --- /dev/null +++ b/arch/sparc/mm/mm_32.h @@ -0,0 +1,24 @@ +/* fault_32.c - visible as they are called from assembler */ +asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, + unsigned long address); +asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, + unsigned long address); + +void window_overflow_fault(void); +void window_underflow_fault(unsigned long sp); +void window_ret_fault(struct pt_regs *regs); + +/* srmmu.c */ +extern char *srmmu_name; +extern int viking_mxcc_present; +extern int flush_page_for_dma_global; + +extern void (*poke_srmmu)(void); + +void __init srmmu_paging_init(void); + +/* iommu.c */ +void ld_mmu_iommu(void); + +/* io-unit.c */ +void ld_mmu_iounit(void); diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index cfbe53c17b0dbb..be65f035d18a11 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -49,7 +49,7 @@ #include #include -#include "srmmu.h" +#include "mm_32.h" enum mbus_module srmmu_modtype; static unsigned int hwbug_bitmask; @@ -100,7 +100,6 @@ static unsigned long srmmu_nocache_end; #define SRMMU_NOCACHE_ALIGN_MAX (sizeof(ctxd_t)*SRMMU_MAX_CONTEXTS) void *srmmu_nocache_pool; -void *srmmu_nocache_bitmap; static struct bit_map srmmu_nocache_map; static inline int srmmu_pmd_none(pmd_t pmd) @@ -173,7 +172,7 @@ static void *__srmmu_get_nocache(int size, int align) printk(KERN_ERR "srmmu: out of nocache %d: %d/%d\n", size, (int) srmmu_nocache_size, srmmu_nocache_map.used << SRMMU_NOCACHE_BITMAP_SHIFT); - return 0; + return NULL; } addr = SRMMU_NOCACHE_VADDR + (offset << SRMMU_NOCACHE_BITMAP_SHIFT); @@ -269,6 +268,7 @@ static void __init srmmu_nocache_calcsize(void) static void __init srmmu_nocache_init(void) { + void *srmmu_nocache_bitmap; unsigned int bitmap_bits; pgd_t *pgd; pmd_t *pmd; @@ -728,7 +728,7 @@ static inline unsigned long srmmu_probe(unsigned long vaddr) "=r" (retval) : "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE)); } else { - retval = leon_swprobe(vaddr, 0); + retval = leon_swprobe(vaddr, NULL); } return retval; } @@ -865,8 +865,6 @@ static void __init map_kernel(void) void (*poke_srmmu)(void) = NULL; -extern unsigned long bootmem_init(unsigned long *pages_avail); - void __init srmmu_paging_init(void) { int i; @@ -1771,9 +1769,6 @@ static struct sparc32_cachetlb_ops smp_cachetlb_ops = { /* Load up routines and constants for sun4m and sun4d mmu */ void __init load_mmu(void) { - extern void ld_mmu_iommu(void); - extern void ld_mmu_iounit(void); - /* Functions */ get_srmmu_type(); diff --git a/arch/sparc/mm/srmmu.h b/arch/sparc/mm/srmmu.h deleted file mode 100644 index 5703274ccf89ed..00000000000000 --- a/arch/sparc/mm/srmmu.h +++ /dev/null @@ -1,4 +0,0 @@ -/* srmmu.c */ -extern char *srmmu_name; - -extern void (*poke_srmmu)(void); diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h index 1ad4a1f7d42b8a..1b109fad9fff3c 100644 --- a/arch/tile/include/asm/atomic_32.h +++ b/arch/tile/include/asm/atomic_32.h @@ -169,16 +169,6 @@ static inline void atomic64_set(atomic64_t *v, long long n) #define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) -/* - * We need to barrier before modifying the word, since the _atomic_xxx() - * routines just tns the lock and then read/modify/write of the word. - * But after the word is updated, the routine issues an "mf" before returning, - * and since it's a function call, we don't even need a compiler barrier. - */ -#define smp_mb__before_atomic_dec() smp_mb() -#define smp_mb__before_atomic_inc() smp_mb() -#define smp_mb__after_atomic_dec() do { } while (0) -#define smp_mb__after_atomic_inc() do { } while (0) #endif /* !__ASSEMBLY__ */ diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h index ad220eed05fc17..7b11c5fadd4220 100644 --- a/arch/tile/include/asm/atomic_64.h +++ b/arch/tile/include/asm/atomic_64.h @@ -105,12 +105,6 @@ static inline long atomic64_add_unless(atomic64_t *v, long a, long u) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) -/* Atomic dec and inc don't implement barrier, so provide them if needed. */ -#define smp_mb__before_atomic_dec() smp_mb() -#define smp_mb__after_atomic_dec() smp_mb() -#define smp_mb__before_atomic_inc() smp_mb() -#define smp_mb__after_atomic_inc() smp_mb() - /* Define this to indicate that cmpxchg is an efficient operation. */ #define __HAVE_ARCH_CMPXCHG diff --git a/arch/tile/include/asm/barrier.h b/arch/tile/include/asm/barrier.h index b5a05d050a8f6d..96a42ae79f4dd6 100644 --- a/arch/tile/include/asm/barrier.h +++ b/arch/tile/include/asm/barrier.h @@ -72,6 +72,20 @@ mb_incoherent(void) #define mb() fast_mb() #define iob() fast_iob() +#ifndef __tilegx__ /* 32 bit */ +/* + * We need to barrier before modifying the word, since the _atomic_xxx() + * routines just tns the lock and then read/modify/write of the word. + * But after the word is updated, the routine issues an "mf" before returning, + * and since it's a function call, we don't even need a compiler barrier. + */ +#define smp_mb__before_atomic() smp_mb() +#define smp_mb__after_atomic() do { } while (0) +#else /* 64 bit */ +#define smp_mb__before_atomic() smp_mb() +#define smp_mb__after_atomic() smp_mb() +#endif + #include #endif /* !__ASSEMBLY__ */ diff --git a/arch/tile/include/asm/bitops.h b/arch/tile/include/asm/bitops.h index d5a206865036a6..20caa346ac0622 100644 --- a/arch/tile/include/asm/bitops.h +++ b/arch/tile/include/asm/bitops.h @@ -17,6 +17,7 @@ #define _ASM_TILE_BITOPS_H #include +#include #ifndef _LINUX_BITOPS_H #error only can be included directly diff --git a/arch/tile/include/asm/bitops_32.h b/arch/tile/include/asm/bitops_32.h index 386865ad2f55a4..bbf7b666f21df8 100644 --- a/arch/tile/include/asm/bitops_32.h +++ b/arch/tile/include/asm/bitops_32.h @@ -49,8 +49,8 @@ static inline void set_bit(unsigned nr, volatile unsigned long *addr) * restricted to acting on a single-word quantity. * * clear_bit() may not contain a memory barrier, so if it is used for - * locking purposes, you should call smp_mb__before_clear_bit() and/or - * smp_mb__after_clear_bit() to ensure changes are visible on other cpus. + * locking purposes, you should call smp_mb__before_atomic() and/or + * smp_mb__after_atomic() to ensure changes are visible on other cpus. */ static inline void clear_bit(unsigned nr, volatile unsigned long *addr) { @@ -121,10 +121,6 @@ static inline int test_and_change_bit(unsigned nr, return (_atomic_xor(addr, mask) & mask) != 0; } -/* See discussion at smp_mb__before_atomic_dec() in . */ -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() do {} while (0) - #include #endif /* _ASM_TILE_BITOPS_32_H */ diff --git a/arch/tile/include/asm/bitops_64.h b/arch/tile/include/asm/bitops_64.h index ad34cd0560857d..bb1a29221fcd85 100644 --- a/arch/tile/include/asm/bitops_64.h +++ b/arch/tile/include/asm/bitops_64.h @@ -32,10 +32,6 @@ static inline void clear_bit(unsigned nr, volatile unsigned long *addr) __insn_fetchand((void *)(addr + nr / BITS_PER_LONG), ~mask); } -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() - - static inline void change_bit(unsigned nr, volatile unsigned long *addr) { unsigned long mask = (1UL << (nr % BITS_PER_LONG)); diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h index 729aa107f64e63..d767ff9f59b9c1 100644 --- a/arch/tile/include/asm/thread_info.h +++ b/arch/tile/include/asm/thread_info.h @@ -129,6 +129,7 @@ extern void _cpu_idle(void); #define TIF_MEMDIE 7 /* OOM killer at work */ #define TIF_NOTIFY_RESUME 8 /* callback before returning to user */ #define TIF_SYSCALL_TRACEPOINT 9 /* syscall tracepoint instrumentation */ +#define TIF_POLLING_NRFLAG 10 /* idle is polling for TIF_NEED_RESCHED */ #define _TIF_SIGPENDING (1<addr, m->size, 0); + reserve_bootmem(m->addr, m->size, BOOTMEM_DEFAULT); } #ifdef CONFIG_BLK_DEV_INITRD @@ -715,7 +715,8 @@ static void __init setup_bootmem_allocator(void) #ifdef CONFIG_KEXEC if (crashk_res.start != crashk_res.end) - reserve_bootmem(crashk_res.start, resource_size(&crashk_res), 0); + reserve_bootmem(crashk_res.start, resource_size(&crashk_res), + BOOTMEM_DEFAULT); #endif } diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index 08eec0b691b061..d824528f6f62fb 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -174,7 +174,6 @@ extern unsigned long long os_makedev(unsigned major, unsigned minor); /* start_up.c */ extern void os_early_checks(void); -extern void can_do_skas(void); extern void os_check_bugs(void); extern void check_host_supports_tls(int *supports_tls, int *tls_min); @@ -187,7 +186,6 @@ extern int os_process_parent(int pid); extern void os_stop_process(int pid); extern void os_kill_process(int pid, int reap_child); extern void os_kill_ptraced_process(int pid, int reap_child); -extern long os_ptrace_ldt(long pid, long addr, long data); extern int os_getpid(void); extern int os_getpgrp(void); diff --git a/arch/um/include/shared/skas/proc_mm.h b/arch/um/include/shared/skas/proc_mm.h deleted file mode 100644 index 9028092096033d..00000000000000 --- a/arch/um/include/shared/skas/proc_mm.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SKAS_PROC_MM_H -#define __SKAS_PROC_MM_H - -#define MM_MMAP 54 -#define MM_MUNMAP 55 -#define MM_MPROTECT 56 -#define MM_COPY_SEGMENTS 57 - -struct mm_mmap { - unsigned long addr; - unsigned long len; - unsigned long prot; - unsigned long flags; - unsigned long fd; - unsigned long offset; -}; - -struct mm_munmap { - unsigned long addr; - unsigned long len; -}; - -struct mm_mprotect { - unsigned long addr; - unsigned long len; - unsigned int prot; -}; - -struct proc_mm_op { - int op; - union { - struct mm_mmap mmap; - struct mm_munmap munmap; - struct mm_mprotect mprotect; - int copy_segments; - } u; -}; - -#endif diff --git a/arch/um/include/shared/skas/skas.h b/arch/um/include/shared/skas/skas.h index c45df961c874dd..911f3c45ad1f89 100644 --- a/arch/um/include/shared/skas/skas.h +++ b/arch/um/include/shared/skas/skas.h @@ -9,13 +9,10 @@ #include extern int userspace_pid[]; -extern int proc_mm, ptrace_faultinfo, ptrace_ldt; -extern int skas_needs_stub; extern int user_thread(unsigned long stack, int flags); extern void new_thread_handler(void); extern void handle_syscall(struct uml_pt_regs *regs); -extern int new_mm(unsigned long stack); extern long execute_syscall_skas(void *r); extern unsigned long current_stub_stack(void); diff --git a/arch/um/include/shared/skas_ptrace.h b/arch/um/include/shared/skas_ptrace.h deleted file mode 100644 index 630a9c92b93c7b..00000000000000 --- a/arch/um/include/shared/skas_ptrace.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#ifndef __SKAS_PTRACE_H -#define __SKAS_PTRACE_H - -#define PTRACE_FAULTINFO 52 -#define PTRACE_SWITCH_MM 55 - -#include - -#endif diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 694d551c88996d..174ee5017264b0 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -8,9 +8,6 @@ #include #include #include -#include - - void user_enable_single_step(struct task_struct *child) { @@ -104,35 +101,6 @@ long arch_ptrace(struct task_struct *child, long request, ret = ptrace_set_thread_area(child, addr, vp); break; - case PTRACE_FAULTINFO: { - /* - * Take the info from thread->arch->faultinfo, - * but transfer max. sizeof(struct ptrace_faultinfo). - * On i386, ptrace_faultinfo is smaller! - */ - ret = copy_to_user(p, &child->thread.arch.faultinfo, - sizeof(struct ptrace_faultinfo)) ? - -EIO : 0; - break; - } - -#ifdef PTRACE_LDT - case PTRACE_LDT: { - struct ptrace_ldt ldt; - - if (copy_from_user(&ldt, p, sizeof(ldt))) { - ret = -EIO; - break; - } - - /* - * This one is confusing, so just punt and return -EIO for - * now - */ - ret = -EIO; - break; - } -#endif default: ret = ptrace_request(child, request, addr, data); if (ret == -EIO) @@ -165,8 +133,7 @@ static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs, */ void syscall_trace_enter(struct pt_regs *regs) { - audit_syscall_entry(HOST_AUDIT_ARCH, - UPT_SYSCALL_NR(®s->regs), + audit_syscall_entry(UPT_SYSCALL_NR(®s->regs), UPT_SYSCALL_ARG1(®s->regs), UPT_SYSCALL_ARG2(®s->regs), UPT_SYSCALL_ARG3(®s->regs), diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index ced8903921aeb6..9bdf67a092a53b 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -15,28 +15,21 @@ void (*pm_power_off)(void); static void kill_off_processes(void) { - if (proc_mm) - /* - * FIXME: need to loop over userspace_pids - */ - os_kill_ptraced_process(userspace_pid[0], 1); - else { - struct task_struct *p; - int pid; - - read_lock(&tasklist_lock); - for_each_process(p) { - struct task_struct *t; - - t = find_lock_task_mm(p); - if (!t) - continue; - pid = t->mm->context.id.u.pid; - task_unlock(t); - os_kill_ptraced_process(pid, 1); - } - read_unlock(&tasklist_lock); + struct task_struct *p; + int pid; + + read_lock(&tasklist_lock); + for_each_process(p) { + struct task_struct *t; + + t = find_lock_task_mm(p); + if (!t) + continue; + pid = t->mm->context.id.u.pid; + task_unlock(t); + os_kill_ptraced_process(pid, 1); } + read_unlock(&tasklist_lock); } void uml_cleanup(void) diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 007d5503f49b79..94abdcc1d6ad19 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -54,35 +54,22 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) unsigned long stack = 0; int ret = -ENOMEM; - if (skas_needs_stub) { - stack = get_zeroed_page(GFP_KERNEL); - if (stack == 0) - goto out; - } + stack = get_zeroed_page(GFP_KERNEL); + if (stack == 0) + goto out; to_mm->id.stack = stack; if (current->mm != NULL && current->mm != &init_mm) from_mm = ¤t->mm->context; - if (proc_mm) { - ret = new_mm(stack); - if (ret < 0) { - printk(KERN_ERR "init_new_context_skas - " - "new_mm failed, errno = %d\n", ret); - goto out_free; - } - to_mm->id.u.mm_fd = ret; - } - else { - if (from_mm) - to_mm->id.u.pid = copy_context_skas0(stack, - from_mm->id.u.pid); - else to_mm->id.u.pid = start_userspace(stack); - - if (to_mm->id.u.pid < 0) { - ret = to_mm->id.u.pid; - goto out_free; - } + if (from_mm) + to_mm->id.u.pid = copy_context_skas0(stack, + from_mm->id.u.pid); + else to_mm->id.u.pid = start_userspace(stack); + + if (to_mm->id.u.pid < 0) { + ret = to_mm->id.u.pid; + goto out_free; } ret = init_new_ldt(to_mm, from_mm); @@ -105,9 +92,6 @@ void uml_setup_stubs(struct mm_struct *mm) { int err, ret; - if (!skas_needs_stub) - return; - ret = init_stub_pte(mm, STUB_CODE, (unsigned long) &__syscall_stub_start); if (ret) @@ -154,25 +138,19 @@ void destroy_context(struct mm_struct *mm) { struct mm_context *mmu = &mm->context; - if (proc_mm) - os_close_file(mmu->id.u.mm_fd); - else { - /* - * If init_new_context wasn't called, this will be - * zero, resulting in a kill(0), which will result in the - * whole UML suddenly dying. Also, cover negative and - * 1 cases, since they shouldn't happen either. - */ - if (mmu->id.u.pid < 2) { - printk(KERN_ERR "corrupt mm_context - pid = %d\n", - mmu->id.u.pid); - return; - } - os_kill_ptraced_process(mmu->id.u.pid, 1); + /* + * If init_new_context wasn't called, this will be + * zero, resulting in a kill(0), which will result in the + * whole UML suddenly dying. Also, cover negative and + * 1 cases, since they shouldn't happen either. + */ + if (mmu->id.u.pid < 2) { + printk(KERN_ERR "corrupt mm_context - pid = %d\n", + mmu->id.u.pid); + return; } + os_kill_ptraced_process(mmu->id.u.pid, 1); - if (skas_needs_stub) - free_page(mmu->id.stack); - + free_page(mmu->id.stack); free_ldt(mmu); } diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 4da11b3c8ddbc3..082955d694f38b 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -10,25 +10,6 @@ #include #include -int new_mm(unsigned long stack) -{ - int fd, err; - - fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); - if (fd < 0) - return fd; - - if (skas_needs_stub) { - err = map_stub_pages(fd, STUB_CODE, STUB_DATA, stack); - if (err) { - os_close_file(fd); - return err; - } - } - - return fd; -} - extern void start_kernel(void); static int __init start_kernel_proc(void *unused) @@ -55,14 +36,6 @@ int __init start_uml(void) { stack_protections((unsigned long) &cpu0_irqstack); set_sigstack(cpu0_irqstack, THREAD_SIZE); - if (proc_mm) { - userspace_pid[0] = start_userspace(0); - if (userspace_pid[0] < 0) { - printf("start_uml - start_userspace returned %d\n", - userspace_pid[0]); - exit(1); - } - } init_new_thread_signals(); diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 974b87474a9900..4a6235b758e671 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -218,7 +218,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, panic("Segfault with no mm"); } - if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi)) + if (SEGV_IS_FIXABLE(&fi)) err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); else { diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 016adf0985d522..6043c767d37852 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -268,7 +268,6 @@ int __init linux_main(int argc, char **argv) unsigned long stack; unsigned int i; int add; - char * mode; for (i = 1; i < argc; i++) { if ((i == 1) && (argv[i][0] == ' ')) @@ -291,15 +290,6 @@ int __init linux_main(int argc, char **argv) /* OS sanity checks that need to happen before the kernel runs */ os_early_checks(); - can_do_skas(); - - if (proc_mm && ptrace_faultinfo) - mode = "SKAS3"; - else - mode = "SKAS0"; - - printf("UML running in %s mode\n", mode); - brk_start = (unsigned long) sbrk(0); /* diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 33496fe2bb52f4..8408aba915b29f 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -16,7 +16,6 @@ #include #include #include -#include #define ARBITRARY_ADDR -1 #define FAILURE_PID -1 @@ -102,21 +101,6 @@ void os_kill_process(int pid, int reap_child) CATCH_EINTR(waitpid(pid, NULL, __WALL)); } -/* This is here uniquely to have access to the userspace errno, i.e. the one - * used by ptrace in case of error. - */ - -long os_ptrace_ldt(long pid, long addr, long data) -{ - int ret; - - ret = ptrace(PTRACE_LDT, pid, addr, data); - - if (ret < 0) - return -errno; - return ret; -} - /* Kill off a ptraced child by all means available. kill it normally first, * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from * which it can't exit directly. diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c index 689b18db798ffb..e7f8c945a573ac 100644 --- a/arch/um/os-Linux/skas/mem.c +++ b/arch/um/os-Linux/skas/mem.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -46,8 +45,6 @@ static int __init init_syscall_regs(void) __initcall(init_syscall_regs); -extern int proc_mm; - static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) { int n, i; @@ -56,10 +53,6 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) unsigned long * syscall; int err, pid = mm_idp->u.pid; - if (proc_mm) - /* FIXME: Need to look up userspace_pid by cpu */ - pid = userspace_pid[0]; - n = ptrace_setregs(pid, syscall_regs); if (n < 0) { printk(UM_KERN_ERR "Registers - \n"); @@ -178,38 +171,12 @@ int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot, int phys_fd, unsigned long long offset, int done, void **data) { int ret; + unsigned long args[] = { virt, len, prot, + MAP_SHARED | MAP_FIXED, phys_fd, + MMAP_OFFSET(offset) }; - if (proc_mm) { - struct proc_mm_op map; - int fd = mm_idp->u.mm_fd; - - map = ((struct proc_mm_op) { .op = MM_MMAP, - .u = - { .mmap = - { .addr = virt, - .len = len, - .prot = prot, - .flags = MAP_SHARED | - MAP_FIXED, - .fd = phys_fd, - .offset= offset - } } } ); - CATCH_EINTR(ret = write(fd, &map, sizeof(map))); - if (ret != sizeof(map)) { - ret = -errno; - printk(UM_KERN_ERR "map : /proc/mm map failed, " - "err = %d\n", -ret); - } - else ret = 0; - } - else { - unsigned long args[] = { virt, len, prot, - MAP_SHARED | MAP_FIXED, phys_fd, - MMAP_OFFSET(offset) }; - - ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, - data, done); - } + ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, + data, done); return ret; } @@ -218,32 +185,11 @@ int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, int done, void **data) { int ret; + unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, + 0 }; - if (proc_mm) { - struct proc_mm_op unmap; - int fd = mm_idp->u.mm_fd; - - unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, - .u = - { .munmap = - { .addr = - (unsigned long) addr, - .len = len } } } ); - CATCH_EINTR(ret = write(fd, &unmap, sizeof(unmap))); - if (ret != sizeof(unmap)) { - ret = -errno; - printk(UM_KERN_ERR "unmap - proc_mm write returned " - "%d\n", ret); - } - else ret = 0; - } - else { - unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, - 0 }; - - ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, - data, done); - } + ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, + data, done); return ret; } @@ -251,33 +197,11 @@ int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, unsigned int prot, int done, void **data) { - struct proc_mm_op protect; int ret; + unsigned long args[] = { addr, len, prot, 0, 0, 0 }; - if (proc_mm) { - int fd = mm_idp->u.mm_fd; - - protect = ((struct proc_mm_op) { .op = MM_MPROTECT, - .u = - { .mprotect = - { .addr = - (unsigned long) addr, - .len = len, - .prot = prot } } } ); - - CATCH_EINTR(ret = write(fd, &protect, sizeof(protect))); - if (ret != sizeof(protect)) { - ret = -errno; - printk(UM_KERN_ERR "protect failed, err = %d", -ret); - } - else ret = 0; - } - else { - unsigned long args[] = { addr, len, prot, 0, 0, 0 }; - - ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, - data, done); - } + ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, + data, done); return ret; } diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index d531879a461769..452c214d86bf39 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -16,11 +16,9 @@ #include #include #include -#include #include #include #include -#include #include int is_skas_winch(int pid, int fd, void *data) @@ -96,50 +94,33 @@ extern unsigned long current_stub_stack(void); static void get_skas_faultinfo(int pid, struct faultinfo *fi) { int err; + unsigned long fpregs[FP_SIZE]; - if (ptrace_faultinfo) { - err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); - if (err) { - printk(UM_KERN_ERR "get_skas_faultinfo - " - "PTRACE_FAULTINFO failed, errno = %d\n", errno); - fatal_sigsegv(); - } - - /* Special handling for i386, which has different structs */ - if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) - memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, - sizeof(struct faultinfo) - - sizeof(struct ptrace_faultinfo)); + err = get_fp_registers(pid, fpregs); + if (err < 0) { + printk(UM_KERN_ERR "save_fp_registers returned %d\n", + err); + fatal_sigsegv(); } - else { - unsigned long fpregs[FP_SIZE]; - - err = get_fp_registers(pid, fpregs); - if (err < 0) { - printk(UM_KERN_ERR "save_fp_registers returned %d\n", - err); - fatal_sigsegv(); - } - err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV); - if (err) { - printk(UM_KERN_ERR "Failed to continue stub, pid = %d, " - "errno = %d\n", pid, errno); - fatal_sigsegv(); - } - wait_stub_done(pid); + err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV); + if (err) { + printk(UM_KERN_ERR "Failed to continue stub, pid = %d, " + "errno = %d\n", pid, errno); + fatal_sigsegv(); + } + wait_stub_done(pid); - /* - * faultinfo is prepared by the stub-segv-handler at start of - * the stub stack page. We just have to copy it. - */ - memcpy(fi, (void *)current_stub_stack(), sizeof(*fi)); + /* + * faultinfo is prepared by the stub-segv-handler at start of + * the stub stack page. We just have to copy it. + */ + memcpy(fi, (void *)current_stub_stack(), sizeof(*fi)); - err = put_fp_registers(pid, fpregs); - if (err < 0) { - printk(UM_KERN_ERR "put_fp_registers returned %d\n", - err); - fatal_sigsegv(); - } + err = put_fp_registers(pid, fpregs); + if (err < 0) { + printk(UM_KERN_ERR "put_fp_registers returned %d\n", + err); + fatal_sigsegv(); } } @@ -203,7 +184,8 @@ extern int __syscall_stub_start; static int userspace_tramp(void *stack) { void *addr; - int err; + int err, fd; + unsigned long long offset; ptrace(PTRACE_TRACEME, 0, 0, 0); @@ -216,36 +198,32 @@ static int userspace_tramp(void *stack) exit(1); } - if (!proc_mm) { - /* - * This has a pte, but it can't be mapped in with the usual - * tlb_flush mechanism because this is part of that mechanism - */ - int fd; - unsigned long long offset; - fd = phys_mapping(to_phys(&__syscall_stub_start), &offset); - addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE, - PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); + /* + * This has a pte, but it can't be mapped in with the usual + * tlb_flush mechanism because this is part of that mechanism + */ + fd = phys_mapping(to_phys(&__syscall_stub_start), &offset); + addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE, + PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); + if (addr == MAP_FAILED) { + printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, " + "errno = %d\n", STUB_CODE, errno); + exit(1); + } + + if (stack != NULL) { + fd = phys_mapping(to_phys(stack), &offset); + addr = mmap((void *) STUB_DATA, + UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED, fd, offset); if (addr == MAP_FAILED) { - printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, " - "errno = %d\n", STUB_CODE, errno); + printk(UM_KERN_ERR "mapping segfault stack " + "at 0x%lx failed, errno = %d\n", + STUB_DATA, errno); exit(1); } - - if (stack != NULL) { - fd = phys_mapping(to_phys(stack), &offset); - addr = mmap((void *) STUB_DATA, - UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_SHARED, fd, offset); - if (addr == MAP_FAILED) { - printk(UM_KERN_ERR "mapping segfault stack " - "at 0x%lx failed, errno = %d\n", - STUB_DATA, errno); - exit(1); - } - } } - if (!ptrace_faultinfo && (stack != NULL)) { + if (stack != NULL) { struct sigaction sa; unsigned long v = STUB_CODE + @@ -291,11 +269,7 @@ int start_userspace(unsigned long stub_stack) sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *); - flags = CLONE_FILES; - if (proc_mm) - flags |= CLONE_VM; - else - flags |= SIGCHLD; + flags = CLONE_FILES | SIGCHLD; pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack); if (pid < 0) { @@ -418,8 +392,7 @@ void userspace(struct uml_pt_regs *regs) switch (sig) { case SIGSEGV: - if (PTRACE_FULL_FAULTINFO || - !ptrace_faultinfo) { + if (PTRACE_FULL_FAULTINFO) { get_skas_faultinfo(pid, ®s->faultinfo); (*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si, @@ -576,67 +549,6 @@ int copy_context_skas0(unsigned long new_stack, int pid) return err; } -/* - * This is used only, if stub pages are needed, while proc_mm is - * available. Opening /proc/mm creates a new mm_context, which lacks - * the stub-pages. Thus, we map them using /proc/mm-fd - */ -int map_stub_pages(int fd, unsigned long code, unsigned long data, - unsigned long stack) -{ - struct proc_mm_op mmop; - int n; - unsigned long long code_offset; - int code_fd = phys_mapping(to_phys((void *) &__syscall_stub_start), - &code_offset); - - mmop = ((struct proc_mm_op) { .op = MM_MMAP, - .u = - { .mmap = - { .addr = code, - .len = UM_KERN_PAGE_SIZE, - .prot = PROT_EXEC, - .flags = MAP_FIXED | MAP_PRIVATE, - .fd = code_fd, - .offset = code_offset - } } }); - CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop))); - if (n != sizeof(mmop)) { - n = errno; - printk(UM_KERN_ERR "mmap args - addr = 0x%lx, fd = %d, " - "offset = %llx\n", code, code_fd, - (unsigned long long) code_offset); - printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for code " - "failed, err = %d\n", n); - return -n; - } - - if (stack) { - unsigned long long map_offset; - int map_fd = phys_mapping(to_phys((void *)stack), &map_offset); - mmop = ((struct proc_mm_op) - { .op = MM_MMAP, - .u = - { .mmap = - { .addr = data, - .len = UM_KERN_PAGE_SIZE, - .prot = PROT_READ | PROT_WRITE, - .flags = MAP_FIXED | MAP_SHARED, - .fd = map_fd, - .offset = map_offset - } } }); - CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop))); - if (n != sizeof(mmop)) { - n = errno; - printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for " - "data failed, err = %d\n", n); - return -n; - } - } - - return 0; -} - void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) { (*buf)[0].JB_IP = (unsigned long) handler; @@ -733,17 +645,5 @@ void reboot_skas(void) void __switch_mm(struct mm_id *mm_idp) { - int err; - - /* FIXME: need cpu pid in __switch_mm */ - if (proc_mm) { - err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, - mm_idp->u.mm_fd); - if (err) { - printk(UM_KERN_ERR "__switch_mm - PTRACE_SWITCH_MM " - "failed, errno = %d\n", errno); - fatal_sigsegv(); - } - } - else userspace_pid[0] = mm_idp->u.pid; + userspace_pid[0] = mm_idp->u.pid; } diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 337518c5042a5c..47f1ff056a54fd 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -24,7 +24,6 @@ #include #include #include -#include static void ptrace_child(void) { @@ -142,44 +141,6 @@ static int stop_ptraced_child(int pid, int exitcode, int mustexit) return ret; } -/* Changed only during early boot */ -int ptrace_faultinfo; -static int disable_ptrace_faultinfo; - -int ptrace_ldt; -static int disable_ptrace_ldt; - -int proc_mm; -static int disable_proc_mm; - -int have_switch_mm; -static int disable_switch_mm; - -int skas_needs_stub; - -static int __init skas0_cmd_param(char *str, int* add) -{ - disable_ptrace_faultinfo = 1; - disable_ptrace_ldt = 1; - disable_proc_mm = 1; - disable_switch_mm = 1; - - return 0; -} - -/* The two __uml_setup would conflict, without this stupid alias. */ - -static int __init mode_skas0_cmd_param(char *str, int* add) - __attribute__((alias("skas0_cmd_param"))); - -__uml_setup("skas0", skas0_cmd_param, -"skas0\n" -" Disables SKAS3 and SKAS4 usage, so that SKAS0 is used\n\n"); - -__uml_setup("mode=skas0", mode_skas0_cmd_param, -"mode=skas0\n" -" Disables SKAS3 and SKAS4 usage, so that SKAS0 is used.\n\n"); - /* Changed only during early boot */ static int force_sysemu_disabled = 0; @@ -376,121 +337,6 @@ void __init os_early_checks(void) stop_ptraced_child(pid, 1, 1); } -static int __init noprocmm_cmd_param(char *str, int* add) -{ - disable_proc_mm = 1; - return 0; -} - -__uml_setup("noprocmm", noprocmm_cmd_param, -"noprocmm\n" -" Turns off usage of /proc/mm, even if host supports it.\n" -" To support /proc/mm, the host needs to be patched using\n" -" the current skas3 patch.\n\n"); - -static int __init noptracefaultinfo_cmd_param(char *str, int* add) -{ - disable_ptrace_faultinfo = 1; - return 0; -} - -__uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param, -"noptracefaultinfo\n" -" Turns off usage of PTRACE_FAULTINFO, even if host supports\n" -" it. To support PTRACE_FAULTINFO, the host needs to be patched\n" -" using the current skas3 patch.\n\n"); - -static int __init noptraceldt_cmd_param(char *str, int* add) -{ - disable_ptrace_ldt = 1; - return 0; -} - -__uml_setup("noptraceldt", noptraceldt_cmd_param, -"noptraceldt\n" -" Turns off usage of PTRACE_LDT, even if host supports it.\n" -" To support PTRACE_LDT, the host needs to be patched using\n" -" the current skas3 patch.\n\n"); - -static inline void check_skas3_ptrace_faultinfo(void) -{ - struct ptrace_faultinfo fi; - int pid, n; - - non_fatal(" - PTRACE_FAULTINFO..."); - pid = start_ptraced_child(); - - n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); - if (n < 0) { - if (errno == EIO) - non_fatal("not found\n"); - else - perror("not found"); - } else if (disable_ptrace_faultinfo) - non_fatal("found but disabled on command line\n"); - else { - ptrace_faultinfo = 1; - non_fatal("found\n"); - } - - stop_ptraced_child(pid, 1, 1); -} - -static inline void check_skas3_ptrace_ldt(void) -{ -#ifdef PTRACE_LDT - int pid, n; - unsigned char ldtbuf[40]; - struct ptrace_ldt ldt_op = (struct ptrace_ldt) { - .func = 2, /* read default ldt */ - .ptr = ldtbuf, - .bytecount = sizeof(ldtbuf)}; - - non_fatal(" - PTRACE_LDT..."); - pid = start_ptraced_child(); - - n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op); - if (n < 0) { - if (errno == EIO) - non_fatal("not found\n"); - else - perror("not found"); - } else if (disable_ptrace_ldt) - non_fatal("found, but use is disabled\n"); - else { - ptrace_ldt = 1; - non_fatal("found\n"); - } - - stop_ptraced_child(pid, 1, 1); -#endif -} - -static inline void check_skas3_proc_mm(void) -{ - non_fatal(" - /proc/mm..."); - if (access("/proc/mm", W_OK) < 0) - perror("not found"); - else if (disable_proc_mm) - non_fatal("found but disabled on command line\n"); - else { - proc_mm = 1; - non_fatal("found\n"); - } -} - -void can_do_skas(void) -{ - non_fatal("Checking for the skas3 patch in the host:\n"); - - check_skas3_proc_mm(); - check_skas3_ptrace_faultinfo(); - check_skas3_ptrace_ldt(); - - if (!proc_mm || !ptrace_faultinfo || !ptrace_ldt) - skas_needs_stub = 1; -} - int __init parse_iomem(char *str, int *add) { struct iomem_region *new; diff --git a/arch/um/sys-ia64/sysdep/skas_ptrace.h b/arch/um/sys-ia64/sysdep/skas_ptrace.h deleted file mode 100644 index 25a38e7157029b..00000000000000 --- a/arch/um/sys-ia64/sysdep/skas_ptrace.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_IA64_SKAS_PTRACE_H -#define __SYSDEP_IA64_SKAS_PTRACE_H - -struct ptrace_faultinfo { - int is_write; - unsigned long addr; -}; - -struct ptrace_ldt { - int func; - void *ptr; - unsigned long bytecount; -}; - -#define PTRACE_LDT 54 - -#endif diff --git a/arch/um/sys-ppc/shared/sysdep/skas_ptrace.h b/arch/um/sys-ppc/shared/sysdep/skas_ptrace.h deleted file mode 100644 index d9fbbac10de0c0..00000000000000 --- a/arch/um/sys-ppc/shared/sysdep/skas_ptrace.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_PPC_SKAS_PTRACE_H -#define __SYSDEP_PPC_SKAS_PTRACE_H - -struct ptrace_faultinfo { - int is_write; - unsigned long addr; -}; - -struct ptrace_ldt { - int func; - void *ptr; - unsigned long bytecount; -}; - -#define PTRACE_LDT 54 - -#endif diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 06a09d968b3b82..f40d52eea2a2e2 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -262,6 +262,9 @@ config ARCH_HWEIGHT_CFLAGS config ARCH_SUPPORTS_UPROBES def_bool y +config FIX_EARLYCON_MEM + def_bool y + source "init/Kconfig" source "kernel/Kconfig.freezer" @@ -534,7 +537,7 @@ config X86_32_IRIS config SCHED_OMIT_FRAME_POINTER def_bool y - prompt "Single-depth WCHAN output" + prompt "Single-depth WCHAN output" if !LTO && !FRAME_POINTER depends on X86 ---help--- Calculate simpler /proc//wchan values. If this option @@ -910,10 +913,27 @@ config VM86 default y depends on X86_32 ---help--- - This option is required by programs like DOSEMU to run 16-bit legacy - code on X86 processors. It also may be needed by software like - XFree86 to initialize some video cards via BIOS. Disabling this - option saves about 6k. + This option is required by programs like DOSEMU to run + 16-bit real mode legacy code on x86 processors. It also may + be needed by software like XFree86 to initialize some video + cards via BIOS. Disabling this option saves about 6K. + +config X86_16BIT + bool "Enable support for 16-bit segments" if EXPERT + default y + ---help--- + This option is required by programs like Wine to run 16-bit + protected mode legacy code on x86 processors. Disabling + this option saves about 300 bytes on i386, or around 6K text + plus 16K runtime memory on x86-64, + +config X86_ESPFIX32 + def_bool y + depends on X86_16BIT && X86_32 + +config X86_ESPFIX64 + def_bool y + depends on X86_16BIT && X86_64 config TOSHIBA tristate "Toshiba Laptop support" diff --git a/arch/x86/Makefile b/arch/x86/Makefile index ce6ad7e6a7d7c7..33f71b01fd22e7 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -79,6 +79,7 @@ else UTS_MACHINE := x86_64 CHECKFLAGS += -D__x86_64__ -m64 + biarch := -m64 KBUILD_AFLAGS += -m64 KBUILD_CFLAGS += -m64 diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index abb9eba61b5001..dbe8dd2fe247fb 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -71,7 +71,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE SETUP_OBJS = $(addprefix $(obj)/,$(setup-y)) -sed-voffset := -e 's/^\([0-9a-fA-F]*\) . \(_text\|_end\)$$/\#define VO_\2 0x\1/p' +sed-voffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(_text\|_end\)$$/\#define VO_\2 0x\1/p' quiet_cmd_voffset = VOFFSET $@ cmd_voffset = $(NM) $< | sed -n $(sed-voffset) > $@ @@ -80,7 +80,7 @@ targets += voffset.h $(obj)/voffset.h: vmlinux FORCE $(call if_changed,voffset) -sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p' +sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p' quiet_cmd_zoffset = ZOFFSET $@ cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@ diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 4703a6c4b8e315..0331d765c2bb71 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -1087,8 +1087,7 @@ struct boot_params *make_boot_params(struct efi_config *c) hdr->type_of_loader = 0x21; /* Convert unicode cmdline to ascii */ - cmdline_ptr = efi_convert_cmdline_to_ascii(sys_table, image, - &options_size); + cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size); if (!cmdline_ptr) goto fail; hdr->cmd_line_ptr = (unsigned long)cmdline_ptr; diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 0d558ee899aec8..2884e0c3e8a588 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -452,7 +452,7 @@ efi32_config: .global efi64_config efi64_config: .fill 11,8,0 - .quad efi_call6 + .quad efi_call .byte 1 #endif /* CONFIG_EFI_STUB */ diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 17684615374b26..57ab74df7eeaa3 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -354,7 +354,7 @@ static void parse_elf(void *output) free(phdrs); } -asmlinkage void *decompress_kernel(void *rmode, memptr heap, +asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap, unsigned char *input_data, unsigned long input_len, unsigned char *output, diff --git a/arch/x86/crypto/ghash-clmulni-intel_asm.S b/arch/x86/crypto/ghash-clmulni-intel_asm.S index 185fad49d86f0c..5d1e0075ac24fa 100644 --- a/arch/x86/crypto/ghash-clmulni-intel_asm.S +++ b/arch/x86/crypto/ghash-clmulni-intel_asm.S @@ -92,7 +92,7 @@ __clmul_gf128mul_ble: ret ENDPROC(__clmul_gf128mul_ble) -/* void clmul_ghash_mul(char *dst, const be128 *shash) */ +/* void clmul_ghash_mul(char *dst, const u128 *shash) */ ENTRY(clmul_ghash_mul) movups (%rdi), DATA movups (%rsi), SHASH @@ -106,7 +106,7 @@ ENDPROC(clmul_ghash_mul) /* * void clmul_ghash_update(char *dst, const char *src, unsigned int srclen, - * const be128 *shash); + * const u128 *shash); */ ENTRY(clmul_ghash_update) cmp $16, %rdx diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c index d785cf2c529c72..88bb7ba8b1753e 100644 --- a/arch/x86/crypto/ghash-clmulni-intel_glue.c +++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c @@ -25,17 +25,17 @@ #define GHASH_BLOCK_SIZE 16 #define GHASH_DIGEST_SIZE 16 -void clmul_ghash_mul(char *dst, const be128 *shash); +void clmul_ghash_mul(char *dst, const u128 *shash); void clmul_ghash_update(char *dst, const char *src, unsigned int srclen, - const be128 *shash); + const u128 *shash); struct ghash_async_ctx { struct cryptd_ahash *cryptd_tfm; }; struct ghash_ctx { - be128 shash; + u128 shash; }; struct ghash_desc_ctx { @@ -68,11 +68,11 @@ static int ghash_setkey(struct crypto_shash *tfm, a = be64_to_cpu(x->a); b = be64_to_cpu(x->b); - ctx->shash.a = (__be64)((b << 1) | (a >> 63)); - ctx->shash.b = (__be64)((a << 1) | (b >> 63)); + ctx->shash.a = (b << 1) | (a >> 63); + ctx->shash.b = (a << 1) | (b >> 63); if (a >> 63) - ctx->shash.b ^= cpu_to_be64(0xc2); + ctx->shash.b ^= ((u64)0xc2) << 56; return 0; } diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 220675795e08c9..f9e181aaba9791 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -383,8 +383,8 @@ int ia32_setup_frame(int sig, struct ksignal *ksig, } else { /* Return stub is in 32bit vsyscall page */ if (current->mm->context.vdso) - restorer = VDSO32_SYMBOL(current->mm->context.vdso, - sigreturn); + restorer = current->mm->context.vdso + + selected_vdso32->sym___kernel_sigreturn; else restorer = &frame->retcode; } @@ -462,8 +462,8 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig, if (ksig->ka.sa.sa_flags & SA_RESTORER) restorer = ksig->ka.sa.sa_restorer; else - restorer = VDSO32_SYMBOL(current->mm->context.vdso, - rt_sigreturn); + restorer = current->mm->context.vdso + + selected_vdso32->sym___kernel_rt_sigreturn; put_user_ex(ptr_to_compat(restorer), &frame->pretcode); /* diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 4299eb05023cf8..f5bdd288181564 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -186,12 +186,12 @@ sysexit_from_sys_call: #ifdef CONFIG_AUDITSYSCALL .macro auditsys_entry_common - movl %esi,%r9d /* 6th arg: 4th syscall arg */ - movl %edx,%r8d /* 5th arg: 3rd syscall arg */ - /* (already in %ecx) 4th arg: 2nd syscall arg */ - movl %ebx,%edx /* 3rd arg: 1st syscall arg */ - movl %eax,%esi /* 2nd arg: syscall number */ - movl $AUDIT_ARCH_I386,%edi /* 1st arg: audit arch */ + movl %esi,%r8d /* 5th arg: 4th syscall arg */ + movl %ecx,%r9d /*swap with edx*/ + movl %edx,%ecx /* 4th arg: 3rd syscall arg */ + movl %r9d,%edx /* 3rd arg: 2nd syscall arg */ + movl %ebx,%esi /* 2nd arg: 1st syscall arg */ + movl %eax,%edi /* 1st arg: syscall number */ call __audit_syscall_entry movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall number */ cmpq $(IA32_NR_syscalls-1),%rax diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index 4582e8e1cd1ad4..7730c1c5c83aa7 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -57,6 +57,12 @@ .long (from) - . ; \ .long (to) - . + 0x7ffffff0 ; \ .popsection + +# define _ASM_NOKPROBE(entry) \ + .pushsection "_kprobe_blacklist","aw" ; \ + _ASM_ALIGN ; \ + _ASM_PTR (entry); \ + .popsection #else # define _ASM_EXTABLE(from,to) \ " .pushsection \"__ex_table\",\"a\"\n" \ @@ -71,6 +77,7 @@ " .long (" #from ") - .\n" \ " .long (" #to ") - . + 0x7ffffff0\n" \ " .popsection\n" +/* For C file, we already have NOKPROBE_SYMBOL macro */ #endif #endif /* _ASM_X86_ASM_H */ diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index b17f4f48ecd7d9..6dd1c7dd0473ae 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -7,6 +7,7 @@ #include #include #include +#include /* * Atomic operations that C can't guarantee us. Useful for @@ -243,12 +244,6 @@ static inline void atomic_or_long(unsigned long *v1, unsigned long v2) : : "r" ((unsigned)(mask)), "m" (*(addr)) \ : "memory") -/* Atomic operations are already serializing on x86 */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #ifdef CONFIG_X86_32 # include #else diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h index 69bbb484502089..5c7198cca5edd1 100644 --- a/arch/x86/include/asm/barrier.h +++ b/arch/x86/include/asm/barrier.h @@ -137,6 +137,10 @@ do { \ #endif +/* Atomic operations are already serializing on x86 */ +#define smp_mb__before_atomic() barrier() +#define smp_mb__after_atomic() barrier() + /* * Stop RDTSC speculation. This is needed when you need to use RDTSC * (or get_cycles or vread that possibly accesses the TSC) in a defined diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index 9fc1af74dc8393..afcd35d331de63 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -15,6 +15,7 @@ #include #include #include +#include #if BITS_PER_LONG == 32 # define _BITOPS_LONG_SHIFT 5 @@ -102,7 +103,7 @@ static inline void __set_bit(long nr, volatile unsigned long *addr) * * clear_bit() is atomic and may not be reordered. However, it does * not contain a memory barrier, so if it is used for locking purposes, - * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic() * in order to ensure changes are visible on other processors. */ static __always_inline void @@ -156,9 +157,6 @@ static inline void __clear_bit_unlock(long nr, volatile unsigned long *addr) __clear_bit(nr, addr); } -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() - /** * __change_bit - Toggle a bit in memory * @nr: the bit to change diff --git a/arch/x86/include/asm/checksum_64.h b/arch/x86/include/asm/checksum_64.h index e6fd8a026c7be5..cd00e17744914c 100644 --- a/arch/x86/include/asm/checksum_64.h +++ b/arch/x86/include/asm/checksum_64.h @@ -184,8 +184,15 @@ static inline unsigned add32_with_carry(unsigned a, unsigned b) asm("addl %2,%0\n\t" "adcl $0,%0" : "=r" (a) - : "0" (a), "r" (b)); + : "0" (a), "rm" (b)); return a; } +#define HAVE_ARCH_CSUM_ADD +static inline __wsum csum_add(__wsum csum, __wsum addend) +{ + return (__force __wsum)add32_with_carry((__force unsigned)csum, + (__force unsigned)addend); +} + #endif /* _ASM_X86_CHECKSUM_64_H */ diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 0869434eaf725e..1eb5f6433ad8aa 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -1,6 +1,7 @@ #ifndef _ASM_X86_EFI_H #define _ASM_X86_EFI_H +#include /* * We map the EFI regions needed for runtime services non-contiguously, * with preserved alignment on virtual addresses starting from -4G down @@ -27,91 +28,58 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...); -#define efi_call_phys0(f) efi_call_phys(f) -#define efi_call_phys1(f, a1) efi_call_phys(f, a1) -#define efi_call_phys2(f, a1, a2) efi_call_phys(f, a1, a2) -#define efi_call_phys3(f, a1, a2, a3) efi_call_phys(f, a1, a2, a3) -#define efi_call_phys4(f, a1, a2, a3, a4) \ - efi_call_phys(f, a1, a2, a3, a4) -#define efi_call_phys5(f, a1, a2, a3, a4, a5) \ - efi_call_phys(f, a1, a2, a3, a4, a5) -#define efi_call_phys6(f, a1, a2, a3, a4, a5, a6) \ - efi_call_phys(f, a1, a2, a3, a4, a5, a6) /* * Wrap all the virtual calls in a way that forces the parameters on the stack. */ +/* Use this macro if your virtual returns a non-void value */ #define efi_call_virt(f, args...) \ - ((efi_##f##_t __attribute__((regparm(0)))*)efi.systab->runtime->f)(args) - -#define efi_call_virt0(f) efi_call_virt(f) -#define efi_call_virt1(f, a1) efi_call_virt(f, a1) -#define efi_call_virt2(f, a1, a2) efi_call_virt(f, a1, a2) -#define efi_call_virt3(f, a1, a2, a3) efi_call_virt(f, a1, a2, a3) -#define efi_call_virt4(f, a1, a2, a3, a4) \ - efi_call_virt(f, a1, a2, a3, a4) -#define efi_call_virt5(f, a1, a2, a3, a4, a5) \ - efi_call_virt(f, a1, a2, a3, a4, a5) -#define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \ - efi_call_virt(f, a1, a2, a3, a4, a5, a6) +({ \ + efi_status_t __s; \ + kernel_fpu_begin(); \ + __s = ((efi_##f##_t __attribute__((regparm(0)))*) \ + efi.systab->runtime->f)(args); \ + kernel_fpu_end(); \ + __s; \ +}) + +/* Use this macro if your virtual call does not return any value */ +#define __efi_call_virt(f, args...) \ +({ \ + kernel_fpu_begin(); \ + ((efi_##f##_t __attribute__((regparm(0)))*) \ + efi.systab->runtime->f)(args); \ + kernel_fpu_end(); \ +}) #define efi_ioremap(addr, size, type, attr) ioremap_cache(addr, size) #else /* !CONFIG_X86_32 */ -extern u64 efi_call0(void *fp); -extern u64 efi_call1(void *fp, u64 arg1); -extern u64 efi_call2(void *fp, u64 arg1, u64 arg2); -extern u64 efi_call3(void *fp, u64 arg1, u64 arg2, u64 arg3); -extern u64 efi_call4(void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4); -extern u64 efi_call5(void *fp, u64 arg1, u64 arg2, u64 arg3, - u64 arg4, u64 arg5); -extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3, - u64 arg4, u64 arg5, u64 arg6); - -#define efi_call_phys0(f) \ - efi_call0((f)) -#define efi_call_phys1(f, a1) \ - efi_call1((f), (u64)(a1)) -#define efi_call_phys2(f, a1, a2) \ - efi_call2((f), (u64)(a1), (u64)(a2)) -#define efi_call_phys3(f, a1, a2, a3) \ - efi_call3((f), (u64)(a1), (u64)(a2), (u64)(a3)) -#define efi_call_phys4(f, a1, a2, a3, a4) \ - efi_call4((f), (u64)(a1), (u64)(a2), (u64)(a3), \ - (u64)(a4)) -#define efi_call_phys5(f, a1, a2, a3, a4, a5) \ - efi_call5((f), (u64)(a1), (u64)(a2), (u64)(a3), \ - (u64)(a4), (u64)(a5)) -#define efi_call_phys6(f, a1, a2, a3, a4, a5, a6) \ - efi_call6((f), (u64)(a1), (u64)(a2), (u64)(a3), \ - (u64)(a4), (u64)(a5), (u64)(a6)) - -#define _efi_call_virtX(x, f, ...) \ +#define EFI_LOADER_SIGNATURE "EL64" + +extern u64 asmlinkage efi_call(void *fp, ...); + +#define efi_call_phys(f, args...) efi_call((f), args) + +#define efi_call_virt(f, ...) \ ({ \ efi_status_t __s; \ \ efi_sync_low_kernel_mappings(); \ preempt_disable(); \ - __s = efi_call##x((void *)efi.systab->runtime->f, __VA_ARGS__); \ + __kernel_fpu_begin(); \ + __s = efi_call((void *)efi.systab->runtime->f, __VA_ARGS__); \ + __kernel_fpu_end(); \ preempt_enable(); \ __s; \ }) -#define efi_call_virt0(f) \ - _efi_call_virtX(0, f) -#define efi_call_virt1(f, a1) \ - _efi_call_virtX(1, f, (u64)(a1)) -#define efi_call_virt2(f, a1, a2) \ - _efi_call_virtX(2, f, (u64)(a1), (u64)(a2)) -#define efi_call_virt3(f, a1, a2, a3) \ - _efi_call_virtX(3, f, (u64)(a1), (u64)(a2), (u64)(a3)) -#define efi_call_virt4(f, a1, a2, a3, a4) \ - _efi_call_virtX(4, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4)) -#define efi_call_virt5(f, a1, a2, a3, a4, a5) \ - _efi_call_virtX(5, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4), (u64)(a5)) -#define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \ - _efi_call_virtX(6, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6)) +/* + * All X86_64 virt calls return non-void values. Thus, use non-void call for + * virt calls that would be void on X86_32. + */ +#define __efi_call_virt(f, args...) efi_call_virt(f, args) extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, u32 type, u64 attribute); diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 2c71182d30ef5b..1a055c81d864d0 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -75,7 +75,12 @@ typedef struct user_fxsr_struct elf_fpxregset_t; #include -extern unsigned int vdso_enabled; +#ifdef CONFIG_X86_64 +extern unsigned int vdso64_enabled; +#endif +#if defined(CONFIG_X86_32) || defined(CONFIG_COMPAT) +extern unsigned int vdso32_enabled; +#endif /* * This is used to ensure we don't load something for the wrong architecture. @@ -269,9 +274,9 @@ extern int force_personality32; struct task_struct; -#define ARCH_DLINFO_IA32(vdso_enabled) \ +#define ARCH_DLINFO_IA32 \ do { \ - if (vdso_enabled) { \ + if (vdso32_enabled) { \ NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \ NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \ } \ @@ -281,7 +286,7 @@ do { \ #define STACK_RND_MASK (0x7ff) -#define ARCH_DLINFO ARCH_DLINFO_IA32(vdso_enabled) +#define ARCH_DLINFO ARCH_DLINFO_IA32 /* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */ @@ -292,16 +297,17 @@ do { \ #define ARCH_DLINFO \ do { \ - if (vdso_enabled) \ + if (vdso64_enabled) \ NEW_AUX_ENT(AT_SYSINFO_EHDR, \ - (unsigned long)current->mm->context.vdso); \ + (unsigned long __force)current->mm->context.vdso); \ } while (0) +/* As a historical oddity, the x32 and x86_64 vDSOs are controlled together. */ #define ARCH_DLINFO_X32 \ do { \ - if (vdso_enabled) \ + if (vdso64_enabled) \ NEW_AUX_ENT(AT_SYSINFO_EHDR, \ - (unsigned long)current->mm->context.vdso); \ + (unsigned long __force)current->mm->context.vdso); \ } while (0) #define AT_SYSINFO 32 @@ -310,7 +316,7 @@ do { \ if (test_thread_flag(TIF_X32)) \ ARCH_DLINFO_X32; \ else \ - ARCH_DLINFO_IA32(sysctl_vsyscall32) + ARCH_DLINFO_IA32 #define COMPAT_ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000) @@ -319,18 +325,17 @@ else \ #define VDSO_CURRENT_BASE ((unsigned long)current->mm->context.vdso) #define VDSO_ENTRY \ - ((unsigned long)VDSO32_SYMBOL(VDSO_CURRENT_BASE, vsyscall)) + ((unsigned long)current->mm->context.vdso + \ + selected_vdso32->sym___kernel_vsyscall) struct linux_binprm; #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 extern int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp); -extern int x32_setup_additional_pages(struct linux_binprm *bprm, - int uses_interp); - -extern int syscall32_setup_pages(struct linux_binprm *, int exstack); -#define compat_arch_setup_additional_pages syscall32_setup_pages +extern int compat_arch_setup_additional_pages(struct linux_binprm *bprm, + int uses_interp); +#define compat_arch_setup_additional_pages compat_arch_setup_additional_pages extern unsigned long arch_randomize_brk(struct mm_struct *mm); #define arch_randomize_brk arch_randomize_brk diff --git a/arch/x86/include/asm/espfix.h b/arch/x86/include/asm/espfix.h new file mode 100644 index 00000000000000..99efebb2f69df5 --- /dev/null +++ b/arch/x86/include/asm/espfix.h @@ -0,0 +1,16 @@ +#ifndef _ASM_X86_ESPFIX_H +#define _ASM_X86_ESPFIX_H + +#ifdef CONFIG_X86_64 + +#include + +DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_stack); +DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr); + +extern void init_espfix_bsp(void); +extern void init_espfix_ap(void); + +#endif /* CONFIG_X86_64 */ + +#endif /* _ASM_X86_ESPFIX_H */ diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index 43f482a0db3706..b0910f97a3eaaa 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -24,7 +24,7 @@ #include #include #else -#include +#include #endif /* @@ -41,7 +41,8 @@ extern unsigned long __FIXADDR_TOP; #define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP) #else -#define FIXADDR_TOP (VSYSCALL_END-PAGE_SIZE) +#define FIXADDR_TOP (round_up(VSYSCALL_ADDR + PAGE_SIZE, 1<> PAGE_SHIFT) - 1, - VVAR_PAGE, - VSYSCALL_HPET, + VSYSCALL_PAGE = (FIXADDR_TOP - VSYSCALL_ADDR) >> PAGE_SHIFT, #ifdef CONFIG_PARAVIRT_CLOCK PVCLOCK_FIXMAP_BEGIN, PVCLOCK_FIXMAP_END = PVCLOCK_FIXMAP_BEGIN+PVCLOCK_VSYSCALL_NR_PAGES-1, diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h index cea1c76d49bf5b..115e3689cd53de 100644 --- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h @@ -87,22 +87,22 @@ static inline int is_x32_frame(void) static __always_inline __pure bool use_eager_fpu(void) { - return static_cpu_has(X86_FEATURE_EAGER_FPU); + return static_cpu_has_safe(X86_FEATURE_EAGER_FPU); } static __always_inline __pure bool use_xsaveopt(void) { - return static_cpu_has(X86_FEATURE_XSAVEOPT); + return static_cpu_has_safe(X86_FEATURE_XSAVEOPT); } static __always_inline __pure bool use_xsave(void) { - return static_cpu_has(X86_FEATURE_XSAVE); + return static_cpu_has_safe(X86_FEATURE_XSAVE); } static __always_inline __pure bool use_fxsr(void) { - return static_cpu_has(X86_FEATURE_FXSR); + return static_cpu_has_safe(X86_FEATURE_FXSR); } static inline void fx_finit(struct i387_fxsave_struct *fx) @@ -293,7 +293,7 @@ static inline int restore_fpu_checking(struct task_struct *tsk) /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception is pending. Clear the x87 state here by setting it to fixed values. "m" is a random variable that should be in L1 */ - if (unlikely(static_cpu_has(X86_FEATURE_FXSAVE_LEAK))) { + if (unlikely(static_cpu_has_safe(X86_FEATURE_FXSAVE_LEAK))) { asm volatile( "fnclex\n\t" "emms\n\t" diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h index b18df579c0e99b..36f7125945e3e2 100644 --- a/arch/x86/include/asm/hpet.h +++ b/arch/x86/include/asm/hpet.h @@ -63,6 +63,7 @@ /* hpet memory map physical address */ extern unsigned long hpet_address; extern unsigned long force_hpet_address; +extern int boot_hpet_disable; extern u8 hpet_blockid; extern int hpet_force_user; extern u8 hpet_msi_disable; diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index a307b7530e540f..4615906d83df5b 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -190,8 +190,8 @@ extern void (*__initconst interrupt[NR_VECTORS-FIRST_EXTERNAL_VECTOR])(void); #define trace_interrupt interrupt #endif -#define VECTOR_UNDEFINED -1 -#define VECTOR_RETRIGGERED -2 +#define VECTOR_UNDEFINED (-1) +#define VECTOR_RETRIGGERED (-2) typedef int vector_irq_t[NR_VECTORS]; DECLARE_PER_CPU(vector_irq_t, vector_irq); diff --git a/arch/x86/include/asm/kprobes.h b/arch/x86/include/asm/kprobes.h index 9454c167629ff1..53cdfb2857abe4 100644 --- a/arch/x86/include/asm/kprobes.h +++ b/arch/x86/include/asm/kprobes.h @@ -116,4 +116,6 @@ struct kprobe_ctlblk { extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); extern int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data); +extern int kprobe_int3_handler(struct pt_regs *regs); +extern int kprobe_debug_handler(struct pt_regs *regs); #endif /* _ASM_X86_KPROBES_H */ diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 7de069afb382e4..e21aee98a5c2dc 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -50,11 +50,7 @@ | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \ | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG)) -#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1) -#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD)) -#define CR3_PCID_ENABLED_RESERVED_BITS 0xFFFFFF0000000000ULL -#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS | \ - 0xFFFFFF0000000000ULL) +#define CR3_L_MODE_RESERVED_BITS 0xFFFFFF0000000000ULL #define CR4_RESERVED_BITS \ (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\ | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \ diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h index 5f55e69627692f..876e74e8eec766 100644 --- a/arch/x86/include/asm/mmu.h +++ b/arch/x86/include/asm/mmu.h @@ -18,7 +18,7 @@ typedef struct { #endif struct mutex lock; - void *vdso; + void __user *vdso; } mm_context_t; #ifdef CONFIG_SMP diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h index c883bf726398a2..7166e25ecb5735 100644 --- a/arch/x86/include/asm/pgtable_64_types.h +++ b/arch/x86/include/asm/pgtable_64_types.h @@ -61,6 +61,8 @@ typedef struct { pteval_t pte; } pte_t; #define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) #define MODULES_END _AC(0xffffffffff000000, UL) #define MODULES_LEN (MODULES_END - MODULES_VADDR) +#define ESPFIX_PGD_ENTRY _AC(-2, UL) +#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << PGDIR_SHIFT) #define EARLY_DYNAMIC_PAGE_TABLES 64 diff --git a/arch/x86/include/asm/proto.h b/arch/x86/include/asm/proto.h index 6fd3fd76979687..a90f8972dad507 100644 --- a/arch/x86/include/asm/proto.h +++ b/arch/x86/include/asm/proto.h @@ -12,8 +12,6 @@ void ia32_syscall(void); void ia32_cstar_target(void); void ia32_sysenter_target(void); -void syscall32_cpu_init(void); - void x86_configure_nx(void); void x86_report_nx(void); diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index 9264f04a4c553a..ff4e7b236e21d5 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -59,6 +59,8 @@ static inline void x86_ce4100_early_setup(void) { } #ifndef _SETUP +#include + /* * This is set up by the setup-routine at boot-time */ diff --git a/arch/x86/include/asm/sync_bitops.h b/arch/x86/include/asm/sync_bitops.h index 05af3b31d52208..f28a24b51dc7c1 100644 --- a/arch/x86/include/asm/sync_bitops.h +++ b/arch/x86/include/asm/sync_bitops.h @@ -41,7 +41,7 @@ static inline void sync_set_bit(long nr, volatile unsigned long *addr) * * sync_clear_bit() is atomic and may not be reordered. However, it does * not contain a memory barrier, so if it is used for locking purposes, - * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic() * in order to ensure changes are visible on other processors. */ static inline void sync_clear_bit(long nr, volatile unsigned long *addr) diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 47e5de25ba799f..854053889d4d2d 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -83,6 +83,7 @@ struct thread_info { #define TIF_FORK 18 /* ret_from_fork */ #define TIF_NOHZ 19 /* in adaptive nohz mode */ #define TIF_MEMDIE 20 /* is terminating due to OOM killer */ +#define TIF_POLLING_NRFLAG 21 /* idle is polling for TIF_NEED_RESCHED */ #define TIF_IO_BITMAP 22 /* uses I/O bitmap */ #define TIF_FORCED_TF 24 /* true if TF in eflags artificially */ #define TIF_BLOCKSTEP 25 /* set when we want DEBUGCTLMSR_BTF */ @@ -106,6 +107,7 @@ struct thread_info { #define _TIF_IA32 (1 << TIF_IA32) #define _TIF_FORK (1 << TIF_FORK) #define _TIF_NOHZ (1 << TIF_NOHZ) +#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP) #define _TIF_FORCED_TF (1 << TIF_FORCED_TF) #define _TIF_BLOCKSTEP (1 << TIF_BLOCKSTEP) @@ -191,8 +193,6 @@ static inline struct thread_info *current_thread_info(void) * have to worry about atomic accesses. */ #define TS_COMPAT 0x0002 /* 32bit syscall active (64BIT)*/ -#define TS_POLLING 0x0004 /* idle task polling need_resched, - skip sending interrupt */ #define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */ #ifndef __ASSEMBLY__ diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index 58d66fe06b6170..ca32508c58c5b6 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -68,7 +68,7 @@ dotraplinkage void do_segment_not_present(struct pt_regs *, long); dotraplinkage void do_stack_segment(struct pt_regs *, long); #ifdef CONFIG_X86_64 dotraplinkage void do_double_fault(struct pt_regs *, long); -asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *); +asmlinkage struct pt_regs *sync_regs(struct pt_regs *); #endif dotraplinkage void do_general_protection(struct pt_regs *, long); dotraplinkage void do_page_fault(struct pt_regs *, unsigned long); diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h index 3087ea9c5f2e86..a040d493a4f9ef 100644 --- a/arch/x86/include/asm/uprobes.h +++ b/arch/x86/include/asm/uprobes.h @@ -33,15 +33,30 @@ typedef u8 uprobe_opcode_t; #define UPROBE_SWBP_INSN 0xcc #define UPROBE_SWBP_INSN_SIZE 1 +struct uprobe_xol_ops; + struct arch_uprobe { - u16 fixups; union { u8 insn[MAX_UINSN_BYTES]; u8 ixol[MAX_UINSN_BYTES]; }; + + const struct uprobe_xol_ops *ops; + + union { + struct { + s32 offs; + u8 ilen; + u8 opc1; + } branch; + struct { #ifdef CONFIG_X86_64 - unsigned long rip_rela_target_address; + long riprel_target; #endif + u8 fixups; + u8 ilen; + } def; + }; }; struct arch_uprobe_task { diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index a30836c8ac4da3..c63e925fd6b738 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -5,7 +5,7 @@ * * SGI UV architectural definitions * - * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_X86_UV_UV_HUB_H @@ -204,16 +204,6 @@ static inline int is_uvx_hub(void) return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE; } -static inline int is_uv2_1_hub(void) -{ - return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE; -} - -static inline int is_uv2_2_hub(void) -{ - return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE + 1; -} - union uvh_apicid { unsigned long v; struct uvh_apicid_s { diff --git a/arch/x86/include/asm/uv/uv_mmrs.h b/arch/x86/include/asm/uv/uv_mmrs.h index e42249bcf7e106..ddd8db6b6e70c9 100644 --- a/arch/x86/include/asm/uv/uv_mmrs.h +++ b/arch/x86/include/asm/uv/uv_mmrs.h @@ -5,7 +5,7 @@ * * SGI UV MMR definitions * - * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_X86_UV_UV_MMRS_H @@ -2802,6 +2802,46 @@ union uv1h_lb_target_physical_apic_id_mask_u { } s1; }; +/* ========================================================================= */ +/* UV3H_GR0_GAM_GR_CONFIG */ +/* ========================================================================= */ +#define UV3H_GR0_GAM_GR_CONFIG 0xc00028UL + +#define UV3H_GR0_GAM_GR_CONFIG_M_SKT_SHFT 0 +#define UV3H_GR0_GAM_GR_CONFIG_SUBSPACE_SHFT 10 +#define UV3H_GR0_GAM_GR_CONFIG_M_SKT_MASK 0x000000000000003fUL +#define UV3H_GR0_GAM_GR_CONFIG_SUBSPACE_MASK 0x0000000000000400UL + +union uv3h_gr0_gam_gr_config_u { + unsigned long v; + struct uv3h_gr0_gam_gr_config_s { + unsigned long m_skt:6; /* RW */ + unsigned long undef_6_9:4; /* Undefined */ + unsigned long subspace:1; /* RW */ + unsigned long reserved:53; + } s3; +}; + +/* ========================================================================= */ +/* UV3H_GR1_GAM_GR_CONFIG */ +/* ========================================================================= */ +#define UV3H_GR1_GAM_GR_CONFIG 0x1000028UL + +#define UV3H_GR1_GAM_GR_CONFIG_M_SKT_SHFT 0 +#define UV3H_GR1_GAM_GR_CONFIG_SUBSPACE_SHFT 10 +#define UV3H_GR1_GAM_GR_CONFIG_M_SKT_MASK 0x000000000000003fUL +#define UV3H_GR1_GAM_GR_CONFIG_SUBSPACE_MASK 0x0000000000000400UL + +union uv3h_gr1_gam_gr_config_u { + unsigned long v; + struct uv3h_gr1_gam_gr_config_s { + unsigned long m_skt:6; /* RW */ + unsigned long undef_6_9:4; /* Undefined */ + unsigned long subspace:1; /* RW */ + unsigned long reserved:53; + } s3; +}; + /* ========================================================================= */ /* UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR */ /* ========================================================================= */ diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h index d1dc55404ff127..d0a2c909c72d6a 100644 --- a/arch/x86/include/asm/vdso.h +++ b/arch/x86/include/asm/vdso.h @@ -3,63 +3,47 @@ #include #include +#include -#ifdef __ASSEMBLER__ +#ifndef __ASSEMBLER__ -#define DEFINE_VDSO_IMAGE(symname, filename) \ -__PAGE_ALIGNED_DATA ; \ - .globl symname##_start, symname##_end ; \ - .align PAGE_SIZE ; \ - symname##_start: ; \ - .incbin filename ; \ - symname##_end: ; \ - .align PAGE_SIZE /* extra data here leaks to userspace. */ ; \ - \ -.previous ; \ - \ - .globl symname##_pages ; \ - .bss ; \ - .align 8 ; \ - .type symname##_pages, @object ; \ - symname##_pages: ; \ - .zero (symname##_end - symname##_start + PAGE_SIZE - 1) / PAGE_SIZE * (BITS_PER_LONG / 8) ; \ - .size symname##_pages, .-symname##_pages +struct vdso_image { + void *data; + unsigned long size; /* Always a multiple of PAGE_SIZE */ + struct page **pages; /* Big enough for data/size page pointers */ -#else + unsigned long alt, alt_len; -#define DECLARE_VDSO_IMAGE(symname) \ - extern char symname##_start[], symname##_end[]; \ - extern struct page *symname##_pages[] + unsigned long sym_end_mapping; /* Total size of the mapping */ -#if defined CONFIG_X86_32 || defined CONFIG_COMPAT + unsigned long sym_vvar_page; + unsigned long sym_hpet_page; + unsigned long sym_VDSO32_NOTE_MASK; + unsigned long sym___kernel_sigreturn; + unsigned long sym___kernel_rt_sigreturn; + unsigned long sym___kernel_vsyscall; + unsigned long sym_VDSO32_SYSENTER_RETURN; +}; -#include +#ifdef CONFIG_X86_64 +extern const struct vdso_image vdso_image_64; +#endif -DECLARE_VDSO_IMAGE(vdso32_int80); -#ifdef CONFIG_COMPAT -DECLARE_VDSO_IMAGE(vdso32_syscall); +#ifdef CONFIG_X86_X32 +extern const struct vdso_image vdso_image_x32; #endif -DECLARE_VDSO_IMAGE(vdso32_sysenter); -/* - * Given a pointer to the vDSO image, find the pointer to VDSO32_name - * as that symbol is defined in the vDSO sources or linker script. - */ -#define VDSO32_SYMBOL(base, name) \ -({ \ - extern const char VDSO32_##name[]; \ - (void __user *)(VDSO32_##name + (unsigned long)(base)); \ -}) +#if defined CONFIG_X86_32 || defined CONFIG_COMPAT +extern const struct vdso_image vdso_image_32_int80; +#ifdef CONFIG_COMPAT +extern const struct vdso_image vdso_image_32_syscall; #endif +extern const struct vdso_image vdso_image_32_sysenter; -/* - * These symbols are defined with the addresses in the vsyscall page. - * See vsyscall-sigreturn.S. - */ -extern void __user __kernel_sigreturn; -extern void __user __kernel_rt_sigreturn; +extern const struct vdso_image *selected_vdso32; +#endif -void __init patch_vdso32(void *vdso, size_t len); +extern void __init init_vdso_image(const struct vdso_image *image); #endif /* __ASSEMBLER__ */ diff --git a/arch/x86/include/asm/vdso32.h b/arch/x86/include/asm/vdso32.h deleted file mode 100644 index 7efb7018406e62..00000000000000 --- a/arch/x86/include/asm/vdso32.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _ASM_X86_VDSO32_H -#define _ASM_X86_VDSO32_H - -#define VDSO_BASE_PAGE 0 -#define VDSO_VVAR_PAGE 1 -#define VDSO_HPET_PAGE 2 -#define VDSO_PAGES 3 -#define VDSO_PREV_PAGES 2 -#define VDSO_OFFSET(x) ((x) * PAGE_SIZE) - -#endif diff --git a/arch/x86/include/asm/vvar.h b/arch/x86/include/asm/vvar.h index 081d909bc49542..5d2b9ad2c6d295 100644 --- a/arch/x86/include/asm/vvar.h +++ b/arch/x86/include/asm/vvar.h @@ -29,31 +29,13 @@ #else -#ifdef BUILD_VDSO32 +extern char __vvar_page; #define DECLARE_VVAR(offset, type, name) \ extern type vvar_ ## name __attribute__((visibility("hidden"))); #define VVAR(name) (vvar_ ## name) -#else - -extern char __vvar_page; - -/* Base address of vvars. This is not ABI. */ -#ifdef CONFIG_X86_64 -#define VVAR_ADDRESS (-10*1024*1024 - 4096) -#else -#define VVAR_ADDRESS (&__vvar_page) -#endif - -#define DECLARE_VVAR(offset, type, name) \ - static type const * const vvaraddr_ ## name = \ - (void *)(VVAR_ADDRESS + (offset)); - -#define VVAR(name) (*vvaraddr_ ## name) -#endif - #define DEFINE_VVAR(type, name) \ type name \ __attribute__((section(".vvar_" #name), aligned(16))) __visible diff --git a/arch/x86/include/uapi/asm/vsyscall.h b/arch/x86/include/uapi/asm/vsyscall.h index 85dc1b3825abc7..b97dd6e263d293 100644 --- a/arch/x86/include/uapi/asm/vsyscall.h +++ b/arch/x86/include/uapi/asm/vsyscall.h @@ -7,11 +7,6 @@ enum vsyscall_num { __NR_vgetcpu, }; -#define VSYSCALL_START (-10UL << 20) -#define VSYSCALL_SIZE 1024 -#define VSYSCALL_END (-2UL << 20) -#define VSYSCALL_MAPPED_PAGES 1 -#define VSYSCALL_ADDR(vsyscall_nr) (VSYSCALL_START+VSYSCALL_SIZE*(vsyscall_nr)) - +#define VSYSCALL_ADDR (-10UL << 20) #endif /* _UAPI_ASM_X86_VSYSCALL_H */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index f4d96000d33aaf..491ef3e59850a4 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o obj-y += syscall_$(BITS).o vsyscall_gtod.o obj-$(CONFIG_X86_64) += vsyscall_64.o obj-$(CONFIG_X86_64) += vsyscall_emu_64.o +obj-$(CONFIG_X86_ESPFIX64) += espfix_64.o obj-$(CONFIG_SYSFS) += ksysfs.o obj-y += bootflag.o e820.o obj-y += pci-dma.o quirks.o topology.o kdebugfs.o diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 3a2ae4c88948dc..31368207837c2f 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -31,7 +31,7 @@ static char temp_stack[4096]; * * Wrapper around acpi_enter_sleep_state() to be called by assmebly. */ -acpi_status asmlinkage x86_acpi_enter_sleep_state(u8 state) +acpi_status asmlinkage __visible x86_acpi_enter_sleep_state(u8 state) { return acpi_enter_sleep_state(state); } diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index df94598ad05a84..703130f469ecf7 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -551,7 +550,7 @@ void *__init_or_module text_poke_early(void *addr, const void *opcode, * * Note: Must be called under text_mutex. */ -void *__kprobes text_poke(void *addr, const void *opcode, size_t len) +void *text_poke(void *addr, const void *opcode, size_t len) { unsigned long flags; char *vaddr; diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index 1400d725c722ee..0d44a8e937658f 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -89,6 +89,7 @@ arch_trigger_all_cpu_backtrace_handler(unsigned int cmd, struct pt_regs *regs) return NMI_DONE; } +NOKPROBE_SYMBOL(arch_trigger_all_cpu_backtrace_handler); static int __init register_trigger_all_cpu_backtrace(void) { diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index d23aa82e7a7bc2..c65b58942a3a3a 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2189,7 +2189,7 @@ void send_cleanup_vector(struct irq_cfg *cfg) cfg->move_in_progress = 0; } -asmlinkage void smp_irq_move_cleanup_interrupt(void) +asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) { unsigned vector, me; @@ -2312,7 +2312,7 @@ int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, int err; if (!config_enabled(CONFIG_SMP)) - return -1; + return -EPERM; if (!cpumask_intersects(mask, cpu_online_mask)) return -EINVAL; @@ -2343,7 +2343,7 @@ int native_ioapic_set_affinity(struct irq_data *data, int ret; if (!config_enabled(CONFIG_SMP)) - return -1; + return -EPERM; raw_spin_lock_irqsave(&ioapic_lock, flags); ret = __ioapic_set_affinity(data, mask, &dest); @@ -3075,9 +3075,11 @@ msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force) struct irq_cfg *cfg = data->chip_data; struct msi_msg msg; unsigned int dest; + int ret; - if (__ioapic_set_affinity(data, mask, &dest)) - return -1; + ret = __ioapic_set_affinity(data, mask, &dest); + if (ret) + return ret; __get_cached_msi_msg(data->msi_desc, &msg); @@ -3177,9 +3179,11 @@ dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask, struct irq_cfg *cfg = data->chip_data; unsigned int dest, irq = data->irq; struct msi_msg msg; + int ret; - if (__ioapic_set_affinity(data, mask, &dest)) - return -1; + ret = __ioapic_set_affinity(data, mask, &dest); + if (ret) + return ret; dmar_msi_read(irq, &msg); @@ -3226,9 +3230,11 @@ static int hpet_msi_set_affinity(struct irq_data *data, struct irq_cfg *cfg = data->chip_data; struct msi_msg msg; unsigned int dest; + int ret; - if (__ioapic_set_affinity(data, mask, &dest)) - return -1; + ret = __ioapic_set_affinity(data, mask, &dest); + if (ret) + return ret; hpet_msi_read(data->handler_data, &msg); @@ -3295,9 +3301,11 @@ ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force) { struct irq_cfg *cfg = data->chip_data; unsigned int dest; + int ret; - if (__ioapic_set_affinity(data, mask, &dest)) - return -1; + ret = __ioapic_set_affinity(data, mask, &dest); + if (ret) + return ret; target_ht_irq(data->irq, dest, cfg->vector); return IRQ_SET_MASK_OK_NOCOPY; diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 7834389ba5be09..293b41df54ef66 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -5,7 +5,7 @@ * * SGI UV APIC functions (note: not an Intel compatible APIC) * - * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved. */ #include #include @@ -440,6 +440,20 @@ static __initdata struct redir_addr redir_addrs[] = { {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR, UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR}, }; +static unsigned char get_n_lshift(int m_val) +{ + union uv3h_gr0_gam_gr_config_u m_gr_config; + + if (is_uv1_hub()) + return m_val; + + if (is_uv2_hub()) + return m_val == 40 ? 40 : 39; + + m_gr_config.v = uv_read_local_mmr(UV3H_GR0_GAM_GR_CONFIG); + return m_gr_config.s3.m_skt; +} + static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size) { union uvh_rh_gam_alias210_overlay_config_2_mmr_u alias; @@ -849,6 +863,7 @@ void __init uv_system_init(void) int gnode_extra, min_pnode = 999999, max_pnode = -1; unsigned long mmr_base, present, paddr; unsigned short pnode_mask; + unsigned char n_lshift; char *hub = (is_uv1_hub() ? "UV1" : (is_uv2_hub() ? "UV2" : "UV3")); @@ -860,6 +875,7 @@ void __init uv_system_init(void) m_val = m_n_config.s.m_skt; n_val = m_n_config.s.n_skt; pnode_mask = (1 << n_val) - 1; + n_lshift = get_n_lshift(m_val); mmr_base = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) & ~UV_MMR_ENABLE; @@ -867,8 +883,9 @@ void __init uv_system_init(void) node_id.v = uv_read_local_mmr(UVH_NODE_ID); gnode_extra = (node_id.s.node_id & ~((1 << n_val) - 1)) >> 1; gnode_upper = ((unsigned long)gnode_extra << m_val); - pr_info("UV: N:%d M:%d pnode_mask:0x%x gnode_upper/extra:0x%lx/0x%x\n", - n_val, m_val, pnode_mask, gnode_upper, gnode_extra); + pr_info("UV: N:%d M:%d pnode_mask:0x%x gnode_upper/extra:0x%lx/0x%x n_lshift 0x%x\n", + n_val, m_val, pnode_mask, gnode_upper, gnode_extra, + n_lshift); pr_info("UV: global MMR base 0x%lx\n", mmr_base); @@ -935,8 +952,7 @@ void __init uv_system_init(void) uv_cpu_hub_info(cpu)->hub_revision = uv_hub_info->hub_revision; uv_cpu_hub_info(cpu)->m_shift = 64 - m_val; - uv_cpu_hub_info(cpu)->n_lshift = is_uv2_1_hub() ? - (m_val == 40 ? 40 : 39) : m_val; + uv_cpu_hub_info(cpu)->n_lshift = n_lshift; pnode = uv_apicid_to_pnode(apicid); blade = boot_pnode_to_blade(pnode); diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 3ab03430211d6d..f3a1f04ed4cb80 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -844,21 +844,10 @@ static int apm_do_idle(void) int polling; int err = 0; - polling = !!(current_thread_info()->status & TS_POLLING); - if (polling) { - current_thread_info()->status &= ~TS_POLLING; - /* - * TS_POLLING-cleared state must be visible before we - * test NEED_RESCHED: - */ - smp_mb(); - } if (!need_resched()) { idled = 1; ret = apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax, &err); } - if (polling) - current_thread_info()->status |= TS_POLLING; if (!idled) return 0; diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index a135239badb7fd..ef1b93f18ed1c3 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -953,6 +955,38 @@ static void vgetcpu_set_mode(void) else vgetcpu_mode = VGETCPU_LSL; } + +/* May not be __init: called during resume */ +static void syscall32_cpu_init(void) +{ + /* Load these always in case some future AMD CPU supports + SYSENTER from compat mode too. */ + wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS); + wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL); + wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target); + + wrmsrl(MSR_CSTAR, ia32_cstar_target); +} +#endif + +#ifdef CONFIG_X86_32 +void enable_sep_cpu(void) +{ + int cpu = get_cpu(); + struct tss_struct *tss = &per_cpu(init_tss, cpu); + + if (!boot_cpu_has(X86_FEATURE_SEP)) { + put_cpu(); + return; + } + + tss->x86_tss.ss1 = __KERNEL_CS; + tss->x86_tss.sp1 = sizeof(struct tss_struct) + (unsigned long) tss; + wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); + wrmsr(MSR_IA32_SYSENTER_ESP, tss->x86_tss.sp1, 0); + wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) ia32_sysenter_target, 0); + put_cpu(); +} #endif void __init identify_boot_cpu(void) @@ -1160,6 +1194,7 @@ int is_debug_stack(unsigned long addr) (addr <= __get_cpu_var(debug_stack_addr) && addr > (__get_cpu_var(debug_stack_addr) - DEBUG_STKSZ)); } +NOKPROBE_SYMBOL(is_debug_stack); DEFINE_PER_CPU(u32, debug_idt_ctr); @@ -1168,6 +1203,7 @@ void debug_stack_set_zero(void) this_cpu_inc(debug_idt_ctr); load_current_idt(); } +NOKPROBE_SYMBOL(debug_stack_set_zero); void debug_stack_reset(void) { @@ -1176,6 +1212,7 @@ void debug_stack_reset(void) if (this_cpu_dec_return(debug_idt_ctr) == 0) load_current_idt(); } +NOKPROBE_SYMBOL(debug_stack_reset); #else /* CONFIG_X86_64 */ diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index d921b7ee659525..36a1bb6d1ee0d4 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -429,14 +429,14 @@ static inline void __smp_thermal_interrupt(void) smp_thermal_vector(); } -asmlinkage void smp_thermal_interrupt(struct pt_regs *regs) +asmlinkage __visible void smp_thermal_interrupt(struct pt_regs *regs) { entering_irq(); __smp_thermal_interrupt(); exiting_ack_irq(); } -asmlinkage void smp_trace_thermal_interrupt(struct pt_regs *regs) +asmlinkage __visible void smp_trace_thermal_interrupt(struct pt_regs *regs) { entering_irq(); trace_thermal_apic_entry(THERMAL_APIC_VECTOR); diff --git a/arch/x86/kernel/cpu/mcheck/threshold.c b/arch/x86/kernel/cpu/mcheck/threshold.c index fe6b1c86645b66..7245980186eea0 100644 --- a/arch/x86/kernel/cpu/mcheck/threshold.c +++ b/arch/x86/kernel/cpu/mcheck/threshold.c @@ -24,14 +24,14 @@ static inline void __smp_threshold_interrupt(void) mce_threshold_vector(); } -asmlinkage void smp_threshold_interrupt(void) +asmlinkage __visible void smp_threshold_interrupt(void) { entering_irq(); __smp_threshold_interrupt(); exiting_ack_irq(); } -asmlinkage void smp_trace_threshold_interrupt(void) +asmlinkage __visible void smp_trace_threshold_interrupt(void) { entering_irq(); trace_threshold_apic_entry(THRESHOLD_APIC_VECTOR); diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 76f98fe5b35c4a..a450373e8e9169 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -132,15 +132,6 @@ static void __init ms_hyperv_init_platform(void) lapic_timer_frequency = hv_lapic_frequency; printk(KERN_INFO "HyperV: LAPIC Timer Frequency: %#x\n", lapic_timer_frequency); - - /* - * On Hyper-V, when we are booting off an EFI firmware stack, - * we do not have many legacy devices including PIC, PIT etc. - */ - if (efi_enabled(EFI_BOOT)) { - printk(KERN_INFO "HyperV: Using null_legacy_pic\n"); - legacy_pic = &null_legacy_pic; - } } #endif diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index ae407f7226c899..32029e35f2b926 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -721,6 +721,7 @@ int perf_assign_events(struct perf_event **events, int n, return sched.state.unassigned; } +EXPORT_SYMBOL_GPL(perf_assign_events); int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) { @@ -1292,7 +1293,7 @@ void perf_events_lapic_init(void) apic_write(APIC_LVTPC, APIC_DM_NMI); } -static int __kprobes +static int perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs) { u64 start_clock; @@ -1310,6 +1311,7 @@ perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs) return ret; } +NOKPROBE_SYMBOL(perf_event_nmi_handler); struct event_constraint emptyconstraint; struct event_constraint unconstrained; diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c index 4c36bbe3173aa0..cbb1be3ed9e432 100644 --- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c +++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c @@ -593,7 +593,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs) return 1; } -static int __kprobes +static int perf_ibs_nmi_handler(unsigned int cmd, struct pt_regs *regs) { int handled = 0; @@ -606,6 +606,7 @@ perf_ibs_nmi_handler(unsigned int cmd, struct pt_regs *regs) return handled; } +NOKPROBE_SYMBOL(perf_ibs_nmi_handler); static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name) { diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index aa333d9668866f..adb02aa62af5e3 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -169,7 +169,6 @@ static struct event_constraint intel_slm_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ - FIXED_EVENT_CONSTRAINT(0x013c, 2), /* CPU_CLK_UNHALTED.REF */ FIXED_EVENT_CONSTRAINT(0x0300, 2), /* pseudo CPU_CLK_UNHALTED.REF */ EVENT_CONSTRAINT_END }; diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index d35078ea14467d..7db54b5d5f8689 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -206,23 +206,21 @@ static void __init dtb_apic_setup(void) static void __init x86_flattree_get_config(void) { u32 size, map_len; - struct boot_param_header *dt; + void *dt; if (!initial_dtb) return; - map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK), - (u64)sizeof(struct boot_param_header)); + map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK), (u64)128); - dt = early_memremap(initial_dtb, map_len); - size = be32_to_cpu(dt->totalsize); + initial_boot_params = dt = early_memremap(initial_dtb, map_len); + size = of_get_flat_dt_size(); if (map_len < size) { early_iounmap(dt, map_len); - dt = early_memremap(initial_dtb, size); + initial_boot_params = dt = early_memremap(initial_dtb, size); map_len = size; } - initial_boot_params = dt; unflatten_and_copy_device_tree(); early_iounmap(dt, map_len); } diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index d9c12d3022a70c..b74ebc7c4402e7 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -200,7 +200,7 @@ static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED; static int die_owner = -1; static unsigned int die_nest_count; -unsigned __kprobes long oops_begin(void) +unsigned long oops_begin(void) { int cpu; unsigned long flags; @@ -223,8 +223,9 @@ unsigned __kprobes long oops_begin(void) return flags; } EXPORT_SYMBOL_GPL(oops_begin); +NOKPROBE_SYMBOL(oops_begin); -void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) +void oops_end(unsigned long flags, struct pt_regs *regs, int signr) { if (regs && kexec_should_crash(current)) crash_kexec(regs); @@ -247,8 +248,9 @@ void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) panic("Fatal exception"); do_exit(signr); } +NOKPROBE_SYMBOL(oops_end); -int __kprobes __die(const char *str, struct pt_regs *regs, long err) +int __die(const char *str, struct pt_regs *regs, long err) { #ifdef CONFIG_X86_32 unsigned short ss; @@ -291,6 +293,7 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err) #endif return 0; } +NOKPROBE_SYMBOL(__die); /* * This is gone through when something in the kernel has done something bad diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index 6e2537c3219060..6cda0baeac9d78 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -530,6 +531,15 @@ static void __init intel_graphics_stolen(int num, int slot, int func) } } +static void __init force_disable_hpet(int num, int slot, int func) +{ +#ifdef CONFIG_HPET_TIMER + boot_hpet_disable = 1; + pr_info("x86/hpet: Will disable the HPET for this platform because it's not reliable\n"); +#endif +} + + #define QFLAG_APPLY_ONCE 0x1 #define QFLAG_APPLIED 0x2 #define QFLAG_DONE (QFLAG_APPLY_ONCE|QFLAG_APPLIED) @@ -567,6 +577,12 @@ static struct chipset early_qrk[] __initdata = { PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check }, { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA, PCI_ANY_ID, QFLAG_APPLY_ONCE, intel_graphics_stolen }, + /* + * HPET on current version of Baytrail platform has accuracy + * problems, disable it for now: + */ + { PCI_VENDOR_ID_INTEL, 0x0f00, + PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet}, {} }; diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index a2a4f469788965..3a39899b6e4e51 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -314,10 +314,6 @@ ENTRY(ret_from_kernel_thread) CFI_ENDPROC ENDPROC(ret_from_kernel_thread) -/* - * Interrupt exit functions should be protected against kprobes - */ - .pushsection .kprobes.text, "ax" /* * Return to user mode is not as complex as all this looks, * but we want the default path for a system call return to @@ -372,10 +368,6 @@ need_resched: END(resume_kernel) #endif CFI_ENDPROC -/* - * End of kprobes section - */ - .popsection /* SYSENTER_RETURN points to after the "sysenter" instruction in the vsyscall page. See vsyscall-sysentry.S, which defines the symbol. */ @@ -456,12 +448,11 @@ sysenter_audit: jnz syscall_trace_entry addl $4,%esp CFI_ADJUST_CFA_OFFSET -4 - /* %esi already in 8(%esp) 6th arg: 4th syscall arg */ - /* %edx already in 4(%esp) 5th arg: 3rd syscall arg */ - /* %ecx already in 0(%esp) 4th arg: 2nd syscall arg */ - movl %ebx,%ecx /* 3rd arg: 1st syscall arg */ - movl %eax,%edx /* 2nd arg: syscall number */ - movl $AUDIT_ARCH_I386,%eax /* 1st arg: audit arch */ + movl %esi,4(%esp) /* 5th arg: 4th syscall arg */ + movl %edx,(%esp) /* 4th arg: 3rd syscall arg */ + /* %ecx already in %ecx 3rd arg: 2nd syscall arg */ + movl %ebx,%edx /* 2nd arg: 1st syscall arg */ + /* %eax already in %eax 1st arg: syscall number */ call __audit_syscall_entry pushl_cfi %ebx movl PT_EAX(%esp),%eax /* reload syscall number */ @@ -495,10 +486,6 @@ sysexit_audit: PTGS_TO_GS_EX ENDPROC(ia32_sysenter_target) -/* - * syscall stub including irq exit should be protected against kprobes - */ - .pushsection .kprobes.text, "ax" # system call handler stub ENTRY(system_call) RING0_INT_FRAME # can't unwind into user space anyway @@ -527,6 +514,7 @@ syscall_exit: restore_all: TRACE_IRQS_IRET restore_all_notrace: +#ifdef CONFIG_X86_ESPFIX32 movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS # Warning: PT_OLDSS(%esp) contains the wrong/random values if we # are returning to the kernel. @@ -537,6 +525,7 @@ restore_all_notrace: cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax CFI_REMEMBER_STATE je ldt_ss # returning to user-space with LDT SS +#endif restore_nocheck: RESTORE_REGS 4 # skip orig_eax/error_code irq_return: @@ -549,13 +538,9 @@ ENTRY(iret_exc) .previous _ASM_EXTABLE(irq_return,iret_exc) +#ifdef CONFIG_X86_ESPFIX32 CFI_RESTORE_STATE ldt_ss: - larl PT_OLDSS(%esp), %eax - jnz restore_nocheck - testl $0x00400000, %eax # returning to 32bit stack? - jnz restore_nocheck # allright, normal return - #ifdef CONFIG_PARAVIRT /* * The kernel can't run on a non-flat stack if paravirt mode @@ -597,6 +582,7 @@ ldt_ss: lss (%esp), %esp /* switch to espfix segment */ CFI_ADJUST_CFA_OFFSET -8 jmp restore_nocheck +#endif CFI_ENDPROC ENDPROC(system_call) @@ -691,10 +677,6 @@ syscall_badsys: jmp resume_userspace END(syscall_badsys) CFI_ENDPROC -/* - * End of kprobes section - */ - .popsection .macro FIXUP_ESPFIX_STACK /* @@ -704,6 +686,7 @@ END(syscall_badsys) * the high word of the segment base from the GDT and swiches to the * normal stack and adjusts ESP with the matching offset. */ +#ifdef CONFIG_X86_ESPFIX32 /* fixup the stack */ mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */ mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */ @@ -713,8 +696,10 @@ END(syscall_badsys) pushl_cfi %eax lss (%esp), %esp /* switch to the normal stack segment */ CFI_ADJUST_CFA_OFFSET -8 +#endif .endm .macro UNWIND_ESPFIX_STACK +#ifdef CONFIG_X86_ESPFIX32 movl %ss, %eax /* see if on espfix stack */ cmpw $__ESPFIX_SS, %ax @@ -725,6 +710,7 @@ END(syscall_badsys) /* switch to normal stack */ FIXUP_ESPFIX_STACK 27: +#endif .endm /* @@ -781,10 +767,6 @@ common_interrupt: ENDPROC(common_interrupt) CFI_ENDPROC -/* - * Irq entries should be protected against kprobes - */ - .pushsection .kprobes.text, "ax" #define BUILD_INTERRUPT3(name, nr, fn) \ ENTRY(name) \ RING0_INT_FRAME; \ @@ -961,10 +943,6 @@ ENTRY(spurious_interrupt_bug) jmp error_code CFI_ENDPROC END(spurious_interrupt_bug) -/* - * End of kprobes section - */ - .popsection #ifdef CONFIG_XEN /* Xen doesn't set %esp to be precisely what the normal sysenter @@ -1239,11 +1217,6 @@ return_to_handler: jmp *%ecx #endif -/* - * Some functions should be protected against kprobes - */ - .pushsection .kprobes.text, "ax" - #ifdef CONFIG_TRACING ENTRY(trace_page_fault) RING0_EC_FRAME @@ -1355,11 +1328,13 @@ END(debug) ENTRY(nmi) RING0_INT_FRAME ASM_CLAC +#ifdef CONFIG_X86_ESPFIX32 pushl_cfi %eax movl %ss, %eax cmpw $__ESPFIX_SS, %ax popl_cfi %eax je nmi_espfix_stack +#endif cmpl $ia32_sysenter_target,(%esp) je nmi_stack_fixup pushl_cfi %eax @@ -1399,6 +1374,7 @@ nmi_debug_stack_check: FIX_STACK 24, nmi_stack_correct, 1 jmp nmi_stack_correct +#ifdef CONFIG_X86_ESPFIX32 nmi_espfix_stack: /* We have a RING0_INT_FRAME here. * @@ -1420,6 +1396,7 @@ nmi_espfix_stack: lss 12+4(%esp), %esp # back to espfix stack CFI_ADJUST_CFA_OFFSET -24 jmp irq_return +#endif CFI_ENDPROC END(nmi) @@ -1453,7 +1430,3 @@ ENTRY(async_page_fault) END(async_page_fault) #endif -/* - * End of kprobes section - */ - .popsection diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 1e96c3628bf24f..4214834c6dd90d 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -58,6 +58,7 @@ #include #include #include +#include #include /* Avoid __ASSEMBLER__'ifying just for this. */ @@ -487,8 +488,6 @@ ENDPROC(native_usergs_sysret64) TRACE_IRQS_OFF .endm -/* save complete stack frame */ - .pushsection .kprobes.text, "ax" ENTRY(save_paranoid) XCPT_FRAME 1 RDI+8 cld @@ -517,7 +516,6 @@ ENTRY(save_paranoid) 1: ret CFI_ENDPROC END(save_paranoid) - .popsection /* * A newly forked process directly context switches into this address. @@ -694,12 +692,11 @@ badsys: * jump back to the normal fast path. */ auditsys: - movq %r10,%r9 /* 6th arg: 4th syscall arg */ - movq %rdx,%r8 /* 5th arg: 3rd syscall arg */ - movq %rsi,%rcx /* 4th arg: 2nd syscall arg */ - movq %rdi,%rdx /* 3rd arg: 1st syscall arg */ - movq %rax,%rsi /* 2nd arg: syscall number */ - movl $AUDIT_ARCH_X86_64,%edi /* 1st arg: audit arch */ + movq %r10,%r8 /* 5th arg: 4th syscall arg */ + movq %rdx,%rcx /* 4th arg: 3rd syscall arg */ + movq %rsi,%rdx /* 3rd arg: 2nd syscall arg */ + movq %rdi,%rsi /* 2nd arg: 1st syscall arg */ + movq %rax,%rdi /* 1st arg: syscall number */ call __audit_syscall_entry LOAD_ARGS 0 /* reload call-clobbered registers */ jmp system_call_fastpath @@ -975,10 +972,6 @@ END(interrupt) call \func .endm -/* - * Interrupt entry/exit should be protected against kprobes - */ - .pushsection .kprobes.text, "ax" /* * The interrupt stubs push (~vector+0x80) onto the stack and * then jump to common_interrupt. @@ -1040,8 +1033,18 @@ restore_args: RESTORE_ARGS 1,8,1 irq_return: + /* + * Are we returning to a stack segment from the LDT? Note: in + * 64-bit mode SS:RSP on the exception stack is always valid. + */ +#ifdef CONFIG_X86_ESPFIX64 + testb $4,(SS-RIP)(%rsp) + jnz irq_return_ldt +#endif + +irq_return_iret: INTERRUPT_RETURN - _ASM_EXTABLE(irq_return, bad_iret) + _ASM_EXTABLE(irq_return_iret, bad_iret) #ifdef CONFIG_PARAVIRT ENTRY(native_iret) @@ -1049,6 +1052,32 @@ ENTRY(native_iret) _ASM_EXTABLE(native_iret, bad_iret) #endif +#ifdef CONFIG_X86_ESPFIX64 +irq_return_ldt: + pushq_cfi %rax + pushq_cfi %rdi + SWAPGS + movq PER_CPU_VAR(espfix_waddr),%rdi + movq %rax,(0*8)(%rdi) /* RAX */ + movq (2*8)(%rsp),%rax /* RIP */ + movq %rax,(1*8)(%rdi) + movq (3*8)(%rsp),%rax /* CS */ + movq %rax,(2*8)(%rdi) + movq (4*8)(%rsp),%rax /* RFLAGS */ + movq %rax,(3*8)(%rdi) + movq (6*8)(%rsp),%rax /* SS */ + movq %rax,(5*8)(%rdi) + movq (5*8)(%rsp),%rax /* RSP */ + movq %rax,(4*8)(%rdi) + andl $0xffff0000,%eax + popq_cfi %rdi + orq PER_CPU_VAR(espfix_stack),%rax + SWAPGS + movq %rax,%rsp + popq_cfi %rax + jmp irq_return_iret +#endif + .section .fixup,"ax" bad_iret: /* @@ -1110,13 +1139,45 @@ ENTRY(retint_kernel) call preempt_schedule_irq jmp exit_intr #endif - CFI_ENDPROC END(common_interrupt) -/* - * End of kprobes section - */ - .popsection + + /* + * If IRET takes a fault on the espfix stack, then we + * end up promoting it to a doublefault. In that case, + * modify the stack to make it look like we just entered + * the #GP handler from user space, similar to bad_iret. + */ +#ifdef CONFIG_X86_ESPFIX64 + ALIGN +__do_double_fault: + XCPT_FRAME 1 RDI+8 + movq RSP(%rdi),%rax /* Trap on the espfix stack? */ + sarq $PGDIR_SHIFT,%rax + cmpl $ESPFIX_PGD_ENTRY,%eax + jne do_double_fault /* No, just deliver the fault */ + cmpl $__KERNEL_CS,CS(%rdi) + jne do_double_fault + movq RIP(%rdi),%rax + cmpq $irq_return_iret,%rax +#ifdef CONFIG_PARAVIRT + je 1f + cmpq $native_iret,%rax +#endif + jne do_double_fault /* This shouldn't happen... */ +1: + movq PER_CPU_VAR(kernel_stack),%rax + subq $(6*8-KERNEL_STACK_OFFSET),%rax /* Reset to original stack */ + movq %rax,RSP(%rdi) + movq $0,(%rax) /* Missing (lost) #GP error code */ + movq $general_protection,RIP(%rdi) + retq + CFI_ENDPROC +END(__do_double_fault) +#else +# define __do_double_fault do_double_fault +#endif + /* * APIC interrupts. @@ -1314,7 +1375,7 @@ zeroentry overflow do_overflow zeroentry bounds do_bounds zeroentry invalid_op do_invalid_op zeroentry device_not_available do_device_not_available -paranoiderrorentry double_fault do_double_fault +paranoiderrorentry double_fault __do_double_fault zeroentry coprocessor_segment_overrun do_coprocessor_segment_overrun errorentry invalid_TSS do_invalid_TSS errorentry segment_not_present do_segment_not_present @@ -1477,11 +1538,6 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \ hyperv_callback_vector hyperv_vector_handler #endif /* CONFIG_HYPERV */ -/* - * Some functions should be protected against kprobes - */ - .pushsection .kprobes.text, "ax" - paranoidzeroentry_ist debug do_debug DEBUG_STACK paranoidzeroentry_ist int3 do_int3 DEBUG_STACK paranoiderrorentry stack_segment do_stack_segment @@ -1601,7 +1657,7 @@ error_sti: */ error_kernelspace: incl %ebx - leaq irq_return(%rip),%rcx + leaq irq_return_iret(%rip),%rcx cmpq %rcx,RIP+8(%rsp) je error_swapgs movl %ecx,%eax /* zero extend */ @@ -1898,7 +1954,3 @@ ENTRY(ignore_sysret) CFI_ENDPROC END(ignore_sysret) -/* - * End of kprobes section - */ - .popsection diff --git a/arch/x86/kernel/espfix_64.c b/arch/x86/kernel/espfix_64.c new file mode 100644 index 00000000000000..6afbb16e9b7948 --- /dev/null +++ b/arch/x86/kernel/espfix_64.c @@ -0,0 +1,209 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2014 Intel Corporation; author: H. Peter Anvin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ----------------------------------------------------------------------- */ + +/* + * The IRET instruction, when returning to a 16-bit segment, only + * restores the bottom 16 bits of the user space stack pointer. This + * causes some 16-bit software to break, but it also leaks kernel state + * to user space. + * + * This works around this by creating percpu "ministacks", each of which + * is mapped 2^16 times 64K apart. When we detect that the return SS is + * on the LDT, we copy the IRET frame to the ministack and use the + * relevant alias to return to userspace. The ministacks are mapped + * readonly, so if the IRET fault we promote #GP to #DF which is an IST + * vector and thus has its own stack; we then do the fixup in the #DF + * handler. + * + * This file sets up the ministacks and the related page tables. The + * actual ministack invocation is in entry_64.S. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Note: we only need 6*8 = 48 bytes for the espfix stack, but round + * it up to a cache line to avoid unnecessary sharing. + */ +#define ESPFIX_STACK_SIZE (8*8UL) +#define ESPFIX_STACKS_PER_PAGE (PAGE_SIZE/ESPFIX_STACK_SIZE) + +/* There is address space for how many espfix pages? */ +#define ESPFIX_PAGE_SPACE (1UL << (PGDIR_SHIFT-PAGE_SHIFT-16)) + +#define ESPFIX_MAX_CPUS (ESPFIX_STACKS_PER_PAGE * ESPFIX_PAGE_SPACE) +#if CONFIG_NR_CPUS > ESPFIX_MAX_CPUS +# error "Need more than one PGD for the ESPFIX hack" +#endif + +#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO) + +/* This contains the *bottom* address of the espfix stack */ +DEFINE_PER_CPU_READ_MOSTLY(unsigned long, espfix_stack); +DEFINE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr); + +/* Initialization mutex - should this be a spinlock? */ +static DEFINE_MUTEX(espfix_init_mutex); + +/* Page allocation bitmap - each page serves ESPFIX_STACKS_PER_PAGE CPUs */ +#define ESPFIX_MAX_PAGES DIV_ROUND_UP(CONFIG_NR_CPUS, ESPFIX_STACKS_PER_PAGE) +static void *espfix_pages[ESPFIX_MAX_PAGES]; + +static __page_aligned_bss pud_t espfix_pud_page[PTRS_PER_PUD] + __aligned(PAGE_SIZE); + +static unsigned int page_random, slot_random; + +/* + * This returns the bottom address of the espfix stack for a specific CPU. + * The math allows for a non-power-of-two ESPFIX_STACK_SIZE, in which case + * we have to account for some amount of padding at the end of each page. + */ +static inline unsigned long espfix_base_addr(unsigned int cpu) +{ + unsigned long page, slot; + unsigned long addr; + + page = (cpu / ESPFIX_STACKS_PER_PAGE) ^ page_random; + slot = (cpu + slot_random) % ESPFIX_STACKS_PER_PAGE; + addr = (page << PAGE_SHIFT) + (slot * ESPFIX_STACK_SIZE); + addr = (addr & 0xffffUL) | ((addr & ~0xffffUL) << 16); + addr += ESPFIX_BASE_ADDR; + return addr; +} + +#define PTE_STRIDE (65536/PAGE_SIZE) +#define ESPFIX_PTE_CLONES (PTRS_PER_PTE/PTE_STRIDE) +#define ESPFIX_PMD_CLONES PTRS_PER_PMD +#define ESPFIX_PUD_CLONES (65536/(ESPFIX_PTE_CLONES*ESPFIX_PMD_CLONES)) + +#define PGTABLE_PROT ((_KERNPG_TABLE & ~_PAGE_RW) | _PAGE_NX) + +static void init_espfix_random(void) +{ + unsigned long rand; + + /* + * This is run before the entropy pools are initialized, + * but this is hopefully better than nothing. + */ + if (!arch_get_random_long(&rand)) { + /* The constant is an arbitrary large prime */ + rdtscll(rand); + rand *= 0xc345c6b72fd16123UL; + } + + slot_random = rand % ESPFIX_STACKS_PER_PAGE; + page_random = (rand / ESPFIX_STACKS_PER_PAGE) + & (ESPFIX_PAGE_SPACE - 1); +} + +void __init init_espfix_bsp(void) +{ + pgd_t *pgd_p; + pteval_t ptemask; + + ptemask = __supported_pte_mask; + + /* Install the espfix pud into the kernel page directory */ + pgd_p = &init_level4_pgt[pgd_index(ESPFIX_BASE_ADDR)]; + pgd_populate(&init_mm, pgd_p, (pud_t *)espfix_pud_page); + + /* Randomize the locations */ + init_espfix_random(); + + /* The rest is the same as for any other processor */ + init_espfix_ap(); +} + +void init_espfix_ap(void) +{ + unsigned int cpu, page; + unsigned long addr; + pud_t pud, *pud_p; + pmd_t pmd, *pmd_p; + pte_t pte, *pte_p; + int n; + void *stack_page; + pteval_t ptemask; + + /* We only have to do this once... */ + if (likely(this_cpu_read(espfix_stack))) + return; /* Already initialized */ + + cpu = smp_processor_id(); + addr = espfix_base_addr(cpu); + page = cpu/ESPFIX_STACKS_PER_PAGE; + + /* Did another CPU already set this up? */ + stack_page = ACCESS_ONCE(espfix_pages[page]); + if (likely(stack_page)) + goto done; + + mutex_lock(&espfix_init_mutex); + + /* Did we race on the lock? */ + stack_page = ACCESS_ONCE(espfix_pages[page]); + if (stack_page) + goto unlock_done; + + ptemask = __supported_pte_mask; + + pud_p = &espfix_pud_page[pud_index(addr)]; + pud = *pud_p; + if (!pud_present(pud)) { + pmd_p = (pmd_t *)__get_free_page(PGALLOC_GFP); + pud = __pud(__pa(pmd_p) | (PGTABLE_PROT & ptemask)); + paravirt_alloc_pud(&init_mm, __pa(pmd_p) >> PAGE_SHIFT); + for (n = 0; n < ESPFIX_PUD_CLONES; n++) + set_pud(&pud_p[n], pud); + } + + pmd_p = pmd_offset(&pud, addr); + pmd = *pmd_p; + if (!pmd_present(pmd)) { + pte_p = (pte_t *)__get_free_page(PGALLOC_GFP); + pmd = __pmd(__pa(pte_p) | (PGTABLE_PROT & ptemask)); + paravirt_alloc_pmd(&init_mm, __pa(pte_p) >> PAGE_SHIFT); + for (n = 0; n < ESPFIX_PMD_CLONES; n++) + set_pmd(&pmd_p[n], pmd); + } + + pte_p = pte_offset_kernel(&pmd, addr); + stack_page = (void *)__get_free_page(GFP_KERNEL); + pte = __pte(__pa(stack_page) | (__PAGE_KERNEL_RO & ptemask)); + paravirt_alloc_pte(&init_mm, __pa(stack_page) >> PAGE_SHIFT); + for (n = 0; n < ESPFIX_PTE_CLONES; n++) + set_pte(&pte_p[n*PTE_STRIDE], pte); + + /* Job is done for this CPU and any CPU which shares this page */ + ACCESS_ONCE(espfix_pages[page]) = stack_page; + +unlock_done: + mutex_unlock(&espfix_init_mutex); +done: + this_cpu_write(espfix_stack, addr); + this_cpu_write(espfix_waddr, (unsigned long)stack_page + + (addr & ~PAGE_MASK)); +} diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 52819e816f87fe..3d837b00502bcc 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -621,8 +621,8 @@ void ftrace_replace_code(int enable) return; remove_breakpoints: + pr_warn("Failed on %s (%d):\n", report, count); ftrace_bug(ret, rec ? rec->ip : 0); - printk(KERN_WARNING "Failed on %s (%d):\n", report, count); for_ftrace_rec_iter(iter) { rec = ftrace_rec_iter_record(iter); /* diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index c61a14a4a3109f..d6c1b983699576 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c @@ -29,7 +29,7 @@ static void __init i386_default_early_setup(void) reserve_ebda_region(); } -asmlinkage void __init i386_start_kernel(void) +asmlinkage __visible void __init i386_start_kernel(void) { sanitize_boot_params(&boot_params); diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 85126ccbdf6b1e..068054f4bf20b7 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -137,7 +137,7 @@ static void __init copy_bootdata(char *real_mode_data) } } -asmlinkage void __init x86_64_start_kernel(char * real_mode_data) +asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data) { int i; diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 8d80ae0116039b..a9777bb5b5a0dc 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -74,9 +74,6 @@ static inline void hpet_writel(unsigned int d, unsigned int a) static inline void hpet_set_mapping(void) { hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); -#ifdef CONFIG_X86_64 - __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VVAR_NOCACHE); -#endif } static inline void hpet_clear_mapping(void) @@ -88,7 +85,7 @@ static inline void hpet_clear_mapping(void) /* * HPET command line enable / disable */ -static int boot_hpet_disable; +int boot_hpet_disable; int hpet_force_user; static int hpet_verbose; diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index a67b47c31314ba..5f9cf20cdb6802 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -424,7 +423,7 @@ EXPORT_SYMBOL_GPL(hw_breakpoint_restore); * NOTIFY_STOP returned for all other cases * */ -static int __kprobes hw_breakpoint_handler(struct die_args *args) +static int hw_breakpoint_handler(struct die_args *args) { int i, cpu, rc = NOTIFY_STOP; struct perf_event *bp; @@ -511,7 +510,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) /* * Handle debug exception notifications. */ -int __kprobes hw_breakpoint_exceptions_notify( +int hw_breakpoint_exceptions_notify( struct notifier_block *unused, unsigned long val, void *data) { if (val != DIE_DEBUG) diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c index 2e977b5d61ddee..8af817105e29cb 100644 --- a/arch/x86/kernel/i8259.c +++ b/arch/x86/kernel/i8259.c @@ -299,13 +299,31 @@ static void unmask_8259A(void) static void init_8259A(int auto_eoi) { unsigned long flags; + unsigned char probe_val = ~(1 << PIC_CASCADE_IR); + unsigned char new_val; i8259A_auto_eoi = auto_eoi; raw_spin_lock_irqsave(&i8259A_lock, flags); - outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ + /* + * Check to see if we have a PIC. + * Mask all except the cascade and read + * back the value we just wrote. If we don't + * have a PIC, we will read 0xff as opposed to the + * value we wrote. + */ outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ + outb(probe_val, PIC_MASTER_IMR); + new_val = inb(PIC_MASTER_IMR); + if (new_val != probe_val) { + printk(KERN_INFO "Using NULL legacy PIC\n"); + legacy_pic = &null_legacy_pic; + raw_spin_unlock_irqrestore(&i8259A_lock, flags); + return; + } + + outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ /* * outb_pic - this has to work on a wide range of PC hardware. diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 283a76a9cc4099..49bbb57da7f581 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -357,6 +357,7 @@ void fixup_irqs(void) struct irq_desc *desc; struct irq_data *data; struct irq_chip *chip; + int ret; for_each_irq_desc(irq, desc) { int break_affinity = 0; @@ -395,10 +396,14 @@ void fixup_irqs(void) if (!irqd_can_move_in_process_context(data) && chip->irq_mask) chip->irq_mask(data); - if (chip->irq_set_affinity) - chip->irq_set_affinity(data, affinity, true); - else if (!(warned++)) - set_affinity = 0; + if (chip->irq_set_affinity) { + ret = chip->irq_set_affinity(data, affinity, true); + if (ret == -ENOSPC) + pr_crit("IRQ %d set affinity failed because there are no available vectors. The device assigned to this IRQ is unstable.\n", irq); + } else { + if (!(warned++)) + set_affinity = 0; + } /* * We unmask if the irq was not marked masked by the diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 61b17dc2c27734..7596df664901ee 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -112,7 +112,8 @@ struct kretprobe_blackpoint kretprobe_blacklist[] = { const int kretprobe_blacklist_size = ARRAY_SIZE(kretprobe_blacklist); -static void __kprobes __synthesize_relative_insn(void *from, void *to, u8 op) +static nokprobe_inline void +__synthesize_relative_insn(void *from, void *to, u8 op) { struct __arch_relative_insn { u8 op; @@ -125,21 +126,23 @@ static void __kprobes __synthesize_relative_insn(void *from, void *to, u8 op) } /* Insert a jump instruction at address 'from', which jumps to address 'to'.*/ -void __kprobes synthesize_reljump(void *from, void *to) +void synthesize_reljump(void *from, void *to) { __synthesize_relative_insn(from, to, RELATIVEJUMP_OPCODE); } +NOKPROBE_SYMBOL(synthesize_reljump); /* Insert a call instruction at address 'from', which calls address 'to'.*/ -void __kprobes synthesize_relcall(void *from, void *to) +void synthesize_relcall(void *from, void *to) { __synthesize_relative_insn(from, to, RELATIVECALL_OPCODE); } +NOKPROBE_SYMBOL(synthesize_relcall); /* * Skip the prefixes of the instruction. */ -static kprobe_opcode_t *__kprobes skip_prefixes(kprobe_opcode_t *insn) +static kprobe_opcode_t *skip_prefixes(kprobe_opcode_t *insn) { insn_attr_t attr; @@ -154,12 +157,13 @@ static kprobe_opcode_t *__kprobes skip_prefixes(kprobe_opcode_t *insn) #endif return insn; } +NOKPROBE_SYMBOL(skip_prefixes); /* * Returns non-zero if opcode is boostable. * RIP relative instructions are adjusted at copying time in 64 bits mode */ -int __kprobes can_boost(kprobe_opcode_t *opcodes) +int can_boost(kprobe_opcode_t *opcodes) { kprobe_opcode_t opcode; kprobe_opcode_t *orig_opcodes = opcodes; @@ -260,7 +264,7 @@ unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long add } /* Check if paddr is at an instruction boundary */ -static int __kprobes can_probe(unsigned long paddr) +static int can_probe(unsigned long paddr) { unsigned long addr, __addr, offset = 0; struct insn insn; @@ -299,7 +303,7 @@ static int __kprobes can_probe(unsigned long paddr) /* * Returns non-zero if opcode modifies the interrupt flag. */ -static int __kprobes is_IF_modifier(kprobe_opcode_t *insn) +static int is_IF_modifier(kprobe_opcode_t *insn) { /* Skip prefixes */ insn = skip_prefixes(insn); @@ -322,7 +326,7 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn) * If not, return null. * Only applicable to 64-bit x86. */ -int __kprobes __copy_instruction(u8 *dest, u8 *src) +int __copy_instruction(u8 *dest, u8 *src) { struct insn insn; kprobe_opcode_t buf[MAX_INSN_SIZE]; @@ -365,7 +369,7 @@ int __kprobes __copy_instruction(u8 *dest, u8 *src) return insn.length; } -static int __kprobes arch_copy_kprobe(struct kprobe *p) +static int arch_copy_kprobe(struct kprobe *p) { int ret; @@ -392,7 +396,7 @@ static int __kprobes arch_copy_kprobe(struct kprobe *p) return 0; } -int __kprobes arch_prepare_kprobe(struct kprobe *p) +int arch_prepare_kprobe(struct kprobe *p) { if (alternatives_text_reserved(p->addr, p->addr)) return -EINVAL; @@ -407,17 +411,17 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) return arch_copy_kprobe(p); } -void __kprobes arch_arm_kprobe(struct kprobe *p) +void arch_arm_kprobe(struct kprobe *p) { text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1); } -void __kprobes arch_disarm_kprobe(struct kprobe *p) +void arch_disarm_kprobe(struct kprobe *p) { text_poke(p->addr, &p->opcode, 1); } -void __kprobes arch_remove_kprobe(struct kprobe *p) +void arch_remove_kprobe(struct kprobe *p) { if (p->ainsn.insn) { free_insn_slot(p->ainsn.insn, (p->ainsn.boostable == 1)); @@ -425,7 +429,8 @@ void __kprobes arch_remove_kprobe(struct kprobe *p) } } -static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) +static nokprobe_inline void +save_previous_kprobe(struct kprobe_ctlblk *kcb) { kcb->prev_kprobe.kp = kprobe_running(); kcb->prev_kprobe.status = kcb->kprobe_status; @@ -433,7 +438,8 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) kcb->prev_kprobe.saved_flags = kcb->kprobe_saved_flags; } -static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) +static nokprobe_inline void +restore_previous_kprobe(struct kprobe_ctlblk *kcb) { __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); kcb->kprobe_status = kcb->prev_kprobe.status; @@ -441,8 +447,9 @@ static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) kcb->kprobe_saved_flags = kcb->prev_kprobe.saved_flags; } -static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, - struct kprobe_ctlblk *kcb) +static nokprobe_inline void +set_current_kprobe(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) { __this_cpu_write(current_kprobe, p); kcb->kprobe_saved_flags = kcb->kprobe_old_flags @@ -451,7 +458,7 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, kcb->kprobe_saved_flags &= ~X86_EFLAGS_IF; } -static void __kprobes clear_btf(void) +static nokprobe_inline void clear_btf(void) { if (test_thread_flag(TIF_BLOCKSTEP)) { unsigned long debugctl = get_debugctlmsr(); @@ -461,7 +468,7 @@ static void __kprobes clear_btf(void) } } -static void __kprobes restore_btf(void) +static nokprobe_inline void restore_btf(void) { if (test_thread_flag(TIF_BLOCKSTEP)) { unsigned long debugctl = get_debugctlmsr(); @@ -471,8 +478,7 @@ static void __kprobes restore_btf(void) } } -void __kprobes -arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) +void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { unsigned long *sara = stack_addr(regs); @@ -481,9 +487,10 @@ arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) /* Replace the return addr with trampoline addr */ *sara = (unsigned long) &kretprobe_trampoline; } +NOKPROBE_SYMBOL(arch_prepare_kretprobe); -static void __kprobes -setup_singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb, int reenter) +static void setup_singlestep(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb, int reenter) { if (setup_detour_execution(p, regs, reenter)) return; @@ -519,22 +526,24 @@ setup_singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *k else regs->ip = (unsigned long)p->ainsn.insn; } +NOKPROBE_SYMBOL(setup_singlestep); /* * We have reentered the kprobe_handler(), since another probe was hit while * within the handler. We save the original kprobes variables and just single * step on the instruction of the new probe without calling any user handlers. */ -static int __kprobes -reenter_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) +static int reenter_kprobe(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) { switch (kcb->kprobe_status) { case KPROBE_HIT_SSDONE: case KPROBE_HIT_ACTIVE: + case KPROBE_HIT_SS: kprobes_inc_nmissed_count(p); setup_singlestep(p, regs, kcb, 1); break; - case KPROBE_HIT_SS: + case KPROBE_REENTER: /* A probe has been hit in the codepath leading up to, or just * after, single-stepping of a probed instruction. This entire * codepath should strictly reside in .kprobes.text section. @@ -553,12 +562,13 @@ reenter_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb return 1; } +NOKPROBE_SYMBOL(reenter_kprobe); /* * Interrupts are disabled on entry as trap3 is an interrupt gate and they * remain disabled throughout this function. */ -static int __kprobes kprobe_handler(struct pt_regs *regs) +int kprobe_int3_handler(struct pt_regs *regs) { kprobe_opcode_t *addr; struct kprobe *p; @@ -621,12 +631,13 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) preempt_enable_no_resched(); return 0; } +NOKPROBE_SYMBOL(kprobe_int3_handler); /* * When a retprobed function returns, this code saves registers and * calls trampoline_handler() runs, which calls the kretprobe's handler. */ -static void __used __kprobes kretprobe_trampoline_holder(void) +static void __used kretprobe_trampoline_holder(void) { asm volatile ( ".global kretprobe_trampoline\n" @@ -657,11 +668,13 @@ static void __used __kprobes kretprobe_trampoline_holder(void) #endif " ret\n"); } +NOKPROBE_SYMBOL(kretprobe_trampoline_holder); +NOKPROBE_SYMBOL(kretprobe_trampoline); /* * Called from kretprobe_trampoline */ -__visible __used __kprobes void *trampoline_handler(struct pt_regs *regs) +__visible __used void *trampoline_handler(struct pt_regs *regs) { struct kretprobe_instance *ri = NULL; struct hlist_head *head, empty_rp; @@ -747,6 +760,7 @@ __visible __used __kprobes void *trampoline_handler(struct pt_regs *regs) } return (void *)orig_ret_address; } +NOKPROBE_SYMBOL(trampoline_handler); /* * Called after single-stepping. p->addr is the address of the @@ -775,8 +789,8 @@ __visible __used __kprobes void *trampoline_handler(struct pt_regs *regs) * jump instruction after the copied instruction, that jumps to the next * instruction after the probepoint. */ -static void __kprobes -resume_execution(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) +static void resume_execution(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) { unsigned long *tos = stack_addr(regs); unsigned long copy_ip = (unsigned long)p->ainsn.insn; @@ -851,12 +865,13 @@ resume_execution(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *k no_change: restore_btf(); } +NOKPROBE_SYMBOL(resume_execution); /* * Interrupts are disabled on entry as trap1 is an interrupt gate and they * remain disabled throughout this function. */ -static int __kprobes post_kprobe_handler(struct pt_regs *regs) +int kprobe_debug_handler(struct pt_regs *regs) { struct kprobe *cur = kprobe_running(); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); @@ -891,8 +906,9 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) return 1; } +NOKPROBE_SYMBOL(kprobe_debug_handler); -int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) +int kprobe_fault_handler(struct pt_regs *regs, int trapnr) { struct kprobe *cur = kprobe_running(); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); @@ -949,12 +965,13 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) return 0; } +NOKPROBE_SYMBOL(kprobe_fault_handler); /* * Wrapper routine for handling exceptions. */ -int __kprobes -kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data) +int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, + void *data) { struct die_args *args = data; int ret = NOTIFY_DONE; @@ -962,22 +979,7 @@ kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *d if (args->regs && user_mode_vm(args->regs)) return ret; - switch (val) { - case DIE_INT3: - if (kprobe_handler(args->regs)) - ret = NOTIFY_STOP; - break; - case DIE_DEBUG: - if (post_kprobe_handler(args->regs)) { - /* - * Reset the BS bit in dr6 (pointed by args->err) to - * denote completion of processing - */ - (*(unsigned long *)ERR_PTR(args->err)) &= ~DR_STEP; - ret = NOTIFY_STOP; - } - break; - case DIE_GPF: + if (val == DIE_GPF) { /* * To be potentially processing a kprobe fault and to * trust the result from kprobe_running(), we have @@ -986,14 +988,12 @@ kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *d if (!preemptible() && kprobe_running() && kprobe_fault_handler(args->regs, args->trapnr)) ret = NOTIFY_STOP; - break; - default: - break; } return ret; } +NOKPROBE_SYMBOL(kprobe_exceptions_notify); -int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) +int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) { struct jprobe *jp = container_of(p, struct jprobe, kp); unsigned long addr; @@ -1017,8 +1017,9 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) regs->ip = (unsigned long)(jp->entry); return 1; } +NOKPROBE_SYMBOL(setjmp_pre_handler); -void __kprobes jprobe_return(void) +void jprobe_return(void) { struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); @@ -1034,8 +1035,10 @@ void __kprobes jprobe_return(void) " nop \n"::"b" (kcb->jprobe_saved_sp):"memory"); } +NOKPROBE_SYMBOL(jprobe_return); +NOKPROBE_SYMBOL(jprobe_return_end); -int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) +int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) { struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); u8 *addr = (u8 *) (regs->ip - 1); @@ -1063,13 +1066,22 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) } return 0; } +NOKPROBE_SYMBOL(longjmp_break_handler); + +bool arch_within_kprobe_blacklist(unsigned long addr) +{ + return (addr >= (unsigned long)__kprobes_text_start && + addr < (unsigned long)__kprobes_text_end) || + (addr >= (unsigned long)__entry_text_start && + addr < (unsigned long)__entry_text_end); +} int __init arch_init_kprobes(void) { return 0; } -int __kprobes arch_trampoline_kprobe(struct kprobe *p) +int arch_trampoline_kprobe(struct kprobe *p) { return 0; } diff --git a/arch/x86/kernel/kprobes/ftrace.c b/arch/x86/kernel/kprobes/ftrace.c index 23ef5c556f0614..717b02a22e6763 100644 --- a/arch/x86/kernel/kprobes/ftrace.c +++ b/arch/x86/kernel/kprobes/ftrace.c @@ -25,8 +25,9 @@ #include "common.h" -static int __skip_singlestep(struct kprobe *p, struct pt_regs *regs, - struct kprobe_ctlblk *kcb) +static nokprobe_inline +int __skip_singlestep(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) { /* * Emulate singlestep (and also recover regs->ip) @@ -41,18 +42,19 @@ static int __skip_singlestep(struct kprobe *p, struct pt_regs *regs, return 1; } -int __kprobes skip_singlestep(struct kprobe *p, struct pt_regs *regs, - struct kprobe_ctlblk *kcb) +int skip_singlestep(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) { if (kprobe_ftrace(p)) return __skip_singlestep(p, regs, kcb); else return 0; } +NOKPROBE_SYMBOL(skip_singlestep); /* Ftrace callback handler for kprobes */ -void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *ops, struct pt_regs *regs) +void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *ops, struct pt_regs *regs) { struct kprobe *p; struct kprobe_ctlblk *kcb; @@ -84,8 +86,9 @@ void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, end: local_irq_restore(flags); } +NOKPROBE_SYMBOL(kprobe_ftrace_handler); -int __kprobes arch_prepare_kprobe_ftrace(struct kprobe *p) +int arch_prepare_kprobe_ftrace(struct kprobe *p) { p->ainsn.insn = NULL; p->ainsn.boostable = -1; diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index 898160b42e4392..f304773285ae36 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c @@ -77,7 +77,7 @@ unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr) } /* Insert a move instruction which sets a pointer to eax/rdi (1st arg). */ -static void __kprobes synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val) +static void synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val) { #ifdef CONFIG_X86_64 *addr++ = 0x48; @@ -138,7 +138,8 @@ asm ( #define INT3_SIZE sizeof(kprobe_opcode_t) /* Optimized kprobe call back function: called from optinsn */ -static void __kprobes optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs) +static void +optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs) { struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); unsigned long flags; @@ -168,8 +169,9 @@ static void __kprobes optimized_callback(struct optimized_kprobe *op, struct pt_ } local_irq_restore(flags); } +NOKPROBE_SYMBOL(optimized_callback); -static int __kprobes copy_optimized_instructions(u8 *dest, u8 *src) +static int copy_optimized_instructions(u8 *dest, u8 *src) { int len = 0, ret; @@ -189,7 +191,7 @@ static int __kprobes copy_optimized_instructions(u8 *dest, u8 *src) } /* Check whether insn is indirect jump */ -static int __kprobes insn_is_indirect_jump(struct insn *insn) +static int insn_is_indirect_jump(struct insn *insn) { return ((insn->opcode.bytes[0] == 0xff && (X86_MODRM_REG(insn->modrm.value) & 6) == 4) || /* Jump */ @@ -224,7 +226,7 @@ static int insn_jump_into_range(struct insn *insn, unsigned long start, int len) } /* Decode whole function to ensure any instructions don't jump into target */ -static int __kprobes can_optimize(unsigned long paddr) +static int can_optimize(unsigned long paddr) { unsigned long addr, size = 0, offset = 0; struct insn insn; @@ -275,7 +277,7 @@ static int __kprobes can_optimize(unsigned long paddr) } /* Check optimized_kprobe can actually be optimized. */ -int __kprobes arch_check_optimized_kprobe(struct optimized_kprobe *op) +int arch_check_optimized_kprobe(struct optimized_kprobe *op) { int i; struct kprobe *p; @@ -290,15 +292,15 @@ int __kprobes arch_check_optimized_kprobe(struct optimized_kprobe *op) } /* Check the addr is within the optimized instructions. */ -int __kprobes -arch_within_optimized_kprobe(struct optimized_kprobe *op, unsigned long addr) +int arch_within_optimized_kprobe(struct optimized_kprobe *op, + unsigned long addr) { return ((unsigned long)op->kp.addr <= addr && (unsigned long)op->kp.addr + op->optinsn.size > addr); } /* Free optimized instruction slot */ -static __kprobes +static void __arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty) { if (op->optinsn.insn) { @@ -308,7 +310,7 @@ void __arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty) } } -void __kprobes arch_remove_optimized_kprobe(struct optimized_kprobe *op) +void arch_remove_optimized_kprobe(struct optimized_kprobe *op) { __arch_remove_optimized_kprobe(op, 1); } @@ -318,7 +320,7 @@ void __kprobes arch_remove_optimized_kprobe(struct optimized_kprobe *op) * Target instructions MUST be relocatable (checked inside) * This is called when new aggr(opt)probe is allocated or reused. */ -int __kprobes arch_prepare_optimized_kprobe(struct optimized_kprobe *op) +int arch_prepare_optimized_kprobe(struct optimized_kprobe *op) { u8 *buf; int ret; @@ -372,7 +374,7 @@ int __kprobes arch_prepare_optimized_kprobe(struct optimized_kprobe *op) * Replace breakpoints (int3) with relative jumps. * Caller must call with locking kprobe_mutex and text_mutex. */ -void __kprobes arch_optimize_kprobes(struct list_head *oplist) +void arch_optimize_kprobes(struct list_head *oplist) { struct optimized_kprobe *op, *tmp; u8 insn_buf[RELATIVEJUMP_SIZE]; @@ -398,7 +400,7 @@ void __kprobes arch_optimize_kprobes(struct list_head *oplist) } /* Replace a relative jump with a breakpoint (int3). */ -void __kprobes arch_unoptimize_kprobe(struct optimized_kprobe *op) +void arch_unoptimize_kprobe(struct optimized_kprobe *op) { u8 insn_buf[RELATIVEJUMP_SIZE]; @@ -424,8 +426,7 @@ extern void arch_unoptimize_kprobes(struct list_head *oplist, } } -int __kprobes -setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter) +int setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter) { struct optimized_kprobe *op; @@ -441,3 +442,4 @@ setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter) } return 0; } +NOKPROBE_SYMBOL(setup_detour_execution); diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 0331cb389d6861..d81abcbfe50142 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -251,8 +251,9 @@ u32 kvm_read_and_reset_pf_reason(void) return reason; } EXPORT_SYMBOL_GPL(kvm_read_and_reset_pf_reason); +NOKPROBE_SYMBOL(kvm_read_and_reset_pf_reason); -dotraplinkage void __kprobes +dotraplinkage void do_async_page_fault(struct pt_regs *regs, unsigned long error_code) { enum ctx_state prev_state; @@ -276,6 +277,7 @@ do_async_page_fault(struct pt_regs *regs, unsigned long error_code) break; } } +NOKPROBE_SYMBOL(do_async_page_fault); static void __init paravirt_ops_setup(void) { diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index af1d14a9ebdae1..c37886d759ccac 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c @@ -229,16 +229,10 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) } } - /* - * On x86-64 we do not support 16-bit segments due to - * IRET leaking the high bits of the kernel stack address. - */ -#ifdef CONFIG_X86_64 - if (!ldt_info.seg_32bit) { + if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) { error = -EINVAL; goto out_unlock; } -#endif fill_ldt(&ldt, &ldt_info); if (oldmode) diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c index b4872b999a713d..c3e985d1751ced 100644 --- a/arch/x86/kernel/nmi.c +++ b/arch/x86/kernel/nmi.c @@ -110,7 +110,7 @@ static void nmi_max_handler(struct irq_work *w) a->handler, whole_msecs, decimal_msecs); } -static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2b) +static int nmi_handle(unsigned int type, struct pt_regs *regs, bool b2b) { struct nmi_desc *desc = nmi_to_desc(type); struct nmiaction *a; @@ -146,6 +146,7 @@ static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2 /* return total number of NMI events handled */ return handled; } +NOKPROBE_SYMBOL(nmi_handle); int __register_nmi_handler(unsigned int type, struct nmiaction *action) { @@ -208,7 +209,7 @@ void unregister_nmi_handler(unsigned int type, const char *name) } EXPORT_SYMBOL_GPL(unregister_nmi_handler); -static __kprobes void +static void pci_serr_error(unsigned char reason, struct pt_regs *regs) { /* check to see if anyone registered against these types of errors */ @@ -238,8 +239,9 @@ pci_serr_error(unsigned char reason, struct pt_regs *regs) reason = (reason & NMI_REASON_CLEAR_MASK) | NMI_REASON_CLEAR_SERR; outb(reason, NMI_REASON_PORT); } +NOKPROBE_SYMBOL(pci_serr_error); -static __kprobes void +static void io_check_error(unsigned char reason, struct pt_regs *regs) { unsigned long i; @@ -269,8 +271,9 @@ io_check_error(unsigned char reason, struct pt_regs *regs) reason &= ~NMI_REASON_CLEAR_IOCHK; outb(reason, NMI_REASON_PORT); } +NOKPROBE_SYMBOL(io_check_error); -static __kprobes void +static void unknown_nmi_error(unsigned char reason, struct pt_regs *regs) { int handled; @@ -298,11 +301,12 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs) pr_emerg("Dazed and confused, but trying to continue\n"); } +NOKPROBE_SYMBOL(unknown_nmi_error); static DEFINE_PER_CPU(bool, swallow_nmi); static DEFINE_PER_CPU(unsigned long, last_nmi_rip); -static __kprobes void default_do_nmi(struct pt_regs *regs) +static void default_do_nmi(struct pt_regs *regs) { unsigned char reason = 0; int handled; @@ -401,6 +405,7 @@ static __kprobes void default_do_nmi(struct pt_regs *regs) else unknown_nmi_error(reason, regs); } +NOKPROBE_SYMBOL(default_do_nmi); /* * NMIs can hit breakpoints which will cause it to lose its @@ -520,7 +525,7 @@ static inline void nmi_nesting_postprocess(void) } #endif -dotraplinkage notrace __kprobes void +dotraplinkage notrace void do_nmi(struct pt_regs *regs, long error_code) { nmi_nesting_preprocess(regs); @@ -537,6 +542,7 @@ do_nmi(struct pt_regs *regs, long error_code) /* On i386, may loop back to preprocess */ nmi_nesting_postprocess(); } +NOKPROBE_SYMBOL(do_nmi); void stop_nmi(void) { diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 1b10af835c31d9..548d25f00c90ad 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -389,6 +390,11 @@ __visible struct pv_cpu_ops pv_cpu_ops = { .end_context_switch = paravirt_nop, }; +/* At this point, native_get/set_debugreg has real function entries */ +NOKPROBE_SYMBOL(native_get_debugreg); +NOKPROBE_SYMBOL(native_set_debugreg); +NOKPROBE_SYMBOL(native_load_idt); + struct pv_apic_ops pv_apic_ops = { #ifdef CONFIG_X86_LOCAL_APIC .startup_ipi_hook = paravirt_nop, diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 9c0280f93d05db..ca5b02d405c3ba 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -52,7 +52,7 @@ asmlinkage extern void ret_from_fork(void); -asmlinkage DEFINE_PER_CPU(unsigned long, old_rsp); +__visible DEFINE_PER_CPU(unsigned long, old_rsp); /* Prints also some state that isn't saved in the pt_regs */ void __show_regs(struct pt_regs *regs, int all) @@ -413,12 +413,11 @@ void set_personality_ia32(bool x32) set_thread_flag(TIF_ADDR32); /* Mark the associated mm as containing 32-bit tasks. */ - if (current->mm) - current->mm->context.ia32_compat = 1; - if (x32) { clear_thread_flag(TIF_IA32); set_thread_flag(TIF_X32); + if (current->mm) + current->mm->context.ia32_compat = TIF_X32; current->personality &= ~READ_IMPLIES_EXEC; /* is_compat_task() uses the presence of the x32 syscall bit flag to determine compat status */ @@ -426,6 +425,8 @@ void set_personality_ia32(bool x32) } else { set_thread_flag(TIF_IA32); clear_thread_flag(TIF_X32); + if (current->mm) + current->mm->context.ia32_compat = TIF_IA32; current->personality |= force_personality32; /* Prepare the first "return" to user space */ current_thread_info()->status |= TS_COMPAT; diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 678c0ada3b3ce5..eb1c87f0b03bcf 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -1488,15 +1488,11 @@ long syscall_trace_enter(struct pt_regs *regs) trace_sys_enter(regs, regs->orig_ax); if (IS_IA32) - audit_syscall_entry(AUDIT_ARCH_I386, - regs->orig_ax, - regs->bx, regs->cx, + audit_syscall_entry(regs->orig_ax, regs->bx, regs->cx, regs->dx, regs->si); #ifdef CONFIG_X86_64 else - audit_syscall_entry(AUDIT_ARCH_X86_64, - regs->orig_ax, - regs->di, regs->si, + audit_syscall_entry(regs->orig_ax, regs->di, regs->si, regs->dx, regs->r10); #endif diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 3399d3a9973033..52b1157c53eb7f 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -191,6 +191,16 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { }, }, + /* Certec */ + { /* Handle problems with rebooting on Certec BPC600 */ + .callback = set_pci_reboot, + .ident = "Certec BPC600", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Certec"), + DMI_MATCH(DMI_PRODUCT_NAME, "BPC600"), + }, + }, + /* Dell */ { /* Handle problems with rebooting on Dell DXP061 */ .callback = set_bios_reboot, diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 9e5de6813e1fa7..a0da58db43a86e 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -298,7 +298,8 @@ __setup_frame(int sig, struct ksignal *ksig, sigset_t *set, } if (current->mm->context.vdso) - restorer = VDSO32_SYMBOL(current->mm->context.vdso, sigreturn); + restorer = current->mm->context.vdso + + selected_vdso32->sym___kernel_sigreturn; else restorer = &frame->retcode; if (ksig->ka.sa.sa_flags & SA_RESTORER) @@ -361,7 +362,8 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, save_altstack_ex(&frame->uc.uc_stack, regs->sp); /* Set up to return from userspace. */ - restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); + restorer = current->mm->context.vdso + + selected_vdso32->sym___kernel_sigreturn; if (ksig->ka.sa.sa_flags & SA_RESTORER) restorer = ksig->ka.sa.sa_restorer; put_user_ex(restorer, &frame->pretcode); diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 7c3a5a61f2e463..be8e1bde07aa47 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -168,7 +168,7 @@ static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs) * this function calls the 'stop' function on all other CPUs in the system. */ -asmlinkage void smp_reboot_interrupt(void) +asmlinkage __visible void smp_reboot_interrupt(void) { ack_APIC_irq(); irq_enter(); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 34826934d4a7b3..5d93ac1b72db07 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -243,6 +243,13 @@ static void notrace start_secondary(void *unused) */ check_tsc_sync_target(); + /* + * Enable the espfix hack for this CPU + */ +#ifdef CONFIG_X86_ESPFIX64 + init_espfix_ap(); +#endif + /* * We need to hold vector_lock so there the set of online cpus * does not change while we are assigning vectors to cpus. Holding diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 57409f6b8c623e..fdbaa5a715f1f3 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -106,7 +106,7 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) preempt_count_dec(); } -static int __kprobes +static nokprobe_inline int do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, struct pt_regs *regs, long error_code) { @@ -136,7 +136,7 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, return -1; } -static void __kprobes +static void do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, long error_code, siginfo_t *info) { @@ -173,6 +173,7 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, else force_sig(signr, tsk); } +NOKPROBE_SYMBOL(do_trap); #define DO_ERROR(trapnr, signr, str, name) \ dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ @@ -263,7 +264,7 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) } #endif -dotraplinkage void __kprobes +dotraplinkage void do_general_protection(struct pt_regs *regs, long error_code) { struct task_struct *tsk; @@ -309,9 +310,10 @@ do_general_protection(struct pt_regs *regs, long error_code) exit: exception_exit(prev_state); } +NOKPROBE_SYMBOL(do_general_protection); /* May run on IST stack. */ -dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_code) +dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code) { enum ctx_state prev_state; @@ -327,13 +329,18 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co if (poke_int3_handler(regs)) return; - prev_state = exception_enter(); #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, SIGTRAP) == NOTIFY_STOP) goto exit; #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ +#ifdef CONFIG_KPROBES + if (kprobe_int3_handler(regs)) + return; +#endif + prev_state = exception_enter(); + if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, SIGTRAP) == NOTIFY_STOP) goto exit; @@ -350,6 +357,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co exit: exception_exit(prev_state); } +NOKPROBE_SYMBOL(do_int3); #ifdef CONFIG_X86_64 /* @@ -357,7 +365,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co * for scheduling or signal handling. The actual stack switch is done in * entry.S */ -asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) +asmlinkage __visible struct pt_regs *sync_regs(struct pt_regs *eregs) { struct pt_regs *regs = eregs; /* Did already sync */ @@ -376,6 +384,7 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) *regs = *eregs; return regs; } +NOKPROBE_SYMBOL(sync_regs); #endif /* @@ -402,7 +411,7 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) * * May run on IST stack. */ -dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) +dotraplinkage void do_debug(struct pt_regs *regs, long error_code) { struct task_struct *tsk = current; enum ctx_state prev_state; @@ -410,8 +419,6 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) unsigned long dr6; int si_code; - prev_state = exception_enter(); - get_debugreg(dr6, 6); /* Filter out all the reserved bits which are preset to 1 */ @@ -440,6 +447,12 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) /* Store the virtualized DR6 value */ tsk->thread.debugreg6 = dr6; +#ifdef CONFIG_KPROBES + if (kprobe_debug_handler(regs)) + goto exit; +#endif + prev_state = exception_enter(); + if (notify_die(DIE_DEBUG, "debug", regs, (long)&dr6, error_code, SIGTRAP) == NOTIFY_STOP) goto exit; @@ -482,6 +495,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) exit: exception_exit(prev_state); } +NOKPROBE_SYMBOL(do_debug); /* * Note that we play around with the 'TS' bit in an attempt to get @@ -601,11 +615,11 @@ do_spurious_interrupt_bug(struct pt_regs *regs, long error_code) #endif } -asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void) +asmlinkage __visible void __attribute__((weak)) smp_thermal_interrupt(void) { } -asmlinkage void __attribute__((weak)) smp_threshold_interrupt(void) +asmlinkage __visible void __attribute__((weak)) smp_threshold_interrupt(void) { } @@ -653,7 +667,7 @@ void math_state_restore(void) } EXPORT_SYMBOL_GPL(math_state_restore); -dotraplinkage void __kprobes +dotraplinkage void do_device_not_available(struct pt_regs *regs, long error_code) { enum ctx_state prev_state; @@ -679,6 +693,7 @@ do_device_not_available(struct pt_regs *regs, long error_code) #endif exception_exit(prev_state); } +NOKPROBE_SYMBOL(do_device_not_available); #ifdef CONFIG_X86_32 dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index 2ed845928b5f3f..2ebadb252093c1 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c @@ -32,20 +32,17 @@ /* Post-execution fixups. */ -/* No fixup needed */ -#define UPROBE_FIX_NONE 0x0 - /* Adjust IP back to vicinity of actual insn */ -#define UPROBE_FIX_IP 0x1 +#define UPROBE_FIX_IP 0x01 /* Adjust the return address of a call insn */ -#define UPROBE_FIX_CALL 0x2 +#define UPROBE_FIX_CALL 0x02 /* Instruction will modify TF, don't change it */ -#define UPROBE_FIX_SETF 0x4 +#define UPROBE_FIX_SETF 0x04 -#define UPROBE_FIX_RIP_AX 0x8000 -#define UPROBE_FIX_RIP_CX 0x4000 +#define UPROBE_FIX_RIP_AX 0x08 +#define UPROBE_FIX_RIP_CX 0x10 #define UPROBE_TRAP_NR UINT_MAX @@ -53,7 +50,7 @@ #define OPCODE1(insn) ((insn)->opcode.bytes[0]) #define OPCODE2(insn) ((insn)->opcode.bytes[1]) #define OPCODE3(insn) ((insn)->opcode.bytes[2]) -#define MODRM_REG(insn) X86_MODRM_REG(insn->modrm.value) +#define MODRM_REG(insn) X86_MODRM_REG((insn)->modrm.value) #define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\ (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \ @@ -67,6 +64,7 @@ * to keep gcc from statically optimizing it out, as variable_test_bit makes * some versions of gcc to think only *(unsigned long*) is used. */ +#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) static volatile u32 good_insns_32[256 / 32] = { /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ /* ---------------------------------------------- */ @@ -89,33 +87,12 @@ static volatile u32 good_insns_32[256 / 32] = { /* ---------------------------------------------- */ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ }; +#else +#define good_insns_32 NULL +#endif -/* Using this for both 64-bit and 32-bit apps */ -static volatile u32 good_2byte_insns[256 / 32] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ---------------------------------------------- */ - W(0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1) | /* 00 */ - W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) , /* 10 */ - W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) | /* 20 */ - W(0x30, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 30 */ - W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 40 */ - W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */ - W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 60 */ - W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1) , /* 70 */ - W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */ - W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */ - W(0xa0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1) | /* a0 */ - W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) , /* b0 */ - W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* c0 */ - W(0xd0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */ - W(0xe0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* e0 */ - W(0xf0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) /* f0 */ - /* ---------------------------------------------- */ - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -}; - -#ifdef CONFIG_X86_64 /* Good-instruction tables for 64-bit apps */ +#if defined(CONFIG_X86_64) static volatile u32 good_insns_64[256 / 32] = { /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ /* ---------------------------------------------- */ @@ -138,7 +115,33 @@ static volatile u32 good_insns_64[256 / 32] = { /* ---------------------------------------------- */ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ }; +#else +#define good_insns_64 NULL #endif + +/* Using this for both 64-bit and 32-bit apps */ +static volatile u32 good_2byte_insns[256 / 32] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ---------------------------------------------- */ + W(0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1) | /* 00 */ + W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) , /* 10 */ + W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) | /* 20 */ + W(0x30, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 30 */ + W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 40 */ + W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */ + W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 60 */ + W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1) , /* 70 */ + W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */ + W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */ + W(0xa0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1) | /* a0 */ + W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) , /* b0 */ + W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* c0 */ + W(0xd0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */ + W(0xe0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* e0 */ + W(0xf0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) /* f0 */ + /* ---------------------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; #undef W /* @@ -209,16 +212,25 @@ static bool is_prefix_bad(struct insn *insn) return false; } -static int validate_insn_32bits(struct arch_uprobe *auprobe, struct insn *insn) +static int uprobe_init_insn(struct arch_uprobe *auprobe, struct insn *insn, bool x86_64) { - insn_init(insn, auprobe->insn, false); + u32 volatile *good_insns; + + insn_init(insn, auprobe->insn, x86_64); + /* has the side-effect of processing the entire instruction */ + insn_get_length(insn); + if (WARN_ON_ONCE(!insn_complete(insn))) + return -ENOEXEC; - /* Skip good instruction prefixes; reject "bad" ones. */ - insn_get_opcode(insn); if (is_prefix_bad(insn)) return -ENOTSUPP; - if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_32)) + if (x86_64) + good_insns = good_insns_64; + else + good_insns = good_insns_32; + + if (test_bit(OPCODE1(insn), (unsigned long *)good_insns)) return 0; if (insn->opcode.nbytes == 2) { @@ -229,72 +241,19 @@ static int validate_insn_32bits(struct arch_uprobe *auprobe, struct insn *insn) return -ENOTSUPP; } -/* - * Figure out which fixups arch_uprobe_post_xol() will need to perform, and - * annotate arch_uprobe->fixups accordingly. To start with, - * arch_uprobe->fixups is either zero or it reflects rip-related fixups. - */ -static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn) +#ifdef CONFIG_X86_64 +static inline bool is_64bit_mm(struct mm_struct *mm) { - bool fix_ip = true, fix_call = false; /* defaults */ - int reg; - - insn_get_opcode(insn); /* should be a nop */ - - switch (OPCODE1(insn)) { - case 0x9d: - /* popf */ - auprobe->fixups |= UPROBE_FIX_SETF; - break; - case 0xc3: /* ret/lret */ - case 0xcb: - case 0xc2: - case 0xca: - /* ip is correct */ - fix_ip = false; - break; - case 0xe8: /* call relative - Fix return addr */ - fix_call = true; - break; - case 0x9a: /* call absolute - Fix return addr, not ip */ - fix_call = true; - fix_ip = false; - break; - case 0xff: - insn_get_modrm(insn); - reg = MODRM_REG(insn); - if (reg == 2 || reg == 3) { - /* call or lcall, indirect */ - /* Fix return addr; ip is correct. */ - fix_call = true; - fix_ip = false; - } else if (reg == 4 || reg == 5) { - /* jmp or ljmp, indirect */ - /* ip is correct. */ - fix_ip = false; - } - break; - case 0xea: /* jmp absolute -- ip is correct */ - fix_ip = false; - break; - default: - break; - } - if (fix_ip) - auprobe->fixups |= UPROBE_FIX_IP; - if (fix_call) - auprobe->fixups |= UPROBE_FIX_CALL; + return !config_enabled(CONFIG_IA32_EMULATION) || + !(mm->context.ia32_compat == TIF_IA32); } - -#ifdef CONFIG_X86_64 /* * If arch_uprobe->insn doesn't use rip-relative addressing, return * immediately. Otherwise, rewrite the instruction so that it accesses * its memory operand indirectly through a scratch register. Set - * arch_uprobe->fixups and arch_uprobe->rip_rela_target_address - * accordingly. (The contents of the scratch register will be saved - * before we single-step the modified instruction, and restored - * afterward.) + * def->fixups and def->riprel_target accordingly. (The contents of the + * scratch register will be saved before we single-step the modified + * instruction, and restored afterward). * * We do this because a rip-relative instruction can access only a * relatively small area (+/- 2 GB from the instruction), and the XOL @@ -309,16 +268,11 @@ static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn) * - There's never a SIB byte. * - The displacement is always 4 bytes. */ -static void -handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn) +static void riprel_analyze(struct arch_uprobe *auprobe, struct insn *insn) { u8 *cursor; u8 reg; - if (mm->context.ia32_compat) - return; - - auprobe->rip_rela_target_address = 0x0; if (!insn_rip_relative(insn)) return; @@ -338,8 +292,6 @@ handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct ins * is the immediate operand. */ cursor = auprobe->insn + insn_offset_modrm(insn); - insn_get_length(insn); - /* * Convert from rip-relative addressing to indirect addressing * via a scratch register. Change the r/m field from 0x5 (%rip) @@ -354,199 +306,395 @@ handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct ins * is NOT the register operand, so we use %rcx (register * #1) for the scratch register. */ - auprobe->fixups = UPROBE_FIX_RIP_CX; + auprobe->def.fixups |= UPROBE_FIX_RIP_CX; /* Change modrm from 00 000 101 to 00 000 001. */ *cursor = 0x1; } else { /* Use %rax (register #0) for the scratch register. */ - auprobe->fixups = UPROBE_FIX_RIP_AX; + auprobe->def.fixups |= UPROBE_FIX_RIP_AX; /* Change modrm from 00 xxx 101 to 00 xxx 000 */ *cursor = (reg << 3); } /* Target address = address of next instruction + (signed) offset */ - auprobe->rip_rela_target_address = (long)insn->length + insn->displacement.value; + auprobe->def.riprel_target = (long)insn->length + insn->displacement.value; /* Displacement field is gone; slide immediate field (if any) over. */ if (insn->immediate.nbytes) { cursor++; memmove(cursor, cursor + insn->displacement.nbytes, insn->immediate.nbytes); } - return; } -static int validate_insn_64bits(struct arch_uprobe *auprobe, struct insn *insn) +static inline unsigned long * +scratch_reg(struct arch_uprobe *auprobe, struct pt_regs *regs) { - insn_init(insn, auprobe->insn, true); - - /* Skip good instruction prefixes; reject "bad" ones. */ - insn_get_opcode(insn); - if (is_prefix_bad(insn)) - return -ENOTSUPP; + return (auprobe->def.fixups & UPROBE_FIX_RIP_AX) ? ®s->ax : ®s->cx; +} - if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_64)) - return 0; +/* + * If we're emulating a rip-relative instruction, save the contents + * of the scratch register and store the target address in that register. + */ +static void riprel_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + if (auprobe->def.fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) { + struct uprobe_task *utask = current->utask; + unsigned long *sr = scratch_reg(auprobe, regs); - if (insn->opcode.nbytes == 2) { - if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns)) - return 0; + utask->autask.saved_scratch_register = *sr; + *sr = utask->vaddr + auprobe->def.riprel_target; } - return -ENOTSUPP; } -static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn) +static void riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, + long *correction) { - if (mm->context.ia32_compat) - return validate_insn_32bits(auprobe, insn); - return validate_insn_64bits(auprobe, insn); + if (auprobe->def.fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) { + struct uprobe_task *utask = current->utask; + unsigned long *sr = scratch_reg(auprobe, regs); + + *sr = utask->autask.saved_scratch_register; + /* + * The original instruction includes a displacement, and so + * is 4 bytes longer than what we've just single-stepped. + * Caller may need to apply other fixups to handle stuff + * like "jmpq *...(%rip)" and "callq *...(%rip)". + */ + if (correction) + *correction += 4; + } } #else /* 32-bit: */ -static void handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn) +static inline bool is_64bit_mm(struct mm_struct *mm) { - /* No RIP-relative addressing on 32-bit */ + return false; } - -static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn) +/* + * No RIP-relative addressing on 32-bit + */ +static void riprel_analyze(struct arch_uprobe *auprobe, struct insn *insn) +{ +} +static void riprel_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ +} +static void riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, + long *correction) { - return validate_insn_32bits(auprobe, insn); } #endif /* CONFIG_X86_64 */ -/** - * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. - * @mm: the probed address space. - * @arch_uprobe: the probepoint information. - * @addr: virtual address at which to install the probepoint - * Return 0 on success or a -ve number on error. - */ -int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr) +struct uprobe_xol_ops { + bool (*emulate)(struct arch_uprobe *, struct pt_regs *); + int (*pre_xol)(struct arch_uprobe *, struct pt_regs *); + int (*post_xol)(struct arch_uprobe *, struct pt_regs *); + void (*abort)(struct arch_uprobe *, struct pt_regs *); +}; + +static inline int sizeof_long(void) { - int ret; - struct insn insn; + return is_ia32_task() ? 4 : 8; +} - auprobe->fixups = 0; - ret = validate_insn_bits(auprobe, mm, &insn); - if (ret != 0) - return ret; +static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + riprel_pre_xol(auprobe, regs); + return 0; +} - handle_riprel_insn(auprobe, mm, &insn); - prepare_fixups(auprobe, &insn); +static int push_ret_address(struct pt_regs *regs, unsigned long ip) +{ + unsigned long new_sp = regs->sp - sizeof_long(); + + if (copy_to_user((void __user *)new_sp, &ip, sizeof_long())) + return -EFAULT; + regs->sp = new_sp; return 0; } -#ifdef CONFIG_X86_64 -/* - * If we're emulating a rip-relative instruction, save the contents - * of the scratch register and store the target address in that register. - */ -static void -pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs, - struct arch_uprobe_task *autask) -{ - if (auprobe->fixups & UPROBE_FIX_RIP_AX) { - autask->saved_scratch_register = regs->ax; - regs->ax = current->utask->vaddr; - regs->ax += auprobe->rip_rela_target_address; - } else if (auprobe->fixups & UPROBE_FIX_RIP_CX) { - autask->saved_scratch_register = regs->cx; - regs->cx = current->utask->vaddr; - regs->cx += auprobe->rip_rela_target_address; +static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + long correction = (long)(utask->vaddr - utask->xol_vaddr); + + riprel_post_xol(auprobe, regs, &correction); + if (auprobe->def.fixups & UPROBE_FIX_IP) { + regs->ip += correction; + } else if (auprobe->def.fixups & UPROBE_FIX_CALL) { + regs->sp += sizeof_long(); + if (push_ret_address(regs, utask->vaddr + auprobe->def.ilen)) + return -ERESTART; } + /* popf; tell the caller to not touch TF */ + if (auprobe->def.fixups & UPROBE_FIX_SETF) + utask->autask.saved_tf = true; + + return 0; } -#else -static void -pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs, - struct arch_uprobe_task *autask) + +static void default_abort_op(struct arch_uprobe *auprobe, struct pt_regs *regs) { - /* No RIP-relative addressing on 32-bit */ + riprel_post_xol(auprobe, regs, NULL); } -#endif -/* - * arch_uprobe_pre_xol - prepare to execute out of line. - * @auprobe: the probepoint information. - * @regs: reflects the saved user state of current task. - */ -int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +static struct uprobe_xol_ops default_xol_ops = { + .pre_xol = default_pre_xol_op, + .post_xol = default_post_xol_op, + .abort = default_abort_op, +}; + +static bool branch_is_call(struct arch_uprobe *auprobe) { - struct arch_uprobe_task *autask; + return auprobe->branch.opc1 == 0xe8; +} - autask = ¤t->utask->autask; - autask->saved_trap_nr = current->thread.trap_nr; - current->thread.trap_nr = UPROBE_TRAP_NR; - regs->ip = current->utask->xol_vaddr; - pre_xol_rip_insn(auprobe, regs, autask); +#define CASE_COND \ + COND(70, 71, XF(OF)) \ + COND(72, 73, XF(CF)) \ + COND(74, 75, XF(ZF)) \ + COND(78, 79, XF(SF)) \ + COND(7a, 7b, XF(PF)) \ + COND(76, 77, XF(CF) || XF(ZF)) \ + COND(7c, 7d, XF(SF) != XF(OF)) \ + COND(7e, 7f, XF(ZF) || XF(SF) != XF(OF)) - autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF); - regs->flags |= X86_EFLAGS_TF; - if (test_tsk_thread_flag(current, TIF_BLOCKSTEP)) - set_task_blockstep(current, false); +#define COND(op_y, op_n, expr) \ + case 0x ## op_y: DO((expr) != 0) \ + case 0x ## op_n: DO((expr) == 0) - return 0; +#define XF(xf) (!!(flags & X86_EFLAGS_ ## xf)) + +static bool is_cond_jmp_opcode(u8 opcode) +{ + switch (opcode) { + #define DO(expr) \ + return true; + CASE_COND + #undef DO + + default: + return false; + } } -/* - * This function is called by arch_uprobe_post_xol() to adjust the return - * address pushed by a call instruction executed out of line. - */ -static int adjust_ret_addr(unsigned long sp, long correction) +static bool check_jmp_cond(struct arch_uprobe *auprobe, struct pt_regs *regs) { - int rasize, ncopied; - long ra = 0; + unsigned long flags = regs->flags; - if (is_ia32_task()) - rasize = 4; - else - rasize = 8; + switch (auprobe->branch.opc1) { + #define DO(expr) \ + return expr; + CASE_COND + #undef DO - ncopied = copy_from_user(&ra, (void __user *)sp, rasize); - if (unlikely(ncopied)) - return -EFAULT; + default: /* not a conditional jmp */ + return true; + } +} - ra += correction; - ncopied = copy_to_user((void __user *)sp, &ra, rasize); - if (unlikely(ncopied)) - return -EFAULT; +#undef XF +#undef COND +#undef CASE_COND - return 0; +static bool branch_emulate_op(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + unsigned long new_ip = regs->ip += auprobe->branch.ilen; + unsigned long offs = (long)auprobe->branch.offs; + + if (branch_is_call(auprobe)) { + /* + * If it fails we execute this (mangled, see the comment in + * branch_clear_offset) insn out-of-line. In the likely case + * this should trigger the trap, and the probed application + * should die or restart the same insn after it handles the + * signal, arch_uprobe_post_xol() won't be even called. + * + * But there is corner case, see the comment in ->post_xol(). + */ + if (push_ret_address(regs, new_ip)) + return false; + } else if (!check_jmp_cond(auprobe, regs)) { + offs = 0; + } + + regs->ip = new_ip + offs; + return true; } -#ifdef CONFIG_X86_64 -static bool is_riprel_insn(struct arch_uprobe *auprobe) +static int branch_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + BUG_ON(!branch_is_call(auprobe)); + /* + * We can only get here if branch_emulate_op() failed to push the ret + * address _and_ another thread expanded our stack before the (mangled) + * "call" insn was executed out-of-line. Just restore ->sp and restart. + * We could also restore ->ip and try to call branch_emulate_op() again. + */ + regs->sp += sizeof_long(); + return -ERESTART; +} + +static void branch_clear_offset(struct arch_uprobe *auprobe, struct insn *insn) { - return ((auprobe->fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) != 0); + /* + * Turn this insn into "call 1f; 1:", this is what we will execute + * out-of-line if ->emulate() fails. We only need this to generate + * a trap, so that the probed task receives the correct signal with + * the properly filled siginfo. + * + * But see the comment in ->post_xol(), in the unlikely case it can + * succeed. So we need to ensure that the new ->ip can not fall into + * the non-canonical area and trigger #GP. + * + * We could turn it into (say) "pushf", but then we would need to + * divorce ->insn[] and ->ixol[]. We need to preserve the 1st byte + * of ->insn[] for set_orig_insn(). + */ + memset(auprobe->insn + insn_offset_immediate(insn), + 0, insn->immediate.nbytes); } -static void -handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction) +static struct uprobe_xol_ops branch_xol_ops = { + .emulate = branch_emulate_op, + .post_xol = branch_post_xol_op, +}; + +/* Returns -ENOSYS if branch_xol_ops doesn't handle this insn */ +static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn) { - if (is_riprel_insn(auprobe)) { - struct arch_uprobe_task *autask; + u8 opc1 = OPCODE1(insn); + int i; + + switch (opc1) { + case 0xeb: /* jmp 8 */ + case 0xe9: /* jmp 32 */ + case 0x90: /* prefix* + nop; same as jmp with .offs = 0 */ + break; - autask = ¤t->utask->autask; - if (auprobe->fixups & UPROBE_FIX_RIP_AX) - regs->ax = autask->saved_scratch_register; - else - regs->cx = autask->saved_scratch_register; + case 0xe8: /* call relative */ + branch_clear_offset(auprobe, insn); + break; + case 0x0f: + if (insn->opcode.nbytes != 2) + return -ENOSYS; /* - * The original instruction includes a displacement, and so - * is 4 bytes longer than what we've just single-stepped. - * Fall through to handle stuff like "jmpq *...(%rip)" and - * "callq *...(%rip)". + * If it is a "near" conditional jmp, OPCODE2() - 0x10 matches + * OPCODE1() of the "short" jmp which checks the same condition. */ - if (correction) - *correction += 4; + opc1 = OPCODE2(insn) - 0x10; + default: + if (!is_cond_jmp_opcode(opc1)) + return -ENOSYS; } + + /* + * 16-bit overrides such as CALLW (66 e8 nn nn) are not supported. + * Intel and AMD behavior differ in 64-bit mode: Intel ignores 66 prefix. + * No one uses these insns, reject any branch insns with such prefix. + */ + for (i = 0; i < insn->prefixes.nbytes; i++) { + if (insn->prefixes.bytes[i] == 0x66) + return -ENOTSUPP; + } + + auprobe->branch.opc1 = opc1; + auprobe->branch.ilen = insn->length; + auprobe->branch.offs = insn->immediate.value; + + auprobe->ops = &branch_xol_ops; + return 0; } -#else -static void -handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction) + +/** + * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. + * @mm: the probed address space. + * @arch_uprobe: the probepoint information. + * @addr: virtual address at which to install the probepoint + * Return 0 on success or a -ve number on error. + */ +int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr) { - /* No RIP-relative addressing on 32-bit */ + struct insn insn; + u8 fix_ip_or_call = UPROBE_FIX_IP; + int ret; + + ret = uprobe_init_insn(auprobe, &insn, is_64bit_mm(mm)); + if (ret) + return ret; + + ret = branch_setup_xol_ops(auprobe, &insn); + if (ret != -ENOSYS) + return ret; + + /* + * Figure out which fixups default_post_xol_op() will need to perform, + * and annotate def->fixups accordingly. To start with, ->fixups is + * either zero or it reflects rip-related fixups. + */ + switch (OPCODE1(&insn)) { + case 0x9d: /* popf */ + auprobe->def.fixups |= UPROBE_FIX_SETF; + break; + case 0xc3: /* ret or lret -- ip is correct */ + case 0xcb: + case 0xc2: + case 0xca: + case 0xea: /* jmp absolute -- ip is correct */ + fix_ip_or_call = 0; + break; + case 0x9a: /* call absolute - Fix return addr, not ip */ + fix_ip_or_call = UPROBE_FIX_CALL; + break; + case 0xff: + switch (MODRM_REG(&insn)) { + case 2: case 3: /* call or lcall, indirect */ + fix_ip_or_call = UPROBE_FIX_CALL; + break; + case 4: case 5: /* jmp or ljmp, indirect */ + fix_ip_or_call = 0; + break; + } + /* fall through */ + default: + riprel_analyze(auprobe, &insn); + } + + auprobe->def.ilen = insn.length; + auprobe->def.fixups |= fix_ip_or_call; + + auprobe->ops = &default_xol_ops; + return 0; +} + +/* + * arch_uprobe_pre_xol - prepare to execute out of line. + * @auprobe: the probepoint information. + * @regs: reflects the saved user state of current task. + */ +int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + if (auprobe->ops->pre_xol) { + int err = auprobe->ops->pre_xol(auprobe, regs); + if (err) + return err; + } + + regs->ip = utask->xol_vaddr; + utask->autask.saved_trap_nr = current->thread.trap_nr; + current->thread.trap_nr = UPROBE_TRAP_NR; + + utask->autask.saved_tf = !!(regs->flags & X86_EFLAGS_TF); + regs->flags |= X86_EFLAGS_TF; + if (test_tsk_thread_flag(current, TIF_BLOCKSTEP)) + set_task_blockstep(current, false); + + return 0; } -#endif /* * If xol insn itself traps and generates a signal(Say, @@ -592,33 +740,39 @@ bool arch_uprobe_xol_was_trapped(struct task_struct *t) */ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) { - struct uprobe_task *utask; - long correction; - int result = 0; + struct uprobe_task *utask = current->utask; + bool send_sigtrap = utask->autask.saved_tf; + int err = 0; WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR); - - utask = current->utask; current->thread.trap_nr = utask->autask.saved_trap_nr; - correction = (long)(utask->vaddr - utask->xol_vaddr); - handle_riprel_post_xol(auprobe, regs, &correction); - if (auprobe->fixups & UPROBE_FIX_IP) - regs->ip += correction; - - if (auprobe->fixups & UPROBE_FIX_CALL) - result = adjust_ret_addr(regs->sp, correction); + if (auprobe->ops->post_xol) { + err = auprobe->ops->post_xol(auprobe, regs); + if (err) { + /* + * Restore ->ip for restart or post mortem analysis. + * ->post_xol() must not return -ERESTART unless this + * is really possible. + */ + regs->ip = utask->vaddr; + if (err == -ERESTART) + err = 0; + send_sigtrap = false; + } + } /* * arch_uprobe_pre_xol() doesn't save the state of TIF_BLOCKSTEP * so we can get an extra SIGTRAP if we do not clear TF. We need * to examine the opcode to make it right. */ - if (utask->autask.saved_tf) + if (send_sigtrap) send_sig(SIGTRAP, current, 0); - else if (!(auprobe->fixups & UPROBE_FIX_SETF)) + + if (!utask->autask.saved_tf) regs->flags &= ~X86_EFLAGS_TF; - return result; + return err; } /* callback routine for handling exceptions. */ @@ -652,41 +806,27 @@ int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, /* * This function gets called when XOL instruction either gets trapped or - * the thread has a fatal signal, so reset the instruction pointer to its - * probed address. + * the thread has a fatal signal. Reset the instruction pointer to its + * probed address for the potential restart or for post mortem analysis. */ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) { struct uprobe_task *utask = current->utask; - current->thread.trap_nr = utask->autask.saved_trap_nr; - handle_riprel_post_xol(auprobe, regs, NULL); - instruction_pointer_set(regs, utask->vaddr); + if (auprobe->ops->abort) + auprobe->ops->abort(auprobe, regs); + current->thread.trap_nr = utask->autask.saved_trap_nr; + regs->ip = utask->vaddr; /* clear TF if it was set by us in arch_uprobe_pre_xol() */ if (!utask->autask.saved_tf) regs->flags &= ~X86_EFLAGS_TF; } -/* - * Skip these instructions as per the currently known x86 ISA. - * rep=0x66*; nop=0x90 - */ static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) { - int i; - - for (i = 0; i < MAX_UINSN_BYTES; i++) { - if (auprobe->insn[i] == 0x66) - continue; - - if (auprobe->insn[i] == 0x90) { - regs->ip += i + 1; - return true; - } - - break; - } + if (auprobe->ops->emulate) + return auprobe->ops->emulate(auprobe, regs); return false; } @@ -701,23 +841,21 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs) { - int rasize, ncopied; + int rasize = sizeof_long(), nleft; unsigned long orig_ret_vaddr = 0; /* clear high bits for 32-bit apps */ - rasize = is_ia32_task() ? 4 : 8; - ncopied = copy_from_user(&orig_ret_vaddr, (void __user *)regs->sp, rasize); - if (unlikely(ncopied)) + if (copy_from_user(&orig_ret_vaddr, (void __user *)regs->sp, rasize)) return -1; /* check whether address has been already hijacked */ if (orig_ret_vaddr == trampoline_vaddr) return orig_ret_vaddr; - ncopied = copy_to_user((void __user *)regs->sp, &trampoline_vaddr, rasize); - if (likely(!ncopied)) + nleft = copy_to_user((void __user *)regs->sp, &trampoline_vaddr, rasize); + if (likely(!nleft)) return orig_ret_vaddr; - if (ncopied != rasize) { + if (nleft != rasize) { pr_err("uprobe: return address clobbered: pid=%d, %%sp=%#lx, " "%%ip=%#lx\n", current->pid, regs->sp, regs->ip); diff --git a/arch/x86/kernel/vsmp_64.c b/arch/x86/kernel/vsmp_64.c index 5edc34b5b9514d..b99b9ad8540c52 100644 --- a/arch/x86/kernel/vsmp_64.c +++ b/arch/x86/kernel/vsmp_64.c @@ -36,7 +36,7 @@ static int irq_routing_comply = 1; * and vice versa. */ -asmlinkage unsigned long vsmp_save_fl(void) +asmlinkage __visible unsigned long vsmp_save_fl(void) { unsigned long flags = native_save_fl(); @@ -56,7 +56,7 @@ __visible void vsmp_restore_fl(unsigned long flags) } PV_CALLEE_SAVE_REGS_THUNK(vsmp_restore_fl); -asmlinkage void vsmp_irq_disable(void) +asmlinkage __visible void vsmp_irq_disable(void) { unsigned long flags = native_save_fl(); @@ -64,7 +64,7 @@ asmlinkage void vsmp_irq_disable(void) } PV_CALLEE_SAVE_REGS_THUNK(vsmp_irq_disable); -asmlinkage void vsmp_irq_enable(void) +asmlinkage __visible void vsmp_irq_enable(void) { unsigned long flags = native_save_fl(); diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index 8b3b3eb3cead2d..ea5b5709aa76ac 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c @@ -91,7 +91,7 @@ static int addr_to_vsyscall_nr(unsigned long addr) { int nr; - if ((addr & ~0xC00UL) != VSYSCALL_START) + if ((addr & ~0xC00UL) != VSYSCALL_ADDR) return -EINVAL; nr = (addr & 0xC00UL) >> 10; @@ -330,24 +330,17 @@ void __init map_vsyscall(void) { extern char __vsyscall_page; unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page); - unsigned long physaddr_vvar_page = __pa_symbol(&__vvar_page); - __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_vsyscall, + __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall, vsyscall_mode == NATIVE ? PAGE_KERNEL_VSYSCALL : PAGE_KERNEL_VVAR); - BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_FIRST_PAGE) != - (unsigned long)VSYSCALL_START); - - __set_fixmap(VVAR_PAGE, physaddr_vvar_page, PAGE_KERNEL_VVAR); - BUILD_BUG_ON((unsigned long)__fix_to_virt(VVAR_PAGE) != - (unsigned long)VVAR_ADDRESS); + BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_PAGE) != + (unsigned long)VSYSCALL_ADDR); } static int __init vsyscall_init(void) { - BUG_ON(VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE)); - cpu_notifier_register_begin(); on_each_cpu(cpu_vsyscall_init, NULL, 1); diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index f47a104a749cd9..333b88db22fe4e 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -495,6 +495,13 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, entry->ecx &= kvm_supported_word6_x86_features; cpuid_mask(&entry->ecx, 6); break; + case 0x80000007: /* Advanced power management */ + /* invariant TSC is CPUID.80000007H:EDX[8] */ + entry->edx &= (1 << 8); + /* mask against host */ + entry->edx &= boot_cpu_data.x86_power; + entry->eax = entry->ebx = entry->ecx = 0; + break; case 0x80000008: { unsigned g_phys_as = (entry->eax >> 16) & 0xff; unsigned virt_as = max((entry->eax >> 8) & 0xff, 48U); @@ -525,7 +532,6 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, case 3: /* Processor serial number */ case 5: /* MONITOR/MWAIT */ case 6: /* Thermal management */ - case 0x80000007: /* Advanced power management */ case 0xC0000002: case 0xC0000003: case 0xC0000004: diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 205b17eed93c2b..e8a58409b5ac0e 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1324,7 +1324,8 @@ static int pio_in_emulated(struct x86_emulate_ctxt *ctxt, rc->end = n * size; } - if (ctxt->rep_prefix && !(ctxt->eflags & EFLG_DF)) { + if (ctxt->rep_prefix && (ctxt->d & String) && + !(ctxt->eflags & EFLG_DF)) { ctxt->dst.data = rc->data + rc->pos; ctxt->dst.type = OP_MEM_STR; ctxt->dst.count = (rc->end - rc->pos) / size; @@ -2496,7 +2497,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, static void save_state_to_tss32(struct x86_emulate_ctxt *ctxt, struct tss_segment_32 *tss) { - tss->cr3 = ctxt->ops->get_cr(ctxt, 3); + /* CR3 and ldt selector are not saved intentionally */ tss->eip = ctxt->_eip; tss->eflags = ctxt->eflags; tss->eax = reg_read(ctxt, VCPU_REGS_RAX); @@ -2514,7 +2515,6 @@ static void save_state_to_tss32(struct x86_emulate_ctxt *ctxt, tss->ds = get_segment_selector(ctxt, VCPU_SREG_DS); tss->fs = get_segment_selector(ctxt, VCPU_SREG_FS); tss->gs = get_segment_selector(ctxt, VCPU_SREG_GS); - tss->ldt_selector = get_segment_selector(ctxt, VCPU_SREG_LDTR); } static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt, @@ -2604,6 +2604,8 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, struct tss_segment_32 tss_seg; int ret; u32 new_tss_base = get_desc_base(new_desc); + u32 eip_offset = offsetof(struct tss_segment_32, eip); + u32 ldt_sel_offset = offsetof(struct tss_segment_32, ldt_selector); ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, &ctxt->exception); @@ -2613,8 +2615,9 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, save_state_to_tss32(ctxt, &tss_seg); - ret = ops->write_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + /* Only GP registers and segment selectors are saved */ + ret = ops->write_std(ctxt, old_tss_base + eip_offset, &tss_seg.eip, + ldt_sel_offset - eip_offset, &ctxt->exception); if (ret != X86EMUL_CONTINUE) /* FIXME: need to provide precise fault address */ return ret; @@ -3386,10 +3389,6 @@ static int check_cr_write(struct x86_emulate_ctxt *ctxt) ctxt->ops->get_msr(ctxt, MSR_EFER, &efer); if (efer & EFER_LMA) rsvd = CR3_L_MODE_RESERVED_BITS; - else if (ctxt->ops->get_cr(ctxt, 4) & X86_CR4_PAE) - rsvd = CR3_PAE_RESERVED_BITS; - else if (ctxt->ops->get_cr(ctxt, 0) & X86_CR0_PG) - rsvd = CR3_NONPAE_RESERVED_BITS; if (new_val & rsvd) return emulate_gp(ctxt, 0); diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index 484bc874688b4b..bd0da433e6d724 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -113,6 +113,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v) return kvm_get_apic_interrupt(v); /* APIC */ } +EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) { diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 813d31038b93bf..65f2400b8268e4 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -595,7 +595,8 @@ static bool mmu_spte_update(u64 *sptep, u64 new_spte) * we always atomicly update it, see the comments in * spte_has_volatile_bits(). */ - if (is_writable_pte(old_spte) && !is_writable_pte(new_spte)) + if (spte_is_locklessly_modifiable(old_spte) && + !is_writable_pte(new_spte)) ret = true; if (!shadow_accessed_mask) @@ -1176,8 +1177,7 @@ static void drop_large_spte(struct kvm_vcpu *vcpu, u64 *sptep) /* * Write-protect on the specified @sptep, @pt_protect indicates whether - * spte writ-protection is caused by protecting shadow page table. - * @flush indicates whether tlb need be flushed. + * spte write-protection is caused by protecting shadow page table. * * Note: write protection is difference between drity logging and spte * protection: @@ -1186,10 +1186,9 @@ static void drop_large_spte(struct kvm_vcpu *vcpu, u64 *sptep) * - for spte protection, the spte can be writable only after unsync-ing * shadow page. * - * Return true if the spte is dropped. + * Return true if tlb need be flushed. */ -static bool -spte_write_protect(struct kvm *kvm, u64 *sptep, bool *flush, bool pt_protect) +static bool spte_write_protect(struct kvm *kvm, u64 *sptep, bool pt_protect) { u64 spte = *sptep; @@ -1199,17 +1198,11 @@ spte_write_protect(struct kvm *kvm, u64 *sptep, bool *flush, bool pt_protect) rmap_printk("rmap_write_protect: spte %p %llx\n", sptep, *sptep); - if (__drop_large_spte(kvm, sptep)) { - *flush |= true; - return true; - } - if (pt_protect) spte &= ~SPTE_MMU_WRITEABLE; spte = spte & ~PT_WRITABLE_MASK; - *flush |= mmu_spte_update(sptep, spte); - return false; + return mmu_spte_update(sptep, spte); } static bool __rmap_write_protect(struct kvm *kvm, unsigned long *rmapp, @@ -1221,11 +1214,8 @@ static bool __rmap_write_protect(struct kvm *kvm, unsigned long *rmapp, for (sptep = rmap_get_first(*rmapp, &iter); sptep;) { BUG_ON(!(*sptep & PT_PRESENT_MASK)); - if (spte_write_protect(kvm, sptep, &flush, pt_protect)) { - sptep = rmap_get_first(*rmapp, &iter); - continue; - } + flush |= spte_write_protect(kvm, sptep, pt_protect); sptep = rmap_get_next(&iter); } @@ -2802,9 +2792,9 @@ static bool page_fault_can_be_fast(u32 error_code) } static bool -fast_pf_fix_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep, u64 spte) +fast_pf_fix_direct_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, + u64 *sptep, u64 spte) { - struct kvm_mmu_page *sp = page_header(__pa(sptep)); gfn_t gfn; WARN_ON(!sp->role.direct); @@ -2830,6 +2820,7 @@ static bool fast_page_fault(struct kvm_vcpu *vcpu, gva_t gva, int level, u32 error_code) { struct kvm_shadow_walk_iterator iterator; + struct kvm_mmu_page *sp; bool ret = false; u64 spte = 0ull; @@ -2853,7 +2844,8 @@ static bool fast_page_fault(struct kvm_vcpu *vcpu, gva_t gva, int level, goto exit; } - if (!is_last_spte(spte, level)) + sp = page_header(__pa(iterator.sptep)); + if (!is_last_spte(spte, sp->role.level)) goto exit; /* @@ -2874,12 +2866,25 @@ static bool fast_page_fault(struct kvm_vcpu *vcpu, gva_t gva, int level, if (!spte_is_locklessly_modifiable(spte)) goto exit; + /* + * Do not fix write-permission on the large spte since we only dirty + * the first page into the dirty-bitmap in fast_pf_fix_direct_spte() + * that means other pages are missed if its slot is dirty-logged. + * + * Instead, we let the slow page fault path create a normal spte to + * fix the access. + * + * See the comments in kvm_arch_commit_memory_region(). + */ + if (sp->role.level > PT_PAGE_TABLE_LEVEL) + goto exit; + /* * Currently, fast page fault only works for direct mapping since * the gfn is not stable for indirect shadow page. * See Documentation/virtual/kvm/locking.txt to get more detail. */ - ret = fast_pf_fix_direct_spte(vcpu, iterator.sptep, spte); + ret = fast_pf_fix_direct_spte(vcpu, sp, iterator.sptep, spte); exit: trace_fast_page_fault(vcpu, gva, error_code, iterator.sptep, spte, ret); @@ -3538,7 +3543,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, case PT32E_ROOT_LEVEL: context->rsvd_bits_mask[0][2] = rsvd_bits(maxphyaddr, 63) | - rsvd_bits(7, 8) | rsvd_bits(1, 2); /* PDPTE */ + rsvd_bits(5, 8) | rsvd_bits(1, 2); /* PDPTE */ context->rsvd_bits_mask[0][1] = exb_bit_rsvd | rsvd_bits(maxphyaddr, 62); /* PDE */ context->rsvd_bits_mask[0][0] = exb_bit_rsvd | @@ -3550,9 +3555,9 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, break; case PT64_ROOT_LEVEL: context->rsvd_bits_mask[0][3] = exb_bit_rsvd | - rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8); + rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7); context->rsvd_bits_mask[0][2] = exb_bit_rsvd | - rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8); + rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7); context->rsvd_bits_mask[0][1] = exb_bit_rsvd | rsvd_bits(maxphyaddr, 51); context->rsvd_bits_mask[0][0] = exb_bit_rsvd | @@ -4304,15 +4309,32 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot) if (*rmapp) __rmap_write_protect(kvm, rmapp, false); - if (need_resched() || spin_needbreak(&kvm->mmu_lock)) { - kvm_flush_remote_tlbs(kvm); + if (need_resched() || spin_needbreak(&kvm->mmu_lock)) cond_resched_lock(&kvm->mmu_lock); - } } } - kvm_flush_remote_tlbs(kvm); spin_unlock(&kvm->mmu_lock); + + /* + * kvm_mmu_slot_remove_write_access() and kvm_vm_ioctl_get_dirty_log() + * which do tlb flush out of mmu-lock should be serialized by + * kvm->slots_lock otherwise tlb flush would be missed. + */ + lockdep_assert_held(&kvm->slots_lock); + + /* + * We can flush all the TLBs out of the mmu lock without TLB + * corruption since we just change the spte from writable to + * readonly so that we only need to care the case of changing + * spte from present to present (changing the spte from present + * to nonpresent will flush all the TLBs immediately), in other + * words, the only case we care is mmu_spte_update() where we + * haved checked SPTE_HOST_WRITEABLE | SPTE_MMU_WRITEABLE + * instead of PT_WRITABLE_MASK, that means it does not depend + * on PT_WRITABLE_MASK anymore. + */ + kvm_flush_remote_tlbs(kvm); } #define BATCH_ZAP_PAGES 10 diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 3842e70bdb7cf9..b982112d2ca5a9 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -104,6 +104,39 @@ static inline int is_present_gpte(unsigned long pte) return pte & PT_PRESENT_MASK; } +/* + * Currently, we have two sorts of write-protection, a) the first one + * write-protects guest page to sync the guest modification, b) another one is + * used to sync dirty bitmap when we do KVM_GET_DIRTY_LOG. The differences + * between these two sorts are: + * 1) the first case clears SPTE_MMU_WRITEABLE bit. + * 2) the first case requires flushing tlb immediately avoiding corrupting + * shadow page table between all vcpus so it should be in the protection of + * mmu-lock. And the another case does not need to flush tlb until returning + * the dirty bitmap to userspace since it only write-protects the page + * logged in the bitmap, that means the page in the dirty bitmap is not + * missed, so it can flush tlb out of mmu-lock. + * + * So, there is the problem: the first case can meet the corrupted tlb caused + * by another case which write-protects pages but without flush tlb + * immediately. In order to making the first case be aware this problem we let + * it flush tlb if we try to write-protect a spte whose SPTE_MMU_WRITEABLE bit + * is set, it works since another case never touches SPTE_MMU_WRITEABLE bit. + * + * Anyway, whenever a spte is updated (only permission and status bits are + * changed) we need to check whether the spte with SPTE_MMU_WRITEABLE becomes + * readonly, if that happens, we need to flush tlb. Fortunately, + * mmu_spte_update() has already handled it perfectly. + * + * The rules to use SPTE_MMU_WRITEABLE and PT_WRITABLE_MASK: + * - if we want to see if it has writable tlb entry or if the spte can be + * writable on the mmu mapping, check SPTE_MMU_WRITEABLE, this is the most + * case, otherwise + * - if we fix page fault on the spte or do write-protection by dirty logging, + * check PT_WRITABLE_MASK. + * + * TODO: introduce APIs to split these two cases. + */ static inline int is_writable_pte(unsigned long pte) { return pte & PT_WRITABLE_MASK; diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 123efd3ec29f2e..41077652826589 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -913,8 +913,7 @@ static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gva_t vaddr, * and kvm_mmu_notifier_invalidate_range_start detect the mapping page isn't * used by guest then tlbs are not flushed, so guest is allowed to access the * freed pages. - * We set tlbs_dirty to let the notifier know this change and delay the flush - * until such a case actually happens. + * And we increase kvm->tlbs_dirty to delay tlbs flush in this case. */ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) { @@ -943,7 +942,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) return -EINVAL; if (FNAME(prefetch_invalid_gpte)(vcpu, sp, &sp->spt[i], gpte)) { - vcpu->kvm->tlbs_dirty = true; + vcpu->kvm->tlbs_dirty++; continue; } @@ -958,7 +957,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) if (gfn != sp->gfns[i]) { drop_spte(vcpu->kvm, &sp->spt[i]); - vcpu->kvm->tlbs_dirty = true; + vcpu->kvm->tlbs_dirty++; continue; } diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 5c4f63151b4d90..cbecaa90399c1f 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -108,7 +108,10 @@ static void kvm_perf_overflow(struct perf_event *perf_event, { struct kvm_pmc *pmc = perf_event->overflow_handler_context; struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu; - __set_bit(pmc->idx, (unsigned long *)&pmu->global_status); + if (!test_and_set_bit(pmc->idx, (unsigned long *)&pmu->reprogram_pmi)) { + __set_bit(pmc->idx, (unsigned long *)&pmu->global_status); + kvm_make_request(KVM_REQ_PMU, pmc->vcpu); + } } static void kvm_perf_overflow_intr(struct perf_event *perf_event, @@ -117,7 +120,7 @@ static void kvm_perf_overflow_intr(struct perf_event *perf_event, struct kvm_pmc *pmc = perf_event->overflow_handler_context; struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu; if (!test_and_set_bit(pmc->idx, (unsigned long *)&pmu->reprogram_pmi)) { - kvm_perf_overflow(perf_event, data, regs); + __set_bit(pmc->idx, (unsigned long *)&pmu->global_status); kvm_make_request(KVM_REQ_PMU, pmc->vcpu); /* * Inject PMI. If vcpu was in a guest mode during NMI PMI diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 33e8c028842fb4..3cdadda7ec638d 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2283,7 +2283,7 @@ static __init void nested_vmx_setup_ctls_msrs(void) rdmsr(MSR_IA32_VMX_EXIT_CTLS, nested_vmx_exit_ctls_low, nested_vmx_exit_ctls_high); nested_vmx_exit_ctls_low = VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR; - /* Note that guest use of VM_EXIT_ACK_INTR_ON_EXIT is not supported. */ + nested_vmx_exit_ctls_high &= #ifdef CONFIG_X86_64 VM_EXIT_HOST_ADDR_SPACE_SIZE | @@ -2291,7 +2291,8 @@ static __init void nested_vmx_setup_ctls_msrs(void) VM_EXIT_LOAD_IA32_PAT | VM_EXIT_SAVE_IA32_PAT; nested_vmx_exit_ctls_high |= VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | VM_EXIT_LOAD_IA32_EFER | VM_EXIT_SAVE_IA32_EFER | - VM_EXIT_SAVE_VMX_PREEMPTION_TIMER; + VM_EXIT_SAVE_VMX_PREEMPTION_TIMER | VM_EXIT_ACK_INTR_ON_EXIT; + if (vmx_mpx_supported()) nested_vmx_exit_ctls_high |= VM_EXIT_CLEAR_BNDCFGS; @@ -2353,12 +2354,11 @@ static __init void nested_vmx_setup_ctls_msrs(void) VMX_EPT_INVEPT_BIT; nested_vmx_ept_caps &= vmx_capability.ept; /* - * Since invept is completely emulated we support both global - * and context invalidation independent of what host cpu - * supports + * For nested guests, we don't do anything specific + * for single context invalidation. Hence, only advertise + * support for global context invalidation. */ - nested_vmx_ept_caps |= VMX_EPT_EXTENT_GLOBAL_BIT | - VMX_EPT_EXTENT_CONTEXT_BIT; + nested_vmx_ept_caps |= VMX_EPT_EXTENT_GLOBAL_BIT; } else nested_vmx_ept_caps = 0; @@ -4564,6 +4564,16 @@ static bool nested_exit_on_intr(struct kvm_vcpu *vcpu) PIN_BASED_EXT_INTR_MASK; } +/* + * In nested virtualization, check if L1 has set + * VM_EXIT_ACK_INTR_ON_EXIT + */ +static bool nested_exit_intr_ack_set(struct kvm_vcpu *vcpu) +{ + return get_vmcs12(vcpu)->vm_exit_controls & + VM_EXIT_ACK_INTR_ON_EXIT; +} + static bool nested_exit_on_nmi(struct kvm_vcpu *vcpu) { return get_vmcs12(vcpu)->pin_based_vm_exec_control & @@ -4878,6 +4888,9 @@ static int handle_exception(struct kvm_vcpu *vcpu) (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) { vcpu->arch.dr6 &= ~15; vcpu->arch.dr6 |= dr6; + if (!(dr6 & ~DR6_RESERVED)) /* icebp */ + skip_emulated_instruction(vcpu); + kvm_queue_exception(vcpu, DB_VECTOR); return 1; } @@ -5565,6 +5578,10 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu) gpa_t gpa; gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS); + if (!kvm_io_bus_write(vcpu->kvm, KVM_FAST_MMIO_BUS, gpa, 0, NULL)) { + skip_emulated_instruction(vcpu); + return 1; + } ret = handle_mmio_page_fault_common(vcpu, gpa, true); if (likely(ret == RET_MMIO_PF_EMULATE)) @@ -6471,7 +6488,6 @@ static int handle_invept(struct kvm_vcpu *vcpu) struct { u64 eptp, gpa; } operand; - u64 eptp_mask = ((1ull << 51) - 1) & PAGE_MASK; if (!(nested_vmx_secondary_ctls_high & SECONDARY_EXEC_ENABLE_EPT) || !(nested_vmx_ept_caps & VMX_EPT_INVEPT_BIT)) { @@ -6511,16 +6527,13 @@ static int handle_invept(struct kvm_vcpu *vcpu) } switch (type) { - case VMX_EPT_EXTENT_CONTEXT: - if ((operand.eptp & eptp_mask) != - (nested_ept_get_cr3(vcpu) & eptp_mask)) - break; case VMX_EPT_EXTENT_GLOBAL: kvm_mmu_sync_roots(vcpu); kvm_mmu_flush_tlb(vcpu); nested_vmx_succeed(vcpu); break; default: + /* Trap single context invalidation invept calls */ BUG_ON(1); break; } @@ -8598,6 +8611,14 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, prepare_vmcs12(vcpu, vmcs12, exit_reason, exit_intr_info, exit_qualification); + if ((exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT) + && nested_exit_intr_ack_set(vcpu)) { + int irq = kvm_cpu_get_interrupt(vcpu); + WARN_ON(irq < 0); + vmcs12->vm_exit_intr_info = irq | + INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR; + } + trace_kvm_nested_vmexit_inject(vmcs12->vm_exit_reason, vmcs12->exit_qualification, vmcs12->idt_vectoring_info_field, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8b8fc0b792baed..f052ac1dce2d6e 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -280,7 +280,7 @@ int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info) } EXPORT_SYMBOL_GPL(kvm_set_apic_base); -asmlinkage void kvm_spurious_fault(void) +asmlinkage __visible void kvm_spurious_fault(void) { /* Fault while not rebooting. We want the trace. */ BUG(); @@ -701,26 +701,11 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) return 0; } - if (is_long_mode(vcpu)) { - if (kvm_read_cr4_bits(vcpu, X86_CR4_PCIDE)) { - if (cr3 & CR3_PCID_ENABLED_RESERVED_BITS) - return 1; - } else - if (cr3 & CR3_L_MODE_RESERVED_BITS) - return 1; - } else { - if (is_pae(vcpu)) { - if (cr3 & CR3_PAE_RESERVED_BITS) - return 1; - if (is_paging(vcpu) && - !load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3)) - return 1; - } - /* - * We don't check reserved bits in nonpae mode, because - * this isn't enforced, and VMware depends on this. - */ - } + if (is_long_mode(vcpu) && (cr3 & CR3_L_MODE_RESERVED_BITS)) + return 1; + if (is_pae(vcpu) && is_paging(vcpu) && + !load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3)) + return 1; vcpu->arch.cr3 = cr3; __set_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail); @@ -2644,6 +2629,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_IRQ_INJECT_STATUS: case KVM_CAP_IRQFD: case KVM_CAP_IOEVENTFD: + case KVM_CAP_IOEVENTFD_NO_LENGTH: case KVM_CAP_PIT2: case KVM_CAP_PIT_STATE2: case KVM_CAP_SET_IDENTITY_MAP_ADDR: @@ -3646,11 +3632,19 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) offset = i * BITS_PER_LONG; kvm_mmu_write_protect_pt_masked(kvm, memslot, offset, mask); } - if (is_dirty) - kvm_flush_remote_tlbs(kvm); spin_unlock(&kvm->mmu_lock); + /* See the comments in kvm_mmu_slot_remove_write_access(). */ + lockdep_assert_held(&kvm->slots_lock); + + /* + * All the TLBs can be flushed out of mmu lock, see the comments in + * kvm_mmu_slot_remove_write_access(). + */ + if (is_dirty) + kvm_flush_remote_tlbs(kvm); + r = -EFAULT; if (copy_to_user(log->dirty_bitmap, dirty_bitmap_buffer, n)) goto out; @@ -4902,7 +4896,7 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu) ctxt->eip = kvm_rip_read(vcpu); ctxt->mode = (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL : (ctxt->eflags & X86_EFLAGS_VM) ? X86EMUL_MODE_VM86 : - cs_l ? X86EMUL_MODE_PROT64 : + (cs_l && is_long_mode(vcpu)) ? X86EMUL_MODE_PROT64 : cs_db ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; ctxt->guest_mode = is_guest_mode(vcpu); @@ -7329,8 +7323,12 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, kvm_mmu_change_mmu_pages(kvm, nr_mmu_pages); /* * Write protect all pages for dirty logging. - * Existing largepage mappings are destroyed here and new ones will - * not be created until the end of the logging. + * + * All the sptes including the large sptes which point to this + * slot are set to readonly. We can not create any new large + * spte on this slot until the end of the logging. + * + * See the comments in fast_page_fault(). */ if ((change != KVM_MR_DELETE) && (mem->flags & KVM_MEM_LOG_DIRTY_PAGES)) kvm_mmu_slot_remove_write_access(kvm, mem->slot); diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index ad1fb5f53925e8..aae94132bc24dd 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -233,13 +233,13 @@ static void lguest_end_context_switch(struct task_struct *next) * flags word contains all kind of stuff, but in practice Linux only cares * about the interrupt flag. Our "save_flags()" just returns that. */ -asmlinkage unsigned long lguest_save_fl(void) +asmlinkage __visible unsigned long lguest_save_fl(void) { return lguest_data.irq_enabled; } /* Interrupts go off... */ -asmlinkage void lguest_irq_disable(void) +asmlinkage __visible void lguest_irq_disable(void) { lguest_data.irq_enabled = 0; } diff --git a/arch/x86/lib/thunk_32.S b/arch/x86/lib/thunk_32.S index 2930ae05d77305..28f85c91671223 100644 --- a/arch/x86/lib/thunk_32.S +++ b/arch/x86/lib/thunk_32.S @@ -4,8 +4,8 @@ * (inspired by Andi Kleen's thunk_64.S) * Subject to the GNU public license, v.2. No warranty of any kind. */ - #include + #include #ifdef CONFIG_TRACE_IRQFLAGS /* put return address in eax (arg1) */ @@ -22,6 +22,7 @@ popl %ecx popl %eax ret + _ASM_NOKPROBE(\name) .endm thunk_ra trace_hardirqs_on_thunk,trace_hardirqs_on_caller diff --git a/arch/x86/lib/thunk_64.S b/arch/x86/lib/thunk_64.S index a63efd6bb6a5a2..92d9feaff42b04 100644 --- a/arch/x86/lib/thunk_64.S +++ b/arch/x86/lib/thunk_64.S @@ -8,6 +8,7 @@ #include #include #include +#include /* rdi: arg1 ... normal C conventions. rax is saved/restored. */ .macro THUNK name, func, put_ret_addr_in_rdi=0 @@ -25,6 +26,7 @@ call \func jmp restore CFI_ENDPROC + _ASM_NOKPROBE(\name) .endm #ifdef CONFIG_TRACE_IRQFLAGS @@ -43,3 +45,4 @@ restore: RESTORE_ARGS ret CFI_ENDPROC + _ASM_NOKPROBE(restore) diff --git a/arch/x86/math-emu/errors.c b/arch/x86/math-emu/errors.c index a5449089cd9fef..9e6545f269e548 100644 --- a/arch/x86/math-emu/errors.c +++ b/arch/x86/math-emu/errors.c @@ -302,7 +302,7 @@ static struct { 0x242 in div_Xsig.S */ -asmlinkage void FPU_exception(int n) +asmlinkage __visible void FPU_exception(int n) { int i, int_type; @@ -492,7 +492,7 @@ int real_2op_NaN(FPU_REG const *b, u_char tagb, /* Invalid arith operation on Valid registers */ /* Returns < 0 if the exception is unmasked */ -asmlinkage int arith_invalid(int deststnr) +asmlinkage __visible int arith_invalid(int deststnr) { EXCEPTION(EX_Invalid); @@ -507,7 +507,7 @@ asmlinkage int arith_invalid(int deststnr) } /* Divide a finite number by zero */ -asmlinkage int FPU_divide_by_zero(int deststnr, u_char sign) +asmlinkage __visible int FPU_divide_by_zero(int deststnr, u_char sign) { FPU_REG *dest = &st(deststnr); int tag = TAG_Valid; @@ -539,7 +539,7 @@ int set_precision_flag(int flags) } /* This may be called often, so keep it lean */ -asmlinkage void set_precision_flag_up(void) +asmlinkage __visible void set_precision_flag_up(void) { if (control_word & CW_Precision) partial_status |= (SW_Precision | SW_C1); /* The masked response */ @@ -548,7 +548,7 @@ asmlinkage void set_precision_flag_up(void) } /* This may be called often, so keep it lean */ -asmlinkage void set_precision_flag_down(void) +asmlinkage __visible void set_precision_flag_down(void) { if (control_word & CW_Precision) { /* The masked response */ partial_status &= ~SW_C1; @@ -557,7 +557,7 @@ asmlinkage void set_precision_flag_down(void) EXCEPTION(EX_Precision); } -asmlinkage int denormal_operand(void) +asmlinkage __visible int denormal_operand(void) { if (control_word & CW_Denormal) { /* The masked response */ partial_status |= SW_Denorm_Op; @@ -568,7 +568,7 @@ asmlinkage int denormal_operand(void) } } -asmlinkage int arith_overflow(FPU_REG *dest) +asmlinkage __visible int arith_overflow(FPU_REG *dest) { int tag = TAG_Valid; @@ -596,7 +596,7 @@ asmlinkage int arith_overflow(FPU_REG *dest) } -asmlinkage int arith_underflow(FPU_REG *dest) +asmlinkage __visible int arith_underflow(FPU_REG *dest) { int tag = TAG_Valid; diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c index 20621d753d5fb4..167ffcac16ed19 100644 --- a/arch/x86/mm/dump_pagetables.c +++ b/arch/x86/mm/dump_pagetables.c @@ -30,12 +30,14 @@ struct pg_state { unsigned long start_address; unsigned long current_address; const struct addr_marker *marker; + unsigned long lines; bool to_dmesg; }; struct addr_marker { unsigned long start_address; const char *name; + unsigned long max_lines; }; /* indices for address_markers; keep sync'd w/ address_markers below */ @@ -46,6 +48,7 @@ enum address_markers_idx { LOW_KERNEL_NR, VMALLOC_START_NR, VMEMMAP_START_NR, + ESPFIX_START_NR, HIGH_KERNEL_NR, MODULES_VADDR_NR, MODULES_END_NR, @@ -68,6 +71,7 @@ static struct addr_marker address_markers[] = { { PAGE_OFFSET, "Low Kernel Mapping" }, { VMALLOC_START, "vmalloc() Area" }, { VMEMMAP_START, "Vmemmap" }, + { ESPFIX_BASE_ADDR, "ESPfix Area", 16 }, { __START_KERNEL_map, "High Kernel Mapping" }, { MODULES_VADDR, "Modules" }, { MODULES_END, "End Modules" }, @@ -182,7 +186,7 @@ static void note_page(struct seq_file *m, struct pg_state *st, pgprot_t new_prot, int level) { pgprotval_t prot, cur; - static const char units[] = "KMGTPE"; + static const char units[] = "BKMGTPE"; /* * If we have a "break" in the series, we need to flush the state that @@ -197,6 +201,7 @@ static void note_page(struct seq_file *m, struct pg_state *st, st->current_prot = new_prot; st->level = level; st->marker = address_markers; + st->lines = 0; pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n", st->marker->name); } else if (prot != cur || level != st->level || @@ -208,17 +213,24 @@ static void note_page(struct seq_file *m, struct pg_state *st, /* * Now print the actual finished series */ - pt_dump_seq_printf(m, st->to_dmesg, "0x%0*lx-0x%0*lx ", - width, st->start_address, - width, st->current_address); - - delta = (st->current_address - st->start_address) >> 10; - while (!(delta & 1023) && unit[1]) { - delta >>= 10; - unit++; + if (!st->marker->max_lines || + st->lines < st->marker->max_lines) { + pt_dump_seq_printf(m, st->to_dmesg, + "0x%0*lx-0x%0*lx ", + width, st->start_address, + width, st->current_address); + + delta = st->current_address - st->start_address; + while (!(delta & 1023) && unit[1]) { + delta >>= 10; + unit++; + } + pt_dump_cont_printf(m, st->to_dmesg, "%9lu%c ", + delta, *unit); + printk_prot(m, st->current_prot, st->level, + st->to_dmesg); } - pt_dump_cont_printf(m, st->to_dmesg, "%9lu%c ", delta, *unit); - printk_prot(m, st->current_prot, st->level, st->to_dmesg); + st->lines++; /* * We print markers for special areas of address space, @@ -226,7 +238,17 @@ static void note_page(struct seq_file *m, struct pg_state *st, * This helps in the interpretation. */ if (st->current_address >= st->marker[1].start_address) { + if (st->marker->max_lines && + st->lines > st->marker->max_lines) { + unsigned long nskip = + st->lines - st->marker->max_lines; + pt_dump_seq_printf(m, st->to_dmesg, + "... %lu entr%s skipped ... \n", + nskip, + nskip == 1 ? "y" : "ies"); + } st->marker++; + st->lines = 0; pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n", st->marker->name); } diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 8e57229926779e..36642793e315fc 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -8,7 +8,7 @@ #include /* oops_begin/end, ... */ #include /* search_exception_table */ #include /* max_low_pfn */ -#include /* __kprobes, ... */ +#include /* NOKPROBE_SYMBOL, ... */ #include /* kmmio_handler, ... */ #include /* perf_sw_event */ #include /* hstate_index_to_shift */ @@ -18,7 +18,8 @@ #include /* dotraplinkage, ... */ #include /* pgd_*(), ... */ #include /* kmemcheck_*(), ... */ -#include /* VSYSCALL_START */ +#include /* VSYSCALL_ADDR */ +#include /* emulate_vsyscall */ #define CREATE_TRACE_POINTS #include @@ -45,7 +46,7 @@ enum x86_pf_error_code { * Returns 0 if mmiotrace is disabled, or if the fault is not * handled by mmiotrace: */ -static inline int __kprobes +static nokprobe_inline int kmmio_fault(struct pt_regs *regs, unsigned long addr) { if (unlikely(is_kmmio_active())) @@ -54,7 +55,7 @@ kmmio_fault(struct pt_regs *regs, unsigned long addr) return 0; } -static inline int __kprobes kprobes_fault(struct pt_regs *regs) +static nokprobe_inline int kprobes_fault(struct pt_regs *regs) { int ret = 0; @@ -261,7 +262,7 @@ void vmalloc_sync_all(void) * * Handle a fault on the vmalloc or module mapping area */ -static noinline __kprobes int vmalloc_fault(unsigned long address) +static noinline int vmalloc_fault(unsigned long address) { unsigned long pgd_paddr; pmd_t *pmd_k; @@ -291,6 +292,7 @@ static noinline __kprobes int vmalloc_fault(unsigned long address) return 0; } +NOKPROBE_SYMBOL(vmalloc_fault); /* * Did it hit the DOS screen memory VA from vm86 mode? @@ -358,7 +360,7 @@ void vmalloc_sync_all(void) * * This assumes no large pages in there. */ -static noinline __kprobes int vmalloc_fault(unsigned long address) +static noinline int vmalloc_fault(unsigned long address) { pgd_t *pgd, *pgd_ref; pud_t *pud, *pud_ref; @@ -425,6 +427,7 @@ static noinline __kprobes int vmalloc_fault(unsigned long address) return 0; } +NOKPROBE_SYMBOL(vmalloc_fault); #ifdef CONFIG_CPU_SUP_AMD static const char errata93_warning[] = @@ -771,7 +774,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, * emulation. */ if (unlikely((error_code & PF_INSTR) && - ((address & ~0xfff) == VSYSCALL_START))) { + ((address & ~0xfff) == VSYSCALL_ADDR))) { if (emulate_vsyscall(regs, address)) return; } @@ -927,7 +930,7 @@ static int spurious_fault_check(unsigned long error_code, pte_t *pte) * There are no security implications to leaving a stale TLB when * increasing the permissions on a page. */ -static noinline __kprobes int +static noinline int spurious_fault(unsigned long error_code, unsigned long address) { pgd_t *pgd; @@ -975,6 +978,7 @@ spurious_fault(unsigned long error_code, unsigned long address) return ret; } +NOKPROBE_SYMBOL(spurious_fault); int show_unhandled_signals = 1; @@ -1030,7 +1034,7 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs) * {,trace_}do_page_fault() have notrace on. Having this an actual function * guarantees there's a function trace entry. */ -static void __kprobes noinline +static noinline void __do_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address) { @@ -1253,8 +1257,9 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, up_read(&mm->mmap_sem); } +NOKPROBE_SYMBOL(__do_page_fault); -dotraplinkage void __kprobes notrace +dotraplinkage void notrace do_page_fault(struct pt_regs *regs, unsigned long error_code) { unsigned long address = read_cr2(); /* Get the faulting address */ @@ -1272,10 +1277,12 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code) __do_page_fault(regs, error_code, address); exception_exit(prev_state); } +NOKPROBE_SYMBOL(do_page_fault); #ifdef CONFIG_TRACING -static void trace_page_fault_entries(unsigned long address, struct pt_regs *regs, - unsigned long error_code) +static nokprobe_inline void +trace_page_fault_entries(unsigned long address, struct pt_regs *regs, + unsigned long error_code) { if (user_mode(regs)) trace_page_fault_user(address, regs, error_code); @@ -1283,7 +1290,7 @@ static void trace_page_fault_entries(unsigned long address, struct pt_regs *regs trace_page_fault_kernel(address, regs, error_code); } -dotraplinkage void __kprobes notrace +dotraplinkage void notrace trace_do_page_fault(struct pt_regs *regs, unsigned long error_code) { /* @@ -1300,4 +1307,5 @@ trace_do_page_fault(struct pt_regs *regs, unsigned long error_code) __do_page_fault(regs, error_code, address); exception_exit(prev_state); } +NOKPROBE_SYMBOL(trace_do_page_fault); #endif /* CONFIG_TRACING */ diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index b92591fa897063..3c7205d4de5292 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -1055,8 +1055,8 @@ void __init mem_init(void) after_bootmem = 1; /* Register memory areas for /proc/kcore */ - kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START, - VSYSCALL_END - VSYSCALL_START, KCORE_OTHER); + kclist_add(&kcore_vsyscall, (void *)VSYSCALL_ADDR, + PAGE_SIZE, KCORE_OTHER); mem_init_print_info(NULL); } @@ -1186,8 +1186,8 @@ int kern_addr_valid(unsigned long addr) * not need special handling anymore: */ static struct vm_area_struct gate_vma = { - .vm_start = VSYSCALL_START, - .vm_end = VSYSCALL_START + (VSYSCALL_MAPPED_PAGES * PAGE_SIZE), + .vm_start = VSYSCALL_ADDR, + .vm_end = VSYSCALL_ADDR + PAGE_SIZE, .vm_page_prot = PAGE_READONLY_EXEC, .vm_flags = VM_READ | VM_EXEC }; @@ -1218,12 +1218,13 @@ int in_gate_area(struct mm_struct *mm, unsigned long addr) */ int in_gate_area_no_mm(unsigned long addr) { - return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END); + return (addr & PAGE_MASK) == VSYSCALL_ADDR; } const char *arch_vma_name(struct vm_area_struct *vma) { - if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) + if (vma->vm_mm && vma->vm_start == + (long __force)vma->vm_mm->context.vdso) return "[vdso]"; if (vma == &gate_vma) return "[vsyscall]"; diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 597ac155c91c82..baff1da354e0ec 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -50,6 +50,21 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size, return err; } +static int __ioremap_check_ram(unsigned long start_pfn, unsigned long nr_pages, + void *arg) +{ + unsigned long i; + + for (i = 0; i < nr_pages; ++i) + if (pfn_valid(start_pfn + i) && + !PageReserved(pfn_to_page(start_pfn + i))) + return 1; + + WARN_ONCE(1, "ioremap on RAM pfn 0x%lx\n", start_pfn); + + return 0; +} + /* * Remap an arbitrary physical address space into the kernel virtual * address space. Needed when the kernel wants to access high addresses @@ -93,14 +108,11 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, /* * Don't allow anybody to remap normal RAM that we're using.. */ + pfn = phys_addr >> PAGE_SHIFT; last_pfn = last_addr >> PAGE_SHIFT; - for (pfn = phys_addr >> PAGE_SHIFT; pfn <= last_pfn; pfn++) { - int is_ram = page_is_ram(pfn); - - if (is_ram && pfn_valid(pfn) && !PageReserved(pfn_to_page(pfn))) - return NULL; - WARN_ON_ONCE(is_ram); - } + if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL, + __ioremap_check_ram) == 1) + return NULL; /* * Mappings have to be page-aligned @@ -355,6 +367,12 @@ void __init early_ioremap_init(void) { pmd_t *pmd; +#ifdef CONFIG_X86_64 + BUILD_BUG_ON((fix_to_virt(0) + PAGE_SIZE) & ((1 << PMD_SHIFT) - 1)); +#else + WARN_ON((fix_to_virt(0) + PAGE_SIZE) & ((1 << PMD_SHIFT) - 1)); +#endif + early_ioremap_setup(); pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)); diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index c96314abd144ca..6fb6927f9e76f3 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -399,13 +399,20 @@ int pmdp_test_and_clear_young(struct vm_area_struct *vma, int ptep_clear_flush_young(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) { - int young; - - young = ptep_test_and_clear_young(vma, address, ptep); - if (young) - flush_tlb_page(vma, address); - - return young; + /* + * On x86 CPUs, clearing the accessed bit without a TLB flush + * doesn't cause data corruption. [ It could cause incorrect + * page aging and the (mistaken) reclaim of hot pages, but the + * chance of that should be relatively low. ] + * + * So as a performance optimization don't flush the TLB when + * clearing the accessed bit, it will eventually be flushed by + * a context switch or a VM operation anyway. [ In the rare + * event of it not getting flushed for a long time the delay + * shouldn't really matter because there's no real memory + * pressure for swapout to react to. ] + */ + return ptep_test_and_clear_young(vma, address, ptep); } #ifdef CONFIG_TRANSPARENT_HUGEPAGE @@ -449,9 +456,9 @@ void __init reserve_top_address(unsigned long reserve) { #ifdef CONFIG_X86_32 BUG_ON(fixmaps_set > 0); - printk(KERN_INFO "Reserving virtual address space above 0x%08x\n", - (int)-reserve); - __FIXADDR_TOP = -reserve - PAGE_SIZE; + __FIXADDR_TOP = round_down(-reserve, 1 << PMD_SHIFT) - PAGE_SIZE; + printk(KERN_INFO "Reserving virtual address space above 0x%08lx (rounded to 0x%08lx)\n", + -reserve, __FIXADDR_TOP + PAGE_SIZE); #endif } diff --git a/arch/x86/platform/efi/early_printk.c b/arch/x86/platform/efi/early_printk.c index 81b506d5befd46..52414211729689 100644 --- a/arch/x86/platform/efi/early_printk.c +++ b/arch/x86/platform/efi/early_printk.c @@ -14,48 +14,92 @@ static const struct font_desc *font; static u32 efi_x, efi_y; +static void *efi_fb; +static bool early_efi_keep; -static __init void early_efi_clear_scanline(unsigned int y) +/* + * efi earlyprintk need use early_ioremap to map the framebuffer. + * But early_ioremap is not usable for earlyprintk=efi,keep, ioremap should + * be used instead. ioremap will be available after paging_init() which is + * earlier than initcall callbacks. Thus adding this early initcall function + * early_efi_map_fb to map the whole efi framebuffer. + */ +static __init int early_efi_map_fb(void) { - unsigned long base, *dst; - u16 len; + unsigned long base, size; + + if (!early_efi_keep) + return 0; base = boot_params.screen_info.lfb_base; - len = boot_params.screen_info.lfb_linelength; + size = boot_params.screen_info.lfb_size; + efi_fb = ioremap(base, size); + + return efi_fb ? 0 : -ENOMEM; +} +early_initcall(early_efi_map_fb); + +/* + * early_efi_map maps efi framebuffer region [start, start + len -1] + * In case earlyprintk=efi,keep we have the whole framebuffer mapped already + * so just return the offset efi_fb + start. + */ +static __init_refok void *early_efi_map(unsigned long start, unsigned long len) +{ + unsigned long base; + + base = boot_params.screen_info.lfb_base; + + if (efi_fb) + return (efi_fb + start); + else + return early_ioremap(base + start, len); +} - dst = early_ioremap(base + y*len, len); +static __init_refok void early_efi_unmap(void *addr, unsigned long len) +{ + if (!efi_fb) + early_iounmap(addr, len); +} + +static void early_efi_clear_scanline(unsigned int y) +{ + unsigned long *dst; + u16 len; + + len = boot_params.screen_info.lfb_linelength; + dst = early_efi_map(y*len, len); if (!dst) return; memset(dst, 0, len); - early_iounmap(dst, len); + early_efi_unmap(dst, len); } -static __init void early_efi_scroll_up(void) +static void early_efi_scroll_up(void) { - unsigned long base, *dst, *src; + unsigned long *dst, *src; u16 len; u32 i, height; - base = boot_params.screen_info.lfb_base; len = boot_params.screen_info.lfb_linelength; height = boot_params.screen_info.lfb_height; for (i = 0; i < height - font->height; i++) { - dst = early_ioremap(base + i*len, len); + dst = early_efi_map(i*len, len); if (!dst) return; - src = early_ioremap(base + (i + font->height) * len, len); + src = early_efi_map((i + font->height) * len, len); if (!src) { - early_iounmap(dst, len); + early_efi_unmap(dst, len); return; } memmove(dst, src, len); - early_iounmap(src, len); - early_iounmap(dst, len); + early_efi_unmap(src, len); + early_efi_unmap(dst, len); } } @@ -79,16 +123,14 @@ static void early_efi_write_char(u32 *dst, unsigned char c, unsigned int h) } } -static __init void +static void early_efi_write(struct console *con, const char *str, unsigned int num) { struct screen_info *si; - unsigned long base; unsigned int len; const char *s; void *dst; - base = boot_params.screen_info.lfb_base; si = &boot_params.screen_info; len = si->lfb_linelength; @@ -109,7 +151,7 @@ early_efi_write(struct console *con, const char *str, unsigned int num) for (h = 0; h < font->height; h++) { unsigned int n, x; - dst = early_ioremap(base + (efi_y + h) * len, len); + dst = early_efi_map((efi_y + h) * len, len); if (!dst) return; @@ -123,7 +165,7 @@ early_efi_write(struct console *con, const char *str, unsigned int num) s++; } - early_iounmap(dst, len); + early_efi_unmap(dst, len); } num -= count; @@ -179,6 +221,9 @@ static __init int early_efi_setup(struct console *con, char *options) for (i = 0; i < (yres - efi_y) / font->height; i++) early_efi_scroll_up(); + /* early_console_register will unset CON_BOOT in case ,keep */ + if (!(con->flags & CON_BOOT)) + early_efi_keep = true; return 0; } diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 3781dd39e8bd55..835b24820eaa05 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -110,7 +110,7 @@ static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) efi_status_t status; spin_lock_irqsave(&rtc_lock, flags); - status = efi_call_virt2(get_time, tm, tc); + status = efi_call_virt(get_time, tm, tc); spin_unlock_irqrestore(&rtc_lock, flags); return status; } @@ -121,7 +121,7 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm) efi_status_t status; spin_lock_irqsave(&rtc_lock, flags); - status = efi_call_virt1(set_time, tm); + status = efi_call_virt(set_time, tm); spin_unlock_irqrestore(&rtc_lock, flags); return status; } @@ -134,8 +134,7 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, efi_status_t status; spin_lock_irqsave(&rtc_lock, flags); - status = efi_call_virt3(get_wakeup_time, - enabled, pending, tm); + status = efi_call_virt(get_wakeup_time, enabled, pending, tm); spin_unlock_irqrestore(&rtc_lock, flags); return status; } @@ -146,8 +145,7 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) efi_status_t status; spin_lock_irqsave(&rtc_lock, flags); - status = efi_call_virt2(set_wakeup_time, - enabled, tm); + status = efi_call_virt(set_wakeup_time, enabled, tm); spin_unlock_irqrestore(&rtc_lock, flags); return status; } @@ -158,17 +156,17 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name, unsigned long *data_size, void *data) { - return efi_call_virt5(get_variable, - name, vendor, attr, - data_size, data); + return efi_call_virt(get_variable, + name, vendor, attr, + data_size, data); } static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor) { - return efi_call_virt3(get_next_variable, - name_size, name, vendor); + return efi_call_virt(get_next_variable, + name_size, name, vendor); } static efi_status_t virt_efi_set_variable(efi_char16_t *name, @@ -177,9 +175,9 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name, unsigned long data_size, void *data) { - return efi_call_virt5(set_variable, - name, vendor, attr, - data_size, data); + return efi_call_virt(set_variable, + name, vendor, attr, + data_size, data); } static efi_status_t virt_efi_query_variable_info(u32 attr, @@ -190,13 +188,13 @@ static efi_status_t virt_efi_query_variable_info(u32 attr, if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) return EFI_UNSUPPORTED; - return efi_call_virt4(query_variable_info, attr, storage_space, - remaining_space, max_variable_size); + return efi_call_virt(query_variable_info, attr, storage_space, + remaining_space, max_variable_size); } static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) { - return efi_call_virt1(get_next_high_mono_count, count); + return efi_call_virt(get_next_high_mono_count, count); } static void virt_efi_reset_system(int reset_type, @@ -204,8 +202,8 @@ static void virt_efi_reset_system(int reset_type, unsigned long data_size, efi_char16_t *data) { - efi_call_virt4(reset_system, reset_type, status, - data_size, data); + __efi_call_virt(reset_system, reset_type, status, + data_size, data); } static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, @@ -215,7 +213,7 @@ static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) return EFI_UNSUPPORTED; - return efi_call_virt3(update_capsule, capsules, count, sg_list); + return efi_call_virt(update_capsule, capsules, count, sg_list); } static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, @@ -226,8 +224,8 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) return EFI_UNSUPPORTED; - return efi_call_virt4(query_capsule_caps, capsules, count, max_size, - reset_type); + return efi_call_virt(query_capsule_caps, capsules, count, max_size, + reset_type); } static efi_status_t __init phys_efi_set_virtual_address_map( @@ -239,9 +237,9 @@ static efi_status_t __init phys_efi_set_virtual_address_map( efi_status_t status; efi_call_phys_prelog(); - status = efi_call_phys4(efi_phys.set_virtual_address_map, - memory_map_size, descriptor_size, - descriptor_version, virtual_map); + status = efi_call_phys(efi_phys.set_virtual_address_map, + memory_map_size, descriptor_size, + descriptor_version, virtual_map); efi_call_phys_epilog(); return status; } diff --git a/arch/x86/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S index e0984ef0374b87..5fcda7272550a7 100644 --- a/arch/x86/platform/efi/efi_stub_64.S +++ b/arch/x86/platform/efi/efi_stub_64.S @@ -73,84 +73,7 @@ 2: .endm -ENTRY(efi_call0) - SAVE_XMM - subq $32, %rsp - SWITCH_PGT - call *%rdi - RESTORE_PGT - addq $32, %rsp - RESTORE_XMM - ret -ENDPROC(efi_call0) - -ENTRY(efi_call1) - SAVE_XMM - subq $32, %rsp - mov %rsi, %rcx - SWITCH_PGT - call *%rdi - RESTORE_PGT - addq $32, %rsp - RESTORE_XMM - ret -ENDPROC(efi_call1) - -ENTRY(efi_call2) - SAVE_XMM - subq $32, %rsp - mov %rsi, %rcx - SWITCH_PGT - call *%rdi - RESTORE_PGT - addq $32, %rsp - RESTORE_XMM - ret -ENDPROC(efi_call2) - -ENTRY(efi_call3) - SAVE_XMM - subq $32, %rsp - mov %rcx, %r8 - mov %rsi, %rcx - SWITCH_PGT - call *%rdi - RESTORE_PGT - addq $32, %rsp - RESTORE_XMM - ret -ENDPROC(efi_call3) - -ENTRY(efi_call4) - SAVE_XMM - subq $32, %rsp - mov %r8, %r9 - mov %rcx, %r8 - mov %rsi, %rcx - SWITCH_PGT - call *%rdi - RESTORE_PGT - addq $32, %rsp - RESTORE_XMM - ret -ENDPROC(efi_call4) - -ENTRY(efi_call5) - SAVE_XMM - subq $48, %rsp - mov %r9, 32(%rsp) - mov %r8, %r9 - mov %rcx, %r8 - mov %rsi, %rcx - SWITCH_PGT - call *%rdi - RESTORE_PGT - addq $48, %rsp - RESTORE_XMM - ret -ENDPROC(efi_call5) - -ENTRY(efi_call6) +ENTRY(efi_call) SAVE_XMM mov (%rsp), %rax mov 8(%rax), %rax @@ -166,7 +89,7 @@ ENTRY(efi_call6) addq $48, %rsp RESTORE_XMM ret -ENDPROC(efi_call6) +ENDPROC(efi_call) #ifdef CONFIG_EFI_MIXED diff --git a/arch/x86/platform/olpc/olpc-xo1-pm.c b/arch/x86/platform/olpc/olpc-xo1-pm.c index ff0174dda810fd..a9acde72d4ed98 100644 --- a/arch/x86/platform/olpc/olpc-xo1-pm.c +++ b/arch/x86/platform/olpc/olpc-xo1-pm.c @@ -75,7 +75,7 @@ static int xo1_power_state_enter(suspend_state_t pm_state) return 0; } -asmlinkage int xo1_do_sleep(u8 sleep_state) +asmlinkage __visible int xo1_do_sleep(u8 sleep_state) { void *pgd_addr = __va(read_cr3()); diff --git a/arch/x86/platform/uv/bios_uv.c b/arch/x86/platform/uv/bios_uv.c index 766612137a62d5..1584cbed0dce25 100644 --- a/arch/x86/platform/uv/bios_uv.c +++ b/arch/x86/platform/uv/bios_uv.c @@ -39,7 +39,7 @@ s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5) */ return BIOS_STATUS_UNIMPLEMENTED; - ret = efi_call6((void *)__va(tab->function), (u64)which, + ret = efi_call((void *)__va(tab->function), (u64)which, a1, a2, a3, a4, a5); return ret; } diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c index 304fca20d96ee3..35e2bb6c0f372d 100644 --- a/arch/x86/power/hibernate_64.c +++ b/arch/x86/power/hibernate_64.c @@ -23,7 +23,7 @@ extern __visible const void __nosave_begin, __nosave_end; /* Defined in hibernate_asm_64.S */ -extern asmlinkage int restore_image(void); +extern asmlinkage __visible int restore_image(void); /* * Address to jump to in the last phase of restore in order to get to the image diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index 3497f14e4dea8a..7c0d7be176a584 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -52,8 +52,9 @@ $(obj)/realmode.elf: $(obj)/realmode.lds $(REALMODE_OBJS) FORCE OBJCOPYFLAGS_realmode.bin := -O binary targets += realmode.bin -$(obj)/realmode.bin: $(obj)/realmode.elf $(obj)/realmode.relocs +$(obj)/realmode.bin: $(obj)/realmode.elf $(obj)/realmode.relocs FORCE $(call if_changed,objcopy) + @: quiet_cmd_relocs = RELOCS $@ cmd_relocs = arch/x86/tools/relocs --realmode $< > $@ diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl index 04376ac3d9efb9..ec255a1646d2da 100644 --- a/arch/x86/syscalls/syscall_64.tbl +++ b/arch/x86/syscalls/syscall_64.tbl @@ -212,10 +212,10 @@ 203 common sched_setaffinity sys_sched_setaffinity 204 common sched_getaffinity sys_sched_getaffinity 205 64 set_thread_area -206 common io_setup sys_io_setup +206 64 io_setup sys_io_setup 207 common io_destroy sys_io_destroy 208 common io_getevents sys_io_getevents -209 common io_submit sys_io_submit +209 64 io_submit sys_io_submit 210 common io_cancel sys_io_cancel 211 64 get_thread_area 212 common lookup_dcookie sys_lookup_dcookie @@ -359,3 +359,5 @@ 540 x32 process_vm_writev compat_sys_process_vm_writev 541 x32 setsockopt compat_sys_setsockopt 542 x32 getsockopt compat_sys_getsockopt +543 x32 io_setup compat_sys_io_setup +544 x32 io_submit compat_sys_io_submit diff --git a/arch/x86/um/asm/ptrace.h b/arch/x86/um/asm/ptrace.h index 54f8102ccde5d2..e59eef20647b3e 100644 --- a/arch/x86/um/asm/ptrace.h +++ b/arch/x86/um/asm/ptrace.h @@ -47,8 +47,6 @@ struct user_desc; #ifdef CONFIG_X86_32 -#define HOST_AUDIT_ARCH AUDIT_ARCH_I386 - extern int ptrace_get_thread_area(struct task_struct *child, int idx, struct user_desc __user *user_desc); @@ -57,8 +55,6 @@ extern int ptrace_set_thread_area(struct task_struct *child, int idx, #else -#define HOST_AUDIT_ARCH AUDIT_ARCH_X86_64 - #define PT_REGS_R8(r) UPT_R8(&(r)->regs) #define PT_REGS_R9(r) UPT_R9(&(r)->regs) #define PT_REGS_R10(r) UPT_R10(&(r)->regs) diff --git a/arch/x86/um/asm/syscall.h b/arch/x86/um/asm/syscall.h new file mode 100644 index 00000000000000..9fe77b7b5a0ed5 --- /dev/null +++ b/arch/x86/um/asm/syscall.h @@ -0,0 +1,15 @@ +#ifndef __UM_ASM_SYSCALL_H +#define __UM_ASM_SYSCALL_H + +#include + +static inline int syscall_get_arch(void) +{ +#ifdef CONFIG_X86_32 + return AUDIT_ARCH_I386; +#else + return AUDIT_ARCH_X86_64; +#endif +} + +#endif /* __UM_ASM_SYSCALL_H */ diff --git a/arch/x86/um/ldt.c b/arch/x86/um/ldt.c index 8e08176f0bcbea..5c0b711d2433d3 100644 --- a/arch/x86/um/ldt.c +++ b/arch/x86/um/ldt.c @@ -8,9 +8,7 @@ #include #include #include -#include #include -#include #include extern int modify_ldt(int func, void *ptr, unsigned long bytecount); @@ -19,105 +17,20 @@ static long write_ldt_entry(struct mm_id *mm_idp, int func, struct user_desc *desc, void **addr, int done) { long res; - - if (proc_mm) { - /* - * This is a special handling for the case, that the mm to - * modify isn't current->active_mm. - * If this is called directly by modify_ldt, - * (current->active_mm->context.skas.u == mm_idp) - * will be true. So no call to __switch_mm(mm_idp) is done. - * If this is called in case of init_new_ldt or PTRACE_LDT, - * mm_idp won't belong to current->active_mm, but child->mm. - * So we need to switch child's mm into our userspace, then - * later switch back. - * - * Note: I'm unsure: should interrupts be disabled here? - */ - if (!current->active_mm || current->active_mm == &init_mm || - mm_idp != ¤t->active_mm->context.id) - __switch_mm(mm_idp); - } - - if (ptrace_ldt) { - struct ptrace_ldt ldt_op = (struct ptrace_ldt) { - .func = func, - .ptr = desc, - .bytecount = sizeof(*desc)}; - u32 cpu; - int pid; - - if (!proc_mm) - pid = mm_idp->u.pid; - else { - cpu = get_cpu(); - pid = userspace_pid[cpu]; - } - - res = os_ptrace_ldt(pid, 0, (unsigned long) &ldt_op); - - if (proc_mm) - put_cpu(); - } - else { - void *stub_addr; - res = syscall_stub_data(mm_idp, (unsigned long *)desc, - (sizeof(*desc) + sizeof(long) - 1) & - ~(sizeof(long) - 1), - addr, &stub_addr); - if (!res) { - unsigned long args[] = { func, - (unsigned long)stub_addr, - sizeof(*desc), - 0, 0, 0 }; - res = run_syscall_stub(mm_idp, __NR_modify_ldt, args, - 0, addr, done); - } + void *stub_addr; + res = syscall_stub_data(mm_idp, (unsigned long *)desc, + (sizeof(*desc) + sizeof(long) - 1) & + ~(sizeof(long) - 1), + addr, &stub_addr); + if (!res) { + unsigned long args[] = { func, + (unsigned long)stub_addr, + sizeof(*desc), + 0, 0, 0 }; + res = run_syscall_stub(mm_idp, __NR_modify_ldt, args, + 0, addr, done); } - if (proc_mm) { - /* - * This is the second part of special handling, that makes - * PTRACE_LDT possible to implement. - */ - if (current->active_mm && current->active_mm != &init_mm && - mm_idp != ¤t->active_mm->context.id) - __switch_mm(¤t->active_mm->context.id); - } - - return res; -} - -static long read_ldt_from_host(void __user * ptr, unsigned long bytecount) -{ - int res, n; - struct ptrace_ldt ptrace_ldt = (struct ptrace_ldt) { - .func = 0, - .bytecount = bytecount, - .ptr = kmalloc(bytecount, GFP_KERNEL)}; - u32 cpu; - - if (ptrace_ldt.ptr == NULL) - return -ENOMEM; - - /* - * This is called from sys_modify_ldt only, so userspace_pid gives - * us the right number - */ - - cpu = get_cpu(); - res = os_ptrace_ldt(userspace_pid[cpu], 0, (unsigned long) &ptrace_ldt); - put_cpu(); - if (res < 0) - goto out; - - n = copy_to_user(ptr, ptrace_ldt.ptr, res); - if (n != 0) - res = -EFAULT; - - out: - kfree(ptrace_ldt.ptr); - return res; } @@ -145,9 +58,6 @@ static int read_ldt(void __user * ptr, unsigned long bytecount) bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; err = bytecount; - if (ptrace_ldt) - return read_ldt_from_host(ptr, bytecount); - mutex_lock(&ldt->lock); if (ldt->entry_count <= LDT_DIRECT_ENTRIES) { size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES; @@ -229,17 +139,11 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func) goto out; } - if (!ptrace_ldt) - mutex_lock(&ldt->lock); + mutex_lock(&ldt->lock); err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1); if (err) goto out_unlock; - else if (ptrace_ldt) { - /* With PTRACE_LDT available, this is used as a flag only */ - ldt->entry_count = 1; - goto out; - } if (ldt_info.entry_number >= ldt->entry_count && ldt_info.entry_number >= LDT_DIRECT_ENTRIES) { @@ -393,91 +297,56 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm) int i; long page, err=0; void *addr = NULL; - struct proc_mm_op copy; - if (!ptrace_ldt) - mutex_init(&new_mm->arch.ldt.lock); + mutex_init(&new_mm->arch.ldt.lock); if (!from_mm) { memset(&desc, 0, sizeof(desc)); /* - * We have to initialize a clean ldt. + * Now we try to retrieve info about the ldt, we + * inherited from the host. All ldt-entries found + * will be reset in the following loop */ - if (proc_mm) { - /* - * If the new mm was created using proc_mm, host's - * default-ldt currently is assigned, which normally - * contains the call-gates for lcall7 and lcall27. - * To remove these gates, we simply write an empty - * entry as number 0 to the host. - */ - err = write_ldt_entry(&new_mm->id, 1, &desc, &addr, 1); - } - else{ - /* - * Now we try to retrieve info about the ldt, we - * inherited from the host. All ldt-entries found - * will be reset in the following loop - */ - ldt_get_host_info(); - for (num_p=host_ldt_entries; *num_p != -1; num_p++) { - desc.entry_number = *num_p; - err = write_ldt_entry(&new_mm->id, 1, &desc, - &addr, *(num_p + 1) == -1); - if (err) - break; - } + ldt_get_host_info(); + for (num_p=host_ldt_entries; *num_p != -1; num_p++) { + desc.entry_number = *num_p; + err = write_ldt_entry(&new_mm->id, 1, &desc, + &addr, *(num_p + 1) == -1); + if (err) + break; } new_mm->arch.ldt.entry_count = 0; goto out; } - if (proc_mm) { - /* - * We have a valid from_mm, so we now have to copy the LDT of - * from_mm to new_mm, because using proc_mm an new mm with - * an empty/default LDT was created in new_mm() - */ - copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, - .u = - { .copy_segments = - from_mm->id.u.mm_fd } } ); - i = os_write_file(new_mm->id.u.mm_fd, ©, sizeof(copy)); - if (i != sizeof(copy)) - printk(KERN_ERR "new_mm : /proc/mm copy_segments " - "failed, err = %d\n", -i); - } - - if (!ptrace_ldt) { - /* - * Our local LDT is used to supply the data for - * modify_ldt(READLDT), if PTRACE_LDT isn't available, - * i.e., we have to use the stub for modify_ldt, which - * can't handle the big read buffer of up to 64kB. - */ - mutex_lock(&from_mm->arch.ldt.lock); - if (from_mm->arch.ldt.entry_count <= LDT_DIRECT_ENTRIES) - memcpy(new_mm->arch.ldt.u.entries, from_mm->arch.ldt.u.entries, - sizeof(new_mm->arch.ldt.u.entries)); - else { - i = from_mm->arch.ldt.entry_count / LDT_ENTRIES_PER_PAGE; - while (i-->0) { - page = __get_free_page(GFP_KERNEL|__GFP_ZERO); - if (!page) { - err = -ENOMEM; - break; - } - new_mm->arch.ldt.u.pages[i] = - (struct ldt_entry *) page; - memcpy(new_mm->arch.ldt.u.pages[i], - from_mm->arch.ldt.u.pages[i], PAGE_SIZE); + /* + * Our local LDT is used to supply the data for + * modify_ldt(READLDT), if PTRACE_LDT isn't available, + * i.e., we have to use the stub for modify_ldt, which + * can't handle the big read buffer of up to 64kB. + */ + mutex_lock(&from_mm->arch.ldt.lock); + if (from_mm->arch.ldt.entry_count <= LDT_DIRECT_ENTRIES) + memcpy(new_mm->arch.ldt.u.entries, from_mm->arch.ldt.u.entries, + sizeof(new_mm->arch.ldt.u.entries)); + else { + i = from_mm->arch.ldt.entry_count / LDT_ENTRIES_PER_PAGE; + while (i-->0) { + page = __get_free_page(GFP_KERNEL|__GFP_ZERO); + if (!page) { + err = -ENOMEM; + break; } + new_mm->arch.ldt.u.pages[i] = + (struct ldt_entry *) page; + memcpy(new_mm->arch.ldt.u.pages[i], + from_mm->arch.ldt.u.pages[i], PAGE_SIZE); } - new_mm->arch.ldt.entry_count = from_mm->arch.ldt.entry_count; - mutex_unlock(&from_mm->arch.ldt.lock); } + new_mm->arch.ldt.entry_count = from_mm->arch.ldt.entry_count; + mutex_unlock(&from_mm->arch.ldt.lock); out: return err; @@ -488,7 +357,7 @@ void free_ldt(struct mm_context *mm) { int i; - if (!ptrace_ldt && mm->arch.ldt.entry_count > LDT_DIRECT_ENTRIES) { + if (mm->arch.ldt.entry_count > LDT_DIRECT_ENTRIES) { i = mm->arch.ldt.entry_count / LDT_ENTRIES_PER_PAGE; while (i-- > 0) free_page((long) mm->arch.ldt.u.pages[i]); diff --git a/arch/x86/um/shared/sysdep/faultinfo_32.h b/arch/x86/um/shared/sysdep/faultinfo_32.h index a26086b8a80022..b6f2437ec29c7a 100644 --- a/arch/x86/um/shared/sysdep/faultinfo_32.h +++ b/arch/x86/um/shared/sysdep/faultinfo_32.h @@ -27,9 +27,6 @@ struct faultinfo { /* This is Page Fault */ #define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14) -/* SKAS3 has no trap_no on i386, but get_skas_faultinfo() sets it to 0. */ -#define SEGV_MAYBE_FIXABLE(fi) ((fi)->trap_no == 0 && ptrace_faultinfo) - #define PTRACE_FULL_FAULTINFO 0 #endif diff --git a/arch/x86/um/shared/sysdep/faultinfo_64.h b/arch/x86/um/shared/sysdep/faultinfo_64.h index f811cbe15d623b..ee88f88974ea0f 100644 --- a/arch/x86/um/shared/sysdep/faultinfo_64.h +++ b/arch/x86/um/shared/sysdep/faultinfo_64.h @@ -27,9 +27,6 @@ struct faultinfo { /* This is Page Fault */ #define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14) -/* No broken SKAS API, which doesn't pass trap_no, here. */ -#define SEGV_MAYBE_FIXABLE(fi) 0 - #define PTRACE_FULL_FAULTINFO 1 #endif diff --git a/arch/x86/um/shared/sysdep/skas_ptrace.h b/arch/x86/um/shared/sysdep/skas_ptrace.h deleted file mode 100644 index 453febe9899392..00000000000000 --- a/arch/x86/um/shared/sysdep/skas_ptrace.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_X86_SKAS_PTRACE_H -#define __SYSDEP_X86_SKAS_PTRACE_H - -struct ptrace_faultinfo { - int is_write; - unsigned long addr; -}; - -struct ptrace_ldt { - int func; - void *ptr; - unsigned long bytecount; -}; - -#define PTRACE_LDT 54 - -#endif diff --git a/arch/x86/um/vdso/vma.c b/arch/x86/um/vdso/vma.c index af91901babb845..916cda4cd5b4c1 100644 --- a/arch/x86/um/vdso/vma.c +++ b/arch/x86/um/vdso/vma.c @@ -12,7 +12,7 @@ #include #include -unsigned int __read_mostly vdso_enabled = 1; +static unsigned int __read_mostly vdso_enabled = 1; unsigned long um_vdso_addr; extern unsigned long task_size; diff --git a/arch/x86/vdso/.gitignore b/arch/x86/vdso/.gitignore index 3282874bc61dd1..aae8ffdd58808a 100644 --- a/arch/x86/vdso/.gitignore +++ b/arch/x86/vdso/.gitignore @@ -1,8 +1,7 @@ vdso.lds -vdso-syms.lds vdsox32.lds -vdsox32-syms.lds -vdso32-syms.lds vdso32-syscall-syms.lds vdso32-sysenter-syms.lds vdso32-int80-syms.lds +vdso-image-*.c +vdso2c diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile index c580d1210ffe98..895d4b16b7e32a 100644 --- a/arch/x86/vdso/Makefile +++ b/arch/x86/vdso/Makefile @@ -24,15 +24,30 @@ vobj64s := $(filter-out $(vobjx32s-compat),$(vobjs-y)) # files to link into kernel obj-y += vma.o -obj-$(VDSO64-y) += vdso.o -obj-$(VDSOX32-y) += vdsox32.o -obj-$(VDSO32-y) += vdso32.o vdso32-setup.o + +# vDSO images to build +vdso_img-$(VDSO64-y) += 64 +vdso_img-$(VDSOX32-y) += x32 +vdso_img-$(VDSO32-y) += 32-int80 +vdso_img-$(CONFIG_COMPAT) += 32-syscall +vdso_img-$(VDSO32-y) += 32-sysenter + +obj-$(VDSO32-y) += vdso32-setup.o vobjs := $(foreach F,$(vobj64s),$(obj)/$F) $(obj)/vdso.o: $(obj)/vdso.so -targets += vdso.so vdso.so.dbg vdso.lds $(vobjs-y) +targets += vdso.lds $(vobjs-y) + +# Build the vDSO image C files and link them in. +vdso_img_objs := $(vdso_img-y:%=vdso-image-%.o) +vdso_img_cfiles := $(vdso_img-y:%=vdso-image-%.c) +vdso_img_sodbg := $(vdso_img-y:%=vdso%.so.dbg) +obj-y += $(vdso_img_objs) +targets += $(vdso_img_cfiles) +targets += $(vdso_img_sodbg) +.SECONDARY: $(vdso_img-y:%=$(obj)/vdso-image-%.c) export CPPFLAGS_vdso.lds += -P -C @@ -41,14 +56,18 @@ VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \ -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 \ $(DISABLE_LTO) -$(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so - -$(obj)/vdso.so.dbg: $(src)/vdso.lds $(vobjs) FORCE +$(obj)/vdso64.so.dbg: $(src)/vdso.lds $(vobjs) FORCE $(call if_changed,vdso) -$(obj)/%.so: OBJCOPYFLAGS := -S -$(obj)/%.so: $(obj)/%.so.dbg FORCE - $(call if_changed,objcopy) +hostprogs-y += vdso2c + +quiet_cmd_vdso2c = VDSO2C $@ +define cmd_vdso2c + $(obj)/vdso2c $< $@ +endef + +$(obj)/vdso-image-%.c: $(obj)/vdso%.so.dbg $(obj)/vdso2c FORCE + $(call if_changed,vdso2c) # # Don't omit frame pointers for ease of userspace debugging, but do @@ -68,22 +87,6 @@ CFLAGS_REMOVE_vclock_gettime.o = -pg CFLAGS_REMOVE_vgetcpu.o = -pg CFLAGS_REMOVE_vvar.o = -pg -targets += vdso-syms.lds -obj-$(VDSO64-y) += vdso-syms.lds - -# -# Match symbols in the DSO that look like VDSO*; produce a file of constants. -# -sed-vdsosym := -e 's/^00*/0/' \ - -e 's/^\([0-9a-fA-F]*\) . \(VDSO[a-zA-Z0-9_]*\)$$/\2 = 0x\1;/p' -quiet_cmd_vdsosym = VDSOSYM $@ -define cmd_vdsosym - $(NM) $< | LC_ALL=C sed -n $(sed-vdsosym) | LC_ALL=C sort > $@ -endef - -$(obj)/%-syms.lds: $(obj)/%.so.dbg FORCE - $(call if_changed,vdsosym) - # # X32 processes use x32 vDSO to access 64bit kernel data. # @@ -94,9 +97,6 @@ $(obj)/%-syms.lds: $(obj)/%.so.dbg FORCE # so that it can reach 64bit address space with 64bit pointers. # -targets += vdsox32-syms.lds -obj-$(VDSOX32-y) += vdsox32-syms.lds - CPPFLAGS_vdsox32.lds = $(CPPFLAGS_vdso.lds) VDSO_LDFLAGS_vdsox32.lds = -Wl,-m,elf32_x86_64 \ -Wl,-soname=linux-vdso.so.1 \ @@ -113,9 +113,7 @@ quiet_cmd_x32 = X32 $@ $(obj)/%-x32.o: $(obj)/%.o FORCE $(call if_changed,x32) -targets += vdsox32.so vdsox32.so.dbg vdsox32.lds $(vobjx32s-y) - -$(obj)/vdsox32.o: $(src)/vdsox32.S $(obj)/vdsox32.so +targets += vdsox32.lds $(vobjx32s-y) $(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE $(call if_changed,vdso) @@ -123,7 +121,6 @@ $(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE # # Build multiple 32-bit vDSO images to choose from at boot time. # -obj-$(VDSO32-y) += vdso32-syms.lds vdso32.so-$(VDSO32-y) += int80 vdso32.so-$(CONFIG_COMPAT) += syscall vdso32.so-$(VDSO32-y) += sysenter @@ -138,10 +135,8 @@ VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf_i386 -Wl,-soname=linux-gate.so.1 override obj-dirs = $(dir $(obj)) $(obj)/vdso32/ targets += vdso32/vdso32.lds -targets += $(vdso32-images) $(vdso32-images:=.dbg) targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o) - -extra-y += $(vdso32-images) +targets += vdso32/vclock_gettime.o $(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%) @@ -166,27 +161,6 @@ $(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \ $(obj)/vdso32/%.o $(call if_changed,vdso) -# Make vdso32-*-syms.lds from each image, and then make sure they match. -# The only difference should be that some do not define VDSO32_SYSENTER_RETURN. - -targets += vdso32-syms.lds $(vdso32.so-y:%=vdso32-%-syms.lds) - -quiet_cmd_vdso32sym = VDSOSYM $@ -define cmd_vdso32sym - if LC_ALL=C sort -u $(filter-out FORCE,$^) > $(@D)/.tmp_$(@F) && \ - $(foreach H,$(filter-out FORCE,$^),\ - if grep -q VDSO32_SYSENTER_RETURN $H; \ - then diff -u $(@D)/.tmp_$(@F) $H; \ - else sed /VDSO32_SYSENTER_RETURN/d $(@D)/.tmp_$(@F) | \ - diff -u - $H; fi &&) : ;\ - then mv -f $(@D)/.tmp_$(@F) $@; \ - else rm -f $(@D)/.tmp_$(@F); exit 1; \ - fi -endef - -$(obj)/vdso32-syms.lds: $(vdso32.so-y:%=$(obj)/vdso32-%-syms.lds) FORCE - $(call if_changed,vdso32sym) - # # The DSO images are built using a special linker script. # @@ -197,7 +171,7 @@ quiet_cmd_vdso = VDSO $@ sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@' VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \ - $(LTO_CFLAGS) + -Wl,-Bsymbolic $(LTO_CFLAGS) GCOV_PROFILE := n # diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index 16d686171e9af8..b2e4f493e5b0ed 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c @@ -30,9 +30,12 @@ extern int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz); extern time_t __vdso_time(time_t *t); #ifdef CONFIG_HPET_TIMER -static inline u32 read_hpet_counter(const volatile void *addr) +extern u8 hpet_page + __attribute__((visibility("hidden"))); + +static notrace cycle_t vread_hpet(void) { - return *(const volatile u32 *) (addr + HPET_COUNTER); + return *(const volatile u32 *)(&hpet_page + HPET_COUNTER); } #endif @@ -43,11 +46,6 @@ static inline u32 read_hpet_counter(const volatile void *addr) #include #include -static notrace cycle_t vread_hpet(void) -{ - return read_hpet_counter((const void *)fix_to_virt(VSYSCALL_HPET)); -} - notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) { long ret; @@ -137,16 +135,6 @@ static notrace cycle_t vread_pvclock(int *mode) #else -extern u8 hpet_page - __attribute__((visibility("hidden"))); - -#ifdef CONFIG_HPET_TIMER -static notrace cycle_t vread_hpet(void) -{ - return read_hpet_counter((const void *)(&hpet_page)); -} -#endif - notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) { long ret; @@ -154,7 +142,7 @@ notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) asm( "mov %%ebx, %%edx \n" "mov %2, %%ebx \n" - "call VDSO32_vsyscall \n" + "call __kernel_vsyscall \n" "mov %%edx, %%ebx \n" : "=a" (ret) : "0" (__NR_clock_gettime), "g" (clock), "c" (ts) @@ -169,7 +157,7 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz) asm( "mov %%ebx, %%edx \n" "mov %2, %%ebx \n" - "call VDSO32_vsyscall \n" + "call __kernel_vsyscall \n" "mov %%edx, %%ebx \n" : "=a" (ret) : "0" (__NR_gettimeofday), "g" (tv), "c" (tz) diff --git a/arch/x86/vdso/vdso-layout.lds.S b/arch/x86/vdso/vdso-layout.lds.S index 9df017ab2285a0..2ec72f651ebffa 100644 --- a/arch/x86/vdso/vdso-layout.lds.S +++ b/arch/x86/vdso/vdso-layout.lds.S @@ -1,3 +1,5 @@ +#include + /* * Linker script for vDSO. This is an ELF shared object prelinked to * its virtual address, and with only one read-only segment. @@ -6,20 +8,6 @@ SECTIONS { -#ifdef BUILD_VDSO32 -#include - - hpet_page = . - VDSO_OFFSET(VDSO_HPET_PAGE); - - vvar = . - VDSO_OFFSET(VDSO_VVAR_PAGE); - - /* Place all vvars at the offsets in asm/vvar.h. */ -#define EMIT_VVAR(name, offset) vvar_ ## name = vvar + offset; -#define __VVAR_KERNEL_LDS -#include -#undef __VVAR_KERNEL_LDS -#undef EMIT_VVAR -#endif . = SIZEOF_HEADERS; .hash : { *(.hash) } :text @@ -60,10 +48,30 @@ SECTIONS .text : { *(.text*) } :text =0x90909090, /* - * The comma above works around a bug in gold: - * https://sourceware.org/bugzilla/show_bug.cgi?id=16804 + * The remainder of the vDSO consists of special pages that are + * shared between the kernel and userspace. It needs to be at the + * end so that it doesn't overlap the mapping of the actual + * vDSO image. */ + . = ALIGN(PAGE_SIZE); + vvar_page = .; + + /* Place all vvars at the offsets in asm/vvar.h. */ +#define EMIT_VVAR(name, offset) vvar_ ## name = vvar_page + offset; +#define __VVAR_KERNEL_LDS +#include +#undef __VVAR_KERNEL_LDS +#undef EMIT_VVAR + + . = vvar_page + PAGE_SIZE; + + hpet_page = .; + . = . + PAGE_SIZE; + + . = ALIGN(PAGE_SIZE); + end_mapping = .; + /DISCARD/ : { *(.discard) *(.discard.*) diff --git a/arch/x86/vdso/vdso.S b/arch/x86/vdso/vdso.S deleted file mode 100644 index be3f23b09af561..00000000000000 --- a/arch/x86/vdso/vdso.S +++ /dev/null @@ -1,3 +0,0 @@ -#include - -DEFINE_VDSO_IMAGE(vdso, "arch/x86/vdso/vdso.so") diff --git a/arch/x86/vdso/vdso.lds.S b/arch/x86/vdso/vdso.lds.S index b96b2677cad828..75e3404c83b1e2 100644 --- a/arch/x86/vdso/vdso.lds.S +++ b/arch/x86/vdso/vdso.lds.S @@ -1,14 +1,11 @@ /* * Linker script for 64-bit vDSO. * We #include the file to define the layout details. - * Here we only choose the prelinked virtual address. * * This file defines the version script giving the user-exported symbols in - * the DSO. We can define local symbols here called VDSO* to make their - * values visible using the asm-x86/vdso.h macros from the kernel proper. + * the DSO. */ -#define VDSO_PRELINK 0xffffffffff700000 #include "vdso-layout.lds.S" /* @@ -28,5 +25,3 @@ VERSION { local: *; }; } - -VDSO64_PRELINK = VDSO_PRELINK; diff --git a/arch/x86/vdso/vdso2c.c b/arch/x86/vdso/vdso2c.c new file mode 100644 index 00000000000000..81edd1ec9df8c6 --- /dev/null +++ b/arch/x86/vdso/vdso2c.c @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +/* Symbols that we need in vdso2c. */ +enum { + sym_vvar_page, + sym_hpet_page, + sym_end_mapping, +}; + +const int special_pages[] = { + sym_vvar_page, + sym_hpet_page, +}; + +char const * const required_syms[] = { + [sym_vvar_page] = "vvar_page", + [sym_hpet_page] = "hpet_page", + [sym_end_mapping] = "end_mapping", + "VDSO32_NOTE_MASK", + "VDSO32_SYSENTER_RETURN", + "__kernel_vsyscall", + "__kernel_sigreturn", + "__kernel_rt_sigreturn", +}; + +__attribute__((format(printf, 1, 2))) __attribute__((noreturn)) +static void fail(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + fprintf(stderr, "Error: "); + vfprintf(stderr, format, ap); + exit(1); + va_end(ap); +} + +#define NSYMS (sizeof(required_syms) / sizeof(required_syms[0])) + +#define BITS 64 +#define GOFUNC go64 +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Sym Elf64_Sym +#define Elf_Dyn Elf64_Dyn +#include "vdso2c.h" +#undef BITS +#undef GOFUNC +#undef Elf_Ehdr +#undef Elf_Shdr +#undef Elf_Phdr +#undef Elf_Sym +#undef Elf_Dyn + +#define BITS 32 +#define GOFUNC go32 +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Phdr Elf32_Phdr +#define Elf_Sym Elf32_Sym +#define Elf_Dyn Elf32_Dyn +#include "vdso2c.h" +#undef BITS +#undef GOFUNC +#undef Elf_Ehdr +#undef Elf_Shdr +#undef Elf_Phdr +#undef Elf_Sym +#undef Elf_Dyn + +static int go(void *addr, size_t len, FILE *outfile, const char *name) +{ + Elf64_Ehdr *hdr = (Elf64_Ehdr *)addr; + + if (hdr->e_ident[EI_CLASS] == ELFCLASS64) { + return go64(addr, len, outfile, name); + } else if (hdr->e_ident[EI_CLASS] == ELFCLASS32) { + return go32(addr, len, outfile, name); + } else { + fprintf(stderr, "Error: unknown ELF class\n"); + return 1; + } +} + +int main(int argc, char **argv) +{ + int fd; + off_t len; + void *addr; + FILE *outfile; + int ret; + char *name, *tmp; + int namelen; + + if (argc != 3) { + printf("Usage: vdso2c INPUT OUTPUT\n"); + return 1; + } + + /* + * Figure out the struct name. If we're writing to a .so file, + * generate raw output insted. + */ + name = strdup(argv[2]); + namelen = strlen(name); + if (namelen >= 3 && !strcmp(name + namelen - 3, ".so")) { + name = NULL; + } else { + tmp = strrchr(name, '/'); + if (tmp) + name = tmp + 1; + tmp = strchr(name, '.'); + if (tmp) + *tmp = '\0'; + for (tmp = name; *tmp; tmp++) + if (*tmp == '-') + *tmp = '_'; + } + + fd = open(argv[1], O_RDONLY); + if (fd == -1) + err(1, "%s", argv[1]); + + len = lseek(fd, 0, SEEK_END); + if (len == (off_t)-1) + err(1, "lseek"); + + addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) + err(1, "mmap"); + + outfile = fopen(argv[2], "w"); + if (!outfile) + err(1, "%s", argv[2]); + + ret = go(addr, (size_t)len, outfile, name); + + munmap(addr, len); + fclose(outfile); + + return ret; +} diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/vdso/vdso2c.h new file mode 100644 index 00000000000000..ed2e894e89abb0 --- /dev/null +++ b/arch/x86/vdso/vdso2c.h @@ -0,0 +1,154 @@ +/* + * This file is included twice from vdso2c.c. It generates code for 32-bit + * and 64-bit vDSOs. We need both for 64-bit builds, since 32-bit vDSOs + * are built for 32-bit userspace. + */ + +static int GOFUNC(void *addr, size_t len, FILE *outfile, const char *name) +{ + int found_load = 0; + unsigned long load_size = -1; /* Work around bogus warning */ + unsigned long data_size; + Elf_Ehdr *hdr = (Elf_Ehdr *)addr; + int i; + unsigned long j; + Elf_Shdr *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr, + *alt_sec = NULL; + Elf_Dyn *dyn = 0, *dyn_end = 0; + const char *secstrings; + uint64_t syms[NSYMS] = {}; + + Elf_Phdr *pt = (Elf_Phdr *)(addr + hdr->e_phoff); + + /* Walk the segment table. */ + for (i = 0; i < hdr->e_phnum; i++) { + if (pt[i].p_type == PT_LOAD) { + if (found_load) + fail("multiple PT_LOAD segs\n"); + + if (pt[i].p_offset != 0 || pt[i].p_vaddr != 0) + fail("PT_LOAD in wrong place\n"); + + if (pt[i].p_memsz != pt[i].p_filesz) + fail("cannot handle memsz != filesz\n"); + + load_size = pt[i].p_memsz; + found_load = 1; + } else if (pt[i].p_type == PT_DYNAMIC) { + dyn = addr + pt[i].p_offset; + dyn_end = addr + pt[i].p_offset + pt[i].p_memsz; + } + } + if (!found_load) + fail("no PT_LOAD seg\n"); + data_size = (load_size + 4095) / 4096 * 4096; + + /* Walk the dynamic table */ + for (i = 0; dyn + i < dyn_end && dyn[i].d_tag != DT_NULL; i++) { + if (dyn[i].d_tag == DT_REL || dyn[i].d_tag == DT_RELSZ || + dyn[i].d_tag == DT_RELENT || dyn[i].d_tag == DT_TEXTREL) + fail("vdso image contains dynamic relocations\n"); + } + + /* Walk the section table */ + secstrings_hdr = addr + hdr->e_shoff + hdr->e_shentsize*hdr->e_shstrndx; + secstrings = addr + secstrings_hdr->sh_offset; + for (i = 0; i < hdr->e_shnum; i++) { + Elf_Shdr *sh = addr + hdr->e_shoff + hdr->e_shentsize * i; + if (sh->sh_type == SHT_SYMTAB) + symtab_hdr = sh; + + if (!strcmp(secstrings + sh->sh_name, ".altinstructions")) + alt_sec = sh; + } + + if (!symtab_hdr) { + fail("no symbol table\n"); + return 1; + } + + strtab_hdr = addr + hdr->e_shoff + + hdr->e_shentsize * symtab_hdr->sh_link; + + /* Walk the symbol table */ + for (i = 0; i < symtab_hdr->sh_size / symtab_hdr->sh_entsize; i++) { + int k; + Elf_Sym *sym = addr + symtab_hdr->sh_offset + + symtab_hdr->sh_entsize * i; + const char *name = addr + strtab_hdr->sh_offset + sym->st_name; + for (k = 0; k < NSYMS; k++) { + if (!strcmp(name, required_syms[k])) { + if (syms[k]) { + fail("duplicate symbol %s\n", + required_syms[k]); + } + syms[k] = sym->st_value; + } + } + } + + /* Validate mapping addresses. */ + for (i = 0; i < sizeof(special_pages) / sizeof(special_pages[0]); i++) { + if (!syms[i]) + continue; /* The mapping isn't used; ignore it. */ + + if (syms[i] % 4096) + fail("%s must be a multiple of 4096\n", + required_syms[i]); + if (syms[i] < data_size) + fail("%s must be after the text mapping\n", + required_syms[i]); + if (syms[sym_end_mapping] < syms[i] + 4096) + fail("%s overruns end_mapping\n", required_syms[i]); + } + if (syms[sym_end_mapping] % 4096) + fail("end_mapping must be a multiple of 4096\n"); + + /* Remove sections. */ + hdr->e_shoff = 0; + hdr->e_shentsize = 0; + hdr->e_shnum = 0; + hdr->e_shstrndx = SHN_UNDEF; + + if (!name) { + fwrite(addr, load_size, 1, outfile); + return 0; + } + + fprintf(outfile, "/* AUTOMATICALLY GENERATED -- DO NOT EDIT */\n\n"); + fprintf(outfile, "#include \n"); + fprintf(outfile, "#include \n"); + fprintf(outfile, "#include \n"); + fprintf(outfile, "\n"); + fprintf(outfile, + "static unsigned char raw_data[%lu] __page_aligned_data = {", + data_size); + for (j = 0; j < load_size; j++) { + if (j % 10 == 0) + fprintf(outfile, "\n\t"); + fprintf(outfile, "0x%02X, ", (int)((unsigned char *)addr)[j]); + } + fprintf(outfile, "\n};\n\n"); + + fprintf(outfile, "static struct page *pages[%lu];\n\n", + data_size / 4096); + + fprintf(outfile, "const struct vdso_image %s = {\n", name); + fprintf(outfile, "\t.data = raw_data,\n"); + fprintf(outfile, "\t.size = %lu,\n", data_size); + fprintf(outfile, "\t.pages = pages,\n"); + if (alt_sec) { + fprintf(outfile, "\t.alt = %lu,\n", + (unsigned long)alt_sec->sh_offset); + fprintf(outfile, "\t.alt_len = %lu,\n", + (unsigned long)alt_sec->sh_size); + } + for (i = 0; i < NSYMS; i++) { + if (syms[i]) + fprintf(outfile, "\t.sym_%s = 0x%" PRIx64 ",\n", + required_syms[i], syms[i]); + } + fprintf(outfile, "};\n"); + + return 0; +} diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c index 00348980a3a64a..c3ed708e50f411 100644 --- a/arch/x86/vdso/vdso32-setup.c +++ b/arch/x86/vdso/vdso32-setup.c @@ -8,27 +8,12 @@ #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 #ifdef CONFIG_COMPAT_VDSO #define VDSO_DEFAULT 0 @@ -36,22 +21,17 @@ #define VDSO_DEFAULT 1 #endif -#ifdef CONFIG_X86_64 -#define vdso_enabled sysctl_vsyscall32 -#define arch_setup_additional_pages syscall32_setup_pages -#endif - /* * Should the kernel map a VDSO page into processes and pass its * address down to glibc upon exec()? */ -unsigned int __read_mostly vdso_enabled = VDSO_DEFAULT; +unsigned int __read_mostly vdso32_enabled = VDSO_DEFAULT; -static int __init vdso_setup(char *s) +static int __init vdso32_setup(char *s) { - vdso_enabled = simple_strtoul(s, NULL, 0); + vdso32_enabled = simple_strtoul(s, NULL, 0); - if (vdso_enabled > 1) + if (vdso32_enabled > 1) pr_warn("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled\n"); return 1; @@ -62,177 +42,45 @@ static int __init vdso_setup(char *s) * behavior on both 64-bit and 32-bit kernels. * On 32-bit kernels, vdso=[012] means the same thing. */ -__setup("vdso32=", vdso_setup); +__setup("vdso32=", vdso32_setup); #ifdef CONFIG_X86_32 -__setup_param("vdso=", vdso32_setup, vdso_setup, 0); - -EXPORT_SYMBOL_GPL(vdso_enabled); +__setup_param("vdso=", vdso_setup, vdso32_setup, 0); #endif -static struct page **vdso32_pages; -static unsigned vdso32_size; - #ifdef CONFIG_X86_64 #define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SYSENTER32)) #define vdso32_syscall() (boot_cpu_has(X86_FEATURE_SYSCALL32)) -/* May not be __init: called during resume */ -void syscall32_cpu_init(void) -{ - /* Load these always in case some future AMD CPU supports - SYSENTER from compat mode too. */ - wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS); - wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL); - wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target); - - wrmsrl(MSR_CSTAR, ia32_cstar_target); -} - #else /* CONFIG_X86_32 */ #define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SEP)) #define vdso32_syscall() (0) -void enable_sep_cpu(void) -{ - int cpu = get_cpu(); - struct tss_struct *tss = &per_cpu(init_tss, cpu); - - if (!boot_cpu_has(X86_FEATURE_SEP)) { - put_cpu(); - return; - } - - tss->x86_tss.ss1 = __KERNEL_CS; - tss->x86_tss.sp1 = sizeof(struct tss_struct) + (unsigned long) tss; - wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); - wrmsr(MSR_IA32_SYSENTER_ESP, tss->x86_tss.sp1, 0); - wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) ia32_sysenter_target, 0); - put_cpu(); -} - #endif /* CONFIG_X86_64 */ +#if defined(CONFIG_X86_32) || defined(CONFIG_COMPAT) +const struct vdso_image *selected_vdso32; +#endif + int __init sysenter_setup(void) { - char *vdso32_start, *vdso32_end; - int npages, i; - #ifdef CONFIG_COMPAT - if (vdso32_syscall()) { - vdso32_start = vdso32_syscall_start; - vdso32_end = vdso32_syscall_end; - vdso32_pages = vdso32_syscall_pages; - } else + if (vdso32_syscall()) + selected_vdso32 = &vdso_image_32_syscall; + else #endif - if (vdso32_sysenter()) { - vdso32_start = vdso32_sysenter_start; - vdso32_end = vdso32_sysenter_end; - vdso32_pages = vdso32_sysenter_pages; - } else { - vdso32_start = vdso32_int80_start; - vdso32_end = vdso32_int80_end; - vdso32_pages = vdso32_int80_pages; - } - - npages = ((vdso32_end - vdso32_start) + PAGE_SIZE - 1) / PAGE_SIZE; - vdso32_size = npages << PAGE_SHIFT; - for (i = 0; i < npages; i++) - vdso32_pages[i] = virt_to_page(vdso32_start + i*PAGE_SIZE); + if (vdso32_sysenter()) + selected_vdso32 = &vdso_image_32_sysenter; + else + selected_vdso32 = &vdso_image_32_int80; - patch_vdso32(vdso32_start, vdso32_size); + init_vdso_image(selected_vdso32); return 0; } -/* Setup a VMA at program startup for the vsyscall page */ -int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) -{ - struct mm_struct *mm = current->mm; - unsigned long addr; - int ret = 0; - struct vm_area_struct *vma; - -#ifdef CONFIG_X86_X32_ABI - if (test_thread_flag(TIF_X32)) - return x32_setup_additional_pages(bprm, uses_interp); -#endif - - if (vdso_enabled != 1) /* Other values all mean "disabled" */ - return 0; - - down_write(&mm->mmap_sem); - - addr = get_unmapped_area(NULL, 0, vdso32_size + VDSO_OFFSET(VDSO_PREV_PAGES), 0, 0); - if (IS_ERR_VALUE(addr)) { - ret = addr; - goto up_fail; - } - - addr += VDSO_OFFSET(VDSO_PREV_PAGES); - - current->mm->context.vdso = (void *)addr; - - /* - * MAYWRITE to allow gdb to COW and set breakpoints - */ - ret = install_special_mapping(mm, - addr, - vdso32_size, - VM_READ|VM_EXEC| - VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, - vdso32_pages); - - if (ret) - goto up_fail; - - vma = _install_special_mapping(mm, - addr - VDSO_OFFSET(VDSO_PREV_PAGES), - VDSO_OFFSET(VDSO_PREV_PAGES), - VM_READ, - NULL); - - if (IS_ERR(vma)) { - ret = PTR_ERR(vma); - goto up_fail; - } - - ret = remap_pfn_range(vma, - addr - VDSO_OFFSET(VDSO_VVAR_PAGE), - __pa_symbol(&__vvar_page) >> PAGE_SHIFT, - PAGE_SIZE, - PAGE_READONLY); - - if (ret) - goto up_fail; - -#ifdef CONFIG_HPET_TIMER - if (hpet_address) { - ret = io_remap_pfn_range(vma, - addr - VDSO_OFFSET(VDSO_HPET_PAGE), - hpet_address >> PAGE_SHIFT, - PAGE_SIZE, - pgprot_noncached(PAGE_READONLY)); - - if (ret) - goto up_fail; - } -#endif - - current_thread_info()->sysenter_return = - VDSO32_SYMBOL(addr, SYSENTER_RETURN); - - up_fail: - if (ret) - current->mm->context.vdso = NULL; - - up_write(&mm->mmap_sem); - - return ret; -} - #ifdef CONFIG_X86_64 subsys_initcall(sysenter_setup); @@ -244,7 +92,7 @@ subsys_initcall(sysenter_setup); static struct ctl_table abi_table2[] = { { .procname = "vsyscall32", - .data = &sysctl_vsyscall32, + .data = &vdso32_enabled, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec diff --git a/arch/x86/vdso/vdso32.S b/arch/x86/vdso/vdso32.S deleted file mode 100644 index 018bcd9f97b426..00000000000000 --- a/arch/x86/vdso/vdso32.S +++ /dev/null @@ -1,9 +0,0 @@ -#include - -DEFINE_VDSO_IMAGE(vdso32_int80, "arch/x86/vdso/vdso32-int80.so") - -#ifdef CONFIG_COMPAT -DEFINE_VDSO_IMAGE(vdso32_syscall, "arch/x86/vdso/vdso32-syscall.so") -#endif - -DEFINE_VDSO_IMAGE(vdso32_sysenter, "arch/x86/vdso/vdso32-sysenter.so") diff --git a/arch/x86/vdso/vdso32/vdso32.lds.S b/arch/x86/vdso/vdso32/vdso32.lds.S index aadb8b9994cd00..31056cf294bf99 100644 --- a/arch/x86/vdso/vdso32/vdso32.lds.S +++ b/arch/x86/vdso/vdso32/vdso32.lds.S @@ -1,17 +1,14 @@ /* * Linker script for 32-bit vDSO. * We #include the file to define the layout details. - * Here we only choose the prelinked virtual address. * * This file defines the version script giving the user-exported symbols in - * the DSO. We can define local symbols here called VDSO* to make their - * values visible using the asm-x86/vdso.h macros from the kernel proper. + * the DSO. */ #include #define BUILD_VDSO32 -#define VDSO_PRELINK 0 #include "../vdso-layout.lds.S" @@ -38,13 +35,3 @@ VERSION local: *; }; } - -/* - * Symbols we define here called VDSO* get their values into vdso32-syms.h. - */ -VDSO32_vsyscall = __kernel_vsyscall; -VDSO32_sigreturn = __kernel_sigreturn; -VDSO32_rt_sigreturn = __kernel_rt_sigreturn; -VDSO32_clock_gettime = clock_gettime; -VDSO32_gettimeofday = gettimeofday; -VDSO32_time = time; diff --git a/arch/x86/vdso/vdsox32.S b/arch/x86/vdso/vdsox32.S deleted file mode 100644 index f4aa34e7f370b9..00000000000000 --- a/arch/x86/vdso/vdsox32.S +++ /dev/null @@ -1,3 +0,0 @@ -#include - -DEFINE_VDSO_IMAGE(vdsox32, "arch/x86/vdso/vdsox32.so") diff --git a/arch/x86/vdso/vdsox32.lds.S b/arch/x86/vdso/vdsox32.lds.S index 62272aa2ae0a7e..46b991b578a8d0 100644 --- a/arch/x86/vdso/vdsox32.lds.S +++ b/arch/x86/vdso/vdsox32.lds.S @@ -1,14 +1,11 @@ /* * Linker script for x32 vDSO. * We #include the file to define the layout details. - * Here we only choose the prelinked virtual address. * * This file defines the version script giving the user-exported symbols in - * the DSO. We can define local symbols here called VDSO* to make their - * values visible using the asm-x86/vdso.h macros from the kernel proper. + * the DSO. */ -#define VDSO_PRELINK 0 #include "vdso-layout.lds.S" /* @@ -24,5 +21,3 @@ VERSION { local: *; }; } - -VDSOX32_PRELINK = VDSO_PRELINK; diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c index 1ad102613127c4..e915eaec4f961b 100644 --- a/arch/x86/vdso/vma.c +++ b/arch/x86/vdso/vma.c @@ -15,115 +15,50 @@ #include #include #include +#include #if defined(CONFIG_X86_64) -unsigned int __read_mostly vdso_enabled = 1; +unsigned int __read_mostly vdso64_enabled = 1; -DECLARE_VDSO_IMAGE(vdso); extern unsigned short vdso_sync_cpuid; -static unsigned vdso_size; - -#ifdef CONFIG_X86_X32_ABI -DECLARE_VDSO_IMAGE(vdsox32); -static unsigned vdsox32_size; -#endif #endif -#if defined(CONFIG_X86_32) || defined(CONFIG_X86_X32_ABI) || \ - defined(CONFIG_COMPAT) -void __init patch_vdso32(void *vdso, size_t len) +void __init init_vdso_image(const struct vdso_image *image) { - Elf32_Ehdr *hdr = vdso; - Elf32_Shdr *sechdrs, *alt_sec = 0; - char *secstrings; - void *alt_data; int i; + int npages = (image->size) / PAGE_SIZE; - BUG_ON(len < sizeof(Elf32_Ehdr)); - BUG_ON(memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0); - - sechdrs = (void *)hdr + hdr->e_shoff; - secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; - - for (i = 1; i < hdr->e_shnum; i++) { - Elf32_Shdr *shdr = &sechdrs[i]; - if (!strcmp(secstrings + shdr->sh_name, ".altinstructions")) { - alt_sec = shdr; - goto found; - } - } - - /* If we get here, it's probably a bug. */ - pr_warning("patch_vdso32: .altinstructions not found\n"); - return; /* nothing to patch */ + BUG_ON(image->size % PAGE_SIZE != 0); + for (i = 0; i < npages; i++) + image->pages[i] = virt_to_page(image->data + i*PAGE_SIZE); -found: - alt_data = (void *)hdr + alt_sec->sh_offset; - apply_alternatives(alt_data, alt_data + alt_sec->sh_size); + apply_alternatives((struct alt_instr *)(image->data + image->alt), + (struct alt_instr *)(image->data + image->alt + + image->alt_len)); } -#endif #if defined(CONFIG_X86_64) -static void __init patch_vdso64(void *vdso, size_t len) -{ - Elf64_Ehdr *hdr = vdso; - Elf64_Shdr *sechdrs, *alt_sec = 0; - char *secstrings; - void *alt_data; - int i; - - BUG_ON(len < sizeof(Elf64_Ehdr)); - BUG_ON(memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0); - - sechdrs = (void *)hdr + hdr->e_shoff; - secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; - - for (i = 1; i < hdr->e_shnum; i++) { - Elf64_Shdr *shdr = &sechdrs[i]; - if (!strcmp(secstrings + shdr->sh_name, ".altinstructions")) { - alt_sec = shdr; - goto found; - } - } - - /* If we get here, it's probably a bug. */ - pr_warning("patch_vdso64: .altinstructions not found\n"); - return; /* nothing to patch */ - -found: - alt_data = (void *)hdr + alt_sec->sh_offset; - apply_alternatives(alt_data, alt_data + alt_sec->sh_size); -} - static int __init init_vdso(void) { - int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE; - int i; - - patch_vdso64(vdso_start, vdso_end - vdso_start); - - vdso_size = npages << PAGE_SHIFT; - for (i = 0; i < npages; i++) - vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE); + init_vdso_image(&vdso_image_64); #ifdef CONFIG_X86_X32_ABI - patch_vdso32(vdsox32_start, vdsox32_end - vdsox32_start); - npages = (vdsox32_end - vdsox32_start + PAGE_SIZE - 1) / PAGE_SIZE; - vdsox32_size = npages << PAGE_SHIFT; - for (i = 0; i < npages; i++) - vdsox32_pages[i] = virt_to_page(vdsox32_start + i*PAGE_SIZE); + init_vdso_image(&vdso_image_x32); #endif return 0; } subsys_initcall(init_vdso); +#endif struct linux_binprm; /* Put the vdso above the (randomized) stack with another randomized offset. This way there is no hole in the middle of address space. To save memory make sure it is still in the same PTE as the stack top. - This doesn't give that many random bits */ + This doesn't give that many random bits. + + Only used for the 64-bit and x32 vdsos. */ static unsigned long vdso_addr(unsigned long start, unsigned len) { unsigned long addr, end; @@ -149,61 +84,142 @@ static unsigned long vdso_addr(unsigned long start, unsigned len) return addr; } -/* Setup a VMA at program startup for the vsyscall page. - Not called for compat tasks */ -static int setup_additional_pages(struct linux_binprm *bprm, - int uses_interp, - struct page **pages, - unsigned size) +static int map_vdso(const struct vdso_image *image, bool calculate_addr) { struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; unsigned long addr; - int ret; + int ret = 0; - if (!vdso_enabled) - return 0; + if (calculate_addr) { + addr = vdso_addr(current->mm->start_stack, + image->sym_end_mapping); + } else { + addr = 0; + } down_write(&mm->mmap_sem); - addr = vdso_addr(mm->start_stack, size); - addr = get_unmapped_area(NULL, addr, size, 0, 0); + + addr = get_unmapped_area(NULL, addr, image->sym_end_mapping, 0, 0); if (IS_ERR_VALUE(addr)) { ret = addr; goto up_fail; } - current->mm->context.vdso = (void *)addr; + current->mm->context.vdso = (void __user *)addr; - ret = install_special_mapping(mm, addr, size, + /* + * MAYWRITE to allow gdb to COW and set breakpoints + */ + ret = install_special_mapping(mm, + addr, + image->size, VM_READ|VM_EXEC| VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, - pages); - if (ret) { - current->mm->context.vdso = NULL; + image->pages); + + if (ret) + goto up_fail; + + vma = _install_special_mapping(mm, + addr + image->size, + image->sym_end_mapping - image->size, + VM_READ, + NULL); + + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); goto up_fail; } + if (image->sym_vvar_page) + ret = remap_pfn_range(vma, + addr + image->sym_vvar_page, + __pa_symbol(&__vvar_page) >> PAGE_SHIFT, + PAGE_SIZE, + PAGE_READONLY); + + if (ret) + goto up_fail; + +#ifdef CONFIG_HPET_TIMER + if (hpet_address && image->sym_hpet_page) { + ret = io_remap_pfn_range(vma, + addr + image->sym_hpet_page, + hpet_address >> PAGE_SHIFT, + PAGE_SIZE, + pgprot_noncached(PAGE_READONLY)); + + if (ret) + goto up_fail; + } +#endif + up_fail: + if (ret) + current->mm->context.vdso = NULL; + up_write(&mm->mmap_sem); return ret; } +#if defined(CONFIG_X86_32) || defined(CONFIG_COMPAT) +static int load_vdso32(void) +{ + int ret; + + if (vdso32_enabled != 1) /* Other values all mean "disabled" */ + return 0; + + ret = map_vdso(selected_vdso32, false); + if (ret) + return ret; + + if (selected_vdso32->sym_VDSO32_SYSENTER_RETURN) + current_thread_info()->sysenter_return = + current->mm->context.vdso + + selected_vdso32->sym_VDSO32_SYSENTER_RETURN; + + return 0; +} +#endif + +#ifdef CONFIG_X86_64 int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { - return setup_additional_pages(bprm, uses_interp, vdso_pages, - vdso_size); + if (!vdso64_enabled) + return 0; + + return map_vdso(&vdso_image_64, true); } +#ifdef CONFIG_COMPAT +int compat_arch_setup_additional_pages(struct linux_binprm *bprm, + int uses_interp) +{ #ifdef CONFIG_X86_X32_ABI -int x32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) + if (test_thread_flag(TIF_X32)) { + if (!vdso64_enabled) + return 0; + + return map_vdso(&vdso_image_x32, true); + } +#endif + + return load_vdso32(); +} +#endif +#else +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { - return setup_additional_pages(bprm, uses_interp, vdsox32_pages, - vdsox32_size); + return load_vdso32(); } #endif +#ifdef CONFIG_X86_64 static __init int vdso_setup(char *s) { - vdso_enabled = simple_strtoul(s, NULL, 0); + vdso64_enabled = simple_strtoul(s, NULL, 0); return 0; } __setup("vdso=", vdso_setup); diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 201d09a7c46bba..c34bfc4bbe7fae 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1515,7 +1515,7 @@ static void __init xen_pvh_early_guest_init(void) } /* First C function to be called on Xen boot */ -asmlinkage void __init xen_start_kernel(void) +asmlinkage __visible void __init xen_start_kernel(void) { struct physdev_set_iopl set_iopl; int rc; diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c index 08f763de26fe41..a1207cb6472a90 100644 --- a/arch/x86/xen/irq.c +++ b/arch/x86/xen/irq.c @@ -23,7 +23,7 @@ void xen_force_evtchn_callback(void) (void)HYPERVISOR_xen_version(0, NULL); } -asmlinkage unsigned long xen_save_fl(void) +asmlinkage __visible unsigned long xen_save_fl(void) { struct vcpu_info *vcpu; unsigned long flags; @@ -63,7 +63,7 @@ __visible void xen_restore_fl(unsigned long flags) } PV_CALLEE_SAVE_REGS_THUNK(xen_restore_fl); -asmlinkage void xen_irq_disable(void) +asmlinkage __visible void xen_irq_disable(void) { /* There's a one instruction preempt window here. We need to make sure we're don't switch CPUs between getting the vcpu @@ -74,7 +74,7 @@ asmlinkage void xen_irq_disable(void) } PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable); -asmlinkage void xen_irq_enable(void) +asmlinkage __visible void xen_irq_enable(void) { struct vcpu_info *vcpu; diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 86e02eabb640bd..3060568248d300 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1494,7 +1494,7 @@ static int xen_pgd_alloc(struct mm_struct *mm) page->private = (unsigned long)user_pgd; if (user_pgd != NULL) { - user_pgd[pgd_index(VSYSCALL_START)] = + user_pgd[pgd_index(VSYSCALL_ADDR)] = __pgd(__pa(level3_user_vsyscall) | _PAGE_TABLE); ret = 0; } @@ -2062,8 +2062,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) case FIX_KMAP_BEGIN ... FIX_KMAP_END: # endif #else - case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE: - case VVAR_PAGE: + case VSYSCALL_PAGE: #endif case FIX_TEXT_POKE0: case FIX_TEXT_POKE1: @@ -2104,8 +2103,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) #ifdef CONFIG_X86_64 /* Replicate changes to map the vsyscall page into the user pagetable vsyscall mapping. */ - if ((idx >= VSYSCALL_LAST_PAGE && idx <= VSYSCALL_FIRST_PAGE) || - idx == VVAR_PAGE) { + if (idx == VSYSCALL_PAGE) { unsigned long vaddr = __fix_to_virt(idx); set_pte_vaddr_pud(level3_user_vsyscall, vaddr, pte); } diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 0982233b9b8433..7225a9557ee298 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -516,10 +516,17 @@ char * __init xen_memory_setup(void) static void __init fiddle_vdso(void) { #ifdef CONFIG_X86_32 + /* + * This could be called before selected_vdso32 is initialized, so + * just fiddle with both possible images. vdso_image_32_syscall + * can't be selected, since it only exists on 64-bit systems. + */ u32 *mask; - mask = VDSO32_SYMBOL(&vdso32_int80_start, NOTE_MASK); + mask = vdso_image_32_int80.data + + vdso_image_32_int80.sym_VDSO32_NOTE_MASK; *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; - mask = VDSO32_SYMBOL(&vdso32_sysenter_start, NOTE_MASK); + mask = vdso_image_32_sysenter.data + + vdso_image_32_sysenter.sym_VDSO32_NOTE_MASK; *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; #endif } diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index e7fb447bce8ead..e5103b47a8cefa 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h @@ -19,6 +19,7 @@ #ifdef __KERNEL__ #include #include +#include #define ATOMIC_INIT(i) { (i) } @@ -387,12 +388,6 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v) #endif } -/* Atomic operations are already serializing */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif /* __KERNEL__ */ #endif /* _XTENSA_ATOMIC_H */ diff --git a/arch/xtensa/include/asm/barrier.h b/arch/xtensa/include/asm/barrier.h index 0a24b04d6b217b..5b88774c75abae 100644 --- a/arch/xtensa/include/asm/barrier.h +++ b/arch/xtensa/include/asm/barrier.h @@ -13,6 +13,9 @@ #define rmb() barrier() #define wmb() mb() +#define smp_mb__before_atomic() barrier() +#define smp_mb__after_atomic() barrier() + #include #endif /* _XTENSA_SYSTEM_H */ diff --git a/arch/xtensa/include/asm/bitops.h b/arch/xtensa/include/asm/bitops.h index 7b6873ae84c295..3f44fa2a53e9fc 100644 --- a/arch/xtensa/include/asm/bitops.h +++ b/arch/xtensa/include/asm/bitops.h @@ -21,9 +21,7 @@ #include #include - -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() +#include #include diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index 562fac664751df..4d54b481123b64 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c @@ -342,7 +342,7 @@ void do_syscall_trace_enter(struct pt_regs *regs) do_syscall_trace(); #if 0 - audit_syscall_entry(current, AUDIT_ARCH_XTENSA..); + audit_syscall_entry(...); #endif } diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index 9757bb74e53296..06370ccea9e90d 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c @@ -74,7 +74,6 @@ extern int initrd_below_start_ok; #endif #ifdef CONFIG_OF -extern u32 __dtb_start[]; void *dtb_start = __dtb_start; #endif @@ -199,7 +198,7 @@ static int __init xtensa_dt_io_area(unsigned long node, const char *uname, int depth, void *data) { const __be32 *ranges; - unsigned long len; + int len; if (depth > 1) return 0; diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index e4a4145926f629..1039fb9ff5f5f9 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -451,7 +451,20 @@ static int blkcg_reset_stats(struct cgroup_subsys_state *css, struct blkcg_gq *blkg; int i; - mutex_lock(&blkcg_pol_mutex); + /* + * XXX: We invoke cgroup_add/rm_cftypes() under blkcg_pol_mutex + * which ends up putting cgroup's internal cgroup_tree_mutex under + * it; however, cgroup_tree_mutex is nested above cgroup file + * active protection and grabbing blkcg_pol_mutex from a cgroup + * file operation creates a possible circular dependency. cgroup + * internal locking is planned to go through further simplification + * and this issue should go away soon. For now, let's trylock + * blkcg_pol_mutex and restart the write on failure. + * + * http://lkml.kernel.org/g/5363C04B.4010400@oracle.com + */ + if (!mutex_trylock(&blkcg_pol_mutex)) + return restart_syscall(); spin_lock_irq(&blkcg->lock); /* diff --git a/block/blk-core.c b/block/blk-core.c index a0e3096c4bb53a..c4269701cb4f79 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -146,8 +146,8 @@ void blk_dump_rq_flags(struct request *rq, char *msg) printk(KERN_INFO " sector %llu, nr/cnr %u/%u\n", (unsigned long long)blk_rq_pos(rq), blk_rq_sectors(rq), blk_rq_cur_sectors(rq)); - printk(KERN_INFO " bio %p, biotail %p, buffer %p, len %u\n", - rq->bio, rq->biotail, rq->buffer, blk_rq_bytes(rq)); + printk(KERN_INFO " bio %p, biotail %p, len %u\n", + rq->bio, rq->biotail, blk_rq_bytes(rq)); if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { printk(KERN_INFO " cdb: "); @@ -251,8 +251,10 @@ void blk_sync_queue(struct request_queue *q) struct blk_mq_hw_ctx *hctx; int i; - queue_for_each_hw_ctx(q, hctx, i) - cancel_delayed_work_sync(&hctx->delayed_work); + queue_for_each_hw_ctx(q, hctx, i) { + cancel_delayed_work_sync(&hctx->run_work); + cancel_delayed_work_sync(&hctx->delay_work); + } } else { cancel_delayed_work_sync(&q->delay_work); } @@ -1360,7 +1362,6 @@ void blk_add_request_payload(struct request *rq, struct page *page, rq->__data_len = rq->resid_len = len; rq->nr_phys_segments = 1; - rq->buffer = bio_data(bio); } EXPORT_SYMBOL_GPL(blk_add_request_payload); @@ -1402,12 +1403,6 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req, bio->bi_next = req->bio; req->bio = bio; - /* - * may not be valid. if the low level driver said - * it didn't need a bounce buffer then it better - * not touch req->buffer either... - */ - req->buffer = bio_data(bio); req->__sector = bio->bi_iter.bi_sector; req->__data_len += bio->bi_iter.bi_size; req->ioprio = ioprio_best(req->ioprio, bio_prio(bio)); @@ -1654,7 +1649,7 @@ static int __init fail_make_request_debugfs(void) struct dentry *dir = fault_create_debugfs_attr("fail_make_request", NULL, &fail_make_request); - return IS_ERR(dir) ? PTR_ERR(dir) : 0; + return PTR_ERR_OR_ZERO(dir); } late_initcall(fail_make_request_debugfs); @@ -2434,7 +2429,6 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) } req->__data_len -= total_bytes; - req->buffer = bio_data(req->bio); /* update sector only for requests with clear definition of sector */ if (req->cmd_type == REQ_TYPE_FS) @@ -2503,7 +2497,7 @@ EXPORT_SYMBOL_GPL(blk_unprep_request); /* * queue lock must be held */ -static void blk_finish_request(struct request *req, int error) +void blk_finish_request(struct request *req, int error) { if (blk_rq_tagged(req)) blk_queue_end_tag(req->q, req); @@ -2529,6 +2523,7 @@ static void blk_finish_request(struct request *req, int error) __blk_put_request(req->q, req); } } +EXPORT_SYMBOL(blk_finish_request); /** * blk_end_bidi_request - Complete a bidi request @@ -2752,10 +2747,9 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, /* Bit 0 (R/W) is identical in rq->cmd_flags and bio->bi_rw */ rq->cmd_flags |= bio->bi_rw & REQ_WRITE; - if (bio_has_data(bio)) { + if (bio_has_data(bio)) rq->nr_phys_segments = bio_phys_segments(q, bio); - rq->buffer = bio_data(bio); - } + rq->__data_len = bio->bi_iter.bi_size; rq->bio = rq->biotail = bio; @@ -2831,7 +2825,7 @@ EXPORT_SYMBOL_GPL(blk_rq_unprep_clone); /* * Copy attributes of the original request to the clone request. - * The actual data parts (e.g. ->cmd, ->buffer, ->sense) are not copied. + * The actual data parts (e.g. ->cmd, ->sense) are not copied. */ static void __blk_rq_prep_clone(struct request *dst, struct request *src) { @@ -2857,7 +2851,7 @@ static void __blk_rq_prep_clone(struct request *dst, struct request *src) * * Description: * Clones bios in @rq_src to @rq, and copies attributes of @rq_src to @rq. - * The actual data parts of @rq_src (e.g. ->cmd, ->buffer, ->sense) + * The actual data parts of @rq_src (e.g. ->cmd, ->sense) * are not copied, and copying such parts is the caller's responsibility. * Also, pages which the original bios are pointing to are not copied * and the cloned bios just point same pages. @@ -2904,19 +2898,26 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src, } EXPORT_SYMBOL_GPL(blk_rq_prep_clone); -int kblockd_schedule_work(struct request_queue *q, struct work_struct *work) +int kblockd_schedule_work(struct work_struct *work) { return queue_work(kblockd_workqueue, work); } EXPORT_SYMBOL(kblockd_schedule_work); -int kblockd_schedule_delayed_work(struct request_queue *q, - struct delayed_work *dwork, unsigned long delay) +int kblockd_schedule_delayed_work(struct delayed_work *dwork, + unsigned long delay) { return queue_delayed_work(kblockd_workqueue, dwork, delay); } EXPORT_SYMBOL(kblockd_schedule_delayed_work); +int kblockd_schedule_delayed_work_on(int cpu, struct delayed_work *dwork, + unsigned long delay) +{ + return queue_delayed_work_on(cpu, kblockd_workqueue, dwork, delay); +} +EXPORT_SYMBOL(kblockd_schedule_delayed_work_on); + #define PLUG_MAGIC 0x91827364 /** diff --git a/block/blk-flush.c b/block/blk-flush.c index 43e6b4755e9a7e..ec7a224d673350 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -134,7 +134,7 @@ static void mq_flush_run(struct work_struct *work) { struct request *rq; - rq = container_of(work, struct request, mq_flush_work); + rq = container_of(work, struct request, requeue_work); memset(&rq->csd, 0, sizeof(rq->csd)); blk_mq_insert_request(rq, false, true, false); @@ -143,8 +143,8 @@ static void mq_flush_run(struct work_struct *work) static bool blk_flush_queue_rq(struct request *rq, bool add_front) { if (rq->q->mq_ops) { - INIT_WORK(&rq->mq_flush_work, mq_flush_run); - kblockd_schedule_work(rq->q, &rq->mq_flush_work); + INIT_WORK(&rq->requeue_work, mq_flush_run); + kblockd_schedule_work(&rq->requeue_work); return false; } else { if (add_front) @@ -306,23 +306,9 @@ static bool blk_kick_flush(struct request_queue *q) */ q->flush_pending_idx ^= 1; - if (q->mq_ops) { - struct blk_mq_ctx *ctx = first_rq->mq_ctx; - struct blk_mq_hw_ctx *hctx = q->mq_ops->map_queue(q, ctx->cpu); - - blk_mq_rq_init(hctx, q->flush_rq); - q->flush_rq->mq_ctx = ctx; - - /* - * Reuse the tag value from the fist waiting request, - * with blk-mq the tag is generated during request - * allocation and drivers can rely on it being inside - * the range they asked for. - */ - q->flush_rq->tag = first_rq->tag; - } else { - blk_rq_init(q, q->flush_rq); - } + blk_rq_init(q, q->flush_rq); + if (q->mq_ops) + blk_mq_clone_flush_request(q->flush_rq, first_rq); q->flush_rq->cmd_type = REQ_TYPE_FS; q->flush_rq->cmd_flags = WRITE_FLUSH | REQ_FLUSH_SEQ; diff --git a/block/blk-iopoll.c b/block/blk-iopoll.c index c11d24e379e2a4..0736729d64941c 100644 --- a/block/blk-iopoll.c +++ b/block/blk-iopoll.c @@ -49,7 +49,7 @@ EXPORT_SYMBOL(blk_iopoll_sched); void __blk_iopoll_complete(struct blk_iopoll *iop) { list_del(&iop->list); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit_unlock(IOPOLL_F_SCHED, &iop->state); } EXPORT_SYMBOL(__blk_iopoll_complete); @@ -64,12 +64,12 @@ EXPORT_SYMBOL(__blk_iopoll_complete); * iopoll handler will not be invoked again before blk_iopoll_sched_prep() * is called. **/ -void blk_iopoll_complete(struct blk_iopoll *iopoll) +void blk_iopoll_complete(struct blk_iopoll *iop) { unsigned long flags; local_irq_save(flags); - __blk_iopoll_complete(iopoll); + __blk_iopoll_complete(iop); local_irq_restore(flags); } EXPORT_SYMBOL(blk_iopoll_complete); @@ -161,7 +161,7 @@ EXPORT_SYMBOL(blk_iopoll_disable); void blk_iopoll_enable(struct blk_iopoll *iop) { BUG_ON(!test_bit(IOPOLL_F_SCHED, &iop->state)); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit_unlock(IOPOLL_F_SCHED, &iop->state); } EXPORT_SYMBOL(blk_iopoll_enable); diff --git a/block/blk-map.c b/block/blk-map.c index f7b22bc215180d..f890d4345b0cb6 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -155,7 +155,6 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq, if (!bio_flagged(bio, BIO_USER_MAPPED)) rq->cmd_flags |= REQ_COPY_USER; - rq->buffer = NULL; return 0; unmap_rq: blk_rq_unmap_user(bio); @@ -238,7 +237,6 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, blk_queue_bounce(q, &bio); bio_get(bio); blk_rq_bio_prep(q, rq, bio); - rq->buffer = NULL; return 0; } EXPORT_SYMBOL(blk_rq_map_user_iov); @@ -325,7 +323,6 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, } blk_queue_bounce(q, &rq->bio); - rq->buffer = NULL; return 0; } EXPORT_SYMBOL(blk_rq_map_kern); diff --git a/block/blk-mq-cpumap.c b/block/blk-mq-cpumap.c index 09792132961991..5d0f93cf358cde 100644 --- a/block/blk-mq-cpumap.c +++ b/block/blk-mq-cpumap.c @@ -80,17 +80,17 @@ int blk_mq_update_queue_map(unsigned int *map, unsigned int nr_queues) return 0; } -unsigned int *blk_mq_make_queue_map(struct blk_mq_reg *reg) +unsigned int *blk_mq_make_queue_map(struct blk_mq_tag_set *set) { unsigned int *map; /* If cpus are offline, map them to first hctx */ map = kzalloc_node(sizeof(*map) * num_possible_cpus(), GFP_KERNEL, - reg->numa_node); + set->numa_node); if (!map) return NULL; - if (!blk_mq_update_queue_map(map, reg->nr_hw_queues)) + if (!blk_mq_update_queue_map(map, set->nr_hw_queues)) return map; kfree(map); diff --git a/block/blk-mq-sysfs.c b/block/blk-mq-sysfs.c index b0ba264b05225c..8145b5b25b4b30 100644 --- a/block/blk-mq-sysfs.c +++ b/block/blk-mq-sysfs.c @@ -203,42 +203,6 @@ static ssize_t blk_mq_hw_sysfs_rq_list_show(struct blk_mq_hw_ctx *hctx, return ret; } -static ssize_t blk_mq_hw_sysfs_ipi_show(struct blk_mq_hw_ctx *hctx, char *page) -{ - ssize_t ret; - - spin_lock(&hctx->lock); - ret = sprintf(page, "%u\n", !!(hctx->flags & BLK_MQ_F_SHOULD_IPI)); - spin_unlock(&hctx->lock); - - return ret; -} - -static ssize_t blk_mq_hw_sysfs_ipi_store(struct blk_mq_hw_ctx *hctx, - const char *page, size_t len) -{ - struct blk_mq_ctx *ctx; - unsigned long ret; - unsigned int i; - - if (kstrtoul(page, 10, &ret)) { - pr_err("blk-mq-sysfs: invalid input '%s'\n", page); - return -EINVAL; - } - - spin_lock(&hctx->lock); - if (ret) - hctx->flags |= BLK_MQ_F_SHOULD_IPI; - else - hctx->flags &= ~BLK_MQ_F_SHOULD_IPI; - spin_unlock(&hctx->lock); - - hctx_for_each_ctx(hctx, ctx, i) - ctx->ipi_redirect = !!ret; - - return len; -} - static ssize_t blk_mq_hw_sysfs_tags_show(struct blk_mq_hw_ctx *hctx, char *page) { return blk_mq_tag_sysfs_show(hctx->tags, page); @@ -246,16 +210,12 @@ static ssize_t blk_mq_hw_sysfs_tags_show(struct blk_mq_hw_ctx *hctx, char *page) static ssize_t blk_mq_hw_sysfs_cpus_show(struct blk_mq_hw_ctx *hctx, char *page) { - unsigned int i, queue_num, first = 1; + unsigned int i, first = 1; ssize_t ret = 0; blk_mq_disable_hotplug(); - for_each_online_cpu(i) { - queue_num = hctx->queue->mq_map[i]; - if (queue_num != hctx->queue_num) - continue; - + for_each_cpu(i, hctx->cpumask) { if (first) ret += sprintf(ret + page, "%u", i); else @@ -311,11 +271,6 @@ static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_pending = { .attr = {.name = "pending", .mode = S_IRUGO }, .show = blk_mq_hw_sysfs_rq_list_show, }; -static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_ipi = { - .attr = {.name = "ipi_redirect", .mode = S_IRUGO | S_IWUSR}, - .show = blk_mq_hw_sysfs_ipi_show, - .store = blk_mq_hw_sysfs_ipi_store, -}; static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_tags = { .attr = {.name = "tags", .mode = S_IRUGO }, .show = blk_mq_hw_sysfs_tags_show, @@ -330,7 +285,6 @@ static struct attribute *default_hw_ctx_attrs[] = { &blk_mq_hw_sysfs_run.attr, &blk_mq_hw_sysfs_dispatched.attr, &blk_mq_hw_sysfs_pending.attr, - &blk_mq_hw_sysfs_ipi.attr, &blk_mq_hw_sysfs_tags.attr, &blk_mq_hw_sysfs_cpus.attr, NULL, diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index 83ae96c51a2762..8dc933bcc22bb9 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -1,78 +1,256 @@ #include #include -#include +#include #include #include "blk.h" #include "blk-mq.h" #include "blk-mq-tag.h" +void blk_mq_wait_for_tags(struct blk_mq_tags *tags, struct blk_mq_hw_ctx *hctx, + bool reserved) +{ + int tag, zero = 0; + + tag = blk_mq_get_tag(tags, hctx, &zero, __GFP_WAIT, reserved); + blk_mq_put_tag(tags, tag, &zero); +} + +static bool bt_has_free_tags(struct blk_mq_bitmap_tags *bt) +{ + int i; + + for (i = 0; i < bt->map_nr; i++) { + struct blk_mq_bitmap *bm = &bt->map[i]; + int ret; + + ret = find_first_zero_bit(&bm->word, bm->depth); + if (ret < bm->depth) + return true; + } + + return false; +} + +bool blk_mq_has_free_tags(struct blk_mq_tags *tags) +{ + if (!tags) + return true; + + return bt_has_free_tags(&tags->bitmap_tags); +} + +static int __bt_get_word(struct blk_mq_bitmap *bm, unsigned int last_tag) +{ + int tag, org_last_tag, end; + + org_last_tag = last_tag = TAG_TO_BIT(last_tag); + end = bm->depth; + do { +restart: + tag = find_next_zero_bit(&bm->word, end, last_tag); + if (unlikely(tag >= end)) { + /* + * We started with an offset, start from 0 to + * exhaust the map. + */ + if (org_last_tag && last_tag) { + end = last_tag; + last_tag = 0; + goto restart; + } + return -1; + } + last_tag = tag + 1; + } while (test_and_set_bit_lock(tag, &bm->word)); + + return tag; +} + /* - * Per tagged queue (tag address space) map + * Straight forward bitmap tag implementation, where each bit is a tag + * (cleared == free, and set == busy). The small twist is using per-cpu + * last_tag caches, which blk-mq stores in the blk_mq_ctx software queue + * contexts. This enables us to drastically limit the space searched, + * without dirtying an extra shared cacheline like we would if we stored + * the cache value inside the shared blk_mq_bitmap_tags structure. On top + * of that, each word of tags is in a separate cacheline. This means that + * multiple users will tend to stick to different cachelines, at least + * until the map is exhausted. */ -struct blk_mq_tags { - unsigned int nr_tags; - unsigned int nr_reserved_tags; - unsigned int nr_batch_move; - unsigned int nr_max_cache; +static int __bt_get(struct blk_mq_bitmap_tags *bt, unsigned int *tag_cache) +{ + unsigned int last_tag, org_last_tag; + int index, i, tag; + + last_tag = org_last_tag = *tag_cache; + index = TAG_TO_INDEX(last_tag); + + for (i = 0; i < bt->map_nr; i++) { + tag = __bt_get_word(&bt->map[index], last_tag); + if (tag != -1) { + tag += index * BITS_PER_LONG; + goto done; + } + + last_tag = 0; + if (++index >= bt->map_nr) + index = 0; + } + + *tag_cache = 0; + return -1; + + /* + * Only update the cache from the allocation path, if we ended + * up using the specific cached tag. + */ +done: + if (tag == org_last_tag) { + last_tag = tag + 1; + if (last_tag >= bt->depth - 1) + last_tag = 0; + + *tag_cache = last_tag; + } - struct percpu_ida free_tags; - struct percpu_ida reserved_tags; -}; + return tag; +} -void blk_mq_wait_for_tags(struct blk_mq_tags *tags) +static inline void bt_index_inc(unsigned int *index) { - int tag = blk_mq_get_tag(tags, __GFP_WAIT, false); - blk_mq_put_tag(tags, tag); + *index = (*index + 1) & (BT_WAIT_QUEUES - 1); } -bool blk_mq_has_free_tags(struct blk_mq_tags *tags) +static struct bt_wait_state *bt_wait_ptr(struct blk_mq_bitmap_tags *bt, + struct blk_mq_hw_ctx *hctx) { - return !tags || - percpu_ida_free_tags(&tags->free_tags, nr_cpu_ids) != 0; + struct bt_wait_state *bs; + + if (!hctx) + return &bt->bs[0]; + + bs = &bt->bs[hctx->wait_index]; + bt_index_inc(&hctx->wait_index); + return bs; } -static unsigned int __blk_mq_get_tag(struct blk_mq_tags *tags, gfp_t gfp) +static int bt_get(struct blk_mq_bitmap_tags *bt, struct blk_mq_hw_ctx *hctx, + unsigned int *last_tag, gfp_t gfp) { + struct bt_wait_state *bs; + DEFINE_WAIT(wait); int tag; - tag = percpu_ida_alloc(&tags->free_tags, (gfp & __GFP_WAIT) ? - TASK_UNINTERRUPTIBLE : TASK_RUNNING); - if (tag < 0) - return BLK_MQ_TAG_FAIL; - return tag + tags->nr_reserved_tags; + tag = __bt_get(bt, last_tag); + if (tag != -1) + return tag; + + if (!(gfp & __GFP_WAIT)) + return -1; + + bs = bt_wait_ptr(bt, hctx); + do { + bool was_empty; + + was_empty = prepare_to_wait(&bs->wait, &wait, TASK_UNINTERRUPTIBLE); + + tag = __bt_get(bt, last_tag); + if (tag != -1) + break; + + if (was_empty) + atomic_set(&bs->wait_cnt, BT_WAIT_BATCH); + + io_schedule(); + } while (1); + + finish_wait(&bs->wait, &wait); + return tag; +} + +static unsigned int __blk_mq_get_tag(struct blk_mq_tags *tags, + struct blk_mq_hw_ctx *hctx, + unsigned int *last_tag, gfp_t gfp) +{ + int tag; + + tag = bt_get(&tags->bitmap_tags, hctx, last_tag, gfp); + if (tag >= 0) + return tag + tags->nr_reserved_tags; + + return BLK_MQ_TAG_FAIL; } static unsigned int __blk_mq_get_reserved_tag(struct blk_mq_tags *tags, gfp_t gfp) { - int tag; + int tag, zero = 0; if (unlikely(!tags->nr_reserved_tags)) { WARN_ON_ONCE(1); return BLK_MQ_TAG_FAIL; } - tag = percpu_ida_alloc(&tags->reserved_tags, (gfp & __GFP_WAIT) ? - TASK_UNINTERRUPTIBLE : TASK_RUNNING); + tag = bt_get(&tags->breserved_tags, NULL, &zero, gfp); if (tag < 0) return BLK_MQ_TAG_FAIL; + return tag; } -unsigned int blk_mq_get_tag(struct blk_mq_tags *tags, gfp_t gfp, bool reserved) +unsigned int blk_mq_get_tag(struct blk_mq_tags *tags, + struct blk_mq_hw_ctx *hctx, unsigned int *last_tag, + gfp_t gfp, bool reserved) { if (!reserved) - return __blk_mq_get_tag(tags, gfp); + return __blk_mq_get_tag(tags, hctx, last_tag, gfp); return __blk_mq_get_reserved_tag(tags, gfp); } +static struct bt_wait_state *bt_wake_ptr(struct blk_mq_bitmap_tags *bt) +{ + int i, wake_index; + + wake_index = bt->wake_index; + for (i = 0; i < BT_WAIT_QUEUES; i++) { + struct bt_wait_state *bs = &bt->bs[wake_index]; + + if (waitqueue_active(&bs->wait)) { + if (wake_index != bt->wake_index) + bt->wake_index = wake_index; + + return bs; + } + + bt_index_inc(&wake_index); + } + + return NULL; +} + +static void bt_clear_tag(struct blk_mq_bitmap_tags *bt, unsigned int tag) +{ + const int index = TAG_TO_INDEX(tag); + struct bt_wait_state *bs; + + clear_bit(TAG_TO_BIT(tag), &bt->map[index].word); + + bs = bt_wake_ptr(bt); + if (bs && atomic_dec_and_test(&bs->wait_cnt)) { + smp_mb__after_clear_bit(); + atomic_set(&bs->wait_cnt, BT_WAIT_BATCH); + bt_index_inc(&bt->wake_index); + wake_up(&bs->wait); + } +} + static void __blk_mq_put_tag(struct blk_mq_tags *tags, unsigned int tag) { BUG_ON(tag >= tags->nr_tags); - percpu_ida_free(&tags->free_tags, tag - tags->nr_reserved_tags); + bt_clear_tag(&tags->bitmap_tags, tag); } static void __blk_mq_put_reserved_tag(struct blk_mq_tags *tags, @@ -80,22 +258,40 @@ static void __blk_mq_put_reserved_tag(struct blk_mq_tags *tags, { BUG_ON(tag >= tags->nr_reserved_tags); - percpu_ida_free(&tags->reserved_tags, tag); + bt_clear_tag(&tags->breserved_tags, tag); } -void blk_mq_put_tag(struct blk_mq_tags *tags, unsigned int tag) +void blk_mq_put_tag(struct blk_mq_tags *tags, unsigned int tag, + unsigned int *last_tag) { - if (tag >= tags->nr_reserved_tags) - __blk_mq_put_tag(tags, tag); - else + if (tag >= tags->nr_reserved_tags) { + const int real_tag = tag - tags->nr_reserved_tags; + + __blk_mq_put_tag(tags, real_tag); + *last_tag = real_tag; + } else __blk_mq_put_reserved_tag(tags, tag); } -static int __blk_mq_tag_iter(unsigned id, void *data) +static void bt_for_each_free(struct blk_mq_bitmap_tags *bt, + unsigned long *free_map, unsigned int off) { - unsigned long *tag_map = data; - __set_bit(id, tag_map); - return 0; + int i, bit = 0; + + for (i = 0; i < bt->map_nr; i++) { + struct blk_mq_bitmap *bm = &bt->map[i]; + + do { + bit = find_next_zero_bit(&bm->word, bm->depth, bit); + if (bit >= bm->depth) + break; + + __set_bit(bit + off, free_map); + bit++; + } while (1); + + off += BITS_PER_LONG; + } } void blk_mq_tag_busy_iter(struct blk_mq_tags *tags, @@ -109,21 +305,94 @@ void blk_mq_tag_busy_iter(struct blk_mq_tags *tags, if (!tag_map) return; - percpu_ida_for_each_free(&tags->free_tags, __blk_mq_tag_iter, tag_map); + bt_for_each_free(&tags->bitmap_tags, tag_map, tags->nr_reserved_tags); if (tags->nr_reserved_tags) - percpu_ida_for_each_free(&tags->reserved_tags, __blk_mq_tag_iter, - tag_map); + bt_for_each_free(&tags->breserved_tags, tag_map, 0); fn(data, tag_map); kfree(tag_map); } +static unsigned int bt_unused_tags(struct blk_mq_bitmap_tags *bt) +{ + unsigned int i, used; + + for (i = 0, used = 0; i < bt->map_nr; i++) { + struct blk_mq_bitmap *bm = &bt->map[i]; + + used += bitmap_weight(&bm->word, bm->depth); + } + + return bt->depth - used; +} + +static int bt_alloc(struct blk_mq_bitmap_tags *bt, unsigned int depth, + int node, bool reserved) +{ + int i; + + /* + * Depth can be zero for reserved tags, that's not a failure + * condition. + */ + if (depth) { + int nr, i, map_depth; + + nr = ALIGN(depth, BITS_PER_LONG) / BITS_PER_LONG; + bt->map = kzalloc_node(nr * sizeof(struct blk_mq_bitmap), + GFP_KERNEL, node); + if (!bt->map) + return -ENOMEM; + + bt->map_nr = nr; + map_depth = depth; + for (i = 0; i < nr; i++) { + bt->map[i].depth = min(map_depth, BITS_PER_LONG); + map_depth -= BITS_PER_LONG; + } + } + + bt->bs = kzalloc(BT_WAIT_QUEUES * sizeof(*bt->bs), GFP_KERNEL); + if (!bt->bs) { + kfree(bt->map); + return -ENOMEM; + } + + for (i = 0; i < BT_WAIT_QUEUES; i++) + init_waitqueue_head(&bt->bs[i].wait); + + bt->depth = depth; + return 0; +} + +static void bt_free(struct blk_mq_bitmap_tags *bt) +{ + kfree(bt->map); + kfree(bt->bs); +} + +static struct blk_mq_tags *blk_mq_init_bitmap_tags(struct blk_mq_tags *tags, + int node) +{ + unsigned int depth = tags->nr_tags - tags->nr_reserved_tags; + + if (bt_alloc(&tags->bitmap_tags, depth, node, false)) + goto enomem; + if (bt_alloc(&tags->breserved_tags, tags->nr_reserved_tags, node, true)) + goto enomem; + + return tags; +enomem: + bt_free(&tags->bitmap_tags); + kfree(tags); + return NULL; +} + struct blk_mq_tags *blk_mq_init_tags(unsigned int total_tags, unsigned int reserved_tags, int node) { unsigned int nr_tags, nr_cache; struct blk_mq_tags *tags; - int ret; if (total_tags > BLK_MQ_TAG_MAX) { pr_err("blk-mq: tag depth too large\n"); @@ -135,72 +404,44 @@ struct blk_mq_tags *blk_mq_init_tags(unsigned int total_tags, return NULL; nr_tags = total_tags - reserved_tags; - nr_cache = nr_tags / num_possible_cpus(); - - if (nr_cache < BLK_MQ_TAG_CACHE_MIN) - nr_cache = BLK_MQ_TAG_CACHE_MIN; - else if (nr_cache > BLK_MQ_TAG_CACHE_MAX) - nr_cache = BLK_MQ_TAG_CACHE_MAX; + nr_cache = nr_tags / num_online_cpus(); tags->nr_tags = total_tags; tags->nr_reserved_tags = reserved_tags; - tags->nr_max_cache = nr_cache; - tags->nr_batch_move = max(1u, nr_cache / 2); - - ret = __percpu_ida_init(&tags->free_tags, tags->nr_tags - - tags->nr_reserved_tags, - tags->nr_max_cache, - tags->nr_batch_move); - if (ret) - goto err_free_tags; - - if (reserved_tags) { - /* - * With max_cahe and batch set to 1, the allocator fallbacks to - * no cached. It's fine reserved tags allocation is slow. - */ - ret = __percpu_ida_init(&tags->reserved_tags, reserved_tags, - 1, 1); - if (ret) - goto err_reserved_tags; - } - return tags; + return blk_mq_init_bitmap_tags(tags, node); -err_reserved_tags: - percpu_ida_destroy(&tags->free_tags); -err_free_tags: - kfree(tags); - return NULL; } void blk_mq_free_tags(struct blk_mq_tags *tags) { - percpu_ida_destroy(&tags->free_tags); - percpu_ida_destroy(&tags->reserved_tags); + bt_free(&tags->bitmap_tags); + bt_free(&tags->breserved_tags); kfree(tags); } +void blk_mq_tag_init_last_tag(struct blk_mq_tags *tags, unsigned int *tag) +{ + unsigned int depth = tags->nr_tags - tags->nr_reserved_tags; + + *tag = prandom_u32() % (depth - 1); +} + ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page) { char *orig_page = page; - unsigned int cpu; + unsigned int free, res; if (!tags) return 0; - page += sprintf(page, "nr_tags=%u, reserved_tags=%u, batch_move=%u," - " max_cache=%u\n", tags->nr_tags, tags->nr_reserved_tags, - tags->nr_batch_move, tags->nr_max_cache); + page += sprintf(page, "nr_tags=%u, reserved_tags=%u\n", + tags->nr_tags, tags->nr_reserved_tags); - page += sprintf(page, "nr_free=%u, nr_reserved=%u\n", - percpu_ida_free_tags(&tags->free_tags, nr_cpu_ids), - percpu_ida_free_tags(&tags->reserved_tags, nr_cpu_ids)); + free = bt_unused_tags(&tags->bitmap_tags); + res = bt_unused_tags(&tags->breserved_tags); - for_each_possible_cpu(cpu) { - page += sprintf(page, " cpu%02u: nr_free=%u\n", cpu, - percpu_ida_free_tags(&tags->free_tags, cpu)); - } + page += sprintf(page, "nr_free=%u, nr_reserved=%u\n", free, res); return page - orig_page; } diff --git a/block/blk-mq-tag.h b/block/blk-mq-tag.h index 947ba2c6148e0b..06d4a2f0f7a04f 100644 --- a/block/blk-mq-tag.h +++ b/block/blk-mq-tag.h @@ -1,17 +1,60 @@ #ifndef INT_BLK_MQ_TAG_H #define INT_BLK_MQ_TAG_H -struct blk_mq_tags; +enum { + BT_WAIT_QUEUES = 8, + BT_WAIT_BATCH = 8, +}; + +struct bt_wait_state { + atomic_t wait_cnt; + wait_queue_head_t wait; +} ____cacheline_aligned_in_smp; + +#define TAG_TO_INDEX(tag) ((tag) / BITS_PER_LONG) +#define TAG_TO_BIT(tag) ((tag) & (BITS_PER_LONG - 1)) + +struct blk_mq_bitmap { + unsigned long word; + unsigned long depth; +} ____cacheline_aligned_in_smp; + +struct blk_mq_bitmap_tags { + unsigned int depth; + unsigned int wake_cnt; + + struct blk_mq_bitmap *map; + unsigned int map_nr; + + unsigned int wake_index; + struct bt_wait_state *bs; +}; + +/* + * Tag address space map. + */ +struct blk_mq_tags { + unsigned int nr_tags; + unsigned int nr_reserved_tags; + + struct blk_mq_bitmap_tags bitmap_tags; + struct blk_mq_bitmap_tags breserved_tags; + + struct request **rqs; + struct list_head page_list; +}; + extern struct blk_mq_tags *blk_mq_init_tags(unsigned int nr_tags, unsigned int reserved_tags, int node); extern void blk_mq_free_tags(struct blk_mq_tags *tags); -extern unsigned int blk_mq_get_tag(struct blk_mq_tags *tags, gfp_t gfp, bool reserved); -extern void blk_mq_wait_for_tags(struct blk_mq_tags *tags); -extern void blk_mq_put_tag(struct blk_mq_tags *tags, unsigned int tag); +extern unsigned int blk_mq_get_tag(struct blk_mq_tags *tags, struct blk_mq_hw_ctx *hctx, unsigned int *last_tag, gfp_t gfp, bool reserved); +extern void blk_mq_wait_for_tags(struct blk_mq_tags *tags, struct blk_mq_hw_ctx *hctx, bool reserved); +extern void blk_mq_put_tag(struct blk_mq_tags *tags, unsigned int tag, unsigned int *last_tag); extern void blk_mq_tag_busy_iter(struct blk_mq_tags *tags, void (*fn)(void *data, unsigned long *), void *data); extern bool blk_mq_has_free_tags(struct blk_mq_tags *tags); extern ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page); +extern void blk_mq_tag_init_last_tag(struct blk_mq_tags *tags, unsigned int *last_tag); enum { BLK_MQ_TAG_CACHE_MIN = 1, diff --git a/block/blk-mq.c b/block/blk-mq.c index 1d2a9bdbee57f1..0c02d0e6ed30b0 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -74,16 +74,16 @@ static void blk_mq_hctx_mark_pending(struct blk_mq_hw_ctx *hctx, } static struct request *__blk_mq_alloc_request(struct blk_mq_hw_ctx *hctx, + struct blk_mq_ctx *ctx, gfp_t gfp, bool reserved) { struct request *rq; unsigned int tag; - tag = blk_mq_get_tag(hctx->tags, gfp, reserved); + tag = blk_mq_get_tag(hctx->tags, hctx, &ctx->last_tag, gfp, reserved); if (tag != BLK_MQ_TAG_FAIL) { - rq = hctx->rqs[tag]; + rq = hctx->tags->rqs[tag]; rq->tag = tag; - return rq; } @@ -186,10 +186,54 @@ static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx, if (blk_queue_io_stat(q)) rw_flags |= REQ_IO_STAT; + INIT_LIST_HEAD(&rq->queuelist); + /* csd/requeue_work/fifo_time is initialized before use */ + rq->q = q; rq->mq_ctx = ctx; rq->cmd_flags = rw_flags; + rq->cmd_type = 0; + /* do not touch atomic flags, it needs atomic ops against the timer */ + rq->cpu = -1; + rq->__data_len = 0; + rq->__sector = (sector_t) -1; + rq->bio = NULL; + rq->biotail = NULL; + INIT_HLIST_NODE(&rq->hash); + RB_CLEAR_NODE(&rq->rb_node); + memset(&rq->flush, 0, max(sizeof(rq->flush), sizeof(rq->elv))); + rq->rq_disk = NULL; + rq->part = NULL; rq->start_time = jiffies; +#ifdef CONFIG_BLK_CGROUP + rq->rl = NULL; set_start_time_ns(rq); + rq->io_start_time_ns = 0; +#endif + rq->nr_phys_segments = 0; +#if defined(CONFIG_BLK_DEV_INTEGRITY) + rq->nr_integrity_segments = 0; +#endif + rq->ioprio = 0; + rq->special = NULL; + /* tag was already set */ + rq->errors = 0; + memset(rq->__cmd, 0, sizeof(rq->__cmd)); + rq->cmd = rq->__cmd; + rq->cmd_len = BLK_MAX_CDB; + + rq->extra_len = 0; + rq->sense_len = 0; + rq->resid_len = 0; + rq->sense = NULL; + + rq->deadline = 0; + INIT_LIST_HEAD(&rq->timeout_list); + rq->timeout = 0; + rq->retries = 0; + rq->end_io = NULL; + rq->end_io_data = NULL; + rq->next_rq = NULL; + ctx->rq_dispatched[rw_is_sync(rw_flags)]++; } @@ -203,18 +247,22 @@ static struct request *blk_mq_alloc_request_pinned(struct request_queue *q, struct blk_mq_ctx *ctx = blk_mq_get_ctx(q); struct blk_mq_hw_ctx *hctx = q->mq_ops->map_queue(q, ctx->cpu); - rq = __blk_mq_alloc_request(hctx, gfp & ~__GFP_WAIT, reserved); + rq = __blk_mq_alloc_request(hctx, ctx, gfp & ~__GFP_WAIT, + reserved); if (rq) { blk_mq_rq_ctx_init(q, ctx, rq, rw); break; } - blk_mq_put_ctx(ctx); - if (!(gfp & __GFP_WAIT)) + if (gfp & __GFP_WAIT) { + __blk_mq_run_hw_queue(hctx); + blk_mq_put_ctx(ctx); + } else { + blk_mq_put_ctx(ctx); break; + } - __blk_mq_run_hw_queue(hctx); - blk_mq_wait_for_tags(hctx->tags); + blk_mq_wait_for_tags(hctx->tags, hctx, reserved); } while (1); return rq; @@ -232,6 +280,7 @@ struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp) blk_mq_put_ctx(rq->mq_ctx); return rq; } +EXPORT_SYMBOL(blk_mq_alloc_request); struct request *blk_mq_alloc_reserved_request(struct request_queue *q, int rw, gfp_t gfp) @@ -248,26 +297,14 @@ struct request *blk_mq_alloc_reserved_request(struct request_queue *q, int rw, } EXPORT_SYMBOL(blk_mq_alloc_reserved_request); -/* - * Re-init and set pdu, if we have it - */ -void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq) -{ - blk_rq_init(hctx->queue, rq); - - if (hctx->cmd_size) - rq->special = blk_mq_rq_to_pdu(rq); -} - static void __blk_mq_free_request(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx, struct request *rq) { const int tag = rq->tag; struct request_queue *q = rq->q; - blk_mq_rq_init(hctx, rq); - blk_mq_put_tag(hctx->tags, tag); - + clear_bit(REQ_ATOM_STARTED, &rq->atomic_flags); + blk_mq_put_tag(hctx->tags, tag, &ctx->last_tag); blk_mq_queue_exit(q); } @@ -283,20 +320,47 @@ void blk_mq_free_request(struct request *rq) __blk_mq_free_request(hctx, ctx, rq); } -bool blk_mq_end_io_partial(struct request *rq, int error, unsigned int nr_bytes) +/* + * Clone all relevant state from a request that has been put on hold in + * the flush state machine into the preallocated flush request that hangs + * off the request queue. + * + * For a driver the flush request should be invisible, that's why we are + * impersonating the original request here. + */ +void blk_mq_clone_flush_request(struct request *flush_rq, + struct request *orig_rq) { - if (blk_update_request(rq, error, blk_rq_bytes(rq))) - return true; + struct blk_mq_hw_ctx *hctx = + orig_rq->q->mq_ops->map_queue(orig_rq->q, orig_rq->mq_ctx->cpu); + flush_rq->mq_ctx = orig_rq->mq_ctx; + flush_rq->tag = orig_rq->tag; + memcpy(blk_mq_rq_to_pdu(flush_rq), blk_mq_rq_to_pdu(orig_rq), + hctx->cmd_size); +} + +inline void __blk_mq_end_io(struct request *rq, int error) +{ blk_account_io_done(rq); - if (rq->end_io) + if (rq->end_io) { rq->end_io(rq, error); - else + } else { + if (unlikely(blk_bidi_rq(rq))) + blk_mq_free_request(rq->next_rq); blk_mq_free_request(rq); - return false; + } } -EXPORT_SYMBOL(blk_mq_end_io_partial); +EXPORT_SYMBOL(__blk_mq_end_io); + +void blk_mq_end_io(struct request *rq, int error) +{ + if (blk_update_request(rq, error, blk_rq_bytes(rq))) + BUG(); + __blk_mq_end_io(rq, error); +} +EXPORT_SYMBOL(blk_mq_end_io); static void __blk_mq_complete_request_remote(void *data) { @@ -308,15 +372,19 @@ static void __blk_mq_complete_request_remote(void *data) void __blk_mq_complete_request(struct request *rq) { struct blk_mq_ctx *ctx = rq->mq_ctx; + bool shared = false; int cpu; - if (!ctx->ipi_redirect) { + if (!test_bit(QUEUE_FLAG_SAME_COMP, &rq->q->queue_flags)) { rq->q->softirq_done_fn(rq); return; } cpu = get_cpu(); - if (cpu != ctx->cpu && cpu_online(ctx->cpu)) { + if (!test_bit(QUEUE_FLAG_SAME_FORCE, &rq->q->queue_flags)) + shared = cpus_share_cache(cpu, ctx->cpu); + + if (cpu != ctx->cpu && !shared && ctx->online) { rq->csd.func = __blk_mq_complete_request_remote; rq->csd.info = rq; rq->csd.flags = 0; @@ -350,13 +418,25 @@ static void blk_mq_start_request(struct request *rq, bool last) trace_block_rq_issue(q, rq); + rq->resid_len = blk_rq_bytes(rq); + if (unlikely(blk_bidi_rq(rq))) + rq->next_rq->resid_len = blk_rq_bytes(rq->next_rq); + /* * Just mark start time and set the started bit. Due to memory * ordering, we know we'll see the correct deadline as long as * REQ_ATOMIC_STARTED is seen. */ rq->deadline = jiffies + q->rq_timeout; + + /* + * Mark us as started and clear complete. Complete might have been + * set if requeue raced with timeout, which then marked it as + * complete. So be sure to clear complete again when we start + * the request, otherwise we'll ignore the completion event. + */ set_bit(REQ_ATOM_STARTED, &rq->atomic_flags); + clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags); if (q->dma_drain_size && blk_rq_bytes(rq)) { /* @@ -378,7 +458,7 @@ static void blk_mq_start_request(struct request *rq, bool last) rq->cmd_flags |= REQ_END; } -static void blk_mq_requeue_request(struct request *rq) +static void __blk_mq_requeue_request(struct request *rq) { struct request_queue *q = rq->q; @@ -391,6 +471,22 @@ static void blk_mq_requeue_request(struct request *rq) rq->nr_phys_segments--; } +void blk_mq_requeue_request(struct request *rq) +{ + __blk_mq_requeue_request(rq); + blk_clear_rq_complete(rq); + + BUG_ON(blk_queued_rq(rq)); + blk_mq_insert_request(rq, true, true, false); +} +EXPORT_SYMBOL(blk_mq_requeue_request); + +struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag) +{ + return tags->rqs[tag]; +} +EXPORT_SYMBOL(blk_mq_tag_to_rq); + struct blk_mq_timeout_data { struct blk_mq_hw_ctx *hctx; unsigned long *next; @@ -412,12 +508,13 @@ static void blk_mq_timeout_check(void *__data, unsigned long *free_tags) do { struct request *rq; - tag = find_next_zero_bit(free_tags, hctx->queue_depth, tag); - if (tag >= hctx->queue_depth) + tag = find_next_zero_bit(free_tags, hctx->tags->nr_tags, tag); + if (tag >= hctx->tags->nr_tags) break; - rq = hctx->rqs[tag++]; - + rq = blk_mq_tag_to_rq(hctx->tags, tag++); + if (rq->q != hctx->queue) + continue; if (!test_bit(REQ_ATOM_STARTED, &rq->atomic_flags)) continue; @@ -442,6 +539,28 @@ static void blk_mq_hw_ctx_check_timeout(struct blk_mq_hw_ctx *hctx, blk_mq_tag_busy_iter(hctx->tags, blk_mq_timeout_check, &data); } +static enum blk_eh_timer_return blk_mq_rq_timed_out(struct request *rq) +{ + struct request_queue *q = rq->q; + + /* + * We know that complete is set at this point. If STARTED isn't set + * anymore, then the request isn't active and the "timeout" should + * just be ignored. This can happen due to the bitflag ordering. + * Timeout first checks if STARTED is set, and if it is, assumes + * the request is active. But if we race with completion, then + * we both flags will get cleared. So check here again, and ignore + * a timeout event with a request that isn't active. + */ + if (!test_bit(REQ_ATOM_STARTED, &rq->atomic_flags)) + return BLK_EH_NOT_HANDLED; + + if (!q->mq_ops->timeout) + return BLK_EH_RESET_TIMER; + + return q->mq_ops->timeout(rq); +} + static void blk_mq_rq_timer(unsigned long data) { struct request_queue *q = (struct request_queue *) data; @@ -495,11 +614,6 @@ static bool blk_mq_attempt_merge(struct request_queue *q, return false; } -void blk_mq_add_timer(struct request *rq) -{ - __blk_add_timer(rq, NULL); -} - /* * Run this hardware queue, pulling any software queues mapped to it in. * Note that this function currently has various problems around ordering @@ -514,6 +628,8 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx) LIST_HEAD(rq_list); int bit, queued; + WARN_ON(!cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask)); + if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state))) return; @@ -525,7 +641,6 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx) for_each_set_bit(bit, hctx->ctx_map, hctx->nr_ctx) { clear_bit(bit, hctx->ctx_map); ctx = hctx->ctxs[bit]; - BUG_ON(bit != ctx->index_hw); spin_lock(&ctx->lock); list_splice_tail_init(&ctx->rq_list, &rq_list); @@ -565,13 +680,8 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx) queued++; continue; case BLK_MQ_RQ_QUEUE_BUSY: - /* - * FIXME: we should have a mechanism to stop the queue - * like blk_stop_queue, otherwise we will waste cpu - * time - */ list_add(&rq->queuelist, &rq_list); - blk_mq_requeue_request(rq); + __blk_mq_requeue_request(rq); break; default: pr_err("blk-mq: bad return on queue: %d\n", ret); @@ -601,17 +711,44 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx) } } +/* + * It'd be great if the workqueue API had a way to pass + * in a mask and had some smarts for more clever placement. + * For now we just round-robin here, switching for every + * BLK_MQ_CPU_WORK_BATCH queued items. + */ +static int blk_mq_hctx_next_cpu(struct blk_mq_hw_ctx *hctx) +{ + int cpu = hctx->next_cpu; + + if (--hctx->next_cpu_batch <= 0) { + int next_cpu; + + next_cpu = cpumask_next(hctx->next_cpu, hctx->cpumask); + if (next_cpu >= nr_cpu_ids) + next_cpu = cpumask_first(hctx->cpumask); + + hctx->next_cpu = next_cpu; + hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH; + } + + return cpu; +} + void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async) { if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state))) return; - if (!async) + if (!async && cpumask_test_cpu(smp_processor_id(), hctx->cpumask)) __blk_mq_run_hw_queue(hctx); + else if (hctx->queue->nr_hw_queues == 1) + kblockd_schedule_delayed_work(&hctx->run_work, 0); else { - struct request_queue *q = hctx->queue; + unsigned int cpu; - kblockd_schedule_delayed_work(q, &hctx->delayed_work, 0); + cpu = blk_mq_hctx_next_cpu(hctx); + kblockd_schedule_delayed_work_on(cpu, &hctx->run_work, 0); } } @@ -626,14 +763,17 @@ void blk_mq_run_queues(struct request_queue *q, bool async) test_bit(BLK_MQ_S_STOPPED, &hctx->state)) continue; + preempt_disable(); blk_mq_run_hw_queue(hctx, async); + preempt_enable(); } } EXPORT_SYMBOL(blk_mq_run_queues); void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx) { - cancel_delayed_work(&hctx->delayed_work); + cancel_delayed_work(&hctx->run_work); + cancel_delayed_work(&hctx->delay_work); set_bit(BLK_MQ_S_STOPPED, &hctx->state); } EXPORT_SYMBOL(blk_mq_stop_hw_queue); @@ -651,11 +791,25 @@ EXPORT_SYMBOL(blk_mq_stop_hw_queues); void blk_mq_start_hw_queue(struct blk_mq_hw_ctx *hctx) { clear_bit(BLK_MQ_S_STOPPED, &hctx->state); + + preempt_disable(); __blk_mq_run_hw_queue(hctx); + preempt_enable(); } EXPORT_SYMBOL(blk_mq_start_hw_queue); -void blk_mq_start_stopped_hw_queues(struct request_queue *q) +void blk_mq_start_hw_queues(struct request_queue *q) +{ + struct blk_mq_hw_ctx *hctx; + int i; + + queue_for_each_hw_ctx(q, hctx, i) + blk_mq_start_hw_queue(hctx); +} +EXPORT_SYMBOL(blk_mq_start_hw_queues); + + +void blk_mq_start_stopped_hw_queues(struct request_queue *q, bool async) { struct blk_mq_hw_ctx *hctx; int i; @@ -665,19 +819,47 @@ void blk_mq_start_stopped_hw_queues(struct request_queue *q) continue; clear_bit(BLK_MQ_S_STOPPED, &hctx->state); - blk_mq_run_hw_queue(hctx, true); + preempt_disable(); + blk_mq_run_hw_queue(hctx, async); + preempt_enable(); } } EXPORT_SYMBOL(blk_mq_start_stopped_hw_queues); -static void blk_mq_work_fn(struct work_struct *work) +static void blk_mq_run_work_fn(struct work_struct *work) { struct blk_mq_hw_ctx *hctx; - hctx = container_of(work, struct blk_mq_hw_ctx, delayed_work.work); + hctx = container_of(work, struct blk_mq_hw_ctx, run_work.work); + __blk_mq_run_hw_queue(hctx); } +static void blk_mq_delay_work_fn(struct work_struct *work) +{ + struct blk_mq_hw_ctx *hctx; + + hctx = container_of(work, struct blk_mq_hw_ctx, delay_work.work); + + if (test_and_clear_bit(BLK_MQ_S_STOPPED, &hctx->state)) + __blk_mq_run_hw_queue(hctx); +} + +void blk_mq_delay_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs) +{ + unsigned long tmo = msecs_to_jiffies(msecs); + + if (hctx->queue->nr_hw_queues == 1) + kblockd_schedule_delayed_work(&hctx->delay_work, tmo); + else { + unsigned int cpu; + + cpu = blk_mq_hctx_next_cpu(hctx); + kblockd_schedule_delayed_work_on(cpu, &hctx->delay_work, tmo); + } +} +EXPORT_SYMBOL(blk_mq_delay_queue); + static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq, bool at_head) { @@ -689,12 +871,13 @@ static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, list_add(&rq->queuelist, &ctx->rq_list); else list_add_tail(&rq->queuelist, &ctx->rq_list); + blk_mq_hctx_mark_pending(hctx, ctx); /* * We do this early, to ensure we are on the right CPU. */ - blk_mq_add_timer(rq); + blk_add_timer(rq); } void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue, @@ -705,7 +888,7 @@ void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue, struct blk_mq_ctx *ctx = rq->mq_ctx, *current_ctx; current_ctx = blk_mq_get_ctx(q); - if (!cpu_online(ctx->cpu)) + if (!ctx->online) rq->mq_ctx = ctx = current_ctx; hctx = q->mq_ops->map_queue(q, ctx->cpu); @@ -719,10 +902,10 @@ void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue, spin_unlock(&ctx->lock); } - blk_mq_put_ctx(current_ctx); - if (run_queue) blk_mq_run_hw_queue(hctx, async); + + blk_mq_put_ctx(current_ctx); } static void blk_mq_insert_requests(struct request_queue *q, @@ -739,7 +922,7 @@ static void blk_mq_insert_requests(struct request_queue *q, current_ctx = blk_mq_get_ctx(q); - if (!cpu_online(ctx->cpu)) + if (!ctx->online) ctx = current_ctx; hctx = q->mq_ops->map_queue(q, ctx->cpu); @@ -758,9 +941,8 @@ static void blk_mq_insert_requests(struct request_queue *q, } spin_unlock(&ctx->lock); - blk_mq_put_ctx(current_ctx); - blk_mq_run_hw_queue(hctx, from_schedule); + blk_mq_put_ctx(current_ctx); } static int plug_ctx_cmp(void *priv, struct list_head *a, struct list_head *b) @@ -863,7 +1045,7 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio) if (is_sync) rw |= REQ_SYNC; trace_block_getrq(q, bio, rw); - rq = __blk_mq_alloc_request(hctx, GFP_ATOMIC, false); + rq = __blk_mq_alloc_request(hctx, ctx, GFP_ATOMIC, false); if (likely(rq)) blk_mq_rq_ctx_init(q, ctx, rq, rw); else { @@ -879,7 +1061,6 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio) if (unlikely(is_flush_fua)) { blk_mq_bio_to_request(rq, bio); - blk_mq_put_ctx(ctx); blk_insert_flush(rq); goto run_queue; } @@ -906,18 +1087,25 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio) } } - spin_lock(&ctx->lock); + if (!(hctx->flags & BLK_MQ_F_SHOULD_MERGE)) { + init_request_from_bio(rq, bio); - if ((hctx->flags & BLK_MQ_F_SHOULD_MERGE) && - blk_mq_attempt_merge(q, ctx, bio)) - __blk_mq_free_request(hctx, ctx, rq); - else { - blk_mq_bio_to_request(rq, bio); + spin_lock(&ctx->lock); +insert_rq: __blk_mq_insert_request(hctx, rq, false); + spin_unlock(&ctx->lock); + blk_account_io_start(rq, 1); + } else { + spin_lock(&ctx->lock); + if (!blk_mq_attempt_merge(q, ctx, bio)) { + init_request_from_bio(rq, bio); + goto insert_rq; + } + + spin_unlock(&ctx->lock); + __blk_mq_free_request(hctx, ctx, rq); } - spin_unlock(&ctx->lock); - blk_mq_put_ctx(ctx); /* * For a SYNC request, send it to the hardware immediately. For an @@ -926,6 +1114,7 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio) */ run_queue: blk_mq_run_hw_queue(hctx, !is_sync || is_flush_fua); + blk_mq_put_ctx(ctx); } /* @@ -937,11 +1126,11 @@ struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *q, const int cpu) } EXPORT_SYMBOL(blk_mq_map_queue); -struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_reg *reg, +struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_tag_set *set, unsigned int hctx_index) { - return kmalloc_node(sizeof(struct blk_mq_hw_ctx), - GFP_KERNEL | __GFP_ZERO, reg->numa_node); + return kzalloc_node(sizeof(struct blk_mq_hw_ctx), GFP_KERNEL, + set->numa_node); } EXPORT_SYMBOL(blk_mq_alloc_single_hw_queue); @@ -993,124 +1182,73 @@ static void blk_mq_hctx_notify(void *data, unsigned long action, blk_mq_hctx_mark_pending(hctx, ctx); spin_unlock(&ctx->lock); - blk_mq_put_ctx(ctx); blk_mq_run_hw_queue(hctx, true); + blk_mq_put_ctx(ctx); } -static int blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx, - int (*init)(void *, struct blk_mq_hw_ctx *, - struct request *, unsigned int), - void *data) -{ - unsigned int i; - int ret = 0; - - for (i = 0; i < hctx->queue_depth; i++) { - struct request *rq = hctx->rqs[i]; - - ret = init(data, hctx, rq, i); - if (ret) - break; - } - - return ret; -} - -int blk_mq_init_commands(struct request_queue *q, - int (*init)(void *, struct blk_mq_hw_ctx *, - struct request *, unsigned int), - void *data) -{ - struct blk_mq_hw_ctx *hctx; - unsigned int i; - int ret = 0; - - queue_for_each_hw_ctx(q, hctx, i) { - ret = blk_mq_init_hw_commands(hctx, init, data); - if (ret) - break; - } - - return ret; -} -EXPORT_SYMBOL(blk_mq_init_commands); - -static void blk_mq_free_hw_commands(struct blk_mq_hw_ctx *hctx, - void (*free)(void *, struct blk_mq_hw_ctx *, - struct request *, unsigned int), - void *data) +static void blk_mq_free_rq_map(struct blk_mq_tag_set *set, + struct blk_mq_tags *tags, unsigned int hctx_idx) { - unsigned int i; + struct page *page; - for (i = 0; i < hctx->queue_depth; i++) { - struct request *rq = hctx->rqs[i]; + if (tags->rqs && set->ops->exit_request) { + int i; - free(data, hctx, rq, i); + for (i = 0; i < tags->nr_tags; i++) { + if (!tags->rqs[i]) + continue; + set->ops->exit_request(set->driver_data, tags->rqs[i], + hctx_idx, i); + } } -} - -void blk_mq_free_commands(struct request_queue *q, - void (*free)(void *, struct blk_mq_hw_ctx *, - struct request *, unsigned int), - void *data) -{ - struct blk_mq_hw_ctx *hctx; - unsigned int i; - - queue_for_each_hw_ctx(q, hctx, i) - blk_mq_free_hw_commands(hctx, free, data); -} -EXPORT_SYMBOL(blk_mq_free_commands); -static void blk_mq_free_rq_map(struct blk_mq_hw_ctx *hctx) -{ - struct page *page; - - while (!list_empty(&hctx->page_list)) { - page = list_first_entry(&hctx->page_list, struct page, lru); + while (!list_empty(&tags->page_list)) { + page = list_first_entry(&tags->page_list, struct page, lru); list_del_init(&page->lru); __free_pages(page, page->private); } - kfree(hctx->rqs); + kfree(tags->rqs); - if (hctx->tags) - blk_mq_free_tags(hctx->tags); + blk_mq_free_tags(tags); } static size_t order_to_size(unsigned int order) { - size_t ret = PAGE_SIZE; - - while (order--) - ret *= 2; - - return ret; + return (size_t)PAGE_SIZE << order; } -static int blk_mq_init_rq_map(struct blk_mq_hw_ctx *hctx, - unsigned int reserved_tags, int node) +static struct blk_mq_tags *blk_mq_init_rq_map(struct blk_mq_tag_set *set, + unsigned int hctx_idx) { + struct blk_mq_tags *tags; unsigned int i, j, entries_per_page, max_order = 4; size_t rq_size, left; - INIT_LIST_HEAD(&hctx->page_list); + tags = blk_mq_init_tags(set->queue_depth, set->reserved_tags, + set->numa_node); + if (!tags) + return NULL; - hctx->rqs = kmalloc_node(hctx->queue_depth * sizeof(struct request *), - GFP_KERNEL, node); - if (!hctx->rqs) - return -ENOMEM; + INIT_LIST_HEAD(&tags->page_list); + + tags->rqs = kmalloc_node(set->queue_depth * sizeof(struct request *), + GFP_KERNEL, set->numa_node); + if (!tags->rqs) { + blk_mq_free_tags(tags); + return NULL; + } /* * rq_size is the size of the request plus driver payload, rounded * to the cacheline size */ - rq_size = round_up(sizeof(struct request) + hctx->cmd_size, + rq_size = round_up(sizeof(struct request) + set->cmd_size, cache_line_size()); - left = rq_size * hctx->queue_depth; + left = rq_size * set->queue_depth; - for (i = 0; i < hctx->queue_depth;) { + for (i = 0; i < set->queue_depth; ) { int this_order = max_order; struct page *page; int to_do; @@ -1120,7 +1258,8 @@ static int blk_mq_init_rq_map(struct blk_mq_hw_ctx *hctx, this_order--; do { - page = alloc_pages_node(node, GFP_KERNEL, this_order); + page = alloc_pages_node(set->numa_node, GFP_KERNEL, + this_order); if (page) break; if (!this_order--) @@ -1130,43 +1269,39 @@ static int blk_mq_init_rq_map(struct blk_mq_hw_ctx *hctx, } while (1); if (!page) - break; + goto fail; page->private = this_order; - list_add_tail(&page->lru, &hctx->page_list); + list_add_tail(&page->lru, &tags->page_list); p = page_address(page); entries_per_page = order_to_size(this_order) / rq_size; - to_do = min(entries_per_page, hctx->queue_depth - i); + to_do = min(entries_per_page, set->queue_depth - i); left -= to_do * rq_size; for (j = 0; j < to_do; j++) { - hctx->rqs[i] = p; - blk_mq_rq_init(hctx, hctx->rqs[i]); + tags->rqs[i] = p; + if (set->ops->init_request) { + if (set->ops->init_request(set->driver_data, + tags->rqs[i], hctx_idx, i, + set->numa_node)) + goto fail; + } + p += rq_size; i++; } } - if (i < (reserved_tags + BLK_MQ_TAG_MIN)) - goto err_rq_map; - else if (i != hctx->queue_depth) { - hctx->queue_depth = i; - pr_warn("%s: queue depth set to %u because of low memory\n", - __func__, i); - } + return tags; - hctx->tags = blk_mq_init_tags(hctx->queue_depth, reserved_tags, node); - if (!hctx->tags) { -err_rq_map: - blk_mq_free_rq_map(hctx); - return -ENOMEM; - } - - return 0; +fail: + pr_warn("%s: failed to allocate requests\n", __func__); + blk_mq_free_rq_map(set, tags, hctx_idx); + return NULL; } static int blk_mq_init_hw_queues(struct request_queue *q, - struct blk_mq_reg *reg, void *driver_data) + struct blk_mq_tag_set *set) { struct blk_mq_hw_ctx *hctx; unsigned int i, j; @@ -1180,23 +1315,22 @@ static int blk_mq_init_hw_queues(struct request_queue *q, node = hctx->numa_node; if (node == NUMA_NO_NODE) - node = hctx->numa_node = reg->numa_node; + node = hctx->numa_node = set->numa_node; - INIT_DELAYED_WORK(&hctx->delayed_work, blk_mq_work_fn); + INIT_DELAYED_WORK(&hctx->run_work, blk_mq_run_work_fn); + INIT_DELAYED_WORK(&hctx->delay_work, blk_mq_delay_work_fn); spin_lock_init(&hctx->lock); INIT_LIST_HEAD(&hctx->dispatch); hctx->queue = q; hctx->queue_num = i; - hctx->flags = reg->flags; - hctx->queue_depth = reg->queue_depth; - hctx->cmd_size = reg->cmd_size; + hctx->flags = set->flags; + hctx->cmd_size = set->cmd_size; blk_mq_init_cpu_notifier(&hctx->cpu_notifier, blk_mq_hctx_notify, hctx); blk_mq_register_cpu_notifier(&hctx->cpu_notifier); - if (blk_mq_init_rq_map(hctx, reg->reserved_tags, node)) - break; + hctx->tags = set->tags[i]; /* * Allocate space for all possible cpus to avoid allocation in @@ -1216,8 +1350,8 @@ static int blk_mq_init_hw_queues(struct request_queue *q, hctx->nr_ctx_map = num_maps; hctx->nr_ctx = 0; - if (reg->ops->init_hctx && - reg->ops->init_hctx(hctx, driver_data, i)) + if (set->ops->init_hctx && + set->ops->init_hctx(hctx, set->driver_data, i)) break; } @@ -1231,12 +1365,12 @@ static int blk_mq_init_hw_queues(struct request_queue *q, if (i == j) break; - if (reg->ops->exit_hctx) - reg->ops->exit_hctx(hctx, j); + if (set->ops->exit_hctx) + set->ops->exit_hctx(hctx, j); blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier); - blk_mq_free_rq_map(hctx); kfree(hctx->ctxs); + kfree(hctx->ctx_map); } return 1; @@ -1258,12 +1392,14 @@ static void blk_mq_init_cpu_queues(struct request_queue *q, __ctx->queue = q; /* If the cpu isn't online, the cpu is mapped to first hctx */ - hctx = q->mq_ops->map_queue(q, i); - hctx->nr_ctx++; - if (!cpu_online(i)) continue; + __ctx->online = 1; + hctx = q->mq_ops->map_queue(q, i); + cpumask_set_cpu(i, hctx->cpumask); + hctx->nr_ctx++; + /* * Set local node, IFF we have more than one hw queue. If * not, we remain on the home node of the device @@ -1280,6 +1416,7 @@ static void blk_mq_map_swqueue(struct request_queue *q) struct blk_mq_ctx *ctx; queue_for_each_hw_ctx(q, hctx, i) { + cpumask_clear(hctx->cpumask); hctx->nr_ctx = 0; } @@ -1288,59 +1425,58 @@ static void blk_mq_map_swqueue(struct request_queue *q) */ queue_for_each_ctx(q, ctx, i) { /* If the cpu isn't online, the cpu is mapped to first hctx */ + if (!cpu_online(i)) { + ctx->online = 0; + continue; + } + + ctx->online = 1; hctx = q->mq_ops->map_queue(q, i); + cpumask_set_cpu(i, hctx->cpumask); ctx->index_hw = hctx->nr_ctx; hctx->ctxs[hctx->nr_ctx++] = ctx; } + + queue_for_each_hw_ctx(q, hctx, i) { + hctx->next_cpu = cpumask_first(hctx->cpumask); + hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH; + } } -struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg, - void *driver_data) +struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) { struct blk_mq_hw_ctx **hctxs; struct blk_mq_ctx *ctx; struct request_queue *q; int i; - if (!reg->nr_hw_queues || - !reg->ops->queue_rq || !reg->ops->map_queue || - !reg->ops->alloc_hctx || !reg->ops->free_hctx) - return ERR_PTR(-EINVAL); - - if (!reg->queue_depth) - reg->queue_depth = BLK_MQ_MAX_DEPTH; - else if (reg->queue_depth > BLK_MQ_MAX_DEPTH) { - pr_err("blk-mq: queuedepth too large (%u)\n", reg->queue_depth); - reg->queue_depth = BLK_MQ_MAX_DEPTH; - } - - if (reg->queue_depth < (reg->reserved_tags + BLK_MQ_TAG_MIN)) - return ERR_PTR(-EINVAL); - ctx = alloc_percpu(struct blk_mq_ctx); if (!ctx) return ERR_PTR(-ENOMEM); - hctxs = kmalloc_node(reg->nr_hw_queues * sizeof(*hctxs), GFP_KERNEL, - reg->numa_node); + hctxs = kmalloc_node(set->nr_hw_queues * sizeof(*hctxs), GFP_KERNEL, + set->numa_node); if (!hctxs) goto err_percpu; - for (i = 0; i < reg->nr_hw_queues; i++) { - hctxs[i] = reg->ops->alloc_hctx(reg, i); + for (i = 0; i < set->nr_hw_queues; i++) { + hctxs[i] = set->ops->alloc_hctx(set, i); if (!hctxs[i]) goto err_hctxs; + if (!zalloc_cpumask_var(&hctxs[i]->cpumask, GFP_KERNEL)) + goto err_hctxs; + hctxs[i]->numa_node = NUMA_NO_NODE; hctxs[i]->queue_num = i; } - q = blk_alloc_queue_node(GFP_KERNEL, reg->numa_node); + q = blk_alloc_queue_node(GFP_KERNEL, set->numa_node); if (!q) goto err_hctxs; - q->mq_map = blk_mq_make_queue_map(reg); + q->mq_map = blk_mq_make_queue_map(set); if (!q->mq_map) goto err_map; @@ -1348,33 +1484,34 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg, blk_queue_rq_timeout(q, 30000); q->nr_queues = nr_cpu_ids; - q->nr_hw_queues = reg->nr_hw_queues; + q->nr_hw_queues = set->nr_hw_queues; q->queue_ctx = ctx; q->queue_hw_ctx = hctxs; - q->mq_ops = reg->ops; + q->mq_ops = set->ops; q->queue_flags |= QUEUE_FLAG_MQ_DEFAULT; q->sg_reserved_size = INT_MAX; blk_queue_make_request(q, blk_mq_make_request); - blk_queue_rq_timed_out(q, reg->ops->timeout); - if (reg->timeout) - blk_queue_rq_timeout(q, reg->timeout); + blk_queue_rq_timed_out(q, blk_mq_rq_timed_out); + if (set->timeout) + blk_queue_rq_timeout(q, set->timeout); - if (reg->ops->complete) - blk_queue_softirq_done(q, reg->ops->complete); + if (set->ops->complete) + blk_queue_softirq_done(q, set->ops->complete); blk_mq_init_flush(q); - blk_mq_init_cpu_queues(q, reg->nr_hw_queues); + blk_mq_init_cpu_queues(q, set->nr_hw_queues); - q->flush_rq = kzalloc(round_up(sizeof(struct request) + reg->cmd_size, - cache_line_size()), GFP_KERNEL); + q->flush_rq = kzalloc(round_up(sizeof(struct request) + + set->cmd_size, cache_line_size()), + GFP_KERNEL); if (!q->flush_rq) goto err_hw; - if (blk_mq_init_hw_queues(q, reg, driver_data)) + if (blk_mq_init_hw_queues(q, set)) goto err_flush_rq; blk_mq_map_swqueue(q); @@ -1392,10 +1529,11 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg, err_map: blk_cleanup_queue(q); err_hctxs: - for (i = 0; i < reg->nr_hw_queues; i++) { + for (i = 0; i < set->nr_hw_queues; i++) { if (!hctxs[i]) break; - reg->ops->free_hctx(hctxs[i], i); + free_cpumask_var(hctxs[i]->cpumask); + set->ops->free_hctx(hctxs[i], i); } kfree(hctxs); err_percpu: @@ -1412,10 +1550,10 @@ void blk_mq_free_queue(struct request_queue *q) queue_for_each_hw_ctx(q, hctx, i) { kfree(hctx->ctx_map); kfree(hctx->ctxs); - blk_mq_free_rq_map(hctx); blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier); if (q->mq_ops->exit_hctx) q->mq_ops->exit_hctx(hctx, i); + free_cpumask_var(hctx->cpumask); q->mq_ops->free_hctx(hctx, i); } @@ -1456,10 +1594,10 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb, struct request_queue *q; /* - * Before new mapping is established, hotadded cpu might already start - * handling requests. This doesn't break anything as we map offline - * CPUs to first hardware queue. We will re-init queue below to get - * optimal settings. + * Before new mappings are established, hotadded cpu might already + * start handling requests. This doesn't break anything as we map + * offline CPUs to first hardware queue. We will re-init the queue + * below to get optimal settings. */ if (action != CPU_DEAD && action != CPU_DEAD_FROZEN && action != CPU_ONLINE && action != CPU_ONLINE_FROZEN) @@ -1472,6 +1610,55 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb, return NOTIFY_OK; } +int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set) +{ + int i; + + if (!set->nr_hw_queues) + return -EINVAL; + if (!set->queue_depth || set->queue_depth > BLK_MQ_MAX_DEPTH) + return -EINVAL; + if (set->queue_depth < set->reserved_tags + BLK_MQ_TAG_MIN) + return -EINVAL; + + if (!set->nr_hw_queues || + !set->ops->queue_rq || !set->ops->map_queue || + !set->ops->alloc_hctx || !set->ops->free_hctx) + return -EINVAL; + + + set->tags = kmalloc_node(set->nr_hw_queues * + sizeof(struct blk_mq_tags *), + GFP_KERNEL, set->numa_node); + if (!set->tags) + goto out; + + for (i = 0; i < set->nr_hw_queues; i++) { + set->tags[i] = blk_mq_init_rq_map(set, i); + if (!set->tags[i]) + goto out_unwind; + } + + return 0; + +out_unwind: + while (--i >= 0) + blk_mq_free_rq_map(set, set->tags[i], i); +out: + return -ENOMEM; +} +EXPORT_SYMBOL(blk_mq_alloc_tag_set); + +void blk_mq_free_tag_set(struct blk_mq_tag_set *set) +{ + int i; + + for (i = 0; i < set->nr_hw_queues; i++) + blk_mq_free_rq_map(set, set->tags[i], i); + kfree(set->tags); +} +EXPORT_SYMBOL(blk_mq_free_tag_set); + void blk_mq_disable_hotplug(void) { mutex_lock(&all_q_mutex); diff --git a/block/blk-mq.h b/block/blk-mq.h index ebbe6bac9d616d..1f06426918e46f 100644 --- a/block/blk-mq.h +++ b/block/blk-mq.h @@ -1,6 +1,8 @@ #ifndef INT_BLK_MQ_H #define INT_BLK_MQ_H +struct blk_mq_tag_set; + struct blk_mq_ctx { struct { spinlock_t lock; @@ -8,8 +10,10 @@ struct blk_mq_ctx { } ____cacheline_aligned_in_smp; unsigned int cpu; + unsigned int online; unsigned int index_hw; - unsigned int ipi_redirect; + + unsigned int last_tag ____cacheline_aligned_in_smp; /* incremented at dispatch time */ unsigned long rq_dispatched[2]; @@ -20,14 +24,15 @@ struct blk_mq_ctx { struct request_queue *queue; struct kobject kobj; -}; +} ____cacheline_aligned_in_smp; void __blk_mq_complete_request(struct request *rq); void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async); void blk_mq_init_flush(struct request_queue *q); void blk_mq_drain_queue(struct request_queue *q); void blk_mq_free_queue(struct request_queue *q); -void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq); +void blk_mq_clone_flush_request(struct request *flush_rq, + struct request *orig_rq); /* * CPU hotplug helpers @@ -45,10 +50,7 @@ void blk_mq_disable_hotplug(void); /* * CPU -> queue mappings */ -struct blk_mq_reg; -extern unsigned int *blk_mq_make_queue_map(struct blk_mq_reg *reg); +extern unsigned int *blk_mq_make_queue_map(struct blk_mq_tag_set *set); extern int blk_mq_update_queue_map(unsigned int *map, unsigned int nr_queues); -void blk_mq_add_timer(struct request *rq); - #endif diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 033745cd7fba62..9353b468335930 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -744,7 +744,7 @@ static inline void throtl_extend_slice(struct throtl_grp *tg, bool rw, static bool throtl_slice_used(struct throtl_grp *tg, bool rw) { if (time_in_range(jiffies, tg->slice_start[rw], tg->slice_end[rw])) - return 0; + return false; return 1; } @@ -842,7 +842,7 @@ static bool tg_with_in_iops_limit(struct throtl_grp *tg, struct bio *bio, if (tg->io_disp[rw] + 1 <= io_allowed) { if (wait) *wait = 0; - return 1; + return true; } /* Calc approx time to dispatch */ @@ -880,7 +880,7 @@ static bool tg_with_in_bps_limit(struct throtl_grp *tg, struct bio *bio, if (tg->bytes_disp[rw] + bio->bi_iter.bi_size <= bytes_allowed) { if (wait) *wait = 0; - return 1; + return true; } /* Calc approx time to dispatch */ @@ -923,7 +923,7 @@ static bool tg_may_dispatch(struct throtl_grp *tg, struct bio *bio, if (tg->bps[rw] == -1 && tg->iops[rw] == -1) { if (wait) *wait = 0; - return 1; + return true; } /* @@ -1258,7 +1258,7 @@ static void throtl_pending_timer_fn(unsigned long arg) * of throtl_data->service_queue. Those bio's are ready and issued by this * function. */ -void blk_throtl_dispatch_work_fn(struct work_struct *work) +static void blk_throtl_dispatch_work_fn(struct work_struct *work) { struct throtl_data *td = container_of(work, struct throtl_data, dispatch_work); diff --git a/block/blk-timeout.c b/block/blk-timeout.c index d96f7061c6fd87..448745683d28bc 100644 --- a/block/blk-timeout.c +++ b/block/blk-timeout.c @@ -96,11 +96,7 @@ static void blk_rq_timed_out(struct request *req) __blk_complete_request(req); break; case BLK_EH_RESET_TIMER: - if (q->mq_ops) - blk_mq_add_timer(req); - else - blk_add_timer(req); - + blk_add_timer(req); blk_clear_rq_complete(req); break; case BLK_EH_NOT_HANDLED: @@ -170,7 +166,15 @@ void blk_abort_request(struct request *req) } EXPORT_SYMBOL_GPL(blk_abort_request); -void __blk_add_timer(struct request *req, struct list_head *timeout_list) +/** + * blk_add_timer - Start timeout timer for a single request + * @req: request that is about to start running. + * + * Notes: + * Each request has its own timer, and as it is added to the queue, we + * set up the timer. When the request completes, we cancel the timer. + */ +void blk_add_timer(struct request *req) { struct request_queue *q = req->q; unsigned long expiry; @@ -188,8 +192,8 @@ void __blk_add_timer(struct request *req, struct list_head *timeout_list) req->timeout = q->rq_timeout; req->deadline = jiffies + req->timeout; - if (timeout_list) - list_add_tail(&req->timeout_list, timeout_list); + if (!q->mq_ops) + list_add_tail(&req->timeout_list, &req->q->timeout_list); /* * If the timer isn't already pending or this timeout is earlier @@ -199,21 +203,18 @@ void __blk_add_timer(struct request *req, struct list_head *timeout_list) expiry = round_jiffies_up(req->deadline); if (!timer_pending(&q->timeout) || - time_before(expiry, q->timeout.expires)) - mod_timer(&q->timeout, expiry); + time_before(expiry, q->timeout.expires)) { + unsigned long diff = q->timeout.expires - expiry; -} + /* + * Due to added timer slack to group timers, the timer + * will often be a little in front of what we asked for. + * So apply some tolerance here too, otherwise we keep + * modifying the timer because expires for value X + * will be X + something. + */ + if (diff >= HZ / 2) + mod_timer(&q->timeout, expiry); + } -/** - * blk_add_timer - Start timeout timer for a single request - * @req: request that is about to start running. - * - * Notes: - * Each request has its own timer, and as it is added to the queue, we - * set up the timer. When the request completes, we cancel the timer. - */ -void blk_add_timer(struct request *req) -{ - __blk_add_timer(req, &req->q->timeout_list); } - diff --git a/block/blk.h b/block/blk.h index 1d880f1f957fe4..79be2cbce7fd37 100644 --- a/block/blk.h +++ b/block/blk.h @@ -37,9 +37,8 @@ bool __blk_end_bidi_request(struct request *rq, int error, void blk_rq_timed_out_timer(unsigned long data); void blk_rq_check_expired(struct request *rq, unsigned long *next_timeout, unsigned int *next_set); -void __blk_add_timer(struct request *req, struct list_head *timeout_list); +void blk_add_timer(struct request *req); void blk_delete_timer(struct request *); -void blk_add_timer(struct request *); bool bio_attempt_front_merge(struct request_queue *q, struct request *req, diff --git a/block/bsg.c b/block/bsg.c index 420a5a9f1b23f7..e5214c1480962e 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -1008,7 +1008,7 @@ int bsg_register_queue(struct request_queue *q, struct device *parent, /* * we need a proper transport to send commands, not a stacked device */ - if (!q->request_fn) + if (!queue_is_rq_based(q)) return 0; bcd = &q->bsg_dev; diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index e0985f1955e7e0..22dffebc7c7353 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -908,7 +908,7 @@ static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) { if (cfqd->busy_queues) { cfq_log(cfqd, "schedule dispatch"); - kblockd_schedule_work(cfqd->queue, &cfqd->unplug_work); + kblockd_schedule_work(&cfqd->unplug_work); } } @@ -4460,7 +4460,7 @@ static int cfq_init_queue(struct request_queue *q, struct elevator_type *e) static ssize_t cfq_var_show(unsigned int var, char *page) { - return sprintf(page, "%d\n", var); + return sprintf(page, "%u\n", var); } static ssize_t diff --git a/crypto/chainiv.c b/crypto/chainiv.c index 834d8dd3d4fc7a..9c294c8f9a0788 100644 --- a/crypto/chainiv.c +++ b/crypto/chainiv.c @@ -126,7 +126,7 @@ static int async_chainiv_schedule_work(struct async_chainiv_ctx *ctx) int err = ctx->err; if (!ctx->queue.qlen) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(CHAINIV_STATE_INUSE, &ctx->state); if (!ctx->queue.qlen || diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index 43665d0d0905dd..e2a34feec7a4cf 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -265,6 +265,9 @@ static int crypto_update_alg(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr *priority = attrs[CRYPTOCFGA_PRIORITY_VAL]; LIST_HEAD(list); + if (!netlink_capable(skb, CAP_NET_ADMIN)) + return -EPERM; + if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name)) return -EINVAL; @@ -295,6 +298,9 @@ static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh, struct crypto_alg *alg; struct crypto_user_alg *p = nlmsg_data(nlh); + if (!netlink_capable(skb, CAP_NET_ADMIN)) + return -EPERM; + if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name)) return -EINVAL; @@ -379,6 +385,9 @@ static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh, struct crypto_user_alg *p = nlmsg_data(nlh); struct nlattr *priority = attrs[CRYPTOCFGA_PRIORITY_VAL]; + if (!netlink_capable(skb, CAP_NET_ADMIN)) + return -EPERM; + if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name)) return -EINVAL; @@ -466,9 +475,6 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) type -= CRYPTO_MSG_BASE; link = &crypto_dispatch[type]; - if (!netlink_capable(skb, CAP_NET_ADMIN)) - return -EPERM; - if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) && (nlh->nlmsg_flags & NLM_F_DUMP))) { struct crypto_alg *alg; diff --git a/crypto/shash.c b/crypto/shash.c index 929058a6856126..47c713954bf30e 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -67,7 +67,8 @@ EXPORT_SYMBOL_GPL(crypto_shash_setkey); static inline unsigned int shash_align_buffer_size(unsigned len, unsigned long mask) { - return len + (mask & ~(__alignof__(u8 __attribute__ ((aligned))) - 1)); + typedef u8 __attribute__ ((aligned)) u8_aligned; + return len + (mask & ~(__alignof__(u8_aligned) - 1)); } static int shash_update_unaligned(struct shash_desc *desc, const u8 *data, diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 870be7b4dc0529..09c93ff216e41d 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -282,6 +282,11 @@ static void test_aead_speed(const char *algo, int enc, unsigned int sec, unsigned int *b_size; unsigned int iv_len; + if (aad_size >= PAGE_SIZE) { + pr_err("associate data length (%u) too big\n", aad_size); + return; + } + if (enc == ENCRYPT) e = "encryption"; else @@ -308,14 +313,14 @@ static void test_aead_speed(const char *algo, int enc, unsigned int sec, if (IS_ERR(tfm)) { pr_err("alg: aead: Failed to load transform for %s: %ld\n", algo, PTR_ERR(tfm)); - return; + goto out_notfm; } req = aead_request_alloc(tfm, GFP_KERNEL); if (!req) { pr_err("alg: aead: Failed to allocate request for %s\n", algo); - goto out; + goto out_noreq; } i = 0; @@ -323,14 +328,7 @@ static void test_aead_speed(const char *algo, int enc, unsigned int sec, b_size = aead_sizes; do { assoc = axbuf[0]; - - if (aad_size < PAGE_SIZE) - memset(assoc, 0xff, aad_size); - else { - pr_err("associate data length (%u) too big\n", - aad_size); - goto out_nosg; - } + memset(assoc, 0xff, aad_size); sg_init_one(&asg[0], assoc, aad_size); if ((*keysize + *b_size) > TVMEMSIZE * PAGE_SIZE) { @@ -392,7 +390,10 @@ static void test_aead_speed(const char *algo, int enc, unsigned int sec, } while (*keysize); out: + aead_request_free(req); +out_noreq: crypto_free_aead(tfm); +out_notfm: kfree(sg); out_nosg: testmgr_free_buf(xoutbuf); diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 3db83dbba1d939..3c95bda11d519f 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -487,10 +487,15 @@ static struct hash_testvec crct10dif_tv_template[] = { * SHA1 test vectors from from FIPS PUB 180-1 * Long vector from CAVS 5.0 */ -#define SHA1_TEST_VECTORS 3 +#define SHA1_TEST_VECTORS 6 static struct hash_testvec sha1_tv_template[] = { { + .plaintext = "", + .psize = 0, + .digest = "\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55" + "\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09", + }, { .plaintext = "abc", .psize = 3, .digest = "\xa9\x99\x3e\x36\x47\x06\x81\x6a\xba\x3e" @@ -529,6 +534,144 @@ static struct hash_testvec sha1_tv_template[] = { "\x45\x9c\x02\xb6\x9b\x4a\xa8\xf5\x82\x17", .np = 4, .tap = { 63, 64, 31, 5 } + }, { + .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", + .psize = 64, + .digest = "\xc8\x71\xf6\x9a\x63\xcc\xa9\x84\x84\x82" + "\x64\xe7\x79\x95\x5d\xd7\x19\x41\x7c\x91", + }, { + .plaintext = "\x08\x9f\x13\xaa\x41\xd8\x4c\xe3" + "\x7a\x11\x85\x1c\xb3\x27\xbe\x55" + "\xec\x60\xf7\x8e\x02\x99\x30\xc7" + "\x3b\xd2\x69\x00\x74\x0b\xa2\x16" + "\xad\x44\xdb\x4f\xe6\x7d\x14\x88" + "\x1f\xb6\x2a\xc1\x58\xef\x63\xfa" + "\x91\x05\x9c\x33\xca\x3e\xd5\x6c" + "\x03\x77\x0e\xa5\x19\xb0\x47\xde" + "\x52\xe9\x80\x17\x8b\x22\xb9\x2d" + "\xc4\x5b\xf2\x66\xfd\x94\x08\x9f" + "\x36\xcd\x41\xd8\x6f\x06\x7a\x11" + "\xa8\x1c\xb3\x4a\xe1\x55\xec\x83" + "\x1a\x8e\x25\xbc\x30\xc7\x5e\xf5" + "\x69\x00\x97\x0b\xa2\x39\xd0\x44" + "\xdb\x72\x09\x7d\x14\xab\x1f\xb6" + "\x4d\xe4\x58\xef\x86\x1d\x91\x28" + "\xbf\x33\xca\x61\xf8\x6c\x03\x9a" + "\x0e\xa5\x3c\xd3\x47\xde\x75\x0c" + "\x80\x17\xae\x22\xb9\x50\xe7\x5b" + "\xf2\x89\x20\x94\x2b\xc2\x36\xcd" + "\x64\xfb\x6f\x06\x9d\x11\xa8\x3f" + "\xd6\x4a\xe1\x78\x0f\x83\x1a\xb1" + "\x25\xbc\x53\xea\x5e\xf5\x8c\x00" + "\x97\x2e\xc5\x39\xd0\x67\xfe\x72" + "\x09\xa0\x14\xab\x42\xd9\x4d\xe4" + "\x7b\x12\x86\x1d\xb4\x28\xbf\x56" + "\xed\x61\xf8\x8f\x03\x9a\x31\xc8" + "\x3c\xd3\x6a\x01\x75\x0c\xa3\x17" + "\xae\x45\xdc\x50\xe7\x7e\x15\x89" + "\x20\xb7\x2b\xc2\x59\xf0\x64\xfb" + "\x92\x06\x9d\x34\xcb\x3f\xd6\x6d" + "\x04\x78\x0f\xa6\x1a\xb1\x48\xdf" + "\x53\xea\x81\x18\x8c\x23\xba\x2e" + "\xc5\x5c\xf3\x67\xfe\x95\x09\xa0" + "\x37\xce\x42\xd9\x70\x07\x7b\x12" + "\xa9\x1d\xb4\x4b\xe2\x56\xed\x84" + "\x1b\x8f\x26\xbd\x31\xc8\x5f\xf6" + "\x6a\x01\x98\x0c\xa3\x3a\xd1\x45" + "\xdc\x73\x0a\x7e\x15\xac\x20\xb7" + "\x4e\xe5\x59\xf0\x87\x1e\x92\x29" + "\xc0\x34\xcb\x62\xf9\x6d\x04\x9b" + "\x0f\xa6\x3d\xd4\x48\xdf\x76\x0d" + "\x81\x18\xaf\x23\xba\x51\xe8\x5c" + "\xf3\x8a\x21\x95\x2c\xc3\x37\xce" + "\x65\xfc\x70\x07\x9e\x12\xa9\x40" + "\xd7\x4b\xe2\x79\x10\x84\x1b\xb2" + "\x26\xbd\x54\xeb\x5f\xf6\x8d\x01" + "\x98\x2f\xc6\x3a\xd1\x68\xff\x73" + "\x0a\xa1\x15\xac\x43\xda\x4e\xe5" + "\x7c\x13\x87\x1e\xb5\x29\xc0\x57" + "\xee\x62\xf9\x90\x04\x9b\x32\xc9" + "\x3d\xd4\x6b\x02\x76\x0d\xa4\x18" + "\xaf\x46\xdd\x51\xe8\x7f\x16\x8a" + "\x21\xb8\x2c\xc3\x5a\xf1\x65\xfc" + "\x93\x07\x9e\x35\xcc\x40\xd7\x6e" + "\x05\x79\x10\xa7\x1b\xb2\x49\xe0" + "\x54\xeb\x82\x19\x8d\x24\xbb\x2f" + "\xc6\x5d\xf4\x68\xff\x96\x0a\xa1" + "\x38\xcf\x43\xda\x71\x08\x7c\x13" + "\xaa\x1e\xb5\x4c\xe3\x57\xee\x85" + "\x1c\x90\x27\xbe\x32\xc9\x60\xf7" + "\x6b\x02\x99\x0d\xa4\x3b\xd2\x46" + "\xdd\x74\x0b\x7f\x16\xad\x21\xb8" + "\x4f\xe6\x5a\xf1\x88\x1f\x93\x2a" + "\xc1\x35\xcc\x63\xfa\x6e\x05\x9c" + "\x10\xa7\x3e\xd5\x49\xe0\x77\x0e" + "\x82\x19\xb0\x24\xbb\x52\xe9\x5d" + "\xf4\x8b\x22\x96\x2d\xc4\x38\xcf" + "\x66\xfd\x71\x08\x9f\x13\xaa\x41" + "\xd8\x4c\xe3\x7a\x11\x85\x1c\xb3" + "\x27\xbe\x55\xec\x60\xf7\x8e\x02" + "\x99\x30\xc7\x3b\xd2\x69\x00\x74" + "\x0b\xa2\x16\xad\x44\xdb\x4f\xe6" + "\x7d\x14\x88\x1f\xb6\x2a\xc1\x58" + "\xef\x63\xfa\x91\x05\x9c\x33\xca" + "\x3e\xd5\x6c\x03\x77\x0e\xa5\x19" + "\xb0\x47\xde\x52\xe9\x80\x17\x8b" + "\x22\xb9\x2d\xc4\x5b\xf2\x66\xfd" + "\x94\x08\x9f\x36\xcd\x41\xd8\x6f" + "\x06\x7a\x11\xa8\x1c\xb3\x4a\xe1" + "\x55\xec\x83\x1a\x8e\x25\xbc\x30" + "\xc7\x5e\xf5\x69\x00\x97\x0b\xa2" + "\x39\xd0\x44\xdb\x72\x09\x7d\x14" + "\xab\x1f\xb6\x4d\xe4\x58\xef\x86" + "\x1d\x91\x28\xbf\x33\xca\x61\xf8" + "\x6c\x03\x9a\x0e\xa5\x3c\xd3\x47" + "\xde\x75\x0c\x80\x17\xae\x22\xb9" + "\x50\xe7\x5b\xf2\x89\x20\x94\x2b" + "\xc2\x36\xcd\x64\xfb\x6f\x06\x9d" + "\x11\xa8\x3f\xd6\x4a\xe1\x78\x0f" + "\x83\x1a\xb1\x25\xbc\x53\xea\x5e" + "\xf5\x8c\x00\x97\x2e\xc5\x39\xd0" + "\x67\xfe\x72\x09\xa0\x14\xab\x42" + "\xd9\x4d\xe4\x7b\x12\x86\x1d\xb4" + "\x28\xbf\x56\xed\x61\xf8\x8f\x03" + "\x9a\x31\xc8\x3c\xd3\x6a\x01\x75" + "\x0c\xa3\x17\xae\x45\xdc\x50\xe7" + "\x7e\x15\x89\x20\xb7\x2b\xc2\x59" + "\xf0\x64\xfb\x92\x06\x9d\x34\xcb" + "\x3f\xd6\x6d\x04\x78\x0f\xa6\x1a" + "\xb1\x48\xdf\x53\xea\x81\x18\x8c" + "\x23\xba\x2e\xc5\x5c\xf3\x67\xfe" + "\x95\x09\xa0\x37\xce\x42\xd9\x70" + "\x07\x7b\x12\xa9\x1d\xb4\x4b\xe2" + "\x56\xed\x84\x1b\x8f\x26\xbd\x31" + "\xc8\x5f\xf6\x6a\x01\x98\x0c\xa3" + "\x3a\xd1\x45\xdc\x73\x0a\x7e\x15" + "\xac\x20\xb7\x4e\xe5\x59\xf0\x87" + "\x1e\x92\x29\xc0\x34\xcb\x62\xf9" + "\x6d\x04\x9b\x0f\xa6\x3d\xd4\x48" + "\xdf\x76\x0d\x81\x18\xaf\x23\xba" + "\x51\xe8\x5c\xf3\x8a\x21\x95\x2c" + "\xc3\x37\xce\x65\xfc\x70\x07\x9e" + "\x12\xa9\x40\xd7\x4b\xe2\x79\x10" + "\x84\x1b\xb2\x26\xbd\x54\xeb\x5f" + "\xf6\x8d\x01\x98\x2f\xc6\x3a\xd1" + "\x68\xff\x73\x0a\xa1\x15\xac\x43" + "\xda\x4e\xe5\x7c\x13\x87\x1e\xb5" + "\x29\xc0\x57\xee\x62\xf9\x90\x04" + "\x9b\x32\xc9\x3d\xd4\x6b\x02\x76" + "\x0d\xa4\x18\xaf\x46\xdd\x51\xe8" + "\x7f\x16\x8a\x21\xb8\x2c\xc3\x5a" + "\xf1\x65\xfc\x93\x07\x9e\x35\xcc" + "\x40\xd7\x6e\x05\x79\x10\xa7\x1b" + "\xb2\x49\xe0\x54\xeb\x82\x19\x8d" + "\x24\xbb\x2f\xc6\x5d\xf4\x68\xff" + "\x96\x0a\xa1\x38\xcf\x43\xda\x71" + "\x08\x7c\x13\xaa\x1e\xb5\x4c", + .psize = 1023, + .digest = "\xb8\xe3\x54\xed\xc5\xfc\xef\xa4" + "\x55\x73\x4a\x81\x99\xe4\x47\x2a" + "\x30\xd6\xc9\x85", } }; @@ -536,10 +679,17 @@ static struct hash_testvec sha1_tv_template[] = { /* * SHA224 test vectors from from FIPS PUB 180-2 */ -#define SHA224_TEST_VECTORS 2 +#define SHA224_TEST_VECTORS 5 static struct hash_testvec sha224_tv_template[] = { { + .plaintext = "", + .psize = 0, + .digest = "\xd1\x4a\x02\x8c\x2a\x3a\x2b\xc9" + "\x47\x61\x02\xbb\x28\x82\x34\xc4" + "\x15\xa2\xb0\x1f\x82\x8e\xa6\x2a" + "\xc5\xb3\xe4\x2f", + }, { .plaintext = "abc", .psize = 3, .digest = "\x23\x09\x7D\x22\x34\x05\xD8\x22" @@ -556,16 +706,164 @@ static struct hash_testvec sha224_tv_template[] = { "\x52\x52\x25\x25", .np = 2, .tap = { 28, 28 } + }, { + .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", + .psize = 64, + .digest = "\xc4\xdb\x2b\x3a\x58\xc3\x99\x01" + "\x42\xfd\x10\x92\xaa\x4e\x04\x08" + "\x58\xbb\xbb\xe8\xf8\x14\xa7\x0c" + "\xef\x3b\xcb\x0e", + }, { + .plaintext = "\x08\x9f\x13\xaa\x41\xd8\x4c\xe3" + "\x7a\x11\x85\x1c\xb3\x27\xbe\x55" + "\xec\x60\xf7\x8e\x02\x99\x30\xc7" + "\x3b\xd2\x69\x00\x74\x0b\xa2\x16" + "\xad\x44\xdb\x4f\xe6\x7d\x14\x88" + "\x1f\xb6\x2a\xc1\x58\xef\x63\xfa" + "\x91\x05\x9c\x33\xca\x3e\xd5\x6c" + "\x03\x77\x0e\xa5\x19\xb0\x47\xde" + "\x52\xe9\x80\x17\x8b\x22\xb9\x2d" + "\xc4\x5b\xf2\x66\xfd\x94\x08\x9f" + "\x36\xcd\x41\xd8\x6f\x06\x7a\x11" + "\xa8\x1c\xb3\x4a\xe1\x55\xec\x83" + "\x1a\x8e\x25\xbc\x30\xc7\x5e\xf5" + "\x69\x00\x97\x0b\xa2\x39\xd0\x44" + "\xdb\x72\x09\x7d\x14\xab\x1f\xb6" + "\x4d\xe4\x58\xef\x86\x1d\x91\x28" + "\xbf\x33\xca\x61\xf8\x6c\x03\x9a" + "\x0e\xa5\x3c\xd3\x47\xde\x75\x0c" + "\x80\x17\xae\x22\xb9\x50\xe7\x5b" + "\xf2\x89\x20\x94\x2b\xc2\x36\xcd" + "\x64\xfb\x6f\x06\x9d\x11\xa8\x3f" + "\xd6\x4a\xe1\x78\x0f\x83\x1a\xb1" + "\x25\xbc\x53\xea\x5e\xf5\x8c\x00" + "\x97\x2e\xc5\x39\xd0\x67\xfe\x72" + "\x09\xa0\x14\xab\x42\xd9\x4d\xe4" + "\x7b\x12\x86\x1d\xb4\x28\xbf\x56" + "\xed\x61\xf8\x8f\x03\x9a\x31\xc8" + "\x3c\xd3\x6a\x01\x75\x0c\xa3\x17" + "\xae\x45\xdc\x50\xe7\x7e\x15\x89" + "\x20\xb7\x2b\xc2\x59\xf0\x64\xfb" + "\x92\x06\x9d\x34\xcb\x3f\xd6\x6d" + "\x04\x78\x0f\xa6\x1a\xb1\x48\xdf" + "\x53\xea\x81\x18\x8c\x23\xba\x2e" + "\xc5\x5c\xf3\x67\xfe\x95\x09\xa0" + "\x37\xce\x42\xd9\x70\x07\x7b\x12" + "\xa9\x1d\xb4\x4b\xe2\x56\xed\x84" + "\x1b\x8f\x26\xbd\x31\xc8\x5f\xf6" + "\x6a\x01\x98\x0c\xa3\x3a\xd1\x45" + "\xdc\x73\x0a\x7e\x15\xac\x20\xb7" + "\x4e\xe5\x59\xf0\x87\x1e\x92\x29" + "\xc0\x34\xcb\x62\xf9\x6d\x04\x9b" + "\x0f\xa6\x3d\xd4\x48\xdf\x76\x0d" + "\x81\x18\xaf\x23\xba\x51\xe8\x5c" + "\xf3\x8a\x21\x95\x2c\xc3\x37\xce" + "\x65\xfc\x70\x07\x9e\x12\xa9\x40" + "\xd7\x4b\xe2\x79\x10\x84\x1b\xb2" + "\x26\xbd\x54\xeb\x5f\xf6\x8d\x01" + "\x98\x2f\xc6\x3a\xd1\x68\xff\x73" + "\x0a\xa1\x15\xac\x43\xda\x4e\xe5" + "\x7c\x13\x87\x1e\xb5\x29\xc0\x57" + "\xee\x62\xf9\x90\x04\x9b\x32\xc9" + "\x3d\xd4\x6b\x02\x76\x0d\xa4\x18" + "\xaf\x46\xdd\x51\xe8\x7f\x16\x8a" + "\x21\xb8\x2c\xc3\x5a\xf1\x65\xfc" + "\x93\x07\x9e\x35\xcc\x40\xd7\x6e" + "\x05\x79\x10\xa7\x1b\xb2\x49\xe0" + "\x54\xeb\x82\x19\x8d\x24\xbb\x2f" + "\xc6\x5d\xf4\x68\xff\x96\x0a\xa1" + "\x38\xcf\x43\xda\x71\x08\x7c\x13" + "\xaa\x1e\xb5\x4c\xe3\x57\xee\x85" + "\x1c\x90\x27\xbe\x32\xc9\x60\xf7" + "\x6b\x02\x99\x0d\xa4\x3b\xd2\x46" + "\xdd\x74\x0b\x7f\x16\xad\x21\xb8" + "\x4f\xe6\x5a\xf1\x88\x1f\x93\x2a" + "\xc1\x35\xcc\x63\xfa\x6e\x05\x9c" + "\x10\xa7\x3e\xd5\x49\xe0\x77\x0e" + "\x82\x19\xb0\x24\xbb\x52\xe9\x5d" + "\xf4\x8b\x22\x96\x2d\xc4\x38\xcf" + "\x66\xfd\x71\x08\x9f\x13\xaa\x41" + "\xd8\x4c\xe3\x7a\x11\x85\x1c\xb3" + "\x27\xbe\x55\xec\x60\xf7\x8e\x02" + "\x99\x30\xc7\x3b\xd2\x69\x00\x74" + "\x0b\xa2\x16\xad\x44\xdb\x4f\xe6" + "\x7d\x14\x88\x1f\xb6\x2a\xc1\x58" + "\xef\x63\xfa\x91\x05\x9c\x33\xca" + "\x3e\xd5\x6c\x03\x77\x0e\xa5\x19" + "\xb0\x47\xde\x52\xe9\x80\x17\x8b" + "\x22\xb9\x2d\xc4\x5b\xf2\x66\xfd" + "\x94\x08\x9f\x36\xcd\x41\xd8\x6f" + "\x06\x7a\x11\xa8\x1c\xb3\x4a\xe1" + "\x55\xec\x83\x1a\x8e\x25\xbc\x30" + "\xc7\x5e\xf5\x69\x00\x97\x0b\xa2" + "\x39\xd0\x44\xdb\x72\x09\x7d\x14" + "\xab\x1f\xb6\x4d\xe4\x58\xef\x86" + "\x1d\x91\x28\xbf\x33\xca\x61\xf8" + "\x6c\x03\x9a\x0e\xa5\x3c\xd3\x47" + "\xde\x75\x0c\x80\x17\xae\x22\xb9" + "\x50\xe7\x5b\xf2\x89\x20\x94\x2b" + "\xc2\x36\xcd\x64\xfb\x6f\x06\x9d" + "\x11\xa8\x3f\xd6\x4a\xe1\x78\x0f" + "\x83\x1a\xb1\x25\xbc\x53\xea\x5e" + "\xf5\x8c\x00\x97\x2e\xc5\x39\xd0" + "\x67\xfe\x72\x09\xa0\x14\xab\x42" + "\xd9\x4d\xe4\x7b\x12\x86\x1d\xb4" + "\x28\xbf\x56\xed\x61\xf8\x8f\x03" + "\x9a\x31\xc8\x3c\xd3\x6a\x01\x75" + "\x0c\xa3\x17\xae\x45\xdc\x50\xe7" + "\x7e\x15\x89\x20\xb7\x2b\xc2\x59" + "\xf0\x64\xfb\x92\x06\x9d\x34\xcb" + "\x3f\xd6\x6d\x04\x78\x0f\xa6\x1a" + "\xb1\x48\xdf\x53\xea\x81\x18\x8c" + "\x23\xba\x2e\xc5\x5c\xf3\x67\xfe" + "\x95\x09\xa0\x37\xce\x42\xd9\x70" + "\x07\x7b\x12\xa9\x1d\xb4\x4b\xe2" + "\x56\xed\x84\x1b\x8f\x26\xbd\x31" + "\xc8\x5f\xf6\x6a\x01\x98\x0c\xa3" + "\x3a\xd1\x45\xdc\x73\x0a\x7e\x15" + "\xac\x20\xb7\x4e\xe5\x59\xf0\x87" + "\x1e\x92\x29\xc0\x34\xcb\x62\xf9" + "\x6d\x04\x9b\x0f\xa6\x3d\xd4\x48" + "\xdf\x76\x0d\x81\x18\xaf\x23\xba" + "\x51\xe8\x5c\xf3\x8a\x21\x95\x2c" + "\xc3\x37\xce\x65\xfc\x70\x07\x9e" + "\x12\xa9\x40\xd7\x4b\xe2\x79\x10" + "\x84\x1b\xb2\x26\xbd\x54\xeb\x5f" + "\xf6\x8d\x01\x98\x2f\xc6\x3a\xd1" + "\x68\xff\x73\x0a\xa1\x15\xac\x43" + "\xda\x4e\xe5\x7c\x13\x87\x1e\xb5" + "\x29\xc0\x57\xee\x62\xf9\x90\x04" + "\x9b\x32\xc9\x3d\xd4\x6b\x02\x76" + "\x0d\xa4\x18\xaf\x46\xdd\x51\xe8" + "\x7f\x16\x8a\x21\xb8\x2c\xc3\x5a" + "\xf1\x65\xfc\x93\x07\x9e\x35\xcc" + "\x40\xd7\x6e\x05\x79\x10\xa7\x1b" + "\xb2\x49\xe0\x54\xeb\x82\x19\x8d" + "\x24\xbb\x2f\xc6\x5d\xf4\x68\xff" + "\x96\x0a\xa1\x38\xcf\x43\xda\x71" + "\x08\x7c\x13\xaa\x1e\xb5\x4c", + .psize = 1023, + .digest = "\x98\x43\x07\x63\x75\xe0\xa7\x1c" + "\x78\xb1\x8b\xfd\x04\xf5\x2d\x91" + "\x20\x48\xa4\x28\xff\x55\xb1\xd3" + "\xe6\xf9\x4f\xcc", } }; /* * SHA256 test vectors from from NIST */ -#define SHA256_TEST_VECTORS 2 +#define SHA256_TEST_VECTORS 5 static struct hash_testvec sha256_tv_template[] = { { + .plaintext = "", + .psize = 0, + .digest = "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14" + "\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24" + "\x27\xae\x41\xe4\x64\x9b\x93\x4c" + "\xa4\x95\x99\x1b\x78\x52\xb8\x55", + }, { .plaintext = "abc", .psize = 3, .digest = "\xba\x78\x16\xbf\x8f\x01\xcf\xea" @@ -581,16 +879,166 @@ static struct hash_testvec sha256_tv_template[] = { "\xf6\xec\xed\xd4\x19\xdb\x06\xc1", .np = 2, .tap = { 28, 28 } - }, + }, { + .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", + .psize = 64, + .digest = "\xb5\xfe\xad\x56\x7d\xff\xcb\xa4" + "\x2c\x32\x29\x32\x19\xbb\xfb\xfa" + "\xd6\xff\x94\xa3\x72\x91\x85\x66" + "\x3b\xa7\x87\x77\x58\xa3\x40\x3a", + }, { + .plaintext = "\x08\x9f\x13\xaa\x41\xd8\x4c\xe3" + "\x7a\x11\x85\x1c\xb3\x27\xbe\x55" + "\xec\x60\xf7\x8e\x02\x99\x30\xc7" + "\x3b\xd2\x69\x00\x74\x0b\xa2\x16" + "\xad\x44\xdb\x4f\xe6\x7d\x14\x88" + "\x1f\xb6\x2a\xc1\x58\xef\x63\xfa" + "\x91\x05\x9c\x33\xca\x3e\xd5\x6c" + "\x03\x77\x0e\xa5\x19\xb0\x47\xde" + "\x52\xe9\x80\x17\x8b\x22\xb9\x2d" + "\xc4\x5b\xf2\x66\xfd\x94\x08\x9f" + "\x36\xcd\x41\xd8\x6f\x06\x7a\x11" + "\xa8\x1c\xb3\x4a\xe1\x55\xec\x83" + "\x1a\x8e\x25\xbc\x30\xc7\x5e\xf5" + "\x69\x00\x97\x0b\xa2\x39\xd0\x44" + "\xdb\x72\x09\x7d\x14\xab\x1f\xb6" + "\x4d\xe4\x58\xef\x86\x1d\x91\x28" + "\xbf\x33\xca\x61\xf8\x6c\x03\x9a" + "\x0e\xa5\x3c\xd3\x47\xde\x75\x0c" + "\x80\x17\xae\x22\xb9\x50\xe7\x5b" + "\xf2\x89\x20\x94\x2b\xc2\x36\xcd" + "\x64\xfb\x6f\x06\x9d\x11\xa8\x3f" + "\xd6\x4a\xe1\x78\x0f\x83\x1a\xb1" + "\x25\xbc\x53\xea\x5e\xf5\x8c\x00" + "\x97\x2e\xc5\x39\xd0\x67\xfe\x72" + "\x09\xa0\x14\xab\x42\xd9\x4d\xe4" + "\x7b\x12\x86\x1d\xb4\x28\xbf\x56" + "\xed\x61\xf8\x8f\x03\x9a\x31\xc8" + "\x3c\xd3\x6a\x01\x75\x0c\xa3\x17" + "\xae\x45\xdc\x50\xe7\x7e\x15\x89" + "\x20\xb7\x2b\xc2\x59\xf0\x64\xfb" + "\x92\x06\x9d\x34\xcb\x3f\xd6\x6d" + "\x04\x78\x0f\xa6\x1a\xb1\x48\xdf" + "\x53\xea\x81\x18\x8c\x23\xba\x2e" + "\xc5\x5c\xf3\x67\xfe\x95\x09\xa0" + "\x37\xce\x42\xd9\x70\x07\x7b\x12" + "\xa9\x1d\xb4\x4b\xe2\x56\xed\x84" + "\x1b\x8f\x26\xbd\x31\xc8\x5f\xf6" + "\x6a\x01\x98\x0c\xa3\x3a\xd1\x45" + "\xdc\x73\x0a\x7e\x15\xac\x20\xb7" + "\x4e\xe5\x59\xf0\x87\x1e\x92\x29" + "\xc0\x34\xcb\x62\xf9\x6d\x04\x9b" + "\x0f\xa6\x3d\xd4\x48\xdf\x76\x0d" + "\x81\x18\xaf\x23\xba\x51\xe8\x5c" + "\xf3\x8a\x21\x95\x2c\xc3\x37\xce" + "\x65\xfc\x70\x07\x9e\x12\xa9\x40" + "\xd7\x4b\xe2\x79\x10\x84\x1b\xb2" + "\x26\xbd\x54\xeb\x5f\xf6\x8d\x01" + "\x98\x2f\xc6\x3a\xd1\x68\xff\x73" + "\x0a\xa1\x15\xac\x43\xda\x4e\xe5" + "\x7c\x13\x87\x1e\xb5\x29\xc0\x57" + "\xee\x62\xf9\x90\x04\x9b\x32\xc9" + "\x3d\xd4\x6b\x02\x76\x0d\xa4\x18" + "\xaf\x46\xdd\x51\xe8\x7f\x16\x8a" + "\x21\xb8\x2c\xc3\x5a\xf1\x65\xfc" + "\x93\x07\x9e\x35\xcc\x40\xd7\x6e" + "\x05\x79\x10\xa7\x1b\xb2\x49\xe0" + "\x54\xeb\x82\x19\x8d\x24\xbb\x2f" + "\xc6\x5d\xf4\x68\xff\x96\x0a\xa1" + "\x38\xcf\x43\xda\x71\x08\x7c\x13" + "\xaa\x1e\xb5\x4c\xe3\x57\xee\x85" + "\x1c\x90\x27\xbe\x32\xc9\x60\xf7" + "\x6b\x02\x99\x0d\xa4\x3b\xd2\x46" + "\xdd\x74\x0b\x7f\x16\xad\x21\xb8" + "\x4f\xe6\x5a\xf1\x88\x1f\x93\x2a" + "\xc1\x35\xcc\x63\xfa\x6e\x05\x9c" + "\x10\xa7\x3e\xd5\x49\xe0\x77\x0e" + "\x82\x19\xb0\x24\xbb\x52\xe9\x5d" + "\xf4\x8b\x22\x96\x2d\xc4\x38\xcf" + "\x66\xfd\x71\x08\x9f\x13\xaa\x41" + "\xd8\x4c\xe3\x7a\x11\x85\x1c\xb3" + "\x27\xbe\x55\xec\x60\xf7\x8e\x02" + "\x99\x30\xc7\x3b\xd2\x69\x00\x74" + "\x0b\xa2\x16\xad\x44\xdb\x4f\xe6" + "\x7d\x14\x88\x1f\xb6\x2a\xc1\x58" + "\xef\x63\xfa\x91\x05\x9c\x33\xca" + "\x3e\xd5\x6c\x03\x77\x0e\xa5\x19" + "\xb0\x47\xde\x52\xe9\x80\x17\x8b" + "\x22\xb9\x2d\xc4\x5b\xf2\x66\xfd" + "\x94\x08\x9f\x36\xcd\x41\xd8\x6f" + "\x06\x7a\x11\xa8\x1c\xb3\x4a\xe1" + "\x55\xec\x83\x1a\x8e\x25\xbc\x30" + "\xc7\x5e\xf5\x69\x00\x97\x0b\xa2" + "\x39\xd0\x44\xdb\x72\x09\x7d\x14" + "\xab\x1f\xb6\x4d\xe4\x58\xef\x86" + "\x1d\x91\x28\xbf\x33\xca\x61\xf8" + "\x6c\x03\x9a\x0e\xa5\x3c\xd3\x47" + "\xde\x75\x0c\x80\x17\xae\x22\xb9" + "\x50\xe7\x5b\xf2\x89\x20\x94\x2b" + "\xc2\x36\xcd\x64\xfb\x6f\x06\x9d" + "\x11\xa8\x3f\xd6\x4a\xe1\x78\x0f" + "\x83\x1a\xb1\x25\xbc\x53\xea\x5e" + "\xf5\x8c\x00\x97\x2e\xc5\x39\xd0" + "\x67\xfe\x72\x09\xa0\x14\xab\x42" + "\xd9\x4d\xe4\x7b\x12\x86\x1d\xb4" + "\x28\xbf\x56\xed\x61\xf8\x8f\x03" + "\x9a\x31\xc8\x3c\xd3\x6a\x01\x75" + "\x0c\xa3\x17\xae\x45\xdc\x50\xe7" + "\x7e\x15\x89\x20\xb7\x2b\xc2\x59" + "\xf0\x64\xfb\x92\x06\x9d\x34\xcb" + "\x3f\xd6\x6d\x04\x78\x0f\xa6\x1a" + "\xb1\x48\xdf\x53\xea\x81\x18\x8c" + "\x23\xba\x2e\xc5\x5c\xf3\x67\xfe" + "\x95\x09\xa0\x37\xce\x42\xd9\x70" + "\x07\x7b\x12\xa9\x1d\xb4\x4b\xe2" + "\x56\xed\x84\x1b\x8f\x26\xbd\x31" + "\xc8\x5f\xf6\x6a\x01\x98\x0c\xa3" + "\x3a\xd1\x45\xdc\x73\x0a\x7e\x15" + "\xac\x20\xb7\x4e\xe5\x59\xf0\x87" + "\x1e\x92\x29\xc0\x34\xcb\x62\xf9" + "\x6d\x04\x9b\x0f\xa6\x3d\xd4\x48" + "\xdf\x76\x0d\x81\x18\xaf\x23\xba" + "\x51\xe8\x5c\xf3\x8a\x21\x95\x2c" + "\xc3\x37\xce\x65\xfc\x70\x07\x9e" + "\x12\xa9\x40\xd7\x4b\xe2\x79\x10" + "\x84\x1b\xb2\x26\xbd\x54\xeb\x5f" + "\xf6\x8d\x01\x98\x2f\xc6\x3a\xd1" + "\x68\xff\x73\x0a\xa1\x15\xac\x43" + "\xda\x4e\xe5\x7c\x13\x87\x1e\xb5" + "\x29\xc0\x57\xee\x62\xf9\x90\x04" + "\x9b\x32\xc9\x3d\xd4\x6b\x02\x76" + "\x0d\xa4\x18\xaf\x46\xdd\x51\xe8" + "\x7f\x16\x8a\x21\xb8\x2c\xc3\x5a" + "\xf1\x65\xfc\x93\x07\x9e\x35\xcc" + "\x40\xd7\x6e\x05\x79\x10\xa7\x1b" + "\xb2\x49\xe0\x54\xeb\x82\x19\x8d" + "\x24\xbb\x2f\xc6\x5d\xf4\x68\xff" + "\x96\x0a\xa1\x38\xcf\x43\xda\x71" + "\x08\x7c\x13\xaa\x1e\xb5\x4c", + .psize = 1023, + .digest = "\xc5\xce\x0c\xca\x01\x4f\x53\x3a" + "\x32\x32\x17\xcc\xd4\x6a\x71\xa9" + "\xf3\xed\x50\x10\x64\x8e\x06\xbe" + "\x9b\x4a\xa6\xbb\x05\x89\x59\x51", + } }; /* * SHA384 test vectors from from NIST and kerneli */ -#define SHA384_TEST_VECTORS 4 +#define SHA384_TEST_VECTORS 6 static struct hash_testvec sha384_tv_template[] = { { + .plaintext = "", + .psize = 0, + .digest = "\x38\xb0\x60\xa7\x51\xac\x96\x38" + "\x4c\xd9\x32\x7e\xb1\xb1\xe3\x6a" + "\x21\xfd\xb7\x11\x14\xbe\x07\x43" + "\x4c\x0c\xc7\xbf\x63\xf6\xe1\xda" + "\x27\x4e\xde\xbf\xe7\x6f\x65\xfb" + "\xd5\x1a\xd2\xf1\x48\x98\xb9\x5b", + }, { .plaintext= "abc", .psize = 3, .digest = "\xcb\x00\x75\x3f\x45\xa3\x5e\x8b" @@ -630,16 +1078,163 @@ static struct hash_testvec sha384_tv_template[] = { "\xc9\x38\xe2\xd1\x99\xe8\xbe\xa4", .np = 4, .tap = { 26, 26, 26, 26 } - }, + }, { + .plaintext = "\x08\x9f\x13\xaa\x41\xd8\x4c\xe3" + "\x7a\x11\x85\x1c\xb3\x27\xbe\x55" + "\xec\x60\xf7\x8e\x02\x99\x30\xc7" + "\x3b\xd2\x69\x00\x74\x0b\xa2\x16" + "\xad\x44\xdb\x4f\xe6\x7d\x14\x88" + "\x1f\xb6\x2a\xc1\x58\xef\x63\xfa" + "\x91\x05\x9c\x33\xca\x3e\xd5\x6c" + "\x03\x77\x0e\xa5\x19\xb0\x47\xde" + "\x52\xe9\x80\x17\x8b\x22\xb9\x2d" + "\xc4\x5b\xf2\x66\xfd\x94\x08\x9f" + "\x36\xcd\x41\xd8\x6f\x06\x7a\x11" + "\xa8\x1c\xb3\x4a\xe1\x55\xec\x83" + "\x1a\x8e\x25\xbc\x30\xc7\x5e\xf5" + "\x69\x00\x97\x0b\xa2\x39\xd0\x44" + "\xdb\x72\x09\x7d\x14\xab\x1f\xb6" + "\x4d\xe4\x58\xef\x86\x1d\x91\x28" + "\xbf\x33\xca\x61\xf8\x6c\x03\x9a" + "\x0e\xa5\x3c\xd3\x47\xde\x75\x0c" + "\x80\x17\xae\x22\xb9\x50\xe7\x5b" + "\xf2\x89\x20\x94\x2b\xc2\x36\xcd" + "\x64\xfb\x6f\x06\x9d\x11\xa8\x3f" + "\xd6\x4a\xe1\x78\x0f\x83\x1a\xb1" + "\x25\xbc\x53\xea\x5e\xf5\x8c\x00" + "\x97\x2e\xc5\x39\xd0\x67\xfe\x72" + "\x09\xa0\x14\xab\x42\xd9\x4d\xe4" + "\x7b\x12\x86\x1d\xb4\x28\xbf\x56" + "\xed\x61\xf8\x8f\x03\x9a\x31\xc8" + "\x3c\xd3\x6a\x01\x75\x0c\xa3\x17" + "\xae\x45\xdc\x50\xe7\x7e\x15\x89" + "\x20\xb7\x2b\xc2\x59\xf0\x64\xfb" + "\x92\x06\x9d\x34\xcb\x3f\xd6\x6d" + "\x04\x78\x0f\xa6\x1a\xb1\x48\xdf" + "\x53\xea\x81\x18\x8c\x23\xba\x2e" + "\xc5\x5c\xf3\x67\xfe\x95\x09\xa0" + "\x37\xce\x42\xd9\x70\x07\x7b\x12" + "\xa9\x1d\xb4\x4b\xe2\x56\xed\x84" + "\x1b\x8f\x26\xbd\x31\xc8\x5f\xf6" + "\x6a\x01\x98\x0c\xa3\x3a\xd1\x45" + "\xdc\x73\x0a\x7e\x15\xac\x20\xb7" + "\x4e\xe5\x59\xf0\x87\x1e\x92\x29" + "\xc0\x34\xcb\x62\xf9\x6d\x04\x9b" + "\x0f\xa6\x3d\xd4\x48\xdf\x76\x0d" + "\x81\x18\xaf\x23\xba\x51\xe8\x5c" + "\xf3\x8a\x21\x95\x2c\xc3\x37\xce" + "\x65\xfc\x70\x07\x9e\x12\xa9\x40" + "\xd7\x4b\xe2\x79\x10\x84\x1b\xb2" + "\x26\xbd\x54\xeb\x5f\xf6\x8d\x01" + "\x98\x2f\xc6\x3a\xd1\x68\xff\x73" + "\x0a\xa1\x15\xac\x43\xda\x4e\xe5" + "\x7c\x13\x87\x1e\xb5\x29\xc0\x57" + "\xee\x62\xf9\x90\x04\x9b\x32\xc9" + "\x3d\xd4\x6b\x02\x76\x0d\xa4\x18" + "\xaf\x46\xdd\x51\xe8\x7f\x16\x8a" + "\x21\xb8\x2c\xc3\x5a\xf1\x65\xfc" + "\x93\x07\x9e\x35\xcc\x40\xd7\x6e" + "\x05\x79\x10\xa7\x1b\xb2\x49\xe0" + "\x54\xeb\x82\x19\x8d\x24\xbb\x2f" + "\xc6\x5d\xf4\x68\xff\x96\x0a\xa1" + "\x38\xcf\x43\xda\x71\x08\x7c\x13" + "\xaa\x1e\xb5\x4c\xe3\x57\xee\x85" + "\x1c\x90\x27\xbe\x32\xc9\x60\xf7" + "\x6b\x02\x99\x0d\xa4\x3b\xd2\x46" + "\xdd\x74\x0b\x7f\x16\xad\x21\xb8" + "\x4f\xe6\x5a\xf1\x88\x1f\x93\x2a" + "\xc1\x35\xcc\x63\xfa\x6e\x05\x9c" + "\x10\xa7\x3e\xd5\x49\xe0\x77\x0e" + "\x82\x19\xb0\x24\xbb\x52\xe9\x5d" + "\xf4\x8b\x22\x96\x2d\xc4\x38\xcf" + "\x66\xfd\x71\x08\x9f\x13\xaa\x41" + "\xd8\x4c\xe3\x7a\x11\x85\x1c\xb3" + "\x27\xbe\x55\xec\x60\xf7\x8e\x02" + "\x99\x30\xc7\x3b\xd2\x69\x00\x74" + "\x0b\xa2\x16\xad\x44\xdb\x4f\xe6" + "\x7d\x14\x88\x1f\xb6\x2a\xc1\x58" + "\xef\x63\xfa\x91\x05\x9c\x33\xca" + "\x3e\xd5\x6c\x03\x77\x0e\xa5\x19" + "\xb0\x47\xde\x52\xe9\x80\x17\x8b" + "\x22\xb9\x2d\xc4\x5b\xf2\x66\xfd" + "\x94\x08\x9f\x36\xcd\x41\xd8\x6f" + "\x06\x7a\x11\xa8\x1c\xb3\x4a\xe1" + "\x55\xec\x83\x1a\x8e\x25\xbc\x30" + "\xc7\x5e\xf5\x69\x00\x97\x0b\xa2" + "\x39\xd0\x44\xdb\x72\x09\x7d\x14" + "\xab\x1f\xb6\x4d\xe4\x58\xef\x86" + "\x1d\x91\x28\xbf\x33\xca\x61\xf8" + "\x6c\x03\x9a\x0e\xa5\x3c\xd3\x47" + "\xde\x75\x0c\x80\x17\xae\x22\xb9" + "\x50\xe7\x5b\xf2\x89\x20\x94\x2b" + "\xc2\x36\xcd\x64\xfb\x6f\x06\x9d" + "\x11\xa8\x3f\xd6\x4a\xe1\x78\x0f" + "\x83\x1a\xb1\x25\xbc\x53\xea\x5e" + "\xf5\x8c\x00\x97\x2e\xc5\x39\xd0" + "\x67\xfe\x72\x09\xa0\x14\xab\x42" + "\xd9\x4d\xe4\x7b\x12\x86\x1d\xb4" + "\x28\xbf\x56\xed\x61\xf8\x8f\x03" + "\x9a\x31\xc8\x3c\xd3\x6a\x01\x75" + "\x0c\xa3\x17\xae\x45\xdc\x50\xe7" + "\x7e\x15\x89\x20\xb7\x2b\xc2\x59" + "\xf0\x64\xfb\x92\x06\x9d\x34\xcb" + "\x3f\xd6\x6d\x04\x78\x0f\xa6\x1a" + "\xb1\x48\xdf\x53\xea\x81\x18\x8c" + "\x23\xba\x2e\xc5\x5c\xf3\x67\xfe" + "\x95\x09\xa0\x37\xce\x42\xd9\x70" + "\x07\x7b\x12\xa9\x1d\xb4\x4b\xe2" + "\x56\xed\x84\x1b\x8f\x26\xbd\x31" + "\xc8\x5f\xf6\x6a\x01\x98\x0c\xa3" + "\x3a\xd1\x45\xdc\x73\x0a\x7e\x15" + "\xac\x20\xb7\x4e\xe5\x59\xf0\x87" + "\x1e\x92\x29\xc0\x34\xcb\x62\xf9" + "\x6d\x04\x9b\x0f\xa6\x3d\xd4\x48" + "\xdf\x76\x0d\x81\x18\xaf\x23\xba" + "\x51\xe8\x5c\xf3\x8a\x21\x95\x2c" + "\xc3\x37\xce\x65\xfc\x70\x07\x9e" + "\x12\xa9\x40\xd7\x4b\xe2\x79\x10" + "\x84\x1b\xb2\x26\xbd\x54\xeb\x5f" + "\xf6\x8d\x01\x98\x2f\xc6\x3a\xd1" + "\x68\xff\x73\x0a\xa1\x15\xac\x43" + "\xda\x4e\xe5\x7c\x13\x87\x1e\xb5" + "\x29\xc0\x57\xee\x62\xf9\x90\x04" + "\x9b\x32\xc9\x3d\xd4\x6b\x02\x76" + "\x0d\xa4\x18\xaf\x46\xdd\x51\xe8" + "\x7f\x16\x8a\x21\xb8\x2c\xc3\x5a" + "\xf1\x65\xfc\x93\x07\x9e\x35\xcc" + "\x40\xd7\x6e\x05\x79\x10\xa7\x1b" + "\xb2\x49\xe0\x54\xeb\x82\x19\x8d" + "\x24\xbb\x2f\xc6\x5d\xf4\x68\xff" + "\x96\x0a\xa1\x38\xcf\x43\xda\x71" + "\x08\x7c\x13\xaa\x1e\xb5\x4c", + .psize = 1023, + .digest = "\x4d\x97\x23\xc8\xea\x7a\x7c\x15" + "\xb8\xff\x97\x9c\xf5\x13\x4f\x31" + "\xde\x67\xf7\x24\x73\xcd\x70\x1c" + "\x03\x4a\xba\x8a\x87\x49\xfe\xdc" + "\x75\x29\x62\x83\xae\x3f\x17\xab" + "\xfd\x10\x4d\x8e\x17\x1c\x1f\xca", + } }; /* * SHA512 test vectors from from NIST and kerneli */ -#define SHA512_TEST_VECTORS 4 +#define SHA512_TEST_VECTORS 6 static struct hash_testvec sha512_tv_template[] = { { + .plaintext = "", + .psize = 0, + .digest = "\xcf\x83\xe1\x35\x7e\xef\xb8\xbd" + "\xf1\x54\x28\x50\xd6\x6d\x80\x07" + "\xd6\x20\xe4\x05\x0b\x57\x15\xdc" + "\x83\xf4\xa9\x21\xd3\x6c\xe9\xce" + "\x47\xd0\xd1\x3c\x5d\x85\xf2\xb0" + "\xff\x83\x18\xd2\x87\x7e\xec\x2f" + "\x63\xb9\x31\xbd\x47\x41\x7a\x81" + "\xa5\x38\x32\x7a\xf9\x27\xda\x3e", + }, { .plaintext = "abc", .psize = 3, .digest = "\xdd\xaf\x35\xa1\x93\x61\x7a\xba" @@ -687,7 +1282,145 @@ static struct hash_testvec sha512_tv_template[] = { "\xed\xb4\x19\x87\x23\x28\x50\xc9", .np = 4, .tap = { 26, 26, 26, 26 } - }, + }, { + .plaintext = "\x08\x9f\x13\xaa\x41\xd8\x4c\xe3" + "\x7a\x11\x85\x1c\xb3\x27\xbe\x55" + "\xec\x60\xf7\x8e\x02\x99\x30\xc7" + "\x3b\xd2\x69\x00\x74\x0b\xa2\x16" + "\xad\x44\xdb\x4f\xe6\x7d\x14\x88" + "\x1f\xb6\x2a\xc1\x58\xef\x63\xfa" + "\x91\x05\x9c\x33\xca\x3e\xd5\x6c" + "\x03\x77\x0e\xa5\x19\xb0\x47\xde" + "\x52\xe9\x80\x17\x8b\x22\xb9\x2d" + "\xc4\x5b\xf2\x66\xfd\x94\x08\x9f" + "\x36\xcd\x41\xd8\x6f\x06\x7a\x11" + "\xa8\x1c\xb3\x4a\xe1\x55\xec\x83" + "\x1a\x8e\x25\xbc\x30\xc7\x5e\xf5" + "\x69\x00\x97\x0b\xa2\x39\xd0\x44" + "\xdb\x72\x09\x7d\x14\xab\x1f\xb6" + "\x4d\xe4\x58\xef\x86\x1d\x91\x28" + "\xbf\x33\xca\x61\xf8\x6c\x03\x9a" + "\x0e\xa5\x3c\xd3\x47\xde\x75\x0c" + "\x80\x17\xae\x22\xb9\x50\xe7\x5b" + "\xf2\x89\x20\x94\x2b\xc2\x36\xcd" + "\x64\xfb\x6f\x06\x9d\x11\xa8\x3f" + "\xd6\x4a\xe1\x78\x0f\x83\x1a\xb1" + "\x25\xbc\x53\xea\x5e\xf5\x8c\x00" + "\x97\x2e\xc5\x39\xd0\x67\xfe\x72" + "\x09\xa0\x14\xab\x42\xd9\x4d\xe4" + "\x7b\x12\x86\x1d\xb4\x28\xbf\x56" + "\xed\x61\xf8\x8f\x03\x9a\x31\xc8" + "\x3c\xd3\x6a\x01\x75\x0c\xa3\x17" + "\xae\x45\xdc\x50\xe7\x7e\x15\x89" + "\x20\xb7\x2b\xc2\x59\xf0\x64\xfb" + "\x92\x06\x9d\x34\xcb\x3f\xd6\x6d" + "\x04\x78\x0f\xa6\x1a\xb1\x48\xdf" + "\x53\xea\x81\x18\x8c\x23\xba\x2e" + "\xc5\x5c\xf3\x67\xfe\x95\x09\xa0" + "\x37\xce\x42\xd9\x70\x07\x7b\x12" + "\xa9\x1d\xb4\x4b\xe2\x56\xed\x84" + "\x1b\x8f\x26\xbd\x31\xc8\x5f\xf6" + "\x6a\x01\x98\x0c\xa3\x3a\xd1\x45" + "\xdc\x73\x0a\x7e\x15\xac\x20\xb7" + "\x4e\xe5\x59\xf0\x87\x1e\x92\x29" + "\xc0\x34\xcb\x62\xf9\x6d\x04\x9b" + "\x0f\xa6\x3d\xd4\x48\xdf\x76\x0d" + "\x81\x18\xaf\x23\xba\x51\xe8\x5c" + "\xf3\x8a\x21\x95\x2c\xc3\x37\xce" + "\x65\xfc\x70\x07\x9e\x12\xa9\x40" + "\xd7\x4b\xe2\x79\x10\x84\x1b\xb2" + "\x26\xbd\x54\xeb\x5f\xf6\x8d\x01" + "\x98\x2f\xc6\x3a\xd1\x68\xff\x73" + "\x0a\xa1\x15\xac\x43\xda\x4e\xe5" + "\x7c\x13\x87\x1e\xb5\x29\xc0\x57" + "\xee\x62\xf9\x90\x04\x9b\x32\xc9" + "\x3d\xd4\x6b\x02\x76\x0d\xa4\x18" + "\xaf\x46\xdd\x51\xe8\x7f\x16\x8a" + "\x21\xb8\x2c\xc3\x5a\xf1\x65\xfc" + "\x93\x07\x9e\x35\xcc\x40\xd7\x6e" + "\x05\x79\x10\xa7\x1b\xb2\x49\xe0" + "\x54\xeb\x82\x19\x8d\x24\xbb\x2f" + "\xc6\x5d\xf4\x68\xff\x96\x0a\xa1" + "\x38\xcf\x43\xda\x71\x08\x7c\x13" + "\xaa\x1e\xb5\x4c\xe3\x57\xee\x85" + "\x1c\x90\x27\xbe\x32\xc9\x60\xf7" + "\x6b\x02\x99\x0d\xa4\x3b\xd2\x46" + "\xdd\x74\x0b\x7f\x16\xad\x21\xb8" + "\x4f\xe6\x5a\xf1\x88\x1f\x93\x2a" + "\xc1\x35\xcc\x63\xfa\x6e\x05\x9c" + "\x10\xa7\x3e\xd5\x49\xe0\x77\x0e" + "\x82\x19\xb0\x24\xbb\x52\xe9\x5d" + "\xf4\x8b\x22\x96\x2d\xc4\x38\xcf" + "\x66\xfd\x71\x08\x9f\x13\xaa\x41" + "\xd8\x4c\xe3\x7a\x11\x85\x1c\xb3" + "\x27\xbe\x55\xec\x60\xf7\x8e\x02" + "\x99\x30\xc7\x3b\xd2\x69\x00\x74" + "\x0b\xa2\x16\xad\x44\xdb\x4f\xe6" + "\x7d\x14\x88\x1f\xb6\x2a\xc1\x58" + "\xef\x63\xfa\x91\x05\x9c\x33\xca" + "\x3e\xd5\x6c\x03\x77\x0e\xa5\x19" + "\xb0\x47\xde\x52\xe9\x80\x17\x8b" + "\x22\xb9\x2d\xc4\x5b\xf2\x66\xfd" + "\x94\x08\x9f\x36\xcd\x41\xd8\x6f" + "\x06\x7a\x11\xa8\x1c\xb3\x4a\xe1" + "\x55\xec\x83\x1a\x8e\x25\xbc\x30" + "\xc7\x5e\xf5\x69\x00\x97\x0b\xa2" + "\x39\xd0\x44\xdb\x72\x09\x7d\x14" + "\xab\x1f\xb6\x4d\xe4\x58\xef\x86" + "\x1d\x91\x28\xbf\x33\xca\x61\xf8" + "\x6c\x03\x9a\x0e\xa5\x3c\xd3\x47" + "\xde\x75\x0c\x80\x17\xae\x22\xb9" + "\x50\xe7\x5b\xf2\x89\x20\x94\x2b" + "\xc2\x36\xcd\x64\xfb\x6f\x06\x9d" + "\x11\xa8\x3f\xd6\x4a\xe1\x78\x0f" + "\x83\x1a\xb1\x25\xbc\x53\xea\x5e" + "\xf5\x8c\x00\x97\x2e\xc5\x39\xd0" + "\x67\xfe\x72\x09\xa0\x14\xab\x42" + "\xd9\x4d\xe4\x7b\x12\x86\x1d\xb4" + "\x28\xbf\x56\xed\x61\xf8\x8f\x03" + "\x9a\x31\xc8\x3c\xd3\x6a\x01\x75" + "\x0c\xa3\x17\xae\x45\xdc\x50\xe7" + "\x7e\x15\x89\x20\xb7\x2b\xc2\x59" + "\xf0\x64\xfb\x92\x06\x9d\x34\xcb" + "\x3f\xd6\x6d\x04\x78\x0f\xa6\x1a" + "\xb1\x48\xdf\x53\xea\x81\x18\x8c" + "\x23\xba\x2e\xc5\x5c\xf3\x67\xfe" + "\x95\x09\xa0\x37\xce\x42\xd9\x70" + "\x07\x7b\x12\xa9\x1d\xb4\x4b\xe2" + "\x56\xed\x84\x1b\x8f\x26\xbd\x31" + "\xc8\x5f\xf6\x6a\x01\x98\x0c\xa3" + "\x3a\xd1\x45\xdc\x73\x0a\x7e\x15" + "\xac\x20\xb7\x4e\xe5\x59\xf0\x87" + "\x1e\x92\x29\xc0\x34\xcb\x62\xf9" + "\x6d\x04\x9b\x0f\xa6\x3d\xd4\x48" + "\xdf\x76\x0d\x81\x18\xaf\x23\xba" + "\x51\xe8\x5c\xf3\x8a\x21\x95\x2c" + "\xc3\x37\xce\x65\xfc\x70\x07\x9e" + "\x12\xa9\x40\xd7\x4b\xe2\x79\x10" + "\x84\x1b\xb2\x26\xbd\x54\xeb\x5f" + "\xf6\x8d\x01\x98\x2f\xc6\x3a\xd1" + "\x68\xff\x73\x0a\xa1\x15\xac\x43" + "\xda\x4e\xe5\x7c\x13\x87\x1e\xb5" + "\x29\xc0\x57\xee\x62\xf9\x90\x04" + "\x9b\x32\xc9\x3d\xd4\x6b\x02\x76" + "\x0d\xa4\x18\xaf\x46\xdd\x51\xe8" + "\x7f\x16\x8a\x21\xb8\x2c\xc3\x5a" + "\xf1\x65\xfc\x93\x07\x9e\x35\xcc" + "\x40\xd7\x6e\x05\x79\x10\xa7\x1b" + "\xb2\x49\xe0\x54\xeb\x82\x19\x8d" + "\x24\xbb\x2f\xc6\x5d\xf4\x68\xff" + "\x96\x0a\xa1\x38\xcf\x43\xda\x71" + "\x08\x7c\x13\xaa\x1e\xb5\x4c", + .psize = 1023, + .digest = "\x76\xc9\xd4\x91\x7a\x5f\x0f\xaa" + "\x13\x39\xf3\x01\x7a\xfa\xe5\x41" + "\x5f\x0b\xf8\xeb\x32\xfc\xbf\xb0" + "\xfa\x8c\xcd\x17\x83\xe2\xfa\xeb" + "\x1c\x19\xde\xe2\x75\xdc\x34\x64" + "\x5f\x35\x9c\x61\x2f\x10\xf9\xec" + "\x59\xca\x9d\xcc\x25\x0c\x43\xba" + "\x85\xa8\xf8\xfe\xb5\x24\xb2\xee", + } }; @@ -12844,7 +13577,7 @@ static struct cipher_testvec cast6_xts_dec_tv_template[] = { #define AES_GCM_4106_DEC_TEST_VECTORS 7 #define AES_GCM_4543_ENC_TEST_VECTORS 1 #define AES_GCM_4543_DEC_TEST_VECTORS 2 -#define AES_CCM_ENC_TEST_VECTORS 7 +#define AES_CCM_ENC_TEST_VECTORS 8 #define AES_CCM_DEC_TEST_VECTORS 7 #define AES_CCM_4309_ENC_TEST_VECTORS 7 #define AES_CCM_4309_DEC_TEST_VECTORS 10 @@ -18746,7 +19479,29 @@ static struct aead_testvec aes_ccm_enc_tv_template[] = { "\x7c\xf9\xbe\xc2\x40\x88\x97\xc6" "\xba", .rlen = 33, - }, + }, { + /* + * This is the same vector as aes_ccm_rfc4309_enc_tv_template[0] + * below but rewritten to use the ccm algorithm directly. + */ + .key = "\x83\xac\x54\x66\xc2\xeb\xe5\x05" + "\x2e\x01\xd1\xfc\x5d\x82\x66\x2e", + .klen = 16, + .iv = "\x03\x96\xac\x59\x30\x07\xa1\xe2\xa2\xc7\x55\x24\0\0\0\0", + .alen = 0, + .input = "\x19\xc8\x81\xf6\xe9\x86\xff\x93" + "\x0b\x78\x67\xe5\xbb\xb7\xfc\x6e" + "\x83\x77\xb3\xa6\x0c\x8c\x9f\x9c" + "\x35\x2e\xad\xe0\x62\xf9\x91\xa1", + .ilen = 32, + .result = "\xab\x6f\xe1\x69\x1d\x19\x99\xa8" + "\x92\xa0\xc4\x6f\x7e\xe2\x8b\xb1" + "\x70\xbb\x8c\xa6\x4c\x6e\x97\x8a" + "\x57\x2b\xbe\x5d\x98\xa6\xb1\x32" + "\xda\x24\xea\xd9\xa1\x39\x98\xfd" + "\xa4\xbe\xd9\xf2\x1a\x6d\x22\xa8", + .rlen = 48, + } }; static struct aead_testvec aes_ccm_dec_tv_template[] = { diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index ab686b31010034..c0160bb451e9cb 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -47,6 +47,23 @@ config ACPI_SLEEP depends on SUSPEND || HIBERNATION default y +config ACPI_PROCFS_POWER + bool "Deprecated power /proc/acpi directories" + depends on PROC_FS + help + For backwards compatibility, this option allows + deprecated power /proc/acpi/ directories to exist, even when + they have been replaced by functions in /sys. + The deprecated directories (and their replacements) include: + /proc/acpi/battery/* (/sys/class/power_supply/*) + /proc/acpi/ac_adapter/* (sys/class/power_supply/*) + This option has no effect on /proc/acpi/ directories + and functions, which do not yet exist in /sys + This option, together with the proc directories, will be + deleted in 2.6.39. + + Say N to delete power /proc/acpi/ directories that have moved to /sys/ + config ACPI_EC_DEBUGFS tristate "EC read/write access through /sys/kernel/debug/ec" default n diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 0331f91d56e663..bce34afadcd05d 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -47,6 +47,7 @@ acpi-y += sysfs.o acpi-$(CONFIG_X86) += acpi_cmos_rtc.o acpi-$(CONFIG_DEBUG_FS) += debugfs.o acpi-$(CONFIG_ACPI_NUMA) += numa.o +acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o ifdef CONFIG_ACPI_VIDEO acpi-y += video_detect.o endif diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 2c01c1da29ce39..c67f6f5ad61107 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -52,11 +52,39 @@ MODULE_AUTHOR("Paul Diefenbaugh"); MODULE_DESCRIPTION("ACPI AC Adapter Driver"); MODULE_LICENSE("GPL"); +static int acpi_ac_add(struct acpi_device *device); +static int acpi_ac_remove(struct acpi_device *device); +static void acpi_ac_notify(struct acpi_device *device, u32 event); + +static const struct acpi_device_id ac_device_ids[] = { + {"ACPI0003", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, ac_device_ids); + +#ifdef CONFIG_PM_SLEEP +static int acpi_ac_resume(struct device *dev); +#endif +static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume); + static int ac_sleep_before_get_state_ms; +static struct acpi_driver acpi_ac_driver = { + .name = "ac", + .class = ACPI_AC_CLASS, + .ids = ac_device_ids, + .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, + .ops = { + .add = acpi_ac_add, + .remove = acpi_ac_remove, + .notify = acpi_ac_notify, + }, + .drv.pm = &acpi_ac_pm, +}; + struct acpi_ac { struct power_supply charger; - struct platform_device *pdev; + struct acpi_device * device; unsigned long long state; struct notifier_block battery_nb; }; @@ -69,10 +97,12 @@ struct acpi_ac { static int acpi_ac_get_state(struct acpi_ac *ac) { - acpi_status status; - acpi_handle handle = ACPI_HANDLE(&ac->pdev->dev); + acpi_status status = AE_OK; + + if (!ac) + return -EINVAL; - status = acpi_evaluate_integer(handle, "_PSR", NULL, + status = acpi_evaluate_integer(ac->device->handle, "_PSR", NULL, &ac->state); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, @@ -117,10 +147,9 @@ static enum power_supply_property ac_props[] = { Driver Model -------------------------------------------------------------------------- */ -static void acpi_ac_notify_handler(acpi_handle handle, u32 event, void *data) +static void acpi_ac_notify(struct acpi_device *device, u32 event) { - struct acpi_ac *ac = data; - struct acpi_device *adev; + struct acpi_ac *ac = acpi_driver_data(device); if (!ac) return; @@ -143,11 +172,10 @@ static void acpi_ac_notify_handler(acpi_handle handle, u32 event, void *data) msleep(ac_sleep_before_get_state_ms); acpi_ac_get_state(ac); - adev = ACPI_COMPANION(&ac->pdev->dev); - acpi_bus_generate_netlink_event(adev->pnp.device_class, - dev_name(&ac->pdev->dev), - event, (u32) ac->state); - acpi_notifier_call_chain(adev, event, (u32) ac->state); + acpi_bus_generate_netlink_event(device->pnp.device_class, + dev_name(&device->dev), event, + (u32) ac->state); + acpi_notifier_call_chain(device, event, (u32) ac->state); kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE); } @@ -192,49 +220,39 @@ static struct dmi_system_id ac_dmi_table[] = { {}, }; -static int acpi_ac_probe(struct platform_device *pdev) +static int acpi_ac_add(struct acpi_device *device) { int result = 0; struct acpi_ac *ac = NULL; - struct acpi_device *adev; - if (!pdev) - return -EINVAL; - adev = ACPI_COMPANION(&pdev->dev); - if (!adev) - return -ENODEV; + if (!device) + return -EINVAL; ac = kzalloc(sizeof(struct acpi_ac), GFP_KERNEL); if (!ac) return -ENOMEM; - strcpy(acpi_device_name(adev), ACPI_AC_DEVICE_NAME); - strcpy(acpi_device_class(adev), ACPI_AC_CLASS); - ac->pdev = pdev; - platform_set_drvdata(pdev, ac); + ac->device = device; + strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_AC_CLASS); + device->driver_data = ac; result = acpi_ac_get_state(ac); if (result) goto end; - ac->charger.name = acpi_device_bid(adev); + ac->charger.name = acpi_device_bid(device); ac->charger.type = POWER_SUPPLY_TYPE_MAINS; ac->charger.properties = ac_props; ac->charger.num_properties = ARRAY_SIZE(ac_props); ac->charger.get_property = get_ac_property; - result = power_supply_register(&pdev->dev, &ac->charger); + result = power_supply_register(&ac->device->dev, &ac->charger); if (result) goto end; - result = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev), - ACPI_ALL_NOTIFY, acpi_ac_notify_handler, ac); - if (result) { - power_supply_unregister(&ac->charger); - goto end; - } printk(KERN_INFO PREFIX "%s [%s] (%s)\n", - acpi_device_name(adev), acpi_device_bid(adev), + acpi_device_name(device), acpi_device_bid(device), ac->state ? "on-line" : "off-line"); ac->battery_nb.notifier_call = acpi_ac_battery_notify; @@ -256,7 +274,7 @@ static int acpi_ac_resume(struct device *dev) if (!dev) return -EINVAL; - ac = platform_get_drvdata(to_platform_device(dev)); + ac = acpi_driver_data(to_acpi_device(dev)); if (!ac) return -EINVAL; @@ -270,19 +288,17 @@ static int acpi_ac_resume(struct device *dev) #else #define acpi_ac_resume NULL #endif -static SIMPLE_DEV_PM_OPS(acpi_ac_pm_ops, NULL, acpi_ac_resume); -static int acpi_ac_remove(struct platform_device *pdev) +static int acpi_ac_remove(struct acpi_device *device) { - struct acpi_ac *ac; + struct acpi_ac *ac = NULL; + - if (!pdev) + if (!device || !acpi_driver_data(device)) return -EINVAL; - acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), - ACPI_ALL_NOTIFY, acpi_ac_notify_handler); + ac = acpi_driver_data(device); - ac = platform_get_drvdata(pdev); if (ac->charger.dev) power_supply_unregister(&ac->charger); unregister_acpi_notifier(&ac->battery_nb); @@ -292,23 +308,6 @@ static int acpi_ac_remove(struct platform_device *pdev) return 0; } -static const struct acpi_device_id acpi_ac_match[] = { - { "ACPI0003", 0 }, - { } -}; -MODULE_DEVICE_TABLE(acpi, acpi_ac_match); - -static struct platform_driver acpi_ac_driver = { - .probe = acpi_ac_probe, - .remove = acpi_ac_remove, - .driver = { - .name = "acpi-ac", - .owner = THIS_MODULE, - .pm = &acpi_ac_pm_ops, - .acpi_match_table = ACPI_PTR(acpi_ac_match), - }, -}; - static int __init acpi_ac_init(void) { int result; @@ -316,7 +315,7 @@ static int __init acpi_ac_init(void) if (acpi_disabled) return -ENODEV; - result = platform_driver_register(&acpi_ac_driver); + result = acpi_bus_register_driver(&acpi_ac_driver); if (result < 0) return -ENODEV; @@ -325,7 +324,7 @@ static int __init acpi_ac_init(void) static void __exit acpi_ac_exit(void) { - platform_driver_unregister(&acpi_ac_driver); + acpi_bus_unregister_driver(&acpi_ac_driver); } module_init(acpi_ac_init); module_exit(acpi_ac_exit); diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 37d73024b82e4f..e20708f2b8e56a 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -215,8 +215,15 @@ static int power_saving_thread(void *data) * borrow CPU time from this CPU and cause RT task use > 95% * CPU time. To make 'avoid starvation' work, takes a nap here. */ - if (do_sleep) + if (unlikely(do_sleep)) schedule_timeout_killable(HZ * idle_pct / 100); + + /* If an external event has set the need_resched flag, then + * we need to deal with it, or this loop will continue to + * spin without calling __mwait(). + */ + if (unlikely(need_resched())) + schedule(); } exit_round_robin(tsk_index); diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index dbfe49e5fd63cc..1d4950388fa13b 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -29,7 +29,6 @@ ACPI_MODULE_NAME("platform"); static const struct acpi_device_id acpi_platform_device_ids[] = { { "PNP0D40" }, - { "ACPI0003" }, { "VPC2004" }, { "BCM4752" }, diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index b06f5f55ada952..52c81c49cc7d83 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -405,7 +405,6 @@ static int acpi_processor_add(struct acpi_device *device, goto err; pr->dev = dev; - dev->offline = pr->flags.need_hotplug_init; /* Trigger the processor driver's .probe() if present. */ if (device_attach(dev) >= 0) diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index b7ed86a20427e4..8bb43f06e11fda 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -135,6 +135,7 @@ acpi-y += \ rsxface.o acpi-y += \ + tbdata.o \ tbfadt.o \ tbfind.o \ tbinstal.o \ diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h new file mode 100644 index 00000000000000..8698ffba6f392d --- /dev/null +++ b/drivers/acpi/acpica/acapps.h @@ -0,0 +1,170 @@ +/****************************************************************************** + * + * Module Name: acapps - common include for ACPI applications/tools + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * 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. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may 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") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _ACAPPS +#define _ACAPPS + +/* Common info for tool signons */ + +#define ACPICA_NAME "Intel ACPI Component Architecture" +#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2014 Intel Corporation" + +#if ACPI_MACHINE_WIDTH == 64 +#define ACPI_WIDTH "-64" + +#elif ACPI_MACHINE_WIDTH == 32 +#define ACPI_WIDTH "-32" + +#else +#error unknown ACPI_MACHINE_WIDTH +#define ACPI_WIDTH "-??" + +#endif + +/* Macros for signons and file headers */ + +#define ACPI_COMMON_SIGNON(utility_name) \ + "\n%s\n%s version %8.8X%s [%s]\n%s\n\n", \ + ACPICA_NAME, \ + utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, __DATE__, \ + ACPICA_COPYRIGHT + +#define ACPI_COMMON_HEADER(utility_name, prefix) \ + "%s%s\n%s%s version %8.8X%s [%s]\n%s%s\n%s\n", \ + prefix, ACPICA_NAME, \ + prefix, utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, __DATE__, \ + prefix, ACPICA_COPYRIGHT, \ + prefix + +/* Macros for usage messages */ + +#define ACPI_USAGE_HEADER(usage) \ + printf ("Usage: %s\nOptions:\n", usage); + +#define ACPI_OPTION(name, description) \ + printf (" %-18s%s\n", name, description); + +#define FILE_SUFFIX_DISASSEMBLY "dsl" +#define ACPI_TABLE_FILE_SUFFIX ".dat" + +/* + * getopt + */ +int acpi_getopt(int argc, char **argv, char *opts); + +int acpi_getopt_argument(int argc, char **argv); + +extern int acpi_gbl_optind; +extern int acpi_gbl_opterr; +extern int acpi_gbl_sub_opt_char; +extern char *acpi_gbl_optarg; + +/* + * cmfsize - Common get file size function + */ +u32 cm_get_file_size(FILE * file); + +#ifndef ACPI_DUMP_APP +/* + * adisasm + */ +acpi_status +ad_aml_disassemble(u8 out_to_file, + char *filename, char *prefix, char **out_filename); + +void ad_print_statistics(void); + +acpi_status ad_find_dsdt(u8 **dsdt_ptr, u32 *dsdt_length); + +void ad_dump_tables(void); + +acpi_status ad_get_local_tables(void); + +acpi_status +ad_parse_table(struct acpi_table_header *table, + acpi_owner_id * owner_id, u8 load_table, u8 external); + +acpi_status ad_display_tables(char *filename, struct acpi_table_header *table); + +acpi_status ad_display_statistics(void); + +/* + * adwalk + */ +void +acpi_dm_cross_reference_namespace(union acpi_parse_object *parse_tree_root, + struct acpi_namespace_node *namespace_root, + acpi_owner_id owner_id); + +void acpi_dm_dump_tree(union acpi_parse_object *origin); + +void acpi_dm_find_orphan_methods(union acpi_parse_object *origin); + +void +acpi_dm_finish_namespace_load(union acpi_parse_object *parse_tree_root, + struct acpi_namespace_node *namespace_root, + acpi_owner_id owner_id); + +void +acpi_dm_convert_resource_indexes(union acpi_parse_object *parse_tree_root, + struct acpi_namespace_node *namespace_root); + +/* + * adfile + */ +acpi_status ad_initialize(void); + +char *fl_generate_filename(char *input_filename, char *suffix); + +acpi_status +fl_split_input_pathname(char *input_path, + char **out_directory_path, char **out_filename); + +char *ad_generate_filename(char *prefix, char *table_id); + +void +ad_write_table(struct acpi_table_header *table, + u32 length, char *table_name, char *oem_table_id); +#endif + +#endif /* _ACAPPS */ diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 68ec61fff18868..7a7811a9fc261e 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -104,9 +104,10 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info); */ acpi_status acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, - struct acpi_generic_address *gpe_block_address, + u64 address, + u8 space_id, u32 register_count, - u8 gpe_block_base_number, + u16 gpe_block_base_number, u32 interrupt_number, struct acpi_gpe_block_info **return_gpe_block); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 49bbc71fad54ef..115eedcade1e3d 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -44,144 +44,14 @@ #ifndef __ACGLOBAL_H__ #define __ACGLOBAL_H__ -/* - * Ensure that the globals are actually defined and initialized only once. - * - * The use of these macros allows a single list of globals (here) in order - * to simplify maintenance of the code. - */ -#ifdef DEFINE_ACPI_GLOBALS -#define ACPI_GLOBAL(type,name) \ - extern type name; \ - type name - -#define ACPI_INIT_GLOBAL(type,name,value) \ - type name=value - -#else -#define ACPI_GLOBAL(type,name) \ - extern type name - -#define ACPI_INIT_GLOBAL(type,name,value) \ - extern type name -#endif - -#ifdef DEFINE_ACPI_GLOBALS - -/* Public globals, available from outside ACPICA subsystem */ - /***************************************************************************** * - * Runtime configuration (static defaults that can be overriden at runtime) + * Globals related to the ACPI tables * ****************************************************************************/ -/* - * Enable "slack" in the AML interpreter? Default is FALSE, and the - * interpreter strictly follows the ACPI specification. Setting to TRUE - * allows the interpreter to ignore certain errors and/or bad AML constructs. - * - * Currently, these features are enabled by this flag: - * - * 1) Allow "implicit return" of last value in a control method - * 2) Allow access beyond the end of an operation region - * 3) Allow access to uninitialized locals/args (auto-init to integer 0) - * 4) Allow ANY object type to be a source operand for the Store() operator - * 5) Allow unresolved references (invalid target name) in package objects - * 6) Enable warning messages for behavior that is not ACPI spec compliant - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE); +/* Master list of all ACPI tables that were found in the RSDT/XSDT */ -/* - * Automatically serialize all methods that create named objects? Default - * is TRUE, meaning that all non_serialized methods are scanned once at - * table load time to determine those that create named objects. Methods - * that create named objects are marked Serialized in order to prevent - * possible run-time problems if they are entered by more than one thread. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, TRUE); - -/* - * Create the predefined _OSI method in the namespace? Default is TRUE - * because ACPI CA is fully compatible with other ACPI implementations. - * Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE); - -/* - * Optionally use default values for the ACPI register widths. Set this to - * TRUE to use the defaults, if an FADT contains incorrect widths/lengths. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_use_default_register_widths, TRUE); - -/* - * Optionally enable output from the AML Debug Object. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_aml_debug_object, FALSE); - -/* - * Optionally copy the entire DSDT to local memory (instead of simply - * mapping it.) There are some BIOSs that corrupt or replace the original - * DSDT, creating the need for this option. Default is FALSE, do not copy - * the DSDT. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_copy_dsdt_locally, FALSE); - -/* - * Optionally ignore an XSDT if present and use the RSDT instead. - * Although the ACPI specification requires that an XSDT be used instead - * of the RSDT, the XSDT has been found to be corrupt or ill-formed on - * some machines. Default behavior is to use the XSDT if present. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE); - -/* - * Optionally use 32-bit FADT addresses if and when there is a conflict - * (address mismatch) between the 32-bit and 64-bit versions of the - * address. Although ACPICA adheres to the ACPI specification which - * requires the use of the corresponding 64-bit address if it is non-zero, - * some machines have been found to have a corrupted non-zero 64-bit - * address. Default is FALSE, do not favor the 32-bit addresses. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, FALSE); - -/* - * Optionally truncate I/O addresses to 16 bits. Provides compatibility - * with other ACPI implementations. NOTE: During ACPICA initialization, - * this value is set to TRUE if any Windows OSI strings have been - * requested by the BIOS. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_truncate_io_addresses, FALSE); - -/* - * Disable runtime checking and repair of values returned by control methods. - * Use only if the repair is causing a problem on a particular machine. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE); - -/* - * Optionally do not load any SSDTs from the RSDT/XSDT during initialization. - * This can be useful for debugging ACPI problems on some machines. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_load, FALSE); - -/* - * We keep track of the latest version of Windows that has been requested by - * the BIOS. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0); - -#endif /* DEFINE_ACPI_GLOBALS */ - -/***************************************************************************** - * - * ACPI Table globals - * - ****************************************************************************/ - -/* - * Master list of all ACPI tables that were found in the RSDT/XSDT. - */ ACPI_GLOBAL(struct acpi_table_list, acpi_gbl_root_table_list); /* DSDT information. Used to check for DSDT corruption */ @@ -279,7 +149,6 @@ ACPI_GLOBAL(acpi_exception_handler, acpi_gbl_exception_handler); ACPI_GLOBAL(acpi_init_handler, acpi_gbl_init_handler); ACPI_GLOBAL(acpi_table_handler, acpi_gbl_table_handler); ACPI_GLOBAL(void *, acpi_gbl_table_handler_context); -ACPI_GLOBAL(struct acpi_walk_state *, acpi_gbl_breakpoint_walk); ACPI_GLOBAL(acpi_interface_handler, acpi_gbl_interface_handler); ACPI_GLOBAL(struct acpi_sci_handler_info *, acpi_gbl_sci_handler_list); @@ -296,7 +165,6 @@ ACPI_GLOBAL(u8, acpi_gbl_reg_methods_executed); /* Misc */ ACPI_GLOBAL(u32, acpi_gbl_original_mode); -ACPI_GLOBAL(u32, acpi_gbl_rsdp_original_location); ACPI_GLOBAL(u32, acpi_gbl_ns_lookup_count); ACPI_GLOBAL(u32, acpi_gbl_ps_find_count); ACPI_GLOBAL(u16, acpi_gbl_pm1_enable_register_save); @@ -483,11 +351,6 @@ ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc); ACPI_GLOBAL(u32, acpi_gbl_num_nodes); ACPI_GLOBAL(u32, acpi_gbl_num_objects); -ACPI_GLOBAL(u32, acpi_gbl_size_of_parse_tree); -ACPI_GLOBAL(u32, acpi_gbl_size_of_method_trees); -ACPI_GLOBAL(u32, acpi_gbl_size_of_node_entries); -ACPI_GLOBAL(u32, acpi_gbl_size_of_acpi_objects); - #endif /* ACPI_DEBUGGER */ /***************************************************************************** @@ -509,5 +372,6 @@ ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_debug_file, NULL); ****************************************************************************/ extern const struct ah_predefined_name asl_predefined_info[]; +extern const struct ah_device_id asl_device_ids[]; #endif /* __ACGLOBAL_H__ */ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 52a21dafb54039..91f801a2e68957 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -450,9 +450,9 @@ struct acpi_gpe_event_info { struct acpi_gpe_register_info { struct acpi_generic_address status_address; /* Address of status reg */ struct acpi_generic_address enable_address; /* Address of enable reg */ + u16 base_gpe_number; /* Base GPE number for this register */ u8 enable_for_wake; /* GPEs to keep enabled when sleeping */ u8 enable_for_run; /* GPEs to keep enabled when running */ - u8 base_gpe_number; /* Base GPE number for this register */ }; /* @@ -466,11 +466,12 @@ struct acpi_gpe_block_info { struct acpi_gpe_xrupt_info *xrupt_block; /* Backpointer to interrupt block */ struct acpi_gpe_register_info *register_info; /* One per GPE register pair */ struct acpi_gpe_event_info *event_info; /* One for each GPE */ - struct acpi_generic_address block_address; /* Base address of the block */ + u64 address; /* Base address of the block */ u32 register_count; /* Number of register pairs in block */ u16 gpe_count; /* Number of individual GPEs in block */ - u8 block_base_number; /* Base GPE number for this block */ - u8 initialized; /* TRUE if this block is initialized */ + u16 block_base_number; /* Base GPE number for this block */ + u8 space_id; + u8 initialized; /* TRUE if this block is initialized */ }; /* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */ @@ -733,7 +734,8 @@ union acpi_parse_value { #define ACPI_DASM_MATCHOP 0x06 /* Parent opcode is a Match() operator */ #define ACPI_DASM_LNOT_PREFIX 0x07 /* Start of a Lnot_equal (etc.) pair of opcodes */ #define ACPI_DASM_LNOT_SUFFIX 0x08 /* End of a Lnot_equal (etc.) pair of opcodes */ -#define ACPI_DASM_IGNORE 0x09 /* Not used at this time */ +#define ACPI_DASM_HID_STRING 0x09 /* String is a _HID or _CID */ +#define ACPI_DASM_IGNORE 0x0A /* Not used at this time */ /* * Generic operation (for example: If, While, Store) @@ -1147,4 +1149,9 @@ struct ah_predefined_name { #endif }; +struct ah_device_id { + char *name; + char *description; +}; + #endif /* __ACLOCAL_H__ */ diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index a48d713e95991d..34001a9fd09847 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -586,6 +586,10 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = { {{"_LID", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, + {{"_LPD", METHOD_0ARGS, + METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Int) */ + PACKAGE_INFO(ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0), + {{"_MAT", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 5fa4b202769790..bda9a7eb50c1cd 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -53,6 +53,26 @@ acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length); +/* + * tbdata - table data structure management + */ +acpi_status acpi_tb_get_next_root_index(u32 *table_index); + +void +acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, + acpi_physical_address address, + u8 flags, struct acpi_table_header *table); + +acpi_status +acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, + acpi_physical_address address, u8 flags); + +void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc); + +u8 acpi_tb_is_table_loaded(u32 table_index); + +void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded); + /* * tbfadt - FADT parse/convert/validate */ @@ -72,22 +92,35 @@ acpi_tb_find_table(char *signature, */ acpi_status acpi_tb_resize_root_table_list(void); -acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc); +acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc); -struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header - *table_header, - struct acpi_table_desc - *table_desc); +void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc); acpi_status -acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index); +acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature); + +void acpi_tb_override_table(struct acpi_table_desc *old_table_desc); + +acpi_status +acpi_tb_acquire_table(struct acpi_table_desc *table_desc, + struct acpi_table_header **table_ptr, + u32 *table_length, u8 *table_flags); + +void +acpi_tb_release_table(struct acpi_table_header *table, + u32 table_length, u8 table_flags); + +acpi_status +acpi_tb_install_standard_table(acpi_physical_address address, + u8 flags, + u8 reload, u8 override, u32 *table_index); acpi_status acpi_tb_store_table(acpi_physical_address address, struct acpi_table_header *table, u32 length, u8 flags, u32 *table_index); -void acpi_tb_delete_table(struct acpi_table_desc *table_desc); +void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc); void acpi_tb_terminate(void); @@ -99,10 +132,6 @@ acpi_status acpi_tb_release_owner_id(u32 table_index); acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id); -u8 acpi_tb_is_table_loaded(u32 table_index); - -void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded); - /* * tbutils - table manager utilities */ @@ -124,8 +153,13 @@ void acpi_tb_check_dsdt_header(void); struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index); void -acpi_tb_install_table(acpi_physical_address address, - char *signature, u32 table_index); +acpi_tb_install_table_with_override(u32 table_index, + struct acpi_table_desc *new_table_desc, + u8 override); + +acpi_status +acpi_tb_install_fixed_table(acpi_physical_address address, + char *signature, u32 table_index); acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address); diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index ceeec0b7ccb176..1e256c5bda2067 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -176,8 +176,7 @@ acpi_status acpi_ut_init_globals(void); char *acpi_ut_get_mutex_name(u32 mutex_id); -const char *acpi_ut_get_notify_name(u32 notify_value); - +const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type); #endif char *acpi_ut_get_type_name(acpi_object_type type); @@ -737,4 +736,11 @@ acpi_ut_method_error(const char *module_name, struct acpi_namespace_node *node, const char *path, acpi_status lookup_status); +/* + * Utility functions for ACPI names and IDs + */ +const struct ah_predefined_name *acpi_ah_match_predefined_name(char *nameseg); + +const struct ah_device_id *acpi_ah_match_hardware_id(char *hid); + #endif /* _ACUTILS_H */ diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 955f83da68a52c..48f70013b488c7 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -383,7 +383,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) if (!(gpe_register_info->enable_for_run | gpe_register_info->enable_for_wake)) { ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, - "Ignore disabled registers for GPE%02X-GPE%02X: " + "Ignore disabled registers for GPE %02X-%02X: " "RunEnable=%02X, WakeEnable=%02X\n", gpe_register_info-> base_gpe_number, @@ -416,7 +416,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) } ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, - "Read registers for GPE%02X-GPE%02X: Status=%02X, Enable=%02X, " + "Read registers for GPE %02X-%02X: Status=%02X, Enable=%02X, " "RunEnable=%02X, WakeEnable=%02X\n", gpe_register_info->base_gpe_number, gpe_register_info->base_gpe_number + @@ -706,7 +706,8 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "Unable to clear GPE%02X", gpe_number)); + "Unable to clear GPE %02X", + gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } } @@ -723,7 +724,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "Unable to disable GPE%02X", gpe_number)); + "Unable to disable GPE %02X", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } @@ -764,7 +765,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "Unable to queue handler for GPE%02X - event disabled", + "Unable to queue handler for GPE %02X - event disabled", gpe_number)); } break; @@ -776,7 +777,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, * a GPE to be enabled if it has no handler or method. */ ACPI_ERROR((AE_INFO, - "No handler or method for GPE%02X, disabling event", + "No handler or method for GPE %02X, disabling event", gpe_number)); break; diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index caaed3c673fdf3..d86699eea33c49 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -252,21 +252,17 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) /* Init the register_info for this GPE register (8 GPEs) */ - this_register->base_gpe_number = - (u8) (gpe_block->block_base_number + - (i * ACPI_GPE_REGISTER_WIDTH)); + this_register->base_gpe_number = (u16) + (gpe_block->block_base_number + + (i * ACPI_GPE_REGISTER_WIDTH)); - this_register->status_address.address = - gpe_block->block_address.address + i; + this_register->status_address.address = gpe_block->address + i; this_register->enable_address.address = - gpe_block->block_address.address + i + - gpe_block->register_count; + gpe_block->address + i + gpe_block->register_count; - this_register->status_address.space_id = - gpe_block->block_address.space_id; - this_register->enable_address.space_id = - gpe_block->block_address.space_id; + this_register->status_address.space_id = gpe_block->space_id; + this_register->enable_address.space_id = gpe_block->space_id; this_register->status_address.bit_width = ACPI_GPE_REGISTER_WIDTH; this_register->enable_address.bit_width = @@ -334,9 +330,10 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) acpi_status acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, - struct acpi_generic_address *gpe_block_address, + u64 address, + u8 space_id, u32 register_count, - u8 gpe_block_base_number, + u16 gpe_block_base_number, u32 interrupt_number, struct acpi_gpe_block_info **return_gpe_block) { @@ -359,15 +356,14 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, /* Initialize the new GPE block */ + gpe_block->address = address; + gpe_block->space_id = space_id; gpe_block->node = gpe_device; gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH); gpe_block->initialized = FALSE; gpe_block->register_count = register_count; gpe_block->block_base_number = gpe_block_base_number; - ACPI_MEMCPY(&gpe_block->block_address, gpe_block_address, - sizeof(struct acpi_generic_address)); - /* * Create the register_info and event_info sub-structures * Note: disables and clears all GPEs in the block @@ -408,12 +404,14 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, } ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, - " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X\n", + " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n", (u32)gpe_block->block_base_number, (u32)(gpe_block->block_base_number + (gpe_block->gpe_count - 1)), gpe_device->name.ascii, gpe_block->register_count, - interrupt_number)); + interrupt_number, + interrupt_number == + acpi_gbl_FADT.sci_interrupt ? " (SCI)" : "")); /* Update global count of currently available GPEs */ diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index ae779c1e871dbf..49fc7effd96111 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -131,8 +131,10 @@ acpi_status acpi_ev_gpe_initialize(void) /* Install GPE Block 0 */ status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, - &acpi_gbl_FADT.xgpe0_block, - register_count0, 0, + acpi_gbl_FADT.xgpe0_block. + address, + acpi_gbl_FADT.xgpe0_block. + space_id, register_count0, 0, acpi_gbl_FADT.sci_interrupt, &acpi_gbl_gpe_fadt_blocks[0]); @@ -169,8 +171,10 @@ acpi_status acpi_ev_gpe_initialize(void) status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, - &acpi_gbl_FADT.xgpe1_block, - register_count1, + acpi_gbl_FADT.xgpe1_block. + address, + acpi_gbl_FADT.xgpe1_block. + space_id, register_count1, acpi_gbl_FADT.gpe1_base, acpi_gbl_FADT. sci_interrupt, diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index 5d594eb2e5ecb6..24ea3424981bd9 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -167,7 +167,8 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n", acpi_ut_get_node_name(node), acpi_ut_get_type_name(node->type), notify_value, - acpi_ut_get_notify_name(notify_value), node)); + acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY), + node)); status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch, info); diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c index 4d8a709c1fc450..29630e303829e2 100644 --- a/drivers/acpi/acpica/evsci.c +++ b/drivers/acpi/acpica/evsci.c @@ -117,7 +117,7 @@ static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context) ACPI_FUNCTION_TRACE(ev_sci_xrupt_handler); /* - * We are guaranteed by the ACPI CA initialization/shutdown code that + * We are guaranteed by the ACPICA initialization/shutdown code that * if this interrupt handler is installed, ACPI is enabled. */ diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index a734b27da0615e..11e5803b8b4195 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -239,7 +239,7 @@ acpi_remove_notify_handler(acpi_handle device, union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj; union acpi_operand_object *previous_handler_obj; - acpi_status status; + acpi_status status = AE_OK; u32 i; ACPI_FUNCTION_TRACE(acpi_remove_notify_handler); @@ -251,20 +251,17 @@ acpi_remove_notify_handler(acpi_handle device, return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Make sure all deferred notify tasks are completed */ - - acpi_os_wait_events_complete(); - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - /* Root Object. Global handlers are removed here */ if (device == ACPI_ROOT_OBJECT) { for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { if (handler_type & (i + 1)) { + status = + acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + if (!acpi_gbl_global_notify[i].handler || (acpi_gbl_global_notify[i].handler != handler)) { @@ -277,31 +274,40 @@ acpi_remove_notify_handler(acpi_handle device, acpi_gbl_global_notify[i].handler = NULL; acpi_gbl_global_notify[i].context = NULL; + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + + /* Make sure all deferred notify tasks are completed */ + + acpi_os_wait_events_complete(); } } - goto unlock_and_exit; + return_ACPI_STATUS(AE_OK); } /* All other objects: Are Notifies allowed on this object? */ if (!acpi_ev_is_notify_object(node)) { - status = AE_TYPE; - goto unlock_and_exit; + return_ACPI_STATUS(AE_TYPE); } /* Must have an existing internal object */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { - status = AE_NOT_EXIST; - goto unlock_and_exit; + return_ACPI_STATUS(AE_NOT_EXIST); } /* Internal object exists. Find the handler and remove it */ for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { if (handler_type & (i + 1)) { + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + handler_obj = obj_desc->common_notify.notify_list[i]; previous_handler_obj = NULL; @@ -329,10 +335,17 @@ acpi_remove_notify_handler(acpi_handle device, handler_obj->notify.next[i]; } + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + + /* Make sure all deferred notify tasks are completed */ + + acpi_os_wait_events_complete(); acpi_ut_remove_reference(handler_obj); } } + return_ACPI_STATUS(status); + unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); @@ -457,6 +470,8 @@ acpi_status acpi_install_sci_handler(acpi_sci_handler address, void *context) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_install_sci_handler) + /******************************************************************************* * * FUNCTION: acpi_remove_sci_handler @@ -468,7 +483,6 @@ acpi_status acpi_install_sci_handler(acpi_sci_handler address, void *context) * DESCRIPTION: Remove a handler for a System Control Interrupt. * ******************************************************************************/ - acpi_status acpi_remove_sci_handler(acpi_sci_handler address) { struct acpi_sci_handler_info *prev_sci_handler; @@ -522,6 +536,8 @@ acpi_status acpi_remove_sci_handler(acpi_sci_handler address) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_remove_sci_handler) + /******************************************************************************* * * FUNCTION: acpi_install_global_event_handler @@ -537,7 +553,6 @@ acpi_status acpi_remove_sci_handler(acpi_sci_handler address) * Can be used to update event counters, etc. * ******************************************************************************/ - acpi_status acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context) { @@ -840,10 +855,6 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Make sure all deferred GPE tasks are completed */ - - acpi_os_wait_events_complete(); - status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -895,9 +906,17 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, (void)acpi_ev_add_gpe_reference(gpe_event_info); } + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + + /* Make sure all deferred GPE tasks are completed */ + + acpi_os_wait_events_complete(); + /* Now we can free the handler object */ ACPI_FREE(handler); + return_ACPI_STATUS(status); unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 20a1392ffe06fd..cb534faf536986 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -599,9 +599,10 @@ acpi_install_gpe_block(acpi_handle gpe_device, * For user-installed GPE Block Devices, the gpe_block_base_number * is always zero */ - status = - acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0, - interrupt_number, &gpe_block); + status = acpi_ev_create_gpe_block(node, gpe_block_address->address, + gpe_block_address->space_id, + register_count, 0, interrupt_number, + &gpe_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 8ba1464efd112a..7d2949420db708 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -343,16 +343,14 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { union acpi_operand_object *ddb_handle; + struct acpi_table_header *table_header; struct acpi_table_header *table; - struct acpi_table_desc table_desc; u32 table_index; acpi_status status; u32 length; ACPI_FUNCTION_TRACE(ex_load_op); - ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc)); - /* Source Object can be either an op_region or a Buffer/Field */ switch (obj_desc->common.type) { @@ -380,17 +378,17 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* Get the table header first so we can get the table length */ - table = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); - if (!table) { + table_header = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); + if (!table_header) { return_ACPI_STATUS(AE_NO_MEMORY); } status = acpi_ex_region_read(obj_desc, sizeof(struct acpi_table_header), - ACPI_CAST_PTR(u8, table)); - length = table->length; - ACPI_FREE(table); + ACPI_CAST_PTR(u8, table_header)); + length = table_header->length; + ACPI_FREE(table_header); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -420,22 +418,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* Allocate a buffer for the table */ - table_desc.pointer = ACPI_ALLOCATE(length); - if (!table_desc.pointer) { + table = ACPI_ALLOCATE(length); + if (!table) { return_ACPI_STATUS(AE_NO_MEMORY); } /* Read the entire table */ status = acpi_ex_region_read(obj_desc, length, - ACPI_CAST_PTR(u8, - table_desc.pointer)); + ACPI_CAST_PTR(u8, table)); if (ACPI_FAILURE(status)) { - ACPI_FREE(table_desc.pointer); + ACPI_FREE(table); return_ACPI_STATUS(status); } - - table_desc.address = obj_desc->region.address; break; case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */ @@ -452,10 +447,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* Get the actual table length from the table header */ - table = + table_header = ACPI_CAST_PTR(struct acpi_table_header, obj_desc->buffer.pointer); - length = table->length; + length = table_header->length; /* Table cannot extend beyond the buffer */ @@ -470,13 +465,12 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, * Copy the table from the buffer because the buffer could be modified * or even deleted in the future */ - table_desc.pointer = ACPI_ALLOCATE(length); - if (!table_desc.pointer) { + table = ACPI_ALLOCATE(length); + if (!table) { return_ACPI_STATUS(AE_NO_MEMORY); } - ACPI_MEMCPY(table_desc.pointer, table, length); - table_desc.address = ACPI_TO_INTEGER(table_desc.pointer); + ACPI_MEMCPY(table, table_header, length); break; default: @@ -484,27 +478,32 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } - /* Validate table checksum (will not get validated in tb_add_table) */ - - status = acpi_tb_verify_checksum(table_desc.pointer, length); - if (ACPI_FAILURE(status)) { - ACPI_FREE(table_desc.pointer); - return_ACPI_STATUS(status); - } - - /* Complete the table descriptor */ + /* Install the new table into the local data structures */ - table_desc.length = length; - table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED; + ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:")); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - /* Install the new table into the local data structures */ + status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table), + ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, + TRUE, TRUE, &table_index); - status = acpi_tb_add_table(&table_desc, &table_index); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); if (ACPI_FAILURE(status)) { /* Delete allocated table buffer */ - acpi_tb_delete_table(&table_desc); + ACPI_FREE(table); + return_ACPI_STATUS(status); + } + + /* + * Note: Now table is "INSTALLED", it must be validated before + * loading. + */ + status = + acpi_tb_validate_table(&acpi_gbl_root_table_list. + tables[table_index]); + if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -536,9 +535,6 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(status); } - ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:")); - acpi_tb_print_table_header(0, table_desc.pointer); - /* Remove the reference by added by acpi_ex_store above */ acpi_ut_remove_reference(ddb_handle); @@ -546,8 +542,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* Invoke table handler if present */ if (acpi_gbl_table_handler) { - (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, - table_desc.pointer, + (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table, acpi_gbl_table_handler_context); } @@ -575,6 +570,13 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) ACPI_FUNCTION_TRACE(ex_unload_table); + /* + * Temporarily emit a warning so that the ASL for the machine can be + * hopefully obtained. This is to say that the Unload() operator is + * extremely rare if not completely unused. + */ + ACPI_WARNING((AE_INFO, "Received request to unload an ACPI table")); + /* * Validate the handle * Although the handle is partially validated in acpi_ex_reconfiguration() diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 973fdae00f9479..925202acc3e4f2 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -134,9 +134,11 @@ static struct acpi_exdump_info acpi_ex_dump_method[9] = { {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.aml_start), "Aml Start"} }; -static struct acpi_exdump_info acpi_ex_dump_mutex[5] = { +static struct acpi_exdump_info acpi_ex_dump_mutex[6] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.original_sync_level), + "Original Sync Level"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"}, {ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth), "Acquire Depth"}, diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c index e701d8c33dbfb3..6aade8e1d2a1fc 100644 --- a/drivers/acpi/acpica/hwpci.c +++ b/drivers/acpi/acpica/hwpci.c @@ -140,11 +140,12 @@ acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id, /* Walk the list, updating the PCI device/function/bus numbers */ status = acpi_hw_process_pci_list(pci_id, list_head); - } - /* Always delete the list */ + /* Delete the list */ + + acpi_hw_delete_pci_list(list_head); + } - acpi_hw_delete_pci_list(list_head); return_ACPI_STATUS(status); } @@ -187,6 +188,10 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device, while (1) { status = acpi_get_parent(current_device, &parent_device); if (ACPI_FAILURE(status)) { + + /* Must delete the list before exit */ + + acpi_hw_delete_pci_list(*return_list_head); return (status); } @@ -199,6 +204,10 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device, list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device)); if (!list_element) { + + /* Must delete the list before exit */ + + acpi_hw_delete_pci_list(*return_list_head); return (AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 75d3690506570d..049d9c22a0f961 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -72,6 +72,8 @@ acpi_buffer_to_resource(u8 *aml_buffer, void *resource; void *current_resource_ptr; + ACPI_FUNCTION_TRACE(acpi_buffer_to_resource); + /* * Note: we allow AE_AML_NO_RESOURCE_END_TAG, since an end tag * is not required here. @@ -85,7 +87,7 @@ acpi_buffer_to_resource(u8 *aml_buffer, status = AE_OK; } if (ACPI_FAILURE(status)) { - return (status); + return_ACPI_STATUS(status); } /* Allocate a buffer for the converted resource */ @@ -93,7 +95,7 @@ acpi_buffer_to_resource(u8 *aml_buffer, resource = ACPI_ALLOCATE_ZEROED(list_size_needed); current_resource_ptr = resource; if (!resource) { - return (AE_NO_MEMORY); + return_ACPI_STATUS(AE_NO_MEMORY); } /* Perform the AML-to-Resource conversion */ @@ -110,9 +112,11 @@ acpi_buffer_to_resource(u8 *aml_buffer, *resource_ptr = resource; } - return (status); + return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_buffer_to_resource) + /******************************************************************************* * * FUNCTION: acpi_rs_create_resource_list @@ -130,10 +134,9 @@ acpi_buffer_to_resource(u8 *aml_buffer, * of device resources. * ******************************************************************************/ - acpi_status acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, - struct acpi_buffer * output_buffer) + struct acpi_buffer *output_buffer) { acpi_status status; diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c new file mode 100644 index 00000000000000..cbe29944dc9735 --- /dev/null +++ b/drivers/acpi/acpica/tbdata.c @@ -0,0 +1,723 @@ +/****************************************************************************** + * + * Module Name: tbdata - Table manager data structure functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * 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. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may 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") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include "accommon.h" +#include "acnamesp.h" +#include "actables.h" + +#define _COMPONENT ACPI_TABLES +ACPI_MODULE_NAME("tbdata") + +/******************************************************************************* + * + * FUNCTION: acpi_tb_init_table_descriptor + * + * PARAMETERS: table_desc - Table descriptor + * address - Physical address of the table + * flags - Allocation flags of the table + * table - Pointer to the table + * + * RETURN: None + * + * DESCRIPTION: Initialize a new table descriptor + * + ******************************************************************************/ +void +acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, + acpi_physical_address address, + u8 flags, struct acpi_table_header *table) +{ + + /* + * Initialize the table descriptor. Set the pointer to NULL, since the + * table is not fully mapped at this time. + */ + ACPI_MEMSET(table_desc, 0, sizeof(struct acpi_table_desc)); + table_desc->address = address; + table_desc->length = table->length; + table_desc->flags = flags; + ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_acquire_table + * + * PARAMETERS: table_desc - Table descriptor + * table_ptr - Where table is returned + * table_length - Where table length is returned + * table_flags - Where table allocation flags are returned + * + * RETURN: Status + * + * DESCRIPTION: Acquire an ACPI table. It can be used for tables not + * maintained in the acpi_gbl_root_table_list. + * + ******************************************************************************/ + +acpi_status +acpi_tb_acquire_table(struct acpi_table_desc *table_desc, + struct acpi_table_header **table_ptr, + u32 *table_length, u8 *table_flags) +{ + struct acpi_table_header *table = NULL; + + switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: + + table = + acpi_os_map_memory(table_desc->address, table_desc->length); + break; + + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: + + table = + ACPI_CAST_PTR(struct acpi_table_header, + table_desc->address); + break; + + default: + + break; + } + + /* Table is not valid yet */ + + if (!table) { + return (AE_NO_MEMORY); + } + + /* Fill the return values */ + + *table_ptr = table; + *table_length = table_desc->length; + *table_flags = table_desc->flags; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_release_table + * + * PARAMETERS: table - Pointer for the table + * table_length - Length for the table + * table_flags - Allocation flags for the table + * + * RETURN: None + * + * DESCRIPTION: Release a table. The inverse of acpi_tb_acquire_table(). + * + ******************************************************************************/ + +void +acpi_tb_release_table(struct acpi_table_header *table, + u32 table_length, u8 table_flags) +{ + + switch (table_flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: + + acpi_os_unmap_memory(table, table_length); + break; + + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: + default: + + break; + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_acquire_temp_table + * + * PARAMETERS: table_desc - Table descriptor to be acquired + * address - Address of the table + * flags - Allocation flags of the table + * + * RETURN: Status + * + * DESCRIPTION: This function validates the table header to obtain the length + * of a table and fills the table descriptor to make its state as + * "INSTALLED". Such a table descriptor is only used for verified + * installation. + * + ******************************************************************************/ + +acpi_status +acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, + acpi_physical_address address, u8 flags) +{ + struct acpi_table_header *table_header; + + switch (flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: + + /* Get the length of the full table from the header */ + + table_header = + acpi_os_map_memory(address, + sizeof(struct acpi_table_header)); + if (!table_header) { + return (AE_NO_MEMORY); + } + + acpi_tb_init_table_descriptor(table_desc, address, flags, + table_header); + acpi_os_unmap_memory(table_header, + sizeof(struct acpi_table_header)); + return (AE_OK); + + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: + + table_header = ACPI_CAST_PTR(struct acpi_table_header, address); + if (!table_header) { + return (AE_NO_MEMORY); + } + + acpi_tb_init_table_descriptor(table_desc, address, flags, + table_header); + return (AE_OK); + + default: + + break; + } + + /* Table is not valid yet */ + + return (AE_NO_MEMORY); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_release_temp_table + * + * PARAMETERS: table_desc - Table descriptor to be released + * + * RETURN: Status + * + * DESCRIPTION: The inverse of acpi_tb_acquire_temp_table(). + * + *****************************************************************************/ + +void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc) +{ + + /* + * Note that the .Address is maintained by the callers of + * acpi_tb_acquire_temp_table(), thus do not invoke acpi_tb_uninstall_table() + * where .Address will be freed. + */ + acpi_tb_invalidate_table(table_desc); +} + +/****************************************************************************** + * + * FUNCTION: acpi_tb_validate_table + * + * PARAMETERS: table_desc - Table descriptor + * + * RETURN: Status + * + * DESCRIPTION: This function is called to validate the table, the returned + * table descriptor is in "VALIDATED" state. + * + *****************************************************************************/ + +acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE(tb_validate_table); + + /* Validate the table if necessary */ + + if (!table_desc->pointer) { + status = acpi_tb_acquire_table(table_desc, &table_desc->pointer, + &table_desc->length, + &table_desc->flags); + if (!table_desc->pointer) { + status = AE_NO_MEMORY; + } + } + + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_invalidate_table + * + * PARAMETERS: table_desc - Table descriptor + * + * RETURN: None + * + * DESCRIPTION: Invalidate one internal ACPI table, this is the inverse of + * acpi_tb_validate_table(). + * + ******************************************************************************/ + +void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc) +{ + + ACPI_FUNCTION_TRACE(tb_invalidate_table); + + /* Table must be validated */ + + if (!table_desc->pointer) { + return_VOID; + } + + acpi_tb_release_table(table_desc->pointer, table_desc->length, + table_desc->flags); + table_desc->pointer = NULL; + + return_VOID; +} + +/****************************************************************************** + * + * FUNCTION: acpi_tb_verify_table + * + * PARAMETERS: table_desc - Table descriptor + * signature - Table signature to verify + * + * RETURN: Status + * + * DESCRIPTION: This function is called to validate and verify the table, the + * returned table descriptor is in "VALIDATED" state. + * + *****************************************************************************/ + +acpi_status +acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE(tb_verify_table); + + /* Validate the table */ + + status = acpi_tb_validate_table(table_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* If a particular signature is expected (DSDT/FACS), it must match */ + + if (signature && !ACPI_COMPARE_NAME(&table_desc->signature, signature)) { + ACPI_BIOS_ERROR((AE_INFO, + "Invalid signature 0x%X for ACPI table, expected [%s]", + table_desc->signature.integer, signature)); + status = AE_BAD_SIGNATURE; + goto invalidate_and_exit; + } + + /* Verify the checksum */ + + status = + acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, + "%4.4s " ACPI_PRINTF_UINT + " Attempted table install failed", + acpi_ut_valid_acpi_name(table_desc->signature. + ascii) ? table_desc-> + signature.ascii : "????", + ACPI_FORMAT_TO_UINT(table_desc->address))); + goto invalidate_and_exit; + } + + return_ACPI_STATUS(AE_OK); + +invalidate_and_exit: + acpi_tb_invalidate_table(table_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_resize_root_table_list + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Expand the size of global table array + * + ******************************************************************************/ + +acpi_status acpi_tb_resize_root_table_list(void) +{ + struct acpi_table_desc *tables; + u32 table_count; + + ACPI_FUNCTION_TRACE(tb_resize_root_table_list); + + /* allow_resize flag is a parameter to acpi_initialize_tables */ + + if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) { + ACPI_ERROR((AE_INFO, + "Resize of Root Table Array is not allowed")); + return_ACPI_STATUS(AE_SUPPORT); + } + + /* Increase the Table Array size */ + + if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { + table_count = acpi_gbl_root_table_list.max_table_count; + } else { + table_count = acpi_gbl_root_table_list.current_table_count; + } + + tables = ACPI_ALLOCATE_ZEROED(((acpi_size) table_count + + ACPI_ROOT_TABLE_SIZE_INCREMENT) * + sizeof(struct acpi_table_desc)); + if (!tables) { + ACPI_ERROR((AE_INFO, + "Could not allocate new root table array")); + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Copy and free the previous table array */ + + if (acpi_gbl_root_table_list.tables) { + ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, + (acpi_size) table_count * + sizeof(struct acpi_table_desc)); + + if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { + ACPI_FREE(acpi_gbl_root_table_list.tables); + } + } + + acpi_gbl_root_table_list.tables = tables; + acpi_gbl_root_table_list.max_table_count = + table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT; + acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED; + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_next_root_index + * + * PARAMETERS: table_index - Where table index is returned + * + * RETURN: Status and table index. + * + * DESCRIPTION: Allocate a new ACPI table entry to the global table list + * + ******************************************************************************/ + +acpi_status acpi_tb_get_next_root_index(u32 *table_index) +{ + acpi_status status; + + /* Ensure that there is room for the table in the Root Table List */ + + if (acpi_gbl_root_table_list.current_table_count >= + acpi_gbl_root_table_list.max_table_count) { + status = acpi_tb_resize_root_table_list(); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + *table_index = acpi_gbl_root_table_list.current_table_count; + acpi_gbl_root_table_list.current_table_count++; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_terminate + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Delete all internal ACPI tables + * + ******************************************************************************/ + +void acpi_tb_terminate(void) +{ + u32 i; + + ACPI_FUNCTION_TRACE(tb_terminate); + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + + /* Delete the individual tables */ + + for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { + acpi_tb_uninstall_table(&acpi_gbl_root_table_list.tables[i]); + } + + /* + * Delete the root table array if allocated locally. Array cannot be + * mapped, so we don't need to check for that flag. + */ + if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { + ACPI_FREE(acpi_gbl_root_table_list.tables); + } + + acpi_gbl_root_table_list.tables = NULL; + acpi_gbl_root_table_list.flags = 0; + acpi_gbl_root_table_list.current_table_count = 0; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_delete_namespace_by_owner + * + * PARAMETERS: table_index - Table index + * + * RETURN: Status + * + * DESCRIPTION: Delete all namespace objects created when this table was loaded. + * + ******************************************************************************/ + +acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) +{ + acpi_owner_id owner_id; + acpi_status status; + + ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner); + + status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + if (table_index >= acpi_gbl_root_table_list.current_table_count) { + + /* The table index does not exist */ + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(AE_NOT_EXIST); + } + + /* Get the owner ID for this table, used to delete namespace nodes */ + + owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id; + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + + /* + * Need to acquire the namespace writer lock to prevent interference + * with any concurrent namespace walks. The interpreter must be + * released during the deletion since the acquisition of the deletion + * lock may block, and also since the execution of a namespace walk + * must be allowed to use the interpreter. + */ + (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); + status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); + + acpi_ns_delete_namespace_by_owner(owner_id); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock); + + status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_allocate_owner_id + * + * PARAMETERS: table_index - Table index + * + * RETURN: Status + * + * DESCRIPTION: Allocates owner_id in table_desc + * + ******************************************************************************/ + +acpi_status acpi_tb_allocate_owner_id(u32 table_index) +{ + acpi_status status = AE_BAD_PARAMETER; + + ACPI_FUNCTION_TRACE(tb_allocate_owner_id); + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.current_table_count) { + status = + acpi_ut_allocate_owner_id(& + (acpi_gbl_root_table_list. + tables[table_index].owner_id)); + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_release_owner_id + * + * PARAMETERS: table_index - Table index + * + * RETURN: Status + * + * DESCRIPTION: Releases owner_id in table_desc + * + ******************************************************************************/ + +acpi_status acpi_tb_release_owner_id(u32 table_index) +{ + acpi_status status = AE_BAD_PARAMETER; + + ACPI_FUNCTION_TRACE(tb_release_owner_id); + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.current_table_count) { + acpi_ut_release_owner_id(& + (acpi_gbl_root_table_list. + tables[table_index].owner_id)); + status = AE_OK; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_owner_id + * + * PARAMETERS: table_index - Table index + * owner_id - Where the table owner_id is returned + * + * RETURN: Status + * + * DESCRIPTION: returns owner_id for the ACPI table + * + ******************************************************************************/ + +acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id * owner_id) +{ + acpi_status status = AE_BAD_PARAMETER; + + ACPI_FUNCTION_TRACE(tb_get_owner_id); + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.current_table_count) { + *owner_id = + acpi_gbl_root_table_list.tables[table_index].owner_id; + status = AE_OK; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_is_table_loaded + * + * PARAMETERS: table_index - Index into the root table + * + * RETURN: Table Loaded Flag + * + ******************************************************************************/ + +u8 acpi_tb_is_table_loaded(u32 table_index) +{ + u8 is_loaded = FALSE; + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.current_table_count) { + is_loaded = (u8) + (acpi_gbl_root_table_list.tables[table_index].flags & + ACPI_TABLE_IS_LOADED); + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return (is_loaded); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_set_table_loaded_flag + * + * PARAMETERS: table_index - Table index + * is_loaded - TRUE if table is loaded, FALSE otherwise + * + * RETURN: None + * + * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE. + * + ******************************************************************************/ + +void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded) +{ + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.current_table_count) { + if (is_loaded) { + acpi_gbl_root_table_list.tables[table_index].flags |= + ACPI_TABLE_IS_LOADED; + } else { + acpi_gbl_root_table_list.tables[table_index].flags &= + ~ACPI_TABLE_IS_LOADED; + } + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); +} diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index ec14588254d433..41519a9580838b 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -52,7 +52,8 @@ ACPI_MODULE_NAME("tbfadt") static void acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, u8 space_id, - u8 byte_width, u64 address, char *register_name); + u8 byte_width, + u64 address, char *register_name, u8 flags); static void acpi_tb_convert_fadt(void); @@ -69,13 +70,14 @@ typedef struct acpi_fadt_info { u16 address32; u16 length; u8 default_length; - u8 type; + u8 flags; } acpi_fadt_info; #define ACPI_FADT_OPTIONAL 0 #define ACPI_FADT_REQUIRED 1 #define ACPI_FADT_SEPARATE_LENGTH 2 +#define ACPI_FADT_GPE_REGISTER 4 static struct acpi_fadt_info fadt_info_table[] = { {"Pm1aEventBlock", @@ -125,14 +127,14 @@ static struct acpi_fadt_info fadt_info_table[] = { ACPI_FADT_OFFSET(gpe0_block), ACPI_FADT_OFFSET(gpe0_block_length), 0, - ACPI_FADT_SEPARATE_LENGTH}, + ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER}, {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block), ACPI_FADT_OFFSET(gpe1_block), ACPI_FADT_OFFSET(gpe1_block_length), 0, - ACPI_FADT_SEPARATE_LENGTH} + ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER} }; #define ACPI_FADT_INFO_ENTRIES \ @@ -189,19 +191,29 @@ static struct acpi_fadt_pm_info fadt_pm_info_table[] = { static void acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, u8 space_id, - u8 byte_width, u64 address, char *register_name) + u8 byte_width, + u64 address, char *register_name, u8 flags) { u8 bit_width; - /* Bit width field in the GAS is only one byte long, 255 max */ - + /* + * Bit width field in the GAS is only one byte long, 255 max. + * Check for bit_width overflow in GAS. + */ bit_width = (u8)(byte_width * 8); - - if (byte_width > 31) { /* (31*8)=248 */ - ACPI_ERROR((AE_INFO, - "%s - 32-bit FADT register is too long (%u bytes, %u bits) " - "to convert to GAS struct - 255 bits max, truncating", - register_name, byte_width, (byte_width * 8))); + if (byte_width > 31) { /* (31*8)=248, (32*8)=256 */ + /* + * No error for GPE blocks, because we do not use the bit_width + * for GPEs, the legacy length (byte_width) is used instead to + * allow for a large number of GPEs. + */ + if (!(flags & ACPI_FADT_GPE_REGISTER)) { + ACPI_ERROR((AE_INFO, + "%s - 32-bit FADT register is too long (%u bytes, %u bits) " + "to convert to GAS struct - 255 bits max, truncating", + register_name, byte_width, + (byte_width * 8))); + } bit_width = 255; } @@ -332,15 +344,15 @@ void acpi_tb_parse_fadt(u32 table_index) /* Obtain the DSDT and FACS tables via their addresses within the FADT */ - acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, - ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); + acpi_tb_install_fixed_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, + ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); /* If Hardware Reduced flag is set, there is no FACS */ if (!acpi_gbl_reduced_hardware) { - acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT. - Xfacs, ACPI_SIG_FACS, - ACPI_TABLE_INDEX_FACS); + acpi_tb_install_fixed_table((acpi_physical_address) + acpi_gbl_FADT.Xfacs, ACPI_SIG_FACS, + ACPI_TABLE_INDEX_FACS); } } @@ -450,6 +462,7 @@ static void acpi_tb_convert_fadt(void) struct acpi_generic_address *address64; u32 address32; u8 length; + u8 flags; u32 i; /* @@ -515,6 +528,7 @@ static void acpi_tb_convert_fadt(void) fadt_info_table[i].length); name = fadt_info_table[i].name; + flags = fadt_info_table[i].flags; /* * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" @@ -554,7 +568,7 @@ static void acpi_tb_convert_fadt(void) [i]. length), (u64)address32, - name); + name, flags); } else if (address64->address != (u64)address32) { /* Address mismatch */ @@ -582,7 +596,8 @@ static void acpi_tb_convert_fadt(void) length), (u64) address32, - name); + name, + flags); } } } @@ -603,7 +618,7 @@ static void acpi_tb_convert_fadt(void) address64->bit_width)); } - if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) { + if (fadt_info_table[i].flags & ACPI_FADT_REQUIRED) { /* * Field is required (Pm1a_event, Pm1a_control). * Both the address and length must be non-zero. @@ -617,7 +632,7 @@ static void acpi_tb_convert_fadt(void) address), length)); } - } else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) { + } else if (fadt_info_table[i].flags & ACPI_FADT_SEPARATE_LENGTH) { /* * Field is optional (Pm2_control, GPE0, GPE1) AND has its own * length field. If present, both the address and length must @@ -726,7 +741,7 @@ static void acpi_tb_setup_fadt_registers(void) (fadt_pm_info_table[i]. register_num * pm1_register_byte_width), - "PmRegisters"); + "PmRegisters", 0); } } } diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index c12003947bd53c..cb947700206ca5 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -99,8 +99,8 @@ acpi_tb_find_table(char *signature, /* Table is not currently mapped, map it */ status = - acpi_tb_verify_table(&acpi_gbl_root_table_list. - tables[i]); + acpi_tb_validate_table(&acpi_gbl_root_table_list. + tables[i]); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index e3040947e9a00f..d4d6029fef4419 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -43,688 +43,483 @@ #include #include "accommon.h" -#include "acnamesp.h" #include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbinstal") -/****************************************************************************** +/* Local prototypes */ +static u8 +acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index); + +/******************************************************************************* * - * FUNCTION: acpi_tb_verify_table + * FUNCTION: acpi_tb_compare_tables * - * PARAMETERS: table_desc - table + * PARAMETERS: table_desc - Table 1 descriptor to be compared + * table_index - Index of table 2 to be compared * - * RETURN: Status + * RETURN: TRUE if both tables are identical. * - * DESCRIPTION: this function is called to verify and map table + * DESCRIPTION: This function compares a table with another table that has + * already been installed in the root table list. * - *****************************************************************************/ -acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc) + ******************************************************************************/ + +static u8 +acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index) { acpi_status status = AE_OK; + u8 is_identical; + struct acpi_table_header *table; + u32 table_length; + u8 table_flags; - ACPI_FUNCTION_TRACE(tb_verify_table); - - /* Map the table if necessary */ - - if (!table_desc->pointer) { - if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == - ACPI_TABLE_ORIGIN_MAPPED) { - table_desc->pointer = - acpi_os_map_memory(table_desc->address, - table_desc->length); - } - if (!table_desc->pointer) { - return_ACPI_STATUS(AE_NO_MEMORY); - } + status = + acpi_tb_acquire_table(&acpi_gbl_root_table_list.tables[table_index], + &table, &table_length, &table_flags); + if (ACPI_FAILURE(status)) { + return (FALSE); } - /* Always calculate checksum, ignore bad checksum if requested */ + /* + * Check for a table match on the entire table length, + * not just the header. + */ + is_identical = (u8)((table_desc->length != table_length || + ACPI_MEMCMP(table_desc->pointer, table, + table_length)) ? FALSE : TRUE); - status = - acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); + /* Release the acquired table */ - return_ACPI_STATUS(status); + acpi_tb_release_table(table, table_length, table_flags); + return (is_identical); } /******************************************************************************* * - * FUNCTION: acpi_tb_add_table + * FUNCTION: acpi_tb_install_table_with_override * - * PARAMETERS: table_desc - Table descriptor - * table_index - Where the table index is returned + * PARAMETERS: table_index - Index into root table array + * new_table_desc - New table descriptor to install + * override - Whether override should be performed * - * RETURN: Status + * RETURN: None * - * DESCRIPTION: This function is called to add an ACPI table. It is used to - * dynamically load tables via the Load and load_table AML - * operators. + * DESCRIPTION: Install an ACPI table into the global data structure. The + * table override mechanism is called to allow the host + * OS to replace any table before it is installed in the root + * table array. * ******************************************************************************/ -acpi_status -acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) +void +acpi_tb_install_table_with_override(u32 table_index, + struct acpi_table_desc *new_table_desc, + u8 override) { - u32 i; - acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE(tb_add_table); - - if (!table_desc->pointer) { - status = acpi_tb_verify_table(table_desc); - if (ACPI_FAILURE(status) || !table_desc->pointer) { - return_ACPI_STATUS(status); - } + if (table_index >= acpi_gbl_root_table_list.current_table_count) { + return; } /* - * Validate the incoming table signature. + * ACPI Table Override: * - * 1) Originally, we checked the table signature for "SSDT" or "PSDT". - * 2) We added support for OEMx tables, signature "OEM". - * 3) Valid tables were encountered with a null signature, so we just - * gave up on validating the signature, (05/2008). - * 4) We encountered non-AML tables such as the MADT, which caused - * interpreter errors and kernel faults. So now, we once again allow - * only "SSDT", "OEMx", and now, also a null signature. (05/2011). + * Before we install the table, let the host OS override it with a new + * one if desired. Any table within the RSDT/XSDT can be replaced, + * including the DSDT which is pointed to by the FADT. */ - if ((table_desc->pointer->signature[0] != 0x00) && - (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)) - && (ACPI_STRNCMP(table_desc->pointer->signature, "OEM", 3))) { - ACPI_BIOS_ERROR((AE_INFO, - "Table has invalid signature [%4.4s] (0x%8.8X), " - "must be SSDT or OEMx", - acpi_ut_valid_acpi_name(table_desc->pointer-> - signature) ? - table_desc->pointer->signature : "????", - *(u32 *)table_desc->pointer->signature)); - - return_ACPI_STATUS(AE_BAD_SIGNATURE); + if (override) { + acpi_tb_override_table(new_table_desc); } - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list. + tables[table_index], + new_table_desc->address, + new_table_desc->flags, + new_table_desc->pointer); - /* Check if table is already registered */ + acpi_tb_print_table_header(new_table_desc->address, + new_table_desc->pointer); - for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { - if (!acpi_gbl_root_table_list.tables[i].pointer) { - status = - acpi_tb_verify_table(&acpi_gbl_root_table_list. - tables[i]); - if (ACPI_FAILURE(status) - || !acpi_gbl_root_table_list.tables[i].pointer) { - continue; - } - } + /* Set the global integer width (based upon revision of the DSDT) */ - /* - * Check for a table match on the entire table length, - * not just the header. - */ - if (table_desc->length != - acpi_gbl_root_table_list.tables[i].length) { - continue; - } - - if (ACPI_MEMCMP(table_desc->pointer, - acpi_gbl_root_table_list.tables[i].pointer, - acpi_gbl_root_table_list.tables[i].length)) { - continue; - } - - /* - * Note: the current mechanism does not unregister a table if it is - * dynamically unloaded. The related namespace entries are deleted, - * but the table remains in the root table list. - * - * The assumption here is that the number of different tables that - * will be loaded is actually small, and there is minimal overhead - * in just keeping the table in case it is needed again. - * - * If this assumption changes in the future (perhaps on large - * machines with many table load/unload operations), tables will - * need to be unregistered when they are unloaded, and slots in the - * root table list should be reused when empty. - */ - - /* - * Table is already registered. - * We can delete the table that was passed as a parameter. - */ - acpi_tb_delete_table(table_desc); - *table_index = i; - - if (acpi_gbl_root_table_list.tables[i]. - flags & ACPI_TABLE_IS_LOADED) { - - /* Table is still loaded, this is an error */ - - status = AE_ALREADY_EXISTS; - goto release; - } else { - /* Table was unloaded, allow it to be reloaded */ - - table_desc->pointer = - acpi_gbl_root_table_list.tables[i].pointer; - table_desc->address = - acpi_gbl_root_table_list.tables[i].address; - status = AE_OK; - goto print_header; - } + if (table_index == ACPI_TABLE_INDEX_DSDT) { + acpi_ut_set_integer_width(new_table_desc->pointer->revision); } - - /* - * ACPI Table Override: - * Allow the host to override dynamically loaded tables. - * NOTE: the table is fully mapped at this point, and the mapping will - * be deleted by tb_table_override if the table is actually overridden. - */ - (void)acpi_tb_table_override(table_desc->pointer, table_desc); - - /* Add the table to the global root table list */ - - status = acpi_tb_store_table(table_desc->address, table_desc->pointer, - table_desc->length, table_desc->flags, - table_index); - if (ACPI_FAILURE(status)) { - goto release; - } - -print_header: - acpi_tb_print_table_header(table_desc->address, table_desc->pointer); - -release: - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(status); } /******************************************************************************* * - * FUNCTION: acpi_tb_table_override + * FUNCTION: acpi_tb_install_fixed_table * - * PARAMETERS: table_header - Header for the original table - * table_desc - Table descriptor initialized for the - * original table. May or may not be mapped. + * PARAMETERS: address - Physical address of DSDT or FACS + * signature - Table signature, NULL if no need to + * match + * table_index - Index into root table array * - * RETURN: Pointer to the entire new table. NULL if table not overridden. - * If overridden, installs the new table within the input table - * descriptor. + * RETURN: Status * - * DESCRIPTION: Attempt table override by calling the OSL override functions. - * Note: If the table is overridden, then the entire new table - * is mapped and returned by this function. + * DESCRIPTION: Install a fixed ACPI table (DSDT/FACS) into the global data + * structure. * ******************************************************************************/ -struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header - *table_header, - struct acpi_table_desc - *table_desc) +acpi_status +acpi_tb_install_fixed_table(acpi_physical_address address, + char *signature, u32 table_index) { + struct acpi_table_desc new_table_desc; acpi_status status; - struct acpi_table_header *new_table = NULL; - acpi_physical_address new_address = 0; - u32 new_table_length = 0; - u8 new_flags; - char *override_type; - /* (1) Attempt logical override (returns a logical address) */ + ACPI_FUNCTION_TRACE(tb_install_fixed_table); - status = acpi_os_table_override(table_header, &new_table); - if (ACPI_SUCCESS(status) && new_table) { - new_address = ACPI_PTR_TO_PHYSADDR(new_table); - new_table_length = new_table->length; - new_flags = ACPI_TABLE_ORIGIN_OVERRIDE; - override_type = "Logical"; - goto finish_override; + if (!address) { + ACPI_ERROR((AE_INFO, + "Null physical address for ACPI table [%s]", + signature)); + return (AE_NO_MEMORY); } - /* (2) Attempt physical override (returns a physical address) */ + /* Fill a table descriptor for validation */ - status = acpi_os_physical_table_override(table_header, - &new_address, - &new_table_length); - if (ACPI_SUCCESS(status) && new_address && new_table_length) { - - /* Map the entire new table */ - - new_table = acpi_os_map_memory(new_address, new_table_length); - if (!new_table) { - ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, - "%4.4s " ACPI_PRINTF_UINT - " Attempted physical table override failed", - table_header->signature, - ACPI_FORMAT_TO_UINT(table_desc-> - address))); - return (NULL); - } - - override_type = "Physical"; - new_flags = ACPI_TABLE_ORIGIN_MAPPED; - goto finish_override; + status = acpi_tb_acquire_temp_table(&new_table_desc, address, + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL); + if (ACPI_FAILURE(status)) { + ACPI_ERROR((AE_INFO, "Could not acquire table length at %p", + ACPI_CAST_PTR(void, address))); + return_ACPI_STATUS(status); } - return (NULL); /* There was no override */ - -finish_override: - - ACPI_INFO((AE_INFO, "%4.4s " ACPI_PRINTF_UINT - " %s table override, new table: " ACPI_PRINTF_UINT, - table_header->signature, - ACPI_FORMAT_TO_UINT(table_desc->address), - override_type, ACPI_FORMAT_TO_UINT(new_table))); + /* Validate and verify a table before installation */ - /* We can now unmap/delete the original table (if fully mapped) */ + status = acpi_tb_verify_table(&new_table_desc, signature); + if (ACPI_FAILURE(status)) { + goto release_and_exit; + } - acpi_tb_delete_table(table_desc); + acpi_tb_install_table_with_override(table_index, &new_table_desc, TRUE); - /* Setup descriptor for the new table */ +release_and_exit: - table_desc->address = new_address; - table_desc->pointer = new_table; - table_desc->length = new_table_length; - table_desc->flags = new_flags; + /* Release the temporary table descriptor */ - return (new_table); + acpi_tb_release_temp_table(&new_table_desc); + return_ACPI_STATUS(status); } /******************************************************************************* * - * FUNCTION: acpi_tb_resize_root_table_list + * FUNCTION: acpi_tb_install_standard_table * - * PARAMETERS: None + * PARAMETERS: address - Address of the table (might be a virtual + * address depending on the table_flags) + * flags - Flags for the table + * reload - Whether reload should be performed + * override - Whether override should be performed + * table_index - Where the table index is returned * * RETURN: Status * - * DESCRIPTION: Expand the size of global table array + * DESCRIPTION: This function is called to install an ACPI table that is + * neither DSDT nor FACS (a "standard" table.) + * When this function is called by "Load" or "LoadTable" opcodes, + * or by acpi_load_table() API, the "Reload" parameter is set. + * After sucessfully returning from this function, table is + * "INSTALLED" but not "VALIDATED". * ******************************************************************************/ -acpi_status acpi_tb_resize_root_table_list(void) +acpi_status +acpi_tb_install_standard_table(acpi_physical_address address, + u8 flags, + u8 reload, u8 override, u32 *table_index) { - struct acpi_table_desc *tables; - u32 table_count; - - ACPI_FUNCTION_TRACE(tb_resize_root_table_list); - - /* allow_resize flag is a parameter to acpi_initialize_tables */ + u32 i; + acpi_status status = AE_OK; + struct acpi_table_desc new_table_desc; - if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) { - ACPI_ERROR((AE_INFO, - "Resize of Root Table Array is not allowed")); - return_ACPI_STATUS(AE_SUPPORT); - } + ACPI_FUNCTION_TRACE(tb_install_standard_table); - /* Increase the Table Array size */ + /* Acquire a temporary table descriptor for validation */ - if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { - table_count = acpi_gbl_root_table_list.max_table_count; - } else { - table_count = acpi_gbl_root_table_list.current_table_count; + status = acpi_tb_acquire_temp_table(&new_table_desc, address, flags); + if (ACPI_FAILURE(status)) { + ACPI_ERROR((AE_INFO, "Could not acquire table length at %p", + ACPI_CAST_PTR(void, address))); + return_ACPI_STATUS(status); } - tables = ACPI_ALLOCATE_ZEROED(((acpi_size) table_count + - ACPI_ROOT_TABLE_SIZE_INCREMENT) * - sizeof(struct acpi_table_desc)); - if (!tables) { - ACPI_ERROR((AE_INFO, - "Could not allocate new root table array")); - return_ACPI_STATUS(AE_NO_MEMORY); + /* + * Optionally do not load any SSDTs from the RSDT/XSDT. This can + * be useful for debugging ACPI problems on some machines. + */ + if (!reload && + acpi_gbl_disable_ssdt_table_install && + ACPI_COMPARE_NAME(&new_table_desc.signature, ACPI_SIG_SSDT)) { + ACPI_INFO((AE_INFO, "Ignoring installation of %4.4s at %p", + new_table_desc.signature.ascii, ACPI_CAST_PTR(void, + address))); + goto release_and_exit; } - /* Copy and free the previous table array */ - - if (acpi_gbl_root_table_list.tables) { - ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, - (acpi_size) table_count * - sizeof(struct acpi_table_desc)); + /* Validate and verify a table before installation */ - if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { - ACPI_FREE(acpi_gbl_root_table_list.tables); - } + status = acpi_tb_verify_table(&new_table_desc, NULL); + if (ACPI_FAILURE(status)) { + goto release_and_exit; } - acpi_gbl_root_table_list.tables = tables; - acpi_gbl_root_table_list.max_table_count = - table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT; - acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED; - - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_store_table - * - * PARAMETERS: address - Table address - * table - Table header - * length - Table length - * flags - flags - * - * RETURN: Status and table index. - * - * DESCRIPTION: Add an ACPI table to the global table list - * - ******************************************************************************/ + if (reload) { + /* + * Validate the incoming table signature. + * + * 1) Originally, we checked the table signature for "SSDT" or "PSDT". + * 2) We added support for OEMx tables, signature "OEM". + * 3) Valid tables were encountered with a null signature, so we just + * gave up on validating the signature, (05/2008). + * 4) We encountered non-AML tables such as the MADT, which caused + * interpreter errors and kernel faults. So now, we once again allow + * only "SSDT", "OEMx", and now, also a null signature. (05/2011). + */ + if ((new_table_desc.signature.ascii[0] != 0x00) && + (!ACPI_COMPARE_NAME + (&new_table_desc.signature, ACPI_SIG_SSDT)) + && (ACPI_STRNCMP(new_table_desc.signature.ascii, "OEM", 3))) + { + ACPI_BIOS_ERROR((AE_INFO, + "Table has invalid signature [%4.4s] (0x%8.8X), " + "must be SSDT or OEMx", + acpi_ut_valid_acpi_name(new_table_desc. + signature. + ascii) ? + new_table_desc.signature. + ascii : "????", + new_table_desc.signature.integer)); + + status = AE_BAD_SIGNATURE; + goto release_and_exit; + } -acpi_status -acpi_tb_store_table(acpi_physical_address address, - struct acpi_table_header *table, - u32 length, u8 flags, u32 *table_index) -{ - acpi_status status; - struct acpi_table_desc *new_table; + /* Check if table is already registered */ - /* Ensure that there is room for the table in the Root Table List */ + for (i = 0; i < acpi_gbl_root_table_list.current_table_count; + ++i) { + /* + * Check for a table match on the entire table length, + * not just the header. + */ + if (!acpi_tb_compare_tables(&new_table_desc, i)) { + continue; + } - if (acpi_gbl_root_table_list.current_table_count >= - acpi_gbl_root_table_list.max_table_count) { - status = acpi_tb_resize_root_table_list(); - if (ACPI_FAILURE(status)) { - return (status); + /* + * Note: the current mechanism does not unregister a table if it is + * dynamically unloaded. The related namespace entries are deleted, + * but the table remains in the root table list. + * + * The assumption here is that the number of different tables that + * will be loaded is actually small, and there is minimal overhead + * in just keeping the table in case it is needed again. + * + * If this assumption changes in the future (perhaps on large + * machines with many table load/unload operations), tables will + * need to be unregistered when they are unloaded, and slots in the + * root table list should be reused when empty. + */ + if (acpi_gbl_root_table_list.tables[i]. + flags & ACPI_TABLE_IS_LOADED) { + + /* Table is still loaded, this is an error */ + + status = AE_ALREADY_EXISTS; + goto release_and_exit; + } else { + /* + * Table was unloaded, allow it to be reloaded. + * As we are going to return AE_OK to the caller, we should + * take the responsibility of freeing the input descriptor. + * Refill the input descriptor to ensure + * acpi_tb_install_table_with_override() can be called again to + * indicate the re-installation. + */ + acpi_tb_uninstall_table(&new_table_desc); + *table_index = i; + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(AE_OK); + } } } - new_table = - &acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list. - current_table_count]; - - /* Initialize added table */ - - new_table->address = address; - new_table->pointer = table; - new_table->length = length; - new_table->owner_id = 0; - new_table->flags = flags; - - ACPI_MOVE_32_TO_32(&new_table->signature, table->signature); - - *table_index = acpi_gbl_root_table_list.current_table_count; - acpi_gbl_root_table_list.current_table_count++; - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_delete_table - * - * PARAMETERS: table_index - Table index - * - * RETURN: None - * - * DESCRIPTION: Delete one internal ACPI table - * - ******************************************************************************/ + /* Add the table to the global root table list */ -void acpi_tb_delete_table(struct acpi_table_desc *table_desc) -{ - /* Table must be mapped or allocated */ - if (!table_desc->pointer) { - return; + status = acpi_tb_get_next_root_index(&i); + if (ACPI_FAILURE(status)) { + goto release_and_exit; } - switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_MAPPED: - - acpi_os_unmap_memory(table_desc->pointer, table_desc->length); - break; - - case ACPI_TABLE_ORIGIN_ALLOCATED: - ACPI_FREE(table_desc->pointer); - break; + *table_index = i; + acpi_tb_install_table_with_override(i, &new_table_desc, override); - /* Not mapped or allocated, there is nothing we can do */ +release_and_exit: - default: + /* Release the temporary table descriptor */ - return; - } - - table_desc->pointer = NULL; + acpi_tb_release_temp_table(&new_table_desc); + return_ACPI_STATUS(status); } /******************************************************************************* * - * FUNCTION: acpi_tb_terminate + * FUNCTION: acpi_tb_override_table * - * PARAMETERS: None + * PARAMETERS: old_table_desc - Validated table descriptor to be + * overridden * * RETURN: None * - * DESCRIPTION: Delete all internal ACPI tables + * DESCRIPTION: Attempt table override by calling the OSL override functions. + * Note: If the table is overridden, then the entire new table + * is acquired and returned by this function. + * Before/after invocation, the table descriptor is in a state + * that is "VALIDATED". * ******************************************************************************/ -void acpi_tb_terminate(void) +void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) { - u32 i; - - ACPI_FUNCTION_TRACE(tb_terminate); - - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - - /* Delete the individual tables */ + acpi_status status; + char *override_type; + struct acpi_table_desc new_table_desc; + struct acpi_table_header *table; + acpi_physical_address address; + u32 length; - for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { - acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]); - } + /* (1) Attempt logical override (returns a logical address) */ - /* - * Delete the root table array if allocated locally. Array cannot be - * mapped, so we don't need to check for that flag. - */ - if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { - ACPI_FREE(acpi_gbl_root_table_list.tables); + status = acpi_os_table_override(old_table_desc->pointer, &table); + if (ACPI_SUCCESS(status) && table) { + acpi_tb_acquire_temp_table(&new_table_desc, + ACPI_PTR_TO_PHYSADDR(table), + ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL); + override_type = "Logical"; + goto finish_override; } - acpi_gbl_root_table_list.tables = NULL; - acpi_gbl_root_table_list.flags = 0; - acpi_gbl_root_table_list.current_table_count = 0; + /* (2) Attempt physical override (returns a physical address) */ - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + status = acpi_os_physical_table_override(old_table_desc->pointer, + &address, &length); + if (ACPI_SUCCESS(status) && address && length) { + acpi_tb_acquire_temp_table(&new_table_desc, address, + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL); + override_type = "Physical"; + goto finish_override; + } - return_VOID; -} + return; /* There was no override */ -/******************************************************************************* - * - * FUNCTION: acpi_tb_delete_namespace_by_owner - * - * PARAMETERS: table_index - Table index - * - * RETURN: Status - * - * DESCRIPTION: Delete all namespace objects created when this table was loaded. - * - ******************************************************************************/ - -acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) -{ - acpi_owner_id owner_id; - acpi_status status; +finish_override: - ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner); + /* Validate and verify a table before overriding */ - status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + status = acpi_tb_verify_table(&new_table_desc, NULL); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + return; } - if (table_index >= acpi_gbl_root_table_list.current_table_count) { - - /* The table index does not exist */ - - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(AE_NOT_EXIST); - } + ACPI_INFO((AE_INFO, "%4.4s " ACPI_PRINTF_UINT + " %s table override, new table: " ACPI_PRINTF_UINT, + old_table_desc->signature.ascii, + ACPI_FORMAT_TO_UINT(old_table_desc->address), + override_type, ACPI_FORMAT_TO_UINT(new_table_desc.address))); - /* Get the owner ID for this table, used to delete namespace nodes */ + /* We can now uninstall the original table */ - owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id; - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + acpi_tb_uninstall_table(old_table_desc); /* - * Need to acquire the namespace writer lock to prevent interference - * with any concurrent namespace walks. The interpreter must be - * released during the deletion since the acquisition of the deletion - * lock may block, and also since the execution of a namespace walk - * must be allowed to use the interpreter. + * Replace the original table descriptor and keep its state as + * "VALIDATED". */ - (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); - status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); + acpi_tb_init_table_descriptor(old_table_desc, new_table_desc.address, + new_table_desc.flags, + new_table_desc.pointer); + acpi_tb_validate_table(old_table_desc); - acpi_ns_delete_namespace_by_owner(owner_id); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + /* Release the temporary table descriptor */ - acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock); - - status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); - return_ACPI_STATUS(status); + acpi_tb_release_temp_table(&new_table_desc); } /******************************************************************************* * - * FUNCTION: acpi_tb_allocate_owner_id + * FUNCTION: acpi_tb_store_table * - * PARAMETERS: table_index - Table index + * PARAMETERS: address - Table address + * table - Table header + * length - Table length + * flags - Install flags + * table_index - Where the table index is returned * - * RETURN: Status + * RETURN: Status and table index. * - * DESCRIPTION: Allocates owner_id in table_desc + * DESCRIPTION: Add an ACPI table to the global table list * ******************************************************************************/ -acpi_status acpi_tb_allocate_owner_id(u32 table_index) +acpi_status +acpi_tb_store_table(acpi_physical_address address, + struct acpi_table_header * table, + u32 length, u8 flags, u32 *table_index) { - acpi_status status = AE_BAD_PARAMETER; - - ACPI_FUNCTION_TRACE(tb_allocate_owner_id); + acpi_status status; + struct acpi_table_desc *table_desc; - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (table_index < acpi_gbl_root_table_list.current_table_count) { - status = acpi_ut_allocate_owner_id - (&(acpi_gbl_root_table_list.tables[table_index].owner_id)); + status = acpi_tb_get_next_root_index(table_index); + if (ACPI_FAILURE(status)) { + return (status); } - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_release_owner_id - * - * PARAMETERS: table_index - Table index - * - * RETURN: Status - * - * DESCRIPTION: Releases owner_id in table_desc - * - ******************************************************************************/ - -acpi_status acpi_tb_release_owner_id(u32 table_index) -{ - acpi_status status = AE_BAD_PARAMETER; - - ACPI_FUNCTION_TRACE(tb_release_owner_id); - - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (table_index < acpi_gbl_root_table_list.current_table_count) { - acpi_ut_release_owner_id(& - (acpi_gbl_root_table_list. - tables[table_index].owner_id)); - status = AE_OK; - } + /* Initialize added table */ - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(status); + table_desc = &acpi_gbl_root_table_list.tables[*table_index]; + acpi_tb_init_table_descriptor(table_desc, address, flags, table); + table_desc->pointer = table; + return (AE_OK); } /******************************************************************************* * - * FUNCTION: acpi_tb_get_owner_id + * FUNCTION: acpi_tb_uninstall_table * - * PARAMETERS: table_index - Table index - * owner_id - Where the table owner_id is returned + * PARAMETERS: table_desc - Table descriptor * - * RETURN: Status + * RETURN: None * - * DESCRIPTION: returns owner_id for the ACPI table + * DESCRIPTION: Delete one internal ACPI table * ******************************************************************************/ -acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id) +void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc) { - acpi_status status = AE_BAD_PARAMETER; - - ACPI_FUNCTION_TRACE(tb_get_owner_id); - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (table_index < acpi_gbl_root_table_list.current_table_count) { - *owner_id = - acpi_gbl_root_table_list.tables[table_index].owner_id; - status = AE_OK; - } + ACPI_FUNCTION_TRACE(tb_uninstall_table); - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_is_table_loaded - * - * PARAMETERS: table_index - Table index - * - * RETURN: Table Loaded Flag - * - ******************************************************************************/ + /* Table must be installed */ -u8 acpi_tb_is_table_loaded(u32 table_index) -{ - u8 is_loaded = FALSE; - - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (table_index < acpi_gbl_root_table_list.current_table_count) { - is_loaded = (u8) - (acpi_gbl_root_table_list.tables[table_index].flags & - ACPI_TABLE_IS_LOADED); + if (!table_desc->address) { + return_VOID; } - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return (is_loaded); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_set_table_loaded_flag - * - * PARAMETERS: table_index - Table index - * is_loaded - TRUE if table is loaded, FALSE otherwise - * - * RETURN: None - * - * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE. - * - ******************************************************************************/ - -void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded) -{ + acpi_tb_invalidate_table(table_desc); - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (table_index < acpi_gbl_root_table_list.current_table_count) { - if (is_loaded) { - acpi_gbl_root_table_list.tables[table_index].flags |= - ACPI_TABLE_IS_LOADED; - } else { - acpi_gbl_root_table_list.tables[table_index].flags &= - ~ACPI_TABLE_IS_LOADED; - } + if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == + ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) { + ACPI_FREE(ACPI_CAST_PTR(void, table_desc->address)); } - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL); + return_VOID; } diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index a4702eee91a820..e37a103013a42b 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -49,8 +49,6 @@ ACPI_MODULE_NAME("tbutils") /* Local prototypes */ -static acpi_status acpi_tb_validate_xsdt(acpi_physical_address address); - static acpi_physical_address acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); @@ -178,9 +176,13 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) } ACPI_MEMCPY(new_table, table_desc->pointer, table_desc->length); - acpi_tb_delete_table(table_desc); - table_desc->pointer = new_table; - table_desc->flags = ACPI_TABLE_ORIGIN_ALLOCATED; + acpi_tb_uninstall_table(table_desc); + + acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT], + ACPI_PTR_TO_PHYSADDR(new_table), + ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, + new_table); ACPI_INFO((AE_INFO, "Forced DSDT copy: length 0x%05X copied locally, original unmapped", @@ -189,116 +191,6 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) return (new_table); } -/******************************************************************************* - * - * FUNCTION: acpi_tb_install_table - * - * PARAMETERS: address - Physical address of DSDT or FACS - * signature - Table signature, NULL if no need to - * match - * table_index - Index into root table array - * - * RETURN: None - * - * DESCRIPTION: Install an ACPI table into the global data structure. The - * table override mechanism is called to allow the host - * OS to replace any table before it is installed in the root - * table array. - * - ******************************************************************************/ - -void -acpi_tb_install_table(acpi_physical_address address, - char *signature, u32 table_index) -{ - struct acpi_table_header *table; - struct acpi_table_header *final_table; - struct acpi_table_desc *table_desc; - - if (!address) { - ACPI_ERROR((AE_INFO, - "Null physical address for ACPI table [%s]", - signature)); - return; - } - - /* Map just the table header */ - - table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); - if (!table) { - ACPI_ERROR((AE_INFO, - "Could not map memory for table [%s] at %p", - signature, ACPI_CAST_PTR(void, address))); - return; - } - - /* If a particular signature is expected (DSDT/FACS), it must match */ - - if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) { - ACPI_BIOS_ERROR((AE_INFO, - "Invalid signature 0x%X for ACPI table, expected [%s]", - *ACPI_CAST_PTR(u32, table->signature), - signature)); - goto unmap_and_exit; - } - - /* - * Initialize the table entry. Set the pointer to NULL, since the - * table is not fully mapped at this time. - */ - table_desc = &acpi_gbl_root_table_list.tables[table_index]; - - table_desc->address = address; - table_desc->pointer = NULL; - table_desc->length = table->length; - table_desc->flags = ACPI_TABLE_ORIGIN_MAPPED; - ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature); - - /* - * ACPI Table Override: - * - * Before we install the table, let the host OS override it with a new - * one if desired. Any table within the RSDT/XSDT can be replaced, - * including the DSDT which is pointed to by the FADT. - * - * NOTE: If the table is overridden, then final_table will contain a - * mapped pointer to the full new table. If the table is not overridden, - * or if there has been a physical override, then the table will be - * fully mapped later (in verify table). In any case, we must - * unmap the header that was mapped above. - */ - final_table = acpi_tb_table_override(table, table_desc); - if (!final_table) { - final_table = table; /* There was no override */ - } - - acpi_tb_print_table_header(table_desc->address, final_table); - - /* Set the global integer width (based upon revision of the DSDT) */ - - if (table_index == ACPI_TABLE_INDEX_DSDT) { - acpi_ut_set_integer_width(final_table->revision); - } - - /* - * If we have a physical override during this early loading of the ACPI - * tables, unmap the table for now. It will be mapped again later when - * it is actually used. This supports very early loading of ACPI tables, - * before virtual memory is fully initialized and running within the - * host OS. Note: A logical override has the ACPI_TABLE_ORIGIN_OVERRIDE - * flag set and will not be deleted below. - */ - if (final_table != table) { - acpi_tb_delete_table(table_desc); - } - -unmap_and_exit: - - /* Always unmap the table header that we mapped above */ - - acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); -} - /******************************************************************************* * * FUNCTION: acpi_tb_get_root_table_entry @@ -355,87 +247,6 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size) } } -/******************************************************************************* - * - * FUNCTION: acpi_tb_validate_xsdt - * - * PARAMETERS: address - Physical address of the XSDT (from RSDP) - * - * RETURN: Status. AE_OK if the table appears to be valid. - * - * DESCRIPTION: Validate an XSDT to ensure that it is of minimum size and does - * not contain any NULL entries. A problem that is seen in the - * field is that the XSDT exists, but is actually useless because - * of one or more (or all) NULL entries. - * - ******************************************************************************/ - -static acpi_status acpi_tb_validate_xsdt(acpi_physical_address xsdt_address) -{ - struct acpi_table_header *table; - u8 *next_entry; - acpi_physical_address address; - u32 length; - u32 entry_count; - acpi_status status; - u32 i; - - /* Get the XSDT length */ - - table = - acpi_os_map_memory(xsdt_address, sizeof(struct acpi_table_header)); - if (!table) { - return (AE_NO_MEMORY); - } - - length = table->length; - acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); - - /* - * Minimum XSDT length is the size of the standard ACPI header - * plus one physical address entry - */ - if (length < (sizeof(struct acpi_table_header) + ACPI_XSDT_ENTRY_SIZE)) { - return (AE_INVALID_TABLE_LENGTH); - } - - /* Map the entire XSDT */ - - table = acpi_os_map_memory(xsdt_address, length); - if (!table) { - return (AE_NO_MEMORY); - } - - /* Get the number of entries and pointer to first entry */ - - status = AE_OK; - next_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); - entry_count = (u32)((table->length - sizeof(struct acpi_table_header)) / - ACPI_XSDT_ENTRY_SIZE); - - /* Validate each entry (physical address) within the XSDT */ - - for (i = 0; i < entry_count; i++) { - address = - acpi_tb_get_root_table_entry(next_entry, - ACPI_XSDT_ENTRY_SIZE); - if (!address) { - - /* Detected a NULL entry, XSDT is invalid */ - - status = AE_NULL_ENTRY; - break; - } - - next_entry += ACPI_XSDT_ENTRY_SIZE; - } - - /* Unmap table */ - - acpi_os_unmap_memory(table, length); - return (status); -} - /******************************************************************************* * * FUNCTION: acpi_tb_parse_root_table @@ -464,6 +275,7 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) u32 length; u8 *table_entry; acpi_status status; + u32 table_index; ACPI_FUNCTION_TRACE(tb_parse_root_table); @@ -502,25 +314,6 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) */ acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); - /* - * If it is present and used, validate the XSDT for access/size - * and ensure that all table entries are at least non-NULL - */ - if (table_entry_size == ACPI_XSDT_ENTRY_SIZE) { - status = acpi_tb_validate_xsdt(address); - if (ACPI_FAILURE(status)) { - ACPI_BIOS_WARNING((AE_INFO, - "XSDT is invalid (%s), using RSDT", - acpi_format_exception(status))); - - /* Fall back to the RSDT */ - - address = - (acpi_physical_address) rsdp->rsdt_physical_address; - table_entry_size = ACPI_RSDT_ENTRY_SIZE; - } - } - /* Map the RSDT/XSDT table header to get the full table length */ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); @@ -573,31 +366,33 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) /* Initialize the root table array from the RSDT/XSDT */ for (i = 0; i < table_count; i++) { - if (acpi_gbl_root_table_list.current_table_count >= - acpi_gbl_root_table_list.max_table_count) { - - /* There is no more room in the root table array, attempt resize */ - - status = acpi_tb_resize_root_table_list(); - if (ACPI_FAILURE(status)) { - ACPI_WARNING((AE_INFO, - "Truncating %u table entries!", - (unsigned) (table_count - - (acpi_gbl_root_table_list. - current_table_count - - 2)))); - break; - } - } /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ - acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list. - current_table_count].address = + address = acpi_tb_get_root_table_entry(table_entry, table_entry_size); + /* Skip NULL entries in RSDT/XSDT */ + + if (!address) { + goto next_table; + } + + status = acpi_tb_install_standard_table(address, + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, + FALSE, TRUE, + &table_index); + + if (ACPI_SUCCESS(status) && + ACPI_COMPARE_NAME(&acpi_gbl_root_table_list. + tables[table_index].signature, + ACPI_SIG_FADT)) { + acpi_tb_parse_fadt(table_index); + } + +next_table: + table_entry += table_entry_size; - acpi_gbl_root_table_list.current_table_count++; } /* @@ -606,22 +401,5 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) */ acpi_os_unmap_memory(table, length); - /* - * Complete the initialization of the root table array by examining - * the header of each table - */ - for (i = 2; i < acpi_gbl_root_table_list.current_table_count; i++) { - acpi_tb_install_table(acpi_gbl_root_table_list.tables[i]. - address, NULL, i); - - /* Special case for FADT - validate it then get the DSDT and FACS */ - - if (ACPI_COMPARE_NAME - (&acpi_gbl_root_table_list.tables[i].signature, - ACPI_SIG_FADT)) { - acpi_tb_parse_fadt(i); - } - } - return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index a1593159d9ea4f..6482b0ded65214 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -206,8 +206,8 @@ acpi_status acpi_get_table_header(char *signature, u32 instance, struct acpi_table_header *out_table_header) { - u32 i; - u32 j; + u32 i; + u32 j; struct acpi_table_header *header; /* Parameter validation */ @@ -233,7 +233,7 @@ acpi_get_table_header(char *signature, if (!acpi_gbl_root_table_list.tables[i].pointer) { if ((acpi_gbl_root_table_list.tables[i].flags & ACPI_TABLE_ORIGIN_MASK) == - ACPI_TABLE_ORIGIN_MAPPED) { + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL) { header = acpi_os_map_memory(acpi_gbl_root_table_list. tables[i].address, @@ -321,8 +321,8 @@ acpi_get_table_with_size(char *signature, u32 instance, struct acpi_table_header **out_table, acpi_size *tbl_size) { - u32 i; - u32 j; + u32 i; + u32 j; acpi_status status; /* Parameter validation */ @@ -346,7 +346,7 @@ acpi_get_table_with_size(char *signature, } status = - acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]); + acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]); if (ACPI_SUCCESS(status)) { *out_table = acpi_gbl_root_table_list.tables[i].pointer; *tbl_size = acpi_gbl_root_table_list.tables[i].length; @@ -390,7 +390,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table) * ******************************************************************************/ acpi_status -acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table) +acpi_get_table_by_index(u32 table_index, struct acpi_table_header ** table) { acpi_status status; @@ -416,8 +416,8 @@ acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table) /* Table is not mapped, map it */ status = - acpi_tb_verify_table(&acpi_gbl_root_table_list. - tables[table_index]); + acpi_tb_validate_table(&acpi_gbl_root_table_list. + tables[table_index]); if (ACPI_FAILURE(status)) { (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 0909420fc77651..ab5308b81aa82e 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -117,7 +117,7 @@ static acpi_status acpi_tb_load_namespace(void) tables[ACPI_TABLE_INDEX_DSDT].signature), ACPI_SIG_DSDT) || - ACPI_FAILURE(acpi_tb_verify_table + ACPI_FAILURE(acpi_tb_validate_table (&acpi_gbl_root_table_list. tables[ACPI_TABLE_INDEX_DSDT]))) { status = AE_NO_ACPI_TABLES; @@ -128,7 +128,7 @@ static acpi_status acpi_tb_load_namespace(void) * Save the DSDT pointer for simple access. This is the mapped memory * address. We must take care here because the address of the .Tables * array can change dynamically as tables are loaded at run-time. Note: - * .Pointer field is not validated until after call to acpi_tb_verify_table. + * .Pointer field is not validated until after call to acpi_tb_validate_table. */ acpi_gbl_DSDT = acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer; @@ -174,24 +174,11 @@ static acpi_status acpi_tb_load_namespace(void) (acpi_gbl_root_table_list.tables[i]. signature), ACPI_SIG_PSDT)) || - ACPI_FAILURE(acpi_tb_verify_table + ACPI_FAILURE(acpi_tb_validate_table (&acpi_gbl_root_table_list.tables[i]))) { continue; } - /* - * Optionally do not load any SSDTs from the RSDT/XSDT. This can - * be useful for debugging ACPI problems on some machines. - */ - if (acpi_gbl_disable_ssdt_table_load) { - ACPI_INFO((AE_INFO, "Ignoring %4.4s at %p", - acpi_gbl_root_table_list.tables[i].signature. - ascii, ACPI_CAST_PTR(void, - acpi_gbl_root_table_list. - tables[i].address))); - continue; - } - /* Ignore errors while loading tables, get as many as possible */ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); @@ -206,6 +193,45 @@ static acpi_status acpi_tb_load_namespace(void) return_ACPI_STATUS(status); } +/******************************************************************************* + * + * FUNCTION: acpi_install_table + * + * PARAMETERS: address - Address of the ACPI table to be installed. + * physical - Whether the address is a physical table + * address or not + * + * RETURN: Status + * + * DESCRIPTION: Dynamically install an ACPI table. + * Note: This function should only be invoked after + * acpi_initialize_tables() and before acpi_load_tables(). + * + ******************************************************************************/ + +acpi_status __init +acpi_install_table(acpi_physical_address address, u8 physical) +{ + acpi_status status; + u8 flags; + u32 table_index; + + ACPI_FUNCTION_TRACE(acpi_install_table); + + if (physical) { + flags = ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL; + } else { + flags = ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL; + } + + status = acpi_tb_install_standard_table(address, flags, + FALSE, FALSE, &table_index); + + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL_INIT(acpi_install_table) + /******************************************************************************* * * FUNCTION: acpi_load_table @@ -222,11 +248,9 @@ static acpi_status acpi_tb_load_namespace(void) * to ensure that the table is not deleted or unmapped. * ******************************************************************************/ - acpi_status acpi_load_table(struct acpi_table_header *table) { acpi_status status; - struct acpi_table_desc table_desc; u32 table_index; ACPI_FUNCTION_TRACE(acpi_load_table); @@ -237,14 +261,6 @@ acpi_status acpi_load_table(struct acpi_table_header *table) return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Init local table descriptor */ - - ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc)); - table_desc.address = ACPI_PTR_TO_PHYSADDR(table); - table_desc.pointer = table; - table_desc.length = table->length; - table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN; - /* Must acquire the interpreter lock during this operation */ status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); @@ -255,7 +271,24 @@ acpi_status acpi_load_table(struct acpi_table_header *table) /* Install the table and load it into the namespace */ ACPI_INFO((AE_INFO, "Host-directed Dynamic ACPI Table Load:")); - status = acpi_tb_add_table(&table_desc, &table_index); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + + status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table), + ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, + TRUE, FALSE, &table_index); + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + if (ACPI_FAILURE(status)) { + goto unlock_and_exit; + } + + /* + * Note: Now table is "INSTALLED", it must be validated before + * using. + */ + status = + acpi_tb_validate_table(&acpi_gbl_root_table_list. + tables[table_index]); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index fbfa9eca011f84..90ec37c473c617 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -462,7 +462,7 @@ char *acpi_ut_get_mutex_name(u32 mutex_id) /* Names for Notify() values, used for debug output */ -static const char *acpi_gbl_notify_value_names[ACPI_NOTIFY_MAX + 1] = { +static const char *acpi_gbl_generic_notify[ACPI_NOTIFY_MAX + 1] = { /* 00 */ "Bus Check", /* 01 */ "Device Check", /* 02 */ "Device Wake", @@ -473,23 +473,75 @@ static const char *acpi_gbl_notify_value_names[ACPI_NOTIFY_MAX + 1] = { /* 07 */ "Power Fault", /* 08 */ "Capabilities Check", /* 09 */ "Device PLD Check", - /* 10 */ "Reserved", - /* 11 */ "System Locality Update", - /* 12 */ "Shutdown Request" + /* 0A */ "Reserved", + /* 0B */ "System Locality Update", + /* 0C */ "Shutdown Request" }; -const char *acpi_ut_get_notify_name(u32 notify_value) +static const char *acpi_gbl_device_notify[4] = { + /* 80 */ "Status Change", + /* 81 */ "Information Change", + /* 82 */ "Device-Specific Change", + /* 83 */ "Device-Specific Change" +}; + +static const char *acpi_gbl_processor_notify[4] = { + /* 80 */ "Performance Capability Change", + /* 81 */ "C-State Change", + /* 82 */ "Throttling Capability Change", + /* 83 */ "Device-Specific Change" +}; + +static const char *acpi_gbl_thermal_notify[4] = { + /* 80 */ "Thermal Status Change", + /* 81 */ "Thermal Trip Point Change", + /* 82 */ "Thermal Device List Change", + /* 83 */ "Thermal Relationship Change" +}; + +const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type) { + /* 00 - 0C are common to all object types */ + if (notify_value <= ACPI_NOTIFY_MAX) { - return (acpi_gbl_notify_value_names[notify_value]); - } else if (notify_value <= ACPI_MAX_SYS_NOTIFY) { + return (acpi_gbl_generic_notify[notify_value]); + } + + /* 0D - 7F are reserved */ + + if (notify_value <= ACPI_MAX_SYS_NOTIFY) { return ("Reserved"); - } else if (notify_value <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) { - return ("Device Specific"); - } else { - return ("Hardware Specific"); } + + /* 80 - 83 are per-object-type */ + + if (notify_value <= 0x83) { + switch (type) { + case ACPI_TYPE_ANY: + case ACPI_TYPE_DEVICE: + return (acpi_gbl_device_notify[notify_value - 0x80]); + + case ACPI_TYPE_PROCESSOR: + return (acpi_gbl_processor_notify[notify_value - 0x80]); + + case ACPI_TYPE_THERMAL: + return (acpi_gbl_thermal_notify[notify_value - 0x80]); + + default: + return ("Target object type does not support notifies"); + } + } + + /* 84 - BF are device-specific */ + + if (notify_value <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) { + return ("Device-Specific"); + } + + /* C0 and above are hardware-specific */ + + return ("Hardware-Specific"); } #endif diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index f3abeae9d2f87b..d69be3cb3faebc 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -55,28 +55,7 @@ ACPI_MODULE_NAME("utglobal") * Static global variable initialization. * ******************************************************************************/ -/* Debug output control masks */ -u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT; - -u32 acpi_dbg_layer = 0; - -/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */ - -struct acpi_table_fadt acpi_gbl_FADT; -u32 acpi_gbl_trace_flags; -acpi_name acpi_gbl_trace_method_name; -u8 acpi_gbl_system_awake_and_running; -u32 acpi_current_gpe_count; - -/* - * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning - * that the ACPI hardware is no longer required. A flag in the FADT indicates - * a reduced HW machine, and that flag is duplicated here for convenience. - */ -u8 acpi_gbl_reduced_hardware; - /* Various state name strings */ - const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = { "\\_S0_", "\\_S1_", @@ -337,7 +316,6 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_acpi_hardware_present = TRUE; acpi_gbl_last_owner_id_index = 0; acpi_gbl_next_owner_id_offset = 0; - acpi_gbl_trace_method_name = 0; acpi_gbl_trace_dbg_level = 0; acpi_gbl_trace_dbg_layer = 0; acpi_gbl_debugger_configuration = DEBUGGER_THREADING; @@ -377,9 +355,7 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_disable_mem_tracking = FALSE; #endif -#ifdef ACPI_DEBUGGER - acpi_gbl_db_terminate_threads = FALSE; -#endif + ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = FALSE); return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index 77219336c7e01f..6dc54b3c28b07e 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -353,7 +353,7 @@ void acpi_ut_print_string(char *string, u16 max_length) } acpi_os_printf("\""); - for (i = 0; string[i] && (i < max_length); i++) { + for (i = 0; (i < max_length) && string[i]; i++) { /* Escape sequences */ diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index edd861102f1bf0..88ef77f3cf88d1 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -53,6 +53,7 @@ ACPI_MODULE_NAME("utxferror") * This module is used for the in-kernel ACPICA as well as the ACPICA * tools/applications. */ +#ifndef ACPI_NO_ERROR_MESSAGES /* Entire module */ /******************************************************************************* * * FUNCTION: acpi_error @@ -249,3 +250,4 @@ acpi_bios_warning(const char *module_name, } ACPI_EXPORT_SYMBOL(acpi_bios_warning) +#endif /* ACPI_NO_ERROR_MESSAGES */ diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 9a2c63b2005038..6e7b2a12860d31 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -36,6 +36,12 @@ #include #include +#ifdef CONFIG_ACPI_PROCFS_POWER +#include +#include +#include +#endif + #include #include @@ -64,6 +70,19 @@ static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); +#ifdef CONFIG_ACPI_PROCFS_POWER +extern struct proc_dir_entry *acpi_lock_battery_dir(void); +extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); + +enum acpi_battery_files { + info_tag = 0, + state_tag, + alarm_tag, + ACPI_BATTERY_NUMFILES, +}; + +#endif + static const struct acpi_device_id battery_device_ids[] = { {"PNP0C0A", 0}, {"", 0}, @@ -299,6 +318,14 @@ static enum power_supply_property energy_battery_props[] = { POWER_SUPPLY_PROP_SERIAL_NUMBER, }; +#ifdef CONFIG_ACPI_PROCFS_POWER +inline char *acpi_battery_units(struct acpi_battery *battery) +{ + return (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) ? + "mA" : "mW"; +} +#endif + /* -------------------------------------------------------------------------- Battery Management -------------------------------------------------------------------------- */ @@ -716,6 +743,279 @@ static void acpi_battery_refresh(struct acpi_battery *battery) sysfs_add_battery(battery); } +/* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ + +#ifdef CONFIG_ACPI_PROCFS_POWER +static struct proc_dir_entry *acpi_battery_dir; + +static int acpi_battery_print_info(struct seq_file *seq, int result) +{ + struct acpi_battery *battery = seq->private; + + if (result) + goto end; + + seq_printf(seq, "present: %s\n", + acpi_battery_present(battery) ? "yes" : "no"); + if (!acpi_battery_present(battery)) + goto end; + if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + seq_printf(seq, "design capacity: unknown\n"); + else + seq_printf(seq, "design capacity: %d %sh\n", + battery->design_capacity, + acpi_battery_units(battery)); + + if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + seq_printf(seq, "last full capacity: unknown\n"); + else + seq_printf(seq, "last full capacity: %d %sh\n", + battery->full_charge_capacity, + acpi_battery_units(battery)); + + seq_printf(seq, "battery technology: %srechargeable\n", + (!battery->technology)?"non-":""); + + if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) + seq_printf(seq, "design voltage: unknown\n"); + else + seq_printf(seq, "design voltage: %d mV\n", + battery->design_voltage); + seq_printf(seq, "design capacity warning: %d %sh\n", + battery->design_capacity_warning, + acpi_battery_units(battery)); + seq_printf(seq, "design capacity low: %d %sh\n", + battery->design_capacity_low, + acpi_battery_units(battery)); + seq_printf(seq, "cycle count: %i\n", battery->cycle_count); + seq_printf(seq, "capacity granularity 1: %d %sh\n", + battery->capacity_granularity_1, + acpi_battery_units(battery)); + seq_printf(seq, "capacity granularity 2: %d %sh\n", + battery->capacity_granularity_2, + acpi_battery_units(battery)); + seq_printf(seq, "model number: %s\n", battery->model_number); + seq_printf(seq, "serial number: %s\n", battery->serial_number); + seq_printf(seq, "battery type: %s\n", battery->type); + seq_printf(seq, "OEM info: %s\n", battery->oem_info); + end: + if (result) + seq_printf(seq, "ERROR: Unable to read battery info\n"); + return result; +} + +static int acpi_battery_print_state(struct seq_file *seq, int result) +{ + struct acpi_battery *battery = seq->private; + + if (result) + goto end; + + seq_printf(seq, "present: %s\n", + acpi_battery_present(battery) ? "yes" : "no"); + if (!acpi_battery_present(battery)) + goto end; + + seq_printf(seq, "capacity state: %s\n", + (battery->state & 0x04) ? "critical" : "ok"); + if ((battery->state & 0x01) && (battery->state & 0x02)) + seq_printf(seq, + "charging state: charging/discharging\n"); + else if (battery->state & 0x01) + seq_printf(seq, "charging state: discharging\n"); + else if (battery->state & 0x02) + seq_printf(seq, "charging state: charging\n"); + else + seq_printf(seq, "charging state: charged\n"); + + if (battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN) + seq_printf(seq, "present rate: unknown\n"); + else + seq_printf(seq, "present rate: %d %s\n", + battery->rate_now, acpi_battery_units(battery)); + + if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN) + seq_printf(seq, "remaining capacity: unknown\n"); + else + seq_printf(seq, "remaining capacity: %d %sh\n", + battery->capacity_now, acpi_battery_units(battery)); + if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN) + seq_printf(seq, "present voltage: unknown\n"); + else + seq_printf(seq, "present voltage: %d mV\n", + battery->voltage_now); + end: + if (result) + seq_printf(seq, "ERROR: Unable to read battery state\n"); + + return result; +} + +static int acpi_battery_print_alarm(struct seq_file *seq, int result) +{ + struct acpi_battery *battery = seq->private; + + if (result) + goto end; + + if (!acpi_battery_present(battery)) { + seq_printf(seq, "present: no\n"); + goto end; + } + seq_printf(seq, "alarm: "); + if (!battery->alarm) + seq_printf(seq, "unsupported\n"); + else + seq_printf(seq, "%u %sh\n", battery->alarm, + acpi_battery_units(battery)); + end: + if (result) + seq_printf(seq, "ERROR: Unable to read battery alarm\n"); + return result; +} + +static ssize_t acpi_battery_write_alarm(struct file *file, + const char __user * buffer, + size_t count, loff_t * ppos) +{ + int result = 0; + char alarm_string[12] = { '\0' }; + struct seq_file *m = file->private_data; + struct acpi_battery *battery = m->private; + + if (!battery || (count > sizeof(alarm_string) - 1)) + return -EINVAL; + if (!acpi_battery_present(battery)) { + result = -ENODEV; + goto end; + } + if (copy_from_user(alarm_string, buffer, count)) { + result = -EFAULT; + goto end; + } + alarm_string[count] = '\0'; + battery->alarm = simple_strtol(alarm_string, NULL, 0); + result = acpi_battery_set_alarm(battery); + end: + if (!result) + return count; + return result; +} + +typedef int(*print_func)(struct seq_file *seq, int result); + +static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = { + acpi_battery_print_info, + acpi_battery_print_state, + acpi_battery_print_alarm, +}; + +static int acpi_battery_read(int fid, struct seq_file *seq) +{ + struct acpi_battery *battery = seq->private; + int result = acpi_battery_update(battery); + return acpi_print_funcs[fid](seq, result); +} + +#define DECLARE_FILE_FUNCTIONS(_name) \ +static int acpi_battery_read_##_name(struct seq_file *seq, void *offset) \ +{ \ + return acpi_battery_read(_name##_tag, seq); \ +} \ +static int acpi_battery_##_name##_open_fs(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, acpi_battery_read_##_name, PDE_DATA(inode)); \ +} + +DECLARE_FILE_FUNCTIONS(info); +DECLARE_FILE_FUNCTIONS(state); +DECLARE_FILE_FUNCTIONS(alarm); + +#undef DECLARE_FILE_FUNCTIONS + +#define FILE_DESCRIPTION_RO(_name) \ + { \ + .name = __stringify(_name), \ + .mode = S_IRUGO, \ + .ops = { \ + .open = acpi_battery_##_name##_open_fs, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ + .owner = THIS_MODULE, \ + }, \ + } + +#define FILE_DESCRIPTION_RW(_name) \ + { \ + .name = __stringify(_name), \ + .mode = S_IFREG | S_IRUGO | S_IWUSR, \ + .ops = { \ + .open = acpi_battery_##_name##_open_fs, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .write = acpi_battery_write_##_name, \ + .release = single_release, \ + .owner = THIS_MODULE, \ + }, \ + } + +static const struct battery_file { + struct file_operations ops; + umode_t mode; + const char *name; +} acpi_battery_file[] = { + FILE_DESCRIPTION_RO(info), + FILE_DESCRIPTION_RO(state), + FILE_DESCRIPTION_RW(alarm), +}; + +#undef FILE_DESCRIPTION_RO +#undef FILE_DESCRIPTION_RW + +static int acpi_battery_add_fs(struct acpi_device *device) +{ + struct proc_dir_entry *entry = NULL; + int i; + + printk(KERN_WARNING PREFIX "Deprecated procfs I/F for battery is loaded," + " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n"); + if (!acpi_device_dir(device)) { + acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), + acpi_battery_dir); + if (!acpi_device_dir(device)) + return -ENODEV; + } + + for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { + entry = proc_create_data(acpi_battery_file[i].name, + acpi_battery_file[i].mode, + acpi_device_dir(device), + &acpi_battery_file[i].ops, + acpi_driver_data(device)); + if (!entry) + return -ENODEV; + } + return 0; +} + +static void acpi_battery_remove_fs(struct acpi_device *device) +{ + int i; + if (!acpi_device_dir(device)) + return; + for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) + remove_proc_entry(acpi_battery_file[i].name, + acpi_device_dir(device)); + + remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); + acpi_device_dir(device) = NULL; +} + +#endif + /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ @@ -790,6 +1090,15 @@ static int acpi_battery_add(struct acpi_device *device) result = acpi_battery_update(battery); if (result) goto fail; +#ifdef CONFIG_ACPI_PROCFS_POWER + result = acpi_battery_add_fs(device); +#endif + if (result) { +#ifdef CONFIG_ACPI_PROCFS_POWER + acpi_battery_remove_fs(device); +#endif + goto fail; + } printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), @@ -816,6 +1125,9 @@ static int acpi_battery_remove(struct acpi_device *device) return -EINVAL; battery = acpi_driver_data(device); unregister_pm_notifier(&battery->pm_nb); +#ifdef CONFIG_ACPI_PROCFS_POWER + acpi_battery_remove_fs(device); +#endif sysfs_remove_battery(battery); mutex_destroy(&battery->lock); mutex_destroy(&battery->sysfs_lock); @@ -866,7 +1178,19 @@ static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) if (dmi_check_system(bat_dmi_table)) battery_bix_broken_package = 1; - acpi_bus_register_driver(&acpi_battery_driver); + +#ifdef CONFIG_ACPI_PROCFS_POWER + acpi_battery_dir = acpi_lock_battery_dir(); + if (!acpi_battery_dir) + return; +#endif + if (acpi_bus_register_driver(&acpi_battery_driver) < 0) { +#ifdef CONFIG_ACPI_PROCFS_POWER + acpi_unlock_battery_dir(acpi_battery_dir); +#endif + return; + } + return; } static int __init acpi_battery_init(void) @@ -878,6 +1202,9 @@ static int __init acpi_battery_init(void) static void __exit acpi_battery_exit(void) { acpi_bus_unregister_driver(&acpi_battery_driver); +#ifdef CONFIG_ACPI_PROCFS_POWER + acpi_unlock_battery_dir(acpi_battery_dir); +#endif } module_init(acpi_battery_init); diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index afec4526c48aa0..3d8413d02a975f 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -314,6 +314,14 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_VERSION, "2349D15"), }, }, + { + .callback = dmi_disable_osi_win8, + .ident = "Dell Inspiron 7737", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7737"), + }, + }, /* * BIOS invocation of _OSI(Linux) is almost always a BIOS bug. @@ -374,6 +382,19 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T500"), }, }, + /* + * Without this this EEEpc exports a non working WMI interface, with + * this it exports a working "good old" eeepc_laptop interface, fixing + * both brightness control, and rfkill not working. + */ + { + .callback = dmi_enable_osi_linux, + .ident = "Asus EEE PC 1015PX", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "1015PX"), + }, + }, {} }; diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index cf925c4f36b70e..610261a1b6c86d 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -340,16 +340,18 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { struct acpi_device *adev; struct acpi_driver *driver; - acpi_status status; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; + bool hotplug_event = false; switch (type) { case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); + hotplug_event = true; break; case ACPI_NOTIFY_DEVICE_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); + hotplug_event = true; break; case ACPI_NOTIFY_DEVICE_WAKE: @@ -358,6 +360,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); + hotplug_event = true; break; case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: @@ -393,16 +396,9 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) driver->ops.notify(adev, type); - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - case ACPI_NOTIFY_EJECT_REQUEST: - status = acpi_hotplug_schedule(adev, type); - if (ACPI_SUCCESS(status)) - return; - default: - break; - } + if (hotplug_event && ACPI_SUCCESS(acpi_hotplug_schedule(adev, type))) + return; + acpi_bus_put_acpi_device(adev); return; diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c new file mode 100644 index 00000000000000..6c9ee68e46fb0a --- /dev/null +++ b/drivers/acpi/cm_sbs.c @@ -0,0 +1,105 @@ +/* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 + +#define PREFIX "ACPI: " + +ACPI_MODULE_NAME("cm_sbs"); +#define ACPI_AC_CLASS "ac_adapter" +#define ACPI_BATTERY_CLASS "battery" +#define _COMPONENT ACPI_SBS_COMPONENT +static struct proc_dir_entry *acpi_ac_dir; +static struct proc_dir_entry *acpi_battery_dir; + +static DEFINE_MUTEX(cm_sbs_mutex); + +static int lock_ac_dir_cnt; +static int lock_battery_dir_cnt; + +struct proc_dir_entry *acpi_lock_ac_dir(void) +{ + mutex_lock(&cm_sbs_mutex); + if (!acpi_ac_dir) + acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir); + if (acpi_ac_dir) { + lock_ac_dir_cnt++; + } else { + printk(KERN_ERR PREFIX + "Cannot create %s\n", ACPI_AC_CLASS); + } + mutex_unlock(&cm_sbs_mutex); + return acpi_ac_dir; +} +EXPORT_SYMBOL(acpi_lock_ac_dir); + +void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir_param) +{ + mutex_lock(&cm_sbs_mutex); + if (acpi_ac_dir_param) + lock_ac_dir_cnt--; + if (lock_ac_dir_cnt == 0 && acpi_ac_dir_param && acpi_ac_dir) { + remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir); + acpi_ac_dir = NULL; + } + mutex_unlock(&cm_sbs_mutex); +} +EXPORT_SYMBOL(acpi_unlock_ac_dir); + +struct proc_dir_entry *acpi_lock_battery_dir(void) +{ + mutex_lock(&cm_sbs_mutex); + if (!acpi_battery_dir) { + acpi_battery_dir = + proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir); + } + if (acpi_battery_dir) { + lock_battery_dir_cnt++; + } else { + printk(KERN_ERR PREFIX + "Cannot create %s\n", ACPI_BATTERY_CLASS); + } + mutex_unlock(&cm_sbs_mutex); + return acpi_battery_dir; +} +EXPORT_SYMBOL(acpi_lock_battery_dir); + +void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir_param) +{ + mutex_lock(&cm_sbs_mutex); + if (acpi_battery_dir_param) + lock_battery_dir_cnt--; + if (lock_battery_dir_cnt == 0 && acpi_battery_dir_param + && acpi_battery_dir) { + remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir); + acpi_battery_dir = NULL; + } + mutex_unlock(&cm_sbs_mutex); + return; +} +EXPORT_SYMBOL(acpi_unlock_battery_dir); diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 6776c599816f33..9aeae41e22fbe1 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1770,16 +1770,15 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) } #endif -static int __init acpi_no_auto_ssdt_setup(char *s) +static int __init acpi_no_static_ssdt_setup(char *s) { - printk(KERN_NOTICE PREFIX "SSDT auto-load disabled\n"); + acpi_gbl_disable_ssdt_table_install = TRUE; + pr_info("ACPI: static SSDT installation disabled\n"); - acpi_gbl_disable_ssdt_table_load = TRUE; - - return 1; + return 0; } -__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup); +early_param("acpi_no_static_ssdt", acpi_no_static_ssdt_setup); static int __init acpi_disable_return_repair(char *s) { diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7efe546a8c4270..db5fc6f9628ebc 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2259,12 +2259,16 @@ int __init acpi_scan_init(void) if (result) goto out; - result = acpi_bus_scan_fixed(); - if (result) { - acpi_detach_data(acpi_root->handle, acpi_scan_drop_device); - acpi_device_del(acpi_root); - put_device(&acpi_root->dev); - goto out; + /* Fixed feature devices do not exist on HW-reduced platform */ + if (!acpi_gbl_reduced_hardware) { + result = acpi_bus_scan_fixed(); + if (result) { + acpi_detach_data(acpi_root->handle, + acpi_scan_drop_device); + acpi_device_del(acpi_root); + put_device(&acpi_root->dev); + goto out; + } } acpi_update_all_gpes(); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 8b6990e417ec87..fced27d8e42f9f 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -68,7 +68,7 @@ MODULE_AUTHOR("Bruno Ducrot"); MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_LICENSE("GPL"); -static bool brightness_switch_enabled = 1; +static bool brightness_switch_enabled; module_param(brightness_switch_enabled, bool, 0644); /* @@ -457,10 +457,10 @@ static struct dmi_system_id video_dmi_table[] __initdata = { }, { .callback = video_set_use_native_backlight, - .ident = "ThinkPad T430s", + .ident = "ThinkPad T430 and T430s", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430s"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430"), }, }, { @@ -471,6 +471,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"), }, }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad T530", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T530"), + }, + }, { .callback = video_set_use_native_backlight, .ident = "ThinkPad X1 Carbon", @@ -511,6 +519,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5733Z"), }, }, + { + .callback = video_set_use_native_backlight, + .ident = "Acer Aspire 5742G", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5742G"), + }, + }, { .callback = video_set_use_native_backlight, .ident = "Acer Aspire V5-431", diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index c2706047337f17..7671dbac6015e5 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -123,6 +123,15 @@ config AHCI_IMX If unsure, say N. +config AHCI_MVEBU + tristate "Marvell EBU AHCI SATA support" + depends on ARCH_MVEBU + help + This option enables support for the Marvebu EBU SoC's + onboard AHCI SATA. + + If unsure, say N. + config AHCI_SUNXI tristate "Allwinner sunxi AHCI SATA support" depends on ARCH_SUNXI @@ -815,7 +824,7 @@ config PATA_AT32 config PATA_AT91 tristate "PATA support for AT91SAM9260" - depends on ARM && ARCH_AT91 + depends on ARM && SOC_AT91SAM9 help This option enables support for IDE devices on the Atmel AT91SAM9260 SoC. diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 44c8016e565c9b..5a02aeecef5b54 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o +obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 71e15b73513d22..60707814a84b19 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1115,6 +1115,17 @@ static bool ahci_broken_online(struct pci_dev *pdev) return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff); } +static bool ahci_broken_devslp(struct pci_dev *pdev) +{ + /* device with broken DEVSLP but still showing SDS capability */ + static const struct pci_device_id ids[] = { + { PCI_VDEVICE(INTEL, 0x0f23)}, /* Valleyview SoC */ + {} + }; + + return pci_match_id(ids, pdev); +} + #ifdef CONFIG_ATA_ACPI static void ahci_gtf_filter_workaround(struct ata_host *host) { @@ -1364,6 +1375,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar]; + /* must set flag prior to save config in order to take effect */ + if (ahci_broken_devslp(pdev)) + hpriv->flags |= AHCI_HFLAG_NO_DEVSLP; + /* save initial config */ ahci_pci_save_initial_config(pdev, hpriv); diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index b5eb886da22635..af63c75c20011e 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -236,6 +236,7 @@ enum { port start (wait until error-handling stage) */ AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */ + AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */ /* ap->flags bits */ diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 497c7abe1c7df5..5824d99e63fda9 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -29,9 +29,25 @@ #include "ahci.h" enum { - PORT_PHY_CTL = 0x178, /* Port0 PHY Control */ - PORT_PHY_CTL_PDDQ_LOC = 0x100000, /* PORT_PHY_CTL bits */ - HOST_TIMER1MS = 0xe0, /* Timer 1-ms */ + /* Timer 1-ms Register */ + IMX_TIMER1MS = 0x00e0, + /* Port0 PHY Control Register */ + IMX_P0PHYCR = 0x0178, + IMX_P0PHYCR_TEST_PDDQ = 1 << 20, + IMX_P0PHYCR_CR_READ = 1 << 19, + IMX_P0PHYCR_CR_WRITE = 1 << 18, + IMX_P0PHYCR_CR_CAP_DATA = 1 << 17, + IMX_P0PHYCR_CR_CAP_ADDR = 1 << 16, + /* Port0 PHY Status Register */ + IMX_P0PHYSR = 0x017c, + IMX_P0PHYSR_CR_ACK = 1 << 18, + IMX_P0PHYSR_CR_DATA_OUT = 0xffff << 0, + /* Lane0 Output Status Register */ + IMX_LANE0_OUT_STAT = 0x2003, + IMX_LANE0_OUT_STAT_RX_PLL_STATE = 1 << 1, + /* Clock Reset Register */ + IMX_CLOCK_RESET = 0x7f3f, + IMX_CLOCK_RESET_RESET = 1 << 0, }; enum ahci_imx_type { @@ -54,9 +70,149 @@ MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support static void ahci_imx_host_stop(struct ata_host *host); +static int imx_phy_crbit_assert(void __iomem *mmio, u32 bit, bool assert) +{ + int timeout = 10; + u32 crval; + u32 srval; + + /* Assert or deassert the bit */ + crval = readl(mmio + IMX_P0PHYCR); + if (assert) + crval |= bit; + else + crval &= ~bit; + writel(crval, mmio + IMX_P0PHYCR); + + /* Wait for the cr_ack signal */ + do { + srval = readl(mmio + IMX_P0PHYSR); + if ((assert ? srval : ~srval) & IMX_P0PHYSR_CR_ACK) + break; + usleep_range(100, 200); + } while (--timeout); + + return timeout ? 0 : -ETIMEDOUT; +} + +static int imx_phy_reg_addressing(u16 addr, void __iomem *mmio) +{ + u32 crval = addr; + int ret; + + /* Supply the address on cr_data_in */ + writel(crval, mmio + IMX_P0PHYCR); + + /* Assert the cr_cap_addr signal */ + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, true); + if (ret) + return ret; + + /* Deassert cr_cap_addr */ + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, false); + if (ret) + return ret; + + return 0; +} + +static int imx_phy_reg_write(u16 val, void __iomem *mmio) +{ + u32 crval = val; + int ret; + + /* Supply the data on cr_data_in */ + writel(crval, mmio + IMX_P0PHYCR); + + /* Assert the cr_cap_data signal */ + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, true); + if (ret) + return ret; + + /* Deassert cr_cap_data */ + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, false); + if (ret) + return ret; + + if (val & IMX_CLOCK_RESET_RESET) { + /* + * In case we're resetting the phy, it's unable to acknowledge, + * so we return immediately here. + */ + crval |= IMX_P0PHYCR_CR_WRITE; + writel(crval, mmio + IMX_P0PHYCR); + goto out; + } + + /* Assert the cr_write signal */ + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, true); + if (ret) + return ret; + + /* Deassert cr_write */ + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, false); + if (ret) + return ret; + +out: + return 0; +} + +static int imx_phy_reg_read(u16 *val, void __iomem *mmio) +{ + int ret; + + /* Assert the cr_read signal */ + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, true); + if (ret) + return ret; + + /* Capture the data from cr_data_out[] */ + *val = readl(mmio + IMX_P0PHYSR) & IMX_P0PHYSR_CR_DATA_OUT; + + /* Deassert cr_read */ + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, false); + if (ret) + return ret; + + return 0; +} + +static int imx_sata_phy_reset(struct ahci_host_priv *hpriv) +{ + void __iomem *mmio = hpriv->mmio; + int timeout = 10; + u16 val; + int ret; + + /* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */ + ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio); + if (ret) + return ret; + ret = imx_phy_reg_write(IMX_CLOCK_RESET_RESET, mmio); + if (ret) + return ret; + + /* Wait for PHY RX_PLL to be stable */ + do { + usleep_range(100, 200); + ret = imx_phy_reg_addressing(IMX_LANE0_OUT_STAT, mmio); + if (ret) + return ret; + ret = imx_phy_reg_read(&val, mmio); + if (ret) + return ret; + if (val & IMX_LANE0_OUT_STAT_RX_PLL_STATE) + break; + } while (--timeout); + + return timeout ? 0 : -ETIMEDOUT; +} + static int imx_sata_enable(struct ahci_host_priv *hpriv) { struct imx_ahci_priv *imxpriv = hpriv->plat_data; + struct device *dev = &imxpriv->ahci_pdev->dev; int ret; if (imxpriv->no_device) @@ -101,6 +257,12 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, IMX6Q_GPR13_SATA_MPLL_CLK_EN, IMX6Q_GPR13_SATA_MPLL_CLK_EN); + + ret = imx_sata_phy_reset(hpriv); + if (ret) { + dev_err(dev, "failed to reset phy: %d\n", ret); + goto disable_regulator; + } } usleep_range(1000, 2000); @@ -156,8 +318,8 @@ static void ahci_imx_error_handler(struct ata_port *ap) * without full reset once the pddq mode is enabled making it * impossible to use as part of libata LPM. */ - reg_val = readl(mmio + PORT_PHY_CTL); - writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL); + reg_val = readl(mmio + IMX_P0PHYCR); + writel(reg_val | IMX_P0PHYCR_TEST_PDDQ, mmio + IMX_P0PHYCR); imx_sata_disable(hpriv); imxpriv->no_device = true; } @@ -217,6 +379,7 @@ static int imx_ahci_probe(struct platform_device *pdev) if (!imxpriv) return -ENOMEM; + imxpriv->ahci_pdev = pdev; imxpriv->no_device = false; imxpriv->first_time = true; imxpriv->type = (enum ahci_imx_type)of_id->data; @@ -248,7 +411,7 @@ static int imx_ahci_probe(struct platform_device *pdev) /* * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, - * and IP vendor specific register HOST_TIMER1MS. + * and IP vendor specific register IMX_TIMER1MS. * Configure CAP_SSS (support stagered spin up). * Implement the port0. * Get the ahb clock rate, and configure the TIMER1MS register. @@ -265,7 +428,7 @@ static int imx_ahci_probe(struct platform_device *pdev) } reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; - writel(reg_val, hpriv->mmio + HOST_TIMER1MS); + writel(reg_val, hpriv->mmio + IMX_TIMER1MS); ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0); if (ret) diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c new file mode 100644 index 00000000000000..1df8630c6b6522 --- /dev/null +++ b/drivers/ata/ahci_mvebu.c @@ -0,0 +1,127 @@ +/* + * AHCI glue platform driver for Marvell EBU SOCs + * + * Copyright (C) 2014 Marvell + * + * Thomas Petazzoni + * Marcin Wojtas + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include "ahci.h" + +#define AHCI_VENDOR_SPECIFIC_0_ADDR 0xa0 +#define AHCI_VENDOR_SPECIFIC_0_DATA 0xa4 + +#define AHCI_WINDOW_CTRL(win) (0x60 + ((win) << 4)) +#define AHCI_WINDOW_BASE(win) (0x64 + ((win) << 4)) +#define AHCI_WINDOW_SIZE(win) (0x68 + ((win) << 4)) + +static void ahci_mvebu_mbus_config(struct ahci_host_priv *hpriv, + const struct mbus_dram_target_info *dram) +{ + int i; + + for (i = 0; i < 4; i++) { + writel(0, hpriv->mmio + AHCI_WINDOW_CTRL(i)); + writel(0, hpriv->mmio + AHCI_WINDOW_BASE(i)); + writel(0, hpriv->mmio + AHCI_WINDOW_SIZE(i)); + } + + for (i = 0; i < dram->num_cs; i++) { + const struct mbus_dram_window *cs = dram->cs + i; + + writel((cs->mbus_attr << 8) | + (dram->mbus_dram_target_id << 4) | 1, + hpriv->mmio + AHCI_WINDOW_CTRL(i)); + writel(cs->base, hpriv->mmio + AHCI_WINDOW_BASE(i)); + writel(((cs->size - 1) & 0xffff0000), + hpriv->mmio + AHCI_WINDOW_SIZE(i)); + } +} + +static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv) +{ + /* + * Enable the regret bit to allow the SATA unit to regret a + * request that didn't receive an acknowlegde and avoid a + * deadlock + */ + writel(0x4, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_ADDR); + writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA); +} + +static const struct ata_port_info ahci_mvebu_port_info = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_platform_ops, +}; + +static int ahci_mvebu_probe(struct platform_device *pdev) +{ + struct ahci_host_priv *hpriv; + const struct mbus_dram_target_info *dram; + int rc; + + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + + rc = ahci_platform_enable_resources(hpriv); + if (rc) + return rc; + + dram = mv_mbus_dram_info(); + if (!dram) + return -ENODEV; + + ahci_mvebu_mbus_config(hpriv, dram); + ahci_mvebu_regret_option(hpriv); + + rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info, 0, 0); + if (rc) + goto disable_resources; + + return 0; + +disable_resources: + ahci_platform_disable_resources(hpriv); + return rc; +} + +static const struct of_device_id ahci_mvebu_of_match[] = { + { .compatible = "marvell,armada-380-ahci", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match); + +/* + * We currently don't provide power management related operations, + * since there is no suspend/resume support at the platform level for + * Armada 38x for the moment. + */ +static struct platform_driver ahci_mvebu_driver = { + .probe = ahci_mvebu_probe, + .remove = ata_platform_remove_one, + .driver = { + .name = "ahci-mvebu", + .owner = THIS_MODULE, + .of_match_table = ahci_mvebu_of_match, + }, +}; +module_platform_driver(ahci_mvebu_driver); + +MODULE_DESCRIPTION("Marvell EBU AHCI SATA driver"); +MODULE_AUTHOR("Thomas Petazzoni , Marcin Wojtas "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ahci_mvebu"); diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 6bd4f660b4e159..b9861453fc8148 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -452,6 +452,13 @@ void ahci_save_initial_config(struct device *dev, cap &= ~HOST_CAP_SNTF; } + if ((cap2 & HOST_CAP2_SDS) && (hpriv->flags & AHCI_HFLAG_NO_DEVSLP)) { + dev_info(dev, + "controller can't do DEVSLP, turning off\n"); + cap2 &= ~HOST_CAP2_SDS; + cap2 &= ~HOST_CAP2_SADM; + } + if (!(cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_YES_FBS)) { dev_info(dev, "controller can do FBS, turning on CAP_FBS\n"); cap |= HOST_CAP_FBS; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 943cc8b83e59bb..ea83828bfea94b 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6314,6 +6314,8 @@ int ata_host_activate(struct ata_host *host, int irq, static void ata_port_detach(struct ata_port *ap) { unsigned long flags; + struct ata_link *link; + struct ata_device *dev; if (!ap->ops->error_handler) goto skip_eh; @@ -6333,6 +6335,13 @@ static void ata_port_detach(struct ata_port *ap) cancel_delayed_work_sync(&ap->hotplug_task); skip_eh: + /* clean up zpodd on port removal */ + ata_for_each_link(link, ap, HOST_FIRST) { + ata_for_each_dev(dev, link, ALL) { + if (zpodd_dev_enabled(dev)) + zpodd_exit(dev); + } + } if (ap->pmp_link) { int i; for (i = 0; i < SATA_PMP_MAX_PORTS; i++) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index ef8567de6a7515..72691fd939483a 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1993,7 +1993,11 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) memcpy(rbuf, hdr, sizeof(hdr)); memcpy(&rbuf[8], "ATA ", 8); ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); - ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); + + /* From SAT, use last 2 words from fw rev unless they are spaces */ + ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV + 2, 4); + if (strncmp(&rbuf[32], " ", 4) == 0) + ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); if (rbuf[32] == 0 || rbuf[32] == ' ') memcpy(&rbuf[32], "n/a ", 4); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index b603720b877dd0..1121153f1ecde7 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2433,15 +2433,6 @@ int ata_pci_sff_activate_host(struct ata_host *host, mask = (1 << 2) | (1 << 0); if ((tmp8 & mask) != mask) legacy_mode = 1; -#if defined(CONFIG_NO_ATA_LEGACY) - /* Some platforms with PCI limits cannot address compat - port space. In that case we punt if their firmware has - left a device in compatibility mode */ - if (legacy_mode) { - printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); - return -EOPNOTSUPP; - } -#endif } if (!devres_open_group(dev, NULL, GFP_KERNEL)) diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index 83c4ddb1bc7f6e..2a97d3a531ece7 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -865,7 +865,7 @@ static int octeon_cf_probe(struct platform_device *pdev) if (node == NULL) return -EINVAL; - cf_port = kzalloc(sizeof(*cf_port), GFP_KERNEL); + cf_port = devm_kzalloc(&pdev->dev, sizeof(*cf_port), GFP_KERNEL); if (!cf_port) return -ENOMEM; @@ -881,10 +881,9 @@ static int octeon_cf_probe(struct platform_device *pdev) n_size = of_n_size_cells(node); reg_prop = of_find_property(node, "reg", ®_len); - if (!reg_prop || reg_len < sizeof(__be32)) { - rv = -EINVAL; - goto free_cf_port; - } + if (!reg_prop || reg_len < sizeof(__be32)) + return -EINVAL; + cs_num = reg_prop->value; cf_port->cs0 = be32_to_cpup(cs_num); @@ -901,16 +900,13 @@ static int octeon_cf_probe(struct platform_device *pdev) res_dma = platform_get_resource(dma_dev, IORESOURCE_MEM, 0); if (!res_dma) { of_node_put(dma_node); - rv = -EINVAL; - goto free_cf_port; + return -EINVAL; } cf_port->dma_base = (u64)devm_ioremap_nocache(&pdev->dev, res_dma->start, resource_size(res_dma)); - if (!cf_port->dma_base) { of_node_put(dma_node); - rv = -EINVAL; - goto free_cf_port; + return -EINVAL; } irq_handler = octeon_cf_interrupt; @@ -921,41 +917,34 @@ static int octeon_cf_probe(struct platform_device *pdev) of_node_put(dma_node); } res_cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res_cs1) { - rv = -EINVAL; - goto free_cf_port; - } + if (!res_cs1) + return -EINVAL; + cs1 = devm_ioremap_nocache(&pdev->dev, res_cs1->start, resource_size(res_cs1)); - if (!cs1) - goto free_cf_port; + return rv; + + if (reg_len < (n_addr + n_size + 1) * sizeof(__be32)) + return -EINVAL; - if (reg_len < (n_addr + n_size + 1) * sizeof(__be32)) { - rv = -EINVAL; - goto free_cf_port; - } cs_num += n_addr + n_size; cf_port->cs1 = be32_to_cpup(cs_num); } res_cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - if (!res_cs0) { - rv = -EINVAL; - goto free_cf_port; - } + if (!res_cs0) + return -EINVAL; cs0 = devm_ioremap_nocache(&pdev->dev, res_cs0->start, resource_size(res_cs0)); - if (!cs0) - goto free_cf_port; + return rv; /* allocate host */ host = ata_host_alloc(&pdev->dev, 1); if (!host) - goto free_cf_port; + return rv; ap = host->ports[0]; ap->private_data = cf_port; @@ -1020,17 +1009,12 @@ static int octeon_cf_probe(struct platform_device *pdev) ata_port_desc(ap, "cmd %p ctl %p", base, ap->ioaddr.ctl_addr); - dev_info(&pdev->dev, "version " DRV_VERSION" %d bit%s.\n", is_16bit ? 16 : 8, cf_port->is_true_ide ? ", True IDE" : ""); return ata_host_activate(host, irq, irq_handler, IRQF_SHARED, &octeon_cf_sht); - -free_cf_port: - kfree(cf_port); - return rv; } static void octeon_cf_shutdown(struct device *dev) diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 8fa8deab644924..4b7b4522b64f8c 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -1,10 +1,10 @@ menu "Generic Driver Options" -config UEVENT_HELPER_PATH - string "path to uevent helper" - default "" +config UEVENT_HELPER + bool "Support for uevent helper" + default y help - Path to uevent helper program forked by the kernel for + The uevent helper program is forked by the kernel for every uevent. Before the switch to the netlink-based uevent source, this was used to hook hotplug scripts into kernel device events. It @@ -15,8 +15,13 @@ config UEVENT_HELPER_PATH that it creates a high system load, or on smaller systems it is known to create out-of-memory situations during bootup. - To disable user space helper program execution at early boot - time specify an empty string here. This setting can be altered +config UEVENT_HELPER_PATH + string "path to uevent helper" + depends on UEVENT_HELPER + default "" + help + To disable user space helper program execution at by default + specify an empty string here. This setting can still be altered via /proc/sys/kernel/hotplug or via /sys/kernel/uevent_helper later at runtime. diff --git a/drivers/base/devres.c b/drivers/base/devres.c index db4e264eecb60c..d0914cba241383 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -831,3 +831,24 @@ void devm_kfree(struct device *dev, void *p) WARN_ON(rc); } EXPORT_SYMBOL_GPL(devm_kfree); + +/** + * devm_kmemdup - Resource-managed kmemdup + * @dev: Device this memory belongs to + * @src: Memory region to duplicate + * @len: Memory region length + * @gfp: GFP mask to use + * + * Duplicate region of a memory using resource managed kmalloc + */ +void *devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp) +{ + void *p; + + p = devm_kmalloc(dev, len, gfp); + if (p) + memcpy(p, src, len); + + return p; +} +EXPORT_SYMBOL_GPL(devm_kmemdup); diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index ea77701deda400..840c7fa80983de 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c @@ -491,7 +491,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kunmap); * dma-buf buffer. * * This function adjusts the passed in vma so that it points at the file of the - * dma_buf operation. It alsog adjusts the starting pgoff and does bounds + * dma_buf operation. It also adjusts the starting pgoff and does bounds * checking on the size of the vma. Then it calls the exporters mmap function to * set up the mapping. * diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index ae098a261fcdb2..eee55c1e5fde49 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -105,7 +105,7 @@ static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) static void genpd_sd_counter_inc(struct generic_pm_domain *genpd) { atomic_inc(&genpd->sd_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } static void genpd_acquire_lock(struct generic_pm_domain *genpd) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 25538675d59e29..d9e376a6d19d83 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -596,96 +595,6 @@ int dev_pm_opp_disable(struct device *dev, unsigned long freq) } EXPORT_SYMBOL_GPL(dev_pm_opp_disable); -#ifdef CONFIG_CPU_FREQ -/** - * dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device - * @dev: device for which we do this operation - * @table: Cpufreq table returned back to caller - * - * Generate a cpufreq table for a provided device- this assumes that the - * opp list is already initialized and ready for usage. - * - * This function allocates required memory for the cpufreq table. It is - * expected that the caller does the required maintenance such as freeing - * the table as required. - * - * Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM - * if no memory available for the operation (table is not populated), returns 0 - * if successful and table is populated. - * - * WARNING: It is important for the callers to ensure refreshing their copy of - * the table if any of the mentioned functions have been invoked in the interim. - * - * Locking: The internal device_opp and opp structures are RCU protected. - * To simplify the logic, we pretend we are updater and hold relevant mutex here - * Callers should ensure that this function is *NOT* called under RCU protection - * or in contexts where mutex locking cannot be used. - */ -int dev_pm_opp_init_cpufreq_table(struct device *dev, - struct cpufreq_frequency_table **table) -{ - struct device_opp *dev_opp; - struct dev_pm_opp *opp; - struct cpufreq_frequency_table *freq_table; - int i = 0; - - /* Pretend as if I am an updater */ - mutex_lock(&dev_opp_list_lock); - - dev_opp = find_device_opp(dev); - if (IS_ERR(dev_opp)) { - int r = PTR_ERR(dev_opp); - mutex_unlock(&dev_opp_list_lock); - dev_err(dev, "%s: Device OPP not found (%d)\n", __func__, r); - return r; - } - - freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) * - (dev_pm_opp_get_opp_count(dev) + 1), GFP_KERNEL); - if (!freq_table) { - mutex_unlock(&dev_opp_list_lock); - dev_warn(dev, "%s: Unable to allocate frequency table\n", - __func__); - return -ENOMEM; - } - - list_for_each_entry(opp, &dev_opp->opp_list, node) { - if (opp->available) { - freq_table[i].driver_data = i; - freq_table[i].frequency = opp->rate / 1000; - i++; - } - } - mutex_unlock(&dev_opp_list_lock); - - freq_table[i].driver_data = i; - freq_table[i].frequency = CPUFREQ_TABLE_END; - - *table = &freq_table[0]; - - return 0; -} -EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table); - -/** - * dev_pm_opp_free_cpufreq_table() - free the cpufreq table - * @dev: device for which we do this operation - * @table: table to free - * - * Free up the table allocated by dev_pm_opp_init_cpufreq_table - */ -void dev_pm_opp_free_cpufreq_table(struct device *dev, - struct cpufreq_frequency_table **table) -{ - if (!table) - return; - - kfree(*table); - *table = NULL; -} -EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table); -#endif /* CONFIG_CPU_FREQ */ - /** * dev_pm_opp_get_notifier() - find notifier_head of the device with opp * @dev: device pointer used to lookup device OPPs. diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index 930cad4e5df8a1..6a7e4fa12854c8 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -23,16 +23,16 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, static int regcache_rbtree_exit(struct regmap *map); struct regcache_rbtree_node { - /* the actual rbtree node holding this block */ - struct rb_node node; - /* base register handled by this block */ - unsigned int base_reg; /* block of adjacent registers */ void *block; /* Which registers are present */ long *cache_present; + /* base register handled by this block */ + unsigned int base_reg; /* number of registers available in the block */ unsigned int blklen; + /* the actual rbtree node holding this block */ + struct rb_node node; } __attribute__ ((packed)); struct regcache_rbtree_ctx { diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index ebd18952976036..ca193d1ef47cb0 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -14,6 +14,79 @@ #include #include + +static int regmap_smbus_byte_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + int ret; + + if (reg > 0xff) + return -EINVAL; + + ret = i2c_smbus_read_byte_data(i2c, reg); + if (ret < 0) + return ret; + + *val = ret; + + return 0; +} + +static int regmap_smbus_byte_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + + if (val > 0xff || reg > 0xff) + return -EINVAL; + + return i2c_smbus_write_byte_data(i2c, reg, val); +} + +static struct regmap_bus regmap_smbus_byte = { + .reg_write = regmap_smbus_byte_reg_write, + .reg_read = regmap_smbus_byte_reg_read, +}; + +static int regmap_smbus_word_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + int ret; + + if (reg > 0xff) + return -EINVAL; + + ret = i2c_smbus_read_word_data(i2c, reg); + if (ret < 0) + return ret; + + *val = ret; + + return 0; +} + +static int regmap_smbus_word_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + + if (val > 0xffff || reg > 0xff) + return -EINVAL; + + return i2c_smbus_write_word_data(i2c, reg, val); +} + +static struct regmap_bus regmap_smbus_word = { + .reg_write = regmap_smbus_word_reg_write, + .reg_read = regmap_smbus_word_reg_read, +}; + static int regmap_i2c_write(void *context, const void *data, size_t count) { struct device *dev = context; @@ -97,6 +170,23 @@ static struct regmap_bus regmap_i2c = { .read = regmap_i2c_read, }; +static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, + const struct regmap_config *config) +{ + if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) + return ®map_i2c; + else if (config->val_bits == 16 && config->reg_bits == 8 && + i2c_check_functionality(i2c->adapter, + I2C_FUNC_SMBUS_WORD_DATA)) + return ®map_smbus_word; + else if (config->val_bits == 8 && config->reg_bits == 8 && + i2c_check_functionality(i2c->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) + return ®map_smbus_byte; + + return ERR_PTR(-ENOTSUPP); +} + /** * regmap_init_i2c(): Initialise register map * @@ -109,7 +199,12 @@ static struct regmap_bus regmap_i2c = { struct regmap *regmap_init_i2c(struct i2c_client *i2c, const struct regmap_config *config) { - return regmap_init(&i2c->dev, ®map_i2c, &i2c->dev, config); + const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config); + + if (IS_ERR(bus)) + return ERR_CAST(bus); + + return regmap_init(&i2c->dev, bus, &i2c->dev, config); } EXPORT_SYMBOL_GPL(regmap_init_i2c); @@ -126,7 +221,12 @@ EXPORT_SYMBOL_GPL(regmap_init_i2c); struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c, const struct regmap_config *config) { - return devm_regmap_init(&i2c->dev, ®map_i2c, &i2c->dev, config); + const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config); + + if (IS_ERR(bus)) + return ERR_CAST(bus); + + return devm_regmap_init(&i2c->dev, bus, &i2c->dev, config); } EXPORT_SYMBOL_GPL(devm_regmap_init_i2c); diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 1e03e7f8bacb22..dff32c6b247441 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -66,12 +66,31 @@ static inline void regmap_mmio_count_check(size_t count) BUG_ON(count % 2 != 0); } +static inline unsigned int +regmap_mmio_get_offset(const void *reg, size_t reg_size) +{ + switch (reg_size) { + case 1: + return *(u8 *)reg; + case 2: + return *(u16 *)reg; + case 4: + return *(u32 *)reg; +#ifdef CONFIG_64BIT + case 8: + return *(u64 *)reg; +#endif + default: + BUG(); + } +} + static int regmap_mmio_gather_write(void *context, const void *reg, size_t reg_size, const void *val, size_t val_size) { struct regmap_mmio_context *ctx = context; - u32 offset; + unsigned int offset; int ret; regmap_mmio_regsize_check(reg_size); @@ -82,7 +101,7 @@ static int regmap_mmio_gather_write(void *context, return ret; } - offset = *(u32 *)reg; + offset = regmap_mmio_get_offset(reg, reg_size); while (val_size) { switch (ctx->val_bytes) { @@ -118,7 +137,7 @@ static int regmap_mmio_gather_write(void *context, static int regmap_mmio_write(void *context, const void *data, size_t count) { struct regmap_mmio_context *ctx = context; - u32 offset = ctx->reg_bytes + ctx->pad_bytes; + unsigned int offset = ctx->reg_bytes + ctx->pad_bytes; regmap_mmio_count_check(count); @@ -131,7 +150,7 @@ static int regmap_mmio_read(void *context, void *val, size_t val_size) { struct regmap_mmio_context *ctx = context; - u32 offset; + unsigned int offset; int ret; regmap_mmio_regsize_check(reg_size); @@ -142,7 +161,7 @@ static int regmap_mmio_read(void *context, return ret; } - offset = *(u32 *)reg; + offset = regmap_mmio_get_offset(reg, reg_size); while (val_size) { switch (ctx->val_bytes) { diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 63e30ef096e2be..74d8c0672cf616 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -35,10 +35,14 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change); +static int _regmap_bus_reg_read(void *context, unsigned int reg, + unsigned int *val); static int _regmap_bus_read(void *context, unsigned int reg, unsigned int *val); static int _regmap_bus_formatted_write(void *context, unsigned int reg, unsigned int val); +static int _regmap_bus_reg_write(void *context, unsigned int reg, + unsigned int val); static int _regmap_bus_raw_write(void *context, unsigned int reg, unsigned int val); @@ -192,6 +196,13 @@ static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift) b[0] = cpu_to_be16(val << shift); } +static void regmap_format_16_le(void *buf, unsigned int val, unsigned int shift) +{ + __le16 *b = buf; + + b[0] = cpu_to_le16(val << shift); +} + static void regmap_format_16_native(void *buf, unsigned int val, unsigned int shift) { @@ -216,6 +227,13 @@ static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift) b[0] = cpu_to_be32(val << shift); } +static void regmap_format_32_le(void *buf, unsigned int val, unsigned int shift) +{ + __le32 *b = buf; + + b[0] = cpu_to_le32(val << shift); +} + static void regmap_format_32_native(void *buf, unsigned int val, unsigned int shift) { @@ -240,6 +258,13 @@ static unsigned int regmap_parse_16_be(const void *buf) return be16_to_cpu(b[0]); } +static unsigned int regmap_parse_16_le(const void *buf) +{ + const __le16 *b = buf; + + return le16_to_cpu(b[0]); +} + static void regmap_parse_16_be_inplace(void *buf) { __be16 *b = buf; @@ -247,6 +272,13 @@ static void regmap_parse_16_be_inplace(void *buf) b[0] = be16_to_cpu(b[0]); } +static void regmap_parse_16_le_inplace(void *buf) +{ + __le16 *b = buf; + + b[0] = le16_to_cpu(b[0]); +} + static unsigned int regmap_parse_16_native(const void *buf) { return *(u16 *)buf; @@ -269,6 +301,13 @@ static unsigned int regmap_parse_32_be(const void *buf) return be32_to_cpu(b[0]); } +static unsigned int regmap_parse_32_le(const void *buf) +{ + const __le32 *b = buf; + + return le32_to_cpu(b[0]); +} + static void regmap_parse_32_be_inplace(void *buf) { __be32 *b = buf; @@ -276,6 +315,13 @@ static void regmap_parse_32_be_inplace(void *buf) b[0] = be32_to_cpu(b[0]); } +static void regmap_parse_32_le_inplace(void *buf) +{ + __le32 *b = buf; + + b[0] = le32_to_cpu(b[0]); +} + static unsigned int regmap_parse_32_native(const void *buf) { return *(u32 *)buf; @@ -493,6 +539,12 @@ struct regmap *regmap_init(struct device *dev, map->reg_read = config->reg_read; map->reg_write = config->reg_write; + map->defer_caching = false; + goto skip_format_initialization; + } else if (!bus->read || !bus->write) { + map->reg_read = _regmap_bus_reg_read; + map->reg_write = _regmap_bus_reg_write; + map->defer_caching = false; goto skip_format_initialization; } else { @@ -608,6 +660,11 @@ struct regmap *regmap_init(struct device *dev, map->format.parse_val = regmap_parse_16_be; map->format.parse_inplace = regmap_parse_16_be_inplace; break; + case REGMAP_ENDIAN_LITTLE: + map->format.format_val = regmap_format_16_le; + map->format.parse_val = regmap_parse_16_le; + map->format.parse_inplace = regmap_parse_16_le_inplace; + break; case REGMAP_ENDIAN_NATIVE: map->format.format_val = regmap_format_16_native; map->format.parse_val = regmap_parse_16_native; @@ -629,6 +686,11 @@ struct regmap *regmap_init(struct device *dev, map->format.parse_val = regmap_parse_32_be; map->format.parse_inplace = regmap_parse_32_be_inplace; break; + case REGMAP_ENDIAN_LITTLE: + map->format.format_val = regmap_format_32_le; + map->format.parse_val = regmap_parse_32_le; + map->format.parse_inplace = regmap_parse_32_le_inplace; + break; case REGMAP_ENDIAN_NATIVE: map->format.format_val = regmap_format_32_native; map->format.parse_val = regmap_parse_32_native; @@ -1284,6 +1346,14 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg, return ret; } +static int _regmap_bus_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct regmap *map = context; + + return map->bus->reg_write(map->bus_context, reg, val); +} + static int _regmap_bus_raw_write(void *context, unsigned int reg, unsigned int val) { @@ -1615,6 +1685,9 @@ static int _regmap_raw_multi_reg_write(struct regmap *map, size_t pair_size = reg_bytes + pad_bytes + val_bytes; size_t len = pair_size * num_regs; + if (!len) + return -EINVAL; + buf = kzalloc(len, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -1662,7 +1735,7 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map, int ret; int i, n; struct reg_default *base; - unsigned int this_page; + unsigned int this_page = 0; /* * the set of registers are not neccessarily in order, but * since the order of write must be preserved this algorithm @@ -1925,6 +1998,14 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, return ret; } +static int _regmap_bus_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct regmap *map = context; + + return map->bus->reg_read(map->bus_context, reg, val); +} + static int _regmap_bus_read(void *context, unsigned int reg, unsigned int *val) { diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 748dea4f34dc1e..758da2287d9a3d 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1406,7 +1406,7 @@ static void redo_fd_request(void) track = block / (floppy->dtype->sects * floppy->type->sect_mult); sector = block % (floppy->dtype->sects * floppy->type->sect_mult); - data = rq->buffer + 512 * cnt; + data = bio_data(rq->bio) + 512 * cnt; #ifdef DEBUG printk("access to track %d, sector %d, with buffer at " "0x%08lx\n", track, sector, data); diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 96b629e1f0c9b0..7e8a55f8917cb9 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1484,7 +1484,7 @@ static void redo_fd_request(void) ReqCnt = 0; ReqCmd = rq_data_dir(fd_request); ReqBlock = blk_rq_pos(fd_request); - ReqBuffer = fd_request->buffer; + ReqBuffer = bio_data(fd_request->bio); setup_req_params( drive ); do_fd_action( drive ); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 73894ca3395662..4595c22f33f71e 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -4080,7 +4080,7 @@ static void cciss_interrupt_mode(ctlr_info_t *h) goto default_int_mode; if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) { - err = pci_enable_msix(h->pdev, cciss_msix_entries, 4); + err = pci_enable_msix_exact(h->pdev, cciss_msix_entries, 4); if (!err) { h->intr[0] = cciss_msix_entries[0].vector; h->intr[1] = cciss_msix_entries[1].vector; @@ -4088,10 +4088,6 @@ static void cciss_interrupt_mode(ctlr_info_t *h) h->intr[3] = cciss_msix_entries[3].vector; h->msix_vector = 1; return; - } - if (err > 0) { - dev_warn(&h->pdev->dev, - "only %d MSI-X vectors available\n", err); } else { dev_warn(&h->pdev->dev, "MSI-X init failed %d\n", err); diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 90ae4ba8f9ee88..05a1780ffa8504 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -29,7 +29,6 @@ #include #include #include "drbd_int.h" -#include "drbd_wrappers.h" enum al_transaction_types { @@ -204,7 +203,7 @@ int drbd_md_sync_page_io(struct drbd_device *device, struct drbd_backing_dev *bd BUG_ON(!bdev->md_bdev); - drbd_dbg(device, "meta_data io: %s [%d]:%s(,%llus,%s) %pS\n", + dynamic_drbd_dbg(device, "meta_data io: %s [%d]:%s(,%llus,%s) %pS\n", current->comm, current->pid, __func__, (unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ", (void*)_RET_IP_ ); @@ -276,7 +275,6 @@ bool drbd_al_begin_io_fastpath(struct drbd_device *device, struct drbd_interval return _al_get(device, first, true); } -static bool drbd_al_begin_io_prepare(struct drbd_device *device, struct drbd_interval *i) { /* for bios crossing activity log extent boundaries, @@ -846,7 +844,7 @@ void __drbd_set_in_sync(struct drbd_device *device, sector_t sector, int size, int wake_up = 0; unsigned long flags; - if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) { + if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_DISCARD_SIZE) { drbd_err(device, "drbd_set_in_sync: sector=%llus size=%d nonsense!\n", (unsigned long long)sector, size); return; @@ -920,7 +918,7 @@ int __drbd_set_out_of_sync(struct drbd_device *device, sector_t sector, int size if (size == 0) return 0; - if (size < 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) { + if (size < 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_DISCARD_SIZE) { drbd_err(device, "sector: %llus, size: %d\n", (unsigned long long)sector, size); return 0; @@ -1023,8 +1021,7 @@ int drbd_rs_begin_io(struct drbd_device *device, sector_t sector) unsigned int enr = BM_SECT_TO_EXT(sector); struct bm_extent *bm_ext; int i, sig; - int sa = 200; /* Step aside 200 times, then grab the extent and let app-IO wait. - 200 times -> 20 seconds. */ + bool sa; retry: sig = wait_event_interruptible(device->al_wait, @@ -1035,12 +1032,15 @@ int drbd_rs_begin_io(struct drbd_device *device, sector_t sector) if (test_bit(BME_LOCKED, &bm_ext->flags)) return 0; + /* step aside only while we are above c-min-rate; unless disabled. */ + sa = drbd_rs_c_min_rate_throttle(device); + for (i = 0; i < AL_EXT_PER_BM_SECT; i++) { sig = wait_event_interruptible(device->al_wait, !_is_in_al(device, enr * AL_EXT_PER_BM_SECT + i) || - test_bit(BME_PRIORITY, &bm_ext->flags)); + (sa && test_bit(BME_PRIORITY, &bm_ext->flags))); - if (sig || (test_bit(BME_PRIORITY, &bm_ext->flags) && sa)) { + if (sig || (sa && test_bit(BME_PRIORITY, &bm_ext->flags))) { spin_lock_irq(&device->al_lock); if (lc_put(device->resync, &bm_ext->lce) == 0) { bm_ext->flags = 0; /* clears BME_NO_WRITES and eventually BME_PRIORITY */ @@ -1052,9 +1052,6 @@ int drbd_rs_begin_io(struct drbd_device *device, sector_t sector) return -EINTR; if (schedule_timeout_interruptible(HZ/10)) return -EINTR; - if (sa && --sa == 0) - drbd_warn(device, "drbd_rs_begin_io() stepped aside for 20sec." - "Resync stalled?\n"); goto retry; } } @@ -1288,7 +1285,7 @@ void drbd_rs_failed_io(struct drbd_device *device, sector_t sector, int size) sector_t esector, nr_sectors; int wake_up = 0; - if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) { + if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_DISCARD_SIZE) { drbd_err(device, "drbd_rs_failed_io: sector=%llus size=%d nonsense!\n", (unsigned long long)sector, size); return; diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index e7093d4291f1a8..a76ceb344d64e9 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -382,6 +382,12 @@ enum { __EE_CALL_AL_COMPLETE_IO, __EE_MAY_SET_IN_SYNC, + /* is this a TRIM aka REQ_DISCARD? */ + __EE_IS_TRIM, + /* our lower level cannot handle trim, + * and we want to fall back to zeroout instead */ + __EE_IS_TRIM_USE_ZEROOUT, + /* In case a barrier failed, * we need to resubmit without the barrier flag. */ __EE_RESUBMITTED, @@ -405,7 +411,9 @@ enum { }; #define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO) #define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC) -#define EE_RESUBMITTED (1<<__EE_RESUBMITTED) +#define EE_IS_TRIM (1<<__EE_IS_TRIM) +#define EE_IS_TRIM_USE_ZEROOUT (1<<__EE_IS_TRIM_USE_ZEROOUT) +#define EE_RESUBMITTED (1<<__EE_RESUBMITTED) #define EE_WAS_ERROR (1<<__EE_WAS_ERROR) #define EE_HAS_DIGEST (1<<__EE_HAS_DIGEST) #define EE_RESTART_REQUESTS (1<<__EE_RESTART_REQUESTS) @@ -579,6 +587,7 @@ struct drbd_resource { struct list_head resources; struct res_opts res_opts; struct mutex conf_update; /* mutex for ready-copy-update of net_conf and disk_conf */ + struct mutex adm_mutex; /* mutex to serialize administrative requests */ spinlock_t req_lock; unsigned susp:1; /* IO suspended by user */ @@ -609,6 +618,7 @@ struct drbd_connection { struct drbd_socket data; /* data/barrier/cstate/parameter packets */ struct drbd_socket meta; /* ping/ack (metadata) packets */ int agreed_pro_version; /* actually used protocol version */ + u32 agreed_features; unsigned long last_received; /* in jiffies, either socket */ unsigned int ko_count; @@ -814,6 +824,28 @@ struct drbd_device { struct submit_worker submit; }; +struct drbd_config_context { + /* assigned from drbd_genlmsghdr */ + unsigned int minor; + /* assigned from request attributes, if present */ + unsigned int volume; +#define VOLUME_UNSPECIFIED (-1U) + /* pointer into the request skb, + * limited lifetime! */ + char *resource_name; + struct nlattr *my_addr; + struct nlattr *peer_addr; + + /* reply buffer */ + struct sk_buff *reply_skb; + /* pointer into reply buffer */ + struct drbd_genlmsghdr *reply_dh; + /* resolved from attributes, if possible */ + struct drbd_device *device; + struct drbd_resource *resource; + struct drbd_connection *connection; +}; + static inline struct drbd_device *minor_to_device(unsigned int minor) { return (struct drbd_device *)idr_find(&drbd_devices, minor); @@ -821,7 +853,7 @@ static inline struct drbd_device *minor_to_device(unsigned int minor) static inline struct drbd_peer_device *first_peer_device(struct drbd_device *device) { - return list_first_entry(&device->peer_devices, struct drbd_peer_device, peer_devices); + return list_first_entry_or_null(&device->peer_devices, struct drbd_peer_device, peer_devices); } #define for_each_resource(resource, _resources) \ @@ -1139,6 +1171,12 @@ struct bm_extent { #define DRBD_MAX_SIZE_H80_PACKET (1U << 15) /* Header 80 only allows packets up to 32KiB data */ #define DRBD_MAX_BIO_SIZE_P95 (1U << 17) /* Protocol 95 to 99 allows bios up to 128KiB */ +/* For now, don't allow more than one activity log extent worth of data + * to be discarded in one go. We may need to rework drbd_al_begin_io() + * to allow for even larger discard ranges */ +#define DRBD_MAX_DISCARD_SIZE AL_EXTENT_SIZE +#define DRBD_MAX_DISCARD_SECTORS (DRBD_MAX_DISCARD_SIZE >> 9) + extern int drbd_bm_init(struct drbd_device *device); extern int drbd_bm_resize(struct drbd_device *device, sector_t sectors, int set_new_bits); extern void drbd_bm_cleanup(struct drbd_device *device); @@ -1229,9 +1267,9 @@ extern struct bio *bio_alloc_drbd(gfp_t gfp_mask); extern rwlock_t global_state_lock; extern int conn_lowest_minor(struct drbd_connection *connection); -enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr); +extern enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsigned int minor); extern void drbd_destroy_device(struct kref *kref); -extern void drbd_delete_device(struct drbd_device *mdev); +extern void drbd_delete_device(struct drbd_device *device); extern struct drbd_resource *drbd_create_resource(const char *name); extern void drbd_free_resource(struct drbd_resource *resource); @@ -1257,7 +1295,7 @@ extern int is_valid_ar_handle(struct drbd_request *, sector_t); /* drbd_nl.c */ -extern int drbd_msg_put_info(const char *info); +extern int drbd_msg_put_info(struct sk_buff *skb, const char *info); extern void drbd_suspend_io(struct drbd_device *device); extern void drbd_resume_io(struct drbd_device *device); extern char *ppsize(char *buf, unsigned long long size); @@ -1283,6 +1321,10 @@ extern void conn_try_outdate_peer_async(struct drbd_connection *connection); extern int drbd_khelper(struct drbd_device *device, char *cmd); /* drbd_worker.c */ +/* bi_end_io handlers */ +extern void drbd_md_io_complete(struct bio *bio, int error); +extern void drbd_peer_request_endio(struct bio *bio, int error); +extern void drbd_request_endio(struct bio *bio, int error); extern int drbd_worker(struct drbd_thread *thi); enum drbd_ret_code drbd_resync_after_valid(struct drbd_device *device, int o_minor); void drbd_resync_after_changed(struct drbd_device *device); @@ -1332,16 +1374,20 @@ extern int w_start_resync(struct drbd_work *, int); extern void resync_timer_fn(unsigned long data); extern void start_resync_timer_fn(unsigned long data); +extern void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req); + /* drbd_receiver.c */ extern int drbd_receiver(struct drbd_thread *thi); extern int drbd_asender(struct drbd_thread *thi); -extern int drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector); +extern bool drbd_rs_c_min_rate_throttle(struct drbd_device *device); +extern bool drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector); extern int drbd_submit_peer_request(struct drbd_device *, struct drbd_peer_request *, const unsigned, const int); extern int drbd_free_peer_reqs(struct drbd_device *, struct list_head *); extern struct drbd_peer_request *drbd_alloc_peer_req(struct drbd_peer_device *, u64, sector_t, unsigned int, + bool, gfp_t) __must_hold(local); extern void __drbd_free_peer_req(struct drbd_device *, struct drbd_peer_request *, int); @@ -1401,6 +1447,37 @@ static inline void drbd_tcp_quickack(struct socket *sock) (char*)&val, sizeof(val)); } +/* sets the number of 512 byte sectors of our virtual device */ +static inline void drbd_set_my_capacity(struct drbd_device *device, + sector_t size) +{ + /* set_capacity(device->this_bdev->bd_disk, size); */ + set_capacity(device->vdisk, size); + device->this_bdev->bd_inode->i_size = (loff_t)size << 9; +} + +/* + * used to submit our private bio + */ +static inline void drbd_generic_make_request(struct drbd_device *device, + int fault_type, struct bio *bio) +{ + __release(local); + if (!bio->bi_bdev) { + printk(KERN_ERR "drbd%d: drbd_generic_make_request: " + "bio->bi_bdev == NULL\n", + device_to_minor(device)); + dump_stack(); + bio_endio(bio, -ENODEV); + return; + } + + if (drbd_insert_fault(device, fault_type)) + bio_endio(bio, -EIO); + else + generic_make_request(bio); +} + void drbd_bump_write_ordering(struct drbd_connection *connection, enum write_ordering_e wo); /* drbd_proc.c */ @@ -1410,6 +1487,7 @@ extern const char *drbd_conn_str(enum drbd_conns s); extern const char *drbd_role_str(enum drbd_role s); /* drbd_actlog.c */ +extern bool drbd_al_begin_io_prepare(struct drbd_device *device, struct drbd_interval *i); extern int drbd_al_begin_io_nonblock(struct drbd_device *device, struct drbd_interval *i); extern void drbd_al_begin_io_commit(struct drbd_device *device, bool delegate); extern bool drbd_al_begin_io_fastpath(struct drbd_device *device, struct drbd_interval *i); @@ -2144,7 +2222,7 @@ static inline void drbd_md_flush(struct drbd_device *device) static inline struct drbd_connection *first_connection(struct drbd_resource *resource) { - return list_first_entry(&resource->connections, + return list_first_entry_or_null(&resource->connections, struct drbd_connection, connections); } diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 331e5cc1227ddf..960645c26e6fc1 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1607,8 +1607,8 @@ static u32 bio_flags_to_wire(struct drbd_connection *connection, unsigned long b return bi_rw & REQ_SYNC ? DP_RW_SYNC : 0; } -/* Used to send write requests - * R_PRIMARY -> Peer (P_DATA) +/* Used to send write or TRIM aka REQ_DISCARD requests + * R_PRIMARY -> Peer (P_DATA, P_TRIM) */ int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request *req) { @@ -1640,6 +1640,16 @@ int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request * dp_flags |= DP_SEND_WRITE_ACK; } p->dp_flags = cpu_to_be32(dp_flags); + + if (dp_flags & DP_DISCARD) { + struct p_trim *t = (struct p_trim*)p; + t->size = cpu_to_be32(req->i.size); + err = __send_command(peer_device->connection, device->vnr, sock, P_TRIM, sizeof(*t), NULL, 0); + goto out; + } + + /* our digest is still only over the payload. + * TRIM does not carry any payload. */ if (dgs) drbd_csum_bio(peer_device->connection->integrity_tfm, req->master_bio, p + 1); err = __send_command(peer_device->connection, device->vnr, sock, P_DATA, sizeof(*p) + dgs, NULL, req->i.size); @@ -1675,6 +1685,7 @@ int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request * ... Be noisy about digest too large ... } */ } +out: mutex_unlock(&sock->mutex); /* locked by drbd_prepare_command() */ return err; @@ -2570,6 +2581,7 @@ struct drbd_resource *drbd_create_resource(const char *name) INIT_LIST_HEAD(&resource->connections); list_add_tail_rcu(&resource->resources, &drbd_resources); mutex_init(&resource->conf_update); + mutex_init(&resource->adm_mutex); spin_lock_init(&resource->req_lock); return resource; @@ -2687,14 +2699,16 @@ static int init_submitter(struct drbd_device *device) return 0; } -enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr) +enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsigned int minor) { + struct drbd_resource *resource = adm_ctx->resource; struct drbd_connection *connection; struct drbd_device *device; struct drbd_peer_device *peer_device, *tmp_peer_device; struct gendisk *disk; struct request_queue *q; int id; + int vnr = adm_ctx->volume; enum drbd_ret_code err = ERR_NOMEM; device = minor_to_device(minor); @@ -2763,7 +2777,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i if (id < 0) { if (id == -ENOSPC) { err = ERR_MINOR_EXISTS; - drbd_msg_put_info("requested minor exists already"); + drbd_msg_put_info(adm_ctx->reply_skb, "requested minor exists already"); } goto out_no_minor_idr; } @@ -2773,7 +2787,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i if (id < 0) { if (id == -ENOSPC) { err = ERR_MINOR_EXISTS; - drbd_msg_put_info("requested minor exists already"); + drbd_msg_put_info(adm_ctx->reply_skb, "requested minor exists already"); } goto out_idr_remove_minor; } @@ -2794,7 +2808,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i if (id < 0) { if (id == -ENOSPC) { err = ERR_INVALID_REQUEST; - drbd_msg_put_info("requested volume exists already"); + drbd_msg_put_info(adm_ctx->reply_skb, "requested volume exists already"); } goto out_idr_remove_from_resource; } @@ -2803,7 +2817,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i if (init_submitter(device)) { err = ERR_NOMEM; - drbd_msg_put_info("unable to create submit workqueue"); + drbd_msg_put_info(adm_ctx->reply_skb, "unable to create submit workqueue"); goto out_idr_remove_vol; } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 526414bc2cab18..1b35c45c92b75d 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -34,7 +34,6 @@ #include "drbd_int.h" #include "drbd_protocol.h" #include "drbd_req.h" -#include "drbd_wrappers.h" #include #include #include @@ -82,32 +81,6 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb); /* used blkdev_get_by_path, to claim our meta data device(s) */ static char *drbd_m_holder = "Hands off! this is DRBD's meta data device."; -/* Configuration is strictly serialized, because generic netlink message - * processing is strictly serialized by the genl_lock(). - * Which means we can use one static global drbd_config_context struct. - */ -static struct drbd_config_context { - /* assigned from drbd_genlmsghdr */ - unsigned int minor; - /* assigned from request attributes, if present */ - unsigned int volume; -#define VOLUME_UNSPECIFIED (-1U) - /* pointer into the request skb, - * limited lifetime! */ - char *resource_name; - struct nlattr *my_addr; - struct nlattr *peer_addr; - - /* reply buffer */ - struct sk_buff *reply_skb; - /* pointer into reply buffer */ - struct drbd_genlmsghdr *reply_dh; - /* resolved from attributes, if possible */ - struct drbd_device *device; - struct drbd_resource *resource; - struct drbd_connection *connection; -} adm_ctx; - static void drbd_adm_send_reply(struct sk_buff *skb, struct genl_info *info) { genlmsg_end(skb, genlmsg_data(nlmsg_data(nlmsg_hdr(skb)))); @@ -117,9 +90,8 @@ static void drbd_adm_send_reply(struct sk_buff *skb, struct genl_info *info) /* Used on a fresh "drbd_adm_prepare"d reply_skb, this cannot fail: The only * reason it could fail was no space in skb, and there are 4k available. */ -int drbd_msg_put_info(const char *info) +int drbd_msg_put_info(struct sk_buff *skb, const char *info) { - struct sk_buff *skb = adm_ctx.reply_skb; struct nlattr *nla; int err = -EMSGSIZE; @@ -143,42 +115,46 @@ int drbd_msg_put_info(const char *info) * and per-family private info->pointers. * But we need to stay compatible with older kernels. * If it returns successfully, adm_ctx members are valid. + * + * At this point, we still rely on the global genl_lock(). + * If we want to avoid that, and allow "genl_family.parallel_ops", we may need + * to add additional synchronization against object destruction/modification. */ #define DRBD_ADM_NEED_MINOR 1 #define DRBD_ADM_NEED_RESOURCE 2 #define DRBD_ADM_NEED_CONNECTION 4 -static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info, - unsigned flags) +static int drbd_adm_prepare(struct drbd_config_context *adm_ctx, + struct sk_buff *skb, struct genl_info *info, unsigned flags) { struct drbd_genlmsghdr *d_in = info->userhdr; const u8 cmd = info->genlhdr->cmd; int err; - memset(&adm_ctx, 0, sizeof(adm_ctx)); + memset(adm_ctx, 0, sizeof(*adm_ctx)); /* genl_rcv_msg only checks for CAP_NET_ADMIN on "GENL_ADMIN_PERM" :( */ if (cmd != DRBD_ADM_GET_STATUS && !capable(CAP_NET_ADMIN)) return -EPERM; - adm_ctx.reply_skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!adm_ctx.reply_skb) { + adm_ctx->reply_skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!adm_ctx->reply_skb) { err = -ENOMEM; goto fail; } - adm_ctx.reply_dh = genlmsg_put_reply(adm_ctx.reply_skb, + adm_ctx->reply_dh = genlmsg_put_reply(adm_ctx->reply_skb, info, &drbd_genl_family, 0, cmd); /* put of a few bytes into a fresh skb of >= 4k will always succeed. * but anyways */ - if (!adm_ctx.reply_dh) { + if (!adm_ctx->reply_dh) { err = -ENOMEM; goto fail; } - adm_ctx.reply_dh->minor = d_in->minor; - adm_ctx.reply_dh->ret_code = NO_ERROR; + adm_ctx->reply_dh->minor = d_in->minor; + adm_ctx->reply_dh->ret_code = NO_ERROR; - adm_ctx.volume = VOLUME_UNSPECIFIED; + adm_ctx->volume = VOLUME_UNSPECIFIED; if (info->attrs[DRBD_NLA_CFG_CONTEXT]) { struct nlattr *nla; /* parse and validate only */ @@ -188,111 +164,131 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info, /* It was present, and valid, * copy it over to the reply skb. */ - err = nla_put_nohdr(adm_ctx.reply_skb, + err = nla_put_nohdr(adm_ctx->reply_skb, info->attrs[DRBD_NLA_CFG_CONTEXT]->nla_len, info->attrs[DRBD_NLA_CFG_CONTEXT]); if (err) goto fail; - /* and assign stuff to the global adm_ctx */ + /* and assign stuff to the adm_ctx */ nla = nested_attr_tb[__nla_type(T_ctx_volume)]; if (nla) - adm_ctx.volume = nla_get_u32(nla); + adm_ctx->volume = nla_get_u32(nla); nla = nested_attr_tb[__nla_type(T_ctx_resource_name)]; if (nla) - adm_ctx.resource_name = nla_data(nla); - adm_ctx.my_addr = nested_attr_tb[__nla_type(T_ctx_my_addr)]; - adm_ctx.peer_addr = nested_attr_tb[__nla_type(T_ctx_peer_addr)]; - if ((adm_ctx.my_addr && - nla_len(adm_ctx.my_addr) > sizeof(adm_ctx.connection->my_addr)) || - (adm_ctx.peer_addr && - nla_len(adm_ctx.peer_addr) > sizeof(adm_ctx.connection->peer_addr))) { + adm_ctx->resource_name = nla_data(nla); + adm_ctx->my_addr = nested_attr_tb[__nla_type(T_ctx_my_addr)]; + adm_ctx->peer_addr = nested_attr_tb[__nla_type(T_ctx_peer_addr)]; + if ((adm_ctx->my_addr && + nla_len(adm_ctx->my_addr) > sizeof(adm_ctx->connection->my_addr)) || + (adm_ctx->peer_addr && + nla_len(adm_ctx->peer_addr) > sizeof(adm_ctx->connection->peer_addr))) { err = -EINVAL; goto fail; } } - adm_ctx.minor = d_in->minor; - adm_ctx.device = minor_to_device(d_in->minor); - if (adm_ctx.resource_name) { - adm_ctx.resource = drbd_find_resource(adm_ctx.resource_name); + adm_ctx->minor = d_in->minor; + adm_ctx->device = minor_to_device(d_in->minor); + + /* We are protected by the global genl_lock(). + * But we may explicitly drop it/retake it in drbd_adm_set_role(), + * so make sure this object stays around. */ + if (adm_ctx->device) + kref_get(&adm_ctx->device->kref); + + if (adm_ctx->resource_name) { + adm_ctx->resource = drbd_find_resource(adm_ctx->resource_name); } - if (!adm_ctx.device && (flags & DRBD_ADM_NEED_MINOR)) { - drbd_msg_put_info("unknown minor"); + if (!adm_ctx->device && (flags & DRBD_ADM_NEED_MINOR)) { + drbd_msg_put_info(adm_ctx->reply_skb, "unknown minor"); return ERR_MINOR_INVALID; } - if (!adm_ctx.resource && (flags & DRBD_ADM_NEED_RESOURCE)) { - drbd_msg_put_info("unknown resource"); - if (adm_ctx.resource_name) + if (!adm_ctx->resource && (flags & DRBD_ADM_NEED_RESOURCE)) { + drbd_msg_put_info(adm_ctx->reply_skb, "unknown resource"); + if (adm_ctx->resource_name) return ERR_RES_NOT_KNOWN; return ERR_INVALID_REQUEST; } if (flags & DRBD_ADM_NEED_CONNECTION) { - if (adm_ctx.resource) { - drbd_msg_put_info("no resource name expected"); + if (adm_ctx->resource) { + drbd_msg_put_info(adm_ctx->reply_skb, "no resource name expected"); return ERR_INVALID_REQUEST; } - if (adm_ctx.device) { - drbd_msg_put_info("no minor number expected"); + if (adm_ctx->device) { + drbd_msg_put_info(adm_ctx->reply_skb, "no minor number expected"); return ERR_INVALID_REQUEST; } - if (adm_ctx.my_addr && adm_ctx.peer_addr) - adm_ctx.connection = conn_get_by_addrs(nla_data(adm_ctx.my_addr), - nla_len(adm_ctx.my_addr), - nla_data(adm_ctx.peer_addr), - nla_len(adm_ctx.peer_addr)); - if (!adm_ctx.connection) { - drbd_msg_put_info("unknown connection"); + if (adm_ctx->my_addr && adm_ctx->peer_addr) + adm_ctx->connection = conn_get_by_addrs(nla_data(adm_ctx->my_addr), + nla_len(adm_ctx->my_addr), + nla_data(adm_ctx->peer_addr), + nla_len(adm_ctx->peer_addr)); + if (!adm_ctx->connection) { + drbd_msg_put_info(adm_ctx->reply_skb, "unknown connection"); return ERR_INVALID_REQUEST; } } /* some more paranoia, if the request was over-determined */ - if (adm_ctx.device && adm_ctx.resource && - adm_ctx.device->resource != adm_ctx.resource) { + if (adm_ctx->device && adm_ctx->resource && + adm_ctx->device->resource != adm_ctx->resource) { pr_warning("request: minor=%u, resource=%s; but that minor belongs to resource %s\n", - adm_ctx.minor, adm_ctx.resource->name, - adm_ctx.device->resource->name); - drbd_msg_put_info("minor exists in different resource"); + adm_ctx->minor, adm_ctx->resource->name, + adm_ctx->device->resource->name); + drbd_msg_put_info(adm_ctx->reply_skb, "minor exists in different resource"); return ERR_INVALID_REQUEST; } - if (adm_ctx.device && - adm_ctx.volume != VOLUME_UNSPECIFIED && - adm_ctx.volume != adm_ctx.device->vnr) { + if (adm_ctx->device && + adm_ctx->volume != VOLUME_UNSPECIFIED && + adm_ctx->volume != adm_ctx->device->vnr) { pr_warning("request: minor=%u, volume=%u; but that minor is volume %u in %s\n", - adm_ctx.minor, adm_ctx.volume, - adm_ctx.device->vnr, - adm_ctx.device->resource->name); - drbd_msg_put_info("minor exists as different volume"); + adm_ctx->minor, adm_ctx->volume, + adm_ctx->device->vnr, + adm_ctx->device->resource->name); + drbd_msg_put_info(adm_ctx->reply_skb, "minor exists as different volume"); return ERR_INVALID_REQUEST; } + /* still, provide adm_ctx->resource always, if possible. */ + if (!adm_ctx->resource) { + adm_ctx->resource = adm_ctx->device ? adm_ctx->device->resource + : adm_ctx->connection ? adm_ctx->connection->resource : NULL; + if (adm_ctx->resource) + kref_get(&adm_ctx->resource->kref); + } + return NO_ERROR; fail: - nlmsg_free(adm_ctx.reply_skb); - adm_ctx.reply_skb = NULL; + nlmsg_free(adm_ctx->reply_skb); + adm_ctx->reply_skb = NULL; return err; } -static int drbd_adm_finish(struct genl_info *info, int retcode) +static int drbd_adm_finish(struct drbd_config_context *adm_ctx, + struct genl_info *info, int retcode) { - if (adm_ctx.connection) { - kref_put(&adm_ctx.connection->kref, drbd_destroy_connection); - adm_ctx.connection = NULL; + if (adm_ctx->device) { + kref_put(&adm_ctx->device->kref, drbd_destroy_device); + adm_ctx->device = NULL; } - if (adm_ctx.resource) { - kref_put(&adm_ctx.resource->kref, drbd_destroy_resource); - adm_ctx.resource = NULL; + if (adm_ctx->connection) { + kref_put(&adm_ctx->connection->kref, &drbd_destroy_connection); + adm_ctx->connection = NULL; + } + if (adm_ctx->resource) { + kref_put(&adm_ctx->resource->kref, drbd_destroy_resource); + adm_ctx->resource = NULL; } - if (!adm_ctx.reply_skb) + if (!adm_ctx->reply_skb) return -ENOMEM; - adm_ctx.reply_dh->ret_code = retcode; - drbd_adm_send_reply(adm_ctx.reply_skb, info); + adm_ctx->reply_dh->ret_code = retcode; + drbd_adm_send_reply(adm_ctx->reply_skb, info); return 0; } @@ -426,6 +422,14 @@ static enum drbd_fencing_p highest_fencing_policy(struct drbd_connection *connec } rcu_read_unlock(); + if (fp == FP_NOT_AVAIL) { + /* IO Suspending works on the whole resource. + Do it only for one device. */ + vnr = 0; + peer_device = idr_get_next(&connection->peer_devices, &vnr); + drbd_change_state(peer_device->device, CS_VERBOSE | CS_HARD, NS(susp_fen, 0)); + } + return fp; } @@ -438,12 +442,13 @@ bool conn_try_outdate_peer(struct drbd_connection *connection) char *ex_to_string; int r; + spin_lock_irq(&connection->resource->req_lock); if (connection->cstate >= C_WF_REPORT_PARAMS) { drbd_err(connection, "Expected cstate < C_WF_REPORT_PARAMS\n"); + spin_unlock_irq(&connection->resource->req_lock); return false; } - spin_lock_irq(&connection->resource->req_lock); connect_cnt = connection->connect_cnt; spin_unlock_irq(&connection->resource->req_lock); @@ -654,11 +659,11 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force) put_ldev(device); } } else { - mutex_lock(&device->resource->conf_update); + /* Called from drbd_adm_set_role only. + * We are still holding the conf_update mutex. */ nc = first_peer_device(device)->connection->net_conf; if (nc) nc->discard_my_data = 0; /* without copy; single bit op is atomic */ - mutex_unlock(&device->resource->conf_update); set_disk_ro(device->vdisk, false); if (get_ldev(device)) { @@ -700,11 +705,12 @@ static const char *from_attrs_err_to_txt(int err) int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; struct set_role_parms parms; int err; enum drbd_ret_code retcode; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) @@ -715,17 +721,22 @@ int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info) err = set_role_parms_from_attrs(&parms, info); if (err) { retcode = ERR_MANDATORY_TAG; - drbd_msg_put_info(from_attrs_err_to_txt(err)); + drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); goto out; } } + genl_unlock(); + mutex_lock(&adm_ctx.resource->adm_mutex); if (info->genlhdr->cmd == DRBD_ADM_PRIMARY) retcode = drbd_set_role(adm_ctx.device, R_PRIMARY, parms.assume_uptodate); else retcode = drbd_set_role(adm_ctx.device, R_SECONDARY, 0); + + mutex_unlock(&adm_ctx.resource->adm_mutex); + genl_lock(); out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } @@ -1104,15 +1115,18 @@ static void drbd_setup_queue_param(struct drbd_device *device, unsigned int max_ struct request_queue * const q = device->rq_queue; unsigned int max_hw_sectors = max_bio_size >> 9; unsigned int max_segments = 0; + struct request_queue *b = NULL; if (get_ldev_if_state(device, D_ATTACHING)) { - struct request_queue * const b = device->ldev->backing_bdev->bd_disk->queue; + b = device->ldev->backing_bdev->bd_disk->queue; max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9); rcu_read_lock(); max_segments = rcu_dereference(device->ldev->disk_conf)->max_bio_bvecs; rcu_read_unlock(); - put_ldev(device); + + blk_set_stacking_limits(&q->limits); + blk_queue_max_write_same_sectors(q, 0); } blk_queue_logical_block_size(q, 512); @@ -1121,8 +1135,25 @@ static void drbd_setup_queue_param(struct drbd_device *device, unsigned int max_ blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS); blk_queue_segment_boundary(q, PAGE_CACHE_SIZE-1); - if (get_ldev_if_state(device, D_ATTACHING)) { - struct request_queue * const b = device->ldev->backing_bdev->bd_disk->queue; + if (b) { + struct drbd_connection *connection = first_peer_device(device)->connection; + + if (blk_queue_discard(b) && + (connection->cstate < C_CONNECTED || connection->agreed_features & FF_TRIM)) { + /* For now, don't allow more than one activity log extent worth of data + * to be discarded in one go. We may need to rework drbd_al_begin_io() + * to allow for even larger discard ranges */ + q->limits.max_discard_sectors = DRBD_MAX_DISCARD_SECTORS; + + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); + /* REALLY? Is stacking secdiscard "legal"? */ + if (blk_queue_secdiscard(b)) + queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q); + } else { + q->limits.max_discard_sectors = 0; + queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); + queue_flag_clear_unlocked(QUEUE_FLAG_SECDISCARD, q); + } blk_queue_stack_limits(q, b); @@ -1164,8 +1195,14 @@ void drbd_reconsider_max_bio_size(struct drbd_device *device) peer = DRBD_MAX_BIO_SIZE_P95; /* drbd 8.3.8 onwards, before 8.4.0 */ else peer = DRBD_MAX_BIO_SIZE; - } + /* We may later detach and re-attach on a disconnected Primary. + * Avoid this setting to jump back in that case. + * We want to store what we know the peer DRBD can handle, + * not what the peer IO backend can handle. */ + if (peer > device->peer_max_bio_size) + device->peer_max_bio_size = peer; + } new = min(local, peer); if (device->state.role == R_PRIMARY && new < now) @@ -1258,19 +1295,21 @@ static unsigned int drbd_al_extents_max(struct drbd_backing_dev *bdev) int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; enum drbd_ret_code retcode; struct drbd_device *device; struct disk_conf *new_disk_conf, *old_disk_conf; struct fifo_buffer *old_plan = NULL, *new_plan = NULL; int err, fifo_size; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) - goto out; + goto finish; device = adm_ctx.device; + mutex_lock(&adm_ctx.resource->adm_mutex); /* we also need a disk * to change the options on */ @@ -1294,7 +1333,7 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) err = disk_conf_from_attrs_for_change(new_disk_conf, info); if (err && err != -ENOMSG) { retcode = ERR_MANDATORY_TAG; - drbd_msg_put_info(from_attrs_err_to_txt(err)); + drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); goto fail_unlock; } @@ -1385,12 +1424,15 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) success: put_ldev(device); out: - drbd_adm_finish(info, retcode); + mutex_unlock(&adm_ctx.resource->adm_mutex); + finish: + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; struct drbd_device *device; int err; enum drbd_ret_code retcode; @@ -1406,13 +1448,14 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) enum drbd_state_rv rv; struct net_conf *nc; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) goto finish; device = adm_ctx.device; + mutex_lock(&adm_ctx.resource->adm_mutex); conn_reconfig_start(first_peer_device(device)->connection); /* if you want to reconfigure, please tear down first */ @@ -1455,7 +1498,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) err = disk_conf_from_attrs(new_disk_conf, info); if (err) { retcode = ERR_MANDATORY_TAG; - drbd_msg_put_info(from_attrs_err_to_txt(err)); + drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); goto fail; } @@ -1619,7 +1662,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) } if (device->state.conn < C_CONNECTED && - device->state.role == R_PRIMARY && + device->state.role == R_PRIMARY && device->ed_uuid && (device->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) { drbd_err(device, "Can only attach to data with current UUID=%016llX\n", (unsigned long long)device->ed_uuid); @@ -1797,7 +1840,8 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) kobject_uevent(&disk_to_dev(device->vdisk)->kobj, KOBJ_CHANGE); put_ldev(device); conn_reconfig_done(first_peer_device(device)->connection); - drbd_adm_finish(info, retcode); + mutex_unlock(&adm_ctx.resource->adm_mutex); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; force_diskless_dec: @@ -1819,9 +1863,9 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) kfree(new_disk_conf); lc_destroy(resync_lru); kfree(new_plan); - + mutex_unlock(&adm_ctx.resource->adm_mutex); finish: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } @@ -1860,11 +1904,12 @@ static int adm_detach(struct drbd_device *device, int force) * Only then we have finally detached. */ int drbd_adm_detach(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; enum drbd_ret_code retcode; struct detach_parms parms = { }; int err; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) @@ -1874,14 +1919,16 @@ int drbd_adm_detach(struct sk_buff *skb, struct genl_info *info) err = detach_parms_from_attrs(&parms, info); if (err) { retcode = ERR_MANDATORY_TAG; - drbd_msg_put_info(from_attrs_err_to_txt(err)); + drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); goto out; } } + mutex_lock(&adm_ctx.resource->adm_mutex); retcode = adm_detach(adm_ctx.device, parms.force_detach); + mutex_unlock(&adm_ctx.resource->adm_mutex); out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } @@ -2055,6 +2102,7 @@ static void free_crypto(struct crypto *crypto) int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; enum drbd_ret_code retcode; struct drbd_connection *connection; struct net_conf *old_net_conf, *new_net_conf = NULL; @@ -2063,13 +2111,14 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) int rsr; /* re-sync running */ struct crypto crypto = { }; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_CONNECTION); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_CONNECTION); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) - goto out; + goto finish; connection = adm_ctx.connection; + mutex_lock(&adm_ctx.resource->adm_mutex); new_net_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL); if (!new_net_conf) { @@ -2084,7 +2133,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) old_net_conf = connection->net_conf; if (!old_net_conf) { - drbd_msg_put_info("net conf missing, try connect"); + drbd_msg_put_info(adm_ctx.reply_skb, "net conf missing, try connect"); retcode = ERR_INVALID_REQUEST; goto fail; } @@ -2096,7 +2145,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) err = net_conf_from_attrs_for_change(new_net_conf, info); if (err && err != -ENOMSG) { retcode = ERR_MANDATORY_TAG; - drbd_msg_put_info(from_attrs_err_to_txt(err)); + drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); goto fail; } @@ -2167,12 +2216,15 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) done: conn_reconfig_done(connection); out: - drbd_adm_finish(info, retcode); + mutex_unlock(&adm_ctx.resource->adm_mutex); + finish: + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; struct drbd_peer_device *peer_device; struct net_conf *old_net_conf, *new_net_conf = NULL; struct crypto crypto = { }; @@ -2182,14 +2234,14 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) int i; int err; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) goto out; if (!(adm_ctx.my_addr && adm_ctx.peer_addr)) { - drbd_msg_put_info("connection endpoint(s) missing"); + drbd_msg_put_info(adm_ctx.reply_skb, "connection endpoint(s) missing"); retcode = ERR_INVALID_REQUEST; goto out; } @@ -2215,6 +2267,7 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) } } + mutex_lock(&adm_ctx.resource->adm_mutex); connection = first_connection(adm_ctx.resource); conn_reconfig_start(connection); @@ -2235,7 +2288,7 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) err = net_conf_from_attrs(new_net_conf, info); if (err && err != -ENOMSG) { retcode = ERR_MANDATORY_TAG; - drbd_msg_put_info(from_attrs_err_to_txt(err)); + drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); goto fail; } @@ -2284,7 +2337,8 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) retcode = conn_request_state(connection, NS(conn, C_UNCONNECTED), CS_VERBOSE); conn_reconfig_done(connection); - drbd_adm_finish(info, retcode); + mutex_unlock(&adm_ctx.resource->adm_mutex); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; fail: @@ -2292,8 +2346,9 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) kfree(new_net_conf); conn_reconfig_done(connection); + mutex_unlock(&adm_ctx.resource->adm_mutex); out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } @@ -2356,13 +2411,14 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_connection *connection int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; struct disconnect_parms parms; struct drbd_connection *connection; enum drbd_state_rv rv; enum drbd_ret_code retcode; int err; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_CONNECTION); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_CONNECTION); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) @@ -2374,18 +2430,20 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info) err = disconnect_parms_from_attrs(&parms, info); if (err) { retcode = ERR_MANDATORY_TAG; - drbd_msg_put_info(from_attrs_err_to_txt(err)); + drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); goto fail; } } + mutex_lock(&adm_ctx.resource->adm_mutex); rv = conn_try_disconnect(connection, parms.force_disconnect); if (rv < SS_SUCCESS) retcode = rv; /* FIXME: Type mismatch. */ else retcode = NO_ERROR; + mutex_unlock(&adm_ctx.resource->adm_mutex); fail: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } @@ -2407,6 +2465,7 @@ void resync_after_online_grow(struct drbd_device *device) int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; struct disk_conf *old_disk_conf, *new_disk_conf = NULL; struct resize_parms rs; struct drbd_device *device; @@ -2417,12 +2476,13 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) sector_t u_size; int err; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) - goto fail; + goto finish; + mutex_lock(&adm_ctx.resource->adm_mutex); device = adm_ctx.device; if (!get_ldev(device)) { retcode = ERR_NO_DISK; @@ -2436,7 +2496,7 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) err = resize_parms_from_attrs(&rs, info); if (err) { retcode = ERR_MANDATORY_TAG; - drbd_msg_put_info(from_attrs_err_to_txt(err)); + drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); goto fail_ldev; } } @@ -2482,7 +2542,7 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) goto fail_ldev; } - if (device->state.conn != C_CONNECTED) { + if (device->state.conn != C_CONNECTED && !rs.resize_force) { retcode = ERR_MD_LAYOUT_CONNECTED; goto fail_ldev; } @@ -2528,7 +2588,9 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) } fail: - drbd_adm_finish(info, retcode); + mutex_unlock(&adm_ctx.resource->adm_mutex); + finish: + drbd_adm_finish(&adm_ctx, info, retcode); return 0; fail_ldev: @@ -2538,11 +2600,12 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; enum drbd_ret_code retcode; struct res_opts res_opts; int err; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) @@ -2555,33 +2618,37 @@ int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info) err = res_opts_from_attrs(&res_opts, info); if (err && err != -ENOMSG) { retcode = ERR_MANDATORY_TAG; - drbd_msg_put_info(from_attrs_err_to_txt(err)); + drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); goto fail; } + mutex_lock(&adm_ctx.resource->adm_mutex); err = set_resource_options(adm_ctx.resource, &res_opts); if (err) { retcode = ERR_INVALID_REQUEST; if (err == -ENOMEM) retcode = ERR_NOMEM; } + mutex_unlock(&adm_ctx.resource->adm_mutex); fail: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; struct drbd_device *device; int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */ - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) goto out; + mutex_lock(&adm_ctx.resource->adm_mutex); device = adm_ctx.device; /* If there is still bitmap IO pending, probably because of a previous @@ -2605,26 +2672,29 @@ int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info) } else retcode = drbd_request_state(device, NS(conn, C_STARTING_SYNC_T)); drbd_resume_io(device); - + mutex_unlock(&adm_ctx.resource->adm_mutex); out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } static int drbd_adm_simple_request_state(struct sk_buff *skb, struct genl_info *info, union drbd_state mask, union drbd_state val) { + struct drbd_config_context adm_ctx; enum drbd_ret_code retcode; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) goto out; + mutex_lock(&adm_ctx.resource->adm_mutex); retcode = drbd_request_state(adm_ctx.device, mask, val); + mutex_unlock(&adm_ctx.resource->adm_mutex); out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } @@ -2639,15 +2709,17 @@ static int drbd_bmio_set_susp_al(struct drbd_device *device) int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; int retcode; /* drbd_ret_code, drbd_state_rv */ struct drbd_device *device; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) goto out; + mutex_lock(&adm_ctx.resource->adm_mutex); device = adm_ctx.device; /* If there is still bitmap IO pending, probably because of a previous @@ -2674,40 +2746,45 @@ int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info) } else retcode = drbd_request_state(device, NS(conn, C_STARTING_SYNC_S)); drbd_resume_io(device); - + mutex_unlock(&adm_ctx.resource->adm_mutex); out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } int drbd_adm_pause_sync(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; enum drbd_ret_code retcode; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) goto out; + mutex_lock(&adm_ctx.resource->adm_mutex); if (drbd_request_state(adm_ctx.device, NS(user_isp, 1)) == SS_NOTHING_TO_DO) retcode = ERR_PAUSE_IS_SET; + mutex_unlock(&adm_ctx.resource->adm_mutex); out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } int drbd_adm_resume_sync(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; union drbd_dev_state s; enum drbd_ret_code retcode; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) goto out; + mutex_lock(&adm_ctx.resource->adm_mutex); if (drbd_request_state(adm_ctx.device, NS(user_isp, 0)) == SS_NOTHING_TO_DO) { s = adm_ctx.device->state; if (s.conn == C_PAUSED_SYNC_S || s.conn == C_PAUSED_SYNC_T) { @@ -2717,9 +2794,9 @@ int drbd_adm_resume_sync(struct sk_buff *skb, struct genl_info *info) retcode = ERR_PAUSE_IS_CLEAR; } } - + mutex_unlock(&adm_ctx.resource->adm_mutex); out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } @@ -2730,15 +2807,17 @@ int drbd_adm_suspend_io(struct sk_buff *skb, struct genl_info *info) int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; struct drbd_device *device; int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */ - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) goto out; + mutex_lock(&adm_ctx.resource->adm_mutex); device = adm_ctx.device; if (test_bit(NEW_CUR_UUID, &device->flags)) { drbd_uuid_new_current(device); @@ -2753,9 +2832,9 @@ int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info) tl_restart(first_peer_device(device)->connection, FAIL_FROZEN_DISK_IO); } drbd_resume_io(device); - + mutex_unlock(&adm_ctx.resource->adm_mutex); out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } @@ -2931,10 +3010,11 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device, int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; enum drbd_ret_code retcode; int err; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) @@ -2946,7 +3026,7 @@ int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info) return err; } out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } @@ -3133,11 +3213,12 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb) int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; enum drbd_ret_code retcode; struct timeout_parms tp; int err; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) @@ -3154,17 +3235,18 @@ int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info) return err; } out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; struct drbd_device *device; enum drbd_ret_code retcode; struct start_ov_parms parms; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) @@ -3179,10 +3261,12 @@ int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info) int err = start_ov_parms_from_attrs(&parms, info); if (err) { retcode = ERR_MANDATORY_TAG; - drbd_msg_put_info(from_attrs_err_to_txt(err)); + drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); goto out; } } + mutex_lock(&adm_ctx.resource->adm_mutex); + /* w_make_ov_request expects position to be aligned */ device->ov_start_sector = parms.ov_start_sector & ~(BM_SECT_PER_BIT-1); device->ov_stop_sector = parms.ov_stop_sector; @@ -3193,21 +3277,24 @@ int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info) wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags)); retcode = drbd_request_state(device, NS(conn, C_VERIFY_S)); drbd_resume_io(device); + + mutex_unlock(&adm_ctx.resource->adm_mutex); out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; struct drbd_device *device; enum drbd_ret_code retcode; int skip_initial_sync = 0; int err; struct new_c_uuid_parms args; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) @@ -3219,11 +3306,12 @@ int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info) err = new_c_uuid_parms_from_attrs(&args, info); if (err) { retcode = ERR_MANDATORY_TAG; - drbd_msg_put_info(from_attrs_err_to_txt(err)); + drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); goto out_nolock; } } + mutex_lock(&adm_ctx.resource->adm_mutex); mutex_lock(device->state_mutex); /* Protects us against serialized state changes. */ if (!get_ldev(device)) { @@ -3268,22 +3356,24 @@ int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info) put_ldev(device); out: mutex_unlock(device->state_mutex); + mutex_unlock(&adm_ctx.resource->adm_mutex); out_nolock: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } static enum drbd_ret_code -drbd_check_resource_name(const char *name) +drbd_check_resource_name(struct drbd_config_context *adm_ctx) { + const char *name = adm_ctx->resource_name; if (!name || !name[0]) { - drbd_msg_put_info("resource name missing"); + drbd_msg_put_info(adm_ctx->reply_skb, "resource name missing"); return ERR_MANDATORY_TAG; } /* if we want to use these in sysfs/configfs/debugfs some day, * we must not allow slashes */ if (strchr(name, '/')) { - drbd_msg_put_info("invalid resource name"); + drbd_msg_put_info(adm_ctx->reply_skb, "invalid resource name"); return ERR_INVALID_REQUEST; } return NO_ERROR; @@ -3291,11 +3381,12 @@ drbd_check_resource_name(const char *name) int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; enum drbd_ret_code retcode; struct res_opts res_opts; int err; - retcode = drbd_adm_prepare(skb, info, 0); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, 0); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) @@ -3305,48 +3396,50 @@ int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info) err = res_opts_from_attrs(&res_opts, info); if (err && err != -ENOMSG) { retcode = ERR_MANDATORY_TAG; - drbd_msg_put_info(from_attrs_err_to_txt(err)); + drbd_msg_put_info(adm_ctx.reply_skb, from_attrs_err_to_txt(err)); goto out; } - retcode = drbd_check_resource_name(adm_ctx.resource_name); + retcode = drbd_check_resource_name(&adm_ctx); if (retcode != NO_ERROR) goto out; if (adm_ctx.resource) { if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) { retcode = ERR_INVALID_REQUEST; - drbd_msg_put_info("resource exists"); + drbd_msg_put_info(adm_ctx.reply_skb, "resource exists"); } /* else: still NO_ERROR */ goto out; } + /* not yet safe for genl_family.parallel_ops */ if (!conn_create(adm_ctx.resource_name, &res_opts)) retcode = ERR_NOMEM; out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; struct drbd_genlmsghdr *dh = info->userhdr; enum drbd_ret_code retcode; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) goto out; if (dh->minor > MINORMASK) { - drbd_msg_put_info("requested minor out of range"); + drbd_msg_put_info(adm_ctx.reply_skb, "requested minor out of range"); retcode = ERR_INVALID_REQUEST; goto out; } if (adm_ctx.volume > DRBD_VOLUME_MAX) { - drbd_msg_put_info("requested volume id out of range"); + drbd_msg_put_info(adm_ctx.reply_skb, "requested volume id out of range"); retcode = ERR_INVALID_REQUEST; goto out; } @@ -3360,9 +3453,11 @@ int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info) goto out; } - retcode = drbd_create_device(adm_ctx.resource, dh->minor, adm_ctx.volume); + mutex_lock(&adm_ctx.resource->adm_mutex); + retcode = drbd_create_device(&adm_ctx, dh->minor); + mutex_unlock(&adm_ctx.resource->adm_mutex); out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } @@ -3383,35 +3478,40 @@ static enum drbd_ret_code adm_del_minor(struct drbd_device *device) int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; enum drbd_ret_code retcode; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_MINOR); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) goto out; + mutex_lock(&adm_ctx.resource->adm_mutex); retcode = adm_del_minor(adm_ctx.device); + mutex_unlock(&adm_ctx.resource->adm_mutex); out: - drbd_adm_finish(info, retcode); + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } int drbd_adm_down(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; struct drbd_resource *resource; struct drbd_connection *connection; struct drbd_device *device; int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */ unsigned i; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) - goto out; + goto finish; resource = adm_ctx.resource; + mutex_lock(&resource->adm_mutex); /* demote */ for_each_connection(connection, resource) { struct drbd_peer_device *peer_device; @@ -3419,14 +3519,14 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info) idr_for_each_entry(&connection->peer_devices, peer_device, i) { retcode = drbd_set_role(peer_device->device, R_SECONDARY, 0); if (retcode < SS_SUCCESS) { - drbd_msg_put_info("failed to demote"); + drbd_msg_put_info(adm_ctx.reply_skb, "failed to demote"); goto out; } } retcode = conn_try_disconnect(connection, 0); if (retcode < SS_SUCCESS) { - drbd_msg_put_info("failed to disconnect"); + drbd_msg_put_info(adm_ctx.reply_skb, "failed to disconnect"); goto out; } } @@ -3435,7 +3535,7 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info) idr_for_each_entry(&resource->devices, device, i) { retcode = adm_detach(device, 0); if (retcode < SS_SUCCESS || retcode > NO_ERROR) { - drbd_msg_put_info("failed to detach"); + drbd_msg_put_info(adm_ctx.reply_skb, "failed to detach"); goto out; } } @@ -3453,7 +3553,7 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info) retcode = adm_del_minor(device); if (retcode != NO_ERROR) { /* "can not happen" */ - drbd_msg_put_info("failed to delete volume"); + drbd_msg_put_info(adm_ctx.reply_skb, "failed to delete volume"); goto out; } } @@ -3462,25 +3562,28 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info) synchronize_rcu(); drbd_free_resource(resource); retcode = NO_ERROR; - out: - drbd_adm_finish(info, retcode); + mutex_unlock(&resource->adm_mutex); +finish: + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info) { + struct drbd_config_context adm_ctx; struct drbd_resource *resource; struct drbd_connection *connection; enum drbd_ret_code retcode; - retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); + retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) - goto out; + goto finish; resource = adm_ctx.resource; + mutex_lock(&resource->adm_mutex); for_each_connection(connection, resource) { if (connection->cstate > C_STANDALONE) { retcode = ERR_NET_CONFIGURED; @@ -3499,7 +3602,9 @@ int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info) drbd_free_resource(resource); retcode = NO_ERROR; out: - drbd_adm_finish(info, retcode); + mutex_unlock(&resource->adm_mutex); +finish: + drbd_adm_finish(&adm_ctx, info, retcode); return 0; } diff --git a/drivers/block/drbd/drbd_nla.c b/drivers/block/drbd/drbd_nla.c index fa672b6df8d6b1..b2d4791498a660 100644 --- a/drivers/block/drbd/drbd_nla.c +++ b/drivers/block/drbd/drbd_nla.c @@ -1,4 +1,3 @@ -#include "drbd_wrappers.h" #include #include #include diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 2f26e8ffa45b0f..89736bdbbc7044 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -116,7 +116,7 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se /* ------------------------ ~18s average ------------------------ */ i = (device->rs_last_mark + 2) % DRBD_SYNC_MARKS; dt = (jiffies - device->rs_mark_time[i]) / HZ; - if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS)) + if (dt > 180) stalled = 1; if (!dt) diff --git a/drivers/block/drbd/drbd_protocol.h b/drivers/block/drbd/drbd_protocol.h index 3c04ec0ea3330c..2da9104a385181 100644 --- a/drivers/block/drbd/drbd_protocol.h +++ b/drivers/block/drbd/drbd_protocol.h @@ -54,6 +54,11 @@ enum drbd_packet { P_CONN_ST_CHG_REPLY = 0x2b, /* meta sock: Connection side state req reply */ P_RETRY_WRITE = 0x2c, /* Protocol C: retry conflicting write request */ P_PROTOCOL_UPDATE = 0x2d, /* data sock: is used in established connections */ + /* 0x2e to 0x30 reserved, used in drbd 9 */ + + /* REQ_DISCARD. We used "discard" in different contexts before, + * which is why I chose TRIM here, to disambiguate. */ + P_TRIM = 0x31, P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */ P_MAX_OPT_CMD = 0x101, @@ -119,6 +124,11 @@ struct p_data { u32 dp_flags; } __packed; +struct p_trim { + struct p_data p_data; + u32 size; /* == bio->bi_size */ +} __packed; + /* * commands which share a struct: * p_block_ack: @@ -150,6 +160,8 @@ struct p_block_req { * ReportParams */ +#define FF_TRIM 1 + struct p_connection_features { u32 protocol_min; u32 feature_flags; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 68e3992e88381c..b6c8aaf4931bc8 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -46,9 +46,10 @@ #include "drbd_int.h" #include "drbd_protocol.h" #include "drbd_req.h" - #include "drbd_vli.h" +#define PRO_FEATURES (FF_TRIM) + struct packet_info { enum drbd_packet cmd; unsigned int size; @@ -65,7 +66,7 @@ enum finish_epoch { static int drbd_do_features(struct drbd_connection *connection); static int drbd_do_auth(struct drbd_connection *connection); static int drbd_disconnected(struct drbd_peer_device *); - +static void conn_wait_active_ee_empty(struct drbd_connection *connection); static enum finish_epoch drbd_may_finish_epoch(struct drbd_connection *, struct drbd_epoch *, enum epoch_event); static int e_end_block(struct drbd_work *, int); @@ -234,9 +235,17 @@ static void drbd_kick_lo_and_reclaim_net(struct drbd_device *device) * @retry: whether to retry, if not enough pages are available right now * * Tries to allocate number pages, first from our own page pool, then from - * the kernel, unless this allocation would exceed the max_buffers setting. + * the kernel. * Possibly retry until DRBD frees sufficient pages somewhere else. * + * If this allocation would exceed the max_buffers setting, we throttle + * allocation (schedule_timeout) to give the system some room to breathe. + * + * We do not use max-buffers as hard limit, because it could lead to + * congestion and further to a distributed deadlock during online-verify or + * (checksum based) resync, if the max-buffers, socket buffer sizes and + * resync-rate settings are mis-configured. + * * Returns a page chain linked via page->private. */ struct page *drbd_alloc_pages(struct drbd_peer_device *peer_device, unsigned int number, @@ -246,10 +255,8 @@ struct page *drbd_alloc_pages(struct drbd_peer_device *peer_device, unsigned int struct page *page = NULL; struct net_conf *nc; DEFINE_WAIT(wait); - int mxb; + unsigned int mxb; - /* Yes, we may run up to @number over max_buffers. If we - * follow it strictly, the admin will get it wrong anyways. */ rcu_read_lock(); nc = rcu_dereference(peer_device->connection->net_conf); mxb = nc ? nc->max_buffers : 1000000; @@ -277,7 +284,8 @@ struct page *drbd_alloc_pages(struct drbd_peer_device *peer_device, unsigned int break; } - schedule(); + if (schedule_timeout(HZ/10) == 0) + mxb = UINT_MAX; } finish_wait(&drbd_pp_wait, &wait); @@ -331,7 +339,7 @@ You must not have the req_lock: struct drbd_peer_request * drbd_alloc_peer_req(struct drbd_peer_device *peer_device, u64 id, sector_t sector, - unsigned int data_size, gfp_t gfp_mask) __must_hold(local) + unsigned int data_size, bool has_payload, gfp_t gfp_mask) __must_hold(local) { struct drbd_device *device = peer_device->device; struct drbd_peer_request *peer_req; @@ -348,7 +356,7 @@ drbd_alloc_peer_req(struct drbd_peer_device *peer_device, u64 id, sector_t secto return NULL; } - if (data_size) { + if (has_payload && data_size) { page = drbd_alloc_pages(peer_device, nr_pages, (gfp_mask & __GFP_WAIT)); if (!page) goto fail; @@ -1026,24 +1034,27 @@ static int conn_connect(struct drbd_connection *connection) if (drbd_send_protocol(connection) == -EOPNOTSUPP) return -1; + /* Prevent a race between resync-handshake and + * being promoted to Primary. + * + * Grab and release the state mutex, so we know that any current + * drbd_set_role() is finished, and any incoming drbd_set_role + * will see the STATE_SENT flag, and wait for it to be cleared. + */ + idr_for_each_entry(&connection->peer_devices, peer_device, vnr) + mutex_lock(peer_device->device->state_mutex); + set_bit(STATE_SENT, &connection->flags); + idr_for_each_entry(&connection->peer_devices, peer_device, vnr) + mutex_unlock(peer_device->device->state_mutex); + rcu_read_lock(); idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { struct drbd_device *device = peer_device->device; kref_get(&device->kref); rcu_read_unlock(); - /* Prevent a race between resync-handshake and - * being promoted to Primary. - * - * Grab and release the state mutex, so we know that any current - * drbd_set_role() is finished, and any incoming drbd_set_role - * will see the STATE_SENT flag, and wait for it to be cleared. - */ - mutex_lock(device->state_mutex); - mutex_unlock(device->state_mutex); - if (discard_my_data) set_bit(DISCARD_MY_DATA, &device->flags); else @@ -1315,6 +1326,20 @@ int drbd_submit_peer_request(struct drbd_device *device, unsigned nr_pages = (ds + PAGE_SIZE -1) >> PAGE_SHIFT; int err = -ENOMEM; + if (peer_req->flags & EE_IS_TRIM_USE_ZEROOUT) { + /* wait for all pending IO completions, before we start + * zeroing things out. */ + conn_wait_active_ee_empty(first_peer_device(device)->connection); + if (blkdev_issue_zeroout(device->ldev->backing_bdev, + sector, ds >> 9, GFP_NOIO)) + peer_req->flags |= EE_WAS_ERROR; + drbd_endio_write_sec_final(peer_req); + return 0; + } + + if (peer_req->flags & EE_IS_TRIM) + nr_pages = 0; /* discards don't have any payload. */ + /* In most cases, we will only need one bio. But in case the lower * level restrictions happen to be different at this offset on this * side than those of the sending peer, we may need to submit the @@ -1326,7 +1351,7 @@ int drbd_submit_peer_request(struct drbd_device *device, next_bio: bio = bio_alloc(GFP_NOIO, nr_pages); if (!bio) { - drbd_err(device, "submit_ee: Allocation of a bio failed\n"); + drbd_err(device, "submit_ee: Allocation of a bio failed (nr_pages=%u)\n", nr_pages); goto fail; } /* > peer_req->i.sector, unless this is the first bio */ @@ -1340,6 +1365,11 @@ int drbd_submit_peer_request(struct drbd_device *device, bios = bio; ++n_bios; + if (rw & REQ_DISCARD) { + bio->bi_iter.bi_size = ds; + goto submit; + } + page_chain_for_each(page) { unsigned len = min_t(unsigned, ds, PAGE_SIZE); if (!bio_add_page(bio, page, len, 0)) { @@ -1360,8 +1390,9 @@ int drbd_submit_peer_request(struct drbd_device *device, sector += len >> 9; --nr_pages; } - D_ASSERT(device, page == NULL); D_ASSERT(device, ds == 0); +submit: + D_ASSERT(device, page == NULL); atomic_set(&peer_req->pending_bios, n_bios); do { @@ -1490,19 +1521,21 @@ static int receive_Barrier(struct drbd_connection *connection, struct packet_inf * and from receive_Data */ static struct drbd_peer_request * read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector, - int data_size) __must_hold(local) + struct packet_info *pi) __must_hold(local) { struct drbd_device *device = peer_device->device; const sector_t capacity = drbd_get_capacity(device->this_bdev); struct drbd_peer_request *peer_req; struct page *page; int dgs, ds, err; + int data_size = pi->size; void *dig_in = peer_device->connection->int_dig_in; void *dig_vv = peer_device->connection->int_dig_vv; unsigned long *data; + struct p_trim *trim = (pi->cmd == P_TRIM) ? pi->data : NULL; dgs = 0; - if (peer_device->connection->peer_integrity_tfm) { + if (!trim && peer_device->connection->peer_integrity_tfm) { dgs = crypto_hash_digestsize(peer_device->connection->peer_integrity_tfm); /* * FIXME: Receive the incoming digest into the receive buffer @@ -1514,9 +1547,15 @@ read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector, data_size -= dgs; } + if (trim) { + D_ASSERT(peer_device, data_size == 0); + data_size = be32_to_cpu(trim->size); + } + if (!expect(IS_ALIGNED(data_size, 512))) return NULL; - if (!expect(data_size <= DRBD_MAX_BIO_SIZE)) + /* prepare for larger trim requests. */ + if (!trim && !expect(data_size <= DRBD_MAX_BIO_SIZE)) return NULL; /* even though we trust out peer, @@ -1532,11 +1571,11 @@ read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector, /* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD * "criss-cross" setup, that might cause write-out on some other DRBD, * which in turn might block on the other node at this very place. */ - peer_req = drbd_alloc_peer_req(peer_device, id, sector, data_size, GFP_NOIO); + peer_req = drbd_alloc_peer_req(peer_device, id, sector, data_size, trim == NULL, GFP_NOIO); if (!peer_req) return NULL; - if (!data_size) + if (trim) return peer_req; ds = data_size; @@ -1676,12 +1715,12 @@ static int e_end_resync_block(struct drbd_work *w, int unused) } static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t sector, - int data_size) __releases(local) + struct packet_info *pi) __releases(local) { struct drbd_device *device = peer_device->device; struct drbd_peer_request *peer_req; - peer_req = read_in_block(peer_device, ID_SYNCER, sector, data_size); + peer_req = read_in_block(peer_device, ID_SYNCER, sector, pi); if (!peer_req) goto fail; @@ -1697,7 +1736,7 @@ static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t secto list_add(&peer_req->w.list, &device->sync_ee); spin_unlock_irq(&device->resource->req_lock); - atomic_add(data_size >> 9, &device->rs_sect_ev); + atomic_add(pi->size >> 9, &device->rs_sect_ev); if (drbd_submit_peer_request(device, peer_req, WRITE, DRBD_FAULT_RS_WR) == 0) return 0; @@ -1785,7 +1824,7 @@ static int receive_RSDataReply(struct drbd_connection *connection, struct packet /* data is submitted to disk within recv_resync_read. * corresponding put_ldev done below on error, * or in drbd_peer_request_endio. */ - err = recv_resync_read(peer_device, sector, pi->size); + err = recv_resync_read(peer_device, sector, pi); } else { if (__ratelimit(&drbd_ratelimit_state)) drbd_err(device, "Can not write resync data to local disk.\n"); @@ -2196,7 +2235,7 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * */ sector = be64_to_cpu(p->sector); - peer_req = read_in_block(peer_device, p->block_id, sector, pi->size); + peer_req = read_in_block(peer_device, p->block_id, sector, pi); if (!peer_req) { put_ldev(device); return -EIO; @@ -2206,7 +2245,15 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * dp_flags = be32_to_cpu(p->dp_flags); rw |= wire_flags_to_bio(dp_flags); - if (peer_req->pages == NULL) { + if (pi->cmd == P_TRIM) { + struct request_queue *q = bdev_get_queue(device->ldev->backing_bdev); + peer_req->flags |= EE_IS_TRIM; + if (!blk_queue_discard(q)) + peer_req->flags |= EE_IS_TRIM_USE_ZEROOUT; + D_ASSERT(peer_device, peer_req->i.size > 0); + D_ASSERT(peer_device, rw & REQ_DISCARD); + D_ASSERT(peer_device, peer_req->pages == NULL); + } else if (peer_req->pages == NULL) { D_ASSERT(device, peer_req->i.size == 0); D_ASSERT(device, dp_flags & DP_FLUSH); } @@ -2242,7 +2289,12 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * update_peer_seq(peer_device, peer_seq); spin_lock_irq(&device->resource->req_lock); } - list_add(&peer_req->w.list, &device->active_ee); + /* if we use the zeroout fallback code, we process synchronously + * and we wait for all pending requests, respectively wait for + * active_ee to become empty in drbd_submit_peer_request(); + * better not add ourselves here. */ + if ((peer_req->flags & EE_IS_TRIM_USE_ZEROOUT) == 0) + list_add(&peer_req->w.list, &device->active_ee); spin_unlock_irq(&device->resource->req_lock); if (device->state.conn == C_SYNC_TARGET) @@ -2313,39 +2365,45 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * * The current sync rate used here uses only the most recent two step marks, * to have a short time average so we can react faster. */ -int drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector) +bool drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector) { - struct gendisk *disk = device->ldev->backing_bdev->bd_contains->bd_disk; - unsigned long db, dt, dbdt; struct lc_element *tmp; - int curr_events; - int throttle = 0; - unsigned int c_min_rate; - - rcu_read_lock(); - c_min_rate = rcu_dereference(device->ldev->disk_conf)->c_min_rate; - rcu_read_unlock(); + bool throttle = true; - /* feature disabled? */ - if (c_min_rate == 0) - return 0; + if (!drbd_rs_c_min_rate_throttle(device)) + return false; spin_lock_irq(&device->al_lock); tmp = lc_find(device->resync, BM_SECT_TO_EXT(sector)); if (tmp) { struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce); - if (test_bit(BME_PRIORITY, &bm_ext->flags)) { - spin_unlock_irq(&device->al_lock); - return 0; - } + if (test_bit(BME_PRIORITY, &bm_ext->flags)) + throttle = false; /* Do not slow down if app IO is already waiting for this extent */ } spin_unlock_irq(&device->al_lock); + return throttle; +} + +bool drbd_rs_c_min_rate_throttle(struct drbd_device *device) +{ + struct gendisk *disk = device->ldev->backing_bdev->bd_contains->bd_disk; + unsigned long db, dt, dbdt; + unsigned int c_min_rate; + int curr_events; + + rcu_read_lock(); + c_min_rate = rcu_dereference(device->ldev->disk_conf)->c_min_rate; + rcu_read_unlock(); + + /* feature disabled? */ + if (c_min_rate == 0) + return false; + curr_events = (int)part_stat_read(&disk->part0, sectors[0]) + (int)part_stat_read(&disk->part0, sectors[1]) - atomic_read(&device->rs_sect_ev); - if (!device->rs_last_events || curr_events - device->rs_last_events > 64) { unsigned long rs_left; int i; @@ -2368,12 +2426,11 @@ int drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector) dbdt = Bit2KB(db/dt); if (dbdt > c_min_rate) - throttle = 1; + return true; } - return throttle; + return false; } - static int receive_DataRequest(struct drbd_connection *connection, struct packet_info *pi) { struct drbd_peer_device *peer_device; @@ -2436,7 +2493,8 @@ static int receive_DataRequest(struct drbd_connection *connection, struct packet /* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD * "criss-cross" setup, that might cause write-out on some other DRBD, * which in turn might block on the other node at this very place. */ - peer_req = drbd_alloc_peer_req(peer_device, p->block_id, sector, size, GFP_NOIO); + peer_req = drbd_alloc_peer_req(peer_device, p->block_id, sector, size, + true /* has real payload */, GFP_NOIO); if (!peer_req) { put_ldev(device); return -ENOMEM; @@ -3648,6 +3706,13 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info put_ldev(device); } + device->peer_max_bio_size = be32_to_cpu(p->max_bio_size); + drbd_reconsider_max_bio_size(device); + /* Leave drbd_reconsider_max_bio_size() before drbd_determine_dev_size(). + In case we cleared the QUEUE_FLAG_DISCARD from our queue in + drbd_reconsider_max_bio_size(), we can be sure that after + drbd_determine_dev_size() no REQ_DISCARDs are in the queue. */ + ddsf = be16_to_cpu(p->dds_flags); if (get_ldev(device)) { dd = drbd_determine_dev_size(device, ddsf, NULL); @@ -3660,9 +3725,6 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info drbd_set_my_capacity(device, p_size); } - device->peer_max_bio_size = be32_to_cpu(p->max_bio_size); - drbd_reconsider_max_bio_size(device); - if (get_ldev(device)) { if (device->ldev->known_size != drbd_get_capacity(device->ldev->backing_bdev)) { device->ldev->known_size = drbd_get_capacity(device->ldev->backing_bdev); @@ -4423,6 +4485,7 @@ static struct data_cmd drbd_cmd_handler[] = { [P_OUT_OF_SYNC] = { 0, sizeof(struct p_block_desc), receive_out_of_sync }, [P_CONN_ST_CHG_REQ] = { 0, sizeof(struct p_req_state), receive_req_conn_state }, [P_PROTOCOL_UPDATE] = { 1, sizeof(struct p_protocol), receive_protocol }, + [P_TRIM] = { 0, sizeof(struct p_trim), receive_Data }, }; static void drbdd(struct drbd_connection *connection) @@ -4630,6 +4693,7 @@ static int drbd_send_features(struct drbd_connection *connection) memset(p, 0, sizeof(*p)); p->protocol_min = cpu_to_be32(PRO_VERSION_MIN); p->protocol_max = cpu_to_be32(PRO_VERSION_MAX); + p->feature_flags = cpu_to_be32(PRO_FEATURES); return conn_send_command(connection, sock, P_CONNECTION_FEATURES, sizeof(*p), NULL, 0); } @@ -4683,10 +4747,14 @@ static int drbd_do_features(struct drbd_connection *connection) goto incompat; connection->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max); + connection->agreed_features = PRO_FEATURES & be32_to_cpu(p->feature_flags); drbd_info(connection, "Handshake successful: " "Agreed network protocol version %d\n", connection->agreed_pro_version); + drbd_info(connection, "Agreed to%ssupport TRIM on protocol level\n", + connection->agreed_features & FF_TRIM ? " " : " not "); + return 1; incompat: @@ -4778,6 +4846,12 @@ static int drbd_do_auth(struct drbd_connection *connection) goto fail; } + if (pi.size < CHALLENGE_LEN) { + drbd_err(connection, "AuthChallenge payload too small.\n"); + rv = -1; + goto fail; + } + peers_ch = kmalloc(pi.size, GFP_NOIO); if (peers_ch == NULL) { drbd_err(connection, "kmalloc of peers_ch failed\n"); @@ -4791,6 +4865,12 @@ static int drbd_do_auth(struct drbd_connection *connection) goto fail; } + if (!memcmp(my_challenge, peers_ch, CHALLENGE_LEN)) { + drbd_err(connection, "Peer presented the same challenge!\n"); + rv = -1; + goto fail; + } + resp_size = crypto_hash_digestsize(connection->cram_hmac_tfm); response = kmalloc(resp_size, GFP_NOIO); if (response == NULL) { diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 3779c8d2875bb0..09803d0d5207ce 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -522,6 +522,13 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, mod_rq_state(req, m, RQ_LOCAL_PENDING, RQ_LOCAL_COMPLETED); break; + case DISCARD_COMPLETED_NOTSUPP: + case DISCARD_COMPLETED_WITH_ERROR: + /* I'd rather not detach from local disk just because it + * failed a REQ_DISCARD. */ + mod_rq_state(req, m, RQ_LOCAL_PENDING, RQ_LOCAL_COMPLETED); + break; + case QUEUE_FOR_NET_READ: /* READ or READA, and * no local disk, @@ -1235,6 +1242,7 @@ void do_submit(struct work_struct *ws) if (list_empty(&incoming)) break; +skip_fast_path: wait_event(device->al_wait, prepare_al_transaction_nonblock(device, &incoming, &pending)); /* Maybe more was queued, while we prepared the transaction? * Try to stuff them into this transaction as well. @@ -1273,6 +1281,25 @@ void do_submit(struct work_struct *ws) list_del_init(&req->tl_requests); drbd_send_and_submit(device, req); } + + /* If all currently hot activity log extents are kept busy by + * incoming requests, we still must not totally starve new + * requests to cold extents. In that case, prepare one request + * in blocking mode. */ + list_for_each_entry_safe(req, tmp, &incoming, tl_requests) { + list_del_init(&req->tl_requests); + req->rq_state |= RQ_IN_ACT_LOG; + if (!drbd_al_begin_io_prepare(device, &req->i)) { + /* Corresponding extent was hot after all? */ + drbd_send_and_submit(device, req); + } else { + /* Found a request to a cold extent. + * Put on "pending" list, + * and try to cumulate with more. */ + list_add(&req->tl_requests, &pending); + goto skip_fast_path; + } + } } } @@ -1326,23 +1353,35 @@ int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct return limit; } -static struct drbd_request *find_oldest_request(struct drbd_connection *connection) +static void find_oldest_requests( + struct drbd_connection *connection, + struct drbd_device *device, + struct drbd_request **oldest_req_waiting_for_peer, + struct drbd_request **oldest_req_waiting_for_disk) { - /* Walk the transfer log, - * and find the oldest not yet completed request */ struct drbd_request *r; + *oldest_req_waiting_for_peer = NULL; + *oldest_req_waiting_for_disk = NULL; list_for_each_entry(r, &connection->transfer_log, tl_requests) { - if (atomic_read(&r->completion_ref)) - return r; + const unsigned s = r->rq_state; + if (!*oldest_req_waiting_for_peer + && ((s & RQ_NET_MASK) && !(s & RQ_NET_DONE))) + *oldest_req_waiting_for_peer = r; + + if (!*oldest_req_waiting_for_disk + && (s & RQ_LOCAL_PENDING) && r->device == device) + *oldest_req_waiting_for_disk = r; + + if (*oldest_req_waiting_for_peer && *oldest_req_waiting_for_disk) + break; } - return NULL; } void request_timer_fn(unsigned long data) { struct drbd_device *device = (struct drbd_device *) data; struct drbd_connection *connection = first_peer_device(device)->connection; - struct drbd_request *req; /* oldest request */ + struct drbd_request *req_disk, *req_peer; /* oldest request */ struct net_conf *nc; unsigned long ent = 0, dt = 0, et, nt; /* effective timeout = ko_count * timeout */ unsigned long now; @@ -1366,8 +1405,8 @@ void request_timer_fn(unsigned long data) now = jiffies; spin_lock_irq(&device->resource->req_lock); - req = find_oldest_request(connection); - if (!req) { + find_oldest_requests(connection, device, &req_peer, &req_disk); + if (req_peer == NULL && req_disk == NULL) { spin_unlock_irq(&device->resource->req_lock); mod_timer(&device->request_timer, now + et); return; @@ -1389,19 +1428,26 @@ void request_timer_fn(unsigned long data) * ~198 days with 250 HZ, we have a window where the timeout would need * to expire twice (worst case) to become effective. Good enough. */ - if (ent && req->rq_state & RQ_NET_PENDING && - time_after(now, req->start_time + ent) && + if (ent && req_peer && + time_after(now, req_peer->start_time + ent) && !time_in_range(now, connection->last_reconnect_jif, connection->last_reconnect_jif + ent)) { drbd_warn(device, "Remote failed to finish a request within ko-count * timeout\n"); _drbd_set_state(_NS(device, conn, C_TIMEOUT), CS_VERBOSE | CS_HARD, NULL); } - if (dt && req->rq_state & RQ_LOCAL_PENDING && req->device == device && - time_after(now, req->start_time + dt) && + if (dt && req_disk && + time_after(now, req_disk->start_time + dt) && !time_in_range(now, device->last_reattach_jif, device->last_reattach_jif + dt)) { drbd_warn(device, "Local backing device failed to meet the disk-timeout\n"); __drbd_chk_io_error(device, DRBD_FORCE_DETACH); } - nt = (time_after(now, req->start_time + et) ? now : req->start_time) + et; + + /* Reschedule timer for the nearest not already expired timeout. + * Fallback to now + min(effective network timeout, disk timeout). */ + ent = (ent && req_peer && time_before(now, req_peer->start_time + ent)) + ? req_peer->start_time + ent : now + et; + dt = (dt && req_disk && time_before(now, req_disk->start_time + dt)) + ? req_disk->start_time + dt : now + et; + nt = time_before(ent, dt) ? ent : dt; spin_unlock_irq(&connection->resource->req_lock); mod_timer(&device->request_timer, nt); } diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index c684c963538ea8..8566cd5866b4e2 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -30,7 +30,6 @@ #include #include #include "drbd_int.h" -#include "drbd_wrappers.h" /* The request callbacks will be called in irq context by the IDE drivers, and in Softirqs/Tasklets/BH context by the SCSI drivers, @@ -111,11 +110,14 @@ enum drbd_req_event { BARRIER_ACKED, /* in protocol A and B */ DATA_RECEIVED, /* (remote read) */ + COMPLETED_OK, READ_COMPLETED_WITH_ERROR, READ_AHEAD_COMPLETED_WITH_ERROR, WRITE_COMPLETED_WITH_ERROR, + DISCARD_COMPLETED_NOTSUPP, + DISCARD_COMPLETED_WITH_ERROR, + ABORT_DISK_IO, - COMPLETED_OK, RESEND, FAIL_FROZEN_DISK_IO, RESTART_FROZEN_DISK_IO, diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 1a84345a3868b9..a5d8aae00e04c9 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -54,8 +54,8 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os, static enum drbd_state_rv is_valid_state(struct drbd_device *, union drbd_state); static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state, struct drbd_connection *); static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns); -static union drbd_state sanitize_state(struct drbd_device *device, union drbd_state ns, - enum sanitize_state_warnings *warn); +static union drbd_state sanitize_state(struct drbd_device *device, union drbd_state os, + union drbd_state ns, enum sanitize_state_warnings *warn); static inline bool is_susp(union drbd_state s) { @@ -287,7 +287,7 @@ _req_st_cond(struct drbd_device *device, union drbd_state mask, spin_lock_irqsave(&device->resource->req_lock, flags); os = drbd_read_state(device); - ns = sanitize_state(device, apply_mask_val(os, mask, val), NULL); + ns = sanitize_state(device, os, apply_mask_val(os, mask, val), NULL); rv = is_valid_transition(os, ns); if (rv >= SS_SUCCESS) rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ @@ -333,7 +333,7 @@ drbd_req_state(struct drbd_device *device, union drbd_state mask, spin_lock_irqsave(&device->resource->req_lock, flags); os = drbd_read_state(device); - ns = sanitize_state(device, apply_mask_val(os, mask, val), NULL); + ns = sanitize_state(device, os, apply_mask_val(os, mask, val), NULL); rv = is_valid_transition(os, ns); if (rv < SS_SUCCESS) { spin_unlock_irqrestore(&device->resource->req_lock, flags); @@ -740,8 +740,8 @@ static void print_sanitize_warnings(struct drbd_device *device, enum sanitize_st * When we loose connection, we have to set the state of the peers disk (pdsk) * to D_UNKNOWN. This rule and many more along those lines are in this function. */ -static union drbd_state sanitize_state(struct drbd_device *device, union drbd_state ns, - enum sanitize_state_warnings *warn) +static union drbd_state sanitize_state(struct drbd_device *device, union drbd_state os, + union drbd_state ns, enum sanitize_state_warnings *warn) { enum drbd_fencing_p fp; enum drbd_disk_state disk_min, disk_max, pdsk_min, pdsk_max; @@ -882,11 +882,13 @@ static union drbd_state sanitize_state(struct drbd_device *device, union drbd_st } if (fp == FP_STONITH && - (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED)) + (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) && + !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED)) ns.susp_fen = 1; /* Suspend IO while fence-peer handler runs (peer lost) */ if (device->resource->res_opts.on_no_data == OND_SUSPEND_IO && - (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE)) + (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) && + !(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE)) ns.susp_nod = 1; /* Suspend IO while no data available (no accessible data available) */ if (ns.aftr_isp || ns.peer_isp || ns.user_isp) { @@ -958,7 +960,7 @@ __drbd_set_state(struct drbd_device *device, union drbd_state ns, os = drbd_read_state(device); - ns = sanitize_state(device, ns, &ssw); + ns = sanitize_state(device, os, ns, &ssw); if (ns.i == os.i) return SS_NOTHING_TO_DO; @@ -1656,7 +1658,7 @@ conn_is_valid_transition(struct drbd_connection *connection, union drbd_state ma idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { struct drbd_device *device = peer_device->device; os = drbd_read_state(device); - ns = sanitize_state(device, apply_mask_val(os, mask, val), NULL); + ns = sanitize_state(device, os, apply_mask_val(os, mask, val), NULL); if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED) ns.disk = os.disk; @@ -1718,7 +1720,7 @@ conn_set_state(struct drbd_connection *connection, union drbd_state mask, union number_of_volumes++; os = drbd_read_state(device); ns = apply_mask_val(os, mask, val); - ns = sanitize_state(device, ns, NULL); + ns = sanitize_state(device, os, ns, NULL); if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED) ns.disk = os.disk; @@ -1763,19 +1765,19 @@ conn_set_state(struct drbd_connection *connection, union drbd_state mask, union static enum drbd_state_rv _conn_rq_cond(struct drbd_connection *connection, union drbd_state mask, union drbd_state val) { - enum drbd_state_rv rv; + enum drbd_state_rv err, rv = SS_UNKNOWN_ERROR; /* continue waiting */; if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &connection->flags)) - return SS_CW_SUCCESS; + rv = SS_CW_SUCCESS; if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &connection->flags)) - return SS_CW_FAILED_BY_PEER; + rv = SS_CW_FAILED_BY_PEER; - rv = conn_is_valid_transition(connection, mask, val, 0); - if (rv == SS_SUCCESS && connection->cstate == C_WF_REPORT_PARAMS) - rv = SS_UNKNOWN_ERROR; /* continue waiting */ + err = conn_is_valid_transition(connection, mask, val, 0); + if (err == SS_SUCCESS && connection->cstate == C_WF_REPORT_PARAMS) + return rv; - return rv; + return err; } enum drbd_state_rv diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 2c4ce42c365788..d8f57b6305cd6f 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -118,7 +118,7 @@ static void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __rele /* writes on behalf of the partner, or resync writes, * "submitted" by the receiver, final stage. */ -static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(local) +void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(local) { unsigned long flags = 0; struct drbd_peer_device *peer_device = peer_req->peer_device; @@ -150,7 +150,9 @@ static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __rel do_wake = list_empty(block_id == ID_SYNCER ? &device->sync_ee : &device->active_ee); - if (test_bit(__EE_WAS_ERROR, &peer_req->flags)) + /* FIXME do we want to detach for failed REQ_DISCARD? + * ((peer_req->flags & (EE_WAS_ERROR|EE_IS_TRIM)) == EE_WAS_ERROR) */ + if (peer_req->flags & EE_WAS_ERROR) __drbd_chk_io_error(device, DRBD_WRITE_ERROR); spin_unlock_irqrestore(&device->resource->req_lock, flags); @@ -176,10 +178,12 @@ void drbd_peer_request_endio(struct bio *bio, int error) struct drbd_device *device = peer_req->peer_device->device; int uptodate = bio_flagged(bio, BIO_UPTODATE); int is_write = bio_data_dir(bio) == WRITE; + int is_discard = !!(bio->bi_rw & REQ_DISCARD); if (error && __ratelimit(&drbd_ratelimit_state)) drbd_warn(device, "%s: error=%d s=%llus\n", - is_write ? "write" : "read", error, + is_write ? (is_discard ? "discard" : "write") + : "read", error, (unsigned long long)peer_req->i.sector); if (!error && !uptodate) { if (__ratelimit(&drbd_ratelimit_state)) @@ -263,7 +267,12 @@ void drbd_request_endio(struct bio *bio, int error) /* to avoid recursion in __req_mod */ if (unlikely(error)) { - what = (bio_data_dir(bio) == WRITE) + if (bio->bi_rw & REQ_DISCARD) + what = (error == -EOPNOTSUPP) + ? DISCARD_COMPLETED_NOTSUPP + : DISCARD_COMPLETED_WITH_ERROR; + else + what = (bio_data_dir(bio) == WRITE) ? WRITE_COMPLETED_WITH_ERROR : (bio_rw(bio) == READ) ? READ_COMPLETED_WITH_ERROR @@ -395,7 +404,7 @@ static int read_for_csum(struct drbd_peer_device *peer_device, sector_t sector, /* GFP_TRY, because if there is no memory available right now, this may * be rescheduled for later. It is "only" background resync, after all. */ peer_req = drbd_alloc_peer_req(peer_device, ID_SYNCER /* unused */, sector, - size, GFP_TRY); + size, true /* has real payload */, GFP_TRY); if (!peer_req) goto defer; @@ -492,10 +501,9 @@ struct fifo_buffer *fifo_alloc(int fifo_size) return fb; } -static int drbd_rs_controller(struct drbd_device *device) +static int drbd_rs_controller(struct drbd_device *device, unsigned int sect_in) { struct disk_conf *dc; - unsigned int sect_in; /* Number of sectors that came in since the last turn */ unsigned int want; /* The number of sectors we want in the proxy */ int req_sect; /* Number of sectors to request in this turn */ int correction; /* Number of sectors more we need in the proxy*/ @@ -505,9 +513,6 @@ static int drbd_rs_controller(struct drbd_device *device) int max_sect; struct fifo_buffer *plan; - sect_in = atomic_xchg(&device->rs_sect_in, 0); /* Number of sectors that came in */ - device->rs_in_flight -= sect_in; - dc = rcu_dereference(device->ldev->disk_conf); plan = rcu_dereference(device->rs_plan_s); @@ -550,11 +555,16 @@ static int drbd_rs_controller(struct drbd_device *device) static int drbd_rs_number_requests(struct drbd_device *device) { - int number; + unsigned int sect_in; /* Number of sectors that came in since the last turn */ + int number, mxb; + + sect_in = atomic_xchg(&device->rs_sect_in, 0); + device->rs_in_flight -= sect_in; rcu_read_lock(); + mxb = drbd_get_max_buffers(device) / 2; if (rcu_dereference(device->rs_plan_s)->size) { - number = drbd_rs_controller(device) >> (BM_BLOCK_SHIFT - 9); + number = drbd_rs_controller(device, sect_in) >> (BM_BLOCK_SHIFT - 9); device->c_sync_rate = number * HZ * (BM_BLOCK_SIZE / 1024) / SLEEP_TIME; } else { device->c_sync_rate = rcu_dereference(device->ldev->disk_conf)->resync_rate; @@ -562,8 +572,14 @@ static int drbd_rs_number_requests(struct drbd_device *device) } rcu_read_unlock(); - /* ignore the amount of pending requests, the resync controller should - * throttle down to incoming reply rate soon enough anyways. */ + /* Don't have more than "max-buffers"/2 in-flight. + * Otherwise we may cause the remote site to stall on drbd_alloc_pages(), + * potentially causing a distributed deadlock on congestion during + * online-verify or (checksum-based) resync, if max-buffers, + * socket buffer sizes and resync rate settings are mis-configured. */ + if (mxb - device->rs_in_flight < number) + number = mxb - device->rs_in_flight; + return number; } @@ -597,7 +613,7 @@ static int make_resync_request(struct drbd_device *device, int cancel) max_bio_size = queue_max_hw_sectors(device->rq_queue) << 9; number = drbd_rs_number_requests(device); - if (number == 0) + if (number <= 0) goto requeue; for (i = 0; i < number; i++) { @@ -647,7 +663,7 @@ static int make_resync_request(struct drbd_device *device, int cancel) */ align = 1; rollback_i = i; - for (;;) { + while (i < number) { if (size + BM_BLOCK_SIZE > max_bio_size) break; @@ -1670,11 +1686,15 @@ void drbd_start_resync(struct drbd_device *device, enum drbd_conns side) } clear_bit(B_RS_H_DONE, &device->flags); - write_lock_irq(&global_state_lock); + /* req_lock: serialize with drbd_send_and_submit() and others + * global_state_lock: for stable sync-after dependencies */ + spin_lock_irq(&device->resource->req_lock); + write_lock(&global_state_lock); /* Did some connection breakage or IO error race with us? */ if (device->state.conn < C_CONNECTED || !get_ldev_if_state(device, D_NEGOTIATING)) { - write_unlock_irq(&global_state_lock); + write_unlock(&global_state_lock); + spin_unlock_irq(&device->resource->req_lock); mutex_unlock(device->state_mutex); return; } @@ -1714,7 +1734,8 @@ void drbd_start_resync(struct drbd_device *device, enum drbd_conns side) } _drbd_pause_after(device); } - write_unlock_irq(&global_state_lock); + write_unlock(&global_state_lock); + spin_unlock_irq(&device->resource->req_lock); if (r == SS_SUCCESS) { /* reset rs_last_bcast when a resync or verify is started, @@ -1778,34 +1799,6 @@ void drbd_start_resync(struct drbd_device *device, enum drbd_conns side) mutex_unlock(device->state_mutex); } -/* If the resource already closed the current epoch, but we did not - * (because we have not yet seen new requests), we should send the - * corresponding barrier now. Must be checked within the same spinlock - * that is used to check for new requests. */ -static bool need_to_send_barrier(struct drbd_connection *connection) -{ - if (!connection->send.seen_any_write_yet) - return false; - - /* Skip barriers that do not contain any writes. - * This may happen during AHEAD mode. */ - if (!connection->send.current_epoch_writes) - return false; - - /* ->req_lock is held when requests are queued on - * connection->sender_work, and put into ->transfer_log. - * It is also held when ->current_tle_nr is increased. - * So either there are already new requests queued, - * and corresponding barriers will be send there. - * Or nothing new is queued yet, so the difference will be 1. - */ - if (atomic_read(&connection->current_tle_nr) != - connection->send.current_epoch_nr + 1) - return false; - - return true; -} - static bool dequeue_work_batch(struct drbd_work_queue *queue, struct list_head *work_list) { spin_lock_irq(&queue->q_lock); @@ -1864,12 +1857,22 @@ static void wait_for_work(struct drbd_connection *connection, struct list_head * spin_unlock_irq(&connection->resource->req_lock); break; } - send_barrier = need_to_send_barrier(connection); + + /* We found nothing new to do, no to-be-communicated request, + * no other work item. We may still need to close the last + * epoch. Next incoming request epoch will be connection -> + * current transfer log epoch number. If that is different + * from the epoch of the last request we communicated, it is + * safe to send the epoch separating barrier now. + */ + send_barrier = + atomic_read(&connection->current_tle_nr) != + connection->send.current_epoch_nr; spin_unlock_irq(&connection->resource->req_lock); - if (send_barrier) { - drbd_send_barrier(connection); - connection->send.current_epoch_nr++; - } + + if (send_barrier) + maybe_send_barrier(connection, + connection->send.current_epoch_nr + 1); schedule(); /* may be woken up for other things but new work, too, * e.g. if the current epoch got closed. diff --git a/drivers/block/drbd/drbd_wrappers.h b/drivers/block/drbd/drbd_wrappers.h deleted file mode 100644 index 3db9ebaf64f6c0..00000000000000 --- a/drivers/block/drbd/drbd_wrappers.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef _DRBD_WRAPPERS_H -#define _DRBD_WRAPPERS_H - -#include -#include -#include "drbd_int.h" - -/* see get_sb_bdev and bd_claim */ -extern char *drbd_sec_holder; - -/* sets the number of 512 byte sectors of our virtual device */ -static inline void drbd_set_my_capacity(struct drbd_device *device, - sector_t size) -{ - /* set_capacity(device->this_bdev->bd_disk, size); */ - set_capacity(device->vdisk, size); - device->this_bdev->bd_inode->i_size = (loff_t)size << 9; -} - -#define drbd_bio_uptodate(bio) bio_flagged(bio, BIO_UPTODATE) - -/* bi_end_io handlers */ -extern void drbd_md_io_complete(struct bio *bio, int error); -extern void drbd_peer_request_endio(struct bio *bio, int error); -extern void drbd_request_endio(struct bio *bio, int error); - -/* - * used to submit our private bio - */ -static inline void drbd_generic_make_request(struct drbd_device *device, - int fault_type, struct bio *bio) -{ - __release(local); - if (!bio->bi_bdev) { - printk(KERN_ERR "drbd%d: drbd_generic_make_request: " - "bio->bi_bdev == NULL\n", - device_to_minor(device)); - dump_stack(); - bio_endio(bio, -ENODEV); - return; - } - - if (drbd_insert_fault(device, fault_type)) - bio_endio(bio, -EIO); - else - generic_make_request(bio); -} - -#ifndef __CHECKER__ -# undef __cond_lock -# define __cond_lock(x,c) (c) -#endif - -#endif diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index fa9bb742df6e0b..dc3a41c82b38a1 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2351,7 +2351,7 @@ static void rw_interrupt(void) } if (CT(COMMAND) != FD_READ || - raw_cmd->kernel_data == current_req->buffer) { + raw_cmd->kernel_data == bio_data(current_req->bio)) { /* transfer directly from buffer */ cont->done(1); } else if (CT(COMMAND) == FD_READ) { @@ -2640,7 +2640,7 @@ static int make_raw_rw_request(void) raw_cmd->flags &= ~FD_RAW_WRITE; raw_cmd->flags |= FD_RAW_READ; COMMAND = FM_MODE(_floppy, FD_READ); - } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) { + } else if ((unsigned long)bio_data(current_req->bio) < MAX_DMA_ADDRESS) { unsigned long dma_limit; int direct, indirect; @@ -2654,13 +2654,13 @@ static int make_raw_rw_request(void) */ max_size = buffer_chain_size(); dma_limit = (MAX_DMA_ADDRESS - - ((unsigned long)current_req->buffer)) >> 9; + ((unsigned long)bio_data(current_req->bio))) >> 9; if ((unsigned long)max_size > dma_limit) max_size = dma_limit; /* 64 kb boundaries */ - if (CROSS_64KB(current_req->buffer, max_size << 9)) + if (CROSS_64KB(bio_data(current_req->bio), max_size << 9)) max_size = (K_64 - - ((unsigned long)current_req->buffer) % + ((unsigned long)bio_data(current_req->bio)) % K_64) >> 9; direct = transfer_size(ssize, max_sector, max_size) - fsector_t; /* @@ -2677,7 +2677,7 @@ static int make_raw_rw_request(void) (DP->read_track & (1 << DRS->probed_format)))))) { max_size = blk_rq_sectors(current_req); } else { - raw_cmd->kernel_data = current_req->buffer; + raw_cmd->kernel_data = bio_data(current_req->bio); raw_cmd->length = current_count_sectors << 9; if (raw_cmd->length == 0) { DPRINT("%s: zero dma transfer attempted\n", __func__); @@ -2731,7 +2731,7 @@ static int make_raw_rw_request(void) raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1; raw_cmd->length <<= 9; if ((raw_cmd->length < current_count_sectors << 9) || - (raw_cmd->kernel_data != current_req->buffer && + (raw_cmd->kernel_data != bio_data(current_req->bio) && CT(COMMAND) == FD_WRITE && (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max || aligned_sector_t < buffer_min)) || @@ -2739,7 +2739,7 @@ static int make_raw_rw_request(void) raw_cmd->length <= 0 || current_count_sectors <= 0) { DPRINT("fractionary current count b=%lx s=%lx\n", raw_cmd->length, current_count_sectors); - if (raw_cmd->kernel_data != current_req->buffer) + if (raw_cmd->kernel_data != bio_data(current_req->bio)) pr_info("addr=%d, length=%ld\n", (int)((raw_cmd->kernel_data - floppy_track_buffer) >> 9), @@ -2756,7 +2756,7 @@ static int make_raw_rw_request(void) return 0; } - if (raw_cmd->kernel_data != current_req->buffer) { + if (raw_cmd->kernel_data != bio_data(current_req->bio)) { if (raw_cmd->kernel_data < floppy_track_buffer || current_count_sectors < 0 || raw_cmd->length < 0 || diff --git a/drivers/block/hd.c b/drivers/block/hd.c index bf397bf108b75d..8a290c08262f26 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -464,11 +464,11 @@ static void read_intr(void) ok_to_read: req = hd_req; - insw(HD_DATA, req->buffer, 256); + insw(HD_DATA, bio_data(req->bio), 256); #ifdef DEBUG printk("%s: read: sector %ld, remaining = %u, buffer=%p\n", req->rq_disk->disk_name, blk_rq_pos(req) + 1, - blk_rq_sectors(req) - 1, req->buffer+512); + blk_rq_sectors(req) - 1, bio_data(req->bio)+512); #endif if (hd_end_request(0, 512)) { SET_HANDLER(&read_intr); @@ -505,7 +505,7 @@ static void write_intr(void) ok_to_write: if (hd_end_request(0, 512)) { SET_HANDLER(&write_intr); - outsw(HD_DATA, req->buffer, 256); + outsw(HD_DATA, bio_data(req->bio), 256); return; } @@ -624,7 +624,7 @@ static void hd_request(void) printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n", req->rq_disk->disk_name, req_data_dir(req) == READ ? "read" : "writ", - cyl, head, sec, nsect, req->buffer); + cyl, head, sec, nsect, bio_data(req->bio)); #endif if (req->cmd_type == REQ_TYPE_FS) { switch (rq_data_dir(req)) { @@ -643,7 +643,7 @@ static void hd_request(void) bad_rw_intr(); goto repeat; } - outsw(HD_DATA, req->buffer, 256); + outsw(HD_DATA, bio_data(req->bio), 256); break; default: printk("unknown hd-command\n"); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f70a230a294522..6cb1beb47c25d1 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -548,7 +548,7 @@ static int loop_thread(void *data) struct loop_device *lo = data; struct bio *bio; - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); while (!kthread_should_stop() || !bio_list_empty(&lo->lo_bio_list)) { diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index eb59b124136690..e352cac707e82f 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -479,7 +479,7 @@ static unsigned int mg_out(struct mg_host *host, static void mg_read_one(struct mg_host *host, struct request *req) { - u16 *buff = (u16 *)req->buffer; + u16 *buff = (u16 *)bio_data(req->bio); u32 i; for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) @@ -496,7 +496,7 @@ static void mg_read(struct request *req) mg_bad_rw_intr(host); MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", - blk_rq_sectors(req), blk_rq_pos(req), req->buffer); + blk_rq_sectors(req), blk_rq_pos(req), bio_data(req->bio)); do { if (mg_wait(host, ATA_DRQ, @@ -514,7 +514,7 @@ static void mg_read(struct request *req) static void mg_write_one(struct mg_host *host, struct request *req) { - u16 *buff = (u16 *)req->buffer; + u16 *buff = (u16 *)bio_data(req->bio); u32 i; for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) @@ -534,7 +534,7 @@ static void mg_write(struct request *req) } MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", - rem, blk_rq_pos(req), req->buffer); + rem, blk_rq_pos(req), bio_data(req->bio)); if (mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { @@ -585,7 +585,7 @@ static void mg_read_intr(struct mg_host *host) mg_read_one(host, req); MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", - blk_rq_pos(req), blk_rq_sectors(req) - 1, req->buffer); + blk_rq_pos(req), blk_rq_sectors(req) - 1, bio_data(req->bio)); /* send read confirm */ outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); @@ -624,7 +624,7 @@ static void mg_write_intr(struct mg_host *host) /* write 1 sector and set handler if remains */ mg_write_one(host, req); MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", - blk_rq_pos(req), blk_rq_sectors(req), req->buffer); + blk_rq_pos(req), blk_rq_sectors(req), bio_data(req->bio)); host->mg_do_intr = mg_write_intr; mod_timer(&host->timer, jiffies + 3 * HZ); } diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 59c5abe32f06f0..3a0882ee16422b 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -173,60 +174,36 @@ static bool mtip_check_surprise_removal(struct pci_dev *pdev) return false; /* device present */ } -/* - * Obtain an empty command slot. - * - * This function needs to be reentrant since it could be called - * at the same time on multiple CPUs. The allocation of the - * command slot must be atomic. - * - * @port Pointer to the port data structure. - * - * return value - * >= 0 Index of command slot obtained. - * -1 No command slots available. - */ -static int get_slot(struct mtip_port *port) +static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd) { - int slot, i; - unsigned int num_command_slots = port->dd->slot_groups * 32; + struct request *rq; - /* - * Try 10 times, because there is a small race here. - * that's ok, because it's still cheaper than a lock. - * - * Race: Since this section is not protected by lock, same bit - * could be chosen by different process contexts running in - * different processor. So instead of costly lock, we are going - * with loop. - */ - for (i = 0; i < 10; i++) { - slot = find_next_zero_bit(port->allocated, - num_command_slots, 1); - if ((slot < num_command_slots) && - (!test_and_set_bit(slot, port->allocated))) - return slot; - } - dev_warn(&port->dd->pdev->dev, "Failed to get a tag.\n"); + rq = blk_mq_alloc_reserved_request(dd->queue, 0, __GFP_WAIT); + return blk_mq_rq_to_pdu(rq); +} - mtip_check_surprise_removal(port->dd->pdev); - return -1; +static void mtip_put_int_command(struct driver_data *dd, struct mtip_cmd *cmd) +{ + blk_put_request(blk_mq_rq_from_pdu(cmd)); } /* - * Release a command slot. - * - * @port Pointer to the port data structure. - * @tag Tag of command to release - * - * return value - * None + * Once we add support for one hctx per mtip group, this will change a bit */ -static inline void release_slot(struct mtip_port *port, int tag) +static struct request *mtip_rq_from_tag(struct driver_data *dd, + unsigned int tag) { - smp_mb__before_clear_bit(); - clear_bit(tag, port->allocated); - smp_mb__after_clear_bit(); + struct blk_mq_hw_ctx *hctx = dd->queue->queue_hw_ctx[0]; + + return blk_mq_tag_to_rq(hctx->tags, tag); +} + +static struct mtip_cmd *mtip_cmd_from_tag(struct driver_data *dd, + unsigned int tag) +{ + struct request *rq = mtip_rq_from_tag(dd, tag); + + return blk_mq_rq_to_pdu(rq); } /* @@ -248,93 +225,28 @@ static inline void release_slot(struct mtip_port *port, int tag) * None */ static void mtip_async_complete(struct mtip_port *port, - int tag, - void *data, - int status) + int tag, struct mtip_cmd *cmd, int status) { - struct mtip_cmd *cmd; - struct driver_data *dd = data; - int unaligned, cb_status = status ? -EIO : 0; - void (*func)(void *, int); + struct driver_data *dd = port->dd; + struct request *rq; if (unlikely(!dd) || unlikely(!port)) return; - cmd = &port->commands[tag]; - if (unlikely(status == PORT_IRQ_TF_ERR)) { dev_warn(&port->dd->pdev->dev, "Command tag %d failed due to TFE\n", tag); } - /* Clear the active flag */ - atomic_set(&port->commands[tag].active, 0); - - /* Upper layer callback */ - func = cmd->async_callback; - if (likely(func && cmpxchg(&cmd->async_callback, func, 0) == func)) { - - /* Unmap the DMA scatter list entries */ - dma_unmap_sg(&dd->pdev->dev, - cmd->sg, - cmd->scatter_ents, - cmd->direction); - - func(cmd->async_data, cb_status); - unaligned = cmd->unaligned; - - /* Clear the allocated bit for the command */ - release_slot(port, tag); - - if (unlikely(unaligned)) - up(&port->cmd_slot_unal); - else - up(&port->cmd_slot); - } -} - -/* - * This function is called for clean the pending command in the - * command slot during the surprise removal of device and return - * error to the upper layer. - * - * @dd Pointer to the DRIVER_DATA structure. - * - * return value - * None - */ -static void mtip_command_cleanup(struct driver_data *dd) -{ - int tag = 0; - struct mtip_cmd *cmd; - struct mtip_port *port = dd->port; - unsigned int num_cmd_slots = dd->slot_groups * 32; + /* Unmap the DMA scatter list entries */ + dma_unmap_sg(&dd->pdev->dev, cmd->sg, cmd->scatter_ents, cmd->direction); - if (!test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) - return; - - if (!port) - return; - - cmd = &port->commands[MTIP_TAG_INTERNAL]; - if (atomic_read(&cmd->active)) - if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) & - (1 << MTIP_TAG_INTERNAL)) - if (cmd->comp_func) - cmd->comp_func(port, MTIP_TAG_INTERNAL, - cmd->comp_data, -ENODEV); - - while (1) { - tag = find_next_bit(port->allocated, num_cmd_slots, tag); - if (tag >= num_cmd_slots) - break; + rq = mtip_rq_from_tag(dd, tag); - cmd = &port->commands[tag]; - if (atomic_read(&cmd->active)) - mtip_async_complete(port, tag, dd, -ENODEV); - } + if (unlikely(cmd->unaligned)) + up(&port->cmd_slot_unal); - set_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag); + blk_mq_end_io(rq, status ? -EIO : 0); } /* @@ -388,8 +300,6 @@ static inline void mtip_issue_ncq_command(struct mtip_port *port, int tag) { int group = tag >> 5; - atomic_set(&port->commands[tag].active, 1); - /* guard SACT and CI registers */ spin_lock(&port->cmd_issue_lock[group]); writel((1 << MTIP_TAG_BIT(tag)), @@ -397,10 +307,6 @@ static inline void mtip_issue_ncq_command(struct mtip_port *port, int tag) writel((1 << MTIP_TAG_BIT(tag)), port->cmd_issue[MTIP_TAG_INDEX(tag)]); spin_unlock(&port->cmd_issue_lock[group]); - - /* Set the command's timeout value.*/ - port->commands[tag].comp_time = jiffies + msecs_to_jiffies( - MTIP_NCQ_COMMAND_TIMEOUT_MS); } /* @@ -648,131 +554,12 @@ static void print_tags(struct driver_data *dd, memset(tagmap, 0, sizeof(tagmap)); for (group = SLOTBITS_IN_LONGS; group > 0; group--) - tagmap_len = sprintf(tagmap + tagmap_len, "%016lX ", + tagmap_len += sprintf(tagmap + tagmap_len, "%016lX ", tagbits[group-1]); dev_warn(&dd->pdev->dev, "%d command(s) %s: tagmap [%s]", cnt, msg, tagmap); } -/* - * Called periodically to see if any read/write commands are - * taking too long to complete. - * - * @data Pointer to the PORT data structure. - * - * return value - * None - */ -static void mtip_timeout_function(unsigned long int data) -{ - struct mtip_port *port = (struct mtip_port *) data; - struct host_to_dev_fis *fis; - struct mtip_cmd *cmd; - int unaligned, tag, cmdto_cnt = 0; - unsigned int bit, group; - unsigned int num_command_slots; - unsigned long to, tagaccum[SLOTBITS_IN_LONGS]; - void (*func)(void *, int); - - if (unlikely(!port)) - return; - - if (unlikely(port->dd->sr)) - return; - - if (test_bit(MTIP_DDF_RESUME_BIT, &port->dd->dd_flag)) { - mod_timer(&port->cmd_timer, - jiffies + msecs_to_jiffies(30000)); - return; - } - /* clear the tag accumulator */ - memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); - num_command_slots = port->dd->slot_groups * 32; - - for (tag = 0; tag < num_command_slots; tag++) { - /* - * Skip internal command slot as it has - * its own timeout mechanism - */ - if (tag == MTIP_TAG_INTERNAL) - continue; - - if (atomic_read(&port->commands[tag].active) && - (time_after(jiffies, port->commands[tag].comp_time))) { - group = tag >> 5; - bit = tag & 0x1F; - - cmd = &port->commands[tag]; - fis = (struct host_to_dev_fis *) cmd->command; - - set_bit(tag, tagaccum); - cmdto_cnt++; - if (cmdto_cnt == 1) - set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); - - /* - * Clear the completed bit. This should prevent - * any interrupt handlers from trying to retire - * the command. - */ - writel(1 << bit, port->completed[group]); - - /* Clear the active flag for the command */ - atomic_set(&port->commands[tag].active, 0); - - func = cmd->async_callback; - if (func && - cmpxchg(&cmd->async_callback, func, 0) == func) { - - /* Unmap the DMA scatter list entries */ - dma_unmap_sg(&port->dd->pdev->dev, - cmd->sg, - cmd->scatter_ents, - cmd->direction); - - func(cmd->async_data, -EIO); - unaligned = cmd->unaligned; - - /* Clear the allocated bit for the command. */ - release_slot(port, tag); - - if (unaligned) - up(&port->cmd_slot_unal); - else - up(&port->cmd_slot); - } - } - } - - if (cmdto_cnt) { - print_tags(port->dd, "timed out", tagaccum, cmdto_cnt); - if (!test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) { - mtip_device_reset(port->dd); - wake_up_interruptible(&port->svc_wait); - } - clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); - } - - if (port->ic_pause_timer) { - to = port->ic_pause_timer + msecs_to_jiffies(1000); - if (time_after(jiffies, to)) { - if (!test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) { - port->ic_pause_timer = 0; - clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags); - clear_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags); - clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); - wake_up_interruptible(&port->svc_wait); - } - - - } - } - - /* Restart the timer */ - mod_timer(&port->cmd_timer, - jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); -} - /* * Internal command completion callback function. * @@ -789,28 +576,19 @@ static void mtip_timeout_function(unsigned long int data) * None */ static void mtip_completion(struct mtip_port *port, - int tag, - void *data, - int status) + int tag, struct mtip_cmd *command, int status) { - struct mtip_cmd *command = &port->commands[tag]; - struct completion *waiting = data; + struct completion *waiting = command->comp_data; if (unlikely(status == PORT_IRQ_TF_ERR)) dev_warn(&port->dd->pdev->dev, "Internal command %d completed with TFE\n", tag); - command->async_callback = NULL; - command->comp_func = NULL; - complete(waiting); } static void mtip_null_completion(struct mtip_port *port, - int tag, - void *data, - int status) + int tag, struct mtip_cmd *command, int status) { - return; } static int mtip_read_log_page(struct mtip_port *port, u8 page, u16 *buffer, @@ -843,18 +621,16 @@ static void mtip_handle_tfe(struct driver_data *dd) port = dd->port; /* Stop the timer to prevent command timeouts. */ - del_timer(&port->cmd_timer); set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) && test_bit(MTIP_TAG_INTERNAL, port->allocated)) { - cmd = &port->commands[MTIP_TAG_INTERNAL]; + cmd = mtip_cmd_from_tag(dd, MTIP_TAG_INTERNAL); dbg_printk(MTIP_DRV_NAME " TFE for the internal command\n"); - atomic_inc(&cmd->active); /* active > 1 indicates error */ if (cmd->comp_data && cmd->comp_func) { cmd->comp_func(port, MTIP_TAG_INTERNAL, - cmd->comp_data, PORT_IRQ_TF_ERR); + cmd, PORT_IRQ_TF_ERR); } goto handle_tfe_exit; } @@ -866,6 +642,8 @@ static void mtip_handle_tfe(struct driver_data *dd) for (group = 0; group < dd->slot_groups; group++) { completed = readl(port->completed[group]); + dev_warn(&dd->pdev->dev, "g=%u, comp=%x\n", group, completed); + /* clear completed status register in the hardware.*/ writel(completed, port->completed[group]); @@ -879,15 +657,11 @@ static void mtip_handle_tfe(struct driver_data *dd) if (tag == MTIP_TAG_INTERNAL) continue; - cmd = &port->commands[tag]; + cmd = mtip_cmd_from_tag(dd, tag); if (likely(cmd->comp_func)) { set_bit(tag, tagaccum); cmd_cnt++; - atomic_set(&cmd->active, 0); - cmd->comp_func(port, - tag, - cmd->comp_data, - 0); + cmd->comp_func(port, tag, cmd, 0); } else { dev_err(&port->dd->pdev->dev, "Missing completion func for tag %d", @@ -947,11 +721,7 @@ static void mtip_handle_tfe(struct driver_data *dd) for (bit = 0; bit < 32; bit++) { reissue = 1; tag = (group << 5) + bit; - cmd = &port->commands[tag]; - - /* If the active bit is set re-issue the command */ - if (atomic_read(&cmd->active) == 0) - continue; + cmd = mtip_cmd_from_tag(dd, tag); fis = (struct host_to_dev_fis *)cmd->command; @@ -970,11 +740,9 @@ static void mtip_handle_tfe(struct driver_data *dd) tag, fail_reason != NULL ? fail_reason : "unknown"); - atomic_set(&cmd->active, 0); if (cmd->comp_func) { cmd->comp_func(port, tag, - cmd->comp_data, - -ENODATA); + cmd, -ENODATA); } continue; } @@ -997,14 +765,9 @@ static void mtip_handle_tfe(struct driver_data *dd) /* Retire a command that will not be reissued */ dev_warn(&port->dd->pdev->dev, "retiring tag %d\n", tag); - atomic_set(&cmd->active, 0); if (cmd->comp_func) - cmd->comp_func( - port, - tag, - cmd->comp_data, - PORT_IRQ_TF_ERR); + cmd->comp_func(port, tag, cmd, PORT_IRQ_TF_ERR); else dev_warn(&port->dd->pdev->dev, "Bad completion for tag %d\n", @@ -1017,9 +780,6 @@ static void mtip_handle_tfe(struct driver_data *dd) /* clear eh_active */ clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); - - mod_timer(&port->cmd_timer, - jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); } /* @@ -1048,15 +808,10 @@ static inline void mtip_workq_sdbfx(struct mtip_port *port, int group, if (unlikely(tag == MTIP_TAG_INTERNAL)) continue; - command = &port->commands[tag]; - /* make internal callback */ - if (likely(command->comp_func)) { - command->comp_func( - port, - tag, - command->comp_data, - 0); - } else { + command = mtip_cmd_from_tag(dd, tag); + if (likely(command->comp_func)) + command->comp_func(port, tag, command, 0); + else { dev_dbg(&dd->pdev->dev, "Null completion for tag %d", tag); @@ -1081,16 +836,13 @@ static inline void mtip_workq_sdbfx(struct mtip_port *port, int group, static inline void mtip_process_legacy(struct driver_data *dd, u32 port_stat) { struct mtip_port *port = dd->port; - struct mtip_cmd *cmd = &port->commands[MTIP_TAG_INTERNAL]; + struct mtip_cmd *cmd = mtip_cmd_from_tag(dd, MTIP_TAG_INTERNAL); if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) && (cmd != NULL) && !(readl(port->cmd_issue[MTIP_TAG_INTERNAL]) & (1 << MTIP_TAG_INTERNAL))) { if (cmd->comp_func) { - cmd->comp_func(port, - MTIP_TAG_INTERNAL, - cmd->comp_data, - 0); + cmd->comp_func(port, MTIP_TAG_INTERNAL, cmd, 0); return; } } @@ -1222,7 +974,6 @@ static irqreturn_t mtip_irq_handler(int irq, void *instance) static void mtip_issue_non_ncq_command(struct mtip_port *port, int tag) { - atomic_set(&port->commands[tag].active, 1); writel(1 << MTIP_TAG_BIT(tag), port->cmd_issue[MTIP_TAG_INDEX(tag)]); } @@ -1335,10 +1086,9 @@ static int mtip_exec_internal_command(struct mtip_port *port, { struct mtip_cmd_sg *command_sg; DECLARE_COMPLETION_ONSTACK(wait); - int rv = 0, ready2go = 1; - struct mtip_cmd *int_cmd = &port->commands[MTIP_TAG_INTERNAL]; - unsigned long to; + struct mtip_cmd *int_cmd; struct driver_data *dd = port->dd; + int rv = 0; /* Make sure the buffer is 8 byte aligned. This is asic specific. */ if (buffer & 0x00000007) { @@ -1346,19 +1096,8 @@ static int mtip_exec_internal_command(struct mtip_port *port, return -EFAULT; } - to = jiffies + msecs_to_jiffies(timeout); - do { - ready2go = !test_and_set_bit(MTIP_TAG_INTERNAL, - port->allocated); - if (ready2go) - break; - mdelay(100); - } while (time_before(jiffies, to)); - if (!ready2go) { - dev_warn(&dd->pdev->dev, - "Internal cmd active. new cmd [%02X]\n", fis->command); - return -EBUSY; - } + int_cmd = mtip_get_int_command(dd); + set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); port->ic_pause_timer = 0; @@ -1371,7 +1110,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, if (mtip_quiesce_io(port, 5000) < 0) { dev_warn(&dd->pdev->dev, "Failed to quiesce IO\n"); - release_slot(port, MTIP_TAG_INTERNAL); + mtip_put_int_command(dd, int_cmd); clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); return -EBUSY; @@ -1497,8 +1236,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, } exec_ic_exit: /* Clear the allocated and active bits for the internal command. */ - atomic_set(&int_cmd->active, 0); - release_slot(port, MTIP_TAG_INTERNAL); + mtip_put_int_command(dd, int_cmd); if (rv >= 0 && mtip_pause_ncq(port, fis)) { /* NCQ paused */ return rv; @@ -1529,6 +1267,37 @@ static inline void ata_swap_string(u16 *buf, unsigned int len) be16_to_cpus(&buf[i]); } +static void mtip_set_timeout(struct driver_data *dd, + struct host_to_dev_fis *fis, + unsigned int *timeout, u8 erasemode) +{ + switch (fis->command) { + case ATA_CMD_DOWNLOAD_MICRO: + *timeout = 120000; /* 2 minutes */ + break; + case ATA_CMD_SEC_ERASE_UNIT: + case 0xFC: + if (erasemode) + *timeout = ((*(dd->port->identify + 90) * 2) * 60000); + else + *timeout = ((*(dd->port->identify + 89) * 2) * 60000); + break; + case ATA_CMD_STANDBYNOW1: + *timeout = 120000; /* 2 minutes */ + break; + case 0xF7: + case 0xFA: + *timeout = 60000; /* 60 seconds */ + break; + case ATA_CMD_SMART: + *timeout = 15000; /* 15 seconds */ + break; + default: + *timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS; + break; + } +} + /* * Request the device identity information. * @@ -1644,6 +1413,7 @@ static int mtip_standby_immediate(struct mtip_port *port) int rv; struct host_to_dev_fis fis; unsigned long start; + unsigned int timeout; /* Build the FIS. */ memset(&fis, 0, sizeof(struct host_to_dev_fis)); @@ -1651,6 +1421,8 @@ static int mtip_standby_immediate(struct mtip_port *port) fis.opts = 1 << 7; fis.command = ATA_CMD_STANDBYNOW1; + mtip_set_timeout(port->dd, &fis, &timeout, 0); + start = jiffies; rv = mtip_exec_internal_command(port, &fis, @@ -1659,7 +1431,7 @@ static int mtip_standby_immediate(struct mtip_port *port) 0, 0, GFP_ATOMIC, - 15000); + timeout); dbg_printk(MTIP_DRV_NAME "Time taken to complete standby cmd: %d ms\n", jiffies_to_msecs(jiffies - start)); if (rv) @@ -2202,36 +1974,6 @@ static unsigned int implicit_sector(unsigned char command, } return rv; } -static void mtip_set_timeout(struct driver_data *dd, - struct host_to_dev_fis *fis, - unsigned int *timeout, u8 erasemode) -{ - switch (fis->command) { - case ATA_CMD_DOWNLOAD_MICRO: - *timeout = 120000; /* 2 minutes */ - break; - case ATA_CMD_SEC_ERASE_UNIT: - case 0xFC: - if (erasemode) - *timeout = ((*(dd->port->identify + 90) * 2) * 60000); - else - *timeout = ((*(dd->port->identify + 89) * 2) * 60000); - break; - case ATA_CMD_STANDBYNOW1: - *timeout = 120000; /* 2 minutes */ - break; - case 0xF7: - case 0xFA: - *timeout = 60000; /* 60 seconds */ - break; - case ATA_CMD_SMART: - *timeout = 15000; /* 15 seconds */ - break; - default: - *timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS; - break; - } -} /* * Executes a taskfile @@ -2606,22 +2348,21 @@ static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd, * return value * None */ -static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector, - int nsect, int nents, int tag, void *callback, - void *data, int dir, int unaligned) +static void mtip_hw_submit_io(struct driver_data *dd, struct request *rq, + struct mtip_cmd *command, int nents, + struct blk_mq_hw_ctx *hctx) { struct host_to_dev_fis *fis; struct mtip_port *port = dd->port; - struct mtip_cmd *command = &port->commands[tag]; - int dma_dir = (dir == READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - u64 start = sector; + int dma_dir = rq_data_dir(rq) == READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + u64 start = blk_rq_pos(rq); + unsigned int nsect = blk_rq_sectors(rq); /* Map the scatter list for DMA access */ nents = dma_map_sg(&dd->pdev->dev, command->sg, nents, dma_dir); command->scatter_ents = nents; - command->unaligned = unaligned; /* * The number of retries for this command before it is * reported as a failure to the upper layers. @@ -2632,8 +2373,10 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector, fis = command->command; fis->type = 0x27; fis->opts = 1 << 7; - fis->command = - (dir == READ ? ATA_CMD_FPDMA_READ : ATA_CMD_FPDMA_WRITE); + if (rq_data_dir(rq) == READ) + fis->command = ATA_CMD_FPDMA_READ; + else + fis->command = ATA_CMD_FPDMA_WRITE; fis->lba_low = start & 0xFF; fis->lba_mid = (start >> 8) & 0xFF; fis->lba_hi = (start >> 16) & 0xFF; @@ -2643,14 +2386,14 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector, fis->device = 1 << 6; fis->features = nsect & 0xFF; fis->features_ex = (nsect >> 8) & 0xFF; - fis->sect_count = ((tag << 3) | (tag >> 5)); + fis->sect_count = ((rq->tag << 3) | (rq->tag >> 5)); fis->sect_cnt_ex = 0; fis->control = 0; fis->res2 = 0; fis->res3 = 0; fill_command_sg(dd, command, nents); - if (unaligned) + if (command->unaligned) fis->device |= 1 << 7; /* Populate the command header */ @@ -2667,82 +2410,18 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector, command->comp_func = mtip_async_complete; command->direction = dma_dir; - /* - * Set the completion function and data for the command passed - * from the upper layer. - */ - command->async_data = data; - command->async_callback = callback; - /* * To prevent this command from being issued * if an internal command is in progress or error handling is active. */ if (port->flags & MTIP_PF_PAUSE_IO) { - set_bit(tag, port->cmds_to_issue); + set_bit(rq->tag, port->cmds_to_issue); set_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags); return; } /* Issue the command to the hardware */ - mtip_issue_ncq_command(port, tag); - - return; -} - -/* - * Release a command slot. - * - * @dd Pointer to the driver data structure. - * @tag Slot tag - * - * return value - * None - */ -static void mtip_hw_release_scatterlist(struct driver_data *dd, int tag, - int unaligned) -{ - struct semaphore *sem = unaligned ? &dd->port->cmd_slot_unal : - &dd->port->cmd_slot; - release_slot(dd->port, tag); - up(sem); -} - -/* - * Obtain a command slot and return its associated scatter list. - * - * @dd Pointer to the driver data structure. - * @tag Pointer to an int that will receive the allocated command - * slot tag. - * - * return value - * Pointer to the scatter list for the allocated command slot - * or NULL if no command slots are available. - */ -static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, - int *tag, int unaligned) -{ - struct semaphore *sem = unaligned ? &dd->port->cmd_slot_unal : - &dd->port->cmd_slot; - - /* - * It is possible that, even with this semaphore, a thread - * may think that no command slots are available. Therefore, we - * need to make an attempt to get_slot(). - */ - down(sem); - *tag = get_slot(dd->port); - - if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) { - up(sem); - return NULL; - } - if (unlikely(*tag < 0)) { - up(sem); - return NULL; - } - - return dd->port->commands[*tag].sg; + mtip_issue_ncq_command(port, rq->tag); } /* @@ -3113,6 +2792,7 @@ static int mtip_free_orphan(struct driver_data *dd) if (dd->queue) { dd->queue->queuedata = NULL; blk_cleanup_queue(dd->queue); + blk_mq_free_tag_set(&dd->tags); dd->queue = NULL; } } @@ -3365,7 +3045,6 @@ static int mtip_service_thread(void *data) */ static void mtip_dma_free(struct driver_data *dd) { - int i; struct mtip_port *port = dd->port; if (port->block1) @@ -3376,13 +3055,6 @@ static void mtip_dma_free(struct driver_data *dd) dmam_free_coherent(&dd->pdev->dev, AHCI_CMD_TBL_SZ, port->command_list, port->command_list_dma); } - - for (i = 0; i < MTIP_MAX_COMMAND_SLOTS; i++) { - if (port->commands[i].command) - dmam_free_coherent(&dd->pdev->dev, CMD_DMA_ALLOC_SZ, - port->commands[i].command, - port->commands[i].command_dma); - } } /* @@ -3396,8 +3068,6 @@ static void mtip_dma_free(struct driver_data *dd) static int mtip_dma_alloc(struct driver_data *dd) { struct mtip_port *port = dd->port; - int i, rv = 0; - u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64; /* Allocate dma memory for RX Fis, Identify, and Sector Bufffer */ port->block1 = @@ -3430,41 +3100,63 @@ static int mtip_dma_alloc(struct driver_data *dd) port->smart_buf = port->block1 + AHCI_SMARTBUF_OFFSET; port->smart_buf_dma = port->block1_dma + AHCI_SMARTBUF_OFFSET; - /* Setup per command SGL DMA region */ - - /* Point the command headers at the command tables */ - for (i = 0; i < MTIP_MAX_COMMAND_SLOTS; i++) { - port->commands[i].command = - dmam_alloc_coherent(&dd->pdev->dev, CMD_DMA_ALLOC_SZ, - &port->commands[i].command_dma, GFP_KERNEL); - if (!port->commands[i].command) { - rv = -ENOMEM; - mtip_dma_free(dd); - return rv; - } - memset(port->commands[i].command, 0, CMD_DMA_ALLOC_SZ); - - port->commands[i].command_header = port->command_list + - (sizeof(struct mtip_cmd_hdr) * i); - port->commands[i].command_header_dma = - dd->port->command_list_dma + - (sizeof(struct mtip_cmd_hdr) * i); + return 0; +} - if (host_cap_64) - port->commands[i].command_header->ctbau = - __force_bit2int cpu_to_le32( - (port->commands[i].command_dma >> 16) >> 16); +static int mtip_hw_get_identify(struct driver_data *dd) +{ + struct smart_attr attr242; + unsigned char *buf; + int rv; - port->commands[i].command_header->ctba = - __force_bit2int cpu_to_le32( - port->commands[i].command_dma & 0xFFFFFFFF); + if (mtip_get_identify(dd->port, NULL) < 0) + return -EFAULT; - sg_init_table(port->commands[i].sg, MTIP_MAX_SG); + if (*(dd->port->identify + MTIP_FTL_REBUILD_OFFSET) == + MTIP_FTL_REBUILD_MAGIC) { + set_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags); + return MTIP_FTL_REBUILD_MAGIC; + } + mtip_dump_identify(dd->port); - /* Mark command as currently inactive */ - atomic_set(&dd->port->commands[i].active, 0); + /* check write protect, over temp and rebuild statuses */ + rv = mtip_read_log_page(dd->port, ATA_LOG_SATA_NCQ, + dd->port->log_buf, + dd->port->log_buf_dma, 1); + if (rv) { + dev_warn(&dd->pdev->dev, + "Error in READ LOG EXT (10h) command\n"); + /* non-critical error, don't fail the load */ + } else { + buf = (unsigned char *)dd->port->log_buf; + if (buf[259] & 0x1) { + dev_info(&dd->pdev->dev, + "Write protect bit is set.\n"); + set_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag); + } + if (buf[288] == 0xF7) { + dev_info(&dd->pdev->dev, + "Exceeded Tmax, drive in thermal shutdown.\n"); + set_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag); + } + if (buf[288] == 0xBF) { + dev_info(&dd->pdev->dev, + "Drive indicates rebuild has failed.\n"); + /* TODO */ + } } - return 0; + + /* get write protect progess */ + memset(&attr242, 0, sizeof(struct smart_attr)); + if (mtip_get_smart_attr(dd->port, 242, &attr242)) + dev_warn(&dd->pdev->dev, + "Unable to check write protect progress\n"); + else + dev_info(&dd->pdev->dev, + "Write protect progress: %u%% (%u blocks)\n", + attr242.cur, le32_to_cpu(attr242.data)); + + return rv; } /* @@ -3481,8 +3173,6 @@ static int mtip_hw_init(struct driver_data *dd) int rv; unsigned int num_command_slots; unsigned long timeout, timetaken; - unsigned char *buf; - struct smart_attr attr242; dd->mmio = pcim_iomap_table(dd->pdev)[MTIP_ABAR]; @@ -3513,8 +3203,6 @@ static int mtip_hw_init(struct driver_data *dd) else dd->unal_qdepth = 0; - /* Counting semaphore to track command slot usage */ - sema_init(&dd->port->cmd_slot, num_command_slots - 1 - dd->unal_qdepth); sema_init(&dd->port->cmd_slot_unal, dd->unal_qdepth); /* Spinlock to prevent concurrent issue */ @@ -3599,73 +3287,16 @@ static int mtip_hw_init(struct driver_data *dd) writel(readl(dd->mmio + HOST_CTL) | HOST_IRQ_EN, dd->mmio + HOST_CTL); - init_timer(&dd->port->cmd_timer); init_waitqueue_head(&dd->port->svc_wait); - dd->port->cmd_timer.data = (unsigned long int) dd->port; - dd->port->cmd_timer.function = mtip_timeout_function; - mod_timer(&dd->port->cmd_timer, - jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); - - if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) { rv = -EFAULT; goto out3; } - if (mtip_get_identify(dd->port, NULL) < 0) { - rv = -EFAULT; - goto out3; - } - mtip_dump_identify(dd->port); - - if (*(dd->port->identify + MTIP_FTL_REBUILD_OFFSET) == - MTIP_FTL_REBUILD_MAGIC) { - set_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags); - return MTIP_FTL_REBUILD_MAGIC; - } - - /* check write protect, over temp and rebuild statuses */ - rv = mtip_read_log_page(dd->port, ATA_LOG_SATA_NCQ, - dd->port->log_buf, - dd->port->log_buf_dma, 1); - if (rv) { - dev_warn(&dd->pdev->dev, - "Error in READ LOG EXT (10h) command\n"); - /* non-critical error, don't fail the load */ - } else { - buf = (unsigned char *)dd->port->log_buf; - if (buf[259] & 0x1) { - dev_info(&dd->pdev->dev, - "Write protect bit is set.\n"); - set_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag); - } - if (buf[288] == 0xF7) { - dev_info(&dd->pdev->dev, - "Exceeded Tmax, drive in thermal shutdown.\n"); - set_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag); - } - if (buf[288] == 0xBF) { - dev_info(&dd->pdev->dev, - "Drive is in security locked state.\n"); - set_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag); - } - } - - /* get write protect progess */ - memset(&attr242, 0, sizeof(struct smart_attr)); - if (mtip_get_smart_attr(dd->port, 242, &attr242)) - dev_warn(&dd->pdev->dev, - "Unable to check write protect progress\n"); - else - dev_info(&dd->pdev->dev, - "Write protect progress: %u%% (%u blocks)\n", - attr242.cur, le32_to_cpu(attr242.data)); return rv; out3: - del_timer_sync(&dd->port->cmd_timer); - /* Disable interrupts on the HBA. */ writel(readl(dd->mmio + HOST_CTL) & ~HOST_IRQ_EN, dd->mmio + HOST_CTL); @@ -3685,6 +3316,22 @@ static int mtip_hw_init(struct driver_data *dd) return rv; } +static void mtip_standby_drive(struct driver_data *dd) +{ + if (dd->sr) + return; + + /* + * Send standby immediate (E0h) to the drive so that it + * saves its state. + */ + if (!test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags) && + !test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag)) + if (mtip_standby_immediate(dd->port)) + dev_warn(&dd->pdev->dev, + "STANDBY IMMEDIATE failed\n"); +} + /* * Called to deinitialize an interface. * @@ -3700,12 +3347,6 @@ static int mtip_hw_exit(struct driver_data *dd) * saves its state. */ if (!dd->sr) { - if (!test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags) && - !test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag)) - if (mtip_standby_immediate(dd->port)) - dev_warn(&dd->pdev->dev, - "STANDBY IMMEDIATE failed\n"); - /* de-initialize the port. */ mtip_deinit_port(dd->port); @@ -3714,8 +3355,6 @@ static int mtip_hw_exit(struct driver_data *dd) dd->mmio + HOST_CTL); } - del_timer_sync(&dd->port->cmd_timer); - /* Release the IRQ. */ irq_set_affinity_hint(dd->pdev->irq, NULL); devm_free_irq(&dd->pdev->dev, dd->pdev->irq, dd); @@ -4032,100 +3671,140 @@ static const struct block_device_operations mtip_block_ops = { * * @queue Pointer to the request queue. Unused other than to obtain * the driver data structure. - * @bio Pointer to the BIO. + * @rq Pointer to the request. * */ -static void mtip_make_request(struct request_queue *queue, struct bio *bio) +static int mtip_submit_request(struct blk_mq_hw_ctx *hctx, struct request *rq) { - struct driver_data *dd = queue->queuedata; - struct scatterlist *sg; - struct bio_vec bvec; - struct bvec_iter iter; - int nents = 0; - int tag = 0, unaligned = 0; + struct driver_data *dd = hctx->queue->queuedata; + struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq); + unsigned int nents; if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) { if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) { - bio_endio(bio, -ENXIO); - return; + return -ENXIO; } if (unlikely(test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))) { - bio_endio(bio, -ENODATA); - return; + return -ENODATA; } if (unlikely(test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag) && - bio_data_dir(bio))) { - bio_endio(bio, -ENODATA); - return; - } - if (unlikely(test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag))) { - bio_endio(bio, -ENODATA); - return; - } - if (test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)) { - bio_endio(bio, -ENXIO); - return; + rq_data_dir(rq))) { + return -ENODATA; } + if (unlikely(test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag))) + return -ENODATA; + if (test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)) + return -ENXIO; } - if (unlikely(bio->bi_rw & REQ_DISCARD)) { - bio_endio(bio, mtip_send_trim(dd, bio->bi_iter.bi_sector, - bio_sectors(bio))); - return; - } + if (rq->cmd_flags & REQ_DISCARD) { + int err; - if (unlikely(!bio_has_data(bio))) { - blk_queue_flush(queue, 0); - bio_endio(bio, 0); - return; + err = mtip_send_trim(dd, blk_rq_pos(rq), blk_rq_sectors(rq)); + blk_mq_end_io(rq, err); + return 0; } - if (bio_data_dir(bio) == WRITE && bio_sectors(bio) <= 64 && - dd->unal_qdepth) { - if (bio->bi_iter.bi_sector % 8 != 0) - /* Unaligned on 4k boundaries */ - unaligned = 1; - else if (bio_sectors(bio) % 8 != 0) /* Aligned but not 4k/8k */ - unaligned = 1; + /* Create the scatter list for this request. */ + nents = blk_rq_map_sg(hctx->queue, rq, cmd->sg); + + /* Issue the read/write. */ + mtip_hw_submit_io(dd, rq, cmd, nents, hctx); + return 0; +} + +static bool mtip_check_unal_depth(struct blk_mq_hw_ctx *hctx, + struct request *rq) +{ + struct driver_data *dd = hctx->queue->queuedata; + struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq); + + if (!dd->unal_qdepth || rq_data_dir(rq) == READ) + return false; + + /* + * If unaligned depth must be limited on this controller, mark it + * as unaligned if the IO isn't on a 4k boundary (start of length). + */ + if (blk_rq_sectors(rq) <= 64) { + if ((blk_rq_pos(rq) & 7) || (blk_rq_sectors(rq) & 7)) + cmd->unaligned = 1; } - sg = mtip_hw_get_scatterlist(dd, &tag, unaligned); - if (likely(sg != NULL)) { - blk_queue_bounce(queue, &bio); + if (cmd->unaligned && down_trylock(&dd->port->cmd_slot_unal)) + return true; - if (unlikely((bio)->bi_vcnt > MTIP_MAX_SG)) { - dev_warn(&dd->pdev->dev, - "Maximum number of SGL entries exceeded\n"); - bio_io_error(bio); - mtip_hw_release_scatterlist(dd, tag, unaligned); - return; - } + return false; +} - /* Create the scatter list for this bio. */ - bio_for_each_segment(bvec, bio, iter) { - sg_set_page(&sg[nents], - bvec.bv_page, - bvec.bv_len, - bvec.bv_offset); - nents++; - } +static int mtip_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *rq) +{ + int ret; - /* Issue the read/write. */ - mtip_hw_submit_io(dd, - bio->bi_iter.bi_sector, - bio_sectors(bio), - nents, - tag, - bio_endio, - bio, - bio_data_dir(bio), - unaligned); - } else - bio_io_error(bio); + if (mtip_check_unal_depth(hctx, rq)) + return BLK_MQ_RQ_QUEUE_BUSY; + + ret = mtip_submit_request(hctx, rq); + if (!ret) + return BLK_MQ_RQ_QUEUE_OK; + + rq->errors = ret; + return BLK_MQ_RQ_QUEUE_ERROR; +} + +static void mtip_free_cmd(void *data, struct request *rq, + unsigned int hctx_idx, unsigned int request_idx) +{ + struct driver_data *dd = data; + struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq); + + if (!cmd->command) + return; + + dmam_free_coherent(&dd->pdev->dev, CMD_DMA_ALLOC_SZ, + cmd->command, cmd->command_dma); +} + +static int mtip_init_cmd(void *data, struct request *rq, unsigned int hctx_idx, + unsigned int request_idx, unsigned int numa_node) +{ + struct driver_data *dd = data; + struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq); + u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64; + + cmd->command = dmam_alloc_coherent(&dd->pdev->dev, CMD_DMA_ALLOC_SZ, + &cmd->command_dma, GFP_KERNEL); + if (!cmd->command) + return -ENOMEM; + + memset(cmd->command, 0, CMD_DMA_ALLOC_SZ); + + /* Point the command headers at the command tables. */ + cmd->command_header = dd->port->command_list + + (sizeof(struct mtip_cmd_hdr) * request_idx); + cmd->command_header_dma = dd->port->command_list_dma + + (sizeof(struct mtip_cmd_hdr) * request_idx); + + if (host_cap_64) + cmd->command_header->ctbau = __force_bit2int cpu_to_le32((cmd->command_dma >> 16) >> 16); + + cmd->command_header->ctba = __force_bit2int cpu_to_le32(cmd->command_dma & 0xFFFFFFFF); + + sg_init_table(cmd->sg, MTIP_MAX_SG); + return 0; } +static struct blk_mq_ops mtip_mq_ops = { + .queue_rq = mtip_queue_rq, + .map_queue = blk_mq_map_queue, + .alloc_hctx = blk_mq_alloc_single_hw_queue, + .free_hctx = blk_mq_free_single_hw_queue, + .init_request = mtip_init_cmd, + .exit_request = mtip_free_cmd, +}; + /* * Block layer initialization function. * @@ -4148,11 +3827,7 @@ static int mtip_block_initialize(struct driver_data *dd) if (dd->disk) goto skip_create_disk; /* hw init done, before rebuild */ - /* Initialize the protocol layer. */ - wait_for_rebuild = mtip_hw_init(dd); - if (wait_for_rebuild < 0) { - dev_err(&dd->pdev->dev, - "Protocol layer initialization failed\n"); + if (mtip_hw_init(dd)) { rv = -EINVAL; goto protocol_init_error; } @@ -4194,16 +3869,27 @@ static int mtip_block_initialize(struct driver_data *dd) mtip_hw_debugfs_init(dd); - /* - * if rebuild pending, start the service thread, and delay the block - * queue creation and add_disk() - */ - if (wait_for_rebuild == MTIP_FTL_REBUILD_MAGIC) - goto start_service_thread; - skip_create_disk: + memset(&dd->tags, 0, sizeof(dd->tags)); + dd->tags.ops = &mtip_mq_ops; + dd->tags.nr_hw_queues = 1; + dd->tags.queue_depth = MTIP_MAX_COMMAND_SLOTS; + dd->tags.reserved_tags = 1; + dd->tags.cmd_size = sizeof(struct mtip_cmd); + dd->tags.numa_node = dd->numa_node; + dd->tags.flags = BLK_MQ_F_SHOULD_MERGE; + dd->tags.driver_data = dd; + + rv = blk_mq_alloc_tag_set(&dd->tags); + if (rv) { + dev_err(&dd->pdev->dev, + "Unable to allocate request queue\n"); + rv = -ENOMEM; + goto block_queue_alloc_init_error; + } + /* Allocate the request queue. */ - dd->queue = blk_alloc_queue_node(GFP_KERNEL, dd->numa_node); + dd->queue = blk_mq_init_queue(&dd->tags); if (dd->queue == NULL) { dev_err(&dd->pdev->dev, "Unable to allocate request queue\n"); @@ -4211,12 +3897,25 @@ static int mtip_block_initialize(struct driver_data *dd) goto block_queue_alloc_init_error; } - /* Attach our request function to the request queue. */ - blk_queue_make_request(dd->queue, mtip_make_request); - dd->disk->queue = dd->queue; dd->queue->queuedata = dd; + /* Initialize the protocol layer. */ + wait_for_rebuild = mtip_hw_get_identify(dd); + if (wait_for_rebuild < 0) { + dev_err(&dd->pdev->dev, + "Protocol layer initialization failed\n"); + rv = -EINVAL; + goto init_hw_cmds_error; + } + + /* + * if rebuild pending, start the service thread, and delay the block + * queue creation and add_disk() + */ + if (wait_for_rebuild == MTIP_FTL_REBUILD_MAGIC) + goto start_service_thread; + /* Set device limits. */ set_bit(QUEUE_FLAG_NONROT, &dd->queue->queue_flags); blk_queue_max_segments(dd->queue, MTIP_MAX_SG); @@ -4295,8 +3994,9 @@ static int mtip_block_initialize(struct driver_data *dd) del_gendisk(dd->disk); read_capacity_error: +init_hw_cmds_error: blk_cleanup_queue(dd->queue); - + blk_mq_free_tag_set(&dd->tags); block_queue_alloc_init_error: mtip_hw_debugfs_exit(dd); disk_index_error: @@ -4345,6 +4045,9 @@ static int mtip_block_remove(struct driver_data *dd) kobject_put(kobj); } } + + mtip_standby_drive(dd); + /* * Delete our gendisk structure. This also removes the device * from /dev @@ -4357,6 +4060,7 @@ static int mtip_block_remove(struct driver_data *dd) if (dd->disk->queue) { del_gendisk(dd->disk); blk_cleanup_queue(dd->queue); + blk_mq_free_tag_set(&dd->tags); dd->queue = NULL; } else put_disk(dd->disk); @@ -4391,6 +4095,8 @@ static int mtip_block_remove(struct driver_data *dd) */ static int mtip_block_shutdown(struct driver_data *dd) { + mtip_hw_shutdown(dd); + /* Delete our gendisk structure, and cleanup the blk queue. */ if (dd->disk) { dev_info(&dd->pdev->dev, @@ -4399,6 +4105,7 @@ static int mtip_block_shutdown(struct driver_data *dd) if (dd->disk->queue) { del_gendisk(dd->disk); blk_cleanup_queue(dd->queue); + blk_mq_free_tag_set(&dd->tags); } else put_disk(dd->disk); dd->disk = NULL; @@ -4408,8 +4115,6 @@ static int mtip_block_shutdown(struct driver_data *dd) spin_lock(&rssd_index_lock); ida_remove(&rssd_index_ida, dd->index); spin_unlock(&rssd_index_lock); - - mtip_hw_shutdown(dd); return 0; } @@ -4479,6 +4184,57 @@ static DEFINE_HANDLER(5); static DEFINE_HANDLER(6); static DEFINE_HANDLER(7); +static void mtip_disable_link_opts(struct driver_data *dd, struct pci_dev *pdev) +{ + int pos; + unsigned short pcie_dev_ctrl; + + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (pos) { + pci_read_config_word(pdev, + pos + PCI_EXP_DEVCTL, + &pcie_dev_ctrl); + if (pcie_dev_ctrl & (1 << 11) || + pcie_dev_ctrl & (1 << 4)) { + dev_info(&dd->pdev->dev, + "Disabling ERO/No-Snoop on bridge device %04x:%04x\n", + pdev->vendor, pdev->device); + pcie_dev_ctrl &= ~(PCI_EXP_DEVCTL_NOSNOOP_EN | + PCI_EXP_DEVCTL_RELAX_EN); + pci_write_config_word(pdev, + pos + PCI_EXP_DEVCTL, + pcie_dev_ctrl); + } + } +} + +static void mtip_fix_ero_nosnoop(struct driver_data *dd, struct pci_dev *pdev) +{ + /* + * This workaround is specific to AMD/ATI chipset with a PCI upstream + * device with device id 0x5aXX + */ + if (pdev->bus && pdev->bus->self) { + if (pdev->bus->self->vendor == PCI_VENDOR_ID_ATI && + ((pdev->bus->self->device & 0xff00) == 0x5a00)) { + mtip_disable_link_opts(dd, pdev->bus->self); + } else { + /* Check further up the topology */ + struct pci_dev *parent_dev = pdev->bus->self; + if (parent_dev->bus && + parent_dev->bus->parent && + parent_dev->bus->parent->self && + parent_dev->bus->parent->self->vendor == + PCI_VENDOR_ID_ATI && + (parent_dev->bus->parent->self->device & + 0xff00) == 0x5a00) { + mtip_disable_link_opts(dd, + parent_dev->bus->parent->self); + } + } + } +} + /* * Called for each supported PCI device detected. * @@ -4630,6 +4386,8 @@ static int mtip_pci_probe(struct pci_dev *pdev, goto msi_initialize_err; } + mtip_fix_ero_nosnoop(dd, pdev); + /* Initialize the block layer. */ rv = mtip_block_initialize(dd); if (rv < 0) { @@ -4710,8 +4468,6 @@ static void mtip_pci_remove(struct pci_dev *pdev) dev_warn(&dd->pdev->dev, "Completion workers still active!\n"); } - /* Cleanup the outstanding commands */ - mtip_command_cleanup(dd); /* Clean up the block layer. */ mtip_block_remove(dd); @@ -4935,13 +4691,13 @@ static int __init mtip_init(void) */ static void __exit mtip_exit(void) { - debugfs_remove_recursive(dfs_parent); - /* Release the allocated major block device number. */ unregister_blkdev(mtip_major, MTIP_DRV_NAME); /* Unregister the PCI driver. */ pci_unregister_driver(&mtip_pci_driver); + + debugfs_remove_recursive(dfs_parent); } MODULE_AUTHOR("Micron Technology, Inc"); diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index ffb955e7ccb995..982a88fe1ab28b 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -331,12 +331,8 @@ struct mtip_cmd { */ void (*comp_func)(struct mtip_port *port, int tag, - void *data, + struct mtip_cmd *cmd, int status); - /* Additional callback function that may be called by comp_func() */ - void (*async_callback)(void *data, int status); - - void *async_data; /* Addl. data passed to async_callback() */ int scatter_ents; /* Number of scatter list entries used */ @@ -347,10 +343,6 @@ struct mtip_cmd { int retries; /* The number of retries left for this command. */ int direction; /* Data transfer direction */ - - unsigned long comp_time; /* command completion time, in jiffies */ - - atomic_t active; /* declares if this command sent to the drive. */ }; /* Structure used to describe a port. */ @@ -436,12 +428,6 @@ struct mtip_port { * or error handling is active */ unsigned long cmds_to_issue[SLOTBITS_IN_LONGS]; - /* - * Array of command slots. Structure includes pointers to the - * command header and command table, and completion function and data - * pointers. - */ - struct mtip_cmd commands[MTIP_MAX_COMMAND_SLOTS]; /* Used by mtip_service_thread to wait for an event */ wait_queue_head_t svc_wait; /* @@ -452,13 +438,7 @@ struct mtip_port { /* * Timer used to complete commands that have been active for too long. */ - struct timer_list cmd_timer; unsigned long ic_pause_timer; - /* - * Semaphore used to block threads if there are no - * command slots available. - */ - struct semaphore cmd_slot; /* Semaphore to control queue depth of unaligned IOs */ struct semaphore cmd_slot_unal; @@ -485,6 +465,8 @@ struct driver_data { struct request_queue *queue; /* Our request queue. */ + struct blk_mq_tag_set tags; /* blk_mq tags */ + struct mtip_port *port; /* Pointer to the port data structure. */ unsigned product_type; /* magic value declaring the product type */ diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 3a70ea2f7cd69b..56a027d6115e0f 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -533,7 +533,7 @@ static int nbd_thread(void *data) struct nbd_device *nbd = data; struct request *req; - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); while (!kthread_should_stop() || !list_empty(&nbd->waiting_queue)) { /* wait for something to do */ wait_event_interruptible(nbd->waiting_wq, diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 091b9ea14feb58..e932398588aa18 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -32,6 +32,7 @@ struct nullb { unsigned int index; struct request_queue *q; struct gendisk *disk; + struct blk_mq_tag_set tag_set; struct hrtimer timer; unsigned int queue_depth; spinlock_t lock; @@ -202,8 +203,8 @@ static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer) entry = llist_reverse_order(entry); do { cmd = container_of(entry, struct nullb_cmd, ll_list); - end_cmd(cmd); entry = entry->next; + end_cmd(cmd); } while (entry); } @@ -226,7 +227,7 @@ static void null_cmd_end_timer(struct nullb_cmd *cmd) static void null_softirq_done_fn(struct request *rq) { - end_cmd(rq->special); + end_cmd(blk_mq_rq_to_pdu(rq)); } static inline void null_handle_cmd(struct nullb_cmd *cmd) @@ -311,7 +312,7 @@ static void null_request_fn(struct request_queue *q) static int null_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *rq) { - struct nullb_cmd *cmd = rq->special; + struct nullb_cmd *cmd = blk_mq_rq_to_pdu(rq); cmd->rq = rq; cmd->nq = hctx->driver_data; @@ -320,10 +321,11 @@ static int null_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *rq) return BLK_MQ_RQ_QUEUE_OK; } -static struct blk_mq_hw_ctx *null_alloc_hctx(struct blk_mq_reg *reg, unsigned int hctx_index) +static struct blk_mq_hw_ctx *null_alloc_hctx(struct blk_mq_tag_set *set, + unsigned int hctx_index) { - int b_size = DIV_ROUND_UP(reg->nr_hw_queues, nr_online_nodes); - int tip = (reg->nr_hw_queues % nr_online_nodes); + int b_size = DIV_ROUND_UP(set->nr_hw_queues, nr_online_nodes); + int tip = (set->nr_hw_queues % nr_online_nodes); int node = 0, i, n; /* @@ -338,7 +340,7 @@ static struct blk_mq_hw_ctx *null_alloc_hctx(struct blk_mq_reg *reg, unsigned in tip--; if (!tip) - b_size = reg->nr_hw_queues / nr_online_nodes; + b_size = set->nr_hw_queues / nr_online_nodes; } } @@ -387,13 +389,17 @@ static struct blk_mq_ops null_mq_ops = { .map_queue = blk_mq_map_queue, .init_hctx = null_init_hctx, .complete = null_softirq_done_fn, + .alloc_hctx = blk_mq_alloc_single_hw_queue, + .free_hctx = blk_mq_free_single_hw_queue, }; -static struct blk_mq_reg null_mq_reg = { - .ops = &null_mq_ops, - .queue_depth = 64, - .cmd_size = sizeof(struct nullb_cmd), - .flags = BLK_MQ_F_SHOULD_MERGE, +static struct blk_mq_ops null_mq_ops_pernode = { + .queue_rq = null_queue_rq, + .map_queue = blk_mq_map_queue, + .init_hctx = null_init_hctx, + .complete = null_softirq_done_fn, + .alloc_hctx = null_alloc_hctx, + .free_hctx = null_free_hctx, }; static void null_del_dev(struct nullb *nullb) @@ -402,6 +408,8 @@ static void null_del_dev(struct nullb *nullb) del_gendisk(nullb->disk); blk_cleanup_queue(nullb->q); + if (queue_mode == NULL_Q_MQ) + blk_mq_free_tag_set(&nullb->tag_set); put_disk(nullb->disk); kfree(nullb); } @@ -506,7 +514,7 @@ static int null_add_dev(void) nullb = kzalloc_node(sizeof(*nullb), GFP_KERNEL, home_node); if (!nullb) - return -ENOMEM; + goto out; spin_lock_init(&nullb->lock); @@ -514,49 +522,47 @@ static int null_add_dev(void) submit_queues = nr_online_nodes; if (setup_queues(nullb)) - goto err; + goto out_free_nullb; if (queue_mode == NULL_Q_MQ) { - null_mq_reg.numa_node = home_node; - null_mq_reg.queue_depth = hw_queue_depth; - null_mq_reg.nr_hw_queues = submit_queues; - - if (use_per_node_hctx) { - null_mq_reg.ops->alloc_hctx = null_alloc_hctx; - null_mq_reg.ops->free_hctx = null_free_hctx; - } else { - null_mq_reg.ops->alloc_hctx = blk_mq_alloc_single_hw_queue; - null_mq_reg.ops->free_hctx = blk_mq_free_single_hw_queue; - } - - nullb->q = blk_mq_init_queue(&null_mq_reg, nullb); + if (use_per_node_hctx) + nullb->tag_set.ops = &null_mq_ops_pernode; + else + nullb->tag_set.ops = &null_mq_ops; + nullb->tag_set.nr_hw_queues = submit_queues; + nullb->tag_set.queue_depth = hw_queue_depth; + nullb->tag_set.numa_node = home_node; + nullb->tag_set.cmd_size = sizeof(struct nullb_cmd); + nullb->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; + nullb->tag_set.driver_data = nullb; + + if (blk_mq_alloc_tag_set(&nullb->tag_set)) + goto out_cleanup_queues; + + nullb->q = blk_mq_init_queue(&nullb->tag_set); + if (!nullb->q) + goto out_cleanup_tags; } else if (queue_mode == NULL_Q_BIO) { nullb->q = blk_alloc_queue_node(GFP_KERNEL, home_node); + if (!nullb->q) + goto out_cleanup_queues; blk_queue_make_request(nullb->q, null_queue_bio); init_driver_queues(nullb); } else { nullb->q = blk_init_queue_node(null_request_fn, &nullb->lock, home_node); + if (!nullb->q) + goto out_cleanup_queues; blk_queue_prep_rq(nullb->q, null_rq_prep_fn); - if (nullb->q) - blk_queue_softirq_done(nullb->q, null_softirq_done_fn); + blk_queue_softirq_done(nullb->q, null_softirq_done_fn); init_driver_queues(nullb); } - if (!nullb->q) - goto queue_fail; - nullb->q->queuedata = nullb; queue_flag_set_unlocked(QUEUE_FLAG_NONROT, nullb->q); disk = nullb->disk = alloc_disk_node(1, home_node); - if (!disk) { -queue_fail: - blk_cleanup_queue(nullb->q); - cleanup_queues(nullb); -err: - kfree(nullb); - return -ENOMEM; - } + if (!disk) + goto out_cleanup_blk_queue; mutex_lock(&lock); list_add_tail(&nullb->list, &nullb_list); @@ -579,6 +585,18 @@ static int null_add_dev(void) sprintf(disk->disk_name, "nullb%d", nullb->index); add_disk(disk); return 0; + +out_cleanup_blk_queue: + blk_cleanup_queue(nullb->q); +out_cleanup_tags: + if (queue_mode == NULL_Q_MQ) + blk_mq_free_tag_set(&nullb->tag_set); +out_cleanup_queues: + cleanup_queues(nullb); +out_free_nullb: + kfree(nullb); +out: + return -ENOMEM; } static int __init null_init(void) diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index e76bdc074dbe56..719cb1bc164016 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -747,7 +747,7 @@ static void do_pcd_request(struct request_queue * q) pcd_current = cd; pcd_sector = blk_rq_pos(pcd_req); pcd_count = blk_rq_cur_sectors(pcd_req); - pcd_buf = pcd_req->buffer; + pcd_buf = bio_data(pcd_req->bio); pcd_busy = 1; ps_set_intr(do_pcd_read, NULL, 0, nice); return; diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 19ad8f0c83efe6..fea7e76a00de66 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -454,7 +454,7 @@ static enum action do_pd_io_start(void) if (pd_block + pd_count > get_capacity(pd_req->rq_disk)) return Fail; pd_run = blk_rq_sectors(pd_req); - pd_buf = pd_req->buffer; + pd_buf = bio_data(pd_req->bio); pd_retries = 0; if (pd_cmd == READ) return do_pd_read_start(); @@ -485,7 +485,7 @@ static int pd_next_buf(void) spin_lock_irqsave(&pd_lock, saved_flags); __blk_end_request_cur(pd_req, 0); pd_count = blk_rq_cur_sectors(pd_req); - pd_buf = pd_req->buffer; + pd_buf = bio_data(pd_req->bio); spin_unlock_irqrestore(&pd_lock, saved_flags); return 0; } diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index f5c86d523ba0c8..9a15fd3c934940 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -795,7 +795,7 @@ static void do_pf_request(struct request_queue * q) } pf_cmd = rq_data_dir(pf_req); - pf_buf = pf_req->buffer; + pf_buf = bio_data(pf_req->bio); pf_retries = 0; pf_busy = 1; @@ -827,7 +827,7 @@ static int pf_next_buf(void) if (!pf_req) return 1; pf_count = blk_rq_cur_sectors(pf_req); - pf_buf = pf_req->buffer; + pf_buf = bio_data(pf_req->bio); } return 0; } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index a2af73db187b69..ef166ad2dbadc3 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1463,7 +1463,7 @@ static int kcdrwd(void *foobar) struct packet_data *pkt; long min_sleep_time, residue; - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); set_freezable(); for (;;) { diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index a69dd93d1bd553..608532d3f8c910 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -563,7 +563,6 @@ skd_prep_discard_cdb(struct skd_scsi_request *scsi_req, req = skreq->req; blk_add_request_payload(req, page, len); - req->buffer = buf; } static void skd_request_fn_not_online(struct request_queue *q); @@ -744,6 +743,7 @@ static void skd_request_fn(struct request_queue *q) break; } skreq->discard_page = 1; + req->completion_data = page; skd_prep_discard_cdb(scsi_req, skreq, page, lba, count); } else if (flush == SKD_FLUSH_ZERO_SIZE_FIRST) { @@ -858,8 +858,7 @@ static void skd_end_request(struct skd_device *skdev, (skreq->discard_page == 1)) { pr_debug("%s:%s:%d, free the page!", skdev->name, __func__, __LINE__); - free_page((unsigned long)req->buffer); - req->buffer = NULL; + __free_page(req->completion_data); } if (unlikely(error)) { @@ -3945,15 +3944,14 @@ static int skd_acquire_msix(struct skd_device *skdev) for (i = 0; i < SKD_MAX_MSIX_COUNT; i++) entries[i].entry = i; - rc = pci_enable_msix_range(pdev, entries, - SKD_MIN_MSIX_COUNT, SKD_MAX_MSIX_COUNT); - if (rc < 0) { + rc = pci_enable_msix_exact(pdev, entries, SKD_MAX_MSIX_COUNT); + if (rc) { pr_err("(%s): failed to enable MSI-X %d\n", skd_name(skdev), rc); goto msix_out; } - skdev->msix_count = rc; + skdev->msix_count = SKD_MAX_MSIX_COUNT; skdev->msix_entries = kzalloc(sizeof(struct skd_msix_entry) * skdev->msix_count, GFP_KERNEL); if (!skdev->msix_entries) { diff --git a/drivers/block/swim.c b/drivers/block/swim.c index b02d53a399f378..6b44bbe528b7b1 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -549,7 +549,7 @@ static void redo_fd_request(struct request_queue *q) case READ: err = floppy_read_sectors(fs, blk_rq_pos(req), blk_rq_cur_sectors(req), - req->buffer); + bio_data(req->bio)); break; } done: diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index c74f7b56e7c401..523ee8fd4c150e 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -342,7 +342,7 @@ static void start_request(struct floppy_state *fs) swim3_dbg("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n", req->rq_disk->disk_name, req->cmd, (long)blk_rq_pos(req), blk_rq_sectors(req), - req->buffer); + bio_data(req->bio)); swim3_dbg(" errors=%d current_nr_sectors=%u\n", req->errors, blk_rq_cur_sectors(req)); #endif @@ -479,11 +479,11 @@ static inline void setup_transfer(struct floppy_state *fs) /* Set up 3 dma commands: write preamble, data, postamble */ init_dma(cp, OUTPUT_MORE, write_preamble, sizeof(write_preamble)); ++cp; - init_dma(cp, OUTPUT_MORE, req->buffer, 512); + init_dma(cp, OUTPUT_MORE, bio_data(req->bio), 512); ++cp; init_dma(cp, OUTPUT_LAST, write_postamble, sizeof(write_postamble)); } else { - init_dma(cp, INPUT_LAST, req->buffer, n * 512); + init_dma(cp, INPUT_LAST, bio_data(req->bio), n * 512); } ++cp; out_le16(&cp->command, DBDMA_STOP); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 6d8a87f252de56..7a51f065edcd94 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -30,6 +30,9 @@ struct virtio_blk /* The disk structure for the kernel. */ struct gendisk *disk; + /* Block layer tags. */ + struct blk_mq_tag_set tag_set; + /* Process context for config space updates */ struct work_struct config_work; @@ -112,7 +115,7 @@ static int __virtblk_add_req(struct virtqueue *vq, static inline void virtblk_request_done(struct request *req) { - struct virtblk_req *vbr = req->special; + struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); int error = virtblk_result(vbr); if (req->cmd_type == REQ_TYPE_BLOCK_PC) { @@ -148,13 +151,13 @@ static void virtblk_done(struct virtqueue *vq) /* In case queue is stopped waiting for more buffers. */ if (req_done) - blk_mq_start_stopped_hw_queues(vblk->disk->queue); + blk_mq_start_stopped_hw_queues(vblk->disk->queue, true); } static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req) { struct virtio_blk *vblk = hctx->queue->queuedata; - struct virtblk_req *vbr = req->special; + struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); unsigned long flags; unsigned int num; const bool last = (req->cmd_flags & REQ_END) != 0; @@ -480,32 +483,28 @@ static const struct device_attribute dev_attr_cache_type_rw = __ATTR(cache_type, S_IRUGO|S_IWUSR, virtblk_cache_type_show, virtblk_cache_type_store); +static int virtblk_init_request(void *data, struct request *rq, + unsigned int hctx_idx, unsigned int request_idx, + unsigned int numa_node) +{ + struct virtio_blk *vblk = data; + struct virtblk_req *vbr = blk_mq_rq_to_pdu(rq); + + sg_init_table(vbr->sg, vblk->sg_elems); + return 0; +} + static struct blk_mq_ops virtio_mq_ops = { .queue_rq = virtio_queue_rq, .map_queue = blk_mq_map_queue, .alloc_hctx = blk_mq_alloc_single_hw_queue, .free_hctx = blk_mq_free_single_hw_queue, .complete = virtblk_request_done, + .init_request = virtblk_init_request, }; -static struct blk_mq_reg virtio_mq_reg = { - .ops = &virtio_mq_ops, - .nr_hw_queues = 1, - .queue_depth = 0, /* Set in virtblk_probe */ - .numa_node = NUMA_NO_NODE, - .flags = BLK_MQ_F_SHOULD_MERGE, -}; -module_param_named(queue_depth, virtio_mq_reg.queue_depth, uint, 0444); - -static int virtblk_init_vbr(void *data, struct blk_mq_hw_ctx *hctx, - struct request *rq, unsigned int nr) -{ - struct virtio_blk *vblk = data; - struct virtblk_req *vbr = rq->special; - - sg_init_table(vbr->sg, vblk->sg_elems); - return 0; -} +static unsigned int virtblk_queue_depth; +module_param_named(queue_depth, virtblk_queue_depth, uint, 0444); static int virtblk_probe(struct virtio_device *vdev) { @@ -561,24 +560,34 @@ static int virtblk_probe(struct virtio_device *vdev) } /* Default queue sizing is to fill the ring. */ - if (!virtio_mq_reg.queue_depth) { - virtio_mq_reg.queue_depth = vblk->vq->num_free; + if (!virtblk_queue_depth) { + virtblk_queue_depth = vblk->vq->num_free; /* ... but without indirect descs, we use 2 descs per req */ if (!virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC)) - virtio_mq_reg.queue_depth /= 2; + virtblk_queue_depth /= 2; } - virtio_mq_reg.cmd_size = + + memset(&vblk->tag_set, 0, sizeof(vblk->tag_set)); + vblk->tag_set.ops = &virtio_mq_ops; + vblk->tag_set.nr_hw_queues = 1; + vblk->tag_set.queue_depth = virtblk_queue_depth; + vblk->tag_set.numa_node = NUMA_NO_NODE; + vblk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; + vblk->tag_set.cmd_size = sizeof(struct virtblk_req) + sizeof(struct scatterlist) * sg_elems; + vblk->tag_set.driver_data = vblk; - q = vblk->disk->queue = blk_mq_init_queue(&virtio_mq_reg, vblk); + err = blk_mq_alloc_tag_set(&vblk->tag_set); + if (err) + goto out_put_disk; + + q = vblk->disk->queue = blk_mq_init_queue(&vblk->tag_set); if (!q) { err = -ENOMEM; - goto out_put_disk; + goto out_free_tags; } - blk_mq_init_commands(q, virtblk_init_vbr, vblk); - q->queuedata = vblk; virtblk_name_format("vd", index, vblk->disk->disk_name, DISK_NAME_LEN); @@ -679,6 +688,8 @@ static int virtblk_probe(struct virtio_device *vdev) out_del_disk: del_gendisk(vblk->disk); blk_cleanup_queue(vblk->disk->queue); +out_free_tags: + blk_mq_free_tag_set(&vblk->tag_set); out_put_disk: put_disk(vblk->disk); out_free_vq: @@ -705,6 +716,8 @@ static void virtblk_remove(struct virtio_device *vdev) del_gendisk(vblk->disk); blk_cleanup_queue(vblk->disk->queue); + blk_mq_free_tag_set(&vblk->tag_set); + /* Stop all the virtqueues. */ vdev->config->reset(vdev); @@ -749,7 +762,7 @@ static int virtblk_restore(struct virtio_device *vdev) vblk->config_enable = true; ret = init_vq(vdev->priv); if (!ret) - blk_mq_start_stopped_hw_queues(vblk->disk->queue); + blk_mq_start_stopped_hw_queues(vblk->disk->queue, true); return ret; } diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index efe1b4761735a7..283a30e88287b6 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -612,10 +612,10 @@ static void do_blkif_request(struct request_queue *rq) } pr_debug("do_blk_req %p: cmd %p, sec %lx, " - "(%u/%u) buffer:%p [%s]\n", + "(%u/%u) [%s]\n", req, req->cmd, (unsigned long)blk_rq_pos(req), blk_rq_cur_sectors(req), blk_rq_sectors(req), - req->buffer, rq_data_dir(req) ? "write" : "read"); + rq_data_dir(req) ? "write" : "read"); if (blkif_queue_request(req)) { blk_requeue_request(rq, req); diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 1393b8871a281a..ab3ea62e5dfc70 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -661,7 +661,7 @@ static void ace_fsm_dostate(struct ace_device *ace) rq_data_dir(req)); ace->req = req; - ace->data_ptr = req->buffer; + ace->data_ptr = bio_data(req->bio); ace->data_count = blk_rq_cur_sectors(req) * ACE_BUF_PER_SECTOR; ace_out32(ace, ACE_MPULBA, blk_rq_pos(req) & 0x0FFFFFFF); @@ -733,7 +733,7 @@ static void ace_fsm_dostate(struct ace_device *ace) * blk_rq_sectors(ace->req), * blk_rq_cur_sectors(ace->req)); */ - ace->data_ptr = ace->req->buffer; + ace->data_ptr = bio_data(ace->req->bio); ace->data_count = blk_rq_cur_sectors(ace->req) * 16; ace_fsm_yieldirq(ace); break; diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 27de5046708a23..968f9e52effa8c 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -87,13 +87,15 @@ static void do_z2_request(struct request_queue *q) while (len) { unsigned long addr = start & Z2RAM_CHUNKMASK; unsigned long size = Z2RAM_CHUNKSIZE - addr; + void *buffer = bio_data(req->bio); + if (len < size) size = len; addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ]; if (rq_data_dir(req) == READ) - memcpy(req->buffer, (char *)addr, size); + memcpy(buffer, (char *)addr, size); else - memcpy((char *)addr, req->buffer, size); + memcpy((char *)addr, buffer, size); start += size; len -= size; } diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 7399303d7d9978..dc79f88f8717f4 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -59,6 +59,8 @@ struct btmrvl_device { }; struct btmrvl_adapter { + void *hw_regs_buf; + u8 *hw_regs; u32 int_count; struct sk_buff_head tx_queue; u8 psmode; @@ -140,7 +142,7 @@ void btmrvl_interrupt(struct btmrvl_private *priv); bool 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_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd); int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv); int btmrvl_enable_ps(struct btmrvl_private *priv); int btmrvl_prepare_command(struct btmrvl_private *priv); diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 2c4997ce248484..e9dbddb0b8f1ef 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -24,6 +24,7 @@ #include #include "btmrvl_drv.h" +#include "btmrvl_sdio.h" #define VERSION "1.0" @@ -201,7 +202,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode, return 0; } -int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) +int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd) { int ret; @@ -337,10 +338,25 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb) static void btmrvl_init_adapter(struct btmrvl_private *priv) { + int buf_size; + skb_queue_head_init(&priv->adapter->tx_queue); priv->adapter->ps_state = PS_AWAKE; + buf_size = ALIGN_SZ(SDIO_BLOCK_SIZE, BTSDIO_DMA_ALIGN); + priv->adapter->hw_regs_buf = kzalloc(buf_size, GFP_KERNEL); + if (!priv->adapter->hw_regs_buf) { + priv->adapter->hw_regs = NULL; + BT_ERR("Unable to allocate buffer for hw_regs."); + } else { + priv->adapter->hw_regs = + (u8 *)ALIGN_ADDR(priv->adapter->hw_regs_buf, + BTSDIO_DMA_ALIGN); + BT_DBG("hw_regs_buf=%p hw_regs=%p", + priv->adapter->hw_regs_buf, priv->adapter->hw_regs); + } + init_waitqueue_head(&priv->adapter->cmd_wait_q); } @@ -348,6 +364,7 @@ static void btmrvl_free_adapter(struct btmrvl_private *priv) { skb_queue_purge(&priv->adapter->tx_queue); + kfree(priv->adapter->hw_regs_buf); kfree(priv->adapter); priv->adapter = NULL; diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 1b52c9f5230d32..9dedca516ff505 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -64,6 +64,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = { .io_port_0 = 0x00, .io_port_1 = 0x01, .io_port_2 = 0x02, + .int_read_to_clear = false, }; static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { .cfg = 0x00, @@ -80,6 +81,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { .io_port_0 = 0x78, .io_port_1 = 0x79, .io_port_2 = 0x7a, + .int_read_to_clear = false, }; static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { @@ -97,6 +99,9 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { .io_port_0 = 0xd8, .io_port_1 = 0xd9, .io_port_2 = 0xda, + .int_read_to_clear = true, + .host_int_rsr = 0x01, + .card_misc_cfg = 0xcc, }; static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { @@ -667,46 +672,78 @@ static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv) return 0; } -static void btmrvl_sdio_interrupt(struct sdio_func *func) +static int btmrvl_sdio_read_to_clear(struct btmrvl_sdio_card *card, u8 *ireg) { - struct btmrvl_private *priv; - struct btmrvl_sdio_card *card; - ulong flags; - u8 ireg = 0; + struct btmrvl_adapter *adapter = card->priv->adapter; int ret; - card = sdio_get_drvdata(func); - if (!card || !card->priv) { - BT_ERR("sbi_interrupt(%p) card or priv is " - "NULL, card=%p\n", func, card); - return; + ret = sdio_readsb(card->func, adapter->hw_regs, 0, SDIO_BLOCK_SIZE); + if (ret) { + BT_ERR("sdio_readsb: read int hw_regs failed: %d", ret); + return ret; } - priv = card->priv; + *ireg = adapter->hw_regs[card->reg->host_intstatus]; + BT_DBG("hw_regs[%#x]=%#x", card->reg->host_intstatus, *ireg); + + return 0; +} - ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret); +static int btmrvl_sdio_write_to_clear(struct btmrvl_sdio_card *card, u8 *ireg) +{ + int ret; + + *ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret); if (ret) { - BT_ERR("sdio_readb: read int status register failed"); - return; + BT_ERR("sdio_readb: read int status failed: %d", ret); + return ret; } - if (ireg != 0) { + if (*ireg) { /* * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS * Clear the interrupt status register and re-enable the * interrupt. */ - BT_DBG("ireg = 0x%x", ireg); + BT_DBG("int_status = 0x%x", *ireg); - sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS | - UP_LD_HOST_INT_STATUS), - card->reg->host_intstatus, &ret); + sdio_writeb(card->func, ~(*ireg) & (DN_LD_HOST_INT_STATUS | + UP_LD_HOST_INT_STATUS), + card->reg->host_intstatus, &ret); if (ret) { - BT_ERR("sdio_writeb: clear int status register failed"); - return; + BT_ERR("sdio_writeb: clear int status failed: %d", ret); + return ret; } } + return 0; +} + +static void btmrvl_sdio_interrupt(struct sdio_func *func) +{ + struct btmrvl_private *priv; + struct btmrvl_sdio_card *card; + ulong flags; + u8 ireg = 0; + int ret; + + card = sdio_get_drvdata(func); + if (!card || !card->priv) { + BT_ERR("sbi_interrupt(%p) card or priv is " + "NULL, card=%p\n", func, card); + return; + } + + priv = card->priv; + + if (card->reg->int_read_to_clear) + ret = btmrvl_sdio_read_to_clear(card, &ireg); + else + ret = btmrvl_sdio_write_to_clear(card, &ireg); + + if (ret) + return; + spin_lock_irqsave(&priv->driver_lock, flags); sdio_ireg |= ireg; spin_unlock_irqrestore(&priv->driver_lock, flags); @@ -777,6 +814,30 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport); + if (card->reg->int_read_to_clear) { + reg = sdio_readb(func, card->reg->host_int_rsr, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + sdio_writeb(func, reg | 0x3f, card->reg->host_int_rsr, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + + reg = sdio_readb(func, card->reg->card_misc_cfg, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + sdio_writeb(func, reg | 0x10, card->reg->card_misc_cfg, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + } + sdio_set_drvdata(func, card); sdio_release_host(func); diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index 43d35a609ca9a9..d4dd3b0fa53d16 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -78,6 +78,9 @@ struct btmrvl_sdio_card_reg { u8 io_port_0; u8 io_port_1; u8 io_port_2; + bool int_read_to_clear; + u8 host_int_rsr; + u8 card_misc_cfg; }; struct btmrvl_sdio_card { diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index a7dfbf9a3afb6b..a1c80b0c7663d2 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -49,6 +49,7 @@ static struct usb_driver btusb_driver; #define BTUSB_WRONG_SCO_MTU 0x40 #define BTUSB_ATH3012 0x80 #define BTUSB_INTEL 0x100 +#define BTUSB_BCM_PATCHRAM 0x200 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -111,7 +112,8 @@ static const struct usb_device_id btusb_table[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) }, /* Broadcom devices with vendor specific id */ - { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01), + .driver_info = BTUSB_BCM_PATCHRAM }, /* Belkin F8065bf - Broadcom based */ { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) }, @@ -1381,6 +1383,154 @@ static int btusb_setup_intel(struct hci_dev *hdev) return 0; } +static int btusb_setup_bcm_patchram(struct hci_dev *hdev) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + struct usb_device *udev = data->udev; + char fw_name[64]; + const struct firmware *fw; + const u8 *fw_ptr; + size_t fw_size; + const struct hci_command_hdr *cmd; + const u8 *cmd_param; + u16 opcode; + struct sk_buff *skb; + struct hci_rp_read_local_version *ver; + long ret; + + snprintf(fw_name, sizeof(fw_name), "brcm/%s-%04x-%04x.hcd", + udev->product ? udev->product : "BCM", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + + ret = request_firmware(&fw, fw_name, &hdev->dev); + if (ret < 0) { + BT_INFO("%s: BCM: patch %s not found", hdev->name, + fw_name); + return 0; + } + + /* Reset */ + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret); + goto done; + } + kfree_skb(skb); + + /* Read Local Version Info */ + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", + hdev->name, ret); + goto done; + } + + if (skb->len != sizeof(*ver)) { + BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", + hdev->name); + kfree_skb(skb); + ret = -EIO; + goto done; + } + + ver = (struct hci_rp_read_local_version *) skb->data; + BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x " + "lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev, + ver->lmp_ver, ver->lmp_subver); + kfree_skb(skb); + + /* Start Download */ + skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: BCM: Download Minidrv command failed (%ld)", + hdev->name, ret); + goto reset_fw; + } + kfree_skb(skb); + + /* 50 msec delay after Download Minidrv completes */ + msleep(50); + + fw_ptr = fw->data; + fw_size = fw->size; + + while (fw_size >= sizeof(*cmd)) { + cmd = (struct hci_command_hdr *) fw_ptr; + fw_ptr += sizeof(*cmd); + fw_size -= sizeof(*cmd); + + if (fw_size < cmd->plen) { + BT_ERR("%s: BCM: patch %s is corrupted", + hdev->name, fw_name); + ret = -EINVAL; + goto reset_fw; + } + + cmd_param = fw_ptr; + fw_ptr += cmd->plen; + fw_size -= cmd->plen; + + opcode = le16_to_cpu(cmd->opcode); + + skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: BCM: patch command %04x failed (%ld)", + hdev->name, opcode, ret); + goto reset_fw; + } + kfree_skb(skb); + } + + /* 250 msec delay after Launch Ram completes */ + msleep(250); + +reset_fw: + /* Reset */ + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret); + goto done; + } + kfree_skb(skb); + + /* Read Local Version Info */ + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", + hdev->name, ret); + goto done; + } + + if (skb->len != sizeof(*ver)) { + BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", + hdev->name); + kfree_skb(skb); + ret = -EIO; + goto done; + } + + ver = (struct hci_rp_read_local_version *) skb->data; + BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x " + "lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev, + ver->lmp_ver, ver->lmp_subver); + kfree_skb(skb); + +done: + release_firmware(fw); + + return ret; +} + static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1486,6 +1636,9 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BCM92035) hdev->setup = btusb_setup_bcm92035; + if (id->driver_info & BTUSB_BCM_PATCHRAM) + hdev->setup = btusb_setup_bcm_patchram; + if (id->driver_info & BTUSB_INTEL) hdev->setup = btusb_setup_intel; diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 7048a583fe51a6..66db9a803373ef 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -55,13 +55,6 @@ struct h4_struct { struct sk_buff_head txq; }; -/* H4 receiver States */ -#define H4_W4_PACKET_TYPE 0 -#define H4_W4_EVENT_HDR 1 -#define H4_W4_ACL_HDR 2 -#define H4_W4_SCO_HDR 3 -#define H4_W4_DATA 4 - /* Initialize protocol */ static int h4_open(struct hci_uart *hu) { diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index f1fbf4f1e5bec2..e00f8f5b5c8e10 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -118,10 +118,6 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) int hci_uart_tx_wakeup(struct hci_uart *hu) { - struct tty_struct *tty = hu->tty; - struct hci_dev *hdev = hu->hdev; - struct sk_buff *skb; - if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); return 0; @@ -129,6 +125,22 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) BT_DBG(""); + schedule_work(&hu->write_work); + + return 0; +} + +static void hci_uart_write_work(struct work_struct *work) +{ + struct hci_uart *hu = container_of(work, struct hci_uart, write_work); + struct tty_struct *tty = hu->tty; + struct hci_dev *hdev = hu->hdev; + struct sk_buff *skb; + + /* REVISIT: should we cope with bad skbs or ->write() returning + * and error value ? + */ + restart: clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); @@ -153,7 +165,6 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) goto restart; clear_bit(HCI_UART_SENDING, &hu->tx_state); - return 0; } static void hci_uart_init_work(struct work_struct *work) @@ -282,6 +293,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) tty->receive_room = 65536; INIT_WORK(&hu->init_ready, hci_uart_init_work); + INIT_WORK(&hu->write_work, hci_uart_write_work); spin_lock_init(&hu->rx_lock); @@ -319,6 +331,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) if (hdev) hci_uart_close(hdev); + cancel_work_sync(&hu->write_work); + if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { if (hdev) { if (test_bit(HCI_UART_REGISTERED, &hu->flags)) diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index fffa61ff5cb149..12df101ca942d1 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -68,6 +68,7 @@ struct hci_uart { unsigned long hdev_flags; struct work_struct init_ready; + struct work_struct write_work; struct hci_uart_proto *proto; void *priv; diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index 293e2e0a0a87c7..26c3779d871da6 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -56,6 +56,7 @@ #include #include #include +#include /* * DDR target is the same on all platforms. @@ -222,12 +223,6 @@ static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus, */ if ((u64)base < wend && end > wbase) return 0; - - /* - * Check if target/attribute conflicts - */ - if (target == wtarget && attr == wattr) - return 0; } return 1; @@ -266,6 +261,17 @@ static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus, mbus->soc->win_cfg_offset(win); u32 ctrl, remap_addr; + if (!is_power_of_2(size)) { + WARN(true, "Invalid MBus window size: 0x%zx\n", size); + return -EINVAL; + } + + if ((base & (phys_addr_t)(size - 1)) != 0) { + WARN(true, "Invalid MBus base/size: %pa len 0x%zx\n", &base, + size); + return -EINVAL; + } + ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) | (attr << WIN_CTRL_ATTR_SHIFT) | (target << WIN_CTRL_TGT_SHIFT) | @@ -413,6 +419,10 @@ static int mvebu_devs_debug_show(struct seq_file *seq, void *v) win, (unsigned long long)wbase, (unsigned long long)(wbase + wsize), wtarget, wattr); + if (!is_power_of_2(wsize) || + ((wbase & (u64)(wsize - 1)) != 0)) + seq_puts(seq, " (Invalid base/size!!)"); + if (win < mbus->soc->num_remappable_wins) { seq_printf(seq, " (remap %016llx)\n", (unsigned long long)wremap); @@ -694,7 +704,6 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, phys_addr_t sdramwins_phys_base, size_t sdramwins_size) { - struct device_node *np; int win; mbus->mbuswins_base = ioremap(mbuswins_phys_base, mbuswins_size); @@ -707,12 +716,6 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, return -ENOMEM; } - np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"); - if (np) { - mbus->hw_io_coherency = 1; - of_node_put(np); - } - for (win = 0; win < mbus->soc->num_wins; win++) mvebu_mbus_disable_window(mbus, win); @@ -882,7 +885,7 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np, } } -int __init mvebu_mbus_dt_init(void) +int __init mvebu_mbus_dt_init(bool is_coherent) { struct resource mbuswins_res, sdramwins_res; struct device_node *np, *controller; @@ -920,6 +923,8 @@ int __init mvebu_mbus_dt_init(void) return -EINVAL; } + mbus_state.hw_io_coherency = is_coherent; + /* Get optional pcie-{mem,io}-aperture properties */ mvebu_mbus_get_pcie_resources(np, &mbus_state.pcie_mem_aperture, &mbus_state.pcie_io_aperture); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 8a3aff724d989c..49ac5662585b8d 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -312,36 +312,24 @@ static const char *mrw_format_status[] = { static const char *mrw_address_space[] = { "DMA", "GAA" }; -#if (ERRLOGMASK!=CD_NOTHING) -#define cdinfo(type, fmt, args...) \ +#if (ERRLOGMASK != CD_NOTHING) +#define cd_dbg(type, fmt, ...) \ do { \ if ((ERRLOGMASK & type) || debug == 1) \ - pr_info(fmt, ##args); \ + pr_debug(fmt, ##__VA_ARGS__); \ } while (0) #else -#define cdinfo(type, fmt, args...) \ +#define cd_dbg(type, fmt, ...) \ do { \ if (0 && (ERRLOGMASK & type) || debug == 1) \ - pr_info(fmt, ##args); \ + pr_debug(fmt, ##__VA_ARGS__); \ } while (0) #endif -/* These are used to simplify getting data in from and back to user land */ -#define IOCTL_IN(arg, type, in) \ - if (copy_from_user(&(in), (type __user *) (arg), sizeof (in))) \ - return -EFAULT; - -#define IOCTL_OUT(arg, type, out) \ - if (copy_to_user((type __user *) (arg), &(out), sizeof (out))) \ - return -EFAULT; - /* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in a lot of places. This macro makes the code more clear. */ #define CDROM_CAN(type) (cdi->ops->capability & ~cdi->mask & (type)) -/* used in the audio ioctls */ -#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret - /* * Another popular OS uses 7 seconds as the hard timeout for default * commands, so it is a good choice for us as well. @@ -349,21 +337,6 @@ do { \ #define CDROM_DEF_TIMEOUT (7 * HZ) /* Not-exported routines. */ -static int open_for_data(struct cdrom_device_info * cdi); -static int check_for_audio_disc(struct cdrom_device_info * cdi, - struct cdrom_device_ops * cdo); -static void sanitize_format(union cdrom_addr *addr, - u_char * curr, u_char requested); -static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, - unsigned long arg); - -int cdrom_get_last_written(struct cdrom_device_info *, long *); -static int cdrom_get_next_writable(struct cdrom_device_info *, long *); -static void cdrom_count_tracks(struct cdrom_device_info *, tracktype*); - -static int cdrom_mrw_exit(struct cdrom_device_info *cdi); - -static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di); static void cdrom_sysctl_register(void); @@ -382,113 +355,65 @@ static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi, return -EIO; } -/* This macro makes sure we don't have to check on cdrom_device_ops - * existence in the run-time routines below. Change_capability is a - * hack to have the capability flags defined const, while we can still - * change it here without gcc complaining at every line. - */ -#define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits) - -int register_cdrom(struct cdrom_device_info *cdi) -{ - static char banner_printed; - struct cdrom_device_ops *cdo = cdi->ops; - int *change_capability = (int *)&cdo->capability; /* hack */ - - cdinfo(CD_OPEN, "entering register_cdrom\n"); - - if (cdo->open == NULL || cdo->release == NULL) - return -EINVAL; - if (!banner_printed) { - pr_info("Uniform CD-ROM driver " REVISION "\n"); - banner_printed = 1; - cdrom_sysctl_register(); - } - - ENSURE(drive_status, CDC_DRIVE_STATUS ); - if (cdo->check_events == NULL && cdo->media_changed == NULL) - *change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC); - ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); - ENSURE(lock_door, CDC_LOCK); - ENSURE(select_speed, CDC_SELECT_SPEED); - ENSURE(get_last_session, CDC_MULTI_SESSION); - ENSURE(get_mcn, CDC_MCN); - ENSURE(reset, CDC_RESET); - ENSURE(generic_packet, CDC_GENERIC_PACKET); - cdi->mc_flags = 0; - cdo->n_minors = 0; - cdi->options = CDO_USE_FFLAGS; - - if (autoclose==1 && CDROM_CAN(CDC_CLOSE_TRAY)) - cdi->options |= (int) CDO_AUTO_CLOSE; - if (autoeject==1 && CDROM_CAN(CDC_OPEN_TRAY)) - cdi->options |= (int) CDO_AUTO_EJECT; - if (lockdoor==1) - cdi->options |= (int) CDO_LOCK; - if (check_media_type==1) - cdi->options |= (int) CDO_CHECK_TYPE; - - if (CDROM_CAN(CDC_MRW_W)) - cdi->exit = cdrom_mrw_exit; - - if (cdi->disk) - cdi->cdda_method = CDDA_BPC_FULL; - else - cdi->cdda_method = CDDA_OLD; - - if (!cdo->generic_packet) - cdo->generic_packet = cdrom_dummy_generic_packet; - - cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); - mutex_lock(&cdrom_mutex); - list_add(&cdi->list, &cdrom_list); - mutex_unlock(&cdrom_mutex); - return 0; -} -#undef ENSURE - -void unregister_cdrom(struct cdrom_device_info *cdi) +static int cdrom_flush_cache(struct cdrom_device_info *cdi) { - cdinfo(CD_OPEN, "entering unregister_cdrom\n"); + struct packet_command cgc; - mutex_lock(&cdrom_mutex); - list_del(&cdi->list); - mutex_unlock(&cdrom_mutex); + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_FLUSH_CACHE; - if (cdi->exit) - cdi->exit(cdi); + cgc.timeout = 5 * 60 * HZ; - cdi->ops->n_minors--; - cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); + return cdi->ops->generic_packet(cdi, &cgc); } -int cdrom_get_media_event(struct cdrom_device_info *cdi, - struct media_event_desc *med) +/* requires CD R/RW */ +static int cdrom_get_disc_info(struct cdrom_device_info *cdi, + disc_information *di) { + struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; - unsigned char buffer[8]; - struct event_header *eh = (struct event_header *) buffer; + int ret, buflen; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); - cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION; - cgc.cmd[1] = 1; /* IMMED */ - cgc.cmd[4] = 1 << 4; /* media event */ - cgc.cmd[8] = sizeof(buffer); + /* set up command and get the disc info */ + init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); + cgc.cmd[0] = GPCMD_READ_DISC_INFO; + cgc.cmd[8] = cgc.buflen = 2; cgc.quiet = 1; - if (cdi->ops->generic_packet(cdi, &cgc)) - return 1; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) + return ret; - if (be16_to_cpu(eh->data_len) < sizeof(*med)) - return 1; + /* not all drives have the same disc_info length, so requeue + * packet with the length the drive tells us it can supply + */ + buflen = be16_to_cpu(di->disc_information_length) + + sizeof(di->disc_information_length); - if (eh->nea || eh->notification_class != 0x4) - return 1; + if (buflen > sizeof(disc_information)) + buflen = sizeof(disc_information); - memcpy(med, &buffer[sizeof(*eh)], sizeof(*med)); - return 0; + cgc.cmd[8] = cgc.buflen = buflen; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) + return ret; + + /* return actual fill size */ + return buflen; } +/* This macro makes sure we don't have to check on cdrom_device_ops + * existence in the run-time routines below. Change_capability is a + * hack to have the capability flags defined const, while we can still + * change it here without gcc complaining at every line. + */ +#define ENSURE(call, bits) \ +do { \ + if (cdo->call == NULL) \ + *change_capability &= ~(bits); \ +} while (0) + /* * the first prototypes used 0x2c as the page code for the mrw mode page, * subsequently this was changed to 0x03. probe the one used by this drive @@ -605,18 +530,6 @@ static int cdrom_mrw_bgformat_susp(struct cdrom_device_info *cdi, int immed) return cdi->ops->generic_packet(cdi, &cgc); } -static int cdrom_flush_cache(struct cdrom_device_info *cdi) -{ - struct packet_command cgc; - - init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); - cgc.cmd[0] = GPCMD_FLUSH_CACHE; - - cgc.timeout = 5 * 60 * HZ; - - return cdi->ops->generic_packet(cdi, &cgc); -} - static int cdrom_mrw_exit(struct cdrom_device_info *cdi) { disc_information di; @@ -650,17 +563,19 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space) cgc.buffer = buffer; cgc.buflen = sizeof(buffer); - if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0))) + ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0); + if (ret) return ret; - mph = (struct mode_page_header *) buffer; + mph = (struct mode_page_header *)buffer; offset = be16_to_cpu(mph->desc_length); size = be16_to_cpu(mph->mode_data_length) + 2; buffer[offset + 3] = space; cgc.buflen = size; - if ((ret = cdrom_mode_select(cdi, &cgc))) + ret = cdrom_mode_select(cdi, &cgc); + if (ret) return ret; pr_info("%s: mrw address space %s selected\n", @@ -668,6 +583,106 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space) return 0; } +int register_cdrom(struct cdrom_device_info *cdi) +{ + static char banner_printed; + struct cdrom_device_ops *cdo = cdi->ops; + int *change_capability = (int *)&cdo->capability; /* hack */ + + cd_dbg(CD_OPEN, "entering register_cdrom\n"); + + if (cdo->open == NULL || cdo->release == NULL) + return -EINVAL; + if (!banner_printed) { + pr_info("Uniform CD-ROM driver " REVISION "\n"); + banner_printed = 1; + cdrom_sysctl_register(); + } + + ENSURE(drive_status, CDC_DRIVE_STATUS); + if (cdo->check_events == NULL && cdo->media_changed == NULL) + *change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC); + ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); + ENSURE(lock_door, CDC_LOCK); + ENSURE(select_speed, CDC_SELECT_SPEED); + ENSURE(get_last_session, CDC_MULTI_SESSION); + ENSURE(get_mcn, CDC_MCN); + ENSURE(reset, CDC_RESET); + ENSURE(generic_packet, CDC_GENERIC_PACKET); + cdi->mc_flags = 0; + cdo->n_minors = 0; + cdi->options = CDO_USE_FFLAGS; + + if (autoclose == 1 && CDROM_CAN(CDC_CLOSE_TRAY)) + cdi->options |= (int) CDO_AUTO_CLOSE; + if (autoeject == 1 && CDROM_CAN(CDC_OPEN_TRAY)) + cdi->options |= (int) CDO_AUTO_EJECT; + if (lockdoor == 1) + cdi->options |= (int) CDO_LOCK; + if (check_media_type == 1) + cdi->options |= (int) CDO_CHECK_TYPE; + + if (CDROM_CAN(CDC_MRW_W)) + cdi->exit = cdrom_mrw_exit; + + if (cdi->disk) + cdi->cdda_method = CDDA_BPC_FULL; + else + cdi->cdda_method = CDDA_OLD; + + if (!cdo->generic_packet) + cdo->generic_packet = cdrom_dummy_generic_packet; + + cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); + mutex_lock(&cdrom_mutex); + list_add(&cdi->list, &cdrom_list); + mutex_unlock(&cdrom_mutex); + return 0; +} +#undef ENSURE + +void unregister_cdrom(struct cdrom_device_info *cdi) +{ + cd_dbg(CD_OPEN, "entering unregister_cdrom\n"); + + mutex_lock(&cdrom_mutex); + list_del(&cdi->list); + mutex_unlock(&cdrom_mutex); + + if (cdi->exit) + cdi->exit(cdi); + + cdi->ops->n_minors--; + cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); +} + +int cdrom_get_media_event(struct cdrom_device_info *cdi, + struct media_event_desc *med) +{ + struct packet_command cgc; + unsigned char buffer[8]; + struct event_header *eh = (struct event_header *)buffer; + + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION; + cgc.cmd[1] = 1; /* IMMED */ + cgc.cmd[4] = 1 << 4; /* media event */ + cgc.cmd[8] = sizeof(buffer); + cgc.quiet = 1; + + if (cdi->ops->generic_packet(cdi, &cgc)) + return 1; + + if (be16_to_cpu(eh->data_len) < sizeof(*med)) + return 1; + + if (eh->nea || eh->notification_class != 0x4) + return 1; + + memcpy(med, &buffer[sizeof(*eh)], sizeof(*med)); + return 0; +} + static int cdrom_get_random_writable(struct cdrom_device_info *cdi, struct rwrt_feature_desc *rfd) { @@ -839,7 +854,7 @@ static int cdrom_ram_open_write(struct cdrom_device_info *cdi) else if (CDF_RWRT == be16_to_cpu(rfd.feature_code)) ret = !rfd.curr; - cdinfo(CD_OPEN, "can open for random write\n"); + cd_dbg(CD_OPEN, "can open for random write\n"); return ret; } @@ -928,12 +943,12 @@ static void cdrom_dvd_rw_close_write(struct cdrom_device_info *cdi) struct packet_command cgc; if (cdi->mmc3_profile != 0x1a) { - cdinfo(CD_CLOSE, "%s: No DVD+RW\n", cdi->name); + cd_dbg(CD_CLOSE, "%s: No DVD+RW\n", cdi->name); return; } if (!cdi->media_written) { - cdinfo(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name); + cd_dbg(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name); return; } @@ -969,82 +984,74 @@ static int cdrom_close_write(struct cdrom_device_info *cdi) #endif } -/* We use the open-option O_NONBLOCK to indicate that the - * purpose of opening is only for subsequent ioctl() calls; no device - * integrity checks are performed. - * - * We hope that all cd-player programs will adopt this convention. It - * is in their own interest: device control becomes a lot easier - * this way. - */ -int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t mode) +/* badly broken, I know. Is due for a fixup anytime. */ +static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype *tracks) { - int ret; - - cdinfo(CD_OPEN, "entering cdrom_open\n"); - - /* open is event synchronization point, check events first */ - check_disk_change(bdev); - - /* if this was a O_NONBLOCK open and we should honor the flags, - * do a quick open without drive/disc integrity checks. */ - cdi->use_count++; - if ((mode & FMODE_NDELAY) && (cdi->options & CDO_USE_FFLAGS)) { - ret = cdi->ops->open(cdi, 1); - } else { - ret = open_for_data(cdi); - if (ret) - goto err; - cdrom_mmc3_profile(cdi); - if (mode & FMODE_WRITE) { - ret = -EROFS; - if (cdrom_open_write(cdi)) - goto err_release; - if (!CDROM_CAN(CDC_RAM)) - goto err_release; - ret = 0; - cdi->media_written = 0; - } + struct cdrom_tochdr header; + struct cdrom_tocentry entry; + int ret, i; + tracks->data = 0; + tracks->audio = 0; + tracks->cdi = 0; + tracks->xa = 0; + tracks->error = 0; + cd_dbg(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); + /* Grab the TOC header so we can see how many tracks there are */ + ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header); + if (ret) { + if (ret == -ENOMEDIUM) + tracks->error = CDS_NO_DISC; + else + tracks->error = CDS_NO_INFO; + return; } - - if (ret) - goto err; - - cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", - cdi->name, cdi->use_count); - return 0; -err_release: - if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { - cdi->ops->lock_door(cdi, 0); - cdinfo(CD_OPEN, "door unlocked.\n"); + /* check what type of tracks are on this disc */ + entry.cdte_format = CDROM_MSF; + for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) { + entry.cdte_track = i; + if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) { + tracks->error = CDS_NO_INFO; + return; + } + if (entry.cdte_ctrl & CDROM_DATA_TRACK) { + if (entry.cdte_format == 0x10) + tracks->cdi++; + else if (entry.cdte_format == 0x20) + tracks->xa++; + else + tracks->data++; + } else { + tracks->audio++; + } + cd_dbg(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n", + i, entry.cdte_format, entry.cdte_ctrl); } - cdi->ops->release(cdi); -err: - cdi->use_count--; - return ret; + cd_dbg(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", + header.cdth_trk1, tracks->audio, tracks->data, + tracks->cdi, tracks->xa); } static -int open_for_data(struct cdrom_device_info * cdi) +int open_for_data(struct cdrom_device_info *cdi) { int ret; struct cdrom_device_ops *cdo = cdi->ops; tracktype tracks; - cdinfo(CD_OPEN, "entering open_for_data\n"); + cd_dbg(CD_OPEN, "entering open_for_data\n"); /* Check if the driver can report drive status. If it can, we can do clever things. If it can't, well, we at least tried! */ if (cdo->drive_status != NULL) { ret = cdo->drive_status(cdi, CDSL_CURRENT); - cdinfo(CD_OPEN, "drive_status=%d\n", ret); + cd_dbg(CD_OPEN, "drive_status=%d\n", ret); if (ret == CDS_TRAY_OPEN) { - cdinfo(CD_OPEN, "the tray is open...\n"); + cd_dbg(CD_OPEN, "the tray is open...\n"); /* can/may i close it? */ if (CDROM_CAN(CDC_CLOSE_TRAY) && cdi->options & CDO_AUTO_CLOSE) { - cdinfo(CD_OPEN, "trying to close the tray.\n"); + cd_dbg(CD_OPEN, "trying to close the tray\n"); ret=cdo->tray_move(cdi,0); if (ret) { - cdinfo(CD_OPEN, "bummer. tried to close the tray but failed.\n"); + cd_dbg(CD_OPEN, "bummer. tried to close the tray but failed.\n"); /* Ignore the error from the low level driver. We don't care why it couldn't close the tray. We only care @@ -1054,19 +1061,19 @@ int open_for_data(struct cdrom_device_info * cdi) goto clean_up_and_return; } } else { - cdinfo(CD_OPEN, "bummer. this drive can't close the tray.\n"); + cd_dbg(CD_OPEN, "bummer. this drive can't close the tray.\n"); ret=-ENOMEDIUM; goto clean_up_and_return; } /* Ok, the door should be closed now.. Check again */ ret = cdo->drive_status(cdi, CDSL_CURRENT); if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) { - cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n"); - cdinfo(CD_OPEN, "tray might not contain a medium.\n"); + cd_dbg(CD_OPEN, "bummer. the tray is still not closed.\n"); + cd_dbg(CD_OPEN, "tray might not contain a medium\n"); ret=-ENOMEDIUM; goto clean_up_and_return; } - cdinfo(CD_OPEN, "the tray is now closed.\n"); + cd_dbg(CD_OPEN, "the tray is now closed\n"); } /* the door should be closed now, check for the disc */ ret = cdo->drive_status(cdi, CDSL_CURRENT); @@ -1077,7 +1084,7 @@ int open_for_data(struct cdrom_device_info * cdi) } cdrom_count_tracks(cdi, &tracks); if (tracks.error == CDS_NO_DISC) { - cdinfo(CD_OPEN, "bummer. no disc.\n"); + cd_dbg(CD_OPEN, "bummer. no disc.\n"); ret=-ENOMEDIUM; goto clean_up_and_return; } @@ -1087,34 +1094,34 @@ int open_for_data(struct cdrom_device_info * cdi) if (cdi->options & CDO_CHECK_TYPE) { /* give people a warning shot, now that CDO_CHECK_TYPE is the default case! */ - cdinfo(CD_OPEN, "bummer. wrong media type.\n"); - cdinfo(CD_WARNING, "pid %d must open device O_NONBLOCK!\n", - (unsigned int)task_pid_nr(current)); + cd_dbg(CD_OPEN, "bummer. wrong media type.\n"); + cd_dbg(CD_WARNING, "pid %d must open device O_NONBLOCK!\n", + (unsigned int)task_pid_nr(current)); ret=-EMEDIUMTYPE; goto clean_up_and_return; } else { - cdinfo(CD_OPEN, "wrong media type, but CDO_CHECK_TYPE not set.\n"); + cd_dbg(CD_OPEN, "wrong media type, but CDO_CHECK_TYPE not set\n"); } } - cdinfo(CD_OPEN, "all seems well, opening the device.\n"); + cd_dbg(CD_OPEN, "all seems well, opening the devicen"); /* all seems well, we can open the device */ ret = cdo->open(cdi, 0); /* open for data */ - cdinfo(CD_OPEN, "opening the device gave me %d.\n", ret); + cd_dbg(CD_OPEN, "opening the device gave me %d\n", ret); /* After all this careful checking, we shouldn't have problems opening the device, but we don't want the device locked if this somehow fails... */ if (ret) { - cdinfo(CD_OPEN, "open device failed.\n"); + cd_dbg(CD_OPEN, "open device failed\n"); goto clean_up_and_return; } if (CDROM_CAN(CDC_LOCK) && (cdi->options & CDO_LOCK)) { cdo->lock_door(cdi, 1); - cdinfo(CD_OPEN, "door locked.\n"); + cd_dbg(CD_OPEN, "door locked\n"); } - cdinfo(CD_OPEN, "device opened successfully.\n"); + cd_dbg(CD_OPEN, "device opened successfully\n"); return ret; /* Something failed. Try to unlock the drive, because some drivers @@ -1123,11 +1130,67 @@ int open_for_data(struct cdrom_device_info * cdi) This ensures that the drive gets unlocked after a mount fails. This is a goto to avoid bloating the driver with redundant code. */ clean_up_and_return: - cdinfo(CD_OPEN, "open failed.\n"); + cd_dbg(CD_OPEN, "open failed\n"); if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { cdo->lock_door(cdi, 0); - cdinfo(CD_OPEN, "door unlocked.\n"); + cd_dbg(CD_OPEN, "door unlocked\n"); + } + return ret; +} + +/* We use the open-option O_NONBLOCK to indicate that the + * purpose of opening is only for subsequent ioctl() calls; no device + * integrity checks are performed. + * + * We hope that all cd-player programs will adopt this convention. It + * is in their own interest: device control becomes a lot easier + * this way. + */ +int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, + fmode_t mode) +{ + int ret; + + cd_dbg(CD_OPEN, "entering cdrom_open\n"); + + /* open is event synchronization point, check events first */ + check_disk_change(bdev); + + /* if this was a O_NONBLOCK open and we should honor the flags, + * do a quick open without drive/disc integrity checks. */ + cdi->use_count++; + if ((mode & FMODE_NDELAY) && (cdi->options & CDO_USE_FFLAGS)) { + ret = cdi->ops->open(cdi, 1); + } else { + ret = open_for_data(cdi); + if (ret) + goto err; + cdrom_mmc3_profile(cdi); + if (mode & FMODE_WRITE) { + ret = -EROFS; + if (cdrom_open_write(cdi)) + goto err_release; + if (!CDROM_CAN(CDC_RAM)) + goto err_release; + ret = 0; + cdi->media_written = 0; + } + } + + if (ret) + goto err; + + cd_dbg(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", + cdi->name, cdi->use_count); + return 0; +err_release: + if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { + cdi->ops->lock_door(cdi, 0); + cd_dbg(CD_OPEN, "door unlocked\n"); } + cdi->ops->release(cdi); +err: + cdi->use_count--; return ret; } @@ -1139,21 +1202,21 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi, { int ret; tracktype tracks; - cdinfo(CD_OPEN, "entering check_for_audio_disc\n"); + cd_dbg(CD_OPEN, "entering check_for_audio_disc\n"); if (!(cdi->options & CDO_CHECK_TYPE)) return 0; if (cdo->drive_status != NULL) { ret = cdo->drive_status(cdi, CDSL_CURRENT); - cdinfo(CD_OPEN, "drive_status=%d\n", ret); + cd_dbg(CD_OPEN, "drive_status=%d\n", ret); if (ret == CDS_TRAY_OPEN) { - cdinfo(CD_OPEN, "the tray is open...\n"); + cd_dbg(CD_OPEN, "the tray is open...\n"); /* can/may i close it? */ if (CDROM_CAN(CDC_CLOSE_TRAY) && cdi->options & CDO_AUTO_CLOSE) { - cdinfo(CD_OPEN, "trying to close the tray.\n"); + cd_dbg(CD_OPEN, "trying to close the tray\n"); ret=cdo->tray_move(cdi,0); if (ret) { - cdinfo(CD_OPEN, "bummer. tried to close tray but failed.\n"); + cd_dbg(CD_OPEN, "bummer. tried to close tray but failed.\n"); /* Ignore the error from the low level driver. We don't care why it couldn't close the tray. We only care @@ -1162,20 +1225,20 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi, return -ENOMEDIUM; } } else { - cdinfo(CD_OPEN, "bummer. this driver can't close the tray.\n"); + cd_dbg(CD_OPEN, "bummer. this driver can't close the tray.\n"); return -ENOMEDIUM; } /* Ok, the door should be closed now.. Check again */ ret = cdo->drive_status(cdi, CDSL_CURRENT); if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) { - cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n"); + cd_dbg(CD_OPEN, "bummer. the tray is still not closed.\n"); return -ENOMEDIUM; } if (ret!=CDS_DISC_OK) { - cdinfo(CD_OPEN, "bummer. disc isn't ready.\n"); + cd_dbg(CD_OPEN, "bummer. disc isn't ready.\n"); return -EIO; } - cdinfo(CD_OPEN, "the tray is now closed.\n"); + cd_dbg(CD_OPEN, "the tray is now closed\n"); } } cdrom_count_tracks(cdi, &tracks); @@ -1193,17 +1256,18 @@ void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode) struct cdrom_device_ops *cdo = cdi->ops; int opened_for_data; - cdinfo(CD_CLOSE, "entering cdrom_release\n"); + cd_dbg(CD_CLOSE, "entering cdrom_release\n"); if (cdi->use_count > 0) cdi->use_count--; if (cdi->use_count == 0) { - cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); + cd_dbg(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", + cdi->name); cdrom_dvd_rw_close_write(cdi); if ((cdo->capability & CDC_LOCK) && !cdi->keeplocked) { - cdinfo(CD_CLOSE, "Unlocking door!\n"); + cd_dbg(CD_CLOSE, "Unlocking door!\n"); cdo->lock_door(cdi, 0); } } @@ -1262,7 +1326,7 @@ static int cdrom_slot_status(struct cdrom_device_info *cdi, int slot) struct cdrom_changer_info *info; int ret; - cdinfo(CD_CHANGER, "entering cdrom_slot_status()\n"); + cd_dbg(CD_CHANGER, "entering cdrom_slot_status()\n"); if (cdi->sanyo_slot) return CDS_NO_INFO; @@ -1292,7 +1356,7 @@ int cdrom_number_of_slots(struct cdrom_device_info *cdi) int nslots = 1; struct cdrom_changer_info *info; - cdinfo(CD_CHANGER, "entering cdrom_number_of_slots()\n"); + cd_dbg(CD_CHANGER, "entering cdrom_number_of_slots()\n"); /* cdrom_read_mech_status requires a valid value for capacity: */ cdi->capacity = 0; @@ -1313,7 +1377,7 @@ static int cdrom_load_unload(struct cdrom_device_info *cdi, int slot) { struct packet_command cgc; - cdinfo(CD_CHANGER, "entering cdrom_load_unload()\n"); + cd_dbg(CD_CHANGER, "entering cdrom_load_unload()\n"); if (cdi->sanyo_slot && slot < 0) return 0; @@ -1342,7 +1406,7 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot) int curslot; int ret; - cdinfo(CD_CHANGER, "entering cdrom_select_disc()\n"); + cd_dbg(CD_CHANGER, "entering cdrom_select_disc()\n"); if (!CDROM_CAN(CDC_SELECT_DISC)) return -EDRIVE_CANT_DO_THIS; @@ -1476,51 +1540,6 @@ int cdrom_media_changed(struct cdrom_device_info *cdi) return media_changed(cdi, 0); } -/* badly broken, I know. Is due for a fixup anytime. */ -static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks) -{ - struct cdrom_tochdr header; - struct cdrom_tocentry entry; - int ret, i; - tracks->data=0; - tracks->audio=0; - tracks->cdi=0; - tracks->xa=0; - tracks->error=0; - cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); - /* Grab the TOC header so we can see how many tracks there are */ - if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header))) { - if (ret == -ENOMEDIUM) - tracks->error = CDS_NO_DISC; - else - tracks->error = CDS_NO_INFO; - return; - } - /* check what type of tracks are on this disc */ - entry.cdte_format = CDROM_MSF; - for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) { - entry.cdte_track = i; - if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) { - tracks->error=CDS_NO_INFO; - return; - } - if (entry.cdte_ctrl & CDROM_DATA_TRACK) { - if (entry.cdte_format == 0x10) - tracks->cdi++; - else if (entry.cdte_format == 0x20) - tracks->xa++; - else - tracks->data++; - } else - tracks->audio++; - cdinfo(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n", - i, entry.cdte_format, entry.cdte_ctrl); - } - cdinfo(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", - header.cdth_trk1, tracks->audio, tracks->data, - tracks->cdi, tracks->xa); -} - /* Requests to the low-level drivers will /always/ be done in the following format convention: @@ -1632,7 +1651,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) switch (ai->type) { /* LU data send */ case DVD_LU_SEND_AGID: - cdinfo(CD_DVD, "entering DVD_LU_SEND_AGID\n"); + cd_dbg(CD_DVD, "entering DVD_LU_SEND_AGID\n"); cgc.quiet = 1; setup_report_key(&cgc, ai->lsa.agid, 0); @@ -1644,7 +1663,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) break; case DVD_LU_SEND_KEY1: - cdinfo(CD_DVD, "entering DVD_LU_SEND_KEY1\n"); + cd_dbg(CD_DVD, "entering DVD_LU_SEND_KEY1\n"); setup_report_key(&cgc, ai->lsk.agid, 2); if ((ret = cdo->generic_packet(cdi, &cgc))) @@ -1655,7 +1674,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) break; case DVD_LU_SEND_CHALLENGE: - cdinfo(CD_DVD, "entering DVD_LU_SEND_CHALLENGE\n"); + cd_dbg(CD_DVD, "entering DVD_LU_SEND_CHALLENGE\n"); setup_report_key(&cgc, ai->lsc.agid, 1); if ((ret = cdo->generic_packet(cdi, &cgc))) @@ -1667,7 +1686,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) /* Post-auth key */ case DVD_LU_SEND_TITLE_KEY: - cdinfo(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n"); + cd_dbg(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n"); cgc.quiet = 1; setup_report_key(&cgc, ai->lstk.agid, 4); cgc.cmd[5] = ai->lstk.lba; @@ -1686,7 +1705,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) break; case DVD_LU_SEND_ASF: - cdinfo(CD_DVD, "entering DVD_LU_SEND_ASF\n"); + cd_dbg(CD_DVD, "entering DVD_LU_SEND_ASF\n"); setup_report_key(&cgc, ai->lsasf.agid, 5); if ((ret = cdo->generic_packet(cdi, &cgc))) @@ -1697,7 +1716,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) /* LU data receive (LU changes state) */ case DVD_HOST_SEND_CHALLENGE: - cdinfo(CD_DVD, "entering DVD_HOST_SEND_CHALLENGE\n"); + cd_dbg(CD_DVD, "entering DVD_HOST_SEND_CHALLENGE\n"); setup_send_key(&cgc, ai->hsc.agid, 1); buf[1] = 0xe; copy_chal(&buf[4], ai->hsc.chal); @@ -1709,7 +1728,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) break; case DVD_HOST_SEND_KEY2: - cdinfo(CD_DVD, "entering DVD_HOST_SEND_KEY2\n"); + cd_dbg(CD_DVD, "entering DVD_HOST_SEND_KEY2\n"); setup_send_key(&cgc, ai->hsk.agid, 3); buf[1] = 0xa; copy_key(&buf[4], ai->hsk.key); @@ -1724,7 +1743,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) /* Misc */ case DVD_INVALIDATE_AGID: cgc.quiet = 1; - cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); + cd_dbg(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); setup_report_key(&cgc, ai->lsa.agid, 0x3f); if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; @@ -1732,7 +1751,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) /* Get region settings */ case DVD_LU_SEND_RPC_STATE: - cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); + cd_dbg(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); setup_report_key(&cgc, 0, 8); memset(&rpc_state, 0, sizeof(rpc_state_t)); cgc.buffer = (char *) &rpc_state; @@ -1749,7 +1768,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) /* Set region settings */ case DVD_HOST_SEND_RPC_STATE: - cdinfo(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n"); + cd_dbg(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n"); setup_send_key(&cgc, 0, 6); buf[1] = 6; buf[4] = ai->hrpcs.pdrc; @@ -1759,7 +1778,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) break; default: - cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type); + cd_dbg(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type); return -ENOTTY; } @@ -1891,7 +1910,8 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s, s->bca.len = buf[0] << 8 | buf[1]; if (s->bca.len < 12 || s->bca.len > 188) { - cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len); + cd_dbg(CD_WARNING, "Received invalid BCA length (%d)\n", + s->bca.len); ret = -EIO; goto out; } @@ -1927,14 +1947,13 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s, s->manufact.len = buf[0] << 8 | buf[1]; if (s->manufact.len < 0) { - cdinfo(CD_WARNING, "Received invalid manufacture info length" - " (%d)\n", s->manufact.len); + cd_dbg(CD_WARNING, "Received invalid manufacture info length (%d)\n", + s->manufact.len); ret = -EIO; } else { if (s->manufact.len > 2048) { - cdinfo(CD_WARNING, "Received invalid manufacture info " - "length (%d): truncating to 2048\n", - s->manufact.len); + cd_dbg(CD_WARNING, "Received invalid manufacture info length (%d): truncating to 2048\n", + s->manufact.len); s->manufact.len = 2048; } memcpy(s->manufact.value, &buf[4], s->manufact.len); @@ -1965,8 +1984,8 @@ static int dvd_read_struct(struct cdrom_device_info *cdi, dvd_struct *s, return dvd_read_manufact(cdi, s, cgc); default: - cdinfo(CD_WARNING, ": Invalid DVD structure read requested (%d)\n", - s->type); + cd_dbg(CD_WARNING, ": Invalid DVD structure read requested (%d)\n", + s->type); return -EINVAL; } } @@ -2255,7 +2274,7 @@ static int cdrom_ioctl_multisession(struct cdrom_device_info *cdi, u8 requested_format; int ret; - cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROMMULTISESSION\n"); if (!(cdi->ops->capability & CDC_MULTI_SESSION)) return -ENOSYS; @@ -2277,13 +2296,13 @@ static int cdrom_ioctl_multisession(struct cdrom_device_info *cdi, if (copy_to_user(argp, &ms_info, sizeof(ms_info))) return -EFAULT; - cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n"); + cd_dbg(CD_DO_IOCTL, "CDROMMULTISESSION successful\n"); return 0; } static int cdrom_ioctl_eject(struct cdrom_device_info *cdi) { - cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROMEJECT\n"); if (!CDROM_CAN(CDC_OPEN_TRAY)) return -ENOSYS; @@ -2300,7 +2319,7 @@ static int cdrom_ioctl_eject(struct cdrom_device_info *cdi) static int cdrom_ioctl_closetray(struct cdrom_device_info *cdi) { - cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); if (!CDROM_CAN(CDC_CLOSE_TRAY)) return -ENOSYS; @@ -2310,7 +2329,7 @@ static int cdrom_ioctl_closetray(struct cdrom_device_info *cdi) static int cdrom_ioctl_eject_sw(struct cdrom_device_info *cdi, unsigned long arg) { - cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); if (!CDROM_CAN(CDC_OPEN_TRAY)) return -ENOSYS; @@ -2329,7 +2348,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi, struct cdrom_changer_info *info; int ret; - cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); if (!CDROM_CAN(CDC_MEDIA_CHANGED)) return -ENOSYS; @@ -2355,7 +2374,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi, static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi, unsigned long arg) { - cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); /* * Options need to be in sync with capability. @@ -2383,7 +2402,7 @@ static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi, static int cdrom_ioctl_clear_options(struct cdrom_device_info *cdi, unsigned long arg) { - cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n"); cdi->options &= ~(int) arg; return cdi->options; @@ -2392,7 +2411,7 @@ static int cdrom_ioctl_clear_options(struct cdrom_device_info *cdi, static int cdrom_ioctl_select_speed(struct cdrom_device_info *cdi, unsigned long arg) { - cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n"); if (!CDROM_CAN(CDC_SELECT_SPEED)) return -ENOSYS; @@ -2402,7 +2421,7 @@ static int cdrom_ioctl_select_speed(struct cdrom_device_info *cdi, static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi, unsigned long arg) { - cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n"); if (!CDROM_CAN(CDC_SELECT_DISC)) return -ENOSYS; @@ -2420,14 +2439,14 @@ static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi, if (cdi->ops->select_disc) return cdi->ops->select_disc(cdi, arg); - cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n"); + cd_dbg(CD_CHANGER, "Using generic cdrom_select_disc()\n"); return cdrom_select_disc(cdi, arg); } static int cdrom_ioctl_reset(struct cdrom_device_info *cdi, struct block_device *bdev) { - cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_RESET\n"); if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -2440,7 +2459,7 @@ static int cdrom_ioctl_reset(struct cdrom_device_info *cdi, static int cdrom_ioctl_lock_door(struct cdrom_device_info *cdi, unsigned long arg) { - cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl"); + cd_dbg(CD_DO_IOCTL, "%socking door\n", arg ? "L" : "Unl"); if (!CDROM_CAN(CDC_LOCK)) return -EDRIVE_CANT_DO_THIS; @@ -2459,7 +2478,7 @@ static int cdrom_ioctl_lock_door(struct cdrom_device_info *cdi, static int cdrom_ioctl_debug(struct cdrom_device_info *cdi, unsigned long arg) { - cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis"); + cd_dbg(CD_DO_IOCTL, "%sabling debug\n", arg ? "En" : "Dis"); if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -2469,7 +2488,7 @@ static int cdrom_ioctl_debug(struct cdrom_device_info *cdi, static int cdrom_ioctl_get_capability(struct cdrom_device_info *cdi) { - cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n"); return (cdi->ops->capability & ~cdi->mask); } @@ -2485,7 +2504,7 @@ static int cdrom_ioctl_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn mcn; int ret; - cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); if (!(cdi->ops->capability & CDC_MCN)) return -ENOSYS; @@ -2495,14 +2514,14 @@ static int cdrom_ioctl_get_mcn(struct cdrom_device_info *cdi, if (copy_to_user(argp, &mcn, sizeof(mcn))) return -EFAULT; - cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n"); + cd_dbg(CD_DO_IOCTL, "CDROM_GET_MCN successful\n"); return 0; } static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi, unsigned long arg) { - cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n"); if (!(cdi->ops->capability & CDC_DRIVE_STATUS)) return -ENOSYS; @@ -2535,7 +2554,7 @@ static int cdrom_ioctl_disc_status(struct cdrom_device_info *cdi) { tracktype tracks; - cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n"); cdrom_count_tracks(cdi, &tracks); if (tracks.error) @@ -2557,13 +2576,13 @@ static int cdrom_ioctl_disc_status(struct cdrom_device_info *cdi) return CDS_DATA_1; /* Policy mode off */ - cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n"); + cd_dbg(CD_WARNING, "This disc doesn't have any tracks I recognize!\n"); return CDS_NO_INFO; } static int cdrom_ioctl_changer_nslots(struct cdrom_device_info *cdi) { - cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); return cdi->capacity; } @@ -2574,7 +2593,7 @@ static int cdrom_ioctl_get_subchnl(struct cdrom_device_info *cdi, u8 requested, back; int ret; - /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ + /* cd_dbg(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ if (copy_from_user(&q, argp, sizeof(q))) return -EFAULT; @@ -2594,7 +2613,7 @@ static int cdrom_ioctl_get_subchnl(struct cdrom_device_info *cdi, if (copy_to_user(argp, &q, sizeof(q))) return -EFAULT; - /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ + /* cd_dbg(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ return 0; } @@ -2604,7 +2623,7 @@ static int cdrom_ioctl_read_tochdr(struct cdrom_device_info *cdi, struct cdrom_tochdr header; int ret; - /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ + /* cd_dbg(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ if (copy_from_user(&header, argp, sizeof(header))) return -EFAULT; @@ -2615,7 +2634,7 @@ static int cdrom_ioctl_read_tochdr(struct cdrom_device_info *cdi, if (copy_to_user(argp, &header, sizeof(header))) return -EFAULT; - /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ + /* cd_dbg(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ return 0; } @@ -2626,7 +2645,7 @@ static int cdrom_ioctl_read_tocentry(struct cdrom_device_info *cdi, u8 requested_format; int ret; - /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ + /* cd_dbg(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ if (copy_from_user(&entry, argp, sizeof(entry))) return -EFAULT; @@ -2643,7 +2662,7 @@ static int cdrom_ioctl_read_tocentry(struct cdrom_device_info *cdi, if (copy_to_user(argp, &entry, sizeof(entry))) return -EFAULT; - /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ + /* cd_dbg(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ return 0; } @@ -2652,7 +2671,7 @@ static int cdrom_ioctl_play_msf(struct cdrom_device_info *cdi, { struct cdrom_msf msf; - cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); if (!CDROM_CAN(CDC_PLAY_AUDIO)) return -ENOSYS; @@ -2667,7 +2686,7 @@ static int cdrom_ioctl_play_trkind(struct cdrom_device_info *cdi, struct cdrom_ti ti; int ret; - cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); if (!CDROM_CAN(CDC_PLAY_AUDIO)) return -ENOSYS; @@ -2684,7 +2703,7 @@ static int cdrom_ioctl_volctrl(struct cdrom_device_info *cdi, { struct cdrom_volctrl volume; - cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); if (!CDROM_CAN(CDC_PLAY_AUDIO)) return -ENOSYS; @@ -2699,7 +2718,7 @@ static int cdrom_ioctl_volread(struct cdrom_device_info *cdi, struct cdrom_volctrl volume; int ret; - cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); if (!CDROM_CAN(CDC_PLAY_AUDIO)) return -ENOSYS; @@ -2718,7 +2737,7 @@ static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi, { int ret; - cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); + cd_dbg(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); if (!CDROM_CAN(CDC_PLAY_AUDIO)) return -ENOSYS; @@ -2728,103 +2747,6 @@ static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi, return cdi->ops->audio_ioctl(cdi, cmd, NULL); } -/* - * Just about every imaginable ioctl is supported in the Uniform layer - * these days. - * ATAPI / SCSI specific code now mainly resides in mmc_ioctl(). - */ -int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, - fmode_t mode, unsigned int cmd, unsigned long arg) -{ - void __user *argp = (void __user *)arg; - int ret; - - /* - * Try the generic SCSI command ioctl's first. - */ - ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); - if (ret != -ENOTTY) - return ret; - - switch (cmd) { - case CDROMMULTISESSION: - return cdrom_ioctl_multisession(cdi, argp); - case CDROMEJECT: - return cdrom_ioctl_eject(cdi); - case CDROMCLOSETRAY: - return cdrom_ioctl_closetray(cdi); - case CDROMEJECT_SW: - return cdrom_ioctl_eject_sw(cdi, arg); - case CDROM_MEDIA_CHANGED: - return cdrom_ioctl_media_changed(cdi, arg); - case CDROM_SET_OPTIONS: - return cdrom_ioctl_set_options(cdi, arg); - case CDROM_CLEAR_OPTIONS: - return cdrom_ioctl_clear_options(cdi, arg); - case CDROM_SELECT_SPEED: - return cdrom_ioctl_select_speed(cdi, arg); - case CDROM_SELECT_DISC: - return cdrom_ioctl_select_disc(cdi, arg); - case CDROMRESET: - return cdrom_ioctl_reset(cdi, bdev); - case CDROM_LOCKDOOR: - return cdrom_ioctl_lock_door(cdi, arg); - case CDROM_DEBUG: - return cdrom_ioctl_debug(cdi, arg); - case CDROM_GET_CAPABILITY: - return cdrom_ioctl_get_capability(cdi); - case CDROM_GET_MCN: - return cdrom_ioctl_get_mcn(cdi, argp); - case CDROM_DRIVE_STATUS: - return cdrom_ioctl_drive_status(cdi, arg); - case CDROM_DISC_STATUS: - return cdrom_ioctl_disc_status(cdi); - case CDROM_CHANGER_NSLOTS: - return cdrom_ioctl_changer_nslots(cdi); - } - - /* - * Use the ioctls that are implemented through the generic_packet() - * interface. this may look at bit funny, but if -ENOTTY is - * returned that particular ioctl is not implemented and we - * let it go through the device specific ones. - */ - if (CDROM_CAN(CDC_GENERIC_PACKET)) { - ret = mmc_ioctl(cdi, cmd, arg); - if (ret != -ENOTTY) - return ret; - } - - /* - * Note: most of the cdinfo() calls are commented out here, - * because they fill up the sys log when CD players poll - * the drive. - */ - switch (cmd) { - case CDROMSUBCHNL: - return cdrom_ioctl_get_subchnl(cdi, argp); - case CDROMREADTOCHDR: - return cdrom_ioctl_read_tochdr(cdi, argp); - case CDROMREADTOCENTRY: - return cdrom_ioctl_read_tocentry(cdi, argp); - case CDROMPLAYMSF: - return cdrom_ioctl_play_msf(cdi, argp); - case CDROMPLAYTRKIND: - return cdrom_ioctl_play_trkind(cdi, argp); - case CDROMVOLCTRL: - return cdrom_ioctl_volctrl(cdi, argp); - case CDROMVOLREAD: - return cdrom_ioctl_volread(cdi, argp); - case CDROMSTART: - case CDROMSTOP: - case CDROMPAUSE: - case CDROMRESUME: - return cdrom_ioctl_audioctl(cdi, cmd); - } - - return -ENOSYS; -} - /* * Required when we need to use READ_10 to issue other than 2048 block * reads @@ -2854,71 +2776,222 @@ static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size) return cdo->generic_packet(cdi, &cgc); } -static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi, - void __user *arg, - struct packet_command *cgc, - int cmd) +static int cdrom_get_track_info(struct cdrom_device_info *cdi, + __u16 track, __u8 type, track_information *ti) { - struct request_sense sense; - struct cdrom_msf msf; - int blocksize = 0, format = 0, lba; - int ret; + struct cdrom_device_ops *cdo = cdi->ops; + struct packet_command cgc; + int ret, buflen; - switch (cmd) { - case CDROMREADRAW: - blocksize = CD_FRAMESIZE_RAW; - break; - case CDROMREADMODE1: - blocksize = CD_FRAMESIZE; - format = 2; - break; - case CDROMREADMODE2: - blocksize = CD_FRAMESIZE_RAW0; - break; - } - IOCTL_IN(arg, struct cdrom_msf, msf); - lba = msf_to_lba(msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0); - /* FIXME: we need upper bound checking, too!! */ - if (lba < 0) - return -EINVAL; + init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); + cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; + cgc.cmd[1] = type & 3; + cgc.cmd[4] = (track & 0xff00) >> 8; + cgc.cmd[5] = track & 0xff; + cgc.cmd[8] = 8; + cgc.quiet = 1; - cgc->buffer = kzalloc(blocksize, GFP_KERNEL); - if (cgc->buffer == NULL) - return -ENOMEM; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) + return ret; - memset(&sense, 0, sizeof(sense)); - cgc->sense = &sense; - cgc->data_direction = CGC_DATA_READ; - ret = cdrom_read_block(cdi, cgc, lba, 1, format, blocksize); - if (ret && sense.sense_key == 0x05 && - sense.asc == 0x20 && - sense.ascq == 0x00) { - /* - * SCSI-II devices are not required to support - * READ_CD, so let's try switching block size - */ - /* FIXME: switch back again... */ - ret = cdrom_switch_blocksize(cdi, blocksize); - if (ret) - goto out; - cgc->sense = NULL; - ret = cdrom_read_cd(cdi, cgc, lba, blocksize, 1); - ret |= cdrom_switch_blocksize(cdi, blocksize); - } - if (!ret && copy_to_user(arg, cgc->buffer, blocksize)) - ret = -EFAULT; + buflen = be16_to_cpu(ti->track_information_length) + + sizeof(ti->track_information_length); + + if (buflen > sizeof(track_information)) + buflen = sizeof(track_information); + + cgc.cmd[8] = cgc.buflen = buflen; + ret = cdo->generic_packet(cdi, &cgc); + if (ret) + return ret; + + /* return actual fill size */ + return buflen; +} + +/* return the last written block on the CD-R media. this is for the udf + file system. */ +int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written) +{ + struct cdrom_tocentry toc; + disc_information di; + track_information ti; + __u32 last_track; + int ret = -1, ti_size; + + if (!CDROM_CAN(CDC_GENERIC_PACKET)) + goto use_toc; + + ret = cdrom_get_disc_info(cdi, &di); + if (ret < (int)(offsetof(typeof(di), last_track_lsb) + + sizeof(di.last_track_lsb))) + goto use_toc; + + /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ + last_track = (di.last_track_msb << 8) | di.last_track_lsb; + ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); + if (ti_size < (int)offsetof(typeof(ti), track_start)) + goto use_toc; + + /* if this track is blank, try the previous. */ + if (ti.blank) { + if (last_track == 1) + goto use_toc; + last_track--; + ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); + } + + if (ti_size < (int)(offsetof(typeof(ti), track_size) + + sizeof(ti.track_size))) + goto use_toc; + + /* if last recorded field is valid, return it. */ + if (ti.lra_v && ti_size >= (int)(offsetof(typeof(ti), last_rec_address) + + sizeof(ti.last_rec_address))) { + *last_written = be32_to_cpu(ti.last_rec_address); + } else { + /* make it up instead */ + *last_written = be32_to_cpu(ti.track_start) + + be32_to_cpu(ti.track_size); + if (ti.free_blocks) + *last_written -= (be32_to_cpu(ti.free_blocks) + 7); + } + return 0; + + /* this is where we end up if the drive either can't do a + GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if + it doesn't give enough information or fails. then we return + the toc contents. */ +use_toc: + toc.cdte_format = CDROM_MSF; + toc.cdte_track = CDROM_LEADOUT; + if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc))) + return ret; + sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA); + *last_written = toc.cdte_addr.lba; + return 0; +} + +/* return the next writable block. also for udf file system. */ +static int cdrom_get_next_writable(struct cdrom_device_info *cdi, + long *next_writable) +{ + disc_information di; + track_information ti; + __u16 last_track; + int ret, ti_size; + + if (!CDROM_CAN(CDC_GENERIC_PACKET)) + goto use_last_written; + + ret = cdrom_get_disc_info(cdi, &di); + if (ret < 0 || ret < offsetof(typeof(di), last_track_lsb) + + sizeof(di.last_track_lsb)) + goto use_last_written; + + /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ + last_track = (di.last_track_msb << 8) | di.last_track_lsb; + ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); + if (ti_size < 0 || ti_size < offsetof(typeof(ti), track_start)) + goto use_last_written; + + /* if this track is blank, try the previous. */ + if (ti.blank) { + if (last_track == 1) + goto use_last_written; + last_track--; + ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); + if (ti_size < 0) + goto use_last_written; + } + + /* if next recordable address field is valid, use it. */ + if (ti.nwa_v && ti_size >= offsetof(typeof(ti), next_writable) + + sizeof(ti.next_writable)) { + *next_writable = be32_to_cpu(ti.next_writable); + return 0; + } + +use_last_written: + ret = cdrom_get_last_written(cdi, next_writable); + if (ret) { + *next_writable = 0; + return ret; + } else { + *next_writable += 7; + return 0; + } +} + +static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi, + void __user *arg, + struct packet_command *cgc, + int cmd) +{ + struct request_sense sense; + struct cdrom_msf msf; + int blocksize = 0, format = 0, lba; + int ret; + + switch (cmd) { + case CDROMREADRAW: + blocksize = CD_FRAMESIZE_RAW; + break; + case CDROMREADMODE1: + blocksize = CD_FRAMESIZE; + format = 2; + break; + case CDROMREADMODE2: + blocksize = CD_FRAMESIZE_RAW0; + break; + } + if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf))) + return -EFAULT; + lba = msf_to_lba(msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0); + /* FIXME: we need upper bound checking, too!! */ + if (lba < 0) + return -EINVAL; + + cgc->buffer = kzalloc(blocksize, GFP_KERNEL); + if (cgc->buffer == NULL) + return -ENOMEM; + + memset(&sense, 0, sizeof(sense)); + cgc->sense = &sense; + cgc->data_direction = CGC_DATA_READ; + ret = cdrom_read_block(cdi, cgc, lba, 1, format, blocksize); + if (ret && sense.sense_key == 0x05 && + sense.asc == 0x20 && + sense.ascq == 0x00) { + /* + * SCSI-II devices are not required to support + * READ_CD, so let's try switching block size + */ + /* FIXME: switch back again... */ + ret = cdrom_switch_blocksize(cdi, blocksize); + if (ret) + goto out; + cgc->sense = NULL; + ret = cdrom_read_cd(cdi, cgc, lba, blocksize, 1); + ret |= cdrom_switch_blocksize(cdi, blocksize); + } + if (!ret && copy_to_user(arg, cgc->buffer, blocksize)) + ret = -EFAULT; out: kfree(cgc->buffer); return ret; } static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi, - void __user *arg) + void __user *arg) { struct cdrom_read_audio ra; int lba; - IOCTL_IN(arg, struct cdrom_read_audio, ra); + if (copy_from_user(&ra, (struct cdrom_read_audio __user *)arg, + sizeof(ra))) + return -EFAULT; if (ra.addr_format == CDROM_MSF) lba = msf_to_lba(ra.addr.msf.minute, @@ -2937,12 +3010,13 @@ static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi, } static noinline int mmc_ioctl_cdrom_subchannel(struct cdrom_device_info *cdi, - void __user *arg) + void __user *arg) { int ret; struct cdrom_subchnl q; u_char requested, back; - IOCTL_IN(arg, struct cdrom_subchnl, q); + if (copy_from_user(&q, (struct cdrom_subchnl __user *)arg, sizeof(q))) + return -EFAULT; requested = q.cdsc_format; if (!((requested == CDROM_MSF) || (requested == CDROM_LBA))) @@ -2954,19 +3028,21 @@ static noinline int mmc_ioctl_cdrom_subchannel(struct cdrom_device_info *cdi, back = q.cdsc_format; /* local copy */ sanitize_format(&q.cdsc_absaddr, &back, requested); sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); - IOCTL_OUT(arg, struct cdrom_subchnl, q); - /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ + if (copy_to_user((struct cdrom_subchnl __user *)arg, &q, sizeof(q))) + return -EFAULT; + /* cd_dbg(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ return 0; } static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi, - void __user *arg, - struct packet_command *cgc) + void __user *arg, + struct packet_command *cgc) { struct cdrom_device_ops *cdo = cdi->ops; struct cdrom_msf msf; - cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); - IOCTL_IN(arg, struct cdrom_msf, msf); + cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); + if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf))) + return -EFAULT; cgc->cmd[0] = GPCMD_PLAY_AUDIO_MSF; cgc->cmd[3] = msf.cdmsf_min0; cgc->cmd[4] = msf.cdmsf_sec0; @@ -2979,13 +3055,14 @@ static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi, } static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi, - void __user *arg, - struct packet_command *cgc) + void __user *arg, + struct packet_command *cgc) { struct cdrom_device_ops *cdo = cdi->ops; struct cdrom_blk blk; - cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); - IOCTL_IN(arg, struct cdrom_blk, blk); + cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); + if (copy_from_user(&blk, (struct cdrom_blk __user *)arg, sizeof(blk))) + return -EFAULT; cgc->cmd[0] = GPCMD_PLAY_AUDIO_10; cgc->cmd[2] = (blk.from >> 24) & 0xff; cgc->cmd[3] = (blk.from >> 16) & 0xff; @@ -2998,9 +3075,9 @@ static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi, } static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi, - void __user *arg, - struct packet_command *cgc, - unsigned int cmd) + void __user *arg, + struct packet_command *cgc, + unsigned int cmd) { struct cdrom_volctrl volctrl; unsigned char buffer[32]; @@ -3008,9 +3085,11 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi, unsigned short offset; int ret; - cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROMVOLUME\n"); - IOCTL_IN(arg, struct cdrom_volctrl, volctrl); + if (copy_from_user(&volctrl, (struct cdrom_volctrl __user *)arg, + sizeof(volctrl))) + return -EFAULT; cgc->buffer = buffer; cgc->buflen = 24; @@ -3030,14 +3109,14 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi, if (offset + 16 > cgc->buflen) { cgc->buflen = offset + 16; ret = cdrom_mode_sense(cdi, cgc, - GPMODE_AUDIO_CTL_PAGE, 0); + GPMODE_AUDIO_CTL_PAGE, 0); if (ret) return ret; } /* sanity check */ if ((buffer[offset] & 0x3f) != GPMODE_AUDIO_CTL_PAGE || - buffer[offset + 1] < 14) + buffer[offset + 1] < 14) return -EINVAL; /* now we have the current volume settings. if it was only @@ -3047,7 +3126,9 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi, volctrl.channel1 = buffer[offset+11]; volctrl.channel2 = buffer[offset+13]; volctrl.channel3 = buffer[offset+15]; - IOCTL_OUT(arg, struct cdrom_volctrl, volctrl); + if (copy_to_user((struct cdrom_volctrl __user *)arg, &volctrl, + sizeof(volctrl))) + return -EFAULT; return 0; } @@ -3069,11 +3150,11 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi, } static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi, - struct packet_command *cgc, - int cmd) + struct packet_command *cgc, + int cmd) { struct cdrom_device_ops *cdo = cdi->ops; - cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); cgc->cmd[0] = GPCMD_START_STOP_UNIT; cgc->cmd[1] = 1; cgc->cmd[4] = (cmd == CDROMSTART) ? 1 : 0; @@ -3082,11 +3163,11 @@ static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi, } static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi, - struct packet_command *cgc, - int cmd) + struct packet_command *cgc, + int cmd) { struct cdrom_device_ops *cdo = cdi->ops; - cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); cgc->cmd[0] = GPCMD_PAUSE_RESUME; cgc->cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; cgc->data_direction = CGC_DATA_NONE; @@ -3094,8 +3175,8 @@ static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi, } static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi, - void __user *arg, - struct packet_command *cgc) + void __user *arg, + struct packet_command *cgc) { int ret; dvd_struct *s; @@ -3108,7 +3189,7 @@ static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi, if (!s) return -ENOMEM; - cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n"); + cd_dbg(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n"); if (copy_from_user(s, arg, size)) { kfree(s); return -EFAULT; @@ -3126,44 +3207,48 @@ static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi, } static noinline int mmc_ioctl_dvd_auth(struct cdrom_device_info *cdi, - void __user *arg) + void __user *arg) { int ret; dvd_authinfo ai; if (!CDROM_CAN(CDC_DVD)) return -ENOSYS; - cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n"); - IOCTL_IN(arg, dvd_authinfo, ai); + cd_dbg(CD_DO_IOCTL, "entering DVD_AUTH\n"); + if (copy_from_user(&ai, (dvd_authinfo __user *)arg, sizeof(ai))) + return -EFAULT; ret = dvd_do_auth(cdi, &ai); if (ret) return ret; - IOCTL_OUT(arg, dvd_authinfo, ai); + if (copy_to_user((dvd_authinfo __user *)arg, &ai, sizeof(ai))) + return -EFAULT; return 0; } static noinline int mmc_ioctl_cdrom_next_writable(struct cdrom_device_info *cdi, - void __user *arg) + void __user *arg) { int ret; long next = 0; - cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); ret = cdrom_get_next_writable(cdi, &next); if (ret) return ret; - IOCTL_OUT(arg, long, next); + if (copy_to_user((long __user *)arg, &next, sizeof(next))) + return -EFAULT; return 0; } static noinline int mmc_ioctl_cdrom_last_written(struct cdrom_device_info *cdi, - void __user *arg) + void __user *arg) { int ret; long last = 0; - cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); + cd_dbg(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); ret = cdrom_get_last_written(cdi, &last); if (ret) return ret; - IOCTL_OUT(arg, long, last); + if (copy_to_user((long __user *)arg, &last, sizeof(last))) + return -EFAULT; return 0; } @@ -3212,181 +3297,101 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, return -ENOTTY; } -static int cdrom_get_track_info(struct cdrom_device_info *cdi, __u16 track, __u8 type, - track_information *ti) -{ - struct cdrom_device_ops *cdo = cdi->ops; - struct packet_command cgc; - int ret, buflen; - - init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); - cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; - cgc.cmd[1] = type & 3; - cgc.cmd[4] = (track & 0xff00) >> 8; - cgc.cmd[5] = track & 0xff; - cgc.cmd[8] = 8; - cgc.quiet = 1; - - if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; - - buflen = be16_to_cpu(ti->track_information_length) + - sizeof(ti->track_information_length); - - if (buflen > sizeof(track_information)) - buflen = sizeof(track_information); - - cgc.cmd[8] = cgc.buflen = buflen; - if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; - - /* return actual fill size */ - return buflen; -} - -/* requires CD R/RW */ -static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di) +/* + * Just about every imaginable ioctl is supported in the Uniform layer + * these days. + * ATAPI / SCSI specific code now mainly resides in mmc_ioctl(). + */ +int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, + fmode_t mode, unsigned int cmd, unsigned long arg) { - struct cdrom_device_ops *cdo = cdi->ops; - struct packet_command cgc; - int ret, buflen; - - /* set up command and get the disc info */ - init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); - cgc.cmd[0] = GPCMD_READ_DISC_INFO; - cgc.cmd[8] = cgc.buflen = 2; - cgc.quiet = 1; - - if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + void __user *argp = (void __user *)arg; + int ret; - /* not all drives have the same disc_info length, so requeue - * packet with the length the drive tells us it can supply + /* + * Try the generic SCSI command ioctl's first. */ - buflen = be16_to_cpu(di->disc_information_length) + - sizeof(di->disc_information_length); - - if (buflen > sizeof(disc_information)) - buflen = sizeof(disc_information); - - cgc.cmd[8] = cgc.buflen = buflen; - if ((ret = cdo->generic_packet(cdi, &cgc))) + ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); + if (ret != -ENOTTY) return ret; - /* return actual fill size */ - return buflen; -} - -/* return the last written block on the CD-R media. this is for the udf - file system. */ -int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written) -{ - struct cdrom_tocentry toc; - disc_information di; - track_information ti; - __u32 last_track; - int ret = -1, ti_size; - - if (!CDROM_CAN(CDC_GENERIC_PACKET)) - goto use_toc; - - ret = cdrom_get_disc_info(cdi, &di); - if (ret < (int)(offsetof(typeof(di), last_track_lsb) - + sizeof(di.last_track_lsb))) - goto use_toc; - - /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ - last_track = (di.last_track_msb << 8) | di.last_track_lsb; - ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); - if (ti_size < (int)offsetof(typeof(ti), track_start)) - goto use_toc; - - /* if this track is blank, try the previous. */ - if (ti.blank) { - if (last_track==1) - goto use_toc; - last_track--; - ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); - } - - if (ti_size < (int)(offsetof(typeof(ti), track_size) - + sizeof(ti.track_size))) - goto use_toc; - - /* if last recorded field is valid, return it. */ - if (ti.lra_v && ti_size >= (int)(offsetof(typeof(ti), last_rec_address) - + sizeof(ti.last_rec_address))) { - *last_written = be32_to_cpu(ti.last_rec_address); - } else { - /* make it up instead */ - *last_written = be32_to_cpu(ti.track_start) + - be32_to_cpu(ti.track_size); - if (ti.free_blocks) - *last_written -= (be32_to_cpu(ti.free_blocks) + 7); + switch (cmd) { + case CDROMMULTISESSION: + return cdrom_ioctl_multisession(cdi, argp); + case CDROMEJECT: + return cdrom_ioctl_eject(cdi); + case CDROMCLOSETRAY: + return cdrom_ioctl_closetray(cdi); + case CDROMEJECT_SW: + return cdrom_ioctl_eject_sw(cdi, arg); + case CDROM_MEDIA_CHANGED: + return cdrom_ioctl_media_changed(cdi, arg); + case CDROM_SET_OPTIONS: + return cdrom_ioctl_set_options(cdi, arg); + case CDROM_CLEAR_OPTIONS: + return cdrom_ioctl_clear_options(cdi, arg); + case CDROM_SELECT_SPEED: + return cdrom_ioctl_select_speed(cdi, arg); + case CDROM_SELECT_DISC: + return cdrom_ioctl_select_disc(cdi, arg); + case CDROMRESET: + return cdrom_ioctl_reset(cdi, bdev); + case CDROM_LOCKDOOR: + return cdrom_ioctl_lock_door(cdi, arg); + case CDROM_DEBUG: + return cdrom_ioctl_debug(cdi, arg); + case CDROM_GET_CAPABILITY: + return cdrom_ioctl_get_capability(cdi); + case CDROM_GET_MCN: + return cdrom_ioctl_get_mcn(cdi, argp); + case CDROM_DRIVE_STATUS: + return cdrom_ioctl_drive_status(cdi, arg); + case CDROM_DISC_STATUS: + return cdrom_ioctl_disc_status(cdi); + case CDROM_CHANGER_NSLOTS: + return cdrom_ioctl_changer_nslots(cdi); } - return 0; - /* this is where we end up if the drive either can't do a - GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if - it doesn't give enough information or fails. then we return - the toc contents. */ -use_toc: - toc.cdte_format = CDROM_MSF; - toc.cdte_track = CDROM_LEADOUT; - if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc))) - return ret; - sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA); - *last_written = toc.cdte_addr.lba; - return 0; -} - -/* return the next writable block. also for udf file system. */ -static int cdrom_get_next_writable(struct cdrom_device_info *cdi, long *next_writable) -{ - disc_information di; - track_information ti; - __u16 last_track; - int ret, ti_size; - - if (!CDROM_CAN(CDC_GENERIC_PACKET)) - goto use_last_written; - - ret = cdrom_get_disc_info(cdi, &di); - if (ret < 0 || ret < offsetof(typeof(di), last_track_lsb) - + sizeof(di.last_track_lsb)) - goto use_last_written; - - /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ - last_track = (di.last_track_msb << 8) | di.last_track_lsb; - ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); - if (ti_size < 0 || ti_size < offsetof(typeof(ti), track_start)) - goto use_last_written; - - /* if this track is blank, try the previous. */ - if (ti.blank) { - if (last_track == 1) - goto use_last_written; - last_track--; - ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); - if (ti_size < 0) - goto use_last_written; + /* + * Use the ioctls that are implemented through the generic_packet() + * interface. this may look at bit funny, but if -ENOTTY is + * returned that particular ioctl is not implemented and we + * let it go through the device specific ones. + */ + if (CDROM_CAN(CDC_GENERIC_PACKET)) { + ret = mmc_ioctl(cdi, cmd, arg); + if (ret != -ENOTTY) + return ret; } - /* if next recordable address field is valid, use it. */ - if (ti.nwa_v && ti_size >= offsetof(typeof(ti), next_writable) - + sizeof(ti.next_writable)) { - *next_writable = be32_to_cpu(ti.next_writable); - return 0; + /* + * Note: most of the cd_dbg() calls are commented out here, + * because they fill up the sys log when CD players poll + * the drive. + */ + switch (cmd) { + case CDROMSUBCHNL: + return cdrom_ioctl_get_subchnl(cdi, argp); + case CDROMREADTOCHDR: + return cdrom_ioctl_read_tochdr(cdi, argp); + case CDROMREADTOCENTRY: + return cdrom_ioctl_read_tocentry(cdi, argp); + case CDROMPLAYMSF: + return cdrom_ioctl_play_msf(cdi, argp); + case CDROMPLAYTRKIND: + return cdrom_ioctl_play_trkind(cdi, argp); + case CDROMVOLCTRL: + return cdrom_ioctl_volctrl(cdi, argp); + case CDROMVOLREAD: + return cdrom_ioctl_volread(cdi, argp); + case CDROMSTART: + case CDROMSTOP: + case CDROMPAUSE: + case CDROMRESUME: + return cdrom_ioctl_audioctl(cdi, cmd); } -use_last_written: - if ((ret = cdrom_get_last_written(cdi, next_writable))) { - *next_writable = 0; - return ret; - } else { - *next_writable += 7; - return 0; - } + return -ENOSYS; } EXPORT_SYMBOL(cdrom_get_last_written); diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 51e75ad964223e..584bc3126403d5 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -602,7 +602,7 @@ static void gdrom_readdisk_dma(struct work_struct *work) spin_unlock(&gdrom_lock); block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET; block_cnt = blk_rq_sectors(req)/GD_TO_BLK; - __raw_writel(virt_to_phys(req->buffer), GDROM_DMA_STARTADDR_REG); + __raw_writel(virt_to_phys(bio_data(req->bio)), GDROM_DMA_STARTADDR_REG); __raw_writel(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG); __raw_writel(1, GDROM_DMA_DIRECTION_REG); __raw_writel(1, GDROM_DMA_ENABLE_REG); diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 244759bbd7b73d..ac6c0f3e2eb28d 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -2,7 +2,7 @@ # Hardware Random Number Generator (RNG) configuration # -config HW_RANDOM +menuconfig HW_RANDOM tristate "Hardware Random Number Generator Core support" default m ---help--- @@ -20,9 +20,11 @@ config HW_RANDOM If unsure, say Y. +if HW_RANDOM + config HW_RANDOM_TIMERIOMEM tristate "Timer IOMEM HW Random Number Generator support" - depends on HW_RANDOM && HAS_IOMEM + depends on HAS_IOMEM ---help--- This driver provides kernel-side support for a generic Random Number Generator used by reading a 'dumb' iomem address that @@ -36,7 +38,7 @@ config HW_RANDOM_TIMERIOMEM config HW_RANDOM_INTEL tristate "Intel HW Random Number Generator support" - depends on HW_RANDOM && (X86 || IA64) && PCI + depends on (X86 || IA64) && PCI default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -49,7 +51,7 @@ config HW_RANDOM_INTEL config HW_RANDOM_AMD tristate "AMD HW Random Number Generator support" - depends on HW_RANDOM && (X86 || PPC_MAPLE) && PCI + depends on (X86 || PPC_MAPLE) && PCI default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -62,8 +64,8 @@ config HW_RANDOM_AMD config HW_RANDOM_ATMEL tristate "Atmel Random Number Generator support" - depends on HW_RANDOM && HAVE_CLK - default (HW_RANDOM && ARCH_AT91) + depends on ARCH_AT91 && HAVE_CLK + default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number Generator hardware found on Atmel AT91 devices. @@ -75,7 +77,7 @@ config HW_RANDOM_ATMEL config HW_RANDOM_BCM63XX tristate "Broadcom BCM63xx Random Number Generator support" - depends on HW_RANDOM && BCM63XX + depends on BCM63XX default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -88,7 +90,7 @@ config HW_RANDOM_BCM63XX config HW_RANDOM_BCM2835 tristate "Broadcom BCM2835 Random Number Generator support" - depends on HW_RANDOM && ARCH_BCM2835 + depends on ARCH_BCM2835 default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -101,7 +103,7 @@ config HW_RANDOM_BCM2835 config HW_RANDOM_GEODE tristate "AMD Geode HW Random Number Generator support" - depends on HW_RANDOM && X86_32 && PCI + depends on X86_32 && PCI default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -114,7 +116,7 @@ config HW_RANDOM_GEODE config HW_RANDOM_N2RNG tristate "Niagara2 Random Number Generator support" - depends on HW_RANDOM && SPARC64 + depends on SPARC64 default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -127,7 +129,7 @@ config HW_RANDOM_N2RNG config HW_RANDOM_VIA tristate "VIA HW Random Number Generator support" - depends on HW_RANDOM && X86 + depends on X86 default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -140,7 +142,7 @@ config HW_RANDOM_VIA config HW_RANDOM_IXP4XX tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support" - depends on HW_RANDOM && ARCH_IXP4XX + depends on ARCH_IXP4XX default HW_RANDOM ---help--- This driver provides kernel-side support for the Pseudo-Random @@ -153,7 +155,7 @@ config HW_RANDOM_IXP4XX config HW_RANDOM_OMAP tristate "OMAP Random Number Generator support" - depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP2PLUS) + depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -167,7 +169,7 @@ config HW_RANDOM_OMAP config HW_RANDOM_OMAP3_ROM tristate "OMAP3 ROM Random Number Generator support" - depends on HW_RANDOM && ARCH_OMAP3 + depends on ARCH_OMAP3 default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -180,7 +182,7 @@ config HW_RANDOM_OMAP3_ROM config HW_RANDOM_OCTEON tristate "Octeon Random Number Generator support" - depends on HW_RANDOM && CAVIUM_OCTEON_SOC + depends on CAVIUM_OCTEON_SOC default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -193,7 +195,7 @@ config HW_RANDOM_OCTEON config HW_RANDOM_PASEMI tristate "PA Semi HW Random Number Generator support" - depends on HW_RANDOM && PPC_PASEMI + depends on PPC_PASEMI default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -206,7 +208,7 @@ config HW_RANDOM_PASEMI config HW_RANDOM_VIRTIO tristate "VirtIO Random Number Generator support" - depends on HW_RANDOM && VIRTIO + depends on VIRTIO ---help--- This driver provides kernel-side support for the virtual Random Number Generator hardware. @@ -216,7 +218,7 @@ config HW_RANDOM_VIRTIO config HW_RANDOM_TX4939 tristate "TX4939 Random Number Generator support" - depends on HW_RANDOM && SOC_TX4939 + depends on SOC_TX4939 default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -229,7 +231,8 @@ config HW_RANDOM_TX4939 config HW_RANDOM_MXC_RNGA tristate "Freescale i.MX RNGA Random Number Generator" - depends on HW_RANDOM && ARCH_HAS_RNGA + depends on ARCH_HAS_RNGA + default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number Generator hardware found on Freescale i.MX processors. @@ -241,7 +244,8 @@ config HW_RANDOM_MXC_RNGA config HW_RANDOM_NOMADIK tristate "ST-Ericsson Nomadik Random Number Generator support" - depends on HW_RANDOM && ARCH_NOMADIK + depends on ARCH_NOMADIK + default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number Generator hardware found on ST-Ericsson SoCs (8815 and 8500). @@ -251,21 +255,10 @@ config HW_RANDOM_NOMADIK If unsure, say Y. -config HW_RANDOM_PICOXCELL - tristate "Picochip picoXcell true random number generator support" - depends on HW_RANDOM && ARCH_PICOXCELL && PICOXCELL_PC3X3 - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on Picochip PC3x3 and later devices. - - To compile this driver as a module, choose M here: the - module will be called picoxcell-rng. - - If unsure, say Y. - config HW_RANDOM_PPC4XX tristate "PowerPC 4xx generic true random number generator support" - depends on HW_RANDOM && PPC && 4xx + depends on PPC && 4xx + default HW_RANDOM ---help--- This driver provides the kernel-side support for the TRNG hardware found in the security function of some PowerPC 4xx SoCs. @@ -275,24 +268,9 @@ config HW_RANDOM_PPC4XX If unsure, say N. -config UML_RANDOM - depends on UML - tristate "Hardware random number generator" - help - This option enables UML's "hardware" random number generator. It - attaches itself to the host's /dev/random, supplying as much entropy - as the host has, rather than the small amount the UML gets from its - own drivers. It registers itself as a standard hardware random number - generator, major 10, minor 183, and the canonical device name is - /dev/hwrng. - The way to make use of this is to install the rng-tools package - (check your distro, or download from - http://sourceforge.net/projects/gkernel/). rngd periodically reads - /dev/hwrng and injects the entropy into /dev/random. - config HW_RANDOM_PSERIES tristate "pSeries HW Random Number Generator support" - depends on HW_RANDOM && PPC64 && IBMVIO + depends on PPC64 && IBMVIO default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -305,7 +283,7 @@ config HW_RANDOM_PSERIES config HW_RANDOM_POWERNV tristate "PowerNV Random Number Generator support" - depends on HW_RANDOM && PPC_POWERNV + depends on PPC_POWERNV default HW_RANDOM ---help--- This is the driver for Random Number Generator hardware found @@ -318,7 +296,8 @@ config HW_RANDOM_POWERNV config HW_RANDOM_EXYNOS tristate "EXYNOS HW random number generator support" - depends on HW_RANDOM && HAS_IOMEM && HAVE_CLK + depends on ARCH_EXYNOS + default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number Generator hardware found on EXYNOS SOCs. @@ -330,7 +309,7 @@ config HW_RANDOM_EXYNOS config HW_RANDOM_TPM tristate "TPM HW Random Number Generator support" - depends on HW_RANDOM && TCG_TPM + depends on TCG_TPM default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -343,7 +322,8 @@ config HW_RANDOM_TPM config HW_RANDOM_MSM tristate "Qualcomm SoCs Random Number Generator support" - depends on HW_RANDOM && ARCH_QCOM + depends on ARCH_QCOM + default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number Generator hardware found on Qualcomm SoCs. @@ -352,3 +332,20 @@ config HW_RANDOM_MSM module will be called msm-rng. If unsure, say Y. + +endif # HW_RANDOM + +config UML_RANDOM + depends on UML + tristate "Hardware random number generator" + help + This option enables UML's "hardware" random number generator. It + attaches itself to the host's /dev/random, supplying as much entropy + as the host has, rather than the small amount the UML gets from its + own drivers. It registers itself as a standard hardware random number + generator, major 10, minor 183, and the canonical device name is + /dev/hwrng. + The way to make use of this is to install the rng-tools package + (check your distro, or download from + http://sourceforge.net/projects/gkernel/). rngd periodically reads + /dev/hwrng and injects the entropy into /dev/random. diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 3ae7755a52e706..199ed283e1497b 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -22,7 +22,6 @@ obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o -obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 9b89ff4881de7c..f66ea258382f36 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -369,10 +369,8 @@ static int omap_rng_probe(struct platform_device *pdev) int ret; priv = devm_kzalloc(dev, sizeof(struct omap_rng_dev), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "could not allocate memory\n"); + if (!priv) return -ENOMEM; - }; omap_rng_ops.priv = (unsigned long)priv; platform_set_drvdata(pdev, priv); diff --git a/drivers/char/hw_random/picoxcell-rng.c b/drivers/char/hw_random/picoxcell-rng.c deleted file mode 100644 index eab5448ad56fb1..00000000000000 --- a/drivers/char/hw_random/picoxcell-rng.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2010-2011 Picochip Ltd., Jamie Iles - * - * 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. - * - * All enquiries to support@picochip.com - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define DATA_REG_OFFSET 0x0200 -#define CSR_REG_OFFSET 0x0278 -#define CSR_OUT_EMPTY_MASK (1 << 24) -#define CSR_FAULT_MASK (1 << 1) -#define TRNG_BLOCK_RESET_MASK (1 << 0) -#define TAI_REG_OFFSET 0x0380 - -/* - * The maximum amount of time in microseconds to spend waiting for data if the - * core wants us to wait. The TRNG should generate 32 bits every 320ns so a - * timeout of 20us seems reasonable. The TRNG does builtin tests of the data - * for randomness so we can't always assume there is data present. - */ -#define PICO_TRNG_TIMEOUT 20 - -static void __iomem *rng_base; -static struct clk *rng_clk; -static struct device *rng_dev; - -static inline u32 picoxcell_trng_read_csr(void) -{ - return __raw_readl(rng_base + CSR_REG_OFFSET); -} - -static inline bool picoxcell_trng_is_empty(void) -{ - return picoxcell_trng_read_csr() & CSR_OUT_EMPTY_MASK; -} - -/* - * Take the random number generator out of reset and make sure the interrupts - * are masked. We shouldn't need to get large amounts of random bytes so just - * poll the status register. The hardware generates 32 bits every 320ns so we - * shouldn't have to wait long enough to warrant waiting for an IRQ. - */ -static void picoxcell_trng_start(void) -{ - __raw_writel(0, rng_base + TAI_REG_OFFSET); - __raw_writel(0, rng_base + CSR_REG_OFFSET); -} - -static void picoxcell_trng_reset(void) -{ - __raw_writel(TRNG_BLOCK_RESET_MASK, rng_base + CSR_REG_OFFSET); - __raw_writel(TRNG_BLOCK_RESET_MASK, rng_base + TAI_REG_OFFSET); - picoxcell_trng_start(); -} - -/* - * Get some random data from the random number generator. The hw_random core - * layer provides us with locking. - */ -static int picoxcell_trng_read(struct hwrng *rng, void *buf, size_t max, - bool wait) -{ - int i; - - /* Wait for some data to become available. */ - for (i = 0; i < PICO_TRNG_TIMEOUT && picoxcell_trng_is_empty(); ++i) { - if (!wait) - return 0; - - udelay(1); - } - - if (picoxcell_trng_read_csr() & CSR_FAULT_MASK) { - dev_err(rng_dev, "fault detected, resetting TRNG\n"); - picoxcell_trng_reset(); - return -EIO; - } - - if (i == PICO_TRNG_TIMEOUT) - return 0; - - *(u32 *)buf = __raw_readl(rng_base + DATA_REG_OFFSET); - return sizeof(u32); -} - -static struct hwrng picoxcell_trng = { - .name = "picoxcell", - .read = picoxcell_trng_read, -}; - -static int picoxcell_trng_probe(struct platform_device *pdev) -{ - int ret; - struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - rng_base = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(rng_base)) - return PTR_ERR(rng_base); - - rng_clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(rng_clk)) { - dev_warn(&pdev->dev, "no clk\n"); - return PTR_ERR(rng_clk); - } - - ret = clk_enable(rng_clk); - if (ret) { - dev_warn(&pdev->dev, "unable to enable clk\n"); - return ret; - } - - picoxcell_trng_start(); - ret = hwrng_register(&picoxcell_trng); - if (ret) - goto err_register; - - rng_dev = &pdev->dev; - dev_info(&pdev->dev, "pixoxcell random number generator active\n"); - - return 0; - -err_register: - clk_disable(rng_clk); - return ret; -} - -static int picoxcell_trng_remove(struct platform_device *pdev) -{ - hwrng_unregister(&picoxcell_trng); - clk_disable(rng_clk); - - return 0; -} - -#ifdef CONFIG_PM -static int picoxcell_trng_suspend(struct device *dev) -{ - clk_disable(rng_clk); - - return 0; -} - -static int picoxcell_trng_resume(struct device *dev) -{ - return clk_enable(rng_clk); -} - -static const struct dev_pm_ops picoxcell_trng_pm_ops = { - .suspend = picoxcell_trng_suspend, - .resume = picoxcell_trng_resume, -}; -#endif /* CONFIG_PM */ - -static struct platform_driver picoxcell_trng_driver = { - .probe = picoxcell_trng_probe, - .remove = picoxcell_trng_remove, - .driver = { - .name = "picoxcell-trng", - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &picoxcell_trng_pm_ops, -#endif /* CONFIG_PM */ - }, -}; - -module_platform_driver(picoxcell_trng_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jamie Iles"); -MODULE_DESCRIPTION("Picochip picoXcell TRNG driver"); diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index 439ff8b28c439c..b6ab9ac3f34d25 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -120,10 +120,8 @@ static int timeriomem_rng_probe(struct platform_device *pdev) /* Allocate memory for the device structure (and zero it) */ priv = devm_kzalloc(&pdev->dev, sizeof(struct timeriomem_rng_private_data), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "failed to allocate device structure.\n"); + if (!priv) return -ENOMEM; - } platform_set_drvdata(pdev, priv); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 1c4bb4f6ce932f..5d665680ae33fe 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1007,7 +1007,7 @@ static int ipmi_thread(void *data) struct timespec busy_until; ipmi_si_set_not_busy(&busy_until); - set_user_nice(current, 19); + set_user_nice(current, MAX_NICE); while (!kthread_should_stop()) { int busy_wait; diff --git a/drivers/char/random.c b/drivers/char/random.c index 6b75713d953a4e..0a19d866a153f2 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -902,6 +902,7 @@ void add_disk_randomness(struct gendisk *disk) add_timer_randomness(disk->random, 0x100 + disk_devt(disk)); trace_add_disk_randomness(disk_devt(disk), ENTROPY_BITS(&input_pool)); } +EXPORT_SYMBOL_GPL(add_disk_randomness); #endif /********************************************************************* diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 6e8d65e9b1d3c1..0102dc788608ec 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -284,10 +284,10 @@ static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd, #endif static const struct file_operations raw_fops = { - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = blkdev_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = blkdev_write_iter, .fsync = blkdev_fsync, .open = raw_open, .release = raw_release, diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig index a7262fb8ce5591..75506e53075b95 100644 --- a/drivers/clk/bcm/Kconfig +++ b/drivers/clk/bcm/Kconfig @@ -6,4 +6,4 @@ config CLK_BCM_KONA help Enable common clock framework support for Broadcom SoCs using "Kona" style clock control units, including those - in the BCM281xx family. + in the BCM281xx and BCM21664 families. diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile index cf93359aa862f8..6297d05a9a1040 100644 --- a/drivers/clk/bcm/Makefile +++ b/drivers/clk/bcm/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o +obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o diff --git a/drivers/clk/bcm/clk-bcm21664.c b/drivers/clk/bcm/clk-bcm21664.c new file mode 100644 index 00000000000000..eeae4cad22816d --- /dev/null +++ b/drivers/clk/bcm/clk-bcm21664.c @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * Copyright 2014 Linaro Limited + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "clk-kona.h" +#include "dt-bindings/clock/bcm21664.h" + +#define BCM21664_CCU_COMMON(_name, _capname) \ + KONA_CCU_COMMON(BCM21664, _name, _capname) + +/* Root CCU */ + +static struct peri_clk_data frac_1m_data = { + .gate = HW_SW_GATE(0x214, 16, 0, 1), + .clocks = CLOCKS("ref_crystal"), +}; + +static struct ccu_data root_ccu_data = { + BCM21664_CCU_COMMON(root, ROOT), + /* no policy control */ + .kona_clks = { + [BCM21664_ROOT_CCU_FRAC_1M] = + KONA_CLK(root, frac_1m, peri), + [BCM21664_ROOT_CCU_CLOCK_COUNT] = LAST_KONA_CLK, + }, +}; + +/* AON CCU */ + +static struct peri_clk_data hub_timer_data = { + .gate = HW_SW_GATE(0x0414, 16, 0, 1), + .hyst = HYST(0x0414, 8, 9), + .clocks = CLOCKS("bbl_32k", + "frac_1m", + "dft_19_5m"), + .sel = SELECTOR(0x0a10, 0, 2), + .trig = TRIGGER(0x0a40, 4), +}; + +static struct ccu_data aon_ccu_data = { + BCM21664_CCU_COMMON(aon, AON), + .policy = { + .enable = CCU_LVM_EN(0x0034, 0), + .control = CCU_POLICY_CTL(0x000c, 0, 1, 2), + }, + .kona_clks = { + [BCM21664_AON_CCU_HUB_TIMER] = + KONA_CLK(aon, hub_timer, peri), + [BCM21664_AON_CCU_CLOCK_COUNT] = LAST_KONA_CLK, + }, +}; + +/* Master CCU */ + +static struct peri_clk_data sdio1_data = { + .gate = HW_SW_GATE(0x0358, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_52m", + "ref_52m", + "var_96m", + "ref_96m"), + .sel = SELECTOR(0x0a28, 0, 3), + .div = DIVIDER(0x0a28, 4, 14), + .trig = TRIGGER(0x0afc, 9), +}; + +static struct peri_clk_data sdio2_data = { + .gate = HW_SW_GATE(0x035c, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_52m", + "ref_52m", + "var_96m", + "ref_96m"), + .sel = SELECTOR(0x0a2c, 0, 3), + .div = DIVIDER(0x0a2c, 4, 14), + .trig = TRIGGER(0x0afc, 10), +}; + +static struct peri_clk_data sdio3_data = { + .gate = HW_SW_GATE(0x0364, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_52m", + "ref_52m", + "var_96m", + "ref_96m"), + .sel = SELECTOR(0x0a34, 0, 3), + .div = DIVIDER(0x0a34, 4, 14), + .trig = TRIGGER(0x0afc, 12), +}; + +static struct peri_clk_data sdio4_data = { + .gate = HW_SW_GATE(0x0360, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_52m", + "ref_52m", + "var_96m", + "ref_96m"), + .sel = SELECTOR(0x0a30, 0, 3), + .div = DIVIDER(0x0a30, 4, 14), + .trig = TRIGGER(0x0afc, 11), +}; + +static struct peri_clk_data sdio1_sleep_data = { + .clocks = CLOCKS("ref_32k"), /* Verify */ + .gate = HW_SW_GATE(0x0358, 18, 2, 3), +}; + +static struct peri_clk_data sdio2_sleep_data = { + .clocks = CLOCKS("ref_32k"), /* Verify */ + .gate = HW_SW_GATE(0x035c, 18, 2, 3), +}; + +static struct peri_clk_data sdio3_sleep_data = { + .clocks = CLOCKS("ref_32k"), /* Verify */ + .gate = HW_SW_GATE(0x0364, 18, 2, 3), +}; + +static struct peri_clk_data sdio4_sleep_data = { + .clocks = CLOCKS("ref_32k"), /* Verify */ + .gate = HW_SW_GATE(0x0360, 18, 2, 3), +}; + +static struct ccu_data master_ccu_data = { + BCM21664_CCU_COMMON(master, MASTER), + .policy = { + .enable = CCU_LVM_EN(0x0034, 0), + .control = CCU_POLICY_CTL(0x000c, 0, 1, 2), + }, + .kona_clks = { + [BCM21664_MASTER_CCU_SDIO1] = + KONA_CLK(master, sdio1, peri), + [BCM21664_MASTER_CCU_SDIO2] = + KONA_CLK(master, sdio2, peri), + [BCM21664_MASTER_CCU_SDIO3] = + KONA_CLK(master, sdio3, peri), + [BCM21664_MASTER_CCU_SDIO4] = + KONA_CLK(master, sdio4, peri), + [BCM21664_MASTER_CCU_SDIO1_SLEEP] = + KONA_CLK(master, sdio1_sleep, peri), + [BCM21664_MASTER_CCU_SDIO2_SLEEP] = + KONA_CLK(master, sdio2_sleep, peri), + [BCM21664_MASTER_CCU_SDIO3_SLEEP] = + KONA_CLK(master, sdio3_sleep, peri), + [BCM21664_MASTER_CCU_SDIO4_SLEEP] = + KONA_CLK(master, sdio4_sleep, peri), + [BCM21664_MASTER_CCU_CLOCK_COUNT] = LAST_KONA_CLK, + }, +}; + +/* Slave CCU */ + +static struct peri_clk_data uartb_data = { + .gate = HW_SW_GATE(0x0400, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_156m", + "ref_156m"), + .sel = SELECTOR(0x0a10, 0, 2), + .div = FRAC_DIVIDER(0x0a10, 4, 12, 8), + .trig = TRIGGER(0x0afc, 2), +}; + +static struct peri_clk_data uartb2_data = { + .gate = HW_SW_GATE(0x0404, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_156m", + "ref_156m"), + .sel = SELECTOR(0x0a14, 0, 2), + .div = FRAC_DIVIDER(0x0a14, 4, 12, 8), + .trig = TRIGGER(0x0afc, 3), +}; + +static struct peri_clk_data uartb3_data = { + .gate = HW_SW_GATE(0x0408, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_156m", + "ref_156m"), + .sel = SELECTOR(0x0a18, 0, 2), + .div = FRAC_DIVIDER(0x0a18, 4, 12, 8), + .trig = TRIGGER(0x0afc, 4), +}; + +static struct peri_clk_data bsc1_data = { + .gate = HW_SW_GATE(0x0458, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_104m", + "ref_104m", + "var_13m", + "ref_13m"), + .sel = SELECTOR(0x0a64, 0, 3), + .trig = TRIGGER(0x0afc, 23), +}; + +static struct peri_clk_data bsc2_data = { + .gate = HW_SW_GATE(0x045c, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_104m", + "ref_104m", + "var_13m", + "ref_13m"), + .sel = SELECTOR(0x0a68, 0, 3), + .trig = TRIGGER(0x0afc, 24), +}; + +static struct peri_clk_data bsc3_data = { + .gate = HW_SW_GATE(0x0470, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_104m", + "ref_104m", + "var_13m", + "ref_13m"), + .sel = SELECTOR(0x0a7c, 0, 3), + .trig = TRIGGER(0x0afc, 18), +}; + +static struct peri_clk_data bsc4_data = { + .gate = HW_SW_GATE(0x0474, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_104m", + "ref_104m", + "var_13m", + "ref_13m"), + .sel = SELECTOR(0x0a80, 0, 3), + .trig = TRIGGER(0x0afc, 19), +}; + +static struct ccu_data slave_ccu_data = { + BCM21664_CCU_COMMON(slave, SLAVE), + .policy = { + .enable = CCU_LVM_EN(0x0034, 0), + .control = CCU_POLICY_CTL(0x000c, 0, 1, 2), + }, + .kona_clks = { + [BCM21664_SLAVE_CCU_UARTB] = + KONA_CLK(slave, uartb, peri), + [BCM21664_SLAVE_CCU_UARTB2] = + KONA_CLK(slave, uartb2, peri), + [BCM21664_SLAVE_CCU_UARTB3] = + KONA_CLK(slave, uartb3, peri), + [BCM21664_SLAVE_CCU_BSC1] = + KONA_CLK(slave, bsc1, peri), + [BCM21664_SLAVE_CCU_BSC2] = + KONA_CLK(slave, bsc2, peri), + [BCM21664_SLAVE_CCU_BSC3] = + KONA_CLK(slave, bsc3, peri), + [BCM21664_SLAVE_CCU_BSC4] = + KONA_CLK(slave, bsc4, peri), + [BCM21664_SLAVE_CCU_CLOCK_COUNT] = LAST_KONA_CLK, + }, +}; + +/* Device tree match table callback functions */ + +static void __init kona_dt_root_ccu_setup(struct device_node *node) +{ + kona_dt_ccu_setup(&root_ccu_data, node); +} + +static void __init kona_dt_aon_ccu_setup(struct device_node *node) +{ + kona_dt_ccu_setup(&aon_ccu_data, node); +} + +static void __init kona_dt_master_ccu_setup(struct device_node *node) +{ + kona_dt_ccu_setup(&master_ccu_data, node); +} + +static void __init kona_dt_slave_ccu_setup(struct device_node *node) +{ + kona_dt_ccu_setup(&slave_ccu_data, node); +} + +CLK_OF_DECLARE(bcm21664_root_ccu, BCM21664_DT_ROOT_CCU_COMPAT, + kona_dt_root_ccu_setup); +CLK_OF_DECLARE(bcm21664_aon_ccu, BCM21664_DT_AON_CCU_COMPAT, + kona_dt_aon_ccu_setup); +CLK_OF_DECLARE(bcm21664_master_ccu, BCM21664_DT_MASTER_CCU_COMPAT, + kona_dt_master_ccu_setup); +CLK_OF_DECLARE(bcm21664_slave_ccu, BCM21664_DT_SLAVE_CCU_COMPAT, + kona_dt_slave_ccu_setup); diff --git a/drivers/clk/bcm/clk-bcm281xx.c b/drivers/clk/bcm/clk-bcm281xx.c index 3c66de696aeb44..502a487d62c5e5 100644 --- a/drivers/clk/bcm/clk-bcm281xx.c +++ b/drivers/clk/bcm/clk-bcm281xx.c @@ -15,14 +15,10 @@ #include "clk-kona.h" #include "dt-bindings/clock/bcm281xx.h" -/* bcm11351 CCU device tree "compatible" strings */ -#define BCM11351_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu" -#define BCM11351_DT_AON_CCU_COMPAT "brcm,bcm11351-aon-ccu" -#define BCM11351_DT_HUB_CCU_COMPAT "brcm,bcm11351-hub-ccu" -#define BCM11351_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu" -#define BCM11351_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu" +#define BCM281XX_CCU_COMMON(_name, _ucase_name) \ + KONA_CCU_COMMON(BCM281XX, _name, _ucase_name) -/* Root CCU clocks */ +/* Root CCU */ static struct peri_clk_data frac_1m_data = { .gate = HW_SW_GATE(0x214, 16, 0, 1), @@ -31,7 +27,16 @@ static struct peri_clk_data frac_1m_data = { .clocks = CLOCKS("ref_crystal"), }; -/* AON CCU clocks */ +static struct ccu_data root_ccu_data = { + BCM281XX_CCU_COMMON(root, ROOT), + .kona_clks = { + [BCM281XX_ROOT_CCU_FRAC_1M] = + KONA_CLK(root, frac_1m, peri), + [BCM281XX_ROOT_CCU_CLOCK_COUNT] = LAST_KONA_CLK, + }, +}; + +/* AON CCU */ static struct peri_clk_data hub_timer_data = { .gate = HW_SW_GATE(0x0414, 16, 0, 1), @@ -60,7 +65,20 @@ static struct peri_clk_data pmu_bsc_var_data = { .trig = TRIGGER(0x0a40, 2), }; -/* Hub CCU clocks */ +static struct ccu_data aon_ccu_data = { + BCM281XX_CCU_COMMON(aon, AON), + .kona_clks = { + [BCM281XX_AON_CCU_HUB_TIMER] = + KONA_CLK(aon, hub_timer, peri), + [BCM281XX_AON_CCU_PMU_BSC] = + KONA_CLK(aon, pmu_bsc, peri), + [BCM281XX_AON_CCU_PMU_BSC_VAR] = + KONA_CLK(aon, pmu_bsc_var, peri), + [BCM281XX_AON_CCU_CLOCK_COUNT] = LAST_KONA_CLK, + }, +}; + +/* Hub CCU */ static struct peri_clk_data tmon_1m_data = { .gate = HW_SW_GATE(0x04a4, 18, 2, 3), @@ -70,7 +88,16 @@ static struct peri_clk_data tmon_1m_data = { .trig = TRIGGER(0x0e84, 1), }; -/* Master CCU clocks */ +static struct ccu_data hub_ccu_data = { + BCM281XX_CCU_COMMON(hub, HUB), + .kona_clks = { + [BCM281XX_HUB_CCU_TMON_1M] = + KONA_CLK(hub, tmon_1m, peri), + [BCM281XX_HUB_CCU_CLOCK_COUNT] = LAST_KONA_CLK, + }, +}; + +/* Master CCU */ static struct peri_clk_data sdio1_data = { .gate = HW_SW_GATE(0x0358, 18, 2, 3), @@ -153,7 +180,28 @@ static struct peri_clk_data hsic2_12m_data = { .trig = TRIGGER(0x0afc, 5), }; -/* Slave CCU clocks */ +static struct ccu_data master_ccu_data = { + BCM281XX_CCU_COMMON(master, MASTER), + .kona_clks = { + [BCM281XX_MASTER_CCU_SDIO1] = + KONA_CLK(master, sdio1, peri), + [BCM281XX_MASTER_CCU_SDIO2] = + KONA_CLK(master, sdio2, peri), + [BCM281XX_MASTER_CCU_SDIO3] = + KONA_CLK(master, sdio3, peri), + [BCM281XX_MASTER_CCU_SDIO4] = + KONA_CLK(master, sdio4, peri), + [BCM281XX_MASTER_CCU_USB_IC] = + KONA_CLK(master, usb_ic, peri), + [BCM281XX_MASTER_CCU_HSIC2_48M] = + KONA_CLK(master, hsic2_48m, peri), + [BCM281XX_MASTER_CCU_HSIC2_12M] = + KONA_CLK(master, hsic2_12m, peri), + [BCM281XX_MASTER_CCU_CLOCK_COUNT] = LAST_KONA_CLK, + }, +}; + +/* Slave CCU */ static struct peri_clk_data uartb_data = { .gate = HW_SW_GATE(0x0400, 18, 2, 3), @@ -261,156 +309,67 @@ static struct peri_clk_data pwm_data = { .trig = TRIGGER(0x0afc, 15), }; -/* - * CCU setup routines - * - * These are called from kona_dt_ccu_setup() to initialize the array - * of clocks provided by the CCU. Once allocated, the entries in - * the array are initialized by calling kona_clk_setup() with the - * initialization data for each clock. They return 0 if successful - * or an error code otherwise. - */ -static int __init bcm281xx_root_ccu_clks_setup(struct ccu_data *ccu) -{ - struct clk **clks; - size_t count = BCM281XX_ROOT_CCU_CLOCK_COUNT; - - clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); - if (!clks) { - pr_err("%s: failed to allocate root clocks\n", __func__); - return -ENOMEM; - } - ccu->data.clks = clks; - ccu->data.clk_num = count; - - PERI_CLK_SETUP(clks, ccu, BCM281XX_ROOT_CCU_FRAC_1M, frac_1m); - - return 0; -} - -static int __init bcm281xx_aon_ccu_clks_setup(struct ccu_data *ccu) -{ - struct clk **clks; - size_t count = BCM281XX_AON_CCU_CLOCK_COUNT; - - clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); - if (!clks) { - pr_err("%s: failed to allocate aon clocks\n", __func__); - return -ENOMEM; - } - ccu->data.clks = clks; - ccu->data.clk_num = count; - - PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_HUB_TIMER, hub_timer); - PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC, pmu_bsc); - PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC_VAR, pmu_bsc_var); - - return 0; -} - -static int __init bcm281xx_hub_ccu_clks_setup(struct ccu_data *ccu) -{ - struct clk **clks; - size_t count = BCM281XX_HUB_CCU_CLOCK_COUNT; - - clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); - if (!clks) { - pr_err("%s: failed to allocate hub clocks\n", __func__); - return -ENOMEM; - } - ccu->data.clks = clks; - ccu->data.clk_num = count; - - PERI_CLK_SETUP(clks, ccu, BCM281XX_HUB_CCU_TMON_1M, tmon_1m); - - return 0; -} - -static int __init bcm281xx_master_ccu_clks_setup(struct ccu_data *ccu) -{ - struct clk **clks; - size_t count = BCM281XX_MASTER_CCU_CLOCK_COUNT; - - clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); - if (!clks) { - pr_err("%s: failed to allocate master clocks\n", __func__); - return -ENOMEM; - } - ccu->data.clks = clks; - ccu->data.clk_num = count; - - PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO1, sdio1); - PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO2, sdio2); - PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO3, sdio3); - PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO4, sdio4); - PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_USB_IC, usb_ic); - PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_48M, hsic2_48m); - PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_12M, hsic2_12m); - - return 0; -} - -static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu) -{ - struct clk **clks; - size_t count = BCM281XX_SLAVE_CCU_CLOCK_COUNT; - - clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); - if (!clks) { - pr_err("%s: failed to allocate slave clocks\n", __func__); - return -ENOMEM; - } - ccu->data.clks = clks; - ccu->data.clk_num = count; - - PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB, uartb); - PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB2, uartb2); - PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB3, uartb3); - PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB4, uartb4); - PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP0, ssp0); - PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP2, ssp2); - PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC1, bsc1); - PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC2, bsc2); - PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC3, bsc3); - PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_PWM, pwm); - - return 0; -} +static struct ccu_data slave_ccu_data = { + BCM281XX_CCU_COMMON(slave, SLAVE), + .kona_clks = { + [BCM281XX_SLAVE_CCU_UARTB] = + KONA_CLK(slave, uartb, peri), + [BCM281XX_SLAVE_CCU_UARTB2] = + KONA_CLK(slave, uartb2, peri), + [BCM281XX_SLAVE_CCU_UARTB3] = + KONA_CLK(slave, uartb3, peri), + [BCM281XX_SLAVE_CCU_UARTB4] = + KONA_CLK(slave, uartb4, peri), + [BCM281XX_SLAVE_CCU_SSP0] = + KONA_CLK(slave, ssp0, peri), + [BCM281XX_SLAVE_CCU_SSP2] = + KONA_CLK(slave, ssp2, peri), + [BCM281XX_SLAVE_CCU_BSC1] = + KONA_CLK(slave, bsc1, peri), + [BCM281XX_SLAVE_CCU_BSC2] = + KONA_CLK(slave, bsc2, peri), + [BCM281XX_SLAVE_CCU_BSC3] = + KONA_CLK(slave, bsc3, peri), + [BCM281XX_SLAVE_CCU_PWM] = + KONA_CLK(slave, pwm, peri), + [BCM281XX_SLAVE_CCU_CLOCK_COUNT] = LAST_KONA_CLK, + }, +}; /* Device tree match table callback functions */ static void __init kona_dt_root_ccu_setup(struct device_node *node) { - kona_dt_ccu_setup(node, bcm281xx_root_ccu_clks_setup); + kona_dt_ccu_setup(&root_ccu_data, node); } static void __init kona_dt_aon_ccu_setup(struct device_node *node) { - kona_dt_ccu_setup(node, bcm281xx_aon_ccu_clks_setup); + kona_dt_ccu_setup(&aon_ccu_data, node); } static void __init kona_dt_hub_ccu_setup(struct device_node *node) { - kona_dt_ccu_setup(node, bcm281xx_hub_ccu_clks_setup); + kona_dt_ccu_setup(&hub_ccu_data, node); } static void __init kona_dt_master_ccu_setup(struct device_node *node) { - kona_dt_ccu_setup(node, bcm281xx_master_ccu_clks_setup); + kona_dt_ccu_setup(&master_ccu_data, node); } static void __init kona_dt_slave_ccu_setup(struct device_node *node) { - kona_dt_ccu_setup(node, bcm281xx_slave_ccu_clks_setup); + kona_dt_ccu_setup(&slave_ccu_data, node); } -CLK_OF_DECLARE(bcm11351_root_ccu, BCM11351_DT_ROOT_CCU_COMPAT, +CLK_OF_DECLARE(bcm281xx_root_ccu, BCM281XX_DT_ROOT_CCU_COMPAT, kona_dt_root_ccu_setup); -CLK_OF_DECLARE(bcm11351_aon_ccu, BCM11351_DT_AON_CCU_COMPAT, +CLK_OF_DECLARE(bcm281xx_aon_ccu, BCM281XX_DT_AON_CCU_COMPAT, kona_dt_aon_ccu_setup); -CLK_OF_DECLARE(bcm11351_hub_ccu, BCM11351_DT_HUB_CCU_COMPAT, +CLK_OF_DECLARE(bcm281xx_hub_ccu, BCM281XX_DT_HUB_CCU_COMPAT, kona_dt_hub_ccu_setup); -CLK_OF_DECLARE(bcm11351_master_ccu, BCM11351_DT_MASTER_CCU_COMPAT, +CLK_OF_DECLARE(bcm281xx_master_ccu, BCM281XX_DT_MASTER_CCU_COMPAT, kona_dt_master_ccu_setup); -CLK_OF_DECLARE(bcm11351_slave_ccu, BCM11351_DT_SLAVE_CCU_COMPAT, +CLK_OF_DECLARE(bcm281xx_slave_ccu, BCM281XX_DT_SLAVE_CCU_COMPAT, kona_dt_slave_ccu_setup); diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c index c7607feb18dd15..e5aededdd3221c 100644 --- a/drivers/clk/bcm/clk-kona-setup.c +++ b/drivers/clk/bcm/clk-kona-setup.c @@ -25,9 +25,34 @@ LIST_HEAD(ccu_list); /* The list of set up CCUs */ /* Validity checking */ +static bool ccu_data_offsets_valid(struct ccu_data *ccu) +{ + struct ccu_policy *ccu_policy = &ccu->policy; + u32 limit; + + limit = ccu->range - sizeof(u32); + limit = round_down(limit, sizeof(u32)); + if (ccu_policy_exists(ccu_policy)) { + if (ccu_policy->enable.offset > limit) { + pr_err("%s: bad policy enable offset for %s " + "(%u > %u)\n", __func__, + ccu->name, ccu_policy->enable.offset, limit); + return false; + } + if (ccu_policy->control.offset > limit) { + pr_err("%s: bad policy control offset for %s " + "(%u > %u)\n", __func__, + ccu->name, ccu_policy->control.offset, limit); + return false; + } + } + + return true; +} + static bool clk_requires_trigger(struct kona_clk *bcm_clk) { - struct peri_clk_data *peri = bcm_clk->peri; + struct peri_clk_data *peri = bcm_clk->u.peri; struct bcm_clk_sel *sel; struct bcm_clk_div *div; @@ -54,7 +79,9 @@ static bool clk_requires_trigger(struct kona_clk *bcm_clk) static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk) { struct peri_clk_data *peri; + struct bcm_clk_policy *policy; struct bcm_clk_gate *gate; + struct bcm_clk_hyst *hyst; struct bcm_clk_div *div; struct bcm_clk_sel *sel; struct bcm_clk_trig *trig; @@ -63,37 +90,59 @@ static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk) u32 limit; BUG_ON(bcm_clk->type != bcm_clk_peri); - peri = bcm_clk->peri; - name = bcm_clk->name; + peri = bcm_clk->u.peri; + name = bcm_clk->init_data.name; range = bcm_clk->ccu->range; limit = range - sizeof(u32); limit = round_down(limit, sizeof(u32)); + policy = &peri->policy; + if (policy_exists(policy)) { + if (policy->offset > limit) { + pr_err("%s: bad policy offset for %s (%u > %u)\n", + __func__, name, policy->offset, limit); + return false; + } + } + gate = &peri->gate; + hyst = &peri->hyst; if (gate_exists(gate)) { if (gate->offset > limit) { pr_err("%s: bad gate offset for %s (%u > %u)\n", __func__, name, gate->offset, limit); return false; } + + if (hyst_exists(hyst)) { + if (hyst->offset > limit) { + pr_err("%s: bad hysteresis offset for %s " + "(%u > %u)\n", __func__, + name, hyst->offset, limit); + return false; + } + } + } else if (hyst_exists(hyst)) { + pr_err("%s: hysteresis but no gate for %s\n", __func__, name); + return false; } div = &peri->div; if (divider_exists(div)) { - if (div->offset > limit) { + if (div->u.s.offset > limit) { pr_err("%s: bad divider offset for %s (%u > %u)\n", - __func__, name, div->offset, limit); + __func__, name, div->u.s.offset, limit); return false; } } div = &peri->pre_div; if (divider_exists(div)) { - if (div->offset > limit) { + if (div->u.s.offset > limit) { pr_err("%s: bad pre-divider offset for %s " "(%u > %u)\n", - __func__, name, div->offset, limit); + __func__, name, div->u.s.offset, limit); return false; } } @@ -167,6 +216,36 @@ static bool bitfield_valid(u32 shift, u32 width, const char *field_name, return true; } +static bool +ccu_policy_valid(struct ccu_policy *ccu_policy, const char *ccu_name) +{ + struct bcm_lvm_en *enable = &ccu_policy->enable; + struct bcm_policy_ctl *control; + + if (!bit_posn_valid(enable->bit, "policy enable", ccu_name)) + return false; + + control = &ccu_policy->control; + if (!bit_posn_valid(control->go_bit, "policy control GO", ccu_name)) + return false; + + if (!bit_posn_valid(control->atl_bit, "policy control ATL", ccu_name)) + return false; + + if (!bit_posn_valid(control->ac_bit, "policy control AC", ccu_name)) + return false; + + return true; +} + +static bool policy_valid(struct bcm_clk_policy *policy, const char *clock_name) +{ + if (!bit_posn_valid(policy->bit, "policy", clock_name)) + return false; + + return true; +} + /* * All gates, if defined, have a status bit, and for hardware-only * gates, that's it. Gates that can be software controlled also @@ -196,6 +275,17 @@ static bool gate_valid(struct bcm_clk_gate *gate, const char *field_name, return true; } +static bool hyst_valid(struct bcm_clk_hyst *hyst, const char *clock_name) +{ + if (!bit_posn_valid(hyst->en_bit, "hysteresis enable", clock_name)) + return false; + + if (!bit_posn_valid(hyst->val_bit, "hysteresis value", clock_name)) + return false; + + return true; +} + /* * A selector bitfield must be valid. Its parent_sel array must * also be reasonable for the field. @@ -249,21 +339,22 @@ static bool div_valid(struct bcm_clk_div *div, const char *field_name, { if (divider_is_fixed(div)) { /* Any fixed divider value but 0 is OK */ - if (div->fixed == 0) { + if (div->u.fixed == 0) { pr_err("%s: bad %s fixed value 0 for %s\n", __func__, field_name, clock_name); return false; } return true; } - if (!bitfield_valid(div->shift, div->width, field_name, clock_name)) + if (!bitfield_valid(div->u.s.shift, div->u.s.width, + field_name, clock_name)) return false; if (divider_has_fraction(div)) - if (div->frac_width > div->width) { + if (div->u.s.frac_width > div->u.s.width) { pr_warn("%s: bad %s fraction width for %s (%u > %u)\n", __func__, field_name, clock_name, - div->frac_width, div->width); + div->u.s.frac_width, div->u.s.width); return false; } @@ -278,7 +369,7 @@ static bool div_valid(struct bcm_clk_div *div, const char *field_name, */ static bool kona_dividers_valid(struct kona_clk *bcm_clk) { - struct peri_clk_data *peri = bcm_clk->peri; + struct peri_clk_data *peri = bcm_clk->u.peri; struct bcm_clk_div *div; struct bcm_clk_div *pre_div; u32 limit; @@ -295,7 +386,7 @@ static bool kona_dividers_valid(struct kona_clk *bcm_clk) limit = BITS_PER_BYTE * sizeof(u32); - return div->frac_width + pre_div->frac_width <= limit; + return div->u.s.frac_width + pre_div->u.s.frac_width <= limit; } @@ -311,7 +402,9 @@ static bool peri_clk_data_valid(struct kona_clk *bcm_clk) { struct peri_clk_data *peri; + struct bcm_clk_policy *policy; struct bcm_clk_gate *gate; + struct bcm_clk_hyst *hyst; struct bcm_clk_sel *sel; struct bcm_clk_div *div; struct bcm_clk_div *pre_div; @@ -328,12 +421,21 @@ peri_clk_data_valid(struct kona_clk *bcm_clk) if (!peri_clk_data_offsets_valid(bcm_clk)) return false; - peri = bcm_clk->peri; - name = bcm_clk->name; + peri = bcm_clk->u.peri; + name = bcm_clk->init_data.name; + + policy = &peri->policy; + if (policy_exists(policy) && !policy_valid(policy, name)) + return false; + gate = &peri->gate; if (gate_exists(gate) && !gate_valid(gate, "gate", name)) return false; + hyst = &peri->hyst; + if (hyst_exists(hyst) && !hyst_valid(hyst, name)) + return false; + sel = &peri->sel; if (selector_exists(sel)) { if (!sel_valid(sel, "selector", name)) @@ -566,7 +668,6 @@ static void peri_clk_teardown(struct peri_clk_data *data, struct clk_init_data *init_data) { clk_sel_teardown(&data->sel, init_data); - init_data->ops = NULL; } /* @@ -575,10 +676,9 @@ static void peri_clk_teardown(struct peri_clk_data *data, * that can be assigned if the clock has one or more parent clocks * associated with it. */ -static int peri_clk_setup(struct ccu_data *ccu, struct peri_clk_data *data, - struct clk_init_data *init_data) +static int +peri_clk_setup(struct peri_clk_data *data, struct clk_init_data *init_data) { - init_data->ops = &kona_peri_clk_ops; init_data->flags = CLK_IGNORE_UNUSED; return clk_sel_setup(data->clocks, &data->sel, init_data); @@ -588,12 +688,12 @@ static void bcm_clk_teardown(struct kona_clk *bcm_clk) { switch (bcm_clk->type) { case bcm_clk_peri: - peri_clk_teardown(bcm_clk->data, &bcm_clk->init_data); + peri_clk_teardown(bcm_clk->u.data, &bcm_clk->init_data); break; default: break; } - bcm_clk->data = NULL; + bcm_clk->u.data = NULL; bcm_clk->type = bcm_clk_none; } @@ -616,39 +716,26 @@ static void kona_clk_teardown(struct clk *clk) bcm_clk_teardown(bcm_clk); } -struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name, - enum bcm_clk_type type, void *data) +struct clk *kona_clk_setup(struct kona_clk *bcm_clk) { - struct kona_clk *bcm_clk; - struct clk_init_data *init_data; + struct clk_init_data *init_data = &bcm_clk->init_data; struct clk *clk = NULL; - bcm_clk = kzalloc(sizeof(*bcm_clk), GFP_KERNEL); - if (!bcm_clk) { - pr_err("%s: failed to allocate bcm_clk for %s\n", __func__, - name); - return NULL; - } - bcm_clk->ccu = ccu; - bcm_clk->name = name; - - init_data = &bcm_clk->init_data; - init_data->name = name; - switch (type) { + switch (bcm_clk->type) { case bcm_clk_peri: - if (peri_clk_setup(ccu, data, init_data)) - goto out_free; + if (peri_clk_setup(bcm_clk->u.data, init_data)) + return NULL; break; default: - data = NULL; - break; + pr_err("%s: clock type %d invalid for %s\n", __func__, + (int)bcm_clk->type, init_data->name); + return NULL; } - bcm_clk->type = type; - bcm_clk->data = data; /* Make sure everything makes sense before we set it up */ if (!kona_clk_valid(bcm_clk)) { - pr_err("%s: clock data invalid for %s\n", __func__, name); + pr_err("%s: clock data invalid for %s\n", __func__, + init_data->name); goto out_teardown; } @@ -656,7 +743,7 @@ struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name, clk = clk_register(NULL, &bcm_clk->hw); if (IS_ERR(clk)) { pr_err("%s: error registering clock %s (%ld)\n", __func__, - name, PTR_ERR(clk)); + init_data->name, PTR_ERR(clk)); goto out_teardown; } BUG_ON(!clk); @@ -664,8 +751,6 @@ struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name, return clk; out_teardown: bcm_clk_teardown(bcm_clk); -out_free: - kfree(bcm_clk); return NULL; } @@ -674,50 +759,64 @@ static void ccu_clks_teardown(struct ccu_data *ccu) { u32 i; - for (i = 0; i < ccu->data.clk_num; i++) - kona_clk_teardown(ccu->data.clks[i]); - kfree(ccu->data.clks); + for (i = 0; i < ccu->clk_data.clk_num; i++) + kona_clk_teardown(ccu->clk_data.clks[i]); + kfree(ccu->clk_data.clks); } static void kona_ccu_teardown(struct ccu_data *ccu) { - if (!ccu) - return; - + kfree(ccu->clk_data.clks); + ccu->clk_data.clks = NULL; if (!ccu->base) - goto done; + return; of_clk_del_provider(ccu->node); /* safe if never added */ ccu_clks_teardown(ccu); list_del(&ccu->links); of_node_put(ccu->node); + ccu->node = NULL; iounmap(ccu->base); -done: - kfree(ccu->name); - kfree(ccu); + ccu->base = NULL; +} + +static bool ccu_data_valid(struct ccu_data *ccu) +{ + struct ccu_policy *ccu_policy; + + if (!ccu_data_offsets_valid(ccu)) + return false; + + ccu_policy = &ccu->policy; + if (ccu_policy_exists(ccu_policy)) + if (!ccu_policy_valid(ccu_policy, ccu->name)) + return false; + + return true; } /* * Set up a CCU. Call the provided ccu_clks_setup callback to * initialize the array of clocks provided by the CCU. */ -void __init kona_dt_ccu_setup(struct device_node *node, - int (*ccu_clks_setup)(struct ccu_data *)) +void __init kona_dt_ccu_setup(struct ccu_data *ccu, + struct device_node *node) { - struct ccu_data *ccu; struct resource res = { 0 }; resource_size_t range; + unsigned int i; int ret; - ccu = kzalloc(sizeof(*ccu), GFP_KERNEL); - if (ccu) - ccu->name = kstrdup(node->name, GFP_KERNEL); - if (!ccu || !ccu->name) { - pr_err("%s: unable to allocate CCU struct for %s\n", - __func__, node->name); - kfree(ccu); + if (ccu->clk_data.clk_num) { + size_t size; - return; + size = ccu->clk_data.clk_num * sizeof(*ccu->clk_data.clks); + ccu->clk_data.clks = kzalloc(size, GFP_KERNEL); + if (!ccu->clk_data.clks) { + pr_err("%s: unable to allocate %u clocks for %s\n", + __func__, ccu->clk_data.clk_num, node->name); + return; + } } ret = of_address_to_resource(node, 0, &res); @@ -735,24 +834,33 @@ void __init kona_dt_ccu_setup(struct device_node *node, } ccu->range = (u32)range; + + if (!ccu_data_valid(ccu)) { + pr_err("%s: ccu data not valid for %s\n", __func__, node->name); + goto out_err; + } + ccu->base = ioremap(res.start, ccu->range); if (!ccu->base) { pr_err("%s: unable to map CCU registers for %s\n", __func__, node->name); goto out_err; } - - spin_lock_init(&ccu->lock); - INIT_LIST_HEAD(&ccu->links); ccu->node = of_node_get(node); - list_add_tail(&ccu->links, &ccu_list); - /* Set up clocks array (in ccu->data) */ - if (ccu_clks_setup(ccu)) - goto out_err; + /* + * Set up each defined kona clock and save the result in + * the clock framework clock array (in ccu->data). Then + * register as a provider for these clocks. + */ + for (i = 0; i < ccu->clk_data.clk_num; i++) { + if (!ccu->kona_clks[i].ccu) + continue; + ccu->clk_data.clks[i] = kona_clk_setup(&ccu->kona_clks[i]); + } - ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->data); + ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->clk_data); if (ret) { pr_err("%s: error adding ccu %s as provider (%d)\n", __func__, node->name, ret); diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index e3d339e08309f6..d603c4e22fca0c 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c @@ -16,6 +16,14 @@ #include +/* + * "Policies" affect the frequencies of bus clocks provided by a + * CCU. (I believe these polices are named "Deep Sleep", "Economy", + * "Normal", and "Turbo".) A lower policy number has lower power + * consumption, and policy 2 is the default. + */ +#define CCU_POLICY_COUNT 4 + #define CCU_ACCESS_PASSWORD 0xA5A500 #define CLK_GATE_DELAY_LOOP 2000 @@ -61,7 +69,7 @@ u64 do_div_round_closest(u64 dividend, unsigned long divisor) /* Convert a divider into the scaled divisor value it represents. */ static inline u64 scaled_div_value(struct bcm_clk_div *div, u32 reg_div) { - return (u64)reg_div + ((u64)1 << div->frac_width); + return (u64)reg_div + ((u64)1 << div->u.s.frac_width); } /* @@ -77,7 +85,7 @@ u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, u32 billionths) BUG_ON(billionths >= BILLION); combined = (u64)div_value * BILLION + billionths; - combined <<= div->frac_width; + combined <<= div->u.s.frac_width; return do_div_round_closest(combined, BILLION); } @@ -87,7 +95,7 @@ static inline u64 scaled_div_min(struct bcm_clk_div *div) { if (divider_is_fixed(div)) - return (u64)div->fixed; + return (u64)div->u.fixed; return scaled_div_value(div, 0); } @@ -98,9 +106,9 @@ u64 scaled_div_max(struct bcm_clk_div *div) u32 reg_div; if (divider_is_fixed(div)) - return (u64)div->fixed; + return (u64)div->u.fixed; - reg_div = ((u32)1 << div->width) - 1; + reg_div = ((u32)1 << div->u.s.width) - 1; return scaled_div_value(div, reg_div); } @@ -115,7 +123,7 @@ divider(struct bcm_clk_div *div, u64 scaled_div) BUG_ON(scaled_div < scaled_div_min(div)); BUG_ON(scaled_div > scaled_div_max(div)); - return (u32)(scaled_div - ((u64)1 << div->frac_width)); + return (u32)(scaled_div - ((u64)1 << div->u.s.frac_width)); } /* Return a rate scaled for use when dividing by a scaled divisor. */ @@ -125,7 +133,7 @@ scale_rate(struct bcm_clk_div *div, u32 rate) if (divider_is_fixed(div)) return (u64)rate; - return (u64)rate << div->frac_width; + return (u64)rate << div->u.s.frac_width; } /* CCU access */ @@ -207,9 +215,154 @@ __ccu_wait_bit(struct ccu_data *ccu, u32 reg_offset, u32 bit, bool want) return true; udelay(1); } + pr_warn("%s: %s/0x%04x bit %u was never %s\n", __func__, + ccu->name, reg_offset, bit, want ? "set" : "clear"); + return false; } +/* Policy operations */ + +static bool __ccu_policy_engine_start(struct ccu_data *ccu, bool sync) +{ + struct bcm_policy_ctl *control = &ccu->policy.control; + u32 offset; + u32 go_bit; + u32 mask; + bool ret; + + /* If we don't need to control policy for this CCU, we're done. */ + if (!policy_ctl_exists(control)) + return true; + + offset = control->offset; + go_bit = control->go_bit; + + /* Ensure we're not busy before we start */ + ret = __ccu_wait_bit(ccu, offset, go_bit, false); + if (!ret) { + pr_err("%s: ccu %s policy engine wouldn't go idle\n", + __func__, ccu->name); + return false; + } + + /* + * If it's a synchronous request, we'll wait for the voltage + * and frequency of the active load to stabilize before + * returning. To do this we select the active load by + * setting the ATL bit. + * + * An asynchronous request instead ramps the voltage in the + * background, and when that process stabilizes, the target + * load is copied to the active load and the CCU frequency + * is switched. We do this by selecting the target load + * (ATL bit clear) and setting the request auto-copy (AC bit + * set). + * + * Note, we do NOT read-modify-write this register. + */ + mask = (u32)1 << go_bit; + if (sync) + mask |= 1 << control->atl_bit; + else + mask |= 1 << control->ac_bit; + __ccu_write(ccu, offset, mask); + + /* Wait for indication that operation is complete. */ + ret = __ccu_wait_bit(ccu, offset, go_bit, false); + if (!ret) + pr_err("%s: ccu %s policy engine never started\n", + __func__, ccu->name); + + return ret; +} + +static bool __ccu_policy_engine_stop(struct ccu_data *ccu) +{ + struct bcm_lvm_en *enable = &ccu->policy.enable; + u32 offset; + u32 enable_bit; + bool ret; + + /* If we don't need to control policy for this CCU, we're done. */ + if (!policy_lvm_en_exists(enable)) + return true; + + /* Ensure we're not busy before we start */ + offset = enable->offset; + enable_bit = enable->bit; + ret = __ccu_wait_bit(ccu, offset, enable_bit, false); + if (!ret) { + pr_err("%s: ccu %s policy engine already stopped\n", + __func__, ccu->name); + return false; + } + + /* Now set the bit to stop the engine (NO read-modify-write) */ + __ccu_write(ccu, offset, (u32)1 << enable_bit); + + /* Wait for indication that it has stopped. */ + ret = __ccu_wait_bit(ccu, offset, enable_bit, false); + if (!ret) + pr_err("%s: ccu %s policy engine never stopped\n", + __func__, ccu->name); + + return ret; +} + +/* + * A CCU has four operating conditions ("policies"), and some clocks + * can be disabled or enabled based on which policy is currently in + * effect. Such clocks have a bit in a "policy mask" register for + * each policy indicating whether the clock is enabled for that + * policy or not. The bit position for a clock is the same for all + * four registers, and the 32-bit registers are at consecutive + * addresses. + */ +static bool policy_init(struct ccu_data *ccu, struct bcm_clk_policy *policy) +{ + u32 offset; + u32 mask; + int i; + bool ret; + + if (!policy_exists(policy)) + return true; + + /* + * We need to stop the CCU policy engine to allow update + * of our policy bits. + */ + if (!__ccu_policy_engine_stop(ccu)) { + pr_err("%s: unable to stop CCU %s policy engine\n", + __func__, ccu->name); + return false; + } + + /* + * For now, if a clock defines its policy bit we just mark + * it "enabled" for all four policies. + */ + offset = policy->offset; + mask = (u32)1 << policy->bit; + for (i = 0; i < CCU_POLICY_COUNT; i++) { + u32 reg_val; + + reg_val = __ccu_read(ccu, offset); + reg_val |= mask; + __ccu_write(ccu, offset, reg_val); + offset += sizeof(u32); + } + + /* We're done updating; fire up the policy engine again. */ + ret = __ccu_policy_engine_start(ccu, true); + if (!ret) + pr_err("%s: unable to restart CCU %s policy engine\n", + __func__, ccu->name); + + return ret; +} + /* Gate operations */ /* Determine whether a clock is gated. CCU lock must be held. */ @@ -374,6 +527,35 @@ static int clk_gate(struct ccu_data *ccu, const char *name, return -EIO; } +/* Hysteresis operations */ + +/* + * If a clock gate requires a turn-off delay it will have + * "hysteresis" register bits defined. The first, if set, enables + * the delay; and if enabled, the second bit determines whether the + * delay is "low" or "high" (1 means high). For now, if it's + * defined for a clock, we set it. + */ +static bool hyst_init(struct ccu_data *ccu, struct bcm_clk_hyst *hyst) +{ + u32 offset; + u32 reg_val; + u32 mask; + + if (!hyst_exists(hyst)) + return true; + + offset = hyst->offset; + mask = (u32)1 << hyst->en_bit; + mask |= (u32)1 << hyst->val_bit; + + reg_val = __ccu_read(ccu, offset); + reg_val |= mask; + __ccu_write(ccu, offset, reg_val); + + return true; +} + /* Trigger operations */ /* @@ -398,14 +580,14 @@ static u64 divider_read_scaled(struct ccu_data *ccu, struct bcm_clk_div *div) u32 reg_div; if (divider_is_fixed(div)) - return (u64)div->fixed; + return (u64)div->u.fixed; flags = ccu_lock(ccu); - reg_val = __ccu_read(ccu, div->offset); + reg_val = __ccu_read(ccu, div->u.s.offset); ccu_unlock(ccu, flags); /* Extract the full divider field from the register value */ - reg_div = bitfield_extract(reg_val, div->shift, div->width); + reg_div = bitfield_extract(reg_val, div->u.s.shift, div->u.s.width); /* Return the scaled divisor value it represents */ return scaled_div_value(div, reg_div); @@ -433,16 +615,17 @@ static int __div_commit(struct ccu_data *ccu, struct bcm_clk_gate *gate, * state was defined in the device tree, we just find out * what its current value is rather than updating it. */ - if (div->scaled_div == BAD_SCALED_DIV_VALUE) { - reg_val = __ccu_read(ccu, div->offset); - reg_div = bitfield_extract(reg_val, div->shift, div->width); - div->scaled_div = scaled_div_value(div, reg_div); + if (div->u.s.scaled_div == BAD_SCALED_DIV_VALUE) { + reg_val = __ccu_read(ccu, div->u.s.offset); + reg_div = bitfield_extract(reg_val, div->u.s.shift, + div->u.s.width); + div->u.s.scaled_div = scaled_div_value(div, reg_div); return 0; } /* Convert the scaled divisor to the value we need to record */ - reg_div = divider(div, div->scaled_div); + reg_div = divider(div, div->u.s.scaled_div); /* Clock needs to be enabled before changing the rate */ enabled = __is_clk_gate_enabled(ccu, gate); @@ -452,9 +635,10 @@ static int __div_commit(struct ccu_data *ccu, struct bcm_clk_gate *gate, } /* Replace the divider value and record the result */ - reg_val = __ccu_read(ccu, div->offset); - reg_val = bitfield_replace(reg_val, div->shift, div->width, reg_div); - __ccu_write(ccu, div->offset, reg_val); + reg_val = __ccu_read(ccu, div->u.s.offset); + reg_val = bitfield_replace(reg_val, div->u.s.shift, div->u.s.width, + reg_div); + __ccu_write(ccu, div->u.s.offset, reg_val); /* If the trigger fails we still want to disable the gate */ if (!__clk_trigger(ccu, trig)) @@ -490,11 +674,11 @@ static int divider_write(struct ccu_data *ccu, struct bcm_clk_gate *gate, BUG_ON(divider_is_fixed(div)); - previous = div->scaled_div; + previous = div->u.s.scaled_div; if (previous == scaled_div) return 0; /* No change */ - div->scaled_div = scaled_div; + div->u.s.scaled_div = scaled_div; flags = ccu_lock(ccu); __ccu_write_enable(ccu); @@ -505,7 +689,7 @@ static int divider_write(struct ccu_data *ccu, struct bcm_clk_gate *gate, ccu_unlock(ccu, flags); if (ret) - div->scaled_div = previous; /* Revert the change */ + div->u.s.scaled_div = previous; /* Revert the change */ return ret; @@ -802,23 +986,23 @@ static int selector_write(struct ccu_data *ccu, struct bcm_clk_gate *gate, static int kona_peri_clk_enable(struct clk_hw *hw) { struct kona_clk *bcm_clk = to_kona_clk(hw); - struct bcm_clk_gate *gate = &bcm_clk->peri->gate; + struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate; - return clk_gate(bcm_clk->ccu, bcm_clk->name, gate, true); + return clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, true); } static void kona_peri_clk_disable(struct clk_hw *hw) { struct kona_clk *bcm_clk = to_kona_clk(hw); - struct bcm_clk_gate *gate = &bcm_clk->peri->gate; + struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate; - (void)clk_gate(bcm_clk->ccu, bcm_clk->name, gate, false); + (void)clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, false); } static int kona_peri_clk_is_enabled(struct clk_hw *hw) { struct kona_clk *bcm_clk = to_kona_clk(hw); - struct bcm_clk_gate *gate = &bcm_clk->peri->gate; + struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate; return is_clk_gate_enabled(bcm_clk->ccu, gate) ? 1 : 0; } @@ -827,7 +1011,7 @@ static unsigned long kona_peri_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct kona_clk *bcm_clk = to_kona_clk(hw); - struct peri_clk_data *data = bcm_clk->peri; + struct peri_clk_data *data = bcm_clk->u.peri; return clk_recalc_rate(bcm_clk->ccu, &data->div, &data->pre_div, parent_rate); @@ -837,20 +1021,20 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { struct kona_clk *bcm_clk = to_kona_clk(hw); - struct bcm_clk_div *div = &bcm_clk->peri->div; + struct bcm_clk_div *div = &bcm_clk->u.peri->div; if (!divider_exists(div)) return __clk_get_rate(hw->clk); /* Quietly avoid a zero rate */ - return round_rate(bcm_clk->ccu, div, &bcm_clk->peri->pre_div, + return round_rate(bcm_clk->ccu, div, &bcm_clk->u.peri->pre_div, rate ? rate : 1, *parent_rate, NULL); } static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) { struct kona_clk *bcm_clk = to_kona_clk(hw); - struct peri_clk_data *data = bcm_clk->peri; + struct peri_clk_data *data = bcm_clk->u.peri; struct bcm_clk_sel *sel = &data->sel; struct bcm_clk_trig *trig; int ret; @@ -870,12 +1054,13 @@ static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) ret = selector_write(bcm_clk->ccu, &data->gate, sel, trig, index); if (ret == -ENXIO) { - pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name); + pr_err("%s: gating failure for %s\n", __func__, + bcm_clk->init_data.name); ret = -EIO; /* Don't proliferate weird errors */ } else if (ret == -EIO) { pr_err("%s: %strigger failed for %s\n", __func__, trig == &data->pre_trig ? "pre-" : "", - bcm_clk->name); + bcm_clk->init_data.name); } return ret; @@ -884,7 +1069,7 @@ static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) static u8 kona_peri_clk_get_parent(struct clk_hw *hw) { struct kona_clk *bcm_clk = to_kona_clk(hw); - struct peri_clk_data *data = bcm_clk->peri; + struct peri_clk_data *data = bcm_clk->u.peri; u8 index; index = selector_read_index(bcm_clk->ccu, &data->sel); @@ -897,7 +1082,7 @@ static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct kona_clk *bcm_clk = to_kona_clk(hw); - struct peri_clk_data *data = bcm_clk->peri; + struct peri_clk_data *data = bcm_clk->u.peri; struct bcm_clk_div *div = &data->div; u64 scaled_div = 0; int ret; @@ -934,10 +1119,12 @@ static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate, ret = divider_write(bcm_clk->ccu, &data->gate, &data->div, &data->trig, scaled_div); if (ret == -ENXIO) { - pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name); + pr_err("%s: gating failure for %s\n", __func__, + bcm_clk->init_data.name); ret = -EIO; /* Don't proliferate weird errors */ } else if (ret == -EIO) { - pr_err("%s: trigger failed for %s\n", __func__, bcm_clk->name); + pr_err("%s: trigger failed for %s\n", __func__, + bcm_clk->init_data.name); } return ret; @@ -958,16 +1145,25 @@ struct clk_ops kona_peri_clk_ops = { static bool __peri_clk_init(struct kona_clk *bcm_clk) { struct ccu_data *ccu = bcm_clk->ccu; - struct peri_clk_data *peri = bcm_clk->peri; - const char *name = bcm_clk->name; + struct peri_clk_data *peri = bcm_clk->u.peri; + const char *name = bcm_clk->init_data.name; struct bcm_clk_trig *trig; BUG_ON(bcm_clk->type != bcm_clk_peri); + if (!policy_init(ccu, &peri->policy)) { + pr_err("%s: error initializing policy for %s\n", + __func__, name); + return false; + } if (!gate_init(ccu, &peri->gate)) { pr_err("%s: error initializing gate for %s\n", __func__, name); return false; } + if (!hyst_init(ccu, &peri->hyst)) { + pr_err("%s: error initializing hyst for %s\n", __func__, name); + return false; + } if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) { pr_err("%s: error initializing divider for %s\n", __func__, name); @@ -1012,13 +1208,13 @@ bool __init kona_ccu_init(struct ccu_data *ccu) { unsigned long flags; unsigned int which; - struct clk **clks = ccu->data.clks; + struct clk **clks = ccu->clk_data.clks; bool success = true; flags = ccu_lock(ccu); __ccu_write_enable(ccu); - for (which = 0; which < ccu->data.clk_num; which++) { + for (which = 0; which < ccu->clk_data.clk_num; which++) { struct kona_clk *bcm_clk; if (!clks[which]) diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h index 5e139adc3dc590..2537b3072910a1 100644 --- a/drivers/clk/bcm/clk-kona.h +++ b/drivers/clk/bcm/clk-kona.h @@ -43,8 +43,14 @@ #define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag)) #define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag))) +/* CCU field state tests */ + +#define ccu_policy_exists(ccu_policy) ((ccu_policy)->enable.offset != 0) + /* Clock field state tests */ +#define policy_exists(policy) ((policy)->offset != 0) + #define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS) #define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED) #define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW) @@ -54,14 +60,19 @@ #define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED) +#define hyst_exists(hyst) ((hyst)->offset != 0) + #define divider_exists(div) FLAG_TEST(div, DIV, EXISTS) #define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED) #define divider_has_fraction(div) (!divider_is_fixed(div) && \ - (div)->frac_width > 0) + (div)->u.s.frac_width > 0) #define selector_exists(sel) ((sel)->width != 0) #define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS) +#define policy_lvm_en_exists(enable) ((enable)->offset != 0) +#define policy_ctl_exists(control) ((control)->offset != 0) + /* Clock type, used to tell common block what it's part of */ enum bcm_clk_type { bcm_clk_none, /* undefined clock type */ @@ -71,25 +82,26 @@ enum bcm_clk_type { }; /* - * Each CCU defines a mapped area of memory containing registers - * used to manage clocks implemented by the CCU. Access to memory - * within the CCU's space is serialized by a spinlock. Before any - * (other) address can be written, a special access "password" value - * must be written to its WR_ACCESS register (located at the base - * address of the range). We keep track of the name of each CCU as - * it is set up, and maintain them in a list. + * CCU policy control for clocks. Clocks can be enabled or disabled + * based on the CCU policy in effect. One bit in each policy mask + * register (one per CCU policy) represents whether the clock is + * enabled when that policy is effect or not. The CCU policy engine + * must be stopped to update these bits, and must be restarted again + * afterward. */ -struct ccu_data { - void __iomem *base; /* base of mapped address space */ - spinlock_t lock; /* serialization lock */ - bool write_enabled; /* write access is currently enabled */ - struct list_head links; /* for ccu_list */ - struct device_node *node; - struct clk_onecell_data data; - const char *name; - u32 range; /* byte range of address space */ +struct bcm_clk_policy { + u32 offset; /* first policy mask register offset */ + u32 bit; /* bit used in all mask registers */ }; +/* Policy initialization macro */ + +#define POLICY(_offset, _bit) \ + { \ + .offset = (_offset), \ + .bit = (_bit), \ + } + /* * Gating control and status is managed by a 32-bit gate register. * @@ -195,6 +207,22 @@ struct bcm_clk_gate { .flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \ } +/* Gate hysteresis for clocks */ +struct bcm_clk_hyst { + u32 offset; /* hyst register offset (normally CLKGATE) */ + u32 en_bit; /* bit used to enable hysteresis */ + u32 val_bit; /* if enabled: 0 = low delay; 1 = high delay */ +}; + +/* Hysteresis initialization macro */ + +#define HYST(_offset, _en_bit, _val_bit) \ + { \ + .offset = (_offset), \ + .en_bit = (_en_bit), \ + .val_bit = (_val_bit), \ + } + /* * Each clock can have zero, one, or two dividers which change the * output rate of the clock. Each divider can be either fixed or @@ -244,9 +272,9 @@ struct bcm_clk_div { u32 frac_width; /* field fraction width */ u64 scaled_div; /* scaled divider value */ - }; + } s; u32 fixed; /* non-zero fixed divider value */ - }; + } u; u32 flags; /* BCM_CLK_DIV_FLAGS_* below */ }; @@ -263,28 +291,28 @@ struct bcm_clk_div { /* A fixed (non-zero) divider */ #define FIXED_DIVIDER(_value) \ { \ - .fixed = (_value), \ + .u.fixed = (_value), \ .flags = FLAG(DIV, EXISTS)|FLAG(DIV, FIXED), \ } /* A divider with an integral divisor */ #define DIVIDER(_offset, _shift, _width) \ { \ - .offset = (_offset), \ - .shift = (_shift), \ - .width = (_width), \ - .scaled_div = BAD_SCALED_DIV_VALUE, \ + .u.s.offset = (_offset), \ + .u.s.shift = (_shift), \ + .u.s.width = (_width), \ + .u.s.scaled_div = BAD_SCALED_DIV_VALUE, \ .flags = FLAG(DIV, EXISTS), \ } /* A divider whose divisor has an integer and fractional part */ #define FRAC_DIVIDER(_offset, _shift, _width, _frac_width) \ { \ - .offset = (_offset), \ - .shift = (_shift), \ - .width = (_width), \ - .frac_width = (_frac_width), \ - .scaled_div = BAD_SCALED_DIV_VALUE, \ + .u.s.offset = (_offset), \ + .u.s.shift = (_shift), \ + .u.s.width = (_width), \ + .u.s.frac_width = (_frac_width), \ + .u.s.scaled_div = BAD_SCALED_DIV_VALUE, \ .flags = FLAG(DIV, EXISTS), \ } @@ -360,7 +388,9 @@ struct bcm_clk_trig { } struct peri_clk_data { + struct bcm_clk_policy policy; struct bcm_clk_gate gate; + struct bcm_clk_hyst hyst; struct bcm_clk_trig pre_trig; struct bcm_clk_div pre_div; struct bcm_clk_trig trig; @@ -373,26 +403,103 @@ struct peri_clk_data { struct kona_clk { struct clk_hw hw; - struct clk_init_data init_data; - const char *name; /* name of this clock */ + struct clk_init_data init_data; /* includes name of this clock */ struct ccu_data *ccu; /* ccu this clock is associated with */ enum bcm_clk_type type; union { void *data; struct peri_clk_data *peri; - }; + } u; }; #define to_kona_clk(_hw) \ container_of(_hw, struct kona_clk, hw) -/* Exported globals */ +/* Initialization macro for an entry in a CCU's kona_clks[] array. */ +#define KONA_CLK(_ccu_name, _clk_name, _type) \ + { \ + .init_data = { \ + .name = #_clk_name, \ + .ops = &kona_ ## _type ## _clk_ops, \ + }, \ + .ccu = &_ccu_name ## _ccu_data, \ + .type = bcm_clk_ ## _type, \ + .u.data = &_clk_name ## _data, \ + } +#define LAST_KONA_CLK { .type = bcm_clk_none } -extern struct clk_ops kona_peri_clk_ops; +/* + * CCU policy control. To enable software update of the policy + * tables the CCU policy engine must be stopped by setting the + * software update enable bit (LVM_EN). After an update the engine + * is restarted using the GO bit and either the GO_ATL or GO_AC bit. + */ +struct bcm_lvm_en { + u32 offset; /* LVM_EN register offset */ + u32 bit; /* POLICY_CONFIG_EN bit in register */ +}; -/* Help functions */ +/* Policy enable initialization macro */ +#define CCU_LVM_EN(_offset, _bit) \ + { \ + .offset = (_offset), \ + .bit = (_bit), \ + } + +struct bcm_policy_ctl { + u32 offset; /* POLICY_CTL register offset */ + u32 go_bit; + u32 atl_bit; /* GO, GO_ATL, and GO_AC bits */ + u32 ac_bit; +}; -#define PERI_CLK_SETUP(clks, ccu, id, name) \ - clks[id] = kona_clk_setup(ccu, #name, bcm_clk_peri, &name ## _data) +/* Policy control initialization macro */ +#define CCU_POLICY_CTL(_offset, _go_bit, _ac_bit, _atl_bit) \ + { \ + .offset = (_offset), \ + .go_bit = (_go_bit), \ + .ac_bit = (_ac_bit), \ + .atl_bit = (_atl_bit), \ + } + +struct ccu_policy { + struct bcm_lvm_en enable; + struct bcm_policy_ctl control; +}; + +/* + * Each CCU defines a mapped area of memory containing registers + * used to manage clocks implemented by the CCU. Access to memory + * within the CCU's space is serialized by a spinlock. Before any + * (other) address can be written, a special access "password" value + * must be written to its WR_ACCESS register (located at the base + * address of the range). We keep track of the name of each CCU as + * it is set up, and maintain them in a list. + */ +struct ccu_data { + void __iomem *base; /* base of mapped address space */ + spinlock_t lock; /* serialization lock */ + bool write_enabled; /* write access is currently enabled */ + struct ccu_policy policy; + struct list_head links; /* for ccu_list */ + struct device_node *node; + struct clk_onecell_data clk_data; + const char *name; + u32 range; /* byte range of address space */ + struct kona_clk kona_clks[]; /* must be last */ +}; + +/* Initialization for common fields in a Kona ccu_data structure */ +#define KONA_CCU_COMMON(_prefix, _name, _ccuname) \ + .name = #_name "_ccu", \ + .lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \ + .links = LIST_HEAD_INIT(_name ## _ccu_data.links), \ + .clk_data = { \ + .clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT, \ + } + +/* Exported globals */ + +extern struct clk_ops kona_peri_clk_ops; /* Externally visible functions */ @@ -401,10 +508,9 @@ extern u64 scaled_div_max(struct bcm_clk_div *div); extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, u32 billionths); -extern struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name, - enum bcm_clk_type type, void *data); -extern void __init kona_dt_ccu_setup(struct device_node *node, - int (*ccu_clks_setup)(struct ccu_data *)); +extern struct clk *kona_clk_setup(struct kona_clk *bcm_clk); +extern void __init kona_dt_ccu_setup(struct ccu_data *ccu, + struct device_node *node); extern bool __init kona_ccu_init(struct ccu_data *ccu); #endif /* _CLK_KONA_H */ diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index ec22112e569f7f..b3c83966be1823 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -43,6 +43,17 @@ static unsigned int _get_table_maxdiv(const struct clk_div_table *table) return maxdiv; } +static unsigned int _get_table_mindiv(const struct clk_div_table *table) +{ + unsigned int mindiv = UINT_MAX; + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div < mindiv) + mindiv = clkt->div; + return mindiv; +} + static unsigned int _get_maxdiv(struct clk_divider *divider) { if (divider->flags & CLK_DIVIDER_ONE_BASED) @@ -144,6 +155,103 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div) return true; } +static int _round_up_table(const struct clk_div_table *table, int div) +{ + const struct clk_div_table *clkt; + int up = _get_table_maxdiv(table); + + for (clkt = table; clkt->div; clkt++) { + if (clkt->div == div) + return clkt->div; + else if (clkt->div < div) + continue; + + if ((clkt->div - div) < (up - div)) + up = clkt->div; + } + + return up; +} + +static int _round_down_table(const struct clk_div_table *table, int div) +{ + const struct clk_div_table *clkt; + int down = _get_table_mindiv(table); + + for (clkt = table; clkt->div; clkt++) { + if (clkt->div == div) + return clkt->div; + else if (clkt->div > div) + continue; + + if ((div - clkt->div) < (div - down)) + down = clkt->div; + } + + return down; +} + +static int _div_round_up(struct clk_divider *divider, + unsigned long parent_rate, unsigned long rate) +{ + int div = DIV_ROUND_UP(parent_rate, rate); + + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + div = __roundup_pow_of_two(div); + if (divider->table) + div = _round_up_table(divider->table, div); + + return div; +} + +static int _div_round_closest(struct clk_divider *divider, + unsigned long parent_rate, unsigned long rate) +{ + int up, down, div; + + up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate); + + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) { + up = __roundup_pow_of_two(div); + down = __rounddown_pow_of_two(div); + } else if (divider->table) { + up = _round_up_table(divider->table, div); + down = _round_down_table(divider->table, div); + } + + return (up - div) <= (div - down) ? up : down; +} + +static int _div_round(struct clk_divider *divider, unsigned long parent_rate, + unsigned long rate) +{ + if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST) + return _div_round_closest(divider, parent_rate, rate); + + return _div_round_up(divider, parent_rate, rate); +} + +static bool _is_best_div(struct clk_divider *divider, + int rate, int now, int best) +{ + if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST) + return abs(rate - now) < abs(rate - best); + + return now <= rate && now > best; +} + +static int _next_div(struct clk_divider *divider, int div) +{ + div++; + + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + return __roundup_pow_of_two(div); + if (divider->table) + return _round_up_table(divider->table, div); + + return div; +} + static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate) { @@ -159,7 +267,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { parent_rate = *best_parent_rate; - bestdiv = DIV_ROUND_UP(parent_rate, rate); + bestdiv = _div_round(divider, parent_rate, rate); bestdiv = bestdiv == 0 ? 1 : bestdiv; bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; return bestdiv; @@ -171,7 +279,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, */ maxdiv = min(ULONG_MAX / rate, maxdiv); - for (i = 1; i <= maxdiv; i++) { + for (i = 1; i <= maxdiv; i = _next_div(divider, i)) { if (!_is_valid_div(divider, i)) continue; if (rate * i == parent_rate_saved) { @@ -186,7 +294,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), MULT_ROUND_UP(rate, i)); now = DIV_ROUND_UP(parent_rate, i); - if (now <= rate && now > best) { + if (_is_best_div(divider, rate, now, best)) { bestdiv = i; best = now; *best_parent_rate = parent_rate; @@ -219,6 +327,10 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, u32 val; div = DIV_ROUND_UP(parent_rate, rate); + + if (!_is_valid_div(divider, div)) + return -EINVAL; + value = _get_val(divider, div); if (value > div_mask(divider)) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index dff0373f53c1fb..4d562206d62f19 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -822,6 +822,9 @@ void __clk_unprepare(struct clk *clk) */ void clk_unprepare(struct clk *clk) { + if (IS_ERR_OR_NULL(clk)) + return; + clk_prepare_lock(); __clk_unprepare(clk); clk_prepare_unlock(); @@ -883,9 +886,6 @@ static void __clk_disable(struct clk *clk) if (!clk) return; - if (WARN_ON(IS_ERR(clk))) - return; - if (WARN_ON(clk->enable_count == 0)) return; @@ -914,6 +914,9 @@ void clk_disable(struct clk *clk) { unsigned long flags; + if (IS_ERR_OR_NULL(clk)) + return; + flags = clk_enable_lock(); __clk_disable(clk); clk_enable_unlock(flags); @@ -1115,6 +1118,13 @@ long clk_get_accuracy(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_get_accuracy); +static unsigned long clk_recalc(struct clk *clk, unsigned long parent_rate) +{ + if (clk->ops->recalc_rate) + return clk->ops->recalc_rate(clk->hw, parent_rate); + return parent_rate; +} + /** * __clk_recalc_rates * @clk: first clk in the subtree @@ -1140,10 +1150,7 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg) if (clk->parent) parent_rate = clk->parent->rate; - if (clk->ops->recalc_rate) - clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate); - else - clk->rate = parent_rate; + clk->rate = clk_recalc(clk, parent_rate); /* * ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE @@ -1334,10 +1341,7 @@ static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate) unsigned long new_rate; int ret = NOTIFY_DONE; - if (clk->ops->recalc_rate) - new_rate = clk->ops->recalc_rate(clk->hw, parent_rate); - else - new_rate = parent_rate; + new_rate = clk_recalc(clk, parent_rate); /* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */ if (clk->notifier_count) @@ -1373,10 +1377,7 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate, new_parent->new_child = clk; hlist_for_each_entry(child, &clk->children, child_node) { - if (child->ops->recalc_rate) - child->new_rate = child->ops->recalc_rate(child->hw, new_rate); - else - child->new_rate = new_rate; + child->new_rate = clk_recalc(child, new_rate); clk_calc_subtree(child, child->new_rate, NULL, 0); } } @@ -1524,10 +1525,7 @@ static void clk_change_rate(struct clk *clk) if (!skip_set_rate && clk->ops->set_rate) clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate); - if (clk->ops->recalc_rate) - clk->rate = clk->ops->recalc_rate(clk->hw, best_parent_rate); - else - clk->rate = best_parent_rate; + clk->rate = clk_recalc(clk, best_parent_rate); if (clk->notifier_count && old_rate != clk->rate) __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate); @@ -1716,9 +1714,6 @@ int clk_set_parent(struct clk *clk, struct clk *parent) if (!clk) return 0; - if (!clk->ops) - return -EINVAL; - /* verify ops for for multi-parent clks */ if ((clk->num_parents > 1) && (!clk->ops->set_parent)) return -ENOSYS; @@ -1984,9 +1979,28 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw) } EXPORT_SYMBOL_GPL(__clk_register); -static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk) +/** + * clk_register - allocate a new clock, register it and return an opaque cookie + * @dev: device that is registering this clock + * @hw: link to hardware-specific clock data + * + * clk_register is the primary interface for populating the clock tree with new + * clock nodes. It returns a pointer to the newly allocated struct clk which + * cannot be dereferenced by driver code but may be used in conjuction with the + * rest of the clock API. In the event of an error clk_register will return an + * error code; drivers must test for an error code after calling clk_register. + */ +struct clk *clk_register(struct device *dev, struct clk_hw *hw) { int i, ret; + struct clk *clk; + + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + if (!clk) { + pr_err("%s: could not allocate clk\n", __func__); + ret = -ENOMEM; + goto fail_out; + } clk->name = kstrdup(hw->init->name, GFP_KERNEL); if (!clk->name) { @@ -2026,7 +2040,7 @@ static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk) ret = __clk_init(dev, clk); if (!ret) - return 0; + return clk; fail_parent_names_copy: while (--i >= 0) @@ -2035,36 +2049,6 @@ static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk) fail_parent_names: kfree(clk->name); fail_name: - return ret; -} - -/** - * clk_register - allocate a new clock, register it and return an opaque cookie - * @dev: device that is registering this clock - * @hw: link to hardware-specific clock data - * - * clk_register is the primary interface for populating the clock tree with new - * clock nodes. It returns a pointer to the newly allocated struct clk which - * cannot be dereferenced by driver code but may be used in conjuction with the - * rest of the clock API. In the event of an error clk_register will return an - * error code; drivers must test for an error code after calling clk_register. - */ -struct clk *clk_register(struct device *dev, struct clk_hw *hw) -{ - int ret; - struct clk *clk; - - clk = kzalloc(sizeof(*clk), GFP_KERNEL); - if (!clk) { - pr_err("%s: could not allocate clk\n", __func__); - ret = -ENOMEM; - goto fail_out; - } - - ret = _clk_register(dev, hw, clk); - if (!ret) - return clk; - kfree(clk); fail_out: return ERR_PTR(ret); @@ -2151,9 +2135,10 @@ void clk_unregister(struct clk *clk) if (!hlist_empty(&clk->children)) { struct clk *child; + struct hlist_node *t; /* Reparent all children to the orphan list. */ - hlist_for_each_entry(child, &clk->children, child_node) + hlist_for_each_entry_safe(child, t, &clk->children, child_node) clk_set_parent(child, NULL); } @@ -2173,7 +2158,7 @@ EXPORT_SYMBOL_GPL(clk_unregister); static void devm_clk_release(struct device *dev, void *res) { - clk_unregister(res); + clk_unregister(*(struct clk **)res); } /** @@ -2188,18 +2173,18 @@ static void devm_clk_release(struct device *dev, void *res) struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw) { struct clk *clk; - int ret; + struct clk **clkp; - clk = devres_alloc(devm_clk_release, sizeof(*clk), GFP_KERNEL); - if (!clk) + clkp = devres_alloc(devm_clk_release, sizeof(*clkp), GFP_KERNEL); + if (!clkp) return ERR_PTR(-ENOMEM); - ret = _clk_register(dev, hw, clk); - if (!ret) { - devres_add(dev, clk); + clk = clk_register(dev, hw); + if (!IS_ERR(clk)) { + *clkp = clk; + devres_add(dev, clkp); } else { - devres_free(clk); - clk = ERR_PTR(ret); + devres_free(clkp); } return clk; diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig index 693f7be129f12a..3b34dba9178d9c 100644 --- a/drivers/clk/mvebu/Kconfig +++ b/drivers/clk/mvebu/Kconfig @@ -34,3 +34,7 @@ config DOVE_CLK config KIRKWOOD_CLK bool select MVEBU_CLK_COMMON + +config ORION_CLK + bool + select MVEBU_CLK_COMMON diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index 4c66162fb0b440..a9a56fc0190158 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o obj-$(CONFIG_DOVE_CLK) += dove.o obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o +obj-$(CONFIG_ORION_CLK) += orion.o diff --git a/drivers/clk/mvebu/orion.c b/drivers/clk/mvebu/orion.c new file mode 100644 index 00000000000000..fd129566c1cef8 --- /dev/null +++ b/drivers/clk/mvebu/orion.c @@ -0,0 +1,210 @@ +/* + * Marvell Orion SoC clocks + * + * Copyright (C) 2014 Thomas Petazzoni + * + * Thomas Petazzoni + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include "common.h" + +static const struct coreclk_ratio orion_coreclk_ratios[] __initconst = { + { .id = 0, .name = "ddrclk", } +}; + +/* + * Orion 5182 + */ + +#define SAR_MV88F5182_TCLK_FREQ 8 +#define SAR_MV88F5182_TCLK_FREQ_MASK 0x3 + +static u32 __init mv88f5182_get_tclk_freq(void __iomem *sar) +{ + u32 opt = (readl(sar) >> SAR_MV88F5182_TCLK_FREQ) & + SAR_MV88F5182_TCLK_FREQ_MASK; + if (opt == 1) + return 150000000; + else if (opt == 2) + return 166666667; + else + return 0; +} + +#define SAR_MV88F5182_CPU_FREQ 4 +#define SAR_MV88F5182_CPU_FREQ_MASK 0xf + +static u32 __init mv88f5182_get_cpu_freq(void __iomem *sar) +{ + u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) & + SAR_MV88F5182_CPU_FREQ_MASK; + if (opt == 0) + return 333333333; + else if (opt == 1 || opt == 2) + return 400000000; + else if (opt == 3) + return 500000000; + else + return 0; +} + +static void __init mv88f5182_get_clk_ratio(void __iomem *sar, int id, + int *mult, int *div) +{ + u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) & + SAR_MV88F5182_CPU_FREQ_MASK; + if (opt == 0 || opt == 1) { + *mult = 1; + *div = 2; + } else if (opt == 2 || opt == 3) { + *mult = 1; + *div = 3; + } else { + *mult = 0; + *div = 1; + } +} + +static const struct coreclk_soc_desc mv88f5182_coreclks = { + .get_tclk_freq = mv88f5182_get_tclk_freq, + .get_cpu_freq = mv88f5182_get_cpu_freq, + .get_clk_ratio = mv88f5182_get_clk_ratio, + .ratios = orion_coreclk_ratios, + .num_ratios = ARRAY_SIZE(orion_coreclk_ratios), +}; + +static void __init mv88f5182_clk_init(struct device_node *np) +{ + return mvebu_coreclk_setup(np, &mv88f5182_coreclks); +} + +CLK_OF_DECLARE(mv88f5182_clk, "marvell,mv88f5182-core-clock", mv88f5182_clk_init); + +/* + * Orion 5281 + */ + +static u32 __init mv88f5281_get_tclk_freq(void __iomem *sar) +{ + /* On 5281, tclk is always 166 Mhz */ + return 166666667; +} + +#define SAR_MV88F5281_CPU_FREQ 4 +#define SAR_MV88F5281_CPU_FREQ_MASK 0xf + +static u32 __init mv88f5281_get_cpu_freq(void __iomem *sar) +{ + u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) & + SAR_MV88F5281_CPU_FREQ_MASK; + if (opt == 1 || opt == 2) + return 400000000; + else if (opt == 3) + return 500000000; + else + return 0; +} + +static void __init mv88f5281_get_clk_ratio(void __iomem *sar, int id, + int *mult, int *div) +{ + u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) & + SAR_MV88F5281_CPU_FREQ_MASK; + if (opt == 1) { + *mult = 1; + *div = 2; + } else if (opt == 2 || opt == 3) { + *mult = 1; + *div = 3; + } else { + *mult = 0; + *div = 1; + } +} + +static const struct coreclk_soc_desc mv88f5281_coreclks = { + .get_tclk_freq = mv88f5281_get_tclk_freq, + .get_cpu_freq = mv88f5281_get_cpu_freq, + .get_clk_ratio = mv88f5281_get_clk_ratio, + .ratios = orion_coreclk_ratios, + .num_ratios = ARRAY_SIZE(orion_coreclk_ratios), +}; + +static void __init mv88f5281_clk_init(struct device_node *np) +{ + return mvebu_coreclk_setup(np, &mv88f5281_coreclks); +} + +CLK_OF_DECLARE(mv88f5281_clk, "marvell,mv88f5281-core-clock", mv88f5281_clk_init); + +/* + * Orion 6183 + */ + +#define SAR_MV88F6183_TCLK_FREQ 9 +#define SAR_MV88F6183_TCLK_FREQ_MASK 0x1 + +static u32 __init mv88f6183_get_tclk_freq(void __iomem *sar) +{ + u32 opt = (readl(sar) >> SAR_MV88F6183_TCLK_FREQ) & + SAR_MV88F6183_TCLK_FREQ_MASK; + if (opt == 0) + return 133333333; + else if (opt == 1) + return 166666667; + else + return 0; +} + +#define SAR_MV88F6183_CPU_FREQ 1 +#define SAR_MV88F6183_CPU_FREQ_MASK 0x3f + +static u32 __init mv88f6183_get_cpu_freq(void __iomem *sar) +{ + u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) & + SAR_MV88F6183_CPU_FREQ_MASK; + if (opt == 9) + return 333333333; + else if (opt == 17) + return 400000000; + else + return 0; +} + +static void __init mv88f6183_get_clk_ratio(void __iomem *sar, int id, + int *mult, int *div) +{ + u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) & + SAR_MV88F6183_CPU_FREQ_MASK; + if (opt == 9 || opt == 17) { + *mult = 1; + *div = 2; + } else { + *mult = 0; + *div = 1; + } +} + +static const struct coreclk_soc_desc mv88f6183_coreclks = { + .get_tclk_freq = mv88f6183_get_tclk_freq, + .get_cpu_freq = mv88f6183_get_cpu_freq, + .get_clk_ratio = mv88f6183_get_clk_ratio, + .ratios = orion_coreclk_ratios, + .num_ratios = ARRAY_SIZE(orion_coreclk_ratios), +}; + + +static void __init mv88f6183_clk_init(struct device_node *np) +{ + return mvebu_coreclk_setup(np, &mv88f6183_coreclks); +} + +CLK_OF_DECLARE(mv88f6183_clk, "marvell,mv88f6183-core-clock", mv88f6183_clk_init); diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 995bcfa021a442..7f696b7d442271 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -13,10 +13,10 @@ config MSM_GCC_8660 i2c, USB, SD/eMMC, etc. config MSM_GCC_8960 - tristate "MSM8960 Global Clock Controller" + tristate "APQ8064/MSM8960 Global Clock Controller" depends on COMMON_CLK_QCOM help - Support for the global clock controller on msm8960 devices. + Support for the global clock controller on apq8064/msm8960 devices. Say Y if you want to use peripheral devices such as UART, SPI, i2c, USB, SD/eMMC, SATA, PCIe, etc. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index f60db2ef1aee6a..689e05bf4f958d 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o +clk-qcom-y += common.o clk-qcom-y += clk-regmap.o clk-qcom-y += clk-pll.o clk-qcom-y += clk-rcg.o diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c new file mode 100644 index 00000000000000..86b45fba5f90cb --- /dev/null +++ b/drivers/clk/qcom/common.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "clk-regmap.h" +#include "reset.h" + +struct qcom_cc { + struct qcom_reset_controller reset; + struct clk_onecell_data data; + struct clk *clks[]; +}; + +int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc) +{ + void __iomem *base; + struct resource *res; + int i, ret; + struct device *dev = &pdev->dev; + struct clk *clk; + struct clk_onecell_data *data; + struct clk **clks; + struct regmap *regmap; + struct qcom_reset_controller *reset; + struct qcom_cc *cc; + size_t num_clks = desc->num_clks; + struct clk_regmap **rclks = desc->clks; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(dev, base, desc->config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, + GFP_KERNEL); + if (!cc) + return -ENOMEM; + + clks = cc->clks; + data = &cc->data; + data->clks = clks; + data->clk_num = num_clks; + + for (i = 0; i < num_clks; i++) { + if (!rclks[i]) + continue; + clk = devm_clk_register_regmap(dev, rclks[i]); + if (IS_ERR(clk)) + return PTR_ERR(clk); + clks[i] = clk; + } + + ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); + if (ret) + return ret; + + reset = &cc->reset; + reset->rcdev.of_node = dev->of_node; + reset->rcdev.ops = &qcom_reset_ops; + reset->rcdev.owner = dev->driver->owner; + reset->rcdev.nr_resets = desc->num_resets; + reset->regmap = regmap; + reset->reset_map = desc->resets; + platform_set_drvdata(pdev, &reset->rcdev); + + ret = reset_controller_register(&reset->rcdev); + if (ret) + of_clk_del_provider(dev->of_node); + + return ret; +} +EXPORT_SYMBOL_GPL(qcom_cc_probe); + +void qcom_cc_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + reset_controller_unregister(platform_get_drvdata(pdev)); +} +EXPORT_SYMBOL_GPL(qcom_cc_remove); diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h new file mode 100644 index 00000000000000..2c3cfc860348e3 --- /dev/null +++ b/drivers/clk/qcom/common.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ +#ifndef __QCOM_CLK_COMMON_H__ +#define __QCOM_CLK_COMMON_H__ + +struct platform_device; +struct regmap_config; +struct clk_regmap; +struct qcom_reset_map; + +struct qcom_cc_desc { + const struct regmap_config *config; + struct clk_regmap **clks; + size_t num_clks; + const struct qcom_reset_map *resets; + size_t num_resets; +}; + +extern int qcom_cc_probe(struct platform_device *pdev, + const struct qcom_cc_desc *desc); + +extern void qcom_cc_remove(struct platform_device *pdev); + +#endif diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c index bc0b7f1fcfbecd..44bc6fa64d78c6 100644 --- a/drivers/clk/qcom/gcc-msm8660.c +++ b/drivers/clk/qcom/gcc-msm8660.c @@ -25,6 +25,7 @@ #include #include +#include "common.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-rcg.h" @@ -2701,94 +2702,28 @@ static const struct regmap_config gcc_msm8660_regmap_config = { .fast_io = true, }; +static const struct qcom_cc_desc gcc_msm8660_desc = { + .config = &gcc_msm8660_regmap_config, + .clks = gcc_msm8660_clks, + .num_clks = ARRAY_SIZE(gcc_msm8660_clks), + .resets = gcc_msm8660_resets, + .num_resets = ARRAY_SIZE(gcc_msm8660_resets), +}; + static const struct of_device_id gcc_msm8660_match_table[] = { { .compatible = "qcom,gcc-msm8660" }, { } }; MODULE_DEVICE_TABLE(of, gcc_msm8660_match_table); -struct qcom_cc { - struct qcom_reset_controller reset; - struct clk_onecell_data data; - struct clk *clks[]; -}; - static int gcc_msm8660_probe(struct platform_device *pdev) { - void __iomem *base; - struct resource *res; - int i, ret; - struct device *dev = &pdev->dev; - struct clk *clk; - struct clk_onecell_data *data; - struct clk **clks; - struct regmap *regmap; - size_t num_clks; - struct qcom_reset_controller *reset; - struct qcom_cc *cc; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8660_regmap_config); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - num_clks = ARRAY_SIZE(gcc_msm8660_clks); - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, - GFP_KERNEL); - if (!cc) - return -ENOMEM; - - clks = cc->clks; - data = &cc->data; - data->clks = clks; - data->clk_num = num_clks; - - /* Temporary until RPM clocks supported */ - clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - clk = clk_register_fixed_rate(dev, "pxo", NULL, CLK_IS_ROOT, 27000000); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - for (i = 0; i < num_clks; i++) { - if (!gcc_msm8660_clks[i]) - continue; - clk = devm_clk_register_regmap(dev, gcc_msm8660_clks[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clks[i] = clk; - } - - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); - if (ret) - return ret; - - reset = &cc->reset; - reset->rcdev.of_node = dev->of_node; - reset->rcdev.ops = &qcom_reset_ops, - reset->rcdev.owner = THIS_MODULE, - reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8660_resets), - reset->regmap = regmap; - reset->reset_map = gcc_msm8660_resets, - platform_set_drvdata(pdev, &reset->rcdev); - - ret = reset_controller_register(&reset->rcdev); - if (ret) - of_clk_del_provider(dev->of_node); - - return ret; + return qcom_cc_probe(pdev, &gcc_msm8660_desc); } static int gcc_msm8660_remove(struct platform_device *pdev) { - of_clk_del_provider(pdev->dev.of_node); - reset_controller_unregister(platform_get_drvdata(pdev)); + qcom_cc_remove(pdev); return 0; } diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index fd446ab2fd98b9..f4ffd91901f8ce 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -25,6 +25,7 @@ #include #include +#include "common.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-rcg.h" @@ -2809,7 +2810,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { [PPSS_PROC_RESET] = { 0x2594, 1 }, [PPSS_RESET] = { 0x2594}, [DMA_BAM_RESET] = { 0x25c0, 7 }, - [SIC_TIC_RESET] = { 0x2600, 7 }, + [SPS_TIC_H_RESET] = { 0x2600, 7 }, [SLIMBUS_H_RESET] = { 0x2620, 7 }, [SFAB_CFPB_M_RESET] = { 0x2680, 7 }, [SFAB_CFPB_S_RESET] = { 0x26c0, 7 }, @@ -2822,7 +2823,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { [SFAB_SFPB_M_RESET] = { 0x2780, 7 }, [SFAB_SFPB_S_RESET] = { 0x27a0, 7 }, [RPM_PROC_RESET] = { 0x27c0, 7 }, - [PMIC_SSBI2_RESET] = { 0x270c, 12 }, + [PMIC_SSBI2_RESET] = { 0x280c, 12 }, [SDC1_RESET] = { 0x2830 }, [SDC2_RESET] = { 0x2850 }, [SDC3_RESET] = { 0x2870 }, @@ -2867,6 +2868,16 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { [RIVA_RESET] = { 0x35e0 }, }; +static struct clk_regmap *gcc_apq8064_clks[] = { + [PLL8] = &pll8.clkr, + [PLL8_VOTE] = &pll8_vote, + [GSBI7_UART_SRC] = &gsbi7_uart_src.clkr, + [GSBI7_UART_CLK] = &gsbi7_uart_clk.clkr, + [GSBI7_QUP_SRC] = &gsbi7_qup_src.clkr, + [GSBI7_QUP_CLK] = &gsbi7_qup_clk.clkr, + [GSBI7_H_CLK] = &gsbi7_h_clk.clkr, +}; + static const struct regmap_config gcc_msm8960_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -2875,51 +2886,38 @@ static const struct regmap_config gcc_msm8960_regmap_config = { .fast_io = true, }; +static const struct qcom_cc_desc gcc_msm8960_desc = { + .config = &gcc_msm8960_regmap_config, + .clks = gcc_msm8960_clks, + .num_clks = ARRAY_SIZE(gcc_msm8960_clks), + .resets = gcc_msm8960_resets, + .num_resets = ARRAY_SIZE(gcc_msm8960_resets), +}; + +static const struct qcom_cc_desc gcc_apq8064_desc = { + .config = &gcc_msm8960_regmap_config, + .clks = gcc_apq8064_clks, + .num_clks = ARRAY_SIZE(gcc_apq8064_clks), + .resets = gcc_msm8960_resets, + .num_resets = ARRAY_SIZE(gcc_msm8960_resets), +}; + static const struct of_device_id gcc_msm8960_match_table[] = { - { .compatible = "qcom,gcc-msm8960" }, + { .compatible = "qcom,gcc-msm8960", .data = &gcc_msm8960_desc }, + { .compatible = "qcom,gcc-apq8064", .data = &gcc_apq8064_desc }, { } }; MODULE_DEVICE_TABLE(of, gcc_msm8960_match_table); -struct qcom_cc { - struct qcom_reset_controller reset; - struct clk_onecell_data data; - struct clk *clks[]; -}; - static int gcc_msm8960_probe(struct platform_device *pdev) { - void __iomem *base; - struct resource *res; - int i, ret; - struct device *dev = &pdev->dev; struct clk *clk; - struct clk_onecell_data *data; - struct clk **clks; - struct regmap *regmap; - size_t num_clks; - struct qcom_reset_controller *reset; - struct qcom_cc *cc; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8960_regmap_config); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - num_clks = ARRAY_SIZE(gcc_msm8960_clks); - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, - GFP_KERNEL); - if (!cc) - return -ENOMEM; - - clks = cc->clks; - data = &cc->data; - data->clks = clks; - data->clk_num = num_clks; + struct device *dev = &pdev->dev; + const struct of_device_id *match; + + match = of_match_device(gcc_msm8960_match_table, &pdev->dev); + if (!match) + return -EINVAL; /* Temporary until RPM clocks supported */ clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000); @@ -2930,39 +2928,12 @@ static int gcc_msm8960_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); - for (i = 0; i < num_clks; i++) { - if (!gcc_msm8960_clks[i]) - continue; - clk = devm_clk_register_regmap(dev, gcc_msm8960_clks[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clks[i] = clk; - } - - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); - if (ret) - return ret; - - reset = &cc->reset; - reset->rcdev.of_node = dev->of_node; - reset->rcdev.ops = &qcom_reset_ops, - reset->rcdev.owner = THIS_MODULE, - reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8960_resets), - reset->regmap = regmap; - reset->reset_map = gcc_msm8960_resets, - platform_set_drvdata(pdev, &reset->rcdev); - - ret = reset_controller_register(&reset->rcdev); - if (ret) - of_clk_del_provider(dev->of_node); - - return ret; + return qcom_cc_probe(pdev, match->data); } static int gcc_msm8960_remove(struct platform_device *pdev) { - of_clk_del_provider(pdev->dev.of_node); - reset_controller_unregister(platform_get_drvdata(pdev)); + qcom_cc_remove(pdev); return 0; } diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c index 51d457e2b9595b..0d1edc1e9b3177 100644 --- a/drivers/clk/qcom/gcc-msm8974.c +++ b/drivers/clk/qcom/gcc-msm8974.c @@ -25,6 +25,7 @@ #include #include +#include "common.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-rcg.h" @@ -2574,51 +2575,24 @@ static const struct regmap_config gcc_msm8974_regmap_config = { .fast_io = true, }; +static const struct qcom_cc_desc gcc_msm8974_desc = { + .config = &gcc_msm8974_regmap_config, + .clks = gcc_msm8974_clocks, + .num_clks = ARRAY_SIZE(gcc_msm8974_clocks), + .resets = gcc_msm8974_resets, + .num_resets = ARRAY_SIZE(gcc_msm8974_resets), +}; + static const struct of_device_id gcc_msm8974_match_table[] = { { .compatible = "qcom,gcc-msm8974" }, { } }; MODULE_DEVICE_TABLE(of, gcc_msm8974_match_table); -struct qcom_cc { - struct qcom_reset_controller reset; - struct clk_onecell_data data; - struct clk *clks[]; -}; - static int gcc_msm8974_probe(struct platform_device *pdev) { - void __iomem *base; - struct resource *res; - int i, ret; - struct device *dev = &pdev->dev; struct clk *clk; - struct clk_onecell_data *data; - struct clk **clks; - struct regmap *regmap; - size_t num_clks; - struct qcom_reset_controller *reset; - struct qcom_cc *cc; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8974_regmap_config); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - num_clks = ARRAY_SIZE(gcc_msm8974_clocks); - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, - GFP_KERNEL); - if (!cc) - return -ENOMEM; - - clks = cc->clks; - data = &cc->data; - data->clks = clks; - data->clk_num = num_clks; + struct device *dev = &pdev->dev; /* Temporary until RPM clocks supported */ clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000); @@ -2631,39 +2605,12 @@ static int gcc_msm8974_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); - for (i = 0; i < num_clks; i++) { - if (!gcc_msm8974_clocks[i]) - continue; - clk = devm_clk_register_regmap(dev, gcc_msm8974_clocks[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clks[i] = clk; - } - - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); - if (ret) - return ret; - - reset = &cc->reset; - reset->rcdev.of_node = dev->of_node; - reset->rcdev.ops = &qcom_reset_ops, - reset->rcdev.owner = THIS_MODULE, - reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8974_resets), - reset->regmap = regmap; - reset->reset_map = gcc_msm8974_resets, - platform_set_drvdata(pdev, &reset->rcdev); - - ret = reset_controller_register(&reset->rcdev); - if (ret) - of_clk_del_provider(dev->of_node); - - return ret; + return qcom_cc_probe(pdev, &gcc_msm8974_desc); } static int gcc_msm8974_remove(struct platform_device *pdev) { - of_clk_del_provider(pdev->dev.of_node); - reset_controller_unregister(platform_get_drvdata(pdev)); + qcom_cc_remove(pdev); return 0; } diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index f9b59c7e48e9c7..12f3c0b64fcd75 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c @@ -26,6 +26,7 @@ #include #include +#include "common.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-rcg.h" @@ -2222,85 +2223,28 @@ static const struct regmap_config mmcc_msm8960_regmap_config = { .fast_io = true, }; +static const struct qcom_cc_desc mmcc_msm8960_desc = { + .config = &mmcc_msm8960_regmap_config, + .clks = mmcc_msm8960_clks, + .num_clks = ARRAY_SIZE(mmcc_msm8960_clks), + .resets = mmcc_msm8960_resets, + .num_resets = ARRAY_SIZE(mmcc_msm8960_resets), +}; + static const struct of_device_id mmcc_msm8960_match_table[] = { { .compatible = "qcom,mmcc-msm8960" }, { } }; MODULE_DEVICE_TABLE(of, mmcc_msm8960_match_table); -struct qcom_cc { - struct qcom_reset_controller reset; - struct clk_onecell_data data; - struct clk *clks[]; -}; - static int mmcc_msm8960_probe(struct platform_device *pdev) { - void __iomem *base; - struct resource *res; - int i, ret; - struct device *dev = &pdev->dev; - struct clk *clk; - struct clk_onecell_data *data; - struct clk **clks; - struct regmap *regmap; - size_t num_clks; - struct qcom_reset_controller *reset; - struct qcom_cc *cc; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, &mmcc_msm8960_regmap_config); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - num_clks = ARRAY_SIZE(mmcc_msm8960_clks); - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, - GFP_KERNEL); - if (!cc) - return -ENOMEM; - - clks = cc->clks; - data = &cc->data; - data->clks = clks; - data->clk_num = num_clks; - - for (i = 0; i < num_clks; i++) { - if (!mmcc_msm8960_clks[i]) - continue; - clk = devm_clk_register_regmap(dev, mmcc_msm8960_clks[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clks[i] = clk; - } - - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); - if (ret) - return ret; - - reset = &cc->reset; - reset->rcdev.of_node = dev->of_node; - reset->rcdev.ops = &qcom_reset_ops, - reset->rcdev.owner = THIS_MODULE, - reset->rcdev.nr_resets = ARRAY_SIZE(mmcc_msm8960_resets), - reset->regmap = regmap; - reset->reset_map = mmcc_msm8960_resets, - platform_set_drvdata(pdev, &reset->rcdev); - - ret = reset_controller_register(&reset->rcdev); - if (ret) - of_clk_del_provider(dev->of_node); - - return ret; + return qcom_cc_probe(pdev, &mmcc_msm8960_desc); } static int mmcc_msm8960_remove(struct platform_device *pdev) { - of_clk_del_provider(pdev->dev.of_node); - reset_controller_unregister(platform_get_drvdata(pdev)); + qcom_cc_remove(pdev); return 0; } diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c index c95774514b81b2..60b7c24a5cd6c4 100644 --- a/drivers/clk/qcom/mmcc-msm8974.c +++ b/drivers/clk/qcom/mmcc-msm8974.c @@ -25,6 +25,7 @@ #include #include +#include "common.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-rcg.h" @@ -2524,88 +2525,39 @@ static const struct regmap_config mmcc_msm8974_regmap_config = { .fast_io = true, }; +static const struct qcom_cc_desc mmcc_msm8974_desc = { + .config = &mmcc_msm8974_regmap_config, + .clks = mmcc_msm8974_clocks, + .num_clks = ARRAY_SIZE(mmcc_msm8974_clocks), + .resets = mmcc_msm8974_resets, + .num_resets = ARRAY_SIZE(mmcc_msm8974_resets), +}; + static const struct of_device_id mmcc_msm8974_match_table[] = { { .compatible = "qcom,mmcc-msm8974" }, { } }; MODULE_DEVICE_TABLE(of, mmcc_msm8974_match_table); -struct qcom_cc { - struct qcom_reset_controller reset; - struct clk_onecell_data data; - struct clk *clks[]; -}; - static int mmcc_msm8974_probe(struct platform_device *pdev) { - void __iomem *base; - struct resource *res; - int i, ret; - struct device *dev = &pdev->dev; - struct clk *clk; - struct clk_onecell_data *data; - struct clk **clks; + int ret; struct regmap *regmap; - size_t num_clks; - struct qcom_reset_controller *reset; - struct qcom_cc *cc; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, &mmcc_msm8974_regmap_config); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - num_clks = ARRAY_SIZE(mmcc_msm8974_clocks); - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, - GFP_KERNEL); - if (!cc) - return -ENOMEM; - - clks = cc->clks; - data = &cc->data; - data->clks = clks; - data->clk_num = num_clks; - - clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true); - clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false); - for (i = 0; i < num_clks; i++) { - if (!mmcc_msm8974_clocks[i]) - continue; - clk = devm_clk_register_regmap(dev, mmcc_msm8974_clocks[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clks[i] = clk; - } - - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); + ret = qcom_cc_probe(pdev, &mmcc_msm8974_desc); if (ret) return ret; - reset = &cc->reset; - reset->rcdev.of_node = dev->of_node; - reset->rcdev.ops = &qcom_reset_ops, - reset->rcdev.owner = THIS_MODULE, - reset->rcdev.nr_resets = ARRAY_SIZE(mmcc_msm8974_resets), - reset->regmap = regmap; - reset->reset_map = mmcc_msm8974_resets, - platform_set_drvdata(pdev, &reset->rcdev); - - ret = reset_controller_register(&reset->rcdev); - if (ret) - of_clk_del_provider(dev->of_node); + regmap = dev_get_regmap(&pdev->dev, NULL); + clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true); + clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false); - return ret; + return 0; } static int mmcc_msm8974_remove(struct platform_device *pdev) { - of_clk_del_provider(pdev->dev.of_node); - reset_controller_unregister(platform_get_drvdata(pdev)); + qcom_cc_remove(pdev); return 0; } diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 8eb4799237f03d..2cb62f87e0683a 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -8,4 +8,8 @@ obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-audss.o +obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o +obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o +obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o +obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o obj-$(CONFIG_ARCH_S3C64XX) += clk-s3c64xx.o diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index e7ee4420da8178..2bb4625ed6f18d 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -24,6 +24,8 @@ #define APLL_CON0 0x100 #define SRC_CPU 0x200 #define DIV_CPU0 0x500 +#define PWR_CTRL1 0x1020 +#define PWR_CTRL2 0x1024 #define MPLL_LOCK 0x4000 #define MPLL_CON0 0x4100 #define SRC_CORE1 0x4204 @@ -80,6 +82,23 @@ #define SRC_CDREX 0x20200 #define PLL_DIV2_SEL 0x20a24 +/*Below definitions are used for PWR_CTRL settings*/ +#define PWR_CTRL1_CORE2_DOWN_RATIO (7 << 28) +#define PWR_CTRL1_CORE1_DOWN_RATIO (7 << 16) +#define PWR_CTRL1_DIV2_DOWN_EN (1 << 9) +#define PWR_CTRL1_DIV1_DOWN_EN (1 << 8) +#define PWR_CTRL1_USE_CORE1_WFE (1 << 5) +#define PWR_CTRL1_USE_CORE0_WFE (1 << 4) +#define PWR_CTRL1_USE_CORE1_WFI (1 << 1) +#define PWR_CTRL1_USE_CORE0_WFI (1 << 0) + +#define PWR_CTRL2_DIV2_UP_EN (1 << 25) +#define PWR_CTRL2_DIV1_UP_EN (1 << 24) +#define PWR_CTRL2_DUR_STANDBY2_VAL (1 << 16) +#define PWR_CTRL2_DUR_STANDBY1_VAL (1 << 8) +#define PWR_CTRL2_CORE2_UP_RATIO (1 << 4) +#define PWR_CTRL2_CORE1_UP_RATIO (1 << 0) + /* list of PLLs to be registered */ enum exynos5250_plls { apll, mpll, cpll, epll, vpll, gpll, bpll, @@ -98,6 +117,8 @@ static struct samsung_clk_reg_dump *exynos5250_save; static unsigned long exynos5250_clk_regs[] __initdata = { SRC_CPU, DIV_CPU0, + PWR_CTRL1, + PWR_CTRL2, SRC_CORE1, SRC_TOP0, SRC_TOP2, @@ -686,6 +707,7 @@ static struct of_device_id ext_clk_match[] __initdata = { /* register exynox5250 clocks */ static void __init exynos5250_clk_init(struct device_node *np) { + unsigned int tmp; if (np) { reg_base = of_iomap(np, 0); if (!reg_base) @@ -722,6 +744,26 @@ static void __init exynos5250_clk_init(struct device_node *np) samsung_clk_register_gate(exynos5250_gate_clks, ARRAY_SIZE(exynos5250_gate_clks)); + /* + * Enable arm clock down (in idle) and set arm divider + * ratios in WFI/WFE state. + */ + tmp = (PWR_CTRL1_CORE2_DOWN_RATIO | PWR_CTRL1_CORE1_DOWN_RATIO | + PWR_CTRL1_DIV2_DOWN_EN | PWR_CTRL1_DIV1_DOWN_EN | + PWR_CTRL1_USE_CORE1_WFE | PWR_CTRL1_USE_CORE0_WFE | + PWR_CTRL1_USE_CORE1_WFI | PWR_CTRL1_USE_CORE0_WFI); + __raw_writel(tmp, reg_base + PWR_CTRL1); + + /* + * Enable arm clock up (on exiting idle). Set arm divider + * ratios when not in idle along with the standby duration + * ratios. + */ + tmp = (PWR_CTRL2_DIV2_UP_EN | PWR_CTRL2_DIV1_UP_EN | + PWR_CTRL2_DUR_STANDBY2_VAL | PWR_CTRL2_DUR_STANDBY1_VAL | + PWR_CTRL2_CORE2_UP_RATIO | PWR_CTRL2_CORE1_UP_RATIO); + __raw_writel(tmp, reg_base + PWR_CTRL2); + exynos5250_clk_sleep_init(); pr_info("Exynos5250: clock setup completed, armclk=%ld\n", diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 81e6d2f49aa001..7fb0a28e65d5f4 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -11,6 +11,7 @@ #include #include +#include #include "clk.h" #include "clk-pll.h" @@ -58,6 +59,72 @@ static long samsung_pll_round_rate(struct clk_hw *hw, return rate_table[i - 1].rate; } +/* + * PLL2126 Clock Type + */ + +#define PLL2126_MDIV_MASK (0xff) +#define PLL2126_PDIV_MASK (0x3f) +#define PLL2126_SDIV_MASK (0x3) +#define PLL2126_MDIV_SHIFT (16) +#define PLL2126_PDIV_SHIFT (8) +#define PLL2126_SDIV_SHIFT (0) + +static unsigned long samsung_pll2126_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 pll_con, mdiv, pdiv, sdiv; + u64 fvco = parent_rate; + + pll_con = __raw_readl(pll->con_reg); + mdiv = (pll_con >> PLL2126_MDIV_SHIFT) & PLL2126_MDIV_MASK; + pdiv = (pll_con >> PLL2126_PDIV_SHIFT) & PLL2126_PDIV_MASK; + sdiv = (pll_con >> PLL2126_SDIV_SHIFT) & PLL2126_SDIV_MASK; + + fvco *= (mdiv + 8); + do_div(fvco, (pdiv + 2) << sdiv); + + return (unsigned long)fvco; +} + +static const struct clk_ops samsung_pll2126_clk_ops = { + .recalc_rate = samsung_pll2126_recalc_rate, +}; + +/* + * PLL3000 Clock Type + */ + +#define PLL3000_MDIV_MASK (0xff) +#define PLL3000_PDIV_MASK (0x3) +#define PLL3000_SDIV_MASK (0x3) +#define PLL3000_MDIV_SHIFT (16) +#define PLL3000_PDIV_SHIFT (8) +#define PLL3000_SDIV_SHIFT (0) + +static unsigned long samsung_pll3000_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 pll_con, mdiv, pdiv, sdiv; + u64 fvco = parent_rate; + + pll_con = __raw_readl(pll->con_reg); + mdiv = (pll_con >> PLL3000_MDIV_SHIFT) & PLL3000_MDIV_MASK; + pdiv = (pll_con >> PLL3000_PDIV_SHIFT) & PLL3000_PDIV_MASK; + sdiv = (pll_con >> PLL3000_SDIV_SHIFT) & PLL3000_SDIV_MASK; + + fvco *= (2 * (mdiv + 8)); + do_div(fvco, pdiv << sdiv); + + return (unsigned long)fvco; +} + +static const struct clk_ops samsung_pll3000_clk_ops = { + .recalc_rate = samsung_pll3000_recalc_rate, +}; + /* * PLL35xx Clock Type */ @@ -564,7 +631,9 @@ static const struct clk_ops samsung_pll46xx_clk_min_ops = { #define PLL6552_PDIV_MASK 0x3f #define PLL6552_SDIV_MASK 0x7 #define PLL6552_MDIV_SHIFT 16 +#define PLL6552_MDIV_SHIFT_2416 14 #define PLL6552_PDIV_SHIFT 8 +#define PLL6552_PDIV_SHIFT_2416 5 #define PLL6552_SDIV_SHIFT 0 static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw, @@ -575,8 +644,13 @@ static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw, u64 fvco = parent_rate; pll_con = __raw_readl(pll->con_reg); - mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK; - pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK; + if (pll->type == pll_6552_s3c2416) { + mdiv = (pll_con >> PLL6552_MDIV_SHIFT_2416) & PLL6552_MDIV_MASK; + pdiv = (pll_con >> PLL6552_PDIV_SHIFT_2416) & PLL6552_PDIV_MASK; + } else { + mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK; + pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK; + } sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK; fvco *= mdiv; @@ -627,6 +701,169 @@ static const struct clk_ops samsung_pll6553_clk_ops = { .recalc_rate = samsung_pll6553_recalc_rate, }; +/* + * PLL Clock Type of S3C24XX before S3C2443 + */ + +#define PLLS3C2410_MDIV_MASK (0xff) +#define PLLS3C2410_PDIV_MASK (0x1f) +#define PLLS3C2410_SDIV_MASK (0x3) +#define PLLS3C2410_MDIV_SHIFT (12) +#define PLLS3C2410_PDIV_SHIFT (4) +#define PLLS3C2410_SDIV_SHIFT (0) + +#define PLLS3C2410_ENABLE_REG_OFFSET 0x10 + +static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 pll_con, mdiv, pdiv, sdiv; + u64 fvco = parent_rate; + + pll_con = __raw_readl(pll->con_reg); + mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK; + pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK; + sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK; + + fvco *= (mdiv + 8); + do_div(fvco, (pdiv + 2) << sdiv); + + return (unsigned int)fvco; +} + +static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 pll_con, mdiv, pdiv, sdiv; + u64 fvco = parent_rate; + + pll_con = __raw_readl(pll->con_reg); + mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK; + pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK; + sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK; + + fvco *= (2 * (mdiv + 8)); + do_div(fvco, (pdiv + 2) << sdiv); + + return (unsigned int)fvco; +} + +static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate; + u32 tmp; + + /* Get required rate settings from table */ + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, __clk_get_name(hw->clk)); + return -EINVAL; + } + + tmp = __raw_readl(pll->con_reg); + + /* Change PLL PMS values */ + tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) | + (PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) | + (PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT)); + tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) | + (rate->pdiv << PLLS3C2410_PDIV_SHIFT) | + (rate->sdiv << PLLS3C2410_SDIV_SHIFT); + __raw_writel(tmp, pll->con_reg); + + /* Time to settle according to the manual */ + udelay(300); + + return 0; +} + +static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 pll_en = __raw_readl(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET); + u32 pll_en_orig = pll_en; + + if (enable) + pll_en &= ~BIT(bit); + else + pll_en |= BIT(bit); + + __raw_writel(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET); + + /* if we started the UPLL, then allow to settle */ + if (enable && (pll_en_orig & BIT(bit))) + udelay(300); + + return 0; +} + +static int samsung_s3c2410_mpll_enable(struct clk_hw *hw) +{ + return samsung_s3c2410_pll_enable(hw, 5, true); +} + +static void samsung_s3c2410_mpll_disable(struct clk_hw *hw) +{ + samsung_s3c2410_pll_enable(hw, 5, false); +} + +static int samsung_s3c2410_upll_enable(struct clk_hw *hw) +{ + return samsung_s3c2410_pll_enable(hw, 7, true); +} + +static void samsung_s3c2410_upll_disable(struct clk_hw *hw) +{ + samsung_s3c2410_pll_enable(hw, 7, false); +} + +static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = { + .recalc_rate = samsung_s3c2410_pll_recalc_rate, + .enable = samsung_s3c2410_mpll_enable, + .disable = samsung_s3c2410_mpll_disable, +}; + +static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = { + .recalc_rate = samsung_s3c2410_pll_recalc_rate, + .enable = samsung_s3c2410_upll_enable, + .disable = samsung_s3c2410_upll_disable, +}; + +static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = { + .recalc_rate = samsung_s3c2440_mpll_recalc_rate, + .enable = samsung_s3c2410_mpll_enable, + .disable = samsung_s3c2410_mpll_disable, +}; + +static const struct clk_ops samsung_s3c2410_mpll_clk_ops = { + .recalc_rate = samsung_s3c2410_pll_recalc_rate, + .enable = samsung_s3c2410_mpll_enable, + .disable = samsung_s3c2410_mpll_disable, + .round_rate = samsung_pll_round_rate, + .set_rate = samsung_s3c2410_pll_set_rate, +}; + +static const struct clk_ops samsung_s3c2410_upll_clk_ops = { + .recalc_rate = samsung_s3c2410_pll_recalc_rate, + .enable = samsung_s3c2410_upll_enable, + .disable = samsung_s3c2410_upll_disable, + .round_rate = samsung_pll_round_rate, + .set_rate = samsung_s3c2410_pll_set_rate, +}; + +static const struct clk_ops samsung_s3c2440_mpll_clk_ops = { + .recalc_rate = samsung_s3c2440_mpll_recalc_rate, + .enable = samsung_s3c2410_mpll_enable, + .disable = samsung_s3c2410_mpll_disable, + .round_rate = samsung_pll_round_rate, + .set_rate = samsung_s3c2410_pll_set_rate, +}; + /* * PLL2550x Clock Type */ @@ -746,6 +983,12 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk, } switch (pll_clk->type) { + case pll_2126: + init.ops = &samsung_pll2126_clk_ops; + break; + case pll_3000: + init.ops = &samsung_pll3000_clk_ops; + break; /* clk_ops for 35xx and 2550 are similar */ case pll_35xx: case pll_2550: @@ -773,6 +1016,7 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk, init.ops = &samsung_pll36xx_clk_ops; break; case pll_6552: + case pll_6552_s3c2416: init.ops = &samsung_pll6552_clk_ops; break; case pll_6553: @@ -786,6 +1030,24 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk, else init.ops = &samsung_pll46xx_clk_ops; break; + case pll_s3c2410_mpll: + if (!pll->rate_table) + init.ops = &samsung_s3c2410_mpll_clk_min_ops; + else + init.ops = &samsung_s3c2410_mpll_clk_ops; + break; + case pll_s3c2410_upll: + if (!pll->rate_table) + init.ops = &samsung_s3c2410_upll_clk_min_ops; + else + init.ops = &samsung_s3c2410_upll_clk_ops; + break; + case pll_s3c2440_mpll: + if (!pll->rate_table) + init.ops = &samsung_s3c2440_mpll_clk_min_ops; + else + init.ops = &samsung_s3c2440_mpll_clk_ops; + break; default: pr_warn("%s: Unknown pll type for pll clk %s\n", __func__, pll_clk->name); diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 6c39030080fbed..6428bcc6df6f07 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -13,6 +13,8 @@ #define __SAMSUNG_CLK_PLL_H enum samsung_pll_type { + pll_2126, + pll_3000, pll_35xx, pll_36xx, pll_2550, @@ -24,7 +26,11 @@ enum samsung_pll_type { pll_4650, pll_4650c, pll_6552, + pll_6552_s3c2416, pll_6553, + pll_s3c2410_mpll, + pll_s3c2410_upll, + pll_s3c2440_mpll, }; #define PLL_35XX_RATE(_rate, _m, _p, _s) \ diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c new file mode 100644 index 00000000000000..8d8dff005c1076 --- /dev/null +++ b/drivers/clk/samsung/clk-s3c2410-dclk.c @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2013 Heiko Stuebner + * + * 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. + * + * Common Clock Framework support for s3c24xx external clock output. + */ + +#include +#include +#include "clk.h" + +/* legacy access to misccr, until dt conversion is finished */ +#include +#include + +#define MUX_DCLK0 0 +#define MUX_DCLK1 1 +#define DIV_DCLK0 2 +#define DIV_DCLK1 3 +#define GATE_DCLK0 4 +#define GATE_DCLK1 5 +#define MUX_CLKOUT0 6 +#define MUX_CLKOUT1 7 +#define DCLK_MAX_CLKS (MUX_CLKOUT1 + 1) + +enum supported_socs { + S3C2410, + S3C2412, + S3C2440, + S3C2443, +}; + +struct s3c24xx_dclk_drv_data { + const char **clkout0_parent_names; + int clkout0_num_parents; + const char **clkout1_parent_names; + int clkout1_num_parents; + const char **mux_parent_names; + int mux_num_parents; +}; + +/* + * Clock for output-parent selection in misccr + */ + +struct s3c24xx_clkout { + struct clk_hw hw; + u32 mask; + u8 shift; +}; + +#define to_s3c24xx_clkout(_hw) container_of(_hw, struct s3c24xx_clkout, hw) + +static u8 s3c24xx_clkout_get_parent(struct clk_hw *hw) +{ + struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw); + int num_parents = __clk_get_num_parents(hw->clk); + u32 val; + + val = readl_relaxed(S3C24XX_MISCCR) >> clkout->shift; + val >>= clkout->shift; + val &= clkout->mask; + + if (val >= num_parents) + return -EINVAL; + + return val; +} + +static int s3c24xx_clkout_set_parent(struct clk_hw *hw, u8 index) +{ + struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw); + int ret = 0; + + s3c2410_modify_misccr((clkout->mask << clkout->shift), + (index << clkout->shift)); + + return ret; +} + +const struct clk_ops s3c24xx_clkout_ops = { + .get_parent = s3c24xx_clkout_get_parent, + .set_parent = s3c24xx_clkout_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +struct clk *s3c24xx_register_clkout(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, + u8 shift, u32 mask) +{ + struct s3c24xx_clkout *clkout; + struct clk *clk; + struct clk_init_data init; + + /* allocate the clkout */ + clkout = kzalloc(sizeof(*clkout), GFP_KERNEL); + if (!clkout) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &s3c24xx_clkout_ops; + init.flags = CLK_IS_BASIC; + init.parent_names = parent_names; + init.num_parents = num_parents; + + clkout->shift = shift; + clkout->mask = mask; + clkout->hw.init = &init; + + clk = clk_register(dev, &clkout->hw); + + return clk; +} + +/* + * dclk and clkout init + */ + +struct s3c24xx_dclk { + struct device *dev; + void __iomem *base; + struct clk_onecell_data clk_data; + struct notifier_block dclk0_div_change_nb; + struct notifier_block dclk1_div_change_nb; + spinlock_t dclk_lock; + unsigned long reg_save; +}; + +#define to_s3c24xx_dclk0(x) \ + container_of(x, struct s3c24xx_dclk, dclk0_div_change_nb) + +#define to_s3c24xx_dclk1(x) \ + container_of(x, struct s3c24xx_dclk, dclk1_div_change_nb) + +PNAME(dclk_s3c2410_p) = { "pclk", "uclk" }; +PNAME(clkout0_s3c2410_p) = { "mpll", "upll", "fclk", "hclk", "pclk", + "gate_dclk0" }; +PNAME(clkout1_s3c2410_p) = { "mpll", "upll", "fclk", "hclk", "pclk", + "gate_dclk1" }; + +PNAME(clkout0_s3c2412_p) = { "mpll", "upll", "rtc_clkout", + "hclk", "pclk", "gate_dclk0" }; +PNAME(clkout1_s3c2412_p) = { "xti", "upll", "fclk", "hclk", "pclk", + "gate_dclk1" }; + +PNAME(clkout0_s3c2440_p) = { "xti", "upll", "fclk", "hclk", "pclk", + "gate_dclk0" }; +PNAME(clkout1_s3c2440_p) = { "mpll", "upll", "rtc_clkout", + "hclk", "pclk", "gate_dclk1" }; + +PNAME(dclk_s3c2443_p) = { "pclk", "epll" }; +PNAME(clkout0_s3c2443_p) = { "xti", "epll", "armclk", "hclk", "pclk", + "gate_dclk0" }; +PNAME(clkout1_s3c2443_p) = { "dummy", "epll", "rtc_clkout", + "hclk", "pclk", "gate_dclk1" }; + +#define DCLKCON_DCLK_DIV_MASK 0xf +#define DCLKCON_DCLK0_DIV_SHIFT 4 +#define DCLKCON_DCLK0_CMP_SHIFT 8 +#define DCLKCON_DCLK1_DIV_SHIFT 20 +#define DCLKCON_DCLK1_CMP_SHIFT 24 + +static void s3c24xx_dclk_update_cmp(struct s3c24xx_dclk *s3c24xx_dclk, + int div_shift, int cmp_shift) +{ + unsigned long flags = 0; + u32 dclk_con, div, cmp; + + spin_lock_irqsave(&s3c24xx_dclk->dclk_lock, flags); + + dclk_con = readl_relaxed(s3c24xx_dclk->base); + + div = ((dclk_con >> div_shift) & DCLKCON_DCLK_DIV_MASK) + 1; + cmp = ((div + 1) / 2) - 1; + + dclk_con &= ~(DCLKCON_DCLK_DIV_MASK << cmp_shift); + dclk_con |= (cmp << cmp_shift); + + writel_relaxed(dclk_con, s3c24xx_dclk->base); + + spin_unlock_irqrestore(&s3c24xx_dclk->dclk_lock, flags); +} + +static int s3c24xx_dclk0_div_notify(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct s3c24xx_dclk *s3c24xx_dclk = to_s3c24xx_dclk0(nb); + + if (event == POST_RATE_CHANGE) { + s3c24xx_dclk_update_cmp(s3c24xx_dclk, + DCLKCON_DCLK0_DIV_SHIFT, DCLKCON_DCLK0_CMP_SHIFT); + } + + return NOTIFY_DONE; +} + +static int s3c24xx_dclk1_div_notify(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct s3c24xx_dclk *s3c24xx_dclk = to_s3c24xx_dclk1(nb); + + if (event == POST_RATE_CHANGE) { + s3c24xx_dclk_update_cmp(s3c24xx_dclk, + DCLKCON_DCLK1_DIV_SHIFT, DCLKCON_DCLK1_CMP_SHIFT); + } + + return NOTIFY_DONE; +} + +#ifdef CONFIG_PM_SLEEP +static int s3c24xx_dclk_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct s3c24xx_dclk *s3c24xx_dclk = platform_get_drvdata(pdev); + + s3c24xx_dclk->reg_save = readl_relaxed(s3c24xx_dclk->base); + return 0; +} + +static int s3c24xx_dclk_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct s3c24xx_dclk *s3c24xx_dclk = platform_get_drvdata(pdev); + + writel_relaxed(s3c24xx_dclk->reg_save, s3c24xx_dclk->base); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(s3c24xx_dclk_pm_ops, + s3c24xx_dclk_suspend, s3c24xx_dclk_resume); + +static int s3c24xx_dclk_probe(struct platform_device *pdev) +{ + struct s3c24xx_dclk *s3c24xx_dclk; + struct resource *mem; + struct clk **clk_table; + struct s3c24xx_dclk_drv_data *dclk_variant; + int ret, i; + + s3c24xx_dclk = devm_kzalloc(&pdev->dev, sizeof(*s3c24xx_dclk), + GFP_KERNEL); + if (!s3c24xx_dclk) + return -ENOMEM; + + s3c24xx_dclk->dev = &pdev->dev; + platform_set_drvdata(pdev, s3c24xx_dclk); + spin_lock_init(&s3c24xx_dclk->dclk_lock); + + clk_table = devm_kzalloc(&pdev->dev, + sizeof(struct clk *) * DCLK_MAX_CLKS, + GFP_KERNEL); + if (!clk_table) + return -ENOMEM; + + s3c24xx_dclk->clk_data.clks = clk_table; + s3c24xx_dclk->clk_data.clk_num = DCLK_MAX_CLKS; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + s3c24xx_dclk->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(s3c24xx_dclk->base)) + return PTR_ERR(s3c24xx_dclk->base); + + dclk_variant = (struct s3c24xx_dclk_drv_data *) + platform_get_device_id(pdev)->driver_data; + + + clk_table[MUX_DCLK0] = clk_register_mux(&pdev->dev, "mux_dclk0", + dclk_variant->mux_parent_names, + dclk_variant->mux_num_parents, 0, + s3c24xx_dclk->base, 1, 1, 0, + &s3c24xx_dclk->dclk_lock); + clk_table[MUX_DCLK1] = clk_register_mux(&pdev->dev, "mux_dclk1", + dclk_variant->mux_parent_names, + dclk_variant->mux_num_parents, 0, + s3c24xx_dclk->base, 17, 1, 0, + &s3c24xx_dclk->dclk_lock); + + clk_table[DIV_DCLK0] = clk_register_divider(&pdev->dev, "div_dclk0", + "mux_dclk0", 0, s3c24xx_dclk->base, + 4, 4, 0, &s3c24xx_dclk->dclk_lock); + clk_table[DIV_DCLK1] = clk_register_divider(&pdev->dev, "div_dclk1", + "mux_dclk1", 0, s3c24xx_dclk->base, + 20, 4, 0, &s3c24xx_dclk->dclk_lock); + + clk_table[GATE_DCLK0] = clk_register_gate(&pdev->dev, "gate_dclk0", + "div_dclk0", CLK_SET_RATE_PARENT, + s3c24xx_dclk->base, 0, 0, + &s3c24xx_dclk->dclk_lock); + clk_table[GATE_DCLK1] = clk_register_gate(&pdev->dev, "gate_dclk1", + "div_dclk1", CLK_SET_RATE_PARENT, + s3c24xx_dclk->base, 16, 0, + &s3c24xx_dclk->dclk_lock); + + clk_table[MUX_CLKOUT0] = s3c24xx_register_clkout(&pdev->dev, + "clkout0", dclk_variant->clkout0_parent_names, + dclk_variant->clkout0_num_parents, 4, 7); + clk_table[MUX_CLKOUT1] = s3c24xx_register_clkout(&pdev->dev, + "clkout1", dclk_variant->clkout1_parent_names, + dclk_variant->clkout1_num_parents, 8, 7); + + for (i = 0; i < DCLK_MAX_CLKS; i++) + if (IS_ERR(clk_table[i])) { + dev_err(&pdev->dev, "clock %d failed to register\n", i); + ret = PTR_ERR(clk_table[i]); + goto err_clk_register; + } + + ret = clk_register_clkdev(clk_table[MUX_DCLK0], "dclk0", NULL); + if (!ret) + ret = clk_register_clkdev(clk_table[MUX_DCLK1], "dclk1", NULL); + if (!ret) + ret = clk_register_clkdev(clk_table[MUX_CLKOUT0], + "clkout0", NULL); + if (!ret) + ret = clk_register_clkdev(clk_table[MUX_CLKOUT1], + "clkout1", NULL); + if (ret) { + dev_err(&pdev->dev, "failed to register aliases, %d\n", ret); + goto err_clk_register; + } + + s3c24xx_dclk->dclk0_div_change_nb.notifier_call = + s3c24xx_dclk0_div_notify; + + s3c24xx_dclk->dclk1_div_change_nb.notifier_call = + s3c24xx_dclk1_div_notify; + + ret = clk_notifier_register(clk_table[DIV_DCLK0], + &s3c24xx_dclk->dclk0_div_change_nb); + if (ret) + goto err_clk_register; + + ret = clk_notifier_register(clk_table[DIV_DCLK1], + &s3c24xx_dclk->dclk1_div_change_nb); + if (ret) + goto err_dclk_notify; + + return 0; + +err_dclk_notify: + clk_notifier_unregister(clk_table[DIV_DCLK0], + &s3c24xx_dclk->dclk0_div_change_nb); +err_clk_register: + for (i = 0; i < DCLK_MAX_CLKS; i++) + if (clk_table[i] && !IS_ERR(clk_table[i])) + clk_unregister(clk_table[i]); + + return ret; +} + +static int s3c24xx_dclk_remove(struct platform_device *pdev) +{ + struct s3c24xx_dclk *s3c24xx_dclk = platform_get_drvdata(pdev); + struct clk **clk_table = s3c24xx_dclk->clk_data.clks; + int i; + + clk_notifier_unregister(clk_table[DIV_DCLK1], + &s3c24xx_dclk->dclk1_div_change_nb); + clk_notifier_unregister(clk_table[DIV_DCLK0], + &s3c24xx_dclk->dclk0_div_change_nb); + + for (i = 0; i < DCLK_MAX_CLKS; i++) + clk_unregister(clk_table[i]); + + return 0; +} + +static struct s3c24xx_dclk_drv_data dclk_variants[] = { + [S3C2410] = { + .clkout0_parent_names = clkout0_s3c2410_p, + .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2410_p), + .clkout1_parent_names = clkout1_s3c2410_p, + .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2410_p), + .mux_parent_names = dclk_s3c2410_p, + .mux_num_parents = ARRAY_SIZE(dclk_s3c2410_p), + }, + [S3C2412] = { + .clkout0_parent_names = clkout0_s3c2412_p, + .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2412_p), + .clkout1_parent_names = clkout1_s3c2412_p, + .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2412_p), + .mux_parent_names = dclk_s3c2410_p, + .mux_num_parents = ARRAY_SIZE(dclk_s3c2410_p), + }, + [S3C2440] = { + .clkout0_parent_names = clkout0_s3c2440_p, + .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2440_p), + .clkout1_parent_names = clkout1_s3c2440_p, + .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2440_p), + .mux_parent_names = dclk_s3c2410_p, + .mux_num_parents = ARRAY_SIZE(dclk_s3c2410_p), + }, + [S3C2443] = { + .clkout0_parent_names = clkout0_s3c2443_p, + .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2443_p), + .clkout1_parent_names = clkout1_s3c2443_p, + .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2443_p), + .mux_parent_names = dclk_s3c2443_p, + .mux_num_parents = ARRAY_SIZE(dclk_s3c2443_p), + }, +}; + +static struct platform_device_id s3c24xx_dclk_driver_ids[] = { + { + .name = "s3c2410-dclk", + .driver_data = (kernel_ulong_t)&dclk_variants[S3C2410], + }, { + .name = "s3c2412-dclk", + .driver_data = (kernel_ulong_t)&dclk_variants[S3C2412], + }, { + .name = "s3c2440-dclk", + .driver_data = (kernel_ulong_t)&dclk_variants[S3C2440], + }, { + .name = "s3c2443-dclk", + .driver_data = (kernel_ulong_t)&dclk_variants[S3C2443], + }, + { } +}; + +MODULE_DEVICE_TABLE(platform, s3c24xx_dclk_driver_ids); + +static struct platform_driver s3c24xx_dclk_driver = { + .driver = { + .name = "s3c24xx-dclk", + .owner = THIS_MODULE, + .pm = &s3c24xx_dclk_pm_ops, + }, + .probe = s3c24xx_dclk_probe, + .remove = s3c24xx_dclk_remove, + .id_table = s3c24xx_dclk_driver_ids, +}; +module_platform_driver(s3c24xx_dclk_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Heiko Stuebner "); +MODULE_DESCRIPTION("Driver for the S3C24XX external clock outputs"); diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c new file mode 100644 index 00000000000000..7b4182186a30ce --- /dev/null +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -0,0 +1,477 @@ +/* + * Copyright (c) 2013 Heiko Stuebner + * + * 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. + * + * Common Clock Framework support for S3C2410 and following SoCs. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" +#include "clk-pll.h" + +#define LOCKTIME 0x00 +#define MPLLCON 0x04 +#define UPLLCON 0x08 +#define CLKCON 0x0c +#define CLKSLOW 0x10 +#define CLKDIVN 0x14 +#define CAMDIVN 0x18 + +/* the soc types */ +enum supported_socs { + S3C2410, + S3C2440, + S3C2442, +}; + +/* list of PLLs to be registered */ +enum s3c2410_plls { + mpll, upll, +}; + +static void __iomem *reg_base; + +#ifdef CONFIG_PM_SLEEP +static struct samsung_clk_reg_dump *s3c2410_save; + +/* + * list of controller registers to be saved and restored during a + * suspend/resume cycle. + */ +static unsigned long s3c2410_clk_regs[] __initdata = { + LOCKTIME, + MPLLCON, + UPLLCON, + CLKCON, + CLKSLOW, + CLKDIVN, + CAMDIVN, +}; + +static int s3c2410_clk_suspend(void) +{ + samsung_clk_save(reg_base, s3c2410_save, + ARRAY_SIZE(s3c2410_clk_regs)); + + return 0; +} + +static void s3c2410_clk_resume(void) +{ + samsung_clk_restore(reg_base, s3c2410_save, + ARRAY_SIZE(s3c2410_clk_regs)); +} + +static struct syscore_ops s3c2410_clk_syscore_ops = { + .suspend = s3c2410_clk_suspend, + .resume = s3c2410_clk_resume, +}; + +static void s3c2410_clk_sleep_init(void) +{ + s3c2410_save = samsung_clk_alloc_reg_dump(s3c2410_clk_regs, + ARRAY_SIZE(s3c2410_clk_regs)); + if (!s3c2410_save) { + pr_warn("%s: failed to allocate sleep save data, no sleep support!\n", + __func__); + return; + } + + register_syscore_ops(&s3c2410_clk_syscore_ops); + return; +} +#else +static void s3c2410_clk_sleep_init(void) {} +#endif + +PNAME(fclk_p) = { "mpll", "div_slow" }; + +struct samsung_mux_clock s3c2410_common_muxes[] __initdata = { + MUX(FCLK, "fclk", fclk_p, CLKSLOW, 4, 1), +}; + +static struct clk_div_table divslow_d[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 6 }, + { .val = 4, .div = 8 }, + { .val = 5, .div = 10 }, + { .val = 6, .div = 12 }, + { .val = 7, .div = 14 }, + { /* sentinel */ }, +}; + +struct samsung_div_clock s3c2410_common_dividers[] __initdata = { + DIV_T(0, "div_slow", "xti", CLKSLOW, 0, 3, divslow_d), + DIV(PCLK, "pclk", "hclk", CLKDIVN, 0, 1), +}; + +struct samsung_gate_clock s3c2410_common_gates[] __initdata = { + GATE(PCLK_SPI, "spi", "pclk", CLKCON, 18, 0, 0), + GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 17, 0, 0), + GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 16, 0, 0), + GATE(PCLK_ADC, "adc", "pclk", CLKCON, 15, 0, 0), + GATE(PCLK_RTC, "rtc", "pclk", CLKCON, 14, 0, 0), + GATE(PCLK_GPIO, "gpio", "pclk", CLKCON, 13, CLK_IGNORE_UNUSED, 0), + GATE(PCLK_UART2, "uart2", "pclk", CLKCON, 12, 0, 0), + GATE(PCLK_UART1, "uart1", "pclk", CLKCON, 11, 0, 0), + GATE(PCLK_UART0, "uart0", "pclk", CLKCON, 10, 0, 0), + GATE(PCLK_SDI, "sdi", "pclk", CLKCON, 9, 0, 0), + GATE(PCLK_PWM, "pwm", "pclk", CLKCON, 8, 0, 0), + GATE(HCLK_USBD, "usb-device", "hclk", CLKCON, 7, 0, 0), + GATE(HCLK_USBH, "usb-host", "hclk", CLKCON, 6, 0, 0), + GATE(HCLK_LCD, "lcd", "hclk", CLKCON, 5, 0, 0), + GATE(HCLK_NAND, "nand", "hclk", CLKCON, 4, 0, 0), +}; + +/* should be added _after_ the soc-specific clocks are created */ +struct samsung_clock_alias s3c2410_common_aliases[] __initdata = { + ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"), + ALIAS(PCLK_ADC, NULL, "adc"), + ALIAS(PCLK_RTC, NULL, "rtc"), + ALIAS(PCLK_PWM, NULL, "timers"), + ALIAS(HCLK_LCD, NULL, "lcd"), + ALIAS(HCLK_USBD, NULL, "usb-device"), + ALIAS(HCLK_USBH, NULL, "usb-host"), + ALIAS(UCLK, NULL, "usb-bus-host"), + ALIAS(UCLK, NULL, "usb-bus-gadget"), + ALIAS(ARMCLK, NULL, "armclk"), + ALIAS(UCLK, NULL, "uclk"), + ALIAS(HCLK, NULL, "hclk"), + ALIAS(MPLL, NULL, "mpll"), + ALIAS(FCLK, NULL, "fclk"), +}; + +/* S3C2410 specific clocks */ + +static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { + /* sorted in descending order */ + /* 2410A extras */ + PLL_35XX_RATE(270000000, 127, 1, 1), + PLL_35XX_RATE(268000000, 126, 1, 1), + PLL_35XX_RATE(266000000, 125, 1, 1), + PLL_35XX_RATE(226000000, 105, 1, 1), + PLL_35XX_RATE(210000000, 132, 2, 1), + /* 2410 common */ + PLL_35XX_RATE(203000000, 161, 3, 1), + PLL_35XX_RATE(192000000, 88, 1, 1), + PLL_35XX_RATE(186000000, 85, 1, 1), + PLL_35XX_RATE(180000000, 82, 1, 1), + PLL_35XX_RATE(170000000, 77, 1, 1), + PLL_35XX_RATE(158000000, 71, 1, 1), + PLL_35XX_RATE(152000000, 68, 1, 1), + PLL_35XX_RATE(147000000, 90, 2, 1), + PLL_35XX_RATE(135000000, 82, 2, 1), + PLL_35XX_RATE(124000000, 116, 1, 2), + PLL_35XX_RATE(118000000, 150, 2, 2), + PLL_35XX_RATE(113000000, 105, 1, 2), + PLL_35XX_RATE(101000000, 127, 2, 2), + PLL_35XX_RATE(90000000, 112, 2, 2), + PLL_35XX_RATE(85000000, 105, 2, 2), + PLL_35XX_RATE(79000000, 71, 1, 2), + PLL_35XX_RATE(68000000, 82, 2, 2), + PLL_35XX_RATE(56000000, 142, 2, 3), + PLL_35XX_RATE(48000000, 120, 2, 3), + PLL_35XX_RATE(51000000, 161, 3, 3), + PLL_35XX_RATE(45000000, 82, 1, 3), + PLL_35XX_RATE(34000000, 82, 2, 3), + { /* sentinel */ }, +}; + +static struct samsung_pll_clock s3c2410_plls[] __initdata = { + [mpll] = PLL(pll_s3c2410_mpll, MPLL, "mpll", "xti", + LOCKTIME, MPLLCON, NULL), + [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "xti", + LOCKTIME, UPLLCON, NULL), +}; + +struct samsung_div_clock s3c2410_dividers[] __initdata = { + DIV(HCLK, "hclk", "mpll", CLKDIVN, 1, 1), +}; + +struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = { + /* + * armclk is directly supplied by the fclk, without + * switching possibility like on the s3c244x below. + */ + FFACTOR(ARMCLK, "armclk", "fclk", 1, 1, 0), + + /* uclk is fed from the unmodified upll */ + FFACTOR(UCLK, "uclk", "upll", 1, 1, 0), +}; + +struct samsung_clock_alias s3c2410_aliases[] __initdata = { + ALIAS(PCLK_UART0, "s3c2410-uart.0", "uart"), + ALIAS(PCLK_UART1, "s3c2410-uart.1", "uart"), + ALIAS(PCLK_UART2, "s3c2410-uart.2", "uart"), + ALIAS(PCLK_UART0, "s3c2410-uart.0", "clk_uart_baud0"), + ALIAS(PCLK_UART1, "s3c2410-uart.1", "clk_uart_baud0"), + ALIAS(PCLK_UART2, "s3c2410-uart.2", "clk_uart_baud0"), + ALIAS(UCLK, NULL, "clk_uart_baud1"), +}; + +/* S3C244x specific clocks */ + +static struct samsung_pll_rate_table pll_s3c244x_12mhz_tbl[] __initdata = { + /* sorted in descending order */ + PLL_35XX_RATE(400000000, 0x5c, 1, 1), + PLL_35XX_RATE(390000000, 0x7a, 2, 1), + PLL_35XX_RATE(380000000, 0x57, 1, 1), + PLL_35XX_RATE(370000000, 0xb1, 4, 1), + PLL_35XX_RATE(360000000, 0x70, 2, 1), + PLL_35XX_RATE(350000000, 0xa7, 4, 1), + PLL_35XX_RATE(340000000, 0x4d, 1, 1), + PLL_35XX_RATE(330000000, 0x66, 2, 1), + PLL_35XX_RATE(320000000, 0x98, 4, 1), + PLL_35XX_RATE(310000000, 0x93, 4, 1), + PLL_35XX_RATE(300000000, 0x75, 3, 1), + PLL_35XX_RATE(240000000, 0x70, 1, 2), + PLL_35XX_RATE(230000000, 0x6b, 1, 2), + PLL_35XX_RATE(220000000, 0x66, 1, 2), + PLL_35XX_RATE(210000000, 0x84, 2, 2), + PLL_35XX_RATE(200000000, 0x5c, 1, 2), + PLL_35XX_RATE(190000000, 0x57, 1, 2), + PLL_35XX_RATE(180000000, 0x70, 2, 2), + PLL_35XX_RATE(170000000, 0x4d, 1, 2), + PLL_35XX_RATE(160000000, 0x98, 4, 2), + PLL_35XX_RATE(150000000, 0x75, 3, 2), + PLL_35XX_RATE(120000000, 0x70, 1, 3), + PLL_35XX_RATE(110000000, 0x66, 1, 3), + PLL_35XX_RATE(100000000, 0x5c, 1, 3), + PLL_35XX_RATE(90000000, 0x70, 2, 3), + PLL_35XX_RATE(80000000, 0x98, 4, 3), + PLL_35XX_RATE(75000000, 0x75, 3, 3), + { /* sentinel */ }, +}; + +static struct samsung_pll_clock s3c244x_common_plls[] __initdata = { + [mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti", + LOCKTIME, MPLLCON, NULL), + [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "xti", + LOCKTIME, UPLLCON, NULL), +}; + +PNAME(hclk_p) = { "fclk", "div_hclk_2", "div_hclk_4", "div_hclk_3" }; +PNAME(armclk_p) = { "fclk", "hclk" }; + +struct samsung_mux_clock s3c244x_common_muxes[] __initdata = { + MUX(HCLK, "hclk", hclk_p, CLKDIVN, 1, 2), + MUX(ARMCLK, "armclk", armclk_p, CAMDIVN, 12, 1), +}; + +struct samsung_fixed_factor_clock s3c244x_common_ffactor[] __initdata = { + FFACTOR(0, "div_hclk_2", "fclk", 1, 2, 0), + FFACTOR(0, "ff_cam", "div_cam", 2, 1, CLK_SET_RATE_PARENT), +}; + +static struct clk_div_table div_hclk_4_d[] = { + { .val = 0, .div = 4 }, + { .val = 1, .div = 8 }, + { /* sentinel */ }, +}; + +static struct clk_div_table div_hclk_3_d[] = { + { .val = 0, .div = 3 }, + { .val = 1, .div = 6 }, + { /* sentinel */ }, +}; + +struct samsung_div_clock s3c244x_common_dividers[] __initdata = { + DIV(UCLK, "uclk", "upll", CLKDIVN, 3, 1), + DIV(0, "div_hclk", "fclk", CLKDIVN, 1, 1), + DIV_T(0, "div_hclk_4", "fclk", CAMDIVN, 9, 1, div_hclk_4_d), + DIV_T(0, "div_hclk_3", "fclk", CAMDIVN, 8, 1, div_hclk_3_d), + DIV(0, "div_cam", "upll", CAMDIVN, 0, 3), +}; + +struct samsung_gate_clock s3c244x_common_gates[] __initdata = { + GATE(HCLK_CAM, "cam", "hclk", CLKCON, 19, 0, 0), +}; + +struct samsung_clock_alias s3c244x_common_aliases[] __initdata = { + ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"), + ALIAS(PCLK_UART1, "s3c2440-uart.1", "uart"), + ALIAS(PCLK_UART2, "s3c2440-uart.2", "uart"), + ALIAS(PCLK_UART0, "s3c2440-uart.0", "clk_uart_baud2"), + ALIAS(PCLK_UART1, "s3c2440-uart.1", "clk_uart_baud2"), + ALIAS(PCLK_UART2, "s3c2440-uart.2", "clk_uart_baud2"), + ALIAS(HCLK_CAM, NULL, "camif"), + ALIAS(CAMIF, NULL, "camif-upll"), +}; + +/* S3C2440 specific clocks */ + +PNAME(s3c2440_camif_p) = { "upll", "ff_cam" }; + +struct samsung_mux_clock s3c2440_muxes[] __initdata = { + MUX(CAMIF, "camif", s3c2440_camif_p, CAMDIVN, 4, 1), +}; + +struct samsung_gate_clock s3c2440_gates[] __initdata = { + GATE(PCLK_AC97, "ac97", "pclk", CLKCON, 20, 0, 0), +}; + +/* S3C2442 specific clocks */ + +struct samsung_fixed_factor_clock s3c2442_ffactor[] __initdata = { + FFACTOR(0, "upll_3", "upll", 1, 3, 0), +}; + +PNAME(s3c2442_camif_p) = { "upll", "ff_cam", "upll", "upll_3" }; + +struct samsung_mux_clock s3c2442_muxes[] __initdata = { + MUX(CAMIF, "camif", s3c2442_camif_p, CAMDIVN, 4, 2), +}; + +/* + * fixed rate clocks generated outside the soc + * Only necessary until the devicetree-move is complete + */ +#define XTI 1 +struct samsung_fixed_rate_clock s3c2410_common_frate_clks[] __initdata = { + FRATE(XTI, "xti", NULL, CLK_IS_ROOT, 0), +}; + +static void __init s3c2410_common_clk_register_fixed_ext(unsigned long xti_f) +{ + struct samsung_clock_alias xti_alias = ALIAS(XTI, NULL, "xtal"); + + s3c2410_common_frate_clks[0].fixed_rate = xti_f; + samsung_clk_register_fixed_rate(s3c2410_common_frate_clks, + ARRAY_SIZE(s3c2410_common_frate_clks)); + + samsung_clk_register_alias(&xti_alias, 1); +} + +void __init s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f, + int current_soc, + void __iomem *base) +{ + reg_base = base; + + if (np) { + reg_base = of_iomap(np, 0); + if (!reg_base) + panic("%s: failed to map registers\n", __func__); + } + + samsung_clk_init(np, reg_base, NR_CLKS); + + /* Register external clocks only in non-dt cases */ + if (!np) + s3c2410_common_clk_register_fixed_ext(xti_f); + + if (current_soc == 2410) { + if (_get_rate("xti") == 12 * MHZ) { + s3c2410_plls[mpll].rate_table = pll_s3c2410_12mhz_tbl; + s3c2410_plls[upll].rate_table = pll_s3c2410_12mhz_tbl; + } + + /* Register PLLs. */ + samsung_clk_register_pll(s3c2410_plls, + ARRAY_SIZE(s3c2410_plls), reg_base); + + } else { /* S3C2440, S3C2442 */ + if (_get_rate("xti") == 12 * MHZ) { + /* + * plls follow different calculation schemes, with the + * upll following the same scheme as the s3c2410 plls + */ + s3c244x_common_plls[mpll].rate_table = + pll_s3c244x_12mhz_tbl; + s3c244x_common_plls[upll].rate_table = + pll_s3c2410_12mhz_tbl; + } + + /* Register PLLs. */ + samsung_clk_register_pll(s3c244x_common_plls, + ARRAY_SIZE(s3c244x_common_plls), reg_base); + } + + /* Register common internal clocks. */ + samsung_clk_register_mux(s3c2410_common_muxes, + ARRAY_SIZE(s3c2410_common_muxes)); + samsung_clk_register_div(s3c2410_common_dividers, + ARRAY_SIZE(s3c2410_common_dividers)); + samsung_clk_register_gate(s3c2410_common_gates, + ARRAY_SIZE(s3c2410_common_gates)); + + if (current_soc == S3C2440 || current_soc == S3C2442) { + samsung_clk_register_div(s3c244x_common_dividers, + ARRAY_SIZE(s3c244x_common_dividers)); + samsung_clk_register_gate(s3c244x_common_gates, + ARRAY_SIZE(s3c244x_common_gates)); + samsung_clk_register_mux(s3c244x_common_muxes, + ARRAY_SIZE(s3c244x_common_muxes)); + samsung_clk_register_fixed_factor(s3c244x_common_ffactor, + ARRAY_SIZE(s3c244x_common_ffactor)); + } + + /* Register SoC-specific clocks. */ + switch (current_soc) { + case S3C2410: + samsung_clk_register_div(s3c2410_dividers, + ARRAY_SIZE(s3c2410_dividers)); + samsung_clk_register_fixed_factor(s3c2410_ffactor, + ARRAY_SIZE(s3c2410_ffactor)); + samsung_clk_register_alias(s3c2410_aliases, + ARRAY_SIZE(s3c2410_common_aliases)); + break; + case S3C2440: + samsung_clk_register_mux(s3c2440_muxes, + ARRAY_SIZE(s3c2440_muxes)); + samsung_clk_register_gate(s3c2440_gates, + ARRAY_SIZE(s3c2440_gates)); + break; + case S3C2442: + samsung_clk_register_mux(s3c2442_muxes, + ARRAY_SIZE(s3c2442_muxes)); + samsung_clk_register_fixed_factor(s3c2442_ffactor, + ARRAY_SIZE(s3c2442_ffactor)); + break; + } + + /* + * Register common aliases at the end, as some of the aliased clocks + * are SoC specific. + */ + samsung_clk_register_alias(s3c2410_common_aliases, + ARRAY_SIZE(s3c2410_common_aliases)); + + if (current_soc == S3C2440 || current_soc == S3C2442) { + samsung_clk_register_alias(s3c244x_common_aliases, + ARRAY_SIZE(s3c244x_common_aliases)); + } + + s3c2410_clk_sleep_init(); +} + +static void __init s3c2410_clk_init(struct device_node *np) +{ + s3c2410_common_clk_init(np, 0, S3C2410, 0); +} +CLK_OF_DECLARE(s3c2410_clk, "samsung,s3c2410-clock", s3c2410_clk_init); + +static void __init s3c2440_clk_init(struct device_node *np) +{ + s3c2410_common_clk_init(np, 0, S3C2440, 0); +} +CLK_OF_DECLARE(s3c2440_clk, "samsung,s3c2440-clock", s3c2440_clk_init); + +static void __init s3c2442_clk_init(struct device_node *np) +{ + s3c2410_common_clk_init(np, 0, S3C2442, 0); +} +CLK_OF_DECLARE(s3c2442_clk, "samsung,s3c2442-clock", s3c2442_clk_init); diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c new file mode 100644 index 00000000000000..0f11a07d5c0107 --- /dev/null +++ b/drivers/clk/samsung/clk-s3c2412.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2013 Heiko Stuebner + * + * 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. + * + * Common Clock Framework support for S3C2412 and S3C2413. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" +#include "clk-pll.h" + +#define LOCKTIME 0x00 +#define MPLLCON 0x04 +#define UPLLCON 0x08 +#define CLKCON 0x0c +#define CLKDIVN 0x14 +#define CLKSRC 0x1c + +/* list of PLLs to be registered */ +enum s3c2412_plls { + mpll, upll, +}; + +static void __iomem *reg_base; + +#ifdef CONFIG_PM_SLEEP +static struct samsung_clk_reg_dump *s3c2412_save; + +/* + * list of controller registers to be saved and restored during a + * suspend/resume cycle. + */ +static unsigned long s3c2412_clk_regs[] __initdata = { + LOCKTIME, + MPLLCON, + UPLLCON, + CLKCON, + CLKDIVN, + CLKSRC, +}; + +static int s3c2412_clk_suspend(void) +{ + samsung_clk_save(reg_base, s3c2412_save, + ARRAY_SIZE(s3c2412_clk_regs)); + + return 0; +} + +static void s3c2412_clk_resume(void) +{ + samsung_clk_restore(reg_base, s3c2412_save, + ARRAY_SIZE(s3c2412_clk_regs)); +} + +static struct syscore_ops s3c2412_clk_syscore_ops = { + .suspend = s3c2412_clk_suspend, + .resume = s3c2412_clk_resume, +}; + +static void s3c2412_clk_sleep_init(void) +{ + s3c2412_save = samsung_clk_alloc_reg_dump(s3c2412_clk_regs, + ARRAY_SIZE(s3c2412_clk_regs)); + if (!s3c2412_save) { + pr_warn("%s: failed to allocate sleep save data, no sleep support!\n", + __func__); + return; + } + + register_syscore_ops(&s3c2412_clk_syscore_ops); + return; +} +#else +static void s3c2412_clk_sleep_init(void) {} +#endif + +static struct clk_div_table divxti_d[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 6 }, + { .val = 4, .div = 8 }, + { .val = 5, .div = 10 }, + { .val = 6, .div = 12 }, + { .val = 7, .div = 14 }, + { /* sentinel */ }, +}; + +struct samsung_div_clock s3c2412_dividers[] __initdata = { + DIV_T(0, "div_xti", "xti", CLKSRC, 0, 3, divxti_d), + DIV(0, "div_cam", "mux_cam", CLKDIVN, 16, 4), + DIV(0, "div_i2s", "mux_i2s", CLKDIVN, 12, 4), + DIV(0, "div_uart", "mux_uart", CLKDIVN, 8, 4), + DIV(0, "div_usb", "mux_usb", CLKDIVN, 6, 1), + DIV(0, "div_hclk_half", "hclk", CLKDIVN, 5, 1), + DIV(ARMDIV, "armdiv", "msysclk", CLKDIVN, 3, 1), + DIV(PCLK, "pclk", "hclk", CLKDIVN, 2, 1), + DIV(HCLK, "hclk", "armdiv", CLKDIVN, 0, 2), +}; + +struct samsung_fixed_factor_clock s3c2412_ffactor[] __initdata = { + FFACTOR(0, "ff_hclk", "hclk", 2, 1, CLK_SET_RATE_PARENT), +}; + +/* + * The first two use the OM[4] setting, which is not readable from + * software, so assume it is set to xti. + */ +PNAME(erefclk_p) = { "xti", "xti", "xti", "ext" }; +PNAME(urefclk_p) = { "xti", "xti", "xti", "ext" }; + +PNAME(camclk_p) = { "usysclk", "hclk" }; +PNAME(usbclk_p) = { "usysclk", "hclk" }; +PNAME(i2sclk_p) = { "erefclk", "mpll" }; +PNAME(uartclk_p) = { "erefclk", "mpll" }; +PNAME(usysclk_p) = { "urefclk", "upll" }; +PNAME(msysclk_p) = { "mdivclk", "mpll" }; +PNAME(mdivclk_p) = { "xti", "div_xti" }; +PNAME(armclk_p) = { "armdiv", "hclk" }; + +struct samsung_mux_clock s3c2412_muxes[] __initdata = { + MUX(0, "erefclk", erefclk_p, CLKSRC, 14, 2), + MUX(0, "urefclk", urefclk_p, CLKSRC, 12, 2), + MUX(0, "mux_cam", camclk_p, CLKSRC, 11, 1), + MUX(0, "mux_usb", usbclk_p, CLKSRC, 10, 1), + MUX(0, "mux_i2s", i2sclk_p, CLKSRC, 9, 1), + MUX(0, "mux_uart", uartclk_p, CLKSRC, 8, 1), + MUX(USYSCLK, "usysclk", usysclk_p, CLKSRC, 5, 1), + MUX(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1), + MUX(MDIVCLK, "mdivclk", mdivclk_p, CLKSRC, 3, 1), + MUX(ARMCLK, "armclk", armclk_p, CLKDIVN, 4, 1), +}; + +static struct samsung_pll_clock s3c2412_plls[] __initdata = { + [mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti", + LOCKTIME, MPLLCON, NULL), + [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk", + LOCKTIME, UPLLCON, NULL), +}; + +struct samsung_gate_clock s3c2412_gates[] __initdata = { + GATE(PCLK_WDT, "wdt", "pclk", CLKCON, 28, 0, 0), + GATE(PCLK_SPI, "spi", "pclk", CLKCON, 27, 0, 0), + GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 26, 0, 0), + GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 25, 0, 0), + GATE(PCLK_ADC, "adc", "pclk", CLKCON, 24, 0, 0), + GATE(PCLK_RTC, "rtc", "pclk", CLKCON, 23, 0, 0), + GATE(PCLK_GPIO, "gpio", "pclk", CLKCON, 22, CLK_IGNORE_UNUSED, 0), + GATE(PCLK_UART2, "uart2", "pclk", CLKCON, 21, 0, 0), + GATE(PCLK_UART1, "uart1", "pclk", CLKCON, 20, 0, 0), + GATE(PCLK_UART0, "uart0", "pclk", CLKCON, 19, 0, 0), + GATE(PCLK_SDI, "sdi", "pclk", CLKCON, 18, 0, 0), + GATE(PCLK_PWM, "pwm", "pclk", CLKCON, 17, 0, 0), + GATE(PCLK_USBD, "usb-device", "pclk", CLKCON, 16, 0, 0), + GATE(SCLK_CAM, "sclk_cam", "div_cam", CLKCON, 15, 0, 0), + GATE(SCLK_UART, "sclk_uart", "div_uart", CLKCON, 14, 0, 0), + GATE(SCLK_I2S, "sclk_i2s", "div_i2s", CLKCON, 13, 0, 0), + GATE(SCLK_USBH, "sclk_usbh", "div_usb", CLKCON, 12, 0, 0), + GATE(SCLK_USBD, "sclk_usbd", "div_usb", CLKCON, 11, 0, 0), + GATE(HCLK_HALF, "hclk_half", "div_hclk_half", CLKCON, 10, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_X2, "hclkx2", "ff_hclk", CLKCON, 9, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_SDRAM, "sdram", "hclk", CLKCON, 8, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_USBH, "usb-host", "hclk", CLKCON, 6, 0, 0), + GATE(HCLK_LCD, "lcd", "hclk", CLKCON, 5, 0, 0), + GATE(HCLK_NAND, "nand", "hclk", CLKCON, 4, 0, 0), + GATE(HCLK_DMA3, "dma3", "hclk", CLKCON, 3, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_DMA2, "dma2", "hclk", CLKCON, 2, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_DMA1, "dma1", "hclk", CLKCON, 1, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_DMA0, "dma0", "hclk", CLKCON, 0, CLK_IGNORE_UNUSED, 0), +}; + +struct samsung_clock_alias s3c2412_aliases[] __initdata = { + ALIAS(PCLK_UART0, "s3c2412-uart.0", "uart"), + ALIAS(PCLK_UART1, "s3c2412-uart.1", "uart"), + ALIAS(PCLK_UART2, "s3c2412-uart.2", "uart"), + ALIAS(PCLK_UART0, "s3c2412-uart.0", "clk_uart_baud2"), + ALIAS(PCLK_UART1, "s3c2412-uart.1", "clk_uart_baud2"), + ALIAS(PCLK_UART2, "s3c2412-uart.2", "clk_uart_baud2"), + ALIAS(SCLK_UART, NULL, "clk_uart_baud3"), + ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"), + ALIAS(PCLK_ADC, NULL, "adc"), + ALIAS(PCLK_RTC, NULL, "rtc"), + ALIAS(PCLK_PWM, NULL, "timers"), + ALIAS(HCLK_LCD, NULL, "lcd"), + ALIAS(PCLK_USBD, NULL, "usb-device"), + ALIAS(SCLK_USBD, NULL, "usb-bus-gadget"), + ALIAS(HCLK_USBH, NULL, "usb-host"), + ALIAS(SCLK_USBH, NULL, "usb-bus-host"), + ALIAS(ARMCLK, NULL, "armclk"), + ALIAS(HCLK, NULL, "hclk"), + ALIAS(MPLL, NULL, "mpll"), + ALIAS(MSYSCLK, NULL, "fclk"), +}; + +/* + * fixed rate clocks generated outside the soc + * Only necessary until the devicetree-move is complete + */ +#define XTI 1 +struct samsung_fixed_rate_clock s3c2412_common_frate_clks[] __initdata = { + FRATE(XTI, "xti", NULL, CLK_IS_ROOT, 0), + FRATE(0, "ext", NULL, CLK_IS_ROOT, 0), +}; + +static void __init s3c2412_common_clk_register_fixed_ext(unsigned long xti_f, + unsigned long ext_f) +{ + /* xtal alias is necessary for the current cpufreq driver */ + struct samsung_clock_alias xti_alias = ALIAS(XTI, NULL, "xtal"); + + s3c2412_common_frate_clks[0].fixed_rate = xti_f; + s3c2412_common_frate_clks[1].fixed_rate = ext_f; + samsung_clk_register_fixed_rate(s3c2412_common_frate_clks, + ARRAY_SIZE(s3c2412_common_frate_clks)); + + samsung_clk_register_alias(&xti_alias, 1); +} + +void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, + unsigned long ext_f, void __iomem *base) +{ + reg_base = base; + + if (np) { + reg_base = of_iomap(np, 0); + if (!reg_base) + panic("%s: failed to map registers\n", __func__); + } + + samsung_clk_init(np, reg_base, NR_CLKS); + + /* Register external clocks only in non-dt cases */ + if (!np) + s3c2412_common_clk_register_fixed_ext(xti_f, ext_f); + + /* Register PLLs. */ + samsung_clk_register_pll(s3c2412_plls, ARRAY_SIZE(s3c2412_plls), + reg_base); + + /* Register common internal clocks. */ + samsung_clk_register_mux(s3c2412_muxes, ARRAY_SIZE(s3c2412_muxes)); + samsung_clk_register_div(s3c2412_dividers, + ARRAY_SIZE(s3c2412_dividers)); + samsung_clk_register_gate(s3c2412_gates, ARRAY_SIZE(s3c2412_gates)); + samsung_clk_register_fixed_factor(s3c2412_ffactor, + ARRAY_SIZE(s3c2412_ffactor)); + samsung_clk_register_alias(s3c2412_aliases, + ARRAY_SIZE(s3c2412_aliases)); + + s3c2412_clk_sleep_init(); +} + +static void __init s3c2412_clk_init(struct device_node *np) +{ + s3c2412_common_clk_init(np, 0, 0, 0); +} +CLK_OF_DECLARE(s3c2412_clk, "samsung,s3c2412-clock", s3c2412_clk_init); diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c new file mode 100644 index 00000000000000..8e4f4517e95c37 --- /dev/null +++ b/drivers/clk/samsung/clk-s3c2443.c @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2013 Heiko Stuebner + * + * 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. + * + * Common Clock Framework support for S3C2443 and following SoCs. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" +#include "clk-pll.h" + +/* S3C2416 clock controller register offsets */ +#define LOCKCON0 0x00 +#define LOCKCON1 0x04 +#define MPLLCON 0x10 +#define EPLLCON 0x18 +#define EPLLCON_K 0x1C +#define CLKSRC 0x20 +#define CLKDIV0 0x24 +#define CLKDIV1 0x28 +#define CLKDIV2 0x2C +#define HCLKCON 0x30 +#define PCLKCON 0x34 +#define SCLKCON 0x38 + +/* the soc types */ +enum supported_socs { + S3C2416, + S3C2443, + S3C2450, +}; + +/* list of PLLs to be registered */ +enum s3c2443_plls { + mpll, epll, +}; + +static void __iomem *reg_base; + +#ifdef CONFIG_PM_SLEEP +static struct samsung_clk_reg_dump *s3c2443_save; + +/* + * list of controller registers to be saved and restored during a + * suspend/resume cycle. + */ +static unsigned long s3c2443_clk_regs[] __initdata = { + LOCKCON0, + LOCKCON1, + MPLLCON, + EPLLCON, + EPLLCON_K, + CLKSRC, + CLKDIV0, + CLKDIV1, + CLKDIV2, + PCLKCON, + HCLKCON, + SCLKCON, +}; + +static int s3c2443_clk_suspend(void) +{ + samsung_clk_save(reg_base, s3c2443_save, + ARRAY_SIZE(s3c2443_clk_regs)); + + return 0; +} + +static void s3c2443_clk_resume(void) +{ + samsung_clk_restore(reg_base, s3c2443_save, + ARRAY_SIZE(s3c2443_clk_regs)); +} + +static struct syscore_ops s3c2443_clk_syscore_ops = { + .suspend = s3c2443_clk_suspend, + .resume = s3c2443_clk_resume, +}; + +static void s3c2443_clk_sleep_init(void) +{ + s3c2443_save = samsung_clk_alloc_reg_dump(s3c2443_clk_regs, + ARRAY_SIZE(s3c2443_clk_regs)); + if (!s3c2443_save) { + pr_warn("%s: failed to allocate sleep save data, no sleep support!\n", + __func__); + return; + } + + register_syscore_ops(&s3c2443_clk_syscore_ops); + return; +} +#else +static void s3c2443_clk_sleep_init(void) {} +#endif + +PNAME(epllref_p) = { "mpllref", "mpllref", "xti", "ext" }; +PNAME(esysclk_p) = { "epllref", "epll" }; +PNAME(mpllref_p) = { "xti", "mdivclk" }; +PNAME(msysclk_p) = { "mpllref", "mpll" }; +PNAME(armclk_p) = { "armdiv" , "hclk" }; +PNAME(i2s0_p) = { "div_i2s0", "ext_i2s", "epllref", "epllref" }; + +struct samsung_mux_clock s3c2443_common_muxes[] __initdata = { + MUX(0, "epllref", epllref_p, CLKSRC, 7, 2), + MUX(ESYSCLK, "esysclk", esysclk_p, CLKSRC, 6, 1), + MUX(0, "mpllref", mpllref_p, CLKSRC, 3, 1), + MUX_A(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1, "msysclk"), + MUX_A(ARMCLK, "armclk", armclk_p, CLKDIV0, 13, 1, "armclk"), + MUX(0, "mux_i2s0", i2s0_p, CLKSRC, 14, 2), +}; + +static struct clk_div_table hclk_d[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 3, .div = 4 }, + { /* sentinel */ }, +}; + +static struct clk_div_table mdivclk_d[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 3 }, + { .val = 2, .div = 5 }, + { .val = 3, .div = 7 }, + { .val = 4, .div = 9 }, + { .val = 5, .div = 11 }, + { .val = 6, .div = 13 }, + { .val = 7, .div = 15 }, + { /* sentinel */ }, +}; + +struct samsung_div_clock s3c2443_common_dividers[] __initdata = { + DIV_T(0, "mdivclk", "xti", CLKDIV0, 6, 3, mdivclk_d), + DIV(0, "prediv", "msysclk", CLKDIV0, 4, 2), + DIV_T(HCLK, "hclk", "prediv", CLKDIV0, 0, 2, hclk_d), + DIV(PCLK, "pclk", "hclk", CLKDIV0, 2, 1), + DIV(0, "div_hsspi0_epll", "esysclk", CLKDIV1, 24, 2), + DIV(0, "div_fimd", "esysclk", CLKDIV1, 16, 8), + DIV(0, "div_i2s0", "esysclk", CLKDIV1, 12, 4), + DIV(0, "div_uart", "esysclk", CLKDIV1, 8, 4), + DIV(0, "div_hsmmc1", "esysclk", CLKDIV1, 6, 2), + DIV(0, "div_usbhost", "esysclk", CLKDIV1, 4, 2), +}; + +struct samsung_gate_clock s3c2443_common_gates[] __initdata = { + GATE(SCLK_HSMMC_EXT, "sclk_hsmmcext", "ext", SCLKCON, 13, 0, 0), + GATE(SCLK_HSMMC1, "sclk_hsmmc1", "div_hsmmc1", SCLKCON, 12, 0, 0), + GATE(SCLK_FIMD, "sclk_fimd", "div_fimd", SCLKCON, 10, 0, 0), + GATE(SCLK_I2S0, "sclk_i2s0", "mux_i2s0", SCLKCON, 9, 0, 0), + GATE(SCLK_UART, "sclk_uart", "div_uart", SCLKCON, 8, 0, 0), + GATE(SCLK_USBH, "sclk_usbhost", "div_usbhost", SCLKCON, 1, 0, 0), + GATE(HCLK_DRAM, "dram", "hclk", HCLKCON, 19, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_SSMC, "ssmc", "hclk", HCLKCON, 18, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_HSMMC1, "hsmmc1", "hclk", HCLKCON, 16, 0, 0), + GATE(HCLK_USBD, "usb-device", "hclk", HCLKCON, 12, 0, 0), + GATE(HCLK_USBH, "usb-host", "hclk", HCLKCON, 11, 0, 0), + GATE(HCLK_LCD, "lcd", "hclk", HCLKCON, 9, 0, 0), + GATE(HCLK_DMA5, "dma5", "hclk", HCLKCON, 5, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_DMA4, "dma4", "hclk", HCLKCON, 4, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_DMA3, "dma3", "hclk", HCLKCON, 3, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_DMA2, "dma2", "hclk", HCLKCON, 2, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_DMA1, "dma1", "hclk", HCLKCON, 1, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_DMA0, "dma0", "hclk", HCLKCON, 0, CLK_IGNORE_UNUSED, 0), + GATE(PCLK_GPIO, "gpio", "pclk", PCLKCON, 13, CLK_IGNORE_UNUSED, 0), + GATE(PCLK_RTC, "rtc", "pclk", PCLKCON, 12, 0, 0), + GATE(PCLK_WDT, "wdt", "pclk", PCLKCON, 11, 0, 0), + GATE(PCLK_PWM, "pwm", "pclk", PCLKCON, 10, 0, 0), + GATE(PCLK_I2S0, "i2s0", "pclk", PCLKCON, 9, 0, 0), + GATE(PCLK_AC97, "ac97", "pclk", PCLKCON, 8, 0, 0), + GATE(PCLK_ADC, "adc", "pclk", PCLKCON, 7, 0, 0), + GATE(PCLK_SPI0, "spi0", "pclk", PCLKCON, 6, 0, 0), + GATE(PCLK_I2C0, "i2c0", "pclk", PCLKCON, 4, 0, 0), + GATE(PCLK_UART3, "uart3", "pclk", PCLKCON, 3, 0, 0), + GATE(PCLK_UART2, "uart2", "pclk", PCLKCON, 2, 0, 0), + GATE(PCLK_UART1, "uart1", "pclk", PCLKCON, 1, 0, 0), + GATE(PCLK_UART0, "uart0", "pclk", PCLKCON, 0, 0, 0), +}; + +struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { + ALIAS(HCLK, NULL, "hclk"), + ALIAS(HCLK_SSMC, NULL, "nand"), + ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"), + ALIAS(PCLK_UART1, "s3c2440-uart.1", "uart"), + ALIAS(PCLK_UART2, "s3c2440-uart.2", "uart"), + ALIAS(PCLK_UART3, "s3c2440-uart.3", "uart"), + ALIAS(PCLK_UART0, "s3c2440-uart.0", "clk_uart_baud2"), + ALIAS(PCLK_UART1, "s3c2440-uart.1", "clk_uart_baud2"), + ALIAS(PCLK_UART2, "s3c2440-uart.2", "clk_uart_baud2"), + ALIAS(PCLK_UART3, "s3c2440-uart.3", "clk_uart_baud2"), + ALIAS(SCLK_UART, NULL, "clk_uart_baud3"), + ALIAS(PCLK_PWM, NULL, "timers"), + ALIAS(PCLK_RTC, NULL, "rtc"), + ALIAS(PCLK_WDT, NULL, "watchdog"), + ALIAS(PCLK_ADC, NULL, "adc"), + ALIAS(PCLK_I2C0, "s3c2410-i2c.0", "i2c"), + ALIAS(HCLK_USBD, NULL, "usb-device"), + ALIAS(HCLK_USBH, NULL, "usb-host"), + ALIAS(SCLK_USBH, NULL, "usb-bus-host"), + ALIAS(PCLK_SPI0, "s3c2443-spi.0", "spi"), + ALIAS(PCLK_SPI0, "s3c2443-spi.0", "spi_busclk0"), + ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "hsmmc"), + ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"), + ALIAS(PCLK_I2S0, "samsung-i2s.0", "iis"), + ALIAS(SCLK_I2S0, NULL, "i2s-if"), + ALIAS(HCLK_LCD, NULL, "lcd"), + ALIAS(SCLK_FIMD, NULL, "sclk_fimd"), +}; + +/* S3C2416 specific clocks */ + +static struct samsung_pll_clock s3c2416_pll_clks[] __initdata = { + [mpll] = PLL(pll_6552_s3c2416, 0, "mpll", "mpllref", + LOCKCON0, MPLLCON, NULL), + [epll] = PLL(pll_6553, 0, "epll", "epllref", + LOCKCON1, EPLLCON, NULL), +}; + +PNAME(s3c2416_hsmmc0_p) = { "sclk_hsmmc0", "sclk_hsmmcext" }; +PNAME(s3c2416_hsmmc1_p) = { "sclk_hsmmc1", "sclk_hsmmcext" }; +PNAME(s3c2416_hsspi0_p) = { "hsspi0_epll", "hsspi0_mpll" }; + +static struct clk_div_table armdiv_s3c2416_d[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 3 }, + { .val = 3, .div = 4 }, + { .val = 5, .div = 6 }, + { .val = 7, .div = 8 }, + { /* sentinel */ }, +}; + +struct samsung_div_clock s3c2416_dividers[] __initdata = { + DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 3, armdiv_s3c2416_d), + DIV(0, "div_hsspi0_mpll", "msysclk", CLKDIV2, 0, 4), + DIV(0, "div_hsmmc0", "esysclk", CLKDIV2, 6, 2), +}; + +struct samsung_mux_clock s3c2416_muxes[] __initdata = { + MUX(MUX_HSMMC0, "mux_hsmmc0", s3c2416_hsmmc0_p, CLKSRC, 16, 1), + MUX(MUX_HSMMC1, "mux_hsmmc1", s3c2416_hsmmc1_p, CLKSRC, 17, 1), + MUX(MUX_HSSPI0, "mux_hsspi0", s3c2416_hsspi0_p, CLKSRC, 18, 1), +}; + +struct samsung_gate_clock s3c2416_gates[] __initdata = { + GATE(0, "hsspi0_mpll", "div_hsspi0_mpll", SCLKCON, 19, 0, 0), + GATE(0, "hsspi0_epll", "div_hsspi0_epll", SCLKCON, 14, 0, 0), + GATE(0, "sclk_hsmmc0", "div_hsmmc0", SCLKCON, 6, 0, 0), + GATE(HCLK_2D, "2d", "hclk", HCLKCON, 20, 0, 0), + GATE(HCLK_HSMMC0, "hsmmc0", "hclk", HCLKCON, 15, 0, 0), + GATE(HCLK_IROM, "irom", "hclk", HCLKCON, 13, CLK_IGNORE_UNUSED, 0), + GATE(PCLK_PCM, "pcm", "pclk", PCLKCON, 19, 0, 0), +}; + +struct samsung_clock_alias s3c2416_aliases[] __initdata = { + ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"), + ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"), + ALIAS(MUX_HSMMC0, "s3c-sdhci.0", "mmc_busclk.2"), + ALIAS(MUX_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"), + ALIAS(MUX_HSSPI0, "s3c2443-spi.0", "spi_busclk2"), + ALIAS(ARMDIV, NULL, "armdiv"), +}; + +/* S3C2443 specific clocks */ + +static struct samsung_pll_clock s3c2443_pll_clks[] __initdata = { + [mpll] = PLL(pll_3000, 0, "mpll", "mpllref", + LOCKCON0, MPLLCON, NULL), + [epll] = PLL(pll_2126, 0, "epll", "epllref", + LOCKCON1, EPLLCON, NULL), +}; + +static struct clk_div_table armdiv_s3c2443_d[] = { + { .val = 0, .div = 1 }, + { .val = 8, .div = 2 }, + { .val = 2, .div = 3 }, + { .val = 9, .div = 4 }, + { .val = 10, .div = 6 }, + { .val = 11, .div = 8 }, + { .val = 13, .div = 12 }, + { .val = 15, .div = 16 }, + { /* sentinel */ }, +}; + +struct samsung_div_clock s3c2443_dividers[] __initdata = { + DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 4, armdiv_s3c2443_d), + DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4), +}; + +struct samsung_gate_clock s3c2443_gates[] __initdata = { + GATE(SCLK_HSSPI0, "sclk_hsspi0", "div_hsspi0_epll", SCLKCON, 14, 0, 0), + GATE(SCLK_CAM, "sclk_cam", "div_cam", SCLKCON, 11, 0, 0), + GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0), + GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 15, 0, 0), + GATE(PCLK_SDI, "sdi", "pclk", PCLKCON, 5, 0, 0), +}; + +struct samsung_clock_alias s3c2443_aliases[] __initdata = { + ALIAS(SCLK_HSSPI0, "s3c2443-spi.0", "spi_busclk2"), + ALIAS(SCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"), + ALIAS(SCLK_CAM, NULL, "camif-upll"), + ALIAS(PCLK_SPI1, "s3c2410-spi.0", "spi"), + ALIAS(PCLK_SDI, NULL, "sdi"), + ALIAS(HCLK_CFC, NULL, "cfc"), + ALIAS(ARMDIV, NULL, "armdiv"), +}; + +/* S3C2450 specific clocks */ + +PNAME(s3c2450_cam_p) = { "div_cam", "hclk" }; +PNAME(s3c2450_hsspi1_p) = { "hsspi1_epll", "hsspi1_mpll" }; +PNAME(i2s1_p) = { "div_i2s1", "ext_i2s", "epllref", "epllref" }; + +struct samsung_div_clock s3c2450_dividers[] __initdata = { + DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4), + DIV(0, "div_hsspi1_epll", "esysclk", CLKDIV2, 24, 2), + DIV(0, "div_hsspi1_mpll", "msysclk", CLKDIV2, 16, 4), + DIV(0, "div_i2s1", "esysclk", CLKDIV2, 12, 4), +}; + +struct samsung_mux_clock s3c2450_muxes[] __initdata = { + MUX(0, "mux_cam", s3c2450_cam_p, CLKSRC, 20, 1), + MUX(MUX_HSSPI1, "mux_hsspi1", s3c2450_hsspi1_p, CLKSRC, 19, 1), + MUX(0, "mux_i2s1", i2s1_p, CLKSRC, 12, 2), +}; + +struct samsung_gate_clock s3c2450_gates[] __initdata = { + GATE(SCLK_I2S1, "sclk_i2s1", "div_i2s1", SCLKCON, 5, 0, 0), + GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, 0, 0), + GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0), + GATE(HCLK_DMA7, "dma7", "hclk", HCLKCON, 7, CLK_IGNORE_UNUSED, 0), + GATE(HCLK_DMA6, "dma6", "hclk", HCLKCON, 6, CLK_IGNORE_UNUSED, 0), + GATE(PCLK_I2S1, "i2s1", "pclk", PCLKCON, 17, 0, 0), + GATE(PCLK_I2C1, "i2c1", "pclk", PCLKCON, 16, 0, 0), + GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 14, 0, 0), +}; + +struct samsung_clock_alias s3c2450_aliases[] __initdata = { + ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi"), + ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi_busclk0"), + ALIAS(MUX_HSSPI1, "s3c2443-spi.1", "spi_busclk2"), + ALIAS(PCLK_I2C1, "s3c2410-i2c.1", "i2c"), +}; + +/* + * fixed rate clocks generated outside the soc + * Only necessary until the devicetree-move is complete + */ +struct samsung_fixed_rate_clock s3c2443_common_frate_clks[] __initdata = { + FRATE(0, "xti", NULL, CLK_IS_ROOT, 0), + FRATE(0, "ext", NULL, CLK_IS_ROOT, 0), + FRATE(0, "ext_i2s", NULL, CLK_IS_ROOT, 0), + FRATE(0, "ext_uart", NULL, CLK_IS_ROOT, 0), +}; + +static void __init s3c2443_common_clk_register_fixed_ext(unsigned long xti_f) +{ + s3c2443_common_frate_clks[0].fixed_rate = xti_f; + samsung_clk_register_fixed_rate(s3c2443_common_frate_clks, + ARRAY_SIZE(s3c2443_common_frate_clks)); +} + +void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, + int current_soc, + void __iomem *base) +{ + reg_base = base; + + if (np) { + reg_base = of_iomap(np, 0); + if (!reg_base) + panic("%s: failed to map registers\n", __func__); + } + + samsung_clk_init(np, reg_base, NR_CLKS); + + /* Register external clocks only in non-dt cases */ + if (!np) + s3c2443_common_clk_register_fixed_ext(xti_f); + + /* Register PLLs. */ + if (current_soc == S3C2416 || current_soc == S3C2450) + samsung_clk_register_pll(s3c2416_pll_clks, + ARRAY_SIZE(s3c2416_pll_clks), reg_base); + else + samsung_clk_register_pll(s3c2443_pll_clks, + ARRAY_SIZE(s3c2443_pll_clks), reg_base); + + /* Register common internal clocks. */ + samsung_clk_register_mux(s3c2443_common_muxes, + ARRAY_SIZE(s3c2443_common_muxes)); + samsung_clk_register_div(s3c2443_common_dividers, + ARRAY_SIZE(s3c2443_common_dividers)); + samsung_clk_register_gate(s3c2443_common_gates, + ARRAY_SIZE(s3c2443_common_gates)); + samsung_clk_register_alias(s3c2443_common_aliases, + ARRAY_SIZE(s3c2443_common_aliases)); + + /* Register SoC-specific clocks. */ + switch (current_soc) { + case S3C2450: + samsung_clk_register_div(s3c2450_dividers, + ARRAY_SIZE(s3c2450_dividers)); + samsung_clk_register_mux(s3c2450_muxes, + ARRAY_SIZE(s3c2450_muxes)); + samsung_clk_register_gate(s3c2450_gates, + ARRAY_SIZE(s3c2450_gates)); + samsung_clk_register_alias(s3c2450_aliases, + ARRAY_SIZE(s3c2450_aliases)); + /* fall through, as s3c2450 extends the s3c2416 clocks */ + case S3C2416: + samsung_clk_register_div(s3c2416_dividers, + ARRAY_SIZE(s3c2416_dividers)); + samsung_clk_register_mux(s3c2416_muxes, + ARRAY_SIZE(s3c2416_muxes)); + samsung_clk_register_gate(s3c2416_gates, + ARRAY_SIZE(s3c2416_gates)); + samsung_clk_register_alias(s3c2416_aliases, + ARRAY_SIZE(s3c2416_aliases)); + break; + case S3C2443: + samsung_clk_register_div(s3c2443_dividers, + ARRAY_SIZE(s3c2443_dividers)); + samsung_clk_register_gate(s3c2443_gates, + ARRAY_SIZE(s3c2443_gates)); + samsung_clk_register_alias(s3c2443_aliases, + ARRAY_SIZE(s3c2443_aliases)); + break; + } + + s3c2443_clk_sleep_init(); +} + +static void __init s3c2416_clk_init(struct device_node *np) +{ + s3c2443_common_clk_init(np, 0, S3C2416, 0); +} +CLK_OF_DECLARE(s3c2416_clk, "samsung,s3c2416-clock", s3c2416_clk_init); + +static void __init s3c2443_clk_init(struct device_node *np) +{ + s3c2443_common_clk_init(np, 0, S3C2443, 0); +} +CLK_OF_DECLARE(s3c2443_clk, "samsung,s3c2443-clock", s3c2443_clk_init); + +static void __init s3c2450_clk_init(struct device_node *np) +{ + s3c2443_common_clk_init(np, 0, S3C2450, 0); +} +CLK_OF_DECLARE(s3c2450_clk, "samsung,s3c2450-clock", s3c2450_clk_init); diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c index 88dafb5e96270f..de6da957a09d6e 100644 --- a/drivers/clk/socfpga/clk-pll.c +++ b/drivers/clk/socfpga/clk-pll.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "clk.h" @@ -43,6 +44,8 @@ #define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw) +void __iomem *clk_mgr_base_addr; + static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk, unsigned long parent_rate) { @@ -87,6 +90,7 @@ static __init struct clk *__socfpga_pll_init(struct device_node *node, const char *clk_name = node->name; const char *parent_name[SOCFPGA_MAX_PARENTS]; struct clk_init_data init; + struct device_node *clkmgr_np; int rc; int i = 0; @@ -96,6 +100,9 @@ static __init struct clk *__socfpga_pll_init(struct device_node *node, if (WARN_ON(!pll_clk)) return NULL; + clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); + clk_mgr_base_addr = of_iomap(clkmgr_np, 0); + BUG_ON(!clk_mgr_base_addr); pll_clk->hw.reg = clk_mgr_base_addr + reg; of_property_read_string(node, "clock-output-names", &clk_name); diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c index 35a960a993f95c..43db947e5f0e51 100644 --- a/drivers/clk/socfpga/clk.c +++ b/drivers/clk/socfpga/clk.c @@ -17,28 +17,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include -#include -#include -#include #include -#include #include "clk.h" -void __iomem *clk_mgr_base_addr; - -static const struct of_device_id socfpga_child_clocks[] __initconst = { - { .compatible = "altr,socfpga-pll-clock", socfpga_pll_init, }, - { .compatible = "altr,socfpga-perip-clk", socfpga_periph_init, }, - { .compatible = "altr,socfpga-gate-clk", socfpga_gate_init, }, - {}, -}; - -static void __init socfpga_clkmgr_init(struct device_node *node) -{ - clk_mgr_base_addr = of_iomap(node, 0); - of_clk_init(socfpga_child_clocks); -} -CLK_OF_DECLARE(socfpga_mgr, "altr,clk-mgr", socfpga_clkmgr_init); +CLK_OF_DECLARE(socfpga_pll_clk, "altr,socfpga-pll-clock", socfpga_pll_init); +CLK_OF_DECLARE(socfpga_perip_clk, "altr,socfpga-perip-clk", socfpga_periph_init); +CLK_OF_DECLARE(socfpga_gate_clk, "altr,socfpga-gate-clk", socfpga_gate_init); diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 9e232644f07edf..3806d97e529b06 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -77,6 +77,41 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, return rate; } +static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_p) +{ + struct clk *clk = hw->clk, *parent, *best_parent = NULL; + int i, num_parents; + unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0; + + /* find the parent that can help provide the fastest rate <= rate */ + num_parents = __clk_get_num_parents(clk); + for (i = 0; i < num_parents; i++) { + parent = clk_get_parent_by_index(clk, i); + if (!parent) + continue; + if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT) + parent_rate = __clk_round_rate(parent, rate); + else + parent_rate = __clk_get_rate(parent); + + child_rate = clk_factors_round_rate(hw, rate, &parent_rate); + + if (child_rate <= rate && child_rate > best_child_rate) { + best_parent = parent; + best = parent_rate; + best_child_rate = child_rate; + } + } + + if (best_parent) + *best_parent_p = best_parent; + *best_parent_rate = best; + + return best_child_rate; +} + static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { @@ -113,6 +148,7 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, } const struct clk_ops clk_factors_ops = { + .determine_rate = clk_factors_determine_rate, .recalc_rate = clk_factors_recalc_rate, .round_rate = clk_factors_round_rate, .set_rate = clk_factors_set_rate, diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index bd7dc733c1ca52..59f90401b9000a 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -506,6 +506,42 @@ CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk", +/** + * clk_sunxi_mmc_phase_control() - configures MMC clock phase control + */ + +void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output) +{ + #define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw) + #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) + + struct clk_composite *composite = to_clk_composite(hw); + struct clk_hw *rate_hw = composite->rate_hw; + struct clk_factors *factors = to_clk_factors(rate_hw); + unsigned long flags = 0; + u32 reg; + + if (factors->lock) + spin_lock_irqsave(factors->lock, flags); + + reg = readl(factors->reg); + + /* set sample clock phase control */ + reg &= ~(0x7 << 20); + reg |= ((sample & 0x7) << 20); + + /* set output clock phase control */ + reg &= ~(0x7 << 8); + reg |= ((output & 0x7) << 8); + + writel(reg, factors->reg); + + if (factors->lock) + spin_unlock_irqrestore(factors->lock, flags); +} +EXPORT_SYMBOL(clk_sunxi_mmc_phase_control); + + /** * sunxi_factors_clk_setup() - Setup function for factor clocks */ diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c index 67c8de572c5018..b4877e0ee91051 100644 --- a/drivers/clk/ti/clk-43xx.c +++ b/drivers/clk/ti/clk-43xx.c @@ -110,9 +110,25 @@ static struct ti_dt_clk am43xx_clks[] = { int __init am43xx_dt_clk_init(void) { + struct clk *clk1, *clk2; + ti_dt_clocks_register(am43xx_clks); omap2_clk_disable_autoidle_all(); + /* + * cpsw_cpts_rft_clk has got the choice of 3 clocksources + * dpll_core_m4_ck, dpll_core_m5_ck and dpll_disp_m2_ck. + * By default dpll_core_m4_ck is selected, witn this as clock + * source the CPTS doesnot work properly. It gives clockcheck errors + * while running PTP. + * clockcheck: clock jumped backward or running slower than expected! + * By selecting dpll_core_m5_ck as the clocksource fixes this issue. + * In AM335x dpll_core_m5_ck is the default clocksource. + */ + clk1 = clk_get_sys(NULL, "cpsw_cpts_rft_clk"); + clk2 = clk_get_sys(NULL, "dpll_core_m5_ck"); + clk_set_parent(clk1, clk2); + return 0; } diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index acf5a329d53876..8d6420013a04ca 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -24,6 +24,7 @@ #include #include #include +#include #define EXYNOS4_MCTREG(x) (x) #define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100) @@ -192,12 +193,19 @@ struct clocksource mct_frc = { .resume = exynos4_frc_resume, }; +static u64 notrace exynos4_read_sched_clock(void) +{ + return exynos4_frc_read(&mct_frc); +} + static void __init exynos4_clocksource_init(void) { exynos4_mct_frc_start(0, 0); if (clocksource_register_hz(&mct_frc, clk_rate)) panic("%s: can't register clocksource\n", mct_frc.name); + + sched_clock_register(exynos4_read_sched_clock, 64, clk_rate); } static void exynos4_mct_comp0_stop(void) diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 580503513f0f10..6e05a1e18e5272 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -85,7 +85,7 @@ config ARM_EXYNOS_CPU_FREQ_BOOST_SW It allows usage of special frequencies for Samsung Exynos processors if thermal conditions are appropriate. - It reguires, for safe operation, thermal framework with properly + It requires, for safe operation, thermal framework with properly defined trip points. If in doubt, say N. @@ -186,7 +186,7 @@ config ARM_S3C2416_CPUFREQ S3C2450 SoC. The S3C2416 supports changing the rate of the armdiv clock source and also entering a so called dynamic voltage scaling mode in which it is possible to reduce the - core voltage of the cpu. + core voltage of the CPU. If in doubt, say N. diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index d369349eeaab2d..89ae88f9189532 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 @@ -10,7 +10,7 @@ config X86_INTEL_PSTATE The driver implements an internal governor and will become the scaling driver and governor for Sandy bridge processors. - When this driver is enabled it will become the perferred + When this driver is enabled it will become the preferred scaling driver for Sandy bridge processors. If in doubt, say N. @@ -52,7 +52,7 @@ config X86_ACPI_CPUFREQ_CPB help The powernow-k8 driver used to provide a sysfs knob called "cpb" to disable the Core Performance Boosting feature of AMD CPUs. This - file has now been superseeded by the more generic "boost" entry. + file has now been superseded by the more generic "boost" entry. By enabling this option the acpi_cpufreq driver provides the old entry in addition to the new boost ones, for compatibility reasons. diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 0dbb963c1aef19..738c8b7b17dc70 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -1,5 +1,7 @@ # CPUfreq core obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o +obj-$(CONFIG_PM_OPP) += cpufreq_opp.o + # CPUfreq stats obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 000e4e0afd7e67..b0c18ed8d83f70 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -213,7 +213,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data) static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data) { - int i; + struct cpufreq_frequency_table *pos; struct acpi_processor_performance *perf; if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) @@ -223,10 +223,9 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data) perf = data->acpi_data; - for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { - if (msr == perf->states[data->freq_table[i].driver_data].status) - return data->freq_table[i].frequency; - } + cpufreq_for_each_entry(pos, data->freq_table) + if (msr == perf->states[pos->driver_data].status) + return pos->frequency; return data->freq_table[0].frequency; } diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index bad2ed317ba294..1f4d4e31505746 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -226,22 +226,22 @@ static inline u32 get_table_count(struct cpufreq_frequency_table *table) /* get the minimum frequency in the cpufreq_frequency_table */ static inline u32 get_table_min(struct cpufreq_frequency_table *table) { - int i; + struct cpufreq_frequency_table *pos; uint32_t min_freq = ~0; - for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) - if (table[i].frequency < min_freq) - min_freq = table[i].frequency; + cpufreq_for_each_entry(pos, table) + if (pos->frequency < min_freq) + min_freq = pos->frequency; return min_freq; } /* get the maximum frequency in the cpufreq_frequency_table */ static inline u32 get_table_max(struct cpufreq_frequency_table *table) { - int i; + struct cpufreq_frequency_table *pos; uint32_t max_freq = 0; - for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) - if (table[i].frequency > max_freq) - max_freq = table[i].frequency; + cpufreq_for_each_entry(pos, table) + if (pos->frequency > max_freq) + max_freq = pos->frequency; return max_freq; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index abda6609d3e79f..a05c92198b9fa8 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -354,6 +354,18 @@ static void cpufreq_notify_post_transition(struct cpufreq_policy *policy, void cpufreq_freq_transition_begin(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs) { + + /* + * Catch double invocations of _begin() which lead to self-deadlock. + * ASYNC_NOTIFICATION drivers are left out because the cpufreq core + * doesn't invoke _begin() on their behalf, and hence the chances of + * double invocations are very low. Moreover, there are scenarios + * where these checks can emit false-positive warnings in these + * drivers; so we avoid that by skipping them altogether. + */ + WARN_ON(!(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION) + && current == policy->transition_task); + wait: wait_event(policy->transition_wait, !policy->transition_ongoing); @@ -365,6 +377,7 @@ void cpufreq_freq_transition_begin(struct cpufreq_policy *policy, } policy->transition_ongoing = true; + policy->transition_task = current; spin_unlock(&policy->transition_lock); @@ -381,6 +394,7 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy, cpufreq_notify_post_transition(policy, freqs, transition_failed); policy->transition_ongoing = false; + policy->transition_task = NULL; wake_up(&policy->transition_wait); } diff --git a/drivers/cpufreq/cpufreq_opp.c b/drivers/cpufreq/cpufreq_opp.c new file mode 100644 index 00000000000000..c0c6f4a4eccf54 --- /dev/null +++ b/drivers/cpufreq/cpufreq_opp.c @@ -0,0 +1,110 @@ +/* + * Generic OPP helper interface for CPUFreq drivers + * + * Copyright (C) 2009-2014 Texas Instruments Incorporated. + * Nishanth Menon + * Romit Dasgupta + * Kevin Hilman + * + * 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 +#include +#include +#include +#include + +/** + * dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device + * @dev: device for which we do this operation + * @table: Cpufreq table returned back to caller + * + * Generate a cpufreq table for a provided device- this assumes that the + * opp list is already initialized and ready for usage. + * + * This function allocates required memory for the cpufreq table. It is + * expected that the caller does the required maintenance such as freeing + * the table as required. + * + * Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM + * if no memory available for the operation (table is not populated), returns 0 + * if successful and table is populated. + * + * WARNING: It is important for the callers to ensure refreshing their copy of + * the table if any of the mentioned functions have been invoked in the interim. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Since we just use the regular accessor functions to access the internal data + * structures, we use RCU read lock inside this function. As a result, users of + * this function DONOT need to use explicit locks for invoking. + */ +int dev_pm_opp_init_cpufreq_table(struct device *dev, + struct cpufreq_frequency_table **table) +{ + struct dev_pm_opp *opp; + struct cpufreq_frequency_table *freq_table = NULL; + int i, max_opps, ret = 0; + unsigned long rate; + + rcu_read_lock(); + + max_opps = dev_pm_opp_get_opp_count(dev); + if (max_opps <= 0) { + ret = max_opps ? max_opps : -ENODATA; + goto out; + } + + freq_table = kzalloc(sizeof(*freq_table) * (max_opps + 1), GFP_KERNEL); + if (!freq_table) { + ret = -ENOMEM; + goto out; + } + + for (i = 0, rate = 0; i < max_opps; i++, rate++) { + /* find next rate */ + opp = dev_pm_opp_find_freq_ceil(dev, &rate); + if (IS_ERR(opp)) { + ret = PTR_ERR(opp); + goto out; + } + freq_table[i].driver_data = i; + freq_table[i].frequency = rate / 1000; + } + + freq_table[i].driver_data = i; + freq_table[i].frequency = CPUFREQ_TABLE_END; + + *table = &freq_table[0]; + +out: + rcu_read_unlock(); + if (ret) + kfree(freq_table); + + return ret; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table); + +/** + * dev_pm_opp_free_cpufreq_table() - free the cpufreq table + * @dev: device for which we do this operation + * @table: table to free + * + * Free up the table allocated by dev_pm_opp_init_cpufreq_table + */ +void dev_pm_opp_free_cpufreq_table(struct device *dev, + struct cpufreq_frequency_table **table) +{ + if (!table) + return; + + kfree(*table); + *table = NULL; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index ecaaebf969fc4e..0cd9b4dcef997d 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -182,11 +182,11 @@ static void cpufreq_stats_free_table(unsigned int cpu) static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) { - unsigned int i, j, count = 0, ret = 0; + unsigned int i, count = 0, ret = 0; struct cpufreq_stats *stat; unsigned int alloc_size; unsigned int cpu = policy->cpu; - struct cpufreq_frequency_table *table; + struct cpufreq_frequency_table *pos, *table; table = cpufreq_frequency_get_table(cpu); if (unlikely(!table)) @@ -205,12 +205,8 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) stat->cpu = cpu; per_cpu(cpufreq_stats_table, cpu) = stat; - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - unsigned int freq = table[i].frequency; - if (freq == CPUFREQ_ENTRY_INVALID) - continue; + cpufreq_for_each_valid_entry(pos, table) count++; - } alloc_size = count * sizeof(int) + count * sizeof(u64); @@ -228,15 +224,11 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) #ifdef CONFIG_CPU_FREQ_STAT_DETAILS stat->trans_table = stat->freq_table + count; #endif - j = 0; - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - unsigned int freq = table[i].frequency; - if (freq == CPUFREQ_ENTRY_INVALID) - continue; - if (freq_table_get_index(stat, freq) == -1) - stat->freq_table[j++] = freq; - } - stat->state_num = j; + i = 0; + cpufreq_for_each_valid_entry(pos, table) + if (freq_table_get_index(stat, pos->frequency) == -1) + stat->freq_table[i++] = pos->frequency; + stat->state_num = i; spin_lock(&cpufreq_stats_lock); stat->last_time = get_jiffies_64(); stat->last_index = freq_table_get_index(stat, policy->cur); diff --git a/drivers/cpufreq/dbx500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c index 412a78bb0c9410..4bebc1b5db48f3 100644 --- a/drivers/cpufreq/dbx500-cpufreq.c +++ b/drivers/cpufreq/dbx500-cpufreq.c @@ -45,7 +45,7 @@ static struct cpufreq_driver dbx500_cpufreq_driver = { static int dbx500_cpufreq_probe(struct platform_device *pdev) { - int i = 0; + struct cpufreq_frequency_table *pos; freq_table = dev_get_platdata(&pdev->dev); if (!freq_table) { @@ -60,10 +60,8 @@ static int dbx500_cpufreq_probe(struct platform_device *pdev) } pr_info("dbx500-cpufreq: Available frequencies:\n"); - while (freq_table[i].frequency != CPUFREQ_TABLE_END) { - pr_info(" %d Mhz\n", freq_table[i].frequency/1000); - i++; - } + cpufreq_for_each_entry(pos, freq_table) + pr_info(" %d Mhz\n", pos->frequency / 1000); return cpufreq_register_driver(&dbx500_cpufreq_driver); } diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c index 7f5d2a68c35328..1c06e786c9baa5 100644 --- a/drivers/cpufreq/elanfreq.c +++ b/drivers/cpufreq/elanfreq.c @@ -147,7 +147,7 @@ static int elanfreq_target(struct cpufreq_policy *policy, static int elanfreq_cpu_init(struct cpufreq_policy *policy) { struct cpuinfo_x86 *c = &cpu_data(0); - unsigned int i; + struct cpufreq_frequency_table *pos; /* capability check */ if ((c->x86_vendor != X86_VENDOR_AMD) || @@ -159,10 +159,9 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy) max_freq = elanfreq_get_cpu_frequency(0); /* table init */ - for (i = 0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) { - if (elanfreq_table[i].frequency > max_freq) - elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID; - } + cpufreq_for_each_entry(pos, elanfreq_table) + if (pos->frequency > max_freq) + pos->frequency = CPUFREQ_ENTRY_INVALID; /* cpuinfo and default policy values */ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index f99cfe24e7bca6..c3e55aa28cf87d 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -29,17 +29,16 @@ static unsigned int locking_frequency; static int exynos_cpufreq_get_index(unsigned int freq) { struct cpufreq_frequency_table *freq_table = exynos_info->freq_table; - int index; + struct cpufreq_frequency_table *pos; - for (index = 0; - freq_table[index].frequency != CPUFREQ_TABLE_END; index++) - if (freq_table[index].frequency == freq) + cpufreq_for_each_entry(pos, freq_table) + if (pos->frequency == freq) break; - if (freq_table[index].frequency == CPUFREQ_TABLE_END) + if (pos->frequency == CPUFREQ_TABLE_END) return -EINVAL; - return index; + return pos - freq_table; } static int exynos_cpufreq_scale(unsigned int target_freq) @@ -49,6 +48,7 @@ static int exynos_cpufreq_scale(unsigned int target_freq) struct cpufreq_policy *policy = cpufreq_cpu_get(0); unsigned int arm_volt, safe_arm_volt = 0; unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz; + struct device *dev = exynos_info->dev; unsigned int old_freq; int index, old_index; int ret = 0; @@ -90,8 +90,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq) /* Firstly, voltage up to increase frequency */ ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt); if (ret) { - pr_err("%s: failed to set cpu voltage to %d\n", - __func__, arm_volt); + dev_err(dev, "failed to set cpu voltage to %d\n", + arm_volt); return ret; } } @@ -100,8 +100,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq) ret = regulator_set_voltage(arm_regulator, safe_arm_volt, safe_arm_volt); if (ret) { - pr_err("%s: failed to set cpu voltage to %d\n", - __func__, safe_arm_volt); + dev_err(dev, "failed to set cpu voltage to %d\n", + safe_arm_volt); return ret; } } @@ -115,8 +115,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq) ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt); if (ret) { - pr_err("%s: failed to set cpu voltage to %d\n", - __func__, arm_volt); + dev_err(dev, "failed to set cpu voltage to %d\n", + arm_volt); goto out; } } @@ -163,6 +163,8 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) if (!exynos_info) return -ENOMEM; + exynos_info->dev = &pdev->dev; + if (soc_is_exynos4210()) ret = exynos4210_cpufreq_init(exynos_info); else if (soc_is_exynos4212() || soc_is_exynos4412()) @@ -176,13 +178,13 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) goto err_vdd_arm; if (exynos_info->set_freq == NULL) { - pr_err("%s: No set_freq function (ERR)\n", __func__); + dev_err(&pdev->dev, "No set_freq function (ERR)\n"); goto err_vdd_arm; } arm_regulator = regulator_get(NULL, "vdd_arm"); if (IS_ERR(arm_regulator)) { - pr_err("%s: failed to get resource vdd_arm\n", __func__); + dev_err(&pdev->dev, "failed to get resource vdd_arm\n"); goto err_vdd_arm; } @@ -192,7 +194,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) if (!cpufreq_register_driver(&exynos_driver)) return 0; - pr_err("%s: failed to register cpufreq driver\n", __func__); + dev_err(&pdev->dev, "failed to register cpufreq driver\n"); regulator_put(arm_regulator); err_vdd_arm: kfree(exynos_info); diff --git a/drivers/cpufreq/exynos-cpufreq.h b/drivers/cpufreq/exynos-cpufreq.h index 3ddade8a51251e..b72ff10a040ef1 100644 --- a/drivers/cpufreq/exynos-cpufreq.h +++ b/drivers/cpufreq/exynos-cpufreq.h @@ -34,6 +34,7 @@ struct apll_freq { }; struct exynos_dvfs_info { + struct device *dev; unsigned long mpll_freq_khz; unsigned int pll_safe_idx; struct clk *cpu_clk; diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c index a6b8214d7b7712..f33f25b483ca6c 100644 --- a/drivers/cpufreq/exynos5440-cpufreq.c +++ b/drivers/cpufreq/exynos5440-cpufreq.c @@ -114,25 +114,23 @@ static struct cpufreq_freqs freqs; static int init_div_table(void) { - struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table; + struct cpufreq_frequency_table *pos, *freq_tbl = dvfs_info->freq_table; unsigned int tmp, clk_div, ema_div, freq, volt_id; - int i = 0; struct dev_pm_opp *opp; rcu_read_lock(); - for (i = 0; freq_tbl[i].frequency != CPUFREQ_TABLE_END; i++) { - + cpufreq_for_each_entry(pos, freq_tbl) { opp = dev_pm_opp_find_freq_exact(dvfs_info->dev, - freq_tbl[i].frequency * 1000, true); + pos->frequency * 1000, true); if (IS_ERR(opp)) { rcu_read_unlock(); dev_err(dvfs_info->dev, "failed to find valid OPP for %u KHZ\n", - freq_tbl[i].frequency); + pos->frequency); return PTR_ERR(opp); } - freq = freq_tbl[i].frequency / 1000; /* In MHZ */ + freq = pos->frequency / 1000; /* In MHZ */ clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK) << P0_7_CPUCLKDEV_SHIFT; clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK) @@ -157,7 +155,8 @@ static int init_div_table(void) tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT) | ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT)); - __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * i); + __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * + (pos - freq_tbl)); } rcu_read_unlock(); @@ -166,8 +165,9 @@ static int init_div_table(void) static void exynos_enable_dvfs(unsigned int cur_frequency) { - unsigned int tmp, i, cpu; + unsigned int tmp, cpu; struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table; + struct cpufreq_frequency_table *pos; /* Disable DVFS */ __raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL); @@ -182,15 +182,15 @@ static void exynos_enable_dvfs(unsigned int cur_frequency) __raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN); /* Set initial performance index */ - for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) - if (freq_table[i].frequency == cur_frequency) + cpufreq_for_each_entry(pos, freq_table) + if (pos->frequency == cur_frequency) break; - if (freq_table[i].frequency == CPUFREQ_TABLE_END) { + if (pos->frequency == CPUFREQ_TABLE_END) { dev_crit(dvfs_info->dev, "Boot up frequency not supported\n"); /* Assign the highest frequency */ - i = 0; - cur_frequency = freq_table[i].frequency; + pos = freq_table; + cur_frequency = pos->frequency; } dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ", @@ -199,7 +199,7 @@ static void exynos_enable_dvfs(unsigned int cur_frequency) for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) { tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4); tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT); - tmp |= (i << C0_3_PSTATE_NEW_SHIFT); + tmp |= ((pos - freq_table) << C0_3_PSTATE_NEW_SHIFT); __raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4); } diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 08e7bbcf6d7362..8e518c68939351 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -21,22 +21,19 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table) { + struct cpufreq_frequency_table *pos; unsigned int min_freq = ~0; unsigned int max_freq = 0; - unsigned int i; + unsigned int freq; - for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { - unsigned int freq = table[i].frequency; - if (freq == CPUFREQ_ENTRY_INVALID) { - pr_debug("table entry %u is invalid, skipping\n", i); + cpufreq_for_each_valid_entry(pos, table) { + freq = pos->frequency; - continue; - } if (!cpufreq_boost_enabled() - && (table[i].flags & CPUFREQ_BOOST_FREQ)) + && (pos->flags & CPUFREQ_BOOST_FREQ)) continue; - pr_debug("table entry %u: %u kHz\n", i, freq); + pr_debug("table entry %u: %u kHz\n", (int)(pos - table), freq); if (freq < min_freq) min_freq = freq; if (freq > max_freq) @@ -57,7 +54,8 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo); int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table) { - unsigned int next_larger = ~0, freq, i = 0; + struct cpufreq_frequency_table *pos; + unsigned int freq, next_larger = ~0; bool found = false; pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n", @@ -65,9 +63,9 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, cpufreq_verify_within_cpu_limits(policy); - for (; freq = table[i].frequency, freq != CPUFREQ_TABLE_END; i++) { - if (freq == CPUFREQ_ENTRY_INVALID) - continue; + cpufreq_for_each_valid_entry(pos, table) { + freq = pos->frequency; + if ((freq >= policy->min) && (freq <= policy->max)) { found = true; break; @@ -118,7 +116,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, .driver_data = ~0, .frequency = 0, }; - unsigned int i; + struct cpufreq_frequency_table *pos; + unsigned int freq, i = 0; pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu); @@ -132,10 +131,10 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, break; } - for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { - unsigned int freq = table[i].frequency; - if (freq == CPUFREQ_ENTRY_INVALID) - continue; + cpufreq_for_each_valid_entry(pos, table) { + freq = pos->frequency; + + i = pos - table; if ((freq < policy->min) || (freq > policy->max)) continue; switch (relation) { @@ -184,8 +183,7 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, unsigned int freq) { - struct cpufreq_frequency_table *table; - int i; + struct cpufreq_frequency_table *pos, *table; table = cpufreq_frequency_get_table(policy->cpu); if (unlikely(!table)) { @@ -193,10 +191,9 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, return -ENOENT; } - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - if (table[i].frequency == freq) - return i; - } + cpufreq_for_each_valid_entry(pos, table) + if (pos->frequency == freq) + return pos - table; return -EINVAL; } @@ -208,16 +205,13 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index); static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf, bool show_boost) { - unsigned int i = 0; ssize_t count = 0; - struct cpufreq_frequency_table *table = policy->freq_table; + struct cpufreq_frequency_table *pos, *table = policy->freq_table; if (!table) return -ENODEV; - for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { - if (table[i].frequency == CPUFREQ_ENTRY_INVALID) - continue; + cpufreq_for_each_valid_entry(pos, table) { /* * show_boost = true and driver_data = BOOST freq * display BOOST freqs @@ -229,10 +223,10 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf, * show_boost = false and driver_data != BOOST freq * display NON BOOST freqs */ - if (show_boost ^ (table[i].flags & CPUFREQ_BOOST_FREQ)) + if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ)) continue; - count += sprintf(&buf[count], "%d ", table[i].frequency); + count += sprintf(&buf[count], "%d ", pos->frequency); } count += sprintf(&buf[count], "\n"); diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 099967302bf259..6658bef99352e0 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -32,8 +32,6 @@ #include #include -#define SAMPLE_COUNT 3 - #define BYT_RATIOS 0x66a #define BYT_VIDS 0x66b #define BYT_TURBO_RATIOS 0x66c @@ -553,14 +551,13 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate); } -static inline void intel_pstate_calc_busy(struct cpudata *cpu, - struct sample *sample) +static inline void intel_pstate_calc_busy(struct cpudata *cpu) { + struct sample *sample = &cpu->sample; int32_t core_pct; int32_t c0_pct; - core_pct = div_fp(int_tofp((sample->aperf)), - int_tofp((sample->mperf))); + core_pct = div_fp(int_tofp(sample->aperf), int_tofp(sample->mperf)); core_pct = mul_fp(core_pct, int_tofp(100)); FP_ROUNDUP(core_pct); @@ -592,7 +589,7 @@ static inline void intel_pstate_sample(struct cpudata *cpu) cpu->sample.mperf -= cpu->prev_mperf; cpu->sample.tsc -= cpu->prev_tsc; - intel_pstate_calc_busy(cpu, &cpu->sample); + intel_pstate_calc_busy(cpu); cpu->prev_aperf = aperf; cpu->prev_mperf = mperf; diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index 5c4369b5d834d9..c913906a719ee0 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -530,6 +530,7 @@ static int longhaul_get_ranges(void) static void longhaul_setup_voltagescaling(void) { + struct cpufreq_frequency_table *freq_pos; union msr_longhaul longhaul; struct mV_pos minvid, maxvid, vid; unsigned int j, speed, pos, kHz_step, numvscales; @@ -608,18 +609,16 @@ static void longhaul_setup_voltagescaling(void) /* Calculate kHz for one voltage step */ kHz_step = (highest_speed - min_vid_speed) / numvscales; - j = 0; - while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { - speed = longhaul_table[j].frequency; + cpufreq_for_each_entry(freq_pos, longhaul_table) { + speed = freq_pos->frequency; if (speed > min_vid_speed) pos = (speed - min_vid_speed) / kHz_step + minvid.pos; else pos = minvid.pos; - longhaul_table[j].driver_data |= mV_vrm_table[pos] << 8; + freq_pos->driver_data |= mV_vrm_table[pos] << 8; vid = vrm_mV_table[mV_vrm_table[pos]]; printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n", - speed, j, vid.mV); - j++; + speed, (int)(freq_pos - longhaul_table), vid.mV); } can_scale_voltage = 1; diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c index f0bc31f5db27a4..d4add86219444a 100644 --- a/drivers/cpufreq/loongson2_cpufreq.c +++ b/drivers/cpufreq/loongson2_cpufreq.c @@ -62,7 +62,7 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy, set_cpus_allowed_ptr(current, &cpus_allowed); /* setting the cpu frequency */ - clk_set_rate(policy->clk, freq); + clk_set_rate(policy->clk, freq * 1000); return 0; } @@ -92,7 +92,7 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy) i++) loongson2_clockmod_table[i].frequency = (rate * i) / 8; - ret = clk_set_rate(cpuclk, rate); + ret = clk_set_rate(cpuclk, rate * 1000); if (ret) { clk_put(cpuclk); return ret; diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c index 84c84b5f0f3a42..35dd4d7ffee082 100644 --- a/drivers/cpufreq/pasemi-cpufreq.c +++ b/drivers/cpufreq/pasemi-cpufreq.c @@ -136,9 +136,10 @@ void restore_astate(int cpu) static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) { + struct cpufreq_frequency_table *pos; const u32 *max_freqp; u32 max_freq; - int i, cur_astate; + int cur_astate; struct resource res; struct device_node *cpu, *dn; int err = -ENODEV; @@ -197,10 +198,9 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) pr_debug("initializing frequency table\n"); /* initialize frequency table */ - for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) { - pas_freqs[i].frequency = - get_astate_freq(pas_freqs[i].driver_data) * 100000; - pr_debug("%d: %d\n", i, pas_freqs[i].frequency); + cpufreq_for_each_entry(pos, pas_freqs) { + pos->frequency = get_astate_freq(pos->driver_data) * 100000; + pr_debug("%d: %d\n", (int)(pos - pas_freqs), pos->frequency); } cur_astate = get_cur_astate(policy->cpu); diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c index 78904e6ca4a020..c8012bc8691072 100644 --- a/drivers/cpufreq/powernow-k6.c +++ b/drivers/cpufreq/powernow-k6.c @@ -151,6 +151,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy, static int powernow_k6_cpu_init(struct cpufreq_policy *policy) { + struct cpufreq_frequency_table *pos; unsigned int i, f; unsigned khz; @@ -168,12 +169,11 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy) } } if (param_max_multiplier) { - for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { - if (clock_ratio[i].driver_data == param_max_multiplier) { + cpufreq_for_each_entry(pos, clock_ratio) + if (pos->driver_data == param_max_multiplier) { max_multiplier = param_max_multiplier; goto have_max_multiplier; } - } printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n"); return -EINVAL; } @@ -201,12 +201,12 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy) param_busfreq = busfreq * 10; /* table init */ - for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { - f = clock_ratio[i].driver_data; + cpufreq_for_each_entry(pos, clock_ratio) { + f = pos->driver_data; if (f > max_multiplier) - clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID; + pos->frequency = CPUFREQ_ENTRY_INVALID; else - clock_ratio[i].frequency = busfreq * f; + pos->frequency = busfreq * f; } /* cpuinfo and default policy values */ diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c index 5be8a48dba74fd..5a4c5a639f618f 100644 --- a/drivers/cpufreq/ppc_cbe_cpufreq.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq.c @@ -67,9 +67,10 @@ static int set_pmode(unsigned int cpu, unsigned int slow_mode) static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) { + struct cpufreq_frequency_table *pos; const u32 *max_freqp; u32 max_freq; - int i, cur_pmode; + int cur_pmode; struct device_node *cpu; cpu = of_get_cpu_node(policy->cpu, NULL); @@ -102,9 +103,9 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) pr_debug("initializing frequency table\n"); /* initialize frequency table */ - for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) { - cbe_freqs[i].frequency = max_freq / cbe_freqs[i].driver_data; - pr_debug("%d: %d\n", i, cbe_freqs[i].frequency); + cpufreq_for_each_entry(pos, cbe_freqs) { + pos->frequency = max_freq / pos->driver_data; + pr_debug("%d: %d\n", (int)(pos - cbe_freqs), pos->frequency); } /* if DEBUG is enabled set_pmode() measures the latency diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c index 4626f90559b551..2fd53eaaec20bf 100644 --- a/drivers/cpufreq/s3c2416-cpufreq.c +++ b/drivers/cpufreq/s3c2416-cpufreq.c @@ -266,7 +266,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq) { int count, v, i, found; - struct cpufreq_frequency_table *freq; + struct cpufreq_frequency_table *pos; struct s3c2416_dvfs *dvfs; count = regulator_count_voltages(s3c_freq->vddarm); @@ -275,12 +275,11 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq) return; } - freq = s3c_freq->freq_table; - while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) { - if (freq->frequency == CPUFREQ_ENTRY_INVALID) - continue; + if (!count) + goto out; - dvfs = &s3c2416_dvfs_table[freq->driver_data]; + cpufreq_for_each_valid_entry(pos, s3c_freq->freq_table) { + dvfs = &s3c2416_dvfs_table[pos->driver_data]; found = 0; /* Check only the min-voltage, more is always ok on S3C2416 */ @@ -292,13 +291,12 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq) if (!found) { pr_debug("cpufreq: %dkHz unsupported by regulator\n", - freq->frequency); - freq->frequency = CPUFREQ_ENTRY_INVALID; + pos->frequency); + pos->frequency = CPUFREQ_ENTRY_INVALID; } - - freq++; } +out: /* Guessed */ s3c_freq->regulator_latency = 1 * 1000 * 1000; } @@ -338,7 +336,7 @@ static struct notifier_block s3c2416_cpufreq_reboot_notifier = { static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy) { struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; - struct cpufreq_frequency_table *freq; + struct cpufreq_frequency_table *pos; struct clk *msysclk; unsigned long rate; int ret; @@ -427,31 +425,27 @@ static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy) s3c_freq->regulator_latency = 0; #endif - freq = s3c_freq->freq_table; - while (freq->frequency != CPUFREQ_TABLE_END) { + cpufreq_for_each_entry(pos, s3c_freq->freq_table) { /* special handling for dvs mode */ - if (freq->driver_data == 0) { + if (pos->driver_data == 0) { if (!s3c_freq->hclk) { pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n", - freq->frequency); - freq->frequency = CPUFREQ_ENTRY_INVALID; + pos->frequency); + pos->frequency = CPUFREQ_ENTRY_INVALID; } else { - freq++; continue; } } /* Check for frequencies we can generate */ rate = clk_round_rate(s3c_freq->armdiv, - freq->frequency * 1000); + pos->frequency * 1000); rate /= 1000; - if (rate != freq->frequency) { + if (rate != pos->frequency) { pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n", - freq->frequency, rate); - freq->frequency = CPUFREQ_ENTRY_INVALID; + pos->frequency, rate); + pos->frequency = CPUFREQ_ENTRY_INVALID; } - - freq++; } /* Datasheet says PLL stabalisation time must be at least 300us, diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index be1b2b5c9753b6..227ebf7c1eeab0 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -141,6 +141,7 @@ static int s3c_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg) static void s3c_cpufreq_setfvco(struct s3c_cpufreq_config *cfg) { + cfg->mpll = _clk_mpll; (cfg->info->set_fvco)(cfg); } diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index ff7d3ecb85f0f3..176e84cc399199 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -118,11 +118,10 @@ static void __init s3c64xx_cpufreq_config_regulator(void) pr_err("Unable to check supported voltages\n"); } - freq = s3c64xx_freq_table; - while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) { - if (freq->frequency == CPUFREQ_ENTRY_INVALID) - continue; + if (!count) + goto out; + cpufreq_for_each_valid_entry(freq, s3c64xx_freq_table) { dvfs = &s3c64xx_dvfs_table[freq->driver_data]; found = 0; @@ -137,10 +136,9 @@ static void __init s3c64xx_cpufreq_config_regulator(void) freq->frequency); freq->frequency = CPUFREQ_ENTRY_INVALID; } - - freq++; } +out: /* Guess based on having to do an I2C/SPI write; in future we * will be able to query the regulator performance here. */ regulator_latency = 1 * 1000 * 1000; @@ -179,8 +177,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy) } #endif - freq = s3c64xx_freq_table; - while (freq->frequency != CPUFREQ_TABLE_END) { + cpufreq_for_each_entry(freq, s3c64xx_freq_table) { unsigned long r; /* Check for frequencies we can generate */ @@ -196,8 +193,6 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy) * frequency is the maximum we can support. */ if (!vddarm && freq->frequency > clk_get_rate(policy->clk) / 1000) freq->frequency = CPUFREQ_ENTRY_INVALID; - - freq++; } /* Datasheet says PLL stabalisation time (if we were to use diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c index 6723f0390f20da..7d4a3157160852 100644 --- a/drivers/cpufreq/speedstep-centrino.c +++ b/drivers/cpufreq/speedstep-centrino.c @@ -28,7 +28,7 @@ #include #define PFX "speedstep-centrino: " -#define MAINTAINER "cpufreq@vger.kernel.org" +#define MAINTAINER "linux-pm@vger.kernel.org" #define INTEL_MSR_RANGE (0xffff) diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index 97ccc31dbdd8fb..ae1d78ea7df7f7 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -1,6 +1,11 @@ # # ARM CPU Idle drivers # +config ARM_ARMADA_370_XP_CPUIDLE + bool "CPU Idle Driver for Armada 370/XP family processors" + depends on ARCH_MVEBU + help + Select this to enable cpuidle on Armada 370/XP processors. config ARM_BIG_LITTLE_CPUIDLE bool "Support for ARM big.LITTLE processors" @@ -44,3 +49,9 @@ config ARM_AT91_CPUIDLE depends on ARCH_AT91 help Select this to enable cpuidle for AT91 processors + +config ARM_EXYNOS_CPUIDLE + bool "Cpu Idle Driver for the Exynos processors" + depends on ARCH_EXYNOS + help + Select this to enable cpuidle for Exynos processors diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index f71ae1b373c5e8..cd3ab59f84614d 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -7,12 +7,14 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o ################################################################################## # ARM SoC drivers +obj-$(CONFIG_ARM_ARMADA_370_XP_CPUIDLE) += cpuidle-armada-370-xp.o obj-$(CONFIG_ARM_BIG_LITTLE_CPUIDLE) += cpuidle-big_little.o obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE) += cpuidle-calxeda.o obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE) += cpuidle-kirkwood.o obj-$(CONFIG_ARM_ZYNQ_CPUIDLE) += cpuidle-zynq.o obj-$(CONFIG_ARM_U8500_CPUIDLE) += cpuidle-ux500.o obj-$(CONFIG_ARM_AT91_CPUIDLE) += cpuidle-at91.o +obj-$(CONFIG_ARM_EXYNOS_CPUIDLE) += cpuidle-exynos.o ############################################################################### # POWERPC drivers diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c index cb6654bfad77f7..73fe2f8d7f961d 100644 --- a/drivers/cpuidle/coupled.c +++ b/drivers/cpuidle/coupled.c @@ -159,7 +159,7 @@ void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, atomic_t *a) { int n = dev->coupled->online_count; - smp_mb__before_atomic_inc(); + smp_mb__before_atomic(); atomic_inc(a); while (atomic_read(a) < n) diff --git a/drivers/cpuidle/cpuidle-armada-370-xp.c b/drivers/cpuidle/cpuidle-armada-370-xp.c new file mode 100644 index 00000000000000..28587d0f3947df --- /dev/null +++ b/drivers/cpuidle/cpuidle-armada-370-xp.c @@ -0,0 +1,93 @@ +/* + * Marvell Armada 370 and Armada XP SoC cpuidle driver + * + * Copyright (C) 2014 Marvell + * + * Nadav Haklai + * Gregory CLEMENT + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * Maintainer: Gregory CLEMENT + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ARMADA_370_XP_MAX_STATES 3 +#define ARMADA_370_XP_FLAG_DEEP_IDLE 0x10000 + +static int (*armada_370_xp_cpu_suspend)(int); + +static int armada_370_xp_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + int ret; + bool deepidle = false; + cpu_pm_enter(); + + if (drv->states[index].flags & ARMADA_370_XP_FLAG_DEEP_IDLE) + deepidle = true; + + ret = armada_370_xp_cpu_suspend(deepidle); + if (ret) + return ret; + + cpu_pm_exit(); + + return index; +} + +static struct cpuidle_driver armada_370_xp_idle_driver = { + .name = "armada_370_xp_idle", + .states[0] = ARM_CPUIDLE_WFI_STATE, + .states[1] = { + .enter = armada_370_xp_enter_idle, + .exit_latency = 10, + .power_usage = 50, + .target_residency = 100, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "MV CPU IDLE", + .desc = "CPU power down", + }, + .states[2] = { + .enter = armada_370_xp_enter_idle, + .exit_latency = 100, + .power_usage = 5, + .target_residency = 1000, + .flags = CPUIDLE_FLAG_TIME_VALID | + ARMADA_370_XP_FLAG_DEEP_IDLE, + .name = "MV CPU DEEP IDLE", + .desc = "CPU and L2 Fabric power down", + }, + .state_count = ARMADA_370_XP_MAX_STATES, +}; + +static int armada_370_xp_cpuidle_probe(struct platform_device *pdev) +{ + + armada_370_xp_cpu_suspend = (void *)(pdev->dev.platform_data); + return cpuidle_register(&armada_370_xp_idle_driver, NULL); +} + +static struct platform_driver armada_370_xp_cpuidle_plat_driver = { + .driver = { + .name = "cpuidle-armada-370-xp", + .owner = THIS_MODULE, + }, + .probe = armada_370_xp_cpuidle_probe, +}; + +module_platform_driver(armada_370_xp_cpuidle_plat_driver); + +MODULE_AUTHOR("Gregory CLEMENT "); +MODULE_DESCRIPTION("Armada 370/XP cpu idle driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/cpuidle/cpuidle-exynos.c b/drivers/cpuidle/cpuidle-exynos.c new file mode 100644 index 00000000000000..7c015126382833 --- /dev/null +++ b/drivers/cpuidle/cpuidle-exynos.c @@ -0,0 +1,99 @@ +/* linux/arch/arm/mach-exynos/cpuidle.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * 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 + +#include +#include +#include + +static void (*exynos_enter_aftr)(void); + +static int idle_finisher(unsigned long flags) +{ + exynos_enter_aftr(); + cpu_do_idle(); + + return 1; +} + +static int exynos_enter_core0_aftr(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + cpu_pm_enter(); + cpu_suspend(0, idle_finisher); + cpu_pm_exit(); + + return index; +} + +static int exynos_enter_lowpower(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + int new_index = index; + + /* AFTR can only be entered when cores other than CPU0 are offline */ + if (num_online_cpus() > 1 || dev->cpu != 0) + new_index = drv->safe_state_index; + + if (new_index == 0) + return arm_cpuidle_simple_enter(dev, drv, new_index); + else + return exynos_enter_core0_aftr(dev, drv, new_index); +} + +static struct cpuidle_driver exynos_idle_driver = { + .name = "exynos_idle", + .owner = THIS_MODULE, + .states = { + [0] = ARM_CPUIDLE_WFI_STATE, + [1] = { + .enter = exynos_enter_lowpower, + .exit_latency = 300, + .target_residency = 100000, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "C1", + .desc = "ARM power down", + }, + }, + .state_count = 2, + .safe_state_index = 0, +}; + +static int exynos_cpuidle_probe(struct platform_device *pdev) +{ + int ret; + + exynos_enter_aftr = (void *)(pdev->dev.platform_data); + + ret = cpuidle_register(&exynos_idle_driver, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to register cpuidle driver\n"); + return ret; + } + + return 0; +} + +static struct platform_driver exynos_cpuidle_driver = { + .probe = exynos_cpuidle_probe, + .driver = { + .name = "exynos_cpuidle", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(exynos_cpuidle_driver); diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 8236746e46bb9d..cb7019977c50fe 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -32,6 +32,7 @@ LIST_HEAD(cpuidle_detected_devices); static int enabled_devices; static int off __read_mostly; static int initialized __read_mostly; +static bool use_deepest_state __read_mostly; int cpuidle_disabled(void) { @@ -65,23 +66,42 @@ int cpuidle_play_dead(void) } /** - * cpuidle_enabled - check if the cpuidle framework is ready - * @dev: cpuidle device for this cpu - * @drv: cpuidle driver for this cpu + * cpuidle_use_deepest_state - Enable/disable the "deepest idle" mode. + * @enable: Whether enable or disable the feature. + * + * If the "deepest idle" mode is enabled, cpuidle will ignore the governor and + * always use the state with the greatest exit latency (out of the states that + * are not disabled). * - * Return 0 on success, otherwise: - * -NODEV : the cpuidle framework is not available - * -EBUSY : the cpuidle framework is not initialized + * This function can only be called after cpuidle_pause() to avoid races. */ -int cpuidle_enabled(struct cpuidle_driver *drv, struct cpuidle_device *dev) +void cpuidle_use_deepest_state(bool enable) { - if (off || !initialized) - return -ENODEV; + use_deepest_state = enable; +} - if (!drv || !dev || !dev->enabled) - return -EBUSY; +/** + * cpuidle_find_deepest_state - Find the state of the greatest exit latency. + * @drv: cpuidle driver for a given CPU. + * @dev: cpuidle device for a given CPU. + */ +static int cpuidle_find_deepest_state(struct cpuidle_driver *drv, + struct cpuidle_device *dev) +{ + unsigned int latency_req = 0; + int i, ret = CPUIDLE_DRIVER_STATE_START - 1; - return 0; + for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { + struct cpuidle_state *s = &drv->states[i]; + struct cpuidle_state_usage *su = &dev->states_usage[i]; + + if (s->disabled || su->disable || s->exit_latency <= latency_req) + continue; + + latency_req = s->exit_latency; + ret = i; + } + return ret; } /** @@ -138,6 +158,15 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, */ int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) { + if (off || !initialized) + return -ENODEV; + + if (!drv || !dev || !dev->enabled) + return -EBUSY; + + if (unlikely(use_deepest_state)) + return cpuidle_find_deepest_state(drv, dev); + return cpuidle_curr_governor->select(drv, dev); } @@ -169,7 +198,7 @@ int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev, */ void cpuidle_reflect(struct cpuidle_device *dev, int index) { - if (cpuidle_curr_governor->reflect) + if (cpuidle_curr_governor->reflect && !unlikely(use_deepest_state)) cpuidle_curr_governor->reflect(dev, index); } diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 71b52329335472..c4f80c15a48dde 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -296,7 +296,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) data->needs_update = 0; } - data->last_state_idx = 0; + data->last_state_idx = CPUIDLE_DRIVER_STATE_START - 1; /* Special case when user has set very strict latency requirement */ if (unlikely(latency_req == 0)) @@ -310,13 +310,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) data->bucket = which_bucket(data->next_timer_us); - /* - * if the correction factor is 0 (eg first time init or cpu hotplug - * etc), we actually want to start out with a unity factor. - */ - if (data->correction_factor[data->bucket] == 0) - data->correction_factor[data->bucket] = RESOLUTION * DECAY; - /* * Force the result of multiplication to be 64 bits even if both * operands are 32 bits. @@ -466,9 +459,17 @@ static int menu_enable_device(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = &per_cpu(menu_devices, dev->cpu); + int i; memset(data, 0, sizeof(struct menu_device)); + /* + * if the correction factor is 0 (eg first time init or cpu hotplug + * etc), we actually want to start out with a unity factor. + */ + for(i = 0; i < BUCKETS; i++) + data->correction_factor[i] = RESOLUTION * DECAY; + return 0; } diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 03ccdb0ccf9ea3..f066fa23cc050f 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -301,14 +301,14 @@ config CRYPTO_DEV_SAHARA found in some Freescale i.MX chips. config CRYPTO_DEV_S5P - tristate "Support for Samsung S5PV210 crypto accelerator" - depends on ARCH_S5PV210 + tristate "Support for Samsung S5PV210/Exynos crypto accelerator" + depends on ARCH_S5PV210 || ARCH_EXYNOS select CRYPTO_AES select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER help This option allows you to have support for S5P crypto acceleration. - Select this to offload Samsung S5PV210 or S5PC110 from AES + Select this to offload Samsung S5PV210 or S5PC110, Exynos from AES algorithms execution. config CRYPTO_DEV_NX diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index d7c9e317423cb2..a083474991abbb 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -716,6 +716,12 @@ static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode) return -EINVAL; } ctx->block_size = CFB32_BLOCK_SIZE; + } else if (mode & AES_FLAGS_CFB64) { + if (!IS_ALIGNED(req->nbytes, CFB64_BLOCK_SIZE)) { + pr_err("request size is not exact amount of CFB64 blocks\n"); + return -EINVAL; + } + ctx->block_size = CFB64_BLOCK_SIZE; } else { if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) { pr_err("request size is not exact amount of AES blocks\n"); @@ -1069,7 +1075,7 @@ static struct crypto_alg aes_algs[] = { .cra_driver_name = "atmel-cfb8-aes", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = CFB64_BLOCK_SIZE, + .cra_blocksize = CFB8_BLOCK_SIZE, .cra_ctxsize = sizeof(struct atmel_aes_ctx), .cra_alignmask = 0x0, .cra_type = &crypto_ablkcipher_type, diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c index c9ff298e6d26e8..b099e33cb07303 100644 --- a/drivers/crypto/bfin_crc.c +++ b/drivers/crypto/bfin_crc.c @@ -29,10 +29,11 @@ #include #include -#include -#include #include #include +#include + +#include "bfin_crc.h" #define CRC_CCRYPTO_QUEUE_LENGTH 5 @@ -54,12 +55,13 @@ struct bfin_crypto_crc { int irq; int dma_ch; u32 poly; - volatile struct crc_register *regs; + struct crc_register *regs; struct ahash_request *req; /* current request in operation */ struct dma_desc_array *sg_cpu; /* virt addr of sg dma descriptors */ dma_addr_t sg_dma; /* phy addr of sg dma descriptors */ u8 *sg_mid_buf; + dma_addr_t sg_mid_dma; /* phy addr of sg mid buffer */ struct tasklet_struct done_task; struct crypto_queue queue; /* waiting requests */ @@ -132,13 +134,13 @@ static struct scatterlist *sg_get(struct scatterlist *sg_list, unsigned int nent static int bfin_crypto_crc_init_hw(struct bfin_crypto_crc *crc, u32 key) { - crc->regs->datacntrld = 0; - crc->regs->control = MODE_CALC_CRC << OPMODE_OFFSET; - crc->regs->curresult = key; + writel(0, &crc->regs->datacntrld); + writel(MODE_CALC_CRC << OPMODE_OFFSET, &crc->regs->control); + writel(key, &crc->regs->curresult); /* setup CRC interrupts */ - crc->regs->status = CMPERRI | DCNTEXPI; - crc->regs->intrenset = CMPERRI | DCNTEXPI; + writel(CMPERRI | DCNTEXPI, &crc->regs->status); + writel(CMPERRI | DCNTEXPI, &crc->regs->intrenset); return 0; } @@ -194,7 +196,6 @@ static void bfin_crypto_crc_config_dma(struct bfin_crypto_crc *crc) dma_map_sg(crc->dev, ctx->sg, ctx->sg_nents, DMA_TO_DEVICE); for_each_sg(ctx->sg, sg, ctx->sg_nents, j) { - dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | DMAEN | PSIZE_32; dma_addr = sg_dma_address(sg); /* deduce extra bytes in last sg */ if (sg_is_last(sg)) @@ -207,12 +208,29 @@ static void bfin_crypto_crc_config_dma(struct bfin_crypto_crc *crc) bytes in current sg buffer. Move addr of current sg and deduce the length of current sg. */ - memcpy(crc->sg_mid_buf +((i-1) << 2) + mid_dma_count, - (void *)dma_addr, + memcpy(crc->sg_mid_buf +(i << 2) + mid_dma_count, + sg_virt(sg), CHKSUM_DIGEST_SIZE - mid_dma_count); dma_addr += CHKSUM_DIGEST_SIZE - mid_dma_count; dma_count -= CHKSUM_DIGEST_SIZE - mid_dma_count; + + dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | + DMAEN | PSIZE_32 | WDSIZE_32; + + /* setup new dma descriptor for next middle dma */ + crc->sg_cpu[i].start_addr = crc->sg_mid_dma + (i << 2); + crc->sg_cpu[i].cfg = dma_config; + crc->sg_cpu[i].x_count = 1; + crc->sg_cpu[i].x_modify = CHKSUM_DIGEST_SIZE; + dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, " + "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n", + i, crc->sg_cpu[i].start_addr, + crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count, + crc->sg_cpu[i].x_modify); + i++; } + + dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | DMAEN | PSIZE_32; /* chop current sg dma len to multiple of 32 bits */ mid_dma_count = dma_count % 4; dma_count &= ~0x3; @@ -243,24 +261,9 @@ static void bfin_crypto_crc_config_dma(struct bfin_crypto_crc *crc) if (mid_dma_count) { /* copy extra bytes to next middle dma buffer */ - dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | - DMAEN | PSIZE_32 | WDSIZE_32; memcpy(crc->sg_mid_buf + (i << 2), - (void *)(dma_addr + (dma_count << 2)), + (u8*)sg_virt(sg) + (dma_count << 2), mid_dma_count); - /* setup new dma descriptor for next middle dma */ - crc->sg_cpu[i].start_addr = dma_map_single(crc->dev, - crc->sg_mid_buf + (i << 2), - CHKSUM_DIGEST_SIZE, DMA_TO_DEVICE); - crc->sg_cpu[i].cfg = dma_config; - crc->sg_cpu[i].x_count = 1; - crc->sg_cpu[i].x_modify = CHKSUM_DIGEST_SIZE; - dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, " - "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n", - i, crc->sg_cpu[i].start_addr, - crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count, - crc->sg_cpu[i].x_modify); - i++; } } @@ -303,6 +306,7 @@ static int bfin_crypto_crc_handle_queue(struct bfin_crypto_crc *crc, int nsg, i, j; unsigned int nextlen; unsigned long flags; + u32 reg; spin_lock_irqsave(&crc->lock, flags); if (req) @@ -402,13 +406,14 @@ static int bfin_crypto_crc_handle_queue(struct bfin_crypto_crc *crc, ctx->sg_buflen += CHKSUM_DIGEST_SIZE; /* set CRC data count before start DMA */ - crc->regs->datacnt = ctx->sg_buflen >> 2; + writel(ctx->sg_buflen >> 2, &crc->regs->datacnt); /* setup and enable CRC DMA */ bfin_crypto_crc_config_dma(crc); /* finally kick off CRC operation */ - crc->regs->control |= BLKEN; + reg = readl(&crc->regs->control); + writel(reg | BLKEN, &crc->regs->control); return -EINPROGRESS; } @@ -529,14 +534,17 @@ static void bfin_crypto_crc_done_task(unsigned long data) static irqreturn_t bfin_crypto_crc_handler(int irq, void *dev_id) { struct bfin_crypto_crc *crc = dev_id; + u32 reg; - if (crc->regs->status & DCNTEXP) { - crc->regs->status = DCNTEXP; + if (readl(&crc->regs->status) & DCNTEXP) { + writel(DCNTEXP, &crc->regs->status); /* prepare results */ - put_unaligned_le32(crc->regs->result, crc->req->result); + put_unaligned_le32(readl(&crc->regs->result), + crc->req->result); - crc->regs->control &= ~BLKEN; + reg = readl(&crc->regs->control); + writel(reg & ~BLKEN, &crc->regs->control); crc->busy = 0; if (crc->req->base.complete) @@ -560,7 +568,7 @@ static int bfin_crypto_crc_suspend(struct platform_device *pdev, pm_message_t st struct bfin_crypto_crc *crc = platform_get_drvdata(pdev); int i = 100000; - while ((crc->regs->control & BLKEN) && --i) + while ((readl(&crc->regs->control) & BLKEN) && --i) cpu_relax(); if (i == 0) @@ -647,29 +655,32 @@ static int bfin_crypto_crc_probe(struct platform_device *pdev) * 1 last + 1 next dma descriptors */ crc->sg_mid_buf = (u8 *)(crc->sg_cpu + ((CRC_MAX_DMA_DESC + 1) << 1)); + crc->sg_mid_dma = crc->sg_dma + sizeof(struct dma_desc_array) + * ((CRC_MAX_DMA_DESC + 1) << 1); - crc->regs->control = 0; - crc->regs->poly = crc->poly = (u32)pdev->dev.platform_data; + writel(0, &crc->regs->control); + crc->poly = (u32)pdev->dev.platform_data; + writel(crc->poly, &crc->regs->poly); - while (!(crc->regs->status & LUTDONE) && (--timeout) > 0) + while (!(readl(&crc->regs->status) & LUTDONE) && (--timeout) > 0) cpu_relax(); if (timeout == 0) dev_info(&pdev->dev, "init crc poly timeout\n"); + platform_set_drvdata(pdev, crc); + spin_lock(&crc_list.lock); list_add(&crc->list, &crc_list.dev_list); spin_unlock(&crc_list.lock); - platform_set_drvdata(pdev, crc); - - ret = crypto_register_ahash(&algs); - if (ret) { - spin_lock(&crc_list.lock); - list_del(&crc->list); - spin_unlock(&crc_list.lock); - dev_err(&pdev->dev, "Cann't register crypto ahash device\n"); - goto out_error_dma; + if (list_is_singular(&crc_list.dev_list)) { + ret = crypto_register_ahash(&algs); + if (ret) { + dev_err(&pdev->dev, + "Can't register crypto ahash device\n"); + goto out_error_dma; + } } dev_info(&pdev->dev, "initialized\n"); diff --git a/drivers/crypto/bfin_crc.h b/drivers/crypto/bfin_crc.h new file mode 100644 index 00000000000000..75cef4dc85a1a8 --- /dev/null +++ b/drivers/crypto/bfin_crc.h @@ -0,0 +1,125 @@ +/* + * bfin_crc.h - interface to Blackfin CRC controllers + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __BFIN_CRC_H__ +#define __BFIN_CRC_H__ + +/* Function driver which use hardware crc must initialize the structure */ +struct crc_info { + /* Input data address */ + unsigned char *in_addr; + /* Output data address */ + unsigned char *out_addr; + /* Input or output bytes */ + unsigned long datasize; + union { + /* CRC to compare with that of input buffer */ + unsigned long crc_compare; + /* Value to compare with input data */ + unsigned long val_verify; + /* Value to fill */ + unsigned long val_fill; + }; + /* Value to program the 32b CRC Polynomial */ + unsigned long crc_poly; + union { + /* CRC calculated from the input data */ + unsigned long crc_result; + /* First failed position to verify input data */ + unsigned long pos_verify; + }; + /* CRC mirror flags */ + unsigned int bitmirr:1; + unsigned int bytmirr:1; + unsigned int w16swp:1; + unsigned int fdsel:1; + unsigned int rsltmirr:1; + unsigned int polymirr:1; + unsigned int cmpmirr:1; +}; + +/* Userspace interface */ +#define CRC_IOC_MAGIC 'C' +#define CRC_IOC_CALC_CRC _IOWR('C', 0x01, unsigned int) +#define CRC_IOC_MEMCPY_CRC _IOWR('C', 0x02, unsigned int) +#define CRC_IOC_VERIFY_VAL _IOWR('C', 0x03, unsigned int) +#define CRC_IOC_FILL_VAL _IOWR('C', 0x04, unsigned int) + + +#ifdef __KERNEL__ + +#include +#include +#include + +struct crc_register { + u32 control; + u32 datacnt; + u32 datacntrld; + u32 __pad_1[2]; + u32 compare; + u32 fillval; + u32 datafifo; + u32 intren; + u32 intrenset; + u32 intrenclr; + u32 poly; + u32 __pad_2[4]; + u32 status; + u32 datacntcap; + u32 __pad_3; + u32 result; + u32 curresult; + u32 __pad_4[3]; + u32 revid; +}; + +/* CRC_STATUS Masks */ +#define CMPERR 0x00000002 /* Compare error */ +#define DCNTEXP 0x00000010 /* datacnt register expired */ +#define IBR 0x00010000 /* Input buffer ready */ +#define OBR 0x00020000 /* Output buffer ready */ +#define IRR 0x00040000 /* Immediate result readt */ +#define LUTDONE 0x00080000 /* Look-up table generation done */ +#define FSTAT 0x00700000 /* FIFO status */ +#define MAX_FIFO 4 /* Max fifo size */ + +/* CRC_CONTROL Masks */ +#define BLKEN 0x00000001 /* Block enable */ +#define OPMODE 0x000000F0 /* Operation mode */ +#define OPMODE_OFFSET 4 /* Operation mode mask offset*/ +#define MODE_DMACPY_CRC 1 /* MTM CRC compute and compare */ +#define MODE_DATA_FILL 2 /* MTM data fill */ +#define MODE_CALC_CRC 3 /* MSM CRC compute and compare */ +#define MODE_DATA_VERIFY 4 /* MSM data verify */ +#define AUTOCLRZ 0x00000100 /* Auto clear to zero */ +#define AUTOCLRF 0x00000200 /* Auto clear to one */ +#define OBRSTALL 0x00001000 /* Stall on output buffer ready */ +#define IRRSTALL 0x00002000 /* Stall on immediate result ready */ +#define BITMIRR 0x00010000 /* Mirror bits within each byte of 32-bit input data */ +#define BITMIRR_OFFSET 16 /* Mirror bits offset */ +#define BYTMIRR 0x00020000 /* Mirror bytes of 32-bit input data */ +#define BYTMIRR_OFFSET 17 /* Mirror bytes offset */ +#define W16SWP 0x00040000 /* Mirror uppper and lower 16-bit word of 32-bit input data */ +#define W16SWP_OFFSET 18 /* Mirror 16-bit word offset */ +#define FDSEL 0x00080000 /* FIFO is written after input data is mirrored */ +#define FDSEL_OFFSET 19 /* Mirror FIFO offset */ +#define RSLTMIRR 0x00100000 /* CRC result registers are mirrored. */ +#define RSLTMIRR_OFFSET 20 /* Mirror CRC result offset. */ +#define POLYMIRR 0x00200000 /* CRC poly register is mirrored. */ +#define POLYMIRR_OFFSET 21 /* Mirror CRC poly offset. */ +#define CMPMIRR 0x00400000 /* CRC compare register is mirrored. */ +#define CMPMIRR_OFFSET 22 /* Mirror CRC compare offset. */ + +/* CRC_INTREN Masks */ +#define CMPERRI 0x02 /* CRC_ERROR_INTR */ +#define DCNTEXPI 0x10 /* CRC_STATUS_INTR */ + +#endif + +#endif diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 5f891254db73f9..339277c7acb9b6 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -918,11 +918,8 @@ static void aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err, edesc = (struct aead_edesc *)((char *)desc - offsetof(struct aead_edesc, hw_desc)); - if (err) { - char tmp[CAAM_ERROR_STR_MAX]; - - dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); - } + if (err) + caam_jr_strstatus(jrdev, err); aead_unmap(jrdev, edesc, req); @@ -969,11 +966,8 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err, req->cryptlen - ctx->authsize, 1); #endif - if (err) { - char tmp[CAAM_ERROR_STR_MAX]; - - dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); - } + if (err) + caam_jr_strstatus(jrdev, err); aead_unmap(jrdev, edesc, req); @@ -1018,11 +1012,8 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, edesc = (struct ablkcipher_edesc *)((char *)desc - offsetof(struct ablkcipher_edesc, hw_desc)); - if (err) { - char tmp[CAAM_ERROR_STR_MAX]; - - dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); - } + if (err) + caam_jr_strstatus(jrdev, err); #ifdef DEBUG print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", @@ -1053,11 +1044,8 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, edesc = (struct ablkcipher_edesc *)((char *)desc - offsetof(struct ablkcipher_edesc, hw_desc)); - if (err) { - char tmp[CAAM_ERROR_STR_MAX]; - - dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); - } + if (err) + caam_jr_strstatus(jrdev, err); #ifdef DEBUG print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 0378328f47a775..0d9284ef96a856 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -545,7 +545,8 @@ static int ahash_setkey(struct crypto_ahash *ahash, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, ctx->key_dma)) { dev_err(jrdev, "unable to map key i/o memory\n"); - return -ENOMEM; + ret = -ENOMEM; + goto map_err; } #ifdef DEBUG print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", @@ -559,6 +560,7 @@ static int ahash_setkey(struct crypto_ahash *ahash, DMA_TO_DEVICE); } +map_err: kfree(hashed_key); return ret; badkey: @@ -631,11 +633,8 @@ static void ahash_done(struct device *jrdev, u32 *desc, u32 err, edesc = (struct ahash_edesc *)((char *)desc - offsetof(struct ahash_edesc, hw_desc)); - if (err) { - char tmp[CAAM_ERROR_STR_MAX]; - - dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); - } + if (err) + caam_jr_strstatus(jrdev, err); ahash_unmap(jrdev, edesc, req, digestsize); kfree(edesc); @@ -669,11 +668,8 @@ static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err, edesc = (struct ahash_edesc *)((char *)desc - offsetof(struct ahash_edesc, hw_desc)); - if (err) { - char tmp[CAAM_ERROR_STR_MAX]; - - dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); - } + if (err) + caam_jr_strstatus(jrdev, err); ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL); kfree(edesc); @@ -707,11 +703,8 @@ static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err, edesc = (struct ahash_edesc *)((char *)desc - offsetof(struct ahash_edesc, hw_desc)); - if (err) { - char tmp[CAAM_ERROR_STR_MAX]; - - dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); - } + if (err) + caam_jr_strstatus(jrdev, err); ahash_unmap_ctx(jrdev, edesc, req, digestsize, DMA_FROM_DEVICE); kfree(edesc); @@ -745,11 +738,8 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err, edesc = (struct ahash_edesc *)((char *)desc - offsetof(struct ahash_edesc, hw_desc)); - if (err) { - char tmp[CAAM_ERROR_STR_MAX]; - - dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); - } + if (err) + caam_jr_strstatus(jrdev, err); ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_TO_DEVICE); kfree(edesc); diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index 3529b54048c9bf..8c07d3153f125d 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -103,11 +103,8 @@ static void rng_done(struct device *jrdev, u32 *desc, u32 err, void *context) bd = (struct buf_data *)((char *)desc - offsetof(struct buf_data, hw_desc)); - if (err) { - char tmp[CAAM_ERROR_STR_MAX]; - - dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); - } + if (err) + caam_jr_strstatus(jrdev, err); atomic_set(&bd->empty, BUF_NOT_EMPTY); complete(&bd->filled); diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c index 9f25f5296029ae..6531054a44c8b8 100644 --- a/drivers/crypto/caam/error.c +++ b/drivers/crypto/caam/error.c @@ -11,243 +11,208 @@ #include "jr.h" #include "error.h" -#define SPRINTFCAT(str, format, param, max_alloc) \ -{ \ - char *tmp; \ - \ - tmp = kmalloc(sizeof(format) + max_alloc, GFP_ATOMIC); \ - sprintf(tmp, format, param); \ - strcat(str, tmp); \ - kfree(tmp); \ -} - -static void report_jump_idx(u32 status, char *outstr) +static const struct { + u8 value; + const char *error_text; +} desc_error_list[] = { + { 0x00, "No error." }, + { 0x01, "SGT Length Error. The descriptor is trying to read more data than is contained in the SGT table." }, + { 0x02, "SGT Null Entry Error." }, + { 0x03, "Job Ring Control Error. There is a bad value in the Job Ring Control register." }, + { 0x04, "Invalid Descriptor Command. The Descriptor Command field is invalid." }, + { 0x05, "Reserved." }, + { 0x06, "Invalid KEY Command" }, + { 0x07, "Invalid LOAD Command" }, + { 0x08, "Invalid STORE Command" }, + { 0x09, "Invalid OPERATION Command" }, + { 0x0A, "Invalid FIFO LOAD Command" }, + { 0x0B, "Invalid FIFO STORE Command" }, + { 0x0C, "Invalid MOVE/MOVE_LEN Command" }, + { 0x0D, "Invalid JUMP Command. A nonlocal JUMP Command is invalid because the target is not a Job Header Command, or the jump is from a Trusted Descriptor to a Job Descriptor, or because the target Descriptor contains a Shared Descriptor." }, + { 0x0E, "Invalid MATH Command" }, + { 0x0F, "Invalid SIGNATURE Command" }, + { 0x10, "Invalid Sequence Command. A SEQ IN PTR OR SEQ OUT PTR Command is invalid or a SEQ KEY, SEQ LOAD, SEQ FIFO LOAD, or SEQ FIFO STORE decremented the input or output sequence length below 0. This error may result if a built-in PROTOCOL Command has encountered a malformed PDU." }, + { 0x11, "Skip data type invalid. The type must be 0xE or 0xF."}, + { 0x12, "Shared Descriptor Header Error" }, + { 0x13, "Header Error. Invalid length or parity, or certain other problems." }, + { 0x14, "Burster Error. Burster has gotten to an illegal state" }, + { 0x15, "Context Register Length Error. The descriptor is trying to read or write past the end of the Context Register. A SEQ LOAD or SEQ STORE with the VLF bit set was executed with too large a length in the variable length register (VSOL for SEQ STORE or VSIL for SEQ LOAD)." }, + { 0x16, "DMA Error" }, + { 0x17, "Reserved." }, + { 0x1A, "Job failed due to JR reset" }, + { 0x1B, "Job failed due to Fail Mode" }, + { 0x1C, "DECO Watchdog timer timeout error" }, + { 0x1D, "DECO tried to copy a key from another DECO but the other DECO's Key Registers were locked" }, + { 0x1E, "DECO attempted to copy data from a DECO that had an unmasked Descriptor error" }, + { 0x1F, "LIODN error. DECO was trying to share from itself or from another DECO but the two Non-SEQ LIODN values didn't match or the 'shared from' DECO's Descriptor required that the SEQ LIODNs be the same and they aren't." }, + { 0x20, "DECO has completed a reset initiated via the DRR register" }, + { 0x21, "Nonce error. When using EKT (CCM) key encryption option in the FIFO STORE Command, the Nonce counter reached its maximum value and this encryption mode can no longer be used." }, + { 0x22, "Meta data is too large (> 511 bytes) for TLS decap (input frame; block ciphers) and IPsec decap (output frame, when doing the next header byte update) and DCRC (output frame)." }, + { 0x23, "Read Input Frame error" }, + { 0x24, "JDKEK, TDKEK or TDSK not loaded error" }, + { 0x80, "DNR (do not run) error" }, + { 0x81, "undefined protocol command" }, + { 0x82, "invalid setting in PDB" }, + { 0x83, "Anti-replay LATE error" }, + { 0x84, "Anti-replay REPLAY error" }, + { 0x85, "Sequence number overflow" }, + { 0x86, "Sigver invalid signature" }, + { 0x87, "DSA Sign Illegal test descriptor" }, + { 0x88, "Protocol Format Error - A protocol has seen an error in the format of data received. When running RSA, this means that formatting with random padding was used, and did not follow the form: 0x00, 0x02, 8-to-N bytes of non-zero pad, 0x00, F data." }, + { 0x89, "Protocol Size Error - A protocol has seen an error in size. When running RSA, pdb size N < (size of F) when no formatting is used; or pdb size N < (F + 11) when formatting is used." }, + { 0xC1, "Blob Command error: Undefined mode" }, + { 0xC2, "Blob Command error: Secure Memory Blob mode error" }, + { 0xC4, "Blob Command error: Black Blob key or input size error" }, + { 0xC5, "Blob Command error: Invalid key destination" }, + { 0xC8, "Blob Command error: Trusted/Secure mode error" }, + { 0xF0, "IPsec TTL or hop limit field either came in as 0, or was decremented to 0" }, + { 0xF1, "3GPP HFN matches or exceeds the Threshold" }, +}; + +static const char * const cha_id_list[] = { + "", + "AES", + "DES", + "ARC4", + "MDHA", + "RNG", + "SNOW f8", + "Kasumi f8/9", + "PKHA", + "CRCA", + "SNOW f9", + "ZUCE", + "ZUCA", +}; + +static const char * const err_id_list[] = { + "No error.", + "Mode error.", + "Data size error.", + "Key size error.", + "PKHA A memory size error.", + "PKHA B memory size error.", + "Data arrived out of sequence error.", + "PKHA divide-by-zero error.", + "PKHA modulus even error.", + "DES key parity error.", + "ICV check failed.", + "Hardware error.", + "Unsupported CCM AAD size.", + "Class 1 CHA is not reset", + "Invalid CHA combination was selected", + "Invalid CHA selected.", +}; + +static const char * const rng_err_id_list[] = { + "", + "", + "", + "Instantiate", + "Not instantiated", + "Test instantiate", + "Prediction resistance", + "Prediction resistance and test request", + "Uninstantiate", + "Secure key generation", +}; + +static void report_ccb_status(struct device *jrdev, const u32 status, + const char *error) { + u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >> + JRSTA_CCBERR_CHAID_SHIFT; + u8 err_id = status & JRSTA_CCBERR_ERRID_MASK; u8 idx = (status & JRSTA_DECOERR_INDEX_MASK) >> JRSTA_DECOERR_INDEX_SHIFT; + char *idx_str; + const char *cha_str = "unidentified cha_id value 0x"; + char cha_err_code[3] = { 0 }; + const char *err_str = "unidentified err_id value 0x"; + char err_err_code[3] = { 0 }; if (status & JRSTA_DECOERR_JUMP) - strcat(outstr, "jump tgt desc idx "); + idx_str = "jump tgt desc idx"; else - strcat(outstr, "desc idx "); - - SPRINTFCAT(outstr, "%d: ", idx, sizeof("255")); -} - -static void report_ccb_status(u32 status, char *outstr) -{ - static const char * const cha_id_list[] = { - "", - "AES", - "DES", - "ARC4", - "MDHA", - "RNG", - "SNOW f8", - "Kasumi f8/9", - "PKHA", - "CRCA", - "SNOW f9", - "ZUCE", - "ZUCA", - }; - static const char * const err_id_list[] = { - "No error.", - "Mode error.", - "Data size error.", - "Key size error.", - "PKHA A memory size error.", - "PKHA B memory size error.", - "Data arrived out of sequence error.", - "PKHA divide-by-zero error.", - "PKHA modulus even error.", - "DES key parity error.", - "ICV check failed.", - "Hardware error.", - "Unsupported CCM AAD size.", - "Class 1 CHA is not reset", - "Invalid CHA combination was selected", - "Invalid CHA selected.", - }; - static const char * const rng_err_id_list[] = { - "", - "", - "", - "Instantiate", - "Not instantiated", - "Test instantiate", - "Prediction resistance", - "Prediction resistance and test request", - "Uninstantiate", - "Secure key generation", - }; - u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >> - JRSTA_CCBERR_CHAID_SHIFT; - u8 err_id = status & JRSTA_CCBERR_ERRID_MASK; + idx_str = "desc idx"; - report_jump_idx(status, outstr); - - if (cha_id < ARRAY_SIZE(cha_id_list)) { - SPRINTFCAT(outstr, "%s: ", cha_id_list[cha_id], - strlen(cha_id_list[cha_id])); - } else { - SPRINTFCAT(outstr, "unidentified cha_id value 0x%02x: ", - cha_id, sizeof("ff")); - } + if (cha_id < ARRAY_SIZE(cha_id_list)) + cha_str = cha_id_list[cha_id]; + else + snprintf(cha_err_code, sizeof(cha_err_code), "%02x", cha_id); if ((cha_id << JRSTA_CCBERR_CHAID_SHIFT) == JRSTA_CCBERR_CHAID_RNG && err_id < ARRAY_SIZE(rng_err_id_list) && strlen(rng_err_id_list[err_id])) { /* RNG-only error */ - SPRINTFCAT(outstr, "%s", rng_err_id_list[err_id], - strlen(rng_err_id_list[err_id])); - } else if (err_id < ARRAY_SIZE(err_id_list)) { - SPRINTFCAT(outstr, "%s", err_id_list[err_id], - strlen(err_id_list[err_id])); - } else { - SPRINTFCAT(outstr, "unidentified err_id value 0x%02x", - err_id, sizeof("ff")); - } + err_str = rng_err_id_list[err_id]; + } else if (err_id < ARRAY_SIZE(err_id_list)) + err_str = err_id_list[err_id]; + else + snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id); + + dev_err(jrdev, "%08x: %s: %s %d: %s%s: %s%s\n", + status, error, idx_str, idx, + cha_str, cha_err_code, + err_str, err_err_code); } -static void report_jump_status(u32 status, char *outstr) +static void report_jump_status(struct device *jrdev, const u32 status, + const char *error) { - SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__)); + dev_err(jrdev, "%08x: %s: %s() not implemented\n", + status, error, __func__); } -static void report_deco_status(u32 status, char *outstr) +static void report_deco_status(struct device *jrdev, const u32 status, + const char *error) { - static const struct { - u8 value; - char *error_text; - } desc_error_list[] = { - { 0x00, "No error." }, - { 0x01, "SGT Length Error. The descriptor is trying to read " - "more data than is contained in the SGT table." }, - { 0x02, "SGT Null Entry Error." }, - { 0x03, "Job Ring Control Error. There is a bad value in the " - "Job Ring Control register." }, - { 0x04, "Invalid Descriptor Command. The Descriptor Command " - "field is invalid." }, - { 0x05, "Reserved." }, - { 0x06, "Invalid KEY Command" }, - { 0x07, "Invalid LOAD Command" }, - { 0x08, "Invalid STORE Command" }, - { 0x09, "Invalid OPERATION Command" }, - { 0x0A, "Invalid FIFO LOAD Command" }, - { 0x0B, "Invalid FIFO STORE Command" }, - { 0x0C, "Invalid MOVE/MOVE_LEN Command" }, - { 0x0D, "Invalid JUMP Command. A nonlocal JUMP Command is " - "invalid because the target is not a Job Header " - "Command, or the jump is from a Trusted Descriptor to " - "a Job Descriptor, or because the target Descriptor " - "contains a Shared Descriptor." }, - { 0x0E, "Invalid MATH Command" }, - { 0x0F, "Invalid SIGNATURE Command" }, - { 0x10, "Invalid Sequence Command. A SEQ IN PTR OR SEQ OUT PTR " - "Command is invalid or a SEQ KEY, SEQ LOAD, SEQ FIFO " - "LOAD, or SEQ FIFO STORE decremented the input or " - "output sequence length below 0. This error may result " - "if a built-in PROTOCOL Command has encountered a " - "malformed PDU." }, - { 0x11, "Skip data type invalid. The type must be 0xE or 0xF."}, - { 0x12, "Shared Descriptor Header Error" }, - { 0x13, "Header Error. Invalid length or parity, or certain " - "other problems." }, - { 0x14, "Burster Error. Burster has gotten to an illegal " - "state" }, - { 0x15, "Context Register Length Error. The descriptor is " - "trying to read or write past the end of the Context " - "Register. A SEQ LOAD or SEQ STORE with the VLF bit " - "set was executed with too large a length in the " - "variable length register (VSOL for SEQ STORE or VSIL " - "for SEQ LOAD)." }, - { 0x16, "DMA Error" }, - { 0x17, "Reserved." }, - { 0x1A, "Job failed due to JR reset" }, - { 0x1B, "Job failed due to Fail Mode" }, - { 0x1C, "DECO Watchdog timer timeout error" }, - { 0x1D, "DECO tried to copy a key from another DECO but the " - "other DECO's Key Registers were locked" }, - { 0x1E, "DECO attempted to copy data from a DECO that had an " - "unmasked Descriptor error" }, - { 0x1F, "LIODN error. DECO was trying to share from itself or " - "from another DECO but the two Non-SEQ LIODN values " - "didn't match or the 'shared from' DECO's Descriptor " - "required that the SEQ LIODNs be the same and they " - "aren't." }, - { 0x20, "DECO has completed a reset initiated via the DRR " - "register" }, - { 0x21, "Nonce error. When using EKT (CCM) key encryption " - "option in the FIFO STORE Command, the Nonce counter " - "reached its maximum value and this encryption mode " - "can no longer be used." }, - { 0x22, "Meta data is too large (> 511 bytes) for TLS decap " - "(input frame; block ciphers) and IPsec decap (output " - "frame, when doing the next header byte update) and " - "DCRC (output frame)." }, - { 0x23, "Read Input Frame error" }, - { 0x24, "JDKEK, TDKEK or TDSK not loaded error" }, - { 0x80, "DNR (do not run) error" }, - { 0x81, "undefined protocol command" }, - { 0x82, "invalid setting in PDB" }, - { 0x83, "Anti-replay LATE error" }, - { 0x84, "Anti-replay REPLAY error" }, - { 0x85, "Sequence number overflow" }, - { 0x86, "Sigver invalid signature" }, - { 0x87, "DSA Sign Illegal test descriptor" }, - { 0x88, "Protocol Format Error - A protocol has seen an error " - "in the format of data received. When running RSA, " - "this means that formatting with random padding was " - "used, and did not follow the form: 0x00, 0x02, 8-to-N " - "bytes of non-zero pad, 0x00, F data." }, - { 0x89, "Protocol Size Error - A protocol has seen an error in " - "size. When running RSA, pdb size N < (size of F) when " - "no formatting is used; or pdb size N < (F + 11) when " - "formatting is used." }, - { 0xC1, "Blob Command error: Undefined mode" }, - { 0xC2, "Blob Command error: Secure Memory Blob mode error" }, - { 0xC4, "Blob Command error: Black Blob key or input size " - "error" }, - { 0xC5, "Blob Command error: Invalid key destination" }, - { 0xC8, "Blob Command error: Trusted/Secure mode error" }, - { 0xF0, "IPsec TTL or hop limit field either came in as 0, " - "or was decremented to 0" }, - { 0xF1, "3GPP HFN matches or exceeds the Threshold" }, - }; - u8 desc_error = status & JRSTA_DECOERR_ERROR_MASK; + u8 err_id = status & JRSTA_DECOERR_ERROR_MASK; + u8 idx = (status & JRSTA_DECOERR_INDEX_MASK) >> + JRSTA_DECOERR_INDEX_SHIFT; + char *idx_str; + const char *err_str = "unidentified error value 0x"; + char err_err_code[3] = { 0 }; int i; - report_jump_idx(status, outstr); + if (status & JRSTA_DECOERR_JUMP) + idx_str = "jump tgt desc idx"; + else + idx_str = "desc idx"; for (i = 0; i < ARRAY_SIZE(desc_error_list); i++) - if (desc_error_list[i].value == desc_error) + if (desc_error_list[i].value == err_id) break; - if (i != ARRAY_SIZE(desc_error_list) && desc_error_list[i].error_text) { - SPRINTFCAT(outstr, "%s", desc_error_list[i].error_text, - strlen(desc_error_list[i].error_text)); - } else { - SPRINTFCAT(outstr, "unidentified error value 0x%02x", - desc_error, sizeof("ff")); - } + if (i != ARRAY_SIZE(desc_error_list) && desc_error_list[i].error_text) + err_str = desc_error_list[i].error_text; + else + snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id); + + dev_err(jrdev, "%08x: %s: %s %d: %s%s\n", + status, error, idx_str, idx, err_str, err_err_code); } -static void report_jr_status(u32 status, char *outstr) +static void report_jr_status(struct device *jrdev, const u32 status, + const char *error) { - SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__)); + dev_err(jrdev, "%08x: %s: %s() not implemented\n", + status, error, __func__); } -static void report_cond_code_status(u32 status, char *outstr) +static void report_cond_code_status(struct device *jrdev, const u32 status, + const char *error) { - SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__)); + dev_err(jrdev, "%08x: %s: %s() not implemented\n", + status, error, __func__); } -char *caam_jr_strstatus(char *outstr, u32 status) +void caam_jr_strstatus(struct device *jrdev, u32 status) { static const struct stat_src { - void (*report_ssed)(u32 status, char *outstr); - char *error; + void (*report_ssed)(struct device *jrdev, const u32 status, + const char *error); + const char *error; } status_src[] = { { NULL, "No error" }, { NULL, NULL }, @@ -259,12 +224,16 @@ char *caam_jr_strstatus(char *outstr, u32 status) { report_cond_code_status, "Condition Code" }, }; u32 ssrc = status >> JRSTA_SSRC_SHIFT; - - sprintf(outstr, "%s: ", status_src[ssrc].error); - - if (status_src[ssrc].report_ssed) - status_src[ssrc].report_ssed(status, outstr); - - return outstr; + const char *error = status_src[ssrc].error; + + /* + * If there is no further error handling function, just + * print the error code, error string and exit. Otherwise + * call the handler function. + */ + if (!status_src[ssrc].report_ssed) + dev_err(jrdev, "%08x: %s: \n", status, status_src[ssrc].error); + else + status_src[ssrc].report_ssed(jrdev, status, error); } EXPORT_SYMBOL(caam_jr_strstatus); diff --git a/drivers/crypto/caam/error.h b/drivers/crypto/caam/error.h index 02c7baa1748e44..b6350b0d915390 100644 --- a/drivers/crypto/caam/error.h +++ b/drivers/crypto/caam/error.h @@ -7,5 +7,5 @@ #ifndef CAAM_ERROR_H #define CAAM_ERROR_H #define CAAM_ERROR_STR_MAX 302 -extern char *caam_jr_strstatus(char *outstr, u32 status); +void caam_jr_strstatus(struct device *jrdev, u32 status); #endif /* CAAM_ERROR_H */ diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c index ea2e406610ebf9..871703c49d2c09 100644 --- a/drivers/crypto/caam/key_gen.c +++ b/drivers/crypto/caam/key_gen.c @@ -19,11 +19,8 @@ void split_key_done(struct device *dev, u32 *desc, u32 err, dev_err(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - if (err) { - char tmp[CAAM_ERROR_STR_MAX]; - - dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); - } + if (err) + caam_jr_strstatus(dev, err); res->err = err; diff --git a/drivers/crypto/ccp/ccp-pci.c b/drivers/crypto/ccp/ccp-pci.c index 93319f9db7531b..0d746236df5ef6 100644 --- a/drivers/crypto/ccp/ccp-pci.c +++ b/drivers/crypto/ccp/ccp-pci.c @@ -48,12 +48,11 @@ static int ccp_get_msix_irqs(struct ccp_device *ccp) for (v = 0; v < ARRAY_SIZE(msix_entry); v++) msix_entry[v].entry = v; - while ((ret = pci_enable_msix(pdev, msix_entry, v)) > 0) - v = ret; - if (ret) + ret = pci_enable_msix_range(pdev, msix_entry, 1, v); + if (ret < 0) return ret; - ccp_pci->msix_count = v; + ccp_pci->msix_count = ret; for (v = 0; v < ccp_pci->msix_count; v++) { /* Set the interrupt names and request the irqs */ snprintf(ccp_pci->msix[v].name, name_len, "ccp-%u", v); diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c index 1e5481d88a262c..c4fcbf47475f59 100644 --- a/drivers/crypto/nx/nx-842.c +++ b/drivers/crypto/nx/nx-842.c @@ -1234,7 +1234,7 @@ static int __exit nx842_remove(struct vio_dev *viodev) old_devdata = rcu_dereference_check(devdata, lockdep_is_held(&devdata_mutex)); of_reconfig_notifier_unregister(&nx842_of_nb); - rcu_assign_pointer(devdata, NULL); + RCU_INIT_POINTER(devdata, NULL); spin_unlock_irqrestore(&devdata_mutex, flags); synchronize_rcu(); dev_set_drvdata(&viodev->dev, NULL); @@ -1285,7 +1285,7 @@ static void __exit nx842_exit(void) spin_lock_irqsave(&devdata_mutex, flags); old_devdata = rcu_dereference_check(devdata, lockdep_is_held(&devdata_mutex)); - rcu_assign_pointer(devdata, NULL); + RCU_INIT_POINTER(devdata, NULL); spin_unlock_irqrestore(&devdata_mutex, flags); synchronize_rcu(); if (old_devdata) diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index ec5f13162b733c..b8bc84be874178 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -223,12 +223,19 @@ static void omap_des_write_n(struct omap_des_dev *dd, u32 offset, static int omap_des_hw_init(struct omap_des_dev *dd) { + int err; + /* * clocks are enabled when request starts and disabled when finished. * It may be long delays between requests. * Device might go to off mode to save power. */ - pm_runtime_get_sync(dd->dev); + err = pm_runtime_get_sync(dd->dev); + if (err < 0) { + pm_runtime_put_noidle(dd->dev); + dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err); + return err; + } if (!(dd->flags & FLAGS_INIT)) { dd->flags |= FLAGS_INIT; @@ -1074,16 +1081,20 @@ static int omap_des_probe(struct platform_device *pdev) if (err) goto err_res; - dd->io_base = devm_request_and_ioremap(dev, res); - if (!dd->io_base) { - dev_err(dev, "can't ioremap\n"); - err = -ENOMEM; + dd->io_base = devm_ioremap_resource(dev, res); + if (IS_ERR(dd->io_base)) { + err = PTR_ERR(dd->io_base); goto err_res; } dd->phys_base = res->start; pm_runtime_enable(dev); - pm_runtime_get_sync(dev); + err = pm_runtime_get_sync(dev); + if (err < 0) { + pm_runtime_put_noidle(dev); + dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err); + goto err_get; + } omap_des_dma_stop(dd); @@ -1148,6 +1159,7 @@ static int omap_des_probe(struct platform_device *pdev) err_irq: tasklet_kill(&dd->done_task); tasklet_kill(&dd->queue_task); +err_get: pm_runtime_disable(dev); err_res: dd = NULL; @@ -1191,7 +1203,14 @@ static int omap_des_suspend(struct device *dev) static int omap_des_resume(struct device *dev) { - pm_runtime_get_sync(dev); + int err; + + err = pm_runtime_get_sync(dev); + if (err < 0) { + pm_runtime_put_noidle(dev); + dev_err(dev, "%s: failed to get_sync(%d)\n", __func__, err); + return err; + } return 0; } #endif diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index be45762f390a27..47c568ec2474cc 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -105,7 +106,7 @@ #define SSS_REG_FCPKDMAO 0x005C /* AES registers */ -#define SSS_REG_AES_CONTROL 0x4000 +#define SSS_REG_AES_CONTROL 0x00 #define SSS_AES_BYTESWAP_DI _BIT(11) #define SSS_AES_BYTESWAP_DO _BIT(10) #define SSS_AES_BYTESWAP_IV _BIT(9) @@ -121,21 +122,25 @@ #define SSS_AES_CHAIN_MODE_CTR _SBF(1, 0x02) #define SSS_AES_MODE_DECRYPT _BIT(0) -#define SSS_REG_AES_STATUS 0x4004 +#define SSS_REG_AES_STATUS 0x04 #define SSS_AES_BUSY _BIT(2) #define SSS_AES_INPUT_READY _BIT(1) #define SSS_AES_OUTPUT_READY _BIT(0) -#define SSS_REG_AES_IN_DATA(s) (0x4010 + (s << 2)) -#define SSS_REG_AES_OUT_DATA(s) (0x4020 + (s << 2)) -#define SSS_REG_AES_IV_DATA(s) (0x4030 + (s << 2)) -#define SSS_REG_AES_CNT_DATA(s) (0x4040 + (s << 2)) -#define SSS_REG_AES_KEY_DATA(s) (0x4080 + (s << 2)) +#define SSS_REG_AES_IN_DATA(s) (0x10 + (s << 2)) +#define SSS_REG_AES_OUT_DATA(s) (0x20 + (s << 2)) +#define SSS_REG_AES_IV_DATA(s) (0x30 + (s << 2)) +#define SSS_REG_AES_CNT_DATA(s) (0x40 + (s << 2)) +#define SSS_REG_AES_KEY_DATA(s) (0x80 + (s << 2)) #define SSS_REG(dev, reg) ((dev)->ioaddr + (SSS_REG_##reg)) #define SSS_READ(dev, reg) __raw_readl(SSS_REG(dev, reg)) #define SSS_WRITE(dev, reg, val) __raw_writel((val), SSS_REG(dev, reg)) +#define SSS_AES_REG(dev, reg) ((dev)->aes_ioaddr + SSS_REG_##reg) +#define SSS_AES_WRITE(dev, reg, val) __raw_writel((val), \ + SSS_AES_REG(dev, reg)) + /* HW engine modes */ #define FLAGS_AES_DECRYPT _BIT(0) #define FLAGS_AES_MODE_MASK _SBF(1, 0x03) @@ -145,6 +150,20 @@ #define AES_KEY_LEN 16 #define CRYPTO_QUEUE_LEN 1 +/** + * struct samsung_aes_variant - platform specific SSS driver data + * @has_hash_irq: true if SSS module uses hash interrupt, false otherwise + * @aes_offset: AES register offset from SSS module's base. + * + * Specifies platform specific configuration of SSS module. + * Note: A structure for driver specific platform data is used for future + * expansion of its usage. + */ +struct samsung_aes_variant { + bool has_hash_irq; + unsigned int aes_offset; +}; + struct s5p_aes_reqctx { unsigned long mode; }; @@ -161,6 +180,7 @@ struct s5p_aes_dev { struct device *dev; struct clk *clk; void __iomem *ioaddr; + void __iomem *aes_ioaddr; int irq_hash; int irq_fc; @@ -173,10 +193,48 @@ struct s5p_aes_dev { struct crypto_queue queue; bool busy; spinlock_t lock; + + struct samsung_aes_variant *variant; }; static struct s5p_aes_dev *s5p_dev; +static const struct samsung_aes_variant s5p_aes_data = { + .has_hash_irq = true, + .aes_offset = 0x4000, +}; + +static const struct samsung_aes_variant exynos_aes_data = { + .has_hash_irq = false, + .aes_offset = 0x200, +}; + +static const struct of_device_id s5p_sss_dt_match[] = { + { + .compatible = "samsung,s5pv210-secss", + .data = &s5p_aes_data, + }, + { + .compatible = "samsung,exynos4210-secss", + .data = &exynos_aes_data, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, s5p_sss_dt_match); + +static inline struct samsung_aes_variant *find_s5p_sss_version + (struct platform_device *pdev) +{ + if (IS_ENABLED(CONFIG_OF) && (pdev->dev.of_node)) { + const struct of_device_id *match; + match = of_match_node(s5p_sss_dt_match, + pdev->dev.of_node); + return (struct samsung_aes_variant *)match->data; + } + return (struct samsung_aes_variant *) + platform_get_device_id(pdev)->driver_data; +} + static void s5p_set_dma_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) { SSS_WRITE(dev, FCBRDMAS, sg_dma_address(sg)); @@ -272,8 +330,12 @@ static void s5p_aes_tx(struct s5p_aes_dev *dev) } s5p_set_dma_outdata(dev, dev->sg_dst); - } else + } else { s5p_aes_complete(dev, err); + + dev->busy = true; + tasklet_schedule(&dev->tasklet); + } } static void s5p_aes_rx(struct s5p_aes_dev *dev) @@ -322,14 +384,15 @@ static void s5p_set_aes(struct s5p_aes_dev *dev, { void __iomem *keystart; - memcpy(dev->ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10); + if (iv) + memcpy(dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10); if (keylen == AES_KEYSIZE_256) - keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(0); + keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(0); else if (keylen == AES_KEYSIZE_192) - keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(2); + keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(2); else - keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(4); + keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(4); memcpy(keystart, key, keylen); } @@ -379,7 +442,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) if (err) goto outdata_error; - SSS_WRITE(dev, AES_CONTROL, aes_control); + SSS_AES_WRITE(dev, AES_CONTROL, aes_control); s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen); s5p_set_dma_indata(dev, req->src); @@ -410,10 +473,13 @@ static void s5p_tasklet_cb(unsigned long data) spin_lock_irqsave(&dev->lock, flags); backlog = crypto_get_backlog(&dev->queue); async_req = crypto_dequeue_request(&dev->queue); - spin_unlock_irqrestore(&dev->lock, flags); - if (!async_req) + if (!async_req) { + dev->busy = false; + spin_unlock_irqrestore(&dev->lock, flags); return; + } + spin_unlock_irqrestore(&dev->lock, flags); if (backlog) backlog->complete(backlog, -EINPROGRESS); @@ -432,14 +498,13 @@ static int s5p_aes_handle_req(struct s5p_aes_dev *dev, int err; spin_lock_irqsave(&dev->lock, flags); + err = ablkcipher_enqueue_request(&dev->queue, req); if (dev->busy) { - err = -EAGAIN; spin_unlock_irqrestore(&dev->lock, flags); goto exit; } dev->busy = true; - err = ablkcipher_enqueue_request(&dev->queue, req); spin_unlock_irqrestore(&dev->lock, flags); tasklet_schedule(&dev->tasklet); @@ -564,6 +629,7 @@ static int s5p_aes_probe(struct platform_device *pdev) struct s5p_aes_dev *pdata; struct device *dev = &pdev->dev; struct resource *res; + struct samsung_aes_variant *variant; if (s5p_dev) return -EEXIST; @@ -577,30 +643,25 @@ static int s5p_aes_probe(struct platform_device *pdev) if (IS_ERR(pdata->ioaddr)) return PTR_ERR(pdata->ioaddr); + variant = find_s5p_sss_version(pdev); + pdata->clk = devm_clk_get(dev, "secss"); if (IS_ERR(pdata->clk)) { dev_err(dev, "failed to find secss clock source\n"); return -ENOENT; } - clk_enable(pdata->clk); + err = clk_prepare_enable(pdata->clk); + if (err < 0) { + dev_err(dev, "Enabling SSS clk failed, err %d\n", err); + return err; + } spin_lock_init(&pdata->lock); - pdata->irq_hash = platform_get_irq_byname(pdev, "hash"); - if (pdata->irq_hash < 0) { - err = pdata->irq_hash; - dev_warn(dev, "hash interrupt is not available.\n"); - goto err_irq; - } - err = devm_request_irq(dev, pdata->irq_hash, s5p_aes_interrupt, - IRQF_SHARED, pdev->name, pdev); - if (err < 0) { - dev_warn(dev, "hash interrupt is not available.\n"); - goto err_irq; - } + pdata->aes_ioaddr = pdata->ioaddr + variant->aes_offset; - pdata->irq_fc = platform_get_irq_byname(pdev, "feed control"); + pdata->irq_fc = platform_get_irq(pdev, 0); if (pdata->irq_fc < 0) { err = pdata->irq_fc; dev_warn(dev, "feed control interrupt is not available.\n"); @@ -613,6 +674,23 @@ static int s5p_aes_probe(struct platform_device *pdev) goto err_irq; } + if (variant->has_hash_irq) { + pdata->irq_hash = platform_get_irq(pdev, 1); + if (pdata->irq_hash < 0) { + err = pdata->irq_hash; + dev_warn(dev, "hash interrupt is not available.\n"); + goto err_irq; + } + err = devm_request_irq(dev, pdata->irq_hash, s5p_aes_interrupt, + IRQF_SHARED, pdev->name, pdev); + if (err < 0) { + dev_warn(dev, "hash interrupt is not available.\n"); + goto err_irq; + } + } + + pdata->busy = false; + pdata->variant = variant; pdata->dev = dev; platform_set_drvdata(pdev, pdata); s5p_dev = pdata; @@ -639,7 +717,7 @@ static int s5p_aes_probe(struct platform_device *pdev) tasklet_kill(&pdata->tasklet); err_irq: - clk_disable(pdata->clk); + clk_disable_unprepare(pdata->clk); s5p_dev = NULL; @@ -659,7 +737,7 @@ static int s5p_aes_remove(struct platform_device *pdev) tasklet_kill(&pdata->tasklet); - clk_disable(pdata->clk); + clk_disable_unprepare(pdata->clk); s5p_dev = NULL; @@ -672,6 +750,7 @@ static struct platform_driver s5p_aes_crypto = { .driver = { .owner = THIS_MODULE, .name = "s5p-secss", + .of_match_table = s5p_sss_dt_match, }, }; diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 5c5863842de92b..b30b7ed89fb27f 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -361,6 +361,20 @@ config FSL_EDMA multiplexing capability for DMA request sources(slot). This module can be found on Freescale Vybrid and LS-1 SoCs. +config XILINX_VDMA + tristate "Xilinx AXI VDMA Engine" + depends on (ARCH_ZYNQ || MICROBLAZE) + select DMA_ENGINE + help + Enable support for Xilinx AXI VDMA Soft IP. + + This engine provides high-bandwidth direct memory access + between memory and AXI4-Stream video type target + peripherals including peripherals which support AXI4- + Stream Video Protocol. It has two stream interfaces/ + channels, Memory Mapped to Stream (MM2S) and Stream to + Memory Mapped (S2MM) for the data transfers. + config DMA_ENGINE bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 5150c82c9caf2e..c779e1eb2db2ac 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -46,3 +46,4 @@ obj-$(CONFIG_K3_DMA) += k3dma.o obj-$(CONFIG_MOXART_DMA) += moxart-dma.o obj-$(CONFIG_FSL_EDMA) += fsl-edma.o obj-$(CONFIG_QCOM_BAM_DMA) += qcom_bam_dma.o +obj-y += xilinx/ diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index a886713937fd05..d5d30ed863ceb9 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -1009,6 +1009,7 @@ static void dmaengine_unmap(struct kref *kref) dma_unmap_page(dev, unmap->addr[i], unmap->len, DMA_BIDIRECTIONAL); } + cnt = unmap->map_cnt; mempool_free(unmap, __get_unmap_pool(cnt)->pool); } @@ -1074,6 +1075,7 @@ dmaengine_get_unmap_data(struct device *dev, int nr, gfp_t flags) memset(unmap, 0, sizeof(*unmap)); kref_init(&unmap->kref); unmap->dev = dev; + unmap->map_cnt = nr; return unmap; } diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index cfdbb92aae1dec..7a740769c2fa59 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -1548,11 +1548,6 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) /* Disable BLOCK interrupts as well */ channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask); - err = devm_request_irq(chip->dev, chip->irq, dw_dma_interrupt, - IRQF_SHARED, "dw_dmac", dw); - if (err) - return err; - /* Create a pool of consistent memory blocks for hardware descriptors */ dw->desc_pool = dmam_pool_create("dw_dmac_desc_pool", chip->dev, sizeof(struct dw_desc), 4, 0); @@ -1563,6 +1558,11 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw); + err = request_irq(chip->irq, dw_dma_interrupt, IRQF_SHARED, + "dw_dmac", dw); + if (err) + return err; + INIT_LIST_HEAD(&dw->dma.channels); for (i = 0; i < nr_channels; i++) { struct dw_dma_chan *dwc = &dw->chan[i]; @@ -1667,6 +1667,7 @@ int dw_dma_remove(struct dw_dma_chip *chip) dw_dma_off(dw); dma_async_device_unregister(&dw->dma); + free_irq(chip->irq, dw); tasklet_kill(&dw->tasklet); list_for_each_entry_safe(dwc, _dwc, &dw->dma.channels, diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index fec59f1a77bb23..be81db78062710 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -93,16 +93,10 @@ static int dw_pci_resume_early(struct device *dev) return dw_dma_resume(chip); }; -#else /* !CONFIG_PM_SLEEP */ - -#define dw_pci_suspend_late NULL -#define dw_pci_resume_early NULL - -#endif /* !CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops dw_pci_dev_pm_ops = { - .suspend_late = dw_pci_suspend_late, - .resume_early = dw_pci_resume_early, + SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_pci_suspend_late, dw_pci_resume_early) }; static DEFINE_PCI_DEVICE_TABLE(dw_pci_id_table) = { diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 453822cc4f9d3a..c5b339af6be572 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -256,7 +256,7 @@ MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table); #ifdef CONFIG_PM_SLEEP -static int dw_suspend_noirq(struct device *dev) +static int dw_suspend_late(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct dw_dma_chip *chip = platform_get_drvdata(pdev); @@ -264,7 +264,7 @@ static int dw_suspend_noirq(struct device *dev) return dw_dma_suspend(chip); } -static int dw_resume_noirq(struct device *dev) +static int dw_resume_early(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct dw_dma_chip *chip = platform_get_drvdata(pdev); @@ -272,20 +272,10 @@ static int dw_resume_noirq(struct device *dev) return dw_dma_resume(chip); } -#else /* !CONFIG_PM_SLEEP */ - -#define dw_suspend_noirq NULL -#define dw_resume_noirq NULL - -#endif /* !CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops dw_dev_pm_ops = { - .suspend_noirq = dw_suspend_noirq, - .resume_noirq = dw_resume_noirq, - .freeze_noirq = dw_suspend_noirq, - .thaw_noirq = dw_resume_noirq, - .restore_noirq = dw_resume_noirq, - .poweroff_noirq = dw_suspend_noirq, + SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_suspend_late, dw_resume_early) }; static struct platform_driver dw_driver = { diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 926360c2db6abc..d08c4dedef3585 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -57,14 +57,48 @@ #define EDMA_MAX_SLOTS MAX_NR_SG #define EDMA_DESCRIPTORS 16 +struct edma_pset { + u32 len; + dma_addr_t addr; + struct edmacc_param param; +}; + struct edma_desc { struct virt_dma_desc vdesc; struct list_head node; + enum dma_transfer_direction direction; int cyclic; int absync; int pset_nr; + struct edma_chan *echan; int processed; - struct edmacc_param pset[0]; + + /* + * The following 4 elements are used for residue accounting. + * + * - processed_stat: the number of SG elements we have traversed + * so far to cover accounting. This is updated directly to processed + * during edma_callback and is always <= processed, because processed + * refers to the number of pending transfer (programmed to EDMA + * controller), where as processed_stat tracks number of transfers + * accounted for so far. + * + * - residue: The amount of bytes we have left to transfer for this desc + * + * - residue_stat: The residue in bytes of data we have covered + * so far for accounting. This is updated directly to residue + * during callbacks to keep it current. + * + * - sg_len: Tracks the length of the current intermediate transfer, + * this is required to update the residue during intermediate transfer + * completion callback. + */ + int processed_stat; + u32 sg_len; + u32 residue; + u32 residue_stat; + + struct edma_pset pset[0]; }; struct edma_cc; @@ -136,12 +170,14 @@ static void edma_execute(struct edma_chan *echan) /* Find out how many left */ left = edesc->pset_nr - edesc->processed; nslots = min(MAX_NR_SG, left); + edesc->sg_len = 0; /* Write descriptor PaRAM set(s) */ for (i = 0; i < nslots; i++) { j = i + edesc->processed; - edma_write_slot(echan->slot[i], &edesc->pset[j]); - dev_dbg(echan->vchan.chan.device->dev, + edma_write_slot(echan->slot[i], &edesc->pset[j].param); + edesc->sg_len += edesc->pset[j].len; + dev_vdbg(echan->vchan.chan.device->dev, "\n pset[%d]:\n" " chnum\t%d\n" " slot\t%d\n" @@ -154,14 +190,14 @@ static void edma_execute(struct edma_chan *echan) " cidx\t%08x\n" " lkrld\t%08x\n", j, echan->ch_num, echan->slot[i], - edesc->pset[j].opt, - edesc->pset[j].src, - edesc->pset[j].dst, - edesc->pset[j].a_b_cnt, - edesc->pset[j].ccnt, - edesc->pset[j].src_dst_bidx, - edesc->pset[j].src_dst_cidx, - edesc->pset[j].link_bcntrld); + edesc->pset[j].param.opt, + edesc->pset[j].param.src, + edesc->pset[j].param.dst, + edesc->pset[j].param.a_b_cnt, + edesc->pset[j].param.ccnt, + edesc->pset[j].param.src_dst_bidx, + edesc->pset[j].param.src_dst_cidx, + edesc->pset[j].param.link_bcntrld); /* Link to the previous slot if not the last set */ if (i != (nslots - 1)) edma_link(echan->slot[i], echan->slot[i+1]); @@ -183,7 +219,8 @@ static void edma_execute(struct edma_chan *echan) } if (edesc->processed <= MAX_NR_SG) { - dev_dbg(dev, "first transfer starting %d\n", echan->ch_num); + dev_dbg(dev, "first transfer starting on channel %d\n", + echan->ch_num); edma_start(echan->ch_num); } else { dev_dbg(dev, "chan: %d: completed %d elements, resuming\n", @@ -197,7 +234,7 @@ static void edma_execute(struct edma_chan *echan) * MAX_NR_SG */ if (echan->missed) { - dev_dbg(dev, "missed event in execute detected\n"); + dev_dbg(dev, "missed event on channel %d\n", echan->ch_num); edma_clean_channel(echan->ch_num); edma_stop(echan->ch_num); edma_start(echan->ch_num); @@ -242,6 +279,26 @@ static int edma_slave_config(struct edma_chan *echan, return 0; } +static int edma_dma_pause(struct edma_chan *echan) +{ + /* Pause/Resume only allowed with cyclic mode */ + if (!echan->edesc->cyclic) + return -EINVAL; + + edma_pause(echan->ch_num); + return 0; +} + +static int edma_dma_resume(struct edma_chan *echan) +{ + /* Pause/Resume only allowed with cyclic mode */ + if (!echan->edesc->cyclic) + return -EINVAL; + + edma_resume(echan->ch_num); + return 0; +} + static int edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) { @@ -257,6 +314,14 @@ static int edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, config = (struct dma_slave_config *)arg; ret = edma_slave_config(echan, config); break; + case DMA_PAUSE: + ret = edma_dma_pause(echan); + break; + + case DMA_RESUME: + ret = edma_dma_resume(echan); + break; + default: ret = -ENOSYS; } @@ -275,18 +340,23 @@ static int edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, * @dma_length: Total length of the DMA transfer * @direction: Direction of the transfer */ -static int edma_config_pset(struct dma_chan *chan, struct edmacc_param *pset, +static int edma_config_pset(struct dma_chan *chan, struct edma_pset *epset, dma_addr_t src_addr, dma_addr_t dst_addr, u32 burst, enum dma_slave_buswidth dev_width, unsigned int dma_length, enum dma_transfer_direction direction) { struct edma_chan *echan = to_edma_chan(chan); struct device *dev = chan->device->dev; + struct edmacc_param *param = &epset->param; int acnt, bcnt, ccnt, cidx; int src_bidx, dst_bidx, src_cidx, dst_cidx; int absync; acnt = dev_width; + + /* src/dst_maxburst == 0 is the same case as src/dst_maxburst == 1 */ + if (!burst) + burst = 1; /* * If the maxburst is equal to the fifo width, use * A-synced transfers. This allows for large contiguous @@ -337,41 +407,50 @@ static int edma_config_pset(struct dma_chan *chan, struct edmacc_param *pset, cidx = acnt * bcnt; } + epset->len = dma_length; + if (direction == DMA_MEM_TO_DEV) { src_bidx = acnt; src_cidx = cidx; dst_bidx = 0; dst_cidx = 0; + epset->addr = src_addr; } else if (direction == DMA_DEV_TO_MEM) { src_bidx = 0; src_cidx = 0; dst_bidx = acnt; dst_cidx = cidx; + epset->addr = dst_addr; + } else if (direction == DMA_MEM_TO_MEM) { + src_bidx = acnt; + src_cidx = cidx; + dst_bidx = acnt; + dst_cidx = cidx; } else { dev_err(dev, "%s: direction not implemented yet\n", __func__); return -EINVAL; } - pset->opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num)); + param->opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num)); /* Configure A or AB synchronized transfers */ if (absync) - pset->opt |= SYNCDIM; + param->opt |= SYNCDIM; - pset->src = src_addr; - pset->dst = dst_addr; + param->src = src_addr; + param->dst = dst_addr; - pset->src_dst_bidx = (dst_bidx << 16) | src_bidx; - pset->src_dst_cidx = (dst_cidx << 16) | src_cidx; + param->src_dst_bidx = (dst_bidx << 16) | src_bidx; + param->src_dst_cidx = (dst_cidx << 16) | src_cidx; - pset->a_b_cnt = bcnt << 16 | acnt; - pset->ccnt = ccnt; + param->a_b_cnt = bcnt << 16 | acnt; + param->ccnt = ccnt; /* * Only time when (bcntrld) auto reload is required is for * A-sync case, and in this case, a requirement of reload value * of SZ_64K-1 only is assured. 'link' is initially set to NULL * and then later will be populated by edma_execute. */ - pset->link_bcntrld = 0xffffffff; + param->link_bcntrld = 0xffffffff; return absync; } @@ -401,23 +480,26 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( dev_width = echan->cfg.dst_addr_width; burst = echan->cfg.dst_maxburst; } else { - dev_err(dev, "%s: bad direction?\n", __func__); + dev_err(dev, "%s: bad direction: %d\n", __func__, direction); return NULL; } if (dev_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) { - dev_err(dev, "Undefined slave buswidth\n"); + dev_err(dev, "%s: Undefined slave buswidth\n", __func__); return NULL; } edesc = kzalloc(sizeof(*edesc) + sg_len * sizeof(edesc->pset[0]), GFP_ATOMIC); if (!edesc) { - dev_dbg(dev, "Failed to allocate a descriptor\n"); + dev_err(dev, "%s: Failed to allocate a descriptor\n", __func__); return NULL; } edesc->pset_nr = sg_len; + edesc->residue = 0; + edesc->direction = direction; + edesc->echan = echan; /* Allocate a PaRAM slot, if needed */ nslots = min_t(unsigned, MAX_NR_SG, sg_len); @@ -429,7 +511,8 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( EDMA_SLOT_ANY); if (echan->slot[i] < 0) { kfree(edesc); - dev_err(dev, "Failed to allocate slot\n"); + dev_err(dev, "%s: Failed to allocate slot\n", + __func__); return NULL; } } @@ -452,16 +535,56 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( } edesc->absync = ret; + edesc->residue += sg_dma_len(sg); /* If this is the last in a current SG set of transactions, enable interrupts so that next set is processed */ if (!((i+1) % MAX_NR_SG)) - edesc->pset[i].opt |= TCINTEN; + edesc->pset[i].param.opt |= TCINTEN; /* If this is the last set, enable completion interrupt flag */ if (i == sg_len - 1) - edesc->pset[i].opt |= TCINTEN; + edesc->pset[i].param.opt |= TCINTEN; } + edesc->residue_stat = edesc->residue; + + return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags); +} + +struct dma_async_tx_descriptor *edma_prep_dma_memcpy( + struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, + size_t len, unsigned long tx_flags) +{ + int ret; + struct edma_desc *edesc; + struct device *dev = chan->device->dev; + struct edma_chan *echan = to_edma_chan(chan); + + if (unlikely(!echan || !len)) + return NULL; + + edesc = kzalloc(sizeof(*edesc) + sizeof(edesc->pset[0]), GFP_ATOMIC); + if (!edesc) { + dev_dbg(dev, "Failed to allocate a descriptor\n"); + return NULL; + } + + edesc->pset_nr = 1; + + ret = edma_config_pset(chan, &edesc->pset[0], src, dest, 1, + DMA_SLAVE_BUSWIDTH_4_BYTES, len, DMA_MEM_TO_MEM); + if (ret < 0) + return NULL; + + edesc->absync = ret; + + /* + * Enable intermediate transfer chaining to re-trigger channel + * on completion of every TR, and enable transfer-completion + * interrupt on completion of the whole transfer. + */ + edesc->pset[0].param.opt |= ITCCHEN; + edesc->pset[0].param.opt |= TCINTEN; return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags); } @@ -493,12 +616,12 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic( dev_width = echan->cfg.dst_addr_width; burst = echan->cfg.dst_maxburst; } else { - dev_err(dev, "%s: bad direction?\n", __func__); + dev_err(dev, "%s: bad direction: %d\n", __func__, direction); return NULL; } if (dev_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) { - dev_err(dev, "Undefined slave buswidth\n"); + dev_err(dev, "%s: Undefined slave buswidth\n", __func__); return NULL; } @@ -523,16 +646,18 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic( edesc = kzalloc(sizeof(*edesc) + nslots * sizeof(edesc->pset[0]), GFP_ATOMIC); if (!edesc) { - dev_dbg(dev, "Failed to allocate a descriptor\n"); + dev_err(dev, "%s: Failed to allocate a descriptor\n", __func__); return NULL; } edesc->cyclic = 1; edesc->pset_nr = nslots; + edesc->residue = edesc->residue_stat = buf_len; + edesc->direction = direction; + edesc->echan = echan; - dev_dbg(dev, "%s: nslots=%d\n", __func__, nslots); - dev_dbg(dev, "%s: period_len=%d\n", __func__, period_len); - dev_dbg(dev, "%s: buf_len=%d\n", __func__, buf_len); + dev_dbg(dev, "%s: channel=%d nslots=%d period_len=%zu buf_len=%zu\n", + __func__, echan->ch_num, nslots, period_len, buf_len); for (i = 0; i < nslots; i++) { /* Allocate a PaRAM slot, if needed */ @@ -542,7 +667,8 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic( EDMA_SLOT_ANY); if (echan->slot[i] < 0) { kfree(edesc); - dev_err(dev, "Failed to allocate slot\n"); + dev_err(dev, "%s: Failed to allocate slot\n", + __func__); return NULL; } } @@ -566,8 +692,8 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic( else src_addr += period_len; - dev_dbg(dev, "%s: Configure period %d of buf:\n", __func__, i); - dev_dbg(dev, + dev_vdbg(dev, "%s: Configure period %d of buf:\n", __func__, i); + dev_vdbg(dev, "\n pset[%d]:\n" " chnum\t%d\n" " slot\t%d\n" @@ -580,14 +706,14 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic( " cidx\t%08x\n" " lkrld\t%08x\n", i, echan->ch_num, echan->slot[i], - edesc->pset[i].opt, - edesc->pset[i].src, - edesc->pset[i].dst, - edesc->pset[i].a_b_cnt, - edesc->pset[i].ccnt, - edesc->pset[i].src_dst_bidx, - edesc->pset[i].src_dst_cidx, - edesc->pset[i].link_bcntrld); + edesc->pset[i].param.opt, + edesc->pset[i].param.src, + edesc->pset[i].param.dst, + edesc->pset[i].param.a_b_cnt, + edesc->pset[i].param.ccnt, + edesc->pset[i].param.src_dst_bidx, + edesc->pset[i].param.src_dst_cidx, + edesc->pset[i].param.link_bcntrld); edesc->absync = ret; @@ -595,7 +721,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic( * Enable interrupts for every period because callback * has to be called for every period. */ - edesc->pset[i].opt |= TCINTEN; + edesc->pset[i].param.opt |= TCINTEN; } return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags); @@ -606,7 +732,6 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data) struct edma_chan *echan = data; struct device *dev = echan->vchan.chan.device->dev; struct edma_desc *edesc; - unsigned long flags; struct edmacc_param p; edesc = echan->edesc; @@ -617,27 +742,34 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data) switch (ch_status) { case EDMA_DMA_COMPLETE: - spin_lock_irqsave(&echan->vchan.lock, flags); + spin_lock(&echan->vchan.lock); if (edesc) { if (edesc->cyclic) { vchan_cyclic_callback(&edesc->vdesc); } else if (edesc->processed == edesc->pset_nr) { dev_dbg(dev, "Transfer complete, stopping channel %d\n", ch_num); + edesc->residue = 0; edma_stop(echan->ch_num); vchan_cookie_complete(&edesc->vdesc); edma_execute(echan); } else { dev_dbg(dev, "Intermediate transfer complete on channel %d\n", ch_num); + + /* Update statistics for tx_status */ + edesc->residue -= edesc->sg_len; + edesc->residue_stat = edesc->residue; + edesc->processed_stat = edesc->processed; + edma_execute(echan); } } - spin_unlock_irqrestore(&echan->vchan.lock, flags); + spin_unlock(&echan->vchan.lock); break; case EDMA_DMA_CC_ERROR: - spin_lock_irqsave(&echan->vchan.lock, flags); + spin_lock(&echan->vchan.lock); edma_read_slot(EDMA_CHAN_SLOT(echan->slot[0]), &p); @@ -668,7 +800,7 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data) edma_trigger_channel(echan->ch_num); } - spin_unlock_irqrestore(&echan->vchan.lock, flags); + spin_unlock(&echan->vchan.lock); break; default: @@ -704,7 +836,7 @@ static int edma_alloc_chan_resources(struct dma_chan *chan) echan->alloced = true; echan->slot[0] = echan->ch_num; - dev_dbg(dev, "allocated channel for %u:%u\n", + dev_dbg(dev, "allocated channel %d for %u:%u\n", echan->ch_num, EDMA_CTLR(echan->ch_num), EDMA_CHAN_SLOT(echan->ch_num)); return 0; @@ -756,23 +888,52 @@ static void edma_issue_pending(struct dma_chan *chan) spin_unlock_irqrestore(&echan->vchan.lock, flags); } -static size_t edma_desc_size(struct edma_desc *edesc) +static u32 edma_residue(struct edma_desc *edesc) { + bool dst = edesc->direction == DMA_DEV_TO_MEM; + struct edma_pset *pset = edesc->pset; + dma_addr_t done, pos; int i; - size_t size; - - if (edesc->absync) - for (size = i = 0; i < edesc->pset_nr; i++) - size += (edesc->pset[i].a_b_cnt & 0xffff) * - (edesc->pset[i].a_b_cnt >> 16) * - edesc->pset[i].ccnt; - else - size = (edesc->pset[0].a_b_cnt & 0xffff) * - (edesc->pset[0].a_b_cnt >> 16) + - (edesc->pset[0].a_b_cnt & 0xffff) * - (SZ_64K - 1) * edesc->pset[0].ccnt; - - return size; + + /* + * We always read the dst/src position from the first RamPar + * pset. That's the one which is active now. + */ + pos = edma_get_position(edesc->echan->slot[0], dst); + + /* + * Cyclic is simple. Just subtract pset[0].addr from pos. + * + * We never update edesc->residue in the cyclic case, so we + * can tell the remaining room to the end of the circular + * buffer. + */ + if (edesc->cyclic) { + done = pos - pset->addr; + edesc->residue_stat = edesc->residue - done; + return edesc->residue_stat; + } + + /* + * For SG operation we catch up with the last processed + * status. + */ + pset += edesc->processed_stat; + + for (i = edesc->processed_stat; i < edesc->processed; i++, pset++) { + /* + * If we are inside this pset address range, we know + * this is the active one. Get the current delta and + * stop walking the psets. + */ + if (pos >= pset->addr && pos < pset->addr + pset->len) + return edesc->residue_stat - (pos - pset->addr); + + /* Otherwise mark it done and update residue_stat. */ + edesc->processed_stat++; + edesc->residue_stat -= pset->len; + } + return edesc->residue_stat; } /* Check request completion status */ @@ -790,13 +951,10 @@ static enum dma_status edma_tx_status(struct dma_chan *chan, return ret; spin_lock_irqsave(&echan->vchan.lock, flags); - vdesc = vchan_find_desc(&echan->vchan, cookie); - if (vdesc) { - txstate->residue = edma_desc_size(to_edma_desc(&vdesc->tx)); - } else if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) { - struct edma_desc *edesc = echan->edesc; - txstate->residue = edma_desc_size(edesc); - } + if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) + txstate->residue = edma_residue(echan->edesc); + else if ((vdesc = vchan_find_desc(&echan->vchan, cookie))) + txstate->residue = to_edma_desc(&vdesc->tx)->residue; spin_unlock_irqrestore(&echan->vchan.lock, flags); return ret; @@ -822,18 +980,43 @@ static void __init edma_chan_init(struct edma_cc *ecc, } } +#define EDMA_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) + +static int edma_dma_device_slave_caps(struct dma_chan *dchan, + struct dma_slave_caps *caps) +{ + caps->src_addr_widths = EDMA_DMA_BUSWIDTHS; + caps->dstn_addr_widths = EDMA_DMA_BUSWIDTHS; + caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + caps->cmd_pause = true; + caps->cmd_terminate = true; + caps->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; + + return 0; +} + static void edma_dma_init(struct edma_cc *ecc, struct dma_device *dma, struct device *dev) { dma->device_prep_slave_sg = edma_prep_slave_sg; dma->device_prep_dma_cyclic = edma_prep_dma_cyclic; + dma->device_prep_dma_memcpy = edma_prep_dma_memcpy; dma->device_alloc_chan_resources = edma_alloc_chan_resources; dma->device_free_chan_resources = edma_free_chan_resources; dma->device_issue_pending = edma_issue_pending; dma->device_tx_status = edma_tx_status; dma->device_control = edma_control; + dma->device_slave_caps = edma_dma_device_slave_caps; dma->dev = dev; + /* + * code using dma memcpy must make sure alignment of + * length is at dma->copy_align boundary. + */ + dma->copy_align = DMA_SLAVE_BUSWIDTH_4_BYTES; + INIT_LIST_HEAD(&dma->channels); } @@ -861,6 +1044,8 @@ static int edma_probe(struct platform_device *pdev) dma_cap_zero(ecc->dma_slave.cap_mask); dma_cap_set(DMA_SLAVE, ecc->dma_slave.cap_mask); + dma_cap_set(DMA_CYCLIC, ecc->dma_slave.cap_mask); + dma_cap_set(DMA_MEMCPY, ecc->dma_slave.cap_mask); edma_dma_init(ecc, &ecc->dma_slave, &pdev->dev); diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index f157c6f76b32b8..e0fec68aed2511 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -61,6 +61,16 @@ static u32 get_sr(struct fsldma_chan *chan) return DMA_IN(chan, &chan->regs->sr, 32); } +static void set_mr(struct fsldma_chan *chan, u32 val) +{ + DMA_OUT(chan, &chan->regs->mr, val, 32); +} + +static u32 get_mr(struct fsldma_chan *chan) +{ + return DMA_IN(chan, &chan->regs->mr, 32); +} + static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr) { DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64); @@ -71,6 +81,11 @@ static dma_addr_t get_cdar(struct fsldma_chan *chan) return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN; } +static void set_bcr(struct fsldma_chan *chan, u32 val) +{ + DMA_OUT(chan, &chan->regs->bcr, val, 32); +} + static u32 get_bcr(struct fsldma_chan *chan) { return DMA_IN(chan, &chan->regs->bcr, 32); @@ -135,7 +150,7 @@ static void set_ld_eol(struct fsldma_chan *chan, struct fsl_desc_sw *desc) static void dma_init(struct fsldma_chan *chan) { /* Reset the channel */ - DMA_OUT(chan, &chan->regs->mr, 0, 32); + set_mr(chan, 0); switch (chan->feature & FSL_DMA_IP_MASK) { case FSL_DMA_IP_85XX: @@ -144,16 +159,15 @@ static void dma_init(struct fsldma_chan *chan) * EOLNIE - End of links interrupt enable * BWC - Bandwidth sharing among channels */ - DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC - | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE, 32); + set_mr(chan, FSL_DMA_MR_BWC | FSL_DMA_MR_EIE + | FSL_DMA_MR_EOLNIE); break; case FSL_DMA_IP_83XX: /* Set the channel to below modes: * EOTIE - End-of-transfer interrupt enable * PRC_RM - PCI read multiple */ - DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EOTIE - | FSL_DMA_MR_PRC_RM, 32); + set_mr(chan, FSL_DMA_MR_EOTIE | FSL_DMA_MR_PRC_RM); break; } } @@ -175,10 +189,10 @@ static void dma_start(struct fsldma_chan *chan) { u32 mode; - mode = DMA_IN(chan, &chan->regs->mr, 32); + mode = get_mr(chan); if (chan->feature & FSL_DMA_CHAN_PAUSE_EXT) { - DMA_OUT(chan, &chan->regs->bcr, 0, 32); + set_bcr(chan, 0); mode |= FSL_DMA_MR_EMP_EN; } else { mode &= ~FSL_DMA_MR_EMP_EN; @@ -191,7 +205,7 @@ static void dma_start(struct fsldma_chan *chan) mode |= FSL_DMA_MR_CS; } - DMA_OUT(chan, &chan->regs->mr, mode, 32); + set_mr(chan, mode); } static void dma_halt(struct fsldma_chan *chan) @@ -200,7 +214,7 @@ static void dma_halt(struct fsldma_chan *chan) int i; /* read the mode register */ - mode = DMA_IN(chan, &chan->regs->mr, 32); + mode = get_mr(chan); /* * The 85xx controller supports channel abort, which will stop @@ -209,14 +223,14 @@ static void dma_halt(struct fsldma_chan *chan) */ if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) { mode |= FSL_DMA_MR_CA; - DMA_OUT(chan, &chan->regs->mr, mode, 32); + set_mr(chan, mode); mode &= ~FSL_DMA_MR_CA; } /* stop the DMA controller */ mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN); - DMA_OUT(chan, &chan->regs->mr, mode, 32); + set_mr(chan, mode); /* wait for the DMA controller to become idle */ for (i = 0; i < 100; i++) { @@ -245,7 +259,7 @@ static void fsl_chan_set_src_loop_size(struct fsldma_chan *chan, int size) { u32 mode; - mode = DMA_IN(chan, &chan->regs->mr, 32); + mode = get_mr(chan); switch (size) { case 0: @@ -259,7 +273,7 @@ static void fsl_chan_set_src_loop_size(struct fsldma_chan *chan, int size) break; } - DMA_OUT(chan, &chan->regs->mr, mode, 32); + set_mr(chan, mode); } /** @@ -277,7 +291,7 @@ static void fsl_chan_set_dst_loop_size(struct fsldma_chan *chan, int size) { u32 mode; - mode = DMA_IN(chan, &chan->regs->mr, 32); + mode = get_mr(chan); switch (size) { case 0: @@ -291,7 +305,7 @@ static void fsl_chan_set_dst_loop_size(struct fsldma_chan *chan, int size) break; } - DMA_OUT(chan, &chan->regs->mr, mode, 32); + set_mr(chan, mode); } /** @@ -312,10 +326,10 @@ static void fsl_chan_set_request_count(struct fsldma_chan *chan, int size) BUG_ON(size > 1024); - mode = DMA_IN(chan, &chan->regs->mr, 32); + mode = get_mr(chan); mode |= (__ilog2(size) << 24) & 0x0f000000; - DMA_OUT(chan, &chan->regs->mr, mode, 32); + set_mr(chan, mode); } /** @@ -403,6 +417,19 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) return cookie; } +/** + * fsl_dma_free_descriptor - Free descriptor from channel's DMA pool. + * @chan : Freescale DMA channel + * @desc: descriptor to be freed + */ +static void fsl_dma_free_descriptor(struct fsldma_chan *chan, + struct fsl_desc_sw *desc) +{ + list_del(&desc->node); + chan_dbg(chan, "LD %p free\n", desc); + dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); +} + /** * fsl_dma_alloc_descriptor - Allocate descriptor from channel's DMA pool. * @chan : Freescale DMA channel @@ -426,13 +453,106 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor(struct fsldma_chan *chan) desc->async_tx.tx_submit = fsl_dma_tx_submit; desc->async_tx.phys = pdesc; -#ifdef FSL_DMA_LD_DEBUG chan_dbg(chan, "LD %p allocated\n", desc); -#endif return desc; } +/** + * fsl_chan_xfer_ld_queue - transfer any pending transactions + * @chan : Freescale DMA channel + * + * HARDWARE STATE: idle + * LOCKING: must hold chan->desc_lock + */ +static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) +{ + struct fsl_desc_sw *desc; + + /* + * If the list of pending descriptors is empty, then we + * don't need to do any work at all + */ + if (list_empty(&chan->ld_pending)) { + chan_dbg(chan, "no pending LDs\n"); + return; + } + + /* + * The DMA controller is not idle, which means that the interrupt + * handler will start any queued transactions when it runs after + * this transaction finishes + */ + if (!chan->idle) { + chan_dbg(chan, "DMA controller still busy\n"); + return; + } + + /* + * If there are some link descriptors which have not been + * transferred, we need to start the controller + */ + + /* + * Move all elements from the queue of pending transactions + * onto the list of running transactions + */ + chan_dbg(chan, "idle, starting controller\n"); + desc = list_first_entry(&chan->ld_pending, struct fsl_desc_sw, node); + list_splice_tail_init(&chan->ld_pending, &chan->ld_running); + + /* + * The 85xx DMA controller doesn't clear the channel start bit + * automatically at the end of a transfer. Therefore we must clear + * it in software before starting the transfer. + */ + if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) { + u32 mode; + + mode = get_mr(chan); + mode &= ~FSL_DMA_MR_CS; + set_mr(chan, mode); + } + + /* + * Program the descriptor's address into the DMA controller, + * then start the DMA transaction + */ + set_cdar(chan, desc->async_tx.phys); + get_cdar(chan); + + dma_start(chan); + chan->idle = false; +} + +/** + * fsldma_cleanup_descriptor - cleanup and free a single link descriptor + * @chan: Freescale DMA channel + * @desc: descriptor to cleanup and free + * + * This function is used on a descriptor which has been executed by the DMA + * controller. It will run any callbacks, submit any dependencies, and then + * free the descriptor. + */ +static void fsldma_cleanup_descriptor(struct fsldma_chan *chan, + struct fsl_desc_sw *desc) +{ + struct dma_async_tx_descriptor *txd = &desc->async_tx; + + /* Run the link descriptor callback function */ + if (txd->callback) { + chan_dbg(chan, "LD %p callback\n", desc); + txd->callback(txd->callback_param); + } + + /* Run any dependencies */ + dma_run_dependencies(txd); + + dma_descriptor_unmap(txd); + chan_dbg(chan, "LD %p free\n", desc); + dma_pool_free(chan->desc_pool, desc, txd->phys); +} + /** * fsl_dma_alloc_chan_resources - Allocate resources for DMA channel. * @chan : Freescale DMA channel @@ -477,13 +597,8 @@ static void fsldma_free_desc_list(struct fsldma_chan *chan, { struct fsl_desc_sw *desc, *_desc; - list_for_each_entry_safe(desc, _desc, list, node) { - list_del(&desc->node); -#ifdef FSL_DMA_LD_DEBUG - chan_dbg(chan, "LD %p free\n", desc); -#endif - dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); - } + list_for_each_entry_safe(desc, _desc, list, node) + fsl_dma_free_descriptor(chan, desc); } static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan, @@ -491,13 +606,8 @@ static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan, { struct fsl_desc_sw *desc, *_desc; - list_for_each_entry_safe_reverse(desc, _desc, list, node) { - list_del(&desc->node); -#ifdef FSL_DMA_LD_DEBUG - chan_dbg(chan, "LD %p free\n", desc); -#endif - dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); - } + list_for_each_entry_safe_reverse(desc, _desc, list, node) + fsl_dma_free_descriptor(chan, desc); } /** @@ -519,35 +629,6 @@ static void fsl_dma_free_chan_resources(struct dma_chan *dchan) chan->desc_pool = NULL; } -static struct dma_async_tx_descriptor * -fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags) -{ - struct fsldma_chan *chan; - struct fsl_desc_sw *new; - - if (!dchan) - return NULL; - - chan = to_fsl_chan(dchan); - - new = fsl_dma_alloc_descriptor(chan); - if (!new) { - chan_err(chan, "%s\n", msg_ld_oom); - return NULL; - } - - new->async_tx.cookie = -EBUSY; - new->async_tx.flags = flags; - - /* Insert the link descriptor to the LD ring */ - list_add_tail(&new->node, &new->tx_list); - - /* Set End-of-link to the last link descriptor of new list */ - set_ld_eol(chan, new); - - return &new->async_tx; -} - static struct dma_async_tx_descriptor * fsl_dma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst, dma_addr_t dma_src, @@ -816,105 +897,6 @@ static int fsl_dma_device_control(struct dma_chan *dchan, return 0; } -/** - * fsldma_cleanup_descriptor - cleanup and free a single link descriptor - * @chan: Freescale DMA channel - * @desc: descriptor to cleanup and free - * - * This function is used on a descriptor which has been executed by the DMA - * controller. It will run any callbacks, submit any dependencies, and then - * free the descriptor. - */ -static void fsldma_cleanup_descriptor(struct fsldma_chan *chan, - struct fsl_desc_sw *desc) -{ - struct dma_async_tx_descriptor *txd = &desc->async_tx; - - /* Run the link descriptor callback function */ - if (txd->callback) { -#ifdef FSL_DMA_LD_DEBUG - chan_dbg(chan, "LD %p callback\n", desc); -#endif - txd->callback(txd->callback_param); - } - - /* Run any dependencies */ - dma_run_dependencies(txd); - - dma_descriptor_unmap(txd); -#ifdef FSL_DMA_LD_DEBUG - chan_dbg(chan, "LD %p free\n", desc); -#endif - dma_pool_free(chan->desc_pool, desc, txd->phys); -} - -/** - * fsl_chan_xfer_ld_queue - transfer any pending transactions - * @chan : Freescale DMA channel - * - * HARDWARE STATE: idle - * LOCKING: must hold chan->desc_lock - */ -static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) -{ - struct fsl_desc_sw *desc; - - /* - * If the list of pending descriptors is empty, then we - * don't need to do any work at all - */ - if (list_empty(&chan->ld_pending)) { - chan_dbg(chan, "no pending LDs\n"); - return; - } - - /* - * The DMA controller is not idle, which means that the interrupt - * handler will start any queued transactions when it runs after - * this transaction finishes - */ - if (!chan->idle) { - chan_dbg(chan, "DMA controller still busy\n"); - return; - } - - /* - * If there are some link descriptors which have not been - * transferred, we need to start the controller - */ - - /* - * Move all elements from the queue of pending transactions - * onto the list of running transactions - */ - chan_dbg(chan, "idle, starting controller\n"); - desc = list_first_entry(&chan->ld_pending, struct fsl_desc_sw, node); - list_splice_tail_init(&chan->ld_pending, &chan->ld_running); - - /* - * The 85xx DMA controller doesn't clear the channel start bit - * automatically at the end of a transfer. Therefore we must clear - * it in software before starting the transfer. - */ - if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) { - u32 mode; - - mode = DMA_IN(chan, &chan->regs->mr, 32); - mode &= ~FSL_DMA_MR_CS; - DMA_OUT(chan, &chan->regs->mr, mode, 32); - } - - /* - * Program the descriptor's address into the DMA controller, - * then start the DMA transaction - */ - set_cdar(chan, desc->async_tx.phys); - get_cdar(chan); - - dma_start(chan); - chan->idle = false; -} - /** * fsl_dma_memcpy_issue_pending - Issue the DMA start command * @chan : Freescale DMA channel @@ -1304,12 +1286,10 @@ static int fsldma_of_probe(struct platform_device *op) fdev->irq = irq_of_parse_and_map(op->dev.of_node, 0); dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask); - dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask); dma_cap_set(DMA_SG, fdev->common.cap_mask); dma_cap_set(DMA_SLAVE, fdev->common.cap_mask); fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources; fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources; - fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt; fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy; fdev->common.device_prep_dma_sg = fsl_dma_prep_sg; fdev->common.device_tx_status = fsl_tx_status; diff --git a/drivers/dma/ioat/dca.c b/drivers/dma/ioat/dca.c index 9e84d5bc930779..3b55bb8d969a6e 100644 --- a/drivers/dma/ioat/dca.c +++ b/drivers/dma/ioat/dca.c @@ -35,6 +35,7 @@ #include "dma.h" #include "registers.h" +#include "dma_v2.h" /* * Bit 7 of a tag map entry is the "valid" bit, if it is set then bits 0:6 @@ -147,7 +148,7 @@ static int ioat_dca_add_requester(struct dca_provider *dca, struct device *dev) u16 id; /* This implementation only supports PCI-Express */ - if (dev->bus != &pci_bus_type) + if (!dev_is_pci(dev)) return -ENODEV; pdev = to_pci_dev(dev); id = dcaid_from_pcidev(pdev); @@ -179,7 +180,7 @@ static int ioat_dca_remove_requester(struct dca_provider *dca, int i; /* This implementation only supports PCI-Express */ - if (dev->bus != &pci_bus_type) + if (!dev_is_pci(dev)) return -ENODEV; pdev = to_pci_dev(dev); @@ -320,7 +321,7 @@ static int ioat2_dca_add_requester(struct dca_provider *dca, struct device *dev) u16 global_req_table; /* This implementation only supports PCI-Express */ - if (dev->bus != &pci_bus_type) + if (!dev_is_pci(dev)) return -ENODEV; pdev = to_pci_dev(dev); id = dcaid_from_pcidev(pdev); @@ -354,7 +355,7 @@ static int ioat2_dca_remove_requester(struct dca_provider *dca, u16 global_req_table; /* This implementation only supports PCI-Express */ - if (dev->bus != &pci_bus_type) + if (!dev_is_pci(dev)) return -ENODEV; pdev = to_pci_dev(dev); @@ -496,7 +497,7 @@ static int ioat3_dca_add_requester(struct dca_provider *dca, struct device *dev) u16 global_req_table; /* This implementation only supports PCI-Express */ - if (dev->bus != &pci_bus_type) + if (!dev_is_pci(dev)) return -ENODEV; pdev = to_pci_dev(dev); id = dcaid_from_pcidev(pdev); @@ -530,7 +531,7 @@ static int ioat3_dca_remove_requester(struct dca_provider *dca, u16 global_req_table; /* This implementation only supports PCI-Express */ - if (dev->bus != &pci_bus_type) + if (!dev_is_pci(dev)) return -ENODEV; pdev = to_pci_dev(dev); diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 4e3549a161324f..b76c1485933beb 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -947,7 +947,7 @@ int ioat_dma_setup_interrupts(struct ioatdma_device *device) for (i = 0; i < msixcnt; i++) device->msix_entries[i].entry = i; - err = pci_enable_msix(pdev, device->msix_entries, msixcnt); + err = pci_enable_msix_exact(pdev, device->msix_entries, msixcnt); if (err) goto msi; diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index b9b38a1cf92fbd..85971d6e964687 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -740,7 +740,7 @@ ioat3_prep_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, return __ioat3_prep_xor_lock(chan, NULL, dest, src, src_cnt, len, flags); } -struct dma_async_tx_descriptor * +static struct dma_async_tx_descriptor * ioat3_prep_xor_val(struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt, size_t len, enum sum_check_flags *result, unsigned long flags) @@ -1091,7 +1091,7 @@ ioat3_prep_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src, } } -struct dma_async_tx_descriptor * +static struct dma_async_tx_descriptor * ioat3_prep_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src, unsigned int src_cnt, const unsigned char *scf, size_t len, enum sum_check_flags *pqres, unsigned long flags) @@ -1133,7 +1133,7 @@ ioat3_prep_pqxor(struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src, flags); } -struct dma_async_tx_descriptor * +static struct dma_async_tx_descriptor * ioat3_prep_pqxor_val(struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt, size_t len, enum sum_check_flags *result, unsigned long flags) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index bf02e7beb51ad5..a7b186d536b3ad 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -29,8 +29,8 @@ #define DALGN 0x00a0 #define DINT 0x00f0 #define DDADR 0x0200 -#define DSADR 0x0204 -#define DTADR 0x0208 +#define DSADR(n) (0x0204 + ((n) << 4)) +#define DTADR(n) (0x0208 + ((n) << 4)) #define DCMD 0x020c #define DCSR_RUN BIT(31) /* Run Bit (read / write) */ @@ -277,7 +277,7 @@ static void mmp_pdma_free_phy(struct mmp_pdma_chan *pchan) return; /* clear the channel mapping in DRCMR */ - reg = DRCMR(pchan->phy->vchan->drcmr); + reg = DRCMR(pchan->drcmr); writel(0, pchan->phy->base + reg); spin_lock_irqsave(&pdev->phy_lock, flags); @@ -748,11 +748,92 @@ static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd, return 0; } +static unsigned int mmp_pdma_residue(struct mmp_pdma_chan *chan, + dma_cookie_t cookie) +{ + struct mmp_pdma_desc_sw *sw; + u32 curr, residue = 0; + bool passed = false; + bool cyclic = chan->cyclic_first != NULL; + + /* + * If the channel does not have a phy pointer anymore, it has already + * been completed. Therefore, its residue is 0. + */ + if (!chan->phy) + return 0; + + if (chan->dir == DMA_DEV_TO_MEM) + curr = readl(chan->phy->base + DTADR(chan->phy->idx)); + else + curr = readl(chan->phy->base + DSADR(chan->phy->idx)); + + list_for_each_entry(sw, &chan->chain_running, node) { + u32 start, end, len; + + if (chan->dir == DMA_DEV_TO_MEM) + start = sw->desc.dtadr; + else + start = sw->desc.dsadr; + + len = sw->desc.dcmd & DCMD_LENGTH; + end = start + len; + + /* + * 'passed' will be latched once we found the descriptor which + * lies inside the boundaries of the curr pointer. All + * descriptors that occur in the list _after_ we found that + * partially handled descriptor are still to be processed and + * are hence added to the residual bytes counter. + */ + + if (passed) { + residue += len; + } else if (curr >= start && curr <= end) { + residue += end - curr; + passed = true; + } + + /* + * Descriptors that have the ENDIRQEN bit set mark the end of a + * transaction chain, and the cookie assigned with it has been + * returned previously from mmp_pdma_tx_submit(). + * + * In case we have multiple transactions in the running chain, + * and the cookie does not match the one the user asked us + * about, reset the state variables and start over. + * + * This logic does not apply to cyclic transactions, where all + * descriptors have the ENDIRQEN bit set, and for which we + * can't have multiple transactions on one channel anyway. + */ + if (cyclic || !(sw->desc.dcmd & DCMD_ENDIRQEN)) + continue; + + if (sw->async_tx.cookie == cookie) { + return residue; + } else { + residue = 0; + passed = false; + } + } + + /* We should only get here in case of cyclic transactions */ + return residue; +} + static enum dma_status mmp_pdma_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, struct dma_tx_state *txstate) { - return dma_cookie_status(dchan, cookie, txstate); + struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan); + enum dma_status ret; + + ret = dma_cookie_status(dchan, cookie, txstate); + if (likely(ret != DMA_ERROR)) + dma_set_residue(txstate, mmp_pdma_residue(chan, cookie)); + + return ret; } /** @@ -858,8 +939,7 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, int idx, int irq) struct mmp_pdma_chan *chan; int ret; - chan = devm_kzalloc(pdev->dev, sizeof(struct mmp_pdma_chan), - GFP_KERNEL); + chan = devm_kzalloc(pdev->dev, sizeof(*chan), GFP_KERNEL); if (chan == NULL) return -ENOMEM; @@ -946,8 +1026,7 @@ static int mmp_pdma_probe(struct platform_device *op) irq_num++; } - pdev->phy = devm_kcalloc(pdev->dev, - dma_channels, sizeof(struct mmp_pdma_chan), + pdev->phy = devm_kcalloc(pdev->dev, dma_channels, sizeof(*pdev->phy), GFP_KERNEL); if (pdev->phy == NULL) return -ENOMEM; diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 448750da4402fb..96104f4eebe8d0 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -52,9 +52,17 @@ #define MPC_DMA_DESCRIPTORS 64 /* Macro definitions */ -#define MPC_DMA_CHANNELS 64 #define MPC_DMA_TCD_OFFSET 0x1000 +/* + * Maximum channel counts for individual hardware variants + * and the maximum channel count over all supported controllers, + * used for data structure size + */ +#define MPC8308_DMACHAN_MAX 16 +#define MPC512x_DMACHAN_MAX 64 +#define MPC_DMA_CHANNELS 64 + /* Arbitration mode of group and channel */ #define MPC_DMA_DMACR_EDCG (1 << 31) #define MPC_DMA_DMACR_ERGA (1 << 3) @@ -649,13 +657,15 @@ static int mpc_dma_probe(struct platform_device *op) mdma = devm_kzalloc(dev, sizeof(struct mpc_dma), GFP_KERNEL); if (!mdma) { dev_err(dev, "Memory exhausted!\n"); - return -ENOMEM; + retval = -ENOMEM; + goto err; } mdma->irq = irq_of_parse_and_map(dn, 0); if (mdma->irq == NO_IRQ) { dev_err(dev, "Error mapping IRQ!\n"); - return -EINVAL; + retval = -EINVAL; + goto err; } if (of_device_is_compatible(dn, "fsl,mpc8308-dma")) { @@ -663,14 +673,15 @@ static int mpc_dma_probe(struct platform_device *op) mdma->irq2 = irq_of_parse_and_map(dn, 1); if (mdma->irq2 == NO_IRQ) { dev_err(dev, "Error mapping IRQ!\n"); - return -EINVAL; + retval = -EINVAL; + goto err_dispose1; } } retval = of_address_to_resource(dn, 0, &res); if (retval) { dev_err(dev, "Error parsing memory region!\n"); - return retval; + goto err_dispose2; } regs_start = res.start; @@ -678,31 +689,34 @@ static int mpc_dma_probe(struct platform_device *op) if (!devm_request_mem_region(dev, regs_start, regs_size, DRV_NAME)) { dev_err(dev, "Error requesting memory region!\n"); - return -EBUSY; + retval = -EBUSY; + goto err_dispose2; } mdma->regs = devm_ioremap(dev, regs_start, regs_size); if (!mdma->regs) { dev_err(dev, "Error mapping memory region!\n"); - return -ENOMEM; + retval = -ENOMEM; + goto err_dispose2; } mdma->tcd = (struct mpc_dma_tcd *)((u8 *)(mdma->regs) + MPC_DMA_TCD_OFFSET); - retval = devm_request_irq(dev, mdma->irq, &mpc_dma_irq, 0, DRV_NAME, - mdma); + retval = request_irq(mdma->irq, &mpc_dma_irq, 0, DRV_NAME, mdma); if (retval) { dev_err(dev, "Error requesting IRQ!\n"); - return -EINVAL; + retval = -EINVAL; + goto err_dispose2; } if (mdma->is_mpc8308) { - retval = devm_request_irq(dev, mdma->irq2, &mpc_dma_irq, 0, - DRV_NAME, mdma); + retval = request_irq(mdma->irq2, &mpc_dma_irq, 0, + DRV_NAME, mdma); if (retval) { dev_err(dev, "Error requesting IRQ2!\n"); - return -EINVAL; + retval = -EINVAL; + goto err_free1; } } @@ -710,10 +724,10 @@ static int mpc_dma_probe(struct platform_device *op) dma = &mdma->dma; dma->dev = dev; - if (!mdma->is_mpc8308) - dma->chancnt = MPC_DMA_CHANNELS; + if (mdma->is_mpc8308) + dma->chancnt = MPC8308_DMACHAN_MAX; else - dma->chancnt = 16; /* MPC8308 DMA has only 16 channels */ + dma->chancnt = MPC512x_DMACHAN_MAX; dma->device_alloc_chan_resources = mpc_dma_alloc_chan_resources; dma->device_free_chan_resources = mpc_dma_free_chan_resources; dma->device_issue_pending = mpc_dma_issue_pending; @@ -747,7 +761,19 @@ static int mpc_dma_probe(struct platform_device *op) * - Round-robin group arbitration, * - Round-robin channel arbitration. */ - if (!mdma->is_mpc8308) { + if (mdma->is_mpc8308) { + /* MPC8308 has 16 channels and lacks some registers */ + out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_ERCA); + + /* enable snooping */ + out_be32(&mdma->regs->dmagpor, MPC_DMA_DMAGPOR_SNOOP_ENABLE); + /* Disable error interrupts */ + out_be32(&mdma->regs->dmaeeil, 0); + + /* Clear interrupts status */ + out_be32(&mdma->regs->dmaintl, 0xFFFF); + out_be32(&mdma->regs->dmaerrl, 0xFFFF); + } else { out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG | MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA); @@ -768,29 +794,28 @@ static int mpc_dma_probe(struct platform_device *op) /* Route interrupts to IPIC */ out_be32(&mdma->regs->dmaihsa, 0); out_be32(&mdma->regs->dmailsa, 0); - } else { - /* MPC8308 has 16 channels and lacks some registers */ - out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_ERCA); - - /* enable snooping */ - out_be32(&mdma->regs->dmagpor, MPC_DMA_DMAGPOR_SNOOP_ENABLE); - /* Disable error interrupts */ - out_be32(&mdma->regs->dmaeeil, 0); - - /* Clear interrupts status */ - out_be32(&mdma->regs->dmaintl, 0xFFFF); - out_be32(&mdma->regs->dmaerrl, 0xFFFF); } /* Register DMA engine */ dev_set_drvdata(dev, mdma); retval = dma_async_device_register(dma); - if (retval) { - devm_free_irq(dev, mdma->irq, mdma); - irq_dispose_mapping(mdma->irq); - } + if (retval) + goto err_free2; return retval; + +err_free2: + if (mdma->is_mpc8308) + free_irq(mdma->irq2, mdma); +err_free1: + free_irq(mdma->irq, mdma); +err_dispose2: + if (mdma->is_mpc8308) + irq_dispose_mapping(mdma->irq2); +err_dispose1: + irq_dispose_mapping(mdma->irq); +err: + return retval; } static int mpc_dma_remove(struct platform_device *op) @@ -799,7 +824,11 @@ static int mpc_dma_remove(struct platform_device *op) struct mpc_dma *mdma = dev_get_drvdata(dev); dma_async_device_unregister(&mdma->dma); - devm_free_irq(dev, mdma->irq, mdma); + if (mdma->is_mpc8308) { + free_irq(mdma->irq2, mdma); + irq_dispose_mapping(mdma->irq2); + } + free_irq(mdma->irq, mdma); irq_dispose_mapping(mdma->irq); return 0; @@ -807,6 +836,7 @@ static int mpc_dma_remove(struct platform_device *op) static struct of_device_id mpc_dma_match[] = { { .compatible = "fsl,mpc5121-dma", }, + { .compatible = "fsl,mpc8308-dma", }, {}, }; diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 766b68ed505c4d..7938272f2edf4f 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -191,12 +191,10 @@ static void mv_set_mode(struct mv_xor_chan *chan, static void mv_chan_activate(struct mv_xor_chan *chan) { - u32 activation; - dev_dbg(mv_chan_to_devp(chan), " activate chan.\n"); - activation = readl_relaxed(XOR_ACTIVATION(chan)); - activation |= 0x1; - writel_relaxed(activation, XOR_ACTIVATION(chan)); + + /* writel ensures all descriptors are flushed before activation */ + writel(BIT(0), XOR_ACTIVATION(chan)); } static char mv_chan_is_busy(struct mv_xor_chan *chan) @@ -312,7 +310,8 @@ mv_xor_clean_slot(struct mv_xor_desc_slot *desc, return 0; } -static void __mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) +/* This function must be called with the mv_xor_chan spinlock held */ +static void mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) { struct mv_xor_desc_slot *iter, *_iter; dma_cookie_t cookie = 0; @@ -368,18 +367,13 @@ static void __mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) mv_chan->dmachan.completed_cookie = cookie; } -static void -mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) -{ - spin_lock_bh(&mv_chan->lock); - __mv_xor_slot_cleanup(mv_chan); - spin_unlock_bh(&mv_chan->lock); -} - static void mv_xor_tasklet(unsigned long data) { struct mv_xor_chan *chan = (struct mv_xor_chan *) data; + + spin_lock_bh(&chan->lock); mv_xor_slot_cleanup(chan); + spin_unlock_bh(&chan->lock); } static struct mv_xor_desc_slot * @@ -658,9 +652,10 @@ static void mv_xor_free_chan_resources(struct dma_chan *chan) struct mv_xor_desc_slot *iter, *_iter; int in_use_descs = 0; + spin_lock_bh(&mv_chan->lock); + mv_xor_slot_cleanup(mv_chan); - spin_lock_bh(&mv_chan->lock); list_for_each_entry_safe(iter, _iter, &mv_chan->chain, chain_node) { in_use_descs++; @@ -702,11 +697,12 @@ static enum dma_status mv_xor_status(struct dma_chan *chan, enum dma_status ret; ret = dma_cookie_status(chan, cookie, txstate); - if (ret == DMA_COMPLETE) { - mv_xor_clean_completed_slots(mv_chan); + if (ret == DMA_COMPLETE) return ret; - } + + spin_lock_bh(&mv_chan->lock); mv_xor_slot_cleanup(mv_chan); + spin_unlock_bh(&mv_chan->lock); return dma_cookie_status(chan, cookie, txstate); } @@ -784,7 +780,7 @@ static void mv_xor_issue_pending(struct dma_chan *chan) static int mv_xor_memcpy_self_test(struct mv_xor_chan *mv_chan) { - int i; + int i, ret; void *src, *dest; dma_addr_t src_dma, dest_dma; struct dma_chan *dma_chan; @@ -821,19 +817,44 @@ static int mv_xor_memcpy_self_test(struct mv_xor_chan *mv_chan) src_dma = dma_map_page(dma_chan->device->dev, virt_to_page(src), 0, PAGE_SIZE, DMA_TO_DEVICE); - unmap->to_cnt = 1; unmap->addr[0] = src_dma; + ret = dma_mapping_error(dma_chan->device->dev, src_dma); + if (ret) { + err = -ENOMEM; + goto free_resources; + } + unmap->to_cnt = 1; + dest_dma = dma_map_page(dma_chan->device->dev, virt_to_page(dest), 0, PAGE_SIZE, DMA_FROM_DEVICE); - unmap->from_cnt = 1; unmap->addr[1] = dest_dma; + ret = dma_mapping_error(dma_chan->device->dev, dest_dma); + if (ret) { + err = -ENOMEM; + goto free_resources; + } + unmap->from_cnt = 1; unmap->len = PAGE_SIZE; tx = mv_xor_prep_dma_memcpy(dma_chan, dest_dma, src_dma, PAGE_SIZE, 0); + if (!tx) { + dev_err(dma_chan->device->dev, + "Self-test cannot prepare operation, disabling\n"); + err = -ENODEV; + goto free_resources; + } + cookie = mv_xor_tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_err(dma_chan->device->dev, + "Self-test submit error, disabling\n"); + err = -ENODEV; + goto free_resources; + } + mv_xor_issue_pending(dma_chan); async_tx_ack(tx); msleep(1); @@ -868,7 +889,7 @@ static int mv_xor_memcpy_self_test(struct mv_xor_chan *mv_chan) static int mv_xor_xor_self_test(struct mv_xor_chan *mv_chan) { - int i, src_idx; + int i, src_idx, ret; struct page *dest; struct page *xor_srcs[MV_XOR_NUM_SRC_TEST]; dma_addr_t dma_srcs[MV_XOR_NUM_SRC_TEST]; @@ -931,19 +952,42 @@ mv_xor_xor_self_test(struct mv_xor_chan *mv_chan) unmap->addr[i] = dma_map_page(dma_chan->device->dev, xor_srcs[i], 0, PAGE_SIZE, DMA_TO_DEVICE); dma_srcs[i] = unmap->addr[i]; + ret = dma_mapping_error(dma_chan->device->dev, unmap->addr[i]); + if (ret) { + err = -ENOMEM; + goto free_resources; + } unmap->to_cnt++; } unmap->addr[src_count] = dma_map_page(dma_chan->device->dev, dest, 0, PAGE_SIZE, DMA_FROM_DEVICE); dest_dma = unmap->addr[src_count]; + ret = dma_mapping_error(dma_chan->device->dev, unmap->addr[src_count]); + if (ret) { + err = -ENOMEM; + goto free_resources; + } unmap->from_cnt = 1; unmap->len = PAGE_SIZE; tx = mv_xor_prep_dma_xor(dma_chan, dest_dma, dma_srcs, src_count, PAGE_SIZE, 0); + if (!tx) { + dev_err(dma_chan->device->dev, + "Self-test cannot prepare operation, disabling\n"); + err = -ENODEV; + goto free_resources; + } cookie = mv_xor_tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_err(dma_chan->device->dev, + "Self-test submit error, disabling\n"); + err = -ENODEV; + goto free_resources; + } + mv_xor_issue_pending(dma_chan); async_tx_ack(tx); msleep(8); diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 52396771acbe53..974794cdb6ed6e 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -73,8 +73,7 @@ static void shdma_chan_xfer_ld_queue(struct shdma_chan *schan) static dma_cookie_t shdma_tx_submit(struct dma_async_tx_descriptor *tx) { struct shdma_desc *chunk, *c, *desc = - container_of(tx, struct shdma_desc, async_tx), - *last = desc; + container_of(tx, struct shdma_desc, async_tx); struct shdma_chan *schan = to_shdma_chan(tx->chan); dma_async_tx_callback callback = tx->callback; dma_cookie_t cookie; @@ -98,19 +97,20 @@ static dma_cookie_t shdma_tx_submit(struct dma_async_tx_descriptor *tx) &chunk->node == &schan->ld_free)) break; chunk->mark = DESC_SUBMITTED; - /* Callback goes to the last chunk */ - chunk->async_tx.callback = NULL; + if (chunk->chunks == 1) { + chunk->async_tx.callback = callback; + chunk->async_tx.callback_param = tx->callback_param; + } else { + /* Callback goes to the last chunk */ + chunk->async_tx.callback = NULL; + } chunk->cookie = cookie; list_move_tail(&chunk->node, &schan->ld_queue); - last = chunk; dev_dbg(schan->dev, "submit #%d@%p on %d\n", - tx->cookie, &last->async_tx, schan->id); + tx->cookie, &chunk->async_tx, schan->id); } - last->async_tx.callback = callback; - last->async_tx.callback_param = tx->callback_param; - if (power_up) { int ret; schan->pm_state = SHDMA_PM_BUSY; @@ -304,6 +304,7 @@ static dma_async_tx_callback __ld_cleanup(struct shdma_chan *schan, bool all) dma_async_tx_callback callback = NULL; void *param = NULL; unsigned long flags; + LIST_HEAD(cyclic_list); spin_lock_irqsave(&schan->chan_lock, flags); list_for_each_entry_safe(desc, _desc, &schan->ld_queue, node) { @@ -369,10 +370,16 @@ static dma_async_tx_callback __ld_cleanup(struct shdma_chan *schan, bool all) if (((desc->mark == DESC_COMPLETED || desc->mark == DESC_WAITING) && async_tx_test_ack(&desc->async_tx)) || all) { - /* Remove from ld_queue list */ - desc->mark = DESC_IDLE; - list_move(&desc->node, &schan->ld_free); + if (all || !desc->cyclic) { + /* Remove from ld_queue list */ + desc->mark = DESC_IDLE; + list_move(&desc->node, &schan->ld_free); + } else { + /* reuse as cyclic */ + desc->mark = DESC_SUBMITTED; + list_move_tail(&desc->node, &cyclic_list); + } if (list_empty(&schan->ld_queue)) { dev_dbg(schan->dev, "Bring down channel %d\n", schan->id); @@ -389,6 +396,8 @@ static dma_async_tx_callback __ld_cleanup(struct shdma_chan *schan, bool all) */ schan->dma_chan.completed_cookie = schan->dma_chan.cookie; + list_splice_tail(&cyclic_list, &schan->ld_queue); + spin_unlock_irqrestore(&schan->chan_lock, flags); if (callback) @@ -521,7 +530,7 @@ static struct shdma_desc *shdma_add_desc(struct shdma_chan *schan, */ static struct dma_async_tx_descriptor *shdma_prep_sg(struct shdma_chan *schan, struct scatterlist *sgl, unsigned int sg_len, dma_addr_t *addr, - enum dma_transfer_direction direction, unsigned long flags) + enum dma_transfer_direction direction, unsigned long flags, bool cyclic) { struct scatterlist *sg; struct shdma_desc *first = NULL, *new = NULL /* compiler... */; @@ -569,7 +578,11 @@ static struct dma_async_tx_descriptor *shdma_prep_sg(struct shdma_chan *schan, if (!new) goto err_get_desc; - new->chunks = chunks--; + new->cyclic = cyclic; + if (cyclic) + new->chunks = 1; + else + new->chunks = chunks--; list_add_tail(&new->node, &tx_list); } while (len); } @@ -612,7 +625,8 @@ static struct dma_async_tx_descriptor *shdma_prep_memcpy( sg_dma_address(&sg) = dma_src; sg_dma_len(&sg) = len; - return shdma_prep_sg(schan, &sg, 1, &dma_dest, DMA_MEM_TO_MEM, flags); + return shdma_prep_sg(schan, &sg, 1, &dma_dest, DMA_MEM_TO_MEM, + flags, false); } static struct dma_async_tx_descriptor *shdma_prep_slave_sg( @@ -640,7 +654,50 @@ static struct dma_async_tx_descriptor *shdma_prep_slave_sg( slave_addr = ops->slave_addr(schan); return shdma_prep_sg(schan, sgl, sg_len, &slave_addr, - direction, flags); + direction, flags, false); +} + +struct dma_async_tx_descriptor *shdma_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct shdma_chan *schan = to_shdma_chan(chan); + struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); + const struct shdma_ops *ops = sdev->ops; + unsigned int sg_len = buf_len / period_len; + int slave_id = schan->slave_id; + dma_addr_t slave_addr; + struct scatterlist sgl[sg_len]; + int i; + + if (!chan) + return NULL; + + BUG_ON(!schan->desc_num); + + /* Someone calling slave DMA on a generic channel? */ + if (slave_id < 0 || (buf_len < period_len)) { + dev_warn(schan->dev, + "%s: bad parameter: buf_len=%d, period_len=%d, id=%d\n", + __func__, buf_len, period_len, slave_id); + return NULL; + } + + slave_addr = ops->slave_addr(schan); + + sg_init_table(sgl, sg_len); + for (i = 0; i < sg_len; i++) { + dma_addr_t src = buf_addr + (period_len * i); + + sg_set_page(&sgl[i], pfn_to_page(PFN_DOWN(src)), period_len, + offset_in_page(src)); + sg_dma_address(&sgl[i]) = src; + sg_dma_len(&sgl[i]) = period_len; + } + + return shdma_prep_sg(schan, sgl, sg_len, &slave_addr, + direction, flags, true); } static int shdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, @@ -915,6 +972,7 @@ int shdma_init(struct device *dev, struct shdma_dev *sdev, /* Compulsory for DMA_SLAVE fields */ dma_dev->device_prep_slave_sg = shdma_prep_slave_sg; + dma_dev->device_prep_dma_cyclic = shdma_prep_dma_cyclic; dma_dev->device_control = shdma_control; dma_dev->dev = dev; diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index bf18c786ed40fb..c7984459ede76b 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -556,7 +556,6 @@ struct d40_gen_dmac { * later * @reg_val_backup_chan: Backup data for standard channel parameter registers. * @gcc_pwr_off_mask: Mask to maintain the channels that can be turned off. - * @initialized: true if the dma has been initialized * @gen_dmac: the struct for generic registers values to represent u8500/8540 * DMA controller */ @@ -594,7 +593,6 @@ struct d40_base { u32 reg_val_backup_v4[BACKUP_REGS_SZ_MAX]; u32 *reg_val_backup_chan; u16 gcc_pwr_off_mask; - bool initialized; struct d40_gen_dmac gen_dmac; }; @@ -1056,62 +1054,6 @@ static int d40_sg_2_dmalen(struct scatterlist *sgl, int sg_len, return len; } - -#ifdef CONFIG_PM -static void dma40_backup(void __iomem *baseaddr, u32 *backup, - u32 *regaddr, int num, bool save) -{ - int i; - - for (i = 0; i < num; i++) { - void __iomem *addr = baseaddr + regaddr[i]; - - if (save) - backup[i] = readl_relaxed(addr); - else - writel_relaxed(backup[i], addr); - } -} - -static void d40_save_restore_registers(struct d40_base *base, bool save) -{ - int i; - - /* Save/Restore channel specific registers */ - for (i = 0; i < base->num_phy_chans; i++) { - void __iomem *addr; - int idx; - - if (base->phy_res[i].reserved) - continue; - - addr = base->virtbase + D40_DREG_PCBASE + i * D40_DREG_PCDELTA; - idx = i * ARRAY_SIZE(d40_backup_regs_chan); - - dma40_backup(addr, &base->reg_val_backup_chan[idx], - d40_backup_regs_chan, - ARRAY_SIZE(d40_backup_regs_chan), - save); - } - - /* Save/Restore global registers */ - dma40_backup(base->virtbase, base->reg_val_backup, - d40_backup_regs, ARRAY_SIZE(d40_backup_regs), - save); - - /* Save/Restore registers only existing on dma40 v3 and later */ - if (base->gen_dmac.backup) - dma40_backup(base->virtbase, base->reg_val_backup_v4, - base->gen_dmac.backup, - base->gen_dmac.backup_size, - save); -} -#else -static void d40_save_restore_registers(struct d40_base *base, bool save) -{ -} -#endif - static int __d40_execute_command_phy(struct d40_chan *d40c, enum d40_command command) { @@ -1495,8 +1437,8 @@ static int d40_pause(struct d40_chan *d40c) if (!d40c->busy) return 0; - pm_runtime_get_sync(d40c->base->dev); spin_lock_irqsave(&d40c->lock, flags); + pm_runtime_get_sync(d40c->base->dev); res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ); @@ -2998,18 +2940,88 @@ static int __init d40_dmaengine_init(struct d40_base *base, } /* Suspend resume functionality */ -#ifdef CONFIG_PM -static int dma40_pm_suspend(struct device *dev) +#ifdef CONFIG_PM_SLEEP +static int dma40_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct d40_base *base = platform_get_drvdata(pdev); - int ret = 0; + int ret; + + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; if (base->lcpa_regulator) ret = regulator_disable(base->lcpa_regulator); return ret; } +static int dma40_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct d40_base *base = platform_get_drvdata(pdev); + int ret = 0; + + if (base->lcpa_regulator) { + ret = regulator_enable(base->lcpa_regulator); + if (ret) + return ret; + } + + return pm_runtime_force_resume(dev); +} +#endif + +#ifdef CONFIG_PM +static void dma40_backup(void __iomem *baseaddr, u32 *backup, + u32 *regaddr, int num, bool save) +{ + int i; + + for (i = 0; i < num; i++) { + void __iomem *addr = baseaddr + regaddr[i]; + + if (save) + backup[i] = readl_relaxed(addr); + else + writel_relaxed(backup[i], addr); + } +} + +static void d40_save_restore_registers(struct d40_base *base, bool save) +{ + int i; + + /* Save/Restore channel specific registers */ + for (i = 0; i < base->num_phy_chans; i++) { + void __iomem *addr; + int idx; + + if (base->phy_res[i].reserved) + continue; + + addr = base->virtbase + D40_DREG_PCBASE + i * D40_DREG_PCDELTA; + idx = i * ARRAY_SIZE(d40_backup_regs_chan); + + dma40_backup(addr, &base->reg_val_backup_chan[idx], + d40_backup_regs_chan, + ARRAY_SIZE(d40_backup_regs_chan), + save); + } + + /* Save/Restore global registers */ + dma40_backup(base->virtbase, base->reg_val_backup, + d40_backup_regs, ARRAY_SIZE(d40_backup_regs), + save); + + /* Save/Restore registers only existing on dma40 v3 and later */ + if (base->gen_dmac.backup) + dma40_backup(base->virtbase, base->reg_val_backup_v4, + base->gen_dmac.backup, + base->gen_dmac.backup_size, + save); +} + static int dma40_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -3030,36 +3042,20 @@ static int dma40_runtime_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct d40_base *base = platform_get_drvdata(pdev); - if (base->initialized) - d40_save_restore_registers(base, false); + d40_save_restore_registers(base, false); writel_relaxed(D40_DREG_GCC_ENABLE_ALL, base->virtbase + D40_DREG_GCC); return 0; } - -static int dma40_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct d40_base *base = platform_get_drvdata(pdev); - int ret = 0; - - if (base->lcpa_regulator) - ret = regulator_enable(base->lcpa_regulator); - - return ret; -} +#endif static const struct dev_pm_ops dma40_pm_ops = { - .suspend = dma40_pm_suspend, - .runtime_suspend = dma40_runtime_suspend, - .runtime_resume = dma40_runtime_resume, - .resume = dma40_resume, + SET_LATE_SYSTEM_SLEEP_PM_OPS(dma40_suspend, dma40_resume) + SET_PM_RUNTIME_PM_OPS(dma40_runtime_suspend, + dma40_runtime_resume, + NULL) }; -#define DMA40_PM_OPS (&dma40_pm_ops) -#else -#define DMA40_PM_OPS NULL -#endif /* Initialization functions. */ @@ -3645,12 +3641,6 @@ static int __init d40_probe(struct platform_device *pdev) goto failure; } - pm_runtime_irq_safe(base->dev); - pm_runtime_set_autosuspend_delay(base->dev, DMA40_AUTOSUSPEND_DELAY); - pm_runtime_use_autosuspend(base->dev); - pm_runtime_enable(base->dev); - pm_runtime_resume(base->dev); - if (base->plat_data->use_esram_lcla) { base->lcpa_regulator = regulator_get(base->dev, "lcla_esram"); @@ -3671,7 +3661,15 @@ static int __init d40_probe(struct platform_device *pdev) } } - base->initialized = true; + writel_relaxed(D40_DREG_GCC_ENABLE_ALL, base->virtbase + D40_DREG_GCC); + + pm_runtime_irq_safe(base->dev); + pm_runtime_set_autosuspend_delay(base->dev, DMA40_AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(base->dev); + pm_runtime_mark_last_busy(base->dev); + pm_runtime_set_active(base->dev); + pm_runtime_enable(base->dev); + ret = d40_dmaengine_init(base, num_reserved_chans); if (ret) goto failure; @@ -3754,7 +3752,7 @@ static struct platform_driver d40_driver = { .driver = { .owner = THIS_MODULE, .name = D40_NAME, - .pm = DMA40_PM_OPS, + .pm = &dma40_pm_ops, .of_match_table = d40_match, }, }; diff --git a/drivers/dma/xilinx/Makefile b/drivers/dma/xilinx/Makefile new file mode 100644 index 00000000000000..3c4e9f2fea2871 --- /dev/null +++ b/drivers/dma/xilinx/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_XILINX_VDMA) += xilinx_vdma.o diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c new file mode 100644 index 00000000000000..42a13e8d460781 --- /dev/null +++ b/drivers/dma/xilinx/xilinx_vdma.c @@ -0,0 +1,1379 @@ +/* + * DMA driver for Xilinx Video DMA Engine + * + * Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved. + * + * Based on the Freescale DMA driver. + * + * Description: + * The AXI Video Direct Memory Access (AXI VDMA) core is a soft Xilinx IP + * core that provides high-bandwidth direct memory access between memory + * and AXI4-Stream type video target peripherals. The core provides efficient + * two dimensional DMA operations with independent asynchronous read (S2MM) + * and write (MM2S) channel operation. It can be configured to have either + * one channel or two channels. If configured as two channels, one is to + * transmit to the video device (MM2S) and another is to receive from the + * video device (S2MM). Initialization, status, interrupt and management + * registers are accessed through an AXI4-Lite slave interface. + * + * 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 +#include +#include +#include + +#include "../dmaengine.h" + +/* Register/Descriptor Offsets */ +#define XILINX_VDMA_MM2S_CTRL_OFFSET 0x0000 +#define XILINX_VDMA_S2MM_CTRL_OFFSET 0x0030 +#define XILINX_VDMA_MM2S_DESC_OFFSET 0x0050 +#define XILINX_VDMA_S2MM_DESC_OFFSET 0x00a0 + +/* Control Registers */ +#define XILINX_VDMA_REG_DMACR 0x0000 +#define XILINX_VDMA_DMACR_DELAY_MAX 0xff +#define XILINX_VDMA_DMACR_DELAY_SHIFT 24 +#define XILINX_VDMA_DMACR_FRAME_COUNT_MAX 0xff +#define XILINX_VDMA_DMACR_FRAME_COUNT_SHIFT 16 +#define XILINX_VDMA_DMACR_ERR_IRQ BIT(14) +#define XILINX_VDMA_DMACR_DLY_CNT_IRQ BIT(13) +#define XILINX_VDMA_DMACR_FRM_CNT_IRQ BIT(12) +#define XILINX_VDMA_DMACR_MASTER_SHIFT 8 +#define XILINX_VDMA_DMACR_FSYNCSRC_SHIFT 5 +#define XILINX_VDMA_DMACR_FRAMECNT_EN BIT(4) +#define XILINX_VDMA_DMACR_GENLOCK_EN BIT(3) +#define XILINX_VDMA_DMACR_RESET BIT(2) +#define XILINX_VDMA_DMACR_CIRC_EN BIT(1) +#define XILINX_VDMA_DMACR_RUNSTOP BIT(0) +#define XILINX_VDMA_DMACR_FSYNCSRC_MASK GENMASK(6, 5) + +#define XILINX_VDMA_REG_DMASR 0x0004 +#define XILINX_VDMA_DMASR_EOL_LATE_ERR BIT(15) +#define XILINX_VDMA_DMASR_ERR_IRQ BIT(14) +#define XILINX_VDMA_DMASR_DLY_CNT_IRQ BIT(13) +#define XILINX_VDMA_DMASR_FRM_CNT_IRQ BIT(12) +#define XILINX_VDMA_DMASR_SOF_LATE_ERR BIT(11) +#define XILINX_VDMA_DMASR_SG_DEC_ERR BIT(10) +#define XILINX_VDMA_DMASR_SG_SLV_ERR BIT(9) +#define XILINX_VDMA_DMASR_EOF_EARLY_ERR BIT(8) +#define XILINX_VDMA_DMASR_SOF_EARLY_ERR BIT(7) +#define XILINX_VDMA_DMASR_DMA_DEC_ERR BIT(6) +#define XILINX_VDMA_DMASR_DMA_SLAVE_ERR BIT(5) +#define XILINX_VDMA_DMASR_DMA_INT_ERR BIT(4) +#define XILINX_VDMA_DMASR_IDLE BIT(1) +#define XILINX_VDMA_DMASR_HALTED BIT(0) +#define XILINX_VDMA_DMASR_DELAY_MASK GENMASK(31, 24) +#define XILINX_VDMA_DMASR_FRAME_COUNT_MASK GENMASK(23, 16) + +#define XILINX_VDMA_REG_CURDESC 0x0008 +#define XILINX_VDMA_REG_TAILDESC 0x0010 +#define XILINX_VDMA_REG_REG_INDEX 0x0014 +#define XILINX_VDMA_REG_FRMSTORE 0x0018 +#define XILINX_VDMA_REG_THRESHOLD 0x001c +#define XILINX_VDMA_REG_FRMPTR_STS 0x0024 +#define XILINX_VDMA_REG_PARK_PTR 0x0028 +#define XILINX_VDMA_PARK_PTR_WR_REF_SHIFT 8 +#define XILINX_VDMA_PARK_PTR_RD_REF_SHIFT 0 +#define XILINX_VDMA_REG_VDMA_VERSION 0x002c + +/* Register Direct Mode Registers */ +#define XILINX_VDMA_REG_VSIZE 0x0000 +#define XILINX_VDMA_REG_HSIZE 0x0004 + +#define XILINX_VDMA_REG_FRMDLY_STRIDE 0x0008 +#define XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_SHIFT 24 +#define XILINX_VDMA_FRMDLY_STRIDE_STRIDE_SHIFT 0 + +#define XILINX_VDMA_REG_START_ADDRESS(n) (0x000c + 4 * (n)) + +/* HW specific definitions */ +#define XILINX_VDMA_MAX_CHANS_PER_DEVICE 0x2 + +#define XILINX_VDMA_DMAXR_ALL_IRQ_MASK \ + (XILINX_VDMA_DMASR_FRM_CNT_IRQ | \ + XILINX_VDMA_DMASR_DLY_CNT_IRQ | \ + XILINX_VDMA_DMASR_ERR_IRQ) + +#define XILINX_VDMA_DMASR_ALL_ERR_MASK \ + (XILINX_VDMA_DMASR_EOL_LATE_ERR | \ + XILINX_VDMA_DMASR_SOF_LATE_ERR | \ + XILINX_VDMA_DMASR_SG_DEC_ERR | \ + XILINX_VDMA_DMASR_SG_SLV_ERR | \ + XILINX_VDMA_DMASR_EOF_EARLY_ERR | \ + XILINX_VDMA_DMASR_SOF_EARLY_ERR | \ + XILINX_VDMA_DMASR_DMA_DEC_ERR | \ + XILINX_VDMA_DMASR_DMA_SLAVE_ERR | \ + XILINX_VDMA_DMASR_DMA_INT_ERR) + +/* + * Recoverable errors are DMA Internal error, SOF Early, EOF Early + * and SOF Late. They are only recoverable when C_FLUSH_ON_FSYNC + * is enabled in the h/w system. + */ +#define XILINX_VDMA_DMASR_ERR_RECOVER_MASK \ + (XILINX_VDMA_DMASR_SOF_LATE_ERR | \ + XILINX_VDMA_DMASR_EOF_EARLY_ERR | \ + XILINX_VDMA_DMASR_SOF_EARLY_ERR | \ + XILINX_VDMA_DMASR_DMA_INT_ERR) + +/* Axi VDMA Flush on Fsync bits */ +#define XILINX_VDMA_FLUSH_S2MM 3 +#define XILINX_VDMA_FLUSH_MM2S 2 +#define XILINX_VDMA_FLUSH_BOTH 1 + +/* Delay loop counter to prevent hardware failure */ +#define XILINX_VDMA_LOOP_COUNT 1000000 + +/** + * struct xilinx_vdma_desc_hw - Hardware Descriptor + * @next_desc: Next Descriptor Pointer @0x00 + * @pad1: Reserved @0x04 + * @buf_addr: Buffer address @0x08 + * @pad2: Reserved @0x0C + * @vsize: Vertical Size @0x10 + * @hsize: Horizontal Size @0x14 + * @stride: Number of bytes between the first + * pixels of each horizontal line @0x18 + */ +struct xilinx_vdma_desc_hw { + u32 next_desc; + u32 pad1; + u32 buf_addr; + u32 pad2; + u32 vsize; + u32 hsize; + u32 stride; +} __aligned(64); + +/** + * struct xilinx_vdma_tx_segment - Descriptor segment + * @hw: Hardware descriptor + * @node: Node in the descriptor segments list + * @phys: Physical address of segment + */ +struct xilinx_vdma_tx_segment { + struct xilinx_vdma_desc_hw hw; + struct list_head node; + dma_addr_t phys; +} __aligned(64); + +/** + * struct xilinx_vdma_tx_descriptor - Per Transaction structure + * @async_tx: Async transaction descriptor + * @segments: TX segments list + * @node: Node in the channel descriptors list + */ +struct xilinx_vdma_tx_descriptor { + struct dma_async_tx_descriptor async_tx; + struct list_head segments; + struct list_head node; +}; + +/** + * struct xilinx_vdma_chan - Driver specific VDMA channel structure + * @xdev: Driver specific device structure + * @ctrl_offset: Control registers offset + * @desc_offset: TX descriptor registers offset + * @lock: Descriptor operation lock + * @pending_list: Descriptors waiting + * @active_desc: Active descriptor + * @allocated_desc: Allocated descriptor + * @done_list: Complete descriptors + * @common: DMA common channel + * @desc_pool: Descriptors pool + * @dev: The dma device + * @irq: Channel IRQ + * @id: Channel ID + * @direction: Transfer direction + * @num_frms: Number of frames + * @has_sg: Support scatter transfers + * @genlock: Support genlock mode + * @err: Channel has errors + * @tasklet: Cleanup work after irq + * @config: Device configuration info + * @flush_on_fsync: Flush on Frame sync + */ +struct xilinx_vdma_chan { + struct xilinx_vdma_device *xdev; + u32 ctrl_offset; + u32 desc_offset; + spinlock_t lock; + struct list_head pending_list; + struct xilinx_vdma_tx_descriptor *active_desc; + struct xilinx_vdma_tx_descriptor *allocated_desc; + struct list_head done_list; + struct dma_chan common; + struct dma_pool *desc_pool; + struct device *dev; + int irq; + int id; + enum dma_transfer_direction direction; + int num_frms; + bool has_sg; + bool genlock; + bool err; + struct tasklet_struct tasklet; + struct xilinx_vdma_config config; + bool flush_on_fsync; +}; + +/** + * struct xilinx_vdma_device - VDMA device structure + * @regs: I/O mapped base address + * @dev: Device Structure + * @common: DMA device structure + * @chan: Driver specific VDMA channel + * @has_sg: Specifies whether Scatter-Gather is present or not + * @flush_on_fsync: Flush on frame sync + */ +struct xilinx_vdma_device { + void __iomem *regs; + struct device *dev; + struct dma_device common; + struct xilinx_vdma_chan *chan[XILINX_VDMA_MAX_CHANS_PER_DEVICE]; + bool has_sg; + u32 flush_on_fsync; +}; + +/* Macros */ +#define to_xilinx_chan(chan) \ + container_of(chan, struct xilinx_vdma_chan, common) +#define to_vdma_tx_descriptor(tx) \ + container_of(tx, struct xilinx_vdma_tx_descriptor, async_tx) + +/* IO accessors */ +static inline u32 vdma_read(struct xilinx_vdma_chan *chan, u32 reg) +{ + return ioread32(chan->xdev->regs + reg); +} + +static inline void vdma_write(struct xilinx_vdma_chan *chan, u32 reg, u32 value) +{ + iowrite32(value, chan->xdev->regs + reg); +} + +static inline void vdma_desc_write(struct xilinx_vdma_chan *chan, u32 reg, + u32 value) +{ + vdma_write(chan, chan->desc_offset + reg, value); +} + +static inline u32 vdma_ctrl_read(struct xilinx_vdma_chan *chan, u32 reg) +{ + return vdma_read(chan, chan->ctrl_offset + reg); +} + +static inline void vdma_ctrl_write(struct xilinx_vdma_chan *chan, u32 reg, + u32 value) +{ + vdma_write(chan, chan->ctrl_offset + reg, value); +} + +static inline void vdma_ctrl_clr(struct xilinx_vdma_chan *chan, u32 reg, + u32 clr) +{ + vdma_ctrl_write(chan, reg, vdma_ctrl_read(chan, reg) & ~clr); +} + +static inline void vdma_ctrl_set(struct xilinx_vdma_chan *chan, u32 reg, + u32 set) +{ + vdma_ctrl_write(chan, reg, vdma_ctrl_read(chan, reg) | set); +} + +/* ----------------------------------------------------------------------------- + * Descriptors and segments alloc and free + */ + +/** + * xilinx_vdma_alloc_tx_segment - Allocate transaction segment + * @chan: Driver specific VDMA channel + * + * Return: The allocated segment on success and NULL on failure. + */ +static struct xilinx_vdma_tx_segment * +xilinx_vdma_alloc_tx_segment(struct xilinx_vdma_chan *chan) +{ + struct xilinx_vdma_tx_segment *segment; + dma_addr_t phys; + + segment = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &phys); + if (!segment) + return NULL; + + memset(segment, 0, sizeof(*segment)); + segment->phys = phys; + + return segment; +} + +/** + * xilinx_vdma_free_tx_segment - Free transaction segment + * @chan: Driver specific VDMA channel + * @segment: VDMA transaction segment + */ +static void xilinx_vdma_free_tx_segment(struct xilinx_vdma_chan *chan, + struct xilinx_vdma_tx_segment *segment) +{ + dma_pool_free(chan->desc_pool, segment, segment->phys); +} + +/** + * xilinx_vdma_tx_descriptor - Allocate transaction descriptor + * @chan: Driver specific VDMA channel + * + * Return: The allocated descriptor on success and NULL on failure. + */ +static struct xilinx_vdma_tx_descriptor * +xilinx_vdma_alloc_tx_descriptor(struct xilinx_vdma_chan *chan) +{ + struct xilinx_vdma_tx_descriptor *desc; + unsigned long flags; + + if (chan->allocated_desc) + return chan->allocated_desc; + + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return NULL; + + spin_lock_irqsave(&chan->lock, flags); + chan->allocated_desc = desc; + spin_unlock_irqrestore(&chan->lock, flags); + + INIT_LIST_HEAD(&desc->segments); + + return desc; +} + +/** + * xilinx_vdma_free_tx_descriptor - Free transaction descriptor + * @chan: Driver specific VDMA channel + * @desc: VDMA transaction descriptor + */ +static void +xilinx_vdma_free_tx_descriptor(struct xilinx_vdma_chan *chan, + struct xilinx_vdma_tx_descriptor *desc) +{ + struct xilinx_vdma_tx_segment *segment, *next; + + if (!desc) + return; + + list_for_each_entry_safe(segment, next, &desc->segments, node) { + list_del(&segment->node); + xilinx_vdma_free_tx_segment(chan, segment); + } + + kfree(desc); +} + +/* Required functions */ + +/** + * xilinx_vdma_free_desc_list - Free descriptors list + * @chan: Driver specific VDMA channel + * @list: List to parse and delete the descriptor + */ +static void xilinx_vdma_free_desc_list(struct xilinx_vdma_chan *chan, + struct list_head *list) +{ + struct xilinx_vdma_tx_descriptor *desc, *next; + + list_for_each_entry_safe(desc, next, list, node) { + list_del(&desc->node); + xilinx_vdma_free_tx_descriptor(chan, desc); + } +} + +/** + * xilinx_vdma_free_descriptors - Free channel descriptors + * @chan: Driver specific VDMA channel + */ +static void xilinx_vdma_free_descriptors(struct xilinx_vdma_chan *chan) +{ + unsigned long flags; + + spin_lock_irqsave(&chan->lock, flags); + + xilinx_vdma_free_desc_list(chan, &chan->pending_list); + xilinx_vdma_free_desc_list(chan, &chan->done_list); + + xilinx_vdma_free_tx_descriptor(chan, chan->active_desc); + chan->active_desc = NULL; + + spin_unlock_irqrestore(&chan->lock, flags); +} + +/** + * xilinx_vdma_free_chan_resources - Free channel resources + * @dchan: DMA channel + */ +static void xilinx_vdma_free_chan_resources(struct dma_chan *dchan) +{ + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan); + + dev_dbg(chan->dev, "Free all channel resources.\n"); + + xilinx_vdma_free_descriptors(chan); + dma_pool_destroy(chan->desc_pool); + chan->desc_pool = NULL; +} + +/** + * xilinx_vdma_chan_desc_cleanup - Clean channel descriptors + * @chan: Driver specific VDMA channel + */ +static void xilinx_vdma_chan_desc_cleanup(struct xilinx_vdma_chan *chan) +{ + struct xilinx_vdma_tx_descriptor *desc, *next; + unsigned long flags; + + spin_lock_irqsave(&chan->lock, flags); + + list_for_each_entry_safe(desc, next, &chan->done_list, node) { + dma_async_tx_callback callback; + void *callback_param; + + /* Remove from the list of running transactions */ + list_del(&desc->node); + + /* Run the link descriptor callback function */ + callback = desc->async_tx.callback; + callback_param = desc->async_tx.callback_param; + if (callback) { + spin_unlock_irqrestore(&chan->lock, flags); + callback(callback_param); + spin_lock_irqsave(&chan->lock, flags); + } + + /* Run any dependencies, then free the descriptor */ + dma_run_dependencies(&desc->async_tx); + xilinx_vdma_free_tx_descriptor(chan, desc); + } + + spin_unlock_irqrestore(&chan->lock, flags); +} + +/** + * xilinx_vdma_do_tasklet - Schedule completion tasklet + * @data: Pointer to the Xilinx VDMA channel structure + */ +static void xilinx_vdma_do_tasklet(unsigned long data) +{ + struct xilinx_vdma_chan *chan = (struct xilinx_vdma_chan *)data; + + xilinx_vdma_chan_desc_cleanup(chan); +} + +/** + * xilinx_vdma_alloc_chan_resources - Allocate channel resources + * @dchan: DMA channel + * + * Return: '0' on success and failure value on error + */ +static int xilinx_vdma_alloc_chan_resources(struct dma_chan *dchan) +{ + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan); + + /* Has this channel already been allocated? */ + if (chan->desc_pool) + return 0; + + /* + * We need the descriptor to be aligned to 64bytes + * for meeting Xilinx VDMA specification requirement. + */ + chan->desc_pool = dma_pool_create("xilinx_vdma_desc_pool", + chan->dev, + sizeof(struct xilinx_vdma_tx_segment), + __alignof__(struct xilinx_vdma_tx_segment), 0); + if (!chan->desc_pool) { + dev_err(chan->dev, + "unable to allocate channel %d descriptor pool\n", + chan->id); + return -ENOMEM; + } + + dma_cookie_init(dchan); + return 0; +} + +/** + * xilinx_vdma_tx_status - Get VDMA transaction status + * @dchan: DMA channel + * @cookie: Transaction identifier + * @txstate: Transaction state + * + * Return: DMA transaction status + */ +static enum dma_status xilinx_vdma_tx_status(struct dma_chan *dchan, + dma_cookie_t cookie, + struct dma_tx_state *txstate) +{ + return dma_cookie_status(dchan, cookie, txstate); +} + +/** + * xilinx_vdma_is_running - Check if VDMA channel is running + * @chan: Driver specific VDMA channel + * + * Return: '1' if running, '0' if not. + */ +static bool xilinx_vdma_is_running(struct xilinx_vdma_chan *chan) +{ + return !(vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) & + XILINX_VDMA_DMASR_HALTED) && + (vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) & + XILINX_VDMA_DMACR_RUNSTOP); +} + +/** + * xilinx_vdma_is_idle - Check if VDMA channel is idle + * @chan: Driver specific VDMA channel + * + * Return: '1' if idle, '0' if not. + */ +static bool xilinx_vdma_is_idle(struct xilinx_vdma_chan *chan) +{ + return vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) & + XILINX_VDMA_DMASR_IDLE; +} + +/** + * xilinx_vdma_halt - Halt VDMA channel + * @chan: Driver specific VDMA channel + */ +static void xilinx_vdma_halt(struct xilinx_vdma_chan *chan) +{ + int loop = XILINX_VDMA_LOOP_COUNT; + + vdma_ctrl_clr(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RUNSTOP); + + /* Wait for the hardware to halt */ + do { + if (vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) & + XILINX_VDMA_DMASR_HALTED) + break; + } while (loop--); + + if (!loop) { + dev_err(chan->dev, "Cannot stop channel %p: %x\n", + chan, vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR)); + chan->err = true; + } + + return; +} + +/** + * xilinx_vdma_start - Start VDMA channel + * @chan: Driver specific VDMA channel + */ +static void xilinx_vdma_start(struct xilinx_vdma_chan *chan) +{ + int loop = XILINX_VDMA_LOOP_COUNT; + + vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RUNSTOP); + + /* Wait for the hardware to start */ + do { + if (!(vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR) & + XILINX_VDMA_DMASR_HALTED)) + break; + } while (loop--); + + if (!loop) { + dev_err(chan->dev, "Cannot start channel %p: %x\n", + chan, vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR)); + + chan->err = true; + } + + return; +} + +/** + * xilinx_vdma_start_transfer - Starts VDMA transfer + * @chan: Driver specific channel struct pointer + */ +static void xilinx_vdma_start_transfer(struct xilinx_vdma_chan *chan) +{ + struct xilinx_vdma_config *config = &chan->config; + struct xilinx_vdma_tx_descriptor *desc; + unsigned long flags; + u32 reg; + struct xilinx_vdma_tx_segment *head, *tail = NULL; + + if (chan->err) + return; + + spin_lock_irqsave(&chan->lock, flags); + + /* There's already an active descriptor, bail out. */ + if (chan->active_desc) + goto out_unlock; + + if (list_empty(&chan->pending_list)) + goto out_unlock; + + desc = list_first_entry(&chan->pending_list, + struct xilinx_vdma_tx_descriptor, node); + + /* If it is SG mode and hardware is busy, cannot submit */ + if (chan->has_sg && xilinx_vdma_is_running(chan) && + !xilinx_vdma_is_idle(chan)) { + dev_dbg(chan->dev, "DMA controller still busy\n"); + goto out_unlock; + } + + /* + * If hardware is idle, then all descriptors on the running lists are + * done, start new transfers + */ + if (chan->has_sg) { + head = list_first_entry(&desc->segments, + struct xilinx_vdma_tx_segment, node); + tail = list_entry(desc->segments.prev, + struct xilinx_vdma_tx_segment, node); + + vdma_ctrl_write(chan, XILINX_VDMA_REG_CURDESC, head->phys); + } + + /* Configure the hardware using info in the config structure */ + reg = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR); + + if (config->frm_cnt_en) + reg |= XILINX_VDMA_DMACR_FRAMECNT_EN; + else + reg &= ~XILINX_VDMA_DMACR_FRAMECNT_EN; + + /* + * With SG, start with circular mode, so that BDs can be fetched. + * In direct register mode, if not parking, enable circular mode + */ + if (chan->has_sg || !config->park) + reg |= XILINX_VDMA_DMACR_CIRC_EN; + + if (config->park) + reg &= ~XILINX_VDMA_DMACR_CIRC_EN; + + vdma_ctrl_write(chan, XILINX_VDMA_REG_DMACR, reg); + + if (config->park && (config->park_frm >= 0) && + (config->park_frm < chan->num_frms)) { + if (chan->direction == DMA_MEM_TO_DEV) + vdma_write(chan, XILINX_VDMA_REG_PARK_PTR, + config->park_frm << + XILINX_VDMA_PARK_PTR_RD_REF_SHIFT); + else + vdma_write(chan, XILINX_VDMA_REG_PARK_PTR, + config->park_frm << + XILINX_VDMA_PARK_PTR_WR_REF_SHIFT); + } + + /* Start the hardware */ + xilinx_vdma_start(chan); + + if (chan->err) + goto out_unlock; + + /* Start the transfer */ + if (chan->has_sg) { + vdma_ctrl_write(chan, XILINX_VDMA_REG_TAILDESC, tail->phys); + } else { + struct xilinx_vdma_tx_segment *segment, *last = NULL; + int i = 0; + + list_for_each_entry(segment, &desc->segments, node) { + vdma_desc_write(chan, + XILINX_VDMA_REG_START_ADDRESS(i++), + segment->hw.buf_addr); + last = segment; + } + + if (!last) + goto out_unlock; + + /* HW expects these parameters to be same for one transaction */ + vdma_desc_write(chan, XILINX_VDMA_REG_HSIZE, last->hw.hsize); + vdma_desc_write(chan, XILINX_VDMA_REG_FRMDLY_STRIDE, + last->hw.stride); + vdma_desc_write(chan, XILINX_VDMA_REG_VSIZE, last->hw.vsize); + } + + list_del(&desc->node); + chan->active_desc = desc; + +out_unlock: + spin_unlock_irqrestore(&chan->lock, flags); +} + +/** + * xilinx_vdma_issue_pending - Issue pending transactions + * @dchan: DMA channel + */ +static void xilinx_vdma_issue_pending(struct dma_chan *dchan) +{ + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan); + + xilinx_vdma_start_transfer(chan); +} + +/** + * xilinx_vdma_complete_descriptor - Mark the active descriptor as complete + * @chan : xilinx DMA channel + * + * CONTEXT: hardirq + */ +static void xilinx_vdma_complete_descriptor(struct xilinx_vdma_chan *chan) +{ + struct xilinx_vdma_tx_descriptor *desc; + unsigned long flags; + + spin_lock_irqsave(&chan->lock, flags); + + desc = chan->active_desc; + if (!desc) { + dev_dbg(chan->dev, "no running descriptors\n"); + goto out_unlock; + } + + dma_cookie_complete(&desc->async_tx); + list_add_tail(&desc->node, &chan->done_list); + + chan->active_desc = NULL; + +out_unlock: + spin_unlock_irqrestore(&chan->lock, flags); +} + +/** + * xilinx_vdma_reset - Reset VDMA channel + * @chan: Driver specific VDMA channel + * + * Return: '0' on success and failure value on error + */ +static int xilinx_vdma_reset(struct xilinx_vdma_chan *chan) +{ + int loop = XILINX_VDMA_LOOP_COUNT; + u32 tmp; + + vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR, XILINX_VDMA_DMACR_RESET); + + tmp = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) & + XILINX_VDMA_DMACR_RESET; + + /* Wait for the hardware to finish reset */ + do { + tmp = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR) & + XILINX_VDMA_DMACR_RESET; + } while (loop-- && tmp); + + if (!loop) { + dev_err(chan->dev, "reset timeout, cr %x, sr %x\n", + vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR), + vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR)); + return -ETIMEDOUT; + } + + chan->err = false; + + return 0; +} + +/** + * xilinx_vdma_chan_reset - Reset VDMA channel and enable interrupts + * @chan: Driver specific VDMA channel + * + * Return: '0' on success and failure value on error + */ +static int xilinx_vdma_chan_reset(struct xilinx_vdma_chan *chan) +{ + int err; + + /* Reset VDMA */ + err = xilinx_vdma_reset(chan); + if (err) + return err; + + /* Enable interrupts */ + vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR, + XILINX_VDMA_DMAXR_ALL_IRQ_MASK); + + return 0; +} + +/** + * xilinx_vdma_irq_handler - VDMA Interrupt handler + * @irq: IRQ number + * @data: Pointer to the Xilinx VDMA channel structure + * + * Return: IRQ_HANDLED/IRQ_NONE + */ +static irqreturn_t xilinx_vdma_irq_handler(int irq, void *data) +{ + struct xilinx_vdma_chan *chan = data; + u32 status; + + /* Read the status and ack the interrupts. */ + status = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMASR); + if (!(status & XILINX_VDMA_DMAXR_ALL_IRQ_MASK)) + return IRQ_NONE; + + vdma_ctrl_write(chan, XILINX_VDMA_REG_DMASR, + status & XILINX_VDMA_DMAXR_ALL_IRQ_MASK); + + if (status & XILINX_VDMA_DMASR_ERR_IRQ) { + /* + * An error occurred. If C_FLUSH_ON_FSYNC is enabled and the + * error is recoverable, ignore it. Otherwise flag the error. + * + * Only recoverable errors can be cleared in the DMASR register, + * make sure not to write to other error bits to 1. + */ + u32 errors = status & XILINX_VDMA_DMASR_ALL_ERR_MASK; + vdma_ctrl_write(chan, XILINX_VDMA_REG_DMASR, + errors & XILINX_VDMA_DMASR_ERR_RECOVER_MASK); + + if (!chan->flush_on_fsync || + (errors & ~XILINX_VDMA_DMASR_ERR_RECOVER_MASK)) { + dev_err(chan->dev, + "Channel %p has errors %x, cdr %x tdr %x\n", + chan, errors, + vdma_ctrl_read(chan, XILINX_VDMA_REG_CURDESC), + vdma_ctrl_read(chan, XILINX_VDMA_REG_TAILDESC)); + chan->err = true; + } + } + + if (status & XILINX_VDMA_DMASR_DLY_CNT_IRQ) { + /* + * Device takes too long to do the transfer when user requires + * responsiveness. + */ + dev_dbg(chan->dev, "Inter-packet latency too long\n"); + } + + if (status & XILINX_VDMA_DMASR_FRM_CNT_IRQ) { + xilinx_vdma_complete_descriptor(chan); + xilinx_vdma_start_transfer(chan); + } + + tasklet_schedule(&chan->tasklet); + return IRQ_HANDLED; +} + +/** + * xilinx_vdma_tx_submit - Submit DMA transaction + * @tx: Async transaction descriptor + * + * Return: cookie value on success and failure value on error + */ +static dma_cookie_t xilinx_vdma_tx_submit(struct dma_async_tx_descriptor *tx) +{ + struct xilinx_vdma_tx_descriptor *desc = to_vdma_tx_descriptor(tx); + struct xilinx_vdma_chan *chan = to_xilinx_chan(tx->chan); + dma_cookie_t cookie; + unsigned long flags; + int err; + + if (chan->err) { + /* + * If reset fails, need to hard reset the system. + * Channel is no longer functional + */ + err = xilinx_vdma_chan_reset(chan); + if (err < 0) + return err; + } + + spin_lock_irqsave(&chan->lock, flags); + + cookie = dma_cookie_assign(tx); + + /* Append the transaction to the pending transactions queue. */ + list_add_tail(&desc->node, &chan->pending_list); + + /* Free the allocated desc */ + chan->allocated_desc = NULL; + + spin_unlock_irqrestore(&chan->lock, flags); + + return cookie; +} + +/** + * xilinx_vdma_dma_prep_interleaved - prepare a descriptor for a + * DMA_SLAVE transaction + * @dchan: DMA channel + * @xt: Interleaved template pointer + * @flags: transfer ack flags + * + * Return: Async transaction descriptor on success and NULL on failure + */ +static struct dma_async_tx_descriptor * +xilinx_vdma_dma_prep_interleaved(struct dma_chan *dchan, + struct dma_interleaved_template *xt, + unsigned long flags) +{ + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan); + struct xilinx_vdma_tx_descriptor *desc; + struct xilinx_vdma_tx_segment *segment, *prev = NULL; + struct xilinx_vdma_desc_hw *hw; + + if (!is_slave_direction(xt->dir)) + return NULL; + + if (!xt->numf || !xt->sgl[0].size) + return NULL; + + /* Allocate a transaction descriptor. */ + desc = xilinx_vdma_alloc_tx_descriptor(chan); + if (!desc) + return NULL; + + dma_async_tx_descriptor_init(&desc->async_tx, &chan->common); + desc->async_tx.tx_submit = xilinx_vdma_tx_submit; + async_tx_ack(&desc->async_tx); + + /* Allocate the link descriptor from DMA pool */ + segment = xilinx_vdma_alloc_tx_segment(chan); + if (!segment) + goto error; + + /* Fill in the hardware descriptor */ + hw = &segment->hw; + hw->vsize = xt->numf; + hw->hsize = xt->sgl[0].size; + hw->stride = xt->sgl[0].icg << + XILINX_VDMA_FRMDLY_STRIDE_STRIDE_SHIFT; + hw->stride |= chan->config.frm_dly << + XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_SHIFT; + + if (xt->dir != DMA_MEM_TO_DEV) + hw->buf_addr = xt->dst_start; + else + hw->buf_addr = xt->src_start; + + /* Link the previous next descriptor to current */ + prev = list_last_entry(&desc->segments, + struct xilinx_vdma_tx_segment, node); + prev->hw.next_desc = segment->phys; + + /* Insert the segment into the descriptor segments list. */ + list_add_tail(&segment->node, &desc->segments); + + prev = segment; + + /* Link the last hardware descriptor with the first. */ + segment = list_first_entry(&desc->segments, + struct xilinx_vdma_tx_segment, node); + prev->hw.next_desc = segment->phys; + + return &desc->async_tx; + +error: + xilinx_vdma_free_tx_descriptor(chan, desc); + return NULL; +} + +/** + * xilinx_vdma_terminate_all - Halt the channel and free descriptors + * @chan: Driver specific VDMA Channel pointer + */ +static void xilinx_vdma_terminate_all(struct xilinx_vdma_chan *chan) +{ + /* Halt the DMA engine */ + xilinx_vdma_halt(chan); + + /* Remove and free all of the descriptors in the lists */ + xilinx_vdma_free_descriptors(chan); +} + +/** + * xilinx_vdma_channel_set_config - Configure VDMA channel + * Run-time configuration for Axi VDMA, supports: + * . halt the channel + * . configure interrupt coalescing and inter-packet delay threshold + * . start/stop parking + * . enable genlock + * + * @dchan: DMA channel + * @cfg: VDMA device configuration pointer + * + * Return: '0' on success and failure value on error + */ +int xilinx_vdma_channel_set_config(struct dma_chan *dchan, + struct xilinx_vdma_config *cfg) +{ + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan); + u32 dmacr; + + if (cfg->reset) + return xilinx_vdma_chan_reset(chan); + + dmacr = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR); + + chan->config.frm_dly = cfg->frm_dly; + chan->config.park = cfg->park; + + /* genlock settings */ + chan->config.gen_lock = cfg->gen_lock; + chan->config.master = cfg->master; + + if (cfg->gen_lock && chan->genlock) { + dmacr |= XILINX_VDMA_DMACR_GENLOCK_EN; + dmacr |= cfg->master << XILINX_VDMA_DMACR_MASTER_SHIFT; + } + + chan->config.frm_cnt_en = cfg->frm_cnt_en; + if (cfg->park) + chan->config.park_frm = cfg->park_frm; + else + chan->config.park_frm = -1; + + chan->config.coalesc = cfg->coalesc; + chan->config.delay = cfg->delay; + + if (cfg->coalesc <= XILINX_VDMA_DMACR_FRAME_COUNT_MAX) { + dmacr |= cfg->coalesc << XILINX_VDMA_DMACR_FRAME_COUNT_SHIFT; + chan->config.coalesc = cfg->coalesc; + } + + if (cfg->delay <= XILINX_VDMA_DMACR_DELAY_MAX) { + dmacr |= cfg->delay << XILINX_VDMA_DMACR_DELAY_SHIFT; + chan->config.delay = cfg->delay; + } + + /* FSync Source selection */ + dmacr &= ~XILINX_VDMA_DMACR_FSYNCSRC_MASK; + dmacr |= cfg->ext_fsync << XILINX_VDMA_DMACR_FSYNCSRC_SHIFT; + + vdma_ctrl_write(chan, XILINX_VDMA_REG_DMACR, dmacr); + + return 0; +} +EXPORT_SYMBOL(xilinx_vdma_channel_set_config); + +/** + * xilinx_vdma_device_control - Configure DMA channel of the device + * @dchan: DMA Channel pointer + * @cmd: DMA control command + * @arg: Channel configuration + * + * Return: '0' on success and failure value on error + */ +static int xilinx_vdma_device_control(struct dma_chan *dchan, + enum dma_ctrl_cmd cmd, unsigned long arg) +{ + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan); + + if (cmd != DMA_TERMINATE_ALL) + return -ENXIO; + + xilinx_vdma_terminate_all(chan); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Probe and remove + */ + +/** + * xilinx_vdma_chan_remove - Per Channel remove function + * @chan: Driver specific VDMA channel + */ +static void xilinx_vdma_chan_remove(struct xilinx_vdma_chan *chan) +{ + /* Disable all interrupts */ + vdma_ctrl_clr(chan, XILINX_VDMA_REG_DMACR, + XILINX_VDMA_DMAXR_ALL_IRQ_MASK); + + if (chan->irq > 0) + free_irq(chan->irq, chan); + + tasklet_kill(&chan->tasklet); + + list_del(&chan->common.device_node); +} + +/** + * xilinx_vdma_chan_probe - Per Channel Probing + * It get channel features from the device tree entry and + * initialize special channel handling routines + * + * @xdev: Driver specific device structure + * @node: Device node + * + * Return: '0' on success and failure value on error + */ +static int xilinx_vdma_chan_probe(struct xilinx_vdma_device *xdev, + struct device_node *node) +{ + struct xilinx_vdma_chan *chan; + bool has_dre = false; + u32 value, width; + int err; + + /* Allocate and initialize the channel structure */ + chan = devm_kzalloc(xdev->dev, sizeof(*chan), GFP_KERNEL); + if (!chan) + return -ENOMEM; + + chan->dev = xdev->dev; + chan->xdev = xdev; + chan->has_sg = xdev->has_sg; + + spin_lock_init(&chan->lock); + INIT_LIST_HEAD(&chan->pending_list); + INIT_LIST_HEAD(&chan->done_list); + + /* Retrieve the channel properties from the device tree */ + has_dre = of_property_read_bool(node, "xlnx,include-dre"); + + chan->genlock = of_property_read_bool(node, "xlnx,genlock-mode"); + + err = of_property_read_u32(node, "xlnx,datawidth", &value); + if (err) { + dev_err(xdev->dev, "missing xlnx,datawidth property\n"); + return err; + } + width = value >> 3; /* Convert bits to bytes */ + + /* If data width is greater than 8 bytes, DRE is not in hw */ + if (width > 8) + has_dre = false; + + if (!has_dre) + xdev->common.copy_align = fls(width - 1); + + if (of_device_is_compatible(node, "xlnx,axi-vdma-mm2s-channel")) { + chan->direction = DMA_MEM_TO_DEV; + chan->id = 0; + + chan->ctrl_offset = XILINX_VDMA_MM2S_CTRL_OFFSET; + chan->desc_offset = XILINX_VDMA_MM2S_DESC_OFFSET; + + if (xdev->flush_on_fsync == XILINX_VDMA_FLUSH_BOTH || + xdev->flush_on_fsync == XILINX_VDMA_FLUSH_MM2S) + chan->flush_on_fsync = true; + } else if (of_device_is_compatible(node, + "xlnx,axi-vdma-s2mm-channel")) { + chan->direction = DMA_DEV_TO_MEM; + chan->id = 1; + + chan->ctrl_offset = XILINX_VDMA_S2MM_CTRL_OFFSET; + chan->desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET; + + if (xdev->flush_on_fsync == XILINX_VDMA_FLUSH_BOTH || + xdev->flush_on_fsync == XILINX_VDMA_FLUSH_S2MM) + chan->flush_on_fsync = true; + } else { + dev_err(xdev->dev, "Invalid channel compatible node\n"); + return -EINVAL; + } + + /* Request the interrupt */ + chan->irq = irq_of_parse_and_map(node, 0); + err = request_irq(chan->irq, xilinx_vdma_irq_handler, IRQF_SHARED, + "xilinx-vdma-controller", chan); + if (err) { + dev_err(xdev->dev, "unable to request IRQ %d\n", chan->irq); + return err; + } + + /* Initialize the tasklet */ + tasklet_init(&chan->tasklet, xilinx_vdma_do_tasklet, + (unsigned long)chan); + + /* + * Initialize the DMA channel and add it to the DMA engine channels + * list. + */ + chan->common.device = &xdev->common; + + list_add_tail(&chan->common.device_node, &xdev->common.channels); + xdev->chan[chan->id] = chan; + + /* Reset the channel */ + err = xilinx_vdma_chan_reset(chan); + if (err < 0) { + dev_err(xdev->dev, "Reset channel failed\n"); + return err; + } + + return 0; +} + +/** + * of_dma_xilinx_xlate - Translation function + * @dma_spec: Pointer to DMA specifier as found in the device tree + * @ofdma: Pointer to DMA controller data + * + * Return: DMA channel pointer on success and NULL on error + */ +static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct xilinx_vdma_device *xdev = ofdma->of_dma_data; + int chan_id = dma_spec->args[0]; + + if (chan_id >= XILINX_VDMA_MAX_CHANS_PER_DEVICE) + return NULL; + + return dma_get_slave_channel(&xdev->chan[chan_id]->common); +} + +/** + * xilinx_vdma_probe - Driver probe function + * @pdev: Pointer to the platform_device structure + * + * Return: '0' on success and failure value on error + */ +static int xilinx_vdma_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct xilinx_vdma_device *xdev; + struct device_node *child; + struct resource *io; + u32 num_frames; + int i, err; + + /* Allocate and initialize the DMA engine structure */ + xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); + if (!xdev) + return -ENOMEM; + + xdev->dev = &pdev->dev; + + /* Request and map I/O memory */ + io = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xdev->regs = devm_ioremap_resource(&pdev->dev, io); + if (IS_ERR(xdev->regs)) + return PTR_ERR(xdev->regs); + + /* Retrieve the DMA engine properties from the device tree */ + xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg"); + + err = of_property_read_u32(node, "xlnx,num-fstores", &num_frames); + if (err < 0) { + dev_err(xdev->dev, "missing xlnx,num-fstores property\n"); + return err; + } + + err = of_property_read_u32(node, "xlnx,flush-fsync", + &xdev->flush_on_fsync); + if (err < 0) + dev_warn(xdev->dev, "missing xlnx,flush-fsync property\n"); + + /* Initialize the DMA engine */ + xdev->common.dev = &pdev->dev; + + INIT_LIST_HEAD(&xdev->common.channels); + dma_cap_set(DMA_SLAVE, xdev->common.cap_mask); + dma_cap_set(DMA_PRIVATE, xdev->common.cap_mask); + + xdev->common.device_alloc_chan_resources = + xilinx_vdma_alloc_chan_resources; + xdev->common.device_free_chan_resources = + xilinx_vdma_free_chan_resources; + xdev->common.device_prep_interleaved_dma = + xilinx_vdma_dma_prep_interleaved; + xdev->common.device_control = xilinx_vdma_device_control; + xdev->common.device_tx_status = xilinx_vdma_tx_status; + xdev->common.device_issue_pending = xilinx_vdma_issue_pending; + + platform_set_drvdata(pdev, xdev); + + /* Initialize the channels */ + for_each_child_of_node(node, child) { + err = xilinx_vdma_chan_probe(xdev, child); + if (err < 0) + goto error; + } + + for (i = 0; i < XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++) + if (xdev->chan[i]) + xdev->chan[i]->num_frms = num_frames; + + /* Register the DMA engine with the core */ + dma_async_device_register(&xdev->common); + + err = of_dma_controller_register(node, of_dma_xilinx_xlate, + xdev); + if (err < 0) { + dev_err(&pdev->dev, "Unable to register DMA to DT\n"); + dma_async_device_unregister(&xdev->common); + goto error; + } + + dev_info(&pdev->dev, "Xilinx AXI VDMA Engine Driver Probed!!\n"); + + return 0; + +error: + for (i = 0; i < XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++) + if (xdev->chan[i]) + xilinx_vdma_chan_remove(xdev->chan[i]); + + return err; +} + +/** + * xilinx_vdma_remove - Driver remove function + * @pdev: Pointer to the platform_device structure + * + * Return: Always '0' + */ +static int xilinx_vdma_remove(struct platform_device *pdev) +{ + struct xilinx_vdma_device *xdev = platform_get_drvdata(pdev); + int i; + + of_dma_controller_free(pdev->dev.of_node); + + dma_async_device_unregister(&xdev->common); + + for (i = 0; i < XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++) + if (xdev->chan[i]) + xilinx_vdma_chan_remove(xdev->chan[i]); + + return 0; +} + +static const struct of_device_id xilinx_vdma_of_ids[] = { + { .compatible = "xlnx,axi-vdma-1.00.a",}, + {} +}; + +static struct platform_driver xilinx_vdma_driver = { + .driver = { + .name = "xilinx-vdma", + .owner = THIS_MODULE, + .of_match_table = xilinx_vdma_of_ids, + }, + .probe = xilinx_vdma_probe, + .remove = xilinx_vdma_remove, +}; + +module_platform_driver(xilinx_vdma_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx VDMA driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index 51b9caa0b024c9..5f43620d580adf 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -6,7 +6,6 @@ static struct amd_decoder_ops *fam_ops; static u8 xec_mask = 0xf; -static u8 nb_err_cpumask = 0xf; static bool report_gart_errors; static void (*nb_bus_decoder)(int node_id, struct mce *m); @@ -852,7 +851,6 @@ static int __init mce_amd_init(void) break; case 0x14: - nb_err_cpumask = 0x3; fam_ops->mc0_mce = cat_mc0_mce; fam_ops->mc1_mce = cat_mc1_mce; fam_ops->mc2_mce = k8_mc2_mce; diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index be56e8ac95e6e3..aebde489c2914d 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -28,13 +28,13 @@ config EXTCON_ADC_JACK Say Y here to enable extcon device driver based on ADC values. config EXTCON_MAX14577 - tristate "MAX14577 EXTCON Support" + tristate "MAX14577/77836 EXTCON Support" depends on MFD_MAX14577 select IRQ_DOMAIN select REGMAP_I2C help If you say yes here you get support for the MUIC device of - Maxim MAX14577 PMIC. The MAX14577 MUIC is a USB port accessory + Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory detector and switch. config EXTCON_MAX77693 diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c index 3846941801b8fd..c76734a7017175 100644 --- a/drivers/extcon/extcon-max14577.c +++ b/drivers/extcon/extcon-max14577.c @@ -1,8 +1,9 @@ /* - * extcon-max14577.c - MAX14577 extcon driver to support MAX14577 MUIC + * extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC * - * Copyright (C) 2013 Samsung Electrnoics + * Copyright (C) 2013,2014 Samsung Electrnoics * Chanwoo Choi + * Krzysztof Kozlowski * * 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 @@ -24,7 +25,6 @@ #include #include -#define DEV_NAME "max14577-muic" #define DELAY_MS_DEFAULT 17000 /* unit: millisecond */ enum max14577_muic_adc_debounce_time { @@ -40,6 +40,42 @@ enum max14577_muic_status { MAX14577_MUIC_STATUS_END, }; +/** + * struct max14577_muic_irq + * @irq: the index of irq list of MUIC device. + * @name: the name of irq. + * @virq: the virtual irq to use irq domain + */ +struct max14577_muic_irq { + unsigned int irq; + const char *name; + unsigned int virq; +}; + +static struct max14577_muic_irq max14577_muic_irqs[] = { + { MAX14577_IRQ_INT1_ADC, "muic-ADC" }, + { MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" }, + { MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" }, + { MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" }, + { MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" }, + { MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" }, + { MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" }, + { MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" }, +}; + +static struct max14577_muic_irq max77836_muic_irqs[] = { + { MAX14577_IRQ_INT1_ADC, "muic-ADC" }, + { MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" }, + { MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" }, + { MAX77836_IRQ_INT1_ADC1K, "muic-ADC1K" }, + { MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" }, + { MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" }, + { MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" }, + { MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" }, + { MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" }, + { MAX77836_IRQ_INT2_VIDRM, "muic-VIDRM" }, +}; + struct max14577_muic_info { struct device *dev; struct max14577 *max14577; @@ -48,6 +84,8 @@ struct max14577_muic_info { int prev_chg_type; u8 status[MAX14577_MUIC_STATUS_END]; + struct max14577_muic_irq *muic_irqs; + unsigned int muic_irqs_num; bool irq_adc; bool irq_chg; struct work_struct irq_work; @@ -74,29 +112,6 @@ enum max14577_muic_cable_group { MAX14577_CABLE_GROUP_CHG, }; -/** - * struct max14577_muic_irq - * @irq: the index of irq list of MUIC device. - * @name: the name of irq. - * @virq: the virtual irq to use irq domain - */ -struct max14577_muic_irq { - unsigned int irq; - const char *name; - unsigned int virq; -}; - -static struct max14577_muic_irq muic_irqs[] = { - { MAX14577_IRQ_INT1_ADC, "muic-ADC" }, - { MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" }, - { MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" }, - { MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" }, - { MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" }, - { MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" }, - { MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" }, - { MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" }, -}; - /* Define supported accessory type */ enum max14577_muic_acc_type { MAX14577_MUIC_ADC_GROUND = 0x0, @@ -528,21 +543,12 @@ static void max14577_muic_irq_work(struct work_struct *work) return; } -static irqreturn_t max14577_muic_irq_handler(int irq, void *data) +/* + * Sets irq_adc or irq_chg in max14577_muic_info and returns 1. + * Returns 0 if irq_type does not match registered IRQ for this device type. + */ +static int max14577_parse_irq(struct max14577_muic_info *info, int irq_type) { - struct max14577_muic_info *info = data; - int i, irq_type = -1; - - /* - * We may be called multiple times for different nested IRQ-s. - * Including changes in INT1_ADC and INT2_CGHTYP at once. - * However we only need to know whether it was ADC, charger - * or both interrupts so decode IRQ and turn on proper flags. - */ - for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) - if (irq == muic_irqs[i].virq) - irq_type = muic_irqs[i].irq; - switch (irq_type) { case MAX14577_IRQ_INT1_ADC: case MAX14577_IRQ_INT1_ADCLOW: @@ -550,7 +556,7 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data) /* Handle all of accessory except for type of charger accessory */ info->irq_adc = true; - break; + return 1; case MAX14577_IRQ_INT2_CHGTYP: case MAX14577_IRQ_INT2_CHGDETRUN: case MAX14577_IRQ_INT2_DCDTMR: @@ -558,8 +564,62 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data) case MAX14577_IRQ_INT2_VBVOLT: /* Handle charger accessory */ info->irq_chg = true; + return 1; + default: + return 0; + } +} + +/* + * Sets irq_adc or irq_chg in max14577_muic_info and returns 1. + * Returns 0 if irq_type does not match registered IRQ for this device type. + */ +static int max77836_parse_irq(struct max14577_muic_info *info, int irq_type) +{ + /* First check common max14577 interrupts */ + if (max14577_parse_irq(info, irq_type)) + return 1; + + switch (irq_type) { + case MAX77836_IRQ_INT1_ADC1K: + info->irq_adc = true; + return 1; + case MAX77836_IRQ_INT2_VIDRM: + /* Handle charger accessory */ + info->irq_chg = true; + return 1; + default: + return 0; + } +} + +static irqreturn_t max14577_muic_irq_handler(int irq, void *data) +{ + struct max14577_muic_info *info = data; + int i, irq_type = -1; + bool irq_parsed; + + /* + * We may be called multiple times for different nested IRQ-s. + * Including changes in INT1_ADC and INT2_CGHTYP at once. + * However we only need to know whether it was ADC, charger + * or both interrupts so decode IRQ and turn on proper flags. + */ + for (i = 0; i < info->muic_irqs_num; i++) + if (irq == info->muic_irqs[i].virq) + irq_type = info->muic_irqs[i].irq; + + switch (info->max14577->dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + irq_parsed = max77836_parse_irq(info, irq_type); break; + case MAXIM_DEVICE_TYPE_MAX14577: default: + irq_parsed = max14577_parse_irq(info, irq_type); + break; + } + + if (!irq_parsed) { dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n", irq_type); return IRQ_HANDLED; @@ -644,9 +704,20 @@ static int max14577_muic_probe(struct platform_device *pdev) INIT_WORK(&info->irq_work, max14577_muic_irq_work); + switch (max14577->dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + info->muic_irqs = max77836_muic_irqs; + info->muic_irqs_num = ARRAY_SIZE(max77836_muic_irqs); + break; + case MAXIM_DEVICE_TYPE_MAX14577: + default: + info->muic_irqs = max14577_muic_irqs; + info->muic_irqs_num = ARRAY_SIZE(max14577_muic_irqs); + } + /* Support irq domain for max14577 MUIC device */ - for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) { - struct max14577_muic_irq *muic_irq = &muic_irqs[i]; + for (i = 0; i < info->muic_irqs_num; i++) { + struct max14577_muic_irq *muic_irq = &info->muic_irqs[i]; unsigned int virq = 0; virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq); @@ -673,7 +744,8 @@ static int max14577_muic_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); return -ENOMEM; } - info->edev->name = DEV_NAME; + + info->edev->name = dev_name(&pdev->dev); info->edev->supported_cable = max14577_extcon_cable; ret = extcon_dev_register(info->edev); if (ret) { @@ -735,18 +807,26 @@ static int max14577_muic_remove(struct platform_device *pdev) return 0; } +static const struct platform_device_id max14577_muic_id[] = { + { "max14577-muic", MAXIM_DEVICE_TYPE_MAX14577, }, + { "max77836-muic", MAXIM_DEVICE_TYPE_MAX77836, }, + { } +}; +MODULE_DEVICE_TABLE(platform, max14577_muic_id); + static struct platform_driver max14577_muic_driver = { .driver = { - .name = DEV_NAME, + .name = "max14577-muic", .owner = THIS_MODULE, }, .probe = max14577_muic_probe, .remove = max14577_muic_remove, + .id_table = max14577_muic_id, }; module_platform_driver(max14577_muic_driver); -MODULE_DESCRIPTION("MAXIM 14577 Extcon driver"); -MODULE_AUTHOR("Chanwoo Choi "); +MODULE_DESCRIPTION("Maxim 14577/77836 Extcon driver"); +MODULE_AUTHOR("Chanwoo Choi , Krzysztof Kozlowski "); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:extcon-max14577"); diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 8db66321956068..995dd42a262731 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -3498,7 +3498,7 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base) } clear_bit_unlock(0, &ctx->flushing_completions); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } tasklet_enable(&ctx->context.tasklet); diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index 2c41eaece2c173..eb6d4be9e722ac 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -11,6 +11,10 @@ */ #define EFI_READ_CHUNK_SIZE (1024 * 1024) +/* error code which can't be mistaken for valid address */ +#define EFI_ERROR (~0UL) + + struct file_info { efi_file_handle_t *handle; u64 size; @@ -33,6 +37,9 @@ static void efi_printk(efi_system_table_t *sys_table_arg, char *str) } } +#define pr_efi(sys_table, msg) efi_printk(sys_table, "EFI stub: "msg) +#define pr_efi_err(sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg) + static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, efi_memory_desc_t **map, @@ -80,6 +87,32 @@ static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, return status; } + +static unsigned long __init get_dram_base(efi_system_table_t *sys_table_arg) +{ + efi_status_t status; + unsigned long map_size; + unsigned long membase = EFI_ERROR; + struct efi_memory_map map; + efi_memory_desc_t *md; + + status = efi_get_memory_map(sys_table_arg, (efi_memory_desc_t **)&map.map, + &map_size, &map.desc_size, NULL, NULL); + if (status != EFI_SUCCESS) + return membase; + + map.map_end = map.map + map_size; + + for_each_efi_memory_desc(&map, md) + if (md->attribute & EFI_MEMORY_WB) + if (membase > md->phys_addr) + membase = md->phys_addr; + + efi_call_early(free_pool, map.map); + + return membase; +} + /* * Allocate at the highest possible address that is not above 'max'. */ @@ -267,7 +300,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, struct file_info *files; unsigned long file_addr; u64 file_size_total; - efi_file_handle_t *fh; + efi_file_handle_t *fh = NULL; efi_status_t status; int nr_files; char *str; @@ -310,7 +343,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, status = efi_call_early(allocate_pool, EFI_LOADER_DATA, nr_files * sizeof(*files), (void **)&files); if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n"); + pr_efi_err(sys_table_arg, "Failed to alloc mem for file handle list\n"); goto fail; } @@ -374,13 +407,13 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000, &file_addr, max_addr); if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "Failed to alloc highmem for files\n"); + pr_efi_err(sys_table_arg, "Failed to alloc highmem for files\n"); goto close_handles; } /* We've run out of free low memory. */ if (file_addr > max_addr) { - efi_printk(sys_table_arg, "We've run out of free low memory\n"); + pr_efi_err(sys_table_arg, "We've run out of free low memory\n"); status = EFI_INVALID_PARAMETER; goto free_file_total; } @@ -401,7 +434,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, &chunksize, (void *)addr); if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "Failed to read file\n"); + pr_efi_err(sys_table_arg, "Failed to read file\n"); goto free_file_total; } addr += chunksize; @@ -486,7 +519,7 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, &new_addr); } if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n"); + pr_efi_err(sys_table_arg, "Failed to allocate usable memory for kernel.\n"); return status; } @@ -502,63 +535,100 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, return status; } +/* + * Get the number of UTF-8 bytes corresponding to an UTF-16 character. + * This overestimates for surrogates, but that is okay. + */ +static int efi_utf8_bytes(u16 c) +{ + return 1 + (c >= 0x80) + (c >= 0x800); +} + +/* + * Convert an UTF-16 string, not necessarily null terminated, to UTF-8. + */ +static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n) +{ + unsigned int c; + + while (n--) { + c = *src++; + if (n && c >= 0xd800 && c <= 0xdbff && + *src >= 0xdc00 && *src <= 0xdfff) { + c = 0x10000 + ((c & 0x3ff) << 10) + (*src & 0x3ff); + src++; + n--; + } + if (c >= 0xd800 && c <= 0xdfff) + c = 0xfffd; /* Unmatched surrogate */ + if (c < 0x80) { + *dst++ = c; + continue; + } + if (c < 0x800) { + *dst++ = 0xc0 + (c >> 6); + goto t1; + } + if (c < 0x10000) { + *dst++ = 0xe0 + (c >> 12); + goto t2; + } + *dst++ = 0xf0 + (c >> 18); + *dst++ = 0x80 + ((c >> 12) & 0x3f); + t2: + *dst++ = 0x80 + ((c >> 6) & 0x3f); + t1: + *dst++ = 0x80 + (c & 0x3f); + } + + return dst; +} + /* * Convert the unicode UEFI command line to ASCII to pass to kernel. * Size of memory allocated return in *cmd_line_len. * Returns NULL on error. */ -static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg, - efi_loaded_image_t *image, - int *cmd_line_len) +static char *efi_convert_cmdline(efi_system_table_t *sys_table_arg, + efi_loaded_image_t *image, + int *cmd_line_len) { - u16 *s2; + const u16 *s2; u8 *s1 = NULL; unsigned long cmdline_addr = 0; - int load_options_size = image->load_options_size / 2; /* ASCII */ - void *options = image->load_options; - int options_size = 0; + int load_options_chars = image->load_options_size / 2; /* UTF-16 */ + const u16 *options = image->load_options; + int options_bytes = 0; /* UTF-8 bytes */ + int options_chars = 0; /* UTF-16 chars */ efi_status_t status; - int i; u16 zero = 0; if (options) { s2 = options; - while (*s2 && *s2 != '\n' && options_size < load_options_size) { - s2++; - options_size++; + while (*s2 && *s2 != '\n' + && options_chars < load_options_chars) { + options_bytes += efi_utf8_bytes(*s2++); + options_chars++; } } - if (options_size == 0) { + if (!options_chars) { /* No command line options, so return empty string*/ - options_size = 1; options = &zero; } - options_size++; /* NUL termination */ -#ifdef CONFIG_ARM - /* - * For ARM, allocate at a high address to avoid reserved - * regions at low addresses that we don't know the specfics of - * at the time we are processing the command line. - */ - status = efi_high_alloc(sys_table_arg, options_size, 0, - &cmdline_addr, 0xfffff000); -#else - status = efi_low_alloc(sys_table_arg, options_size, 0, - &cmdline_addr); -#endif + options_bytes++; /* NUL termination */ + + status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr); if (status != EFI_SUCCESS) return NULL; s1 = (u8 *)cmdline_addr; - s2 = (u16 *)options; - - for (i = 0; i < options_size - 1; i++) - *s1++ = *s2++; + s2 = (const u16 *)options; + s1 = efi_utf16_to_utf8(s1, s2, options_chars); *s1 = '\0'; - *cmd_line_len = options_size; + *cmd_line_len = options_bytes; return (char *)cmdline_addr; } diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index 50ea412a25e640..463c56545ae80a 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -69,6 +69,7 @@ #include #include #include +#include #define EFIVARS_VERSION "0.08" #define EFIVARS_DATE "2004-May-17" @@ -86,6 +87,15 @@ static struct kset *efivars_kset; static struct bin_attribute *efivars_new_var; static struct bin_attribute *efivars_del_var; +struct compat_efi_variable { + efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)]; + efi_guid_t VendorGuid; + __u32 DataSize; + __u8 Data[1024]; + __u32 Status; + __u32 Attributes; +} __packed; + struct efivar_attribute { struct attribute attr; ssize_t (*show) (struct efivar_entry *entry, char *buf); @@ -189,45 +199,107 @@ efivar_data_read(struct efivar_entry *entry, char *buf) memcpy(buf, var->Data, var->DataSize); return var->DataSize; } -/* - * We allow each variable to be edited via rewriting the - * entire efi variable structure. - */ -static ssize_t -efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) -{ - struct efi_variable *new_var, *var = &entry->var; - int err; - if (count != sizeof(struct efi_variable)) - return -EINVAL; - - new_var = (struct efi_variable *)buf; +static inline int +sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor, + unsigned long size, u32 attributes, u8 *data) +{ /* * If only updating the variable data, then the name * and guid should remain the same */ - if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) || - efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) { + if (memcmp(name, var->VariableName, sizeof(var->VariableName)) || + efi_guidcmp(vendor, var->VendorGuid)) { printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n"); return -EINVAL; } - if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){ + if ((size <= 0) || (attributes == 0)){ printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n"); return -EINVAL; } - if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || - efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { + if ((attributes & ~EFI_VARIABLE_MASK) != 0 || + efivar_validate(name, data, size) == false) { printk(KERN_ERR "efivars: Malformed variable content\n"); return -EINVAL; } - memcpy(&entry->var, new_var, count); + return 0; +} + +static inline bool is_compat(void) +{ + if (IS_ENABLED(CONFIG_COMPAT) && is_compat_task()) + return true; + + return false; +} + +static void +copy_out_compat(struct efi_variable *dst, struct compat_efi_variable *src) +{ + memcpy(dst->VariableName, src->VariableName, EFI_VAR_NAME_LEN); + memcpy(dst->Data, src->Data, sizeof(src->Data)); + + dst->VendorGuid = src->VendorGuid; + dst->DataSize = src->DataSize; + dst->Attributes = src->Attributes; +} + +/* + * We allow each variable to be edited via rewriting the + * entire efi variable structure. + */ +static ssize_t +efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) +{ + struct efi_variable *new_var, *var = &entry->var; + efi_char16_t *name; + unsigned long size; + efi_guid_t vendor; + u32 attributes; + u8 *data; + int err; + + if (is_compat()) { + struct compat_efi_variable *compat; + + if (count != sizeof(*compat)) + return -EINVAL; + + compat = (struct compat_efi_variable *)buf; + attributes = compat->Attributes; + vendor = compat->VendorGuid; + name = compat->VariableName; + size = compat->DataSize; + data = compat->Data; + + err = sanity_check(var, name, vendor, size, attributes, data); + if (err) + return err; + + copy_out_compat(&entry->var, compat); + } else { + if (count != sizeof(struct efi_variable)) + return -EINVAL; + + new_var = (struct efi_variable *)buf; - err = efivar_entry_set(entry, new_var->Attributes, - new_var->DataSize, new_var->Data, NULL); + attributes = new_var->Attributes; + vendor = new_var->VendorGuid; + name = new_var->VariableName; + size = new_var->DataSize; + data = new_var->Data; + + err = sanity_check(var, name, vendor, size, attributes, data); + if (err) + return err; + + memcpy(&entry->var, new_var, count); + } + + err = efivar_entry_set(entry, attributes, size, data, NULL); if (err) { printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err); return -EIO; @@ -240,6 +312,8 @@ static ssize_t efivar_show_raw(struct efivar_entry *entry, char *buf) { struct efi_variable *var = &entry->var; + struct compat_efi_variable *compat; + size_t size; if (!entry || !buf) return 0; @@ -249,9 +323,23 @@ efivar_show_raw(struct efivar_entry *entry, char *buf) &entry->var.DataSize, entry->var.Data)) return -EIO; - memcpy(buf, var, sizeof(*var)); + if (is_compat()) { + compat = (struct compat_efi_variable *)buf; + + size = sizeof(*compat); + memcpy(compat->VariableName, var->VariableName, + EFI_VAR_NAME_LEN); + memcpy(compat->Data, var->Data, sizeof(compat->Data)); + + compat->VendorGuid = var->VendorGuid; + compat->DataSize = var->DataSize; + compat->Attributes = var->Attributes; + } else { + size = sizeof(*var); + memcpy(buf, var, size); + } - return sizeof(*var); + return size; } /* @@ -326,15 +414,39 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t count) { + struct compat_efi_variable *compat = (struct compat_efi_variable *)buf; struct efi_variable *new_var = (struct efi_variable *)buf; struct efivar_entry *new_entry; + bool need_compat = is_compat(); + efi_char16_t *name; + unsigned long size; + u32 attributes; + u8 *data; int err; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || - efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { + if (need_compat) { + if (count != sizeof(*compat)) + return -EINVAL; + + attributes = compat->Attributes; + name = compat->VariableName; + size = compat->DataSize; + data = compat->Data; + } else { + if (count != sizeof(*new_var)) + return -EINVAL; + + attributes = new_var->Attributes; + name = new_var->VariableName; + size = new_var->DataSize; + data = new_var->Data; + } + + if ((attributes & ~EFI_VARIABLE_MASK) != 0 || + efivar_validate(name, data, size) == false) { printk(KERN_ERR "efivars: Malformed variable content\n"); return -EINVAL; } @@ -343,10 +455,13 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, if (!new_entry) return -ENOMEM; - memcpy(&new_entry->var, new_var, sizeof(*new_var)); + if (need_compat) + copy_out_compat(&new_entry->var, compat); + else + memcpy(&new_entry->var, new_var, sizeof(*new_var)); - err = efivar_entry_set(new_entry, new_var->Attributes, new_var->DataSize, - new_var->Data, &efivar_sysfs_list); + err = efivar_entry_set(new_entry, attributes, size, + data, &efivar_sysfs_list); if (err) { if (err == -EEXIST) err = -EINVAL; @@ -369,15 +484,32 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, char *buf, loff_t pos, size_t count) { struct efi_variable *del_var = (struct efi_variable *)buf; + struct compat_efi_variable *compat; struct efivar_entry *entry; + efi_char16_t *name; + efi_guid_t vendor; int err = 0; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (is_compat()) { + if (count != sizeof(*compat)) + return -EINVAL; + + compat = (struct compat_efi_variable *)buf; + name = compat->VariableName; + vendor = compat->VendorGuid; + } else { + if (count != sizeof(*del_var)) + return -EINVAL; + + name = del_var->VariableName; + vendor = del_var->VendorGuid; + } + efivar_entry_iter_begin(); - entry = efivar_entry_find(del_var->VariableName, del_var->VendorGuid, - &efivar_sysfs_list, true); + entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true); if (!entry) err = -EINVAL; else if (__efivar_entry_delete(entry)) diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index b22659cccca42e..f0a43646a2f3f4 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -42,7 +42,7 @@ DECLARE_WORK(efivar_work, NULL); EXPORT_SYMBOL_GPL(efivar_work); static bool -validate_device_path(struct efi_variable *var, int match, u8 *buffer, +validate_device_path(efi_char16_t *var_name, int match, u8 *buffer, unsigned long len) { struct efi_generic_dev_path *node; @@ -75,7 +75,7 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer, } static bool -validate_boot_order(struct efi_variable *var, int match, u8 *buffer, +validate_boot_order(efi_char16_t *var_name, int match, u8 *buffer, unsigned long len) { /* An array of 16-bit integers */ @@ -86,18 +86,18 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer, } static bool -validate_load_option(struct efi_variable *var, int match, u8 *buffer, +validate_load_option(efi_char16_t *var_name, int match, u8 *buffer, unsigned long len) { u16 filepathlength; int i, desclength = 0, namelen; - namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName)); + namelen = ucs2_strnlen(var_name, EFI_VAR_NAME_LEN); /* Either "Boot" or "Driver" followed by four digits of hex */ for (i = match; i < match+4; i++) { - if (var->VariableName[i] > 127 || - hex_to_bin(var->VariableName[i] & 0xff) < 0) + if (var_name[i] > 127 || + hex_to_bin(var_name[i] & 0xff) < 0) return true; } @@ -132,12 +132,12 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, /* * And, finally, check the filepath */ - return validate_device_path(var, match, buffer + desclength + 6, + return validate_device_path(var_name, match, buffer + desclength + 6, filepathlength); } static bool -validate_uint16(struct efi_variable *var, int match, u8 *buffer, +validate_uint16(efi_char16_t *var_name, int match, u8 *buffer, unsigned long len) { /* A single 16-bit integer */ @@ -148,7 +148,7 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer, } static bool -validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, +validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer, unsigned long len) { int i; @@ -166,7 +166,7 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, struct variable_validate { char *name; - bool (*validate)(struct efi_variable *var, int match, u8 *data, + bool (*validate)(efi_char16_t *var_name, int match, u8 *data, unsigned long len); }; @@ -189,10 +189,10 @@ static const struct variable_validate variable_validate[] = { }; bool -efivar_validate(struct efi_variable *var, u8 *data, unsigned long len) +efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len) { int i; - u16 *unicode_name = var->VariableName; + u16 *unicode_name = var_name; for (i = 0; variable_validate[i].validate != NULL; i++) { const char *name = variable_validate[i].name; @@ -208,7 +208,7 @@ efivar_validate(struct efi_variable *var, u8 *data, unsigned long len) /* Wildcard in the matching name means we've matched */ if (c == '*') - return variable_validate[i].validate(var, + return variable_validate[i].validate(var_name, match, data, len); /* Case sensitive match */ @@ -217,7 +217,7 @@ efivar_validate(struct efi_variable *var, u8 *data, unsigned long len) /* Reached the end of the string while matching */ if (!c) - return variable_validate[i].validate(var, + return variable_validate[i].validate(var_name, match, data, len); } } @@ -805,7 +805,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, *set = false; - if (efivar_validate(&entry->var, data, *size) == false) + if (efivar_validate(name, data, *size) == false) return -EINVAL; /* diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index a86c49a605c636..c58b828e882f7a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -243,6 +243,14 @@ config GPIO_OCTEON Say yes here to support the on-chip GPIO lines on the OCTEON family of SOCs. +config GPIO_OMAP + bool "TI OMAP GPIO support" + default y if ARCH_OMAP + depends on ARM && ARCH_OMAP + select GPIOLIB_IRQCHIP + help + Say yes here to enable GPIO support for TI OMAP SoCs. + config GPIO_PL061 bool "PrimeCell PL061 GPIO support" depends on ARM_AMBA @@ -579,6 +587,7 @@ config GPIO_STP_XWAY config GPIO_TC3589X bool "TC3589X GPIOs" depends on MFD_TC3589X + select GPIOLIB_IRQCHIP help This enables support for the GPIOs found on the TC3589X I/O Expander. @@ -739,7 +748,7 @@ config GPIO_SODAVILLE config GPIO_TIMBERDALE bool "Support for timberdale GPIO IP" - depends on MFD_TIMBERDALE && HAS_IOMEM + depends on MFD_TIMBERDALE ---help--- Add support for the GPIO IP in the timberdale FPGA. diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 6309aff1d806be..d10f6a9d875a2b 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o -obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o +obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index ed5711f77e2d05..4d25a06bb45ee1 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -260,9 +260,6 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, ct->regs.ack = GPIO_PORTA_EOI; ct->regs.mask = GPIO_INTMASK; - irq_setup_generic_chip(irq_gc, IRQ_MSK(port->bgc.gc.ngpio), - IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); - irq_set_chained_handler(irq, dwapb_irq_handler); irq_set_handler_data(irq, gpio); diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index 7b95a4a8318c2b..1237a73c3c911c 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -18,15 +18,9 @@ */ #include -#include -#include #include -#include #include -#include #include -#include -#include #include #define GEF_GPIO_DIRECT 0x00 @@ -39,28 +33,26 @@ #define GEF_GPIO_OVERRUN 0x1C #define GEF_GPIO_MODE 0x20 -static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value) +static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); unsigned int data; - data = ioread32be(reg); - /* value: 0=low; 1=high */ - if (value & 0x1) - data = data | (0x1 << offset); + data = ioread32be(mmchip->regs + GEF_GPIO_OUT); + if (value) + data = data | BIT(offset); else - data = data & ~(0x1 << offset); - - iowrite32be(data, reg); + data = data & ~BIT(offset); + iowrite32be(data, mmchip->regs + GEF_GPIO_OUT); } - static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset) { unsigned int data; struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data | (0x1 << offset); + data = data | BIT(offset); iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); return 0; @@ -71,11 +63,11 @@ static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) unsigned int data; struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - /* Set direction before switching to input */ - _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); + /* Set value before switching to output */ + gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data & ~(0x1 << offset); + data = data & ~BIT(offset); iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); return 0; @@ -83,116 +75,56 @@ static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) static int gef_gpio_get(struct gpio_chip *chip, unsigned offset) { - unsigned int data; - int state = 0; struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - data = ioread32be(mmchip->regs + GEF_GPIO_IN); - state = (int)((data >> offset) & 0x1); - - return state; + return !!(ioread32be(mmchip->regs + GEF_GPIO_IN) & BIT(offset)); } -static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); -} +static const struct of_device_id gef_gpio_ids[] = { + { + .compatible = "gef,sbc610-gpio", + .data = (void *)19, + }, { + .compatible = "gef,sbc310-gpio", + .data = (void *)6, + }, { + .compatible = "ge,imp3a-gpio", + .data = (void *)16, + }, + { } +}; +MODULE_DEVICE_TABLE(of, gef_gpio_ids); -static int __init gef_gpio_init(void) +static int __init gef_gpio_probe(struct platform_device *pdev) { - struct device_node *np; - int retval; - struct of_mm_gpio_chip *gef_gpio_chip; - - for_each_compatible_node(np, NULL, "gef,sbc610-gpio") { - - pr_debug("%s: Initialising GEF GPIO\n", np->full_name); - - /* Allocate chip structure */ - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); - if (!gef_gpio_chip) { - pr_err("%s: Unable to allocate structure\n", - np->full_name); - continue; - } - - /* Setup pointers to chip functions */ - gef_gpio_chip->gc.of_gpio_n_cells = 2; - gef_gpio_chip->gc.ngpio = 19; - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->gc.get = gef_gpio_get; - gef_gpio_chip->gc.set = gef_gpio_set; - - /* This function adds a memory mapped GPIO chip */ - retval = of_mm_gpiochip_add(np, gef_gpio_chip); - if (retval) { - kfree(gef_gpio_chip); - pr_err("%s: Unable to add GPIO\n", np->full_name); - } - } - - for_each_compatible_node(np, NULL, "gef,sbc310-gpio") { - - pr_debug("%s: Initialising GEF GPIO\n", np->full_name); - - /* Allocate chip structure */ - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); - if (!gef_gpio_chip) { - pr_err("%s: Unable to allocate structure\n", - np->full_name); - continue; - } - - /* Setup pointers to chip functions */ - gef_gpio_chip->gc.of_gpio_n_cells = 2; - gef_gpio_chip->gc.ngpio = 6; - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->gc.get = gef_gpio_get; - gef_gpio_chip->gc.set = gef_gpio_set; - - /* This function adds a memory mapped GPIO chip */ - retval = of_mm_gpiochip_add(np, gef_gpio_chip); - if (retval) { - kfree(gef_gpio_chip); - pr_err("%s: Unable to add GPIO\n", np->full_name); - } - } - - for_each_compatible_node(np, NULL, "ge,imp3a-gpio") { - - pr_debug("%s: Initialising GE GPIO\n", np->full_name); - - /* Allocate chip structure */ - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); - if (!gef_gpio_chip) { - pr_err("%s: Unable to allocate structure\n", - np->full_name); - continue; - } - - /* Setup pointers to chip functions */ - gef_gpio_chip->gc.of_gpio_n_cells = 2; - gef_gpio_chip->gc.ngpio = 16; - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->gc.get = gef_gpio_get; - gef_gpio_chip->gc.set = gef_gpio_set; - - /* This function adds a memory mapped GPIO chip */ - retval = of_mm_gpiochip_add(np, gef_gpio_chip); - if (retval) { - kfree(gef_gpio_chip); - pr_err("%s: Unable to add GPIO\n", np->full_name); - } - } + const struct of_device_id *of_id = + of_match_device(gef_gpio_ids, &pdev->dev); + struct of_mm_gpio_chip *mmchip; + + mmchip = devm_kzalloc(&pdev->dev, sizeof(*mmchip), GFP_KERNEL); + if (!mmchip) + return -ENOMEM; + + /* Setup pointers to chip functions */ + mmchip->gc.ngpio = (u16)(uintptr_t)of_id->data; + mmchip->gc.of_gpio_n_cells = 2; + mmchip->gc.direction_input = gef_gpio_dir_in; + mmchip->gc.direction_output = gef_gpio_dir_out; + mmchip->gc.get = gef_gpio_get; + mmchip->gc.set = gef_gpio_set; + + /* This function adds a memory mapped GPIO chip */ + return of_mm_gpiochip_add(pdev->dev.of_node, mmchip); +}; - return 0; +static struct platform_driver gef_gpio_driver = { + .driver = { + .name = "gef-gpio", + .owner = THIS_MODULE, + .of_match_table = gef_gpio_ids, + }, }; -arch_initcall(gef_gpio_init); +module_platform_driver_probe(gef_gpio_driver, gef_gpio_probe); MODULE_DESCRIPTION("GE I/O FPGA GPIO driver"); MODULE_AUTHOR("Martyn Welch "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:gpio-kempld"); +MODULE_ALIAS("platform:kempld-gpio"); diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index 8672755f95c915..0814584fcdc1e1 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -237,10 +237,9 @@ int __max730x_remove(struct device *dev) ts->write(dev, 0x04, 0x00); ret = gpiochip_remove(&ts->chip); - if (!ret) { + if (!ret) mutex_destroy(&ts->lock); - kfree(ts); - } else + else dev_err(dev, "Failed to remove GPIO controller: %d\n", ret); return ret; diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 99a68310e7c09e..3d53fd6880d197 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -894,9 +894,11 @@ static int mcp23s08_probe(struct spi_device *spi) dev_err(&spi->dev, "invalid spi-present-mask\n"); return -ENODEV; } - - for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) + for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { + if ((spi_present_mask & (1 << addr))) + chips++; pullups[addr] = 0; + } } else { type = spi_get_device_id(spi)->driver_data; pdata = dev_get_platdata(&spi->dev); @@ -919,12 +921,12 @@ static int mcp23s08_probe(struct spi_device *spi) pullups[addr] = pdata->chip[addr].pullups; } - if (!chips) - return -ENODEV; - base = pdata->base; } + if (!chips) + return -ENODEV; + data = kzalloc(sizeof(*data) + chips * sizeof(struct mcp23s08), GFP_KERNEL); if (!data) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 19b886c21b1dbe..47c6056fe85001 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -24,9 +24,9 @@ #include #include #include -#include #include #include +#include #include #define OFF_MODE 1 @@ -52,7 +52,6 @@ struct gpio_bank { struct list_head node; void __iomem *base; u16 irq; - struct irq_domain *domain; u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; struct gpio_regs context; @@ -95,11 +94,10 @@ static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq) return bank->chip.base + gpio_irq; } -static int omap_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +static inline struct gpio_bank *_irq_data_get_bank(struct irq_data *d) { - struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); - - return irq_find_mapping(bank->domain, offset); + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + return container_of(chip, struct gpio_bank, chip); } static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) @@ -479,7 +477,7 @@ static int gpio_is_input(struct gpio_bank *bank, int mask) static int gpio_irq_type(struct irq_data *d, unsigned type) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned gpio = 0; int retval; unsigned long flags; @@ -514,14 +512,6 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) return -EINVAL; } - retval = gpio_lock_as_irq(&bank->chip, offset); - if (retval) { - dev_err(bank->dev, "unable to lock offset %d for IRQ\n", - offset); - spin_unlock_irqrestore(&bank->lock, flags); - return retval; - } - bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio); spin_unlock_irqrestore(&bank->lock, flags); @@ -664,7 +654,7 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio) /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ static int gpio_wake_enable(struct irq_data *d, unsigned int enable) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); return _set_gpio_wakeup(bank, gpio, enable); @@ -732,11 +722,12 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) unsigned int bit; struct gpio_bank *bank; int unmasked = 0; - struct irq_chip *chip = irq_desc_get_chip(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + struct gpio_chip *chip = irq_get_handler_data(irq); - chained_irq_enter(chip, desc); + chained_irq_enter(irqchip, desc); - bank = irq_get_handler_data(irq); + bank = container_of(chip, struct gpio_bank, chip); isr_reg = bank->base + bank->regs->irqstatus; pm_runtime_get_sync(bank->dev); @@ -764,7 +755,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) configured, we could unmask GPIO bank interrupt immediately */ if (!level_mask && !unmasked) { unmasked = 1; - chained_irq_exit(chip, desc); + chained_irq_exit(irqchip, desc); } if (!isr) @@ -784,7 +775,8 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) if (bank->toggle_mask & (1 << bit)) _toggle_gpio_edge_triggering(bank, bit); - generic_handle_irq(irq_find_mapping(bank->domain, bit)); + generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, + bit)); } } /* if bank has any level sensitive GPIO pin interrupt @@ -793,13 +785,13 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) interrupt */ exit: if (!unmasked) - chained_irq_exit(chip, desc); + chained_irq_exit(irqchip, desc); pm_runtime_put(bank->dev); } static void gpio_irq_shutdown(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned long flags; unsigned offset = GPIO_INDEX(bank, gpio); @@ -821,7 +813,7 @@ static void gpio_irq_shutdown(struct irq_data *d) static void gpio_ack_irq(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); _clear_gpio_irqstatus(bank, gpio); @@ -829,7 +821,7 @@ static void gpio_ack_irq(struct irq_data *d) static void gpio_mask_irq(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned long flags; @@ -841,7 +833,7 @@ static void gpio_mask_irq(struct irq_data *d) static void gpio_unmask_irq(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned int irq_mask = GPIO_BIT(bank, gpio); u32 trigger = irqd_get_trigger_type(d); @@ -936,6 +928,21 @@ static inline void mpuio_init(struct gpio_bank *bank) /*---------------------------------------------------------------------*/ +static int gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_bank *bank; + unsigned long flags; + void __iomem *reg; + int dir; + + bank = container_of(chip, struct gpio_bank, chip); + reg = bank->base + bank->regs->direction; + spin_lock_irqsave(&bank->lock, flags); + dir = !!(readl_relaxed(reg) & BIT(offset)); + spin_unlock_irqrestore(&bank->lock, flags); + return dir; +} + static int gpio_input(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank; @@ -1081,10 +1088,12 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, IRQ_NOREQUEST | IRQ_NOPROBE, 0); } -static void omap_gpio_chip_init(struct gpio_bank *bank) +static int omap_gpio_chip_init(struct gpio_bank *bank) { int j; static int gpio; + int irq_base = 0; + int ret; /* * REVISIT eventually switch from OMAP-specific gpio structs @@ -1092,12 +1101,12 @@ static void omap_gpio_chip_init(struct gpio_bank *bank) */ bank->chip.request = omap_gpio_request; bank->chip.free = omap_gpio_free; + bank->chip.get_direction = gpio_get_direction; bank->chip.direction_input = gpio_input; bank->chip.get = gpio_get; bank->chip.direction_output = gpio_output; bank->chip.set_debounce = gpio_debounce; bank->chip.set = gpio_set; - bank->chip.to_irq = omap_gpio_to_irq; if (bank->is_mpuio) { bank->chip.label = "mpuio"; if (bank->regs->wkup_en) @@ -1110,22 +1119,48 @@ static void omap_gpio_chip_init(struct gpio_bank *bank) } bank->chip.ngpio = bank->width; - gpiochip_add(&bank->chip); + ret = gpiochip_add(&bank->chip); + if (ret) { + dev_err(bank->dev, "Could not register gpio chip %d\n", ret); + return ret; + } + +#ifdef CONFIG_ARCH_OMAP1 + /* + * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop + * irq_alloc_descs() since a base IRQ offset will no longer be needed. + */ + irq_base = irq_alloc_descs(-1, 0, bank->width, 0); + if (irq_base < 0) { + dev_err(bank->dev, "Couldn't allocate IRQ numbers\n"); + return -ENODEV; + } +#endif + + ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip, + irq_base, gpio_irq_handler, + IRQ_TYPE_NONE); + + if (ret) { + dev_err(bank->dev, "Couldn't add irqchip to gpiochip %d\n", ret); + ret = gpiochip_remove(&bank->chip); + return -ENODEV; + } + + gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip, + bank->irq, gpio_irq_handler); for (j = 0; j < bank->width; j++) { - int irq = irq_create_mapping(bank->domain, j); + int irq = irq_find_mapping(bank->chip.irqdomain, j); irq_set_lockdep_class(irq, &gpio_lock_class); - irq_set_chip_data(irq, bank); if (bank->is_mpuio) { omap_mpuio_alloc_gc(bank, irq, bank->width); - } else { - irq_set_chip_and_handler(irq, &gpio_irq_chip, - handle_simple_irq); - set_irq_flags(irq, IRQF_VALID); + irq_set_chip_and_handler(irq, NULL, NULL); + set_irq_flags(irq, 0); } } - irq_set_chained_handler(bank->irq, gpio_irq_handler); - irq_set_handler_data(bank->irq, bank); + + return 0; } static const struct of_device_id omap_gpio_match[]; @@ -1138,9 +1173,7 @@ static int omap_gpio_probe(struct platform_device *pdev) const struct omap_gpio_platform_data *pdata; struct resource *res; struct gpio_bank *bank; -#ifdef CONFIG_ARCH_OMAP1 - int irq_base; -#endif + int ret; match = of_match_device(of_match_ptr(omap_gpio_match), dev); @@ -1162,6 +1195,7 @@ static int omap_gpio_probe(struct platform_device *pdev) bank->irq = res->start; bank->dev = dev; + bank->chip.dev = dev; bank->dbck_flag = pdata->dbck_flag; bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; @@ -1182,29 +1216,6 @@ static int omap_gpio_probe(struct platform_device *pdev) pdata->get_context_loss_count; } -#ifdef CONFIG_ARCH_OMAP1 - /* - * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop - * irq_alloc_descs() and irq_domain_add_legacy() and just use a - * linear IRQ domain mapping for all OMAP platforms. - */ - irq_base = irq_alloc_descs(-1, 0, bank->width, 0); - if (irq_base < 0) { - dev_err(dev, "Couldn't allocate IRQ numbers\n"); - return -ENODEV; - } - - bank->domain = irq_domain_add_legacy(node, bank->width, irq_base, - 0, &irq_domain_simple_ops, NULL); -#else - bank->domain = irq_domain_add_linear(node, bank->width, - &irq_domain_simple_ops, NULL); -#endif - if (!bank->domain) { - dev_err(dev, "Couldn't register an IRQ domain\n"); - return -ENODEV; - } - if (bank->regs->set_dataout && bank->regs->clr_dataout) bank->set_dataout = _set_gpio_dataout_reg; else @@ -1216,7 +1227,7 @@ static int omap_gpio_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); bank->base = devm_ioremap_resource(dev, res); if (IS_ERR(bank->base)) { - irq_domain_remove(bank->domain); + irq_domain_remove(bank->chip.irqdomain); return PTR_ERR(bank->base); } @@ -1230,7 +1241,11 @@ static int omap_gpio_probe(struct platform_device *pdev) mpuio_init(bank); omap_gpio_mod_init(bank); - omap_gpio_chip_init(bank); + + ret = omap_gpio_chip_init(bank); + if (ret) + return ret; + omap_gpio_show_rev(bank); pm_runtime_put(bank->dev); diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index b0f475243cef68..84553d35bdfafd 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 03c91482432cfb..bfcfeeefcf78f0 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -377,6 +378,9 @@ static int gpio_rcar_probe(struct platform_device *pdev) platform_set_drvdata(pdev, p); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + io = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -460,6 +464,8 @@ static int gpio_rcar_probe(struct platform_device *pdev) err1: irq_domain_remove(p->irq_domain); err0: + pm_runtime_put(dev); + pm_runtime_disable(dev); return ret; } @@ -473,6 +479,8 @@ static int gpio_rcar_remove(struct platform_device *pdev) return ret; irq_domain_remove(p->irq_domain); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); return 0; } diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c index 88577c3272a553..7a319e5138a595 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/gpio-rdc321x.c @@ -141,7 +141,8 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) return -ENODEV; } - rdc321x_gpio_dev = kzalloc(sizeof(struct rdc321x_gpio), GFP_KERNEL); + rdc321x_gpio_dev = devm_kzalloc(&pdev->dev, sizeof(struct rdc321x_gpio), + GFP_KERNEL); if (!rdc321x_gpio_dev) { dev_err(&pdev->dev, "failed to allocate private data\n"); return -ENOMEM; @@ -150,8 +151,7 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg1"); if (!r) { dev_err(&pdev->dev, "failed to get gpio-reg1 resource\n"); - err = -ENODEV; - goto out_free; + return -ENODEV; } spin_lock_init(&rdc321x_gpio_dev->lock); @@ -162,8 +162,7 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg2"); if (!r) { dev_err(&pdev->dev, "failed to get gpio-reg2 resource\n"); - err = -ENODEV; - goto out_free; + return -ENODEV; } rdc321x_gpio_dev->reg2_ctrl_base = r->start; @@ -187,21 +186,17 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) rdc321x_gpio_dev->reg1_data_base, &rdc321x_gpio_dev->data_reg[0]); if (err) - goto out_free; + return err; err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev, rdc321x_gpio_dev->reg2_data_base, &rdc321x_gpio_dev->data_reg[1]); if (err) - goto out_free; + return err; dev_info(&pdev->dev, "registering %d GPIOs\n", rdc321x_gpio_dev->chip.ngpio); return gpiochip_add(&rdc321x_gpio_dev->chip); - -out_free: - kfree(rdc321x_gpio_dev); - return err; } static int rdc321x_gpio_remove(struct platform_device *pdev) @@ -213,8 +208,6 @@ static int rdc321x_gpio_remove(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "failed to unregister chip\n"); - kfree(rdc321x_gpio_dev); - return ret; } diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 5af65719b95daf..a9b1cd16c84831 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -97,8 +97,6 @@ static int sch_gpio_core_direction_out(struct gpio_chip *gc, u8 curr_dirs; unsigned short offset, bit; - sch_gpio_core_set(gc, gpio_num, val); - spin_lock(&gpio_lock); offset = CGIO + gpio_num / 8; @@ -109,6 +107,17 @@ static int sch_gpio_core_direction_out(struct gpio_chip *gc, outb(curr_dirs & ~(1 << bit), gpio_ba + offset); spin_unlock(&gpio_lock); + + /* + * according to the datasheet, writing to the level register has no + * effect when GPIO is programmed as input. + * Actually the the level register is read-only when configured as input. + * Thus presetting the output level before switching to output is _NOT_ possible. + * Hence we set the level after configuring the GPIO as output. + * But we cannot prevent a short low pulse if direction is set to high + * and an external pull-up is connected. + */ + sch_gpio_core_set(gc, gpio_num, val); return 0; } @@ -178,8 +187,6 @@ static int sch_gpio_resume_direction_out(struct gpio_chip *gc, u8 curr_dirs; unsigned short offset, bit; - sch_gpio_resume_set(gc, gpio_num, val); - offset = RGIO + gpio_num / 8; bit = gpio_num % 8; @@ -190,6 +197,17 @@ static int sch_gpio_resume_direction_out(struct gpio_chip *gc, outb(curr_dirs & ~(1 << bit), gpio_ba + offset); spin_unlock(&gpio_lock); + + /* + * according to the datasheet, writing to the level register has no + * effect when GPIO is programmed as input. + * Actually the the level register is read-only when configured as input. + * Thus presetting the output level before switching to output is _NOT_ possible. + * Hence we set the level after configuring the GPIO as output. + * But we cannot prevent a short low pulse if direction is set to high + * and an external pull-up is connected. + */ + sch_gpio_resume_set(gc, gpio_num, val); return 0; } diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c index 0357387b364532..f942b80ee403fb 100644 --- a/drivers/gpio/gpio-sch311x.c +++ b/drivers/gpio/gpio-sch311x.c @@ -327,14 +327,22 @@ static int __init sch311x_detect(int sio_config_port, unsigned short *addr) if (err) return err; - /* Check device ID. We currently know about: - * SCH3112 (0x7c), SCH3114 (0x7d), and SCH3116 (0x7f). */ + /* Check device ID. */ reg = sch311x_sio_inb(sio_config_port, 0x20); - if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) { + switch (reg) { + case 0x7c: /* SCH3112 */ + dev_id = 2; + break; + case 0x7d: /* SCH3114 */ + dev_id = 4; + break; + case 0x7f: /* SCH3116 */ + dev_id = 6; + break; + default: err = -ENODEV; goto exit; } - dev_id = reg == 0x7c ? 2 : reg == 0x7d ? 4 : 6; /* Select logical device A (runtime registers) */ sch311x_sio_outb(sio_config_port, 0x07, 0x0a); diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index 13d73fb2b5e1a2..b51ca9f5c14018 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #define NO_UPDATE_PENDING -1 diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 1019320984d778..51f7cbd9ff713c 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -12,8 +12,6 @@ #include #include #include -#include -#include #include #include @@ -31,10 +29,6 @@ struct tc3589x_gpio { struct tc3589x *tc3589x; struct device *dev; struct mutex irq_lock; - struct irq_domain *domain; - - int irq_base; - /* Caches of interrupt control registers for bus_lock */ u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; @@ -95,30 +89,6 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip, return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0); } -/** - * tc3589x_gpio_irq_get_irq(): Map a hardware IRQ on a chip to a Linux IRQ - * - * @tc3589x_gpio: tc3589x_gpio_irq controller to operate on. - * @irq: index of the hardware interrupt requested in the chip IRQs - * - * Useful for drivers to request their own IRQs. - */ -static int tc3589x_gpio_irq_get_irq(struct tc3589x_gpio *tc3589x_gpio, - int hwirq) -{ - if (!tc3589x_gpio) - return -EINVAL; - - return irq_create_mapping(tc3589x_gpio->domain, hwirq); -} - -static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); - - return tc3589x_gpio_irq_get_irq(tc3589x_gpio, offset); -} - static struct gpio_chip template_chip = { .label = "tc3589x", .owner = THIS_MODULE, @@ -126,13 +96,13 @@ static struct gpio_chip template_chip = { .get = tc3589x_gpio_get, .direction_output = tc3589x_gpio_direction_output, .set = tc3589x_gpio_set, - .to_irq = tc3589x_gpio_to_irq, .can_sleep = true, }; static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -159,14 +129,16 @@ static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void tc3589x_gpio_irq_lock(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); mutex_lock(&tc3589x_gpio->irq_lock); } static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; static const u8 regmap[] = { [REG_IBE] = TC3589x_GPIOIBE0, @@ -194,7 +166,8 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) static void tc3589x_gpio_irq_mask(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -204,7 +177,8 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d) static void tc3589x_gpio_irq_unmask(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -242,7 +216,8 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = i * 8 + bit; - int irq = tc3589x_gpio_irq_get_irq(tc3589x_gpio, line); + int irq = irq_find_mapping(tc3589x_gpio->chip.irqdomain, + line); handle_nested_irq(irq); stat &= ~(1 << bit); @@ -254,61 +229,6 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct tc3589x *tc3589x_gpio = d->host_data; - - irq_set_chip_data(irq, tc3589x_gpio); - irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, - handle_simple_irq); - irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - - return 0; -} - -static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) -{ -#ifdef CONFIG_ARM - set_irq_flags(irq, 0); -#endif - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); -} - -static struct irq_domain_ops tc3589x_irq_ops = { - .map = tc3589x_gpio_irq_map, - .unmap = tc3589x_gpio_irq_unmap, - .xlate = irq_domain_xlate_twocell, -}; - -static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio, - struct device_node *np) -{ - int base = tc3589x_gpio->irq_base; - - /* - * If this results in a linear domain, irq_create_mapping() will - * take care of allocating IRQ descriptors at runtime. When a base - * is provided, the IRQ descriptors will be allocated when the - * domain is instantiated. - */ - tc3589x_gpio->domain = irq_domain_add_simple(np, - tc3589x_gpio->chip.ngpio, base, &tc3589x_irq_ops, - tc3589x_gpio); - if (!tc3589x_gpio->domain) { - dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n"); - return -ENOSYS; - } - - return 0; -} - static int tc3589x_gpio_probe(struct platform_device *pdev) { struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); @@ -329,7 +249,8 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) if (irq < 0) return irq; - tc3589x_gpio = kzalloc(sizeof(struct tc3589x_gpio), GFP_KERNEL); + tc3589x_gpio = devm_kzalloc(&pdev->dev, sizeof(struct tc3589x_gpio), + GFP_KERNEL); if (!tc3589x_gpio) return -ENOMEM; @@ -347,30 +268,36 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) tc3589x_gpio->chip.of_node = np; #endif - tc3589x_gpio->irq_base = tc3589x->irq_base ? - tc3589x->irq_base + TC3589x_INT_GPIO(0) : 0; - /* Bring the GPIO module out of reset */ ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_RSTCTRL_GPIRST, 0); if (ret < 0) - goto out_free; - - ret = tc3589x_gpio_irq_init(tc3589x_gpio, np); - if (ret) - goto out_free; + return ret; - ret = request_threaded_irq(irq, NULL, tc3589x_gpio_irq, IRQF_ONESHOT, - "tc3589x-gpio", tc3589x_gpio); + ret = devm_request_threaded_irq(&pdev->dev, + irq, NULL, tc3589x_gpio_irq, + IRQF_ONESHOT, "tc3589x-gpio", + tc3589x_gpio); if (ret) { dev_err(&pdev->dev, "unable to get irq: %d\n", ret); - goto out_free; + return ret; } ret = gpiochip_add(&tc3589x_gpio->chip); if (ret) { dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); - goto out_freeirq; + return ret; + } + + ret = gpiochip_irqchip_add(&tc3589x_gpio->chip, + &tc3589x_gpio_irq_chip, + 0, + handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(&pdev->dev, + "could not connect irqchip to gpiochip\n"); + return ret; } if (pdata && pdata->setup) @@ -379,12 +306,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tc3589x_gpio); return 0; - -out_freeirq: - free_irq(irq, tc3589x_gpio); -out_free: - kfree(tc3589x_gpio); - return ret; } static int tc3589x_gpio_remove(struct platform_device *pdev) @@ -392,7 +313,6 @@ static int tc3589x_gpio_remove(struct platform_device *pdev) struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio; - int irq = platform_get_irq(pdev, 0); int ret; if (pdata && pdata->remove) @@ -405,10 +325,6 @@ static int tc3589x_gpio_remove(struct platform_device *pdev) return ret; } - free_irq(irq, tc3589x_gpio); - - kfree(tc3589x_gpio); - return 0; } diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index 9bf5034b6cdb61..6270f755d0ed3d 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -81,9 +81,15 @@ static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin, static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin) { struct zevio_gpio *controller = to_zevio_gpio(chip); + u32 val, dir; - /* Only reading allowed, so no spinlock needed */ - u32 val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT); + spin_lock(&controller->lock); + dir = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); + if (dir & BIT(ZEVIO_GPIO_BIT(pin))) + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT); + else + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); + spin_unlock(&controller->lock); return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1; } @@ -209,7 +215,7 @@ static struct platform_driver zevio_gpio_driver = { .driver = { .name = "gpio-zevio", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(zevio_gpio_of_match), + .of_match_table = zevio_gpio_of_match, }, .probe = zevio_gpio_probe, }; diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 2024d45e550362..db98d3a12f707a 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -48,7 +48,7 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) if (ret < 0) return false; - gg_data->out_gpio = gpio_to_desc(ret + gc->base); + gg_data->out_gpio = gpiochip_get_desc(gc, ret); return true; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f48817d974802c..86eb0467fc5a12 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1363,6 +1363,11 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, int parent_irq, irq_flow_handler_t parent_handler) { + if (gpiochip->can_sleep) { + chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n"); + return; + } + irq_set_chained_handler(parent_irq, parent_handler); /* * The parent irqchip is already using the chip_data for this @@ -1372,6 +1377,12 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, } EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); +/* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpiochip_irq_lock_class; + /** * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip * @d: the irqdomain used by this irqchip @@ -1388,22 +1399,35 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, struct gpio_chip *chip = d->host_data; irq_set_chip_data(irq, chip); + irq_set_lockdep_class(irq, &gpiochip_irq_lock_class); irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); + /* Chips that can sleep need nested thread handlers */ + if (chip->can_sleep) + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else irq_set_noprobe(irq); #endif - irq_set_irq_type(irq, chip->irq_default_type); + /* + * No set-up of the hardware will happen if IRQ_TYPE_NONE + * is passed as default type. + */ + if (chip->irq_default_type != IRQ_TYPE_NONE) + irq_set_irq_type(irq, chip->irq_default_type); return 0; } static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq) { + struct gpio_chip *chip = d->host_data; + #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif + if (chip->can_sleep) + irq_set_nested_thread(irq, 0); irq_set_chip_and_handler(irq, NULL, NULL); irq_set_chip_data(irq, NULL); } @@ -1471,7 +1495,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) * @first_irq: if not dynamically assigned, the base (first) IRQ to * allocate gpiochip irqs from * @handler: the irq handler to use (often a predefined irq core function) - * @type: the default type for IRQs on this irqchip + * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE + * to have the core avoid setting up any default type in the hardware. * * This function closely associates a certain irqchip with a certain * gpiochip, providing an irq domain to translate the local IRQs to @@ -2571,22 +2596,27 @@ void gpiod_add_lookup_table(struct gpiod_lookup_table *table) mutex_unlock(&gpio_lookup_lock); } -#ifdef CONFIG_OF static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) { + static const char *suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ enum of_gpio_flags of_flags; struct gpio_desc *desc; + unsigned int i; - if (con_id) - snprintf(prop_name, 32, "%s-gpios", con_id); - else - snprintf(prop_name, 32, "gpios"); + for (i = 0; i < ARRAY_SIZE(suffixes); i++) { + if (con_id) + snprintf(prop_name, 32, "%s-%s", con_id, suffixes[i]); + else + snprintf(prop_name, 32, "%s", suffixes[i]); - desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, - &of_flags); + desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, + &of_flags); + if (!IS_ERR(desc)) + break; + } if (IS_ERR(desc)) return desc; @@ -2596,14 +2626,6 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, return desc; } -#else -static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, - unsigned int idx, - enum gpio_lookup_flags *flags) -{ - return ERR_PTR(-ENODEV); -} -#endif static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, unsigned int idx, diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 32982da82694be..567cfbde0883df 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -173,7 +173,7 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto err_kms; - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); if (ret) goto err_kms; diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 5137f15dba19e7..2ba39ac7d22211 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -198,7 +198,6 @@ static const struct file_operations ast_fops = { static struct drm_driver driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM, - .dev_priv_size = 0, .load = ast_driver_load, .unload = ast_driver_unload, diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 50535fd5a88d25..01bf9e730acf60 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -411,16 +411,13 @@ static void ast_bo_unref(struct ast_bo **bo) tbo = &((*bo)->bo); ttm_bo_unref(&tbo); - if (tbo == NULL) - *bo = NULL; - + *bo = NULL; } + void ast_gem_free_object(struct drm_gem_object *obj) { struct ast_bo *ast_bo = gem_to_ast_bo(obj); - if (!ast_bo) - return; ast_bo_unref(&ast_bo); } diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index f488be55d650e3..b9a695d92792ee 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -434,17 +434,13 @@ static void bochs_bo_unref(struct bochs_bo **bo) tbo = &((*bo)->bo); ttm_bo_unref(&tbo); - if (tbo == NULL) - *bo = NULL; - + *bo = NULL; } void bochs_gem_free_object(struct drm_gem_object *obj) { struct bochs_bo *bochs_bo = gem_to_bochs_bo(obj); - if (!bochs_bo) - return; bochs_bo_unref(&bochs_bo); } diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index 4b0170cf53fd92..99c1983f99d228 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -264,17 +264,13 @@ static void cirrus_bo_unref(struct cirrus_bo **bo) tbo = &((*bo)->bo); ttm_bo_unref(&tbo); - if (tbo == NULL) - *bo = NULL; - + *bo = NULL; } void cirrus_gem_free_object(struct drm_gem_object *obj) { struct cirrus_bo *cirrus_bo = gem_to_cirrus_bo(obj); - if (!cirrus_bo) - return; cirrus_bo_unref(&cirrus_bo); } diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index edec31fe3fed86..ef7f0199a0f1e5 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -656,13 +656,13 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request) DRM_DEBUG("zone invalid\n"); return -EINVAL; } - spin_lock(&dev->count_lock); + spin_lock(&dev->buf_lock); if (dev->buf_use) { - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); return -EBUSY; } atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); mutex_lock(&dev->struct_mutex); entry = &dma->bufs[order]; @@ -805,13 +805,13 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; total = PAGE_SIZE << page_order; - spin_lock(&dev->count_lock); + spin_lock(&dev->buf_lock); if (dev->buf_use) { - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); return -EBUSY; } atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); mutex_lock(&dev->struct_mutex); entry = &dma->bufs[order]; @@ -1015,13 +1015,13 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; - spin_lock(&dev->count_lock); + spin_lock(&dev->buf_lock); if (dev->buf_use) { - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); return -EBUSY; } atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); mutex_lock(&dev->struct_mutex); entry = &dma->bufs[order]; @@ -1175,7 +1175,7 @@ int drm_addbufs(struct drm_device *dev, void *data, * \param arg pointer to a drm_buf_info structure. * \return zero on success or a negative number on failure. * - * Increments drm_device::buf_use while holding the drm_device::count_lock + * Increments drm_device::buf_use while holding the drm_device::buf_lock * lock, preventing of allocating more buffers after this call. Information * about each requested buffer is then copied into user space. */ @@ -1196,13 +1196,13 @@ int drm_infobufs(struct drm_device *dev, void *data, if (!dma) return -EINVAL; - spin_lock(&dev->count_lock); + spin_lock(&dev->buf_lock); if (atomic_read(&dev->buf_alloc)) { - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); return -EBUSY; } ++dev->buf_use; /* Can't allocate more after this call */ - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { if (dma->bufs[i].buf_count) @@ -1381,13 +1381,13 @@ int drm_mapbufs(struct drm_device *dev, void *data, if (!dma) return -EINVAL; - spin_lock(&dev->count_lock); + spin_lock(&dev->buf_lock); if (atomic_read(&dev->buf_alloc)) { - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); return -EBUSY; } dev->buf_use++; /* Can't allocate more after this call */ - spin_unlock(&dev->count_lock); + spin_unlock(&dev->buf_lock); if (request->count >= dma->buf_count) { if ((dev->agp && (dma->flags & _DRM_DMA_USE_AGP)) diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index 534cb89b160d68..ae251b8abd0ec0 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -131,11 +131,11 @@ drm_clflush_sg(struct sg_table *st) EXPORT_SYMBOL(drm_clflush_sg); void -drm_clflush_virt_range(char *addr, unsigned long length) +drm_clflush_virt_range(void *addr, unsigned long length) { #if defined(CONFIG_X86) if (cpu_has_clflush) { - char *end = addr + length; + void *end = addr + length; mb(); for (; addr < end; addr += boot_cpu_data.x86_clflush_size) clflush(addr); diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index 7473035dd28b78..86feedd5e6f696 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c @@ -47,18 +47,16 @@ int drm_name_info(struct seq_file *m, void *data) struct drm_minor *minor = node->minor; struct drm_device *dev = minor->dev; struct drm_master *master = minor->master; - const char *bus_name; if (!master) return 0; - bus_name = dev->driver->bus->get_name(dev); if (master->unique) { seq_printf(m, "%s %s %s\n", - bus_name, + dev->driver->name, dev_name(dev->dev), master->unique); } else { seq_printf(m, "%s %s\n", - bus_name, dev_name(dev->dev)); + dev->driver->name, dev_name(dev->dev)); } return 0; } diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 93a42040bedb38..38269d5aa33377 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -72,9 +72,6 @@ static void drm_unset_busid(struct drm_device *dev, struct drm_master *master) { - kfree(dev->devname); - dev->devname = NULL; - kfree(master->unique); master->unique = NULL; master->unique_len = 0; @@ -93,7 +90,8 @@ drm_unset_busid(struct drm_device *dev, * Copies the bus id from userspace into drm_device::unique, and verifies that * it matches the device this DRM is attached to (EINVAL otherwise). Deprecated * in interface version 1.1 and will return EBUSY when setversion has requested - * version 1.1 or greater. + * version 1.1 or greater. Also note that KMS is all version 1.1 and later and + * UMS was only ever supported on pci devices. */ int drm_setunique(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -108,10 +106,13 @@ int drm_setunique(struct drm_device *dev, void *data, if (!u->unique_len || u->unique_len > 1024) return -EINVAL; - if (!dev->driver->bus->set_unique) + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + if (WARN_ON(!dev->pdev)) return -EINVAL; - ret = dev->driver->bus->set_unique(dev, master, u); + ret = drm_pci_set_unique(dev, master, u); if (ret) goto err; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index c2676b5908d9f6..a0f2982bd4f4ad 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -56,33 +56,6 @@ */ #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 -/** - * Get interrupt from bus id. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument, pointing to a drm_irq_busid structure. - * \return zero on success or a negative number on failure. - * - * Finds the PCI device with the specified bus id and gets its IRQ number. - * This IOCTL is deprecated, and will now return EINVAL for any busid not equal - * to that of the device that this DRM instance attached to. - */ -int drm_irq_by_busid(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_irq_busid *p = data; - - if (!dev->driver->bus->irq_by_busid) - return -EINVAL; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) - return -EINVAL; - - return dev->driver->bus->irq_by_busid(dev, p); -} - /* * Clear vblank timestamp buffer for a crtc. */ @@ -156,7 +129,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) */ if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) { atomic_inc(&dev->vblank[crtc].count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } /* Invalidate all timestamps while vblank irq's are off. */ @@ -269,34 +242,26 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state) * \c irq_preinstall() and \c irq_postinstall() functions * before and after the installation. */ -int drm_irq_install(struct drm_device *dev) +int drm_irq_install(struct drm_device *dev, int irq) { int ret; unsigned long sh_flags = 0; - char *irqname; if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; - if (drm_dev_to_irq(dev) == 0) + if (irq == 0) return -EINVAL; - mutex_lock(&dev->struct_mutex); - /* Driver must have been initialized */ - if (!dev->dev_private) { - mutex_unlock(&dev->struct_mutex); + if (!dev->dev_private) return -EINVAL; - } - if (dev->irq_enabled) { - mutex_unlock(&dev->struct_mutex); + if (dev->irq_enabled) return -EBUSY; - } dev->irq_enabled = true; - mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); + DRM_DEBUG("irq=%d\n", irq); /* Before installing handler */ if (dev->driver->irq_preinstall) @@ -306,18 +271,11 @@ int drm_irq_install(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED)) sh_flags = IRQF_SHARED; - if (dev->devname) - irqname = dev->devname; - else - irqname = dev->driver->name; - - ret = request_irq(drm_dev_to_irq(dev), dev->driver->irq_handler, - sh_flags, irqname, dev); + ret = request_irq(irq, dev->driver->irq_handler, + sh_flags, dev->driver->name, dev); if (ret < 0) { - mutex_lock(&dev->struct_mutex); dev->irq_enabled = false; - mutex_unlock(&dev->struct_mutex); return ret; } @@ -329,12 +287,12 @@ int drm_irq_install(struct drm_device *dev) ret = dev->driver->irq_postinstall(dev); if (ret < 0) { - mutex_lock(&dev->struct_mutex); dev->irq_enabled = false; - mutex_unlock(&dev->struct_mutex); if (!drm_core_check_feature(dev, DRIVER_MODESET)) vga_client_register(dev->pdev, NULL, NULL, NULL); - free_irq(drm_dev_to_irq(dev), dev); + free_irq(irq, dev); + } else { + dev->irq = irq; } return ret; @@ -357,10 +315,8 @@ int drm_irq_uninstall(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; - mutex_lock(&dev->struct_mutex); irq_enabled = dev->irq_enabled; dev->irq_enabled = false; - mutex_unlock(&dev->struct_mutex); /* * Wake up any waiters so they don't hang. @@ -379,7 +335,7 @@ int drm_irq_uninstall(struct drm_device *dev) if (!irq_enabled) return -EINVAL; - DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); + DRM_DEBUG("irq=%d\n", dev->irq); if (!drm_core_check_feature(dev, DRIVER_MODESET)) vga_client_register(dev->pdev, NULL, NULL, NULL); @@ -387,7 +343,7 @@ int drm_irq_uninstall(struct drm_device *dev) if (dev->driver->irq_uninstall) dev->driver->irq_uninstall(dev); - free_irq(drm_dev_to_irq(dev), dev); + free_irq(dev->irq, dev); return 0; } @@ -408,28 +364,38 @@ int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_control *ctl = data; + int ret = 0, irq; /* if we haven't irq we fallback for compatibility reasons - * this used to be a separate function in drm_dma.h */ + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + /* UMS was only ever support on pci devices. */ + if (WARN_ON(!dev->pdev)) + return -EINVAL; switch (ctl->func) { case DRM_INST_HANDLER: - if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) - return 0; - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return 0; + irq = dev->pdev->irq; + if (dev->if_version < DRM_IF_VERSION(1, 2) && - ctl->irq != drm_dev_to_irq(dev)) + ctl->irq != irq) return -EINVAL; - return drm_irq_install(dev); + mutex_lock(&dev->struct_mutex); + ret = drm_irq_install(dev, irq); + mutex_unlock(&dev->struct_mutex); + + return ret; case DRM_UNINST_HANDLER: - if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) - return 0; - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return 0; - return drm_irq_uninstall(dev); + mutex_lock(&dev->struct_mutex); + ret = drm_irq_uninstall(dev); + mutex_unlock(&dev->struct_mutex); + + return ret; default: return -EINVAL; } @@ -864,9 +830,9 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) vblanktimestamp(dev, crtc, tslot) = t_vblank; } - smp_mb__before_atomic_inc(); + smp_mb__before_atomic(); atomic_add(diff, &dev->vblank[crtc].count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } /** @@ -1160,9 +1126,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, int ret; unsigned int flags, seq, crtc, high_crtc; - if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) - if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled)) - return -EINVAL; + if (!dev->irq_enabled) + return -EINVAL; if (vblwait->request.type & _DRM_VBLANK_SIGNAL) return -EINVAL; @@ -1330,9 +1295,9 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) /* Increment cooked vblank count. This also atomically commits * the timestamp computed above. */ - smp_mb__before_atomic_inc(); + smp_mb__before_atomic(); atomic_inc(&dev->vblank[crtc].count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } else { DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", crtc, (int) diff_ns); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 8b410576fce4b4..bedf1894e17e5f 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1013,6 +1013,7 @@ EXPORT_SYMBOL(drm_mode_sort); /** * drm_mode_connector_list_update - update the mode list for the connector * @connector: the connector to update + * @merge_type_bits: whether to merge or overright type bits. * * This moves the modes from the @connector probed_modes list * to the actual mode list. It compares the probed mode against the current @@ -1021,7 +1022,8 @@ EXPORT_SYMBOL(drm_mode_sort); * This is just a helper functions doesn't validate any modes itself and also * doesn't prune any invalid modes. Callers need to do that themselves. */ -void drm_mode_connector_list_update(struct drm_connector *connector) +void drm_mode_connector_list_update(struct drm_connector *connector, + bool merge_type_bits) { struct drm_display_mode *mode; struct drm_display_mode *pmode, *pt; @@ -1039,7 +1041,10 @@ void drm_mode_connector_list_update(struct drm_connector *connector) /* if equal delete the probed mode */ mode->status = pmode->status; /* Merge type bits together */ - mode->type |= pmode->type; + if (merge_type_bits) + mode->type |= pmode->type; + else + mode->type = pmode->type; list_del(&pmode->head); drm_mode_destroy(connector->dev, pmode); break; diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 9c696a5ad74de2..d237de36a07a97 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -137,21 +137,9 @@ static int drm_get_pci_domain(struct drm_device *dev) return pci_domain_nr(dev->pdev->bus); } -static int drm_pci_get_irq(struct drm_device *dev) -{ - return dev->pdev->irq; -} - -static const char *drm_pci_get_name(struct drm_device *dev) -{ - struct pci_driver *pdriver = dev->driver->kdriver.pci; - return pdriver->name; -} - static int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) { int len, ret; - struct pci_driver *pdriver = dev->driver->kdriver.pci; master->unique_len = 40; master->unique_size = master->unique_len; master->unique = kmalloc(master->unique_size, GFP_KERNEL); @@ -173,29 +161,16 @@ static int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) } else master->unique_len = len; - dev->devname = - kmalloc(strlen(pdriver->name) + - master->unique_len + 2, GFP_KERNEL); - - if (dev->devname == NULL) { - ret = -ENOMEM; - goto err; - } - - sprintf(dev->devname, "%s@%s", pdriver->name, - master->unique); - return 0; err: return ret; } -static int drm_pci_set_unique(struct drm_device *dev, - struct drm_master *master, - struct drm_unique *u) +int drm_pci_set_unique(struct drm_device *dev, + struct drm_master *master, + struct drm_unique *u) { int domain, bus, slot, func, ret; - const char *bus_name; master->unique_len = u->unique_len; master->unique_size = u->unique_len + 1; @@ -212,17 +187,6 @@ static int drm_pci_set_unique(struct drm_device *dev, master->unique[master->unique_len] = '\0'; - bus_name = dev->driver->bus->get_name(dev); - dev->devname = kmalloc(strlen(bus_name) + - strlen(master->unique) + 2, GFP_KERNEL); - if (!dev->devname) { - ret = -ENOMEM; - goto err; - } - - sprintf(dev->devname, "%s@%s", bus_name, - master->unique); - /* Return error if the busid submitted doesn't match the device's actual * busid. */ @@ -247,7 +211,6 @@ static int drm_pci_set_unique(struct drm_device *dev, return ret; } - static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) { if ((p->busnum >> 8) != drm_get_pci_domain(dev) || @@ -262,6 +225,37 @@ static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) return 0; } +/** + * Get interrupt from bus id. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument, pointing to a drm_irq_busid structure. + * \return zero on success or a negative number on failure. + * + * Finds the PCI device with the specified bus id and gets its IRQ number. + * This IOCTL is deprecated, and will now return EINVAL for any busid not equal + * to that of the device that this DRM instance attached to. + */ +int drm_irq_by_busid(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_irq_busid *p = data; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + /* UMS was only ever support on PCI devices. */ + if (WARN_ON(!dev->pdev)) + return -EINVAL; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return -EINVAL; + + return drm_pci_irq_by_busid(dev, p); +} + static void drm_pci_agp_init(struct drm_device *dev) { if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { @@ -287,12 +281,7 @@ void drm_pci_agp_destroy(struct drm_device *dev) } static struct drm_bus drm_pci_bus = { - .bus_type = DRIVER_BUS_PCI, - .get_irq = drm_pci_get_irq, - .get_name = drm_pci_get_name, .set_busid = drm_pci_set_busid, - .set_unique = drm_pci_set_unique, - .irq_by_busid = drm_pci_irq_by_busid, }; /** @@ -375,7 +364,6 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver) DRM_DEBUG("\n"); - driver->kdriver.pci = pdriver; driver->bus = &drm_pci_bus; if (driver->driver_features & DRIVER_MODESET) @@ -453,6 +441,19 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver) } void drm_pci_agp_destroy(struct drm_device *dev) {} + +int drm_irq_by_busid(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return -EINVAL; +} + +int drm_pci_set_unique(struct drm_device *dev, + struct drm_master *master, + struct drm_unique *u) +{ + return -EINVAL; +} #endif EXPORT_SYMBOL(drm_pci_init); diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 319ff538560119..234e0bc1ae5109 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -68,16 +68,6 @@ static int drm_get_platform_dev(struct platform_device *platdev, return ret; } -static int drm_platform_get_irq(struct drm_device *dev) -{ - return platform_get_irq(dev->platformdev, 0); -} - -static const char *drm_platform_get_name(struct drm_device *dev) -{ - return dev->platformdev->name; -} - static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *master) { int len, ret, id; @@ -106,26 +96,12 @@ static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *mas goto err; } - dev->devname = - kmalloc(strlen(dev->platformdev->name) + - master->unique_len + 2, GFP_KERNEL); - - if (dev->devname == NULL) { - ret = -ENOMEM; - goto err; - } - - sprintf(dev->devname, "%s@%s", dev->platformdev->name, - master->unique); return 0; err: return ret; } static struct drm_bus drm_platform_bus = { - .bus_type = DRIVER_BUS_PLATFORM, - .get_irq = drm_platform_get_irq, - .get_name = drm_platform_get_name, .set_busid = drm_platform_set_busid, }; @@ -145,7 +121,6 @@ int drm_platform_init(struct drm_driver *driver, struct platform_device *platfor { DRM_DEBUG("\n"); - driver->kdriver.platform_device = platform_device; driver->bus = &drm_platform_bus; return drm_get_platform_dev(platform_device, driver); } diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index e70f54d4a5810c..8afdd0998a8c7f 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -82,26 +82,8 @@ static void drm_mode_validate_flag(struct drm_connector *connector, return; } -/** - * drm_helper_probe_single_connector_modes - get complete set of display modes - * @connector: connector to probe - * @maxX: max width for modes - * @maxY: max height for modes - * - * Based on the helper callbacks implemented by @connector try to detect all - * valid modes. Modes will first be added to the connector's probed_modes list, - * then culled (based on validity and the @maxX, @maxY parameters) and put into - * the normal modes list. - * - * Intended to be use as a generic implementation of the ->fill_modes() - * @connector vfunc for drivers that use the crtc helpers for output mode - * filtering and detection. - * - * Returns: - * The number of modes found on @connector. - */ -int drm_helper_probe_single_connector_modes(struct drm_connector *connector, - uint32_t maxX, uint32_t maxY) +static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector, + uint32_t maxX, uint32_t maxY, bool merge_type_bits) { struct drm_device *dev = connector->dev; struct drm_display_mode *mode; @@ -155,7 +137,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, if (count == 0) goto prune; - drm_mode_connector_list_update(connector); + drm_mode_connector_list_update(connector, merge_type_bits); if (maxX && maxY) drm_mode_validate_size(dev, &connector->modes, maxX, maxY); @@ -194,8 +176,48 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, return count; } + +/** + * drm_helper_probe_single_connector_modes - get complete set of display modes + * @connector: connector to probe + * @maxX: max width for modes + * @maxY: max height for modes + * + * Based on the helper callbacks implemented by @connector try to detect all + * valid modes. Modes will first be added to the connector's probed_modes list, + * then culled (based on validity and the @maxX, @maxY parameters) and put into + * the normal modes list. + * + * Intended to be use as a generic implementation of the ->fill_modes() + * @connector vfunc for drivers that use the crtc helpers for output mode + * filtering and detection. + * + * Returns: + * The number of modes found on @connector. + */ +int drm_helper_probe_single_connector_modes(struct drm_connector *connector, + uint32_t maxX, uint32_t maxY) +{ + return drm_helper_probe_single_connector_modes_merge_bits(connector, maxX, maxY, true); +} EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); +/** + * drm_helper_probe_single_connector_modes_nomerge - get complete set of display modes + * @connector: connector to probe + * @maxX: max width for modes + * @maxY: max height for modes + * + * This operates like drm_hehlper_probe_single_connector_modes except it + * replaces the mode bits instead of merging them for preferred modes. + */ +int drm_helper_probe_single_connector_modes_nomerge(struct drm_connector *connector, + uint32_t maxX, uint32_t maxY) +{ + return drm_helper_probe_single_connector_modes_merge_bits(connector, maxX, maxY, false); +} +EXPORT_SYMBOL(drm_helper_probe_single_connector_modes_nomerge); + /** * drm_kms_helper_hotplug_event - fire off KMS hotplug events * @dev: drm_device whose connector state changed diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 4c24c3ac1efaf2..1447b0ee367685 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -128,7 +128,10 @@ struct drm_master *drm_master_create(struct drm_minor *minor) kref_init(&master->refcount); spin_lock_init(&master->lock.spinlock); init_waitqueue_head(&master->lock.lock_queue); - drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER); + if (drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER)) { + kfree(master); + return NULL; + } INIT_LIST_HEAD(&master->magicfree); master->minor = minor; @@ -166,9 +169,6 @@ static void drm_master_destroy(struct kref *kref) master->unique_len = 0; } - kfree(dev->devname); - dev->devname = NULL; - list_for_each_entry_safe(pt, next, &master->magicfree, head) { list_del(&pt->head); drm_ht_remove_item(&master->magiclist, &pt->hash_item); @@ -569,7 +569,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, INIT_LIST_HEAD(&dev->maplist); INIT_LIST_HEAD(&dev->vblank_event_list); - spin_lock_init(&dev->count_lock); + spin_lock_init(&dev->buf_lock); spin_lock_init(&dev->event_lock); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); @@ -648,8 +648,6 @@ static void drm_dev_release(struct kref *ref) drm_minor_free(dev, DRM_MINOR_RENDER); drm_minor_free(dev, DRM_MINOR_CONTROL); - kfree(dev->devname); - mutex_destroy(&dev->master_mutex); kfree(dev); } diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c index c3406aad294463..c6c7c29ad46f43 100644 --- a/drivers/gpu/drm/drm_usb.c +++ b/drivers/gpu/drm/drm_usb.c @@ -36,16 +36,6 @@ int drm_get_usb_dev(struct usb_interface *interface, } EXPORT_SYMBOL(drm_get_usb_dev); -static int drm_usb_get_irq(struct drm_device *dev) -{ - return 0; -} - -static const char *drm_usb_get_name(struct drm_device *dev) -{ - return "USB"; -} - static int drm_usb_set_busid(struct drm_device *dev, struct drm_master *master) { @@ -53,9 +43,6 @@ static int drm_usb_set_busid(struct drm_device *dev, } static struct drm_bus drm_usb_bus = { - .bus_type = DRIVER_BUS_USB, - .get_irq = drm_usb_get_irq, - .get_name = drm_usb_get_name, .set_busid = drm_usb_set_busid, }; @@ -64,7 +51,6 @@ int drm_usb_init(struct drm_driver *driver, struct usb_driver *udriver) int res; DRM_DEBUG("\n"); - driver->kdriver.usb = udriver; driver->bus = &drm_usb_bus; res = usb_register(udriver); diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 09312b87747094..3d78144387ac6c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -284,7 +284,7 @@ static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id) /* * This case is search ipp driver by prop_id handle. * sometimes, ipp subsystem find driver by prop_id. - * e.g PAUSE state, queue buf, command contro. + * e.g PAUSE state, queue buf, command control. */ list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", count++, (int)ippdrv); diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index b686e56646ebd4..0a3101a3db19bb 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -354,7 +354,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags) PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R); spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); - drm_irq_install(dev); + drm_irq_install(dev, dev->pdev->irq); dev->vblank_disable_allowed = true; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 48af5cac1902bb..240c331405b92f 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -568,11 +568,11 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data) static uint8_t tda998x_cksum(uint8_t *buf, size_t bytes) { - uint8_t sum = 0; + int sum = 0; while (bytes--) - sum += *buf++; - return (255 - sum) + 1; + sum -= *buf++; + return sum; } #define HB(x) (x) diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index bea2d67196fb47..e4e3c01b8cbc66 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -71,7 +71,7 @@ config DRM_I915_PRELIMINARY_HW_SUPPORT config DRM_I915_UMS bool "Enable userspace modesetting on Intel hardware (DEPRECATED)" - depends on DRM_I915 + depends on DRM_I915 && BROKEN default n help Choose this option if you still need userspace modesetting. diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c index a0f5bdd694919a..80449f47596085 100644 --- a/drivers/gpu/drm/i915/dvo_ch7xxx.c +++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c @@ -160,7 +160,7 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) if (i2c_transfer(adapter, msgs, 2) == 2) { *ch = in_buf[0]; return true; - }; + } if (!ch7xxx->quiet) { DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n", diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c index 0f1865d7d4d841..0f2587ff347c95 100644 --- a/drivers/gpu/drm/i915/dvo_ivch.c +++ b/drivers/gpu/drm/i915/dvo_ivch.c @@ -195,7 +195,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) if (i2c_transfer(adapter, msgs, 3) == 3) { *data = (in_buf[1] << 8) | in_buf[0]; return true; - }; + } if (!priv->quiet) { DRM_DEBUG_KMS("Unable to read register 0x%02x from " diff --git a/drivers/gpu/drm/i915/dvo_ns2501.c b/drivers/gpu/drm/i915/dvo_ns2501.c index 8155ded79079df..74f2af7c2d3ed4 100644 --- a/drivers/gpu/drm/i915/dvo_ns2501.c +++ b/drivers/gpu/drm/i915/dvo_ns2501.c @@ -121,7 +121,7 @@ static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch) if (i2c_transfer(adapter, msgs, 2) == 2) { *ch = in_buf[0]; return true; - }; + } if (!ns->quiet) { DRM_DEBUG_KMS @@ -233,9 +233,8 @@ static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo, struct drm_display_mode *mode) { DRM_DEBUG_KMS - ("%s: is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n", - __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay, - mode->vtotal); + ("is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n", + mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal); /* * Currently, these are all the modes I have data from. @@ -261,9 +260,8 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo, struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); DRM_DEBUG_KMS - ("%s: set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n", - __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay, - mode->vtotal); + ("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n", + mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal); /* * Where do I find the native resolution for which scaling is not required??? @@ -277,8 +275,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo, if (mode->hdisplay == 800 && mode->vdisplay == 600) { /* mode 277 */ ns->reg_8_shadow &= ~NS2501_8_BPAS; - DRM_DEBUG_KMS("%s: switching to 800x600\n", - __FUNCTION__); + DRM_DEBUG_KMS("switching to 800x600\n"); /* * No, I do not know where this data comes from. @@ -341,8 +338,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo, } else if (mode->hdisplay == 640 && mode->vdisplay == 480) { /* mode 274 */ - DRM_DEBUG_KMS("%s: switching to 640x480\n", - __FUNCTION__); + DRM_DEBUG_KMS("switching to 640x480\n"); /* * No, I do not know where this data comes from. * It is just what the video bios left in the DVO, so @@ -406,8 +402,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo, } else if (mode->hdisplay == 1024 && mode->vdisplay == 768) { /* mode 280 */ - DRM_DEBUG_KMS("%s: switching to 1024x768\n", - __FUNCTION__); + DRM_DEBUG_KMS("switching to 1024x768\n"); /* * This might or might not work, actually. I'm silently * assuming here that the native panel resolution is @@ -458,8 +453,7 @@ static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable) struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); unsigned char ch; - DRM_DEBUG_KMS("%s: Trying set the dpms of the DVO to %i\n", - __FUNCTION__, enable); + DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable); ch = ns->reg_8_shadow; diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c index 7b3e9e93620034..fa011496707659 100644 --- a/drivers/gpu/drm/i915/dvo_sil164.c +++ b/drivers/gpu/drm/i915/dvo_sil164.c @@ -93,7 +93,7 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) if (i2c_transfer(adapter, msgs, 2) == 2) { *ch = in_buf[0]; return true; - }; + } if (!sil->quiet) { DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n", diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c index 12ea4b16469277..7853719a0e8132 100644 --- a/drivers/gpu/drm/i915/dvo_tfp410.c +++ b/drivers/gpu/drm/i915/dvo_tfp410.c @@ -118,7 +118,7 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) if (i2c_transfer(adapter, msgs, 2) == 2) { *ch = in_buf[0]; return true; - }; + } if (!tfp->quiet) { DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n", diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 4cf6d020d5135e..69d34e47d3bc22 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -28,7 +28,7 @@ #include "i915_drv.h" /** - * DOC: i915 batch buffer command parser + * DOC: batch buffer command parser * * Motivation: * Certain OpenGL features (e.g. transform feedback, performance monitoring) @@ -86,6 +86,367 @@ * general bitmasking mechanism. */ +#define STD_MI_OPCODE_MASK 0xFF800000 +#define STD_3D_OPCODE_MASK 0xFFFF0000 +#define STD_2D_OPCODE_MASK 0xFFC00000 +#define STD_MFX_OPCODE_MASK 0xFFFF0000 + +#define CMD(op, opm, f, lm, fl, ...) \ + { \ + .flags = (fl) | ((f) ? CMD_DESC_FIXED : 0), \ + .cmd = { (op), (opm) }, \ + .length = { (lm) }, \ + __VA_ARGS__ \ + } + +/* Convenience macros to compress the tables */ +#define SMI STD_MI_OPCODE_MASK +#define S3D STD_3D_OPCODE_MASK +#define S2D STD_2D_OPCODE_MASK +#define SMFX STD_MFX_OPCODE_MASK +#define F true +#define S CMD_DESC_SKIP +#define R CMD_DESC_REJECT +#define W CMD_DESC_REGISTER +#define B CMD_DESC_BITMASK +#define M CMD_DESC_MASTER + +/* Command Mask Fixed Len Action + ---------------------------------------------------------- */ +static const struct drm_i915_cmd_descriptor common_cmds[] = { + CMD( MI_NOOP, SMI, F, 1, S ), + CMD( MI_USER_INTERRUPT, SMI, F, 1, R ), + CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, M ), + CMD( MI_ARB_CHECK, SMI, F, 1, S ), + CMD( MI_REPORT_HEAD, SMI, F, 1, S ), + CMD( MI_SUSPEND_FLUSH, SMI, F, 1, S ), + CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, R ), + CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, R ), + CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W, + .reg = { .offset = 1, .mask = 0x007FFFFC } ), + CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W | B, + .reg = { .offset = 1, .mask = 0x007FFFFC }, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), + CMD( MI_LOAD_REGISTER_MEM, SMI, !F, 0xFF, W | B, + .reg = { .offset = 1, .mask = 0x007FFFFC }, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), + CMD( MI_BATCH_BUFFER_START, SMI, !F, 0xFF, S ), +}; + +static const struct drm_i915_cmd_descriptor render_cmds[] = { + CMD( MI_FLUSH, SMI, F, 1, S ), + CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), + CMD( MI_PREDICATE, SMI, F, 1, S ), + CMD( MI_TOPOLOGY_FILTER, SMI, F, 1, S ), + CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), + CMD( MI_SET_CONTEXT, SMI, !F, 0xFF, R ), + CMD( MI_URB_CLEAR, SMI, !F, 0xFF, S ), + CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3F, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), + CMD( MI_UPDATE_GTT, SMI, !F, 0xFF, R ), + CMD( MI_CLFLUSH, SMI, !F, 0x3FF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), + CMD( MI_REPORT_PERF_COUNT, SMI, !F, 0x3F, B, + .bits = {{ + .offset = 1, + .mask = MI_REPORT_PERF_COUNT_GGTT, + .expected = 0, + }}, ), + CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), + CMD( GFX_OP_3DSTATE_VF_STATISTICS, S3D, F, 1, S ), + CMD( PIPELINE_SELECT, S3D, F, 1, S ), + CMD( MEDIA_VFE_STATE, S3D, !F, 0xFFFF, B, + .bits = {{ + .offset = 2, + .mask = MEDIA_VFE_STATE_MMIO_ACCESS_MASK, + .expected = 0, + }}, ), + CMD( GPGPU_OBJECT, S3D, !F, 0xFF, S ), + CMD( GPGPU_WALKER, S3D, !F, 0xFF, S ), + CMD( GFX_OP_3DSTATE_SO_DECL_LIST, S3D, !F, 0x1FF, S ), + CMD( GFX_OP_PIPE_CONTROL(5), S3D, !F, 0xFF, B, + .bits = {{ + .offset = 1, + .mask = (PIPE_CONTROL_MMIO_WRITE | PIPE_CONTROL_NOTIFY), + .expected = 0, + }, + { + .offset = 1, + .mask = (PIPE_CONTROL_GLOBAL_GTT_IVB | + PIPE_CONTROL_STORE_DATA_INDEX), + .expected = 0, + .condition_offset = 1, + .condition_mask = PIPE_CONTROL_POST_SYNC_OP_MASK, + }}, ), +}; + +static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = { + CMD( MI_SET_PREDICATE, SMI, F, 1, S ), + CMD( MI_RS_CONTROL, SMI, F, 1, S ), + CMD( MI_URB_ATOMIC_ALLOC, SMI, F, 1, S ), + CMD( MI_RS_CONTEXT, SMI, F, 1, S ), + CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ), + CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ), + CMD( MI_LOAD_REGISTER_REG, SMI, !F, 0xFF, R ), + CMD( MI_RS_STORE_DATA_IMM, SMI, !F, 0xFF, S ), + CMD( MI_LOAD_URB_MEM, SMI, !F, 0xFF, S ), + CMD( MI_STORE_URB_MEM, SMI, !F, 0xFF, S ), + CMD( GFX_OP_3DSTATE_DX9_CONSTANTF_VS, S3D, !F, 0x7FF, S ), + CMD( GFX_OP_3DSTATE_DX9_CONSTANTF_PS, S3D, !F, 0x7FF, S ), + + CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_VS, S3D, !F, 0x1FF, S ), + CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_GS, S3D, !F, 0x1FF, S ), + CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_HS, S3D, !F, 0x1FF, S ), + CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_DS, S3D, !F, 0x1FF, S ), + CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_PS, S3D, !F, 0x1FF, S ), +}; + +static const struct drm_i915_cmd_descriptor video_cmds[] = { + CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), + CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), + CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), + CMD( MI_FLUSH_DW, SMI, !F, 0x3F, B, + .bits = {{ + .offset = 0, + .mask = MI_FLUSH_DW_NOTIFY, + .expected = 0, + }, + { + .offset = 1, + .mask = MI_FLUSH_DW_USE_GTT, + .expected = 0, + .condition_offset = 0, + .condition_mask = MI_FLUSH_DW_OP_MASK, + }, + { + .offset = 0, + .mask = MI_FLUSH_DW_STORE_INDEX, + .expected = 0, + .condition_offset = 0, + .condition_mask = MI_FLUSH_DW_OP_MASK, + }}, ), + CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), + /* + * MFX_WAIT doesn't fit the way we handle length for most commands. + * It has a length field but it uses a non-standard length bias. + * It is always 1 dword though, so just treat it as fixed length. + */ + CMD( MFX_WAIT, SMFX, F, 1, S ), +}; + +static const struct drm_i915_cmd_descriptor vecs_cmds[] = { + CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), + CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), + CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), + CMD( MI_FLUSH_DW, SMI, !F, 0x3F, B, + .bits = {{ + .offset = 0, + .mask = MI_FLUSH_DW_NOTIFY, + .expected = 0, + }, + { + .offset = 1, + .mask = MI_FLUSH_DW_USE_GTT, + .expected = 0, + .condition_offset = 0, + .condition_mask = MI_FLUSH_DW_OP_MASK, + }, + { + .offset = 0, + .mask = MI_FLUSH_DW_STORE_INDEX, + .expected = 0, + .condition_offset = 0, + .condition_mask = MI_FLUSH_DW_OP_MASK, + }}, ), + CMD( MI_CONDITIONAL_BATCH_BUFFER_END, SMI, !F, 0xFF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), +}; + +static const struct drm_i915_cmd_descriptor blt_cmds[] = { + CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), + CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3FF, B, + .bits = {{ + .offset = 0, + .mask = MI_GLOBAL_GTT, + .expected = 0, + }}, ), + CMD( MI_UPDATE_GTT, SMI, !F, 0x3F, R ), + CMD( MI_FLUSH_DW, SMI, !F, 0x3F, B, + .bits = {{ + .offset = 0, + .mask = MI_FLUSH_DW_NOTIFY, + .expected = 0, + }, + { + .offset = 1, + .mask = MI_FLUSH_DW_USE_GTT, + .expected = 0, + .condition_offset = 0, + .condition_mask = MI_FLUSH_DW_OP_MASK, + }, + { + .offset = 0, + .mask = MI_FLUSH_DW_STORE_INDEX, + .expected = 0, + .condition_offset = 0, + .condition_mask = MI_FLUSH_DW_OP_MASK, + }}, ), + CMD( COLOR_BLT, S2D, !F, 0x3F, S ), + CMD( SRC_COPY_BLT, S2D, !F, 0x3F, S ), +}; + +static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] = { + CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ), + CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ), +}; + +#undef CMD +#undef SMI +#undef S3D +#undef S2D +#undef SMFX +#undef F +#undef S +#undef R +#undef W +#undef B +#undef M + +static const struct drm_i915_cmd_table gen7_render_cmds[] = { + { common_cmds, ARRAY_SIZE(common_cmds) }, + { render_cmds, ARRAY_SIZE(render_cmds) }, +}; + +static const struct drm_i915_cmd_table hsw_render_ring_cmds[] = { + { common_cmds, ARRAY_SIZE(common_cmds) }, + { render_cmds, ARRAY_SIZE(render_cmds) }, + { hsw_render_cmds, ARRAY_SIZE(hsw_render_cmds) }, +}; + +static const struct drm_i915_cmd_table gen7_video_cmds[] = { + { common_cmds, ARRAY_SIZE(common_cmds) }, + { video_cmds, ARRAY_SIZE(video_cmds) }, +}; + +static const struct drm_i915_cmd_table hsw_vebox_cmds[] = { + { common_cmds, ARRAY_SIZE(common_cmds) }, + { vecs_cmds, ARRAY_SIZE(vecs_cmds) }, +}; + +static const struct drm_i915_cmd_table gen7_blt_cmds[] = { + { common_cmds, ARRAY_SIZE(common_cmds) }, + { blt_cmds, ARRAY_SIZE(blt_cmds) }, +}; + +static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = { + { common_cmds, ARRAY_SIZE(common_cmds) }, + { blt_cmds, ARRAY_SIZE(blt_cmds) }, + { hsw_blt_cmds, ARRAY_SIZE(hsw_blt_cmds) }, +}; + +/* + * Register whitelists, sorted by increasing register offset. + * + * Some registers that userspace accesses are 64 bits. The register + * access commands only allow 32-bit accesses. Hence, we have to include + * entries for both halves of the 64-bit registers. + */ + +/* Convenience macro for adding 64-bit registers */ +#define REG64(addr) (addr), (addr + sizeof(u32)) + +static const u32 gen7_render_regs[] = { + REG64(HS_INVOCATION_COUNT), + REG64(DS_INVOCATION_COUNT), + REG64(IA_VERTICES_COUNT), + REG64(IA_PRIMITIVES_COUNT), + REG64(VS_INVOCATION_COUNT), + REG64(GS_INVOCATION_COUNT), + REG64(GS_PRIMITIVES_COUNT), + REG64(CL_INVOCATION_COUNT), + REG64(CL_PRIMITIVES_COUNT), + REG64(PS_INVOCATION_COUNT), + REG64(PS_DEPTH_COUNT), + OACONTROL, /* Only allowed for LRI and SRM. See below. */ + GEN7_3DPRIM_END_OFFSET, + GEN7_3DPRIM_START_VERTEX, + GEN7_3DPRIM_VERTEX_COUNT, + GEN7_3DPRIM_INSTANCE_COUNT, + GEN7_3DPRIM_START_INSTANCE, + GEN7_3DPRIM_BASE_VERTEX, + REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), + REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), + REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), + REG64(GEN7_SO_NUM_PRIMS_WRITTEN(3)), + REG64(GEN7_SO_PRIM_STORAGE_NEEDED(0)), + REG64(GEN7_SO_PRIM_STORAGE_NEEDED(1)), + REG64(GEN7_SO_PRIM_STORAGE_NEEDED(2)), + REG64(GEN7_SO_PRIM_STORAGE_NEEDED(3)), + GEN7_SO_WRITE_OFFSET(0), + GEN7_SO_WRITE_OFFSET(1), + GEN7_SO_WRITE_OFFSET(2), + GEN7_SO_WRITE_OFFSET(3), +}; + +static const u32 gen7_blt_regs[] = { + BCS_SWCTRL, +}; + +static const u32 ivb_master_regs[] = { + FORCEWAKE_MT, + DERRMR, + GEN7_PIPE_DE_LOAD_SL(PIPE_A), + GEN7_PIPE_DE_LOAD_SL(PIPE_B), + GEN7_PIPE_DE_LOAD_SL(PIPE_C), +}; + +static const u32 hsw_master_regs[] = { + FORCEWAKE_MT, + DERRMR, +}; + +#undef REG64 + static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) { u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT; @@ -137,12 +498,13 @@ static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header) return 0; } -static void validate_cmds_sorted(struct intel_ring_buffer *ring) +static bool validate_cmds_sorted(struct intel_ring_buffer *ring) { int i; + bool ret = true; if (!ring->cmd_tables || ring->cmd_table_count == 0) - return; + return true; for (i = 0; i < ring->cmd_table_count; i++) { const struct drm_i915_cmd_table *table = &ring->cmd_tables[i]; @@ -154,35 +516,45 @@ static void validate_cmds_sorted(struct intel_ring_buffer *ring) &table->table[i]; u32 curr = desc->cmd.value & desc->cmd.mask; - if (curr < previous) + if (curr < previous) { DRM_ERROR("CMD: table not sorted ring=%d table=%d entry=%d cmd=0x%08X prev=0x%08X\n", ring->id, i, j, curr, previous); + ret = false; + } previous = curr; } } + + return ret; } -static void check_sorted(int ring_id, const u32 *reg_table, int reg_count) +static bool check_sorted(int ring_id, const u32 *reg_table, int reg_count) { int i; u32 previous = 0; + bool ret = true; for (i = 0; i < reg_count; i++) { u32 curr = reg_table[i]; - if (curr < previous) + if (curr < previous) { DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n", ring_id, i, curr, previous); + ret = false; + } previous = curr; } + + return ret; } -static void validate_regs_sorted(struct intel_ring_buffer *ring) +static bool validate_regs_sorted(struct intel_ring_buffer *ring) { - check_sorted(ring->id, ring->reg_table, ring->reg_count); - check_sorted(ring->id, ring->master_reg_table, ring->master_reg_count); + return check_sorted(ring->id, ring->reg_table, ring->reg_count) && + check_sorted(ring->id, ring->master_reg_table, + ring->master_reg_count); } /** @@ -200,15 +572,58 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) switch (ring->id) { case RCS: + if (IS_HASWELL(ring->dev)) { + ring->cmd_tables = hsw_render_ring_cmds; + ring->cmd_table_count = + ARRAY_SIZE(hsw_render_ring_cmds); + } else { + ring->cmd_tables = gen7_render_cmds; + ring->cmd_table_count = ARRAY_SIZE(gen7_render_cmds); + } + + ring->reg_table = gen7_render_regs; + ring->reg_count = ARRAY_SIZE(gen7_render_regs); + + if (IS_HASWELL(ring->dev)) { + ring->master_reg_table = hsw_master_regs; + ring->master_reg_count = ARRAY_SIZE(hsw_master_regs); + } else { + ring->master_reg_table = ivb_master_regs; + ring->master_reg_count = ARRAY_SIZE(ivb_master_regs); + } + ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask; break; case VCS: + ring->cmd_tables = gen7_video_cmds; + ring->cmd_table_count = ARRAY_SIZE(gen7_video_cmds); ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; break; case BCS: + if (IS_HASWELL(ring->dev)) { + ring->cmd_tables = hsw_blt_ring_cmds; + ring->cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmds); + } else { + ring->cmd_tables = gen7_blt_cmds; + ring->cmd_table_count = ARRAY_SIZE(gen7_blt_cmds); + } + + ring->reg_table = gen7_blt_regs; + ring->reg_count = ARRAY_SIZE(gen7_blt_regs); + + if (IS_HASWELL(ring->dev)) { + ring->master_reg_table = hsw_master_regs; + ring->master_reg_count = ARRAY_SIZE(hsw_master_regs); + } else { + ring->master_reg_table = ivb_master_regs; + ring->master_reg_count = ARRAY_SIZE(ivb_master_regs); + } + ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask; break; case VECS: + ring->cmd_tables = hsw_vebox_cmds; + ring->cmd_table_count = ARRAY_SIZE(hsw_vebox_cmds); /* VECS can use the same length_mask function as VCS */ ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; break; @@ -218,8 +633,8 @@ void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring) BUG(); } - validate_cmds_sorted(ring); - validate_regs_sorted(ring); + BUG_ON(!validate_cmds_sorted(ring)); + BUG_ON(!validate_regs_sorted(ring)); } static const struct drm_i915_cmd_descriptor* @@ -331,13 +746,111 @@ static u32 *vmap_batch(struct drm_i915_gem_object *obj) */ bool i915_needs_cmd_parser(struct intel_ring_buffer *ring) { + struct drm_i915_private *dev_priv = ring->dev->dev_private; + /* No command tables indicates a platform without parsing */ if (!ring->cmd_tables) return false; + /* + * XXX: VLV is Gen7 and therefore has cmd_tables, but has PPGTT + * disabled. That will cause all of the parser's PPGTT checks to + * fail. For now, disable parsing when PPGTT is off. + */ + if (!dev_priv->mm.aliasing_ppgtt) + return false; + return (i915.enable_cmd_parser == 1); } +static bool check_cmd(const struct intel_ring_buffer *ring, + const struct drm_i915_cmd_descriptor *desc, + const u32 *cmd, + const bool is_master, + bool *oacontrol_set) +{ + if (desc->flags & CMD_DESC_REJECT) { + DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd); + return false; + } + + if ((desc->flags & CMD_DESC_MASTER) && !is_master) { + DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n", + *cmd); + return false; + } + + if (desc->flags & CMD_DESC_REGISTER) { + u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; + + /* + * OACONTROL requires some special handling for writes. We + * want to make sure that any batch which enables OA also + * disables it before the end of the batch. The goal is to + * prevent one process from snooping on the perf data from + * another process. To do that, we need to check the value + * that will be written to the register. Hence, limit + * OACONTROL writes to only MI_LOAD_REGISTER_IMM commands. + */ + if (reg_addr == OACONTROL) { + if (desc->cmd.value == MI_LOAD_REGISTER_MEM) + return false; + + if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) + *oacontrol_set = (cmd[2] != 0); + } + + if (!valid_reg(ring->reg_table, + ring->reg_count, reg_addr)) { + if (!is_master || + !valid_reg(ring->master_reg_table, + ring->master_reg_count, + reg_addr)) { + DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", + reg_addr, + *cmd, + ring->id); + return false; + } + } + } + + if (desc->flags & CMD_DESC_BITMASK) { + int i; + + for (i = 0; i < MAX_CMD_DESC_BITMASKS; i++) { + u32 dword; + + if (desc->bits[i].mask == 0) + break; + + if (desc->bits[i].condition_mask != 0) { + u32 offset = + desc->bits[i].condition_offset; + u32 condition = cmd[offset] & + desc->bits[i].condition_mask; + + if (condition == 0) + continue; + } + + dword = cmd[desc->bits[i].offset] & + desc->bits[i].mask; + + if (dword != desc->bits[i].expected) { + DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (ring=%d)\n", + *cmd, + desc->bits[i].mask, + desc->bits[i].expected, + dword, ring->id); + return false; + } + } + } + + return true; +} + #define LENGTH_BIAS 2 /** @@ -361,6 +874,7 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, u32 *cmd, *batch_base, *batch_end; struct drm_i915_cmd_descriptor default_desc = { 0 }; int needs_clflush = 0; + bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */ ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush); if (ret) { @@ -402,76 +916,27 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, length = ((*cmd & desc->length.mask) + LENGTH_BIAS); if ((batch_end - cmd) < length) { - DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%d batchlen=%td\n", + DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%u batchlen=%td\n", *cmd, length, - (unsigned long)(batch_end - cmd)); - ret = -EINVAL; - break; - } - - if (desc->flags & CMD_DESC_REJECT) { - DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd); + batch_end - cmd); ret = -EINVAL; break; } - if ((desc->flags & CMD_DESC_MASTER) && !is_master) { - DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n", - *cmd); + if (!check_cmd(ring, desc, cmd, is_master, &oacontrol_set)) { ret = -EINVAL; break; } - if (desc->flags & CMD_DESC_REGISTER) { - u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; - - if (!valid_reg(ring->reg_table, - ring->reg_count, reg_addr)) { - if (!is_master || - !valid_reg(ring->master_reg_table, - ring->master_reg_count, - reg_addr)) { - DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", - reg_addr, - *cmd, - ring->id); - ret = -EINVAL; - break; - } - } - } - - if (desc->flags & CMD_DESC_BITMASK) { - int i; - - for (i = 0; i < MAX_CMD_DESC_BITMASKS; i++) { - u32 dword; - - if (desc->bits[i].mask == 0) - break; - - dword = cmd[desc->bits[i].offset] & - desc->bits[i].mask; - - if (dword != desc->bits[i].expected) { - DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (ring=%d)\n", - *cmd, - desc->bits[i].mask, - desc->bits[i].expected, - dword, ring->id); - ret = -EINVAL; - break; - } - } - - if (ret) - break; - } - cmd += length; } + if (oacontrol_set) { + DRM_DEBUG_DRIVER("CMD: batch set OACONTROL but did not clear it\n"); + ret = -EINVAL; + } + if (cmd >= batch_end) { DRM_DEBUG_DRIVER("CMD: Got to the end of the buffer w/o a BBE cmd!\n"); ret = -EINVAL; @@ -483,3 +948,22 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, return ret; } + +/** + * i915_cmd_parser_get_version() - get the cmd parser version number + * + * The cmd parser maintains a simple increasing integer version number suitable + * for passing to userspace clients to determine what operations are permitted. + * + * Return: the current version number of the cmd parser + */ +int i915_cmd_parser_get_version(void) +{ + /* + * Command parser version history + * + * 1. Initial version. Checks batches and reports violations, but leaves + * hardware parsing enabled (so does not allow new use cases). + */ + return 1; +} diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 195fe5bc0aacf5..18b3565f431a03 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -966,7 +966,7 @@ static int i915_rstdby_delays(struct seq_file *m, void *unused) return 0; } -static int i915_cur_delayinfo(struct seq_file *m, void *unused) +static int i915_frequency_info(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; @@ -991,6 +991,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + u32 rpmodectl, rpinclimit, rpdeclimit; u32 rpstat, cagf, reqf; u32 rpupei, rpcurup, rpprevup; u32 rpdownei, rpcurdown, rpprevdown; @@ -1011,6 +1012,10 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) reqf >>= 25; reqf *= GT_FREQUENCY_MULTIPLIER; + rpmodectl = I915_READ(GEN6_RP_CONTROL); + rpinclimit = I915_READ(GEN6_RP_UP_THRESHOLD); + rpdeclimit = I915_READ(GEN6_RP_DOWN_THRESHOLD); + rpstat = I915_READ(GEN6_RPSTAT1); rpupei = I915_READ(GEN6_RP_CUR_UP_EI); rpcurup = I915_READ(GEN6_RP_CUR_UP); @@ -1027,14 +1032,23 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); mutex_unlock(&dev->struct_mutex); + seq_printf(m, "PM IER=0x%08x IMR=0x%08x ISR=0x%08x IIR=0x%08x, MASK=0x%08x\n", + I915_READ(GEN6_PMIER), + I915_READ(GEN6_PMIMR), + I915_READ(GEN6_PMISR), + I915_READ(GEN6_PMIIR), + I915_READ(GEN6_PMINTRMSK)); seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); - seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat); seq_printf(m, "Render p-state ratio: %d\n", (gt_perf_status & 0xff00) >> 8); seq_printf(m, "Render p-state VID: %d\n", gt_perf_status & 0xff); seq_printf(m, "Render p-state limit: %d\n", rp_state_limits & 0xff); + seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat); + seq_printf(m, "RPMODECTL: 0x%08x\n", rpmodectl); + seq_printf(m, "RPINCLIMIT: 0x%08x\n", rpinclimit); + seq_printf(m, "RPDECLIMIT: 0x%08x\n", rpdeclimit); seq_printf(m, "RPNSWREQ: %dMHz\n", reqf); seq_printf(m, "CAGF: %dMHz\n", cagf); seq_printf(m, "RP CUR UP EI: %dus\n", rpupei & @@ -1225,9 +1239,13 @@ static int vlv_drpc_info(struct seq_file *m) u32 rpmodectl1, rcctl1; unsigned fw_rendercount = 0, fw_mediacount = 0; + intel_runtime_pm_get(dev_priv); + rpmodectl1 = I915_READ(GEN6_RP_CONTROL); rcctl1 = I915_READ(GEN6_RC_CONTROL); + intel_runtime_pm_put(dev_priv); + seq_printf(m, "Video Turbo Mode: %s\n", yesno(rpmodectl1 & GEN6_RP_MEDIA_TURBO)); seq_printf(m, "Turbo enabled: %s\n", @@ -1247,6 +1265,11 @@ static int vlv_drpc_info(struct seq_file *m) (I915_READ(VLV_GTLC_PW_STATUS) & VLV_GTLC_PW_MEDIA_STATUS_MASK) ? "Up" : "Down"); + seq_printf(m, "Render RC6 residency since boot: %u\n", + I915_READ(VLV_GT_RENDER_RC6)); + seq_printf(m, "Media RC6 residency since boot: %u\n", + I915_READ(VLV_GT_MEDIA_RC6)); + spin_lock_irq(&dev_priv->uncore.lock); fw_rendercount = dev_priv->uncore.fw_rendercount; fw_mediacount = dev_priv->uncore.fw_mediacount; @@ -1675,6 +1698,9 @@ static int i915_context_status(struct seq_file *m, void *unused) } list_for_each_entry(ctx, &dev_priv->context_list, link) { + if (ctx->obj == NULL) + continue; + seq_puts(m, "HW context "); describe_ctx(m, ctx); for_each_ring(ring, dev_priv, i) @@ -1816,8 +1842,7 @@ static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev) u64 pdp = I915_READ(ring->mmio_base + offset + 4); pdp <<= 32; pdp |= I915_READ(ring->mmio_base + offset); - for (i = 0; i < 4; i++) - seq_printf(m, "\tPDP%d 0x%016llx\n", i, pdp); + seq_printf(m, "\tPDP%d 0x%016llx\n", i, pdp); } } } @@ -1885,53 +1910,6 @@ static int i915_ppgtt_info(struct seq_file *m, void *data) return 0; } -static int i915_dpio_info(struct seq_file *m, void *data) -{ - struct drm_info_node *node = (struct drm_info_node *) m->private; - struct drm_device *dev = node->minor->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int ret; - - - if (!IS_VALLEYVIEW(dev)) { - seq_puts(m, "unsupported\n"); - return 0; - } - - ret = mutex_lock_interruptible(&dev_priv->dpio_lock); - if (ret) - return ret; - - seq_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL)); - - seq_printf(m, "DPIO PLL DW3 CH0 : 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW3(0))); - seq_printf(m, "DPIO PLL DW3 CH1: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW3(1))); - - seq_printf(m, "DPIO PLL DW5 CH0: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW5(0))); - seq_printf(m, "DPIO PLL DW5 CH1: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW5(1))); - - seq_printf(m, "DPIO PLL DW7 CH0: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW7(0))); - seq_printf(m, "DPIO PLL DW7 CH1: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW7(1))); - - seq_printf(m, "DPIO PLL DW10 CH0: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW10(0))); - seq_printf(m, "DPIO PLL DW10 CH1: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW10(1))); - - seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, VLV_CMN_DW0)); - - mutex_unlock(&dev_priv->dpio_lock); - - return 0; -} - static int i915_llc(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; @@ -2044,7 +2022,7 @@ static int i915_pc8_status(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (!IS_HASWELL(dev)) { + if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { seq_puts(m, "not supported\n"); return 0; } @@ -3286,9 +3264,15 @@ static int i915_wedged_set(void *data, u64 val) { struct drm_device *dev = data; + struct drm_i915_private *dev_priv = dev->dev_private; + + intel_runtime_pm_get(dev_priv); i915_handle_error(dev, val, "Manually setting wedged to %llu", val); + + intel_runtime_pm_put(dev_priv); + return 0; } @@ -3774,7 +3758,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS}, {"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS}, {"i915_rstdby_delays", i915_rstdby_delays, 0}, - {"i915_cur_delayinfo", i915_cur_delayinfo, 0}, + {"i915_frequency_info", i915_frequency_info, 0}, {"i915_delayfreq_table", i915_delayfreq_table, 0}, {"i915_inttoext_table", i915_inttoext_table, 0}, {"i915_drpc_info", i915_drpc_info, 0}, @@ -3790,7 +3774,6 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0}, {"i915_swizzle_info", i915_swizzle_info, 0}, {"i915_ppgtt_info", i915_ppgtt_info, 0}, - {"i915_dpio", i915_dpio_info, 0}, {"i915_llc", i915_llc, 0}, {"i915_edp_psr_status", i915_edp_psr_status, 0}, {"i915_sink_crc_eDP1", i915_sink_crc, 0}, diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 96177eec0a0eb9..d02c8de4bd6c5b 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1017,6 +1017,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_EXEC_HANDLE_LUT: value = 1; break; + case I915_PARAM_CMD_PARSER_VERSION: + value = i915_cmd_parser_get_version(); + break; default: DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; @@ -1277,12 +1280,13 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_ static bool i915_switcheroo_can_switch(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - bool can_switch; - spin_lock(&dev->count_lock); - can_switch = (dev->open_count == 0); - spin_unlock(&dev->count_lock); - return can_switch; + /* + * FIXME: open_count is protected by drm_global_mutex but that would lead to + * locking inversion with the driver load path. And the access here is + * completely racy anyway. So don't bother with locking for now. + */ + return dev->open_count == 0; } static const struct vga_switcheroo_client_ops i915_switcheroo_ops = { @@ -1326,7 +1330,7 @@ static int i915_load_modeset_init(struct drm_device *dev) intel_power_domains_init_hw(dev_priv); - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, dev->pdev->irq); if (ret) goto cleanup_gem_stolen; @@ -1336,7 +1340,7 @@ static int i915_load_modeset_init(struct drm_device *dev) ret = i915_gem_init(dev); if (ret) - goto cleanup_power; + goto cleanup_irq; INIT_WORK(&dev_priv->console_resume_work, intel_console_resume); @@ -1345,10 +1349,8 @@ static int i915_load_modeset_init(struct drm_device *dev) /* Always safe in the mode setting case. */ /* FIXME: do pre/post-mode set stuff in core KMS code */ dev->vblank_disable_allowed = true; - if (INTEL_INFO(dev)->num_pipes == 0) { - intel_display_power_put(dev_priv, POWER_DOMAIN_VGA); + if (INTEL_INFO(dev)->num_pipes == 0) return 0; - } ret = intel_fbdev_init(dev); if (ret) @@ -1383,8 +1385,7 @@ static int i915_load_modeset_init(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); WARN_ON(dev_priv->mm.aliasing_ppgtt); drm_mm_takedown(&dev_priv->gtt.base.mm); -cleanup_power: - intel_display_power_put(dev_priv, POWER_DOMAIN_VGA); +cleanup_irq: drm_irq_uninstall(dev); cleanup_gem_stolen: i915_gem_cleanup_stolen(dev); @@ -1569,6 +1570,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->backlight_lock); spin_lock_init(&dev_priv->uncore.lock); spin_lock_init(&dev_priv->mm.object_stat_lock); + dev_priv->ring_index = 0; mutex_init(&dev_priv->dpio_lock); mutex_init(&dev_priv->modeset_restore_lock); @@ -1926,6 +1928,8 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; + if (file_priv && file_priv->bsd_ring) + file_priv->bsd_ring = NULL; kfree(file_priv); } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 82f4d1f47d3b73..4024e16ae63d57 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -279,6 +279,26 @@ static const struct intel_device_info intel_broadwell_m_info = { GEN_DEFAULT_PIPEOFFSETS, }; +static const struct intel_device_info intel_broadwell_gt3d_info = { + .gen = 8, .num_pipes = 3, + .need_gfx_hws = 1, .has_hotplug = 1, + .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING, + .has_llc = 1, + .has_ddi = 1, + .has_fbc = 1, + GEN_DEFAULT_PIPEOFFSETS, +}; + +static const struct intel_device_info intel_broadwell_gt3m_info = { + .gen = 8, .is_mobile = 1, .num_pipes = 3, + .need_gfx_hws = 1, .has_hotplug = 1, + .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING, + .has_llc = 1, + .has_ddi = 1, + .has_fbc = 1, + GEN_DEFAULT_PIPEOFFSETS, +}; + /* * Make sure any device matches here are from most specific to most * general. For example, since the Quanta match is based on the subsystem @@ -311,8 +331,10 @@ static const struct intel_device_info intel_broadwell_m_info = { INTEL_HSW_M_IDS(&intel_haswell_m_info), \ INTEL_VLV_M_IDS(&intel_valleyview_m_info), \ INTEL_VLV_D_IDS(&intel_valleyview_d_info), \ - INTEL_BDW_M_IDS(&intel_broadwell_m_info), \ - INTEL_BDW_D_IDS(&intel_broadwell_d_info) + INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info), \ + INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info), \ + INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info), \ + INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info) static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_PCI_IDS, @@ -551,7 +573,6 @@ static int i915_drm_thaw_early(struct drm_device *dev) static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) { struct drm_i915_private *dev_priv = dev->dev_private; - int error = 0; if (drm_core_check_feature(dev, DRIVER_MODESET) && restore_gtt_mappings) { @@ -569,12 +590,14 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) drm_mode_config_reset(dev); mutex_lock(&dev->struct_mutex); - - error = i915_gem_init_hw(dev); + if (i915_gem_init_hw(dev)) { + DRM_ERROR("failed to re-initialize GPU, declaring wedged!\n"); + atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter); + } mutex_unlock(&dev->struct_mutex); /* We need working interrupts for modeset enabling ... */ - drm_irq_install(dev); + drm_irq_install(dev, dev->pdev->irq); intel_modeset_init_hw(dev); @@ -613,7 +636,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) mutex_unlock(&dev_priv->modeset_restore_lock); intel_runtime_pm_put(dev_priv); - return error; + return 0; } static int i915_drm_thaw(struct drm_device *dev) @@ -746,18 +769,20 @@ int i915_reset(struct drm_device *dev) return ret; } + /* + * FIXME: This is horribly race against concurrent pageflip and + * vblank wait ioctls since they can observe dev->irqs_disabled + * being false when they shouldn't be able to. + */ drm_irq_uninstall(dev); - drm_irq_install(dev); + drm_irq_install(dev, dev->pdev->irq); /* rps/rc6 re-init is necessary to restore state lost after the * reset and the re-install of drm irq. Skip for ironlake per * previous concerns that it doesn't respond well to some forms * of re-init after reset. */ - if (INTEL_INFO(dev)->gen > 5) { - mutex_lock(&dev->struct_mutex); - intel_enable_gt_powersave(dev); - mutex_unlock(&dev->struct_mutex); - } + if (INTEL_INFO(dev)->gen > 5) + intel_reset_gt_powersave(dev); intel_hpd_init(dev); } else { @@ -891,19 +916,429 @@ static int i915_pm_poweroff(struct device *dev) return i915_drm_freeze(drm_dev); } -static int i915_runtime_suspend(struct device *device) +static int hsw_runtime_suspend(struct drm_i915_private *dev_priv) +{ + hsw_enable_pc8(dev_priv); + + return 0; +} + +static int snb_runtime_resume(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + + intel_init_pch_refclk(dev); + + return 0; +} + +static int hsw_runtime_resume(struct drm_i915_private *dev_priv) +{ + hsw_disable_pc8(dev_priv); + + return 0; +} + +/* + * Save all Gunit registers that may be lost after a D3 and a subsequent + * S0i[R123] transition. The list of registers needing a save/restore is + * defined in the VLV2_S0IXRegs document. This documents marks all Gunit + * registers in the following way: + * - Driver: saved/restored by the driver + * - Punit : saved/restored by the Punit firmware + * - No, w/o marking: no need to save/restore, since the register is R/O or + * used internally by the HW in a way that doesn't depend + * keeping the content across a suspend/resume. + * - Debug : used for debugging + * + * We save/restore all registers marked with 'Driver', with the following + * exceptions: + * - Registers out of use, including also registers marked with 'Debug'. + * These have no effect on the driver's operation, so we don't save/restore + * them to reduce the overhead. + * - Registers that are fully setup by an initialization function called from + * the resume path. For example many clock gating and RPS/RC6 registers. + * - Registers that provide the right functionality with their reset defaults. + * + * TODO: Except for registers that based on the above 3 criteria can be safely + * ignored, we save/restore all others, practically treating the HW context as + * a black-box for the driver. Further investigation is needed to reduce the + * saved/restored registers even further, by following the same 3 criteria. + */ +static void vlv_save_gunit_s0ix_state(struct drm_i915_private *dev_priv) +{ + struct vlv_s0ix_state *s = &dev_priv->vlv_s0ix_state; + int i; + + /* GAM 0x4000-0x4770 */ + s->wr_watermark = I915_READ(GEN7_WR_WATERMARK); + s->gfx_prio_ctrl = I915_READ(GEN7_GFX_PRIO_CTRL); + s->arb_mode = I915_READ(ARB_MODE); + s->gfx_pend_tlb0 = I915_READ(GEN7_GFX_PEND_TLB0); + s->gfx_pend_tlb1 = I915_READ(GEN7_GFX_PEND_TLB1); + + for (i = 0; i < ARRAY_SIZE(s->lra_limits); i++) + s->lra_limits[i] = I915_READ(GEN7_LRA_LIMITS_BASE + i * 4); + + s->media_max_req_count = I915_READ(GEN7_MEDIA_MAX_REQ_COUNT); + s->gfx_max_req_count = I915_READ(GEN7_MEDIA_MAX_REQ_COUNT); + + s->render_hwsp = I915_READ(RENDER_HWS_PGA_GEN7); + s->ecochk = I915_READ(GAM_ECOCHK); + s->bsd_hwsp = I915_READ(BSD_HWS_PGA_GEN7); + s->blt_hwsp = I915_READ(BLT_HWS_PGA_GEN7); + + s->tlb_rd_addr = I915_READ(GEN7_TLB_RD_ADDR); + + /* MBC 0x9024-0x91D0, 0x8500 */ + s->g3dctl = I915_READ(VLV_G3DCTL); + s->gsckgctl = I915_READ(VLV_GSCKGCTL); + s->mbctl = I915_READ(GEN6_MBCTL); + + /* GCP 0x9400-0x9424, 0x8100-0x810C */ + s->ucgctl1 = I915_READ(GEN6_UCGCTL1); + s->ucgctl3 = I915_READ(GEN6_UCGCTL3); + s->rcgctl1 = I915_READ(GEN6_RCGCTL1); + s->rcgctl2 = I915_READ(GEN6_RCGCTL2); + s->rstctl = I915_READ(GEN6_RSTCTL); + s->misccpctl = I915_READ(GEN7_MISCCPCTL); + + /* GPM 0xA000-0xAA84, 0x8000-0x80FC */ + s->gfxpause = I915_READ(GEN6_GFXPAUSE); + s->rpdeuhwtc = I915_READ(GEN6_RPDEUHWTC); + s->rpdeuc = I915_READ(GEN6_RPDEUC); + s->ecobus = I915_READ(ECOBUS); + s->pwrdwnupctl = I915_READ(VLV_PWRDWNUPCTL); + s->rp_down_timeout = I915_READ(GEN6_RP_DOWN_TIMEOUT); + s->rp_deucsw = I915_READ(GEN6_RPDEUCSW); + s->rcubmabdtmr = I915_READ(GEN6_RCUBMABDTMR); + s->rcedata = I915_READ(VLV_RCEDATA); + s->spare2gh = I915_READ(VLV_SPAREG2H); + + /* Display CZ domain, 0x4400C-0x4402C, 0x4F000-0x4F11F */ + s->gt_imr = I915_READ(GTIMR); + s->gt_ier = I915_READ(GTIER); + s->pm_imr = I915_READ(GEN6_PMIMR); + s->pm_ier = I915_READ(GEN6_PMIER); + + for (i = 0; i < ARRAY_SIZE(s->gt_scratch); i++) + s->gt_scratch[i] = I915_READ(GEN7_GT_SCRATCH_BASE + i * 4); + + /* GT SA CZ domain, 0x100000-0x138124 */ + s->tilectl = I915_READ(TILECTL); + s->gt_fifoctl = I915_READ(GTFIFOCTL); + s->gtlc_wake_ctrl = I915_READ(VLV_GTLC_WAKE_CTRL); + s->gtlc_survive = I915_READ(VLV_GTLC_SURVIVABILITY_REG); + s->pmwgicz = I915_READ(VLV_PMWGICZ); + + /* Gunit-Display CZ domain, 0x182028-0x1821CF */ + s->gu_ctl0 = I915_READ(VLV_GU_CTL0); + s->gu_ctl1 = I915_READ(VLV_GU_CTL1); + s->clock_gate_dis2 = I915_READ(VLV_GUNIT_CLOCK_GATE2); + + /* + * Not saving any of: + * DFT, 0x9800-0x9EC0 + * SARB, 0xB000-0xB1FC + * GAC, 0x5208-0x524C, 0x14000-0x14C000 + * PCI CFG + */ +} + +static void vlv_restore_gunit_s0ix_state(struct drm_i915_private *dev_priv) +{ + struct vlv_s0ix_state *s = &dev_priv->vlv_s0ix_state; + u32 val; + int i; + + /* GAM 0x4000-0x4770 */ + I915_WRITE(GEN7_WR_WATERMARK, s->wr_watermark); + I915_WRITE(GEN7_GFX_PRIO_CTRL, s->gfx_prio_ctrl); + I915_WRITE(ARB_MODE, s->arb_mode | (0xffff << 16)); + I915_WRITE(GEN7_GFX_PEND_TLB0, s->gfx_pend_tlb0); + I915_WRITE(GEN7_GFX_PEND_TLB1, s->gfx_pend_tlb1); + + for (i = 0; i < ARRAY_SIZE(s->lra_limits); i++) + I915_WRITE(GEN7_LRA_LIMITS_BASE + i * 4, s->lra_limits[i]); + + I915_WRITE(GEN7_MEDIA_MAX_REQ_COUNT, s->media_max_req_count); + I915_WRITE(GEN7_MEDIA_MAX_REQ_COUNT, s->gfx_max_req_count); + + I915_WRITE(RENDER_HWS_PGA_GEN7, s->render_hwsp); + I915_WRITE(GAM_ECOCHK, s->ecochk); + I915_WRITE(BSD_HWS_PGA_GEN7, s->bsd_hwsp); + I915_WRITE(BLT_HWS_PGA_GEN7, s->blt_hwsp); + + I915_WRITE(GEN7_TLB_RD_ADDR, s->tlb_rd_addr); + + /* MBC 0x9024-0x91D0, 0x8500 */ + I915_WRITE(VLV_G3DCTL, s->g3dctl); + I915_WRITE(VLV_GSCKGCTL, s->gsckgctl); + I915_WRITE(GEN6_MBCTL, s->mbctl); + + /* GCP 0x9400-0x9424, 0x8100-0x810C */ + I915_WRITE(GEN6_UCGCTL1, s->ucgctl1); + I915_WRITE(GEN6_UCGCTL3, s->ucgctl3); + I915_WRITE(GEN6_RCGCTL1, s->rcgctl1); + I915_WRITE(GEN6_RCGCTL2, s->rcgctl2); + I915_WRITE(GEN6_RSTCTL, s->rstctl); + I915_WRITE(GEN7_MISCCPCTL, s->misccpctl); + + /* GPM 0xA000-0xAA84, 0x8000-0x80FC */ + I915_WRITE(GEN6_GFXPAUSE, s->gfxpause); + I915_WRITE(GEN6_RPDEUHWTC, s->rpdeuhwtc); + I915_WRITE(GEN6_RPDEUC, s->rpdeuc); + I915_WRITE(ECOBUS, s->ecobus); + I915_WRITE(VLV_PWRDWNUPCTL, s->pwrdwnupctl); + I915_WRITE(GEN6_RP_DOWN_TIMEOUT,s->rp_down_timeout); + I915_WRITE(GEN6_RPDEUCSW, s->rp_deucsw); + I915_WRITE(GEN6_RCUBMABDTMR, s->rcubmabdtmr); + I915_WRITE(VLV_RCEDATA, s->rcedata); + I915_WRITE(VLV_SPAREG2H, s->spare2gh); + + /* Display CZ domain, 0x4400C-0x4402C, 0x4F000-0x4F11F */ + I915_WRITE(GTIMR, s->gt_imr); + I915_WRITE(GTIER, s->gt_ier); + I915_WRITE(GEN6_PMIMR, s->pm_imr); + I915_WRITE(GEN6_PMIER, s->pm_ier); + + for (i = 0; i < ARRAY_SIZE(s->gt_scratch); i++) + I915_WRITE(GEN7_GT_SCRATCH_BASE + i * 4, s->gt_scratch[i]); + + /* GT SA CZ domain, 0x100000-0x138124 */ + I915_WRITE(TILECTL, s->tilectl); + I915_WRITE(GTFIFOCTL, s->gt_fifoctl); + /* + * Preserve the GT allow wake and GFX force clock bit, they are not + * be restored, as they are used to control the s0ix suspend/resume + * sequence by the caller. + */ + val = I915_READ(VLV_GTLC_WAKE_CTRL); + val &= VLV_GTLC_ALLOWWAKEREQ; + val |= s->gtlc_wake_ctrl & ~VLV_GTLC_ALLOWWAKEREQ; + I915_WRITE(VLV_GTLC_WAKE_CTRL, val); + + val = I915_READ(VLV_GTLC_SURVIVABILITY_REG); + val &= VLV_GFX_CLK_FORCE_ON_BIT; + val |= s->gtlc_survive & ~VLV_GFX_CLK_FORCE_ON_BIT; + I915_WRITE(VLV_GTLC_SURVIVABILITY_REG, val); + + I915_WRITE(VLV_PMWGICZ, s->pmwgicz); + + /* Gunit-Display CZ domain, 0x182028-0x1821CF */ + I915_WRITE(VLV_GU_CTL0, s->gu_ctl0); + I915_WRITE(VLV_GU_CTL1, s->gu_ctl1); + I915_WRITE(VLV_GUNIT_CLOCK_GATE2, s->clock_gate_dis2); +} + +int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool force_on) +{ + u32 val; + int err; + + val = I915_READ(VLV_GTLC_SURVIVABILITY_REG); + WARN_ON(!!(val & VLV_GFX_CLK_FORCE_ON_BIT) == force_on); + +#define COND (I915_READ(VLV_GTLC_SURVIVABILITY_REG) & VLV_GFX_CLK_STATUS_BIT) + /* Wait for a previous force-off to settle */ + if (force_on) { + err = wait_for(!COND, 20); + if (err) { + DRM_ERROR("timeout waiting for GFX clock force-off (%08x)\n", + I915_READ(VLV_GTLC_SURVIVABILITY_REG)); + return err; + } + } + + val = I915_READ(VLV_GTLC_SURVIVABILITY_REG); + val &= ~VLV_GFX_CLK_FORCE_ON_BIT; + if (force_on) + val |= VLV_GFX_CLK_FORCE_ON_BIT; + I915_WRITE(VLV_GTLC_SURVIVABILITY_REG, val); + + if (!force_on) + return 0; + + err = wait_for(COND, 20); + if (err) + DRM_ERROR("timeout waiting for GFX clock force-on (%08x)\n", + I915_READ(VLV_GTLC_SURVIVABILITY_REG)); + + return err; +#undef COND +} + +static int vlv_allow_gt_wake(struct drm_i915_private *dev_priv, bool allow) +{ + u32 val; + int err = 0; + + val = I915_READ(VLV_GTLC_WAKE_CTRL); + val &= ~VLV_GTLC_ALLOWWAKEREQ; + if (allow) + val |= VLV_GTLC_ALLOWWAKEREQ; + I915_WRITE(VLV_GTLC_WAKE_CTRL, val); + POSTING_READ(VLV_GTLC_WAKE_CTRL); + +#define COND (!!(I915_READ(VLV_GTLC_PW_STATUS) & VLV_GTLC_ALLOWWAKEACK) == \ + allow) + err = wait_for(COND, 1); + if (err) + DRM_ERROR("timeout disabling GT waking\n"); + return err; +#undef COND +} + +static int vlv_wait_for_gt_wells(struct drm_i915_private *dev_priv, + bool wait_for_on) +{ + u32 mask; + u32 val; + int err; + + mask = VLV_GTLC_PW_MEDIA_STATUS_MASK | VLV_GTLC_PW_RENDER_STATUS_MASK; + val = wait_for_on ? mask : 0; +#define COND ((I915_READ(VLV_GTLC_PW_STATUS) & mask) == val) + if (COND) + return 0; + + DRM_DEBUG_KMS("waiting for GT wells to go %s (%08x)\n", + wait_for_on ? "on" : "off", + I915_READ(VLV_GTLC_PW_STATUS)); + + /* + * RC6 transitioning can be delayed up to 2 msec (see + * valleyview_enable_rps), use 3 msec for safety. + */ + err = wait_for(COND, 3); + if (err) + DRM_ERROR("timeout waiting for GT wells to go %s\n", + wait_for_on ? "on" : "off"); + + return err; +#undef COND +} + +static void vlv_check_no_gt_access(struct drm_i915_private *dev_priv) +{ + if (!(I915_READ(VLV_GTLC_PW_STATUS) & VLV_GTLC_ALLOWWAKEERR)) + return; + + DRM_ERROR("GT register access while GT waking disabled\n"); + I915_WRITE(VLV_GTLC_PW_STATUS, VLV_GTLC_ALLOWWAKEERR); +} + +static int vlv_runtime_suspend(struct drm_i915_private *dev_priv) +{ + u32 mask; + int err; + + /* + * Bspec defines the following GT well on flags as debug only, so + * don't treat them as hard failures. + */ + (void)vlv_wait_for_gt_wells(dev_priv, false); + + mask = VLV_GTLC_RENDER_CTX_EXISTS | VLV_GTLC_MEDIA_CTX_EXISTS; + WARN_ON((I915_READ(VLV_GTLC_WAKE_CTRL) & mask) != mask); + + vlv_check_no_gt_access(dev_priv); + + err = vlv_force_gfx_clock(dev_priv, true); + if (err) + goto err1; + + err = vlv_allow_gt_wake(dev_priv, false); + if (err) + goto err2; + vlv_save_gunit_s0ix_state(dev_priv); + + err = vlv_force_gfx_clock(dev_priv, false); + if (err) + goto err2; + + return 0; + +err2: + /* For safety always re-enable waking and disable gfx clock forcing */ + vlv_allow_gt_wake(dev_priv, true); +err1: + vlv_force_gfx_clock(dev_priv, false); + + return err; +} + +static int vlv_runtime_resume(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + int err; + int ret; + + /* + * If any of the steps fail just try to continue, that's the best we + * can do at this point. Return the first error code (which will also + * leave RPM permanently disabled). + */ + ret = vlv_force_gfx_clock(dev_priv, true); + + vlv_restore_gunit_s0ix_state(dev_priv); + + err = vlv_allow_gt_wake(dev_priv, true); + if (!ret) + ret = err; + + err = vlv_force_gfx_clock(dev_priv, false); + if (!ret) + ret = err; + + vlv_check_no_gt_access(dev_priv); + + intel_init_clock_gating(dev); + i915_gem_restore_fences(dev); + + return ret; +} + +static int intel_runtime_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct drm_device *dev = pci_get_drvdata(pdev); struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + if (WARN_ON_ONCE(!(dev_priv->rps.enabled && intel_enable_rc6(dev)))) + return -ENODEV; WARN_ON(!HAS_RUNTIME_PM(dev)); assert_force_wake_inactive(dev_priv); DRM_DEBUG_KMS("Suspending device\n"); - if (HAS_PC8(dev)) - hsw_enable_pc8(dev_priv); + /* + * rps.work can't be rearmed here, since we get here only after making + * sure the GPU is idle and the RPS freq is set to the minimum. See + * intel_mark_idle(). + */ + cancel_work_sync(&dev_priv->rps.work); + intel_runtime_pm_disable_interrupts(dev); + + if (IS_GEN6(dev)) { + ret = 0; + } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + ret = hsw_runtime_suspend(dev_priv); + } else if (IS_VALLEYVIEW(dev)) { + ret = vlv_runtime_suspend(dev_priv); + } else { + ret = -ENODEV; + WARN_ON(1); + } + + if (ret) { + DRM_ERROR("Runtime suspend failed, disabling it (%d)\n", ret); + intel_runtime_pm_restore_interrupts(dev); + + return ret; + } i915_gem_release_all_mmaps(dev_priv); @@ -923,11 +1358,12 @@ static int i915_runtime_suspend(struct device *device) return 0; } -static int i915_runtime_resume(struct device *device) +static int intel_runtime_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct drm_device *dev = pci_get_drvdata(pdev); struct drm_i915_private *dev_priv = dev->dev_private; + int ret; WARN_ON(!HAS_RUNTIME_PM(dev)); @@ -936,11 +1372,33 @@ static int i915_runtime_resume(struct device *device) intel_opregion_notify_adapter(dev, PCI_D0); dev_priv->pm.suspended = false; - if (HAS_PC8(dev)) - hsw_disable_pc8(dev_priv); + if (IS_GEN6(dev)) { + ret = snb_runtime_resume(dev_priv); + } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + ret = hsw_runtime_resume(dev_priv); + } else if (IS_VALLEYVIEW(dev)) { + ret = vlv_runtime_resume(dev_priv); + } else { + WARN_ON(1); + ret = -ENODEV; + } + + /* + * No point of rolling back things in case of an error, as the best + * we can do is to hope that things will still work (and disable RPM). + */ + i915_gem_init_swizzling(dev); + gen6_update_ring_freq(dev); + + intel_runtime_pm_restore_interrupts(dev); + intel_reset_gt_powersave(dev); - DRM_DEBUG_KMS("Device resumed\n"); - return 0; + if (ret) + DRM_ERROR("Runtime resume failed, disabling it (%d)\n", ret); + else + DRM_DEBUG_KMS("Device resumed\n"); + + return ret; } static const struct dev_pm_ops i915_pm_ops = { @@ -954,8 +1412,8 @@ static const struct dev_pm_ops i915_pm_ops = { .poweroff = i915_pm_poweroff, .restore_early = i915_pm_resume_early, .restore = i915_pm_resume, - .runtime_suspend = i915_runtime_suspend, - .runtime_resume = i915_runtime_resume, + .runtime_suspend = intel_runtime_suspend, + .runtime_resume = intel_runtime_resume, }; static const struct vm_operations_struct i915_gem_vm_ops = { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 108e1ec2fa4b49..cae30a10123989 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -35,6 +35,7 @@ #include "i915_reg.h" #include "intel_bios.h" #include "intel_ringbuffer.h" +#include "i915_gem_gtt.h" #include #include #include @@ -324,7 +325,6 @@ struct drm_i915_error_state { u32 gab_ctl; u32 gfx_mode; u32 extra_instdone[I915_NUM_INSTDONE_REG]; - u32 pipestat[I915_MAX_PIPES]; u64 fence[I915_MAX_NUM_FENCES]; struct intel_overlay_error_state *overlay; struct intel_display_error_state *display; @@ -358,7 +358,7 @@ struct drm_i915_error_state { u64 bbaddr; u64 acthd; u32 fault_reg; - u32 faddr; + u64 faddr; u32 rc_psmi; /* sleep state */ u32 semaphore_mboxes[I915_NUM_RINGS - 1]; @@ -572,168 +572,6 @@ enum i915_cache_level { I915_CACHE_WT, /* hsw:gt3e WriteThrough for scanouts */ }; -typedef uint32_t gen6_gtt_pte_t; - -/** - * A VMA represents a GEM BO that is bound into an address space. Therefore, a - * VMA's presence cannot be guaranteed before binding, or after unbinding the - * object into/from the address space. - * - * To make things as simple as possible (ie. no refcounting), a VMA's lifetime - * will always be <= an objects lifetime. So object refcounting should cover us. - */ -struct i915_vma { - struct drm_mm_node node; - struct drm_i915_gem_object *obj; - struct i915_address_space *vm; - - /** This object's place on the active/inactive lists */ - struct list_head mm_list; - - struct list_head vma_link; /* Link in the object's VMA list */ - - /** This vma's place in the batchbuffer or on the eviction list */ - struct list_head exec_list; - - /** - * Used for performing relocations during execbuffer insertion. - */ - struct hlist_node exec_node; - unsigned long exec_handle; - struct drm_i915_gem_exec_object2 *exec_entry; - - /** - * How many users have pinned this object in GTT space. The following - * users can each hold at most one reference: pwrite/pread, pin_ioctl - * (via user_pin_count), execbuffer (objects are not allowed multiple - * times for the same batchbuffer), and the framebuffer code. When - * switching/pageflipping, the framebuffer code has at most two buffers - * pinned per crtc. - * - * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3 - * bits with absolutely no headroom. So use 4 bits. */ - unsigned int pin_count:4; -#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf - - /** Unmap an object from an address space. This usually consists of - * setting the valid PTE entries to a reserved scratch page. */ - void (*unbind_vma)(struct i915_vma *vma); - /* Map an object into an address space with the given cache flags. */ -#define GLOBAL_BIND (1<<0) - void (*bind_vma)(struct i915_vma *vma, - enum i915_cache_level cache_level, - u32 flags); -}; - -struct i915_address_space { - struct drm_mm mm; - struct drm_device *dev; - struct list_head global_link; - unsigned long start; /* Start offset always 0 for dri2 */ - size_t total; /* size addr space maps (ex. 2GB for ggtt) */ - - struct { - dma_addr_t addr; - struct page *page; - } scratch; - - /** - * List of objects currently involved in rendering. - * - * Includes buffers having the contents of their GPU caches - * flushed, not necessarily primitives. last_rendering_seqno - * represents when the rendering involved will be completed. - * - * A reference is held on the buffer while on this list. - */ - struct list_head active_list; - - /** - * LRU list of objects which are not in the ringbuffer and - * are ready to unbind, but are still in the GTT. - * - * last_rendering_seqno is 0 while an object is in this list. - * - * A reference is not held on the buffer while on this list, - * as merely being GTT-bound shouldn't prevent its being - * freed, and we'll pull it off the list in the free path. - */ - struct list_head inactive_list; - - /* FIXME: Need a more generic return type */ - gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr, - enum i915_cache_level level, - bool valid); /* Create a valid PTE */ - void (*clear_range)(struct i915_address_space *vm, - uint64_t start, - uint64_t length, - bool use_scratch); - void (*insert_entries)(struct i915_address_space *vm, - struct sg_table *st, - uint64_t start, - enum i915_cache_level cache_level); - void (*cleanup)(struct i915_address_space *vm); -}; - -/* The Graphics Translation Table is the way in which GEN hardware translates a - * Graphics Virtual Address into a Physical Address. In addition to the normal - * collateral associated with any va->pa translations GEN hardware also has a - * portion of the GTT which can be mapped by the CPU and remain both coherent - * and correct (in cases like swizzling). That region is referred to as GMADR in - * the spec. - */ -struct i915_gtt { - struct i915_address_space base; - size_t stolen_size; /* Total size of stolen memory */ - - unsigned long mappable_end; /* End offset that we can CPU map */ - struct io_mapping *mappable; /* Mapping to our CPU mappable region */ - phys_addr_t mappable_base; /* PA of our GMADR */ - - /** "Graphics Stolen Memory" holds the global PTEs */ - void __iomem *gsm; - - bool do_idle_maps; - - int mtrr; - - /* global gtt ops */ - int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total, - size_t *stolen, phys_addr_t *mappable_base, - unsigned long *mappable_end); -}; -#define gtt_total_entries(gtt) ((gtt).base.total >> PAGE_SHIFT) - -#define GEN8_LEGACY_PDPS 4 -struct i915_hw_ppgtt { - struct i915_address_space base; - struct kref ref; - struct drm_mm_node node; - unsigned num_pd_entries; - unsigned num_pd_pages; /* gen8+ */ - union { - struct page **pt_pages; - struct page **gen8_pt_pages[GEN8_LEGACY_PDPS]; - }; - struct page *pd_pages; - union { - uint32_t pd_offset; - dma_addr_t pd_dma_addr[GEN8_LEGACY_PDPS]; - }; - union { - dma_addr_t *pt_dma_addr; - dma_addr_t *gen8_pt_dma_addr[4]; - }; - - struct i915_hw_context *ctx; - - int (*enable)(struct i915_hw_ppgtt *ppgtt); - int (*switch_mm)(struct i915_hw_ppgtt *ppgtt, - struct intel_ring_buffer *ring, - bool synchronous); - void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m); -}; - struct i915_ctx_hang_stats { /* This context had batch pending when hang was declared */ unsigned batch_pending; @@ -794,6 +632,10 @@ struct i915_fbc { } no_fbc_reason; }; +struct i915_drrs { + struct intel_connector *connector; +}; + struct i915_psr { bool sink_support; bool source_ok; @@ -977,6 +819,67 @@ struct i915_suspend_saved_registers { u32 savePCH_PORT_HOTPLUG; }; +struct vlv_s0ix_state { + /* GAM */ + u32 wr_watermark; + u32 gfx_prio_ctrl; + u32 arb_mode; + u32 gfx_pend_tlb0; + u32 gfx_pend_tlb1; + u32 lra_limits[GEN7_LRA_LIMITS_REG_NUM]; + u32 media_max_req_count; + u32 gfx_max_req_count; + u32 render_hwsp; + u32 ecochk; + u32 bsd_hwsp; + u32 blt_hwsp; + u32 tlb_rd_addr; + + /* MBC */ + u32 g3dctl; + u32 gsckgctl; + u32 mbctl; + + /* GCP */ + u32 ucgctl1; + u32 ucgctl3; + u32 rcgctl1; + u32 rcgctl2; + u32 rstctl; + u32 misccpctl; + + /* GPM */ + u32 gfxpause; + u32 rpdeuhwtc; + u32 rpdeuc; + u32 ecobus; + u32 pwrdwnupctl; + u32 rp_down_timeout; + u32 rp_deucsw; + u32 rcubmabdtmr; + u32 rcedata; + u32 spare2gh; + + /* Display 1 CZ domain */ + u32 gt_imr; + u32 gt_ier; + u32 pm_imr; + u32 pm_ier; + u32 gt_scratch[GEN7_GT_SCRATCH_REG_NUM]; + + /* GT SA CZ domain */ + u32 tilectl; + u32 gt_fifoctl; + u32 gtlc_wake_ctrl; + u32 gtlc_survive; + u32 pmwgicz; + + /* Display 2 CZ domain */ + u32 gu_ctl0; + u32 gu_ctl1; + u32 clock_gate_dis2; +}; + struct intel_gen6_power_mgmt { /* work and pm_iir are protected by dev_priv->irq_lock */ struct work_struct work; @@ -1086,6 +989,7 @@ struct i915_power_domains { * time are on. They are kept on until after the first modeset. */ bool init_power_on; + bool initializing; int power_well_count; struct mutex lock; @@ -1260,8 +1164,12 @@ struct i915_gpu_error { */ wait_queue_head_t reset_queue; - /* For gpu hang simulation. */ - unsigned int stop_rings; + /* Userspace knobs for gpu hang simulation; + * combines both a ring mask, and extra flags + */ + u32 stop_rings; +#define I915_STOP_RING_ALLOW_BAN (1 << 31) +#define I915_STOP_RING_ALLOW_WARN (1 << 30) /* For missed irq/seqno simulation. */ unsigned int test_irq_rings; @@ -1281,6 +1189,12 @@ struct ddi_vbt_port_info { uint8_t supports_dp:1; }; +enum drrs_support_type { + DRRS_NOT_SUPPORTED = 0, + STATIC_DRRS_SUPPORT = 1, + SEAMLESS_DRRS_SUPPORT = 2 +}; + struct intel_vbt_data { struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ @@ -1296,6 +1210,8 @@ struct intel_vbt_data { int lvds_ssc_freq; unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ + enum drrs_support_type drrs_type; + /* eDP */ int edp_rate; int edp_lanes; @@ -1315,6 +1231,12 @@ struct intel_vbt_data { /* MIPI DSI */ struct { u16 panel_id; + struct mipi_config *config; + struct mipi_pps_data *pps; + u8 seq_version; + u32 size; + u8 *data; + u8 *sequence[MIPI_SEQ_MAX]; } dsi; int crt_ddc_pin; @@ -1366,23 +1288,13 @@ struct ilk_wm_values { * goes back to false exactly before we reenable the IRQs. We use this variable * to check if someone is trying to enable/disable IRQs while they're supposed * to be disabled. This shouldn't happen and we'll print some error messages in - * case it happens, but if it actually happens we'll also update the variables - * inside struct regsave so when we restore the IRQs they will contain the - * latest expected values. + * case it happens. * * For more, read the Documentation/power/runtime_pm.txt. */ struct i915_runtime_pm { bool suspended; bool irqs_disabled; - - struct { - uint32_t deimr; - uint32_t sdeimr; - uint32_t gtimr; - uint32_t gtier; - uint32_t gen6_pmimr; - } regsave; }; enum intel_pipe_crc_source { @@ -1415,7 +1327,7 @@ struct intel_pipe_crc { wait_queue_head_t wq; }; -typedef struct drm_i915_private { +struct drm_i915_private { struct drm_device *dev; struct kmem_cache *slab; @@ -1484,6 +1396,7 @@ typedef struct drm_i915_private { struct timer_list hotplug_reenable_timer; struct i915_fbc fbc; + struct i915_drrs drrs; struct intel_opregion opregion; struct intel_vbt_data vbt; @@ -1501,6 +1414,7 @@ typedef struct drm_i915_private { int num_fence_regs; /* 8 on pre-965, 16 otherwise */ unsigned int fsb_freq, mem_freq, is_ddr3; + unsigned int vlv_cdclk_freq; /** * wq - Driver workqueue for GEM. @@ -1524,7 +1438,7 @@ typedef struct drm_i915_private { struct mutex modeset_restore_lock; struct list_head vm_list; /* Global list of all address spaces */ - struct i915_gtt gtt; /* VMA representing the global address space */ + struct i915_gtt gtt; /* VM representing the global address space */ struct i915_gem_mm mm; @@ -1595,6 +1509,7 @@ typedef struct drm_i915_private { u32 suspend_count; struct i915_suspend_saved_registers regfile; + struct vlv_s0ix_state vlv_s0ix_state; struct { /* @@ -1620,7 +1535,9 @@ typedef struct drm_i915_private { struct i915_dri1_state dri1; /* Old ums support infrastructure, same warning applies. */ struct i915_ums_state ums; -} drm_i915_private_t; + /* the indicator for dispatch video commands on two BSD rings */ + int ring_index; +}; static inline struct drm_i915_private *to_i915(const struct drm_device *dev) { @@ -1827,6 +1744,7 @@ struct drm_i915_file_private { struct i915_hw_context *private_default_ctx; atomic_t rps_wait_boost; + struct intel_ring_buffer *bsd_ring; }; /* @@ -1894,11 +1812,17 @@ struct drm_i915_cmd_descriptor { * the expected value, the parser rejects it. Only valid if flags has * the CMD_DESC_BITMASK bit set. Only entries where mask is non-zero * are valid. + * + * If the check specifies a non-zero condition_mask then the parser + * only performs the check when the bits specified by condition_mask + * are non-zero. */ struct { u32 offset; u32 mask; u32 expected; + u32 condition_offset; + u32 condition_mask; } bits[MAX_CMD_DESC_BITMASKS]; }; @@ -1940,8 +1864,9 @@ struct drm_i915_cmd_table { (dev)->pdev->device == 0x0106 || \ (dev)->pdev->device == 0x010A) #define IS_VALLEYVIEW(dev) (INTEL_INFO(dev)->is_valleyview) +#define IS_CHERRYVIEW(dev) (INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev)) #define IS_HASWELL(dev) (INTEL_INFO(dev)->is_haswell) -#define IS_BROADWELL(dev) (INTEL_INFO(dev)->gen == 8) +#define IS_BROADWELL(dev) (!INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev)) #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) #define IS_HSW_EARLY_SDV(dev) (IS_HASWELL(dev) && \ ((dev)->pdev->device & 0xFF00) == 0x0C00) @@ -1977,17 +1902,21 @@ struct drm_i915_cmd_table { #define BSD_RING (1<ring_mask & BSD_RING) -#define HAS_BLT(dev) (INTEL_INFO(dev)->ring_mask & BLT_RING) -#define HAS_VEBOX(dev) (INTEL_INFO(dev)->ring_mask & VEBOX_RING) -#define HAS_LLC(dev) (INTEL_INFO(dev)->has_llc) -#define HAS_WT(dev) (IS_HASWELL(dev) && to_i915(dev)->ellc_size) +#define BSD2_RING (1<ring_mask & BSD_RING) +#define HAS_BSD2(dev) (INTEL_INFO(dev)->ring_mask & BSD2_RING) +#define HAS_BLT(dev) (INTEL_INFO(dev)->ring_mask & BLT_RING) +#define HAS_VEBOX(dev) (INTEL_INFO(dev)->ring_mask & VEBOX_RING) +#define HAS_LLC(dev) (INTEL_INFO(dev)->has_llc) +#define HAS_WT(dev) ((IS_HASWELL(dev) || IS_BROADWELL(dev)) && \ + to_i915(dev)->ellc_size) #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) #define HAS_HW_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 6) -#define HAS_ALIASING_PPGTT(dev) (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) -#define HAS_PPGTT(dev) (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev) \ - && !IS_BROADWELL(dev)) +#define HAS_ALIASING_PPGTT(dev) (INTEL_INFO(dev)->gen >= 6 && \ + (!IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))) +#define HAS_PPGTT(dev) (INTEL_INFO(dev)->gen >= 7 \ + && !IS_GEN8(dev)) #define USES_PPGTT(dev) intel_enable_ppgtt(dev, false) #define USES_FULL_PPGTT(dev) intel_enable_ppgtt(dev, true) @@ -2025,8 +1954,8 @@ struct drm_i915_cmd_table { #define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi) #define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg) #define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev)) -#define HAS_PC8(dev) (IS_HASWELL(dev)) /* XXX HSW:ULX */ -#define HAS_RUNTIME_PM(dev) (IS_HASWELL(dev)) +#define HAS_RUNTIME_PM(dev) (IS_GEN6(dev) || IS_HASWELL(dev) || \ + IS_BROADWELL(dev) || IS_VALLEYVIEW(dev)) #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 @@ -2083,6 +2012,7 @@ struct i915_params { bool prefault_disable; bool reset; bool disable_display; + bool disable_vtd_wa; }; extern struct i915_params i915 __read_mostly; @@ -2111,6 +2041,7 @@ extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv); extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv); extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); +int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on); extern void intel_console_resume(struct work_struct *work); @@ -2287,6 +2218,7 @@ struct drm_i915_gem_request * i915_gem_find_active_request(struct intel_ring_buffer *ring); bool i915_gem_retire_requests(struct drm_device *dev); +void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring); int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible); static inline bool i915_reset_in_progress(struct i915_gpu_error *error) @@ -2305,6 +2237,18 @@ static inline u32 i915_reset_count(struct i915_gpu_error *error) return ((atomic_read(&error->reset_counter) & ~I915_WEDGED) + 1) / 2; } +static inline bool i915_stop_ring_allow_ban(struct drm_i915_private *dev_priv) +{ + return dev_priv->gpu_error.stop_rings == 0 || + dev_priv->gpu_error.stop_rings & I915_STOP_RING_ALLOW_BAN; +} + +static inline bool i915_stop_ring_allow_warn(struct drm_i915_private *dev_priv) +{ + return dev_priv->gpu_error.stop_rings == 0 || + dev_priv->gpu_error.stop_rings & I915_STOP_RING_ALLOW_WARN; +} + void i915_gem_reset(struct drm_device *dev); bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force); int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj); @@ -2469,23 +2413,12 @@ int __must_check i915_gem_evict_something(struct drm_device *dev, int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle); int i915_gem_evict_everything(struct drm_device *dev); -/* i915_gem_gtt.c */ -void i915_check_and_clear_faults(struct drm_device *dev); -void i915_gem_suspend_gtt_mappings(struct drm_device *dev); -void i915_gem_restore_gtt_mappings(struct drm_device *dev); -int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj); -void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj); -void i915_gem_init_global_gtt(struct drm_device *dev); -void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, - unsigned long mappable_end, unsigned long end); -int i915_gem_gtt_init(struct drm_device *dev); +/* belongs in i915_gem_gtt.h */ static inline void i915_gem_chipset_flush(struct drm_device *dev) { if (INTEL_INFO(dev)->gen < 6) intel_gtt_chipset_flush(); } -int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); -bool intel_enable_ppgtt(struct drm_device *dev, bool full); /* i915_gem_stolen.c */ int i915_gem_init_stolen(struct drm_device *dev); @@ -2553,6 +2486,7 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone); const char *i915_cache_level_str(int type); /* i915_cmd_parser.c */ +int i915_cmd_parser_get_version(void); void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring); bool i915_needs_cmd_parser(struct intel_ring_buffer *ring); int i915_parse_cmds(struct intel_ring_buffer *ring, @@ -2704,20 +2638,6 @@ void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val); int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val); -void vlv_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine); -void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine); - -#define FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg) \ - (((reg) >= 0x2000 && (reg) < 0x4000) ||\ - ((reg) >= 0x5000 && (reg) < 0x8000) ||\ - ((reg) >= 0xB000 && (reg) < 0x12000) ||\ - ((reg) >= 0x2E000 && (reg) < 0x30000)) - -#define FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)\ - (((reg) >= 0x12000 && (reg) < 0x14000) ||\ - ((reg) >= 0x22000 && (reg) < 0x24000) ||\ - ((reg) >= 0x30000 && (reg) < 0x40000)) - #define FORCEWAKE_RENDER (1 << 0) #define FORCEWAKE_MEDIA (1 << 1) #define FORCEWAKE_ALL (FORCEWAKE_RENDER | FORCEWAKE_MEDIA) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2871ce75f43864..a000a8bf955be3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -43,6 +43,9 @@ static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *o static __must_check int i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, bool readonly); +static void +i915_gem_object_retire(struct drm_i915_gem_object *obj); + static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, @@ -61,7 +64,6 @@ static unsigned long i915_gem_inactive_scan(struct shrinker *shrinker, static unsigned long i915_gem_purge(struct drm_i915_private *dev_priv, long target); static unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv); static void i915_gem_object_truncate(struct drm_i915_gem_object *obj); -static void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring); static bool cpu_cache_is_coherent(struct drm_device *dev, enum i915_cache_level level) @@ -352,6 +354,8 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj, ret = i915_gem_object_wait_rendering(obj, true); if (ret) return ret; + + i915_gem_object_retire(obj); } ret = i915_gem_object_get_pages(obj); @@ -767,6 +771,8 @@ i915_gem_shmem_pwrite(struct drm_device *dev, ret = i915_gem_object_wait_rendering(obj, false); if (ret) return ret; + + i915_gem_object_retire(obj); } /* Same trick applies to invalidate partially written cachelines read * before writing. */ @@ -1154,7 +1160,8 @@ static int i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring) { - i915_gem_retire_requests_ring(ring); + if (!obj->active) + return 0; /* Manually manage the write flush as we may have not yet * retired the buffer. @@ -1164,7 +1171,6 @@ i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj, * we know we have passed the last write. */ obj->last_write_seqno = 0; - obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; return 0; } @@ -1785,58 +1791,58 @@ static unsigned long __i915_gem_shrink(struct drm_i915_private *dev_priv, long target, bool purgeable_only) { - struct list_head still_bound_list; - struct drm_i915_gem_object *obj, *next; + struct list_head still_in_list; + struct drm_i915_gem_object *obj; unsigned long count = 0; - list_for_each_entry_safe(obj, next, - &dev_priv->mm.unbound_list, - global_list) { - if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) && - i915_gem_object_put_pages(obj) == 0) { - count += obj->base.size >> PAGE_SHIFT; - if (count >= target) - return count; - } - } - /* - * As we may completely rewrite the bound list whilst unbinding + * As we may completely rewrite the (un)bound list whilst unbinding * (due to retiring requests) we have to strictly process only * one element of the list at the time, and recheck the list * on every iteration. + * + * In particular, we must hold a reference whilst removing the + * object as we may end up waiting for and/or retiring the objects. + * This might release the final reference (held by the active list) + * and result in the object being freed from under us. This is + * similar to the precautions the eviction code must take whilst + * removing objects. + * + * Also note that although these lists do not hold a reference to + * the object we can safely grab one here: The final object + * unreferencing and the bound_list are both protected by the + * dev->struct_mutex and so we won't ever be able to observe an + * object on the bound_list with a reference count equals 0. */ - INIT_LIST_HEAD(&still_bound_list); + INIT_LIST_HEAD(&still_in_list); + while (count < target && !list_empty(&dev_priv->mm.unbound_list)) { + obj = list_first_entry(&dev_priv->mm.unbound_list, + typeof(*obj), global_list); + list_move_tail(&obj->global_list, &still_in_list); + + if (!i915_gem_object_is_purgeable(obj) && purgeable_only) + continue; + + drm_gem_object_reference(&obj->base); + + if (i915_gem_object_put_pages(obj) == 0) + count += obj->base.size >> PAGE_SHIFT; + + drm_gem_object_unreference(&obj->base); + } + list_splice(&still_in_list, &dev_priv->mm.unbound_list); + + INIT_LIST_HEAD(&still_in_list); while (count < target && !list_empty(&dev_priv->mm.bound_list)) { struct i915_vma *vma, *v; obj = list_first_entry(&dev_priv->mm.bound_list, typeof(*obj), global_list); - list_move_tail(&obj->global_list, &still_bound_list); + list_move_tail(&obj->global_list, &still_in_list); if (!i915_gem_object_is_purgeable(obj) && purgeable_only) continue; - /* - * Hold a reference whilst we unbind this object, as we may - * end up waiting for and retiring requests. This might - * release the final reference (held by the active list) - * and result in the object being freed from under us. - * in this object being freed. - * - * Note 1: Shrinking the bound list is special since only active - * (and hence bound objects) can contain such limbo objects, so - * we don't need special tricks for shrinking the unbound list. - * The only other place where we have to be careful with active - * objects suddenly disappearing due to retiring requests is the - * eviction code. - * - * Note 2: Even though the bound list doesn't hold a reference - * to the object we can safely grab one here: The final object - * unreferencing and the bound_list are both protected by the - * dev->struct_mutex and so we won't ever be able to observe an - * object on the bound_list with a reference count equals 0. - */ drm_gem_object_reference(&obj->base); list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link) @@ -1848,7 +1854,7 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target, drm_gem_object_unreference(&obj->base); } - list_splice(&still_bound_list, &dev_priv->mm.bound_list); + list_splice(&still_in_list, &dev_priv->mm.bound_list); return count; } @@ -1862,17 +1868,8 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target) static unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv) { - struct drm_i915_gem_object *obj, *next; - long freed = 0; - i915_gem_evict_everything(dev_priv->dev); - - list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, - global_list) { - if (i915_gem_object_put_pages(obj) == 0) - freed += obj->base.size >> PAGE_SHIFT; - } - return freed; + return __i915_gem_shrink(dev_priv, LONG_MAX, false); } static int @@ -2089,6 +2086,19 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) WARN_ON(i915_verify_lists(dev)); } +static void +i915_gem_object_retire(struct drm_i915_gem_object *obj) +{ + struct intel_ring_buffer *ring = obj->ring; + + if (ring == NULL) + return; + + if (i915_seqno_passed(ring->get_seqno(ring, true), + obj->last_read_seqno)) + i915_gem_object_move_to_inactive(obj); +} + static int i915_gem_init_seqno(struct drm_device *dev, u32 seqno) { @@ -2108,8 +2118,8 @@ i915_gem_init_seqno(struct drm_device *dev, u32 seqno) for_each_ring(ring, dev_priv, i) { intel_ring_init_seqno(ring, seqno); - for (j = 0; j < ARRAY_SIZE(ring->sync_seqno); j++) - ring->sync_seqno[j] = 0; + for (j = 0; j < ARRAY_SIZE(ring->semaphore.sync_seqno); j++) + ring->semaphore.sync_seqno[j] = 0; } return 0; @@ -2277,8 +2287,9 @@ static bool i915_context_is_banned(struct drm_i915_private *dev_priv, if (!i915_gem_context_is_default(ctx)) { DRM_DEBUG("context hanging too fast, banning!\n"); return true; - } else if (dev_priv->gpu_error.stop_rings == 0) { - DRM_ERROR("gpu hanging too fast, banning!\n"); + } else if (i915_stop_ring_allow_ban(dev_priv)) { + if (i915_stop_ring_allow_warn(dev_priv)) + DRM_ERROR("gpu hanging too fast, banning!\n"); return true; } } @@ -2383,6 +2394,11 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, i915_gem_free_request(request); } + + /* These may not have been flush before the reset, do so now */ + kfree(ring->preallocated_lazy_request); + ring->preallocated_lazy_request = NULL; + ring->outstanding_lazy_seqno = 0; } void i915_gem_restore_fences(struct drm_device *dev) @@ -2423,8 +2439,6 @@ void i915_gem_reset(struct drm_device *dev) for_each_ring(ring, dev_priv, i) i915_gem_reset_ring_cleanup(dev_priv, ring); - i915_gem_cleanup_ringbuffer(dev); - i915_gem_context_reset(dev); i915_gem_restore_fences(dev); @@ -2433,7 +2447,7 @@ void i915_gem_reset(struct drm_device *dev) /** * This function clears the request list as sequence numbers are passed. */ -static void +void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) { uint32_t seqno; @@ -2677,7 +2691,7 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, idx = intel_ring_sync_index(from, to); seqno = obj->last_read_seqno; - if (seqno <= from->sync_seqno[idx]) + if (seqno <= from->semaphore.sync_seqno[idx]) return 0; ret = i915_gem_check_olr(obj->ring, seqno); @@ -2685,13 +2699,13 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, return ret; trace_i915_gem_ring_sync_to(from, to, seqno); - ret = to->sync_to(to, from, seqno); + ret = to->semaphore.sync_to(to, from, seqno); if (!ret) /* We use last_read_seqno because sync_to() * might have just caused seqno wrap under * the radar. */ - from->sync_seqno[idx] = obj->last_read_seqno; + from->semaphore.sync_seqno[idx] = obj->last_read_seqno; return ret; } @@ -3425,6 +3439,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) if (ret) return ret; + i915_gem_object_retire(obj); i915_gem_object_flush_cpu_write_domain(obj, false); /* Serialise direct access to this object with the barriers for @@ -3523,6 +3538,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, * in obj->write_domain and have been skipping the clflushes. * Just set it to the CPU cache for now. */ + i915_gem_object_retire(obj); WARN_ON(obj->base.write_domain & ~I915_GEM_DOMAIN_CPU); old_read_domains = obj->base.read_domains; @@ -3745,6 +3761,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) if (ret) return ret; + i915_gem_object_retire(obj); i915_gem_object_flush_gtt_write_domain(obj); old_write_domain = obj->base.write_domain; @@ -3834,9 +3851,13 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, uint32_t alignment, unsigned flags) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; struct i915_vma *vma; int ret; + if (WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base)) + return -ENODEV; + if (WARN_ON(flags & (PIN_GLOBAL | PIN_MAPPABLE) && !i915_is_ggtt(vm))) return -EINVAL; @@ -4232,6 +4253,17 @@ void i915_gem_vma_destroy(struct i915_vma *vma) kfree(vma); } +static void +i915_gem_stop_ringbuffers(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + int i; + + for_each_ring(ring, dev_priv, i) + intel_stop_ring_buffer(ring); +} + int i915_gem_suspend(struct drm_device *dev) { @@ -4253,7 +4285,7 @@ i915_gem_suspend(struct drm_device *dev) i915_gem_evict_everything(dev); i915_kernel_lost_context(dev); - i915_gem_cleanup_ringbuffer(dev); + i915_gem_stop_ringbuffers(dev); /* Hack! Don't let anybody do execbuf while we don't control the chip. * We need to replace this with a semaphore, or something. @@ -4373,13 +4405,20 @@ static int i915_gem_init_rings(struct drm_device *dev) goto cleanup_blt_ring; } + if (HAS_BSD2(dev)) { + ret = intel_init_bsd2_ring_buffer(dev); + if (ret) + goto cleanup_vebox_ring; + } ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000)); if (ret) - goto cleanup_vebox_ring; + goto cleanup_bsd2_ring; return 0; +cleanup_bsd2_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[VCS2]); cleanup_vebox_ring: intel_cleanup_ring_buffer(&dev_priv->ring[VECS]); cleanup_blt_ring: @@ -4437,15 +4476,11 @@ i915_gem_init_hw(struct drm_device *dev) * the do_switch), but before enabling PPGTT. So don't move this. */ ret = i915_gem_context_enable(dev_priv); - if (ret) { + if (ret && ret != -EIO) { DRM_ERROR("Context enable failed %d\n", ret); - goto err_out; + i915_gem_cleanup_ringbuffer(dev); } - return 0; - -err_out: - i915_gem_cleanup_ringbuffer(dev); return ret; } @@ -4458,8 +4493,9 @@ int i915_gem_init(struct drm_device *dev) if (IS_VALLEYVIEW(dev)) { /* VLVA0 (potential hack), BIOS isn't actually waking us */ - I915_WRITE(VLV_GTLC_WAKE_CTRL, 1); - if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & 1) == 1, 10)) + I915_WRITE(VLV_GTLC_WAKE_CTRL, VLV_GTLC_ALLOWWAKEREQ); + if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & + VLV_GTLC_ALLOWWAKEACK), 10)) DRM_DEBUG_DRIVER("allow wake ack timed out\n"); } @@ -4472,18 +4508,21 @@ int i915_gem_init(struct drm_device *dev) } ret = i915_gem_init_hw(dev); - mutex_unlock(&dev->struct_mutex); - if (ret) { - WARN_ON(dev_priv->mm.aliasing_ppgtt); - i915_gem_context_fini(dev); - drm_mm_takedown(&dev_priv->gtt.base.mm); - return ret; + if (ret == -EIO) { + /* Allow ring initialisation to fail by marking the GPU as + * wedged. But we only want to do this where the GPU is angry, + * for all other failure, such as an allocation failure, bail. + */ + DRM_ERROR("Failed to initialize GPU, declaring it wedged\n"); + atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter); + ret = 0; } + mutex_unlock(&dev->struct_mutex); /* Allow hardware batchbuffers unless told otherwise, but not for KMS. */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) dev_priv->dri1.allow_batchbuffer = 1; - return 0; + return ret; } void @@ -4522,16 +4561,15 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, } BUG_ON(!list_empty(&dev_priv->gtt.base.active_list)); - mutex_unlock(&dev->struct_mutex); - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, dev->pdev->irq); if (ret) goto cleanup_ringbuffer; + mutex_unlock(&dev->struct_mutex); return 0; cleanup_ringbuffer: - mutex_lock(&dev->struct_mutex); i915_gem_cleanup_ringbuffer(dev); dev_priv->ums.mm_suspended = 1; mutex_unlock(&dev->struct_mutex); @@ -4546,7 +4584,9 @@ i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; + mutex_lock(&dev->struct_mutex); drm_irq_uninstall(dev); + mutex_unlock(&dev->struct_mutex); return i915_gem_suspend(dev); } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index d72db15afa02fd..f77b4c126465e1 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -240,7 +240,15 @@ __create_hw_context(struct drm_device *dev, goto err_out; } - if (INTEL_INFO(dev)->gen >= 7) { + /* + * Try to make the context utilize L3 as well as LLC. + * + * On VLV we don't have L3 controls in the PTEs so we + * shouldn't touch the cache level, especially as that + * would make the object snooped which might have a + * negative performance impact. + */ + if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev)) { ret = i915_gem_object_set_cache_level(ctx->obj, I915_CACHE_L3_LLC); /* Failure shouldn't ever happen this early */ @@ -549,7 +557,7 @@ mi_set_context(struct intel_ring_buffer *ring, * explicitly, so we rely on the value at ring init, stored in * itlb_before_ctx_switch. */ - if (IS_GEN6(ring->dev) && ring->itlb_before_ctx_switch) { + if (IS_GEN6(ring->dev)) { ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, 0); if (ret) return ret; @@ -559,8 +567,8 @@ mi_set_context(struct intel_ring_buffer *ring, if (ret) return ret; - /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw */ - if (IS_GEN7(ring->dev)) + /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw */ + if (INTEL_INFO(ring->dev)->gen >= 7) intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE); else intel_ring_emit(ring, MI_NOOP); @@ -578,7 +586,7 @@ mi_set_context(struct intel_ring_buffer *ring, */ intel_ring_emit(ring, MI_NOOP); - if (IS_GEN7(ring->dev)) + if (INTEL_INFO(ring->dev)->gen >= 7) intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_ENABLE); else intel_ring_emit(ring, MI_NOOP); diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c index 9bb533e0d76234..321102a8374ba0 100644 --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c @@ -161,12 +161,8 @@ static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) { struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); struct drm_device *dev = obj->base.dev; - int ret; - - ret = i915_mutex_lock_interruptible(dev); - if (ret) - return; + mutex_lock(&dev->struct_mutex); if (--obj->vmapping_count == 0) { vunmap(obj->dma_buf_vmapping); obj->dma_buf_vmapping = NULL; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 2c9d9cbaf65330..47fe8ecef135fa 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -262,10 +262,12 @@ static inline int use_cpu_reloc(struct drm_i915_gem_object *obj) static int relocate_entry_cpu(struct drm_i915_gem_object *obj, - struct drm_i915_gem_relocation_entry *reloc) + struct drm_i915_gem_relocation_entry *reloc, + uint64_t target_offset) { struct drm_device *dev = obj->base.dev; uint32_t page_offset = offset_in_page(reloc->offset); + uint64_t delta = reloc->delta + target_offset; char *vaddr; int ret; @@ -275,7 +277,7 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj, vaddr = kmap_atomic(i915_gem_object_get_page(obj, reloc->offset >> PAGE_SHIFT)); - *(uint32_t *)(vaddr + page_offset) = reloc->delta; + *(uint32_t *)(vaddr + page_offset) = lower_32_bits(delta); if (INTEL_INFO(dev)->gen >= 8) { page_offset = offset_in_page(page_offset + sizeof(uint32_t)); @@ -286,7 +288,7 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj, (reloc->offset + sizeof(uint32_t)) >> PAGE_SHIFT)); } - *(uint32_t *)(vaddr + page_offset) = 0; + *(uint32_t *)(vaddr + page_offset) = upper_32_bits(delta); } kunmap_atomic(vaddr); @@ -296,10 +298,12 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj, static int relocate_entry_gtt(struct drm_i915_gem_object *obj, - struct drm_i915_gem_relocation_entry *reloc) + struct drm_i915_gem_relocation_entry *reloc, + uint64_t target_offset) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + uint64_t delta = reloc->delta + target_offset; uint32_t __iomem *reloc_entry; void __iomem *reloc_page; int ret; @@ -318,7 +322,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj, reloc->offset & PAGE_MASK); reloc_entry = (uint32_t __iomem *) (reloc_page + offset_in_page(reloc->offset)); - iowrite32(reloc->delta, reloc_entry); + iowrite32(lower_32_bits(delta), reloc_entry); if (INTEL_INFO(dev)->gen >= 8) { reloc_entry += 1; @@ -331,7 +335,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj, reloc_entry = reloc_page; } - iowrite32(0, reloc_entry); + iowrite32(upper_32_bits(delta), reloc_entry); } io_mapping_unmap_atomic(reloc_page); @@ -348,7 +352,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, struct drm_gem_object *target_obj; struct drm_i915_gem_object *target_i915_obj; struct i915_vma *target_vma; - uint32_t target_offset; + uint64_t target_offset; int ret; /* we've already hold a reference to all valid objects */ @@ -426,11 +430,10 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, if (obj->active && in_atomic()) return -EFAULT; - reloc->delta += target_offset; if (use_cpu_reloc(obj)) - ret = relocate_entry_cpu(obj, reloc); + ret = relocate_entry_cpu(obj, reloc, target_offset); else - ret = relocate_entry_gtt(obj, reloc); + ret = relocate_entry_gtt(obj, reloc, target_offset); if (ret) return ret; @@ -955,6 +958,9 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, if (i915_gem_obj_ggtt_bound(obj) && i915_gem_obj_to_ggtt(obj)->pin_count) intel_mark_fb_busy(obj, ring); + + /* update for the implicit flush after a batch */ + obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; } trace_i915_gem_object_change_domain(obj, old_read, old_write); @@ -981,8 +987,10 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; int ret, i; - if (!IS_GEN7(dev) || ring != &dev_priv->ring[RCS]) - return 0; + if (!IS_GEN7(dev) || ring != &dev_priv->ring[RCS]) { + DRM_DEBUG("sol reset is gen7/rcs only\n"); + return -EINVAL; + } ret = intel_ring_begin(ring, 4 * 3); if (ret) @@ -999,6 +1007,37 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev, return 0; } +/** + * Find one BSD ring to dispatch the corresponding BSD command. + * The Ring ID is returned. + */ +static int gen8_dispatch_bsd_ring(struct drm_device *dev, + struct drm_file *file) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_file_private *file_priv = file->driver_priv; + + /* Check whether the file_priv is using one ring */ + if (file_priv->bsd_ring) + return file_priv->bsd_ring->id; + else { + /* If no, use the ping-pong mechanism to select one ring */ + int ring_id; + + mutex_lock(&dev->struct_mutex); + if (dev_priv->ring_index == 0) { + ring_id = VCS; + dev_priv->ring_index = 1; + } else { + ring_id = VCS2; + dev_priv->ring_index = 0; + } + file_priv->bsd_ring = &dev_priv->ring[ring_id]; + mutex_unlock(&dev->struct_mutex); + return ring_id; + } +} + static int i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_file *file, @@ -1013,7 +1052,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct i915_hw_context *ctx; struct i915_address_space *vm; const u32 ctx_id = i915_execbuffer2_get_context_id(*args); - u32 exec_start = args->batch_start_offset, exec_len; + u64 exec_start = args->batch_start_offset, exec_len; u32 mask, flags; int ret, mode, i; bool need_relocs; @@ -1035,7 +1074,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (args->flags & I915_EXEC_IS_PINNED) flags |= I915_DISPATCH_PINNED; - if ((args->flags & I915_EXEC_RING_MASK) > I915_NUM_RINGS) { + if ((args->flags & I915_EXEC_RING_MASK) > LAST_USER_RING) { DRM_DEBUG("execbuf with unknown ring: %d\n", (int)(args->flags & I915_EXEC_RING_MASK)); return -EINVAL; @@ -1043,7 +1082,14 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_DEFAULT) ring = &dev_priv->ring[RCS]; - else + else if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_BSD) { + if (HAS_BSD2(dev)) { + int ring_id; + ring_id = gen8_dispatch_bsd_ring(dev, file); + ring = &dev_priv->ring[ring_id]; + } else + ring = &dev_priv->ring[VCS]; + } else ring = &dev_priv->ring[(args->flags & I915_EXEC_RING_MASK) - 1]; if (!intel_ring_initialized(ring)) { @@ -1058,14 +1104,22 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, case I915_EXEC_CONSTANTS_REL_GENERAL: case I915_EXEC_CONSTANTS_ABSOLUTE: case I915_EXEC_CONSTANTS_REL_SURFACE: - if (ring == &dev_priv->ring[RCS] && - mode != dev_priv->relative_constants_mode) { - if (INTEL_INFO(dev)->gen < 4) + if (mode != 0 && ring != &dev_priv->ring[RCS]) { + DRM_DEBUG("non-0 rel constants mode on non-RCS\n"); + return -EINVAL; + } + + if (mode != dev_priv->relative_constants_mode) { + if (INTEL_INFO(dev)->gen < 4) { + DRM_DEBUG("no rel constants on pre-gen4\n"); return -EINVAL; + } if (INTEL_INFO(dev)->gen > 5 && - mode == I915_EXEC_CONSTANTS_REL_SURFACE) + mode == I915_EXEC_CONSTANTS_REL_SURFACE) { + DRM_DEBUG("rel surface constants mode invalid on gen5+\n"); return -EINVAL; + } /* The HW changed the meaning on this bit on gen6 */ if (INTEL_INFO(dev)->gen >= 6) @@ -1113,6 +1167,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, ret = -EFAULT; goto pre_mutex_err; } + } else { + if (args->DR1 || args->DR4 || args->cliprects_ptr) { + DRM_DEBUG("0 cliprects but dirt in cliprects fields\n"); + return -EINVAL; + } } intel_runtime_pm_get(dev_priv); @@ -1132,7 +1191,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, mutex_unlock(&dev->struct_mutex); ret = PTR_ERR(ctx); goto pre_mutex_err; - } + } i915_gem_context_reference(ctx); @@ -1142,6 +1201,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, eb = eb_create(args); if (eb == NULL) { + i915_gem_context_unreference(ctx); mutex_unlock(&dev->struct_mutex); ret = -ENOMEM; goto pre_mutex_err; @@ -1389,6 +1449,11 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, return -EINVAL; } + if (args->rsvd2 != 0) { + DRM_DEBUG("dirty rvsd2 field\n"); + return -EINVAL; + } + exec2_list = kmalloc(sizeof(*exec2_list)*args->buffer_count, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); if (exec2_list == NULL) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 154b0f8bb88de0..f59cec08fab79d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -30,7 +30,8 @@ #include "i915_trace.h" #include "intel_drv.h" -static void gen8_setup_private_ppat(struct drm_i915_private *dev_priv); +static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv); +static void chv_setup_private_ppat(struct drm_i915_private *dev_priv); bool intel_enable_ppgtt(struct drm_device *dev, bool full) { @@ -65,59 +66,6 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt) return HAS_ALIASING_PPGTT(dev) ? 1 : 0; } -#define GEN6_PPGTT_PD_ENTRIES 512 -#define I915_PPGTT_PT_ENTRIES (PAGE_SIZE / sizeof(gen6_gtt_pte_t)) -typedef uint64_t gen8_gtt_pte_t; -typedef gen8_gtt_pte_t gen8_ppgtt_pde_t; - -/* PPGTT stuff */ -#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0)) -#define HSW_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0x7f0)) - -#define GEN6_PDE_VALID (1 << 0) -/* gen6+ has bit 11-4 for physical addr bit 39-32 */ -#define GEN6_PDE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) - -#define GEN6_PTE_VALID (1 << 0) -#define GEN6_PTE_UNCACHED (1 << 1) -#define HSW_PTE_UNCACHED (0) -#define GEN6_PTE_CACHE_LLC (2 << 1) -#define GEN7_PTE_CACHE_L3_LLC (3 << 1) -#define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) -#define HSW_PTE_ADDR_ENCODE(addr) HSW_GTT_ADDR_ENCODE(addr) - -/* Cacheability Control is a 4-bit value. The low three bits are stored in * - * bits 3:1 of the PTE, while the fourth bit is stored in bit 11 of the PTE. - */ -#define HSW_CACHEABILITY_CONTROL(bits) ((((bits) & 0x7) << 1) | \ - (((bits) & 0x8) << (11 - 3))) -#define HSW_WB_LLC_AGE3 HSW_CACHEABILITY_CONTROL(0x2) -#define HSW_WB_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0x3) -#define HSW_WB_ELLC_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0xb) -#define HSW_WB_ELLC_LLC_AGE3 HSW_CACHEABILITY_CONTROL(0x8) -#define HSW_WT_ELLC_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0x6) -#define HSW_WT_ELLC_LLC_AGE3 HSW_CACHEABILITY_CONTROL(0x7) - -#define GEN8_PTES_PER_PAGE (PAGE_SIZE / sizeof(gen8_gtt_pte_t)) -#define GEN8_PDES_PER_PAGE (PAGE_SIZE / sizeof(gen8_ppgtt_pde_t)) - -/* GEN8 legacy style addressis defined as a 3 level page table: - * 31:30 | 29:21 | 20:12 | 11:0 - * PDPE | PDE | PTE | offset - * The difference as compared to normal x86 3 level page table is the PDPEs are - * programmed via register. - */ -#define GEN8_PDPE_SHIFT 30 -#define GEN8_PDPE_MASK 0x3 -#define GEN8_PDE_SHIFT 21 -#define GEN8_PDE_MASK 0x1ff -#define GEN8_PTE_SHIFT 12 -#define GEN8_PTE_MASK 0x1ff - -#define PPAT_UNCACHED_INDEX (_PAGE_PWT | _PAGE_PCD) -#define PPAT_CACHED_PDE_INDEX 0 /* WB LLC */ -#define PPAT_CACHED_INDEX _PAGE_PAT /* WB LLCeLLC */ -#define PPAT_DISPLAY_ELLC_INDEX _PAGE_PCD /* WT eLLC */ static void ppgtt_bind_vma(struct i915_vma *vma, enum i915_cache_level cache_level, @@ -131,10 +79,19 @@ static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr, { gen8_gtt_pte_t pte = valid ? _PAGE_PRESENT | _PAGE_RW : 0; pte |= addr; - if (level != I915_CACHE_NONE) - pte |= PPAT_CACHED_INDEX; - else + + switch (level) { + case I915_CACHE_NONE: pte |= PPAT_UNCACHED_INDEX; + break; + case I915_CACHE_WT: + pte |= PPAT_DISPLAY_ELLC_INDEX; + break; + default: + pte |= PPAT_CACHED_INDEX; + break; + } + return pte; } @@ -197,9 +154,6 @@ static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr, return pte; } -#define BYT_PTE_WRITEABLE (1 << 1) -#define BYT_PTE_SNOOPED_BY_CPU_CACHES (1 << 2) - static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr, enum i915_cache_level level, bool valid) @@ -332,6 +286,8 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, num_entries--; } + if (!HAS_LLC(ppgtt->base.dev)) + drm_clflush_virt_range(pt_vaddr, PAGE_SIZE); kunmap_atomic(pt_vaddr); pte = 0; @@ -368,6 +324,8 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, gen8_pte_encode(sg_page_iter_dma_address(&sg_iter), cache_level, true); if (++pte == GEN8_PTES_PER_PAGE) { + if (!HAS_LLC(ppgtt->base.dev)) + drm_clflush_virt_range(pt_vaddr, PAGE_SIZE); kunmap_atomic(pt_vaddr); pt_vaddr = NULL; if (++pde == GEN8_PDES_PER_PAGE) { @@ -377,8 +335,11 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, pte = 0; } } - if (pt_vaddr) + if (pt_vaddr) { + if (!HAS_LLC(ppgtt->base.dev)) + drm_clflush_virt_range(pt_vaddr, PAGE_SIZE); kunmap_atomic(pt_vaddr); + } } static void gen8_free_page_tables(struct page **pt_pages) @@ -641,6 +602,8 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size) pd_vaddr[j] = gen8_pde_encode(ppgtt->base.dev, addr, I915_CACHE_LLC); } + if (!HAS_LLC(ppgtt->base.dev)) + drm_clflush_virt_range(pd_vaddr, PAGE_SIZE); kunmap_atomic(pd_vaddr); } @@ -1067,8 +1030,6 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) { -#define GEN6_PD_ALIGN (PAGE_SIZE * 16) -#define GEN6_PD_SIZE (GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE) struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; bool retried = false; @@ -1084,8 +1045,7 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) &ppgtt->node, GEN6_PD_SIZE, GEN6_PD_ALIGN, 0, 0, dev_priv->gtt.base.total, - DRM_MM_SEARCH_DEFAULT, - DRM_MM_CREATE_DEFAULT); + DRM_MM_TOPDOWN); if (ret == -ENOSPC && !retried) { ret = i915_gem_evict_something(dev, &dev_priv->gtt.base, GEN6_PD_SIZE, GEN6_PD_ALIGN, @@ -1384,7 +1344,11 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) if (INTEL_INFO(dev)->gen >= 8) { - gen8_setup_private_ppat(dev_priv); + if (IS_CHERRYVIEW(dev)) + chv_setup_private_ppat(dev_priv); + else + bdw_setup_private_ppat(dev_priv); + return; } @@ -1436,7 +1400,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm, (gen8_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; int i = 0; struct sg_page_iter sg_iter; - dma_addr_t addr; + dma_addr_t addr = 0; for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) { addr = sg_dma_address(sg_iter.sg) + @@ -1856,19 +1820,8 @@ static int ggtt_probe_common(struct drm_device *dev, /* The GGTT and PPGTT need a private PPAT setup in order to handle cacheability * bits. When using advanced contexts each context stores its own PAT, but * writing this data shouldn't be harmful even in those cases. */ -static void gen8_setup_private_ppat(struct drm_i915_private *dev_priv) -{ -#define GEN8_PPAT_UC (0<<0) -#define GEN8_PPAT_WC (1<<0) -#define GEN8_PPAT_WT (2<<0) -#define GEN8_PPAT_WB (3<<0) -#define GEN8_PPAT_ELLC_OVERRIDE (0<<2) -/* FIXME(BDW): Bspec is completely confused about cache control bits. */ -#define GEN8_PPAT_LLC (1<<2) -#define GEN8_PPAT_LLCELLC (2<<2) -#define GEN8_PPAT_LLCeLLC (3<<2) -#define GEN8_PPAT_AGE(x) (x<<4) -#define GEN8_PPAT(i, x) ((uint64_t) (x) << ((i) * 8)) +static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv) +{ uint64_t pat; pat = GEN8_PPAT(0, GEN8_PPAT_WB | GEN8_PPAT_LLC) | /* for normal objects, no eLLC */ @@ -1886,6 +1839,33 @@ static void gen8_setup_private_ppat(struct drm_i915_private *dev_priv) I915_WRITE(GEN8_PRIVATE_PAT + 4, pat >> 32); } +static void chv_setup_private_ppat(struct drm_i915_private *dev_priv) +{ + uint64_t pat; + + /* + * Map WB on BDW to snooped on CHV. + * + * Only the snoop bit has meaning for CHV, the rest is + * ignored. + * + * Note that the harware enforces snooping for all page + * table accesses. The snoop bit is actually ignored for + * PDEs. + */ + pat = GEN8_PPAT(0, CHV_PPAT_SNOOP) | + GEN8_PPAT(1, 0) | + GEN8_PPAT(2, 0) | + GEN8_PPAT(3, 0) | + GEN8_PPAT(4, CHV_PPAT_SNOOP) | + GEN8_PPAT(5, CHV_PPAT_SNOOP) | + GEN8_PPAT(6, CHV_PPAT_SNOOP) | + GEN8_PPAT(7, CHV_PPAT_SNOOP); + + I915_WRITE(GEN8_PRIVATE_PAT, pat); + I915_WRITE(GEN8_PRIVATE_PAT + 4, pat >> 32); +} + static int gen8_gmch_probe(struct drm_device *dev, size_t *gtt_total, size_t *stolen, @@ -1911,7 +1891,10 @@ static int gen8_gmch_probe(struct drm_device *dev, gtt_size = gen8_get_total_gtt_size(snb_gmch_ctl); *gtt_total = (gtt_size / sizeof(gen8_gtt_pte_t)) << PAGE_SHIFT; - gen8_setup_private_ppat(dev_priv); + if (IS_CHERRYVIEW(dev)) + chv_setup_private_ppat(dev_priv); + else + bdw_setup_private_ppat(dev_priv); ret = ggtt_probe_common(dev, gtt_size); @@ -2050,6 +2033,11 @@ int i915_gem_gtt_init(struct drm_device *dev) i915.enable_ppgtt = sanitize_enable_ppgtt(dev, i915.enable_ppgtt); DRM_DEBUG_DRIVER("ppgtt mode: %i\n", i915.enable_ppgtt); +#ifdef CONFIG_INTEL_IOMMU + if (intel_iommu_gfx_mapped) + DRM_INFO("VT-d active for gfx access\n"); +#endif + return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h new file mode 100644 index 00000000000000..cfca023c4076c8 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -0,0 +1,284 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Please try to maintain the following order within this file unless it makes + * sense to do otherwise. From top to bottom: + * 1. typedefs + * 2. #defines, and macros + * 3. structure definitions + * 4. function prototypes + * + * Within each section, please try to order by generation in ascending order, + * from top to bottom (ie. gen6 on the top, gen8 on the bottom). + */ + +#ifndef __I915_GEM_GTT_H__ +#define __I915_GEM_GTT_H__ + +typedef uint32_t gen6_gtt_pte_t; +typedef uint64_t gen8_gtt_pte_t; +typedef gen8_gtt_pte_t gen8_ppgtt_pde_t; + +#define gtt_total_entries(gtt) ((gtt).base.total >> PAGE_SHIFT) + +#define I915_PPGTT_PT_ENTRIES (PAGE_SIZE / sizeof(gen6_gtt_pte_t)) +/* gen6-hsw has bit 11-4 for physical addr bit 39-32 */ +#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0)) +#define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) +#define GEN6_PDE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) +#define GEN6_PTE_CACHE_LLC (2 << 1) +#define GEN6_PTE_UNCACHED (1 << 1) +#define GEN6_PTE_VALID (1 << 0) + +#define GEN6_PPGTT_PD_ENTRIES 512 +#define GEN6_PD_SIZE (GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE) +#define GEN6_PD_ALIGN (PAGE_SIZE * 16) +#define GEN6_PDE_VALID (1 << 0) + +#define GEN7_PTE_CACHE_L3_LLC (3 << 1) + +#define BYT_PTE_SNOOPED_BY_CPU_CACHES (1 << 2) +#define BYT_PTE_WRITEABLE (1 << 1) + +/* Cacheability Control is a 4-bit value. The low three bits are stored in bits + * 3:1 of the PTE, while the fourth bit is stored in bit 11 of the PTE. + */ +#define HSW_CACHEABILITY_CONTROL(bits) ((((bits) & 0x7) << 1) | \ + (((bits) & 0x8) << (11 - 3))) +#define HSW_WB_LLC_AGE3 HSW_CACHEABILITY_CONTROL(0x2) +#define HSW_WB_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0x3) +#define HSW_WB_ELLC_LLC_AGE3 HSW_CACHEABILITY_CONTROL(0x8) +#define HSW_WB_ELLC_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0xb) +#define HSW_WT_ELLC_LLC_AGE3 HSW_CACHEABILITY_CONTROL(0x7) +#define HSW_WT_ELLC_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0x6) +#define HSW_PTE_UNCACHED (0) +#define HSW_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0x7f0)) +#define HSW_PTE_ADDR_ENCODE(addr) HSW_GTT_ADDR_ENCODE(addr) + +/* GEN8 legacy style address is defined as a 3 level page table: + * 31:30 | 29:21 | 20:12 | 11:0 + * PDPE | PDE | PTE | offset + * The difference as compared to normal x86 3 level page table is the PDPEs are + * programmed via register. + */ +#define GEN8_PDPE_SHIFT 30 +#define GEN8_PDPE_MASK 0x3 +#define GEN8_PDE_SHIFT 21 +#define GEN8_PDE_MASK 0x1ff +#define GEN8_PTE_SHIFT 12 +#define GEN8_PTE_MASK 0x1ff +#define GEN8_LEGACY_PDPS 4 +#define GEN8_PTES_PER_PAGE (PAGE_SIZE / sizeof(gen8_gtt_pte_t)) +#define GEN8_PDES_PER_PAGE (PAGE_SIZE / sizeof(gen8_ppgtt_pde_t)) + +#define PPAT_UNCACHED_INDEX (_PAGE_PWT | _PAGE_PCD) +#define PPAT_CACHED_PDE_INDEX 0 /* WB LLC */ +#define PPAT_CACHED_INDEX _PAGE_PAT /* WB LLCeLLC */ +#define PPAT_DISPLAY_ELLC_INDEX _PAGE_PCD /* WT eLLC */ + +#define CHV_PPAT_SNOOP (1<<6) +#define GEN8_PPAT_AGE(x) (x<<4) +#define GEN8_PPAT_LLCeLLC (3<<2) +#define GEN8_PPAT_LLCELLC (2<<2) +#define GEN8_PPAT_LLC (1<<2) +#define GEN8_PPAT_WB (3<<0) +#define GEN8_PPAT_WT (2<<0) +#define GEN8_PPAT_WC (1<<0) +#define GEN8_PPAT_UC (0<<0) +#define GEN8_PPAT_ELLC_OVERRIDE (0<<2) +#define GEN8_PPAT(i, x) ((uint64_t) (x) << ((i) * 8)) + +enum i915_cache_level; +/** + * A VMA represents a GEM BO that is bound into an address space. Therefore, a + * VMA's presence cannot be guaranteed before binding, or after unbinding the + * object into/from the address space. + * + * To make things as simple as possible (ie. no refcounting), a VMA's lifetime + * will always be <= an objects lifetime. So object refcounting should cover us. + */ +struct i915_vma { + struct drm_mm_node node; + struct drm_i915_gem_object *obj; + struct i915_address_space *vm; + + /** This object's place on the active/inactive lists */ + struct list_head mm_list; + + struct list_head vma_link; /* Link in the object's VMA list */ + + /** This vma's place in the batchbuffer or on the eviction list */ + struct list_head exec_list; + + /** + * Used for performing relocations during execbuffer insertion. + */ + struct hlist_node exec_node; + unsigned long exec_handle; + struct drm_i915_gem_exec_object2 *exec_entry; + + /** + * How many users have pinned this object in GTT space. The following + * users can each hold at most one reference: pwrite/pread, pin_ioctl + * (via user_pin_count), execbuffer (objects are not allowed multiple + * times for the same batchbuffer), and the framebuffer code. When + * switching/pageflipping, the framebuffer code has at most two buffers + * pinned per crtc. + * + * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3 + * bits with absolutely no headroom. So use 4 bits. */ + unsigned int pin_count:4; +#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf + + /** Unmap an object from an address space. This usually consists of + * setting the valid PTE entries to a reserved scratch page. */ + void (*unbind_vma)(struct i915_vma *vma); + /* Map an object into an address space with the given cache flags. */ +#define GLOBAL_BIND (1<<0) + void (*bind_vma)(struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 flags); +}; + +struct i915_address_space { + struct drm_mm mm; + struct drm_device *dev; + struct list_head global_link; + unsigned long start; /* Start offset always 0 for dri2 */ + size_t total; /* size addr space maps (ex. 2GB for ggtt) */ + + struct { + dma_addr_t addr; + struct page *page; + } scratch; + + /** + * List of objects currently involved in rendering. + * + * Includes buffers having the contents of their GPU caches + * flushed, not necessarily primitives. last_rendering_seqno + * represents when the rendering involved will be completed. + * + * A reference is held on the buffer while on this list. + */ + struct list_head active_list; + + /** + * LRU list of objects which are not in the ringbuffer and + * are ready to unbind, but are still in the GTT. + * + * last_rendering_seqno is 0 while an object is in this list. + * + * A reference is not held on the buffer while on this list, + * as merely being GTT-bound shouldn't prevent its being + * freed, and we'll pull it off the list in the free path. + */ + struct list_head inactive_list; + + /* FIXME: Need a more generic return type */ + gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr, + enum i915_cache_level level, + bool valid); /* Create a valid PTE */ + void (*clear_range)(struct i915_address_space *vm, + uint64_t start, + uint64_t length, + bool use_scratch); + void (*insert_entries)(struct i915_address_space *vm, + struct sg_table *st, + uint64_t start, + enum i915_cache_level cache_level); + void (*cleanup)(struct i915_address_space *vm); +}; + +/* The Graphics Translation Table is the way in which GEN hardware translates a + * Graphics Virtual Address into a Physical Address. In addition to the normal + * collateral associated with any va->pa translations GEN hardware also has a + * portion of the GTT which can be mapped by the CPU and remain both coherent + * and correct (in cases like swizzling). That region is referred to as GMADR in + * the spec. + */ +struct i915_gtt { + struct i915_address_space base; + size_t stolen_size; /* Total size of stolen memory */ + + unsigned long mappable_end; /* End offset that we can CPU map */ + struct io_mapping *mappable; /* Mapping to our CPU mappable region */ + phys_addr_t mappable_base; /* PA of our GMADR */ + + /** "Graphics Stolen Memory" holds the global PTEs */ + void __iomem *gsm; + + bool do_idle_maps; + + int mtrr; + + /* global gtt ops */ + int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total, + size_t *stolen, phys_addr_t *mappable_base, + unsigned long *mappable_end); +}; + +struct i915_hw_ppgtt { + struct i915_address_space base; + struct kref ref; + struct drm_mm_node node; + unsigned num_pd_entries; + unsigned num_pd_pages; /* gen8+ */ + union { + struct page **pt_pages; + struct page **gen8_pt_pages[GEN8_LEGACY_PDPS]; + }; + struct page *pd_pages; + union { + uint32_t pd_offset; + dma_addr_t pd_dma_addr[GEN8_LEGACY_PDPS]; + }; + union { + dma_addr_t *pt_dma_addr; + dma_addr_t *gen8_pt_dma_addr[4]; + }; + + struct i915_hw_context *ctx; + + int (*enable)(struct i915_hw_ppgtt *ppgtt); + int (*switch_mm)(struct i915_hw_ppgtt *ppgtt, + struct intel_ring_buffer *ring, + bool synchronous); + void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m); +}; + +int i915_gem_gtt_init(struct drm_device *dev); +void i915_gem_init_global_gtt(struct drm_device *dev); +void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, + unsigned long mappable_end, unsigned long end); + +bool intel_enable_ppgtt(struct drm_device *dev, bool full); +int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); + +void i915_check_and_clear_faults(struct drm_device *dev); +void i915_gem_suspend_gtt_mappings(struct drm_device *dev); +void i915_gem_restore_gtt_mappings(struct drm_device *dev); + +int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj); +void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj); + +#endif diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 12f1d43b2d68fb..2d819858c19b03 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -42,6 +42,7 @@ static const char *ring_str(int ring) case VCS: return "bsd"; case BCS: return "blt"; case VECS: return "vebox"; + case VCS2: return "bsd2"; default: return ""; } } @@ -257,7 +258,8 @@ static void i915_ring_error_state(struct drm_i915_error_state_buf *m, err_printf(m, " INSTPS: 0x%08x\n", ring->instps); } err_printf(m, " INSTPM: 0x%08x\n", ring->instpm); - err_printf(m, " FADDR: 0x%08x\n", ring->faddr); + err_printf(m, " FADDR: 0x%08x %08x\n", upper_32_bits(ring->faddr), + lower_32_bits(ring->faddr)); if (INTEL_INFO(dev)->gen >= 6) { err_printf(m, " RC PSMI: 0x%08x\n", ring->rc_psmi); err_printf(m, " FAULT_REG: 0x%08x\n", ring->fault_reg); @@ -452,16 +454,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, err_printf(m, "%s --- HW Context = 0x%08x\n", dev_priv->ring[i].name, obj->gtt_offset); - offset = 0; - for (elt = 0; elt < PAGE_SIZE/16; elt += 4) { - err_printf(m, "[%04x] %08x %08x %08x %08x\n", - offset, - obj->pages[0][elt], - obj->pages[0][elt+1], - obj->pages[0][elt+2], - obj->pages[0][elt+3]); - offset += 16; - } + print_error_obj(m, obj); } } @@ -764,14 +757,14 @@ static void i915_record_ring_state(struct drm_device *dev, = I915_READ(RING_SYNC_0(ring->mmio_base)); ering->semaphore_mboxes[1] = I915_READ(RING_SYNC_1(ring->mmio_base)); - ering->semaphore_seqno[0] = ring->sync_seqno[0]; - ering->semaphore_seqno[1] = ring->sync_seqno[1]; + ering->semaphore_seqno[0] = ring->semaphore.sync_seqno[0]; + ering->semaphore_seqno[1] = ring->semaphore.sync_seqno[1]; } if (HAS_VEBOX(dev)) { ering->semaphore_mboxes[2] = I915_READ(RING_SYNC_2(ring->mmio_base)); - ering->semaphore_seqno[2] = ring->sync_seqno[2]; + ering->semaphore_seqno[2] = ring->semaphore.sync_seqno[2]; } if (INTEL_INFO(dev)->gen >= 4) { @@ -781,8 +774,10 @@ static void i915_record_ring_state(struct drm_device *dev, ering->instdone = I915_READ(RING_INSTDONE(ring->mmio_base)); ering->instps = I915_READ(RING_INSTPS(ring->mmio_base)); ering->bbaddr = I915_READ(RING_BBADDR(ring->mmio_base)); - if (INTEL_INFO(dev)->gen >= 8) + if (INTEL_INFO(dev)->gen >= 8) { + ering->faddr |= (u64) I915_READ(RING_DMA_FADD_UDW(ring->mmio_base)) << 32; ering->bbaddr |= (u64) I915_READ(RING_BBADDR_UDW(ring->mmio_base)) << 32; + } ering->bbstate = I915_READ(RING_BBSTATE(ring->mmio_base)); } else { ering->faddr = I915_READ(DMA_FADD_I8XX); @@ -875,10 +870,7 @@ static void i915_gem_record_active_context(struct intel_ring_buffer *ring, list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { if ((error->ccid & PAGE_MASK) == i915_gem_obj_ggtt_offset(obj)) { - ering->ctx = i915_error_object_create_sized(dev_priv, - obj, - &dev_priv->gtt.base, - 1); + ering->ctx = i915_error_ggtt_object_create(dev_priv, obj); break; } } @@ -1037,7 +1029,6 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv, struct drm_i915_error_state *error) { struct drm_device *dev = dev_priv->dev; - int pipe; /* General organization * 1. Registers specific to a single generation @@ -1062,9 +1053,6 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv, error->gfx_mode = I915_READ(GFX_MODE); } - if (IS_GEN2(dev)) - error->ier = I915_READ16(IER); - /* 2: Registers which belong to multiple generations */ if (INTEL_INFO(dev)->gen >= 7) error->forcewake = I915_READ(FORCEWAKE_MT); @@ -1088,9 +1076,10 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv, if (HAS_PCH_SPLIT(dev)) error->ier = I915_READ(DEIER) | I915_READ(GTIER); else { - error->ier = I915_READ(IER); - for_each_pipe(pipe) - error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); + if (IS_GEN2(dev)) + error->ier = I915_READ16(IER); + else + error->ier = I915_READ(IER); } /* 4: Everything else */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f98ba4e6e70b94..8ea5bcb3b15cbd 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -80,17 +80,64 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS }; +/* IIR can theoretically queue up two events. Be paranoid. */ +#define GEN8_IRQ_RESET_NDX(type, which) do { \ + I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ + POSTING_READ(GEN8_##type##_IMR(which)); \ + I915_WRITE(GEN8_##type##_IER(which), 0); \ + I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ + POSTING_READ(GEN8_##type##_IIR(which)); \ + I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ + POSTING_READ(GEN8_##type##_IIR(which)); \ +} while (0) + +#define GEN5_IRQ_RESET(type) do { \ + I915_WRITE(type##IMR, 0xffffffff); \ + POSTING_READ(type##IMR); \ + I915_WRITE(type##IER, 0); \ + I915_WRITE(type##IIR, 0xffffffff); \ + POSTING_READ(type##IIR); \ + I915_WRITE(type##IIR, 0xffffffff); \ + POSTING_READ(type##IIR); \ +} while (0) + +/* + * We should clear IMR at preinstall/uninstall, and just check at postinstall. + */ +#define GEN5_ASSERT_IIR_IS_ZERO(reg) do { \ + u32 val = I915_READ(reg); \ + if (val) { \ + WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n", \ + (reg), val); \ + I915_WRITE((reg), 0xffffffff); \ + POSTING_READ(reg); \ + I915_WRITE((reg), 0xffffffff); \ + POSTING_READ(reg); \ + } \ +} while (0) + +#define GEN8_IRQ_INIT_NDX(type, which, imr_val, ier_val) do { \ + GEN5_ASSERT_IIR_IS_ZERO(GEN8_##type##_IIR(which)); \ + I915_WRITE(GEN8_##type##_IMR(which), (imr_val)); \ + I915_WRITE(GEN8_##type##_IER(which), (ier_val)); \ + POSTING_READ(GEN8_##type##_IER(which)); \ +} while (0) + +#define GEN5_IRQ_INIT(type, imr_val, ier_val) do { \ + GEN5_ASSERT_IIR_IS_ZERO(type##IIR); \ + I915_WRITE(type##IMR, (imr_val)); \ + I915_WRITE(type##IER, (ier_val)); \ + POSTING_READ(type##IER); \ +} while (0) + /* For display hotplug interrupt */ static void ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask) { assert_spin_locked(&dev_priv->irq_lock); - if (dev_priv->pm.irqs_disabled) { - WARN(1, "IRQs disabled\n"); - dev_priv->pm.regsave.deimr &= ~mask; + if (WARN_ON(dev_priv->pm.irqs_disabled)) return; - } if ((dev_priv->irq_mask & mask) != 0) { dev_priv->irq_mask &= ~mask; @@ -104,11 +151,8 @@ ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask) { assert_spin_locked(&dev_priv->irq_lock); - if (dev_priv->pm.irqs_disabled) { - WARN(1, "IRQs disabled\n"); - dev_priv->pm.regsave.deimr |= mask; + if (WARN_ON(dev_priv->pm.irqs_disabled)) return; - } if ((dev_priv->irq_mask & mask) != mask) { dev_priv->irq_mask |= mask; @@ -129,13 +173,8 @@ static void ilk_update_gt_irq(struct drm_i915_private *dev_priv, { assert_spin_locked(&dev_priv->irq_lock); - if (dev_priv->pm.irqs_disabled) { - WARN(1, "IRQs disabled\n"); - dev_priv->pm.regsave.gtimr &= ~interrupt_mask; - dev_priv->pm.regsave.gtimr |= (~enabled_irq_mask & - interrupt_mask); + if (WARN_ON(dev_priv->pm.irqs_disabled)) return; - } dev_priv->gt_irq_mask &= ~interrupt_mask; dev_priv->gt_irq_mask |= (~enabled_irq_mask & interrupt_mask); @@ -167,13 +206,8 @@ static void snb_update_pm_irq(struct drm_i915_private *dev_priv, assert_spin_locked(&dev_priv->irq_lock); - if (dev_priv->pm.irqs_disabled) { - WARN(1, "IRQs disabled\n"); - dev_priv->pm.regsave.gen6_pmimr &= ~interrupt_mask; - dev_priv->pm.regsave.gen6_pmimr |= (~enabled_irq_mask & - interrupt_mask); + if (WARN_ON(dev_priv->pm.irqs_disabled)) return; - } new_val = dev_priv->pm_irq_mask; new_val &= ~interrupt_mask; @@ -313,14 +347,8 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv, assert_spin_locked(&dev_priv->irq_lock); - if (dev_priv->pm.irqs_disabled && - (interrupt_mask & SDE_HOTPLUG_MASK_CPT)) { - WARN(1, "IRQs disabled\n"); - dev_priv->pm.regsave.sdeimr &= ~interrupt_mask; - dev_priv->pm.regsave.sdeimr |= (~enabled_irq_mask & - interrupt_mask); + if (WARN_ON(dev_priv->pm.irqs_disabled)) return; - } I915_WRITE(SDEIMR, sdeimr); POSTING_READ(SDEIMR); @@ -503,8 +531,10 @@ __i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, assert_spin_locked(&dev_priv->irq_lock); - if (WARN_ON_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK || - status_mask & ~PIPESTAT_INT_STATUS_MASK)) + if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK || + status_mask & ~PIPESTAT_INT_STATUS_MASK, + "pipe %c: enable_mask=0x%x, status_mask=0x%x\n", + pipe_name(pipe), enable_mask, status_mask)) return; if ((pipestat & enable_mask) == enable_mask) @@ -527,8 +557,10 @@ __i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, assert_spin_locked(&dev_priv->irq_lock); - if (WARN_ON_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK || - status_mask & ~PIPESTAT_INT_STATUS_MASK)) + if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK || + status_mask & ~PIPESTAT_INT_STATUS_MASK, + "pipe %c: enable_mask=0x%x, status_mask=0x%x\n", + pipe_name(pipe), enable_mask, status_mask)) return; if ((pipestat & enable_mask) == 0) @@ -719,24 +751,32 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) /* raw reads, only for fast reads of display block, no need for forcewake etc. */ #define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__)) -static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe) +static int __intel_get_crtc_scanline(struct intel_crtc *crtc) { + struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t status; - int reg; + const struct drm_display_mode *mode = &crtc->config.adjusted_mode; + enum pipe pipe = crtc->pipe; + int vtotal = mode->crtc_vtotal; + int position; - if (INTEL_INFO(dev)->gen >= 8) { - status = GEN8_PIPE_VBLANK; - reg = GEN8_DE_PIPE_ISR(pipe); - } else if (INTEL_INFO(dev)->gen >= 7) { - status = DE_PIPE_VBLANK_IVB(pipe); - reg = DEISR; - } else { - status = DE_PIPE_VBLANK(pipe); - reg = DEISR; - } + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + vtotal /= 2; - return __raw_i915_read32(dev_priv, reg) & status; + if (IS_GEN2(dev)) + position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2; + else + position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; + + /* + * Scanline counter increments at leading edge of hsync, and + * it starts counting from vtotal-1 on the first active line. + * That means the scanline counter value is always one less + * than what we would expect. Ie. just after start of vblank, + * which also occurs at start of hsync (on the last active line), + * the scanline counter will read vblank_start-1. + */ + return (position + 1) % vtotal; } static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, @@ -748,7 +788,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode; int position; - int vbl_start, vbl_end, htotal, vtotal; + int vbl_start, vbl_end, hsync_start, htotal, vtotal; bool in_vbl = true; int ret = 0; unsigned long irqflags; @@ -760,6 +800,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, } htotal = mode->crtc_htotal; + hsync_start = mode->crtc_hsync_start; vtotal = mode->crtc_vtotal; vbl_start = mode->crtc_vblank_start; vbl_end = mode->crtc_vblank_end; @@ -778,7 +819,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, * following code must not block on uncore.lock. */ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - + /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ /* Get optional system timestamp before query. */ @@ -789,68 +830,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, /* No obvious pixelcount register. Only query vertical * scanout position from Display scan line register. */ - if (IS_GEN2(dev)) - position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2; - else - position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; - - if (HAS_DDI(dev)) { - /* - * On HSW HDMI outputs there seems to be a 2 line - * difference, whereas eDP has the normal 1 line - * difference that earlier platforms have. External - * DP is unknown. For now just check for the 2 line - * difference case on all output types on HSW+. - * - * This might misinterpret the scanline counter being - * one line too far along on eDP, but that's less - * dangerous than the alternative since that would lead - * the vblank timestamp code astray when it sees a - * scanline count before vblank_start during a vblank - * interrupt. - */ - in_vbl = ilk_pipe_in_vblank_locked(dev, pipe); - if ((in_vbl && (position == vbl_start - 2 || - position == vbl_start - 1)) || - (!in_vbl && (position == vbl_end - 2 || - position == vbl_end - 1))) - position = (position + 2) % vtotal; - } else if (HAS_PCH_SPLIT(dev)) { - /* - * The scanline counter increments at the leading edge - * of hsync, ie. it completely misses the active portion - * of the line. Fix up the counter at both edges of vblank - * to get a more accurate picture whether we're in vblank - * or not. - */ - in_vbl = ilk_pipe_in_vblank_locked(dev, pipe); - if ((in_vbl && position == vbl_start - 1) || - (!in_vbl && position == vbl_end - 1)) - position = (position + 1) % vtotal; - } else { - /* - * ISR vblank status bits don't work the way we'd want - * them to work on non-PCH platforms (for - * ilk_pipe_in_vblank_locked()), and there doesn't - * appear any other way to determine if we're currently - * in vblank. - * - * Instead let's assume that we're already in vblank if - * we got called from the vblank interrupt and the - * scanline counter value indicates that we're on the - * line just prior to vblank start. This should result - * in the correct answer, unless the vblank interrupt - * delivery really got delayed for almost exactly one - * full frame/field. - */ - if (flags & DRM_CALLED_FROM_VBLIRQ && - position == vbl_start - 1) { - position = (position + 1) % vtotal; - - /* Signal this correction as "applied". */ - ret |= 0x8; - } - } + position = __intel_get_crtc_scanline(intel_crtc); } else { /* Have access to pixelcount since start of frame. * We can split this into vertical and horizontal @@ -862,6 +842,17 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, vbl_start *= htotal; vbl_end *= htotal; vtotal *= htotal; + + /* + * Start of vblank interrupt is triggered at start of hsync, + * just prior to the first active line of vblank. However we + * consider lines to start at the leading edge of horizontal + * active. So, should we get here before we've crossed into + * the horizontal active of the first line in vblank, we would + * not set the DRM_SCANOUTPOS_INVBL flag. In order to fix that, + * always add htotal-hsync_start to the current pixel position. + */ + position = (position + htotal - hsync_start) % vtotal; } /* Get optional system timestamp after query. */ @@ -900,6 +891,19 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, return ret; } +int intel_get_crtc_scanline(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + unsigned long irqflags; + int position; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + position = __intel_get_crtc_scanline(crtc); + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + + return position; +} + static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, int *max_error, struct timeval *vblank_time, @@ -1315,13 +1319,16 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, DRM_ERROR("The master control interrupt lied (GT0)!\n"); } - if (master_ctl & GEN8_GT_VCS1_IRQ) { + if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) { tmp = I915_READ(GEN8_GT_IIR(1)); if (tmp) { ret = IRQ_HANDLED; vcs = tmp >> GEN8_VCS1_IRQ_SHIFT; if (vcs & GT_RENDER_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[VCS]); + vcs = tmp >> GEN8_VCS2_IRQ_SHIFT; + if (vcs & GT_RENDER_USER_INTERRUPT) + notify_ring(dev, &dev_priv->ring[VCS2]); I915_WRITE(GEN8_GT_IIR(1), tmp); } else DRM_ERROR("The master control interrupt lied (GT1)!\n"); @@ -1549,6 +1556,19 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) } } +static bool intel_pipe_handle_vblank(struct drm_device *dev, enum pipe pipe) +{ + struct intel_crtc *crtc; + + if (!drm_handle_vblank(dev, pipe)) + return false; + + crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe)); + wake_up(&crtc->vbl_wait); + + return true; +} + static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1600,7 +1620,7 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir) for_each_pipe(pipe) { if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS) - drm_handle_vblank(dev, pipe); + intel_pipe_handle_vblank(dev, pipe); if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) { intel_prepare_page_flip(dev, pipe); @@ -1619,6 +1639,33 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir) gmbus_irq_handler(dev); } +static void i9xx_hpd_irq_handler(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + + if (IS_G4X(dev)) { + u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; + + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_g4x); + } else { + u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; + + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); + } + + if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && + hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) + dp_aux_irq_handler(dev); + + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); + /* + * Make sure hotplug status is cleared before we clear IIR, or else we + * may miss hotplug events. + */ + POSTING_READ(PORT_HOTPLUG_STAT); +} + static irqreturn_t valleyview_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; @@ -1641,19 +1688,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) valleyview_pipestat_irq_handler(dev, iir); /* Consume port. Then clear IIR or we'll miss events */ - if (iir & I915_DISPLAY_PORT_INTERRUPT) { - u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); - u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; - - intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); - - if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) - dp_aux_irq_handler(dev); - - I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); - I915_READ(PORT_HOTPLUG_STAT); - } - + if (iir & I915_DISPLAY_PORT_INTERRUPT) + i9xx_hpd_irq_handler(dev); if (pm_iir) gen6_rps_irq_handler(dev_priv, pm_iir); @@ -1827,7 +1863,7 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir) for_each_pipe(pipe) { if (de_iir & DE_PIPE_VBLANK(pipe)) - drm_handle_vblank(dev, pipe); + intel_pipe_handle_vblank(dev, pipe); if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) @@ -1877,7 +1913,7 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir) for_each_pipe(pipe) { if (de_iir & (DE_PIPE_VBLANK_IVB(pipe))) - drm_handle_vblank(dev, pipe); + intel_pipe_handle_vblank(dev, pipe); /* plane/pipes map 1:1 on ilk+ */ if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) { @@ -2020,9 +2056,9 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe)); if (pipe_iir & GEN8_PIPE_VBLANK) - drm_handle_vblank(dev, pipe); + intel_pipe_handle_vblank(dev, pipe); - if (pipe_iir & GEN8_PIPE_FLIP_DONE) { + if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) { intel_prepare_page_flip(dev, pipe); intel_finish_page_flip_plane(dev, pipe); } @@ -2136,6 +2172,14 @@ static void i915_error_work_func(struct work_struct *work) kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, reset_event); + /* + * In most cases it's guaranteed that we get here with an RPM + * reference held, for example because there is a pending GPU + * request that won't finish until the reset is done. This + * isn't the case at least when we get here by doing a + * simulated reset via debugs, so get an RPM reference. + */ + intel_runtime_pm_get(dev_priv); /* * All state reset _must_ be completed before we update the * reset counter, for otherwise waiters might miss the reset @@ -2146,6 +2190,8 @@ static void i915_error_work_func(struct work_struct *work) intel_display_handle_reset(dev); + intel_runtime_pm_put(dev_priv); + if (ret == 0) { /* * After all the gem state is reset, increment the reset @@ -2157,7 +2203,7 @@ static void i915_error_work_func(struct work_struct *work) * updates before * the counter increment. */ - smp_mb__before_atomic_inc(); + smp_mb__before_atomic(); atomic_inc(&dev_priv->gpu_error.reset_counter); kobject_uevent_env(&dev->primary->kdev->kobj, @@ -2511,6 +2557,55 @@ ring_idle(struct intel_ring_buffer *ring, u32 seqno) i915_seqno_passed(seqno, ring_last_seqno(ring))); } +static bool +ipehr_is_semaphore_wait(struct drm_device *dev, u32 ipehr) +{ + if (INTEL_INFO(dev)->gen >= 8) { + /* + * FIXME: gen8 semaphore support - currently we don't emit + * semaphores on bdw anyway, but this needs to be addressed when + * we merge that code. + */ + return false; + } else { + ipehr &= ~MI_SEMAPHORE_SYNC_MASK; + return ipehr == (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | + MI_SEMAPHORE_REGISTER); + } +} + +static struct intel_ring_buffer * +semaphore_wait_to_signaller_ring(struct intel_ring_buffer *ring, u32 ipehr) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct intel_ring_buffer *signaller; + int i; + + if (INTEL_INFO(dev_priv->dev)->gen >= 8) { + /* + * FIXME: gen8 semaphore support - currently we don't emit + * semaphores on bdw anyway, but this needs to be addressed when + * we merge that code. + */ + return NULL; + } else { + u32 sync_bits = ipehr & MI_SEMAPHORE_SYNC_MASK; + + for_each_ring(signaller, dev_priv, i) { + if(ring == signaller) + continue; + + if (sync_bits == signaller->semaphore.mbox.wait[ring->id]) + return signaller; + } + } + + DRM_ERROR("No signaller ring found for ring %i, ipehr 0x%08x\n", + ring->id, ipehr); + + return NULL; +} + static struct intel_ring_buffer * semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno) { @@ -2519,8 +2614,7 @@ semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno) int i; ipehr = I915_READ(RING_IPEHR(ring->mmio_base)); - if ((ipehr & ~(0x3 << 16)) != - (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER)) + if (!ipehr_is_semaphore_wait(ring->dev, ipehr)) return NULL; /* @@ -2552,7 +2646,7 @@ semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno) return NULL; *seqno = ioread32(ring->virtual_start + head + 4) + 1; - return &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3]; + return semaphore_wait_to_signaller_ring(ring, ipehr); } static int semaphore_passed(struct intel_ring_buffer *ring) @@ -2759,57 +2853,68 @@ void i915_queue_hangcheck(struct drm_device *dev) round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } -static void ibx_irq_preinstall(struct drm_device *dev) +static void ibx_irq_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; if (HAS_PCH_NOP(dev)) return; - /* south display irq */ - I915_WRITE(SDEIMR, 0xffffffff); - /* - * SDEIER is also touched by the interrupt handler to work around missed - * PCH interrupts. Hence we can't update it after the interrupt handler - * is enabled - instead we unconditionally enable all PCH interrupt - * sources here, but then only unmask them as needed with SDEIMR. - */ + GEN5_IRQ_RESET(SDE); + + if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev)) + I915_WRITE(SERR_INT, 0xffffffff); +} + +/* + * SDEIER is also touched by the interrupt handler to work around missed PCH + * interrupts. Hence we can't update it after the interrupt handler is enabled - + * instead we unconditionally enable all PCH interrupt sources here, but then + * only unmask them as needed with SDEIMR. + * + * This function needs to be called before interrupts are enabled. + */ +static void ibx_irq_pre_postinstall(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (HAS_PCH_NOP(dev)) + return; + + WARN_ON(I915_READ(SDEIER) != 0); I915_WRITE(SDEIER, 0xffffffff); POSTING_READ(SDEIER); } -static void gen5_gt_irq_preinstall(struct drm_device *dev) +static void gen5_gt_irq_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - /* and GT */ - I915_WRITE(GTIMR, 0xffffffff); - I915_WRITE(GTIER, 0x0); - POSTING_READ(GTIER); - - if (INTEL_INFO(dev)->gen >= 6) { - /* and PM */ - I915_WRITE(GEN6_PMIMR, 0xffffffff); - I915_WRITE(GEN6_PMIER, 0x0); - POSTING_READ(GEN6_PMIER); - } + GEN5_IRQ_RESET(GT); + if (INTEL_INFO(dev)->gen >= 6) + GEN5_IRQ_RESET(GEN6_PM); } /* drm_dma.h hooks */ -static void ironlake_irq_preinstall(struct drm_device *dev) +static void ironlake_irq_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - I915_WRITE(HWSTAM, 0xeffe); + I915_WRITE(HWSTAM, 0xffffffff); - I915_WRITE(DEIMR, 0xffffffff); - I915_WRITE(DEIER, 0x0); - POSTING_READ(DEIER); + GEN5_IRQ_RESET(DE); + if (IS_GEN7(dev)) + I915_WRITE(GEN7_ERR_INT, 0xffffffff); - gen5_gt_irq_preinstall(dev); + gen5_gt_irq_reset(dev); - ibx_irq_preinstall(dev); + ibx_irq_reset(dev); +} + +static void ironlake_irq_preinstall(struct drm_device *dev) +{ + ironlake_irq_reset(dev); } static void valleyview_irq_preinstall(struct drm_device *dev) @@ -2827,7 +2932,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev) I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIIR, I915_READ(GTIIR)); - gen5_gt_irq_preinstall(dev); + gen5_gt_irq_reset(dev); I915_WRITE(DPINVGTT, 0xff); @@ -2841,7 +2946,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev) POSTING_READ(VLV_IER); } -static void gen8_irq_preinstall(struct drm_device *dev) +static void gen8_irq_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; @@ -2849,43 +2954,24 @@ static void gen8_irq_preinstall(struct drm_device *dev) I915_WRITE(GEN8_MASTER_IRQ, 0); POSTING_READ(GEN8_MASTER_IRQ); - /* IIR can theoretically queue up two events. Be paranoid */ -#define GEN8_IRQ_INIT_NDX(type, which) do { \ - I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ - POSTING_READ(GEN8_##type##_IMR(which)); \ - I915_WRITE(GEN8_##type##_IER(which), 0); \ - I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ - POSTING_READ(GEN8_##type##_IIR(which)); \ - I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ - } while (0) - -#define GEN8_IRQ_INIT(type) do { \ - I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \ - POSTING_READ(GEN8_##type##_IMR); \ - I915_WRITE(GEN8_##type##_IER, 0); \ - I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ - POSTING_READ(GEN8_##type##_IIR); \ - I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ - } while (0) - - GEN8_IRQ_INIT_NDX(GT, 0); - GEN8_IRQ_INIT_NDX(GT, 1); - GEN8_IRQ_INIT_NDX(GT, 2); - GEN8_IRQ_INIT_NDX(GT, 3); + GEN8_IRQ_RESET_NDX(GT, 0); + GEN8_IRQ_RESET_NDX(GT, 1); + GEN8_IRQ_RESET_NDX(GT, 2); + GEN8_IRQ_RESET_NDX(GT, 3); - for_each_pipe(pipe) { - GEN8_IRQ_INIT_NDX(DE_PIPE, pipe); - } + for_each_pipe(pipe) + GEN8_IRQ_RESET_NDX(DE_PIPE, pipe); - GEN8_IRQ_INIT(DE_PORT); - GEN8_IRQ_INIT(DE_MISC); - GEN8_IRQ_INIT(PCU); -#undef GEN8_IRQ_INIT -#undef GEN8_IRQ_INIT_NDX + GEN5_IRQ_RESET(GEN8_DE_PORT_); + GEN5_IRQ_RESET(GEN8_DE_MISC_); + GEN5_IRQ_RESET(GEN8_PCU_); - POSTING_READ(GEN8_PCU_IIR); + ibx_irq_reset(dev); +} - ibx_irq_preinstall(dev); +static void gen8_irq_preinstall(struct drm_device *dev) +{ + gen8_irq_reset(dev); } static void ibx_hpd_irq_setup(struct drm_device *dev) @@ -2931,15 +3017,12 @@ static void ibx_irq_postinstall(struct drm_device *dev) if (HAS_PCH_NOP(dev)) return; - if (HAS_PCH_IBX(dev)) { + if (HAS_PCH_IBX(dev)) mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; - } else { + else mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; - I915_WRITE(SERR_INT, I915_READ(SERR_INT)); - } - - I915_WRITE(SDEIIR, I915_READ(SDEIIR)); + GEN5_ASSERT_IIR_IS_ZERO(SDEIIR); I915_WRITE(SDEIMR, ~mask); } @@ -2965,10 +3048,7 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev) gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT; } - I915_WRITE(GTIIR, I915_READ(GTIIR)); - I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - I915_WRITE(GTIER, gt_irqs); - POSTING_READ(GTIER); + GEN5_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs); if (INTEL_INFO(dev)->gen >= 6) { pm_irqs |= dev_priv->pm_rps_events; @@ -2977,10 +3057,7 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev) pm_irqs |= PM_VEBOX_USER_INTERRUPT; dev_priv->pm_irq_mask = 0xffffffff; - I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); - I915_WRITE(GEN6_PMIMR, dev_priv->pm_irq_mask); - I915_WRITE(GEN6_PMIER, pm_irqs); - POSTING_READ(GEN6_PMIER); + GEN5_IRQ_INIT(GEN6_PM, dev_priv->pm_irq_mask, pm_irqs); } } @@ -2997,8 +3074,6 @@ static int ironlake_irq_postinstall(struct drm_device *dev) DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB); extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB | DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB); - - I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT)); } else { display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | @@ -3011,11 +3086,11 @@ static int ironlake_irq_postinstall(struct drm_device *dev) dev_priv->irq_mask = ~display_mask; - /* should always can generate irq */ - I915_WRITE(DEIIR, I915_READ(DEIIR)); - I915_WRITE(DEIMR, dev_priv->irq_mask); - I915_WRITE(DEIER, display_mask | extra_mask); - POSTING_READ(DEIER); + I915_WRITE(HWSTAM, 0xeffe); + + ibx_irq_pre_postinstall(dev); + + GEN5_IRQ_INIT(DE, dev_priv->irq_mask, display_mask | extra_mask); gen5_gt_irq_postinstall(dev); @@ -3175,21 +3250,14 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv) GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT }; - for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++) { - u32 tmp = I915_READ(GEN8_GT_IIR(i)); - if (tmp) - DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n", - i, tmp); - I915_WRITE(GEN8_GT_IMR(i), ~gt_interrupts[i]); - I915_WRITE(GEN8_GT_IER(i), gt_interrupts[i]); - } - POSTING_READ(GEN8_GT_IER(0)); + for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++) + GEN8_IRQ_INIT_NDX(GT, i, ~gt_interrupts[i], gt_interrupts[i]); } static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; - uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE | + uint32_t de_pipe_masked = GEN8_PIPE_PRIMARY_FLIP_DONE | GEN8_PIPE_CDCLK_CRC_DONE | GEN8_DE_PIPE_IRQ_FAULT_ERRORS; uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK | @@ -3199,25 +3267,19 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked; dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_masked; - for_each_pipe(pipe) { - u32 tmp = I915_READ(GEN8_DE_PIPE_IIR(pipe)); - if (tmp) - DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n", - pipe, tmp); - I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); - I915_WRITE(GEN8_DE_PIPE_IER(pipe), de_pipe_enables); - } - POSTING_READ(GEN8_DE_PIPE_ISR(0)); + for_each_pipe(pipe) + GEN8_IRQ_INIT_NDX(DE_PIPE, pipe, dev_priv->de_irq_mask[pipe], + de_pipe_enables); - I915_WRITE(GEN8_DE_PORT_IMR, ~GEN8_AUX_CHANNEL_A); - I915_WRITE(GEN8_DE_PORT_IER, GEN8_AUX_CHANNEL_A); - POSTING_READ(GEN8_DE_PORT_IER); + GEN5_IRQ_INIT(GEN8_DE_PORT_, ~GEN8_AUX_CHANNEL_A, GEN8_AUX_CHANNEL_A); } static int gen8_irq_postinstall(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + ibx_irq_pre_postinstall(dev); + gen8_gt_irq_postinstall(dev_priv); gen8_de_irq_postinstall(dev_priv); @@ -3232,41 +3294,13 @@ static int gen8_irq_postinstall(struct drm_device *dev) static void gen8_irq_uninstall(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; if (!dev_priv) return; - I915_WRITE(GEN8_MASTER_IRQ, 0); - -#define GEN8_IRQ_FINI_NDX(type, which) do { \ - I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ - I915_WRITE(GEN8_##type##_IER(which), 0); \ - I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ - } while (0) - -#define GEN8_IRQ_FINI(type) do { \ - I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \ - I915_WRITE(GEN8_##type##_IER, 0); \ - I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ - } while (0) - - GEN8_IRQ_FINI_NDX(GT, 0); - GEN8_IRQ_FINI_NDX(GT, 1); - GEN8_IRQ_FINI_NDX(GT, 2); - GEN8_IRQ_FINI_NDX(GT, 3); - - for_each_pipe(pipe) { - GEN8_IRQ_FINI_NDX(DE_PIPE, pipe); - } - - GEN8_IRQ_FINI(DE_PORT); - GEN8_IRQ_FINI(DE_MISC); - GEN8_IRQ_FINI(PCU); -#undef GEN8_IRQ_FINI -#undef GEN8_IRQ_FINI_NDX + intel_hpd_irq_uninstall(dev_priv); - POSTING_READ(GEN8_PCU_IIR); + gen8_irq_reset(dev); } static void valleyview_irq_uninstall(struct drm_device *dev) @@ -3278,6 +3312,8 @@ static void valleyview_irq_uninstall(struct drm_device *dev) if (!dev_priv) return; + I915_WRITE(VLV_MASTER_IER, 0); + intel_hpd_irq_uninstall(dev_priv); for_each_pipe(pipe) @@ -3309,26 +3345,7 @@ static void ironlake_irq_uninstall(struct drm_device *dev) intel_hpd_irq_uninstall(dev_priv); - I915_WRITE(HWSTAM, 0xffffffff); - - I915_WRITE(DEIMR, 0xffffffff); - I915_WRITE(DEIER, 0x0); - I915_WRITE(DEIIR, I915_READ(DEIIR)); - if (IS_GEN7(dev)) - I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT)); - - I915_WRITE(GTIMR, 0xffffffff); - I915_WRITE(GTIER, 0x0); - I915_WRITE(GTIIR, I915_READ(GTIIR)); - - if (HAS_PCH_NOP(dev)) - return; - - I915_WRITE(SDEIMR, 0xffffffff); - I915_WRITE(SDEIER, 0x0); - I915_WRITE(SDEIIR, I915_READ(SDEIIR)); - if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev)) - I915_WRITE(SERR_INT, I915_READ(SERR_INT)); + ironlake_irq_reset(dev); } static void i8xx_irq_preinstall(struct drm_device * dev) @@ -3386,7 +3403,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); - if (!drm_handle_vblank(dev, pipe)) + if (!intel_pipe_handle_vblank(dev, pipe)) return false; if ((iir & flip_pending) == 0) @@ -3571,7 +3588,7 @@ static bool i915_handle_vblank(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); - if (!drm_handle_vblank(dev, pipe)) + if (!intel_pipe_handle_vblank(dev, pipe)) return false; if ((iir & flip_pending) == 0) @@ -3636,16 +3653,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) break; /* Consume port. Then clear IIR or we'll miss events */ - if ((I915_HAS_HOTPLUG(dev)) && - (iir & I915_DISPLAY_PORT_INTERRUPT)) { - u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); - u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; - - intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); - - I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); - POSTING_READ(PORT_HOTPLUG_STAT); - } + if (I915_HAS_HOTPLUG(dev) && + iir & I915_DISPLAY_PORT_INTERRUPT) + i9xx_hpd_irq_handler(dev); I915_WRITE(IIR, iir & ~flip_mask); new_iir = I915_READ(IIR); /* Flush posted writes */ @@ -3879,22 +3889,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) ret = IRQ_HANDLED; /* Consume port. Then clear IIR or we'll miss events */ - if (iir & I915_DISPLAY_PORT_INTERRUPT) { - u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); - u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ? - HOTPLUG_INT_STATUS_G4X : - HOTPLUG_INT_STATUS_I915); - - intel_hpd_irq_handler(dev, hotplug_trigger, - IS_G4X(dev) ? hpd_status_g4x : hpd_status_i915); - - if (IS_G4X(dev) && - (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)) - dp_aux_irq_handler(dev); - - I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); - I915_READ(PORT_HOTPLUG_STAT); - } + if (iir & I915_DISPLAY_PORT_INTERRUPT) + i9xx_hpd_irq_handler(dev); I915_WRITE(IIR, iir & ~flip_mask); new_iir = I915_READ(IIR); /* Flush posted writes */ @@ -4121,57 +4117,20 @@ void intel_hpd_init(struct drm_device *dev) } /* Disable interrupts so we can allow runtime PM. */ -void hsw_runtime_pm_disable_interrupts(struct drm_device *dev) +void intel_runtime_pm_disable_interrupts(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - - dev_priv->pm.regsave.deimr = I915_READ(DEIMR); - dev_priv->pm.regsave.sdeimr = I915_READ(SDEIMR); - dev_priv->pm.regsave.gtimr = I915_READ(GTIMR); - dev_priv->pm.regsave.gtier = I915_READ(GTIER); - dev_priv->pm.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR); - - ironlake_disable_display_irq(dev_priv, 0xffffffff); - ibx_disable_display_interrupt(dev_priv, 0xffffffff); - ilk_disable_gt_irq(dev_priv, 0xffffffff); - snb_disable_pm_irq(dev_priv, 0xffffffff); + dev->driver->irq_uninstall(dev); dev_priv->pm.irqs_disabled = true; - - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } /* Restore interrupts so we can recover from runtime PM. */ -void hsw_runtime_pm_restore_interrupts(struct drm_device *dev) +void intel_runtime_pm_restore_interrupts(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long irqflags; - uint32_t val; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - - val = I915_READ(DEIMR); - WARN(val != 0xffffffff, "DEIMR is 0x%08x\n", val); - - val = I915_READ(SDEIMR); - WARN(val != 0xffffffff, "SDEIMR is 0x%08x\n", val); - - val = I915_READ(GTIMR); - WARN(val != 0xffffffff, "GTIMR is 0x%08x\n", val); - - val = I915_READ(GEN6_PMIMR); - WARN(val != 0xffffffff, "GEN6_PMIMR is 0x%08x\n", val); dev_priv->pm.irqs_disabled = false; - - ironlake_enable_display_irq(dev_priv, ~dev_priv->pm.regsave.deimr); - ibx_enable_display_interrupt(dev_priv, ~dev_priv->pm.regsave.sdeimr); - ilk_enable_gt_irq(dev_priv, ~dev_priv->pm.regsave.gtimr); - snb_enable_pm_irq(dev_priv, ~dev_priv->pm.regsave.gen6_pmimr); - I915_WRITE(GTIER, dev_priv->pm.regsave.gtier); - - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + dev->driver->irq_preinstall(dev); + dev->driver->irq_postinstall(dev); } diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index d1d7980f0e010c..d05a2afa17dc60 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -46,7 +46,8 @@ struct i915_params i915 __read_mostly = { .reset = true, .invert_brightness = 0, .disable_display = 0, - .enable_cmd_parser = 0, + .enable_cmd_parser = 1, + .disable_vtd_wa = 0, }; module_param_named(modeset, i915.modeset, int, 0400); @@ -149,6 +150,9 @@ MODULE_PARM_DESC(invert_brightness, module_param_named(disable_display, i915.disable_display, bool, 0600); MODULE_PARM_DESC(disable_display, "Disable display (default: false)"); +module_param_named(disable_vtd_wa, i915.disable_vtd_wa, bool, 0600); +MODULE_PARM_DESC(disable_vtd_wa, "Disable all VT-d workarounds (default: false)"); + module_param_named(enable_cmd_parser, i915.enable_cmd_parser, int, 0600); MODULE_PARM_DESC(enable_cmd_parser, - "Enable command parsing (1=enabled, 0=disabled [default])"); + "Enable command parsing (1=enabled [default], 0=disabled)"); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c77af69c2d8f5f..03ffc57a01148f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -92,6 +92,9 @@ #define GEN6_MBC_SNPCR_LOW (2<<21) #define GEN6_MBC_SNPCR_MIN (3<<21) /* only 1/16th of the cache is shared */ +#define VLV_G3DCTL 0x9024 +#define VLV_GSCKGCTL 0x9028 + #define GEN6_MBCTL 0x0907c #define GEN6_MBCTL_ENABLE_BOOT_FETCH (1 << 4) #define GEN6_MBCTL_CTX_FETCH_NEEDED (1 << 3) @@ -190,6 +193,8 @@ * Memory interface instructions used by the kernel */ #define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags)) +/* Many MI commands use bit 22 of the header dword for GGTT vs PPGTT */ +#define MI_GLOBAL_GTT (1<<22) #define MI_NOOP MI_INSTR(0, 0) #define MI_USER_INTERRUPT MI_INSTR(0x02, 0) @@ -244,7 +249,8 @@ #define MI_SEMAPHORE_SYNC_BVE (0<<16) /* VECS wait for BCS (VEBSYNC) */ #define MI_SEMAPHORE_SYNC_VVE (1<<16) /* VECS wait for VCS (VEVSYNC) */ #define MI_SEMAPHORE_SYNC_RVE (2<<16) /* VECS wait for RCS (VERSYNC) */ -#define MI_SEMAPHORE_SYNC_INVALID (3<<16) +#define MI_SEMAPHORE_SYNC_INVALID (3<<16) +#define MI_SEMAPHORE_SYNC_MASK (3<<16) #define MI_SET_CONTEXT MI_INSTR(0x18, 0) #define MI_MM_SPACE_GTT (1<<8) #define MI_MM_SPACE_PHYSICAL (0<<8) @@ -262,13 +268,16 @@ * - One can actually load arbitrary many arbitrary registers: Simply issue x * address/value pairs. Don't overdue it, though, x <= 2^4 must hold! */ -#define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*x-1) -#define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*x-1) +#define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*(x)-1) +#define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*(x)-1) +#define MI_STORE_REGISTER_MEM_GEN8(x) MI_INSTR(0x24, 3*(x)-1) #define MI_SRM_LRM_GLOBAL_GTT (1<<22) #define MI_FLUSH_DW MI_INSTR(0x26, 1) /* for GEN6 */ #define MI_FLUSH_DW_STORE_INDEX (1<<21) #define MI_INVALIDATE_TLB (1<<18) #define MI_FLUSH_DW_OP_STOREDW (1<<14) +#define MI_FLUSH_DW_OP_MASK (3<<14) +#define MI_FLUSH_DW_NOTIFY (1<<8) #define MI_INVALIDATE_BSD (1<<7) #define MI_FLUSH_DW_USE_GTT (1<<2) #define MI_FLUSH_DW_USE_PPGTT (0<<2) @@ -330,9 +339,12 @@ #define DISPLAY_PLANE_B (1<<20) #define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|(len-2)) #define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24) /* gen7+ */ +#define PIPE_CONTROL_MMIO_WRITE (1<<23) +#define PIPE_CONTROL_STORE_DATA_INDEX (1<<21) #define PIPE_CONTROL_CS_STALL (1<<20) #define PIPE_CONTROL_TLB_INVALIDATE (1<<18) #define PIPE_CONTROL_QW_WRITE (1<<14) +#define PIPE_CONTROL_POST_SYNC_OP_MASK (3<<14) #define PIPE_CONTROL_DEPTH_STALL (1<<13) #define PIPE_CONTROL_WRITE_FLUSH (1<<12) #define PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH (1<<12) /* gen6+ */ @@ -347,6 +359,94 @@ #define PIPE_CONTROL_DEPTH_CACHE_FLUSH (1<<0) #define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */ +/* + * Commands used only by the command parser + */ +#define MI_SET_PREDICATE MI_INSTR(0x01, 0) +#define MI_ARB_CHECK MI_INSTR(0x05, 0) +#define MI_RS_CONTROL MI_INSTR(0x06, 0) +#define MI_URB_ATOMIC_ALLOC MI_INSTR(0x09, 0) +#define MI_PREDICATE MI_INSTR(0x0C, 0) +#define MI_RS_CONTEXT MI_INSTR(0x0F, 0) +#define MI_TOPOLOGY_FILTER MI_INSTR(0x0D, 0) +#define MI_LOAD_SCAN_LINES_EXCL MI_INSTR(0x13, 0) +#define MI_URB_CLEAR MI_INSTR(0x19, 0) +#define MI_UPDATE_GTT MI_INSTR(0x23, 0) +#define MI_CLFLUSH MI_INSTR(0x27, 0) +#define MI_REPORT_PERF_COUNT MI_INSTR(0x28, 0) +#define MI_REPORT_PERF_COUNT_GGTT (1<<0) +#define MI_LOAD_REGISTER_MEM MI_INSTR(0x29, 0) +#define MI_LOAD_REGISTER_REG MI_INSTR(0x2A, 0) +#define MI_RS_STORE_DATA_IMM MI_INSTR(0x2B, 0) +#define MI_LOAD_URB_MEM MI_INSTR(0x2C, 0) +#define MI_STORE_URB_MEM MI_INSTR(0x2D, 0) +#define MI_CONDITIONAL_BATCH_BUFFER_END MI_INSTR(0x36, 0) + +#define PIPELINE_SELECT ((0x3<<29)|(0x1<<27)|(0x1<<24)|(0x4<<16)) +#define GFX_OP_3DSTATE_VF_STATISTICS ((0x3<<29)|(0x1<<27)|(0x0<<24)|(0xB<<16)) +#define MEDIA_VFE_STATE ((0x3<<29)|(0x2<<27)|(0x0<<24)|(0x0<<16)) +#define MEDIA_VFE_STATE_MMIO_ACCESS_MASK (0x18) +#define GPGPU_OBJECT ((0x3<<29)|(0x2<<27)|(0x1<<24)|(0x4<<16)) +#define GPGPU_WALKER ((0x3<<29)|(0x2<<27)|(0x1<<24)|(0x5<<16)) +#define GFX_OP_3DSTATE_DX9_CONSTANTF_VS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x39<<16)) +#define GFX_OP_3DSTATE_DX9_CONSTANTF_PS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x3A<<16)) +#define GFX_OP_3DSTATE_SO_DECL_LIST \ + ((0x3<<29)|(0x3<<27)|(0x1<<24)|(0x17<<16)) + +#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_VS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x43<<16)) +#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_GS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x44<<16)) +#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_HS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x45<<16)) +#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_DS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x46<<16)) +#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_PS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x47<<16)) + +#define MFX_WAIT ((0x3<<29)|(0x1<<27)|(0x0<<16)) + +#define COLOR_BLT ((0x2<<29)|(0x40<<22)) +#define SRC_COPY_BLT ((0x2<<29)|(0x43<<22)) + +/* + * Registers used only by the command parser + */ +#define BCS_SWCTRL 0x22200 + +#define HS_INVOCATION_COUNT 0x2300 +#define DS_INVOCATION_COUNT 0x2308 +#define IA_VERTICES_COUNT 0x2310 +#define IA_PRIMITIVES_COUNT 0x2318 +#define VS_INVOCATION_COUNT 0x2320 +#define GS_INVOCATION_COUNT 0x2328 +#define GS_PRIMITIVES_COUNT 0x2330 +#define CL_INVOCATION_COUNT 0x2338 +#define CL_PRIMITIVES_COUNT 0x2340 +#define PS_INVOCATION_COUNT 0x2348 +#define PS_DEPTH_COUNT 0x2350 + +/* There are the 4 64-bit counter registers, one for each stream output */ +#define GEN7_SO_NUM_PRIMS_WRITTEN(n) (0x5200 + (n) * 8) + +#define GEN7_SO_PRIM_STORAGE_NEEDED(n) (0x5240 + (n) * 8) + +#define GEN7_3DPRIM_END_OFFSET 0x2420 +#define GEN7_3DPRIM_START_VERTEX 0x2430 +#define GEN7_3DPRIM_VERTEX_COUNT 0x2434 +#define GEN7_3DPRIM_INSTANCE_COUNT 0x2438 +#define GEN7_3DPRIM_START_INSTANCE 0x243C +#define GEN7_3DPRIM_BASE_VERTEX 0x2440 + +#define OACONTROL 0x2360 + +#define _GEN7_PIPEA_DE_LOAD_SL 0x70068 +#define _GEN7_PIPEB_DE_LOAD_SL 0x71068 +#define GEN7_PIPE_DE_LOAD_SL(pipe) _PIPE(pipe, \ + _GEN7_PIPEA_DE_LOAD_SL, \ + _GEN7_PIPEB_DE_LOAD_SL) /* * Reset registers @@ -663,6 +763,7 @@ enum punit_power_well { #define RENDER_RING_BASE 0x02000 #define BSD_RING_BASE 0x04000 #define GEN6_BSD_RING_BASE 0x12000 +#define GEN8_BSD2_RING_BASE 0x1c000 #define VEBOX_RING_BASE 0x1a000 #define BLT_RING_BASE 0x22000 #define RING_TAIL(base) ((base)+0x30) @@ -688,9 +789,20 @@ enum punit_power_well { #define RING_MAX_IDLE(base) ((base)+0x54) #define RING_HWS_PGA(base) ((base)+0x80) #define RING_HWS_PGA_GEN6(base) ((base)+0x2080) -#define ARB_MODE 0x04030 + +#define GEN7_WR_WATERMARK 0x4028 +#define GEN7_GFX_PRIO_CTRL 0x402C +#define ARB_MODE 0x4030 #define ARB_MODE_SWIZZLE_SNB (1<<4) #define ARB_MODE_SWIZZLE_IVB (1<<5) +#define GEN7_GFX_PEND_TLB0 0x4034 +#define GEN7_GFX_PEND_TLB1 0x4038 +/* L3, CVS, ZTLB, RCC, CASC LRA min, max values */ +#define GEN7_LRA_LIMITS_BASE 0x403C +#define GEN7_LRA_LIMITS_REG_NUM 13 +#define GEN7_MEDIA_MAX_REQ_COUNT 0x4070 +#define GEN7_GFX_MAX_REQ_COUNT 0x4074 + #define GAMTARBMODE 0x04a08 #define ARB_MODE_BWGTLB_DISABLE (1<<9) #define ARB_MODE_SWIZZLE_BDW (1<<1) @@ -725,6 +837,9 @@ enum punit_power_well { #define RING_WAIT_I8XX (1<<0) /* gen2, PRBx_HEAD */ #define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */ #define RING_WAIT_SEMAPHORE (1<<10) /* gen6+ */ + +#define GEN7_TLB_RD_ADDR 0x4700 + #if 0 #define PRB0_TAIL 0x02030 #define PRB0_HEAD 0x02034 @@ -748,6 +863,7 @@ enum punit_power_well { #define RING_INSTDONE(base) ((base)+0x6c) #define RING_INSTPS(base) ((base)+0x70) #define RING_DMA_FADD(base) ((base)+0x78) +#define RING_DMA_FADD_UDW(base) ((base)+0x60) /* gen8+ */ #define RING_INSTPM(base) ((base)+0xc0) #define RING_MI_MODE(base) ((base)+0x9c) #define INSTPS 0x02070 /* 965+ only */ @@ -842,7 +958,7 @@ enum punit_power_well { #define GFX_MODE_GEN7 0x0229c #define RING_MODE_GEN7(ring) ((ring)->mmio_base+0x29c) #define GFX_RUN_LIST_ENABLE (1<<15) -#define GFX_TLB_INVALIDATE_ALWAYS (1<<13) +#define GFX_TLB_INVALIDATE_EXPLICIT (1<<13) #define GFX_SURFACE_FAULT_ENABLE (1<<12) #define GFX_REPLAY_MODE (1<<11) #define GFX_PSMI_GRANULARITY (1<<10) @@ -850,6 +966,8 @@ enum punit_power_well { #define VLV_DISPLAY_BASE 0x180000 +#define VLV_GU_CTL0 (VLV_DISPLAY_BASE + 0x2030) +#define VLV_GU_CTL1 (VLV_DISPLAY_BASE + 0x2034) #define SCPD0 0x0209c /* 915+ only */ #define IER 0x020a0 #define IIR 0x020a4 @@ -857,6 +975,7 @@ enum punit_power_well { #define ISR 0x020ac #define VLV_GUNIT_CLOCK_GATE (VLV_DISPLAY_BASE + 0x2060) #define GCFG_DIS (1<<8) +#define VLV_GUNIT_CLOCK_GATE2 (VLV_DISPLAY_BASE + 0x2064) #define VLV_IIR_RW (VLV_DISPLAY_BASE + 0x2084) #define VLV_IER (VLV_DISPLAY_BASE + 0x20a0) #define VLV_IIR (VLV_DISPLAY_BASE + 0x20a4) @@ -973,6 +1092,7 @@ enum punit_power_well { #define ECO_FLIP_DONE (1<<0) #define CACHE_MODE_0_GEN7 0x7000 /* IVB+ */ +#define RC_OP_FLUSH_ENABLE (1<<0) #define HIZ_RAW_STALL_OPT_DISABLE (1<<2) #define CACHE_MODE_1 0x7004 /* IVB+ */ #define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6) @@ -1024,24 +1144,43 @@ enum punit_power_well { /* These are all the "old" interrupts */ #define ILK_BSD_USER_INTERRUPT (1<<5) + +#define I915_PM_INTERRUPT (1<<31) +#define I915_ISP_INTERRUPT (1<<22) +#define I915_LPE_PIPE_B_INTERRUPT (1<<21) +#define I915_LPE_PIPE_A_INTERRUPT (1<<20) +#define I915_MIPIB_INTERRUPT (1<<19) +#define I915_MIPIA_INTERRUPT (1<<18) #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) #define I915_DISPLAY_PORT_INTERRUPT (1<<17) +#define I915_DISPLAY_PIPE_C_HBLANK_INTERRUPT (1<<16) +#define I915_MASTER_ERROR_INTERRUPT (1<<15) #define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) +#define I915_DISPLAY_PIPE_B_HBLANK_INTERRUPT (1<<14) #define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) /* p-state */ +#define I915_DISPLAY_PIPE_A_HBLANK_INTERRUPT (1<<13) #define I915_HWB_OOM_INTERRUPT (1<<13) +#define I915_LPE_PIPE_C_INTERRUPT (1<<12) #define I915_SYNC_STATUS_INTERRUPT (1<<12) +#define I915_MISC_INTERRUPT (1<<11) #define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) +#define I915_DISPLAY_PIPE_C_VBLANK_INTERRUPT (1<<10) #define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10) +#define I915_DISPLAY_PIPE_C_EVENT_INTERRUPT (1<<9) #define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9) +#define I915_DISPLAY_PIPE_C_DPBM_INTERRUPT (1<<8) #define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8) #define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7) #define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6) #define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5) #define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) +#define I915_DISPLAY_PIPE_A_DPBM_INTERRUPT (1<<3) +#define I915_DISPLAY_PIPE_B_DPBM_INTERRUPT (1<<2) #define I915_DEBUG_INTERRUPT (1<<2) +#define I915_WINVALID_INTERRUPT (1<<1) #define I915_USER_INTERRUPT (1<<1) #define I915_ASLE_INTERRUPT (1<<0) -#define I915_BSD_USER_INTERRUPT (1 << 25) +#define I915_BSD_USER_INTERRUPT (1<<25) #define GEN6_BSD_RNCID 0x12198 @@ -3258,6 +3397,7 @@ enum punit_power_well { #define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */ #define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */ #define PIPECONF_INTERLACE_MODE_MASK (7 << 21) +#define PIPECONF_EDP_RR_MODE_SWITCH (1 << 20) #define PIPECONF_CXSR_DOWNCLOCK (1<<16) #define PIPECONF_COLOR_RANGE_SELECT (1 << 13) #define PIPECONF_BPC_MASK (0x7 << 5) @@ -3276,6 +3416,7 @@ enum punit_power_well { #define SPRITE1_FLIP_DONE_INT_EN_VLV (1UL<<30) #define PIPE_CRC_ERROR_ENABLE (1UL<<29) #define PIPE_CRC_DONE_ENABLE (1UL<<28) +#define PERF_COUNTER2_INTERRUPT_EN (1UL<<27) #define PIPE_GMBUS_EVENT_ENABLE (1UL<<27) #define PLANE_FLIP_DONE_INT_EN_VLV (1UL<<26) #define PIPE_HOTPLUG_INTERRUPT_ENABLE (1UL<<26) @@ -3287,8 +3428,10 @@ enum punit_power_well { #define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) #define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) #define PIPE_B_PSR_INTERRUPT_ENABLE_VLV (1UL<<19) +#define PERF_COUNTER_INTERRUPT_EN (1UL<<19) #define PIPE_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18) /* pre-965 */ #define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */ +#define PIPE_FRAMESTART_INTERRUPT_ENABLE (1UL<<17) #define PIPE_VBLANK_INTERRUPT_ENABLE (1UL<<17) #define PIPEA_HBLANK_INT_EN_VLV (1UL<<16) #define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16) @@ -3296,6 +3439,7 @@ enum punit_power_well { #define SPRITE0_FLIP_DONE_INT_STATUS_VLV (1UL<<14) #define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) #define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12) +#define PERF_COUNTER2_INTERRUPT_STATUS (1UL<<11) #define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11) #define PLANE_FLIP_DONE_INT_STATUS_VLV (1UL<<10) #define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL<<10) @@ -3304,12 +3448,16 @@ enum punit_power_well { #define PIPE_DPST_EVENT_STATUS (1UL<<7) #define PIPE_LEGACY_BLC_EVENT_STATUS (1UL<<6) #define PIPE_A_PSR_STATUS_VLV (1UL<<6) +#define PIPE_LEGACY_BLC_EVENT_STATUS (1UL<<6) #define PIPE_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) #define PIPE_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4) #define PIPE_B_PSR_STATUS_VLV (1UL<<3) +#define PERF_COUNTER_INTERRUPT_STATUS (1UL<<3) #define PIPE_HOTPLUG_TV_INTERRUPT_STATUS (1UL<<2) /* pre-965 */ #define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ +#define PIPE_FRAMESTART_INTERRUPT_STATUS (1UL<<1) #define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1) +#define PIPE_HBLANK_INT_STATUS (1UL<<0) #define PIPE_OVERLAY_UPDATED_STATUS (1UL<<0) #define PIPESTAT_INT_ENABLE_MASK 0x7fff0000 @@ -3355,14 +3503,25 @@ enum punit_power_well { #define SPRITED_FLIP_DONE_INT_EN (1<<26) #define SPRITEC_FLIP_DONE_INT_EN (1<<25) #define PLANEB_FLIP_DONE_INT_EN (1<<24) +#define PIPE_PSR_INT_EN (1<<22) #define PIPEA_LINE_COMPARE_INT_EN (1<<21) #define PIPEA_HLINE_INT_EN (1<<20) #define PIPEA_VBLANK_INT_EN (1<<19) #define SPRITEB_FLIP_DONE_INT_EN (1<<18) #define SPRITEA_FLIP_DONE_INT_EN (1<<17) #define PLANEA_FLIPDONE_INT_EN (1<<16) - -#define DPINVGTT (VLV_DISPLAY_BASE + 0x7002c) /* VLV only */ +#define PIPEC_LINE_COMPARE_INT_EN (1<<13) +#define PIPEC_HLINE_INT_EN (1<<12) +#define PIPEC_VBLANK_INT_EN (1<<11) +#define SPRITEF_FLIPDONE_INT_EN (1<<10) +#define SPRITEE_FLIPDONE_INT_EN (1<<9) +#define PLANEC_FLIPDONE_INT_EN (1<<8) + +#define DPINVGTT (VLV_DISPLAY_BASE + 0x7002c) /* VLV/CHV only */ +#define SPRITEF_INVALID_GTT_INT_EN (1<<27) +#define SPRITEE_INVALID_GTT_INT_EN (1<<26) +#define PLANEC_INVALID_GTT_INT_EN (1<<25) +#define CURSORC_INVALID_GTT_INT_EN (1<<24) #define CURSORB_INVALID_GTT_INT_EN (1<<23) #define CURSORA_INVALID_GTT_INT_EN (1<<22) #define SPRITED_INVALID_GTT_INT_EN (1<<21) @@ -3372,6 +3531,11 @@ enum punit_power_well { #define SPRITEA_INVALID_GTT_INT_EN (1<<17) #define PLANEA_INVALID_GTT_INT_EN (1<<16) #define DPINVGTT_EN_MASK 0xff0000 +#define DPINVGTT_EN_MASK_CHV 0xfff0000 +#define SPRITEF_INVALID_GTT_STATUS (1<<11) +#define SPRITEE_INVALID_GTT_STATUS (1<<10) +#define PLANEC_INVALID_GTT_STATUS (1<<9) +#define CURSORC_INVALID_GTT_STATUS (1<<8) #define CURSORB_INVALID_GTT_STATUS (1<<7) #define CURSORA_INVALID_GTT_STATUS (1<<6) #define SPRITED_INVALID_GTT_STATUS (1<<5) @@ -3381,6 +3545,7 @@ enum punit_power_well { #define SPRITEA_INVALID_GTT_STATUS (1<<1) #define PLANEA_INVALID_GTT_STATUS (1<<0) #define DPINVGTT_STATUS_MASK 0xff +#define DPINVGTT_STATUS_MASK_CHV 0xfff #define DSPARB 0x70030 #define DSPARB_CSTART_MASK (0x7f << 7) @@ -3535,9 +3700,9 @@ enum punit_power_well { #define PIPE_PIXEL_MASK 0x00ffffff #define PIPE_PIXEL_SHIFT 0 /* GM45+ just has to be different */ -#define _PIPEA_FRMCOUNT_GM45 (dev_priv->info.display_mmio_offset + 0x70040) -#define _PIPEA_FLIPCOUNT_GM45 (dev_priv->info.display_mmio_offset + 0x70044) -#define PIPE_FRMCOUNT_GM45(pipe) _PIPE(pipe, _PIPEA_FRMCOUNT_GM45, _PIPEB_FRMCOUNT_GM45) +#define _PIPEA_FRMCOUNT_GM45 0x70040 +#define _PIPEA_FLIPCOUNT_GM45 0x70044 +#define PIPE_FRMCOUNT_GM45(pipe) _PIPE2(pipe, _PIPEA_FRMCOUNT_GM45) /* Cursor A & B regs */ #define _CURACNTR (dev_priv->info.display_mmio_offset + 0x70080) @@ -4120,7 +4285,7 @@ enum punit_power_well { #define GEN8_PIPE_SPRITE_FAULT (1 << 9) #define GEN8_PIPE_PRIMARY_FAULT (1 << 8) #define GEN8_PIPE_SPRITE_FLIP_DONE (1 << 5) -#define GEN8_PIPE_FLIP_DONE (1 << 4) +#define GEN8_PIPE_PRIMARY_FLIP_DONE (1 << 4) #define GEN8_PIPE_SCAN_LINE_EVENT (1 << 2) #define GEN8_PIPE_VSYNC (1 << 1) #define GEN8_PIPE_VBLANK (1 << 0) @@ -4888,6 +5053,8 @@ enum punit_power_well { #define EDP_LINK_TRAIN_VOL_EMP_MASK_IVB (0x3f<<22) +#define VLV_PMWGICZ 0x1300a4 + #define FORCEWAKE 0xA18C #define FORCEWAKE_VLV 0x1300b0 #define FORCEWAKE_ACK_VLV 0x1300b4 @@ -4896,15 +5063,22 @@ enum punit_power_well { #define FORCEWAKE_ACK_HSW 0x130044 #define FORCEWAKE_ACK 0x130090 #define VLV_GTLC_WAKE_CTRL 0x130090 +#define VLV_GTLC_RENDER_CTX_EXISTS (1 << 25) +#define VLV_GTLC_MEDIA_CTX_EXISTS (1 << 24) +#define VLV_GTLC_ALLOWWAKEREQ (1 << 0) + #define VLV_GTLC_PW_STATUS 0x130094 -#define VLV_GTLC_PW_RENDER_STATUS_MASK 0x80 -#define VLV_GTLC_PW_MEDIA_STATUS_MASK 0x20 +#define VLV_GTLC_ALLOWWAKEACK (1 << 0) +#define VLV_GTLC_ALLOWWAKEERR (1 << 1) +#define VLV_GTLC_PW_MEDIA_STATUS_MASK (1 << 5) +#define VLV_GTLC_PW_RENDER_STATUS_MASK (1 << 7) #define FORCEWAKE_MT 0xa188 /* multi-threaded */ #define FORCEWAKE_KERNEL 0x1 #define FORCEWAKE_USER 0x2 #define FORCEWAKE_MT_ACK 0x130040 #define ECOBUS 0xa180 #define FORCEWAKE_MT_ENABLE (1<<5) +#define VLV_SPAREG2H 0xA194 #define GTFIFODBG 0x120000 #define GT_FIFO_SBDROPERR (1<<6) @@ -4934,12 +5108,19 @@ enum punit_power_well { # define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE (1 << 12) # define GEN6_RCCUNIT_CLOCK_GATE_DISABLE (1 << 11) +#define GEN6_UCGCTL3 0x9408 + #define GEN7_UCGCTL4 0x940c #define GEN7_L3BANK2X_CLOCK_GATE_DISABLE (1<<25) +#define GEN6_RCGCTL1 0x9410 +#define GEN6_RCGCTL2 0x9414 +#define GEN6_RSTCTL 0x9420 + #define GEN8_UCGCTL6 0x9430 #define GEN8_SDEUNIT_CLOCK_GATE_DISABLE (1<<14) +#define GEN6_GFXPAUSE 0xA000 #define GEN6_RPNSWREQ 0xA008 #define GEN6_TURBO_DISABLE (1<<31) #define GEN6_FREQUENCY(x) ((x)<<25) @@ -4992,6 +5173,9 @@ enum punit_power_well { #define GEN6_RP_UP_EI 0xA068 #define GEN6_RP_DOWN_EI 0xA06C #define GEN6_RP_IDLE_HYSTERSIS 0xA070 +#define GEN6_RPDEUHWTC 0xA080 +#define GEN6_RPDEUC 0xA084 +#define GEN6_RPDEUCSW 0xA088 #define GEN6_RC_STATE 0xA094 #define GEN6_RC1_WAKE_RATE_LIMIT 0xA098 #define GEN6_RC6_WAKE_RATE_LIMIT 0xA09C @@ -4999,11 +5183,14 @@ enum punit_power_well { #define GEN6_RC_EVALUATION_INTERVAL 0xA0A8 #define GEN6_RC_IDLE_HYSTERSIS 0xA0AC #define GEN6_RC_SLEEP 0xA0B0 +#define GEN6_RCUBMABDTMR 0xA0B0 #define GEN6_RC1e_THRESHOLD 0xA0B4 #define GEN6_RC6_THRESHOLD 0xA0B8 #define GEN6_RC6p_THRESHOLD 0xA0BC +#define VLV_RCEDATA 0xA0BC #define GEN6_RC6pp_THRESHOLD 0xA0C0 #define GEN6_PMINTRMSK 0xA168 +#define VLV_PWRDWNUPCTL 0xA294 #define GEN6_PMISR 0x44020 #define GEN6_PMIMR 0x44024 /* rps_lock */ @@ -5020,6 +5207,9 @@ enum punit_power_well { GEN6_PM_RP_DOWN_THRESHOLD | \ GEN6_PM_RP_DOWN_TIMEOUT) +#define GEN7_GT_SCRATCH_BASE 0x4F100 +#define GEN7_GT_SCRATCH_REG_NUM 8 + #define VLV_GTLC_SURVIVABILITY_REG 0x130098 #define VLV_GFX_CLK_STATUS_BIT (1<<3) #define VLV_GFX_CLK_FORCE_ON_BIT (1<<2) @@ -5030,6 +5220,9 @@ enum punit_power_well { #define VLV_MEDIA_RC6_COUNT_EN (1<<1) #define VLV_RENDER_RC6_COUNT_EN (1<<0) #define GEN6_GT_GFX_RC6 0x138108 +#define VLV_GT_RENDER_RC6 0x138108 +#define VLV_GT_MEDIA_RC6 0x13810C + #define GEN6_GT_GFX_RC6p 0x13810C #define GEN6_GT_GFX_RC6pp 0x138110 diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 9c57029f6f4b4b..3620997e43f50b 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -263,6 +263,8 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, flush_delayed_work(&dev_priv->rps.delayed_resume_work); + intel_runtime_pm_get(dev_priv); + mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) { u32 freq; @@ -273,6 +275,8 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, } mutex_unlock(&dev_priv->rps.hw_lock); + intel_runtime_pm_put(dev_priv); + return snprintf(buf, PAGE_SIZE, "%d\n", ret); } diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 23c26f1f8b372e..b29d7b1828f1dc 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -7,6 +7,7 @@ #include #include "i915_drv.h" +#include "intel_drv.h" #include "intel_ringbuffer.h" #undef TRACE_SYSTEM @@ -14,6 +15,80 @@ #define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM) #define TRACE_INCLUDE_FILE i915_trace +/* pipe updates */ + +TRACE_EVENT(i915_pipe_update_start, + TP_PROTO(struct intel_crtc *crtc, u32 min, u32 max), + TP_ARGS(crtc, min, max), + + TP_STRUCT__entry( + __field(enum pipe, pipe) + __field(u32, frame) + __field(u32, scanline) + __field(u32, min) + __field(u32, max) + ), + + TP_fast_assign( + __entry->pipe = crtc->pipe; + __entry->frame = crtc->base.dev->driver->get_vblank_counter(crtc->base.dev, + crtc->pipe); + __entry->scanline = intel_get_crtc_scanline(crtc); + __entry->min = min; + __entry->max = max; + ), + + TP_printk("pipe %c, frame=%u, scanline=%u, min=%u, max=%u", + pipe_name(__entry->pipe), __entry->frame, + __entry->scanline, __entry->min, __entry->max) +); + +TRACE_EVENT(i915_pipe_update_vblank_evaded, + TP_PROTO(struct intel_crtc *crtc, u32 min, u32 max, u32 frame), + TP_ARGS(crtc, min, max, frame), + + TP_STRUCT__entry( + __field(enum pipe, pipe) + __field(u32, frame) + __field(u32, scanline) + __field(u32, min) + __field(u32, max) + ), + + TP_fast_assign( + __entry->pipe = crtc->pipe; + __entry->frame = frame; + __entry->scanline = intel_get_crtc_scanline(crtc); + __entry->min = min; + __entry->max = max; + ), + + TP_printk("pipe %c, frame=%u, scanline=%u, min=%u, max=%u", + pipe_name(__entry->pipe), __entry->frame, + __entry->scanline, __entry->min, __entry->max) +); + +TRACE_EVENT(i915_pipe_update_end, + TP_PROTO(struct intel_crtc *crtc, u32 frame), + TP_ARGS(crtc, frame), + + TP_STRUCT__entry( + __field(enum pipe, pipe) + __field(u32, frame) + __field(u32, scanline) + ), + + TP_fast_assign( + __entry->pipe = crtc->pipe; + __entry->frame = frame; + __entry->scanline = intel_get_crtc_scanline(crtc); + ), + + TP_printk("pipe %c, frame=%u, scanline=%u", + pipe_name(__entry->pipe), __entry->frame, + __entry->scanline) +); + /* object tracking */ TRACE_EVENT(i915_gem_object_create, diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index fa486c5fbb0250..2945f57c53ee9a 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -49,13 +49,19 @@ find_section(struct bdb_header *bdb, int section_id) total = bdb->bdb_size; /* walk the sections looking for section_id */ - while (index < total) { + while (index + 3 < total) { current_id = *(base + index); index++; + current_size = *((u16 *)(base + index)); index += 2; + + if (index + current_size > total) + return NULL; + if (current_id == section_id) return base + index; + index += current_size; } @@ -206,7 +212,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, const struct lvds_dvo_timing *panel_dvo_timing; const struct lvds_fp_timing *fp_timing; struct drm_display_mode *panel_fixed_mode; - int i, downclock; + int i, downclock, drrs_mode; lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); if (!lvds_options) @@ -218,6 +224,28 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, panel_type = lvds_options->panel_type; + drrs_mode = (lvds_options->dps_panel_type_bits + >> (panel_type * 2)) & MODE_MASK; + /* + * VBT has static DRRS = 0 and seamless DRRS = 2. + * The below piece of code is required to adjust vbt.drrs_type + * to match the enum drrs_support_type. + */ + switch (drrs_mode) { + case 0: + dev_priv->vbt.drrs_type = STATIC_DRRS_SUPPORT; + DRM_DEBUG_KMS("DRRS supported mode is static\n"); + break; + case 2: + dev_priv->vbt.drrs_type = SEAMLESS_DRRS_SUPPORT; + DRM_DEBUG_KMS("DRRS supported mode is seamless\n"); + break; + default: + dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED; + DRM_DEBUG_KMS("DRRS not supported (VBT input)\n"); + break; + } + lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); if (!lvds_lfp_data) return; @@ -526,6 +554,16 @@ parse_driver_features(struct drm_i915_private *dev_priv, if (driver->dual_frequency) dev_priv->render_reclock_avail = true; + + DRM_DEBUG_KMS("DRRS State Enabled:%d\n", driver->drrs_enabled); + /* + * If DRRS is not supported, drrs_type has to be set to 0. + * This is because, VBT is configured in such a way that + * static DRRS is 0 and DRRS not supported is represented by + * driver->drrs_enabled=false + */ + if (!driver->drrs_enabled) + dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED; } static void @@ -604,19 +642,217 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) } } +static u8 *goto_next_sequence(u8 *data, int *size) +{ + u16 len; + int tmp = *size; + + if (--tmp < 0) + return NULL; + + /* goto first element */ + data++; + while (1) { + switch (*data) { + case MIPI_SEQ_ELEM_SEND_PKT: + /* + * skip by this element payload size + * skip elem id, command flag and data type + */ + tmp -= 5; + if (tmp < 0) + return NULL; + + data += 3; + len = *((u16 *)data); + + tmp -= len; + if (tmp < 0) + return NULL; + + /* skip by len */ + data = data + 2 + len; + break; + case MIPI_SEQ_ELEM_DELAY: + /* skip by elem id, and delay is 4 bytes */ + tmp -= 5; + if (tmp < 0) + return NULL; + + data += 5; + break; + case MIPI_SEQ_ELEM_GPIO: + tmp -= 3; + if (tmp < 0) + return NULL; + + data += 3; + break; + default: + DRM_ERROR("Unknown element\n"); + return NULL; + } + + /* end of sequence ? */ + if (*data == 0) + break; + } + + /* goto next sequence or end of block byte */ + if (--tmp < 0) + return NULL; + + data++; + + /* update amount of data left for the sequence block to be parsed */ + *size = tmp; + return data; +} + static void parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb) { - struct bdb_mipi *mipi; + struct bdb_mipi_config *start; + struct bdb_mipi_sequence *sequence; + struct mipi_config *config; + struct mipi_pps_data *pps; + u8 *data, *seq_data; + int i, panel_id, seq_size; + u16 block_size; + + /* Initialize this to undefined indicating no generic MIPI support */ + dev_priv->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID; + + /* Block #40 is already parsed and panel_fixed_mode is + * stored in dev_priv->lfp_lvds_vbt_mode + * resuse this when needed + */ - mipi = find_section(bdb, BDB_MIPI_CONFIG); - if (!mipi) { - DRM_DEBUG_KMS("No MIPI BDB found"); + /* Parse #52 for panel index used from panel_type already + * parsed + */ + start = find_section(bdb, BDB_MIPI_CONFIG); + if (!start) { + DRM_DEBUG_KMS("No MIPI config BDB found"); return; } - /* XXX: add more info */ + DRM_DEBUG_DRIVER("Found MIPI Config block, panel index = %d\n", + panel_type); + + /* + * get hold of the correct configuration block and pps data as per + * the panel_type as index + */ + config = &start->config[panel_type]; + pps = &start->pps[panel_type]; + + /* store as of now full data. Trim when we realise all is not needed */ + dev_priv->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL); + if (!dev_priv->vbt.dsi.config) + return; + + dev_priv->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL); + if (!dev_priv->vbt.dsi.pps) { + kfree(dev_priv->vbt.dsi.config); + return; + } + + /* We have mandatory mipi config blocks. Initialize as generic panel */ dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; + + /* Check if we have sequence block as well */ + sequence = find_section(bdb, BDB_MIPI_SEQUENCE); + if (!sequence) { + DRM_DEBUG_KMS("No MIPI Sequence found, parsing complete\n"); + return; + } + + DRM_DEBUG_DRIVER("Found MIPI sequence block\n"); + + block_size = get_blocksize(sequence); + + /* + * parse the sequence block for individual sequences + */ + dev_priv->vbt.dsi.seq_version = sequence->version; + + seq_data = &sequence->data[0]; + + /* + * sequence block is variable length and hence we need to parse and + * get the sequence data for specific panel id + */ + for (i = 0; i < MAX_MIPI_CONFIGURATIONS; i++) { + panel_id = *seq_data; + seq_size = *((u16 *) (seq_data + 1)); + if (panel_id == panel_type) + break; + + /* skip the sequence including seq header of 3 bytes */ + seq_data = seq_data + 3 + seq_size; + if ((seq_data - &sequence->data[0]) > block_size) { + DRM_ERROR("Sequence start is beyond sequence block size, corrupted sequence block\n"); + return; + } + } + + if (i == MAX_MIPI_CONFIGURATIONS) { + DRM_ERROR("Sequence block detected but no valid configuration\n"); + return; + } + + /* check if found sequence is completely within the sequence block + * just being paranoid */ + if (seq_size > block_size) { + DRM_ERROR("Corrupted sequence/size, bailing out\n"); + return; + } + + /* skip the panel id(1 byte) and seq size(2 bytes) */ + dev_priv->vbt.dsi.data = kmemdup(seq_data + 3, seq_size, GFP_KERNEL); + if (!dev_priv->vbt.dsi.data) + return; + + /* + * loop into the sequence data and split into multiple sequneces + * There are only 5 types of sequences as of now + */ + data = dev_priv->vbt.dsi.data; + dev_priv->vbt.dsi.size = seq_size; + + /* two consecutive 0x00 indicate end of all sequences */ + while (1) { + int seq_id = *data; + if (MIPI_SEQ_MAX > seq_id && seq_id > MIPI_SEQ_UNDEFINED) { + dev_priv->vbt.dsi.sequence[seq_id] = data; + DRM_DEBUG_DRIVER("Found mipi sequence - %d\n", seq_id); + } else { + DRM_ERROR("undefined sequence\n"); + goto err; + } + + /* partial parsing to skip elements */ + data = goto_next_sequence(data, &seq_size); + + if (data == NULL) { + DRM_ERROR("Sequence elements going beyond block itself. Sequence block parsing failed\n"); + goto err; + } + + if (*data == 0) + break; /* end of sequence reached */ + } + + DRM_DEBUG_DRIVER("MIPI related vbt parsing complete\n"); + return; +err: + kfree(dev_priv->vbt.dsi.data); + dev_priv->vbt.dsi.data = NULL; + + /* error during parsing so set all pointers to null + * because of partial parsing */ + memset(dev_priv->vbt.dsi.sequence, 0, MIPI_SEQ_MAX); } static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, @@ -869,6 +1105,46 @@ static const struct dmi_system_id intel_no_opregion_vbt[] = { { } }; +static struct bdb_header *validate_vbt(char *base, size_t size, + struct vbt_header *vbt, + const char *source) +{ + size_t offset; + struct bdb_header *bdb; + + if (vbt == NULL) { + DRM_DEBUG_DRIVER("VBT signature missing\n"); + return NULL; + } + + offset = (char *)vbt - base; + if (offset + sizeof(struct vbt_header) > size) { + DRM_DEBUG_DRIVER("VBT header incomplete\n"); + return NULL; + } + + if (memcmp(vbt->signature, "$VBT", 4)) { + DRM_DEBUG_DRIVER("VBT invalid signature\n"); + return NULL; + } + + offset += vbt->bdb_offset; + if (offset + sizeof(struct bdb_header) > size) { + DRM_DEBUG_DRIVER("BDB header incomplete\n"); + return NULL; + } + + bdb = (struct bdb_header *)(base + offset); + if (offset + bdb->bdb_size > size) { + DRM_DEBUG_DRIVER("BDB incomplete\n"); + return NULL; + } + + DRM_DEBUG_KMS("Using VBT from %s: %20s\n", + source, vbt->signature); + return bdb; +} + /** * intel_parse_bios - find VBT and initialize settings from the BIOS * @dev: DRM device @@ -892,20 +1168,13 @@ intel_parse_bios(struct drm_device *dev) init_vbt_defaults(dev_priv); /* XXX Should this validation be moved to intel_opregion.c? */ - if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) { - struct vbt_header *vbt = dev_priv->opregion.vbt; - if (memcmp(vbt->signature, "$VBT", 4) == 0) { - DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n", - vbt->signature); - bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset); - } else - dev_priv->opregion.vbt = NULL; - } + if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) + bdb = validate_vbt((char *)dev_priv->opregion.header, OPREGION_SIZE, + (struct vbt_header *)dev_priv->opregion.vbt, + "OpRegion"); if (bdb == NULL) { - struct vbt_header *vbt = NULL; - size_t size; - int i; + size_t i, size; bios = pci_map_rom(pdev, &size); if (!bios) @@ -913,19 +1182,18 @@ intel_parse_bios(struct drm_device *dev) /* Scour memory looking for the VBT signature */ for (i = 0; i + 4 < size; i++) { - if (!memcmp(bios + i, "$VBT", 4)) { - vbt = (struct vbt_header *)(bios + i); + if (memcmp(bios + i, "$VBT", 4) == 0) { + bdb = validate_vbt(bios, size, + (struct vbt_header *)(bios + i), + "PCI ROM"); break; } } - if (!vbt) { - DRM_DEBUG_DRIVER("VBT signature missing\n"); + if (!bdb) { pci_unmap_rom(pdev, bios); return -1; } - - bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); } /* Grab useful general definitions */ diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index f27f7b282465aa..6009debebaaf64 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -282,6 +282,9 @@ struct bdb_general_definitions { union child_device_config devices[0]; } __packed; +/* Mask for DRRS / Panel Channel / SSC / BLT control bits extraction */ +#define MODE_MASK 0x3 + struct bdb_lvds_options { u8 panel_type; u8 rsvd1; @@ -294,6 +297,18 @@ struct bdb_lvds_options { u8 lvds_edid:1; u8 rsvd2:1; u8 rsvd4; + /* LVDS Panel channel bits stored here */ + u32 lvds_panel_channel_bits; + /* LVDS SSC (Spread Spectrum Clock) bits stored here. */ + u16 ssc_bits; + u16 ssc_freq; + u16 ssc_ddt; + /* Panel color depth defined here */ + u16 panel_color_depth; + /* LVDS panel type bits stored here */ + u32 dps_panel_type_bits; + /* LVDS backlight control type bits stored here */ + u32 blt_control_type_bits; } __packed; /* LFP pointer table contains entries to the struct below */ @@ -482,6 +497,20 @@ struct bdb_driver_features { u8 hdmi_termination; u8 custom_vbt_version; + /* Driver features data block */ + u16 rmpm_enabled:1; + u16 s2ddt_enabled:1; + u16 dpst_enabled:1; + u16 bltclt_enabled:1; + u16 adb_enabled:1; + u16 drrs_enabled:1; + u16 grs_enabled:1; + u16 gpmt_enabled:1; + u16 tbt_enabled:1; + u16 psr_enabled:1; + u16 ips_enabled:1; + u16 reserved3:4; + u16 pc_feature_valid:1; } __packed; #define EDP_18BPP 0 @@ -870,4 +899,35 @@ struct bdb_mipi_sequence { u8 data[0]; }; +/* MIPI Sequnece Block definitions */ +enum mipi_seq { + MIPI_SEQ_UNDEFINED = 0, + MIPI_SEQ_ASSERT_RESET, + MIPI_SEQ_INIT_OTP, + MIPI_SEQ_DISPLAY_ON, + MIPI_SEQ_DISPLAY_OFF, + MIPI_SEQ_DEASSERT_RESET, + MIPI_SEQ_MAX +}; + +enum mipi_seq_element { + MIPI_SEQ_ELEM_UNDEFINED = 0, + MIPI_SEQ_ELEM_SEND_PKT, + MIPI_SEQ_ELEM_DELAY, + MIPI_SEQ_ELEM_GPIO, + MIPI_SEQ_ELEM_STATUS, + MIPI_SEQ_ELEM_MAX +}; + +enum mipi_gpio_pin_index { + MIPI_GPIO_UNDEFINED = 0, + MIPI_GPIO_PANEL_ENABLE, + MIPI_GPIO_BL_ENABLE, + MIPI_GPIO_PWM_ENABLE, + MIPI_GPIO_RESET_N, + MIPI_GPIO_PWR_DOWN_R, + MIPI_GPIO_STDBY_RST_N, + MIPI_GPIO_MAX +}; + #endif /* _I830_BIOS_H_ */ diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index aa5a3dc43342a1..22d8347f7838eb 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -144,28 +144,49 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crt *crt = intel_encoder_to_crt(encoder); - u32 temp; + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode; + u32 adpa; + + if (INTEL_INFO(dev)->gen >= 5) + adpa = ADPA_HOTPLUG_BITS; + else + adpa = 0; - temp = I915_READ(crt->adpa_reg); - temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); - temp &= ~ADPA_DAC_ENABLE; + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) + adpa |= ADPA_HSYNC_ACTIVE_HIGH; + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) + adpa |= ADPA_VSYNC_ACTIVE_HIGH; + + /* For CPT allow 3 pipe config, for others just use A or B */ + if (HAS_PCH_LPT(dev)) + ; /* Those bits don't exist here */ + else if (HAS_PCH_CPT(dev)) + adpa |= PORT_TRANS_SEL_CPT(crtc->pipe); + else if (crtc->pipe == 0) + adpa |= ADPA_PIPE_A_SELECT; + else + adpa |= ADPA_PIPE_B_SELECT; + + if (!HAS_PCH_SPLIT(dev)) + I915_WRITE(BCLRPAT(crtc->pipe), 0); switch (mode) { case DRM_MODE_DPMS_ON: - temp |= ADPA_DAC_ENABLE; + adpa |= ADPA_DAC_ENABLE; break; case DRM_MODE_DPMS_STANDBY: - temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; + adpa |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; break; case DRM_MODE_DPMS_SUSPEND: - temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; + adpa |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; break; case DRM_MODE_DPMS_OFF: - temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; + adpa |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; break; } - I915_WRITE(crt->adpa_reg, temp); + I915_WRITE(crt->adpa_reg, adpa); } static void intel_disable_crt(struct intel_encoder *encoder) @@ -274,42 +295,6 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder, return true; } -static void intel_crt_mode_set(struct intel_encoder *encoder) -{ - - struct drm_device *dev = encoder->base.dev; - struct intel_crt *crt = intel_encoder_to_crt(encoder); - struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode; - u32 adpa; - - if (INTEL_INFO(dev)->gen >= 5) - adpa = ADPA_HOTPLUG_BITS; - else - adpa = 0; - - if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) - adpa |= ADPA_HSYNC_ACTIVE_HIGH; - if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) - adpa |= ADPA_VSYNC_ACTIVE_HIGH; - - /* For CPT allow 3 pipe config, for others just use A or B */ - if (HAS_PCH_LPT(dev)) - ; /* Those bits don't exist here */ - else if (HAS_PCH_CPT(dev)) - adpa |= PORT_TRANS_SEL_CPT(crtc->pipe); - else if (crtc->pipe == 0) - adpa |= ADPA_PIPE_A_SELECT; - else - adpa |= ADPA_PIPE_B_SELECT; - - if (!HAS_PCH_SPLIT(dev)) - I915_WRITE(BCLRPAT(crtc->pipe), 0); - - I915_WRITE(crt->adpa_reg, adpa); -} - static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -867,7 +852,6 @@ void intel_crt_init(struct drm_device *dev) crt->adpa_reg = ADPA; crt->base.compute_config = intel_crt_compute_config; - crt->base.mode_set = intel_crt_mode_set; crt->base.disable = intel_disable_crt; crt->base.enable = intel_enable_crt; if (I915_HAS_HOTPLUG(dev)) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 48aa516a1ac0c3..617e2630b78246 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -765,7 +765,7 @@ static void g4x_wait_for_vblank(struct drm_device *dev, int pipe) frame = I915_READ(frame_reg); if (wait_for(I915_READ_NOTRACE(frame_reg) != frame, 50)) - DRM_DEBUG_KMS("vblank wait timed out\n"); + WARN(1, "vblank wait timed out\n"); } /** @@ -1804,16 +1804,6 @@ static void intel_enable_pipe(struct intel_crtc *crtc) I915_WRITE(reg, val | PIPECONF_ENABLE); POSTING_READ(reg); - - /* - * There's no guarantee the pipe will really start running now. It - * depends on the Gen, the output type and the relative order between - * pipe and plane enabling. Avoid waiting on HSW+ since it's not - * necessary. - * TODO: audit the previous gens. - */ - if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) - intel_wait_for_vblank(dev_priv->dev, pipe); } /** @@ -1890,14 +1880,14 @@ static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv, /* If the pipe isn't enabled, we can't pump pixels and may hang */ assert_pipe_enabled(dev_priv, pipe); - WARN(intel_crtc->primary_enabled, "Primary plane already enabled\n"); + if (intel_crtc->primary_enabled) + return; intel_crtc->primary_enabled = true; reg = DSPCNTR(plane); val = I915_READ(reg); - if (val & DISPLAY_PLANE_ENABLE) - return; + WARN_ON(val & DISPLAY_PLANE_ENABLE); I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE); intel_flush_primary_plane(dev_priv, plane); @@ -1920,14 +1910,14 @@ static void intel_disable_primary_hw_plane(struct drm_i915_private *dev_priv, int reg; u32 val; - WARN(!intel_crtc->primary_enabled, "Primary plane already disabled\n"); + if (!intel_crtc->primary_enabled) + return; intel_crtc->primary_enabled = false; reg = DSPCNTR(plane); val = I915_READ(reg); - if ((val & DISPLAY_PLANE_ENABLE) == 0) - return; + WARN_ON((val & DISPLAY_PLANE_ENABLE) == 0); I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE); intel_flush_primary_plane(dev_priv, plane); @@ -2166,15 +2156,6 @@ static int i9xx_update_primary_plane(struct drm_crtc *crtc, u32 dspcntr; u32 reg; - switch (plane) { - case 0: - case 1: - break; - default: - DRM_ERROR("Can't update plane %c in SAREA\n", plane_name(plane)); - return -EINVAL; - } - intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; @@ -2267,16 +2248,6 @@ static int ironlake_update_primary_plane(struct drm_crtc *crtc, u32 dspcntr; u32 reg; - switch (plane) { - case 0: - case 1: - case 2: - break; - default: - DRM_ERROR("Can't update plane %c in SAREA\n", plane_name(plane)); - return -EINVAL; - } - intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; @@ -2628,12 +2599,10 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - int plane = intel_crtc->plane; u32 reg, temp, tries; - /* FDI needs bits from pipe & plane first */ + /* FDI needs bits from pipe first */ assert_pipe_enabled(dev_priv, pipe); - assert_plane_enabled(dev_priv, plane); /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit for train result */ @@ -3602,10 +3571,13 @@ void hsw_disable_ips(struct intel_crtc *crtc) return; assert_plane_enabled(dev_priv, crtc->plane); - if (IS_BROADWELL(crtc->base.dev)) { + if (IS_BROADWELL(dev)) { mutex_lock(&dev_priv->rps.hw_lock); WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0)); mutex_unlock(&dev_priv->rps.hw_lock); + /* wait for pcode to finish disabling IPS, which may take up to 42ms */ + if (wait_for((I915_READ(IPS_CTL) & IPS_ENABLE) == 0, 42)) + DRM_ERROR("Timed out waiting for IPS disable\n"); } else { I915_WRITE(IPS_CTL, 0); POSTING_READ(IPS_CTL); @@ -3662,6 +3634,46 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc) hsw_enable_ips(intel_crtc); } +static void ilk_crtc_enable_planes(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + + intel_enable_primary_hw_plane(dev_priv, plane, pipe); + intel_enable_planes(crtc); + intel_crtc_update_cursor(crtc, true); + + hsw_enable_ips(intel_crtc); + + mutex_lock(&dev->struct_mutex); + intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); +} + +static void ilk_crtc_disable_planes(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + + intel_crtc_wait_for_pending_flips(crtc); + drm_vblank_off(dev, pipe); + + if (dev_priv->fbc.plane == plane) + intel_disable_fbc(dev); + + hsw_disable_ips(intel_crtc); + + intel_crtc_update_cursor(crtc, false); + intel_disable_planes(crtc); + intel_disable_primary_hw_plane(dev_priv, plane, pipe); +} + static void ironlake_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3669,7 +3681,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - int plane = intel_crtc->plane; WARN_ON(!crtc->enabled); @@ -3705,23 +3716,18 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(crtc); intel_enable_pipe(intel_crtc); - intel_enable_primary_hw_plane(dev_priv, plane, pipe); - intel_enable_planes(crtc); - intel_crtc_update_cursor(crtc, true); if (intel_crtc->config.has_pch_encoder) ironlake_pch_enable(crtc); - mutex_lock(&dev->struct_mutex); - intel_update_fbc(dev); - mutex_unlock(&dev->struct_mutex); - for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); if (HAS_PCH_CPT(dev)) cpt_verify_modeset(dev, intel_crtc->pipe); + ilk_crtc_enable_planes(crtc); + /* * There seems to be a race in PCH platform hw (at least on some * outputs) where an enabled pipe still completes any pageflip right @@ -3739,47 +3745,6 @@ static bool hsw_crtc_supports_ips(struct intel_crtc *crtc) return HAS_IPS(crtc->base.dev) && crtc->pipe == PIPE_A; } -static void haswell_crtc_enable_planes(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; - int plane = intel_crtc->plane; - - intel_enable_primary_hw_plane(dev_priv, plane, pipe); - intel_enable_planes(crtc); - intel_crtc_update_cursor(crtc, true); - - hsw_enable_ips(intel_crtc); - - mutex_lock(&dev->struct_mutex); - intel_update_fbc(dev); - mutex_unlock(&dev->struct_mutex); -} - -static void haswell_crtc_disable_planes(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; - int plane = intel_crtc->plane; - - intel_crtc_wait_for_pending_flips(crtc); - drm_vblank_off(dev, pipe); - - /* FBC must be disabled before disabling the plane on HSW. */ - if (dev_priv->fbc.plane == plane) - intel_disable_fbc(dev); - - hsw_disable_ips(intel_crtc); - - intel_crtc_update_cursor(crtc, false); - intel_disable_planes(crtc); - intel_disable_primary_hw_plane(dev_priv, plane, pipe); -} - /* * This implements the workaround described in the "notes" section of the mode * set sequence documentation. When going from no pipes or single pipe to @@ -3862,7 +3827,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) /* If we change the relative order between pipe/planes enabling, we need * to change the workaround. */ haswell_mode_set_planes_workaround(intel_crtc); - haswell_crtc_enable_planes(crtc); + ilk_crtc_enable_planes(crtc); } static void ironlake_pfit_disable(struct intel_crtc *crtc) @@ -3887,26 +3852,16 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - int plane = intel_crtc->plane; u32 reg, temp; - if (!intel_crtc->active) return; + ilk_crtc_disable_planes(crtc); + for_each_encoder_on_crtc(dev, crtc, encoder) encoder->disable(encoder); - intel_crtc_wait_for_pending_flips(crtc); - drm_vblank_off(dev, pipe); - - if (dev_priv->fbc.plane == plane) - intel_disable_fbc(dev); - - intel_crtc_update_cursor(crtc, false); - intel_disable_planes(crtc); - intel_disable_primary_hw_plane(dev_priv, plane, pipe); - if (intel_crtc->config.has_pch_encoder) intel_set_pch_fifo_underrun_reporting(dev, pipe, false); @@ -3965,7 +3920,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) if (!intel_crtc->active) return; - haswell_crtc_disable_planes(crtc); + ilk_crtc_disable_planes(crtc); for_each_encoder_on_crtc(dev, crtc, encoder) { intel_opregion_notify_encoder(encoder, false); @@ -4207,6 +4162,9 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) struct drm_i915_private *dev_priv = dev->dev_private; u32 val, cmd; + WARN_ON(valleyview_cur_cdclk(dev_priv) != dev_priv->vlv_cdclk_freq); + dev_priv->vlv_cdclk_freq = cdclk; + if (cdclk >= 320) /* jump to highest voltage for 400MHz too */ cmd = 2; else if (cdclk == 266) @@ -4261,7 +4219,7 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) intel_i2c_reset(dev); } -static int valleyview_cur_cdclk(struct drm_i915_private *dev_priv) +int valleyview_cur_cdclk(struct drm_i915_private *dev_priv) { int cur_cdclk, vco; int divider; @@ -4282,10 +4240,6 @@ static int valleyview_cur_cdclk(struct drm_i915_private *dev_priv) static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv, int max_pixclk) { - int cur_cdclk; - - cur_cdclk = valleyview_cur_cdclk(dev_priv); - /* * Really only a few cases to deal with, as only 4 CDclks are supported: * 200MHz @@ -4327,9 +4281,9 @@ static void valleyview_modeset_global_pipes(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc; int max_pixclk = intel_mode_max_pixclk(dev_priv); - int cur_cdclk = valleyview_cur_cdclk(dev_priv); - if (valleyview_calc_cdclk(dev_priv, max_pixclk) == cur_cdclk) + if (valleyview_calc_cdclk(dev_priv, max_pixclk) == + dev_priv->vlv_cdclk_freq) return; /* disable/enable all currently active pipes while we change cdclk */ @@ -4343,10 +4297,9 @@ static void valleyview_modeset_global_resources(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int max_pixclk = intel_mode_max_pixclk(dev_priv); - int cur_cdclk = valleyview_cur_cdclk(dev_priv); int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); - if (req_cdclk != cur_cdclk) + if (req_cdclk != dev_priv->vlv_cdclk_freq) valleyview_set_cdclk(dev, req_cdclk); modeset_update_crtc_power_domains(dev); } @@ -4387,7 +4340,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(crtc); intel_enable_pipe(intel_crtc); + intel_wait_for_vblank(dev_priv->dev, pipe); intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); + intel_enable_primary_hw_plane(dev_priv, plane, pipe); intel_enable_planes(crtc); intel_crtc_update_cursor(crtc, true); @@ -4426,7 +4381,9 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(crtc); intel_enable_pipe(intel_crtc); + intel_wait_for_vblank(dev_priv->dev, pipe); intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); + intel_enable_primary_hw_plane(dev_priv, plane, pipe); intel_enable_planes(crtc); /* The fixup needs to happen before cursor is enabled */ @@ -5245,9 +5202,6 @@ static void vlv_update_pll(struct intel_crtc *crtc) << DPLL_MD_UDI_MULTIPLIER_SHIFT; crtc->config.dpll_hw_state.dpll_md = dpll_md; - if (crtc->config.has_dp_encoder) - intel_dp_set_m_n(crtc); - mutex_unlock(&dev_priv->dpio_lock); } @@ -5325,9 +5279,6 @@ static void i9xx_update_pll(struct intel_crtc *crtc, << DPLL_MD_UDI_MULTIPLIER_SHIFT; crtc->config.dpll_hw_state.dpll_md = dpll_md; } - - if (crtc->config.has_dp_encoder) - intel_dp_set_m_n(crtc); } static void i8xx_update_pll(struct intel_crtc *crtc, @@ -5656,6 +5607,9 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, dspcntr |= DISPPLANE_SEL_PIPE_B; } + if (intel_crtc->config.has_dp_encoder) + intel_dp_set_m_n(intel_crtc); + intel_set_pipe_timings(intel_crtc); /* pipesrc and dspsize control the size that is scaled from, @@ -6880,8 +6834,6 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) struct drm_device *dev = dev_priv->dev; struct intel_ddi_plls *plls = &dev_priv->ddi_plls; struct intel_crtc *crtc; - unsigned long irqflags; - uint32_t val; list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) WARN(crtc->active, "CRTC for pipe %c enabled\n", @@ -6902,14 +6854,29 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) "Utility pin enabled\n"); WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n"); - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - val = I915_READ(DEIMR); - WARN((val | DE_PCH_EVENT_IVB) != 0xffffffff, - "Unexpected DEIMR bits enabled: 0x%x\n", val); - val = I915_READ(SDEIMR); - WARN((val | SDE_HOTPLUG_MASK_CPT) != 0xffffffff, - "Unexpected SDEIMR bits enabled: 0x%x\n", val); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + /* + * In theory we can still leave IRQs enabled, as long as only the HPD + * interrupts remain enabled. We used to check for that, but since it's + * gen-specific and since we only disable LCPLL after we fully disable + * the interrupts, the check below should be enough. + */ + WARN(!dev_priv->pm.irqs_disabled, "IRQs enabled\n"); +} + +static void hsw_write_dcomp(struct drm_i915_private *dev_priv, uint32_t val) +{ + struct drm_device *dev = dev_priv->dev; + + if (IS_HASWELL(dev)) { + mutex_lock(&dev_priv->rps.hw_lock); + if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP, + val)) + DRM_ERROR("Failed to disable D_COMP\n"); + mutex_unlock(&dev_priv->rps.hw_lock); + } else { + I915_WRITE(D_COMP, val); + } + POSTING_READ(D_COMP); } /* @@ -6949,11 +6916,7 @@ static void hsw_disable_lcpll(struct drm_i915_private *dev_priv, val = I915_READ(D_COMP); val |= D_COMP_COMP_DISABLE; - mutex_lock(&dev_priv->rps.hw_lock); - if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP, val)) - DRM_ERROR("Failed to disable D_COMP\n"); - mutex_unlock(&dev_priv->rps.hw_lock); - POSTING_READ(D_COMP); + hsw_write_dcomp(dev_priv, val); ndelay(100); if (wait_for((I915_READ(D_COMP) & D_COMP_RCOMP_IN_PROGRESS) == 0, 1)) @@ -7008,11 +6971,7 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv) val = I915_READ(D_COMP); val |= D_COMP_COMP_FORCE; val &= ~D_COMP_COMP_DISABLE; - mutex_lock(&dev_priv->rps.hw_lock); - if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP, val)) - DRM_ERROR("Failed to enable D_COMP\n"); - mutex_unlock(&dev_priv->rps.hw_lock); - POSTING_READ(D_COMP); + hsw_write_dcomp(dev_priv, val); val = I915_READ(LCPLL_CTL); val &= ~LCPLL_PLL_DISABLE; @@ -7066,8 +7025,6 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv) struct drm_device *dev = dev_priv->dev; uint32_t val; - WARN_ON(!HAS_PC8(dev)); - DRM_DEBUG_KMS("Enabling package C8+\n"); if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { @@ -7077,7 +7034,6 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv) } lpt_disable_clkout_dp(dev); - hsw_runtime_pm_disable_interrupts(dev); hsw_disable_lcpll(dev_priv, true, true); } @@ -7086,12 +7042,9 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv) struct drm_device *dev = dev_priv->dev; uint32_t val; - WARN_ON(!HAS_PC8(dev)); - DRM_DEBUG_KMS("Disabling package C8+\n"); hsw_restore_lcpll(dev_priv); - hsw_runtime_pm_restore_interrupts(dev); lpt_init_pch_refclk(dev); if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { @@ -7101,10 +7054,11 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv) } intel_prepare_ddi(dev); - i915_gem_init_swizzling(dev); - mutex_lock(&dev_priv->rps.hw_lock); - gen6_update_ring_freq(dev); - mutex_unlock(&dev_priv->rps.hw_lock); +} + +static void snb_modeset_global_resources(struct drm_device *dev) +{ + modeset_update_crtc_power_domains(dev); } static void haswell_modeset_global_resources(struct drm_device *dev) @@ -7254,7 +7208,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, encoder->base.base.id, drm_get_encoder_name(&encoder->base), mode->base.id, mode->name); - encoder->mode_set(encoder); + + if (encoder->mode_set) + encoder->mode_set(encoder); } return 0; @@ -7374,7 +7330,6 @@ static void haswell_write_eld(struct drm_connector *connector, { struct drm_i915_private *dev_priv = connector->dev->dev_private; uint8_t *eld = connector->eld; - struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t eldv; uint32_t i; @@ -7387,17 +7342,14 @@ static void haswell_write_eld(struct drm_connector *connector, int aud_config = HSW_AUD_CFG(pipe); int aud_cntrl_st2 = HSW_AUD_PIN_ELD_CP_VLD; - - DRM_DEBUG_DRIVER("HDMI: Haswell Audio initialize....\n"); - /* Audio output enable */ DRM_DEBUG_DRIVER("HDMI audio: enable codec\n"); tmp = I915_READ(aud_cntrl_st2); tmp |= (AUDIO_OUTPUT_ENABLE_A << (pipe * 4)); I915_WRITE(aud_cntrl_st2, tmp); + POSTING_READ(aud_cntrl_st2); - /* Wait for 1 vertical blank */ - intel_wait_for_vblank(dev, pipe); + assert_pipe_disabled(dev_priv, to_intel_crtc(crtc)->pipe); /* Set ELD valid state */ tmp = I915_READ(aud_cntrl_st2); @@ -8836,8 +8788,16 @@ static int intel_gen7_queue_flip(struct drm_device *dev, } len = 4; - if (ring->id == RCS) + if (ring->id == RCS) { len += 6; + /* + * On Gen 8, SRM is now taking an extra dword to accommodate + * 48bits addresses, and we need a NOOP for the batch size to + * stay even. + */ + if (IS_GEN8(dev)) + len += 2; + } /* * BSpec MI_DISPLAY_FLIP for IVB: @@ -8872,10 +8832,18 @@ static int intel_gen7_queue_flip(struct drm_device *dev, intel_ring_emit(ring, ~(DERRMR_PIPEA_PRI_FLIP_DONE | DERRMR_PIPEB_PRI_FLIP_DONE | DERRMR_PIPEC_PRI_FLIP_DONE)); - intel_ring_emit(ring, MI_STORE_REGISTER_MEM(1) | - MI_SRM_LRM_GLOBAL_GTT); + if (IS_GEN8(dev)) + intel_ring_emit(ring, MI_STORE_REGISTER_MEM_GEN8(1) | + MI_SRM_LRM_GLOBAL_GTT); + else + intel_ring_emit(ring, MI_STORE_REGISTER_MEM(1) | + MI_SRM_LRM_GLOBAL_GTT); intel_ring_emit(ring, DERRMR); intel_ring_emit(ring, ring->scratch.gtt_offset + 256); + if (IS_GEN8(dev)) { + intel_ring_emit(ring, 0); + intel_ring_emit(ring, MI_NOOP); + } } intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit); @@ -10578,16 +10546,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs); - if (IS_GEN2(dev)) { - intel_crtc->max_cursor_width = GEN2_CURSOR_WIDTH; - intel_crtc->max_cursor_height = GEN2_CURSOR_HEIGHT; - } else { - intel_crtc->max_cursor_width = CURSOR_WIDTH; - intel_crtc->max_cursor_height = CURSOR_HEIGHT; - } - dev->mode_config.cursor_width = intel_crtc->max_cursor_width; - dev->mode_config.cursor_height = intel_crtc->max_cursor_height; - drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256); for (i = 0; i < 256; i++) { intel_crtc->lut_r[i] = i; @@ -10606,6 +10564,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->plane = !pipe; } + init_waitqueue_head(&intel_crtc->vbl_wait); + BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL); dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base; @@ -11088,6 +11048,8 @@ static void intel_init_display(struct drm_device *dev) } else if (IS_GEN6(dev)) { dev_priv->display.fdi_link_train = gen6_fdi_link_train; dev_priv->display.write_eld = ironlake_write_eld; + dev_priv->display.modeset_global_resources = + snb_modeset_global_resources; } else if (IS_IVYBRIDGE(dev)) { /* FIXME: detect B0+ stepping and use auto training */ dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; @@ -11292,9 +11254,7 @@ void intel_modeset_init_hw(struct drm_device *dev) intel_reset_dpio(dev); - mutex_lock(&dev->struct_mutex); intel_enable_gt_powersave(dev); - mutex_unlock(&dev->struct_mutex); } void intel_modeset_suspend_hw(struct drm_device *dev) @@ -11338,6 +11298,15 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.max_width = 8192; dev->mode_config.max_height = 8192; } + + if (IS_GEN2(dev)) { + dev->mode_config.cursor_width = GEN2_CURSOR_WIDTH; + dev->mode_config.cursor_height = GEN2_CURSOR_HEIGHT; + } else { + dev->mode_config.cursor_width = MAX_CURSOR_WIDTH; + dev->mode_config.cursor_height = MAX_CURSOR_HEIGHT; + } + dev->mode_config.fb_base = dev_priv->gtt.mappable_base; DRM_DEBUG_KMS("%d display pipe%s available.\n", @@ -11616,6 +11585,16 @@ void i915_redisable_vga(struct drm_device *dev) i915_redisable_vga_power_on(dev); } +static bool primary_get_hw_state(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + + if (!crtc->active) + return false; + + return I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE; +} + static void intel_modeset_readout_hw_state(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -11635,7 +11614,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) &crtc->config); crtc->base.enabled = crtc->active; - crtc->primary_enabled = crtc->active; + crtc->primary_enabled = primary_get_hw_state(crtc); DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", crtc->base.base.id, @@ -11938,6 +11917,7 @@ struct intel_display_error_state { struct intel_pipe_error_state { bool power_domain_on; u32 source; + u32 stat; } pipe[I915_MAX_PIPES]; struct intel_plane_error_state { @@ -12019,6 +11999,9 @@ intel_display_capture_error_state(struct drm_device *dev) } error->pipe[i].source = I915_READ(PIPESRC(i)); + + if (!HAS_PCH_SPLIT(dev)) + error->pipe[i].stat = I915_READ(PIPESTAT(i)); } error->num_transcoders = INTEL_INFO(dev)->num_pipes; @@ -12069,6 +12052,7 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m, err_printf(m, " Power: %s\n", error->pipe[i].power_domain_on ? "on" : "off"); err_printf(m, " SRC: %08x\n", error->pipe[i].source); + err_printf(m, " STAT: %08x\n", error->pipe[i].stat); err_printf(m, "Plane [%d]:\n", i); err_printf(m, " CNTR: %08x\n", error->plane[i].control); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5ca68aa9f237e0..87b0a515d7a5f8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -314,8 +314,12 @@ static bool edp_have_panel_vdd(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct intel_encoder *intel_encoder = &intel_dig_port->base; + enum intel_display_power_domain power_domain; - return !dev_priv->pm.suspended && + power_domain = intel_display_port_power_domain(intel_encoder); + return intel_display_power_enabled(dev_priv, power_domain) && (I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD) != 0; } @@ -739,6 +743,20 @@ intel_dp_set_clock(struct intel_encoder *encoder, } } +static void +intel_dp_set_m2_n2(struct intel_crtc *crtc, struct intel_link_m_n *m_n) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder transcoder = crtc->config.cpu_transcoder; + + I915_WRITE(PIPE_DATA_M2(transcoder), + TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(PIPE_DATA_N2(transcoder), m_n->gmch_n); + I915_WRITE(PIPE_LINK_M2(transcoder), m_n->link_m); + I915_WRITE(PIPE_LINK_N2(transcoder), m_n->link_n); +} + bool intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config) @@ -843,6 +861,14 @@ intel_dp_compute_config(struct intel_encoder *encoder, pipe_config->port_clock, &pipe_config->dp_m_n); + if (intel_connector->panel.downclock_mode != NULL && + intel_dp->drrs_state.type == SEAMLESS_DRRS_SUPPORT) { + intel_link_compute_m_n(bpp, lane_count, + intel_connector->panel.downclock_mode->clock, + pipe_config->port_clock, + &pipe_config->dp_m2_n2); + } + intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw); return true; @@ -1045,7 +1071,10 @@ static u32 ironlake_get_pp_control(struct intel_dp *intel_dp) static bool _edp_panel_vdd_on(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct intel_encoder *intel_encoder = &intel_dig_port->base; struct drm_i915_private *dev_priv = dev->dev_private; + enum intel_display_power_domain power_domain; u32 pp; u32 pp_stat_reg, pp_ctrl_reg; bool need_to_disable = !intel_dp->want_panel_vdd; @@ -1058,7 +1087,8 @@ static bool _edp_panel_vdd_on(struct intel_dp *intel_dp) if (edp_have_panel_vdd(intel_dp)) return need_to_disable; - intel_runtime_pm_get(dev_priv); + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_get(dev_priv, power_domain); DRM_DEBUG_KMS("Turning eDP VDD on\n"); @@ -1105,6 +1135,11 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp) WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); if (!intel_dp->want_panel_vdd && edp_have_panel_vdd(intel_dp)) { + struct intel_digital_port *intel_dig_port = + dp_to_dig_port(intel_dp); + struct intel_encoder *intel_encoder = &intel_dig_port->base; + enum intel_display_power_domain power_domain; + DRM_DEBUG_KMS("Turning eDP VDD off\n"); pp = ironlake_get_pp_control(intel_dp); @@ -1123,7 +1158,8 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp) if ((pp & POWER_TARGET_ON) == 0) intel_dp->last_power_cycle = jiffies; - intel_runtime_pm_put(dev_priv); + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_put(dev_priv, power_domain); } } @@ -1207,8 +1243,11 @@ void intel_edp_panel_on(struct intel_dp *intel_dp) void intel_edp_panel_off(struct intel_dp *intel_dp) { + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct intel_encoder *intel_encoder = &intel_dig_port->base; struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; + enum intel_display_power_domain power_domain; u32 pp; u32 pp_ctrl_reg; @@ -1238,7 +1277,8 @@ void intel_edp_panel_off(struct intel_dp *intel_dp) wait_panel_off(intel_dp); /* We got a reference when we enabled the VDD. */ - intel_runtime_pm_put(dev_priv); + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_put(dev_priv, power_domain); } void intel_edp_backlight_on(struct intel_dp *intel_dp) @@ -1779,17 +1819,23 @@ static void intel_disable_dp(struct intel_encoder *encoder) intel_dp_link_down(intel_dp); } -static void intel_post_disable_dp(struct intel_encoder *encoder) +static void g4x_post_disable_dp(struct intel_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); enum port port = dp_to_dig_port(intel_dp)->port; - struct drm_device *dev = encoder->base.dev; - if (port == PORT_A || IS_VALLEYVIEW(dev)) { - intel_dp_link_down(intel_dp); - if (!IS_VALLEYVIEW(dev)) - ironlake_edp_pll_off(intel_dp); - } + if (port != PORT_A) + return; + + intel_dp_link_down(intel_dp); + ironlake_edp_pll_off(intel_dp); +} + +static void vlv_post_disable_dp(struct intel_encoder *encoder) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + + intel_dp_link_down(intel_dp); } static void intel_enable_dp(struct intel_encoder *encoder) @@ -2738,9 +2784,6 @@ intel_dp_link_down(struct intel_dp *intel_dp) } POSTING_READ(intel_dp->output_reg); - /* We don't really know why we're doing this */ - intel_wait_for_vblank(dev, intel_crtc->pipe); - if (HAS_PCH_IBX(dev) && I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) { struct drm_crtc *crtc = intel_dig_port->base.base.crtc; @@ -3614,6 +3657,130 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, I915_READ(pp_div_reg)); } +void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *encoder; + struct intel_dp *intel_dp = NULL; + struct intel_crtc_config *config = NULL; + struct intel_crtc *intel_crtc = NULL; + struct intel_connector *intel_connector = dev_priv->drrs.connector; + u32 reg, val; + enum edp_drrs_refresh_rate_type index = DRRS_HIGH_RR; + + if (refresh_rate <= 0) { + DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n"); + return; + } + + if (intel_connector == NULL) { + DRM_DEBUG_KMS("DRRS supported for eDP only.\n"); + return; + } + + if (INTEL_INFO(dev)->gen < 8 && intel_edp_is_psr_enabled(dev)) { + DRM_DEBUG_KMS("DRRS is disabled as PSR is enabled\n"); + return; + } + + encoder = intel_attached_encoder(&intel_connector->base); + intel_dp = enc_to_intel_dp(&encoder->base); + intel_crtc = encoder->new_crtc; + + if (!intel_crtc) { + DRM_DEBUG_KMS("DRRS: intel_crtc not initialized\n"); + return; + } + + config = &intel_crtc->config; + + if (intel_dp->drrs_state.type < SEAMLESS_DRRS_SUPPORT) { + DRM_DEBUG_KMS("Only Seamless DRRS supported.\n"); + return; + } + + if (intel_connector->panel.downclock_mode->vrefresh == refresh_rate) + index = DRRS_LOW_RR; + + if (index == intel_dp->drrs_state.refresh_rate_type) { + DRM_DEBUG_KMS( + "DRRS requested for previously set RR...ignoring\n"); + return; + } + + if (!intel_crtc->active) { + DRM_DEBUG_KMS("eDP encoder disabled. CRTC not Active\n"); + return; + } + + if (INTEL_INFO(dev)->gen > 6 && INTEL_INFO(dev)->gen < 8) { + reg = PIPECONF(intel_crtc->config.cpu_transcoder); + val = I915_READ(reg); + if (index > DRRS_HIGH_RR) { + val |= PIPECONF_EDP_RR_MODE_SWITCH; + intel_dp_set_m2_n2(intel_crtc, &config->dp_m2_n2); + } else { + val &= ~PIPECONF_EDP_RR_MODE_SWITCH; + } + I915_WRITE(reg, val); + } + + /* + * mutex taken to ensure that there is no race between differnt + * drrs calls trying to update refresh rate. This scenario may occur + * in future when idleness detection based DRRS in kernel and + * possible calls from user space to set differnt RR are made. + */ + + mutex_lock(&intel_dp->drrs_state.mutex); + + intel_dp->drrs_state.refresh_rate_type = index; + + mutex_unlock(&intel_dp->drrs_state.mutex); + + DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate); +} + +static struct drm_display_mode * +intel_dp_drrs_init(struct intel_digital_port *intel_dig_port, + struct intel_connector *intel_connector, + struct drm_display_mode *fixed_mode) +{ + struct drm_connector *connector = &intel_connector->base; + struct intel_dp *intel_dp = &intel_dig_port->dp; + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_display_mode *downclock_mode = NULL; + + if (INTEL_INFO(dev)->gen <= 6) { + DRM_DEBUG_KMS("DRRS supported for Gen7 and above\n"); + return NULL; + } + + if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) { + DRM_INFO("VBT doesn't support DRRS\n"); + return NULL; + } + + downclock_mode = intel_find_panel_downclock + (dev, fixed_mode, connector); + + if (!downclock_mode) { + DRM_INFO("DRRS not supported\n"); + return NULL; + } + + dev_priv->drrs.connector = intel_connector; + + mutex_init(&intel_dp->drrs_state.mutex); + + intel_dp->drrs_state.type = dev_priv->vbt.drrs_type; + + intel_dp->drrs_state.refresh_rate_type = DRRS_HIGH_RR; + DRM_INFO("seamless DRRS supported for eDP panel.\n"); + return downclock_mode; +} + static bool intel_edp_init_connector(struct intel_dp *intel_dp, struct intel_connector *intel_connector, struct edp_power_seq *power_seq) @@ -3624,10 +3791,13 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_display_mode *fixed_mode = NULL; + struct drm_display_mode *downclock_mode = NULL; bool has_dpcd; struct drm_display_mode *scan; struct edid *edid; + intel_dp->drrs_state.type = DRRS_NOT_SUPPORTED; + if (!is_edp(intel_dp)) return true; @@ -3678,6 +3848,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, list_for_each_entry(scan, &connector->probed_modes, head) { if ((scan->type & DRM_MODE_TYPE_PREFERRED)) { fixed_mode = drm_mode_duplicate(dev, scan); + downclock_mode = intel_dp_drrs_init( + intel_dig_port, + intel_connector, fixed_mode); break; } } @@ -3691,7 +3864,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, } mutex_unlock(&dev->mode_config.mutex); - intel_panel_init(&intel_connector->panel, fixed_mode, NULL); + intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode); intel_panel_setup_backlight(connector); return true; @@ -3842,16 +4015,17 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->compute_config = intel_dp_compute_config; intel_encoder->mode_set = intel_dp_mode_set; intel_encoder->disable = intel_disable_dp; - intel_encoder->post_disable = intel_post_disable_dp; intel_encoder->get_hw_state = intel_dp_get_hw_state; intel_encoder->get_config = intel_dp_get_config; if (IS_VALLEYVIEW(dev)) { intel_encoder->pre_pll_enable = vlv_dp_pre_pll_enable; intel_encoder->pre_enable = vlv_pre_enable_dp; intel_encoder->enable = vlv_enable_dp; + intel_encoder->post_disable = vlv_post_disable_dp; } else { intel_encoder->pre_enable = g4x_pre_enable_dp; intel_encoder->enable = g4x_enable_dp; + intel_encoder->post_disable = g4x_post_disable_dp; } intel_dig_port->port = port; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 328b1a70264b4c..d8b540b891d1a7 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -81,8 +81,8 @@ /* Maximum cursor sizes */ #define GEN2_CURSOR_WIDTH 64 #define GEN2_CURSOR_HEIGHT 64 -#define CURSOR_WIDTH 256 -#define CURSOR_HEIGHT 256 +#define MAX_CURSOR_WIDTH 256 +#define MAX_CURSOR_HEIGHT 256 #define INTEL_I2C_BUS_DVO 1 #define INTEL_I2C_BUS_SDVO 2 @@ -306,6 +306,9 @@ struct intel_crtc_config { int pipe_bpp; struct intel_link_m_n dp_m_n; + /* m2_n2 for eDP downclock */ + struct intel_link_m_n dp_m2_n2; + /* * Frequence the dpll for the port should run at. Differs from the * adjusted dotclock e.g. for DP or 12bpc hdmi mode. This is also @@ -343,6 +346,9 @@ struct intel_pipe_wm { struct intel_wm_level wm[5]; uint32_t linetime; bool fbc_wm_enabled; + bool pipe_enabled; + bool sprites_enabled; + bool sprites_scaled; }; struct intel_crtc { @@ -374,7 +380,6 @@ struct intel_crtc { uint32_t cursor_addr; int16_t cursor_x, cursor_y; int16_t cursor_width, cursor_height; - int16_t max_cursor_width, max_cursor_height; bool cursor_visible; struct intel_plane_config plane_config; @@ -396,6 +401,8 @@ struct intel_crtc { /* watermarks currently being used */ struct intel_pipe_wm active; } wm; + + wait_queue_head_t vbl_wait; }; struct intel_plane_wm_parameters { @@ -484,6 +491,17 @@ struct intel_hdmi { #define DP_MAX_DOWNSTREAM_PORTS 0x10 +/** + * HIGH_RR is the highest eDP panel refresh rate read from EDID + * LOW_RR is the lowest eDP panel refresh rate found from EDID + * parsing for same resolution. + */ +enum edp_drrs_refresh_rate_type { + DRRS_HIGH_RR, + DRRS_LOW_RR, + DRRS_MAX_RR, /* RR count */ +}; + struct intel_dp { uint32_t output_reg; uint32_t aux_ch_ctl_reg; @@ -522,6 +540,12 @@ struct intel_dp { bool has_aux_irq, int send_bytes, uint32_t aux_clock_divider); + struct { + enum drrs_support_type type; + enum edp_drrs_refresh_rate_type refresh_rate_type; + struct mutex mutex; + } drrs_state; + }; struct intel_digital_port { @@ -629,8 +653,9 @@ void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); -void hsw_runtime_pm_disable_interrupts(struct drm_device *dev); -void hsw_runtime_pm_restore_interrupts(struct drm_device *dev); +void intel_runtime_pm_disable_interrupts(struct drm_device *dev); +void intel_runtime_pm_restore_interrupts(struct drm_device *dev); +int intel_get_crtc_scanline(struct intel_crtc *crtc); /* intel_crt.c */ @@ -666,6 +691,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder, const char *intel_output_name(int output); bool intel_has_pending_fb_unpin(struct drm_device *dev); int intel_pch_rawclk(struct drm_device *dev); +int valleyview_cur_cdclk(struct drm_i915_private *dev_priv); void intel_mark_busy(struct drm_device *dev); void intel_mark_fb_busy(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring); @@ -774,7 +800,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp); void intel_edp_psr_enable(struct intel_dp *intel_dp); void intel_edp_psr_disable(struct intel_dp *intel_dp); void intel_edp_psr_update(struct drm_device *dev); - +void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate); /* intel_dsi.c */ bool intel_dsi_init(struct drm_device *dev); @@ -902,6 +928,7 @@ void intel_init_gt_powersave(struct drm_device *dev); void intel_cleanup_gt_powersave(struct drm_device *dev); void intel_enable_gt_powersave(struct drm_device *dev); void intel_disable_gt_powersave(struct drm_device *dev); +void intel_reset_gt_powersave(struct drm_device *dev); void ironlake_teardown_rc6(struct drm_device *dev); void gen6_update_ring_freq(struct drm_device *dev); void gen6_rps_idle(struct drm_i915_private *dev_priv); @@ -909,6 +936,7 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv); void intel_runtime_pm_get(struct drm_i915_private *dev_priv); +void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv); void intel_runtime_pm_put(struct drm_i915_private *dev_priv); void intel_init_runtime_pm(struct drm_i915_private *dev_priv); void intel_fini_runtime_pm(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 33656647f8bcf5..4e271c768fd0c5 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -110,6 +110,15 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); + mutex_lock(&dev_priv->dpio_lock); + /* program rcomp for compliance, reduce from 50 ohms to 45 ohms + * needed everytime after power gate */ + vlv_flisdsi_write(dev_priv, 0x04, 0x0004); + mutex_unlock(&dev_priv->dpio_lock); + + /* bandgap reset is needed after everytime we do power gate */ + band_gap_reset(dev_priv); + val = I915_READ(MIPI_PORT_CTRL(pipe)); I915_WRITE(MIPI_PORT_CTRL(pipe), val | LP_OUTPUT_HOLD); usleep_range(1000, 1500); @@ -122,21 +131,6 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder) I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY); usleep_range(2000, 2500); } -static void intel_dsi_pre_enable(struct intel_encoder *encoder) -{ - struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); - - DRM_DEBUG_KMS("\n"); - - if (intel_dsi->dev.dev_ops->panel_reset) - intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev); - - /* put device in ready state */ - intel_dsi_device_ready(encoder); - - if (intel_dsi->dev.dev_ops->send_otp_cmds) - intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev); -} static void intel_dsi_enable(struct intel_encoder *encoder) { @@ -153,18 +147,63 @@ static void intel_dsi_enable(struct intel_encoder *encoder) I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4); else { msleep(20); /* XXX */ - dpi_send_cmd(intel_dsi, TURN_ON); + dpi_send_cmd(intel_dsi, TURN_ON, DPI_LP_MODE_EN); msleep(100); + if (intel_dsi->dev.dev_ops->enable) + intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); + /* assert ip_tg_enable signal */ temp = I915_READ(MIPI_PORT_CTRL(pipe)) & ~LANE_CONFIGURATION_MASK; temp = temp | intel_dsi->port_bits; I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE); POSTING_READ(MIPI_PORT_CTRL(pipe)); } +} + +static void intel_dsi_pre_enable(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + enum pipe pipe = intel_crtc->pipe; + u32 tmp; + + DRM_DEBUG_KMS("\n"); - if (intel_dsi->dev.dev_ops->enable) - intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); + /* Disable DPOunit clock gating, can stall pipe + * and we need DPLL REFA always enabled */ + tmp = I915_READ(DPLL(pipe)); + tmp |= DPLL_REFA_CLK_ENABLE_VLV; + I915_WRITE(DPLL(pipe), tmp); + + tmp = I915_READ(DSPCLK_GATE_D); + tmp |= DPOUNIT_CLOCK_GATE_DISABLE; + I915_WRITE(DSPCLK_GATE_D, tmp); + + /* put device in ready state */ + intel_dsi_device_ready(encoder); + + if (intel_dsi->dev.dev_ops->panel_reset) + intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev); + + if (intel_dsi->dev.dev_ops->send_otp_cmds) + intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev); + + /* Enable port in pre-enable phase itself because as per hw team + * recommendation, port should be enabled befor plane & pipe */ + intel_dsi_enable(encoder); +} + +static void intel_dsi_enable_nop(struct intel_encoder *encoder) +{ + DRM_DEBUG_KMS("\n"); + + /* for DSI port enable has to be done before pipe + * and plane enable, so port enable is done in + * pre_enable phase itself unlike other encoders + */ } static void intel_dsi_disable(struct intel_encoder *encoder) @@ -179,7 +218,8 @@ static void intel_dsi_disable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); if (is_vid_mode(intel_dsi)) { - dpi_send_cmd(intel_dsi, SHUTDOWN); + /* Send Shutdown command to the panel in LP mode */ + dpi_send_cmd(intel_dsi, SHUTDOWN, DPI_LP_MODE_EN); msleep(10); /* de-assert ip_tg_enable signal */ @@ -190,6 +230,23 @@ static void intel_dsi_disable(struct intel_encoder *encoder) msleep(2); } + /* Panel commands can be sent when clock is in LP11 */ + I915_WRITE(MIPI_DEVICE_READY(pipe), 0x0); + + temp = I915_READ(MIPI_CTRL(pipe)); + temp &= ~ESCAPE_CLOCK_DIVIDER_MASK; + I915_WRITE(MIPI_CTRL(pipe), temp | + intel_dsi->escape_clk_div << + ESCAPE_CLOCK_DIVIDER_SHIFT); + + I915_WRITE(MIPI_EOT_DISABLE(pipe), CLOCKSTOP); + + temp = I915_READ(MIPI_DSI_FUNC_PRG(pipe)); + temp &= ~VID_MODE_FORMAT_MASK; + I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), temp); + + I915_WRITE(MIPI_DEVICE_READY(pipe), 0x1); + /* if disable packets are sent before sending shutdown packet then in * some next enable sequence send turn on packet error is observed */ if (intel_dsi->dev.dev_ops->disable) @@ -227,14 +284,21 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) vlv_disable_dsi_pll(encoder); } + static void intel_dsi_post_disable(struct intel_encoder *encoder) { + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + u32 val; DRM_DEBUG_KMS("\n"); intel_dsi_clear_device_ready(encoder); + val = I915_READ(DSPCLK_GATE_D); + val &= ~DPOUNIT_CLOCK_GATE_DISABLE; + I915_WRITE(DSPCLK_GATE_D, val); + if (intel_dsi->dev.dev_ops->disable_panel_power) intel_dsi->dev.dev_ops->disable_panel_power(&intel_dsi->dev); } @@ -379,9 +443,6 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); - /* XXX: Location of the call */ - band_gap_reset(dev_priv); - /* escape clock divider, 20MHz, shared for A and C. device ready must be * off when doing this! txclkesc? */ tmp = I915_READ(MIPI_CTRL(0)); @@ -452,10 +513,17 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) /* dphy stuff */ /* in terms of low power clock */ - I915_WRITE(MIPI_INIT_COUNT(pipe), txclkesc(ESCAPE_CLOCK_DIVIDER_1, 100)); + I915_WRITE(MIPI_INIT_COUNT(pipe), txclkesc(intel_dsi->escape_clk_div, 100)); + + val = 0; + if (intel_dsi->eotp_pkt == 0) + val |= EOT_DISABLE; + + if (intel_dsi->clock_stop) + val |= CLOCKSTOP; /* recovery disables */ - I915_WRITE(MIPI_EOT_DISABLE(pipe), intel_dsi->eot_disable); + I915_WRITE(MIPI_EOT_DISABLE(pipe), val); /* in terms of txbyteclkhs. actual high to low switch + * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK. @@ -484,9 +552,14 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT); if (is_vid_mode(intel_dsi)) + /* Some panels might have resolution which is not a multiple of + * 64 like 1366 x 768. Enable RANDOM resolution support for such + * panels by default */ I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe), intel_dsi->video_frmt_cfg_bits | - intel_dsi->video_mode_format); + intel_dsi->video_mode_format | + IP_TG_CONFIG | + RANDOM_DPI_DISPLAY_RESOLUTION); } static enum drm_connector_status @@ -594,7 +667,7 @@ bool intel_dsi_init(struct drm_device *dev) intel_encoder->compute_config = intel_dsi_compute_config; intel_encoder->pre_pll_enable = intel_dsi_pre_pll_enable; intel_encoder->pre_enable = intel_dsi_pre_enable; - intel_encoder->enable = intel_dsi_enable; + intel_encoder->enable = intel_dsi_enable_nop; intel_encoder->mode_set = intel_dsi_mode_set; intel_encoder->disable = intel_dsi_disable; intel_encoder->post_disable = intel_dsi_post_disable; diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index b4a27cec882f76..550714c7860e8a 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -95,8 +95,10 @@ struct intel_dsi { u32 video_mode_format; /* eot for MIPI_EOT_DISABLE register */ - u32 eot_disable; + u8 eotp_pkt; + u8 clock_stop; + u8 escape_clk_div; u32 port_bits; u32 bw_timer; u32 dphy_reg; diff --git a/drivers/gpu/drm/i915/intel_dsi_cmd.c b/drivers/gpu/drm/i915/intel_dsi_cmd.c index 7c40f981d2c75d..3eeb21b9fddfac 100644 --- a/drivers/gpu/drm/i915/intel_dsi_cmd.c +++ b/drivers/gpu/drm/i915/intel_dsi_cmd.c @@ -389,7 +389,7 @@ int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel, * * XXX: commands with data in MIPI_DPI_DATA? */ -int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd) +int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs) { struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_device *dev = encoder->dev; @@ -399,7 +399,7 @@ int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd) u32 mask; /* XXX: pipe, hs */ - if (intel_dsi->hs) + if (hs) cmd &= ~DPI_LP_MODE; else cmd |= DPI_LP_MODE; diff --git a/drivers/gpu/drm/i915/intel_dsi_cmd.h b/drivers/gpu/drm/i915/intel_dsi_cmd.h index 54c8a234a2e0fc..9a18cbfa546010 100644 --- a/drivers/gpu/drm/i915/intel_dsi_cmd.h +++ b/drivers/gpu/drm/i915/intel_dsi_cmd.h @@ -33,6 +33,9 @@ #include "intel_drv.h" #include "intel_dsi.h" +#define DPI_LP_MODE_EN false +#define DPI_HS_MODE_EN true + void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable); int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel, @@ -47,7 +50,7 @@ int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd, int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel, u8 *reqdata, int reqlen, u8 *buf, int buflen); -int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd); +int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs); /* XXX: questionable write helpers */ static inline int dsi_vc_dcs_write_0(struct intel_dsi *intel_dsi, diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 7fe3feedfe039c..1604235d58e6f5 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -285,7 +285,7 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder, return true; } -static void intel_dvo_mode_set(struct intel_encoder *encoder) +static void intel_dvo_pre_enable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -475,7 +475,7 @@ void intel_dvo_init(struct drm_device *dev) intel_encoder->get_hw_state = intel_dvo_get_hw_state; intel_encoder->get_config = intel_dvo_get_config; intel_encoder->compute_config = intel_dvo_compute_config; - intel_encoder->mode_set = intel_dvo_mode_set; + intel_encoder->pre_enable = intel_dvo_pre_enable; intel_connector->get_hw_state = intel_dvo_connector_get_hw_state; intel_connector->unregister = intel_connector_unregister; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 157267aa356165..b606162cc17c75 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -557,10 +557,12 @@ static void vlv_set_infoframes(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); + u32 port = VIDEO_DIP_PORT(intel_dig_port->port); assert_hdmi_port_disabled(intel_hdmi); @@ -576,9 +578,19 @@ static void vlv_set_infoframes(struct drm_encoder *encoder, return; } + if (port != (val & VIDEO_DIP_PORT_MASK)) { + if (val & VIDEO_DIP_ENABLE) { + val &= ~VIDEO_DIP_ENABLE; + I915_WRITE(reg, val); + POSTING_READ(reg); + } + val &= ~VIDEO_DIP_PORT_MASK; + val |= port; + } + val |= VIDEO_DIP_ENABLE; - val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | - VIDEO_DIP_ENABLE_GCP); + val &= ~(VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_ENABLE_VENDOR | + VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP); I915_WRITE(reg, val); POSTING_READ(reg); @@ -638,8 +650,8 @@ static void intel_hdmi_mode_set(struct intel_encoder *encoder) else hdmi_val |= SDVO_COLOR_FORMAT_8bpc; - /* Required on CPT */ - if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) + if (intel_hdmi->has_hdmi_sink && + (HAS_PCH_CPT(dev) || IS_VALLEYVIEW(dev))) hdmi_val |= HDMI_MODE_SELECT_HDMI; if (intel_hdmi->has_audio) { @@ -657,8 +669,6 @@ static void intel_hdmi_mode_set(struct intel_encoder *encoder) I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val); POSTING_READ(intel_hdmi->hdmi_reg); - - intel_hdmi->set_infoframes(&encoder->base, adjusted_mode); } static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, @@ -1104,13 +1114,26 @@ intel_hdmi_set_property(struct drm_connector *connector, return 0; } +static void intel_hdmi_pre_enable(struct intel_encoder *encoder) +{ + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + + intel_hdmi->set_infoframes(&encoder->base, adjusted_mode); +} + static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) { struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); + struct intel_hdmi *intel_hdmi = &dport->hdmi; struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; u32 val; @@ -1144,6 +1167,8 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888); mutex_unlock(&dev_priv->dpio_lock); + intel_hdmi->set_infoframes(&encoder->base, adjusted_mode); + intel_enable_hdmi(encoder); vlv_wait_port_ready(dev_priv, dport); @@ -1339,6 +1364,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) intel_encoder->enable = vlv_enable_hdmi; intel_encoder->post_disable = vlv_hdmi_post_disable; } else { + intel_encoder->pre_enable = intel_hdmi_pre_enable; intel_encoder->enable = intel_enable_hdmi; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index f1ecf916474a93..1b1541dfb4400a 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -111,13 +111,6 @@ static void intel_lvds_get_config(struct intel_encoder *encoder, pipe_config->adjusted_mode.flags |= flags; - /* gen2/3 store dither state in pfit control, needs to match */ - if (INTEL_INFO(dev)->gen < 4) { - tmp = I915_READ(PFIT_CONTROL); - - pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE; - } - dotclock = pipe_config->port_clock; if (HAS_PCH_SPLIT(dev_priv->dev)) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 0eead16aeda740..44ad415e37067b 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -308,16 +308,16 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | PFIT_FILTER_FUZZY); + /* Make sure pre-965 set dither correctly for 18bpp panels. */ + if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + out: if ((pfit_control & PFIT_ENABLE) == 0) { pfit_control = 0; pfit_pgm_ratios = 0; } - /* Make sure pre-965 set dither correctly for 18bpp panels. */ - if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) - pfit_control |= PANEL_8TO6_DITHER_ENABLE; - pipe_config->gmch_pfit.control = pfit_control; pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; pipe_config->gmch_pfit.lvds_border_bits = border; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 19e94c3edc1957..834c49c2beb77e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1831,6 +1831,40 @@ static unsigned int ilk_display_fifo_size(const struct drm_device *dev) return 512; } +static unsigned int ilk_plane_wm_reg_max(const struct drm_device *dev, + int level, bool is_sprite) +{ + if (INTEL_INFO(dev)->gen >= 8) + /* BDW primary/sprite plane watermarks */ + return level == 0 ? 255 : 2047; + else if (INTEL_INFO(dev)->gen >= 7) + /* IVB/HSW primary/sprite plane watermarks */ + return level == 0 ? 127 : 1023; + else if (!is_sprite) + /* ILK/SNB primary plane watermarks */ + return level == 0 ? 127 : 511; + else + /* ILK/SNB sprite plane watermarks */ + return level == 0 ? 63 : 255; +} + +static unsigned int ilk_cursor_wm_reg_max(const struct drm_device *dev, + int level) +{ + if (INTEL_INFO(dev)->gen >= 7) + return level == 0 ? 63 : 255; + else + return level == 0 ? 31 : 63; +} + +static unsigned int ilk_fbc_wm_reg_max(const struct drm_device *dev) +{ + if (INTEL_INFO(dev)->gen >= 8) + return 31; + else + return 15; +} + /* Calculate the maximum primary/sprite plane watermark */ static unsigned int ilk_plane_wm_max(const struct drm_device *dev, int level, @@ -1839,7 +1873,6 @@ static unsigned int ilk_plane_wm_max(const struct drm_device *dev, bool is_sprite) { unsigned int fifo_size = ilk_display_fifo_size(dev); - unsigned int max; /* if sprites aren't enabled, sprites get nothing */ if (is_sprite && !config->sprites_enabled) @@ -1870,19 +1903,7 @@ static unsigned int ilk_plane_wm_max(const struct drm_device *dev, } /* clamp to max that the registers can hold */ - if (INTEL_INFO(dev)->gen >= 8) - max = level == 0 ? 255 : 2047; - else if (INTEL_INFO(dev)->gen >= 7) - /* IVB/HSW primary/sprite plane watermarks */ - max = level == 0 ? 127 : 1023; - else if (!is_sprite) - /* ILK/SNB primary plane watermarks */ - max = level == 0 ? 127 : 511; - else - /* ILK/SNB sprite plane watermarks */ - max = level == 0 ? 63 : 255; - - return min(fifo_size, max); + return min(fifo_size, ilk_plane_wm_reg_max(dev, level, is_sprite)); } /* Calculate the maximum cursor plane watermark */ @@ -1895,20 +1916,7 @@ static unsigned int ilk_cursor_wm_max(const struct drm_device *dev, return 64; /* otherwise just report max that registers can hold */ - if (INTEL_INFO(dev)->gen >= 7) - return level == 0 ? 63 : 255; - else - return level == 0 ? 31 : 63; -} - -/* Calculate the maximum FBC watermark */ -static unsigned int ilk_fbc_wm_max(const struct drm_device *dev) -{ - /* max that registers can hold */ - if (INTEL_INFO(dev)->gen >= 8) - return 31; - else - return 15; + return ilk_cursor_wm_reg_max(dev, level); } static void ilk_compute_wm_maximums(const struct drm_device *dev, @@ -1920,7 +1928,17 @@ static void ilk_compute_wm_maximums(const struct drm_device *dev, max->pri = ilk_plane_wm_max(dev, level, config, ddb_partitioning, false); max->spr = ilk_plane_wm_max(dev, level, config, ddb_partitioning, true); max->cur = ilk_cursor_wm_max(dev, level, config); - max->fbc = ilk_fbc_wm_max(dev); + max->fbc = ilk_fbc_wm_reg_max(dev); +} + +static void ilk_compute_wm_reg_maximums(struct drm_device *dev, + int level, + struct ilk_wm_maximums *max) +{ + max->pri = ilk_plane_wm_reg_max(dev, level, false); + max->spr = ilk_plane_wm_reg_max(dev, level, true); + max->cur = ilk_cursor_wm_reg_max(dev, level); + max->fbc = ilk_fbc_wm_reg_max(dev); } static bool ilk_validate_wm_level(int level, @@ -2115,38 +2133,52 @@ static void ilk_setup_wm_latency(struct drm_device *dev) } static void ilk_compute_wm_parameters(struct drm_crtc *crtc, - struct ilk_pipe_wm_parameters *p, - struct intel_wm_config *config) + struct ilk_pipe_wm_parameters *p) { struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum pipe pipe = intel_crtc->pipe; struct drm_plane *plane; - p->active = intel_crtc_active(crtc); - if (p->active) { - p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal; - p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc); - p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8; - p->cur.bytes_per_pixel = 4; - p->pri.horiz_pixels = intel_crtc->config.pipe_src_w; - p->cur.horiz_pixels = intel_crtc->cursor_width; - /* TODO: for now, assume primary and cursor planes are always enabled. */ - p->pri.enabled = true; - p->cur.enabled = true; - } + if (!intel_crtc_active(crtc)) + return; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - config->num_pipes_active += intel_crtc_active(crtc); + p->active = true; + p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal; + p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc); + p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8; + p->cur.bytes_per_pixel = 4; + p->pri.horiz_pixels = intel_crtc->config.pipe_src_w; + p->cur.horiz_pixels = intel_crtc->cursor_width; + /* TODO: for now, assume primary and cursor planes are always enabled. */ + p->pri.enabled = true; + p->cur.enabled = true; drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { struct intel_plane *intel_plane = to_intel_plane(plane); - if (intel_plane->pipe == pipe) + if (intel_plane->pipe == pipe) { p->spr = intel_plane->wm; + break; + } + } +} + +static void ilk_compute_wm_config(struct drm_device *dev, + struct intel_wm_config *config) +{ + struct intel_crtc *intel_crtc; + + /* Compute the currently _active_ config */ + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { + const struct intel_pipe_wm *wm = &intel_crtc->wm.active; - config->sprites_enabled |= intel_plane->wm.enabled; - config->sprites_scaled |= intel_plane->wm.scaled; + if (!wm->pipe_enabled) + continue; + + config->sprites_enabled |= wm->sprites_enabled; + config->sprites_scaled |= wm->sprites_scaled; + config->num_pipes_active++; } } @@ -2166,8 +2198,9 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, }; struct ilk_wm_maximums max; - /* LP0 watermarks always use 1/2 DDB partitioning */ - ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max); + pipe_wm->pipe_enabled = params->active; + pipe_wm->sprites_enabled = params->spr.enabled; + pipe_wm->sprites_scaled = params->spr.scaled; /* ILK/SNB: LP2+ watermarks only w/o sprites */ if (INTEL_INFO(dev)->gen <= 6 && params->spr.enabled) @@ -2177,15 +2210,37 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, if (params->spr.scaled) max_level = 0; - for (level = 0; level <= max_level; level++) - ilk_compute_wm_level(dev_priv, level, params, - &pipe_wm->wm[level]); + ilk_compute_wm_level(dev_priv, 0, params, &pipe_wm->wm[0]); if (IS_HASWELL(dev) || IS_BROADWELL(dev)) pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc); + /* LP0 watermarks always use 1/2 DDB partitioning */ + ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max); + /* At least LP0 must be valid */ - return ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]); + if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0])) + return false; + + ilk_compute_wm_reg_maximums(dev, 1, &max); + + for (level = 1; level <= max_level; level++) { + struct intel_wm_level wm = {}; + + ilk_compute_wm_level(dev_priv, level, params, &wm); + + /* + * Disable any watermark level that exceeds the + * register maximums since such watermarks are + * always invalid. + */ + if (!ilk_validate_wm_level(level, &max, &wm)) + break; + + pipe_wm->wm[level] = wm; + } + + return true; } /* @@ -2197,20 +2252,28 @@ static void ilk_merge_wm_level(struct drm_device *dev, { const struct intel_crtc *intel_crtc; + ret_wm->enable = true; + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { - const struct intel_wm_level *wm = - &intel_crtc->wm.active.wm[level]; + const struct intel_pipe_wm *active = &intel_crtc->wm.active; + const struct intel_wm_level *wm = &active->wm[level]; + + if (!active->pipe_enabled) + continue; + /* + * The watermark values may have been used in the past, + * so we must maintain them in the registers for some + * time even if the level is now disabled. + */ if (!wm->enable) - return; + ret_wm->enable = false; ret_wm->pri_val = max(ret_wm->pri_val, wm->pri_val); ret_wm->spr_val = max(ret_wm->spr_val, wm->spr_val); ret_wm->cur_val = max(ret_wm->cur_val, wm->cur_val); ret_wm->fbc_val = max(ret_wm->fbc_val, wm->fbc_val); } - - ret_wm->enable = true; } /* @@ -2222,6 +2285,7 @@ static void ilk_wm_merge(struct drm_device *dev, struct intel_pipe_wm *merged) { int level, max_level = ilk_wm_max_level(dev); + int last_enabled_level = max_level; /* ILK/SNB/IVB: LP1+ watermarks only w/ single pipe */ if ((INTEL_INFO(dev)->gen <= 6 || IS_IVYBRIDGE(dev)) && @@ -2237,15 +2301,19 @@ static void ilk_wm_merge(struct drm_device *dev, ilk_merge_wm_level(dev, level, wm); - if (!ilk_validate_wm_level(level, max, wm)) - break; + if (level > last_enabled_level) + wm->enable = false; + else if (!ilk_validate_wm_level(level, max, wm)) + /* make sure all following levels get disabled */ + last_enabled_level = level - 1; /* * The spec says it is preferred to disable * FBC WMs instead of disabling a WM level. */ if (wm->fbc_val > max->fbc) { - merged->fbc_wm_enabled = false; + if (wm->enable) + merged->fbc_wm_enabled = false; wm->fbc_val = 0; } } @@ -2300,14 +2368,19 @@ static void ilk_compute_wm_results(struct drm_device *dev, level = ilk_wm_lp_to_level(wm_lp, merged); r = &merged->wm[level]; - if (!r->enable) - break; - results->wm_lp[wm_lp - 1] = WM3_LP_EN | + /* + * Maintain the watermark values even if the level is + * disabled. Doing otherwise could cause underruns. + */ + results->wm_lp[wm_lp - 1] = (ilk_wm_lp_latency(dev, level) << WM1_LP_LATENCY_SHIFT) | (r->pri_val << WM1_LP_SR_SHIFT) | r->cur_val; + if (r->enable) + results->wm_lp[wm_lp - 1] |= WM1_LP_SR_EN; + if (INTEL_INFO(dev)->gen >= 8) results->wm_lp[wm_lp - 1] |= r->fbc_val << WM1_LP_FBC_SHIFT_BDW; @@ -2315,6 +2388,10 @@ static void ilk_compute_wm_results(struct drm_device *dev, results->wm_lp[wm_lp - 1] |= r->fbc_val << WM1_LP_FBC_SHIFT; + /* + * Always set WM1S_LP_EN when spr_val != 0, even if the + * level is disabled. Doing otherwise could cause underruns. + */ if (INTEL_INFO(dev)->gen <= 6 && r->spr_val) { WARN_ON(wm_lp != 1); results->wm_lp_spr[wm_lp - 1] = WM1S_LP_EN | r->spr_val; @@ -2558,7 +2635,7 @@ static void ilk_update_wm(struct drm_crtc *crtc) struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; struct intel_wm_config config = {}; - ilk_compute_wm_parameters(crtc, ¶ms, &config); + ilk_compute_wm_parameters(crtc, ¶ms); intel_compute_pipe_wm(crtc, ¶ms, &pipe_wm); @@ -2567,6 +2644,8 @@ static void ilk_update_wm(struct drm_crtc *crtc) intel_crtc->wm.active = pipe_wm; + ilk_compute_wm_config(dev, &config); + ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max); ilk_wm_merge(dev, &config, &max, &lp_wm_1_2); @@ -2633,7 +2712,9 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) if (IS_HASWELL(dev) || IS_BROADWELL(dev)) hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe)); - if (intel_crtc_active(crtc)) { + active->pipe_enabled = intel_crtc_active(crtc); + + if (active->pipe_enabled) { u32 tmp = hw->wm_pipe[pipe]; /* @@ -2674,8 +2755,10 @@ void ilk_wm_get_hw_state(struct drm_device *dev) hw->wm_lp[2] = I915_READ(WM3_LP_ILK); hw->wm_lp_spr[0] = I915_READ(WM1S_LP_ILK); - hw->wm_lp_spr[1] = I915_READ(WM2S_LP_IVB); - hw->wm_lp_spr[2] = I915_READ(WM3S_LP_IVB); + if (INTEL_INFO(dev)->gen >= 7) { + hw->wm_lp_spr[1] = I915_READ(WM2S_LP_IVB); + hw->wm_lp_spr[2] = I915_READ(WM3S_LP_IVB); + } if (IS_HASWELL(dev) || IS_BROADWELL(dev)) hw->partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ? @@ -3051,7 +3134,7 @@ void gen6_set_rps(struct drm_device *dev, u8 val) if (val != dev_priv->rps.cur_freq) { gen6_set_rps_thresholds(dev_priv, val); - if (IS_HASWELL(dev)) + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) I915_WRITE(GEN6_RPNSWREQ, HSW_FREQUENCY(val)); else @@ -3094,16 +3177,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv) /* Mask turbo interrupt so that they will not come in between */ I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); - /* Bring up the Gfx clock */ - I915_WRITE(VLV_GTLC_SURVIVABILITY_REG, - I915_READ(VLV_GTLC_SURVIVABILITY_REG) | - VLV_GFX_CLK_FORCE_ON_BIT); - - if (wait_for(((VLV_GFX_CLK_STATUS_BIT & - I915_READ(VLV_GTLC_SURVIVABILITY_REG)) != 0), 5)) { - DRM_ERROR("GFX_CLK_ON request timed out\n"); - return; - } + vlv_force_gfx_clock(dev_priv, true); dev_priv->rps.cur_freq = dev_priv->rps.min_freq_softlimit; @@ -3114,10 +3188,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv) & GENFREQSTATUS) == 0, 5)) DRM_ERROR("timed out waiting for Punit\n"); - /* Release the Gfx clock */ - I915_WRITE(VLV_GTLC_SURVIVABILITY_REG, - I915_READ(VLV_GTLC_SURVIVABILITY_REG) & - ~VLV_GFX_CLK_FORCE_ON_BIT); + vlv_force_gfx_clock(dev_priv, false); I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq)); @@ -3215,21 +3286,48 @@ static void valleyview_disable_rps(struct drm_device *dev) static void intel_print_rc6_info(struct drm_device *dev, u32 mode) { + if (IS_VALLEYVIEW(dev)) { + if (mode & (GEN7_RC_CTL_TO_MODE | GEN6_RC_CTL_EI_MODE(1))) + mode = GEN6_RC_CTL_RC6_ENABLE; + else + mode = 0; + } DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n", (mode & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off", (mode & GEN6_RC_CTL_RC6p_ENABLE) ? "on" : "off", (mode & GEN6_RC_CTL_RC6pp_ENABLE) ? "on" : "off"); } -int intel_enable_rc6(const struct drm_device *dev) +static int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6) { /* No RC6 before Ironlake */ if (INTEL_INFO(dev)->gen < 5) return 0; + /* RC6 is only on Ironlake mobile not on desktop */ + if (INTEL_INFO(dev)->gen == 5 && !IS_IRONLAKE_M(dev)) + return 0; + + /* Disable RC6 on Broadwell for now */ + if (IS_BROADWELL(dev)) + return 0; + /* Respect the kernel parameter if it is set */ - if (i915.enable_rc6 >= 0) - return i915.enable_rc6; + if (enable_rc6 >= 0) { + int mask; + + if (INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev)) + mask = INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE | + INTEL_RC6pp_ENABLE; + else + mask = INTEL_RC6_ENABLE; + + if ((enable_rc6 & mask) != enable_rc6) + DRM_INFO("Adjusting RC6 mask to %d (requested %d, valid %d)\n", + enable_rc6, enable_rc6 & mask, mask); + + return enable_rc6 & mask; + } /* Disable RC6 on Ironlake */ if (INTEL_INFO(dev)->gen == 5) @@ -3241,6 +3339,11 @@ int intel_enable_rc6(const struct drm_device *dev) return INTEL_RC6_ENABLE; } +int intel_enable_rc6(const struct drm_device *dev) +{ + return i915.enable_rc6; +} + static void gen6_enable_rps_interrupts(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3252,6 +3355,27 @@ static void gen6_enable_rps_interrupts(struct drm_device *dev) spin_unlock_irq(&dev_priv->irq_lock); } +static void parse_rp_state_cap(struct drm_i915_private *dev_priv, u32 rp_state_cap) +{ + /* All of these values are in units of 50MHz */ + dev_priv->rps.cur_freq = 0; + /* static values from HW: RP0 < RPe < RP1 < RPn (min_freq) */ + dev_priv->rps.rp1_freq = (rp_state_cap >> 8) & 0xff; + dev_priv->rps.rp0_freq = (rp_state_cap >> 0) & 0xff; + dev_priv->rps.min_freq = (rp_state_cap >> 16) & 0xff; + /* XXX: only BYT has a special efficient freq */ + dev_priv->rps.efficient_freq = dev_priv->rps.rp1_freq; + /* hw_max = RP0 until we check for overclocking */ + dev_priv->rps.max_freq = dev_priv->rps.rp0_freq; + + /* Preserve min/max settings in case of re-init */ + if (dev_priv->rps.max_freq_softlimit == 0) + dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq; + + if (dev_priv->rps.min_freq_softlimit == 0) + dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq; +} + static void gen8_enable_rps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3270,6 +3394,7 @@ static void gen8_enable_rps(struct drm_device *dev) I915_WRITE(GEN6_RC_CONTROL, 0); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + parse_rp_state_cap(dev_priv, rp_state_cap); /* 2b: Program RC6 thresholds.*/ I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16); @@ -3289,8 +3414,10 @@ static void gen8_enable_rps(struct drm_device *dev) rc6_mask); /* 4 Program defaults and thresholds for RPS*/ - I915_WRITE(GEN6_RPNSWREQ, HSW_FREQUENCY(10)); /* Request 500 MHz */ - I915_WRITE(GEN6_RC_VIDEO_FREQ, HSW_FREQUENCY(12)); /* Request 600 MHz */ + I915_WRITE(GEN6_RPNSWREQ, + HSW_FREQUENCY(dev_priv->rps.rp1_freq)); + I915_WRITE(GEN6_RC_VIDEO_FREQ, + HSW_FREQUENCY(dev_priv->rps.rp1_freq)); /* NB: Docs say 1s, and 1000000 - which aren't equivalent */ I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 100000000 / 128); /* 1 second timeout */ @@ -3356,23 +3483,7 @@ static void gen6_enable_rps(struct drm_device *dev) rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); - /* All of these values are in units of 50MHz */ - dev_priv->rps.cur_freq = 0; - /* static values from HW: RP0 < RPe < RP1 < RPn (min_freq) */ - dev_priv->rps.rp1_freq = (rp_state_cap >> 8) & 0xff; - dev_priv->rps.rp0_freq = (rp_state_cap >> 0) & 0xff; - dev_priv->rps.min_freq = (rp_state_cap >> 16) & 0xff; - /* XXX: only BYT has a special efficient freq */ - dev_priv->rps.efficient_freq = dev_priv->rps.rp1_freq; - /* hw_max = RP0 until we check for overclocking */ - dev_priv->rps.max_freq = dev_priv->rps.rp0_freq; - - /* Preserve min/max settings in case of re-init */ - if (dev_priv->rps.max_freq_softlimit == 0) - dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq; - - if (dev_priv->rps.min_freq_softlimit == 0) - dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq; + parse_rp_state_cap(dev_priv, rp_state_cap); /* disable the counters and set deterministic thresholds */ I915_WRITE(GEN6_RC_CONTROL, 0); @@ -3454,7 +3565,7 @@ static void gen6_enable_rps(struct drm_device *dev) gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); } -void gen6_update_ring_freq(struct drm_device *dev) +static void __gen6_update_ring_freq(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int min_freq = 15; @@ -3524,6 +3635,18 @@ void gen6_update_ring_freq(struct drm_device *dev) } } +void gen6_update_ring_freq(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (INTEL_INFO(dev)->gen < 6 || IS_VALLEYVIEW(dev)) + return; + + mutex_lock(&dev_priv->rps.hw_lock); + __gen6_update_ring_freq(dev); + mutex_unlock(&dev_priv->rps.hw_lock); +} + int valleyview_rps_max_freq(struct drm_i915_private *dev_priv) { u32 val, rp0; @@ -3618,6 +3741,45 @@ static void valleyview_cleanup_pctx(struct drm_device *dev) dev_priv->vlv_pctx = NULL; } +static void valleyview_init_gt_powersave(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + valleyview_setup_pctx(dev); + + mutex_lock(&dev_priv->rps.hw_lock); + + dev_priv->rps.max_freq = valleyview_rps_max_freq(dev_priv); + dev_priv->rps.rp0_freq = dev_priv->rps.max_freq; + DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n", + vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq), + dev_priv->rps.max_freq); + + dev_priv->rps.efficient_freq = valleyview_rps_rpe_freq(dev_priv); + DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n", + vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq), + dev_priv->rps.efficient_freq); + + dev_priv->rps.min_freq = valleyview_rps_min_freq(dev_priv); + DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n", + vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq), + dev_priv->rps.min_freq); + + /* Preserve min/max settings in case of re-init */ + if (dev_priv->rps.max_freq_softlimit == 0) + dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq; + + if (dev_priv->rps.min_freq_softlimit == 0) + dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq; + + mutex_unlock(&dev_priv->rps.hw_lock); +} + +static void valleyview_cleanup_gt_powersave(struct drm_device *dev) +{ + valleyview_cleanup_pctx(dev); +} + static void valleyview_enable_rps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3684,29 +3846,6 @@ static void valleyview_enable_rps(struct drm_device *dev) vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq), dev_priv->rps.cur_freq); - dev_priv->rps.max_freq = valleyview_rps_max_freq(dev_priv); - dev_priv->rps.rp0_freq = dev_priv->rps.max_freq; - DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq), - dev_priv->rps.max_freq); - - dev_priv->rps.efficient_freq = valleyview_rps_rpe_freq(dev_priv); - DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq), - dev_priv->rps.efficient_freq); - - dev_priv->rps.min_freq = valleyview_rps_min_freq(dev_priv); - DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq), - dev_priv->rps.min_freq); - - /* Preserve min/max settings in case of re-init */ - if (dev_priv->rps.max_freq_softlimit == 0) - dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq; - - if (dev_priv->rps.min_freq_softlimit == 0) - dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq; - DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n", vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq), dev_priv->rps.efficient_freq); @@ -3833,7 +3972,7 @@ static void ironlake_enable_rc6(struct drm_device *dev) I915_WRITE(PWRCTXA, i915_gem_obj_ggtt_offset(dev_priv->ips.pwrctx) | PWRCTX_EN); I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); - intel_print_rc6_info(dev, INTEL_RC6_ENABLE); + intel_print_rc6_info(dev, GEN6_RC_CTL_RC6_ENABLE); } static unsigned long intel_pxfreq(u32 vidfreq) @@ -4447,14 +4586,16 @@ static void intel_init_emon(struct drm_device *dev) void intel_init_gt_powersave(struct drm_device *dev) { + i915.enable_rc6 = sanitize_rc6_option(dev, i915.enable_rc6); + if (IS_VALLEYVIEW(dev)) - valleyview_setup_pctx(dev); + valleyview_init_gt_powersave(dev); } void intel_cleanup_gt_powersave(struct drm_device *dev) { if (IS_VALLEYVIEW(dev)) - valleyview_cleanup_pctx(dev); + valleyview_cleanup_gt_powersave(dev); } void intel_disable_gt_powersave(struct drm_device *dev) @@ -4467,7 +4608,7 @@ void intel_disable_gt_powersave(struct drm_device *dev) if (IS_IRONLAKE_M(dev)) { ironlake_disable_drps(dev); ironlake_disable_rc6(dev); - } else if (INTEL_INFO(dev)->gen >= 6) { + } else if (IS_GEN6(dev) || IS_GEN7(dev)) { cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work); cancel_work_sync(&dev_priv->rps.work); mutex_lock(&dev_priv->rps.hw_lock); @@ -4493,13 +4634,15 @@ static void intel_gen6_powersave_work(struct work_struct *work) valleyview_enable_rps(dev); } else if (IS_BROADWELL(dev)) { gen8_enable_rps(dev); - gen6_update_ring_freq(dev); + __gen6_update_ring_freq(dev); } else { gen6_enable_rps(dev); - gen6_update_ring_freq(dev); + __gen6_update_ring_freq(dev); } dev_priv->rps.enabled = true; mutex_unlock(&dev_priv->rps.hw_lock); + + intel_runtime_pm_put(dev_priv); } void intel_enable_gt_powersave(struct drm_device *dev) @@ -4507,20 +4650,38 @@ void intel_enable_gt_powersave(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; if (IS_IRONLAKE_M(dev)) { + mutex_lock(&dev->struct_mutex); ironlake_enable_drps(dev); ironlake_enable_rc6(dev); intel_init_emon(dev); + mutex_unlock(&dev->struct_mutex); } else if (IS_GEN6(dev) || IS_GEN7(dev)) { /* * PCU communication is slow and this doesn't need to be * done at any specific time, so do this out of our fast path * to make resume and init faster. + * + * We depend on the HW RC6 power context save/restore + * mechanism when entering D3 through runtime PM suspend. So + * disable RPM until RPS/RC6 is properly setup. We can only + * get here via the driver load/system resume/runtime resume + * paths, so the _noresume version is enough (and in case of + * runtime resume it's necessary). */ - schedule_delayed_work(&dev_priv->rps.delayed_resume_work, - round_jiffies_up_relative(HZ)); + if (schedule_delayed_work(&dev_priv->rps.delayed_resume_work, + round_jiffies_up_relative(HZ))) + intel_runtime_pm_get_noresume(dev_priv); } } +void intel_reset_gt_powersave(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->rps.enabled = false; + intel_enable_gt_powersave(dev); +} + static void ibx_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -4626,6 +4787,9 @@ static void ironlake_init_clock_gating(struct drm_device *dev) I915_WRITE(CACHE_MODE_0, _MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE)); + /* WaDisable_RenderCache_OperationalFlush:ilk */ + I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE)); + g4x_disable_trickle_feed(dev); ibx_init_clock_gating(dev); @@ -4701,6 +4865,9 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_GT_MODE, _MASKED_BIT_ENABLE(GEN6_TD_FOUR_ROW_DISPATCH_DISABLE)); + /* WaDisable_RenderCache_OperationalFlush:snb */ + I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE)); + /* * BSpec recoomends 8x4 when MSAA is used, * however in practice 16x4 seems fastest. @@ -4869,6 +5036,10 @@ static void gen8_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, _MASKED_BIT_ENABLE(GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE)); + /* WaDisableDopClockGating:bdw May not be needed for production */ + I915_WRITE(GEN7_ROW_CHICKEN2, + _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); + /* WaSwitchSolVfFArbitrationPriority:bdw */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); @@ -4940,6 +5111,9 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_FF_THREAD_MODE, I915_READ(GEN7_FF_THREAD_MODE) & ~GEN7_FF_VS_REF_CNT_FFME); + /* WaDisable_RenderCache_OperationalFlush:hsw */ + I915_WRITE(CACHE_MODE_0_GEN7, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE)); + /* enable HiZ Raw Stall Optimization */ I915_WRITE(CACHE_MODE_0_GEN7, _MASKED_BIT_DISABLE(HIZ_RAW_STALL_OPT_DISABLE)); @@ -4992,6 +5166,9 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); + /* WaDisable_RenderCache_OperationalFlush:ivb */ + I915_WRITE(CACHE_MODE_0_GEN7, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE)); + /* Apply the WaDisableRHWOOptimizationForRenderHang:ivb workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); @@ -5086,6 +5263,10 @@ static void valleyview_init_clock_gating(struct drm_device *dev) } DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq); + dev_priv->vlv_cdclk_freq = valleyview_cur_cdclk(dev_priv); + DRM_DEBUG_DRIVER("Current CD clock rate: %d MHz", + dev_priv->vlv_cdclk_freq); + I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE); /* WaDisableEarlyCull:vlv */ @@ -5103,6 +5284,9 @@ static void valleyview_init_clock_gating(struct drm_device *dev) _MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP | GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); + /* WaDisable_RenderCache_OperationalFlush:vlv */ + I915_WRITE(CACHE_MODE_0_GEN7, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE)); + /* WaForceL3Serialization:vlv */ I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & ~L3SQ_URB_READ_CAM_MATCH_DISABLE); @@ -5172,6 +5356,9 @@ static void g4x_init_clock_gating(struct drm_device *dev) I915_WRITE(CACHE_MODE_0, _MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE)); + /* WaDisable_RenderCache_OperationalFlush:g4x */ + I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE)); + g4x_disable_trickle_feed(dev); } @@ -5186,6 +5373,9 @@ static void crestline_init_clock_gating(struct drm_device *dev) I915_WRITE16(DEUC, 0); I915_WRITE(MI_ARB_STATE, _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE)); + + /* WaDisable_RenderCache_OperationalFlush:gen4 */ + I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE)); } static void broadwater_init_clock_gating(struct drm_device *dev) @@ -5200,6 +5390,9 @@ static void broadwater_init_clock_gating(struct drm_device *dev) I915_WRITE(RENCLK_GATE_D2, 0); I915_WRITE(MI_ARB_STATE, _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE)); + + /* WaDisable_RenderCache_OperationalFlush:gen4 */ + I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE)); } static void gen3_init_clock_gating(struct drm_device *dev) @@ -5551,11 +5744,13 @@ static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv, spin_unlock_irq(&dev_priv->irq_lock); /* - * During driver initialization we need to defer enabling hotplug - * processing until fbdev is set up. + * During driver initialization/resume we can avoid restoring the + * part of the HW/SW state that will be inited anyway explicitly. */ - if (dev_priv->enable_hotplug_processing) - intel_hpd_init(dev_priv->dev); + if (dev_priv->power_domains.initializing) + return; + + intel_hpd_init(dev_priv->dev); i915_redisable_vga_power_on(dev_priv->dev); } @@ -5919,9 +6114,13 @@ static void intel_power_domains_resume(struct drm_i915_private *dev_priv) void intel_power_domains_init_hw(struct drm_i915_private *dev_priv) { + struct i915_power_domains *power_domains = &dev_priv->power_domains; + + power_domains->initializing = true; /* For now, we need the power well to be always enabled. */ intel_display_set_init_power(dev_priv, true); intel_power_domains_resume(dev_priv); + power_domains->initializing = false; } void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv) @@ -5946,6 +6145,18 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv) WARN(dev_priv->pm.suspended, "Device still suspended.\n"); } +void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + if (!HAS_RUNTIME_PM(dev)) + return; + + WARN(dev_priv->pm.suspended, "Getting nosync-ref while suspended.\n"); + pm_runtime_get_noresume(device); +} + void intel_runtime_pm_put(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; @@ -5968,6 +6179,15 @@ void intel_init_runtime_pm(struct drm_i915_private *dev_priv) pm_runtime_set_active(device); + /* + * RPM depends on RC6 to save restore the GT HW context, so make RC6 a + * requirement. + */ + if (!intel_enable_rc6(dev)) { + DRM_INFO("RC6 disabled, disabling runtime PM support\n"); + return; + } + pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */ pm_runtime_mark_last_busy(device); pm_runtime_use_autosuspend(device); @@ -5983,6 +6203,9 @@ void intel_fini_runtime_pm(struct drm_i915_private *dev_priv) if (!HAS_RUNTIME_PM(dev)) return; + if (!intel_enable_rc6(dev)) + return; + /* Make sure we're not suspended first. */ pm_runtime_get_sync(device); pm_runtime_disable(device); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 79fb4cc2137c19..9907d66becddf4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -33,20 +33,36 @@ #include "i915_trace.h" #include "intel_drv.h" -static inline int ring_space(struct intel_ring_buffer *ring) +/* Early gen2 devices have a cacheline of just 32 bytes, using 64 is overkill, + * but keeps the logic simple. Indeed, the whole purpose of this macro is just + * to give some inclination as to some of the magic values used in the various + * workarounds! + */ +#define CACHELINE_BYTES 64 + +static inline int __ring_space(int head, int tail, int size) { - int space = (ring->head & HEAD_ADDR) - (ring->tail + I915_RING_FREE_SPACE); + int space = head - (tail + I915_RING_FREE_SPACE); if (space < 0) - space += ring->size; + space += size; return space; } -void __intel_ring_advance(struct intel_ring_buffer *ring) +static inline int ring_space(struct intel_ring_buffer *ring) +{ + return __ring_space(ring->head & HEAD_ADDR, ring->tail, ring->size); +} + +static bool intel_ring_stopped(struct intel_ring_buffer *ring) { struct drm_i915_private *dev_priv = ring->dev->dev_private; + return dev_priv->gpu_error.stop_rings & intel_ring_flag(ring); +} +void __intel_ring_advance(struct intel_ring_buffer *ring) +{ ring->tail &= ring->size - 1; - if (dev_priv->gpu_error.stop_rings & intel_ring_flag(ring)) + if (intel_ring_stopped(ring)) return; ring->write_tail(ring, ring->tail); } @@ -175,7 +191,7 @@ gen4_render_ring_flush(struct intel_ring_buffer *ring, static int intel_emit_post_sync_nonzero_flush(struct intel_ring_buffer *ring) { - u32 scratch_addr = ring->scratch.gtt_offset + 128; + u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; @@ -212,7 +228,7 @@ gen6_render_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { u32 flags = 0; - u32 scratch_addr = ring->scratch.gtt_offset + 128; + u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; /* Force SNB workarounds for PIPE_CONTROL flushes */ @@ -306,7 +322,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { u32 flags = 0; - u32 scratch_addr = ring->scratch.gtt_offset + 128; + u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; /* @@ -367,7 +383,7 @@ gen8_render_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { u32 flags = 0; - u32 scratch_addr = ring->scratch.gtt_offset + 128; + u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; flags |= PIPE_CONTROL_CS_STALL; @@ -512,12 +528,11 @@ static int init_ring_common(struct intel_ring_buffer *ring) I915_READ_START(ring) == i915_gem_obj_ggtt_offset(obj) && (I915_READ_HEAD(ring) & HEAD_ADDR) == 0, 50)) { DRM_ERROR("%s initialization failed " - "ctl %08x head %08x tail %08x start %08x\n", - ring->name, - I915_READ_CTL(ring), - I915_READ_HEAD(ring), - I915_READ_TAIL(ring), - I915_READ_START(ring)); + "ctl %08x (valid? %d) head %08x tail %08x start %08x [expected %08lx]\n", + ring->name, + I915_READ_CTL(ring), I915_READ_CTL(ring) & RING_VALID, + I915_READ_HEAD(ring), I915_READ_TAIL(ring), + I915_READ_START(ring), (unsigned long)i915_gem_obj_ggtt_offset(obj)); ret = -EIO; goto out; } @@ -601,13 +616,15 @@ static int init_render_ring(struct intel_ring_buffer *ring) I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE)); /* Required for the hardware to program scanline values for waiting */ + /* WaEnableFlushTlbInvalidationMode:snb */ if (INTEL_INFO(dev)->gen == 6) I915_WRITE(GFX_MODE, - _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_ALWAYS)); + _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT)); + /* WaBCSVCSTlbInvalidationMode:ivb,vlv,hsw */ if (IS_GEN7(dev)) I915_WRITE(GFX_MODE_GEN7, - _MASKED_BIT_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) | + _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT) | _MASKED_BIT_ENABLE(GFX_REPLAY_MODE)); if (INTEL_INFO(dev)->gen >= 5) { @@ -624,13 +641,6 @@ static int init_render_ring(struct intel_ring_buffer *ring) */ I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB)); - - /* This is not explicitly set for GEN6, so read the register. - * see intel_ring_mi_set_context() for why we care. - * TODO: consider explicitly setting the bit for GEN5 - */ - ring->itlb_before_ctx_switch = - !!(I915_READ(GFX_MODE) & GFX_TLB_INVALIDATE_ALWAYS); } if (INTEL_INFO(dev)->gen >= 6) @@ -658,20 +668,44 @@ static void render_ring_cleanup(struct intel_ring_buffer *ring) ring->scratch.obj = NULL; } -static void -update_mboxes(struct intel_ring_buffer *ring, - u32 mmio_offset) +static int gen6_signal(struct intel_ring_buffer *signaller, + unsigned int num_dwords) { -/* NB: In order to be able to do semaphore MBOX updates for varying number - * of rings, it's easiest if we round up each individual update to a - * multiple of 2 (since ring updates must always be a multiple of 2) - * even though the actual update only requires 3 dwords. - */ + struct drm_device *dev = signaller->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *useless; + int i, ret; + + /* NB: In order to be able to do semaphore MBOX updates for varying + * number of rings, it's easiest if we round up each individual update + * to a multiple of 2 (since ring updates must always be a multiple of + * 2) even though the actual update only requires 3 dwords. + */ #define MBOX_UPDATE_DWORDS 4 - intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(ring, mmio_offset); - intel_ring_emit(ring, ring->outstanding_lazy_seqno); - intel_ring_emit(ring, MI_NOOP); + if (i915_semaphore_is_enabled(dev)) + num_dwords += ((I915_NUM_RINGS-1) * MBOX_UPDATE_DWORDS); + + ret = intel_ring_begin(signaller, num_dwords); + if (ret) + return ret; +#undef MBOX_UPDATE_DWORDS + + for_each_ring(useless, dev_priv, i) { + u32 mbox_reg = signaller->semaphore.mbox.signal[i]; + if (mbox_reg != GEN6_NOSYNC) { + intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1)); + intel_ring_emit(signaller, mbox_reg); + intel_ring_emit(signaller, signaller->outstanding_lazy_seqno); + intel_ring_emit(signaller, MI_NOOP); + } else { + intel_ring_emit(signaller, MI_NOOP); + intel_ring_emit(signaller, MI_NOOP); + intel_ring_emit(signaller, MI_NOOP); + intel_ring_emit(signaller, MI_NOOP); + } + } + + return 0; } /** @@ -686,27 +720,12 @@ update_mboxes(struct intel_ring_buffer *ring, static int gen6_add_request(struct intel_ring_buffer *ring) { - struct drm_device *dev = ring->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_ring_buffer *useless; - int i, ret, num_dwords = 4; - - if (i915_semaphore_is_enabled(dev)) - num_dwords += ((I915_NUM_RINGS-1) * MBOX_UPDATE_DWORDS); -#undef MBOX_UPDATE_DWORDS + int ret; - ret = intel_ring_begin(ring, num_dwords); + ret = ring->semaphore.signal(ring, 4); if (ret) return ret; - if (i915_semaphore_is_enabled(dev)) { - for_each_ring(useless, dev_priv, i) { - u32 mbox_reg = ring->signal_mbox[i]; - if (mbox_reg != GEN6_NOSYNC) - update_mboxes(ring, mbox_reg); - } - } - intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); intel_ring_emit(ring, ring->outstanding_lazy_seqno); @@ -735,10 +754,11 @@ gen6_ring_sync(struct intel_ring_buffer *waiter, struct intel_ring_buffer *signaller, u32 seqno) { - int ret; u32 dw1 = MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER; + u32 wait_mbox = signaller->semaphore.mbox.wait[waiter->id]; + int ret; /* Throughout all of the GEM code, seqno passed implies our current * seqno is >= the last seqno executed. However for hardware the @@ -746,8 +766,7 @@ gen6_ring_sync(struct intel_ring_buffer *waiter, */ seqno -= 1; - WARN_ON(signaller->semaphore_register[waiter->id] == - MI_SEMAPHORE_SYNC_INVALID); + WARN_ON(wait_mbox == MI_SEMAPHORE_SYNC_INVALID); ret = intel_ring_begin(waiter, 4); if (ret) @@ -755,9 +774,7 @@ gen6_ring_sync(struct intel_ring_buffer *waiter, /* If seqno wrap happened, omit the wait with no-ops */ if (likely(!i915_gem_has_seqno_wrapped(waiter->dev, seqno))) { - intel_ring_emit(waiter, - dw1 | - signaller->semaphore_register[waiter->id]); + intel_ring_emit(waiter, dw1 | wait_mbox); intel_ring_emit(waiter, seqno); intel_ring_emit(waiter, 0); intel_ring_emit(waiter, MI_NOOP); @@ -784,7 +801,7 @@ do { \ static int pc_render_add_request(struct intel_ring_buffer *ring) { - u32 scratch_addr = ring->scratch.gtt_offset + 128; + u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; /* For Ironlake, MI_USER_INTERRUPT was deprecated and apparently @@ -806,15 +823,15 @@ pc_render_add_request(struct intel_ring_buffer *ring) intel_ring_emit(ring, ring->outstanding_lazy_seqno); intel_ring_emit(ring, 0); PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; /* write to separate cachelines */ + scratch_addr += 2 * CACHELINE_BYTES; /* write to separate cachelines */ PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; + scratch_addr += 2 * CACHELINE_BYTES; PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; + scratch_addr += 2 * CACHELINE_BYTES; PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; + scratch_addr += 2 * CACHELINE_BYTES; PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; + scratch_addr += 2 * CACHELINE_BYTES; PIPE_CONTROL_FLUSH(ring, scratch_addr); intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE | @@ -989,6 +1006,11 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring) case BCS: mmio = BLT_HWS_PGA_GEN7; break; + /* + * VCS2 actually doesn't exist on Gen7. Only shut up + * gcc switch check warning + */ + case VCS2: case VCS: mmio = BSD_HWS_PGA_GEN7; break; @@ -1193,7 +1215,7 @@ gen8_ring_put_irq(struct intel_ring_buffer *ring) static int i965_dispatch_execbuffer(struct intel_ring_buffer *ring, - u32 offset, u32 length, + u64 offset, u32 length, unsigned flags) { int ret; @@ -1216,7 +1238,7 @@ i965_dispatch_execbuffer(struct intel_ring_buffer *ring, #define I830_BATCH_LIMIT (256*1024) static int i830_dispatch_execbuffer(struct intel_ring_buffer *ring, - u32 offset, u32 len, + u64 offset, u32 len, unsigned flags) { int ret; @@ -1267,7 +1289,7 @@ i830_dispatch_execbuffer(struct intel_ring_buffer *ring, static int i915_dispatch_execbuffer(struct intel_ring_buffer *ring, - u32 offset, u32 len, + u64 offset, u32 len, unsigned flags) { int ret; @@ -1299,45 +1321,39 @@ static void cleanup_status_page(struct intel_ring_buffer *ring) static int init_status_page(struct intel_ring_buffer *ring) { - struct drm_device *dev = ring->dev; struct drm_i915_gem_object *obj; - int ret; - obj = i915_gem_alloc_object(dev, 4096); - if (obj == NULL) { - DRM_ERROR("Failed to allocate status page\n"); - ret = -ENOMEM; - goto err; - } + if ((obj = ring->status_page.obj) == NULL) { + int ret; - ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC); - if (ret) - goto err_unref; + obj = i915_gem_alloc_object(ring->dev, 4096); + if (obj == NULL) { + DRM_ERROR("Failed to allocate status page\n"); + return -ENOMEM; + } - ret = i915_gem_obj_ggtt_pin(obj, 4096, 0); - if (ret) - goto err_unref; + ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC); + if (ret) + goto err_unref; + + ret = i915_gem_obj_ggtt_pin(obj, 4096, 0); + if (ret) { +err_unref: + drm_gem_object_unreference(&obj->base); + return ret; + } + + ring->status_page.obj = obj; + } ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(obj); ring->status_page.page_addr = kmap(sg_page(obj->pages->sgl)); - if (ring->status_page.page_addr == NULL) { - ret = -ENOMEM; - goto err_unpin; - } - ring->status_page.obj = obj; memset(ring->status_page.page_addr, 0, PAGE_SIZE); DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n", ring->name, ring->status_page.gfx_addr); return 0; - -err_unpin: - i915_gem_object_ggtt_unpin(obj); -err_unref: - drm_gem_object_unreference(&obj->base); -err: - return ret; } static int init_phys_status_page(struct intel_ring_buffer *ring) @@ -1357,44 +1373,23 @@ static int init_phys_status_page(struct intel_ring_buffer *ring) return 0; } -static int intel_init_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring) +static int allocate_ring_buffer(struct intel_ring_buffer *ring) { + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_gem_object *obj; - struct drm_i915_private *dev_priv = dev->dev_private; int ret; - ring->dev = dev; - INIT_LIST_HEAD(&ring->active_list); - INIT_LIST_HEAD(&ring->request_list); - ring->size = 32 * PAGE_SIZE; - memset(ring->sync_seqno, 0, sizeof(ring->sync_seqno)); - - init_waitqueue_head(&ring->irq_queue); - - if (I915_NEED_GFX_HWS(dev)) { - ret = init_status_page(ring); - if (ret) - return ret; - } else { - BUG_ON(ring->id != RCS); - ret = init_phys_status_page(ring); - if (ret) - return ret; - } + if (ring->obj) + return 0; obj = NULL; if (!HAS_LLC(dev)) obj = i915_gem_object_create_stolen(dev, ring->size); if (obj == NULL) obj = i915_gem_alloc_object(dev, ring->size); - if (obj == NULL) { - DRM_ERROR("Failed to allocate ringbuffer\n"); - ret = -ENOMEM; - goto err_hws; - } - - ring->obj = obj; + if (obj == NULL) + return -ENOMEM; ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE); if (ret) @@ -1408,55 +1403,72 @@ static int intel_init_ring_buffer(struct drm_device *dev, ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj), ring->size); if (ring->virtual_start == NULL) { - DRM_ERROR("Failed to map ringbuffer.\n"); ret = -EINVAL; goto err_unpin; } - ret = ring->init(ring); - if (ret) - goto err_unmap; + ring->obj = obj; + return 0; + +err_unpin: + i915_gem_object_ggtt_unpin(obj); +err_unref: + drm_gem_object_unreference(&obj->base); + return ret; +} + +static int intel_init_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + int ret; + + ring->dev = dev; + INIT_LIST_HEAD(&ring->active_list); + INIT_LIST_HEAD(&ring->request_list); + ring->size = 32 * PAGE_SIZE; + memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno)); + + init_waitqueue_head(&ring->irq_queue); + + if (I915_NEED_GFX_HWS(dev)) { + ret = init_status_page(ring); + if (ret) + return ret; + } else { + BUG_ON(ring->id != RCS); + ret = init_phys_status_page(ring); + if (ret) + return ret; + } + + ret = allocate_ring_buffer(ring); + if (ret) { + DRM_ERROR("Failed to allocate ringbuffer %s: %d\n", ring->name, ret); + return ret; + } /* Workaround an erratum on the i830 which causes a hang if * the TAIL pointer points to within the last 2 cachelines * of the buffer. */ ring->effective_size = ring->size; - if (IS_I830(ring->dev) || IS_845G(ring->dev)) - ring->effective_size -= 128; + if (IS_I830(dev) || IS_845G(dev)) + ring->effective_size -= 2 * CACHELINE_BYTES; i915_cmd_parser_init_ring(ring); - return 0; - -err_unmap: - iounmap(ring->virtual_start); -err_unpin: - i915_gem_object_ggtt_unpin(obj); -err_unref: - drm_gem_object_unreference(&obj->base); - ring->obj = NULL; -err_hws: - cleanup_status_page(ring); - return ret; + return ring->init(ring); } void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) { - struct drm_i915_private *dev_priv; - int ret; + struct drm_i915_private *dev_priv = to_i915(ring->dev); if (ring->obj == NULL) return; - /* Disable the ring buffer. The ring must be idle at this point */ - dev_priv = ring->dev->dev_private; - ret = intel_ring_idle(ring); - if (ret && !i915_reset_in_progress(&dev_priv->gpu_error)) - DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n", - ring->name, ret); - - I915_WRITE_CTL(ring, 0); + intel_stop_ring_buffer(ring); + WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0); iounmap(ring->virtual_start); @@ -1475,7 +1487,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n) { struct drm_i915_gem_request *request; - u32 seqno = 0, tail; + u32 seqno = 0; int ret; if (ring->last_retired_head != -1) { @@ -1488,26 +1500,10 @@ static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n) } list_for_each_entry(request, &ring->request_list, list) { - int space; - - if (request->tail == -1) - continue; - - space = request->tail - (ring->tail + I915_RING_FREE_SPACE); - if (space < 0) - space += ring->size; - if (space >= n) { + if (__ring_space(request->tail, ring->tail, ring->size) >= n) { seqno = request->seqno; - tail = request->tail; break; } - - /* Consume this request in case we need more space than - * is available and so need to prevent a race between - * updating last_retired_head and direct reads of - * I915_RING_HEAD. It also provides a nice sanity check. - */ - request->tail = -1; } if (seqno == 0) @@ -1517,11 +1513,11 @@ static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n) if (ret) return ret; - ring->head = tail; - ring->space = ring_space(ring); - if (WARN_ON(ring->space < n)) - return -ENOSPC; + i915_gem_retire_requests_ring(ring); + ring->head = ring->last_retired_head; + ring->last_retired_head = -1; + ring->space = ring_space(ring); return 0; } @@ -1539,7 +1535,6 @@ static int ring_wait_for_space(struct intel_ring_buffer *ring, int n) /* force the tail write in case we have been skipping them */ __intel_ring_advance(ring); - trace_i915_ring_wait_begin(ring); /* With GEM the hangcheck timer should kick us out of the loop, * leaving it early runs the risk of corrupting GEM state (due * to running on almost untested codepaths). But on resume @@ -1547,12 +1542,13 @@ static int ring_wait_for_space(struct intel_ring_buffer *ring, int n) * case by choosing an insanely large timeout. */ end = jiffies + 60 * HZ; + trace_i915_ring_wait_begin(ring); do { ring->head = I915_READ_HEAD(ring); ring->space = ring_space(ring); if (ring->space >= n) { - trace_i915_ring_wait_end(ring); - return 0; + ret = 0; + break; } if (!drm_core_check_feature(dev, DRIVER_MODESET) && @@ -1564,13 +1560,23 @@ static int ring_wait_for_space(struct intel_ring_buffer *ring, int n) msleep(1); + if (dev_priv->mm.interruptible && signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + ret = i915_gem_check_wedge(&dev_priv->gpu_error, dev_priv->mm.interruptible); if (ret) - return ret; - } while (!time_after(jiffies, end)); + break; + + if (time_after(jiffies, end)) { + ret = -EBUSY; + break; + } + } while (1); trace_i915_ring_wait_end(ring); - return -EBUSY; + return ret; } static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring) @@ -1684,12 +1690,13 @@ int intel_ring_begin(struct intel_ring_buffer *ring, /* Align the ring tail to a cacheline boundary */ int intel_ring_cacheline_align(struct intel_ring_buffer *ring) { - int num_dwords = (64 - (ring->tail & 63)) / sizeof(uint32_t); + int num_dwords = (ring->tail & (CACHELINE_BYTES - 1)) / sizeof(uint32_t); int ret; if (num_dwords == 0) return 0; + num_dwords = CACHELINE_BYTES / sizeof(uint32_t) - num_dwords; ret = intel_ring_begin(ring, num_dwords); if (ret) return ret; @@ -1789,7 +1796,7 @@ static int gen6_bsd_ring_flush(struct intel_ring_buffer *ring, static int gen8_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, - u32 offset, u32 len, + u64 offset, u32 len, unsigned flags) { struct drm_i915_private *dev_priv = ring->dev->dev_private; @@ -1803,8 +1810,8 @@ gen8_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, /* FIXME(BDW): Address space and security selectors. */ intel_ring_emit(ring, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8)); - intel_ring_emit(ring, offset); - intel_ring_emit(ring, 0); + intel_ring_emit(ring, lower_32_bits(offset)); + intel_ring_emit(ring, upper_32_bits(offset)); intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); @@ -1813,7 +1820,7 @@ gen8_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, static int hsw_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, - u32 offset, u32 len, + u64 offset, u32 len, unsigned flags) { int ret; @@ -1834,7 +1841,7 @@ hsw_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, static int gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, - u32 offset, u32 len, + u64 offset, u32 len, unsigned flags) { int ret; @@ -1920,15 +1927,24 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT; ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; - ring->sync_to = gen6_ring_sync; - ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_INVALID; - ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_RV; - ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_RB; - ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_RVE; - ring->signal_mbox[RCS] = GEN6_NOSYNC; - ring->signal_mbox[VCS] = GEN6_VRSYNC; - ring->signal_mbox[BCS] = GEN6_BRSYNC; - ring->signal_mbox[VECS] = GEN6_VERSYNC; + ring->semaphore.sync_to = gen6_ring_sync; + ring->semaphore.signal = gen6_signal; + /* + * The current semaphore is only applied on pre-gen8 platform. + * And there is no VCS2 ring on the pre-gen8 platform. So the + * semaphore between RCS and VCS2 is initialized as INVALID. + * Gen8 will initialize the sema between VCS2 and RCS later. + */ + ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_RV; + ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_RB; + ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_RVE; + ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.signal[RCS] = GEN6_NOSYNC; + ring->semaphore.mbox.signal[VCS] = GEN6_VRSYNC; + ring->semaphore.mbox.signal[BCS] = GEN6_BRSYNC; + ring->semaphore.mbox.signal[VECS] = GEN6_VERSYNC; + ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC; } else if (IS_GEN5(dev)) { ring->add_request = pc_render_add_request; ring->flush = gen4_render_ring_flush; @@ -2046,7 +2062,7 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) ring->size = size; ring->effective_size = ring->size; if (IS_I830(ring->dev) || IS_845G(ring->dev)) - ring->effective_size -= 128; + ring->effective_size -= 2 * CACHELINE_BYTES; ring->virtual_start = ioremap_wc(start, size); if (ring->virtual_start == NULL) { @@ -2096,15 +2112,24 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; } - ring->sync_to = gen6_ring_sync; - ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VR; - ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_INVALID; - ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VB; - ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_VVE; - ring->signal_mbox[RCS] = GEN6_RVSYNC; - ring->signal_mbox[VCS] = GEN6_NOSYNC; - ring->signal_mbox[BCS] = GEN6_BVSYNC; - ring->signal_mbox[VECS] = GEN6_VEVSYNC; + ring->semaphore.sync_to = gen6_ring_sync; + ring->semaphore.signal = gen6_signal; + /* + * The current semaphore is only applied on pre-gen8 platform. + * And there is no VCS2 ring on the pre-gen8 platform. So the + * semaphore between VCS and VCS2 is initialized as INVALID. + * Gen8 will initialize the sema between VCS2 and VCS later. + */ + ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_VR; + ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_VB; + ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_VVE; + ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.signal[RCS] = GEN6_RVSYNC; + ring->semaphore.mbox.signal[VCS] = GEN6_NOSYNC; + ring->semaphore.mbox.signal[BCS] = GEN6_BVSYNC; + ring->semaphore.mbox.signal[VECS] = GEN6_VEVSYNC; + ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC; } else { ring->mmio_base = BSD_RING_BASE; ring->flush = bsd_ring_flush; @@ -2127,6 +2152,58 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) return intel_init_ring_buffer(dev, ring); } +/** + * Initialize the second BSD ring for Broadwell GT3. + * It is noted that this only exists on Broadwell GT3. + */ +int intel_init_bsd2_ring_buffer(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->ring[VCS2]; + + if ((INTEL_INFO(dev)->gen != 8)) { + DRM_ERROR("No dual-BSD ring on non-BDW machine\n"); + return -EINVAL; + } + + ring->name = "bds2_ring"; + ring->id = VCS2; + + ring->write_tail = ring_write_tail; + ring->mmio_base = GEN8_BSD2_RING_BASE; + ring->flush = gen6_bsd_ring_flush; + ring->add_request = gen6_add_request; + ring->get_seqno = gen6_ring_get_seqno; + ring->set_seqno = ring_set_seqno; + ring->irq_enable_mask = + GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT; + ring->irq_get = gen8_ring_get_irq; + ring->irq_put = gen8_ring_put_irq; + ring->dispatch_execbuffer = + gen8_ring_dispatch_execbuffer; + ring->semaphore.sync_to = gen6_ring_sync; + /* + * The current semaphore is only applied on the pre-gen8. And there + * is no bsd2 ring on the pre-gen8. So now the semaphore_register + * between VCS2 and other ring is initialized as invalid. + * Gen8 will initialize the sema between VCS2 and other ring later. + */ + ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.signal[RCS] = GEN6_NOSYNC; + ring->semaphore.mbox.signal[VCS] = GEN6_NOSYNC; + ring->semaphore.mbox.signal[BCS] = GEN6_NOSYNC; + ring->semaphore.mbox.signal[VECS] = GEN6_NOSYNC; + ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC; + + ring->init = init_ring_common; + + return intel_init_ring_buffer(dev, ring); +} + int intel_init_blt_ring_buffer(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2153,15 +2230,24 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) ring->irq_put = gen6_ring_put_irq; ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; } - ring->sync_to = gen6_ring_sync; - ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_BR; - ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_BV; - ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_INVALID; - ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_BVE; - ring->signal_mbox[RCS] = GEN6_RBSYNC; - ring->signal_mbox[VCS] = GEN6_VBSYNC; - ring->signal_mbox[BCS] = GEN6_NOSYNC; - ring->signal_mbox[VECS] = GEN6_VEBSYNC; + ring->semaphore.sync_to = gen6_ring_sync; + ring->semaphore.signal = gen6_signal; + /* + * The current semaphore is only applied on pre-gen8 platform. And + * there is no VCS2 ring on the pre-gen8 platform. So the semaphore + * between BCS and VCS2 is initialized as INVALID. + * Gen8 will initialize the sema between BCS and VCS2 later. + */ + ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_BR; + ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_BV; + ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_BVE; + ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.signal[RCS] = GEN6_RBSYNC; + ring->semaphore.mbox.signal[VCS] = GEN6_VBSYNC; + ring->semaphore.mbox.signal[BCS] = GEN6_NOSYNC; + ring->semaphore.mbox.signal[VECS] = GEN6_VEBSYNC; + ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC; ring->init = init_ring_common; return intel_init_ring_buffer(dev, ring); @@ -2194,15 +2280,18 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev) ring->irq_put = hsw_vebox_put_irq; ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; } - ring->sync_to = gen6_ring_sync; - ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VER; - ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_VEV; - ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VEB; - ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_INVALID; - ring->signal_mbox[RCS] = GEN6_RVESYNC; - ring->signal_mbox[VCS] = GEN6_VVESYNC; - ring->signal_mbox[BCS] = GEN6_BVESYNC; - ring->signal_mbox[VECS] = GEN6_NOSYNC; + ring->semaphore.sync_to = gen6_ring_sync; + ring->semaphore.signal = gen6_signal; + ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_VER; + ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_VEV; + ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_VEB; + ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore.mbox.signal[RCS] = GEN6_RVESYNC; + ring->semaphore.mbox.signal[VCS] = GEN6_VVESYNC; + ring->semaphore.mbox.signal[BCS] = GEN6_BVESYNC; + ring->semaphore.mbox.signal[VECS] = GEN6_NOSYNC; + ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC; ring->init = init_ring_common; return intel_init_ring_buffer(dev, ring); @@ -2245,3 +2334,19 @@ intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring) ring->gpu_caches_dirty = false; return 0; } + +void +intel_stop_ring_buffer(struct intel_ring_buffer *ring) +{ + int ret; + + if (!intel_ring_initialized(ring)) + return; + + ret = intel_ring_idle(ring); + if (ret && !i915_reset_in_progress(&to_i915(ring->dev)->gpu_error)) + DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n", + ring->name, ret); + + stop_ring(ring); +} diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 2b91c4b4d34b2e..72c3c15f62405b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -61,8 +61,10 @@ struct intel_ring_buffer { VCS, BCS, VECS, + VCS2 } id; -#define I915_NUM_RINGS 4 +#define I915_NUM_RINGS 5 +#define LAST_USER_RING (VECS + 1) u32 mmio_base; void __iomem *virtual_start; struct drm_device *dev; @@ -88,7 +90,6 @@ struct intel_ring_buffer { unsigned irq_refcount; /* protected by dev_priv->irq_lock */ u32 irq_enable_mask; /* bitmask to enable ring interrupt */ u32 trace_irq_seqno; - u32 sync_seqno[I915_NUM_RINGS-1]; bool __must_check (*irq_get)(struct intel_ring_buffer *ring); void (*irq_put)(struct intel_ring_buffer *ring); @@ -111,19 +112,30 @@ struct intel_ring_buffer { void (*set_seqno)(struct intel_ring_buffer *ring, u32 seqno); int (*dispatch_execbuffer)(struct intel_ring_buffer *ring, - u32 offset, u32 length, + u64 offset, u32 length, unsigned flags); #define I915_DISPATCH_SECURE 0x1 #define I915_DISPATCH_PINNED 0x2 void (*cleanup)(struct intel_ring_buffer *ring); - int (*sync_to)(struct intel_ring_buffer *ring, + + struct { + u32 sync_seqno[I915_NUM_RINGS-1]; + + struct { + /* our mbox written by others */ + u32 wait[I915_NUM_RINGS]; + /* mboxes this ring signals to */ + u32 signal[I915_NUM_RINGS]; + } mbox; + + /* AKA wait() */ + int (*sync_to)(struct intel_ring_buffer *ring, struct intel_ring_buffer *to, u32 seqno); - - /* our mbox written by others */ - u32 semaphore_register[I915_NUM_RINGS]; - /* mboxes this ring signals to */ - u32 signal_mbox[I915_NUM_RINGS]; + int (*signal)(struct intel_ring_buffer *signaller, + /* num_dwords needed by caller */ + unsigned int num_dwords); + } semaphore; /** * List of objects currently involved in rendering from the @@ -153,10 +165,6 @@ struct intel_ring_buffer { wait_queue_head_t irq_queue; - /** - * Do an explicit TLB flush before MI_SET_CONTEXT - */ - bool itlb_before_ctx_switch; struct i915_hw_context *default_context; struct i915_hw_context *last_context; @@ -267,6 +275,7 @@ intel_write_status_page(struct intel_ring_buffer *ring, #define I915_GEM_HWS_SCRATCH_INDEX 0x30 #define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT) +void intel_stop_ring_buffer(struct intel_ring_buffer *ring); void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring); int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n); @@ -290,6 +299,7 @@ int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring); int intel_init_render_ring_buffer(struct drm_device *dev); int intel_init_bsd_ring_buffer(struct drm_device *dev); +int intel_init_bsd2_ring_buffer(struct drm_device *dev); int intel_init_blt_ring_buffer(struct drm_device *dev); int intel_init_vebox_ring_buffer(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index d27155adf5db2b..2bf09e8eb5ed43 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1174,7 +1174,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, return true; } -static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder) +static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder) { struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2424,8 +2424,8 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector, if (ret < 0) goto err1; - ret = sysfs_create_link(&encoder->ddc.dev.kobj, - &drm_connector->kdev->kobj, + ret = sysfs_create_link(&drm_connector->kdev->kobj, + &encoder->ddc.dev.kobj, encoder->ddc.dev.kobj.name); if (ret < 0) goto err2; @@ -2999,7 +2999,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) intel_encoder->compute_config = intel_sdvo_compute_config; intel_encoder->disable = intel_disable_sdvo; - intel_encoder->mode_set = intel_sdvo_mode_set; + intel_encoder->pre_enable = intel_sdvo_pre_enable; intel_encoder->enable = intel_enable_sdvo; intel_encoder->get_hw_state = intel_sdvo_get_hw_state; intel_encoder->get_config = intel_sdvo_get_config; diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index 0954f132726ea0..b1a5514e695a71 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -182,6 +182,14 @@ u32 vlv_dpio_read(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) vlv_sideband_rw(dev_priv, DPIO_DEVFN, DPIO_PHY_IOSF_PORT(DPIO_PHY(pipe)), DPIO_OPCODE_REG_READ, reg, &val); + + /* + * FIXME: There might be some registers where all 1's is a valid value, + * so ideally we should check the register offset instead... + */ + WARN(val == 0xffffffff, "DPIO read pipe %c reg 0x%x == 0x%x\n", + pipe_name(pipe), reg, val); + return val; } diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 336ae6c602f2a6..213cd58f041252 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -37,6 +37,106 @@ #include #include "i915_drv.h" +static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs) +{ + /* paranoia */ + if (!mode->crtc_htotal) + return 1; + + return DIV_ROUND_UP(usecs * mode->crtc_clock, 1000 * mode->crtc_htotal); +} + +static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) +{ + struct drm_device *dev = crtc->base.dev; + const struct drm_display_mode *mode = &crtc->config.adjusted_mode; + enum pipe pipe = crtc->pipe; + long timeout = msecs_to_jiffies_timeout(1); + int scanline, min, max, vblank_start; + DEFINE_WAIT(wait); + + WARN_ON(!mutex_is_locked(&crtc->base.mutex)); + + vblank_start = mode->crtc_vblank_start; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + vblank_start = DIV_ROUND_UP(vblank_start, 2); + + /* FIXME needs to be calibrated sensibly */ + min = vblank_start - usecs_to_scanlines(mode, 100); + max = vblank_start - 1; + + if (min <= 0 || max <= 0) + return false; + + if (WARN_ON(drm_vblank_get(dev, pipe))) + return false; + + local_irq_disable(); + + trace_i915_pipe_update_start(crtc, min, max); + + for (;;) { + /* + * prepare_to_wait() has a memory barrier, which guarantees + * other CPUs can see the task state update by the time we + * read the scanline. + */ + prepare_to_wait(&crtc->vbl_wait, &wait, TASK_UNINTERRUPTIBLE); + + scanline = intel_get_crtc_scanline(crtc); + if (scanline < min || scanline > max) + break; + + if (timeout <= 0) { + DRM_ERROR("Potential atomic update failure on pipe %c\n", + pipe_name(crtc->pipe)); + break; + } + + local_irq_enable(); + + timeout = schedule_timeout(timeout); + + local_irq_disable(); + } + + finish_wait(&crtc->vbl_wait, &wait); + + drm_vblank_put(dev, pipe); + + *start_vbl_count = dev->driver->get_vblank_counter(dev, pipe); + + trace_i915_pipe_update_vblank_evaded(crtc, min, max, *start_vbl_count); + + return true; +} + +static void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count) +{ + struct drm_device *dev = crtc->base.dev; + enum pipe pipe = crtc->pipe; + u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe); + + trace_i915_pipe_update_end(crtc, end_vbl_count); + + local_irq_enable(); + + if (start_vbl_count != end_vbl_count) + DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u)\n", + pipe_name(pipe), start_vbl_count, end_vbl_count); +} + +static void intel_update_primary_plane(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + int reg = DSPCNTR(crtc->plane); + + if (crtc->primary_enabled) + I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); + else + I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); +} + static void vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -48,11 +148,14 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, struct drm_device *dev = dplane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(dplane); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; int plane = intel_plane->plane; u32 sprctl; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + u32 start_vbl_count; + bool atomic_update; sprctl = I915_READ(SPCNTR(pipe, plane)); @@ -131,6 +234,10 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, fb->pitches[0]); linear_offset -= sprsurf_offset; + atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); + + intel_update_primary_plane(intel_crtc); + I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); @@ -143,7 +250,11 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, I915_WRITE(SPCNTR(pipe, plane), sprctl); I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); - POSTING_READ(SPSURF(pipe, plane)); + + intel_flush_primary_plane(dev_priv, intel_crtc->plane); + + if (atomic_update) + intel_pipe_update_end(intel_crtc, start_vbl_count); } static void @@ -152,14 +263,25 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) struct drm_device *dev = dplane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(dplane); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; int plane = intel_plane->plane; + u32 start_vbl_count; + bool atomic_update; + + atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); + + intel_update_primary_plane(intel_crtc); I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) & ~SP_ENABLE); /* Activate double buffered register update */ I915_WRITE(SPSURF(pipe, plane), 0); - POSTING_READ(SPSURF(pipe, plane)); + + intel_flush_primary_plane(dev_priv, intel_crtc->plane); + + if (atomic_update) + intel_pipe_update_end(intel_crtc, start_vbl_count); intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false); } @@ -226,10 +348,13 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; u32 sprctl, sprscale = 0; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + u32 start_vbl_count; + bool atomic_update; sprctl = I915_READ(SPRCTL(pipe)); @@ -299,6 +424,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, pixel_size, fb->pitches[0]); linear_offset -= sprsurf_offset; + atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); + + intel_update_primary_plane(intel_crtc); + I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); @@ -317,7 +446,11 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, I915_WRITE(SPRCTL(pipe), sprctl); I915_WRITE(SPRSURF(pipe), i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); - POSTING_READ(SPRSURF(pipe)); + + intel_flush_primary_plane(dev_priv, intel_crtc->plane); + + if (atomic_update) + intel_pipe_update_end(intel_crtc, start_vbl_count); } static void @@ -326,7 +459,14 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; + u32 start_vbl_count; + bool atomic_update; + + atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); + + intel_update_primary_plane(intel_crtc); I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); /* Can't leave the scaler enabled... */ @@ -334,7 +474,11 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) I915_WRITE(SPRSCALE(pipe), 0); /* Activate double buffered register update */ I915_WRITE(SPRSURF(pipe), 0); - POSTING_READ(SPRSURF(pipe)); + + intel_flush_primary_plane(dev_priv, intel_crtc->plane); + + if (atomic_update) + intel_pipe_update_end(intel_crtc, start_vbl_count); /* * Avoid underruns when disabling the sprite. @@ -410,10 +554,13 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; unsigned long dvssurf_offset, linear_offset; u32 dvscntr, dvsscale; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + u32 start_vbl_count; + bool atomic_update; dvscntr = I915_READ(DVSCNTR(pipe)); @@ -478,6 +625,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, pixel_size, fb->pitches[0]); linear_offset -= dvssurf_offset; + atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); + + intel_update_primary_plane(intel_crtc); + I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); @@ -491,7 +642,11 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, I915_WRITE(DVSCNTR(pipe), dvscntr); I915_WRITE(DVSSURF(pipe), i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); - POSTING_READ(DVSSURF(pipe)); + + intel_flush_primary_plane(dev_priv, intel_crtc->plane); + + if (atomic_update) + intel_pipe_update_end(intel_crtc, start_vbl_count); } static void @@ -500,14 +655,25 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; + u32 start_vbl_count; + bool atomic_update; + + atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); + + intel_update_primary_plane(intel_crtc); I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE); /* Disable the scaler */ I915_WRITE(DVSSCALE(pipe), 0); /* Flush double buffered register updates */ I915_WRITE(DVSSURF(pipe), 0); - POSTING_READ(DVSSURF(pipe)); + + intel_flush_primary_plane(dev_priv, intel_crtc->plane); + + if (atomic_update) + intel_pipe_update_end(intel_crtc, start_vbl_count); /* * Avoid underruns when disabling the sprite. @@ -519,20 +685,10 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) } static void -intel_enable_primary(struct drm_crtc *crtc) +intel_post_enable_primary(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int reg = DSPCNTR(intel_crtc->plane); - - if (intel_crtc->primary_enabled) - return; - - intel_crtc->primary_enabled = true; - - I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); - intel_flush_primary_plane(dev_priv, intel_crtc->plane); /* * FIXME IPS should be fine as long as one plane is @@ -551,17 +707,11 @@ intel_enable_primary(struct drm_crtc *crtc) } static void -intel_disable_primary(struct drm_crtc *crtc) +intel_pre_disable_primary(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int reg = DSPCNTR(intel_crtc->plane); - - if (!intel_crtc->primary_enabled) - return; - - intel_crtc->primary_enabled = false; mutex_lock(&dev->struct_mutex); if (dev_priv->fbc.plane == intel_crtc->plane) @@ -575,9 +725,6 @@ intel_disable_primary(struct drm_crtc *crtc) * versa. */ hsw_disable_ips(intel_crtc); - - I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); - intel_flush_primary_plane(dev_priv, intel_crtc->plane); } static int @@ -671,7 +818,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_i915_gem_object *obj = intel_fb->obj; struct drm_i915_gem_object *old_obj = intel_plane->obj; int ret; - bool disable_primary = false; + bool primary_enabled; bool visible; int hscale, vscale; int max_scale, min_scale; @@ -842,8 +989,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, * If the sprite is completely covering the primary plane, * we can disable the primary and save power. */ - disable_primary = drm_rect_equals(&dst, &clip) && !colorkey_enabled(intel_plane); - WARN_ON(disable_primary && !visible && intel_crtc->active); + primary_enabled = !drm_rect_equals(&dst, &clip) || colorkey_enabled(intel_plane); + WARN_ON(!primary_enabled && !visible && intel_crtc->active); mutex_lock(&dev->struct_mutex); @@ -870,12 +1017,12 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, intel_plane->obj = obj; if (intel_crtc->active) { - /* - * Be sure to re-enable the primary before the sprite is no longer - * covering it fully. - */ - if (!disable_primary) - intel_enable_primary(crtc); + bool primary_was_enabled = intel_crtc->primary_enabled; + + intel_crtc->primary_enabled = primary_enabled; + + if (primary_was_enabled && !primary_enabled) + intel_pre_disable_primary(crtc); if (visible) intel_plane->update_plane(plane, crtc, fb, obj, @@ -884,8 +1031,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, else intel_plane->disable_plane(plane, crtc); - if (disable_primary) - intel_disable_primary(crtc); + if (!primary_was_enabled && primary_enabled) + intel_post_enable_primary(crtc); } /* Unpin old obj after new one is active to avoid ugliness */ @@ -923,8 +1070,14 @@ intel_disable_plane(struct drm_plane *plane) intel_crtc = to_intel_crtc(plane->crtc); if (intel_crtc->active) { - intel_enable_primary(plane->crtc); + bool primary_was_enabled = intel_crtc->primary_enabled; + + intel_crtc->primary_enabled = true; + intel_plane->disable_plane(plane, plane->crtc); + + if (!primary_was_enabled && intel_crtc->primary_enabled) + intel_post_enable_primary(plane->crtc); } if (intel_plane->obj) { diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index bafe92e317d5d2..e0193e8020b853 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -934,7 +934,86 @@ intel_tv_compute_config(struct intel_encoder *encoder, return true; } -static void intel_tv_mode_set(struct intel_encoder *encoder) +static void +set_tv_mode_timings(struct drm_i915_private *dev_priv, + const struct tv_mode *tv_mode, + bool burst_ena) +{ + u32 hctl1, hctl2, hctl3; + u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; + + hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) | + (tv_mode->htotal << TV_HTOTAL_SHIFT); + + hctl2 = (tv_mode->hburst_start << 16) | + (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT); + + if (burst_ena) + hctl2 |= TV_BURST_ENA; + + hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) | + (tv_mode->hblank_end << TV_HBLANK_END_SHIFT); + + vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) | + (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) | + (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT); + + vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) | + (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) | + (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT); + + vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) | + (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) | + (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT); + + if (tv_mode->veq_ena) + vctl3 |= TV_EQUAL_ENA; + + vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) | + (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT); + + vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) | + (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT); + + vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) | + (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT); + + vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) | + (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT); + + I915_WRITE(TV_H_CTL_1, hctl1); + I915_WRITE(TV_H_CTL_2, hctl2); + I915_WRITE(TV_H_CTL_3, hctl3); + I915_WRITE(TV_V_CTL_1, vctl1); + I915_WRITE(TV_V_CTL_2, vctl2); + I915_WRITE(TV_V_CTL_3, vctl3); + I915_WRITE(TV_V_CTL_4, vctl4); + I915_WRITE(TV_V_CTL_5, vctl5); + I915_WRITE(TV_V_CTL_6, vctl6); + I915_WRITE(TV_V_CTL_7, vctl7); +} + +static void set_color_conversion(struct drm_i915_private *dev_priv, + const struct color_conversion *color_conversion) +{ + if (!color_conversion) + return; + + I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | + color_conversion->gy); + I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) | + color_conversion->ay); + I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | + color_conversion->gu); + I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | + color_conversion->au); + I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | + color_conversion->gv); + I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | + color_conversion->av); +} + +static void intel_tv_pre_enable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -942,14 +1021,13 @@ static void intel_tv_mode_set(struct intel_encoder *encoder) struct intel_tv *intel_tv = enc_to_tv(encoder); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); u32 tv_ctl; - u32 hctl1, hctl2, hctl3; - u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; u32 scctl1, scctl2, scctl3; int i, j; const struct video_levels *video_levels; const struct color_conversion *color_conversion; bool burst_ena; - int pipe = intel_crtc->pipe; + int xpos = 0x0, ypos = 0x0; + unsigned int xsize, ysize; if (!tv_mode) return; /* can't happen (mode_prepare prevents this) */ @@ -982,44 +1060,6 @@ static void intel_tv_mode_set(struct intel_encoder *encoder) burst_ena = tv_mode->burst_ena; break; } - hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) | - (tv_mode->htotal << TV_HTOTAL_SHIFT); - - hctl2 = (tv_mode->hburst_start << 16) | - (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT); - - if (burst_ena) - hctl2 |= TV_BURST_ENA; - - hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) | - (tv_mode->hblank_end << TV_HBLANK_END_SHIFT); - - vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) | - (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) | - (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT); - - vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) | - (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) | - (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT); - - vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) | - (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) | - (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT); - - if (tv_mode->veq_ena) - vctl3 |= TV_EQUAL_ENA; - - vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) | - (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT); - - vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) | - (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT); - - vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) | - (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT); - - vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) | - (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT); if (intel_crtc->pipe == 1) tv_ctl |= TV_ENC_PIPEB_SELECT; @@ -1051,37 +1091,16 @@ static void intel_tv_mode_set(struct intel_encoder *encoder) tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT; /* Enable two fixes for the chips that need them. */ - if (dev->pdev->device < 0x2772) + if (IS_I915GM(dev)) tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX; - I915_WRITE(TV_H_CTL_1, hctl1); - I915_WRITE(TV_H_CTL_2, hctl2); - I915_WRITE(TV_H_CTL_3, hctl3); - I915_WRITE(TV_V_CTL_1, vctl1); - I915_WRITE(TV_V_CTL_2, vctl2); - I915_WRITE(TV_V_CTL_3, vctl3); - I915_WRITE(TV_V_CTL_4, vctl4); - I915_WRITE(TV_V_CTL_5, vctl5); - I915_WRITE(TV_V_CTL_6, vctl6); - I915_WRITE(TV_V_CTL_7, vctl7); + set_tv_mode_timings(dev_priv, tv_mode, burst_ena); + I915_WRITE(TV_SC_CTL_1, scctl1); I915_WRITE(TV_SC_CTL_2, scctl2); I915_WRITE(TV_SC_CTL_3, scctl3); - if (color_conversion) { - I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | - color_conversion->gy); - I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) | - color_conversion->ay); - I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | - color_conversion->gu); - I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | - color_conversion->au); - I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | - color_conversion->gv); - I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | - color_conversion->av); - } + set_color_conversion(dev_priv, color_conversion); if (INTEL_INFO(dev)->gen >= 4) I915_WRITE(TV_CLR_KNOBS, 0x00404000); @@ -1092,46 +1111,25 @@ static void intel_tv_mode_set(struct intel_encoder *encoder) I915_WRITE(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); - { - int pipeconf_reg = PIPECONF(pipe); - int dspcntr_reg = DSPCNTR(intel_crtc->plane); - int pipeconf = I915_READ(pipeconf_reg); - int dspcntr = I915_READ(dspcntr_reg); - int xpos = 0x0, ypos = 0x0; - unsigned int xsize, ysize; - /* Pipe must be off here */ - I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); - intel_flush_primary_plane(dev_priv, intel_crtc->plane); - - /* Wait for vblank for the disable to take effect */ - if (IS_GEN2(dev)) - intel_wait_for_vblank(dev, intel_crtc->pipe); - - I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE); - /* Wait for vblank for the disable to take effect. */ - intel_wait_for_pipe_off(dev, intel_crtc->pipe); - - /* Filter ctl must be set before TV_WIN_SIZE */ - I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); - xsize = tv_mode->hblank_start - tv_mode->hblank_end; - if (tv_mode->progressive) - ysize = tv_mode->nbr_end + 1; - else - ysize = 2*tv_mode->nbr_end + 1; - - xpos += intel_tv->margin[TV_MARGIN_LEFT]; - ypos += intel_tv->margin[TV_MARGIN_TOP]; - xsize -= (intel_tv->margin[TV_MARGIN_LEFT] + - intel_tv->margin[TV_MARGIN_RIGHT]); - ysize -= (intel_tv->margin[TV_MARGIN_TOP] + - intel_tv->margin[TV_MARGIN_BOTTOM]); - I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos); - I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize); - - I915_WRITE(pipeconf_reg, pipeconf); - I915_WRITE(dspcntr_reg, dspcntr); - intel_flush_primary_plane(dev_priv, intel_crtc->plane); - } + + assert_pipe_disabled(dev_priv, intel_crtc->pipe); + + /* Filter ctl must be set before TV_WIN_SIZE */ + I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); + xsize = tv_mode->hblank_start - tv_mode->hblank_end; + if (tv_mode->progressive) + ysize = tv_mode->nbr_end + 1; + else + ysize = 2*tv_mode->nbr_end + 1; + + xpos += intel_tv->margin[TV_MARGIN_LEFT]; + ypos += intel_tv->margin[TV_MARGIN_TOP]; + xsize -= (intel_tv->margin[TV_MARGIN_LEFT] + + intel_tv->margin[TV_MARGIN_RIGHT]); + ysize -= (intel_tv->margin[TV_MARGIN_TOP] + + intel_tv->margin[TV_MARGIN_BOTTOM]); + I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos); + I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize); j = 0; for (i = 0; i < 60; i++) @@ -1634,7 +1632,7 @@ intel_tv_init(struct drm_device *dev) intel_encoder->compute_config = intel_tv_compute_config; intel_encoder->get_config = intel_tv_get_config; - intel_encoder->mode_set = intel_tv_mode_set; + intel_encoder->pre_enable = intel_tv_pre_enable; intel_encoder->enable = intel_enable_tv; intel_encoder->disable = intel_disable_tv; intel_encoder->get_hw_state = intel_tv_get_hw_state; diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index f729dc71d5beb0..76dc185793cebe 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -253,8 +253,7 @@ static void __vlv_force_wake_put(struct drm_i915_private *dev_priv, } -void vlv_force_wake_get(struct drm_i915_private *dev_priv, - int fw_engine) +static void vlv_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) { unsigned long irqflags; @@ -273,8 +272,7 @@ void vlv_force_wake_get(struct drm_i915_private *dev_priv, spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } -void vlv_force_wake_put(struct drm_i915_private *dev_priv, - int fw_engine) +static void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) { unsigned long irqflags; @@ -372,7 +370,7 @@ void intel_uncore_early_sanitize(struct drm_device *dev) if (HAS_FPGA_DBG_UNCLAIMED(dev)) __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM); - if (IS_HASWELL(dev) && + if ((IS_HASWELL(dev) || IS_BROADWELL(dev)) && (__raw_i915_read32(dev_priv, HSW_EDRAM_PRESENT) == 1)) { /* The docs do not explain exactly how the calculation can be * made. It is somewhat guessable, but for now, it's always @@ -486,6 +484,17 @@ void assert_force_wake_inactive(struct drm_i915_private *dev_priv) #define NEEDS_FORCE_WAKE(dev_priv, reg) \ ((reg) < 0x40000 && (reg) != FORCEWAKE) +#define FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg) \ + (((reg) >= 0x2000 && (reg) < 0x4000) ||\ + ((reg) >= 0x5000 && (reg) < 0x8000) ||\ + ((reg) >= 0xB000 && (reg) < 0x12000) ||\ + ((reg) >= 0x2E000 && (reg) < 0x30000)) + +#define FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)\ + (((reg) >= 0x12000 && (reg) < 0x14000) ||\ + ((reg) >= 0x22000 && (reg) < 0x24000) ||\ + ((reg) >= 0x30000 && (reg) < 0x40000)) + static void ilk_dummy_write(struct drm_i915_private *dev_priv) { @@ -852,12 +861,15 @@ void intel_uncore_fini(struct drm_device *dev) intel_uncore_forcewake_reset(dev, false); } +#define GEN_RANGE(l, h) GENMASK(h, l) + static const struct register_whitelist { uint64_t offset; uint32_t size; - uint32_t gen_bitmask; /* support gens, 0x10 for 4, 0x30 for 4 and 5, etc. */ + /* supported gens, 0x10 for 4, 0x30 for 4 and 5, etc. */ + uint32_t gen_bitmask; } whitelist[] = { - { RING_TIMESTAMP(RENDER_RING_BASE), 8, 0x1F0 }, + { RING_TIMESTAMP(RENDER_RING_BASE), 8, GEN_RANGE(4, 8) }, }; int i915_reg_read_ioctl(struct drm_device *dev, diff --git a/drivers/gpu/drm/mga/mga_state.c b/drivers/gpu/drm/mga/mga_state.c index 314685b7f41fc4..3cb58df5237e68 100644 --- a/drivers/gpu/drm/mga/mga_state.c +++ b/drivers/gpu/drm/mga/mga_state.c @@ -1020,7 +1020,7 @@ static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *fil switch (param->param) { case MGA_PARAM_IRQ_NR: - value = drm_dev_to_irq(dev); + value = dev->pdev->irq; break; case MGA_PARAM_CARD_TYPE: value = dev_priv->chipset; diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index 26868e5c55b076..f6b283b8375ec7 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -322,17 +322,13 @@ static void mgag200_bo_unref(struct mgag200_bo **bo) tbo = &((*bo)->bo); ttm_bo_unref(&tbo); - if (tbo == NULL) - *bo = NULL; - + *bo = NULL; } void mgag200_gem_free_object(struct drm_gem_object *obj) { struct mgag200_bo *mgag200_bo = gem_to_mga_bo(obj); - if (!mgag200_bo) - return; mgag200_bo_unref(&mgag200_bo); } diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index f9de156b9e65c9..50ec1bed5820e8 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -288,7 +288,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) } pm_runtime_get_sync(dev->dev); - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); pm_runtime_put_sync(dev->dev); if (ret < 0) { dev_err(dev->dev, "failed to install IRQ handler\n"); diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index fb84da3cb50d50..4f4c3fec6916fc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -64,12 +64,13 @@ static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - bool can_switch; - spin_lock(&dev->count_lock); - can_switch = (dev->open_count == 0); - spin_unlock(&dev->count_lock); - return can_switch; + /* + * FIXME: open_count is protected by drm_global_mutex but that would lead to + * locking inversion with the driver load path. And the access here is + * completely racy anyway. So don't bother with locking for now. + */ + return dev->open_count == 0; } static const struct vga_switcheroo_client_ops diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c index 1f1f8371a199c1..db1601fdbe2946 100644 --- a/drivers/gpu/drm/panel/panel-ld9040.c +++ b/drivers/gpu/drm/panel/panel-ld9040.c @@ -27,6 +27,7 @@ #define MCS_ELVSS_ON 0xb1 #define MCS_USER_SETTING 0xf0 #define MCS_DISPCTL 0xf2 +#define MCS_POWER_CTRL 0xf4 #define MCS_GTCON 0xf7 #define MCS_PANEL_CONDITION 0xf8 #define MCS_GAMMA_SET1 0xf9 @@ -182,6 +183,8 @@ static void ld9040_init(struct ld9040 *ctx) ld9040_dcs_write_seq_static(ctx, MCS_DISPCTL, 0x02, 0x08, 0x08, 0x10, 0x10); ld9040_dcs_write_seq_static(ctx, MCS_MANPWR, 0x04); + ld9040_dcs_write_seq_static(ctx, MCS_POWER_CTRL, + 0x0a, 0x87, 0x25, 0x6a, 0x44, 0x02, 0x88); ld9040_dcs_write_seq_static(ctx, MCS_ELVSS_ON, 0x0d, 0x00, 0x16); ld9040_dcs_write_seq_static(ctx, MCS_GTCON, 0x09, 0x00, 0x00); ld9040_brightness_set(ctx); diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index 35941d2412b828..06e57a26db7a5e 100644 --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -847,6 +847,7 @@ static void s6e8aa0_read_mtp_id(struct s6e8aa0 *ctx) if (i >= ARRAY_SIZE(s6e8aa0_variants)) { dev_err(ctx->dev, "unsupported display version %d\n", id[1]); ctx->error = -EINVAL; + return; } ctx->variant = &s6e8aa0_variants[i]; diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 41bdd174657e6e..3ab9072d362353 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -841,7 +841,7 @@ static const struct drm_connector_funcs qxl_connector_funcs = { .save = qxl_conn_save, .restore = qxl_conn_restore, .detect = qxl_conn_detect, - .fill_modes = drm_helper_probe_single_connector_modes, + .fill_modes = drm_helper_probe_single_connector_modes_nomerge, .set_property = qxl_conn_set_property, .destroy = qxl_conn_destroy, }; diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index fee8748bdca52f..6e936634d65c8d 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -214,7 +214,6 @@ static struct pci_driver qxl_pci_driver = { static struct drm_driver qxl_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, - .dev_priv_size = 0, .load = qxl_driver_load, .unload = qxl_driver_unload, diff --git a/drivers/gpu/drm/qxl/qxl_irq.c b/drivers/gpu/drm/qxl/qxl_irq.c index 28f84b4fce32fa..34d6a85e902365 100644 --- a/drivers/gpu/drm/qxl/qxl_irq.c +++ b/drivers/gpu/drm/qxl/qxl_irq.c @@ -87,7 +87,7 @@ int qxl_irq_init(struct qxl_device *qdev) atomic_set(&qdev->irq_received_cursor, 0); atomic_set(&qdev->irq_received_io_cmd, 0); qdev->irq_received_error = 0; - ret = drm_irq_install(qdev->ddev); + ret = drm_irq_install(qdev->ddev, qdev->ddev->pdev->irq); qdev->ram_header->int_mask = QXL_INTERRUPT_MASK; if (unlikely(ret != 0)) { DRM_ERROR("Failed installing irq: %d\n", ret); diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index d52c27527b9a63..71a1baeac14edc 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -109,13 +109,11 @@ static const struct vm_operations_struct *ttm_vm_ops; static int qxl_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct ttm_buffer_object *bo; - struct qxl_device *qdev; int r; bo = (struct ttm_buffer_object *)vma->vm_private_data; if (bo == NULL) return VM_FAULT_NOPAGE; - qdev = qxl_get_qdev(bo->bdev); r = ttm_vm_ops->fault(vma, vmf); return r; } @@ -162,10 +160,6 @@ static int qxl_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, struct ttm_mem_type_manager *man) { - struct qxl_device *qdev; - - qdev = qxl_get_qdev(bdev); - switch (type) { case TTM_PL_SYSTEM: /* System memory */ diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c index e806dacd452f7b..97064dd434c28f 100644 --- a/drivers/gpu/drm/r128/r128_state.c +++ b/drivers/gpu/drm/r128/r128_state.c @@ -1594,7 +1594,7 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi switch (param->param) { case R128_PARAM_IRQ_NR: - value = drm_dev_to_irq(dev); + value = dev->pdev->irq; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 0e770bbf7e29d7..c2edb2d14030ce 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1126,12 +1126,13 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero static bool radeon_switcheroo_can_switch(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - bool can_switch; - spin_lock(&dev->count_lock); - can_switch = (dev->open_count == 0); - spin_unlock(&dev->count_lock); - return can_switch; + /* + * FIXME: open_count is protected by drm_global_mutex but that would lead to + * locking inversion with the driver load path. And the access here is + * completely racy anyway. So don't bother with locking for now. + */ + return dev->open_count == 0; } static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = { diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index c00a2f58518502..15447a4119f428 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -519,7 +519,6 @@ static struct drm_driver kms_driver = { DRIVER_USE_AGP | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER, - .dev_priv_size = 0, .load = radeon_driver_load_kms, .open = radeon_driver_open_kms, .preclose = radeon_driver_preclose_kms, diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 089c9ffb0aa95e..16807afab36250 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -287,7 +287,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev) INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func); rdev->irq.installed = true; - r = drm_irq_install(rdev->ddev); + r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq); if (r) { rdev->irq.installed = false; flush_work(&rdev->hotplug_work); diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index 956ab7f14e1650..b576549fc78379 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -3054,7 +3054,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) value = 0; else - value = drm_dev_to_irq(dev); + value = dev->pdev->irq; break; case RADEON_PARAM_GART_BASE: value = dev_priv->gart_vm_start; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index c839c9c89efbf6..82c84c7fd4f6e1 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -185,7 +185,7 @@ static int shmob_drm_load(struct drm_device *dev, unsigned long flags) goto done; } - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); if (ret < 0) { dev_err(&pdev->dev, "failed to install IRQ handler\n"); goto done; diff --git a/drivers/gpu/drm/tegra/bus.c b/drivers/gpu/drm/tegra/bus.c index 71cef5c13dc81d..b3a66d65cb5356 100644 --- a/drivers/gpu/drm/tegra/bus.c +++ b/drivers/gpu/drm/tegra/bus.c @@ -12,9 +12,7 @@ static int drm_host1x_set_busid(struct drm_device *dev, struct drm_master *master) { const char *device = dev_name(dev->dev); - const char *driver = dev->driver->name; const char *bus = dev->dev->bus->name; - int length; master->unique_len = strlen(bus) + 1 + strlen(device); master->unique_size = master->unique_len; @@ -25,19 +23,10 @@ static int drm_host1x_set_busid(struct drm_device *dev, snprintf(master->unique, master->unique_len + 1, "%s:%s", bus, device); - length = strlen(driver) + 1 + master->unique_len; - - dev->devname = kmalloc(length + 1, GFP_KERNEL); - if (!dev->devname) - return -ENOMEM; - - snprintf(dev->devname, length + 1, "%s@%s", driver, master->unique); - return 0; } static struct drm_bus drm_host1x_bus = { - .bus_type = DRIVER_BUS_HOST1X, .set_busid = drm_host1x_set_busid, }; diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index edb871d7d395cb..859e424e15e519 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -29,6 +29,254 @@ static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane) return container_of(plane, struct tegra_plane, base); } +static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap) +{ + /* assume no swapping of fetched data */ + if (swap) + *swap = BYTE_SWAP_NOSWAP; + + switch (format) { + case DRM_FORMAT_XBGR8888: + return WIN_COLOR_DEPTH_R8G8B8A8; + + case DRM_FORMAT_XRGB8888: + return WIN_COLOR_DEPTH_B8G8R8A8; + + case DRM_FORMAT_RGB565: + return WIN_COLOR_DEPTH_B5G6R5; + + case DRM_FORMAT_UYVY: + return WIN_COLOR_DEPTH_YCbCr422; + + case DRM_FORMAT_YUYV: + if (swap) + *swap = BYTE_SWAP_SWAP2; + + return WIN_COLOR_DEPTH_YCbCr422; + + case DRM_FORMAT_YUV420: + return WIN_COLOR_DEPTH_YCbCr420P; + + case DRM_FORMAT_YUV422: + return WIN_COLOR_DEPTH_YCbCr422P; + + default: + break; + } + + WARN(1, "unsupported pixel format %u, using default\n", format); + return WIN_COLOR_DEPTH_B8G8R8A8; +} + +static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar) +{ + switch (format) { + case WIN_COLOR_DEPTH_YCbCr422: + case WIN_COLOR_DEPTH_YUV422: + if (planar) + *planar = false; + + return true; + + case WIN_COLOR_DEPTH_YCbCr420P: + case WIN_COLOR_DEPTH_YUV420P: + case WIN_COLOR_DEPTH_YCbCr422P: + case WIN_COLOR_DEPTH_YUV422P: + case WIN_COLOR_DEPTH_YCbCr422R: + case WIN_COLOR_DEPTH_YUV422R: + case WIN_COLOR_DEPTH_YCbCr422RA: + case WIN_COLOR_DEPTH_YUV422RA: + if (planar) + *planar = true; + + return true; + } + + return false; +} + +static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v, + unsigned int bpp) +{ + fixed20_12 outf = dfixed_init(out); + fixed20_12 inf = dfixed_init(in); + u32 dda_inc; + int max; + + if (v) + max = 15; + else { + switch (bpp) { + case 2: + max = 8; + break; + + default: + WARN_ON_ONCE(1); + /* fallthrough */ + case 4: + max = 4; + break; + } + } + + outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1)); + inf.full -= dfixed_const(1); + + dda_inc = dfixed_div(inf, outf); + dda_inc = min_t(u32, dda_inc, dfixed_const(max)); + + return dda_inc; +} + +static inline u32 compute_initial_dda(unsigned int in) +{ + fixed20_12 inf = dfixed_init(in); + return dfixed_frac(inf); +} + +static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, + const struct tegra_dc_window *window) +{ + unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp; + unsigned long value; + bool yuv, planar; + + /* + * For YUV planar modes, the number of bytes per pixel takes into + * account only the luma component and therefore is 1. + */ + yuv = tegra_dc_format_is_yuv(window->format, &planar); + if (!yuv) + bpp = window->bits_per_pixel / 8; + else + bpp = planar ? 1 : 2; + + value = WINDOW_A_SELECT << index; + tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); + + tegra_dc_writel(dc, window->format, DC_WIN_COLOR_DEPTH); + tegra_dc_writel(dc, window->swap, DC_WIN_BYTE_SWAP); + + value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x); + tegra_dc_writel(dc, value, DC_WIN_POSITION); + + value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w); + tegra_dc_writel(dc, value, DC_WIN_SIZE); + + h_offset = window->src.x * bpp; + v_offset = window->src.y; + h_size = window->src.w * bpp; + v_size = window->src.h; + + value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size); + tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE); + + /* + * For DDA computations the number of bytes per pixel for YUV planar + * modes needs to take into account all Y, U and V components. + */ + if (yuv && planar) + bpp = 2; + + h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp); + v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp); + + value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda); + tegra_dc_writel(dc, value, DC_WIN_DDA_INC); + + h_dda = compute_initial_dda(window->src.x); + v_dda = compute_initial_dda(window->src.y); + + tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA); + tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA); + + tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE); + tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE); + + tegra_dc_writel(dc, window->base[0], DC_WINBUF_START_ADDR); + + if (yuv && planar) { + tegra_dc_writel(dc, window->base[1], DC_WINBUF_START_ADDR_U); + tegra_dc_writel(dc, window->base[2], DC_WINBUF_START_ADDR_V); + value = window->stride[1] << 16 | window->stride[0]; + tegra_dc_writel(dc, value, DC_WIN_LINE_STRIDE); + } else { + tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE); + } + + if (window->bottom_up) + v_offset += window->src.h - 1; + + tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET); + tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET); + + if (window->tiled) { + value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV | + DC_WIN_BUFFER_ADDR_MODE_TILE; + } else { + value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV | + DC_WIN_BUFFER_ADDR_MODE_LINEAR; + } + + tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE); + + value = WIN_ENABLE; + + if (yuv) { + /* setup default colorspace conversion coefficients */ + tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF); + tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB); + tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR); + tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR); + tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG); + tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG); + tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB); + tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB); + + value |= CSC_ENABLE; + } else if (window->bits_per_pixel < 24) { + value |= COLOR_EXPAND; + } + + if (window->bottom_up) + value |= V_DIRECTION; + + tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); + + /* + * Disable blending and assume Window A is the bottom-most window, + * Window C is the top-most window and Window B is in the middle. + */ + tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_NOKEY); + tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_1WIN); + + switch (index) { + case 0: + tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_X); + tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y); + tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY); + break; + + case 1: + tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X); + tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y); + tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY); + break; + + case 2: + tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X); + tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_Y); + tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_3WIN_XY); + break; + } + + tegra_dc_writel(dc, WIN_A_UPDATE << index, DC_CMD_STATE_CONTROL); + tegra_dc_writel(dc, WIN_A_ACT_REQ << index, DC_CMD_STATE_CONTROL); + + return 0; +} + static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, @@ -49,7 +297,7 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, window.dst.y = crtc_y; window.dst.w = crtc_w; window.dst.h = crtc_h; - window.format = tegra_dc_format(fb->pixel_format); + window.format = tegra_dc_format(fb->pixel_format, &window.swap); window.bits_per_pixel = fb->bits_per_pixel; window.bottom_up = tegra_fb_is_bottom_up(fb); window.tiled = tegra_fb_is_tiled(fb); @@ -117,6 +365,7 @@ static const uint32_t plane_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565, DRM_FORMAT_UYVY, + DRM_FORMAT_YUYV, DRM_FORMAT_YUV420, DRM_FORMAT_YUV422, }; @@ -150,9 +399,9 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, struct drm_framebuffer *fb) { - unsigned int format = tegra_dc_format(fb->pixel_format); struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); unsigned int h_offset = 0, v_offset = 0; + unsigned int format, swap; unsigned long value; tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER); @@ -162,7 +411,10 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR); tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE); + + format = tegra_dc_format(fb->pixel_format, &swap); tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH); + tegra_dc_writel(dc, swap, DC_WIN_BYTE_SWAP); if (tegra_fb_is_tiled(fb)) { value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV | @@ -177,13 +429,13 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, /* make sure bottom-up buffers are properly displayed */ if (tegra_fb_is_bottom_up(fb)) { value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); - value |= INVERT_V; + value |= V_DIRECTION; tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); v_offset += fb->height - 1; } else { value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); - value &= ~INVERT_V; + value &= ~V_DIRECTION; tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); } @@ -334,52 +586,11 @@ static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v, - unsigned int bpp) -{ - fixed20_12 outf = dfixed_init(out); - fixed20_12 inf = dfixed_init(in); - u32 dda_inc; - int max; - - if (v) - max = 15; - else { - switch (bpp) { - case 2: - max = 8; - break; - - default: - WARN_ON_ONCE(1); - /* fallthrough */ - case 4: - max = 4; - break; - } - } - - outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1)); - inf.full -= dfixed_const(1); - - dda_inc = dfixed_div(inf, outf); - dda_inc = min_t(u32, dda_inc, dfixed_const(max)); - - return dda_inc; -} - -static inline u32 compute_initial_dda(unsigned int in) -{ - fixed20_12 inf = dfixed_init(in); - return dfixed_frac(inf); -} - static int tegra_dc_set_timings(struct tegra_dc *dc, struct drm_display_mode *mode) { - /* TODO: For HDMI compliance, h & v ref_to_sync should be set to 1 */ - unsigned int h_ref_to_sync = 0; - unsigned int v_ref_to_sync = 0; + unsigned int h_ref_to_sync = 1; + unsigned int v_ref_to_sync = 1; unsigned long value; tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS); @@ -406,13 +617,14 @@ static int tegra_dc_set_timings(struct tegra_dc *dc, } static int tegra_crtc_setup_clk(struct drm_crtc *crtc, - struct drm_display_mode *mode, - unsigned long *div) + struct drm_display_mode *mode) { - unsigned long pclk = mode->clock * 1000, rate; + unsigned long pclk = mode->clock * 1000; struct tegra_dc *dc = to_tegra_dc(crtc); struct tegra_output *output = NULL; struct drm_encoder *encoder; + unsigned int div; + u32 value; long err; list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, head) @@ -425,221 +637,23 @@ static int tegra_crtc_setup_clk(struct drm_crtc *crtc, return -ENODEV; /* - * This assumes that the display controller will divide its parent - * clock by 2 to generate the pixel clock. + * This assumes that the parent clock is pll_d_out0 or pll_d2_out + * respectively, each of which divides the base pll_d by 2. */ - err = tegra_output_setup_clock(output, dc->clk, pclk * 2); + err = tegra_output_setup_clock(output, dc->clk, pclk, &div); if (err < 0) { dev_err(dc->dev, "failed to setup clock: %ld\n", err); return err; } - rate = clk_get_rate(dc->clk); - *div = (rate * 2 / pclk) - 2; - - DRM_DEBUG_KMS("rate: %lu, div: %lu\n", rate, *div); - - return 0; -} - -static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar) -{ - switch (format) { - case WIN_COLOR_DEPTH_YCbCr422: - case WIN_COLOR_DEPTH_YUV422: - if (planar) - *planar = false; - - return true; - - case WIN_COLOR_DEPTH_YCbCr420P: - case WIN_COLOR_DEPTH_YUV420P: - case WIN_COLOR_DEPTH_YCbCr422P: - case WIN_COLOR_DEPTH_YUV422P: - case WIN_COLOR_DEPTH_YCbCr422R: - case WIN_COLOR_DEPTH_YUV422R: - case WIN_COLOR_DEPTH_YCbCr422RA: - case WIN_COLOR_DEPTH_YUV422RA: - if (planar) - *planar = true; - - return true; - } - - return false; -} - -int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, - const struct tegra_dc_window *window) -{ - unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp; - unsigned long value; - bool yuv, planar; - - /* - * For YUV planar modes, the number of bytes per pixel takes into - * account only the luma component and therefore is 1. - */ - yuv = tegra_dc_format_is_yuv(window->format, &planar); - if (!yuv) - bpp = window->bits_per_pixel / 8; - else - bpp = planar ? 1 : 2; - - value = WINDOW_A_SELECT << index; - tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); - - tegra_dc_writel(dc, window->format, DC_WIN_COLOR_DEPTH); - tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP); - - value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x); - tegra_dc_writel(dc, value, DC_WIN_POSITION); - - value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w); - tegra_dc_writel(dc, value, DC_WIN_SIZE); - - h_offset = window->src.x * bpp; - v_offset = window->src.y; - h_size = window->src.w * bpp; - v_size = window->src.h; - - value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size); - tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE); + DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk), div); - /* - * For DDA computations the number of bytes per pixel for YUV planar - * modes needs to take into account all Y, U and V components. - */ - if (yuv && planar) - bpp = 2; - - h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp); - v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp); - - value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda); - tegra_dc_writel(dc, value, DC_WIN_DDA_INC); - - h_dda = compute_initial_dda(window->src.x); - v_dda = compute_initial_dda(window->src.y); - - tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA); - tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA); - - tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE); - tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE); - - tegra_dc_writel(dc, window->base[0], DC_WINBUF_START_ADDR); - - if (yuv && planar) { - tegra_dc_writel(dc, window->base[1], DC_WINBUF_START_ADDR_U); - tegra_dc_writel(dc, window->base[2], DC_WINBUF_START_ADDR_V); - value = window->stride[1] << 16 | window->stride[0]; - tegra_dc_writel(dc, value, DC_WIN_LINE_STRIDE); - } else { - tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE); - } - - if (window->bottom_up) - v_offset += window->src.h - 1; - - tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET); - tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET); - - if (window->tiled) { - value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV | - DC_WIN_BUFFER_ADDR_MODE_TILE; - } else { - value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV | - DC_WIN_BUFFER_ADDR_MODE_LINEAR; - } - - tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE); - - value = WIN_ENABLE; - - if (yuv) { - /* setup default colorspace conversion coefficients */ - tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF); - tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB); - tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR); - tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR); - tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG); - tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG); - tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB); - tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB); - - value |= CSC_ENABLE; - } else if (window->bits_per_pixel < 24) { - value |= COLOR_EXPAND; - } - - if (window->bottom_up) - value |= INVERT_V; - - tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); - - /* - * Disable blending and assume Window A is the bottom-most window, - * Window C is the top-most window and Window B is in the middle. - */ - tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_NOKEY); - tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_1WIN); - - switch (index) { - case 0: - tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_X); - tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y); - tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY); - break; - - case 1: - tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X); - tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y); - tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY); - break; - - case 2: - tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X); - tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_Y); - tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_3WIN_XY); - break; - } - - tegra_dc_writel(dc, WIN_A_UPDATE << index, DC_CMD_STATE_CONTROL); - tegra_dc_writel(dc, WIN_A_ACT_REQ << index, DC_CMD_STATE_CONTROL); + value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1; + tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); return 0; } -unsigned int tegra_dc_format(uint32_t format) -{ - switch (format) { - case DRM_FORMAT_XBGR8888: - return WIN_COLOR_DEPTH_R8G8B8A8; - - case DRM_FORMAT_XRGB8888: - return WIN_COLOR_DEPTH_B8G8R8A8; - - case DRM_FORMAT_RGB565: - return WIN_COLOR_DEPTH_B5G6R5; - - case DRM_FORMAT_UYVY: - return WIN_COLOR_DEPTH_YCbCr422; - - case DRM_FORMAT_YUV420: - return WIN_COLOR_DEPTH_YCbCr420P; - - case DRM_FORMAT_YUV422: - return WIN_COLOR_DEPTH_YCbCr422P; - - default: - break; - } - - WARN(1, "unsupported pixel format %u, using default\n", format); - return WIN_COLOR_DEPTH_B8G8R8A8; -} - static int tegra_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted, @@ -648,12 +662,12 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, struct tegra_bo *bo = tegra_fb_get_plane(crtc->primary->fb, 0); struct tegra_dc *dc = to_tegra_dc(crtc); struct tegra_dc_window window; - unsigned long div, value; + u32 value; int err; drm_vblank_pre_modeset(crtc->dev, dc->pipe); - err = tegra_crtc_setup_clk(crtc, mode, &div); + err = tegra_crtc_setup_clk(crtc, mode); if (err) { dev_err(dc->dev, "failed to setup clock for CRTC: %d\n", err); return err; @@ -669,9 +683,6 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, tegra_dc_writel(dc, value, DC_DISP_INTERLACE_CONTROL); } - value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1; - tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); - /* setup window parameters */ memset(&window, 0, sizeof(window)); window.src.x = 0; @@ -682,7 +693,8 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, window.dst.y = 0; window.dst.w = mode->hdisplay; window.dst.h = mode->vdisplay; - window.format = tegra_dc_format(crtc->primary->fb->pixel_format); + window.format = tegra_dc_format(crtc->primary->fb->pixel_format, + &window.swap); window.bits_per_pixel = crtc->primary->fb->bits_per_pixel; window.stride[0] = crtc->primary->fb->pitches[0]; window.base[0] = bo->paddr; @@ -728,10 +740,6 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc) WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY); - value = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | - PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; - tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); - /* initialize timer */ value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) | WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20); diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index c94101494826c8..44e31aefe8999f 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -312,7 +312,8 @@ #define DC_WIN_CSC_KVB 0x618 #define DC_WIN_WIN_OPTIONS 0x700 -#define INVERT_V (1 << 2) +#define H_DIRECTION (1 << 0) +#define V_DIRECTION (1 << 2) #define COLOR_EXPAND (1 << 6) #define CSC_ENABLE (1 << 18) #define WIN_ENABLE (1 << 30) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 6f5b6e2f552e37..09ee77923d6769 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -666,6 +666,7 @@ static const struct of_device_id host1x_drm_subdevs[] = { { .compatible = "nvidia,tegra114-gr3d", }, { .compatible = "nvidia,tegra124-dc", }, { .compatible = "nvidia,tegra124-sor", }, + { .compatible = "nvidia,tegra124-hdmi", }, { /* sentinel */ } }; diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 126332c3ecbb6b..784fd5c77441b7 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -80,13 +80,13 @@ host1x_to_drm_client(struct host1x_client *client) return container_of(client, struct tegra_drm_client, base); } -extern int tegra_drm_register_client(struct tegra_drm *tegra, - struct tegra_drm_client *client); -extern int tegra_drm_unregister_client(struct tegra_drm *tegra, - struct tegra_drm_client *client); +int tegra_drm_register_client(struct tegra_drm *tegra, + struct tegra_drm_client *client); +int tegra_drm_unregister_client(struct tegra_drm *tegra, + struct tegra_drm_client *client); -extern int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm); -extern int tegra_drm_exit(struct tegra_drm *tegra); +int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm); +int tegra_drm_exit(struct tegra_drm *tegra); struct tegra_dc_soc_info; struct tegra_output; @@ -156,6 +156,7 @@ struct tegra_dc_window { } dst; unsigned int bits_per_pixel; unsigned int format; + unsigned int swap; unsigned int stride[2]; unsigned long base[3]; bool bottom_up; @@ -163,19 +164,15 @@ struct tegra_dc_window { }; /* from dc.c */ -extern unsigned int tegra_dc_format(uint32_t format); -extern int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, - const struct tegra_dc_window *window); -extern void tegra_dc_enable_vblank(struct tegra_dc *dc); -extern void tegra_dc_disable_vblank(struct tegra_dc *dc); -extern void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, - struct drm_file *file); +void tegra_dc_enable_vblank(struct tegra_dc *dc); +void tegra_dc_disable_vblank(struct tegra_dc *dc); +void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); struct tegra_output_ops { int (*enable)(struct tegra_output *output); int (*disable)(struct tegra_output *output); int (*setup_clock)(struct tegra_output *output, struct clk *clk, - unsigned long pclk); + unsigned long pclk, unsigned int *div); int (*check_mode)(struct tegra_output *output, struct drm_display_mode *mode, enum drm_mode_status *status); @@ -233,10 +230,11 @@ static inline int tegra_output_disable(struct tegra_output *output) } static inline int tegra_output_setup_clock(struct tegra_output *output, - struct clk *clk, unsigned long pclk) + struct clk *clk, unsigned long pclk, + unsigned int *div) { if (output && output->ops && output->ops->setup_clock) - return output->ops->setup_clock(output, clk, pclk); + return output->ops->setup_clock(output, clk, pclk, div); return output ? -ENOSYS : -EINVAL; } @@ -256,22 +254,20 @@ int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device); void drm_host1x_exit(struct drm_driver *driver, struct host1x_device *device); /* from rgb.c */ -extern int tegra_dc_rgb_probe(struct tegra_dc *dc); -extern int tegra_dc_rgb_remove(struct tegra_dc *dc); -extern int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc); -extern int tegra_dc_rgb_exit(struct tegra_dc *dc); +int tegra_dc_rgb_probe(struct tegra_dc *dc); +int tegra_dc_rgb_remove(struct tegra_dc *dc); +int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc); +int tegra_dc_rgb_exit(struct tegra_dc *dc); /* from output.c */ -extern int tegra_output_probe(struct tegra_output *output); -extern int tegra_output_remove(struct tegra_output *output); -extern int tegra_output_init(struct drm_device *drm, struct tegra_output *output); -extern int tegra_output_exit(struct tegra_output *output); +int tegra_output_probe(struct tegra_output *output); +int tegra_output_remove(struct tegra_output *output); +int tegra_output_init(struct drm_device *drm, struct tegra_output *output); +int tegra_output_exit(struct tegra_output *output); /* from dpaux.c */ - struct tegra_dpaux; struct drm_dp_link; -struct drm_dp_aux; struct tegra_dpaux *tegra_dpaux_find_by_of_node(struct device_node *np); enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux); @@ -288,10 +284,10 @@ struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, unsigned int index); bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer); bool tegra_fb_is_tiled(struct drm_framebuffer *framebuffer); -extern int tegra_drm_fb_init(struct drm_device *drm); -extern void tegra_drm_fb_exit(struct drm_device *drm); +int tegra_drm_fb_init(struct drm_device *drm); +void tegra_drm_fb_exit(struct drm_device *drm); #ifdef CONFIG_DRM_TEGRA_FBDEV -extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev); +void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev); #endif extern struct platform_driver tegra_dc_driver; diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 0e599f0417c068..3838575f71c64c 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -14,6 +14,8 @@ #include #include +#include + #include #include @@ -43,11 +45,15 @@ struct tegra_dsi { struct drm_minor *minor; struct dentry *debugfs; + unsigned long flags; enum mipi_dsi_pixel_format format; unsigned int lanes; struct tegra_mipi_device *mipi; struct mipi_dsi_host host; + + struct regulator *vdd; + bool enabled; }; static inline struct tegra_dsi * @@ -244,8 +250,10 @@ static int tegra_dsi_debugfs_exit(struct tegra_dsi *dsi) #define PKT_LP (1 << 30) #define NUM_PKT_SEQ 12 -/* non-burst mode with sync-end */ -static const u32 pkt_seq_vnb_syne[NUM_PKT_SEQ] = { +/* + * non-burst mode with sync pulses + */ +static const u32 pkt_seq_video_non_burst_sync_pulses[NUM_PKT_SEQ] = { [ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) | PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) | @@ -280,6 +288,36 @@ static const u32 pkt_seq_vnb_syne[NUM_PKT_SEQ] = { PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4), }; +/* + * non-burst mode with sync events + */ +static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = { + [ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) | + PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) | + PKT_LP, + [ 1] = 0, + [ 2] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | + PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) | + PKT_LP, + [ 3] = 0, + [ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | + PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) | + PKT_LP, + [ 5] = 0, + [ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | + PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) | + PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3), + [ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4), + [ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | + PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) | + PKT_LP, + [ 9] = 0, + [10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | + PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) | + PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3), + [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4), +}; + static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi) { struct mipi_dphy_timing timing; @@ -361,28 +399,70 @@ static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format, return 0; } +static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format, + enum tegra_dsi_format *fmt) +{ + switch (format) { + case MIPI_DSI_FMT_RGB888: + *fmt = TEGRA_DSI_FORMAT_24P; + break; + + case MIPI_DSI_FMT_RGB666: + *fmt = TEGRA_DSI_FORMAT_18NP; + break; + + case MIPI_DSI_FMT_RGB666_PACKED: + *fmt = TEGRA_DSI_FORMAT_18P; + break; + + case MIPI_DSI_FMT_RGB565: + *fmt = TEGRA_DSI_FORMAT_16P; + break; + + default: + return -EINVAL; + } + + return 0; +} + static int tegra_output_dsi_enable(struct tegra_output *output) { struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); struct drm_display_mode *mode = &dc->base.mode; unsigned int hact, hsw, hbp, hfp, i, mul, div; struct tegra_dsi *dsi = to_dsi(output); - /* FIXME: don't hardcode this */ - const u32 *pkt_seq = pkt_seq_vnb_syne; + enum tegra_dsi_format format; unsigned long value; + const u32 *pkt_seq; int err; + if (dsi->enabled) + return 0; + + if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { + DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n"); + pkt_seq = pkt_seq_video_non_burst_sync_pulses; + } else { + DRM_DEBUG_KMS("Non-burst video mode with sync events\n"); + pkt_seq = pkt_seq_video_non_burst_sync_events; + } + err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); if (err < 0) return err; + err = tegra_dsi_get_format(dsi->format, &format); + if (err < 0) + return err; + err = clk_enable(dsi->clk); if (err < 0) return err; reset_control_deassert(dsi->rst); - value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(dsi->format) | + value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) | DSI_CONTROL_LANES(dsi->lanes - 1) | DSI_CONTROL_SOURCE(dc->pipe); tegra_dsi_writel(dsi, value, DSI_CONTROL); @@ -454,6 +534,8 @@ static int tegra_output_dsi_enable(struct tegra_output *output) value |= DSI_POWER_CONTROL_ENABLE; tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); + dsi->enabled = true; + return 0; } @@ -463,9 +545,12 @@ static int tegra_output_dsi_disable(struct tegra_output *output) struct tegra_dsi *dsi = to_dsi(output); unsigned long value; + if (!dsi->enabled) + return 0; + /* disable DSI controller */ value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); - value &= DSI_POWER_CONTROL_ENABLE; + value &= ~DSI_POWER_CONTROL_ENABLE; tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); /* @@ -492,30 +577,44 @@ static int tegra_output_dsi_disable(struct tegra_output *output) clk_disable(dsi->clk); + dsi->enabled = false; + return 0; } static int tegra_output_dsi_setup_clock(struct tegra_output *output, - struct clk *clk, unsigned long pclk) + struct clk *clk, unsigned long pclk, + unsigned int *divp) { struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); struct drm_display_mode *mode = &dc->base.mode; unsigned int timeout, mul, div, vrefresh; struct tegra_dsi *dsi = to_dsi(output); unsigned long bclk, plld, value; - struct clk *base; int err; err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); if (err < 0) return err; + DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, dsi->lanes); vrefresh = drm_mode_vrefresh(mode); + DRM_DEBUG_KMS("vrefresh: %u\n", vrefresh); - pclk = mode->htotal * mode->vtotal * vrefresh; + /* compute byte clock */ bclk = (pclk * mul) / (div * dsi->lanes); - plld = DIV_ROUND_UP(bclk * 8, 1000000); - pclk = (plld * 1000000) / 2; + + /* + * Compute bit clock and round up to the next MHz. + */ + plld = DIV_ROUND_UP(bclk * 8, 1000000) * 1000000; + + /* + * We divide the frequency by two here, but we make up for that by + * setting the shift clock divider (further below) to half of the + * correct value. + */ + plld /= 2; err = clk_set_parent(clk, dsi->clk_parent); if (err < 0) { @@ -523,19 +622,25 @@ static int tegra_output_dsi_setup_clock(struct tegra_output *output, return err; } - base = clk_get_parent(dsi->clk_parent); - - /* - * This assumes that the parent clock is pll_d_out0 or pll_d2_out - * respectively, each of which divides the base pll_d by 2. - */ - err = clk_set_rate(base, pclk * 2); + err = clk_set_rate(dsi->clk_parent, plld); if (err < 0) { dev_err(dsi->dev, "failed to set base clock rate to %lu Hz\n", - pclk * 2); + plld); return err; } + /* + * Derive pixel clock from bit clock using the shift clock divider. + * Note that this is only half of what we would expect, but we need + * that to make up for the fact that we divided the bit clock by a + * factor of two above. + * + * It's not clear exactly why this is necessary, but the display is + * not working properly otherwise. Perhaps the PLLs cannot generate + * frequencies sufficiently high. + */ + *divp = ((8 * mul) / (div * dsi->lanes)) - 2; + /* * XXX: Move the below somewhere else so that we don't need to have * access to the vrefresh in this function? @@ -612,7 +717,6 @@ static int tegra_dsi_init(struct host1x_client *client) { struct tegra_drm *tegra = dev_get_drvdata(client->parent); struct tegra_dsi *dsi = host1x_client_to_dsi(client); - unsigned long value, i; int err; dsi->output.type = TEGRA_OUTPUT_DSI; @@ -631,40 +735,12 @@ static int tegra_dsi_init(struct host1x_client *client) dev_err(dsi->dev, "debugfs setup failed: %d\n", err); } - /* - * enable high-speed mode, checksum generation, ECC generation and - * disable raw mode - */ - value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL); - value |= DSI_HOST_CONTROL_ECC | DSI_HOST_CONTROL_CS | - DSI_HOST_CONTROL_HS; - value &= ~DSI_HOST_CONTROL_RAW; - tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); - - tegra_dsi_writel(dsi, 0, DSI_SOL_DELAY); - tegra_dsi_writel(dsi, 0, DSI_MAX_THRESHOLD); - - tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_CONTROL); - - for (i = 0; i < 8; i++) { - tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + i); - tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_8 + i); - } - - for (i = 0; i < 12; i++) - tegra_dsi_writel(dsi, 0, DSI_PKT_SEQ_0_LO + i); - - tegra_dsi_writel(dsi, 0, DSI_DCS_CMDS); - err = tegra_dsi_pad_calibrate(dsi); if (err < 0) { dev_err(dsi->dev, "MIPI calibration failed: %d\n", err); return err; } - tegra_dsi_writel(dsi, DSI_POWER_CONTROL_ENABLE, DSI_POWER_CONTROL); - usleep_range(300, 1000); - return 0; } @@ -715,66 +791,13 @@ static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi) return 0; } -static void tegra_dsi_initialize(struct tegra_dsi *dsi) -{ - unsigned int i; - - tegra_dsi_writel(dsi, 0, DSI_POWER_CONTROL); - - tegra_dsi_writel(dsi, 0, DSI_INT_ENABLE); - tegra_dsi_writel(dsi, 0, DSI_INT_STATUS); - tegra_dsi_writel(dsi, 0, DSI_INT_MASK); - - tegra_dsi_writel(dsi, 0, DSI_HOST_CONTROL); - tegra_dsi_writel(dsi, 0, DSI_CONTROL); - - tegra_dsi_writel(dsi, 0, DSI_SOL_DELAY); - tegra_dsi_writel(dsi, 0, DSI_MAX_THRESHOLD); - - tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_CONTROL); - - for (i = 0; i < 8; i++) { - tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + i); - tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_8 + i); - } - - for (i = 0; i < 12; i++) - tegra_dsi_writel(dsi, 0, DSI_PKT_SEQ_0_LO + i); - - tegra_dsi_writel(dsi, 0, DSI_DCS_CMDS); - - for (i = 0; i < 4; i++) - tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1 + i); - - tegra_dsi_writel(dsi, 0x00000000, DSI_PHY_TIMING_0); - tegra_dsi_writel(dsi, 0x00000000, DSI_PHY_TIMING_1); - tegra_dsi_writel(dsi, 0x000000ff, DSI_PHY_TIMING_2); - tegra_dsi_writel(dsi, 0x00000000, DSI_BTA_TIMING); - - tegra_dsi_writel(dsi, 0, DSI_TIMEOUT_0); - tegra_dsi_writel(dsi, 0, DSI_TIMEOUT_1); - tegra_dsi_writel(dsi, 0, DSI_TO_TALLY); - - tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0); - tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_CD); - tegra_dsi_writel(dsi, 0, DSI_PAD_CD_STATUS); - tegra_dsi_writel(dsi, 0, DSI_VIDEO_MODE_CONTROL); - tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1); - tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2); - tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3); - tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4); - - tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL); - tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START); - tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE); -} - static int tegra_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *device) { struct tegra_dsi *dsi = host_to_tegra(host); struct tegra_output *output = &dsi->output; + dsi->flags = device->mode_flags; dsi->format = device->format; dsi->lanes = device->lanes; @@ -829,6 +852,7 @@ static int tegra_dsi_probe(struct platform_device *pdev) * attaches to the DSI host, the parameters will be taken from * the attached device. */ + dsi->flags = MIPI_DSI_MODE_VIDEO; dsi->format = MIPI_DSI_FMT_RGB888; dsi->lanes = 4; @@ -872,6 +896,18 @@ static int tegra_dsi_probe(struct platform_device *pdev) return err; } + dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi"); + if (IS_ERR(dsi->vdd)) { + dev_err(&pdev->dev, "cannot get VDD supply\n"); + return PTR_ERR(dsi->vdd); + } + + err = regulator_enable(dsi->vdd); + if (err < 0) { + dev_err(&pdev->dev, "cannot enable VDD supply\n"); + return err; + } + err = tegra_dsi_setup_clocks(dsi); if (err < 0) { dev_err(&pdev->dev, "cannot setup clocks\n"); @@ -883,8 +919,6 @@ static int tegra_dsi_probe(struct platform_device *pdev) if (IS_ERR(dsi->regs)) return PTR_ERR(dsi->regs); - tegra_dsi_initialize(dsi); - dsi->mipi = tegra_mipi_request(&pdev->dev); if (IS_ERR(dsi->mipi)) return PTR_ERR(dsi->mipi); @@ -929,9 +963,11 @@ static int tegra_dsi_remove(struct platform_device *pdev) mipi_dsi_host_unregister(&dsi->host); tegra_mipi_free(dsi->mipi); + regulator_disable(dsi->vdd); clk_disable_unprepare(dsi->clk_parent); clk_disable_unprepare(dsi->clk_lp); clk_disable_unprepare(dsi->clk); + reset_control_assert(dsi->rst); err = tegra_output_remove(&dsi->output); if (err < 0) { diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h index 1db5cc24ea914c..5ce610d08d770a 100644 --- a/drivers/gpu/drm/tegra/dsi.h +++ b/drivers/gpu/drm/tegra/dsi.h @@ -117,4 +117,14 @@ #define DSI_INIT_SEQ_DATA_14 0x5e #define DSI_INIT_SEQ_DATA_15 0x5f +/* + * pixel format as used in the DSI_CONTROL_FORMAT field + */ +enum tegra_dsi_format { + TEGRA_DSI_FORMAT_16P, + TEGRA_DSI_FORMAT_18NP, + TEGRA_DSI_FORMAT_18P, + TEGRA_DSI_FORMAT_24P, +}; + #endif diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 6928015d11a49e..fec1a63d32c92a 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -42,8 +42,9 @@ struct tegra_hdmi { struct device *dev; bool enabled; - struct regulator *vdd; + struct regulator *hdmi; struct regulator *pll; + struct regulator *vdd; void __iomem *regs; unsigned int irq; @@ -317,6 +318,85 @@ static const struct tmds_config tegra114_tmds_config[] = { }, }; +static const struct tmds_config tegra124_tmds_config[] = { + { /* 480p/576p / 25.2MHz/27MHz modes */ + .pclk = 27000000, + .pll0 = SOR_PLL_ICHPMP(1) | SOR_PLL_BG_V17_S(3) | + SOR_PLL_VCOCAP(0) | SOR_PLL_RESISTORSEL, + .pll1 = SOR_PLL_LOADADJ(3) | SOR_PLL_TMDS_TERMADJ(0), + .pe_current = PE_CURRENT0(PE_CURRENT_0_mA_T114) | + PE_CURRENT1(PE_CURRENT_0_mA_T114) | + PE_CURRENT2(PE_CURRENT_0_mA_T114) | + PE_CURRENT3(PE_CURRENT_0_mA_T114), + .drive_current = + DRIVE_CURRENT_LANE0_T114(DRIVE_CURRENT_10_400_mA_T114) | + DRIVE_CURRENT_LANE1_T114(DRIVE_CURRENT_10_400_mA_T114) | + DRIVE_CURRENT_LANE2_T114(DRIVE_CURRENT_10_400_mA_T114) | + DRIVE_CURRENT_LANE3_T114(DRIVE_CURRENT_10_400_mA_T114), + .peak_current = PEAK_CURRENT_LANE0(PEAK_CURRENT_0_000_mA) | + PEAK_CURRENT_LANE1(PEAK_CURRENT_0_000_mA) | + PEAK_CURRENT_LANE2(PEAK_CURRENT_0_000_mA) | + PEAK_CURRENT_LANE3(PEAK_CURRENT_0_000_mA), + }, { /* 720p / 74.25MHz modes */ + .pclk = 74250000, + .pll0 = SOR_PLL_ICHPMP(1) | SOR_PLL_BG_V17_S(3) | + SOR_PLL_VCOCAP(1) | SOR_PLL_RESISTORSEL, + .pll1 = SOR_PLL_PE_EN | SOR_PLL_LOADADJ(3) | + SOR_PLL_TMDS_TERMADJ(0), + .pe_current = PE_CURRENT0(PE_CURRENT_15_mA_T114) | + PE_CURRENT1(PE_CURRENT_15_mA_T114) | + PE_CURRENT2(PE_CURRENT_15_mA_T114) | + PE_CURRENT3(PE_CURRENT_15_mA_T114), + .drive_current = + DRIVE_CURRENT_LANE0_T114(DRIVE_CURRENT_10_400_mA_T114) | + DRIVE_CURRENT_LANE1_T114(DRIVE_CURRENT_10_400_mA_T114) | + DRIVE_CURRENT_LANE2_T114(DRIVE_CURRENT_10_400_mA_T114) | + DRIVE_CURRENT_LANE3_T114(DRIVE_CURRENT_10_400_mA_T114), + .peak_current = PEAK_CURRENT_LANE0(PEAK_CURRENT_0_000_mA) | + PEAK_CURRENT_LANE1(PEAK_CURRENT_0_000_mA) | + PEAK_CURRENT_LANE2(PEAK_CURRENT_0_000_mA) | + PEAK_CURRENT_LANE3(PEAK_CURRENT_0_000_mA), + }, { /* 1080p / 148.5MHz modes */ + .pclk = 148500000, + .pll0 = SOR_PLL_ICHPMP(1) | SOR_PLL_BG_V17_S(3) | + SOR_PLL_VCOCAP(3) | SOR_PLL_RESISTORSEL, + .pll1 = SOR_PLL_PE_EN | SOR_PLL_LOADADJ(3) | + SOR_PLL_TMDS_TERMADJ(0), + .pe_current = PE_CURRENT0(PE_CURRENT_10_mA_T114) | + PE_CURRENT1(PE_CURRENT_10_mA_T114) | + PE_CURRENT2(PE_CURRENT_10_mA_T114) | + PE_CURRENT3(PE_CURRENT_10_mA_T114), + .drive_current = + DRIVE_CURRENT_LANE0_T114(DRIVE_CURRENT_12_400_mA_T114) | + DRIVE_CURRENT_LANE1_T114(DRIVE_CURRENT_12_400_mA_T114) | + DRIVE_CURRENT_LANE2_T114(DRIVE_CURRENT_12_400_mA_T114) | + DRIVE_CURRENT_LANE3_T114(DRIVE_CURRENT_12_400_mA_T114), + .peak_current = PEAK_CURRENT_LANE0(PEAK_CURRENT_0_000_mA) | + PEAK_CURRENT_LANE1(PEAK_CURRENT_0_000_mA) | + PEAK_CURRENT_LANE2(PEAK_CURRENT_0_000_mA) | + PEAK_CURRENT_LANE3(PEAK_CURRENT_0_000_mA), + }, { /* 225/297MHz modes */ + .pclk = UINT_MAX, + .pll0 = SOR_PLL_ICHPMP(1) | SOR_PLL_BG_V17_S(3) | + SOR_PLL_VCOCAP(0xf) | SOR_PLL_RESISTORSEL, + .pll1 = SOR_PLL_LOADADJ(3) | SOR_PLL_TMDS_TERMADJ(7) + | SOR_PLL_TMDS_TERM_ENABLE, + .pe_current = PE_CURRENT0(PE_CURRENT_0_mA_T114) | + PE_CURRENT1(PE_CURRENT_0_mA_T114) | + PE_CURRENT2(PE_CURRENT_0_mA_T114) | + PE_CURRENT3(PE_CURRENT_0_mA_T114), + .drive_current = + DRIVE_CURRENT_LANE0_T114(DRIVE_CURRENT_25_200_mA_T114) | + DRIVE_CURRENT_LANE1_T114(DRIVE_CURRENT_25_200_mA_T114) | + DRIVE_CURRENT_LANE2_T114(DRIVE_CURRENT_25_200_mA_T114) | + DRIVE_CURRENT_LANE3_T114(DRIVE_CURRENT_19_200_mA_T114), + .peak_current = PEAK_CURRENT_LANE0(PEAK_CURRENT_3_000_mA) | + PEAK_CURRENT_LANE1(PEAK_CURRENT_3_000_mA) | + PEAK_CURRENT_LANE2(PEAK_CURRENT_3_000_mA) | + PEAK_CURRENT_LANE3(PEAK_CURRENT_0_800_mA), + }, +}; + static const struct tegra_hdmi_audio_config * tegra_hdmi_get_audio_config(unsigned int audio_freq, unsigned int pclk) { @@ -716,13 +796,9 @@ static int tegra_output_hdmi_enable(struct tegra_output *output) return err; } - /* - * This assumes that the display controller will divide its parent - * clock by 2 to generate the pixel clock. - */ - err = tegra_output_setup_clock(output, hdmi->clk, pclk * 2); + err = regulator_enable(hdmi->vdd); if (err < 0) { - dev_err(hdmi->dev, "failed to setup clock: %d\n", err); + dev_err(hdmi->dev, "failed to enable VDD regulator: %d\n", err); return err; } @@ -730,7 +806,7 @@ static int tegra_output_hdmi_enable(struct tegra_output *output) if (err < 0) return err; - err = clk_enable(hdmi->clk); + err = clk_prepare_enable(hdmi->clk); if (err < 0) { dev_err(hdmi->dev, "failed to enable clock: %d\n", err); return err; @@ -740,6 +816,17 @@ static int tegra_output_hdmi_enable(struct tegra_output *output) usleep_range(1000, 2000); reset_control_deassert(hdmi->rst); + /* power up sequence */ + value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PLL0); + value &= ~SOR_PLL_PDBG; + tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_PLL0); + + usleep_range(10, 20); + + value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PLL0); + value &= ~SOR_PLL_PWR; + tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_PLL0); + tegra_dc_writel(dc, VSYNC_H_POSITION(1), DC_DISP_DISP_TIMING_OPTIONS); tegra_dc_writel(dc, DITHER_CONTROL_DISABLE | BASE_COLOR_SIZE888, @@ -838,9 +925,13 @@ static int tegra_output_hdmi_enable(struct tegra_output *output) tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_SEQ_INST(0)); tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_SEQ_INST(8)); - value = 0x1c800; + value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_CSTM); value &= ~SOR_CSTM_ROTCLK(~0); value |= SOR_CSTM_ROTCLK(2); + value |= SOR_CSTM_PLLDIV; + value &= ~SOR_CSTM_LVDS_ENABLE; + value &= ~SOR_CSTM_MODE_MASK; + value |= SOR_CSTM_MODE_TMDS; tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_CSTM); /* start SOR */ @@ -930,10 +1021,18 @@ static int tegra_output_hdmi_disable(struct tegra_output *output) * sure it's only executed when the output is attached to one. */ if (dc) { + /* + * XXX: We can't do this here because it causes HDMI to go + * into an erroneous state with the result that HDMI won't + * properly work once disabled. See also a similar symptom + * for the SOR output. + */ + /* value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL); value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE); tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); + */ value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); value &= ~DISP_CTRL_MODE_MASK; @@ -947,8 +1046,9 @@ static int tegra_output_hdmi_disable(struct tegra_output *output) tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); } + clk_disable_unprepare(hdmi->clk); reset_control_assert(hdmi->rst); - clk_disable(hdmi->clk); + regulator_disable(hdmi->vdd); regulator_disable(hdmi->pll); hdmi->enabled = false; @@ -957,10 +1057,10 @@ static int tegra_output_hdmi_disable(struct tegra_output *output) } static int tegra_output_hdmi_setup_clock(struct tegra_output *output, - struct clk *clk, unsigned long pclk) + struct clk *clk, unsigned long pclk, + unsigned int *div) { struct tegra_hdmi *hdmi = to_hdmi(output); - struct clk *base; int err; err = clk_set_parent(clk, hdmi->clk_parent); @@ -969,17 +1069,12 @@ static int tegra_output_hdmi_setup_clock(struct tegra_output *output, return err; } - base = clk_get_parent(hdmi->clk_parent); - - /* - * This assumes that the parent clock is pll_d_out0 or pll_d2_out - * respectively, each of which divides the base pll_d by 2. - */ - err = clk_set_rate(base, pclk * 2); + err = clk_set_rate(hdmi->clk_parent, pclk); if (err < 0) - dev_err(output->dev, - "failed to set base clock rate to %lu Hz\n", - pclk * 2); + dev_err(output->dev, "failed to set clock rate to %lu Hz\n", + pclk); + + *div = 0; return 0; } @@ -1017,7 +1112,7 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data) struct tegra_hdmi *hdmi = node->info_ent->data; int err; - err = clk_enable(hdmi->clk); + err = clk_prepare_enable(hdmi->clk); if (err) return err; @@ -1186,7 +1281,7 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data) #undef DUMP_REG - clk_disable(hdmi->clk); + clk_disable_unprepare(hdmi->clk); return 0; } @@ -1256,13 +1351,6 @@ static int tegra_hdmi_init(struct host1x_client *client) struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); int err; - err = regulator_enable(hdmi->vdd); - if (err < 0) { - dev_err(client->dev, "failed to enable VDD regulator: %d\n", - err); - return err; - } - hdmi->output.type = TEGRA_OUTPUT_HDMI; hdmi->output.dev = client->dev; hdmi->output.ops = &hdmi_ops; @@ -1279,6 +1367,13 @@ static int tegra_hdmi_init(struct host1x_client *client) dev_err(client->dev, "debugfs setup failed: %d\n", err); } + err = regulator_enable(hdmi->hdmi); + if (err < 0) { + dev_err(client->dev, "failed to enable HDMI regulator: %d\n", + err); + return err; + } + return 0; } @@ -1287,6 +1382,8 @@ static int tegra_hdmi_exit(struct host1x_client *client) struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); int err; + regulator_disable(hdmi->hdmi); + if (IS_ENABLED(CONFIG_DEBUG_FS)) { err = tegra_hdmi_debugfs_exit(hdmi); if (err < 0) @@ -1306,8 +1403,6 @@ static int tegra_hdmi_exit(struct host1x_client *client) return err; } - regulator_disable(hdmi->vdd); - return 0; } @@ -1340,7 +1435,16 @@ static const struct tegra_hdmi_config tegra114_hdmi_config = { .has_sor_io_peak_current = true, }; +static const struct tegra_hdmi_config tegra124_hdmi_config = { + .tmds = tegra124_tmds_config, + .num_tmds = ARRAY_SIZE(tegra124_tmds_config), + .fuse_override_offset = HDMI_NV_PDISP_SOR_PAD_CTLS0, + .fuse_override_value = 1 << 31, + .has_sor_io_peak_current = true, +}; + static const struct of_device_id tegra_hdmi_of_match[] = { + { .compatible = "nvidia,tegra124-hdmi", .data = &tegra124_hdmi_config }, { .compatible = "nvidia,tegra114-hdmi", .data = &tegra114_hdmi_config }, { .compatible = "nvidia,tegra30-hdmi", .data = &tegra30_hdmi_config }, { .compatible = "nvidia,tegra20-hdmi", .data = &tegra20_hdmi_config }, @@ -1381,28 +1485,20 @@ static int tegra_hdmi_probe(struct platform_device *pdev) return PTR_ERR(hdmi->rst); } - err = clk_prepare(hdmi->clk); - if (err < 0) - return err; - hdmi->clk_parent = devm_clk_get(&pdev->dev, "parent"); if (IS_ERR(hdmi->clk_parent)) return PTR_ERR(hdmi->clk_parent); - err = clk_prepare(hdmi->clk_parent); - if (err < 0) - return err; - err = clk_set_parent(hdmi->clk, hdmi->clk_parent); if (err < 0) { dev_err(&pdev->dev, "failed to setup clocks: %d\n", err); return err; } - hdmi->vdd = devm_regulator_get(&pdev->dev, "vdd"); - if (IS_ERR(hdmi->vdd)) { - dev_err(&pdev->dev, "failed to get VDD regulator\n"); - return PTR_ERR(hdmi->vdd); + hdmi->hdmi = devm_regulator_get(&pdev->dev, "hdmi"); + if (IS_ERR(hdmi->hdmi)) { + dev_err(&pdev->dev, "failed to get HDMI regulator\n"); + return PTR_ERR(hdmi->hdmi); } hdmi->pll = devm_regulator_get(&pdev->dev, "pll"); @@ -1411,6 +1507,12 @@ static int tegra_hdmi_probe(struct platform_device *pdev) return PTR_ERR(hdmi->pll); } + hdmi->vdd = devm_regulator_get(&pdev->dev, "vdd"); + if (IS_ERR(hdmi->vdd)) { + dev_err(&pdev->dev, "failed to get VDD regulator\n"); + return PTR_ERR(hdmi->vdd); + } + hdmi->output.dev = &pdev->dev; err = tegra_output_probe(&hdmi->output); @@ -1462,8 +1564,8 @@ static int tegra_hdmi_remove(struct platform_device *pdev) return err; } - clk_unprepare(hdmi->clk_parent); - clk_unprepare(hdmi->clk); + clk_disable_unprepare(hdmi->clk_parent); + clk_disable_unprepare(hdmi->clk); return 0; } diff --git a/drivers/gpu/drm/tegra/hdmi.h b/drivers/gpu/drm/tegra/hdmi.h index 0aebc485f7fa36..919a19df4e1b59 100644 --- a/drivers/gpu/drm/tegra/hdmi.h +++ b/drivers/gpu/drm/tegra/hdmi.h @@ -190,6 +190,11 @@ #define HDMI_NV_PDISP_SOR_CSTM 0x5a #define SOR_CSTM_ROTCLK(x) (((x) & 0xf) << 24) +#define SOR_CSTM_PLLDIV (1 << 21) +#define SOR_CSTM_LVDS_ENABLE (1 << 16) +#define SOR_CSTM_MODE_LVDS (0 << 12) +#define SOR_CSTM_MODE_TMDS (1 << 12) +#define SOR_CSTM_MODE_MASK (3 << 12) #define HDMI_NV_PDISP_SOR_LVDS 0x5b #define HDMI_NV_PDISP_SOR_CRCA 0x5c diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index 0266fb40479eae..d6af9be48f42ff 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -159,11 +159,38 @@ static int tegra_output_rgb_disable(struct tegra_output *output) } static int tegra_output_rgb_setup_clock(struct tegra_output *output, - struct clk *clk, unsigned long pclk) + struct clk *clk, unsigned long pclk, + unsigned int *div) { struct tegra_rgb *rgb = to_rgb(output); + int err; + + err = clk_set_parent(clk, rgb->clk_parent); + if (err < 0) { + dev_err(output->dev, "failed to set parent: %d\n", err); + return err; + } - return clk_set_parent(clk, rgb->clk_parent); + /* + * We may not want to change the frequency of the parent clock, since + * it may be a parent for other peripherals. This is due to the fact + * that on Tegra20 there's only a single clock dedicated to display + * (pll_d_out0), whereas later generations have a second one that can + * be used to independently drive a second output (pll_d2_out0). + * + * As a way to support multiple outputs on Tegra20 as well, pll_p is + * typically used as the parent clock for the display controllers. + * But this comes at a cost: pll_p is the parent of several other + * peripherals, so its frequency shouldn't change out of the blue. + * + * The best we can do at this point is to use the shift clock divider + * and hope that the desired frequency can be matched (or at least + * matched sufficiently close that the panel will still work). + */ + + *div = ((clk_get_rate(clk) * 2) / pclk) - 2; + + return 0; } static int tegra_output_rgb_check_mode(struct tegra_output *output, diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 49ef5729f435da..7d66f6e5391990 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -33,7 +34,10 @@ struct tegra_sor { struct tegra_dpaux *dpaux; + struct mutex lock; bool enabled; + + struct dentry *debugfs; }; static inline struct tegra_sor * @@ -296,14 +300,16 @@ static int tegra_output_sor_enable(struct tegra_output *output) unsigned int vbe, vse, hbe, hse, vbs, hbs, i; struct tegra_sor *sor = to_sor(output); unsigned long value; - int err; + int err = 0; + + mutex_lock(&sor->lock); if (sor->enabled) - return 0; + goto unlock; err = clk_prepare_enable(sor->clk); if (err < 0) - return err; + goto unlock; reset_control_deassert(sor->rst); @@ -385,7 +391,7 @@ static int tegra_output_sor_enable(struct tegra_output *output) err = tegra_io_rail_power_on(TEGRA_IO_RAIL_LVDS); if (err < 0) { dev_err(sor->dev, "failed to power on I/O rail: %d\n", err); - return err; + goto unlock; } usleep_range(5, 100); @@ -509,21 +515,21 @@ static int tegra_output_sor_enable(struct tegra_output *output) if (err < 0) { dev_err(sor->dev, "failed to probe eDP link: %d\n", err); - return err; + goto unlock; } err = drm_dp_link_power_up(aux, &link); if (err < 0) { dev_err(sor->dev, "failed to power up eDP link: %d\n", err); - return err; + goto unlock; } err = drm_dp_link_configure(aux, &link); if (err < 0) { dev_err(sor->dev, "failed to configure eDP link: %d\n", err); - return err; + goto unlock; } rate = drm_dp_link_rate_to_bw_code(link.rate); @@ -558,7 +564,7 @@ static int tegra_output_sor_enable(struct tegra_output *output) if (err < 0) { dev_err(sor->dev, "DP fast link training failed: %d\n", err); - return err; + goto unlock; } dev_dbg(sor->dev, "fast link training succeeded\n"); @@ -567,7 +573,7 @@ static int tegra_output_sor_enable(struct tegra_output *output) err = tegra_sor_power_up(sor, 250); if (err < 0) { dev_err(sor->dev, "failed to power up SOR: %d\n", err); - return err; + goto unlock; } /* start display controller in continuous mode */ @@ -632,7 +638,7 @@ static int tegra_output_sor_enable(struct tegra_output *output) err = tegra_sor_setup_pwm(sor, 250); if (err < 0) { dev_err(sor->dev, "failed to setup PWM: %d\n", err); - return err; + goto unlock; } value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); @@ -644,18 +650,20 @@ static int tegra_output_sor_enable(struct tegra_output *output) err = tegra_sor_attach(sor); if (err < 0) { dev_err(sor->dev, "failed to attach SOR: %d\n", err); - return err; + goto unlock; } err = tegra_sor_wakeup(sor); if (err < 0) { dev_err(sor->dev, "failed to enable DC: %d\n", err); - return err; + goto unlock; } sor->enabled = true; - return 0; +unlock: + mutex_unlock(&sor->lock); + return err; } static int tegra_sor_detach(struct tegra_sor *sor) @@ -783,15 +791,17 @@ static int tegra_output_sor_disable(struct tegra_output *output) struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); struct tegra_sor *sor = to_sor(output); unsigned long value; - int err; + int err = 0; + + mutex_lock(&sor->lock); if (!sor->enabled) - return 0; + goto unlock; err = tegra_sor_detach(sor); if (err < 0) { dev_err(sor->dev, "failed to detach SOR: %d\n", err); - return err; + goto unlock; } tegra_sor_writel(sor, 0, SOR_STATE_1); @@ -832,21 +842,21 @@ static int tegra_output_sor_disable(struct tegra_output *output) err = tegra_sor_power_down(sor); if (err < 0) { dev_err(sor->dev, "failed to power down SOR: %d\n", err); - return err; + goto unlock; } if (sor->dpaux) { err = tegra_dpaux_disable(sor->dpaux); if (err < 0) { dev_err(sor->dev, "failed to disable DP: %d\n", err); - return err; + goto unlock; } } err = tegra_io_rail_power_off(TEGRA_IO_RAIL_LVDS); if (err < 0) { dev_err(sor->dev, "failed to power off I/O rail: %d\n", err); - return err; + goto unlock; } reset_control_assert(sor->rst); @@ -854,17 +864,20 @@ static int tegra_output_sor_disable(struct tegra_output *output) sor->enabled = false; - return 0; +unlock: + mutex_unlock(&sor->lock); + return err; } static int tegra_output_sor_setup_clock(struct tegra_output *output, - struct clk *clk, unsigned long pclk) + struct clk *clk, unsigned long pclk, + unsigned int *div) { struct tegra_sor *sor = to_sor(output); int err; /* round to next MHz */ - pclk = DIV_ROUND_UP(pclk / 2, 1000000) * 1000000; + pclk = DIV_ROUND_UP(pclk, 1000000) * 1000000; err = clk_set_parent(clk, sor->clk_parent); if (err < 0) { @@ -874,11 +887,12 @@ static int tegra_output_sor_setup_clock(struct tegra_output *output, err = clk_set_rate(sor->clk_parent, pclk); if (err < 0) { - dev_err(sor->dev, "failed to set base clock rate to %lu Hz\n", - pclk * 2); + dev_err(sor->dev, "failed to set clock rate to %lu Hz\n", pclk); return err; } + *div = 0; + return 0; } @@ -914,6 +928,120 @@ static const struct tegra_output_ops sor_ops = { .detect = tegra_output_sor_detect, }; +static int tegra_sor_crc_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + + return 0; +} + +static int tegra_sor_crc_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout) +{ + u32 value; + + timeout = jiffies + msecs_to_jiffies(timeout); + + while (time_before(jiffies, timeout)) { + value = tegra_sor_readl(sor, SOR_CRC_A); + if (value & SOR_CRC_A_VALID) + return 0; + + usleep_range(100, 200); + } + + return -ETIMEDOUT; +} + +static ssize_t tegra_sor_crc_read(struct file *file, char __user *buffer, + size_t size, loff_t *ppos) +{ + struct tegra_sor *sor = file->private_data; + ssize_t num, err; + char buf[10]; + u32 value; + + mutex_lock(&sor->lock); + + if (!sor->enabled) { + err = -EAGAIN; + goto unlock; + } + + value = tegra_sor_readl(sor, SOR_STATE_1); + value &= ~SOR_STATE_ASY_CRC_MODE_MASK; + tegra_sor_writel(sor, value, SOR_STATE_1); + + value = tegra_sor_readl(sor, SOR_CRC_CNTRL); + value |= SOR_CRC_CNTRL_ENABLE; + tegra_sor_writel(sor, value, SOR_CRC_CNTRL); + + value = tegra_sor_readl(sor, SOR_TEST); + value &= ~SOR_TEST_CRC_POST_SERIALIZE; + tegra_sor_writel(sor, value, SOR_TEST); + + err = tegra_sor_crc_wait(sor, 100); + if (err < 0) + goto unlock; + + tegra_sor_writel(sor, SOR_CRC_A_RESET, SOR_CRC_A); + value = tegra_sor_readl(sor, SOR_CRC_B); + + num = scnprintf(buf, sizeof(buf), "%08x\n", value); + + err = simple_read_from_buffer(buffer, size, ppos, buf, num); + +unlock: + mutex_unlock(&sor->lock); + return err; +} + +static const struct file_operations tegra_sor_crc_fops = { + .owner = THIS_MODULE, + .open = tegra_sor_crc_open, + .read = tegra_sor_crc_read, + .release = tegra_sor_crc_release, +}; + +static int tegra_sor_debugfs_init(struct tegra_sor *sor, struct dentry *root) +{ + struct dentry *entry; + int err = 0; + + sor->debugfs = debugfs_create_dir("sor", root); + if (!sor->debugfs) + return -ENOMEM; + + entry = debugfs_create_file("crc", 0644, sor->debugfs, sor, + &tegra_sor_crc_fops); + if (!entry) { + dev_err(sor->dev, + "cannot create /sys/kernel/debug/dri/%s/sor/crc\n", + root->d_name.name); + err = -ENOMEM; + goto remove; + } + + return err; + +remove: + debugfs_remove(sor->debugfs); + sor->debugfs = NULL; + return err; +} + +static int tegra_sor_debugfs_exit(struct tegra_sor *sor) +{ + debugfs_remove(sor->debugfs); + sor->debugfs = NULL; + + return 0; +} + static int tegra_sor_init(struct host1x_client *client) { struct tegra_drm *tegra = dev_get_drvdata(client->parent); @@ -934,6 +1062,14 @@ static int tegra_sor_init(struct host1x_client *client) return err; } + if (IS_ENABLED(CONFIG_DEBUG_FS)) { + struct dentry *root = tegra->drm->primary->debugfs_root; + + err = tegra_sor_debugfs_init(sor, root); + if (err < 0) + dev_err(sor->dev, "debugfs setup failed: %d\n", err); + } + if (sor->dpaux) { err = tegra_dpaux_attach(sor->dpaux, &sor->output); if (err < 0) { @@ -964,6 +1100,12 @@ static int tegra_sor_exit(struct host1x_client *client) } } + if (IS_ENABLED(CONFIG_DEBUG_FS)) { + err = tegra_sor_debugfs_exit(sor); + if (err < 0) + dev_err(sor->dev, "debugfs cleanup failed: %d\n", err); + } + err = tegra_output_exit(&sor->output); if (err < 0) { dev_err(sor->dev, "output cleanup failed: %d\n", err); @@ -1045,6 +1187,8 @@ static int tegra_sor_probe(struct platform_device *pdev) sor->client.ops = &sor_client_ops; sor->client.dev = &pdev->dev; + mutex_init(&sor->lock); + err = host1x_client_register(&sor->client); if (err < 0) { dev_err(&pdev->dev, "failed to register host1x client: %d\n", diff --git a/drivers/gpu/drm/tegra/sor.h b/drivers/gpu/drm/tegra/sor.h index f4156d54cd058d..a5f8853fedb5aa 100644 --- a/drivers/gpu/drm/tegra/sor.h +++ b/drivers/gpu/drm/tegra/sor.h @@ -47,6 +47,7 @@ #define SOR_HEAD_STATE_4(x) (0x0d + (x)) #define SOR_HEAD_STATE_5(x) (0x0f + (x)) #define SOR_CRC_CNTRL 0x11 +#define SOR_CRC_CNTRL_ENABLE (1 << 0) #define SOR_DP_DEBUG_MVID 0x12 #define SOR_CLK_CNTRL 0x13 @@ -69,6 +70,7 @@ #define SOR_PWR_NORMAL_STATE_PU (1 << 0) #define SOR_TEST 0x16 +#define SOR_TEST_CRC_POST_SERIALIZE (1 << 23) #define SOR_TEST_ATTACHED (1 << 10) #define SOR_TEST_HEAD_MODE_MASK (3 << 8) #define SOR_TEST_HEAD_MODE_AWAKE (2 << 8) @@ -115,6 +117,8 @@ #define SOR_LVDS 0x1c #define SOR_CRC_A 0x1d +#define SOR_CRC_A_VALID (1 << 0) +#define SOR_CRC_A_RESET (1 << 0) #define SOR_CRC_B 0x1e #define SOR_BLANK 0x1f #define SOR_SEQ_CTL 0x20 diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 171a8203892ce1..b20b69488dc9b2 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -268,7 +268,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) } pm_runtime_get_sync(dev->dev); - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); pm_runtime_put_sync(dev->dev); if (ret < 0) { dev_err(dev->dev, "failed to install IRQ handler\n"); diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index f5ae57406f3447..e1038a945f40c6 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -294,6 +294,7 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags) dev->dev_private = udl; if (!udl_parse_vendor_descriptor(dev, dev->usbdev)) { + ret = -ENODEV; DRM_ERROR("firmware not recognized. Assume incompatible device\n"); goto err; } diff --git a/drivers/gpu/drm/via/via_mm.c b/drivers/gpu/drm/via/via_mm.c index 92788910548349..d70b1e1544bf68 100644 --- a/drivers/gpu/drm/via/via_mm.c +++ b/drivers/gpu/drm/via/via_mm.c @@ -79,7 +79,7 @@ int via_final_context(struct drm_device *dev, int context) /* Linux specific until context tracking code gets ported to BSD */ /* Last context, perform cleanup */ - if (list_is_singular(&dev->ctxlist) && dev->dev_private) { + if (list_is_singular(&dev->ctxlist)) { DRM_DEBUG("Last Context\n"); drm_irq_uninstall(dev); via_cleanup_futex(dev_priv); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 4a223bbea3b34e..6bdd15eea7e85e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -806,7 +806,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) } if (dev_priv->capabilities & SVGA_CAP_IRQMASK) { - ret = drm_irq_install(dev); + ret = drm_irq_install(dev, dev->pdev->irq); if (ret != 0) { DRM_ERROR("Failed installing irq: %d\n", ret); goto out_no_irq; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index a2dde5ad81385b..e7199b454ca055 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2001,7 +2001,7 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, if (du->pref_mode) list_move(&du->pref_mode->head, &connector->probed_modes); - drm_mode_connector_list_update(connector); + drm_mode_connector_list_update(connector, true); return 1; } diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7af9d0b5dea16f..762f15d6ed88bc 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -657,6 +657,14 @@ config HID_SUNPLUS ---help--- Support for Sunplus wireless desktop. +config HID_RMI + tristate "Synaptics RMI4 device support" + depends on HID + ---help--- + Support for Synaptics RMI4 touchpads. + Say Y here if you have a Synaptics RMI4 touchpads over i2c-hid or usbhid + and want support for its special functionalities. + config HID_GREENASIA tristate "GreenAsia (Product ID 0x12) game controller support" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index fc712dde02a48f..a6fa6baf368e49 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -97,6 +97,7 @@ obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \ hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.o \ hid-roccat-lua.o hid-roccat-pyra.o hid-roccat-ryos.o hid-roccat-savu.o +obj-$(CONFIG_HID_RMI) += hid-rmi.o obj-$(CONFIG_HID_SAITEK) += hid-saitek.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index da52279de93965..e0f67538ee7a5c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1884,6 +1884,8 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, HID_ANY_ID) }, + { HID_I2C_DEVICE(USB_VENDOR_ID_SYNAPTICS, HID_ANY_ID) }, { HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 53b771d5683c68..941ab3c287ec8f 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -855,6 +855,16 @@ static const char *keys[KEY_MAX + 1] = { [KEY_KBDILLUMDOWN] = "KbdIlluminationDown", [KEY_KBDILLUMUP] = "KbdIlluminationUp", [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", + [KEY_BUTTONCONFIG] = "ButtonConfig", + [KEY_TASKMANAGER] = "TaskManager", + [KEY_JOURNAL] = "Journal", + [KEY_CONTROLPANEL] = "ControlPanel", + [KEY_APPSELECT] = "AppSelect", + [KEY_SCREENSAVER] = "ScreenSaver", + [KEY_VOICECOMMAND] = "VoiceCommand", + [KEY_BRIGHTNESS_MIN] = "BrightnessMin", + [KEY_BRIGHTNESS_MAX] = "BrightnessMax", + [KEY_BRIGHTNESS_AUTO] = "BrightnessAuto", }; static const char *relatives[REL_MAX + 1] = { diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index e7e8b19a928433..9f2076acffb1d4 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -721,6 +721,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x06c: map_key_clear(KEY_YELLOW); break; case 0x06d: map_key_clear(KEY_ZOOM); break; + case 0x06f: map_key_clear(KEY_BRIGHTNESSUP); break; + case 0x070: map_key_clear(KEY_BRIGHTNESSDOWN); break; + case 0x072: map_key_clear(KEY_BRIGHTNESS_TOGGLE); break; + case 0x073: map_key_clear(KEY_BRIGHTNESS_MIN); break; + case 0x074: map_key_clear(KEY_BRIGHTNESS_MAX); break; + case 0x075: map_key_clear(KEY_BRIGHTNESS_AUTO); break; + case 0x082: map_key_clear(KEY_VIDEO_NEXT); break; case 0x083: map_key_clear(KEY_LAST); break; case 0x084: map_key_clear(KEY_ENTER); break; @@ -761,6 +768,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0bf: map_key_clear(KEY_SLOW); break; case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break; + case 0x0cf: map_key_clear(KEY_VOICECOMMAND); break; case 0x0e0: map_abs_clear(ABS_VOLUME); break; case 0x0e2: map_key_clear(KEY_MUTE); break; case 0x0e5: map_key_clear(KEY_BASSBOOST); break; @@ -768,6 +776,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; case 0x0f5: map_key_clear(KEY_SLOW); break; + case 0x181: map_key_clear(KEY_BUTTONCONFIG); break; case 0x182: map_key_clear(KEY_BOOKMARKS); break; case 0x183: map_key_clear(KEY_CONFIG); break; case 0x184: map_key_clear(KEY_WORDPROCESSOR); break; @@ -781,6 +790,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x18c: map_key_clear(KEY_VOICEMAIL); break; case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break; case 0x18e: map_key_clear(KEY_CALENDAR); break; + case 0x18f: map_key_clear(KEY_TASKMANAGER); break; + case 0x190: map_key_clear(KEY_JOURNAL); break; case 0x191: map_key_clear(KEY_FINANCE); break; case 0x192: map_key_clear(KEY_CALC); break; case 0x193: map_key_clear(KEY_PLAYER); break; @@ -789,12 +800,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x199: map_key_clear(KEY_CHAT); break; case 0x19c: map_key_clear(KEY_LOGOFF); break; case 0x19e: map_key_clear(KEY_COFFEE); break; + case 0x19f: map_key_clear(KEY_CONTROLPANEL); break; + case 0x1a2: map_key_clear(KEY_APPSELECT); break; case 0x1a3: map_key_clear(KEY_NEXT); break; case 0x1a4: map_key_clear(KEY_PREVIOUS); break; case 0x1a6: map_key_clear(KEY_HELP); break; case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; case 0x1ab: map_key_clear(KEY_SPELLCHECK); break; case 0x1ae: map_key_clear(KEY_KEYBOARD); break; + case 0x1b1: map_key_clear(KEY_SCREENSAVER); break; case 0x1b4: map_key_clear(KEY_FILE); break; case 0x1b6: map_key_clear(KEY_IMAGES); break; case 0x1b7: map_key_clear(KEY_AUDIO); break; diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c new file mode 100644 index 00000000000000..7da9509894de68 --- /dev/null +++ b/drivers/hid/hid-rmi.c @@ -0,0 +1,888 @@ +/* + * Copyright (c) 2013 Andrew Duggan + * Copyright (c) 2013 Synaptics Incorporated + * Copyright (c) 2014 Benjamin Tissoires + * Copyright (c) 2014 Red Hat, 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 +#include "hid-ids.h" + +#define RMI_MOUSE_REPORT_ID 0x01 /* Mouse emulation Report */ +#define RMI_WRITE_REPORT_ID 0x09 /* Output Report */ +#define RMI_READ_ADDR_REPORT_ID 0x0a /* Output Report */ +#define RMI_READ_DATA_REPORT_ID 0x0b /* Input Report */ +#define RMI_ATTN_REPORT_ID 0x0c /* Input Report */ +#define RMI_SET_RMI_MODE_REPORT_ID 0x0f /* Feature Report */ + +/* flags */ +#define RMI_READ_REQUEST_PENDING BIT(0) +#define RMI_READ_DATA_PENDING BIT(1) +#define RMI_STARTED BIT(2) + +enum rmi_mode_type { + RMI_MODE_OFF = 0, + RMI_MODE_ATTN_REPORTS = 1, + RMI_MODE_NO_PACKED_ATTN_REPORTS = 2, +}; + +struct rmi_function { + unsigned page; /* page of the function */ + u16 query_base_addr; /* base address for queries */ + u16 command_base_addr; /* base address for commands */ + u16 control_base_addr; /* base address for controls */ + u16 data_base_addr; /* base address for datas */ + unsigned int interrupt_base; /* cross-function interrupt number + * (uniq in the device)*/ + unsigned int interrupt_count; /* number of interrupts */ + unsigned int report_size; /* size of a report */ + unsigned long irq_mask; /* mask of the interrupts + * (to be applied against ATTN IRQ) */ +}; + +/** + * struct rmi_data - stores information for hid communication + * + * @page_mutex: Locks current page to avoid changing pages in unexpected ways. + * @page: Keeps track of the current virtual page + * + * @wait: Used for waiting for read data + * + * @writeReport: output buffer when writing RMI registers + * @readReport: input buffer when reading RMI registers + * + * @input_report_size: size of an input report (advertised by HID) + * @output_report_size: size of an output report (advertised by HID) + * + * @flags: flags for the current device (started, reading, etc...) + * + * @f11: placeholder of internal RMI function F11 description + * @f30: placeholder of internal RMI function F30 description + * + * @max_fingers: maximum finger count reported by the device + * @max_x: maximum x value reported by the device + * @max_y: maximum y value reported by the device + * + * @gpio_led_count: count of GPIOs + LEDs reported by F30 + * @button_count: actual physical buttons count + * @button_mask: button mask used to decode GPIO ATTN reports + * @button_state_mask: pull state of the buttons + * + * @input: pointer to the kernel input device + * + * @reset_work: worker which will be called in case of a mouse report + * @hdev: pointer to the struct hid_device + */ +struct rmi_data { + struct mutex page_mutex; + int page; + + wait_queue_head_t wait; + + u8 *writeReport; + u8 *readReport; + + int input_report_size; + int output_report_size; + + unsigned long flags; + + struct rmi_function f11; + struct rmi_function f30; + + unsigned int max_fingers; + unsigned int max_x; + unsigned int max_y; + unsigned int x_size_mm; + unsigned int y_size_mm; + + unsigned int gpio_led_count; + unsigned int button_count; + unsigned long button_mask; + unsigned long button_state_mask; + + struct input_dev *input; + + struct work_struct reset_work; + struct hid_device *hdev; +}; + +#define RMI_PAGE(addr) (((addr) >> 8) & 0xff) + +static int rmi_write_report(struct hid_device *hdev, u8 *report, int len); + +/** + * rmi_set_page - Set RMI page + * @hdev: The pointer to the hid_device struct + * @page: The new page address. + * + * RMI devices have 16-bit addressing, but some of the physical + * implementations (like SMBus) only have 8-bit addressing. So RMI implements + * a page address at 0xff of every page so we can reliable page addresses + * every 256 registers. + * + * The page_mutex lock must be held when this function is entered. + * + * Returns zero on success, non-zero on failure. + */ +static int rmi_set_page(struct hid_device *hdev, u8 page) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + int retval; + + data->writeReport[0] = RMI_WRITE_REPORT_ID; + data->writeReport[1] = 1; + data->writeReport[2] = 0xFF; + data->writeReport[4] = page; + + retval = rmi_write_report(hdev, data->writeReport, + data->output_report_size); + if (retval != data->output_report_size) { + dev_err(&hdev->dev, + "%s: set page failed: %d.", __func__, retval); + return retval; + } + + data->page = page; + return 0; +} + +static int rmi_set_mode(struct hid_device *hdev, u8 mode) +{ + int ret; + u8 txbuf[2] = {RMI_SET_RMI_MODE_REPORT_ID, mode}; + + ret = hid_hw_raw_request(hdev, RMI_SET_RMI_MODE_REPORT_ID, txbuf, + sizeof(txbuf), HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + if (ret < 0) { + dev_err(&hdev->dev, "unable to set rmi mode to %d (%d)\n", mode, + ret); + return ret; + } + + return 0; +} + +static int rmi_write_report(struct hid_device *hdev, u8 *report, int len) +{ + int ret; + + ret = hid_hw_output_report(hdev, (void *)report, len); + if (ret < 0) { + dev_err(&hdev->dev, "failed to write hid report (%d)\n", ret); + return ret; + } + + return ret; +} + +static int rmi_read_block(struct hid_device *hdev, u16 addr, void *buf, + const int len) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + int bytes_read; + int bytes_needed; + int retries; + int read_input_count; + + mutex_lock(&data->page_mutex); + + if (RMI_PAGE(addr) != data->page) { + ret = rmi_set_page(hdev, RMI_PAGE(addr)); + if (ret < 0) + goto exit; + } + + for (retries = 5; retries > 0; retries--) { + data->writeReport[0] = RMI_READ_ADDR_REPORT_ID; + data->writeReport[1] = 0; /* old 1 byte read count */ + data->writeReport[2] = addr & 0xFF; + data->writeReport[3] = (addr >> 8) & 0xFF; + data->writeReport[4] = len & 0xFF; + data->writeReport[5] = (len >> 8) & 0xFF; + + set_bit(RMI_READ_REQUEST_PENDING, &data->flags); + + ret = rmi_write_report(hdev, data->writeReport, + data->output_report_size); + if (ret != data->output_report_size) { + clear_bit(RMI_READ_REQUEST_PENDING, &data->flags); + dev_err(&hdev->dev, + "failed to write request output report (%d)\n", + ret); + goto exit; + } + + bytes_read = 0; + bytes_needed = len; + while (bytes_read < len) { + if (!wait_event_timeout(data->wait, + test_bit(RMI_READ_DATA_PENDING, &data->flags), + msecs_to_jiffies(1000))) { + hid_warn(hdev, "%s: timeout elapsed\n", + __func__); + ret = -EAGAIN; + break; + } + + read_input_count = data->readReport[1]; + memcpy(buf + bytes_read, &data->readReport[2], + read_input_count < bytes_needed ? + read_input_count : bytes_needed); + + bytes_read += read_input_count; + bytes_needed -= read_input_count; + clear_bit(RMI_READ_DATA_PENDING, &data->flags); + } + + if (ret >= 0) { + ret = 0; + break; + } + } + +exit: + clear_bit(RMI_READ_REQUEST_PENDING, &data->flags); + mutex_unlock(&data->page_mutex); + return ret; +} + +static inline int rmi_read(struct hid_device *hdev, u16 addr, void *buf) +{ + return rmi_read_block(hdev, addr, buf, 1); +} + +static void rmi_f11_process_touch(struct rmi_data *hdata, int slot, + u8 finger_state, u8 *touch_data) +{ + int x, y, wx, wy; + int wide, major, minor; + int z; + + input_mt_slot(hdata->input, slot); + input_mt_report_slot_state(hdata->input, MT_TOOL_FINGER, + finger_state == 0x01); + if (finger_state == 0x01) { + x = (touch_data[0] << 4) | (touch_data[2] & 0x07); + y = (touch_data[1] << 4) | (touch_data[2] >> 4); + wx = touch_data[3] & 0x07; + wy = touch_data[3] >> 4; + wide = (wx > wy); + major = max(wx, wy); + minor = min(wx, wy); + z = touch_data[4]; + + /* y is inverted */ + y = hdata->max_y - y; + + input_event(hdata->input, EV_ABS, ABS_MT_POSITION_X, x); + input_event(hdata->input, EV_ABS, ABS_MT_POSITION_Y, y); + input_event(hdata->input, EV_ABS, ABS_MT_ORIENTATION, wide); + input_event(hdata->input, EV_ABS, ABS_MT_PRESSURE, z); + input_event(hdata->input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); + input_event(hdata->input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); + } +} + +static void rmi_reset_work(struct work_struct *work) +{ + struct rmi_data *hdata = container_of(work, struct rmi_data, + reset_work); + + /* switch the device to RMI if we receive a generic mouse report */ + rmi_set_mode(hdata->hdev, RMI_MODE_ATTN_REPORTS); +} + +static inline int rmi_schedule_reset(struct hid_device *hdev) +{ + struct rmi_data *hdata = hid_get_drvdata(hdev); + return schedule_work(&hdata->reset_work); +} + +static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data, + int size) +{ + struct rmi_data *hdata = hid_get_drvdata(hdev); + int offset; + int i; + + if (size < hdata->f11.report_size) + return 0; + + if (!(irq & hdata->f11.irq_mask)) + return 0; + + offset = (hdata->max_fingers >> 2) + 1; + for (i = 0; i < hdata->max_fingers; i++) { + int fs_byte_position = i >> 2; + int fs_bit_position = (i & 0x3) << 1; + int finger_state = (data[fs_byte_position] >> fs_bit_position) & + 0x03; + + rmi_f11_process_touch(hdata, i, finger_state, + &data[offset + 5 * i]); + } + input_mt_sync_frame(hdata->input); + input_sync(hdata->input); + return hdata->f11.report_size; +} + +static int rmi_f30_input_event(struct hid_device *hdev, u8 irq, u8 *data, + int size) +{ + struct rmi_data *hdata = hid_get_drvdata(hdev); + int i; + int button = 0; + bool value; + + if (!(irq & hdata->f30.irq_mask)) + return 0; + + for (i = 0; i < hdata->gpio_led_count; i++) { + if (test_bit(i, &hdata->button_mask)) { + value = (data[i / 8] >> (i & 0x07)) & BIT(0); + if (test_bit(i, &hdata->button_state_mask)) + value = !value; + input_event(hdata->input, EV_KEY, BTN_LEFT + button++, + value); + } + } + return hdata->f30.report_size; +} + +static int rmi_input_event(struct hid_device *hdev, u8 *data, int size) +{ + struct rmi_data *hdata = hid_get_drvdata(hdev); + unsigned long irq_mask = 0; + unsigned index = 2; + + if (!(test_bit(RMI_STARTED, &hdata->flags))) + return 0; + + irq_mask |= hdata->f11.irq_mask; + irq_mask |= hdata->f30.irq_mask; + + if (data[1] & ~irq_mask) + hid_warn(hdev, "unknown intr source:%02lx %s:%d\n", + data[1] & ~irq_mask, __FILE__, __LINE__); + + if (hdata->f11.interrupt_base < hdata->f30.interrupt_base) { + index += rmi_f11_input_event(hdev, data[1], &data[index], + size - index); + index += rmi_f30_input_event(hdev, data[1], &data[index], + size - index); + } else { + index += rmi_f30_input_event(hdev, data[1], &data[index], + size - index); + index += rmi_f11_input_event(hdev, data[1], &data[index], + size - index); + } + + return 1; +} + +static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size) +{ + struct rmi_data *hdata = hid_get_drvdata(hdev); + + if (!test_bit(RMI_READ_REQUEST_PENDING, &hdata->flags)) { + hid_err(hdev, "no read request pending\n"); + return 0; + } + + memcpy(hdata->readReport, data, size < hdata->input_report_size ? + size : hdata->input_report_size); + set_bit(RMI_READ_DATA_PENDING, &hdata->flags); + wake_up(&hdata->wait); + + return 1; +} + +static int rmi_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) +{ + switch (data[0]) { + case RMI_READ_DATA_REPORT_ID: + return rmi_read_data_event(hdev, data, size); + case RMI_ATTN_REPORT_ID: + return rmi_input_event(hdev, data, size); + case RMI_MOUSE_REPORT_ID: + rmi_schedule_reset(hdev); + break; + } + + return 0; +} + +static int rmi_post_reset(struct hid_device *hdev) +{ + return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); +} + +static int rmi_post_resume(struct hid_device *hdev) +{ + return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); +} + +#define RMI4_MAX_PAGE 0xff +#define RMI4_PAGE_SIZE 0x0100 + +#define PDT_START_SCAN_LOCATION 0x00e9 +#define PDT_END_SCAN_LOCATION 0x0005 +#define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff) + +struct pdt_entry { + u8 query_base_addr:8; + u8 command_base_addr:8; + u8 control_base_addr:8; + u8 data_base_addr:8; + u8 interrupt_source_count:3; + u8 bits3and4:2; + u8 function_version:2; + u8 bit7:1; + u8 function_number:8; +} __attribute__((__packed__)); + +static inline unsigned long rmi_gen_mask(unsigned irq_base, unsigned irq_count) +{ + return GENMASK(irq_count + irq_base - 1, irq_base); +} + +static void rmi_register_function(struct rmi_data *data, + struct pdt_entry *pdt_entry, int page, unsigned interrupt_count) +{ + struct rmi_function *f = NULL; + u16 page_base = page << 8; + + switch (pdt_entry->function_number) { + case 0x11: + f = &data->f11; + break; + case 0x30: + f = &data->f30; + break; + } + + if (f) { + f->page = page; + f->query_base_addr = page_base | pdt_entry->query_base_addr; + f->command_base_addr = page_base | pdt_entry->command_base_addr; + f->control_base_addr = page_base | pdt_entry->control_base_addr; + f->data_base_addr = page_base | pdt_entry->data_base_addr; + f->interrupt_base = interrupt_count; + f->interrupt_count = pdt_entry->interrupt_source_count; + f->irq_mask = rmi_gen_mask(f->interrupt_base, + f->interrupt_count); + } +} + +static int rmi_scan_pdt(struct hid_device *hdev) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + struct pdt_entry entry; + int page; + bool page_has_function; + int i; + int retval; + int interrupt = 0; + u16 page_start, pdt_start , pdt_end; + + hid_info(hdev, "Scanning PDT...\n"); + + for (page = 0; (page <= RMI4_MAX_PAGE); page++) { + page_start = RMI4_PAGE_SIZE * page; + pdt_start = page_start + PDT_START_SCAN_LOCATION; + pdt_end = page_start + PDT_END_SCAN_LOCATION; + + page_has_function = false; + for (i = pdt_start; i >= pdt_end; i -= sizeof(entry)) { + retval = rmi_read_block(hdev, i, &entry, sizeof(entry)); + if (retval) { + hid_err(hdev, + "Read of PDT entry at %#06x failed.\n", + i); + goto error_exit; + } + + if (RMI4_END_OF_PDT(entry.function_number)) + break; + + page_has_function = true; + + hid_info(hdev, "Found F%02X on page %#04x\n", + entry.function_number, page); + + rmi_register_function(data, &entry, page, interrupt); + interrupt += entry.interrupt_source_count; + } + + if (!page_has_function) + break; + } + + hid_info(hdev, "%s: Done with PDT scan.\n", __func__); + retval = 0; + +error_exit: + return retval; +} + +static int rmi_populate_f11(struct hid_device *hdev) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + u8 buf[20]; + int ret; + bool has_query12; + bool has_physical_props; + unsigned x_size, y_size; + + if (!data->f11.query_base_addr) { + hid_err(hdev, "No 2D sensor found, giving up.\n"); + return -ENODEV; + } + + /* query 0 contains some useful information */ + ret = rmi_read(hdev, data->f11.query_base_addr, buf); + if (ret) { + hid_err(hdev, "can not get query 0: %d.\n", ret); + return ret; + } + has_query12 = !!(buf[0] & BIT(5)); + + /* query 1 to get the max number of fingers */ + ret = rmi_read(hdev, data->f11.query_base_addr + 1, buf); + if (ret) { + hid_err(hdev, "can not get NumberOfFingers: %d.\n", ret); + return ret; + } + data->max_fingers = (buf[0] & 0x07) + 1; + if (data->max_fingers > 5) + data->max_fingers = 10; + + data->f11.report_size = data->max_fingers * 5 + + DIV_ROUND_UP(data->max_fingers, 4); + + if (!(buf[0] & BIT(4))) { + hid_err(hdev, "No absolute events, giving up.\n"); + return -ENODEV; + } + + /* + * query 12 to know if the physical properties are reported + * (query 12 is at offset 10 for HID devices) + */ + if (has_query12) { + ret = rmi_read(hdev, data->f11.query_base_addr + 10, buf); + if (ret) { + hid_err(hdev, "can not get query 12: %d.\n", ret); + return ret; + } + has_physical_props = !!(buf[0] & BIT(5)); + + if (has_physical_props) { + ret = rmi_read_block(hdev, + data->f11.query_base_addr + 11, buf, 4); + if (ret) { + hid_err(hdev, "can not read query 15-18: %d.\n", + ret); + return ret; + } + + x_size = buf[0] | (buf[1] << 8); + y_size = buf[2] | (buf[3] << 8); + + data->x_size_mm = DIV_ROUND_CLOSEST(x_size, 10); + data->y_size_mm = DIV_ROUND_CLOSEST(y_size, 10); + + hid_info(hdev, "%s: size in mm: %d x %d\n", + __func__, data->x_size_mm, data->y_size_mm); + } + } + + /* retrieve the ctrl registers */ + ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 20); + if (ret) { + hid_err(hdev, "can not read ctrl block of size 20: %d.\n", ret); + return ret; + } + + data->max_x = buf[6] | (buf[7] << 8); + data->max_y = buf[8] | (buf[9] << 8); + + return 0; +} + +static int rmi_populate_f30(struct hid_device *hdev) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + u8 buf[20]; + int ret; + bool has_gpio, has_led; + unsigned bytes_per_ctrl; + u8 ctrl2_addr; + int ctrl2_3_length; + int i; + + /* function F30 is for physical buttons */ + if (!data->f30.query_base_addr) { + hid_err(hdev, "No GPIO/LEDs found, giving up.\n"); + return -ENODEV; + } + + ret = rmi_read_block(hdev, data->f30.query_base_addr, buf, 2); + if (ret) { + hid_err(hdev, "can not get F30 query registers: %d.\n", ret); + return ret; + } + + has_gpio = !!(buf[0] & BIT(3)); + has_led = !!(buf[0] & BIT(2)); + data->gpio_led_count = buf[1] & 0x1f; + + /* retrieve ctrl 2 & 3 registers */ + bytes_per_ctrl = (data->gpio_led_count + 7) / 8; + /* Ctrl0 is present only if both has_gpio and has_led are set*/ + ctrl2_addr = (has_gpio && has_led) ? bytes_per_ctrl : 0; + /* Ctrl1 is always be present */ + ctrl2_addr += bytes_per_ctrl; + ctrl2_3_length = 2 * bytes_per_ctrl; + + data->f30.report_size = bytes_per_ctrl; + + ret = rmi_read_block(hdev, data->f30.control_base_addr + ctrl2_addr, + buf, ctrl2_3_length); + if (ret) { + hid_err(hdev, "can not read ctrl 2&3 block of size %d: %d.\n", + ctrl2_3_length, ret); + return ret; + } + + for (i = 0; i < data->gpio_led_count; i++) { + int byte_position = i >> 3; + int bit_position = i & 0x07; + u8 dir_byte = buf[byte_position]; + u8 data_byte = buf[byte_position + bytes_per_ctrl]; + bool dir = (dir_byte >> bit_position) & BIT(0); + bool dat = (data_byte >> bit_position) & BIT(0); + + if (dir == 0) { + /* input mode */ + if (dat) { + /* actual buttons have pull up resistor */ + data->button_count++; + set_bit(i, &data->button_mask); + set_bit(i, &data->button_state_mask); + } + } + + } + + return 0; +} + +static int rmi_populate(struct hid_device *hdev) +{ + int ret; + + ret = rmi_scan_pdt(hdev); + if (ret) { + hid_err(hdev, "PDT scan failed with code %d.\n", ret); + return ret; + } + + ret = rmi_populate_f11(hdev); + if (ret) { + hid_err(hdev, "Error while initializing F11 (%d).\n", ret); + return ret; + } + + ret = rmi_populate_f30(hdev); + if (ret) + hid_warn(hdev, "Error while initializing F30 (%d).\n", ret); + + return 0; +} + +static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + struct input_dev *input = hi->input; + int ret; + int res_x, res_y, i; + + data->input = input; + + hid_dbg(hdev, "Opening low level driver\n"); + ret = hid_hw_open(hdev); + if (ret) + return; + + /* Allow incoming hid reports */ + hid_device_io_start(hdev); + + ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + if (ret < 0) { + dev_err(&hdev->dev, "failed to set rmi mode\n"); + goto exit; + } + + ret = rmi_set_page(hdev, 0); + if (ret < 0) { + dev_err(&hdev->dev, "failed to set page select to 0.\n"); + goto exit; + } + + ret = rmi_populate(hdev); + if (ret) + goto exit; + + __set_bit(EV_ABS, input->evbit); + input_set_abs_params(input, ABS_MT_POSITION_X, 1, data->max_x, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 1, data->max_y, 0, 0); + + if (data->x_size_mm && data->x_size_mm) { + res_x = (data->max_x - 1) / data->x_size_mm; + res_y = (data->max_y - 1) / data->x_size_mm; + + input_abs_set_res(input, ABS_MT_POSITION_X, res_x); + input_abs_set_res(input, ABS_MT_POSITION_Y, res_y); + } + + input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0); + input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0); + + input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER); + + if (data->button_count) { + __set_bit(EV_KEY, input->evbit); + for (i = 0; i < data->button_count; i++) + __set_bit(BTN_LEFT + i, input->keybit); + + if (data->button_count == 1) + __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); + } + + set_bit(RMI_STARTED, &data->flags); + +exit: + hid_device_io_stop(hdev); + hid_hw_close(hdev); +} + +static int rmi_input_mapping(struct hid_device *hdev, + struct hid_input *hi, struct hid_field *field, + struct hid_usage *usage, unsigned long **bit, int *max) +{ + /* we want to make HID ignore the advertised HID collection */ + return -1; +} + +static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + struct rmi_data *data = NULL; + int ret; + size_t alloc_size; + + data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + INIT_WORK(&data->reset_work, rmi_reset_work); + data->hdev = hdev; + + hid_set_drvdata(hdev, data); + + hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + return ret; + } + + data->input_report_size = (hdev->report_enum[HID_INPUT_REPORT] + .report_id_hash[RMI_ATTN_REPORT_ID]->size >> 3) + + 1 /* report id */; + data->output_report_size = (hdev->report_enum[HID_OUTPUT_REPORT] + .report_id_hash[RMI_WRITE_REPORT_ID]->size >> 3) + + 1 /* report id */; + + alloc_size = data->output_report_size + data->input_report_size; + + data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL); + if (!data->writeReport) { + ret = -ENOMEM; + return ret; + } + + data->readReport = data->writeReport + data->output_report_size; + + init_waitqueue_head(&data->wait); + + mutex_init(&data->page_mutex); + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(hdev, "hw start failed\n"); + return ret; + } + + if (!test_bit(RMI_STARTED, &data->flags)) { + hid_hw_stop(hdev); + return -EIO; + } + + return 0; +} + +static void rmi_remove(struct hid_device *hdev) +{ + struct rmi_data *hdata = hid_get_drvdata(hdev); + + clear_bit(RMI_STARTED, &hdata->flags); + + hid_hw_stop(hdev); +} + +static const struct hid_device_id rmi_id[] = { + { HID_I2C_DEVICE(USB_VENDOR_ID_SYNAPTICS, HID_ANY_ID) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, HID_ANY_ID) }, + { } +}; +MODULE_DEVICE_TABLE(hid, rmi_id); + +static struct hid_driver rmi_driver = { + .name = "hid-rmi", + .id_table = rmi_id, + .probe = rmi_probe, + .remove = rmi_remove, + .raw_event = rmi_raw_event, + .input_mapping = rmi_input_mapping, + .input_configured = rmi_input_configured, +#ifdef CONFIG_PM + .resume = rmi_post_resume, + .reset_resume = rmi_post_reset, +#endif +}; + +module_hid_driver(rmi_driver); + +MODULE_AUTHOR("Andrew Duggan "); +MODULE_DESCRIPTION("RMI HID driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 908de278921944..2259eaa8b98886 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "hid-ids.h" @@ -717,8 +718,39 @@ static enum power_supply_property sony_battery_props[] = { POWER_SUPPLY_PROP_STATUS, }; +struct sixaxis_led { + __u8 time_enabled; /* the total time the led is active (0xff means forever) */ + __u8 duty_length; /* how long a cycle is in deciseconds (0 means "really fast") */ + __u8 enabled; + __u8 duty_off; /* % of duty_length the led is off (0xff means 100%) */ + __u8 duty_on; /* % of duty_length the led is on (0xff mean 100%) */ +} __packed; + +struct sixaxis_rumble { + __u8 padding; + __u8 right_duration; /* Right motor duration (0xff means forever) */ + __u8 right_motor_on; /* Right (small) motor on/off, only supports values of 0 or 1 (off/on) */ + __u8 left_duration; /* Left motor duration (0xff means forever) */ + __u8 left_motor_force; /* left (large) motor, supports force values from 0 to 255 */ +} __packed; + +struct sixaxis_output_report { + __u8 report_id; + struct sixaxis_rumble rumble; + __u8 padding[4]; + __u8 leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */ + struct sixaxis_led led[4]; /* LEDx at (4 - x) */ + struct sixaxis_led _reserved; /* LED5, not actually soldered */ +} __packed; + +union sixaxis_output_report_01 { + struct sixaxis_output_report data; + __u8 buf[36]; +}; + static spinlock_t sony_dev_list_lock; static LIST_HEAD(sony_device_list); +static DEFINE_IDA(sony_device_id_allocator); struct sony_sc { spinlock_t lock; @@ -728,6 +760,7 @@ struct sony_sc { unsigned long quirks; struct work_struct state_worker; struct power_supply battery; + int device_id; #ifdef CONFIG_SONY_FF __u8 left; @@ -740,6 +773,8 @@ struct sony_sc { __u8 battery_charging; __u8 battery_capacity; __u8 led_state[MAX_LEDS]; + __u8 led_delay_on[MAX_LEDS]; + __u8 led_delay_off[MAX_LEDS]; __u8 led_count; }; @@ -1048,6 +1083,52 @@ static int dualshock4_set_operational_bt(struct hid_device *hdev) HID_FEATURE_REPORT, HID_REQ_GET_REPORT); } +static void sixaxis_set_leds_from_id(int id, __u8 values[MAX_LEDS]) +{ + static const __u8 sixaxis_leds[10][4] = { + { 0x01, 0x00, 0x00, 0x00 }, + { 0x00, 0x01, 0x00, 0x00 }, + { 0x00, 0x00, 0x01, 0x00 }, + { 0x00, 0x00, 0x00, 0x01 }, + { 0x01, 0x00, 0x00, 0x01 }, + { 0x00, 0x01, 0x00, 0x01 }, + { 0x00, 0x00, 0x01, 0x01 }, + { 0x01, 0x00, 0x01, 0x01 }, + { 0x00, 0x01, 0x01, 0x01 }, + { 0x01, 0x01, 0x01, 0x01 } + }; + + BUG_ON(MAX_LEDS < ARRAY_SIZE(sixaxis_leds[0])); + + if (id < 0) + return; + + id %= 10; + memcpy(values, sixaxis_leds[id], sizeof(sixaxis_leds[id])); +} + +static void dualshock4_set_leds_from_id(int id, __u8 values[MAX_LEDS]) +{ + /* The first 4 color/index entries match what the PS4 assigns */ + static const __u8 color_code[7][3] = { + /* Blue */ { 0x00, 0x00, 0x01 }, + /* Red */ { 0x01, 0x00, 0x00 }, + /* Green */ { 0x00, 0x01, 0x00 }, + /* Pink */ { 0x02, 0x00, 0x01 }, + /* Orange */ { 0x02, 0x01, 0x00 }, + /* Teal */ { 0x00, 0x01, 0x01 }, + /* White */ { 0x01, 0x01, 0x01 } + }; + + BUG_ON(MAX_LEDS < ARRAY_SIZE(color_code[0])); + + if (id < 0) + return; + + id %= 7; + memcpy(values, color_code[id], sizeof(color_code[id])); +} + static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds) { struct list_head *report_list = @@ -1066,19 +1147,18 @@ static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds) hid_hw_request(hdev, report, HID_REQ_SET_REPORT); } -static void sony_set_leds(struct hid_device *hdev, const __u8 *leds, int count) +static void sony_set_leds(struct sony_sc *sc, const __u8 *leds, int count) { - struct sony_sc *drv_data = hid_get_drvdata(hdev); int n; BUG_ON(count > MAX_LEDS); - if (drv_data->quirks & BUZZ_CONTROLLER && count == 4) { - buzz_set_leds(hdev, leds); + if (sc->quirks & BUZZ_CONTROLLER && count == 4) { + buzz_set_leds(sc->hdev, leds); } else { for (n = 0; n < count; n++) - drv_data->led_state[n] = leds[n]; - schedule_work(&drv_data->state_worker); + sc->led_state[n] = leds[n]; + schedule_work(&sc->state_worker); } } @@ -1090,6 +1170,7 @@ static void sony_led_set_brightness(struct led_classdev *led, struct sony_sc *drv_data; int n; + int force_update; drv_data = hid_get_drvdata(hdev); if (!drv_data) { @@ -1097,12 +1178,29 @@ static void sony_led_set_brightness(struct led_classdev *led, return; } + /* + * The Sixaxis on USB will override any LED settings sent to it + * and keep flashing all of the LEDs until the PS button is pressed. + * Updates, even if redundant, must be always be sent to the + * controller to avoid having to toggle the state of an LED just to + * stop the flashing later on. + */ + force_update = !!(drv_data->quirks & SIXAXIS_CONTROLLER_USB); + for (n = 0; n < drv_data->led_count; n++) { - if (led == drv_data->leds[n]) { - if (value != drv_data->led_state[n]) { - drv_data->led_state[n] = value; - sony_set_leds(hdev, drv_data->led_state, drv_data->led_count); - } + if (led == drv_data->leds[n] && (force_update || + (value != drv_data->led_state[n] || + drv_data->led_delay_on[n] || + drv_data->led_delay_off[n]))) { + + drv_data->led_state[n] = value; + + /* Setting the brightness stops the blinking */ + drv_data->led_delay_on[n] = 0; + drv_data->led_delay_off[n] = 0; + + sony_set_leds(drv_data, drv_data->led_state, + drv_data->led_count); break; } } @@ -1130,63 +1228,112 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led) return LED_OFF; } -static void sony_leds_remove(struct hid_device *hdev) +static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on, + unsigned long *delay_off) { - struct sony_sc *drv_data; - struct led_classdev *led; + struct device *dev = led->dev->parent; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct sony_sc *drv_data = hid_get_drvdata(hdev); int n; + __u8 new_on, new_off; - drv_data = hid_get_drvdata(hdev); - BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT)); + if (!drv_data) { + hid_err(hdev, "No device data\n"); + return -EINVAL; + } + + /* Max delay is 255 deciseconds or 2550 milliseconds */ + if (*delay_on > 2550) + *delay_on = 2550; + if (*delay_off > 2550) + *delay_off = 2550; + + /* Blink at 1 Hz if both values are zero */ + if (!*delay_on && !*delay_off) + *delay_on = *delay_off = 500; + + new_on = *delay_on / 10; + new_off = *delay_off / 10; for (n = 0; n < drv_data->led_count; n++) { - led = drv_data->leds[n]; - drv_data->leds[n] = NULL; + if (led == drv_data->leds[n]) + break; + } + + /* This LED is not registered on this device */ + if (n >= drv_data->led_count) + return -EINVAL; + + /* Don't schedule work if the values didn't change */ + if (new_on != drv_data->led_delay_on[n] || + new_off != drv_data->led_delay_off[n]) { + drv_data->led_delay_on[n] = new_on; + drv_data->led_delay_off[n] = new_off; + schedule_work(&drv_data->state_worker); + } + + return 0; +} + +static void sony_leds_remove(struct sony_sc *sc) +{ + struct led_classdev *led; + int n; + + BUG_ON(!(sc->quirks & SONY_LED_SUPPORT)); + + for (n = 0; n < sc->led_count; n++) { + led = sc->leds[n]; + sc->leds[n] = NULL; if (!led) continue; led_classdev_unregister(led); kfree(led); } - drv_data->led_count = 0; + sc->led_count = 0; } -static int sony_leds_init(struct hid_device *hdev) +static int sony_leds_init(struct sony_sc *sc) { - struct sony_sc *drv_data; + struct hid_device *hdev = sc->hdev; int n, ret = 0; - int max_brightness; - int use_colors; + int use_ds4_names; struct led_classdev *led; size_t name_sz; char *name; size_t name_len; const char *name_fmt; - static const char * const color_str[] = { "red", "green", "blue" }; - static const __u8 initial_values[MAX_LEDS] = { 0x00, 0x00, 0x00, 0x00 }; + static const char * const ds4_name_str[] = { "red", "green", "blue", + "global" }; + __u8 initial_values[MAX_LEDS] = { 0 }; + __u8 max_brightness[MAX_LEDS] = { 1 }; + __u8 use_hw_blink[MAX_LEDS] = { 0 }; - drv_data = hid_get_drvdata(hdev); - BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT)); + BUG_ON(!(sc->quirks & SONY_LED_SUPPORT)); - if (drv_data->quirks & BUZZ_CONTROLLER) { - drv_data->led_count = 4; - max_brightness = 1; - use_colors = 0; + if (sc->quirks & BUZZ_CONTROLLER) { + sc->led_count = 4; + use_ds4_names = 0; name_len = strlen("::buzz#"); name_fmt = "%s::buzz%d"; /* Validate expected report characteristics. */ if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7)) return -ENODEV; - } else if (drv_data->quirks & DUALSHOCK4_CONTROLLER) { - drv_data->led_count = 3; - max_brightness = 255; - use_colors = 1; + } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { + dualshock4_set_leds_from_id(sc->device_id, initial_values); + initial_values[3] = 1; + sc->led_count = 4; + memset(max_brightness, 255, 3); + use_hw_blink[3] = 1; + use_ds4_names = 1; name_len = 0; name_fmt = "%s:%s"; } else { - drv_data->led_count = 4; - max_brightness = 1; - use_colors = 0; + sixaxis_set_leds_from_id(sc->device_id, initial_values); + sc->led_count = 4; + memset(use_hw_blink, 1, 4); + use_ds4_names = 0; name_len = strlen("::sony#"); name_fmt = "%s::sony%d"; } @@ -1196,14 +1343,14 @@ static int sony_leds_init(struct hid_device *hdev) * only relevant if the driver is loaded after somebody actively set the * LEDs to on */ - sony_set_leds(hdev, initial_values, drv_data->led_count); + sony_set_leds(sc, initial_values, sc->led_count); name_sz = strlen(dev_name(&hdev->dev)) + name_len + 1; - for (n = 0; n < drv_data->led_count; n++) { + for (n = 0; n < sc->led_count; n++) { - if (use_colors) - name_sz = strlen(dev_name(&hdev->dev)) + strlen(color_str[n]) + 2; + if (use_ds4_names) + name_sz = strlen(dev_name(&hdev->dev)) + strlen(ds4_name_str[n]) + 2; led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL); if (!led) { @@ -1213,30 +1360,35 @@ static int sony_leds_init(struct hid_device *hdev) } name = (void *)(&led[1]); - if (use_colors) - snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), color_str[n]); + if (use_ds4_names) + snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), + ds4_name_str[n]); else snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1); led->name = name; - led->brightness = 0; - led->max_brightness = max_brightness; + led->brightness = initial_values[n]; + led->max_brightness = max_brightness[n]; led->brightness_get = sony_led_get_brightness; led->brightness_set = sony_led_set_brightness; + if (use_hw_blink[n]) + led->blink_set = sony_led_blink_set; + + sc->leds[n] = led; + ret = led_classdev_register(&hdev->dev, led); if (ret) { hid_err(hdev, "Failed to register LED %d\n", n); + sc->leds[n] = NULL; kfree(led); goto error_leds; } - - drv_data->leds[n] = led; } return ret; error_leds: - sony_leds_remove(hdev); + sony_leds_remove(sc); return ret; } @@ -1244,29 +1396,52 @@ static int sony_leds_init(struct hid_device *hdev) static void sixaxis_state_worker(struct work_struct *work) { struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); - unsigned char buf[] = { - 0x01, - 0x00, 0xff, 0x00, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x27, 0x10, 0x00, 0x32, - 0xff, 0x27, 0x10, 0x00, 0x32, - 0xff, 0x27, 0x10, 0x00, 0x32, - 0xff, 0x27, 0x10, 0x00, 0x32, - 0x00, 0x00, 0x00, 0x00, 0x00 + int n; + union sixaxis_output_report_01 report = { + .buf = { + 0x01, + 0x00, 0xff, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00 + } }; #ifdef CONFIG_SONY_FF - buf[3] = sc->right ? 1 : 0; - buf[5] = sc->left; + report.data.rumble.right_motor_on = sc->right ? 1 : 0; + report.data.rumble.left_motor_force = sc->left; #endif - buf[10] |= sc->led_state[0] << 1; - buf[10] |= sc->led_state[1] << 2; - buf[10] |= sc->led_state[2] << 3; - buf[10] |= sc->led_state[3] << 4; + report.data.leds_bitmap |= sc->led_state[0] << 1; + report.data.leds_bitmap |= sc->led_state[1] << 2; + report.data.leds_bitmap |= sc->led_state[2] << 3; + report.data.leds_bitmap |= sc->led_state[3] << 4; + + /* Set flag for all leds off, required for 3rd party INTEC controller */ + if ((report.data.leds_bitmap & 0x1E) == 0) + report.data.leds_bitmap |= 0x20; - hid_hw_raw_request(sc->hdev, 0x01, buf, sizeof(buf), HID_OUTPUT_REPORT, - HID_REQ_SET_REPORT); + /* + * The LEDs in the report are indexed in reverse order to their + * corresponding light on the controller. + * Index 0 = LED 4, index 1 = LED 3, etc... + * + * In the case of both delay values being zero (blinking disabled) the + * default report values should be used or the controller LED will be + * always off. + */ + for (n = 0; n < 4; n++) { + if (sc->led_delay_on[n] || sc->led_delay_off[n]) { + report.data.led[3 - n].duty_off = sc->led_delay_off[n]; + report.data.led[3 - n].duty_on = sc->led_delay_on[n]; + } + } + + hid_hw_raw_request(sc->hdev, report.data.report_id, report.buf, + sizeof(report), HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); } static void dualshock4_state_worker(struct work_struct *work) @@ -1279,7 +1454,7 @@ static void dualshock4_state_worker(struct work_struct *work) if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { buf[0] = 0x05; - buf[1] = 0x03; + buf[1] = 0xFF; offset = 4; } else { buf[0] = 0x11; @@ -1295,9 +1470,18 @@ static void dualshock4_state_worker(struct work_struct *work) offset += 2; #endif - buf[offset++] = sc->led_state[0]; - buf[offset++] = sc->led_state[1]; - buf[offset++] = sc->led_state[2]; + /* LED 3 is the global control */ + if (sc->led_state[3]) { + buf[offset++] = sc->led_state[0]; + buf[offset++] = sc->led_state[1]; + buf[offset++] = sc->led_state[2]; + } else { + offset += 3; + } + + /* If both delay values are zero the DualShock 4 disables blinking. */ + buf[offset++] = sc->led_delay_on[3]; + buf[offset++] = sc->led_delay_off[3]; if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) hid_hw_output_report(hdev, buf, 32); @@ -1323,9 +1507,9 @@ static int sony_play_effect(struct input_dev *dev, void *data, return 0; } -static int sony_init_ff(struct hid_device *hdev) +static int sony_init_ff(struct sony_sc *sc) { - struct hid_input *hidinput = list_entry(hdev->inputs.next, + struct hid_input *hidinput = list_entry(sc->hdev->inputs.next, struct hid_input, list); struct input_dev *input_dev = hidinput->input; @@ -1334,7 +1518,7 @@ static int sony_init_ff(struct hid_device *hdev) } #else -static int sony_init_ff(struct hid_device *hdev) +static int sony_init_ff(struct sony_sc *sc) { return 0; } @@ -1384,8 +1568,6 @@ static int sony_battery_get_property(struct power_supply *psy, static int sony_battery_probe(struct sony_sc *sc) { - static atomic_t power_id_seq = ATOMIC_INIT(0); - unsigned long power_id; struct hid_device *hdev = sc->hdev; int ret; @@ -1395,15 +1577,13 @@ static int sony_battery_probe(struct sony_sc *sc) */ sc->battery_capacity = 100; - power_id = (unsigned long)atomic_inc_return(&power_id_seq); - sc->battery.properties = sony_battery_props; sc->battery.num_properties = ARRAY_SIZE(sony_battery_props); sc->battery.get_property = sony_battery_get_property; sc->battery.type = POWER_SUPPLY_TYPE_BATTERY; sc->battery.use_for_apm = 0; - sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%lu", - power_id); + sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%pMR", + sc->mac_address); if (!sc->battery.name) return -ENOMEM; @@ -1578,6 +1758,52 @@ static int sony_check_add(struct sony_sc *sc) return sony_check_add_dev_list(sc); } +static int sony_set_device_id(struct sony_sc *sc) +{ + int ret; + + /* + * Only DualShock 4 or Sixaxis controllers get an id. + * All others are set to -1. + */ + if ((sc->quirks & SIXAXIS_CONTROLLER) || + (sc->quirks & DUALSHOCK4_CONTROLLER)) { + ret = ida_simple_get(&sony_device_id_allocator, 0, 0, + GFP_KERNEL); + if (ret < 0) { + sc->device_id = -1; + return ret; + } + sc->device_id = ret; + } else { + sc->device_id = -1; + } + + return 0; +} + +static void sony_release_device_id(struct sony_sc *sc) +{ + if (sc->device_id >= 0) { + ida_simple_remove(&sony_device_id_allocator, sc->device_id); + sc->device_id = -1; + } +} + +static inline void sony_init_work(struct sony_sc *sc, + void (*worker)(struct work_struct *)) +{ + if (!sc->worker_initialized) + INIT_WORK(&sc->state_worker, worker); + + sc->worker_initialized = 1; +} + +static inline void sony_cancel_work_sync(struct sony_sc *sc) +{ + if (sc->worker_initialized) + cancel_work_sync(&sc->state_worker); +} static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -1615,6 +1841,12 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } + ret = sony_set_device_id(sc); + if (ret < 0) { + hid_err(hdev, "failed to allocate the device id\n"); + goto err_stop; + } + if (sc->quirks & SIXAXIS_CONTROLLER_USB) { /* * The Sony Sixaxis does not handle HID Output Reports on the @@ -1629,8 +1861,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID; ret = sixaxis_set_operational_usb(hdev); - sc->worker_initialized = 1; - INIT_WORK(&sc->state_worker, sixaxis_state_worker); + sony_init_work(sc, sixaxis_state_worker); } else if (sc->quirks & SIXAXIS_CONTROLLER_BT) { /* * The Sixaxis wants output reports sent on the ctrl endpoint @@ -1638,8 +1869,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) */ hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; ret = sixaxis_set_operational_bt(hdev); - sc->worker_initialized = 1; - INIT_WORK(&sc->state_worker, sixaxis_state_worker); + sony_init_work(sc, sixaxis_state_worker); } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) { /* @@ -1661,8 +1891,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret < 0) goto err_stop; - sc->worker_initialized = 1; - INIT_WORK(&sc->state_worker, dualshock4_state_worker); + sony_init_work(sc, dualshock4_state_worker); } else { ret = 0; } @@ -1675,7 +1904,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_stop; if (sc->quirks & SONY_LED_SUPPORT) { - ret = sony_leds_init(hdev); + ret = sony_leds_init(sc); if (ret < 0) goto err_stop; } @@ -1694,7 +1923,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) } if (sc->quirks & SONY_FF_SUPPORT) { - ret = sony_init_ff(hdev); + ret = sony_init_ff(sc); if (ret < 0) goto err_close; } @@ -1704,12 +1933,12 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) hid_hw_close(hdev); err_stop: if (sc->quirks & SONY_LED_SUPPORT) - sony_leds_remove(hdev); + sony_leds_remove(sc); if (sc->quirks & SONY_BATTERY_SUPPORT) sony_battery_remove(sc); - if (sc->worker_initialized) - cancel_work_sync(&sc->state_worker); + sony_cancel_work_sync(sc); sony_remove_dev_list(sc); + sony_release_device_id(sc); hid_hw_stop(hdev); return ret; } @@ -1719,18 +1948,19 @@ static void sony_remove(struct hid_device *hdev) struct sony_sc *sc = hid_get_drvdata(hdev); if (sc->quirks & SONY_LED_SUPPORT) - sony_leds_remove(hdev); + sony_leds_remove(sc); if (sc->quirks & SONY_BATTERY_SUPPORT) { hid_hw_close(hdev); sony_battery_remove(sc); } - if (sc->worker_initialized) - cancel_work_sync(&sc->state_worker); + sony_cancel_work_sync(sc); sony_remove_dev_list(sc); + sony_release_device_id(sc); + hid_hw_stop(hdev); } @@ -1775,6 +2005,22 @@ static struct hid_driver sony_driver = { .report_fixup = sony_report_fixup, .raw_event = sony_raw_event }; -module_hid_driver(sony_driver); + +static int __init sony_init(void) +{ + dbg_hid("Sony:%s\n", __func__); + + return hid_register_driver(&sony_driver); +} + +static void __exit sony_exit(void) +{ + dbg_hid("Sony:%s\n", __func__); + + ida_destroy(&sony_device_id_allocator); + hid_unregister_driver(&sony_driver); +} +module_init(sony_init); +module_exit(sony_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c index a97c78845f7b19..31de890d14cf47 100644 --- a/drivers/hid/hid-thingm.c +++ b/drivers/hid/hid-thingm.c @@ -1,7 +1,7 @@ /* * ThingM blink(1) USB RGB LED driver * - * Copyright 2013 Savoir-faire Linux Inc. + * Copyright 2013-2014 Savoir-faire Linux Inc. * Vivien Didelot * * This program is free software; you can redistribute it and/or @@ -10,244 +10,285 @@ */ #include +#include #include #include +#include +#include #include "hid-ids.h" -#define BLINK1_CMD_SIZE 9 +#define REPORT_ID 1 +#define REPORT_SIZE 9 -#define blink1_rgb_to_r(rgb) ((rgb & 0xFF0000) >> 16) -#define blink1_rgb_to_g(rgb) ((rgb & 0x00FF00) >> 8) -#define blink1_rgb_to_b(rgb) ((rgb & 0x0000FF) >> 0) +/* Firmware major number of supported devices */ +#define THINGM_MAJOR_MK1 '1' +#define THINGM_MAJOR_MK2 '2' -/** - * struct blink1_data - blink(1) device specific data - * @hdev: HID device. - * @led_cdev: LED class instance. - * @rgb: 8-bit per channel RGB notation. - * @fade: fade time in hundredths of a second. - * @brightness: brightness coefficient. - * @play: play/pause in-memory patterns. - */ -struct blink1_data { +struct thingm_fwinfo { + char major; + unsigned numrgb; + unsigned first; +}; + +const struct thingm_fwinfo thingm_fwinfo[] = { + { + .major = THINGM_MAJOR_MK1, + .numrgb = 1, + .first = 0, + }, { + .major = THINGM_MAJOR_MK2, + .numrgb = 2, + .first = 1, + } +}; + +/* A red, green or blue channel, part of an RGB chip */ +struct thingm_led { + struct thingm_rgb *rgb; + struct led_classdev ldev; + char name[32]; +}; + +/* Basically a WS2812 5050 RGB LED chip */ +struct thingm_rgb { + struct thingm_device *tdev; + struct thingm_led red; + struct thingm_led green; + struct thingm_led blue; + struct work_struct work; + u8 num; +}; + +struct thingm_device { struct hid_device *hdev; - struct led_classdev led_cdev; - u32 rgb; - u16 fade; - u8 brightness; - bool play; + struct { + char major; + char minor; + } version; + const struct thingm_fwinfo *fwinfo; + struct mutex lock; + struct thingm_rgb *rgb; }; -static int blink1_send_command(struct blink1_data *data, - u8 buf[BLINK1_CMD_SIZE]) +static int thingm_send(struct thingm_device *tdev, u8 buf[REPORT_SIZE]) { int ret; - hid_dbg(data->hdev, "command: %d%c%.2x%.2x%.2x%.2x%.2x%.2x%.2x\n", + hid_dbg(tdev->hdev, "-> %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]); - ret = hid_hw_raw_request(data->hdev, buf[0], buf, BLINK1_CMD_SIZE, - HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); return ret < 0 ? ret : 0; } -static int blink1_update_color(struct blink1_data *data) +static int thingm_recv(struct thingm_device *tdev, u8 buf[REPORT_SIZE]) { - u8 buf[BLINK1_CMD_SIZE] = { 1, 'n', 0, 0, 0, 0, 0, 0, 0 }; - - if (data->brightness) { - unsigned int coef = DIV_ROUND_CLOSEST(255, data->brightness); + int ret; - buf[2] = DIV_ROUND_CLOSEST(blink1_rgb_to_r(data->rgb), coef); - buf[3] = DIV_ROUND_CLOSEST(blink1_rgb_to_g(data->rgb), coef); - buf[4] = DIV_ROUND_CLOSEST(blink1_rgb_to_b(data->rgb), coef); - } + ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE, + HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + if (ret < 0) + return ret; - if (data->fade) { - buf[1] = 'c'; - buf[5] = (data->fade & 0xFF00) >> 8; - buf[6] = (data->fade & 0x00FF); - } + hid_dbg(tdev->hdev, "<- %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n", + buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5], buf[6], buf[7], buf[8]); - return blink1_send_command(data, buf); + return 0; } -static void blink1_led_set(struct led_classdev *led_cdev, - enum led_brightness brightness) +static int thingm_version(struct thingm_device *tdev) { - struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent); + u8 buf[REPORT_SIZE] = { REPORT_ID, 'v', 0, 0, 0, 0, 0, 0, 0 }; + int err; - data->brightness = brightness; - if (blink1_update_color(data)) - hid_err(data->hdev, "failed to update color\n"); -} + err = thingm_send(tdev, buf); + if (err) + return err; -static enum led_brightness blink1_led_get(struct led_classdev *led_cdev) -{ - struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent); + err = thingm_recv(tdev, buf); + if (err) + return err; - return data->brightness; + tdev->version.major = buf[3]; + tdev->version.minor = buf[4]; + + return 0; } -static ssize_t blink1_show_rgb(struct device *dev, - struct device_attribute *attr, char *buf) +static int thingm_write_color(struct thingm_rgb *rgb) { - struct blink1_data *data = dev_get_drvdata(dev->parent); + u8 buf[REPORT_SIZE] = { REPORT_ID, 'c', 0, 0, 0, 0, 0, rgb->num, 0 }; - return sprintf(buf, "%.6X\n", data->rgb); + buf[2] = rgb->red.ldev.brightness; + buf[3] = rgb->green.ldev.brightness; + buf[4] = rgb->blue.ldev.brightness; + + return thingm_send(rgb->tdev, buf); } -static ssize_t blink1_store_rgb(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +static void thingm_work(struct work_struct *work) { - struct blink1_data *data = dev_get_drvdata(dev->parent); - long unsigned int rgb; - int ret; + struct thingm_rgb *rgb = container_of(work, struct thingm_rgb, work); - ret = kstrtoul(buf, 16, &rgb); - if (ret) - return ret; - - /* RGB triplet notation is 24-bit hexadecimal */ - if (rgb > 0xFFFFFF) - return -EINVAL; + mutex_lock(&rgb->tdev->lock); - data->rgb = rgb; - ret = blink1_update_color(data); + if (thingm_write_color(rgb)) + hid_err(rgb->tdev->hdev, "failed to write color\n"); - return ret ? ret : count; + mutex_unlock(&rgb->tdev->lock); } -static DEVICE_ATTR(rgb, S_IRUGO | S_IWUSR, blink1_show_rgb, blink1_store_rgb); - -static ssize_t blink1_show_fade(struct device *dev, - struct device_attribute *attr, char *buf) +static void thingm_led_set(struct led_classdev *ldev, + enum led_brightness brightness) { - struct blink1_data *data = dev_get_drvdata(dev->parent); + struct thingm_led *led = container_of(ldev, struct thingm_led, ldev); - return sprintf(buf, "%d\n", data->fade * 10); + /* the ledclass has already stored the brightness value */ + schedule_work(&led->rgb->work); } -static ssize_t blink1_store_fade(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +static int thingm_init_rgb(struct thingm_rgb *rgb) { - struct blink1_data *data = dev_get_drvdata(dev->parent); - long unsigned int fade; - int ret; + const int minor = ((struct hidraw *) rgb->tdev->hdev->hidraw)->minor; + int err; + + /* Register the red diode */ + snprintf(rgb->red.name, sizeof(rgb->red.name), + "thingm%d:red:led%d", minor, rgb->num); + rgb->red.ldev.name = rgb->red.name; + rgb->red.ldev.max_brightness = 255; + rgb->red.ldev.brightness_set = thingm_led_set; + rgb->red.rgb = rgb; + + err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->red.ldev); + if (err) + return err; + + /* Register the green diode */ + snprintf(rgb->green.name, sizeof(rgb->green.name), + "thingm%d:green:led%d", minor, rgb->num); + rgb->green.ldev.name = rgb->green.name; + rgb->green.ldev.max_brightness = 255; + rgb->green.ldev.brightness_set = thingm_led_set; + rgb->green.rgb = rgb; + + err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->green.ldev); + if (err) + goto unregister_red; + + /* Register the blue diode */ + snprintf(rgb->blue.name, sizeof(rgb->blue.name), + "thingm%d:blue:led%d", minor, rgb->num); + rgb->blue.ldev.name = rgb->blue.name; + rgb->blue.ldev.max_brightness = 255; + rgb->blue.ldev.brightness_set = thingm_led_set; + rgb->blue.rgb = rgb; + + err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->blue.ldev); + if (err) + goto unregister_green; + + INIT_WORK(&rgb->work, thingm_work); - ret = kstrtoul(buf, 10, &fade); - if (ret) - return ret; + return 0; - /* blink(1) accepts 16-bit fade time, number of 10ms ticks */ - fade = DIV_ROUND_CLOSEST(fade, 10); - if (fade > 65535) - return -EINVAL; +unregister_green: + led_classdev_unregister(&rgb->green.ldev); - data->fade = fade; +unregister_red: + led_classdev_unregister(&rgb->red.ldev); - return count; + return err; } -static DEVICE_ATTR(fade, S_IRUGO | S_IWUSR, - blink1_show_fade, blink1_store_fade); - -static ssize_t blink1_show_play(struct device *dev, - struct device_attribute *attr, char *buf) +static void thingm_remove_rgb(struct thingm_rgb *rgb) { - struct blink1_data *data = dev_get_drvdata(dev->parent); - - return sprintf(buf, "%d\n", data->play); + flush_work(&rgb->work); + led_classdev_unregister(&rgb->red.ldev); + led_classdev_unregister(&rgb->green.ldev); + led_classdev_unregister(&rgb->blue.ldev); } -static ssize_t blink1_store_play(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id) { - struct blink1_data *data = dev_get_drvdata(dev->parent); - u8 cmd[BLINK1_CMD_SIZE] = { 1, 'p', 0, 0, 0, 0, 0, 0, 0 }; - long unsigned int play; - int ret; + struct thingm_device *tdev; + int i, err; - ret = kstrtoul(buf, 10, &play); - if (ret) - return ret; + tdev = devm_kzalloc(&hdev->dev, sizeof(struct thingm_device), + GFP_KERNEL); + if (!tdev) + return -ENOMEM; - data->play = !!play; - cmd[2] = data->play; - ret = blink1_send_command(data, cmd); + tdev->hdev = hdev; + hid_set_drvdata(hdev, tdev); - return ret ? ret : count; -} - -static DEVICE_ATTR(play, S_IRUGO | S_IWUSR, - blink1_show_play, blink1_store_play); + err = hid_parse(hdev); + if (err) + goto error; -static const struct attribute_group blink1_sysfs_group = { - .attrs = (struct attribute *[]) { - &dev_attr_rgb.attr, - &dev_attr_fade.attr, - &dev_attr_play.attr, - NULL - }, -}; + err = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (err) + goto error; -static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id) -{ - struct blink1_data *data; - struct led_classdev *led; - char led_name[13]; - int ret; + mutex_init(&tdev->lock); - data = devm_kzalloc(&hdev->dev, sizeof(struct blink1_data), GFP_KERNEL); - if (!data) - return -ENOMEM; + err = thingm_version(tdev); + if (err) + goto stop; - hid_set_drvdata(hdev, data); - data->hdev = hdev; - data->rgb = 0xFFFFFF; /* set a default white color */ + hid_dbg(hdev, "firmware version: %c.%c\n", + tdev->version.major, tdev->version.minor); - ret = hid_parse(hdev); - if (ret) - goto error; + for (i = 0; i < ARRAY_SIZE(thingm_fwinfo) && !tdev->fwinfo; ++i) + if (thingm_fwinfo[i].major == tdev->version.major) + tdev->fwinfo = &thingm_fwinfo[i]; - ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); - if (ret) - goto error; + if (!tdev->fwinfo) { + hid_err(hdev, "unsupported firmware %c\n", tdev->version.major); + goto stop; + } - /* blink(1) serial numbers range is 0x1A001000 to 0x1A002FFF */ - led = &data->led_cdev; - snprintf(led_name, sizeof(led_name), "blink1::%s", hdev->uniq + 4); - led->name = led_name; - led->brightness_set = blink1_led_set; - led->brightness_get = blink1_led_get; - ret = led_classdev_register(&hdev->dev, led); - if (ret) + tdev->rgb = devm_kzalloc(&hdev->dev, + sizeof(struct thingm_rgb) * tdev->fwinfo->numrgb, + GFP_KERNEL); + if (!tdev->rgb) { + err = -ENOMEM; goto stop; + } - ret = sysfs_create_group(&led->dev->kobj, &blink1_sysfs_group); - if (ret) - goto remove_led; + for (i = 0; i < tdev->fwinfo->numrgb; ++i) { + struct thingm_rgb *rgb = tdev->rgb + i; + + rgb->tdev = tdev; + rgb->num = tdev->fwinfo->first + i; + err = thingm_init_rgb(rgb); + if (err) { + while (--i >= 0) + thingm_remove_rgb(tdev->rgb + i); + goto stop; + } + } return 0; - -remove_led: - led_classdev_unregister(led); stop: hid_hw_stop(hdev); error: - return ret; + return err; } static void thingm_remove(struct hid_device *hdev) { - struct blink1_data *data = hid_get_drvdata(hdev); - struct led_classdev *led = &data->led_cdev; + struct thingm_device *tdev = hid_get_drvdata(hdev); + int i; + + for (i = 0; i < tdev->fwinfo->numrgb; ++i) + thingm_remove_rgb(tdev->rgb + i); - sysfs_remove_group(&led->dev->kobj, &blink1_sysfs_group); - led_classdev_unregister(led); hid_hw_stop(hdev); } diff --git a/drivers/hsi/clients/hsi_char.c b/drivers/hsi/clients/hsi_char.c index e61e5f991aa538..30733209fde2c5 100644 --- a/drivers/hsi/clients/hsi_char.c +++ b/drivers/hsi/clients/hsi_char.c @@ -705,7 +705,7 @@ static int hsc_probe(struct device *dev) if (!hsc_major) { ret = alloc_chrdev_region(&hsc_dev, hsc_baseminor, HSC_DEVS, devname); - if (ret > 0) + if (ret == 0) hsc_major = MAJOR(hsc_dev); } else { hsc_dev = MKDEV(hsc_major, hsc_baseminor); diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 602ca86a6488d6..284cf66489f428 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -471,18 +471,26 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) } EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl); +static void reset_channel_cb(void *arg) +{ + struct vmbus_channel *channel = arg; + + channel->onchannel_callback = NULL; +} + static void vmbus_close_internal(struct vmbus_channel *channel) { struct vmbus_channel_close_channel *msg; int ret; - unsigned long flags; channel->state = CHANNEL_OPEN_STATE; channel->sc_creation_callback = NULL; /* Stop callback and cancel the timer asap */ - spin_lock_irqsave(&channel->inbound_lock, flags); - channel->onchannel_callback = NULL; - spin_unlock_irqrestore(&channel->inbound_lock, flags); + if (channel->target_cpu != smp_processor_id()) + smp_call_function_single(channel->target_cpu, reset_channel_cb, + channel, true); + else + reset_channel_cb(channel); /* Send a closing message */ @@ -674,8 +682,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel, u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset, multi_pagebuffer->len); - - if ((pfncount < 0) || (pfncount > MAX_MULTIPAGE_BUFFER_COUNT)) + if (pfncount > MAX_MULTIPAGE_BUFFER_COUNT) return -EINVAL; /* diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index fa920469bf104f..6c8b032cacba7c 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -149,6 +149,7 @@ static struct vmbus_channel *alloc_channel(void) spin_lock_init(&channel->sc_lock); INIT_LIST_HEAD(&channel->sc_list); + INIT_LIST_HEAD(&channel->percpu_list); channel->controlwq = create_workqueue("hv_vmbus_ctl"); if (!channel->controlwq) { @@ -188,7 +189,20 @@ static void free_channel(struct vmbus_channel *channel) queue_work(vmbus_connection.work_queue, &channel->work); } +static void percpu_channel_enq(void *arg) +{ + struct vmbus_channel *channel = arg; + int cpu = smp_processor_id(); + + list_add_tail(&channel->percpu_list, &hv_context.percpu_list[cpu]); +} +static void percpu_channel_deq(void *arg) +{ + struct vmbus_channel *channel = arg; + + list_del(&channel->percpu_list); +} /* * vmbus_process_rescind_offer - @@ -210,6 +224,12 @@ static void vmbus_process_rescind_offer(struct work_struct *work) msg.header.msgtype = CHANNELMSG_RELID_RELEASED; vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released)); + if (channel->target_cpu != smp_processor_id()) + smp_call_function_single(channel->target_cpu, + percpu_channel_deq, channel, true); + else + percpu_channel_deq(channel); + if (channel->primary_channel == NULL) { spin_lock_irqsave(&vmbus_connection.channel_lock, flags); list_del(&channel->listentry); @@ -245,6 +265,7 @@ static void vmbus_process_offer(struct work_struct *work) work); struct vmbus_channel *channel; bool fnew = true; + bool enq = false; int ret; unsigned long flags; @@ -264,12 +285,22 @@ static void vmbus_process_offer(struct work_struct *work) } } - if (fnew) + if (fnew) { list_add_tail(&newchannel->listentry, &vmbus_connection.chn_list); + enq = true; + } spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); + if (enq) { + if (newchannel->target_cpu != smp_processor_id()) + smp_call_function_single(newchannel->target_cpu, + percpu_channel_enq, + newchannel, true); + else + percpu_channel_enq(newchannel); + } if (!fnew) { /* * Check to see if this is a sub-channel. @@ -282,6 +313,14 @@ static void vmbus_process_offer(struct work_struct *work) spin_lock_irqsave(&channel->sc_lock, flags); list_add_tail(&newchannel->sc_list, &channel->sc_list); spin_unlock_irqrestore(&channel->sc_lock, flags); + + if (newchannel->target_cpu != smp_processor_id()) + smp_call_function_single(newchannel->target_cpu, + percpu_channel_enq, + newchannel, true); + else + percpu_channel_enq(newchannel); + newchannel->state = CHANNEL_OPEN_STATE; if (channel->sc_creation_callback != NULL) channel->sc_creation_callback(newchannel); @@ -365,7 +404,7 @@ static u32 next_vp; * performance critical channels (IDE, SCSI and Network) will be uniformly * distributed across all available CPUs. */ -static u32 get_vp_index(uuid_le *type_guid) +static void init_vp_index(struct vmbus_channel *channel, uuid_le *type_guid) { u32 cur_cpu; int i; @@ -387,10 +426,13 @@ static u32 get_vp_index(uuid_le *type_guid) * Also if the channel is not a performance critical * channel, bind it to cpu 0. */ - return 0; + channel->target_cpu = 0; + channel->target_vp = 0; + return; } cur_cpu = (++next_vp % max_cpus); - return hv_context.vp_index[cur_cpu]; + channel->target_cpu = cur_cpu; + channel->target_vp = hv_context.vp_index[cur_cpu]; } /* @@ -438,7 +480,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) offer->connection_id; } - newchannel->target_vp = get_vp_index(&offer->offer.if_type); + init_vp_index(newchannel, &offer->offer.if_type); memcpy(&newchannel->offermsg, offer, sizeof(struct vmbus_channel_offer_channel)); diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 2e7801af466e58..7f10c151632acc 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -234,6 +234,28 @@ int vmbus_connect(void) return ret; } +/* + * Map the given relid to the corresponding channel based on the + * per-cpu list of channels that have been affinitized to this CPU. + * This will be used in the channel callback path as we can do this + * mapping in a lock-free fashion. + */ +static struct vmbus_channel *pcpu_relid2channel(u32 relid) +{ + struct vmbus_channel *channel; + struct vmbus_channel *found_channel = NULL; + int cpu = smp_processor_id(); + struct list_head *pcpu_head = &hv_context.percpu_list[cpu]; + + list_for_each_entry(channel, pcpu_head, percpu_list) { + if (channel->offermsg.child_relid == relid) { + found_channel = channel; + break; + } + } + + return found_channel; +} /* * relid2channel - Get the channel object given its @@ -277,7 +299,6 @@ struct vmbus_channel *relid2channel(u32 relid) static void process_chn_event(u32 relid) { struct vmbus_channel *channel; - unsigned long flags; void *arg; bool read_state; u32 bytes_to_read; @@ -286,7 +307,7 @@ static void process_chn_event(u32 relid) * Find the channel based on this relid and invokes the * channel callback to process the event */ - channel = relid2channel(relid); + channel = pcpu_relid2channel(relid); if (!channel) { pr_err("channel not found for relid - %u\n", relid); @@ -296,13 +317,12 @@ static void process_chn_event(u32 relid) /* * A channel once created is persistent even when there * is no driver handling the device. An unloading driver - * sets the onchannel_callback to NULL under the - * protection of the channel inbound_lock. Thus, checking - * and invoking the driver specific callback takes care of - * orderly unloading of the driver. + * sets the onchannel_callback to NULL on the same CPU + * as where this interrupt is handled (in an interrupt context). + * Thus, checking and invoking the driver specific callback takes + * care of orderly unloading of the driver. */ - spin_lock_irqsave(&channel->inbound_lock, flags); if (channel->onchannel_callback != NULL) { arg = channel->channel_callback_context; read_state = channel->batched_reading; @@ -327,7 +347,6 @@ static void process_chn_event(u32 relid) pr_err("no channel callback for relid - %u\n", relid); } - spin_unlock_irqrestore(&channel->inbound_lock, flags); } /* diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index bcb49502c3bf22..edfc8488cb0358 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -383,6 +383,8 @@ void hv_synic_init(void *arg) */ rdmsrl(HV_X64_MSR_VP_INDEX, vp_index); hv_context.vp_index[cpu] = (u32)vp_index; + + INIT_LIST_HEAD(&hv_context.percpu_list[cpu]); return; } diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 7e6d78dc9437de..5e90c5d771a7bf 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -19,6 +19,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -459,6 +460,11 @@ static bool do_hot_add; */ static uint pressure_report_delay = 45; +/* + * The last time we posted a pressure report to host. + */ +static unsigned long last_post_time; + module_param(hot_add, bool, (S_IRUGO | S_IWUSR)); MODULE_PARM_DESC(hot_add, "If set attempt memory hot_add"); @@ -542,6 +548,7 @@ struct hv_dynmem_device { static struct hv_dynmem_device dm_device; +static void post_status(struct hv_dynmem_device *dm); #ifdef CONFIG_MEMORY_HOTPLUG static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size) @@ -612,7 +619,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, * have not been "onlined" within the allowed time. */ wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ); - + post_status(&dm_device); } return; @@ -951,11 +958,17 @@ static void post_status(struct hv_dynmem_device *dm) { struct dm_status status; struct sysinfo val; + unsigned long now = jiffies; + unsigned long last_post = last_post_time; if (pressure_report_delay > 0) { --pressure_report_delay; return; } + + if (!time_after(now, (last_post_time + HZ))) + return; + si_meminfo(&val); memset(&status, 0, sizeof(struct dm_status)); status.hdr.type = DM_STATUS_REPORT; @@ -983,6 +996,14 @@ static void post_status(struct hv_dynmem_device *dm) if (status.hdr.trans_id != atomic_read(&trans_id)) return; + /* + * If the last post time that we sampled has changed, + * we have raced, don't post the status. + */ + if (last_post != last_post_time) + return; + + last_post_time = jiffies; vmbus_sendpacket(dm->dev->channel, &status, sizeof(struct dm_status), (unsigned long)NULL, @@ -1117,7 +1138,7 @@ static void balloon_up(struct work_struct *dummy) if (ret == -EAGAIN) msleep(20); - + post_status(&dm_device); } while (ret == -EAGAIN); if (ret) { @@ -1144,8 +1165,10 @@ static void balloon_down(struct hv_dynmem_device *dm, struct dm_unballoon_response resp; int i; - for (i = 0; i < range_count; i++) + for (i = 0; i < range_count; i++) { free_balloon_pages(dm, &range_array[i]); + post_status(&dm_device); + } if (req->more_pages == 1) return; diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 860134da80396c..18d1a8404cbc0e 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -510,6 +510,11 @@ struct hv_context { * basis. */ struct tasklet_struct *event_dpc[NR_CPUS]; + /* + * To optimize the mapping of relid to channel, maintain + * per-cpu list of the channels based on their CPU affinity. + */ + struct list_head percpu_list[NR_CPUS]; }; extern struct hv_context hv_context; diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 32f5132c4652d4..9e57b77ecd34ef 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -1387,10 +1387,8 @@ static int f71805f_probe(struct platform_device *pdev) data = devm_kzalloc(&pdev->dev, sizeof(struct f71805f_data), GFP_KERNEL); - if (!data) { - pr_err("Out of memory\n"); + if (!data) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(&pdev->dev, res->start + ADDR_REG_OFFSET, 2, diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c index 20ab0fb85395c8..030e7ff589be95 100644 --- a/drivers/hwmon/ibmpex.c +++ b/drivers/hwmon/ibmpex.c @@ -463,10 +463,8 @@ static void ibmpex_register_bmc(int iface, struct device *dev) int err; data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(dev, "Insufficient memory for BMC interface.\n"); + if (!data) return; - } data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; data->address.channel = IPMI_BMC_CHANNEL; diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 505a59e100b0b9..97204dce162db6 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -47,7 +47,7 @@ #define LM70_CHIP_LM74 3 /* NS LM74 */ struct lm70 { - struct device *hwmon_dev; + struct spi_device *spi; struct mutex lock; unsigned int chip; }; @@ -56,11 +56,11 @@ struct lm70 { static ssize_t lm70_sense_temp(struct device *dev, struct device_attribute *attr, char *buf) { - struct spi_device *spi = to_spi_device(dev); + struct lm70 *p_lm70 = dev_get_drvdata(dev); + struct spi_device *spi = p_lm70->spi; int status, val = 0; u8 rxbuf[2]; s16 raw = 0; - struct lm70 *p_lm70 = spi_get_drvdata(spi); if (mutex_lock_interruptible(&p_lm70->lock)) return -ERESTARTSYS; @@ -121,21 +121,20 @@ static ssize_t lm70_sense_temp(struct device *dev, static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL); -static ssize_t lm70_show_name(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - return sprintf(buf, "%s\n", to_spi_device(dev)->modalias); -} +static struct attribute *lm70_attrs[] = { + &dev_attr_temp1_input.attr, + NULL +}; -static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL); +ATTRIBUTE_GROUPS(lm70); /*----------------------------------------------------------------------*/ static int lm70_probe(struct spi_device *spi) { int chip = spi_get_device_id(spi)->driver_data; + struct device *hwmon_dev; struct lm70 *p_lm70; - int status; /* signaling is SPI_MODE_0 */ if (spi->mode & (SPI_CPOL | SPI_CPHA)) @@ -149,46 +148,14 @@ static int lm70_probe(struct spi_device *spi) mutex_init(&p_lm70->lock); p_lm70->chip = chip; + p_lm70->spi = spi; - spi_set_drvdata(spi, p_lm70); - - status = device_create_file(&spi->dev, &dev_attr_temp1_input); - if (status) - goto out_dev_create_temp_file_failed; - status = device_create_file(&spi->dev, &dev_attr_name); - if (status) - goto out_dev_create_file_failed; - - /* sysfs hook */ - p_lm70->hwmon_dev = hwmon_device_register(&spi->dev); - if (IS_ERR(p_lm70->hwmon_dev)) { - dev_dbg(&spi->dev, "hwmon_device_register failed.\n"); - status = PTR_ERR(p_lm70->hwmon_dev); - goto out_dev_reg_failed; - } - - return 0; - -out_dev_reg_failed: - device_remove_file(&spi->dev, &dev_attr_name); -out_dev_create_file_failed: - device_remove_file(&spi->dev, &dev_attr_temp1_input); -out_dev_create_temp_file_failed: - return status; + hwmon_dev = devm_hwmon_device_register_with_groups(&spi->dev, + spi->modalias, + p_lm70, lm70_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } -static int lm70_remove(struct spi_device *spi) -{ - struct lm70 *p_lm70 = spi_get_drvdata(spi); - - hwmon_device_unregister(p_lm70->hwmon_dev); - device_remove_file(&spi->dev, &dev_attr_temp1_input); - device_remove_file(&spi->dev, &dev_attr_name); - - return 0; -} - - static const struct spi_device_id lm70_ids[] = { { "lm70", LM70_CHIP_LM70 }, { "tmp121", LM70_CHIP_TMP121 }, @@ -205,7 +172,6 @@ static struct spi_driver lm70_driver = { }, .id_table = lm70_ids, .probe = lm70_probe, - .remove = lm70_remove, }; module_spi_driver(lm70_driver); diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 84a55eacd9034a..479ffbeed3f8a0 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -72,6 +72,7 @@ static const u8 LM75_REG_TEMP[3] = { /* Each client has this additional data */ struct lm75_data { + struct i2c_client *client; struct device *hwmon_dev; struct thermal_zone_device *tz; struct mutex update_lock; @@ -130,8 +131,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); - struct lm75_data *data = i2c_get_clientdata(client); + struct lm75_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int nr = attr->index; long temp; int error; @@ -165,17 +166,14 @@ static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp, set_temp, 2); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); -static struct attribute *lm75_attributes[] = { +static struct attribute *lm75_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, NULL }; - -static const struct attribute_group lm75_group = { - .attrs = lm75_attributes, -}; +ATTRIBUTE_GROUPS(lm75); /*-----------------------------------------------------------------------*/ @@ -184,6 +182,7 @@ static const struct attribute_group lm75_group = { static int lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct lm75_data *data; int status; u8 set_mask, clr_mask; @@ -194,10 +193,11 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) return -EIO; - data = devm_kzalloc(&client->dev, sizeof(struct lm75_data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL); if (!data) return -ENOMEM; + data->client = client; i2c_set_clientdata(client, data); mutex_init(&data->update_lock); @@ -269,7 +269,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) /* configure as specified */ status = lm75_read_value(client, LM75_REG_CONF); if (status < 0) { - dev_dbg(&client->dev, "Can't read config? %d\n", status); + dev_dbg(dev, "Can't read config? %d\n", status); return status; } data->orig_conf = status; @@ -277,43 +277,32 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) new |= set_mask; if (status != new) lm75_write_value(client, LM75_REG_CONF, new); - dev_dbg(&client->dev, "Config %02x\n", new); + dev_dbg(dev, "Config %02x\n", new); - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &lm75_group); - if (status) - return status; + data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, + data, lm75_groups); + if (IS_ERR(data->hwmon_dev)) + return PTR_ERR(data->hwmon_dev); - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - status = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - data->tz = thermal_zone_of_sensor_register(&client->dev, + data->tz = thermal_zone_of_sensor_register(data->hwmon_dev, 0, - &client->dev, + data->hwmon_dev, lm75_read_temp, NULL); if (IS_ERR(data->tz)) data->tz = NULL; - dev_info(&client->dev, "%s: sensor '%s'\n", + dev_info(dev, "%s: sensor '%s'\n", dev_name(data->hwmon_dev), client->name); return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &lm75_group); - return status; } static int lm75_remove(struct i2c_client *client) { struct lm75_data *data = i2c_get_clientdata(client); - thermal_zone_of_sensor_unregister(&client->dev, data->tz); + thermal_zone_of_sensor_unregister(data->hwmon_dev, data->tz); hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm75_group); lm75_write_value(client, LM75_REG_CONF, data->orig_conf); return 0; } @@ -507,8 +496,8 @@ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) static struct lm75_data *lm75_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm75_data *data = i2c_get_clientdata(client); + struct lm75_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct lm75_data *ret = data; mutex_lock(&data->update_lock); diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 502771c06fd99e..5ceb443b938d77 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -19,10 +19,6 @@ * 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 @@ -47,50 +43,33 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, #define LM77_REG_TEMP_MIN 0x04 #define LM77_REG_TEMP_MAX 0x05 +enum temp_index { + t_input = 0, + t_crit, + t_min, + t_max, + t_hyst, + t_num_temp +}; + +static const u8 temp_regs[t_num_temp] = { + [t_input] = LM77_REG_TEMP, + [t_min] = LM77_REG_TEMP_MIN, + [t_max] = LM77_REG_TEMP_MAX, + [t_crit] = LM77_REG_TEMP_CRIT, + [t_hyst] = LM77_REG_TEMP_HYST, +}; + /* Each client has this additional data */ struct lm77_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; unsigned long last_updated; /* In jiffies */ - int temp_input; /* Temperatures */ - int temp_crit; - int temp_min; - int temp_max; - int temp_hyst; + int temp[t_num_temp]; /* index using temp_index */ u8 alarms; }; -static int lm77_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info); -static void lm77_init_client(struct i2c_client *client); -static int lm77_remove(struct i2c_client *client); -static u16 lm77_read_value(struct i2c_client *client, u8 reg); -static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value); - -static struct lm77_data *lm77_update_device(struct device *dev); - - -static const struct i2c_device_id lm77_id[] = { - { "lm77", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, lm77_id); - -/* This is the driver that will be inserted */ -static struct i2c_driver lm77_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "lm77", - }, - .probe = lm77_probe, - .remove = lm77_remove, - .id_table = lm77_id, - .detect = lm77_detect, - .address_list = normal_i2c, -}; - /* straight from the datasheet */ #define LM77_TEMP_MIN (-55000) #define LM77_TEMP_MAX 125000 @@ -110,97 +89,109 @@ static inline int LM77_TEMP_FROM_REG(s16 reg) return (reg / 8) * 500; } -/* sysfs stuff */ - -/* read routines for temperature limits */ -#define show(value) \ -static ssize_t show_##value(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct lm77_data *data = lm77_update_device(dev); \ - return sprintf(buf, "%d\n", data->value); \ +/* + * All registers are word-sized, except for the configuration register. + * The LM77 uses the high-byte first convention. + */ +static u16 lm77_read_value(struct i2c_client *client, u8 reg) +{ + if (reg == LM77_REG_CONF) + return i2c_smbus_read_byte_data(client, reg); + else + return i2c_smbus_read_word_swapped(client, reg); } -show(temp_input); -show(temp_crit); -show(temp_min); -show(temp_max); +static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (reg == LM77_REG_CONF) + return i2c_smbus_write_byte_data(client, reg, value); + else + return i2c_smbus_write_word_swapped(client, reg, value); +} -/* read routines for hysteresis values */ -static ssize_t show_temp_crit_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static struct lm77_data *lm77_update_device(struct device *dev) { - struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst); + struct lm77_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int i; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Starting lm77 update\n"); + for (i = 0; i < t_num_temp; i++) { + data->temp[i] = + LM77_TEMP_FROM_REG(lm77_read_value(client, + temp_regs[i])); + } + data->alarms = + lm77_read_value(client, LM77_REG_TEMP) & 0x0007; + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; } -static ssize_t show_temp_min_hyst(struct device *dev, - struct device_attribute *attr, char *buf) + +/* sysfs stuff */ + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst); + + return sprintf(buf, "%d\n", data->temp[attr->index]); } -static ssize_t show_temp_max_hyst(struct device *dev, - struct device_attribute *attr, char *buf) + +static ssize_t show_temp_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst); -} + int nr = attr->index; + int temp; -/* write routines */ -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm77_data *data = i2c_get_clientdata(client); \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err) \ - return err; \ - \ - mutex_lock(&data->update_lock); \ - data->value = val; \ - lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value)); \ - mutex_unlock(&data->update_lock); \ - return count; \ -} + temp = nr == t_min ? data->temp[nr] + data->temp[t_hyst] : + data->temp[nr] - data->temp[t_hyst]; -set(temp_min, LM77_REG_TEMP_MIN); -set(temp_max, LM77_REG_TEMP_MAX); + return sprintf(buf, "%d\n", temp); +} -/* - * hysteresis is stored as a relative value on the chip, so it has to be - * converted first - */ -static ssize_t set_temp_crit_hyst(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - unsigned long val; + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm77_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int nr = attr->index; + long val; int err; - err = kstrtoul(buf, 10, &val); + err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); - data->temp_hyst = data->temp_crit - val; - lm77_write_value(client, LM77_REG_TEMP_HYST, - LM77_TEMP_TO_REG(data->temp_hyst)); + data->temp[nr] = val; + lm77_write_value(client, temp_regs[nr], LM77_TEMP_TO_REG(val)); mutex_unlock(&data->update_lock); return count; } -/* preserve hysteresis when setting T_crit */ -static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, +/* + * hysteresis is stored as a relative value on the chip, so it has to be + * converted first. + */ +static ssize_t set_temp_hyst(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - int oldcrithyst; + struct lm77_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int err; @@ -209,13 +200,9 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - oldcrithyst = data->temp_crit - data->temp_hyst; - data->temp_crit = val; - data->temp_hyst = data->temp_crit - oldcrithyst; - lm77_write_value(client, LM77_REG_TEMP_CRIT, - LM77_TEMP_TO_REG(data->temp_crit)); + data->temp[t_hyst] = data->temp[t_crit] - val; lm77_write_value(client, LM77_REG_TEMP_HYST, - LM77_TEMP_TO_REG(data->temp_hyst)); + LM77_TEMP_TO_REG(data->temp[t_hyst])); mutex_unlock(&data->update_lock); return count; } @@ -228,43 +215,37 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } -static DEVICE_ATTR(temp1_input, S_IRUGO, - show_temp_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, - show_temp_crit, set_temp_crit); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, - show_temp_min, set_temp_min); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, - show_temp_max, set_temp_max); - -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, - show_temp_crit_hyst, set_temp_crit_hyst); -static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, - show_temp_min_hyst, NULL); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, - show_temp_max_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_crit); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_min); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_max); + +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, + set_temp_hyst, t_crit); +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_hyst, NULL, t_min); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1); -static struct attribute *lm77_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp1_crit.attr, - &dev_attr_temp1_min.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_crit_hyst.attr, - &dev_attr_temp1_min_hyst.attr, - &dev_attr_temp1_max_hyst.attr, +static struct attribute *lm77_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, NULL }; - -static const struct attribute_group lm77_group = { - .attrs = lm77_attributes, -}; +ATTRIBUTE_GROUPS(lm77); /* Return 0 if detection is successful, -ENODEV otherwise */ static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info) @@ -337,111 +318,52 @@ static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info) return 0; } +static void lm77_init_client(struct i2c_client *client) +{ + /* Initialize the LM77 chip - turn off shutdown mode */ + int conf = lm77_read_value(client, LM77_REG_CONF); + if (conf & 1) + lm77_write_value(client, LM77_REG_CONF, conf & 0xfe); +} + static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; + struct device *hwmon_dev; struct lm77_data *data; - int err; data = devm_kzalloc(dev, sizeof(struct lm77_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); /* Initialize the LM77 chip */ lm77_init_client(client); - /* Register sysfs hooks */ - err = sysfs_create_group(&dev->kobj, &lm77_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - return 0; - -exit_remove: - sysfs_remove_group(&dev->kobj, &lm77_group); - return err; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, lm77_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } -static int lm77_remove(struct i2c_client *client) -{ - struct lm77_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm77_group); - return 0; -} - -/* - * All registers are word-sized, except for the configuration register. - * The LM77 uses the high-byte first convention. - */ -static u16 lm77_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == LM77_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return i2c_smbus_read_word_swapped(client, reg); -} - -static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == LM77_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_swapped(client, reg, value); -} - -static void lm77_init_client(struct i2c_client *client) -{ - /* Initialize the LM77 chip - turn off shutdown mode */ - int conf = lm77_read_value(client, LM77_REG_CONF); - if (conf & 1) - lm77_write_value(client, LM77_REG_CONF, conf & 0xfe); -} - -static struct lm77_data *lm77_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(&client->dev, "Starting lm77 update\n"); - data->temp_input = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP)); - data->temp_hyst = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_HYST)); - data->temp_crit = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_CRIT)); - data->temp_min = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_MIN)); - data->temp_max = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_MAX)); - data->alarms = - lm77_read_value(client, LM77_REG_TEMP) & 0x0007; - data->last_updated = jiffies; - data->valid = 1; - } - - mutex_unlock(&data->update_lock); +static const struct i2c_device_id lm77_id[] = { + { "lm77", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm77_id); - return data; -} +/* This is the driver that will be inserted */ +static struct i2c_driver lm77_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "lm77", + }, + .probe = lm77_probe, + .id_table = lm77_id, + .detect = lm77_detect, + .address_list = normal_i2c, +}; module_i2c_driver(lm77_driver); diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index b9022db6511ae4..d2060e245ff589 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -34,10 +34,6 @@ * 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 @@ -93,46 +89,53 @@ static inline u8 ALARMS_FROM_REG(s16 reg) return reg & 0x0007; } -/* Driver data (common to all clients) */ -static struct i2c_driver lm92_driver; +enum temp_index { + t_input, + t_crit, + t_min, + t_max, + t_hyst, + t_num_regs +}; + +static const u8 regs[t_num_regs] = { + [t_input] = LM92_REG_TEMP, + [t_crit] = LM92_REG_TEMP_CRIT, + [t_min] = LM92_REG_TEMP_LOW, + [t_max] = LM92_REG_TEMP_HIGH, + [t_hyst] = LM92_REG_TEMP_HYST, +}; /* Client data (each client gets its own) */ struct lm92_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ /* registers values */ - s16 temp1_input, temp1_crit, temp1_min, temp1_max, temp1_hyst; + s16 temp[t_num_regs]; /* index with enum temp_index */ }; - /* * Sysfs attributes and callback functions */ static struct lm92_data *lm92_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm92_data *data = i2c_get_clientdata(client); + struct lm92_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int i; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { dev_dbg(&client->dev, "Updating lm92 data\n"); - data->temp1_input = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP); - data->temp1_hyst = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP_HYST); - data->temp1_crit = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP_CRIT); - data->temp1_min = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP_LOW); - data->temp1_max = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP_HIGH); - + for (i = 0; i < t_num_regs; i++) { + data->temp[i] = + i2c_smbus_read_word_swapped(client, regs[i]); + } data->last_updated = jiffies; data->valid = 1; } @@ -142,68 +145,60 @@ static struct lm92_data *lm92_update_device(struct device *dev) return data; } -#define show_temp(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct lm92_data *data = lm92_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ -} -show_temp(temp1_input); -show_temp(temp1_crit); -show_temp(temp1_min); -show_temp(temp1_max); - -#define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \ - const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm92_data *data = i2c_get_clientdata(client); \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err) \ - return err; \ -\ - mutex_lock(&data->update_lock); \ - data->value = TEMP_TO_REG(val); \ - i2c_smbus_write_word_swapped(client, reg, data->value); \ - mutex_unlock(&data->update_lock); \ - return count; \ +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm92_data *data = lm92_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); } -set_temp(temp1_crit, LM92_REG_TEMP_CRIT); -set_temp(temp1_min, LM92_REG_TEMP_LOW); -set_temp(temp1_max, LM92_REG_TEMP_HIGH); -static ssize_t show_temp1_crit_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { - struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit) - - TEMP_FROM_REG(data->temp1_hyst)); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm92_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int nr = attr->index; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + data->temp[nr] = TEMP_TO_REG(val); + i2c_smbus_write_word_swapped(client, regs[nr], data->temp[nr]); + mutex_unlock(&data->update_lock); + return count; } -static ssize_t show_temp1_max_hyst(struct device *dev, - struct device_attribute *attr, char *buf) + +static ssize_t show_temp_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max) - - TEMP_FROM_REG(data->temp1_hyst)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]) + - TEMP_FROM_REG(data->temp[t_hyst])); } -static ssize_t show_temp1_min_hyst(struct device *dev, - struct device_attribute *attr, char *buf) + +static ssize_t show_temp_min_hyst(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min) - + TEMP_FROM_REG(data->temp1_hyst)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min]) + + TEMP_FROM_REG(data->temp[t_hyst])); } -static ssize_t set_temp1_crit_hyst(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t set_temp_hyst(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm92_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm92_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; int err; @@ -212,9 +207,9 @@ static ssize_t set_temp1_crit_hyst(struct device *dev, return err; mutex_lock(&data->update_lock); - data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val; + data->temp[t_hyst] = TEMP_FROM_REG(data->temp[attr->index]) - val; i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST, - TEMP_TO_REG(data->temp1_hyst)); + TEMP_TO_REG(data->temp[t_hyst])); mutex_unlock(&data->update_lock); return count; } @@ -223,7 +218,7 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input)); + return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp[t_input])); } static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, @@ -231,26 +226,25 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, { int bitnr = to_sensor_dev_attr(attr)->index; struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", (data->temp1_input >> bitnr) & 1); + return sprintf(buf, "%d\n", (data->temp[t_input] >> bitnr) & 1); } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit, - set_temp1_crit); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp1_crit_hyst, - set_temp1_crit_hyst); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp1_min, - set_temp1_min); -static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp1_min_hyst, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max, - set_temp1_max); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_crit); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, + set_temp_hyst, t_crit); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_min); +static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_min_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_max); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1); - /* * Detection and registration */ @@ -322,24 +316,21 @@ static int max6635_check(struct i2c_client *client) return 1; } -static struct attribute *lm92_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp1_crit.attr, - &dev_attr_temp1_crit_hyst.attr, - &dev_attr_temp1_min.attr, +static struct attribute *lm92_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, &dev_attr_temp1_min_hyst.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_max_hyst.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &dev_attr_alarms.attr, &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, NULL }; - -static const struct attribute_group lm92_group = { - .attrs = lm92_attributes, -}; +ATTRIBUTE_GROUPS(lm92); /* Return 0 if detection is successful, -ENODEV otherwise */ static int lm92_detect(struct i2c_client *new_client, @@ -371,46 +362,24 @@ static int lm92_detect(struct i2c_client *new_client, static int lm92_probe(struct i2c_client *new_client, const struct i2c_device_id *id) { + struct device *hwmon_dev; struct lm92_data *data; - int err; data = devm_kzalloc(&new_client->dev, sizeof(struct lm92_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(new_client, data); + data->client = new_client; mutex_init(&data->update_lock); /* Initialize the chipset */ lm92_init_client(new_client); - /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, &lm92_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - return 0; - -exit_remove: - sysfs_remove_group(&new_client->dev.kobj, &lm92_group); - return err; -} - -static int lm92_remove(struct i2c_client *client) -{ - struct lm92_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm92_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev, + new_client->name, + data, lm92_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } @@ -431,7 +400,6 @@ static struct i2c_driver lm92_driver = { .name = "lm92", }, .probe = lm92_probe, - .remove = lm92_remove, .id_table = lm92_id, .detect = lm92_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index adf23165a6a709..6c2df576f25304 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -2747,10 +2747,8 @@ static int lm93_probe(struct i2c_client *client, } data = devm_kzalloc(&client->dev, sizeof(struct lm93_data), GFP_KERNEL); - if (!data) { - dev_dbg(&client->dev, "out of memory!\n"); + if (!data) return -ENOMEM; - } i2c_set_clientdata(client, data); /* housekeeping */ diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index eda077de8a9f72..f67d71ee8386a4 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -192,10 +192,8 @@ static int max1111_probe(struct spi_device *spi) return err; data = devm_kzalloc(&spi->dev, sizeof(struct max1111_data), GFP_KERNEL); - if (data == NULL) { - dev_err(&spi->dev, "failed to allocate memory\n"); + if (data == NULL) return -ENOMEM; - } switch (chip) { case max1110: diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c index 96dccaf919d1da..82128ad79a911c 100644 --- a/drivers/hwmon/max197.c +++ b/drivers/hwmon/max197.c @@ -275,10 +275,8 @@ static int max197_probe(struct platform_device *pdev) } data = devm_kzalloc(&pdev->dev, sizeof(struct max197_data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "devm_kzalloc failed\n"); + if (!data) return -ENOMEM; - } data->pdata = pdata; mutex_init(&data->lock); diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index d847e0a084e0f6..9e4684e747eace 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -1081,10 +1081,8 @@ static int pc87427_probe(struct platform_device *pdev) data = devm_kzalloc(&pdev->dev, sizeof(struct pc87427_data), GFP_KERNEL); - if (!data) { - pr_err("Out of memory\n"); + if (!data) return -ENOMEM; - } data->address[0] = sio_data->address[0]; data->address[1] = sio_data->address[1]; diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c index 73bd64e8c30a8b..0674c13bbd4bff 100644 --- a/drivers/hwmon/s3c-hwmon.c +++ b/drivers/hwmon/s3c-hwmon.c @@ -285,10 +285,8 @@ static int s3c_hwmon_probe(struct platform_device *dev) } hwmon = devm_kzalloc(&dev->dev, sizeof(struct s3c_hwmon), GFP_KERNEL); - if (hwmon == NULL) { - dev_err(&dev->dev, "no memory\n"); + if (hwmon == NULL) return -ENOMEM; - } platform_set_drvdata(dev, hwmon); diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 6748b4583e7b35..51719956cc03f5 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -51,6 +51,7 @@ #define TMP102_THIGH_REG 0x03 struct tmp102 { + struct i2c_client *client; struct device *hwmon_dev; struct thermal_zone_device *tz; struct mutex lock; @@ -77,9 +78,10 @@ static const u8 tmp102_reg[] = { TMP102_THIGH_REG, }; -static struct tmp102 *tmp102_update_device(struct i2c_client *client) +static struct tmp102 *tmp102_update_device(struct device *dev) { - struct tmp102 *tmp102 = i2c_get_clientdata(client); + struct tmp102 *tmp102 = dev_get_drvdata(dev); + struct i2c_client *client = tmp102->client; mutex_lock(&tmp102->lock); if (time_after(jiffies, tmp102->last_update + HZ / 3)) { @@ -98,7 +100,7 @@ static struct tmp102 *tmp102_update_device(struct i2c_client *client) static int tmp102_read_temp(void *dev, long *temp) { - struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev)); + struct tmp102 *tmp102 = tmp102_update_device(dev); *temp = tmp102->temp[0]; @@ -110,7 +112,7 @@ static ssize_t tmp102_show_temp(struct device *dev, char *buf) { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); - struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev)); + struct tmp102 *tmp102 = tmp102_update_device(dev); return sprintf(buf, "%d\n", tmp102->temp[sda->index]); } @@ -120,8 +122,8 @@ static ssize_t tmp102_set_temp(struct device *dev, const char *buf, size_t count) { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); - struct i2c_client *client = to_i2c_client(dev); - struct tmp102 *tmp102 = i2c_get_clientdata(client); + struct tmp102 *tmp102 = dev_get_drvdata(dev); + struct i2c_client *client = tmp102->client; long val; int status; @@ -145,16 +147,13 @@ static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp, static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp, tmp102_set_temp, 2); -static struct attribute *tmp102_attributes[] = { +static struct attribute *tmp102_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, NULL }; - -static const struct attribute_group tmp102_attr_group = { - .attrs = tmp102_attributes, -}; +ATTRIBUTE_GROUPS(tmp102); #define TMP102_CONFIG (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1) #define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL) @@ -162,72 +161,68 @@ static const struct attribute_group tmp102_attr_group = { static int tmp102_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; + struct device *hwmon_dev; struct tmp102 *tmp102; int status; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - dev_err(&client->dev, + dev_err(dev, "adapter doesn't support SMBus word transactions\n"); return -ENODEV; } - tmp102 = devm_kzalloc(&client->dev, sizeof(*tmp102), GFP_KERNEL); + tmp102 = devm_kzalloc(dev, sizeof(*tmp102), GFP_KERNEL); if (!tmp102) return -ENOMEM; i2c_set_clientdata(client, tmp102); + tmp102->client = client; status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (status < 0) { - dev_err(&client->dev, "error reading config register\n"); + dev_err(dev, "error reading config register\n"); return status; } tmp102->config_orig = status; status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, TMP102_CONFIG); if (status < 0) { - dev_err(&client->dev, "error writing config register\n"); + dev_err(dev, "error writing config register\n"); goto fail_restore_config; } status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (status < 0) { - dev_err(&client->dev, "error reading config register\n"); + dev_err(dev, "error reading config register\n"); goto fail_restore_config; } status &= ~TMP102_CONFIG_RD_ONLY; if (status != TMP102_CONFIG) { - dev_err(&client->dev, "config settings did not stick\n"); + dev_err(dev, "config settings did not stick\n"); status = -ENODEV; goto fail_restore_config; } tmp102->last_update = jiffies - HZ; mutex_init(&tmp102->lock); - status = sysfs_create_group(&client->dev.kobj, &tmp102_attr_group); - if (status) { - dev_dbg(&client->dev, "could not create sysfs files\n"); + hwmon_dev = hwmon_device_register_with_groups(dev, client->name, + tmp102, tmp102_groups); + if (IS_ERR(hwmon_dev)) { + dev_dbg(dev, "unable to register hwmon device\n"); + status = PTR_ERR(hwmon_dev); goto fail_restore_config; } - tmp102->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(tmp102->hwmon_dev)) { - dev_dbg(&client->dev, "unable to register hwmon device\n"); - status = PTR_ERR(tmp102->hwmon_dev); - goto fail_remove_sysfs; - } - - tmp102->tz = thermal_zone_of_sensor_register(&client->dev, 0, - &client->dev, + tmp102->hwmon_dev = hwmon_dev; + tmp102->tz = thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev, tmp102_read_temp, NULL); if (IS_ERR(tmp102->tz)) tmp102->tz = NULL; - dev_info(&client->dev, "initialized\n"); + dev_info(dev, "initialized\n"); return 0; -fail_remove_sysfs: - sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group); fail_restore_config: i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, tmp102->config_orig); @@ -238,9 +233,8 @@ static int tmp102_remove(struct i2c_client *client) { struct tmp102 *tmp102 = i2c_get_clientdata(client); - thermal_zone_of_sensor_unregister(&client->dev, tmp102->tz); + thermal_zone_of_sensor_unregister(tmp102->hwmon_dev, tmp102->tz); hwmon_device_unregister(tmp102->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group); /* Stop monitoring if device was stopped originally */ if (tmp102->config_orig & TMP102_CONF_SD) { diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index ae26b06fa8190d..7bab7a9bedc669 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -69,7 +69,7 @@ static const struct i2c_device_id tmp421_id[] = { MODULE_DEVICE_TABLE(i2c, tmp421_id); struct tmp421_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; unsigned long last_updated; @@ -99,8 +99,8 @@ static int temp_from_u16(u16 reg) static struct tmp421_data *tmp421_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct tmp421_data *data = i2c_get_clientdata(client); + struct tmp421_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int i; mutex_lock(&data->update_lock); @@ -198,6 +198,11 @@ static const struct attribute_group tmp421_group = { .is_visible = tmp421_is_visible, }; +static const struct attribute_group *tmp421_groups[] = { + &tmp421_group, + NULL +}; + static int tmp421_init_client(struct i2c_client *client) { int config, config_orig; @@ -264,47 +269,26 @@ static int tmp421_detect(struct i2c_client *client, static int tmp421_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; + struct device *hwmon_dev; struct tmp421_data *data; int err; - data = devm_kzalloc(&client->dev, sizeof(struct tmp421_data), - GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct tmp421_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); mutex_init(&data->update_lock); data->channels = id->driver_data; + data->client = client; err = tmp421_init_client(client); if (err) return err; - err = sysfs_create_group(&client->dev.kobj, &tmp421_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - data->hwmon_dev = NULL; - goto exit_remove; - } - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &tmp421_group); - return err; -} - -static int tmp421_remove(struct i2c_client *client) -{ - struct tmp421_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &tmp421_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, tmp421_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static struct i2c_driver tmp421_driver = { @@ -313,7 +297,6 @@ static struct i2c_driver tmp421_driver = { .name = "tmp421", }, .probe = tmp421_probe, - .remove = tmp421_remove, .id_table = tmp421_id, .detect = tmp421_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 6b2f1a42b3ff9d..344b22ec25533e 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -1152,10 +1152,8 @@ static int vt1211_probe(struct platform_device *pdev) int i, err; data = devm_kzalloc(dev, sizeof(struct vt1211_data), GFP_KERNEL); - if (!data) { - dev_err(dev, "Out of memory\n"); + if (!data) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(dev, res->start, resource_size(res), diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 8fb46aab2d87d5..a04c49f2a0118a 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -416,6 +416,7 @@ config BLK_DEV_CY82C693 config BLK_DEV_CS5520 tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)" + depends on X86_32 || COMPILE_TEST select BLK_DEV_IDEDMA_PCI help Include support for PIO tuning and virtual DMA on the Cyrix MediaGX @@ -426,6 +427,7 @@ config BLK_DEV_CS5520 config BLK_DEV_CS5530 tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support" + depends on X86_32 || COMPILE_TEST select BLK_DEV_IDEDMA_PCI help Include support for UDMA on the Cyrix MediaGX 5530 chipset. This @@ -435,7 +437,7 @@ config BLK_DEV_CS5530 config BLK_DEV_CS5535 tristate "AMD CS5535 chipset support" - depends on X86 && !X86_64 + depends on X86_32 select BLK_DEV_IDEDMA_PCI help Include support for UDMA on the NSC/AMD CS5535 companion chipset. @@ -486,6 +488,7 @@ config BLK_DEV_JMICRON config BLK_DEV_SC1200 tristate "National SCx200 chipset support" + depends on X86_32 || COMPILE_TEST select BLK_DEV_IDEDMA_PCI help This driver adds support for the on-board IDE controller on the diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 16f69be820c7bb..ee880382e3bce5 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -188,10 +188,9 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, ledtrig_ide_activity(); - pr_debug("%s: %sing: block=%llu, sectors=%u, buffer=0x%08lx\n", + pr_debug("%s: %sing: block=%llu, sectors=%u\n", drive->name, rq_data_dir(rq) == READ ? "read" : "writ", - (unsigned long long)block, blk_rq_sectors(rq), - (unsigned long)rq->buffer); + (unsigned long long)block, blk_rq_sectors(rq)); if (hwif->rw_disk) hwif->rw_disk(drive, rq); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 2a744a91370e64..a3d3b1733c49c6 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -853,8 +853,9 @@ static int init_irq (ide_hwif_t *hwif) if (irq_handler == NULL) irq_handler = ide_intr; - if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif)) - goto out_up; + if (!host->get_lock) + if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif)) + goto out_up; #if !defined(__mc68000__) printk(KERN_INFO "%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name, @@ -1533,7 +1534,8 @@ static void ide_unregister(ide_hwif_t *hwif) ide_proc_unregister_port(hwif); - free_irq(hwif->irq, hwif); + if (!hwif->host->get_lock) + free_irq(hwif->irq, hwif); device_unregister(hwif->portdev); device_unregister(&hwif->gendev); diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 5dd0e120a504cd..743485e4d6f83c 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -74,6 +74,7 @@ if IIO_TRIGGER source "drivers/iio/trigger/Kconfig" endif #IIO_TRIGGER source "drivers/iio/pressure/Kconfig" +source "drivers/iio/proximity/Kconfig" source "drivers/iio/temperature/Kconfig" endif # IIO diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 887d39090d7568..698afc2d17ce84 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -24,5 +24,6 @@ obj-y += light/ obj-y += magnetometer/ obj-y += orientation/ obj-y += pressure/ +obj-y += proximity/ obj-y += temperature/ obj-y += trigger/ diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index e23e50850655f3..1e120fa1e156c6 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -65,4 +65,16 @@ config KXSD9 Say yes here to build support for the Kionix KXSD9 accelerometer. Currently this only supports the device via an SPI interface. +config MMA8452 + tristate "Freescale MMA8452Q Accelerometer Driver" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the Freescale MMA8452Q 3-axis + accelerometer. + + To compile this driver as a module, choose M here: the module + will be called mma8452. + endmenu diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index c48d15f25616a7..dc0e379c2592e4 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_BMA180) += bma180.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o obj-$(CONFIG_KXSD9) += kxsd9.o +obj-$(CONFIG_MMA8452) += mma8452.o obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o st_accel-y := st_accel_core.o diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 3dcdbad654565f..69abf9163df7e3 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,10 @@ struct accel_3d_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX]; u32 accel_val[ACCEL_3D_CHANNEL_MAX]; + int scale_pre_decml; + int scale_post_decml; + int scale_precision; + int value_offset; }; static const u32 accel_3d_addresses[ACCEL_3D_CHANNEL_MAX] = { @@ -56,6 +61,7 @@ static const struct iio_chan_spec accel_3d_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_X, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -65,6 +71,7 @@ static const struct iio_chan_spec accel_3d_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Y, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -74,6 +81,7 @@ static const struct iio_chan_spec accel_3d_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Z, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -104,31 +112,42 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev, u32 address; int ret; int ret_type; + s32 poll_value; *val = 0; *val2 = 0; switch (mask) { case 0: + poll_value = hid_sensor_read_poll_value( + &accel_state->common_attributes); + if (poll_value < 0) + return -EINVAL; + + hid_sensor_power_state(&accel_state->common_attributes, true); + msleep_interruptible(poll_value * 2); report_id = accel_state->accel[chan->scan_index].report_id; address = accel_3d_addresses[chan->scan_index]; if (report_id >= 0) *val = sensor_hub_input_attr_get_raw_value( - accel_state->common_attributes.hsdev, - HID_USAGE_SENSOR_ACCEL_3D, address, - report_id); + accel_state->common_attributes.hsdev, + HID_USAGE_SENSOR_ACCEL_3D, address, + report_id); else { *val = 0; + hid_sensor_power_state(&accel_state->common_attributes, + false); return -EINVAL; } + hid_sensor_power_state(&accel_state->common_attributes, false); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: - *val = accel_state->accel[CHANNEL_SCAN_INDEX_X].units; - ret_type = IIO_VAL_INT; + *val = accel_state->scale_pre_decml; + *val2 = accel_state->scale_post_decml; + ret_type = accel_state->scale_precision; break; case IIO_CHAN_INFO_OFFSET: - *val = hid_sensor_convert_exponent( - accel_state->accel[CHANNEL_SCAN_INDEX_X].unit_expo); + *val = accel_state->value_offset; ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SAMP_FREQ: @@ -197,9 +216,8 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev, struct iio_dev *indio_dev = platform_get_drvdata(priv); struct accel_3d_state *accel_state = iio_priv(indio_dev); - dev_dbg(&indio_dev->dev, "accel_3d_proc_event [%d]\n", - accel_state->common_attributes.data_ready); - if (accel_state->common_attributes.data_ready) + dev_dbg(&indio_dev->dev, "accel_3d_proc_event\n"); + if (atomic_read(&accel_state->common_attributes.data_ready)) hid_sensor_push_data(indio_dev, accel_state->accel_val, sizeof(accel_state->accel_val)); @@ -262,6 +280,11 @@ static int accel_3d_parse_report(struct platform_device *pdev, st->accel[1].index, st->accel[1].report_id, st->accel[2].index, st->accel[2].report_id); + st->scale_precision = hid_sensor_format_scale( + HID_USAGE_SENSOR_ACCEL_3D, + &st->accel[CHANNEL_SCAN_INDEX_X], + &st->scale_pre_decml, &st->scale_post_decml); + /* Set Sensitivity field ids, when there is no individual modifier */ if (st->common_attributes.sensitivity.index < 0) { sensor_hub_input_get_attribute_info(hsdev, @@ -333,7 +356,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); goto error_free_dev_mem; } - accel_state->common_attributes.data_ready = false; + atomic_set(&accel_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, &accel_state->common_attributes); if (ret < 0) { diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c new file mode 100644 index 00000000000000..17aeea1705665f --- /dev/null +++ b/drivers/iio/accel/mma8452.c @@ -0,0 +1,439 @@ +/* + * mma8452.c - Support for Freescale MMA8452Q 3-axis 12-bit accelerometer + * + * Copyright 2014 Peter Meerwald + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * 7-bit I2C slave address 0x1c/0x1d (pin selectable) + * + * TODO: interrupt, thresholding, orientation / freefall events, autosleep + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MMA8452_STATUS 0x00 +#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */ +#define MMA8452_OUT_Y 0x03 +#define MMA8452_OUT_Z 0x05 +#define MMA8452_WHO_AM_I 0x0d +#define MMA8452_DATA_CFG 0x0e +#define MMA8452_OFF_X 0x2f +#define MMA8452_OFF_Y 0x30 +#define MMA8452_OFF_Z 0x31 +#define MMA8452_CTRL_REG1 0x2a +#define MMA8452_CTRL_REG2 0x2b + +#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) + +#define MMA8452_CTRL_DR_MASK (BIT(5) | BIT(4) | BIT(3)) +#define MMA8452_CTRL_DR_SHIFT 3 +#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ +#define MMA8452_CTRL_ACTIVE BIT(0) + +#define MMA8452_DATA_CFG_FS_MASK (BIT(1) | BIT(0)) +#define MMA8452_DATA_CFG_FS_2G 0 +#define MMA8452_DATA_CFG_FS_4G 1 +#define MMA8452_DATA_CFG_FS_8G 2 + +#define MMA8452_DEVICE_ID 0x2a + +struct mma8452_data { + struct i2c_client *client; + struct mutex lock; + u8 ctrl_reg1; + u8 data_cfg; +}; + +static int mma8452_drdy(struct mma8452_data *data) +{ + int tries = 150; + + while (tries-- > 0) { + int ret = i2c_smbus_read_byte_data(data->client, + MMA8452_STATUS); + if (ret < 0) + return ret; + if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY) + return 0; + msleep(20); + } + + dev_err(&data->client->dev, "data not ready\n"); + return -EIO; +} + +static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) +{ + int ret = mma8452_drdy(data); + if (ret < 0) + return ret; + return i2c_smbus_read_i2c_block_data(data->client, + MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf); +} + +static ssize_t mma8452_show_int_plus_micros(char *buf, + const int (*vals)[2], int n) +{ + size_t len = 0; + + while (n-- > 0) + len += scnprintf(buf + len, PAGE_SIZE - len, + "%d.%06d ", vals[n][0], vals[n][1]); + + /* replace trailing space by newline */ + buf[len - 1] = '\n'; + + return len; +} + +static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n, + int val, int val2) +{ + while (n-- > 0) + if (val == vals[n][0] && val2 == vals[n][1]) + return n; + + return -EINVAL; +} + +static const int mma8452_samp_freq[8][2] = { + {800, 0}, {400, 0}, {200, 0}, {100, 0}, {50, 0}, {12, 500000}, + {6, 250000}, {1, 560000} +}; + +static const int mma8452_scales[3][2] = { + {0, 977}, {0, 1953}, {0, 3906} +}; + +static ssize_t mma8452_show_samp_freq_avail(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return mma8452_show_int_plus_micros(buf, mma8452_samp_freq, + ARRAY_SIZE(mma8452_samp_freq)); +} + +static ssize_t mma8452_show_scale_avail(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return mma8452_show_int_plus_micros(buf, mma8452_scales, + ARRAY_SIZE(mma8452_scales)); +} + +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail); +static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO, + mma8452_show_scale_avail, NULL, 0); + +static int mma8452_get_samp_freq_index(struct mma8452_data *data, + int val, int val2) +{ + return mma8452_get_int_plus_micros_index(mma8452_samp_freq, + ARRAY_SIZE(mma8452_samp_freq), val, val2); +} + +static int mma8452_get_scale_index(struct mma8452_data *data, + int val, int val2) +{ + return mma8452_get_int_plus_micros_index(mma8452_scales, + ARRAY_SIZE(mma8452_scales), val, val2); +} + +static int mma8452_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct mma8452_data *data = iio_priv(indio_dev); + __be16 buffer[3]; + int i, ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + + mutex_lock(&data->lock); + ret = mma8452_read(data, buffer); + mutex_unlock(&data->lock); + if (ret < 0) + return ret; + *val = sign_extend32( + be16_to_cpu(buffer[chan->scan_index]) >> 4, 11); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK; + *val = mma8452_scales[i][0]; + *val2 = mma8452_scales[i][1]; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + i = (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >> + MMA8452_CTRL_DR_SHIFT; + *val = mma8452_samp_freq[i][0]; + *val2 = mma8452_samp_freq[i][1]; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_CALIBBIAS: + ret = i2c_smbus_read_byte_data(data->client, MMA8452_OFF_X + + chan->scan_index); + if (ret < 0) + return ret; + *val = sign_extend32(ret, 7); + return IIO_VAL_INT; + } + return -EINVAL; +} + +static int mma8452_standby(struct mma8452_data *data) +{ + return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, + data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE); +} + +static int mma8452_active(struct mma8452_data *data) +{ + return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, + data->ctrl_reg1); +} + +static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val) +{ + int ret; + + mutex_lock(&data->lock); + + /* config can only be changed when in standby */ + ret = mma8452_standby(data); + if (ret < 0) + goto fail; + + ret = i2c_smbus_write_byte_data(data->client, reg, val); + if (ret < 0) + goto fail; + + ret = mma8452_active(data); + if (ret < 0) + goto fail; + + ret = 0; +fail: + mutex_unlock(&data->lock); + return ret; +} + +static int mma8452_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct mma8452_data *data = iio_priv(indio_dev); + int i; + + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + i = mma8452_get_samp_freq_index(data, val, val2); + if (i < 0) + return -EINVAL; + + data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; + data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; + return mma8452_change_config(data, MMA8452_CTRL_REG1, + data->ctrl_reg1); + case IIO_CHAN_INFO_SCALE: + i = mma8452_get_scale_index(data, val, val2); + if (i < 0) + return -EINVAL; + data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; + data->data_cfg |= i; + return mma8452_change_config(data, MMA8452_DATA_CFG, + data->data_cfg); + case IIO_CHAN_INFO_CALIBBIAS: + if (val < -128 || val > 127) + return -EINVAL; + return mma8452_change_config(data, MMA8452_OFF_X + + chan->scan_index, val); + default: + return -EINVAL; + } +} + +static irqreturn_t mma8452_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct mma8452_data *data = iio_priv(indio_dev); + u8 buffer[16]; /* 3 16-bit channels + padding + ts */ + int ret; + + ret = mma8452_read(data, (__be16 *) buffer); + if (ret < 0) + goto done; + + iio_push_to_buffers_with_timestamp(indio_dev, buffer, + iio_get_time_ns()); + +done: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +#define MMA8452_CHANNEL(axis, idx) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = idx, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .shift = 4, \ + .endianness = IIO_BE, \ + }, \ +} + +static const struct iio_chan_spec mma8452_channels[] = { + MMA8452_CHANNEL(X, 0), + MMA8452_CHANNEL(Y, 1), + MMA8452_CHANNEL(Z, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static struct attribute *mma8452_attributes[] = { + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_in_accel_scale_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group mma8452_group = { + .attrs = mma8452_attributes, +}; + +static const struct iio_info mma8452_info = { + .attrs = &mma8452_group, + .read_raw = &mma8452_read_raw, + .write_raw = &mma8452_write_raw, + .driver_module = THIS_MODULE, +}; + +static const unsigned long mma8452_scan_masks[] = {0x7, 0}; + +static int mma8452_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct mma8452_data *data; + struct iio_dev *indio_dev; + int ret; + + ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); + if (ret < 0) + return ret; + if (ret != MMA8452_DEVICE_ID) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + mutex_init(&data->lock); + + i2c_set_clientdata(client, indio_dev); + indio_dev->info = &mma8452_info; + indio_dev->name = id->name; + indio_dev->dev.parent = &client->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = mma8452_channels; + indio_dev->num_channels = ARRAY_SIZE(mma8452_channels); + indio_dev->available_scan_masks = mma8452_scan_masks; + + data->ctrl_reg1 = MMA8452_CTRL_ACTIVE | + (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT); + ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1, + data->ctrl_reg1); + if (ret < 0) + return ret; + + data->data_cfg = MMA8452_DATA_CFG_FS_2G; + ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG, + data->data_cfg); + if (ret < 0) + return ret; + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + mma8452_trigger_handler, NULL); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) + goto buffer_cleanup; + return 0; + +buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); + return ret; +} + +static int mma8452_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + mma8452_standby(iio_priv(indio_dev)); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mma8452_suspend(struct device *dev) +{ + return mma8452_standby(iio_priv(i2c_get_clientdata( + to_i2c_client(dev)))); +} + +static int mma8452_resume(struct device *dev) +{ + return mma8452_active(iio_priv(i2c_get_clientdata( + to_i2c_client(dev)))); +} + +static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume); +#define MMA8452_PM_OPS (&mma8452_pm_ops) +#else +#define MMA8452_PM_OPS NULL +#endif + +static const struct i2c_device_id mma8452_id[] = { + { "mma8452", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mma8452_id); + +static struct i2c_driver mma8452_driver = { + .driver = { + .name = "mma8452", + .pm = MMA8452_PM_OPS, + }, + .probe = mma8452_probe, + .remove = mma8452_remove, + .id_table = mma8452_id, +}; +module_i2c_driver(mma8452_driver); + +MODULE_AUTHOR("Peter Meerwald "); +MODULE_DESCRIPTION("Freescale MMA8452 accelerometer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 38caedc76b98f2..a2abf7c2ce3be4 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -459,6 +459,8 @@ int st_accel_common_probe(struct iio_dev *indio_dev, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &accel_info; + st_sensors_power_enable(indio_dev); + err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_accel_sensors), st_accel_sensors); if (err < 0) @@ -496,6 +498,9 @@ int st_accel_common_probe(struct iio_dev *indio_dev, if (err) goto st_accel_device_register_error; + dev_info(&indio_dev->dev, "registered accelerometer %s\n", + indio_dev->name); + return 0; st_accel_device_register_error: @@ -512,6 +517,8 @@ void st_accel_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *adata = iio_priv(indio_dev); + st_sensors_power_disable(indio_dev); + iio_device_unregister(indio_dev); if (adata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 24c28e3f93a3c9..90f596db940da4 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -96,6 +96,17 @@ config AD7923 To compile this driver as a module, choose M here: the module will be called ad7923. +config AD799X + tristate "Analog Devices AD799x ADC driver" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Analog Devices: + ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998 + i2c analog to digital converters (ADC). Provides direct access + via sysfs. + config AT91_ADC tristate "Atmel AT91 ADC" depends on ARCH_AT91 @@ -107,7 +118,7 @@ config AT91_ADC config EXYNOS_ADC tristate "Exynos ADC driver support" - depends on OF + depends on ARCH_EXYNOS || (OF && COMPILE_TEST) help Core support for the ADC block found in the Samsung EXYNOS series of SoCs for drivers such as the touchscreen and hwmon to use to share @@ -146,11 +157,12 @@ config MCP320X called mcp320x. config MCP3422 - tristate "Microchip Technology MCP3422/3/4 driver" + tristate "Microchip Technology MCP3422/3/4/6/7/8 driver" depends on I2C help - Say yes here to build support for Microchip Technology's MCP3422, - MCP3423 or MCP3424 analog to digital converters. + Say yes here to build support for Microchip Technology's + MCP3422, MCP3423, MCP3424, MCP3426, MCP3427 or MCP3428 + analog to digital converters. This driver can also be built as a module. If so, the module will be called mcp3422. diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ab346d88c68874..9d60f2deaaaf27 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7887) += ad7887.o +obj-$(CONFIG_AD799X) += ad799x.o obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/iio/adc/ad799x.c similarity index 80% rename from drivers/staging/iio/adc/ad799x_core.c rename to drivers/iio/adc/ad799x.c index 979ec77d6c2d1b..39b4cb48d738c8 100644 --- a/drivers/staging/iio/adc/ad799x_core.c +++ b/drivers/iio/adc/ad799x.c @@ -37,8 +37,144 @@ #include #include #include +#include +#include -#include "ad799x.h" +#define AD799X_CHANNEL_SHIFT 4 +#define AD799X_STORAGEBITS 16 +/* + * AD7991, AD7995 and AD7999 defines + */ + +#define AD7991_REF_SEL 0x08 +#define AD7991_FLTR 0x04 +#define AD7991_BIT_TRIAL_DELAY 0x02 +#define AD7991_SAMPLE_DELAY 0x01 + +/* + * AD7992, AD7993, AD7994, AD7997 and AD7998 defines + */ + +#define AD7998_FLTR 0x08 +#define AD7998_ALERT_EN 0x04 +#define AD7998_BUSY_ALERT 0x02 +#define AD7998_BUSY_ALERT_POL 0x01 + +#define AD7998_CONV_RES_REG 0x0 +#define AD7998_ALERT_STAT_REG 0x1 +#define AD7998_CONF_REG 0x2 +#define AD7998_CYCLE_TMR_REG 0x3 + +#define AD7998_DATALOW_REG(x) ((x) * 3 + 0x4) +#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5) +#define AD7998_HYST_REG(x) ((x) * 3 + 0x6) + +#define AD7998_CYC_MASK 0x7 +#define AD7998_CYC_DIS 0x0 +#define AD7998_CYC_TCONF_32 0x1 +#define AD7998_CYC_TCONF_64 0x2 +#define AD7998_CYC_TCONF_128 0x3 +#define AD7998_CYC_TCONF_256 0x4 +#define AD7998_CYC_TCONF_512 0x5 +#define AD7998_CYC_TCONF_1024 0x6 +#define AD7998_CYC_TCONF_2048 0x7 + +#define AD7998_ALERT_STAT_CLEAR 0xFF + +/* + * AD7997 and AD7997 defines + */ + +#define AD7997_8_READ_SINGLE 0x80 +#define AD7997_8_READ_SEQUENCE 0x70 +/* TODO: move this into a common header */ +#define RES_MASK(bits) ((1 << (bits)) - 1) + +enum { + ad7991, + ad7995, + ad7999, + ad7992, + ad7993, + ad7994, + ad7997, + ad7998 +}; + +/** + * struct ad799x_chip_info - chip specific information + * @channel: channel specification + * @num_channels: number of channels + * @monitor_mode: whether the chip supports monitor interrupts + * @default_config: device default configuration + * @event_attrs: pointer to the monitor event attribute group + */ +struct ad799x_chip_info { + struct iio_chan_spec channel[9]; + int num_channels; + u16 default_config; + const struct iio_info *info; +}; + +struct ad799x_state { + struct i2c_client *client; + const struct ad799x_chip_info *chip_info; + struct regulator *reg; + struct regulator *vref; + unsigned id; + u16 config; + + u8 *rx_buf; + unsigned int transfer_size; +}; + +/** + * ad799x_trigger_handler() bh of trigger launched polling to ring buffer + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + **/ +static irqreturn_t ad799x_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad799x_state *st = iio_priv(indio_dev); + int b_sent; + u8 cmd; + + switch (st->id) { + case ad7991: + case ad7995: + case ad7999: + cmd = st->config | + (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT); + break; + case ad7992: + case ad7993: + case ad7994: + cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) | + AD7998_CONV_RES_REG; + break; + case ad7997: + case ad7998: + cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG; + break; + default: + cmd = 0; + } + + b_sent = i2c_smbus_read_i2c_block_data(st->client, + cmd, st->transfer_size, st->rx_buf); + if (b_sent < 0) + goto out; + + iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, + iio_get_time_ns()); +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} /* * ad799x register access by I2C @@ -578,9 +714,10 @@ static int ad799x_probe(struct i2c_client *client, indio_dev->channels = st->chip_info->channel; indio_dev->num_channels = st->chip_info->num_channels; - ret = ad799x_register_ring_funcs_and_init(indio_dev); + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &ad799x_trigger_handler, NULL); if (ret) - goto error_disable_reg; + goto error_disable_vref; if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, @@ -601,12 +738,11 @@ static int ad799x_probe(struct i2c_client *client, return 0; error_cleanup_ring: - ad799x_ring_cleanup(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); +error_disable_vref: + regulator_disable(st->vref); error_disable_reg: - if (!IS_ERR(st->vref)) - regulator_disable(st->vref); - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); + regulator_disable(st->reg); return ret; } @@ -618,11 +754,9 @@ static int ad799x_remove(struct i2c_client *client) iio_device_unregister(indio_dev); - ad799x_ring_cleanup(indio_dev); - if (!IS_ERR(st->vref)) - regulator_disable(st->vref); - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); + iio_triggered_buffer_cleanup(indio_dev); + regulator_disable(st->vref); + regulator_disable(st->reg); kfree(st->rx_buf); return 0; diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index affa93f517893b..010578f1d76264 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -82,7 +82,7 @@ enum adc_version { #define ADC_CON_EN_START (1u << 0) #define ADC_DATX_MASK 0xFFF -#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(1000)) +#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) struct exynos_adc { void __iomem *regs; @@ -112,6 +112,30 @@ static inline unsigned int exynos_adc_get_version(struct platform_device *pdev) return (unsigned int)match->data; } +static void exynos_adc_hw_init(struct exynos_adc *info) +{ + u32 con1, con2; + + if (info->version == ADC_V2) { + con1 = ADC_V2_CON1_SOFT_RESET; + writel(con1, ADC_V2_CON1(info->regs)); + + con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL | + ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0); + writel(con2, ADC_V2_CON2(info->regs)); + + /* Enable interrupts */ + writel(1, ADC_V2_INT_EN(info->regs)); + } else { + /* set default prescaler values and Enable prescaler */ + con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; + + /* Enable 12-bit ADC resolution */ + con1 |= ADC_V1_CON_RES; + writel(con1, ADC_V1_CON(info->regs)); + } +} + static int exynos_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, @@ -121,11 +145,13 @@ static int exynos_read_raw(struct iio_dev *indio_dev, struct exynos_adc *info = iio_priv(indio_dev); unsigned long timeout; u32 con1, con2; + int ret; if (mask != IIO_CHAN_INFO_RAW) return -EINVAL; mutex_lock(&indio_dev->mlock); + reinit_completion(&info->completion); /* Select the channel to be used and Trigger conversion */ if (info->version == ADC_V2) { @@ -145,16 +171,21 @@ static int exynos_read_raw(struct iio_dev *indio_dev, ADC_V1_CON(info->regs)); } - timeout = wait_for_completion_interruptible_timeout + timeout = wait_for_completion_timeout (&info->completion, EXYNOS_ADC_TIMEOUT); - *val = info->value; + if (timeout == 0) { + dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); + exynos_adc_hw_init(info); + ret = -ETIMEDOUT; + } else { + *val = info->value; + *val2 = 0; + ret = IIO_VAL_INT; + } mutex_unlock(&indio_dev->mlock); - if (timeout == 0) - return -ETIMEDOUT; - - return IIO_VAL_INT; + return ret; } static irqreturn_t exynos_adc_isr(int irq, void *dev_id) @@ -226,30 +257,6 @@ static int exynos_adc_remove_devices(struct device *dev, void *c) return 0; } -static void exynos_adc_hw_init(struct exynos_adc *info) -{ - u32 con1, con2; - - if (info->version == ADC_V2) { - con1 = ADC_V2_CON1_SOFT_RESET; - writel(con1, ADC_V2_CON1(info->regs)); - - con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL | - ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0); - writel(con2, ADC_V2_CON2(info->regs)); - - /* Enable interrupts */ - writel(1, ADC_V2_INT_EN(info->regs)); - } else { - /* set default prescaler values and Enable prescaler */ - con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; - - /* Enable 12-bit ADC resolution */ - con1 |= ADC_V1_CON_RES; - writel(con1, ADC_V1_CON(info->regs)); - } -} - static int exynos_adc_probe(struct platform_device *pdev) { struct exynos_adc *info = NULL; @@ -290,32 +297,30 @@ static int exynos_adc_probe(struct platform_device *pdev) init_completion(&info->completion); - ret = request_irq(info->irq, exynos_adc_isr, - 0, dev_name(&pdev->dev), info); - if (ret < 0) { - dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", - info->irq); - return ret; - } - - writel(1, info->enable_reg); - info->clk = devm_clk_get(&pdev->dev, "adc"); if (IS_ERR(info->clk)) { dev_err(&pdev->dev, "failed getting clock, err = %ld\n", PTR_ERR(info->clk)); - ret = PTR_ERR(info->clk); - goto err_irq; + return PTR_ERR(info->clk); } info->vdd = devm_regulator_get(&pdev->dev, "vdd"); if (IS_ERR(info->vdd)) { dev_err(&pdev->dev, "failed getting regulator, err = %ld\n", PTR_ERR(info->vdd)); - ret = PTR_ERR(info->vdd); - goto err_irq; + return PTR_ERR(info->vdd); } + ret = regulator_enable(info->vdd); + if (ret) + return ret; + + ret = clk_prepare_enable(info->clk); + if (ret) + goto err_disable_reg; + + writel(1, info->enable_reg); + info->version = exynos_adc_get_version(pdev); platform_set_drvdata(pdev, indio_dev); @@ -332,16 +337,18 @@ static int exynos_adc_probe(struct platform_device *pdev) else indio_dev->num_channels = MAX_ADC_V2_CHANNELS; + ret = request_irq(info->irq, exynos_adc_isr, + 0, dev_name(&pdev->dev), info); + if (ret < 0) { + dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", + info->irq); + goto err_disable_clk; + } + ret = iio_device_register(indio_dev); if (ret) goto err_irq; - ret = regulator_enable(info->vdd); - if (ret) - goto err_iio_dev; - - clk_prepare_enable(info->clk); - exynos_adc_hw_init(info); ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev); @@ -355,12 +362,14 @@ static int exynos_adc_probe(struct platform_device *pdev) err_of_populate: device_for_each_child(&indio_dev->dev, NULL, exynos_adc_remove_devices); - regulator_disable(info->vdd); - clk_disable_unprepare(info->clk); -err_iio_dev: iio_device_unregister(indio_dev); err_irq: free_irq(info->irq, info); +err_disable_clk: + writel(0, info->enable_reg); + clk_disable_unprepare(info->clk); +err_disable_reg: + regulator_disable(info->vdd); return ret; } @@ -371,11 +380,11 @@ static int exynos_adc_remove(struct platform_device *pdev) device_for_each_child(&indio_dev->dev, NULL, exynos_adc_remove_devices); - regulator_disable(info->vdd); - clk_disable_unprepare(info->clk); - writel(0, info->enable_reg); iio_device_unregister(indio_dev); free_irq(info->irq, info); + writel(0, info->enable_reg); + clk_disable_unprepare(info->clk); + regulator_disable(info->vdd); return 0; } @@ -397,8 +406,8 @@ static int exynos_adc_suspend(struct device *dev) writel(con, ADC_V1_CON(info->regs)); } - clk_disable_unprepare(info->clk); writel(0, info->enable_reg); + clk_disable_unprepare(info->clk); regulator_disable(info->vdd); return 0; @@ -414,9 +423,11 @@ static int exynos_adc_resume(struct device *dev) if (ret) return ret; - writel(1, info->enable_reg); - clk_prepare_enable(info->clk); + ret = clk_prepare_enable(info->clk); + if (ret) + return ret; + writel(1, info->enable_reg); exynos_adc_hw_init(info); return 0; diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index 47dcb34ff44c47..51672256072bc8 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -1,10 +1,11 @@ /* - * mcp3422.c - driver for the Microchip mcp3422/3/4 chip family + * mcp3422.c - driver for the Microchip mcp3422/3/4/6/7/8 chip family * * Copyright (C) 2013, Angelo Compagnucci * Author: Angelo Compagnucci * * Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf + * http://ww1.microchip.com/downloads/en/DeviceDoc/22226a.pdf * * This driver exports the value of analog input voltage to sysfs, the * voltage unit is nV. @@ -96,6 +97,7 @@ static const int mcp3422_sign_extend[4] = { /* Client data (each client gets its own) */ struct mcp3422 { struct i2c_client *i2c; + u8 id; u8 config; u8 pga[4]; struct mutex lock; @@ -238,6 +240,8 @@ static int mcp3422_write_raw(struct iio_dev *iio, temp = MCP3422_SRATE_15; break; case 3: + if (adc->id > 4) + return -EINVAL; temp = MCP3422_SRATE_3; break; default: @@ -271,6 +275,17 @@ static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev, } } +static ssize_t mcp3422_show_samp_freqs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); + + if (adc->id > 4) + return sprintf(buf, "240 60 15\n"); + + return sprintf(buf, "240 60 15 3\n"); +} + static ssize_t mcp3422_show_scales(struct device *dev, struct device_attribute *attr, char *buf) { @@ -284,12 +299,13 @@ static ssize_t mcp3422_show_scales(struct device *dev, mcp3422_scales[sample_rate][3]); } -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("240 60 15 3"); +static IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO, + mcp3422_show_samp_freqs, NULL, 0); static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, mcp3422_show_scales, NULL, 0); static struct attribute *mcp3422_attributes[] = { - &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, NULL, }; @@ -335,6 +351,7 @@ static int mcp3422_probe(struct i2c_client *client, adc = iio_priv(indio_dev); adc->i2c = client; + adc->id = (u8)(id->driver_data); mutex_init(&adc->lock); @@ -343,13 +360,16 @@ static int mcp3422_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &mcp3422_info; - switch ((unsigned int)(id->driver_data)) { + switch (adc->id) { case 2: case 3: + case 6: + case 7: indio_dev->channels = mcp3422_channels; indio_dev->num_channels = ARRAY_SIZE(mcp3422_channels); break; case 4: + case 8: indio_dev->channels = mcp3424_channels; indio_dev->num_channels = ARRAY_SIZE(mcp3424_channels); break; @@ -375,6 +395,9 @@ static const struct i2c_device_id mcp3422_id[] = { { "mcp3422", 2 }, { "mcp3423", 3 }, { "mcp3424", 4 }, + { "mcp3426", 6 }, + { "mcp3427", 7 }, + { "mcp3428", 8 }, { } }; MODULE_DEVICE_TABLE(i2c, mcp3422_id); @@ -399,5 +422,5 @@ static struct i2c_driver mcp3422_driver = { module_i2c_driver(mcp3422_driver); MODULE_AUTHOR("Angelo Compagnucci "); -MODULE_DESCRIPTION("Microchip mcp3422/3/4 driver"); +MODULE_DESCRIPTION("Microchip mcp3422/3/4/6/7/8 driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index 75b54730a963ab..372964635ccff2 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -26,6 +26,40 @@ #include #include +struct { + u32 usage_id; + int unit; /* 0 for default others from HID sensor spec */ + int scale_val0; /* scale, whole number */ + int scale_val1; /* scale, fraction in micros */ +} static unit_conversion[] = { + {HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650}, + {HID_USAGE_SENSOR_ACCEL_3D, + HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0}, + {HID_USAGE_SENSOR_ACCEL_3D, + HID_USAGE_SENSOR_UNITS_G, 9, 806650}, + + {HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453}, + {HID_USAGE_SENSOR_GYRO_3D, + HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0}, + {HID_USAGE_SENSOR_GYRO_3D, + HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND, 0, 17453}, + + {HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000}, + {HID_USAGE_SENSOR_COMPASS_3D, HID_USAGE_SENSOR_UNITS_GAUSS, 1, 0}, + + {HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453}, + {HID_USAGE_SENSOR_INCLINOMETER_3D, + HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453}, + {HID_USAGE_SENSOR_INCLINOMETER_3D, + HID_USAGE_SENSOR_UNITS_RADIANS, 1, 0}, + + {HID_USAGE_SENSOR_ALS, 0, 1, 0}, + {HID_USAGE_SENSOR_ALS, HID_USAGE_SENSOR_UNITS_LUX, 1, 0}, + + {HID_USAGE_SENSOR_PRESSURE, 0, 100000, 0}, + {HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 1, 0}, +}; + static int pow_10(unsigned power) { int i; @@ -113,6 +147,26 @@ static u32 convert_to_vtf_format(int size, int exp, int val1, int val2) return value; } +s32 hid_sensor_read_poll_value(struct hid_sensor_common *st) +{ + s32 value = 0; + int ret; + + ret = sensor_hub_get_feature(st->hsdev, + st->poll.report_id, + st->poll.index, &value); + + if (ret < 0 || value < 0) { + return -EINVAL; + } else { + if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) + value = value * 1000; + } + + return value; +} +EXPORT_SYMBOL(hid_sensor_read_poll_value); + int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, int *val1, int *val2) { @@ -209,6 +263,86 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, } EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value); +/* + * This fuction applies the unit exponent to the scale. + * For example: + * 9.806650 ->exp:2-> val0[980]val1[665000] + * 9.000806 ->exp:2-> val0[900]val1[80600] + * 0.174535 ->exp:2-> val0[17]val1[453500] + * 1.001745 ->exp:0-> val0[1]val1[1745] + * 1.001745 ->exp:2-> val0[100]val1[174500] + * 1.001745 ->exp:4-> val0[10017]val1[450000] + * 9.806650 ->exp:-2-> val0[0]val1[98066] + */ +static void adjust_exponent_micro(int *val0, int *val1, int scale0, + int scale1, int exp) +{ + int i; + int x; + int res; + int rem; + + if (exp > 0) { + *val0 = scale0 * pow_10(exp); + res = 0; + if (exp > 6) { + *val1 = 0; + return; + } + for (i = 0; i < exp; ++i) { + x = scale1 / pow_10(5 - i); + res += (pow_10(exp - 1 - i) * x); + scale1 = scale1 % pow_10(5 - i); + } + *val0 += res; + *val1 = scale1 * pow_10(exp); + } else if (exp < 0) { + exp = abs(exp); + if (exp > 6) { + *val0 = *val1 = 0; + return; + } + *val0 = scale0 / pow_10(exp); + rem = scale0 % pow_10(exp); + res = 0; + for (i = 0; i < (6 - exp); ++i) { + x = scale1 / pow_10(5 - i); + res += (pow_10(5 - exp - i) * x); + scale1 = scale1 % pow_10(5 - i); + } + *val1 = rem * pow_10(6 - exp) + res; + } else { + *val0 = scale0; + *val1 = scale1; + } +} + +int hid_sensor_format_scale(u32 usage_id, + struct hid_sensor_hub_attribute_info *attr_info, + int *val0, int *val1) +{ + int i; + int exp; + + *val0 = 1; + *val1 = 0; + + for (i = 0; ARRAY_SIZE(unit_conversion); ++i) { + if (unit_conversion[i].usage_id == usage_id && + unit_conversion[i].unit == attr_info->units) { + exp = hid_sensor_convert_exponent( + attr_info->unit_expo); + adjust_exponent_micro(val0, val1, + unit_conversion[i].scale_val0, + unit_conversion[i].scale_val1, exp); + break; + } + } + + return IIO_VAL_INT_PLUS_MICRO; +} +EXPORT_SYMBOL(hid_sensor_format_scale); + int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, u32 usage_id, struct hid_sensor_common *st) diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index dbefbdaf7cd10b..73282cee0c81f1 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -28,16 +28,17 @@ #include #include "hid-sensor-trigger.h" -static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) +int hid_sensor_power_state(struct hid_sensor_common *st, bool state) { - struct hid_sensor_common *st = iio_trigger_get_drvdata(trig); int state_val; int report_val; if (state) { if (sensor_hub_device_open(st->hsdev)) return -EIO; + + atomic_inc(&st->data_ready); + state_val = hid_sensor_get_usage_index(st->hsdev, st->power_state.report_id, st->power_state.index, @@ -47,6 +48,8 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, st->report_state.index, HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM); } else { + if (!atomic_dec_and_test(&st->data_ready)) + return 0; sensor_hub_device_close(st->hsdev); state_val = hid_sensor_get_usage_index(st->hsdev, st->power_state.report_id, @@ -57,7 +60,6 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, st->report_state.index, HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM); } - st->data_ready = state; if (state_val >= 0) { state_val += st->power_state.logical_minimum; @@ -75,6 +77,13 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, return 0; } +EXPORT_SYMBOL(hid_sensor_power_state); + +static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state); +} void hid_sensor_remove_trigger(struct hid_sensor_common *attrb) { diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h index ca02f7811aa8c6..0f8e78c249d358 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h @@ -22,5 +22,6 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, struct hid_sensor_common *attrb); void hid_sensor_remove_trigger(struct hid_sensor_common *attrb); +int hid_sensor_power_state(struct hid_sensor_common *st, bool state); #endif diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 7ba1ef27021323..e8b932fed70ecb 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -198,6 +199,42 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) } EXPORT_SYMBOL(st_sensors_set_axis_enable); +void st_sensors_power_enable(struct iio_dev *indio_dev) +{ + struct st_sensor_data *pdata = iio_priv(indio_dev); + int err; + + /* Regulators not mandatory, but if requested we should enable them. */ + pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd"); + if (!IS_ERR(pdata->vdd)) { + err = regulator_enable(pdata->vdd); + if (err != 0) + dev_warn(&indio_dev->dev, + "Failed to enable specified Vdd supply\n"); + } + + pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio"); + if (!IS_ERR(pdata->vdd_io)) { + err = regulator_enable(pdata->vdd_io); + if (err != 0) + dev_warn(&indio_dev->dev, + "Failed to enable specified Vdd_IO supply\n"); + } +} +EXPORT_SYMBOL(st_sensors_power_enable); + +void st_sensors_power_disable(struct iio_dev *indio_dev) +{ + struct st_sensor_data *pdata = iio_priv(indio_dev); + + if (!IS_ERR(pdata->vdd)) + regulator_disable(pdata->vdd); + + if (!IS_ERR(pdata->vdd_io)) + regulator_disable(pdata->vdd_io); +} +EXPORT_SYMBOL(st_sensors_power_disable); + static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev, struct st_sensors_platform_data *pdata) { diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index 59d6bc3e04df87..40f4e4935d0df0 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,10 @@ struct gyro_3d_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info gyro[GYRO_3D_CHANNEL_MAX]; u32 gyro_val[GYRO_3D_CHANNEL_MAX]; + int scale_pre_decml; + int scale_post_decml; + int scale_precision; + int value_offset; }; static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = { @@ -56,6 +61,7 @@ static const struct iio_chan_spec gyro_3d_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_X, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -65,6 +71,7 @@ static const struct iio_chan_spec gyro_3d_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Y, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -74,6 +81,7 @@ static const struct iio_chan_spec gyro_3d_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -104,31 +112,42 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev, u32 address; int ret; int ret_type; + s32 poll_value; *val = 0; *val2 = 0; switch (mask) { case 0: + poll_value = hid_sensor_read_poll_value( + &gyro_state->common_attributes); + if (poll_value < 0) + return -EINVAL; + + hid_sensor_power_state(&gyro_state->common_attributes, true); + msleep_interruptible(poll_value * 2); report_id = gyro_state->gyro[chan->scan_index].report_id; address = gyro_3d_addresses[chan->scan_index]; if (report_id >= 0) *val = sensor_hub_input_attr_get_raw_value( - gyro_state->common_attributes.hsdev, - HID_USAGE_SENSOR_GYRO_3D, address, - report_id); + gyro_state->common_attributes.hsdev, + HID_USAGE_SENSOR_GYRO_3D, address, + report_id); else { *val = 0; + hid_sensor_power_state(&gyro_state->common_attributes, + false); return -EINVAL; } + hid_sensor_power_state(&gyro_state->common_attributes, false); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: - *val = gyro_state->gyro[CHANNEL_SCAN_INDEX_X].units; - ret_type = IIO_VAL_INT; + *val = gyro_state->scale_pre_decml; + *val2 = gyro_state->scale_post_decml; + ret_type = gyro_state->scale_precision; break; case IIO_CHAN_INFO_OFFSET: - *val = hid_sensor_convert_exponent( - gyro_state->gyro[CHANNEL_SCAN_INDEX_X].unit_expo); + *val = gyro_state->value_offset; ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SAMP_FREQ: @@ -197,9 +216,8 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, struct iio_dev *indio_dev = platform_get_drvdata(priv); struct gyro_3d_state *gyro_state = iio_priv(indio_dev); - dev_dbg(&indio_dev->dev, "gyro_3d_proc_event [%d]\n", - gyro_state->common_attributes.data_ready); - if (gyro_state->common_attributes.data_ready) + dev_dbg(&indio_dev->dev, "gyro_3d_proc_event\n"); + if (atomic_read(&gyro_state->common_attributes.data_ready)) hid_sensor_push_data(indio_dev, gyro_state->gyro_val, sizeof(gyro_state->gyro_val)); @@ -262,6 +280,11 @@ static int gyro_3d_parse_report(struct platform_device *pdev, st->gyro[1].index, st->gyro[1].report_id, st->gyro[2].index, st->gyro[2].report_id); + st->scale_precision = hid_sensor_format_scale( + HID_USAGE_SENSOR_GYRO_3D, + &st->gyro[CHANNEL_SCAN_INDEX_X], + &st->scale_pre_decml, &st->scale_post_decml); + /* Set Sensitivity field ids, when there is no individual modifier */ if (st->common_attributes.sensitivity.index < 0) { sensor_hub_input_get_attribute_info(hsdev, @@ -330,7 +353,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); goto error_free_dev_mem; } - gyro_state->common_attributes.data_ready = false; + atomic_set(&gyro_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, &gyro_state->common_attributes); if (ret < 0) { diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index 4d3f3b92b361ef..8295e318399f98 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -110,8 +110,6 @@ static int itg3200_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - - return ret; } static ssize_t itg3200_read_frequency(struct device *dev, diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index a8e174a47bc409..ed74a906998953 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -311,6 +311,8 @@ int st_gyro_common_probe(struct iio_dev *indio_dev, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &gyro_info; + st_sensors_power_enable(indio_dev); + err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_gyro_sensors), st_gyro_sensors); if (err < 0) @@ -344,6 +346,9 @@ int st_gyro_common_probe(struct iio_dev *indio_dev, if (err) goto st_gyro_device_register_error; + dev_info(&indio_dev->dev, "registered gyroscope %s\n", + indio_dev->name); + return 0; st_gyro_device_register_error: @@ -360,6 +365,8 @@ void st_gyro_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *gdata = iio_priv(indio_dev); + st_sensors_power_disable(indio_dev); + iio_device_unregister(indio_dev); if (gdata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index f6db6af36ba6de..5f0ea77fe7176e 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -35,7 +35,7 @@ int __iio_add_chan_devattr(const char *postfix, struct list_head *attr_list); void iio_free_chan_devattr_list(struct list_head *attr_list); -ssize_t iio_format_value(char *buf, unsigned int type, int val, int val2); +ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals); /* Event interface flags */ #define IIO_BUSY_BIT_POS 1 diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig index 361b2328453d47..2d0608ba88d7d6 100644 --- a/drivers/iio/imu/inv_mpu6050/Kconfig +++ b/drivers/iio/imu/inv_mpu6050/Kconfig @@ -9,6 +9,8 @@ config INV_MPU6050_IIO select IIO_TRIGGERED_BUFFER help This driver supports the Invensense MPU6050 devices. + This driver can also support MPU6500 in MPU6050 compatibility mode + and also in MPU6500 mode with some limitations. It is a gyroscope/accelerometer combo device. This driver can be built as a module. The module will be called inv-mpu6050. diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index d8ad606c7cd0c7..0c6517c94a9db9 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -767,6 +767,7 @@ static SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume); */ static const struct i2c_device_id inv_mpu_id[] = { {"mpu6050", INV_MPU6050}, + {"mpu6500", INV_MPU6500}, {} }; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index 0ab382be1e6419..e7799315d4dc1c 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -59,6 +59,7 @@ struct inv_mpu6050_reg_map { /*device enum */ enum inv_devices { INV_MPU6050, + INV_MPU6500, INV_NUM_PARTS }; diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index e472cff6eeae38..36b1ae92e2392b 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -150,7 +150,16 @@ static ssize_t iio_show_fixed_type(struct device *dev, type = IIO_BE; #endif } - return sprintf(buf, "%s:%c%d/%d>>%u\n", + if (this_attr->c->scan_type.repeat > 1) + return sprintf(buf, "%s:%c%d/%dX%d>>%u\n", + iio_endian_prefix[type], + this_attr->c->scan_type.sign, + this_attr->c->scan_type.realbits, + this_attr->c->scan_type.storagebits, + this_attr->c->scan_type.repeat, + this_attr->c->scan_type.shift); + else + return sprintf(buf, "%s:%c%d/%d>>%u\n", iio_endian_prefix[type], this_attr->c->scan_type.sign, this_attr->c->scan_type.realbits, @@ -475,14 +484,22 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, for_each_set_bit(i, mask, indio_dev->masklength) { ch = iio_find_channel_from_si(indio_dev, i); - length = ch->scan_type.storagebits / 8; + if (ch->scan_type.repeat > 1) + length = ch->scan_type.storagebits / 8 * + ch->scan_type.repeat; + else + length = ch->scan_type.storagebits / 8; bytes = ALIGN(bytes, length); bytes += length; } if (timestamp) { ch = iio_find_channel_from_si(indio_dev, indio_dev->scan_index_timestamp); - length = ch->scan_type.storagebits / 8; + if (ch->scan_type.repeat > 1) + length = ch->scan_type.storagebits / 8 * + ch->scan_type.repeat; + else + length = ch->scan_type.storagebits / 8; bytes = ALIGN(bytes, length); bytes += length; } @@ -959,7 +976,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, indio_dev->masklength, in_ind + 1); ch = iio_find_channel_from_si(indio_dev, in_ind); - length = ch->scan_type.storagebits/8; + if (ch->scan_type.repeat > 1) + length = ch->scan_type.storagebits / 8 * + ch->scan_type.repeat; + else + length = ch->scan_type.storagebits / 8; /* Make sure we are aligned */ in_loc += length; if (in_loc % length) @@ -971,7 +992,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, goto error_clear_mux_table; } ch = iio_find_channel_from_si(indio_dev, in_ind); - length = ch->scan_type.storagebits/8; + if (ch->scan_type.repeat > 1) + length = ch->scan_type.storagebits / 8 * + ch->scan_type.repeat; + else + length = ch->scan_type.storagebits / 8; if (out_loc % length) out_loc += length - out_loc % length; if (in_loc % length) @@ -992,7 +1017,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, } ch = iio_find_channel_from_si(indio_dev, indio_dev->scan_index_timestamp); - length = ch->scan_type.storagebits/8; + if (ch->scan_type.repeat > 1) + length = ch->scan_type.storagebits / 8 * + ch->scan_type.repeat; + else + length = ch->scan_type.storagebits / 8; if (out_loc % length) out_loc += length - out_loc % length; if (in_loc % length) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index ede16aec20fbd6..4b1f375c5659d0 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -84,6 +84,9 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_LIGHT_RED] = "red", [IIO_MOD_LIGHT_GREEN] = "green", [IIO_MOD_LIGHT_BLUE] = "blue", + [IIO_MOD_QUATERNION] = "quaternion", + [IIO_MOD_TEMP_AMBIENT] = "ambient", + [IIO_MOD_TEMP_OBJECT] = "object", }; /* relies on pairs of these shared then separate */ @@ -340,7 +343,7 @@ ssize_t iio_enum_read(struct iio_dev *indio_dev, else if (i >= e->num_items) return -EINVAL; - return sprintf(buf, "%s\n", e->items[i]); + return snprintf(buf, PAGE_SIZE, "%s\n", e->items[i]); } EXPORT_SYMBOL_GPL(iio_enum_read); @@ -373,41 +376,53 @@ EXPORT_SYMBOL_GPL(iio_enum_write); * @buf: The buffer to which the formated value gets written * @type: One of the IIO_VAL_... constants. This decides how the val and val2 * parameters are formatted. - * @val: First part of the value, exact meaning depends on the type parameter. - * @val2: Second part of the value, exact meaning depends on the type parameter. + * @vals: pointer to the values, exact meaning depends on the type parameter. */ -ssize_t iio_format_value(char *buf, unsigned int type, int val, int val2) +ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) { unsigned long long tmp; bool scale_db = false; switch (type) { case IIO_VAL_INT: - return sprintf(buf, "%d\n", val); + return sprintf(buf, "%d\n", vals[0]); case IIO_VAL_INT_PLUS_MICRO_DB: scale_db = true; case IIO_VAL_INT_PLUS_MICRO: - if (val2 < 0) - return sprintf(buf, "-%ld.%06u%s\n", abs(val), -val2, + if (vals[1] < 0) + return sprintf(buf, "-%ld.%06u%s\n", abs(vals[0]), + -vals[1], scale_db ? " dB" : ""); else - return sprintf(buf, "%d.%06u%s\n", val, val2, + return sprintf(buf, "%d.%06u%s\n", vals[0], vals[1], scale_db ? " dB" : ""); case IIO_VAL_INT_PLUS_NANO: - if (val2 < 0) - return sprintf(buf, "-%ld.%09u\n", abs(val), -val2); + if (vals[1] < 0) + return sprintf(buf, "-%ld.%09u\n", abs(vals[0]), + -vals[1]); else - return sprintf(buf, "%d.%09u\n", val, val2); + return sprintf(buf, "%d.%09u\n", vals[0], vals[1]); case IIO_VAL_FRACTIONAL: - tmp = div_s64((s64)val * 1000000000LL, val2); - val2 = do_div(tmp, 1000000000LL); - val = tmp; - return sprintf(buf, "%d.%09u\n", val, val2); + tmp = div_s64((s64)vals[0] * 1000000000LL, vals[1]); + vals[1] = do_div(tmp, 1000000000LL); + vals[0] = tmp; + return sprintf(buf, "%d.%09u\n", vals[0], vals[1]); case IIO_VAL_FRACTIONAL_LOG2: - tmp = (s64)val * 1000000000LL >> val2; - val2 = do_div(tmp, 1000000000LL); - val = tmp; - return sprintf(buf, "%d.%09u\n", val, val2); + tmp = (s64)vals[0] * 1000000000LL >> vals[1]; + vals[1] = do_div(tmp, 1000000000LL); + vals[0] = tmp; + return sprintf(buf, "%d.%09u\n", vals[0], vals[1]); + case IIO_VAL_INT_MULTIPLE: + { + int i; + int len = 0; + + for (i = 0; i < size; ++i) + len += snprintf(&buf[len], PAGE_SIZE - len, "%d ", + vals[i]); + len += snprintf(&buf[len], PAGE_SIZE - len, "\n"); + return len; + } default: return 0; } @@ -419,14 +434,23 @@ static ssize_t iio_read_channel_info(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int val, val2; - int ret = indio_dev->info->read_raw(indio_dev, this_attr->c, - &val, &val2, this_attr->address); + int vals[INDIO_MAX_RAW_ELEMENTS]; + int ret; + int val_len = 2; + + if (indio_dev->info->read_raw_multi) + ret = indio_dev->info->read_raw_multi(indio_dev, this_attr->c, + INDIO_MAX_RAW_ELEMENTS, + vals, &val_len, + this_attr->address); + else + ret = indio_dev->info->read_raw(indio_dev, this_attr->c, + &vals[0], &vals[1], this_attr->address); if (ret < 0) return ret; - return iio_format_value(buf, ret, val, val2); + return iio_format_value(buf, ret, val_len, vals); } /** @@ -716,6 +740,8 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, int i, ret, attrcount = 0; for_each_set_bit(i, infomask, sizeof(infomask)*8) { + if (i >= ARRAY_SIZE(iio_chan_info_postfix)) + return -EINVAL; ret = __iio_add_chan_devattr(iio_chan_info_postfix[i], chan, &iio_read_channel_info, @@ -820,7 +846,7 @@ static ssize_t iio_show_dev_name(struct device *dev, char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - return sprintf(buf, "%s\n", indio_dev->name); + return snprintf(buf, PAGE_SIZE, "%s\n", indio_dev->name); } static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL); diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index ea6e06b9c7d429..258a973a1fb8da 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -270,7 +270,7 @@ static ssize_t iio_ev_value_show(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int val, val2; + int val, val2, val_arr[2]; int ret; ret = indio_dev->info->read_event_value(indio_dev, @@ -279,7 +279,9 @@ static ssize_t iio_ev_value_show(struct device *dev, &val, &val2); if (ret < 0) return ret; - return iio_format_value(buf, ret, val, val2); + val_arr[0] = val; + val_arr[1] = val2; + return iio_format_value(buf, ret, 2, val_arr); } static ssize_t iio_ev_value_store(struct device *dev, @@ -321,7 +323,9 @@ static int iio_device_add_event(struct iio_dev *indio_dev, char *postfix; int ret; - for_each_set_bit(i, mask, sizeof(*mask)) { + for_each_set_bit(i, mask, sizeof(*mask)*8) { + if (i >= ARRAY_SIZE(iio_ev_info_text)) + return -EINVAL; postfix = kasprintf(GFP_KERNEL, "%s_%s_%s", iio_ev_type_text[type], iio_ev_dir_text[dir], iio_ev_info_text[i]); diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 0cf5f8e06cfcc6..d833d55052eadf 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -417,12 +417,24 @@ static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, enum iio_chan_info_enum info) { int unused; + int vals[INDIO_MAX_RAW_ELEMENTS]; + int ret; + int val_len = 2; if (val2 == NULL) val2 = &unused; - return chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel, - val, val2, info); + if (chan->indio_dev->info->read_raw_multi) { + ret = chan->indio_dev->info->read_raw_multi(chan->indio_dev, + chan->channel, INDIO_MAX_RAW_ELEMENTS, + vals, &val_len, info); + *val = vals[0]; + *val2 = vals[1]; + } else + ret = chan->indio_dev->info->read_raw(chan->indio_dev, + chan->channel, val, val2, info); + + return ret; } int iio_read_channel_raw(struct iio_channel *chan, int *val) @@ -443,6 +455,24 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val) } EXPORT_SYMBOL_GPL(iio_read_channel_raw); +int iio_read_channel_average_raw(struct iio_channel *chan, int *val) +{ + int ret; + + mutex_lock(&chan->indio_dev->info_exist_lock); + if (chan->indio_dev->info == NULL) { + ret = -ENODEV; + goto err_unlock; + } + + ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW); +err_unlock: + mutex_unlock(&chan->indio_dev->info_exist_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(iio_read_channel_average_raw); + static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, int raw, int *processed, unsigned int scale) { diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 5ea4a03c7e71b4..04bdb85d2d9f33 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -5,13 +5,13 @@ * IIO features supported by the driver: * * Read-only raw channels: - * - illiminance_clear [lux] - * - illiminance_ir + * - illuminance_clear [lux] + * - illuminance_ir * - proximity * * Triggered buffer: - * - illiminance_clear - * - illiminance_ir + * - illuminance_clear + * - illuminance_ir * - proximity * * Events: diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 621541fb10a986..f34c94380b416f 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,10 @@ struct als_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info als_illum; u32 illum; + int scale_pre_decml; + int scale_post_decml; + int scale_precision; + int value_offset; }; /* Channel definitions */ @@ -45,6 +50,7 @@ static const struct iio_chan_spec als_channels[] = { .type = IIO_INTENSITY, .modified = 1, .channel2 = IIO_MOD_LIGHT_BOTH, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -75,6 +81,7 @@ static int als_read_raw(struct iio_dev *indio_dev, u32 address; int ret; int ret_type; + s32 poll_value; *val = 0; *val2 = 0; @@ -90,24 +97,35 @@ static int als_read_raw(struct iio_dev *indio_dev, report_id = -1; break; } - if (report_id >= 0) + if (report_id >= 0) { + poll_value = hid_sensor_read_poll_value( + &als_state->common_attributes); + if (poll_value < 0) + return -EINVAL; + + hid_sensor_power_state(&als_state->common_attributes, + true); + msleep_interruptible(poll_value * 2); + *val = sensor_hub_input_attr_get_raw_value( - als_state->common_attributes.hsdev, - HID_USAGE_SENSOR_ALS, address, - report_id); - else { + als_state->common_attributes.hsdev, + HID_USAGE_SENSOR_ALS, address, + report_id); + hid_sensor_power_state(&als_state->common_attributes, + false); + } else { *val = 0; return -EINVAL; } ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: - *val = als_state->als_illum.units; - ret_type = IIO_VAL_INT; + *val = als_state->scale_pre_decml; + *val2 = als_state->scale_post_decml; + ret_type = als_state->scale_precision; break; case IIO_CHAN_INFO_OFFSET: - *val = hid_sensor_convert_exponent( - als_state->als_illum.unit_expo); + *val = als_state->value_offset; ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SAMP_FREQ: @@ -176,9 +194,8 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev, struct iio_dev *indio_dev = platform_get_drvdata(priv); struct als_state *als_state = iio_priv(indio_dev); - dev_dbg(&indio_dev->dev, "als_proc_event [%d]\n", - als_state->common_attributes.data_ready); - if (als_state->common_attributes.data_ready) + dev_dbg(&indio_dev->dev, "als_proc_event\n"); + if (atomic_read(&als_state->common_attributes.data_ready)) hid_sensor_push_data(indio_dev, &als_state->illum, sizeof(als_state->illum)); @@ -229,6 +246,11 @@ static int als_parse_report(struct platform_device *pdev, dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index, st->als_illum.report_id); + st->scale_precision = hid_sensor_format_scale( + HID_USAGE_SENSOR_ALS, + &st->als_illum, + &st->scale_pre_decml, &st->scale_post_decml); + /* Set Sensitivity field ids, when there is no individual modifier */ if (st->common_attributes.sensitivity.index < 0) { sensor_hub_input_get_attribute_info(hsdev, @@ -296,7 +318,7 @@ static int hid_als_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); goto error_free_dev_mem; } - als_state->common_attributes.data_ready = false; + atomic_set(&als_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, &als_state->common_attributes); if (ret < 0) { diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index 1894ab196f97dd..d203ef4d892f26 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,7 @@ static int prox_read_raw(struct iio_dev *indio_dev, u32 address; int ret; int ret_type; + s32 poll_value; *val = 0; *val2 = 0; @@ -90,12 +92,24 @@ static int prox_read_raw(struct iio_dev *indio_dev, report_id = -1; break; } - if (report_id >= 0) + if (report_id >= 0) { + poll_value = hid_sensor_read_poll_value( + &prox_state->common_attributes); + if (poll_value < 0) + return -EINVAL; + + hid_sensor_power_state(&prox_state->common_attributes, + true); + + msleep_interruptible(poll_value * 2); + *val = sensor_hub_input_attr_get_raw_value( prox_state->common_attributes.hsdev, HID_USAGE_SENSOR_PROX, address, report_id); - else { + hid_sensor_power_state(&prox_state->common_attributes, + false); + } else { *val = 0; return -EINVAL; } @@ -176,9 +190,8 @@ static int prox_proc_event(struct hid_sensor_hub_device *hsdev, struct iio_dev *indio_dev = platform_get_drvdata(priv); struct prox_state *prox_state = iio_priv(indio_dev); - dev_dbg(&indio_dev->dev, "prox_proc_event [%d]\n", - prox_state->common_attributes.data_ready); - if (prox_state->common_attributes.data_ready) + dev_dbg(&indio_dev->dev, "prox_proc_event\n"); + if (atomic_read(&prox_state->common_attributes.data_ready)) hid_sensor_push_data(indio_dev, &prox_state->human_presence, sizeof(prox_state->human_presence)); @@ -297,7 +310,7 @@ static int hid_prox_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); goto error_free_dev_mem; } - prox_state->common_attributes.data_ready = false; + atomic_set(&prox_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, &prox_state->common_attributes); if (ret) { diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index d86d226dcd67e0..05a364c543f851 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -11,7 +11,8 @@ config AK8975 depends on GPIOLIB help Say yes here to build support for Asahi Kasei AK8975 3-Axis - Magnetometer. + Magnetometer. This driver can also support AK8963, if i2c + device name is identified as ak8963. To compile this driver as a module, choose M here: the module will be called ak8975. diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 74866d1efd1b8a..09ea5c481f4c22 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -85,7 +86,14 @@ #define AK8975_MAX_CONVERSION_TIMEOUT 500 #define AK8975_CONVERSION_DONE_POLL_TIME 10 #define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000) -#define RAW_TO_GAUSS(asa) ((((asa) + 128) * 3000) / 256) +#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256) +#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256) + +/* Compatible Asahi Kasei Compass parts */ +enum asahi_compass_chipset { + AK8975, + AK8963, +}; /* * Per-instance context data for the device. @@ -101,6 +109,7 @@ struct ak8975_data { int eoc_irq; wait_queue_head_t data_ready_queue; unsigned long flags; + enum asahi_compass_chipset chipset; }; static const int ak8975_index_to_reg[] = { @@ -272,9 +281,21 @@ static int ak8975_setup(struct i2c_client *client) * Since ASA doesn't change, we cache the resultant scale factor into the * device context in ak8975_setup(). */ - data->raw_to_gauss[0] = RAW_TO_GAUSS(data->asa[0]); - data->raw_to_gauss[1] = RAW_TO_GAUSS(data->asa[1]); - data->raw_to_gauss[2] = RAW_TO_GAUSS(data->asa[2]); + if (data->chipset == AK8963) { + /* + * H range is +-8190 and magnetometer range is +-4912. + * So HuT using the above explanation for 8975, + * 4912/8190 = ~ 6/10. + * So the Hadj should use 6/10 instead of 3/10. + */ + data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]); + data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]); + data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]); + } else { + data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]); + data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]); + data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]); + } return 0; } @@ -455,6 +476,27 @@ static const struct iio_info ak8975_info = { .driver_module = THIS_MODULE, }; +static const struct acpi_device_id ak_acpi_match[] = { + {"AK8975", AK8975}, + {"AK8963", AK8963}, + {"INVN6500", AK8963}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, ak_acpi_match); + +static char *ak8975_match_acpi_device(struct device *dev, + enum asahi_compass_chipset *chipset) +{ + const struct acpi_device_id *id; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return NULL; + *chipset = (int)id->driver_data; + + return (char *)dev_name(dev); +} + static int ak8975_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -462,6 +504,7 @@ static int ak8975_probe(struct i2c_client *client, struct iio_dev *indio_dev; int eoc_gpio; int err; + char *name = NULL; /* Grab and set up the supplied GPIO. */ if (client->dev.platform_data) @@ -499,6 +542,19 @@ static int ak8975_probe(struct i2c_client *client, data->eoc_gpio = eoc_gpio; data->eoc_irq = 0; + /* id will be NULL when enumerated via ACPI */ + if (id) { + data->chipset = + (enum asahi_compass_chipset)(id->driver_data); + name = (char *) id->name; + } else if (ACPI_HANDLE(&client->dev)) + name = ak8975_match_acpi_device(&client->dev, &data->chipset); + else { + err = -ENOSYS; + goto exit_free_iio; + } + dev_dbg(&client->dev, "Asahi compass chip %s\n", name); + /* Perform some basic start-of-day setup of the device. */ err = ak8975_setup(client); if (err < 0) { @@ -513,9 +569,8 @@ static int ak8975_probe(struct i2c_client *client, indio_dev->channels = ak8975_channels; indio_dev->num_channels = ARRAY_SIZE(ak8975_channels); indio_dev->info = &ak8975_info; - indio_dev->name = id->name; indio_dev->modes = INDIO_DIRECT_MODE; - + indio_dev->name = name; err = iio_device_register(indio_dev); if (err < 0) goto exit_free_iio; @@ -552,7 +607,8 @@ static int ak8975_remove(struct i2c_client *client) } static const struct i2c_device_id ak8975_id[] = { - {"ak8975", 0}, + {"ak8975", AK8975}, + {"ak8963", AK8963}, {} }; @@ -569,6 +625,7 @@ static struct i2c_driver ak8975_driver = { .driver = { .name = "ak8975", .of_match_table = ak8975_of_match, + .acpi_match_table = ACPI_PTR(ak_acpi_match), }, .probe = ak8975_probe, .remove = ak8975_remove, diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index 6d162b7e7af583..41cf29e2a37188 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,10 @@ struct magn_3d_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX]; u32 magn_val[MAGN_3D_CHANNEL_MAX]; + int scale_pre_decml; + int scale_post_decml; + int scale_precision; + int value_offset; }; static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = { @@ -56,6 +61,7 @@ static const struct iio_chan_spec magn_3d_channels[] = { .type = IIO_MAGN, .modified = 1, .channel2 = IIO_MOD_X, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -65,6 +71,7 @@ static const struct iio_chan_spec magn_3d_channels[] = { .type = IIO_MAGN, .modified = 1, .channel2 = IIO_MOD_Y, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -74,6 +81,7 @@ static const struct iio_chan_spec magn_3d_channels[] = { .type = IIO_MAGN, .modified = 1, .channel2 = IIO_MOD_Z, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -104,11 +112,20 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, u32 address; int ret; int ret_type; + s32 poll_value; *val = 0; *val2 = 0; switch (mask) { case 0: + poll_value = hid_sensor_read_poll_value( + &magn_state->common_attributes); + if (poll_value < 0) + return -EINVAL; + + hid_sensor_power_state(&magn_state->common_attributes, true); + msleep_interruptible(poll_value * 2); + report_id = magn_state->magn[chan->scan_index].report_id; address = magn_3d_addresses[chan->scan_index]; @@ -119,17 +136,20 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, report_id); else { *val = 0; + hid_sensor_power_state(&magn_state->common_attributes, + false); return -EINVAL; } + hid_sensor_power_state(&magn_state->common_attributes, false); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: - *val = magn_state->magn[CHANNEL_SCAN_INDEX_X].units; - ret_type = IIO_VAL_INT; + *val = magn_state->scale_pre_decml; + *val2 = magn_state->scale_post_decml; + ret_type = magn_state->scale_precision; break; case IIO_CHAN_INFO_OFFSET: - *val = hid_sensor_convert_exponent( - magn_state->magn[CHANNEL_SCAN_INDEX_X].unit_expo); + *val = magn_state->value_offset; ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SAMP_FREQ: @@ -198,9 +218,8 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, struct iio_dev *indio_dev = platform_get_drvdata(priv); struct magn_3d_state *magn_state = iio_priv(indio_dev); - dev_dbg(&indio_dev->dev, "magn_3d_proc_event [%d]\n", - magn_state->common_attributes.data_ready); - if (magn_state->common_attributes.data_ready) + dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n"); + if (atomic_read(&magn_state->common_attributes.data_ready)) hid_sensor_push_data(indio_dev, magn_state->magn_val, sizeof(magn_state->magn_val)); @@ -263,6 +282,11 @@ static int magn_3d_parse_report(struct platform_device *pdev, st->magn[1].index, st->magn[1].report_id, st->magn[2].index, st->magn[2].report_id); + st->scale_precision = hid_sensor_format_scale( + HID_USAGE_SENSOR_COMPASS_3D, + &st->magn[CHANNEL_SCAN_INDEX_X], + &st->scale_pre_decml, &st->scale_post_decml); + /* Set Sensitivity field ids, when there is no individual modifier */ if (st->common_attributes.sensitivity.index < 0) { sensor_hub_input_get_attribute_info(hsdev, @@ -334,7 +358,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); goto error_free_dev_mem; } - magn_state->common_attributes.data_ready = false; + atomic_set(&magn_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, &magn_state->common_attributes); if (ret < 0) { diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index 8b77782474d7a1..e3106b43ef488f 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -199,6 +199,13 @@ static int mag3110_read_raw(struct iio_dev *indio_dev, *val = mag3110_samp_freq[i][0]; *val2 = mag3110_samp_freq[i][1]; return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_CALIBBIAS: + ret = i2c_smbus_read_word_swapped(data->client, + MAG3110_OFF_X + 2 * chan->scan_index); + if (ret < 0) + return ret; + *val = sign_extend32(ret >> 1, 14); + return IIO_VAL_INT; } return -EINVAL; } @@ -223,6 +230,11 @@ static int mag3110_write_raw(struct iio_dev *indio_dev, data->ctrl_reg1 |= rate << MAG3110_CTRL_DR_SHIFT; return i2c_smbus_write_byte_data(data->client, MAG3110_CTRL_REG1, data->ctrl_reg1); + case IIO_CHAN_INFO_CALIBBIAS: + if (val < -10000 || val > 10000) + return -EINVAL; + return i2c_smbus_write_word_swapped(data->client, + MAG3110_OFF_X + 2 * chan->scan_index, val << 1); default: return -EINVAL; } @@ -260,7 +272,8 @@ static irqreturn_t mag3110_trigger_handler(int irq, void *p) .type = IIO_MAGN, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ BIT(IIO_CHAN_INFO_SCALE), \ .scan_index = idx, \ @@ -338,14 +351,14 @@ static int mag3110_probe(struct i2c_client *client, indio_dev->num_channels = ARRAY_SIZE(mag3110_channels); indio_dev->available_scan_masks = mag3110_scan_masks; - data->ctrl_reg1 = MAG3110_CTRL_DR_DEFAULT; + data->ctrl_reg1 = MAG3110_CTRL_DR_DEFAULT << MAG3110_CTRL_DR_SHIFT; ret = i2c_smbus_write_byte_data(client, MAG3110_CTRL_REG1, data->ctrl_reg1); if (ret < 0) return ret; ret = i2c_smbus_write_byte_data(client, MAG3110_CTRL_REG2, - MAG3110_CTRL_AUTO_MRST_EN | MAG3110_CTRL_RAW); + MAG3110_CTRL_AUTO_MRST_EN); if (ret < 0) return ret; diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 52bbcfa1e07795..240a21dd0c6111 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -355,6 +355,8 @@ int st_magn_common_probe(struct iio_dev *indio_dev, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &magn_info; + st_sensors_power_enable(indio_dev); + err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_magn_sensors), st_magn_sensors); if (err < 0) @@ -387,6 +389,9 @@ int st_magn_common_probe(struct iio_dev *indio_dev, if (err) goto st_magn_device_register_error; + dev_info(&indio_dev->dev, "registered magnetometer %s\n", + indio_dev->name); + return 0; st_magn_device_register_error: @@ -403,6 +408,8 @@ void st_magn_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *mdata = iio_priv(indio_dev); + st_sensors_power_disable(indio_dev); + iio_device_unregister(indio_dev); if (mdata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); diff --git a/drivers/iio/orientation/Kconfig b/drivers/iio/orientation/Kconfig index 58c62c837e12f3..e3aa1e58d920f4 100644 --- a/drivers/iio/orientation/Kconfig +++ b/drivers/iio/orientation/Kconfig @@ -16,4 +16,16 @@ config HID_SENSOR_INCLINOMETER_3D Say yes here to build support for the HID SENSOR Inclinometer 3D. +config HID_SENSOR_DEVICE_ROTATION + depends on HID_SENSOR_HUB + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select HID_SENSOR_IIO_COMMON + select HID_SENSOR_IIO_TRIGGER + tristate "HID Device Rotation" + help + Say yes here to build support for the HID SENSOR + device rotation. The output of a device rotation sensor + is presented using quaternion format. + endmenu diff --git a/drivers/iio/orientation/Makefile b/drivers/iio/orientation/Makefile index 2c97572ee919b4..4734dabbde13ee 100644 --- a/drivers/iio/orientation/Makefile +++ b/drivers/iio/orientation/Makefile @@ -4,3 +4,4 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_HID_SENSOR_INCLINOMETER_3D) += hid-sensor-incl-3d.o +obj-$(CONFIG_HID_SENSOR_DEVICE_ROTATION) += hid-sensor-rotation.o diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index 070feab08faa8e..2478f6c2ef2547 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,10 @@ struct incl_3d_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info incl[INCLI_3D_CHANNEL_MAX]; u32 incl_val[INCLI_3D_CHANNEL_MAX]; + int scale_pre_decml; + int scale_post_decml; + int scale_precision; + int value_offset; }; static const u32 incl_3d_addresses[INCLI_3D_CHANNEL_MAX] = { @@ -106,11 +111,20 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev, int report_id = -1; u32 address; int ret_type; + s32 poll_value; *val = 0; *val2 = 0; switch (mask) { case IIO_CHAN_INFO_RAW: + poll_value = hid_sensor_read_poll_value( + &incl_state->common_attributes); + if (poll_value < 0) + return -EINVAL; + + hid_sensor_power_state(&incl_state->common_attributes, true); + msleep_interruptible(poll_value * 2); + report_id = incl_state->incl[chan->scan_index].report_id; address = incl_3d_addresses[chan->scan_index]; @@ -120,17 +134,20 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev, HID_USAGE_SENSOR_INCLINOMETER_3D, address, report_id); else { + hid_sensor_power_state(&incl_state->common_attributes, + false); return -EINVAL; } + hid_sensor_power_state(&incl_state->common_attributes, false); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: - *val = incl_state->incl[CHANNEL_SCAN_INDEX_X].units; - ret_type = IIO_VAL_INT; + *val = incl_state->scale_pre_decml; + *val2 = incl_state->scale_post_decml; + ret_type = incl_state->scale_precision; break; case IIO_CHAN_INFO_OFFSET: - *val = hid_sensor_convert_exponent( - incl_state->incl[CHANNEL_SCAN_INDEX_X].unit_expo); + *val = incl_state->value_offset; ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SAMP_FREQ: @@ -196,9 +213,8 @@ static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev, struct iio_dev *indio_dev = platform_get_drvdata(priv); struct incl_3d_state *incl_state = iio_priv(indio_dev); - dev_dbg(&indio_dev->dev, "incl_3d_proc_event [%d]\n", - incl_state->common_attributes.data_ready); - if (incl_state->common_attributes.data_ready) + dev_dbg(&indio_dev->dev, "incl_3d_proc_event\n"); + if (atomic_read(&incl_state->common_attributes.data_ready)) hid_sensor_push_data(indio_dev, (u8 *)incl_state->incl_val, sizeof(incl_state->incl_val)); @@ -279,6 +295,11 @@ static int incl_3d_parse_report(struct platform_device *pdev, st->incl[1].index, st->incl[1].report_id, st->incl[2].index, st->incl[2].report_id); + st->scale_precision = hid_sensor_format_scale( + HID_USAGE_SENSOR_INCLINOMETER_3D, + &st->incl[CHANNEL_SCAN_INDEX_X], + &st->scale_pre_decml, &st->scale_post_decml); + /* Set Sensitivity field ids, when there is no individual modifier */ if (st->common_attributes.sensitivity.index < 0) { sensor_hub_input_get_attribute_info(hsdev, @@ -349,7 +370,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); goto error_free_dev_mem; } - incl_state->common_attributes.data_ready = false; + atomic_set(&incl_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, &incl_state->common_attributes); if (ret) { diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c new file mode 100644 index 00000000000000..dccf848e8b0fdd --- /dev/null +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -0,0 +1,346 @@ +/* + * HID Sensors Driver + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../common/hid-sensors/hid-sensor-trigger.h" + +struct dev_rot_state { + struct hid_sensor_hub_callbacks callbacks; + struct hid_sensor_common common_attributes; + struct hid_sensor_hub_attribute_info quaternion; + u32 sampled_vals[4]; +}; + +/* Channel definitions */ +static const struct iio_chan_spec dev_rot_channels[] = { + { + .type = IIO_ROT, + .modified = 1, + .channel2 = IIO_MOD_QUATERNION, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS) + } +}; + +/* Adjust channel real bits based on report descriptor */ +static void dev_rot_adjust_channel_bit_mask(struct iio_chan_spec *chan, + int size) +{ + chan->scan_type.sign = 's'; + /* Real storage bits will change based on the report desc. */ + chan->scan_type.realbits = size * 8; + /* Maximum size of a sample to capture is u32 */ + chan->scan_type.storagebits = sizeof(u32) * 8; + chan->scan_type.repeat = 4; +} + +/* Channel read_raw handler */ +static int dev_rot_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int size, int *vals, int *val_len, + long mask) +{ + struct dev_rot_state *rot_state = iio_priv(indio_dev); + int ret_type; + int i; + + vals[0] = 0; + vals[1] = 0; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (size >= 4) { + for (i = 0; i < 4; ++i) + vals[i] = rot_state->sampled_vals[i]; + ret_type = IIO_VAL_INT_MULTIPLE; + *val_len = 4; + } else + ret_type = -EINVAL; + break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret_type = hid_sensor_read_samp_freq_value( + &rot_state->common_attributes, &vals[0], &vals[1]); + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret_type = hid_sensor_read_raw_hyst_value( + &rot_state->common_attributes, &vals[0], &vals[1]); + break; + default: + ret_type = -EINVAL; + break; + } + + return ret_type; +} + +/* Channel write_raw handler */ +static int dev_rot_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct dev_rot_state *rot_state = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_write_samp_freq_value( + &rot_state->common_attributes, val, val2); + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_write_raw_hyst_value( + &rot_state->common_attributes, val, val2); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct iio_info dev_rot_info = { + .driver_module = THIS_MODULE, + .read_raw_multi = &dev_rot_read_raw, + .write_raw = &dev_rot_write_raw, +}; + +/* Function to push data to buffer */ +static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +{ + dev_dbg(&indio_dev->dev, "hid_sensor_push_data >>\n"); + iio_push_to_buffers(indio_dev, (u8 *)data); + dev_dbg(&indio_dev->dev, "hid_sensor_push_data <<\n"); + +} + +/* Callback handler to send event after all samples are received and captured */ +static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + void *priv) +{ + struct iio_dev *indio_dev = platform_get_drvdata(priv); + struct dev_rot_state *rot_state = iio_priv(indio_dev); + + dev_dbg(&indio_dev->dev, "dev_rot_proc_event\n"); + if (atomic_read(&rot_state->common_attributes.data_ready)) + hid_sensor_push_data(indio_dev, + (u8 *)rot_state->sampled_vals, + sizeof(rot_state->sampled_vals)); + + return 0; +} + +/* Capture samples in local storage */ +static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + size_t raw_len, char *raw_data, + void *priv) +{ + struct iio_dev *indio_dev = platform_get_drvdata(priv); + struct dev_rot_state *rot_state = iio_priv(indio_dev); + + if (usage_id == HID_USAGE_SENSOR_ORIENT_QUATERNION) { + memcpy(rot_state->sampled_vals, raw_data, + sizeof(rot_state->sampled_vals)); + dev_dbg(&indio_dev->dev, "Recd Quat len:%zu::%zu\n", raw_len, + sizeof(rot_state->sampled_vals)); + } + + return 0; +} + +/* Parse report which is specific to an usage id*/ +static int dev_rot_parse_report(struct platform_device *pdev, + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + unsigned usage_id, + struct dev_rot_state *st) +{ + int ret; + + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_ORIENT_QUATERNION, + &st->quaternion); + if (ret) + return ret; + + dev_rot_adjust_channel_bit_mask(&channels[0], + st->quaternion.size / 4); + + dev_dbg(&pdev->dev, "dev_rot %x:%x\n", st->quaternion.index, + st->quaternion.report_id); + + dev_dbg(&pdev->dev, "dev_rot: attrib size %d\n", + st->quaternion.size); + + /* Set Sensitivity field ids, when there is no individual modifier */ + if (st->common_attributes.sensitivity.index < 0) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_DATA_ORIENTATION, + &st->common_attributes.sensitivity); + dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", + st->common_attributes.sensitivity.index, + st->common_attributes.sensitivity.report_id); + } + + return 0; +} + +/* Function to initialize the processing for usage id */ +static int hid_dev_rot_probe(struct platform_device *pdev) +{ + int ret; + static char *name = "dev_rotation"; + struct iio_dev *indio_dev; + struct dev_rot_state *rot_state; + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_chan_spec *channels; + + indio_dev = devm_iio_device_alloc(&pdev->dev, + sizeof(struct dev_rot_state)); + if (indio_dev == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, indio_dev); + + rot_state = iio_priv(indio_dev); + rot_state->common_attributes.hsdev = hsdev; + rot_state->common_attributes.pdev = pdev; + + ret = hid_sensor_parse_common_attributes(hsdev, + HID_USAGE_SENSOR_DEVICE_ORIENTATION, + &rot_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "failed to setup common attributes\n"); + return ret; + } + + channels = devm_kmemdup(&pdev->dev, dev_rot_channels, + sizeof(dev_rot_channels), GFP_KERNEL); + if (!channels) { + dev_err(&pdev->dev, "failed to duplicate channels\n"); + return -ENOMEM; + } + + ret = dev_rot_parse_report(pdev, hsdev, channels, + HID_USAGE_SENSOR_DEVICE_ORIENTATION, rot_state); + if (ret) { + dev_err(&pdev->dev, "failed to setup attributes\n"); + return ret; + } + + indio_dev->channels = channels; + indio_dev->num_channels = ARRAY_SIZE(dev_rot_channels); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &dev_rot_info; + indio_dev->name = name; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + NULL, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); + return ret; + } + atomic_set(&rot_state->common_attributes.data_ready, 0); + ret = hid_sensor_setup_trigger(indio_dev, name, + &rot_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "trigger setup failed\n"); + goto error_unreg_buffer_funcs; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_trigger; + } + + rot_state->callbacks.send_event = dev_rot_proc_event; + rot_state->callbacks.capture_sample = dev_rot_capture_sample; + rot_state->callbacks.pdev = pdev; + ret = sensor_hub_register_callback(hsdev, + HID_USAGE_SENSOR_DEVICE_ORIENTATION, + &rot_state->callbacks); + if (ret) { + dev_err(&pdev->dev, "callback reg failed\n"); + goto error_iio_unreg; + } + + return 0; + +error_iio_unreg: + iio_device_unregister(indio_dev); +error_remove_trigger: + hid_sensor_remove_trigger(&rot_state->common_attributes); +error_unreg_buffer_funcs: + iio_triggered_buffer_cleanup(indio_dev); + return ret; +} + +/* Function to deinitialize the processing for usage id */ +static int hid_dev_rot_remove(struct platform_device *pdev) +{ + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct dev_rot_state *rot_state = iio_priv(indio_dev); + + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_DEVICE_ORIENTATION); + iio_device_unregister(indio_dev); + hid_sensor_remove_trigger(&rot_state->common_attributes); + iio_triggered_buffer_cleanup(indio_dev); + + return 0; +} + +static struct platform_device_id hid_dev_rot_ids[] = { + { + /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ + .name = "HID-SENSOR-20008a", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, hid_dev_rot_ids); + +static struct platform_driver hid_dev_rot_platform_driver = { + .id_table = hid_dev_rot_ids, + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, + .probe = hid_dev_rot_probe, + .remove = hid_dev_rot_remove, +}; +module_platform_driver(hid_dev_rot_platform_driver); + +MODULE_DESCRIPTION("HID Sensor Device Rotation"); +MODULE_AUTHOR("Srinivas Pandruvada "); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index d88ff17fedb290..ffac8ac1efca8c 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -19,6 +19,16 @@ config HID_SENSOR_PRESS To compile this driver as a module, choose M here: the module will be called hid-sensor-press. +config MPL115 + tristate "Freescale MPL115A2 pressure sensor driver" + depends on I2C + help + Say yes here to build support for the Freescale MPL115A2 + pressure sensor connected via I2C. + + To compile this driver as a module, choose M here: the module + will be called mpl115. + config MPL3115 tristate "Freescale MPL3115A2 pressure sensor driver" depends on I2C diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index 4a57bf65b04b9e..c53d2500737ad6 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -4,6 +4,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o +obj-$(CONFIG_MPL115) += mpl115.o obj-$(CONFIG_MPL3115) += mpl3115.o obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o st_pressure-y := st_pressure_core.o diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index e0e6409aa94e30..1cd190c7378814 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,10 @@ struct press_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info press_attr; u32 press_data; + int scale_pre_decml; + int scale_post_decml; + int scale_precision; + int value_offset; }; /* Channel definitions */ @@ -75,6 +80,7 @@ static int press_read_raw(struct iio_dev *indio_dev, u32 address; int ret; int ret_type; + s32 poll_value; *val = 0; *val2 = 0; @@ -90,24 +96,35 @@ static int press_read_raw(struct iio_dev *indio_dev, report_id = -1; break; } - if (report_id >= 0) + if (report_id >= 0) { + poll_value = hid_sensor_read_poll_value( + &press_state->common_attributes); + if (poll_value < 0) + return -EINVAL; + hid_sensor_power_state(&press_state->common_attributes, + true); + + msleep_interruptible(poll_value * 2); + *val = sensor_hub_input_attr_get_raw_value( press_state->common_attributes.hsdev, HID_USAGE_SENSOR_PRESSURE, address, report_id); - else { + hid_sensor_power_state(&press_state->common_attributes, + false); + } else { *val = 0; return -EINVAL; } ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: - *val = press_state->press_attr.units; - ret_type = IIO_VAL_INT; + *val = press_state->scale_pre_decml; + *val2 = press_state->scale_post_decml; + ret_type = press_state->scale_precision; break; case IIO_CHAN_INFO_OFFSET: - *val = hid_sensor_convert_exponent( - press_state->press_attr.unit_expo); + *val = press_state->value_offset; ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SAMP_FREQ: @@ -176,9 +193,8 @@ static int press_proc_event(struct hid_sensor_hub_device *hsdev, struct iio_dev *indio_dev = platform_get_drvdata(priv); struct press_state *press_state = iio_priv(indio_dev); - dev_dbg(&indio_dev->dev, "press_proc_event [%d]\n", - press_state->common_attributes.data_ready); - if (press_state->common_attributes.data_ready) + dev_dbg(&indio_dev->dev, "press_proc_event\n"); + if (atomic_read(&press_state->common_attributes.data_ready)) hid_sensor_push_data(indio_dev, &press_state->press_data, sizeof(press_state->press_data)); @@ -229,6 +245,11 @@ static int press_parse_report(struct platform_device *pdev, dev_dbg(&pdev->dev, "press %x:%x\n", st->press_attr.index, st->press_attr.report_id); + st->scale_precision = hid_sensor_format_scale( + HID_USAGE_SENSOR_PRESSURE, + &st->press_attr, + &st->scale_pre_decml, &st->scale_post_decml); + /* Set Sensitivity field ids, when there is no individual modifier */ if (st->common_attributes.sensitivity.index < 0) { sensor_hub_input_get_attribute_info(hsdev, @@ -298,7 +319,7 @@ static int hid_press_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); goto error_free_dev_mem; } - press_state->common_attributes.data_ready = false; + atomic_set(&press_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, &press_state->common_attributes); if (ret) { diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c new file mode 100644 index 00000000000000..f5ecd6e19f5de7 --- /dev/null +++ b/drivers/iio/pressure/mpl115.c @@ -0,0 +1,211 @@ +/* + * mpl115.c - Support for Freescale MPL115A2 pressure/temperature sensor + * + * Copyright (c) 2014 Peter Meerwald + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * (7-bit I2C slave address 0x60) + * + * TODO: shutdown pin + * + */ + +#include +#include +#include +#include + +#define MPL115_PADC 0x00 /* pressure ADC output value, MSB first, 10 bit */ +#define MPL115_TADC 0x02 /* temperature ADC output value, MSB first, 10 bit */ +#define MPL115_A0 0x04 /* 12 bit integer, 3 bit fraction */ +#define MPL115_B1 0x06 /* 2 bit integer, 13 bit fraction */ +#define MPL115_B2 0x08 /* 1 bit integer, 14 bit fraction */ +#define MPL115_C12 0x0a /* 0 bit integer, 13 bit fraction */ +#define MPL115_CONVERT 0x12 /* convert temperature and pressure */ + +struct mpl115_data { + struct i2c_client *client; + struct mutex lock; + s16 a0; + s16 b1, b2; + s16 c12; +}; + +static int mpl115_request(struct mpl115_data *data) +{ + int ret = i2c_smbus_write_byte_data(data->client, MPL115_CONVERT, 0); + if (ret < 0) + return ret; + + usleep_range(3000, 4000); + + return 0; +} + +static int mpl115_comp_pressure(struct mpl115_data *data, int *val, int *val2) +{ + int ret; + u16 padc, tadc; + int a1, y1, pcomp; + unsigned kpa; + + mutex_lock(&data->lock); + ret = mpl115_request(data); + if (ret < 0) + goto done; + + ret = i2c_smbus_read_word_swapped(data->client, MPL115_PADC); + if (ret < 0) + goto done; + padc = ret >> 6; + + ret = i2c_smbus_read_word_swapped(data->client, MPL115_TADC); + if (ret < 0) + goto done; + tadc = ret >> 6; + + /* see Freescale AN3785 */ + a1 = data->b1 + ((data->c12 * tadc) >> 11); + y1 = (data->a0 << 10) + a1 * padc; + + /* compensated pressure with 4 fractional bits */ + pcomp = (y1 + ((data->b2 * (int) tadc) >> 1)) >> 9; + + kpa = pcomp * (115 - 50) / 1023 + (50 << 4); + *val = kpa >> 4; + *val2 = (kpa & 15) * (1000000 >> 4); +done: + mutex_unlock(&data->lock); + return ret; +} + +static int mpl115_read_temp(struct mpl115_data *data) +{ + int ret; + + mutex_lock(&data->lock); + ret = mpl115_request(data); + if (ret < 0) + goto done; + ret = i2c_smbus_read_word_swapped(data->client, MPL115_TADC); +done: + mutex_unlock(&data->lock); + return ret; +} + +static int mpl115_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct mpl115_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + ret = mpl115_comp_pressure(data, val, val2); + if (ret < 0) + return ret; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_RAW: + /* temperature -5.35 C / LSB, 472 LSB is 25 C */ + ret = mpl115_read_temp(data); + if (ret < 0) + return ret; + *val = ret >> 6; + return IIO_VAL_INT; + case IIO_CHAN_INFO_OFFSET: + *val = 605; + *val2 = 750000; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SCALE: + *val = -186; + *val2 = 915888; + return IIO_VAL_INT_PLUS_MICRO; + } + return -EINVAL; +} + +static const struct iio_chan_spec mpl115_channels[] = { + { + .type = IIO_PRESSURE, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static const struct iio_info mpl115_info = { + .read_raw = &mpl115_read_raw, + .driver_module = THIS_MODULE, +}; + +static int mpl115_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct mpl115_data *data; + struct iio_dev *indio_dev; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + mutex_init(&data->lock); + + i2c_set_clientdata(client, indio_dev); + indio_dev->info = &mpl115_info; + indio_dev->name = id->name; + indio_dev->dev.parent = &client->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = mpl115_channels; + indio_dev->num_channels = ARRAY_SIZE(mpl115_channels); + + ret = i2c_smbus_read_word_swapped(data->client, MPL115_A0); + if (ret < 0) + return ret; + data->a0 = ret; + ret = i2c_smbus_read_word_swapped(data->client, MPL115_B1); + if (ret < 0) + return ret; + data->b1 = ret; + ret = i2c_smbus_read_word_swapped(data->client, MPL115_B2); + if (ret < 0) + return ret; + data->b2 = ret; + ret = i2c_smbus_read_word_swapped(data->client, MPL115_C12); + if (ret < 0) + return ret; + data->c12 = ret; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id mpl115_id[] = { + { "mpl115", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mpl115_id); + +static struct i2c_driver mpl115_driver = { + .driver = { + .name = "mpl115", + }, + .probe = mpl115_probe, + .id_table = mpl115_id, +}; +module_i2c_driver(mpl115_driver); + +MODULE_AUTHOR("Peter Meerwald "); +MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 7418768ed49c62..cd7e01f3a93b5f 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -387,40 +386,6 @@ static const struct iio_trigger_ops st_press_trigger_ops = { #define ST_PRESS_TRIGGER_OPS NULL #endif -static void st_press_power_enable(struct iio_dev *indio_dev) -{ - struct st_sensor_data *pdata = iio_priv(indio_dev); - int err; - - /* Regulators not mandatory, but if requested we should enable them. */ - pdata->vdd = devm_regulator_get_optional(&indio_dev->dev, "vdd"); - if (!IS_ERR(pdata->vdd)) { - err = regulator_enable(pdata->vdd); - if (err != 0) - dev_warn(&indio_dev->dev, - "Failed to enable specified Vdd supply\n"); - } - - pdata->vdd_io = devm_regulator_get_optional(&indio_dev->dev, "vddio"); - if (!IS_ERR(pdata->vdd_io)) { - err = regulator_enable(pdata->vdd_io); - if (err != 0) - dev_warn(&indio_dev->dev, - "Failed to enable specified Vdd_IO supply\n"); - } -} - -static void st_press_power_disable(struct iio_dev *indio_dev) -{ - struct st_sensor_data *pdata = iio_priv(indio_dev); - - if (!IS_ERR(pdata->vdd)) - regulator_disable(pdata->vdd); - - if (!IS_ERR(pdata->vdd_io)) - regulator_disable(pdata->vdd_io); -} - int st_press_common_probe(struct iio_dev *indio_dev, struct st_sensors_platform_data *plat_data) { @@ -431,7 +396,7 @@ int st_press_common_probe(struct iio_dev *indio_dev, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &press_info; - st_press_power_enable(indio_dev); + st_sensors_power_enable(indio_dev); err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_press_sensors), @@ -474,6 +439,9 @@ int st_press_common_probe(struct iio_dev *indio_dev, if (err) goto st_press_device_register_error; + dev_info(&indio_dev->dev, "registered pressure sensor %s\n", + indio_dev->name); + return err; st_press_device_register_error: @@ -490,7 +458,7 @@ void st_press_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *pdata = iio_priv(indio_dev); - st_press_power_disable(indio_dev); + st_sensors_power_disable(indio_dev); iio_device_unregister(indio_dev); if (pdata->get_irq_data_ready(indio_dev) > 0) diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig new file mode 100644 index 00000000000000..0c8cdf58f6a19b --- /dev/null +++ b/drivers/iio/proximity/Kconfig @@ -0,0 +1,19 @@ +# +# Proximity sensors +# + +menu "Lightning sensors" + +config AS3935 + tristate "AS3935 Franklin lightning sensor" + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + depends on SPI + help + Say Y here to build SPI interface support for the Austrian + Microsystems AS3935 lightning detection sensor. + + To compile this driver as a module, choose M here: the + module will be called as3935 + +endmenu diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile new file mode 100644 index 00000000000000..743adee1c8bff9 --- /dev/null +++ b/drivers/iio/proximity/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for IIO proximity sensors +# + +# When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AS3935) += as3935.o diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c new file mode 100644 index 00000000000000..bf677bfe8eb2c5 --- /dev/null +++ b/drivers/iio/proximity/as3935.c @@ -0,0 +1,456 @@ +/* + * as3935.c - Support for AS3935 Franklin lightning sensor + * + * Copyright (C) 2014 Matt Ranostay + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define AS3935_AFE_GAIN 0x00 +#define AS3935_AFE_MASK 0x3F +#define AS3935_AFE_GAIN_MAX 0x1F +#define AS3935_AFE_PWR_BIT BIT(0) + +#define AS3935_INT 0x03 +#define AS3935_INT_MASK 0x07 +#define AS3935_EVENT_INT BIT(3) +#define AS3935_NOISE_INT BIT(1) + +#define AS3935_DATA 0x07 +#define AS3935_DATA_MASK 0x3F + +#define AS3935_TUNE_CAP 0x08 +#define AS3935_CALIBRATE 0x3D + +#define AS3935_WRITE_DATA BIT(15) +#define AS3935_READ_DATA BIT(14) +#define AS3935_ADDRESS(x) ((x) << 8) + +#define MAX_PF_CAP 120 +#define TUNE_CAP_DIV 8 + +struct as3935_state { + struct spi_device *spi; + struct iio_trigger *trig; + struct mutex lock; + struct delayed_work work; + + u32 tune_cap; + u8 buf[2] ____cacheline_aligned; +}; + +static const struct iio_chan_spec as3935_channels[] = { + { + .type = IIO_PROXIMITY, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_PROCESSED), + .scan_index = 0, + .scan_type = { + .sign = 'u', + .realbits = 6, + .storagebits = 8, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static int as3935_read(struct as3935_state *st, unsigned int reg, int *val) +{ + u8 cmd; + int ret; + + cmd = (AS3935_READ_DATA | AS3935_ADDRESS(reg)) >> 8; + ret = spi_w8r8(st->spi, cmd); + if (ret < 0) + return ret; + *val = ret; + + return 0; +}; + +static int as3935_write(struct as3935_state *st, + unsigned int reg, + unsigned int val) +{ + u8 *buf = st->buf; + + buf[0] = (AS3935_WRITE_DATA | AS3935_ADDRESS(reg)) >> 8; + buf[1] = val; + + return spi_write(st->spi, buf, 2); +}; + +static ssize_t as3935_sensor_sensitivity_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct as3935_state *st = iio_priv(dev_to_iio_dev(dev)); + int val, ret; + + ret = as3935_read(st, AS3935_AFE_GAIN, &val); + if (ret) + return ret; + val = (val & AS3935_AFE_MASK) >> 1; + + return sprintf(buf, "%d\n", val); +}; + +static ssize_t as3935_sensor_sensitivity_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct as3935_state *st = iio_priv(dev_to_iio_dev(dev)); + unsigned long val; + int ret; + + ret = kstrtoul((const char *) buf, 10, &val); + if (ret) + return -EINVAL; + + if (val > AS3935_AFE_GAIN_MAX) + return -EINVAL; + + as3935_write(st, AS3935_AFE_GAIN, val << 1); + + return len; +}; + +static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR, + as3935_sensor_sensitivity_show, as3935_sensor_sensitivity_store, 0); + + +static struct attribute *as3935_attributes[] = { + &iio_dev_attr_sensor_sensitivity.dev_attr.attr, + NULL, +}; + +static struct attribute_group as3935_attribute_group = { + .attrs = as3935_attributes, +}; + +static int as3935_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) +{ + struct as3935_state *st = iio_priv(indio_dev); + int ret; + + + switch (m) { + case IIO_CHAN_INFO_PROCESSED: + case IIO_CHAN_INFO_RAW: + *val2 = 0; + ret = as3935_read(st, AS3935_DATA, val); + if (ret) + return ret; + + if (m == IIO_CHAN_INFO_RAW) + return IIO_VAL_INT; + + /* storm out of range */ + if (*val == AS3935_DATA_MASK) + return -EINVAL; + *val *= 1000; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT; +} + +static const struct iio_info as3935_info = { + .driver_module = THIS_MODULE, + .attrs = &as3935_attribute_group, + .read_raw = &as3935_read_raw, +}; + +static irqreturn_t as3935_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct as3935_state *st = iio_priv(indio_dev); + int val, ret; + + ret = as3935_read(st, AS3935_DATA, &val); + if (ret) + goto err_read; + val &= AS3935_DATA_MASK; + val *= 1000; + + iio_push_to_buffers_with_timestamp(indio_dev, &val, pf->timestamp); +err_read: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +}; + +static const struct iio_trigger_ops iio_interrupt_trigger_ops = { + .owner = THIS_MODULE, +}; + +static void as3935_event_work(struct work_struct *work) +{ + struct as3935_state *st; + int val; + + st = container_of(work, struct as3935_state, work.work); + + as3935_read(st, AS3935_INT, &val); + val &= AS3935_INT_MASK; + + switch (val) { + case AS3935_EVENT_INT: + iio_trigger_poll(st->trig, iio_get_time_ns()); + break; + case AS3935_NOISE_INT: + dev_warn(&st->spi->dev, "noise level is too high"); + break; + } +}; + +static irqreturn_t as3935_interrupt_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct as3935_state *st = iio_priv(indio_dev); + + /* + * Delay work for >2 milliseconds after an interrupt to allow + * estimated distance to recalculated. + */ + + schedule_delayed_work(&st->work, msecs_to_jiffies(3)); + + return IRQ_HANDLED; +} + +static void calibrate_as3935(struct as3935_state *st) +{ + mutex_lock(&st->lock); + + /* mask disturber interrupt bit */ + as3935_write(st, AS3935_INT, BIT(5)); + + as3935_write(st, AS3935_CALIBRATE, 0x96); + as3935_write(st, AS3935_TUNE_CAP, + BIT(5) | (st->tune_cap / TUNE_CAP_DIV)); + + mdelay(2); + as3935_write(st, AS3935_TUNE_CAP, (st->tune_cap / TUNE_CAP_DIV)); + + mutex_unlock(&st->lock); +} + +#ifdef CONFIG_PM_SLEEP +static int as3935_suspend(struct spi_device *spi, pm_message_t msg) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct as3935_state *st = iio_priv(indio_dev); + int val, ret; + + mutex_lock(&st->lock); + ret = as3935_read(st, AS3935_AFE_GAIN, &val); + if (ret) + goto err_suspend; + val |= AS3935_AFE_PWR_BIT; + + ret = as3935_write(st, AS3935_AFE_GAIN, val); + +err_suspend: + mutex_unlock(&st->lock); + + return ret; +} + +static int as3935_resume(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct as3935_state *st = iio_priv(indio_dev); + int val, ret; + + mutex_lock(&st->lock); + ret = as3935_read(st, AS3935_AFE_GAIN, &val); + if (ret) + goto err_resume; + val &= ~AS3935_AFE_PWR_BIT; + ret = as3935_write(st, AS3935_AFE_GAIN, val); + +err_resume: + mutex_unlock(&st->lock); + + return ret; +} +#else +#define as3935_suspend NULL +#define as3935_resume NULL +#endif + +static int as3935_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct iio_trigger *trig; + struct as3935_state *st; + struct device_node *np = spi->dev.of_node; + int ret; + + /* Be sure lightning event interrupt is specified */ + if (!spi->irq) { + dev_err(&spi->dev, "unable to get event interrupt\n"); + return -EINVAL; + } + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + st->tune_cap = 0; + + spi_set_drvdata(spi, indio_dev); + mutex_init(&st->lock); + INIT_DELAYED_WORK(&st->work, as3935_event_work); + + ret = of_property_read_u32(np, + "ams,tuning-capacitor-pf", &st->tune_cap); + if (ret) { + st->tune_cap = 0; + dev_warn(&spi->dev, + "no tuning-capacitor-pf set, defaulting to %d", + st->tune_cap); + } + + if (st->tune_cap > MAX_PF_CAP) { + dev_err(&spi->dev, + "wrong tuning-capacitor-pf setting of %d\n", + st->tune_cap); + return -EINVAL; + } + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->channels = as3935_channels; + indio_dev->num_channels = ARRAY_SIZE(as3935_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &as3935_info; + + trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", + indio_dev->name, indio_dev->id); + + if (!trig) + return -ENOMEM; + + st->trig = trig; + trig->dev.parent = indio_dev->dev.parent; + iio_trigger_set_drvdata(trig, indio_dev); + trig->ops = &iio_interrupt_trigger_ops; + + ret = iio_trigger_register(trig); + if (ret) { + dev_err(&spi->dev, "failed to register trigger\n"); + return ret; + } + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &as3935_trigger_handler, NULL); + + if (ret) { + dev_err(&spi->dev, "cannot setup iio trigger\n"); + goto unregister_trigger; + } + + calibrate_as3935(st); + + ret = devm_request_irq(&spi->dev, spi->irq, + &as3935_interrupt_handler, + IRQF_TRIGGER_RISING, + dev_name(&spi->dev), + indio_dev); + + if (ret) { + dev_err(&spi->dev, "unable to request irq\n"); + goto unregister_buffer; + } + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&spi->dev, "unable to register device\n"); + goto unregister_buffer; + } + return 0; + +unregister_buffer: + iio_triggered_buffer_cleanup(indio_dev); + +unregister_trigger: + iio_trigger_unregister(st->trig); + + return ret; +}; + +static int as3935_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct as3935_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + iio_trigger_unregister(st->trig); + + return 0; +}; + +static const struct spi_device_id as3935_id[] = { + {"as3935", 0}, + {}, +}; +MODULE_DEVICE_TABLE(spi, as3935_id); + +static struct spi_driver as3935_driver = { + .driver = { + .name = "as3935", + .owner = THIS_MODULE, + }, + .probe = as3935_probe, + .remove = as3935_remove, + .id_table = as3935_id, + .suspend = as3935_suspend, + .resume = as3935_resume, +}; +module_spi_driver(as3935_driver); + +MODULE_AUTHOR("Matt Ranostay "); +MODULE_DESCRIPTION("AS3935 lightning sensor"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:as3935"); diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig index 372f8fb3085fa1..21feaa4661b467 100644 --- a/drivers/iio/temperature/Kconfig +++ b/drivers/iio/temperature/Kconfig @@ -3,6 +3,16 @@ # menu "Temperature sensors" +config MLX90614 + tristate "MLX90614 contact-less infrared sensor" + depends on I2C + help + If you say yes here you get support for the Melexis + MLX90614 contact-less infrared sensor connected with I2C. + + This driver can also be built as a module. If so, the module will + be called mlx90614. + config TMP006 tristate "TMP006 infrared thermopile sensor" depends on I2C diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile index 24d7b602db3ec3..40710a81158e1c 100644 --- a/drivers/iio/temperature/Makefile +++ b/drivers/iio/temperature/Makefile @@ -2,4 +2,5 @@ # Makefile for industrial I/O temperature drivers # +obj-$(CONFIG_MLX90614) += mlx90614.o obj-$(CONFIG_TMP006) += tmp006.o diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c new file mode 100644 index 00000000000000..c8b6ac8b2d69ad --- /dev/null +++ b/drivers/iio/temperature/mlx90614.c @@ -0,0 +1,150 @@ +/* + * mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor + * + * Copyright (c) 2014 Peter Meerwald + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * Driver for the Melexis MLX90614 I2C 16-bit IR thermopile sensor + * + * (7-bit I2C slave address 0x5a, 100KHz bus speed only!) + * + * TODO: sleep mode, configuration EEPROM + */ + +#include +#include +#include + +#include + +#define MLX90614_OP_RAM 0x00 + +/* RAM offsets with 16-bit data, MSB first */ +#define MLX90614_TA 0x06 /* ambient temperature */ +#define MLX90614_TOBJ1 0x07 /* object temperature */ + +struct mlx90614_data { + struct i2c_client *client; +}; + +static int mlx90614_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *val, + int *val2, long mask) +{ + struct mlx90614_data *data = iio_priv(indio_dev); + s32 ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */ + switch (channel->channel2) { + case IIO_MOD_TEMP_AMBIENT: + ret = i2c_smbus_read_word_data(data->client, + MLX90614_OP_RAM | MLX90614_TA); + if (ret < 0) + return ret; + break; + case IIO_MOD_TEMP_OBJECT: + ret = i2c_smbus_read_word_data(data->client, + MLX90614_OP_RAM | MLX90614_TOBJ1); + if (ret < 0) + return ret; + break; + default: + return -EINVAL; + } + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_OFFSET: + *val = 13657; + *val2 = 500000; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SCALE: + *val = 20; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static const struct iio_chan_spec mlx90614_channels[] = { + { + .type = IIO_TEMP, + .modified = 1, + .channel2 = IIO_MOD_TEMP_AMBIENT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_TEMP, + .modified = 1, + .channel2 = IIO_MOD_TEMP_OBJECT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static const struct iio_info mlx90614_info = { + .read_raw = mlx90614_read_raw, + .driver_module = THIS_MODULE, +}; + +static int mlx90614_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct mlx90614_data *data; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + indio_dev->dev.parent = &client->dev; + indio_dev->name = id->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &mlx90614_info; + + indio_dev->channels = mlx90614_channels; + indio_dev->num_channels = ARRAY_SIZE(mlx90614_channels); + + return iio_device_register(indio_dev); +} + +static int mlx90614_remove(struct i2c_client *client) +{ + iio_device_unregister(i2c_get_clientdata(client)); + + return 0; +} + +static const struct i2c_device_id mlx90614_id[] = { + { "mlx90614", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mlx90614_id); + +static struct i2c_driver mlx90614_driver = { + .driver = { + .name = "mlx90614", + .owner = THIS_MODULE, + }, + .probe = mlx90614_probe, + .remove = mlx90614_remove, + .id_table = mlx90614_id, +}; +module_i2c_driver(mlx90614_driver); + +MODULE_AUTHOR("Peter Meerwald "); +MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index ce953d895f5b2b..fd325ec9f064c9 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -629,12 +629,10 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) return copy_to_user(p, str, len) ? -EFAULT : len; } -#define OLD_KEY_MAX 0x1ff static int handle_eviocgbit(struct input_dev *dev, unsigned int type, unsigned int size, void __user *p, int compat_mode) { - static unsigned long keymax_warn_time; unsigned long *bits; int len; @@ -652,24 +650,8 @@ static int handle_eviocgbit(struct input_dev *dev, default: return -EINVAL; } - /* - * Work around bugs in userspace programs that like to do - * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len' - * should be in bytes, not in bits. - */ - if (type == EV_KEY && size == OLD_KEY_MAX) { - len = OLD_KEY_MAX; - if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000)) - pr_warning("(EVIOCGBIT): Suspicious buffer size %u, " - "limiting output to %zu bytes. See " - "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n", - OLD_KEY_MAX, - BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long)); - } - return bits_to_user(bits, len, size, p, compat_mode); } -#undef OLD_KEY_MAX static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p) { diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 76842d7dc2e3da..948a3030487091 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -524,6 +524,17 @@ config KEYBOARD_STOWAWAY To compile this driver as a module, choose M here: the module will be called stowaway. +config KEYBOARD_ST_KEYSCAN + tristate "STMicroelectronics keyscan support" + depends on ARCH_STI || COMPILE_TEST + select INPUT_MATRIXKMAP + help + Say Y here if you want to use a keypad attached to the keyscan block + on some STMicroelectronics SoC devices. + + To compile this driver as a module, choose M here: the + module will be called st-keyscan. + config KEYBOARD_SUNKBD tristate "Sun Type 4 and Type 5 keyboard" select SERIO diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 11cff7b84b47cd..7504ae19049dab 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o +obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o diff --git a/drivers/input/keyboard/clps711x-keypad.c b/drivers/input/keyboard/clps711x-keypad.c index 3955aecee44b99..552b65c6e6b0bc 100644 --- a/drivers/input/keyboard/clps711x-keypad.c +++ b/drivers/input/keyboard/clps711x-keypad.c @@ -185,7 +185,7 @@ static int clps711x_keypad_remove(struct platform_device *pdev) return 0; } -static struct of_device_id clps711x_keypad_of_match[] = { +static const struct of_device_id clps711x_keypad_of_match[] = { { .compatible = "cirrus,clps711x-keypad", }, { } }; diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 2db13246eb8e0b..af85218506c15b 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -578,23 +578,18 @@ gpio_keys_get_devtree_pdata(struct device *dev) int i; node = dev->of_node; - if (!node) { - error = -ENODEV; - goto err_out; - } + if (!node) + return ERR_PTR(-ENODEV); nbuttons = of_get_child_count(node); - if (nbuttons == 0) { - error = -ENODEV; - goto err_out; - } + if (nbuttons == 0) + return ERR_PTR(-ENODEV); - pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button), - GFP_KERNEL); - if (!pdata) { - error = -ENOMEM; - goto err_out; - } + pdata = devm_kzalloc(dev, + sizeof(*pdata) + nbuttons * sizeof(*button), + GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); pdata->buttons = (struct gpio_keys_button *)(pdata + 1); pdata->nbuttons = nbuttons; @@ -619,7 +614,7 @@ gpio_keys_get_devtree_pdata(struct device *dev) dev_err(dev, "Failed to get gpio flags, error: %d\n", error); - goto err_free_pdata; + return ERR_PTR(error); } button = &pdata->buttons[i++]; @@ -630,8 +625,7 @@ gpio_keys_get_devtree_pdata(struct device *dev) if (of_property_read_u32(pp, "linux,code", &button->code)) { dev_err(dev, "Button without keycode: 0x%x\n", button->gpio); - error = -EINVAL; - goto err_free_pdata; + return ERR_PTR(-EINVAL); } button->desc = of_get_property(pp, "label", NULL); @@ -646,20 +640,13 @@ gpio_keys_get_devtree_pdata(struct device *dev) button->debounce_interval = 5; } - if (pdata->nbuttons == 0) { - error = -EINVAL; - goto err_free_pdata; - } + if (pdata->nbuttons == 0) + return ERR_PTR(-EINVAL); return pdata; - -err_free_pdata: - kfree(pdata); -err_out: - return ERR_PTR(error); } -static struct of_device_id gpio_keys_of_match[] = { +static const struct of_device_id gpio_keys_of_match[] = { { .compatible = "gpio-keys", }, { }, }; @@ -691,6 +678,7 @@ static int gpio_keys_probe(struct platform_device *pdev) const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); struct gpio_keys_drvdata *ddata; struct input_dev *input; + size_t size; int i, error; int wakeup = 0; @@ -700,14 +688,18 @@ static int gpio_keys_probe(struct platform_device *pdev) return PTR_ERR(pdata); } - ddata = kzalloc(sizeof(struct gpio_keys_drvdata) + - pdata->nbuttons * sizeof(struct gpio_button_data), - GFP_KERNEL); - input = input_allocate_device(); - if (!ddata || !input) { + size = sizeof(struct gpio_keys_drvdata) + + pdata->nbuttons * sizeof(struct gpio_button_data); + ddata = devm_kzalloc(dev, size, GFP_KERNEL); + if (!ddata) { dev_err(dev, "failed to allocate state\n"); - error = -ENOMEM; - goto fail1; + return -ENOMEM; + } + + input = devm_input_allocate_device(dev); + if (!input) { + dev_err(dev, "failed to allocate input device\n"); + return -ENOMEM; } ddata->pdata = pdata; @@ -768,20 +760,12 @@ static int gpio_keys_probe(struct platform_device *pdev) while (--i >= 0) gpio_remove_key(&ddata->data[i]); - fail1: - input_free_device(input); - kfree(ddata); - /* If we have no platform data, we allocated pdata dynamically. */ - if (!dev_get_platdata(&pdev->dev)) - kfree(pdata); - return error; } static int gpio_keys_remove(struct platform_device *pdev) { struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); - struct input_dev *input = ddata->input; int i; sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); @@ -791,14 +775,6 @@ static int gpio_keys_remove(struct platform_device *pdev) for (i = 0; i < ddata->pdata->nbuttons; i++) gpio_remove_key(&ddata->data[i]); - input_unregister_device(input); - - /* If we have no platform data, we allocated pdata dynamically. */ - if (!dev_get_platdata(&pdev->dev)) - kfree(ddata->pdata); - - kfree(ddata); - return 0; } diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index e571e194ff84e8..bea53a633c52e2 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -191,7 +191,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct return ERR_PTR(error); } -static struct of_device_id gpio_keys_polled_of_match[] = { +static const struct of_device_id gpio_keys_polled_of_match[] = { { .compatible = "gpio-keys-polled", }, { }, }; diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 97ec33572e563f..8280cb16260be6 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -415,7 +415,7 @@ static int imx_keypad_open(struct input_dev *dev) } #ifdef CONFIG_OF -static struct of_device_id imx_keypad_of_match[] = { +static const struct of_device_id imx_keypad_of_match[] = { { .compatible = "fsl,imx21-kpp", }, { /* sentinel */ } }; diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c new file mode 100644 index 00000000000000..758b48731415a2 --- /dev/null +++ b/drivers/input/keyboard/st-keyscan.c @@ -0,0 +1,274 @@ +/* + * STMicroelectronics Key Scanning driver + * + * Copyright (c) 2014 STMicroelectonics Ltd. + * Author: Stuart Menefy + * + * Based on sh_keysc.c, copyright 2008 Magnus Damm + * + * 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 +#include + +#define ST_KEYSCAN_MAXKEYS 16 + +#define KEYSCAN_CONFIG_OFF 0x0 +#define KEYSCAN_CONFIG_ENABLE 0x1 +#define KEYSCAN_DEBOUNCE_TIME_OFF 0x4 +#define KEYSCAN_MATRIX_STATE_OFF 0x8 +#define KEYSCAN_MATRIX_DIM_OFF 0xc +#define KEYSCAN_MATRIX_DIM_X_SHIFT 0x0 +#define KEYSCAN_MATRIX_DIM_Y_SHIFT 0x2 + +struct st_keyscan { + void __iomem *base; + int irq; + struct clk *clk; + struct input_dev *input_dev; + unsigned long last_state; + unsigned int n_rows; + unsigned int n_cols; + unsigned int debounce_us; +}; + +static irqreturn_t keyscan_isr(int irq, void *dev_id) +{ + struct st_keyscan *keypad = dev_id; + unsigned short *keycode = keypad->input_dev->keycode; + unsigned long state, change; + int bit_nr; + + state = readl(keypad->base + KEYSCAN_MATRIX_STATE_OFF) & 0xffff; + change = keypad->last_state ^ state; + keypad->last_state = state; + + for_each_set_bit(bit_nr, &change, BITS_PER_LONG) + input_report_key(keypad->input_dev, + keycode[bit_nr], state & BIT(bit_nr)); + + input_sync(keypad->input_dev); + + return IRQ_HANDLED; +} + +static int keyscan_start(struct st_keyscan *keypad) +{ + int error; + + error = clk_enable(keypad->clk); + if (error) + return error; + + writel(keypad->debounce_us * (clk_get_rate(keypad->clk) / 1000000), + keypad->base + KEYSCAN_DEBOUNCE_TIME_OFF); + + writel(((keypad->n_cols - 1) << KEYSCAN_MATRIX_DIM_X_SHIFT) | + ((keypad->n_rows - 1) << KEYSCAN_MATRIX_DIM_Y_SHIFT), + keypad->base + KEYSCAN_MATRIX_DIM_OFF); + + writel(KEYSCAN_CONFIG_ENABLE, keypad->base + KEYSCAN_CONFIG_OFF); + + return 0; +} + +static void keyscan_stop(struct st_keyscan *keypad) +{ + writel(0, keypad->base + KEYSCAN_CONFIG_OFF); + + clk_disable(keypad->clk); +} + +static int keyscan_open(struct input_dev *dev) +{ + struct st_keyscan *keypad = input_get_drvdata(dev); + + return keyscan_start(keypad); +} + +static void keyscan_close(struct input_dev *dev) +{ + struct st_keyscan *keypad = input_get_drvdata(dev); + + keyscan_stop(keypad); +} + +static int keypad_matrix_key_parse_dt(struct st_keyscan *keypad_data) +{ + struct device *dev = keypad_data->input_dev->dev.parent; + struct device_node *np = dev->of_node; + int error; + + error = matrix_keypad_parse_of_params(dev, &keypad_data->n_rows, + &keypad_data->n_cols); + if (error) { + dev_err(dev, "failed to parse keypad params\n"); + return error; + } + + of_property_read_u32(np, "st,debounce-us", &keypad_data->debounce_us); + + dev_dbg(dev, "n_rows=%d n_col=%d debounce=%d\n", + keypad_data->n_rows, keypad_data->n_cols, + keypad_data->debounce_us); + + return 0; +} + +static int keyscan_probe(struct platform_device *pdev) +{ + struct st_keyscan *keypad_data; + struct input_dev *input_dev; + struct resource *res; + int error; + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, "no DT data present\n"); + return -EINVAL; + } + + keypad_data = devm_kzalloc(&pdev->dev, sizeof(*keypad_data), + GFP_KERNEL); + if (!keypad_data) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) { + dev_err(&pdev->dev, "failed to allocate the input device\n"); + return -ENOMEM; + } + + input_dev->name = pdev->name; + input_dev->phys = "keyscan-keys/input0"; + input_dev->dev.parent = &pdev->dev; + input_dev->open = keyscan_open; + input_dev->close = keyscan_close; + + input_dev->id.bustype = BUS_HOST; + + error = keypad_matrix_key_parse_dt(keypad_data); + if (error) + return error; + + error = matrix_keypad_build_keymap(NULL, NULL, + keypad_data->n_rows, + keypad_data->n_cols, + NULL, input_dev); + if (error) { + dev_err(&pdev->dev, "failed to build keymap\n"); + return error; + } + + input_set_drvdata(input_dev, keypad_data); + + keypad_data->input_dev = input_dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + keypad_data->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(keypad_data->base)) + return PTR_ERR(keypad_data->base); + + keypad_data->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(keypad_data->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + return PTR_ERR(keypad_data->clk); + } + + error = clk_enable(keypad_data->clk); + if (error) { + dev_err(&pdev->dev, "failed to enable clock\n"); + return error; + } + + keyscan_stop(keypad_data); + + keypad_data->irq = platform_get_irq(pdev, 0); + if (keypad_data->irq < 0) { + dev_err(&pdev->dev, "no IRQ specified\n"); + return -EINVAL; + } + + error = devm_request_irq(&pdev->dev, keypad_data->irq, keyscan_isr, 0, + pdev->name, keypad_data); + if (error) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + return error; + } + + error = input_register_device(input_dev); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + return error; + } + + platform_set_drvdata(pdev, keypad_data); + + device_set_wakeup_capable(&pdev->dev, 1); + + return 0; +} + +static int keyscan_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct st_keyscan *keypad = platform_get_drvdata(pdev); + struct input_dev *input = keypad->input_dev; + + mutex_lock(&input->mutex); + + if (device_may_wakeup(dev)) + enable_irq_wake(keypad->irq); + else if (input->users) + keyscan_stop(keypad); + + mutex_unlock(&input->mutex); + return 0; +} + +static int keyscan_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct st_keyscan *keypad = platform_get_drvdata(pdev); + struct input_dev *input = keypad->input_dev; + int retval = 0; + + mutex_lock(&input->mutex); + + if (device_may_wakeup(dev)) + disable_irq_wake(keypad->irq); + else if (input->users) + retval = keyscan_start(keypad); + + mutex_unlock(&input->mutex); + return retval; +} + +static SIMPLE_DEV_PM_OPS(keyscan_dev_pm_ops, keyscan_suspend, keyscan_resume); + +static const struct of_device_id keyscan_of_match[] = { + { .compatible = "st,sti-keyscan" }, + { }, +}; +MODULE_DEVICE_TABLE(of, keyscan_of_match); + +static struct platform_driver keyscan_device_driver = { + .probe = keyscan_probe, + .driver = { + .name = "st-keyscan", + .pm = &keyscan_dev_pm_ops, + .of_match_table = of_match_ptr(keyscan_of_match), + } +}; + +module_platform_driver(keyscan_device_driver); + +MODULE_AUTHOR("Stuart Menefy "); +MODULE_DESCRIPTION("STMicroelectronics keyscan device driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index 74494a357522db..ad7abae690781a 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -296,6 +296,65 @@ static void tc3589x_keypad_close(struct input_dev *input) tc3589x_keypad_disable(keypad); } +#ifdef CONFIG_OF +static const struct tc3589x_keypad_platform_data * +tc3589x_keypad_of_probe(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct tc3589x_keypad_platform_data *plat; + u32 cols, rows; + u32 debounce_ms; + int proplen; + + if (!np) + return ERR_PTR(-ENODEV); + + plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL); + if (!plat) + return ERR_PTR(-ENOMEM); + + of_property_read_u32(np, "keypad,num-columns", &cols); + of_property_read_u32(np, "keypad,num-rows", &rows); + plat->kcol = (u8) cols; + plat->krow = (u8) rows; + if (!plat->krow || !plat->kcol || + plat->krow > TC_KPD_ROWS || plat->kcol > TC_KPD_COLUMNS) { + dev_err(dev, + "keypad columns/rows not properly specified (%ux%u)\n", + plat->kcol, plat->krow); + return ERR_PTR(-EINVAL); + } + + if (!of_get_property(np, "linux,keymap", &proplen)) { + dev_err(dev, "property linux,keymap not found\n"); + return ERR_PTR(-ENOENT); + } + + plat->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat"); + plat->enable_wakeup = of_property_read_bool(np, "linux,wakeup"); + + /* The custom delay format is ms/16 */ + of_property_read_u32(np, "debounce-delay-ms", &debounce_ms); + if (debounce_ms) + plat->debounce_period = debounce_ms * 16; + else + plat->debounce_period = TC_KPD_DEBOUNCE_PERIOD; + + plat->settle_time = TC_KPD_SETTLE_TIME; + /* FIXME: should be property of the IRQ resource? */ + plat->irqtype = IRQF_TRIGGER_FALLING; + + return plat; +} +#else +static inline const struct tc3589x_keypad_platform_data * +tc3589x_keypad_of_probe(struct device *dev) +{ + return ERR_PTR(-ENODEV); +} +#endif + + static int tc3589x_keypad_probe(struct platform_device *pdev) { struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); @@ -306,8 +365,11 @@ static int tc3589x_keypad_probe(struct platform_device *pdev) plat = tc3589x->pdata->keypad; if (!plat) { - dev_err(&pdev->dev, "invalid keypad platform data\n"); - return -EINVAL; + plat = tc3589x_keypad_of_probe(&pdev->dev); + if (IS_ERR(plat)) { + dev_err(&pdev->dev, "invalid keypad platform data\n"); + return PTR_ERR(plat); + } } irq = platform_get_irq(pdev, 0); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 5928ea71dd6963..2ff4425a893b36 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -224,7 +224,7 @@ config INPUT_GP2A config INPUT_GPIO_BEEPER tristate "Generic GPIO Beeper support" - depends on OF_GPIO + depends on GPIOLIB help Say Y here if you have a beeper connected to a GPIO pin. diff --git a/drivers/input/misc/gpio-beeper.c b/drivers/input/misc/gpio-beeper.c index b757435e2b3d0e..8886af63eae3c1 100644 --- a/drivers/input/misc/gpio-beeper.c +++ b/drivers/input/misc/gpio-beeper.c @@ -1,7 +1,7 @@ /* * Generic GPIO beeper driver * - * Copyright (C) 2013 Alexander Shiyan + * Copyright (C) 2013-2014 Alexander Shiyan * * 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 @@ -11,7 +11,8 @@ #include #include -#include +#include +#include #include #include @@ -19,14 +20,13 @@ struct gpio_beeper { struct work_struct work; - int gpio; - bool active_low; + struct gpio_desc *desc; bool beeping; }; static void gpio_beeper_toggle(struct gpio_beeper *beep, bool on) { - gpio_set_value_cansleep(beep->gpio, on ^ beep->active_low); + gpiod_set_value_cansleep(beep->desc, on); } static void gpio_beeper_work(struct work_struct *work) @@ -65,18 +65,16 @@ static void gpio_beeper_close(struct input_dev *input) static int gpio_beeper_probe(struct platform_device *pdev) { struct gpio_beeper *beep; - enum of_gpio_flags flags; struct input_dev *input; - unsigned long gflags; int err; beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL); if (!beep) return -ENOMEM; - beep->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, &flags); - if (!gpio_is_valid(beep->gpio)) - return beep->gpio; + beep->desc = devm_gpiod_get(&pdev->dev, NULL); + if (IS_ERR(beep->desc)) + return PTR_ERR(beep->desc); input = devm_input_allocate_device(&pdev->dev); if (!input) @@ -94,10 +92,7 @@ static int gpio_beeper_probe(struct platform_device *pdev) input_set_capability(input, EV_SND, SND_BELL); - beep->active_low = flags & OF_GPIO_ACTIVE_LOW; - gflags = beep->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; - - err = devm_gpio_request_one(&pdev->dev, beep->gpio, gflags, pdev->name); + err = gpiod_direction_output(beep->desc, 0); if (err) return err; @@ -106,17 +101,19 @@ static int gpio_beeper_probe(struct platform_device *pdev) return input_register_device(input); } -static struct of_device_id gpio_beeper_of_match[] = { +#ifdef CONFIG_OF +static const struct of_device_id gpio_beeper_of_match[] = { { .compatible = BEEPER_MODNAME, }, { } }; MODULE_DEVICE_TABLE(of, gpio_beeper_of_match); +#endif static struct platform_driver gpio_beeper_platform_driver = { .driver = { .name = BEEPER_MODNAME, .owner = THIS_MODULE, - .of_match_table = gpio_beeper_of_match, + .of_match_table = of_match_ptr(gpio_beeper_of_match), }, .probe = gpio_beeper_probe, }; diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 99b9e42aa7482c..93558a1c7f704f 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -143,7 +143,7 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) } #ifdef CONFIG_OF -static struct of_device_id rotary_encoder_of_match[] = { +static const struct of_device_id rotary_encoder_of_match[] = { { .compatible = "rotary-encoder", }, { }, }; diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c index 77dc23b94eb1ea..6d26eecc278c7e 100644 --- a/drivers/input/misc/twl6040-vibra.c +++ b/drivers/input/misc/twl6040-vibra.c @@ -262,7 +262,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev) struct vibra_info *info; int vddvibl_uV = 0; int vddvibr_uV = 0; - int ret; + int error; twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node, "vibra"); @@ -309,12 +309,12 @@ static int twl6040_vibra_probe(struct platform_device *pdev) mutex_init(&info->mutex); - ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, - twl6040_vib_irq_handler, 0, - "twl6040_irq_vib", info); - if (ret) { - dev_err(info->dev, "VIB IRQ request failed: %d\n", ret); - return ret; + error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, + twl6040_vib_irq_handler, 0, + "twl6040_irq_vib", info); + if (error) { + dev_err(info->dev, "VIB IRQ request failed: %d\n", error); + return error; } info->supplies[0].supply = "vddvibl"; @@ -323,40 +323,40 @@ static int twl6040_vibra_probe(struct platform_device *pdev) * When booted with Device tree the regulators are attached to the * parent device (twl6040 MFD core) */ - ret = regulator_bulk_get(twl6040_core_dev, ARRAY_SIZE(info->supplies), - info->supplies); - if (ret) { - dev_err(info->dev, "couldn't get regulators %d\n", ret); - return ret; + error = devm_regulator_bulk_get(twl6040_core_dev, + ARRAY_SIZE(info->supplies), + info->supplies); + if (error) { + dev_err(info->dev, "couldn't get regulators %d\n", error); + return error; } if (vddvibl_uV) { - ret = regulator_set_voltage(info->supplies[0].consumer, - vddvibl_uV, vddvibl_uV); - if (ret) { + error = regulator_set_voltage(info->supplies[0].consumer, + vddvibl_uV, vddvibl_uV); + if (error) { dev_err(info->dev, "failed to set VDDVIBL volt %d\n", - ret); - goto err_regulator; + error); + return error; } } if (vddvibr_uV) { - ret = regulator_set_voltage(info->supplies[1].consumer, - vddvibr_uV, vddvibr_uV); - if (ret) { + error = regulator_set_voltage(info->supplies[1].consumer, + vddvibr_uV, vddvibr_uV); + if (error) { dev_err(info->dev, "failed to set VDDVIBR volt %d\n", - ret); - goto err_regulator; + error); + return error; } } INIT_WORK(&info->play_work, vibra_play_work); - info->input_dev = input_allocate_device(); - if (info->input_dev == NULL) { + info->input_dev = devm_input_allocate_device(&pdev->dev); + if (!info->input_dev) { dev_err(info->dev, "couldn't allocate input device\n"); - ret = -ENOMEM; - goto err_regulator; + return -ENOMEM; } input_set_drvdata(info->input_dev, info); @@ -367,44 +367,25 @@ static int twl6040_vibra_probe(struct platform_device *pdev) info->input_dev->close = twl6040_vibra_close; __set_bit(FF_RUMBLE, info->input_dev->ffbit); - ret = input_ff_create_memless(info->input_dev, NULL, vibra_play); - if (ret < 0) { + error = input_ff_create_memless(info->input_dev, NULL, vibra_play); + if (error) { dev_err(info->dev, "couldn't register vibrator to FF\n"); - goto err_ialloc; + return error; } - ret = input_register_device(info->input_dev); - if (ret < 0) { + error = input_register_device(info->input_dev); + if (error) { dev_err(info->dev, "couldn't register input device\n"); - goto err_iff; + return error; } platform_set_drvdata(pdev, info); - return 0; - -err_iff: - input_ff_destroy(info->input_dev); -err_ialloc: - input_free_device(info->input_dev); -err_regulator: - regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); - return ret; -} - -static int twl6040_vibra_remove(struct platform_device *pdev) -{ - struct vibra_info *info = platform_get_drvdata(pdev); - - input_unregister_device(info->input_dev); - regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); - return 0; } static struct platform_driver twl6040_vibra_driver = { .probe = twl6040_vibra_probe, - .remove = twl6040_vibra_remove, .driver = { .name = "twl6040-vibra", .owner = THIS_MODULE, diff --git a/drivers/input/serio/apbps2.c b/drivers/input/serio/apbps2.c index 17e01a807ddc60..98be824544a531 100644 --- a/drivers/input/serio/apbps2.c +++ b/drivers/input/serio/apbps2.c @@ -203,7 +203,7 @@ static int apbps2_of_remove(struct platform_device *of_dev) return 0; } -static struct of_device_id apbps2_of_match[] = { +static const struct of_device_id apbps2_of_match[] = { { .name = "GAISLER_APBPS2", }, { .name = "01_060", }, {} diff --git a/drivers/input/serio/olpc_apsp.c b/drivers/input/serio/olpc_apsp.c index 5d2fe7ece7ca0e..d906f3ebc8c86c 100644 --- a/drivers/input/serio/olpc_apsp.c +++ b/drivers/input/serio/olpc_apsp.c @@ -262,7 +262,7 @@ static int olpc_apsp_remove(struct platform_device *pdev) return 0; } -static struct of_device_id olpc_apsp_dt_ids[] = { +static const struct of_device_id olpc_apsp_dt_ids[] = { { .compatible = "olpc,ap-sp", }, {} }; diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 4822c57a3756f4..378e3bb0520523 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -484,6 +484,8 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) input_report_key(input, BTN_TOUCH, 0); input_report_abs(input, ABS_PRESSURE, 0); input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max); + if (features->quirks & WACOM_QUIRK_MULTI_INPUT) + wacom->shared->stylus_in_proximity = true; } /* Exit report */ @@ -558,6 +560,55 @@ static void wacom_intuos_general(struct wacom_wac *wacom) } } +static bool wacom_intuos_outbound(struct wacom_wac *wacom) +{ + struct wacom_features *features = &wacom->features; + unsigned char *data = wacom->data; + struct input_dev *input = wacom->input; + unsigned int bound = 200; + bool outbound = false; + + /* Intuos and old Cintiqs use ready bit for outbound tracking */ + if (!(data[1] & 0x40)) + outbound = true; + + /* New Cintiqs have 200 counts of outbound */ + if (features->type >= WACOM_21UX2 && features->type <= WACOM_13HD) { + if (wacom->x_mapped < bound) { + wacom->x_mapped = 0; + outbound = true; + } else { + wacom->x_mapped -= bound; + if (wacom->x_mapped > features->x_max) { + wacom->x_mapped = features->x_max; + outbound = true; + } + } + + if (wacom->y_mapped < bound) { + wacom->y_mapped = 0; + outbound = true; + } else { + wacom->y_mapped -= bound; + if (wacom->y_mapped > features->y_max) { + wacom->y_mapped = features->y_max; + outbound = true; + } + } + } + + /* Intuos supports outbound tracking */ + if (outbound && (features->type >= INTUOS3S && features->type <= INTUOSPL)) { + input_report_abs(input, ABS_X, wacom->x_mapped); + input_report_abs(input, ABS_Y, wacom->y_mapped); + input_report_abs(input, ABS_MISC, wacom->id[0]); + input_report_key(input, wacom->tool[0], 1); + input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[0]); + } + + return outbound; +} + static int wacom_intuos_irq(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; @@ -798,17 +849,22 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) return 0; } - /* Cintiq doesn't send data when RDY bit isn't set */ - if (features->type == CINTIQ && !(data[1] & 0x40)) - return 0; + if (features->type >= INTUOS3S) { + wacom->x_mapped = (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1); + wacom->y_mapped = (data[4] << 9) | (data[5] << 1) | (data[9] & 1); + } else { + wacom->x_mapped = be16_to_cpup((__be16 *)&data[2]); + wacom->y_mapped = be16_to_cpup((__be16 *)&data[4]); + } + + if (wacom_intuos_outbound(wacom)) + return 0; + input_report_abs(input, ABS_X, wacom->x_mapped); + input_report_abs(input, ABS_Y, wacom->y_mapped); if (features->type >= INTUOS3S) { - input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1)); - input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1)); input_report_abs(input, ABS_DISTANCE, ((data[9] >> 2) & 0x3f)); } else { - input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[2])); - input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[4])); input_report_abs(input, ABS_DISTANCE, ((data[9] >> 3) & 0x1f)); } @@ -2123,10 +2179,10 @@ static const struct wacom_features wacom_features_0x317 = 63, INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 }; static const struct wacom_features wacom_features_0xF4 = - { "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047, + { "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104080, 65200, 2047, 63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xF8 = - { "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047, /* Pen */ + { "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS, 104080, 65200, 2047, /* Pen */ 63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 }; static const struct wacom_features wacom_features_0xF6 = @@ -2142,7 +2198,7 @@ static const struct wacom_features wacom_features_0xC6 = { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0x304 = - { "Wacom Cintiq 13HD", WACOM_PKGLEN_INTUOS, 59552, 33848, 1023, + { "Wacom Cintiq 13HD", WACOM_PKGLEN_INTUOS, 59152, 33448, 1023, 63, WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xC7 = { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, @@ -2157,23 +2213,23 @@ static const struct wacom_features wacom_features_0xFB = { "Wacom DTU1031", WACOM_PKGLEN_DTUS, 22096, 13960, 511, 0, DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x57 = - { "Wacom DTK2241", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047, + { "Wacom DTK2241", WACOM_PKGLEN_INTUOS, 95440, 53860, 2047, 63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES}; static const struct wacom_features wacom_features_0x59 = /* Pen */ - { "Wacom DTH2242", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047, + { "Wacom DTH2242", WACOM_PKGLEN_INTUOS, 95440, 53860, 2047, 63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D }; static const struct wacom_features wacom_features_0x5D = /* Touch */ { "Wacom DTH2242", .type = WACOM_24HDT, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10 }; static const struct wacom_features wacom_features_0xCC = - { "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87200, 65600, 2047, + { "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 86400, 64800, 2047, 63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xFA = - { "Wacom Cintiq 22HD", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047, + { "Wacom Cintiq 22HD", WACOM_PKGLEN_INTUOS, 95440, 53860, 2047, 63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0x5B = - { "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047, + { "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS, 95440, 53860, 2047, 63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e }; static const struct wacom_features wacom_features_0x5E = @@ -2316,7 +2372,7 @@ static const struct wacom_features wacom_features_0x6004 = { "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x0307 = - { "Wacom ISDv5 307", WACOM_PKGLEN_INTUOS, 59552, 33848, 2047, + { "Wacom ISDv5 307", WACOM_PKGLEN_INTUOS, 59152, 33448, 2047, 63, CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 }; static const struct wacom_features wacom_features_0x0309 = diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index f69c0ebe7fa90d..9f947c31ec2caa 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -93,9 +93,9 @@ enum { DTK, WACOM_24HD, CINTIQ_HYBRID, + WACOM_13HD, CINTIQ, WACOM_BEE, - WACOM_13HD, WACOM_MO, WIRELESS, BAMBOO_PT, @@ -148,6 +148,8 @@ struct wacom_wac { int tool[2]; int id[2]; __u32 serial[2]; + unsigned int x_mapped; + unsigned int y_mapped; struct wacom_features features; struct wacom_shared *shared; struct input_dev *input; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 68edc9db2c6446..e2f0264af5cc93 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -858,7 +858,7 @@ config TOUCHSCREEN_TSC2007 config TOUCHSCREEN_W90X900 tristate "W90P910 touchscreen driver" - depends on HAVE_CLK + depends on ARCH_W90X900 help Say Y here if you have a W90P910 based touchscreen. diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index 6793c85903aeb7..523865daa1d39c 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -210,11 +210,6 @@ static bool gpio3; module_param(gpio3, bool, 0); MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3"); -/* - * ad7877_read/write are only used for initial setup and for sysfs controls. - * The main traffic is done using spi_async() in the interrupt handler. - */ - static int ad7877_read(struct spi_device *spi, u16 reg) { struct ser_req *req; diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 7f8aa981500d88..da201b8e37dc90 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -706,7 +706,7 @@ static void ads7846_read_state(struct ads7846 *ts) m = &ts->msg[msg_idx]; error = spi_sync(ts->spi, m); if (error) { - dev_err(&ts->spi->dev, "spi_async --> %d\n", error); + dev_err(&ts->spi->dev, "spi_sync --> %d\n", error); packet->tc.ignore = true; return; } diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index d3f9f6b0f9b797..7f3c9478778701 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -679,7 +679,7 @@ static const struct i2c_device_id auo_pixcir_idtable[] = { MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable); #ifdef CONFIG_OF -static struct of_device_id auo_pixcir_ts_dt_idtable[] = { +static const struct of_device_id auo_pixcir_ts_dt_idtable[] = { { .compatible = "auo,auo_pixcir_ts" }, {}, }; diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index e6bcb13680b2d0..c8057847d71d47 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -262,7 +262,7 @@ static int egalax_ts_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume); -static struct of_device_id egalax_ts_dt_ids[] = { +static const struct of_device_id egalax_ts_dt_ids[] = { { .compatible = "eeti,egalax_ts" }, { /* sentinel */ } }; diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index 2058253b55d9bf..bb47d3442a35ee 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -384,7 +384,7 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = { #endif #ifdef CONFIG_OF -static struct of_device_id lpc32xx_tsc_of_match[] = { +static const struct of_device_id lpc32xx_tsc_of_match[] = { { .compatible = "nxp,lpc3220-tsc", }, { }, }; diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 8a598c065391dd..9d83413bbba737 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -570,7 +570,7 @@ static const struct i2c_device_id mms114_id[] = { MODULE_DEVICE_TABLE(i2c, mms114_id); #ifdef CONFIG_OF -static struct of_device_id mms114_dt_match[] = { +static const struct of_device_id mms114_dt_match[] = { { .compatible = "melfas,mms114" }, { } }; diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 550adcbbfc2321..d981e49368adf4 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -579,7 +579,7 @@ static int tsc2005_probe(struct spi_device *spi) int error; if (!pdata) { - dev_dbg(&spi->dev, "no platform data\n"); + dev_err(&spi->dev, "no platform data\n"); return -ENODEV; } @@ -591,7 +591,7 @@ static int tsc2005_probe(struct spi_device *spi) max_p = pdata->ts_pressure_max ? : MAX_12BIT; if (spi->irq <= 0) { - dev_dbg(&spi->dev, "no irq\n"); + dev_err(&spi->dev, "no irq\n"); return -ENODEV; } @@ -604,12 +604,13 @@ static int tsc2005_probe(struct spi_device *spi) if (error) return error; - ts = kzalloc(sizeof(*ts), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!ts || !input_dev) { - error = -ENOMEM; - goto err_free_mem; - } + ts = devm_kzalloc(&spi->dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&spi->dev); + if (!input_dev) + return -ENOMEM; ts->spi = spi; ts->idev = input_dev; @@ -649,12 +650,13 @@ static int tsc2005_probe(struct spi_device *spi) /* Ensure the touchscreen is off */ tsc2005_stop_scan(ts); - error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - "tsc2005", ts); + error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, + tsc2005_irq_thread, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "tsc2005", ts); if (error) { dev_err(&spi->dev, "Failed to request irq, err: %d\n", error); - goto err_free_mem; + return error; } spi_set_drvdata(spi, ts); @@ -662,7 +664,7 @@ static int tsc2005_probe(struct spi_device *spi) if (error) { dev_err(&spi->dev, "Failed to create sysfs attributes, err: %d\n", error); - goto err_clear_drvdata; + return error; } error = input_register_device(ts->idev); @@ -677,23 +679,12 @@ static int tsc2005_probe(struct spi_device *spi) err_remove_sysfs: sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); -err_clear_drvdata: - free_irq(spi->irq, ts); -err_free_mem: - input_free_device(input_dev); - kfree(ts); return error; } static int tsc2005_remove(struct spi_device *spi) { - struct tsc2005 *ts = spi_get_drvdata(spi); - - sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); - - free_irq(ts->spi->irq, ts); - input_unregister_device(ts->idev); - kfree(ts); + sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); return 0; } diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 01d30cedde460f..feea85b52fa89c 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -880,7 +880,7 @@ static struct i2c_device_id zforce_idtable[] = { MODULE_DEVICE_TABLE(i2c, zforce_idtable); #ifdef CONFIG_OF -static struct of_device_id zforce_dt_idtable[] = { +static const struct of_device_id zforce_dt_idtable[] = { { .compatible = "neonode,zforce" }, {}, }; diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 7fcbfc498fa93c..895af06a667fef 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -34,6 +34,9 @@ #include "omap-iopgtable.h" #include "omap-iommu.h" +#define to_iommu(dev) \ + ((struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))) + #define for_each_iotlb_cr(obj, n, __i, cr) \ for (__i = 0; \ (__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true); \ @@ -391,6 +394,7 @@ static void flush_iotlb_page(struct omap_iommu *obj, u32 da) __func__, start, da, bytes); iotlb_load_cr(obj, &cr); iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY); + break; } } pm_runtime_put_sync(obj->dev); @@ -1037,19 +1041,18 @@ static void iopte_cachep_ctor(void *iopte) clean_dcache_area(iopte, IOPTE_TABLE_SIZE); } -static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, - u32 flags) +static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, int pgsz) { memset(e, 0, sizeof(*e)); e->da = da; e->pa = pa; - e->valid = 1; + e->valid = MMU_CAM_V; /* FIXME: add OMAP1 support */ - e->pgsz = flags & MMU_CAM_PGSZ_MASK; - e->endian = flags & MMU_RAM_ENDIAN_MASK; - e->elsz = flags & MMU_RAM_ELSZ_MASK; - e->mixed = flags & MMU_RAM_MIXED_MASK; + e->pgsz = pgsz; + e->endian = MMU_RAM_ENDIAN_LITTLE; + e->elsz = MMU_RAM_ELSZ_8; + e->mixed = 0; return iopgsz_to_bytes(e->pgsz); } @@ -1062,9 +1065,8 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, struct device *dev = oiommu->dev; struct iotlb_entry e; int omap_pgsz; - u32 ret, flags; + u32 ret; - /* we only support mapping a single iommu page for now */ omap_pgsz = bytes_to_iopgsz(bytes); if (omap_pgsz < 0) { dev_err(dev, "invalid size to map: %d\n", bytes); @@ -1073,9 +1075,7 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, dev_dbg(dev, "mapping da 0x%lx to pa 0x%x size 0x%x\n", da, pa, bytes); - flags = omap_pgsz | prot; - - iotlb_init_entry(&e, da, pa, flags); + iotlb_init_entry(&e, da, pa, omap_pgsz); ret = omap_iopgtable_store_entry(oiommu, &e); if (ret) @@ -1248,12 +1248,6 @@ static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain, return ret; } -static int omap_iommu_domain_has_cap(struct iommu_domain *domain, - unsigned long cap) -{ - return 0; -} - static int omap_iommu_add_device(struct device *dev) { struct omap_iommu_arch_data *arch_data; @@ -1305,7 +1299,6 @@ static struct iommu_ops omap_iommu_ops = { .map = omap_iommu_map, .unmap = omap_iommu_unmap, .iova_to_phys = omap_iommu_iova_to_phys, - .domain_has_cap = omap_iommu_domain_has_cap, .add_device = omap_iommu_add_device, .remove_device = omap_iommu_remove_device, .pgsize_bitmap = OMAP_IOMMU_PGSIZES, diff --git a/drivers/iommu/omap-iopgtable.h b/drivers/iommu/omap-iopgtable.h index b6f9a51746caad..f891683e3f05af 100644 --- a/drivers/iommu/omap-iopgtable.h +++ b/drivers/iommu/omap-iopgtable.h @@ -93,6 +93,3 @@ static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask) /* to find an entry in the second-level page table. */ #define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1)) #define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da)) - -#define to_iommu(dev) \ - (platform_get_drvdata(to_platform_device(dev))) diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 3899ba7821c5e7..c887e6eebc4143 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -310,7 +311,8 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h, } #ifdef CONFIG_SMP -void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq) +static void armada_mpic_send_doorbell(const struct cpumask *mask, + unsigned int irq) { int cpu; unsigned long map = 0; @@ -330,7 +332,7 @@ void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq) ARMADA_370_XP_SW_TRIG_INT_OFFS); } -void armada_xp_mpic_smp_cpu_init(void) +static void armada_xp_mpic_smp_cpu_init(void) { /* Clear pending IPIs */ writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); @@ -342,6 +344,20 @@ void armada_xp_mpic_smp_cpu_init(void) /* Unmask IPI interrupt */ writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); } + +static int armada_xp_mpic_secondary_init(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) + armada_xp_mpic_smp_cpu_init(); + return NOTIFY_OK; +} + +static struct notifier_block armada_370_xp_mpic_cpu_notifier = { + .notifier_call = armada_xp_mpic_secondary_init, + .priority = 100, +}; + #endif /* CONFIG_SMP */ static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { @@ -497,6 +513,10 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node, if (parent_irq <= 0) { irq_set_default_host(armada_370_xp_mpic_domain); set_handle_irq(armada_370_xp_handle_irq); +#ifdef CONFIG_SMP + set_smp_cross_call(armada_mpic_send_doorbell); + register_cpu_notifier(&armada_370_xp_mpic_cpu_notifier); +#endif } else { irq_set_chained_handler(parent_irq, armada_370_xp_mpic_handle_cascade_irq); diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c index e25f246cd2fb9a..34d18b48bb78fe 100644 --- a/drivers/irqchip/irq-orion.c +++ b/drivers/irqchip/irq-orion.c @@ -42,7 +42,7 @@ __exception_irq_entry orion_handle_irq(struct pt_regs *regs) u32 stat = readl_relaxed(gc->reg_base + ORION_IRQ_CAUSE) & gc->mask_cache; while (stat) { - u32 hwirq = ffs(stat) - 1; + u32 hwirq = __fls(stat); u32 irq = irq_find_mapping(orion_irq_domain, gc->irq_base + hwirq); handle_IRQ(irq, regs); @@ -117,7 +117,7 @@ static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc) gc->mask_cache; while (stat) { - u32 hwirq = ffs(stat) - 1; + u32 hwirq = __fls(stat); generic_handle_irq(irq_find_mapping(d, gc->irq_base + hwirq)); stat &= ~(1 << hwirq); diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index 414dbf6da89afd..fc9f9d03fa13b8 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -197,25 +197,6 @@ typedef struct _hfc4s8s_hw { -/***************************/ -/* inline function defines */ -/***************************/ -#ifdef HISAX_HFC4S8S_PCIMEM /* inline functions memory mapped */ - -/* memory write and dummy IO read to avoid PCI byte merge problems */ -#define Write_hfc8(a, b, c) {(*((volatile u_char *)(a->membase + b)) = c); inb(a->iobase + 4);} -/* memory write without dummy IO access for fifo data access */ -#define fWrite_hfc8(a, b, c) (*((volatile u_char *)(a->membase + b)) = c) -#define Read_hfc8(a, b) (*((volatile u_char *)(a->membase + b))) -#define Write_hfc16(a, b, c) (*((volatile unsigned short *)(a->membase + b)) = c) -#define Read_hfc16(a, b) (*((volatile unsigned short *)(a->membase + b))) -#define Write_hfc32(a, b, c) (*((volatile unsigned long *)(a->membase + b)) = c) -#define Read_hfc32(a, b) (*((volatile unsigned long *)(a->membase + b))) -#define wait_busy(a) {while ((Read_hfc8(a, R_STATUS) & M_BUSY));} -#define PCI_ENA_MEMIO 0x03 - -#else - /* inline functions io mapped */ static inline void SetRegAddr(hfc4s8s_hw *a, u_char b) @@ -306,8 +287,6 @@ wait_busy(hfc4s8s_hw *a) #define PCI_ENA_REGIO 0x01 -#endif /* HISAX_HFC4S8S_PCIMEM */ - /******************************************************/ /* function to read critical counter registers that */ /* may be updated by the chip during read */ @@ -724,26 +703,15 @@ rx_d_frame(struct hfc4s8s_l1 *l1p, int ech) return; } else { /* read errornous D frame */ - -#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1p->hw, A_FIFO_DATA0); -#endif while (z1 >= 4) { -#ifdef HISAX_HFC4S8S_PCIMEM - Read_hfc32(l1p->hw, A_FIFO_DATA0); -#else fRead_hfc32(l1p->hw); -#endif z1 -= 4; } while (z1--) -#ifdef HISAX_HFC4S8S_PCIMEM - Read_hfc8(l1p->hw, A_FIFO_DATA0); -#else - fRead_hfc8(l1p->hw); -#endif + fRead_hfc8(l1p->hw); Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); wait_busy(l1p->hw); @@ -753,27 +721,16 @@ rx_d_frame(struct hfc4s8s_l1 *l1p, int ech) cp = skb->data; -#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1p->hw, A_FIFO_DATA0); -#endif while (z1 >= 4) { -#ifdef HISAX_HFC4S8S_PCIMEM - *((unsigned long *) cp) = - Read_hfc32(l1p->hw, A_FIFO_DATA0); -#else *((unsigned long *) cp) = fRead_hfc32(l1p->hw); -#endif cp += 4; z1 -= 4; } while (z1--) -#ifdef HISAX_HFC4S8S_PCIMEM - *cp++ = Read_hfc8(l1p->hw, A_FIFO_DATA0); -#else - *cp++ = fRead_hfc8(l1p->hw); -#endif + *cp++ = fRead_hfc8(l1p->hw); Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */ wait_busy(l1p->hw); @@ -859,28 +816,17 @@ rx_b_frame(struct hfc4s8s_btype *bch) wait_busy(l1->hw); return; } -#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1->hw, A_FIFO_DATA0); -#endif while (z1 >= 4) { -#ifdef HISAX_HFC4S8S_PCIMEM - *((unsigned long *) bch->rx_ptr) = - Read_hfc32(l1->hw, A_FIFO_DATA0); -#else *((unsigned long *) bch->rx_ptr) = fRead_hfc32(l1->hw); -#endif bch->rx_ptr += 4; z1 -= 4; } while (z1--) -#ifdef HISAX_HFC4S8S_PCIMEM - *(bch->rx_ptr++) = Read_hfc8(l1->hw, A_FIFO_DATA0); -#else - *(bch->rx_ptr++) = fRead_hfc8(l1->hw); -#endif + *(bch->rx_ptr++) = fRead_hfc8(l1->hw); if (hdlc_complete) { /* increment f counter */ @@ -940,29 +886,17 @@ tx_d_frame(struct hfc4s8s_l1 *l1p) if ((skb = skb_dequeue(&l1p->d_tx_queue))) { cp = skb->data; cnt = skb->len; -#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1p->hw, A_FIFO_DATA0); -#endif while (cnt >= 4) { -#ifdef HISAX_HFC4S8S_PCIMEM - fWrite_hfc32(l1p->hw, A_FIFO_DATA0, - *(unsigned long *) cp); -#else SetRegAddr(l1p->hw, A_FIFO_DATA0); fWrite_hfc32(l1p->hw, *(unsigned long *) cp); -#endif cp += 4; cnt -= 4; } -#ifdef HISAX_HFC4S8S_PCIMEM - while (cnt--) - fWrite_hfc8(l1p->hw, A_FIFO_DATA0, *cp++); -#else while (cnt--) fWrite_hfc8(l1p->hw, *cp++); -#endif l1p->tx_cnt = skb->truesize; Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */ @@ -1037,26 +971,15 @@ tx_b_frame(struct hfc4s8s_btype *bch) cp = skb->data + bch->tx_cnt; bch->tx_cnt += cnt; -#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1->hw, A_FIFO_DATA0); -#endif while (cnt >= 4) { -#ifdef HISAX_HFC4S8S_PCIMEM - fWrite_hfc32(l1->hw, A_FIFO_DATA0, - *(unsigned long *) cp); -#else fWrite_hfc32(l1->hw, *(unsigned long *) cp); -#endif cp += 4; cnt -= 4; } while (cnt--) -#ifdef HISAX_HFC4S8S_PCIMEM - fWrite_hfc8(l1->hw, A_FIFO_DATA0, *cp++); -#else - fWrite_hfc8(l1->hw, *cp++); -#endif + fWrite_hfc8(l1->hw, *cp++); if (bch->tx_cnt >= skb->len) { if (bch->mode == L1_MODE_HDLC) { @@ -1281,10 +1204,8 @@ hfc4s8s_interrupt(int intno, void *dev_id) if (!hw || !(hw->mr.r_irq_ctrl & M_GLOB_IRQ_EN)) return IRQ_NONE; -#ifndef HISAX_HFC4S8S_PCIMEM /* read current selected regsister */ old_ioreg = GetRegAddr(hw); -#endif /* Layer 1 State change */ hw->mr.r_irq_statech |= @@ -1292,9 +1213,7 @@ hfc4s8s_interrupt(int intno, void *dev_id) if (! (b = (Read_hfc8(hw, R_STATUS) & (M_MISC_IRQSTA | M_FR_IRQSTA))) && !hw->mr.r_irq_statech) { -#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(hw, old_ioreg); -#endif return IRQ_NONE; } @@ -1322,9 +1241,7 @@ hfc4s8s_interrupt(int intno, void *dev_id) /* queue the request to allow other cards to interrupt */ schedule_work(&hw->tqueue); -#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(hw, old_ioreg); -#endif return IRQ_HANDLED; } /* hfc4s8s_interrupt */ @@ -1471,13 +1388,8 @@ static void release_pci_ports(hfc4s8s_hw *hw) { pci_write_config_word(hw->pdev, PCI_COMMAND, 0); -#ifdef HISAX_HFC4S8S_PCIMEM - if (hw->membase) - iounmap((void *) hw->membase); -#else if (hw->iobase) release_region(hw->iobase, 8); -#endif } /*****************************************/ @@ -1486,11 +1398,7 @@ release_pci_ports(hfc4s8s_hw *hw) static void enable_pci_ports(hfc4s8s_hw *hw) { -#ifdef HISAX_HFC4S8S_PCIMEM - pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_MEMIO); -#else pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_REGIO); -#endif } /*************************************/ @@ -1561,15 +1469,9 @@ setup_instance(hfc4s8s_hw *hw) hw->irq); goto out; } -#ifdef HISAX_HFC4S8S_PCIMEM - printk(KERN_INFO - "HFC-4S/8S: found PCI card at membase 0x%p, irq %d\n", - hw->hw_membase, hw->irq); -#else printk(KERN_INFO "HFC-4S/8S: found PCI card at iobase 0x%x, irq %d\n", hw->iobase, hw->irq); -#endif hfc_hardware_enable(hw, 1, 0); @@ -1614,17 +1516,12 @@ hfc4s8s_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->irq = pdev->irq; hw->iobase = pci_resource_start(pdev, 0); -#ifdef HISAX_HFC4S8S_PCIMEM - hw->hw_membase = (u_char *) pci_resource_start(pdev, 1); - hw->membase = ioremap((ulong) hw->hw_membase, 256); -#else if (!request_region(hw->iobase, 8, hw->card_name)) { printk(KERN_INFO "HFC-4S/8S: failed to request address space at 0x%04x\n", hw->iobase); goto out; } -#endif pci_set_drvdata(pdev, hw); err = setup_instance(hw); diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 20626821b997ae..1e81d7a09a6457 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -297,16 +297,6 @@ config LEDS_PCA963X LED driver chip accessed via the I2C bus. Supported devices include PCA9633 and PCA9634 -config LEDS_PCA9685 - tristate "LED support for PCA9685 I2C chip" - depends on LEDS_CLASS - depends on I2C - help - This option enables support for LEDs connected to the PCA9685 - LED driver chip accessed via the I2C bus. - The PCA9685 offers 12-bit PWM (4095 levels of brightness) on - 16 individual channels. - config LEDS_WM831X_STATUS tristate "LED support for status LEDs on WM831x PMICs" depends on LEDS_CLASS @@ -476,6 +466,8 @@ config LEDS_OT200 This option enables support for the LEDs on the Bachmann OT200. Say Y to enable LEDs on the Bachmann OT200. +comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)" + config LEDS_BLINKM tristate "LED support for the BlinkM I2C RGB LED" depends on LEDS_CLASS @@ -484,6 +476,14 @@ config LEDS_BLINKM This option enables support for the BlinkM RGB LED connected through I2C. Say Y to enable support for the BlinkM LED. +config LEDS_VERSATILE + bool "LED support for the ARM Versatile and RealView" + depends on ARCH_REALVIEW || ARCH_VERSATILE + depends on LEDS_CLASS + help + This option enabled support for the LEDs on the ARM Versatile + and RealView boards. Say Y to enabled these. + comment "LED Triggers" source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 3cd76dbd9be2ff..79c5155199a7d4 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -36,7 +36,6 @@ obj-$(CONFIG_LEDS_OT200) += leds-ot200.o obj-$(CONFIG_LEDS_FSG) += leds-fsg.o obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o obj-$(CONFIG_LEDS_PCA963X) += leds-pca963x.o -obj-$(CONFIG_LEDS_PCA9685) += leds-pca9685.o obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o obj-$(CONFIG_LEDS_DA9052) += leds-da9052.o obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o @@ -54,6 +53,7 @@ obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o +obj-$(CONFIG_LEDS_VERSATILE) += leds-versatile.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/dell-led.c b/drivers/leds/dell-led.c index e5c57389efd636..c36acaf566a6e4 100644 --- a/drivers/leds/dell-led.c +++ b/drivers/leds/dell-led.c @@ -15,12 +15,15 @@ #include #include #include +#include +#include MODULE_AUTHOR("Louis Davis/Jim Dailey"); MODULE_DESCRIPTION("Dell LED Control Driver"); MODULE_LICENSE("GPL"); #define DELL_LED_BIOS_GUID "F6E4FE6E-909D-47cb-8BAB-C9F6F2F8D396" +#define DELL_APP_GUID "A80593CE-A997-11DA-B012-B622A1EF5492" MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID); /* Error Result Codes: */ @@ -39,6 +42,149 @@ MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID); #define CMD_LED_OFF 17 #define CMD_LED_BLINK 18 +struct app_wmi_args { + u16 class; + u16 selector; + u32 arg1; + u32 arg2; + u32 arg3; + u32 arg4; + u32 res1; + u32 res2; + u32 res3; + u32 res4; + char dummy[92]; +}; + +#define GLOBAL_MIC_MUTE_ENABLE 0x364 +#define GLOBAL_MIC_MUTE_DISABLE 0x365 + +struct dell_bios_data_token { + u16 tokenid; + u16 location; + u16 value; +}; + +struct __attribute__ ((__packed__)) dell_bios_calling_interface { + struct dmi_header header; + u16 cmd_io_addr; + u8 cmd_io_code; + u32 supported_cmds; + struct dell_bios_data_token damap[]; +}; + +static struct dell_bios_data_token dell_mic_tokens[2]; + +static int dell_wmi_perform_query(struct app_wmi_args *args) +{ + struct app_wmi_args *bios_return; + union acpi_object *obj; + struct acpi_buffer input; + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_status status; + u32 rc = -EINVAL; + + input.length = 128; + input.pointer = args; + + status = wmi_evaluate_method(DELL_APP_GUID, 0, 1, &input, &output); + if (!ACPI_SUCCESS(status)) + goto err_out0; + + obj = output.pointer; + if (!obj) + goto err_out0; + + if (obj->type != ACPI_TYPE_BUFFER) + goto err_out1; + + bios_return = (struct app_wmi_args *)obj->buffer.pointer; + rc = bios_return->res1; + if (rc) + goto err_out1; + + memcpy(args, bios_return, sizeof(struct app_wmi_args)); + rc = 0; + + err_out1: + kfree(obj); + err_out0: + return rc; +} + +static void __init find_micmute_tokens(const struct dmi_header *dm, void *dummy) +{ + struct dell_bios_calling_interface *calling_interface; + struct dell_bios_data_token *token; + int token_size = sizeof(struct dell_bios_data_token); + int i = 0; + + if (dm->type == 0xda && dm->length > 17) { + calling_interface = container_of(dm, + struct dell_bios_calling_interface, header); + + token = &calling_interface->damap[i]; + while (token->tokenid != 0xffff) { + if (token->tokenid == GLOBAL_MIC_MUTE_DISABLE) + memcpy(&dell_mic_tokens[0], token, token_size); + else if (token->tokenid == GLOBAL_MIC_MUTE_ENABLE) + memcpy(&dell_mic_tokens[1], token, token_size); + + i++; + token = &calling_interface->damap[i]; + } + } +} + +static int dell_micmute_led_set(int state) +{ + struct app_wmi_args args; + struct dell_bios_data_token *token; + + if (!wmi_has_guid(DELL_APP_GUID)) + return -ENODEV; + + if (state == 0 || state == 1) + token = &dell_mic_tokens[state]; + else + return -EINVAL; + + memset(&args, 0, sizeof(struct app_wmi_args)); + + args.class = 1; + args.arg1 = token->location; + args.arg2 = token->value; + + dell_wmi_perform_query(&args); + + return state; +} + +int dell_app_wmi_led_set(int whichled, int on) +{ + int state = 0; + + switch (whichled) { + case DELL_LED_MICMUTE: + state = dell_micmute_led_set(on); + break; + default: + pr_warn("led type %x is not supported\n", whichled); + break; + } + + return state; +} +EXPORT_SYMBOL_GPL(dell_app_wmi_led_set); + +static int __init dell_micmute_led_init(void) +{ + memset(dell_mic_tokens, 0, sizeof(struct dell_bios_data_token) * 2); + dmi_walk(find_micmute_tokens, NULL); + + return 0; +} + struct bios_args { unsigned char length; unsigned char result_code; @@ -181,21 +327,32 @@ static int __init dell_led_init(void) { int error = 0; - if (!wmi_has_guid(DELL_LED_BIOS_GUID)) + if (!wmi_has_guid(DELL_LED_BIOS_GUID) && !wmi_has_guid(DELL_APP_GUID)) return -ENODEV; - error = led_off(); - if (error != 0) - return -ENODEV; + if (wmi_has_guid(DELL_APP_GUID)) + error = dell_micmute_led_init(); - return led_classdev_register(NULL, &dell_led); + if (wmi_has_guid(DELL_LED_BIOS_GUID)) { + error = led_off(); + if (error != 0) + return -ENODEV; + + error = led_classdev_register(NULL, &dell_led); + } + + return error; } static void __exit dell_led_exit(void) { - led_classdev_unregister(&dell_led); + int error = 0; - led_off(); + if (wmi_has_guid(DELL_LED_BIOS_GUID)) { + error = led_off(); + if (error == 0) + led_classdev_unregister(&dell_led); + } } module_init(dell_led_init); diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index d1e1bca90d11e7..c2def5551ce1bd 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -130,10 +130,9 @@ static int pm860x_led_dt_init(struct platform_device *pdev, struct device_node *nproot, *np; int iset = 0; - nproot = of_node_get(pdev->dev.parent->of_node); - if (!nproot) + if (!pdev->dev.parent->of_node) return -ENODEV; - nproot = of_find_node_by_name(nproot, "leds"); + nproot = of_get_child_by_name(pdev->dev.parent->of_node, "leds"); if (!nproot) { dev_err(&pdev->dev, "failed to find leds node\n"); return -ENODEV; diff --git a/drivers/leds/leds-adp5520.c b/drivers/leds/leds-adp5520.c index 86b5bdb0c77303..5036d7b4f82e81 100644 --- a/drivers/leds/leds-adp5520.c +++ b/drivers/leds/leds-adp5520.c @@ -120,13 +120,10 @@ static int adp5520_led_probe(struct platform_device *pdev) led = devm_kzalloc(&pdev->dev, sizeof(*led) * pdata->num_leds, GFP_KERNEL); - if (led == NULL) { - dev_err(&pdev->dev, "failed to alloc memory\n"); + if (!led) return -ENOMEM; - } ret = adp5520_led_prepare(pdev); - if (ret) { dev_err(&pdev->dev, "failed to write\n"); return ret; diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c index fb5a3472d61444..6078c15d3452df 100644 --- a/drivers/leds/leds-bd2802.c +++ b/drivers/leds/leds-bd2802.c @@ -678,10 +678,8 @@ static int bd2802_probe(struct i2c_client *client, int ret, i; led = devm_kzalloc(&client->dev, sizeof(struct bd2802_led), GFP_KERNEL); - if (!led) { - dev_err(&client->dev, "failed to allocate driver data\n"); + if (!led) return -ENOMEM; - } led->client = client; pdata = led->pdata = dev_get_platdata(&client->dev); diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c index 35dffb100388c1..54b8b5216b8b62 100644 --- a/drivers/leds/leds-da903x.c +++ b/drivers/leds/leds-da903x.c @@ -108,10 +108,8 @@ static int da903x_led_probe(struct platform_device *pdev) } led = devm_kzalloc(&pdev->dev, sizeof(struct da903x_led), GFP_KERNEL); - if (led == NULL) { - dev_err(&pdev->dev, "failed to alloc memory for LED%d\n", id); + if (!led) return -ENOMEM; - } led->cdev.name = pdata->name; led->cdev.default_trigger = pdata->default_trigger; diff --git a/drivers/leds/leds-da9052.c b/drivers/leds/leds-da9052.c index 01486adc7f8ba9..e4da1f460ac58b 100644 --- a/drivers/leds/leds-da9052.c +++ b/drivers/leds/leds-da9052.c @@ -126,8 +126,7 @@ static int da9052_led_probe(struct platform_device *pdev) led = devm_kzalloc(&pdev->dev, sizeof(struct da9052_led) * pled->num_leds, GFP_KERNEL); - if (led == NULL) { - dev_err(&pdev->dev, "Failed to alloc memory\n"); + if (!led) { error = -ENOMEM; goto err; } diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index cb5ed82994baed..9e1716f8098ca2 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -1,5 +1,5 @@ /* - * lp5523.c - LP5523 LED Driver + * lp5523.c - LP5523, LP55231 LED Driver * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2012 Texas Instruments @@ -814,6 +814,7 @@ MODULE_DEVICE_TABLE(i2c, lp5523_id); #ifdef CONFIG_OF static const struct of_device_id of_lp5523_leds_match[] = { { .compatible = "national,lp5523", }, + { .compatible = "ti,lp55231", }, {}, }; diff --git a/drivers/leds/leds-pca9685.c b/drivers/leds/leds-pca9685.c deleted file mode 100644 index 6e1ef3a9d6ef02..00000000000000 --- a/drivers/leds/leds-pca9685.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright 2013 Maximilian Güntner - * - * This file is subject to the terms and conditions of version 2 of - * the GNU General Public License. See the file COPYING in the main - * directory of this archive for more details. - * - * Based on leds-pca963x.c driver by - * Peter Meerwald - * - * Driver for the NXP PCA9685 12-Bit PWM LED driver chip. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Register Addresses */ -#define PCA9685_MODE1 0x00 -#define PCA9685_MODE2 0x01 -#define PCA9685_LED0_ON_L 0x06 -#define PCA9685_ALL_LED_ON_L 0xFA - -/* MODE1 Register */ -#define PCA9685_ALLCALL 0x00 -#define PCA9685_SLEEP 0x04 -#define PCA9685_AI 0x05 - -/* MODE2 Register */ -#define PCA9685_INVRT 0x04 -#define PCA9685_OUTDRV 0x02 - -static const struct i2c_device_id pca9685_id[] = { - { "pca9685", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, pca9685_id); - -struct pca9685_led { - struct i2c_client *client; - struct work_struct work; - u16 brightness; - struct led_classdev led_cdev; - int led_num; /* 0-15 */ - char name[32]; -}; - -static void pca9685_write_msg(struct i2c_client *client, u8 *buf, u8 len) -{ - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0x00, - .len = len, - .buf = buf - }; - i2c_transfer(client->adapter, &msg, 1); -} - -static void pca9685_all_off(struct i2c_client *client) -{ - u8 i2c_buffer[5] = {PCA9685_ALL_LED_ON_L, 0x00, 0x00, 0x00, 0x10}; - pca9685_write_msg(client, i2c_buffer, 5); -} - -static void pca9685_led_work(struct work_struct *work) -{ - struct pca9685_led *pca9685; - u8 i2c_buffer[5]; - - pca9685 = container_of(work, struct pca9685_led, work); - i2c_buffer[0] = PCA9685_LED0_ON_L + 4 * pca9685->led_num; - /* - * 4095 is the maximum brightness, so we set the ON time to 0x1000 - * which disables the PWM generator for that LED - */ - if (pca9685->brightness == 4095) - *((__le16 *)(i2c_buffer+1)) = cpu_to_le16(0x1000); - else - *((__le16 *)(i2c_buffer+1)) = 0x0000; - - if (pca9685->brightness == 0) - *((__le16 *)(i2c_buffer+3)) = cpu_to_le16(0x1000); - else if (pca9685->brightness == 4095) - *((__le16 *)(i2c_buffer+3)) = 0x0000; - else - *((__le16 *)(i2c_buffer+3)) = cpu_to_le16(pca9685->brightness); - - pca9685_write_msg(pca9685->client, i2c_buffer, 5); -} - -static void pca9685_led_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - struct pca9685_led *pca9685; - pca9685 = container_of(led_cdev, struct pca9685_led, led_cdev); - pca9685->brightness = value; - - schedule_work(&pca9685->work); -} - -static int pca9685_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct pca9685_led *pca9685; - struct pca9685_platform_data *pdata; - int err; - u8 i; - - pdata = dev_get_platdata(&client->dev); - if (pdata) { - if (pdata->leds.num_leds < 1 || pdata->leds.num_leds > 15) { - dev_err(&client->dev, "board info must claim 1-16 LEDs"); - return -EINVAL; - } - } - - pca9685 = devm_kzalloc(&client->dev, 16 * sizeof(*pca9685), GFP_KERNEL); - if (!pca9685) - return -ENOMEM; - - i2c_set_clientdata(client, pca9685); - pca9685_all_off(client); - - for (i = 0; i < 16; i++) { - pca9685[i].client = client; - pca9685[i].led_num = i; - pca9685[i].name[0] = '\0'; - if (pdata && i < pdata->leds.num_leds) { - if (pdata->leds.leds[i].name) - strncpy(pca9685[i].name, - pdata->leds.leds[i].name, - sizeof(pca9685[i].name)-1); - if (pdata->leds.leds[i].default_trigger) - pca9685[i].led_cdev.default_trigger = - pdata->leds.leds[i].default_trigger; - } - if (strlen(pca9685[i].name) == 0) { - /* - * Write adapter and address to the name as well. - * Otherwise multiple chips attached to one host would - * not work. - */ - snprintf(pca9685[i].name, sizeof(pca9685[i].name), - "pca9685:%d:x%.2x:%d", - client->adapter->nr, client->addr, i); - } - pca9685[i].led_cdev.name = pca9685[i].name; - pca9685[i].led_cdev.max_brightness = 0xfff; - pca9685[i].led_cdev.brightness_set = pca9685_led_set; - - INIT_WORK(&pca9685[i].work, pca9685_led_work); - err = led_classdev_register(&client->dev, &pca9685[i].led_cdev); - if (err < 0) - goto exit; - } - - if (pdata) - i2c_smbus_write_byte_data(client, PCA9685_MODE2, - pdata->outdrv << PCA9685_OUTDRV | - pdata->inverted << PCA9685_INVRT); - else - i2c_smbus_write_byte_data(client, PCA9685_MODE2, - PCA9685_TOTEM_POLE << PCA9685_OUTDRV); - /* Enable Auto-Increment, enable oscillator, ALLCALL/SUBADDR disabled */ - i2c_smbus_write_byte_data(client, PCA9685_MODE1, BIT(PCA9685_AI)); - - return 0; - -exit: - while (i--) { - led_classdev_unregister(&pca9685[i].led_cdev); - cancel_work_sync(&pca9685[i].work); - } - return err; -} - -static int pca9685_remove(struct i2c_client *client) -{ - struct pca9685_led *pca9685 = i2c_get_clientdata(client); - u8 i; - - for (i = 0; i < 16; i++) { - led_classdev_unregister(&pca9685[i].led_cdev); - cancel_work_sync(&pca9685[i].work); - } - pca9685_all_off(client); - return 0; -} - -static struct i2c_driver pca9685_driver = { - .driver = { - .name = "leds-pca9685", - .owner = THIS_MODULE, - }, - .probe = pca9685_probe, - .remove = pca9685_remove, - .id_table = pca9685_id, -}; - -module_i2c_driver(pca9685_driver); - -MODULE_AUTHOR("Maximilian Güntner "); -MODULE_DESCRIPTION("PCA9685 LED Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index 7d0aaed1e23a88..f5cf1b0f274873 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -69,6 +69,10 @@ static void led_pwm_set(struct led_classdev *led_cdev, duty *= brightness; do_div(duty, max); + + if (led_dat->active_low) + duty = led_dat->period - duty; + led_dat->duty = duty; if (led_dat->can_sleep) @@ -92,55 +96,75 @@ static void led_pwm_cleanup(struct led_pwm_priv *priv) } } -static int led_pwm_create_of(struct platform_device *pdev, - struct led_pwm_priv *priv) +static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, + struct led_pwm *led, struct device_node *child) { - struct device_node *child; + struct led_pwm_data *led_data = &priv->leds[priv->num_leds]; int ret; - for_each_child_of_node(pdev->dev.of_node, child) { - struct led_pwm_data *led_dat = &priv->leds[priv->num_leds]; + led_data->active_low = led->active_low; + led_data->period = led->pwm_period_ns; + led_data->cdev.name = led->name; + led_data->cdev.default_trigger = led->default_trigger; + led_data->cdev.brightness_set = led_pwm_set; + led_data->cdev.brightness = LED_OFF; + led_data->cdev.max_brightness = led->max_brightness; + led_data->cdev.flags = LED_CORE_SUSPENDRESUME; + + if (child) + led_data->pwm = devm_of_pwm_get(dev, child, NULL); + else + led_data->pwm = devm_pwm_get(dev, led->name); + if (IS_ERR(led_data->pwm)) { + ret = PTR_ERR(led_data->pwm); + dev_err(dev, "unable to request PWM for %s: %d\n", + led->name, ret); + return ret; + } - led_dat->cdev.name = of_get_property(child, "label", - NULL) ? : child->name; + if (child) + led_data->period = pwm_get_period(led_data->pwm); - led_dat->pwm = devm_of_pwm_get(&pdev->dev, child, NULL); - if (IS_ERR(led_dat->pwm)) { - dev_err(&pdev->dev, "unable to request PWM for %s\n", - led_dat->cdev.name); - ret = PTR_ERR(led_dat->pwm); - goto err; - } - /* Get the period from PWM core when n*/ - led_dat->period = pwm_get_period(led_dat->pwm); + led_data->can_sleep = pwm_can_sleep(led_data->pwm); + if (led_data->can_sleep) + INIT_WORK(&led_data->work, led_pwm_work); - led_dat->cdev.default_trigger = of_get_property(child, - "linux,default-trigger", NULL); - of_property_read_u32(child, "max-brightness", - &led_dat->cdev.max_brightness); + ret = led_classdev_register(dev, &led_data->cdev); + if (ret == 0) { + priv->num_leds++; + } else { + dev_err(dev, "failed to register PWM led for %s: %d\n", + led->name, ret); + } - led_dat->cdev.brightness_set = led_pwm_set; - led_dat->cdev.brightness = LED_OFF; - led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; + return ret; +} - led_dat->can_sleep = pwm_can_sleep(led_dat->pwm); - if (led_dat->can_sleep) - INIT_WORK(&led_dat->work, led_pwm_work); +static int led_pwm_create_of(struct device *dev, struct led_pwm_priv *priv) +{ + struct device_node *child; + struct led_pwm led; + int ret = 0; - ret = led_classdev_register(&pdev->dev, &led_dat->cdev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register for %s\n", - led_dat->cdev.name); + memset(&led, 0, sizeof(led)); + + for_each_child_of_node(dev->of_node, child) { + led.name = of_get_property(child, "label", NULL) ? : + child->name; + + led.default_trigger = of_get_property(child, + "linux,default-trigger", NULL); + led.active_low = of_property_read_bool(child, "active-low"); + of_property_read_u32(child, "max-brightness", + &led.max_brightness); + + ret = led_pwm_add(dev, priv, &led, child); + if (ret) { of_node_put(child); - goto err; + break; } - priv->num_leds++; } - return 0; -err: - led_pwm_cleanup(priv); - return ret; } @@ -166,51 +190,23 @@ static int led_pwm_probe(struct platform_device *pdev) if (pdata) { for (i = 0; i < count; i++) { - struct led_pwm *cur_led = &pdata->leds[i]; - struct led_pwm_data *led_dat = &priv->leds[i]; - - led_dat->pwm = devm_pwm_get(&pdev->dev, cur_led->name); - if (IS_ERR(led_dat->pwm)) { - ret = PTR_ERR(led_dat->pwm); - dev_err(&pdev->dev, - "unable to request PWM for %s\n", - cur_led->name); - goto err; - } - - led_dat->cdev.name = cur_led->name; - led_dat->cdev.default_trigger = cur_led->default_trigger; - led_dat->active_low = cur_led->active_low; - led_dat->period = cur_led->pwm_period_ns; - led_dat->cdev.brightness_set = led_pwm_set; - led_dat->cdev.brightness = LED_OFF; - led_dat->cdev.max_brightness = cur_led->max_brightness; - led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; - - led_dat->can_sleep = pwm_can_sleep(led_dat->pwm); - if (led_dat->can_sleep) - INIT_WORK(&led_dat->work, led_pwm_work); - - ret = led_classdev_register(&pdev->dev, &led_dat->cdev); - if (ret < 0) - goto err; + ret = led_pwm_add(&pdev->dev, priv, &pdata->leds[i], + NULL); + if (ret) + break; } - priv->num_leds = count; } else { - ret = led_pwm_create_of(pdev, priv); - if (ret) - return ret; + ret = led_pwm_create_of(&pdev->dev, priv); + } + + if (ret) { + led_pwm_cleanup(priv); + return ret; } platform_set_drvdata(pdev, priv); return 0; - -err: - priv->num_leds = i; - led_pwm_cleanup(priv); - - return ret; } static int led_pwm_remove(struct platform_device *pdev) diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c index 28988b7b4faba3..785eb53a87fc11 100644 --- a/drivers/leds/leds-s3c24xx.c +++ b/drivers/leds/leds-s3c24xx.c @@ -76,10 +76,8 @@ static int s3c24xx_led_probe(struct platform_device *dev) led = devm_kzalloc(&dev->dev, sizeof(struct s3c24xx_gpio_led), GFP_KERNEL); - if (led == NULL) { - dev_err(&dev->dev, "No memory for device\n"); + if (!led) return -ENOMEM; - } platform_set_drvdata(dev, led); diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c index 388632d23d4471..0b8cc4a021a684 100644 --- a/drivers/leds/leds-sunfire.c +++ b/drivers/leds/leds-sunfire.c @@ -135,10 +135,8 @@ static int sunfire_led_generic_probe(struct platform_device *pdev, } p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); - if (!p) { - dev_err(&pdev->dev, "Could not allocate struct sunfire_drvdata\n"); + if (!p) return -ENOMEM; - } for (i = 0; i < NUM_LEDS_PER_BOARD; i++) { struct led_classdev *lp = &p->leds[i].led_cdev; diff --git a/arch/arm/plat-versatile/leds.c b/drivers/leds/leds-versatile.c similarity index 68% rename from arch/arm/plat-versatile/leds.c rename to drivers/leds/leds-versatile.c index d2490d00b46cd4..80553022d661fc 100644 --- a/arch/arm/plat-versatile/leds.c +++ b/drivers/leds/leds-versatile.c @@ -7,22 +7,14 @@ */ #include #include +#include #include #include #include - -#include -#include - -#ifdef VERSATILE_SYS_BASE -#define LEDREG (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET) -#endif - -#ifdef REALVIEW_SYS_BASE -#define LEDREG (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET) -#endif +#include struct versatile_led { + void __iomem *base; struct led_classdev cdev; u8 mask; }; @@ -50,30 +42,37 @@ static void versatile_led_set(struct led_classdev *cdev, { struct versatile_led *led = container_of(cdev, struct versatile_led, cdev); - u32 reg = readl(LEDREG); + u32 reg = readl(led->base); if (b != LED_OFF) reg |= led->mask; else reg &= ~led->mask; - writel(reg, LEDREG); + writel(reg, led->base); } static enum led_brightness versatile_led_get(struct led_classdev *cdev) { struct versatile_led *led = container_of(cdev, struct versatile_led, cdev); - u32 reg = readl(LEDREG); + u32 reg = readl(led->base); return (reg & led->mask) ? LED_FULL : LED_OFF; } -static int __init versatile_leds_init(void) +static int versatile_leds_probe(struct platform_device *dev) { int i; + struct resource *res; + void __iomem *base; - /* All ON */ - writel(0xff, LEDREG); + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&dev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + /* All off */ + writel(0, base); for (i = 0; i < ARRAY_SIZE(versatile_leds); i++) { struct versatile_led *led; @@ -81,6 +80,7 @@ static int __init versatile_leds_init(void) if (!led) break; + led->base = base; led->cdev.name = versatile_leds[i].name; led->cdev.brightness_set = versatile_led_set; led->cdev.brightness_get = versatile_led_get; @@ -96,8 +96,15 @@ static int __init versatile_leds_init(void) return 0; } -/* - * Since we may have triggers on any subsystem, defer registration - * until after subsystem_init. - */ -fs_initcall(versatile_leds_init); +static struct platform_driver versatile_leds_driver = { + .driver = { + .name = "versatile-leds", + }, + .probe = versatile_leds_probe, +}; + +module_platform_driver(versatile_leds_driver); + +MODULE_AUTHOR("Linus Walleij "); +MODULE_DESCRIPTION("ARM Versatile LED driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/trigger/ledtrig-cpu.c b/drivers/leds/trigger/ledtrig-cpu.c index 1c3ee9fcaf34c5..aec0f02b6b3ef2 100644 --- a/drivers/leds/trigger/ledtrig-cpu.c +++ b/drivers/leds/trigger/ledtrig-cpu.c @@ -47,7 +47,7 @@ static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig); */ void ledtrig_cpu(enum cpu_led_event ledevt) { - struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig); + struct led_trigger_cpu *trig = this_cpu_ptr(&cpu_trig); /* Locate the correct CPU LED */ switch (ledevt) { diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 82c9c5d35251f6..d2ebcf3230942a 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -828,7 +828,7 @@ static inline bool cached_dev_get(struct cached_dev *dc) return false; /* Paired with the mb in cached_dev_attach */ - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); return true; } diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h index 7ef7461912be25..a08e3eeac3c5fb 100644 --- a/drivers/md/bcache/closure.h +++ b/drivers/md/bcache/closure.h @@ -243,7 +243,7 @@ static inline void set_closure_fn(struct closure *cl, closure_fn *fn, cl->fn = fn; cl->wq = wq; /* between atomic_dec() in closure_put() */ - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); } static inline void closure_queue(struct closure *cl) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 66c5d130c8c24c..4e84095833dbce 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -607,9 +607,9 @@ static void write_endio(struct bio *bio, int error) BUG_ON(!test_bit(B_WRITING, &b->state)); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(B_WRITING, &b->state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&b->state, B_WRITING); } @@ -997,9 +997,9 @@ static void read_endio(struct bio *bio, int error) BUG_ON(!test_bit(B_READING, &b->state)); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(B_READING, &b->state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&b->state, B_READING); } diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index ebddef5237e4b2..8e0caed0bf7465 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -642,7 +642,7 @@ static void free_pending_exception(struct dm_snap_pending_exception *pe) struct dm_snapshot *s = pe->snap; mempool_free(pe, s->pending_pool); - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_dec(&s->pending_exceptions_count); } @@ -783,7 +783,7 @@ static int init_hash_tables(struct dm_snapshot *s) static void merge_shutdown(struct dm_snapshot *s) { clear_bit_unlock(RUNNING_MERGE, &s->state_bits); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&s->state_bits, RUNNING_MERGE); } diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 13abade76ad9bb..15f748ba6754f5 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -935,7 +935,7 @@ static int commit(struct pool *pool) { int r; - if (get_pool_mode(pool) != PM_WRITE) + if (get_pool_mode(pool) >= PM_READ_ONLY) return -EINVAL; r = dm_pool_commit_metadata(pool->pmd); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 455e6491649889..aa9e093343d435 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1544,7 +1544,6 @@ static int setup_clone(struct request *clone, struct request *rq, clone->cmd = rq->cmd; clone->cmd_len = rq->cmd_len; clone->sense = rq->sense; - clone->buffer = rq->buffer; clone->end_io = end_clone_request; clone->end_io_data = tio; @@ -2447,7 +2446,7 @@ static void dm_wq_work(struct work_struct *work) static void dm_queue_flush(struct mapped_device *md) { clear_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); queue_work(md->wq, &md->work); } diff --git a/drivers/md/md.c b/drivers/md/md.c index 8fda38d23e3847..f477e4ca0f786e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3448,6 +3448,8 @@ level_store(struct mddev *mddev, const char *buf, size_t len) mddev->level = LEVEL_NONE; return rv; } + if (mddev->ro) + return -EROFS; /* request to change the personality. Need to ensure: * - array is not engaged in resync/recovery/reshape @@ -3634,6 +3636,8 @@ layout_store(struct mddev *mddev, const char *buf, size_t len) int err; if (mddev->pers->check_reshape == NULL) return -EBUSY; + if (mddev->ro) + return -EROFS; mddev->new_layout = n; err = mddev->pers->check_reshape(mddev); if (err) { @@ -3723,6 +3727,8 @@ chunk_size_store(struct mddev *mddev, const char *buf, size_t len) int err; if (mddev->pers->check_reshape == NULL) return -EBUSY; + if (mddev->ro) + return -EROFS; mddev->new_chunk_sectors = n >> 9; err = mddev->pers->check_reshape(mddev); if (err) { @@ -6135,6 +6141,8 @@ static int update_size(struct mddev *mddev, sector_t num_sectors) */ if (mddev->sync_thread) return -EBUSY; + if (mddev->ro) + return -EROFS; rdev_for_each(rdev, mddev) { sector_t avail = rdev->sectors; @@ -6157,6 +6165,8 @@ static int update_raid_disks(struct mddev *mddev, int raid_disks) /* change the number of raid disks */ if (mddev->pers->check_reshape == NULL) return -EINVAL; + if (mddev->ro) + return -EROFS; if (raid_disks <= 0 || (mddev->max_disks && raid_disks >= mddev->max_disks)) return -EINVAL; @@ -8516,7 +8526,8 @@ static int md_notify_reboot(struct notifier_block *this, if (mddev_trylock(mddev)) { if (mddev->pers) __md_stop_writes(mddev); - mddev->safemode = 2; + if (mddev->persistent) + mddev->safemode = 2; mddev_unlock(mddev); } need_delay = 1; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 33fc408e5eacef..cb882aae9e20d4 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1172,6 +1172,13 @@ static void __make_request(struct mddev *mddev, struct bio *bio) int max_sectors; int sectors; + /* + * Register the new request and wait if the reconstruction + * thread has put up a bar for new requests. + * Continue immediately if no resync is active currently. + */ + wait_barrier(conf); + sectors = bio_sectors(bio); while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && bio->bi_iter.bi_sector < conf->reshape_progress && @@ -1552,12 +1559,6 @@ static void make_request(struct mddev *mddev, struct bio *bio) md_write_start(mddev, bio); - /* - * Register the new request and wait if the reconstruction - * thread has put up a bar for new requests. - * Continue immediately if no resync is active currently. - */ - wait_barrier(conf); do { diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index ad1b9bea446ebd..3c0007ef85edad 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -479,6 +479,7 @@ static void shrink_buffers(struct stripe_head *sh) int num = sh->raid_conf->pool_size; for (i = 0; i < num ; i++) { + WARN_ON(sh->dev[i].page != sh->dev[i].orig_page); p = sh->dev[i].page; if (!p) continue; @@ -499,6 +500,7 @@ static int grow_buffers(struct stripe_head *sh) return 1; } sh->dev[i].page = page; + sh->dev[i].orig_page = page; } return 0; } @@ -855,6 +857,9 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) bi->bi_rw |= REQ_NOMERGE; + if (test_bit(R5_SkipCopy, &sh->dev[i].flags)) + WARN_ON(test_bit(R5_UPTODATE, &sh->dev[i].flags)); + sh->dev[i].vec.bv_page = sh->dev[i].page; bi->bi_vcnt = 1; bi->bi_io_vec[0].bv_len = STRIPE_SIZE; bi->bi_io_vec[0].bv_offset = 0; @@ -899,6 +904,9 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) else rbi->bi_iter.bi_sector = (sh->sector + rrdev->data_offset); + if (test_bit(R5_SkipCopy, &sh->dev[i].flags)) + WARN_ON(test_bit(R5_UPTODATE, &sh->dev[i].flags)); + sh->dev[i].rvec.bv_page = sh->dev[i].page; rbi->bi_vcnt = 1; rbi->bi_io_vec[0].bv_len = STRIPE_SIZE; rbi->bi_io_vec[0].bv_offset = 0; @@ -927,8 +935,9 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) } static struct dma_async_tx_descriptor * -async_copy_data(int frombio, struct bio *bio, struct page *page, - sector_t sector, struct dma_async_tx_descriptor *tx) +async_copy_data(int frombio, struct bio *bio, struct page **page, + sector_t sector, struct dma_async_tx_descriptor *tx, + struct stripe_head *sh) { struct bio_vec bvl; struct bvec_iter iter; @@ -965,11 +974,16 @@ async_copy_data(int frombio, struct bio *bio, struct page *page, if (clen > 0) { b_offset += bvl.bv_offset; bio_page = bvl.bv_page; - if (frombio) - tx = async_memcpy(page, bio_page, page_offset, + if (frombio) { + if (sh->raid_conf->skip_copy && + b_offset == 0 && page_offset == 0 && + clen == STRIPE_SIZE) + *page = bio_page; + else + tx = async_memcpy(*page, bio_page, page_offset, b_offset, clen, &submit); - else - tx = async_memcpy(bio_page, page, b_offset, + } else + tx = async_memcpy(bio_page, *page, b_offset, page_offset, clen, &submit); } /* chain the operations */ @@ -1045,8 +1059,8 @@ static void ops_run_biofill(struct stripe_head *sh) spin_unlock_irq(&sh->stripe_lock); while (rbi && rbi->bi_iter.bi_sector < dev->sector + STRIPE_SECTORS) { - tx = async_copy_data(0, rbi, dev->page, - dev->sector, tx); + tx = async_copy_data(0, rbi, &dev->page, + dev->sector, tx, sh); rbi = r5_next_bio(rbi, dev->sector); } } @@ -1384,6 +1398,7 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx) BUG_ON(dev->written); wbi = dev->written = chosen; spin_unlock_irq(&sh->stripe_lock); + WARN_ON(dev->page != dev->orig_page); while (wbi && wbi->bi_iter.bi_sector < dev->sector + STRIPE_SECTORS) { @@ -1393,9 +1408,15 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx) set_bit(R5_SyncIO, &dev->flags); if (wbi->bi_rw & REQ_DISCARD) set_bit(R5_Discard, &dev->flags); - else - tx = async_copy_data(1, wbi, dev->page, - dev->sector, tx); + else { + tx = async_copy_data(1, wbi, &dev->page, + dev->sector, tx, sh); + if (dev->page != dev->orig_page) { + set_bit(R5_SkipCopy, &dev->flags); + clear_bit(R5_UPTODATE, &dev->flags); + clear_bit(R5_OVERWRITE, &dev->flags); + } + } wbi = r5_next_bio(wbi, dev->sector); } } @@ -1426,7 +1447,7 @@ static void ops_complete_reconstruct(void *stripe_head_ref) struct r5dev *dev = &sh->dev[i]; if (dev->written || i == pd_idx || i == qd_idx) { - if (!discard) + if (!discard && !test_bit(R5_SkipCopy, &dev->flags)) set_bit(R5_UPTODATE, &dev->flags); if (fua) set_bit(R5_WantFUA, &dev->flags); @@ -2133,24 +2154,20 @@ static void raid5_end_write_request(struct bio *bi, int error) } static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous); - + static void raid5_build_block(struct stripe_head *sh, int i, int previous) { struct r5dev *dev = &sh->dev[i]; bio_init(&dev->req); dev->req.bi_io_vec = &dev->vec; - dev->req.bi_vcnt++; - dev->req.bi_max_vecs++; + dev->req.bi_max_vecs = 1; dev->req.bi_private = sh; - dev->vec.bv_page = dev->page; bio_init(&dev->rreq); dev->rreq.bi_io_vec = &dev->rvec; - dev->rreq.bi_vcnt++; - dev->rreq.bi_max_vecs++; + dev->rreq.bi_max_vecs = 1; dev->rreq.bi_private = sh; - dev->rvec.bv_page = dev->page; dev->flags = 0; dev->sector = compute_blocknr(sh, i, previous); @@ -2750,6 +2767,11 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, /* and fail all 'written' */ bi = sh->dev[i].written; sh->dev[i].written = NULL; + if (test_and_clear_bit(R5_SkipCopy, &sh->dev[i].flags)) { + WARN_ON(test_bit(R5_UPTODATE, &sh->dev[i].flags)); + sh->dev[i].page = sh->dev[i].orig_page; + } + if (bi) bitmap_end = 1; while (bi && bi->bi_iter.bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { @@ -2991,12 +3013,17 @@ static void handle_stripe_clean_event(struct r5conf *conf, dev = &sh->dev[i]; if (!test_bit(R5_LOCKED, &dev->flags) && (test_bit(R5_UPTODATE, &dev->flags) || - test_bit(R5_Discard, &dev->flags))) { + test_bit(R5_Discard, &dev->flags) || + test_bit(R5_SkipCopy, &dev->flags))) { /* We can return any write requests */ struct bio *wbi, *wbi2; pr_debug("Return write for disc %d\n", i); if (test_and_clear_bit(R5_Discard, &dev->flags)) clear_bit(R5_UPTODATE, &dev->flags); + if (test_and_clear_bit(R5_SkipCopy, &dev->flags)) { + WARN_ON(test_bit(R5_UPTODATE, &dev->flags)); + dev->page = dev->orig_page; + } wbi = dev->written; dev->written = NULL; while (wbi && wbi->bi_iter.bi_sector < @@ -3015,6 +3042,8 @@ static void handle_stripe_clean_event(struct r5conf *conf, 0); } else if (test_bit(R5_Discard, &dev->flags)) discard_pending = 1; + WARN_ON(test_bit(R5_SkipCopy, &dev->flags)); + WARN_ON(dev->page != dev->orig_page); } if (!discard_pending && test_bit(R5_Discard, &sh->dev[sh->pd_idx].flags)) { @@ -4400,7 +4429,7 @@ static void raid5_unplug(struct blk_plug_cb *blk_cb, bool from_schedule) * STRIPE_ON_UNPLUG_LIST clear but the stripe * is still in our list */ - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(STRIPE_ON_UNPLUG_LIST, &sh->state); /* * STRIPE_ON_RELEASE_LIST could be set here. In that @@ -5354,6 +5383,50 @@ raid5_preread_bypass_threshold = __ATTR(preread_bypass_threshold, raid5_show_preread_threshold, raid5_store_preread_threshold); +static ssize_t +raid5_show_skip_copy(struct mddev *mddev, char *page) +{ + struct r5conf *conf = mddev->private; + if (conf) + return sprintf(page, "%d\n", conf->skip_copy); + else + return 0; +} + +static ssize_t +raid5_store_skip_copy(struct mddev *mddev, const char *page, size_t len) +{ + struct r5conf *conf = mddev->private; + unsigned long new; + if (len >= PAGE_SIZE) + return -EINVAL; + if (!conf) + return -ENODEV; + + if (kstrtoul(page, 10, &new)) + return -EINVAL; + new = !!new; + if (new == conf->skip_copy) + return len; + + mddev_suspend(mddev); + conf->skip_copy = new; + if (new) + mddev->queue->backing_dev_info.capabilities |= + BDI_CAP_STABLE_WRITES; + else + mddev->queue->backing_dev_info.capabilities &= + ~BDI_CAP_STABLE_WRITES; + mddev_resume(mddev); + return len; +} + +static struct md_sysfs_entry +raid5_skip_copy = __ATTR(skip_copy, S_IRUGO | S_IWUSR, + raid5_show_skip_copy, + raid5_store_skip_copy); + + static ssize_t stripe_cache_active_show(struct mddev *mddev, char *page) { @@ -5439,6 +5512,7 @@ static struct attribute *raid5_attrs[] = { &raid5_stripecache_active.attr, &raid5_preread_bypass_threshold.attr, &raid5_group_thread_cnt.attr, + &raid5_skip_copy.attr, NULL, }; static struct attribute_group raid5_attrs_group = { diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 01ad8ae8f57830..bc72cd4be5f8e1 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -232,7 +232,7 @@ struct stripe_head { */ struct bio req, rreq; struct bio_vec vec, rvec; - struct page *page; + struct page *page, *orig_page; struct bio *toread, *read, *towrite, *written; sector_t sector; /* sector of this page */ unsigned long flags; @@ -299,6 +299,7 @@ enum r5dev_flags { * data in, and now is a good time to write it out. */ R5_Discard, /* Discard the stripe */ + R5_SkipCopy, /* Don't copy data from bio to stripe cache */ }; /* @@ -436,6 +437,7 @@ struct r5conf { atomic_t pending_full_writes; /* full write backlog */ int bypass_count; /* bypassed prereads */ int bypass_threshold; /* preread nice */ + int skip_copy; /* Don't copy data from bio to stripe cache */ struct list_head *last_hold; /* detect hold_list promotions */ atomic_t reshape_stripes; /* stripes with pending writes for reshape */ diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index a4459301b5f829..ee0f57e01b5677 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1616,7 +1616,7 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state) if (ret < 0) return -EINVAL; - node_ep = v4l2_of_get_next_endpoint(node, NULL); + node_ep = of_graph_get_next_endpoint(node, NULL); if (!node_ep) { dev_warn(dev, "no endpoint defined for node: %s\n", node->full_name); diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index b4f12d00be059c..65670825296209 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -372,18 +372,32 @@ static int vpbe_stop_streaming(struct vb2_queue *vq) { struct vpbe_fh *fh = vb2_get_drv_priv(vq); struct vpbe_layer *layer = fh->layer; + struct vpbe_display *disp = fh->disp_dev; + unsigned long flags; if (!vb2_is_streaming(vq)) return 0; /* release all active buffers */ + spin_lock_irqsave(&disp->dma_queue_lock, flags); + if (layer->cur_frm == layer->next_frm) { + vb2_buffer_done(&layer->cur_frm->vb, VB2_BUF_STATE_ERROR); + } else { + if (layer->cur_frm != NULL) + vb2_buffer_done(&layer->cur_frm->vb, + VB2_BUF_STATE_ERROR); + if (layer->next_frm != NULL) + vb2_buffer_done(&layer->next_frm->vb, + VB2_BUF_STATE_ERROR); + } + while (!list_empty(&layer->dma_queue)) { layer->next_frm = list_entry(layer->dma_queue.next, struct vpbe_disp_buffer, list); list_del(&layer->next_frm->list); vb2_buffer_done(&layer->next_frm->vb, VB2_BUF_STATE_ERROR); } - + spin_unlock_irqrestore(&disp->dma_queue_lock, flags); return 0; } diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index d762246eabf5a3..0379cb9f9a9c25 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -734,6 +734,8 @@ static int vpfe_release(struct file *file) } vpfe_dev->io_usrs = 0; vpfe_dev->numbuffers = config_params.numbuffers; + videobuf_stop(&vpfe_dev->buffer_queue); + videobuf_mmap_free(&vpfe_dev->buffer_queue); } /* Decrement device usrs counter */ diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 756da78bac2310..8dea0b84a3ad66 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -358,8 +358,31 @@ static int vpif_stop_streaming(struct vb2_queue *vq) common = &ch->common[VPIF_VIDEO_INDEX]; + /* Disable channel as per its device type and channel id */ + if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { + enable_channel0(0); + channel0_intr_enable(0); + } + if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || + (2 == common->started)) { + enable_channel1(0); + channel1_intr_enable(0); + } + common->started = 0; + /* release all active buffers */ spin_lock_irqsave(&common->irqlock, flags); + if (common->cur_frm == common->next_frm) { + vb2_buffer_done(&common->cur_frm->vb, VB2_BUF_STATE_ERROR); + } else { + if (common->cur_frm != NULL) + vb2_buffer_done(&common->cur_frm->vb, + VB2_BUF_STATE_ERROR); + if (common->next_frm != NULL) + vb2_buffer_done(&common->next_frm->vb, + VB2_BUF_STATE_ERROR); + } + while (!list_empty(&common->dma_queue)) { common->next_frm = list_entry(common->dma_queue.next, struct vpif_cap_buffer, list); @@ -933,17 +956,6 @@ static int vpif_release(struct file *filep) if (fh->io_allowed[VPIF_VIDEO_INDEX]) { /* Reset io_usrs member of channel object */ common->io_usrs = 0; - /* Disable channel as per its device type and channel id */ - if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { - enable_channel0(0); - channel0_intr_enable(0); - } - if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || - (2 == common->started)) { - enable_channel1(0); - channel1_intr_enable(0); - } - common->started = 0; /* Free buffers allocated */ vb2_queue_release(&common->buffer_queue); vb2_dma_contig_cleanup_ctx(common->alloc_ctx); diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 0ac841e35aa48d..aed41edd050102 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -320,8 +320,31 @@ static int vpif_stop_streaming(struct vb2_queue *vq) common = &ch->common[VPIF_VIDEO_INDEX]; + /* Disable channel */ + if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { + enable_channel2(0); + channel2_intr_enable(0); + } + if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || + (2 == common->started)) { + enable_channel3(0); + channel3_intr_enable(0); + } + common->started = 0; + /* release all active buffers */ spin_lock_irqsave(&common->irqlock, flags); + if (common->cur_frm == common->next_frm) { + vb2_buffer_done(&common->cur_frm->vb, VB2_BUF_STATE_ERROR); + } else { + if (common->cur_frm != NULL) + vb2_buffer_done(&common->cur_frm->vb, + VB2_BUF_STATE_ERROR); + if (common->next_frm != NULL) + vb2_buffer_done(&common->next_frm->vb, + VB2_BUF_STATE_ERROR); + } + while (!list_empty(&common->dma_queue)) { common->next_frm = list_entry(common->dma_queue.next, struct vpif_disp_buffer, list); @@ -773,18 +796,6 @@ static int vpif_release(struct file *filep) if (fh->io_allowed[VPIF_VIDEO_INDEX]) { /* Reset io_usrs member of channel object */ common->io_usrs = 0; - /* Disable channel */ - if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { - enable_channel2(0); - channel2_intr_enable(0); - } - if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || - (2 == common->started)) { - enable_channel3(0); - channel3_intr_enable(0); - } - common->started = 0; - /* Free buffers allocated */ vb2_queue_release(&common->buffer_queue); vb2_dma_contig_cleanup_ctx(common->alloc_ctx); diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index da2fc86cc52433..25dbf5b05a9618 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -122,7 +122,7 @@ static struct fimc_fmt fimc_formats[] = { }, { .name = "YUV 4:2:2 planar, Y/Cb/Cr", .fourcc = V4L2_PIX_FMT_YUV422P, - .depth = { 12 }, + .depth = { 16 }, .color = FIMC_FMT_YCBYCR422, .memplanes = 1, .colplanes = 3, diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile index 7407b8338ccfa3..bc38f03394cda0 100644 --- a/drivers/media/usb/dvb-usb-v2/Makefile +++ b/drivers/media/usb/dvb-usb-v2/Makefile @@ -41,4 +41,3 @@ ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends ccflags-y += -I$(srctree)/drivers/media/tuners ccflags-y += -I$(srctree)/drivers/media/common -ccflags-y += -I$(srctree)/drivers/staging/media/rtl2832u_sdr diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index de02db802acea6..e35580618936cd 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -399,7 +399,7 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) /* clear 'streaming' status bit */ clear_bit(ADAP_STREAMING, &adap->state_bits); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&adap->state_bits, ADAP_STREAMING); skip_feed_stop: @@ -550,7 +550,7 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe) err: if (!adap->suspend_resume_active) { clear_bit(ADAP_INIT, &adap->state_bits); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&adap->state_bits, ADAP_INIT); } @@ -591,7 +591,7 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) if (!adap->suspend_resume_active) { adap->active_fe = -1; clear_bit(ADAP_SLEEP, &adap->state_bits); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&adap->state_bits, ADAP_SLEEP); } diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 61d196e8b3abde..dcbd392e6efc8f 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -24,7 +24,6 @@ #include "rtl2830.h" #include "rtl2832.h" -#include "rtl2832_sdr.h" #include "qt1010.h" #include "mt2060.h" @@ -36,6 +35,45 @@ #include "tua9001.h" #include "r820t.h" +/* + * RTL2832_SDR module is in staging. That logic is added in order to avoid any + * hard dependency to drivers/staging/ directory as we want compile mainline + * driver even whole staging directory is missing. + */ +#include + +#if IS_ENABLED(CONFIG_DVB_RTL2832_SDR) +struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, const struct rtl2832_config *cfg, + struct v4l2_subdev *sd); +#else +static inline struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, const struct rtl2832_config *cfg, + struct v4l2_subdev *sd) +{ + return NULL; +} +#endif + +#ifdef CONFIG_MEDIA_ATTACH +#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \ + void *__r = NULL; \ + typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ + if (__a) { \ + __r = (void *) __a(ARGS); \ + if (__r == NULL) \ + symbol_put(FUNCTION); \ + } \ + __r; \ +}) + +#else +#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \ + FUNCTION(ARGS); \ +}) + +#endif + static int rtl28xxu_disable_rc; module_param_named(disable_rc, rtl28xxu_disable_rc, int, 0644); MODULE_PARM_DESC(disable_rc, "disable RTL2832U remote controller"); @@ -908,7 +946,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) adap->fe[0]->ops.tuner_ops.get_rf_strength; /* attach SDR */ - dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, + dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, &rtl28xxu_rtl2832_fc0012_config, NULL); break; case TUNER_RTL2832_FC0013: @@ -920,7 +958,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) adap->fe[0]->ops.tuner_ops.get_rf_strength; /* attach SDR */ - dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, + dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, &rtl28xxu_rtl2832_fc0013_config, NULL); break; case TUNER_RTL2832_E4000: { @@ -951,7 +989,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) i2c_set_adapdata(i2c_adap_internal, d); /* attach SDR */ - dvb_attach(rtl2832_sdr_attach, adap->fe[0], + dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], i2c_adap_internal, &rtl28xxu_rtl2832_e4000_config, sd); } @@ -982,7 +1020,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) adap->fe[0]->ops.tuner_ops.get_rf_strength; /* attach SDR */ - dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, + dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, &rtl28xxu_rtl2832_r820t_config, NULL); break; case TUNER_RTL2832_R828D: diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c index 7277dbd2afcdb8..ecbcb39feb71ad 100644 --- a/drivers/media/usb/gspca/sonixb.c +++ b/drivers/media/usb/gspca/sonixb.c @@ -1430,10 +1430,8 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)}, {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)}, {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)}, -#if !IS_ENABLED(CONFIG_USB_SN9C102) {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)}, {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)}, -#endif {USB_DEVICE(0x0c45, 0x6027), SB(OV7630, 101)}, /* Genius Eye 310 */ {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)}, {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)}, diff --git a/drivers/memory/mvebu-devbus.c b/drivers/memory/mvebu-devbus.c index 110c03627051cb..ff7138fd66d143 100644 --- a/drivers/memory/mvebu-devbus.c +++ b/drivers/memory/mvebu-devbus.c @@ -2,7 +2,7 @@ * Marvell EBU SoC Device Bus Controller * (memory controller for NOR/NAND/SRAM/FPGA devices) * - * Copyright (C) 2013 Marvell + * Copyright (C) 2013-2014 Marvell * * 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 @@ -30,19 +30,47 @@ #include /* Register definitions */ -#define DEV_WIDTH_BIT 30 -#define BADR_SKEW_BIT 28 -#define RD_HOLD_BIT 23 -#define ACC_NEXT_BIT 17 -#define RD_SETUP_BIT 12 -#define ACC_FIRST_BIT 6 - -#define SYNC_ENABLE_BIT 24 -#define WR_HIGH_BIT 16 -#define WR_LOW_BIT 8 - -#define READ_PARAM_OFFSET 0x0 -#define WRITE_PARAM_OFFSET 0x4 +#define ARMADA_DEV_WIDTH_SHIFT 30 +#define ARMADA_BADR_SKEW_SHIFT 28 +#define ARMADA_RD_HOLD_SHIFT 23 +#define ARMADA_ACC_NEXT_SHIFT 17 +#define ARMADA_RD_SETUP_SHIFT 12 +#define ARMADA_ACC_FIRST_SHIFT 6 + +#define ARMADA_SYNC_ENABLE_SHIFT 24 +#define ARMADA_WR_HIGH_SHIFT 16 +#define ARMADA_WR_LOW_SHIFT 8 + +#define ARMADA_READ_PARAM_OFFSET 0x0 +#define ARMADA_WRITE_PARAM_OFFSET 0x4 + +#define ORION_RESERVED (0x2 << 30) +#define ORION_BADR_SKEW_SHIFT 28 +#define ORION_WR_HIGH_EXT_BIT BIT(27) +#define ORION_WR_HIGH_EXT_MASK 0x8 +#define ORION_WR_LOW_EXT_BIT BIT(26) +#define ORION_WR_LOW_EXT_MASK 0x8 +#define ORION_ALE_WR_EXT_BIT BIT(25) +#define ORION_ALE_WR_EXT_MASK 0x8 +#define ORION_ACC_NEXT_EXT_BIT BIT(24) +#define ORION_ACC_NEXT_EXT_MASK 0x10 +#define ORION_ACC_FIRST_EXT_BIT BIT(23) +#define ORION_ACC_FIRST_EXT_MASK 0x10 +#define ORION_TURN_OFF_EXT_BIT BIT(22) +#define ORION_TURN_OFF_EXT_MASK 0x8 +#define ORION_DEV_WIDTH_SHIFT 20 +#define ORION_WR_HIGH_SHIFT 17 +#define ORION_WR_HIGH_MASK 0x7 +#define ORION_WR_LOW_SHIFT 14 +#define ORION_WR_LOW_MASK 0x7 +#define ORION_ALE_WR_SHIFT 11 +#define ORION_ALE_WR_MASK 0x7 +#define ORION_ACC_NEXT_SHIFT 7 +#define ORION_ACC_NEXT_MASK 0xF +#define ORION_ACC_FIRST_SHIFT 3 +#define ORION_ACC_FIRST_MASK 0xF +#define ORION_TURN_OFF_SHIFT 0 +#define ORION_TURN_OFF_MASK 0x7 struct devbus_read_params { u32 bus_width; @@ -89,117 +117,167 @@ static int get_timing_param_ps(struct devbus *devbus, return 0; } -static int devbus_set_timing_params(struct devbus *devbus, - struct device_node *node) +static int devbus_get_timing_params(struct devbus *devbus, + struct device_node *node, + struct devbus_read_params *r, + struct devbus_write_params *w) { - struct devbus_read_params r; - struct devbus_write_params w; - u32 value; int err; - dev_dbg(devbus->dev, "Setting timing parameter, tick is %lu ps\n", - devbus->tick_ps); - - /* Get read timings */ - err = of_property_read_u32(node, "devbus,bus-width", &r.bus_width); + err = of_property_read_u32(node, "devbus,bus-width", &r->bus_width); if (err < 0) { dev_err(devbus->dev, "%s has no 'devbus,bus-width' property\n", node->full_name); return err; } - /* Convert bit width to byte width */ - r.bus_width /= 8; + + /* + * The bus width is encoded into the register as 0 for 8 bits, + * and 1 for 16 bits, so we do the necessary conversion here. + */ + if (r->bus_width == 8) + r->bus_width = 0; + else if (r->bus_width == 16) + r->bus_width = 1; + else { + dev_err(devbus->dev, "invalid bus width %d\n", r->bus_width); + return -EINVAL; + } err = get_timing_param_ps(devbus, node, "devbus,badr-skew-ps", - &r.badr_skew); + &r->badr_skew); if (err < 0) return err; err = get_timing_param_ps(devbus, node, "devbus,turn-off-ps", - &r.turn_off); + &r->turn_off); if (err < 0) return err; err = get_timing_param_ps(devbus, node, "devbus,acc-first-ps", - &r.acc_first); + &r->acc_first); if (err < 0) return err; err = get_timing_param_ps(devbus, node, "devbus,acc-next-ps", - &r.acc_next); + &r->acc_next); if (err < 0) return err; - err = get_timing_param_ps(devbus, node, "devbus,rd-setup-ps", - &r.rd_setup); - if (err < 0) - return err; - - err = get_timing_param_ps(devbus, node, "devbus,rd-hold-ps", - &r.rd_hold); - if (err < 0) - return err; - - /* Get write timings */ - err = of_property_read_u32(node, "devbus,sync-enable", - &w.sync_enable); - if (err < 0) { - dev_err(devbus->dev, - "%s has no 'devbus,sync-enable' property\n", - node->full_name); - return err; + if (of_device_is_compatible(devbus->dev->of_node, "marvell,mvebu-devbus")) { + err = get_timing_param_ps(devbus, node, "devbus,rd-setup-ps", + &r->rd_setup); + if (err < 0) + return err; + + err = get_timing_param_ps(devbus, node, "devbus,rd-hold-ps", + &r->rd_hold); + if (err < 0) + return err; + + err = of_property_read_u32(node, "devbus,sync-enable", + &w->sync_enable); + if (err < 0) { + dev_err(devbus->dev, + "%s has no 'devbus,sync-enable' property\n", + node->full_name); + return err; + } } err = get_timing_param_ps(devbus, node, "devbus,ale-wr-ps", - &w.ale_wr); + &w->ale_wr); if (err < 0) return err; err = get_timing_param_ps(devbus, node, "devbus,wr-low-ps", - &w.wr_low); + &w->wr_low); if (err < 0) return err; err = get_timing_param_ps(devbus, node, "devbus,wr-high-ps", - &w.wr_high); + &w->wr_high); if (err < 0) return err; + return 0; +} + +static void devbus_orion_set_timing_params(struct devbus *devbus, + struct device_node *node, + struct devbus_read_params *r, + struct devbus_write_params *w) +{ + u32 value; + + /* + * The hardware designers found it would be a good idea to + * split most of the values in the register into two fields: + * one containing all the low-order bits, and another one + * containing just the high-order bit. For all of those + * fields, we have to split the value into these two parts. + */ + value = (r->turn_off & ORION_TURN_OFF_MASK) << ORION_TURN_OFF_SHIFT | + (r->acc_first & ORION_ACC_FIRST_MASK) << ORION_ACC_FIRST_SHIFT | + (r->acc_next & ORION_ACC_NEXT_MASK) << ORION_ACC_NEXT_SHIFT | + (w->ale_wr & ORION_ALE_WR_MASK) << ORION_ALE_WR_SHIFT | + (w->wr_low & ORION_WR_LOW_MASK) << ORION_WR_LOW_SHIFT | + (w->wr_high & ORION_WR_HIGH_MASK) << ORION_WR_HIGH_SHIFT | + r->bus_width << ORION_DEV_WIDTH_SHIFT | + ((r->turn_off & ORION_TURN_OFF_EXT_MASK) ? ORION_TURN_OFF_EXT_BIT : 0) | + ((r->acc_first & ORION_ACC_FIRST_EXT_MASK) ? ORION_ACC_FIRST_EXT_BIT : 0) | + ((r->acc_next & ORION_ACC_NEXT_EXT_MASK) ? ORION_ACC_NEXT_EXT_BIT : 0) | + ((w->ale_wr & ORION_ALE_WR_EXT_MASK) ? ORION_ALE_WR_EXT_BIT : 0) | + ((w->wr_low & ORION_WR_LOW_EXT_MASK) ? ORION_WR_LOW_EXT_BIT : 0) | + ((w->wr_high & ORION_WR_HIGH_EXT_MASK) ? ORION_WR_HIGH_EXT_BIT : 0) | + (r->badr_skew << ORION_BADR_SKEW_SHIFT) | + ORION_RESERVED; + + writel(value, devbus->base); +} + +static void devbus_armada_set_timing_params(struct devbus *devbus, + struct device_node *node, + struct devbus_read_params *r, + struct devbus_write_params *w) +{ + u32 value; + /* Set read timings */ - value = r.bus_width << DEV_WIDTH_BIT | - r.badr_skew << BADR_SKEW_BIT | - r.rd_hold << RD_HOLD_BIT | - r.acc_next << ACC_NEXT_BIT | - r.rd_setup << RD_SETUP_BIT | - r.acc_first << ACC_FIRST_BIT | - r.turn_off; + value = r->bus_width << ARMADA_DEV_WIDTH_SHIFT | + r->badr_skew << ARMADA_BADR_SKEW_SHIFT | + r->rd_hold << ARMADA_RD_HOLD_SHIFT | + r->acc_next << ARMADA_ACC_NEXT_SHIFT | + r->rd_setup << ARMADA_RD_SETUP_SHIFT | + r->acc_first << ARMADA_ACC_FIRST_SHIFT | + r->turn_off; dev_dbg(devbus->dev, "read parameters register 0x%p = 0x%x\n", - devbus->base + READ_PARAM_OFFSET, + devbus->base + ARMADA_READ_PARAM_OFFSET, value); - writel(value, devbus->base + READ_PARAM_OFFSET); + writel(value, devbus->base + ARMADA_READ_PARAM_OFFSET); /* Set write timings */ - value = w.sync_enable << SYNC_ENABLE_BIT | - w.wr_low << WR_LOW_BIT | - w.wr_high << WR_HIGH_BIT | - w.ale_wr; + value = w->sync_enable << ARMADA_SYNC_ENABLE_SHIFT | + w->wr_low << ARMADA_WR_LOW_SHIFT | + w->wr_high << ARMADA_WR_HIGH_SHIFT | + w->ale_wr; dev_dbg(devbus->dev, "write parameters register: 0x%p = 0x%x\n", - devbus->base + WRITE_PARAM_OFFSET, + devbus->base + ARMADA_WRITE_PARAM_OFFSET, value); - writel(value, devbus->base + WRITE_PARAM_OFFSET); - - return 0; + writel(value, devbus->base + ARMADA_WRITE_PARAM_OFFSET); } static int mvebu_devbus_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = pdev->dev.of_node; + struct devbus_read_params r; + struct devbus_write_params w; struct devbus *devbus; struct resource *res; struct clk *clk; @@ -229,10 +307,21 @@ static int mvebu_devbus_probe(struct platform_device *pdev) rate = clk_get_rate(clk) / 1000; devbus->tick_ps = 1000000000 / rate; - /* Read the device tree node and set the new timing parameters */ - err = devbus_set_timing_params(devbus, node); - if (err < 0) - return err; + dev_dbg(devbus->dev, "Setting timing parameter, tick is %lu ps\n", + devbus->tick_ps); + + if (!of_property_read_bool(node, "devbus,keep-config")) { + /* Read the Device Tree node */ + err = devbus_get_timing_params(devbus, node, &r, &w); + if (err < 0) + return err; + + /* Set the new timing parameters */ + if (of_device_is_compatible(node, "marvell,orion-devbus")) + devbus_orion_set_timing_params(devbus, node, &r, &w); + else + devbus_armada_set_timing_params(devbus, node, &r, &w); + } /* * We need to create a child device explicitly from here to @@ -248,6 +337,7 @@ static int mvebu_devbus_probe(struct platform_device *pdev) static const struct of_device_id mvebu_devbus_of_match[] = { { .compatible = "marvell,mvebu-devbus" }, + { .compatible = "marvell,orion-devbus" }, {}, }; MODULE_DEVICE_TABLE(of, mvebu_devbus_of_match); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 33834120d05711..bc9bbf6b5649bb 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -250,6 +250,16 @@ config MFD_INTEL_MSIC Passage) chip. This chip embeds audio, battery, GPIO, etc. devices used in Intel Medfield platforms. +config MFD_IPAQ_MICRO + bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" + depends on SA1100_H3100 || SA1100_H3600 + select MFD_CORE + help + Select this to get support for the Microcontroller found in + the Compaq iPAQ handheld computers. This is an Atmel + AT90LS8535 microcontroller flashed with a special iPAQ + firmware using the custom protocol implemented in this driver. + config MFD_JANZ_CMODIO tristate "Janz CMOD-IO PCI MODULbus Carrier Board" select MFD_CORE @@ -331,15 +341,15 @@ config MFD_88PM860X battery-charger under the corresponding menus. config MFD_MAX14577 - bool "Maxim Semiconductor MAX14577 MUIC + Charger Support" + bool "Maxim Semiconductor MAX14577/77836 MUIC + Charger Support" depends on I2C=y select MFD_CORE select REGMAP_I2C select REGMAP_IRQ select IRQ_DOMAIN help - Say yes here to add support for Maxim Semiconductor MAX14577. - This is a Micro-USB IC with Charger controls on chip. + Say yes here to add support for Maxim Semiconductor MAX14577 and + MAX77836 Micro-USB ICs with battery charger. This driver provides common support for accessing the device; additional drivers must be enabled in order to use the functionality of the device. diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2851275e2656f8..59132084f2cd61 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -166,3 +166,4 @@ obj-$(CONFIG_MFD_RETU) += retu-mfd.o obj-$(CONFIG_MFD_AS3711) += as3711.o obj-$(CONFIG_MFD_AS3722) += as3722.o obj-$(CONFIG_MFD_STW481X) += stw481x.o +obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 1c3ae57082ed7b..07e6e27be23cbc 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -508,19 +508,31 @@ int arizona_of_get_type(struct device *dev) } EXPORT_SYMBOL_GPL(arizona_of_get_type); +int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop, + bool mandatory) +{ + int gpio; + + gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0); + if (gpio < 0) { + if (mandatory) + dev_err(arizona->dev, + "Mandatory DT gpio %s missing/malformed: %d\n", + prop, gpio); + + gpio = 0; + } + + return gpio; +} +EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio); + static int arizona_of_get_core_pdata(struct arizona *arizona) { + struct arizona_pdata *pdata = &arizona->pdata; int ret, i; - arizona->pdata.reset = of_get_named_gpio(arizona->dev->of_node, - "wlf,reset", 0); - if (arizona->pdata.reset < 0) - arizona->pdata.reset = 0; - - arizona->pdata.ldoena = of_get_named_gpio(arizona->dev->of_node, - "wlf,ldoena", 0); - if (arizona->pdata.ldoena < 0) - arizona->pdata.ldoena = 0; + pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true); ret = of_property_read_u32_array(arizona->dev->of_node, "wlf,gpio-defaults", @@ -652,6 +664,9 @@ int arizona_dev_init(struct arizona *arizona) return -EINVAL; } + /* Mark DCVDD as external, LDO1 driver will clear if internal */ + arizona->external_dcvdd = true; + ret = mfd_add_devices(arizona->dev, -1, early_devs, ARRAY_SIZE(early_devs), NULL, 0, NULL); if (ret != 0) { @@ -851,14 +866,6 @@ int arizona_dev_init(struct arizona *arizona) arizona->pdata.gpio_defaults[i]); } - /* - * LDO1 can only be used to supply DCVDD so if it has no - * consumers then DCVDD is supplied externally. - */ - if (arizona->pdata.ldo1 && - arizona->pdata.ldo1->num_consumer_supplies == 0) - arizona->external_dcvdd = true; - pm_runtime_set_autosuspend_delay(arizona->dev, 100); pm_runtime_use_autosuspend(arizona->dev); pm_runtime_enable(arizona->dev); diff --git a/drivers/mfd/bcm590xx.c b/drivers/mfd/bcm590xx.c index e9a33c79431bfd..be4d0ac4874c60 100644 --- a/drivers/mfd/bcm590xx.c +++ b/drivers/mfd/bcm590xx.c @@ -64,6 +64,12 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c, return ret; } +static int bcm590xx_i2c_remove(struct i2c_client *i2c) +{ + mfd_remove_devices(&i2c->dev); + return 0; +} + static const struct of_device_id bcm590xx_of_match[] = { { .compatible = "brcm,bcm59056" }, { } @@ -83,6 +89,7 @@ static struct i2c_driver bcm590xx_i2c_driver = { .of_match_table = of_match_ptr(bcm590xx_of_match), }, .probe = bcm590xx_i2c_probe, + .remove = bcm590xx_i2c_remove, .id_table = bcm590xx_i2c_id, }; module_i2c_driver(bcm590xx_i2c_driver); @@ -90,4 +97,4 @@ module_i2c_driver(bcm590xx_i2c_driver); MODULE_AUTHOR("Matt Porter "); MODULE_DESCRIPTION("BCM590xx multi-function driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:bcm590xx"); +MODULE_ALIAS("i2c:bcm590xx"); diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 783fe2e73e1edd..fae69b1db5b142 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -184,3 +184,6 @@ int cros_ec_resume(struct cros_ec_device *ec_dev) EXPORT_SYMBOL(cros_ec_resume); #endif + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ChromeOS EC core driver"); diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 7694e0700d3403..b11fdd63eecdaa 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -1734,18 +1734,17 @@ static struct cpufreq_frequency_table db8500_cpufreq_table[] = { static long round_armss_rate(unsigned long rate) { + struct cpufreq_frequency_table *pos; long freq = 0; - int i = 0; /* cpufreq table frequencies is in KHz. */ rate = rate / 1000; /* Find the corresponding arm opp from the cpufreq table. */ - while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) { - freq = db8500_cpufreq_table[i].frequency; + cpufreq_for_each_entry(pos, db8500_cpufreq_table) { + freq = pos->frequency; if (freq == rate) break; - i++; } /* Return the last valid value, even if a match was not found. */ @@ -1886,23 +1885,21 @@ static void set_clock_rate(u8 clock, unsigned long rate) static int set_armss_rate(unsigned long rate) { - int i = 0; + struct cpufreq_frequency_table *pos; /* cpufreq table frequencies is in KHz. */ rate = rate / 1000; /* Find the corresponding arm opp from the cpufreq table. */ - while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) { - if (db8500_cpufreq_table[i].frequency == rate) + cpufreq_for_each_entry(pos, db8500_cpufreq_table) + if (pos->frequency == rate) break; - i++; - } - if (db8500_cpufreq_table[i].frequency != rate) + if (pos->frequency != rate) return -EINVAL; /* Set the new arm opp. */ - return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].driver_data); + return db8500_prcmu_set_arm_opp(pos->driver_data); } static int set_plldsi_rate(unsigned long rate) diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c new file mode 100644 index 00000000000000..1763d6db346ea3 --- /dev/null +++ b/drivers/mfd/ipaq-micro.c @@ -0,0 +1,482 @@ +/* + * Compaq iPAQ h3xxx Atmel microcontroller companion support + * + * This is an Atmel AT90LS8535 with a special flashed-in firmware that + * implements the special protocol used by this driver. + * + * based on previous kernel 2.4 version by Andrew Christian + * Author : Alessandro Gardich + * Author : Dmitry Artamonow + * Author : Linus Walleij + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static void ipaq_micro_trigger_tx(struct ipaq_micro *micro) +{ + struct ipaq_micro_txdev *tx = µ->tx; + struct ipaq_micro_msg *msg = micro->msg; + int i, bp; + u8 checksum; + u32 val; + + bp = 0; + tx->buf[bp++] = CHAR_SOF; + + checksum = ((msg->id & 0x0f) << 4) | (msg->tx_len & 0x0f); + tx->buf[bp++] = checksum; + + for (i = 0; i < msg->tx_len; i++) { + tx->buf[bp++] = msg->tx_data[i]; + checksum += msg->tx_data[i]; + } + + tx->buf[bp++] = checksum; + tx->len = bp; + tx->index = 0; + print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_OFFSET, 16, 1, + tx->buf, tx->len, true); + + /* Enable interrupt */ + val = readl(micro->base + UTCR3); + val |= UTCR3_TIE; + writel(val, micro->base + UTCR3); +} + +int ipaq_micro_tx_msg(struct ipaq_micro *micro, struct ipaq_micro_msg *msg) +{ + unsigned long flags; + + dev_dbg(micro->dev, "TX msg: %02x, %d bytes\n", msg->id, msg->tx_len); + + spin_lock_irqsave(µ->lock, flags); + if (micro->msg) { + list_add_tail(&msg->node, µ->queue); + spin_unlock_irqrestore(µ->lock, flags); + return 0; + } + micro->msg = msg; + ipaq_micro_trigger_tx(micro); + spin_unlock_irqrestore(µ->lock, flags); + return 0; +} +EXPORT_SYMBOL(ipaq_micro_tx_msg); + +static void micro_rx_msg(struct ipaq_micro *micro, u8 id, int len, u8 *data) +{ + int i; + + dev_dbg(micro->dev, "RX msg: %02x, %d bytes\n", id, len); + + spin_lock(µ->lock); + switch (id) { + case MSG_VERSION: + case MSG_EEPROM_READ: + case MSG_EEPROM_WRITE: + case MSG_BACKLIGHT: + case MSG_NOTIFY_LED: + case MSG_THERMAL_SENSOR: + case MSG_BATTERY: + /* Handle synchronous messages */ + if (micro->msg && micro->msg->id == id) { + struct ipaq_micro_msg *msg = micro->msg; + + memcpy(msg->rx_data, data, len); + msg->rx_len = len; + complete(µ->msg->ack); + if (!list_empty(µ->queue)) { + micro->msg = list_entry(micro->queue.next, + struct ipaq_micro_msg, + node); + list_del_init(µ->msg->node); + ipaq_micro_trigger_tx(micro); + } else + micro->msg = NULL; + dev_dbg(micro->dev, "OK RX message 0x%02x\n", id); + } else { + dev_err(micro->dev, + "out of band RX message 0x%02x\n", id); + if(!micro->msg) + dev_info(micro->dev, "no message queued\n"); + else + dev_info(micro->dev, "expected message %02x\n", + micro->msg->id); + } + break; + case MSG_KEYBOARD: + if (micro->key) + micro->key(micro->key_data, len, data); + else + dev_dbg(micro->dev, "key message ignored, no handle \n"); + break; + case MSG_TOUCHSCREEN: + if (micro->ts) + micro->ts(micro->ts_data, len, data); + else + dev_dbg(micro->dev, "touchscreen message ignored, no handle \n"); + break; + default: + dev_err(micro->dev, + "unknown msg %d [%d] ", id, len); + for (i = 0; i < len; ++i) + pr_cont("0x%02x ", data[i]); + pr_cont("\n"); + } + spin_unlock(µ->lock); +} + +static void micro_process_char(struct ipaq_micro *micro, u8 ch) +{ + struct ipaq_micro_rxdev *rx = µ->rx; + + switch (rx->state) { + case STATE_SOF: /* Looking for SOF */ + if (ch == CHAR_SOF) + rx->state = STATE_ID; /* Next byte is the id and len */ + break; + case STATE_ID: /* Looking for id and len byte */ + rx->id = (ch & 0xf0) >> 4 ; + rx->len = (ch & 0x0f); + rx->index = 0; + rx->chksum = ch; + rx->state = (rx->len > 0) ? STATE_DATA : STATE_CHKSUM; + break; + case STATE_DATA: /* Looking for 'len' data bytes */ + rx->chksum += ch; + rx->buf[rx->index] = ch; + if (++rx->index == rx->len) + rx->state = STATE_CHKSUM; + break; + case STATE_CHKSUM: /* Looking for the checksum */ + if (ch == rx->chksum) + micro_rx_msg(micro, rx->id, rx->len, rx->buf); + rx->state = STATE_SOF; + break; + } +} + +static void micro_rx_chars(struct ipaq_micro *micro) +{ + u32 status, ch; + + while ((status = readl(micro->base + UTSR1)) & UTSR1_RNE) { + ch = readl(micro->base + UTDR); + if (status & UTSR1_PRE) + dev_err(micro->dev, "rx: parity error\n"); + else if (status & UTSR1_FRE) + dev_err(micro->dev, "rx: framing error\n"); + else if (status & UTSR1_ROR) + dev_err(micro->dev, "rx: overrun error\n"); + micro_process_char(micro, ch); + } +} + +static void ipaq_micro_get_version(struct ipaq_micro *micro) +{ + struct ipaq_micro_msg msg = { + .id = MSG_VERSION, + }; + + ipaq_micro_tx_msg_sync(micro, &msg); + if (msg.rx_len == 4) { + memcpy(micro->version, msg.rx_data, 4); + micro->version[4] = '\0'; + } else if (msg.rx_len == 9) { + memcpy(micro->version, msg.rx_data, 4); + micro->version[4] = '\0'; + /* Bytes 4-7 are "pack", byte 8 is "boot type" */ + } else { + dev_err(micro->dev, + "illegal version message %d bytes\n", msg.rx_len); + } +} + +static void ipaq_micro_eeprom_read(struct ipaq_micro *micro, + u8 address, u8 len, u8 *data) +{ + struct ipaq_micro_msg msg = { + .id = MSG_EEPROM_READ, + }; + u8 i; + + for (i = 0; i < len; i++) { + msg.tx_data[0] = address + i; + msg.tx_data[1] = 1; + msg.tx_len = 2; + ipaq_micro_tx_msg_sync(micro, &msg); + memcpy(data + (i * 2), msg.rx_data, 2); + } +} + +static char *ipaq_micro_str(u8 *wchar, u8 len) +{ + char retstr[256]; + u8 i; + + for (i = 0; i < len / 2; i++) + retstr[i] = wchar[i * 2]; + return kstrdup(retstr, GFP_KERNEL); +} + +static u16 ipaq_micro_to_u16(u8 *data) +{ + return data[1] << 8 | data[0]; +} + +static void ipaq_micro_eeprom_dump(struct ipaq_micro *micro) +{ + u8 dump[256]; + char *str; + + ipaq_micro_eeprom_read(micro, 0, 128, dump); + str = ipaq_micro_str(dump, 10); + if (str) { + dev_info(micro->dev, "HM version %s\n", str); + kfree(str); + } + str = ipaq_micro_str(dump+10, 40); + if (str) { + dev_info(micro->dev, "serial number: %s\n", str); + /* Feed the random pool with this */ + add_device_randomness(str, strlen(str)); + kfree(str); + } + str = ipaq_micro_str(dump+50, 20); + if (str) { + dev_info(micro->dev, "module ID: %s\n", str); + kfree(str); + } + str = ipaq_micro_str(dump+70, 10); + if (str) { + dev_info(micro->dev, "product revision: %s\n", str); + kfree(str); + } + dev_info(micro->dev, "product ID: %u\n", ipaq_micro_to_u16(dump+80)); + dev_info(micro->dev, "frame rate: %u fps\n", + ipaq_micro_to_u16(dump+82)); + dev_info(micro->dev, "page mode: %u\n", ipaq_micro_to_u16(dump+84)); + dev_info(micro->dev, "country ID: %u\n", ipaq_micro_to_u16(dump+86)); + dev_info(micro->dev, "color display: %s\n", + ipaq_micro_to_u16(dump+88) ? "yes" : "no"); + dev_info(micro->dev, "ROM size: %u MiB\n", ipaq_micro_to_u16(dump+90)); + dev_info(micro->dev, "RAM size: %u KiB\n", ipaq_micro_to_u16(dump+92)); + dev_info(micro->dev, "screen: %u x %u\n", + ipaq_micro_to_u16(dump+94), ipaq_micro_to_u16(dump+96)); + print_hex_dump(KERN_DEBUG, "eeprom: ", DUMP_PREFIX_OFFSET, 16, 1, + dump, 256, true); + +} + +static void micro_tx_chars(struct ipaq_micro *micro) +{ + struct ipaq_micro_txdev *tx = µ->tx; + u32 val; + + while ((tx->index < tx->len) && + (readl(micro->base + UTSR1) & UTSR1_TNF)) { + writel(tx->buf[tx->index], micro->base + UTDR); + tx->index++; + } + + /* Stop interrupts */ + val = readl(micro->base + UTCR3); + val &= ~UTCR3_TIE; + writel(val, micro->base + UTCR3); +} + +static void micro_reset_comm(struct ipaq_micro *micro) +{ + struct ipaq_micro_rxdev *rx = µ->rx; + u32 val; + + if (micro->msg) + complete(µ->msg->ack); + + /* Initialize Serial channel protocol frame */ + rx->state = STATE_SOF; /* Reset the state machine */ + + /* Set up interrupts */ + writel(0x01, micro->sdlc + 0x0); /* Select UART mode */ + + /* Clean up CR3 */ + writel(0x0, micro->base + UTCR3); + + /* Format: 8N1 */ + writel(UTCR0_8BitData | UTCR0_1StpBit, micro->base + UTCR0); + + /* Baud rate: 115200 */ + writel(0x0, micro->base + UTCR1); + writel(0x1, micro->base + UTCR2); + + /* Clear SR0 */ + writel(0xff, micro->base + UTSR0); + + /* Enable RX int, disable TX int */ + writel(UTCR3_TXE | UTCR3_RXE | UTCR3_RIE, micro->base + UTCR3); + val = readl(micro->base + UTCR3); + val &= ~UTCR3_TIE; + writel(val, micro->base + UTCR3); +} + +static irqreturn_t micro_serial_isr(int irq, void *dev_id) +{ + struct ipaq_micro *micro = dev_id; + struct ipaq_micro_txdev *tx = µ->tx; + u32 status; + + status = readl(micro->base + UTSR0); + do { + if (status & (UTSR0_RID | UTSR0_RFS)) { + if (status & UTSR0_RID) + /* Clear the Receiver IDLE bit */ + writel(UTSR0_RID, micro->base + UTSR0); + micro_rx_chars(micro); + } + + /* Clear break bits */ + if (status & (UTSR0_RBB | UTSR0_REB)) + writel(status & (UTSR0_RBB | UTSR0_REB), + micro->base + UTSR0); + + if (status & UTSR0_TFS) + micro_tx_chars(micro); + + status = readl(micro->base + UTSR0); + + } while (((tx->index < tx->len) && (status & UTSR0_TFS)) || + (status & (UTSR0_RFS | UTSR0_RID))); + + return IRQ_HANDLED; +} + +static struct mfd_cell micro_cells[] = { + { .name = "ipaq-micro-backlight", }, + { .name = "ipaq-micro-battery", }, + { .name = "ipaq-micro-keys", }, + { .name = "ipaq-micro-ts", }, + { .name = "ipaq-micro-leds", }, +}; + +static int micro_resume(struct device *dev) +{ + struct ipaq_micro *micro = dev_get_drvdata(dev); + + micro_reset_comm(micro); + mdelay(10); + + return 0; +} + +static int micro_probe(struct platform_device *pdev) +{ + struct ipaq_micro *micro; + struct resource *res; + int ret; + int irq; + + micro = devm_kzalloc(&pdev->dev, sizeof(*micro), GFP_KERNEL); + if (!micro) + return -ENOMEM; + + micro->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + micro->base = devm_request_and_ioremap(&pdev->dev, res); + if (!micro->base) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + return -EINVAL; + + micro->sdlc = devm_request_and_ioremap(&pdev->dev, res); + if (!micro->sdlc) + return -ENOMEM; + + micro_reset_comm(micro); + + irq = platform_get_irq(pdev, 0); + if (!irq) + return -EINVAL; + ret = devm_request_irq(&pdev->dev, irq, micro_serial_isr, + IRQF_SHARED, "ipaq-micro", + micro); + if (ret) { + dev_err(&pdev->dev, "unable to grab serial port IRQ\n"); + return ret; + } else + dev_info(&pdev->dev, "grabbed serial port IRQ\n"); + + spin_lock_init(µ->lock); + INIT_LIST_HEAD(µ->queue); + platform_set_drvdata(pdev, micro); + + ret = mfd_add_devices(&pdev->dev, pdev->id, micro_cells, + ARRAY_SIZE(micro_cells), NULL, 0, NULL); + if (ret) { + dev_err(&pdev->dev, "error adding MFD cells"); + return ret; + } + + /* Check version */ + ipaq_micro_get_version(micro); + dev_info(&pdev->dev, "Atmel micro ASIC version %s\n", micro->version); + ipaq_micro_eeprom_dump(micro); + + return 0; +} + +static int micro_remove(struct platform_device *pdev) +{ + struct ipaq_micro *micro = platform_get_drvdata(pdev); + u32 val; + + mfd_remove_devices(&pdev->dev); + + val = readl(micro->base + UTCR3); + val &= ~(UTCR3_RXE | UTCR3_RIE); /* disable receive interrupt */ + val &= ~(UTCR3_TXE | UTCR3_TIE); /* disable transmit interrupt */ + writel(val, micro->base + UTCR3); + + return 0; +} + +static const struct dev_pm_ops micro_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(NULL, micro_resume) +}; + +static struct platform_driver micro_device_driver = { + .driver = { + .name = "ipaq-h3xxx-micro", + .pm = µ_dev_pm_ops, + }, + .probe = micro_probe, + .remove = micro_remove, + /* .shutdown = micro_suspend, // FIXME */ +}; +module_platform_driver(micro_device_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("driver for iPAQ Atmel micro core and backlight"); diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index 07692604e11912..25c5ca6797da70 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -288,9 +288,38 @@ EXPORT_SYMBOL_GPL(kempld_release_mutex); */ static int kempld_get_info(struct kempld_device_data *pld) { + int ret; struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); + char major, minor; + + ret = pdata->get_info(pld); + if (ret) + return ret; + + /* The Kontron PLD firmware version string has the following format: + * Pwxy.zzzz + * P: Fixed + * w: PLD number - 1 hex digit + * x: Major version - 1 alphanumerical digit (0-9A-V) + * y: Minor version - 1 alphanumerical digit (0-9A-V) + * zzzz: Build number - 4 zero padded hex digits */ - return pdata->get_info(pld); + if (pld->info.major < 10) + major = pld->info.major + '0'; + else + major = (pld->info.major - 10) + 'A'; + if (pld->info.minor < 10) + minor = pld->info.minor + '0'; + else + minor = (pld->info.minor - 10) + 'A'; + + ret = scnprintf(pld->info.version, sizeof(pld->info.version), + "P%X%c%c.%04X", pld->info.number, major, minor, + pld->info.buildnr); + if (ret < 0) + return ret; + + return 0; } /* @@ -307,9 +336,71 @@ static int kempld_register_cells(struct kempld_device_data *pld) return pdata->register_cells(pld); } +static const char *kempld_get_type_string(struct kempld_device_data *pld) +{ + const char *version_type; + + switch (pld->info.type) { + case 0: + version_type = "release"; + break; + case 1: + version_type = "debug"; + break; + case 2: + version_type = "custom"; + break; + default: + version_type = "unspecified"; + break; + } + + return version_type; +} + +static ssize_t kempld_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kempld_device_data *pld = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version); +} + +static ssize_t kempld_specification_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kempld_device_data *pld = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major, + pld->info.spec_minor); +} + +static ssize_t kempld_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kempld_device_data *pld = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld)); +} + +static DEVICE_ATTR(pld_version, S_IRUGO, kempld_version_show, NULL); +static DEVICE_ATTR(pld_specification, S_IRUGO, kempld_specification_show, + NULL); +static DEVICE_ATTR(pld_type, S_IRUGO, kempld_type_show, NULL); + +static struct attribute *pld_attributes[] = { + &dev_attr_pld_version.attr, + &dev_attr_pld_specification.attr, + &dev_attr_pld_type.attr, + NULL +}; + +static const struct attribute_group pld_attr_group = { + .attrs = pld_attributes, +}; + static int kempld_detect_device(struct kempld_device_data *pld) { - char *version_type; u8 index_reg; int ret; @@ -335,27 +426,19 @@ static int kempld_detect_device(struct kempld_device_data *pld) if (ret) return ret; - switch (pld->info.type) { - case 0: - version_type = "release"; - break; - case 1: - version_type = "debug"; - break; - case 2: - version_type = "custom"; - break; - default: - version_type = "unspecified"; - } + dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n", + pld->info.version, kempld_get_type_string(pld), + pld->info.spec_major, pld->info.spec_minor); + + ret = sysfs_create_group(&pld->dev->kobj, &pld_attr_group); + if (ret) + return ret; - dev_info(pld->dev, "Found Kontron PLD %d\n", pld->info.number); - dev_info(pld->dev, "%s version %d.%d build %d, specification %d.%d\n", - version_type, pld->info.major, pld->info.minor, - pld->info.buildnr, pld->info.spec_major, - pld->info.spec_minor); + ret = kempld_register_cells(pld); + if (ret) + sysfs_remove_group(&pld->dev->kobj, &pld_attr_group); - return kempld_register_cells(pld); + return ret; } static int kempld_probe(struct platform_device *pdev) @@ -399,6 +482,8 @@ static int kempld_remove(struct platform_device *pdev) struct kempld_device_data *pld = platform_get_drvdata(pdev); struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); + sysfs_remove_group(&pld->dev->kobj, &pld_attr_group); + mfd_remove_devices(&pdev->dev); pdata->release_hardware_mutex(pld); diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 3f10ea3f45d1ae..7d8482ff586882 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -488,6 +488,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { [LPC_PPT] = { .name = "Panther Point", .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, }, [LPC_LPT] = { .name = "Lynx Point", diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index 5f13cefe8defcf..484d372a4892b6 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -1,7 +1,7 @@ /* - * max14577.c - mfd core driver for the Maxim 14577 + * max14577.c - mfd core driver for the Maxim 14577/77836 * - * Copyright (C) 2013 Samsung Electrnoics + * Copyright (C) 2014 Samsung Electrnoics * Chanwoo Choi * Krzysztof Kozlowski * @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,38 @@ static struct mfd_cell max14577_devs[] = { { .name = "max14577-charger", }, }; -static bool max14577_volatile_reg(struct device *dev, unsigned int reg) +static struct mfd_cell max77836_devs[] = { + { + .name = "max77836-muic", + .of_compatible = "maxim,max77836-muic", + }, + { + .name = "max77836-regulator", + .of_compatible = "maxim,max77836-regulator", + }, + { + .name = "max77836-charger", + .of_compatible = "maxim,max77836-charger", + }, + { + .name = "max77836-battery", + .of_compatible = "maxim,max77836-battery", + }, +}; + +static struct of_device_id max14577_dt_match[] = { + { + .compatible = "maxim,max14577", + .data = (void *)MAXIM_DEVICE_TYPE_MAX14577, + }, + { + .compatible = "maxim,max77836", + .data = (void *)MAXIM_DEVICE_TYPE_MAX77836, + }, + {}, +}; + +static bool max14577_muic_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case MAX14577_REG_INT1 ... MAX14577_REG_STATUS3: @@ -48,49 +80,221 @@ static bool max14577_volatile_reg(struct device *dev, unsigned int reg) return false; } -static const struct regmap_config max14577_regmap_config = { +static bool max77836_muic_volatile_reg(struct device *dev, unsigned int reg) +{ + /* Any max14577 volatile registers are also max77836 volatile. */ + if (max14577_muic_volatile_reg(dev, reg)) + return true; + + switch (reg) { + case MAX77836_FG_REG_VCELL_MSB ... MAX77836_FG_REG_SOC_LSB: + case MAX77836_FG_REG_CRATE_MSB ... MAX77836_FG_REG_CRATE_LSB: + case MAX77836_FG_REG_STATUS_H ... MAX77836_FG_REG_STATUS_L: + case MAX77836_PMIC_REG_INTSRC: + case MAX77836_PMIC_REG_TOPSYS_INT: + case MAX77836_PMIC_REG_TOPSYS_STAT: + return true; + default: + break; + } + return false; +} + +static const struct regmap_config max14577_muic_regmap_config = { .reg_bits = 8, .val_bits = 8, - .volatile_reg = max14577_volatile_reg, + .volatile_reg = max14577_muic_volatile_reg, .max_register = MAX14577_REG_END, }; +static const struct regmap_config max77836_pmic_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = max77836_muic_volatile_reg, + .max_register = MAX77836_PMIC_REG_END, +}; + static const struct regmap_irq max14577_irqs[] = { /* INT1 interrupts */ - { .reg_offset = 0, .mask = INT1_ADC_MASK, }, - { .reg_offset = 0, .mask = INT1_ADCLOW_MASK, }, - { .reg_offset = 0, .mask = INT1_ADCERR_MASK, }, + { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, }, + { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, }, + { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, }, /* INT2 interrupts */ - { .reg_offset = 1, .mask = INT2_CHGTYP_MASK, }, - { .reg_offset = 1, .mask = INT2_CHGDETRUN_MASK, }, - { .reg_offset = 1, .mask = INT2_DCDTMR_MASK, }, - { .reg_offset = 1, .mask = INT2_DBCHG_MASK, }, - { .reg_offset = 1, .mask = INT2_VBVOLT_MASK, }, + { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, }, + { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, }, + { .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, }, + { .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, }, + { .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, }, /* INT3 interrupts */ - { .reg_offset = 2, .mask = INT3_EOC_MASK, }, - { .reg_offset = 2, .mask = INT3_CGMBC_MASK, }, - { .reg_offset = 2, .mask = INT3_OVP_MASK, }, - { .reg_offset = 2, .mask = INT3_MBCCHGERR_MASK, }, + { .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, }, + { .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, }, + { .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, }, + { .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, }, }; static const struct regmap_irq_chip max14577_irq_chip = { .name = "max14577", .status_base = MAX14577_REG_INT1, .mask_base = MAX14577_REG_INTMASK1, - .mask_invert = 1, + .mask_invert = true, .num_regs = 3, .irqs = max14577_irqs, .num_irqs = ARRAY_SIZE(max14577_irqs), }; +static const struct regmap_irq max77836_muic_irqs[] = { + /* INT1 interrupts */ + { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, }, + { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, }, + { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, }, + { .reg_offset = 0, .mask = MAX77836_INT1_ADC1K_MASK, }, + /* INT2 interrupts */ + { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, }, + { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, }, + { .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, }, + { .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, }, + { .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, }, + { .reg_offset = 1, .mask = MAX77836_INT2_VIDRM_MASK, }, + /* INT3 interrupts */ + { .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, }, + { .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, }, + { .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, }, + { .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, }, +}; + +static const struct regmap_irq_chip max77836_muic_irq_chip = { + .name = "max77836-muic", + .status_base = MAX14577_REG_INT1, + .mask_base = MAX14577_REG_INTMASK1, + .mask_invert = true, + .num_regs = 3, + .irqs = max77836_muic_irqs, + .num_irqs = ARRAY_SIZE(max77836_muic_irqs), +}; + +static const struct regmap_irq max77836_pmic_irqs[] = { + { .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T120C_MASK, }, + { .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T140C_MASK, }, +}; + +static const struct regmap_irq_chip max77836_pmic_irq_chip = { + .name = "max77836-pmic", + .status_base = MAX77836_PMIC_REG_TOPSYS_INT, + .mask_base = MAX77836_PMIC_REG_TOPSYS_INT_MASK, + .mask_invert = false, + .num_regs = 1, + .irqs = max77836_pmic_irqs, + .num_irqs = ARRAY_SIZE(max77836_pmic_irqs), +}; + +static void max14577_print_dev_type(struct max14577 *max14577) +{ + u8 reg_data, vendor_id, device_id; + int ret; + + ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID, + ®_data); + if (ret) { + dev_err(max14577->dev, + "Failed to read DEVICEID register: %d\n", ret); + return; + } + + vendor_id = ((reg_data & DEVID_VENDORID_MASK) >> + DEVID_VENDORID_SHIFT); + device_id = ((reg_data & DEVID_DEVICEID_MASK) >> + DEVID_DEVICEID_SHIFT); + + dev_info(max14577->dev, "Device type: %u (ID: 0x%x, vendor: 0x%x)\n", + max14577->dev_type, device_id, vendor_id); +} + +/* + * Max77836 specific initialization code for driver probe. + * Adds new I2C dummy device, regmap and regmap IRQ chip. + * Unmasks Interrupt Source register. + * + * On success returns 0. + * On failure returns errno and reverts any changes done so far (e.g. remove + * I2C dummy device), except masking the INT SRC register. + */ +static int max77836_init(struct max14577 *max14577) +{ + int ret; + u8 intsrc_mask; + + max14577->i2c_pmic = i2c_new_dummy(max14577->i2c->adapter, + I2C_ADDR_PMIC); + if (!max14577->i2c_pmic) { + dev_err(max14577->dev, "Failed to register PMIC I2C device\n"); + return -ENODEV; + } + i2c_set_clientdata(max14577->i2c_pmic, max14577); + + max14577->regmap_pmic = devm_regmap_init_i2c(max14577->i2c_pmic, + &max77836_pmic_regmap_config); + if (IS_ERR(max14577->regmap_pmic)) { + ret = PTR_ERR(max14577->regmap_pmic); + dev_err(max14577->dev, "Failed to allocate PMIC register map: %d\n", + ret); + goto err; + } + + /* Un-mask MAX77836 Interrupt Source register */ + ret = max14577_read_reg(max14577->regmap_pmic, + MAX77836_PMIC_REG_INTSRC_MASK, &intsrc_mask); + if (ret < 0) { + dev_err(max14577->dev, "Failed to read PMIC register\n"); + goto err; + } + + intsrc_mask &= ~(MAX77836_INTSRC_MASK_TOP_INT_MASK); + intsrc_mask &= ~(MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK); + ret = max14577_write_reg(max14577->regmap_pmic, + MAX77836_PMIC_REG_INTSRC_MASK, intsrc_mask); + if (ret < 0) { + dev_err(max14577->dev, "Failed to write PMIC register\n"); + goto err; + } + + ret = regmap_add_irq_chip(max14577->regmap_pmic, max14577->irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED, + 0, &max77836_pmic_irq_chip, + &max14577->irq_data_pmic); + if (ret != 0) { + dev_err(max14577->dev, "Failed to request PMIC IRQ %d: %d\n", + max14577->irq, ret); + goto err; + } + + return 0; + +err: + i2c_unregister_device(max14577->i2c_pmic); + + return ret; +} + +/* + * Max77836 specific de-initialization code for driver remove. + */ +static void max77836_remove(struct max14577 *max14577) +{ + regmap_del_irq_chip(max14577->irq, max14577->irq_data_pmic); + i2c_unregister_device(max14577->i2c_pmic); +} + static int max14577_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct max14577 *max14577; struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev); struct device_node *np = i2c->dev.of_node; - u8 reg_data; int ret = 0; + const struct regmap_irq_chip *irq_chip; + struct mfd_cell *mfd_devs; + unsigned int mfd_devs_size; + int irq_flags; if (np) { pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); @@ -113,7 +317,8 @@ static int max14577_i2c_probe(struct i2c_client *i2c, max14577->i2c = i2c; max14577->irq = i2c->irq; - max14577->regmap = devm_regmap_init_i2c(i2c, &max14577_regmap_config); + max14577->regmap = devm_regmap_init_i2c(i2c, + &max14577_muic_regmap_config); if (IS_ERR(max14577->regmap)) { ret = PTR_ERR(max14577->regmap); dev_err(max14577->dev, "Failed to allocate register map: %d\n", @@ -121,23 +326,36 @@ static int max14577_i2c_probe(struct i2c_client *i2c, return ret; } - ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID, - ®_data); - if (ret) { - dev_err(max14577->dev, "Device not found on this channel: %d\n", - ret); - return ret; + if (np) { + const struct of_device_id *of_id; + + of_id = of_match_device(max14577_dt_match, &i2c->dev); + if (of_id) + max14577->dev_type = (unsigned int)of_id->data; + } else { + max14577->dev_type = id->driver_data; + } + + max14577_print_dev_type(max14577); + + switch (max14577->dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + irq_chip = &max77836_muic_irq_chip; + mfd_devs = max77836_devs; + mfd_devs_size = ARRAY_SIZE(max77836_devs); + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED; + break; + case MAXIM_DEVICE_TYPE_MAX14577: + default: + irq_chip = &max14577_irq_chip; + mfd_devs = max14577_devs; + mfd_devs_size = ARRAY_SIZE(max14577_devs); + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + break; } - max14577->vendor_id = ((reg_data & DEVID_VENDORID_MASK) >> - DEVID_VENDORID_SHIFT); - max14577->device_id = ((reg_data & DEVID_DEVICEID_MASK) >> - DEVID_DEVICEID_SHIFT); - dev_info(max14577->dev, "Device ID: 0x%x, vendor: 0x%x\n", - max14577->device_id, max14577->vendor_id); ret = regmap_add_irq_chip(max14577->regmap, max14577->irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0, - &max14577_irq_chip, + irq_flags, 0, irq_chip, &max14577->irq_data); if (ret != 0) { dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", @@ -145,8 +363,15 @@ static int max14577_i2c_probe(struct i2c_client *i2c, return ret; } - ret = mfd_add_devices(max14577->dev, -1, max14577_devs, - ARRAY_SIZE(max14577_devs), NULL, 0, + /* Max77836 specific initialization code (additional regmap) */ + if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) { + ret = max77836_init(max14577); + if (ret < 0) + goto err_max77836; + } + + ret = mfd_add_devices(max14577->dev, -1, mfd_devs, + mfd_devs_size, NULL, 0, regmap_irq_get_domain(max14577->irq_data)); if (ret < 0) goto err_mfd; @@ -156,6 +381,9 @@ static int max14577_i2c_probe(struct i2c_client *i2c, return 0; err_mfd: + if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) + max77836_remove(max14577); +err_max77836: regmap_del_irq_chip(max14577->irq, max14577->irq_data); return ret; @@ -167,12 +395,15 @@ static int max14577_i2c_remove(struct i2c_client *i2c) mfd_remove_devices(max14577->dev); regmap_del_irq_chip(max14577->irq, max14577->irq_data); + if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) + max77836_remove(max14577); return 0; } static const struct i2c_device_id max14577_i2c_id[] = { - { "max14577", 0 }, + { "max14577", MAXIM_DEVICE_TYPE_MAX14577, }, + { "max77836", MAXIM_DEVICE_TYPE_MAX77836, }, { } }; MODULE_DEVICE_TABLE(i2c, max14577_i2c_id); @@ -215,11 +446,6 @@ static int max14577_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -static struct of_device_id max14577_dt_match[] = { - { .compatible = "maxim,max14577", }, - {}, -}; - static SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume); static struct i2c_driver max14577_i2c_driver = { @@ -236,6 +462,9 @@ static struct i2c_driver max14577_i2c_driver = { static int __init max14577_i2c_init(void) { + BUILD_BUG_ON(ARRAY_SIZE(max14577_i2c_id) != MAXIM_DEVICE_TYPE_NUM); + BUILD_BUG_ON(ARRAY_SIZE(max14577_dt_match) != MAXIM_DEVICE_TYPE_NUM); + return i2c_add_driver(&max14577_i2c_driver); } subsys_initcall(max14577_i2c_init); @@ -247,5 +476,5 @@ static void __exit max14577_i2c_exit(void) module_exit(max14577_i2c_exit); MODULE_AUTHOR("Chanwoo Choi , Krzysztof Kozlowski "); -MODULE_DESCRIPTION("MAXIM 14577 multi-function core driver"); +MODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 06e64b6fcb89d6..ddabc8157eb013 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -660,22 +660,26 @@ int mc13xxx_common_init(struct device *dev) if (ret) return ret; + mutex_init(&mc13xxx->lock); + ret = request_threaded_irq(mc13xxx->irq, NULL, mc13xxx_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx); if (ret) return ret; - mutex_init(&mc13xxx->lock); - if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata) mc13xxx->flags = pdata->flags; if (mc13xxx->flags & MC13XXX_USE_ADC) mc13xxx_add_subdevice(mc13xxx, "%s-adc"); - if (mc13xxx->flags & MC13XXX_USE_CODEC) - mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec", - pdata->codec, sizeof(*pdata->codec)); + if (mc13xxx->flags & MC13XXX_USE_CODEC) { + if (pdata) + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec", + pdata->codec, sizeof(*pdata->codec)); + else + mc13xxx_add_subdevice(mc13xxx, "%s-codec"); + } if (mc13xxx->flags & MC13XXX_USE_RTC) mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c index b53b9d46cc4534..141ea52c46e3af 100644 --- a/drivers/mfd/rtsx_usb.c +++ b/drivers/mfd/rtsx_usb.c @@ -67,7 +67,7 @@ static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr, ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout); add_timer(&ucr->sg_timer); usb_sg_wait(&ucr->current_sg); - del_timer(&ucr->sg_timer); + del_timer_sync(&ucr->sg_timer); if (act_len) *act_len = ucr->current_sg.bytes; @@ -644,14 +644,14 @@ static int rtsx_usb_probe(struct usb_interface *intf, if (ret) goto out_init_fail; + /* initialize USB SG transfer timer */ + setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr); + ret = mfd_add_devices(&intf->dev, usb_dev->devnum, rtsx_usb_cells, ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL); if (ret) goto out_init_fail; - /* initialize USB SG transfer timer */ - init_timer(&ucr->sg_timer); - setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr); #ifdef CONFIG_PM intf->needs_remote_wakeup = 1; usb_enable_autosuspend(usb_dev); @@ -687,9 +687,15 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message) dev_dbg(&intf->dev, "%s called with pm message 0x%04u\n", __func__, message.event); + /* + * Call to make sure LED is off during suspend to save more power. + * It is NOT a permanent state and could be turned on anytime later. + * Thus no need to call turn_on when resunming. + */ mutex_lock(&ucr->dev_mutex); rtsx_usb_turn_off_led(ucr); mutex_unlock(&ucr->dev_mutex); + return 0; } diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 1cf27521fff4f2..09fd256abcf604 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -196,20 +195,6 @@ static const struct regmap_config s5m8767_regmap_config = { .cache_type = REGCACHE_FLAT, }; -static const struct regmap_config s5m_rtc_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = SEC_RTC_REG_MAX, -}; - -static const struct regmap_config s2mps14_rtc_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = S2MPS_RTC_REG_MAX, -}; - #ifdef CONFIG_OF /* * Only the common platform data elements for s5m8767 are parsed here from the @@ -264,8 +249,9 @@ static int sec_pmic_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); - const struct regmap_config *regmap, *regmap_rtc; + const struct regmap_config *regmap; struct sec_pmic_dev *sec_pmic; + unsigned long device_type; int ret; sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev), @@ -277,7 +263,7 @@ static int sec_pmic_probe(struct i2c_client *i2c, sec_pmic->dev = &i2c->dev; sec_pmic->i2c = i2c; sec_pmic->irq = i2c->irq; - sec_pmic->type = sec_i2c_get_driver_data(i2c, id); + device_type = sec_i2c_get_driver_data(i2c, id); if (sec_pmic->dev->of_node) { pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); @@ -285,7 +271,7 @@ static int sec_pmic_probe(struct i2c_client *i2c, ret = PTR_ERR(pdata); return ret; } - pdata->device_type = sec_pmic->type; + pdata->device_type = device_type; } if (pdata) { sec_pmic->device_type = pdata->device_type; @@ -298,39 +284,21 @@ static int sec_pmic_probe(struct i2c_client *i2c, switch (sec_pmic->device_type) { case S2MPA01: regmap = &s2mpa01_regmap_config; - /* - * The rtc-s5m driver does not support S2MPA01 and there - * is no mfd_cell for S2MPA01 RTC device. - * However we must pass something to devm_regmap_init_i2c() - * so use S5M-like regmap config even though it wouldn't work. - */ - regmap_rtc = &s5m_rtc_regmap_config; break; case S2MPS11X: regmap = &s2mps11_regmap_config; - /* - * The rtc-s5m driver does not support S2MPS11 and there - * is no mfd_cell for S2MPS11 RTC device. - * However we must pass something to devm_regmap_init_i2c() - * so use S5M-like regmap config even though it wouldn't work. - */ - regmap_rtc = &s5m_rtc_regmap_config; break; case S2MPS14X: regmap = &s2mps14_regmap_config; - regmap_rtc = &s2mps14_rtc_regmap_config; break; case S5M8763X: regmap = &s5m8763_regmap_config; - regmap_rtc = &s5m_rtc_regmap_config; break; case S5M8767X: regmap = &s5m8767_regmap_config; - regmap_rtc = &s5m_rtc_regmap_config; break; default: regmap = &sec_regmap_config; - regmap_rtc = &s5m_rtc_regmap_config; break; } @@ -342,21 +310,6 @@ static int sec_pmic_probe(struct i2c_client *i2c, return ret; } - sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); - if (!sec_pmic->rtc) { - dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n"); - return -ENODEV; - } - i2c_set_clientdata(sec_pmic->rtc, sec_pmic); - - sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc); - if (IS_ERR(sec_pmic->regmap_rtc)) { - ret = PTR_ERR(sec_pmic->regmap_rtc); - dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n", - ret); - goto err_regmap_rtc; - } - if (pdata && pdata->cfg_pmic_irq) pdata->cfg_pmic_irq(); @@ -403,8 +356,6 @@ static int sec_pmic_probe(struct i2c_client *i2c, err_mfd: sec_irq_exit(sec_pmic); -err_regmap_rtc: - i2c_unregister_device(sec_pmic->rtc); return ret; } @@ -414,7 +365,6 @@ static int sec_pmic_remove(struct i2c_client *i2c) mfd_remove_devices(sec_pmic->dev); sec_irq_exit(sec_pmic); - i2c_unregister_device(sec_pmic->rtc); return 0; } diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index 64e7913aadc6cf..654e2c1dbf7a61 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c @@ -385,7 +385,7 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) &sec_pmic->irq_data); break; default: - dev_err(sec_pmic->dev, "Unknown device type %d\n", + dev_err(sec_pmic->dev, "Unknown device type %lu\n", sec_pmic->device_type); return -EINVAL; } diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index ba1a25d758c12e..1c3e6e2efe4108 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c @@ -32,14 +32,6 @@ #define NUM_INT_REG 2 #define TOTAL_NUM_REG 0x18 -/* interrupt status registers */ -#define TPS65090_INT_STS 0x0 -#define TPS65090_INT_STS2 0x1 - -/* interrupt mask registers */ -#define TPS65090_INT_MSK 0x2 -#define TPS65090_INT_MSK2 0x3 - #define TPS65090_INT1_MASK_VAC_STATUS_CHANGE 1 #define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE 2 #define TPS65090_INT1_MASK_BAT_STATUS_CHANGE 3 @@ -64,11 +56,16 @@ static struct resource charger_resources[] = { } }; -static const struct mfd_cell tps65090s[] = { - { +enum tps65090_cells { + PMIC = 0, + CHARGER = 1, +}; + +static struct mfd_cell tps65090s[] = { + [PMIC] = { .name = "tps65090-pmic", }, - { + [CHARGER] = { .name = "tps65090-charger", .num_resources = ARRAY_SIZE(charger_resources), .resources = &charger_resources[0], @@ -139,17 +136,26 @@ static struct regmap_irq_chip tps65090_irq_chip = { .irqs = tps65090_irqs, .num_irqs = ARRAY_SIZE(tps65090_irqs), .num_regs = NUM_INT_REG, - .status_base = TPS65090_INT_STS, - .mask_base = TPS65090_INT_MSK, + .status_base = TPS65090_REG_INTR_STS, + .mask_base = TPS65090_REG_INTR_MASK, .mask_invert = true, }; static bool is_volatile_reg(struct device *dev, unsigned int reg) { - if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS2)) - return true; - else + /* Nearly all registers have status bits mixed in, except a few */ + switch (reg) { + case TPS65090_REG_INTR_MASK: + case TPS65090_REG_INTR_MASK2: + case TPS65090_REG_CG_CTRL0: + case TPS65090_REG_CG_CTRL1: + case TPS65090_REG_CG_CTRL2: + case TPS65090_REG_CG_CTRL3: + case TPS65090_REG_CG_CTRL4: + case TPS65090_REG_CG_CTRL5: return false; + } + return true; } static const struct regmap_config tps65090_regmap_config = { @@ -211,6 +217,9 @@ static int tps65090_i2c_probe(struct i2c_client *client, "IRQ init failed with err: %d\n", ret); return ret; } + } else { + /* Don't tell children they have an IRQ that'll never fire */ + tps65090s[CHARGER].num_resources = 0; } ret = mfd_add_devices(tps65090->dev, -1, tps65090s, diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index e87140bef66721..db11b4f4061161 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -98,7 +98,11 @@ #define TWL4030_BASEADD_BACKUP 0x0014 #define TWL4030_BASEADD_INT 0x002E #define TWL4030_BASEADD_PM_MASTER 0x0036 + #define TWL4030_BASEADD_PM_RECEIVER 0x005B +#define TWL4030_DCDC_GLOBAL_CFG 0x06 +#define SMARTREFLEX_ENABLE BIT(3) + #define TWL4030_BASEADD_RTC 0x001C #define TWL4030_BASEADD_SECURED_REG 0x0000 @@ -1204,6 +1208,11 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) * Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface. * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0, * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0. + * + * Also, always enable SmartReflex bit as that's needed for omaps to + * to do anything over I2C4 for voltage scaling even if SmartReflex + * is disabled. Without the SmartReflex bit omap sys_clkreq idle + * signal will never trigger for retention idle. */ if (twl_class_is_4030()) { u8 temp; @@ -1212,6 +1221,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \ I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU); twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1); + + twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp, + TWL4030_DCDC_GLOBAL_CFG); + temp |= SMARTREFLEX_ENABLE; + twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp, + TWL4030_DCDC_GLOBAL_CFG); } if (node) { diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 1942b6f231dae3..58bc2be6e6a554 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -549,6 +549,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */ { 0x000002A9, 0x300A }, /* R681 - Mic Detect Level 4 */ { 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */ + { 0x000002CB, 0x0000 }, /* R715 - Isolation control */ { 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */ { 0x00000300, 0x0000 }, /* R768 - Input Enables */ { 0x00000308, 0x0000 }, /* R776 - Input Rate */ @@ -1580,6 +1581,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_MIC_DETECT_LEVEL_3: case ARIZONA_MIC_DETECT_LEVEL_4: case ARIZONA_MIC_NOISE_MIX_CONTROL_1: + case ARIZONA_ISOLATION_CONTROL: case ARIZONA_JACK_DETECT_ANALOGUE: case ARIZONA_INPUT_ENABLES: case ARIZONA_INPUT_ENABLES_STATUS: diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 8baff0effc7dfa..fe2230cb64e224 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -53,7 +53,7 @@ config AD525X_DPOT_SPI config ATMEL_PWM tristate "Atmel AT32/AT91 PWM support" - depends on HAVE_CLK + depends on HAVE_CLK && (AVR32 || ARCH_AT91 || COMPILE_TEST) help This option enables device driver support for the PWM channels on certain Atmel processors. Pulse Width Modulation is used for @@ -200,7 +200,7 @@ config ICS932S401 config ATMEL_SSC tristate "Device driver for Atmel SSC peripheral" - depends on HAS_IOMEM + depends on HAS_IOMEM && (AVR32 || ARCH_AT91 || COMPILE_TEST) ---help--- This option enables device driver support for Atmel Synchronized Serial Communication peripheral (SSC). diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c index b7ebf8021d99d8..c72e96b523eda0 100644 --- a/drivers/misc/arm-charlcd.c +++ b/drivers/misc/arm-charlcd.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -366,11 +367,17 @@ static const struct dev_pm_ops charlcd_pm_ops = { .resume = charlcd_resume, }; +static const struct of_device_id charlcd_match[] = { + { .compatible = "arm,versatile-lcd", }, + {} +}; + static struct platform_driver charlcd_driver = { .driver = { .name = DRIVERNAME, .owner = THIS_MODULE, .pm = &charlcd_pm_ops, + .of_match_table = of_match_ptr(charlcd_match), }, .remove = __exit_p(charlcd_remove), }; diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c index 6a672f9ef522c7..b909fb30232adb 100644 --- a/drivers/misc/ds1682.c +++ b/drivers/misc/ds1682.c @@ -85,7 +85,6 @@ static ssize_t ds1682_store(struct device *dev, struct device_attribute *attr, { struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); struct i2c_client *client = to_i2c_client(dev); - char *endp; u64 val; __le32 val_le; int rc; @@ -93,8 +92,8 @@ static ssize_t ds1682_store(struct device *dev, struct device_attribute *attr, dev_dbg(dev, "ds1682_store() called on %s\n", attr->attr.name); /* Decode input */ - val = simple_strtoull(buf, &endp, 0); - if (buf == endp) { + rc = kstrtoull(buf, 0, &val); + if (rc < 0) { dev_dbg(dev, "input string not a number\n"); return -EINVAL; } diff --git a/drivers/misc/genwqe/card_debugfs.c b/drivers/misc/genwqe/card_debugfs.c index 50d2096ea1c74d..0a33ade64109d4 100644 --- a/drivers/misc/genwqe/card_debugfs.c +++ b/drivers/misc/genwqe/card_debugfs.c @@ -348,7 +348,7 @@ int genwqe_init_debugfs(struct genwqe_dev *cd) char name[64]; unsigned int i; - sprintf(card_name, "%s%u_card", GENWQE_DEVNAME, cd->card_idx); + sprintf(card_name, "%s%d_card", GENWQE_DEVNAME, cd->card_idx); root = debugfs_create_dir(card_name, cd->debugfs_genwqe); if (!root) { @@ -454,7 +454,7 @@ int genwqe_init_debugfs(struct genwqe_dev *cd) } for (i = 0; i < GENWQE_MAX_VFS; i++) { - sprintf(name, "vf%d_jobtimeout_msec", i); + sprintf(name, "vf%u_jobtimeout_msec", i); file = debugfs_create_u32(name, 0666, root, &cd->vf_jobtimeout_msec[i]); diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index d049d271699cac..c00adfaa627940 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c @@ -718,7 +718,7 @@ int genwqe_set_interrupt_capability(struct genwqe_dev *cd, int count) int rc; struct pci_dev *pci_dev = cd->pci_dev; - rc = pci_enable_msi_block(pci_dev, count); + rc = pci_enable_msi_exact(pci_dev, count); if (rc == 0) cd->flags |= GENWQE_FLAG_MSI_ENABLED; return rc; diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index b8deb345548057..0d6234db00fa12 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -111,8 +111,6 @@ int mei_amthif_host_init(struct mei_device *dev) return ret; } - cl->state = MEI_FILE_CONNECTING; - ret = mei_cl_connect(cl, NULL); dev->iamthif_state = MEI_IAMTHIF_IDLE; diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index ddc5ac92a200a8..0e993ef28b94ff 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -247,7 +247,7 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, return id; if (length > dev->me_clients[id].props.max_msg_length) - return -EINVAL; + return -EFBIG; cb = mei_io_cb_init(cl, NULL); if (!cb) @@ -427,8 +427,6 @@ int mei_cl_enable_device(struct mei_cl_device *device) mutex_lock(&dev->device_lock); - cl->state = MEI_FILE_CONNECTING; - err = mei_cl_connect(cl, NULL); if (err < 0) { mutex_unlock(&dev->device_lock); diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 8c078b808cd325..59d20c599b1657 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -415,6 +416,10 @@ void mei_host_client_init(struct work_struct *work) dev->reset_count = 0; mutex_unlock(&dev->device_lock); + + pm_runtime_mark_last_busy(&dev->pdev->dev); + dev_dbg(&dev->pdev->dev, "rpm: autosuspend\n"); + pm_runtime_autosuspend(&dev->pdev->dev); } /** @@ -425,6 +430,12 @@ void mei_host_client_init(struct work_struct *work) */ bool mei_hbuf_acquire(struct mei_device *dev) { + if (mei_pg_state(dev) == MEI_PG_ON || + dev->pg_event == MEI_PG_EVENT_WAIT) { + dev_dbg(&dev->pdev->dev, "device is in pg\n"); + return false; + } + if (!dev->hbuf_is_ready) { dev_dbg(&dev->pdev->dev, "hbuf is not ready\n"); return false; @@ -460,9 +471,18 @@ int mei_cl_disconnect(struct mei_cl *cl) if (cl->state != MEI_FILE_DISCONNECTING) return 0; + rets = pm_runtime_get(&dev->pdev->dev); + if (rets < 0 && rets != -EINPROGRESS) { + pm_runtime_put_noidle(&dev->pdev->dev); + cl_err(dev, cl, "rpm: get failed %d\n", rets); + return rets; + } + cb = mei_io_cb_init(cl, NULL); - if (!cb) - return -ENOMEM; + if (!cb) { + rets = -ENOMEM; + goto free; + } cb->fop_type = MEI_FOP_CLOSE; if (mei_hbuf_acquire(dev)) { @@ -494,8 +514,7 @@ int mei_cl_disconnect(struct mei_cl *cl) cl_err(dev, cl, "wrong status client disconnect.\n"); if (err) - cl_dbg(dev, cl, "wait failed disconnect err=%08x\n", - err); + cl_dbg(dev, cl, "wait failed disconnect err=%d\n", err); cl_err(dev, cl, "failed to disconnect from FW client.\n"); } @@ -503,6 +522,10 @@ int mei_cl_disconnect(struct mei_cl *cl) mei_io_list_flush(&dev->ctrl_rd_list, cl); mei_io_list_flush(&dev->ctrl_wr_list, cl); free: + cl_dbg(dev, cl, "rpm: autosuspend\n"); + pm_runtime_mark_last_busy(&dev->pdev->dev); + pm_runtime_put_autosuspend(&dev->pdev->dev); + mei_io_cb_free(cb); return rets; } @@ -557,6 +580,13 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file) dev = cl->dev; + rets = pm_runtime_get(&dev->pdev->dev); + if (rets < 0 && rets != -EINPROGRESS) { + pm_runtime_put_noidle(&dev->pdev->dev); + cl_err(dev, cl, "rpm: get failed %d\n", rets); + return rets; + } + cb = mei_io_cb_init(cl, file); if (!cb) { rets = -ENOMEM; @@ -567,6 +597,7 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file) /* run hbuf acquire last so we don't have to undo */ if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) { + cl->state = MEI_FILE_CONNECTING; if (mei_hbm_cl_connect_req(dev, cl)) { rets = -ENODEV; goto out; @@ -596,6 +627,10 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file) rets = cl->status; out: + cl_dbg(dev, cl, "rpm: autosuspend\n"); + pm_runtime_mark_last_busy(&dev->pdev->dev); + pm_runtime_put_autosuspend(&dev->pdev->dev); + mei_io_cb_free(cb); return rets; } @@ -713,23 +748,31 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) return -ENOTTY; } + rets = pm_runtime_get(&dev->pdev->dev); + if (rets < 0 && rets != -EINPROGRESS) { + pm_runtime_put_noidle(&dev->pdev->dev); + cl_err(dev, cl, "rpm: get failed %d\n", rets); + return rets; + } + cb = mei_io_cb_init(cl, NULL); - if (!cb) - return -ENOMEM; + if (!cb) { + rets = -ENOMEM; + goto out; + } /* always allocate at least client max message */ length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length); rets = mei_io_cb_alloc_resp_buf(cb, length); if (rets) - goto err; + goto out; cb->fop_type = MEI_FOP_READ; if (mei_hbuf_acquire(dev)) { - if (mei_hbm_cl_flow_control_req(dev, cl)) { - cl_err(dev, cl, "flow control send failed\n"); - rets = -ENODEV; - goto err; - } + rets = mei_hbm_cl_flow_control_req(dev, cl); + if (rets < 0) + goto out; + list_add_tail(&cb->list, &dev->read_list.list); } else { list_add_tail(&cb->list, &dev->ctrl_wr_list.list); @@ -737,9 +780,14 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) cl->read_cb = cb; - return rets; -err: - mei_io_cb_free(cb); +out: + cl_dbg(dev, cl, "rpm: autosuspend\n"); + pm_runtime_mark_last_busy(&dev->pdev->dev); + pm_runtime_put_autosuspend(&dev->pdev->dev); + + if (rets) + mei_io_cb_free(cb); + return rets; } @@ -776,7 +824,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, return rets; if (rets == 0) { - cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); + cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); return 0; } @@ -856,6 +904,12 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size); + rets = pm_runtime_get(&dev->pdev->dev); + if (rets < 0 && rets != -EINPROGRESS) { + pm_runtime_put_noidle(&dev->pdev->dev); + cl_err(dev, cl, "rpm: get failed %d\n", rets); + return rets; + } cb->fop_type = MEI_FOP_WRITE; cb->buf_idx = 0; @@ -926,6 +980,10 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) rets = buf->size; err: + cl_dbg(dev, cl, "rpm: autosuspend\n"); + pm_runtime_mark_last_busy(&dev->pdev->dev); + pm_runtime_put_autosuspend(&dev->pdev->dev); + return rets; } diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 4960288e543a26..b9a4bb5921f1b9 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -14,10 +14,12 @@ * */ +#include #include #include #include #include +#include #include "mei_dev.h" #include "hbm.h" @@ -289,6 +291,34 @@ static int mei_hbm_prop_req(struct mei_device *dev) return 0; } +/* + * mei_hbm_pg - sends pg command + * + * @dev: the device structure + * @pg_cmd: the pg command code + * + * This function returns -EIO on write failure + */ +int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd) +{ + struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; + struct hbm_power_gate *req; + const size_t len = sizeof(struct hbm_power_gate); + int ret; + + mei_hbm_hdr(mei_hdr, len); + + req = (struct hbm_power_gate *)dev->wr_msg.data; + memset(req, 0, len); + req->hbm_cmd = pg_cmd; + + ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); + if (ret) + dev_err(&dev->pdev->dev, "power gate command write failed.\n"); + return ret; +} +EXPORT_SYMBOL_GPL(mei_hbm_pg); + /** * mei_hbm_stop_req - send stop request message * @@ -701,6 +731,27 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) mei_hbm_cl_flow_control_res(dev, flow_control); break; + case MEI_PG_ISOLATION_ENTRY_RES_CMD: + dev_dbg(&dev->pdev->dev, "power gate isolation entry response received\n"); + dev->pg_event = MEI_PG_EVENT_RECEIVED; + if (waitqueue_active(&dev->wait_pg)) + wake_up(&dev->wait_pg); + break; + + case MEI_PG_ISOLATION_EXIT_REQ_CMD: + dev_dbg(&dev->pdev->dev, "power gate isolation exit request received\n"); + dev->pg_event = MEI_PG_EVENT_RECEIVED; + if (waitqueue_active(&dev->wait_pg)) + wake_up(&dev->wait_pg); + else + /* + * If the driver is not waiting on this then + * this is HW initiated exit from PG. + * Start runtime pm resume sequence to exit from PG. + */ + pm_request_resume(&dev->pdev->dev); + break; + case HOST_CLIENT_PROPERTIES_RES_CMD: dev_dbg(&dev->pdev->dev, "hbm: properties response: message received.\n"); diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h index 20e8782711c0c5..8e39cee408d016 100644 --- a/drivers/misc/mei/hbm.h +++ b/drivers/misc/mei/hbm.h @@ -57,6 +57,7 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl); int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl); int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl); bool mei_hbm_version_is_supported(struct mei_device *dev); +int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd); #endif /* _MEI_HBM_H_ */ diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index cabc04383685d4..a7856c0ac5761f 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -133,6 +133,8 @@ #define ME_CB_RW 8 /* ME_CSR_HA - ME Control Status Host Access register (read only) */ #define ME_CSR_HA 0xC +/* H_HGC_CSR - PGI register */ +#define H_HPG_CSR 0x10 /* register bits of H_CSR (Host Control Status register) */ @@ -162,6 +164,8 @@ access to ME_CBD */ #define ME_CBWP_HRA 0x00FF0000 /* ME CB Read Pointer HRA - host read only access to ME_CBRP */ #define ME_CBRP_HRA 0x0000FF00 +/* ME Power Gate Isolation Capability HRA - host ready only access */ +#define ME_PGIC_HRA 0x00000040 /* ME Reset HRA - host read only access to ME_RST */ #define ME_RST_HRA 0x00000010 /* ME Ready HRA - host read only access to ME_RDY */ @@ -173,4 +177,9 @@ access to ME_CBD */ /* ME Interrupt Enable HRA - host read only access to ME_IE */ #define ME_IE_HRA 0x00000001 + +/* register bits - H_HPG_CSR */ +#define H_HPG_CSR_PGIHEXR 0x00000001 +#define H_HPG_CSR_PGI 0x00000002 + #endif /* _MEI_HW_MEI_REGS_H_ */ diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 8dbdaaef1af57d..a31bc4c36cca8f 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -109,10 +109,27 @@ static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr) */ static void mei_me_hw_config(struct mei_device *dev) { + struct mei_me_hw *hw = to_me_hw(dev); u32 hcsr = mei_hcsr_read(to_me_hw(dev)); /* Doesn't change in runtime */ dev->hbuf_depth = (hcsr & H_CBD) >> 24; + + hw->pg_state = MEI_PG_OFF; } + +/** + * mei_me_pg_state - translate internal pg state + * to the mei power gating state + * + * @hw - me hardware + * returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise + */ +static inline enum mei_pg_state mei_me_pg_state(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + return hw->pg_state; +} + /** * mei_clear_interrupts - clear and stop interrupts * @@ -430,6 +447,144 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer, return 0; } +/** + * mei_me_pg_enter - write pg enter register to mei device. + * + * @dev: the device structure + */ +static void mei_me_pg_enter(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + u32 reg = mei_me_reg_read(hw, H_HPG_CSR); + reg |= H_HPG_CSR_PGI; + mei_me_reg_write(hw, H_HPG_CSR, reg); +} + +/** + * mei_me_pg_enter - write pg enter register to mei device. + * + * @dev: the device structure + */ +static void mei_me_pg_exit(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + u32 reg = mei_me_reg_read(hw, H_HPG_CSR); + + WARN(!(reg & H_HPG_CSR_PGI), "PGI is not set\n"); + + reg |= H_HPG_CSR_PGIHEXR; + mei_me_reg_write(hw, H_HPG_CSR, reg); +} + +/** + * mei_me_pg_set_sync - perform pg entry procedure + * + * @dev: the device structure + * + * returns 0 on success an error code otherwise + */ +int mei_me_pg_set_sync(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + unsigned long timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT); + int ret; + + dev->pg_event = MEI_PG_EVENT_WAIT; + + ret = mei_hbm_pg(dev, MEI_PG_ISOLATION_ENTRY_REQ_CMD); + if (ret) + return ret; + + mutex_unlock(&dev->device_lock); + wait_event_timeout(dev->wait_pg, + dev->pg_event == MEI_PG_EVENT_RECEIVED, timeout); + mutex_lock(&dev->device_lock); + + if (dev->pg_event == MEI_PG_EVENT_RECEIVED) { + mei_me_pg_enter(dev); + ret = 0; + } else { + ret = -ETIME; + } + + dev->pg_event = MEI_PG_EVENT_IDLE; + hw->pg_state = MEI_PG_ON; + + return ret; +} + +/** + * mei_me_pg_unset_sync - perform pg exit procedure + * + * @dev: the device structure + * + * returns 0 on success an error code otherwise + */ +int mei_me_pg_unset_sync(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + unsigned long timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT); + int ret; + + if (dev->pg_event == MEI_PG_EVENT_RECEIVED) + goto reply; + + dev->pg_event = MEI_PG_EVENT_WAIT; + + mei_me_pg_exit(dev); + + mutex_unlock(&dev->device_lock); + wait_event_timeout(dev->wait_pg, + dev->pg_event == MEI_PG_EVENT_RECEIVED, timeout); + mutex_lock(&dev->device_lock); + +reply: + if (dev->pg_event == MEI_PG_EVENT_RECEIVED) + ret = mei_hbm_pg(dev, MEI_PG_ISOLATION_EXIT_RES_CMD); + else + ret = -ETIME; + + dev->pg_event = MEI_PG_EVENT_IDLE; + hw->pg_state = MEI_PG_OFF; + + return ret; +} + +/** + * mei_me_pg_is_enabled - detect if PG is supported by HW + * + * @dev: the device structure + * + * returns: true is pg supported, false otherwise + */ +static bool mei_me_pg_is_enabled(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + u32 reg = mei_me_reg_read(hw, ME_CSR_HA); + + if ((reg & ME_PGIC_HRA) == 0) + goto notsupported; + + if (dev->version.major_version < HBM_MAJOR_VERSION_PGI) + goto notsupported; + + if (dev->version.major_version == HBM_MAJOR_VERSION_PGI && + dev->version.minor_version < HBM_MINOR_VERSION_PGI) + goto notsupported; + + return true; + +notsupported: + dev_dbg(&dev->pdev->dev, "pg: not supported: HGP = %d hbm version %d.%d ?= %d.%d\n", + !!(reg & ME_PGIC_HRA), + dev->version.major_version, + dev->version.minor_version, + HBM_MAJOR_VERSION_PGI, + HBM_MINOR_VERSION_PGI); + + return false; +} + /** * mei_me_irq_quick_handler - The ISR of the MEI device * @@ -524,9 +679,15 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) dev->hbuf_is_ready = mei_hbuf_is_ready(dev); - rets = mei_irq_write_handler(dev, &complete_list); - - dev->hbuf_is_ready = mei_hbuf_is_ready(dev); + /* + * During PG handshake only allowed write is the replay to the + * PG exit message, so block calling write function + * if the pg state is not idle + */ + if (dev->pg_event == MEI_PG_EVENT_IDLE) { + rets = mei_irq_write_handler(dev, &complete_list); + dev->hbuf_is_ready = mei_hbuf_is_ready(dev); + } mei_irq_compl_handler(dev, &complete_list); @@ -535,8 +696,65 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) mutex_unlock(&dev->device_lock); return IRQ_HANDLED; } + +/** + * mei_me_fw_status - retrieve fw status from the pci config space + * + * @dev: the device structure + * @fw_status: fw status registers storage + * + * returns 0 on success an error code otherwise + */ +static int mei_me_fw_status(struct mei_device *dev, + struct mei_fw_status *fw_status) +{ + const u32 pci_cfg_reg[] = {PCI_CFG_HFS_1, PCI_CFG_HFS_2}; + int i; + + if (!fw_status) + return -EINVAL; + + switch (dev->pdev->device) { + case MEI_DEV_ID_IBXPK_1: + case MEI_DEV_ID_IBXPK_2: + case MEI_DEV_ID_CPT_1: + case MEI_DEV_ID_PBG_1: + case MEI_DEV_ID_PPT_1: + case MEI_DEV_ID_PPT_2: + case MEI_DEV_ID_PPT_3: + case MEI_DEV_ID_LPT_H: + case MEI_DEV_ID_LPT_W: + case MEI_DEV_ID_LPT_LP: + case MEI_DEV_ID_LPT_HR: + case MEI_DEV_ID_WPT_LP: + fw_status->count = 2; + break; + case MEI_DEV_ID_ICH10_1: + case MEI_DEV_ID_ICH10_2: + case MEI_DEV_ID_ICH10_3: + case MEI_DEV_ID_ICH10_4: + fw_status->count = 1; + break; + default: + fw_status->count = 0; + break; + } + + for (i = 0; i < fw_status->count && i < MEI_FW_STATUS_MAX; i++) { + int ret; + ret = pci_read_config_dword(dev->pdev, + pci_cfg_reg[i], &fw_status->status[i]); + if (ret) + return ret; + } + return 0; +} + static const struct mei_hw_ops mei_me_hw_ops = { + .pg_state = mei_me_pg_state, + + .fw_status = mei_me_fw_status, .host_is_ready = mei_me_host_is_ready, .hw_is_ready = mei_me_hw_is_ready, @@ -544,6 +762,8 @@ static const struct mei_hw_ops mei_me_hw_ops = { .hw_config = mei_me_hw_config, .hw_start = mei_me_hw_start, + .pg_is_enabled = mei_me_pg_is_enabled, + .intr_clear = mei_me_intr_clear, .intr_enable = mei_me_intr_enable, .intr_disable = mei_me_intr_disable, diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h index 893d5119fa9bb6..0a75ab85b3a2d9 100644 --- a/drivers/misc/mei/hw-me.h +++ b/drivers/misc/mei/hw-me.h @@ -24,6 +24,8 @@ #include "mei_dev.h" #include "client.h" +#define MEI_ME_RPM_TIMEOUT 500 /* ms */ + struct mei_me_hw { void __iomem *mem_addr; /* @@ -31,12 +33,16 @@ struct mei_me_hw { */ u32 host_hw_state; u32 me_hw_state; + enum mei_pg_state pg_state; }; #define to_me_hw(dev) (struct mei_me_hw *)((dev)->hw) struct mei_device *mei_me_dev_init(struct pci_dev *pdev); +int mei_me_pg_set_sync(struct mei_device *dev); +int mei_me_pg_unset_sync(struct mei_device *dev); + irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id); irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id); diff --git a/drivers/misc/mei/hw-txe-regs.h b/drivers/misc/mei/hw-txe-regs.h index 7283c24c1af19e..f19229c4e65586 100644 --- a/drivers/misc/mei/hw-txe-regs.h +++ b/drivers/misc/mei/hw-txe-regs.h @@ -89,7 +89,7 @@ enum { # define PCI_CFG_TXE_FW_STS0_ERR_CODE_MSK 0x0000F000 # define PCI_CFG_TXE_FW_STS0_OP_MODE_MSK 0x000F0000 # define PCI_CFG_TXE_FW_STS0_RST_CNT_MSK 0x00F00000 - +#define PCI_CFG_TXE_FW_STS1 0x48 #define IPC_BASE_ADDR 0x80400 /* SeC IPC Base Address */ diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c index f60182a52f964f..455a6a56b82b3b 100644 --- a/drivers/misc/mei/hw-txe.c +++ b/drivers/misc/mei/hw-txe.c @@ -158,7 +158,7 @@ static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req) dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n", hw->aliveness, req); if (do_req) { - hw->recvd_aliveness = false; + dev->pg_event = MEI_PG_EVENT_WAIT; mei_txe_br_reg_write(hw, SICR_HOST_ALIVENESS_REQ_REG, req); } return do_req; @@ -213,6 +213,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected) do { hw->aliveness = mei_txe_aliveness_get(dev); if (hw->aliveness == expected) { + dev->pg_event = MEI_PG_EVENT_IDLE; dev_dbg(&dev->pdev->dev, "aliveness settled after %d msecs\n", t); return t; @@ -223,6 +224,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected) t += MSEC_PER_SEC / 5; } while (t < SEC_ALIVENESS_WAIT_TIMEOUT); + dev->pg_event = MEI_PG_EVENT_IDLE; dev_err(&dev->pdev->dev, "aliveness timed out\n"); return -ETIME; } @@ -249,19 +251,22 @@ static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected) return 0; mutex_unlock(&dev->device_lock); - err = wait_event_timeout(hw->wait_aliveness, - hw->recvd_aliveness, timeout); + err = wait_event_timeout(hw->wait_aliveness_resp, + dev->pg_event == MEI_PG_EVENT_RECEIVED, timeout); mutex_lock(&dev->device_lock); hw->aliveness = mei_txe_aliveness_get(dev); ret = hw->aliveness == expected ? 0 : -ETIME; if (ret) - dev_err(&dev->pdev->dev, "aliveness timed out"); + dev_warn(&dev->pdev->dev, "aliveness timed out = %ld aliveness = %d event = %d\n", + err, hw->aliveness, dev->pg_event); else - dev_dbg(&dev->pdev->dev, "aliveness settled after %d msecs\n", - jiffies_to_msecs(timeout - err)); - hw->recvd_aliveness = false; + dev_dbg(&dev->pdev->dev, "aliveness settled after = %d msec aliveness = %d event = %d\n", + jiffies_to_msecs(timeout - err), + hw->aliveness, dev->pg_event); + + dev->pg_event = MEI_PG_EVENT_IDLE; return ret; } @@ -279,6 +284,32 @@ int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req) return 0; } +/** + * mei_txe_pg_is_enabled - detect if PG is supported by HW + * + * @dev: the device structure + * + * returns: true is pg supported, false otherwise + */ +static bool mei_txe_pg_is_enabled(struct mei_device *dev) +{ + return true; +} + +/** + * mei_txe_pg_state - translate aliveness register value + * to the mei power gating state + * + * @dev: the device structure + * + * returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise + */ +static inline enum mei_pg_state mei_txe_pg_state(struct mei_device *dev) +{ + struct mei_txe_hw *hw = to_txe_hw(dev); + return hw->aliveness ? MEI_PG_OFF : MEI_PG_ON; +} + /** * mei_txe_input_ready_interrupt_enable - sets the Input Ready Interrupt * @@ -589,7 +620,10 @@ static int mei_txe_write(struct mei_device *dev, mei_txe_input_ready_interrupt_enable(dev); if (!mei_txe_is_input_ready(dev)) { - dev_err(&dev->pdev->dev, "Input is not ready"); + struct mei_fw_status fw_status; + mei_fw_status(dev, &fw_status); + dev_err(&dev->pdev->dev, "Input is not ready " FW_STS_FMT "\n", + FW_STS_PRM(fw_status)); return -EAGAIN; } @@ -960,9 +994,9 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) /* Clear the interrupt cause */ dev_dbg(&dev->pdev->dev, "Aliveness Interrupt: Status: %d\n", hw->aliveness); - hw->recvd_aliveness = true; - if (waitqueue_active(&hw->wait_aliveness)) - wake_up(&hw->wait_aliveness); + dev->pg_event = MEI_PG_EVENT_RECEIVED; + if (waitqueue_active(&hw->wait_aliveness_resp)) + wake_up(&hw->wait_aliveness_resp); } @@ -1008,15 +1042,51 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) return IRQ_HANDLED; } + +/** + * mei_txe_fw_status - retrieve fw status from the pci config space + * + * @dev: the device structure + * @fw_status: fw status registers storage + * + * returns: 0 on success an error code otherwise + */ +static int mei_txe_fw_status(struct mei_device *dev, + struct mei_fw_status *fw_status) +{ + const u32 pci_cfg_reg[] = {PCI_CFG_TXE_FW_STS0, PCI_CFG_TXE_FW_STS1}; + int i; + + if (!fw_status) + return -EINVAL; + + fw_status->count = 2; + + for (i = 0; i < fw_status->count && i < MEI_FW_STATUS_MAX; i++) { + int ret; + ret = pci_read_config_dword(dev->pdev, + pci_cfg_reg[i], &fw_status->status[i]); + if (ret) + return ret; + } + + return 0; +} + static const struct mei_hw_ops mei_txe_hw_ops = { + .fw_status = mei_txe_fw_status, .host_is_ready = mei_txe_host_is_ready, + .pg_state = mei_txe_pg_state, + .hw_is_ready = mei_txe_hw_is_ready, .hw_reset = mei_txe_hw_reset, .hw_config = mei_txe_hw_config, .hw_start = mei_txe_hw_start, + .pg_is_enabled = mei_txe_pg_is_enabled, + .intr_clear = mei_txe_intr_clear, .intr_enable = mei_txe_intr_enable, .intr_disable = mei_txe_intr_disable, @@ -1055,7 +1125,7 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev) hw = to_txe_hw(dev); - init_waitqueue_head(&hw->wait_aliveness); + init_waitqueue_head(&hw->wait_aliveness_resp); dev->ops = &mei_txe_hw_ops; diff --git a/drivers/misc/mei/hw-txe.h b/drivers/misc/mei/hw-txe.h index 0812d98633a449..e8dd2d165c25c8 100644 --- a/drivers/misc/mei/hw-txe.h +++ b/drivers/misc/mei/hw-txe.h @@ -22,6 +22,8 @@ #include "hw.h" #include "hw-txe-regs.h" +#define MEI_TXI_RPM_TIMEOUT 500 /* ms */ + /* Flatten Hierarchy interrupt cause */ #define TXE_INTR_READINESS_BIT 0 /* HISR_INT_0_STS */ #define TXE_INTR_READINESS HISR_INT_0_STS @@ -35,12 +37,11 @@ /** * struct mei_txe_hw - txe hardware specifics * - * @mem_addr: SeC and BRIDGE bars - * @aliveness: aliveness (power gating) state of the hardware - * @readiness: readiness state of the hardware - * @wait_aliveness: aliveness wait queue - * @recvd_aliveness: aliveness interrupt was recived - * @intr_cause: translated interrupt cause + * @mem_addr: SeC and BRIDGE bars + * @aliveness: aliveness (power gating) state of the hardware + * @readiness: readiness state of the hardware + * @wait_aliveness_resp: aliveness wait queue + * @intr_cause: translated interrupt cause */ struct mei_txe_hw { void __iomem *mem_addr[NUM_OF_MEM_BARS]; @@ -48,8 +49,7 @@ struct mei_txe_hw { u32 readiness; u32 slots; - wait_queue_head_t wait_aliveness; - bool recvd_aliveness; + wait_queue_head_t wait_aliveness_resp; unsigned long intr_cause; }; diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 6b476ab49b2e0d..dd448e58cc874e 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -31,14 +31,21 @@ #define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */ #define MEI_IAMTHIF_READ_TIMER 10 /* HPS */ +#define MEI_PGI_TIMEOUT 1 /* PG Isolation time response 1 sec */ #define MEI_HBM_TIMEOUT 1 /* 1 second */ /* * MEI Version */ -#define HBM_MINOR_VERSION 0 +#define HBM_MINOR_VERSION 1 #define HBM_MAJOR_VERSION 1 +/* + * MEI version with PGI support + */ +#define HBM_MINOR_VERSION_PGI 1 +#define HBM_MAJOR_VERSION_PGI 1 + /* Host bus message command opcode */ #define MEI_HBM_CMD_OP_MSK 0x7f /* Host bus message command RESPONSE */ @@ -69,6 +76,11 @@ #define MEI_FLOW_CONTROL_CMD 0x08 +#define MEI_PG_ISOLATION_ENTRY_REQ_CMD 0x0a +#define MEI_PG_ISOLATION_ENTRY_RES_CMD 0x8a +#define MEI_PG_ISOLATION_EXIT_REQ_CMD 0x0b +#define MEI_PG_ISOLATION_EXIT_RES_CMD 0x8b + /* * MEI Stop Reason * used by hbm_host_stop_request.reason @@ -207,6 +219,17 @@ struct hbm_props_response { struct mei_client_properties client_properties; } __packed; +/** + * struct hbm_power_gate - power gate request/response + * + * @hbm_cmd - bus message command header + * @reserved[3] + */ +struct hbm_power_gate { + u8 hbm_cmd; + u8 reserved[3]; +} __packed; + /** * struct hbm_client_connect_request - connect/disconnect request * diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 4460975c0eefcc..b3f70eb17934b6 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -74,9 +74,13 @@ int mei_reset(struct mei_device *dev) if (state != MEI_DEV_INITIALIZING && state != MEI_DEV_DISABLED && state != MEI_DEV_POWER_DOWN && - state != MEI_DEV_POWER_UP) - dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", - mei_dev_state_str(state)); + state != MEI_DEV_POWER_UP) { + struct mei_fw_status fw_status; + mei_fw_status(dev, &fw_status); + dev_warn(&dev->pdev->dev, + "unexpected reset: dev_state = %s " FW_STS_FMT "\n", + mei_dev_state_str(state), FW_STS_PRM(fw_status)); + } /* we're already in reset, cancel the init timer * if the reset was called due the hbm protocol error @@ -303,7 +307,28 @@ void mei_stop(struct mei_device *dev) } EXPORT_SYMBOL_GPL(mei_stop); +/** + * mei_write_is_idle - check if the write queues are idle + * + * @dev: the device structure + * + * returns true of there is no pending write + */ +bool mei_write_is_idle(struct mei_device *dev) +{ + bool idle = (dev->dev_state == MEI_DEV_ENABLED && + list_empty(&dev->ctrl_wr_list.list) && + list_empty(&dev->write_list.list)); + dev_dbg(&dev->pdev->dev, "write pg: is idle[%d] state=%s ctrl=%d write=%d\n", + idle, + mei_dev_state_str(dev->dev_state), + list_empty(&dev->ctrl_wr_list.list), + list_empty(&dev->write_list.list)); + + return idle; +} +EXPORT_SYMBOL_GPL(mei_write_is_idle); void mei_device_init(struct mei_device *dev) { @@ -312,6 +337,7 @@ void mei_device_init(struct mei_device *dev) INIT_LIST_HEAD(&dev->device_list); mutex_init(&dev->device_lock); init_waitqueue_head(&dev->wait_hw_ready); + init_waitqueue_head(&dev->wait_pg); init_waitqueue_head(&dev->wait_recvd_msg); init_waitqueue_head(&dev->wait_stop_wd); dev->dev_state = MEI_DEV_INITIALIZING; @@ -340,6 +366,8 @@ void mei_device_init(struct mei_device *dev) * 0: Reserved for MEI Bus Message communications */ bitmap_set(dev->host_clients_map, 0, 1); + + dev->pg_event = MEI_PG_EVENT_IDLE; } EXPORT_SYMBOL_GPL(mei_device_init); diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 147413145c97d8..66f0a1a0645143 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -467,7 +467,6 @@ static int mei_ioctl_connect_client(struct file *file, } cl->me_client_id = dev->me_clients[i].client_id; - cl->state = MEI_FILE_CONNECTING; dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n", cl->me_client_id); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 94a516716d226b..1aaaf0b6681c08 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -153,6 +153,20 @@ struct mei_msg_data { unsigned char *data; }; +/* Maximum number of processed FW status registers */ +#define MEI_FW_STATUS_MAX 2 + +/* + * struct mei_fw_status - storage of FW status data + * + * @count - number of actually available elements in array + * @status - FW status registers + */ +struct mei_fw_status { + int count; + u32 status[MEI_FW_STATUS_MAX]; +}; + /** * struct mei_me_client - representation of me (fw) client * @@ -213,6 +227,7 @@ struct mei_cl { /** struct mei_hw_ops * + * @fw_status - read FW status from PCI config space * @host_is_ready - query for host readiness * @hw_is_ready - query if hw is ready @@ -220,6 +235,9 @@ struct mei_cl { * @hw_start - start hw after reset * @hw_config - configure hw + * @pg_state - power gating state of the device + * @pg_is_enabled - is power gating enabled + * @intr_clear - clear pending interrupts * @intr_enable - enable interrupts * @intr_disable - disable interrupts @@ -237,6 +255,8 @@ struct mei_cl { */ struct mei_hw_ops { + int (*fw_status)(struct mei_device *dev, + struct mei_fw_status *fw_status); bool (*host_is_ready)(struct mei_device *dev); bool (*hw_is_ready)(struct mei_device *dev); @@ -244,6 +264,9 @@ struct mei_hw_ops { int (*hw_start)(struct mei_device *dev); void (*hw_config)(struct mei_device *dev); + enum mei_pg_state (*pg_state)(struct mei_device *dev); + bool (*pg_is_enabled)(struct mei_device *dev); + void (*intr_clear)(struct mei_device *dev); void (*intr_enable)(struct mei_device *dev); void (*intr_disable)(struct mei_device *dev); @@ -331,11 +354,37 @@ struct mei_cl_device { void *priv_data; }; + + /** + * enum mei_pg_event - power gating transition events + * + * @MEI_PG_EVENT_IDLE: the driver is not in power gating transition + * @MEI_PG_EVENT_WAIT: the driver is waiting for a pg event to complete + * @MEI_PG_EVENT_RECEIVED: the driver received pg event + */ +enum mei_pg_event { + MEI_PG_EVENT_IDLE, + MEI_PG_EVENT_WAIT, + MEI_PG_EVENT_RECEIVED, +}; + +/** + * enum mei_pg_state - device internal power gating state + * + * @MEI_PG_OFF: device is not power gated - it is active + * @MEI_PG_ON: device is power gated - it is in lower power state + */ +enum mei_pg_state { + MEI_PG_OFF = 0, + MEI_PG_ON = 1, +}; + /** * struct mei_device - MEI private device struct * @reset_count - limits the number of consecutive resets * @hbm_state - state of host bus message protocol + * @pg_event - power gating event * @mem_addr - mem mapped base register address * @hbuf_depth - depth of hardware host/write buffer is slots @@ -371,6 +420,7 @@ struct mei_device { * waiting queue for receive message from FW */ wait_queue_head_t wait_hw_ready; + wait_queue_head_t wait_pg; wait_queue_head_t wait_recvd_msg; wait_queue_head_t wait_stop_wd; @@ -382,6 +432,14 @@ struct mei_device { enum mei_hbm_state hbm_state; u16 init_clients_timer; + /* + * Power Gating support + */ + enum mei_pg_event pg_event; +#ifdef CONFIG_PM_RUNTIME + struct dev_pm_domain pg_domain; +#endif /* CONFIG_PM_RUNTIME */ + unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */ u32 rd_msg_hdr; @@ -557,6 +615,17 @@ static inline void mei_hw_config(struct mei_device *dev) { dev->ops->hw_config(dev); } + +static inline enum mei_pg_state mei_pg_state(struct mei_device *dev) +{ + return dev->ops->pg_state(dev); +} + +static inline bool mei_pg_is_enabled(struct mei_device *dev) +{ + return dev->ops->pg_is_enabled(dev); +} + static inline int mei_hw_reset(struct mei_device *dev, bool enable) { return dev->ops->hw_reset(dev, enable); @@ -629,8 +698,21 @@ static inline int mei_count_full_read_slots(struct mei_device *dev) return dev->ops->rdbuf_full_slots(dev); } +static inline int mei_fw_status(struct mei_device *dev, + struct mei_fw_status *fw_status) +{ + return dev->ops->fw_status(dev, fw_status); +} + +#define FW_STS_FMT "%08X %08X" +#define FW_STS_PRM(fw_status) \ + (fw_status).count > 0 ? (fw_status).status[0] : 0xDEADBEEF, \ + (fw_status).count > 1 ? (fw_status).status[1] : 0xDEADBEEF + bool mei_hbuf_acquire(struct mei_device *dev); +bool mei_write_is_idle(struct mei_device *dev); + #if IS_ENABLED(CONFIG_DEBUG_FS) int mei_dbgfs_register(struct mei_device *dev, const char *name); void mei_dbgfs_deregister(struct mei_device *dev); diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 95889e2e31ffd1..88516b02c6855c 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -33,6 +33,8 @@ #include #include +#include + #include #include "mei_dev.h" @@ -85,6 +87,14 @@ static const struct pci_device_id mei_me_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, mei_me_pci_tbl); +#ifdef CONFIG_PM_RUNTIME +static inline void mei_me_set_pm_domain(struct mei_device *dev); +static inline void mei_me_unset_pm_domain(struct mei_device *dev); +#else +static inline void mei_me_set_pm_domain(struct mei_device *dev) {} +static inline void mei_me_unset_pm_domain(struct mei_device *dev) {} +#endif /* CONFIG_PM_RUNTIME */ + /** * mei_quirk_probe - probe for devices that doesn't valid ME interface * @@ -212,6 +222,9 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto release_irq; } + pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_ME_RPM_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + err = mei_register(dev); if (err) goto release_irq; @@ -220,6 +233,17 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) schedule_delayed_work(&dev->timer_work, HZ); + /* + * For not wake-able HW runtime pm framework + * can't be used on pci device level. + * Use domain runtime pm callbacks instead. + */ + if (!pci_dev_run_wake(pdev)) + mei_me_set_pm_domain(dev); + + if (mei_pg_is_enabled(dev)) + pm_runtime_put_noidle(&pdev->dev); + dev_dbg(&pdev->dev, "initialization successful.\n"); return 0; @@ -259,12 +283,18 @@ static void mei_me_remove(struct pci_dev *pdev) if (!dev) return; + if (mei_pg_is_enabled(dev)) + pm_runtime_get_noresume(&pdev->dev); + hw = to_me_hw(dev); dev_dbg(&pdev->dev, "stop\n"); mei_stop(dev); + if (!pci_dev_run_wake(pdev)) + mei_me_unset_pm_domain(dev); + /* disable interrupts */ mei_disable_interrupts(dev); @@ -343,12 +373,120 @@ static int mei_me_pci_resume(struct device *device) return 0; } +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM_RUNTIME +static int mei_me_pm_runtime_idle(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct mei_device *dev; + + dev_dbg(&pdev->dev, "rpm: me: runtime_idle\n"); + + dev = pci_get_drvdata(pdev); + if (!dev) + return -ENODEV; + if (mei_write_is_idle(dev)) + pm_schedule_suspend(device, MEI_ME_RPM_TIMEOUT * 2); + + return -EBUSY; +} + +static int mei_me_pm_runtime_suspend(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct mei_device *dev; + int ret; + + dev_dbg(&pdev->dev, "rpm: me: runtime suspend\n"); + + dev = pci_get_drvdata(pdev); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->device_lock); + + if (mei_write_is_idle(dev)) + ret = mei_me_pg_set_sync(dev); + else + ret = -EAGAIN; + + mutex_unlock(&dev->device_lock); + + dev_dbg(&pdev->dev, "rpm: me: runtime suspend ret=%d\n", ret); + + return ret; +} + +static int mei_me_pm_runtime_resume(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct mei_device *dev; + int ret; + + dev_dbg(&pdev->dev, "rpm: me: runtime resume\n"); + + dev = pci_get_drvdata(pdev); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->device_lock); + + ret = mei_me_pg_unset_sync(dev); + + mutex_unlock(&dev->device_lock); + + dev_dbg(&pdev->dev, "rpm: me: runtime resume ret = %d\n", ret); + + return ret; +} + +/** + * mei_me_set_pm_domain - fill and set pm domian stucture for device + * + * @dev: mei_device + */ +static inline void mei_me_set_pm_domain(struct mei_device *dev) +{ + struct pci_dev *pdev = dev->pdev; + + if (pdev->dev.bus && pdev->dev.bus->pm) { + dev->pg_domain.ops = *pdev->dev.bus->pm; + + dev->pg_domain.ops.runtime_suspend = mei_me_pm_runtime_suspend; + dev->pg_domain.ops.runtime_resume = mei_me_pm_runtime_resume; + dev->pg_domain.ops.runtime_idle = mei_me_pm_runtime_idle; + + pdev->dev.pm_domain = &dev->pg_domain; + } +} + +/** + * mei_me_unset_pm_domain - clean pm domian stucture for device + * + * @dev: mei_device + */ +static inline void mei_me_unset_pm_domain(struct mei_device *dev) +{ + /* stop using pm callbacks if any */ + dev->pdev->dev.pm_domain = NULL; +} +#endif /* CONFIG_PM_RUNTIME */ + +#ifdef CONFIG_PM +static const struct dev_pm_ops mei_me_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(mei_me_pci_suspend, + mei_me_pci_resume) + SET_RUNTIME_PM_OPS( + mei_me_pm_runtime_suspend, + mei_me_pm_runtime_resume, + mei_me_pm_runtime_idle) +}; -static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume); #define MEI_ME_PM_OPS (&mei_me_pm_ops) #else #define MEI_ME_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM */ /* * PCI driver structure */ diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c index ad3adb009a1e4c..2c3f5625a04e34 100644 --- a/drivers/misc/mei/pci-txe.c +++ b/drivers/misc/mei/pci-txe.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -40,6 +41,13 @@ static const struct pci_device_id mei_txe_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl); +#ifdef CONFIG_PM_RUNTIME +static inline void mei_txe_set_pm_domain(struct mei_device *dev); +static inline void mei_txe_unset_pm_domain(struct mei_device *dev); +#else +static inline void mei_txe_set_pm_domain(struct mei_device *dev) {} +static inline void mei_txe_unset_pm_domain(struct mei_device *dev) {} +#endif /* CONFIG_PM_RUNTIME */ static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw) { @@ -137,12 +145,25 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto release_irq; } + pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + err = mei_register(dev); if (err) goto release_irq; pci_set_drvdata(pdev, dev); + /* + * For not wake-able HW runtime pm framework + * can't be used on pci device level. + * Use domain runtime pm callbacks instead. + */ + if (!pci_dev_run_wake(pdev)) + mei_txe_set_pm_domain(dev); + + pm_runtime_put_noidle(&pdev->dev); + return 0; release_irq: @@ -187,10 +208,15 @@ static void mei_txe_remove(struct pci_dev *pdev) return; } + pm_runtime_get_noresume(&pdev->dev); + hw = to_txe_hw(dev); mei_stop(dev); + if (!pci_dev_run_wake(pdev)) + mei_txe_unset_pm_domain(dev); + /* disable interrupts */ mei_disable_interrupts(dev); free_irq(pdev->irq, dev); @@ -265,15 +291,131 @@ static int mei_txe_pci_resume(struct device *device) return err; } +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM_RUNTIME +static int mei_txe_pm_runtime_idle(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct mei_device *dev; + + dev_dbg(&pdev->dev, "rpm: txe: runtime_idle\n"); + + dev = pci_get_drvdata(pdev); + if (!dev) + return -ENODEV; + if (mei_write_is_idle(dev)) + pm_schedule_suspend(device, MEI_TXI_RPM_TIMEOUT * 2); + + return -EBUSY; +} +static int mei_txe_pm_runtime_suspend(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct mei_device *dev; + int ret; + + dev_dbg(&pdev->dev, "rpm: txe: runtime suspend\n"); + + dev = pci_get_drvdata(pdev); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->device_lock); + + if (mei_write_is_idle(dev)) + ret = mei_txe_aliveness_set_sync(dev, 0); + else + ret = -EAGAIN; + + /* + * If everything is okay we're about to enter PCI low + * power state (D3) therefor we need to disable the + * interrupts towards host. + * However if device is not wakeable we do not enter + * D-low state and we need to keep the interrupt kicking + */ + if (!ret && pci_dev_run_wake(pdev)) + mei_disable_interrupts(dev); + + dev_dbg(&pdev->dev, "rpm: txe: runtime suspend ret=%d\n", ret); + + mutex_unlock(&dev->device_lock); + return ret; +} + +static int mei_txe_pm_runtime_resume(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct mei_device *dev; + int ret; + + dev_dbg(&pdev->dev, "rpm: txe: runtime resume\n"); + + dev = pci_get_drvdata(pdev); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->device_lock); + + mei_enable_interrupts(dev); + + ret = mei_txe_aliveness_set_sync(dev, 1); + + mutex_unlock(&dev->device_lock); + + dev_dbg(&pdev->dev, "rpm: txe: runtime resume ret = %d\n", ret); + + return ret; +} + +/** + * mei_txe_set_pm_domain - fill and set pm domian stucture for device + * + * @dev: mei_device + */ +static inline void mei_txe_set_pm_domain(struct mei_device *dev) +{ + struct pci_dev *pdev = dev->pdev; + + if (pdev->dev.bus && pdev->dev.bus->pm) { + dev->pg_domain.ops = *pdev->dev.bus->pm; + + dev->pg_domain.ops.runtime_suspend = mei_txe_pm_runtime_suspend; + dev->pg_domain.ops.runtime_resume = mei_txe_pm_runtime_resume; + dev->pg_domain.ops.runtime_idle = mei_txe_pm_runtime_idle; + + pdev->dev.pm_domain = &dev->pg_domain; + } +} -static SIMPLE_DEV_PM_OPS(mei_txe_pm_ops, - mei_txe_pci_suspend, - mei_txe_pci_resume); +/** + * mei_txe_unset_pm_domain - clean pm domian stucture for device + * + * @dev: mei_device + */ +static inline void mei_txe_unset_pm_domain(struct mei_device *dev) +{ + /* stop using pm callbacks if any */ + dev->pdev->dev.pm_domain = NULL; +} +#endif /* CONFIG_PM_RUNTIME */ + +#ifdef CONFIG_PM +static const struct dev_pm_ops mei_txe_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(mei_txe_pci_suspend, + mei_txe_pci_resume) + SET_RUNTIME_PM_OPS( + mei_txe_pm_runtime_suspend, + mei_txe_pm_runtime_resume, + mei_txe_pm_runtime_idle) +}; #define MEI_TXE_PM_OPS (&mei_txe_pm_ops) #else #define MEI_TXE_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM */ + /* * PCI driver structure */ diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index ebf1cbc198fd34..a84a664dfccb28 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -84,8 +84,6 @@ int mei_wd_host_init(struct mei_device *dev) return ret; } - cl->state = MEI_FILE_CONNECTING; - ret = mei_cl_connect(cl, NULL); if (ret) { diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index 0535d1e0bc7879..104a05f6b7384f 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c @@ -6,7 +6,7 @@ * This file supports the user system call for file open, close, mmap, etc. * This also incudes the driver initialization code. * - * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2008-2014 Silicon Graphics, 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 @@ -58,6 +58,11 @@ static int max_user_cbrs, max_user_dsr_bytes; static struct miscdevice gru_miscdev; +static int gru_supported(void) +{ + return is_uv_system() && + (uv_hub_info->hub_revision < UV3_HUB_REVISION_BASE); +} /* * gru_vma_close @@ -518,7 +523,7 @@ static int __init gru_init(void) { int ret; - if (!is_uv_system() || (is_uvx_hub() && !is_uv2_hub())) + if (!gru_supported()) return 0; #if defined CONFIG_IA64 @@ -573,7 +578,7 @@ static int __init gru_init(void) static void __exit gru_exit(void) { - if (!is_uv_system()) + if (!gru_supported()) return; gru_teardown_tlb_irqs(); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index acbc3f2aaaf9e3..79ba3a5bbf17cf 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -800,6 +800,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) data->timeout_ns = limit_us * 1000; data->timeout_clks = 0; } + + /* assign limit value if invalid */ + if (timeout_us == 0) + data->timeout_ns = limit_us * 1000; } /* @@ -2403,6 +2407,11 @@ void mmc_rescan(struct work_struct *work) container_of(work, struct mmc_host, detect.work); int i; + if (host->trigger_card_event && host->ops->card_event) { + host->ops->card_event(host); + host->trigger_card_event = false; + } + if (host->rescan_disable) return; diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 54829c0ed0002f..509229b48b55c3 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data) case MMC_TIMING_UHS_DDR50: str = "sd uhs DDR50"; break; + case MMC_TIMING_MMC_DDR52: + str = "mmc DDR52"; + break; case MMC_TIMING_MMC_HS200: str = "mmc high-speed SDR200"; break; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 1ab5f3a0af5b73..fbcf93d8185857 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -694,18 +694,10 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_rel_sectors.attr, NULL, }; - -static struct attribute_group mmc_std_attr_group = { - .attrs = mmc_std_attrs, -}; - -static const struct attribute_group *mmc_attr_groups[] = { - &mmc_std_attr_group, - NULL, -}; +ATTRIBUTE_GROUPS(mmc_std); static struct device_type mmc_type = { - .groups = mmc_attr_groups, + .groups = mmc_std_groups, }; /* @@ -1264,7 +1256,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, goto err; } mmc_card_set_ddr_mode(card); - mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50); + mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52); mmc_set_bus_width(card->host, bus_width); } } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 2dd359d2242fa8..aef515755e5bf9 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -707,18 +707,10 @@ static struct attribute *sd_std_attrs[] = { &dev_attr_serial.attr, NULL, }; - -static struct attribute_group sd_std_attr_group = { - .attrs = sd_std_attrs, -}; - -static const struct attribute_group *sd_attr_groups[] = { - &sd_std_attr_group, - NULL, -}; +ATTRIBUTE_GROUPS(sd_std); struct device_type sd_type = { - .groups = sd_attr_groups, + .groups = sd_std_groups, }; /* diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 4d721c6e2af010..9933e426bc3696 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -943,40 +943,21 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host) */ static int mmc_sdio_suspend(struct mmc_host *host) { - int i, err = 0; - - for (i = 0; i < host->card->sdio_funcs; i++) { - struct sdio_func *func = host->card->sdio_func[i]; - if (func && sdio_func_present(func) && func->dev.driver) { - const struct dev_pm_ops *pmops = func->dev.driver->pm; - err = pmops->suspend(&func->dev); - if (err) - break; - } - } - while (err && --i >= 0) { - struct sdio_func *func = host->card->sdio_func[i]; - if (func && sdio_func_present(func) && func->dev.driver) { - const struct dev_pm_ops *pmops = func->dev.driver->pm; - pmops->resume(&func->dev); - } - } - - if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { + if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { mmc_claim_host(host); sdio_disable_wide(host->card); mmc_release_host(host); } - if (!err && !mmc_card_keep_power(host)) + if (!mmc_card_keep_power(host)) mmc_power_off(host); - return err; + return 0; } static int mmc_sdio_resume(struct mmc_host *host) { - int i, err = 0; + int err = 0; BUG_ON(!host); BUG_ON(!host->card); @@ -1019,24 +1000,6 @@ static int mmc_sdio_resume(struct mmc_host *host) wake_up_process(host->sdio_irq_thread); mmc_release_host(host); - /* - * If the card looked to be the same as before suspending, then - * we proceed to resume all card functions. If one of them returns - * an error then we simply return that error to the core and the - * card will be redetected as new. It is the responsibility of - * the function driver to perform further tests with the extra - * knowledge it has of the card to confirm the card is indeed the - * same as before suspending (same MAC address for network cards, - * etc.) and return an error otherwise. - */ - for (i = 0; !err && i < host->card->sdio_funcs; i++) { - struct sdio_func *func = host->card->sdio_func[i]; - if (func && sdio_func_present(func) && func->dev.driver) { - const struct dev_pm_ops *pmops = func->dev.driver->pm; - err = pmops->resume(&func->dev); - } - } - host->pm_flags &= ~MMC_PM_KEEP_POWER; return err; } diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 92d1ba8e8153ab..4fa8fef9147f75 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -197,20 +197,8 @@ static int sdio_bus_remove(struct device *dev) #ifdef CONFIG_PM -#ifdef CONFIG_PM_SLEEP -static int pm_no_operation(struct device *dev) -{ - /* - * Prevent the PM core from calling SDIO device drivers' suspend - * callback routines, which it is not supposed to do, by using this - * empty function as the bus type suspend callaback for SDIO. - */ - return 0; -} -#endif - static const struct dev_pm_ops sdio_bus_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation) + SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume) SET_RUNTIME_PM_OPS( pm_generic_runtime_suspend, pm_generic_runtime_resume, diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index f7650b899e3d42..5f89cb83d5f000 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -32,9 +32,7 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) /* Schedule a card detection after a debounce timeout */ struct mmc_host *host = dev_id; - if (host->ops->card_event) - host->ops->card_event(host); - + host->trigger_card_event = true; mmc_detect_change(host, msecs_to_jiffies(200)); return IRQ_HANDLED; diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 8aaf8c1f3f63a3..b675882307e4f8 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -694,3 +694,10 @@ config MMC_REALTEK_PCI help Say Y here to include driver code to support SD/MMC card interface of Realtek PCI-E card reader + +config MMC_REALTEK_USB + tristate "Realtek USB SD/MMC Card Interface Driver" + depends on MFD_RTSX_USB + help + Say Y here to include driver code to support SD/MMC card interface + of Realtek RTS5129/39 series card reader diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 0c8aa5e1e304b5..3eb48b656f2514 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_MMC_USHC) += ushc.o obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o +obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 3423c5ed50c7a0..0fbc53ac7eae8f 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -187,7 +187,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) unsigned long actual; u8 div = priv->ciu_div + 1; - if (ios->timing == MMC_TIMING_UHS_DDR50) { + if (ios->timing == MMC_TIMING_MMC_DDR52) { mci_writel(host, CLKSEL, priv->ddr_timing); /* Should be double rate for DDR mode */ if (ios->bus_width == MMC_BUS_WIDTH_8) @@ -386,8 +386,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode, /* Common capabilities of Exynos4/Exynos5 SoC */ static unsigned long exynos_dwmmc_caps[4] = { - MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR | - MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, + MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, MMC_CAP_CMD23, MMC_CAP_CMD23, MMC_CAP_CMD23, @@ -426,7 +425,7 @@ static int dw_mci_exynos_probe(struct platform_device *pdev) return dw_mci_pltfm_register(pdev, drv_data); } -const struct dev_pm_ops dw_mci_exynos_pmops = { +static const struct dev_pm_ops dw_mci_exynos_pmops = { SET_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend, dw_mci_exynos_resume) .resume_noirq = dw_mci_exynos_resume_noirq, .thaw_noirq = dw_mci_exynos_resume_noirq, diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index cced599d5aebe2..d40991299218ba 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -235,12 +235,6 @@ static void dw_mci_init_debugfs(struct dw_mci_slot *slot) } #endif /* defined(CONFIG_DEBUG_FS) */ -static void dw_mci_set_timeout(struct dw_mci *host) -{ - /* timeout (maximum) */ - mci_writel(host, TMOUT, 0xffffffff); -} - static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) { struct mmc_data *data; @@ -257,9 +251,8 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) (cmd->opcode == SD_IO_RW_DIRECT && ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT)) cmdr |= SDMMC_CMD_STOP; - else - if (cmd->opcode != MMC_SEND_STATUS && cmd->data) - cmdr |= SDMMC_CMD_PRV_DAT_WAIT; + else if (cmd->opcode != MMC_SEND_STATUS && cmd->data) + cmdr |= SDMMC_CMD_PRV_DAT_WAIT; if (cmd->flags & MMC_RSP_PRESENT) { /* We expect a response, so set this bit */ @@ -850,8 +843,6 @@ static void __dw_mci_start_request(struct dw_mci *host, u32 cmdflags; mrq = slot->mrq; - if (host->pdata->select_slot) - host->pdata->select_slot(slot->id); host->cur_slot = slot; host->mrq = mrq; @@ -864,7 +855,7 @@ static void __dw_mci_start_request(struct dw_mci *host, data = cmd->data; if (data) { - dw_mci_set_timeout(host); + mci_writel(host, TMOUT, 0xFFFFFFFF); mci_writel(host, BYTCNT, data->blksz*data->blocks); mci_writel(host, BLKSIZ, data->blksz); } @@ -962,7 +953,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) regs = mci_readl(slot->host, UHS_REG); /* DDR mode set */ - if (ios->timing == MMC_TIMING_UHS_DDR50) + if (ios->timing == MMC_TIMING_MMC_DDR52) regs |= ((0x1 << slot->id) << 16); else regs &= ~((0x1 << slot->id) << 16); @@ -985,17 +976,11 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_UP: set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); - /* Power up slot */ - if (slot->host->pdata->setpower) - slot->host->pdata->setpower(slot->id, mmc->ocr_avail); regs = mci_readl(slot->host, PWREN); regs |= (1 << slot->id); mci_writel(slot->host, PWREN, regs); break; case MMC_POWER_OFF: - /* Power down slot */ - if (slot->host->pdata->setpower) - slot->host->pdata->setpower(slot->id, 0); regs = mci_readl(slot->host, PWREN); regs &= ~(1 << slot->id); mci_writel(slot->host, PWREN, regs); @@ -1009,15 +994,13 @@ static int dw_mci_get_ro(struct mmc_host *mmc) { int read_only; struct dw_mci_slot *slot = mmc_priv(mmc); - struct dw_mci_board *brd = slot->host->pdata; + int gpio_ro = mmc_gpio_get_ro(mmc); /* Use platform get_ro function, else try on board write protect */ if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT) read_only = 0; - else if (brd->get_ro) - read_only = brd->get_ro(slot->id); - else if (gpio_is_valid(slot->wp_gpio)) - read_only = gpio_get_value(slot->wp_gpio); + else if (!IS_ERR_VALUE(gpio_ro)) + read_only = gpio_ro; else read_only = mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; @@ -1039,8 +1022,6 @@ static int dw_mci_get_cd(struct mmc_host *mmc) /* Use platform get_cd function, else try onboard card detect */ if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) present = 1; - else if (brd->get_cd) - present = !brd->get_cd(slot->id); else if (!IS_ERR_VALUE(gpio_cd)) present = gpio_cd; else @@ -2045,86 +2026,15 @@ static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) return quirks; } - -/* find out bus-width for a given slot */ -static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot) -{ - struct device_node *np = dw_mci_of_find_slot_node(dev, slot); - u32 bus_wd = 1; - - if (!np) - return 1; - - if (of_property_read_u32(np, "bus-width", &bus_wd)) - dev_err(dev, "bus-width property not found, assuming width" - " as 1\n"); - return bus_wd; -} - -/* find the write protect gpio for a given slot; or -1 if none specified */ -static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot) -{ - struct device_node *np = dw_mci_of_find_slot_node(dev, slot); - int gpio; - - if (!np) - return -EINVAL; - - gpio = of_get_named_gpio(np, "wp-gpios", 0); - - /* Having a missing entry is valid; return silently */ - if (!gpio_is_valid(gpio)) - return -EINVAL; - - if (devm_gpio_request(dev, gpio, "dw-mci-wp")) { - dev_warn(dev, "gpio [%d] request failed\n", gpio); - return -EINVAL; - } - - return gpio; -} - -/* find the cd gpio for a given slot */ -static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot, - struct mmc_host *mmc) -{ - struct device_node *np = dw_mci_of_find_slot_node(dev, slot); - int gpio; - - if (!np) - return; - - gpio = of_get_named_gpio(np, "cd-gpios", 0); - - /* Having a missing entry is valid; return silently */ - if (!gpio_is_valid(gpio)) - return; - - if (mmc_gpio_request_cd(mmc, gpio, 0)) - dev_warn(dev, "gpio [%d] request failed\n", gpio); -} #else /* CONFIG_OF */ static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) { return 0; } -static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot) -{ - return 1; -} static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) { return NULL; } -static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot) -{ - return -EINVAL; -} -static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot, - struct mmc_host *mmc) -{ - return; -} #endif /* CONFIG_OF */ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) @@ -2134,7 +2044,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) const struct dw_mci_drv_data *drv_data = host->drv_data; int ctrl_id, ret; u32 freq[2]; - u8 bus_width; mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); if (!mmc) @@ -2158,17 +2067,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) mmc->f_max = freq[1]; } - if (host->pdata->get_ocr) - mmc->ocr_avail = host->pdata->get_ocr(id); - else - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - - /* - * Start with slot power disabled, it will be enabled when a card - * is detected. - */ - if (host->pdata->setpower) - host->pdata->setpower(id, 0); + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; if (host->pdata->caps) mmc->caps = host->pdata->caps; @@ -2189,19 +2088,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) if (host->pdata->caps2) mmc->caps2 = host->pdata->caps2; - if (host->pdata->get_bus_wd) - bus_width = host->pdata->get_bus_wd(slot->id); - else if (host->dev->of_node) - bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id); - else - bus_width = 1; - - switch (bus_width) { - case 8: - mmc->caps |= MMC_CAP_8_BIT_DATA; - case 4: - mmc->caps |= MMC_CAP_4_BIT_DATA; - } + mmc_of_parse(mmc); if (host->pdata->blk_settings) { mmc->max_segs = host->pdata->blk_settings->max_segs; @@ -2226,8 +2113,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) #endif /* CONFIG_MMC_DW_IDMAC */ } - slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id); - dw_mci_of_get_cd_gpio(host->dev, slot->id, mmc); + if (dw_mci_get_cd(mmc)) + set_bit(DW_MMC_CARD_PRESENT, &slot->flags); + else + clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); ret = mmc_add_host(mmc); if (ret) @@ -2249,10 +2138,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) { - /* Shutdown detect IRQ */ - if (slot->host->pdata->exit) - slot->host->pdata->exit(id); - /* Debugfs stuff is cleaned up by mmc core */ mmc_remove_host(slot->mmc); slot->host->slot[id] = NULL; @@ -2399,24 +2284,9 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) return ERR_PTR(ret); } - if (of_find_property(np, "keep-power-in-suspend", NULL)) - pdata->pm_caps |= MMC_PM_KEEP_POWER; - - if (of_find_property(np, "enable-sdio-wakeup", NULL)) - pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; - if (of_find_property(np, "supports-highspeed", NULL)) pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; - if (of_find_property(np, "caps2-mmc-hs200-1_8v", NULL)) - pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR; - - if (of_find_property(np, "caps2-mmc-hs200-1_2v", NULL)) - pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR; - - if (of_get_property(np, "cd-inverted", NULL)) - pdata->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; - return pdata; } @@ -2442,9 +2312,9 @@ int dw_mci_probe(struct dw_mci *host) } } - if (!host->pdata->select_slot && host->pdata->num_slots > 1) { + if (host->pdata->num_slots > 1) { dev_err(host->dev, - "Platform data must supply select_slot function\n"); + "Platform data must supply num_slots.\n"); return -ENODEV; } @@ -2474,12 +2344,19 @@ int dw_mci_probe(struct dw_mci *host) ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz); if (ret) dev_warn(host->dev, - "Unable to set bus rate to %ul\n", + "Unable to set bus rate to %uHz\n", host->pdata->bus_hz); } host->bus_hz = clk_get_rate(host->ciu_clk); } + if (!host->bus_hz) { + dev_err(host->dev, + "Platform data must supply bus speed\n"); + ret = -ENODEV; + goto err_clk_ciu; + } + if (drv_data && drv_data->init) { ret = drv_data->init(host); if (ret) { @@ -2516,13 +2393,6 @@ int dw_mci_probe(struct dw_mci *host) } } - if (!host->bus_hz) { - dev_err(host->dev, - "Platform data must supply bus speed\n"); - ret = -ENODEV; - goto err_regulator; - } - host->quirks = host->pdata->quirks; spin_lock_init(&host->lock); @@ -2666,8 +2536,6 @@ int dw_mci_probe(struct dw_mci *host) err_dmaunmap: if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); - -err_regulator: if (host->vmmc) regulator_disable(host->vmmc); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 68349779c39614..738fa241d05882 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -195,7 +195,6 @@ extern int dw_mci_resume(struct dw_mci *host); * @mmc: The mmc_host representing this slot. * @host: The MMC controller this slot is using. * @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX) - * @wp_gpio: If gpio_is_valid() we'll use this to read write protect. * @ctype: Card type for this slot. * @mrq: mmc_request currently being processed or waiting to be * processed, or NULL when the slot is idle. @@ -214,7 +213,6 @@ struct dw_mci_slot { struct dw_mci *host; int quirks; - int wp_gpio; u32 ctype; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 771c60ab4a320a..7e853932393bf0 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -299,7 +299,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) clk |= MCI_ST_8BIT_BUS; - if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50) + if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 || + host->mmc->ios.timing == MMC_TIMING_MMC_DDR52) clk |= MCI_ST_UX500_NEG_EDGE; mmci_write_clkreg(host, clk); @@ -784,7 +785,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) mmci_write_clkreg(host, clk); } - if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50) + if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 || + host->mmc->ios.timing == MMC_TIMING_MMC_DDR52) datactrl |= MCI_ST_DPSM_DDRMODE; /* diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index f7199c83f5cf8e..86401c09e35723 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -124,9 +124,8 @@ enum mxcmci_type { struct mxcmci_host { struct mmc_host *mmc; - struct resource *res; void __iomem *base; - int irq; + dma_addr_t phys_base; int detect_irq; struct dma_chan *dma; struct dma_async_tx_descriptor *desc; @@ -241,33 +240,26 @@ static inline void mxcmci_writew(struct mxcmci_host *host, u16 val, int reg) static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); -static inline void mxcmci_init_ocr(struct mxcmci_host *host) +static void mxcmci_init_ocr(struct mxcmci_host *host) { - host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); - + host->vcc = devm_regulator_get(mmc_dev(host->mmc), "vmmc"); if (IS_ERR(host->vcc)) { - host->vcc = NULL; + if (host->pdata && host->pdata->ocr_avail) + host->mmc->ocr_avail = host->pdata->ocr_avail; + else + host->mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; } else { host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc); if (host->pdata && host->pdata->ocr_avail) dev_warn(mmc_dev(host->mmc), "pdata->ocr_avail will not be used\n"); } - - if (host->vcc == NULL) { - /* fall-back to platform data */ - if (host->pdata && host->pdata->ocr_avail) - host->mmc->ocr_avail = host->pdata->ocr_avail; - else - host->mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - } } -static inline void mxcmci_set_power(struct mxcmci_host *host, - unsigned char power_mode, - unsigned int vdd) +static void mxcmci_set_power(struct mxcmci_host *host, unsigned char power_mode, + unsigned int vdd) { - if (host->vcc) { + if (!IS_ERR(host->vcc)) { if (power_mode == MMC_POWER_UP) mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); else if (power_mode == MMC_POWER_OFF) @@ -299,7 +291,6 @@ static void mxcmci_softreset(struct mxcmci_host *host) mxcmci_writew(host, 0xff, MMC_REG_RES_TO); } -static int mxcmci_setup_dma(struct mmc_host *mmc); #if IS_ENABLED(CONFIG_PPC_MPC512x) static inline void buffer_swap32(u32 *buf, int len) @@ -868,8 +859,8 @@ static int mxcmci_setup_dma(struct mmc_host *mmc) struct mxcmci_host *host = mmc_priv(mmc); struct dma_slave_config *config = &host->dma_slave_config; - config->dst_addr = host->res->start + MMC_REG_BUFFER_ACCESS; - config->src_addr = host->res->start + MMC_REG_BUFFER_ACCESS; + config->dst_addr = host->phys_base + MMC_REG_BUFFER_ACCESS; + config->src_addr = host->phys_base + MMC_REG_BUFFER_ACCESS; config->dst_addr_width = 4; config->src_addr_width = 4; config->dst_maxburst = host->burstlen; @@ -1040,8 +1031,8 @@ static const struct mmc_host_ops mxcmci_ops = { static int mxcmci_probe(struct platform_device *pdev) { struct mmc_host *mmc; - struct mxcmci_host *host = NULL; - struct resource *iores, *r; + struct mxcmci_host *host; + struct resource *res; int ret = 0, irq; bool dat3_card_detect = false; dma_cap_mask_t mask; @@ -1052,21 +1043,25 @@ static int mxcmci_probe(struct platform_device *pdev) of_id = of_match_device(mxcmci_of_match, &pdev->dev); - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); - if (!iores || irq < 0) + if (irq < 0) return -EINVAL; - r = request_mem_region(iores->start, resource_size(iores), pdev->name); - if (!r) - return -EBUSY; + mmc = mmc_alloc_host(sizeof(*host), &pdev->dev); + if (!mmc) + return -ENOMEM; + + host = mmc_priv(mmc); - mmc = mmc_alloc_host(sizeof(struct mxcmci_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out_release_mem; + host->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(host->base)) { + ret = PTR_ERR(host->base); + goto out_free; } + host->phys_base = res->start; + ret = mmc_of_parse(mmc); if (ret) goto out_free; @@ -1084,13 +1079,6 @@ static int mxcmci_probe(struct platform_device *pdev) mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_seg_size = mmc->max_req_size; - host = mmc_priv(mmc); - host->base = ioremap(r->start, resource_size(r)); - if (!host->base) { - ret = -ENOMEM; - goto out_free; - } - if (of_id) { const struct platform_device_id *id_entry = of_id->data; host->devtype = id_entry->driver_data; @@ -1120,19 +1108,16 @@ static int mxcmci_probe(struct platform_device *pdev) else host->default_irq_mask = 0; - host->res = r; - host->irq = irq; - host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(host->clk_ipg)) { ret = PTR_ERR(host->clk_ipg); - goto out_iounmap; + goto out_free; } host->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(host->clk_per)) { ret = PTR_ERR(host->clk_per); - goto out_iounmap; + goto out_free; } clk_prepare_enable(host->clk_per); @@ -1159,9 +1144,9 @@ static int mxcmci_probe(struct platform_device *pdev) if (!host->pdata) { host->dma = dma_request_slave_channel(&pdev->dev, "rx-tx"); } else { - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (r) { - host->dmareq = r->start; + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (res) { + host->dmareq = res->start; host->dma_data.peripheral_type = IMX_DMATYPE_SDHC; host->dma_data.priority = DMA_PRIO_LOW; host->dma_data.dma_request = host->dmareq; @@ -1178,7 +1163,8 @@ static int mxcmci_probe(struct platform_device *pdev) INIT_WORK(&host->datawork, mxcmci_datawork); - ret = request_irq(host->irq, mxcmci_irq, 0, DRIVER_NAME, host); + ret = devm_request_irq(&pdev->dev, irq, mxcmci_irq, 0, + dev_name(&pdev->dev), host); if (ret) goto out_free_dma; @@ -1188,7 +1174,7 @@ static int mxcmci_probe(struct platform_device *pdev) ret = host->pdata->init(&pdev->dev, mxcmci_detect_irq, host->mmc); if (ret) - goto out_free_irq; + goto out_free_dma; } init_timer(&host->watchdog); @@ -1199,20 +1185,17 @@ static int mxcmci_probe(struct platform_device *pdev) return 0; -out_free_irq: - free_irq(host->irq, host); out_free_dma: if (host->dma) dma_release_channel(host->dma); + out_clk_put: clk_disable_unprepare(host->clk_per); clk_disable_unprepare(host->clk_ipg); -out_iounmap: - iounmap(host->base); + out_free: mmc_free_host(mmc); -out_release_mem: - release_mem_region(iores->start, resource_size(iores)); + return ret; } @@ -1223,30 +1206,21 @@ static int mxcmci_remove(struct platform_device *pdev) mmc_remove_host(mmc); - if (host->vcc) - regulator_put(host->vcc); - if (host->pdata && host->pdata->exit) host->pdata->exit(&pdev->dev, mmc); - free_irq(host->irq, host); - iounmap(host->base); - if (host->dma) dma_release_channel(host->dma); clk_disable_unprepare(host->clk_per); clk_disable_unprepare(host->clk_ipg); - release_mem_region(host->res->start, resource_size(host->res)); - mmc_free_host(mmc); return 0; } -#ifdef CONFIG_PM -static int mxcmci_suspend(struct device *dev) +static int __maybe_unused mxcmci_suspend(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct mxcmci_host *host = mmc_priv(mmc); @@ -1256,7 +1230,7 @@ static int mxcmci_suspend(struct device *dev) return 0; } -static int mxcmci_resume(struct device *dev) +static int __maybe_unused mxcmci_resume(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct mxcmci_host *host = mmc_priv(mmc); @@ -1266,11 +1240,7 @@ static int mxcmci_resume(struct device *dev) return 0; } -static const struct dev_pm_ops mxcmci_pm_ops = { - .suspend = mxcmci_suspend, - .resume = mxcmci_resume, -}; -#endif +static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); static struct platform_driver mxcmci_driver = { .probe = mxcmci_probe, @@ -1279,9 +1249,7 @@ static struct platform_driver mxcmci_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &mxcmci_pm_ops, -#endif .of_match_table = mxcmci_of_match, } }; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index e91ee21549d03a..b4de63bf10fdfd 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -582,7 +582,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) * - MMC/SD clock coming out of controller > 25MHz */ if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) && - (ios->timing != MMC_TIMING_UHS_DDR50) && + (ios->timing != MMC_TIMING_MMC_DDR52) && ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) { regval = OMAP_HSMMC_READ(host->base, HCTL); if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000) @@ -602,7 +602,7 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host) u32 con; con = OMAP_HSMMC_READ(host->base, CON); - if (ios->timing == MMC_TIMING_UHS_DDR50) + if (ios->timing == MMC_TIMING_MMC_DDR52) con |= DDR; /* configure in DDR mode */ else con &= ~DDR; diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 0b9ded13a3ae89..b4a032b283b786 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -62,25 +62,24 @@ static inline void sd_clear_error(struct realtek_pci_sdmmc *host) } #ifdef DEBUG +static inline void sd_print_reg(struct realtek_pci_sdmmc *host, u16 reg) +{ + u8 val = 0; + + if (rtsx_pci_read_register(host->pcr, reg, &val) < 0) + dev_dbg(sdmmc_dev(host), "read 0x%04x failed\n", reg); + else + dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", reg, val); +} + static void sd_print_debug_regs(struct realtek_pci_sdmmc *host) { - struct rtsx_pcr *pcr = host->pcr; u16 i; - u8 *ptr; - /* Print SD host internal registers */ - rtsx_pci_init_cmd(pcr); for (i = 0xFDA0; i <= 0xFDAE; i++) - rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); + sd_print_reg(host, i); for (i = 0xFD52; i <= 0xFD69; i++) - rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); - rtsx_pci_send_cmd(pcr, 100); - - ptr = rtsx_pci_get_cmd_data(pcr); - for (i = 0xFDA0; i <= 0xFDAE; i++) - dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); - for (i = 0xFD52; i <= 0xFD69; i++) - dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); + sd_print_reg(host, i); } #else #define sd_print_debug_regs(host) @@ -236,6 +235,9 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, case MMC_RSP_R1: rsp_type = SD_RSP_TYPE_R1; break; + case MMC_RSP_R1 & ~MMC_RSP_CRC: + rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7; + break; case MMC_RSP_R1B: rsp_type = SD_RSP_TYPE_R1b; break; @@ -258,8 +260,11 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, if (cmd->opcode == SD_SWITCH_VOLTAGE) { err = rtsx_pci_write_register(pcr, SD_BUS_STAT, 0xFF, SD_CLK_TOGGLE_EN); - if (err < 0) + if (err < 0) { + rtsx_pci_write_register(pcr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); goto out; + } clock_toggled = true; } @@ -816,6 +821,7 @@ static int sd_set_timing(struct realtek_pci_sdmmc *host, unsigned char timing) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); break; + case MMC_TIMING_MMC_DDR52: case MMC_TIMING_UHS_DDR50: rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, 0x0C | SD_ASYNC_FIFO_NOT_RST, @@ -896,6 +902,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->vpclk = true; host->double_clk = false; break; + case MMC_TIMING_MMC_DDR52: case MMC_TIMING_UHS_DDR50: case MMC_TIMING_UHS_SDR25: host->ssc_depth = RTSX_SSC_DEPTH_1M; diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c new file mode 100644 index 00000000000000..e11fafa6fc6be8 --- /dev/null +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -0,0 +1,1455 @@ +/* Realtek USB SD/MMC Card Interface driver + * + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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 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, see . + * + * Author: + * Roger Tseng + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +#include +#include +#define RTSX_USB_USE_LEDS_CLASS +#endif + +struct rtsx_usb_sdmmc { + struct platform_device *pdev; + struct rtsx_ucr *ucr; + struct mmc_host *mmc; + struct mmc_request *mrq; + + struct mutex host_mutex; + + u8 ssc_depth; + unsigned int clock; + bool vpclk; + bool double_clk; + bool host_removal; + bool card_exist; + bool initial_mode; + bool ddr_mode; + + unsigned char power_mode; + +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) + struct led_classdev led; + char led_name[32]; + struct work_struct led_work; +#endif +}; + +static inline struct device *sdmmc_dev(struct rtsx_usb_sdmmc *host) +{ + return &(host->pdev->dev); +} + +static inline void sd_clear_error(struct rtsx_usb_sdmmc *host) +{ + struct rtsx_ucr *ucr = host->ucr; + rtsx_usb_ep0_write_register(ucr, CARD_STOP, + SD_STOP | SD_CLR_ERR, + SD_STOP | SD_CLR_ERR); + + rtsx_usb_clear_dma_err(ucr); + rtsx_usb_clear_fsm_err(ucr); +} + +#ifdef DEBUG +static void sd_print_debug_regs(struct rtsx_usb_sdmmc *host) +{ + struct rtsx_ucr *ucr = host->ucr; + u8 val = 0; + + rtsx_usb_ep0_read_register(ucr, SD_STAT1, &val); + dev_dbg(sdmmc_dev(host), "SD_STAT1: 0x%x\n", val); + rtsx_usb_ep0_read_register(ucr, SD_STAT2, &val); + dev_dbg(sdmmc_dev(host), "SD_STAT2: 0x%x\n", val); + rtsx_usb_ep0_read_register(ucr, SD_BUS_STAT, &val); + dev_dbg(sdmmc_dev(host), "SD_BUS_STAT: 0x%x\n", val); +} +#else +#define sd_print_debug_regs(host) +#endif /* DEBUG */ + +static int sd_read_data(struct rtsx_usb_sdmmc *host, struct mmc_command *cmd, + u16 byte_cnt, u8 *buf, int buf_len, int timeout) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + u8 trans_mode; + + if (!buf) + buf_len = 0; + + rtsx_usb_init_cmd(ucr); + if (cmd != NULL) { + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__ + , cmd->opcode); + if (cmd->opcode == MMC_SEND_TUNING_BLOCK) + trans_mode = SD_TM_AUTO_TUNING; + else + trans_mode = SD_TM_NORMAL_READ; + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD0, 0xFF, (u8)(cmd->opcode) | 0x40); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD1, 0xFF, (u8)(cmd->arg >> 24)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD2, 0xFF, (u8)(cmd->arg >> 16)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD3, 0xFF, (u8)(cmd->arg >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD4, 0xFF, (u8)cmd->arg); + } else { + trans_mode = SD_TM_AUTO_READ_3; + } + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H, + 0xFF, (u8)(byte_cnt >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, + SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); + if (trans_mode != SD_TM_AUTO_TUNING) + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, + 0xFF, trans_mode | SD_TRANSFER_START); + rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + if (cmd != NULL) { + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD1, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD2, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD3, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD4, 0, 0); + } + + err = rtsx_usb_send_cmd(ucr, MODE_CR, timeout); + if (err) { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_send_cmd failed (err = %d)\n", err); + return err; + } + + err = rtsx_usb_get_rsp(ucr, !cmd ? 1 : 5, timeout); + if (err || (ucr->rsp_buf[0] & SD_TRANSFER_ERR)) { + sd_print_debug_regs(host); + + if (!err) { + dev_dbg(sdmmc_dev(host), + "Transfer failed (SD_TRANSFER = %02x)\n", + ucr->rsp_buf[0]); + err = -EIO; + } else { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_get_rsp failed (err = %d)\n", err); + } + + return err; + } + + if (cmd != NULL) { + cmd->resp[0] = get_unaligned_be32(ucr->rsp_buf + 1); + dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n", + cmd->resp[0]); + } + + if (buf && buf_len) { + /* 2-byte aligned part */ + err = rtsx_usb_read_ppbuf(ucr, buf, byte_cnt - (byte_cnt % 2)); + if (err) { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_read_ppbuf failed (err = %d)\n", err); + return err; + } + + /* unaligned byte */ + if (byte_cnt % 2) + return rtsx_usb_read_register(ucr, + PPBUF_BASE2 + byte_cnt, + buf + byte_cnt - 1); + } + + return 0; +} + +static int sd_write_data(struct rtsx_usb_sdmmc *host, struct mmc_command *cmd, + u16 byte_cnt, u8 *buf, int buf_len, int timeout) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + u8 trans_mode; + + if (!buf) + buf_len = 0; + + if (buf && buf_len) { + err = rtsx_usb_write_ppbuf(ucr, buf, buf_len); + if (err) { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_write_ppbuf failed (err = %d)\n", + err); + return err; + } + } + + trans_mode = (cmd != NULL) ? SD_TM_AUTO_WRITE_2 : SD_TM_AUTO_WRITE_3; + rtsx_usb_init_cmd(ucr); + + if (cmd != NULL) { + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__, + cmd->opcode); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD0, 0xFF, (u8)(cmd->opcode) | 0x40); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD1, 0xFF, (u8)(cmd->arg >> 24)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD2, 0xFF, (u8)(cmd->arg >> 16)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD3, 0xFF, (u8)(cmd->arg >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD4, 0xFF, (u8)cmd->arg); + } + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H, + 0xFF, (u8)(byte_cnt >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, + SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, + trans_mode | SD_TRANSFER_START); + rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + if (cmd != NULL) { + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD1, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD2, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD3, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD4, 0, 0); + } + + err = rtsx_usb_send_cmd(ucr, MODE_CR, timeout); + if (err) { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_send_cmd failed (err = %d)\n", err); + return err; + } + + err = rtsx_usb_get_rsp(ucr, !cmd ? 1 : 5, timeout); + if (err) { + sd_print_debug_regs(host); + dev_dbg(sdmmc_dev(host), + "rtsx_usb_get_rsp failed (err = %d)\n", err); + return err; + } + + if (cmd != NULL) { + cmd->resp[0] = get_unaligned_be32(ucr->rsp_buf + 1); + dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n", + cmd->resp[0]); + } + + return 0; +} + +static void sd_send_cmd_get_rsp(struct rtsx_usb_sdmmc *host, + struct mmc_command *cmd) +{ + struct rtsx_ucr *ucr = host->ucr; + u8 cmd_idx = (u8)cmd->opcode; + u32 arg = cmd->arg; + int err = 0; + int timeout = 100; + int i; + u8 *ptr; + int stat_idx = 0; + int len = 2; + u8 rsp_type; + + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", + __func__, cmd_idx, arg); + + /* Response type: + * R0 + * R1, R5, R6, R7 + * R1b + * R2 + * R3, R4 + */ + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + rsp_type = SD_RSP_TYPE_R0; + break; + case MMC_RSP_R1: + rsp_type = SD_RSP_TYPE_R1; + break; + case MMC_RSP_R1 & ~MMC_RSP_CRC: + rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7; + break; + case MMC_RSP_R1B: + rsp_type = SD_RSP_TYPE_R1b; + break; + case MMC_RSP_R2: + rsp_type = SD_RSP_TYPE_R2; + break; + case MMC_RSP_R3: + rsp_type = SD_RSP_TYPE_R3; + break; + default: + dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n"); + err = -EINVAL; + goto out; + } + + if (rsp_type == SD_RSP_TYPE_R1b) + timeout = 3000; + + if (cmd->opcode == SD_SWITCH_VOLTAGE) { + err = rtsx_usb_write_register(ucr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, + SD_CLK_TOGGLE_EN); + if (err) + goto out; + } + + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, PINGPONG_BUFFER); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, + 0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START); + rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END | SD_STAT_IDLE, + SD_TRANSFER_END | SD_STAT_IDLE); + + if (rsp_type == SD_RSP_TYPE_R2) { + /* Read data from ping-pong buffer */ + for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++) + rtsx_usb_add_cmd(ucr, READ_REG_CMD, (u16)i, 0, 0); + stat_idx = 16; + } else if (rsp_type != SD_RSP_TYPE_R0) { + /* Read data from SD_CMDx registers */ + for (i = SD_CMD0; i <= SD_CMD4; i++) + rtsx_usb_add_cmd(ucr, READ_REG_CMD, (u16)i, 0, 0); + stat_idx = 5; + } + len += stat_idx; + + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_STAT1, 0, 0); + + err = rtsx_usb_send_cmd(ucr, MODE_CR, 100); + if (err) { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_send_cmd error (err = %d)\n", err); + goto out; + } + + err = rtsx_usb_get_rsp(ucr, len, timeout); + if (err || (ucr->rsp_buf[0] & SD_TRANSFER_ERR)) { + sd_print_debug_regs(host); + sd_clear_error(host); + + if (!err) { + dev_dbg(sdmmc_dev(host), + "Transfer failed (SD_TRANSFER = %02x)\n", + ucr->rsp_buf[0]); + err = -EIO; + } else { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_get_rsp failed (err = %d)\n", err); + } + + goto out; + } + + if (rsp_type == SD_RSP_TYPE_R0) { + err = 0; + goto out; + } + + /* Skip result of CHECK_REG_CMD */ + ptr = ucr->rsp_buf + 1; + + /* Check (Start,Transmission) bit of Response */ + if ((ptr[0] & 0xC0) != 0) { + err = -EILSEQ; + dev_dbg(sdmmc_dev(host), "Invalid response bit\n"); + goto out; + } + + /* Check CRC7 */ + if (!(rsp_type & SD_NO_CHECK_CRC7)) { + if (ptr[stat_idx] & SD_CRC7_ERR) { + err = -EILSEQ; + dev_dbg(sdmmc_dev(host), "CRC7 error\n"); + goto out; + } + } + + if (rsp_type == SD_RSP_TYPE_R2) { + for (i = 0; i < 4; i++) { + cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4); + dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n", + i, cmd->resp[i]); + } + } else { + cmd->resp[0] = get_unaligned_be32(ptr + 1); + dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n", + cmd->resp[0]); + } + +out: + cmd->error = err; +} + +static int sd_rw_multi(struct rtsx_usb_sdmmc *host, struct mmc_request *mrq) +{ + struct rtsx_ucr *ucr = host->ucr; + struct mmc_data *data = mrq->data; + int read = (data->flags & MMC_DATA_READ) ? 1 : 0; + u8 cfg2, trans_mode; + int err; + u8 flag; + size_t data_len = data->blksz * data->blocks; + unsigned int pipe; + + if (read) { + dev_dbg(sdmmc_dev(host), "%s: read %zu bytes\n", + __func__, data_len); + cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0; + trans_mode = SD_TM_AUTO_READ_3; + } else { + dev_dbg(sdmmc_dev(host), "%s: write %zu bytes\n", + __func__, data_len); + cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0; + trans_mode = SD_TM_AUTO_WRITE_3; + } + + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L, + 0xFF, (u8)data->blocks); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H, + 0xFF, (u8)(data->blocks >> 8)); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, RING_BUFFER); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC3, + 0xFF, (u8)(data_len >> 24)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC2, + 0xFF, (u8)(data_len >> 16)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC1, + 0xFF, (u8)(data_len >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC0, + 0xFF, (u8)data_len); + if (read) { + flag = MODE_CDIR; + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL, + 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_FROM_CARD | DMA_EN | DMA_512); + } else { + flag = MODE_CDOR; + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL, + 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_TO_CARD | DMA_EN | DMA_512); + } + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, cfg2); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, + trans_mode | SD_TRANSFER_START); + rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + err = rtsx_usb_send_cmd(ucr, flag, 100); + if (err) + return err; + + if (read) + pipe = usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN); + else + pipe = usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT); + + err = rtsx_usb_transfer_data(ucr, pipe, data->sg, data_len, + data->sg_len, NULL, 10000); + if (err) { + dev_dbg(sdmmc_dev(host), "rtsx_usb_transfer_data error %d\n" + , err); + sd_clear_error(host); + return err; + } + + return rtsx_usb_get_rsp(ucr, 1, 2000); +} + +static inline void sd_enable_initial_mode(struct rtsx_usb_sdmmc *host) +{ + rtsx_usb_write_register(host->ucr, SD_CFG1, + SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_128); +} + +static inline void sd_disable_initial_mode(struct rtsx_usb_sdmmc *host) +{ + rtsx_usb_write_register(host->ucr, SD_CFG1, + SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0); +} + +static void sd_normal_rw(struct rtsx_usb_sdmmc *host, + struct mmc_request *mrq) +{ + struct mmc_command *cmd = mrq->cmd; + struct mmc_data *data = mrq->data; + u8 *buf; + + buf = kzalloc(data->blksz, GFP_NOIO); + if (!buf) { + cmd->error = -ENOMEM; + return; + } + + if (data->flags & MMC_DATA_READ) { + if (host->initial_mode) + sd_disable_initial_mode(host); + + cmd->error = sd_read_data(host, cmd, (u16)data->blksz, buf, + data->blksz, 200); + + if (host->initial_mode) + sd_enable_initial_mode(host); + + sg_copy_from_buffer(data->sg, data->sg_len, buf, data->blksz); + } else { + sg_copy_to_buffer(data->sg, data->sg_len, buf, data->blksz); + + cmd->error = sd_write_data(host, cmd, (u16)data->blksz, buf, + data->blksz, 200); + } + + kfree(buf); +} + +static int sd_change_phase(struct rtsx_usb_sdmmc *host, u8 sample_point, int tx) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + + dev_dbg(sdmmc_dev(host), "%s: %s sample_point = %d\n", + __func__, tx ? "TX" : "RX", sample_point); + + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE); + + if (tx) + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL, + 0x0F, sample_point); + else + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK1_CTL, + 0x0F, sample_point); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL, + PHASE_NOT_RESET, PHASE_NOT_RESET); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, 0); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_RST, 0); + + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + if (err) + return err; + + return 0; +} + +static inline u32 get_phase_point(u32 phase_map, unsigned int idx) +{ + idx &= MAX_PHASE; + return phase_map & (1 << idx); +} + +static int get_phase_len(u32 phase_map, unsigned int idx) +{ + int i; + + for (i = 0; i < MAX_PHASE + 1; i++) { + if (get_phase_point(phase_map, idx + i) == 0) + return i; + } + return MAX_PHASE + 1; +} + +static u8 sd_search_final_phase(struct rtsx_usb_sdmmc *host, u32 phase_map) +{ + int start = 0, len = 0; + int start_final = 0, len_final = 0; + u8 final_phase = 0xFF; + + if (phase_map == 0) { + dev_dbg(sdmmc_dev(host), "Phase: [map:%x]\n", phase_map); + return final_phase; + } + + while (start < MAX_PHASE + 1) { + len = get_phase_len(phase_map, start); + if (len_final < len) { + start_final = start; + len_final = len; + } + start += len ? len : 1; + } + + final_phase = (start_final + len_final / 2) & MAX_PHASE; + dev_dbg(sdmmc_dev(host), "Phase: [map:%x] [maxlen:%d] [final:%d]\n", + phase_map, len_final, final_phase); + + return final_phase; +} + +static void sd_wait_data_idle(struct rtsx_usb_sdmmc *host) +{ + int err, i; + u8 val = 0; + + for (i = 0; i < 100; i++) { + err = rtsx_usb_ep0_read_register(host->ucr, + SD_DATA_STATE, &val); + if (val & SD_DATA_IDLE) + return; + + usleep_range(100, 1000); + } +} + +static int sd_tuning_rx_cmd(struct rtsx_usb_sdmmc *host, + u8 opcode, u8 sample_point) +{ + int err; + struct mmc_command cmd = {0}; + + err = sd_change_phase(host, sample_point, 0); + if (err) + return err; + + cmd.opcode = MMC_SEND_TUNING_BLOCK; + err = sd_read_data(host, &cmd, 0x40, NULL, 0, 100); + if (err) { + /* Wait till SD DATA IDLE */ + sd_wait_data_idle(host); + sd_clear_error(host); + return err; + } + + return 0; +} + +static void sd_tuning_phase(struct rtsx_usb_sdmmc *host, + u8 opcode, u16 *phase_map) +{ + int err, i; + u16 raw_phase_map = 0; + + for (i = MAX_PHASE; i >= 0; i--) { + err = sd_tuning_rx_cmd(host, opcode, (u8)i); + if (!err) + raw_phase_map |= 1 << i; + } + + if (phase_map) + *phase_map = raw_phase_map; +} + +static int sd_tuning_rx(struct rtsx_usb_sdmmc *host, u8 opcode) +{ + int err, i; + u16 raw_phase_map[RX_TUNING_CNT] = {0}, phase_map; + u8 final_phase; + + /* setting fixed default TX phase */ + err = sd_change_phase(host, 0x01, 1); + if (err) { + dev_dbg(sdmmc_dev(host), "TX phase setting failed\n"); + return err; + } + + /* tuning RX phase */ + for (i = 0; i < RX_TUNING_CNT; i++) { + sd_tuning_phase(host, opcode, &(raw_phase_map[i])); + + if (raw_phase_map[i] == 0) + break; + } + + phase_map = 0xFFFF; + for (i = 0; i < RX_TUNING_CNT; i++) { + dev_dbg(sdmmc_dev(host), "RX raw_phase_map[%d] = 0x%04x\n", + i, raw_phase_map[i]); + phase_map &= raw_phase_map[i]; + } + dev_dbg(sdmmc_dev(host), "RX phase_map = 0x%04x\n", phase_map); + + if (phase_map) { + final_phase = sd_search_final_phase(host, phase_map); + if (final_phase == 0xFF) + return -EINVAL; + + err = sd_change_phase(host, final_phase, 0); + if (err) + return err; + } else { + return -EINVAL; + } + + return 0; +} + +static int sdmmc_get_ro(struct mmc_host *mmc) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + int err; + u16 val; + + if (host->host_removal) + return -ENOMEDIUM; + + mutex_lock(&ucr->dev_mutex); + + /* Check SD card detect */ + err = rtsx_usb_get_card_status(ucr, &val); + + mutex_unlock(&ucr->dev_mutex); + + + /* Treat failed detection as non-ro */ + if (err) + return 0; + + if (val & SD_WP) + return 1; + + return 0; +} + +static int sdmmc_get_cd(struct mmc_host *mmc) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + int err; + u16 val; + + if (host->host_removal) + return -ENOMEDIUM; + + mutex_lock(&ucr->dev_mutex); + + /* Check SD card detect */ + err = rtsx_usb_get_card_status(ucr, &val); + + mutex_unlock(&ucr->dev_mutex); + + /* Treat failed detection as non-exist */ + if (err) + goto no_card; + + if (val & SD_CD) { + host->card_exist = true; + return 1; + } + +no_card: + host->card_exist = false; + return 0; +} + +static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + struct mmc_command *cmd = mrq->cmd; + struct mmc_data *data = mrq->data; + unsigned int data_size = 0; + + dev_dbg(sdmmc_dev(host), "%s\n", __func__); + + if (host->host_removal) { + cmd->error = -ENOMEDIUM; + goto finish; + } + + if ((!host->card_exist)) { + cmd->error = -ENOMEDIUM; + goto finish_detect_card; + } + + /* + * Reject SDIO CMDs to speed up card identification + * since unsupported + */ + if (cmd->opcode == SD_IO_SEND_OP_COND || + cmd->opcode == SD_IO_RW_DIRECT || + cmd->opcode == SD_IO_RW_EXTENDED) { + cmd->error = -EINVAL; + goto finish; + } + + mutex_lock(&ucr->dev_mutex); + + mutex_lock(&host->host_mutex); + host->mrq = mrq; + mutex_unlock(&host->host_mutex); + + if (mrq->data) + data_size = data->blocks * data->blksz; + + if (!data_size) { + sd_send_cmd_get_rsp(host, cmd); + } else if ((!(data_size % 512) && cmd->opcode != MMC_SEND_EXT_CSD) || + mmc_op_multi(cmd->opcode)) { + sd_send_cmd_get_rsp(host, cmd); + + if (!cmd->error) { + sd_rw_multi(host, mrq); + + if (mmc_op_multi(cmd->opcode) && mrq->stop) { + sd_send_cmd_get_rsp(host, mrq->stop); + rtsx_usb_write_register(ucr, MC_FIFO_CTL, + FIFO_FLUSH, FIFO_FLUSH); + } + } + } else { + sd_normal_rw(host, mrq); + } + + if (mrq->data) { + if (cmd->error || data->error) + data->bytes_xfered = 0; + else + data->bytes_xfered = data->blocks * data->blksz; + } + + mutex_unlock(&ucr->dev_mutex); + +finish_detect_card: + if (cmd->error) { + /* + * detect card when fail to update card existence state and + * speed up card removal when retry + */ + sdmmc_get_cd(mmc); + dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error); + } + +finish: + mutex_lock(&host->host_mutex); + host->mrq = NULL; + mutex_unlock(&host->host_mutex); + + mmc_request_done(mmc, mrq); +} + +static int sd_set_bus_width(struct rtsx_usb_sdmmc *host, + unsigned char bus_width) +{ + int err = 0; + u8 width[] = { + [MMC_BUS_WIDTH_1] = SD_BUS_WIDTH_1BIT, + [MMC_BUS_WIDTH_4] = SD_BUS_WIDTH_4BIT, + [MMC_BUS_WIDTH_8] = SD_BUS_WIDTH_8BIT, + }; + + if (bus_width <= MMC_BUS_WIDTH_8) + err = rtsx_usb_write_register(host->ucr, SD_CFG1, + 0x03, width[bus_width]); + + return err; +} + +static int sd_pull_ctl_disable_lqfp48(struct rtsx_ucr *ucr) +{ + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int sd_pull_ctl_disable_qfn24(struct rtsx_ucr *ucr) +{ + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x56); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int sd_pull_ctl_enable_lqfp48(struct rtsx_ucr *ucr) +{ + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0xAA); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0xAA); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0xA9); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int sd_pull_ctl_enable_qfn24(struct rtsx_ucr *ucr) +{ + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0xA5); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x9A); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0xA5); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x9A); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x65); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x5A); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int sd_power_on(struct rtsx_usb_sdmmc *host) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + + dev_dbg(sdmmc_dev(host), "%s\n", __func__); + rtsx_usb_init_cmd(ucr); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SHARE_MODE, + CARD_SHARE_MASK, CARD_SHARE_SD); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, + SD_CLK_EN, SD_CLK_EN); + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + if (err) + return err; + + if (CHECK_PKG(ucr, LQFP48)) + err = sd_pull_ctl_enable_lqfp48(ucr); + else + err = sd_pull_ctl_enable_qfn24(ucr); + if (err) + return err; + + err = rtsx_usb_write_register(ucr, CARD_PWR_CTL, + POWER_MASK, PARTIAL_POWER_ON); + if (err) + return err; + + usleep_range(800, 1000); + + rtsx_usb_init_cmd(ucr); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, + POWER_MASK|LDO3318_PWR_MASK, POWER_ON|LDO_ON); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, + SD_OUTPUT_EN, SD_OUTPUT_EN); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int sd_power_off(struct rtsx_usb_sdmmc *host) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + + dev_dbg(sdmmc_dev(host), "%s\n", __func__); + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, + POWER_MASK, POWER_OFF); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, + POWER_MASK|LDO3318_PWR_MASK, POWER_OFF|LDO_SUSPEND); + + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + if (err) + return err; + + if (CHECK_PKG(ucr, LQFP48)) + return sd_pull_ctl_disable_lqfp48(ucr); + return sd_pull_ctl_disable_qfn24(ucr); +} + +static int sd_set_power_mode(struct rtsx_usb_sdmmc *host, + unsigned char power_mode) +{ + int err; + + if (power_mode != MMC_POWER_OFF) + power_mode = MMC_POWER_ON; + + if (power_mode == host->power_mode) + return 0; + + if (power_mode == MMC_POWER_OFF) { + err = sd_power_off(host); + pm_runtime_put(sdmmc_dev(host)); + } else { + pm_runtime_get_sync(sdmmc_dev(host)); + err = sd_power_on(host); + } + + if (!err) + host->power_mode = power_mode; + + return err; +} + +static int sd_set_timing(struct rtsx_usb_sdmmc *host, + unsigned char timing, bool *ddr_mode) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + + *ddr_mode = false; + + rtsx_usb_init_cmd(ucr); + + switch (timing) { + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_UHS_SDR50: + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, + 0x0C | SD_ASYNC_FIFO_RST, + SD_30_MODE | SD_ASYNC_FIFO_RST); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1); + break; + + case MMC_TIMING_UHS_DDR50: + *ddr_mode = true; + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, + 0x0C | SD_ASYNC_FIFO_RST, + SD_DDR_MODE | SD_ASYNC_FIFO_RST); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PUSH_POINT_CTL, + DDR_VAR_TX_CMD_DAT, DDR_VAR_TX_CMD_DAT); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, + DDR_VAR_RX_DAT | DDR_VAR_RX_CMD, + DDR_VAR_RX_DAT | DDR_VAR_RX_CMD); + break; + + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, + 0x0C, SD_20_MODE); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PUSH_POINT_CTL, + SD20_TX_SEL_MASK, SD20_TX_14_AHEAD); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, + SD20_RX_SEL_MASK, SD20_RX_14_DELAY); + break; + + default: + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CFG1, 0x0C, SD_20_MODE); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_PUSH_POINT_CTL, 0xFF, 0); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, + SD20_RX_SEL_MASK, SD20_RX_POS_EDGE); + break; + } + + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + + return err; +} + +static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + + dev_dbg(sdmmc_dev(host), "%s\n", __func__); + mutex_lock(&ucr->dev_mutex); + + if (rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD)) { + mutex_unlock(&ucr->dev_mutex); + return; + } + + sd_set_power_mode(host, ios->power_mode); + sd_set_bus_width(host, ios->bus_width); + sd_set_timing(host, ios->timing, &host->ddr_mode); + + host->vpclk = false; + host->double_clk = true; + + switch (ios->timing) { + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_UHS_SDR50: + host->ssc_depth = SSC_DEPTH_2M; + host->vpclk = true; + host->double_clk = false; + break; + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_UHS_SDR25: + host->ssc_depth = SSC_DEPTH_1M; + break; + default: + host->ssc_depth = SSC_DEPTH_512K; + break; + } + + host->initial_mode = (ios->clock <= 1000000) ? true : false; + host->clock = ios->clock; + + rtsx_usb_switch_clock(host->ucr, host->clock, host->ssc_depth, + host->initial_mode, host->double_clk, host->vpclk); + + mutex_unlock(&ucr->dev_mutex); + dev_dbg(sdmmc_dev(host), "%s end\n", __func__); +} + +static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + int err = 0; + + dev_dbg(sdmmc_dev(host), "%s: signal_voltage = %d\n", + __func__, ios->signal_voltage); + + if (host->host_removal) + return -ENOMEDIUM; + + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) + return -EPERM; + + mutex_lock(&ucr->dev_mutex); + + err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD); + if (err) { + mutex_unlock(&ucr->dev_mutex); + return err; + } + + /* Let mmc core do the busy checking, simply stop the forced-toggle + * clock(while issuing CMD11) and switch voltage. + */ + rtsx_usb_init_cmd(ucr); + + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PAD_CTL, + SD_IO_USING_1V8, SD_IO_USING_3V3); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG, + TUNE_SD18_MASK, TUNE_SD18_3V3); + } else { + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, + SD_CLK_FORCE_STOP); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PAD_CTL, + SD_IO_USING_1V8, SD_IO_USING_1V8); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG, + TUNE_SD18_MASK, TUNE_SD18_1V8); + } + + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + mutex_unlock(&ucr->dev_mutex); + + return err; +} + +static int sdmmc_card_busy(struct mmc_host *mmc) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + int err; + u8 stat; + u8 mask = SD_DAT3_STATUS | SD_DAT2_STATUS | SD_DAT1_STATUS + | SD_DAT0_STATUS; + + dev_dbg(sdmmc_dev(host), "%s\n", __func__); + + mutex_lock(&ucr->dev_mutex); + + err = rtsx_usb_write_register(ucr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, + SD_CLK_TOGGLE_EN); + if (err) + goto out; + + mdelay(1); + + err = rtsx_usb_read_register(ucr, SD_BUS_STAT, &stat); + if (err) + goto out; + + err = rtsx_usb_write_register(ucr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); +out: + mutex_unlock(&ucr->dev_mutex); + + if (err) + return err; + + /* check if any pin between dat[0:3] is low */ + if ((stat & mask) != mask) + return 1; + else + return 0; +} + +static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + int err = 0; + + if (host->host_removal) + return -ENOMEDIUM; + + mutex_lock(&ucr->dev_mutex); + + if (!host->ddr_mode) + err = sd_tuning_rx(host, MMC_SEND_TUNING_BLOCK); + + mutex_unlock(&ucr->dev_mutex); + + return err; +} + +static const struct mmc_host_ops rtsx_usb_sdmmc_ops = { + .request = sdmmc_request, + .set_ios = sdmmc_set_ios, + .get_ro = sdmmc_get_ro, + .get_cd = sdmmc_get_cd, + .start_signal_voltage_switch = sdmmc_switch_voltage, + .card_busy = sdmmc_card_busy, + .execute_tuning = sdmmc_execute_tuning, +}; + +#ifdef RTSX_USB_USE_LEDS_CLASS +static void rtsx_usb_led_control(struct led_classdev *led, + enum led_brightness brightness) +{ + struct rtsx_usb_sdmmc *host = container_of(led, + struct rtsx_usb_sdmmc, led); + + if (host->host_removal) + return; + + host->led.brightness = brightness; + schedule_work(&host->led_work); +} + +static void rtsx_usb_update_led(struct work_struct *work) +{ + struct rtsx_usb_sdmmc *host = + container_of(work, struct rtsx_usb_sdmmc, led_work); + struct rtsx_ucr *ucr = host->ucr; + + mutex_lock(&ucr->dev_mutex); + + if (host->led.brightness == LED_OFF) + rtsx_usb_turn_off_led(ucr); + else + rtsx_usb_turn_on_led(ucr); + + mutex_unlock(&ucr->dev_mutex); +} +#endif + +static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host) +{ + struct mmc_host *mmc = host->mmc; + + mmc->f_min = 250000; + mmc->f_max = 208000000; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST | + MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 | + MMC_CAP_NEEDS_POLL; + + mmc->max_current_330 = 400; + mmc->max_current_180 = 800; + mmc->ops = &rtsx_usb_sdmmc_ops; + mmc->max_segs = 256; + mmc->max_seg_size = 65536; + mmc->max_blk_size = 512; + mmc->max_blk_count = 65535; + mmc->max_req_size = 524288; + + host->power_mode = MMC_POWER_OFF; +} + +static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc; + struct rtsx_usb_sdmmc *host; + struct rtsx_ucr *ucr; +#ifdef RTSX_USB_USE_LEDS_CLASS + int err; +#endif + + ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent)); + if (!ucr) + return -ENXIO; + + dev_dbg(&(pdev->dev), ": Realtek USB SD/MMC controller found\n"); + + mmc = mmc_alloc_host(sizeof(*host), &pdev->dev); + if (!mmc) + return -ENOMEM; + + host = mmc_priv(mmc); + host->ucr = ucr; + host->mmc = mmc; + host->pdev = pdev; + platform_set_drvdata(pdev, host); + + mutex_init(&host->host_mutex); + rtsx_usb_init_host(host); + pm_runtime_enable(&pdev->dev); + +#ifdef RTSX_USB_USE_LEDS_CLASS + snprintf(host->led_name, sizeof(host->led_name), + "%s::", mmc_hostname(mmc)); + host->led.name = host->led_name; + host->led.brightness = LED_OFF; + host->led.default_trigger = mmc_hostname(mmc); + host->led.brightness_set = rtsx_usb_led_control; + + err = led_classdev_register(mmc_dev(mmc), &host->led); + if (err) + dev_err(&(pdev->dev), + "Failed to register LED device: %d\n", err); + INIT_WORK(&host->led_work, rtsx_usb_update_led); + +#endif + mmc_add_host(mmc); + + return 0; +} + +static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev) +{ + struct rtsx_usb_sdmmc *host = platform_get_drvdata(pdev); + struct mmc_host *mmc; + + if (!host) + return 0; + + mmc = host->mmc; + host->host_removal = true; + + mutex_lock(&host->host_mutex); + if (host->mrq) { + dev_dbg(&(pdev->dev), + "%s: Controller removed during transfer\n", + mmc_hostname(mmc)); + host->mrq->cmd->error = -ENOMEDIUM; + if (host->mrq->stop) + host->mrq->stop->error = -ENOMEDIUM; + mmc_request_done(mmc, host->mrq); + } + mutex_unlock(&host->host_mutex); + + mmc_remove_host(mmc); + +#ifdef RTSX_USB_USE_LEDS_CLASS + cancel_work_sync(&host->led_work); + led_classdev_unregister(&host->led); +#endif + + mmc_free_host(mmc); + pm_runtime_disable(&pdev->dev); + platform_set_drvdata(pdev, NULL); + + dev_dbg(&(pdev->dev), + ": Realtek USB SD/MMC module has been removed\n"); + + return 0; +} + +static struct platform_device_id rtsx_usb_sdmmc_ids[] = { + { + .name = "rtsx_usb_sdmmc", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, rtsx_usb_sdmmc_ids); + +static struct platform_driver rtsx_usb_sdmmc_driver = { + .probe = rtsx_usb_sdmmc_drv_probe, + .remove = rtsx_usb_sdmmc_drv_remove, + .id_table = rtsx_usb_sdmmc_ids, + .driver = { + .owner = THIS_MODULE, + .name = "rtsx_usb_sdmmc", + }, +}; +module_platform_driver(rtsx_usb_sdmmc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Roger Tseng "); +MODULE_DESCRIPTION("Realtek USB SD/MMC Card Host Driver"); diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index d61eb5a708331d..c12301e90d1674 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -33,9 +33,6 @@ #define MAX_BUS_CLK (4) -/* Number of gpio's used is max data bus width + command and clock lines */ -#define NUM_GPIOS(x) (x + 2) - /** * struct sdhci_s3c - S3C SDHCI instance * @host: The SDHCI host created diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9a79fc4b60ca82..a31f06dadf6fff 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1510,6 +1510,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) /* In case of UHS-I modes, set High Speed Enable */ if ((ios->timing == MMC_TIMING_MMC_HS200) || + (ios->timing == MMC_TIMING_MMC_DDR52) || (ios->timing == MMC_TIMING_UHS_SDR50) || (ios->timing == MMC_TIMING_UHS_SDR104) || (ios->timing == MMC_TIMING_UHS_DDR50) || @@ -1570,7 +1571,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) ctrl_2 |= SDHCI_CTRL_UHS_SDR25; else if (ios->timing == MMC_TIMING_UHS_SDR50) ctrl_2 |= SDHCI_CTRL_UHS_SDR50; - else if (ios->timing == MMC_TIMING_UHS_DDR50) + else if ((ios->timing == MMC_TIMING_UHS_DDR50) || + (ios->timing == MMC_TIMING_MMC_DDR52)) ctrl_2 |= SDHCI_CTRL_UHS_DDR50; sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); } diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 54730f4aac87f0..656fbba4c4223f 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -803,12 +803,13 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, break; } switch (host->timing) { - case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: /* * MMC core will only set this timing, if the host - * advertises the MMC_CAP_UHS_DDR50 capability. MMCIF - * implementations with this capability, e.g. sh73a0, - * will have to set it in their platform data. + * advertises the MMC_CAP_1_8V_DDR/MMC_CAP_1_2V_DDR + * capability. MMCIF implementations with this + * capability, e.g. sh73a0, will have to set it + * in their platform data. */ tmp |= CMD_SET_DARS; break; diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 5d49a21296187c..94b821042d9da4 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -321,6 +321,8 @@ source "drivers/mtd/onenand/Kconfig" source "drivers/mtd/lpddr/Kconfig" +source "drivers/mtd/spi-nor/Kconfig" + source "drivers/mtd/ubi/Kconfig" endif # MTD diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 4cfb31e6c966ad..99bb9a1f6e16fc 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -32,4 +32,5 @@ inftl-objs := inftlcore.o inftlmount.o obj-y += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/ +obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/ obj-$(CONFIG_MTD_UBI) += ubi/ diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 1210bc2923b713..c49d0b127fefb3 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -80,7 +80,7 @@ config MTD_DATAFLASH_OTP config MTD_M25P80 tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" - depends on SPI_MASTER + depends on SPI_MASTER && MTD_SPI_NOR help This enables access to most modern SPI flash chips, used for program and data storage. Series supported include Atmel AT26DF, @@ -212,7 +212,7 @@ config MTD_DOCG3 config MTD_ST_SPI_FSM tristate "ST Microelectronics SPI FSM Serial Flash Controller" - depends on ARM || SH + depends on ARCH_STI help This provides an MTD device driver for the ST Microelectronics SPI Fast Sequence Mode (FSM) Serial Flash Controller and support diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 524dab3ac9381f..1557d8f672c1eb 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -19,485 +19,98 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include #include +#include -/* Flash opcodes. */ -#define OPCODE_WREN 0x06 /* Write enable */ -#define OPCODE_RDSR 0x05 /* Read status register */ -#define OPCODE_WRSR 0x01 /* Write status register 1 byte */ -#define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ -#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ -#define OPCODE_DUAL_READ 0x3b /* Read data bytes (Dual SPI) */ -#define OPCODE_QUAD_READ 0x6b /* Read data bytes (Quad SPI) */ -#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ -#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ -#define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ -#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */ -#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ -#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ -#define OPCODE_RDID 0x9f /* Read JEDEC ID */ -#define OPCODE_RDCR 0x35 /* Read configuration register */ - -/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ -#define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */ -#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ -#define OPCODE_DUAL_READ_4B 0x3c /* Read data bytes (Dual SPI) */ -#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes (Quad SPI) */ -#define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */ -#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */ - -/* Used for SST flashes only. */ -#define OPCODE_BP 0x02 /* Byte program */ -#define OPCODE_WRDI 0x04 /* Write disable */ -#define OPCODE_AAI_WP 0xad /* Auto address increment word program */ - -/* Used for Macronix and Winbond flashes. */ -#define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */ -#define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */ - -/* Used for Spansion flashes only. */ -#define OPCODE_BRWR 0x17 /* Bank register write */ - -/* Status Register bits. */ -#define SR_WIP 1 /* Write in progress */ -#define SR_WEL 2 /* Write enable latch */ -/* meaning of other SR_* bits may differ between vendors */ -#define SR_BP0 4 /* Block protect 0 */ -#define SR_BP1 8 /* Block protect 1 */ -#define SR_BP2 0x10 /* Block protect 2 */ -#define SR_SRWD 0x80 /* SR write protect */ - -#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ - -/* Configuration Register bits. */ -#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */ - -/* Define max times to check status register before we give up. */ -#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ #define MAX_CMD_SIZE 6 - -#define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16) - -/****************************************************************************/ - -enum read_type { - M25P80_NORMAL = 0, - M25P80_FAST, - M25P80_DUAL, - M25P80_QUAD, -}; - struct m25p { struct spi_device *spi; - struct mutex lock; + struct spi_nor spi_nor; struct mtd_info mtd; - u16 page_size; - u16 addr_width; - u8 erase_opcode; - u8 read_opcode; - u8 program_opcode; - u8 *command; - enum read_type flash_read; + u8 command[MAX_CMD_SIZE]; }; -static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) -{ - return container_of(mtd, struct m25p, mtd); -} - -/****************************************************************************/ - -/* - * Internal helper functions - */ - -/* - * Read the status register, returning its value in the location - * Return the status register value. - * Returns negative if error occurred. - */ -static int read_sr(struct m25p *flash) -{ - ssize_t retval; - u8 code = OPCODE_RDSR; - u8 val; - - retval = spi_write_then_read(flash->spi, &code, 1, &val, 1); - - if (retval < 0) { - dev_err(&flash->spi->dev, "error %d reading SR\n", - (int) retval); - return retval; - } - - return val; -} - -/* - * Read configuration register, returning its value in the - * location. Return the configuration register value. - * Returns negative if error occured. - */ -static int read_cr(struct m25p *flash) -{ - u8 code = OPCODE_RDCR; - int ret; - u8 val; - - ret = spi_write_then_read(flash->spi, &code, 1, &val, 1); - if (ret < 0) { - dev_err(&flash->spi->dev, "error %d reading CR\n", ret); - return ret; - } - - return val; -} - -/* - * Write status register 1 byte - * Returns negative if error occurred. - */ -static int write_sr(struct m25p *flash, u8 val) -{ - flash->command[0] = OPCODE_WRSR; - flash->command[1] = val; - - return spi_write(flash->spi, flash->command, 2); -} - -/* - * Set write enable latch with Write Enable command. - * Returns negative if error occurred. - */ -static inline int write_enable(struct m25p *flash) -{ - u8 code = OPCODE_WREN; - - return spi_write_then_read(flash->spi, &code, 1, NULL, 0); -} - -/* - * Send write disble instruction to the chip. - */ -static inline int write_disable(struct m25p *flash) -{ - u8 code = OPCODE_WRDI; - - return spi_write_then_read(flash->spi, &code, 1, NULL, 0); -} - -/* - * Enable/disable 4-byte addressing mode. - */ -static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable) -{ - int status; - bool need_wren = false; - - switch (JEDEC_MFR(jedec_id)) { - case CFI_MFR_ST: /* Micron, actually */ - /* Some Micron need WREN command; all will accept it */ - need_wren = true; - case CFI_MFR_MACRONIX: - case 0xEF /* winbond */: - if (need_wren) - write_enable(flash); - - flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B; - status = spi_write(flash->spi, flash->command, 1); - - if (need_wren) - write_disable(flash); - - return status; - default: - /* Spansion style */ - flash->command[0] = OPCODE_BRWR; - flash->command[1] = enable << 7; - return spi_write(flash->spi, flash->command, 2); - } -} - -/* - * Service routine to read status register until ready, or timeout occurs. - * Returns non-zero if error. - */ -static int wait_till_ready(struct m25p *flash) -{ - unsigned long deadline; - int sr; - - deadline = jiffies + MAX_READY_WAIT_JIFFIES; - - do { - if ((sr = read_sr(flash)) < 0) - break; - else if (!(sr & SR_WIP)) - return 0; - - cond_resched(); - - } while (!time_after_eq(jiffies, deadline)); - - return 1; -} - -/* - * Write status Register and configuration register with 2 bytes - * The first byte will be written to the status register, while the - * second byte will be written to the configuration register. - * Return negative if error occured. - */ -static int write_sr_cr(struct m25p *flash, u16 val) -{ - flash->command[0] = OPCODE_WRSR; - flash->command[1] = val & 0xff; - flash->command[2] = (val >> 8); - - return spi_write(flash->spi, flash->command, 3); -} - -static int macronix_quad_enable(struct m25p *flash) -{ - int ret, val; - u8 cmd[2]; - cmd[0] = OPCODE_WRSR; - - val = read_sr(flash); - cmd[1] = val | SR_QUAD_EN_MX; - write_enable(flash); - - spi_write(flash->spi, &cmd, 2); - - if (wait_till_ready(flash)) - return 1; - - ret = read_sr(flash); - if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) { - dev_err(&flash->spi->dev, "Macronix Quad bit not set\n"); - return -EINVAL; - } - - return 0; -} - -static int spansion_quad_enable(struct m25p *flash) +static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len) { + struct m25p *flash = nor->priv; + struct spi_device *spi = flash->spi; int ret; - int quad_en = CR_QUAD_EN_SPAN << 8; - - write_enable(flash); - ret = write_sr_cr(flash, quad_en); - if (ret < 0) { - dev_err(&flash->spi->dev, - "error while writing configuration register\n"); - return -EINVAL; - } - - /* read back and check it */ - ret = read_cr(flash); - if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { - dev_err(&flash->spi->dev, "Spansion Quad bit not set\n"); - return -EINVAL; - } - - return 0; -} - -static int set_quad_mode(struct m25p *flash, u32 jedec_id) -{ - int status; - - switch (JEDEC_MFR(jedec_id)) { - case CFI_MFR_MACRONIX: - status = macronix_quad_enable(flash); - if (status) { - dev_err(&flash->spi->dev, - "Macronix quad-read not enabled\n"); - return -EINVAL; - } - return status; - default: - status = spansion_quad_enable(flash); - if (status) { - dev_err(&flash->spi->dev, - "Spansion quad-read not enabled\n"); - return -EINVAL; - } - return status; - } -} - -/* - * Erase the whole flash memory - * - * Returns 0 if successful, non-zero otherwise. - */ -static int erase_chip(struct m25p *flash) -{ - pr_debug("%s: %s %lldKiB\n", dev_name(&flash->spi->dev), __func__, - (long long)(flash->mtd.size >> 10)); + ret = spi_write_then_read(spi, &code, 1, val, len); + if (ret < 0) + dev_err(&spi->dev, "error %d reading %x\n", ret, code); - /* Wait until finished previous write command. */ - if (wait_till_ready(flash)) - return 1; - - /* Send write enable, then erase commands. */ - write_enable(flash); - - /* Set up command buffer. */ - flash->command[0] = OPCODE_CHIP_ERASE; - - spi_write(flash->spi, flash->command, 1); - - return 0; + return ret; } -static void m25p_addr2cmd(struct m25p *flash, unsigned int addr, u8 *cmd) +static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd) { /* opcode is in cmd[0] */ - cmd[1] = addr >> (flash->addr_width * 8 - 8); - cmd[2] = addr >> (flash->addr_width * 8 - 16); - cmd[3] = addr >> (flash->addr_width * 8 - 24); - cmd[4] = addr >> (flash->addr_width * 8 - 32); + cmd[1] = addr >> (nor->addr_width * 8 - 8); + cmd[2] = addr >> (nor->addr_width * 8 - 16); + cmd[3] = addr >> (nor->addr_width * 8 - 24); + cmd[4] = addr >> (nor->addr_width * 8 - 32); } -static int m25p_cmdsz(struct m25p *flash) +static int m25p_cmdsz(struct spi_nor *nor) { - return 1 + flash->addr_width; + return 1 + nor->addr_width; } -/* - * Erase one sector of flash memory at offset ``offset'' which is any - * address within the sector which should be erased. - * - * Returns 0 if successful, non-zero otherwise. - */ -static int erase_sector(struct m25p *flash, u32 offset) +static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len, + int wr_en) { - pr_debug("%s: %s %dKiB at 0x%08x\n", dev_name(&flash->spi->dev), - __func__, flash->mtd.erasesize / 1024, offset); - - /* Wait until finished previous write command. */ - if (wait_till_ready(flash)) - return 1; + struct m25p *flash = nor->priv; + struct spi_device *spi = flash->spi; - /* Send write enable, then erase commands. */ - write_enable(flash); - - /* Set up command buffer. */ - flash->command[0] = flash->erase_opcode; - m25p_addr2cmd(flash, offset, flash->command); - - spi_write(flash->spi, flash->command, m25p_cmdsz(flash)); + flash->command[0] = opcode; + if (buf) + memcpy(&flash->command[1], buf, len); - return 0; + return spi_write(spi, flash->command, len + 1); } -/****************************************************************************/ - -/* - * MTD implementation - */ - -/* - * Erase an address range on the flash chip. The address range may extend - * one or more erase sectors. Return an error is there is a problem erasing. - */ -static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) +static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len, + size_t *retlen, const u_char *buf) { - struct m25p *flash = mtd_to_m25p(mtd); - u32 addr,len; - uint32_t rem; - - pr_debug("%s: %s at 0x%llx, len %lld\n", dev_name(&flash->spi->dev), - __func__, (long long)instr->addr, - (long long)instr->len); - - div_u64_rem(instr->len, mtd->erasesize, &rem); - if (rem) - return -EINVAL; - - addr = instr->addr; - len = instr->len; - - mutex_lock(&flash->lock); - - /* whole-chip erase? */ - if (len == flash->mtd.size) { - if (erase_chip(flash)) { - instr->state = MTD_ERASE_FAILED; - mutex_unlock(&flash->lock); - return -EIO; - } + struct m25p *flash = nor->priv; + struct spi_device *spi = flash->spi; + struct spi_transfer t[2] = {}; + struct spi_message m; + int cmd_sz = m25p_cmdsz(nor); - /* REVISIT in some cases we could speed up erasing large regions - * by using OPCODE_SE instead of OPCODE_BE_4K. We may have set up - * to use "small sector erase", but that's not always optimal. - */ + spi_message_init(&m); - /* "sector"-at-a-time erase */ - } else { - while (len) { - if (erase_sector(flash, addr)) { - instr->state = MTD_ERASE_FAILED; - mutex_unlock(&flash->lock); - return -EIO; - } + if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) + cmd_sz = 1; - addr += mtd->erasesize; - len -= mtd->erasesize; - } - } + flash->command[0] = nor->program_opcode; + m25p_addr2cmd(nor, to, flash->command); - mutex_unlock(&flash->lock); + t[0].tx_buf = flash->command; + t[0].len = cmd_sz; + spi_message_add_tail(&t[0], &m); - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); + t[1].tx_buf = buf; + t[1].len = len; + spi_message_add_tail(&t[1], &m); - return 0; -} + spi_sync(spi, &m); -/* - * Dummy Cycle calculation for different type of read. - * It can be used to support more commands with - * different dummy cycle requirements. - */ -static inline int m25p80_dummy_cycles_read(struct m25p *flash) -{ - switch (flash->flash_read) { - case M25P80_FAST: - case M25P80_DUAL: - case M25P80_QUAD: - return 1; - case M25P80_NORMAL: - return 0; - default: - dev_err(&flash->spi->dev, "No valid read type supported\n"); - return -1; - } + *retlen += m.actual_length - cmd_sz; } -static inline unsigned int m25p80_rx_nbits(const struct m25p *flash) +static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor) { - switch (flash->flash_read) { - case M25P80_DUAL: + switch (nor->flash_read) { + case SPI_NOR_DUAL: return 2; - case M25P80_QUAD: + case SPI_NOR_QUAD: return 4; default: return 0; @@ -505,590 +118,72 @@ static inline unsigned int m25p80_rx_nbits(const struct m25p *flash) } /* - * Read an address range from the flash chip. The address range + * Read an address range from the nor chip. The address range * may be any size provided it is within the physical boundaries. */ -static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) +static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, + size_t *retlen, u_char *buf) { - struct m25p *flash = mtd_to_m25p(mtd); + struct m25p *flash = nor->priv; + struct spi_device *spi = flash->spi; struct spi_transfer t[2]; struct spi_message m; - uint8_t opcode; - int dummy; + int dummy = nor->read_dummy; + int ret; - pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), - __func__, (u32)from, len); + /* Wait till previous write/erase is done. */ + ret = nor->wait_till_ready(nor); + if (ret) + return ret; spi_message_init(&m); memset(t, 0, (sizeof t)); - dummy = m25p80_dummy_cycles_read(flash); - if (dummy < 0) { - dev_err(&flash->spi->dev, "No valid read command supported\n"); - return -EINVAL; - } + flash->command[0] = nor->read_opcode; + m25p_addr2cmd(nor, from, flash->command); t[0].tx_buf = flash->command; - t[0].len = m25p_cmdsz(flash) + dummy; + t[0].len = m25p_cmdsz(nor) + dummy; spi_message_add_tail(&t[0], &m); t[1].rx_buf = buf; - t[1].rx_nbits = m25p80_rx_nbits(flash); + t[1].rx_nbits = m25p80_rx_nbits(nor); t[1].len = len; spi_message_add_tail(&t[1], &m); - mutex_lock(&flash->lock); - - /* Wait till previous write/erase is done. */ - if (wait_till_ready(flash)) { - /* REVISIT status return?? */ - mutex_unlock(&flash->lock); - return 1; - } - - /* Set up the write data buffer. */ - opcode = flash->read_opcode; - flash->command[0] = opcode; - m25p_addr2cmd(flash, from, flash->command); - - spi_sync(flash->spi, &m); - - *retlen = m.actual_length - m25p_cmdsz(flash) - dummy; - - mutex_unlock(&flash->lock); + spi_sync(spi, &m); + *retlen = m.actual_length - m25p_cmdsz(nor) - dummy; return 0; } -/* - * Write an address range to the flash chip. Data must be written in - * FLASH_PAGESIZE chunks. The address range may be any size provided - * it is within the physical boundaries. - */ -static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static int m25p80_erase(struct spi_nor *nor, loff_t offset) { - struct m25p *flash = mtd_to_m25p(mtd); - u32 page_offset, page_size; - struct spi_transfer t[2]; - struct spi_message m; - - pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), - __func__, (u32)to, len); - - spi_message_init(&m); - memset(t, 0, (sizeof t)); - - t[0].tx_buf = flash->command; - t[0].len = m25p_cmdsz(flash); - spi_message_add_tail(&t[0], &m); - - t[1].tx_buf = buf; - spi_message_add_tail(&t[1], &m); - - mutex_lock(&flash->lock); - - /* Wait until finished previous write command. */ - if (wait_till_ready(flash)) { - mutex_unlock(&flash->lock); - return 1; - } - - write_enable(flash); - - /* Set up the opcode in the write buffer. */ - flash->command[0] = flash->program_opcode; - m25p_addr2cmd(flash, to, flash->command); - - page_offset = to & (flash->page_size - 1); - - /* do all the bytes fit onto one page? */ - if (page_offset + len <= flash->page_size) { - t[1].len = len; - - spi_sync(flash->spi, &m); - - *retlen = m.actual_length - m25p_cmdsz(flash); - } else { - u32 i; - - /* the size of data remaining on the first page */ - page_size = flash->page_size - page_offset; - - t[1].len = page_size; - spi_sync(flash->spi, &m); - - *retlen = m.actual_length - m25p_cmdsz(flash); - - /* write everything in flash->page_size chunks */ - for (i = page_size; i < len; i += page_size) { - page_size = len - i; - if (page_size > flash->page_size) - page_size = flash->page_size; - - /* write the next page to flash */ - m25p_addr2cmd(flash, to + i, flash->command); - - t[1].tx_buf = buf + i; - t[1].len = page_size; - - wait_till_ready(flash); - - write_enable(flash); - - spi_sync(flash->spi, &m); - - *retlen += m.actual_length - m25p_cmdsz(flash); - } - } - - mutex_unlock(&flash->lock); - - return 0; -} - -static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - struct m25p *flash = mtd_to_m25p(mtd); - struct spi_transfer t[2]; - struct spi_message m; - size_t actual; - int cmd_sz, ret; - - pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), - __func__, (u32)to, len); - - spi_message_init(&m); - memset(t, 0, (sizeof t)); - - t[0].tx_buf = flash->command; - t[0].len = m25p_cmdsz(flash); - spi_message_add_tail(&t[0], &m); - - t[1].tx_buf = buf; - spi_message_add_tail(&t[1], &m); + struct m25p *flash = nor->priv; + int ret; - mutex_lock(&flash->lock); + dev_dbg(nor->dev, "%dKiB at 0x%08x\n", + flash->mtd.erasesize / 1024, (u32)offset); /* Wait until finished previous write command. */ - ret = wait_till_ready(flash); + ret = nor->wait_till_ready(nor); if (ret) - goto time_out; - - write_enable(flash); - - actual = to % 2; - /* Start write from odd address. */ - if (actual) { - flash->command[0] = OPCODE_BP; - m25p_addr2cmd(flash, to, flash->command); - - /* write one byte. */ - t[1].len = 1; - spi_sync(flash->spi, &m); - ret = wait_till_ready(flash); - if (ret) - goto time_out; - *retlen += m.actual_length - m25p_cmdsz(flash); - } - to += actual; - - flash->command[0] = OPCODE_AAI_WP; - m25p_addr2cmd(flash, to, flash->command); - - /* Write out most of the data here. */ - cmd_sz = m25p_cmdsz(flash); - for (; actual < len - 1; actual += 2) { - t[0].len = cmd_sz; - /* write two bytes. */ - t[1].len = 2; - t[1].tx_buf = buf + actual; + return ret; - spi_sync(flash->spi, &m); - ret = wait_till_ready(flash); - if (ret) - goto time_out; - *retlen += m.actual_length - cmd_sz; - cmd_sz = 1; - to += 2; - } - write_disable(flash); - ret = wait_till_ready(flash); + /* Send write enable, then erase commands. */ + ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0); if (ret) - goto time_out; - - /* Write out trailing byte if it exists. */ - if (actual != len) { - write_enable(flash); - flash->command[0] = OPCODE_BP; - m25p_addr2cmd(flash, to, flash->command); - t[0].len = m25p_cmdsz(flash); - t[1].len = 1; - t[1].tx_buf = buf + actual; - - spi_sync(flash->spi, &m); - ret = wait_till_ready(flash); - if (ret) - goto time_out; - *retlen += m.actual_length - m25p_cmdsz(flash); - write_disable(flash); - } - -time_out: - mutex_unlock(&flash->lock); - return ret; -} - -static int m25p80_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - struct m25p *flash = mtd_to_m25p(mtd); - uint32_t offset = ofs; - uint8_t status_old, status_new; - int res = 0; - - mutex_lock(&flash->lock); - /* Wait until finished previous command */ - if (wait_till_ready(flash)) { - res = 1; - goto err; - } - - status_old = read_sr(flash); - - if (offset < flash->mtd.size-(flash->mtd.size/2)) - status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0; - else if (offset < flash->mtd.size-(flash->mtd.size/4)) - status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1; - else if (offset < flash->mtd.size-(flash->mtd.size/8)) - status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0; - else if (offset < flash->mtd.size-(flash->mtd.size/16)) - status_new = (status_old & ~(SR_BP0|SR_BP1)) | SR_BP2; - else if (offset < flash->mtd.size-(flash->mtd.size/32)) - status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0; - else if (offset < flash->mtd.size-(flash->mtd.size/64)) - status_new = (status_old & ~(SR_BP2|SR_BP0)) | SR_BP1; - else - status_new = (status_old & ~(SR_BP2|SR_BP1)) | SR_BP0; - - /* Only modify protection if it will not unlock other areas */ - if ((status_new&(SR_BP2|SR_BP1|SR_BP0)) > - (status_old&(SR_BP2|SR_BP1|SR_BP0))) { - write_enable(flash); - if (write_sr(flash, status_new) < 0) { - res = 1; - goto err; - } - } - -err: mutex_unlock(&flash->lock); - return res; -} - -static int m25p80_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - struct m25p *flash = mtd_to_m25p(mtd); - uint32_t offset = ofs; - uint8_t status_old, status_new; - int res = 0; - - mutex_lock(&flash->lock); - /* Wait until finished previous command */ - if (wait_till_ready(flash)) { - res = 1; - goto err; - } - - status_old = read_sr(flash); - - if (offset+len > flash->mtd.size-(flash->mtd.size/64)) - status_new = status_old & ~(SR_BP2|SR_BP1|SR_BP0); - else if (offset+len > flash->mtd.size-(flash->mtd.size/32)) - status_new = (status_old & ~(SR_BP2|SR_BP1)) | SR_BP0; - else if (offset+len > flash->mtd.size-(flash->mtd.size/16)) - status_new = (status_old & ~(SR_BP2|SR_BP0)) | SR_BP1; - else if (offset+len > flash->mtd.size-(flash->mtd.size/8)) - status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0; - else if (offset+len > flash->mtd.size-(flash->mtd.size/4)) - status_new = (status_old & ~(SR_BP0|SR_BP1)) | SR_BP2; - else if (offset+len > flash->mtd.size-(flash->mtd.size/2)) - status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0; - else - status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1; - - /* Only modify protection if it will not lock other areas */ - if ((status_new&(SR_BP2|SR_BP1|SR_BP0)) < - (status_old&(SR_BP2|SR_BP1|SR_BP0))) { - write_enable(flash); - if (write_sr(flash, status_new) < 0) { - res = 1; - goto err; - } - } - -err: mutex_unlock(&flash->lock); - return res; -} - -/****************************************************************************/ - -/* - * SPI device driver setup and teardown - */ - -struct flash_info { - /* JEDEC id zero means "no ID" (most older chips); otherwise it has - * a high byte of zero plus three data bytes: the manufacturer id, - * then a two byte device id. - */ - u32 jedec_id; - u16 ext_id; - - /* The size listed here is what works with OPCODE_SE, which isn't - * necessarily called a "sector" by the vendor. - */ - unsigned sector_size; - u16 n_sectors; - - u16 page_size; - u16 addr_width; - - u16 flags; -#define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */ -#define M25P_NO_ERASE 0x02 /* No erase command needed */ -#define SST_WRITE 0x04 /* use SST byte programming */ -#define M25P_NO_FR 0x08 /* Can't do fastread */ -#define SECT_4K_PMC 0x10 /* OPCODE_BE_4K_PMC works uniformly */ -#define M25P80_DUAL_READ 0x20 /* Flash supports Dual Read */ -#define M25P80_QUAD_READ 0x40 /* Flash supports Quad Read */ -}; - -#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ - ((kernel_ulong_t)&(struct flash_info) { \ - .jedec_id = (_jedec_id), \ - .ext_id = (_ext_id), \ - .sector_size = (_sector_size), \ - .n_sectors = (_n_sectors), \ - .page_size = 256, \ - .flags = (_flags), \ - }) - -#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \ - ((kernel_ulong_t)&(struct flash_info) { \ - .sector_size = (_sector_size), \ - .n_sectors = (_n_sectors), \ - .page_size = (_page_size), \ - .addr_width = (_addr_width), \ - .flags = (_flags), \ - }) - -/* NOTE: double check command sets and memory organization when you add - * more flash chips. This current list focusses on newer chips, which - * have been converging on command sets which including JEDEC ID. - */ -static const struct spi_device_id m25p_ids[] = { - /* Atmel -- some are (confusingly) marketed as "DataFlash" */ - { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, - { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, - - { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) }, - { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, - { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, - - { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, - { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, - { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, - { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, - - { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, - - /* EON -- en25xxx */ - { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, - { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, - { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, - { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, - { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, - { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, - - /* ESMT */ - { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) }, - - /* Everspin */ - { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, M25P_NO_ERASE | M25P_NO_FR) }, - { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, M25P_NO_ERASE | M25P_NO_FR) }, - - /* GigaDevice */ - { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) }, - { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) }, - - /* Intel/Numonyx -- xxxs33b */ - { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, - { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, - { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, - - /* Macronix */ - { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, - { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, - { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, - { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, - { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) }, - { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, - { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, - { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, - { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, - { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, - { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, - { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, M25P80_QUAD_READ) }, - { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, M25P80_QUAD_READ) }, - - /* Micron */ - { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, - { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, - { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, - { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, - { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) }, - - /* PMC */ - { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, - { "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) }, - { "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) }, - - /* Spansion -- single (large) sector size only, at least - * for the chips listed here (without boot sectors). - */ - { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, 0) }, - { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, - { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, - { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, M25P80_DUAL_READ | M25P80_QUAD_READ) }, - { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_DUAL_READ | M25P80_QUAD_READ) }, - { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, - { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, - { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, - { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) }, - { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) }, - { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, - { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, - { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, - { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, - { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, - { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, - { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, - { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, - - /* SST -- large erase sizes are "overlays", "sectors" are 4K */ - { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, - { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, - { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) }, - { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) }, - { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) }, - { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) }, - { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) }, - { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) }, - { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, - - /* ST Microelectronics -- newer production may have feature updates */ - { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, - { "m25p10", INFO(0x202011, 0, 32 * 1024, 4, 0) }, - { "m25p20", INFO(0x202012, 0, 64 * 1024, 4, 0) }, - { "m25p40", INFO(0x202013, 0, 64 * 1024, 8, 0) }, - { "m25p80", INFO(0x202014, 0, 64 * 1024, 16, 0) }, - { "m25p16", INFO(0x202015, 0, 64 * 1024, 32, 0) }, - { "m25p32", INFO(0x202016, 0, 64 * 1024, 64, 0) }, - { "m25p64", INFO(0x202017, 0, 64 * 1024, 128, 0) }, - { "m25p128", INFO(0x202018, 0, 256 * 1024, 64, 0) }, - { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) }, - - { "m25p05-nonjedec", INFO(0, 0, 32 * 1024, 2, 0) }, - { "m25p10-nonjedec", INFO(0, 0, 32 * 1024, 4, 0) }, - { "m25p20-nonjedec", INFO(0, 0, 64 * 1024, 4, 0) }, - { "m25p40-nonjedec", INFO(0, 0, 64 * 1024, 8, 0) }, - { "m25p80-nonjedec", INFO(0, 0, 64 * 1024, 16, 0) }, - { "m25p16-nonjedec", INFO(0, 0, 64 * 1024, 32, 0) }, - { "m25p32-nonjedec", INFO(0, 0, 64 * 1024, 64, 0) }, - { "m25p64-nonjedec", INFO(0, 0, 64 * 1024, 128, 0) }, - { "m25p128-nonjedec", INFO(0, 0, 256 * 1024, 64, 0) }, - - { "m45pe10", INFO(0x204011, 0, 64 * 1024, 2, 0) }, - { "m45pe80", INFO(0x204014, 0, 64 * 1024, 16, 0) }, - { "m45pe16", INFO(0x204015, 0, 64 * 1024, 32, 0) }, - - { "m25pe20", INFO(0x208012, 0, 64 * 1024, 4, 0) }, - { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, - { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, - - { "m25px16", INFO(0x207115, 0, 64 * 1024, 32, SECT_4K) }, - { "m25px32", INFO(0x207116, 0, 64 * 1024, 64, SECT_4K) }, - { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, - { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, - { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, - - /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ - { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, - { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, - { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, - { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, - { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, - { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, - { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) }, - - /* Catalyst / On Semiconductor -- non-JEDEC */ - { "cat25c11", CAT25_INFO( 16, 8, 16, 1, M25P_NO_ERASE | M25P_NO_FR) }, - { "cat25c03", CAT25_INFO( 32, 8, 16, 2, M25P_NO_ERASE | M25P_NO_FR) }, - { "cat25c09", CAT25_INFO( 128, 8, 32, 2, M25P_NO_ERASE | M25P_NO_FR) }, - { "cat25c17", CAT25_INFO( 256, 8, 32, 2, M25P_NO_ERASE | M25P_NO_FR) }, - { "cat25128", CAT25_INFO(2048, 8, 64, 2, M25P_NO_ERASE | M25P_NO_FR) }, - { }, -}; -MODULE_DEVICE_TABLE(spi, m25p_ids); - -static const struct spi_device_id *jedec_probe(struct spi_device *spi) -{ - int tmp; - u8 code = OPCODE_RDID; - u8 id[5]; - u32 jedec; - u16 ext_jedec; - struct flash_info *info; + return ret; - /* JEDEC also defines an optional "extended device information" - * string for after vendor-specific data, after the three bytes - * we use here. Supporting some chips might require using it. - */ - tmp = spi_write_then_read(spi, &code, 1, id, 5); - if (tmp < 0) { - pr_debug("%s: error %d reading JEDEC ID\n", - dev_name(&spi->dev), tmp); - return ERR_PTR(tmp); - } - jedec = id[0]; - jedec = jedec << 8; - jedec |= id[1]; - jedec = jedec << 8; - jedec |= id[2]; + /* Set up command buffer. */ + flash->command[0] = nor->erase_opcode; + m25p_addr2cmd(nor, offset, flash->command); - ext_jedec = id[3] << 8 | id[4]; + spi_write(flash->spi, flash->command, m25p_cmdsz(nor)); - for (tmp = 0; tmp < ARRAY_SIZE(m25p_ids) - 1; tmp++) { - info = (void *)m25p_ids[tmp].driver_data; - if (info->jedec_id == jedec) { - if (info->ext_id == 0 || info->ext_id == ext_jedec) - return &m25p_ids[tmp]; - } - } - dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); - return ERR_PTR(-ENODEV); + return 0; } - /* * board specific setup should have ensured the SPI clock used here * matches what the READ command supports, at least until this driver @@ -1096,231 +191,43 @@ static const struct spi_device_id *jedec_probe(struct spi_device *spi) */ static int m25p_probe(struct spi_device *spi) { - const struct spi_device_id *id = spi_get_device_id(spi); - struct flash_platform_data *data; - struct m25p *flash; - struct flash_info *info; - unsigned i; struct mtd_part_parser_data ppdata; - struct device_node *np = spi->dev.of_node; + struct flash_platform_data *data; + struct m25p *flash; + struct spi_nor *nor; + enum read_mode mode = SPI_NOR_NORMAL; int ret; - /* Platform data helps sort out which chip type we have, as - * well as how this board partitions it. If we don't have - * a chip ID, try the JEDEC id commands; they'll work for most - * newer chips, even if we don't recognize the particular chip. - */ - data = dev_get_platdata(&spi->dev); - if (data && data->type) { - const struct spi_device_id *plat_id; - - for (i = 0; i < ARRAY_SIZE(m25p_ids) - 1; i++) { - plat_id = &m25p_ids[i]; - if (strcmp(data->type, plat_id->name)) - continue; - break; - } - - if (i < ARRAY_SIZE(m25p_ids) - 1) - id = plat_id; - else - dev_warn(&spi->dev, "unrecognized id %s\n", data->type); - } - - info = (void *)id->driver_data; - - if (info->jedec_id) { - const struct spi_device_id *jid; - - jid = jedec_probe(spi); - if (IS_ERR(jid)) { - return PTR_ERR(jid); - } else if (jid != id) { - /* - * JEDEC knows better, so overwrite platform ID. We - * can't trust partitions any longer, but we'll let - * mtd apply them anyway, since some partitions may be - * marked read-only, and we don't want to lose that - * information, even if it's not 100% accurate. - */ - dev_warn(&spi->dev, "found %s, expected %s\n", - jid->name, id->name); - id = jid; - info = (void *)jid->driver_data; - } - } - flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); if (!flash) return -ENOMEM; - flash->command = devm_kzalloc(&spi->dev, MAX_CMD_SIZE, GFP_KERNEL); - if (!flash->command) - return -ENOMEM; - - flash->spi = spi; - mutex_init(&flash->lock); - spi_set_drvdata(spi, flash); - - /* - * Atmel, SST and Intel/Numonyx serial flash tend to power - * up with the software protection bits set - */ + nor = &flash->spi_nor; - if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ATMEL || - JEDEC_MFR(info->jedec_id) == CFI_MFR_INTEL || - JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) { - write_enable(flash); - write_sr(flash, 0); - } - - if (data && data->name) - flash->mtd.name = data->name; - else - flash->mtd.name = dev_name(&spi->dev); - - flash->mtd.type = MTD_NORFLASH; - flash->mtd.writesize = 1; - flash->mtd.flags = MTD_CAP_NORFLASH; - flash->mtd.size = info->sector_size * info->n_sectors; - flash->mtd._erase = m25p80_erase; - flash->mtd._read = m25p80_read; - - /* flash protection support for STmicro chips */ - if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) { - flash->mtd._lock = m25p80_lock; - flash->mtd._unlock = m25p80_unlock; - } + /* install the hooks */ + nor->read = m25p80_read; + nor->write = m25p80_write; + nor->erase = m25p80_erase; + nor->write_reg = m25p80_write_reg; + nor->read_reg = m25p80_read_reg; - /* sst flash chips use AAI word program */ - if (info->flags & SST_WRITE) - flash->mtd._write = sst_write; - else - flash->mtd._write = m25p80_write; + nor->dev = &spi->dev; + nor->mtd = &flash->mtd; + nor->priv = flash; - /* prefer "small sector" erase if possible */ - if (info->flags & SECT_4K) { - flash->erase_opcode = OPCODE_BE_4K; - flash->mtd.erasesize = 4096; - } else if (info->flags & SECT_4K_PMC) { - flash->erase_opcode = OPCODE_BE_4K_PMC; - flash->mtd.erasesize = 4096; - } else { - flash->erase_opcode = OPCODE_SE; - flash->mtd.erasesize = info->sector_size; - } + spi_set_drvdata(spi, flash); + flash->mtd.priv = nor; + flash->spi = spi; - if (info->flags & M25P_NO_ERASE) - flash->mtd.flags |= MTD_NO_ERASE; + if (spi->mode & SPI_RX_QUAD) + mode = SPI_NOR_QUAD; + ret = spi_nor_scan(nor, spi_get_device_id(spi), mode); + if (ret) + return ret; + data = dev_get_platdata(&spi->dev); ppdata.of_node = spi->dev.of_node; - flash->mtd.dev.parent = &spi->dev; - flash->page_size = info->page_size; - flash->mtd.writebufsize = flash->page_size; - - if (np) { - /* If we were instantiated by DT, use it */ - if (of_property_read_bool(np, "m25p,fast-read")) - flash->flash_read = M25P80_FAST; - else - flash->flash_read = M25P80_NORMAL; - } else { - /* If we weren't instantiated by DT, default to fast-read */ - flash->flash_read = M25P80_FAST; - } - - /* Some devices cannot do fast-read, no matter what DT tells us */ - if (info->flags & M25P_NO_FR) - flash->flash_read = M25P80_NORMAL; - - /* Quad/Dual-read mode takes precedence over fast/normal */ - if (spi->mode & SPI_RX_QUAD && info->flags & M25P80_QUAD_READ) { - ret = set_quad_mode(flash, info->jedec_id); - if (ret) { - dev_err(&flash->spi->dev, "quad mode not supported\n"); - return ret; - } - flash->flash_read = M25P80_QUAD; - } else if (spi->mode & SPI_RX_DUAL && info->flags & M25P80_DUAL_READ) { - flash->flash_read = M25P80_DUAL; - } - /* Default commands */ - switch (flash->flash_read) { - case M25P80_QUAD: - flash->read_opcode = OPCODE_QUAD_READ; - break; - case M25P80_DUAL: - flash->read_opcode = OPCODE_DUAL_READ; - break; - case M25P80_FAST: - flash->read_opcode = OPCODE_FAST_READ; - break; - case M25P80_NORMAL: - flash->read_opcode = OPCODE_NORM_READ; - break; - default: - dev_err(&flash->spi->dev, "No Read opcode defined\n"); - return -EINVAL; - } - - flash->program_opcode = OPCODE_PP; - - if (info->addr_width) - flash->addr_width = info->addr_width; - else if (flash->mtd.size > 0x1000000) { - /* enable 4-byte addressing if the device exceeds 16MiB */ - flash->addr_width = 4; - if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { - /* Dedicated 4-byte command set */ - switch (flash->flash_read) { - case M25P80_QUAD: - flash->read_opcode = OPCODE_QUAD_READ_4B; - break; - case M25P80_DUAL: - flash->read_opcode = OPCODE_DUAL_READ_4B; - break; - case M25P80_FAST: - flash->read_opcode = OPCODE_FAST_READ_4B; - break; - case M25P80_NORMAL: - flash->read_opcode = OPCODE_NORM_READ_4B; - break; - } - flash->program_opcode = OPCODE_PP_4B; - /* No small sector erase for 4-byte command set */ - flash->erase_opcode = OPCODE_SE_4B; - flash->mtd.erasesize = info->sector_size; - } else - set_4byte(flash, info->jedec_id, 1); - } else { - flash->addr_width = 3; - } - - dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name, - (long long)flash->mtd.size >> 10); - - pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) " - ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", - flash->mtd.name, - (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), - flash->mtd.erasesize, flash->mtd.erasesize / 1024, - flash->mtd.numeraseregions); - - if (flash->mtd.numeraseregions) - for (i = 0; i < flash->mtd.numeraseregions; i++) - pr_debug("mtd.eraseregions[%d] = { .offset = 0x%llx, " - ".erasesize = 0x%.8x (%uKiB), " - ".numblocks = %d }\n", - i, (long long)flash->mtd.eraseregions[i].offset, - flash->mtd.eraseregions[i].erasesize, - flash->mtd.eraseregions[i].erasesize / 1024, - flash->mtd.eraseregions[i].numblocks); - - - /* partitions should match sector boundaries; and it may be good to - * use readonly partitions for writeprotected sectors (BP2..BP0). - */ return mtd_device_parse_register(&flash->mtd, NULL, &ppdata, data ? data->parts : NULL, data ? data->nr_parts : 0); @@ -1341,7 +248,7 @@ static struct spi_driver m25p80_driver = { .name = "m25p80", .owner = THIS_MODULE, }, - .id_table = m25p_ids, + .id_table = spi_nor_ids, .probe = m25p_probe, .remove = m25p_remove, diff --git a/drivers/mtd/devices/serial_flash_cmds.h b/drivers/mtd/devices/serial_flash_cmds.h index 4f0c2c7c898ea7..f59a125295d01d 100644 --- a/drivers/mtd/devices/serial_flash_cmds.h +++ b/drivers/mtd/devices/serial_flash_cmds.h @@ -13,43 +13,23 @@ #define _MTD_SERIAL_FLASH_CMDS_H /* Generic Flash Commands/OPCODEs */ -#define FLASH_CMD_WREN 0x06 -#define FLASH_CMD_WRDI 0x04 -#define FLASH_CMD_RDID 0x9f -#define FLASH_CMD_RDSR 0x05 -#define FLASH_CMD_RDSR2 0x35 -#define FLASH_CMD_WRSR 0x01 -#define FLASH_CMD_SE_4K 0x20 -#define FLASH_CMD_SE_32K 0x52 -#define FLASH_CMD_SE 0xd8 -#define FLASH_CMD_CHIPERASE 0xc7 -#define FLASH_CMD_WRVCR 0x81 -#define FLASH_CMD_RDVCR 0x85 +#define SPINOR_OP_RDSR2 0x35 +#define SPINOR_OP_WRVCR 0x81 +#define SPINOR_OP_RDVCR 0x85 /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */ -#define FLASH_CMD_READ 0x03 /* READ */ -#define FLASH_CMD_READ_FAST 0x0b /* FAST READ */ -#define FLASH_CMD_READ_1_1_2 0x3b /* DUAL OUTPUT READ */ -#define FLASH_CMD_READ_1_2_2 0xbb /* DUAL I/O READ */ -#define FLASH_CMD_READ_1_1_4 0x6b /* QUAD OUTPUT READ */ -#define FLASH_CMD_READ_1_4_4 0xeb /* QUAD I/O READ */ +#define SPINOR_OP_READ_1_2_2 0xbb /* DUAL I/O READ */ +#define SPINOR_OP_READ_1_4_4 0xeb /* QUAD I/O READ */ -#define FLASH_CMD_WRITE 0x02 /* PAGE PROGRAM */ -#define FLASH_CMD_WRITE_1_1_2 0xa2 /* DUAL INPUT PROGRAM */ -#define FLASH_CMD_WRITE_1_2_2 0xd2 /* DUAL INPUT EXT PROGRAM */ -#define FLASH_CMD_WRITE_1_1_4 0x32 /* QUAD INPUT PROGRAM */ -#define FLASH_CMD_WRITE_1_4_4 0x12 /* QUAD INPUT EXT PROGRAM */ - -#define FLASH_CMD_EN4B_ADDR 0xb7 /* Enter 4-byte address mode */ -#define FLASH_CMD_EX4B_ADDR 0xe9 /* Exit 4-byte address mode */ +#define SPINOR_OP_WRITE 0x02 /* PAGE PROGRAM */ +#define SPINOR_OP_WRITE_1_1_2 0xa2 /* DUAL INPUT PROGRAM */ +#define SPINOR_OP_WRITE_1_2_2 0xd2 /* DUAL INPUT EXT PROGRAM */ +#define SPINOR_OP_WRITE_1_1_4 0x32 /* QUAD INPUT PROGRAM */ +#define SPINOR_OP_WRITE_1_4_4 0x12 /* QUAD INPUT EXT PROGRAM */ /* READ commands with 32-bit addressing */ -#define FLASH_CMD_READ4 0x13 -#define FLASH_CMD_READ4_FAST 0x0c -#define FLASH_CMD_READ4_1_1_2 0x3c -#define FLASH_CMD_READ4_1_2_2 0xbc -#define FLASH_CMD_READ4_1_1_4 0x6c -#define FLASH_CMD_READ4_1_4_4 0xec +#define SPINOR_OP_READ4_1_2_2 0xbc +#define SPINOR_OP_READ4_1_4_4 0xec /* Configuration flags */ #define FLASH_FLAG_SINGLE 0x000000ff diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c index 1957d7c8e1853c..f97fe144077d77 100644 --- a/drivers/mtd/devices/st_spi_fsm.c +++ b/drivers/mtd/devices/st_spi_fsm.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -201,44 +202,6 @@ #define STFSM_MAX_WAIT_SEQ_MS 1000 /* FSM execution time */ -/* Flash Commands */ -#define FLASH_CMD_WREN 0x06 -#define FLASH_CMD_WRDI 0x04 -#define FLASH_CMD_RDID 0x9f -#define FLASH_CMD_RDSR 0x05 -#define FLASH_CMD_RDSR2 0x35 -#define FLASH_CMD_WRSR 0x01 -#define FLASH_CMD_SE_4K 0x20 -#define FLASH_CMD_SE_32K 0x52 -#define FLASH_CMD_SE 0xd8 -#define FLASH_CMD_CHIPERASE 0xc7 -#define FLASH_CMD_WRVCR 0x81 -#define FLASH_CMD_RDVCR 0x85 - -#define FLASH_CMD_READ 0x03 /* READ */ -#define FLASH_CMD_READ_FAST 0x0b /* FAST READ */ -#define FLASH_CMD_READ_1_1_2 0x3b /* DUAL OUTPUT READ */ -#define FLASH_CMD_READ_1_2_2 0xbb /* DUAL I/O READ */ -#define FLASH_CMD_READ_1_1_4 0x6b /* QUAD OUTPUT READ */ -#define FLASH_CMD_READ_1_4_4 0xeb /* QUAD I/O READ */ - -#define FLASH_CMD_WRITE 0x02 /* PAGE PROGRAM */ -#define FLASH_CMD_WRITE_1_1_2 0xa2 /* DUAL INPUT PROGRAM */ -#define FLASH_CMD_WRITE_1_2_2 0xd2 /* DUAL INPUT EXT PROGRAM */ -#define FLASH_CMD_WRITE_1_1_4 0x32 /* QUAD INPUT PROGRAM */ -#define FLASH_CMD_WRITE_1_4_4 0x12 /* QUAD INPUT EXT PROGRAM */ - -#define FLASH_CMD_EN4B_ADDR 0xb7 /* Enter 4-byte address mode */ -#define FLASH_CMD_EX4B_ADDR 0xe9 /* Exit 4-byte address mode */ - -/* READ commands with 32-bit addressing (N25Q256 and S25FLxxxS) */ -#define FLASH_CMD_READ4 0x13 -#define FLASH_CMD_READ4_FAST 0x0c -#define FLASH_CMD_READ4_1_1_2 0x3c -#define FLASH_CMD_READ4_1_2_2 0xbc -#define FLASH_CMD_READ4_1_1_4 0x6c -#define FLASH_CMD_READ4_1_4_4 0xec - /* S25FLxxxS commands */ #define S25FL_CMD_WRITE4_1_1_4 0x34 #define S25FL_CMD_SE4 0xdc @@ -246,7 +209,7 @@ #define S25FL_CMD_DYBWR 0xe1 #define S25FL_CMD_DYBRD 0xe0 #define S25FL_CMD_WRITE4 0x12 /* Note, opcode clashes with - * 'FLASH_CMD_WRITE_1_4_4' + * 'SPINOR_OP_WRITE_1_4_4' * as found on N25Qxxx devices! */ /* Status register */ @@ -261,6 +224,12 @@ #define S25FL_STATUS_E_ERR 0x20 #define S25FL_STATUS_P_ERR 0x40 +#define N25Q_CMD_WRVCR 0x81 +#define N25Q_CMD_RDVCR 0x85 +#define N25Q_CMD_RDVECR 0x65 +#define N25Q_CMD_RDNVCR 0xb5 +#define N25Q_CMD_WRNVCR 0xb1 + #define FLASH_PAGESIZE 256 /* In Bytes */ #define FLASH_PAGESIZE_32 (FLASH_PAGESIZE / 4) /* In uint32_t */ #define FLASH_MAX_BUSY_WAIT (300 * HZ) /* Maximum 'CHIPERASE' time */ @@ -270,7 +239,6 @@ */ #define CFG_READ_TOGGLE_32BIT_ADDR 0x00000001 #define CFG_WRITE_TOGGLE_32BIT_ADDR 0x00000002 -#define CFG_WRITE_EX_32BIT_ADDR_DELAY 0x00000004 #define CFG_ERASESEC_TOGGLE_32BIT_ADDR 0x00000008 #define CFG_S25FL_CHECK_ERROR_FLAGS 0x00000010 @@ -329,7 +297,7 @@ struct flash_info { u32 jedec_id; u16 ext_id; /* - * The size listed here is what works with FLASH_CMD_SE, which isn't + * The size listed here is what works with SPINOR_OP_SE, which isn't * necessarily called a "sector" by the vendor. */ unsigned sector_size; @@ -369,17 +337,26 @@ static struct flash_info flash_types[] = { { "m25px32", 0x207116, 0, 64 * 1024, 64, M25PX_FLAG, 75, NULL }, { "m25px64", 0x207117, 0, 64 * 1024, 128, M25PX_FLAG, 75, NULL }, + /* Macronix MX25xxx + * - Support for 'FLASH_FLAG_WRITE_1_4_4' is omitted for devices + * where operating frequency must be reduced. + */ #define MX25_FLAG (FLASH_FLAG_READ_WRITE | \ FLASH_FLAG_READ_FAST | \ FLASH_FLAG_READ_1_1_2 | \ FLASH_FLAG_READ_1_2_2 | \ FLASH_FLAG_READ_1_1_4 | \ - FLASH_FLAG_READ_1_4_4 | \ FLASH_FLAG_SE_4K | \ FLASH_FLAG_SE_32K) + { "mx25l3255e", 0xc29e16, 0, 64 * 1024, 64, + (MX25_FLAG | FLASH_FLAG_WRITE_1_4_4), 86, + stfsm_mx25_config}, { "mx25l25635e", 0xc22019, 0, 64*1024, 512, (MX25_FLAG | FLASH_FLAG_32BIT_ADDR | FLASH_FLAG_RESET), 70, stfsm_mx25_config }, + { "mx25l25655e", 0xc22619, 0, 64*1024, 512, + (MX25_FLAG | FLASH_FLAG_32BIT_ADDR | FLASH_FLAG_RESET), 70, + stfsm_mx25_config}, #define N25Q_FLAG (FLASH_FLAG_READ_WRITE | \ FLASH_FLAG_READ_FAST | \ @@ -407,6 +384,8 @@ static struct flash_info flash_types[] = { FLASH_FLAG_READ_1_4_4 | \ FLASH_FLAG_WRITE_1_1_4 | \ FLASH_FLAG_READ_FAST) + { "s25fl032p", 0x010215, 0x4d00, 64 * 1024, 64, S25FLXXXP_FLAG, 80, + stfsm_s25fl_config}, { "s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, S25FLXXXP_FLAG, 80, stfsm_s25fl_config }, { "s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, S25FLXXXP_FLAG, 80, @@ -473,22 +452,22 @@ static struct flash_info flash_types[] = { /* Default READ configurations, in order of preference */ static struct seq_rw_config default_read_configs[] = { - {FLASH_FLAG_READ_1_4_4, FLASH_CMD_READ_1_4_4, 0, 4, 4, 0x00, 2, 4}, - {FLASH_FLAG_READ_1_1_4, FLASH_CMD_READ_1_1_4, 0, 1, 4, 0x00, 4, 0}, - {FLASH_FLAG_READ_1_2_2, FLASH_CMD_READ_1_2_2, 0, 2, 2, 0x00, 4, 0}, - {FLASH_FLAG_READ_1_1_2, FLASH_CMD_READ_1_1_2, 0, 1, 2, 0x00, 0, 8}, - {FLASH_FLAG_READ_FAST, FLASH_CMD_READ_FAST, 0, 1, 1, 0x00, 0, 8}, - {FLASH_FLAG_READ_WRITE, FLASH_CMD_READ, 0, 1, 1, 0x00, 0, 0}, + {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4, 0, 4, 4, 0x00, 2, 4}, + {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4, 0, 1, 4, 0x00, 4, 0}, + {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2, 0, 2, 2, 0x00, 4, 0}, + {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2, 0, 1, 2, 0x00, 0, 8}, + {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST, 0, 1, 1, 0x00, 0, 8}, + {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ, 0, 1, 1, 0x00, 0, 0}, {0x00, 0, 0, 0, 0, 0x00, 0, 0}, }; /* Default WRITE configurations */ static struct seq_rw_config default_write_configs[] = { - {FLASH_FLAG_WRITE_1_4_4, FLASH_CMD_WRITE_1_4_4, 1, 4, 4, 0x00, 0, 0}, - {FLASH_FLAG_WRITE_1_1_4, FLASH_CMD_WRITE_1_1_4, 1, 1, 4, 0x00, 0, 0}, - {FLASH_FLAG_WRITE_1_2_2, FLASH_CMD_WRITE_1_2_2, 1, 2, 2, 0x00, 0, 0}, - {FLASH_FLAG_WRITE_1_1_2, FLASH_CMD_WRITE_1_1_2, 1, 1, 2, 0x00, 0, 0}, - {FLASH_FLAG_READ_WRITE, FLASH_CMD_WRITE, 1, 1, 1, 0x00, 0, 0}, + {FLASH_FLAG_WRITE_1_4_4, SPINOR_OP_WRITE_1_4_4, 1, 4, 4, 0x00, 0, 0}, + {FLASH_FLAG_WRITE_1_1_4, SPINOR_OP_WRITE_1_1_4, 1, 1, 4, 0x00, 0, 0}, + {FLASH_FLAG_WRITE_1_2_2, SPINOR_OP_WRITE_1_2_2, 1, 2, 2, 0x00, 0, 0}, + {FLASH_FLAG_WRITE_1_1_2, SPINOR_OP_WRITE_1_1_2, 1, 1, 2, 0x00, 0, 0}, + {FLASH_FLAG_READ_WRITE, SPINOR_OP_WRITE, 1, 1, 1, 0x00, 0, 0}, {0x00, 0, 0, 0, 0, 0x00, 0, 0}, }; @@ -511,12 +490,12 @@ static struct seq_rw_config default_write_configs[] = { * cycles. */ static struct seq_rw_config n25q_read3_configs[] = { - {FLASH_FLAG_READ_1_4_4, FLASH_CMD_READ_1_4_4, 0, 4, 4, 0x00, 0, 8}, - {FLASH_FLAG_READ_1_1_4, FLASH_CMD_READ_1_1_4, 0, 1, 4, 0x00, 0, 8}, - {FLASH_FLAG_READ_1_2_2, FLASH_CMD_READ_1_2_2, 0, 2, 2, 0x00, 0, 8}, - {FLASH_FLAG_READ_1_1_2, FLASH_CMD_READ_1_1_2, 0, 1, 2, 0x00, 0, 8}, - {FLASH_FLAG_READ_FAST, FLASH_CMD_READ_FAST, 0, 1, 1, 0x00, 0, 8}, - {FLASH_FLAG_READ_WRITE, FLASH_CMD_READ, 0, 1, 1, 0x00, 0, 0}, + {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4, 0, 4, 4, 0x00, 0, 8}, + {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4, 0, 1, 4, 0x00, 0, 8}, + {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2, 0, 2, 2, 0x00, 0, 8}, + {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2, 0, 1, 2, 0x00, 0, 8}, + {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST, 0, 1, 1, 0x00, 0, 8}, + {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ, 0, 1, 1, 0x00, 0, 0}, {0x00, 0, 0, 0, 0, 0x00, 0, 0}, }; @@ -526,12 +505,12 @@ static struct seq_rw_config n25q_read3_configs[] = { * - 'FAST' variants configured for 8 dummy cycles (see note above.) */ static struct seq_rw_config n25q_read4_configs[] = { - {FLASH_FLAG_READ_1_4_4, FLASH_CMD_READ4_1_4_4, 0, 4, 4, 0x00, 0, 8}, - {FLASH_FLAG_READ_1_1_4, FLASH_CMD_READ4_1_1_4, 0, 1, 4, 0x00, 0, 8}, - {FLASH_FLAG_READ_1_2_2, FLASH_CMD_READ4_1_2_2, 0, 2, 2, 0x00, 0, 8}, - {FLASH_FLAG_READ_1_1_2, FLASH_CMD_READ4_1_1_2, 0, 1, 2, 0x00, 0, 8}, - {FLASH_FLAG_READ_FAST, FLASH_CMD_READ4_FAST, 0, 1, 1, 0x00, 0, 8}, - {FLASH_FLAG_READ_WRITE, FLASH_CMD_READ4, 0, 1, 1, 0x00, 0, 0}, + {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4, 0, 4, 4, 0x00, 0, 8}, + {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4, 0, 1, 4, 0x00, 0, 8}, + {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2, 0, 2, 2, 0x00, 0, 8}, + {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2, 0, 1, 2, 0x00, 0, 8}, + {FLASH_FLAG_READ_FAST, SPINOR_OP_READ4_FAST, 0, 1, 1, 0x00, 0, 8}, + {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4, 0, 1, 1, 0x00, 0, 0}, {0x00, 0, 0, 0, 0, 0x00, 0, 0}, }; @@ -544,7 +523,7 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq) { seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_EN4B_ADDR) | + SEQ_OPC_OPCODE(SPINOR_OP_EN4B) | SEQ_OPC_CSDEASSERT); seq->seq[0] = STFSM_INST_CMD1; @@ -572,12 +551,12 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq) * entering a state that is incompatible with the SPIBoot Controller. */ static struct seq_rw_config stfsm_s25fl_read4_configs[] = { - {FLASH_FLAG_READ_1_4_4, FLASH_CMD_READ4_1_4_4, 0, 4, 4, 0x00, 2, 4}, - {FLASH_FLAG_READ_1_1_4, FLASH_CMD_READ4_1_1_4, 0, 1, 4, 0x00, 0, 8}, - {FLASH_FLAG_READ_1_2_2, FLASH_CMD_READ4_1_2_2, 0, 2, 2, 0x00, 4, 0}, - {FLASH_FLAG_READ_1_1_2, FLASH_CMD_READ4_1_1_2, 0, 1, 2, 0x00, 0, 8}, - {FLASH_FLAG_READ_FAST, FLASH_CMD_READ4_FAST, 0, 1, 1, 0x00, 0, 8}, - {FLASH_FLAG_READ_WRITE, FLASH_CMD_READ4, 0, 1, 1, 0x00, 0, 0}, + {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4, 0, 4, 4, 0x00, 2, 4}, + {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4, 0, 1, 4, 0x00, 0, 8}, + {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2, 0, 2, 2, 0x00, 4, 0}, + {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2, 0, 1, 2, 0x00, 0, 8}, + {FLASH_FLAG_READ_FAST, SPINOR_OP_READ4_FAST, 0, 1, 1, 0x00, 0, 8}, + {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4, 0, 1, 1, 0x00, 0, 0}, {0x00, 0, 0, 0, 0, 0x00, 0, 0}, }; @@ -590,13 +569,13 @@ static struct seq_rw_config stfsm_s25fl_write4_configs[] = { /* * [W25Qxxx] Configuration */ -#define W25Q_STATUS_QE (0x1 << 9) +#define W25Q_STATUS_QE (0x1 << 1) static struct stfsm_seq stfsm_seq_read_jedec = { .data_size = TRANSFER_SIZE(8), .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_RDID)), + SEQ_OPC_OPCODE(SPINOR_OP_RDID)), .seq = { STFSM_INST_CMD1, STFSM_INST_DATA_READ, @@ -612,7 +591,7 @@ static struct stfsm_seq stfsm_seq_read_status_fifo = { .data_size = TRANSFER_SIZE(4), .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_RDSR)), + SEQ_OPC_OPCODE(SPINOR_OP_RDSR)), .seq = { STFSM_INST_CMD1, STFSM_INST_DATA_READ, @@ -628,10 +607,10 @@ static struct stfsm_seq stfsm_seq_erase_sector = { /* 'addr_cfg' configured during initialisation */ .seq_opc = { (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT), + SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT), (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_SE)), + SEQ_OPC_OPCODE(SPINOR_OP_SE)), }, .seq = { STFSM_INST_CMD1, @@ -649,10 +628,10 @@ static struct stfsm_seq stfsm_seq_erase_sector = { static struct stfsm_seq stfsm_seq_erase_chip = { .seq_opc = { (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT), + SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT), (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_CHIPERASE) | SEQ_OPC_CSDEASSERT), + SEQ_OPC_OPCODE(SPINOR_OP_CHIP_ERASE) | SEQ_OPC_CSDEASSERT), }, .seq = { STFSM_INST_CMD1, @@ -669,26 +648,9 @@ static struct stfsm_seq stfsm_seq_erase_chip = { static struct stfsm_seq stfsm_seq_write_status = { .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT), - .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_WRSR)), - .seq = { - STFSM_INST_CMD1, - STFSM_INST_CMD2, - STFSM_INST_STA_WR1, - STFSM_INST_STOP, - }, - .seq_cfg = (SEQ_CFG_PADS_1 | - SEQ_CFG_READNOTWRITE | - SEQ_CFG_CSDEASSERT | - SEQ_CFG_STARTSEQ), -}; - -static struct stfsm_seq stfsm_seq_wrvcr = { - .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT), + SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT), .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_WRVCR)), + SEQ_OPC_OPCODE(SPINOR_OP_WRSR)), .seq = { STFSM_INST_CMD1, STFSM_INST_CMD2, @@ -704,9 +666,9 @@ static struct stfsm_seq stfsm_seq_wrvcr = { static int stfsm_n25q_en_32bit_addr_seq(struct stfsm_seq *seq) { seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_EN4B_ADDR)); + SEQ_OPC_OPCODE(SPINOR_OP_EN4B)); seq->seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_WREN) | + SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT); seq->seq[0] = STFSM_INST_CMD2; @@ -793,7 +755,7 @@ static void stfsm_read_fifo(struct stfsm *fsm, uint32_t *buf, uint32_t size) dev_dbg(fsm->dev, "Reading %d bytes from FIFO\n", size); - BUG_ON((((uint32_t)buf) & 0x3) || (size & 0x3)); + BUG_ON((((uintptr_t)buf) & 0x3) || (size & 0x3)); while (remaining) { for (;;) { @@ -817,7 +779,7 @@ static int stfsm_write_fifo(struct stfsm *fsm, const uint32_t *buf, dev_dbg(fsm->dev, "writing %d bytes to FIFO\n", size); - BUG_ON((((uint32_t)buf) & 0x3) || (size & 0x3)); + BUG_ON((((uintptr_t)buf) & 0x3) || (size & 0x3)); writesl(fsm->base + SPI_FAST_SEQ_DATA_REG, buf, words); @@ -827,7 +789,7 @@ static int stfsm_write_fifo(struct stfsm *fsm, const uint32_t *buf, static int stfsm_enter_32bit_addr(struct stfsm *fsm, int enter) { struct stfsm_seq *seq = &fsm->stfsm_seq_en_32bit_addr; - uint32_t cmd = enter ? FLASH_CMD_EN4B_ADDR : FLASH_CMD_EX4B_ADDR; + uint32_t cmd = enter ? SPINOR_OP_EN4B : SPINOR_OP_EX4B; seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | @@ -851,7 +813,7 @@ static uint8_t stfsm_wait_busy(struct stfsm *fsm) /* Use RDRS1 */ seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_RDSR)); + SEQ_OPC_OPCODE(SPINOR_OP_RDSR)); /* Load read_status sequence */ stfsm_load_seq(fsm, seq); @@ -889,60 +851,57 @@ static uint8_t stfsm_wait_busy(struct stfsm *fsm) } static int stfsm_read_status(struct stfsm *fsm, uint8_t cmd, - uint8_t *status) + uint8_t *data, int bytes) { struct stfsm_seq *seq = &stfsm_seq_read_status_fifo; uint32_t tmp; + uint8_t *t = (uint8_t *)&tmp; + int i; - dev_dbg(fsm->dev, "reading STA[%s]\n", - (cmd == FLASH_CMD_RDSR) ? "1" : "2"); + dev_dbg(fsm->dev, "read 'status' register [0x%02x], %d byte(s)\n", + cmd, bytes); - seq->seq_opc[0] = (SEQ_OPC_PADS_1 | - SEQ_OPC_CYCLES(8) | + BUG_ON(bytes != 1 && bytes != 2); + + seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | SEQ_OPC_OPCODE(cmd)), stfsm_load_seq(fsm, seq); stfsm_read_fifo(fsm, &tmp, 4); - *status = (uint8_t)(tmp >> 24); + for (i = 0; i < bytes; i++) + data[i] = t[i]; stfsm_wait_seq(fsm); return 0; } -static int stfsm_write_status(struct stfsm *fsm, uint16_t status, - int sta_bytes) +static int stfsm_write_status(struct stfsm *fsm, uint8_t cmd, + uint16_t data, int bytes, int wait_busy) { struct stfsm_seq *seq = &stfsm_seq_write_status; - dev_dbg(fsm->dev, "writing STA[%s] 0x%04x\n", - (sta_bytes == 1) ? "1" : "1+2", status); - - seq->status = (uint32_t)status | STA_PADS_1 | STA_CSDEASSERT; - seq->seq[2] = (sta_bytes == 1) ? - STFSM_INST_STA_WR1 : STFSM_INST_STA_WR1_2; - - stfsm_load_seq(fsm, seq); - - stfsm_wait_seq(fsm); + dev_dbg(fsm->dev, + "write 'status' register [0x%02x], %d byte(s), 0x%04x\n" + " %s wait-busy\n", cmd, bytes, data, wait_busy ? "with" : "no"); - return 0; -}; + BUG_ON(bytes != 1 && bytes != 2); -static int stfsm_wrvcr(struct stfsm *fsm, uint8_t data) -{ - struct stfsm_seq *seq = &stfsm_seq_wrvcr; - - dev_dbg(fsm->dev, "writing VCR 0x%02x\n", data); + seq->seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | + SEQ_OPC_OPCODE(cmd)); - seq->status = (STA_DATA_BYTE1(data) | STA_PADS_1 | STA_CSDEASSERT); + seq->status = (uint32_t)data | STA_PADS_1 | STA_CSDEASSERT; + seq->seq[2] = (bytes == 1) ? STFSM_INST_STA_WR1 : STFSM_INST_STA_WR1_2; stfsm_load_seq(fsm, seq); stfsm_wait_seq(fsm); + if (wait_busy) + stfsm_wait_busy(fsm); + return 0; } @@ -1027,7 +986,7 @@ static void stfsm_prepare_rw_seq(struct stfsm *fsm, if (cfg->write) seq->seq_opc[i++] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_WREN) | + SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT); /* Address configuration (24 or 32-bit addresses) */ @@ -1149,31 +1108,36 @@ static int stfsm_mx25_config(struct stfsm *fsm) stfsm_mx25_en_32bit_addr_seq(&fsm->stfsm_seq_en_32bit_addr); soc_reset = stfsm_can_handle_soc_reset(fsm); - if (soc_reset || !fsm->booted_from_spi) { + if (soc_reset || !fsm->booted_from_spi) /* If we can handle SoC resets, we enable 32-bit address * mode pervasively */ stfsm_enter_32bit_addr(fsm, 1); - } else { + else /* Else, enable/disable 32-bit addressing before/after * each operation */ fsm->configuration = (CFG_READ_TOGGLE_32BIT_ADDR | CFG_WRITE_TOGGLE_32BIT_ADDR | CFG_ERASESEC_TOGGLE_32BIT_ADDR); - /* It seems a small delay is required after exiting - * 32-bit mode following a write operation. The issue - * is under investigation. - */ - fsm->configuration |= CFG_WRITE_EX_32BIT_ADDR_DELAY; - } } - /* For QUAD mode, set 'QE' STATUS bit */ + /* Check status of 'QE' bit, update if required. */ + stfsm_read_status(fsm, SPINOR_OP_RDSR, &sta, 1); data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1; if (data_pads == 4) { - stfsm_read_status(fsm, FLASH_CMD_RDSR, &sta); - sta |= MX25_STATUS_QE; - stfsm_write_status(fsm, sta, 1); + if (!(sta & MX25_STATUS_QE)) { + /* Set 'QE' */ + sta |= MX25_STATUS_QE; + + stfsm_write_status(fsm, SPINOR_OP_WRSR, sta, 1, 1); + } + } else { + if (sta & MX25_STATUS_QE) { + /* Clear 'QE' */ + sta &= ~MX25_STATUS_QE; + + stfsm_write_status(fsm, SPINOR_OP_WRSR, sta, 1, 1); + } } return 0; @@ -1239,7 +1203,7 @@ static int stfsm_n25q_config(struct stfsm *fsm) */ vcr = (N25Q_VCR_DUMMY_CYCLES(8) | N25Q_VCR_XIP_DISABLED | N25Q_VCR_WRAP_CONT); - stfsm_wrvcr(fsm, vcr); + stfsm_write_status(fsm, N25Q_CMD_WRVCR, vcr, 1, 0); return 0; } @@ -1297,7 +1261,7 @@ static void stfsm_s25fl_write_dyb(struct stfsm *fsm, uint32_t offs, uint8_t dby) { struct stfsm_seq seq = { .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_WREN) | + SEQ_OPC_OPCODE(SPINOR_OP_WREN) | SEQ_OPC_CSDEASSERT), .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | SEQ_OPC_OPCODE(S25FL_CMD_DYBWR)), @@ -1337,7 +1301,7 @@ static int stfsm_s25fl_clear_status_reg(struct stfsm *fsm) SEQ_OPC_CSDEASSERT), .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | - SEQ_OPC_OPCODE(FLASH_CMD_WRDI) | + SEQ_OPC_OPCODE(SPINOR_OP_WRDI) | SEQ_OPC_CSDEASSERT), .seq = { STFSM_INST_CMD1, @@ -1367,6 +1331,7 @@ static int stfsm_s25fl_config(struct stfsm *fsm) uint32_t offs; uint16_t sta_wr; uint8_t sr1, cr1, dyb; + int update_sr = 0; int ret; if (flags & FLASH_FLAG_32BIT_ADDR) { @@ -1414,34 +1379,28 @@ static int stfsm_s25fl_config(struct stfsm *fsm) } } - /* Check status of 'QE' bit */ + /* Check status of 'QE' bit, update if required. */ + stfsm_read_status(fsm, SPINOR_OP_RDSR2, &cr1, 1); data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1; - stfsm_read_status(fsm, FLASH_CMD_RDSR2, &cr1); if (data_pads == 4) { if (!(cr1 & STFSM_S25FL_CONFIG_QE)) { /* Set 'QE' */ cr1 |= STFSM_S25FL_CONFIG_QE; - stfsm_read_status(fsm, FLASH_CMD_RDSR, &sr1); - sta_wr = ((uint16_t)cr1 << 8) | sr1; - - stfsm_write_status(fsm, sta_wr, 2); - - stfsm_wait_busy(fsm); + update_sr = 1; } } else { - if ((cr1 & STFSM_S25FL_CONFIG_QE)) { + if (cr1 & STFSM_S25FL_CONFIG_QE) { /* Clear 'QE' */ cr1 &= ~STFSM_S25FL_CONFIG_QE; - stfsm_read_status(fsm, FLASH_CMD_RDSR, &sr1); - sta_wr = ((uint16_t)cr1 << 8) | sr1; - - stfsm_write_status(fsm, sta_wr, 2); - - stfsm_wait_busy(fsm); + update_sr = 1; } - + } + if (update_sr) { + stfsm_read_status(fsm, SPINOR_OP_RDSR, &sr1, 1); + sta_wr = ((uint16_t)cr1 << 8) | sr1; + stfsm_write_status(fsm, SPINOR_OP_WRSR, sta_wr, 2, 1); } /* @@ -1456,27 +1415,36 @@ static int stfsm_s25fl_config(struct stfsm *fsm) static int stfsm_w25q_config(struct stfsm *fsm) { uint32_t data_pads; - uint16_t sta_wr; - uint8_t sta1, sta2; + uint8_t sr1, sr2; + uint16_t sr_wr; + int update_sr = 0; int ret; ret = stfsm_prepare_rwe_seqs_default(fsm); if (ret) return ret; - /* If using QUAD mode, set QE STATUS bit */ + /* Check status of 'QE' bit, update if required. */ + stfsm_read_status(fsm, SPINOR_OP_RDSR2, &sr2, 1); data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1; if (data_pads == 4) { - stfsm_read_status(fsm, FLASH_CMD_RDSR, &sta1); - stfsm_read_status(fsm, FLASH_CMD_RDSR2, &sta2); - - sta_wr = ((uint16_t)sta2 << 8) | sta1; - - sta_wr |= W25Q_STATUS_QE; - - stfsm_write_status(fsm, sta_wr, 2); - - stfsm_wait_busy(fsm); + if (!(sr2 & W25Q_STATUS_QE)) { + /* Set 'QE' */ + sr2 |= W25Q_STATUS_QE; + update_sr = 1; + } + } else { + if (sr2 & W25Q_STATUS_QE) { + /* Clear 'QE' */ + sr2 &= ~W25Q_STATUS_QE; + update_sr = 1; + } + } + if (update_sr) { + /* Write status register */ + stfsm_read_status(fsm, SPINOR_OP_RDSR, &sr1, 1); + sr_wr = ((uint16_t)sr2 << 8) | sr1; + stfsm_write_status(fsm, SPINOR_OP_WRSR, sr_wr, 2, 1); } return 0; @@ -1506,7 +1474,7 @@ static int stfsm_read(struct stfsm *fsm, uint8_t *buf, uint32_t size, read_mask = (data_pads << 2) - 1; /* Handle non-aligned buf */ - p = ((uint32_t)buf & 0x3) ? (uint8_t *)page_buf : buf; + p = ((uintptr_t)buf & 0x3) ? (uint8_t *)page_buf : buf; /* Handle non-aligned size */ size_ub = (size + read_mask) & ~read_mask; @@ -1528,7 +1496,7 @@ static int stfsm_read(struct stfsm *fsm, uint8_t *buf, uint32_t size, } /* Handle non-aligned buf */ - if ((uint32_t)buf & 0x3) + if ((uintptr_t)buf & 0x3) memcpy(buf, page_buf, size); /* Wait for sequence to finish */ @@ -1570,7 +1538,7 @@ static int stfsm_write(struct stfsm *fsm, const uint8_t *buf, write_mask = (data_pads << 2) - 1; /* Handle non-aligned buf */ - if ((uint32_t)buf & 0x3) { + if ((uintptr_t)buf & 0x3) { memcpy(page_buf, buf, size); p = (uint8_t *)page_buf; } else { @@ -1628,11 +1596,8 @@ static int stfsm_write(struct stfsm *fsm, const uint8_t *buf, stfsm_s25fl_clear_status_reg(fsm); /* Exit 32-bit address mode, if required */ - if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR) { + if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR) stfsm_enter_32bit_addr(fsm, 0); - if (fsm->configuration & CFG_WRITE_EX_32BIT_ADDR_DELAY) - udelay(1); - } return 0; } @@ -1736,7 +1701,7 @@ static int stfsm_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, while (len) { /* Write up to page boundary */ - bytes = min(FLASH_PAGESIZE - page_offs, len); + bytes = min_t(size_t, FLASH_PAGESIZE - page_offs, len); ret = stfsm_write(fsm, b, bytes, to); if (ret) @@ -1935,6 +1900,13 @@ static int stfsm_init(struct stfsm *fsm) fsm->base + SPI_CONFIGDATA); writel(STFSM_DEFAULT_WR_TIME, fsm->base + SPI_STATUS_WR_TIME_REG); + /* + * Set the FSM 'WAIT' delay to the minimum workable value. Note, for + * our purposes, the WAIT instruction is used purely to achieve + * "sequence validity" rather than actually implement a delay. + */ + writel(0x00000001, fsm->base + SPI_PROGRAM_ERASE_TIME); + /* Clear FIFO, just in case */ stfsm_clear_fifo(fsm); diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 0b2ccb68c0d024..43e30992a3697a 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -82,12 +82,14 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, block = blk_rq_pos(req) << 9 >> tr->blkshift; nsect = blk_rq_cur_bytes(req) >> tr->blkshift; - - buf = req->buffer; + buf = bio_data(req->bio); if (req->cmd_type != REQ_TYPE_FS) return -EIO; + if (req->cmd_flags & REQ_FLUSH) + return tr->flush(dev); + if (blk_rq_pos(req) + blk_rq_cur_sectors(req) > get_capacity(req->rq_disk)) return -EIO; @@ -408,6 +410,9 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) if (!new->rq) goto error3; + if (tr->flush) + blk_queue_flush(new->rq, REQ_FLUSH); + new->rq->queuedata = new; blk_queue_logical_block_size(new->rq, tr->blksize); diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index c07cd573ad3af0..9f2012a3e76435 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1233,7 +1233,7 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) return status; } -static void denali_erase(struct mtd_info *mtd, int page) +static int denali_erase(struct mtd_info *mtd, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); @@ -1250,8 +1250,7 @@ static void denali_erase(struct mtd_info *mtd, int page) irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP | INTR_STATUS__ERASE_FAIL); - denali->status = (irq_status & INTR_STATUS__ERASE_FAIL) ? - NAND_STATUS_FAIL : PASS; + return (irq_status & INTR_STATUS__ERASE_FAIL) ? NAND_STATUS_FAIL : PASS; } static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, @@ -1584,7 +1583,7 @@ int denali_init(struct denali_nand_info *denali) denali->nand.ecc.write_page_raw = denali_write_page_raw; denali->nand.ecc.read_oob = denali_read_oob; denali->nand.ecc.write_oob = denali_write_oob; - denali->nand.erase_cmd = denali_erase; + denali->nand.erase = denali_erase; if (nand_scan_tail(&denali->mtd)) { ret = -ENXIO; diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 1b0265e85a066b..ce24637e14f176 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -872,7 +872,7 @@ static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand, return 0; } -static void docg4_erase_block(struct mtd_info *mtd, int page) +static int docg4_erase_block(struct mtd_info *mtd, int page) { struct nand_chip *nand = mtd->priv; struct docg4_priv *doc = nand->priv; @@ -916,6 +916,8 @@ static void docg4_erase_block(struct mtd_info *mtd, int page) write_nop(docptr); poll_status(doc); write_nop(docptr); + + return nand->waitfunc(mtd, nand); } static int write_page(struct mtd_info *mtd, struct nand_chip *nand, @@ -1236,7 +1238,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd) nand->block_markbad = docg4_block_markbad; nand->read_buf = docg4_read_buf; nand->write_buf = docg4_write_buf16; - nand->erase_cmd = docg4_erase_block; + nand->erase = docg4_erase_block; nand->ecc.read_page = docg4_read_page; nand->ecc.write_page = docg4_write_page; nand->ecc.read_page_raw = docg4_read_page_raw; diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index dd1df605a1d61e..ec4db2a359e5de 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -861,7 +861,7 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this, struct resources *r = &this->resources; unsigned long rate = clk_get_rate(r->clock[0]); int mode = this->timing_mode; - int dll_threshold = 16; /* in ns */ + int dll_threshold = this->devdata->max_chain_delay; unsigned long delay; unsigned long clk_period; int t_rea; @@ -886,9 +886,6 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this, /* [3] for GPMI_HW_GPMI_CTRL1 */ hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; - if (GPMI_IS_MX6Q(this)) - dll_threshold = 12; - /* * Enlarge 10 times for the numerator and denominator in {3}. * This make us to get more accurate result. diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index bb77f750e75a3b..e88d64e1e9632d 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -53,6 +53,24 @@ static struct nand_ecclayout gpmi_hw_ecclayout = { .oobfree = { {.offset = 0, .length = 0} } }; +static const struct gpmi_devdata gpmi_devdata_imx23 = { + .type = IS_MX23, + .bch_max_ecc_strength = 20, + .max_chain_delay = 16, +}; + +static const struct gpmi_devdata gpmi_devdata_imx28 = { + .type = IS_MX28, + .bch_max_ecc_strength = 20, + .max_chain_delay = 16, +}; + +static const struct gpmi_devdata gpmi_devdata_imx6q = { + .type = IS_MX6Q, + .bch_max_ecc_strength = 40, + .max_chain_delay = 12, +}; + static irqreturn_t bch_irq(int irq, void *cookie) { struct gpmi_nand_data *this = cookie; @@ -102,14 +120,8 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this) /* The mx23/mx28 only support the GF13. */ if (geo->gf_len == 14) return false; - - if (geo->ecc_strength > MXS_ECC_STRENGTH_MAX) - return false; - } else if (GPMI_IS_MX6Q(this)) { - if (geo->ecc_strength > MX6_ECC_STRENGTH_MAX) - return false; } - return true; + return geo->ecc_strength <= this->devdata->bch_max_ecc_strength; } /* @@ -270,8 +282,7 @@ static int legacy_set_geometry(struct gpmi_nand_data *this) "We can not support this nand chip." " Its required ecc strength(%d) is beyond our" " capability(%d).\n", geo->ecc_strength, - (GPMI_IS_MX6Q(this) ? MX6_ECC_STRENGTH_MAX - : MXS_ECC_STRENGTH_MAX)); + this->devdata->bch_max_ecc_strength); return -EINVAL; } @@ -1740,23 +1751,16 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) return ret; } -static const struct platform_device_id gpmi_ids[] = { - { .name = "imx23-gpmi-nand", .driver_data = IS_MX23, }, - { .name = "imx28-gpmi-nand", .driver_data = IS_MX28, }, - { .name = "imx6q-gpmi-nand", .driver_data = IS_MX6Q, }, - {} -}; - static const struct of_device_id gpmi_nand_id_table[] = { { .compatible = "fsl,imx23-gpmi-nand", - .data = (void *)&gpmi_ids[IS_MX23], + .data = (void *)&gpmi_devdata_imx23, }, { .compatible = "fsl,imx28-gpmi-nand", - .data = (void *)&gpmi_ids[IS_MX28], + .data = (void *)&gpmi_devdata_imx28, }, { .compatible = "fsl,imx6q-gpmi-nand", - .data = (void *)&gpmi_ids[IS_MX6Q], + .data = (void *)&gpmi_devdata_imx6q, }, {} }; MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); @@ -1767,18 +1771,18 @@ static int gpmi_nand_probe(struct platform_device *pdev) const struct of_device_id *of_id; int ret; + this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL); + if (!this) + return -ENOMEM; + of_id = of_match_device(gpmi_nand_id_table, &pdev->dev); if (of_id) { - pdev->id_entry = of_id->data; + this->devdata = of_id->data; } else { dev_err(&pdev->dev, "Failed to find the right device id.\n"); return -ENODEV; } - this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL); - if (!this) - return -ENOMEM; - platform_set_drvdata(pdev, this); this->pdev = pdev; this->dev = &pdev->dev; @@ -1823,7 +1827,6 @@ static struct platform_driver gpmi_nand_driver = { }, .probe = gpmi_nand_probe, .remove = gpmi_nand_remove, - .id_table = gpmi_ids, }; module_platform_driver(gpmi_nand_driver); diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index 4c801fa1872530..7904e8329b67c0 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -119,11 +119,24 @@ struct nand_timing { int8_t tRHOH_in_ns; }; +enum gpmi_type { + IS_MX23, + IS_MX28, + IS_MX6Q +}; + +struct gpmi_devdata { + enum gpmi_type type; + int bch_max_ecc_strength; + int max_chain_delay; /* See the async EDO mode */ +}; + struct gpmi_nand_data { /* flags */ #define GPMI_ASYNC_EDO_ENABLED (1 << 0) #define GPMI_TIMING_INIT_OK (1 << 1) int flags; + const struct gpmi_devdata *devdata; /* System Interface */ struct device *dev; @@ -281,15 +294,8 @@ extern int gpmi_read_page(struct gpmi_nand_data *, #define STATUS_ERASED 0xff #define STATUS_UNCORRECTABLE 0xfe -/* BCH's bit correction capability. */ -#define MXS_ECC_STRENGTH_MAX 20 /* mx23 and mx28 */ -#define MX6_ECC_STRENGTH_MAX 40 - -/* Use the platform_id to distinguish different Archs. */ -#define IS_MX23 0x0 -#define IS_MX28 0x1 -#define IS_MX6Q 0x2 -#define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23) -#define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28) -#define GPMI_IS_MX6Q(x) ((x)->pdev->id_entry->driver_data == IS_MX6Q) +/* Use the devdata to distinguish different Archs. */ +#define GPMI_IS_MX23(x) ((x)->devdata->type == IS_MX23) +#define GPMI_IS_MX28(x) ((x)->devdata->type == IS_MX28) +#define GPMI_IS_MX6Q(x) ((x)->devdata->type == IS_MX6Q) #endif diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 9d01c4df838c91..7853b9b0a05ed8 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1204,8 +1204,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, * ecc.pos. Let's make sure that there are no gaps in ECC positions. */ for (i = 0; i < eccfrag_len - 1; i++) { - if (eccpos[i + start_step * chip->ecc.bytes] + 1 != - eccpos[i + start_step * chip->ecc.bytes + 1]) { + if (eccpos[i + index] + 1 != eccpos[i + index + 1]) { gaps = 1; break; } @@ -2618,18 +2617,20 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, } /** - * single_erase_cmd - [GENERIC] NAND standard block erase command function + * single_erase - [GENERIC] NAND standard block erase command function * @mtd: MTD device structure * @page: the page address of the block which will be erased * - * Standard erase command for NAND chips. + * Standard erase command for NAND chips. Returns NAND status. */ -static void single_erase_cmd(struct mtd_info *mtd, int page) +static int single_erase(struct mtd_info *mtd, int page) { struct nand_chip *chip = mtd->priv; /* Send commands to erase a block */ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); + + return chip->waitfunc(mtd, chip); } /** @@ -2710,9 +2711,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, (page + pages_per_block)) chip->pagebuf = -1; - chip->erase_cmd(mtd, page & chip->pagemask); - - status = chip->waitfunc(mtd, chip); + status = chip->erase(mtd, page & chip->pagemask); /* * See if operation failed and additional status checks are @@ -3607,7 +3606,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->onfi_version = 0; if (!type->name || !type->pagesize) { - /* Check is chip is ONFI compliant */ + /* Check if the chip is ONFI compliant */ if (nand_flash_detect_onfi(mtd, chip, &busw)) goto ident_done; @@ -3685,7 +3684,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, } chip->badblockbits = 8; - chip->erase_cmd = single_erase_cmd; + chip->erase = single_erase; /* Do not replace user supplied command function! */ if (mtd->writesize > 512 && chip->cmdfunc == nand_command) diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 053c9a2d47c3d0..97c4c0216c9072 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -506,7 +506,7 @@ int __nand_correct_data(unsigned char *buf, if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1) return 1; /* error in ECC data; no action needed */ - pr_err("%s: uncorrectable ECC error", __func__); + pr_err("%s: uncorrectable ECC error\n", __func__); return -1; } EXPORT_SYMBOL(__nand_correct_data); diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 42e8a770e631c6..4f0d83648e5a5a 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -575,12 +575,12 @@ static int alloc_device(struct nandsim *ns) cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600); if (IS_ERR(cfile)) return PTR_ERR(cfile); - if (!cfile->f_op->read && !cfile->f_op->aio_read) { + if (!(cfile->f_mode & FMODE_CAN_READ)) { NS_ERR("alloc_device: cache file not readable\n"); err = -EINVAL; goto err_close; } - if (!cfile->f_op->write && !cfile->f_op->aio_write) { + if (!(cfile->f_mode & FMODE_CAN_WRITE)) { NS_ERR("alloc_device: cache file not writeable\n"); err = -EINVAL; goto err_close; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 1ff49b80bdaf7e..1b800bcda5a475 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1237,6 +1237,7 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, return 0; } +#ifdef CONFIG_MTD_NAND_OMAP_BCH /** * erased_sector_bitflips - count bit flips * @data: data sector buffer @@ -1276,7 +1277,6 @@ static int erased_sector_bitflips(u_char *data, u_char *oob, return flip_bits; } -#ifdef CONFIG_MTD_NAND_OMAP_BCH /** * omap_elm_correct_data - corrects page data area in case error reported * @mtd: MTD device structure diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig new file mode 100644 index 00000000000000..f8acfa4310efac --- /dev/null +++ b/drivers/mtd/spi-nor/Kconfig @@ -0,0 +1,17 @@ +menuconfig MTD_SPI_NOR + tristate "SPI-NOR device support" + depends on MTD + help + This is the framework for the SPI NOR which can be used by the SPI + device drivers and the SPI-NOR device driver. + +if MTD_SPI_NOR + +config SPI_FSL_QUADSPI + tristate "Freescale Quad SPI controller" + depends on ARCH_MXC + help + This enables support for the Quad SPI controller in master mode. + We only connect the NOR to this controller now. + +endif # MTD_SPI_NOR diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile new file mode 100644 index 00000000000000..6a7ce1462247f4 --- /dev/null +++ b/drivers/mtd/spi-nor/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o +obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c new file mode 100644 index 00000000000000..8d659a2888d5f0 --- /dev/null +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -0,0 +1,1009 @@ +/* + * Freescale QuadSPI driver. + * + * Copyright (C) 2013 Freescale Semiconductor, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The registers */ +#define QUADSPI_MCR 0x00 +#define QUADSPI_MCR_RESERVED_SHIFT 16 +#define QUADSPI_MCR_RESERVED_MASK (0xF << QUADSPI_MCR_RESERVED_SHIFT) +#define QUADSPI_MCR_MDIS_SHIFT 14 +#define QUADSPI_MCR_MDIS_MASK (1 << QUADSPI_MCR_MDIS_SHIFT) +#define QUADSPI_MCR_CLR_TXF_SHIFT 11 +#define QUADSPI_MCR_CLR_TXF_MASK (1 << QUADSPI_MCR_CLR_TXF_SHIFT) +#define QUADSPI_MCR_CLR_RXF_SHIFT 10 +#define QUADSPI_MCR_CLR_RXF_MASK (1 << QUADSPI_MCR_CLR_RXF_SHIFT) +#define QUADSPI_MCR_DDR_EN_SHIFT 7 +#define QUADSPI_MCR_DDR_EN_MASK (1 << QUADSPI_MCR_DDR_EN_SHIFT) +#define QUADSPI_MCR_END_CFG_SHIFT 2 +#define QUADSPI_MCR_END_CFG_MASK (3 << QUADSPI_MCR_END_CFG_SHIFT) +#define QUADSPI_MCR_SWRSTHD_SHIFT 1 +#define QUADSPI_MCR_SWRSTHD_MASK (1 << QUADSPI_MCR_SWRSTHD_SHIFT) +#define QUADSPI_MCR_SWRSTSD_SHIFT 0 +#define QUADSPI_MCR_SWRSTSD_MASK (1 << QUADSPI_MCR_SWRSTSD_SHIFT) + +#define QUADSPI_IPCR 0x08 +#define QUADSPI_IPCR_SEQID_SHIFT 24 +#define QUADSPI_IPCR_SEQID_MASK (0xF << QUADSPI_IPCR_SEQID_SHIFT) + +#define QUADSPI_BUF0CR 0x10 +#define QUADSPI_BUF1CR 0x14 +#define QUADSPI_BUF2CR 0x18 +#define QUADSPI_BUFXCR_INVALID_MSTRID 0xe + +#define QUADSPI_BUF3CR 0x1c +#define QUADSPI_BUF3CR_ALLMST_SHIFT 31 +#define QUADSPI_BUF3CR_ALLMST (1 << QUADSPI_BUF3CR_ALLMST_SHIFT) + +#define QUADSPI_BFGENCR 0x20 +#define QUADSPI_BFGENCR_PAR_EN_SHIFT 16 +#define QUADSPI_BFGENCR_PAR_EN_MASK (1 << (QUADSPI_BFGENCR_PAR_EN_SHIFT)) +#define QUADSPI_BFGENCR_SEQID_SHIFT 12 +#define QUADSPI_BFGENCR_SEQID_MASK (0xF << QUADSPI_BFGENCR_SEQID_SHIFT) + +#define QUADSPI_BUF0IND 0x30 +#define QUADSPI_BUF1IND 0x34 +#define QUADSPI_BUF2IND 0x38 +#define QUADSPI_SFAR 0x100 + +#define QUADSPI_SMPR 0x108 +#define QUADSPI_SMPR_DDRSMP_SHIFT 16 +#define QUADSPI_SMPR_DDRSMP_MASK (7 << QUADSPI_SMPR_DDRSMP_SHIFT) +#define QUADSPI_SMPR_FSDLY_SHIFT 6 +#define QUADSPI_SMPR_FSDLY_MASK (1 << QUADSPI_SMPR_FSDLY_SHIFT) +#define QUADSPI_SMPR_FSPHS_SHIFT 5 +#define QUADSPI_SMPR_FSPHS_MASK (1 << QUADSPI_SMPR_FSPHS_SHIFT) +#define QUADSPI_SMPR_HSENA_SHIFT 0 +#define QUADSPI_SMPR_HSENA_MASK (1 << QUADSPI_SMPR_HSENA_SHIFT) + +#define QUADSPI_RBSR 0x10c +#define QUADSPI_RBSR_RDBFL_SHIFT 8 +#define QUADSPI_RBSR_RDBFL_MASK (0x3F << QUADSPI_RBSR_RDBFL_SHIFT) + +#define QUADSPI_RBCT 0x110 +#define QUADSPI_RBCT_WMRK_MASK 0x1F +#define QUADSPI_RBCT_RXBRD_SHIFT 8 +#define QUADSPI_RBCT_RXBRD_USEIPS (0x1 << QUADSPI_RBCT_RXBRD_SHIFT) + +#define QUADSPI_TBSR 0x150 +#define QUADSPI_TBDR 0x154 +#define QUADSPI_SR 0x15c +#define QUADSPI_SR_IP_ACC_SHIFT 1 +#define QUADSPI_SR_IP_ACC_MASK (0x1 << QUADSPI_SR_IP_ACC_SHIFT) +#define QUADSPI_SR_AHB_ACC_SHIFT 2 +#define QUADSPI_SR_AHB_ACC_MASK (0x1 << QUADSPI_SR_AHB_ACC_SHIFT) + +#define QUADSPI_FR 0x160 +#define QUADSPI_FR_TFF_MASK 0x1 + +#define QUADSPI_SFA1AD 0x180 +#define QUADSPI_SFA2AD 0x184 +#define QUADSPI_SFB1AD 0x188 +#define QUADSPI_SFB2AD 0x18c +#define QUADSPI_RBDR 0x200 + +#define QUADSPI_LUTKEY 0x300 +#define QUADSPI_LUTKEY_VALUE 0x5AF05AF0 + +#define QUADSPI_LCKCR 0x304 +#define QUADSPI_LCKER_LOCK 0x1 +#define QUADSPI_LCKER_UNLOCK 0x2 + +#define QUADSPI_RSER 0x164 +#define QUADSPI_RSER_TFIE (0x1 << 0) + +#define QUADSPI_LUT_BASE 0x310 + +/* + * The definition of the LUT register shows below: + * + * --------------------------------------------------- + * | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 | + * --------------------------------------------------- + */ +#define OPRND0_SHIFT 0 +#define PAD0_SHIFT 8 +#define INSTR0_SHIFT 10 +#define OPRND1_SHIFT 16 + +/* Instruction set for the LUT register. */ +#define LUT_STOP 0 +#define LUT_CMD 1 +#define LUT_ADDR 2 +#define LUT_DUMMY 3 +#define LUT_MODE 4 +#define LUT_MODE2 5 +#define LUT_MODE4 6 +#define LUT_READ 7 +#define LUT_WRITE 8 +#define LUT_JMP_ON_CS 9 +#define LUT_ADDR_DDR 10 +#define LUT_MODE_DDR 11 +#define LUT_MODE2_DDR 12 +#define LUT_MODE4_DDR 13 +#define LUT_READ_DDR 14 +#define LUT_WRITE_DDR 15 +#define LUT_DATA_LEARN 16 + +/* + * The PAD definitions for LUT register. + * + * The pad stands for the lines number of IO[0:3]. + * For example, the Quad read need four IO lines, so you should + * set LUT_PAD4 which means we use four IO lines. + */ +#define LUT_PAD1 0 +#define LUT_PAD2 1 +#define LUT_PAD4 2 + +/* Oprands for the LUT register. */ +#define ADDR24BIT 0x18 +#define ADDR32BIT 0x20 + +/* Macros for constructing the LUT register. */ +#define LUT0(ins, pad, opr) \ + (((opr) << OPRND0_SHIFT) | ((LUT_##pad) << PAD0_SHIFT) | \ + ((LUT_##ins) << INSTR0_SHIFT)) + +#define LUT1(ins, pad, opr) (LUT0(ins, pad, opr) << OPRND1_SHIFT) + +/* other macros for LUT register. */ +#define QUADSPI_LUT(x) (QUADSPI_LUT_BASE + (x) * 4) +#define QUADSPI_LUT_NUM 64 + +/* SEQID -- we can have 16 seqids at most. */ +#define SEQID_QUAD_READ 0 +#define SEQID_WREN 1 +#define SEQID_WRDI 2 +#define SEQID_RDSR 3 +#define SEQID_SE 4 +#define SEQID_CHIP_ERASE 5 +#define SEQID_PP 6 +#define SEQID_RDID 7 +#define SEQID_WRSR 8 +#define SEQID_RDCR 9 +#define SEQID_EN4B 10 +#define SEQID_BRWR 11 + +enum fsl_qspi_devtype { + FSL_QUADSPI_VYBRID, + FSL_QUADSPI_IMX6SX, +}; + +struct fsl_qspi_devtype_data { + enum fsl_qspi_devtype devtype; + int rxfifo; + int txfifo; +}; + +static struct fsl_qspi_devtype_data vybrid_data = { + .devtype = FSL_QUADSPI_VYBRID, + .rxfifo = 128, + .txfifo = 64 +}; + +static struct fsl_qspi_devtype_data imx6sx_data = { + .devtype = FSL_QUADSPI_IMX6SX, + .rxfifo = 128, + .txfifo = 512 +}; + +#define FSL_QSPI_MAX_CHIP 4 +struct fsl_qspi { + struct mtd_info mtd[FSL_QSPI_MAX_CHIP]; + struct spi_nor nor[FSL_QSPI_MAX_CHIP]; + void __iomem *iobase; + void __iomem *ahb_base; /* Used when read from AHB bus */ + u32 memmap_phy; + struct clk *clk, *clk_en; + struct device *dev; + struct completion c; + struct fsl_qspi_devtype_data *devtype_data; + u32 nor_size; + u32 nor_num; + u32 clk_rate; + unsigned int chip_base_addr; /* We may support two chips. */ +}; + +static inline int is_vybrid_qspi(struct fsl_qspi *q) +{ + return q->devtype_data->devtype == FSL_QUADSPI_VYBRID; +} + +static inline int is_imx6sx_qspi(struct fsl_qspi *q) +{ + return q->devtype_data->devtype == FSL_QUADSPI_IMX6SX; +} + +/* + * An IC bug makes us to re-arrange the 32-bit data. + * The following chips, such as IMX6SLX, have fixed this bug. + */ +static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a) +{ + return is_vybrid_qspi(q) ? __swab32(a) : a; +} + +static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q) +{ + writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY); + writel(QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR); +} + +static inline void fsl_qspi_lock_lut(struct fsl_qspi *q) +{ + writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY); + writel(QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR); +} + +static irqreturn_t fsl_qspi_irq_handler(int irq, void *dev_id) +{ + struct fsl_qspi *q = dev_id; + u32 reg; + + /* clear interrupt */ + reg = readl(q->iobase + QUADSPI_FR); + writel(reg, q->iobase + QUADSPI_FR); + + if (reg & QUADSPI_FR_TFF_MASK) + complete(&q->c); + + dev_dbg(q->dev, "QUADSPI_FR : 0x%.8x:0x%.8x\n", q->chip_base_addr, reg); + return IRQ_HANDLED; +} + +static void fsl_qspi_init_lut(struct fsl_qspi *q) +{ + void __iomem *base = q->iobase; + int rxfifo = q->devtype_data->rxfifo; + u32 lut_base; + u8 cmd, addrlen, dummy; + int i; + + fsl_qspi_unlock_lut(q); + + /* Clear all the LUT table */ + for (i = 0; i < QUADSPI_LUT_NUM; i++) + writel(0, base + QUADSPI_LUT_BASE + i * 4); + + /* Quad Read */ + lut_base = SEQID_QUAD_READ * 4; + + if (q->nor_size <= SZ_16M) { + cmd = SPINOR_OP_READ_1_1_4; + addrlen = ADDR24BIT; + dummy = 8; + } else { + /* use the 4-byte address */ + cmd = SPINOR_OP_READ_1_1_4; + addrlen = ADDR32BIT; + dummy = 8; + } + + writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), + base + QUADSPI_LUT(lut_base)); + writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ, PAD4, rxfifo), + base + QUADSPI_LUT(lut_base + 1)); + + /* Write enable */ + lut_base = SEQID_WREN * 4; + writel(LUT0(CMD, PAD1, SPINOR_OP_WREN), base + QUADSPI_LUT(lut_base)); + + /* Page Program */ + lut_base = SEQID_PP * 4; + + if (q->nor_size <= SZ_16M) { + cmd = SPINOR_OP_PP; + addrlen = ADDR24BIT; + } else { + /* use the 4-byte address */ + cmd = SPINOR_OP_PP; + addrlen = ADDR32BIT; + } + + writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), + base + QUADSPI_LUT(lut_base)); + writel(LUT0(WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1)); + + /* Read Status */ + lut_base = SEQID_RDSR * 4; + writel(LUT0(CMD, PAD1, SPINOR_OP_RDSR) | LUT1(READ, PAD1, 0x1), + base + QUADSPI_LUT(lut_base)); + + /* Erase a sector */ + lut_base = SEQID_SE * 4; + + if (q->nor_size <= SZ_16M) { + cmd = SPINOR_OP_SE; + addrlen = ADDR24BIT; + } else { + /* use the 4-byte address */ + cmd = SPINOR_OP_SE; + addrlen = ADDR32BIT; + } + + writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), + base + QUADSPI_LUT(lut_base)); + + /* Erase the whole chip */ + lut_base = SEQID_CHIP_ERASE * 4; + writel(LUT0(CMD, PAD1, SPINOR_OP_CHIP_ERASE), + base + QUADSPI_LUT(lut_base)); + + /* READ ID */ + lut_base = SEQID_RDID * 4; + writel(LUT0(CMD, PAD1, SPINOR_OP_RDID) | LUT1(READ, PAD1, 0x8), + base + QUADSPI_LUT(lut_base)); + + /* Write Register */ + lut_base = SEQID_WRSR * 4; + writel(LUT0(CMD, PAD1, SPINOR_OP_WRSR) | LUT1(WRITE, PAD1, 0x2), + base + QUADSPI_LUT(lut_base)); + + /* Read Configuration Register */ + lut_base = SEQID_RDCR * 4; + writel(LUT0(CMD, PAD1, SPINOR_OP_RDCR) | LUT1(READ, PAD1, 0x1), + base + QUADSPI_LUT(lut_base)); + + /* Write disable */ + lut_base = SEQID_WRDI * 4; + writel(LUT0(CMD, PAD1, SPINOR_OP_WRDI), base + QUADSPI_LUT(lut_base)); + + /* Enter 4 Byte Mode (Micron) */ + lut_base = SEQID_EN4B * 4; + writel(LUT0(CMD, PAD1, SPINOR_OP_EN4B), base + QUADSPI_LUT(lut_base)); + + /* Enter 4 Byte Mode (Spansion) */ + lut_base = SEQID_BRWR * 4; + writel(LUT0(CMD, PAD1, SPINOR_OP_BRWR), base + QUADSPI_LUT(lut_base)); + + fsl_qspi_lock_lut(q); +} + +/* Get the SEQID for the command */ +static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) +{ + switch (cmd) { + case SPINOR_OP_READ_1_1_4: + return SEQID_QUAD_READ; + case SPINOR_OP_WREN: + return SEQID_WREN; + case SPINOR_OP_WRDI: + return SEQID_WRDI; + case SPINOR_OP_RDSR: + return SEQID_RDSR; + case SPINOR_OP_SE: + return SEQID_SE; + case SPINOR_OP_CHIP_ERASE: + return SEQID_CHIP_ERASE; + case SPINOR_OP_PP: + return SEQID_PP; + case SPINOR_OP_RDID: + return SEQID_RDID; + case SPINOR_OP_WRSR: + return SEQID_WRSR; + case SPINOR_OP_RDCR: + return SEQID_RDCR; + case SPINOR_OP_EN4B: + return SEQID_EN4B; + case SPINOR_OP_BRWR: + return SEQID_BRWR; + default: + dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd); + break; + } + return -EINVAL; +} + +static int +fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len) +{ + void __iomem *base = q->iobase; + int seqid; + u32 reg, reg2; + int err; + + init_completion(&q->c); + dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len:%d, cmd:%.2x\n", + q->chip_base_addr, addr, len, cmd); + + /* save the reg */ + reg = readl(base + QUADSPI_MCR); + + writel(q->memmap_phy + q->chip_base_addr + addr, base + QUADSPI_SFAR); + writel(QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS, + base + QUADSPI_RBCT); + writel(reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR); + + do { + reg2 = readl(base + QUADSPI_SR); + if (reg2 & (QUADSPI_SR_IP_ACC_MASK | QUADSPI_SR_AHB_ACC_MASK)) { + udelay(1); + dev_dbg(q->dev, "The controller is busy, 0x%x\n", reg2); + continue; + } + break; + } while (1); + + /* trigger the LUT now */ + seqid = fsl_qspi_get_seqid(q, cmd); + writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR); + + /* Wait for the interrupt. */ + err = wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000)); + if (!err) { + dev_err(q->dev, + "cmd 0x%.2x timeout, addr@%.8x, FR:0x%.8x, SR:0x%.8x\n", + cmd, addr, readl(base + QUADSPI_FR), + readl(base + QUADSPI_SR)); + err = -ETIMEDOUT; + } else { + err = 0; + } + + /* restore the MCR */ + writel(reg, base + QUADSPI_MCR); + + return err; +} + +/* Read out the data from the QUADSPI_RBDR buffer registers. */ +static void fsl_qspi_read_data(struct fsl_qspi *q, int len, u8 *rxbuf) +{ + u32 tmp; + int i = 0; + + while (len > 0) { + tmp = readl(q->iobase + QUADSPI_RBDR + i * 4); + tmp = fsl_qspi_endian_xchg(q, tmp); + dev_dbg(q->dev, "chip addr:0x%.8x, rcv:0x%.8x\n", + q->chip_base_addr, tmp); + + if (len >= 4) { + *((u32 *)rxbuf) = tmp; + rxbuf += 4; + } else { + memcpy(rxbuf, &tmp, len); + break; + } + + len -= 4; + i++; + } +} + +/* + * If we have changed the content of the flash by writing or erasing, + * we need to invalidate the AHB buffer. If we do not do so, we may read out + * the wrong data. The spec tells us reset the AHB domain and Serial Flash + * domain at the same time. + */ +static inline void fsl_qspi_invalid(struct fsl_qspi *q) +{ + u32 reg; + + reg = readl(q->iobase + QUADSPI_MCR); + reg |= QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK; + writel(reg, q->iobase + QUADSPI_MCR); + + /* + * The minimum delay : 1 AHB + 2 SFCK clocks. + * Delay 1 us is enough. + */ + udelay(1); + + reg &= ~(QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK); + writel(reg, q->iobase + QUADSPI_MCR); +} + +static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor, + u8 opcode, unsigned int to, u32 *txbuf, + unsigned count, size_t *retlen) +{ + int ret, i, j; + u32 tmp; + + dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len : %d\n", + q->chip_base_addr, to, count); + + /* clear the TX FIFO. */ + tmp = readl(q->iobase + QUADSPI_MCR); + writel(tmp | QUADSPI_MCR_CLR_RXF_MASK, q->iobase + QUADSPI_MCR); + + /* fill the TX data to the FIFO */ + for (j = 0, i = ((count + 3) / 4); j < i; j++) { + tmp = fsl_qspi_endian_xchg(q, *txbuf); + writel(tmp, q->iobase + QUADSPI_TBDR); + txbuf++; + } + + /* Trigger it */ + ret = fsl_qspi_runcmd(q, opcode, to, count); + + if (ret == 0 && retlen) + *retlen += count; + + return ret; +} + +static void fsl_qspi_set_map_addr(struct fsl_qspi *q) +{ + int nor_size = q->nor_size; + void __iomem *base = q->iobase; + + writel(nor_size + q->memmap_phy, base + QUADSPI_SFA1AD); + writel(nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD); + writel(nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD); + writel(nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD); +} + +/* + * There are two different ways to read out the data from the flash: + * the "IP Command Read" and the "AHB Command Read". + * + * The IC guy suggests we use the "AHB Command Read" which is faster + * then the "IP Command Read". (What's more is that there is a bug in + * the "IP Command Read" in the Vybrid.) + * + * After we set up the registers for the "AHB Command Read", we can use + * the memcpy to read the data directly. A "missed" access to the buffer + * causes the controller to clear the buffer, and use the sequence pointed + * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash. + */ +static void fsl_qspi_init_abh_read(struct fsl_qspi *q) +{ + void __iomem *base = q->iobase; + int seqid; + + /* AHB configuration for access buffer 0/1/2 .*/ + writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR); + writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR); + writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR); + writel(QUADSPI_BUF3CR_ALLMST, base + QUADSPI_BUF3CR); + + /* We only use the buffer3 */ + writel(0, base + QUADSPI_BUF0IND); + writel(0, base + QUADSPI_BUF1IND); + writel(0, base + QUADSPI_BUF2IND); + + /* Set the default lut sequence for AHB Read. */ + seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode); + writel(seqid << QUADSPI_BFGENCR_SEQID_SHIFT, + q->iobase + QUADSPI_BFGENCR); +} + +/* We use this function to do some basic init for spi_nor_scan(). */ +static int fsl_qspi_nor_setup(struct fsl_qspi *q) +{ + void __iomem *base = q->iobase; + u32 reg; + int ret; + + /* the default frequency, we will change it in the future.*/ + ret = clk_set_rate(q->clk, 66000000); + if (ret) + return ret; + + /* Init the LUT table. */ + fsl_qspi_init_lut(q); + + /* Disable the module */ + writel(QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK, + base + QUADSPI_MCR); + + reg = readl(base + QUADSPI_SMPR); + writel(reg & ~(QUADSPI_SMPR_FSDLY_MASK + | QUADSPI_SMPR_FSPHS_MASK + | QUADSPI_SMPR_HSENA_MASK + | QUADSPI_SMPR_DDRSMP_MASK), base + QUADSPI_SMPR); + + /* Enable the module */ + writel(QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK, + base + QUADSPI_MCR); + + /* enable the interrupt */ + writel(QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER); + + return 0; +} + +static int fsl_qspi_nor_setup_last(struct fsl_qspi *q) +{ + unsigned long rate = q->clk_rate; + int ret; + + if (is_imx6sx_qspi(q)) + rate *= 4; + + ret = clk_set_rate(q->clk, rate); + if (ret) + return ret; + + /* Init the LUT table again. */ + fsl_qspi_init_lut(q); + + /* Init for AHB read */ + fsl_qspi_init_abh_read(q); + + return 0; +} + +static struct of_device_id fsl_qspi_dt_ids[] = { + { .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, }, + { .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids); + +static void fsl_qspi_set_base_addr(struct fsl_qspi *q, struct spi_nor *nor) +{ + q->chip_base_addr = q->nor_size * (nor - q->nor); +} + +static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) +{ + int ret; + struct fsl_qspi *q = nor->priv; + + ret = fsl_qspi_runcmd(q, opcode, 0, len); + if (ret) + return ret; + + fsl_qspi_read_data(q, len, buf); + return 0; +} + +static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len, + int write_enable) +{ + struct fsl_qspi *q = nor->priv; + int ret; + + if (!buf) { + ret = fsl_qspi_runcmd(q, opcode, 0, 1); + if (ret) + return ret; + + if (opcode == SPINOR_OP_CHIP_ERASE) + fsl_qspi_invalid(q); + + } else if (len > 0) { + ret = fsl_qspi_nor_write(q, nor, opcode, 0, + (u32 *)buf, len, NULL); + } else { + dev_err(q->dev, "invalid cmd %d\n", opcode); + ret = -EINVAL; + } + + return ret; +} + +static void fsl_qspi_write(struct spi_nor *nor, loff_t to, + size_t len, size_t *retlen, const u_char *buf) +{ + struct fsl_qspi *q = nor->priv; + + fsl_qspi_nor_write(q, nor, nor->program_opcode, to, + (u32 *)buf, len, retlen); + + /* invalid the data in the AHB buffer. */ + fsl_qspi_invalid(q); +} + +static int fsl_qspi_read(struct spi_nor *nor, loff_t from, + size_t len, size_t *retlen, u_char *buf) +{ + struct fsl_qspi *q = nor->priv; + u8 cmd = nor->read_opcode; + int ret; + + dev_dbg(q->dev, "cmd [%x],read from (0x%p, 0x%.8x, 0x%.8x),len:%d\n", + cmd, q->ahb_base, q->chip_base_addr, (unsigned int)from, len); + + /* Wait until the previous command is finished. */ + ret = nor->wait_till_ready(nor); + if (ret) + return ret; + + /* Read out the data directly from the AHB buffer.*/ + memcpy(buf, q->ahb_base + q->chip_base_addr + from, len); + + *retlen += len; + return 0; +} + +static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs) +{ + struct fsl_qspi *q = nor->priv; + int ret; + + dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n", + nor->mtd->erasesize / 1024, q->chip_base_addr, (u32)offs); + + /* Wait until finished previous write command. */ + ret = nor->wait_till_ready(nor); + if (ret) + return ret; + + /* Send write enable, then erase commands. */ + ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0); + if (ret) + return ret; + + ret = fsl_qspi_runcmd(q, nor->erase_opcode, offs, 0); + if (ret) + return ret; + + fsl_qspi_invalid(q); + return 0; +} + +static int fsl_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) +{ + struct fsl_qspi *q = nor->priv; + int ret; + + ret = clk_enable(q->clk_en); + if (ret) + return ret; + + ret = clk_enable(q->clk); + if (ret) { + clk_disable(q->clk_en); + return ret; + } + + fsl_qspi_set_base_addr(q, nor); + return 0; +} + +static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) +{ + struct fsl_qspi *q = nor->priv; + + clk_disable(q->clk); + clk_disable(q->clk_en); +} + +static int fsl_qspi_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct mtd_part_parser_data ppdata; + struct device *dev = &pdev->dev; + struct fsl_qspi *q; + struct resource *res; + struct spi_nor *nor; + struct mtd_info *mtd; + int ret, i = 0; + bool has_second_chip = false; + const struct of_device_id *of_id = + of_match_device(fsl_qspi_dt_ids, &pdev->dev); + + q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL); + if (!q) + return -ENOMEM; + + q->nor_num = of_get_child_count(dev->of_node); + if (!q->nor_num || q->nor_num > FSL_QSPI_MAX_CHIP) + return -ENODEV; + + /* find the resources */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI"); + q->iobase = devm_ioremap_resource(dev, res); + if (IS_ERR(q->iobase)) { + ret = PTR_ERR(q->iobase); + goto map_failed; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "QuadSPI-memory"); + q->ahb_base = devm_ioremap_resource(dev, res); + if (IS_ERR(q->ahb_base)) { + ret = PTR_ERR(q->ahb_base); + goto map_failed; + } + q->memmap_phy = res->start; + + /* find the clocks */ + q->clk_en = devm_clk_get(dev, "qspi_en"); + if (IS_ERR(q->clk_en)) { + ret = PTR_ERR(q->clk_en); + goto map_failed; + } + + q->clk = devm_clk_get(dev, "qspi"); + if (IS_ERR(q->clk)) { + ret = PTR_ERR(q->clk); + goto map_failed; + } + + ret = clk_prepare_enable(q->clk_en); + if (ret) { + dev_err(dev, "can not enable the qspi_en clock\n"); + goto map_failed; + } + + ret = clk_prepare_enable(q->clk); + if (ret) { + clk_disable_unprepare(q->clk_en); + dev_err(dev, "can not enable the qspi clock\n"); + goto map_failed; + } + + /* find the irq */ + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "failed to get the irq\n"); + goto irq_failed; + } + + ret = devm_request_irq(dev, ret, + fsl_qspi_irq_handler, 0, pdev->name, q); + if (ret) { + dev_err(dev, "failed to request irq.\n"); + goto irq_failed; + } + + q->dev = dev; + q->devtype_data = (struct fsl_qspi_devtype_data *)of_id->data; + platform_set_drvdata(pdev, q); + + ret = fsl_qspi_nor_setup(q); + if (ret) + goto irq_failed; + + if (of_get_property(np, "fsl,qspi-has-second-chip", NULL)) + has_second_chip = true; + + /* iterate the subnodes. */ + for_each_available_child_of_node(dev->of_node, np) { + const struct spi_device_id *id; + char modalias[40]; + + /* skip the holes */ + if (!has_second_chip) + i *= 2; + + nor = &q->nor[i]; + mtd = &q->mtd[i]; + + nor->mtd = mtd; + nor->dev = dev; + nor->priv = q; + mtd->priv = nor; + + /* fill the hooks */ + nor->read_reg = fsl_qspi_read_reg; + nor->write_reg = fsl_qspi_write_reg; + nor->read = fsl_qspi_read; + nor->write = fsl_qspi_write; + nor->erase = fsl_qspi_erase; + + nor->prepare = fsl_qspi_prep; + nor->unprepare = fsl_qspi_unprep; + + if (of_modalias_node(np, modalias, sizeof(modalias)) < 0) + goto map_failed; + + id = spi_nor_match_id(modalias); + if (!id) + goto map_failed; + + ret = of_property_read_u32(np, "spi-max-frequency", + &q->clk_rate); + if (ret < 0) + goto map_failed; + + /* set the chip address for READID */ + fsl_qspi_set_base_addr(q, nor); + + ret = spi_nor_scan(nor, id, SPI_NOR_QUAD); + if (ret) + goto map_failed; + + ppdata.of_node = np; + ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); + if (ret) + goto map_failed; + + /* Set the correct NOR size now. */ + if (q->nor_size == 0) { + q->nor_size = mtd->size; + + /* Map the SPI NOR to accessiable address */ + fsl_qspi_set_map_addr(q); + } + + /* + * The TX FIFO is 64 bytes in the Vybrid, but the Page Program + * may writes 265 bytes per time. The write is working in the + * unit of the TX FIFO, not in the unit of the SPI NOR's page + * size. + * + * So shrink the spi_nor->page_size if it is larger then the + * TX FIFO. + */ + if (nor->page_size > q->devtype_data->txfifo) + nor->page_size = q->devtype_data->txfifo; + + i++; + } + + /* finish the rest init. */ + ret = fsl_qspi_nor_setup_last(q); + if (ret) + goto last_init_failed; + + clk_disable(q->clk); + clk_disable(q->clk_en); + dev_info(dev, "QuadSPI SPI NOR flash driver\n"); + return 0; + +last_init_failed: + for (i = 0; i < q->nor_num; i++) + mtd_device_unregister(&q->mtd[i]); + +irq_failed: + clk_disable_unprepare(q->clk); + clk_disable_unprepare(q->clk_en); +map_failed: + dev_err(dev, "Freescale QuadSPI probe failed\n"); + return ret; +} + +static int fsl_qspi_remove(struct platform_device *pdev) +{ + struct fsl_qspi *q = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < q->nor_num; i++) + mtd_device_unregister(&q->mtd[i]); + + /* disable the hardware */ + writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR); + writel(0x0, q->iobase + QUADSPI_RSER); + + clk_unprepare(q->clk); + clk_unprepare(q->clk_en); + return 0; +} + +static struct platform_driver fsl_qspi_driver = { + .driver = { + .name = "fsl-quadspi", + .bus = &platform_bus_type, + .owner = THIS_MODULE, + .of_match_table = fsl_qspi_dt_ids, + }, + .probe = fsl_qspi_probe, + .remove = fsl_qspi_remove, +}; +module_platform_driver(fsl_qspi_driver); + +MODULE_DESCRIPTION("Freescale QuadSPI Controller Driver"); +MODULE_AUTHOR("Freescale Semiconductor Inc."); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c new file mode 100644 index 00000000000000..d6f44d52770151 --- /dev/null +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -0,0 +1,1107 @@ +/* + * Based on m25p80.c, by Mike Lavender (mike@steroidmicros.com), with + * influence from lart.c (Abraham Van Der Merwe) and mtd_dataflash.c + * + * Copyright (C) 2005, Intec Automation Inc. + * Copyright (C) 2014, Freescale Semiconductor, Inc. + * + * This code 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 +#include + +#include +#include +#include +#include +#include + +/* Define max times to check status register before we give up. */ +#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ + +#define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16) + +/* + * Read the status register, returning its value in the location + * Return the status register value. + * Returns negative if error occurred. + */ +static int read_sr(struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1); + if (ret < 0) { + pr_err("error %d reading SR\n", (int) ret); + return ret; + } + + return val; +} + +/* + * Read configuration register, returning its value in the + * location. Return the configuration register value. + * Returns negative if error occured. + */ +static int read_cr(struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = nor->read_reg(nor, SPINOR_OP_RDCR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading CR\n", ret); + return ret; + } + + return val; +} + +/* + * Dummy Cycle calculation for different type of read. + * It can be used to support more commands with + * different dummy cycle requirements. + */ +static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor) +{ + switch (nor->flash_read) { + case SPI_NOR_FAST: + case SPI_NOR_DUAL: + case SPI_NOR_QUAD: + return 1; + case SPI_NOR_NORMAL: + return 0; + } + return 0; +} + +/* + * Write status register 1 byte + * Returns negative if error occurred. + */ +static inline int write_sr(struct spi_nor *nor, u8 val) +{ + nor->cmd_buf[0] = val; + return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0); +} + +/* + * Set write enable latch with Write Enable command. + * Returns negative if error occurred. + */ +static inline int write_enable(struct spi_nor *nor) +{ + return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0); +} + +/* + * Send write disble instruction to the chip. + */ +static inline int write_disable(struct spi_nor *nor) +{ + return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0, 0); +} + +static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) +{ + return mtd->priv; +} + +/* Enable/disable 4-byte addressing mode. */ +static inline int set_4byte(struct spi_nor *nor, u32 jedec_id, int enable) +{ + int status; + bool need_wren = false; + u8 cmd; + + switch (JEDEC_MFR(jedec_id)) { + case CFI_MFR_ST: /* Micron, actually */ + /* Some Micron need WREN command; all will accept it */ + need_wren = true; + case CFI_MFR_MACRONIX: + case 0xEF /* winbond */: + if (need_wren) + write_enable(nor); + + cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B; + status = nor->write_reg(nor, cmd, NULL, 0, 0); + if (need_wren) + write_disable(nor); + + return status; + default: + /* Spansion style */ + nor->cmd_buf[0] = enable << 7; + return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1, 0); + } +} + +static int spi_nor_wait_till_ready(struct spi_nor *nor) +{ + unsigned long deadline; + int sr; + + deadline = jiffies + MAX_READY_WAIT_JIFFIES; + + do { + cond_resched(); + + sr = read_sr(nor); + if (sr < 0) + break; + else if (!(sr & SR_WIP)) + return 0; + } while (!time_after_eq(jiffies, deadline)); + + return -ETIMEDOUT; +} + +/* + * Service routine to read status register until ready, or timeout occurs. + * Returns non-zero if error. + */ +static int wait_till_ready(struct spi_nor *nor) +{ + return nor->wait_till_ready(nor); +} + +/* + * Erase the whole flash memory + * + * Returns 0 if successful, non-zero otherwise. + */ +static int erase_chip(struct spi_nor *nor) +{ + int ret; + + dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd->size >> 10)); + + /* Wait until finished previous write command. */ + ret = wait_till_ready(nor); + if (ret) + return ret; + + /* Send write enable, then erase commands. */ + write_enable(nor); + + return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0, 0); +} + +static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops) +{ + int ret = 0; + + mutex_lock(&nor->lock); + + if (nor->prepare) { + ret = nor->prepare(nor, ops); + if (ret) { + dev_err(nor->dev, "failed in the preparation.\n"); + mutex_unlock(&nor->lock); + return ret; + } + } + return ret; +} + +static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops) +{ + if (nor->unprepare) + nor->unprepare(nor, ops); + mutex_unlock(&nor->lock); +} + +/* + * Erase an address range on the nor chip. The address range may extend + * one or more erase sectors. Return an error is there is a problem erasing. + */ +static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + u32 addr, len; + uint32_t rem; + int ret; + + dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr, + (long long)instr->len); + + div_u64_rem(instr->len, mtd->erasesize, &rem); + if (rem) + return -EINVAL; + + addr = instr->addr; + len = instr->len; + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_ERASE); + if (ret) + return ret; + + /* whole-chip erase? */ + if (len == mtd->size) { + if (erase_chip(nor)) { + ret = -EIO; + goto erase_err; + } + + /* REVISIT in some cases we could speed up erasing large regions + * by using SPINOR_OP_SE instead of SPINOR_OP_BE_4K. We may have set up + * to use "small sector erase", but that's not always optimal. + */ + + /* "sector"-at-a-time erase */ + } else { + while (len) { + if (nor->erase(nor, addr)) { + ret = -EIO; + goto erase_err; + } + + addr += mtd->erasesize; + len -= mtd->erasesize; + } + } + + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); + + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + + return ret; + +erase_err: + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); + instr->state = MTD_ERASE_FAILED; + return ret; +} + +static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + uint32_t offset = ofs; + uint8_t status_old, status_new; + int ret = 0; + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK); + if (ret) + return ret; + + /* Wait until finished previous command */ + ret = wait_till_ready(nor); + if (ret) + goto err; + + status_old = read_sr(nor); + + if (offset < mtd->size - (mtd->size / 2)) + status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0; + else if (offset < mtd->size - (mtd->size / 4)) + status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1; + else if (offset < mtd->size - (mtd->size / 8)) + status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0; + else if (offset < mtd->size - (mtd->size / 16)) + status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2; + else if (offset < mtd->size - (mtd->size / 32)) + status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0; + else if (offset < mtd->size - (mtd->size / 64)) + status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1; + else + status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0; + + /* Only modify protection if it will not unlock other areas */ + if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) > + (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { + write_enable(nor); + ret = write_sr(nor, status_new); + if (ret) + goto err; + } + +err: + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); + return ret; +} + +static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + uint32_t offset = ofs; + uint8_t status_old, status_new; + int ret = 0; + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); + if (ret) + return ret; + + /* Wait until finished previous command */ + ret = wait_till_ready(nor); + if (ret) + goto err; + + status_old = read_sr(nor); + + if (offset+len > mtd->size - (mtd->size / 64)) + status_new = status_old & ~(SR_BP2 | SR_BP1 | SR_BP0); + else if (offset+len > mtd->size - (mtd->size / 32)) + status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0; + else if (offset+len > mtd->size - (mtd->size / 16)) + status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1; + else if (offset+len > mtd->size - (mtd->size / 8)) + status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0; + else if (offset+len > mtd->size - (mtd->size / 4)) + status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2; + else if (offset+len > mtd->size - (mtd->size / 2)) + status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0; + else + status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1; + + /* Only modify protection if it will not lock other areas */ + if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) < + (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { + write_enable(nor); + ret = write_sr(nor, status_new); + if (ret) + goto err; + } + +err: + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); + return ret; +} + +struct flash_info { + /* JEDEC id zero means "no ID" (most older chips); otherwise it has + * a high byte of zero plus three data bytes: the manufacturer id, + * then a two byte device id. + */ + u32 jedec_id; + u16 ext_id; + + /* The size listed here is what works with SPINOR_OP_SE, which isn't + * necessarily called a "sector" by the vendor. + */ + unsigned sector_size; + u16 n_sectors; + + u16 page_size; + u16 addr_width; + + u16 flags; +#define SECT_4K 0x01 /* SPINOR_OP_BE_4K works uniformly */ +#define SPI_NOR_NO_ERASE 0x02 /* No erase command needed */ +#define SST_WRITE 0x04 /* use SST byte programming */ +#define SPI_NOR_NO_FR 0x08 /* Can't do fastread */ +#define SECT_4K_PMC 0x10 /* SPINOR_OP_BE_4K_PMC works uniformly */ +#define SPI_NOR_DUAL_READ 0x20 /* Flash supports Dual Read */ +#define SPI_NOR_QUAD_READ 0x40 /* Flash supports Quad Read */ +}; + +#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ + ((kernel_ulong_t)&(struct flash_info) { \ + .jedec_id = (_jedec_id), \ + .ext_id = (_ext_id), \ + .sector_size = (_sector_size), \ + .n_sectors = (_n_sectors), \ + .page_size = 256, \ + .flags = (_flags), \ + }) + +#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \ + ((kernel_ulong_t)&(struct flash_info) { \ + .sector_size = (_sector_size), \ + .n_sectors = (_n_sectors), \ + .page_size = (_page_size), \ + .addr_width = (_addr_width), \ + .flags = (_flags), \ + }) + +/* NOTE: double check command sets and memory organization when you add + * more nor chips. This current list focusses on newer chips, which + * have been converging on command sets which including JEDEC ID. + */ +const struct spi_device_id spi_nor_ids[] = { + /* Atmel -- some are (confusingly) marketed as "DataFlash" */ + { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, + { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, + + { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) }, + { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, + { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, + + { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, + { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, + { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, + { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, + + { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, + + /* EON -- en25xxx */ + { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, + { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, + { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, + { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, + { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, + { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, + + /* ESMT */ + { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) }, + + /* Everspin */ + { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + + /* GigaDevice */ + { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) }, + { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) }, + + /* Intel/Numonyx -- xxxs33b */ + { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, + { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, + { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + + /* Macronix */ + { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, + { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, + { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, + { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, + { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) }, + { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, + { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, + { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, + { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, + { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, + { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, + { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) }, + { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, + + /* Micron */ + { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, + { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, + { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, + { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, + { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) }, + + /* PMC */ + { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, + { "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) }, + { "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) }, + + /* Spansion -- single (large) sector size only, at least + * for the chips listed here (without boot sectors). + */ + { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, 0) }, + { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, + { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, + { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, + { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, + { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, + { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) }, + { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) }, + { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, + { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, + { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, + { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, + { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, + { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, + { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, + { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + + /* SST -- large erase sizes are "overlays", "sectors" are 4K */ + { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, + { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, + { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) }, + { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) }, + { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) }, + { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) }, + { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) }, + { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) }, + { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, + + /* ST Microelectronics -- newer production may have feature updates */ + { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, + { "m25p10", INFO(0x202011, 0, 32 * 1024, 4, 0) }, + { "m25p20", INFO(0x202012, 0, 64 * 1024, 4, 0) }, + { "m25p40", INFO(0x202013, 0, 64 * 1024, 8, 0) }, + { "m25p80", INFO(0x202014, 0, 64 * 1024, 16, 0) }, + { "m25p16", INFO(0x202015, 0, 64 * 1024, 32, 0) }, + { "m25p32", INFO(0x202016, 0, 64 * 1024, 64, 0) }, + { "m25p64", INFO(0x202017, 0, 64 * 1024, 128, 0) }, + { "m25p128", INFO(0x202018, 0, 256 * 1024, 64, 0) }, + { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) }, + + { "m25p05-nonjedec", INFO(0, 0, 32 * 1024, 2, 0) }, + { "m25p10-nonjedec", INFO(0, 0, 32 * 1024, 4, 0) }, + { "m25p20-nonjedec", INFO(0, 0, 64 * 1024, 4, 0) }, + { "m25p40-nonjedec", INFO(0, 0, 64 * 1024, 8, 0) }, + { "m25p80-nonjedec", INFO(0, 0, 64 * 1024, 16, 0) }, + { "m25p16-nonjedec", INFO(0, 0, 64 * 1024, 32, 0) }, + { "m25p32-nonjedec", INFO(0, 0, 64 * 1024, 64, 0) }, + { "m25p64-nonjedec", INFO(0, 0, 64 * 1024, 128, 0) }, + { "m25p128-nonjedec", INFO(0, 0, 256 * 1024, 64, 0) }, + + { "m45pe10", INFO(0x204011, 0, 64 * 1024, 2, 0) }, + { "m45pe80", INFO(0x204014, 0, 64 * 1024, 16, 0) }, + { "m45pe16", INFO(0x204015, 0, 64 * 1024, 32, 0) }, + + { "m25pe20", INFO(0x208012, 0, 64 * 1024, 4, 0) }, + { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, + { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, + + { "m25px16", INFO(0x207115, 0, 64 * 1024, 32, SECT_4K) }, + { "m25px32", INFO(0x207116, 0, 64 * 1024, 64, SECT_4K) }, + { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, + { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, + { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, + + /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ + { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, + { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, + { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, + { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, + { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, + { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, + { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, + { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, + { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, + { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, + { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, + { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, + { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, + { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) }, + + /* Catalyst / On Semiconductor -- non-JEDEC */ + { "cat25c11", CAT25_INFO( 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "cat25c03", CAT25_INFO( 32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { }, +}; +EXPORT_SYMBOL_GPL(spi_nor_ids); + +static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) +{ + int tmp; + u8 id[5]; + u32 jedec; + u16 ext_jedec; + struct flash_info *info; + + tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, 5); + if (tmp < 0) { + dev_dbg(nor->dev, " error %d reading JEDEC ID\n", tmp); + return ERR_PTR(tmp); + } + jedec = id[0]; + jedec = jedec << 8; + jedec |= id[1]; + jedec = jedec << 8; + jedec |= id[2]; + + ext_jedec = id[3] << 8 | id[4]; + + for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) { + info = (void *)spi_nor_ids[tmp].driver_data; + if (info->jedec_id == jedec) { + if (info->ext_id == 0 || info->ext_id == ext_jedec) + return &spi_nor_ids[tmp]; + } + } + dev_err(nor->dev, "unrecognized JEDEC id %06x\n", jedec); + return ERR_PTR(-ENODEV); +} + +static const struct spi_device_id *jedec_probe(struct spi_nor *nor) +{ + return nor->read_id(nor); +} + +static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + int ret; + + dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len); + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ); + if (ret) + return ret; + + ret = nor->read(nor, from, len, retlen, buf); + + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ); + return ret; +} + +static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + size_t actual; + int ret; + + dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE); + if (ret) + return ret; + + /* Wait until finished previous write command. */ + ret = wait_till_ready(nor); + if (ret) + goto time_out; + + write_enable(nor); + + nor->sst_write_second = false; + + actual = to % 2; + /* Start write from odd address. */ + if (actual) { + nor->program_opcode = SPINOR_OP_BP; + + /* write one byte. */ + nor->write(nor, to, 1, retlen, buf); + ret = wait_till_ready(nor); + if (ret) + goto time_out; + } + to += actual; + + /* Write out most of the data here. */ + for (; actual < len - 1; actual += 2) { + nor->program_opcode = SPINOR_OP_AAI_WP; + + /* write two bytes. */ + nor->write(nor, to, 2, retlen, buf + actual); + ret = wait_till_ready(nor); + if (ret) + goto time_out; + to += 2; + nor->sst_write_second = true; + } + nor->sst_write_second = false; + + write_disable(nor); + ret = wait_till_ready(nor); + if (ret) + goto time_out; + + /* Write out trailing byte if it exists. */ + if (actual != len) { + write_enable(nor); + + nor->program_opcode = SPINOR_OP_BP; + nor->write(nor, to, 1, retlen, buf + actual); + + ret = wait_till_ready(nor); + if (ret) + goto time_out; + write_disable(nor); + } +time_out: + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); + return ret; +} + +/* + * Write an address range to the nor chip. Data must be written in + * FLASH_PAGESIZE chunks. The address range may be any size provided + * it is within the physical boundaries. + */ +static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + u32 page_offset, page_size, i; + int ret; + + dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE); + if (ret) + return ret; + + /* Wait until finished previous write command. */ + ret = wait_till_ready(nor); + if (ret) + goto write_err; + + write_enable(nor); + + page_offset = to & (nor->page_size - 1); + + /* do all the bytes fit onto one page? */ + if (page_offset + len <= nor->page_size) { + nor->write(nor, to, len, retlen, buf); + } else { + /* the size of data remaining on the first page */ + page_size = nor->page_size - page_offset; + nor->write(nor, to, page_size, retlen, buf); + + /* write everything in nor->page_size chunks */ + for (i = page_size; i < len; i += page_size) { + page_size = len - i; + if (page_size > nor->page_size) + page_size = nor->page_size; + + wait_till_ready(nor); + write_enable(nor); + + nor->write(nor, to + i, page_size, retlen, buf + i); + } + } + +write_err: + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); + return 0; +} + +static int macronix_quad_enable(struct spi_nor *nor) +{ + int ret, val; + + val = read_sr(nor); + write_enable(nor); + + nor->cmd_buf[0] = val | SR_QUAD_EN_MX; + nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0); + + if (wait_till_ready(nor)) + return 1; + + ret = read_sr(nor); + if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) { + dev_err(nor->dev, "Macronix Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +/* + * Write status Register and configuration register with 2 bytes + * The first byte will be written to the status register, while the + * second byte will be written to the configuration register. + * Return negative if error occured. + */ +static int write_sr_cr(struct spi_nor *nor, u16 val) +{ + nor->cmd_buf[0] = val & 0xff; + nor->cmd_buf[1] = (val >> 8); + + return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2, 0); +} + +static int spansion_quad_enable(struct spi_nor *nor) +{ + int ret; + int quad_en = CR_QUAD_EN_SPAN << 8; + + write_enable(nor); + + ret = write_sr_cr(nor, quad_en); + if (ret < 0) { + dev_err(nor->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + /* read back and check it */ + ret = read_cr(nor); + if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { + dev_err(nor->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +static int set_quad_mode(struct spi_nor *nor, u32 jedec_id) +{ + int status; + + switch (JEDEC_MFR(jedec_id)) { + case CFI_MFR_MACRONIX: + status = macronix_quad_enable(nor); + if (status) { + dev_err(nor->dev, "Macronix quad-read not enabled\n"); + return -EINVAL; + } + return status; + default: + status = spansion_quad_enable(nor); + if (status) { + dev_err(nor->dev, "Spansion quad-read not enabled\n"); + return -EINVAL; + } + return status; + } +} + +static int spi_nor_check(struct spi_nor *nor) +{ + if (!nor->dev || !nor->read || !nor->write || + !nor->read_reg || !nor->write_reg || !nor->erase) { + pr_err("spi-nor: please fill all the necessary fields!\n"); + return -EINVAL; + } + + if (!nor->read_id) + nor->read_id = spi_nor_read_id; + if (!nor->wait_till_ready) + nor->wait_till_ready = spi_nor_wait_till_ready; + + return 0; +} + +int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, + enum read_mode mode) +{ + struct flash_info *info; + struct flash_platform_data *data; + struct device *dev = nor->dev; + struct mtd_info *mtd = nor->mtd; + struct device_node *np = dev->of_node; + int ret; + int i; + + ret = spi_nor_check(nor); + if (ret) + return ret; + + /* Platform data helps sort out which chip type we have, as + * well as how this board partitions it. If we don't have + * a chip ID, try the JEDEC id commands; they'll work for most + * newer chips, even if we don't recognize the particular chip. + */ + data = dev_get_platdata(dev); + if (data && data->type) { + const struct spi_device_id *plat_id; + + for (i = 0; i < ARRAY_SIZE(spi_nor_ids) - 1; i++) { + plat_id = &spi_nor_ids[i]; + if (strcmp(data->type, plat_id->name)) + continue; + break; + } + + if (i < ARRAY_SIZE(spi_nor_ids) - 1) + id = plat_id; + else + dev_warn(dev, "unrecognized id %s\n", data->type); + } + + info = (void *)id->driver_data; + + if (info->jedec_id) { + const struct spi_device_id *jid; + + jid = jedec_probe(nor); + if (IS_ERR(jid)) { + return PTR_ERR(jid); + } else if (jid != id) { + /* + * JEDEC knows better, so overwrite platform ID. We + * can't trust partitions any longer, but we'll let + * mtd apply them anyway, since some partitions may be + * marked read-only, and we don't want to lose that + * information, even if it's not 100% accurate. + */ + dev_warn(dev, "found %s, expected %s\n", + jid->name, id->name); + id = jid; + info = (void *)jid->driver_data; + } + } + + mutex_init(&nor->lock); + + /* + * Atmel, SST and Intel/Numonyx serial nor tend to power + * up with the software protection bits set + */ + + if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ATMEL || + JEDEC_MFR(info->jedec_id) == CFI_MFR_INTEL || + JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) { + write_enable(nor); + write_sr(nor, 0); + } + + if (data && data->name) + mtd->name = data->name; + else + mtd->name = dev_name(dev); + + mtd->type = MTD_NORFLASH; + mtd->writesize = 1; + mtd->flags = MTD_CAP_NORFLASH; + mtd->size = info->sector_size * info->n_sectors; + mtd->_erase = spi_nor_erase; + mtd->_read = spi_nor_read; + + /* nor protection support for STmicro chips */ + if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) { + mtd->_lock = spi_nor_lock; + mtd->_unlock = spi_nor_unlock; + } + + /* sst nor chips use AAI word program */ + if (info->flags & SST_WRITE) + mtd->_write = sst_write; + else + mtd->_write = spi_nor_write; + + /* prefer "small sector" erase if possible */ + if (info->flags & SECT_4K) { + nor->erase_opcode = SPINOR_OP_BE_4K; + mtd->erasesize = 4096; + } else if (info->flags & SECT_4K_PMC) { + nor->erase_opcode = SPINOR_OP_BE_4K_PMC; + mtd->erasesize = 4096; + } else { + nor->erase_opcode = SPINOR_OP_SE; + mtd->erasesize = info->sector_size; + } + + if (info->flags & SPI_NOR_NO_ERASE) + mtd->flags |= MTD_NO_ERASE; + + mtd->dev.parent = dev; + nor->page_size = info->page_size; + mtd->writebufsize = nor->page_size; + + if (np) { + /* If we were instantiated by DT, use it */ + if (of_property_read_bool(np, "m25p,fast-read")) + nor->flash_read = SPI_NOR_FAST; + else + nor->flash_read = SPI_NOR_NORMAL; + } else { + /* If we weren't instantiated by DT, default to fast-read */ + nor->flash_read = SPI_NOR_FAST; + } + + /* Some devices cannot do fast-read, no matter what DT tells us */ + if (info->flags & SPI_NOR_NO_FR) + nor->flash_read = SPI_NOR_NORMAL; + + /* Quad/Dual-read mode takes precedence over fast/normal */ + if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) { + ret = set_quad_mode(nor, info->jedec_id); + if (ret) { + dev_err(dev, "quad mode not supported\n"); + return ret; + } + nor->flash_read = SPI_NOR_QUAD; + } else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) { + nor->flash_read = SPI_NOR_DUAL; + } + + /* Default commands */ + switch (nor->flash_read) { + case SPI_NOR_QUAD: + nor->read_opcode = SPINOR_OP_READ_1_1_4; + break; + case SPI_NOR_DUAL: + nor->read_opcode = SPINOR_OP_READ_1_1_2; + break; + case SPI_NOR_FAST: + nor->read_opcode = SPINOR_OP_READ_FAST; + break; + case SPI_NOR_NORMAL: + nor->read_opcode = SPINOR_OP_READ; + break; + default: + dev_err(dev, "No Read opcode defined\n"); + return -EINVAL; + } + + nor->program_opcode = SPINOR_OP_PP; + + if (info->addr_width) + nor->addr_width = info->addr_width; + else if (mtd->size > 0x1000000) { + /* enable 4-byte addressing if the device exceeds 16MiB */ + nor->addr_width = 4; + if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { + /* Dedicated 4-byte command set */ + switch (nor->flash_read) { + case SPI_NOR_QUAD: + nor->read_opcode = SPINOR_OP_READ4_1_1_4; + break; + case SPI_NOR_DUAL: + nor->read_opcode = SPINOR_OP_READ4_1_1_2; + break; + case SPI_NOR_FAST: + nor->read_opcode = SPINOR_OP_READ4_FAST; + break; + case SPI_NOR_NORMAL: + nor->read_opcode = SPINOR_OP_READ4; + break; + } + nor->program_opcode = SPINOR_OP_PP_4B; + /* No small sector erase for 4-byte command set */ + nor->erase_opcode = SPINOR_OP_SE_4B; + mtd->erasesize = info->sector_size; + } else + set_4byte(nor, info->jedec_id, 1); + } else { + nor->addr_width = 3; + } + + nor->read_dummy = spi_nor_read_dummy_cycles(nor); + + dev_info(dev, "%s (%lld Kbytes)\n", id->name, + (long long)mtd->size >> 10); + + dev_dbg(dev, + "mtd .name = %s, .size = 0x%llx (%lldMiB), " + ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", + mtd->name, (long long)mtd->size, (long long)(mtd->size >> 20), + mtd->erasesize, mtd->erasesize / 1024, mtd->numeraseregions); + + if (mtd->numeraseregions) + for (i = 0; i < mtd->numeraseregions; i++) + dev_dbg(dev, + "mtd.eraseregions[%d] = { .offset = 0x%llx, " + ".erasesize = 0x%.8x (%uKiB), " + ".numblocks = %d }\n", + i, (long long)mtd->eraseregions[i].offset, + mtd->eraseregions[i].erasesize, + mtd->eraseregions[i].erasesize / 1024, + mtd->eraseregions[i].numblocks); + return 0; +} +EXPORT_SYMBOL_GPL(spi_nor_scan); + +const struct spi_device_id *spi_nor_match_id(char *name) +{ + const struct spi_device_id *id = spi_nor_ids; + + while (id->name[0]) { + if (!strcmp(name, id->name)) + return id; + id++; + } + return NULL; +} +EXPORT_SYMBOL_GPL(spi_nor_match_id); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Huang Shijie "); +MODULE_AUTHOR("Mike Lavender"); +MODULE_DESCRIPTION("framework for SPI NOR"); diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index 2e9e2d11f204aa..f19ab1acde1f22 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c @@ -69,8 +69,8 @@ static int write_eraseblock(int ebnum) int err = 0; loff_t addr = ebnum * mtd->erasesize; + prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { - prandom_bytes_state(&rnd_state, writebuf, use_len); ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; @@ -78,7 +78,7 @@ static int write_eraseblock(int ebnum) ops.oobretlen = 0; ops.ooboffs = use_offset; ops.datbuf = NULL; - ops.oobbuf = writebuf; + ops.oobbuf = writebuf + (use_len_max * i) + use_offset; err = mtd_write_oob(mtd, addr, &ops); if (err || ops.oobretlen != use_len) { pr_err("error: writeoob failed at %#llx\n", @@ -122,8 +122,8 @@ static int verify_eraseblock(int ebnum) int err = 0; loff_t addr = ebnum * mtd->erasesize; + prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { - prandom_bytes_state(&rnd_state, writebuf, use_len); ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; @@ -139,7 +139,8 @@ static int verify_eraseblock(int ebnum) errcnt += 1; return err ? err : -1; } - if (memcmp(readbuf, writebuf, use_len)) { + if (memcmp(readbuf, writebuf + (use_len_max * i) + use_offset, + use_len)) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; @@ -166,7 +167,9 @@ static int verify_eraseblock(int ebnum) errcnt += 1; return err ? err : -1; } - if (memcmp(readbuf + use_offset, writebuf, use_len)) { + if (memcmp(readbuf + use_offset, + writebuf + (use_len_max * i) + use_offset, + use_len)) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; @@ -566,8 +569,8 @@ static int __init mtd_oobtest_init(void) if (bbt[i] || bbt[i + 1]) continue; addr = (i + 1) * mtd->erasesize - mtd->writesize; + prandom_bytes_state(&rnd_state, writebuf, sz * cnt); for (pg = 0; pg < cnt; ++pg) { - prandom_bytes_state(&rnd_state, writebuf, sz); ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; @@ -575,7 +578,7 @@ static int __init mtd_oobtest_init(void) ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; - ops.oobbuf = writebuf; + ops.oobbuf = writebuf + pg * sz; err = mtd_write_oob(mtd, addr, &ops); if (err) goto out; diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index 8d659e6a1b4c08..20a667c95da4b8 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -253,7 +253,7 @@ static int do_ubiblock_request(struct ubiblock *dev, struct request *req) * flash access anyway. */ mutex_lock(&dev->dev_mutex); - ret = ubiblock_read(dev, req->buffer, sec, len); + ret = ubiblock_read(dev, bio_data(req->bio), sec, len); mutex_unlock(&dev->dev_mutex); return ret; diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index b667a51ed21517..9a0d61e0c188a9 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2440,7 +2440,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) goto err_free; } - slave_agg_no = bond_xmit_hash(bond, skb, slaves_in_agg); + slave_agg_no = bond_xmit_hash(bond, skb) % slaves_in_agg; first_ok_slave = NULL; bond_for_each_slave_rcu(bond, slave, iter) { diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 9f69e818b0009d..70de039dad2e09 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1347,6 +1347,77 @@ void bond_alb_deinitialize(struct bonding *bond) rlb_deinitialize(bond); } +static int bond_do_alb_xmit(struct sk_buff *skb, struct bonding *bond, + struct slave *tx_slave) +{ + struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct ethhdr *eth_data = eth_hdr(skb); + + if (!tx_slave) { + /* unbalanced or unassigned, send through primary */ + tx_slave = rcu_dereference(bond->curr_active_slave); + if (bond->params.tlb_dynamic_lb) + bond_info->unbalanced_load += skb->len; + } + + if (tx_slave && SLAVE_IS_OK(tx_slave)) { + if (tx_slave != rcu_dereference(bond->curr_active_slave)) { + ether_addr_copy(eth_data->h_source, + tx_slave->dev->dev_addr); + } + + bond_dev_queue_xmit(bond, skb, tx_slave->dev); + goto out; + } + + if (tx_slave && bond->params.tlb_dynamic_lb) { + _lock_tx_hashtbl(bond); + __tlb_clear_slave(bond, tx_slave, 0); + _unlock_tx_hashtbl(bond); + } + + /* no suitable interface, frame not sent */ + dev_kfree_skb_any(skb); +out: + return NETDEV_TX_OK; +} + +int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev) +{ + struct bonding *bond = netdev_priv(bond_dev); + struct ethhdr *eth_data; + struct slave *tx_slave = NULL; + u32 hash_index; + + skb_reset_mac_header(skb); + eth_data = eth_hdr(skb); + + /* Do not TX balance any multicast or broadcast */ + if (!is_multicast_ether_addr(eth_data->h_dest)) { + switch (skb->protocol) { + case htons(ETH_P_IP): + case htons(ETH_P_IPX): + /* In case of IPX, it will falback to L2 hash */ + case htons(ETH_P_IPV6): + hash_index = bond_xmit_hash(bond, skb); + if (bond->params.tlb_dynamic_lb) { + tx_slave = tlb_choose_channel(bond, + hash_index & 0xFF, + skb->len); + } else { + struct list_head *iter; + int idx = hash_index % bond->slave_cnt; + + bond_for_each_slave_rcu(bond, tx_slave, iter) + if (--idx < 0) + break; + } + break; + } + } + return bond_do_alb_xmit(skb, bond, tx_slave); +} + int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); @@ -1355,7 +1426,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) struct slave *tx_slave = NULL; static const __be32 ip_bcast = htonl(0xffffffff); int hash_size = 0; - int do_tx_balance = 1; + bool do_tx_balance = true; u32 hash_index = 0; const u8 *hash_start = NULL; struct ipv6hdr *ip6hdr; @@ -1370,7 +1441,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) if (ether_addr_equal_64bits(eth_data->h_dest, mac_bcast) || (iph->daddr == ip_bcast) || (iph->protocol == IPPROTO_IGMP)) { - do_tx_balance = 0; + do_tx_balance = false; break; } hash_start = (char *)&(iph->daddr); @@ -1382,7 +1453,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) * that here just in case. */ if (ether_addr_equal_64bits(eth_data->h_dest, mac_bcast)) { - do_tx_balance = 0; + do_tx_balance = false; break; } @@ -1390,7 +1461,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) * broadcasts in IPv4. */ if (ether_addr_equal_64bits(eth_data->h_dest, mac_v6_allmcast)) { - do_tx_balance = 0; + do_tx_balance = false; break; } @@ -1400,7 +1471,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) */ ip6hdr = ipv6_hdr(skb); if (ipv6_addr_any(&ip6hdr->saddr)) { - do_tx_balance = 0; + do_tx_balance = false; break; } @@ -1410,7 +1481,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) case ETH_P_IPX: if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) { /* something is wrong with this packet */ - do_tx_balance = 0; + do_tx_balance = false; break; } @@ -1419,7 +1490,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) * this family since it has an "ARP" like * mechanism */ - do_tx_balance = 0; + do_tx_balance = false; break; } @@ -1427,12 +1498,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) hash_size = ETH_ALEN; break; case ETH_P_ARP: - do_tx_balance = 0; + do_tx_balance = false; if (bond_info->rlb_enabled) tx_slave = rlb_arp_xmit(skb, bond); break; default: - do_tx_balance = 0; + do_tx_balance = false; break; } @@ -1441,32 +1512,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) tx_slave = tlb_choose_channel(bond, hash_index, skb->len); } - if (!tx_slave) { - /* unbalanced or unassigned, send through primary */ - tx_slave = rcu_dereference(bond->curr_active_slave); - bond_info->unbalanced_load += skb->len; - } - - if (tx_slave && SLAVE_IS_OK(tx_slave)) { - if (tx_slave != rcu_dereference(bond->curr_active_slave)) { - ether_addr_copy(eth_data->h_source, - tx_slave->dev->dev_addr); - } - - bond_dev_queue_xmit(bond, skb, tx_slave->dev); - goto out; - } - - if (tx_slave) { - _lock_tx_hashtbl(bond); - __tlb_clear_slave(bond, tx_slave, 0); - _unlock_tx_hashtbl(bond); - } - - /* no suitable interface, frame not sent */ - dev_kfree_skb_any(skb); -out: - return NETDEV_TX_OK; + return bond_do_alb_xmit(skb, bond, tx_slave); } void bond_alb_monitor(struct work_struct *work) diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index e09dd4bfafffcf..5fc76c01636cb6 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -175,6 +175,7 @@ void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave); void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link); void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave); int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev); +int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev); void bond_alb_monitor(struct work_struct *); int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr); void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 69aff72c895716..9d08e007d85309 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3015,20 +3015,18 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, * bond_xmit_hash - generate a hash value based on the xmit policy * @bond: bonding device * @skb: buffer to use for headers - * @count: modulo value * * This function will extract the necessary headers from the skb buffer and use * them to generate a hash based on the xmit_policy set in the bonding device - * which will be reduced modulo count before returning. */ -int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count) +u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb) { struct flow_keys flow; u32 hash; if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER2 || !bond_flow_dissect(bond, skb, &flow)) - return bond_eth_hash(skb) % count; + return bond_eth_hash(skb); if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER23 || bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23) @@ -3039,7 +3037,7 @@ int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count) hash ^= (hash >> 16); hash ^= (hash >> 8); - return hash % count; + return hash; } /*-------------------------- Device entry points ----------------------------*/ @@ -3098,7 +3096,8 @@ static int bond_open(struct net_device *bond_dev) */ if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB))) return -ENOMEM; - queue_delayed_work(bond->wq, &bond->alb_work, 0); + if (bond->params.tlb_dynamic_lb) + queue_delayed_work(bond->wq, &bond->alb_work, 0); } if (bond->params.miimon) /* link check interval, in milliseconds. */ @@ -3666,7 +3665,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); - bond_xmit_slave_id(bond, skb, bond_xmit_hash(bond, skb, bond->slave_cnt)); + bond_xmit_slave_id(bond, skb, bond_xmit_hash(bond, skb) % bond->slave_cnt); return NETDEV_TX_OK; } @@ -3776,8 +3775,9 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev case BOND_MODE_8023AD: return bond_3ad_xmit_xor(skb, dev); case BOND_MODE_ALB: - case BOND_MODE_TLB: return bond_alb_xmit(skb, dev); + case BOND_MODE_TLB: + return bond_tlb_xmit(skb, dev); default: /* Should never happen, mode already checked */ pr_err("%s: Error: Unknown bonding mode %d\n", @@ -3998,7 +3998,8 @@ static int bond_check_params(struct bond_params *params) if (xmit_hash_policy) { if ((bond_mode != BOND_MODE_XOR) && - (bond_mode != BOND_MODE_8023AD)) { + (bond_mode != BOND_MODE_8023AD) && + (bond_mode != BOND_MODE_TLB)) { pr_info("xmit_hash_policy param is irrelevant in mode %s\n", bond_mode_name(bond_mode)); } else { @@ -4304,6 +4305,7 @@ static int bond_check_params(struct bond_params *params) params->min_links = min_links; params->lp_interval = lp_interval; params->packets_per_slave = packets_per_slave; + params->tlb_dynamic_lb = 1; /* Default value */ if (packets_per_slave > 0) { params->reciprocal_packets_per_slave = reciprocal_value(packets_per_slave); diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 724e30fa20b9fa..9fba7a1e6d51ea 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -70,6 +70,8 @@ static int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_slaves_set(struct bonding *bond, const struct bond_opt_value *newval); +static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, + const struct bond_opt_value *newval); static const struct bond_opt_value bond_mode_tbl[] = { @@ -179,6 +181,12 @@ static const struct bond_opt_value bond_lp_interval_tbl[] = { { NULL, -1, 0}, }; +static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = { + { "off", 0, 0}, + { "on", 1, BOND_VALFLAG_DEFAULT}, + { NULL, -1, 0} +}; + static const struct bond_option bond_opts[] = { [BOND_OPT_MODE] = { .id = BOND_OPT_MODE, @@ -199,7 +207,7 @@ static const struct bond_option bond_opts[] = { [BOND_OPT_XMIT_HASH] = { .id = BOND_OPT_XMIT_HASH, .name = "xmit_hash_policy", - .desc = "balance-xor and 802.3ad hashing method", + .desc = "balance-xor, 802.3ad, and tlb hashing method", .values = bond_xmit_hashtype_tbl, .set = bond_option_xmit_hash_policy_set }, @@ -364,6 +372,15 @@ static const struct bond_option bond_opts[] = { .flags = BOND_OPTFLAG_RAWVAL, .set = bond_option_slaves_set }, + [BOND_OPT_TLB_DYNAMIC_LB] = { + .id = BOND_OPT_TLB_DYNAMIC_LB, + .name = "dynamic_lb", + .desc = "Enable dynamic flow shuffling", + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_TLB)), + .values = bond_tlb_dynamic_lb_tbl, + .flags = BOND_OPTFLAG_IFDOWN, + .set = bond_option_tlb_dynamic_lb_set, + }, { } }; @@ -1337,3 +1354,13 @@ static int bond_option_slaves_set(struct bonding *bond, ret = -EPERM; goto out; } + +static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + pr_info("%s: Setting dynamic-lb to %s (%llu)\n", + bond->dev->name, newval->string, newval->value); + bond->params.tlb_dynamic_lb = newval->value; + + return 0; +} diff --git a/drivers/net/bonding/bond_options.h b/drivers/net/bonding/bond_options.h index 12be9e1bfb0c0d..c1860f06145aca 100644 --- a/drivers/net/bonding/bond_options.h +++ b/drivers/net/bonding/bond_options.h @@ -62,6 +62,7 @@ enum { BOND_OPT_RESEND_IGMP, BOND_OPT_LP_INTERVAL, BOND_OPT_SLAVES, + BOND_OPT_TLB_DYNAMIC_LB, BOND_OPT_LAST }; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 5f6babcfc26e6a..cb95ee44c2b4df 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1039,6 +1039,34 @@ static ssize_t bonding_store_lp_interval(struct device *d, static DEVICE_ATTR(lp_interval, S_IRUGO | S_IWUSR, bonding_show_lp_interval, bonding_store_lp_interval); +static ssize_t bonding_show_tlb_dynamic_lb(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + return sprintf(buf, "%d\n", bond->params.tlb_dynamic_lb); +} + +static ssize_t bonding_store_tlb_dynamic_lb(struct device *d, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct bonding *bond = to_bond(d); + int ret; + + ret = bond_opt_tryset_rtnl(bond, BOND_OPT_TLB_DYNAMIC_LB, + (char *)buf); + if (!ret) + ret = count; + + return ret; +} + +static DEVICE_ATTR(tlb_dynamic_lb, S_IRUGO | S_IWUSR, + bonding_show_tlb_dynamic_lb, + bonding_store_tlb_dynamic_lb); + static ssize_t bonding_show_packets_per_slave(struct device *d, struct device_attribute *attr, char *buf) @@ -1099,6 +1127,7 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_min_links.attr, &dev_attr_lp_interval.attr, &dev_attr_packets_per_slave.attr, + &dev_attr_tlb_dynamic_lb.attr, NULL, }; diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index b8bdd0acc8f334..c1c7c2f12ac446 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -174,6 +174,7 @@ struct bond_params { int resend_igmp; int lp_interval; int packets_per_slave; + int tlb_dynamic_lb; struct reciprocal_value reciprocal_packets_per_slave; }; @@ -499,7 +500,7 @@ int bond_sysfs_slave_add(struct slave *slave); void bond_sysfs_slave_del(struct slave *slave); int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev); int bond_release(struct net_device *bond_dev, struct net_device *slave_dev); -int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count); +u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb); void bond_select_active_slave(struct bonding *bond); void bond_change_active_slave(struct bonding *bond, struct slave *new_active); void bond_create_debugfs(void); diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 9e7d95dae2c703..4aacaa9b478aa9 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -77,12 +77,6 @@ config CAN_TI_HECC Driver for TI HECC (High End CAN Controller) module found on many TI devices. The device specifications are available from www.ti.com -config CAN_MCP251X - tristate "Microchip MCP251x SPI CAN controllers" - depends on SPI && HAS_DMA - ---help--- - Driver for the Microchip MCP251x SPI CAN controllers. - config CAN_BFIN depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x tristate "Analog Devices Blackfin on-chip CAN" @@ -133,6 +127,8 @@ source "drivers/net/can/c_can/Kconfig" source "drivers/net/can/cc770/Kconfig" +source "drivers/net/can/spi/Kconfig" + source "drivers/net/can/usb/Kconfig" source "drivers/net/can/softing/Kconfig" diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index c7440392adbbaa..c42058868b0fd0 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -10,6 +10,7 @@ can-dev-y := dev.o can-dev-$(CONFIG_CAN_LEDS) += led.o +obj-y += spi/ obj-y += usb/ obj-y += softing/ @@ -19,7 +20,6 @@ obj-$(CONFIG_CAN_C_CAN) += c_can/ obj-$(CONFIG_CAN_CC770) += cc770/ obj-$(CONFIG_CAN_AT91) += at91_can.o obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o -obj-$(CONFIG_CAN_MCP251X) += mcp251x.o obj-$(CONFIG_CAN_BFIN) += bfin_can.o obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o diff --git a/drivers/net/can/c_can/c_can_pci.c b/drivers/net/can/c_can/c_can_pci.c index fe5f6303b58400..58f71e1fcc4e7b 100644 --- a/drivers/net/can/c_can/c_can_pci.c +++ b/drivers/net/can/c_can/c_can_pci.c @@ -19,9 +19,13 @@ #include "c_can.h" +#define PCI_DEVICE_ID_PCH_CAN 0x8818 +#define PCH_PCI_SOFT_RESET 0x01fc + enum c_can_pci_reg_align { C_CAN_REG_ALIGN_16, C_CAN_REG_ALIGN_32, + C_CAN_REG_32, }; struct c_can_pci_data { @@ -31,6 +35,10 @@ struct c_can_pci_data { enum c_can_pci_reg_align reg_align; /* Set the frequency */ unsigned int freq; + /* PCI bar number */ + int bar; + /* Callback for reset */ + void (*init)(const struct c_can_priv *priv, bool enable); }; /* @@ -63,6 +71,29 @@ static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv, writew(val, priv->base + 2 * priv->regs[index]); } +static u16 c_can_pci_read_reg_32bit(struct c_can_priv *priv, + enum reg index) +{ + return (u16)ioread32(priv->base + 2 * priv->regs[index]); +} + +static void c_can_pci_write_reg_32bit(struct c_can_priv *priv, + enum reg index, u16 val) +{ + iowrite32((u32)val, priv->base + 2 * priv->regs[index]); +} + +static void c_can_pci_reset_pch(const struct c_can_priv *priv, bool enable) +{ + if (enable) { + u32 __iomem *addr = priv->base + PCH_PCI_SOFT_RESET; + + /* write to sw reset register */ + iowrite32(1, addr); + iowrite32(0, addr); + } +} + static int c_can_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -90,7 +121,8 @@ static int c_can_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); } - addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); + addr = pci_iomap(pdev, c_can_pci_data->bar, + pci_resource_len(pdev, c_can_pci_data->bar)); if (!addr) { dev_err(&pdev->dev, "device has no PCI memory resources, " @@ -147,11 +179,17 @@ static int c_can_pci_probe(struct pci_dev *pdev, priv->read_reg = c_can_pci_read_reg_aligned_to_16bit; priv->write_reg = c_can_pci_write_reg_aligned_to_16bit; break; + case C_CAN_REG_32: + priv->read_reg = c_can_pci_read_reg_32bit; + priv->write_reg = c_can_pci_write_reg_32bit; + break; default: ret = -EINVAL; goto out_free_c_can; } + priv->raminit = c_can_pci_data->init; + ret = register_c_can_dev(dev); if (ret) { dev_err(&pdev->dev, "registering %s failed (err=%d)\n", @@ -198,6 +236,15 @@ static struct c_can_pci_data c_can_sta2x11= { .type = BOSCH_C_CAN, .reg_align = C_CAN_REG_ALIGN_32, .freq = 52000000, /* 52 Mhz */ + .bar = 0, +}; + +static struct c_can_pci_data c_can_pch = { + .type = BOSCH_C_CAN, + .reg_align = C_CAN_REG_32, + .freq = 50000000, /* 50 MHz */ + .init = c_can_pci_reset_pch, + .bar = 1, }; #define C_CAN_ID(_vend, _dev, _driverdata) { \ @@ -207,6 +254,8 @@ static struct c_can_pci_data c_can_sta2x11= { static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = { C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN, c_can_sta2x11), + C_CAN_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_CAN, + c_can_pch), {}, }; static struct pci_driver c_can_pci_driver = { diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c index 7d8c8f3672dd99..bacd236ce3064d 100644 --- a/drivers/net/can/softing/softing_main.c +++ b/drivers/net/can/softing/softing_main.c @@ -556,15 +556,6 @@ static int softing_card_boot(struct softing *card) /* * netdev sysfs */ -static ssize_t show_channel(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct net_device *ndev = to_net_dev(dev); - struct softing_priv *priv = netdev2softing(ndev); - - return sprintf(buf, "%i\n", priv->index); -} - static ssize_t show_chip(struct device *dev, struct device_attribute *attr, char *buf) { @@ -609,12 +600,10 @@ static ssize_t store_output(struct device *dev, struct device_attribute *attr, return count; } -static const DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL); static const DEVICE_ATTR(chip, S_IRUGO, show_chip, NULL); static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output); static const struct attribute *const netdev_sysfs_attrs[] = { - &dev_attr_channel.attr, &dev_attr_chip.attr, &dev_attr_output.attr, NULL, @@ -679,17 +668,20 @@ static int softing_netdev_register(struct net_device *netdev) { int ret; - netdev->sysfs_groups[0] = &netdev_sysfs_group; ret = register_candev(netdev); if (ret) { dev_alert(&netdev->dev, "register failed\n"); return ret; } + if (sysfs_create_group(&netdev->dev.kobj, &netdev_sysfs_group) < 0) + netdev_alert(netdev, "sysfs group failed\n"); + return 0; } static void softing_netdev_cleanup(struct net_device *netdev) { + sysfs_remove_group(&netdev->dev.kobj, &netdev_sysfs_group); unregister_candev(netdev); free_candev(netdev); } @@ -721,8 +713,6 @@ DEV_ATTR_RO(firmware_version, id.fw_version); DEV_ATTR_RO_STR(hardware, pdat->name); DEV_ATTR_RO(hardware_version, id.hw_version); DEV_ATTR_RO(license, id.license); -DEV_ATTR_RO(frequency, id.freq); -DEV_ATTR_RO(txpending, tx.pending); static struct attribute *softing_pdev_attrs[] = { &dev_attr_serial.attr, @@ -731,8 +721,6 @@ static struct attribute *softing_pdev_attrs[] = { &dev_attr_hardware.attr, &dev_attr_hardware_version.attr, &dev_attr_license.attr, - &dev_attr_frequency.attr, - &dev_attr_txpending.attr, NULL, }; diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig new file mode 100644 index 00000000000000..148cae5871a6ba --- /dev/null +++ b/drivers/net/can/spi/Kconfig @@ -0,0 +1,10 @@ +menu "CAN SPI interfaces" + depends on SPI + +config CAN_MCP251X + tristate "Microchip MCP251x SPI CAN controllers" + depends on HAS_DMA + ---help--- + Driver for the Microchip MCP251x SPI CAN controllers. + +endmenu diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile new file mode 100644 index 00000000000000..90bcacffbc65c1 --- /dev/null +++ b/drivers/net/can/spi/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the Linux Controller Area Network SPI drivers. +# + + +obj-$(CONFIG_CAN_MCP251X) += mcp251x.o + +ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/spi/mcp251x.c similarity index 96% rename from drivers/net/can/mcp251x.c rename to drivers/net/can/spi/mcp251x.c index 28c11f81524524..bc235f9dc7543e 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -214,6 +214,8 @@ #define TX_ECHO_SKB_MAX 1 +#define MCP251X_OST_DELAY_MS (5) + #define DEVICE_NAME "mcp251x" static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */ @@ -624,50 +626,45 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv, static int mcp251x_hw_reset(struct spi_device *spi) { struct mcp251x_priv *priv = spi_get_drvdata(spi); + u8 reg; int ret; - unsigned long timeout; + + /* Wait for oscillator startup timer after power up */ + mdelay(MCP251X_OST_DELAY_MS); priv->spi_tx_buf[0] = INSTRUCTION_RESET; - ret = spi_write(spi, priv->spi_tx_buf, 1); - if (ret) { - dev_err(&spi->dev, "reset failed: ret = %d\n", ret); - return -EIO; - } + ret = mcp251x_spi_trans(spi, 1); + if (ret) + return ret; + + /* Wait for oscillator startup timer after reset */ + mdelay(MCP251X_OST_DELAY_MS); + + reg = mcp251x_read_reg(spi, CANSTAT); + if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF) + return -ENODEV; - /* Wait for reset to finish */ - timeout = jiffies + HZ; - mdelay(10); - while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) - != CANCTRL_REQOP_CONF) { - schedule(); - if (time_after(jiffies, timeout)) { - dev_err(&spi->dev, "MCP251x didn't" - " enter in conf mode after reset\n"); - return -EBUSY; - } - } return 0; } static int mcp251x_hw_probe(struct spi_device *spi) { - int st1, st2; + u8 ctrl; + int ret; - mcp251x_hw_reset(spi); + ret = mcp251x_hw_reset(spi); + if (ret) + return ret; - /* - * Please note that these are "magic values" based on after - * reset defaults taken from data sheet which allows us to see - * if we really have a chip on the bus (we avoid common all - * zeroes or all ones situations) - */ - st1 = mcp251x_read_reg(spi, CANSTAT) & 0xEE; - st2 = mcp251x_read_reg(spi, CANCTRL) & 0x17; + ctrl = mcp251x_read_reg(spi, CANCTRL); + + dev_dbg(&spi->dev, "CANCTRL 0x%02x\n", ctrl); - dev_dbg(&spi->dev, "CANSTAT 0x%02x CANCTRL 0x%02x\n", st1, st2); + /* Check for power up default value */ + if ((ctrl & 0x17) != 0x07) + return -ENODEV; - /* Check for power up default values */ - return (st1 == 0x80 && st2 == 0x07) ? 1 : 0; + return 0; } static int mcp251x_power_enable(struct regulator *reg, int enable) @@ -776,7 +773,6 @@ static void mcp251x_restart_work_handler(struct work_struct *ws) mutex_lock(&priv->mcp_lock); if (priv->after_suspend) { - mdelay(10); mcp251x_hw_reset(spi); mcp251x_setup(net, priv, spi); if (priv->after_suspend & AFTER_SUSPEND_RESTART) { @@ -1032,8 +1028,8 @@ static int mcp251x_can_probe(struct spi_device *spi) struct mcp251x_platform_data *pdata = dev_get_platdata(&spi->dev); struct net_device *net; struct mcp251x_priv *priv; - int freq, ret = -ENODEV; struct clk *clk; + int freq, ret; clk = devm_clk_get(&spi->dev, NULL); if (IS_ERR(clk)) { @@ -1076,6 +1072,18 @@ static int mcp251x_can_probe(struct spi_device *spi) priv->net = net; priv->clk = clk; + spi_set_drvdata(spi, priv); + + /* Configure the SPI bus */ + spi->bits_per_word = 8; + if (mcp251x_is_2510(spi)) + spi->max_speed_hz = spi->max_speed_hz ? : 5 * 1000 * 1000; + else + spi->max_speed_hz = spi->max_speed_hz ? : 10 * 1000 * 1000; + ret = spi_setup(spi); + if (ret) + goto out_clk; + priv->power = devm_regulator_get(&spi->dev, "vdd"); priv->transceiver = devm_regulator_get(&spi->dev, "xceiver"); if ((PTR_ERR(priv->power) == -EPROBE_DEFER) || @@ -1088,8 +1096,6 @@ static int mcp251x_can_probe(struct spi_device *spi) if (ret) goto out_clk; - spi_set_drvdata(spi, priv); - priv->spi = spi; mutex_init(&priv->mcp_lock); @@ -1134,20 +1140,11 @@ static int mcp251x_can_probe(struct spi_device *spi) SET_NETDEV_DEV(net, &spi->dev); - /* Configure the SPI bus */ - spi->mode = spi->mode ? : SPI_MODE_0; - if (mcp251x_is_2510(spi)) - spi->max_speed_hz = spi->max_speed_hz ? : 5 * 1000 * 1000; - else - spi->max_speed_hz = spi->max_speed_hz ? : 10 * 1000 * 1000; - spi->bits_per_word = 8; - spi_setup(spi); - /* Here is OK to not lock the MCP, no one knows about it yet */ - if (!mcp251x_hw_probe(spi)) { - ret = -ENODEV; + ret = mcp251x_hw_probe(spi); + if (ret) goto error_probe; - } + mcp251x_hw_sleep(spi); ret = register_candev(net); @@ -1156,7 +1153,7 @@ static int mcp251x_can_probe(struct spi_device *spi) devm_can_led_init(net); - return ret; + return 0; error_probe: if (mcp251x_enable_dma) diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index fc96a3d83ebecd..0b918ebad76b2f 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -19,7 +19,7 @@ config CAN_KVASER_USB This driver adds support for Kvaser CAN/USB devices like Kvaser Leaf Light. - The driver gives support for the following devices: + The driver provides support for the following devices: - Kvaser Leaf Light - Kvaser Leaf Professional HS - Kvaser Leaf SemiPro HS @@ -36,6 +36,8 @@ config CAN_KVASER_USB - Kvaser Leaf Light "China" - Kvaser BlackBird SemiPro - Kvaser USBcan R + - Kvaser Leaf Light v2 + - Kvaser Mini PCI Express HS If unsure, say N. diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 4ca46edc061d76..541fb7a05625aa 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -53,6 +53,8 @@ #define USB_OEM_MERCURY_PRODUCT_ID 34 #define USB_OEM_LEAF_PRODUCT_ID 35 #define USB_CAN_R_PRODUCT_ID 39 +#define USB_LEAF_LITE_V2_PRODUCT_ID 288 +#define USB_MINI_PCIE_HS_PRODUCT_ID 289 /* USB devices features */ #define KVASER_HAS_SILENT_MODE BIT(0) @@ -356,6 +358,8 @@ static const struct usb_device_id kvaser_usb_table[] = { .driver_info = KVASER_HAS_TXRX_ERRORS }, { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID), .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) }, { } }; MODULE_DEVICE_TABLE(usb, kvaser_usb_table); @@ -379,38 +383,43 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id, void *buf; int actual_len; int err; - int pos = 0; + int pos; + unsigned long to = jiffies + msecs_to_jiffies(USB_RECV_TIMEOUT); buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; - err = usb_bulk_msg(dev->udev, - usb_rcvbulkpipe(dev->udev, - dev->bulk_in->bEndpointAddress), - buf, RX_BUFFER_SIZE, &actual_len, - USB_RECV_TIMEOUT); - if (err < 0) - goto end; + do { + err = usb_bulk_msg(dev->udev, + usb_rcvbulkpipe(dev->udev, + dev->bulk_in->bEndpointAddress), + buf, RX_BUFFER_SIZE, &actual_len, + USB_RECV_TIMEOUT); + if (err < 0) + goto end; - while (pos <= actual_len - MSG_HEADER_LEN) { - tmp = buf + pos; + pos = 0; + while (pos <= actual_len - MSG_HEADER_LEN) { + tmp = buf + pos; - if (!tmp->len) - break; + if (!tmp->len) + break; - if (pos + tmp->len > actual_len) { - dev_err(dev->udev->dev.parent, "Format error\n"); - break; - } + if (pos + tmp->len > actual_len) { + dev_err(dev->udev->dev.parent, + "Format error\n"); + break; + } - if (tmp->id == id) { - memcpy(msg, tmp, tmp->len); - goto end; - } + if (tmp->id == id) { + memcpy(msg, tmp, tmp->len); + goto end; + } - pos += tmp->len; - } + pos += tmp->len; + } + } while (time_before(jiffies, to)); err = -EINVAL; diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c index 41ee5b6ae91751..69c42513dd724b 100644 --- a/drivers/net/dsa/mv88e6123_61_65.c +++ b/drivers/net/dsa/mv88e6123_61_65.c @@ -289,7 +289,7 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p) static int mv88e6123_61_65_setup(struct dsa_switch *ds) { - struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int i; int ret; diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index dadfafba64e9ac..953bc6a49e5944 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c @@ -155,7 +155,7 @@ static int mv88e6131_setup_global(struct dsa_switch *ds) static int mv88e6131_setup_port(struct dsa_switch *ds, int p) { - struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int addr = REG_PORT(p); u16 val; @@ -274,7 +274,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) static int mv88e6131_setup(struct dsa_switch *ds) { - struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int i; int ret; diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 17314ed9456d32..9ce2146346b6cd 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -74,7 +74,7 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg) int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg) { - struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; mutex_lock(&ps->smi_mutex); @@ -118,7 +118,7 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr, int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val) { - struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; mutex_lock(&ps->smi_mutex); @@ -256,7 +256,7 @@ static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps) static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds) { - struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; mutex_lock(&ps->ppu_mutex); @@ -283,7 +283,7 @@ static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds) static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds) { - struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); /* Schedule a timer to re-enable the PHY polling unit. */ mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10)); @@ -292,7 +292,7 @@ static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds) void mv88e6xxx_ppu_state_init(struct dsa_switch *ds) { - struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); mutex_init(&ps->ppu_mutex); INIT_WORK(&ps->ppu_work, mv88e6xxx_ppu_reenable_work); @@ -463,7 +463,7 @@ void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int nr_stats, struct mv88e6xxx_hw_stat *stats, int port, uint64_t *data) { - struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; int i; diff --git a/drivers/net/ethernet/altera/altera_msgdma.c b/drivers/net/ethernet/altera/altera_msgdma.c index 4d1f2fdd5c3275..38c500f95b9e97 100644 --- a/drivers/net/ethernet/altera/altera_msgdma.c +++ b/drivers/net/ethernet/altera/altera_msgdma.c @@ -37,10 +37,8 @@ void msgdma_start_rxdma(struct altera_tse_private *priv) void msgdma_reset(struct altera_tse_private *priv) { int counter; - struct msgdma_csr *txcsr = - (struct msgdma_csr *)priv->tx_dma_csr; - struct msgdma_csr *rxcsr = - (struct msgdma_csr *)priv->rx_dma_csr; + struct msgdma_csr *txcsr = priv->tx_dma_csr; + struct msgdma_csr *rxcsr = priv->rx_dma_csr; /* Reset Rx mSGDMA */ iowrite32(MSGDMA_CSR_STAT_MASK, &rxcsr->status); @@ -138,8 +136,7 @@ u32 msgdma_tx_completions(struct altera_tse_private *priv) u32 ready = 0; u32 inuse; u32 status; - struct msgdma_csr *txcsr = - (struct msgdma_csr *)priv->tx_dma_csr; + struct msgdma_csr *txcsr = priv->tx_dma_csr; /* Get number of sent descriptors */ inuse = ioread32(&txcsr->rw_fill_level) & 0xffff; @@ -190,10 +187,8 @@ u32 msgdma_rx_status(struct altera_tse_private *priv) u32 rxstatus = 0; u32 pktlength; u32 pktstatus; - struct msgdma_csr *rxcsr = - (struct msgdma_csr *)priv->rx_dma_csr; - struct msgdma_response *rxresp = - (struct msgdma_response *)priv->rx_dma_resp; + struct msgdma_csr *rxcsr = priv->rx_dma_csr; + struct msgdma_response *rxresp = priv->rx_dma_resp; if (ioread32(&rxcsr->resp_fill_level) & 0xffff) { pktlength = ioread32(&rxresp->bytes_transferred); diff --git a/drivers/net/ethernet/altera/altera_sgdma.c b/drivers/net/ethernet/altera/altera_sgdma.c index 9ce8630692b6e7..dbd40e15b5ccc2 100644 --- a/drivers/net/ethernet/altera/altera_sgdma.c +++ b/drivers/net/ethernet/altera/altera_sgdma.c @@ -126,12 +126,12 @@ void sgdma_uninitialize(struct altera_tse_private *priv) */ void sgdma_reset(struct altera_tse_private *priv) { - u32 *ptxdescripmem = (u32 *)priv->tx_dma_desc; + u32 *ptxdescripmem = priv->tx_dma_desc; u32 txdescriplen = priv->txdescmem; - u32 *prxdescripmem = (u32 *)priv->rx_dma_desc; + u32 *prxdescripmem = priv->rx_dma_desc; u32 rxdescriplen = priv->rxdescmem; - struct sgdma_csr *ptxsgdma = (struct sgdma_csr *)priv->tx_dma_csr; - struct sgdma_csr *prxsgdma = (struct sgdma_csr *)priv->rx_dma_csr; + struct sgdma_csr *ptxsgdma = priv->tx_dma_csr; + struct sgdma_csr *prxsgdma = priv->rx_dma_csr; /* Initialize descriptor memory to 0 */ memset(ptxdescripmem, 0, txdescriplen); @@ -167,13 +167,13 @@ void sgdma_disable_txirq(struct altera_tse_private *priv) void sgdma_clear_rxirq(struct altera_tse_private *priv) { - struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr; + struct sgdma_csr *csr = priv->rx_dma_csr; tse_set_bit(&csr->control, SGDMA_CTRLREG_CLRINT); } void sgdma_clear_txirq(struct altera_tse_private *priv) { - struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr; + struct sgdma_csr *csr = priv->tx_dma_csr; tse_set_bit(&csr->control, SGDMA_CTRLREG_CLRINT); } @@ -185,8 +185,7 @@ void sgdma_clear_txirq(struct altera_tse_private *priv) int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer) { int pktstx = 0; - struct sgdma_descrip *descbase = - (struct sgdma_descrip *)priv->tx_dma_desc; + struct sgdma_descrip *descbase = priv->tx_dma_desc; struct sgdma_descrip *cdesc = &descbase[0]; struct sgdma_descrip *ndesc = &descbase[1]; @@ -219,7 +218,7 @@ int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer) u32 sgdma_tx_completions(struct altera_tse_private *priv) { u32 ready = 0; - struct sgdma_descrip *desc = (struct sgdma_descrip *)priv->tx_dma_desc; + struct sgdma_descrip *desc = priv->tx_dma_desc; if (!sgdma_txbusy(priv) && ((desc->control & SGDMA_CONTROL_HW_OWNED) == 0) && @@ -246,8 +245,8 @@ void sgdma_add_rx_desc(struct altera_tse_private *priv, */ u32 sgdma_rx_status(struct altera_tse_private *priv) { - struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr; - struct sgdma_descrip *base = (struct sgdma_descrip *)priv->rx_dma_desc; + struct sgdma_csr *csr = priv->rx_dma_csr; + struct sgdma_descrip *base = priv->rx_dma_desc; struct sgdma_descrip *desc = NULL; int pktsrx; unsigned int rxstatus = 0; @@ -351,10 +350,8 @@ static void sgdma_setup_descrip(struct sgdma_descrip *desc, */ static int sgdma_async_read(struct altera_tse_private *priv) { - struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr; - struct sgdma_descrip *descbase = - (struct sgdma_descrip *)priv->rx_dma_desc; - + struct sgdma_csr *csr = priv->rx_dma_csr; + struct sgdma_descrip *descbase = priv->rx_dma_desc; struct sgdma_descrip *cdesc = &descbase[0]; struct sgdma_descrip *ndesc = &descbase[1]; @@ -397,7 +394,7 @@ static int sgdma_async_read(struct altera_tse_private *priv) static int sgdma_async_write(struct altera_tse_private *priv, struct sgdma_descrip *desc) { - struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr; + struct sgdma_csr *csr = priv->tx_dma_csr; if (sgdma_txbusy(priv)) return 0; @@ -518,7 +515,7 @@ queue_rx_peekhead(struct altera_tse_private *priv) */ static int sgdma_rxbusy(struct altera_tse_private *priv) { - struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr; + struct sgdma_csr *csr = priv->rx_dma_csr; return ioread32(&csr->status) & SGDMA_STSREG_BUSY; } @@ -528,7 +525,7 @@ static int sgdma_rxbusy(struct altera_tse_private *priv) static int sgdma_txbusy(struct altera_tse_private *priv) { int delay = 0; - struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr; + struct sgdma_csr *csr = priv->tx_dma_csr; /* if DMA is busy, wait for current transactino to finish */ while ((ioread32(&csr->status) & SGDMA_STSREG_BUSY) && (delay++ < 100)) diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 85dbddd03722b2..3e488094b07318 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -150,4 +150,15 @@ config BGMAC In case of using this driver on BCM4706 it's also requires to enable BCMA_DRIVER_GMAC_CMN to make it work. +config SYSTEMPORT + tristate "Broadcom SYSTEMPORT internal MAC support" + depends on OF + select MII + select PHYLIB + select FIXED_PHY if SYSTEMPORT=y + help + This driver supports the built-in Ethernet MACs found in the + Broadcom BCM7xxx Set Top Box family chipset using an internal + Ethernet switch. + endif # NET_VENDOR_BROADCOM diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile index fd639a0d4c7d64..e2a958a657e0bb 100644 --- a/drivers/net/ethernet/broadcom/Makefile +++ b/drivers/net/ethernet/broadcom/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_BNX2X) += bnx2x/ obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_TIGON3) += tg3.o obj-$(CONFIG_BGMAC) += bgmac.o +obj-$(CONFIG_SYSTEMPORT) += bcmsysport.o diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index a7d11f5565d693..8db34d38967583 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -1315,8 +1315,7 @@ static const struct bcm_enet_stats bcm_enet_gstrings_stats[] = { }; -#define BCM_ENET_STATS_LEN \ - (sizeof(bcm_enet_gstrings_stats) / sizeof(struct bcm_enet_stats)) +#define BCM_ENET_STATS_LEN ARRAY_SIZE(bcm_enet_gstrings_stats) static const u32 unused_mib_regs[] = { ETH_MIB_TX_ALL_OCTETS, diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c new file mode 100644 index 00000000000000..4dc8d1e9829b08 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -0,0 +1,1614 @@ +/* + * Broadcom BCM7xxx System Port Ethernet MAC driver + * + * Copyright (C) 2014 Broadcom 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bcmsysport.h" + +/* I/O accessors register helpers */ +#define BCM_SYSPORT_IO_MACRO(name, offset) \ +static inline u32 name##_readl(struct bcm_sysport_priv *priv, u32 off) \ +{ \ + u32 reg = __raw_readl(priv->base + offset + off); \ + return reg; \ +} \ +static inline void name##_writel(struct bcm_sysport_priv *priv, \ + u32 val, u32 off) \ +{ \ + __raw_writel(val, priv->base + offset + off); \ +} \ + +BCM_SYSPORT_IO_MACRO(intrl2_0, SYS_PORT_INTRL2_0_OFFSET); +BCM_SYSPORT_IO_MACRO(intrl2_1, SYS_PORT_INTRL2_1_OFFSET); +BCM_SYSPORT_IO_MACRO(umac, SYS_PORT_UMAC_OFFSET); +BCM_SYSPORT_IO_MACRO(tdma, SYS_PORT_TDMA_OFFSET); +BCM_SYSPORT_IO_MACRO(rdma, SYS_PORT_RDMA_OFFSET); +BCM_SYSPORT_IO_MACRO(rxchk, SYS_PORT_RXCHK_OFFSET); +BCM_SYSPORT_IO_MACRO(txchk, SYS_PORT_TXCHK_OFFSET); +BCM_SYSPORT_IO_MACRO(rbuf, SYS_PORT_RBUF_OFFSET); +BCM_SYSPORT_IO_MACRO(tbuf, SYS_PORT_TBUF_OFFSET); +BCM_SYSPORT_IO_MACRO(topctrl, SYS_PORT_TOPCTRL_OFFSET); + +/* L2-interrupt masking/unmasking helpers, does automatic saving of the applied + * mask in a software copy to avoid CPU_MASK_STATUS reads in hot-paths. + */ +#define BCM_SYSPORT_INTR_L2(which) \ +static inline void intrl2_##which##_mask_clear(struct bcm_sysport_priv *priv, \ + u32 mask) \ +{ \ + intrl2_##which##_writel(priv, mask, INTRL2_CPU_MASK_CLEAR); \ + priv->irq##which##_mask &= ~(mask); \ +} \ +static inline void intrl2_##which##_mask_set(struct bcm_sysport_priv *priv, \ + u32 mask) \ +{ \ + intrl2_## which##_writel(priv, mask, INTRL2_CPU_MASK_SET); \ + priv->irq##which##_mask |= (mask); \ +} \ + +BCM_SYSPORT_INTR_L2(0) +BCM_SYSPORT_INTR_L2(1) + +/* Register accesses to GISB/RBUS registers are expensive (few hundred + * nanoseconds), so keep the check for 64-bits explicit here to save + * one register write per-packet on 32-bits platforms. + */ +static inline void dma_desc_set_addr(struct bcm_sysport_priv *priv, + void __iomem *d, + dma_addr_t addr) +{ +#ifdef CONFIG_PHYS_ADDR_T_64BIT + __raw_writel(upper_32_bits(addr) & DESC_ADDR_HI_MASK, + d + DESC_ADDR_HI_STATUS_LEN); +#endif + __raw_writel(lower_32_bits(addr), d + DESC_ADDR_LO); +} + +static inline void tdma_port_write_desc_addr(struct bcm_sysport_priv *priv, + struct dma_desc *desc, + unsigned int port) +{ + /* Ports are latched, so write upper address first */ + tdma_writel(priv, desc->addr_status_len, TDMA_WRITE_PORT_HI(port)); + tdma_writel(priv, desc->addr_lo, TDMA_WRITE_PORT_LO(port)); +} + +/* Ethtool operations */ +static int bcm_sysport_set_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + + if (!netif_running(dev)) + return -EINVAL; + + return phy_ethtool_sset(priv->phydev, cmd); +} + +static int bcm_sysport_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + + if (!netif_running(dev)) + return -EINVAL; + + return phy_ethtool_gset(priv->phydev, cmd); +} + +static int bcm_sysport_set_rx_csum(struct net_device *dev, + netdev_features_t wanted) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + u32 reg; + + priv->rx_csum_en = !!(wanted & NETIF_F_RXCSUM); + reg = rxchk_readl(priv, RXCHK_CONTROL); + if (priv->rx_csum_en) + reg |= RXCHK_EN; + else + reg &= ~RXCHK_EN; + + /* If UniMAC forwards CRC, we need to skip over it to get + * a valid CHK bit to be set in the per-packet status word + */ + if (priv->rx_csum_en && priv->crc_fwd) + reg |= RXCHK_SKIP_FCS; + else + reg &= ~RXCHK_SKIP_FCS; + + rxchk_writel(priv, reg, RXCHK_CONTROL); + + return 0; +} + +static int bcm_sysport_set_tx_csum(struct net_device *dev, + netdev_features_t wanted) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + u32 reg; + + /* Hardware transmit checksum requires us to enable the Transmit status + * block prepended to the packet contents + */ + priv->tsb_en = !!(wanted & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)); + reg = tdma_readl(priv, TDMA_CONTROL); + if (priv->tsb_en) + reg |= TSB_EN; + else + reg &= ~TSB_EN; + tdma_writel(priv, reg, TDMA_CONTROL); + + return 0; +} + +static int bcm_sysport_set_features(struct net_device *dev, + netdev_features_t features) +{ + netdev_features_t changed = features ^ dev->features; + netdev_features_t wanted = dev->wanted_features; + int ret = 0; + + if (changed & NETIF_F_RXCSUM) + ret = bcm_sysport_set_rx_csum(dev, wanted); + if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) + ret = bcm_sysport_set_tx_csum(dev, wanted); + + return ret; +} + +/* Hardware counters must be kept in sync because the order/offset + * is important here (order in structure declaration = order in hardware) + */ +static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = { + /* general stats */ + STAT_NETDEV(rx_packets), + STAT_NETDEV(tx_packets), + STAT_NETDEV(rx_bytes), + STAT_NETDEV(tx_bytes), + STAT_NETDEV(rx_errors), + STAT_NETDEV(tx_errors), + STAT_NETDEV(rx_dropped), + STAT_NETDEV(tx_dropped), + STAT_NETDEV(multicast), + /* UniMAC RSV counters */ + STAT_MIB_RX("rx_64_octets", mib.rx.pkt_cnt.cnt_64), + STAT_MIB_RX("rx_65_127_oct", mib.rx.pkt_cnt.cnt_127), + STAT_MIB_RX("rx_128_255_oct", mib.rx.pkt_cnt.cnt_255), + STAT_MIB_RX("rx_256_511_oct", mib.rx.pkt_cnt.cnt_511), + STAT_MIB_RX("rx_512_1023_oct", mib.rx.pkt_cnt.cnt_1023), + STAT_MIB_RX("rx_1024_1518_oct", mib.rx.pkt_cnt.cnt_1518), + STAT_MIB_RX("rx_vlan_1519_1522_oct", mib.rx.pkt_cnt.cnt_mgv), + STAT_MIB_RX("rx_1522_2047_oct", mib.rx.pkt_cnt.cnt_2047), + STAT_MIB_RX("rx_2048_4095_oct", mib.rx.pkt_cnt.cnt_4095), + STAT_MIB_RX("rx_4096_9216_oct", mib.rx.pkt_cnt.cnt_9216), + STAT_MIB_RX("rx_pkts", mib.rx.pkt), + STAT_MIB_RX("rx_bytes", mib.rx.bytes), + STAT_MIB_RX("rx_multicast", mib.rx.mca), + STAT_MIB_RX("rx_broadcast", mib.rx.bca), + STAT_MIB_RX("rx_fcs", mib.rx.fcs), + STAT_MIB_RX("rx_control", mib.rx.cf), + STAT_MIB_RX("rx_pause", mib.rx.pf), + STAT_MIB_RX("rx_unknown", mib.rx.uo), + STAT_MIB_RX("rx_align", mib.rx.aln), + STAT_MIB_RX("rx_outrange", mib.rx.flr), + STAT_MIB_RX("rx_code", mib.rx.cde), + STAT_MIB_RX("rx_carrier", mib.rx.fcr), + STAT_MIB_RX("rx_oversize", mib.rx.ovr), + STAT_MIB_RX("rx_jabber", mib.rx.jbr), + STAT_MIB_RX("rx_mtu_err", mib.rx.mtue), + STAT_MIB_RX("rx_good_pkts", mib.rx.pok), + STAT_MIB_RX("rx_unicast", mib.rx.uc), + STAT_MIB_RX("rx_ppp", mib.rx.ppp), + STAT_MIB_RX("rx_crc", mib.rx.rcrc), + /* UniMAC TSV counters */ + STAT_MIB_TX("tx_64_octets", mib.tx.pkt_cnt.cnt_64), + STAT_MIB_TX("tx_65_127_oct", mib.tx.pkt_cnt.cnt_127), + STAT_MIB_TX("tx_128_255_oct", mib.tx.pkt_cnt.cnt_255), + STAT_MIB_TX("tx_256_511_oct", mib.tx.pkt_cnt.cnt_511), + STAT_MIB_TX("tx_512_1023_oct", mib.tx.pkt_cnt.cnt_1023), + STAT_MIB_TX("tx_1024_1518_oct", mib.tx.pkt_cnt.cnt_1518), + STAT_MIB_TX("tx_vlan_1519_1522_oct", mib.tx.pkt_cnt.cnt_mgv), + STAT_MIB_TX("tx_1522_2047_oct", mib.tx.pkt_cnt.cnt_2047), + STAT_MIB_TX("tx_2048_4095_oct", mib.tx.pkt_cnt.cnt_4095), + STAT_MIB_TX("tx_4096_9216_oct", mib.tx.pkt_cnt.cnt_9216), + STAT_MIB_TX("tx_pkts", mib.tx.pkts), + STAT_MIB_TX("tx_multicast", mib.tx.mca), + STAT_MIB_TX("tx_broadcast", mib.tx.bca), + STAT_MIB_TX("tx_pause", mib.tx.pf), + STAT_MIB_TX("tx_control", mib.tx.cf), + STAT_MIB_TX("tx_fcs_err", mib.tx.fcs), + STAT_MIB_TX("tx_oversize", mib.tx.ovr), + STAT_MIB_TX("tx_defer", mib.tx.drf), + STAT_MIB_TX("tx_excess_defer", mib.tx.edf), + STAT_MIB_TX("tx_single_col", mib.tx.scl), + STAT_MIB_TX("tx_multi_col", mib.tx.mcl), + STAT_MIB_TX("tx_late_col", mib.tx.lcl), + STAT_MIB_TX("tx_excess_col", mib.tx.ecl), + STAT_MIB_TX("tx_frags", mib.tx.frg), + STAT_MIB_TX("tx_total_col", mib.tx.ncl), + STAT_MIB_TX("tx_jabber", mib.tx.jbr), + STAT_MIB_TX("tx_bytes", mib.tx.bytes), + STAT_MIB_TX("tx_good_pkts", mib.tx.pok), + STAT_MIB_TX("tx_unicast", mib.tx.uc), + /* UniMAC RUNT counters */ + STAT_RUNT("rx_runt_pkts", mib.rx_runt_cnt), + STAT_RUNT("rx_runt_valid_fcs", mib.rx_runt_fcs), + STAT_RUNT("rx_runt_inval_fcs_align", mib.rx_runt_fcs_align), + STAT_RUNT("rx_runt_bytes", mib.rx_runt_bytes), + /* RXCHK misc statistics */ + STAT_RXCHK("rxchk_bad_csum", mib.rxchk_bad_csum, RXCHK_BAD_CSUM_CNTR), + STAT_RXCHK("rxchk_other_pkt_disc", mib.rxchk_other_pkt_disc, + RXCHK_OTHER_DISC_CNTR), + /* RBUF misc statistics */ + STAT_RBUF("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt, RBUF_OVFL_DISC_CNTR), + STAT_RBUF("rbuf_err_cnt", mib.rbuf_err_cnt, RBUF_ERR_PKT_CNTR), +}; + +#define BCM_SYSPORT_STATS_LEN ARRAY_SIZE(bcm_sysport_gstrings_stats) + +static void bcm_sysport_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); + strlcpy(info->version, "0.1", sizeof(info->version)); + strlcpy(info->bus_info, "platform", sizeof(info->bus_info)); + info->n_stats = BCM_SYSPORT_STATS_LEN; +} + +static u32 bcm_sysport_get_msglvl(struct net_device *dev) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + + return priv->msg_enable; +} + +static void bcm_sysport_set_msglvl(struct net_device *dev, u32 enable) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + + priv->msg_enable = enable; +} + +static int bcm_sysport_get_sset_count(struct net_device *dev, int string_set) +{ + switch (string_set) { + case ETH_SS_STATS: + return BCM_SYSPORT_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void bcm_sysport_get_strings(struct net_device *dev, + u32 stringset, u8 *data) +{ + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < BCM_SYSPORT_STATS_LEN; i++) { + memcpy(data + i * ETH_GSTRING_LEN, + bcm_sysport_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + } + break; + default: + break; + } +} + +static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv) +{ + int i, j = 0; + + for (i = 0; i < BCM_SYSPORT_STATS_LEN; i++) { + const struct bcm_sysport_stats *s; + u8 offset = 0; + u32 val = 0; + char *p; + + s = &bcm_sysport_gstrings_stats[i]; + switch (s->type) { + case BCM_SYSPORT_STAT_NETDEV: + continue; + case BCM_SYSPORT_STAT_MIB_RX: + case BCM_SYSPORT_STAT_MIB_TX: + case BCM_SYSPORT_STAT_RUNT: + if (s->type != BCM_SYSPORT_STAT_MIB_RX) + offset = UMAC_MIB_STAT_OFFSET; + val = umac_readl(priv, UMAC_MIB_START + j + offset); + break; + case BCM_SYSPORT_STAT_RXCHK: + val = rxchk_readl(priv, s->reg_offset); + if (val == ~0) + rxchk_writel(priv, 0, s->reg_offset); + break; + case BCM_SYSPORT_STAT_RBUF: + val = rbuf_readl(priv, s->reg_offset); + if (val == ~0) + rbuf_writel(priv, 0, s->reg_offset); + break; + } + + j += s->stat_sizeof; + p = (char *)priv + s->stat_offset; + *(u32 *)p = val; + } + + netif_dbg(priv, hw, priv->netdev, "updated MIB counters\n"); +} + +static void bcm_sysport_get_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + int i; + + if (netif_running(dev)) + bcm_sysport_update_mib_counters(priv); + + for (i = 0; i < BCM_SYSPORT_STATS_LEN; i++) { + const struct bcm_sysport_stats *s; + char *p; + + s = &bcm_sysport_gstrings_stats[i]; + if (s->type == BCM_SYSPORT_STAT_NETDEV) + p = (char *)&dev->stats; + else + p = (char *)priv; + p += s->stat_offset; + data[i] = *(u32 *)p; + } +} + +static void bcm_sysport_free_cb(struct bcm_sysport_cb *cb) +{ + dev_kfree_skb_any(cb->skb); + cb->skb = NULL; + dma_unmap_addr_set(cb, dma_addr, 0); +} + +static int bcm_sysport_rx_refill(struct bcm_sysport_priv *priv, + struct bcm_sysport_cb *cb) +{ + struct device *kdev = &priv->pdev->dev; + struct net_device *ndev = priv->netdev; + dma_addr_t mapping; + int ret; + + cb->skb = netdev_alloc_skb(priv->netdev, RX_BUF_LENGTH); + if (!cb->skb) { + netif_err(priv, rx_err, ndev, "SKB alloc failed\n"); + return -ENOMEM; + } + + mapping = dma_map_single(kdev, cb->skb->data, + RX_BUF_LENGTH, DMA_FROM_DEVICE); + ret = dma_mapping_error(kdev, mapping); + if (ret) { + bcm_sysport_free_cb(cb); + netif_err(priv, rx_err, ndev, "DMA mapping failure\n"); + return ret; + } + + dma_unmap_addr_set(cb, dma_addr, mapping); + dma_desc_set_addr(priv, priv->rx_bd_assign_ptr, mapping); + + priv->rx_bd_assign_index++; + priv->rx_bd_assign_index &= (priv->num_rx_bds - 1); + priv->rx_bd_assign_ptr = priv->rx_bds + + (priv->rx_bd_assign_index * DESC_SIZE); + + netif_dbg(priv, rx_status, ndev, "RX refill\n"); + + return 0; +} + +static int bcm_sysport_alloc_rx_bufs(struct bcm_sysport_priv *priv) +{ + struct bcm_sysport_cb *cb; + int ret = 0; + unsigned int i; + + for (i = 0; i < priv->num_rx_bds; i++) { + cb = &priv->rx_cbs[priv->rx_bd_assign_index]; + if (cb->skb) + continue; + + ret = bcm_sysport_rx_refill(priv, cb); + if (ret) + break; + } + + return ret; +} + +/* Poll the hardware for up to budget packets to process */ +static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, + unsigned int budget) +{ + struct device *kdev = &priv->pdev->dev; + struct net_device *ndev = priv->netdev; + unsigned int processed = 0, to_process; + struct bcm_sysport_cb *cb; + struct sk_buff *skb; + unsigned int p_index; + u16 len, status; + struct rsb *rsb; + + /* Determine how much we should process since last call */ + p_index = rdma_readl(priv, RDMA_PROD_INDEX); + p_index &= RDMA_PROD_INDEX_MASK; + + if (p_index < priv->rx_c_index) + to_process = (RDMA_CONS_INDEX_MASK + 1) - + priv->rx_c_index + p_index; + else + to_process = p_index - priv->rx_c_index; + + netif_dbg(priv, rx_status, ndev, + "p_index=%d rx_c_index=%d to_process=%d\n", + p_index, priv->rx_c_index, to_process); + + while ((processed < to_process) && + (processed < budget)) { + + cb = &priv->rx_cbs[priv->rx_read_ptr]; + skb = cb->skb; + dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr), + dma_unmap_len(cb, dma_len), DMA_FROM_DEVICE); + + /* Extract the Receive Status Block prepended */ + rsb = (struct rsb *)skb->data; + len = (rsb->rx_status_len >> DESC_LEN_SHIFT) & DESC_LEN_MASK; + status = (rsb->rx_status_len >> DESC_STATUS_SHIFT) & + DESC_STATUS_MASK; + + processed++; + priv->rx_read_ptr++; + if (priv->rx_read_ptr == priv->num_rx_bds) + priv->rx_read_ptr = 0; + + netif_dbg(priv, rx_status, ndev, + "p=%d, c=%d, rd_ptr=%d, len=%d, flag=0x%04x\n", + p_index, priv->rx_c_index, priv->rx_read_ptr, + len, status); + + if (unlikely(!skb)) { + netif_err(priv, rx_err, ndev, "out of memory!\n"); + ndev->stats.rx_dropped++; + ndev->stats.rx_errors++; + goto refill; + } + + if (unlikely(!(status & DESC_EOP) || !(status & DESC_SOP))) { + netif_err(priv, rx_status, ndev, "fragmented packet!\n"); + ndev->stats.rx_dropped++; + ndev->stats.rx_errors++; + bcm_sysport_free_cb(cb); + goto refill; + } + + if (unlikely(status & (RX_STATUS_ERR | RX_STATUS_OVFLOW))) { + netif_err(priv, rx_err, ndev, "error packet\n"); + if (RX_STATUS_OVFLOW) + ndev->stats.rx_over_errors++; + ndev->stats.rx_dropped++; + ndev->stats.rx_errors++; + bcm_sysport_free_cb(cb); + goto refill; + } + + skb_put(skb, len); + + /* Hardware validated our checksum */ + if (likely(status & DESC_L4_CSUM)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* Hardware pre-pends packets with 2bytes between Ethernet + * and IP header plus we have the Receive Status Block, strip + * off all of this from the SKB. + */ + skb_pull(skb, sizeof(*rsb) + 2); + len -= (sizeof(*rsb) + 2); + + /* UniMAC may forward CRC */ + if (priv->crc_fwd) { + skb_trim(skb, len - ETH_FCS_LEN); + len -= ETH_FCS_LEN; + } + + skb->protocol = eth_type_trans(skb, ndev); + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += len; + + napi_gro_receive(&priv->napi, skb); +refill: + bcm_sysport_rx_refill(priv, cb); + } + + return processed; +} + +static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_priv *priv, + struct bcm_sysport_cb *cb, + unsigned int *bytes_compl, + unsigned int *pkts_compl) +{ + struct device *kdev = &priv->pdev->dev; + struct net_device *ndev = priv->netdev; + + if (cb->skb) { + ndev->stats.tx_bytes += cb->skb->len; + *bytes_compl += cb->skb->len; + dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr), + dma_unmap_len(cb, dma_len), + DMA_TO_DEVICE); + ndev->stats.tx_packets++; + (*pkts_compl)++; + bcm_sysport_free_cb(cb); + /* SKB fragment */ + } else if (dma_unmap_addr(cb, dma_addr)) { + ndev->stats.tx_bytes += dma_unmap_len(cb, dma_len); + dma_unmap_page(kdev, dma_unmap_addr(cb, dma_addr), + dma_unmap_len(cb, dma_len), DMA_TO_DEVICE); + dma_unmap_addr_set(cb, dma_addr, 0); + } +} + +/* Reclaim queued SKBs for transmission completion, lockless version */ +static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, + struct bcm_sysport_tx_ring *ring) +{ + struct net_device *ndev = priv->netdev; + unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs; + unsigned int pkts_compl = 0, bytes_compl = 0; + struct bcm_sysport_cb *cb; + struct netdev_queue *txq; + u32 hw_ind; + + txq = netdev_get_tx_queue(ndev, ring->index); + + /* Compute how many descriptors have been processed since last call */ + hw_ind = tdma_readl(priv, TDMA_DESC_RING_PROD_CONS_INDEX(ring->index)); + c_index = (hw_ind >> RING_CONS_INDEX_SHIFT) & RING_CONS_INDEX_MASK; + ring->p_index = (hw_ind & RING_PROD_INDEX_MASK); + + last_c_index = ring->c_index; + num_tx_cbs = ring->size; + + c_index &= (num_tx_cbs - 1); + + if (c_index >= last_c_index) + last_tx_cn = c_index - last_c_index; + else + last_tx_cn = num_tx_cbs - last_c_index + c_index; + + netif_dbg(priv, tx_done, ndev, + "ring=%d c_index=%d last_tx_cn=%d last_c_index=%d\n", + ring->index, c_index, last_tx_cn, last_c_index); + + while (last_tx_cn-- > 0) { + cb = ring->cbs + last_c_index; + bcm_sysport_tx_reclaim_one(priv, cb, &bytes_compl, &pkts_compl); + + ring->desc_count++; + last_c_index++; + last_c_index &= (num_tx_cbs - 1); + } + + ring->c_index = c_index; + + if (netif_tx_queue_stopped(txq) && pkts_compl) + netif_tx_wake_queue(txq); + + netif_dbg(priv, tx_done, ndev, + "ring=%d c_index=%d pkts_compl=%d, bytes_compl=%d\n", + ring->index, ring->c_index, pkts_compl, bytes_compl); + + return pkts_compl; +} + +/* Locked version of the per-ring TX reclaim routine */ +static unsigned int bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, + struct bcm_sysport_tx_ring *ring) +{ + unsigned int released; + + spin_lock(&ring->lock); + released = __bcm_sysport_tx_reclaim(priv, ring); + spin_unlock(&ring->lock); + + return released; +} + +static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget) +{ + struct bcm_sysport_tx_ring *ring = + container_of(napi, struct bcm_sysport_tx_ring, napi); + unsigned int work_done = 0; + + work_done = bcm_sysport_tx_reclaim(ring->priv, ring); + + if (work_done < budget) { + napi_complete(napi); + /* re-enable TX interrupt */ + intrl2_1_mask_clear(ring->priv, BIT(ring->index)); + } + + return work_done; +} + +static void bcm_sysport_tx_reclaim_all(struct bcm_sysport_priv *priv) +{ + unsigned int q; + + for (q = 0; q < priv->netdev->num_tx_queues; q++) + bcm_sysport_tx_reclaim(priv, &priv->tx_rings[q]); +} + +static int bcm_sysport_poll(struct napi_struct *napi, int budget) +{ + struct bcm_sysport_priv *priv = + container_of(napi, struct bcm_sysport_priv, napi); + unsigned int work_done = 0; + + work_done = bcm_sysport_desc_rx(priv, budget); + + priv->rx_c_index += work_done; + priv->rx_c_index &= RDMA_CONS_INDEX_MASK; + rdma_writel(priv, priv->rx_c_index, RDMA_CONS_INDEX); + + if (work_done < budget) { + napi_complete(napi); + /* re-enable RX interrupts */ + intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE); + } + + return work_done; +} + + +/* RX and misc interrupt routine */ +static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bcm_sysport_priv *priv = netdev_priv(dev); + + priv->irq0_stat = intrl2_0_readl(priv, INTRL2_CPU_STATUS) & + ~intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); + intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR); + + if (unlikely(priv->irq0_stat == 0)) { + netdev_warn(priv->netdev, "spurious RX interrupt\n"); + return IRQ_NONE; + } + + if (priv->irq0_stat & INTRL2_0_RDMA_MBDONE) { + if (likely(napi_schedule_prep(&priv->napi))) { + /* disable RX interrupts */ + intrl2_0_mask_set(priv, INTRL2_0_RDMA_MBDONE); + __napi_schedule(&priv->napi); + } + } + + /* TX ring is full, perform a full reclaim since we do not know + * which one would trigger this interrupt + */ + if (priv->irq0_stat & INTRL2_0_TX_RING_FULL) + bcm_sysport_tx_reclaim_all(priv); + + return IRQ_HANDLED; +} + +/* TX interrupt service routine */ +static irqreturn_t bcm_sysport_tx_isr(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bcm_sysport_priv *priv = netdev_priv(dev); + struct bcm_sysport_tx_ring *txr; + unsigned int ring; + + priv->irq1_stat = intrl2_1_readl(priv, INTRL2_CPU_STATUS) & + ~intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); + intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); + + if (unlikely(priv->irq1_stat == 0)) { + netdev_warn(priv->netdev, "spurious TX interrupt\n"); + return IRQ_NONE; + } + + for (ring = 0; ring < dev->num_tx_queues; ring++) { + if (!(priv->irq1_stat & BIT(ring))) + continue; + + txr = &priv->tx_rings[ring]; + + if (likely(napi_schedule_prep(&txr->napi))) { + intrl2_1_mask_set(priv, BIT(ring)); + __napi_schedule(&txr->napi); + } + } + + return IRQ_HANDLED; +} + +static int bcm_sysport_insert_tsb(struct sk_buff *skb, struct net_device *dev) +{ + struct sk_buff *nskb; + struct tsb *tsb; + u32 csum_info; + u8 ip_proto; + u16 csum_start; + u16 ip_ver; + + /* Re-allocate SKB if needed */ + if (unlikely(skb_headroom(skb) < sizeof(*tsb))) { + nskb = skb_realloc_headroom(skb, sizeof(*tsb)); + dev_kfree_skb(skb); + if (!nskb) { + dev->stats.tx_errors++; + dev->stats.tx_dropped++; + return -ENOMEM; + } + skb = nskb; + } + + tsb = (struct tsb *)skb_push(skb, sizeof(*tsb)); + /* Zero-out TSB by default */ + memset(tsb, 0, sizeof(*tsb)); + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + ip_ver = htons(skb->protocol); + switch (ip_ver) { + case ETH_P_IP: + ip_proto = ip_hdr(skb)->protocol; + break; + case ETH_P_IPV6: + ip_proto = ipv6_hdr(skb)->nexthdr; + break; + default: + return 0; + } + + /* Get the checksum offset and the L4 (transport) offset */ + csum_start = skb_checksum_start_offset(skb) - sizeof(*tsb); + csum_info = (csum_start + skb->csum_offset) & L4_CSUM_PTR_MASK; + csum_info |= (csum_start << L4_PTR_SHIFT); + + if (ip_proto == IPPROTO_TCP || ip_proto == IPPROTO_UDP) { + csum_info |= L4_LENGTH_VALID; + if (ip_proto == IPPROTO_UDP && ip_ver == ETH_P_IP) + csum_info |= L4_UDP; + } else + csum_info = 0; + + tsb->l4_ptr_dest_map = csum_info; + } + + return 0; +} + +static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + struct device *kdev = &priv->pdev->dev; + struct bcm_sysport_tx_ring *ring; + struct bcm_sysport_cb *cb; + struct netdev_queue *txq; + struct dma_desc *desc; + dma_addr_t mapping; + u32 len_status; + u16 queue; + int ret; + + queue = skb_get_queue_mapping(skb); + txq = netdev_get_tx_queue(dev, queue); + ring = &priv->tx_rings[queue]; + + /* lock against tx reclaim in BH context */ + spin_lock(&ring->lock); + if (unlikely(ring->desc_count == 0)) { + netif_tx_stop_queue(txq); + netdev_err(dev, "queue %d awake and ring full!\n", queue); + ret = NETDEV_TX_BUSY; + goto out; + } + + /* Insert TSB and checksum infos */ + if (priv->tsb_en) { + ret = bcm_sysport_insert_tsb(skb, dev); + if (ret) { + ret = NETDEV_TX_OK; + goto out; + } + } + + mapping = dma_map_single(kdev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(kdev, mapping)) { + netif_err(priv, tx_err, dev, "DMA map failed at %p (len=%d)\n", + skb->data, skb->len); + ret = NETDEV_TX_OK; + goto out; + } + + /* Remember the SKB for future freeing */ + cb = &ring->cbs[ring->curr_desc]; + cb->skb = skb; + dma_unmap_addr_set(cb, dma_addr, mapping); + dma_unmap_len_set(cb, dma_len, skb->len); + + /* Fetch a descriptor entry from our pool */ + desc = ring->desc_cpu; + + desc->addr_lo = lower_32_bits(mapping); + len_status = upper_32_bits(mapping) & DESC_ADDR_HI_MASK; + len_status |= (skb->len << DESC_LEN_SHIFT); + len_status |= (DESC_SOP | DESC_EOP | TX_STATUS_APP_CRC) << + DESC_STATUS_SHIFT; + if (skb->ip_summed == CHECKSUM_PARTIAL) + len_status |= (DESC_L4_CSUM << DESC_STATUS_SHIFT); + + ring->curr_desc++; + if (ring->curr_desc == ring->size) + ring->curr_desc = 0; + ring->desc_count--; + + /* Ensure write completion of the descriptor status/length + * in DRAM before the System Port WRITE_PORT register latches + * the value + */ + wmb(); + desc->addr_status_len = len_status; + wmb(); + + /* Write this descriptor address to the RING write port */ + tdma_port_write_desc_addr(priv, desc, ring->index); + + /* Check ring space and update SW control flow */ + if (ring->desc_count == 0) + netif_tx_stop_queue(txq); + + netif_dbg(priv, tx_queued, dev, "ring=%d desc_count=%d, curr_desc=%d\n", + ring->index, ring->desc_count, ring->curr_desc); + + ret = NETDEV_TX_OK; +out: + spin_unlock(&ring->lock); + return ret; +} + +static void bcm_sysport_tx_timeout(struct net_device *dev) +{ + netdev_warn(dev, "transmit timeout!\n"); + + dev->trans_start = jiffies; + dev->stats.tx_errors++; + + netif_tx_wake_all_queues(dev); +} + +/* phylib adjust link callback */ +static void bcm_sysport_adj_link(struct net_device *dev) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + unsigned int changed = 0; + u32 cmd_bits = 0, reg; + + if (priv->old_link != phydev->link) { + changed = 1; + priv->old_link = phydev->link; + } + + if (priv->old_duplex != phydev->duplex) { + changed = 1; + priv->old_duplex = phydev->duplex; + } + + switch (phydev->speed) { + case SPEED_2500: + cmd_bits = CMD_SPEED_2500; + break; + case SPEED_1000: + cmd_bits = CMD_SPEED_1000; + break; + case SPEED_100: + cmd_bits = CMD_SPEED_100; + break; + case SPEED_10: + cmd_bits = CMD_SPEED_10; + break; + default: + break; + } + cmd_bits <<= CMD_SPEED_SHIFT; + + if (phydev->duplex == DUPLEX_HALF) + cmd_bits |= CMD_HD_EN; + + if (priv->old_pause != phydev->pause) { + changed = 1; + priv->old_pause = phydev->pause; + } + + if (!phydev->pause) + cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE; + + reg = umac_readl(priv, UMAC_CMD); + reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) | + CMD_HD_EN | CMD_RX_PAUSE_IGNORE | + CMD_TX_PAUSE_IGNORE); + reg |= cmd_bits; + umac_writel(priv, reg, UMAC_CMD); + + if (changed) + phy_print_status(priv->phydev); +} + +static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv, + unsigned int index) +{ + struct bcm_sysport_tx_ring *ring = &priv->tx_rings[index]; + struct device *kdev = &priv->pdev->dev; + size_t size; + void *p; + u32 reg; + + /* Simple descriptors partitioning for now */ + size = 256; + + /* We just need one DMA descriptor which is DMA-able, since writing to + * the port will allocate a new descriptor in its internal linked-list + */ + p = dma_zalloc_coherent(kdev, 1, &ring->desc_dma, GFP_KERNEL); + if (!p) { + netif_err(priv, hw, priv->netdev, "DMA alloc failed\n"); + return -ENOMEM; + } + + ring->cbs = kzalloc(sizeof(struct bcm_sysport_cb) * size, GFP_KERNEL); + if (!ring->cbs) { + netif_err(priv, hw, priv->netdev, "CB allocation failed\n"); + return -ENOMEM; + } + + /* Initialize SW view of the ring */ + spin_lock_init(&ring->lock); + ring->priv = priv; + netif_napi_add(priv->netdev, &ring->napi, bcm_sysport_tx_poll, 64); + ring->index = index; + ring->size = size; + ring->alloc_size = ring->size; + ring->desc_cpu = p; + ring->desc_count = ring->size; + ring->curr_desc = 0; + + /* Initialize HW ring */ + tdma_writel(priv, RING_EN, TDMA_DESC_RING_HEAD_TAIL_PTR(index)); + tdma_writel(priv, 0, TDMA_DESC_RING_COUNT(index)); + tdma_writel(priv, 1, TDMA_DESC_RING_INTR_CONTROL(index)); + tdma_writel(priv, 0, TDMA_DESC_RING_PROD_CONS_INDEX(index)); + tdma_writel(priv, RING_IGNORE_STATUS, TDMA_DESC_RING_MAPPING(index)); + tdma_writel(priv, 0, TDMA_DESC_RING_PCP_DEI_VID(index)); + + /* Program the number of descriptors as MAX_THRESHOLD and half of + * its size for the hysteresis trigger + */ + tdma_writel(priv, ring->size | + 1 << RING_HYST_THRESH_SHIFT, + TDMA_DESC_RING_MAX_HYST(index)); + + /* Enable the ring queue in the arbiter */ + reg = tdma_readl(priv, TDMA_TIER1_ARB_0_QUEUE_EN); + reg |= (1 << index); + tdma_writel(priv, reg, TDMA_TIER1_ARB_0_QUEUE_EN); + + napi_enable(&ring->napi); + + netif_dbg(priv, hw, priv->netdev, + "TDMA cfg, size=%d, desc_cpu=%p\n", + ring->size, ring->desc_cpu); + + return 0; +} + +static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv, + unsigned int index) +{ + struct bcm_sysport_tx_ring *ring = &priv->tx_rings[index]; + struct device *kdev = &priv->pdev->dev; + u32 reg; + + /* Caller should stop the TDMA engine */ + reg = tdma_readl(priv, TDMA_STATUS); + if (!(reg & TDMA_DISABLED)) + netdev_warn(priv->netdev, "TDMA not stopped!\n"); + + napi_disable(&ring->napi); + netif_napi_del(&ring->napi); + + bcm_sysport_tx_reclaim(priv, ring); + + kfree(ring->cbs); + ring->cbs = NULL; + + if (ring->desc_dma) { + dma_free_coherent(kdev, 1, ring->desc_cpu, ring->desc_dma); + ring->desc_dma = 0; + } + ring->size = 0; + ring->alloc_size = 0; + + netif_dbg(priv, hw, priv->netdev, "TDMA fini done\n"); +} + +/* RDMA helper */ +static inline int rdma_enable_set(struct bcm_sysport_priv *priv, + unsigned int enable) +{ + unsigned int timeout = 1000; + u32 reg; + + reg = rdma_readl(priv, RDMA_CONTROL); + if (enable) + reg |= RDMA_EN; + else + reg &= ~RDMA_EN; + rdma_writel(priv, reg, RDMA_CONTROL); + + /* Poll for RMDA disabling completion */ + do { + reg = rdma_readl(priv, RDMA_STATUS); + if (!!(reg & RDMA_DISABLED) == !enable) + return 0; + usleep_range(1000, 2000); + } while (timeout-- > 0); + + netdev_err(priv->netdev, "timeout waiting for RDMA to finish\n"); + + return -ETIMEDOUT; +} + +/* TDMA helper */ +static inline int tdma_enable_set(struct bcm_sysport_priv *priv, + unsigned int enable) +{ + unsigned int timeout = 1000; + u32 reg; + + reg = tdma_readl(priv, TDMA_CONTROL); + if (enable) + reg |= TDMA_EN; + else + reg &= ~TDMA_EN; + tdma_writel(priv, reg, TDMA_CONTROL); + + /* Poll for TMDA disabling completion */ + do { + reg = tdma_readl(priv, TDMA_STATUS); + if (!!(reg & TDMA_DISABLED) == !enable) + return 0; + + usleep_range(1000, 2000); + } while (timeout-- > 0); + + netdev_err(priv->netdev, "timeout waiting for TDMA to finish\n"); + + return -ETIMEDOUT; +} + +static int bcm_sysport_init_rx_ring(struct bcm_sysport_priv *priv) +{ + u32 reg; + int ret; + + /* Initialize SW view of the RX ring */ + priv->num_rx_bds = NUM_RX_DESC; + priv->rx_bds = priv->base + SYS_PORT_RDMA_OFFSET; + priv->rx_bd_assign_ptr = priv->rx_bds; + priv->rx_bd_assign_index = 0; + priv->rx_c_index = 0; + priv->rx_read_ptr = 0; + priv->rx_cbs = kzalloc(priv->num_rx_bds * + sizeof(struct bcm_sysport_cb), GFP_KERNEL); + if (!priv->rx_cbs) { + netif_err(priv, hw, priv->netdev, "CB allocation failed\n"); + return -ENOMEM; + } + + ret = bcm_sysport_alloc_rx_bufs(priv); + if (ret) { + netif_err(priv, hw, priv->netdev, "SKB allocation failed\n"); + return ret; + } + + /* Initialize HW, ensure RDMA is disabled */ + reg = rdma_readl(priv, RDMA_STATUS); + if (!(reg & RDMA_DISABLED)) + rdma_enable_set(priv, 0); + + rdma_writel(priv, 0, RDMA_WRITE_PTR_LO); + rdma_writel(priv, 0, RDMA_WRITE_PTR_HI); + rdma_writel(priv, 0, RDMA_PROD_INDEX); + rdma_writel(priv, 0, RDMA_CONS_INDEX); + rdma_writel(priv, priv->num_rx_bds << RDMA_RING_SIZE_SHIFT | + RX_BUF_LENGTH, RDMA_RING_BUF_SIZE); + /* Operate the queue in ring mode */ + rdma_writel(priv, 0, RDMA_START_ADDR_HI); + rdma_writel(priv, 0, RDMA_START_ADDR_LO); + rdma_writel(priv, 0, RDMA_END_ADDR_HI); + rdma_writel(priv, NUM_HW_RX_DESC_WORDS - 1, RDMA_END_ADDR_LO); + + rdma_writel(priv, 1, RDMA_MBDONE_INTR); + + netif_dbg(priv, hw, priv->netdev, + "RDMA cfg, num_rx_bds=%d, rx_bds=%p\n", + priv->num_rx_bds, priv->rx_bds); + + return 0; +} + +static void bcm_sysport_fini_rx_ring(struct bcm_sysport_priv *priv) +{ + struct bcm_sysport_cb *cb; + unsigned int i; + u32 reg; + + /* Caller should ensure RDMA is disabled */ + reg = rdma_readl(priv, RDMA_STATUS); + if (!(reg & RDMA_DISABLED)) + netdev_warn(priv->netdev, "RDMA not stopped!\n"); + + for (i = 0; i < priv->num_rx_bds; i++) { + cb = &priv->rx_cbs[i]; + if (dma_unmap_addr(cb, dma_addr)) + dma_unmap_single(&priv->pdev->dev, + dma_unmap_addr(cb, dma_addr), + RX_BUF_LENGTH, DMA_FROM_DEVICE); + bcm_sysport_free_cb(cb); + } + + kfree(priv->rx_cbs); + priv->rx_cbs = NULL; + + netif_dbg(priv, hw, priv->netdev, "RDMA fini done\n"); +} + +static void bcm_sysport_set_rx_mode(struct net_device *dev) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + u32 reg; + + reg = umac_readl(priv, UMAC_CMD); + if (dev->flags & IFF_PROMISC) + reg |= CMD_PROMISC; + else + reg &= ~CMD_PROMISC; + umac_writel(priv, reg, UMAC_CMD); + + /* No support for ALLMULTI */ + if (dev->flags & IFF_ALLMULTI) + return; +} + +static inline void umac_enable_set(struct bcm_sysport_priv *priv, + unsigned int enable) +{ + u32 reg; + + reg = umac_readl(priv, UMAC_CMD); + if (enable) + reg |= CMD_RX_EN | CMD_TX_EN; + else + reg &= ~(CMD_RX_EN | CMD_TX_EN); + umac_writel(priv, reg, UMAC_CMD); +} + +static inline int umac_reset(struct bcm_sysport_priv *priv) +{ + unsigned int timeout = 0; + u32 reg; + int ret = 0; + + umac_writel(priv, 0, UMAC_CMD); + while (timeout++ < 1000) { + reg = umac_readl(priv, UMAC_CMD); + if (!(reg & CMD_SW_RESET)) + break; + + udelay(1); + } + + if (timeout == 1000) { + dev_err(&priv->pdev->dev, + "timeout waiting for MAC to come out of reset\n"); + ret = -ETIMEDOUT; + } + + return ret; +} + +static void umac_set_hw_addr(struct bcm_sysport_priv *priv, + unsigned char *addr) +{ + umac_writel(priv, (addr[0] << 24) | (addr[1] << 16) | + (addr[2] << 8) | addr[3], UMAC_MAC0); + umac_writel(priv, (addr[4] << 8) | addr[5], UMAC_MAC1); +} + +static void topctrl_flush(struct bcm_sysport_priv *priv) +{ + topctrl_writel(priv, RX_FLUSH, RX_FLUSH_CNTL); + topctrl_writel(priv, TX_FLUSH, TX_FLUSH_CNTL); + mdelay(1); + topctrl_writel(priv, 0, RX_FLUSH_CNTL); + topctrl_writel(priv, 0, TX_FLUSH_CNTL); +} + +static int bcm_sysport_open(struct net_device *dev) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + unsigned int i; + u32 reg; + int ret; + + /* Reset UniMAC */ + ret = umac_reset(priv); + if (ret) { + netdev_err(dev, "UniMAC reset failed\n"); + return ret; + } + + /* Flush TX and RX FIFOs at TOPCTRL level */ + topctrl_flush(priv); + + /* Disable the UniMAC RX/TX */ + umac_enable_set(priv, 0); + + /* Enable RBUF 2bytes alignment and Receive Status Block */ + reg = rbuf_readl(priv, RBUF_CONTROL); + reg |= RBUF_4B_ALGN | RBUF_RSB_EN; + rbuf_writel(priv, reg, RBUF_CONTROL); + + /* Set maximum frame length */ + umac_writel(priv, UMAC_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN); + + /* Set MAC address */ + umac_set_hw_addr(priv, dev->dev_addr); + + /* Read CRC forward */ + priv->crc_fwd = !!(umac_readl(priv, UMAC_CMD) & CMD_CRC_FWD); + + priv->phydev = of_phy_connect_fixed_link(dev, bcm_sysport_adj_link, + priv->phy_interface); + if (!priv->phydev) { + netdev_err(dev, "could not attach to PHY\n"); + return -ENODEV; + } + + /* Reset house keeping link status */ + priv->old_duplex = -1; + priv->old_link = -1; + priv->old_pause = -1; + + /* mask all interrupts and request them */ + intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); + intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); + intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); + intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); + intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + + ret = request_irq(priv->irq0, bcm_sysport_rx_isr, 0, dev->name, dev); + if (ret) { + netdev_err(dev, "failed to request RX interrupt\n"); + goto out_phy_disconnect; + } + + ret = request_irq(priv->irq1, bcm_sysport_tx_isr, 0, dev->name, dev); + if (ret) { + netdev_err(dev, "failed to request TX interrupt\n"); + goto out_free_irq0; + } + + /* Initialize both hardware and software ring */ + for (i = 0; i < dev->num_tx_queues; i++) { + ret = bcm_sysport_init_tx_ring(priv, i); + if (ret) { + netdev_err(dev, "failed to initialize TX ring %d\n", + i); + goto out_free_tx_ring; + } + } + + /* Initialize linked-list */ + tdma_writel(priv, TDMA_LL_RAM_INIT_BUSY, TDMA_STATUS); + + /* Initialize RX ring */ + ret = bcm_sysport_init_rx_ring(priv); + if (ret) { + netdev_err(dev, "failed to initialize RX ring\n"); + goto out_free_rx_ring; + } + + /* Turn on RDMA */ + ret = rdma_enable_set(priv, 1); + if (ret) + goto out_free_rx_ring; + + /* Enable RX interrupt and TX ring full interrupt */ + intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE | INTRL2_0_TX_RING_FULL); + + /* Turn on TDMA */ + ret = tdma_enable_set(priv, 1); + if (ret) + goto out_clear_rx_int; + + /* Enable NAPI */ + napi_enable(&priv->napi); + + /* Turn on UniMAC TX/RX */ + umac_enable_set(priv, 1); + + phy_start(priv->phydev); + + /* Enable TX interrupts for the 32 TXQs */ + intrl2_1_mask_clear(priv, 0xffffffff); + + /* Last call before we start the real business */ + netif_tx_start_all_queues(dev); + + return 0; + +out_clear_rx_int: + intrl2_0_mask_set(priv, INTRL2_0_RDMA_MBDONE | INTRL2_0_TX_RING_FULL); +out_free_rx_ring: + bcm_sysport_fini_rx_ring(priv); +out_free_tx_ring: + for (i = 0; i < dev->num_tx_queues; i++) + bcm_sysport_fini_tx_ring(priv, i); + free_irq(priv->irq1, dev); +out_free_irq0: + free_irq(priv->irq0, dev); +out_phy_disconnect: + phy_disconnect(priv->phydev); + return ret; +} + +static int bcm_sysport_stop(struct net_device *dev) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + unsigned int i; + u32 reg; + int ret; + + /* stop all software from updating hardware */ + netif_tx_stop_all_queues(dev); + napi_disable(&priv->napi); + phy_stop(priv->phydev); + + /* mask all interrupts */ + intrl2_0_mask_set(priv, 0xffffffff); + intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); + intrl2_1_mask_set(priv, 0xffffffff); + intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); + + /* Disable UniMAC RX */ + reg = umac_readl(priv, UMAC_CMD); + reg &= ~CMD_RX_EN; + umac_writel(priv, reg, UMAC_CMD); + + ret = tdma_enable_set(priv, 0); + if (ret) { + netdev_err(dev, "timeout disabling RDMA\n"); + return ret; + } + + /* Wait for a maximum packet size to be drained */ + usleep_range(2000, 3000); + + ret = rdma_enable_set(priv, 0); + if (ret) { + netdev_err(dev, "timeout disabling TDMA\n"); + return ret; + } + + /* Disable UniMAC TX */ + reg = umac_readl(priv, UMAC_CMD); + reg &= ~CMD_TX_EN; + umac_writel(priv, reg, UMAC_CMD); + + /* Free RX/TX rings SW structures */ + for (i = 0; i < dev->num_tx_queues; i++) + bcm_sysport_fini_tx_ring(priv, i); + bcm_sysport_fini_rx_ring(priv); + + free_irq(priv->irq0, dev); + free_irq(priv->irq1, dev); + + /* Disconnect from PHY */ + phy_disconnect(priv->phydev); + + return 0; +} + +static struct ethtool_ops bcm_sysport_ethtool_ops = { + .get_settings = bcm_sysport_get_settings, + .set_settings = bcm_sysport_set_settings, + .get_drvinfo = bcm_sysport_get_drvinfo, + .get_msglevel = bcm_sysport_get_msglvl, + .set_msglevel = bcm_sysport_set_msglvl, + .get_link = ethtool_op_get_link, + .get_strings = bcm_sysport_get_strings, + .get_ethtool_stats = bcm_sysport_get_stats, + .get_sset_count = bcm_sysport_get_sset_count, +}; + +static const struct net_device_ops bcm_sysport_netdev_ops = { + .ndo_start_xmit = bcm_sysport_xmit, + .ndo_tx_timeout = bcm_sysport_tx_timeout, + .ndo_open = bcm_sysport_open, + .ndo_stop = bcm_sysport_stop, + .ndo_set_features = bcm_sysport_set_features, + .ndo_set_rx_mode = bcm_sysport_set_rx_mode, +}; + +#define REV_FMT "v%2x.%02x" + +static int bcm_sysport_probe(struct platform_device *pdev) +{ + struct bcm_sysport_priv *priv; + struct device_node *dn; + struct net_device *dev; + const void *macaddr; + struct resource *r; + u32 txq, rxq; + int ret; + + dn = pdev->dev.of_node; + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + /* Read the Transmit/Receive Queue properties */ + if (of_property_read_u32(dn, "systemport,num-txq", &txq)) + txq = TDMA_NUM_RINGS; + if (of_property_read_u32(dn, "systemport,num-rxq", &rxq)) + rxq = 1; + + dev = alloc_etherdev_mqs(sizeof(*priv), txq, rxq); + if (!dev) + return -ENOMEM; + + /* Initialize private members */ + priv = netdev_priv(dev); + + priv->irq0 = platform_get_irq(pdev, 0); + priv->irq1 = platform_get_irq(pdev, 1); + if (priv->irq0 <= 0 || priv->irq1 <= 0) { + dev_err(&pdev->dev, "invalid interrupts\n"); + ret = -EINVAL; + goto err; + } + + priv->base = devm_request_and_ioremap(&pdev->dev, r); + if (!priv->base) { + dev_err(&pdev->dev, "register remap failed\n"); + ret = -ENOMEM; + goto err; + } + + priv->netdev = dev; + priv->pdev = pdev; + + priv->phy_interface = of_get_phy_mode(dn); + /* Default to GMII interface mode */ + if (priv->phy_interface < 0) + priv->phy_interface = PHY_INTERFACE_MODE_GMII; + + /* Initialize netdevice members */ + macaddr = of_get_mac_address(dn); + if (!macaddr || !is_valid_ether_addr(macaddr)) { + dev_warn(&pdev->dev, "using random Ethernet MAC\n"); + random_ether_addr(dev->dev_addr); + } else { + ether_addr_copy(dev->dev_addr, macaddr); + } + + SET_NETDEV_DEV(dev, &pdev->dev); + dev_set_drvdata(&pdev->dev, dev); + SET_ETHTOOL_OPS(dev, &bcm_sysport_ethtool_ops); + dev->netdev_ops = &bcm_sysport_netdev_ops; + netif_napi_add(dev, &priv->napi, bcm_sysport_poll, 64); + + /* HW supported features, none enabled by default */ + dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + + /* Set the needed headroom once and for all */ + BUILD_BUG_ON(sizeof(struct tsb) != 8); + dev->needed_headroom += sizeof(struct tsb); + + /* We are interfaced to a switch which handles the multicast + * filtering for us, so we do not support programming any + * multicast hash table in this Ethernet MAC. + */ + dev->flags &= ~IFF_MULTICAST; + + ret = register_netdev(dev); + if (ret) { + dev_err(&pdev->dev, "failed to register net_device\n"); + goto err; + } + + priv->rev = topctrl_readl(priv, REV_CNTL) & REV_MASK; + dev_info(&pdev->dev, + "Broadcom SYSTEMPORT" REV_FMT + " at 0x%p (irqs: %d, %d, TXQs: %d, RXQs: %d)\n", + (priv->rev >> 8) & 0xff, priv->rev & 0xff, + priv->base, priv->irq0, priv->irq1, txq, rxq); + + return 0; +err: + free_netdev(dev); + return ret; +} + +static int bcm_sysport_remove(struct platform_device *pdev) +{ + struct net_device *dev = dev_get_drvdata(&pdev->dev); + + /* Not much to do, ndo_close has been called + * and we use managed allocations + */ + unregister_netdev(dev); + free_netdev(dev); + dev_set_drvdata(&pdev->dev, NULL); + + return 0; +} + +static const struct of_device_id bcm_sysport_of_match[] = { + { .compatible = "brcm,systemport-v1.00" }, + { .compatible = "brcm,systemport" }, + { /* sentinel */ } +}; + +static struct platform_driver bcm_sysport_driver = { + .probe = bcm_sysport_probe, + .remove = bcm_sysport_remove, + .driver = { + .name = "brcm-systemport", + .owner = THIS_MODULE, + .of_match_table = bcm_sysport_of_match, + }, +}; +module_platform_driver(bcm_sysport_driver); + +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("Broadcom System Port Ethernet MAC driver"); +MODULE_ALIAS("platform:brcm-systemport"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h new file mode 100644 index 00000000000000..a0441e7c83cd84 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bcmsysport.h @@ -0,0 +1,677 @@ +/* + * Broadcom BCM7xxx System Port Ethernet MAC driver + * + * Copyright (C) 2014 Broadcom 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. + */ + +#ifndef __BCM_SYSPORT_H +#define __BCM_SYSPORT_H + +#include + +/* Receive/transmit descriptor format */ +#define DESC_ADDR_HI_STATUS_LEN 0x00 +#define DESC_ADDR_HI_SHIFT 0 +#define DESC_ADDR_HI_MASK 0xff +#define DESC_STATUS_SHIFT 8 +#define DESC_STATUS_MASK 0x3ff +#define DESC_LEN_SHIFT 18 +#define DESC_LEN_MASK 0x7fff +#define DESC_ADDR_LO 0x04 + +/* HW supports 40-bit addressing hence the */ +#define DESC_SIZE (WORDS_PER_DESC * sizeof(u32)) + +/* Default RX buffer allocation size */ +#define RX_BUF_LENGTH 2048 + +/* Body(1500) + EH_SIZE(14) + VLANTAG(4) + BRCMTAG(6) + FCS(4) = 1528. + * 1536 is multiple of 256 bytes + */ +#define ENET_BRCM_TAG_LEN 6 +#define ENET_PAD 8 +#define UMAC_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \ + ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD) + +/* Transmit status block */ +struct tsb { + u32 pcp_dei_vid; +#define PCP_DEI_MASK 0xf +#define VID_SHIFT 4 +#define VID_MASK 0xfff + u32 l4_ptr_dest_map; +#define L4_CSUM_PTR_MASK 0x1ff +#define L4_PTR_SHIFT 9 +#define L4_PTR_MASK 0x1ff +#define L4_UDP (1 << 18) +#define L4_LENGTH_VALID (1 << 19) +#define DEST_MAP_SHIFT 20 +#define DEST_MAP_MASK 0x1ff +}; + +/* Receive status block uses the same + * definitions as the DMA descriptor + */ +struct rsb { + u32 rx_status_len; + u32 brcm_egress_tag; +}; + +/* Common Receive/Transmit status bits */ +#define DESC_L4_CSUM (1 << 7) +#define DESC_SOP (1 << 8) +#define DESC_EOP (1 << 9) + +/* Receive Status bits */ +#define RX_STATUS_UCAST 0 +#define RX_STATUS_BCAST 0x04 +#define RX_STATUS_MCAST 0x08 +#define RX_STATUS_L2_MCAST 0x0c +#define RX_STATUS_ERR (1 << 4) +#define RX_STATUS_OVFLOW (1 << 5) +#define RX_STATUS_PARSE_FAIL (1 << 6) + +/* Transmit Status bits */ +#define TX_STATUS_VLAN_NO_ACT 0x00 +#define TX_STATUS_VLAN_PCP_TSB 0x01 +#define TX_STATUS_VLAN_QUEUE 0x02 +#define TX_STATUS_VLAN_VID_TSB 0x03 +#define TX_STATUS_OWR_CRC (1 << 2) +#define TX_STATUS_APP_CRC (1 << 3) +#define TX_STATUS_BRCM_TAG_NO_ACT 0 +#define TX_STATUS_BRCM_TAG_ZERO 0x10 +#define TX_STATUS_BRCM_TAG_ONE_QUEUE 0x20 +#define TX_STATUS_BRCM_TAG_ONE_TSB 0x30 +#define TX_STATUS_SKIP_BYTES (1 << 6) + +/* Specific register definitions */ +#define SYS_PORT_TOPCTRL_OFFSET 0 +#define REV_CNTL 0x00 +#define REV_MASK 0xffff + +#define RX_FLUSH_CNTL 0x04 +#define RX_FLUSH (1 << 0) + +#define TX_FLUSH_CNTL 0x08 +#define TX_FLUSH (1 << 0) + +#define MISC_CNTL 0x0c +#define SYS_CLK_SEL (1 << 0) +#define TDMA_EOP_SEL (1 << 1) + +/* Level-2 Interrupt controller offsets and defines */ +#define SYS_PORT_INTRL2_0_OFFSET 0x200 +#define SYS_PORT_INTRL2_1_OFFSET 0x240 +#define INTRL2_CPU_STATUS 0x00 +#define INTRL2_CPU_SET 0x04 +#define INTRL2_CPU_CLEAR 0x08 +#define INTRL2_CPU_MASK_STATUS 0x0c +#define INTRL2_CPU_MASK_SET 0x10 +#define INTRL2_CPU_MASK_CLEAR 0x14 + +/* Level-2 instance 0 interrupt bits */ +#define INTRL2_0_GISB_ERR (1 << 0) +#define INTRL2_0_RBUF_OVFLOW (1 << 1) +#define INTRL2_0_TBUF_UNDFLOW (1 << 2) +#define INTRL2_0_MPD (1 << 3) +#define INTRL2_0_BRCM_MATCH_TAG (1 << 4) +#define INTRL2_0_RDMA_MBDONE (1 << 5) +#define INTRL2_0_OVER_MAX_THRESH (1 << 6) +#define INTRL2_0_BELOW_HYST_THRESH (1 << 7) +#define INTRL2_0_FREE_LIST_EMPTY (1 << 8) +#define INTRL2_0_TX_RING_FULL (1 << 9) +#define INTRL2_0_DESC_ALLOC_ERR (1 << 10) +#define INTRL2_0_UNEXP_PKTSIZE_ACK (1 << 11) + +/* RXCHK offset and defines */ +#define SYS_PORT_RXCHK_OFFSET 0x300 + +#define RXCHK_CONTROL 0x00 +#define RXCHK_EN (1 << 0) +#define RXCHK_SKIP_FCS (1 << 1) +#define RXCHK_BAD_CSUM_DIS (1 << 2) +#define RXCHK_BRCM_TAG_EN (1 << 3) +#define RXCHK_BRCM_TAG_MATCH_SHIFT 4 +#define RXCHK_BRCM_TAG_MATCH_MASK 0xff +#define RXCHK_PARSE_TNL (1 << 12) +#define RXCHK_VIOL_EN (1 << 13) +#define RXCHK_VIOL_DIS (1 << 14) +#define RXCHK_INCOM_PKT (1 << 15) +#define RXCHK_V6_DUPEXT_EN (1 << 16) +#define RXCHK_V6_DUPEXT_DIS (1 << 17) +#define RXCHK_ETHERTYPE_DIS (1 << 18) +#define RXCHK_L2_HDR_DIS (1 << 19) +#define RXCHK_L3_HDR_DIS (1 << 20) +#define RXCHK_MAC_RX_ERR_DIS (1 << 21) +#define RXCHK_PARSE_AUTH (1 << 22) + +#define RXCHK_BRCM_TAG0 0x04 +#define RXCHK_BRCM_TAG(i) ((i) * RXCHK_BRCM_TAG0) +#define RXCHK_BRCM_TAG0_MASK 0x24 +#define RXCHK_BRCM_TAG_MASK(i) ((i) * RXCHK_BRCM_TAG0_MASK) +#define RXCHK_BRCM_TAG_MATCH_STATUS 0x44 +#define RXCHK_ETHERTYPE 0x48 +#define RXCHK_BAD_CSUM_CNTR 0x4C +#define RXCHK_OTHER_DISC_CNTR 0x50 + +/* TXCHCK offsets and defines */ +#define SYS_PORT_TXCHK_OFFSET 0x380 +#define TXCHK_PKT_RDY_THRESH 0x00 + +/* Receive buffer offset and defines */ +#define SYS_PORT_RBUF_OFFSET 0x400 + +#define RBUF_CONTROL 0x00 +#define RBUF_RSB_EN (1 << 0) +#define RBUF_4B_ALGN (1 << 1) +#define RBUF_BRCM_TAG_STRIP (1 << 2) +#define RBUF_BAD_PKT_DISC (1 << 3) +#define RBUF_RESUME_THRESH_SHIFT 4 +#define RBUF_RESUME_THRESH_MASK 0xff +#define RBUF_OK_TO_SEND_SHIFT 12 +#define RBUF_OK_TO_SEND_MASK 0xff +#define RBUF_CRC_REPLACE (1 << 20) +#define RBUF_OK_TO_SEND_MODE (1 << 21) +#define RBUF_RSB_SWAP (1 << 22) +#define RBUF_ACPI_EN (1 << 23) + +#define RBUF_PKT_RDY_THRESH 0x04 + +#define RBUF_STATUS 0x08 +#define RBUF_WOL_MODE (1 << 0) +#define RBUF_MPD (1 << 1) +#define RBUF_ACPI (1 << 2) + +#define RBUF_OVFL_DISC_CNTR 0x0c +#define RBUF_ERR_PKT_CNTR 0x10 + +/* Transmit buffer offset and defines */ +#define SYS_PORT_TBUF_OFFSET 0x600 + +#define TBUF_CONTROL 0x00 +#define TBUF_BP_EN (1 << 0) +#define TBUF_MAX_PKT_THRESH_SHIFT 1 +#define TBUF_MAX_PKT_THRESH_MASK 0x1f +#define TBUF_FULL_THRESH_SHIFT 8 +#define TBUF_FULL_THRESH_MASK 0x1f + +/* UniMAC offset and defines */ +#define SYS_PORT_UMAC_OFFSET 0x800 + +#define UMAC_CMD 0x008 +#define CMD_TX_EN (1 << 0) +#define CMD_RX_EN (1 << 1) +#define CMD_SPEED_SHIFT 2 +#define CMD_SPEED_10 0 +#define CMD_SPEED_100 1 +#define CMD_SPEED_1000 2 +#define CMD_SPEED_2500 3 +#define CMD_SPEED_MASK 3 +#define CMD_PROMISC (1 << 4) +#define CMD_PAD_EN (1 << 5) +#define CMD_CRC_FWD (1 << 6) +#define CMD_PAUSE_FWD (1 << 7) +#define CMD_RX_PAUSE_IGNORE (1 << 8) +#define CMD_TX_ADDR_INS (1 << 9) +#define CMD_HD_EN (1 << 10) +#define CMD_SW_RESET (1 << 13) +#define CMD_LCL_LOOP_EN (1 << 15) +#define CMD_AUTO_CONFIG (1 << 22) +#define CMD_CNTL_FRM_EN (1 << 23) +#define CMD_NO_LEN_CHK (1 << 24) +#define CMD_RMT_LOOP_EN (1 << 25) +#define CMD_PRBL_EN (1 << 27) +#define CMD_TX_PAUSE_IGNORE (1 << 28) +#define CMD_TX_RX_EN (1 << 29) +#define CMD_RUNT_FILTER_DIS (1 << 30) + +#define UMAC_MAC0 0x00c +#define UMAC_MAC1 0x010 +#define UMAC_MAX_FRAME_LEN 0x014 + +#define UMAC_TX_FLUSH 0x334 + +#define UMAC_MIB_START 0x400 + +/* There is a 0xC gap between the end of RX and beginning of TX stats and then + * between the end of TX stats and the beginning of the RX RUNT + */ +#define UMAC_MIB_STAT_OFFSET 0xc + +#define UMAC_MIB_CTRL 0x580 +#define MIB_RX_CNT_RST (1 << 0) +#define MIB_RUNT_CNT_RST (1 << 1) +#define MIB_TX_CNT_RST (1 << 2) +#define UMAC_MDF_CTRL 0x650 +#define UMAC_MDF_ADDR 0x654 + +/* Receive DMA offset and defines */ +#define SYS_PORT_RDMA_OFFSET 0x2000 + +#define RDMA_CONTROL 0x1000 +#define RDMA_EN (1 << 0) +#define RDMA_RING_CFG (1 << 1) +#define RDMA_DISC_EN (1 << 2) +#define RDMA_BUF_DATA_OFFSET_SHIFT 4 +#define RDMA_BUF_DATA_OFFSET_MASK 0x3ff + +#define RDMA_STATUS 0x1004 +#define RDMA_DISABLED (1 << 0) +#define RDMA_DESC_RAM_INIT_BUSY (1 << 1) +#define RDMA_BP_STATUS (1 << 2) + +#define RDMA_SCB_BURST_SIZE 0x1008 + +#define RDMA_RING_BUF_SIZE 0x100c +#define RDMA_RING_SIZE_SHIFT 16 + +#define RDMA_WRITE_PTR_HI 0x1010 +#define RDMA_WRITE_PTR_LO 0x1014 +#define RDMA_PROD_INDEX 0x1018 +#define RDMA_PROD_INDEX_MASK 0xffff + +#define RDMA_CONS_INDEX 0x101c +#define RDMA_CONS_INDEX_MASK 0xffff + +#define RDMA_START_ADDR_HI 0x1020 +#define RDMA_START_ADDR_LO 0x1024 +#define RDMA_END_ADDR_HI 0x1028 +#define RDMA_END_ADDR_LO 0x102c + +#define RDMA_MBDONE_INTR 0x1030 +#define RDMA_INTR_THRESH_MASK 0xff +#define RDMA_TIMEOUT_SHIFT 16 +#define RDMA_TIMEOUT_MASK 0xffff + +#define RDMA_XON_XOFF_THRESH 0x1034 +#define RDMA_XON_XOFF_THRESH_MASK 0xffff +#define RDMA_XOFF_THRESH_SHIFT 16 + +#define RDMA_READ_PTR_HI 0x1038 +#define RDMA_READ_PTR_LO 0x103c + +#define RDMA_OVERRIDE 0x1040 +#define RDMA_LE_MODE (1 << 0) +#define RDMA_REG_MODE (1 << 1) + +#define RDMA_TEST 0x1044 +#define RDMA_TP_OUT_SEL (1 << 0) +#define RDMA_MEM_SEL (1 << 1) + +#define RDMA_DEBUG 0x1048 + +/* Transmit DMA offset and defines */ +#define TDMA_NUM_RINGS 32 /* rings = queues */ +#define TDMA_PORT_SIZE DESC_SIZE /* two 32-bits words */ + +#define SYS_PORT_TDMA_OFFSET 0x4000 +#define TDMA_WRITE_PORT_OFFSET 0x0000 +#define TDMA_WRITE_PORT_HI(i) (TDMA_WRITE_PORT_OFFSET + \ + (i) * TDMA_PORT_SIZE) +#define TDMA_WRITE_PORT_LO(i) (TDMA_WRITE_PORT_OFFSET + \ + sizeof(u32) + (i) * TDMA_PORT_SIZE) + +#define TDMA_READ_PORT_OFFSET (TDMA_WRITE_PORT_OFFSET + \ + (TDMA_NUM_RINGS * TDMA_PORT_SIZE)) +#define TDMA_READ_PORT_HI(i) (TDMA_READ_PORT_OFFSET + \ + (i) * TDMA_PORT_SIZE) +#define TDMA_READ_PORT_LO(i) (TDMA_READ_PORT_OFFSET + \ + sizeof(u32) + (i) * TDMA_PORT_SIZE) + +#define TDMA_READ_PORT_CMD_OFFSET (TDMA_READ_PORT_OFFSET + \ + (TDMA_NUM_RINGS * TDMA_PORT_SIZE)) +#define TDMA_READ_PORT_CMD(i) (TDMA_READ_PORT_CMD_OFFSET + \ + (i) * sizeof(u32)) + +#define TDMA_DESC_RING_00_BASE (TDMA_READ_PORT_CMD_OFFSET + \ + (TDMA_NUM_RINGS * sizeof(u32))) + +/* Register offsets and defines relatives to a specific ring number */ +#define RING_HEAD_TAIL_PTR 0x00 +#define RING_HEAD_MASK 0x7ff +#define RING_TAIL_SHIFT 11 +#define RING_TAIL_MASK 0x7ff +#define RING_FLUSH (1 << 24) +#define RING_EN (1 << 25) + +#define RING_COUNT 0x04 +#define RING_COUNT_MASK 0x7ff +#define RING_BUFF_DONE_SHIFT 11 +#define RING_BUFF_DONE_MASK 0x7ff + +#define RING_MAX_HYST 0x08 +#define RING_MAX_THRESH_MASK 0x7ff +#define RING_HYST_THRESH_SHIFT 11 +#define RING_HYST_THRESH_MASK 0x7ff + +#define RING_INTR_CONTROL 0x0c +#define RING_INTR_THRESH_MASK 0x7ff +#define RING_EMPTY_INTR_EN (1 << 15) +#define RING_TIMEOUT_SHIFT 16 +#define RING_TIMEOUT_MASK 0xffff + +#define RING_PROD_CONS_INDEX 0x10 +#define RING_PROD_INDEX_MASK 0xffff +#define RING_CONS_INDEX_SHIFT 16 +#define RING_CONS_INDEX_MASK 0xffff + +#define RING_MAPPING 0x14 +#define RING_QID_MASK 0x3 +#define RING_PORT_ID_SHIFT 3 +#define RING_PORT_ID_MASK 0x7 +#define RING_IGNORE_STATUS (1 << 6) +#define RING_FAILOVER_EN (1 << 7) +#define RING_CREDIT_SHIFT 8 +#define RING_CREDIT_MASK 0xffff + +#define RING_PCP_DEI_VID 0x18 +#define RING_VID_MASK 0x7ff +#define RING_DEI (1 << 12) +#define RING_PCP_SHIFT 13 +#define RING_PCP_MASK 0x7 +#define RING_PKT_SIZE_ADJ_SHIFT 16 +#define RING_PKT_SIZE_ADJ_MASK 0xf + +#define TDMA_DESC_RING_SIZE 28 + +/* Defininition for a given TX ring base address */ +#define TDMA_DESC_RING_BASE(i) (TDMA_DESC_RING_00_BASE + \ + ((i) * TDMA_DESC_RING_SIZE)) + +/* Ring indexed register addreses */ +#define TDMA_DESC_RING_HEAD_TAIL_PTR(i) (TDMA_DESC_RING_BASE(i) + \ + RING_HEAD_TAIL_PTR) +#define TDMA_DESC_RING_COUNT(i) (TDMA_DESC_RING_BASE(i) + \ + RING_COUNT) +#define TDMA_DESC_RING_MAX_HYST(i) (TDMA_DESC_RING_BASE(i) + \ + RING_MAX_HYST) +#define TDMA_DESC_RING_INTR_CONTROL(i) (TDMA_DESC_RING_BASE(i) + \ + RING_INTR_CONTROL) +#define TDMA_DESC_RING_PROD_CONS_INDEX(i) \ + (TDMA_DESC_RING_BASE(i) + \ + RING_PROD_CONS_INDEX) +#define TDMA_DESC_RING_MAPPING(i) (TDMA_DESC_RING_BASE(i) + \ + RING_MAPPING) +#define TDMA_DESC_RING_PCP_DEI_VID(i) (TDMA_DESC_RING_BASE(i) + \ + RING_PCP_DEI_VID) + +#define TDMA_CONTROL 0x600 +#define TDMA_EN (1 << 0) +#define TSB_EN (1 << 1) +#define TSB_SWAP (1 << 2) +#define ACB_ALGO (1 << 3) +#define BUF_DATA_OFFSET_SHIFT 4 +#define BUF_DATA_OFFSET_MASK 0x3ff +#define VLAN_EN (1 << 14) +#define SW_BRCM_TAG (1 << 15) +#define WNC_KPT_SIZE_UPDATE (1 << 16) +#define SYNC_PKT_SIZE (1 << 17) +#define ACH_TXDONE_DELAY_SHIFT 18 +#define ACH_TXDONE_DELAY_MASK 0xff + +#define TDMA_STATUS 0x604 +#define TDMA_DISABLED (1 << 0) +#define TDMA_LL_RAM_INIT_BUSY (1 << 1) + +#define TDMA_SCB_BURST_SIZE 0x608 +#define TDMA_OVER_MAX_THRESH_STATUS 0x60c +#define TDMA_OVER_HYST_THRESH_STATUS 0x610 +#define TDMA_TPID 0x614 + +#define TDMA_FREE_LIST_HEAD_TAIL_PTR 0x618 +#define TDMA_FREE_HEAD_MASK 0x7ff +#define TDMA_FREE_TAIL_SHIFT 11 +#define TDMA_FREE_TAIL_MASK 0x7ff + +#define TDMA_FREE_LIST_COUNT 0x61c +#define TDMA_FREE_LIST_COUNT_MASK 0x7ff + +#define TDMA_TIER2_ARB_CTRL 0x620 +#define TDMA_ARB_MODE_RR 0 +#define TDMA_ARB_MODE_WEIGHT_RR 0x1 +#define TDMA_ARB_MODE_STRICT 0x2 +#define TDMA_ARB_MODE_DEFICIT_RR 0x3 +#define TDMA_CREDIT_SHIFT 4 +#define TDMA_CREDIT_MASK 0xffff + +#define TDMA_TIER1_ARB_0_CTRL 0x624 +#define TDMA_ARB_EN (1 << 0) + +#define TDMA_TIER1_ARB_0_QUEUE_EN 0x628 +#define TDMA_TIER1_ARB_1_CTRL 0x62c +#define TDMA_TIER1_ARB_1_QUEUE_EN 0x630 +#define TDMA_TIER1_ARB_2_CTRL 0x634 +#define TDMA_TIER1_ARB_2_QUEUE_EN 0x638 +#define TDMA_TIER1_ARB_3_CTRL 0x63c +#define TDMA_TIER1_ARB_3_QUEUE_EN 0x640 + +#define TDMA_SCB_ENDIAN_OVERRIDE 0x644 +#define TDMA_LE_MODE (1 << 0) +#define TDMA_REG_MODE (1 << 1) + +#define TDMA_TEST 0x648 +#define TDMA_TP_OUT_SEL (1 << 0) +#define TDMA_MEM_TM (1 << 1) + +#define TDMA_DEBUG 0x64c + +/* Transmit/Receive descriptor */ +struct dma_desc { + u32 addr_status_len; + u32 addr_lo; +}; + +/* Number of Receive hardware descriptor words */ +#define NUM_HW_RX_DESC_WORDS 1024 +/* Real number of usable descriptors */ +#define NUM_RX_DESC (NUM_HW_RX_DESC_WORDS / WORDS_PER_DESC) + +/* Internal linked-list RAM has up to 1536 entries */ +#define NUM_TX_DESC 1536 + +#define WORDS_PER_DESC (sizeof(struct dma_desc) / sizeof(u32)) + +/* Rx/Tx common counter group.*/ +struct bcm_sysport_pkt_counters { + u32 cnt_64; /* RO Received/Transmited 64 bytes packet */ + u32 cnt_127; /* RO Rx/Tx 127 bytes packet */ + u32 cnt_255; /* RO Rx/Tx 65-255 bytes packet */ + u32 cnt_511; /* RO Rx/Tx 256-511 bytes packet */ + u32 cnt_1023; /* RO Rx/Tx 512-1023 bytes packet */ + u32 cnt_1518; /* RO Rx/Tx 1024-1518 bytes packet */ + u32 cnt_mgv; /* RO Rx/Tx 1519-1522 good VLAN packet */ + u32 cnt_2047; /* RO Rx/Tx 1522-2047 bytes packet*/ + u32 cnt_4095; /* RO Rx/Tx 2048-4095 bytes packet*/ + u32 cnt_9216; /* RO Rx/Tx 4096-9216 bytes packet*/ +}; + +/* RSV, Receive Status Vector */ +struct bcm_sysport_rx_counters { + struct bcm_sysport_pkt_counters pkt_cnt; + u32 pkt; /* RO (0x428) Received pkt count*/ + u32 bytes; /* RO Received byte count */ + u32 mca; /* RO # of Received multicast pkt */ + u32 bca; /* RO # of Receive broadcast pkt */ + u32 fcs; /* RO # of Received FCS error */ + u32 cf; /* RO # of Received control frame pkt*/ + u32 pf; /* RO # of Received pause frame pkt */ + u32 uo; /* RO # of unknown op code pkt */ + u32 aln; /* RO # of alignment error count */ + u32 flr; /* RO # of frame length out of range count */ + u32 cde; /* RO # of code error pkt */ + u32 fcr; /* RO # of carrier sense error pkt */ + u32 ovr; /* RO # of oversize pkt*/ + u32 jbr; /* RO # of jabber count */ + u32 mtue; /* RO # of MTU error pkt*/ + u32 pok; /* RO # of Received good pkt */ + u32 uc; /* RO # of unicast pkt */ + u32 ppp; /* RO # of PPP pkt */ + u32 rcrc; /* RO (0x470),# of CRC match pkt */ +}; + +/* TSV, Transmit Status Vector */ +struct bcm_sysport_tx_counters { + struct bcm_sysport_pkt_counters pkt_cnt; + u32 pkts; /* RO (0x4a8) Transmited pkt */ + u32 mca; /* RO # of xmited multicast pkt */ + u32 bca; /* RO # of xmited broadcast pkt */ + u32 pf; /* RO # of xmited pause frame count */ + u32 cf; /* RO # of xmited control frame count */ + u32 fcs; /* RO # of xmited FCS error count */ + u32 ovr; /* RO # of xmited oversize pkt */ + u32 drf; /* RO # of xmited deferral pkt */ + u32 edf; /* RO # of xmited Excessive deferral pkt*/ + u32 scl; /* RO # of xmited single collision pkt */ + u32 mcl; /* RO # of xmited multiple collision pkt*/ + u32 lcl; /* RO # of xmited late collision pkt */ + u32 ecl; /* RO # of xmited excessive collision pkt*/ + u32 frg; /* RO # of xmited fragments pkt*/ + u32 ncl; /* RO # of xmited total collision count */ + u32 jbr; /* RO # of xmited jabber count*/ + u32 bytes; /* RO # of xmited byte count */ + u32 pok; /* RO # of xmited good pkt */ + u32 uc; /* RO (0x0x4f0)# of xmited unitcast pkt */ +}; + +struct bcm_sysport_mib { + struct bcm_sysport_rx_counters rx; + struct bcm_sysport_tx_counters tx; + u32 rx_runt_cnt; + u32 rx_runt_fcs; + u32 rx_runt_fcs_align; + u32 rx_runt_bytes; + u32 rxchk_bad_csum; + u32 rxchk_other_pkt_disc; + u32 rbuf_ovflow_cnt; + u32 rbuf_err_cnt; +}; + +/* HW maintains a large list of counters */ +enum bcm_sysport_stat_type { + BCM_SYSPORT_STAT_NETDEV = -1, + BCM_SYSPORT_STAT_MIB_RX, + BCM_SYSPORT_STAT_MIB_TX, + BCM_SYSPORT_STAT_RUNT, + BCM_SYSPORT_STAT_RXCHK, + BCM_SYSPORT_STAT_RBUF, +}; + +/* Macros to help define ethtool statistics */ +#define STAT_NETDEV(m) { \ + .stat_string = __stringify(m), \ + .stat_sizeof = sizeof(((struct net_device_stats *)0)->m), \ + .stat_offset = offsetof(struct net_device_stats, m), \ + .type = BCM_SYSPORT_STAT_NETDEV, \ +} + +#define STAT_MIB(str, m, _type) { \ + .stat_string = str, \ + .stat_sizeof = sizeof(((struct bcm_sysport_priv *)0)->m), \ + .stat_offset = offsetof(struct bcm_sysport_priv, m), \ + .type = _type, \ +} + +#define STAT_MIB_RX(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_MIB_RX) +#define STAT_MIB_TX(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_MIB_TX) +#define STAT_RUNT(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_RUNT) + +#define STAT_RXCHK(str, m, ofs) { \ + .stat_string = str, \ + .stat_sizeof = sizeof(((struct bcm_sysport_priv *)0)->m), \ + .stat_offset = offsetof(struct bcm_sysport_priv, m), \ + .type = BCM_SYSPORT_STAT_RXCHK, \ + .reg_offset = ofs, \ +} + +#define STAT_RBUF(str, m, ofs) { \ + .stat_string = str, \ + .stat_sizeof = sizeof(((struct bcm_sysport_priv *)0)->m), \ + .stat_offset = offsetof(struct bcm_sysport_priv, m), \ + .type = BCM_SYSPORT_STAT_RBUF, \ + .reg_offset = ofs, \ +} + +struct bcm_sysport_stats { + char stat_string[ETH_GSTRING_LEN]; + int stat_sizeof; + int stat_offset; + enum bcm_sysport_stat_type type; + /* reg offset from UMAC base for misc counters */ + u16 reg_offset; +}; + +/* Software house keeping helper structure */ +struct bcm_sysport_cb { + struct sk_buff *skb; /* SKB for RX packets */ + void __iomem *bd_addr; /* Buffer descriptor PHYS addr */ + + DEFINE_DMA_UNMAP_ADDR(dma_addr); + DEFINE_DMA_UNMAP_LEN(dma_len); +}; + +/* Software view of the TX ring */ +struct bcm_sysport_tx_ring { + spinlock_t lock; /* Ring lock for tx reclaim/xmit */ + struct napi_struct napi; /* NAPI per tx queue */ + dma_addr_t desc_dma; /* DMA cookie */ + unsigned int index; /* Ring index */ + unsigned int size; /* Ring current size */ + unsigned int alloc_size; /* Ring one-time allocated size */ + unsigned int desc_count; /* Number of descriptors */ + unsigned int curr_desc; /* Current descriptor */ + unsigned int c_index; /* Last consumer index */ + unsigned int p_index; /* Current producer index */ + struct bcm_sysport_cb *cbs; /* Transmit control blocks */ + struct dma_desc *desc_cpu; /* CPU view of the descriptor */ + struct bcm_sysport_priv *priv; /* private context backpointer */ +}; + +/* Driver private structure */ +struct bcm_sysport_priv { + void __iomem *base; + u32 irq0_stat; + u32 irq0_mask; + u32 irq1_stat; + u32 irq1_mask; + struct napi_struct napi ____cacheline_aligned; + struct net_device *netdev; + struct platform_device *pdev; + int irq0; + int irq1; + + /* Transmit rings */ + struct bcm_sysport_tx_ring tx_rings[TDMA_NUM_RINGS]; + + /* Receive queue */ + void __iomem *rx_bds; + void __iomem *rx_bd_assign_ptr; + unsigned int rx_bd_assign_index; + struct bcm_sysport_cb *rx_cbs; + unsigned int num_rx_bds; + unsigned int rx_read_ptr; + unsigned int rx_c_index; + + /* PHY device */ + struct phy_device *phydev; + phy_interface_t phy_interface; + int old_pause; + int old_link; + int old_duplex; + + /* Misc fields */ + unsigned int rx_csum_en:1; + unsigned int tsb_en:1; + unsigned int crc_fwd:1; + u16 rev; + + /* MIB related fields */ + struct bcm_sysport_mib mib; + + /* Ethtool */ + u32 msg_enable; +}; +#endif /* __BCM_SYSPORT_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 9261d5313b5be2..dd57c7c5a3da8e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2781,7 +2781,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) case LOAD_OPEN: netif_tx_start_all_queues(bp->dev); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); break; case LOAD_DIAG: @@ -4939,9 +4939,9 @@ void bnx2x_update_coalesce_sb_index(struct bnx2x *bp, u8 fw_sb_id, void bnx2x_schedule_sp_rtnl(struct bnx2x *bp, enum sp_rtnl_flag flag, u32 verbose) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); set_bit(flag, &bp->sp_rtnl_state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); DP((BNX2X_MSG_SP | verbose), "Scheduling sp_rtnl task [Flag: %d]\n", flag); schedule_delayed_work(&bp->sp_rtnl_task, 0); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index b260913db23609..55a887fd17b448 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -1858,10 +1858,10 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe) return; #endif - smp_mb__before_atomic_inc(); + smp_mb__before_atomic(); atomic_inc(&bp->cq_spq_left); /* push the change in bp->spq_left and towards the memory */ - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); DP(BNX2X_MSG_SP, "bp->cq_spq_left %x\n", atomic_read(&bp->cq_spq_left)); @@ -1876,11 +1876,11 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe) * sp_state is cleared, and this order prevents * races */ - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); set_bit(BNX2X_AFEX_PENDING_VIFSET_MCP_ACK, &bp->sp_state); wmb(); clear_bit(BNX2X_AFEX_FCOE_Q_UPDATE_PENDING, &bp->sp_state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); /* schedule the sp task as mcp ack is required */ bnx2x_schedule_sp_task(bp); @@ -5272,9 +5272,9 @@ static void bnx2x_after_function_update(struct bnx2x *bp) __clear_bit(RAMROD_COMP_WAIT, &queue_params.ramrod_flags); /* mark latest Q bit */ - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); set_bit(BNX2X_AFEX_FCOE_Q_UPDATE_PENDING, &bp->sp_state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); /* send Q update ramrod for FCoE Q */ rc = bnx2x_queue_state_change(bp, &queue_params); @@ -5500,7 +5500,7 @@ static void bnx2x_eq_int(struct bnx2x *bp) spqe_cnt++; } /* for */ - smp_mb__before_atomic_inc(); + smp_mb__before_atomic(); atomic_add(spqe_cnt, &bp->eq_spq_left); bp->eq_cons = sw_cons; @@ -13871,9 +13871,9 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl) case DRV_CTL_RET_L2_SPQ_CREDIT_CMD: { int count = ctl->data.credit.credit_count; - smp_mb__before_atomic_inc(); + smp_mb__before_atomic(); atomic_add(count, &bp->cq_spq_left); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); break; } case DRV_CTL_ULP_REGISTER_CMD: { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 31297266b743e2..d725317c427738 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -258,16 +258,16 @@ static bool bnx2x_raw_check_pending(struct bnx2x_raw_obj *o) static void bnx2x_raw_clear_pending(struct bnx2x_raw_obj *o) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(o->state, o->pstate); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } static void bnx2x_raw_set_pending(struct bnx2x_raw_obj *o) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); set_bit(o->state, o->pstate); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } /** @@ -2131,7 +2131,7 @@ static int bnx2x_set_rx_mode_e1x(struct bnx2x *bp, /* The operation is completed */ clear_bit(p->state, p->pstate); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return 0; } @@ -3576,16 +3576,16 @@ int bnx2x_config_mcast(struct bnx2x *bp, static void bnx2x_mcast_clear_sched(struct bnx2x_mcast_obj *o) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(o->sched_state, o->raw.pstate); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } static void bnx2x_mcast_set_sched(struct bnx2x_mcast_obj *o) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); set_bit(o->sched_state, o->raw.pstate); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } static bool bnx2x_mcast_check_sched(struct bnx2x_mcast_obj *o) @@ -4200,7 +4200,7 @@ int bnx2x_queue_state_change(struct bnx2x *bp, if (rc) { o->next_state = BNX2X_Q_STATE_MAX; clear_bit(pending_bit, pending); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return rc; } @@ -4288,7 +4288,7 @@ static int bnx2x_queue_comp_cmd(struct bnx2x *bp, wmb(); clear_bit(cmd, &o->pending); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return 0; } @@ -5279,7 +5279,7 @@ static inline int bnx2x_func_state_change_comp(struct bnx2x *bp, wmb(); clear_bit(cmd, &o->pending); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return 0; } @@ -5926,7 +5926,7 @@ int bnx2x_func_state_change(struct bnx2x *bp, if (rc) { o->next_state = BNX2X_F_STATE_MAX; clear_bit(cmd, pending); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return rc; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index 81cc2d9831c219..4f0da5312613d8 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -1650,9 +1650,9 @@ static void bnx2x_vf_handle_filters_eqe(struct bnx2x *bp, struct bnx2x_virtf *vf) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(BNX2X_FILTER_RX_MODE_PENDING, &vf->filter_state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } static void bnx2x_vf_handle_rss_update_eqe(struct bnx2x *bp, @@ -2990,9 +2990,9 @@ void bnx2x_iov_task(struct work_struct *work) void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); set_bit(flag, &bp->iov_task_state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); DP(BNX2X_MSG_IOV, "Scheduling iov task [Flag: %d]\n", flag); queue_delayed_work(bnx2x_iov_wq, &bp->iov_task, 0); } diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c index 09f3fefcbf9ce4..4dd48d2fa80432 100644 --- a/drivers/net/ethernet/broadcom/cnic.c +++ b/drivers/net/ethernet/broadcom/cnic.c @@ -436,7 +436,7 @@ static int cnic_offld_prep(struct cnic_sock *csk) static int cnic_close_prep(struct cnic_sock *csk) { clear_bit(SK_F_CONNECT_START, &csk->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) { while (test_and_set_bit(SK_F_OFFLD_SCHED, &csk->flags)) @@ -450,7 +450,7 @@ static int cnic_close_prep(struct cnic_sock *csk) static int cnic_abort_prep(struct cnic_sock *csk) { clear_bit(SK_F_CONNECT_START, &csk->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); while (test_and_set_bit(SK_F_OFFLD_SCHED, &csk->flags)) msleep(1); @@ -3646,7 +3646,7 @@ static int cnic_cm_destroy(struct cnic_sock *csk) csk_hold(csk); clear_bit(SK_F_INUSE, &csk->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); while (atomic_read(&csk->ref_count) != 1) msleep(1); cnic_cm_cleanup(csk); @@ -4026,7 +4026,7 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe) L4_KCQE_COMPLETION_STATUS_PARITY_ERROR) set_bit(SK_F_HW_ERR, &csk->flags); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(SK_F_OFFLD_SCHED, &csk->flags); cnic_cm_upcall(cp, csk, opcode); break; diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index 675550fe8ee90d..3a77f9ead00499 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -249,7 +249,7 @@ bnad_tx_complete(struct bnad *bnad, struct bna_tcb *tcb) if (likely(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) bna_ib_ack(tcb->i_dbell, sent); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags); return sent; @@ -1126,7 +1126,7 @@ bnad_tx_cleanup(struct delayed_work *work) bnad_txq_cleanup(bnad, tcb); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags); } @@ -2992,7 +2992,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) sent = bnad_txcmpl_process(bnad, tcb); if (likely(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) bna_ib_ack(tcb->i_dbell, sent); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags); } else { netif_stop_queue(netdev); diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c index 0fe7ff750d77e1..05613a85ce617a 100644 --- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c +++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c @@ -281,7 +281,7 @@ static int cxgb_close(struct net_device *dev) if (adapter->params.stats_update_period && !(adapter->open_device_map & PORT_MASK)) { /* Stop statistics accumulation. */ - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); spin_lock(&adapter->work_lock); /* sync with update task */ spin_unlock(&adapter->work_lock); cancel_mac_stats_update(adapter); diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c index 8b069f96e920e4..3dfcf600fcc68b 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c @@ -1379,7 +1379,7 @@ static inline int check_desc_avail(struct adapter *adap, struct sge_txq *q, struct sge_qset *qs = txq_to_qset(q, qid); set_bit(qid, &qs->txq_stopped); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); if (should_restart_tx(q) && test_and_clear_bit(qid, &qs->txq_stopped)) @@ -1492,7 +1492,7 @@ static void restart_ctrlq(unsigned long data) if (!skb_queue_empty(&q->sendq)) { set_bit(TXQ_CTRL, &qs->txq_stopped); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); if (should_restart_tx(q) && test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) @@ -1697,7 +1697,7 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); if (unlikely(q->size - q->in_use < ndesc)) { set_bit(TXQ_OFLD, &qs->txq_stopped); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); if (should_restart_tx(q) && test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index ca95cf2954eb33..e249528c8e60bb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -2031,7 +2031,7 @@ static void sge_rx_timer_cb(unsigned long data) struct sge_fl *fl = s->egr_map[id]; clear_bit(id, s->starving_fl); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); if (fl_starving(fl)) { rxq = container_of(fl, struct sge_eth_rxq, fl); diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index 9cfa4b4bb089d3..9d88c1d50b49ba 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -1951,7 +1951,7 @@ static void sge_rx_timer_cb(unsigned long data) struct sge_fl *fl = s->egr_map[id]; clear_bit(id, s->starving_fl); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); /* * Since we are accessing fl without a lock there's a diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 97db5a7179df1c..2f67c7c8d41337 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -120,6 +120,9 @@ static inline char *nic_name(struct pci_dev *pdev) #define MAX_VFS 30 /* Max VFs supported by BE3 FW */ #define FW_VER_LEN 32 +#define RSS_INDIR_TABLE_LEN 128 +#define RSS_HASH_KEY_LEN 40 + struct be_dma_mem { void *va; dma_addr_t dma; @@ -409,6 +412,13 @@ struct be_resources { u32 if_cap_flags; }; +struct rss_info { + u64 rss_flags; + u8 rsstable[RSS_INDIR_TABLE_LEN]; + u8 rss_queue[RSS_INDIR_TABLE_LEN]; + u8 rss_hkey[RSS_HASH_KEY_LEN]; +}; + struct be_adapter { struct pci_dev *pdev; struct net_device *netdev; @@ -507,7 +517,7 @@ struct be_adapter { u32 msg_enable; int be_get_temp_freq; u8 pf_number; - u64 rss_flags; + struct rss_info rss_info; }; #define be_physfn(adapter) (!adapter->virtfn) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index d1ec15af0d2482..07e78e89a348ec 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2020,13 +2020,10 @@ int be_cmd_reset_function(struct be_adapter *adapter) } int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, - u32 rss_hash_opts, u16 table_size) + u32 rss_hash_opts, u16 table_size, u8 *rss_hkey) { struct be_mcc_wrb *wrb; struct be_cmd_req_rss_config *req; - u32 myhash[10] = {0x15d43fa5, 0x2534685a, 0x5f87693a, 0x5668494e, - 0x33cf6a53, 0x383334c6, 0x76ac4257, 0x59b242b2, - 0x3ea83c02, 0x4a110304}; int status; if (!(be_if_cap_flags(adapter) & BE_IF_FLAGS_RSS)) @@ -2049,7 +2046,7 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, req->hdr.version = 1; memcpy(req->cpu_table, rsstable, table_size); - memcpy(req->hash, myhash, sizeof(myhash)); + memcpy(req->hash, rss_hkey, RSS_HASH_KEY_LEN); be_dws_cpu_to_le(req->hash, sizeof(req->hash)); status = be_mbox_notify_wait(adapter); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index b60e4d53c1c9a9..4ea79b9c67e934 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -2068,7 +2068,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *function_mode, u32 *function_caps, u16 *asic_rev); int be_cmd_reset_function(struct be_adapter *adapter); int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, - u32 rss_hash_opts, u16 table_size); + u32 rss_hash_opts, u16 table_size, u8 *rss_hkey); int be_process_mcc(struct be_adapter *adapter); int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, u8 beacon, u8 status, u8 state); diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 15ba96cba65df1..6f3494e41511f6 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -933,27 +933,27 @@ static u64 be_get_rss_hash_opts(struct be_adapter *adapter, u64 flow_type) switch (flow_type) { case TCP_V4_FLOW: - if (adapter->rss_flags & RSS_ENABLE_IPV4) + if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV4) data |= RXH_IP_DST | RXH_IP_SRC; - if (adapter->rss_flags & RSS_ENABLE_TCP_IPV4) + if (adapter->rss_info.rss_flags & RSS_ENABLE_TCP_IPV4) data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; break; case UDP_V4_FLOW: - if (adapter->rss_flags & RSS_ENABLE_IPV4) + if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV4) data |= RXH_IP_DST | RXH_IP_SRC; - if (adapter->rss_flags & RSS_ENABLE_UDP_IPV4) + if (adapter->rss_info.rss_flags & RSS_ENABLE_UDP_IPV4) data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; break; case TCP_V6_FLOW: - if (adapter->rss_flags & RSS_ENABLE_IPV6) + if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV6) data |= RXH_IP_DST | RXH_IP_SRC; - if (adapter->rss_flags & RSS_ENABLE_TCP_IPV6) + if (adapter->rss_info.rss_flags & RSS_ENABLE_TCP_IPV6) data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; break; case UDP_V6_FLOW: - if (adapter->rss_flags & RSS_ENABLE_IPV6) + if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV6) data |= RXH_IP_DST | RXH_IP_SRC; - if (adapter->rss_flags & RSS_ENABLE_UDP_IPV6) + if (adapter->rss_info.rss_flags & RSS_ENABLE_UDP_IPV6) data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; break; } @@ -992,7 +992,7 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter, struct be_rx_obj *rxo; int status = 0, i, j; u8 rsstable[128]; - u32 rss_flags = adapter->rss_flags; + u32 rss_flags = adapter->rss_info.rss_flags; if (cmd->data != L3_RSS_FLAGS && cmd->data != (L3_RSS_FLAGS | L4_RSS_FLAGS)) @@ -1039,7 +1039,7 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter, return -EINVAL; } - if (rss_flags == adapter->rss_flags) + if (rss_flags == adapter->rss_info.rss_flags) return status; if (be_multi_rxq(adapter)) { @@ -1051,9 +1051,11 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter, } } } - status = be_cmd_rss_config(adapter, rsstable, rss_flags, 128); + + status = be_cmd_rss_config(adapter, adapter->rss_info.rsstable, + rss_flags, 128, adapter->rss_info.rss_hkey); if (!status) - adapter->rss_flags = rss_flags; + adapter->rss_info.rss_flags = rss_flags; return status; } @@ -1103,6 +1105,68 @@ static int be_set_channels(struct net_device *netdev, return be_update_queues(adapter); } +static u32 be_get_rxfh_indir_size(struct net_device *netdev) +{ + return RSS_INDIR_TABLE_LEN; +} + +static u32 be_get_rxfh_key_size(struct net_device *netdev) +{ + return RSS_HASH_KEY_LEN; +} + +static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey) +{ + struct be_adapter *adapter = netdev_priv(netdev); + int i; + struct rss_info *rss = &adapter->rss_info; + + if (indir) { + for (i = 0; i < RSS_INDIR_TABLE_LEN; i++) + indir[i] = rss->rss_queue[i]; + } + + if (hkey) + memcpy(hkey, rss->rss_hkey, RSS_HASH_KEY_LEN); + + return 0; +} + +static int be_set_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey) +{ + int rc = 0, i, j; + struct be_adapter *adapter = netdev_priv(netdev); + u8 rsstable[RSS_INDIR_TABLE_LEN]; + + if (indir) { + struct be_rx_obj *rxo; + for (i = 0; i < RSS_INDIR_TABLE_LEN; i++) { + j = indir[i]; + rxo = &adapter->rx_obj[j]; + rsstable[i] = rxo->rss_id; + adapter->rss_info.rss_queue[i] = j; + } + } else { + memcpy(rsstable, adapter->rss_info.rsstable, + RSS_INDIR_TABLE_LEN); + } + + if (!hkey) + hkey = adapter->rss_info.rss_hkey; + + rc = be_cmd_rss_config(adapter, rsstable, + adapter->rss_info.rss_flags, + RSS_INDIR_TABLE_LEN, hkey); + if (rc) { + adapter->rss_info.rss_flags = RSS_ENABLE_NONE; + return -EIO; + } + memcpy(adapter->rss_info.rss_hkey, hkey, RSS_HASH_KEY_LEN); + memcpy(adapter->rss_info.rsstable, rsstable, + RSS_INDIR_TABLE_LEN); + return 0; +} + const struct ethtool_ops be_ethtool_ops = { .get_settings = be_get_settings, .get_drvinfo = be_get_drvinfo, @@ -1129,6 +1193,10 @@ const struct ethtool_ops be_ethtool_ops = { .self_test = be_self_test, .get_rxnfc = be_get_rxnfc, .set_rxnfc = be_set_rxnfc, + .get_rxfh_indir_size = be_get_rxfh_indir_size, + .get_rxfh_key_size = be_get_rxfh_key_size, + .get_rxfh = be_get_rxfh, + .set_rxfh = be_set_rxfh, .get_channels = be_get_channels, .set_channels = be_set_channels }; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index a18645407d2152..a3c6a27d13fa59 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2774,7 +2774,8 @@ static int be_rx_qs_create(struct be_adapter *adapter) { struct be_rx_obj *rxo; int rc, i, j; - u8 rsstable[128]; + u8 rss_hkey[RSS_HASH_KEY_LEN]; + struct rss_info *rss = &adapter->rss_info; for_all_rx_queues(adapter, rxo, i) { rc = be_queue_alloc(adapter, &rxo->q, RX_Q_LEN, @@ -2799,31 +2800,37 @@ static int be_rx_qs_create(struct be_adapter *adapter) } if (be_multi_rxq(adapter)) { - for (j = 0; j < 128; j += adapter->num_rx_qs - 1) { + for (j = 0; j < RSS_INDIR_TABLE_LEN; + j += adapter->num_rx_qs - 1) { for_all_rss_queues(adapter, rxo, i) { - if ((j + i) >= 128) + if ((j + i) >= RSS_INDIR_TABLE_LEN) break; - rsstable[j + i] = rxo->rss_id; + rss->rsstable[j + i] = rxo->rss_id; + rss->rss_queue[j + i] = i; } } - adapter->rss_flags = RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4 | - RSS_ENABLE_TCP_IPV6 | RSS_ENABLE_IPV6; + rss->rss_flags = RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4 | + RSS_ENABLE_TCP_IPV6 | RSS_ENABLE_IPV6; if (!BEx_chip(adapter)) - adapter->rss_flags |= RSS_ENABLE_UDP_IPV4 | - RSS_ENABLE_UDP_IPV6; + rss->rss_flags |= RSS_ENABLE_UDP_IPV4 | + RSS_ENABLE_UDP_IPV6; } else { /* Disable RSS, if only default RX Q is created */ - adapter->rss_flags = RSS_ENABLE_NONE; + rss->rss_flags = RSS_ENABLE_NONE; } - rc = be_cmd_rss_config(adapter, rsstable, adapter->rss_flags, - 128); + get_random_bytes(rss_hkey, RSS_HASH_KEY_LEN); + rc = be_cmd_rss_config(adapter, rss->rsstable, + rss->rss_flags, + 128, rss_hkey); if (rc) { - adapter->rss_flags = RSS_ENABLE_NONE; + rss->rss_flags = RSS_ENABLE_NONE; return rc; } + memcpy(rss->rss_hkey, rss_hkey, RSS_HASH_KEY_LEN); + /* First time posting */ for_all_rx_queues(adapter, rxo, i) be_post_rx_frags(rxo, GFP_KERNEL); diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 8b70ca7e342b6f..f3658bdb64cc42 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -769,11 +769,6 @@ static int ethoc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return phy_mii_ioctl(phy, ifr, cmd); } -static int ethoc_config(struct net_device *dev, struct ifmap *map) -{ - return -ENOSYS; -} - static void ethoc_do_set_mac_address(struct net_device *dev) { struct ethoc *priv = netdev_priv(dev); @@ -995,7 +990,6 @@ static const struct net_device_ops ethoc_netdev_ops = { .ndo_open = ethoc_open, .ndo_stop = ethoc_stop, .ndo_do_ioctl = ethoc_ioctl, - .ndo_set_config = ethoc_config, .ndo_set_mac_address = ethoc_set_mac_address, .ndo_set_rx_mode = ethoc_set_multicast_list, .ndo_change_mtu = ethoc_change_mtu, diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index e2d42475b006aa..ee6ddbd4f25278 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1798,9 +1798,9 @@ void stop_gfar(struct net_device *dev) netif_tx_stop_all_queues(dev); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); set_bit(GFAR_DOWN, &priv->state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); disable_napi(priv); @@ -2043,9 +2043,9 @@ int startup_gfar(struct net_device *ndev) gfar_init_tx_rx_base(priv); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(GFAR_DOWN, &priv->state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); /* Start Rx/Tx DMA and enable the interrupts */ gfar_start(priv); diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 1471c5464a89e7..e27e60910949c9 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -265,10 +265,10 @@ struct e1000_adapter { u32 tx_hwtstamp_timeouts; /* Rx */ - bool (*clean_rx) (struct e1000_ring *ring, int *work_done, - int work_to_do) ____cacheline_aligned_in_smp; - void (*alloc_rx_buf) (struct e1000_ring *ring, int cleaned_count, - gfp_t gfp); + bool (*clean_rx)(struct e1000_ring *ring, int *work_done, + int work_to_do) ____cacheline_aligned_in_smp; + void (*alloc_rx_buf)(struct e1000_ring *ring, int cleaned_count, + gfp_t gfp); struct e1000_ring *rx_ring; u32 rx_int_delay; diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index cad250bc1b99fc..4e5ad7ebe1f24b 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -169,6 +169,7 @@ static int e1000_get_settings(struct net_device *netdev, } } else if (!pm_runtime_suspended(netdev->dev.parent)) { u32 status = er32(STATUS); + if (status & E1000_STATUS_LU) { if (status & E1000_STATUS_SPEED_1000) speed = SPEED_1000; @@ -783,25 +784,26 @@ static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data, reg + (offset << 2), val, (test[pat] & write & mask)); *data = reg; - return 1; + return true; } } - return 0; + return false; } static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data, int reg, u32 mask, u32 write) { u32 val; + __ew32(&adapter->hw, reg, write & mask); val = __er32(&adapter->hw, reg); if ((write & mask) != (val & mask)) { e_err("set/check test failed (reg 0x%05X): got 0x%08X expected 0x%08X\n", reg, (val & mask), (write & mask)); *data = reg; - return 1; + return true; } - return 0; + return false; } #define REG_PATTERN_TEST_ARRAY(reg, offset, mask, write) \ @@ -1717,6 +1719,7 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data) *data = 0; if (hw->phy.media_type == e1000_media_type_internal_serdes) { int i = 0; + hw->mac.serdes_has_link = false; /* On some blade server designs, link establishment diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index f0bbd4246d71d8..5f55395616612d 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1334,6 +1334,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) if (((hw->mac.type == e1000_pch2lan) || (hw->mac.type == e1000_pch_lpt)) && link) { u32 reg; + reg = er32(STATUS); if (!(reg & (E1000_STATUS_FD | E1000_STATUS_SPEED_MASK))) { u16 emi_addr; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 3e69386add04ab..e4207efd13f865 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -599,6 +599,7 @@ static void e1000e_update_rdt_wa(struct e1000_ring *rx_ring, unsigned int i) if (unlikely(!ret_val && (i != readl(rx_ring->tail)))) { u32 rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); e_err("ME firmware caused invalid RDT - resetting\n"); schedule_work(&adapter->reset_task); @@ -615,6 +616,7 @@ static void e1000e_update_tdt_wa(struct e1000_ring *tx_ring, unsigned int i) if (unlikely(!ret_val && (i != readl(tx_ring->tail)))) { u32 tctl = er32(TCTL); + ew32(TCTL, tctl & ~E1000_TCTL_EN); e_err("ME firmware caused invalid TDT - resetting\n"); schedule_work(&adapter->reset_task); @@ -1198,6 +1200,7 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring) while ((eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) && (count < tx_ring->count)) { bool cleaned = false; + rmb(); /* read buffer_info after eop_desc */ for (; !cleaned; count++) { tx_desc = E1000_TX_DESC(*tx_ring, i); @@ -1753,6 +1756,7 @@ static irqreturn_t e1000_intr_msi(int __always_unused irq, void *data) adapter->flags & FLAG_RX_NEEDS_RESTART) { /* disable receives */ u32 rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); adapter->flags |= FLAG_RESTART_NOW; } @@ -1960,6 +1964,7 @@ static void e1000_configure_msix(struct e1000_adapter *adapter) /* Workaround issue with spurious interrupts on 82574 in MSI-X mode */ if (hw->mac.type == e1000_82574) { u32 rfctl = er32(RFCTL); + rfctl |= E1000_RFCTL_ACK_DIS; ew32(RFCTL, rfctl); } @@ -2204,6 +2209,7 @@ static void e1000_irq_disable(struct e1000_adapter *adapter) if (adapter->msix_entries) { int i; + for (i = 0; i < adapter->num_vectors; i++) synchronize_irq(adapter->msix_entries[i].vector); } else { @@ -2921,6 +2927,7 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) if (adapter->flags2 & FLAG2_DMA_BURST) { u32 txdctl = er32(TXDCTL(0)); + txdctl &= ~(E1000_TXDCTL_PTHRESH | E1000_TXDCTL_HTHRESH | E1000_TXDCTL_WTHRESH); /* set up some performance related parameters to encourage the @@ -3239,6 +3246,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) if (adapter->flags & FLAG_IS_ICH) { u32 rxdctl = er32(RXDCTL(0)); + ew32(RXDCTL(0), rxdctl | 0x3); } @@ -4695,6 +4703,7 @@ static void e1000e_update_stats(struct e1000_adapter *adapter) /* Correctable ECC Errors */ if (hw->mac.type == e1000_pch_lpt) { u32 pbeccsts = er32(PBECCSTS); + adapter->corr_errors += pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK; adapter->uncorr_errors += @@ -4808,6 +4817,7 @@ static void e1000e_enable_receives(struct e1000_adapter *adapter) (adapter->flags & FLAG_RESTART_NOW)) { struct e1000_hw *hw = &adapter->hw; u32 rctl = er32(RCTL); + ew32(RCTL, rctl | E1000_RCTL_EN); adapter->flags &= ~FLAG_RESTART_NOW; } @@ -4930,6 +4940,7 @@ static void e1000_watchdog_task(struct work_struct *work) if ((adapter->flags & FLAG_TARC_SPEED_MODE_BIT) && !txb2b) { u32 tarc0; + tarc0 = er32(TARC(0)); tarc0 &= ~SPEED_MODE_BIT; ew32(TARC(0), tarc0); @@ -5170,7 +5181,7 @@ static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb) __be16 protocol; if (skb->ip_summed != CHECKSUM_PARTIAL) - return 0; + return false; if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; @@ -5215,7 +5226,7 @@ static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb) i = 0; tx_ring->next_to_use = i; - return 1; + return true; } static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb, @@ -6209,6 +6220,7 @@ static int __e1000_resume(struct pci_dev *pdev) e1e_wphy(&adapter->hw, BM_WUS, ~0); } else { u32 wus = er32(WUS); + if (wus) { e_info("MAC Wakeup cause - %s\n", wus & E1000_WUS_EX ? "Unicast Packet" : @@ -7027,7 +7039,7 @@ static const struct pci_error_handlers e1000_err_handler = { .resume = e1000_io_resume, }; -static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = { +static const struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 }, @@ -7144,6 +7156,7 @@ static struct pci_driver e1000_driver = { static int __init e1000_init_module(void) { int ret; + pr_info("Intel(R) PRO/1000 Network Driver - %s\n", e1000e_driver_version); pr_info("Copyright(c) 1999 - 2014 Intel Corporation.\n"); diff --git a/drivers/net/ethernet/intel/e1000e/nvm.c b/drivers/net/ethernet/intel/e1000e/nvm.c index a9a976f04bffe9..b1f212b7baf7e7 100644 --- a/drivers/net/ethernet/intel/e1000e/nvm.c +++ b/drivers/net/ethernet/intel/e1000e/nvm.c @@ -398,6 +398,7 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) /* Loop to allow for up to whole page write of eeprom */ while (widx < words) { u16 word_out = data[widx]; + word_out = (word_out >> 8) | (word_out << 8); e1000_shift_out_eec_bits(hw, word_out, 16); widx++; diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c index d0ac0f3249c886..aa1923f7ebdd2e 100644 --- a/drivers/net/ethernet/intel/e1000e/param.c +++ b/drivers/net/ethernet/intel/e1000e/param.c @@ -436,6 +436,7 @@ void e1000e_check_options(struct e1000_adapter *adapter) if (num_IntMode > bd) { unsigned int int_mode = IntMode[bd]; + e1000_validate_option(&int_mode, &opt, adapter); adapter->int_mode = int_mode; } else { @@ -457,6 +458,7 @@ void e1000e_check_options(struct e1000_adapter *adapter) if (num_SmartPowerDownEnable > bd) { unsigned int spd = SmartPowerDownEnable[bd]; + e1000_validate_option(&spd, &opt, adapter); if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) && spd) adapter->flags |= FLAG_SMART_POWER_DOWN; @@ -473,6 +475,7 @@ void e1000e_check_options(struct e1000_adapter *adapter) if (num_CrcStripping > bd) { unsigned int crc_stripping = CrcStripping[bd]; + e1000_validate_option(&crc_stripping, &opt, adapter); if (crc_stripping == OPTION_ENABLED) { adapter->flags2 |= FLAG2_CRC_STRIPPING; @@ -495,6 +498,7 @@ void e1000e_check_options(struct e1000_adapter *adapter) if (num_KumeranLockLoss > bd) { unsigned int kmrn_lock_loss = KumeranLockLoss[bd]; + e1000_validate_option(&kmrn_lock_loss, &opt, adapter); enabled = kmrn_lock_loss; } diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c index 00b3fc98bf309b..b2005e13fb0158 100644 --- a/drivers/net/ethernet/intel/e1000e/phy.c +++ b/drivers/net/ethernet/intel/e1000e/phy.c @@ -2896,6 +2896,7 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data, (hw->phy.addr == 2) && !(MAX_PHY_REG_ADDRESS & reg) && (data & (1 << 11))) { u16 data2 = 0x7EFF; + ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3, &data2, false); diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index beb7b4393a6c26..a46571c1e9f187 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -329,9 +329,7 @@ struct i40e_pf { struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_caps; struct sk_buff *ptp_tx_skb; - struct work_struct ptp_tx_work; struct hwtstamp_config tstamp_config; - unsigned long ptp_tx_start; unsigned long last_rx_ptp_check; spinlock_t tmreg_lock; /* Used to protect the device time registers. */ u64 ptp_base_adj; diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index ed3902bf249b3e..34415d342ece38 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -32,6 +32,16 @@ static void i40e_resume_aq(struct i40e_hw *hw); +/** + * i40e_is_nvm_update_op - return true if this is an NVM update operation + * @desc: API request descriptor + **/ +static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc) +{ + return (desc->opcode == i40e_aqc_opc_nvm_erase) || + (desc->opcode == i40e_aqc_opc_nvm_update); +} + /** * i40e_adminq_init_regs - Initialize AdminQ registers * @hw: pointer to the hardware structure @@ -585,6 +595,7 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw) /* pre-emptive resource lock release */ i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL); + hw->aq.nvm_busy = false; ret_code = i40e_aq_set_hmc_resource_profile(hw, I40E_HMC_PROFILE_DEFAULT, @@ -708,6 +719,12 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, goto asq_send_command_exit; } + if (i40e_is_nvm_update_op(desc) && hw->aq.nvm_busy) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: NVM busy.\n"); + status = I40E_ERR_NVM; + goto asq_send_command_exit; + } + details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use); if (cmd_details) { *details = *cmd_details; @@ -835,6 +852,9 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; } + if (i40e_is_nvm_update_op(desc)) + hw->aq.nvm_busy = true; + /* update the error if time out occurred */ if ((!cmd_completed) && (!details->async && !details->postpone)) { @@ -929,6 +949,9 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw, e->msg_size); } + if (i40e_is_nvm_update_op(&e->desc)) + hw->aq.nvm_busy = false; + /* Restore the original datalen and buffer address in the desc, * FW updates datalen to indicate the event message * size diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h index 993f7685a91116..b1552fbc48a0e6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h @@ -90,6 +90,7 @@ struct i40e_adminq_info { u16 fw_min_ver; /* firmware minor version */ u16 api_maj_ver; /* api major version */ u16 api_min_ver; /* api minor version */ + bool nvm_busy; struct mutex asq_mutex; /* Send queue lock */ struct mutex arq_mutex; /* Receive queue lock */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 7b6374a8f8da5c..f2ba4b76ecd31a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -182,9 +182,6 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_add_mirror_rule = 0x0260, i40e_aqc_opc_delete_mirror_rule = 0x0261, - i40e_aqc_opc_set_storm_control_config = 0x0280, - i40e_aqc_opc_get_storm_control_config = 0x0281, - /* DCB commands */ i40e_aqc_opc_dcb_ignore_pfc = 0x0301, i40e_aqc_opc_dcb_updated = 0x0302, @@ -207,6 +204,7 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_query_switching_comp_bw_config = 0x041A, i40e_aqc_opc_suspend_port_tx = 0x041B, i40e_aqc_opc_resume_port_tx = 0x041C, + i40e_aqc_opc_configure_partition_bw = 0x041D, /* hmc */ i40e_aqc_opc_query_hmc_resource_profile = 0x0500, @@ -1289,27 +1287,6 @@ struct i40e_aqc_add_delete_mirror_rule_completion { I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion); -/* Set Storm Control Configuration (direct 0x0280) - * Get Storm Control Configuration (direct 0x0281) - * the command and response use the same descriptor structure - */ -struct i40e_aqc_set_get_storm_control_config { - __le32 broadcast_threshold; - __le32 multicast_threshold; - __le32 control_flags; -#define I40E_AQC_STORM_CONTROL_MDIPW 0x01 -#define I40E_AQC_STORM_CONTROL_MDICW 0x02 -#define I40E_AQC_STORM_CONTROL_BDIPW 0x04 -#define I40E_AQC_STORM_CONTROL_BDICW 0x08 -#define I40E_AQC_STORM_CONTROL_BIDU 0x10 -#define I40E_AQC_STORM_CONTROL_INTERVAL_SHIFT 8 -#define I40E_AQC_STORM_CONTROL_INTERVAL_MASK (0x3FF << \ - I40E_AQC_STORM_CONTROL_INTERVAL_SHIFT) - u8 reserved[4]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_get_storm_control_config); - /* DCB 0x03xx*/ /* PFC Ignore (direct 0x0301) @@ -1499,6 +1476,15 @@ struct i40e_aqc_query_switching_comp_bw_config_resp { * (direct 0x041B and 0x041C) uses the generic SEID struct */ +/* Configure partition BW + * (indirect 0x041D) + */ +struct i40e_aqc_configure_partition_bw_data { + __le16 pf_valid_bits; + u8 min_bw[16]; /* guaranteed bandwidth */ + u8 max_bw[16]; /* bandwidth limit */ +}; + /* Get and set the active HMC resource profile and status. * (direct 0x0500) and (direct 0x0501) */ @@ -1583,11 +1569,8 @@ struct i40e_aq_get_phy_abilities_resp { #define I40E_AQ_PHY_FLAG_PAUSE_TX 0x01 #define I40E_AQ_PHY_FLAG_PAUSE_RX 0x02 #define I40E_AQ_PHY_FLAG_LOW_POWER 0x04 -#define I40E_AQ_PHY_FLAG_AN_SHIFT 3 -#define I40E_AQ_PHY_FLAG_AN_MASK (0x3 << I40E_AQ_PHY_FLAG_AN_SHIFT) -#define I40E_AQ_PHY_FLAG_AN_OFF 0x00 /* link forced on */ -#define I40E_AQ_PHY_FLAG_AN_OFF_LINK_DOWN 0x01 -#define I40E_AQ_PHY_FLAG_AN_ON 0x02 +#define I40E_AQ_PHY_LINK_ENABLED 0x08 +#define I40E_AQ_PHY_AN_ENABLED 0x10 #define I40E_AQ_PHY_FLAG_MODULE_QUAL 0x20 __le16 eee_capability; #define I40E_AQ_EEE_100BASE_TX 0x0002 diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 922cdcc45c54b1..22eefda3a5303d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -975,6 +975,13 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, hw_link_info->an_info = resp->an_info; hw_link_info->ext_info = resp->ext_info; hw_link_info->loopback = resp->loopback; + hw_link_info->max_frame_size = le16_to_cpu(resp->max_frame_size); + hw_link_info->pacing = resp->config & I40E_AQ_CONFIG_PACING_MASK; + + if (resp->config & I40E_AQ_CONFIG_CRC_ENA) + hw_link_info->crc_enable = true; + else + hw_link_info->crc_enable = false; if (resp->command_flags & cpu_to_le16(I40E_AQ_LSE_ENABLE)) hw_link_info->lse_enable = true; @@ -1300,6 +1307,7 @@ i40e_status i40e_aq_send_driver_version(struct i40e_hw *hw, struct i40e_aqc_driver_version *cmd = (struct i40e_aqc_driver_version *)&desc.params.raw; i40e_status status; + u16 len; if (dv == NULL) return I40E_ERR_PARAM; @@ -1311,7 +1319,14 @@ i40e_status i40e_aq_send_driver_version(struct i40e_hw *hw, cmd->driver_minor_ver = dv->minor_version; cmd->driver_build_ver = dv->build_version; cmd->driver_subbuild_ver = dv->subbuild_version; - status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + + len = 0; + while (len < sizeof(dv->driver_string) && + (dv->driver_string[len] < 0x80) && + dv->driver_string[len]) + len++; + status = i40e_asq_send_command(hw, &desc, dv->driver_string, + len, cmd_details); return status; } @@ -2094,8 +2109,8 @@ i40e_status i40e_aq_start_lldp(struct i40e_hw *hw, * @cmd_details: pointer to command details structure or NULL **/ i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw, - u16 udp_port, u8 header_len, - u8 protocol_index, u8 *filter_index, + u16 udp_port, u8 protocol_index, + u8 *filter_index, struct i40e_asq_cmd_details *cmd_details) { struct i40e_aq_desc desc; @@ -2252,6 +2267,35 @@ static i40e_status i40e_aq_tx_sched_cmd(struct i40e_hw *hw, u16 seid, return status; } +/** + * i40e_aq_config_vsi_bw_limit - Configure VSI BW Limit + * @hw: pointer to the hw struct + * @seid: VSI seid + * @credit: BW limit credits (0 = disabled) + * @max_credit: Max BW limit credits + * @cmd_details: pointer to command details structure or NULL + **/ +i40e_status i40e_aq_config_vsi_bw_limit(struct i40e_hw *hw, + u16 seid, u16 credit, u8 max_credit, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aqc_configure_vsi_bw_limit *cmd = + (struct i40e_aqc_configure_vsi_bw_limit *)&desc.params.raw; + i40e_status status; + + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_configure_vsi_bw_limit); + + cmd->vsi_seid = cpu_to_le16(seid); + cmd->credit = cpu_to_le16(credit); + cmd->max_credit = max_credit; + + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + + return status; +} + /** * i40e_aq_config_vsi_tc_bw - Config VSI BW Allocation per TC * @hw: pointer to the hw struct diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 3c37386fd138fd..1aaec400b28ecb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1744,10 +1744,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp, i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_ATR_ENABLED, false); } else if (strncmp(cmd_buf, "fd-atr on", 9) == 0) { i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_ATR_ENABLED, true); - } else if (strncmp(cmd_buf, "fd-sb off", 9) == 0) { - i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_SB_ENABLED, false); - } else if (strncmp(cmd_buf, "fd-sb on", 8) == 0) { - i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_SB_ENABLED, true); } else if (strncmp(cmd_buf, "lldp", 4) == 0) { if (strncmp(&cmd_buf[5], "stop", 4) == 0) { int ret; @@ -1967,8 +1963,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp, dev_info(&pf->pdev->dev, " rem fd_filter \n"); dev_info(&pf->pdev->dev, " fd-atr off\n"); dev_info(&pf->pdev->dev, " fd-atr on\n"); - dev_info(&pf->pdev->dev, " fd-sb off\n"); - dev_info(&pf->pdev->dev, " fd-sb on\n"); dev_info(&pf->pdev->dev, " lldp start\n"); dev_info(&pf->pdev->dev, " lldp stop\n"); dev_info(&pf->pdev->dev, " lldp get local\n"); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 03d99cbc5c251b..0cf47c958081ad 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -649,7 +649,7 @@ static void i40e_get_ethtool_stats(struct net_device *netdev, sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } rcu_read_lock(); - for (j = 0; j < vsi->num_queue_pairs; j++, i += 4) { + for (j = 0; j < vsi->num_queue_pairs; j++) { struct i40e_ring *tx_ring = ACCESS_ONCE(vsi->tx_rings[j]); struct i40e_ring *rx_ring; @@ -662,14 +662,16 @@ static void i40e_get_ethtool_stats(struct net_device *netdev, data[i] = tx_ring->stats.packets; data[i + 1] = tx_ring->stats.bytes; } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start)); + i += 2; /* Rx ring is the 2nd half of the queue pair */ rx_ring = &tx_ring[1]; do { start = u64_stats_fetch_begin_irq(&rx_ring->syncp); - data[i + 2] = rx_ring->stats.packets; - data[i + 3] = rx_ring->stats.bytes; + data[i] = rx_ring->stats.packets; + data[i + 1] = rx_ring->stats.bytes; } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start)); + i += 2; } rcu_read_unlock(); if (vsi == pf->vsi[pf->lan_vsi]) { @@ -1189,6 +1191,12 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf, return -EINVAL; fsp->flow_type = rule->flow_type; + if (fsp->flow_type == IP_USER_FLOW) { + fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; + fsp->h_u.usr_ip4_spec.proto = 0; + fsp->m_u.usr_ip4_spec.proto = 0; + } + fsp->h_u.tcp_ip4_spec.psrc = rule->src_port; fsp->h_u.tcp_ip4_spec.pdst = rule->dst_port; fsp->h_u.tcp_ip4_spec.ip4src = rule->src_ip[0]; diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c index d5d98fe2691dd6..5c341aeb5d530d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c @@ -747,6 +747,7 @@ static struct i40e_context_ele i40e_hmc_rxq_ce_info[] = { { I40E_HMC_STORE(i40e_hmc_obj_rxq, tphdata_ena), 1, 195 }, { I40E_HMC_STORE(i40e_hmc_obj_rxq, tphhead_ena), 1, 196 }, { I40E_HMC_STORE(i40e_hmc_obj_rxq, lrxqthresh), 3, 198 }, + { I40E_HMC_STORE(i40e_hmc_obj_rxq, prefena), 1, 201 }, { 0 } }; diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h index 341de925a29831..eb65fe23c4a700 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h @@ -56,6 +56,7 @@ struct i40e_hmc_obj_rxq { u8 tphdata_ena; u8 tphhead_ena; u8 lrxqthresh; + u8 prefena; /* NOTE: normally must be set to 1 at init */ }; /* Tx queue context data */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index cf0761f08911b5..e64e5f2dfb2f75 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 3 -#define DRV_VERSION_BUILD 36 +#define DRV_VERSION_BUILD 46 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN @@ -2312,6 +2312,8 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) rx_ctx.crcstrip = 1; rx_ctx.l2tsel = 1; rx_ctx.showiv = 1; + /* set the prefena field to 1 because the manual says to */ + rx_ctx.prefena = 1; /* clear the context in the HMC */ err = i40e_clear_lan_rx_queue_context(hw, pf_q); @@ -3160,9 +3162,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) usleep_range(1000, 2000); } /* Skip if the queue is already in the requested state */ - if (enable && (tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) - continue; - if (!enable && !(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) + if (enable == !!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) continue; /* turn on/off the queue */ @@ -3178,13 +3178,8 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) /* wait for the change to finish */ for (j = 0; j < 10; j++) { tx_reg = rd32(hw, I40E_QTX_ENA(pf_q)); - if (enable) { - if ((tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) - break; - } else { - if (!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) - break; - } + if (enable == !!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) + break; udelay(10); } @@ -3223,15 +3218,9 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable) usleep_range(1000, 2000); } - if (enable) { - /* is STAT set ? */ - if ((rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) - continue; - } else { - /* is !STAT set ? */ - if (!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) - continue; - } + /* Skip if the queue is already in the requested state */ + if (enable == !!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) + continue; /* turn on/off the queue */ if (enable) @@ -3244,13 +3233,8 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable) for (j = 0; j < 10; j++) { rx_reg = rd32(hw, I40E_QRX_ENA(pf_q)); - if (enable) { - if ((rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) - break; - } else { - if (!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) - break; - } + if (enable == !!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) + break; udelay(10); } @@ -3512,6 +3496,19 @@ static void i40e_napi_disable_all(struct i40e_vsi *vsi) napi_disable(&vsi->q_vectors[q_idx]->napi); } +/** + * i40e_vsi_close - Shut down a VSI + * @vsi: the vsi to be quelled + **/ +static void i40e_vsi_close(struct i40e_vsi *vsi) +{ + if (!test_and_set_bit(__I40E_DOWN, &vsi->state)) + i40e_down(vsi); + i40e_vsi_free_irq(vsi); + i40e_vsi_free_tx_resources(vsi); + i40e_vsi_free_rx_resources(vsi); +} + /** * i40e_quiesce_vsi - Pause a given VSI * @vsi: the VSI being paused @@ -3525,8 +3522,7 @@ static void i40e_quiesce_vsi(struct i40e_vsi *vsi) if (vsi->netdev && netif_running(vsi->netdev)) { vsi->netdev->netdev_ops->ndo_stop(vsi->netdev); } else { - set_bit(__I40E_DOWN, &vsi->state); - i40e_down(vsi); + i40e_vsi_close(vsi); } } @@ -3543,7 +3539,7 @@ static void i40e_unquiesce_vsi(struct i40e_vsi *vsi) if (vsi->netdev && netif_running(vsi->netdev)) vsi->netdev->netdev_ops->ndo_open(vsi->netdev); else - i40e_up(vsi); /* this clears the DOWN bit */ + i40e_vsi_open(vsi); /* this clears the DOWN bit */ } /** @@ -4028,6 +4024,8 @@ static void i40e_dcb_reconfigure(struct i40e_pf *pf) pf->vsi[v]->seid); /* Will try to configure as many components */ } else { + /* Re-configure VSI vectors based on updated TC map */ + i40e_vsi_map_rings_to_vectors(pf->vsi[v]); if (pf->vsi[v]->netdev) i40e_dcbnl_set_all(pf->vsi[v]); } @@ -4067,6 +4065,9 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) DCB_CAP_DCBX_VER_IEEE; pf->flags |= I40E_FLAG_DCB_ENABLED; } + } else { + dev_info(&pf->pdev->dev, "AQ Querying DCB configuration failed: %d\n", + pf->hw.aq.asq_last_status); } out: @@ -4309,24 +4310,32 @@ int i40e_vsi_open(struct i40e_vsi *vsi) if (err) goto err_setup_rx; - if (!vsi->netdev) { + if (vsi->netdev) { + snprintf(int_name, sizeof(int_name) - 1, "%s-%s", + dev_driver_string(&pf->pdev->dev), vsi->netdev->name); + err = i40e_vsi_request_irq(vsi, int_name); + if (err) + goto err_setup_rx; + + /* Notify the stack of the actual queue counts. */ + err = netif_set_real_num_tx_queues(vsi->netdev, + vsi->num_queue_pairs); + if (err) + goto err_set_queues; + + err = netif_set_real_num_rx_queues(vsi->netdev, + vsi->num_queue_pairs); + if (err) + goto err_set_queues; + + } else if (vsi->type == I40E_VSI_FDIR) { + snprintf(int_name, sizeof(int_name) - 1, "%s-fdir", + dev_driver_string(&pf->pdev->dev)); + err = i40e_vsi_request_irq(vsi, int_name); + } else { err = EINVAL; goto err_setup_rx; } - snprintf(int_name, sizeof(int_name) - 1, "%s-%s", - dev_driver_string(&pf->pdev->dev), vsi->netdev->name); - err = i40e_vsi_request_irq(vsi, int_name); - if (err) - goto err_setup_rx; - - /* Notify the stack of the actual queue counts. */ - err = netif_set_real_num_tx_queues(vsi->netdev, vsi->num_queue_pairs); - if (err) - goto err_set_queues; - - err = netif_set_real_num_rx_queues(vsi->netdev, vsi->num_queue_pairs); - if (err) - goto err_set_queues; err = i40e_up_complete(vsi); if (err) @@ -4383,14 +4392,7 @@ static int i40e_close(struct net_device *netdev) struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; - if (test_and_set_bit(__I40E_DOWN, &vsi->state)) - return 0; - - i40e_down(vsi); - i40e_vsi_free_irq(vsi); - - i40e_vsi_free_tx_resources(vsi); - i40e_vsi_free_rx_resources(vsi); + i40e_vsi_close(vsi); return 0; } @@ -4676,7 +4678,7 @@ static void i40e_service_event_complete(struct i40e_pf *pf) BUG_ON(!test_bit(__I40E_SERVICE_SCHED, &pf->state)); /* flush memory to make sure state is correct before next watchog */ - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(__I40E_SERVICE_SCHED, &pf->state); } @@ -5226,9 +5228,6 @@ static int i40e_get_capabilities(struct i40e_pf *pf) } } while (err); - /* increment MSI-X count because current FW skips one */ - pf->hw.func_caps.num_msix_vectors++; - if (((pf->hw.aq.fw_maj_ver == 2) && (pf->hw.aq.fw_min_ver < 22)) || (pf->hw.aq.fw_maj_ver < 2)) { pf->hw.func_caps.num_msix_vectors++; @@ -5267,8 +5266,7 @@ static int i40e_vsi_clear(struct i40e_vsi *vsi); static void i40e_fdir_sb_setup(struct i40e_pf *pf) { struct i40e_vsi *vsi; - bool new_vsi = false; - int err, i; + int i; if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED)) return; @@ -5288,47 +5286,12 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf) pf->vsi[pf->lan_vsi]->seid, 0); if (!vsi) { dev_info(&pf->pdev->dev, "Couldn't create FDir VSI\n"); - goto err_vsi; + pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; + return; } - new_vsi = true; } - i40e_vsi_setup_irqhandler(vsi, i40e_fdir_clean_ring); - err = i40e_vsi_setup_tx_resources(vsi); - if (err) - goto err_setup_tx; - err = i40e_vsi_setup_rx_resources(vsi); - if (err) - goto err_setup_rx; - - if (new_vsi) { - char int_name[IFNAMSIZ + 9]; - err = i40e_vsi_configure(vsi); - if (err) - goto err_setup_rx; - snprintf(int_name, sizeof(int_name) - 1, "%s-fdir", - dev_driver_string(&pf->pdev->dev)); - err = i40e_vsi_request_irq(vsi, int_name); - if (err) - goto err_setup_rx; - err = i40e_up_complete(vsi); - if (err) - goto err_up_complete; - clear_bit(__I40E_NEEDS_RESTART, &vsi->state); - } - - return; - -err_up_complete: - i40e_down(vsi); - i40e_vsi_free_irq(vsi); -err_setup_rx: - i40e_vsi_free_rx_resources(vsi); -err_setup_tx: - i40e_vsi_free_tx_resources(vsi); -err_vsi: - pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; - i40e_vsi_clear(vsi); + i40e_vsi_setup_irqhandler(vsi, i40e_fdir_clean_ring); } /** @@ -5642,7 +5605,6 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf) **/ static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf) { - const int vxlan_hdr_qwords = 4; struct i40e_hw *hw = &pf->hw; i40e_status ret; u8 filter_index; @@ -5660,7 +5622,6 @@ static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf) port = pf->vxlan_ports[i]; ret = port ? i40e_aq_add_udp_tunnel(hw, ntohs(port), - vxlan_hdr_qwords, I40E_AQC_TUNNEL_TYPE_VXLAN, &filter_index, NULL) : i40e_aq_del_udp_tunnel(hw, i, NULL); @@ -6649,6 +6610,96 @@ static void i40e_del_vxlan_port(struct net_device *netdev, } #endif +#ifdef HAVE_FDB_OPS +#ifdef USE_CONST_DEV_UC_CHAR +static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], + struct net_device *dev, + const unsigned char *addr, + u16 flags) +#else +static int i40e_ndo_fdb_add(struct ndmsg *ndm, + struct net_device *dev, + unsigned char *addr, + u16 flags) +#endif +{ + struct i40e_netdev_priv *np = netdev_priv(dev); + struct i40e_pf *pf = np->vsi->back; + int err = 0; + + if (!(pf->flags & I40E_FLAG_SRIOV_ENABLED)) + return -EOPNOTSUPP; + + /* Hardware does not support aging addresses so if a + * ndm_state is given only allow permanent addresses + */ + if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) { + netdev_info(dev, "FDB only supports static addresses\n"); + return -EINVAL; + } + + if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) + err = dev_uc_add_excl(dev, addr); + else if (is_multicast_ether_addr(addr)) + err = dev_mc_add_excl(dev, addr); + else + err = -EINVAL; + + /* Only return duplicate errors if NLM_F_EXCL is set */ + if (err == -EEXIST && !(flags & NLM_F_EXCL)) + err = 0; + + return err; +} + +#ifndef USE_DEFAULT_FDB_DEL_DUMP +#ifdef USE_CONST_DEV_UC_CHAR +static int i40e_ndo_fdb_del(struct ndmsg *ndm, + struct net_device *dev, + const unsigned char *addr) +#else +static int i40e_ndo_fdb_del(struct ndmsg *ndm, + struct net_device *dev, + unsigned char *addr) +#endif +{ + struct i40e_netdev_priv *np = netdev_priv(dev); + struct i40e_pf *pf = np->vsi->back; + int err = -EOPNOTSUPP; + + if (ndm->ndm_state & NUD_PERMANENT) { + netdev_info(dev, "FDB only supports static addresses\n"); + return -EINVAL; + } + + if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { + if (is_unicast_ether_addr(addr)) + err = dev_uc_del(dev, addr); + else if (is_multicast_ether_addr(addr)) + err = dev_mc_del(dev, addr); + else + err = -EINVAL; + } + + return err; +} + +static int i40e_ndo_fdb_dump(struct sk_buff *skb, + struct netlink_callback *cb, + struct net_device *dev, + int idx) +{ + struct i40e_netdev_priv *np = netdev_priv(dev); + struct i40e_pf *pf = np->vsi->back; + + if (pf->flags & I40E_FLAG_SRIOV_ENABLED) + idx = ndo_dflt_fdb_dump(skb, cb, dev, idx); + + return idx; +} + +#endif /* USE_DEFAULT_FDB_DEL_DUMP */ +#endif /* HAVE_FDB_OPS */ static const struct net_device_ops i40e_netdev_ops = { .ndo_open = i40e_open, .ndo_stop = i40e_close, @@ -6676,6 +6727,13 @@ static const struct net_device_ops i40e_netdev_ops = { .ndo_add_vxlan_port = i40e_add_vxlan_port, .ndo_del_vxlan_port = i40e_del_vxlan_port, #endif +#ifdef HAVE_FDB_OPS + .ndo_fdb_add = i40e_ndo_fdb_add, +#ifndef USE_DEFAULT_FDB_DEL_DUMP + .ndo_fdb_del = i40e_ndo_fdb_del, + .ndo_fdb_dump = i40e_ndo_fdb_dump, +#endif +#endif }; /** @@ -6720,10 +6778,12 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_RXCSUM | - NETIF_F_NTUPLE | NETIF_F_RXHASH | 0; + if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) + netdev->features |= NETIF_F_NTUPLE; + /* copy netdev features into list of user selectable features */ netdev->hw_features |= netdev->features; @@ -6982,11 +7042,7 @@ int i40e_vsi_release(struct i40e_vsi *vsi) unregister_netdev(vsi->netdev); } } else { - if (!test_and_set_bit(__I40E_DOWN, &vsi->state)) - i40e_down(vsi); - i40e_vsi_free_irq(vsi); - i40e_vsi_free_tx_resources(vsi); - i40e_vsi_free_rx_resources(vsi); + i40e_vsi_close(vsi); } i40e_vsi_disable_irq(vsi); } @@ -8090,6 +8146,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) u16 link_status; int err = 0; u32 len; + u32 i; err = pci_enable_device_mem(pdev); if (err) @@ -8243,7 +8300,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) { dev_info(&pdev->dev, "init_pf_dcb failed: %d\n", err); pf->flags &= ~I40E_FLAG_DCB_ENABLED; - goto err_init_dcb; + /* Continue without DCB enabled */ } #endif /* CONFIG_I40E_DCB */ @@ -8279,6 +8336,13 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "setup_pf_switch failed: %d\n", err); goto err_vsis; } + /* if FDIR VSI was set up, start it now */ + for (i = 0; i < pf->hw.func_caps.num_vsis; i++) { + if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) { + i40e_vsi_open(pf->vsi[i]); + break; + } + } /* The main driver is (mostly) up and happy. We need to set this state * before setting up the misc vector or we get a race and the vector @@ -8332,6 +8396,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dv.minor_version = DRV_VERSION_MINOR; dv.build_version = DRV_VERSION_BUILD; dv.subbuild_version = 0; + strncpy(dv.driver_string, DRV_VERSION, sizeof(dv.driver_string)); i40e_aq_send_driver_version(&pf->hw, &dv, NULL); /* since everything's happy, start the service_task timer */ @@ -8373,9 +8438,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_switch_setup: i40e_reset_interrupt_capability(pf); del_timer_sync(&pf->service_timer); -#ifdef CONFIG_I40E_DCB -err_init_dcb: -#endif /* CONFIG_I40E_DCB */ err_mac_addr: err_configure_lan_hmc: (void)i40e_shutdown_lan_hmc(hw); diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 9cd57e617959b1..d351832bf2359a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -157,8 +157,8 @@ i40e_status i40e_aq_stop_lldp(struct i40e_hw *hw, bool shutdown_agent, i40e_status i40e_aq_start_lldp(struct i40e_hw *hw, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw, - u16 udp_port, u8 header_len, - u8 protocol_index, u8 *filter_index, + u16 udp_port, u8 protocol_index, + u8 *filter_index, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_del_udp_tunnel(struct i40e_hw *hw, u8 index, struct i40e_asq_cmd_details *cmd_details); @@ -167,6 +167,9 @@ i40e_status i40e_aq_delete_element(struct i40e_hw *hw, u16 seid, i40e_status i40e_aq_mac_address_write(struct i40e_hw *hw, u16 flags, u8 *mac_addr, struct i40e_asq_cmd_details *cmd_details); +i40e_status i40e_aq_config_vsi_bw_limit(struct i40e_hw *hw, + u16 seid, u16 credit, u8 max_credit, + struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_dcb_updated(struct i40e_hw *hw, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_hmc_resource_profile(struct i40e_hw *hw, diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index e61e63720800fc..1fedc7a1589d11 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -216,40 +216,6 @@ static int i40e_ptp_settime(struct ptp_clock_info *ptp, return 0; } -/** - * i40e_ptp_tx_work - * @work: pointer to work struct - * - * This work function polls the PRTTSYN_STAT_0.TXTIME bit to determine when a - * Tx timestamp event has occurred, in order to pass the Tx timestamp value up - * the stack in the skb. - */ -static void i40e_ptp_tx_work(struct work_struct *work) -{ - struct i40e_pf *pf = container_of(work, struct i40e_pf, - ptp_tx_work); - struct i40e_hw *hw = &pf->hw; - u32 prttsyn_stat_0; - - if (!pf->ptp_tx_skb) - return; - - if (time_is_before_jiffies(pf->ptp_tx_start + - I40E_PTP_TX_TIMEOUT)) { - dev_kfree_skb_any(pf->ptp_tx_skb); - pf->ptp_tx_skb = NULL; - pf->tx_hwtstamp_timeouts++; - dev_warn(&pf->pdev->dev, "clearing Tx timestamp hang\n"); - return; - } - - prttsyn_stat_0 = rd32(hw, I40E_PRTTSYN_STAT_0); - if (prttsyn_stat_0 & I40E_PRTTSYN_STAT_0_TXTIME_MASK) - i40e_ptp_tx_hwtstamp(pf); - else - schedule_work(&pf->ptp_tx_work); -} - /** * i40e_ptp_enable - Enable/disable ancillary features of the PHC subsystem * @ptp: The PTP clock structure @@ -608,7 +574,6 @@ void i40e_ptp_init(struct i40e_pf *pf) u32 regval; spin_lock_init(&pf->tmreg_lock); - INIT_WORK(&pf->ptp_tx_work, i40e_ptp_tx_work); dev_info(&pf->pdev->dev, "%s: added PHC on %s\n", __func__, netdev->name); @@ -647,7 +612,6 @@ void i40e_ptp_stop(struct i40e_pf *pf) pf->ptp_tx = false; pf->ptp_rx = false; - cancel_work_sync(&pf->ptp_tx_work); if (pf->ptp_tx_skb) { dev_kfree_skb_any(pf->ptp_tx_skb); pf->ptp_tx_skb = NULL; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 9478ddc66caf8d..ece7ae99b03a57 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1825,9 +1825,6 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb, *cd_type_cmd_tso_mss |= (u64)I40E_TX_CTX_DESC_TSYN << I40E_TXD_CTX_QW1_CMD_SHIFT; - pf->ptp_tx_start = jiffies; - schedule_work(&pf->ptp_tx_work); - return 1; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 71a968fe557f33..c4df8bac2db17d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -167,6 +167,9 @@ struct i40e_link_status { u8 loopback; /* is Link Status Event notification to SW enabled */ bool lse_enable; + u16 max_frame_size; + bool crc_enable; + u8 pacing; }; struct i40e_phy_info { @@ -409,6 +412,7 @@ struct i40e_driver_version { u8 minor_version; u8 build_version; u8 subbuild_version; + u8 driver_string[32]; }; /* RX Descriptors */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 02c11a7f7d29e8..82e7abf643081c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -28,6 +28,24 @@ /***********************misc routines*****************************/ +/** + * i40e_vc_disable_vf + * @pf: pointer to the pf info + * @vf: pointer to the vf info + * + * Disable the VF through a SW reset + **/ +static inline void i40e_vc_disable_vf(struct i40e_pf *pf, struct i40e_vf *vf) +{ + struct i40e_hw *hw = &pf->hw; + u32 reg; + + reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id)); + reg |= I40E_VPGEN_VFRTRIG_VFSWR_MASK; + wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg); + i40e_flush(hw); +} + /** * i40e_vc_isvalid_vsi_id * @vf: pointer to the vf info @@ -416,6 +434,15 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) if (ret) dev_err(&pf->pdev->dev, "Unable to program ucast filters\n"); + /* Set VF bandwidth if specified */ + if (vf->tx_rate) { + ret = i40e_aq_config_vsi_bw_limit(&pf->hw, vsi->seid, + vf->tx_rate / 50, 0, NULL); + if (ret) + dev_err(&pf->pdev->dev, "Unable to set tx rate, VF %d, error code %d.\n", + vf->vf_id, ret); + } + error_alloc_vsi_res: return ret; } @@ -2022,10 +2049,11 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) } /* delete the temporary mac address */ - i40e_del_filter(vsi, vf->default_lan_addr.addr, 0, true, false); + i40e_del_filter(vsi, vf->default_lan_addr.addr, vf->port_vlan_id, + true, false); /* add the new mac address */ - f = i40e_add_filter(vsi, mac, 0, true, false); + f = i40e_add_filter(vsi, mac, vf->port_vlan_id, true, false); if (!f) { dev_err(&pf->pdev->dev, "Unable to add VF ucast filter\n"); @@ -2088,18 +2116,28 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, goto error_pvid; } - if (vsi->info.pvid == 0 && i40e_is_vsi_in_vlan(vsi)) + if (vsi->info.pvid == 0 && i40e_is_vsi_in_vlan(vsi)) { dev_err(&pf->pdev->dev, "VF %d has already configured VLAN filters and the administrator is requesting a port VLAN override.\nPlease unload and reload the VF driver for this change to take effect.\n", vf_id); + /* Administrator Error - knock the VF offline until he does + * the right thing by reconfiguring his network correctly + * and then reloading the VF driver. + */ + i40e_vc_disable_vf(pf, vf); + } /* Check for condition where there was already a port VLAN ID * filter set and now it is being deleted by setting it to zero. + * Additionally check for the condition where there was a port + * VLAN but now there is a new and different port VLAN being set. * Before deleting all the old VLAN filters we must add new ones * with -1 (I40E_VLAN_ANY) or otherwise we're left with all our * MAC addresses deleted. */ - if (!(vlan_id || qos) && vsi->info.pvid) + if ((!(vlan_id || qos) || + (vlan_id | qos) != le16_to_cpu(vsi->info.pvid)) && + vsi->info.pvid) ret = i40e_vsi_add_vlan(vsi, I40E_VLAN_ANY); if (vsi->info.pvid) { @@ -2160,7 +2198,61 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, **/ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int tx_rate) { - return -EOPNOTSUPP; + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + struct i40e_vsi *vsi; + struct i40e_vf *vf; + int speed = 0; + int ret = 0; + + /* validate the request */ + if (vf_id >= pf->num_alloc_vfs) { + dev_err(&pf->pdev->dev, "Invalid VF Identifier %d.\n", vf_id); + ret = -EINVAL; + goto error; + } + + vf = &(pf->vf[vf_id]); + vsi = pf->vsi[vf->lan_vsi_index]; + if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) { + dev_err(&pf->pdev->dev, "Uninitialized VF %d.\n", vf_id); + ret = -EINVAL; + goto error; + } + + switch (pf->hw.phy.link_info.link_speed) { + case I40E_LINK_SPEED_40GB: + speed = 40000; + break; + case I40E_LINK_SPEED_10GB: + speed = 10000; + break; + case I40E_LINK_SPEED_1GB: + speed = 1000; + break; + default: + break; + } + + if (tx_rate > speed) { + dev_err(&pf->pdev->dev, "Invalid tx rate %d specified for vf %d.", + tx_rate, vf->vf_id); + ret = -EINVAL; + goto error; + } + + /* Tx rate credits are in values of 50Mbps, 0 is disabled*/ + ret = i40e_aq_config_vsi_bw_limit(&pf->hw, vsi->seid, tx_rate / 50, 0, + NULL); + if (ret) { + dev_err(&pf->pdev->dev, "Unable to set tx rate, error code %d.\n", + ret); + ret = -EIO; + goto error; + } + vf->tx_rate = tx_rate; +error: + return ret; } /** @@ -2200,10 +2292,17 @@ int i40e_ndo_get_vf_config(struct net_device *netdev, memcpy(&ivi->mac, vf->default_lan_addr.addr, ETH_ALEN); - ivi->tx_rate = 0; + ivi->tx_rate = vf->tx_rate; ivi->vlan = le16_to_cpu(vsi->info.pvid) & I40E_VLAN_MASK; ivi->qos = (le16_to_cpu(vsi->info.pvid) & I40E_PRIORITY_MASK) >> I40E_VLAN_PRIORITY_SHIFT; + if (vf->link_forced == false) + ivi->linkstate = IFLA_VF_LINK_STATE_AUTO; + else if (vf->link_up == true) + ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE; + else + ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE; + ret = 0; error_param: diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index 389c47f396d526..ba3d1f8414beab 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -98,6 +98,7 @@ struct i40e_vf { unsigned long vf_caps; /* vf's adv. capabilities */ unsigned long vf_states; /* vf's runtime states */ + unsigned int tx_rate; /* Tx bandwidth limit in Mbps */ bool link_forced; bool link_up; /* only valid if vf link is forced */ }; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index 5470ce95936ed4..c79df257f830d7 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -27,6 +27,16 @@ #include "i40e_adminq.h" #include "i40e_prototype.h" +/** + * i40e_is_nvm_update_op - return true if this is an NVM update operation + * @desc: API request descriptor + **/ +static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc) +{ + return (desc->opcode == i40e_aqc_opc_nvm_erase) || + (desc->opcode == i40e_aqc_opc_nvm_update); +} + /** * i40e_adminq_init_regs - Initialize AdminQ registers * @hw: pointer to the hardware structure @@ -659,6 +669,12 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, goto asq_send_command_exit; } + if (i40e_is_nvm_update_op(desc) && hw->aq.nvm_busy) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: NVM busy.\n"); + status = I40E_ERR_NVM; + goto asq_send_command_exit; + } + details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use); if (cmd_details) { *details = *cmd_details; @@ -786,6 +802,9 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; } + if (i40e_is_nvm_update_op(desc)) + hw->aq.nvm_busy = true; + /* update the error if time out occurred */ if ((!cmd_completed) && (!details->async && !details->postpone)) { @@ -880,6 +899,9 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw, e->msg_size); } + if (i40e_is_nvm_update_op(&e->desc)) + hw->aq.nvm_busy = false; + /* Restore the original datalen and buffer address in the desc, * FW updates datalen to indicate the event message * size diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h index 8f72c31d95cc85..7d24be528601c9 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h @@ -87,6 +87,7 @@ struct i40e_adminq_info { u16 fw_min_ver; /* firmware minor version */ u16 api_maj_ver; /* api major version */ u16 api_min_ver; /* api minor version */ + bool nvm_busy; struct mutex asq_mutex; /* Send queue lock */ struct mutex arq_mutex; /* Receive queue lock */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index 97662b6bd98a3e..6e617669c32625 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -180,9 +180,6 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_add_mirror_rule = 0x0260, i40e_aqc_opc_delete_mirror_rule = 0x0261, - i40e_aqc_opc_set_storm_control_config = 0x0280, - i40e_aqc_opc_get_storm_control_config = 0x0281, - /* DCB commands */ i40e_aqc_opc_dcb_ignore_pfc = 0x0301, i40e_aqc_opc_dcb_updated = 0x0302, @@ -205,6 +202,7 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_query_switching_comp_bw_config = 0x041A, i40e_aqc_opc_suspend_port_tx = 0x041B, i40e_aqc_opc_resume_port_tx = 0x041C, + i40e_aqc_opc_configure_partition_bw = 0x041D, /* hmc */ i40e_aqc_opc_query_hmc_resource_profile = 0x0500, @@ -1289,27 +1287,6 @@ struct i40e_aqc_add_delete_mirror_rule_completion { I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion); -/* Set Storm Control Configuration (direct 0x0280) - * Get Storm Control Configuration (direct 0x0281) - * the command and response use the same descriptor structure - */ -struct i40e_aqc_set_get_storm_control_config { - __le32 broadcast_threshold; - __le32 multicast_threshold; - __le32 control_flags; -#define I40E_AQC_STORM_CONTROL_MDIPW 0x01 -#define I40E_AQC_STORM_CONTROL_MDICW 0x02 -#define I40E_AQC_STORM_CONTROL_BDIPW 0x04 -#define I40E_AQC_STORM_CONTROL_BDICW 0x08 -#define I40E_AQC_STORM_CONTROL_BIDU 0x10 -#define I40E_AQC_STORM_CONTROL_INTERVAL_SHIFT 8 -#define I40E_AQC_STORM_CONTROL_INTERVAL_MASK (0x3FF << \ - I40E_AQC_STORM_CONTROL_INTERVAL_SHIFT) - u8 reserved[4]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_get_storm_control_config); - /* DCB 0x03xx*/ /* PFC Ignore (direct 0x0301) @@ -1499,6 +1476,15 @@ struct i40e_aqc_query_switching_comp_bw_config_resp { * (direct 0x041B and 0x041C) uses the generic SEID struct */ +/* Configure partition BW + * (indirect 0x041D) + */ +struct i40e_aqc_configure_partition_bw_data { + __le16 pf_valid_bits; + u8 min_bw[16]; /* guaranteed bandwidth */ + u8 max_bw[16]; /* bandwidth limit */ +}; + /* Get and set the active HMC resource profile and status. * (direct 0x0500) and (direct 0x0501) */ @@ -1583,11 +1569,8 @@ struct i40e_aq_get_phy_abilities_resp { #define I40E_AQ_PHY_FLAG_PAUSE_TX 0x01 #define I40E_AQ_PHY_FLAG_PAUSE_RX 0x02 #define I40E_AQ_PHY_FLAG_LOW_POWER 0x04 -#define I40E_AQ_PHY_FLAG_AN_SHIFT 3 -#define I40E_AQ_PHY_FLAG_AN_MASK (0x3 << I40E_AQ_PHY_FLAG_AN_SHIFT) -#define I40E_AQ_PHY_FLAG_AN_OFF 0x00 /* link forced on */ -#define I40E_AQ_PHY_FLAG_AN_OFF_LINK_DOWN 0x01 -#define I40E_AQ_PHY_FLAG_AN_ON 0x02 +#define I40E_AQ_PHY_LINK_ENABLED 0x08 +#define I40E_AQ_PHY_AN_ENABLED 0x10 #define I40E_AQ_PHY_FLAG_MODULE_QUAL 0x20 __le16 eee_capability; #define I40E_AQ_EEE_100BASE_TX 0x0002 diff --git a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h index 17e42ca26d0ba0..775fcb2463d7f4 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h @@ -53,6 +53,7 @@ struct i40e_hmc_obj_rxq { u8 tphdata_ena; u8 tphhead_ena; u8 lrxqthresh; + u8 prefena; /* NOTE: normally must be set to 1 at init */ }; /* Tx queue context data */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 4673b3381eddaa..51a6dee3c7b1a6 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -173,6 +173,9 @@ struct i40e_link_status { u8 loopback; /* is Link Status Event notification to SW enabled */ bool lse_enable; + u16 max_frame_size; + bool crc_enable; + u8 pacing; }; struct i40e_phy_info { @@ -415,6 +418,7 @@ struct i40e_driver_version { u8 minor_version; u8 build_version; u8 subbuild_version; + u8 driver_string[32]; }; /* RX Descriptors */ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c index 8b0db1ce179c54..a46be016039e37 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c @@ -365,6 +365,316 @@ static int i40evf_set_coalesce(struct net_device *netdev, return 0; } +/** + * i40e_get_rss_hash_opts - Get RSS hash Input Set for each flow type + * @adapter: board private structure + * @cmd: ethtool rxnfc command + * + * Returns Success if the flow is supported, else Invalid Input. + **/ +static int i40evf_get_rss_hash_opts(struct i40evf_adapter *adapter, + struct ethtool_rxnfc *cmd) +{ + struct i40e_hw *hw = &adapter->hw; + u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) | + ((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32); + + /* We always hash on IP src and dest addresses */ + cmd->data = RXH_IP_SRC | RXH_IP_DST; + + switch (cmd->flow_type) { + case TCP_V4_FLOW: + if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP)) + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + break; + case UDP_V4_FLOW: + if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP)) + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + break; + + case SCTP_V4_FLOW: + case AH_ESP_V4_FLOW: + case AH_V4_FLOW: + case ESP_V4_FLOW: + case IPV4_FLOW: + break; + + case TCP_V6_FLOW: + if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP)) + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + break; + case UDP_V6_FLOW: + if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP)) + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + break; + + case SCTP_V6_FLOW: + case AH_ESP_V6_FLOW: + case AH_V6_FLOW: + case ESP_V6_FLOW: + case IPV6_FLOW: + break; + default: + cmd->data = 0; + return -EINVAL; + } + + return 0; +} + +/** + * i40evf_get_rxnfc - command to get RX flow classification rules + * @netdev: network interface device structure + * @cmd: ethtool rxnfc command + * + * Returns Success if the command is supported. + **/ +static int i40evf_get_rxnfc(struct net_device *netdev, + struct ethtool_rxnfc *cmd, + u32 *rule_locs) +{ + struct i40evf_adapter *adapter = netdev_priv(netdev); + int ret = -EOPNOTSUPP; + + switch (cmd->cmd) { + case ETHTOOL_GRXRINGS: + cmd->data = adapter->vsi_res->num_queue_pairs; + ret = 0; + break; + case ETHTOOL_GRXFH: + ret = i40evf_get_rss_hash_opts(adapter, cmd); + break; + default: + break; + } + + return ret; +} + +/** + * i40evf_set_rss_hash_opt - Enable/Disable flow types for RSS hash + * @adapter: board private structure + * @cmd: ethtool rxnfc command + * + * Returns Success if the flow input set is supported. + **/ +static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, + struct ethtool_rxnfc *nfc) +{ + struct i40e_hw *hw = &adapter->hw; + + u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) | + ((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32); + + /* RSS does not support anything other than hashing + * to queues on src and dst IPs and ports + */ + if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3)) + return -EINVAL; + + /* We need at least the IP SRC and DEST fields for hashing */ + if (!(nfc->data & RXH_IP_SRC) || + !(nfc->data & RXH_IP_DST)) + return -EINVAL; + + switch (nfc->flow_type) { + case TCP_V4_FLOW: + switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { + case 0: + hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); + break; + case (RXH_L4_B_0_1 | RXH_L4_B_2_3): + hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); + break; + default: + return -EINVAL; + } + break; + case TCP_V6_FLOW: + switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { + case 0: + hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); + break; + case (RXH_L4_B_0_1 | RXH_L4_B_2_3): + hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); + break; + default: + return -EINVAL; + } + break; + case UDP_V4_FLOW: + switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { + case 0: + hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | + ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); + break; + case (RXH_L4_B_0_1 | RXH_L4_B_2_3): + hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | + ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); + break; + default: + return -EINVAL; + } + break; + case UDP_V6_FLOW: + switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { + case 0: + hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | + ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); + break; + case (RXH_L4_B_0_1 | RXH_L4_B_2_3): + hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | + ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); + break; + default: + return -EINVAL; + } + break; + case AH_ESP_V4_FLOW: + case AH_V4_FLOW: + case ESP_V4_FLOW: + case SCTP_V4_FLOW: + if ((nfc->data & RXH_L4_B_0_1) || + (nfc->data & RXH_L4_B_2_3)) + return -EINVAL; + hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); + break; + case AH_ESP_V6_FLOW: + case AH_V6_FLOW: + case ESP_V6_FLOW: + case SCTP_V6_FLOW: + if ((nfc->data & RXH_L4_B_0_1) || + (nfc->data & RXH_L4_B_2_3)) + return -EINVAL; + hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); + break; + case IPV4_FLOW: + hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | + ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4); + break; + case IPV6_FLOW: + hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | + ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); + break; + default: + return -EINVAL; + } + + wr32(hw, I40E_VFQF_HENA(0), (u32)hena); + wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32)); + i40e_flush(hw); + + return 0; +} + +/** + * i40evf_set_rxnfc - command to set RX flow classification rules + * @netdev: network interface device structure + * @cmd: ethtool rxnfc command + * + * Returns Success if the command is supported. + **/ +static int i40evf_set_rxnfc(struct net_device *netdev, + struct ethtool_rxnfc *cmd) +{ + struct i40evf_adapter *adapter = netdev_priv(netdev); + int ret = -EOPNOTSUPP; + + switch (cmd->cmd) { + case ETHTOOL_SRXFH: + ret = i40evf_set_rss_hash_opt(adapter, cmd); + break; + default: + break; + } + + return ret; +} + +/** + * i40evf_get_channels: get the number of channels supported by the device + * @netdev: network interface device structure + * @ch: channel information structure + * + * For the purposes of our device, we only use combined channels, i.e. a tx/rx + * queue pair. Report one extra channel to match our "other" MSI-X vector. + **/ +static void i40evf_get_channels(struct net_device *netdev, + struct ethtool_channels *ch) +{ + struct i40evf_adapter *adapter = netdev_priv(netdev); + + /* Report maximum channels */ + ch->max_combined = adapter->vsi_res->num_queue_pairs; + + ch->max_other = NONQ_VECS; + ch->other_count = NONQ_VECS; + + ch->combined_count = adapter->vsi_res->num_queue_pairs; +} + +/** + * i40evf_get_rxfh_indir_size - get the rx flow hash indirection table size + * @netdev: network interface device structure + * + * Returns the table size. + **/ +static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev) +{ + return (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4; +} + +/** + * i40evf_get_rxfh_indir - get the rx flow hash indirection table + * @netdev: network interface device structure + * @indir: indirection table + * + * Reads the indirection table directly from the hardware. Always returns 0. + **/ +static int i40evf_get_rxfh_indir(struct net_device *netdev, u32 *indir) +{ + struct i40evf_adapter *adapter = netdev_priv(netdev); + struct i40e_hw *hw = &adapter->hw; + u32 hlut_val; + int i, j; + + for (i = 0, j = 0; i < I40E_VFQF_HLUT_MAX_INDEX; i++) { + hlut_val = rd32(hw, I40E_VFQF_HLUT(i)); + indir[j++] = hlut_val & 0xff; + indir[j++] = (hlut_val >> 8) & 0xff; + indir[j++] = (hlut_val >> 16) & 0xff; + indir[j++] = (hlut_val >> 24) & 0xff; + } + return 0; +} + +/** + * i40evf_set_rxfh_indir - set the rx flow hash indirection table + * @netdev: network interface device structure + * @indir: indirection table + * + * Returns -EINVAL if the table specifies an inavlid queue id, otherwise + * returns 0 after programming the table. + **/ +static int i40evf_set_rxfh_indir(struct net_device *netdev, const u32 *indir) +{ + struct i40evf_adapter *adapter = netdev_priv(netdev); + struct i40e_hw *hw = &adapter->hw; + u32 hlut_val; + int i, j; + + for (i = 0, j = 0; i < I40E_VFQF_HLUT_MAX_INDEX + 1; i++) { + hlut_val = indir[j++]; + hlut_val |= indir[j++] << 8; + hlut_val |= indir[j++] << 16; + hlut_val |= indir[j++] << 24; + wr32(hw, I40E_VFQF_HLUT(i), hlut_val); + } + + return 0; +} + static struct ethtool_ops i40evf_ethtool_ops = { .get_settings = i40evf_get_settings, .get_drvinfo = i40evf_get_drvinfo, @@ -378,6 +688,12 @@ static struct ethtool_ops i40evf_ethtool_ops = { .set_msglevel = i40evf_set_msglevel, .get_coalesce = i40evf_get_coalesce, .set_coalesce = i40evf_set_coalesce, + .get_rxnfc = i40evf_get_rxnfc, + .set_rxnfc = i40evf_set_rxnfc, + .get_rxfh_indir_size = i40evf_get_rxfh_indir_size, + .get_rxfh_indir = i40evf_get_rxfh_indir, + .set_rxfh_indir = i40evf_set_rxfh_indir, + .get_channels = i40evf_get_channels, }; /** diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 2797548fde0dd9..6edd581dffa74f 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -25,13 +25,15 @@ #include "i40e_prototype.h" static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter); static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter); +static void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter); +static void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter); static int i40evf_close(struct net_device *netdev); char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710 X710 Virtual Function Network Driver"; -#define DRV_VERSION "0.9.16" +#define DRV_VERSION "0.9.23" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; @@ -1309,7 +1311,6 @@ static void i40evf_watchdog_task(struct work_struct *work) goto restart_watchdog; if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { - dev_info(&adapter->pdev->dev, "Checking for redemption\n"); if ((rd32(hw, I40E_VFGEN_RSTAT) & 0x3) == I40E_VFR_VFACTIVE) { /* A chance for redemption! */ dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n"); @@ -1534,9 +1535,13 @@ static void i40evf_reset_task(struct work_struct *work) rstat_val); adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; - if (netif_running(adapter->netdev)) - i40evf_close(adapter->netdev); - + if (netif_running(adapter->netdev)) { + set_bit(__I40E_DOWN, &adapter->vsi.state); + i40evf_down(adapter); + i40evf_free_traffic_irqs(adapter); + i40evf_free_all_tx_resources(adapter); + i40evf_free_all_rx_resources(adapter); + } i40evf_free_misc_irq(adapter); i40evf_reset_interrupt_capability(adapter); i40evf_free_queues(adapter); diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index fa36fe12e77502..2e36c670d8df48 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* e1000_82575 * e1000_82576 @@ -73,9 +70,8 @@ static s32 igb_validate_nvm_checksum_82580(struct e1000_hw *hw); static s32 igb_update_nvm_checksum_82580(struct e1000_hw *hw); static s32 igb_validate_nvm_checksum_i350(struct e1000_hw *hw); static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw); -static const u16 e1000_82580_rxpbs_table[] = - { 36, 72, 144, 1, 2, 4, 8, 16, - 35, 70, 140 }; +static const u16 e1000_82580_rxpbs_table[] = { + 36, 72, 144, 1, 2, 4, 8, 16, 35, 70, 140 }; /** * igb_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO @@ -526,7 +522,7 @@ static s32 igb_set_sfp_media_type_82575(struct e1000_hw *hw) static s32 igb_get_invariants_82575(struct e1000_hw *hw) { struct e1000_mac_info *mac = &hw->mac; - struct e1000_dev_spec_82575 * dev_spec = &hw->dev_spec._82575; + struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575; s32 ret_val; u32 ctrl_ext = 0; u32 link_mode = 0; @@ -1180,8 +1176,8 @@ static void igb_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask) { u32 swfw_sync; - while (igb_get_hw_semaphore(hw) != 0); - /* Empty */ + while (igb_get_hw_semaphore(hw) != 0) + ; /* Empty */ swfw_sync = rd32(E1000_SW_FW_SYNC); swfw_sync &= ~mask; @@ -1216,7 +1212,7 @@ static s32 igb_get_cfg_done_82575(struct e1000_hw *hw) while (timeout) { if (rd32(E1000_EEMNGCTL) & mask) break; - msleep(1); + usleep_range(1000, 2000); timeout--; } if (!timeout) @@ -1269,7 +1265,7 @@ static s32 igb_check_for_link_82575(struct e1000_hw *hw) if (hw->phy.media_type != e1000_media_type_copper) { ret_val = igb_get_pcs_speed_and_duplex_82575(hw, &speed, - &duplex); + &duplex); /* Use this flag to determine if link needs to be checked or * not. If we have link clear the flag so that we do not * continue to check for link. @@ -1316,7 +1312,7 @@ void igb_power_up_serdes_link_82575(struct e1000_hw *hw) /* flush the write to verify completion */ wrfl(); - msleep(1); + usleep_range(1000, 2000); } /** @@ -1411,7 +1407,7 @@ void igb_shutdown_serdes_link_82575(struct e1000_hw *hw) /* flush the write to verify completion */ wrfl(); - msleep(1); + usleep_range(1000, 2000); } } @@ -1436,9 +1432,8 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw) /* set the completion timeout for interface */ ret_val = igb_set_pcie_completion_timeout(hw); - if (ret_val) { + if (ret_val) hw_dbg("PCI-E Set completion timeout has failed.\n"); - } hw_dbg("Masking off all interrupts\n"); wr32(E1000_IMC, 0xffffffff); @@ -1447,7 +1442,7 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw) wr32(E1000_TCTL, E1000_TCTL_PSP); wrfl(); - msleep(10); + usleep_range(10000, 20000); ctrl = rd32(E1000_CTRL); @@ -1676,7 +1671,7 @@ static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw) hw->mac.type == e1000_82576) { ret_val = hw->nvm.ops.read(hw, NVM_COMPAT, 1, &data); if (ret_val) { - printk(KERN_DEBUG "NVM Read Error\n\n"); + hw_dbg(KERN_DEBUG "NVM Read Error\n\n"); return ret_val; } @@ -1689,7 +1684,7 @@ static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw) * link either autoneg or be forced to 1000/Full */ ctrl_reg |= E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD | - E1000_CTRL_FD | E1000_CTRL_FRCDPX; + E1000_CTRL_FD | E1000_CTRL_FRCDPX; /* set speed of 1000/Full if speed/duplex is forced */ reg |= E1000_PCS_LCTL_FSV_1000 | E1000_PCS_LCTL_FDV_FULL; @@ -1925,7 +1920,7 @@ void igb_rx_fifo_flush_82575(struct e1000_hw *hw) } /* Poll all queues to verify they have shut down */ for (ms_wait = 0; ms_wait < 10; ms_wait++) { - msleep(1); + usleep_range(1000, 2000); rx_enabled = 0; for (i = 0; i < 4; i++) rx_enabled |= rd32(E1000_RXDCTL(i)); @@ -1953,7 +1948,7 @@ void igb_rx_fifo_flush_82575(struct e1000_hw *hw) wr32(E1000_RCTL, temp_rctl); wr32(E1000_RCTL, temp_rctl | E1000_RCTL_EN); wrfl(); - msleep(2); + usleep_range(2000, 3000); /* Enable RX queues that were previously enabled and restore our * previous state @@ -2005,14 +2000,14 @@ static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw) * 16ms to 55ms */ ret_val = igb_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2, - &pcie_devctl2); + &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); + &pcie_devctl2); out: /* disable completion timeout resend */ gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND; @@ -2241,7 +2236,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw) wr32(E1000_TCTL, E1000_TCTL_PSP); wrfl(); - msleep(10); + usleep_range(10000, 11000); /* Determine whether or not a global dev reset is requested */ if (global_device_reset && @@ -2259,7 +2254,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw) /* Add delay to insure DEV_RST has time to complete */ if (global_device_reset) - msleep(5); + usleep_range(5000, 6000); ret_val = igb_get_auto_rd_done(hw); if (ret_val) { @@ -2436,8 +2431,7 @@ static s32 igb_update_nvm_checksum_82580(struct e1000_hw *hw) ret_val = hw->nvm.ops.read(hw, NVM_COMPATIBILITY_REG_3, 1, &nvm_data); if (ret_val) { - hw_dbg("NVM Read Error while updating checksum" - " compatibility bit.\n"); + hw_dbg("NVM Read Error while updating checksum compatibility bit.\n"); goto out; } @@ -2447,8 +2441,7 @@ static s32 igb_update_nvm_checksum_82580(struct e1000_hw *hw) ret_val = hw->nvm.ops.write(hw, NVM_COMPATIBILITY_REG_3, 1, &nvm_data); if (ret_val) { - hw_dbg("NVM Write Error while updating checksum" - " compatibility bit.\n"); + hw_dbg("NVM Write Error while updating checksum compatibility bit.\n"); goto out; } } diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h index 09d78be7241656..b407c55738fadf 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.h +++ b/drivers/net/ethernet/intel/igb/e1000_82575.h @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_82575_H_ #define _E1000_82575_H_ @@ -37,9 +34,9 @@ s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset, u8 dev_addr, u8 data); #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)) + (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 @@ -67,16 +64,16 @@ s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset, u8 dev_addr, #define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000 #define E1000_EICR_TX_QUEUE ( \ - E1000_EICR_TX_QUEUE0 | \ - E1000_EICR_TX_QUEUE1 | \ - E1000_EICR_TX_QUEUE2 | \ - E1000_EICR_TX_QUEUE3) + E1000_EICR_TX_QUEUE0 | \ + E1000_EICR_TX_QUEUE1 | \ + E1000_EICR_TX_QUEUE2 | \ + E1000_EICR_TX_QUEUE3) #define E1000_EICR_RX_QUEUE ( \ - E1000_EICR_RX_QUEUE0 | \ - E1000_EICR_RX_QUEUE1 | \ - E1000_EICR_RX_QUEUE2 | \ - E1000_EICR_RX_QUEUE3) + E1000_EICR_RX_QUEUE0 | \ + E1000_EICR_RX_QUEUE1 | \ + E1000_EICR_RX_QUEUE2 | \ + E1000_EICR_RX_QUEUE3) /* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */ #define E1000_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */ @@ -92,8 +89,7 @@ union e1000_adv_rx_desc { struct { struct { __le16 pkt_info; /* RSS type, Packet type */ - __le16 hdr_info; /* Split Header, - * header buffer length */ + __le16 hdr_info; /* Split Head, buf len */ } lo_dword; union { __le32 rss; /* RSS Hash */ diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h index b05bf925ac7219..f85be6695e4485 100644 --- a/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/drivers/net/ethernet/intel/igb/e1000_defines.h @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_DEFINES_H_ #define _E1000_DEFINES_H_ @@ -101,11 +98,11 @@ /* Same mask, but for extended and packet split descriptors */ #define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \ - E1000_RXDEXT_STATERR_CE | \ - E1000_RXDEXT_STATERR_SE | \ - E1000_RXDEXT_STATERR_SEQ | \ - E1000_RXDEXT_STATERR_CXE | \ - E1000_RXDEXT_STATERR_RXE) + E1000_RXDEXT_STATERR_CE | \ + E1000_RXDEXT_STATERR_SE | \ + E1000_RXDEXT_STATERR_SEQ | \ + E1000_RXDEXT_STATERR_CXE | \ + E1000_RXDEXT_STATERR_RXE) #define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 #define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 @@ -307,33 +304,25 @@ #define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ /* DMA Coalescing register fields */ -#define E1000_DMACR_DMACWT_MASK 0x00003FFF /* DMA Coalescing - * Watchdog Timer */ -#define E1000_DMACR_DMACTHR_MASK 0x00FF0000 /* DMA Coalescing Receive - * Threshold */ +#define E1000_DMACR_DMACWT_MASK 0x00003FFF /* DMA Coal Watchdog Timer */ +#define E1000_DMACR_DMACTHR_MASK 0x00FF0000 /* DMA Coal Rx Threshold */ #define E1000_DMACR_DMACTHR_SHIFT 16 -#define E1000_DMACR_DMAC_LX_MASK 0x30000000 /* Lx when no PCIe - * transactions */ +#define E1000_DMACR_DMAC_LX_MASK 0x30000000 /* Lx when no PCIe trans */ #define E1000_DMACR_DMAC_LX_SHIFT 28 #define E1000_DMACR_DMAC_EN 0x80000000 /* Enable DMA Coalescing */ /* DMA Coalescing BMC-to-OS Watchdog Enable */ #define E1000_DMACR_DC_BMC2OSW_EN 0x00008000 -#define E1000_DMCTXTH_DMCTTHR_MASK 0x00000FFF /* DMA Coalescing Transmit - * Threshold */ +#define E1000_DMCTXTH_DMCTTHR_MASK 0x00000FFF /* DMA Coal Tx Threshold */ #define E1000_DMCTLX_TTLX_MASK 0x00000FFF /* Time to LX request */ -#define E1000_DMCRTRH_UTRESH_MASK 0x0007FFFF /* Receive Traffic Rate - * Threshold */ -#define E1000_DMCRTRH_LRPRCW 0x80000000 /* Rcv packet rate in - * current window */ +#define E1000_DMCRTRH_UTRESH_MASK 0x0007FFFF /* Rx Traffic Rate Thresh */ +#define E1000_DMCRTRH_LRPRCW 0x80000000 /* Rx pkt rate curr window */ -#define E1000_DMCCNT_CCOUNT_MASK 0x01FFFFFF /* DMA Coal Rcv Traffic - * Current Cnt */ +#define E1000_DMCCNT_CCOUNT_MASK 0x01FFFFFF /* DMA Coal Rx Current Cnt */ -#define E1000_FCRTC_RTH_COAL_MASK 0x0003FFF0 /* Flow ctrl Rcv Threshold - * High val */ +#define E1000_FCRTC_RTH_COAL_MASK 0x0003FFF0 /* FC Rx Thresh High val */ #define E1000_FCRTC_RTH_COAL_SHIFT 4 #define E1000_PCIEMISC_LX_DECISION 0x00000080 /* Lx power decision */ @@ -406,12 +395,12 @@ * o LSC = Link Status Change */ #define IMS_ENABLE_MASK ( \ - E1000_IMS_RXT0 | \ - E1000_IMS_TXDW | \ - E1000_IMS_RXDMT0 | \ - E1000_IMS_RXSEQ | \ - E1000_IMS_LSC | \ - E1000_IMS_DOUTSYNC) + E1000_IMS_RXT0 | \ + E1000_IMS_TXDW | \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ | \ + E1000_IMS_LSC | \ + E1000_IMS_DOUTSYNC) /* Interrupt Mask Set */ #define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1011,8 +1000,7 @@ #define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F /* DMA Coalescing register fields */ -#define E1000_PCIEMISC_LX_DECISION 0x00000080 /* Lx power decision based - on DMA coal */ +#define E1000_PCIEMISC_LX_DECISION 0x00000080 /* Lx power on DMA coal */ /* Tx Rate-Scheduler Config fields */ #define E1000_RTTBCNRC_RS_ENA 0x80000000 diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h index 10741d170f2dda..89925e4058498e 100644 --- a/drivers/net/ethernet/intel/igb/e1000_hw.h +++ b/drivers/net/ethernet/intel/igb/e1000_hw.h @@ -1,28 +1,24 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_HW_H_ #define _E1000_HW_H_ @@ -320,15 +316,15 @@ struct e1000_host_mng_command_info { #include "e1000_mbx.h" struct e1000_mac_operations { - s32 (*check_for_link)(struct e1000_hw *); - s32 (*reset_hw)(struct e1000_hw *); - s32 (*init_hw)(struct e1000_hw *); + s32 (*check_for_link)(struct e1000_hw *); + s32 (*reset_hw)(struct e1000_hw *); + s32 (*init_hw)(struct e1000_hw *); bool (*check_mng_mode)(struct e1000_hw *); - s32 (*setup_physical_interface)(struct e1000_hw *); + s32 (*setup_physical_interface)(struct e1000_hw *); void (*rar_set)(struct e1000_hw *, u8 *, u32); - s32 (*read_mac_addr)(struct e1000_hw *); - s32 (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *); - s32 (*acquire_swfw_sync)(struct e1000_hw *, u16); + s32 (*read_mac_addr)(struct e1000_hw *); + s32 (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *); + s32 (*acquire_swfw_sync)(struct e1000_hw *, u16); void (*release_swfw_sync)(struct e1000_hw *, u16); #ifdef CONFIG_IGB_HWMON s32 (*get_thermal_sensor_data)(struct e1000_hw *); @@ -338,31 +334,31 @@ struct e1000_mac_operations { }; struct e1000_phy_operations { - s32 (*acquire)(struct e1000_hw *); - s32 (*check_polarity)(struct e1000_hw *); - s32 (*check_reset_block)(struct e1000_hw *); - s32 (*force_speed_duplex)(struct e1000_hw *); - s32 (*get_cfg_done)(struct e1000_hw *hw); - s32 (*get_cable_length)(struct e1000_hw *); - s32 (*get_phy_info)(struct e1000_hw *); - s32 (*read_reg)(struct e1000_hw *, u32, u16 *); + s32 (*acquire)(struct e1000_hw *); + s32 (*check_polarity)(struct e1000_hw *); + s32 (*check_reset_block)(struct e1000_hw *); + s32 (*force_speed_duplex)(struct e1000_hw *); + s32 (*get_cfg_done)(struct e1000_hw *hw); + s32 (*get_cable_length)(struct e1000_hw *); + s32 (*get_phy_info)(struct e1000_hw *); + s32 (*read_reg)(struct e1000_hw *, u32, u16 *); void (*release)(struct e1000_hw *); - s32 (*reset)(struct e1000_hw *); - s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); - s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); - s32 (*write_reg)(struct e1000_hw *, u32, u16); + s32 (*reset)(struct e1000_hw *); + s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); + s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); + s32 (*write_reg)(struct e1000_hw *, u32, u16); s32 (*read_i2c_byte)(struct e1000_hw *, u8, u8, u8 *); s32 (*write_i2c_byte)(struct e1000_hw *, u8, u8, u8); }; struct e1000_nvm_operations { - s32 (*acquire)(struct e1000_hw *); - s32 (*read)(struct e1000_hw *, u16, u16, u16 *); + s32 (*acquire)(struct e1000_hw *); + s32 (*read)(struct e1000_hw *, u16, u16, u16 *); void (*release)(struct e1000_hw *); - s32 (*write)(struct e1000_hw *, u16, u16, u16 *); - s32 (*update)(struct e1000_hw *); - s32 (*validate)(struct e1000_hw *); - s32 (*valid_led_default)(struct e1000_hw *, u16 *); + s32 (*write)(struct e1000_hw *, u16, u16, u16 *); + s32 (*update)(struct e1000_hw *); + s32 (*validate)(struct e1000_hw *); + s32 (*valid_led_default)(struct e1000_hw *, u16 *); }; #define E1000_MAX_SENSORS 3 diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c index f67f8a170b90c8..2231598fb42d12 100644 --- a/drivers/net/ethernet/intel/igb/e1000_i210.c +++ b/drivers/net/ethernet/intel/igb/e1000_i210.c @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* e1000_i210 * e1000_i211 @@ -435,6 +432,7 @@ static s32 igb_read_invm_i210(struct e1000_hw *hw, u16 offset, *data = ID_LED_RESERVED_FFFF; ret_val = E1000_SUCCESS; } + break; case NVM_SUB_DEV_ID: *data = hw->subsystem_device_id; break; diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.h b/drivers/net/ethernet/intel/igb/e1000_i210.h index 907fe99a981313..9f34976687baed 100644 --- a/drivers/net/ethernet/intel/igb/e1000_i210.h +++ b/drivers/net/ethernet/intel/igb/e1000_i210.h @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_I210_H_ #define _E1000_I210_H_ diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c index 1e0c404db81a26..2a88595f956cf4 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mac.c +++ b/drivers/net/ethernet/intel/igb/e1000_mac.c @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include #include @@ -442,7 +439,7 @@ static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) * 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) + u8 *mc_addr_list, u32 mc_addr_count) { u32 hash_value, hash_bit, hash_reg; int i; @@ -866,8 +863,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) goto out; if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { - hw_dbg("Copper PHY and Auto Neg " - "has not completed.\n"); + hw_dbg("Copper PHY and Auto Neg has not completed.\n"); goto out; } @@ -1265,7 +1261,7 @@ s32 igb_get_auto_rd_done(struct e1000_hw *hw) while (i < AUTO_READ_DONE_TIMEOUT) { if (rd32(E1000_EECD) & E1000_EECD_AUTO_RD) break; - msleep(1); + usleep_range(1000, 2000); i++; } @@ -1298,7 +1294,7 @@ static s32 igb_valid_led_default(struct e1000_hw *hw, u16 *data) } if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) { - switch(hw->phy.media_type) { + switch (hw->phy.media_type) { case e1000_media_type_internal_serdes: *data = ID_LED_DEFAULT_82575_SERDES; break; diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.h b/drivers/net/ethernet/intel/igb/e1000_mac.h index 99299ba8ee3a2d..ea24961b0d705e 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mac.h +++ b/drivers/net/ethernet/intel/igb/e1000_mac.h @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_MAC_H_ #define _E1000_MAC_H_ diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.c b/drivers/net/ethernet/intel/igb/e1000_mbx.c index d5b121771c3137..162cc49345d09b 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mbx.c +++ b/drivers/net/ethernet/intel/igb/e1000_mbx.c @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include "e1000_mbx.h" diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.h b/drivers/net/ethernet/intel/igb/e1000_mbx.h index f52f5515e5a8a8..d20af6b2f58169 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mbx.h +++ b/drivers/net/ethernet/intel/igb/e1000_mbx.h @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_MBX_H_ #define _E1000_MBX_H_ diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c index 9abf82919c6553..92bcdbe756b202 100644 --- a/drivers/net/ethernet/intel/igb/e1000_nvm.c +++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c @@ -1,28 +1,24 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include #include @@ -480,6 +476,7 @@ s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) /* Loop to allow for up to whole page write of eeprom */ while (widx < words) { u16 word_out = data[widx]; + word_out = (word_out >> 8) | (word_out << 8); igb_shift_out_eec_bits(hw, word_out, 16); widx++; diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.h b/drivers/net/ethernet/intel/igb/e1000_nvm.h index 5b101170b17e4b..febc9cdb739125 100644 --- a/drivers/net/ethernet/intel/igb/e1000_nvm.h +++ b/drivers/net/ethernet/intel/igb/e1000_nvm.h @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_NVM_H_ #define _E1000_NVM_H_ @@ -32,7 +29,7 @@ void igb_release_nvm(struct e1000_hw *hw); s32 igb_read_mac_addr(struct e1000_hw *hw); s32 igb_read_part_num(struct e1000_hw *hw, u32 *part_num); s32 igb_read_part_string(struct e1000_hw *hw, u8 *part_num, - u32 part_num_size); + u32 part_num_size); s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); s32 igb_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c index 4009bbab7407d2..424f16c43759b1 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.c +++ b/drivers/net/ethernet/intel/igb/e1000_phy.c @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include #include @@ -924,8 +921,7 @@ static s32 igb_copper_link_autoneg(struct e1000_hw *hw) if (phy->autoneg_wait_to_complete) { ret_val = igb_wait_autoneg(hw); if (ret_val) { - hw_dbg("Error while waiting for " - "autoneg to complete\n"); + hw_dbg("Error while waiting for autoneg to complete\n"); goto out; } } @@ -2244,7 +2240,7 @@ void igb_power_down_phy_copper(struct e1000_hw *hw) hw->phy.ops.write_reg(hw, GS40G_COPPER_SPEC, power_reg); } hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); - msleep(1); + usleep_range(1000, 2000); } /** diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h index 4c2c36c46a7398..fe921e29dda8f9 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.h +++ b/drivers/net/ethernet/intel/igb/e1000_phy.h @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_PHY_H_ #define _E1000_PHY_H_ diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h index bdb246e848e13b..833bbb948d9709 100644 --- a/drivers/net/ethernet/intel/igb/e1000_regs.h +++ b/drivers/net/ethernet/intel/igb/e1000_regs.h @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_REGS_H_ #define _E1000_REGS_H_ @@ -301,9 +298,9 @@ #define E1000_RA2 0x054E0 /* 2nd half of Rx address array - RW Array */ #define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4)) #define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \ - (0x054E0 + ((_i - 16) * 8))) + (0x054E0 + ((_i - 16) * 8))) #define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \ - (0x054E4 + ((_i - 16) * 8))) + (0x054E4 + ((_i - 16) * 8))) #define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8)) #define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4)) #define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4)) @@ -358,8 +355,7 @@ #define E1000_VMBMEM(_n) (0x00800 + (64 * (_n))) #define E1000_VMOLR(_n) (0x05AD0 + (4 * (_n))) #define E1000_DVMOLR(_n) (0x0C038 + (64 * (_n))) -#define E1000_VLVF(_n) (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine - * Filter - RW */ +#define E1000_VLVF(_n) (0x05D00 + (4 * (_n))) /* VLAN VM Filter */ #define E1000_VMVIR(_n) (0x03700 + (4 * (_n))) struct e1000_hw; diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 27130065d92a70..06102d1f7c0362 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -1,29 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* Linux PRO/1000 Ethernet Driver main header file */ @@ -198,6 +194,7 @@ struct igb_tx_buffer { unsigned int bytecount; u16 gso_segs; __be16 protocol; + DEFINE_DMA_UNMAP_ADDR(dma); DEFINE_DMA_UNMAP_LEN(len); u32 tx_flags; diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index e5570acbeea845..333a2b0bbada8c 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* ethtool support for igb */ @@ -286,7 +283,7 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) } while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; @@ -399,7 +396,7 @@ static int igb_set_pauseparam(struct net_device *netdev, adapter->fc_autoneg = pause->autoneg; while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (adapter->fc_autoneg == AUTONEG_ENABLE) { hw->fc.requested_mode = e1000_fc_default; @@ -886,7 +883,7 @@ static int igb_set_ringparam(struct net_device *netdev, } while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (!netif_running(adapter->netdev)) { for (i = 0; i < adapter->num_tx_queues; i++) @@ -1060,8 +1057,8 @@ static struct igb_reg_test reg_test_i350[] = { { E1000_TDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, { E1000_TDT(4), 0x40, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, - { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, - { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, { E1000_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, { E1000_RA, 0, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, @@ -1103,8 +1100,8 @@ static struct igb_reg_test reg_test_82580[] = { { E1000_TDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, { E1000_TDT(4), 0x40, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, - { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, - { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, { E1000_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, { E1000_RA, 0, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, @@ -1132,8 +1129,10 @@ static struct igb_reg_test reg_test_82576[] = { { E1000_RDBAH(4), 0x40, 12, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, { E1000_RDLEN(4), 0x40, 12, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, /* Enable all RX queues before testing. */ - { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE }, - { E1000_RXDCTL(4), 0x40, 12, WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE }, + { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, + E1000_RXDCTL_QUEUE_ENABLE }, + { E1000_RXDCTL(4), 0x40, 12, WRITE_NO_TEST, 0, + E1000_RXDCTL_QUEUE_ENABLE }, /* RDH is read-only for 82576, only test RDT. */ { E1000_RDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, { E1000_RDT(4), 0x40, 12, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, @@ -1149,14 +1148,14 @@ static struct igb_reg_test reg_test_82576[] = { { E1000_TDBAH(4), 0x40, 12, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, { E1000_TDLEN(4), 0x40, 12, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF }, { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, - { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, - { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, { E1000_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, { E1000_RA, 0, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, { E1000_RA, 0, 16, TABLE64_TEST_HI, 0x83FFFFFF, 0xFFFFFFFF }, { E1000_RA2, 0, 8, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, { E1000_RA2, 0, 8, TABLE64_TEST_HI, 0x83FFFFFF, 0xFFFFFFFF }, - { E1000_MTA, 0, 128,TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_MTA, 0, 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, { 0, 0, 0, 0 } }; @@ -1170,7 +1169,8 @@ static struct igb_reg_test reg_test_82575[] = { { E1000_RDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, { E1000_RDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, /* Enable all four RX queues before testing. */ - { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE }, + { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, + E1000_RXDCTL_QUEUE_ENABLE }, /* RDH is read-only for 82575, only test RDT. */ { E1000_RDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, { E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, 0 }, @@ -1196,8 +1196,8 @@ static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data, { struct e1000_hw *hw = &adapter->hw; u32 pat, val; - static const u32 _test[] = - {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; + static const u32 _test[] = { + 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; for (pat = 0; pat < ARRAY_SIZE(_test); pat++) { wr32(reg, (_test[pat] & write)); val = rd32(reg) & mask; @@ -1206,11 +1206,11 @@ static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data, "pattern test reg %04X failed: got 0x%08X expected 0x%08X\n", reg, val, (_test[pat] & write & mask)); *data = reg; - return 1; + return true; } } - return 0; + return false; } static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data, @@ -1218,17 +1218,18 @@ static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data, { struct e1000_hw *hw = &adapter->hw; u32 val; + wr32(reg, write & mask); val = rd32(reg); if ((write & mask) != (val & mask)) { dev_err(&adapter->pdev->dev, - "set/check reg %04X test failed: got 0x%08X expected 0x%08X\n", reg, - (val & mask), (write & mask)); + "set/check reg %04X test failed: got 0x%08X expected 0x%08X\n", + reg, (val & mask), (write & mask)); *data = reg; - return 1; + return true; } - return 0; + return false; } #define REG_PATTERN_TEST(reg, mask, write) \ @@ -1387,14 +1388,14 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) /* Hook up test interrupt handler just for this test */ if (adapter->flags & IGB_FLAG_HAS_MSIX) { if (request_irq(adapter->msix_entries[0].vector, - igb_test_intr, 0, netdev->name, adapter)) { + igb_test_intr, 0, netdev->name, adapter)) { *data = 1; return -1; } } else if (adapter->flags & IGB_FLAG_HAS_MSI) { shared_int = false; if (request_irq(irq, - igb_test_intr, 0, netdev->name, adapter)) { + igb_test_intr, 0, netdev->name, adapter)) { *data = 1; return -1; } @@ -1412,7 +1413,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) /* Disable all the interrupts */ wr32(E1000_IMC, ~0); wrfl(); - msleep(10); + usleep_range(10000, 11000); /* Define all writable bits for ICS */ switch (hw->mac.type) { @@ -1459,7 +1460,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) wr32(E1000_IMC, mask); wr32(E1000_ICS, mask); wrfl(); - msleep(10); + usleep_range(10000, 11000); if (adapter->test_icr & mask) { *data = 3; @@ -1481,7 +1482,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) wr32(E1000_IMS, mask); wr32(E1000_ICS, mask); wrfl(); - msleep(10); + usleep_range(10000, 11000); if (!(adapter->test_icr & mask)) { *data = 4; @@ -1503,7 +1504,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) wr32(E1000_IMC, ~mask); wr32(E1000_ICS, ~mask); wrfl(); - msleep(10); + usleep_range(10000, 11000); if (adapter->test_icr & mask) { *data = 5; @@ -1515,7 +1516,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) /* Disable all the interrupts */ wr32(E1000_IMC, ~0); wrfl(); - msleep(10); + usleep_range(10000, 11000); /* Unhook test interrupt handler */ if (adapter->flags & IGB_FLAG_HAS_MSIX) @@ -1949,6 +1950,7 @@ static int igb_link_test(struct igb_adapter *adapter, u64 *data) *data = 0; if (hw->phy.media_type == e1000_media_type_internal_serdes) { int i = 0; + hw->mac.serdes_has_link = false; /* On some blade server designs, link establishment @@ -2413,9 +2415,11 @@ static int igb_get_rss_hash_opts(struct igb_adapter *adapter, switch (cmd->flow_type) { case TCP_V4_FLOW: cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + /* Fall through */ case UDP_V4_FLOW: if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV4_UDP) cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + /* Fall through */ case SCTP_V4_FLOW: case AH_ESP_V4_FLOW: case AH_V4_FLOW: @@ -2425,9 +2429,11 @@ static int igb_get_rss_hash_opts(struct igb_adapter *adapter, break; case TCP_V6_FLOW: cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + /* Fall through */ case UDP_V6_FLOW: if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV6_UDP) cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + /* Fall through */ case SCTP_V6_FLOW: case AH_ESP_V6_FLOW: case AH_V6_FLOW: diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c index 8333f67acf96b3..44b6a68f1af727 100644 --- a/drivers/net/ethernet/intel/igb/igb_hwmon.c +++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include "igb.h" #include "e1000_82575.h" diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 16430a8440fa3c..bfcda8a455f46c 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1,28 +1,25 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2014 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope 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, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -75,7 +72,7 @@ static const struct e1000_info *igb_info_tbl[] = { [board_82575] = &e1000_82575_info, }; -static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = { +static const struct pci_device_id igb_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_1GBPS) }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_SGMII) }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_2_5GBPS) }, @@ -117,7 +114,6 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = { MODULE_DEVICE_TABLE(pci, igb_pci_tbl); -void igb_reset(struct igb_adapter *); static int igb_setup_all_tx_resources(struct igb_adapter *); static int igb_setup_all_rx_resources(struct igb_adapter *); static void igb_free_all_tx_resources(struct igb_adapter *); @@ -141,7 +137,7 @@ static void igb_watchdog(unsigned long); static void igb_watchdog_task(struct work_struct *); static netdev_tx_t igb_xmit_frame(struct sk_buff *skb, struct net_device *); static struct rtnl_link_stats64 *igb_get_stats64(struct net_device *dev, - struct rtnl_link_stats64 *stats); + struct rtnl_link_stats64 *stats); static int igb_change_mtu(struct net_device *, int); static int igb_set_mac(struct net_device *, void *); static void igb_set_uta(struct igb_adapter *adapter); @@ -159,7 +155,8 @@ static bool igb_clean_rx_irq(struct igb_q_vector *, int); static int igb_ioctl(struct net_device *, struct ifreq *, int cmd); static void igb_tx_timeout(struct net_device *); static void igb_reset_task(struct work_struct *); -static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features); +static void igb_vlan_mode(struct net_device *netdev, + netdev_features_t features); static int igb_vlan_rx_add_vid(struct net_device *, __be16, u16); static int igb_vlan_rx_kill_vid(struct net_device *, __be16, u16); static void igb_restore_vlan(struct igb_adapter *); @@ -215,10 +212,9 @@ static struct notifier_block dca_notifier = { static void igb_netpoll(struct net_device *); #endif #ifdef CONFIG_PCI_IOV -static unsigned int max_vfs = 0; +static unsigned int max_vfs; module_param(max_vfs, uint, 0); -MODULE_PARM_DESC(max_vfs, "Maximum number of virtual functions to allocate " - "per physical function"); +MODULE_PARM_DESC(max_vfs, "Maximum number of virtual functions to allocate per physical function"); #endif /* CONFIG_PCI_IOV */ static pci_ers_result_t igb_io_error_detected(struct pci_dev *, @@ -384,8 +380,7 @@ static void igb_dump(struct igb_adapter *adapter) /* Print netdevice Info */ if (netdev) { dev_info(&adapter->pdev->dev, "Net device Info\n"); - pr_info("Device Name state trans_start " - "last_rx\n"); + pr_info("Device Name state trans_start last_rx\n"); pr_info("%-15s %016lX %016lX %016lX\n", netdev->name, netdev->state, netdev->trans_start, netdev->last_rx); } @@ -438,9 +433,7 @@ static void igb_dump(struct igb_adapter *adapter) pr_info("------------------------------------\n"); pr_info("TX QUEUE INDEX = %d\n", tx_ring->queue_index); pr_info("------------------------------------\n"); - pr_info("T [desc] [address 63:0 ] [PlPOCIStDDM Ln] " - "[bi->dma ] leng ntw timestamp " - "bi->skb\n"); + pr_info("T [desc] [address 63:0 ] [PlPOCIStDDM Ln] [bi->dma ] leng ntw timestamp bi->skb\n"); for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) { const char *next_desc; @@ -458,9 +451,8 @@ static void igb_dump(struct igb_adapter *adapter) else next_desc = ""; - pr_info("T [0x%03X] %016llX %016llX %016llX" - " %04X %p %016llX %p%s\n", i, - le64_to_cpu(u0->a), + pr_info("T [0x%03X] %016llX %016llX %016llX %04X %p %016llX %p%s\n", + i, le64_to_cpu(u0->a), le64_to_cpu(u0->b), (u64)dma_unmap_addr(buffer_info, dma), dma_unmap_len(buffer_info, len), @@ -519,10 +511,8 @@ static void igb_dump(struct igb_adapter *adapter) pr_info("------------------------------------\n"); pr_info("RX QUEUE INDEX = %d\n", rx_ring->queue_index); pr_info("------------------------------------\n"); - pr_info("R [desc] [ PktBuf A0] [ HeadBuf DD] " - "[bi->dma ] [bi->skb] <-- Adv Rx Read format\n"); - pr_info("RWB[desc] [PcsmIpSHl PtRs] [vl er S cks ln] -----" - "----------- [bi->skb] <-- Adv Rx Write-Back format\n"); + pr_info("R [desc] [ PktBuf A0] [ HeadBuf DD] [bi->dma ] [bi->skb] <-- Adv Rx Read format\n"); + pr_info("RWB[desc] [PcsmIpSHl PtRs] [vl er S cks ln] ---------------- [bi->skb] <-- Adv Rx Write-Back format\n"); for (i = 0; i < rx_ring->count; i++) { const char *next_desc; @@ -584,7 +574,7 @@ static int igb_get_i2c_data(void *data) struct e1000_hw *hw = &adapter->hw; s32 i2cctl = rd32(E1000_I2CPARAMS); - return ((i2cctl & E1000_I2C_DATA_IN) != 0); + return !!(i2cctl & E1000_I2C_DATA_IN); } /** @@ -648,7 +638,7 @@ static int igb_get_i2c_clk(void *data) struct e1000_hw *hw = &adapter->hw; s32 i2cctl = rd32(E1000_I2CPARAMS); - return ((i2cctl & E1000_I2C_CLK_IN) != 0); + return !!(i2cctl & E1000_I2C_CLK_IN); } static const struct i2c_algo_bit_data igb_i2c_algo = { @@ -681,9 +671,9 @@ struct net_device *igb_get_hw_dev(struct e1000_hw *hw) static int __init igb_init_module(void) { int ret; + pr_info("%s - version %s\n", igb_driver_string, igb_driver_version); - pr_info("%s\n", igb_copyright); #ifdef CONFIG_IGB_DCA @@ -736,12 +726,14 @@ static void igb_cache_ring_register(struct igb_adapter *adapter) adapter->rx_ring[i]->reg_idx = rbase_offset + Q_IDX_82576(i); } + /* Fall through */ case e1000_82575: case e1000_82580: case e1000_i350: case e1000_i354: case e1000_i210: case e1000_i211: + /* Fall through */ default: for (; i < adapter->num_rx_queues; i++) adapter->rx_ring[i]->reg_idx = rbase_offset + i; @@ -1292,8 +1284,7 @@ static int igb_alloc_q_vector(struct igb_adapter *adapter, if (adapter->hw.mac.type >= e1000_82576) set_bit(IGB_RING_FLAG_RX_SCTP_CSUM, &ring->flags); - /* - * On i350, i354, i210, and i211, loopback VLAN packets + /* On i350, i354, i210, and i211, loopback VLAN packets * have the tag byte-swapped. */ if (adapter->hw.mac.type >= e1000_i350) @@ -1345,6 +1336,7 @@ static int igb_alloc_q_vectors(struct igb_adapter *adapter) for (; v_idx < q_vectors; v_idx++) { int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - v_idx); int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - v_idx); + err = igb_alloc_q_vector(adapter, q_vectors, v_idx, tqpv, txr_idx, rqpv, rxr_idx); @@ -1484,6 +1476,7 @@ static void igb_irq_disable(struct igb_adapter *adapter) */ if (adapter->flags & IGB_FLAG_HAS_MSIX) { u32 regval = rd32(E1000_EIAM); + wr32(E1000_EIAM, regval & ~adapter->eims_enable_mask); wr32(E1000_EIMC, adapter->eims_enable_mask); regval = rd32(E1000_EIAC); @@ -1495,6 +1488,7 @@ static void igb_irq_disable(struct igb_adapter *adapter) wrfl(); if (adapter->flags & IGB_FLAG_HAS_MSIX) { int i; + for (i = 0; i < adapter->num_q_vectors; i++) synchronize_irq(adapter->msix_entries[i].vector); } else { @@ -1513,6 +1507,7 @@ static void igb_irq_enable(struct igb_adapter *adapter) if (adapter->flags & IGB_FLAG_HAS_MSIX) { u32 ims = E1000_IMS_LSC | E1000_IMS_DOUTSYNC | E1000_IMS_DRSTA; 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); @@ -1745,6 +1740,7 @@ int igb_up(struct igb_adapter *adapter) /* notify VFs that reset has been completed */ if (adapter->vfs_allocated_count) { u32 reg_data = rd32(E1000_CTRL_EXT); + reg_data |= E1000_CTRL_EXT_PFRSTD; wr32(E1000_CTRL_EXT, reg_data); } @@ -1787,7 +1783,7 @@ void igb_down(struct igb_adapter *adapter) wr32(E1000_TCTL, tctl); /* flush both disables and wait for them to finish */ wrfl(); - msleep(10); + usleep_range(10000, 11000); igb_irq_disable(adapter); @@ -1827,7 +1823,7 @@ void igb_reinit_locked(struct igb_adapter *adapter) { WARN_ON(in_interrupt()); while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); igb_down(adapter); igb_up(adapter); clear_bit(__IGB_RESETTING, &adapter->state); @@ -1960,6 +1956,7 @@ void igb_reset(struct igb_adapter *adapter) /* disable receive for all VFs and wait one second */ if (adapter->vfs_allocated_count) { int i; + for (i = 0 ; i < adapter->vfs_allocated_count; i++) adapter->vf_data[i].flags &= IGB_VF_FLAG_PF_SET_MAC; @@ -2529,7 +2526,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* let the f/w know that the h/w is now under the control of the - * driver. */ + * driver. + */ igb_get_hw_control(adapter); strcpy(netdev->name, "eth%d"); @@ -3077,6 +3075,7 @@ static int __igb_open(struct net_device *netdev, bool resuming) /* notify VFs that reset has been completed */ if (adapter->vfs_allocated_count) { u32 reg_data = rd32(E1000_CTRL_EXT); + reg_data |= E1000_CTRL_EXT_PFRSTD; wr32(E1000_CTRL_EXT, reg_data); } @@ -3248,7 +3247,7 @@ void igb_setup_tctl(struct igb_adapter *adapter) * Configure a transmit ring after a reset. **/ void igb_configure_tx_ring(struct igb_adapter *adapter, - struct igb_ring *ring) + struct igb_ring *ring) { struct e1000_hw *hw = &adapter->hw; u32 txdctl = 0; @@ -3389,7 +3388,8 @@ static void igb_setup_mrqc(struct igb_adapter *adapter) if (adapter->rss_indir_tbl_init != num_rx_queues) { for (j = 0; j < IGB_RETA_SIZE; j++) - adapter->rss_indir_tbl[j] = (j * num_rx_queues) / IGB_RETA_SIZE; + adapter->rss_indir_tbl[j] = + (j * num_rx_queues) / IGB_RETA_SIZE; adapter->rss_indir_tbl_init = num_rx_queues; } igb_write_rss_indir_tbl(adapter); @@ -3430,6 +3430,7 @@ static void igb_setup_mrqc(struct igb_adapter *adapter) if (hw->mac.type > e1000_82575) { /* Set the default pool for the PF's first queue */ u32 vtctl = rd32(E1000_VT_CTL); + vtctl &= ~(E1000_VT_CTL_DEFAULT_POOL_MASK | E1000_VT_CTL_DISABLE_DEF_POOL); vtctl |= adapter->vfs_allocated_count << @@ -3511,7 +3512,7 @@ void igb_setup_rctl(struct igb_adapter *adapter) } static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size, - int vfn) + int vfn) { struct e1000_hw *hw = &adapter->hw; u32 vmolr; @@ -4058,7 +4059,8 @@ static void igb_check_wvbr(struct igb_adapter *adapter) switch (hw->mac.type) { case e1000_82576: case e1000_i350: - if (!(wvbr = rd32(E1000_WVBR))) + wvbr = rd32(E1000_WVBR); + if (!wvbr) return; break; default: @@ -4077,7 +4079,7 @@ static void igb_spoof_check(struct igb_adapter *adapter) if (!adapter->wvbr) return; - for(j = 0; j < adapter->vfs_allocated_count; j++) { + for (j = 0; j < adapter->vfs_allocated_count; j++) { if (adapter->wvbr & (1 << j) || adapter->wvbr & (1 << (j + IGB_STAGGERED_QUEUE_OFFSET))) { dev_warn(&adapter->pdev->dev, @@ -4209,14 +4211,15 @@ static void igb_watchdog_task(struct work_struct *work) if (!netif_carrier_ok(netdev)) { u32 ctrl; + hw->mac.ops.get_speed_and_duplex(hw, &adapter->link_speed, &adapter->link_duplex); ctrl = rd32(E1000_CTRL); /* Links status message must follow this format */ - printk(KERN_INFO "igb: %s NIC Link is Up %d Mbps %s " - "Duplex, Flow Control: %s\n", + netdev_info(netdev, + "igb: %s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n", netdev->name, adapter->link_speed, adapter->link_duplex == FULL_DUPLEX ? @@ -4242,11 +4245,8 @@ static void igb_watchdog_task(struct work_struct *work) /* check for thermal sensor event */ if (igb_thermal_sensor_event(hw, - E1000_THSTAT_LINK_THROTTLE)) { - netdev_info(netdev, "The network adapter link " - "speed was downshifted because it " - "overheated\n"); - } + E1000_THSTAT_LINK_THROTTLE)) + netdev_info(netdev, "The network adapter link speed was downshifted because it overheated\n"); /* adjust timeout factor according to speed/duplex */ adapter->tx_timeout_factor = 1; @@ -4277,12 +4277,11 @@ static void igb_watchdog_task(struct work_struct *work) /* check for thermal sensor event */ if (igb_thermal_sensor_event(hw, E1000_THSTAT_PWR_DOWN)) { - netdev_err(netdev, "The network adapter was " - "stopped because it overheated\n"); + netdev_err(netdev, "The network adapter was stopped because it overheated\n"); } /* Links status message must follow this format */ - printk(KERN_INFO "igb: %s NIC Link is Down\n", + netdev_info(netdev, "igb: %s NIC Link is Down\n", netdev->name); netif_carrier_off(netdev); @@ -4344,6 +4343,7 @@ static void igb_watchdog_task(struct work_struct *work) /* Cause software interrupt to ensure Rx ring is cleaned */ if (adapter->flags & IGB_FLAG_HAS_MSIX) { u32 eics = 0; + for (i = 0; i < adapter->num_q_vectors; i++) eics |= adapter->q_vector[i]->eims_value; wr32(E1000_EICS, eics); @@ -4483,13 +4483,12 @@ static void igb_update_itr(struct igb_q_vector *q_vector, case low_latency: /* 50 usec aka 20000 ints/s */ if (bytes > 10000) { /* this if handles the TSO accounting */ - if (bytes/packets > 8000) { + if (bytes/packets > 8000) itrval = bulk_latency; - } else if ((packets < 10) || ((bytes/packets) > 1200)) { + else if ((packets < 10) || ((bytes/packets) > 1200)) itrval = bulk_latency; - } else if ((packets > 35)) { + else if ((packets > 35)) itrval = lowest_latency; - } } else if (bytes/packets > 2000) { itrval = bulk_latency; } else if (packets <= 2 && bytes < 512) { @@ -4675,6 +4674,7 @@ static void igb_tx_csum(struct igb_ring *tx_ring, struct igb_tx_buffer *first) return; } else { u8 l4_hdr = 0; + switch (first->protocol) { case htons(ETH_P_IP): vlan_macip_lens |= skb_network_header_len(skb); @@ -4962,6 +4962,7 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, */ if (NETDEV_FRAG_PAGE_MAX_SIZE > IGB_MAX_DATA_PER_TXD) { unsigned short f; + for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size); } else { @@ -5140,7 +5141,7 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu) max_frame = ETH_FRAME_LEN + ETH_FCS_LEN; while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); /* igb_down has a dependency on max_frame_size */ adapter->max_frame_size = max_frame; @@ -5621,6 +5622,7 @@ static int igb_set_vf_promisc(struct igb_adapter *adapter, u32 *msgbuf, u32 vf) vmolr |= E1000_VMOLR_MPME; } else if (vf_data->num_vf_mc_hashes) { int j; + vmolr |= E1000_VMOLR_ROMPE; for (j = 0; j < vf_data->num_vf_mc_hashes; j++) igb_mta_set(hw, vf_data->vf_mc_hashes[j]); @@ -5672,6 +5674,7 @@ static void igb_restore_vf_multicasts(struct igb_adapter *adapter) for (i = 0; i < adapter->vfs_allocated_count; i++) { u32 vmolr = rd32(E1000_VMOLR(i)); + vmolr &= ~(E1000_VMOLR_ROMPE | E1000_VMOLR_MPME); vf_data = &adapter->vf_data[i]; @@ -5770,6 +5773,7 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf) if (!adapter->vf_data[vf].vlans_enabled) { u32 size; + reg = rd32(E1000_VMOLR(vf)); size = reg & E1000_VMOLR_RLPML_MASK; size += 4; @@ -5798,6 +5802,7 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf) 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; @@ -5902,8 +5907,8 @@ static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf) */ if (!add && (adapter->netdev->flags & IFF_PROMISC)) { u32 vlvf, bits; - int regndx = igb_find_vlvf_entry(adapter, vid); + if (regndx < 0) goto out; /* See if any other pools are set for this VLAN filter @@ -6494,7 +6499,7 @@ static void igb_reuse_rx_page(struct igb_ring *rx_ring, rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0; /* transfer page from old buffer to new buffer */ - memcpy(new_buff, old_buff, sizeof(struct igb_rx_buffer)); + *new_buff = *old_buff; /* sync the buffer for use by the device */ dma_sync_single_range_for_device(rx_ring->dev, old_buff->dma, @@ -6963,6 +6968,7 @@ static void igb_process_skb_fields(struct igb_ring *rx_ring, if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) && igb_test_staterr(rx_desc, E1000_RXD_STAT_VP)) { u16 vid; + if (igb_test_staterr(rx_desc, E1000_RXDEXT_STATERR_LB) && test_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &rx_ring->flags)) vid = be16_to_cpu(rx_desc->wb.upper.vlan); @@ -7051,7 +7057,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget) if (cleaned_count) igb_alloc_rx_buffers(rx_ring, cleaned_count); - return (total_packets < budget); + return total_packets < budget; } static bool igb_alloc_mapped_page(struct igb_ring *rx_ring, @@ -7172,7 +7178,7 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) break; case SIOCGMIIREG: if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, - &data->val_out)) + &data->val_out)) return -EIO; break; case SIOCSMIIREG: @@ -7955,11 +7961,13 @@ static void igb_vmm_control(struct igb_adapter *adapter) reg = rd32(E1000_DTXCTL); reg |= E1000_DTXCTL_VLAN_ADDED; wr32(E1000_DTXCTL, reg); + /* Fall through */ case e1000_82580: /* enable replication vlan tag stripping */ reg = rd32(E1000_RPLOLR); reg |= E1000_RPLOLR_STRVLAN; wr32(E1000_RPLOLR, reg); + /* Fall through */ case e1000_i350: /* none of the above registers are supported by i350 */ break; @@ -8049,6 +8057,7 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba) } /* endif adapter->dmac is not disabled */ } else if (hw->mac.type == e1000_82580) { u32 reg = rd32(E1000_PCIEMISC); + wr32(E1000_PCIEMISC, reg & ~E1000_PCIEMISC_LX_DECISION); wr32(E1000_DMACR, 0); } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index c6c4ca7d68e61a..c688c8a4c0630e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -155,7 +155,6 @@ struct vf_data_storage { struct vf_macvlans { struct list_head l; int vf; - int rar_entry; bool free; bool is_macvlan; u8 vf_macvlan[ETH_ALEN]; @@ -613,6 +612,15 @@ static inline void ixgbe_write_tail(struct ixgbe_ring *ring, u32 value) #define MAX_MSIX_VECTORS_82598 18 #define MAX_Q_VECTORS_82598 16 +struct ixgbe_mac_addr { + u8 addr[ETH_ALEN]; + u16 queue; + u16 state; /* bitmask */ +}; +#define IXGBE_MAC_STATE_DEFAULT 0x1 +#define IXGBE_MAC_STATE_MODIFIED 0x2 +#define IXGBE_MAC_STATE_IN_USE 0x4 + #define MAX_Q_VECTORS MAX_Q_VECTORS_82599 #define MAX_MSIX_COUNT MAX_MSIX_VECTORS_82599 @@ -785,6 +793,7 @@ struct ixgbe_adapter { u32 timer_event_accumulator; u32 vferr_refcount; + struct ixgbe_mac_addr *mac_table; struct kobject *info_kobj; #ifdef CONFIG_IXGBE_HWMON struct hwmon_buff *ixgbe_hwmon_buff; @@ -863,6 +872,13 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter); int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter); int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id, u16 subdevice_id); +#ifdef CONFIG_PCI_IOV +void ixgbe_full_sync_mac_table(struct ixgbe_adapter *adapter); +#endif +int ixgbe_add_mac_filter(struct ixgbe_adapter *adapter, + u8 *addr, u16 queue); +int ixgbe_del_mac_filter(struct ixgbe_adapter *adapter, + u8 *addr, u16 queue); void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter); netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *, struct ixgbe_adapter *, struct ixgbe_ring *); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index 4c78ea8946c1b4..1c52e4753480c0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -337,19 +337,25 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) int i; bool link_up; - /* - * Validate the water mark configuration for packet buffer 0. Zero - * water marks indicate that the packet buffer was not configured - * and the watermarks for packet buffer 0 should always be configured. - */ - if (!hw->fc.low_water || - !hw->fc.high_water[0] || - !hw->fc.pause_time) { - hw_dbg(hw, "Invalid water mark configuration\n"); + /* Validate the water mark configuration */ + if (!hw->fc.pause_time) { ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; goto out; } + /* Low water mark of zero causes XOFF floods */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + if ((hw->fc.current_mode & ixgbe_fc_tx_pause) && + hw->fc.high_water[i]) { + if (!hw->fc.low_water[i] || + hw->fc.low_water[i] >= hw->fc.high_water[i]) { + hw_dbg(hw, "Invalid water mark configuration\n"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + } + } + /* * On 82598 having Rx FC on causes resets while doing 1G * so if it's on turn it off once we know link_speed. For @@ -432,12 +438,11 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl_reg); IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); - fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE; - /* Set up and enable Rx high/low water mark thresholds, enable XON. */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { if ((hw->fc.current_mode & ixgbe_fc_tx_pause) && hw->fc.high_water[i]) { + fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE; fcrth = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), fcrtl); IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), fcrth); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 981b8a7b100df5..bdc55819179d19 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -271,6 +271,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) **/ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) { + s32 ret_val; u32 ctrl_ext; /* Set the media type */ @@ -292,12 +293,15 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) IXGBE_WRITE_FLUSH(hw); /* Setup flow control */ - ixgbe_setup_fc(hw); + ret_val = ixgbe_setup_fc(hw); + if (!ret_val) + goto out; /* Clear adapter stopped flag */ hw->adapter_stopped = false; - return 0; +out: + return ret_val; } /** @@ -2106,19 +2110,25 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) u32 fcrtl, fcrth; int i; - /* - * Validate the water mark configuration for packet buffer 0. Zero - * water marks indicate that the packet buffer was not configured - * and the watermarks for packet buffer 0 should always be configured. - */ - if (!hw->fc.low_water || - !hw->fc.high_water[0] || - !hw->fc.pause_time) { - hw_dbg(hw, "Invalid water mark configuration\n"); + /* Validate the water mark configuration. */ + if (!hw->fc.pause_time) { ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; goto out; } + /* Low water mark of zero causes XOFF floods */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + if ((hw->fc.current_mode & ixgbe_fc_tx_pause) && + hw->fc.high_water[i]) { + if (!hw->fc.low_water[i] || + hw->fc.low_water[i] >= hw->fc.high_water[i]) { + hw_dbg(hw, "Invalid water mark configuration\n"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + } + } + /* Negotiate the fc mode to use */ ixgbe_fc_autoneg(hw); @@ -2181,12 +2191,11 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg); IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg); - fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE; - /* Set up and enable Rx high/low water mark thresholds, enable XON. */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { if ((hw->fc.current_mode & ixgbe_fc_tx_pause) && hw->fc.high_water[i]) { + fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE; IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), fcrtl); fcrth = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; } else { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h index f12c40fb5537a1..d15ff2e5edb76b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h @@ -141,8 +141,6 @@ static inline bool ixgbe_removed(void __iomem *addr) return unlikely(!addr); } -void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg); - static inline void ixgbe_write_reg(struct ixgbe_hw *hw, u32 reg, u32 value) { u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr); @@ -172,18 +170,7 @@ static inline void ixgbe_write_reg64(struct ixgbe_hw *hw, u32 reg, u64 value) } #define IXGBE_WRITE_REG64(a, reg, value) ixgbe_write_reg64((a), (reg), (value)) -static inline u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg) -{ - u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr); - u32 value; - - if (ixgbe_removed(reg_addr)) - return IXGBE_FAILED_READ_REG; - value = readl(reg_addr + reg); - if (unlikely(value == IXGBE_FAILED_READ_REG)) - ixgbe_check_remove(hw, reg); - return value; -} +u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg); #define IXGBE_READ_REG(a, reg) ixgbe_read_reg((a), (reg)) #define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) \ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c index 7a77f37a7cbcbd..d3ba63f9ad3712 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c @@ -208,7 +208,6 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en) IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg); - fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE; /* Configure PFC Tx thresholds per TC */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { if (!(pfc_en & (1 << i))) { @@ -217,6 +216,7 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en) continue; } + fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE; reg = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), fcrtl); IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), reg); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c index bdb99b3b0f30f4..3b932fe64ab66c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c @@ -242,7 +242,6 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) max_tc = prio_tc[i]; } - fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE; /* Configure PFC Tx thresholds per TC */ for (i = 0; i <= max_tc; i++) { @@ -257,6 +256,7 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) if (enabled) { reg = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; + fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE; IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), fcrtl); } else { reg = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)) - 32; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h index b16cc786750dec..0772b7730fce92 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h @@ -81,9 +81,7 @@ struct ixgbe_fcoe { void *extra_ddp_buffer; dma_addr_t extra_ddp_buffer_dma; unsigned long mode; -#ifdef CONFIG_IXGBE_DCB u8 up; -#endif }; #endif /* _IXGBE_FCOE_H */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index d62e7a25cf972d..6674646ff9f222 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -301,7 +301,7 @@ static void ixgbe_remove_adapter(struct ixgbe_hw *hw) ixgbe_service_event_schedule(adapter); } -void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg) +static void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg) { u32 value; @@ -320,6 +320,32 @@ void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg) ixgbe_remove_adapter(hw); } +/** + * ixgbe_read_reg - Read from device register + * @hw: hw specific details + * @reg: offset of register to read + * + * Returns : value read or IXGBE_FAILED_READ_REG if removed + * + * This function is used to read device registers. It checks for device + * removal by confirming any read that returns all ones by checking the + * status register value for all ones. This function avoids reading from + * the hardware if a removal was previously detected in which case it + * returns IXGBE_FAILED_READ_REG (all ones). + */ +u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg) +{ + u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr); + u32 value; + + if (ixgbe_removed(reg_addr)) + return IXGBE_FAILED_READ_REG; + value = readl(reg_addr + reg); + if (unlikely(value == IXGBE_FAILED_READ_REG)) + ixgbe_check_remove(hw, reg); + return value; +} + static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev) { u16 value; @@ -376,7 +402,7 @@ static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter) BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state)); /* flush memory to make sure state is correct before next watchdog */ - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state); } @@ -3742,35 +3768,6 @@ static int ixgbe_vlan_rx_kill_vid(struct net_device *netdev, return 0; } -/** - * ixgbe_vlan_filter_disable - helper to disable hw vlan filtering - * @adapter: driver data - */ -static void ixgbe_vlan_filter_disable(struct ixgbe_adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - u32 vlnctrl; - - vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); - vlnctrl &= ~(IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN); - IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); -} - -/** - * ixgbe_vlan_filter_enable - helper to enable hw vlan filtering - * @adapter: driver data - */ -static void ixgbe_vlan_filter_enable(struct ixgbe_adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - u32 vlnctrl; - - vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); - vlnctrl |= IXGBE_VLNCTRL_VFE; - vlnctrl &= ~IXGBE_VLNCTRL_CFIEN; - IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); -} - /** * ixgbe_vlan_strip_disable - helper to disable hw vlan stripping * @adapter: driver data @@ -3849,6 +3846,158 @@ static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter) ixgbe_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), vid); } +/** + * ixgbe_write_mc_addr_list - write multicast addresses to MTA + * @netdev: network interface device structure + * + * Writes multicast address list to the MTA hash table. + * Returns: -ENOMEM on failure + * 0 on no addresses written + * X on writing X addresses to MTA + **/ +static int ixgbe_write_mc_addr_list(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + + if (!netif_running(netdev)) + return 0; + + if (hw->mac.ops.update_mc_addr_list) + hw->mac.ops.update_mc_addr_list(hw, netdev); + else + return -ENOMEM; + +#ifdef CONFIG_PCI_IOV + ixgbe_restore_vf_multicasts(adapter); +#endif + + return netdev_mc_count(netdev); +} + +#ifdef CONFIG_PCI_IOV +void ixgbe_full_sync_mac_table(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + int i; + for (i = 0; i < hw->mac.num_rar_entries; i++) { + if (adapter->mac_table[i].state & IXGBE_MAC_STATE_IN_USE) + hw->mac.ops.set_rar(hw, i, adapter->mac_table[i].addr, + adapter->mac_table[i].queue, + IXGBE_RAH_AV); + else + hw->mac.ops.clear_rar(hw, i); + + adapter->mac_table[i].state &= ~(IXGBE_MAC_STATE_MODIFIED); + } +} +#endif + +static void ixgbe_sync_mac_table(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + int i; + for (i = 0; i < hw->mac.num_rar_entries; i++) { + if (adapter->mac_table[i].state & IXGBE_MAC_STATE_MODIFIED) { + if (adapter->mac_table[i].state & + IXGBE_MAC_STATE_IN_USE) + hw->mac.ops.set_rar(hw, i, + adapter->mac_table[i].addr, + adapter->mac_table[i].queue, + IXGBE_RAH_AV); + else + hw->mac.ops.clear_rar(hw, i); + + adapter->mac_table[i].state &= + ~(IXGBE_MAC_STATE_MODIFIED); + } + } +} + +static void ixgbe_flush_sw_mac_table(struct ixgbe_adapter *adapter) +{ + int i; + struct ixgbe_hw *hw = &adapter->hw; + + for (i = 0; i < hw->mac.num_rar_entries; i++) { + adapter->mac_table[i].state |= IXGBE_MAC_STATE_MODIFIED; + adapter->mac_table[i].state &= ~IXGBE_MAC_STATE_IN_USE; + memset(adapter->mac_table[i].addr, 0, ETH_ALEN); + adapter->mac_table[i].queue = 0; + } + ixgbe_sync_mac_table(adapter); +} + +static int ixgbe_available_rars(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + int i, count = 0; + + for (i = 0; i < hw->mac.num_rar_entries; i++) { + if (adapter->mac_table[i].state == 0) + count++; + } + return count; +} + +/* this function destroys the first RAR entry */ +static void ixgbe_mac_set_default_filter(struct ixgbe_adapter *adapter, + u8 *addr) +{ + struct ixgbe_hw *hw = &adapter->hw; + + memcpy(&adapter->mac_table[0].addr, addr, ETH_ALEN); + adapter->mac_table[0].queue = VMDQ_P(0); + adapter->mac_table[0].state = (IXGBE_MAC_STATE_DEFAULT | + IXGBE_MAC_STATE_IN_USE); + hw->mac.ops.set_rar(hw, 0, adapter->mac_table[0].addr, + adapter->mac_table[0].queue, + IXGBE_RAH_AV); +} + +int ixgbe_add_mac_filter(struct ixgbe_adapter *adapter, u8 *addr, u16 queue) +{ + struct ixgbe_hw *hw = &adapter->hw; + int i; + + if (is_zero_ether_addr(addr)) + return -EINVAL; + + for (i = 0; i < hw->mac.num_rar_entries; i++) { + if (adapter->mac_table[i].state & IXGBE_MAC_STATE_IN_USE) + continue; + adapter->mac_table[i].state |= (IXGBE_MAC_STATE_MODIFIED | + IXGBE_MAC_STATE_IN_USE); + ether_addr_copy(adapter->mac_table[i].addr, addr); + adapter->mac_table[i].queue = queue; + ixgbe_sync_mac_table(adapter); + return i; + } + return -ENOMEM; +} + +int ixgbe_del_mac_filter(struct ixgbe_adapter *adapter, u8 *addr, u16 queue) +{ + /* search table for addr, if found, set to 0 and sync */ + int i; + struct ixgbe_hw *hw = &adapter->hw; + + if (is_zero_ether_addr(addr)) + return -EINVAL; + + for (i = 0; i < hw->mac.num_rar_entries; i++) { + if (ether_addr_equal(addr, adapter->mac_table[i].addr) && + adapter->mac_table[i].queue == queue) { + adapter->mac_table[i].state |= IXGBE_MAC_STATE_MODIFIED; + adapter->mac_table[i].state &= ~IXGBE_MAC_STATE_IN_USE; + memset(adapter->mac_table[i].addr, 0, ETH_ALEN); + adapter->mac_table[i].queue = 0; + ixgbe_sync_mac_table(adapter); + return 0; + } + } + return -ENOMEM; +} /** * ixgbe_write_uc_addr_list - write unicast addresses to RAR table * @netdev: network interface device structure @@ -3858,39 +4007,23 @@ static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter) * 0 on no addresses written * X on writing X addresses to the RAR table **/ -static int ixgbe_write_uc_addr_list(struct net_device *netdev) +static int ixgbe_write_uc_addr_list(struct net_device *netdev, int vfn) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - struct ixgbe_hw *hw = &adapter->hw; - unsigned int rar_entries = hw->mac.num_rar_entries - 1; int count = 0; - /* In SR-IOV/VMDQ modes significantly less RAR entries are available */ - if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) - rar_entries = IXGBE_MAX_PF_MACVLANS - 1; - /* return ENOMEM indicating insufficient memory for addresses */ - if (netdev_uc_count(netdev) > rar_entries) + if (netdev_uc_count(netdev) > ixgbe_available_rars(adapter)) return -ENOMEM; if (!netdev_uc_empty(netdev)) { struct netdev_hw_addr *ha; - /* return error if we do not support writing to RAR table */ - if (!hw->mac.ops.set_rar) - return -ENOMEM; - netdev_for_each_uc_addr(ha, netdev) { - if (!rar_entries) - break; - hw->mac.ops.set_rar(hw, rar_entries--, ha->addr, - VMDQ_P(0), IXGBE_RAH_AV); + ixgbe_del_mac_filter(adapter, ha->addr, vfn); + ixgbe_add_mac_filter(adapter, ha->addr, vfn); count++; } } - /* write the addresses in reverse order to avoid write combining */ - for (; rar_entries > 0 ; rar_entries--) - hw->mac.ops.clear_rar(hw, rar_entries); - return count; } @@ -3908,11 +4041,12 @@ void ixgbe_set_rx_mode(struct net_device *netdev) struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; u32 fctrl, vmolr = IXGBE_VMOLR_BAM | IXGBE_VMOLR_AUPE; + u32 vlnctrl; int count; /* Check for Promiscuous and All Multicast modes */ - fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); /* set all bits that we expect to always be set */ fctrl &= ~IXGBE_FCTRL_SBP; /* disable store-bad-packets */ @@ -3922,26 +4056,24 @@ void ixgbe_set_rx_mode(struct net_device *netdev) /* clear the bits we are changing the status of */ fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); - + vlnctrl &= ~(IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN); if (netdev->flags & IFF_PROMISC) { hw->addr_ctrl.user_set_promisc = true; fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); - vmolr |= (IXGBE_VMOLR_ROPE | IXGBE_VMOLR_MPE); + vmolr |= IXGBE_VMOLR_MPE; /* Only disable hardware filter vlans in promiscuous mode * if SR-IOV and VMDQ are disabled - otherwise ensure * that hardware VLAN filters remain enabled. */ if (!(adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED | IXGBE_FLAG_SRIOV_ENABLED))) - ixgbe_vlan_filter_disable(adapter); - else - ixgbe_vlan_filter_enable(adapter); + vlnctrl |= (IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN); } else { if (netdev->flags & IFF_ALLMULTI) { fctrl |= IXGBE_FCTRL_MPE; vmolr |= IXGBE_VMOLR_MPE; } - ixgbe_vlan_filter_enable(adapter); + vlnctrl |= IXGBE_VLNCTRL_VFE; hw->addr_ctrl.user_set_promisc = false; } @@ -3950,7 +4082,7 @@ void ixgbe_set_rx_mode(struct net_device *netdev) * sufficient space to store all the addresses then enable * unicast promiscuous mode */ - count = ixgbe_write_uc_addr_list(netdev); + count = ixgbe_write_uc_addr_list(netdev, VMDQ_P(0)); if (count < 0) { fctrl |= IXGBE_FCTRL_UPE; vmolr |= IXGBE_VMOLR_ROPE; @@ -3960,11 +4092,13 @@ void ixgbe_set_rx_mode(struct net_device *netdev) * then we should just turn on promiscuous mode so * that we can at least receive multicast traffic */ - hw->mac.ops.update_mc_addr_list(hw, netdev); - vmolr |= IXGBE_VMOLR_ROMPE; - - if (adapter->num_vfs) - ixgbe_restore_vf_multicasts(adapter); + count = ixgbe_write_mc_addr_list(netdev); + if (count < 0) { + fctrl |= IXGBE_FCTRL_MPE; + vmolr |= IXGBE_VMOLR_MPE; + } else if (count) { + vmolr |= IXGBE_VMOLR_ROMPE; + } if (hw->mac.type != ixgbe_mac_82598EB) { vmolr |= IXGBE_READ_REG(hw, IXGBE_VMOLR(VMDQ_P(0))) & @@ -3985,6 +4119,7 @@ void ixgbe_set_rx_mode(struct net_device *netdev) /* NOTE: VLAN filtering is disabled by setting PROMISC */ } + IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) @@ -4101,8 +4236,8 @@ static int ixgbe_hpbthresh(struct ixgbe_adapter *adapter, int pb) (tc < IXGBE_FCOE_JUMBO_FRAME_SIZE) && (pb == ixgbe_fcoe_get_tc(adapter))) tc = IXGBE_FCOE_JUMBO_FRAME_SIZE; - #endif + /* Calculate delay value for device */ switch (hw->mac.type) { case ixgbe_mac_X540: @@ -4143,7 +4278,7 @@ static int ixgbe_hpbthresh(struct ixgbe_adapter *adapter, int pb) * @adapter: board private structure to calculate for * @pb: packet buffer to calculate */ -static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter) +static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter, int pb) { struct ixgbe_hw *hw = &adapter->hw; struct net_device *dev = adapter->netdev; @@ -4153,6 +4288,14 @@ static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter) /* Calculate max LAN frame size */ tc = dev->mtu + ETH_HLEN + ETH_FCS_LEN; +#ifdef IXGBE_FCOE + /* FCoE traffic class uses FCOE jumbo frames */ + if ((dev->features & NETIF_F_FCOE_MTU) && + (tc < IXGBE_FCOE_JUMBO_FRAME_SIZE) && + (pb == netdev_get_prio_tc_map(dev, adapter->fcoe.up))) + tc = IXGBE_FCOE_JUMBO_FRAME_SIZE; +#endif + /* Calculate delay value for device */ switch (hw->mac.type) { case ixgbe_mac_X540: @@ -4179,15 +4322,17 @@ static void ixgbe_pbthresh_setup(struct ixgbe_adapter *adapter) if (!num_tc) num_tc = 1; - hw->fc.low_water = ixgbe_lpbthresh(adapter); - for (i = 0; i < num_tc; i++) { hw->fc.high_water[i] = ixgbe_hpbthresh(adapter, i); + hw->fc.low_water[i] = ixgbe_lpbthresh(adapter, i); /* Low water marks must not be larger than high water marks */ - if (hw->fc.low_water > hw->fc.high_water[i]) - hw->fc.low_water = 0; + if (hw->fc.low_water[i] > hw->fc.high_water[i]) + hw->fc.low_water[i] = 0; } + + for (; i < MAX_TRAFFIC_CLASS; i++) + hw->fc.high_water[i] = 0; } static void ixgbe_configure_pb(struct ixgbe_adapter *adapter) @@ -4249,20 +4394,10 @@ static void ixgbe_macvlan_set_rx_mode(struct net_device *dev, unsigned int pool, vmolr |= IXGBE_VMOLR_ROMPE; hw->mac.ops.update_mc_addr_list(hw, dev); } - ixgbe_write_uc_addr_list(adapter->netdev); + ixgbe_write_uc_addr_list(adapter->netdev, pool); IXGBE_WRITE_REG(hw, IXGBE_VMOLR(pool), vmolr); } -static void ixgbe_add_mac_filter(struct ixgbe_adapter *adapter, - u8 *addr, u16 pool) -{ - struct ixgbe_hw *hw = &adapter->hw; - unsigned int entry; - - entry = hw->mac.num_rar_entries - pool; - hw->mac.ops.set_rar(hw, entry, addr, VMDQ_P(pool), IXGBE_RAH_AV); -} - static void ixgbe_fwd_psrtype(struct ixgbe_fwd_adapter *vadapter) { struct ixgbe_adapter *adapter = vadapter->real_adapter; @@ -4672,7 +4807,7 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter) if (hw->mac.ops.enable_tx_laser) hw->mac.ops.enable_tx_laser(hw); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(__IXGBE_DOWN, &adapter->state); ixgbe_napi_enable_all(adapter); @@ -4742,7 +4877,9 @@ void ixgbe_up(struct ixgbe_adapter *adapter) void ixgbe_reset(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; int err; + u8 old_addr[ETH_ALEN]; if (ixgbe_removed(hw->hw_addr)) return; @@ -4778,9 +4915,10 @@ void ixgbe_reset(struct ixgbe_adapter *adapter) } clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); - - /* reprogram the RAR[0] in case user changed it. */ - hw->mac.ops.set_rar(hw, 0, hw->mac.addr, VMDQ_P(0), IXGBE_RAH_AV); + /* do not flush user set addresses */ + memcpy(old_addr, &adapter->mac_table[0].addr, netdev->addr_len); + ixgbe_flush_sw_mac_table(adapter); + ixgbe_mac_set_default_filter(adapter, old_addr); /* update SAN MAC vmdq pool selection */ if (hw->mac.san_mac_rar_index) @@ -5026,6 +5164,10 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter) #endif /* CONFIG_IXGBE_DCB */ #endif /* IXGBE_FCOE */ + adapter->mac_table = kzalloc(sizeof(struct ixgbe_mac_addr) * + hw->mac.num_rar_entries, + GFP_ATOMIC); + /* Set MAC specific capability flags and exceptions */ switch (hw->mac.type) { case ixgbe_mac_82598EB: @@ -5568,7 +5710,7 @@ static int ixgbe_resume(struct pci_dev *pdev) e_dev_err("Cannot enable PCI device from suspend\n"); return err; } - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(__IXGBE_DISABLED, &adapter->state); pci_set_master(pdev); @@ -7172,16 +7314,17 @@ static int ixgbe_set_mac(struct net_device *netdev, void *p) struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; struct sockaddr *addr = p; + int ret; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; + ixgbe_del_mac_filter(adapter, hw->mac.addr, VMDQ_P(0)); memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len); - hw->mac.ops.set_rar(hw, 0, hw->mac.addr, VMDQ_P(0), IXGBE_RAH_AV); - - return 0; + ret = ixgbe_add_mac_filter(adapter, hw->mac.addr, VMDQ_P(0)); + return ret > 0 ? 0 : ret; } static int @@ -8187,6 +8330,8 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_sw_init; } + ixgbe_mac_set_default_filter(adapter, hw->mac.perm_addr); + setup_timer(&adapter->service_timer, &ixgbe_service_timer, (unsigned long) adapter); @@ -8319,6 +8464,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ixgbe_disable_sriov(adapter); adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP; iounmap(adapter->io_addr); + kfree(adapter->mac_table); err_ioremap: free_netdev(netdev); err_alloc_etherdev: @@ -8392,6 +8538,7 @@ static void ixgbe_remove(struct pci_dev *pdev) e_dev_info("complete\n"); + kfree(adapter->mac_table); free_netdev(netdev); pci_disable_pcie_error_reporting(pdev); @@ -8542,7 +8689,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) e_err(probe, "Cannot re-enable PCI device after reset.\n"); result = PCI_ERS_RESULT_DISCONNECT; } else { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(__IXGBE_DISABLED, &adapter->state); adapter->hw.hw_addr = adapter->io_addr; pci_set_master(pdev); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index e6c68d396c992f..a01417c066208e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -72,8 +72,6 @@ static int __ixgbe_enable_sriov(struct ixgbe_adapter *adapter) for (i = 0; i < num_vf_macvlans; i++) { mv_list->vf = -1; mv_list->free = true; - mv_list->rar_entry = hw->mac.num_rar_entries - - (i + adapter->num_vfs + 1); list_add(&mv_list->l, &adapter->vf_mvs.l); mv_list++; } @@ -327,6 +325,7 @@ static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter, u32 vector_bit; u32 vector_reg; u32 mta_reg; + u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf)); /* only so many hash values supported */ entries = min(entries, IXGBE_MAX_VF_MC_ENTRIES); @@ -353,25 +352,13 @@ static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter, mta_reg |= (1 << vector_bit); IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg); } + vmolr |= IXGBE_VMOLR_ROMPE; + IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf), vmolr); return 0; } -static void ixgbe_restore_vf_macvlans(struct ixgbe_adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - struct list_head *pos; - struct vf_macvlans *entry; - - list_for_each(pos, &adapter->vf_mvs.l) { - entry = list_entry(pos, struct vf_macvlans, l); - if (!entry->free) - hw->mac.ops.set_rar(hw, entry->rar_entry, - entry->vf_macvlan, - entry->vf, IXGBE_RAH_AV); - } -} - +#ifdef CONFIG_PCI_IOV void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; @@ -382,6 +369,7 @@ void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter) u32 mta_reg; for (i = 0; i < adapter->num_vfs; i++) { + u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(i)); vfinfo = &adapter->vfinfo[i]; for (j = 0; j < vfinfo->num_vf_mc_hashes; j++) { hw->addr_ctrl.mta_in_use++; @@ -391,11 +379,18 @@ void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter) mta_reg |= (1 << vector_bit); IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg); } + + if (vfinfo->num_vf_mc_hashes) + vmolr |= IXGBE_VMOLR_ROMPE; + else + vmolr &= ~IXGBE_VMOLR_ROMPE; + IXGBE_WRITE_REG(hw, IXGBE_VMOLR(i), vmolr); } /* Restore any VF macvlans */ - ixgbe_restore_vf_macvlans(adapter); + ixgbe_full_sync_mac_table(adapter); } +#endif static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, u32 vf) @@ -495,8 +490,7 @@ static s32 ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf) static void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe) { u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf)); - vmolr |= (IXGBE_VMOLR_ROMPE | - IXGBE_VMOLR_BAM); + vmolr |= IXGBE_VMOLR_BAM; if (aupe) vmolr |= IXGBE_VMOLR_AUPE; else @@ -514,7 +508,6 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf) { struct ixgbe_hw *hw = &adapter->hw; struct vf_data_storage *vfinfo = &adapter->vfinfo[vf]; - int rar_entry = hw->mac.num_rar_entries - (vf + 1); u8 num_tcs = netdev_get_num_tc(adapter->netdev); /* add PF assigned VLAN or VLAN 0 */ @@ -544,7 +537,7 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf) /* Flush and reset the mta with the new values */ ixgbe_set_rx_mode(adapter->netdev); - hw->mac.ops.clear_rar(hw, rar_entry); + ixgbe_del_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf); /* reset VF api back to unknown */ adapter->vfinfo[vf].vf_api = ixgbe_mbox_api_10; @@ -553,11 +546,9 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf) static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter, int vf, unsigned char *mac_addr) { - struct ixgbe_hw *hw = &adapter->hw; - int rar_entry = hw->mac.num_rar_entries - (vf + 1); - + ixgbe_del_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf); memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, ETH_ALEN); - hw->mac.ops.set_rar(hw, rar_entry, mac_addr, vf, IXGBE_RAH_AV); + ixgbe_add_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf); return 0; } @@ -565,7 +556,6 @@ static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter, static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter, int vf, int index, unsigned char *mac_addr) { - struct ixgbe_hw *hw = &adapter->hw; struct list_head *pos; struct vf_macvlans *entry; @@ -576,7 +566,8 @@ static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter, entry->vf = -1; entry->free = true; entry->is_macvlan = false; - hw->mac.ops.clear_rar(hw, entry->rar_entry); + ixgbe_del_mac_filter(adapter, + entry->vf_macvlan, vf); } } } @@ -612,7 +603,7 @@ static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter, entry->vf = vf; memcpy(entry->vf_macvlan, mac_addr, ETH_ALEN); - hw->mac.ops.set_rar(hw, entry->rar_entry, mac_addr, vf, IXGBE_RAH_AV); + ixgbe_add_mac_filter(adapter, mac_addr, vf); return 0; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h index 139eaddfb2ed5c..cea64014760497 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h @@ -34,7 +34,9 @@ */ #define IXGBE_MAX_VFS_DRV_LIMIT (IXGBE_MAX_VF_FUNCTIONS - 1) +#ifdef CONFIG_PCI_IOV void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter); +#endif void ixgbe_msg_task(struct ixgbe_adapter *adapter); int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask); void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 8a6ff2423f0769..551d6089a4d3eb 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -2746,7 +2746,7 @@ struct ixgbe_bus_info { /* Flow control parameters */ struct ixgbe_fc_info { u32 high_water[MAX_TRAFFIC_CLASS]; /* Flow Control High-water */ - u32 low_water; /* Flow Control Low-water */ + u32 low_water[MAX_TRAFFIC_CLASS]; /* Flow Control Low-water */ u16 pause_time; /* Flow Control Pause timer */ bool send_xon; /* Flow control send XON */ bool strict_ieee; /* Strict IEEE mode */ diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index d0799e8e31e4ea..75467f83772ca6 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -85,7 +85,7 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbevf_pci_tbl) = { MODULE_DEVICE_TABLE(pci, ixgbevf_pci_tbl); MODULE_AUTHOR("Intel Corporation, "); -MODULE_DESCRIPTION("Intel(R) 82599 Virtual Function Driver"); +MODULE_DESCRIPTION("Intel(R) 10 Gigabit Virtual Function Network Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); @@ -1668,7 +1668,7 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter) spin_unlock_bh(&adapter->mbx_lock); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(__IXGBEVF_DOWN, &adapter->state); ixgbevf_napi_enable_all(adapter); @@ -3354,7 +3354,7 @@ static int ixgbevf_resume(struct pci_dev *pdev) dev_err(&pdev->dev, "Cannot enable PCI device from suspend\n"); return err; } - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(__IXGBEVF_DISABLED, &adapter->state); pci_set_master(pdev); @@ -3712,7 +3712,7 @@ static pci_ers_result_t ixgbevf_io_slot_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_DISCONNECT; } - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(__IXGBEVF_DISABLED, &adapter->state); pci_set_master(pdev); diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index b0c6050479eb46..6e664d9038d60d 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -1988,7 +1988,7 @@ jme_alloc_txdesc(struct jme_adapter *jme, return idx; } -static void +static int jme_fill_tx_map(struct pci_dev *pdev, struct txdesc *txdesc, struct jme_buffer_info *txbi, @@ -2005,6 +2005,9 @@ jme_fill_tx_map(struct pci_dev *pdev, len, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(pdev, dmaaddr))) + return -EINVAL; + pci_dma_sync_single_for_device(pdev, dmaaddr, len, @@ -2021,9 +2024,30 @@ jme_fill_tx_map(struct pci_dev *pdev, txbi->mapping = dmaaddr; txbi->len = len; + return 0; } -static void +static void jme_drop_tx_map(struct jme_adapter *jme, int startidx, int endidx) +{ + struct jme_ring *txring = &(jme->txring[0]); + struct jme_buffer_info *txbi = txring->bufinf, *ctxbi; + int mask = jme->tx_ring_mask; + int j; + + for (j = startidx ; j < endidx ; ++j) { + ctxbi = txbi + ((startidx + j + 2) & (mask)); + pci_unmap_page(jme->pdev, + ctxbi->mapping, + ctxbi->len, + PCI_DMA_TODEVICE); + + ctxbi->mapping = 0; + ctxbi->len = 0; + } + +} + +static int jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx) { struct jme_ring *txring = &(jme->txring[0]); @@ -2034,25 +2058,37 @@ jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx) int mask = jme->tx_ring_mask; const struct skb_frag_struct *frag; u32 len; + int ret = 0; for (i = 0 ; i < nr_frags ; ++i) { frag = &skb_shinfo(skb)->frags[i]; ctxdesc = txdesc + ((idx + i + 2) & (mask)); ctxbi = txbi + ((idx + i + 2) & (mask)); - jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, + ret = jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, skb_frag_page(frag), frag->page_offset, skb_frag_size(frag), hidma); + if (ret) { + jme_drop_tx_map(jme, idx, idx+i); + goto out; + } + } len = skb_is_nonlinear(skb) ? skb_headlen(skb) : skb->len; ctxdesc = txdesc + ((idx + 1) & (mask)); ctxbi = txbi + ((idx + 1) & (mask)); - jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, virt_to_page(skb->data), + ret = jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, virt_to_page(skb->data), offset_in_page(skb->data), len, hidma); + if (ret) + jme_drop_tx_map(jme, idx, idx+i); + +out: + return ret; } + static int jme_tx_tso(struct sk_buff *skb, __le16 *mss, u8 *flags) { @@ -2131,6 +2167,7 @@ jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx) struct txdesc *txdesc; struct jme_buffer_info *txbi; u8 flags; + int ret = 0; txdesc = (struct txdesc *)txring->desc + idx; txbi = txring->bufinf + idx; @@ -2155,7 +2192,10 @@ jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx) if (jme_tx_tso(skb, &txdesc->desc1.mss, &flags)) jme_tx_csum(jme, skb, &flags); jme_tx_vlan(skb, &txdesc->desc1.vlan, &flags); - jme_map_tx_skb(jme, skb, idx); + ret = jme_map_tx_skb(jme, skb, idx); + if (ret) + return ret; + txdesc->desc1.flags = flags; /* * Set tx buffer info after telling NIC to send @@ -2228,7 +2268,8 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_BUSY; } - jme_fill_tx_desc(jme, skb, idx); + if (jme_fill_tx_desc(jme, skb, idx)) + return NETDEV_TX_BUSY; jwrite32(jme, JME_TXCS, jme->reg_txcs | TXCS_SELECT_QUEUE0 | diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index a2844ff322c4c6..e900c1abdef789 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -534,15 +534,6 @@ static inline void s2io_start_all_tx_queue(struct s2io_nic *sp) netif_tx_start_all_queues(sp->dev); } -static inline void s2io_start_tx_queue(struct s2io_nic *sp, int fifo_no) -{ - if (!sp->config.multiq) - sp->mac_control.fifos[fifo_no].queue_state = - FIFO_QUEUE_START; - - netif_tx_start_all_queues(sp->dev); -} - static inline void s2io_wake_all_tx_queue(struct s2io_nic *sp) { if (!sp->config.multiq) { diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig index c14bd3116e454e..d49cba1290814e 100644 --- a/drivers/net/ethernet/qlogic/Kconfig +++ b/drivers/net/ethernet/qlogic/Kconfig @@ -66,6 +66,17 @@ config QLCNIC_VXLAN Say Y here if you want to enable hardware offload support for Virtual eXtensible Local Area Network (VXLAN) in the driver. +config QLCNIC_HWMON + bool "QLOGIC QLCNIC 82XX and 83XX family HWMON support" + depends on QLCNIC && HWMON && !(QLCNIC=y && HWMON=m) + default y + ---help--- + This configuration parameter can be used to read the + board temperature in Converged Ethernet devices + supported by qlcnic. + + This data is available via the hwmon sysfs interface. + config QLGE tristate "QLogic QLGE 10Gb Ethernet Driver Support" depends on PCI diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 7b52a88923ef2e..97b4e598844966 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -39,8 +39,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 3 -#define _QLCNIC_LINUX_SUBVERSION 57 -#define QLCNIC_LINUX_VERSIONID "5.3.57" +#define _QLCNIC_LINUX_SUBVERSION 58 +#define QLCNIC_LINUX_VERSIONID "5.3.58" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) @@ -537,6 +537,7 @@ struct qlcnic_hardware_context { u8 phys_port_id[ETH_ALEN]; u8 lb_mode; u16 vxlan_port; + struct device *hwmon_dev; }; struct qlcnic_adapter_stats { @@ -1719,22 +1720,6 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring) tx_ring->producer; } -static inline int qlcnic_set_real_num_queues(struct qlcnic_adapter *adapter, - struct net_device *netdev) -{ - int err; - - netdev->num_tx_queues = adapter->drv_tx_rings; - netdev->real_num_tx_queues = adapter->drv_tx_rings; - - err = netif_set_real_num_tx_queues(netdev, adapter->drv_tx_rings); - if (err) - netdev_err(netdev, "failed to set %d Tx queues\n", - adapter->drv_tx_rings); - - return err; -} - struct qlcnic_nic_template { int (*config_bridged_mode) (struct qlcnic_adapter *, u32); int (*config_led) (struct qlcnic_adapter *, u32, u32); @@ -2361,4 +2346,18 @@ static inline u32 qlcnic_get_vnic_func_count(struct qlcnic_adapter *adapter) else return QLC_DEFAULT_VNIC_COUNT; } + +#ifdef CONFIG_QLCNIC_HWMON +void qlcnic_register_hwmon_dev(struct qlcnic_adapter *); +void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *); +#else +static inline void qlcnic_register_hwmon_dev(struct qlcnic_adapter *adapter) +{ + return; +} +static inline void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *adapter) +{ + return; +} +#endif #endif /* __QLCNIC_H_ */ diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index b7cffb46a75dbd..7c125d7fb547e3 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -33,6 +33,7 @@ static void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *); #define RSS_HASHTYPE_IP_TCP 0x3 #define QLC_83XX_FW_MBX_CMD 0 #define QLC_SKIP_INACTIVE_PCI_REGS 7 +#define QLC_MAX_LEGACY_FUNC_SUPP 8 static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { {QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1}, @@ -357,8 +358,15 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter) if (!ahw->intr_tbl) return -ENOMEM; - if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) + if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { + if (adapter->ahw->pci_func >= QLC_MAX_LEGACY_FUNC_SUPP) { + dev_err(&adapter->pdev->dev, "PCI function number 8 and higher are not supported with legacy interrupt, func 0x%x\n", + ahw->pci_func); + return -EOPNOTSUPP; + } + qlcnic_83xx_enable_legacy(adapter); + } for (i = 0; i < num_msix; i++) { if (adapter->flags & QLCNIC_MSIX_ENABLED) @@ -879,6 +887,9 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx, return 0; } } + + dev_err(&adapter->pdev->dev, "%s: Invalid mailbox command opcode 0x%x\n", + __func__, type); return -EINVAL; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index ba20c721ee97f5..34d273794e9664 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -2181,6 +2181,8 @@ int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter) max_sds_rings = QLCNIC_MAX_SDS_RINGS; max_tx_rings = QLCNIC_MAX_TX_RINGS; } else { + dev_err(&adapter->pdev->dev, "%s: Invalid opmode %d\n", + __func__, ret); return -EIO; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index c1e11f5715b056..304e247bdf339c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -1027,8 +1027,11 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id, u32 arg1; if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC || - !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE)) + !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE)) { + dev_err(&adapter->pdev->dev, "%s: Not a management function\n", + __func__); return err; + } arg1 = id | (enable_mirroring ? BIT_4 : 0); arg1 |= pci_func << 8; @@ -1318,8 +1321,12 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u32 arg1, arg2 = 0; u8 pci_func; - if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) + if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) { + dev_err(&adapter->pdev->dev, "%s: Not a management function\n", + __func__); return err; + } + pci_func = esw_cfg->pci_func; index = qlcnic_is_valid_nic_func(adapter, pci_func); if (index < 0) @@ -1363,6 +1370,8 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, arg1 &= ~(0x0ffff << 16); break; default: + dev_err(&adapter->pdev->dev, "%s: Invalid opmode 0x%x\n", + __func__, esw_cfg->op_mode); return err; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 173b3d12991f55..deb2278b48d530 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -305,7 +305,6 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, { struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data); struct ethhdr *phdr = (struct ethhdr *)(skb->data); - struct net_device *netdev = adapter->netdev; u16 protocol = ntohs(skb->protocol); struct qlcnic_filter *fil, *tmp_fil; struct hlist_head *head; @@ -330,13 +329,6 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, return; } - if (adapter->fhash.fnum >= adapter->fhash.fmax) { - adapter->stats.mac_filter_limit_overrun++; - netdev_info(netdev, "Can not add more than %d mac-vlan filters, configured %d\n", - adapter->fhash.fmax, adapter->fhash.fnum); - return; - } - memcpy(&src_addr, phdr->h_source, ETH_ALEN); hval = qlcnic_mac_hash(src_addr, vlan_id); hindex = hval & (adapter->fhash.fbucket_size - 1); @@ -353,6 +345,11 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, } } + if (unlikely(adapter->fhash.fnum >= adapter->fhash.fmax)) { + adapter->stats.mac_filter_limit_overrun++; + return; + } + fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC); if (!fil) return; @@ -1216,8 +1213,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter, if (!skb) return buffer; - if (adapter->drv_mac_learn && - (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { + if (adapter->rx_mac_learn) { t_vid = 0; is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0); qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); @@ -1293,8 +1289,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, if (!skb) return buffer; - if (adapter->drv_mac_learn && - (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { + if (adapter->rx_mac_learn) { t_vid = 0; is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0); qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 0bc914859e38be..c93c175c7294ae 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -690,10 +690,10 @@ int qlcnic_setup_tss_rss_intr(struct qlcnic_adapter *adapter) adapter->msix_entries[vector].entry = vector; restore: - err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); - if (err > 0) { + err = pci_enable_msix_exact(pdev, adapter->msix_entries, num_msix); + if (err == -ENOSPC) { if (!adapter->drv_tss_rings && !adapter->drv_rss_rings) - return -ENOSPC; + return err; netdev_info(adapter->netdev, "Unable to allocate %d MSI-X vectors, Available vectors %d\n", @@ -1014,6 +1014,8 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *adapter) if (pfn >= ahw->max_vnic_func) { ret = QL_STATUS_INVALID_PARAM; + dev_err(&adapter->pdev->dev, "%s: Invalid function 0x%x, max 0x%x\n", + __func__, pfn, ahw->max_vnic_func); goto err_eswitch; } @@ -2052,6 +2054,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int drv_sds_rings) static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter) { + struct qlcnic_hardware_context *ahw = adapter->ahw; int err = 0; adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context), @@ -2061,6 +2064,18 @@ static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter) goto err_out; } + if (qlcnic_83xx_check(adapter)) { + ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX_TX; + ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US; + ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS; + ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; + ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; + } else { + ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX; + ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; + ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; + } + /* clear stats */ memset(&adapter->stats, 0, sizeof(adapter->stats)); err_out: @@ -2206,6 +2221,31 @@ static void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *adapter) ahw->max_uc_count = count; } +static int qlcnic_set_real_num_queues(struct qlcnic_adapter *adapter, + u8 tx_queues, u8 rx_queues) +{ + struct net_device *netdev = adapter->netdev; + int err = 0; + + if (tx_queues) { + err = netif_set_real_num_tx_queues(netdev, tx_queues); + if (err) { + netdev_err(netdev, "failed to set %d Tx queues\n", + tx_queues); + return err; + } + } + + if (rx_queues) { + err = netif_set_real_num_rx_queues(netdev, rx_queues); + if (err) + netdev_err(netdev, "failed to set %d Rx queues\n", + rx_queues); + } + + return err; +} + int qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev, int pci_using_dac) @@ -2269,7 +2309,8 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev, netdev->priv_flags |= IFF_UNICAST_FLT; netdev->irq = adapter->msix_entries[0].vector; - err = qlcnic_set_real_num_queues(adapter, netdev); + err = qlcnic_set_real_num_queues(adapter, adapter->drv_tx_rings, + adapter->drv_sds_rings); if (err) return err; @@ -2526,9 +2567,11 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) case -ENOMEM: dev_err(&pdev->dev, "Adapter initialization failed. Please reboot\n"); goto err_out_free_hw; + case -EOPNOTSUPP: + dev_err(&pdev->dev, "Adapter initialization failed\n"); + goto err_out_free_hw; default: - dev_err(&pdev->dev, "Adapter initialization failed. A reboot may be required to recover from this failure\n"); - dev_err(&pdev->dev, "If reboot does not help to recover from this failure, try a flash update of the adapter\n"); + dev_err(&pdev->dev, "Adapter initialization failed. Driver will load in maintenance mode to recover the adapter using the application\n"); goto err_out_maintenance_mode; } } @@ -2602,7 +2645,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) qlcnic_alloc_lb_filters_mem(adapter); qlcnic_add_sysfs(adapter); - + qlcnic_register_hwmon_dev(adapter); return 0; err_out_disable_mbx_intr: @@ -2709,6 +2752,8 @@ static void qlcnic_remove(struct pci_dev *pdev) qlcnic_remove_sysfs(adapter); + qlcnic_unregister_hwmon_dev(adapter); + qlcnic_cleanup_pci_map(adapter->ahw); qlcnic_release_firmware(adapter); @@ -2943,9 +2988,13 @@ static void qlcnic_dump_tx_rings(struct qlcnic_adapter *adapter) tx_ring->tx_stats.xmit_called, tx_ring->tx_stats.xmit_on, tx_ring->tx_stats.xmit_off); + + if (tx_ring->crb_intr_mask) + netdev_info(netdev, "crb_intr_mask=%d\n", + readl(tx_ring->crb_intr_mask)); + netdev_info(netdev, - "crb_intr_mask=%d, hw_producer=%d, sw_producer=%d sw_consumer=%d, hw_consumer=%d\n", - readl(tx_ring->crb_intr_mask), + "hw_producer=%d, sw_producer=%d sw_consumer=%d, hw_consumer=%d\n", readl(tx_ring->crb_cmd_producer), tx_ring->producer, tx_ring->sw_consumer, le32_to_cpu(*(tx_ring->hw_consumer))); @@ -3978,12 +4027,21 @@ int qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt, int qlcnic_setup_rings(struct qlcnic_adapter *adapter) { struct net_device *netdev = adapter->netdev; + u8 tx_rings, rx_rings; int err; if (test_bit(__QLCNIC_RESETTING, &adapter->state)) return -EBUSY; + tx_rings = adapter->drv_tss_rings; + rx_rings = adapter->drv_rss_rings; + netif_device_detach(netdev); + + err = qlcnic_set_real_num_queues(adapter, tx_rings, rx_rings); + if (err) + goto done; + if (netif_running(netdev)) __qlcnic_down(adapter, netdev); @@ -4003,7 +4061,17 @@ int qlcnic_setup_rings(struct qlcnic_adapter *adapter) return err; } - netif_set_real_num_tx_queues(netdev, adapter->drv_tx_rings); + /* Check if we need to update real_num_{tx|rx}_queues because + * qlcnic_setup_intr() may change Tx/Rx rings size + */ + if ((tx_rings != adapter->drv_tx_rings) || + (rx_rings != adapter->drv_sds_rings)) { + err = qlcnic_set_real_num_queues(adapter, + adapter->drv_tx_rings, + adapter->drv_sds_rings); + if (err) + goto done; + } if (qlcnic_83xx_check(adapter)) { qlcnic_83xx_initialize_nic(adapter, 1); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index 2801379915447d..c7926ce85fecf7 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -16,6 +16,7 @@ #define QLC_VF_FLOOD_BIT BIT_16 #define QLC_FLOOD_MODE 0x5 #define QLC_SRIOV_ALLOW_VLAN0 BIT_19 +#define QLC_INTR_COAL_TYPE_MASK 0x7 static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8); @@ -1178,19 +1179,41 @@ static int qlcnic_sriov_validate_cfg_intrcoal(struct qlcnic_adapter *adapter, { struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; u16 ctx_id, pkts, time; + int err = -EINVAL; + u8 type; + type = cmd->req.arg[1] & QLC_INTR_COAL_TYPE_MASK; ctx_id = cmd->req.arg[1] >> 16; pkts = cmd->req.arg[2] & 0xffff; time = cmd->req.arg[2] >> 16; - if (ctx_id != vf->rx_ctx_id) - return -EINVAL; - if (pkts > coal->rx_packets) - return -EINVAL; - if (time < coal->rx_time_us) - return -EINVAL; + switch (type) { + case QLCNIC_INTR_COAL_TYPE_RX: + if (ctx_id != vf->rx_ctx_id || pkts > coal->rx_packets || + time < coal->rx_time_us) + goto err_label; + break; + case QLCNIC_INTR_COAL_TYPE_TX: + if (ctx_id != vf->tx_ctx_id || pkts > coal->tx_packets || + time < coal->tx_time_us) + goto err_label; + break; + default: + netdev_err(adapter->netdev, "Invalid coalescing type 0x%x received\n", + type); + return err; + } return 0; + +err_label: + netdev_err(adapter->netdev, "Expected: rx_ctx_id 0x%x rx_packets 0x%x rx_time_us 0x%x tx_ctx_id 0x%x tx_packets 0x%x tx_time_us 0x%x\n", + vf->rx_ctx_id, coal->rx_packets, coal->rx_time_us, + vf->tx_ctx_id, coal->tx_packets, coal->tx_time_us); + netdev_err(adapter->netdev, "Received: ctx_id 0x%x packets 0x%x time_us 0x%x type 0x%x\n", + ctx_id, pkts, time, type); + + return err; } static int qlcnic_sriov_pf_cfg_intrcoal_cmd(struct qlcnic_bc_trans *tran, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index cd346e27f2e127..f5786d5792df06 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -19,6 +19,10 @@ #include #include #include +#ifdef CONFIG_QLCNIC_HWMON +#include +#include +#endif #define QLC_STATUS_UNSUPPORTED_CMD -2 @@ -358,6 +362,8 @@ int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func) if (adapter->npars[i].pci_func == pci_func) return i; } + + dev_err(&adapter->pdev->dev, "%s: Invalid nic function\n", __func__); return -EINVAL; } @@ -1243,6 +1249,68 @@ static struct bin_attribute bin_attr_flash = { .write = qlcnic_83xx_sysfs_flash_write_handler, }; +#ifdef CONFIG_QLCNIC_HWMON + +static ssize_t qlcnic_hwmon_show_temp(struct device *dev, + struct device_attribute *dev_attr, + char *buf) +{ + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + unsigned int temperature = 0, value = 0; + + if (qlcnic_83xx_check(adapter)) + value = QLCRDX(adapter->ahw, QLC_83XX_ASIC_TEMP); + else if (qlcnic_82xx_check(adapter)) + value = QLC_SHARED_REG_RD32(adapter, QLCNIC_ASIC_TEMP); + + temperature = qlcnic_get_temp_val(value); + /* display millidegree celcius */ + temperature *= 1000; + return sprintf(buf, "%u\n", temperature); +} + +/* hwmon-sysfs attributes */ +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, + qlcnic_hwmon_show_temp, NULL, 1); + +static struct attribute *qlcnic_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL +}; + +ATTRIBUTE_GROUPS(qlcnic_hwmon); + +void qlcnic_register_hwmon_dev(struct qlcnic_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + struct device *hwmon_dev; + + /* Skip hwmon registration for a VF device */ + if (qlcnic_sriov_vf_check(adapter)) { + adapter->ahw->hwmon_dev = NULL; + return; + } + hwmon_dev = hwmon_device_register_with_groups(dev, qlcnic_driver_name, + adapter, + qlcnic_hwmon_groups); + if (IS_ERR(hwmon_dev)) { + dev_err(dev, "Cannot register with hwmon, err=%ld\n", + PTR_ERR(hwmon_dev)); + hwmon_dev = NULL; + } + adapter->ahw->hwmon_dev = hwmon_dev; +} + +void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *adapter) +{ + struct device *hwmon_dev = adapter->ahw->hwmon_dev; + if (hwmon_dev) { + hwmon_device_unregister(hwmon_dev); + adapter->ahw->hwmon_dev = NULL; + } +} +#endif + void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter) { struct device *dev = &adapter->pdev->dev; diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 0a1d76acab8171..6e36fe14b84849 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -3595,7 +3595,7 @@ static int ql_request_irq(struct ql_adapter *qdev) } return status; err_irq: - netif_err(qdev, ifup, qdev->ndev, "Failed to get the interrupts!!!/n"); + netif_err(qdev, ifup, qdev->ndev, "Failed to get the interrupts!!!\n"); ql_free_irq(qdev); return status; } diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 82a9a983869fe6..698494481d1807 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -425,8 +425,8 @@ static int init_tx_ring(struct device *dev, u8 queue_no, * @rx_rsize: ring size * Description: this function initializes the DMA RX descriptor */ -void free_rx_ring(struct device *dev, struct sxgbe_rx_queue *rx_ring, - int rx_rsize) +static void free_rx_ring(struct device *dev, struct sxgbe_rx_queue *rx_ring, + int rx_rsize) { dma_free_coherent(dev, rx_rsize * sizeof(struct sxgbe_rx_norm_desc), rx_ring->dma_rx, rx_ring->dma_rx_phy); @@ -519,8 +519,8 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, * @tx_rsize: ring size * Description: this function initializes the DMA TX descriptor */ -void free_tx_ring(struct device *dev, struct sxgbe_tx_queue *tx_ring, - int tx_rsize) +static void free_tx_ring(struct device *dev, struct sxgbe_tx_queue *tx_ring, + int tx_rsize) { dma_free_coherent(dev, tx_rsize * sizeof(struct sxgbe_tx_norm_desc), tx_ring->dma_tx, tx_ring->dma_tx_phy); @@ -1221,11 +1221,10 @@ static int sxgbe_release(struct net_device *dev) return 0; } - /* Prepare first Tx descriptor for doing TSO operation */ -void sxgbe_tso_prepare(struct sxgbe_priv_data *priv, - struct sxgbe_tx_norm_desc *first_desc, - struct sk_buff *skb) +static void sxgbe_tso_prepare(struct sxgbe_priv_data *priv, + struct sxgbe_tx_norm_desc *first_desc, + struct sk_buff *skb) { unsigned int total_hdr_len, tcp_hdr_len; @@ -1914,40 +1913,6 @@ static void sxgbe_set_rx_mode(struct net_device *dev) readl(ioaddr + SXGBE_HASH_LOW)); } -/** - * sxgbe_config - entry point for changing configuration mode passed on by - * ifconfig - * @dev : pointer to the device structure - * @map : pointer to the device mapping structure - * Description: - * This function is a driver entry point which gets called by the kernel - * whenever some device configuration is changed. - * Return value: - * This function returns 0 if success and appropriate error otherwise. - */ -static int sxgbe_config(struct net_device *dev, struct ifmap *map) -{ - struct sxgbe_priv_data *priv = netdev_priv(dev); - - /* Can't act on a running interface */ - if (dev->flags & IFF_UP) - return -EBUSY; - - /* Don't allow changing the I/O address */ - if (map->base_addr != (unsigned long)priv->ioaddr) { - netdev_warn(dev, "can't change I/O address\n"); - return -EOPNOTSUPP; - } - - /* Don't allow changing the IRQ */ - if (map->irq != priv->irq) { - netdev_warn(dev, "not change IRQ number %d\n", priv->irq); - return -EOPNOTSUPP; - } - - return 0; -} - #ifdef CONFIG_NET_POLL_CONTROLLER /** * sxgbe_poll_controller - entry point for polling receive by device @@ -2009,7 +1974,6 @@ static const struct net_device_ops sxgbe_netdev_ops = { .ndo_set_rx_mode = sxgbe_set_rx_mode, .ndo_tx_timeout = sxgbe_tx_timeout, .ndo_do_ioctl = sxgbe_ioctl, - .ndo_set_config = sxgbe_config, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = sxgbe_poll_controller, #endif diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index d940034acdd4aa..93cf4f63f42646 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2214,27 +2214,6 @@ static void stmmac_tx_timeout(struct net_device *dev) stmmac_tx_err(priv); } -/* Configuration changes (passed on by ifconfig) */ -static int stmmac_config(struct net_device *dev, struct ifmap *map) -{ - if (dev->flags & IFF_UP) /* can't act on a running interface */ - return -EBUSY; - - /* Don't allow changing the I/O address */ - if (map->base_addr != dev->base_addr) { - pr_warn("%s: can't change I/O address\n", dev->name); - return -EOPNOTSUPP; - } - - /* Don't allow changing the IRQ */ - if (map->irq != dev->irq) { - pr_warn("%s: not change IRQ number %d\n", dev->name, dev->irq); - return -EOPNOTSUPP; - } - - return 0; -} - /** * stmmac_set_rx_mode - entry point for multicast addressing * @dev : pointer to the device structure @@ -2600,7 +2579,6 @@ static const struct net_device_ops stmmac_netdev_ops = { .ndo_set_rx_mode = stmmac_set_rx_mode, .ndo_tx_timeout = stmmac_tx_timeout, .ndo_do_ioctl = stmmac_ioctl, - .ndo_set_config = stmmac_config, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = stmmac_poll_controller, #endif diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index a468eb10782361..a5b1e1b776fe33 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -205,10 +205,13 @@ int stmmac_mdio_register(struct net_device *ndev) if (new_bus == NULL) return -ENOMEM; - if (mdio_bus_data->irqs) + if (mdio_bus_data->irqs) { irqlist = mdio_bus_data->irqs; - else + } else { + for (addr = 0; addr < PHY_MAX_ADDR; addr++) + priv->mii_irq[addr] = PHY_POLL; irqlist = priv->mii_irq; + } #ifdef CONFIG_OF if (priv->device->of_node) diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index 73f74f36943717..7399a52f7c260a 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -313,19 +313,6 @@ static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, }; static struct mii_bus *cpmac_mii; -static int cpmac_config(struct net_device *dev, struct ifmap *map) -{ - if (dev->flags & IFF_UP) - return -EBUSY; - - /* Don't allow changing the I/O address */ - if (map->base_addr != dev->base_addr) - return -EOPNOTSUPP; - - /* ignore other fields */ - return 0; -} - static void cpmac_set_multicast_list(struct net_device *dev) { struct netdev_hw_addr *ha; @@ -1100,7 +1087,6 @@ static const struct net_device_ops cpmac_netdev_ops = { .ndo_tx_timeout = cpmac_tx_timeout, .ndo_set_rx_mode = cpmac_set_multicast_list, .ndo_do_ioctl = cpmac_ioctl, - .ndo_set_config = cpmac_config, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 36aa109416c4c3..d14c8da5316014 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -248,20 +248,31 @@ struct cpsw_ss_regs { #define TS_131 (1<<11) /* Time Sync Dest IP Addr 131 enable */ #define TS_130 (1<<10) /* Time Sync Dest IP Addr 130 enable */ #define TS_129 (1<<9) /* Time Sync Dest IP Addr 129 enable */ -#define TS_BIT8 (1<<8) /* ts_ttl_nonzero? */ +#define TS_TTL_NONZERO (1<<8) /* Time Sync Time To Live Non-zero enable */ +#define TS_ANNEX_F_EN (1<<6) /* Time Sync Annex F enable */ #define TS_ANNEX_D_EN (1<<4) /* Time Sync Annex D enable */ #define TS_LTYPE2_EN (1<<3) /* Time Sync LTYPE 2 enable */ #define TS_LTYPE1_EN (1<<2) /* Time Sync LTYPE 1 enable */ #define TS_TX_EN (1<<1) /* Time Sync Transmit Enable */ #define TS_RX_EN (1<<0) /* Time Sync Receive Enable */ -#define CTRL_TS_BITS \ - (TS_320 | TS_319 | TS_132 | TS_131 | TS_130 | TS_129 | TS_BIT8 | \ - TS_ANNEX_D_EN | TS_LTYPE1_EN) +#define CTRL_V2_TS_BITS \ + (TS_320 | TS_319 | TS_132 | TS_131 | TS_130 | TS_129 |\ + TS_TTL_NONZERO | TS_ANNEX_D_EN | TS_LTYPE1_EN) -#define CTRL_ALL_TS_MASK (CTRL_TS_BITS | TS_TX_EN | TS_RX_EN) -#define CTRL_TX_TS_BITS (CTRL_TS_BITS | TS_TX_EN) -#define CTRL_RX_TS_BITS (CTRL_TS_BITS | TS_RX_EN) +#define CTRL_V2_ALL_TS_MASK (CTRL_V2_TS_BITS | TS_TX_EN | TS_RX_EN) +#define CTRL_V2_TX_TS_BITS (CTRL_V2_TS_BITS | TS_TX_EN) +#define CTRL_V2_RX_TS_BITS (CTRL_V2_TS_BITS | TS_RX_EN) + + +#define CTRL_V3_TS_BITS \ + (TS_320 | TS_319 | TS_132 | TS_131 | TS_130 | TS_129 |\ + TS_TTL_NONZERO | TS_ANNEX_F_EN | TS_ANNEX_D_EN |\ + TS_LTYPE1_EN) + +#define CTRL_V3_ALL_TS_MASK (CTRL_V3_TS_BITS | TS_TX_EN | TS_RX_EN) +#define CTRL_V3_TX_TS_BITS (CTRL_V3_TS_BITS | TS_TX_EN) +#define CTRL_V3_RX_TS_BITS (CTRL_V3_TS_BITS | TS_RX_EN) /* Bit definitions for the CPSW2_TS_SEQ_MTYPE register */ #define TS_SEQ_ID_OFFSET_SHIFT (16) /* Time Sync Sequence ID Offset */ @@ -1376,13 +1387,27 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv) slave = &priv->slaves[priv->data.active_slave]; ctrl = slave_read(slave, CPSW2_CONTROL); - ctrl &= ~CTRL_ALL_TS_MASK; + switch (priv->version) { + case CPSW_VERSION_2: + ctrl &= ~CTRL_V2_ALL_TS_MASK; - if (priv->cpts->tx_enable) - ctrl |= CTRL_TX_TS_BITS; + if (priv->cpts->tx_enable) + ctrl |= CTRL_V2_TX_TS_BITS; - if (priv->cpts->rx_enable) - ctrl |= CTRL_RX_TS_BITS; + if (priv->cpts->rx_enable) + ctrl |= CTRL_V2_RX_TS_BITS; + break; + case CPSW_VERSION_3: + default: + ctrl &= ~CTRL_V3_ALL_TS_MASK; + + if (priv->cpts->tx_enable) + ctrl |= CTRL_V3_TX_TS_BITS; + + if (priv->cpts->rx_enable) + ctrl |= CTRL_V3_RX_TS_BITS; + break; + } mtype = (30 << TS_SEQ_ID_OFFSET_SHIFT) | EVENT_MSG_BITS; @@ -1398,7 +1423,8 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) struct hwtstamp_config cfg; if (priv->version != CPSW_VERSION_1 && - priv->version != CPSW_VERSION_2) + priv->version != CPSW_VERSION_2 && + priv->version != CPSW_VERSION_3) return -EOPNOTSUPP; if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) @@ -1443,6 +1469,7 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) cpsw_hwtstamp_v1(priv); break; case CPSW_VERSION_2: + case CPSW_VERSION_3: cpsw_hwtstamp_v2(priv); break; default: @@ -1459,7 +1486,8 @@ static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) struct hwtstamp_config cfg; if (priv->version != CPSW_VERSION_1 && - priv->version != CPSW_VERSION_2) + priv->version != CPSW_VERSION_2 && + priv->version != CPSW_VERSION_3) return -EOPNOTSUPP; cfg.flags = 0; diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c index 243513980b5151..6b56f85951e581 100644 --- a/drivers/net/ethernet/ti/cpts.c +++ b/drivers/net/ethernet/ti/cpts.c @@ -236,13 +236,11 @@ static void cpts_overflow_check(struct work_struct *work) schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD); } -#define CPTS_REF_CLOCK_NAME "cpsw_cpts_rft_clk" - -static void cpts_clk_init(struct cpts *cpts) +static void cpts_clk_init(struct device *dev, struct cpts *cpts) { - cpts->refclk = clk_get(NULL, CPTS_REF_CLOCK_NAME); + cpts->refclk = devm_clk_get(dev, "cpts"); if (IS_ERR(cpts->refclk)) { - pr_err("Failed to clk_get %s\n", CPTS_REF_CLOCK_NAME); + dev_err(dev, "Failed to get cpts refclk\n"); cpts->refclk = NULL; return; } @@ -252,7 +250,6 @@ static void cpts_clk_init(struct cpts *cpts) static void cpts_clk_release(struct cpts *cpts) { clk_disable(cpts->refclk); - clk_put(cpts->refclk); } static int cpts_match(struct sk_buff *skb, unsigned int ptp_class, @@ -390,7 +387,7 @@ int cpts_register(struct device *dev, struct cpts *cpts, for (i = 0; i < CPTS_MAX_EVENTS; i++) list_add(&cpts->pool_data[i].list, &cpts->pool); - cpts_clk_init(cpts); + cpts_clk_init(dev, cpts); cpts_write32(cpts, CPTS_EN, control); cpts_write32(cpts, TS_PEND_EN, int_enable); diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c index 0cca9dec5d8277..34e97eca561c27 100644 --- a/drivers/net/ethernet/ti/davinci_mdio.c +++ b/drivers/net/ethernet/ti/davinci_mdio.c @@ -321,15 +321,14 @@ static int davinci_mdio_probe(struct platform_device *pdev) struct phy_device *phy; int ret, addr; - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - data->bus = mdiobus_alloc(); + data->bus = devm_mdiobus_alloc(dev); if (!data->bus) { dev_err(dev, "failed to alloc mii bus\n"); - ret = -ENOMEM; - goto bail_out; + return -ENOMEM; } if (dev->of_node) { @@ -349,12 +348,9 @@ static int davinci_mdio_probe(struct platform_device *pdev) data->bus->parent = dev; data->bus->priv = data; - /* Select default pin state */ - pinctrl_pm_select_default_state(&pdev->dev); - pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); - data->clk = clk_get(&pdev->dev, "fck"); + data->clk = devm_clk_get(dev, "fck"); if (IS_ERR(data->clk)) { dev_err(dev, "failed to get device clock\n"); ret = PTR_ERR(data->clk); @@ -367,24 +363,9 @@ static int davinci_mdio_probe(struct platform_device *pdev) spin_lock_init(&data->lock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "could not find register map resource\n"); - ret = -ENOENT; - goto bail_out; - } - - res = devm_request_mem_region(dev, res->start, resource_size(res), - dev_name(dev)); - if (!res) { - dev_err(dev, "could not allocate register map resource\n"); - ret = -ENXIO; - goto bail_out; - } - - data->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!data->regs) { - dev_err(dev, "could not map mdio registers\n"); - ret = -ENOMEM; + data->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(data->regs)) { + ret = PTR_ERR(data->regs); goto bail_out; } @@ -406,16 +387,9 @@ static int davinci_mdio_probe(struct platform_device *pdev) return 0; bail_out: - if (data->bus) - mdiobus_free(data->bus); - - if (data->clk) - clk_put(data->clk); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - kfree(data); - return ret; } @@ -423,18 +397,12 @@ static int davinci_mdio_remove(struct platform_device *pdev) { struct davinci_mdio_data *data = platform_get_drvdata(pdev); - if (data->bus) { + if (data->bus) mdiobus_unregister(data->bus); - mdiobus_free(data->bus); - } - if (data->clk) - clk_put(data->clk); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - kfree(data); - return 0; } diff --git a/drivers/net/ethernet/via/Kconfig b/drivers/net/ethernet/via/Kconfig index 8a049a2b44742a..f66ddaee0c877f 100644 --- a/drivers/net/ethernet/via/Kconfig +++ b/drivers/net/ethernet/via/Kconfig @@ -19,7 +19,7 @@ if NET_VENDOR_VIA config VIA_RHINE tristate "VIA Rhine support" - depends on PCI + depends on (PCI || USE_OF) select CRC32 select MII ---help--- diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index f61dc2b72bb2f4..981be0154be393 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -94,6 +94,10 @@ static const int multicast_filter_limit = 32; #include #include #include +#include +#include +#include +#include #include #include #include @@ -116,13 +120,6 @@ static const int multicast_filter_limit = 32; static const char version[] = "v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker"; -/* This driver was written to use PCI memory space. Some early versions - of the Rhine may only work correctly with I/O space accesses. */ -#ifdef CONFIG_VIA_RHINE_MMIO -#define USE_MMIO -#else -#endif - MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver"); MODULE_LICENSE("GPL"); @@ -260,6 +257,12 @@ enum rhine_quirks { rq6patterns = 0x0040, /* 6 instead of 4 patterns for WOL */ rqStatusWBRace = 0x0080, /* Tx Status Writeback Error possible */ rqRhineI = 0x0100, /* See comment below */ + rqIntPHY = 0x0200, /* Integrated PHY */ + rqMgmt = 0x0400, /* Management adapter */ + rqNeedEnMMIO = 0x0800, /* Whether the core needs to be + * switched from PIO mode to MMIO + * (only applies to PCI) + */ }; /* * rqRhineI: VT86C100A (aka Rhine-I) uses different bits to enable @@ -279,6 +282,15 @@ static DEFINE_PCI_DEVICE_TABLE(rhine_pci_tbl) = { }; MODULE_DEVICE_TABLE(pci, rhine_pci_tbl); +/* OpenFirmware identifiers for platform-bus devices + * The .data field is currently only used to store quirks + */ +static u32 vt8500_quirks = rqWOL | rqForceReset | rq6patterns; +static struct of_device_id rhine_of_tbl[] = { + { .compatible = "via,vt8500-rhine", .data = &vt8500_quirks }, + { } /* terminate list */ +}; +MODULE_DEVICE_TABLE(of, rhine_of_tbl); /* Offsets to the device registers. */ enum register_offsets { @@ -338,13 +350,11 @@ enum bcr1_bits { BCR1_MED1=0x80, /* for VT6102 */ }; -#ifdef USE_MMIO /* Registers we check that mmio and reg are the same. */ static const int mmio_verify_registers[] = { RxConfig, TxConfig, IntrEnable, ConfigA, ConfigB, ConfigC, ConfigD, 0 }; -#endif /* Bits in the interrupt status/mask registers. */ enum intr_status_bits { @@ -446,7 +456,7 @@ struct rhine_private { unsigned char *tx_bufs; dma_addr_t tx_bufs_dma; - struct pci_dev *pdev; + int irq; long pioaddr; struct net_device *dev; struct napi_struct napi; @@ -649,20 +659,46 @@ static void rhine_chip_reset(struct net_device *dev) "failed" : "succeeded"); } -#ifdef USE_MMIO static void enable_mmio(long pioaddr, u32 quirks) { int n; - if (quirks & rqRhineI) { - /* More recent docs say that this bit is reserved ... */ - n = inb(pioaddr + ConfigA) | 0x20; - outb(n, pioaddr + ConfigA); - } else { - n = inb(pioaddr + ConfigD) | 0x80; - outb(n, pioaddr + ConfigD); + + if (quirks & rqNeedEnMMIO) { + if (quirks & rqRhineI) { + /* More recent docs say that this bit is reserved */ + n = inb(pioaddr + ConfigA) | 0x20; + outb(n, pioaddr + ConfigA); + } else { + n = inb(pioaddr + ConfigD) | 0x80; + outb(n, pioaddr + ConfigD); + } } } -#endif + +static inline int verify_mmio(struct device *hwdev, + long pioaddr, + void __iomem *ioaddr, + u32 quirks) +{ + if (quirks & rqNeedEnMMIO) { + int i = 0; + + /* Check that selected MMIO registers match the PIO ones */ + while (mmio_verify_registers[i]) { + int reg = mmio_verify_registers[i++]; + unsigned char a = inb(pioaddr+reg); + unsigned char b = readb(ioaddr+reg); + + if (a != b) { + dev_err(hwdev, + "MMIO do not match PIO [%02x] (%02x != %02x)\n", + reg, a, b); + return -EIO; + } + } + } + return 0; +} /* * Loads bytes 0x00-0x05, 0x6E-0x6F, 0x78-0x7B from EEPROM @@ -682,14 +718,12 @@ static void rhine_reload_eeprom(long pioaddr, struct net_device *dev) if (i > 512) pr_info("%4d cycles used @ %s:%d\n", i, __func__, __LINE__); -#ifdef USE_MMIO /* * Reloading from EEPROM overwrites ConfigA-D, so we must re-enable * MMIO. If reloading EEPROM was done first this could be avoided, but * it is not known if that still works with the "win98-reboot" problem. */ enable_mmio(pioaddr, rp->quirks); -#endif /* Turn off EEPROM-controlled wake-up (magic packet) */ if (rp->quirks & rqWOL) @@ -701,7 +735,7 @@ static void rhine_reload_eeprom(long pioaddr, struct net_device *dev) static void rhine_poll(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); - const int irq = rp->pdev->irq; + const int irq = rp->irq; disable_irq(irq); rhine_interrupt(irq, dev); @@ -846,7 +880,8 @@ static void rhine_hw_init(struct net_device *dev, long pioaddr) msleep(5); /* Reload EEPROM controlled bytes cleared by soft reset */ - rhine_reload_eeprom(pioaddr, dev); + if (dev_is_pci(dev->dev.parent)) + rhine_reload_eeprom(pioaddr, dev); } static const struct net_device_ops rhine_netdev_ops = { @@ -867,125 +902,37 @@ static const struct net_device_ops rhine_netdev_ops = { #endif }; -static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +static int rhine_init_one_common(struct device *hwdev, u32 quirks, + long pioaddr, void __iomem *ioaddr, int irq) { struct net_device *dev; struct rhine_private *rp; - int i, rc; - u32 quirks; - long pioaddr; - long memaddr; - void __iomem *ioaddr; - int io_size, phy_id; + int i, rc, phy_id; const char *name; -#ifdef USE_MMIO - int bar = 1; -#else - int bar = 0; -#endif - -/* when built into the kernel, we only print version if device is found */ -#ifndef MODULE - pr_info_once("%s\n", version); -#endif - - io_size = 256; - phy_id = 0; - quirks = 0; - name = "Rhine"; - if (pdev->revision < VTunknown0) { - quirks = rqRhineI; - io_size = 128; - } - else if (pdev->revision >= VT6102) { - quirks = rqWOL | rqForceReset; - if (pdev->revision < VT6105) { - name = "Rhine II"; - quirks |= rqStatusWBRace; /* Rhine-II exclusive */ - } - else { - phy_id = 1; /* Integrated PHY, phy_id fixed to 1 */ - if (pdev->revision >= VT6105_B0) - quirks |= rq6patterns; - if (pdev->revision < VT6105M) - name = "Rhine III"; - else - name = "Rhine III (Management Adapter)"; - } - } - - rc = pci_enable_device(pdev); - if (rc) - goto err_out; /* this should always be supported */ - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + rc = dma_set_mask(hwdev, DMA_BIT_MASK(32)); if (rc) { - dev_err(&pdev->dev, - "32-bit PCI DMA addresses not supported by the card!?\n"); - goto err_out_pci_disable; - } - - /* sanity check */ - if ((pci_resource_len(pdev, 0) < io_size) || - (pci_resource_len(pdev, 1) < io_size)) { - rc = -EIO; - dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n"); - goto err_out_pci_disable; + dev_err(hwdev, "32-bit DMA addresses not supported by the card!?\n"); + goto err_out; } - pioaddr = pci_resource_start(pdev, 0); - memaddr = pci_resource_start(pdev, 1); - - pci_set_master(pdev); - dev = alloc_etherdev(sizeof(struct rhine_private)); if (!dev) { rc = -ENOMEM; - goto err_out_pci_disable; + goto err_out; } - SET_NETDEV_DEV(dev, &pdev->dev); + SET_NETDEV_DEV(dev, hwdev); rp = netdev_priv(dev); rp->dev = dev; rp->quirks = quirks; rp->pioaddr = pioaddr; - rp->pdev = pdev; + rp->base = ioaddr; + rp->irq = irq; rp->msg_enable = netif_msg_init(debug, RHINE_MSG_DEFAULT); - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) - goto err_out_free_netdev; - - ioaddr = pci_iomap(pdev, bar, io_size); - if (!ioaddr) { - rc = -EIO; - dev_err(&pdev->dev, - "ioremap failed for device %s, region 0x%X @ 0x%lX\n", - pci_name(pdev), io_size, memaddr); - goto err_out_free_res; - } - -#ifdef USE_MMIO - enable_mmio(pioaddr, quirks); - - /* Check that selected MMIO registers match the PIO ones */ - i = 0; - while (mmio_verify_registers[i]) { - int reg = mmio_verify_registers[i++]; - unsigned char a = inb(pioaddr+reg); - unsigned char b = readb(ioaddr+reg); - if (a != b) { - rc = -EIO; - dev_err(&pdev->dev, - "MMIO do not match PIO [%02x] (%02x != %02x)\n", - reg, a, b); - goto err_out_unmap; - } - } -#endif /* USE_MMIO */ - - rp->base = ioaddr; + phy_id = rp->quirks & rqIntPHY ? 1 : 0; u64_stats_init(&rp->tx_stats.syncp); u64_stats_init(&rp->rx_stats.syncp); @@ -1030,7 +977,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rp->quirks & rqRhineI) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; - if (pdev->revision >= VT6105M) + if (rp->quirks & rqMgmt) dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER; @@ -1038,18 +985,21 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* dev->name not defined before register_netdev()! */ rc = register_netdev(dev); if (rc) - goto err_out_unmap; + goto err_out_free_netdev; + + if (rp->quirks & rqRhineI) + name = "Rhine"; + else if (rp->quirks & rqStatusWBRace) + name = "Rhine II"; + else if (rp->quirks & rqMgmt) + name = "Rhine III (Management Adapter)"; + else + name = "Rhine III"; netdev_info(dev, "VIA %s at 0x%lx, %pM, IRQ %d\n", - name, -#ifdef USE_MMIO - memaddr, -#else - (long)ioaddr, -#endif - dev->dev_addr, pdev->irq); + name, (long)ioaddr, dev->dev_addr, rp->irq); - pci_set_drvdata(pdev, dev); + dev_set_drvdata(hwdev, dev); { u16 mii_cmd; @@ -1078,41 +1028,158 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; +err_out_free_netdev: + free_netdev(dev); +err_out: + return rc; +} + +static int rhine_init_one_pci(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct device *hwdev = &pdev->dev; + int rc; + long pioaddr, memaddr; + void __iomem *ioaddr; + int io_size = pdev->revision < VTunknown0 ? 128 : 256; + +/* This driver was written to use PCI memory space. Some early versions + * of the Rhine may only work correctly with I/O space accesses. + * TODO: determine for which revisions this is true and assign the flag + * in code as opposed to this Kconfig option (???) + */ +#ifdef CONFIG_VIA_RHINE_MMIO + u32 quirks = rqNeedEnMMIO; +#else + u32 quirks = 0; +#endif + +/* when built into the kernel, we only print version if device is found */ +#ifndef MODULE + pr_info_once("%s\n", version); +#endif + + rc = pci_enable_device(pdev); + if (rc) + goto err_out; + + if (pdev->revision < VTunknown0) { + quirks |= rqRhineI; + } else if (pdev->revision >= VT6102) { + quirks |= rqWOL | rqForceReset; + if (pdev->revision < VT6105) { + quirks |= rqStatusWBRace; + } else { + quirks |= rqIntPHY; + if (pdev->revision >= VT6105_B0) + quirks |= rq6patterns; + if (pdev->revision >= VT6105M) + quirks |= rqMgmt; + } + } + + /* sanity check */ + if ((pci_resource_len(pdev, 0) < io_size) || + (pci_resource_len(pdev, 1) < io_size)) { + rc = -EIO; + dev_err(hwdev, "Insufficient PCI resources, aborting\n"); + goto err_out_pci_disable; + } + + pioaddr = pci_resource_start(pdev, 0); + memaddr = pci_resource_start(pdev, 1); + + pci_set_master(pdev); + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out_pci_disable; + + ioaddr = pci_iomap(pdev, (quirks & rqNeedEnMMIO ? 1 : 0), io_size); + if (!ioaddr) { + rc = -EIO; + dev_err(hwdev, + "ioremap failed for device %s, region 0x%X @ 0x%lX\n", + dev_name(hwdev), io_size, memaddr); + goto err_out_free_res; + } + + enable_mmio(pioaddr, quirks); + + rc = verify_mmio(hwdev, pioaddr, ioaddr, quirks); + if (rc) + goto err_out_unmap; + + rc = rhine_init_one_common(&pdev->dev, quirks, + pioaddr, ioaddr, pdev->irq); + if (!rc) + return 0; + err_out_unmap: pci_iounmap(pdev, ioaddr); err_out_free_res: pci_release_regions(pdev); -err_out_free_netdev: - free_netdev(dev); err_out_pci_disable: pci_disable_device(pdev); err_out: return rc; } +static int rhine_init_one_platform(struct platform_device *pdev) +{ + const struct of_device_id *match; + const u32 *quirks; + int irq; + struct resource *res; + void __iomem *ioaddr; + + match = of_match_device(rhine_of_tbl, &pdev->dev); + if (!match) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ioaddr)) + return PTR_ERR(ioaddr); + + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (!irq) + return -EINVAL; + + quirks = match->data; + if (!quirks) + return -EINVAL; + + return rhine_init_one_common(&pdev->dev, *quirks, + (long)ioaddr, ioaddr, irq); +} + static int alloc_ring(struct net_device* dev) { struct rhine_private *rp = netdev_priv(dev); + struct device *hwdev = dev->dev.parent; void *ring; dma_addr_t ring_dma; - ring = pci_alloc_consistent(rp->pdev, - RX_RING_SIZE * sizeof(struct rx_desc) + - TX_RING_SIZE * sizeof(struct tx_desc), - &ring_dma); + ring = dma_alloc_coherent(hwdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + &ring_dma, + GFP_ATOMIC); if (!ring) { netdev_err(dev, "Could not allocate DMA memory\n"); return -ENOMEM; } if (rp->quirks & rqRhineI) { - rp->tx_bufs = pci_alloc_consistent(rp->pdev, - PKT_BUF_SZ * TX_RING_SIZE, - &rp->tx_bufs_dma); + rp->tx_bufs = dma_alloc_coherent(hwdev, + PKT_BUF_SZ * TX_RING_SIZE, + &rp->tx_bufs_dma, + GFP_ATOMIC); if (rp->tx_bufs == NULL) { - pci_free_consistent(rp->pdev, - RX_RING_SIZE * sizeof(struct rx_desc) + - TX_RING_SIZE * sizeof(struct tx_desc), - ring, ring_dma); + dma_free_coherent(hwdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + ring, ring_dma); return -ENOMEM; } } @@ -1128,16 +1195,17 @@ static int alloc_ring(struct net_device* dev) static void free_ring(struct net_device* dev) { struct rhine_private *rp = netdev_priv(dev); + struct device *hwdev = dev->dev.parent; - pci_free_consistent(rp->pdev, - RX_RING_SIZE * sizeof(struct rx_desc) + - TX_RING_SIZE * sizeof(struct tx_desc), - rp->rx_ring, rp->rx_ring_dma); + dma_free_coherent(hwdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + rp->rx_ring, rp->rx_ring_dma); rp->tx_ring = NULL; if (rp->tx_bufs) - pci_free_consistent(rp->pdev, PKT_BUF_SZ * TX_RING_SIZE, - rp->tx_bufs, rp->tx_bufs_dma); + dma_free_coherent(hwdev, PKT_BUF_SZ * TX_RING_SIZE, + rp->tx_bufs, rp->tx_bufs_dma); rp->tx_bufs = NULL; @@ -1146,6 +1214,7 @@ static void free_ring(struct net_device* dev) static void alloc_rbufs(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); + struct device *hwdev = dev->dev.parent; dma_addr_t next; int i; @@ -1174,9 +1243,9 @@ static void alloc_rbufs(struct net_device *dev) break; rp->rx_skbuff_dma[i] = - pci_map_single(rp->pdev, skb->data, rp->rx_buf_sz, - PCI_DMA_FROMDEVICE); - if (dma_mapping_error(&rp->pdev->dev, rp->rx_skbuff_dma[i])) { + dma_map_single(hwdev, skb->data, rp->rx_buf_sz, + DMA_FROM_DEVICE); + if (dma_mapping_error(hwdev, rp->rx_skbuff_dma[i])) { rp->rx_skbuff_dma[i] = 0; dev_kfree_skb(skb); break; @@ -1190,6 +1259,7 @@ static void alloc_rbufs(struct net_device *dev) static void free_rbufs(struct net_device* dev) { struct rhine_private *rp = netdev_priv(dev); + struct device *hwdev = dev->dev.parent; int i; /* Free all the skbuffs in the Rx queue. */ @@ -1197,9 +1267,9 @@ static void free_rbufs(struct net_device* dev) rp->rx_ring[i].rx_status = 0; rp->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ if (rp->rx_skbuff[i]) { - pci_unmap_single(rp->pdev, + dma_unmap_single(hwdev, rp->rx_skbuff_dma[i], - rp->rx_buf_sz, PCI_DMA_FROMDEVICE); + rp->rx_buf_sz, DMA_FROM_DEVICE); dev_kfree_skb(rp->rx_skbuff[i]); } rp->rx_skbuff[i] = NULL; @@ -1230,6 +1300,7 @@ static void alloc_tbufs(struct net_device* dev) static void free_tbufs(struct net_device* dev) { struct rhine_private *rp = netdev_priv(dev); + struct device *hwdev = dev->dev.parent; int i; for (i = 0; i < TX_RING_SIZE; i++) { @@ -1238,10 +1309,10 @@ static void free_tbufs(struct net_device* dev) rp->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ if (rp->tx_skbuff[i]) { if (rp->tx_skbuff_dma[i]) { - pci_unmap_single(rp->pdev, + dma_unmap_single(hwdev, rp->tx_skbuff_dma[i], rp->tx_skbuff[i]->len, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); } dev_kfree_skb(rp->tx_skbuff[i]); } @@ -1469,7 +1540,7 @@ static void init_registers(struct net_device *dev) rhine_set_rx_mode(dev); - if (rp->pdev->revision >= VT6105M) + if (rp->quirks & rqMgmt) rhine_init_cam_filter(dev); napi_enable(&rp->napi); @@ -1581,16 +1652,15 @@ static int rhine_open(struct net_device *dev) void __iomem *ioaddr = rp->base; int rc; - rc = request_irq(rp->pdev->irq, rhine_interrupt, IRQF_SHARED, dev->name, - dev); + rc = request_irq(rp->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev); if (rc) return rc; - netif_dbg(rp, ifup, dev, "%s() irq %d\n", __func__, rp->pdev->irq); + netif_dbg(rp, ifup, dev, "%s() irq %d\n", __func__, rp->irq); rc = alloc_ring(dev); if (rc) { - free_irq(rp->pdev->irq, dev); + free_irq(rp->irq, dev); return rc; } alloc_rbufs(dev); @@ -1659,6 +1729,7 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb, struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); + struct device *hwdev = dev->dev.parent; void __iomem *ioaddr = rp->base; unsigned entry; @@ -1695,9 +1766,9 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb, rp->tx_bufs)); } else { rp->tx_skbuff_dma[entry] = - pci_map_single(rp->pdev, skb->data, skb->len, - PCI_DMA_TODEVICE); - if (dma_mapping_error(&rp->pdev->dev, rp->tx_skbuff_dma[entry])) { + dma_map_single(hwdev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(hwdev, rp->tx_skbuff_dma[entry])) { dev_kfree_skb_any(skb); rp->tx_skbuff_dma[entry] = 0; dev->stats.tx_dropped++; @@ -1788,6 +1859,7 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) static void rhine_tx(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); + struct device *hwdev = dev->dev.parent; int txstatus = 0, entry = rp->dirty_tx % TX_RING_SIZE; /* find and cleanup dirty tx descriptors */ @@ -1831,10 +1903,10 @@ static void rhine_tx(struct net_device *dev) } /* Free the original skb. */ if (rp->tx_skbuff_dma[entry]) { - pci_unmap_single(rp->pdev, + dma_unmap_single(hwdev, rp->tx_skbuff_dma[entry], rp->tx_skbuff[entry]->len, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); } dev_consume_skb_any(rp->tx_skbuff[entry]); rp->tx_skbuff[entry] = NULL; @@ -1863,6 +1935,7 @@ static inline u16 rhine_get_vlan_tci(struct sk_buff *skb, int data_size) static int rhine_rx(struct net_device *dev, int limit) { struct rhine_private *rp = netdev_priv(dev); + struct device *hwdev = dev->dev.parent; int count; int entry = rp->cur_rx % RX_RING_SIZE; @@ -1924,19 +1997,19 @@ static int rhine_rx(struct net_device *dev, int limit) if (pkt_len < rx_copybreak) skb = netdev_alloc_skb_ip_align(dev, pkt_len); if (skb) { - pci_dma_sync_single_for_cpu(rp->pdev, - rp->rx_skbuff_dma[entry], - rp->rx_buf_sz, - PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(hwdev, + rp->rx_skbuff_dma[entry], + rp->rx_buf_sz, + DMA_FROM_DEVICE); skb_copy_to_linear_data(skb, rp->rx_skbuff[entry]->data, pkt_len); skb_put(skb, pkt_len); - pci_dma_sync_single_for_device(rp->pdev, - rp->rx_skbuff_dma[entry], - rp->rx_buf_sz, - PCI_DMA_FROMDEVICE); + dma_sync_single_for_device(hwdev, + rp->rx_skbuff_dma[entry], + rp->rx_buf_sz, + DMA_FROM_DEVICE); } else { skb = rp->rx_skbuff[entry]; if (skb == NULL) { @@ -1945,10 +2018,10 @@ static int rhine_rx(struct net_device *dev, int limit) } rp->rx_skbuff[entry] = NULL; skb_put(skb, pkt_len); - pci_unmap_single(rp->pdev, + dma_unmap_single(hwdev, rp->rx_skbuff_dma[entry], rp->rx_buf_sz, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); } if (unlikely(desc_length & DescTag)) @@ -1979,10 +2052,11 @@ static int rhine_rx(struct net_device *dev, int limit) if (skb == NULL) break; /* Better luck next round. */ rp->rx_skbuff_dma[entry] = - pci_map_single(rp->pdev, skb->data, + dma_map_single(hwdev, skb->data, rp->rx_buf_sz, - PCI_DMA_FROMDEVICE); - if (dma_mapping_error(&rp->pdev->dev, rp->rx_skbuff_dma[entry])) { + DMA_FROM_DEVICE); + if (dma_mapping_error(hwdev, + rp->rx_skbuff_dma[entry])) { dev_kfree_skb(skb); rp->rx_skbuff_dma[entry] = 0; break; @@ -2103,7 +2177,7 @@ static void rhine_set_rx_mode(struct net_device *dev) /* Too many to match, or accept all multicasts. */ iowrite32(0xffffffff, ioaddr + MulticastFilter0); iowrite32(0xffffffff, ioaddr + MulticastFilter1); - } else if (rp->pdev->revision >= VT6105M) { + } else if (rp->quirks & rqMgmt) { int i = 0; u32 mCAMmask = 0; /* 32 mCAMs (6105M and better) */ netdev_for_each_mc_addr(ha, dev) { @@ -2125,7 +2199,7 @@ static void rhine_set_rx_mode(struct net_device *dev) iowrite32(mc_filter[1], ioaddr + MulticastFilter1); } /* enable/disable VLAN receive filtering */ - if (rp->pdev->revision >= VT6105M) { + if (rp->quirks & rqMgmt) { if (dev->flags & IFF_PROMISC) BYTE_REG_BITS_OFF(BCR1_VIDFR, ioaddr + PCIBusConfig1); else @@ -2136,11 +2210,11 @@ static void rhine_set_rx_mode(struct net_device *dev) static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct rhine_private *rp = netdev_priv(dev); + struct device *hwdev = dev->dev.parent; strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); strlcpy(info->version, DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info)); + strlcpy(info->bus_info, dev_name(hwdev), sizeof(info->bus_info)); } static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) @@ -2277,7 +2351,7 @@ static int rhine_close(struct net_device *dev) /* Stop the chip's Tx and Rx processes. */ iowrite16(CmdStop, ioaddr + ChipCmd); - free_irq(rp->pdev->irq, dev); + free_irq(rp->irq, dev); free_rbufs(dev); free_tbufs(dev); free_ring(dev); @@ -2286,7 +2360,7 @@ static int rhine_close(struct net_device *dev) } -static void rhine_remove_one(struct pci_dev *pdev) +static void rhine_remove_one_pci(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct rhine_private *rp = netdev_priv(dev); @@ -2300,7 +2374,21 @@ static void rhine_remove_one(struct pci_dev *pdev) pci_disable_device(pdev); } -static void rhine_shutdown (struct pci_dev *pdev) +static int rhine_remove_one_platform(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct rhine_private *rp = netdev_priv(dev); + + unregister_netdev(dev); + + iounmap(rp->base); + + free_netdev(dev); + + return 0; +} + +static void rhine_shutdown_pci(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct rhine_private *rp = netdev_priv(dev); @@ -2354,8 +2442,7 @@ static void rhine_shutdown (struct pci_dev *pdev) #ifdef CONFIG_PM_SLEEP static int rhine_suspend(struct device *device) { - struct pci_dev *pdev = to_pci_dev(device); - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = dev_get_drvdata(device); struct rhine_private *rp = netdev_priv(dev); if (!netif_running(dev)) @@ -2367,23 +2454,21 @@ static int rhine_suspend(struct device *device) netif_device_detach(dev); - rhine_shutdown(pdev); + if (dev_is_pci(device)) + rhine_shutdown_pci(to_pci_dev(device)); return 0; } static int rhine_resume(struct device *device) { - struct pci_dev *pdev = to_pci_dev(device); - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = dev_get_drvdata(device); struct rhine_private *rp = netdev_priv(dev); if (!netif_running(dev)) return 0; -#ifdef USE_MMIO enable_mmio(rp->pioaddr, rp->quirks); -#endif rhine_power_init(dev); free_tbufs(dev); free_rbufs(dev); @@ -2408,15 +2493,26 @@ static SIMPLE_DEV_PM_OPS(rhine_pm_ops, rhine_suspend, rhine_resume); #endif /* !CONFIG_PM_SLEEP */ -static struct pci_driver rhine_driver = { +static struct pci_driver rhine_driver_pci = { .name = DRV_NAME, .id_table = rhine_pci_tbl, - .probe = rhine_init_one, - .remove = rhine_remove_one, - .shutdown = rhine_shutdown, + .probe = rhine_init_one_pci, + .remove = rhine_remove_one_pci, + .shutdown = rhine_shutdown_pci, .driver.pm = RHINE_PM_OPS, }; +static struct platform_driver rhine_driver_platform = { + .probe = rhine_init_one_platform, + .remove = rhine_remove_one_platform, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = rhine_of_tbl, + .pm = RHINE_PM_OPS, + } +}; + static struct dmi_system_id rhine_dmi_table[] __initdata = { { .ident = "EPIA-M", @@ -2437,6 +2533,8 @@ static struct dmi_system_id rhine_dmi_table[] __initdata = { static int __init rhine_init(void) { + int ret_pci, ret_platform; + /* when a module, this is printed whether or not devices are found in probe */ #ifdef MODULE pr_info("%s\n", version); @@ -2449,13 +2547,19 @@ static int __init rhine_init(void) else if (avoid_D3) pr_info("avoid_D3 set\n"); - return pci_register_driver(&rhine_driver); + ret_pci = pci_register_driver(&rhine_driver_pci); + ret_platform = platform_driver_register(&rhine_driver_platform); + if ((ret_pci < 0) && (ret_platform < 0)) + return ret_pci; + + return 0; } static void __exit rhine_cleanup(void) { - pci_unregister_driver(&rhine_driver); + platform_driver_unregister(&rhine_driver_platform); + pci_unregister_driver(&rhine_driver_pci); } diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index d18f711d0b0cd4..4b7df5a5c966a6 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -28,50 +28,119 @@ #include #include -/* Fwd declaration */ -struct hv_netvsc_packet; -struct ndis_tcp_ip_checksum_info; +/* RSS related */ +#define OID_GEN_RECEIVE_SCALE_CAPABILITIES 0x00010203 /* query only */ +#define OID_GEN_RECEIVE_SCALE_PARAMETERS 0x00010204 /* query and set */ -/* Represent the xfer page packet which contains 1 or more netvsc packet */ -struct xferpage_packet { - struct list_head list_ent; - u32 status; +#define NDIS_OBJECT_TYPE_RSS_CAPABILITIES 0x88 +#define NDIS_OBJECT_TYPE_RSS_PARAMETERS 0x89 - /* # of netvsc packets this xfer packet contains */ - u32 count; +#define NDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2 2 +#define NDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2 2 + +struct ndis_obj_header { + u8 type; + u8 rev; + u16 size; +} __packed; + +/* ndis_recv_scale_cap/cap_flag */ +#define NDIS_RSS_CAPS_MESSAGE_SIGNALED_INTERRUPTS 0x01000000 +#define NDIS_RSS_CAPS_CLASSIFICATION_AT_ISR 0x02000000 +#define NDIS_RSS_CAPS_CLASSIFICATION_AT_DPC 0x04000000 +#define NDIS_RSS_CAPS_USING_MSI_X 0x08000000 +#define NDIS_RSS_CAPS_RSS_AVAILABLE_ON_PORTS 0x10000000 +#define NDIS_RSS_CAPS_SUPPORTS_MSI_X 0x20000000 +#define NDIS_RSS_CAPS_HASH_TYPE_TCP_IPV4 0x00000100 +#define NDIS_RSS_CAPS_HASH_TYPE_TCP_IPV6 0x00000200 +#define NDIS_RSS_CAPS_HASH_TYPE_TCP_IPV6_EX 0x00000400 + +struct ndis_recv_scale_cap { /* NDIS_RECEIVE_SCALE_CAPABILITIES */ + struct ndis_obj_header hdr; + u32 cap_flag; + u32 num_int_msg; + u32 num_recv_que; + u16 num_indirect_tabent; +} __packed; + + +/* ndis_recv_scale_param flags */ +#define NDIS_RSS_PARAM_FLAG_BASE_CPU_UNCHANGED 0x0001 +#define NDIS_RSS_PARAM_FLAG_HASH_INFO_UNCHANGED 0x0002 +#define NDIS_RSS_PARAM_FLAG_ITABLE_UNCHANGED 0x0004 +#define NDIS_RSS_PARAM_FLAG_HASH_KEY_UNCHANGED 0x0008 +#define NDIS_RSS_PARAM_FLAG_DISABLE_RSS 0x0010 + +/* Hash info bits */ +#define NDIS_HASH_FUNC_TOEPLITZ 0x00000001 +#define NDIS_HASH_IPV4 0x00000100 +#define NDIS_HASH_TCP_IPV4 0x00000200 +#define NDIS_HASH_IPV6 0x00000400 +#define NDIS_HASH_IPV6_EX 0x00000800 +#define NDIS_HASH_TCP_IPV6 0x00001000 +#define NDIS_HASH_TCP_IPV6_EX 0x00002000 + +#define NDIS_RSS_INDIRECTION_TABLE_MAX_SIZE_REVISION_2 (128 * 4) +#define NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2 40 + +#define ITAB_NUM 128 +#define HASH_KEYLEN NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2 +extern u8 netvsc_hash_key[]; + +struct ndis_recv_scale_param { /* NDIS_RECEIVE_SCALE_PARAMETERS */ + struct ndis_obj_header hdr; + + /* Qualifies the rest of the information */ + u16 flag; + + /* The base CPU number to do receive processing. not used */ + u16 base_cpu_number; + + /* This describes the hash function and type being enabled */ + u32 hashinfo; + + /* The size of indirection table array */ + u16 indirect_tabsize; + + /* The offset of the indirection table from the beginning of this + * structure + */ + u32 indirect_taboffset; + + /* The size of the hash secret key */ + u16 hashkey_size; + + /* The offset of the secret key from the beginning of this structure */ + u32 kashkey_offset; + + u32 processor_masks_offset; + u32 num_processor_masks; + u32 processor_masks_entry_size; }; +/* Fwd declaration */ +struct ndis_tcp_ip_checksum_info; + /* * Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame * within the RNDIS */ struct hv_netvsc_packet { /* Bookkeeping stuff */ - struct list_head list_ent; u32 status; struct hv_device *device; bool is_data_pkt; u16 vlan_tci; - /* - * Valid only for receives when we break a xfer page packet - * into multiple netvsc packets - */ - struct xferpage_packet *xfer_page_pkt; + u16 q_idx; + struct vmbus_channel *channel; - union { - struct { - u64 recv_completion_tid; - void *recv_completion_ctx; - void (*recv_completion)(void *context); - } recv; - struct { - u64 send_completion_tid; - void *send_completion_ctx; - void (*send_completion)(void *context); - } send; - } completion; + u64 send_completion_tid; + void *send_completion_ctx; + void (*send_completion)(void *context); + + u32 send_buf_index; /* This points to the memory after page_buf */ struct rndis_message *rndis_msg; @@ -120,6 +189,7 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, int netvsc_recv_callback(struct hv_device *device_obj, struct hv_netvsc_packet *packet, struct ndis_tcp_ip_checksum_info *csum_info); +void netvsc_channel_cb(void *context); int rndis_filter_open(struct hv_device *dev); int rndis_filter_close(struct hv_device *dev); int rndis_filter_device_add(struct hv_device *dev, @@ -514,14 +584,16 @@ struct nvsp_message { #define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */ #define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY (1024*1024*15) /* 15MB */ +#define NETVSC_SEND_BUFFER_SIZE (1024 * 1024) /* 1MB */ +#define NETVSC_INVALID_INDEX -1 -#define NETVSC_RECEIVE_BUFFER_ID 0xcafe -/* Preallocated receive packets */ -#define NETVSC_RECEIVE_PACKETLIST_COUNT 256 +#define NETVSC_RECEIVE_BUFFER_ID 0xcafe #define NETVSC_PACKET_SIZE 2048 +#define VRSS_SEND_TAB_SIZE 16 + /* Per netvsc channel-specific */ struct netvsc_device { struct hv_device *dev; @@ -532,12 +604,6 @@ struct netvsc_device { wait_queue_head_t wait_drain; bool start_remove; bool destroy; - /* - * List of free preallocated hv_netvsc_packet to represent receive - * packet - */ - struct list_head recv_pkt_list; - spinlock_t recv_pkt_list_lock; /* Receive buffer allocated by us but manages by NetVSP */ void *recv_buf; @@ -546,6 +612,15 @@ struct netvsc_device { u32 recv_section_cnt; struct nvsp_1_receive_buffer_section *recv_section; + /* Send buffer allocated by us */ + void *send_buf; + u32 send_buf_size; + u32 send_buf_gpadl_handle; + u32 send_section_cnt; + u32 send_section_size; + unsigned long *send_section_map; + int map_words; + /* Used for NetVSP initialization protocol */ struct completion channel_init_wait; struct nvsp_message channel_init_pkt; @@ -555,10 +630,20 @@ struct netvsc_device { struct net_device *ndev; + struct vmbus_channel *chn_table[NR_CPUS]; + u32 send_table[VRSS_SEND_TAB_SIZE]; + u32 num_chn; + atomic_t queue_sends[NR_CPUS]; + /* Holds rndis device info */ void *extension; - /* The recive buffer for this device */ + + int ring_size; + + /* The primary channel callback buffer */ unsigned char cb_buffer[NETVSC_PACKET_SIZE]; + /* The sub channel callback buffer */ + unsigned char *sub_cb_buf; }; /* NdisInitialize message */ diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index f7629ecefa84a6..c041f63a6d3053 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "hyperv_net.h" @@ -80,7 +81,7 @@ static struct netvsc_device *get_inbound_net_device(struct hv_device *device) } -static int netvsc_destroy_recv_buf(struct netvsc_device *net_device) +static int netvsc_destroy_buf(struct netvsc_device *net_device) { struct nvsp_message *revoke_packet; int ret = 0; @@ -146,10 +147,62 @@ static int netvsc_destroy_recv_buf(struct netvsc_device *net_device) net_device->recv_section = NULL; } + /* Deal with the send buffer we may have setup. + * If we got a send section size, it means we received a + * SendsendBufferComplete msg (ie sent + * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need + * to send a revoke msg here + */ + if (net_device->send_section_size) { + /* Send the revoke receive buffer */ + revoke_packet = &net_device->revoke_packet; + memset(revoke_packet, 0, sizeof(struct nvsp_message)); + + revoke_packet->hdr.msg_type = + NVSP_MSG1_TYPE_REVOKE_SEND_BUF; + revoke_packet->msg.v1_msg.revoke_recv_buf.id = 0; + + ret = vmbus_sendpacket(net_device->dev->channel, + revoke_packet, + sizeof(struct nvsp_message), + (unsigned long)revoke_packet, + VM_PKT_DATA_INBAND, 0); + /* If we failed here, we might as well return and + * have a leak rather than continue and a bugchk + */ + if (ret != 0) { + netdev_err(ndev, "unable to send " + "revoke send buffer to netvsp\n"); + return ret; + } + } + /* Teardown the gpadl on the vsp end */ + if (net_device->send_buf_gpadl_handle) { + ret = vmbus_teardown_gpadl(net_device->dev->channel, + net_device->send_buf_gpadl_handle); + + /* If we failed here, we might as well return and have a leak + * rather than continue and a bugchk + */ + if (ret != 0) { + netdev_err(ndev, + "unable to teardown send buffer's gpadl\n"); + return ret; + } + net_device->recv_buf_gpadl_handle = 0; + } + if (net_device->send_buf) { + /* Free up the receive buffer */ + free_pages((unsigned long)net_device->send_buf, + get_order(net_device->send_buf_size)); + net_device->send_buf = NULL; + } + kfree(net_device->send_section_map); + return ret; } -static int netvsc_init_recv_buf(struct hv_device *device) +static int netvsc_init_buf(struct hv_device *device) { int ret = 0; int t; @@ -248,10 +301,90 @@ static int netvsc_init_recv_buf(struct hv_device *device) goto cleanup; } + /* Now setup the send buffer. + */ + net_device->send_buf = + (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, + get_order(net_device->send_buf_size)); + if (!net_device->send_buf) { + netdev_err(ndev, "unable to allocate send " + "buffer of size %d\n", net_device->send_buf_size); + ret = -ENOMEM; + goto cleanup; + } + + /* Establish the gpadl handle for this buffer on this + * channel. Note: This call uses the vmbus connection rather + * than the channel to establish the gpadl handle. + */ + ret = vmbus_establish_gpadl(device->channel, net_device->send_buf, + net_device->send_buf_size, + &net_device->send_buf_gpadl_handle); + if (ret != 0) { + netdev_err(ndev, + "unable to establish send buffer's gpadl\n"); + goto cleanup; + } + + /* Notify the NetVsp of the gpadl handle */ + init_packet = &net_device->channel_init_pkt; + memset(init_packet, 0, sizeof(struct nvsp_message)); + init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF; + init_packet->msg.v1_msg.send_recv_buf.gpadl_handle = + net_device->send_buf_gpadl_handle; + init_packet->msg.v1_msg.send_recv_buf.id = 0; + + /* Send the gpadl notification request */ + ret = vmbus_sendpacket(device->channel, init_packet, + sizeof(struct nvsp_message), + (unsigned long)init_packet, + VM_PKT_DATA_INBAND, + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (ret != 0) { + netdev_err(ndev, + "unable to send send buffer's gpadl to netvsp\n"); + goto cleanup; + } + + t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ); + BUG_ON(t == 0); + + /* Check the response */ + if (init_packet->msg.v1_msg. + send_send_buf_complete.status != NVSP_STAT_SUCCESS) { + netdev_err(ndev, "Unable to complete send buffer " + "initialization with NetVsp - status %d\n", + init_packet->msg.v1_msg. + send_recv_buf_complete.status); + ret = -EINVAL; + goto cleanup; + } + + /* Parse the response */ + net_device->send_section_size = init_packet->msg. + v1_msg.send_send_buf_complete.section_size; + + /* Section count is simply the size divided by the section size. + */ + net_device->send_section_cnt = + net_device->send_buf_size/net_device->send_section_size; + + dev_info(&device->device, "Send section size: %d, Section count:%d\n", + net_device->send_section_size, net_device->send_section_cnt); + + /* Setup state for managing the send buffer. */ + net_device->map_words = DIV_ROUND_UP(net_device->send_section_cnt, + BITS_PER_LONG); + + net_device->send_section_map = + kzalloc(net_device->map_words * sizeof(ulong), GFP_KERNEL); + if (net_device->send_section_map == NULL) + goto cleanup; + goto exit; cleanup: - netvsc_destroy_recv_buf(net_device); + netvsc_destroy_buf(net_device); exit: return ret; @@ -369,8 +502,9 @@ static int netvsc_connect_vsp(struct hv_device *device) net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY; else net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; + net_device->send_buf_size = NETVSC_SEND_BUFFER_SIZE; - ret = netvsc_init_recv_buf(device); + ret = netvsc_init_buf(device); cleanup: return ret; @@ -378,7 +512,7 @@ static int netvsc_connect_vsp(struct hv_device *device) static void netvsc_disconnect_vsp(struct netvsc_device *net_device) { - netvsc_destroy_recv_buf(net_device); + netvsc_destroy_buf(net_device); } /* @@ -387,7 +521,6 @@ static void netvsc_disconnect_vsp(struct netvsc_device *net_device) int netvsc_device_remove(struct hv_device *device) { struct netvsc_device *net_device; - struct hv_netvsc_packet *netvsc_packet, *pos; unsigned long flags; net_device = hv_get_drvdata(device); @@ -416,11 +549,8 @@ int netvsc_device_remove(struct hv_device *device) vmbus_close(device->channel); /* Release all resources */ - list_for_each_entry_safe(netvsc_packet, pos, - &net_device->recv_pkt_list, list_ent) { - list_del(&netvsc_packet->list_ent); - kfree(netvsc_packet); - } + if (net_device->sub_cb_buf) + vfree(net_device->sub_cb_buf); kfree(net_device); return 0; @@ -444,6 +574,12 @@ static inline u32 hv_ringbuf_avail_percent( return avail_write * 100 / ring_info->ring_datasize; } +static inline void netvsc_free_send_slot(struct netvsc_device *net_device, + u32 index) +{ + sync_change_bit(index, net_device->send_section_map); +} + static void netvsc_send_completion(struct netvsc_device *net_device, struct hv_device *device, struct vmpacket_descriptor *packet) @@ -451,6 +587,7 @@ static void netvsc_send_completion(struct netvsc_device *net_device, struct nvsp_message *nvsp_packet; struct hv_netvsc_packet *nvsc_packet; struct net_device *ndev; + u32 send_index; ndev = net_device->ndev; @@ -461,7 +598,9 @@ static void netvsc_send_completion(struct netvsc_device *net_device, (nvsp_packet->hdr.msg_type == NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE) || (nvsp_packet->hdr.msg_type == - NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE)) { + NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE) || + (nvsp_packet->hdr.msg_type == + NVSP_MSG5_TYPE_SUBCHANNEL)) { /* Copy the response back */ memcpy(&net_device->channel_init_pkt, nvsp_packet, sizeof(struct nvsp_message)); @@ -469,28 +608,39 @@ static void netvsc_send_completion(struct netvsc_device *net_device, } else if (nvsp_packet->hdr.msg_type == NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) { int num_outstanding_sends; + u16 q_idx = 0; + struct vmbus_channel *channel = device->channel; + int queue_sends; /* Get the send context */ nvsc_packet = (struct hv_netvsc_packet *)(unsigned long) packet->trans_id; /* Notify the layer above us */ - if (nvsc_packet) - nvsc_packet->completion.send.send_completion( - nvsc_packet->completion.send. - send_completion_ctx); + if (nvsc_packet) { + send_index = nvsc_packet->send_buf_index; + if (send_index != NETVSC_INVALID_INDEX) + netvsc_free_send_slot(net_device, send_index); + q_idx = nvsc_packet->q_idx; + channel = nvsc_packet->channel; + nvsc_packet->send_completion(nvsc_packet-> + send_completion_ctx); + } num_outstanding_sends = atomic_dec_return(&net_device->num_outstanding_sends); + queue_sends = atomic_dec_return(&net_device-> + queue_sends[q_idx]); if (net_device->destroy && num_outstanding_sends == 0) wake_up(&net_device->wait_drain); - if (netif_queue_stopped(ndev) && !net_device->start_remove && - (hv_ringbuf_avail_percent(&device->channel->outbound) - > RING_AVAIL_PERCENT_HIWATER || - num_outstanding_sends < 1)) - netif_wake_queue(ndev); + if (netif_tx_queue_stopped(netdev_get_tx_queue(ndev, q_idx)) && + !net_device->start_remove && + (hv_ringbuf_avail_percent(&channel->outbound) > + RING_AVAIL_PERCENT_HIWATER || queue_sends < 1)) + netif_tx_wake_queue(netdev_get_tx_queue( + ndev, q_idx)); } else { netdev_err(ndev, "Unknown send completion packet type- " "%d received!!\n", nvsp_packet->hdr.msg_type); @@ -498,6 +648,52 @@ static void netvsc_send_completion(struct netvsc_device *net_device, } +static u32 netvsc_get_next_send_section(struct netvsc_device *net_device) +{ + unsigned long index; + u32 max_words = net_device->map_words; + unsigned long *map_addr = (unsigned long *)net_device->send_section_map; + u32 section_cnt = net_device->send_section_cnt; + int ret_val = NETVSC_INVALID_INDEX; + int i; + int prev_val; + + for (i = 0; i < max_words; i++) { + if (!~(map_addr[i])) + continue; + index = ffz(map_addr[i]); + prev_val = sync_test_and_set_bit(index, &map_addr[i]); + if (prev_val) + continue; + if ((index + (i * BITS_PER_LONG)) >= section_cnt) + break; + ret_val = (index + (i * BITS_PER_LONG)); + break; + } + return ret_val; +} + +u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device, + unsigned int section_index, + struct hv_netvsc_packet *packet) +{ + char *start = net_device->send_buf; + char *dest = (start + (section_index * net_device->send_section_size)); + int i; + u32 msg_size = 0; + + for (i = 0; i < packet->page_buf_cnt; i++) { + char *src = phys_to_virt(packet->page_buf[i].pfn << PAGE_SHIFT); + u32 offset = packet->page_buf[i].offset; + u32 len = packet->page_buf[i].len; + + memcpy(dest, (src + offset), len); + msg_size += len; + dest += len; + } + return msg_size; +} + int netvsc_send(struct hv_device *device, struct hv_netvsc_packet *packet) { @@ -505,7 +701,12 @@ int netvsc_send(struct hv_device *device, int ret = 0; struct nvsp_message sendMessage; struct net_device *ndev; + struct vmbus_channel *out_channel = NULL; u64 req_id; + unsigned int section_index = NETVSC_INVALID_INDEX; + u32 msg_size = 0; + struct sk_buff *skb; + net_device = get_outbound_net_device(device); if (!net_device) @@ -521,25 +722,46 @@ int netvsc_send(struct hv_device *device, sendMessage.msg.v1_msg.send_rndis_pkt.channel_type = 1; } - /* Not using send buffer section */ + /* Attempt to send via sendbuf */ + if (packet->total_data_buflen < net_device->send_section_size) { + section_index = netvsc_get_next_send_section(net_device); + if (section_index != NETVSC_INVALID_INDEX) { + msg_size = netvsc_copy_to_send_buf(net_device, + section_index, + packet); + skb = (struct sk_buff *) + (unsigned long)packet->send_completion_tid; + if (skb) + dev_kfree_skb_any(skb); + packet->page_buf_cnt = 0; + } + } + packet->send_buf_index = section_index; + + sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_index = - 0xFFFFFFFF; - sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = 0; + section_index; + sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = msg_size; - if (packet->completion.send.send_completion) + if (packet->send_completion) req_id = (ulong)packet; else req_id = 0; + out_channel = net_device->chn_table[packet->q_idx]; + if (out_channel == NULL) + out_channel = device->channel; + packet->channel = out_channel; + if (packet->page_buf_cnt) { - ret = vmbus_sendpacket_pagebuffer(device->channel, + ret = vmbus_sendpacket_pagebuffer(out_channel, packet->page_buf, packet->page_buf_cnt, &sendMessage, sizeof(struct nvsp_message), req_id); } else { - ret = vmbus_sendpacket(device->channel, &sendMessage, + ret = vmbus_sendpacket(out_channel, &sendMessage, sizeof(struct nvsp_message), req_id, VM_PKT_DATA_INBAND, @@ -548,17 +770,24 @@ int netvsc_send(struct hv_device *device, if (ret == 0) { atomic_inc(&net_device->num_outstanding_sends); - if (hv_ringbuf_avail_percent(&device->channel->outbound) < + atomic_inc(&net_device->queue_sends[packet->q_idx]); + + if (hv_ringbuf_avail_percent(&out_channel->outbound) < RING_AVAIL_PERCENT_LOWATER) { - netif_stop_queue(ndev); + netif_tx_stop_queue(netdev_get_tx_queue( + ndev, packet->q_idx)); + if (atomic_read(&net_device-> - num_outstanding_sends) < 1) - netif_wake_queue(ndev); + queue_sends[packet->q_idx]) < 1) + netif_tx_wake_queue(netdev_get_tx_queue( + ndev, packet->q_idx)); } } else if (ret == -EAGAIN) { - netif_stop_queue(ndev); - if (atomic_read(&net_device->num_outstanding_sends) < 1) { - netif_wake_queue(ndev); + netif_tx_stop_queue(netdev_get_tx_queue( + ndev, packet->q_idx)); + if (atomic_read(&net_device->queue_sends[packet->q_idx]) < 1) { + netif_tx_wake_queue(netdev_get_tx_queue( + ndev, packet->q_idx)); ret = -ENOSPC; } } else { @@ -570,6 +799,7 @@ int netvsc_send(struct hv_device *device, } static void netvsc_send_recv_completion(struct hv_device *device, + struct vmbus_channel *channel, struct netvsc_device *net_device, u64 transaction_id, u32 status) { @@ -587,7 +817,7 @@ static void netvsc_send_recv_completion(struct hv_device *device, retry_send_cmplt: /* Send the completion */ - ret = vmbus_sendpacket(device->channel, &recvcompMessage, + ret = vmbus_sendpacket(channel, &recvcompMessage, sizeof(struct nvsp_message), transaction_id, VM_PKT_COMP, 0); if (ret == 0) { @@ -613,76 +843,20 @@ static void netvsc_send_recv_completion(struct hv_device *device, } } -/* Send a receive completion packet to RNDIS device (ie NetVsp) */ -static void netvsc_receive_completion(void *context) -{ - struct hv_netvsc_packet *packet = context; - struct hv_device *device = packet->device; - struct netvsc_device *net_device; - u64 transaction_id = 0; - bool fsend_receive_comp = false; - unsigned long flags; - struct net_device *ndev; - u32 status = NVSP_STAT_NONE; - - /* - * Even though it seems logical to do a GetOutboundNetDevice() here to - * send out receive completion, we are using GetInboundNetDevice() - * since we may have disable outbound traffic already. - */ - net_device = get_inbound_net_device(device); - if (!net_device) - return; - ndev = net_device->ndev; - - /* Overloading use of the lock. */ - spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); - - if (packet->status != NVSP_STAT_SUCCESS) - packet->xfer_page_pkt->status = NVSP_STAT_FAIL; - - packet->xfer_page_pkt->count--; - - /* - * Last one in the line that represent 1 xfer page packet. - * Return the xfer page packet itself to the freelist - */ - if (packet->xfer_page_pkt->count == 0) { - fsend_receive_comp = true; - transaction_id = packet->completion.recv.recv_completion_tid; - status = packet->xfer_page_pkt->status; - list_add_tail(&packet->xfer_page_pkt->list_ent, - &net_device->recv_pkt_list); - - } - - /* Put the packet back */ - list_add_tail(&packet->list_ent, &net_device->recv_pkt_list); - spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags); - - /* Send a receive completion for the xfer page packet */ - if (fsend_receive_comp) - netvsc_send_recv_completion(device, net_device, transaction_id, - status); - -} - static void netvsc_receive(struct netvsc_device *net_device, + struct vmbus_channel *channel, struct hv_device *device, struct vmpacket_descriptor *packet) { struct vmtransfer_page_packet_header *vmxferpage_packet; struct nvsp_message *nvsp_packet; - struct hv_netvsc_packet *netvsc_packet = NULL; - /* struct netvsc_driver *netvscDriver; */ - struct xferpage_packet *xferpage_packet = NULL; + struct hv_netvsc_packet nv_pkt; + struct hv_netvsc_packet *netvsc_packet = &nv_pkt; + u32 status = NVSP_STAT_SUCCESS; int i; int count = 0; - unsigned long flags; struct net_device *ndev; - LIST_HEAD(listHead); - ndev = net_device->ndev; /* @@ -715,77 +889,14 @@ static void netvsc_receive(struct netvsc_device *net_device, return; } - /* - * Grab free packets (range count + 1) to represent this xfer - * page packet. +1 to represent the xfer page packet itself. - * We grab it here so that we know exactly how many we can - * fulfil - */ - spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); - while (!list_empty(&net_device->recv_pkt_list)) { - list_move_tail(net_device->recv_pkt_list.next, &listHead); - if (++count == vmxferpage_packet->range_cnt + 1) - break; - } - spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags); - - /* - * We need at least 2 netvsc pkts (1 to represent the xfer - * page and at least 1 for the range) i.e. we can handled - * some of the xfer page packet ranges... - */ - if (count < 2) { - netdev_err(ndev, "Got only %d netvsc pkt...needed " - "%d pkts. Dropping this xfer page packet completely!\n", - count, vmxferpage_packet->range_cnt + 1); - - /* Return it to the freelist */ - spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); - for (i = count; i != 0; i--) { - list_move_tail(listHead.next, - &net_device->recv_pkt_list); - } - spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, - flags); - - netvsc_send_recv_completion(device, net_device, - vmxferpage_packet->d.trans_id, - NVSP_STAT_FAIL); - - return; - } - - /* Remove the 1st packet to represent the xfer page packet itself */ - xferpage_packet = (struct xferpage_packet *)listHead.next; - list_del(&xferpage_packet->list_ent); - xferpage_packet->status = NVSP_STAT_SUCCESS; - - /* This is how much we can satisfy */ - xferpage_packet->count = count - 1; - - if (xferpage_packet->count != vmxferpage_packet->range_cnt) { - netdev_err(ndev, "Needed %d netvsc pkts to satisfy " - "this xfer page...got %d\n", - vmxferpage_packet->range_cnt, xferpage_packet->count); - } + count = vmxferpage_packet->range_cnt; + netvsc_packet->device = device; + netvsc_packet->channel = channel; /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */ - for (i = 0; i < (count - 1); i++) { - netvsc_packet = (struct hv_netvsc_packet *)listHead.next; - list_del(&netvsc_packet->list_ent); - + for (i = 0; i < count; i++) { /* Initialize the netvsc packet */ netvsc_packet->status = NVSP_STAT_SUCCESS; - netvsc_packet->xfer_page_pkt = xferpage_packet; - netvsc_packet->completion.recv.recv_completion = - netvsc_receive_completion; - netvsc_packet->completion.recv.recv_completion_ctx = - netvsc_packet; - netvsc_packet->device = device; - /* Save this so that we can send it back */ - netvsc_packet->completion.recv.recv_completion_tid = - vmxferpage_packet->d.trans_id; - netvsc_packet->data = (void *)((unsigned long)net_device-> recv_buf + vmxferpage_packet->ranges[i].byte_offset); netvsc_packet->total_data_buflen = @@ -794,16 +905,53 @@ static void netvsc_receive(struct netvsc_device *net_device, /* Pass it to the upper layer */ rndis_filter_receive(device, netvsc_packet); - netvsc_receive_completion(netvsc_packet-> - completion.recv.recv_completion_ctx); + if (netvsc_packet->status != NVSP_STAT_SUCCESS) + status = NVSP_STAT_FAIL; + } + + netvsc_send_recv_completion(device, channel, net_device, + vmxferpage_packet->d.trans_id, status); +} + + +static void netvsc_send_table(struct hv_device *hdev, + struct vmpacket_descriptor *vmpkt) +{ + struct netvsc_device *nvscdev; + struct net_device *ndev; + struct nvsp_message *nvmsg; + int i; + u32 count, *tab; + + nvscdev = get_outbound_net_device(hdev); + if (!nvscdev) + return; + ndev = nvscdev->ndev; + + nvmsg = (struct nvsp_message *)((unsigned long)vmpkt + + (vmpkt->offset8 << 3)); + + if (nvmsg->hdr.msg_type != NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE) + return; + + count = nvmsg->msg.v5_msg.send_table.count; + if (count != VRSS_SEND_TAB_SIZE) { + netdev_err(ndev, "Received wrong send-table size:%u\n", count); + return; } + tab = (u32 *)((unsigned long)&nvmsg->msg.v5_msg.send_table + + nvmsg->msg.v5_msg.send_table.offset); + + for (i = 0; i < count; i++) + nvscdev->send_table[i] = tab[i]; } -static void netvsc_channel_cb(void *context) +void netvsc_channel_cb(void *context) { int ret; - struct hv_device *device = context; + struct vmbus_channel *channel = (struct vmbus_channel *)context; + struct hv_device *device; struct netvsc_device *net_device; u32 bytes_recvd; u64 request_id; @@ -812,14 +960,19 @@ static void netvsc_channel_cb(void *context) int bufferlen = NETVSC_PACKET_SIZE; struct net_device *ndev; + if (channel->primary_channel != NULL) + device = channel->primary_channel->device_obj; + else + device = channel->device_obj; + net_device = get_inbound_net_device(device); if (!net_device) return; ndev = net_device->ndev; - buffer = net_device->cb_buffer; + buffer = get_per_channel_state(channel); do { - ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen, + ret = vmbus_recvpacket_raw(channel, buffer, bufferlen, &bytes_recvd, &request_id); if (ret == 0) { if (bytes_recvd > 0) { @@ -831,8 +984,12 @@ static void netvsc_channel_cb(void *context) break; case VM_PKT_DATA_USING_XFER_PAGES: - netvsc_receive(net_device, - device, desc); + netvsc_receive(net_device, channel, + device, desc); + break; + + case VM_PKT_DATA_INBAND: + netvsc_send_table(device, desc); break; default: @@ -880,11 +1037,9 @@ static void netvsc_channel_cb(void *context) int netvsc_device_add(struct hv_device *device, void *additional_info) { int ret = 0; - int i; int ring_size = ((struct netvsc_device_info *)additional_info)->ring_size; struct netvsc_device *net_device; - struct hv_netvsc_packet *packet, *pos; struct net_device *ndev; net_device = alloc_net_device(device); @@ -893,6 +1048,8 @@ int netvsc_device_add(struct hv_device *device, void *additional_info) goto cleanup; } + net_device->ring_size = ring_size; + /* * Coming into this function, struct net_device * is * registered as the driver private data. @@ -903,24 +1060,14 @@ int netvsc_device_add(struct hv_device *device, void *additional_info) ndev = net_device->ndev; /* Initialize the NetVSC channel extension */ - spin_lock_init(&net_device->recv_pkt_list_lock); - - INIT_LIST_HEAD(&net_device->recv_pkt_list); - - for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) { - packet = kzalloc(sizeof(struct hv_netvsc_packet), GFP_KERNEL); - if (!packet) - break; - - list_add_tail(&packet->list_ent, - &net_device->recv_pkt_list); - } init_completion(&net_device->channel_init_wait); + set_per_channel_state(device->channel, net_device->cb_buffer); + /* Open the channel */ ret = vmbus_open(device->channel, ring_size * PAGE_SIZE, ring_size * PAGE_SIZE, NULL, 0, - netvsc_channel_cb, device); + netvsc_channel_cb, device->channel); if (ret != 0) { netdev_err(ndev, "unable to open channel: %d\n", ret); @@ -930,6 +1077,8 @@ int netvsc_device_add(struct hv_device *device, void *additional_info) /* Channel is opened */ pr_info("hv_netvsc channel opened successfully\n"); + net_device->chn_table[0] = device->channel; + /* Connect with the NetVsp */ ret = netvsc_connect_vsp(device); if (ret != 0) { @@ -946,16 +1095,8 @@ int netvsc_device_add(struct hv_device *device, void *additional_info) cleanup: - if (net_device) { - list_for_each_entry_safe(packet, pos, - &net_device->recv_pkt_list, - list_ent) { - list_del(&packet->list_ent); - kfree(packet); - } - + if (net_device) kfree(net_device); - } return ret; } diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 7918d5132c1f14..64c7816a5d6a19 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -101,7 +101,7 @@ static int netvsc_open(struct net_device *net) return ret; } - netif_start_queue(net); + netif_tx_start_all_queues(net); nvdev = hv_get_drvdata(device_obj); rdev = nvdev->extension; @@ -149,15 +149,98 @@ static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size, return ppi; } +union sub_key { + u64 k; + struct { + u8 pad[3]; + u8 kb; + u32 ka; + }; +}; + +/* Toeplitz hash function + * data: network byte order + * return: host byte order + */ +static u32 comp_hash(u8 *key, int klen, u8 *data, int dlen) +{ + union sub_key subk; + int k_next = 4; + u8 dt; + int i, j; + u32 ret = 0; + + subk.k = 0; + subk.ka = ntohl(*(u32 *)key); + + for (i = 0; i < dlen; i++) { + subk.kb = key[k_next]; + k_next = (k_next + 1) % klen; + dt = data[i]; + for (j = 0; j < 8; j++) { + if (dt & 0x80) + ret ^= subk.ka; + dt <<= 1; + subk.k <<= 1; + } + } + + return ret; +} + +static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb) +{ + struct iphdr *iphdr; + int data_len; + bool ret = false; + + if (eth_hdr(skb)->h_proto != htons(ETH_P_IP)) + return false; + + iphdr = ip_hdr(skb); + + if (iphdr->version == 4) { + if (iphdr->protocol == IPPROTO_TCP) + data_len = 12; + else + data_len = 8; + *hash = comp_hash(netvsc_hash_key, HASH_KEYLEN, + (u8 *)&iphdr->saddr, data_len); + ret = true; + } + + return ret; +} + +static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback) +{ + struct net_device_context *net_device_ctx = netdev_priv(ndev); + struct hv_device *hdev = net_device_ctx->device_ctx; + struct netvsc_device *nvsc_dev = hv_get_drvdata(hdev); + u32 hash; + u16 q_idx = 0; + + if (nvsc_dev == NULL || ndev->real_num_tx_queues <= 1) + return 0; + + if (netvsc_set_hash(&hash, skb)) + q_idx = nvsc_dev->send_table[hash % VRSS_SEND_TAB_SIZE] % + ndev->real_num_tx_queues; + + return q_idx; +} + static void netvsc_xmit_completion(void *context) { struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; struct sk_buff *skb = (struct sk_buff *) - (unsigned long)packet->completion.send.send_completion_tid; + (unsigned long)packet->send_completion_tid; + u32 index = packet->send_buf_index; kfree(packet); - if (skb) + if (skb && (index == NETVSC_INVALID_INDEX)) dev_kfree_skb_any(skb); } @@ -333,6 +416,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) packet->vlan_tci = skb->vlan_tci; + packet->q_idx = skb_get_queue_mapping(skb); + packet->is_data_pkt = true; packet->total_data_buflen = skb->len; @@ -341,9 +426,9 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) (num_data_pgs * sizeof(struct hv_page_buffer))); /* Set the completion routine */ - packet->completion.send.send_completion = netvsc_xmit_completion; - packet->completion.send.send_completion_ctx = packet; - packet->completion.send.send_completion_tid = (unsigned long)skb; + packet->send_completion = netvsc_xmit_completion; + packet->send_completion_ctx = packet; + packet->send_completion_tid = (unsigned long)skb; isvlan = packet->vlan_tci & VLAN_TAG_PRESENT; @@ -558,6 +643,10 @@ int netvsc_recv_callback(struct hv_device *device_obj, __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), packet->vlan_tci); + skb_record_rx_queue(skb, packet->channel-> + offermsg.offer.sub_channel_index % + net->real_num_rx_queues); + net->stats.rx_packets++; net->stats.rx_bytes += packet->total_data_buflen; @@ -606,7 +695,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) hv_set_drvdata(hdev, ndev); device_info.ring_size = ring_size; rndis_filter_device_add(hdev, &device_info); - netif_wake_queue(ndev); + netif_tx_wake_all_queues(ndev); return 0; } @@ -652,6 +741,7 @@ static const struct net_device_ops device_ops = { .ndo_change_mtu = netvsc_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = netvsc_set_mac_addr, + .ndo_select_queue = netvsc_select_queue, }; /* @@ -698,9 +788,11 @@ static int netvsc_probe(struct hv_device *dev, struct net_device *net = NULL; struct net_device_context *net_device_ctx; struct netvsc_device_info device_info; + struct netvsc_device *nvdev; int ret; - net = alloc_etherdev(sizeof(struct net_device_context)); + net = alloc_etherdev_mq(sizeof(struct net_device_context), + num_online_cpus()); if (!net) return -ENOMEM; @@ -733,6 +825,12 @@ static int netvsc_probe(struct hv_device *dev, } memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); + nvdev = hv_get_drvdata(dev); + netif_set_real_num_tx_queues(net, nvdev->num_chn); + netif_set_real_num_rx_queues(net, nvdev->num_chn); + dev_info(&dev->device, "real num tx,rx queues:%u, %u\n", + net->real_num_tx_queues, net->real_num_rx_queues); + ret = register_netdev(net); if (ret != 0) { pr_err("Unable to register netdev.\n"); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 143a98caf618a9..99c527adae5bf1 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -31,7 +31,7 @@ #include "hyperv_net.h" -#define RNDIS_EXT_LEN 100 +#define RNDIS_EXT_LEN PAGE_SIZE struct rndis_request { struct list_head list_ent; struct completion wait_event; @@ -94,6 +94,8 @@ static struct rndis_request *get_rndis_request(struct rndis_device *dev, rndis_msg->ndis_msg_type = msg_type; rndis_msg->msg_len = msg_len; + request->pkt.q_idx = 0; + /* * Set the request id. This field is always after the rndis header for * request/response packet types so we just used the SetRequest as a @@ -234,7 +236,7 @@ static int rndis_filter_send_request(struct rndis_device *dev, packet->page_buf[0].len; } - packet->completion.send.send_completion = NULL; + packet->send_completion = NULL; ret = netvsc_send(dev->net_dev->dev, packet); return ret; @@ -399,8 +401,6 @@ static void rndis_filter_receive_data(struct rndis_device *dev, pkt->total_data_buflen = rndis_pkt->data_len; pkt->data = (void *)((unsigned long)pkt->data + data_offset); - pkt->is_data_pkt = true; - vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO); if (vlan) { pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid | @@ -509,6 +509,19 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, query->info_buflen = 0; query->dev_vc_handle = 0; + if (oid == OID_GEN_RECEIVE_SCALE_CAPABILITIES) { + struct ndis_recv_scale_cap *cap; + + request->request_msg.msg_len += + sizeof(struct ndis_recv_scale_cap); + query->info_buflen = sizeof(struct ndis_recv_scale_cap); + cap = (struct ndis_recv_scale_cap *)((unsigned long)query + + query->info_buf_offset); + cap->hdr.type = NDIS_OBJECT_TYPE_RSS_CAPABILITIES; + cap->hdr.rev = NDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2; + cap->hdr.size = sizeof(struct ndis_recv_scale_cap); + } + ret = rndis_filter_send_request(dev, request); if (ret != 0) goto cleanup; @@ -695,6 +708,89 @@ int rndis_filter_set_offload_params(struct hv_device *hdev, return ret; } +u8 netvsc_hash_key[HASH_KEYLEN] = { + 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, + 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, + 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, + 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, + 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa +}; + +int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue) +{ + struct net_device *ndev = rdev->net_dev->ndev; + struct rndis_request *request; + struct rndis_set_request *set; + struct rndis_set_complete *set_complete; + u32 extlen = sizeof(struct ndis_recv_scale_param) + + 4*ITAB_NUM + HASH_KEYLEN; + struct ndis_recv_scale_param *rssp; + u32 *itab; + u8 *keyp; + int i, t, ret; + + request = get_rndis_request( + rdev, RNDIS_MSG_SET, + RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); + if (!request) + return -ENOMEM; + + set = &request->request_msg.msg.set_req; + set->oid = OID_GEN_RECEIVE_SCALE_PARAMETERS; + set->info_buflen = extlen; + set->info_buf_offset = sizeof(struct rndis_set_request); + set->dev_vc_handle = 0; + + rssp = (struct ndis_recv_scale_param *)(set + 1); + rssp->hdr.type = NDIS_OBJECT_TYPE_RSS_PARAMETERS; + rssp->hdr.rev = NDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2; + rssp->hdr.size = sizeof(struct ndis_recv_scale_param); + rssp->flag = 0; + rssp->hashinfo = NDIS_HASH_FUNC_TOEPLITZ | NDIS_HASH_IPV4 | + NDIS_HASH_TCP_IPV4; + rssp->indirect_tabsize = 4*ITAB_NUM; + rssp->indirect_taboffset = sizeof(struct ndis_recv_scale_param); + rssp->hashkey_size = HASH_KEYLEN; + rssp->kashkey_offset = rssp->indirect_taboffset + + rssp->indirect_tabsize; + + /* Set indirection table entries */ + itab = (u32 *)(rssp + 1); + for (i = 0; i < ITAB_NUM; i++) + itab[i] = i % num_queue; + + /* Set hask key values */ + keyp = (u8 *)((unsigned long)rssp + rssp->kashkey_offset); + for (i = 0; i < HASH_KEYLEN; i++) + keyp[i] = netvsc_hash_key[i]; + + + ret = rndis_filter_send_request(rdev, request); + if (ret != 0) + goto cleanup; + + t = wait_for_completion_timeout(&request->wait_event, 5*HZ); + if (t == 0) { + netdev_err(ndev, "timeout before we got a set response...\n"); + /* can't put_rndis_request, since we may still receive a + * send-completion. + */ + return -ETIMEDOUT; + } else { + set_complete = &request->response_msg.msg.set_complete; + if (set_complete->status != RNDIS_STATUS_SUCCESS) { + netdev_err(ndev, "Fail to set RSS parameters:0x%x\n", + set_complete->status); + ret = -EINVAL; + } + } + +cleanup: + put_rndis_request(rdev, request); + return ret; +} + + static int rndis_filter_query_device_link_status(struct rndis_device *dev) { u32 size = sizeof(u32); @@ -886,6 +982,28 @@ static int rndis_filter_close_device(struct rndis_device *dev) return ret; } +static void netvsc_sc_open(struct vmbus_channel *new_sc) +{ + struct netvsc_device *nvscdev; + u16 chn_index = new_sc->offermsg.offer.sub_channel_index; + int ret; + + nvscdev = hv_get_drvdata(new_sc->primary_channel->device_obj); + + if (chn_index >= nvscdev->num_chn) + return; + + set_per_channel_state(new_sc, nvscdev->sub_cb_buf + (chn_index - 1) * + NETVSC_PACKET_SIZE); + + ret = vmbus_open(new_sc, nvscdev->ring_size * PAGE_SIZE, + nvscdev->ring_size * PAGE_SIZE, NULL, 0, + netvsc_channel_cb, new_sc); + + if (ret == 0) + nvscdev->chn_table[chn_index] = new_sc; +} + int rndis_filter_device_add(struct hv_device *dev, void *additional_info) { @@ -894,6 +1012,10 @@ int rndis_filter_device_add(struct hv_device *dev, struct rndis_device *rndis_device; struct netvsc_device_info *device_info = additional_info; struct ndis_offload_params offloads; + struct nvsp_message *init_packet; + int t; + struct ndis_recv_scale_cap rsscap; + u32 rsscap_size = sizeof(struct ndis_recv_scale_cap); rndis_device = get_rndis_device(); if (!rndis_device) @@ -913,6 +1035,7 @@ int rndis_filter_device_add(struct hv_device *dev, /* Initialize the rndis device */ net_device = hv_get_drvdata(dev); + net_device->num_chn = 1; net_device->extension = rndis_device; rndis_device->net_dev = net_device; @@ -952,7 +1075,6 @@ int rndis_filter_device_add(struct hv_device *dev, if (ret) goto err_dev_remv; - rndis_filter_query_device_link_status(rndis_device); device_info->link_state = rndis_device->link_state; @@ -961,7 +1083,66 @@ int rndis_filter_device_add(struct hv_device *dev, rndis_device->hw_mac_adr, device_info->link_state ? "down" : "up"); - return ret; + if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5) + return 0; + + /* vRSS setup */ + memset(&rsscap, 0, rsscap_size); + ret = rndis_filter_query_device(rndis_device, + OID_GEN_RECEIVE_SCALE_CAPABILITIES, + &rsscap, &rsscap_size); + if (ret || rsscap.num_recv_que < 2) + goto out; + + net_device->num_chn = (num_online_cpus() < rsscap.num_recv_que) ? + num_online_cpus() : rsscap.num_recv_que; + if (net_device->num_chn == 1) + goto out; + + net_device->sub_cb_buf = vzalloc((net_device->num_chn - 1) * + NETVSC_PACKET_SIZE); + if (!net_device->sub_cb_buf) { + net_device->num_chn = 1; + dev_info(&dev->device, "No memory for subchannels.\n"); + goto out; + } + + vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open); + + init_packet = &net_device->channel_init_pkt; + memset(init_packet, 0, sizeof(struct nvsp_message)); + init_packet->hdr.msg_type = NVSP_MSG5_TYPE_SUBCHANNEL; + init_packet->msg.v5_msg.subchn_req.op = NVSP_SUBCHANNEL_ALLOCATE; + init_packet->msg.v5_msg.subchn_req.num_subchannels = + net_device->num_chn - 1; + ret = vmbus_sendpacket(dev->channel, init_packet, + sizeof(struct nvsp_message), + (unsigned long)init_packet, + VM_PKT_DATA_INBAND, + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (ret) + goto out; + t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ); + if (t == 0) { + ret = -ETIMEDOUT; + goto out; + } + if (init_packet->msg.v5_msg.subchn_comp.status != + NVSP_STAT_SUCCESS) { + ret = -ENODEV; + goto out; + } + net_device->num_chn = 1 + + init_packet->msg.v5_msg.subchn_comp.num_subchannels; + + vmbus_are_subchannels_present(dev->channel); + + ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn); + +out: + if (ret) + net_device->num_chn = 1; + return 0; /* return 0 because primary channel can be used alone */ err_dev_remv: rndis_filter_device_remove(dev); diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index e36f194673a45a..4517b149ed0786 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -692,10 +693,7 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb) if (rc < 0) goto err_rx; - rc = at86rf230_start(dev); - - return rc; - + return at86rf230_start(dev); err_rx: at86rf230_start(dev); err: @@ -963,33 +961,24 @@ static irqreturn_t at86rf230_isr_level(int irq, void *data) return at86rf230_isr(irq, data); } -static int at86rf230_irq_polarity(struct at86rf230_local *lp, int pol) -{ - return at86rf230_write_subreg(lp, SR_IRQ_POLARITY, pol); -} - static int at86rf230_hw_init(struct at86rf230_local *lp) { - struct at86rf230_platform_data *pdata = lp->spi->dev.platform_data; - int rc, irq_pol; - u8 status; + int rc, irq_pol, irq_type; + u8 dvdd; u8 csma_seed[2]; - rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status); - if (rc) - return rc; - rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_FORCE_TRX_OFF); if (rc) return rc; + irq_type = irq_get_trigger_type(lp->spi->irq); /* configure irq polarity, defaults to high active */ - if (pdata->irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW)) + if (irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW)) irq_pol = IRQ_ACTIVE_LOW; else irq_pol = IRQ_ACTIVE_HIGH; - rc = at86rf230_irq_polarity(lp, irq_pol); + rc = at86rf230_write_subreg(lp, SR_IRQ_POLARITY, irq_pol); if (rc) return rc; @@ -1017,10 +1006,10 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) /* Wait the next SLEEP cycle */ msleep(100); - rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status); + rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &dvdd); if (rc) return rc; - if (!status) { + if (!dvdd) { dev_err(&lp->spi->dev, "DVDD error\n"); return -EINVAL; } @@ -1032,7 +1021,6 @@ static struct at86rf230_platform_data * at86rf230_get_pdata(struct spi_device *spi) { struct at86rf230_platform_data *pdata; - const char *irq_type; if (!IS_ENABLED(CONFIG_OF) || !spi->dev.of_node) return spi->dev.platform_data; @@ -1044,19 +1032,6 @@ at86rf230_get_pdata(struct spi_device *spi) pdata->rstn = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0); pdata->slp_tr = of_get_named_gpio(spi->dev.of_node, "sleep-gpio", 0); - pdata->irq_type = IRQF_TRIGGER_RISING; - of_property_read_string(spi->dev.of_node, "irq-type", &irq_type); - if (!strcmp(irq_type, "level-high")) - pdata->irq_type = IRQF_TRIGGER_HIGH; - else if (!strcmp(irq_type, "level-low")) - pdata->irq_type = IRQF_TRIGGER_LOW; - else if (!strcmp(irq_type, "edge-rising")) - pdata->irq_type = IRQF_TRIGGER_RISING; - else if (!strcmp(irq_type, "edge-falling")) - pdata->irq_type = IRQF_TRIGGER_FALLING; - else - dev_warn(&spi->dev, "wrong irq-type specified using edge-rising\n"); - spi->dev.platform_data = pdata; done: return pdata; @@ -1071,7 +1046,7 @@ static int at86rf230_probe(struct spi_device *spi) u8 part = 0, version = 0, status; irq_handler_t irq_handler; work_func_t irq_worker; - int rc; + int rc, irq_type; const char *chip; struct ieee802154_ops *ops = NULL; @@ -1087,27 +1062,17 @@ static int at86rf230_probe(struct spi_device *spi) } if (gpio_is_valid(pdata->rstn)) { - rc = gpio_request(pdata->rstn, "rstn"); + rc = devm_gpio_request_one(&spi->dev, pdata->rstn, + GPIOF_OUT_INIT_HIGH, "rstn"); if (rc) return rc; } if (gpio_is_valid(pdata->slp_tr)) { - rc = gpio_request(pdata->slp_tr, "slp_tr"); - if (rc) - goto err_slp_tr; - } - - if (gpio_is_valid(pdata->rstn)) { - rc = gpio_direction_output(pdata->rstn, 1); - if (rc) - goto err_gpio_dir; - } - - if (gpio_is_valid(pdata->slp_tr)) { - rc = gpio_direction_output(pdata->slp_tr, 0); + rc = devm_gpio_request_one(&spi->dev, pdata->slp_tr, + GPIOF_OUT_INIT_LOW, "slp_tr"); if (rc) - goto err_gpio_dir; + return rc; } /* Reset */ @@ -1121,13 +1086,12 @@ static int at86rf230_probe(struct spi_device *spi) rc = __at86rf230_detect_device(spi, &man_id, &part, &version); if (rc < 0) - goto err_gpio_dir; + return rc; if (man_id != 0x001f) { dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n", man_id >> 8, man_id & 0xFF); - rc = -EINVAL; - goto err_gpio_dir; + return -EINVAL; } switch (part) { @@ -1154,16 +1118,12 @@ static int at86rf230_probe(struct spi_device *spi) } dev_info(&spi->dev, "Detected %s chip version %d\n", chip, version); - if (!ops) { - rc = -ENOTSUPP; - goto err_gpio_dir; - } + if (!ops) + return -ENOTSUPP; dev = ieee802154_alloc_device(sizeof(*lp), ops); - if (!dev) { - rc = -ENOMEM; - goto err_gpio_dir; - } + if (!dev) + return -ENOMEM; lp = dev->priv; lp->dev = dev; @@ -1176,7 +1136,8 @@ static int at86rf230_probe(struct spi_device *spi) dev->extra_tx_headroom = 0; dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK; - if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { + irq_type = irq_get_trigger_type(spi->irq); + if (irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { irq_worker = at86rf230_irqwork; irq_handler = at86rf230_isr; } else { @@ -1202,75 +1163,65 @@ static int at86rf230_probe(struct spi_device *spi) if (rc) goto err_hw_init; - rc = request_irq(spi->irq, irq_handler, - IRQF_SHARED | pdata->irq_type, - dev_name(&spi->dev), lp); + /* Read irq status register to reset irq line */ + rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status); if (rc) goto err_hw_init; - /* Read irq status register to reset irq line */ - rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status); + rc = devm_request_irq(&spi->dev, spi->irq, irq_handler, IRQF_SHARED, + dev_name(&spi->dev), lp); if (rc) - goto err_irq; + goto err_hw_init; rc = ieee802154_register_device(lp->dev); if (rc) - goto err_irq; + goto err_hw_init; return rc; -err_irq: - free_irq(spi->irq, lp); err_hw_init: flush_work(&lp->irqwork); - spi_set_drvdata(spi, NULL); mutex_destroy(&lp->bmux); ieee802154_free_device(lp->dev); -err_gpio_dir: - if (gpio_is_valid(pdata->slp_tr)) - gpio_free(pdata->slp_tr); -err_slp_tr: - if (gpio_is_valid(pdata->rstn)) - gpio_free(pdata->rstn); return rc; } static int at86rf230_remove(struct spi_device *spi) { struct at86rf230_local *lp = spi_get_drvdata(spi); - struct at86rf230_platform_data *pdata = spi->dev.platform_data; /* mask all at86rf230 irq's */ at86rf230_write_subreg(lp, SR_IRQ_MASK, 0); ieee802154_unregister_device(lp->dev); - - free_irq(spi->irq, lp); flush_work(&lp->irqwork); - - if (gpio_is_valid(pdata->slp_tr)) - gpio_free(pdata->slp_tr); - if (gpio_is_valid(pdata->rstn)) - gpio_free(pdata->rstn); - mutex_destroy(&lp->bmux); ieee802154_free_device(lp->dev); - dev_dbg(&spi->dev, "unregistered at86rf230\n"); + return 0; } -#if IS_ENABLED(CONFIG_OF) -static struct of_device_id at86rf230_of_match[] = { +static const struct of_device_id at86rf230_of_match[] = { { .compatible = "atmel,at86rf230", }, { .compatible = "atmel,at86rf231", }, { .compatible = "atmel,at86rf233", }, { .compatible = "atmel,at86rf212", }, { }, }; -#endif +MODULE_DEVICE_TABLE(of, at86rf230_of_match); + +static const struct spi_device_id at86rf230_device_id[] = { + { .name = "at86rf230", }, + { .name = "at86rf231", }, + { .name = "at86rf233", }, + { .name = "at86rf212", }, + { }, +}; +MODULE_DEVICE_TABLE(spi, at86rf230_device_id); static struct spi_driver at86rf230_driver = { + .id_table = at86rf230_device_id, .driver = { .of_match_table = of_match_ptr(at86rf230_of_match), .name = "at86rf230", diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c index cadf52e224645f..e3fe9a286136a9 100644 --- a/drivers/net/irda/sh_sir.c +++ b/drivers/net/irda/sh_sir.c @@ -217,21 +217,17 @@ static int sh_sir_crc_init(struct sh_sir_self *self) static u32 sh_sir_find_sclk(struct clk *irda_clk) { struct cpufreq_frequency_table *freq_table = irda_clk->freq_table; + struct cpufreq_frequency_table *pos; struct clk *pclk = clk_get(NULL, "peripheral_clk"); u32 limit, min = 0xffffffff, tmp; - int i, index = 0; + int index = 0; limit = clk_get_rate(pclk); clk_put(pclk); /* IrDA can not set over peripheral_clk */ - for (i = 0; - freq_table[i].frequency != CPUFREQ_TABLE_END; - i++) { - u32 freq = freq_table[i].frequency; - - if (freq == CPUFREQ_ENTRY_INVALID) - continue; + cpufreq_for_each_valid_entry(pos, freq_table) { + u32 freq = pos->frequency; /* IrDA should not over peripheral_clk */ if (freq > limit) @@ -240,7 +236,7 @@ static u32 sh_sir_find_sclk(struct clk *irda_clk) tmp = freq % SCLK_BASE; if (tmp < min) { min = tmp; - index = i; + index = pos - freq_table; } } diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index e641bb2403624f..11dbdf36d9c1b3 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -62,10 +62,6 @@ #include "w83977af.h" #include "w83977af_ir.h" -#ifdef CONFIG_ARCH_NETWINDER /* Adjust to NetWinder differences */ -#undef CONFIG_NETWINDER_TX_DMA_PROBLEMS /* Not needed */ -#define CONFIG_NETWINDER_RX_DMA_PROBLEMS /* Must have this one! */ -#endif #define CONFIG_USE_W977_PNP /* Currently needed */ #define PIO_MAX_SPEED 115200 @@ -332,7 +328,7 @@ static int w83977af_probe(int iobase, int irq, int dma) w977_write_reg(0x74, dma+1, efbase[i]); #else w977_write_reg(0x74, dma, efbase[i]); -#endif /*CONFIG_ARCH_NETWINDER */ +#endif /* CONFIG_ARCH_NETWINDER */ w977_write_reg(0x75, 0x04, efbase[i]); /* Disable Tx DMA */ /* Set append hardware CRC, enable IR bank selection */ @@ -563,10 +559,6 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb, static void w83977af_dma_write(struct w83977af_ir *self, int iobase) { __u8 set; -#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS - unsigned long flags; - __u8 hcr; -#endif IRDA_DEBUG(4, "%s(), len=%d\n", __func__ , self->tx_buff.len); /* Save current set */ @@ -579,30 +571,13 @@ static void w83977af_dma_write(struct w83977af_ir *self, int iobase) /* Choose transmit DMA channel */ switch_bank(iobase, SET2); outb(ADCR1_D_CHSW|/*ADCR1_DMA_F|*/ADCR1_ADV_SL, iobase+ADCR1); -#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS - spin_lock_irqsave(&self->lock, flags); - - disable_dma(self->io.dma); - clear_dma_ff(self->io.dma); - set_dma_mode(self->io.dma, DMA_MODE_READ); - set_dma_addr(self->io.dma, self->tx_buff_dma); - set_dma_count(self->io.dma, self->tx_buff.len); -#else irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len, DMA_MODE_WRITE); -#endif self->io.direction = IO_XMIT; /* Enable DMA */ switch_bank(iobase, SET0); -#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS - hcr = inb(iobase+HCR); - outb(hcr | HCR_EN_DMA, iobase+HCR); - enable_dma(self->io.dma); - spin_unlock_irqrestore(&self->lock, flags); -#else outb(inb(iobase+HCR) | HCR_EN_DMA | HCR_TX_WT, iobase+HCR); -#endif /* Restore set register */ outb(set, iobase+SSR); @@ -711,7 +686,7 @@ static int w83977af_dma_receive(struct w83977af_ir *self) { int iobase; __u8 set; -#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS +#ifdef CONFIG_ARCH_NETWINDER unsigned long flags; __u8 hcr; #endif @@ -736,7 +711,7 @@ static int w83977af_dma_receive(struct w83977af_ir *self) self->io.direction = IO_RECV; self->rx_buff.data = self->rx_buff.head; -#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS +#ifdef CONFIG_ARCH_NETWINDER spin_lock_irqsave(&self->lock, flags); disable_dma(self->io.dma); @@ -759,7 +734,7 @@ static int w83977af_dma_receive(struct w83977af_ir *self) /* Enable DMA */ switch_bank(iobase, SET0); -#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS +#ifdef CONFIG_ARCH_NETWINDER hcr = inb(iobase+HCR); outb(hcr | HCR_EN_DMA, iobase+HCR); enable_dma(self->io.dma); diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index b0e2865a681078..f0118d1a3e4687 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -40,10 +41,18 @@ struct macvlan_port { struct hlist_head vlan_hash[MACVLAN_HASH_SIZE]; struct list_head vlans; struct rcu_head rcu; + struct sk_buff_head bc_queue; + struct work_struct bc_work; bool passthru; int count; }; +struct macvlan_skb_cb { + const struct macvlan_dev *src; +}; + +#define MACVLAN_SKB_CB(__skb) ((struct macvlan_skb_cb *)&((__skb)->cb[0])) + static void macvlan_port_destroy(struct net_device *dev); static struct macvlan_port *macvlan_port_get_rcu(const struct net_device *dev) @@ -120,7 +129,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev = vlan->dev; if (local) - return dev_forward_skb(dev, skb); + return __dev_forward_skb(dev, skb); skb->dev = dev; if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) @@ -128,7 +137,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb, else skb->pkt_type = PACKET_MULTICAST; - return netif_rx(skb); + return 0; } static u32 macvlan_hash_mix(const struct macvlan_dev *vlan) @@ -175,32 +184,32 @@ static void macvlan_broadcast(struct sk_buff *skb, if (likely(nskb)) err = macvlan_broadcast_one( nskb, vlan, eth, - mode == MACVLAN_MODE_BRIDGE); + mode == MACVLAN_MODE_BRIDGE) ?: + netif_rx_ni(nskb); macvlan_count_rx(vlan, skb->len + ETH_HLEN, err == NET_RX_SUCCESS, 1); } } } -/* called under rcu_read_lock() from netif_receive_skb */ -static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) +static void macvlan_process_broadcast(struct work_struct *w) { - struct macvlan_port *port; - struct sk_buff *skb = *pskb; - const struct ethhdr *eth = eth_hdr(skb); - const struct macvlan_dev *vlan; - const struct macvlan_dev *src; - struct net_device *dev; - unsigned int len = 0; - int ret = NET_RX_DROP; + struct macvlan_port *port = container_of(w, struct macvlan_port, + bc_work); + struct sk_buff *skb; + struct sk_buff_head list; + + skb_queue_head_init(&list); + + spin_lock_bh(&port->bc_queue.lock); + skb_queue_splice_tail_init(&port->bc_queue, &list); + spin_unlock_bh(&port->bc_queue.lock); + + while ((skb = __skb_dequeue(&list))) { + const struct macvlan_dev *src = MACVLAN_SKB_CB(skb)->src; + + rcu_read_lock(); - port = macvlan_port_get_rcu(skb->dev); - if (is_multicast_ether_addr(eth->h_dest)) { - skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN); - if (!skb) - return RX_HANDLER_CONSUMED; - eth = eth_hdr(skb); - src = macvlan_hash_lookup(port, eth->h_source); if (!src) /* frame comes from an external address */ macvlan_broadcast(skb, port, NULL, @@ -213,20 +222,80 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) macvlan_broadcast(skb, port, src->dev, MACVLAN_MODE_VEPA | MACVLAN_MODE_BRIDGE); - else if (src->mode == MACVLAN_MODE_BRIDGE) + else /* * flood only to VEPA ports, bridge ports * already saw the frame on the way out. */ macvlan_broadcast(skb, port, src->dev, MACVLAN_MODE_VEPA); - else { + + rcu_read_unlock(); + + kfree_skb(skb); + } +} + +static void macvlan_broadcast_enqueue(struct macvlan_port *port, + struct sk_buff *skb) +{ + struct sk_buff *nskb; + int err = -ENOMEM; + + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) + goto err; + + spin_lock(&port->bc_queue.lock); + if (skb_queue_len(&port->bc_queue) < skb->dev->tx_queue_len) { + __skb_queue_tail(&port->bc_queue, nskb); + err = 0; + } + spin_unlock(&port->bc_queue.lock); + + if (err) + goto free_nskb; + + schedule_work(&port->bc_work); + return; + +free_nskb: + kfree_skb(nskb); +err: + atomic_long_inc(&skb->dev->rx_dropped); +} + +/* called under rcu_read_lock() from netif_receive_skb */ +static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) +{ + struct macvlan_port *port; + struct sk_buff *skb = *pskb; + const struct ethhdr *eth = eth_hdr(skb); + const struct macvlan_dev *vlan; + const struct macvlan_dev *src; + struct net_device *dev; + unsigned int len = 0; + int ret = NET_RX_DROP; + + port = macvlan_port_get_rcu(skb->dev); + if (is_multicast_ether_addr(eth->h_dest)) { + skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN); + if (!skb) + return RX_HANDLER_CONSUMED; + eth = eth_hdr(skb); + src = macvlan_hash_lookup(port, eth->h_source); + if (src && src->mode != MACVLAN_MODE_VEPA && + src->mode != MACVLAN_MODE_BRIDGE) { /* forward to original port. */ vlan = src; - ret = macvlan_broadcast_one(skb, vlan, eth, 0); + ret = macvlan_broadcast_one(skb, vlan, eth, 0) ?: + netif_rx(skb); goto out; } + MACVLAN_SKB_CB(skb)->src = src; + macvlan_broadcast_enqueue(port, skb); + return RX_HANDLER_PASS; } @@ -761,6 +830,9 @@ static int macvlan_port_create(struct net_device *dev) for (i = 0; i < MACVLAN_HASH_SIZE; i++) INIT_HLIST_HEAD(&port->vlan_hash[i]); + skb_queue_head_init(&port->bc_queue); + INIT_WORK(&port->bc_work, macvlan_process_broadcast); + err = netdev_rx_handler_register(dev, macvlan_handle_frame, port); if (err) kfree(port); @@ -773,6 +845,7 @@ static void macvlan_port_destroy(struct net_device *dev) { struct macvlan_port *port = macvlan_port_get_rtnl(dev); + cancel_work_sync(&port->bc_work); dev->priv_flags &= ~IFF_MACVLAN_PORT; netdev_rx_handler_unregister(dev); kfree_rcu(port, rcu); diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 643464d5a727b3..6c622aedbae111 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -144,41 +144,11 @@ static int at803x_resume(struct phy_device *phydev) static int at803x_config_init(struct phy_device *phydev) { - int val; int ret; - u32 features; - - features = SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_AUI | - SUPPORTED_FIBRE | SUPPORTED_BNC; - - val = phy_read(phydev, MII_BMSR); - if (val < 0) - return val; - - if (val & BMSR_ANEGCAPABLE) - features |= SUPPORTED_Autoneg; - if (val & BMSR_100FULL) - features |= SUPPORTED_100baseT_Full; - if (val & BMSR_100HALF) - features |= SUPPORTED_100baseT_Half; - if (val & BMSR_10FULL) - features |= SUPPORTED_10baseT_Full; - if (val & BMSR_10HALF) - features |= SUPPORTED_10baseT_Half; - - if (val & BMSR_ESTATEN) { - val = phy_read(phydev, MII_ESTATUS); - if (val < 0) - return val; - - if (val & ESTATUS_1000_TFULL) - features |= SUPPORTED_1000baseT_Full; - if (val & ESTATUS_1000_THALF) - features |= SUPPORTED_1000baseT_Half; - } - phydev->supported = features; - phydev->advertising = features; + ret = genphy_config_init(phydev); + if (ret < 0) + return ret; if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { ret = phy_write(phydev, AT803X_DEBUG_ADDR, @@ -283,8 +253,7 @@ static int __init atheros_init(void) static void __exit atheros_exit(void) { - return phy_drivers_unregister(at803x_driver, - ARRAY_SIZE(at803x_driver)); + phy_drivers_unregister(at803x_driver, ARRAY_SIZE(at803x_driver)); } module_init(atheros_init); diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 76f54b32a12083..68a9a3867c0f23 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -69,6 +69,73 @@ struct mii_bus *mdiobus_alloc_size(size_t size) } EXPORT_SYMBOL(mdiobus_alloc_size); +static void _devm_mdiobus_free(struct device *dev, void *res) +{ + mdiobus_free(*(struct mii_bus **)res); +} + +static int devm_mdiobus_match(struct device *dev, void *res, void *data) +{ + struct mii_bus **r = res; + + if (WARN_ON(!r || !*r)) + return 0; + + return *r == data; +} + +/** + * devm_mdiobus_alloc_size - Resource-managed mdiobus_alloc_size() + * @dev: Device to allocate mii_bus for + * @sizeof_priv: Space to allocate for private structure. + * + * Managed mdiobus_alloc_size. mii_bus allocated with this function is + * automatically freed on driver detach. + * + * If an mii_bus allocated with this function needs to be freed separately, + * devm_mdiobus_free() must be used. + * + * RETURNS: + * Pointer to allocated mii_bus on success, NULL on failure. + */ +struct mii_bus *devm_mdiobus_alloc_size(struct device *dev, int sizeof_priv) +{ + struct mii_bus **ptr, *bus; + + ptr = devres_alloc(_devm_mdiobus_free, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + /* use raw alloc_dr for kmalloc caller tracing */ + bus = mdiobus_alloc_size(sizeof_priv); + if (bus) { + *ptr = bus; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return bus; +} +EXPORT_SYMBOL_GPL(devm_mdiobus_alloc); + +/** + * devm_mdiobus_free - Resource-managed mdiobus_free() + * @dev: Device this mii_bus belongs to + * @bus: the mii_bus associated with the device + * + * Free mii_bus allocated with devm_mdiobus_alloc_size(). + */ +void devm_mdiobus_free(struct device *dev, struct mii_bus *bus) +{ + int rc; + + rc = devres_release(dev, _devm_mdiobus_free, + devm_mdiobus_match, bus); + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_mdiobus_free); + /** * mdiobus_release - mii_bus device release callback * @d: the target struct device that contains the mii_bus diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index d849684231c149..bc7c7d2f75f26e 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -283,6 +283,110 @@ static int ksz9021_config_init(struct phy_device *phydev) return 0; } +#define MII_KSZ9031RN_MMD_CTRL_REG 0x0d +#define MII_KSZ9031RN_MMD_REGDATA_REG 0x0e +#define OP_DATA 1 +#define KSZ9031_PS_TO_REG 60 + +/* Extended registers */ +#define MII_KSZ9031RN_CONTROL_PAD_SKEW 4 +#define MII_KSZ9031RN_RX_DATA_PAD_SKEW 5 +#define MII_KSZ9031RN_TX_DATA_PAD_SKEW 6 +#define MII_KSZ9031RN_CLK_PAD_SKEW 8 + +static int ksz9031_extended_write(struct phy_device *phydev, + u8 mode, u32 dev_addr, u32 regnum, u16 val) +{ + phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, dev_addr); + phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, regnum); + phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, (mode << 14) | dev_addr); + return phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, val); +} + +static int ksz9031_extended_read(struct phy_device *phydev, + u8 mode, u32 dev_addr, u32 regnum) +{ + phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, dev_addr); + phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, regnum); + phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, (mode << 14) | dev_addr); + return phy_read(phydev, MII_KSZ9031RN_MMD_REGDATA_REG); +} + +static int ksz9031_of_load_skew_values(struct phy_device *phydev, + struct device_node *of_node, + u16 reg, size_t field_sz, + char *field[], u8 numfields) +{ + int val[4] = {-1, -2, -3, -4}; + int matches = 0; + u16 mask; + u16 maxval; + u16 newval; + int i; + + for (i = 0; i < numfields; i++) + if (!of_property_read_u32(of_node, field[i], val + i)) + matches++; + + if (!matches) + return 0; + + if (matches < numfields) + newval = ksz9031_extended_read(phydev, OP_DATA, 2, reg); + else + newval = 0; + + maxval = (field_sz == 4) ? 0xf : 0x1f; + for (i = 0; i < numfields; i++) + if (val[i] != -(i + 1)) { + mask = 0xffff; + mask ^= maxval << (field_sz * i); + newval = (newval & mask) | + (((val[i] / KSZ9031_PS_TO_REG) & maxval) + << (field_sz * i)); + } + + return ksz9031_extended_write(phydev, OP_DATA, 2, reg, newval); +} + +static int ksz9031_config_init(struct phy_device *phydev) +{ + struct device *dev = &phydev->dev; + struct device_node *of_node = dev->of_node; + char *clk_skews[2] = {"rxc-skew-ps", "txc-skew-ps"}; + char *rx_data_skews[4] = { + "rxd0-skew-ps", "rxd1-skew-ps", + "rxd2-skew-ps", "rxd3-skew-ps" + }; + char *tx_data_skews[4] = { + "txd0-skew-ps", "txd1-skew-ps", + "txd2-skew-ps", "txd3-skew-ps" + }; + char *control_skews[2] = {"txen-skew-ps", "rxdv-skew-ps"}; + + if (!of_node && dev->parent->of_node) + of_node = dev->parent->of_node; + + if (of_node) { + ksz9031_of_load_skew_values(phydev, of_node, + MII_KSZ9031RN_CLK_PAD_SKEW, 5, + clk_skews, 2); + + ksz9031_of_load_skew_values(phydev, of_node, + MII_KSZ9031RN_CONTROL_PAD_SKEW, 4, + control_skews, 2); + + ksz9031_of_load_skew_values(phydev, of_node, + MII_KSZ9031RN_RX_DATA_PAD_SKEW, 4, + rx_data_skews, 4); + + ksz9031_of_load_skew_values(phydev, of_node, + MII_KSZ9031RN_TX_DATA_PAD_SKEW, 4, + tx_data_skews, 4); + } + return 0; +} + #define KSZ8873MLL_GLOBAL_CONTROL_4 0x06 #define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX (1 << 6) #define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED (1 << 4) @@ -469,7 +573,7 @@ static struct phy_driver ksphy_driver[] = { .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, - .config_init = kszphy_config_init, + .config_init = ksz9031_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 0ce606624296a8..466ae3e0632201 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1067,7 +1067,7 @@ int genphy_soft_reset(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_soft_reset); -static int genphy_config_init(struct phy_device *phydev) +int genphy_config_init(struct phy_device *phydev) { int val; u32 features; @@ -1118,6 +1118,7 @@ static int gen10g_soft_reset(struct phy_device *phydev) /* Do nothing for now */ return 0; } +EXPORT_SYMBOL(genphy_config_init); static int gen10g_config_init(struct phy_device *phydev) { diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 11f34813e23fb5..180c49479c42f9 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -249,8 +249,7 @@ static int __init smsc_init(void) static void __exit smsc_exit(void) { - return phy_drivers_unregister(smsc_phy_driver, - ARRAY_SIZE(smsc_phy_driver)); + phy_drivers_unregister(smsc_phy_driver, ARRAY_SIZE(smsc_phy_driver)); } MODULE_DESCRIPTION("SMSC PHY driver"); diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c index 14372c65a7e820..5dc0935da99c52 100644 --- a/drivers/net/phy/vitesse.c +++ b/drivers/net/phy/vitesse.c @@ -319,8 +319,7 @@ static int __init vsc82xx_init(void) static void __exit vsc82xx_exit(void) { - return phy_drivers_unregister(vsc82xx_driver, - ARRAY_SIZE(vsc82xx_driver)); + phy_drivers_unregister(vsc82xx_driver, ARRAY_SIZE(vsc82xx_driver)); } module_init(vsc82xx_init); diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index c9f3281506af56..13f7705fd679a1 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -204,17 +204,23 @@ static void do_neigh_solicit(struct usbnet *dev, u8 *buf, u16 tci) return; /* need to send the NA on the VLAN dev, if any */ - if (tci) + rcu_read_lock(); + if (tci) { netdev = __vlan_find_dev_deep(dev->net, htons(ETH_P_8021Q), tci); - else + if (!netdev) { + rcu_read_unlock(); + return; + } + } else { netdev = dev->net; - if (!netdev) - return; + } + dev_hold(netdev); + rcu_read_unlock(); in6_dev = in6_dev_get(netdev); if (!in6_dev) - return; + goto out; is_router = !!in6_dev->cnf.forwarding; in6_dev_put(in6_dev); @@ -224,6 +230,8 @@ static void do_neigh_solicit(struct usbnet *dev, u8 *buf, u16 tci) true /* solicited */, false /* override */, true /* inc_opt */); +out: + dev_put(netdev); } static bool is_neigh_solicit(u8 *buf, size_t len) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 8a852b5f215f1c..b852bb368acc8c 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1724,6 +1724,13 @@ static int virtnet_probe(struct virtio_device *vdev) if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) vi->has_cvq = true; + if (vi->any_header_sg) { + if (vi->mergeable_rx_bufs) + dev->needed_headroom = sizeof(struct virtio_net_hdr_mrg_rxbuf); + else + dev->needed_headroom = sizeof(struct virtio_net_hdr); + } + /* Use single tx/rx queue pair as default */ vi->curr_queue_pairs = 1; vi->max_queue_pairs = max_queue_pairs; diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 4dbb2ed85b9724..1dfee9a7fbf785 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -127,6 +127,7 @@ struct vxlan_dev { struct list_head next; /* vxlan's per namespace list */ struct vxlan_sock *vn_sock; /* listening socket */ struct net_device *dev; + struct net *net; /* netns for packet i/o */ struct vxlan_rdst default_dst; /* default destination */ union vxlan_addr saddr; /* source address */ __be16 dst_port; @@ -1203,6 +1204,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, remote_ip = &vxlan->default_dst.remote_ip; skb_reset_mac_header(skb); + skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev))); skb->protocol = eth_type_trans(skb, vxlan->dev); /* Ignore packet loops (and multicast echo) */ @@ -1618,7 +1620,8 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, struct dst_entry *dst, struct sk_buff *skb, struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr, __u8 prio, __u8 ttl, - __be16 src_port, __be16 dst_port, __be32 vni) + __be16 src_port, __be16 dst_port, __be32 vni, + bool xnet) { struct ipv6hdr *ip6h; struct vxlanhdr *vxh; @@ -1631,7 +1634,7 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, skb->encapsulation = 1; } - skb_scrub_packet(skb, false); + skb_scrub_packet(skb, xnet); min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len + VXLAN_HLEN + sizeof(struct ipv6hdr) @@ -1711,7 +1714,7 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, int vxlan_xmit_skb(struct vxlan_sock *vs, struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, - __be16 src_port, __be16 dst_port, __be32 vni) + __be16 src_port, __be16 dst_port, __be32 vni, bool xnet) { struct vxlanhdr *vxh; struct udphdr *uh; @@ -1760,7 +1763,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, return err; return iptunnel_xmit(vs->sock->sk, rt, skb, src, dst, IPPROTO_UDP, - tos, ttl, df, false); + tos, ttl, df, xnet); } EXPORT_SYMBOL_GPL(vxlan_xmit_skb); @@ -1853,7 +1856,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, fl4.daddr = dst->sin.sin_addr.s_addr; fl4.saddr = vxlan->saddr.sin.sin_addr.s_addr; - rt = ip_route_output_key(dev_net(dev), &fl4); + rt = ip_route_output_key(vxlan->net, &fl4); if (IS_ERR(rt)) { netdev_dbg(dev, "no route to %pI4\n", &dst->sin.sin_addr.s_addr); @@ -1874,7 +1877,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct vxlan_dev *dst_vxlan; ip_rt_put(rt); - dst_vxlan = vxlan_find_vni(dev_net(dev), vni, dst_port); + dst_vxlan = vxlan_find_vni(vxlan->net, vni, dst_port); if (!dst_vxlan) goto tx_error; vxlan_encap_bypass(skb, vxlan, dst_vxlan); @@ -1887,7 +1890,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, err = vxlan_xmit_skb(vxlan->vn_sock, rt, skb, fl4.saddr, dst->sin.sin_addr.s_addr, tos, ttl, df, src_port, dst_port, - htonl(vni << 8)); + htonl(vni << 8), + !net_eq(vxlan->net, dev_net(vxlan->dev))); if (err < 0) goto rt_tx_error; @@ -1927,7 +1931,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct vxlan_dev *dst_vxlan; dst_release(ndst); - dst_vxlan = vxlan_find_vni(dev_net(dev), vni, dst_port); + dst_vxlan = vxlan_find_vni(vxlan->net, vni, dst_port); if (!dst_vxlan) goto tx_error; vxlan_encap_bypass(skb, vxlan, dst_vxlan); @@ -1938,7 +1942,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, err = vxlan6_xmit_skb(vxlan->vn_sock, ndst, skb, dev, &fl6.saddr, &fl6.daddr, 0, ttl, - src_port, dst_port, htonl(vni << 8)); + src_port, dst_port, htonl(vni << 8), + !net_eq(vxlan->net, dev_net(vxlan->dev))); #endif } @@ -2082,7 +2087,7 @@ static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan) static int vxlan_init(struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); - struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); + struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); struct vxlan_sock *vs; dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); @@ -2090,7 +2095,7 @@ static int vxlan_init(struct net_device *dev) return -ENOMEM; spin_lock(&vn->sock_lock); - vs = vxlan_find_sock(dev_net(dev), vxlan->dst_port); + vs = vxlan_find_sock(vxlan->net, vxlan->dst_port); if (vs) { /* If we have a socket with same port already, reuse it */ atomic_inc(&vs->refcnt); @@ -2172,8 +2177,8 @@ static void vxlan_flush(struct vxlan_dev *vxlan) /* Cleanup timer and forwarding table on shutdown */ static int vxlan_stop(struct net_device *dev) { - struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); struct vxlan_sock *vs = vxlan->vn_sock; if (vs && vxlan_addr_multicast(&vxlan->default_dst.remote_ip) && @@ -2202,7 +2207,7 @@ static int vxlan_change_mtu(struct net_device *dev, int new_mtu) struct net_device *lowerdev; int max_mtu; - lowerdev = __dev_get_by_index(dev_net(dev), dst->remote_ifindex); + lowerdev = __dev_get_by_index(vxlan->net, dst->remote_ifindex); if (lowerdev == NULL) return eth_change_mtu(dev, new_mtu); @@ -2285,7 +2290,6 @@ static void vxlan_setup(struct net_device *dev) dev->tx_queue_len = 0; dev->features |= NETIF_F_LLTX; - dev->features |= NETIF_F_NETNS_LOCAL; dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; dev->features |= NETIF_F_RXCSUM; dev->features |= NETIF_F_GSO_SOFTWARE; @@ -2578,7 +2582,7 @@ EXPORT_SYMBOL_GPL(vxlan_sock_add); static void vxlan_sock_work(struct work_struct *work) { struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, sock_work); - struct net *net = dev_net(vxlan->dev); + struct net *net = vxlan->net; struct vxlan_net *vn = net_generic(net, vxlan_net_id); __be16 port = vxlan->dst_port; struct vxlan_sock *nvs; @@ -2605,6 +2609,8 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, if (!data[IFLA_VXLAN_ID]) return -EINVAL; + vxlan->net = dev_net(dev); + vni = nla_get_u32(data[IFLA_VXLAN_ID]); dst->remote_vni = vni; @@ -2739,8 +2745,8 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, static void vxlan_dellink(struct net_device *dev, struct list_head *head) { - struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); spin_lock(&vn->sock_lock); if (!hlist_unhashed(&vxlan->hlist)) @@ -2905,8 +2911,33 @@ static __net_init int vxlan_init_net(struct net *net) return 0; } +static void __net_exit vxlan_exit_net(struct net *net) +{ + struct vxlan_net *vn = net_generic(net, vxlan_net_id); + struct vxlan_dev *vxlan, *next; + struct net_device *dev, *aux; + LIST_HEAD(list); + + rtnl_lock(); + for_each_netdev_safe(net, dev, aux) + if (dev->rtnl_link_ops == &vxlan_link_ops) + unregister_netdevice_queue(dev, &list); + + list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next) { + /* If vxlan->dev is in the same netns, it has already been added + * to the list by the previous loop. + */ + if (!net_eq(dev_net(vxlan->dev), net)) + unregister_netdevice_queue(dev, &list); + } + + unregister_netdevice_many(&list); + rtnl_unlock(); +} + static struct pernet_operations vxlan_net_ops = { .init = vxlan_init_net, + .exit = vxlan_exit_net, .id = &vxlan_net_id, .size = sizeof(struct vxlan_net), }; diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 507d9a9ee69ad4..f92050617ae682 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1090,7 +1090,8 @@ static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return ret; } -static void ar5523_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void ar5523_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct ar5523 *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index a1f0996288508e..17d221abd58c0b 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -175,7 +175,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar, return 0; } -int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param) +int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result) { struct bmi_cmd cmd; union bmi_resp resp; @@ -184,7 +184,7 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param) int ret; ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n", - address, *param); + address, param); if (ar->bmi.done_sent) { ath10k_warn("command disallowed\n"); @@ -193,7 +193,7 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param) cmd.id = __cpu_to_le32(BMI_EXECUTE); cmd.execute.addr = __cpu_to_le32(address); - cmd.execute.param = __cpu_to_le32(*param); + cmd.execute.param = __cpu_to_le32(param); ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen); if (ret) { @@ -204,10 +204,13 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param) if (resplen < sizeof(resp.execute)) { ath10k_warn("invalid execute response length (%d)\n", resplen); - return ret; + return -EIO; } - *param = __le32_to_cpu(resp.execute.result); + *result = __le32_to_cpu(resp.execute.result); + + ath10k_dbg(ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result); + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 8d81ce1cec216c..3a9bdf51c96a21 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -217,7 +217,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address, ret; \ }) -int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param); +int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result); int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address); int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length); int ath10k_bmi_fast_download(struct ath10k *ar, u32 address, diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index a79499c8235009..1e4cad8632b527 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -840,35 +840,17 @@ void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state, static int ath10k_ce_init_src_ring(struct ath10k *ar, unsigned int ce_id, - struct ath10k_ce_pipe *ce_state, const struct ce_attr *attr) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_ring *src_ring; - unsigned int nentries = attr->src_nentries; - unsigned int ce_nbytes; - u32 ctrl_addr = ath10k_ce_base_address(ce_id); - dma_addr_t base_addr; - char *ptr; - - nentries = roundup_pow_of_two(nentries); - - if (ce_state->src_ring) { - WARN_ON(ce_state->src_ring->nentries != nentries); - return 0; - } + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_ring *src_ring = ce_state->src_ring; + u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id); - ce_nbytes = sizeof(struct ath10k_ce_ring) + (nentries * sizeof(void *)); - ptr = kzalloc(ce_nbytes, GFP_KERNEL); - if (ptr == NULL) - return -ENOMEM; + nentries = roundup_pow_of_two(attr->src_nentries); - ce_state->src_ring = (struct ath10k_ce_ring *)ptr; - src_ring = ce_state->src_ring; - - ptr += sizeof(struct ath10k_ce_ring); - src_ring->nentries = nentries; - src_ring->nentries_mask = nentries - 1; + memset(src_ring->per_transfer_context, 0, + nentries * sizeof(*src_ring->per_transfer_context)); src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); src_ring->sw_index &= src_ring->nentries_mask; @@ -878,21 +860,87 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar, ath10k_ce_src_ring_write_index_get(ar, ctrl_addr); src_ring->write_index &= src_ring->nentries_mask; - src_ring->per_transfer_context = (void **)ptr; + ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, + src_ring->base_addr_ce_space); + ath10k_ce_src_ring_size_set(ar, ctrl_addr, nentries); + ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, attr->src_sz_max); + ath10k_ce_src_ring_byte_swap_set(ar, ctrl_addr, 0); + ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0); + ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries); + + ath10k_dbg(ATH10K_DBG_BOOT, + "boot init ce src ring id %d entries %d base_addr %p\n", + ce_id, nentries, src_ring->base_addr_owner_space); + + return 0; +} + +static int ath10k_ce_init_dest_ring(struct ath10k *ar, + unsigned int ce_id, + const struct ce_attr *attr) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; + u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id); + + nentries = roundup_pow_of_two(attr->dest_nentries); + + memset(dest_ring->per_transfer_context, 0, + nentries * sizeof(*dest_ring->per_transfer_context)); + + dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); + dest_ring->sw_index &= dest_ring->nentries_mask; + dest_ring->write_index = + ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr); + dest_ring->write_index &= dest_ring->nentries_mask; + + ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, + dest_ring->base_addr_ce_space); + ath10k_ce_dest_ring_size_set(ar, ctrl_addr, nentries); + ath10k_ce_dest_ring_byte_swap_set(ar, ctrl_addr, 0); + ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0); + ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries); + + ath10k_dbg(ATH10K_DBG_BOOT, + "boot ce dest ring id %d entries %d base_addr %p\n", + ce_id, nentries, dest_ring->base_addr_owner_space); + + return 0; +} + +static struct ath10k_ce_ring * +ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, + const struct ce_attr *attr) +{ + struct ath10k_ce_ring *src_ring; + u32 nentries = attr->src_nentries; + dma_addr_t base_addr; + + nentries = roundup_pow_of_two(nentries); + + src_ring = kzalloc(sizeof(*src_ring) + + (nentries * + sizeof(*src_ring->per_transfer_context)), + GFP_KERNEL); + if (src_ring == NULL) + return ERR_PTR(-ENOMEM); + + src_ring->nentries = nentries; + src_ring->nentries_mask = nentries - 1; /* * Legacy platforms that do not support cache * coherent DMA are unsupported */ src_ring->base_addr_owner_space_unaligned = - pci_alloc_consistent(ar_pci->pdev, - (nentries * sizeof(struct ce_desc) + - CE_DESC_RING_ALIGN), - &base_addr); + dma_alloc_coherent(ar->dev, + (nentries * sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + &base_addr, GFP_KERNEL); if (!src_ring->base_addr_owner_space_unaligned) { - kfree(ce_state->src_ring); - ce_state->src_ring = NULL; - return -ENOMEM; + kfree(src_ring); + return ERR_PTR(-ENOMEM); } src_ring->base_addr_ce_space_unaligned = base_addr; @@ -912,88 +960,54 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar, kmalloc((nentries * sizeof(struct ce_desc) + CE_DESC_RING_ALIGN), GFP_KERNEL); if (!src_ring->shadow_base_unaligned) { - pci_free_consistent(ar_pci->pdev, - (nentries * sizeof(struct ce_desc) + - CE_DESC_RING_ALIGN), - src_ring->base_addr_owner_space, - src_ring->base_addr_ce_space); - kfree(ce_state->src_ring); - ce_state->src_ring = NULL; - return -ENOMEM; + dma_free_coherent(ar->dev, + (nentries * sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + src_ring->base_addr_owner_space, + src_ring->base_addr_ce_space); + kfree(src_ring); + return ERR_PTR(-ENOMEM); } src_ring->shadow_base = PTR_ALIGN( src_ring->shadow_base_unaligned, CE_DESC_RING_ALIGN); - ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, - src_ring->base_addr_ce_space); - ath10k_ce_src_ring_size_set(ar, ctrl_addr, nentries); - ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, attr->src_sz_max); - ath10k_ce_src_ring_byte_swap_set(ar, ctrl_addr, 0); - ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0); - ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries); - - ath10k_dbg(ATH10K_DBG_BOOT, - "boot ce src ring id %d entries %d base_addr %p\n", - ce_id, nentries, src_ring->base_addr_owner_space); - - return 0; + return src_ring; } -static int ath10k_ce_init_dest_ring(struct ath10k *ar, - unsigned int ce_id, - struct ath10k_ce_pipe *ce_state, - const struct ce_attr *attr) +static struct ath10k_ce_ring * +ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id, + const struct ce_attr *attr) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_ring *dest_ring; - unsigned int nentries = attr->dest_nentries; - unsigned int ce_nbytes; - u32 ctrl_addr = ath10k_ce_base_address(ce_id); + u32 nentries; dma_addr_t base_addr; - char *ptr; - nentries = roundup_pow_of_two(nentries); + nentries = roundup_pow_of_two(attr->dest_nentries); - if (ce_state->dest_ring) { - WARN_ON(ce_state->dest_ring->nentries != nentries); - return 0; - } - - ce_nbytes = sizeof(struct ath10k_ce_ring) + (nentries * sizeof(void *)); - ptr = kzalloc(ce_nbytes, GFP_KERNEL); - if (ptr == NULL) - return -ENOMEM; - - ce_state->dest_ring = (struct ath10k_ce_ring *)ptr; - dest_ring = ce_state->dest_ring; + dest_ring = kzalloc(sizeof(*dest_ring) + + (nentries * + sizeof(*dest_ring->per_transfer_context)), + GFP_KERNEL); + if (dest_ring == NULL) + return ERR_PTR(-ENOMEM); - ptr += sizeof(struct ath10k_ce_ring); dest_ring->nentries = nentries; dest_ring->nentries_mask = nentries - 1; - dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); - dest_ring->sw_index &= dest_ring->nentries_mask; - dest_ring->write_index = - ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr); - dest_ring->write_index &= dest_ring->nentries_mask; - - dest_ring->per_transfer_context = (void **)ptr; - /* * Legacy platforms that do not support cache * coherent DMA are unsupported */ dest_ring->base_addr_owner_space_unaligned = - pci_alloc_consistent(ar_pci->pdev, - (nentries * sizeof(struct ce_desc) + - CE_DESC_RING_ALIGN), - &base_addr); + dma_alloc_coherent(ar->dev, + (nentries * sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + &base_addr, GFP_KERNEL); if (!dest_ring->base_addr_owner_space_unaligned) { - kfree(ce_state->dest_ring); - ce_state->dest_ring = NULL; - return -ENOMEM; + kfree(dest_ring); + return ERR_PTR(-ENOMEM); } dest_ring->base_addr_ce_space_unaligned = base_addr; @@ -1012,39 +1026,7 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, dest_ring->base_addr_ce_space_unaligned, CE_DESC_RING_ALIGN); - ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, - dest_ring->base_addr_ce_space); - ath10k_ce_dest_ring_size_set(ar, ctrl_addr, nentries); - ath10k_ce_dest_ring_byte_swap_set(ar, ctrl_addr, 0); - ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0); - ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries); - - ath10k_dbg(ATH10K_DBG_BOOT, - "boot ce dest ring id %d entries %d base_addr %p\n", - ce_id, nentries, dest_ring->base_addr_owner_space); - - return 0; -} - -static struct ath10k_ce_pipe *ath10k_ce_init_state(struct ath10k *ar, - unsigned int ce_id, - const struct ce_attr *attr) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; - u32 ctrl_addr = ath10k_ce_base_address(ce_id); - - spin_lock_bh(&ar_pci->ce_lock); - - ce_state->ar = ar; - ce_state->id = ce_id; - ce_state->ctrl_addr = ctrl_addr; - ce_state->attr_flags = attr->flags; - ce_state->src_sz_max = attr->src_sz_max; - - spin_unlock_bh(&ar_pci->ce_lock); - - return ce_state; + return dest_ring; } /* @@ -1054,11 +1036,11 @@ static struct ath10k_ce_pipe *ath10k_ce_init_state(struct ath10k *ar, * initialization. It may be that only one side or the other is * initialized by software/firmware. */ -struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, - unsigned int ce_id, - const struct ce_attr *attr) +int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, + const struct ce_attr *attr) { - struct ath10k_ce_pipe *ce_state; + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; int ret; /* @@ -1074,64 +1056,128 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, ret = ath10k_pci_wake(ar); if (ret) - return NULL; + return ret; - ce_state = ath10k_ce_init_state(ar, ce_id, attr); - if (!ce_state) { - ath10k_err("Failed to initialize CE state for ID: %d\n", ce_id); - goto out; - } + spin_lock_bh(&ar_pci->ce_lock); + ce_state->ar = ar; + ce_state->id = ce_id; + ce_state->ctrl_addr = ath10k_ce_base_address(ce_id); + ce_state->attr_flags = attr->flags; + ce_state->src_sz_max = attr->src_sz_max; + spin_unlock_bh(&ar_pci->ce_lock); if (attr->src_nentries) { - ret = ath10k_ce_init_src_ring(ar, ce_id, ce_state, attr); + ret = ath10k_ce_init_src_ring(ar, ce_id, attr); if (ret) { ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n", ce_id, ret); - ath10k_ce_deinit(ce_state); - ce_state = NULL; goto out; } } if (attr->dest_nentries) { - ret = ath10k_ce_init_dest_ring(ar, ce_id, ce_state, attr); + ret = ath10k_ce_init_dest_ring(ar, ce_id, attr); if (ret) { ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n", ce_id, ret); - ath10k_ce_deinit(ce_state); - ce_state = NULL; goto out; } } out: ath10k_pci_sleep(ar); - return ce_state; + return ret; } -void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state) +static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id) +{ + u32 ctrl_addr = ath10k_ce_base_address(ce_id); + + ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, 0); + ath10k_ce_src_ring_size_set(ar, ctrl_addr, 0); + ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, 0); + ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, 0); +} + +static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id) +{ + u32 ctrl_addr = ath10k_ce_base_address(ce_id); + + ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, 0); + ath10k_ce_dest_ring_size_set(ar, ctrl_addr, 0); + ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, 0); +} + +void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) +{ + int ret; + + ret = ath10k_pci_wake(ar); + if (ret) + return; + + ath10k_ce_deinit_src_ring(ar, ce_id); + ath10k_ce_deinit_dest_ring(ar, ce_id); + + ath10k_pci_sleep(ar); +} + +int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, + const struct ce_attr *attr) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + int ret; + + if (attr->src_nentries) { + ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr); + if (IS_ERR(ce_state->src_ring)) { + ret = PTR_ERR(ce_state->src_ring); + ath10k_err("failed to allocate copy engine source ring %d: %d\n", + ce_id, ret); + ce_state->src_ring = NULL; + return ret; + } + } + + if (attr->dest_nentries) { + ce_state->dest_ring = ath10k_ce_alloc_dest_ring(ar, ce_id, + attr); + if (IS_ERR(ce_state->dest_ring)) { + ret = PTR_ERR(ce_state->dest_ring); + ath10k_err("failed to allocate copy engine destination ring %d: %d\n", + ce_id, ret); + ce_state->dest_ring = NULL; + return ret; + } + } + + return 0; +} + +void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) { - struct ath10k *ar = ce_state->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; if (ce_state->src_ring) { kfree(ce_state->src_ring->shadow_base_unaligned); - pci_free_consistent(ar_pci->pdev, - (ce_state->src_ring->nentries * - sizeof(struct ce_desc) + - CE_DESC_RING_ALIGN), - ce_state->src_ring->base_addr_owner_space, - ce_state->src_ring->base_addr_ce_space); + dma_free_coherent(ar->dev, + (ce_state->src_ring->nentries * + sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + ce_state->src_ring->base_addr_owner_space, + ce_state->src_ring->base_addr_ce_space); kfree(ce_state->src_ring); } if (ce_state->dest_ring) { - pci_free_consistent(ar_pci->pdev, - (ce_state->dest_ring->nentries * - sizeof(struct ce_desc) + - CE_DESC_RING_ALIGN), - ce_state->dest_ring->base_addr_owner_space, - ce_state->dest_ring->base_addr_ce_space); + dma_free_coherent(ar->dev, + (ce_state->dest_ring->nentries * + sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + ce_state->dest_ring->base_addr_owner_space, + ce_state->dest_ring->base_addr_ce_space); kfree(ce_state->dest_ring); } diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 8eb7f99ed99227..fd0bc3561e42a9 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -104,7 +104,8 @@ struct ath10k_ce_ring { void *shadow_base_unaligned; struct ce_desc *shadow_base; - void **per_transfer_context; + /* keep last */ + void *per_transfer_context[0]; }; struct ath10k_ce_pipe { @@ -210,10 +211,12 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, /*==================CE Engine Initialization=======================*/ -/* Initialize an instance of a CE */ -struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, - unsigned int ce_id, - const struct ce_attr *attr); +int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, + const struct ce_attr *attr); +void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id); +int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, + const struct ce_attr *attr); +void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id); /*==================CE Engine Shutdown=======================*/ /* @@ -236,8 +239,6 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, unsigned int *nbytesp, unsigned int *transfer_idp); -void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state); - /*==================CE Interrupt Handlers====================*/ void ath10k_ce_per_engine_service_any(struct ath10k *ar); void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id); diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index ebc5fc2ede75cb..6abde37fb339c9 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -249,30 +249,40 @@ static int ath10k_download_board_data(struct ath10k *ar) static int ath10k_download_and_run_otp(struct ath10k *ar) { - u32 address = ar->hw_params.patch_load_addr; - u32 exec_param; + u32 result, address = ar->hw_params.patch_load_addr; int ret; /* OTP is optional */ - if (!ar->otp_data || !ar->otp_len) + if (!ar->otp_data || !ar->otp_len) { + ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n", + ar->otp_data, ar->otp_len); return 0; + } + + ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", + address, ar->otp_len); ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len); if (ret) { ath10k_err("could not write otp (%d)\n", ret); - goto exit; + return ret; } - exec_param = 0; - ret = ath10k_bmi_execute(ar, address, &exec_param); + ret = ath10k_bmi_execute(ar, address, 0, &result); if (ret) { ath10k_err("could not execute otp (%d)\n", ret); - goto exit; + return ret; } -exit: - return ret; + ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); + + if (result != 0) { + ath10k_err("otp calibration failed: %d", result); + return -EINVAL; + } + + return 0; } static int ath10k_download_fw(struct ath10k *ar) @@ -389,8 +399,8 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) /* first fetch the firmware file (firmware-*.bin) */ ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name); if (IS_ERR(ar->firmware)) { - ath10k_err("Could not fetch firmware file '%s': %ld\n", - name, PTR_ERR(ar->firmware)); + ath10k_err("could not fetch firmware file '%s/%s': %ld\n", + ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware)); return PTR_ERR(ar->firmware); } @@ -401,14 +411,14 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1; if (len < magic_len) { - ath10k_err("firmware image too small to contain magic: %zu\n", - len); + ath10k_err("firmware file '%s/%s' too small to contain magic: %zu\n", + ar->hw_params.fw.dir, name, len); ret = -EINVAL; goto err; } if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) { - ath10k_err("Invalid firmware magic\n"); + ath10k_err("invalid firmware magic\n"); ret = -EINVAL; goto err; } @@ -430,7 +440,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) data += sizeof(*hdr); if (len < ie_len) { - ath10k_err("Invalid length for FW IE %d (%zu < %zu)\n", + ath10k_err("invalid length for FW IE %d (%zu < %zu)\n", ie_id, len, ie_len); ret = -EINVAL; goto err; @@ -513,8 +523,8 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) } if (!ar->firmware_data || !ar->firmware_len) { - ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from %s, skipping\n", - name); + ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n", + ar->hw_params.fw.dir, name); ret = -ENOMEDIUM; goto err; } @@ -531,7 +541,9 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) ar->hw_params.fw.board); if (IS_ERR(ar->board)) { ret = PTR_ERR(ar->board); - ath10k_err("could not fetch board data (%d)\n", ret); + ath10k_err("could not fetch board data '%s/%s' (%d)\n", + ar->hw_params.fw.dir, ar->hw_params.fw.board, + ret); goto err; } @@ -549,19 +561,21 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) { int ret; + ar->fw_api = 2; + ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); + ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE); - if (ret == 0) { - ar->fw_api = 2; - goto out; - } + if (ret == 0) + goto success; + + ar->fw_api = 1; + ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); ret = ath10k_core_fetch_firmware_api_1(ar); if (ret) return ret; - ar->fw_api = 1; - -out: +success: ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api); return 0; @@ -572,16 +586,22 @@ static int ath10k_init_download_firmware(struct ath10k *ar) int ret; ret = ath10k_download_board_data(ar); - if (ret) + if (ret) { + ath10k_err("failed to download board data: %d\n", ret); return ret; + } ret = ath10k_download_and_run_otp(ar); - if (ret) + if (ret) { + ath10k_err("failed to run otp: %d\n", ret); return ret; + } ret = ath10k_download_fw(ar); - if (ret) + if (ret) { + ath10k_err("failed to download firmware: %d\n", ret); return ret; + } return ret; } @@ -835,9 +855,12 @@ int ath10k_core_start(struct ath10k *ar) INIT_LIST_HEAD(&ar->arvifs); if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) - ath10k_info("%s (0x%x) fw %s api %d htt %d.%d\n", - ar->hw_params.name, ar->target_version, - ar->hw->wiphy->fw_version, ar->fw_api, + ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", + ar->hw_params.name, + ar->target_version, + ar->chip_id, + ar->hw->wiphy->fw_version, + ar->fw_api, ar->htt.target_version_major, ar->htt.target_version_minor); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 0e71979d837cf9..2c1dfd71914688 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -119,6 +119,7 @@ struct ath10k_peer_stat { u8 peer_macaddr[ETH_ALEN]; u32 peer_rssi; u32 peer_tx_rate; + u32 peer_rx_rate; /* 10x only */ }; struct ath10k_target_stats { @@ -130,6 +131,12 @@ struct ath10k_target_stats { u32 cycle_count; u32 phy_err_count; u32 chan_tx_power; + u32 ack_rx_bad; + u32 rts_bad; + u32 rts_good; + u32 fcs_bad; + u32 no_beacons; + u32 mib_int_count; /* PDEV TX stats */ s32 comp_queued; @@ -260,6 +267,8 @@ struct ath10k_vif { u8 fixed_rate; u8 fixed_nss; u8 force_sgi; + bool use_cts_prot; + int num_legacy_stations; }; struct ath10k_vif_iter { @@ -419,13 +428,18 @@ struct ath10k { struct cfg80211_chan_def chandef; int free_vdev_map; + bool promisc; + bool monitor; int monitor_vdev_id; - bool monitor_enabled; - bool monitor_present; + bool monitor_started; unsigned int filter_flags; unsigned long dev_flags; u32 dfs_block_radar_events; + /* protected by conf_mutex */ + bool radar_enabled; + int num_started_vdevs; + struct wmi_pdev_set_wmm_params_arg wmm_params; struct completion install_key_done; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 6debd281350aeb..1b7ff4ba122ce4 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -161,7 +161,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, u8 *tmp = ev->data; struct ath10k_target_stats *stats; int num_pdev_stats, num_vdev_stats, num_peer_stats; - struct wmi_pdev_stats *ps; + struct wmi_pdev_stats_10x *ps; int i; spin_lock_bh(&ar->data_lock); @@ -173,7 +173,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */ if (num_pdev_stats) { - ps = (struct wmi_pdev_stats *)tmp; + ps = (struct wmi_pdev_stats_10x *)tmp; stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf); stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count); @@ -228,7 +228,18 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop); stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs); - tmp += sizeof(struct wmi_pdev_stats); + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, + ar->fw_features)) { + stats->ack_rx_bad = __le32_to_cpu(ps->ack_rx_bad); + stats->rts_bad = __le32_to_cpu(ps->rts_bad); + stats->rts_good = __le32_to_cpu(ps->rts_good); + stats->fcs_bad = __le32_to_cpu(ps->fcs_bad); + stats->no_beacons = __le32_to_cpu(ps->no_beacons); + stats->mib_int_count = __le32_to_cpu(ps->mib_int_count); + tmp += sizeof(struct wmi_pdev_stats_10x); + } else { + tmp += sizeof(struct wmi_pdev_stats_old); + } } /* 0 or max vdevs */ @@ -243,22 +254,29 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, } if (num_peer_stats) { - struct wmi_peer_stats *peer_stats; + struct wmi_peer_stats_10x *peer_stats; struct ath10k_peer_stat *s; stats->peers = num_peer_stats; for (i = 0; i < num_peer_stats; i++) { - peer_stats = (struct wmi_peer_stats *)tmp; + peer_stats = (struct wmi_peer_stats_10x *)tmp; s = &stats->peer_stat[i]; - WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr, - s->peer_macaddr); + memcpy(s->peer_macaddr, &peer_stats->peer_macaddr.addr, + ETH_ALEN); s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi); s->peer_tx_rate = __le32_to_cpu(peer_stats->peer_tx_rate); - - tmp += sizeof(struct wmi_peer_stats); + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, + ar->fw_features)) { + s->peer_rx_rate = + __le32_to_cpu(peer_stats->peer_rx_rate); + tmp += sizeof(struct wmi_peer_stats_10x); + + } else { + tmp += sizeof(struct wmi_peer_stats_old); + } } } @@ -272,7 +290,7 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, struct ath10k *ar = file->private_data; struct ath10k_target_stats *fw_stats; char *buf = NULL; - unsigned int len = 0, buf_len = 2500; + unsigned int len = 0, buf_len = 8000; ssize_t ret_cnt = 0; long left; int i; @@ -320,6 +338,16 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, "Cycle count", fw_stats->cycle_count); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", "PHY error count", fw_stats->phy_err_count); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "RTS bad count", fw_stats->rts_bad); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "RTS good count", fw_stats->rts_good); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "FCS bad count", fw_stats->fcs_bad); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "No beacon count", fw_stats->no_beacons); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "MIB int count", fw_stats->mib_int_count); len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "%30s\n", @@ -411,8 +439,8 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, "MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs); len += scnprintf(buf + len, buf_len - len, "\n"); - len += scnprintf(buf + len, buf_len - len, "%30s\n", - "ath10k PEER stats"); + len += scnprintf(buf + len, buf_len - len, "%30s (%d)\n", + "ath10k PEER stats", fw_stats->peers); len += scnprintf(buf + len, buf_len - len, "%30s\n\n", "================="); @@ -425,6 +453,9 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, len += scnprintf(buf + len, buf_len - len, "%30s %u\n", "Peer TX rate", fw_stats->peer_stat[i].peer_tx_rate); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "Peer RX rate", + fw_stats->peer_stat[i].peer_rx_rate); len += scnprintf(buf + len, buf_len - len, "\n"); } spin_unlock_bh(&ar->data_lock); @@ -451,27 +482,37 @@ static ssize_t ath10k_read_simulate_fw_crash(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - const char buf[] = "To simulate firmware crash write the keyword" - " `crash` to this file.\nThis will force firmware" - " to report a crash to the host system.\n"; + const char buf[] = "To simulate firmware crash write one of the" + " keywords to this file:\n `soft` - this will send" + " WMI_FORCE_FW_HANG_ASSERT to firmware if FW" + " supports that command.\n `hard` - this will send" + " to firmware command with illegal parameters" + " causing firmware crash.\n"; + return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); } +/* Simulate firmware crash: + * 'soft': Call wmi command causing firmware hang. This firmware hang is + * recoverable by warm firmware reset. + * 'hard': Force firmware crash by setting any vdev parameter for not allowed + * vdev id. This is hard firmware crash because it is recoverable only by cold + * firmware reset. + */ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; - char buf[32] = {}; + char buf[32]; int ret; mutex_lock(&ar->conf_mutex); simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); - if (strcmp(buf, "crash") && strcmp(buf, "crash\n")) { - ret = -EINVAL; - goto exit; - } + + /* make sure that buf is null terminated */ + buf[sizeof(buf) - 1] = 0; if (ar->state != ATH10K_STATE_ON && ar->state != ATH10K_STATE_RESTARTED) { @@ -479,14 +520,30 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, goto exit; } - ath10k_info("simulating firmware crash\n"); + /* drop the possible '\n' from the end */ + if (buf[count - 1] == '\n') { + buf[count - 1] = 0; + count--; + } - ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); - if (ret) - ath10k_warn("failed to force fw hang (%d)\n", ret); + if (!strcmp(buf, "soft")) { + ath10k_info("simulating soft firmware crash\n"); + ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); + } else if (!strcmp(buf, "hard")) { + ath10k_info("simulating hard firmware crash\n"); + ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1, + ar->wmi.vdev_param->rts_threshold, 0); + } else { + ret = -EINVAL; + goto exit; + } + + if (ret) { + ath10k_warn("failed to simulate firmware crash: %d\n", ret); + goto exit; + } - if (ret == 0) - ret = count; + ret = count; exit: mutex_unlock(&ar->conf_mutex); diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 7f1bccd3597f1b..5b58dbb174161a 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -157,6 +157,9 @@ int ath10k_htc_send(struct ath10k_htc *htc, goto err_pull; } ep->tx_credits -= credits; + ath10k_dbg(ATH10K_DBG_HTC, + "htc ep %d consumed %d credits (total %d)\n", + eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); } @@ -185,6 +188,9 @@ int ath10k_htc_send(struct ath10k_htc *htc, if (ep->tx_credit_flow_enabled) { spin_lock_bh(&htc->tx_lock); ep->tx_credits += credits; + ath10k_dbg(ATH10K_DBG_HTC, + "htc ep %d reverted %d credits back (total %d)\n", + eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); if (ep->ep_ops.ep_tx_credits) @@ -234,12 +240,12 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc, if (report->eid >= ATH10K_HTC_EP_COUNT) break; - ath10k_dbg(ATH10K_DBG_HTC, "ep %d got %d credits\n", - report->eid, report->credits); - ep = &htc->endpoint[report->eid]; ep->tx_credits += report->credits; + ath10k_dbg(ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n", + report->eid, report->credits, ep->tx_credits); + if (ep->ep_ops.ep_tx_credits) { spin_unlock_bh(&htc->tx_lock); ep->ep_ops.ep_tx_credits(htc->ar); diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 654867fc1ae73b..645a563e3fb967 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "htc.h" #include "rx_desc.h" @@ -1172,23 +1173,6 @@ struct htt_peer_unmap_event { u16 peer_id; }; -struct htt_rx_info { - struct sk_buff *skb; - enum htt_rx_mpdu_status status; - enum htt_rx_mpdu_encrypt_type encrypt_type; - s8 signal; - struct { - u8 info0; - u32 info1; - u32 info2; - } rate; - - u32 tsf; - bool fcs_err; - bool amsdu_more; - bool mic_err; -}; - struct ath10k_htt_txbuf { struct htt_data_tx_desc_frag frags[2]; struct ath10k_htc_hdr htc_hdr; @@ -1289,6 +1273,9 @@ struct ath10k_htt { struct tasklet_struct txrx_compl_task; struct sk_buff_head tx_compl_q; struct sk_buff_head rx_compl_q; + + /* rx_status template */ + struct ieee80211_rx_status rx_status; }; #define RX_HTT_HDR_STATUS_LEN 64 diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index cdcbe2de95f97d..f85a3cf6da3103 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -297,6 +297,7 @@ static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb) } } +/* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, u8 **fw_desc, int *fw_desc_len, struct sk_buff **head_msdu, @@ -310,7 +311,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, if (htt->rx_confused) { ath10k_warn("htt is confused. refusing rx\n"); - return 0; + return -1; } msdu = *head_msdu = ath10k_htt_rx_netbuf_pop(htt); @@ -442,6 +443,9 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, } *tail_msdu = msdu; + if (*head_msdu == NULL) + msdu_chaining = -1; + /* * Don't refill the ring yet. * @@ -636,6 +640,190 @@ struct amsdu_subframe_hdr { __be16 len; } __packed; +static const u8 rx_legacy_rate_idx[] = { + 3, /* 0x00 - 11Mbps */ + 2, /* 0x01 - 5.5Mbps */ + 1, /* 0x02 - 2Mbps */ + 0, /* 0x03 - 1Mbps */ + 3, /* 0x04 - 11Mbps */ + 2, /* 0x05 - 5.5Mbps */ + 1, /* 0x06 - 2Mbps */ + 0, /* 0x07 - 1Mbps */ + 10, /* 0x08 - 48Mbps */ + 8, /* 0x09 - 24Mbps */ + 6, /* 0x0A - 12Mbps */ + 4, /* 0x0B - 6Mbps */ + 11, /* 0x0C - 54Mbps */ + 9, /* 0x0D - 36Mbps */ + 7, /* 0x0E - 18Mbps */ + 5, /* 0x0F - 9Mbps */ +}; + +static void ath10k_htt_rx_h_rates(struct ath10k *ar, + enum ieee80211_band band, + u8 info0, u32 info1, u32 info2, + struct ieee80211_rx_status *status) +{ + u8 cck, rate, rate_idx, bw, sgi, mcs, nss; + u8 preamble = 0; + + /* Check if valid fields */ + if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID)) + return; + + preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE); + + switch (preamble) { + case HTT_RX_LEGACY: + cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK; + rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE); + rate_idx = 0; + + if (rate < 0x08 || rate > 0x0F) + break; + + switch (band) { + case IEEE80211_BAND_2GHZ: + if (cck) + rate &= ~BIT(3); + rate_idx = rx_legacy_rate_idx[rate]; + break; + case IEEE80211_BAND_5GHZ: + rate_idx = rx_legacy_rate_idx[rate]; + /* We are using same rate table registering + HW - ath10k_rates[]. In case of 5GHz skip + CCK rates, so -4 here */ + rate_idx -= 4; + break; + default: + break; + } + + status->rate_idx = rate_idx; + break; + case HTT_RX_HT: + case HTT_RX_HT_WITH_TXBF: + /* HT-SIG - Table 20-11 in info1 and info2 */ + mcs = info1 & 0x1F; + nss = mcs >> 3; + bw = (info1 >> 7) & 1; + sgi = (info2 >> 7) & 1; + + status->rate_idx = mcs; + status->flag |= RX_FLAG_HT; + if (sgi) + status->flag |= RX_FLAG_SHORT_GI; + if (bw) + status->flag |= RX_FLAG_40MHZ; + break; + case HTT_RX_VHT: + case HTT_RX_VHT_WITH_TXBF: + /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2 + TODO check this */ + mcs = (info2 >> 4) & 0x0F; + nss = ((info1 >> 10) & 0x07) + 1; + bw = info1 & 3; + sgi = info2 & 1; + + status->rate_idx = mcs; + status->vht_nss = nss; + + if (sgi) + status->flag |= RX_FLAG_SHORT_GI; + + switch (bw) { + /* 20MHZ */ + case 0: + break; + /* 40MHZ */ + case 1: + status->flag |= RX_FLAG_40MHZ; + break; + /* 80MHZ */ + case 2: + status->vht_flag |= RX_VHT_FLAG_80MHZ; + } + + status->flag |= RX_FLAG_VHT; + break; + default: + break; + } +} + +static void ath10k_htt_rx_h_protected(struct ath10k_htt *htt, + struct ieee80211_rx_status *rx_status, + struct sk_buff *skb, + enum htt_rx_mpdu_encrypt_type enctype) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + + if (enctype == HTT_RX_MPDU_ENCRYPT_NONE) { + rx_status->flag &= ~(RX_FLAG_DECRYPTED | + RX_FLAG_IV_STRIPPED | + RX_FLAG_MMIC_STRIPPED); + return; + } + + rx_status->flag |= RX_FLAG_DECRYPTED | + RX_FLAG_IV_STRIPPED | + RX_FLAG_MMIC_STRIPPED; + hdr->frame_control = __cpu_to_le16(__le16_to_cpu(hdr->frame_control) & + ~IEEE80211_FCTL_PROTECTED); +} + +static bool ath10k_htt_rx_h_channel(struct ath10k *ar, + struct ieee80211_rx_status *status) +{ + struct ieee80211_channel *ch; + + spin_lock_bh(&ar->data_lock); + ch = ar->scan_channel; + if (!ch) + ch = ar->rx_channel; + spin_unlock_bh(&ar->data_lock); + + if (!ch) + return false; + + status->band = ch->band; + status->freq = ch->center_freq; + + return true; +} + +static void ath10k_process_rx(struct ath10k *ar, + struct ieee80211_rx_status *rx_status, + struct sk_buff *skb) +{ + struct ieee80211_rx_status *status; + + status = IEEE80211_SKB_RXCB(skb); + *status = *rx_status; + + ath10k_dbg(ATH10K_DBG_DATA, + "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %imic-err %i\n", + skb, + skb->len, + status->flag == 0 ? "legacy" : "", + status->flag & RX_FLAG_HT ? "ht" : "", + status->flag & RX_FLAG_VHT ? "vht" : "", + status->flag & RX_FLAG_40MHZ ? "40" : "", + status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "", + status->flag & RX_FLAG_SHORT_GI ? "sgi " : "", + status->rate_idx, + status->vht_nss, + status->freq, + status->band, status->flag, + !!(status->flag & RX_FLAG_FAILED_FCS_CRC), + !!(status->flag & RX_FLAG_MMIC_ERROR)); + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", + skb->data, skb->len); + + ieee80211_rx(ar->hw, skb); +} + static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr) { /* nwifi header is padded to 4 bytes. this fixes 4addr rx */ @@ -643,11 +831,12 @@ static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr) } static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, - struct htt_rx_info *info) + struct ieee80211_rx_status *rx_status, + struct sk_buff *skb_in) { struct htt_rx_desc *rxd; + struct sk_buff *skb = skb_in; struct sk_buff *first; - struct sk_buff *skb = info->skb; enum rx_msdu_decap_format fmt; enum htt_rx_mpdu_encrypt_type enctype; struct ieee80211_hdr *hdr; @@ -728,24 +917,27 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, break; } - info->skb = skb; - info->encrypt_type = enctype; + skb_in = skb; + ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype); skb = skb->next; - info->skb->next = NULL; + skb_in->next = NULL; if (skb) - info->amsdu_more = true; + rx_status->flag |= RX_FLAG_AMSDU_MORE; + else + rx_status->flag &= ~RX_FLAG_AMSDU_MORE; - ath10k_process_rx(htt->ar, info); + ath10k_process_rx(htt->ar, rx_status, skb_in); } /* FIXME: It might be nice to re-assemble the A-MSDU when there's a * monitor interface active for sniffing purposes. */ } -static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info) +static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, + struct ieee80211_rx_status *rx_status, + struct sk_buff *skb) { - struct sk_buff *skb = info->skb; struct htt_rx_desc *rxd; struct ieee80211_hdr *hdr; enum rx_msdu_decap_format fmt; @@ -808,66 +1000,9 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info) break; } - info->skb = skb; - info->encrypt_type = enctype; - - ath10k_process_rx(htt->ar, info); -} - -static bool ath10k_htt_rx_has_decrypt_err(struct sk_buff *skb) -{ - struct htt_rx_desc *rxd; - u32 flags; - - rxd = (void *)skb->data - sizeof(*rxd); - flags = __le32_to_cpu(rxd->attention.flags); - - if (flags & RX_ATTENTION_FLAGS_DECRYPT_ERR) - return true; - - return false; -} - -static bool ath10k_htt_rx_has_fcs_err(struct sk_buff *skb) -{ - struct htt_rx_desc *rxd; - u32 flags; - - rxd = (void *)skb->data - sizeof(*rxd); - flags = __le32_to_cpu(rxd->attention.flags); - - if (flags & RX_ATTENTION_FLAGS_FCS_ERR) - return true; - - return false; -} - -static bool ath10k_htt_rx_has_mic_err(struct sk_buff *skb) -{ - struct htt_rx_desc *rxd; - u32 flags; - - rxd = (void *)skb->data - sizeof(*rxd); - flags = __le32_to_cpu(rxd->attention.flags); - - if (flags & RX_ATTENTION_FLAGS_TKIP_MIC_ERR) - return true; - - return false; -} - -static bool ath10k_htt_rx_is_mgmt(struct sk_buff *skb) -{ - struct htt_rx_desc *rxd; - u32 flags; - - rxd = (void *)skb->data - sizeof(*rxd); - flags = __le32_to_cpu(rxd->attention.flags); - - if (flags & RX_ATTENTION_FLAGS_MGMT_TYPE) - return true; + ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype); - return false; + ath10k_process_rx(htt->ar, rx_status, skb); } static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) @@ -952,21 +1087,73 @@ static int ath10k_unchain_msdu(struct sk_buff *msdu_head) return 0; } +static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt, + struct sk_buff *head, + enum htt_rx_mpdu_status status, + bool channel_set, + u32 attention) +{ + if (head->len == 0) { + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx dropping due to zero-len\n"); + return false; + } + + if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) { + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx dropping due to decrypt-err\n"); + return false; + } + + if (!channel_set) { + ath10k_warn("no channel configured; ignoring frame!\n"); + return false; + } + + /* Skip mgmt frames while we handle this in WMI */ + if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL || + attention & RX_ATTENTION_FLAGS_MGMT_TYPE) { + ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); + return false; + } + + if (status != HTT_RX_IND_MPDU_STATUS_OK && + status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && + status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER && + !htt->ar->monitor_started) { + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx ignoring frame w/ status %d\n", + status); + return false; + } + + if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx CAC running\n"); + return false; + } + + return true; +} + static void ath10k_htt_rx_handler(struct ath10k_htt *htt, struct htt_rx_indication *rx) { - struct htt_rx_info info; + struct ieee80211_rx_status *rx_status = &htt->rx_status; struct htt_rx_indication_mpdu_range *mpdu_ranges; + struct htt_rx_desc *rxd; + enum htt_rx_mpdu_status status; struct ieee80211_hdr *hdr; int num_mpdu_ranges; + u32 attention; int fw_desc_len; u8 *fw_desc; + bool channel_set; int i, j; + int ret; lockdep_assert_held(&htt->rx_ring.lock); - memset(&info, 0, sizeof(info)); - fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes); fw_desc = (u8 *)&rx->fw_desc; @@ -974,106 +1161,90 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES); mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx); + /* Fill this once, while this is per-ppdu */ + if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_START_VALID) { + memset(rx_status, 0, sizeof(*rx_status)); + rx_status->signal = ATH10K_DEFAULT_NOISE_FLOOR + + rx->ppdu.combined_rssi; + } + + if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_END_VALID) { + /* TSF available only in 32-bit */ + rx_status->mactime = __le32_to_cpu(rx->ppdu.tsf) & 0xffffffff; + rx_status->flag |= RX_FLAG_MACTIME_END; + } + + channel_set = ath10k_htt_rx_h_channel(htt->ar, rx_status); + + if (channel_set) { + ath10k_htt_rx_h_rates(htt->ar, rx_status->band, + rx->ppdu.info0, + __le32_to_cpu(rx->ppdu.info1), + __le32_to_cpu(rx->ppdu.info2), + rx_status); + } + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ", rx, sizeof(*rx) + (sizeof(struct htt_rx_indication_mpdu_range) * num_mpdu_ranges)); for (i = 0; i < num_mpdu_ranges; i++) { - info.status = mpdu_ranges[i].mpdu_range_status; + status = mpdu_ranges[i].mpdu_range_status; for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) { struct sk_buff *msdu_head, *msdu_tail; - enum htt_rx_mpdu_status status; - int msdu_chaining; msdu_head = NULL; msdu_tail = NULL; - msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, - &fw_desc, - &fw_desc_len, - &msdu_head, - &msdu_tail); - - if (!msdu_head) { - ath10k_warn("htt rx no data!\n"); - continue; - } - - if (msdu_head->len == 0) { - ath10k_dbg(ATH10K_DBG_HTT, - "htt rx dropping due to zero-len\n"); - ath10k_htt_rx_free_msdu_chain(msdu_head); - continue; - } - - if (ath10k_htt_rx_has_decrypt_err(msdu_head)) { - ath10k_dbg(ATH10K_DBG_HTT, - "htt rx dropping due to decrypt-err\n"); + ret = ath10k_htt_rx_amsdu_pop(htt, + &fw_desc, + &fw_desc_len, + &msdu_head, + &msdu_tail); + + if (ret < 0) { + ath10k_warn("failed to pop amsdu from htt rx ring %d\n", + ret); ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } - status = info.status; - - /* Skip mgmt frames while we handle this in WMI */ - if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL || - ath10k_htt_rx_is_mgmt(msdu_head)) { - ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); - ath10k_htt_rx_free_msdu_chain(msdu_head); - continue; - } + rxd = container_of((void *)msdu_head->data, + struct htt_rx_desc, + msdu_payload); + attention = __le32_to_cpu(rxd->attention.flags); - if (status != HTT_RX_IND_MPDU_STATUS_OK && - status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && - status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER && - !htt->ar->monitor_enabled) { - ath10k_dbg(ATH10K_DBG_HTT, - "htt rx ignoring frame w/ status %d\n", - status); + if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head, + status, + channel_set, + attention)) { ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } - if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { - ath10k_dbg(ATH10K_DBG_HTT, - "htt rx CAC running\n"); + if (ret > 0 && + ath10k_unchain_msdu(msdu_head) < 0) { ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } - if (msdu_chaining && - (ath10k_unchain_msdu(msdu_head) < 0)) { - ath10k_htt_rx_free_msdu_chain(msdu_head); - continue; - } - - info.skb = msdu_head; - info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head); - info.mic_err = ath10k_htt_rx_has_mic_err(msdu_head); - - if (info.fcs_err) - ath10k_dbg(ATH10K_DBG_HTT, - "htt rx has FCS err\n"); - - if (info.mic_err) - ath10k_dbg(ATH10K_DBG_HTT, - "htt rx has MIC err\n"); - - info.signal = ATH10K_DEFAULT_NOISE_FLOOR; - info.signal += rx->ppdu.combined_rssi; + if (attention & RX_ATTENTION_FLAGS_FCS_ERR) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + else + rx_status->flag &= ~RX_FLAG_FAILED_FCS_CRC; - info.rate.info0 = rx->ppdu.info0; - info.rate.info1 = __le32_to_cpu(rx->ppdu.info1); - info.rate.info2 = __le32_to_cpu(rx->ppdu.info2); - info.tsf = __le32_to_cpu(rx->ppdu.tsf); + if (attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR) + rx_status->flag |= RX_FLAG_MMIC_ERROR; + else + rx_status->flag &= ~RX_FLAG_MMIC_ERROR; hdr = ath10k_htt_rx_skb_get_hdr(msdu_head); if (ath10k_htt_rx_hdr_is_amsdu(hdr)) - ath10k_htt_rx_amsdu(htt, &info); + ath10k_htt_rx_amsdu(htt, rx_status, msdu_head); else - ath10k_htt_rx_msdu(htt, &info); + ath10k_htt_rx_msdu(htt, rx_status, msdu_head); } } @@ -1084,11 +1255,12 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, struct htt_rx_fragment_indication *frag) { struct sk_buff *msdu_head, *msdu_tail; + enum htt_rx_mpdu_encrypt_type enctype; struct htt_rx_desc *rxd; enum rx_msdu_decap_format fmt; - struct htt_rx_info info = {}; + struct ieee80211_rx_status *rx_status = &htt->rx_status; struct ieee80211_hdr *hdr; - int msdu_chaining; + int ret; bool tkip_mic_err; bool decrypt_err; u8 *fw_desc; @@ -1102,19 +1274,15 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, msdu_tail = NULL; spin_lock_bh(&htt->rx_ring.lock); - msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, - &msdu_head, &msdu_tail); + ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, + &msdu_head, &msdu_tail); spin_unlock_bh(&htt->rx_ring.lock); ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); - if (!msdu_head) { - ath10k_warn("htt rx frag no data\n"); - return; - } - - if (msdu_chaining || msdu_head != msdu_tail) { - ath10k_warn("aggregation with fragmentation?!\n"); + if (ret) { + ath10k_warn("failed to pop amsdu from httr rx ring for fragmented rx %d\n", + ret); ath10k_htt_rx_free_msdu_chain(msdu_head); return; } @@ -1136,57 +1304,54 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, goto end; } - info.skb = msdu_head; - info.status = HTT_RX_IND_MPDU_STATUS_OK; - info.encrypt_type = MS(__le32_to_cpu(rxd->mpdu_start.info0), - RX_MPDU_START_INFO0_ENCRYPT_TYPE); - info.skb->ip_summed = ath10k_htt_rx_get_csum_state(info.skb); + enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), + RX_MPDU_START_INFO0_ENCRYPT_TYPE); + ath10k_htt_rx_h_protected(htt, rx_status, msdu_head, enctype); + msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head); - if (tkip_mic_err) { + if (tkip_mic_err) ath10k_warn("tkip mic error\n"); - info.status = HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR; - } if (decrypt_err) { ath10k_warn("decryption err in fragmented rx\n"); - dev_kfree_skb_any(info.skb); + dev_kfree_skb_any(msdu_head); goto end; } - if (info.encrypt_type != HTT_RX_MPDU_ENCRYPT_NONE) { + if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) { hdrlen = ieee80211_hdrlen(hdr->frame_control); - paramlen = ath10k_htt_rx_crypto_param_len(info.encrypt_type); + paramlen = ath10k_htt_rx_crypto_param_len(enctype); /* It is more efficient to move the header than the payload */ - memmove((void *)info.skb->data + paramlen, - (void *)info.skb->data, + memmove((void *)msdu_head->data + paramlen, + (void *)msdu_head->data, hdrlen); - skb_pull(info.skb, paramlen); - hdr = (struct ieee80211_hdr *)info.skb->data; + skb_pull(msdu_head, paramlen); + hdr = (struct ieee80211_hdr *)msdu_head->data; } /* remove trailing FCS */ trim = 4; /* remove crypto trailer */ - trim += ath10k_htt_rx_crypto_tail_len(info.encrypt_type); + trim += ath10k_htt_rx_crypto_tail_len(enctype); /* last fragment of TKIP frags has MIC */ if (!ieee80211_has_morefrags(hdr->frame_control) && - info.encrypt_type == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) + enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) trim += 8; - if (trim > info.skb->len) { + if (trim > msdu_head->len) { ath10k_warn("htt rx fragment: trailer longer than the frame itself? drop\n"); - dev_kfree_skb_any(info.skb); + dev_kfree_skb_any(msdu_head); goto end; } - skb_trim(info.skb, info.skb->len - trim); + skb_trim(msdu_head, msdu_head->len - trim); ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ", - info.skb->data, info.skb->len); - ath10k_process_rx(htt->ar, &info); + msdu_head->data, msdu_head->len); + ath10k_process_rx(htt->ar, rx_status, msdu_head); end: if (fw_desc_len > 0) { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 35fc44e281f579..007e855f4ba99f 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -28,6 +28,7 @@ #define QCA988X_HW_2_0_CHIP_ID_REV 0x2 #define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0" #define QCA988X_HW_2_0_FW_FILE "firmware.bin" +#define QCA988X_HW_2_0_FW_2_FILE "firmware-2.bin" #define QCA988X_HW_2_0_OTP_FILE "otp.bin" #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234 diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 511a2f81e7afc1..0ac5437492fd5c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -165,7 +165,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif, first_errno = ret; if (ret) - ath10k_warn("could not remove peer wep key %d (%d)\n", + ath10k_warn("failed to remove peer wep key %d: %d\n", i, ret); peer->keys[i] = NULL; @@ -213,7 +213,8 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, first_errno = ret; if (ret) - ath10k_warn("could not remove key for %pM\n", addr); + ath10k_warn("failed to remove key for %pM: %d\n", + addr, ret); } return first_errno; @@ -323,14 +324,14 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) ret = ath10k_wmi_peer_create(ar, vdev_id, addr); if (ret) { - ath10k_warn("Failed to create wmi peer %pM on vdev %i: %i\n", + ath10k_warn("failed to create wmi peer %pM on vdev %i: %i\n", addr, vdev_id, ret); return ret; } ret = ath10k_wait_for_peer_created(ar, vdev_id, addr); if (ret) { - ath10k_warn("Failed to wait for created wmi peer %pM on vdev %i: %i\n", + ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n", addr, vdev_id, ret); return ret; } @@ -351,7 +352,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) ret = ath10k_wmi_pdev_set_param(ar, param, ATH10K_KICKOUT_THRESHOLD); if (ret) { - ath10k_warn("Failed to set kickout threshold on vdev %i: %d\n", + ath10k_warn("failed to set kickout threshold on vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -360,7 +361,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, ATH10K_KEEPALIVE_MIN_IDLE); if (ret) { - ath10k_warn("Failed to set keepalive minimum idle time on vdev %i : %d\n", + ath10k_warn("failed to set keepalive minimum idle time on vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -369,7 +370,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, ATH10K_KEEPALIVE_MAX_IDLE); if (ret) { - ath10k_warn("Failed to set keepalive maximum idle time on vdev %i: %d\n", + ath10k_warn("failed to set keepalive maximum idle time on vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -378,7 +379,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, ATH10K_KEEPALIVE_MAX_UNRESPONSIVE); if (ret) { - ath10k_warn("Failed to set keepalive maximum unresponsive time on vdev %i: %d\n", + ath10k_warn("failed to set keepalive maximum unresponsive time on vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -488,92 +489,20 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) return 0; } -static int ath10k_vdev_start(struct ath10k_vif *arvif) +static bool ath10k_monitor_is_enabled(struct ath10k *ar) { - struct ath10k *ar = arvif->ar; - struct cfg80211_chan_def *chandef = &ar->chandef; - struct wmi_vdev_start_request_arg arg = {}; - int ret = 0; - lockdep_assert_held(&ar->conf_mutex); - reinit_completion(&ar->vdev_setup_done); - - arg.vdev_id = arvif->vdev_id; - arg.dtim_period = arvif->dtim_period; - arg.bcn_intval = arvif->beacon_interval; - - arg.channel.freq = chandef->chan->center_freq; - arg.channel.band_center_freq1 = chandef->center_freq1; - arg.channel.mode = chan_to_phymode(chandef); - - arg.channel.min_power = 0; - arg.channel.max_power = chandef->chan->max_power * 2; - arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; - arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2; - - if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { - arg.ssid = arvif->u.ap.ssid; - arg.ssid_len = arvif->u.ap.ssid_len; - arg.hidden_ssid = arvif->u.ap.hidden_ssid; - - /* For now allow DFS for AP mode */ - arg.channel.chan_radar = - !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); - } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { - arg.ssid = arvif->vif->bss_conf.ssid; - arg.ssid_len = arvif->vif->bss_conf.ssid_len; - } - ath10k_dbg(ATH10K_DBG_MAC, - "mac vdev %d start center_freq %d phymode %s\n", - arg.vdev_id, arg.channel.freq, - ath10k_wmi_phymode_str(arg.channel.mode)); - - ret = ath10k_wmi_vdev_start(ar, &arg); - if (ret) { - ath10k_warn("WMI vdev %i start failed: ret %d\n", - arg.vdev_id, ret); - return ret; - } - - ret = ath10k_vdev_setup_sync(ar); - if (ret) { - ath10k_warn("vdev %i setup failed %d\n", - arg.vdev_id, ret); - return ret; - } - - return ret; -} - -static int ath10k_vdev_stop(struct ath10k_vif *arvif) -{ - struct ath10k *ar = arvif->ar; - int ret; + "mac monitor refs: promisc %d monitor %d cac %d\n", + ar->promisc, ar->monitor, + test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)); - lockdep_assert_held(&ar->conf_mutex); - - reinit_completion(&ar->vdev_setup_done); - - ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); - if (ret) { - ath10k_warn("WMI vdev %i stop failed: ret %d\n", - arvif->vdev_id, ret); - return ret; - } - - ret = ath10k_vdev_setup_sync(ar); - if (ret) { - ath10k_warn("vdev %i setup sync failed %d\n", - arvif->vdev_id, ret); - return ret; - } - - return ret; + return ar->promisc || ar->monitor || + test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); } -static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) +static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) { struct cfg80211_chan_def *chandef = &ar->chandef; struct ieee80211_channel *channel = chandef->chan; @@ -582,11 +511,6 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) lockdep_assert_held(&ar->conf_mutex); - if (!ar->monitor_present) { - ath10k_warn("mac montor stop -- monitor is not present\n"); - return -EINVAL; - } - arg.vdev_id = vdev_id; arg.channel.freq = channel->center_freq; arg.channel.band_center_freq1 = chandef->center_freq1; @@ -604,88 +528,75 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) ret = ath10k_wmi_vdev_start(ar, &arg); if (ret) { - ath10k_warn("Monitor vdev %i start failed: ret %d\n", + ath10k_warn("failed to request monitor vdev %i start: %d\n", vdev_id, ret); return ret; } ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn("Monitor vdev %i setup failed %d\n", + ath10k_warn("failed to synchronize setup for monitor vdev %i: %d\n", vdev_id, ret); return ret; } ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); if (ret) { - ath10k_warn("Monitor vdev %i up failed: %d\n", + ath10k_warn("failed to put up monitor vdev %i: %d\n", vdev_id, ret); goto vdev_stop; } ar->monitor_vdev_id = vdev_id; - ar->monitor_enabled = true; + ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i started\n", + ar->monitor_vdev_id); return 0; vdev_stop: ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn("Monitor vdev %i stop failed: %d\n", + ath10k_warn("failed to stop monitor vdev %i after start failure: %d\n", ar->monitor_vdev_id, ret); return ret; } -static int ath10k_monitor_stop(struct ath10k *ar) +static int ath10k_monitor_vdev_stop(struct ath10k *ar) { int ret = 0; lockdep_assert_held(&ar->conf_mutex); - if (!ar->monitor_present) { - ath10k_warn("mac montor stop -- monitor is not present\n"); - return -EINVAL; - } - - if (!ar->monitor_enabled) { - ath10k_warn("mac montor stop -- monitor is not enabled\n"); - return -EINVAL; - } - ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn("Monitor vdev %i down failed: %d\n", + ath10k_warn("failed to put down monitor vdev %i: %d\n", ar->monitor_vdev_id, ret); ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn("Monitor vdev %i stop failed: %d\n", + ath10k_warn("failed to to request monitor vdev %i stop: %d\n", ar->monitor_vdev_id, ret); ret = ath10k_vdev_setup_sync(ar); if (ret) - ath10k_warn("Monitor_down sync failed, vdev %i: %d\n", + ath10k_warn("failed to synchronise monitor vdev %i: %d\n", ar->monitor_vdev_id, ret); - ar->monitor_enabled = false; + ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n", + ar->monitor_vdev_id); return ret; } -static int ath10k_monitor_create(struct ath10k *ar) +static int ath10k_monitor_vdev_create(struct ath10k *ar) { int bit, ret = 0; lockdep_assert_held(&ar->conf_mutex); - if (ar->monitor_present) { - ath10k_warn("Monitor mode already enabled\n"); - return 0; - } - bit = ffs(ar->free_vdev_map); if (bit == 0) { - ath10k_warn("No free VDEV slots\n"); + ath10k_warn("failed to find free vdev id for monitor vdev\n"); return -ENOMEM; } @@ -696,7 +607,7 @@ static int ath10k_monitor_create(struct ath10k *ar) WMI_VDEV_TYPE_MONITOR, 0, ar->mac_addr); if (ret) { - ath10k_warn("WMI vdev %i monitor create failed: ret %d\n", + ath10k_warn("failed to request monitor vdev %i creation: %d\n", ar->monitor_vdev_id, ret); goto vdev_fail; } @@ -704,7 +615,6 @@ static int ath10k_monitor_create(struct ath10k *ar) ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n", ar->monitor_vdev_id); - ar->monitor_present = true; return 0; vdev_fail: @@ -715,48 +625,123 @@ static int ath10k_monitor_create(struct ath10k *ar) return ret; } -static int ath10k_monitor_destroy(struct ath10k *ar) +static int ath10k_monitor_vdev_delete(struct ath10k *ar) { int ret = 0; lockdep_assert_held(&ar->conf_mutex); - if (!ar->monitor_present) - return 0; - ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id); if (ret) { - ath10k_warn("WMI vdev %i monitor delete failed: %d\n", + ath10k_warn("failed to request wmi monitor vdev %i removal: %d\n", ar->monitor_vdev_id, ret); return ret; } ar->free_vdev_map |= 1 << (ar->monitor_vdev_id); - ar->monitor_present = false; ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n", ar->monitor_vdev_id); return ret; } -static int ath10k_start_cac(struct ath10k *ar) +static int ath10k_monitor_start(struct ath10k *ar) { int ret; lockdep_assert_held(&ar->conf_mutex); - set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + if (!ath10k_monitor_is_enabled(ar)) { + ath10k_warn("trying to start monitor with no references\n"); + return 0; + } + + if (ar->monitor_started) { + ath10k_dbg(ATH10K_DBG_MAC, "mac monitor already started\n"); + return 0; + } - ret = ath10k_monitor_create(ar); + ret = ath10k_monitor_vdev_create(ar); if (ret) { - clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + ath10k_warn("failed to create monitor vdev: %d\n", ret); return ret; } - ret = ath10k_monitor_start(ar, ar->monitor_vdev_id); + ret = ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id); if (ret) { + ath10k_warn("failed to start monitor vdev: %d\n", ret); + ath10k_monitor_vdev_delete(ar); + return ret; + } + + ar->monitor_started = true; + ath10k_dbg(ATH10K_DBG_MAC, "mac monitor started\n"); + + return 0; +} + +static void ath10k_monitor_stop(struct ath10k *ar) +{ + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + if (ath10k_monitor_is_enabled(ar)) { + ath10k_dbg(ATH10K_DBG_MAC, + "mac monitor will be stopped later\n"); + return; + } + + if (!ar->monitor_started) { + ath10k_dbg(ATH10K_DBG_MAC, + "mac monitor probably failed to start earlier\n"); + return; + } + + ret = ath10k_monitor_vdev_stop(ar); + if (ret) + ath10k_warn("failed to stop monitor vdev: %d\n", ret); + + ret = ath10k_monitor_vdev_delete(ar); + if (ret) + ath10k_warn("failed to delete monitor vdev: %d\n", ret); + + ar->monitor_started = false; + ath10k_dbg(ATH10K_DBG_MAC, "mac monitor stopped\n"); +} + +static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + u32 vdev_param, rts_cts = 0; + + lockdep_assert_held(&ar->conf_mutex); + + vdev_param = ar->wmi.vdev_param->enable_rtscts; + + if (arvif->use_cts_prot || arvif->num_legacy_stations > 0) + rts_cts |= SM(WMI_RTSCTS_ENABLED, WMI_RTSCTS_SET); + + if (arvif->num_legacy_stations > 0) + rts_cts |= SM(WMI_RTSCTS_ACROSS_SW_RETRIES, + WMI_RTSCTS_PROFILE); + + return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, + rts_cts); +} + +static int ath10k_start_cac(struct ath10k *ar) +{ + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + + ret = ath10k_monitor_start(ar); + if (ret) { + ath10k_warn("failed to start monitor (cac): %d\n", ret); clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); - ath10k_monitor_destroy(ar); return ret; } @@ -774,58 +759,26 @@ static int ath10k_stop_cac(struct ath10k *ar) if (!test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) return 0; - ath10k_monitor_stop(ar); - ath10k_monitor_destroy(ar); clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + ath10k_monitor_stop(ar); ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n"); return 0; } -static const char *ath10k_dfs_state(enum nl80211_dfs_state dfs_state) -{ - switch (dfs_state) { - case NL80211_DFS_USABLE: - return "USABLE"; - case NL80211_DFS_UNAVAILABLE: - return "UNAVAILABLE"; - case NL80211_DFS_AVAILABLE: - return "AVAILABLE"; - default: - WARN_ON(1); - return "bug"; - } -} - -static void ath10k_config_radar_detection(struct ath10k *ar) +static void ath10k_recalc_radar_detection(struct ath10k *ar) { - struct ieee80211_channel *chan = ar->hw->conf.chandef.chan; - bool radar = ar->hw->conf.radar_enabled; - bool chan_radar = !!(chan->flags & IEEE80211_CHAN_RADAR); - enum nl80211_dfs_state dfs_state = chan->dfs_state; int ret; lockdep_assert_held(&ar->conf_mutex); - ath10k_dbg(ATH10K_DBG_MAC, - "mac radar config update: chan %dMHz radar %d chan radar %d chan state %s\n", - chan->center_freq, radar, chan_radar, - ath10k_dfs_state(dfs_state)); - - /* - * It's safe to call it even if CAC is not started. - * This call here guarantees changing channel, etc. will stop CAC. - */ ath10k_stop_cac(ar); - if (!radar) - return; - - if (!chan_radar) + if (!ar->radar_enabled) return; - if (dfs_state != NL80211_DFS_USABLE) + if (ar->num_started_vdevs > 0) return; ret = ath10k_start_cac(ar); @@ -835,11 +788,106 @@ static void ath10k_config_radar_detection(struct ath10k *ar) * radiation is not allowed, make this channel DFS_UNAVAILABLE * by indicating that radar was detected. */ - ath10k_warn("failed to start CAC (%d)\n", ret); + ath10k_warn("failed to start CAC: %d\n", ret); ieee80211_radar_detected(ar->hw); } } +static int ath10k_vdev_start(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + struct cfg80211_chan_def *chandef = &ar->chandef; + struct wmi_vdev_start_request_arg arg = {}; + int ret = 0; + + lockdep_assert_held(&ar->conf_mutex); + + reinit_completion(&ar->vdev_setup_done); + + arg.vdev_id = arvif->vdev_id; + arg.dtim_period = arvif->dtim_period; + arg.bcn_intval = arvif->beacon_interval; + + arg.channel.freq = chandef->chan->center_freq; + arg.channel.band_center_freq1 = chandef->center_freq1; + arg.channel.mode = chan_to_phymode(chandef); + + arg.channel.min_power = 0; + arg.channel.max_power = chandef->chan->max_power * 2; + arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; + arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2; + + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { + arg.ssid = arvif->u.ap.ssid; + arg.ssid_len = arvif->u.ap.ssid_len; + arg.hidden_ssid = arvif->u.ap.hidden_ssid; + + /* For now allow DFS for AP mode */ + arg.channel.chan_radar = + !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); + } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { + arg.ssid = arvif->vif->bss_conf.ssid; + arg.ssid_len = arvif->vif->bss_conf.ssid_len; + } + + ath10k_dbg(ATH10K_DBG_MAC, + "mac vdev %d start center_freq %d phymode %s\n", + arg.vdev_id, arg.channel.freq, + ath10k_wmi_phymode_str(arg.channel.mode)); + + ret = ath10k_wmi_vdev_start(ar, &arg); + if (ret) { + ath10k_warn("failed to start WMI vdev %i: %d\n", + arg.vdev_id, ret); + return ret; + } + + ret = ath10k_vdev_setup_sync(ar); + if (ret) { + ath10k_warn("failed to synchronise setup for vdev %i: %d\n", + arg.vdev_id, ret); + return ret; + } + + ar->num_started_vdevs++; + ath10k_recalc_radar_detection(ar); + + return ret; +} + +static int ath10k_vdev_stop(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + reinit_completion(&ar->vdev_setup_done); + + ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); + if (ret) { + ath10k_warn("failed to stop WMI vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + ret = ath10k_vdev_setup_sync(ar); + if (ret) { + ath10k_warn("failed to syncronise setup for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + WARN_ON(ar->num_started_vdevs == 0); + + if (ar->num_started_vdevs != 0) { + ar->num_started_vdevs--; + ath10k_recalc_radar_detection(ar); + } + + return ret; +} + static void ath10k_control_beaconing(struct ath10k_vif *arvif, struct ieee80211_bss_conf *info) { @@ -880,7 +928,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { - ath10k_warn("Failed to bring up vdev %d: %i\n", + ath10k_warn("failed to bring up vdev %d: %i\n", arvif->vdev_id, ret); ath10k_vdev_stop(arvif); return; @@ -904,7 +952,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, if (!info->ibss_joined) { ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer); if (ret) - ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n", + ath10k_warn("failed to delete IBSS self peer %pM for vdev %d: %d\n", self_peer, arvif->vdev_id, ret); if (is_zero_ether_addr(arvif->bssid)) @@ -913,7 +961,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, arvif->bssid); if (ret) { - ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n", + ath10k_warn("failed to delete IBSS BSSID peer %pM for vdev %d: %d\n", arvif->bssid, arvif->vdev_id, ret); return; } @@ -925,7 +973,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer); if (ret) { - ath10k_warn("Failed to create IBSS self peer:%pM for VDEV:%d ret:%d\n", + ath10k_warn("failed to create IBSS self peer %pM for vdev %d: %d\n", self_peer, arvif->vdev_id, ret); return; } @@ -934,7 +982,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param, ATH10K_DEFAULT_ATIM); if (ret) - ath10k_warn("Failed to set IBSS ATIM for VDEV:%d ret:%d\n", + ath10k_warn("failed to set IBSS ATIM for vdev %d: %d\n", arvif->vdev_id, ret); } @@ -961,7 +1009,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, conf->dynamic_ps_timeout); if (ret) { - ath10k_warn("Failed to set inactivity time for vdev %d: %i\n", + ath10k_warn("failed to set inactivity time for vdev %d: %i\n", arvif->vdev_id, ret); return ret; } @@ -974,8 +1022,8 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode); if (ret) { - ath10k_warn("Failed to set PS Mode: %d for VDEV: %d\n", - psmode, arvif->vdev_id); + ath10k_warn("failed to set PS Mode %d for vdev %d: %d\n", + psmode, arvif->vdev_id, ret); return ret; } @@ -1429,7 +1477,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ap_sta = ieee80211_find_sta(vif, bss_conf->bssid); if (!ap_sta) { - ath10k_warn("Failed to find station entry for %pM, vdev %i\n", + ath10k_warn("failed to find station entry for bss %pM vdev %i\n", bss_conf->bssid, arvif->vdev_id); rcu_read_unlock(); return; @@ -1442,7 +1490,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta, bss_conf, &peer_arg); if (ret) { - ath10k_warn("Peer assoc prepare failed for %pM vdev %i\n: %d", + ath10k_warn("failed to prepare peer assoc for %pM vdev %i: %d\n", bss_conf->bssid, arvif->vdev_id, ret); rcu_read_unlock(); return; @@ -1452,7 +1500,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ret = ath10k_wmi_peer_assoc(ar, &peer_arg); if (ret) { - ath10k_warn("Peer assoc failed for %pM vdev %i\n: %d", + ath10k_warn("failed to run peer assoc for %pM vdev %i: %d\n", bss_conf->bssid, arvif->vdev_id, ret); return; } @@ -1473,7 +1521,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { - ath10k_warn("VDEV: %d up failed: ret %d\n", + ath10k_warn("failed to set vdev %d up: %d\n", arvif->vdev_id, ret); return; } @@ -1524,7 +1572,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, } static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, - struct ieee80211_sta *sta) + struct ieee80211_sta *sta, bool reassoc) { struct wmi_peer_assoc_complete_arg peer_arg; int ret = 0; @@ -1533,34 +1581,46 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg); if (ret) { - ath10k_warn("WMI peer assoc prepare failed for %pM vdev %i: %i\n", + ath10k_warn("failed to prepare WMI peer assoc for %pM vdev %i: %i\n", sta->addr, arvif->vdev_id, ret); return ret; } + peer_arg.peer_reassoc = reassoc; ret = ath10k_wmi_peer_assoc(ar, &peer_arg); if (ret) { - ath10k_warn("Peer assoc failed for STA %pM vdev %i: %d\n", + ath10k_warn("failed to run peer assoc for STA %pM vdev %i: %d\n", sta->addr, arvif->vdev_id, ret); return ret; } ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap); if (ret) { - ath10k_warn("failed to setup peer SMPS for vdev: %d\n", ret); + ath10k_warn("failed to setup peer SMPS for vdev %d: %d\n", + arvif->vdev_id, ret); return ret; } + if (!sta->wme) { + arvif->num_legacy_stations++; + ret = ath10k_recalc_rtscts_prot(arvif); + if (ret) { + ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", + arvif->vdev_id, ret); + return ret; + } + } + ret = ath10k_install_peer_wep_keys(arvif, sta->addr); if (ret) { - ath10k_warn("could not install peer wep keys for vdev %i: %d\n", + ath10k_warn("failed to install peer wep keys for vdev %i: %d\n", arvif->vdev_id, ret); return ret; } ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta); if (ret) { - ath10k_warn("could not set qos params for STA %pM for vdev %i: %d\n", + ath10k_warn("failed to set qos params for STA %pM for vdev %i: %d\n", sta->addr, arvif->vdev_id, ret); return ret; } @@ -1575,9 +1635,19 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif, lockdep_assert_held(&ar->conf_mutex); + if (!sta->wme) { + arvif->num_legacy_stations--; + ret = ath10k_recalc_rtscts_prot(arvif); + if (ret) { + ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", + arvif->vdev_id, ret); + return ret; + } + } + ret = ath10k_clear_peer_keys(arvif, sta->addr); if (ret) { - ath10k_warn("could not clear all peer wep keys for vdev %i: %d\n", + ath10k_warn("failed to clear all peer wep keys for vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -1685,19 +1755,44 @@ static int ath10k_update_channel_list(struct ath10k *ar) return ret; } +static enum wmi_dfs_region +ath10k_mac_get_dfs_region(enum nl80211_dfs_regions dfs_region) +{ + switch (dfs_region) { + case NL80211_DFS_UNSET: + return WMI_UNINIT_DFS_DOMAIN; + case NL80211_DFS_FCC: + return WMI_FCC_DFS_DOMAIN; + case NL80211_DFS_ETSI: + return WMI_ETSI_DFS_DOMAIN; + case NL80211_DFS_JP: + return WMI_MKK4_DFS_DOMAIN; + } + return WMI_UNINIT_DFS_DOMAIN; +} + static void ath10k_regd_update(struct ath10k *ar) { struct reg_dmn_pair_mapping *regpair; int ret; + enum wmi_dfs_region wmi_dfs_reg; + enum nl80211_dfs_regions nl_dfs_reg; lockdep_assert_held(&ar->conf_mutex); ret = ath10k_update_channel_list(ar); if (ret) - ath10k_warn("could not update channel list (%d)\n", ret); + ath10k_warn("failed to update channel list: %d\n", ret); regpair = ar->ath_common.regulatory.regpair; + if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) { + nl_dfs_reg = ar->dfs_detector->region; + wmi_dfs_reg = ath10k_mac_get_dfs_region(nl_dfs_reg); + } else { + wmi_dfs_reg = WMI_UNINIT_DFS_DOMAIN; + } + /* Target allows setting up per-band regdomain but ath_common provides * a combined one only */ ret = ath10k_wmi_pdev_set_regdomain(ar, @@ -1705,9 +1800,10 @@ static void ath10k_regd_update(struct ath10k *ar) regpair->reg_domain, /* 2ghz */ regpair->reg_domain, /* 5ghz */ regpair->reg_2ghz_ctl, - regpair->reg_5ghz_ctl); + regpair->reg_5ghz_ctl, + wmi_dfs_reg); if (ret) - ath10k_warn("could not set pdev regdomain (%d)\n", ret); + ath10k_warn("failed to set pdev regdomain: %d\n", ret); } static void ath10k_reg_notifier(struct wiphy *wiphy, @@ -1725,7 +1821,7 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector, request->dfs_region); if (!result) - ath10k_warn("dfs region 0x%X not supported, will trigger radar for every pulse\n", + ath10k_warn("DFS region 0x%X not supported, will trigger radar for every pulse\n", request->dfs_region); } @@ -1759,10 +1855,10 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, if (info->control.vif) return ath10k_vif_to_arvif(info->control.vif)->vdev_id; - if (ar->monitor_enabled) + if (ar->monitor_started) return ar->monitor_vdev_id; - ath10k_warn("could not resolve vdev id\n"); + ath10k_warn("failed to resolve vdev id\n"); return 0; } @@ -1803,7 +1899,9 @@ static void ath10k_tx_wep_key_work(struct work_struct *work) arvif->ar->wmi.vdev_param->def_keyid, keyidx); if (ret) { - ath10k_warn("could not update wep keyidx (%d)\n", ret); + ath10k_warn("failed to update wep key index for vdev %d: %d\n", + arvif->vdev_id, + ret); return; } @@ -1879,7 +1977,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) ar->fw_features)) { if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >= ATH10K_MAX_NUM_MGMT_PENDING) { - ath10k_warn("wmi mgmt_tx queue limit reached\n"); + ath10k_warn("reached WMI management tranmist queue limit\n"); ret = -EBUSY; goto exit; } @@ -1903,7 +2001,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) exit: if (ret) { - ath10k_warn("tx failed (%d). dropping packet.\n", ret); + ath10k_warn("failed to transmit packet, dropping: %d\n", ret); ieee80211_free_txskb(ar->hw, skb); } } @@ -1964,7 +2062,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) if (!peer) { ret = ath10k_peer_create(ar, vdev_id, peer_addr); if (ret) - ath10k_warn("peer %pM on vdev %d not created (%d)\n", + ath10k_warn("failed to create peer %pM on vdev %d: %d\n", peer_addr, vdev_id, ret); } @@ -1984,7 +2082,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) if (!peer) { ret = ath10k_peer_delete(ar, vdev_id, peer_addr); if (ret) - ath10k_warn("peer %pM on vdev %d not deleted (%d)\n", + ath10k_warn("failed to delete peer %pM on vdev %d: %d\n", peer_addr, vdev_id, ret); } @@ -2018,7 +2116,8 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) ret = ath10k_wmi_mgmt_tx(ar, skb); if (ret) { - ath10k_warn("wmi mgmt_tx failed (%d)\n", ret); + ath10k_warn("failed to transmit management frame via WMI: %d\n", + ret); ieee80211_free_txskb(ar->hw, skb); } } @@ -2043,7 +2142,7 @@ void ath10k_reset_scan(unsigned long ptr) return; } - ath10k_warn("scan timeout. resetting. fw issue?\n"); + ath10k_warn("scan timed out, firmware problem?\n"); if (ar->scan.is_roc) ieee80211_remain_on_channel_expired(ar->hw); @@ -2079,7 +2178,7 @@ static int ath10k_abort_scan(struct ath10k *ar) ret = ath10k_wmi_stop_scan(ar, &arg); if (ret) { - ath10k_warn("could not submit wmi stop scan (%d)\n", ret); + ath10k_warn("failed to stop wmi scan: %d\n", ret); spin_lock_bh(&ar->data_lock); ar->scan.in_progress = false; ath10k_offchan_tx_purge(ar); @@ -2099,7 +2198,7 @@ static int ath10k_abort_scan(struct ath10k *ar) spin_lock_bh(&ar->data_lock); if (ar->scan.in_progress) { - ath10k_warn("could not stop scan. its still in progress\n"); + ath10k_warn("failed to stop scan, it's still in progress\n"); ar->scan.in_progress = false; ath10k_offchan_tx_purge(ar); ret = -ETIMEDOUT; @@ -2194,7 +2293,13 @@ void ath10k_halt(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); - ath10k_stop_cac(ar); + if (ath10k_monitor_is_enabled(ar)) { + clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + ar->promisc = false; + ar->monitor = false; + ath10k_monitor_stop(ar); + } + del_timer_sync(&ar->scan.timeout); ath10k_offchan_tx_purge(ar); ath10k_mgmt_over_wmi_tx_purge(ar); @@ -2226,14 +2331,14 @@ static int ath10k_start(struct ieee80211_hw *hw) ret = ath10k_hif_power_up(ar); if (ret) { - ath10k_err("could not init hif (%d)\n", ret); + ath10k_err("Could not init hif: %d\n", ret); ar->state = ATH10K_STATE_OFF; goto exit; } ret = ath10k_core_start(ar); if (ret) { - ath10k_err("could not init core (%d)\n", ret); + ath10k_err("Could not init core: %d\n", ret); ath10k_hif_power_down(ar); ar->state = ATH10K_STATE_OFF; goto exit; @@ -2246,13 +2351,11 @@ static int ath10k_start(struct ieee80211_hw *hw) ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1); if (ret) - ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n", - ret); + ath10k_warn("failed to enable PMF QOS: %d\n", ret); ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1); if (ret) - ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", - ret); + ath10k_warn("failed to enable dynamic BW: %d\n", ret); /* * By default FW set ARP frames ac to voice (6). In that case ARP @@ -2266,11 +2369,12 @@ static int ath10k_start(struct ieee80211_hw *hw) ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->arp_ac_override, 0); if (ret) { - ath10k_warn("could not set arp ac override parameter: %d\n", + ath10k_warn("failed to set arp ac override parameter: %d\n", ret); goto exit; } + ar->num_started_vdevs = 0; ath10k_regd_update(ar); ret = 0; @@ -2309,7 +2413,7 @@ static int ath10k_config_ps(struct ath10k *ar) list_for_each_entry(arvif, &ar->arvifs, list) { ret = ath10k_mac_vif_setup_ps(arvif); if (ret) { - ath10k_warn("could not setup powersave (%d)\n", ret); + ath10k_warn("failed to setup powersave: %d\n", ret); break; } } @@ -2343,7 +2447,6 @@ static const char *chandef_get_width(enum nl80211_chan_width width) static void ath10k_config_chan(struct ath10k *ar) { struct ath10k_vif *arvif; - bool monitor_was_enabled; int ret; lockdep_assert_held(&ar->conf_mutex); @@ -2357,10 +2460,8 @@ static void ath10k_config_chan(struct ath10k *ar) /* First stop monitor interface. Some FW versions crash if there's a * lone monitor interface. */ - monitor_was_enabled = ar->monitor_enabled; - - if (ar->monitor_enabled) - ath10k_monitor_stop(ar); + if (ar->monitor_started) + ath10k_monitor_vdev_stop(ar); list_for_each_entry(arvif, &ar->arvifs, list) { if (!arvif->is_started) @@ -2371,7 +2472,7 @@ static void ath10k_config_chan(struct ath10k *ar) ret = ath10k_vdev_stop(arvif); if (ret) { - ath10k_warn("could not stop vdev %d (%d)\n", + ath10k_warn("failed to stop vdev %d: %d\n", arvif->vdev_id, ret); continue; } @@ -2388,7 +2489,7 @@ static void ath10k_config_chan(struct ath10k *ar) ret = ath10k_vdev_start(arvif); if (ret) { - ath10k_warn("could not start vdev %d (%d)\n", + ath10k_warn("failed to start vdev %d: %d\n", arvif->vdev_id, ret); continue; } @@ -2399,14 +2500,14 @@ static void ath10k_config_chan(struct ath10k *ar) ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { - ath10k_warn("could not bring vdev up %d (%d)\n", + ath10k_warn("failed to bring vdev up %d: %d\n", arvif->vdev_id, ret); continue; } } - if (monitor_was_enabled) - ath10k_monitor_start(ar, ar->monitor_vdev_id); + if (ath10k_monitor_is_enabled(ar)) + ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id); } static int ath10k_config(struct ieee80211_hw *hw, u32 changed) @@ -2420,15 +2521,17 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { ath10k_dbg(ATH10K_DBG_MAC, - "mac config channel %d mhz flags 0x%x\n", + "mac config channel %dMHz flags 0x%x radar %d\n", conf->chandef.chan->center_freq, - conf->chandef.chan->flags); + conf->chandef.chan->flags, + conf->radar_enabled); spin_lock_bh(&ar->data_lock); ar->rx_channel = conf->chandef.chan; spin_unlock_bh(&ar->data_lock); - ath10k_config_radar_detection(ar); + ar->radar_enabled = conf->radar_enabled; + ath10k_recalc_radar_detection(ar); if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) { ar->chandef = conf->chandef; @@ -2444,14 +2547,14 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) ret = ath10k_wmi_pdev_set_param(ar, param, hw->conf.power_level * 2); if (ret) - ath10k_warn("mac failed to set 2g txpower %d (%d)\n", + ath10k_warn("failed to set 2g txpower %d: %d\n", hw->conf.power_level, ret); param = ar->wmi.pdev_param->txpower_limit5g; ret = ath10k_wmi_pdev_set_param(ar, param, hw->conf.power_level * 2); if (ret) - ath10k_warn("mac failed to set 5g txpower %d (%d)\n", + ath10k_warn("failed to set 5g txpower %d: %d\n", hw->conf.power_level, ret); } @@ -2459,10 +2562,19 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) ath10k_config_ps(ar); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { - if (conf->flags & IEEE80211_CONF_MONITOR) - ret = ath10k_monitor_create(ar); - else - ret = ath10k_monitor_destroy(ar); + if (conf->flags & IEEE80211_CONF_MONITOR && !ar->monitor) { + ar->monitor = true; + ret = ath10k_monitor_start(ar); + if (ret) { + ath10k_warn("failed to start monitor (config): %d\n", + ret); + ar->monitor = false; + } + } else if (!(conf->flags & IEEE80211_CONF_MONITOR) && + ar->monitor) { + ar->monitor = false; + ath10k_monitor_stop(ar); + } } mutex_unlock(&ar->conf_mutex); @@ -2497,12 +2609,6 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work); INIT_LIST_HEAD(&arvif->list); - if ((vif->type == NL80211_IFTYPE_MONITOR) && ar->monitor_present) { - ath10k_warn("Only one monitor interface allowed\n"); - ret = -EBUSY; - goto err; - } - bit = ffs(ar->free_vdev_map); if (bit == 0) { ret = -EBUSY; @@ -2545,7 +2651,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, vif->addr); if (ret) { - ath10k_warn("WMI vdev %i create failed: ret %d\n", + ath10k_warn("failed to create WMI vdev %i: %d\n", arvif->vdev_id, ret); goto err; } @@ -2557,7 +2663,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param, arvif->def_wep_key_idx); if (ret) { - ath10k_warn("Failed to set vdev %i default keyid: %d\n", + ath10k_warn("failed to set vdev %i default key id: %d\n", arvif->vdev_id, ret); goto err_vdev_delete; } @@ -2567,7 +2673,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ATH10K_HW_TXRX_NATIVE_WIFI); /* 10.X firmware does not support this VDEV parameter. Do not warn */ if (ret && ret != -EOPNOTSUPP) { - ath10k_warn("Failed to set vdev %i TX encap: %d\n", + ath10k_warn("failed to set vdev %i TX encapsulation: %d\n", arvif->vdev_id, ret); goto err_vdev_delete; } @@ -2575,14 +2681,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr); if (ret) { - ath10k_warn("Failed to create vdev %i peer for AP: %d\n", + ath10k_warn("failed to create vdev %i peer for AP: %d\n", arvif->vdev_id, ret); goto err_vdev_delete; } ret = ath10k_mac_set_kickout(arvif); if (ret) { - ath10k_warn("Failed to set vdev %i kickout parameters: %d\n", + ath10k_warn("failed to set vdev %i kickout parameters: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2594,7 +2700,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); if (ret) { - ath10k_warn("Failed to set vdev %i RX wake policy: %d\n", + ath10k_warn("failed to set vdev %i RX wake policy: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2604,7 +2710,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); if (ret) { - ath10k_warn("Failed to set vdev %i TX wake thresh: %d\n", + ath10k_warn("failed to set vdev %i TX wake thresh: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2614,7 +2720,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); if (ret) { - ath10k_warn("Failed to set vdev %i PSPOLL count: %d\n", + ath10k_warn("failed to set vdev %i PSPOLL count: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2622,21 +2728,18 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold); if (ret) { - ath10k_warn("failed to set rts threshold for vdev %d (%d)\n", + ath10k_warn("failed to set rts threshold for vdev %d: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold); if (ret) { - ath10k_warn("failed to set frag threshold for vdev %d (%d)\n", + ath10k_warn("failed to set frag threshold for vdev %d: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) - ar->monitor_present = true; - mutex_unlock(&ar->conf_mutex); return 0; @@ -2679,7 +2782,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr); if (ret) - ath10k_warn("Failed to remove peer for AP vdev %i: %d\n", + ath10k_warn("failed to remove peer for AP vdev %i: %d\n", arvif->vdev_id, ret); kfree(arvif->u.ap.noa_data); @@ -2690,12 +2793,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id); if (ret) - ath10k_warn("WMI vdev %i delete failed: %d\n", + ath10k_warn("failed to delete WMI vdev %i: %d\n", arvif->vdev_id, ret); - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) - ar->monitor_present = false; - ath10k_peer_cleanup(ar, arvif->vdev_id); mutex_unlock(&ar->conf_mutex); @@ -2728,28 +2828,17 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, *total_flags &= SUPPORTED_FILTERS; ar->filter_flags = *total_flags; - /* Monitor must not be started if it wasn't created first. - * Promiscuous mode may be started on a non-monitor interface - in - * such case the monitor vdev is not created so starting the - * monitor makes no sense. Since ath10k uses no special RX filters - * (only BSS filter in STA mode) there's no need for any special - * action here. */ - if ((ar->filter_flags & FIF_PROMISC_IN_BSS) && - !ar->monitor_enabled && ar->monitor_present) { - ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d start\n", - ar->monitor_vdev_id); - - ret = ath10k_monitor_start(ar, ar->monitor_vdev_id); - if (ret) - ath10k_warn("Unable to start monitor mode\n"); - } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && - ar->monitor_enabled && ar->monitor_present) { - ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d stop\n", - ar->monitor_vdev_id); - - ret = ath10k_monitor_stop(ar); - if (ret) - ath10k_warn("Unable to stop monitor mode\n"); + if (ar->filter_flags & FIF_PROMISC_IN_BSS && !ar->promisc) { + ar->promisc = true; + ret = ath10k_monitor_start(ar); + if (ret) { + ath10k_warn("failed to start monitor (promisc): %d\n", + ret); + ar->promisc = false; + } + } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && ar->promisc) { + ar->promisc = false; + ath10k_monitor_stop(ar); } mutex_unlock(&ar->conf_mutex); @@ -2780,7 +2869,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, arvif->vdev_id, arvif->beacon_interval); if (ret) - ath10k_warn("Failed to set beacon interval for vdev %d: %i\n", + ath10k_warn("failed to set beacon interval for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -2793,7 +2882,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_pdev_set_param(ar, pdev_param, WMI_BEACON_STAGGERED_MODE); if (ret) - ath10k_warn("Failed to set beacon mode for vdev %d: %i\n", + ath10k_warn("failed to set beacon mode for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -2808,7 +2897,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, arvif->dtim_period); if (ret) - ath10k_warn("Failed to set dtim period for vdev %d: %i\n", + ath10k_warn("failed to set dtim period for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -2829,7 +2918,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_peer_create(ar, arvif->vdev_id, info->bssid); if (ret) - ath10k_warn("Failed to add peer %pM for vdev %d when changing bssid: %i\n", + ath10k_warn("failed to add peer %pM for vdev %d when changing bssid: %i\n", info->bssid, arvif->vdev_id, ret); if (vif->type == NL80211_IFTYPE_STATION) { @@ -2868,20 +2957,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ath10k_control_beaconing(arvif, info); if (changed & BSS_CHANGED_ERP_CTS_PROT) { - u32 cts_prot; - if (info->use_cts_prot) - cts_prot = 1; - else - cts_prot = 0; - + arvif->use_cts_prot = info->use_cts_prot; ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n", - arvif->vdev_id, cts_prot); + arvif->vdev_id, info->use_cts_prot); - vdev_param = ar->wmi.vdev_param->enable_rtscts; - ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, - cts_prot); + ret = ath10k_recalc_rtscts_prot(arvif); if (ret) - ath10k_warn("Failed to set CTS prot for vdev %d: %d\n", + ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", arvif->vdev_id, ret); } @@ -2900,7 +2982,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, slottime); if (ret) - ath10k_warn("Failed to set erp slot for vdev %d: %i\n", + ath10k_warn("failed to set erp slot for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -2919,7 +3001,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, preamble); if (ret) - ath10k_warn("Failed to set preamble for vdev %d: %i\n", + ath10k_warn("failed to set preamble for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -2990,7 +3072,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, ret = ath10k_start_scan(ar, &arg); if (ret) { - ath10k_warn("could not start hw scan (%d)\n", ret); + ath10k_warn("failed to start hw scan: %d\n", ret); spin_lock_bh(&ar->data_lock); ar->scan.in_progress = false; spin_unlock_bh(&ar->data_lock); @@ -3010,8 +3092,7 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); ret = ath10k_abort_scan(ar); if (ret) { - ath10k_warn("couldn't abort scan (%d). forcefully sending scan completion to mac80211\n", - ret); + ath10k_warn("failed to abort scan: %d\n", ret); ieee80211_scan_completed(hw, 1 /* aborted */); } mutex_unlock(&ar->conf_mutex); @@ -3089,7 +3170,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!peer) { if (cmd == SET_KEY) { - ath10k_warn("cannot install key for non-existent peer %pM\n", + ath10k_warn("failed to install key for non-existent peer %pM\n", peer_addr); ret = -EOPNOTSUPP; goto exit; @@ -3112,7 +3193,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = ath10k_install_key(arvif, key, cmd, peer_addr); if (ret) { - ath10k_warn("key installation failed for vdev %i peer %pM: %d\n", + ath10k_warn("failed to install key for vdev %i peer %pM: %d\n", arvif->vdev_id, peer_addr, ret); goto exit; } @@ -3127,7 +3208,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, peer->keys[key->keyidx] = NULL; else if (peer == NULL) /* impossible unless FW goes crazy */ - ath10k_warn("peer %pM disappeared!\n", peer_addr); + ath10k_warn("Peer %pM disappeared!\n", peer_addr); spin_unlock_bh(&ar->data_lock); exit: @@ -3195,6 +3276,16 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, smps, err); } + if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { + ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", + sta->addr); + + err = ath10k_station_assoc(ar, arvif, sta, true); + if (err) + ath10k_warn("failed to reassociate station: %pM\n", + sta->addr); + } + mutex_unlock(&ar->conf_mutex); } @@ -3236,7 +3327,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, max_num_peers = TARGET_NUM_PEERS; if (ar->num_peers >= max_num_peers) { - ath10k_warn("Number of peers exceeded: peers number %d (max peers %d)\n", + ath10k_warn("number of peers exceeded: peers number %d (max peers %d)\n", ar->num_peers, max_num_peers); ret = -ENOBUFS; goto exit; @@ -3248,7 +3339,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); if (ret) - ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n", + ath10k_warn("failed to add peer %pM for vdev %d when adding a new sta: %i\n", sta->addr, arvif->vdev_id, ret); } else if ((old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST)) { @@ -3260,7 +3351,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, arvif->vdev_id, sta->addr); ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); if (ret) - ath10k_warn("Failed to delete peer %pM for vdev %d: %i\n", + ath10k_warn("failed to delete peer %pM for vdev %d: %i\n", sta->addr, arvif->vdev_id, ret); if (vif->type == NL80211_IFTYPE_STATION) @@ -3275,9 +3366,9 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM associated\n", sta->addr); - ret = ath10k_station_assoc(ar, arvif, sta); + ret = ath10k_station_assoc(ar, arvif, sta, false); if (ret) - ath10k_warn("Failed to associate station %pM for vdev %i: %i\n", + ath10k_warn("failed to associate station %pM for vdev %i: %i\n", sta->addr, arvif->vdev_id, ret); } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTH && @@ -3291,7 +3382,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ret = ath10k_station_disassoc(ar, arvif, sta); if (ret) - ath10k_warn("Failed to disassociate station: %pM vdev %i ret %i\n", + ath10k_warn("failed to disassociate station: %pM vdev %i: %i\n", sta->addr, arvif->vdev_id, ret); } exit: @@ -3339,7 +3430,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, WMI_STA_PS_PARAM_UAPSD, arvif->u.sta.uapsd); if (ret) { - ath10k_warn("could not set uapsd params %d\n", ret); + ath10k_warn("failed to set uapsd params: %d\n", ret); goto exit; } @@ -3352,7 +3443,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, WMI_STA_PS_PARAM_RX_WAKE_POLICY, value); if (ret) - ath10k_warn("could not set rx wake param %d\n", ret); + ath10k_warn("failed to set rx wake param: %d\n", ret); exit: return ret; @@ -3402,13 +3493,13 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw, /* FIXME: FW accepts wmm params per hw, not per vif */ ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params); if (ret) { - ath10k_warn("could not set wmm params %d\n", ret); + ath10k_warn("failed to set wmm params: %d\n", ret); goto exit; } ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd); if (ret) - ath10k_warn("could not set sta uapsd %d\n", ret); + ath10k_warn("failed to set sta uapsd: %d\n", ret); exit: mutex_unlock(&ar->conf_mutex); @@ -3461,7 +3552,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ret = ath10k_start_scan(ar, &arg); if (ret) { - ath10k_warn("could not start roc scan (%d)\n", ret); + ath10k_warn("failed to start roc scan: %d\n", ret); spin_lock_bh(&ar->data_lock); ar->scan.in_progress = false; spin_unlock_bh(&ar->data_lock); @@ -3470,7 +3561,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ); if (ret == 0) { - ath10k_warn("could not switch to channel for roc scan\n"); + ath10k_warn("failed to switch to channel for roc scan\n"); ath10k_abort_scan(ar); ret = -ETIMEDOUT; goto exit; @@ -3511,7 +3602,7 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) ret = ath10k_mac_set_rts(arvif, value); if (ret) { - ath10k_warn("could not set rts threshold for vdev %d (%d)\n", + ath10k_warn("failed to set rts threshold for vdev %d: %d\n", arvif->vdev_id, ret); break; } @@ -3534,7 +3625,7 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) ret = ath10k_mac_set_rts(arvif, value); if (ret) { - ath10k_warn("could not set fragmentation threshold for vdev %d (%d)\n", + ath10k_warn("failed to set fragmentation threshold for vdev %d: %d\n", arvif->vdev_id, ret); break; } @@ -3544,7 +3635,8 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) return ret; } -static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct ath10k *ar = hw->priv; bool skip; @@ -3573,7 +3665,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) }), ATH10K_FLUSH_TIMEOUT_HZ); if (ret <= 0 || skip) - ath10k_warn("tx not flushed (skip %i ar-state %i): %i\n", + ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n", skip, ar->state, ret); skip: @@ -3608,7 +3700,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw, ret = ath10k_hif_suspend(ar); if (ret) { - ath10k_warn("could not suspend hif (%d)\n", ret); + ath10k_warn("failed to suspend hif: %d\n", ret); goto resume; } @@ -3617,7 +3709,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw, resume: ret = ath10k_wmi_pdev_resume_target(ar); if (ret) - ath10k_warn("could not resume target (%d)\n", ret); + ath10k_warn("failed to resume target: %d\n", ret); ret = 1; exit: @@ -3634,14 +3726,14 @@ static int ath10k_resume(struct ieee80211_hw *hw) ret = ath10k_hif_resume(ar); if (ret) { - ath10k_warn("could not resume hif (%d)\n", ret); + ath10k_warn("failed to resume hif: %d\n", ret); ret = 1; goto exit; } ret = ath10k_wmi_pdev_resume_target(ar); if (ret) { - ath10k_warn("could not resume target (%d)\n", ret); + ath10k_warn("failed to resume target: %d\n", ret); ret = 1; goto exit; } @@ -3964,7 +4056,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, fixed_rate); if (ret) { - ath10k_warn("Could not set fixed_rate param 0x%02x: %d\n", + ath10k_warn("failed to set fixed rate param 0x%02x: %d\n", fixed_rate, ret); ret = -EINVAL; goto exit; @@ -3977,7 +4069,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, vdev_param, fixed_nss); if (ret) { - ath10k_warn("Could not set fixed_nss param %d: %d\n", + ath10k_warn("failed to set fixed nss param %d: %d\n", fixed_nss, ret); ret = -EINVAL; goto exit; @@ -3990,7 +4082,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, force_sgi); if (ret) { - ath10k_warn("Could not set sgi param %d: %d\n", + ath10k_warn("failed to set sgi param %d: %d\n", force_sgi, ret); ret = -EINVAL; goto exit; @@ -4026,7 +4118,7 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, } if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) { - ath10k_warn("Could not force SGI usage for default rate settings\n"); + ath10k_warn("failed to force SGI usage for default rate settings\n"); return -EINVAL; } @@ -4072,8 +4164,8 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, bw = WMI_PEER_CHWIDTH_80MHZ; break; case IEEE80211_STA_RX_BW_160: - ath10k_warn("mac sta rc update for %pM: invalid bw %d\n", - sta->addr, sta->bandwidth); + ath10k_warn("Invalid bandwith %d in rc update for %pM\n", + sta->bandwidth, sta->addr); bw = WMI_PEER_CHWIDTH_20MHZ; break; } @@ -4099,8 +4191,8 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, smps = WMI_PEER_SMPS_DYNAMIC; break; case IEEE80211_SMPS_NUM_MODES: - ath10k_warn("mac sta rc update for %pM: invalid smps: %d\n", - sta->addr, sta->smps_mode); + ath10k_warn("Invalid smps %d in sta rc update for %pM\n", + sta->smps_mode, sta->addr); smps = WMI_PEER_SMPS_PS_NONE; break; } @@ -4108,15 +4200,6 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, arsta->smps = smps; } - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { - /* FIXME: Not implemented. Probably the only way to do it would - * be to re-assoc the peer. */ - changed &= ~IEEE80211_RC_SUPP_RATES_CHANGED; - ath10k_dbg(ATH10K_DBG_MAC, - "mac sta rc update for %pM: changing supported rates not implemented\n", - sta->addr); - } - arsta->changed |= changed; spin_unlock_bh(&ar->data_lock); @@ -4516,7 +4599,6 @@ int ath10k_mac_register(struct ath10k *ar) IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_SUPPORTS_STATIC_SMPS | - IEEE80211_HW_WANT_MONITOR_VIF | IEEE80211_HW_AP_LINK_PS | IEEE80211_HW_SPECTRUM_MGMT; @@ -4570,19 +4652,19 @@ int ath10k_mac_register(struct ath10k *ar) NL80211_DFS_UNSET); if (!ar->dfs_detector) - ath10k_warn("dfs pattern detector init failed\n"); + ath10k_warn("failed to initialise DFS pattern detector\n"); } ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, ath10k_reg_notifier); if (ret) { - ath10k_err("Regulatory initialization failed: %i\n", ret); + ath10k_err("failed to initialise regulatory: %i\n", ret); goto err_free; } ret = ieee80211_register_hw(ar->hw); if (ret) { - ath10k_err("ieee80211 registration failed: %d\n", ret); + ath10k_err("failed to register ieee80211: %d\n", ret); goto err_free; } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 9d242d801d9d35..bf1083d52e61d5 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -39,15 +39,27 @@ enum ath10k_pci_irq_mode { ATH10K_PCI_IRQ_MSI = 2, }; -static unsigned int ath10k_target_ps; +enum ath10k_pci_reset_mode { + ATH10K_PCI_RESET_AUTO = 0, + ATH10K_PCI_RESET_WARM_ONLY = 1, +}; + +static unsigned int ath10k_pci_target_ps; static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO; +static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO; -module_param(ath10k_target_ps, uint, 0644); -MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option"); +module_param_named(target_ps, ath10k_pci_target_ps, uint, 0644); +MODULE_PARM_DESC(target_ps, "Enable ath10k Target (SoC) PS option"); module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644); MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)"); +module_param_named(reset_mode, ath10k_pci_reset_mode, uint, 0644); +MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); + +/* how long wait to wait for target to initialise, in ms */ +#define ATH10K_PCI_TARGET_WAIT 3000 + #define QCA988X_2_0_DEVICE_ID (0x003c) static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = { @@ -346,9 +358,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, * 2) Buffer in DMA-able space */ orig_nbytes = nbytes; - data_buf = (unsigned char *)pci_alloc_consistent(ar_pci->pdev, - orig_nbytes, - &ce_data_base); + data_buf = (unsigned char *)dma_alloc_coherent(ar->dev, + orig_nbytes, + &ce_data_base, + GFP_ATOMIC); if (!data_buf) { ret = -ENOMEM; @@ -442,12 +455,12 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, __le32_to_cpu(((__le32 *)data_buf)[i]); } } else - ath10k_dbg(ATH10K_DBG_PCI, "%s failure (0x%x)\n", - __func__, address); + ath10k_warn("failed to read diag value at 0x%x: %d\n", + address, ret); if (data_buf) - pci_free_consistent(ar_pci->pdev, orig_nbytes, - data_buf, ce_data_base); + dma_free_coherent(ar->dev, orig_nbytes, data_buf, + ce_data_base); return ret; } @@ -490,9 +503,10 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, * 2) Buffer in DMA-able space */ orig_nbytes = nbytes; - data_buf = (unsigned char *)pci_alloc_consistent(ar_pci->pdev, - orig_nbytes, - &ce_data_base); + data_buf = (unsigned char *)dma_alloc_coherent(ar->dev, + orig_nbytes, + &ce_data_base, + GFP_ATOMIC); if (!data_buf) { ret = -ENOMEM; goto done; @@ -588,13 +602,13 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, done: if (data_buf) { - pci_free_consistent(ar_pci->pdev, orig_nbytes, data_buf, - ce_data_base); + dma_free_coherent(ar->dev, orig_nbytes, data_buf, + ce_data_base); } if (ret != 0) - ath10k_dbg(ATH10K_DBG_PCI, "%s failure (0x%x)\n", __func__, - address); + ath10k_warn("failed to write diag value at 0x%x: %d\n", + address, ret); return ret; } @@ -803,6 +817,9 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + ath10k_dbg(ATH10K_DBG_PCI, "pci hif get free queue number\n"); + return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl); } @@ -854,6 +871,8 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, int force) { + ath10k_dbg(ATH10K_DBG_PCI, "pci hif send complete check\n"); + if (!force) { int resources; /* @@ -880,7 +899,7 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar, { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); + ath10k_dbg(ATH10K_DBG_PCI, "pci hif set callbacks\n"); memcpy(&ar_pci->msg_callbacks_current, callbacks, sizeof(ar_pci->msg_callbacks_current)); @@ -938,6 +957,8 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, { int ret = 0; + ath10k_dbg(ATH10K_DBG_PCI, "pci hif map service\n"); + /* polling for received messages not supported */ *dl_is_polled = 0; @@ -997,6 +1018,8 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, { int ul_is_polled, dl_is_polled; + ath10k_dbg(ATH10K_DBG_PCI, "pci hif get default pipe\n"); + (void)ath10k_pci_hif_map_service_to_pipe(ar, ATH10K_HTC_SVC_ID_RSVD_CTRL, ul_pipe, @@ -1098,6 +1121,8 @@ static int ath10k_pci_hif_start(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret, ret_early; + ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n"); + ath10k_pci_free_early_irq(ar); ath10k_pci_kill_tasklet(ar); @@ -1233,18 +1258,10 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar) static void ath10k_pci_ce_deinit(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_pipe *pipe_info; - int pipe_num; + int i; - for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { - pipe_info = &ar_pci->pipe_info[pipe_num]; - if (pipe_info->ce_hdl) { - ath10k_ce_deinit(pipe_info->ce_hdl); - pipe_info->ce_hdl = NULL; - pipe_info->buf_sz = 0; - } - } + for (i = 0; i < CE_COUNT; i++) + ath10k_ce_deinit_pipe(ar, i); } static void ath10k_pci_hif_stop(struct ath10k *ar) @@ -1252,7 +1269,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); + ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n"); ret = ath10k_ce_disable_interrupts(ar); if (ret) @@ -1697,30 +1714,49 @@ static int ath10k_pci_init_config(struct ath10k *ar) return 0; } +static int ath10k_pci_alloc_ce(struct ath10k *ar) +{ + int i, ret; + + for (i = 0; i < CE_COUNT; i++) { + ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]); + if (ret) { + ath10k_err("failed to allocate copy engine pipe %d: %d\n", + i, ret); + return ret; + } + } + return 0; +} + +static void ath10k_pci_free_ce(struct ath10k *ar) +{ + int i; + + for (i = 0; i < CE_COUNT; i++) + ath10k_ce_free_pipe(ar, i); +} static int ath10k_pci_ce_init(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci_pipe *pipe_info; const struct ce_attr *attr; - int pipe_num; + int pipe_num, ret; for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { pipe_info = &ar_pci->pipe_info[pipe_num]; + pipe_info->ce_hdl = &ar_pci->ce_states[pipe_num]; pipe_info->pipe_num = pipe_num; pipe_info->hif_ce_state = ar; attr = &host_ce_config_wlan[pipe_num]; - pipe_info->ce_hdl = ath10k_ce_init(ar, pipe_num, attr); - if (pipe_info->ce_hdl == NULL) { - ath10k_err("failed to initialize CE for pipe: %d\n", - pipe_num); - - /* It is safe to call it here. It checks if ce_hdl is - * valid for each pipe */ - ath10k_pci_ce_deinit(ar); - return -1; + ret = ath10k_ce_init_pipe(ar, pipe_num, attr); + if (ret) { + ath10k_err("failed to initialize copy engine pipe %d: %d\n", + pipe_num, ret); + return ret; } if (pipe_num == CE_COUNT - 1) { @@ -1741,16 +1777,15 @@ static int ath10k_pci_ce_init(struct ath10k *ar) static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - u32 fw_indicator_address, fw_indicator; + u32 fw_indicator; ath10k_pci_wake(ar); - fw_indicator_address = ar_pci->fw_indicator_address; - fw_indicator = ath10k_pci_read32(ar, fw_indicator_address); + fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); if (fw_indicator & FW_IND_EVENT_PENDING) { /* ACK: clear Target-side pending event */ - ath10k_pci_write32(ar, fw_indicator_address, + ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, fw_indicator & ~FW_IND_EVENT_PENDING); if (ar_pci->started) { @@ -1769,11 +1804,10 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) static int ath10k_pci_warm_reset(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret = 0; u32 val; - ath10k_dbg(ATH10K_DBG_BOOT, "boot performing warm chip reset\n"); + ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n"); ret = ath10k_do_pci_wake(ar); if (ret) { @@ -1801,7 +1835,7 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) msleep(100); /* clear fw indicator */ - ath10k_pci_write32(ar, ar_pci->fw_indicator_address, 0); + ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0); /* clear target LF timer interrupts */ val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + @@ -1934,7 +1968,9 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) irq_mode = "legacy"; if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) - ath10k_info("pci irq %s\n", irq_mode); + ath10k_info("pci irq %s irq_mode %d reset_mode %d\n", + irq_mode, ath10k_pci_irq_mode, + ath10k_pci_reset_mode); return 0; @@ -1956,6 +1992,8 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) { int ret; + ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power up\n"); + /* * Hardware CUS232 version 2 has some issues with cold reset and the * preferred (and safer) way to perform a device reset is through a @@ -1966,9 +2004,14 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) */ ret = __ath10k_pci_hif_power_up(ar, false); if (ret) { - ath10k_warn("failed to power up target using warm reset (%d), trying cold reset\n", + ath10k_warn("failed to power up target using warm reset: %d\n", ret); + if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) + return ret; + + ath10k_warn("trying cold reset\n"); + ret = __ath10k_pci_hif_power_up(ar, true); if (ret) { ath10k_err("failed to power up target using cold reset too (%d)\n", @@ -1984,12 +2027,14 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n"); + ath10k_pci_free_early_irq(ar); ath10k_pci_kill_tasklet(ar); ath10k_pci_deinit_irq(ar); + ath10k_pci_ce_deinit(ar); ath10k_pci_warm_reset(ar); - ath10k_pci_ce_deinit(ar); if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ath10k_do_pci_sleep(ar); } @@ -2137,7 +2182,6 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) static void ath10k_pci_early_irq_tasklet(unsigned long data) { struct ath10k *ar = (struct ath10k *)data; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); u32 fw_ind; int ret; @@ -2148,9 +2192,9 @@ static void ath10k_pci_early_irq_tasklet(unsigned long data) return; } - fw_ind = ath10k_pci_read32(ar, ar_pci->fw_indicator_address); + fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); if (fw_ind & FW_IND_EVENT_PENDING) { - ath10k_pci_write32(ar, ar_pci->fw_indicator_address, + ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, fw_ind & ~FW_IND_EVENT_PENDING); /* Some structures are unavailable during early boot or at @@ -2385,33 +2429,50 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) static int ath10k_pci_wait_for_target_init(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - int wait_limit = 300; /* 3 sec */ + unsigned long timeout; int ret; + u32 val; + + ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n"); ret = ath10k_pci_wake(ar); if (ret) { - ath10k_err("failed to wake up target: %d\n", ret); + ath10k_err("failed to wake up target for init: %d\n", ret); return ret; } - while (wait_limit-- && - !(ioread32(ar_pci->mem + FW_INDICATOR_ADDRESS) & - FW_IND_INITIALIZED)) { + timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT); + + do { + val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); + + ath10k_dbg(ATH10K_DBG_BOOT, "boot target indicator %x\n", val); + + /* target should never return this */ + if (val == 0xffffffff) + continue; + + if (val & FW_IND_INITIALIZED) + break; + if (ar_pci->num_msi_intrs == 0) /* Fix potential race by repeating CORE_BASE writes */ - iowrite32(PCIE_INTR_FIRMWARE_MASK | - PCIE_INTR_CE_MASK_ALL, - ar_pci->mem + (SOC_CORE_BASE_ADDRESS | - PCIE_INTR_ENABLE_ADDRESS)); + ath10k_pci_soc_write32(ar, PCIE_INTR_ENABLE_ADDRESS, + PCIE_INTR_FIRMWARE_MASK | + PCIE_INTR_CE_MASK_ALL); + mdelay(10); - } + } while (time_before(jiffies, timeout)); - if (wait_limit < 0) { - ath10k_err("target stalled\n"); - ret = -EIO; + if (val == 0xffffffff || !(val & FW_IND_INITIALIZED)) { + ath10k_err("failed to receive initialized event from target: %08x\n", + val); + ret = -ETIMEDOUT; goto out; } + ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n"); + out: ath10k_pci_sleep(ar); return ret; @@ -2422,6 +2483,8 @@ static int ath10k_pci_cold_reset(struct ath10k *ar) int i, ret; u32 val; + ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n"); + ret = ath10k_do_pci_wake(ar); if (ret) { ath10k_err("failed to wake up target: %d\n", @@ -2453,6 +2516,9 @@ static int ath10k_pci_cold_reset(struct ath10k *ar) } ath10k_do_pci_sleep(ar); + + ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n"); + return 0; } @@ -2484,7 +2550,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, struct ath10k_pci *ar_pci; u32 lcr_val, chip_id; - ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); + ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n"); ar_pci = kzalloc(sizeof(*ar_pci), GFP_KERNEL); if (ar_pci == NULL) @@ -2503,7 +2569,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_ar_pci; } - if (ath10k_target_ps) + if (ath10k_pci_target_ps) set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features); ath10k_pci_dump_features(ar_pci); @@ -2516,7 +2582,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev, } ar_pci->ar = ar; - ar_pci->fw_indicator_address = FW_INDICATOR_ADDRESS; atomic_set(&ar_pci->keep_awake_count, 0); pci_set_drvdata(pdev, ar); @@ -2594,16 +2659,24 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ath10k_do_pci_sleep(ar); + ret = ath10k_pci_alloc_ce(ar); + if (ret) { + ath10k_err("failed to allocate copy engine pipes: %d\n", ret); + goto err_iomap; + } + ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem); ret = ath10k_core_register(ar, chip_id); if (ret) { ath10k_err("failed to register driver core: %d\n", ret); - goto err_iomap; + goto err_free_ce; } return 0; +err_free_ce: + ath10k_pci_free_ce(ar); err_iomap: pci_iounmap(pdev, mem); err_master: @@ -2626,7 +2699,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev) struct ath10k *ar = pci_get_drvdata(pdev); struct ath10k_pci *ar_pci; - ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); + ath10k_dbg(ATH10K_DBG_PCI, "pci remove\n"); if (!ar) return; @@ -2639,6 +2712,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev) tasklet_kill(&ar_pci->msi_fw_err); ath10k_core_unregister(ar); + ath10k_pci_free_ce(ar); pci_iounmap(pdev, ar_pci->mem); pci_release_region(pdev, BAR_NUM); @@ -2680,6 +2754,5 @@ module_exit(ath10k_pci_exit); MODULE_AUTHOR("Qualcomm Atheros"); MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE); -MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_OTP_FILE); +MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE); MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index b43fdb4f731973..dfdebb4157aa17 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -189,9 +189,6 @@ struct ath10k_pci { struct ath10k_hif_cb msg_callbacks_current; - /* Target address used to signal a pending firmware event */ - u32 fw_indicator_address; - /* Copy Engine used for Diagnostic Accesses */ struct ath10k_ce_pipe *ce_diag; diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 0541dd939ce9d8..82669a77e553b8 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -100,189 +100,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, wake_up(&htt->empty_tx_wq); } -static const u8 rx_legacy_rate_idx[] = { - 3, /* 0x00 - 11Mbps */ - 2, /* 0x01 - 5.5Mbps */ - 1, /* 0x02 - 2Mbps */ - 0, /* 0x03 - 1Mbps */ - 3, /* 0x04 - 11Mbps */ - 2, /* 0x05 - 5.5Mbps */ - 1, /* 0x06 - 2Mbps */ - 0, /* 0x07 - 1Mbps */ - 10, /* 0x08 - 48Mbps */ - 8, /* 0x09 - 24Mbps */ - 6, /* 0x0A - 12Mbps */ - 4, /* 0x0B - 6Mbps */ - 11, /* 0x0C - 54Mbps */ - 9, /* 0x0D - 36Mbps */ - 7, /* 0x0E - 18Mbps */ - 5, /* 0x0F - 9Mbps */ -}; - -static void process_rx_rates(struct ath10k *ar, struct htt_rx_info *info, - enum ieee80211_band band, - struct ieee80211_rx_status *status) -{ - u8 cck, rate, rate_idx, bw, sgi, mcs, nss; - u8 info0 = info->rate.info0; - u32 info1 = info->rate.info1; - u32 info2 = info->rate.info2; - u8 preamble = 0; - - /* Check if valid fields */ - if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID)) - return; - - preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE); - - switch (preamble) { - case HTT_RX_LEGACY: - cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK; - rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE); - rate_idx = 0; - - if (rate < 0x08 || rate > 0x0F) - break; - - switch (band) { - case IEEE80211_BAND_2GHZ: - if (cck) - rate &= ~BIT(3); - rate_idx = rx_legacy_rate_idx[rate]; - break; - case IEEE80211_BAND_5GHZ: - rate_idx = rx_legacy_rate_idx[rate]; - /* We are using same rate table registering - HW - ath10k_rates[]. In case of 5GHz skip - CCK rates, so -4 here */ - rate_idx -= 4; - break; - default: - break; - } - - status->rate_idx = rate_idx; - break; - case HTT_RX_HT: - case HTT_RX_HT_WITH_TXBF: - /* HT-SIG - Table 20-11 in info1 and info2 */ - mcs = info1 & 0x1F; - nss = mcs >> 3; - bw = (info1 >> 7) & 1; - sgi = (info2 >> 7) & 1; - - status->rate_idx = mcs; - status->flag |= RX_FLAG_HT; - if (sgi) - status->flag |= RX_FLAG_SHORT_GI; - if (bw) - status->flag |= RX_FLAG_40MHZ; - break; - case HTT_RX_VHT: - case HTT_RX_VHT_WITH_TXBF: - /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2 - TODO check this */ - mcs = (info2 >> 4) & 0x0F; - nss = ((info1 >> 10) & 0x07) + 1; - bw = info1 & 3; - sgi = info2 & 1; - - status->rate_idx = mcs; - status->vht_nss = nss; - - if (sgi) - status->flag |= RX_FLAG_SHORT_GI; - - switch (bw) { - /* 20MHZ */ - case 0: - break; - /* 40MHZ */ - case 1: - status->flag |= RX_FLAG_40MHZ; - break; - /* 80MHZ */ - case 2: - status->vht_flag |= RX_VHT_FLAG_80MHZ; - } - - status->flag |= RX_FLAG_VHT; - break; - default: - break; - } -} - -void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info) -{ - struct ieee80211_rx_status *status; - struct ieee80211_channel *ch; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)info->skb->data; - - status = IEEE80211_SKB_RXCB(info->skb); - memset(status, 0, sizeof(*status)); - - if (info->encrypt_type != HTT_RX_MPDU_ENCRYPT_NONE) { - status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED | - RX_FLAG_MMIC_STRIPPED; - hdr->frame_control = __cpu_to_le16( - __le16_to_cpu(hdr->frame_control) & - ~IEEE80211_FCTL_PROTECTED); - } - - if (info->mic_err) - status->flag |= RX_FLAG_MMIC_ERROR; - - if (info->fcs_err) - status->flag |= RX_FLAG_FAILED_FCS_CRC; - - if (info->amsdu_more) - status->flag |= RX_FLAG_AMSDU_MORE; - - status->signal = info->signal; - - spin_lock_bh(&ar->data_lock); - ch = ar->scan_channel; - if (!ch) - ch = ar->rx_channel; - spin_unlock_bh(&ar->data_lock); - - if (!ch) { - ath10k_warn("no channel configured; ignoring frame!\n"); - dev_kfree_skb_any(info->skb); - return; - } - - process_rx_rates(ar, info, ch->band, status); - status->band = ch->band; - status->freq = ch->center_freq; - - if (info->rate.info0 & HTT_RX_INDICATION_INFO0_END_VALID) { - /* TSF available only in 32-bit */ - status->mactime = info->tsf & 0xffffffff; - status->flag |= RX_FLAG_MACTIME_END; - } - - ath10k_dbg(ATH10K_DBG_DATA, - "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i\n", - info->skb, - info->skb->len, - status->flag == 0 ? "legacy" : "", - status->flag & RX_FLAG_HT ? "ht" : "", - status->flag & RX_FLAG_VHT ? "vht" : "", - status->flag & RX_FLAG_40MHZ ? "40" : "", - status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "", - status->flag & RX_FLAG_SHORT_GI ? "sgi " : "", - status->rate_idx, - status->vht_nss, - status->freq, - status->band, status->flag, info->fcs_err); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", - info->skb->data, info->skb->len); - - ieee80211_rx(ar->hw, info->skb); -} - struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, const u8 *addr) { diff --git a/drivers/net/wireless/ath/ath10k/txrx.h b/drivers/net/wireless/ath/ath10k/txrx.h index 356dc9c04c9e39..aee3e20058f814 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.h +++ b/drivers/net/wireless/ath/ath10k/txrx.h @@ -21,7 +21,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, const struct htt_tx_done *tx_done); -void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info); struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, const u8 *addr); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index cb1f7b5bcf4cde..fe4d5f1c672f56 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1362,13 +1362,10 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) struct sk_buff *bcn; int ret, vdev_id = 0; - ath10k_dbg(ATH10K_DBG_MGMT, "WMI_HOST_SWBA_EVENTID\n"); - ev = (struct wmi_host_swba_event *)skb->data; map = __le32_to_cpu(ev->vdev_map); - ath10k_dbg(ATH10K_DBG_MGMT, "host swba:\n" - "-vdev map 0x%x\n", + ath10k_dbg(ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n", ev->vdev_map); for (; map; map >>= 1, vdev_id++) { @@ -1385,12 +1382,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) bcn_info = &ev->bcn_info[i]; ath10k_dbg(ATH10K_DBG_MGMT, - "-bcn_info[%d]:\n" - "--tim_len %d\n" - "--tim_mcast %d\n" - "--tim_changed %d\n" - "--tim_num_ps_pending %d\n" - "--tim_bitmap 0x%08x%08x%08x%08x\n", + "mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n", i, __le32_to_cpu(bcn_info->tim_info.tim_len), __le32_to_cpu(bcn_info->tim_info.tim_mcast), @@ -2393,8 +2385,9 @@ int ath10k_wmi_connect_htc_service(struct ath10k *ar) return 0; } -int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, - u16 rd5g, u16 ctl2g, u16 ctl5g) +static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd, + u16 rd2g, u16 rd5g, u16 ctl2g, + u16 ctl5g) { struct wmi_pdev_set_regdomain_cmd *cmd; struct sk_buff *skb; @@ -2418,6 +2411,46 @@ int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, ar->wmi.cmd->pdev_set_regdomain_cmdid); } +static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd, + u16 rd2g, u16 rd5g, + u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg) +{ + struct wmi_pdev_set_regdomain_cmd_10x *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_pdev_set_regdomain_cmd_10x *)skb->data; + cmd->reg_domain = __cpu_to_le32(rd); + cmd->reg_domain_2G = __cpu_to_le32(rd2g); + cmd->reg_domain_5G = __cpu_to_le32(rd5g); + cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g); + cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g); + cmd->dfs_domain = __cpu_to_le32(dfs_reg); + + ath10k_dbg(ATH10K_DBG_WMI, + "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n", + rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_set_regdomain_cmdid); +} + +int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, + u16 rd5g, u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg) +{ + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) + return ath10k_wmi_10x_pdev_set_regdomain(ar, rd, rd2g, rd5g, + ctl2g, ctl5g, dfs_reg); + else + return ath10k_wmi_main_pdev_set_regdomain(ar, rd, rd2g, rd5g, + ctl2g, ctl5g); +} + int ath10k_wmi_pdev_set_channel(struct ath10k *ar, const struct wmi_channel_arg *arg) { @@ -3456,8 +3489,9 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set); ath10k_dbg(ATH10K_DBG_WMI, - "wmi peer assoc vdev %d addr %pM\n", - arg->vdev_id, arg->addr); + "wmi peer assoc vdev %d addr %pM (%s)\n", + arg->vdev_id, arg->addr, + arg->peer_reassoc ? "reassociate" : "new"); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 4fcc96aa9513b8..2731b375ed20b2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -198,16 +198,6 @@ struct wmi_mac_addr { } __packed; } __packed; -/* macro to convert MAC address from WMI word format to char array */ -#define WMI_MAC_ADDR_TO_CHAR_ARRAY(pwmi_mac_addr, c_macaddr) do { \ - (c_macaddr)[0] = ((pwmi_mac_addr)->word0) & 0xff; \ - (c_macaddr)[1] = (((pwmi_mac_addr)->word0) >> 8) & 0xff; \ - (c_macaddr)[2] = (((pwmi_mac_addr)->word0) >> 16) & 0xff; \ - (c_macaddr)[3] = (((pwmi_mac_addr)->word0) >> 24) & 0xff; \ - (c_macaddr)[4] = ((pwmi_mac_addr)->word1) & 0xff; \ - (c_macaddr)[5] = (((pwmi_mac_addr)->word1) >> 8) & 0xff; \ - } while (0) - struct wmi_cmd_map { u32 init_cmdid; u32 start_scan_cmdid; @@ -1265,7 +1255,7 @@ struct wmi_resource_config { */ __le32 rx_decap_mode; - /* what is the maximum scan requests than can be queued */ + /* what is the maximum number of scan requests that can be queued */ __le32 scan_max_pending_reqs; /* maximum VDEV that could use BMISS offload */ @@ -1450,7 +1440,7 @@ struct wmi_resource_config_10x { */ __le32 rx_decap_mode; - /* what is the maximum scan requests than can be queued */ + /* what is the maximum number of scan requests that can be queued */ __le32 scan_max_pending_reqs; /* maximum VDEV that could use BMISS offload */ @@ -2185,6 +2175,31 @@ struct wmi_pdev_set_regdomain_cmd { __le32 conformance_test_limit_5G; } __packed; +enum wmi_dfs_region { + /* Uninitialized dfs domain */ + WMI_UNINIT_DFS_DOMAIN = 0, + + /* FCC3 dfs domain */ + WMI_FCC_DFS_DOMAIN = 1, + + /* ETSI dfs domain */ + WMI_ETSI_DFS_DOMAIN = 2, + + /*Japan dfs domain */ + WMI_MKK4_DFS_DOMAIN = 3, +}; + +struct wmi_pdev_set_regdomain_cmd_10x { + __le32 reg_domain; + __le32 reg_domain_2G; + __le32 reg_domain_5G; + __le32 conformance_test_limit_2G; + __le32 conformance_test_limit_5G; + + /* dfs domain from wmi_dfs_region */ + __le32 dfs_domain; +} __packed; + /* Command to set/unset chip in quiet mode */ struct wmi_pdev_set_quiet_cmd { /* period in TUs */ @@ -2210,6 +2225,19 @@ enum ath10k_protmode { ATH10K_PROT_RTSCTS = 2, /* RTS-CTS */ }; +enum wmi_rtscts_profile { + WMI_RTSCTS_FOR_NO_RATESERIES = 0, + WMI_RTSCTS_FOR_SECOND_RATESERIES, + WMI_RTSCTS_ACROSS_SW_RETRIES +}; + +#define WMI_RTSCTS_ENABLED 1 +#define WMI_RTSCTS_SET_MASK 0x0f +#define WMI_RTSCTS_SET_LSB 0 + +#define WMI_RTSCTS_PROFILE_MASK 0xf0 +#define WMI_RTSCTS_PROFILE_LSB 4 + enum wmi_beacon_gen_mode { WMI_BEACON_STAGGERED_MODE = 0, WMI_BEACON_BURST_MODE = 1 @@ -2682,6 +2710,9 @@ struct wal_dbg_tx_stats { /* wal pdev resets */ __le32 pdev_resets; + /* frames dropped due to non-availability of stateless TIDs */ + __le32 stateless_tid_alloc_failure; + __le32 phy_underrun; /* MPDU is more than txop limit */ @@ -2738,13 +2769,21 @@ enum wmi_stats_id { WMI_REQUEST_AP_STAT = 0x02 }; +struct wlan_inst_rssi_args { + __le16 cfg_retry_count; + __le16 retry_count; +}; + struct wmi_request_stats_cmd { __le32 stats_id; - /* - * Space to add parameters like - * peer mac addr - */ + __le32 vdev_id; + + /* peer MAC address */ + struct wmi_mac_addr peer_macaddr; + + /* Instantaneous RSSI arguments */ + struct wlan_inst_rssi_args inst_rssi_args; } __packed; /* Suspend option */ @@ -2795,7 +2834,7 @@ struct wmi_stats_event { * PDEV statistics * TODO: add all PDEV stats here */ -struct wmi_pdev_stats { +struct wmi_pdev_stats_old { __le32 chan_nf; /* Channel noise floor */ __le32 tx_frame_count; /* TX frame count */ __le32 rx_frame_count; /* RX frame count */ @@ -2806,6 +2845,23 @@ struct wmi_pdev_stats { struct wal_dbg_stats wal; /* WAL dbg stats */ } __packed; +struct wmi_pdev_stats_10x { + __le32 chan_nf; /* Channel noise floor */ + __le32 tx_frame_count; /* TX frame count */ + __le32 rx_frame_count; /* RX frame count */ + __le32 rx_clear_count; /* rx clear count */ + __le32 cycle_count; /* cycle count */ + __le32 phy_err_count; /* Phy error count */ + __le32 chan_tx_pwr; /* channel tx power */ + struct wal_dbg_stats wal; /* WAL dbg stats */ + __le32 ack_rx_bad; + __le32 rts_bad; + __le32 rts_good; + __le32 fcs_bad; + __le32 no_beacons; + __le32 mib_int_count; +} __packed; + /* * VDEV statistics * TODO: add all VDEV stats here @@ -2818,10 +2874,17 @@ struct wmi_vdev_stats { * peer statistics. * TODO: add more stats */ -struct wmi_peer_stats { +struct wmi_peer_stats_old { + struct wmi_mac_addr peer_macaddr; + __le32 peer_rssi; + __le32 peer_tx_rate; +} __packed; + +struct wmi_peer_stats_10x { struct wmi_mac_addr peer_macaddr; __le32 peer_rssi; __le32 peer_tx_rate; + __le32 peer_rx_rate; } __packed; struct wmi_vdev_create_cmd { @@ -4202,7 +4265,8 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar, int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt); int ath10k_wmi_pdev_resume_target(struct ath10k *ar); int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, - u16 rd5g, u16 ctl2g, u16 ctl5g); + u16 rd5g, u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg); int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value); int ath10k_wmi_cmd_init(struct ath10k *ar); int ath10k_wmi_start_scan(struct ath10k *ar, const struct wmi_start_scan_arg *); diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 1a2973b7acf250..0fce1c76638e9c 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -3709,8 +3709,8 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP), AR5K_TPC); } else { - ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX | - AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); + ath5k_hw_reg_write(ah, AR5K_TUNE_MAX_TXPOWER, + AR5K_PHY_TXPOWER_RATE_MAX); } return 0; diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index e39e5860a2e934..9c125ff083f73d 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig @@ -1,11 +1,19 @@ config ATH6KL tristate "Atheros mobile chipsets support" + depends on CFG80211 + ---help--- + This module adds core support for wireless adapters based on + Atheros AR6003 and AR6004 chipsets. You still need separate + bus drivers for USB and SDIO to be able to use real devices. + + If you choose to build it as a module, it will be called + ath6kl_core. Please note that AR6002 and AR6001 are not + supported by this driver. config ATH6KL_SDIO tristate "Atheros ath6kl SDIO support" depends on ATH6KL depends on MMC - depends on CFG80211 ---help--- This module adds support for wireless adapters based on Atheros AR6003 and AR6004 chipsets running over SDIO. If you @@ -17,25 +25,31 @@ config ATH6KL_USB tristate "Atheros ath6kl USB support" depends on ATH6KL depends on USB - depends on CFG80211 ---help--- This module adds support for wireless adapters based on - Atheros AR6004 chipset running over USB. This is still under - implementation and it isn't functional. If you choose to - build it as a module, it will be called ath6kl_usb. + Atheros AR6004 chipset and chipsets based on it running over + USB. If you choose to build it as a module, it will be + called ath6kl_usb. config ATH6KL_DEBUG bool "Atheros ath6kl debugging" depends on ATH6KL ---help--- - Enables debug support + Enables ath6kl debug support, including debug messages + enabled with debug_mask module parameter and debugfs + interface. + + If unsure, say Y to make it easier to debug problems. config ATH6KL_TRACING bool "Atheros ath6kl tracing support" depends on ATH6KL depends on EVENT_TRACING ---help--- - Select this to ath6kl use tracing infrastructure. + Select this to ath6kl use tracing infrastructure which, for + example, can be enabled with help of trace-cmd. All debug + messages and commands are delivered to using individually + enablable trace points. If unsure, say Y to make it easier to debug problems. @@ -47,3 +61,5 @@ config ATH6KL_REGDOMAIN Enabling this makes it possible to change the regdomain in the firmware. This can be only enabled if regulatory requirements are taken into account. + + If unsure, say N. diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index c2c6f460495859..09285084bcd3d0 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -724,8 +724,9 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to cfg80211\n", bssid); kfree(ie); - } else + } else { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n"); + } return bss; } @@ -970,7 +971,6 @@ static int ath6kl_set_probed_ssids(struct ath6kl *ar, ssid_list[i].flag, ssid_list[i].ssid.ssid_len, ssid_list[i].ssid.ssid); - } /* Make sure no old entries are left behind */ @@ -1897,7 +1897,6 @@ static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif, /* Configure the patterns that we received from the user. */ for (i = 0; i < wow->n_patterns; i++) { - /* * Convert given nl80211 specific mask value to equivalent * driver specific mask value and send it to the chip along @@ -2850,8 +2849,9 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, if (p.prwise_crypto_type == 0) { p.prwise_crypto_type = NONE_CRYPT; ath6kl_set_cipher(vif, 0, true); - } else if (info->crypto.n_ciphers_pairwise == 1) + } else if (info->crypto.n_ciphers_pairwise == 1) { ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true); + } switch (info->crypto.cipher_group) { case WLAN_CIPHER_SUITE_WEP40: @@ -2897,7 +2897,6 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, } if (info->inactivity_timeout) { - inactivity_timeout = info->inactivity_timeout; if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS) diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 4b46adbe8c923b..b0b6520427600a 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -45,9 +45,9 @@ module_param(testmode, uint, 0644); module_param(recovery_enable, uint, 0644); module_param(heart_beat_poll, uint, 0644); MODULE_PARM_DESC(recovery_enable, "Enable recovery from firmware error"); -MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic" \ - "polling. This also specifies the polling interval in" \ - "msecs. Set reocvery_enable for this to be effective"); +MODULE_PARM_DESC(heart_beat_poll, + "Enable fw error detection periodic polling in msecs - Also set recovery_enable for this to be effective"); + void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) { diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index dbfd17d0a5faa3..55c4064dd5067f 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -172,7 +172,6 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, struct ath6kl_irq_proc_registers *irq_proc_reg, struct ath6kl_irq_enable_reg *irq_enable_reg) { - ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n")); if (irq_proc_reg != NULL) { @@ -219,7 +218,6 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, "GMBOX lookahead alias 1: 0x%x\n", irq_proc_reg->rx_gmbox_lkahd_alias[1]); } - } if (irq_enable_reg != NULL) { @@ -1396,7 +1394,6 @@ static ssize_t ath6kl_create_qos_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct ath6kl *ar = file->private_data; struct ath6kl_vif *vif; char buf[200]; @@ -1575,7 +1572,6 @@ static ssize_t ath6kl_delete_qos_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct ath6kl *ar = file->private_data; struct ath6kl_vif *vif; char buf[100]; diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index ca9ba005f2871f..e194c10d9f0071 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -97,8 +97,8 @@ static inline void ath6kl_dump_registers(struct ath6kl_device *dev, struct ath6kl_irq_proc_registers *irq_proc_reg, struct ath6kl_irq_enable_reg *irq_en_reg) { - } + static inline void dump_cred_dist_stats(struct htc_target *target) { } diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index fea7709b5dda59..18c070850a09b8 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -37,7 +37,6 @@ static int ath6kl_hif_cp_scat_dma_buf(struct hif_scatter_req *req, buf = req->virt_dma_buf; for (i = 0; i < req->scat_entries; i++) { - if (from_dma) memcpy(req->scat_list[i].buf, buf, req->scat_list[i].len); @@ -116,7 +115,6 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar) le32_to_cpu(regdump_val[i + 2]), le32_to_cpu(regdump_val[i + 3])); } - } static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) @@ -701,5 +699,4 @@ int ath6kl_hif_setup(struct ath6kl_device *dev) fail_setup: return status; - } diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h index 61f6b21fb0aeea..dc6bd8cd9b837d 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.h +++ b/drivers/net/wireless/ath/ath6kl/hif.h @@ -197,9 +197,9 @@ struct hif_scatter_req { /* bounce buffer for upper layers to copy to/from */ u8 *virt_dma_buf; - struct hif_scatter_item scat_list[1]; - u32 scat_q_depth; + + struct hif_scatter_item scat_list[0]; }; struct ath6kl_irq_proc_registers { diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index 65e5b719093d47..e481f14b98787e 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -112,9 +112,9 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, if (cur_ep_dist->endpoint == ENDPOINT_0) continue; - if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) + if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) { cur_ep_dist->cred_norm = cur_ep_dist->cred_per_msg; - else { + } else { /* * For the remaining data endpoints, we assume that * each cred_per_msg are the same. We use a simple @@ -129,7 +129,6 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, count = (count * 3) >> 2; count = max(count, cur_ep_dist->cred_per_msg); cur_ep_dist->cred_norm = count; - } ath6kl_dbg(ATH6KL_DBG_CREDIT, @@ -549,7 +548,6 @@ static int htc_check_credits(struct htc_target *target, enum htc_endpoint_id eid, unsigned int len, int *req_cred) { - *req_cred = (len > target->tgt_cred_sz) ? DIV_ROUND_UP(len, target->tgt_cred_sz) : 1; @@ -608,7 +606,6 @@ static void ath6kl_htc_tx_pkts_get(struct htc_target *target, unsigned int len; while (true) { - flags = 0; if (list_empty(&endpoint->txq)) @@ -889,7 +886,6 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, ac = target->dev->ar->ep2ac_map[endpoint->eid]; while (true) { - if (list_empty(&endpoint->txq)) break; @@ -1190,7 +1186,6 @@ static void ath6kl_htc_mbox_flush_txep(struct htc_target *target, list_add_tail(&packet->list, &container); htc_tx_complete(endpoint, &container); } - } static void ath6kl_htc_flush_txep_all(struct htc_target *target) @@ -1394,7 +1389,6 @@ static int ath6kl_htc_rx_setup(struct htc_target *target, ep_cb = ep->ep_cb; for (j = 0; j < n_msg; j++) { - /* * Reset flag, any packets allocated using the * rx_alloc() API cannot be recycled on @@ -1424,9 +1418,9 @@ static int ath6kl_htc_rx_setup(struct htc_target *target, } } - if (list_empty(&ep->rx_bufq)) + if (list_empty(&ep->rx_bufq)) { packet = NULL; - else { + } else { packet = list_first_entry(&ep->rx_bufq, struct htc_packet, list); list_del(&packet->list); @@ -1487,7 +1481,6 @@ static int ath6kl_htc_rx_alloc(struct htc_target *target, spin_lock_bh(&target->rx_lock); for (i = 0; i < msg; i++) { - htc_hdr = (struct htc_frame_hdr *)&lk_ahds[i]; if (htc_hdr->eid >= ENDPOINT_MAX) { @@ -1708,7 +1701,6 @@ static int htc_parse_trailer(struct htc_target *target, lk_ahd = (struct htc_lookahead_report *) record_buf; if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) && next_lk_ahds) { - ath6kl_dbg(ATH6KL_DBG_HTC, "htc rx lk_ahd found pre_valid 0x%x post_valid 0x%x\n", lk_ahd->pre_valid, lk_ahd->post_valid); @@ -1755,7 +1747,6 @@ static int htc_parse_trailer(struct htc_target *target, } return 0; - } static int htc_proc_trailer(struct htc_target *target, @@ -1776,7 +1767,6 @@ static int htc_proc_trailer(struct htc_target *target, status = 0; while (len > 0) { - if (len < sizeof(struct htc_record_hdr)) { status = -ENOMEM; break; @@ -2098,7 +2088,6 @@ static int ath6kl_htc_rx_fetch(struct htc_target *target, } if (!fetched_pkts) { - packet = list_first_entry(rx_pktq, struct htc_packet, list); @@ -2173,7 +2162,6 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, look_aheads[0] = msg_look_ahead; while (true) { - /* * First lookahead sets the expected endpoint IDs for all * packets in a bundle. @@ -2825,8 +2813,9 @@ static int ath6kl_htc_reset(struct htc_target *target) packet->buf = packet->buf_start; packet->endpoint = ENDPOINT_0; list_add_tail(&packet->list, &target->free_ctrl_rxbuf); - } else + } else { list_add_tail(&packet->list, &target->free_ctrl_txbuf); + } } return 0; diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index 67aa924ed8b317..756fe52a12c8ad 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -137,7 +137,6 @@ static void get_htc_packet_credit_based(struct htc_target *target, credits_required = 0; } else { - if (ep->cred_dist.credits < credits_required) break; @@ -169,7 +168,6 @@ static void get_htc_packet_credit_based(struct htc_target *target, /* queue this packet into the caller's queue */ list_add_tail(&packet->list, queue); } - } static void get_htc_packet(struct htc_target *target, @@ -279,7 +277,6 @@ static int htc_issue_packets(struct htc_target *target, list_add(&packet->list, pkt_queue); break; } - } if (status != 0) { @@ -385,7 +382,6 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, */ list_for_each_entry_safe(packet, tmp_pkt, txq, list) { - ath6kl_dbg(ATH6KL_DBG_HTC, "%s: Indicat overflowed TX pkts: %p\n", __func__, packet); @@ -403,7 +399,6 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, list_move_tail(&packet->list, &send_queue); } - } if (list_empty(&send_queue)) { @@ -454,7 +449,6 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, * enough transmit resources. */ while (true) { - if (get_queue_depth(&ep->txq) == 0) break; @@ -495,8 +489,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, } spin_lock_bh(&target->tx_lock); - } + /* done with this endpoint, we can clear the count */ ep->tx_proc_cnt = 0; spin_unlock_bh(&target->tx_lock); @@ -1106,7 +1100,6 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, dev_kfree_skb(skb); return status; - } static void htc_flush_rx_queue(struct htc_target *target, @@ -1258,7 +1251,6 @@ static int ath6kl_htc_pipe_conn_service(struct htc_target *target, tx_alloc = 0; } else { - tx_alloc = htc_get_credit_alloc(target, conn_req->svc_id); if (tx_alloc == 0) { status = -ENOMEM; diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 4f316bdcbab58d..d5ef211f261c2c 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1192,7 +1192,6 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) if (board_ext_address && ar->fw_board_len == (board_data_size + board_ext_data_size)) { - /* write extended board data */ ath6kl_dbg(ATH6KL_DBG_BOOT, "writing extended board data to 0x%x (%d B)\n", diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 5839fc23bdc789..d56554674da479 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -571,7 +571,6 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status) static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) { - struct ath6kl *ar = vif->ar; vif->profile.ch = cpu_to_le16(channel); @@ -600,7 +599,6 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel) { - struct ath6kl_vif *vif; int res = 0; @@ -692,9 +690,9 @@ void ath6kl_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid, bool ismcast) cfg80211_michael_mic_failure(vif->ndev, sta->mac, NL80211_KEYTYPE_PAIRWISE, keyid, tsc, GFP_KERNEL); - } else + } else { ath6kl_cfg80211_tkip_micerr_event(vif, keyid, ismcast); - + } } static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) @@ -1093,8 +1091,9 @@ static int ath6kl_open(struct net_device *dev) if (test_bit(CONNECTED, &vif->flags)) { netif_carrier_on(dev); netif_wake_queue(dev); - } else + } else { netif_carrier_off(dev); + } return 0; } @@ -1146,7 +1145,6 @@ static int ath6kl_set_features(struct net_device *dev, dev->features = features | NETIF_F_RXCSUM; return err; } - } return err; diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 7126bdd4236c2b..339d89f14d32b1 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -348,7 +348,7 @@ static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio, int i, scat_req_sz, scat_list_sz, size; u8 *virt_buf; - scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item); + scat_list_sz = n_scat_entry * sizeof(struct hif_scatter_item); scat_req_sz = sizeof(*s_req) + scat_list_sz; if (!virt_scat) @@ -425,8 +425,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, memcpy(tbuf, buf, len); bounced = true; - } else + } else { tbuf = buf; + } ret = ath6kl_sdio_io(ar_sdio->func, request, addr, tbuf, len); if ((request & HIF_READ) && bounced) @@ -441,9 +442,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, static void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio, struct bus_request *req) { - if (req->scat_req) + if (req->scat_req) { ath6kl_sdio_scat_rw(ar_sdio, req); - else { + } else { void *context; int status; @@ -656,7 +657,6 @@ static void ath6kl_sdio_scatter_req_add(struct ath6kl *ar, list_add_tail(&s_req->list, &ar_sdio->scat_req); spin_unlock_bh(&ar_sdio->scat_lock); - } /* scatter gather read write request */ @@ -674,9 +674,9 @@ static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar, "hif-scatter: total len: %d scatter entries: %d\n", scat_req->len, scat_req->scat_entries); - if (request & HIF_SYNCHRONOUS) + if (request & HIF_SYNCHRONOUS) { status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest); - else { + } else { spin_lock_bh(&ar_sdio->wr_async_lock); list_add_tail(&scat_req->busrequest->list, &ar_sdio->wr_asyncq); spin_unlock_bh(&ar_sdio->wr_async_lock); @@ -856,7 +856,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (ar->suspend_mode == WLAN_POWER_STATE_WOW || (!ar->suspend_mode && wow)) { - ret = ath6kl_set_sdio_pm_caps(ar); if (ret) goto cut_pwr; @@ -878,7 +877,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP || !ar->suspend_mode || try_deepsleep) { - flags = sdio_get_host_pm_caps(func); if (!(flags & MMC_PM_KEEP_POWER)) goto cut_pwr; @@ -1061,7 +1059,6 @@ static int ath6kl_sdio_bmi_credits(struct ath6kl *ar) timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) { - /* * Hit the credit counter with a 4-byte access, the first byte * read will hit the counter and cause a decrement, while the diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h index a580a629a0da6b..d5eeeae7711b25 100644 --- a/drivers/net/wireless/ath/ath6kl/target.h +++ b/drivers/net/wireless/ath/ath6kl/target.h @@ -289,7 +289,7 @@ struct host_interest { u32 hi_hp_rx_traffic_ratio; /* 0xd8 */ /* test applications flags */ - u32 hi_test_apps_related ; /* 0xdc */ + u32 hi_test_apps_related; /* 0xdc */ /* location of test script */ u32 hi_ota_testscript; /* 0xe0 */ /* location of CAL data */ diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index ebb24045a8ae6c..40432fe7a5d2cc 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -125,8 +125,9 @@ static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn, *flags |= WMI_DATA_HDR_FLAGS_UAPSD; spin_unlock_bh(&conn->psq_lock); return false; - } else if (!conn->apsd_info) + } else if (!conn->apsd_info) { return false; + } if (test_bit(WMM_ENABLED, &vif->flags)) { ether_type = be16_to_cpu(datap->h_proto); @@ -316,8 +317,9 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, cookie = NULL; ath6kl_err("wmi ctrl ep full, dropping pkt : 0x%p, len:%d\n", skb, skb->len); - } else + } else { cookie = ath6kl_alloc_cookie(ar); + } if (cookie == NULL) { spin_unlock_bh(&ar->lock); @@ -359,7 +361,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) struct ath6kl_vif *vif = netdev_priv(dev); u32 map_no = 0; u16 htc_tag = ATH6KL_DATA_PKT_TAG; - u8 ac = 99 ; /* initialize to unmapped ac */ + u8 ac = 99; /* initialize to unmapped ac */ bool chk_adhoc_ps_mapping = false; int ret; struct wmi_tx_meta_v2 meta_v2; @@ -449,8 +451,9 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) if (ret) goto fail_tx; } - } else + } else { goto fail_tx; + } spin_lock_bh(&ar->lock); @@ -702,7 +705,6 @@ void ath6kl_tx_complete(struct htc_target *target, /* reap completed packets */ while (!list_empty(packet_queue)) { - packet = list_first_entry(packet_queue, struct htc_packet, list); list_del(&packet->list); @@ -1089,8 +1091,9 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid, else skb_queue_tail(&rxtid->q, node->skb); node->skb = NULL; - } else + } else { stats->num_hole++; + } rxtid->seq_next = ATH6KL_NEXT_SEQ_NO(rxtid->seq_next); idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); @@ -1211,7 +1214,7 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid, return is_queued; spin_lock_bh(&rxtid->lock); - for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { + for (idx = 0; idx < rxtid->hold_q_sz; idx++) { if (rxtid->hold_q[idx].skb) { /* * There is a frame in the queue and no @@ -1265,7 +1268,6 @@ static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif, is_apsdq_empty_at_start = is_apsdq_empty; while ((!is_apsdq_empty) && (num_frames_to_deliver)) { - spin_lock_bh(&conn->psq_lock); skb = skb_dequeue(&conn->apsdq); is_apsdq_empty = skb_queue_empty(&conn->apsdq); @@ -1606,16 +1608,18 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) if (!conn) return; aggr_conn = conn->aggr_conn; - } else + } else { aggr_conn = vif->aggr_cntxt->aggr_conn; + } if (aggr_process_recv_frm(aggr_conn, tid, seq_no, is_amsdu, skb)) { /* aggregation code will handle the skb */ return; } - } else if (!is_broadcast_ether_addr(datap->h_dest)) + } else if (!is_broadcast_ether_addr(datap->h_dest)) { vif->net_stats.multicast++; + } ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb); } @@ -1710,8 +1714,9 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no, sta = ath6kl_find_sta_by_aid(vif->ar, aid); if (sta) aggr_conn = sta->aggr_conn; - } else + } else { aggr_conn = vif->aggr_cntxt->aggr_conn; + } if (!aggr_conn) return; @@ -1766,7 +1771,6 @@ void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info, skb_queue_head_init(&rxtid->q); spin_lock_init(&rxtid->lock); } - } struct aggr_info *aggr_init(struct ath6kl_vif *vif) @@ -1806,8 +1810,9 @@ void aggr_recv_delba_req_evt(struct ath6kl_vif *vif, u8 tid_mux) sta = ath6kl_find_sta_by_aid(vif->ar, aid); if (sta) aggr_conn = sta->aggr_conn; - } else + } else { aggr_conn = vif->aggr_cntxt->aggr_conn; + } if (!aggr_conn) return; diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 56c3fd5cef65a0..3afc5a463d06f8 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -236,7 +236,6 @@ static void ath6kl_usb_free_pipe_resources(struct ath6kl_usb_pipe *pipe) break; kfree(urb_context); } - } static void ath6kl_usb_cleanup_pipe_resources(struct ath6kl_usb *ar_usb) @@ -245,7 +244,6 @@ static void ath6kl_usb_cleanup_pipe_resources(struct ath6kl_usb *ar_usb) for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++) ath6kl_usb_free_pipe_resources(&ar_usb->pipes[i]); - } static u8 ath6kl_usb_get_logical_pipe_num(struct ath6kl_usb *ar_usb, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 8b4ce28e3ce8f5..0c0e1e36e40fe7 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -289,8 +289,9 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx, ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) + sizeof(struct ath6kl_llc_snap_hdr), layer2_priority); - } else + } else { usr_pri = layer2_priority & 0x7; + } /* * Queue the EAPOL frames in the same WMM_AC_VO queue @@ -359,8 +360,9 @@ int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb) hdr_size = roundup(sizeof(struct ieee80211_qos_hdr), sizeof(u32)); skb_pull(skb, hdr_size); - } else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA)) + } else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA)) { skb_pull(skb, sizeof(struct ieee80211_hdr_3addr)); + } datap = skb->data; llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap); @@ -936,7 +938,6 @@ ath6kl_regd_find_country_by_rd(u16 regdmn) static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) { - struct ath6kl_wmi_regdomain *ev; struct country_code_to_enum_rd *country = NULL; struct reg_dmn_pair_mapping *regpair = NULL; @@ -946,10 +947,9 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) ev = (struct ath6kl_wmi_regdomain *) datap; reg_code = le32_to_cpu(ev->reg_code); - if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) + if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) { country = ath6kl_regd_find_country((u16) reg_code); - else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) { - + } else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) { regpair = ath6kl_get_regpair((u16) reg_code); country = ath6kl_regd_find_country_by_rd((u16) reg_code); if (regpair) @@ -1499,7 +1499,6 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len, if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) && (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) { - ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion); tsinfo = le16_to_cpu(ts->tsinfo); tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) & @@ -1530,7 +1529,6 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len, * for delete qos stream from AP */ else if (reply->cac_indication == CAC_INDICATION_DELETE) { - ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion); tsinfo = le16_to_cpu(ts->tsinfo); ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) & @@ -2479,7 +2477,6 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) goto free_data_skb; for (index = 0; index < num_pri_streams; index++) { - if (WARN_ON(!data_sync_bufs[index].skb)) goto free_data_skb; @@ -2704,7 +2701,6 @@ static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi) for (i = 0; i < WMM_NUM_AC; i++) { if (stream_exist & (1 << i)) { - /* * FIXME: Is this lock & unlock inside * for loop correct? may need rework. @@ -2870,8 +2866,9 @@ int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx, if (host_mode == ATH6KL_HOST_MODE_ASLEEP) { ath6kl_wmi_relinquish_implicit_pstream_credits(wmi); cmd->asleep = cpu_to_le32(1); - } else + } else { cmd->awake = cpu_to_le32(1); + } ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_HOST_SLEEP_MODE_CMDID, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index b5f226503baf7e..d9115cac4885e9 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -898,7 +898,6 @@ struct wmi_start_scan_cmd { * flags here */ enum wmi_scan_ctrl_flags_bits { - /* set if can scan in the connect cmd */ CONNECT_SCAN_CTRL_FLAGS = 0x01, @@ -1068,7 +1067,7 @@ struct wmi_power_mode_cmd { } __packed; /* - * Policy to determnine whether power save failure event should be sent to + * Policy to determine whether power save failure event should be sent to * host during scanning */ enum power_save_fail_event_policy { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 0a6163e9248c0f..c38399bc9aa96e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -410,7 +410,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009e54, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h index f76139bbb74f0f..2c42ff05efa38f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h @@ -592,7 +592,7 @@ static const u32 ar9331_1p1_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009fc0, 0x803e4788}, diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h index 0ac8be96097f2e..2154efcd390051 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h @@ -231,7 +231,7 @@ static const u32 ar9331_1p2_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009fc0, 0x803e4788}, diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h index a01f0edb65182a..b995ffe88b33bb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -318,7 +318,7 @@ static const u32 ar9340_1p0_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009e54, 0x00000000}, @@ -348,9 +348,9 @@ static const u32 ar9340_1p0_baseband_core[][2] = { {0x0000a370, 0x00000000}, {0x0000a390, 0x00000001}, {0x0000a394, 0x00000444}, - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x210d0401}, - {0x0000a3a0, 0xab9a7144}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, {0x0000a3a4, 0x00000000}, {0x0000a3a8, 0xaaaaaaaa}, {0x0000a3ac, 0x3c466478}, diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h index 3c9113d9b1bc3c..8e5c3b9786e3ac 100644 --- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h @@ -257,9 +257,9 @@ static const u32 qca953x_1p0_baseband_core[][2] = { {0x0000a370, 0x00000000}, {0x0000a390, 0x00000001}, {0x0000a394, 0x00000444}, - {0x0000a398, 0x1f020503}, - {0x0000a39c, 0x29180c03}, - {0x0000a3a0, 0x9a8b6844}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, {0x0000a3a4, 0x000000ff}, {0x0000a3a8, 0x6a6a6a6a}, {0x0000a3ac, 0x6a6a6a6a}, diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index e6aec2c0207ff4..a5ca65240af30b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -90,7 +90,7 @@ static const u32 ar9580_1p0_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009e54, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3ba03dde42150b..33a2ae77b59514 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -114,6 +114,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_TXFIFO_DEPTH 8 #define ATH_TX_ERROR 0x01 +/* Stop tx traffic 1ms before the GO goes away */ +#define ATH_P2P_PS_STOP_TIME 1000 + #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_MAX 4096 #define IEEE80211_WEP_IVLEN 3 @@ -366,11 +369,15 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, /********/ struct ath_vif { + struct ieee80211_vif *vif; struct ath_node mcast_node; int av_bslot; bool primary_sta_vif; __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ struct ath_buf *av_bcbuf; + + /* P2P Client */ + struct ieee80211_noa_data noa; }; struct ath9k_vif_iter_data { @@ -463,6 +470,8 @@ int ath_update_survey_stats(struct ath_softc *sc); void ath_update_survey_nf(struct ath_softc *sc, int channel); void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); void ath_ps_full_sleep(unsigned long data); +void ath9k_p2p_ps_timer(void *priv); +void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif); /**********/ /* BTCOEX */ @@ -713,6 +722,9 @@ struct ath_softc { struct completion paprd_complete; wait_queue_head_t tx_wait; + struct ath_gen_timer *p2p_ps_timer; + struct ath_vif *p2p_ps_vif; + unsigned long driver_data; u8 gtt_cnt; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index bd9e634879e69d..e387f0b2954a0c 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -537,8 +537,6 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, cur_conf->dtim_period = bss_conf->dtim_period; cur_conf->dtim_count = 1; cur_conf->ibss_creator = bss_conf->ibss_creator; - cur_conf->bmiss_timeout = - ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; /* * It looks like mac80211 may end up using beacon interval of zero in @@ -549,6 +547,9 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, if (cur_conf->beacon_interval == 0) cur_conf->beacon_interval = 100; + cur_conf->bmiss_timeout = + ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; + /* * We don't parse dtim period from mac80211 during the driver * initialization as it breaks association with hidden-ssid diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c8a9dfab1fee2e..dffefee60f2213 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -246,6 +246,8 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) return; case AR9300_DEVID_AR953X: ah->hw_version.macVersion = AR_SREV_VERSION_9531; + if (ah->get_mac_revision) + ah->hw_version.macRev = ah->get_mac_revision(); return; } diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 36ae6490e5543a..1af77081181e12 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -508,7 +508,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, sc->tx99_power = MAX_RATE_POWER + 1; init_waitqueue_head(&sc->tx_wait); - if (!pdata) { + if (!pdata || pdata->use_eeprom) { ah->ah_flags |= AH_USE_EEPROM; sc->sc_ah->led_pin = -1; } else { @@ -589,6 +589,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, if (ret) goto err_btcoex; + sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer, + NULL, sc, AR_FIRST_NDP_TIMER); + ath9k_cmn_init_crypto(sc->sc_ah); ath9k_init_misc(sc); ath_fill_led_pin(sc); @@ -644,13 +647,13 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc) static const struct ieee80211_iface_limit if_limits[] = { { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_WDS) }, { .max = 8, .types = #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif - BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_AP) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) }, }; @@ -711,7 +714,8 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) hw->flags |= IEEE80211_HW_MFP_CAPABLE; - hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; + hw->wiphy->features |= (NL80211_FEATURE_ACTIVE_MONITOR | + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE); if (!config_enabled(CONFIG_ATH9K_TX99)) { hw->wiphy->interface_modes = @@ -855,6 +859,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc) { int i = 0; + if (sc->p2p_ps_timer) + ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer); + ath9k_deinit_btcoex(sc); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d69853b848ce1f..8d7b9b66fefa59 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -261,6 +261,8 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) sc->gtt_cnt = 0; ieee80211_wake_queues(sc->hw); + ath9k_p2p_ps_timer(sc); + return true; } @@ -1119,6 +1121,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); + avp->vif = vif; + an->sc = sc; an->sta = NULL; an->vif = vif; @@ -1163,6 +1167,29 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, return 0; } +static void +ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp) +{ + struct ath_hw *ah = sc->sc_ah; + s32 tsf, target_tsf; + + if (!avp || !avp->noa.has_next_tsf) + return; + + ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer); + + tsf = ath9k_hw_gettsf32(sc->sc_ah); + + target_tsf = avp->noa.next_tsf; + if (!avp->noa.absent) + target_tsf -= ATH_P2P_PS_STOP_TIME; + + if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME) + target_tsf = tsf + ATH_P2P_PS_STOP_TIME; + + ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000); +} + static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -1174,6 +1201,13 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); + spin_lock_bh(&sc->sc_pcu_lock); + if (avp == sc->p2p_ps_vif) { + sc->p2p_ps_vif = NULL; + ath9k_update_p2p_ps_timer(sc, NULL); + } + spin_unlock_bh(&sc->sc_pcu_lock); + sc->nvifs--; sc->tx99_vif = NULL; @@ -1636,6 +1670,72 @@ static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif) ath9k_set_assoc_state(sc, vif); } +void ath9k_p2p_ps_timer(void *priv) +{ + struct ath_softc *sc = priv; + struct ath_vif *avp = sc->p2p_ps_vif; + struct ieee80211_vif *vif; + struct ieee80211_sta *sta; + struct ath_node *an; + u32 tsf; + + if (!avp) + return; + + tsf = ath9k_hw_gettsf32(sc->sc_ah); + if (!avp->noa.absent) + tsf += ATH_P2P_PS_STOP_TIME; + + if (!avp->noa.has_next_tsf || + avp->noa.next_tsf - tsf > BIT(31)) + ieee80211_update_p2p_noa(&avp->noa, tsf); + + ath9k_update_p2p_ps_timer(sc, avp); + + rcu_read_lock(); + + vif = avp->vif; + sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); + if (!sta) + goto out; + + an = (void *) sta->drv_priv; + if (an->sleeping == !!avp->noa.absent) + goto out; + + an->sleeping = avp->noa.absent; + if (an->sleeping) + ath_tx_aggr_sleep(sta, sc, an); + else + ath_tx_aggr_wakeup(sc, an); + +out: + rcu_read_unlock(); +} + +void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_vif *avp = (void *)vif->drv_priv; + unsigned long flags; + u32 tsf; + + if (!sc->p2p_ps_timer) + return; + + if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p) + return; + + sc->p2p_ps_vif = avp; + + spin_lock_irqsave(&sc->sc_pm_lock, flags); + if (!(sc->ps_flags & PS_BEACON_SYNC)) { + tsf = ath9k_hw_gettsf32(sc->sc_ah); + ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf); + ath9k_update_p2p_ps_timer(sc, avp); + } + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); +} + static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1710,6 +1810,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } } + if (changed & BSS_CHANGED_P2P_PS) { + spin_lock_bh(&sc->sc_pcu_lock); + ath9k_update_p2p_ps(sc, vif); + spin_unlock_bh(&sc->sc_pcu_lock); + } + if (changed & CHECK_ANI) ath_check_ani(sc); @@ -1883,7 +1989,8 @@ static bool ath9k_has_tx_pending(struct ath_softc *sc) return !!npend; } -static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 19df969ec90932..43ae199601f7ad 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -538,7 +538,10 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, PS, "Reconfigure beacon timers based on synchronized timestamp\n"); - ath9k_set_beacon(sc); + if (!(WARN_ON_ONCE(sc->cur_beacon_conf.beacon_interval == 0))) + ath9k_set_beacon(sc); + if (sc->p2p_ps_vif) + ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif); } if (ath_beacon_dtim_pending_cab(skb)) { diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 4c8cdb097b6599..f8ded84b7be8c5 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1707,7 +1707,9 @@ static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx, return 0; } -static void carl9170_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void carl9170_op_flush(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 queues, bool drop) { struct ar9170 *ar = hw->priv; unsigned int vid; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 5824cd41e4bac6..73593aa3cd9813 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -338,7 +338,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) } if (isr) - wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr); + wil_dbg_irq(wil, "un-handled MISC ISR bits 0x%08x\n", isr); wil->isr_misc = 0; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 95f4efe9ef37c6..1b265fd19de260 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -363,8 +363,8 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil) wil_err(wil, "Firmware not ready\n"); return -ETIME; } else { - wil_dbg_misc(wil, "FW ready after %d ms\n", - jiffies_to_msecs(to-left)); + wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n", + jiffies_to_msecs(to-left), wil->hw_version); } return 0; } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index f1e1bb338d681e..0660884183070d 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -74,8 +74,6 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) if (rc) goto release_irq; - wil_info(wil, "HW version: 0x%08x\n", wil->hw_version); - return 0; release_irq: diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index d04629fe053f5e..ec29954bd44dd1 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -91,6 +91,22 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) spin_lock(&r->reorder_lock); + /** Due to the race between WMI events, where BACK establishment + * reported, and data Rx, few packets may be pass up before reorder + * buffer get allocated. Catch up by pretending SSN is what we + * see in the 1-st Rx packet + */ + if (r->first_time) { + r->first_time = false; + if (seq != r->head_seq_num) { + wil_err(wil, "Error: 1-st frame with wrong sequence" + " %d, should be %d. Fixing...\n", seq, + r->head_seq_num); + r->head_seq_num = seq; + r->ssn = seq; + } + } + /* frame with out of date sequence number */ if (seq_less(seq, r->head_seq_num)) { dev_kfree_skb(skb); @@ -162,6 +178,7 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, r->head_seq_num = ssn; r->buf_size = size; r->stored_mpdu_num = 0; + r->first_time = true; return r; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 2a2dec75f02606..d3b8659ca32e17 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -35,7 +35,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MEM_SIZE (2*1024*1024UL) #define WIL6210_RX_RING_SIZE (128) -#define WIL6210_TX_RING_SIZE (128) +#define WIL6210_TX_RING_SIZE (512) #define WIL6210_MAX_TX_RINGS (24) /* HW limit */ #define WIL6210_MAX_CID (8) /* HW limit */ #define WIL6210_NAPI_BUDGET (16) /* arbitrary */ @@ -301,6 +301,7 @@ struct wil_tid_ampdu_rx { u16 buf_size; u16 timeout; u8 dialog_token; + bool first_time; /* is it 1-st time this buffer used? */ }; struct wil6210_stats { diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 2ba56eef0c457d..e9a11cb3428ad1 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -192,7 +192,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) might_sleep(); if (!test_bit(wil_status_fwready, &wil->status)) { - wil_err(wil, "FW not ready\n"); + wil_err(wil, "WMI: cannot send command while FW not ready\n"); return -EAGAIN; } @@ -276,8 +276,8 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) wil->fw_version = le32_to_cpu(evt->sw_version); wil->n_mids = evt->numof_additional_mids; - wil_dbg_wmi(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version, - evt->mac, wil->n_mids); + wil_info(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version, + evt->mac, wil->n_mids); if (!is_valid_ether_addr(ndev->dev_addr)) { memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); @@ -290,7 +290,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, int len) { - wil_dbg_wmi(wil, "WMI: FW ready\n"); + wil_dbg_wmi(wil, "WMI: got FW ready event\n"); set_bit(wil_status_fwready, &wil->status); /* reuse wmi_ready for the firmware ready indication */ @@ -348,7 +348,7 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, { if (wil->scan_request) { struct wmi_scan_complete_event *data = d; - bool aborted = (data->status != 0); + bool aborted = (data->status != WMI_SCAN_SUCCESS); wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); cfg80211_scan_done(wil->scan_request, aborted); @@ -802,6 +802,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) .network_type = wmi_nettype, .disable_sec_offload = 1, .channel = chan - 1, + .pcp_max_assoc_sta = WIL6210_MAX_CID, }; struct { struct wil6210_mbox_hdr_wmi wmi; diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 50b8528394f405..17334c852866c3 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -28,7 +28,7 @@ #define __WILOCITY_WMI_H__ /* General */ - +#define WILOCITY_MAX_ASSOC_STA (8) #define WMI_MAC_LEN (6) #define WMI_PROX_RANGE_NUM (3) @@ -219,15 +219,6 @@ struct wmi_disconnect_sta_cmd { __le16 disconnect_reason; } __packed; -/* - * WMI_RECONNECT_CMDID - */ -struct wmi_reconnect_cmd { - u8 channel; /* hint */ - u8 reserved; - u8 bssid[WMI_MAC_LEN]; /* mandatory if set */ -} __packed; - /* * WMI_SET_PMK_CMDID @@ -296,11 +287,13 @@ enum wmi_scan_type { WMI_LONG_SCAN = 0, WMI_SHORT_SCAN = 1, WMI_PBC_SCAN = 2, + WMI_ACTIVE_SCAN = 3, + WMI_DIRECT_SCAN = 4, }; struct wmi_start_scan_cmd { - u8 reserved[8]; - + u8 direct_scan_mac_addr[6]; + u8 reserved[2]; __le32 home_dwell_time; /* Max duration in the home channel(ms) */ __le32 force_scan_interval; /* Time interval between scans (ms)*/ u8 scan_type; /* wmi_scan_type */ @@ -332,6 +325,7 @@ struct wmi_probed_ssid_cmd { u8 ssid[WMI_MAX_SSID_LEN]; } __packed; + /* * WMI_SET_APPIE_CMDID * Add Application specified IE to a management frame @@ -427,7 +421,7 @@ struct wmi_bcon_ctrl_cmd { __le16 frag_num; __le64 ss_mask; u8 network_type; - u8 reserved; + u8 pcp_max_assoc_sta; u8 disable_sec_offload; u8 disable_sec; } __packed; @@ -450,7 +444,7 @@ enum wmi_port_role { struct wmi_port_allocate_cmd { u8 mac[WMI_MAC_LEN]; u8 port_role; - u8 midid; + u8 mid; } __packed; /* @@ -467,6 +461,7 @@ struct wmi_delete_port_cmd { enum wmi_discovery_mode { WMI_DISCOVERY_MODE_NON_OFFLOAD = 0, WMI_DISCOVERY_MODE_OFFLOAD = 1, + WMI_DISCOVERY_MODE_PEER2PEER = 2, }; struct wmi_p2p_cfg_cmd { @@ -493,7 +488,8 @@ struct wmi_power_mgmt_cfg_cmd { */ struct wmi_pcp_start_cmd { __le16 bcon_interval; - u8 reserved0[10]; + u8 pcp_max_assoc_sta; + u8 reserved0[9]; u8 network_type; u8 channel; u8 disable_sec_offload; @@ -857,6 +853,7 @@ enum wmi_event_id { WMI_RF_MGMT_STATUS_EVENTID = 0x1853, WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, WMI_RX_MGMT_PACKET_EVENTID = 0x1840, + WMI_TX_MGMT_PACKET_EVENTID = 0x1841, /* Performance monitoring events */ WMI_DATA_PORT_OPEN_EVENTID = 0x1860, @@ -1040,16 +1037,23 @@ enum wmi_disconnect_reason { struct wmi_disconnect_event { __le16 protocol_reason_status; /* reason code, see 802.11 spec. */ u8 bssid[WMI_MAC_LEN]; /* set if known */ - u8 disconnect_reason; /* see wmi_disconnect_reason_e */ - u8 assoc_resp_len; - u8 assoc_info[0]; + u8 disconnect_reason; /* see wmi_disconnect_reason */ + u8 assoc_resp_len; /* not in use */ + u8 assoc_info[0]; /* not in use */ } __packed; /* * WMI_SCAN_COMPLETE_EVENTID */ +enum scan_status { + WMI_SCAN_SUCCESS = 0, + WMI_SCAN_FAILED = 1, + WMI_SCAN_ABORTED = 2, + WMI_SCAN_REJECTED = 3, +}; + struct wmi_scan_complete_event { - __le32 status; + __le32 status; /* scan_status */ } __packed; /* @@ -1256,6 +1260,14 @@ struct wmi_rx_mgmt_info { u8 channel; /* From Radio MNGR */ } __packed; + +/* + * WMI_TX_MGMT_PACKET_EVENTID + */ +struct wmi_tx_mgmt_packet_event { + u8 payload[0]; +} __packed; + struct wmi_rx_mgmt_packet_event { struct wmi_rx_mgmt_info info; u8 payload[0]; diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 54376fddfaf9f1..4113b693476403 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -915,10 +915,6 @@ struct b43_wl { char rng_name[30 + 1]; #endif /* CONFIG_B43_HWRNG */ - /* List of all wireless devices on this chip */ - struct list_head devlist; - u8 nr_devs; - bool radiotap_enabled; bool radio_enabled; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 69fc3d65531a7e..32e08d35c06e13 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1195,8 +1195,13 @@ static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode) B43_BCMA_CLKCTLST_PHY_PLL_REQ; u32 status = B43_BCMA_CLKCTLST_80211_PLL_ST | B43_BCMA_CLKCTLST_PHY_PLL_ST; + u32 flags; + + flags = B43_BCMA_IOCTL_PHY_CLKEN; + if (gmode) + flags |= B43_BCMA_IOCTL_GMODE; + b43_device_enable(dev, flags); - b43_device_enable(dev, B43_BCMA_IOCTL_PHY_CLKEN); bcma_core_set_clockmode(dev->dev->bdev, BCMA_CLKMODE_FAST); b43_bcma_phy_reset(dev); bcma_core_pll_ctl(dev->dev->bdev, req, status, true); @@ -3735,40 +3740,35 @@ static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan) { struct b43_wldev *up_dev = NULL; struct b43_wldev *down_dev; - struct b43_wldev *d; int err; bool uninitialized_var(gmode); int prev_status; /* Find a device and PHY which supports the band. */ - list_for_each_entry(d, &wl->devlist, list) { - switch (chan->band) { - case IEEE80211_BAND_5GHZ: - if (d->phy.supports_5ghz) { - up_dev = d; - gmode = false; - } - break; - case IEEE80211_BAND_2GHZ: - if (d->phy.supports_2ghz) { - up_dev = d; - gmode = true; - } - break; - default: - B43_WARN_ON(1); - return -EINVAL; + switch (chan->band) { + case IEEE80211_BAND_5GHZ: + if (wl->current_dev->phy.supports_5ghz) { + up_dev = wl->current_dev; + gmode = false; } - if (up_dev) - break; + break; + case IEEE80211_BAND_2GHZ: + if (wl->current_dev->phy.supports_2ghz) { + up_dev = wl->current_dev; + gmode = true; + } + break; + default: + B43_WARN_ON(1); + return -EINVAL; } + if (!up_dev) { b43err(wl, "Could not find a device for %s-GHz band operation\n", band_to_string(chan->band)); return -ENODEV; } - if ((up_dev == wl->current_dev) && - (!!wl->current_dev->phy.gmode == !!gmode)) { + if (!!wl->current_dev->phy.gmode == !!gmode) { /* This device is already running. */ return 0; } @@ -5178,7 +5178,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) } dev->phy.gmode = have_2ghz_phy; - dev->phy.radio_on = true; b43_wireless_core_reset(dev, dev->phy.gmode); err = b43_phy_versioning(dev); @@ -5270,7 +5269,6 @@ static void b43_one_core_detach(struct b43_bus_dev *dev) b43_debugfs_remove_device(wldev); b43_wireless_core_detach(wldev); list_del(&wldev->list); - wl->nr_devs--; b43_bus_set_wldev(dev, NULL); kfree(wldev); } @@ -5295,8 +5293,6 @@ static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl) if (err) goto err_kfree_wldev; - list_add(&wldev->list, &wl->devlist); - wl->nr_devs++; b43_bus_set_wldev(dev, wldev); b43_debugfs_add_device(wldev); @@ -5386,7 +5382,6 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) wl->hw = hw; 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); INIT_WORK(&wl->tx_work, b43_tx_work); @@ -5486,39 +5481,42 @@ int b43_ssb_probe(struct ssb_device *sdev, const struct ssb_device_id *id) struct b43_bus_dev *dev; struct b43_wl *wl; int err; - int first = 0; dev = b43_bus_dev_ssb_init(sdev); if (!dev) return -ENOMEM; wl = ssb_get_devtypedata(sdev); - if (!wl) { - /* Probing the first core. Must setup common struct b43_wl */ - first = 1; - b43_sprom_fixup(sdev->bus); - wl = b43_wireless_init(dev); - if (IS_ERR(wl)) { - err = PTR_ERR(wl); - goto out; - } - ssb_set_devtypedata(sdev, wl); - B43_WARN_ON(ssb_get_devtypedata(sdev) != wl); + if (wl) { + b43err(NULL, "Dual-core devices are not supported\n"); + err = -ENOTSUPP; + goto err_ssb_kfree_dev; + } + + b43_sprom_fixup(sdev->bus); + + wl = b43_wireless_init(dev); + if (IS_ERR(wl)) { + err = PTR_ERR(wl); + goto err_ssb_kfree_dev; } + ssb_set_devtypedata(sdev, wl); + B43_WARN_ON(ssb_get_devtypedata(sdev) != wl); + err = b43_one_core_attach(dev, wl); if (err) - goto err_wireless_exit; + goto err_ssb_wireless_exit; /* setup and start work to load firmware */ INIT_WORK(&wl->firmware_load, b43_request_firmware); schedule_work(&wl->firmware_load); - out: return err; - err_wireless_exit: - if (first) - b43_wireless_exit(dev, wl); +err_ssb_wireless_exit: + b43_wireless_exit(dev, wl); +err_ssb_kfree_dev: + kfree(dev); return err; } @@ -5546,13 +5544,8 @@ static void b43_ssb_remove(struct ssb_device *sdev) /* Unregister HW RNG driver */ b43_rng_exit(wl); - if (list_empty(&wl->devlist)) { - b43_leds_unregister(wl); - /* Last core on the chip unregistered. - * We can destroy common struct b43_wl. - */ - b43_wireless_exit(dev, wl); - } + b43_leds_unregister(wl); + b43_wireless_exit(dev, wl); } static struct ssb_driver b43_ssb_driver = { diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index dbaa5189019894..3e45989f418d00 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -96,7 +96,7 @@ int b43_phy_init(struct b43_wldev *dev) phy->channel = ops->get_default_chan(dev); - ops->software_rfkill(dev, false); + b43_software_rfkill(dev, false); err = ops->init(dev); if (err) { b43err(dev->wl, "PHY init failed\n"); @@ -116,7 +116,7 @@ int b43_phy_init(struct b43_wldev *dev) if (ops->exit) ops->exit(dev); err_block_rf: - ops->software_rfkill(dev, true); + b43_software_rfkill(dev, true); return err; } @@ -125,7 +125,7 @@ void b43_phy_exit(struct b43_wldev *dev) { const struct b43_phy_operations *ops = dev->phy.ops; - ops->software_rfkill(dev, true); + b43_software_rfkill(dev, true); if (ops->exit) ops->exit(dev); } diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 12f467b8d564f1..8f5c14bc10e6fe 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -1587,6 +1587,7 @@ static void b43_phy_initb5(struct b43_wldev *dev) b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/Init/B6 */ static void b43_phy_initb6(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -1670,7 +1671,7 @@ static void b43_phy_initb6(struct b43_wldev *dev) b43_radio_write16(dev, 0x50, 0x20); } if (phy->radio_rev <= 2) { - b43_radio_write16(dev, 0x7C, 0x20); + b43_radio_write16(dev, 0x50, 0x20); b43_radio_write16(dev, 0x5A, 0x70); b43_radio_write16(dev, 0x5B, 0x7B); b43_radio_write16(dev, 0x5C, 0xB0); @@ -1686,9 +1687,8 @@ static void b43_phy_initb6(struct b43_wldev *dev) b43_phy_write(dev, 0x2A, 0x8AC0); b43_phy_write(dev, 0x0038, 0x0668); b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control); - if (phy->radio_rev <= 5) { + if (phy->radio_rev == 4 || phy->radio_rev == 5) b43_phy_maskset(dev, 0x5D, 0xFF80, 0x0003); - } if (phy->radio_rev <= 2) b43_radio_write16(dev, 0x005D, 0x000D); diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 24ccbe96e0c8a0..41dab89a2942dd 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -257,6 +257,72 @@ static void b43_nphy_rf_ctl_override(struct b43_wldev *dev, u16 field, } } +static void b43_nphy_rf_ctl_intc_override_rev7(struct b43_wldev *dev, + enum n_intc_override intc_override, + u16 value, u8 core_sel) +{ + u16 reg, tmp, tmp2, val; + int core; + + for (core = 0; core < 2; core++) { + if ((core_sel == 1 && core != 0) || + (core_sel == 2 && core != 1)) + continue; + + reg = (core == 0) ? B43_NPHY_RFCTL_INTC1 : B43_NPHY_RFCTL_INTC2; + + switch (intc_override) { + case N_INTC_OVERRIDE_OFF: + b43_phy_write(dev, reg, 0); + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); + break; + case N_INTC_OVERRIDE_TRSW: + b43_phy_maskset(dev, reg, ~0xC0, value << 6); + b43_phy_set(dev, reg, 0x400); + + b43_phy_mask(dev, 0x2ff, ~0xC000 & 0xFFFF); + b43_phy_set(dev, 0x2ff, 0x2000); + b43_phy_set(dev, 0x2ff, 0x0001); + break; + case N_INTC_OVERRIDE_PA: + tmp = 0x0030; + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + val = value << 5; + else + val = value << 4; + b43_phy_maskset(dev, reg, ~tmp, val); + b43_phy_set(dev, reg, 0x1000); + break; + case N_INTC_OVERRIDE_EXT_LNA_PU: + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { + tmp = 0x0001; + tmp2 = 0x0004; + val = value; + } else { + tmp = 0x0004; + tmp2 = 0x0001; + val = value << 2; + } + b43_phy_maskset(dev, reg, ~tmp, val); + b43_phy_mask(dev, reg, ~tmp2); + break; + case N_INTC_OVERRIDE_EXT_LNA_GAIN: + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { + tmp = 0x0002; + tmp2 = 0x0008; + val = value << 1; + } else { + tmp = 0x0008; + tmp2 = 0x0002; + val = value << 3; + } + b43_phy_maskset(dev, reg, ~tmp, val); + b43_phy_mask(dev, reg, ~tmp2); + break; + } + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */ static void b43_nphy_rf_ctl_intc_override(struct b43_wldev *dev, enum n_intc_override intc_override, @@ -265,6 +331,12 @@ static void b43_nphy_rf_ctl_intc_override(struct b43_wldev *dev, u8 i, j; u16 reg, tmp, val; + if (dev->phy.rev >= 7) { + b43_nphy_rf_ctl_intc_override_rev7(dev, intc_override, value, + core); + return; + } + B43_WARN_ON(dev->phy.rev < 3); for (i = 0; i < 2; i++) { @@ -419,7 +491,8 @@ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable) static const u16 clip[] = { 0xFFFF, 0xFFFF }; if (nphy->deaf_count++ == 0) { nphy->classifier_state = b43_nphy_classifier(dev, 0, 0); - b43_nphy_classifier(dev, 0x7, 0); + b43_nphy_classifier(dev, 0x7, + B43_NPHY_CLASSCTL_WAITEDEN); b43_nphy_read_clip_detection(dev, nphy->clip_state); b43_nphy_write_clip_detection(dev, clip); } @@ -734,9 +807,16 @@ static void b43_radio_2056_setup(struct b43_wldev *dev, u16 bias, cbias; u16 pag_boost, padg_boost, pgag_boost, mixg_boost; u16 paa_boost, pada_boost, pgaa_boost, mixa_boost; + bool is_pkg_fab_smic; B43_WARN_ON(dev->phy.rev < 3); + is_pkg_fab_smic = + ((dev->dev->chip_id == BCMA_CHIP_ID_BCM43224 || + dev->dev->chip_id == BCMA_CHIP_ID_BCM43225 || + dev->dev->chip_id == BCMA_CHIP_ID_BCM43421) && + dev->dev->chip_pkg == BCMA_PKG_ID_BCM43224_FAB_SMIC); + b43_chantab_radio_2056_upload(dev, e); b2056_upload_syn_pll_cp2(dev, band == IEEE80211_BAND_5GHZ); @@ -744,7 +824,8 @@ static void b43_radio_2056_setup(struct b43_wldev *dev, b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1, 0x1F); b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2, 0x1F); - if (dev->dev->chip_id == 0x4716) { + if (dev->dev->chip_id == BCMA_CHIP_ID_BCM4716 || + dev->dev->chip_id == BCMA_CHIP_ID_BCM47162) { b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x14); b43_radio_write(dev, B2056_SYN_PLL_CP2, 0); } else { @@ -752,6 +833,13 @@ static void b43_radio_2056_setup(struct b43_wldev *dev, b43_radio_write(dev, B2056_SYN_PLL_CP2, 0x14); } } + if (sprom->boardflags2_hi & B43_BFH2_GPLL_WAR2 && + b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1, 0x1f); + b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2, 0x1f); + b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x0b); + b43_radio_write(dev, B2056_SYN_PLL_CP2, 0x20); + } if (sprom->boardflags2_lo & B43_BFL2_APLL_WAR && b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1, 0x1F); @@ -767,7 +855,8 @@ static void b43_radio_2056_setup(struct b43_wldev *dev, b43_radio_write(dev, offset | B2056_TX_PADG_IDAC, 0xcc); - if (dev->dev->chip_id == 0x4716) { + if (dev->dev->chip_id == BCMA_CHIP_ID_BCM4716 || + dev->dev->chip_id == BCMA_CHIP_ID_BCM47162) { bias = 0x40; cbias = 0x45; pag_boost = 0x5; @@ -776,6 +865,10 @@ static void b43_radio_2056_setup(struct b43_wldev *dev, } else { bias = 0x25; cbias = 0x20; + if (is_pkg_fab_smic) { + bias = 0x2a; + cbias = 0x38; + } pag_boost = 0x4; pgag_boost = 0x03; mixg_boost = 0x65; @@ -844,6 +937,8 @@ static void b43_radio_2056_setup(struct b43_wldev *dev, mixa_boost = 0xF; } + cbias = is_pkg_fab_smic ? 0x35 : 0x30; + for (i = 0; i < 2; i++) { offset = i ? B2056_TX1 : B2056_TX0; @@ -862,11 +957,11 @@ static void b43_radio_2056_setup(struct b43_wldev *dev, b43_radio_write(dev, offset | B2056_TX_PADA_CASCBIAS, 0x03); b43_radio_write(dev, - offset | B2056_TX_INTPAA_IAUX_STAT, 0x50); + offset | B2056_TX_INTPAA_IAUX_STAT, 0x30); b43_radio_write(dev, - offset | B2056_TX_INTPAA_IMAIN_STAT, 0x50); + offset | B2056_TX_INTPAA_IMAIN_STAT, 0x30); b43_radio_write(dev, - offset | B2056_TX_INTPAA_CASCBIAS, 0x30); + offset | B2056_TX_INTPAA_CASCBIAS, cbias); } } @@ -1164,23 +1259,20 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, u16 seq_mode; u32 tmp; - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, true); + b43_nphy_stay_in_carrier_search(dev, true); if ((nphy->bb_mult_save & 0x80000000) == 0) { tmp = b43_ntab_read(dev, B43_NTAB16(15, 87)); nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000; } + /* TODO: add modify_bbmult argument */ if (!dev->phy.is_40mhz) tmp = 0x6464; else tmp = 0x4747; b43_ntab_write(dev, B43_NTAB16(15, 87), tmp); - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, false); - b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1)); if (loops != 0xFFFF) @@ -1213,6 +1305,8 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, b43err(dev->wl, "run samples timeout\n"); b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode); + + b43_nphy_stay_in_carrier_search(dev, false); } /************************************************** @@ -1588,8 +1682,8 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) struct b43_phy_n *nphy = dev->phy.n; u16 saved_regs_phy_rfctl[2]; - u16 saved_regs_phy[13]; - u16 regs_to_store[] = { + u16 saved_regs_phy[22]; + u16 regs_to_store_rev3[] = { B43_NPHY_AFECTL_OVER1, B43_NPHY_AFECTL_OVER, B43_NPHY_AFECTL_C1, B43_NPHY_AFECTL_C2, B43_NPHY_TXF_40CO_B1S1, B43_NPHY_RFCTL_OVER, @@ -1598,6 +1692,20 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) B43_NPHY_RFCTL_LUT_TRSW_UP1, B43_NPHY_RFCTL_LUT_TRSW_UP2, B43_NPHY_RFCTL_RSSIO1, B43_NPHY_RFCTL_RSSIO2 }; + u16 regs_to_store_rev7[] = { + B43_NPHY_AFECTL_OVER1, B43_NPHY_AFECTL_OVER, + B43_NPHY_AFECTL_C1, B43_NPHY_AFECTL_C2, + B43_NPHY_TXF_40CO_B1S1, B43_NPHY_RFCTL_OVER, + 0x342, 0x343, 0x346, 0x347, + 0x2ff, + B43_NPHY_TXF_40CO_B1S0, B43_NPHY_TXF_40CO_B32S1, + B43_NPHY_RFCTL_CMD, + B43_NPHY_RFCTL_LUT_TRSW_UP1, B43_NPHY_RFCTL_LUT_TRSW_UP2, + 0x340, 0x341, 0x344, 0x345, + B43_NPHY_RFCTL_RSSIO1, B43_NPHY_RFCTL_RSSIO2 + }; + u16 *regs_to_store; + int regs_amount; u16 class; @@ -1617,6 +1725,15 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) u8 rx_core_state; int core, i, j, vcm; + if (dev->phy.rev >= 7) { + regs_to_store = regs_to_store_rev7; + regs_amount = ARRAY_SIZE(regs_to_store_rev7); + } else { + regs_to_store = regs_to_store_rev3; + regs_amount = ARRAY_SIZE(regs_to_store_rev3); + } + BUG_ON(regs_amount > ARRAY_SIZE(saved_regs_phy)); + class = b43_nphy_classifier(dev, 0, 0); b43_nphy_classifier(dev, 7, 4); b43_nphy_read_clip_detection(dev, clip_state); @@ -1624,22 +1741,29 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) saved_regs_phy_rfctl[0] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); saved_regs_phy_rfctl[1] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); - for (i = 0; i < ARRAY_SIZE(regs_to_store); i++) + for (i = 0; i < regs_amount; i++) saved_regs_phy[i] = b43_phy_read(dev, regs_to_store[i]); b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_OFF, 0, 7); b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, 1, 7); - b43_nphy_rf_ctl_override(dev, 0x1, 0, 0, false); - b43_nphy_rf_ctl_override(dev, 0x2, 1, 0, false); - b43_nphy_rf_ctl_override(dev, 0x80, 1, 0, false); - b43_nphy_rf_ctl_override(dev, 0x40, 1, 0, false); - - if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { - b43_nphy_rf_ctl_override(dev, 0x20, 0, 0, false); - b43_nphy_rf_ctl_override(dev, 0x10, 1, 0, false); + + if (dev->phy.rev >= 7) { + /* TODO */ + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { + } else { + } } else { - b43_nphy_rf_ctl_override(dev, 0x10, 0, 0, false); - b43_nphy_rf_ctl_override(dev, 0x20, 1, 0, false); + b43_nphy_rf_ctl_override(dev, 0x1, 0, 0, false); + b43_nphy_rf_ctl_override(dev, 0x2, 1, 0, false); + b43_nphy_rf_ctl_override(dev, 0x80, 1, 0, false); + b43_nphy_rf_ctl_override(dev, 0x40, 1, 0, false); + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { + b43_nphy_rf_ctl_override(dev, 0x20, 0, 0, false); + b43_nphy_rf_ctl_override(dev, 0x10, 1, 0, false); + } else { + b43_nphy_rf_ctl_override(dev, 0x10, 0, 0, false); + b43_nphy_rf_ctl_override(dev, 0x20, 1, 0, false); + } } rx_core_state = b43_nphy_get_rx_core_state(dev); @@ -1654,8 +1778,11 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) /* Grab RSSI results for every possible VCM */ for (vcm = 0; vcm < 8; vcm++) { - b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC, 0xE3, - vcm << 2); + if (dev->phy.rev >= 7) + ; + else + b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC, + 0xE3, vcm << 2); b43_nphy_poll_rssi(dev, N_RSSI_NB, results[vcm], 8); } @@ -1682,8 +1809,11 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) } /* Select the best VCM */ - b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC, 0xE3, - vcm_final << 2); + if (dev->phy.rev >= 7) + ; + else + b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC, + 0xE3, vcm_final << 2); for (i = 0; i < 4; i++) { if (core != i / 2) @@ -1736,9 +1866,9 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) b43_phy_set(dev, B43_NPHY_RFCTL_OVER, 0x1); b43_phy_set(dev, B43_NPHY_RFCTL_CMD, B43_NPHY_RFCTL_CMD_RXTX); - b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S1, ~0x1); + b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~0x1); - for (i = 0; i < ARRAY_SIZE(regs_to_store); i++) + for (i = 0; i < regs_amount; i++) b43_phy_write(dev, regs_to_store[i], saved_regs_phy[i]); /* Store for future configuration */ @@ -2494,8 +2624,8 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) struct ssb_sprom *sprom = dev->dev->bus_sprom; /* TX to RX */ - u8 tx2rx_events[8] = { 0x4, 0x3, 0x6, 0x5, 0x2, 0x1, 0x8, 0x1F }; - u8 tx2rx_delays[8] = { 8, 4, 2, 2, 4, 4, 6, 1 }; + u8 tx2rx_events[7] = { 0x4, 0x3, 0x5, 0x2, 0x1, 0x8, 0x1F }; + u8 tx2rx_delays[7] = { 8, 4, 4, 4, 4, 6, 1 }; /* RX to TX */ u8 rx2tx_events_ipa[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0xF, 0x3, 0x1F }; @@ -2503,6 +2633,23 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) u8 rx2tx_events[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0x3, 0x4, 0x1F }; u8 rx2tx_delays[9] = { 8, 6, 6, 4, 4, 18, 42, 1, 1 }; + u16 vmids[5][4] = { + { 0xa2, 0xb4, 0xb4, 0x89, }, /* 0 */ + { 0xb4, 0xb4, 0xb4, 0x24, }, /* 1 */ + { 0xa2, 0xb4, 0xb4, 0x74, }, /* 2 */ + { 0xa2, 0xb4, 0xb4, 0x270, }, /* 3 */ + { 0xa2, 0xb4, 0xb4, 0x00, }, /* 4 and 5 */ + }; + u16 gains[5][4] = { + { 0x02, 0x02, 0x02, 0x00, }, /* 0 */ + { 0x02, 0x02, 0x02, 0x02, }, /* 1 */ + { 0x02, 0x02, 0x02, 0x04, }, /* 2 */ + { 0x02, 0x02, 0x02, 0x00, }, /* 3 */ + { 0x02, 0x02, 0x02, 0x00, }, /* 4 and 5 */ + }; + u16 *vmid, *gain; + + u8 pdet_range; u16 tmp16; u32 tmp32; @@ -2561,7 +2708,71 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) b43_ntab_write(dev, B43_NTAB16(8, 0), 2); b43_ntab_write(dev, B43_NTAB16(8, 16), 2); - /* TODO */ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + pdet_range = sprom->fem.ghz2.pdet_range; + else + pdet_range = sprom->fem.ghz5.pdet_range; + vmid = vmids[min_t(u16, pdet_range, 4)]; + gain = gains[min_t(u16, pdet_range, 4)]; + switch (pdet_range) { + case 3: + if (!(dev->phy.rev >= 4 && + b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) + break; + /* FALL THROUGH */ + case 0: + case 1: + b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x08), 4, vmid); + b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x18), 4, vmid); + b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x0c), 4, gain); + b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x1c), 4, gain); + break; + case 2: + if (dev->phy.rev >= 6) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + vmid[3] = 0x94; + else + vmid[3] = 0x8e; + gain[3] = 3; + } else if (dev->phy.rev == 5) { + vmid[3] = 0x84; + gain[3] = 2; + } + b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x08), 4, vmid); + b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x18), 4, vmid); + b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x0c), 4, gain); + b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x1c), 4, gain); + break; + case 4: + case 5: + if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) { + if (pdet_range == 4) { + vmid[3] = 0x8e; + tmp16 = 0x96; + gain[3] = 0x2; + } else { + vmid[3] = 0x89; + tmp16 = 0x89; + gain[3] = 0; + } + } else { + if (pdet_range == 4) { + vmid[3] = 0x89; + tmp16 = 0x8b; + gain[3] = 0x2; + } else { + vmid[3] = 0x74; + tmp16 = 0x70; + gain[3] = 0; + } + } + b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x08), 4, vmid); + b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x0c), 4, gain); + vmid[3] = tmp16; + b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x18), 4, vmid); + b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x1c), 4, gain); + break; + } b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_MAST_BIAS, 0x00); b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_MAST_BIAS, 0x00); @@ -2600,7 +2811,7 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) /* Dropped probably-always-true condition */ b43_phy_write(dev, B43_NPHY_ED_CRS40ASSERTTHRESH0, 0x03eb); b43_phy_write(dev, B43_NPHY_ED_CRS40ASSERTTHRESH1, 0x03eb); - b43_phy_write(dev, B43_NPHY_ED_CRS40DEASSERTTHRESH1, 0x0341); + b43_phy_write(dev, B43_NPHY_ED_CRS40DEASSERTTHRESH0, 0x0341); b43_phy_write(dev, B43_NPHY_ED_CRS40DEASSERTTHRESH1, 0x0341); b43_phy_write(dev, B43_NPHY_ED_CRS20LASSERTTHRESH0, 0x042b); b43_phy_write(dev, B43_NPHY_ED_CRS20LASSERTTHRESH1, 0x042b); @@ -3211,6 +3422,20 @@ static void b43_nphy_tx_prepare_adjusted_power_table(struct b43_wldev *dev) u8 idx, delta; u8 i, stf_mode; + /* Array adj_pwr_tbl corresponds to the hardware table. It consists of + * 21 groups, each containing 4 entries. + * + * First group has entries for CCK modulation. + * The rest of groups has 1 entry per modulation (SISO, CDD, STBC, SDM). + * + * Group 0 is for CCK + * Groups 1..4 use BPSK (group per coding rate) + * Groups 5..8 use QPSK (group per coding rate) + * Groups 9..12 use 16-QAM (group per coding rate) + * Groups 13..16 use 64-QAM (group per coding rate) + * Groups 17..20 are unknown + */ + for (i = 0; i < 4; i++) nphy->adj_pwr_tbl[i] = nphy->tx_power_offset[i]; @@ -3409,10 +3634,8 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev) } b43_nphy_tx_prepare_adjusted_power_table(dev); - /* b43_ntab_write_bulk(dev, B43_NTAB16(26, 64), 84, nphy->adj_pwr_tbl); b43_ntab_write_bulk(dev, B43_NTAB16(27, 64), 84, nphy->adj_pwr_tbl); - */ if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, false); @@ -5124,7 +5347,7 @@ static int b43_phy_initn(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_TXMACIF_HOLDOFF, 0x0015); b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320); if (phy->rev >= 3 && phy->rev <= 6) - b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0014); + b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0032); b43_nphy_tx_lp_fbw(dev); if (phy->rev >= 3) b43_nphy_spur_workaround(dev); @@ -5441,8 +5664,11 @@ static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg) { /* Register 1 is a 32-bit register. */ B43_WARN_ON(reg == 1); - /* N-PHY needs 0x100 for read access */ - reg |= 0x100; + + if (dev->phy.rev >= 7) + reg |= 0x200; /* Radio 0x2057 */ + else + reg |= 0x100; b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); diff --git a/drivers/net/wireless/b43/radio_2056.c b/drivers/net/wireless/b43/radio_2056.c index b4fd9345d673a3..a07e4cacab7727 100644 --- a/drivers/net/wireless/b43/radio_2056.c +++ b/drivers/net/wireless/b43/radio_2056.c @@ -48,7 +48,7 @@ struct b2056_inittabs_pts { unsigned int rx_length; }; -static const struct b2056_inittab_entry b2056_inittab_rev3_syn[] = { +static const struct b2056_inittab_entry b2056_inittab_phy_rev3_syn[] = { [B2056_SYN_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_SYN_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_SYN_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -232,7 +232,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev3_syn[] = { [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev3_tx[] = { +static const struct b2056_inittab_entry b2056_inittab_phy_rev3_tx[] = { [B2056_TX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_TX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_TX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -380,7 +380,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev3_tx[] = { [B2056_TX_STATUS_TXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev3_rx[] = { +static const struct b2056_inittab_entry b2056_inittab_phy_rev3_rx[] = { [B2056_RX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_RX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_RX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -530,7 +530,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev3_rx[] = { [B2056_RX_STATUS_HPC_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev4_syn[] = { +static const struct b2056_inittab_entry b2056_inittab_phy_rev4_syn[] = { [B2056_SYN_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_SYN_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_SYN_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -714,7 +714,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev4_syn[] = { [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev4_tx[] = { +static const struct b2056_inittab_entry b2056_inittab_phy_rev4_tx[] = { [B2056_TX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_TX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_TX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -862,7 +862,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev4_tx[] = { [B2056_TX_STATUS_TXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev4_rx[] = { +static const struct b2056_inittab_entry b2056_inittab_phy_rev4_rx[] = { [B2056_RX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_RX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_RX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -1012,7 +1012,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev4_rx[] = { [B2056_RX_STATUS_HPC_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev5_syn[] = { +static const struct b2056_inittab_entry b2056_inittab_radio_rev5_syn[] = { [B2056_SYN_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_SYN_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_SYN_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -1196,7 +1196,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev5_syn[] = { [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev5_tx[] = { +static const struct b2056_inittab_entry b2056_inittab_radio_rev5_tx[] = { [B2056_TX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_TX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_TX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -1352,7 +1352,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev5_tx[] = { [B2056_TX_GMBB_IDAC7] = { .ghz5 = 0x0075, .ghz2 = 0x0075, UPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev5_rx[] = { +static const struct b2056_inittab_entry b2056_inittab_radio_rev5_rx[] = { [B2056_RX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_RX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_RX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -1502,7 +1502,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev5_rx[] = { [B2056_RX_STATUS_HPC_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev6_syn[] = { +static const struct b2056_inittab_entry b2056_inittab_radio_rev6_syn[] = { [B2056_SYN_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_SYN_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_SYN_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -1686,7 +1686,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev6_syn[] = { [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev6_tx[] = { +static const struct b2056_inittab_entry b2056_inittab_radio_rev6_tx[] = { [B2056_TX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_TX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_TX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -1842,7 +1842,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev6_tx[] = { [B2056_TX_GMBB_IDAC7] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev6_rx[] = { +static const struct b2056_inittab_entry b2056_inittab_radio_rev6_rx[] = { [B2056_RX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_RX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_RX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -1992,7 +1992,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev6_rx[] = { [B2056_RX_STATUS_HPC_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev7_syn[] = { +static const struct b2056_inittab_entry b2056_inittab_radio_rev7_9_syn[] = { [B2056_SYN_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_SYN_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_SYN_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -2176,7 +2176,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev7_syn[] = { [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev7_tx[] = { +static const struct b2056_inittab_entry b2056_inittab_radio_rev7_9_tx[] = { [B2056_TX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_TX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_TX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -2332,7 +2332,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev7_tx[] = { [B2056_TX_GMBB_IDAC7] = { .ghz5 = 0x0075, .ghz2 = 0x0075, UPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev7_rx[] = { +static const struct b2056_inittab_entry b2056_inittab_radio_rev7_9_rx[] = { [B2056_RX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_RX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_RX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -2482,7 +2482,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev7_rx[] = { [B2056_RX_STATUS_HPC_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev8_syn[] = { +static const struct b2056_inittab_entry b2056_inittab_radio_rev8_syn[] = { [B2056_SYN_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_SYN_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_SYN_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -2666,7 +2666,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev8_syn[] = { [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev8_tx[] = { +static const struct b2056_inittab_entry b2056_inittab_radio_rev8_tx[] = { [B2056_TX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_TX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_TX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -2822,7 +2822,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev8_tx[] = { [B2056_TX_GMBB_IDAC7] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, }, }; -static const struct b2056_inittab_entry b2056_inittab_rev8_rx[] = { +static const struct b2056_inittab_entry b2056_inittab_radio_rev8_rx[] = { [B2056_RX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_RX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2056_RX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, @@ -2972,24 +2972,69 @@ static const struct b2056_inittab_entry b2056_inittab_rev8_rx[] = { [B2056_RX_STATUS_HPC_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, }; -#define INITTABSPTS(prefix) \ - .syn = prefix##_syn, \ - .syn_length = ARRAY_SIZE(prefix##_syn), \ - .tx = prefix##_tx, \ - .tx_length = ARRAY_SIZE(prefix##_tx), \ - .rx = prefix##_rx, \ - .rx_length = ARRAY_SIZE(prefix##_rx) +static const struct b2056_inittab_entry b2056_inittab_radio_rev11_syn[] = { + [B2056_SYN_PLL_PFD] = { .ghz5 = 0x0006, .ghz2 = 0x0006, UPLOAD, }, + [B2056_SYN_PLL_CP2] = { .ghz5 = 0x003f, .ghz2 = 0x003f, UPLOAD, }, + [B2056_SYN_PLL_LOOPFILTER1] = { .ghz5 = 0x0006, .ghz2 = 0x0006, UPLOAD, }, + [B2056_SYN_PLL_LOOPFILTER2] = { .ghz5 = 0x0006, .ghz2 = 0x0006, UPLOAD, }, + [B2056_SYN_PLL_LOOPFILTER4] = { .ghz5 = 0x002b, .ghz2 = 0x002b, UPLOAD, }, + [B2056_SYN_PLL_VCO2] = { .ghz5 = 0x00f7, .ghz2 = 0x00f7, UPLOAD, }, + [B2056_SYN_PLL_VCOCAL12] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, }, + [B2056_SYN_LOGENBUF2] = { .ghz5 = 0x008f, .ghz2 = 0x008f, UPLOAD, }, +}; -static const struct b2056_inittabs_pts b2056_inittabs[] = { - [3] = { INITTABSPTS(b2056_inittab_rev3) }, - [4] = { INITTABSPTS(b2056_inittab_rev4) }, - [5] = { INITTABSPTS(b2056_inittab_rev5) }, - [6] = { INITTABSPTS(b2056_inittab_rev6) }, - [7] = { INITTABSPTS(b2056_inittab_rev7) }, - [8] = { INITTABSPTS(b2056_inittab_rev8) }, - [9] = { INITTABSPTS(b2056_inittab_rev7) }, +static const struct b2056_inittab_entry b2056_inittab_radio_rev11_tx[] = { + [B2056_TX_PA_SPARE2] = { .ghz5 = 0x00ee, .ghz2 = 0x00ee, UPLOAD, }, + [B2056_TX_INTPAA_IAUX_STAT] = { .ghz5 = 0x0050, .ghz2 = 0x0050, UPLOAD, }, + [B2056_TX_INTPAA_IMAIN_STAT] = { .ghz5 = 0x0050, .ghz2 = 0x0050, UPLOAD, }, + [B2056_TX_INTPAA_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, }, + [B2056_TX_INTPAG_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, }, + [B2056_TX_PADA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, }, + [B2056_TX_PADA_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, }, + [B2056_TX_PADG_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, }, + [B2056_TX_PGAA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, }, + [B2056_TX_PGAA_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, }, + [B2056_TX_PGAG_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, }, + [B2056_TX_GMBB_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, }, + [B2056_TX_TXSPARE1] = { .ghz5 = 0x0030, .ghz2 = 0x0030, UPLOAD, }, +}; + +static const struct b2056_inittab_entry b2056_inittab_radio_rev11_rx[] = { + [B2056_RX_BIASPOLE_LNAA1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, }, + [B2056_RX_LNAA2_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, }, + [B2056_RX_BIASPOLE_LNAG1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, }, + [B2056_RX_LNAG2_IDAC] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, }, + [B2056_RX_MIXA_VCM] = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, }, + [B2056_RX_MIXA_LOB_BIAS] = { .ghz5 = 0x0088, .ghz2 = 0x0088, UPLOAD, }, + [B2056_RX_MIXA_BIAS_AUX] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, }, + [B2056_RX_MIXG_VCM] = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, }, + [B2056_RX_TIA_IOPAMP] = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, }, + [B2056_RX_TIA_QOPAMP] = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, }, + [B2056_RX_TIA_IMISC] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, }, + [B2056_RX_TIA_QMISC] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, }, + [B2056_RX_RXLPF_OUTVCM] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, }, + [B2056_RX_VGA_BIAS_DCCANCEL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, }, + [B2056_RX_RXSPARE3] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, }, }; +#define INITTABSPTS(prefix) \ + static const struct b2056_inittabs_pts prefix = { \ + .syn = prefix##_syn, \ + .syn_length = ARRAY_SIZE(prefix##_syn), \ + .tx = prefix##_tx, \ + .tx_length = ARRAY_SIZE(prefix##_tx), \ + .rx = prefix##_rx, \ + .rx_length = ARRAY_SIZE(prefix##_rx), \ + } + +INITTABSPTS(b2056_inittab_phy_rev3); +INITTABSPTS(b2056_inittab_phy_rev4); +INITTABSPTS(b2056_inittab_radio_rev5); +INITTABSPTS(b2056_inittab_radio_rev6); +INITTABSPTS(b2056_inittab_radio_rev7_9); +INITTABSPTS(b2056_inittab_radio_rev8); +INITTABSPTS(b2056_inittab_radio_rev11); + #define RADIOREGS3(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \ r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \ r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, \ @@ -3041,7 +3086,7 @@ static const struct b2056_inittabs_pts b2056_inittabs[] = { .phy_regs.phy_bw6 = r5 /* http://bcm-v4.sipsolutions.net/802.11/Radio/2056/ChannelTable */ -static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] = { +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_phy_rev3[] = { { .freq = 4920, RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, @@ -4036,7 +4081,7 @@ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] = }, }; -static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev4[] = { +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_phy_rev4[] = { { .freq = 4920, RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, @@ -5031,7 +5076,7 @@ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev4[] = }, }; -static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev5[] = { +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_radio_rev5[] = { { .freq = 4920, RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, @@ -6026,7 +6071,7 @@ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev5[] = }, }; -static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev6[] = { +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_radio_rev6[] = { { .freq = 4920, RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, @@ -7021,7 +7066,7 @@ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev6[] = }, }; -static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev7_9[] = { +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_radio_rev7_9[] = { { .freq = 4920, RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, @@ -8016,7 +8061,7 @@ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev7_9[] }, }; -static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev8[] = { +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_radio_rev8[] = { { .freq = 4920, RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, @@ -9011,6 +9056,236 @@ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev8[] = }, }; +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_radio_rev11[] = { + { + .freq = 5180, + RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x02, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00), + PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb), + }, + { + .freq = 5200, + RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x02, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, + 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9), + }, + { + .freq = 5220, + RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x02, + 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, + 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00), + PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7), + }, + { + .freq = 5745, + RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x05, 0x05, 0x02, + 0x15, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, + 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00), + PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9), + }, + { + .freq = 5765, + RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x05, 0x05, 0x02, + 0x15, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00), + PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8), + }, + { + .freq = 5785, + RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x05, 0x05, 0x02, + 0x15, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00), + PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6), + }, + { + .freq = 5805, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x05, 0x05, 0x02, + 0x15, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00), + PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4), + }, + { + .freq = 5825, + RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x05, 0x05, 0x02, + 0x15, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x69, 0x00), + PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3), + }, + { + .freq = 2412, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { + .freq = 2417, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { + .freq = 2422, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x67, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { + .freq = 2427, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x57, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { + .freq = 2432, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x56, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { + .freq = 2437, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x46, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { + .freq = 2442, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { + .freq = 2447, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { + .freq = 2452, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x23, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { + .freq = 2457, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x12, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { + .freq = 2462, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, + { + .freq = 2467, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x00, 0x22, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09), + PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b), + }, + { + .freq = 2472, + RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09), + PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429), + }, + { + .freq = 2484, + RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x06, 0x06, 0x04, + 0x2b, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09), + PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424), + }, +}; + +static const struct b2056_inittabs_pts +*b43_nphy_get_inittabs_rev3(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + switch (dev->phy.rev) { + case 3: + return &b2056_inittab_phy_rev3; + case 4: + return &b2056_inittab_phy_rev4; + default: + switch (phy->radio_rev) { + case 5: + return &b2056_inittab_radio_rev5; + case 6: + return &b2056_inittab_radio_rev6; + case 7: + case 9: + return &b2056_inittab_radio_rev7_9; + case 8: + return &b2056_inittab_radio_rev8; + case 11: + return &b2056_inittab_radio_rev11; + } + } + + return NULL; +} + static void b2056_upload_inittab(struct b43_wldev *dev, bool ghz5, bool ignore_uploadflag, u16 routing, const struct b2056_inittab_entry *e, @@ -9037,11 +9312,11 @@ void b2056_upload_inittabs(struct b43_wldev *dev, { const struct b2056_inittabs_pts *pts; - if (dev->phy.rev >= ARRAY_SIZE(b2056_inittabs)) { + pts = b43_nphy_get_inittabs_rev3(dev); + if (!pts) { B43_WARN_ON(1); return; } - pts = &b2056_inittabs[dev->phy.rev]; b2056_upload_inittab(dev, ghz5, ignore_uploadflag, B2056_SYN, pts->syn, pts->syn_length); @@ -9060,11 +9335,12 @@ void b2056_upload_syn_pll_cp2(struct b43_wldev *dev, bool ghz5) const struct b2056_inittabs_pts *pts; const struct b2056_inittab_entry *e; - if (dev->phy.rev >= ARRAY_SIZE(b2056_inittabs)) { + pts = b43_nphy_get_inittabs_rev3(dev); + if (!pts) { B43_WARN_ON(1); return; } - pts = &b2056_inittabs[dev->phy.rev]; + e = &pts->syn[B2056_SYN_PLL_CP2]; b43_radio_write(dev, B2056_SYN_PLL_CP2, ghz5 ? e->ghz5 : e->ghz2); @@ -9073,38 +9349,46 @@ void b2056_upload_syn_pll_cp2(struct b43_wldev *dev, bool ghz5) const struct b43_nphy_channeltab_entry_rev3 * b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq) { + struct b43_phy *phy = &dev->phy; const struct b43_nphy_channeltab_entry_rev3 *e; unsigned int length, i; - switch (dev->phy.rev) { + switch (phy->rev) { case 3: - e = b43_nphy_channeltab_rev3; - length = ARRAY_SIZE(b43_nphy_channeltab_rev3); + e = b43_nphy_channeltab_phy_rev3; + length = ARRAY_SIZE(b43_nphy_channeltab_phy_rev3); break; case 4: - e = b43_nphy_channeltab_rev4; - length = ARRAY_SIZE(b43_nphy_channeltab_rev4); - break; - case 5: - e = b43_nphy_channeltab_rev5; - length = ARRAY_SIZE(b43_nphy_channeltab_rev5); - break; - case 6: - e = b43_nphy_channeltab_rev6; - length = ARRAY_SIZE(b43_nphy_channeltab_rev6); - break; - case 7: - case 9: - e = b43_nphy_channeltab_rev7_9; - length = ARRAY_SIZE(b43_nphy_channeltab_rev7_9); - break; - case 8: - e = b43_nphy_channeltab_rev8; - length = ARRAY_SIZE(b43_nphy_channeltab_rev8); + e = b43_nphy_channeltab_phy_rev4; + length = ARRAY_SIZE(b43_nphy_channeltab_phy_rev4); break; default: - B43_WARN_ON(1); - return NULL; + switch (phy->radio_rev) { + case 5: + e = b43_nphy_channeltab_radio_rev5; + length = ARRAY_SIZE(b43_nphy_channeltab_radio_rev5); + break; + case 6: + e = b43_nphy_channeltab_radio_rev6; + length = ARRAY_SIZE(b43_nphy_channeltab_radio_rev6); + break; + case 7: + case 9: + e = b43_nphy_channeltab_radio_rev7_9; + length = ARRAY_SIZE(b43_nphy_channeltab_radio_rev7_9); + break; + case 8: + e = b43_nphy_channeltab_radio_rev8; + length = ARRAY_SIZE(b43_nphy_channeltab_radio_rev8); + break; + case 11: + e = b43_nphy_channeltab_radio_rev11; + length = ARRAY_SIZE(b43_nphy_channeltab_radio_rev11); + break; + default: + B43_WARN_ON(1); + return NULL; + } } for (i = 0; i < length; i++, e++) { diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 94c755fdda1474..50d03ffeac8c57 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -1627,74 +1627,7 @@ static const u32 b43_ntab_tdtrn_r3[] = { 0xfa58fc00, 0x0b64fc7e, 0x0800f7b6, 0x00f006be, }; -static const u32 b43_ntab_noisevar0_r3[] = { - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, - 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, -}; - -static const u32 b43_ntab_noisevar1_r3[] = { +static const u32 b43_ntab_noisevar_r3[] = { 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, 0x02110211, 0x0000014d, @@ -3114,8 +3047,7 @@ static void b43_nphy_tables_init_rev3(struct b43_wldev *dev) ntab_upload(dev, B43_NTAB_TMAP_R3, b43_ntab_tmap_r3); ntab_upload(dev, B43_NTAB_INTLEVEL_R3, b43_ntab_intlevel_r3); ntab_upload(dev, B43_NTAB_TDTRN_R3, b43_ntab_tdtrn_r3); - ntab_upload(dev, B43_NTAB_NOISEVAR0_R3, b43_ntab_noisevar0_r3); - ntab_upload(dev, B43_NTAB_NOISEVAR1_R3, b43_ntab_noisevar1_r3); + ntab_upload(dev, B43_NTAB_NOISEVAR_R3, b43_ntab_noisevar_r3); ntab_upload(dev, B43_NTAB_MCS_R3, b43_ntab_mcs_r3); ntab_upload(dev, B43_NTAB_TDI20A0_R3, b43_ntab_tdi20a0_r3); ntab_upload(dev, B43_NTAB_TDI20A1_R3, b43_ntab_tdi20a1_r3); diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 9ff33adcff891c..3a58aee4c4cf71 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -143,8 +143,7 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent( #define B43_NTAB_TMAP_R3 B43_NTAB32(12, 0) /* TM AP */ #define B43_NTAB_INTLEVEL_R3 B43_NTAB32(13, 0) /* INT LV */ #define B43_NTAB_TDTRN_R3 B43_NTAB32(14, 0) /* TD TRN */ -#define B43_NTAB_NOISEVAR0_R3 B43_NTAB32(16, 0) /* noise variance 0 */ -#define B43_NTAB_NOISEVAR1_R3 B43_NTAB32(16, 128) /* noise variance 1 */ +#define B43_NTAB_NOISEVAR_R3 B43_NTAB32(16, 0) /* noise variance */ #define B43_NTAB_MCS_R3 B43_NTAB16(18, 0) /* MCS */ #define B43_NTAB_TDI20A0_R3 B43_NTAB32(19, 128) /* TDI 20/0 */ #define B43_NTAB_TDI20A1_R3 B43_NTAB32(19, 256) /* TDI 20/1 */ diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c index 9b1a038be08b86..c218c08fb2f5b1 100644 --- a/drivers/net/wireless/b43/wa.c +++ b/drivers/net/wireless/b43/wa.c @@ -441,7 +441,7 @@ static void b43_wa_altagc(struct b43_wldev *dev) static void b43_wa_tr_ltov(struct b43_wldev *dev) /* TR Lookup Table Original Values */ { - b43_gtab_write(dev, B43_GTAB_ORIGTR, 0, 0xC480); + b43_gtab_write(dev, B43_GTAB_ORIGTR, 0, 0x7654); } static void b43_wa_cpll_nonpilot(struct b43_wldev *dev) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 8c5fa4e581392d..43c71bfaa4744f 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -897,7 +897,8 @@ static bool brcms_tx_flush_completed(struct brcms_info *wl) return result; } -static void brcms_ops_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void brcms_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct brcms_info *wl = hw->priv; int ret; diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c index 103f7bce893208..cd0cad7f775993 100644 --- a/drivers/net/wireless/cw1200/sta.c +++ b/drivers/net/wireless/cw1200/sta.c @@ -936,7 +936,8 @@ static int __cw1200_flush(struct cw1200_common *priv, bool drop) return ret; } -void cw1200_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +void cw1200_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct cw1200_common *priv = hw->priv; diff --git a/drivers/net/wireless/cw1200/sta.h b/drivers/net/wireless/cw1200/sta.h index 35babb62cc6a8b..b7e386b7662b66 100644 --- a/drivers/net/wireless/cw1200/sta.h +++ b/drivers/net/wireless/cw1200/sta.h @@ -40,7 +40,8 @@ int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, int cw1200_set_rts_threshold(struct ieee80211_hw *hw, u32 value); -void cw1200_flush(struct ieee80211_hw *hw, u32 queues, bool drop); +void cw1200_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); u64 cw1200_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list); diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c index d37a6fd90d400a..b598e2803500ec 100644 --- a/drivers/net/wireless/iwlegacy/3945.c +++ b/drivers/net/wireless/iwlegacy/3945.c @@ -573,7 +573,7 @@ il3945_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) rx_status.flag |= RX_FLAG_SHORTPRE; if ((unlikely(rx_stats->phy_count > 20))) { - D_DROP("dsp size out of range [0,20]: %d/n", + D_DROP("dsp size out of range [0,20]: %d\n", rx_stats->phy_count); return; } diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 888ad5c74639e3..c159c05db6ef21 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -670,7 +670,7 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) } if ((unlikely(phy_res->cfg_phy_cnt > 20))) { - D_DROP("dsp size out of range [0,20]: %d/n", + D_DROP("dsp size out of range [0,20]: %d\n", phy_res->cfg_phy_cnt); return; } diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 4f42174d999412..ecc674627e6e10 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -4755,7 +4755,8 @@ il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } EXPORT_SYMBOL(il_mac_change_interface); -void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +void il_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct il_priv *il = hw->priv; unsigned long timeout = jiffies + msecs_to_jiffies(500); diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h index dfb13c70efe83e..ea5c0f863c4ee3 100644 --- a/drivers/net/wireless/iwlegacy/common.h +++ b/drivers/net/wireless/iwlegacy/common.h @@ -1723,7 +1723,8 @@ void il_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum nl80211_iftype newtype, bool newp2p); -void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop); +void il_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); int il_alloc_txq_mem(struct il_priv *il); void il_free_txq_mem(struct il_priv *il); diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 74b3b4de7bb7de..b82d30c0f0c973 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -2,10 +2,6 @@ config IWLWIFI tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) " depends on PCI && MAC80211 && HAS_IOMEM select FW_LOADER - select NEW_LEDS - select LEDS_CLASS - select LEDS_TRIGGERS - select MAC80211_LEDS ---help--- Select to build the driver supporting the: @@ -43,6 +39,14 @@ config IWLWIFI say M here and read . The module will be called iwlwifi. +config IWLWIFI_LEDS + bool + depends on IWLWIFI + depends on LEDS_CLASS + select LEDS_TRIGGERS + select MAC80211_LEDS + default y + config IWLDVM tristate "Intel Wireless WiFi DVM Firmware support" depends on IWLWIFI diff --git a/drivers/net/wireless/iwlwifi/dvm/Makefile b/drivers/net/wireless/iwlwifi/dvm/Makefile index dce7ab2e0c4bfd..4d19685f31c3ad 100644 --- a/drivers/net/wireless/iwlwifi/dvm/Makefile +++ b/drivers/net/wireless/iwlwifi/dvm/Makefile @@ -4,9 +4,10 @@ iwldvm-objs += main.o rs.o mac80211.o ucode.o tx.o iwldvm-objs += lib.o calib.o tt.o sta.o rx.o iwldvm-objs += power.o -iwldvm-objs += scan.o led.o +iwldvm-objs += scan.o iwldvm-objs += rxon.o devices.o +iwldvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwldvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 3441f70d0ff911..a6f22c32a27994 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -888,9 +888,11 @@ struct iwl_priv { struct iwl_event_log event_log; +#ifdef CONFIG_IWLWIFI_LEDS struct led_classdev led; unsigned long blink_on, blink_off; bool led_registered; +#endif /* WoWLAN GTK rekey data */ u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN]; diff --git a/drivers/net/wireless/iwlwifi/dvm/led.h b/drivers/net/wireless/iwlwifi/dvm/led.h index 6a0817d9c4fa05..1c6b2252d0f24c 100644 --- a/drivers/net/wireless/iwlwifi/dvm/led.h +++ b/drivers/net/wireless/iwlwifi/dvm/led.h @@ -36,8 +36,20 @@ struct iwl_priv; #define IWL_LED_ACTIVITY (0<<1) #define IWL_LED_LINK (1<<1) +#ifdef CONFIG_IWLWIFI_LEDS void iwlagn_led_enable(struct iwl_priv *priv); void iwl_leds_init(struct iwl_priv *priv); void iwl_leds_exit(struct iwl_priv *priv); +#else +static inline void iwlagn_led_enable(struct iwl_priv *priv) +{ +} +static inline void iwl_leds_init(struct iwl_priv *priv) +{ +} +static inline void iwl_leds_exit(struct iwl_priv *priv) +{ +} +#endif #endif /* __iwl_leds_h__ */ diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 576f7ee38ca589..d169228f59e700 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -180,7 +180,7 @@ void iwlagn_dev_txfifo_flush(struct iwl_priv *priv) goto done; } IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n"); - iwl_trans_wait_tx_queue_empty(priv->trans); + iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff); done: ieee80211_wake_queues(priv->hw); mutex_unlock(&priv->mutex); diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index dd55c9cf7ba803..29af7b51e37087 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -1091,7 +1091,8 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw, FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } -static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); @@ -1119,7 +1120,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop) } } IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n"); - iwl_trans_wait_tx_queue_empty(priv->trans); + iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff); done: mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 6a6df71af1d7ba..6a00353768f328 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -2053,6 +2053,17 @@ static bool iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) return false; } +static void iwl_napi_add(struct iwl_op_mode *op_mode, + struct napi_struct *napi, + struct net_device *napi_dev, + int (*poll)(struct napi_struct *, int), + int weight) +{ + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + + ieee80211_napi_add(priv->hw, napi, napi_dev, poll, weight); +} + static const struct iwl_op_mode_ops iwl_dvm_ops = { .start = iwl_op_mode_dvm_start, .stop = iwl_op_mode_dvm_stop, @@ -2065,6 +2076,7 @@ static const struct iwl_op_mode_ops iwl_dvm_ops = { .cmd_queue_full = iwl_cmd_queue_full, .nic_config = iwl_nic_config, .wimax_active = iwl_wimax_active, + .napi_add = iwl_napi_add, }; /***************************************************************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 854ba84ccb7309..c3817fae16c042 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -62,6 +62,7 @@ static const struct iwl_base_params iwl1000_base_params = { .led_compensation = 51, .wd_timeout = IWL_WATCHDOG_DISABLED, .max_event_log_size = 128, + .scd_chain_ext_wa = true, }; static const struct iwl_ht_params iwl1000_ht_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 3e63323637f3f5..21e5d0843a62a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -75,6 +75,7 @@ static const struct iwl_base_params iwl2000_base_params = { .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .scd_chain_ext_wa = true, }; @@ -88,6 +89,7 @@ static const struct iwl_base_params iwl2030_base_params = { .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .scd_chain_ext_wa = true, }; static const struct iwl_ht_params iwl2000_ht_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 6674f2c4541c18..332bbede39e5b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -61,6 +61,7 @@ static const struct iwl_base_params iwl5000_base_params = { .led_compensation = 51, .wd_timeout = IWL_WATCHDOG_DISABLED, .max_event_log_size = 512, + .scd_chain_ext_wa = true, }; static const struct iwl_ht_params iwl5000_ht_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 8048de90233fa0..8f2c3c8c6b843f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -85,6 +85,7 @@ static const struct iwl_base_params iwl6000_base_params = { .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .scd_chain_ext_wa = true, }; static const struct iwl_base_params iwl6050_base_params = { @@ -97,6 +98,7 @@ static const struct iwl_base_params iwl6050_base_params = { .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 1024, .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .scd_chain_ext_wa = true, }; static const struct iwl_base_params iwl6000_g2_base_params = { @@ -109,6 +111,7 @@ static const struct iwl_base_params iwl6000_g2_base_params = { .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .scd_chain_ext_wa = true, }; static const struct iwl_ht_params iwl6000_ht_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 4c2d4ef28b220c..48730064da73f5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -71,12 +71,12 @@ #define IWL3160_UCODE_API_MAX 9 /* Oldest version we won't warn about */ -#define IWL7260_UCODE_API_OK 8 -#define IWL3160_UCODE_API_OK 8 +#define IWL7260_UCODE_API_OK 9 +#define IWL3160_UCODE_API_OK 9 /* Lowest firmware API version supported */ -#define IWL7260_UCODE_API_MIN 7 -#define IWL3160_UCODE_API_MIN 7 +#define IWL7260_UCODE_API_MIN 8 +#define IWL3160_UCODE_API_MIN 8 /* NVM versions */ #define IWL7260_NVM_VERSION 0x0a1d @@ -98,7 +98,7 @@ #define NVM_HW_SECTION_NUM_FAMILY_7000 0 static const struct iwl_base_params iwl7000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_7000, .num_of_queues = IWLAGN_NUM_QUEUES, .pll_cfg_val = 0, .shadow_ram_support = true, @@ -107,6 +107,7 @@ static const struct iwl_base_params iwl7000_base_params = { .max_event_log_size = 512, .shadow_reg_enable = true, .pcie_l1_allowed = true, + .apmg_wake_up_wa = true, }; static const struct iwl_ht_params iwl7000_ht_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index f5bd82b885929a..b26b68ce8205bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -85,7 +85,7 @@ #define NVM_HW_SECTION_NUM_FAMILY_8000 10 static const struct iwl_base_params iwl8000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, .num_of_queues = IWLAGN_NUM_QUEUES, .pll_cfg_val = 0, .shadow_ram_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index 7f37fb86837b7a..04a483d386592c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h @@ -102,9 +102,7 @@ /* EEPROM */ #define IWLAGN_EEPROM_IMG_SIZE 2048 -/* OTP */ -/* 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 */ diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 3f17dc3f2c8a9f..97f23d6e480b23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -146,6 +146,9 @@ static inline u8 num_of_ant(u8 mask) * @wd_timeout: TX queues watchdog timeout * @max_event_log_size: size of event log buffer size for ucode event logging * @shadow_reg_enable: HW shadow register support + * @apmg_wake_up_wa: should the MAC access REQ be asserted when a command + * is in flight. This is due to a HW bug in 7260, 3160 and 7265. + * @scd_chain_ext_wa: should the chain extension feature in SCD be disabled. */ struct iwl_base_params { int eeprom_size; @@ -160,6 +163,8 @@ struct iwl_base_params { u32 max_event_log_size; const bool shadow_reg_enable; const bool pcie_l1_allowed; + const bool apmg_wake_up_wa; + const bool scd_chain_ext_wa; }; /* @@ -188,6 +193,11 @@ struct iwl_ht_params { #define EEPROM_6000_REG_BAND_24_HT40_CHANNELS 0x80 #define EEPROM_REGULATORY_BAND_NO_HT40 0 +/* lower blocks contain EEPROM image and calibration data */ +#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ +#define OTP_LOW_IMAGE_SIZE_FAMILY_7000 (4 * 512 * sizeof(u16)) /* 4 KB */ +#define OTP_LOW_IMAGE_SIZE_FAMILY_8000 (32 * 512 * sizeof(u16)) /* 32 KB */ + struct iwl_eeprom_params { const u8 regulatory_bands[7]; bool enhanced_txpower; @@ -264,6 +274,7 @@ struct iwl_cfg { u8 nvm_hw_section_num; bool lp_xtal_workaround; const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; + bool no_power_up_nic_in_init; }; /* diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h similarity index 82% rename from drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h rename to drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index 58c8941c0d95ef..2953ffceda3881 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -71,10 +71,15 @@ * enum iwl_fw_error_dump_type - types of data in the dump file * @IWL_FW_ERROR_DUMP_SRAM: * @IWL_FW_ERROR_DUMP_REG: + * @IWL_FW_ERROR_DUMP_RXF: + * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as + * &struct iwl_fw_error_dump_txcmd packets */ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_SRAM = 0, IWL_FW_ERROR_DUMP_REG = 1, + IWL_FW_ERROR_DUMP_RXF = 2, + IWL_FW_ERROR_DUMP_TXCMD = 3, IWL_FW_ERROR_DUMP_MAX, }; @@ -89,7 +94,7 @@ struct iwl_fw_error_dump_data { __le32 type; __le32 len; __u8 data[]; -} __packed __aligned(4); +} __packed; /** * struct iwl_fw_error_dump_file - the layout of the header of the file @@ -101,6 +106,29 @@ struct iwl_fw_error_dump_file { __le32 barker; __le32 file_len; u8 data[0]; -} __packed __aligned(4); +} __packed; + +/** + * struct iwl_fw_error_dump_txcmd - TX command data + * @cmdlen: original length of command + * @caplen: captured length of command (may be less) + * @data: captured command data, @caplen bytes + */ +struct iwl_fw_error_dump_txcmd { + __le32 cmdlen; + __le32 caplen; + u8 data[]; +} __packed; + +/** + * iwl_mvm_fw_error_next_data - advance fw error dump data pointer + * @data: previous data block + * Returns: next data block + */ +static inline struct iwl_fw_error_dump_data * +iwl_mvm_fw_error_next_data(struct iwl_fw_error_dump_data *data) +{ + return (void *)(data->data + le32_to_cpu(data->len)); +} #endif /* __fw_error_dump_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index d14f19339d6140..6fea27c0dd8e1d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -77,26 +77,21 @@ * @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD * @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan * offload profile config command. - * @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api - * @IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API. * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six * (rather than two) IPv6 addresses - * @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element * from the probe request template. - * @IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API: modified D3 API to allow keeping - * connection when going back to D0 * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) - * @IWL_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan. - * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API - * @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command - * containing CAM (Continuous Active Mode) indication. + * @IWL_UCODE_TLV_FLAGS_P2P_PM: P2P client supports PM as a stand alone MAC * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and * P2P client interfaces simultaneously if they are in different bindings. + * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_SCM: support power save on BSS station and + * P2P client interfaces simultaneously if they are in same bindings. * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients + * @IWL_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS. */ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_PAN = BIT(0), @@ -104,22 +99,15 @@ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_MFP = BIT(2), IWL_UCODE_TLV_FLAGS_P2P = BIT(3), IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), - IWL_UCODE_TLV_FLAGS_NEWBT_COEX = BIT(5), - IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT = BIT(6), IWL_UCODE_TLV_FLAGS_SHORT_BL = BIT(7), - IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8), - IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2 = BIT(9), IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), - IWL_UCODE_TLV_FLAGS_BF_UPDATED = BIT(11), IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12), - IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API = BIT(14), IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15), IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16), - IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17), - IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19), - IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD = BIT(20), + IWL_UCODE_TLV_FLAGS_P2P_PM = BIT(21), IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM = BIT(22), - IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), + IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM = BIT(23), + IWL_UCODE_TLV_FLAGS_EBS_SUPPORT = BIT(25), IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30), @@ -128,9 +116,11 @@ enum iwl_ucode_tlv_flag { /** * enum iwl_ucode_tlv_api - ucode api * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. + * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), + IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), }; /** @@ -183,6 +173,7 @@ enum iwl_ucode_sec { #define IWL_UCODE_SECTION_MAX 12 #define IWL_API_ARRAY_SIZE 1 #define IWL_CAPABILITIES_ARRAY_SIZE 1 +#define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC struct iwl_ucode_capabilities { u32 max_probe_length; diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 6be30c69850619..49963e4a887ee7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -62,6 +62,7 @@ #include #include #include +#include #include "iwl-drv.h" #include "iwl-modparams.h" #include "iwl-nvm-parse.h" @@ -134,12 +135,13 @@ static const u8 iwl_nvm_channels_family_8000[] = { 149, 153, 157, 161, 165, 169, 173, 177, 181 }; -#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) +#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) #define IWL_NUM_CHANNELS_FAMILY_8000 ARRAY_SIZE(iwl_nvm_channels_family_8000) -#define NUM_2GHZ_CHANNELS 14 -#define FIRST_2GHZ_HT_MINUS 5 -#define LAST_2GHZ_HT_PLUS 9 -#define LAST_5GHZ_HT 161 +#define NUM_2GHZ_CHANNELS 14 +#define NUM_2GHZ_CHANNELS_FAMILY_8000 13 +#define FIRST_2GHZ_HT_MINUS 5 +#define LAST_2GHZ_HT_PLUS 9 +#define LAST_5GHZ_HT 161 #define DEFAULT_MAX_TX_POWER 16 @@ -202,21 +204,23 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, struct ieee80211_channel *channel; u16 ch_flags; bool is_5ghz; - int num_of_ch; + int num_of_ch, num_2ghz_channels; const u8 *nvm_chan; if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { num_of_ch = IWL_NUM_CHANNELS; nvm_chan = &iwl_nvm_channels[0]; + num_2ghz_channels = NUM_2GHZ_CHANNELS; } else { num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000; nvm_chan = &iwl_nvm_channels_family_8000[0]; + num_2ghz_channels = NUM_2GHZ_CHANNELS_FAMILY_8000; } for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); - if (ch_idx >= NUM_2GHZ_CHANNELS && + if (ch_idx >= num_2ghz_channels && !data->sku_cap_band_52GHz_enable) ch_flags &= ~NVM_CHANNEL_VALID; @@ -225,7 +229,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, "Ch. %d Flags %x [%sGHz] - No traffic\n", nvm_chan[ch_idx], ch_flags, - (ch_idx >= NUM_2GHZ_CHANNELS) ? + (ch_idx >= num_2ghz_channels) ? "5.2" : "2.4"); continue; } @@ -234,7 +238,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, n_channels++; channel->hw_value = nvm_chan[ch_idx]; - channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ? + channel->band = (ch_idx < num_2ghz_channels) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; channel->center_freq = ieee80211_channel_to_frequency( @@ -242,7 +246,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, /* TODO: Need to be dependent to the NVM */ channel->flags = IEEE80211_CHAN_NO_HT40; - if (ch_idx < NUM_2GHZ_CHANNELS && + if (ch_idx < num_2ghz_channels && (ch_flags & NVM_CHANNEL_40MHZ)) { if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS) channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; @@ -250,7 +254,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; } else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT && (ch_flags & NVM_CHANNEL_40MHZ)) { - if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) + if ((ch_idx - num_2ghz_channels) % 2 == 0) channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; else channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; @@ -447,13 +451,7 @@ static void iwl_set_hw_address(const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const __le16 *nvm_sec) { - u8 hw_addr[ETH_ALEN]; - - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) - memcpy(hw_addr, nvm_sec + HW_ADDR, ETH_ALEN); - else - memcpy(hw_addr, nvm_sec + MAC_ADDRESS_OVERRIDE_FAMILY_8000, - ETH_ALEN); + const u8 *hw_addr = (const u8 *)(nvm_sec + HW_ADDR); /* The byte order is little endian 16 bit, meaning 214365 */ data->hw_addr[0] = hw_addr[1]; @@ -464,6 +462,41 @@ static void iwl_set_hw_address(const struct iwl_cfg *cfg, data->hw_addr[5] = hw_addr[4]; } +static void iwl_set_hw_address_family_8000(const struct iwl_cfg *cfg, + struct iwl_nvm_data *data, + const __le16 *mac_override, + const __le16 *nvm_hw) +{ + const u8 *hw_addr; + + if (mac_override) { + hw_addr = (const u8 *)(mac_override + + MAC_ADDRESS_OVERRIDE_FAMILY_8000); + + /* The byte order is little endian 16 bit, meaning 214365 */ + data->hw_addr[0] = hw_addr[1]; + data->hw_addr[1] = hw_addr[0]; + data->hw_addr[2] = hw_addr[3]; + data->hw_addr[3] = hw_addr[2]; + data->hw_addr[4] = hw_addr[5]; + data->hw_addr[5] = hw_addr[4]; + + if (is_valid_ether_addr(hw_addr)) + return; + } + + /* take the MAC address from the OTP */ + hw_addr = (const u8 *)(nvm_hw + HW_ADDR0_FAMILY_8000); + data->hw_addr[0] = hw_addr[3]; + data->hw_addr[1] = hw_addr[2]; + data->hw_addr[2] = hw_addr[1]; + data->hw_addr[3] = hw_addr[0]; + + hw_addr = (const u8 *)(nvm_hw + HW_ADDR1_FAMILY_8000); + data->hw_addr[4] = hw_addr[1]; + data->hw_addr[5] = hw_addr[0]; +} + struct iwl_nvm_data * iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, @@ -523,7 +556,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, rx_chains); } else { /* MAC address in family 8000 */ - iwl_set_hw_address(cfg, data, mac_override); + iwl_set_hw_address_family_8000(cfg, data, mac_override, nvm_hw); iwl_init_sbands(dev, cfg, data, regulatory, sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index ea29504ac61704..99785c892f963c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -63,6 +63,7 @@ #ifndef __iwl_op_mode_h__ #define __iwl_op_mode_h__ +#include #include struct iwl_op_mode; @@ -112,8 +113,11 @@ struct iwl_cfg; * @stop: stop the op_mode. Must free all the memory allocated. * May sleep * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the - * HCMD this Rx responds to. - * This callback may sleep, it is called from a threaded IRQ handler. + * HCMD this Rx responds to. Can't sleep. + * @napi_add: NAPI initialisation. The transport is fully responsible for NAPI, + * but the higher layers need to know about it (in particular mac80211 to + * to able to call the right NAPI RX functions); this function is needed + * to eventually call netif_napi_add() with higher layer involvement. * @queue_full: notifies that a HW queue is full. * Must be atomic and called with BH disabled. * @queue_not_full: notifies that a HW queue is not full any more. @@ -143,6 +147,11 @@ struct iwl_op_mode_ops { void (*stop)(struct iwl_op_mode *op_mode); int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); + void (*napi_add)(struct iwl_op_mode *op_mode, + struct napi_struct *napi, + struct net_device *napi_dev, + int (*poll)(struct napi_struct *, int), + int weight); void (*queue_full)(struct iwl_op_mode *op_mode, int queue); void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue); bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); @@ -180,7 +189,6 @@ static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd) { - might_sleep(); return op_mode->ops->rx(op_mode, rxb, cmd); } @@ -249,4 +257,15 @@ static inline int iwl_op_mode_exit_d0i3(struct iwl_op_mode *op_mode) return op_mode->ops->exit_d0i3(op_mode); } +static inline void iwl_op_mode_napi_add(struct iwl_op_mode *op_mode, + struct napi_struct *napi, + struct net_device *napi_dev, + int (*poll)(struct napi_struct *, int), + int weight) +{ + if (!op_mode->ops->napi_add) + return; + op_mode->ops->napi_add(op_mode, napi, napi_dev, poll, weight); +} + #endif /* __iwl_op_mode_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 5f657c501406cc..779311080a9ef8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -348,4 +348,12 @@ enum secure_load_status_reg { #define LMPM_SECURE_TIME_OUT (100) +/* Rx FIFO */ +#define RXF_SIZE_ADDR (0xa00c88) +#define RXF_SIZE_BYTE_CND_POS (7) +#define RXF_SIZE_BYTE_CNT_MSK (0x3ff << RXF_SIZE_BYTE_CND_POS) + +#define RXF_LD_FENCE_OFFSET_ADDR (0xa00c10) +#define RXF_FIFO_RD_FENCE_ADDR (0xa00c0c) + #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 8cdb0dd618a6fd..84ad48de6e29e4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -437,8 +437,7 @@ struct iwl_trans; * this one. The op_mode must not configure the HCMD queue. May sleep. * @txq_disable: de-configure a Tx queue to send AMPDUs * Must be atomic - * @wait_tx_queue_empty: wait until all tx queues are empty - * May sleep + * @wait_tx_queue_empty: wait until tx queues are empty. May sleep. * @dbgfs_register: add the dbgfs files under this directory. Files will be * automatically deleted. * @write8: write a u8 to a register at offset ofs from the BAR @@ -464,6 +463,11 @@ struct iwl_trans; * @unref: release a reference previously taken with @ref. Note that * initially the reference count is 1, making an initial @unref * necessary to allow low power states. + * @dump_data: fill a data dump with debug data, maybe containing last + * TX'ed commands and similar. When called with a NULL buffer and + * zero buffer length, provide only the (estimated) required buffer + * length. Return the used buffer length. + * Note that the transport must fill in the proper file headers. */ struct iwl_trans_ops { @@ -490,7 +494,7 @@ struct iwl_trans_ops { void (*txq_disable)(struct iwl_trans *trans, int queue); int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); - int (*wait_tx_queue_empty)(struct iwl_trans *trans); + int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm); void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val); void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val); @@ -512,6 +516,10 @@ struct iwl_trans_ops { u32 value); void (*ref)(struct iwl_trans *trans); void (*unref)(struct iwl_trans *trans); + +#ifdef CONFIG_IWLWIFI_DEBUGFS + u32 (*dump_data)(struct iwl_trans *trans, void *buf, u32 buflen); +#endif }; /** @@ -665,6 +673,16 @@ static inline void iwl_trans_unref(struct iwl_trans *trans) trans->ops->unref(trans); } +#ifdef CONFIG_IWLWIFI_DEBUGFS +static inline u32 iwl_trans_dump_data(struct iwl_trans *trans, + void *buf, u32 buflen) +{ + if (!trans->ops->dump_data) + return 0; + return trans->ops->dump_data(trans, buf, buflen); +} +#endif + static inline int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { @@ -759,12 +777,13 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0); } -static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) +static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, + u32 txq_bm) { if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); - return trans->ops->wait_tx_queue_empty(trans); + return trans->ops->wait_tx_queue_empty(trans, txq_bm); } static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index ccdd3b7c4cce38..c30d7f64ec1e4e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -3,8 +3,9 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o iwlmvm-y += scan.o time-event.o rs.o iwlmvm-y += power.o coex.o -iwlmvm-y += led.o tt.o offloading.o +iwlmvm-y += tt.o offloading.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o +iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmvm-$(CONFIG_PM_SLEEP) += d3.o ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index fa858d548d13c0..4284672d039761 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -104,11 +104,8 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { #define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65) #define BT_ANTENNA_COUPLING_THRESHOLD (30) -int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) +static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) { - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) - return 0; - return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC, sizeof(struct iwl_bt_coex_prio_tbl_cmd), &iwl_bt_prio_tbl); @@ -573,8 +570,9 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) int ret; u32 flags; - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) - return 0; + ret = iwl_send_bt_prio_tbl(mvm); + if (ret) + return ret; bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); if (!bt_cmd) @@ -582,10 +580,12 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) cmd.data[0] = bt_cmd; bt_cmd->max_kill = 5; - bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD, - bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling, - bt_cmd->bt4_tx_tx_delta_freq_thr = 15, - bt_cmd->bt4_tx_rx_max_freq0 = 15, + bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD; + bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling; + bt_cmd->bt4_tx_tx_delta_freq_thr = 15; + bt_cmd->bt4_tx_rx_max_freq0 = 15; + bt_cmd->override_primary_lut = BT_COEX_INVALID_LUT; + bt_cmd->override_secondary_lut = BT_COEX_INVALID_LUT; flags = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE; @@ -611,14 +611,14 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); if (IWL_MVM_BT_COEX_CORUNNING) { - bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_CORUN_LUT_20 | - BT_VALID_CORUN_LUT_40); + bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_CORUN_LUT_20 | + BT_VALID_CORUN_LUT_40); bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING); } if (IWL_MVM_BT_COEX_MPLUT) { bt_cmd->flags |= cpu_to_le32(BT_COEX_MPLUT); - bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); + bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); } if (mvm->cfg->bt_shared_single_ant) @@ -1215,6 +1215,17 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT; } +bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, + enum ieee80211_band band) +{ + u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading); + + if (band != IEEE80211_BAND_2GHZ) + return false; + + return bt_activity >= BT_LOW_TRAFFIC; +} + u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *info, u8 ac) { @@ -1249,9 +1260,6 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) { - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) - return; - iwl_mvm_bt_coex_notif_handle(mvm); } diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index e56f5a0edf8553..7694472a303e00 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -744,10 +744,8 @@ static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm, int err; u32 size; - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) { - cmd.data[0] = &query_cmd; - cmd.len[0] = sizeof(query_cmd); - } + cmd.data[0] = &query_cmd; + cmd.len[0] = sizeof(query_cmd); err = iwl_mvm_send_cmd(mvm, &cmd); if (err) @@ -758,10 +756,8 @@ static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm, err = -EINVAL; } else { err = le16_to_cpup((__le16 *)cmd.resp_pkt->data); - /* new API returns next, not last-used seqno */ - if (mvm->fw->ucode_capa.flags & - IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) - err = (u16) (err - 0x10); + /* firmware returns next, not last-used seqno */ + err = (u16) (err - 0x10); } iwl_free_resp(&cmd); @@ -785,10 +781,6 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvmvif->seqno_valid = false; - if (!(mvm->fw->ucode_capa.flags & - IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API)) - return; - if (iwl_mvm_send_cmd_pdu(mvm, NON_QOS_TX_COUNTER_CMD, CMD_SYNC, sizeof(query_cmd), &query_cmd)) IWL_ERR(mvm, "failed to set non-QoS seqno\n"); @@ -1082,6 +1074,15 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + if (iwl_mvm_is_d0i3_supported(mvm)) { + mutex_lock(&mvm->d0i3_suspend_mutex); + __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); + mutex_unlock(&mvm->d0i3_suspend_mutex); + return 0; + } + return __iwl_mvm_suspend(hw, wowlan, false); } @@ -1277,7 +1278,7 @@ static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs, } static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, - struct iwl_wowlan_status_v6 *status) + struct iwl_wowlan_status *status) { union iwl_all_tsc_rsc *rsc = &status->gtk.rsc.all_tsc_rsc; @@ -1294,7 +1295,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, } struct iwl_mvm_d3_gtk_iter_data { - struct iwl_wowlan_status_v6 *status; + struct iwl_wowlan_status *status; void *last_gtk; u32 cipher; bool find_phase, unhandled_cipher; @@ -1370,7 +1371,7 @@ static void iwl_mvm_d3_update_gtks(struct ieee80211_hw *hw, static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_wowlan_status_v6 *status) + struct iwl_wowlan_status *status) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_d3_gtk_iter_data gtkdata = { @@ -1468,7 +1469,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, .flags = CMD_SYNC | CMD_WANT_SKB, }; struct iwl_wowlan_status_data status; - struct iwl_wowlan_status_v6 *status_v6; + struct iwl_wowlan_status *fw_status; int ret, len, status_size, i; bool keep; struct ieee80211_sta *ap_sta; @@ -1505,10 +1506,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, if (!cmd.resp_pkt) goto out_unlock; - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) - status_size = sizeof(struct iwl_wowlan_status_v6); - else - status_size = sizeof(struct iwl_wowlan_status_v4); + status_size = sizeof(*fw_status); len = iwl_rx_packet_payload_len(cmd.resp_pkt); if (len < status_size) { @@ -1516,35 +1514,18 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, goto out_free_resp; } - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) { - status_v6 = (void *)cmd.resp_pkt->data; - - status.pattern_number = le16_to_cpu(status_v6->pattern_number); - for (i = 0; i < 8; i++) - status.qos_seq_ctr[i] = - le16_to_cpu(status_v6->qos_seq_ctr[i]); - status.wakeup_reasons = le32_to_cpu(status_v6->wakeup_reasons); - status.wake_packet_length = - le32_to_cpu(status_v6->wake_packet_length); - status.wake_packet_bufsize = - le32_to_cpu(status_v6->wake_packet_bufsize); - status.wake_packet = status_v6->wake_packet; - } else { - struct iwl_wowlan_status_v4 *status_v4; - status_v6 = NULL; - status_v4 = (void *)cmd.resp_pkt->data; - - status.pattern_number = le16_to_cpu(status_v4->pattern_number); - for (i = 0; i < 8; i++) - status.qos_seq_ctr[i] = - le16_to_cpu(status_v4->qos_seq_ctr[i]); - status.wakeup_reasons = le32_to_cpu(status_v4->wakeup_reasons); - status.wake_packet_length = - le32_to_cpu(status_v4->wake_packet_length); - status.wake_packet_bufsize = - le32_to_cpu(status_v4->wake_packet_bufsize); - status.wake_packet = status_v4->wake_packet; - } + fw_status = (void *)cmd.resp_pkt->data; + + status.pattern_number = le16_to_cpu(fw_status->pattern_number); + for (i = 0; i < 8; i++) + status.qos_seq_ctr[i] = + le16_to_cpu(fw_status->qos_seq_ctr[i]); + status.wakeup_reasons = le32_to_cpu(fw_status->wakeup_reasons); + status.wake_packet_length = + le32_to_cpu(fw_status->wake_packet_length); + status.wake_packet_bufsize = + le32_to_cpu(fw_status->wake_packet_bufsize); + status.wake_packet = fw_status->wake_packet; if (len != status_size + ALIGN(status.wake_packet_bufsize, 4)) { IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); @@ -1571,7 +1552,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, iwl_mvm_report_wakeup_reasons(mvm, vif, &status); - keep = iwl_mvm_setup_connection_keep(mvm, vif, status_v6); + keep = iwl_mvm_setup_connection_keep(mvm, vif, fw_status); iwl_free_resp(&cmd); return keep; @@ -1674,6 +1655,19 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + if (iwl_mvm_is_d0i3_supported(mvm)) { + bool exit_now; + + mutex_lock(&mvm->d0i3_suspend_mutex); + __clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); + exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP, + &mvm->d0i3_suspend_flags); + mutex_unlock(&mvm->d0i3_suspend_mutex); + if (exit_now) + _iwl_mvm_exit_d0i3(mvm); + return 0; + } + return __iwl_mvm_resume(mvm, false); } diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 9b59e1d7ae71ea..6047cfdafb959e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -103,10 +103,6 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val); dbgfs_pm->tx_data_timeout = val; break; - case MVM_DEBUGFS_PM_DISABLE_POWER_OFF: - IWL_DEBUG_POWER(mvm, "disable_power_off=%d\n", val); - dbgfs_pm->disable_power_off = val; - break; case MVM_DEBUGFS_PM_LPRX_ENA: IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled"); dbgfs_pm->lprx_ena = val; @@ -154,12 +150,6 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf, if (sscanf(buf + 16, "%d", &val) != 1) return -EINVAL; param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT; - } else if (!strncmp("disable_power_off=", buf, 18) && - !(mvm->fw->ucode_capa.flags & - IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) { - if (sscanf(buf + 18, "%d", &val) != 1) - return -EINVAL; - param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF; } else if (!strncmp("lprx=", buf, 5)) { if (sscanf(buf + 5, "%d", &val) != 1) return -EINVAL; @@ -592,8 +582,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return; } - if ((mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT) && - iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && + if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) || (vif->type == NL80211_IFTYPE_STATION && vif->p2p && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM))) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 1b52deea60812e..bef487bb880ee2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -67,7 +67,7 @@ #include "iwl-io.h" #include "iwl-prph.h" #include "debugfs.h" -#include "fw-error-dump.h" +#include "iwl-fw-error-dump.h" static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) @@ -136,9 +136,6 @@ static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file) file->private_data = mvm->fw_error_dump; mvm->fw_error_dump = NULL; - kfree(mvm->fw_error_sram); - mvm->fw_error_sram = NULL; - mvm->fw_error_sram_len = 0; ret = 0; out: @@ -1004,6 +1001,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); PRINT_MVM_REF(IWL_MVM_REF_USER); + PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -1108,9 +1106,9 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); static const struct file_operations iwl_dbgfs_fw_error_dump_ops = { - .open = iwl_dbgfs_fw_error_dump_open, - .read = iwl_dbgfs_fw_error_dump_read, - .release = iwl_dbgfs_fw_error_dump_release, + .open = iwl_dbgfs_fw_error_dump_open, + .read = iwl_dbgfs_fw_error_dump_read, + .release = iwl_dbgfs_fw_error_dump_release, }; #ifdef CONFIG_IWLWIFI_BCAST_FILTERING @@ -1138,9 +1136,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD) - MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, - S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, + S_IRUSR | S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index 21877e5966a809..5fe82c29c8ad07 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h @@ -141,7 +141,8 @@ enum iwl_bt_coex_lut_type { BT_COEX_TX_DIS_LUT, BT_COEX_MAX_LUT, -}; + BT_COEX_INVALID_LUT = 0xff, +}; /* BT_COEX_DECISION_LUT_INDEX_API_E_VER_1 */ #define BT_COEX_LUT_SIZE (12) #define BT_COEX_CORUN_LUT_SIZE (32) @@ -154,19 +155,23 @@ enum iwl_bt_coex_lut_type { * @flags:&enum iwl_bt_coex_flags * @max_kill: * @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power - * @bt4_antenna_isolation: - * @bt4_antenna_isolation_thr: - * @bt4_tx_tx_delta_freq_thr: - * @bt4_tx_rx_max_freq0: - * @bt_prio_boost: + * @override_primary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT + * should be set by default + * @override_secondary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT + * should be set by default + * @bt4_antenna_isolation: antenna isolation + * @bt4_antenna_isolation_thr: antenna threshold value + * @bt4_tx_tx_delta_freq_thr: TxTx delta frequency + * @bt4_tx_rx_max_freq0: TxRx max frequency + * @bt_prio_boost: BT priority boost registers * @wifi_tx_prio_boost: SW boost of wifi tx priority * @wifi_rx_prio_boost: SW boost of wifi rx priority - * @kill_ack_msk: - * @kill_cts_msk: - * @decision_lut: - * @bt4_multiprio_lut: - * @bt4_corun_lut20: - * @bt4_corun_lut40: + * @kill_ack_msk: kill ACK mask. 1 - Tx ACK, 0 - kill Tx of ACK. + * @kill_cts_msk: kill CTS mask. 1 - Tx CTS, 0 - kill Tx of CTS. + * @decision_lut: PTA decision LUT, per Prio-Ch + * @bt4_multiprio_lut: multi priority LUT configuration + * @bt4_corun_lut20: co-running 20 MHz LUT configuration + * @bt4_corun_lut40: co-running 40 MHz LUT configuration * @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk * * The structure is used for the BT_COEX command. @@ -175,7 +180,8 @@ struct iwl_bt_coex_cmd { __le32 flags; u8 max_kill; u8 bt_reduced_tx_power; - u8 reserved[2]; + u8 override_primary_lut; + u8 override_secondary_lut; u8 bt4_antenna_isolation; u8 bt4_antenna_isolation_thr; @@ -194,7 +200,7 @@ struct iwl_bt_coex_cmd { __le32 bt4_corun_lut40[BT_COEX_CORUN_LUT_SIZE]; __le32 valid_bit_msk; -} __packed; /* BT_COEX_CMD_API_S_VER_3 */ +} __packed; /* BT_COEX_CMD_API_S_VER_5 */ /** * struct iwl_bt_coex_ci_cmd - bt coex channel inhibition command @@ -282,7 +288,7 @@ enum iwl_bt_activity_grading { BT_ON_NO_CONNECTION = 1, BT_LOW_TRAFFIC = 2, BT_HIGH_TRAFFIC = 3, -}; +}; /* BT_COEX_BT_ACTIVITY_GRADING_API_E_VER_1 */ /** * struct iwl_bt_coex_profile_notif - notification about BT coex @@ -310,7 +316,7 @@ struct iwl_bt_coex_profile_notif { __le32 primary_ch_lut; __le32 secondary_ch_lut; __le32 bt_activity_grading; -} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_2 */ +} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_3 */ enum iwl_bt_coex_prio_table_event { BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0, diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index 10fcc1a79ebddf..13696fe419b778 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h @@ -345,21 +345,6 @@ enum iwl_wowlan_wakeup_reason { IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12), }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ -struct iwl_wowlan_status_v4 { - __le64 replay_ctr; - __le16 pattern_number; - __le16 non_qos_seq_ctr; - __le16 qos_seq_ctr[8]; - __le32 wakeup_reasons; - __le32 rekey_status; - __le32 num_of_gtk_rekeys; - __le32 transmitted_ndps; - __le32 received_beacons; - __le32 wake_packet_length; - __le32 wake_packet_bufsize; - u8 wake_packet[]; /* can be truncated from _length to _bufsize */ -} __packed; /* WOWLAN_STATUSES_API_S_VER_4 */ - struct iwl_wowlan_gtk_status { u8 key_index; u8 reserved[3]; @@ -368,7 +353,7 @@ struct iwl_wowlan_gtk_status { struct iwl_wowlan_rsc_tsc_params_cmd rsc; } __packed; -struct iwl_wowlan_status_v6 { +struct iwl_wowlan_status { struct iwl_wowlan_gtk_status gtk; __le64 replay_ctr; __le16 pattern_number; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index 39148b5bb33262..8bb5b94bf96396 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h @@ -334,7 +334,7 @@ enum { */ struct iwl_lq_cmd { u8 sta_id; - u8 reserved1; + u8 reduced_tpc; u16 control; /* LINK_QUAL_GENERAL_PARAMS_API_S_VER_1 */ u8 flags; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 9426905de6b283..6959fda3fe09d0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -169,8 +169,12 @@ enum iwl_scan_type { SCAN_TYPE_DISCOVERY_FORCED = 6, }; /* SCAN_ACTIVITY_TYPE_E_VER_1 */ -/* Maximal number of channels to scan */ -#define MAX_NUM_SCAN_CHANNELS 0x24 +/** + * Maximal number of channels to scan + * it should be equal to: + * max(IWL_NUM_CHANNELS, IWL_NUM_CHANNELS_FAMILY_8000) + */ +#define MAX_NUM_SCAN_CHANNELS 50 /** * struct iwl_scan_cmd - scan request command @@ -183,9 +187,9 @@ enum iwl_scan_type { * this number of packets were received (typically 1) * @passive2active: is auto switching from passive to active during scan allowed * @rxchain_sel_flags: RXON_RX_CHAIN_* - * @max_out_time: in usecs, max out of serving channel time + * @max_out_time: in TUs, max out of serving channel time * @suspend_time: how long to pause scan when returning to service channel: - * bits 0-19: beacon interal in usecs (suspend before executing) + * bits 0-19: beacon interal in TUs (suspend before executing) * bits 20-23: reserved * bits 24-31: number of beacons (suspend between channels) * @rxon_flags: RXON_FLG_* @@ -383,8 +387,8 @@ enum scan_framework_client { * @quiet_plcp_th: quiet channel num of packets threshold * @good_CRC_th: passive to active promotion threshold * @rx_chain: RXON rx chain. - * @max_out_time: max uSec to be out of assoceated channel - * @suspend_time: pause scan this long when returning to service channel + * @max_out_time: max TUs to be out of assoceated channel + * @suspend_time: pause scan this TUs when returning to service channel * @flags: RXON flags * @filter_flags: RXONfilter * @tx_cmd: tx command for active scan; for 2GHz and for 5GHz. @@ -534,13 +538,16 @@ struct iwl_scan_offload_schedule { * * IWL_SCAN_OFFLOAD_FLAG_PASS_ALL: pass all results - no filtering. * IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan. - * IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN: use energy based scan before partial scan - * on A band. + * IWL_SCAN_OFFLOAD_FLAG_EBS_QUICK_MODE: EBS duration is 100mSec - typical + * beacon period. Finding channel activity in this mode is not guaranteed. + * IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE: EBS duration is 200mSec. + * Assuming beacon period is 100ms finding channel activity is guaranteed. */ enum iwl_scan_offload_flags { IWL_SCAN_OFFLOAD_FLAG_PASS_ALL = BIT(0), IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL = BIT(2), - IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN = BIT(3), + IWL_SCAN_OFFLOAD_FLAG_EBS_QUICK_MODE = BIT(5), + IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE = BIT(6), }; /** @@ -563,17 +570,24 @@ enum iwl_scan_offload_compleate_status { IWL_SCAN_OFFLOAD_ABORTED = 2, }; +enum iwl_scan_ebs_status { + IWL_SCAN_EBS_SUCCESS, + IWL_SCAN_EBS_FAILED, + IWL_SCAN_EBS_CHAN_NOT_FOUND, +}; + /** * iwl_scan_offload_complete - SCAN_OFFLOAD_COMPLETE_NTF_API_S_VER_1 * @last_schedule_line: last schedule line executed (fast or regular) * @last_schedule_iteration: last scan iteration executed before scan abort * @status: enum iwl_scan_offload_compleate_status + * @ebs_status: last EBS status, see IWL_SCAN_EBS_* */ struct iwl_scan_offload_complete { u8 last_schedule_line; u8 last_schedule_iteration; u8 status; - u8 reserved; + u8 ebs_status; } __packed; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h index d636478672626e..39cebee8016fea 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h @@ -255,22 +255,19 @@ struct iwl_mvm_keyinfo { } __packed; /** - * struct iwl_mvm_add_sta_cmd_v5 - Add/modify a station in the fw's sta table. + * struct iwl_mvm_add_sta_cmd - Add/modify a station in the fw's sta table. * ( REPLY_ADD_STA = 0x18 ) * @add_modify: 1: modify existing, 0: add new station - * @unicast_tx_key_id: unicast tx key id. Relevant only when unicast key sent - * @multicast_tx_key_id: multicast tx key id. Relevant only when multicast key - * sent + * @awake_acs: + * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable + * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. * @mac_id_n_color: the Mac context this station belongs to * @addr[ETH_ALEN]: station's MAC address * @sta_id: index of station in uCode's station table * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave * alone. 1 - modify, 0 - don't change. - * @key: look at %iwl_mvm_keyinfo * @station_flags: look at %iwl_sta_flags * @station_flags_msk: what of %station_flags have changed - * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable - * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. * @add_immediate_ba_tid: tid for which to add block-ack support (Rx) * Set %STA_MODIFY_ADD_BA_TID to use this field, and also set * add_immediate_ba_ssn. @@ -294,40 +291,7 @@ struct iwl_mvm_keyinfo { * ADD_STA sets up the table entry for one station, either creating a new * entry, or modifying a pre-existing one. */ -struct iwl_mvm_add_sta_cmd_v5 { - u8 add_modify; - u8 unicast_tx_key_id; - u8 multicast_tx_key_id; - u8 reserved1; - __le32 mac_id_n_color; - u8 addr[ETH_ALEN]; - __le16 reserved2; - u8 sta_id; - u8 modify_mask; - __le16 reserved3; - struct iwl_mvm_keyinfo key; - __le32 station_flags; - __le32 station_flags_msk; - __le16 tid_disable_tx; - __le16 reserved4; - u8 add_immediate_ba_tid; - u8 remove_immediate_ba_tid; - __le16 add_immediate_ba_ssn; - __le16 sleep_tx_count; - __le16 sleep_state_flags; - __le16 assoc_id; - __le16 beamform_flags; - __le32 tfd_queue_msk; -} __packed; /* ADD_STA_CMD_API_S_VER_5 */ - -/** - * struct iwl_mvm_add_sta_cmd_v7 - Add / modify a station - * VER_7 of this command is quite similar to VER_5 except - * exclusion of all fields related to the security key installation. - * It only differs from VER_6 by the "awake_acs" field that is - * reserved and ignored in VER_6. - */ -struct iwl_mvm_add_sta_cmd_v7 { +struct iwl_mvm_add_sta_cmd { u8 add_modify; u8 awake_acs; __le16 tid_disable_tx; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index 8e122f3a7a74e8..6cc5f52b807f1b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h @@ -482,7 +482,8 @@ struct iwl_mvm_tx_resp { u8 pa_integ_res_b[3]; u8 pa_integ_res_c[3]; __le16 measurement_req_id; - __le16 reserved; + u8 reduced_tpc; + u8 reserved; __le32 tfd_info; __le16 seq_ctl; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 6e75b52588de3c..309a9b9a94fecc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -71,6 +71,7 @@ #include "fw-api-power.h" #include "fw-api-d3.h" #include "fw-api-coex.h" +#include "fw-api-scan.h" /* maximal number of Tx queues in any platform */ #define IWL_MVM_MAX_QUEUES 20 @@ -604,52 +605,7 @@ enum { TE_V1_NOTIF_INTERNAL_FRAG_END = BIT(7), }; /* MAC_EVENT_ACTION_API_E_VER_2 */ - -/** - * struct iwl_time_event_cmd_api_v1 - configuring Time Events - * with struct MAC_TIME_EVENT_DATA_API_S_VER_1 (see also - * with version 2. determined by IWL_UCODE_TLV_FLAGS) - * ( TIME_EVENT_CMD = 0x29 ) - * @id_and_color: ID and color of the relevant MAC - * @action: action to perform, one of FW_CTXT_ACTION_* - * @id: this field has two meanings, depending on the action: - * If the action is ADD, then it means the type of event to add. - * For all other actions it is the unique event ID assigned when the - * event was added by the FW. - * @apply_time: When to start the Time Event (in GP2) - * @max_delay: maximum delay to event's start (apply time), in TU - * @depends_on: the unique ID of the event we depend on (if any) - * @interval: interval between repetitions, in TU - * @interval_reciprocal: 2^32 / interval - * @duration: duration of event in TU - * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS - * @dep_policy: one of TE_V1_INDEPENDENT, TE_V1_DEP_OTHER, TE_V1_DEP_TSF - * and TE_V1_EVENT_SOCIOPATHIC - * @is_present: 0 or 1, are we present or absent during the Time Event - * @max_frags: maximal number of fragments the Time Event can be divided to - * @notify: notifications using TE_V1_NOTIF_* (whom to notify when) - */ -struct iwl_time_event_cmd_v1 { - /* COMMON_INDEX_HDR_API_S_VER_1 */ - __le32 id_and_color; - __le32 action; - __le32 id; - /* MAC_TIME_EVENT_DATA_API_S_VER_1 */ - __le32 apply_time; - __le32 max_delay; - __le32 dep_policy; - __le32 depends_on; - __le32 is_present; - __le32 max_frags; - __le32 interval; - __le32 interval_reciprocal; - __le32 duration; - __le32 repeat; - __le32 notify; -} __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_1 */ - - -/* Time event - defines for command API v2 */ +/* Time event - defines for command API */ /* * @TE_V2_FRAG_NONE: fragmentation of the time event is NOT allowed. @@ -680,7 +636,7 @@ enum { #define TE_V2_PLACEMENT_POS 12 #define TE_V2_ABSENCE_POS 15 -/* Time event policy values (for time event cmd api v2) +/* Time event policy values * A notification (both event and fragment) includes a status indicating weather * the FW was able to schedule the event or not. For fragment start/end * notification the status is always success. There is no start/end fragment @@ -727,7 +683,7 @@ enum { }; /** - * struct iwl_time_event_cmd_api_v2 - configuring Time Events + * struct iwl_time_event_cmd_api - configuring Time Events * with struct MAC_TIME_EVENT_DATA_API_S_VER_2 (see also * with version 1. determined by IWL_UCODE_TLV_FLAGS) * ( TIME_EVENT_CMD = 0x29 ) @@ -750,7 +706,7 @@ enum { * TE_EVENT_SOCIOPATHIC * using TE_ABSENCE and using TE_NOTIF_* */ -struct iwl_time_event_cmd_v2 { +struct iwl_time_event_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ __le32 id_and_color; __le32 action; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 7ce20062f32d44..34ae3f32b300a3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -288,14 +288,14 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) goto error; } - ret = iwl_send_bt_prio_tbl(mvm); + ret = iwl_send_bt_init_conf(mvm); if (ret) goto error; /* Read the NVM only at driver load time, no need to do this twice */ if (read_nvm) { /* Read nvm */ - ret = iwl_nvm_init(mvm); + ret = iwl_nvm_init(mvm, true); if (ret) { IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); goto error; @@ -424,10 +424,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) goto error; - ret = iwl_send_bt_prio_tbl(mvm); - if (ret) - goto error; - ret = iwl_send_bt_init_conf(mvm); if (ret) goto error; @@ -468,12 +464,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm) /* Initialize tx backoffs to the minimal possible */ iwl_mvm_tt_tx_backoff(mvm, 0); - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) { - ret = iwl_power_legacy_set_cam_mode(mvm); - if (ret) - goto error; - } - ret = iwl_mvm_power_update_device(mvm); if (ret) goto error; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 9ccec10bba1662..56cf58e9569891 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -667,12 +667,9 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, if (vif->bss_conf.qos) cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); - /* Don't use cts to self as the fw doesn't support it currently. */ if (vif->bss_conf.use_cts_prot) { cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT); - if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8) - cmd->protection_flags |= - cpu_to_le32(MAC_PROT_FLG_SELF_CTS_EN); + cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_SELF_CTS_EN); } IWL_DEBUG_RATE(mvm, "use_cts_prot %d, ht_operation_mode %d\n", vif->bss_conf.use_cts_prot, @@ -1240,11 +1237,23 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, u32 rate __maybe_unused = le32_to_cpu(beacon->beacon_notify_hdr.initial_rate); + lockdep_assert_held(&mvm->mutex); + IWL_DEBUG_RX(mvm, "beacon status %#x retries:%d tsf:0x%16llX rate:%d\n", status & TX_STATUS_MSK, beacon->beacon_notify_hdr.failure_frame, le64_to_cpu(beacon->tsf), rate); + + if (unlikely(mvm->csa_vif && mvm->csa_vif->csa_active)) { + if (!ieee80211_csa_is_complete(mvm->csa_vif)) { + iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm->csa_vif); + } else { + ieee80211_csa_finish(mvm->csa_vif); + mvm->csa_vif = NULL; + } + } + return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index f0cebf12c7b841..63868282bae5c5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -276,6 +276,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_TIMING_BEACON_ONLY | IEEE80211_HW_CONNECTION_MONITOR | + IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_SUPPORTS_STATIC_SMPS; @@ -285,6 +286,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IEEE80211_RADIOTAP_MCS_HAVE_STBC; hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC; hw->rate_control_algorithm = "iwl-mvm-rs"; + hw->uapsd_queues = IWL_UAPSD_AC_INFO; + hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; /* * Enable 11w if advertised by firmware and software crypto @@ -295,11 +298,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) !iwlwifi_mod_params.sw_crypto) hw->flags |= IEEE80211_HW_MFP_CAPABLE; - if (0 && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT) { - hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; - hw->uapsd_queues = IWL_UAPSD_AC_INFO; - hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; - } + /* Disable uAPSD due to firmware issues */ + if (true) + hw->flags &= ~IEEE80211_HW_SUPPORTS_UAPSD; hw->sta_data_size = sizeof(struct iwl_mvm_sta); hw->vif_data_size = sizeof(struct iwl_mvm_vif); @@ -309,11 +310,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_P2P_DEVICE); - - /* IBSS has bugs in older versions */ - if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8) - hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | @@ -322,6 +320,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_CSA_FLOW) + hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; hw->wiphy->n_iface_combinations = ARRAY_SIZE(iwl_mvm_iface_combinations); @@ -365,14 +366,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) else hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) { - hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; - hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; - hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; - /* we create the 802.11 header and zero length SSID IE. */ - hw->wiphy->max_sched_scan_ie_len = - SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2; - } + hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; + hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; + /* we create the 802.11 header and zero length SSID IE. */ + hw->wiphy->max_sched_scan_ie_len = SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2; hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | NL80211_FEATURE_P2P_GO_OPPPS; @@ -386,7 +384,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) } #ifdef CONFIG_PM_SLEEP - if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len && + if (iwl_mvm_is_d0i3_supported(mvm) && + device_can_wakeup(mvm->trans->dev)) { + mvm->wowlan.flags = WIPHY_WOWLAN_ANY; + hw->wiphy->wowlan = &mvm->wowlan; + } else if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len && mvm->trans->ops->d3_suspend && mvm->trans->ops->d3_resume && device_can_wakeup(mvm->trans->dev)) { @@ -540,13 +542,22 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, return -EACCES; /* return from D0i3 before starting a new Tx aggregation */ - if (action == IEEE80211_AMPDU_TX_START) { + switch (action) { + case IEEE80211_AMPDU_TX_START: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + case IEEE80211_AMPDU_TX_OPERATIONAL: iwl_mvm_ref(mvm, IWL_MVM_REF_TX_AGG); tx_agg_ref = true; /* - * wait synchronously until D0i3 exit to get the correct - * sequence number for the tid + * for tx start, wait synchronously until D0i3 exit to + * get the correct sequence number for the tid. + * additionally, some other ampdu actions use direct + * target access, which is not handled automatically + * by the trans layer (unlike commands), so wait for + * d0i3 exit in these cases as well. */ if (!wait_event_timeout(mvm->d0i3_exit_waitq, !test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status), HZ)) { @@ -554,6 +565,9 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG); return -EIO; } + break; + default: + break; } mutex_lock(&mvm->mutex); @@ -827,8 +841,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, goto out_remove_mac; if (!mvm->bf_allowed_vif && - vif->type == NL80211_IFTYPE_STATION && !vif->p2p && - mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED){ + vif->type == NL80211_IFTYPE_STATION && !vif->p2p) { mvm->bf_allowed_vif = mvmvif; vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | IEEE80211_VIF_SUPPORTS_CQM_RSSI; @@ -1223,6 +1236,10 @@ static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING)) return 0; + /* bcast filtering isn't supported for P2P client */ + if (vif->p2p) + return 0; + if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) return 0; @@ -1697,6 +1714,11 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, ret = iwl_mvm_add_sta(mvm, vif, sta); } else if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_AUTH) { + /* + * EBS may be disabled due to previous failures reported by FW. + * Reset EBS status here assuming environment has been changed. + */ + mvm->last_ebs_successful = true; ret = 0; } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) { @@ -1807,6 +1829,11 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); + if (iwl_mvm_is_associated(mvm)) { + ret = -EBUSY; + goto out; + } + switch (mvm->scan_status) { case IWL_MVM_SCAN_OS: IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n"); @@ -2179,6 +2206,11 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, switch (vif->type) { case NL80211_IFTYPE_AP: + /* Unless it's a CSA flow we have nothing to do here */ + if (vif->csa_active) { + mvmvif->ap_ibss_active = true; + break; + } case NL80211_IFTYPE_ADHOC: /* * The AP binding flow is handled as part of the start_ap flow @@ -2215,6 +2247,12 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, goto out_remove_binding; } + /* Handle binding during CSA */ + if (vif->type == NL80211_IFTYPE_AP) { + iwl_mvm_update_quotas(mvm, vif); + iwl_mvm_mac_ctxt_changed(mvm, vif); + } + goto out_unlock; out_remove_binding: @@ -2239,13 +2277,20 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); switch (vif->type) { - case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: goto out_unlock; case NL80211_IFTYPE_MONITOR: mvmvif->monitor_active = false; iwl_mvm_update_quotas(mvm, NULL); break; + case NL80211_IFTYPE_AP: + /* This part is triggered only during CSA */ + if (!vif->csa_active || !mvmvif->ap_ibss_active) + goto out_unlock; + + mvmvif->ap_ibss_active = false; + iwl_mvm_update_quotas(mvm, NULL); + /*TODO: bt_coex notification here? */ default: break; } @@ -2341,6 +2386,53 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, } #endif +static void iwl_mvm_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + mutex_lock(&mvm->mutex); + if (WARN(mvm->csa_vif && mvm->csa_vif->csa_active, + "Another CSA is already in progress")) + goto out_unlock; + + IWL_DEBUG_MAC80211(mvm, "CSA started to freq %d\n", + chandef->center_freq1); + mvm->csa_vif = vif; + +out_unlock: + mutex_unlock(&mvm->mutex); +} + +static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u32 queues, bool drop) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_mvm_vif *mvmvif; + struct iwl_mvm_sta *mvmsta; + + if (!vif || vif->type != NL80211_IFTYPE_STATION) + return; + + mutex_lock(&mvm->mutex); + mvmvif = iwl_mvm_vif_from_mac80211(vif); + mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id); + + if (WARN_ON_ONCE(!mvmsta)) + goto done; + + if (drop) { + if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true)) + IWL_ERR(mvm, "flush request fail\n"); + } else { + iwl_trans_wait_tx_queue_empty(mvm->trans, + mvmsta->tfd_queue_msk); + } +done: + mutex_unlock(&mvm->mutex); +} + const struct ieee80211_ops iwl_mvm_hw_ops = { .tx = iwl_mvm_mac_tx, .ampdu_action = iwl_mvm_mac_ampdu_action, @@ -2364,6 +2456,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .sta_rc_update = iwl_mvm_sta_rc_update, .conf_tx = iwl_mvm_mac_conf_tx, .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, + .flush = iwl_mvm_mac_flush, .sched_scan_start = iwl_mvm_mac_sched_scan_start, .sched_scan_stop = iwl_mvm_mac_sched_scan_stop, .set_key = iwl_mvm_mac_set_key, @@ -2383,6 +2476,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .set_tim = iwl_mvm_set_tim, + .channel_switch_beacon = iwl_mvm_channel_switch_beacon, + CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) #ifdef CONFIG_PM_SLEEP diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d564233a65da61..d93857080e492a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -164,7 +164,6 @@ enum iwl_dbgfs_pm_mask { MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS = BIT(2), MVM_DEBUGFS_PM_RX_DATA_TIMEOUT = BIT(3), MVM_DEBUGFS_PM_TX_DATA_TIMEOUT = BIT(4), - MVM_DEBUGFS_PM_DISABLE_POWER_OFF = BIT(5), MVM_DEBUGFS_PM_LPRX_ENA = BIT(6), MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7), MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8), @@ -177,7 +176,6 @@ struct iwl_dbgfs_pm { u32 tx_data_timeout; bool skip_over_dtim; u8 skip_dtim_periods; - bool disable_power_off; bool lprx_ena; u32 lprx_rssi_threshold; bool snooze_ena; @@ -232,6 +230,7 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_USER, IWL_MVM_REF_TX, IWL_MVM_REF_TX_AGG, + IWL_MVM_REF_EXIT_WORK, IWL_MVM_REF_COUNT, }; @@ -265,6 +264,7 @@ struct iwl_mvm_vif_bf_data { * @uploaded: indicates the MAC context has been added to the device * @ap_ibss_active: indicates that AP/IBSS is configured and that the interface * should get quota etc. + * @pm_enabled - Indicate if MAC power management is allowed * @monitor_active: indicates that monitor context is configured, and that the * interface should get quota etc. * @low_latency: indicates that this interface is in low-latency mode @@ -283,6 +283,7 @@ struct iwl_mvm_vif { bool uploaded; bool ap_ibss_active; + bool pm_enabled; bool monitor_active; bool low_latency; struct iwl_mvm_vif_bf_data bf_data; @@ -451,6 +452,11 @@ struct iwl_mvm_frame_stats { int last_frame_idx; }; +enum { + D0I3_DEFER_WAKEUP, + D0I3_PENDING_WAKEUP, +}; + struct iwl_mvm { /* for logger access */ struct device *dev; @@ -535,6 +541,8 @@ struct iwl_mvm { /* Internal station */ struct iwl_mvm_int_sta aux_sta; + bool last_ebs_successful; + u8 scan_last_antenna_idx; /* to toggle TX between antennas */ u8 mgmt_last_antenna_idx; @@ -578,8 +586,12 @@ struct iwl_mvm { void *fw_error_dump; void *fw_error_sram; u32 fw_error_sram_len; + u32 *fw_error_rxf; + u32 fw_error_rxf_len; +#ifdef CONFIG_IWLWIFI_LEDS struct led_classdev led; +#endif struct ieee80211_vif *p2p_device_vif; @@ -601,6 +613,9 @@ struct iwl_mvm { bool d0i3_offloading; struct work_struct d0i3_exit_work; struct sk_buff_head d0i3_tx; + /* protect d0i3_suspend_flags */ + struct mutex d0i3_suspend_mutex; + unsigned long d0i3_suspend_flags; /* sync d0i3_tx queue and IWL_MVM_STATUS_IN_D0I3 status flag */ spinlock_t d0i3_tx_lock; wait_queue_head_t d0i3_exit_waitq; @@ -629,8 +644,8 @@ struct iwl_mvm { /* Indicate if device power save is allowed */ bool ps_disabled; - /* Indicate if device power management is allowed */ - bool pm_disabled; + + struct ieee80211_vif *csa_vif; }; /* Extract MVM priv from op_mode and _hw */ @@ -705,6 +720,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm); +void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm); #endif u8 first_antenna(u8 mask); u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); @@ -745,7 +761,7 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, struct iwl_device_cmd *cmd); /* NVM */ -int iwl_nvm_init(struct iwl_mvm *mvm); +int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic); int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm); int iwl_mvm_up(struct iwl_mvm *mvm); @@ -874,8 +890,6 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, int rs_pretty_print_rate(char *buf, const u32 rate); /* power management */ -int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm); - int iwl_mvm_power_update_device(struct iwl_mvm *mvm); int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -886,8 +900,18 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); +#ifdef CONFIG_IWLWIFI_LEDS int iwl_mvm_leds_init(struct iwl_mvm *mvm); void iwl_mvm_leds_exit(struct iwl_mvm *mvm); +#else +static inline int iwl_mvm_leds_init(struct iwl_mvm *mvm) +{ + return 0; +} +static inline void iwl_mvm_leds_exit(struct iwl_mvm *mvm) +{ +} +#endif /* D3 (WoWLAN, NetDetect) */ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); @@ -922,9 +946,9 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); +int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); /* BT Coex */ -int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm); int iwl_send_bt_init_conf(struct iwl_mvm *mvm); int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, @@ -936,6 +960,8 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, struct ieee80211_sta *sta); bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct ieee80211_sta *sta); +bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, + enum ieee80211_band band); u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *info, u8 ac); int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable); @@ -1003,6 +1029,9 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) return mvmvif->low_latency; } +/* Assoc status */ +bool iwl_mvm_is_associated(struct iwl_mvm *mvm); + /* Thermal management and CT-kill */ void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff); void iwl_mvm_tt_handler(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index cf2d09f53782b0..6b88c29ebe6b7a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -238,13 +238,20 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) return NULL; } } else { + /* SW and REGULATORY sections are mandatory */ if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || - !mvm->nvm_sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data || !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) { IWL_ERR(mvm, "Can't parse empty family 8000 NVM sections\n"); return NULL; } + /* MAC_OVERRIDE or at least HW section must exist */ + if (!mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data && + !mvm->nvm_sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data) { + IWL_ERR(mvm, + "Can't parse mac_address, empty sections\n"); + return NULL; + } } if (WARN_ON(!mvm->cfg)) @@ -427,7 +434,7 @@ int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm) return ret; } -int iwl_nvm_init(struct iwl_mvm *mvm) +int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) { int ret, i, section; u8 *nvm_buffer, *temp; @@ -437,13 +444,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm) if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS)) return -EINVAL; - /* load external NVM if configured */ - if (iwlwifi_mod_params.nvm_file) { - /* move to External NVM flow */ - ret = iwl_mvm_read_external_nvm(mvm); - if (ret) - return ret; - } else { + /* load NVM values from nic */ + if (read_nvm_from_nic) { /* list of NVM sections we are allowed/need to read */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { nvm_to_read[0] = mvm->cfg->nvm_hw_section_num; @@ -463,7 +465,6 @@ int iwl_nvm_init(struct iwl_mvm *mvm) /* Read From FW NVM */ IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); - /* TODO: find correct NVM max size for a section */ nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, GFP_KERNEL); if (!nvm_buffer) @@ -511,6 +512,15 @@ int iwl_nvm_init(struct iwl_mvm *mvm) return ret; } + /* load external NVM if configured */ + if (iwlwifi_mod_params.nvm_file) { + /* move to External NVM flow */ + ret = iwl_mvm_read_external_nvm(mvm); + if (ret) + return ret; + } + + /* parse the relevant nvm sections */ mvm->nvm_data = iwl_parse_nvm_sections(mvm); if (!mvm->nvm_data) return -ENODATA; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 9545d7fdd4bfc6..f8530b329d174a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -79,8 +79,8 @@ #include "iwl-prph.h" #include "rs.h" #include "fw-api-scan.h" -#include "fw-error-dump.h" #include "time-event.h" +#include "iwl-fw-error-dump.h" /* * module name, copyright, version, etc. @@ -220,7 +220,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true), - RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false), + RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, true), RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true), RX_HANDLER(ANTENNA_COUPLING_NOTIFICATION, iwl_mvm_rx_ant_coupling_notif, true), @@ -402,6 +402,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->sf_state = SF_UNINIT; mutex_init(&mvm->mutex); + mutex_init(&mvm->d0i3_suspend_mutex); spin_lock_init(&mvm->async_handlers_lock); INIT_LIST_HEAD(&mvm->time_event_list); INIT_LIST_HEAD(&mvm->async_handlers_list); @@ -466,12 +467,18 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, min_backoff = calc_min_backoff(trans, cfg); iwl_mvm_tt_initialize(mvm, min_backoff); + if (WARN(cfg->no_power_up_nic_in_init && !iwlwifi_mod_params.nvm_file, + "not allowing power-up and not having nvm_file\n")) + goto out_free; + /* - * If the NVM exists in an external file, - * there is no need to unnecessarily power up the NIC at driver load + * Even if nvm exists in the nvm_file driver should read agin the nvm + * from the nic because there might be entries that exist in the OTP + * and not in the file. + * for nics with no_power_up_nic_in_init: rely completley on nvm_file */ - if (iwlwifi_mod_params.nvm_file) { - err = iwl_nvm_init(mvm); + if (cfg->no_power_up_nic_in_init && iwlwifi_mod_params.nvm_file) { + err = iwl_nvm_init(mvm, false); if (err) goto out_free; } else { @@ -518,7 +525,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, out_free: iwl_phy_db_free(mvm->phy_db); kfree(mvm->scan_cmd); - if (!iwlwifi_mod_params.nvm_file) + if (!cfg->no_power_up_nic_in_init || !iwlwifi_mod_params.nvm_file) iwl_trans_op_mode_leave(trans); ieee80211_free_hw(mvm->hw); return NULL; @@ -538,6 +545,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) kfree(mvm->scan_cmd); vfree(mvm->fw_error_dump); kfree(mvm->fw_error_sram); + kfree(mvm->fw_error_rxf); kfree(mvm->mcast_filter_cmd); mvm->mcast_filter_cmd = NULL; @@ -814,6 +822,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; u32 file_len; + u32 trans_len; lockdep_assert_held(&mvm->mutex); @@ -821,8 +830,13 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) return; file_len = mvm->fw_error_sram_len + + mvm->fw_error_rxf_len + sizeof(*dump_file) + - sizeof(*dump_data); + sizeof(*dump_data) * 2; + + trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0); + if (trans_len) + file_len += trans_len; dump_file = vmalloc(file_len); if (!dump_file) @@ -833,7 +847,12 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); dump_file->file_len = cpu_to_le32(file_len); dump_data = (void *)dump_file->data; - dump_data->type = IWL_FW_ERROR_DUMP_SRAM; + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); + dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len); + memcpy(dump_data->data, mvm->fw_error_rxf, mvm->fw_error_rxf_len); + + dump_data = iwl_mvm_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); dump_data->len = cpu_to_le32(mvm->fw_error_sram_len); /* @@ -842,6 +861,23 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) * mvm->fw_error_sram right now. */ memcpy(dump_data->data, mvm->fw_error_sram, mvm->fw_error_sram_len); + + kfree(mvm->fw_error_rxf); + mvm->fw_error_rxf = NULL; + mvm->fw_error_rxf_len = 0; + + kfree(mvm->fw_error_sram); + mvm->fw_error_sram = NULL; + mvm->fw_error_sram_len = 0; + + if (trans_len) { + void *buf = iwl_mvm_fw_error_next_data(dump_data); + u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, + trans_len); + dump_data = (void *)((u8 *)buf + real_trans_len); + dump_file->file_len = + cpu_to_le32(file_len - trans_len + real_trans_len); + } } #endif @@ -853,6 +889,7 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) #ifdef CONFIG_IWLWIFI_DEBUGFS iwl_mvm_fw_error_sram_dump(mvm); + iwl_mvm_fw_error_rxf_dump(mvm); #endif iwl_mvm_nic_restart(mvm); @@ -1128,7 +1165,7 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) .id = WOWLAN_GET_STATUSES, .flags = CMD_SYNC | CMD_HIGH_PRIO | CMD_WANT_SKB, }; - struct iwl_wowlan_status_v6 *status; + struct iwl_wowlan_status *status; int ret; u32 disconnection_reasons, wakeup_reasons; __le16 *qos_seq = NULL; @@ -1158,18 +1195,27 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) iwl_free_resp(&get_status_cmd); out: iwl_mvm_d0i3_enable_tx(mvm, qos_seq); + iwl_mvm_unref(mvm, IWL_MVM_REF_EXIT_WORK); mutex_unlock(&mvm->mutex); } -static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) +int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm) { - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE | CMD_WAKE_UP_TRANS; int ret; IWL_DEBUG_RPM(mvm, "MVM exiting D0i3\n"); + mutex_lock(&mvm->d0i3_suspend_mutex); + if (test_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags)) { + IWL_DEBUG_RPM(mvm, "Deferring d0i3 exit until resume\n"); + __set_bit(D0I3_PENDING_WAKEUP, &mvm->d0i3_suspend_flags); + mutex_unlock(&mvm->d0i3_suspend_mutex); + return 0; + } + mutex_unlock(&mvm->d0i3_suspend_mutex); + ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); if (ret) goto out; @@ -1183,6 +1229,25 @@ static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) return ret; } +static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) +{ + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + + iwl_mvm_ref(mvm, IWL_MVM_REF_EXIT_WORK); + return _iwl_mvm_exit_d0i3(mvm); +} + +static void iwl_mvm_napi_add(struct iwl_op_mode *op_mode, + struct napi_struct *napi, + struct net_device *napi_dev, + int (*poll)(struct napi_struct *, int), + int weight) +{ + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + + ieee80211_napi_add(mvm->hw, napi, napi_dev, poll, weight); +} + static const struct iwl_op_mode_ops iwl_mvm_ops = { .start = iwl_op_mode_mvm_start, .stop = iwl_op_mode_mvm_stop, @@ -1196,4 +1261,5 @@ static const struct iwl_op_mode_ops iwl_mvm_ops = { .nic_config = iwl_mvm_nic_config, .enter_d0i3 = iwl_mvm_enter_d0i3, .exit_d0i3 = iwl_mvm_exit_d0i3, + .napi_add = iwl_mvm_napi_add, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index 237efe0ac1c44d..eafc517a5f9ecf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c @@ -202,18 +202,15 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) { - int ret; - WARN_ON(!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && ctxt->ref); lockdep_assert_held(&mvm->mutex); ctxt->channel = chandef->chan; - ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, - chains_static, chains_dynamic, - FW_CTXT_ACTION_ADD, 0); - return ret; + return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, + chains_static, chains_dynamic, + FW_CTXT_ACTION_ADD, 0); } /* diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 6b636eab33391c..78309f7d0b7b8c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -268,6 +268,30 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm, IWL_MVM_PS_HEAVY_RX_THLD_PERCENT; } +static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid, + ETH_ALEN)) + return false; + + if (vif->p2p && + !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD)) + return false; + /* + * Avoid using uAPSD if P2P client is associated to GO that uses + * opportunistic power save. This is due to current FW limitation. + */ + if (vif->p2p && + (vif->bss_conf.p2p_noa_attr.oppps_ctwindow & + IEEE80211_P2P_OPPPS_ENABLE_BIT)) + return false; + + return true; +} + static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mac_power_cmd *cmd) @@ -280,7 +304,6 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, bool radar_detect = false; struct iwl_mvm_vif *mvmvif __maybe_unused = iwl_mvm_vif_from_mac80211(vif); - bool allow_uapsd = true; cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); @@ -303,13 +326,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && - mvmvif->dbgfs_pm.disable_power_off) - cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); -#endif if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || - mvm->pm_disabled) + !mvmvif->pm_enabled) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); @@ -351,23 +369,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT); } - if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid, - ETH_ALEN)) - allow_uapsd = false; - - if (vif->p2p && - !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD)) - allow_uapsd = false; - /* - * Avoid using uAPSD if P2P client is associated to GO that uses - * opportunistic power save. This is due to current FW limitation. - */ - if (vif->p2p && - vif->bss_conf.p2p_noa_attr.oppps_ctwindow & - IEEE80211_P2P_OPPPS_ENABLE_BIT) - allow_uapsd = false; - - if (allow_uapsd) + if (iwl_mvm_power_allow_uapsd(mvm, vif)) iwl_mvm_power_configure_uapsd(mvm, vif, cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -421,13 +423,6 @@ static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm, { struct iwl_mac_power_cmd cmd = {}; - if (vif->type != NL80211_IFTYPE_STATION) - return 0; - - if (vif->p2p && - !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) - return 0; - iwl_mvm_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_log(mvm, &cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -444,12 +439,6 @@ int iwl_mvm_power_update_device(struct iwl_mvm *mvm) .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), }; - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) - return 0; - - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) - return 0; - if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) mvm->ps_disabled = true; @@ -508,86 +497,69 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, return 0; } -struct iwl_power_constraint { +struct iwl_power_vifs { struct ieee80211_vif *bf_vif; struct ieee80211_vif *bss_vif; struct ieee80211_vif *p2p_vif; - u16 bss_phyctx_id; - u16 p2p_phyctx_id; - bool pm_disabled; - bool ps_disabled; - struct iwl_mvm *mvm; + struct ieee80211_vif *ap_vif; + struct ieee80211_vif *monitor_vif; + bool p2p_active; + bool bss_active; + bool ap_active; + bool monitor_active; }; static void iwl_mvm_power_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_power_constraint *power_iterator = _data; - struct iwl_mvm *mvm = power_iterator->mvm; + struct iwl_power_vifs *power_iterator = _data; + mvmvif->pm_enabled = false; switch (ieee80211_vif_type_p2p(vif)) { case NL80211_IFTYPE_P2P_DEVICE: break; case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_AP: - /* no BSS power mgmt if we have an active AP */ - if (mvmvif->ap_ibss_active) - power_iterator->pm_disabled = true; + /* only a single MAC of the same type */ + WARN_ON(power_iterator->ap_vif); + power_iterator->ap_vif = vif; + if (mvmvif->phy_ctxt) + if (mvmvif->phy_ctxt->id < MAX_PHYS) + power_iterator->ap_active = true; break; case NL80211_IFTYPE_MONITOR: - /* no BSS power mgmt and no device power save */ - power_iterator->pm_disabled = true; - power_iterator->ps_disabled = true; + /* only a single MAC of the same type */ + WARN_ON(power_iterator->monitor_vif); + power_iterator->monitor_vif = vif; + if (mvmvif->phy_ctxt) + if (mvmvif->phy_ctxt->id < MAX_PHYS) + power_iterator->monitor_active = true; break; case NL80211_IFTYPE_P2P_CLIENT: - if (mvmvif->phy_ctxt) - power_iterator->p2p_phyctx_id = mvmvif->phy_ctxt->id; - - /* we should have only one P2P vif */ + /* only a single MAC of the same type */ WARN_ON(power_iterator->p2p_vif); power_iterator->p2p_vif = vif; - - IWL_DEBUG_POWER(mvm, "p2p: p2p_id=%d, bss_id=%d\n", - power_iterator->p2p_phyctx_id, - power_iterator->bss_phyctx_id); - if (!(mvm->fw->ucode_capa.flags & - IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) { - /* no BSS power mgmt if we have a P2P client*/ - power_iterator->pm_disabled = true; - } else if (power_iterator->p2p_phyctx_id < MAX_PHYS && - power_iterator->bss_phyctx_id < MAX_PHYS && - power_iterator->p2p_phyctx_id == - power_iterator->bss_phyctx_id) { - power_iterator->pm_disabled = true; - } + if (mvmvif->phy_ctxt) + if (mvmvif->phy_ctxt->id < MAX_PHYS) + power_iterator->p2p_active = true; break; case NL80211_IFTYPE_STATION: - if (mvmvif->phy_ctxt) - power_iterator->bss_phyctx_id = mvmvif->phy_ctxt->id; - - /* we should have only one BSS vif */ + /* only a single MAC of the same type */ WARN_ON(power_iterator->bss_vif); power_iterator->bss_vif = vif; + if (mvmvif->phy_ctxt) + if (mvmvif->phy_ctxt->id < MAX_PHYS) + power_iterator->bss_active = true; if (mvmvif->bf_data.bf_enabled && !WARN_ON(power_iterator->bf_vif)) power_iterator->bf_vif = vif; - IWL_DEBUG_POWER(mvm, "bss: p2p_id=%d, bss_id=%d\n", - power_iterator->p2p_phyctx_id, - power_iterator->bss_phyctx_id); - if (mvm->fw->ucode_capa.flags & - IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM && - (power_iterator->p2p_phyctx_id < MAX_PHYS && - power_iterator->bss_phyctx_id < MAX_PHYS && - power_iterator->p2p_phyctx_id == - power_iterator->bss_phyctx_id)) - power_iterator->pm_disabled = true; break; default: @@ -596,70 +568,118 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac, } static void -iwl_mvm_power_get_global_constraint(struct iwl_mvm *mvm, - struct iwl_power_constraint *constraint) +iwl_mvm_power_set_pm(struct iwl_mvm *mvm, + struct iwl_power_vifs *vifs) { - lockdep_assert_held(&mvm->mutex); + struct iwl_mvm_vif *bss_mvmvif = NULL; + struct iwl_mvm_vif *p2p_mvmvif = NULL; + struct iwl_mvm_vif *ap_mvmvif = NULL; + bool client_same_channel = false; + bool ap_same_channel = false; - if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) { - constraint->pm_disabled = true; - constraint->ps_disabled = true; - } + lockdep_assert_held(&mvm->mutex); + /* get vifs info + set pm_enable to false */ ieee80211_iterate_active_interfaces_atomic(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_power_iterator, constraint); + iwl_mvm_power_iterator, vifs); + + if (vifs->bss_vif) + bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif); + + if (vifs->p2p_vif) + p2p_mvmvif = iwl_mvm_vif_from_mac80211(vifs->p2p_vif); + + if (vifs->ap_vif) + ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif); + + /* enable PM on bss if bss stand alone */ + if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) { + bss_mvmvif->pm_enabled = true; + return; + } + + /* enable PM on p2p if p2p stand alone */ + if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) { + if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM) + p2p_mvmvif->pm_enabled = true; + return; + } + + if (vifs->bss_active && vifs->p2p_active) + client_same_channel = (bss_mvmvif->phy_ctxt->id == + p2p_mvmvif->phy_ctxt->id); + if (vifs->bss_active && vifs->ap_active) + ap_same_channel = (bss_mvmvif->phy_ctxt->id == + ap_mvmvif->phy_ctxt->id); + + /* bss is not stand alone: enable PM if alone on its channel */ + if (vifs->bss_active && !(client_same_channel || ap_same_channel) && + (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) { + bss_mvmvif->pm_enabled = true; + return; + } + + /* + * There is only one channel in the system and there are only + * bss and p2p clients that share it + */ + if (client_same_channel && !vifs->ap_active && + (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM)) { + /* share same channel*/ + bss_mvmvif->pm_enabled = true; + if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM) + p2p_mvmvif->pm_enabled = true; + } } int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_power_constraint constraint = { - .p2p_phyctx_id = MAX_PHYS, - .bss_phyctx_id = MAX_PHYS, - .mvm = mvm, - }; + struct iwl_mvm_vif *mvmvif; + struct iwl_power_vifs vifs = {}; bool ba_enable; int ret; lockdep_assert_held(&mvm->mutex); - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) - return 0; - - iwl_mvm_power_get_global_constraint(mvm, &constraint); - mvm->ps_disabled = constraint.ps_disabled; - mvm->pm_disabled = constraint.pm_disabled; + iwl_mvm_power_set_pm(mvm, &vifs); + /* disable PS if CAM */ + if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) { + mvm->ps_disabled = true; + } else { /* don't update device power state unless we add / remove monitor */ - if (vif->type == NL80211_IFTYPE_MONITOR) { - ret = iwl_mvm_power_update_device(mvm); - if (ret) - return ret; + if (vifs.monitor_vif) { + if (vifs.monitor_active) + mvm->ps_disabled = true; + ret = iwl_mvm_power_update_device(mvm); + if (ret) + return ret; + } } - if (constraint.bss_vif) { - ret = iwl_mvm_power_send_cmd(mvm, constraint.bss_vif); + if (vifs.bss_vif) { + ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif); if (ret) return ret; } - if (constraint.p2p_vif) { - ret = iwl_mvm_power_send_cmd(mvm, constraint.p2p_vif); + if (vifs.p2p_vif) { + ret = iwl_mvm_power_send_cmd(mvm, vifs.p2p_vif); if (ret) return ret; } - if (!constraint.bf_vif) + if (!vifs.bf_vif) return 0; - vif = constraint.bf_vif; + vif = vifs.bf_vif; mvmvif = iwl_mvm_vif_from_mac80211(vif); - ba_enable = !(constraint.pm_disabled || constraint.ps_disabled || + ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled || !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif)); - return iwl_mvm_update_beacon_abort(mvm, constraint.bf_vif, ba_enable); + return iwl_mvm_update_beacon_abort(mvm, vifs.bf_vif, ba_enable); } #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -671,19 +691,10 @@ int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct iwl_mac_power_cmd cmd = {}; int pos = 0; - if (WARN_ON(!(mvm->fw->ucode_capa.flags & - IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))) - return 0; - mutex_lock(&mvm->mutex); memcpy(&cmd, &mvmvif->mac_pwr_cmd, sizeof(cmd)); mutex_unlock(&mvm->mutex); - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) - pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", - (cmd.flags & - cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? - 0 : 1); pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", iwlmvm_mod_params.power_scheme); pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", @@ -826,8 +837,7 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; - if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED) || - vif->type != NL80211_IFTYPE_STATION || vif->p2p) + if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags); @@ -914,13 +924,3 @@ int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, return iwl_mvm_enable_beacon_filter(mvm, vif, flags); } - -int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm) -{ - struct iwl_powertable_cmd cmd = { - .keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC, - }; - - return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, - sizeof(cmd), &cmd); -} diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 9f52c5b3f0ec0e..10ad1dca5f17a7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -211,7 +211,7 @@ static const struct rs_tx_column rs_tx_columns[] = { .next_columns = { RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_SISO_ANT_A, - RS_COLUMN_SISO_ANT_B, + RS_COLUMN_MIMO2, RS_COLUMN_INVALID, RS_COLUMN_INVALID, RS_COLUMN_INVALID, @@ -223,8 +223,8 @@ static const struct rs_tx_column rs_tx_columns[] = { .ant = ANT_B, .next_columns = { RS_COLUMN_LEGACY_ANT_A, - RS_COLUMN_SISO_ANT_A, RS_COLUMN_SISO_ANT_B, + RS_COLUMN_MIMO2, RS_COLUMN_INVALID, RS_COLUMN_INVALID, RS_COLUMN_INVALID, @@ -238,10 +238,10 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_B, RS_COLUMN_MIMO2, RS_COLUMN_SISO_ANT_A_SGI, - RS_COLUMN_SISO_ANT_B_SGI, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_INVALID, + RS_COLUMN_INVALID, }, .checks = { rs_siso_allow, @@ -254,10 +254,10 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_A, RS_COLUMN_MIMO2, RS_COLUMN_SISO_ANT_B_SGI, - RS_COLUMN_SISO_ANT_A_SGI, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_INVALID, + RS_COLUMN_INVALID, }, .checks = { rs_siso_allow, @@ -271,10 +271,10 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_B_SGI, RS_COLUMN_MIMO2_SGI, RS_COLUMN_SISO_ANT_A, - RS_COLUMN_SISO_ANT_B, - RS_COLUMN_MIMO2, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, }, .checks = { rs_siso_allow, @@ -289,10 +289,10 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_A_SGI, RS_COLUMN_MIMO2_SGI, RS_COLUMN_SISO_ANT_B, - RS_COLUMN_SISO_ANT_A, - RS_COLUMN_MIMO2, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, }, .checks = { rs_siso_allow, @@ -304,12 +304,12 @@ static const struct rs_tx_column rs_tx_columns[] = { .ant = ANT_AB, .next_columns = { RS_COLUMN_SISO_ANT_A, - RS_COLUMN_SISO_ANT_B, - RS_COLUMN_SISO_ANT_A_SGI, - RS_COLUMN_SISO_ANT_B_SGI, RS_COLUMN_MIMO2_SGI, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, }, .checks = { rs_mimo_allow, @@ -321,12 +321,12 @@ static const struct rs_tx_column rs_tx_columns[] = { .sgi = true, .next_columns = { RS_COLUMN_SISO_ANT_A_SGI, - RS_COLUMN_SISO_ANT_B_SGI, - RS_COLUMN_SISO_ANT_A, - RS_COLUMN_SISO_ANT_B, RS_COLUMN_MIMO2, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, }, .checks = { rs_mimo_allow, @@ -527,6 +527,9 @@ static void rs_rate_scale_clear_tbl_windows(struct iwl_mvm *mvm, IWL_DEBUG_RATE(mvm, "Clearing up window stats\n"); for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&tbl->win[i]); + + for (i = 0; i < ARRAY_SIZE(tbl->tpc_win); i++) + rs_rate_scale_clear_window(&tbl->tpc_win[i]); } static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) @@ -656,17 +659,34 @@ static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, return 0; } -static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, - int scale_index, int attempts, int successes) +static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta, + struct iwl_scale_tbl_info *tbl, + int scale_index, int attempts, int successes, + u8 reduced_txp) { struct iwl_rate_scale_data *window = NULL; + int ret; if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) return -EINVAL; + if (tbl->column != RS_COLUMN_INVALID) { + lq_sta->tx_stats[tbl->column][scale_index].total += attempts; + lq_sta->tx_stats[tbl->column][scale_index].success += successes; + } + /* Select window for current tx bit rate */ window = &(tbl->win[scale_index]); + ret = _rs_collect_tx_data(tbl, scale_index, attempts, successes, + window); + if (ret) + return ret; + + if (WARN_ON_ONCE(reduced_txp > TPC_MAX_REDUCTION)) + return -EINVAL; + + window = &tbl->tpc_win[reduced_txp]; return _rs_collect_tx_data(tbl, scale_index, attempts, successes, window); } @@ -1000,6 +1020,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, u32 ucode_rate; struct rs_rate rate; struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; + u8 reduced_txp = (uintptr_t)info->status.status_driver_data[0]; /* Treat uninitialized rate scaling data same as non-existing. */ if (!lq_sta) { @@ -1010,7 +1031,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, return; } -#ifdef CPTCFG_MAC80211_DEBUGFS +#ifdef CONFIG_MAC80211_DEBUGFS /* Disable last tx check if we are debugging with fixed rate */ if (lq_sta->dbg_fixed_rate) { IWL_DEBUG_RATE(mvm, "Fixed rate. avoid rate scaling\n"); @@ -1141,9 +1162,10 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, if (info->flags & IEEE80211_TX_STAT_AMPDU) { ucode_rate = le32_to_cpu(table->rs_table[0]); rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); - rs_collect_tx_data(curr_tbl, rate.index, + rs_collect_tx_data(lq_sta, curr_tbl, rate.index, info->status.ampdu_len, - info->status.ampdu_ack_len); + info->status.ampdu_ack_len, + reduced_txp); /* Update success/fail counts if not searching for new mode */ if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { @@ -1176,8 +1198,9 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, else continue; - rs_collect_tx_data(tmp_tbl, rate.index, 1, - i < retries ? 0 : legacy_success); + rs_collect_tx_data(lq_sta, tmp_tbl, rate.index, 1, + i < retries ? 0 : legacy_success, + reduced_txp); } /* Update success/fail counts if not searching for new mode */ @@ -1188,6 +1211,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, } /* The last TX rate is cached in lq_sta; it's set in if/else above */ lq_sta->last_rate_n_flags = ucode_rate; + IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp); done: /* See if there's a better rate or modulation mode to try. */ if (sta && sta->supp_rates[sband->band]) @@ -1311,105 +1335,50 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, tbl->expected_tpt = rs_get_expected_tpt_table(lq_sta, column, rate->bw); } -/* - * Find starting rate for new "search" high-throughput mode of modulation. - * Goal is to find lowest expected rate (under perfect conditions) that is - * above the current measured throughput of "active" mode, to give new mode - * a fair chance to prove itself without too many challenges. - * - * This gets called when transitioning to more aggressive modulation - * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive - * (i.e. MIMO to SISO). When moving to MIMO, bit rate will typically need - * to decrease to match "active" throughput. When moving from MIMO to SISO, - * bit rate will typically need to increase, but not if performance was bad. - */ static s32 rs_get_best_rate(struct iwl_mvm *mvm, struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl, /* "search" */ - u16 rate_mask, s8 index) + unsigned long rate_mask, s8 index) { - /* "active" values */ struct iwl_scale_tbl_info *active_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - s32 active_sr = active_tbl->win[index].success_ratio; - s32 active_tpt = active_tbl->expected_tpt[index]; - /* expected "search" throughput */ + s32 success_ratio = active_tbl->win[index].success_ratio; + u16 expected_current_tpt = active_tbl->expected_tpt[index]; const u16 *tpt_tbl = tbl->expected_tpt; - - s32 new_rate, high, low, start_hi; u16 high_low; - s8 rate = index; - - new_rate = high = low = start_hi = IWL_RATE_INVALID; - - while (1) { - high_low = rs_get_adjacent_rate(mvm, rate, rate_mask, - tbl->rate.type); + u32 target_tpt; + int rate_idx; - low = high_low & 0xff; - high = (high_low >> 8) & 0xff; - - /* - * Lower the "search" bit rate, to give new "search" mode - * approximately the same throughput as "active" if: - * - * 1) "Active" mode has been working modestly well (but not - * great), and expected "search" throughput (under perfect - * conditions) at candidate rate is above the actual - * measured "active" throughput (but less than expected - * "active" throughput under perfect conditions). - * OR - * 2) "Active" mode has been working perfectly or very well - * and expected "search" throughput (under perfect - * conditions) at candidate rate is above expected - * "active" throughput (under perfect conditions). - */ - if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) && - ((active_sr > RS_SR_FORCE_DECREASE) && - (active_sr <= IWL_RATE_HIGH_TH) && - (tpt_tbl[rate] <= active_tpt))) || - ((active_sr >= IWL_RATE_SCALE_SWITCH) && - (tpt_tbl[rate] > active_tpt))) { - /* (2nd or later pass) - * If we've already tried to raise the rate, and are - * now trying to lower it, use the higher rate. */ - if (start_hi != IWL_RATE_INVALID) { - new_rate = start_hi; - break; - } - - new_rate = rate; + if (success_ratio > RS_SR_NO_DECREASE) { + target_tpt = 100 * expected_current_tpt; + IWL_DEBUG_RATE(mvm, + "SR %d high. Find rate exceeding EXPECTED_CURRENT %d\n", + success_ratio, target_tpt); + } else { + target_tpt = lq_sta->last_tpt; + IWL_DEBUG_RATE(mvm, + "SR %d not thag good. Find rate exceeding ACTUAL_TPT %d\n", + success_ratio, target_tpt); + } - /* Loop again with lower rate */ - if (low != IWL_RATE_INVALID) - rate = low; + rate_idx = find_first_bit(&rate_mask, BITS_PER_LONG); - /* Lower rate not available, use the original */ - else - break; - - /* Else try to raise the "search" rate to match "active" */ - } else { - /* (2nd or later pass) - * If we've already tried to lower the rate, and are - * now trying to raise it, use the lower rate. */ - if (new_rate != IWL_RATE_INVALID) - break; + while (rate_idx != IWL_RATE_INVALID) { + if (target_tpt < (100 * tpt_tbl[rate_idx])) + break; - /* Loop again with higher rate */ - else if (high != IWL_RATE_INVALID) { - start_hi = high; - rate = high; + high_low = rs_get_adjacent_rate(mvm, rate_idx, rate_mask, + tbl->rate.type); - /* Higher rate not available, use the original */ - } else { - new_rate = rate; - break; - } - } + rate_idx = (high_low >> 8) & 0xff; } - return new_rate; + IWL_DEBUG_RATE(mvm, "Best rate found %d target_tp %d expected_new %d\n", + rate_idx, target_tpt, + rate_idx != IWL_RATE_INVALID ? + 100 * tpt_tbl[rate_idx] : IWL_INVALID_VALUE); + + return rate_idx; } static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta) @@ -1584,7 +1553,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, tpt = lq_sta->last_tpt / 100; expected_tpt_tbl = rs_get_expected_tpt_table(lq_sta, next_col, - tbl->rate.bw); + rs_bw_from_sta_bw(sta)); if (WARN_ON_ONCE(!expected_tpt_tbl)) continue; @@ -1625,7 +1594,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, const struct rs_tx_column *curr_column = &rs_tx_columns[tbl->column]; u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); - u16 rate_mask = 0; + unsigned long rate_mask = 0; u32 rate_idx = 0; memcpy(search_tbl, tbl, sz); @@ -1667,7 +1636,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, !(BIT(rate_idx) & rate_mask)) { IWL_DEBUG_RATE(mvm, "can not switch with index %d" - " rate mask %x\n", + " rate mask %lx\n", rate_idx, rate_mask); goto err; @@ -1769,6 +1738,203 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm, return action; } +static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index, + int *weaker, int *stronger) +{ + *weaker = index + TPC_TX_POWER_STEP; + if (*weaker > TPC_MAX_REDUCTION) + *weaker = TPC_INVALID; + + *stronger = index - TPC_TX_POWER_STEP; + if (*stronger < 0) + *stronger = TPC_INVALID; +} + +static bool rs_tpc_allowed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct rs_rate *rate, enum ieee80211_band band) +{ + int index = rate->index; + bool cam = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM); + bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION && + !vif->bss_conf.ps); + + IWL_DEBUG_RATE(mvm, "cam: %d sta_ps_disabled %d\n", + cam, sta_ps_disabled); + /* + * allow tpc only if power management is enabled, or bt coex + * activity grade allows it and we are on 2.4Ghz. + */ + if ((cam || sta_ps_disabled) && + !iwl_mvm_bt_coex_is_tpc_allowed(mvm, band)) + return false; + + IWL_DEBUG_RATE(mvm, "check rate, table type: %d\n", rate->type); + if (is_legacy(rate)) + return index == IWL_RATE_54M_INDEX; + if (is_ht(rate)) + return index == IWL_RATE_MCS_7_INDEX; + if (is_vht(rate)) + return index == IWL_RATE_MCS_7_INDEX || + index == IWL_RATE_MCS_8_INDEX || + index == IWL_RATE_MCS_9_INDEX; + + WARN_ON_ONCE(1); + return false; +} + +enum tpc_action { + TPC_ACTION_STAY, + TPC_ACTION_DECREASE, + TPC_ACTION_INCREASE, + TPC_ACTION_NO_RESTIRCTION, +}; + +static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm, + s32 sr, int weak, int strong, + int current_tpt, + int weak_tpt, int strong_tpt) +{ + /* stay until we have valid tpt */ + if (current_tpt == IWL_INVALID_VALUE) { + IWL_DEBUG_RATE(mvm, "no current tpt. stay.\n"); + return TPC_ACTION_STAY; + } + + /* Too many failures, increase txp */ + if (sr <= TPC_SR_FORCE_INCREASE || current_tpt == 0) { + IWL_DEBUG_RATE(mvm, "increase txp because of weak SR\n"); + return TPC_ACTION_NO_RESTIRCTION; + } + + /* try decreasing first if applicable */ + if (weak != TPC_INVALID) { + if (weak_tpt == IWL_INVALID_VALUE && + (strong_tpt == IWL_INVALID_VALUE || + current_tpt >= strong_tpt)) { + IWL_DEBUG_RATE(mvm, + "no weak txp measurement. decrease txp\n"); + return TPC_ACTION_DECREASE; + } + + if (weak_tpt > current_tpt) { + IWL_DEBUG_RATE(mvm, + "lower txp has better tpt. decrease txp\n"); + return TPC_ACTION_DECREASE; + } + } + + /* next, increase if needed */ + if (sr < TPC_SR_NO_INCREASE && strong != TPC_INVALID) { + if (weak_tpt == IWL_INVALID_VALUE && + strong_tpt != IWL_INVALID_VALUE && + current_tpt < strong_tpt) { + IWL_DEBUG_RATE(mvm, + "higher txp has better tpt. increase txp\n"); + return TPC_ACTION_INCREASE; + } + + if (weak_tpt < current_tpt && + (strong_tpt == IWL_INVALID_VALUE || + strong_tpt > current_tpt)) { + IWL_DEBUG_RATE(mvm, + "lower txp has worse tpt. increase txp\n"); + return TPC_ACTION_INCREASE; + } + } + + IWL_DEBUG_RATE(mvm, "no need to increase or decrease txp - stay\n"); + return TPC_ACTION_STAY; +} + +static bool rs_tpc_perform(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta, + struct iwl_scale_tbl_info *tbl) +{ + struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct ieee80211_vif *vif = mvm_sta->vif; + struct ieee80211_chanctx_conf *chanctx_conf; + enum ieee80211_band band; + struct iwl_rate_scale_data *window; + struct rs_rate *rate = &tbl->rate; + enum tpc_action action; + s32 sr; + u8 cur = lq_sta->lq.reduced_tpc; + int current_tpt; + int weak, strong; + int weak_tpt = IWL_INVALID_VALUE, strong_tpt = IWL_INVALID_VALUE; + +#ifdef CONFIG_MAC80211_DEBUGFS + if (lq_sta->dbg_fixed_txp_reduction <= TPC_MAX_REDUCTION) { + IWL_DEBUG_RATE(mvm, "fixed tpc: %d", + lq_sta->dbg_fixed_txp_reduction); + lq_sta->lq.reduced_tpc = lq_sta->dbg_fixed_txp_reduction; + return cur != lq_sta->dbg_fixed_txp_reduction; + } +#endif + + rcu_read_lock(); + chanctx_conf = rcu_dereference(vif->chanctx_conf); + if (WARN_ON(!chanctx_conf)) + band = IEEE80211_NUM_BANDS; + else + band = chanctx_conf->def.chan->band; + rcu_read_unlock(); + + if (!rs_tpc_allowed(mvm, vif, rate, band)) { + IWL_DEBUG_RATE(mvm, + "tpc is not allowed. remove txp restrictions"); + lq_sta->lq.reduced_tpc = TPC_NO_REDUCTION; + return cur != TPC_NO_REDUCTION; + } + + rs_get_adjacent_txp(mvm, cur, &weak, &strong); + + /* Collect measured throughputs for current and adjacent rates */ + window = tbl->tpc_win; + sr = window[cur].success_ratio; + current_tpt = window[cur].average_tpt; + if (weak != TPC_INVALID) + weak_tpt = window[weak].average_tpt; + if (strong != TPC_INVALID) + strong_tpt = window[strong].average_tpt; + + IWL_DEBUG_RATE(mvm, + "(TPC: %d): cur_tpt %d SR %d weak %d strong %d weak_tpt %d strong_tpt %d\n", + cur, current_tpt, sr, weak, strong, + weak_tpt, strong_tpt); + + action = rs_get_tpc_action(mvm, sr, weak, strong, + current_tpt, weak_tpt, strong_tpt); + + /* override actions if we are on the edge */ + if (weak == TPC_INVALID && action == TPC_ACTION_DECREASE) { + IWL_DEBUG_RATE(mvm, "already in lowest txp, stay"); + action = TPC_ACTION_STAY; + } else if (strong == TPC_INVALID && + (action == TPC_ACTION_INCREASE || + action == TPC_ACTION_NO_RESTIRCTION)) { + IWL_DEBUG_RATE(mvm, "already in highest txp, stay"); + action = TPC_ACTION_STAY; + } + + switch (action) { + case TPC_ACTION_DECREASE: + lq_sta->lq.reduced_tpc = weak; + return true; + case TPC_ACTION_INCREASE: + lq_sta->lq.reduced_tpc = strong; + return true; + case TPC_ACTION_NO_RESTIRCTION: + lq_sta->lq.reduced_tpc = TPC_NO_REDUCTION; + return true; + case TPC_ACTION_STAY: + /* do nothing */ + break; + } + return false; +} + /* * Do rate scaling and search for new modulation mode. */ @@ -2019,6 +2185,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, break; case RS_ACTION_STAY: /* No change */ + if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) + update_lq = rs_tpc_perform(mvm, sta, lq_sta, tbl); + break; default: break; } @@ -2271,10 +2440,6 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta, if (i == IWL_RATE_9M_INDEX) continue; - /* Disable MCS9 as a workaround */ - if (i == IWL_RATE_MCS_9_INDEX) - continue; - /* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */ if (i == IWL_RATE_MCS_9_INDEX && sta->bandwidth == IEEE80211_STA_RX_BW_20) @@ -2293,10 +2458,6 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta, if (i == IWL_RATE_9M_INDEX) continue; - /* Disable MCS9 as a workaround */ - if (i == IWL_RATE_MCS_9_INDEX) - continue; - /* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */ if (i == IWL_RATE_MCS_9_INDEX && sta->bandwidth == IEEE80211_STA_RX_BW_20) @@ -2478,6 +2639,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->is_agg = 0; #ifdef CONFIG_MAC80211_DEBUGFS lq_sta->dbg_fixed_rate = 0; + lq_sta->dbg_fixed_txp_reduction = TPC_INVALID; #endif #ifdef CONFIG_IWLWIFI_DEBUGFS iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats); @@ -2653,6 +2815,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, rs_build_rates_table_from_fixed(mvm, lq_cmd, lq_sta->band, lq_sta->dbg_fixed_rate); + lq_cmd->reduced_tpc = 0; ant = (lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS; } else @@ -2783,7 +2946,6 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, size_t buf_size; u32 parsed_rate; - mvm = lq_sta->drv; memset(buf, 0, sizeof(buf)); buf_size = min(count, sizeof(buf) - 1); @@ -2856,6 +3018,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, lq_sta->lq.agg_disable_start_th, lq_sta->lq.agg_frame_cnt_limit); + desc += sprintf(buff+desc, "reduced tpc=%d\n", lq_sta->lq.reduced_tpc); desc += sprintf(buff+desc, "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n", lq_sta->lq.initial_rate_index[0], @@ -2928,6 +3091,94 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = { .llseek = default_llseek, }; +static ssize_t rs_sta_dbgfs_drv_tx_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + static const char * const column_name[] = { + [RS_COLUMN_LEGACY_ANT_A] = "LEGACY_ANT_A", + [RS_COLUMN_LEGACY_ANT_B] = "LEGACY_ANT_B", + [RS_COLUMN_SISO_ANT_A] = "SISO_ANT_A", + [RS_COLUMN_SISO_ANT_B] = "SISO_ANT_B", + [RS_COLUMN_SISO_ANT_A_SGI] = "SISO_ANT_A_SGI", + [RS_COLUMN_SISO_ANT_B_SGI] = "SISO_ANT_B_SGI", + [RS_COLUMN_MIMO2] = "MIMO2", + [RS_COLUMN_MIMO2_SGI] = "MIMO2_SGI", + }; + + static const char * const rate_name[] = { + [IWL_RATE_1M_INDEX] = "1M", + [IWL_RATE_2M_INDEX] = "2M", + [IWL_RATE_5M_INDEX] = "5.5M", + [IWL_RATE_11M_INDEX] = "11M", + [IWL_RATE_6M_INDEX] = "6M|MCS0", + [IWL_RATE_9M_INDEX] = "9M", + [IWL_RATE_12M_INDEX] = "12M|MCS1", + [IWL_RATE_18M_INDEX] = "18M|MCS2", + [IWL_RATE_24M_INDEX] = "24M|MCS3", + [IWL_RATE_36M_INDEX] = "36M|MCS4", + [IWL_RATE_48M_INDEX] = "48M|MCS5", + [IWL_RATE_54M_INDEX] = "54M|MCS6", + [IWL_RATE_MCS_7_INDEX] = "MCS7", + [IWL_RATE_MCS_8_INDEX] = "MCS8", + [IWL_RATE_MCS_9_INDEX] = "MCS9", + }; + + char *buff, *pos, *endpos; + int col, rate; + ssize_t ret; + struct iwl_lq_sta *lq_sta = file->private_data; + struct rs_rate_stats *stats; + static const size_t bufsz = 1024; + + buff = kmalloc(bufsz, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + pos = buff; + endpos = pos + bufsz; + + pos += scnprintf(pos, endpos - pos, "COLUMN,"); + for (rate = 0; rate < IWL_RATE_COUNT; rate++) + pos += scnprintf(pos, endpos - pos, "%s,", rate_name[rate]); + pos += scnprintf(pos, endpos - pos, "\n"); + + for (col = 0; col < RS_COLUMN_COUNT; col++) { + pos += scnprintf(pos, endpos - pos, + "%s,", column_name[col]); + + for (rate = 0; rate < IWL_RATE_COUNT; rate++) { + stats = &(lq_sta->tx_stats[col][rate]); + pos += scnprintf(pos, endpos - pos, + "%llu/%llu,", + stats->success, + stats->total); + } + pos += scnprintf(pos, endpos - pos, "\n"); + } + + ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff); + kfree(buff); + return ret; +} + +static ssize_t rs_sta_dbgfs_drv_tx_stats_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_lq_sta *lq_sta = file->private_data; + memset(lq_sta->tx_stats, 0, sizeof(lq_sta->tx_stats)); + + return count; +} + +static const struct file_operations rs_sta_dbgfs_drv_tx_stats_ops = { + .read = rs_sta_dbgfs_drv_tx_stats_read, + .write = rs_sta_dbgfs_drv_tx_stats_write, + .open = simple_open, + .llseek = default_llseek, +}; + static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) { struct iwl_lq_sta *lq_sta = mvm_sta; @@ -2937,9 +3188,15 @@ static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) lq_sta->rs_sta_dbgfs_stats_table_file = debugfs_create_file("rate_stats_table", S_IRUSR, dir, lq_sta, &rs_sta_dbgfs_stats_table_ops); + lq_sta->rs_sta_dbgfs_drv_tx_stats_file = + debugfs_create_file("drv_tx_stats", S_IRUSR | S_IWUSR, dir, + lq_sta, &rs_sta_dbgfs_drv_tx_stats_ops); lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, &lq_sta->tx_agg_tid_en); + lq_sta->rs_sta_dbgfs_reduced_txp_file = + debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir, + &lq_sta->dbg_fixed_txp_reduction); } static void rs_remove_debugfs(void *mvm, void *mvm_sta) @@ -2947,7 +3204,9 @@ static void rs_remove_debugfs(void *mvm, void *mvm_sta) struct iwl_lq_sta *lq_sta = mvm_sta; debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); + debugfs_remove(lq_sta->rs_sta_dbgfs_drv_tx_stats_file); debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); + debugfs_remove(lq_sta->rs_sta_dbgfs_reduced_txp_file); } #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 0acfac96a56c6d..374a83d7db25a9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -158,6 +158,13 @@ enum { #define RS_SR_FORCE_DECREASE 1920 /* 15% */ #define RS_SR_NO_DECREASE 10880 /* 85% */ +#define TPC_SR_FORCE_INCREASE 9600 /* 75% */ +#define TPC_SR_NO_INCREASE 10880 /* 85% */ +#define TPC_TX_POWER_STEP 3 +#define TPC_MAX_REDUCTION 15 +#define TPC_NO_REDUCTION 0 +#define TPC_INVALID 0xff + #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */ #define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000) #define LINK_QUAL_AGG_TIME_LIMIT_MIN (100) @@ -266,9 +273,16 @@ enum rs_column { RS_COLUMN_MIMO2_SGI, RS_COLUMN_LAST = RS_COLUMN_MIMO2_SGI, + RS_COLUMN_COUNT = RS_COLUMN_LAST + 1, RS_COLUMN_INVALID, }; +/* Packet stats per rate */ +struct rs_rate_stats { + u64 success; + u64 total; +}; + /** * struct iwl_scale_tbl_info -- tx params and success history for all rates * @@ -280,6 +294,8 @@ struct iwl_scale_tbl_info { enum rs_column column; const u16 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ + /* per txpower-reduction history */ + struct iwl_rate_scale_data tpc_win[TPC_MAX_REDUCTION + 1]; }; enum { @@ -315,6 +331,8 @@ struct iwl_lq_sta { bool is_vht; enum ieee80211_band band; + struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; + /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ unsigned long active_legacy_rate; unsigned long active_siso_rate; @@ -334,8 +352,11 @@ struct iwl_lq_sta { #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *rs_sta_dbgfs_scale_table_file; struct dentry *rs_sta_dbgfs_stats_table_file; + struct dentry *rs_sta_dbgfs_drv_tx_stats_file; struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; + struct dentry *rs_sta_dbgfs_reduced_txp_file; u32 dbg_fixed_rate; + u8 dbg_fixed_txp_reduction; #endif struct iwl_mvm *drv; @@ -345,6 +366,9 @@ struct iwl_lq_sta { u32 last_rate_n_flags; /* packets destined for this STA are aggregated */ u8 is_agg; + + /* tx power reduce for this sta */ + int tpc_reduce; }; /* Initialize station's rate scaling information after adding station */ diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 6061553a5e4449..cf7276967acdec 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -60,7 +60,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ #include "iwl-trans.h" - #include "mvm.h" #include "fw-api.h" @@ -130,42 +129,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); - ieee80211_rx_ni(mvm->hw, skb); -} - -static void iwl_mvm_calc_rssi(struct iwl_mvm *mvm, - struct iwl_rx_phy_info *phy_info, - struct ieee80211_rx_status *rx_status) -{ - int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; - u32 agc_a, agc_b; - u32 val; - - val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); - agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS; - agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS; - - val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]); - rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS; - rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; - - /* - * dBm = rssi dB - agc dB - constant. - * Higher AGC (higher radio gain) means lower signal. - */ - rssi_a_dbm = rssi_a - IWL_RSSI_OFFSET - agc_a; - rssi_b_dbm = rssi_b - IWL_RSSI_OFFSET - agc_b; - max_rssi_dbm = max_t(int, rssi_a_dbm, rssi_b_dbm); - - IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n", - rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b); - - rx_status->signal = max_rssi_dbm; - rx_status->chains = (le16_to_cpu(phy_info->phy_flags) & - RX_RES_PHY_FLAGS_ANTENNA) - >> RX_RES_PHY_FLAGS_ANTENNA_POS; - rx_status->chain_signal[0] = rssi_a_dbm; - rx_status->chain_signal[1] = rssi_b_dbm; + ieee80211_rx(mvm->hw, skb); } /* @@ -337,10 +301,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, */ /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_RX_ENERGY_API) - iwl_mvm_get_signal_strength(mvm, phy_info, &rx_status); - else - iwl_mvm_calc_rssi(mvm, phy_info, &rx_status); + iwl_mvm_get_signal_strength(mvm, phy_info, &rx_status); IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal, (unsigned long long)rx_status.mactime); @@ -394,6 +355,8 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; rx_status.flag |= RX_FLAG_VHT; rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT; + if (rate_n_flags & RATE_MCS_BF_MSK) + rx_status.vht_flag |= RX_VHT_FLAG_BF; } else { rx_status.rate_idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index c91dc8498852c4..3e25af44afd70a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -277,51 +277,22 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_scan_condition_iterator, &global_bound); - /* - * Under low latency traffic passive scan is fragmented meaning - * that dwell on a particular channel will be fragmented. Each fragment - * dwell time is 20ms and fragments period is 105ms. Skipping to next - * channel will be delayed by the same period - 105ms. So suspend_time - * parameter describing both fragments and channels skipping periods is - * set to 105ms. This value is chosen so that overall passive scan - * duration will not be too long. Max_out_time in this case is set to - * 70ms, so for active scanning operating channel will be left for 70ms - * while for passive still for 20ms (fragment dwell). - */ - if (global_bound) { - if (!iwl_mvm_low_latency(mvm)) { - params->suspend_time = ieee80211_tu_to_usec(100); - params->max_out_time = ieee80211_tu_to_usec(600); - } else { - params->suspend_time = ieee80211_tu_to_usec(105); - /* P2P doesn't support fragmented passive scan, so - * configure max_out_time to be at least longest dwell - * time for passive scan. - */ - if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p) { - params->max_out_time = ieee80211_tu_to_usec(70); - params->passive_fragmented = true; - } else { - u32 passive_dwell; - /* - * Use band G so that passive channel dwell time - * will be assigned with maximum value. - */ - band = IEEE80211_BAND_2GHZ; - passive_dwell = iwl_mvm_get_passive_dwell(band); - params->max_out_time = - ieee80211_tu_to_usec(passive_dwell); - } - } + if (!global_bound) + goto not_bound; + + params->suspend_time = 100; + params->max_out_time = 600; + + if (iwl_mvm_low_latency(mvm)) { + params->suspend_time = 250; + params->max_out_time = 250; } +not_bound: + for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { - if (params->passive_fragmented) - params->dwell[band].passive = 20; - else - params->dwell[band].passive = - iwl_mvm_get_passive_dwell(band); + params->dwell[band].passive = iwl_mvm_get_passive_dwell(band); params->dwell[band].active = iwl_mvm_get_active_dwell(band, n_ssids); } @@ -348,7 +319,10 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, struct iwl_mvm_scan_params params = {}; lockdep_assert_held(&mvm->mutex); - BUG_ON(mvm->scan_cmd == NULL); + + /* we should have failed registration if scan_cmd was NULL */ + if (WARN_ON(mvm->scan_cmd == NULL)) + return -ENOMEM; IWL_DEBUG_SCAN(mvm, "Handling mac80211 scan request\n"); mvm->scan_status = IWL_MVM_SCAN_OS; @@ -567,9 +541,13 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, /* scan status must be locked for proper checking */ lockdep_assert_held(&mvm->mutex); - IWL_DEBUG_SCAN(mvm, "Scheduled scan completed, status %s\n", + IWL_DEBUG_SCAN(mvm, + "Scheduled scan completed, status %s EBS status %s:%d\n", scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? - "completed" : "aborted"); + "completed" : "aborted", scan_notif->ebs_status == + IWL_SCAN_EBS_SUCCESS ? "success" : "failed", + scan_notif->ebs_status); + /* only call mac80211 completion if the stop was initiated by FW */ if (mvm->scan_status == IWL_MVM_SCAN_SCHED) { @@ -577,6 +555,8 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, ieee80211_sched_scan_stopped(mvm->hw); } + mvm->last_ebs_successful = !scan_notif->ebs_status; + return 0; } @@ -913,6 +893,11 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, scan_req.flags |= cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_PASS_ALL); } + if (mvm->last_ebs_successful && + mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) + scan_req.flags |= + cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE); + return iwl_mvm_send_cmd_pdu(mvm, SCAN_OFFLOAD_REQUEST_CMD, CMD_SYNC, sizeof(scan_req), &scan_req); } diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c index 88809b2d165445..7edfd15efc9d00 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/iwlwifi/mvm/sf.c @@ -237,9 +237,6 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif, .sta_vif_ap_sta_id = IWL_MVM_STATION_COUNT, }; - if (IWL_UCODE_API(mvm->fw->ucode_ver) < 8) - return 0; - /* * Ignore the call if we are in HW Restart flow, or if the handled * vif is a p2p device. diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index f339ef88425087..3e11b9d802e759 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -66,115 +66,6 @@ #include "sta.h" #include "rs.h" -static void iwl_mvm_add_sta_cmd_v7_to_v5(struct iwl_mvm_add_sta_cmd_v7 *cmd_v7, - struct iwl_mvm_add_sta_cmd_v5 *cmd_v5) -{ - memset(cmd_v5, 0, sizeof(*cmd_v5)); - - cmd_v5->add_modify = cmd_v7->add_modify; - cmd_v5->tid_disable_tx = cmd_v7->tid_disable_tx; - cmd_v5->mac_id_n_color = cmd_v7->mac_id_n_color; - memcpy(cmd_v5->addr, cmd_v7->addr, ETH_ALEN); - cmd_v5->sta_id = cmd_v7->sta_id; - cmd_v5->modify_mask = cmd_v7->modify_mask; - cmd_v5->station_flags = cmd_v7->station_flags; - cmd_v5->station_flags_msk = cmd_v7->station_flags_msk; - cmd_v5->add_immediate_ba_tid = cmd_v7->add_immediate_ba_tid; - cmd_v5->remove_immediate_ba_tid = cmd_v7->remove_immediate_ba_tid; - cmd_v5->add_immediate_ba_ssn = cmd_v7->add_immediate_ba_ssn; - cmd_v5->sleep_tx_count = cmd_v7->sleep_tx_count; - cmd_v5->sleep_state_flags = cmd_v7->sleep_state_flags; - cmd_v5->assoc_id = cmd_v7->assoc_id; - cmd_v5->beamform_flags = cmd_v7->beamform_flags; - cmd_v5->tfd_queue_msk = cmd_v7->tfd_queue_msk; -} - -static void -iwl_mvm_add_sta_key_to_add_sta_cmd_v5(struct iwl_mvm_add_sta_key_cmd *key_cmd, - struct iwl_mvm_add_sta_cmd_v5 *sta_cmd, - u32 mac_id_n_color) -{ - memset(sta_cmd, 0, sizeof(*sta_cmd)); - - sta_cmd->sta_id = key_cmd->sta_id; - sta_cmd->add_modify = STA_MODE_MODIFY; - sta_cmd->modify_mask = STA_MODIFY_KEY; - sta_cmd->mac_id_n_color = cpu_to_le32(mac_id_n_color); - - sta_cmd->key.key_offset = key_cmd->key_offset; - sta_cmd->key.key_flags = key_cmd->key_flags; - memcpy(sta_cmd->key.key, key_cmd->key, sizeof(sta_cmd->key.key)); - sta_cmd->key.tkip_rx_tsc_byte2 = key_cmd->tkip_rx_tsc_byte2; - memcpy(sta_cmd->key.tkip_rx_ttak, key_cmd->tkip_rx_ttak, - sizeof(sta_cmd->key.tkip_rx_ttak)); -} - -static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm, - struct iwl_mvm_add_sta_cmd_v7 *cmd, - int *status) -{ - struct iwl_mvm_add_sta_cmd_v5 cmd_v5; - - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD) - return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(*cmd), - cmd, status); - - iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5); - - return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd_v5), - &cmd_v5, status); -} - -static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags, - struct iwl_mvm_add_sta_cmd_v7 *cmd) -{ - struct iwl_mvm_add_sta_cmd_v5 cmd_v5; - - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD) - return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, - sizeof(*cmd), cmd); - - iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5); - - return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5), - &cmd_v5); -} - -static int -iwl_mvm_send_add_sta_key_cmd_status(struct iwl_mvm *mvm, - struct iwl_mvm_add_sta_key_cmd *cmd, - u32 mac_id_n_color, - int *status) -{ - struct iwl_mvm_add_sta_cmd_v5 sta_cmd; - - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD) - return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, - sizeof(*cmd), cmd, status); - - iwl_mvm_add_sta_key_to_add_sta_cmd_v5(cmd, &sta_cmd, mac_id_n_color); - - return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(sta_cmd), - &sta_cmd, status); -} - -static int iwl_mvm_send_add_sta_key_cmd(struct iwl_mvm *mvm, - u32 flags, - struct iwl_mvm_add_sta_key_cmd *cmd, - u32 mac_id_n_color) -{ - struct iwl_mvm_add_sta_cmd_v5 sta_cmd; - - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD) - return iwl_mvm_send_cmd_pdu(mvm, ADD_STA_KEY, flags, - sizeof(*cmd), cmd); - - iwl_mvm_add_sta_key_to_add_sta_cmd_v5(cmd, &sta_cmd, mac_id_n_color); - - return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(sta_cmd), - &sta_cmd); -} - static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, enum nl80211_iftype iftype) { @@ -207,7 +98,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, bool update) { struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - struct iwl_mvm_add_sta_cmd_v7 add_sta_cmd; + struct iwl_mvm_add_sta_cmd add_sta_cmd; int ret; u32 status; u32 agg_size = 0, mpdu_dens = 0; @@ -295,7 +186,8 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT); status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_add_sta_cmd_status(mvm, &add_sta_cmd, &status); + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(add_sta_cmd), + &add_sta_cmd, &status); if (ret) return ret; @@ -380,7 +272,7 @@ int iwl_mvm_update_sta(struct iwl_mvm *mvm, int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool drain) { - struct iwl_mvm_add_sta_cmd_v7 cmd = {}; + struct iwl_mvm_add_sta_cmd cmd = {}; int ret; u32 status; @@ -393,7 +285,8 @@ int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW); status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status); + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), + &cmd, &status); if (ret) return ret; @@ -498,7 +391,7 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk) sta_id); continue; } - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL); clear_bit(sta_id, mvm->sta_drained); } @@ -520,14 +413,6 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, /* flush its queues here since we are freeing mvm_sta */ ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true); - /* - * Put a non-NULL since the fw station isn't removed. - * It will be removed after the MAC will be set as - * unassoc. - */ - rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], - ERR_PTR(-EINVAL)); - /* if we are associated - we can't remove the AP STA now */ if (vif->bss_conf.assoc) return ret; @@ -557,7 +442,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, } else { spin_unlock_bh(&mvm_sta->lock); ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); - rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); } return ret; @@ -571,7 +456,7 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL); return ret; } @@ -593,7 +478,7 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) { - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], NULL); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL); memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); sta->sta_id = IWL_MVM_STATION_COUNT; } @@ -603,13 +488,13 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, const u8 *addr, u16 mac_id, u16 color) { - struct iwl_mvm_add_sta_cmd_v7 cmd; + struct iwl_mvm_add_sta_cmd cmd; int ret; u32 status; lockdep_assert_held(&mvm->mutex); - memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v7)); + memset(&cmd, 0, sizeof(cmd)); cmd.sta_id = sta->sta_id; cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, color)); @@ -619,7 +504,8 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, if (addr) memcpy(cmd.addr, addr, ETH_ALEN); - ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status); + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), + &cmd, &status); if (ret) return ret; @@ -753,7 +639,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u16 ssn, bool start) { struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - struct iwl_mvm_add_sta_cmd_v7 cmd = {}; + struct iwl_mvm_add_sta_cmd cmd = {}; int ret; u32 status; @@ -777,7 +663,8 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, STA_MODIFY_REMOVE_BA_TID; status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status); + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), + &cmd, &status); if (ret) return ret; @@ -812,7 +699,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u8 queue, bool start) { struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - struct iwl_mvm_add_sta_cmd_v7 cmd = {}; + struct iwl_mvm_add_sta_cmd cmd = {}; int ret; u32 status; @@ -834,7 +721,8 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg); status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status); + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), + &cmd, &status); if (ret) return ret; @@ -1129,12 +1017,11 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags) { - __le16 key_flags; struct iwl_mvm_add_sta_key_cmd cmd = {}; + __le16 key_flags; int ret, status; u16 keyidx; int i; - u32 mac_id_n_color = mvm_sta->mac_id_n_color; keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & STA_KEY_FLG_KEYID_MSK; @@ -1167,12 +1054,11 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, status = ADD_STA_SUCCESS; if (cmd_flags == CMD_SYNC) - ret = iwl_mvm_send_add_sta_key_cmd_status(mvm, &cmd, - mac_id_n_color, - &status); + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, sizeof(cmd), + &cmd, &status); else - ret = iwl_mvm_send_add_sta_key_cmd(mvm, CMD_ASYNC, &cmd, - mac_id_n_color); + ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA_KEY, CMD_ASYNC, + sizeof(cmd), &cmd); switch (status) { case ADD_STA_SUCCESS: @@ -1399,9 +1285,8 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, cmd.sta_id = sta_id; status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_add_sta_key_cmd_status(mvm, &cmd, - mvm_sta->mac_id_n_color, - &status); + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, sizeof(cmd), + &cmd, &status); switch (status) { case ADD_STA_SUCCESS: @@ -1448,7 +1333,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - struct iwl_mvm_add_sta_cmd_v7 cmd = { + struct iwl_mvm_add_sta_cmd cmd = { .add_modify = STA_MODE_MODIFY, .sta_id = mvmsta->sta_id, .station_flags_msk = cpu_to_le32(STA_FLG_PS), @@ -1456,7 +1341,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, }; int ret; - ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); if (ret) IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); } @@ -1468,7 +1353,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, bool agg) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - struct iwl_mvm_add_sta_cmd_v7 cmd = { + struct iwl_mvm_add_sta_cmd cmd = { .add_modify = STA_MODE_MODIFY, .sta_id = mvmsta->sta_id, .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, @@ -1538,7 +1423,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_UAPSD); } - ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); if (ret) IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); } diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 2ed84c421481c7..e5e3071ff2523a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -253,6 +253,8 @@ enum iwl_mvm_agg_state { * This is basically (last acked packet++). * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA). + * @reduced_tpc: Reduced tx power. Holds the data between the + * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA). * @state: state of the BA agreement establishment / tear down. * @txq_id: Tx queue used by the BA session * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or @@ -265,6 +267,7 @@ struct iwl_mvm_tid_data { u16 next_reclaimed; /* The rest is Tx AGG related */ u32 rate_n_flags; + u8 reduced_tpc; enum iwl_mvm_agg_state state; u16 txq_id; u16 ssn; diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 61331245ad9324..a9402937f767a3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -273,67 +273,10 @@ static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait, return true; } -/* used to convert from time event API v2 to v1 */ -#define TE_V2_DEP_POLICY_MSK (TE_V2_DEP_OTHER | TE_V2_DEP_TSF |\ - TE_V2_EVENT_SOCIOPATHIC) -static inline u16 te_v2_get_notify(__le16 policy) -{ - return le16_to_cpu(policy) & TE_V2_NOTIF_MSK; -} - -static inline u16 te_v2_get_dep_policy(__le16 policy) -{ - return (le16_to_cpu(policy) & TE_V2_DEP_POLICY_MSK) >> - TE_V2_PLACEMENT_POS; -} - -static inline u16 te_v2_get_absence(__le16 policy) -{ - return (le16_to_cpu(policy) & TE_V2_ABSENCE) >> TE_V2_ABSENCE_POS; -} - -static void iwl_mvm_te_v2_to_v1(const struct iwl_time_event_cmd_v2 *cmd_v2, - struct iwl_time_event_cmd_v1 *cmd_v1) -{ - cmd_v1->id_and_color = cmd_v2->id_and_color; - cmd_v1->action = cmd_v2->action; - cmd_v1->id = cmd_v2->id; - cmd_v1->apply_time = cmd_v2->apply_time; - cmd_v1->max_delay = cmd_v2->max_delay; - cmd_v1->depends_on = cmd_v2->depends_on; - cmd_v1->interval = cmd_v2->interval; - cmd_v1->duration = cmd_v2->duration; - if (cmd_v2->repeat == TE_V2_REPEAT_ENDLESS) - cmd_v1->repeat = cpu_to_le32(TE_V1_REPEAT_ENDLESS); - else - cmd_v1->repeat = cpu_to_le32(cmd_v2->repeat); - cmd_v1->max_frags = cpu_to_le32(cmd_v2->max_frags); - cmd_v1->interval_reciprocal = 0; /* unused */ - - cmd_v1->dep_policy = cpu_to_le32(te_v2_get_dep_policy(cmd_v2->policy)); - cmd_v1->is_present = cpu_to_le32(!te_v2_get_absence(cmd_v2->policy)); - cmd_v1->notify = cpu_to_le32(te_v2_get_notify(cmd_v2->policy)); -} - -static int iwl_mvm_send_time_event_cmd(struct iwl_mvm *mvm, - const struct iwl_time_event_cmd_v2 *cmd) -{ - struct iwl_time_event_cmd_v1 cmd_v1; - - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2) - return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, - sizeof(*cmd), cmd); - - iwl_mvm_te_v2_to_v1(cmd, &cmd_v1); - return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, - sizeof(cmd_v1), &cmd_v1); -} - - static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_time_event_data *te_data, - struct iwl_time_event_cmd_v2 *te_cmd) + struct iwl_time_event_cmd *te_cmd) { static const u8 time_event_response[] = { TIME_EVENT_CMD }; struct iwl_notification_wait wait_time_event; @@ -369,7 +312,8 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, ARRAY_SIZE(time_event_response), iwl_mvm_time_event_response, te_data); - ret = iwl_mvm_send_time_event_cmd(mvm, te_cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, + sizeof(*te_cmd), te_cmd); if (ret) { IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); iwl_remove_notification(&mvm->notif_wait, &wait_time_event); @@ -397,7 +341,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; - struct iwl_time_event_cmd_v2 time_cmd = {}; + struct iwl_time_event_cmd time_cmd = {}; lockdep_assert_held(&mvm->mutex); @@ -453,7 +397,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif, struct iwl_mvm_time_event_data *te_data) { - struct iwl_time_event_cmd_v2 time_cmd = {}; + struct iwl_time_event_cmd time_cmd = {}; u32 id, uid; int ret; @@ -490,7 +434,8 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id)); - ret = iwl_mvm_send_time_event_cmd(mvm, &time_cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, + sizeof(time_cmd), &time_cmd); if (WARN_ON(ret)) return; } @@ -510,7 +455,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; - struct iwl_time_event_cmd_v2 time_cmd = {}; + struct iwl_time_event_cmd time_cmd = {}; lockdep_assert_held(&mvm->mutex); if (te_data->running) { diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 7a99fa361954e0..39a3e03a0acdcc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -468,13 +468,14 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm) } if (params->support_tx_backoff) { - tx_backoff = 0; + tx_backoff = tt->min_backoff; for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) { if (temperature < params->tx_backoff[i].temperature) break; - tx_backoff = params->tx_backoff[i].backoff; + tx_backoff = max(tt->min_backoff, + params->tx_backoff[i].backoff); } - if (tx_backoff != 0) + if (tx_backoff != tt->min_backoff) throttle_enable = true; if (tt->tx_backoff != tx_backoff) iwl_mvm_tt_tx_backoff(mvm, tx_backoff); @@ -484,7 +485,8 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm) IWL_WARN(mvm, "Due to high temperature thermal throttling initiated\n"); tt->throttle = true; - } else if (tt->throttle && !tt->dynamic_smps && tt->tx_backoff == 0 && + } else if (tt->throttle && !tt->dynamic_smps && + tt->tx_backoff == tt->min_backoff && temperature <= params->tx_protection_exit) { IWL_WARN(mvm, "Temperature is back to normal thermal throttling stopped\n"); diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 879aeac46cc103..ff1b630e130eed 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -636,7 +636,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, seq_ctl = le16_to_cpu(hdr->seq_ctrl); } - ieee80211_tx_status_ni(mvm->hw, skb); + BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1); + info->status.status_driver_data[0] = + (void *)(uintptr_t)tx_resp->reduced_tpc; + + ieee80211_tx_status(mvm->hw, skb); } if (txq_id >= mvm->first_agg_queue) { @@ -815,6 +819,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); mvmsta->tid_data[tid].rate_n_flags = le32_to_cpu(tx_resp->initial_rate); + mvmsta->tid_data[tid].reduced_tpc = tx_resp->reduced_tpc; } rcu_read_unlock(); @@ -928,6 +933,8 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, info->status.ampdu_len = ba_notif->txed; iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags, info); + info->status.status_driver_data[0] = + (void *)(uintptr_t)tid_data->reduced_tpc; } } @@ -937,7 +944,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, while (!skb_queue_empty(&reclaimed_skbs)) { skb = __skb_dequeue(&reclaimed_skbs); - ieee80211_tx_status_ni(mvm->hw, skb); + ieee80211_tx_status(mvm->hw, skb); } return 0; diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index d619851745a19b..9cd0309216df77 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -64,6 +64,7 @@ #include "iwl-debug.h" #include "iwl-io.h" +#include "iwl-prph.h" #include "mvm.h" #include "fw-api-rs.h" @@ -469,6 +470,8 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) mvm->status, table.valid); } + /* Do not change this output - scripts rely on it */ + IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version); trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low, @@ -516,13 +519,14 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) iwl_mvm_dump_umac_error_log(mvm); } +#ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm) { const struct fw_img *img; u32 ofs, sram_len; void *sram; - if (!mvm->ucode_loaded || mvm->fw_error_sram) + if (!mvm->ucode_loaded || mvm->fw_error_sram || mvm->fw_error_dump) return; img = &mvm->fw->img[mvm->cur_ucode]; @@ -538,6 +542,48 @@ void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm) mvm->fw_error_sram_len = sram_len; } +void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm) +{ + int i, reg_val; + unsigned long flags; + + if (!mvm->ucode_loaded || mvm->fw_error_rxf || mvm->fw_error_dump) + return; + + /* reading buffer size */ + reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR); + mvm->fw_error_rxf_len = + (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS; + + /* the register holds the value divided by 128 */ + mvm->fw_error_rxf_len = mvm->fw_error_rxf_len << 7; + + if (!mvm->fw_error_rxf_len) + return; + + mvm->fw_error_rxf = kzalloc(mvm->fw_error_rxf_len, GFP_ATOMIC); + if (!mvm->fw_error_rxf) { + mvm->fw_error_rxf_len = 0; + return; + } + + if (!iwl_trans_grab_nic_access(mvm->trans, false, &flags)) { + kfree(mvm->fw_error_rxf); + mvm->fw_error_rxf = NULL; + mvm->fw_error_rxf_len = 0; + return; + } + + for (i = 0; i < (mvm->fw_error_rxf_len / sizeof(u32)); i++) { + iwl_trans_write_prph(mvm->trans, RXF_LD_FENCE_OFFSET_ADDR, + i * sizeof(u32)); + mvm->fw_error_rxf[i] = + iwl_trans_read_prph(mvm->trans, RXF_FIFO_RD_FENCE_ADDR); + } + iwl_trans_release_nic_access(mvm->trans, &flags); +} +#endif + /** * iwl_mvm_send_lq_cmd() - Send link quality command * @init: This command is sent as part of station initialization right @@ -644,3 +690,22 @@ bool iwl_mvm_low_latency(struct iwl_mvm *mvm) return result; } + +static void iwl_mvm_assoc_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) +{ + bool *assoc = _data; + + if (vif->bss_conf.assoc) + *assoc = true; +} + +bool iwl_mvm_is_associated(struct iwl_mvm *mvm) +{ + bool assoc = false; + + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_assoc_iter, &assoc); + + return assoc; +} diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 9091513ea7388c..6c22b23a284572 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -102,7 +102,7 @@ struct iwl_rxq { u32 write_actual; struct list_head rx_free; struct list_head rx_used; - int need_update; + bool need_update; struct iwl_rb_status *rb_stts; dma_addr_t rb_stts_dma; spinlock_t lock; @@ -117,21 +117,19 @@ struct iwl_dma_ptr { /** * iwl_queue_inc_wrap - increment queue index, wrap back to beginning * @index -- current index - * @n_bd -- total number of entries in queue (must be power of 2) */ -static inline int iwl_queue_inc_wrap(int index, int n_bd) +static inline int iwl_queue_inc_wrap(int index) { - return ++index & (n_bd - 1); + return ++index & (TFD_QUEUE_SIZE_MAX - 1); } /** * iwl_queue_dec_wrap - decrement queue index, wrap back to end * @index -- current index - * @n_bd -- total number of entries in queue (must be power of 2) */ -static inline int iwl_queue_dec_wrap(int index, int n_bd) +static inline int iwl_queue_dec_wrap(int index) { - return --index & (n_bd - 1); + return --index & (TFD_QUEUE_SIZE_MAX - 1); } struct iwl_cmd_meta { @@ -145,13 +143,13 @@ struct iwl_cmd_meta { * * Contains common data for Rx and Tx queues. * - * Note the difference between n_bd and n_window: the hardware - * always assumes 256 descriptors, so n_bd is always 256 (unless + * Note the difference between TFD_QUEUE_SIZE_MAX and n_window: the hardware + * always assumes 256 descriptors, so TFD_QUEUE_SIZE_MAX is always 256 (unless * there might be HW changes in the future). For the normal TX * queues, n_window, which is the size of the software queue data * is also 256; however, for the command queue, n_window is only * 32 since we don't need so many commands pending. Since the HW - * still uses 256 BDs for DMA though, n_bd stays 256. As a result, + * still uses 256 BDs for DMA though, TFD_QUEUE_SIZE_MAX stays 256. As a result, * the software buffers (in the variables @meta, @txb in struct * iwl_txq) only have 32 entries, while the HW buffers (@tfds in * the same struct) have 256. @@ -162,7 +160,6 @@ struct iwl_cmd_meta { * data is a window overlayed over the HW queue. */ struct iwl_queue { - int n_bd; /* number of BDs in this queue */ int write_ptr; /* 1-st empty entry (index) host_w*/ int read_ptr; /* last used entry (index) host_r*/ /* use for monitoring and recovering the stuck queue */ @@ -231,7 +228,7 @@ struct iwl_txq { spinlock_t lock; struct timer_list stuck_timer; struct iwl_trans_pcie *trans_pcie; - u8 need_update; + bool need_update; u8 active; bool ampdu; }; @@ -270,6 +267,9 @@ struct iwl_trans_pcie { struct iwl_trans *trans; struct iwl_drv *drv; + struct net_device napi_dev; + struct napi_struct napi; + /* INT ICT Table */ __le32 *ict_tbl; dma_addr_t ict_tbl_dma; @@ -362,7 +362,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue); int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id); -void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq); +void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans); int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); void iwl_pcie_hcmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb, int handler_status); @@ -370,6 +370,13 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct sk_buff_head *skbs); void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); +static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx) +{ + struct iwl_tfd_tb *tb = &tfd->tbs[idx]; + + return le16_to_cpu(tb->hi_n_len) >> 4; +} + /***************************************************** * Error handling ******************************************************/ diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index fdfa3969cac986..a2698e5e062c99 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -145,15 +145,13 @@ int iwl_pcie_rx_stop(struct iwl_trans *trans) /* * iwl_pcie_rxq_inc_wr_ptr - Update the write pointer for the RX queue */ -static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, - struct iwl_rxq *rxq) +static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rxq *rxq = &trans_pcie->rxq; u32 reg; - spin_lock(&rxq->lock); - - if (rxq->need_update == 0) - goto exit_unlock; + lockdep_assert_held(&rxq->lock); /* * explicitly wake up the NIC if: @@ -169,13 +167,27 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, reg); iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - goto exit_unlock; + rxq->need_update = true; + return; } } rxq->write_actual = round_down(rxq->write, 8); iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual); - rxq->need_update = 0; +} + +static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rxq *rxq = &trans_pcie->rxq; + + spin_lock(&rxq->lock); + + if (!rxq->need_update) + goto exit_unlock; + + iwl_pcie_rxq_inc_wr_ptr(trans); + rxq->need_update = false; exit_unlock: spin_unlock(&rxq->lock); @@ -236,9 +248,8 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) * Increment device's write pointer in multiples of 8. */ if (rxq->write_actual != (rxq->write & ~0x7)) { spin_lock(&rxq->lock); - rxq->need_update = 1; + iwl_pcie_rxq_inc_wr_ptr(trans); spin_unlock(&rxq->lock); - iwl_pcie_rxq_inc_wr_ptr(trans, rxq); } } @@ -362,20 +373,9 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans) * Also restock the Rx queue via iwl_pcie_rxq_restock. * This is called as a scheduled work item (except for during initialization) */ -static void iwl_pcie_rx_replenish(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - - iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL); - - spin_lock(&trans_pcie->irq_lock); - iwl_pcie_rxq_restock(trans); - spin_unlock(&trans_pcie->irq_lock); -} - -static void iwl_pcie_rx_replenish_now(struct iwl_trans *trans) +static void iwl_pcie_rx_replenish(struct iwl_trans *trans, gfp_t gfp) { - iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC); + iwl_pcie_rxq_alloc_rbs(trans, gfp); iwl_pcie_rxq_restock(trans); } @@ -385,7 +385,7 @@ static void iwl_pcie_rx_replenish_work(struct work_struct *data) struct iwl_trans_pcie *trans_pcie = container_of(data, struct iwl_trans_pcie, rx_replenish); - iwl_pcie_rx_replenish(trans_pcie->trans); + iwl_pcie_rx_replenish(trans_pcie->trans, GFP_KERNEL); } static int iwl_pcie_rx_alloc(struct iwl_trans *trans) @@ -521,14 +521,13 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts)); spin_unlock(&rxq->lock); - iwl_pcie_rx_replenish(trans); + iwl_pcie_rx_replenish(trans, GFP_KERNEL); iwl_pcie_rx_hw_init(trans, rxq); - spin_lock(&trans_pcie->irq_lock); - rxq->need_update = 1; - iwl_pcie_rxq_inc_wr_ptr(trans, rxq); - spin_unlock(&trans_pcie->irq_lock); + spin_lock(&rxq->lock); + iwl_pcie_rxq_inc_wr_ptr(trans); + spin_unlock(&rxq->lock); return 0; } @@ -673,7 +672,6 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, /* Reuse the page if possible. For notification packets and * SKBs that fail to Rx correctly, add them back into the * rx_free list for reuse later. */ - spin_lock(&rxq->lock); if (rxb->page != NULL) { rxb->page_dma = dma_map_page(trans->dev, rxb->page, 0, @@ -694,7 +692,6 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, } } else list_add_tail(&rxb->list, &rxq->rx_used); - spin_unlock(&rxq->lock); } /* @@ -709,6 +706,8 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans) u32 count = 8; int total_empty; +restart: + spin_lock(&rxq->lock); /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ r = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF; @@ -743,18 +742,25 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans) count++; if (count >= 8) { rxq->read = i; - iwl_pcie_rx_replenish_now(trans); + spin_unlock(&rxq->lock); + iwl_pcie_rx_replenish(trans, GFP_ATOMIC); count = 0; + goto restart; } } } /* Backtrack one entry */ rxq->read = i; + spin_unlock(&rxq->lock); + if (fill_rx) - iwl_pcie_rx_replenish_now(trans); + iwl_pcie_rx_replenish(trans, GFP_ATOMIC); else iwl_pcie_rxq_restock(trans); + + if (trans_pcie->napi.poll) + napi_gro_flush(&trans_pcie->napi, false); } /* @@ -844,7 +850,7 @@ static u32 iwl_pcie_int_cause_ict(struct iwl_trans *trans) trans_pcie->ict_index, read); trans_pcie->ict_tbl[trans_pcie->ict_index] = 0; trans_pcie->ict_index = - iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT); + ((trans_pcie->ict_index + 1) & (ICT_COUNT - 1)); read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]); trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, @@ -876,7 +882,6 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) struct isr_statistics *isr_stats = &trans_pcie->isr_stats; u32 inta = 0; u32 handled = 0; - u32 i; lock_map_acquire(&trans->sync_cmd_lockdep_map); @@ -1028,9 +1033,8 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) /* uCode wakes up after power-down sleep */ if (inta & CSR_INT_BIT_WAKEUP) { IWL_DEBUG_ISR(trans, "Wakeup interrupt\n"); - iwl_pcie_rxq_inc_wr_ptr(trans, &trans_pcie->rxq); - for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) - iwl_pcie_txq_inc_wr_ptr(trans, &trans_pcie->txq[i]); + iwl_pcie_rxq_check_wrptr(trans); + iwl_pcie_txq_check_wrptrs(trans); isr_stats->wakeup++; @@ -1068,8 +1072,6 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) iwl_write8(trans, CSR_INT_PERIODIC_REG, CSR_INT_PERIODIC_DIS); - iwl_pcie_rx_handle(trans); - /* * Enable periodic interrupt in 8 msec only if we received * real RX interrupt (instead of just periodic int), to catch @@ -1082,6 +1084,10 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) CSR_INT_PERIODIC_ENA); isr_stats->rx++; + + local_bh_disable(); + iwl_pcie_rx_handle(trans); + local_bh_enable(); } /* This "Tx" DMA channel is used only for loading uCode */ diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index dcfd6d866d0950..a1af903f6c9bd8 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -73,6 +73,7 @@ #include "iwl-csr.h" #include "iwl-prph.h" #include "iwl-agn-hw.h" +#include "iwl-fw-error-dump.h" #include "internal.h" static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg) @@ -103,7 +104,6 @@ static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) /* PCI registers */ #define PCI_CFG_RETRY_TIMEOUT 0x041 -#define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC static void iwl_pcie_apm_config(struct iwl_trans *trans) { @@ -1053,6 +1053,12 @@ static void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr, iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val); } +static int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget) +{ + WARN_ON(1); + return 0; +} + static void iwl_trans_pcie_configure(struct iwl_trans *trans, const struct iwl_trans_config *trans_cfg) { @@ -1079,6 +1085,18 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, trans_pcie->command_names = trans_cfg->command_names; trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; + + /* Initialize NAPI here - it should be before registering to mac80211 + * in the opmode but after the HW struct is allocated. + * As this function may be called again in some corner cases don't + * do anything if NAPI was already initialized. + */ + if (!trans_pcie->napi.poll && trans->op_mode->ops->napi_add) { + init_dummy_netdev(&trans_pcie->napi_dev); + iwl_op_mode_napi_add(trans->op_mode, &trans_pcie->napi, + &trans_pcie->napi_dev, + iwl_pcie_dummy_napi_poll, 64); + } } void iwl_trans_pcie_free(struct iwl_trans *trans) @@ -1099,6 +1117,9 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) pci_disable_device(trans_pcie->pci_dev); kmem_cache_destroy(trans->dev_cmd_pool); + if (trans_pcie->napi.poll) + netif_napi_del(&trans_pcie->napi); + kfree(trans); } @@ -1237,7 +1258,7 @@ static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, #define IWL_FLUSH_WAIT_MS 2000 -static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) +static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq; @@ -1250,13 +1271,31 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) /* waiting for all the tx frames complete might take a while */ for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) { + u8 wr_ptr; + if (cnt == trans_pcie->cmd_queue) continue; + if (!test_bit(cnt, trans_pcie->queue_used)) + continue; + if (!(BIT(cnt) & txq_bm)) + continue; + + IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", cnt); txq = &trans_pcie->txq[cnt]; q = &txq->q; - while (q->read_ptr != q->write_ptr && !time_after(jiffies, - now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) + wr_ptr = ACCESS_ONCE(q->write_ptr); + + while (q->read_ptr != ACCESS_ONCE(q->write_ptr) && + !time_after(jiffies, + now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) { + u8 write_ptr = ACCESS_ONCE(q->write_ptr); + + if (WARN_ONCE(wr_ptr != write_ptr, + "WR pointer moved while flushing %d -> %d\n", + wr_ptr, write_ptr)) + return -ETIMEDOUT; msleep(1); + } if (q->read_ptr != q->write_ptr) { IWL_ERR(trans, @@ -1264,6 +1303,7 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) ret = -ETIMEDOUT; break; } + IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", cnt); } if (!ret) @@ -1298,8 +1338,8 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) IWL_ERR(trans, "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n", cnt, active ? "" : "in", fifo, tbl_dw, - iwl_read_prph(trans, - SCD_QUEUE_RDPTR(cnt)) & (txq->q.n_bd - 1), + iwl_read_prph(trans, SCD_QUEUE_RDPTR(cnt)) & + (TFD_QUEUE_SIZE_MAX - 1), iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt))); } @@ -1630,6 +1670,61 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, IWL_ERR(trans, "failed to create the trans debugfs entry\n"); return -ENOMEM; } + +static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd) +{ + u32 cmdlen = 0; + int i; + + for (i = 0; i < IWL_NUM_OF_TBS; i++) + cmdlen += iwl_pcie_tfd_tb_get_len(tfd, i); + + return cmdlen; +} + +static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, + void *buf, u32 buflen) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_fw_error_dump_data *data; + struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue]; + struct iwl_fw_error_dump_txcmd *txcmd; + u32 len; + int i, ptr; + + if (!buf) + return sizeof(*data) + + cmdq->q.n_window * (sizeof(*txcmd) + + TFD_MAX_PAYLOAD_SIZE); + + len = 0; + data = buf; + data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD); + txcmd = (void *)data->data; + spin_lock_bh(&cmdq->lock); + ptr = cmdq->q.write_ptr; + for (i = 0; i < cmdq->q.n_window; i++) { + u8 idx = get_cmd_index(&cmdq->q, ptr); + u32 caplen, cmdlen; + + cmdlen = iwl_trans_pcie_get_cmdlen(&cmdq->tfds[ptr]); + caplen = min_t(u32, TFD_MAX_PAYLOAD_SIZE, cmdlen); + + if (cmdlen) { + len += sizeof(*txcmd) + caplen; + txcmd->cmdlen = cpu_to_le32(cmdlen); + txcmd->caplen = cpu_to_le32(caplen); + memcpy(txcmd->data, cmdq->entries[idx].cmd, caplen); + txcmd = (void *)((u8 *)txcmd->data + caplen); + } + + ptr = iwl_queue_dec_wrap(ptr); + } + spin_unlock_bh(&cmdq->lock); + + data->len = cpu_to_le32(len); + return sizeof(*data) + len; +} #else static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, struct dentry *dir) @@ -1672,6 +1767,10 @@ static const struct iwl_trans_ops trans_ops_pcie = { .grab_nic_access = iwl_trans_pcie_grab_nic_access, .release_nic_access = iwl_trans_pcie_release_nic_access, .set_bits_mask = iwl_trans_pcie_set_bits_mask, + +#ifdef CONFIG_IWLWIFI_DEBUGFS + .dump_data = iwl_trans_pcie_dump_data, +#endif }; struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, @@ -1749,6 +1848,10 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); + trans->dev = &pdev->dev; + trans_pcie->pci_dev = pdev; + iwl_disable_interrupts(trans); + err = pci_enable_msi(pdev); if (err) { dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", err); @@ -1760,8 +1863,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } } - trans->dev = &pdev->dev; - trans_pcie->pci_dev = pdev; trans->hw_rev = iwl_read32(trans, CSR_HW_REV); trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), @@ -1787,8 +1888,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, goto out_pci_disable_msi; } - trans_pcie->inta_mask = CSR_INI_SET_MASK; - if (iwl_pcie_alloc_ict(trans)) goto out_free_cmd_pool; @@ -1800,6 +1899,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, goto out_free_ict; } + trans_pcie->inta_mask = CSR_INI_SET_MASK; + return trans; out_free_ict: diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 3b0c72c1005446..77a512a5a755d8 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -70,20 +70,20 @@ static int iwl_queue_space(const struct iwl_queue *q) /* * To avoid ambiguity between empty and completely full queues, there - * should always be less than q->n_bd elements in the queue. - * If q->n_window is smaller than q->n_bd, there is no need to reserve - * any queue entries for this purpose. + * should always be less than TFD_QUEUE_SIZE_MAX elements in the queue. + * If q->n_window is smaller than TFD_QUEUE_SIZE_MAX, there is no need + * to reserve any queue entries for this purpose. */ - if (q->n_window < q->n_bd) + if (q->n_window < TFD_QUEUE_SIZE_MAX) max = q->n_window; else - max = q->n_bd - 1; + max = TFD_QUEUE_SIZE_MAX - 1; /* - * q->n_bd is a power of 2, so the following is equivalent to modulo by - * q->n_bd and is well defined for negative dividends. + * TFD_QUEUE_SIZE_MAX is a power of 2, so the following is equivalent to + * modulo by TFD_QUEUE_SIZE_MAX and is well defined. */ - used = (q->write_ptr - q->read_ptr) & (q->n_bd - 1); + used = (q->write_ptr - q->read_ptr) & (TFD_QUEUE_SIZE_MAX - 1); if (WARN_ON(used > max)) return 0; @@ -94,17 +94,11 @@ static int iwl_queue_space(const struct iwl_queue *q) /* * iwl_queue_init - Initialize queue's high/low-water and read/write indexes */ -static int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id) +static int iwl_queue_init(struct iwl_queue *q, int slots_num, u32 id) { - q->n_bd = count; q->n_window = slots_num; q->id = id; - /* count must be power-of-two size, otherwise iwl_queue_inc_wrap - * and iwl_queue_dec_wrap are broken. */ - if (WARN_ON(!is_power_of_2(count))) - return -EINVAL; - /* slots_num must be power-of-two size, otherwise * get_cmd_index is broken. */ if (WARN_ON(!is_power_of_2(slots_num))) @@ -197,13 +191,13 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) IWL_ERR(trans, "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n", i, active ? "" : "in", fifo, tbl_dw, - iwl_read_prph(trans, - SCD_QUEUE_RDPTR(i)) & (txq->q.n_bd - 1), + iwl_read_prph(trans, SCD_QUEUE_RDPTR(i)) & + (TFD_QUEUE_SIZE_MAX - 1), iwl_read_prph(trans, SCD_QUEUE_WRPTR(i))); } for (i = q->read_ptr; i != q->write_ptr; - i = iwl_queue_inc_wrap(i, q->n_bd)) + i = iwl_queue_inc_wrap(i)) IWL_ERR(trans, "scratch %d = 0x%08x\n", i, le32_to_cpu(txq->scratchbufs[i].scratch)); @@ -287,14 +281,14 @@ static void iwl_pcie_txq_inval_byte_cnt_tbl(struct iwl_trans *trans, /* * iwl_pcie_txq_inc_wr_ptr - Send new write index to hardware */ -void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq) +static void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, + struct iwl_txq *txq) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 reg = 0; int txq_id = txq->q.id; - if (txq->need_update == 0) - return; + lockdep_assert_held(&txq->lock); /* * explicitly wake up the NIC if: @@ -317,6 +311,7 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq) txq_id, reg); iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + txq->need_update = true; return; } } @@ -327,8 +322,23 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq) */ IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->q.write_ptr); iwl_write32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); +} + +void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int i; + + for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { + struct iwl_txq *txq = &trans_pcie->txq[i]; - txq->need_update = 0; + spin_lock(&txq->lock); + if (trans_pcie->txq[i].need_update) { + iwl_pcie_txq_inc_wr_ptr(trans, txq); + trans_pcie->txq[i].need_update = false; + } + spin_unlock(&txq->lock); + } } static inline dma_addr_t iwl_pcie_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) @@ -343,13 +353,6 @@ static inline dma_addr_t iwl_pcie_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) return addr; } -static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx) -{ - struct iwl_tfd_tb *tb = &tfd->tbs[idx]; - - return le16_to_cpu(tb->hi_n_len) >> 4; -} - static inline void iwl_pcie_tfd_set_tb(struct iwl_tfd *tfd, u8 idx, dma_addr_t addr, u16 len) { @@ -409,13 +412,17 @@ static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) { struct iwl_tfd *tfd_tmp = txq->tfds; - /* rd_ptr is bounded by n_bd and idx is bounded by n_window */ + /* rd_ptr is bounded by TFD_QUEUE_SIZE_MAX and + * idx is bounded by n_window + */ int rd_ptr = txq->q.read_ptr; int idx = get_cmd_index(&txq->q, rd_ptr); lockdep_assert_held(&txq->lock); - /* We have only q->n_window txq->entries, but we use q->n_bd tfds */ + /* We have only q->n_window txq->entries, but we use + * TFD_QUEUE_SIZE_MAX tfds + */ iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr]); /* free SKB */ @@ -436,7 +443,7 @@ static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) } static int iwl_pcie_txq_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, - dma_addr_t addr, u16 len, u8 reset) + dma_addr_t addr, u16 len, bool reset) { struct iwl_queue *q; struct iwl_tfd *tfd, *tfd_tmp; @@ -542,15 +549,14 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, { int ret; - txq->need_update = 0; + txq->need_update = false; /* 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)); /* Initialize queue's high/low-water marks, and head/tail indexes */ - ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num, - txq_id); + ret = iwl_queue_init(&txq->q, slots_num, txq_id); if (ret) return ret; @@ -575,15 +581,12 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) struct iwl_txq *txq = &trans_pcie->txq[txq_id]; struct iwl_queue *q = &txq->q; - if (!q->n_bd) - return; - spin_lock_bh(&txq->lock); while (q->write_ptr != q->read_ptr) { IWL_DEBUG_TX_REPLY(trans, "Q %d Free %d\n", txq_id, q->read_ptr); iwl_pcie_txq_free_tfd(trans, txq); - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr); } txq->active = false; spin_unlock_bh(&txq->lock); @@ -620,10 +623,12 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) } /* De-alloc circular buffer of TFDs */ - if (txq->q.n_bd) { - dma_free_coherent(dev, sizeof(struct iwl_tfd) * - txq->q.n_bd, txq->tfds, txq->q.dma_addr); + if (txq->tfds) { + dma_free_coherent(dev, + sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX, + txq->tfds, txq->q.dma_addr); txq->q.dma_addr = 0; + txq->tfds = NULL; dma_free_coherent(dev, sizeof(*txq->scratchbufs) * txq->q.n_window, @@ -680,7 +685,8 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) /* The chain extension of the SCD doesn't work well. This feature is * enabled by default by the HW, so we need to disable it manually. */ - iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); + if (trans->cfg->base_params->scd_chain_ext_wa) + iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue, trans_pcie->cmd_fifo); @@ -931,8 +937,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq = &trans_pcie->txq[txq_id]; - /* n_bd is usually 256 => n_bd - 1 = 0xff */ - int tfd_num = ssn & (txq->q.n_bd - 1); + int tfd_num = ssn & (TFD_QUEUE_SIZE_MAX - 1); struct iwl_queue *q = &txq->q; int last_to_free; @@ -956,12 +961,12 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, /*Since we free until index _not_ inclusive, the one before index is * the last we will free. This one must be used */ - last_to_free = iwl_queue_dec_wrap(tfd_num, q->n_bd); + last_to_free = iwl_queue_dec_wrap(tfd_num); if (!iwl_queue_used(q, last_to_free)) { IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n", - __func__, txq_id, last_to_free, q->n_bd, + __func__, txq_id, last_to_free, TFD_QUEUE_SIZE_MAX, q->write_ptr, q->read_ptr); goto out; } @@ -971,7 +976,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, for (; q->read_ptr != tfd_num; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr)) { if (WARN_ON_ONCE(txq->entries[txq->q.read_ptr].skb == NULL)) continue; @@ -1010,16 +1015,16 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) lockdep_assert_held(&txq->lock); - if ((idx >= q->n_bd) || (!iwl_queue_used(q, idx))) { + if ((idx >= TFD_QUEUE_SIZE_MAX) || (!iwl_queue_used(q, idx))) { IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.\n", - __func__, txq_id, idx, q->n_bd, + __func__, txq_id, idx, TFD_QUEUE_SIZE_MAX, q->write_ptr, q->read_ptr); return; } - for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + for (idx = iwl_queue_inc_wrap(idx); q->read_ptr != idx; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr)) { if (nfreed++ > 0) { IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", @@ -1028,7 +1033,8 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) } } - if (q->read_ptr == q->write_ptr) { + if (trans->cfg->base_params->apmg_wake_up_wa && + q->read_ptr == q->write_ptr) { spin_lock_irqsave(&trans_pcie->reg_lock, flags); WARN_ON(!trans_pcie->cmd_in_flight); trans_pcie->cmd_in_flight = false; @@ -1309,28 +1315,39 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, cmd_pos = offsetof(struct iwl_device_cmd, payload); copy_size = sizeof(out_cmd->hdr); for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { - int copy = 0; + int copy; if (!cmd->len[i]) continue; - /* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */ - if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) { - copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size; - - if (copy > cmd->len[i]) - copy = cmd->len[i]; - } - /* copy everything if not nocopy/dup */ if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | - IWL_HCMD_DFL_DUP))) + IWL_HCMD_DFL_DUP))) { copy = cmd->len[i]; - if (copy) { memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy); cmd_pos += copy; copy_size += copy; + continue; + } + + /* + * Otherwise we need at least IWL_HCMD_SCRATCHBUF_SIZE copied + * in total (for the scratchbuf handling), but copy up to what + * we can fit into the payload for debug dump purposes. + */ + copy = min_t(int, TFD_MAX_PAYLOAD_SIZE - cmd_pos, cmd->len[i]); + + memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy); + cmd_pos += copy; + + /* However, treat copy_size the proper way, we need it below */ + if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) { + copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size; + + if (copy > cmd->len[i]) + copy = cmd->len[i]; + copy_size += copy; } } @@ -1345,7 +1362,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, memcpy(&txq->scratchbufs[q->write_ptr], &out_cmd->hdr, scratch_size); iwl_pcie_txq_build_tfd(trans, txq, iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr), - scratch_size, 1); + scratch_size, true); /* map first command fragment, if any remains */ if (copy_size > scratch_size) { @@ -1361,7 +1378,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, } iwl_pcie_txq_build_tfd(trans, txq, phys_addr, - copy_size - scratch_size, 0); + copy_size - scratch_size, false); } /* map the remaining (adjusted) nocopy/dup fragments */ @@ -1384,7 +1401,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, goto out; } - iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], 0); + iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], false); } out_meta->flags = cmd->flags; @@ -1392,8 +1409,6 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, kfree(txq->entries[idx].free_buf); txq->entries[idx].free_buf = dup_buf; - txq->need_update = 1; - trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); /* start timer if queue currently empty */ @@ -1405,9 +1420,11 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, /* * wake up the NIC to make sure that the firmware will see the host * command - we will let the NIC sleep once all the host commands - * returned. + * returned. This needs to be done only on NICs that have + * apmg_wake_up_wa set. */ - if (!trans_pcie->cmd_in_flight) { + if (trans->cfg->base_params->apmg_wake_up_wa && + !trans_pcie->cmd_in_flight) { trans_pcie->cmd_in_flight = true; __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); @@ -1427,7 +1444,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, } /* Increment and update queue's write index */ - q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr); iwl_pcie_txq_inc_wr_ptr(trans, txq); spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); @@ -1661,7 +1678,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, dma_addr_t tb0_phys, tb1_phys, scratch_phys; void *tb1_addr; u16 len, tb1_len, tb2_len; - u8 wait_write_ptr = 0; + bool wait_write_ptr; __le16 fc = hdr->frame_control; u8 hdr_len = ieee80211_hdrlen(fc); u16 wifi_seq; @@ -1722,7 +1739,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, memcpy(&txq->scratchbufs[q->write_ptr], &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE); iwl_pcie_txq_build_tfd(trans, txq, tb0_phys, - IWL_HCMD_SCRATCHBUF_SIZE, 1); + IWL_HCMD_SCRATCHBUF_SIZE, true); /* there must be data left over for TB1 or this code must be changed */ BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_HCMD_SCRATCHBUF_SIZE); @@ -1732,7 +1749,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, tb1_phys = dma_map_single(trans->dev, tb1_addr, tb1_len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(trans->dev, tb1_phys))) goto out_err; - iwl_pcie_txq_build_tfd(trans, txq, tb1_phys, tb1_len, 0); + iwl_pcie_txq_build_tfd(trans, txq, tb1_phys, tb1_len, false); /* * Set up TFD's third entry to point directly to remainder @@ -1748,7 +1765,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, &txq->tfds[q->write_ptr]); goto out_err; } - iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, 0); + iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, false); } /* Set up entry for this TFD in Tx byte-count array */ @@ -1762,12 +1779,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, trace_iwlwifi_dev_tx_data(trans->dev, skb, skb->data + hdr_len, tb2_len); - if (!ieee80211_has_morefrags(fc)) { - txq->need_update = 1; - } else { - wait_write_ptr = 1; - txq->need_update = 0; - } + wait_write_ptr = ieee80211_has_morefrags(fc); /* start timer if queue currently empty */ if (txq->need_update && q->read_ptr == q->write_ptr && @@ -1775,22 +1787,19 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); /* Tell device the write index *just past* this latest filled TFD */ - q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - iwl_pcie_txq_inc_wr_ptr(trans, txq); + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr); + if (!wait_write_ptr) + iwl_pcie_txq_inc_wr_ptr(trans, txq); /* * At this point the frame is "transmitted" successfully - * and we will get a TX status notification eventually, - * regardless of the value of ret. "ret" only indicates - * whether or not we should update the write pointer. + * and we will get a TX status notification eventually. */ if (iwl_queue_space(q) < q->high_mark) { - if (wait_write_ptr) { - txq->need_update = 1; + if (wait_write_ptr) iwl_pcie_txq_inc_wr_ptr(trans, txq); - } else { + else iwl_stop_queue(trans, txq); - } } spin_unlock(&txq->lock); return 0; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 9d7a52f5a4102a..a312c653d1163f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1676,7 +1676,9 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, return 0; } -static void mac80211_hwsim_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void mac80211_hwsim_flush(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 queues, bool drop) { /* Not implemented, queues only on kernel side */ } @@ -2056,6 +2058,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_HAS_CHANNEL_SWITCH; hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; + hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; /* ask mac80211 to reserve space for magic */ hw->vif_data_size = sizeof(struct hwsim_vif_priv); diff --git a/drivers/net/wireless/mwifiex/11ac.c b/drivers/net/wireless/mwifiex/11ac.c index c92f27aa71ede1..706831df1fa2a4 100644 --- a/drivers/net/wireless/mwifiex/11ac.c +++ b/drivers/net/wireless/mwifiex/11ac.c @@ -212,8 +212,7 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv, sizeof(struct mwifiex_ie_types_header)); memcpy((u8 *)vht_op + sizeof(struct mwifiex_ie_types_header), - (u8 *)bss_desc->bcn_vht_oper + - sizeof(struct ieee_types_header), + (u8 *)bss_desc->bcn_vht_oper, le16_to_cpu(vht_op->header.len)); /* negotiate the channel width and central freq diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index d14ead8beca860..e1c2f67ae85e69 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -345,8 +345,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, memcpy((u8 *) ht_info + sizeof(struct mwifiex_ie_types_header), - (u8 *) bss_desc->bcn_ht_oper + - sizeof(struct ieee_types_header), + (u8 *)bss_desc->bcn_ht_oper, le16_to_cpu(ht_info->header.len)); if (!(sband->ht_cap.cap & @@ -750,3 +749,45 @@ void mwifiex_set_ba_params(struct mwifiex_private *priv) return; } + +u8 mwifiex_get_sec_chan_offset(int chan) +{ + u8 sec_offset; + + switch (chan) { + case 36: + case 44: + case 52: + case 60: + case 100: + case 108: + case 116: + case 124: + case 132: + case 140: + case 149: + case 157: + sec_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + break; + case 40: + case 48: + case 56: + case 64: + case 104: + case 112: + case 120: + case 128: + case 136: + case 144: + case 153: + case 161: + sec_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; + break; + case 165: + default: + sec_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; + break; + } + + return sec_offset; +} diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 40b007a00f4bd9..43889d9e3b35d4 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -63,6 +63,7 @@ int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, int cmd_action, struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl); void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra); +u8 mwifiex_get_sec_chan_offset(int chan); static inline u8 mwifiex_is_station_ampdu_allowed(struct mwifiex_private *priv, diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 63211707f93955..860dfe71cf965b 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -160,6 +160,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, int pad = 0, ret; struct mwifiex_tx_param tx_param; struct txpd *ptx_pd = NULL; + struct timeval tv; int headroom = adapter->iface_type == MWIFIEX_USB ? 0 : INTF_HEADER_LEN; skb_src = skb_peek(&pra_list->skb_head); @@ -184,6 +185,9 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, tx_info_aggr->bss_num = tx_info_src->bss_num; skb_aggr->priority = skb_src->priority; + do_gettimeofday(&tv); + skb_aggr->tstamp = timeval_to_ktime(tv); + do { /* Check if AMSDU can accommodate this MSDU */ if (skb_tailroom(skb_aggr) < (skb_src->len + LLC_SNAP_LEN)) @@ -236,18 +240,11 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_USB_EP_DATA, skb_aggr, NULL); } else { - /* - * Padding per MSDU will affect the length of next - * packet and hence the exact length of next packet - * is uncertain here. - * - * Also, aggregation of transmission buffer, while - * downloading the data to the card, wont gain much - * on the AMSDU packets as the AMSDU packets utilizes - * the transmission buffer space to the maximum - * (adapter->tx_buf_size). - */ - tx_param.next_pkt_len = 0; + if (skb_src) + tx_param.next_pkt_len = + skb_src->len + sizeof(struct txpd); + else + tx_param.next_pkt_len = 0; ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb_aggr, &tx_param); diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README index b9242c3dca435e..3b55ce5690a54e 100644 --- a/drivers/net/wireless/mwifiex/README +++ b/drivers/net/wireless/mwifiex/README @@ -200,4 +200,11 @@ getlog cat getlog +fw_dump + This command is used to dump firmware memory into files. + Separate file will be created for each memory segment. + Usage: + + cat fw_dump + =============================================================================== diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 1062c918a7bffb..8dee6c86f4f1dc 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -955,8 +955,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) adapter->cmd_wait_q.status = -ETIMEDOUT; wake_up_interruptible(&adapter->cmd_wait_q.wait); mwifiex_cancel_pending_ioctl(adapter); - /* reset cmd_sent flag to unblock new commands */ - adapter->cmd_sent = false; } } if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index b8a49aad12fd66..7b419bbcd5444f 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -256,6 +256,29 @@ mwifiex_info_read(struct file *file, char __user *ubuf, return ret; } +/* + * Proc firmware dump read handler. + * + * This function is called when the 'fw_dump' file is opened for + * reading. + * This function dumps firmware memory in different files + * (ex. DTCM, ITCM, SQRAM etc.) based on the the segments for + * debugging. + */ +static ssize_t +mwifiex_fw_dump_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = file->private_data; + + if (!priv->adapter->if_ops.fw_dump) + return -EIO; + + priv->adapter->if_ops.fw_dump(priv->adapter); + + return 0; +} + /* * Proc getlog file read handler. * @@ -699,6 +722,7 @@ static const struct file_operations mwifiex_dfs_##name##_fops = { \ MWIFIEX_DFS_FILE_READ_OPS(info); MWIFIEX_DFS_FILE_READ_OPS(debug); MWIFIEX_DFS_FILE_READ_OPS(getlog); +MWIFIEX_DFS_FILE_READ_OPS(fw_dump); MWIFIEX_DFS_FILE_OPS(regrdwr); MWIFIEX_DFS_FILE_OPS(rdeeprom); @@ -722,6 +746,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) MWIFIEX_DFS_ADD_FILE(getlog); MWIFIEX_DFS_ADD_FILE(regrdwr); MWIFIEX_DFS_ADD_FILE(rdeeprom); + MWIFIEX_DFS_ADD_FILE(fw_dump); } /* diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index e7b3e16e5d34f1..38da6ff6f41623 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -42,12 +42,12 @@ #define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2 #define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16 -#define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE 16 -#define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE 32 +#define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE 64 +#define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE 64 #define MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE 32 #define MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE 16 -#define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE 32 -#define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE 48 +#define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE 64 +#define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE 64 #define MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE 48 #define MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE 32 diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index b485dc1ae5ebc4..ee59508307ccaa 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -169,6 +169,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146) #define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) #define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156) +#define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194) #define TLV_TYPE_FW_API_REV (PROPRIETARY_TLV_BASE_ID + 199) #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 @@ -229,6 +230,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISENABLED_40MHZ_INTOLERANT(Dot11nDevCap) (Dot11nDevCap & BIT(8)) #define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & BIT(22)) #define ISSUPP_BEAMFORMING(Dot11nDevCap) (Dot11nDevCap & BIT(30)) +#define ISALLOWED_CHANWIDTH40(ht_param) (ht_param & BIT(2)) /* httxcfg bitmap * 0 reserved @@ -487,6 +489,7 @@ enum P2P_MODES { #define EVENT_UAP_MIC_COUNTERMEASURES 0x0000004c #define EVENT_HOSTWAKE_STAIE 0x0000004d #define EVENT_CHANNEL_SWITCH_ANN 0x00000050 +#define EVENT_TDLS_GENERIC_EVENT 0x00000052 #define EVENT_EXT_SCAN_REPORT 0x00000058 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f @@ -519,6 +522,7 @@ enum P2P_MODES { #define ACT_TDLS_DELETE 0x00 #define ACT_TDLS_CREATE 0x01 #define ACT_TDLS_CONFIG 0x02 +#define TDLS_EVENT_LINK_TEAR_DOWN 3 #define MWIFIEX_FW_V15 15 @@ -708,6 +712,13 @@ struct mwifiex_ie_types_vendor_param_set { u8 ie[MWIFIEX_MAX_VSIE_LEN]; }; +#define MWIFIEX_TDLS_IDLE_TIMEOUT 60 + +struct mwifiex_ie_types_tdls_idle_timeout { + struct mwifiex_ie_types_header header; + __le16 value; +} __packed; + struct mwifiex_ie_types_rsn_param_set { struct mwifiex_ie_types_header header; u8 rsn_ie[1]; @@ -1745,6 +1756,15 @@ struct host_cmd_ds_802_11_subsc_evt { __le16 events; } __packed; +struct mwifiex_tdls_generic_event { + __le16 type; + u8 peer_mac[ETH_ALEN]; + union { + __le16 reason_code; + __le16 reserved; + } u; +} __packed; + struct mwifiex_ie { __le16 ie_index; __le16 mgmt_subtype_mask; diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index ee494db5406097..1b576722671d5e 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -303,7 +303,7 @@ struct mwifiex_ds_ant_cfg { u32 rx_ant; }; -#define MWIFIEX_NUM_OF_CMD_BUFFER 20 +#define MWIFIEX_NUM_OF_CMD_BUFFER 50 #define MWIFIEX_SIZE_OF_CMD_BUFFER 2048 enum { diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 9c771b3e99186f..cbabc12fbda390 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -521,7 +521,6 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) release_firmware(adapter->firmware); adapter->firmware = NULL; } - complete(&adapter->fw_load); if (init_failed) mwifiex_free_adapter(adapter); up(sem); @@ -535,7 +534,6 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) { int ret; - init_completion(&adapter->fw_load); ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name, adapter->dev, GFP_KERNEL, adapter, mwifiex_fw_dpc); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index d53e1e8c9467a6..34181192a666b7 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -672,6 +672,7 @@ struct mwifiex_if_ops { int (*init_fw_port) (struct mwifiex_adapter *); int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); void (*card_reset) (struct mwifiex_adapter *); + void (*fw_dump)(struct mwifiex_adapter *); int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); }; @@ -787,7 +788,6 @@ struct mwifiex_adapter { struct mwifiex_wait_queue cmd_wait_q; u8 scan_wait_q_woken; spinlock_t queue_lock; /* lock for tx queues */ - struct completion fw_load; u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; u16 max_mgmt_ie_index; u8 scan_delay_cnt; diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index a7e8b96b2d9024..c2cfeec466d87b 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -221,9 +221,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev) if (!adapter || !adapter->priv_num) return; - /* In case driver is removed when asynchronous FW load is in progress */ - wait_for_completion(&adapter->fw_load); - if (user_rmmod) { #ifdef CONFIG_PM_SLEEP if (adapter->is_suspended) diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 7b3af3d29ded47..d75f4ebd4bdce7 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -29,9 +29,6 @@ #define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN 14 #define MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD 4 -#define MWIFIEX_LIMIT_1_CHANNEL_PER_SCAN_CMD 15 -#define MWIFIEX_LIMIT_2_CHANNELS_PER_SCAN_CMD 27 -#define MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD 35 /* Memory needed to store a max sized Channel List TLV for a firmware scan */ #define CHAN_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_header) \ @@ -1055,20 +1052,10 @@ mwifiex_config_scan(struct mwifiex_private *priv, /* * In associated state we will reduce the number of channels scanned per - * scan command to avoid any traffic delay/loss. This number is decided - * based on total number of channels to be scanned due to constraints - * of command buffers. + * scan command to 1 to avoid any traffic delay/loss. */ - if (priv->media_connected) { - if (chan_num < MWIFIEX_LIMIT_1_CHANNEL_PER_SCAN_CMD) + if (priv->media_connected) *max_chan_per_scan = 1; - else if (chan_num < MWIFIEX_LIMIT_2_CHANNELS_PER_SCAN_CMD) - *max_chan_per_scan = 2; - else if (chan_num < MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD) - *max_chan_per_scan = 3; - else - *max_chan_per_scan = 4; - } } /* @@ -1353,23 +1340,17 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, bss_entry->beacon_buf); break; case WLAN_EID_BSS_COEX_2040: - bss_entry->bcn_bss_co_2040 = current_ptr + - sizeof(struct ieee_types_header); - bss_entry->bss_co_2040_offset = (u16) (current_ptr + - sizeof(struct ieee_types_header) - - bss_entry->beacon_buf); + bss_entry->bcn_bss_co_2040 = current_ptr; + bss_entry->bss_co_2040_offset = + (u16) (current_ptr - bss_entry->beacon_buf); break; case WLAN_EID_EXT_CAPABILITY: - bss_entry->bcn_ext_cap = current_ptr + - sizeof(struct ieee_types_header); - bss_entry->ext_cap_offset = (u16) (current_ptr + - sizeof(struct ieee_types_header) - - bss_entry->beacon_buf); + bss_entry->bcn_ext_cap = current_ptr; + bss_entry->ext_cap_offset = + (u16) (current_ptr - bss_entry->beacon_buf); break; case WLAN_EID_OPMODE_NOTIF: - bss_entry->oper_mode = - (void *)(current_ptr + - sizeof(struct ieee_types_header)); + bss_entry->oper_mode = (void *)current_ptr; bss_entry->oper_mode_offset = (u16)((u8 *)bss_entry->oper_mode - bss_entry->beacon_buf); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index d206f04d499498..a1773d3cb49f48 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -85,6 +85,8 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) card->supports_sdio_new_mode = data->supports_sdio_new_mode; card->has_control_mask = data->has_control_mask; card->tx_buf_size = data->tx_buf_size; + card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size; + card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; } sdio_claim_host(func); @@ -177,9 +179,6 @@ mwifiex_sdio_remove(struct sdio_func *func) if (!adapter || !adapter->priv_num) return; - /* In case driver is removed when asynchronous FW load is in progress */ - wait_for_completion(&adapter->fw_load); - if (user_rmmod) { if (adapter->is_suspended) mwifiex_sdio_resume(adapter->dev); @@ -1842,8 +1841,8 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) card->mpa_rx.len_arr = kzalloc(sizeof(*card->mpa_rx.len_arr) * card->mp_agg_pkt_limit, GFP_KERNEL); ret = mwifiex_alloc_sdio_mpa_buffers(adapter, - SDIO_MP_TX_AGGR_DEF_BUF_SIZE, - SDIO_MP_RX_AGGR_DEF_BUF_SIZE); + card->mp_tx_agg_buf_size, + card->mp_rx_agg_buf_size); if (ret) { dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n"); kfree(card->mp_regs); diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index c71201b2e2a333..6eea30b43ed714 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -64,10 +64,8 @@ #define UP_LD_CMD_PORT_HOST_INT_STATUS (0x40U) #define DN_LD_CMD_PORT_HOST_INT_STATUS (0x80U) -#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (8192) /* 8K */ - -/* Multi port RX aggregation buffer size */ -#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (16384) /* 16K */ +#define MWIFIEX_MP_AGGR_BUF_SIZE_16K (16384) +#define MWIFIEX_MP_AGGR_BUF_SIZE_32K (32768) /* Misc. Config Register : Auto Re-enable interrupts */ #define AUTO_RE_ENABLE_INT BIT(4) @@ -234,6 +232,8 @@ struct sdio_mmc_card { bool supports_sdio_new_mode; bool has_control_mask; u16 tx_buf_size; + u32 mp_tx_agg_buf_size; + u32 mp_rx_agg_buf_size; u32 mp_rd_bitmap; u32 mp_wr_bitmap; @@ -258,6 +258,8 @@ struct mwifiex_sdio_device { bool supports_sdio_new_mode; bool has_control_mask; u16 tx_buf_size; + u32 mp_tx_agg_buf_size; + u32 mp_rx_agg_buf_size; }; static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = { @@ -315,6 +317,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { .supports_sdio_new_mode = false, .has_control_mask = true, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, + .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, + .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { @@ -325,6 +329,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { .supports_sdio_new_mode = false, .has_control_mask = true, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, + .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, + .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { @@ -335,6 +341,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { .supports_sdio_new_mode = false, .has_control_mask = true, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, + .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, + .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { @@ -345,6 +353,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { .supports_sdio_new_mode = true, .has_control_mask = false, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, + .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, + .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, }; /* diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index e3cac1495cc705..88202ce0c13965 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1546,6 +1546,7 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, struct mwifiex_ie_types_extcap *extcap; struct mwifiex_ie_types_vhtcap *vht_capab; struct mwifiex_ie_types_aid *aid; + struct mwifiex_ie_types_tdls_idle_timeout *timeout; u8 *pos, qos_info; u16 config_len = 0; struct station_parameters *params = priv->sta_params; @@ -1643,6 +1644,12 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, config_len += sizeof(struct mwifiex_ie_types_aid); } + timeout = (void *)(pos + config_len); + timeout->header.type = cpu_to_le16(TLV_TYPE_TDLS_IDLE_TIMEOUT); + timeout->header.len = cpu_to_le16(sizeof(timeout->value)); + timeout->value = cpu_to_le16(MWIFIEX_TDLS_IDLE_TIMEOUT); + config_len += sizeof(struct mwifiex_ie_types_tdls_idle_timeout); + break; default: dev_err(priv->adapter->dev, "Unknown TDLS operation\n"); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 368450cc56c7d9..5aea719219a319 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -134,6 +134,42 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) netif_carrier_off(priv->netdev); } +static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, + struct sk_buff *event_skb) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_sta_node *sta_ptr; + struct mwifiex_tdls_generic_event *tdls_evt = + (void *)event_skb->data + sizeof(adapter->event_cause); + + /* reserved 2 bytes are not mandatory in tdls event */ + if (event_skb->len < (sizeof(struct mwifiex_tdls_generic_event) - + sizeof(u16) - sizeof(adapter->event_cause))) { + dev_err(adapter->dev, "Invalid event length!\n"); + return -1; + } + + sta_ptr = mwifiex_get_sta_entry(priv, tdls_evt->peer_mac); + if (!sta_ptr) { + dev_err(adapter->dev, "cannot get sta entry!\n"); + return -1; + } + + switch (le16_to_cpu(tdls_evt->type)) { + case TDLS_EVENT_LINK_TEAR_DOWN: + cfg80211_tdls_oper_request(priv->netdev, + tdls_evt->peer_mac, + NL80211_TDLS_TEARDOWN, + le16_to_cpu(tdls_evt->u.reason_code), + GFP_KERNEL); + break; + default: + break; + } + + return 0; +} + /* * This function handles events generated by firmware. * @@ -459,6 +495,10 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) false); break; + case EVENT_TDLS_GENERIC_EVENT: + ret = mwifiex_parse_tdls_event(priv, adapter->event_skb); + break; + default: dev_dbg(adapter->dev, "event: unknown event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 97662a1ba58cf0..6bef47c2a70de6 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -185,6 +185,48 @@ static int mwifiex_tdls_add_vht_capab(struct mwifiex_private *priv, return 0; } +static int +mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, u8 *mac, + u8 vht_enabled, struct sk_buff *skb) +{ + struct ieee80211_ht_operation *ht_oper; + struct mwifiex_sta_node *sta_ptr; + struct mwifiex_bssdescriptor *bss_desc = + &priv->curr_bss_params.bss_descriptor; + u8 *pos; + + sta_ptr = mwifiex_get_sta_entry(priv, mac); + if (unlikely(!sta_ptr)) { + dev_warn(priv->adapter->dev, + "TDLS peer station not found in list\n"); + return -1; + } + + pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_operation) + 2); + *pos++ = WLAN_EID_HT_OPERATION; + *pos++ = sizeof(struct ieee80211_ht_operation); + ht_oper = (void *)pos; + + ht_oper->primary_chan = bss_desc->channel; + + /* follow AP's channel bandwidth */ + if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) && + bss_desc->bcn_ht_cap && + ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_oper->ht_param)) + ht_oper->ht_param = bss_desc->bcn_ht_oper->ht_param; + + if (vht_enabled) { + ht_oper->ht_param = + mwifiex_get_sec_chan_offset(bss_desc->channel); + ht_oper->ht_param |= BIT(2); + } + + memcpy(&sta_ptr->tdls_cap.ht_oper, ht_oper, + sizeof(struct ieee80211_ht_operation)); + + return 0; +} + static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv, u8 *mac, struct sk_buff *skb) { @@ -428,6 +470,17 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, dev_kfree_skb_any(skb); return ret; } + ret = mwifiex_tdls_add_ht_oper(priv, peer, 1, skb); + if (ret) { + dev_kfree_skb_any(skb); + return ret; + } + } else { + ret = mwifiex_tdls_add_ht_oper(priv, peer, 0, skb); + if (ret) { + dev_kfree_skb_any(skb); + return ret; + } } break; diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index 9be6544bddedf9..32643555dd2a32 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -175,17 +175,19 @@ mwifiex_set_ht_params(struct mwifiex_private *priv, switch (GET_RXSTBC(cap_info)) { case MWIFIEX_RX_STBC1: /* HT_CAP 1X1 mode */ - memset(&bss_cfg->ht_cap.mcs, 0xff, 1); + bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff; break; case MWIFIEX_RX_STBC12: /* fall through */ case MWIFIEX_RX_STBC123: /* HT_CAP 2X2 mode */ - memset(&bss_cfg->ht_cap.mcs, 0xff, 2); + bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff; + bss_cfg->ht_cap.mcs.rx_mask[1] = 0xff; break; default: dev_warn(priv->adapter->dev, "Unsupported RX-STBC, default to 2x2\n"); - memset(&bss_cfg->ht_cap.mcs, 0xff, 2); + bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff; + bss_cfg->ht_cap.mcs.rx_mask[1] = 0xff; break; } priv->ap_11n_enabled = 1; diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index edbe4aff00d85b..a8ce8130cfaeed 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -22,9 +22,9 @@ #define USB_VERSION "1.0" +static u8 user_rmmod; static struct mwifiex_if_ops usb_ops; static struct semaphore add_remove_card_sem; -static struct usb_card_rec *usb_card; static struct usb_device_id mwifiex_usb_table[] = { /* 8797 */ @@ -532,28 +532,38 @@ static int mwifiex_usb_resume(struct usb_interface *intf) static void mwifiex_usb_disconnect(struct usb_interface *intf) { struct usb_card_rec *card = usb_get_intfdata(intf); + struct mwifiex_adapter *adapter; - if (!card) { - pr_err("%s: card is NULL\n", __func__); + if (!card || !card->adapter) { + pr_err("%s: card or card->adapter is NULL\n", __func__); return; } - mwifiex_usb_free(card); + adapter = card->adapter; + if (!adapter->priv_num) + return; - if (card->adapter) { - struct mwifiex_adapter *adapter = card->adapter; + if (user_rmmod) { +#ifdef CONFIG_PM + if (adapter->is_suspended) + mwifiex_usb_resume(intf); +#endif - if (!adapter->priv_num) - return; + mwifiex_deauthenticate_all(adapter); - dev_dbg(adapter->dev, "%s: removing card\n", __func__); - mwifiex_remove_card(adapter, &add_remove_card_sem); + mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), + MWIFIEX_FUNC_SHUTDOWN); } + mwifiex_usb_free(card); + + dev_dbg(adapter->dev, "%s: removing card\n", __func__); + mwifiex_remove_card(adapter, &add_remove_card_sem); + usb_set_intfdata(intf, NULL); usb_put_dev(interface_to_usbdev(intf)); kfree(card); - usb_card = NULL; return; } @@ -565,6 +575,7 @@ static struct usb_driver mwifiex_usb_driver = { .id_table = mwifiex_usb_table, .suspend = mwifiex_usb_suspend, .resume = mwifiex_usb_resume, + .soft_unbind = 1, }; static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) @@ -762,7 +773,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) card->adapter = adapter; adapter->dev = &card->udev->dev; - usb_card = card; switch (le16_to_cpu(card->udev->descriptor.idProduct)) { case USB8897_PID_1: @@ -1025,25 +1035,8 @@ static void mwifiex_usb_cleanup_module(void) if (!down_interruptible(&add_remove_card_sem)) up(&add_remove_card_sem); - if (usb_card && usb_card->adapter) { - struct mwifiex_adapter *adapter = usb_card->adapter; - - /* In case driver is removed when asynchronous FW downloading is - * in progress - */ - wait_for_completion(&adapter->fw_load); - -#ifdef CONFIG_PM - if (adapter->is_suspended) - mwifiex_usb_resume(usb_card->intf); -#endif - - mwifiex_deauthenticate_all(adapter); - - mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, - MWIFIEX_BSS_ROLE_ANY), - MWIFIEX_FUNC_SHUTDOWN); - } + /* set the flag as user is removing this module */ + user_rmmod = 1; usb_deregister(&mwifiex_usb_driver); } diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 0a7cc742aed71e..94b6c74ba727ee 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -426,15 +426,6 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) priv->tos_to_tid_inv[i]; } - priv->aggr_prio_tbl[6].amsdu - = priv->aggr_prio_tbl[6].ampdu_ap - = priv->aggr_prio_tbl[6].ampdu_user - = BA_STREAM_NOT_ALLOWED; - - priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap - = priv->aggr_prio_tbl[7].ampdu_user - = BA_STREAM_NOT_ALLOWED; - mwifiex_set_ba_params(priv); mwifiex_reset_11n_rx_seq_num(priv); diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index eede90b63f8479..7be3a4839640c6 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -669,7 +669,8 @@ static unsigned int p54_flush_count(struct p54_common *priv) return total; } -static void p54_flush(struct ieee80211_hw *dev, u32 queues, bool drop) +static void p54_flush(struct ieee80211_hw *dev, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct p54_common *priv = dev->priv; unsigned int total, i; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index cbf0a589d32af0..8330fa33e50b1e 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -343,7 +343,7 @@ static void ray_detach(struct pcmcia_device *link) ray_release(link); local = netdev_priv(dev); - del_timer(&local->timer); + del_timer_sync(&local->timer); if (link->priv) { unregister_netdev(dev); diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 1b28cda6ca8812..2eefbf159bc0d0 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1083,7 +1083,7 @@ void rsi_inform_bss_status(struct rsi_common *common, { if (status) { rsi_hal_send_sta_notify_frame(common, - NL80211_IFTYPE_STATION, + RSI_IFTYPE_STATION, STA_CONNECTED, bssid, qos_enable, @@ -1092,7 +1092,7 @@ void rsi_inform_bss_status(struct rsi_common *common, rsi_send_auto_rate_request(common); } else { rsi_hal_send_sta_notify_frame(common, - NL80211_IFTYPE_STATION, + RSI_IFTYPE_STATION, STA_DISCONNECTED, bssid, qos_enable, diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index ac67c4ad63c2d3..225215a3b8bb48 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -73,6 +73,7 @@ #define RX_BA_INDICATION 1 #define RSI_TBL_SZ 40 #define MAX_RETRIES 8 +#define RSI_IFTYPE_STATION 0 #define STD_RATE_MCS7 0x07 #define STD_RATE_MCS6 0x06 diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 41d4a8167dc32f..c17fcf272728cb 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1005,10 +1005,9 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) entry->skb->len + padding_len); /* - * Enable beaconing again. + * Restore beaconing state. */ - rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg); /* * Clean up beacon skb. @@ -1039,13 +1038,14 @@ static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev, void rt2800_clear_beacon(struct queue_entry *entry) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - u32 reg; + u32 orig_reg, reg; /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &orig_reg); + reg = orig_reg; rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -1055,10 +1055,9 @@ void rt2800_clear_beacon(struct queue_entry *entry) rt2800_clear_beacon_register(rt2x00dev, entry->entry_idx); /* - * Enabled beaconing again. + * Restore beaconing state. */ - rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg); } EXPORT_SYMBOL_GPL(rt2800_clear_beacon); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index e3b885d8f7dbfd..010b76505243ed 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1448,7 +1448,8 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); -void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop); +void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index a87ee9b6585a72..212ac4842c1628 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -749,7 +749,8 @@ void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw) } EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll); -void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct rt2x00_dev *rt2x00dev = hw->priv; struct data_queue *queue; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 24402984ee5749..9048a9cbe52cb9 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2031,13 +2031,14 @@ static void rt61pci_write_beacon(struct queue_entry *entry, static void rt61pci_clear_beacon(struct queue_entry *entry) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - u32 reg; + u32 orig_reg, reg; /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, &orig_reg); + reg = orig_reg; rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -2048,10 +2049,9 @@ static void rt61pci_clear_beacon(struct queue_entry *entry) HW_BEACON_OFFSET(entry->entry_idx), 0); /* - * Enable beaconing again. + * Restore global beaconing state. */ - rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); - rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, orig_reg); } /* diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index a140170b1eb3e6..95724ff9c72687 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1597,13 +1597,14 @@ static void rt73usb_clear_beacon(struct queue_entry *entry) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; unsigned int beacon_base; - u32 reg; + u32 orig_reg, reg; /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &orig_reg); + reg = orig_reg; rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -1614,10 +1615,9 @@ static void rt73usb_clear_beacon(struct queue_entry *entry) rt2x00usb_register_write(rt2x00dev, beacon_base, 0); /* - * Enable beaconing again. + * Restore beaconing state. */ - rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); - rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, orig_reg); } static int rt73usb_get_tx_data_len(struct queue_entry *entry) diff --git a/drivers/net/wireless/rtl818x/rtl8180/Makefile b/drivers/net/wireless/rtl818x/rtl8180/Makefile index 08b056db4a3b79..21005bd8b43c97 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/Makefile +++ b/drivers/net/wireless/rtl818x/rtl8180/Makefile @@ -1,5 +1,5 @@ -rtl8180-objs := dev.o rtl8225.o sa2400.o max2820.o grf5101.o rtl8225se.o +rtl818x_pci-objs := dev.o rtl8225.o sa2400.o max2820.o grf5101.o rtl8225se.o -obj-$(CONFIG_RTL8180) += rtl8180.o +obj-$(CONFIG_RTL8180) += rtl818x_pci.o ccflags-y += -Idrivers/net/wireless/rtl818x diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 98d8256f037788..2c1c02bafa10bb 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -284,6 +284,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) rx_status.band = dev->conf.chandef.chan->band; rx_status.mactime = tsft; rx_status.flag |= RX_FLAG_MACTIME_START; + if (flags & RTL818X_RX_DESC_FLAG_SPLCP) + rx_status.flag |= RX_FLAG_SHORTPRE; if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; @@ -461,18 +463,23 @@ static void rtl8180_tx(struct ieee80211_hw *dev, RTL818X_TX_DESC_FLAG_NO_ENC; rc_flags = info->control.rates[0].flags; + + /* HW will perform RTS-CTS when only RTS flags is set. + * HW will perform CTS-to-self when both RTS and CTS flags are set. + * RTS rate and RTS duration will be used also for CTS-to-self. + */ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { tx_flags |= RTL818X_TX_DESC_FLAG_RTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + rts_duration = ieee80211_rts_duration(dev, priv->vif, + skb->len, info); } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - tx_flags |= RTL818X_TX_DESC_FLAG_CTS; + tx_flags |= RTL818X_TX_DESC_FLAG_RTS | RTL818X_TX_DESC_FLAG_CTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + rts_duration = ieee80211_ctstoself_duration(dev, priv->vif, + skb->len, info); } - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) - rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, - info); - if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) { unsigned int remainder; @@ -683,9 +690,8 @@ static void rtl8180_int_enable(struct ieee80211_hw *dev) struct rtl8180_priv *priv = dev->priv; if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { - rtl818x_iowrite32(priv, &priv->map->IMR, IMR_TMGDOK | - IMR_TBDER | IMR_THPDER | - IMR_THPDER | IMR_THPDOK | + rtl818x_iowrite32(priv, &priv->map->IMR, + IMR_TBDER | IMR_TBDOK | IMR_TVODER | IMR_TVODOK | IMR_TVIDER | IMR_TVIDOK | IMR_TBEDER | IMR_TBEDOK | @@ -911,7 +917,10 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev) reg32 &= 0x00ffff00; reg32 |= 0xb8000054; rtl818x_iowrite32(priv, &priv->map->RF_PARA, reg32); - } + } else + /* stop unused queus (no dma alloc) */ + rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, + (1<<1) | (1<<2)); priv->rf->init(dev); diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index 0ca17cda48fa1c..629ad8cfa17b59 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -253,14 +253,21 @@ static void rtl8187_tx(struct ieee80211_hw *dev, flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; if (ieee80211_has_morefrags(tx_hdr->frame_control)) flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; + + /* HW will perform RTS-CTS when only RTS flags is set. + * HW will perform CTS-to-self when both RTS and CTS flags are set. + * RTS rate and RTS duration will be used also for CTS-to-self. + */ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { flags |= RTL818X_TX_DESC_FLAG_RTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, skb->len, info); } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - flags |= RTL818X_TX_DESC_FLAG_CTS; + flags |= RTL818X_TX_DESC_FLAG_RTS | RTL818X_TX_DESC_FLAG_CTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + rts_dur = ieee80211_ctstoself_duration(dev, priv->vif, + skb->len, info); } if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { @@ -381,6 +388,8 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.freq = dev->conf.chandef.chan->center_freq; rx_status.band = dev->conf.chandef.chan->band; rx_status.flag |= RX_FLAG_MACTIME_START; + if (flags & RTL818X_RX_DESC_FLAG_SPLCP) + rx_status.flag |= RX_FLAG_SHORTPRE; if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h index 45ea4e1c4abe15..7abef95d278bc6 100644 --- a/drivers/net/wireless/rtl818x/rtl818x.h +++ b/drivers/net/wireless/rtl818x/rtl818x.h @@ -334,9 +334,9 @@ struct rtl818x_csr { * I don't like to introduce a ton of "reserved".. * They are for RTL8187SE */ -#define REG_ADDR1(addr) ((u8 __iomem *)priv->map + addr) -#define REG_ADDR2(addr) ((__le16 __iomem *)priv->map + (addr >> 1)) -#define REG_ADDR4(addr) ((__le32 __iomem *)priv->map + (addr >> 2)) +#define REG_ADDR1(addr) ((u8 __iomem *)priv->map + (addr)) +#define REG_ADDR2(addr) ((__le16 __iomem *)priv->map + ((addr) >> 1)) +#define REG_ADDR4(addr) ((__le32 __iomem *)priv->map + ((addr) >> 2)) #define FEMR_SE REG_ADDR2(0x1D4) #define ARFR REG_ADDR2(0x1E0) diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 4ec424f2667202..b1ed6d0796f67e 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -1387,7 +1387,8 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw) * before switch channel or power save, or tx buffer packet * maybe send after offchannel or rf sleep, this may cause * dis-association by AP */ -static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void rtl_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct rtl_priv *rtlpriv = rtl_priv(hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c index 1b4101bf9974e8..347af1e4f438e5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c @@ -93,7 +93,6 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw) u8 tid; rtl8188ee_bt_reg_init(hw); - rtlpci->msi_support = true; rtlpriv->dm.dm_initialgain_enable = 1; rtlpriv->dm.dm_flag = 0; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 07cb06da672972..a903c2671b4d17 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -511,7 +511,7 @@ static int _rtl92cu_init_power_on(struct ieee80211_hw *hw) pr_info("MAC auto ON okay!\n"); break; } - if (pollingCount++ > 100) { + if (pollingCount++ > 1000) { RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "Failed to polling REG_APS_FSMCO[APFM_ONMAC] done!\n"); return -ENODEV; diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c index b4577ebc4bb0bb..a07213645da013 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c @@ -92,7 +92,7 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); rtl8723be_bt_reg_init(hw); - rtlpci->msi_support = true; + rtlpci->msi_support = false; rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer(); rtlpriv->dm.dm_initialgain_enable = 1; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index ed88d39134839e..4cd739de052705 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -543,7 +543,7 @@ static int wlcore_irq_locked(struct wl1271 *wl) * wl1271_ps_elp_wakeup cannot be called concurrently. */ clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); ret = wlcore_fw_status(wl, wl->fw_status); if (ret < 0) @@ -5184,7 +5184,8 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); } -static void wlcore_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void wlcore_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct wl1271 *wl = hw->priv; diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 29ef2492951fcd..d3dd7bfdf3f1f3 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -217,7 +217,7 @@ static struct wl1271_if_operations sdio_ops = { static int wl1271_probe(struct sdio_func *func, const struct sdio_device_id *id) { - struct wlcore_platdev_data *pdev_data; + struct wlcore_platdev_data pdev_data; struct wl12xx_sdio_glue *glue; struct resource res[1]; mmc_pm_flag_t mmcflags; @@ -228,16 +228,13 @@ static int wl1271_probe(struct sdio_func *func, if (func->num != 0x02) return -ENODEV; - pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL); - if (!pdev_data) - goto out; - - pdev_data->if_ops = &sdio_ops; + memset(&pdev_data, 0x00, sizeof(pdev_data)); + pdev_data.if_ops = &sdio_ops; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&func->dev, "can't allocate glue\n"); - goto out_free_pdev_data; + goto out; } glue->dev = &func->dev; @@ -248,9 +245,9 @@ static int wl1271_probe(struct sdio_func *func, /* Use block mode for transferring over one block size of data */ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; - pdev_data->pdata = wl12xx_get_platform_data(); - if (IS_ERR(pdev_data->pdata)) { - ret = PTR_ERR(pdev_data->pdata); + pdev_data.pdata = wl12xx_get_platform_data(); + if (IS_ERR(pdev_data.pdata)) { + ret = PTR_ERR(pdev_data.pdata); dev_err(glue->dev, "missing wlan platform data: %d\n", ret); goto out_free_glue; } @@ -260,7 +257,7 @@ static int wl1271_probe(struct sdio_func *func, dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); if (mmcflags & MMC_PM_KEEP_POWER) - pdev_data->pdata->pwr_in_suspend = true; + pdev_data.pdata->pwr_in_suspend = true; sdio_set_drvdata(func, glue); @@ -289,7 +286,7 @@ static int wl1271_probe(struct sdio_func *func, memset(res, 0x00, sizeof(res)); - res[0].start = pdev_data->pdata->irq; + res[0].start = pdev_data.pdata->irq; res[0].flags = IORESOURCE_IRQ; res[0].name = "irq"; @@ -299,8 +296,8 @@ static int wl1271_probe(struct sdio_func *func, goto out_dev_put; } - ret = platform_device_add_data(glue->core, pdev_data, - sizeof(*pdev_data)); + ret = platform_device_add_data(glue->core, &pdev_data, + sizeof(pdev_data)); if (ret) { dev_err(glue->dev, "can't add platform data\n"); goto out_dev_put; @@ -319,9 +316,6 @@ static int wl1271_probe(struct sdio_func *func, out_free_glue: kfree(glue); -out_free_pdev_data: - kfree(pdev_data); - out: return ret; } diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index dbe826dd7c23c4..5f3a389dd74cdf 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -327,27 +327,25 @@ static struct wl1271_if_operations spi_ops = { static int wl1271_probe(struct spi_device *spi) { struct wl12xx_spi_glue *glue; - struct wlcore_platdev_data *pdev_data; + struct wlcore_platdev_data pdev_data; struct resource res[1]; int ret = -ENOMEM; - pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL); - if (!pdev_data) - goto out; + memset(&pdev_data, 0x00, sizeof(pdev_data)); - pdev_data->pdata = dev_get_platdata(&spi->dev); - if (!pdev_data->pdata) { + pdev_data.pdata = dev_get_platdata(&spi->dev); + if (!pdev_data.pdata) { dev_err(&spi->dev, "no platform data\n"); ret = -ENODEV; - goto out_free_pdev_data; + goto out; } - pdev_data->if_ops = &spi_ops; + pdev_data.if_ops = &spi_ops; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&spi->dev, "can't allocate glue\n"); - goto out_free_pdev_data; + goto out; } glue->dev = &spi->dev; @@ -385,8 +383,8 @@ static int wl1271_probe(struct spi_device *spi) goto out_dev_put; } - ret = platform_device_add_data(glue->core, pdev_data, - sizeof(*pdev_data)); + ret = platform_device_add_data(glue->core, &pdev_data, + sizeof(pdev_data)); if (ret) { dev_err(glue->dev, "can't add platform data\n"); goto out_dev_put; @@ -406,9 +404,6 @@ static int wl1271_probe(struct spi_device *spi) out_free_glue: kfree(glue); -out_free_pdev_data: - kfree(pdev_data); - out: return ret; } diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 889005fa4d0405..2dcb0541012d01 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -20,6 +20,7 @@ config OF_SELFTEST config OF_FLATTREE bool select DTC + select LIBFDT config OF_EARLY_FLATTREE bool diff --git a/drivers/of/Makefile b/drivers/of/Makefile index ed9660adad7751..9891232f999e1c 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -10,3 +10,5 @@ obj-$(CONFIG_OF_PCI) += of_pci.o obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o obj-$(CONFIG_OF_MTD) += of_mtd.o obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o + +CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt diff --git a/drivers/of/address.c b/drivers/of/address.c index cb4242a69cd529..d244b2859aac63 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -721,3 +721,113 @@ void __iomem *of_iomap(struct device_node *np, int index) return ioremap(res.start, resource_size(&res)); } EXPORT_SYMBOL(of_iomap); + +/** + * of_dma_get_range - Get DMA range info + * @np: device node to get DMA range info + * @dma_addr: pointer to store initial DMA address of DMA range + * @paddr: pointer to store initial CPU address of DMA range + * @size: pointer to store size of DMA range + * + * Look in bottom up direction for the first "dma-ranges" property + * and parse it. + * dma-ranges format: + * DMA addr (dma_addr) : naddr cells + * CPU addr (phys_addr_t) : pna cells + * size : nsize cells + * + * It returns -ENODEV if "dma-ranges" property was not found + * for this device in DT. + */ +int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *size) +{ + struct device_node *node = of_node_get(np); + const __be32 *ranges = NULL; + int len, naddr, nsize, pna; + int ret = 0; + u64 dmaaddr; + + if (!node) + return -EINVAL; + + while (1) { + naddr = of_n_addr_cells(node); + nsize = of_n_size_cells(node); + node = of_get_next_parent(node); + if (!node) + break; + + ranges = of_get_property(node, "dma-ranges", &len); + + /* Ignore empty ranges, they imply no translation required */ + if (ranges && len > 0) + break; + + /* + * At least empty ranges has to be defined for parent node if + * DMA is supported + */ + if (!ranges) + break; + } + + if (!ranges) { + pr_debug("%s: no dma-ranges found for node(%s)\n", + __func__, np->full_name); + ret = -ENODEV; + goto out; + } + + len /= sizeof(u32); + + pna = of_n_addr_cells(node); + + /* dma-ranges format: + * DMA addr : naddr cells + * CPU addr : pna cells + * size : nsize cells + */ + dmaaddr = of_read_number(ranges, naddr); + *paddr = of_translate_dma_address(np, ranges); + if (*paddr == OF_BAD_ADDR) { + pr_err("%s: translation of DMA address(%pad) to CPU address failed node(%s)\n", + __func__, dma_addr, np->full_name); + ret = -EINVAL; + goto out; + } + *dma_addr = dmaaddr; + + *size = of_read_number(ranges + naddr + pna, nsize); + + pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n", + *dma_addr, *paddr, *size); + +out: + of_node_put(node); + + return ret; +} +EXPORT_SYMBOL_GPL(of_dma_get_range); + +/** + * of_dma_is_coherent - Check if device is coherent + * @np: device node + * + * It returns true if "dma-coherent" property was found + * for this device in DT. + */ +bool of_dma_is_coherent(struct device_node *np) +{ + struct device_node *node = of_node_get(np); + + while (node) { + if (of_property_read_bool(node, "dma-coherent")) { + of_node_put(node); + return true; + } + node = of_get_next_parent(node); + } + of_node_put(node); + return false; +} +EXPORT_SYMBOL_GPL(of_dma_is_coherent); \ No newline at end of file diff --git a/drivers/of/base.c b/drivers/of/base.c index 6d4ee22708c937..1feb90ff31d902 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2036,8 +2036,8 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) * @np: Pointer to the given device_node * @stem: Alias stem of the given device_node * - * The function travels the lookup table to get alias id for the given - * device_node and alias stem. It returns the alias id if find it. + * The function travels the lookup table to get the alias id for the given + * device_node and alias stem. It returns the alias id if found. */ int of_alias_get_id(struct device_node *np, const char *stem) { diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 7a2ef7bb8022b4..a6f83ea107ae03 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -20,62 +19,12 @@ #include #include #include +#include +#include #include /* for COMMAND_LINE_SIZE */ -#ifdef CONFIG_PPC -#include -#endif /* CONFIG_PPC */ - #include -char *of_fdt_get_string(struct boot_param_header *blob, u32 offset) -{ - return ((char *)blob) + - be32_to_cpu(blob->off_dt_strings) + offset; -} - -/** - * of_fdt_get_property - Given a node in the given flat blob, return - * the property ptr - */ -void *of_fdt_get_property(struct boot_param_header *blob, - unsigned long node, const char *name, - unsigned long *size) -{ - unsigned long p = node; - - do { - u32 tag = be32_to_cpup((__be32 *)p); - u32 sz, noff; - const char *nstr; - - p += 4; - if (tag == OF_DT_NOP) - continue; - if (tag != OF_DT_PROP) - return NULL; - - sz = be32_to_cpup((__be32 *)p); - noff = be32_to_cpup((__be32 *)(p + 4)); - p += 8; - if (be32_to_cpu(blob->version) < 0x10) - p = ALIGN(p, sz >= 8 ? 8 : 4); - - nstr = of_fdt_get_string(blob, noff); - if (nstr == NULL) { - pr_warning("Can't find property index name !\n"); - return NULL; - } - if (strcmp(name, nstr) == 0) { - if (size) - *size = sz; - return (void *)p; - } - p += sz; - p = ALIGN(p, 4); - } while (1); -} - /** * of_fdt_is_compatible - Return true if given node from the given blob has * compat in its compatible list @@ -86,13 +35,14 @@ void *of_fdt_get_property(struct boot_param_header *blob, * On match, returns a non-zero value with smaller values returned for more * specific compatible values. */ -int of_fdt_is_compatible(struct boot_param_header *blob, +int of_fdt_is_compatible(const void *blob, unsigned long node, const char *compat) { const char *cp; - unsigned long cplen, l, score = 0; + int cplen; + unsigned long l, score = 0; - cp = of_fdt_get_property(blob, node, "compatible", &cplen); + cp = fdt_getprop(blob, node, "compatible", &cplen); if (cp == NULL) return 0; while (cplen > 0) { @@ -110,7 +60,7 @@ int of_fdt_is_compatible(struct boot_param_header *blob, /** * of_fdt_match - Return true if node matches a list of compatible values */ -int of_fdt_match(struct boot_param_header *blob, unsigned long node, +int of_fdt_match(const void *blob, unsigned long node, const char *const *compat) { unsigned int tmp, score = 0; @@ -149,30 +99,29 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size, * @allnextpp: pointer to ->allnext from last allocated device_node * @fpsize: Size of the node path up at the current depth. */ -static void * unflatten_dt_node(struct boot_param_header *blob, +static void * unflatten_dt_node(void *blob, void *mem, - void **p, + int *poffset, struct device_node *dad, struct device_node ***allnextpp, unsigned long fpsize) { + const __be32 *p; struct device_node *np; struct property *pp, **prev_pp = NULL; - char *pathp; - u32 tag; + const char *pathp; unsigned int l, allocl; + static int depth = 0; + int old_depth; + int offset; int has_name = 0; int new_format = 0; - tag = be32_to_cpup(*p); - if (tag != OF_DT_BEGIN_NODE) { - pr_err("Weird tag at start of node: %x\n", tag); + pathp = fdt_get_name(blob, *poffset, &l); + if (!pathp) return mem; - } - *p += 4; - pathp = *p; - l = allocl = strlen(pathp) + 1; - *p = PTR_ALIGN(*p + l, 4); + + allocl = l++; /* version 0x10 has a more compact unit name here instead of the full * path. we accumulate the full path size using "fpsize", we'll rebuild @@ -190,7 +139,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob, fpsize = 1; allocl = 2; l = 1; - *pathp = '\0'; + pathp = ""; } else { /* account for '/' and path size minus terminal 0 * already in 'l' @@ -237,32 +186,23 @@ static void * unflatten_dt_node(struct boot_param_header *blob, } } /* process properties */ - while (1) { - u32 sz, noff; - char *pname; - - tag = be32_to_cpup(*p); - if (tag == OF_DT_NOP) { - *p += 4; - continue; - } - if (tag != OF_DT_PROP) + for (offset = fdt_first_property_offset(blob, *poffset); + (offset >= 0); + (offset = fdt_next_property_offset(blob, offset))) { + const char *pname; + u32 sz; + + if (!(p = fdt_getprop_by_offset(blob, offset, &pname, &sz))) { + offset = -FDT_ERR_INTERNAL; break; - *p += 4; - sz = be32_to_cpup(*p); - noff = be32_to_cpup(*p + 4); - *p += 8; - if (be32_to_cpu(blob->version) < 0x10) - *p = PTR_ALIGN(*p, sz >= 8 ? 8 : 4); - - pname = of_fdt_get_string(blob, noff); + } + if (pname == NULL) { pr_info("Can't find property name in list !\n"); break; } if (strcmp(pname, "name") == 0) has_name = 1; - l = strlen(pname) + 1; pp = unflatten_dt_alloc(&mem, sizeof(struct property), __alignof__(struct property)); if (allnextpp) { @@ -274,26 +214,25 @@ static void * unflatten_dt_node(struct boot_param_header *blob, if ((strcmp(pname, "phandle") == 0) || (strcmp(pname, "linux,phandle") == 0)) { if (np->phandle == 0) - np->phandle = be32_to_cpup((__be32*)*p); + np->phandle = be32_to_cpup(p); } /* And we process the "ibm,phandle" property * used in pSeries dynamic device tree * stuff */ if (strcmp(pname, "ibm,phandle") == 0) - np->phandle = be32_to_cpup((__be32 *)*p); - pp->name = pname; + np->phandle = be32_to_cpup(p); + pp->name = (char *)pname; pp->length = sz; - pp->value = *p; + pp->value = (__be32 *)p; *prev_pp = pp; prev_pp = &pp->next; } - *p = PTR_ALIGN((*p) + sz, 4); } /* with version 0x10 we may not have the name property, recreate * it here from the unit name if absent */ if (!has_name) { - char *p1 = pathp, *ps = pathp, *pa = NULL; + const char *p1 = pathp, *ps = pathp, *pa = NULL; int sz; while (*p1) { @@ -330,19 +269,18 @@ static void * unflatten_dt_node(struct boot_param_header *blob, if (!np->type) np->type = ""; } - while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) { - if (tag == OF_DT_NOP) - *p += 4; - else - mem = unflatten_dt_node(blob, mem, p, np, allnextpp, - fpsize); - tag = be32_to_cpup(*p); - } - if (tag != OF_DT_END_NODE) { - pr_err("Weird tag at end of node: %x\n", tag); - return mem; - } - *p += 4; + + old_depth = depth; + *poffset = fdt_next_node(blob, *poffset, &depth); + if (depth < 0) + depth = 0; + while (*poffset > 0 && depth > old_depth) + mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp, + fpsize); + + if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) + pr_err("unflatten: error %d processing FDT\n", *poffset); + return mem; } @@ -358,12 +296,13 @@ static void * unflatten_dt_node(struct boot_param_header *blob, * @dt_alloc: An allocator that provides a virtual address to memory * for the resulting tree */ -static void __unflatten_device_tree(struct boot_param_header *blob, +static void __unflatten_device_tree(void *blob, struct device_node **mynodes, void * (*dt_alloc)(u64 size, u64 align)) { unsigned long size; - void *start, *mem; + int start; + void *mem; struct device_node **allnextp = mynodes; pr_debug(" -> unflatten_device_tree()\n"); @@ -374,17 +313,17 @@ static void __unflatten_device_tree(struct boot_param_header *blob, } pr_debug("Unflattening device tree:\n"); - pr_debug("magic: %08x\n", be32_to_cpu(blob->magic)); - pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize)); - pr_debug("version: %08x\n", be32_to_cpu(blob->version)); + pr_debug("magic: %08x\n", fdt_magic(blob)); + pr_debug("size: %08x\n", fdt_totalsize(blob)); + pr_debug("version: %08x\n", fdt_version(blob)); - if (be32_to_cpu(blob->magic) != OF_DT_HEADER) { + if (fdt_check_header(blob)) { pr_err("Invalid device tree blob header\n"); return; } /* First pass, scan for size */ - start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct); + start = 0; size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0); size = ALIGN(size, 4); @@ -399,10 +338,8 @@ static void __unflatten_device_tree(struct boot_param_header *blob, pr_debug(" unflattening %p...\n", mem); /* Second pass, do actual unflattening */ - start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct); + start = 0; unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); - if (be32_to_cpup(start) != OF_DT_END) - pr_warning("Weird tag at end of tree: %08x\n", be32_to_cpup(start)); if (be32_to_cpup(mem + size) != 0xdeadbeef) pr_warning("End of tree marker overwritten: %08x\n", be32_to_cpup(mem + size)); @@ -427,9 +364,7 @@ static void *kernel_tree_alloc(u64 size, u64 align) void of_fdt_unflatten_tree(unsigned long *blob, struct device_node **mynodes) { - struct boot_param_header *device_tree = - (struct boot_param_header *)blob; - __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc); + __unflatten_device_tree(blob, mynodes, &kernel_tree_alloc); } EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); @@ -437,7 +372,7 @@ EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); int __initdata dt_root_addr_cells; int __initdata dt_root_size_cells; -struct boot_param_header *initial_boot_params; +void *initial_boot_params; #ifdef CONFIG_OF_EARLY_FLATTREE @@ -449,8 +384,8 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, { int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); phys_addr_t base, size; - unsigned long len; - __be32 *prop; + int len; + const __be32 *prop; int nomap, first = 1; prop = of_get_flat_dt_prop(node, "reg", &len); @@ -493,7 +428,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, */ static int __init __reserved_mem_check_root(unsigned long node) { - __be32 *prop; + const __be32 *prop; prop = of_get_flat_dt_prop(node, "#size-cells", NULL); if (!prop || be32_to_cpup(prop) != dt_root_size_cells) @@ -557,9 +492,25 @@ static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, */ void __init early_init_fdt_scan_reserved_mem(void) { + int n; + u64 base, size; + if (!initial_boot_params) return; + /* Reserve the dtb region */ + early_init_dt_reserve_memory_arch(__pa(initial_boot_params), + fdt_totalsize(initial_boot_params), + 0); + + /* Process header /memreserve/ fields */ + for (n = 0; ; n++) { + fdt_get_mem_rsv(initial_boot_params, n, &base, &size); + if (!size) + break; + early_init_dt_reserve_memory_arch(base, size, 0); + } + of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); fdt_init_reserved_mem(); } @@ -578,47 +529,19 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, void *data), void *data) { - unsigned long p = ((unsigned long)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_dt_struct); - int rc = 0; - int depth = -1; - - do { - u32 tag = be32_to_cpup((__be32 *)p); - const char *pathp; - - p += 4; - if (tag == OF_DT_END_NODE) { - depth--; - continue; - } - if (tag == OF_DT_NOP) - continue; - if (tag == OF_DT_END) - break; - if (tag == OF_DT_PROP) { - u32 sz = be32_to_cpup((__be32 *)p); - p += 8; - if (be32_to_cpu(initial_boot_params->version) < 0x10) - p = ALIGN(p, sz >= 8 ? 8 : 4); - p += sz; - p = ALIGN(p, 4); - continue; - } - if (tag != OF_DT_BEGIN_NODE) { - pr_err("Invalid tag %x in flat device tree!\n", tag); - return -EINVAL; - } - depth++; - pathp = (char *)p; - p = ALIGN(p + strlen(pathp) + 1, 4); + const void *blob = initial_boot_params; + const char *pathp; + int offset, rc = 0, depth = -1; + + for (offset = fdt_next_node(blob, -1, &depth); + offset >= 0 && depth >= 0 && !rc; + offset = fdt_next_node(blob, offset, &depth)) { + + pathp = fdt_get_name(blob, offset, NULL); if (*pathp == '/') pathp = kbasename(pathp); - rc = it(p, pathp, depth, data); - if (rc != 0) - break; - } while (1); - + rc = it(offset, pathp, depth, data); + } return rc; } @@ -627,14 +550,15 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, */ unsigned long __init of_get_flat_dt_root(void) { - unsigned long p = ((unsigned long)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_dt_struct); - - while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) - p += 4; - BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); - p += 4; - return ALIGN(p + strlen((char *)p) + 1, 4); + return 0; +} + +/** + * of_get_flat_dt_size - Return the total size of the FDT + */ +int __init of_get_flat_dt_size(void) +{ + return fdt_totalsize(initial_boot_params); } /** @@ -643,10 +567,10 @@ unsigned long __init of_get_flat_dt_root(void) * This function can be used within scan_flattened_dt callback to get * access to properties */ -void *__init of_get_flat_dt_prop(unsigned long node, const char *name, - unsigned long *size) +const void *__init of_get_flat_dt_prop(unsigned long node, const char *name, + int *size) { - return of_fdt_get_property(initial_boot_params, node, name, size); + return fdt_getprop(initial_boot_params, node, name, size); } /** @@ -676,73 +600,6 @@ struct fdt_scan_status { void *data; }; -/** - * fdt_scan_node_by_path - iterator for of_scan_flat_dt_by_path function - */ -static int __init fdt_scan_node_by_path(unsigned long node, const char *uname, - int depth, void *data) -{ - struct fdt_scan_status *st = data; - - /* - * if scan at the requested fdt node has been completed, - * return -ENXIO to abort further scanning - */ - if (depth <= st->depth) - return -ENXIO; - - /* requested fdt node has been found, so call iterator function */ - if (st->found) - return st->iterator(node, uname, depth, st->data); - - /* check if scanning automata is entering next level of fdt nodes */ - if (depth == st->depth + 1 && - strncmp(st->name, uname, st->namelen) == 0 && - uname[st->namelen] == 0) { - st->depth += 1; - if (st->name[st->namelen] == 0) { - st->found = 1; - } else { - const char *next = st->name + st->namelen + 1; - st->name = next; - st->namelen = strcspn(next, "/"); - } - return 0; - } - - /* scan next fdt node */ - return 0; -} - -/** - * of_scan_flat_dt_by_path - scan flattened tree blob and call callback on each - * child of the given path. - * @path: path to start searching for children - * @it: callback function - * @data: context data pointer - * - * This function is used to scan the flattened device-tree starting from the - * node given by path. It is used to extract information (like reserved - * memory), which is required on ealy boot before we can unflatten the tree. - */ -int __init of_scan_flat_dt_by_path(const char *path, - int (*it)(unsigned long node, const char *name, int depth, void *data), - void *data) -{ - struct fdt_scan_status st = {path, 0, -1, 0, it, data}; - int ret = 0; - - if (initial_boot_params) - ret = of_scan_flat_dt(fdt_scan_node_by_path, &st); - - if (!st.found) - return -ENOENT; - else if (ret == -ENXIO) /* scan has been completed */ - return 0; - else - return ret; -} - const char * __init of_flat_dt_get_machine_name(void) { const char *name; @@ -782,7 +639,7 @@ const void * __init of_flat_dt_match_machine(const void *default_match, } if (!best_data) { const char *prop; - long size; + int size; pr_err("\n unrecognized device tree list:\n[ "); @@ -811,8 +668,8 @@ const void * __init of_flat_dt_match_machine(const void *default_match, static void __init early_init_dt_check_for_initrd(unsigned long node) { u64 start, end; - unsigned long len; - __be32 *prop; + int len; + const __be32 *prop; pr_debug("Looking for initrd properties... "); @@ -845,7 +702,7 @@ static inline void early_init_dt_check_for_initrd(unsigned long node) int __init early_init_dt_scan_root(unsigned long node, const char *uname, int depth, void *data) { - __be32 *prop; + const __be32 *prop; if (depth != 0) return 0; @@ -867,9 +724,9 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname, return 1; } -u64 __init dt_mem_next_cell(int s, __be32 **cellp) +u64 __init dt_mem_next_cell(int s, const __be32 **cellp) { - __be32 *p = *cellp; + const __be32 *p = *cellp; *cellp = p + s; return of_read_number(p, s); @@ -881,9 +738,9 @@ u64 __init dt_mem_next_cell(int s, __be32 **cellp) int __init early_init_dt_scan_memory(unsigned long node, const char *uname, int depth, void *data) { - char *type = of_get_flat_dt_prop(node, "device_type", NULL); - __be32 *reg, *endp; - unsigned long l; + const char *type = of_get_flat_dt_prop(node, "device_type", NULL); + const __be32 *reg, *endp; + int l; /* We are scanning "memory" nodes only */ if (type == NULL) { @@ -904,7 +761,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname, endp = reg + (l / sizeof(__be32)); - pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", + pr_debug("memory scan node %s, reg size %d, data: %x %x %x %x,\n", uname, l, reg[0], reg[1], reg[2], reg[3]); while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { @@ -927,8 +784,8 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname, int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data) { - unsigned long l; - char *p; + int l; + const char *p; pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); @@ -1003,8 +860,8 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align) int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size, bool nomap) { - pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n", - base, size, nomap ? " (nomap)" : ""); + pr_err("Reserved memory not supported, ignoring range 0x%pa - 0x%pa%s\n", + &base, &size, nomap ? " (nomap)" : ""); return -ENOSYS; } #endif @@ -1018,7 +875,7 @@ bool __init early_init_dt_scan(void *params) initial_boot_params = params; /* check device tree validity */ - if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) { + if (fdt_check_header(params)) { initial_boot_params = NULL; return false; } @@ -1073,9 +930,9 @@ void __init unflatten_and_copy_device_tree(void) return; } - size = __be32_to_cpu(initial_boot_params->totalsize); + size = fdt_totalsize(initial_boot_params); dt = early_init_dt_alloc_memory_arch(size, - __alignof__(struct boot_param_header)); + roundup_pow_of_two(FDT_V17_SIZE)); if (dt) { memcpy(dt, initial_boot_params, size); @@ -1084,4 +941,27 @@ void __init unflatten_and_copy_device_tree(void) unflatten_device_tree(); } +#if defined(CONFIG_DEBUG_FS) && defined(DEBUG) +static struct debugfs_blob_wrapper flat_dt_blob; + +static int __init of_flat_dt_debugfs_export_fdt(void) +{ + struct dentry *d = debugfs_create_dir("device-tree", NULL); + + if (!d) + return -ENOENT; + + flat_dt_blob.data = initial_boot_params; + flat_dt_blob.size = fdt_totalsize(initial_boot_params); + + d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR, + d, &flat_dt_blob); + if (!d) + return -ENOENT; + + return 0; +} +module_init(of_flat_dt_debugfs_export_fdt); +#endif + #endif /* CONFIG_OF_EARLY_FLATTREE */ diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index daaaf935911db2..e420eb52e5c92a 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -95,8 +95,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node, int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); phys_addr_t start = 0, end = 0; phys_addr_t base = 0, align = 0, size; - unsigned long len; - __be32 *prop; + int len; + const __be32 *prop; int nomap; int ret; diff --git a/drivers/of/platform.c b/drivers/of/platform.c index bd47fbc53dc962..4e91583a390883 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -188,6 +188,64 @@ struct platform_device *of_device_alloc(struct device_node *np, } EXPORT_SYMBOL(of_device_alloc); +/** + * of_dma_configure - Setup DMA configuration + * @dev: Device to apply DMA configuration + * + * Try to get devices's DMA configuration from DT and update it + * accordingly. + * + * In case if platform code need to use own special DMA configuration,it + * can use Platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE event + * to fix up DMA configuration. + */ +static void of_dma_configure(struct platform_device *pdev) +{ + u64 dma_addr, paddr, size; + int ret; + struct device *dev = &pdev->dev; + +#if defined(CONFIG_MICROBLAZE) + pdev->archdata.dma_mask = 0xffffffffUL; +#endif + + /* + * Set default dma-mask to 32 bit. Drivers are expected to setup + * the correct supported dma_mask. + */ + dev->coherent_dma_mask = DMA_BIT_MASK(32); + + /* + * Set it to coherent_dma_mask by default if the architecture + * code has not set it. + */ + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; + + /* + * if dma-coherent property exist, call arch hook to setup + * dma coherent operations. + */ + if (of_dma_is_coherent(dev->of_node)) { + set_arch_dma_coherent_ops(dev); + dev_dbg(dev, "device is dma coherent\n"); + } + + /* + * if dma-ranges property doesn't exist - just return else + * setup the dma offset + */ + ret = of_dma_get_range(dev->of_node, &dma_addr, &paddr, &size); + if (ret < 0) { + dev_dbg(dev, "no dma range information to setup\n"); + return; + } + + /* DMA ranges found. Calculate and set dma_pfn_offset */ + dev->dma_pfn_offset = PFN_DOWN(paddr - dma_addr); + dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", dev->dma_pfn_offset); +} + /** * of_platform_device_create_pdata - Alloc, initialize and register an of_device * @np: pointer to node to create device for @@ -213,12 +271,7 @@ static struct platform_device *of_platform_device_create_pdata( if (!dev) return NULL; -#if defined(CONFIG_MICROBLAZE) - dev->archdata.dma_mask = 0xffffffffUL; -#endif - dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - if (!dev->dev.dma_mask) - dev->dev.dma_mask = &dev->dev.coherent_dma_mask; + of_dma_configure(dev); dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index fb8aed307c2821..ba2bf55a38df52 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "pci.h" diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c index 47aaf22d814e19..0e5f3c95af5bd7 100644 --- a/drivers/pci/host-bridge.c +++ b/drivers/pci/host-bridge.c @@ -3,7 +3,6 @@ */ #include -#include #include #include diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index d3d1cfd51e095f..e384e253459473 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -293,6 +293,58 @@ static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port, return PCIBIOS_SUCCESSFUL; } +/* + * Remove windows, starting from the largest ones to the smallest + * ones. + */ +static void mvebu_pcie_del_windows(struct mvebu_pcie_port *port, + phys_addr_t base, size_t size) +{ + while (size) { + size_t sz = 1 << (fls(size) - 1); + + mvebu_mbus_del_window(base, sz); + base += sz; + size -= sz; + } +} + +/* + * MBus windows can only have a power of two size, but PCI BARs do not + * have this constraint. Therefore, we have to split the PCI BAR into + * areas each having a power of two size. We start from the largest + * one (i.e highest order bit set in the size). + */ +static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port, + unsigned int target, unsigned int attribute, + phys_addr_t base, size_t size, + phys_addr_t remap) +{ + size_t size_mapped = 0; + + while (size) { + size_t sz = 1 << (fls(size) - 1); + int ret; + + ret = mvebu_mbus_add_window_remap_by_id(target, attribute, base, + sz, remap); + if (ret) { + dev_err(&port->pcie->pdev->dev, + "Could not create MBus window at 0x%x, size 0x%x: %d\n", + base, sz, ret); + mvebu_pcie_del_windows(port, base - size_mapped, + size_mapped); + return; + } + + size -= sz; + size_mapped += sz; + base += sz; + if (remap != MVEBU_MBUS_NO_REMAP) + remap += sz; + } +} + static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) { phys_addr_t iobase; @@ -304,8 +356,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) /* If a window was configured, remove it */ if (port->iowin_base) { - mvebu_mbus_del_window(port->iowin_base, - port->iowin_size); + mvebu_pcie_del_windows(port, port->iowin_base, + port->iowin_size); port->iowin_base = 0; port->iowin_size = 0; } @@ -331,11 +383,11 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) port->iowin_base = port->pcie->io.start + iobase; port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) | (port->bridge.iolimitupper << 16)) - - iobase); + iobase) + 1; - mvebu_mbus_add_window_remap_by_id(port->io_target, port->io_attr, - port->iowin_base, port->iowin_size, - iobase); + mvebu_pcie_add_windows(port, port->io_target, port->io_attr, + port->iowin_base, port->iowin_size, + iobase); } static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) @@ -346,8 +398,8 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) /* If a window was configured, remove it */ if (port->memwin_base) { - mvebu_mbus_del_window(port->memwin_base, - port->memwin_size); + mvebu_pcie_del_windows(port, port->memwin_base, + port->memwin_size); port->memwin_base = 0; port->memwin_size = 0; } @@ -364,10 +416,11 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) port->memwin_base = ((port->bridge.membase & 0xFFF0) << 16); port->memwin_size = (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) - - port->memwin_base; + port->memwin_base + 1; - mvebu_mbus_add_window_by_id(port->mem_target, port->mem_attr, - port->memwin_base, port->memwin_size); + mvebu_pcie_add_windows(port, port->mem_target, port->mem_attr, + port->memwin_base, port->memwin_size, + MVEBU_MBUS_NO_REMAP); } /* @@ -743,14 +796,21 @@ static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, /* * On the PCI-to-PCI bridge side, the I/O windows must have at - * least a 64 KB size and be aligned on their size, and the - * memory windows must have at least a 1 MB size and be - * aligned on their size + * least a 64 KB size and the memory windows must have at + * least a 1 MB size. Moreover, MBus windows need to have a + * base address aligned on their size, and their size must be + * a power of two. This means that if the BAR doesn't have a + * power of two size, several MBus windows will actually be + * created. We need to ensure that the biggest MBus window + * (which will be the first one) is aligned on its size, which + * explains the rounddown_pow_of_two() being done here. */ if (res->flags & IORESOURCE_IO) - return round_up(start, max_t(resource_size_t, SZ_64K, size)); + return round_up(start, max_t(resource_size_t, SZ_64K, + rounddown_pow_of_two(size))); else if (res->flags & IORESOURCE_MEM) - return round_up(start, max_t(resource_size_t, SZ_1M, size)); + return round_up(start, max_t(resource_size_t, SZ_1M, + rounddown_pow_of_two(size))); else return start; } diff --git a/drivers/pci/hotplug-pci.c b/drivers/pci/hotplug-pci.c index 6258dc260d9f54..c68366cee6b72e 100644 --- a/drivers/pci/hotplug-pci.c +++ b/drivers/pci/hotplug-pci.c @@ -4,7 +4,7 @@ #include #include "pci.h" -int __ref pci_hp_add_bridge(struct pci_dev *dev) +int pci_hp_add_bridge(struct pci_dev *dev) { struct pci_bus *parent = dev->bus; int pass, busnr, start = parent->busn_res.start; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index bccc27ee10308f..bb945e33b1ecf2 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -41,7 +41,6 @@ #define pr_fmt(fmt) "acpiphp_glue: " fmt -#include #include #include @@ -501,7 +500,7 @@ static int acpiphp_rescan_slot(struct acpiphp_slot *slot) * This function should be called per *physical slot*, * not per each slot object in ACPI namespace. */ -static void __ref enable_slot(struct acpiphp_slot *slot) +static void enable_slot(struct acpiphp_slot *slot) { struct pci_dev *dev; struct pci_bus *bus = slot->bus; diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 8c146485176814..b238a1a2837223 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -250,7 +250,7 @@ int cpci_led_off(struct slot* slot) * Device configuration functions */ -int __ref cpci_configure_slot(struct slot *slot) +int cpci_configure_slot(struct slot *slot) { struct pci_dev *dev; struct pci_bus *parent; diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c index 76ba8a1c774dfa..9600a392eaae86 100644 --- a/drivers/pci/hotplug/cpqphp_nvram.c +++ b/drivers/pci/hotplug/cpqphp_nvram.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include "cpqphp.h" #include "cpqphp_nvram.h" diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 8a66866b8cf1ad..8e9012dca450df 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -127,7 +127,7 @@ struct controller { #define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_HPS) #define EMI(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_EIP) #define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_NCCS) -#define PSN(ctrl) ((ctrl)->slot_cap >> 19) +#define PSN(ctrl) (((ctrl)->slot_cap & PCI_EXP_SLTCAP_PSN) >> 19) int pciehp_sysfs_enable_slot(struct slot *slot); int pciehp_sysfs_disable_slot(struct slot *slot); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index d7d058fa19a428..1463412cf7f8e9 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -159,6 +159,8 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); if (slot_status & PCI_EXP_SLTSTA_CC) { + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_CC); if (!ctrl->no_cmd_complete) { /* * After 1 sec and CMD_COMPLETED still not set, just diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c index 16f9203523179c..e246a10a0d2c5e 100644 --- a/drivers/pci/hotplug/pcihp_slot.c +++ b/drivers/pci/hotplug/pcihp_slot.c @@ -160,8 +160,7 @@ void pci_configure_slot(struct pci_dev *dev) (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) return; - if (dev->bus) - pcie_bus_configure_settings(dev->bus); + pcie_bus_configure_settings(dev->bus); memset(&hpp, 0, sizeof(hpp)); ret = pci_get_hp_params(dev, &hpp); diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 4796c15fba941d..984d708552f6f9 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -223,16 +223,16 @@ int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, type_tmp = (char *) &types[1]; /* Iterate through parent properties, looking for my-drc-index */ - for (i = 0; i < indexes[0]; i++) { + for (i = 0; i < be32_to_cpu(indexes[0]); i++) { if ((unsigned int) indexes[i + 1] == *my_index) { if (drc_name) *drc_name = name_tmp; if (drc_type) *drc_type = type_tmp; if (drc_index) - *drc_index = *my_index; + *drc_index = be32_to_cpu(*my_index); if (drc_power_domain) - *drc_power_domain = domains[i+1]; + *drc_power_domain = be32_to_cpu(domains[i+1]); return 0; } name_tmp += (strlen(name_tmp) + 1); @@ -321,16 +321,19 @@ int rpaphp_add_slot(struct device_node *dn) /* register PCI devices */ name = (char *) &names[1]; type = (char *) &types[1]; - for (i = 0; i < indexes[0]; i++) { + for (i = 0; i < be32_to_cpu(indexes[0]); i++) { + int index; - slot = alloc_slot_struct(dn, indexes[i + 1], name, power_domains[i + 1]); + index = be32_to_cpu(indexes[i + 1]); + slot = alloc_slot_struct(dn, index, name, + be32_to_cpu(power_domains[i + 1])); if (!slot) return -ENOMEM; slot->type = simple_strtoul(type, NULL, 10); dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n", - indexes[i + 1], name, type); + index, name, type); retval = rpaphp_enable_slot(slot); if (!retval) diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c index 8d2ce22151eb62..d1332d2f8730cd 100644 --- a/drivers/pci/hotplug/s390_pci_hpc.c +++ b/drivers/pci/hotplug/s390_pci_hpc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index 2bf69fe1926c6b..18209ebc097961 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -34,7 +34,7 @@ #include "../pci.h" #include "shpchp.h" -int __ref shpchp_configure_device(struct slot *p_slot) +int shpchp_configure_device(struct slot *p_slot) { struct pci_dev *dev; struct controller *ctrl = p_slot->ctrl; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 955ab7990c5bd7..275585c2dee29e 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -544,22 +543,18 @@ static int populate_msi_sysfs(struct pci_dev *pdev) if (!msi_attrs) return -ENOMEM; list_for_each_entry(entry, &pdev->msi_list, list) { - char *name = kmalloc(20, GFP_KERNEL); - if (!name) - goto error_attrs; - msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL); - if (!msi_dev_attr) { - kfree(name); + if (!msi_dev_attr) goto error_attrs; - } + msi_attrs[count] = &msi_dev_attr->attr; - sprintf(name, "%d", entry->irq); sysfs_attr_init(&msi_dev_attr->attr); - msi_dev_attr->attr.name = name; + msi_dev_attr->attr.name = kasprintf(GFP_KERNEL, "%d", + entry->irq); + if (!msi_dev_attr->attr.name) + goto error_attrs; msi_dev_attr->attr.mode = S_IRUGO; msi_dev_attr->show = msi_mode_show; - msi_attrs[count] = &msi_dev_attr->attr; ++count; } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d911e0c1f35979..ff236ed4f5cf4f 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -107,7 +107,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) subdevice=PCI_ANY_ID, class=0, class_mask=0; unsigned long driver_data=0; int fields=0; - int retval; + int retval = 0; fields = sscanf(buf, "%x %x %x %x %x %x %lx", &vendor, &device, &subvendor, &subdevice, @@ -115,6 +115,26 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) if (fields < 2) return -EINVAL; + if (fields != 7) { + struct pci_dev *pdev = kzalloc(sizeof(*pdev), GFP_KERNEL); + if (!pdev) + return -ENOMEM; + + pdev->vendor = vendor; + pdev->device = device; + pdev->subsystem_vendor = subvendor; + pdev->subsystem_device = subdevice; + pdev->class = class; + + if (pci_match_id(pdrv->id_table, pdev)) + retval = -EEXIST; + + kfree(pdev); + + if (retval) + return retval; + } + /* Only accept driver_data values that match an existing id_table entry */ if (ids) { @@ -1325,8 +1345,6 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env) return -ENODEV; pdev = to_pci_dev(dev); - if (!pdev) - return -ENODEV; if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class)) return -ENOMEM; @@ -1347,6 +1365,7 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env) (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), (u8)(pdev->class))) return -ENOMEM; + return 0; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7325d43bf030ce..c423be182158ed 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -106,7 +106,7 @@ static bool pcie_ari_disabled; * Given a PCI bus, returns the highest PCI bus number present in the set * including the given PCI bus and its list of child PCI buses. */ -unsigned char pci_bus_max_busnr(struct pci_bus* bus) +unsigned char pci_bus_max_busnr(struct pci_bus *bus) { struct pci_bus *tmp; unsigned char max, n; @@ -1371,7 +1371,7 @@ static void pcim_release(struct device *gendev, void *res) pci_disable_device(dev); } -static struct pci_devres * get_pci_dr(struct pci_dev *pdev) +static struct pci_devres *get_pci_dr(struct pci_dev *pdev) { struct pci_devres *dr, *new_dr; @@ -1385,7 +1385,7 @@ static struct pci_devres * get_pci_dr(struct pci_dev *pdev) return devres_get(&pdev->dev, new_dr, NULL, NULL); } -static struct pci_devres * find_pci_dr(struct pci_dev *pdev) +static struct pci_devres *find_pci_dr(struct pci_dev *pdev) { if (pci_is_managed(pdev)) return devres_find(&pdev->dev, pcim_release, NULL, NULL); @@ -3167,14 +3167,7 @@ static int pci_pm_reset(struct pci_dev *dev, int probe) return 0; } -/** - * pci_reset_bridge_secondary_bus - Reset the secondary bus on a PCI bridge. - * @dev: Bridge device - * - * Use the bridge control register to assert reset on the secondary bus. - * Devices on the secondary bus are left in power-on state. - */ -void pci_reset_bridge_secondary_bus(struct pci_dev *dev) +void __weak pcibios_reset_secondary_bus(struct pci_dev *dev) { u16 ctrl; @@ -3199,6 +3192,18 @@ void pci_reset_bridge_secondary_bus(struct pci_dev *dev) */ ssleep(1); } + +/** + * pci_reset_bridge_secondary_bus - Reset the secondary bus on a PCI bridge. + * @dev: Bridge device + * + * Use the bridge control register to assert reset on the secondary bus. + * Devices on the secondary bus are left in power-on state. + */ +void pci_reset_bridge_secondary_bus(struct pci_dev *dev) +{ + pcibios_reset_secondary_bus(dev); +} EXPORT_SYMBOL_GPL(pci_reset_bridge_secondary_bus); static int pci_parent_bus_reset(struct pci_dev *dev, int probe) @@ -4125,7 +4130,7 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, u16 cmd; int rc; - WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) & (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY))); + WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) && (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY))); /* ARCH specific VGA enables */ rc = pci_set_vga_state_arch(dev, decode, command_bits, flags); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 6bd082299e3190..fe233a3099cf60 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -201,11 +201,11 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, struct resource *res, unsigned int reg); int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type); void pci_configure_ari(struct pci_dev *dev); -void __ref __pci_bus_size_bridges(struct pci_bus *bus, +void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head); -void __ref __pci_bus_assign_resources(const struct pci_bus *bus, - struct list_head *realloc_head, - struct list_head *fail_head); +void __pci_bus_assign_resources(const struct pci_bus *bus, + struct list_head *realloc_head, + struct list_head *fail_head); /** * pci_ari_enabled - query ARI forwarding status diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 986f8eadfd3939..2f0ce668a775ed 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -99,7 +99,7 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) for (i = 0; i < nr_entries; i++) msix_entries[i].entry = i; - status = pci_enable_msix(dev, msix_entries, nr_entries); + status = pci_enable_msix_exact(dev, msix_entries, nr_entries); if (status) goto Exit; @@ -171,7 +171,7 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) pci_disable_msix(dev); /* Now allocate the MSI-X vectors for real */ - status = pci_enable_msix(dev, msix_entries, nvec); + status = pci_enable_msix_exact(dev, msix_entries, nvec); if (status) goto Exit; } @@ -379,10 +379,13 @@ int pcie_port_device_register(struct pci_dev *dev) /* * Initialize service irqs. Don't use service devices that * require interrupts if there is no way to generate them. + * However, some drivers may have a polling mode (e.g. pciehp_poll_mode) + * that can be used in the absence of irqs. Allow them to determine + * if that is to be used. */ status = init_service_irqs(dev, irqs, capabilities); if (status) { - capabilities &= PCIE_PORT_SERVICE_VC; + capabilities &= PCIE_PORT_SERVICE_VC | PCIE_PORT_SERVICE_HP; if (!capabilities) goto error_disable; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ef09f5f2fe6c0b..490031fd21084c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -719,7 +719,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, return child; } -struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr) +struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr) { struct pci_bus *child; @@ -1369,7 +1369,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) WARN_ON(ret < 0); } -struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn) +struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) { struct pci_dev *dev; @@ -1617,7 +1617,7 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data) */ void pcie_bus_configure_settings(struct pci_bus *bus) { - u8 smpss; + u8 smpss = 0; if (!bus->self) return; @@ -1958,7 +1958,7 @@ EXPORT_SYMBOL(pci_scan_bus); * * Returns the max number of subordinate bus discovered. */ -unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge) +unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge) { unsigned int max; struct pci_bus *bus = bridge->subordinate; @@ -1981,7 +1981,7 @@ unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge) * * Returns the max number of subordinate bus discovered. */ -unsigned int __ref pci_rescan_bus(struct pci_bus *bus) +unsigned int pci_rescan_bus(struct pci_bus *bus) { unsigned int max; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e7292065a1b13f..9825ad01d812c4 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2954,6 +2954,7 @@ static void disable_igfx_irq(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq); /* * PCI devices which are on Intel chips can skip the 10ms delay @@ -3453,6 +3454,8 @@ static const u16 pci_quirk_intel_pch_acs_ids[] = { /* Wildcat PCH */ 0x9c90, 0x9c91, 0x9c92, 0x9c93, 0x9c94, 0x9c95, 0x9c96, 0x9c97, 0x9c98, 0x9c99, 0x9c9a, 0x9c9b, + /* Patsburg (X79) PCH */ + 0x1d10, 0x1d12, 0x1d14, 0x1d16, 0x1d18, 0x1d1a, 0x1d1c, 0x1d1e, }; static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev) diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 4a1b972efe7f2f..8e495bda678f2e 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -7,7 +7,6 @@ * Copyright (C) 2003 -- 2004 Greg Kroah-Hartman */ -#include #include #include #include diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 138bdd6393be87..d219d44709b2fe 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1113,8 +1113,7 @@ static void pci_bus_size_cardbus(struct pci_bus *bus, ; } -void __ref __pci_bus_size_bridges(struct pci_bus *bus, - struct list_head *realloc_head) +void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) { struct pci_dev *dev; unsigned long mask, prefmask; @@ -1178,15 +1177,15 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus, } } -void __ref pci_bus_size_bridges(struct pci_bus *bus) +void pci_bus_size_bridges(struct pci_bus *bus) { __pci_bus_size_bridges(bus, NULL); } EXPORT_SYMBOL(pci_bus_size_bridges); -void __ref __pci_bus_assign_resources(const struct pci_bus *bus, - struct list_head *realloc_head, - struct list_head *fail_head) +void __pci_bus_assign_resources(const struct pci_bus *bus, + struct list_head *realloc_head, + struct list_head *fail_head) { struct pci_bus *b; struct pci_dev *dev; @@ -1218,15 +1217,15 @@ void __ref __pci_bus_assign_resources(const struct pci_bus *bus, } } -void __ref pci_bus_assign_resources(const struct pci_bus *bus) +void pci_bus_assign_resources(const struct pci_bus *bus) { __pci_bus_assign_resources(bus, NULL, NULL); } EXPORT_SYMBOL(pci_bus_assign_resources); -static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge, - struct list_head *add_head, - struct list_head *fail_head) +static void __pci_bridge_assign_resources(const struct pci_dev *bridge, + struct list_head *add_head, + struct list_head *fail_head) { struct pci_bus *b; @@ -1304,9 +1303,9 @@ enum release_type { * try to release pci bridge resources that is from leaf bridge, * so we can allocate big new one later */ -static void __ref pci_bus_release_bridge_resources(struct pci_bus *bus, - unsigned long type, - enum release_type rel_type) +static void pci_bus_release_bridge_resources(struct pci_bus *bus, + unsigned long type, + enum release_type rel_type) { struct pci_dev *dev; bool is_leaf_bridge = true; diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index 9bd6864ec5d3fc..dbc4ffcf42decd 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -10,7 +10,6 @@ */ -#include #include #include #include diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 7eed671d55861c..1e37c590a1833c 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -16,7 +16,6 @@ * Resource sorting */ -#include #include #include #include diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 179b8edc22624d..53df39a22c8acb 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -662,9 +662,9 @@ static void pcifront_do_aer(struct work_struct *data) notify_remote_via_evtchn(pdev->evtchn); /*in case of we lost an aer request in four lines time_window*/ - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(_PDEVB_op_active, &pdev->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); schedule_pcifront_aer_op(pdev); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index e00c02d0a09429..934fd89978d3c0 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -84,6 +84,9 @@ config PINCTRL_AT91 depends on ARCH_AT91 select PINMUX select PINCONF + select GPIOLIB + select OF_GPIO + select GPIOLIB_IRQCHIP help Say Y here to enable the at91 pinctrl driver @@ -222,9 +225,25 @@ config PINCTRL_MSM select PINCONF select GENERIC_PINCONF +config PINCTRL_APQ8064 + tristate "Qualcomm APQ8064 pin controller driver" + depends on GPIOLIB && OF + select PINCTRL_MSM + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm TLMM block found in the Qualcomm APQ8064 platform. + +config PINCTRL_IPQ8064 + tristate "Qualcomm IPQ8064 pin controller driver" + depends on GPIOLIB && OF + select PINCTRL_MSM + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm TLMM block found in the Qualcomm IPQ8064 platform. + config PINCTRL_MSM8X74 tristate "Qualcomm 8x74 pin controller driver" - depends on GPIOLIB && OF + depends on GPIOLIB && OF && (ARCH_QCOM || COMPILE_TEST) select PINCTRL_MSM help This is the pinctrl, pinmux, pinconf and gpiolib driver for the @@ -270,6 +289,7 @@ config PINCTRL_SIRF bool "CSR SiRFprimaII/SiRFmarco pin controller driver" depends on ARCH_SIRF select PINMUX + select GPIOLIB_IRQCHIP config PINCTRL_SUNXI bool @@ -281,6 +301,7 @@ config PINCTRL_ST depends on OF select PINMUX select PINCONF + select GPIOLIB_IRQCHIP config PINCTRL_TEGRA bool diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 6d3fd62b9ae836..68bb399fc5770f 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -38,6 +38,8 @@ obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o obj-$(CONFIG_PINCTRL_IMX25) += pinctrl-imx25.o obj-$(CONFIG_PINCTRL_IMX28) += pinctrl-imx28.o obj-$(CONFIG_PINCTRL_MSM) += pinctrl-msm.o +obj-$(CONFIG_PINCTRL_APQ8064) += pinctrl-apq8064.o +obj-$(CONFIG_PINCTRL_IPQ8064) += pinctrl-ipq8064.o obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o obj-$(CONFIG_PINCTRL_STN8815) += pinctrl-nomadik-stn8815.o diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index c0fe6091566a47..e09474ecde2346 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -468,6 +468,9 @@ int pinctrl_get_group_pins(struct pinctrl_dev *pctldev, const char *pin_group, const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; int gs; + if (!pctlops->get_group_pins) + return -EINVAL; + gs = pinctrl_get_group_selector(pctldev, pin_group); if (gs < 0) return gs; @@ -1362,15 +1365,16 @@ static int pinctrl_groups_show(struct seq_file *s, void *what) seq_puts(s, "registered pin groups:\n"); while (selector < ngroups) { - const unsigned *pins; - unsigned num_pins; + const unsigned *pins = NULL; + unsigned num_pins = 0; const char *gname = ops->get_group_name(pctldev, selector); const char *pname; - int ret; + int ret = 0; int i; - ret = ops->get_group_pins(pctldev, selector, - &pins, &num_pins); + if (ops->get_group_pins) + ret = ops->get_group_pins(pctldev, selector, + &pins, &num_pins); if (ret) seq_printf(s, "%s [ERROR GETTING PINS]\n", gname); @@ -1694,8 +1698,7 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev) if (!ops || !ops->get_groups_count || - !ops->get_group_name || - !ops->get_group_pins) + !ops->get_group_name) return -EINVAL; if (ops->dt_node_to_map && !ops->dt_free_map) diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig index cc298fade93a79..d6dd8358a6f60e 100644 --- a/drivers/pinctrl/mvebu/Kconfig +++ b/drivers/pinctrl/mvebu/Kconfig @@ -30,4 +30,8 @@ config PINCTRL_ARMADA_XP bool select PINCTRL_MVEBU +config PINCTRL_ORION + bool + select PINCTRL_MVEBU + endif diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile index bc1b9f14f539a2..a0818e96374b7f 100644 --- a/drivers/pinctrl/mvebu/Makefile +++ b/drivers/pinctrl/mvebu/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o obj-$(CONFIG_PINCTRL_ARMADA_375) += pinctrl-armada-375.o obj-$(CONFIG_PINCTRL_ARMADA_38X) += pinctrl-armada-38x.o obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o +obj-$(CONFIG_PINCTRL_ORION) += pinctrl-orion.o diff --git a/drivers/pinctrl/mvebu/pinctrl-orion.c b/drivers/pinctrl/mvebu/pinctrl-orion.c new file mode 100644 index 00000000000000..dda1e7254e15f1 --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-orion.c @@ -0,0 +1,261 @@ +/* + * Marvell Orion pinctrl driver based on mvebu pinctrl core + * + * Author: Thomas Petazzoni + * + * 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. + * + * The first 16 MPP pins on Orion are easy to handle: they are + * configured through 2 consecutive registers, located at the base + * address of the MPP device. + * + * However the last 4 MPP pins are handled by a register at offset + * 0x50 from the base address, so it is not consecutive with the first + * two registers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pinctrl-mvebu.h" + +static void __iomem *mpp_base; +static void __iomem *high_mpp_base; + +static int orion_mpp_ctrl_get(unsigned pid, unsigned long *config) +{ + unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + + if (pid < 16) { + unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + *config = (readl(mpp_base + off) >> shift) & MVEBU_MPP_MASK; + } + else { + *config = (readl(high_mpp_base) >> shift) & MVEBU_MPP_MASK; + } + + return 0; +} + +static int orion_mpp_ctrl_set(unsigned pid, unsigned long config) +{ + unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + + if (pid < 16) { + unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + u32 reg = readl(mpp_base + off) & ~(MVEBU_MPP_MASK << shift); + writel(reg | (config << shift), mpp_base + off); + } + else { + u32 reg = readl(high_mpp_base) & ~(MVEBU_MPP_MASK << shift); + writel(reg | (config << shift), high_mpp_base); + } + + return 0; +} + +#define V(f5181l, f5182, f5281) \ + ((f5181l << 0) | (f5182 << 1) | (f5281 << 2)) + +enum orion_variant { + V_5181L = V(1, 0, 0), + V_5182 = V(0, 1, 0), + V_5281 = V(0, 0, 1), + V_ALL = V(1, 1, 1), +}; + +static struct mvebu_mpp_mode orion_mpp_modes[] = { + MPP_MODE(0, + MPP_VAR_FUNCTION(0x0, "pcie", "rstout", V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "req2", V_ALL), + MPP_VAR_FUNCTION(0x3, "gpio", NULL, V_ALL)), + MPP_MODE(1, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "gnt2", V_ALL)), + MPP_MODE(2, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "req3", V_ALL), + MPP_VAR_FUNCTION(0x3, "pci-1", "pme", V_ALL)), + MPP_MODE(3, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "gnt3", V_ALL)), + MPP_MODE(4, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "req4", V_ALL), + MPP_VAR_FUNCTION(0x4, "bootnand", "re", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V_5182)), + MPP_MODE(5, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "gnt4", V_ALL), + MPP_VAR_FUNCTION(0x4, "bootnand", "we", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V_5182)), + MPP_MODE(6, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "req5", V_ALL), + MPP_VAR_FUNCTION(0x4, "nand", "re0", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181L), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V_5182)), + MPP_MODE(7, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "gnt5", V_ALL), + MPP_VAR_FUNCTION(0x4, "nand", "we0", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181L), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V_5182)), + MPP_MODE(8, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "col", V_ALL)), + MPP_MODE(9, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "rxerr", V_ALL)), + MPP_MODE(10, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "crs", V_ALL)), + MPP_MODE(11, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "txerr", V_ALL)), + MPP_MODE(12, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "txd4", V_ALL), + MPP_VAR_FUNCTION(0x4, "nand", "re1", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "sata0", "ledprsnt", V_5182)), + MPP_MODE(13, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "txd5", V_ALL), + MPP_VAR_FUNCTION(0x4, "nand", "we1", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "sata1", "ledprsnt", V_5182)), + MPP_MODE(14, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "txd6", V_ALL), + MPP_VAR_FUNCTION(0x4, "nand", "re2", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "sata0", "ledact", V_5182)), + MPP_MODE(15, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "txd7", V_ALL), + MPP_VAR_FUNCTION(0x4, "nand", "we2", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "sata1", "ledact", V_5182)), + MPP_MODE(16, + MPP_VAR_FUNCTION(0x0, "uart1", "rxd", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x1, "ge", "rxd4", V_ALL), + MPP_VAR_FUNCTION(0x5, "gpio", NULL, V_5182)), + MPP_MODE(17, + MPP_VAR_FUNCTION(0x0, "uart1", "txd", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x1, "ge", "rxd5", V_ALL), + MPP_VAR_FUNCTION(0x5, "gpio", NULL, V_5182)), + MPP_MODE(18, + MPP_VAR_FUNCTION(0x0, "uart1", "cts", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x1, "ge", "rxd6", V_ALL), + MPP_VAR_FUNCTION(0x5, "gpio", NULL, V_5182)), + MPP_MODE(19, + MPP_VAR_FUNCTION(0x0, "uart1", "rts", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x1, "ge", "rxd7", V_ALL), + MPP_VAR_FUNCTION(0x5, "gpio", NULL, V_5182)), +}; + +static struct mvebu_mpp_ctrl orion_mpp_controls[] = { + MPP_FUNC_CTRL(0, 19, NULL, orion_mpp_ctrl), +}; + +static struct pinctrl_gpio_range mv88f5181l_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 16), +}; + +static struct pinctrl_gpio_range mv88f5182_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 19), +}; + +static struct pinctrl_gpio_range mv88f5281_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 16), +}; + +static struct mvebu_pinctrl_soc_info mv88f5181l_info = { + .variant = V_5181L, + .controls = orion_mpp_controls, + .ncontrols = ARRAY_SIZE(orion_mpp_controls), + .modes = orion_mpp_modes, + .nmodes = ARRAY_SIZE(orion_mpp_modes), + .gpioranges = mv88f5181l_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f5181l_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv88f5182_info = { + .variant = V_5182, + .controls = orion_mpp_controls, + .ncontrols = ARRAY_SIZE(orion_mpp_controls), + .modes = orion_mpp_modes, + .nmodes = ARRAY_SIZE(orion_mpp_modes), + .gpioranges = mv88f5182_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f5182_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv88f5281_info = { + .variant = V_5281, + .controls = orion_mpp_controls, + .ncontrols = ARRAY_SIZE(orion_mpp_controls), + .modes = orion_mpp_modes, + .nmodes = ARRAY_SIZE(orion_mpp_modes), + .gpioranges = mv88f5281_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f5281_gpio_ranges), +}; + +/* + * There are multiple variants of the Orion SoCs, but in terms of pin + * muxing, they are identical. + */ +static struct of_device_id orion_pinctrl_of_match[] = { + { .compatible = "marvell,88f5181l-pinctrl", .data = &mv88f5181l_info }, + { .compatible = "marvell,88f5182-pinctrl", .data = &mv88f5182_info }, + { .compatible = "marvell,88f5281-pinctrl", .data = &mv88f5281_info }, + { } +}; + +static int orion_pinctrl_probe(struct platform_device *pdev) +{ + const struct of_device_id *match = + of_match_device(orion_pinctrl_of_match, &pdev->dev); + struct resource *res; + + pdev->dev.platform_data = (void*)match->data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mpp_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mpp_base)) + return PTR_ERR(mpp_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + high_mpp_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(high_mpp_base)) + return PTR_ERR(high_mpp_base); + + return mvebu_pinctrl_probe(pdev); +} + +static int orion_pinctrl_remove(struct platform_device *pdev) +{ + return mvebu_pinctrl_remove(pdev); +} + +static struct platform_driver orion_pinctrl_driver = { + .driver = { + .name = "orion-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(orion_pinctrl_of_match), + }, + .probe = orion_pinctrl_probe, + .remove = orion_pinctrl_remove, +}; + +module_platform_driver(orion_pinctrl_driver); + +MODULE_AUTHOR("Thomas Petazzoni "); +MODULE_DESCRIPTION("Marvell Orion pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c index 0cc0eec83396e0..5c44feb54ebb47 100644 --- a/drivers/pinctrl/pinctrl-adi2.c +++ b/drivers/pinctrl/pinctrl-adi2.c @@ -927,7 +927,7 @@ static int adi_gpio_irq_map(struct irq_domain *d, unsigned int irq, return 0; } -const struct irq_domain_ops adi_gpio_irq_domain_ops = { +static const struct irq_domain_ops adi_gpio_irq_domain_ops = { .map = adi_gpio_irq_map, .xlate = irq_domain_xlate_onecell, }; diff --git a/drivers/pinctrl/pinctrl-apq8064.c b/drivers/pinctrl/pinctrl-apq8064.c new file mode 100644 index 00000000000000..7c2a8baaea8025 --- /dev/null +++ b/drivers/pinctrl/pinctrl-apq8064.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2014, Sony Mobile Communications AB. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +#include +#include +#include +#include + +#include "pinctrl-msm.h" + +static const struct pinctrl_pin_desc apq8064_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), +}; + +#define DECLARE_APQ_GPIO_PINS(pin) static const unsigned int gpio##pin##_pins[] = { pin } +DECLARE_APQ_GPIO_PINS(0); +DECLARE_APQ_GPIO_PINS(1); +DECLARE_APQ_GPIO_PINS(2); +DECLARE_APQ_GPIO_PINS(3); +DECLARE_APQ_GPIO_PINS(4); +DECLARE_APQ_GPIO_PINS(5); +DECLARE_APQ_GPIO_PINS(6); +DECLARE_APQ_GPIO_PINS(7); +DECLARE_APQ_GPIO_PINS(8); +DECLARE_APQ_GPIO_PINS(9); +DECLARE_APQ_GPIO_PINS(10); +DECLARE_APQ_GPIO_PINS(11); +DECLARE_APQ_GPIO_PINS(12); +DECLARE_APQ_GPIO_PINS(13); +DECLARE_APQ_GPIO_PINS(14); +DECLARE_APQ_GPIO_PINS(15); +DECLARE_APQ_GPIO_PINS(16); +DECLARE_APQ_GPIO_PINS(17); +DECLARE_APQ_GPIO_PINS(18); +DECLARE_APQ_GPIO_PINS(19); +DECLARE_APQ_GPIO_PINS(20); +DECLARE_APQ_GPIO_PINS(21); +DECLARE_APQ_GPIO_PINS(22); +DECLARE_APQ_GPIO_PINS(23); +DECLARE_APQ_GPIO_PINS(24); +DECLARE_APQ_GPIO_PINS(25); +DECLARE_APQ_GPIO_PINS(26); +DECLARE_APQ_GPIO_PINS(27); +DECLARE_APQ_GPIO_PINS(28); +DECLARE_APQ_GPIO_PINS(29); +DECLARE_APQ_GPIO_PINS(30); +DECLARE_APQ_GPIO_PINS(31); +DECLARE_APQ_GPIO_PINS(32); +DECLARE_APQ_GPIO_PINS(33); +DECLARE_APQ_GPIO_PINS(34); +DECLARE_APQ_GPIO_PINS(35); +DECLARE_APQ_GPIO_PINS(36); +DECLARE_APQ_GPIO_PINS(37); +DECLARE_APQ_GPIO_PINS(38); +DECLARE_APQ_GPIO_PINS(39); +DECLARE_APQ_GPIO_PINS(40); +DECLARE_APQ_GPIO_PINS(41); +DECLARE_APQ_GPIO_PINS(42); +DECLARE_APQ_GPIO_PINS(43); +DECLARE_APQ_GPIO_PINS(44); +DECLARE_APQ_GPIO_PINS(45); +DECLARE_APQ_GPIO_PINS(46); +DECLARE_APQ_GPIO_PINS(47); +DECLARE_APQ_GPIO_PINS(48); +DECLARE_APQ_GPIO_PINS(49); +DECLARE_APQ_GPIO_PINS(50); +DECLARE_APQ_GPIO_PINS(51); +DECLARE_APQ_GPIO_PINS(52); +DECLARE_APQ_GPIO_PINS(53); +DECLARE_APQ_GPIO_PINS(54); +DECLARE_APQ_GPIO_PINS(55); +DECLARE_APQ_GPIO_PINS(56); +DECLARE_APQ_GPIO_PINS(57); +DECLARE_APQ_GPIO_PINS(58); +DECLARE_APQ_GPIO_PINS(59); +DECLARE_APQ_GPIO_PINS(60); +DECLARE_APQ_GPIO_PINS(61); +DECLARE_APQ_GPIO_PINS(62); +DECLARE_APQ_GPIO_PINS(63); +DECLARE_APQ_GPIO_PINS(64); +DECLARE_APQ_GPIO_PINS(65); +DECLARE_APQ_GPIO_PINS(66); +DECLARE_APQ_GPIO_PINS(67); +DECLARE_APQ_GPIO_PINS(68); +DECLARE_APQ_GPIO_PINS(69); +DECLARE_APQ_GPIO_PINS(70); +DECLARE_APQ_GPIO_PINS(71); +DECLARE_APQ_GPIO_PINS(72); +DECLARE_APQ_GPIO_PINS(73); +DECLARE_APQ_GPIO_PINS(74); +DECLARE_APQ_GPIO_PINS(75); +DECLARE_APQ_GPIO_PINS(76); +DECLARE_APQ_GPIO_PINS(77); +DECLARE_APQ_GPIO_PINS(78); +DECLARE_APQ_GPIO_PINS(79); +DECLARE_APQ_GPIO_PINS(80); +DECLARE_APQ_GPIO_PINS(81); +DECLARE_APQ_GPIO_PINS(82); +DECLARE_APQ_GPIO_PINS(83); +DECLARE_APQ_GPIO_PINS(84); +DECLARE_APQ_GPIO_PINS(85); +DECLARE_APQ_GPIO_PINS(86); +DECLARE_APQ_GPIO_PINS(87); +DECLARE_APQ_GPIO_PINS(88); +DECLARE_APQ_GPIO_PINS(89); + +#define FUNCTION(fname) \ + [APQ_MUX_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10) \ + { \ + .name = "gpio" #id, \ + .pins = gpio##id##_pins, \ + .npins = ARRAY_SIZE(gpio##id##_pins), \ + .funcs = (int[]){ \ + APQ_MUX_NA, /* gpio mode */ \ + APQ_MUX_##f1, \ + APQ_MUX_##f2, \ + APQ_MUX_##f3, \ + APQ_MUX_##f4, \ + APQ_MUX_##f5, \ + APQ_MUX_##f6, \ + APQ_MUX_##f7, \ + APQ_MUX_##f8, \ + APQ_MUX_##f9, \ + APQ_MUX_##f10, \ + }, \ + .nfuncs = 11, \ + .ctl_reg = 0x1000 + 0x10 * id, \ + .io_reg = 0x1004 + 0x10 * id, \ + .intr_cfg_reg = 0x1008 + 0x10 * id, \ + .intr_status_reg = 0x100c + 0x10 * id, \ + .intr_target_reg = 0x400 + 0x4 * id, \ + .mux_bit = 2, \ + .pull_bit = 0, \ + .drv_bit = 6, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_ack_high = 1, \ + .intr_target_bit = 0, \ + .intr_raw_status_bit = 3, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 1, \ + } + +enum apq8064_functions { + APQ_MUX_cam_mclk, + APQ_MUX_codec_mic_i2s, + APQ_MUX_codec_spkr_i2s, + APQ_MUX_gsbi1, + APQ_MUX_gsbi2, + APQ_MUX_gsbi3, + APQ_MUX_gsbi4, + APQ_MUX_gsbi4_cam_i2c, + APQ_MUX_gsbi5, + APQ_MUX_gsbi5_spi_cs1, + APQ_MUX_gsbi5_spi_cs2, + APQ_MUX_gsbi5_spi_cs3, + APQ_MUX_gsbi6, + APQ_MUX_gsbi6_spi_cs1, + APQ_MUX_gsbi6_spi_cs2, + APQ_MUX_gsbi6_spi_cs3, + APQ_MUX_gsbi7, + APQ_MUX_gsbi7_spi_cs1, + APQ_MUX_gsbi7_spi_cs2, + APQ_MUX_gsbi7_spi_cs3, + APQ_MUX_gsbi_cam_i2c, + APQ_MUX_hdmi, + APQ_MUX_mi2s, + APQ_MUX_riva_bt, + APQ_MUX_riva_fm, + APQ_MUX_riva_wlan, + APQ_MUX_sdc2, + APQ_MUX_sdc4, + APQ_MUX_slimbus, + APQ_MUX_spkr_i2s, + APQ_MUX_tsif1, + APQ_MUX_tsif2, + APQ_MUX_usb2_hsic, + APQ_MUX_NA, +}; + +static const char * const cam_mclk_groups[] = { + "gpio4" "gpio5" +}; +static const char * const codec_mic_i2s_groups[] = { + "gpio34", "gpio35", "gpio36", "gpio37", "gpio38" +}; +static const char * const codec_spkr_i2s_groups[] = { + "gpio39", "gpio40", "gpio41", "gpio42" +}; +static const char * const gsbi1_groups[] = { + "gpio18", "gpio19", "gpio20", "gpio21" +}; +static const char * const gsbi2_groups[] = { + "gpio22", "gpio23", "gpio24", "gpio25" +}; +static const char * const gsbi3_groups[] = { + "gpio6", "gpio7", "gpio8", "gpio9" +}; +static const char * const gsbi4_groups[] = { + "gpio10", "gpio11", "gpio12", "gpio13" +}; +static const char * const gsbi4_cam_i2c_groups[] = { + "gpio10", "gpio11", "gpio12", "gpio13" +}; +static const char * const gsbi5_groups[] = { + "gpio51", "gpio52", "gpio53", "gpio54" +}; +static const char * const gsbi5_spi_cs1_groups[] = { + "gpio47" +}; +static const char * const gsbi5_spi_cs2_groups[] = { + "gpio31" +}; +static const char * const gsbi5_spi_cs3_groups[] = { + "gpio32" +}; +static const char * const gsbi6_groups[] = { + "gpio14", "gpio15", "gpio16", "gpio17" +}; +static const char * const gsbi6_spi_cs1_groups[] = { + "gpio47" +}; +static const char * const gsbi6_spi_cs2_groups[] = { + "gpio31" +}; +static const char * const gsbi6_spi_cs3_groups[] = { + "gpio32" +}; +static const char * const gsbi7_groups[] = { + "gpio82", "gpio83", "gpio84", "gpio85" +}; +static const char * const gsbi7_spi_cs1_groups[] = { + "gpio47" +}; +static const char * const gsbi7_spi_cs2_groups[] = { + "gpio31" +}; +static const char * const gsbi7_spi_cs3_groups[] = { + "gpio32" +}; +static const char * const gsbi_cam_i2c_groups[] = { + "gpio10", "gpio11", "gpio12", "gpio13" +}; +static const char * const hdmi_groups[] = { + "gpio69", "gpio70", "gpio71", "gpio72" +}; +static const char * const mi2s_groups[] = { + "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", "gpio33" +}; +static const char * const riva_bt_groups[] = { + "gpio16", "gpio17" +}; +static const char * const riva_fm_groups[] = { + "gpio14", "gpio15" +}; +static const char * const riva_wlan_groups[] = { + "gpio64", "gpio65", "gpio66", "gpio67", "gpio68" +}; +static const char * const sdc2_groups[] = { + "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62" +}; +static const char * const sdc4_groups[] = { + "gpio63", "gpio64", "gpio65", "gpio66", "gpio67", "gpio68" +}; +static const char * const slimbus_groups[] = { + "gpio40", "gpio41" +}; +static const char * const spkr_i2s_groups[] = { + "gpio47", "gpio48", "gpio49", "gpio50" +}; +static const char * const tsif1_groups[] = { + "gpio55", "gpio56", "gpio57" +}; +static const char * const tsif2_groups[] = { + "gpio58", "gpio59", "gpio60" +}; +static const char * const usb2_hsic_groups[] = { + "gpio88", "gpio89" +}; + +static const struct msm_function apq8064_functions[] = { + FUNCTION(cam_mclk), + FUNCTION(codec_mic_i2s), + FUNCTION(codec_spkr_i2s), + FUNCTION(gsbi1), + FUNCTION(gsbi2), + FUNCTION(gsbi3), + FUNCTION(gsbi4), + FUNCTION(gsbi4_cam_i2c), + FUNCTION(gsbi5), + FUNCTION(gsbi5_spi_cs1), + FUNCTION(gsbi5_spi_cs2), + FUNCTION(gsbi5_spi_cs3), + FUNCTION(gsbi6), + FUNCTION(gsbi6_spi_cs1), + FUNCTION(gsbi6_spi_cs2), + FUNCTION(gsbi6_spi_cs3), + FUNCTION(gsbi7), + FUNCTION(gsbi7_spi_cs1), + FUNCTION(gsbi7_spi_cs2), + FUNCTION(gsbi7_spi_cs3), + FUNCTION(gsbi_cam_i2c), + FUNCTION(hdmi), + FUNCTION(mi2s), + FUNCTION(riva_bt), + FUNCTION(riva_fm), + FUNCTION(riva_wlan), + FUNCTION(sdc2), + FUNCTION(sdc4), + FUNCTION(slimbus), + FUNCTION(spkr_i2s), + FUNCTION(tsif1), + FUNCTION(tsif2), + FUNCTION(usb2_hsic), +}; + +static const struct msm_pingroup apq8064_groups[] = { + PINGROUP(0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(4, NA, NA, cam_mclk, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(5, NA, cam_mclk, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(6, gsbi3, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(7, gsbi3, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(8, gsbi3, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(9, gsbi3, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(10, gsbi4, NA, NA, NA, NA, NA, NA, NA, gsbi4_cam_i2c, NA), + PINGROUP(11, gsbi4, NA, NA, NA, NA, NA, NA, NA, NA, gsbi4_cam_i2c), + PINGROUP(12, gsbi4, NA, NA, NA, NA, gsbi4_cam_i2c, NA, NA, NA, NA), + PINGROUP(13, gsbi4, NA, NA, NA, NA, gsbi4_cam_i2c, NA, NA, NA, NA), + PINGROUP(14, riva_fm, gsbi6, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(15, riva_fm, gsbi6, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(16, riva_bt, gsbi6, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(17, riva_bt, gsbi6, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(18, gsbi1, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(19, gsbi1, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(20, gsbi1, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(21, gsbi1, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(22, gsbi2, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(23, gsbi2, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(24, gsbi2, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(25, gsbi2, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(26, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(27, mi2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(28, mi2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(29, mi2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(30, mi2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(31, mi2s, NA, gsbi5_spi_cs2, gsbi6_spi_cs2, gsbi7_spi_cs2, NA, NA, NA, NA, NA), + PINGROUP(32, mi2s, NA, NA, NA, NA, gsbi5_spi_cs3, gsbi6_spi_cs3, gsbi7_spi_cs3, NA, NA), + PINGROUP(33, mi2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(34, codec_mic_i2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(35, codec_mic_i2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(36, codec_mic_i2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(37, codec_mic_i2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(38, codec_mic_i2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(39, codec_spkr_i2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(40, slimbus, codec_spkr_i2s, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(41, slimbus, codec_spkr_i2s, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(42, codec_spkr_i2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(43, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(44, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(45, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(46, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(47, spkr_i2s, gsbi5_spi_cs1, gsbi6_spi_cs1, gsbi7_spi_cs1, NA, NA, NA, NA, NA, NA), + PINGROUP(48, spkr_i2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(49, spkr_i2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(50, spkr_i2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(51, NA, gsbi5, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(52, NA, gsbi5, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(53, NA, gsbi5, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(54, NA, gsbi5, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(55, tsif1, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(56, tsif1, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(57, tsif1, sdc2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(58, tsif2, sdc2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(59, tsif2, sdc2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(60, tsif2, sdc2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(61, NA, sdc2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(62, NA, sdc2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(63, NA, sdc4, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(64, riva_wlan, sdc4, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(65, riva_wlan, sdc4, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(66, riva_wlan, sdc4, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(67, riva_wlan, sdc4, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(68, riva_wlan, sdc4, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(69, hdmi, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(70, hdmi, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(71, hdmi, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(72, hdmi, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(73, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(74, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(75, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(76, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(77, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(78, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(79, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(80, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(81, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(82, NA, gsbi7, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(83, gsbi7, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(84, NA, gsbi7, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(85, NA, NA, gsbi7, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(86, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(87, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(88, usb2_hsic, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(89, usb2_hsic, NA, NA, NA, NA, NA, NA, NA, NA, NA), +}; + +#define NUM_GPIO_PINGROUPS 90 + +static const struct msm_pinctrl_soc_data apq8064_pinctrl = { + .pins = apq8064_pins, + .npins = ARRAY_SIZE(apq8064_pins), + .functions = apq8064_functions, + .nfunctions = ARRAY_SIZE(apq8064_functions), + .groups = apq8064_groups, + .ngroups = ARRAY_SIZE(apq8064_groups), + .ngpios = NUM_GPIO_PINGROUPS, +}; + +static int apq8064_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &apq8064_pinctrl); +} + +static const struct of_device_id apq8064_pinctrl_of_match[] = { + { .compatible = "qcom,apq8064-pinctrl", }, + { }, +}; + +static struct platform_driver apq8064_pinctrl_driver = { + .driver = { + .name = "apq8064-pinctrl", + .owner = THIS_MODULE, + .of_match_table = apq8064_pinctrl_of_match, + }, + .probe = apq8064_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init apq8064_pinctrl_init(void) +{ + return platform_driver_register(&apq8064_pinctrl_driver); +} +arch_initcall(apq8064_pinctrl_init); + +static void __exit apq8064_pinctrl_exit(void) +{ + platform_driver_unregister(&apq8064_pinctrl_driver); +} +module_exit(apq8064_pinctrl_exit); + +MODULE_AUTHOR("Bjorn Andersson "); +MODULE_DESCRIPTION("Qualcomm APQ8064 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, apq8064_pinctrl_of_match); diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 5d24aaec5dbcba..84a9594a0caa0e 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -16,9 +16,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -47,7 +44,6 @@ struct at91_gpio_chip { int pioc_idx; /* PIO bank index */ void __iomem *regbase; /* PIO bank virtual address */ struct clk *clock; /* associated clock */ - struct irq_domain *domain; /* associated irq domain */ struct at91_pinctrl_mux_ops *ops; /* ops */ }; @@ -1192,21 +1188,6 @@ static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset, return 0; } -static int at91_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); - int virq; - - if (offset < chip->ngpio) - virq = irq_create_mapping(at91_gpio->domain, offset); - else - virq = -ENXIO; - - dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n", - chip->label, offset + chip->base, virq); - return virq; -} - #ifdef CONFIG_DEBUG_FS static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) { @@ -1216,8 +1197,7 @@ static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) void __iomem *pio = at91_gpio->regbase; for (i = 0; i < chip->ngpio; i++) { - unsigned pin = chip->base + i; - unsigned mask = pin_to_mask(pin); + unsigned mask = pin_to_mask(i); const char *gpio_label; u32 pdsr; @@ -1336,6 +1316,11 @@ static int alt_gpio_irq_type(struct irq_data *d, unsigned type) return 0; } +static void gpio_irq_ack(struct irq_data *d) +{ + /* the interrupt is already cleared before by reading ISR */ +} + static unsigned int gpio_irq_startup(struct irq_data *d) { struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); @@ -1435,6 +1420,7 @@ void at91_pinctrl_gpio_resume(void) static struct irq_chip gpio_irqchip = { .name = "GPIO", + .irq_ack = gpio_irq_ack, .irq_startup = gpio_irq_startup, .irq_shutdown = gpio_irq_shutdown, .irq_disable = gpio_irq_mask, @@ -1446,9 +1432,11 @@ static struct irq_chip gpio_irqchip = { static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_desc_get_chip(desc); - struct irq_data *idata = irq_desc_get_irq_data(desc); - struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata); + struct irq_chip *chip = irq_get_chip(irq); + struct gpio_chip *gpio_chip = irq_desc_get_handler_data(desc); + struct at91_gpio_chip *at91_gpio = container_of(gpio_chip, + struct at91_gpio_chip, chip); + void __iomem *pio = at91_gpio->regbase; unsigned long isr; int n; @@ -1469,81 +1457,19 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) } for_each_set_bit(n, &isr, BITS_PER_LONG) { - generic_handle_irq(irq_find_mapping(at91_gpio->domain, n)); + generic_handle_irq(irq_find_mapping( + gpio_chip->irqdomain, n)); } } chained_irq_exit(chip, desc); /* now it may re-trigger */ } -/* - * This lock class tells lockdep that GPIO irqs are in a different - * category than their parents, so it won't report false recursion. - */ -static struct lock_class_key gpio_lock_class; - -static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - struct at91_gpio_chip *at91_gpio = h->host_data; - void __iomem *pio = at91_gpio->regbase; - u32 mask = 1 << hw; - - irq_set_lockdep_class(virq, &gpio_lock_class); - - /* - * Can use the "simple" and not "edge" handler since it's - * shorter, and the AIC handles interrupts sanely. - */ - irq_set_chip(virq, &gpio_irqchip); - if ((at91_gpio->ops == &at91sam9x5_ops) && - (readl_relaxed(pio + PIO_AIMMR) & mask) && - (readl_relaxed(pio + PIO_ELSR) & mask)) - irq_set_handler(virq, handle_level_irq); - else - irq_set_handler(virq, handle_simple_irq); - set_irq_flags(virq, IRQF_VALID); - irq_set_chip_data(virq, at91_gpio); - - return 0; -} - -static int at91_gpio_irq_domain_xlate(struct irq_domain *d, - struct device_node *ctrlr, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, - unsigned int *out_type) -{ - struct at91_gpio_chip *at91_gpio = d->host_data; - int ret; - int pin = at91_gpio->chip.base + intspec[0]; - - if (WARN_ON(intsize < 2)) - return -EINVAL; - *out_hwirq = intspec[0]; - *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; - - ret = gpio_request(pin, ctrlr->full_name); - if (ret) - return ret; - - ret = gpio_direction_input(pin); - if (ret) - return ret; - - return 0; -} - -static struct irq_domain_ops at91_gpio_ops = { - .map = at91_gpio_irq_map, - .xlate = at91_gpio_irq_domain_xlate, -}; - static int at91_gpio_of_irq_setup(struct device_node *node, struct at91_gpio_chip *at91_gpio) { - struct at91_gpio_chip *prev = NULL; struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq); + int ret; at91_gpio->pioc_hwirq = irqd_to_hwirq(d); @@ -1553,26 +1479,25 @@ static int at91_gpio_of_irq_setup(struct device_node *node, /* Disable irqs of this PIO controller */ writel_relaxed(~0, at91_gpio->regbase + PIO_IDR); - /* Setup irq domain */ - at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio, - &at91_gpio_ops, at91_gpio); - if (!at91_gpio->domain) + /* + * Let the generic code handle this edge IRQ, the the chained + * handler will perform the actual work of handling the parent + * interrupt. + */ + ret = gpiochip_irqchip_add(&at91_gpio->chip, + &gpio_irqchip, + 0, + handle_edge_irq, + IRQ_TYPE_EDGE_BOTH); + if (ret) panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n", at91_gpio->pioc_idx); - /* Setup chained handler */ - if (at91_gpio->pioc_idx) - prev = gpio_chips[at91_gpio->pioc_idx - 1]; - - /* The top level handler handles one bank of GPIOs, except - * on some SoC it can handle up to three... - * We only set up the handler for the first of the list. - */ - if (prev && prev->next == at91_gpio) - return 0; - - irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio); - irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler); + /* Then register the chain on the parent IRQ */ + gpiochip_set_chained_irqchip(&at91_gpio->chip, + &gpio_irqchip, + at91_gpio->pioc_virq, + gpio_irq_handler); return 0; } @@ -1586,7 +1511,6 @@ static struct gpio_chip at91_gpio_template = { .get = at91_gpio_get, .direction_output = at91_gpio_direction_output, .set = at91_gpio_set, - .to_irq = at91_gpio_to_irq, .dbg_show = at91_gpio_dbg_show, .can_sleep = false, .ngpio = MAX_NB_GPIO_PER_BANK, diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 07c81306f2f3bd..9609c23834cef2 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -718,6 +718,73 @@ struct samsung_pin_ctrl s5pv210_pin_ctrl[] = { }, }; +/* pin banks of exynos3250 pin-controller 0 */ +static struct samsung_pin_bank exynos3250_pin_banks0[] = { + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), + EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), + EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08), + EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c), + EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10), + EXYNOS_PIN_BANK_EINTG(4, 0x0a0, "gpd0", 0x14), + EXYNOS_PIN_BANK_EINTG(4, 0x0c0, "gpd1", 0x18), +}; + +/* pin banks of exynos3250 pin-controller 1 */ +static struct samsung_pin_bank exynos3250_pin_banks1[] = { + EXYNOS_PIN_BANK_EINTN(8, 0x120, "gpe0"), + EXYNOS_PIN_BANK_EINTN(8, 0x140, "gpe1"), + EXYNOS_PIN_BANK_EINTN(3, 0x180, "gpe2"), + EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpk0", 0x08), + EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c), + EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10), + EXYNOS_PIN_BANK_EINTG(4, 0x0c0, "gpl0", 0x18), + EXYNOS_PIN_BANK_EINTG(8, 0x260, "gpm0", 0x24), + EXYNOS_PIN_BANK_EINTG(7, 0x280, "gpm1", 0x28), + EXYNOS_PIN_BANK_EINTG(5, 0x2a0, "gpm2", 0x2c), + EXYNOS_PIN_BANK_EINTG(8, 0x2c0, "gpm3", 0x30), + EXYNOS_PIN_BANK_EINTG(8, 0x2e0, "gpm4", 0x34), + EXYNOS_PIN_BANK_EINTW(8, 0xc00, "gpx0", 0x00), + EXYNOS_PIN_BANK_EINTW(8, 0xc20, "gpx1", 0x04), + EXYNOS_PIN_BANK_EINTW(8, 0xc40, "gpx2", 0x08), + EXYNOS_PIN_BANK_EINTW(8, 0xc60, "gpx3", 0x0c), +}; + +/* + * Samsung pinctrl driver data for Exynos3250 SoC. Exynos3250 SoC includes + * two gpio/pin-mux/pinconfig controllers. + */ +struct samsung_pin_ctrl exynos3250_pin_ctrl[] = { + { + /* pin-controller instance 0 data */ + .pin_banks = exynos3250_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos3250_pin_banks0), + .geint_con = EXYNOS_GPIO_ECON_OFFSET, + .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, + .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, + .svc = EXYNOS_SVC_OFFSET, + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + .label = "exynos3250-gpio-ctrl0", + }, { + /* pin-controller instance 1 data */ + .pin_banks = exynos3250_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos3250_pin_banks1), + .geint_con = EXYNOS_GPIO_ECON_OFFSET, + .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, + .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, + .weint_con = EXYNOS_WKUP_ECON_OFFSET, + .weint_mask = EXYNOS_WKUP_EMASK_OFFSET, + .weint_pend = EXYNOS_WKUP_EPEND_OFFSET, + .svc = EXYNOS_SVC_OFFSET, + .eint_gpio_init = exynos_eint_gpio_init, + .eint_wkup_init = exynos_eint_wkup_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + .label = "exynos3250-gpio-ctrl1", + }, +}; + /* pin banks of exynos4210 pin-controller 0 */ static struct samsung_pin_bank exynos4210_pin_banks0[] = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c index e118fb121e0247..a24448e5d3996e 100644 --- a/drivers/pinctrl/pinctrl-imx.c +++ b/drivers/pinctrl/pinctrl-imx.c @@ -491,7 +491,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np, pin->mux_mode |= IOMUXC_CONFIG_SION; pin->config = config & ~IMX_PAD_SION; - dev_dbg(info->dev, "%s: %d 0x%08lx", info->pins[pin_id].name, + dev_dbg(info->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name, pin->mux_mode, pin->config); } diff --git a/drivers/pinctrl/pinctrl-ipq8064.c b/drivers/pinctrl/pinctrl-ipq8064.c new file mode 100644 index 00000000000000..1700b498aea7d8 --- /dev/null +++ b/drivers/pinctrl/pinctrl-ipq8064.c @@ -0,0 +1,653 @@ +/* + * Copyright (c) 2014, The Linux Foundation. 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 version 2 and + * only 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. + * + */ + +#include +#include +#include +#include + +#include "pinctrl-msm.h" + +static const struct pinctrl_pin_desc ipq8064_pins[] = { + PINCTRL_PIN(0, "GPIO_1"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + + PINCTRL_PIN(69, "SDC3_CLK"), + PINCTRL_PIN(70, "SDC3_CMD"), + PINCTRL_PIN(71, "SDC3_DATA"), +}; + +#define DECLARE_IPQ_GPIO_PINS(pin) static const unsigned int gpio##pin##_pins[] = { pin } +DECLARE_IPQ_GPIO_PINS(0); +DECLARE_IPQ_GPIO_PINS(1); +DECLARE_IPQ_GPIO_PINS(2); +DECLARE_IPQ_GPIO_PINS(3); +DECLARE_IPQ_GPIO_PINS(4); +DECLARE_IPQ_GPIO_PINS(5); +DECLARE_IPQ_GPIO_PINS(6); +DECLARE_IPQ_GPIO_PINS(7); +DECLARE_IPQ_GPIO_PINS(8); +DECLARE_IPQ_GPIO_PINS(9); +DECLARE_IPQ_GPIO_PINS(10); +DECLARE_IPQ_GPIO_PINS(11); +DECLARE_IPQ_GPIO_PINS(12); +DECLARE_IPQ_GPIO_PINS(13); +DECLARE_IPQ_GPIO_PINS(14); +DECLARE_IPQ_GPIO_PINS(15); +DECLARE_IPQ_GPIO_PINS(16); +DECLARE_IPQ_GPIO_PINS(17); +DECLARE_IPQ_GPIO_PINS(18); +DECLARE_IPQ_GPIO_PINS(19); +DECLARE_IPQ_GPIO_PINS(20); +DECLARE_IPQ_GPIO_PINS(21); +DECLARE_IPQ_GPIO_PINS(22); +DECLARE_IPQ_GPIO_PINS(23); +DECLARE_IPQ_GPIO_PINS(24); +DECLARE_IPQ_GPIO_PINS(25); +DECLARE_IPQ_GPIO_PINS(26); +DECLARE_IPQ_GPIO_PINS(27); +DECLARE_IPQ_GPIO_PINS(28); +DECLARE_IPQ_GPIO_PINS(29); +DECLARE_IPQ_GPIO_PINS(30); +DECLARE_IPQ_GPIO_PINS(31); +DECLARE_IPQ_GPIO_PINS(32); +DECLARE_IPQ_GPIO_PINS(33); +DECLARE_IPQ_GPIO_PINS(34); +DECLARE_IPQ_GPIO_PINS(35); +DECLARE_IPQ_GPIO_PINS(36); +DECLARE_IPQ_GPIO_PINS(37); +DECLARE_IPQ_GPIO_PINS(38); +DECLARE_IPQ_GPIO_PINS(39); +DECLARE_IPQ_GPIO_PINS(40); +DECLARE_IPQ_GPIO_PINS(41); +DECLARE_IPQ_GPIO_PINS(42); +DECLARE_IPQ_GPIO_PINS(43); +DECLARE_IPQ_GPIO_PINS(44); +DECLARE_IPQ_GPIO_PINS(45); +DECLARE_IPQ_GPIO_PINS(46); +DECLARE_IPQ_GPIO_PINS(47); +DECLARE_IPQ_GPIO_PINS(48); +DECLARE_IPQ_GPIO_PINS(49); +DECLARE_IPQ_GPIO_PINS(50); +DECLARE_IPQ_GPIO_PINS(51); +DECLARE_IPQ_GPIO_PINS(52); +DECLARE_IPQ_GPIO_PINS(53); +DECLARE_IPQ_GPIO_PINS(54); +DECLARE_IPQ_GPIO_PINS(55); +DECLARE_IPQ_GPIO_PINS(56); +DECLARE_IPQ_GPIO_PINS(57); +DECLARE_IPQ_GPIO_PINS(58); +DECLARE_IPQ_GPIO_PINS(59); +DECLARE_IPQ_GPIO_PINS(60); +DECLARE_IPQ_GPIO_PINS(61); +DECLARE_IPQ_GPIO_PINS(62); +DECLARE_IPQ_GPIO_PINS(63); +DECLARE_IPQ_GPIO_PINS(64); +DECLARE_IPQ_GPIO_PINS(65); +DECLARE_IPQ_GPIO_PINS(66); +DECLARE_IPQ_GPIO_PINS(67); +DECLARE_IPQ_GPIO_PINS(68); + +static const unsigned int sdc3_clk_pins[] = { 69 }; +static const unsigned int sdc3_cmd_pins[] = { 70 }; +static const unsigned int sdc3_data_pins[] = { 71 }; + +#define FUNCTION(fname) \ + [IPQ_MUX_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10) \ + { \ + .name = "gpio" #id, \ + .pins = gpio##id##_pins, \ + .npins = ARRAY_SIZE(gpio##id##_pins), \ + .funcs = (int[]){ \ + IPQ_MUX_NA, /* gpio mode */ \ + IPQ_MUX_##f1, \ + IPQ_MUX_##f2, \ + IPQ_MUX_##f3, \ + IPQ_MUX_##f4, \ + IPQ_MUX_##f5, \ + IPQ_MUX_##f6, \ + IPQ_MUX_##f7, \ + IPQ_MUX_##f8, \ + IPQ_MUX_##f9, \ + IPQ_MUX_##f10, \ + }, \ + .nfuncs = 11, \ + .ctl_reg = 0x1000 + 0x10 * id, \ + .io_reg = 0x1004 + 0x10 * id, \ + .intr_cfg_reg = 0x1008 + 0x10 * id, \ + .intr_status_reg = 0x100c + 0x10 * id, \ + .intr_target_reg = 0x400 + 0x4 * id, \ + .mux_bit = 2, \ + .pull_bit = 0, \ + .drv_bit = 6, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_ack_high = 1, \ + .intr_target_bit = 0, \ + .intr_raw_status_bit = 3, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 1, \ + } + +#define SDC_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +enum ipq8064_functions { + IPQ_MUX_mdio, + IPQ_MUX_mi2s, + IPQ_MUX_pdm, + IPQ_MUX_ssbi, + IPQ_MUX_spmi, + IPQ_MUX_audio_pcm, + IPQ_MUX_gsbi1, + IPQ_MUX_gsbi2, + IPQ_MUX_gsbi4, + IPQ_MUX_gsbi5, + IPQ_MUX_gsbi5_spi_cs1, + IPQ_MUX_gsbi5_spi_cs2, + IPQ_MUX_gsbi5_spi_cs3, + IPQ_MUX_gsbi6, + IPQ_MUX_gsbi7, + IPQ_MUX_nss_spi, + IPQ_MUX_sdc1, + IPQ_MUX_spdif, + IPQ_MUX_nand, + IPQ_MUX_tsif1, + IPQ_MUX_tsif2, + IPQ_MUX_usb_fs_n, + IPQ_MUX_usb_fs, + IPQ_MUX_usb2_hsic, + IPQ_MUX_rgmii2, + IPQ_MUX_sata, + IPQ_MUX_pcie1_rst, + IPQ_MUX_pcie1_prsnt, + IPQ_MUX_pcie1_pwrflt, + IPQ_MUX_pcie1_pwren_n, + IPQ_MUX_pcie1_pwren, + IPQ_MUX_pcie1_clk_req, + IPQ_MUX_pcie2_rst, + IPQ_MUX_pcie2_prsnt, + IPQ_MUX_pcie2_pwrflt, + IPQ_MUX_pcie2_pwren_n, + IPQ_MUX_pcie2_pwren, + IPQ_MUX_pcie2_clk_req, + IPQ_MUX_pcie3_rst, + IPQ_MUX_pcie3_prsnt, + IPQ_MUX_pcie3_pwrflt, + IPQ_MUX_pcie3_pwren_n, + IPQ_MUX_pcie3_pwren, + IPQ_MUX_pcie3_clk_req, + IPQ_MUX_ps_hold, + IPQ_MUX_NA, +}; + +static const char * const mdio_groups[] = { + "gpio0", "gpio1", "gpio10", "gpio11", +}; + +static const char * const mi2s_groups[] = { + "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", + "gpio33", "gpio55", "gpio56", "gpio57", "gpio58", +}; + +static const char * const pdm_groups[] = { + "gpio3", "gpio16", "gpio17", "gpio22", "gpio30", "gpio31", + "gpio34", "gpio35", "gpio52", "gpio55", "gpio56", "gpio58", + "gpio59", +}; + +static const char * const ssbi_groups[] = { + "gpio10", "gpio11", +}; + +static const char * const spmi_groups[] = { + "gpio10", "gpio11", +}; + +static const char * const audio_pcm_groups[] = { + "gpio14", "gpio15", "gpio16", "gpio17", +}; + +static const char * const gsbi1_groups[] = { + "gpio51", "gpio52", "gpio53", "gpio54", +}; + +static const char * const gsbi2_groups[] = { + "gpio22", "gpio23", "gpio24", "gpio25", +}; + +static const char * const gsbi4_groups[] = { + "gpio10", "gpio11", "gpio12", "gpio13", +}; + +static const char * const gsbi5_groups[] = { + "gpio18", "gpio19", "gpio20", "gpio21", +}; + +static const char * const gsbi5_spi_cs1_groups[] = { + "gpio6", "gpio61", +}; + +static const char * const gsbi5_spi_cs2_groups[] = { + "gpio7", "gpio62", +}; + +static const char * const gsbi5_spi_cs3_groups[] = { + "gpio2", +}; + +static const char * const gsbi6_groups[] = { + "gpio27", "gpio28", "gpio29", "gpio30", "gpio55", "gpio56", + "gpio57", "gpio58", +}; + +static const char * const gsbi7_groups[] = { + "gpio6", "gpio7", "gpio8", "gpio9", +}; + +static const char * const nss_spi_groups[] = { + "gpio14", "gpio15", "gpio16", "gpio17", "gpio55", "gpio56", + "gpio57", "gpio58", +}; + +static const char * const sdc1_groups[] = { + "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43", + "gpio44", "gpio45", "gpio46", "gpio47", +}; + +static const char * const spdif_groups[] = { + "gpio_10", "gpio_48", +}; + +static const char * const nand_groups[] = { + "gpio34", "gpio35", "gpio36", "gpio37", "gpio38", "gpio39", + "gpio40", "gpio41", "gpio42", "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47", +}; + +static const char * const tsif1_groups[] = { + "gpio55", "gpio56", "gpio57", "gpio58", +}; + +static const char * const tsif2_groups[] = { + "gpio59", "gpio60", "gpio61", "gpio62", +}; + +static const char * const usb_fs_n_groups[] = { + "gpio6", +}; + +static const char * const usb_fs_groups[] = { + "gpio6", "gpio7", "gpio8", +}; + +static const char * const usb2_hsic_groups[] = { + "gpio67", "gpio68", +}; + +static const char * const rgmii2_groups[] = { + "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", + "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62", +}; + +static const char * const sata_groups[] = { + "gpio10", +}; + +static const char * const pcie1_rst_groups[] = { + "gpio3", +}; + +static const char * const pcie1_prsnt_groups[] = { + "gpio3", "gpio11", +}; + +static const char * const pcie1_pwren_n_groups[] = { + "gpio4", "gpio12", +}; + +static const char * const pcie1_pwren_groups[] = { + "gpio4", "gpio12", +}; + +static const char * const pcie1_pwrflt_groups[] = { + "gpio5", "gpio13", +}; + +static const char * const pcie1_clk_req_groups[] = { + "gpio5", +}; + +static const char * const pcie2_rst_groups[] = { + "gpio48", +}; + +static const char * const pcie2_prsnt_groups[] = { + "gpio11", "gpio48", +}; + +static const char * const pcie2_pwren_n_groups[] = { + "gpio12", "gpio49", +}; + +static const char * const pcie2_pwren_groups[] = { + "gpio12", "gpio49", +}; + +static const char * const pcie2_pwrflt_groups[] = { + "gpio13", "gpio50", +}; + +static const char * const pcie2_clk_req_groups[] = { + "gpio50", +}; + +static const char * const pcie3_rst_groups[] = { + "gpio63", +}; + +static const char * const pcie3_prsnt_groups[] = { + "gpio11", +}; + +static const char * const pcie3_pwren_n_groups[] = { + "gpio12", +}; + +static const char * const pcie3_pwren_groups[] = { + "gpio12", +}; + +static const char * const pcie3_pwrflt_groups[] = { + "gpio13", +}; + +static const char * const pcie3_clk_req_groups[] = { + "gpio65", +}; + +static const char * const ps_hold_groups[] = { + "gpio26", +}; + +static const struct msm_function ipq8064_functions[] = { + FUNCTION(mdio), + FUNCTION(ssbi), + FUNCTION(spmi), + FUNCTION(mi2s), + FUNCTION(pdm), + FUNCTION(audio_pcm), + FUNCTION(gsbi1), + FUNCTION(gsbi2), + FUNCTION(gsbi4), + FUNCTION(gsbi5), + FUNCTION(gsbi5_spi_cs1), + FUNCTION(gsbi5_spi_cs2), + FUNCTION(gsbi5_spi_cs3), + FUNCTION(gsbi6), + FUNCTION(gsbi7), + FUNCTION(nss_spi), + FUNCTION(sdc1), + FUNCTION(spdif), + FUNCTION(nand), + FUNCTION(tsif1), + FUNCTION(tsif2), + FUNCTION(usb_fs_n), + FUNCTION(usb_fs), + FUNCTION(usb2_hsic), + FUNCTION(rgmii2), + FUNCTION(sata), + FUNCTION(pcie1_rst), + FUNCTION(pcie1_prsnt), + FUNCTION(pcie1_pwren_n), + FUNCTION(pcie1_pwren), + FUNCTION(pcie1_pwrflt), + FUNCTION(pcie1_clk_req), + FUNCTION(pcie2_rst), + FUNCTION(pcie2_prsnt), + FUNCTION(pcie2_pwren_n), + FUNCTION(pcie2_pwren), + FUNCTION(pcie2_pwrflt), + FUNCTION(pcie2_clk_req), + FUNCTION(pcie3_rst), + FUNCTION(pcie3_prsnt), + FUNCTION(pcie3_pwren_n), + FUNCTION(pcie3_pwren), + FUNCTION(pcie3_pwrflt), + FUNCTION(pcie3_clk_req), + FUNCTION(ps_hold), +}; + +static const struct msm_pingroup ipq8064_groups[] = { + PINGROUP(0, mdio, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(1, mdio, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(2, gsbi5_spi_cs3, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(3, pcie1_rst, pcie1_prsnt, pdm, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(4, pcie1_pwren_n, pcie1_pwren, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(5, pcie1_clk_req, pcie1_pwrflt, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(6, gsbi7, usb_fs, gsbi5_spi_cs1, usb_fs_n, NA, NA, NA, NA, NA, NA), + PINGROUP(7, gsbi7, usb_fs, gsbi5_spi_cs2, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(8, gsbi7, usb_fs, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(9, gsbi7, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(10, gsbi4, spdif, sata, ssbi, mdio, spmi, NA, NA, NA, NA), + PINGROUP(11, gsbi4, pcie2_prsnt, pcie1_prsnt, pcie3_prsnt, ssbi, mdio, spmi, NA, NA, NA), + PINGROUP(12, gsbi4, pcie2_pwren_n, pcie1_pwren_n, pcie3_pwren_n, pcie2_pwren, pcie1_pwren, pcie3_pwren, NA, NA, NA), + PINGROUP(13, gsbi4, pcie2_pwrflt, pcie1_pwrflt, pcie3_pwrflt, NA, NA, NA, NA, NA, NA), + PINGROUP(14, audio_pcm, nss_spi, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(15, audio_pcm, nss_spi, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(16, audio_pcm, nss_spi, pdm, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(17, audio_pcm, nss_spi, pdm, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(18, gsbi5, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(19, gsbi5, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(20, gsbi5, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(21, gsbi5, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(22, gsbi2, pdm, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(23, gsbi2, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(24, gsbi2, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(25, gsbi2, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(26, ps_hold, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(27, mi2s, rgmii2, gsbi6, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(28, mi2s, rgmii2, gsbi6, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(29, mi2s, rgmii2, gsbi6, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(30, mi2s, rgmii2, gsbi6, pdm, NA, NA, NA, NA, NA, NA), + PINGROUP(31, mi2s, rgmii2, pdm, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(32, mi2s, rgmii2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(33, mi2s, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(34, nand, pdm, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(35, nand, pdm, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(36, nand, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(37, nand, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(38, nand, sdc1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(39, nand, sdc1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(40, nand, sdc1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(41, nand, sdc1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(42, nand, sdc1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(43, nand, sdc1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(44, nand, sdc1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(45, nand, sdc1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(46, nand, sdc1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(47, nand, sdc1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(48, pcie2_rst, spdif, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(49, pcie2_pwren_n, pcie2_pwren, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(50, pcie2_clk_req, pcie2_pwrflt, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(51, gsbi1, rgmii2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(52, gsbi1, rgmii2, pdm, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(53, gsbi1, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(54, gsbi1, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(55, tsif1, mi2s, gsbi6, pdm, nss_spi, NA, NA, NA, NA, NA), + PINGROUP(56, tsif1, mi2s, gsbi6, pdm, nss_spi, NA, NA, NA, NA, NA), + PINGROUP(57, tsif1, mi2s, gsbi6, nss_spi, NA, NA, NA, NA, NA, NA), + PINGROUP(58, tsif1, mi2s, gsbi6, pdm, nss_spi, NA, NA, NA, NA, NA), + PINGROUP(59, tsif2, rgmii2, pdm, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(60, tsif2, rgmii2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(61, tsif2, rgmii2, gsbi5_spi_cs1, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(62, tsif2, rgmii2, gsbi5_spi_cs2, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(63, pcie3_rst, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(65, pcie3_clk_req, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(66, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(67, usb2_hsic, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(68, usb2_hsic, NA, NA, NA, NA, NA, NA, NA, NA, NA), + SDC_PINGROUP(sdc3_clk, 0x204a, 14, 6), + SDC_PINGROUP(sdc3_cmd, 0x204a, 11, 3), + SDC_PINGROUP(sdc3_data, 0x204a, 9, 0), +}; + +#define NUM_GPIO_PINGROUPS 69 + +static const struct msm_pinctrl_soc_data ipq8064_pinctrl = { + .pins = ipq8064_pins, + .npins = ARRAY_SIZE(ipq8064_pins), + .functions = ipq8064_functions, + .nfunctions = ARRAY_SIZE(ipq8064_functions), + .groups = ipq8064_groups, + .ngroups = ARRAY_SIZE(ipq8064_groups), + .ngpios = NUM_GPIO_PINGROUPS, +}; + +static int ipq8064_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &ipq8064_pinctrl); +} + +static const struct of_device_id ipq8064_pinctrl_of_match[] = { + { .compatible = "qcom,ipq8064-pinctrl", }, + { }, +}; + +static struct platform_driver ipq8064_pinctrl_driver = { + .driver = { + .name = "ipq8064-pinctrl", + .owner = THIS_MODULE, + .of_match_table = ipq8064_pinctrl_of_match, + }, + .probe = ipq8064_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init ipq8064_pinctrl_init(void) +{ + return platform_driver_register(&ipq8064_pinctrl_driver); +} +arch_initcall(ipq8064_pinctrl_init); + +static void __exit ipq8064_pinctrl_exit(void) +{ + platform_driver_unregister(&ipq8064_pinctrl_driver); +} +module_exit(ipq8064_pinctrl_exit); + +MODULE_AUTHOR("Andy Gross "); +MODULE_DESCRIPTION("Qualcomm IPQ8064 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, ipq8064_pinctrl_of_match); diff --git a/drivers/pinctrl/pinctrl-lantiq.h b/drivers/pinctrl/pinctrl-lantiq.h index 6d07f023853205..c7cfad5527d70a 100644 --- a/drivers/pinctrl/pinctrl-lantiq.h +++ b/drivers/pinctrl/pinctrl-lantiq.h @@ -10,6 +10,7 @@ */ #ifndef __PINCTRL_LANTIQ_H +#define __PINCTRL_LANTIQ_H #include #include diff --git a/drivers/pinctrl/pinctrl-msm.c b/drivers/pinctrl/pinctrl-msm.c index e43fbce56598a6..5fa9341cc5892f 100644 --- a/drivers/pinctrl/pinctrl-msm.c +++ b/drivers/pinctrl/pinctrl-msm.c @@ -145,12 +145,12 @@ static int msm_pinmux_enable(struct pinctrl_dev *pctldev, if (WARN_ON(g->mux_bit < 0)) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(g->funcs); i++) { + for (i = 0; i < g->nfuncs; i++) { if (g->funcs[i] == function) break; } - if (WARN_ON(i == ARRAY_SIZE(g->funcs))) + if (WARN_ON(i == g->nfuncs)) return -EINVAL; spin_lock_irqsave(&pctrl->lock, flags); diff --git a/drivers/pinctrl/pinctrl-msm.h b/drivers/pinctrl/pinctrl-msm.h index 6e26f1b676d75f..7b2a227a590aaf 100644 --- a/drivers/pinctrl/pinctrl-msm.h +++ b/drivers/pinctrl/pinctrl-msm.h @@ -65,7 +65,8 @@ struct msm_pingroup { const unsigned *pins; unsigned npins; - unsigned funcs[8]; + unsigned *funcs; + unsigned nfuncs; s16 ctl_reg; s16 io_reg; diff --git a/drivers/pinctrl/pinctrl-msm8x74.c b/drivers/pinctrl/pinctrl-msm8x74.c index dde5529807aab7..57766d56e257b9 100644 --- a/drivers/pinctrl/pinctrl-msm8x74.c +++ b/drivers/pinctrl/pinctrl-msm8x74.c @@ -341,7 +341,7 @@ static const unsigned int sdc2_data_pins[] = { 151 }; .name = "gpio" #id, \ .pins = gpio##id##_pins, \ .npins = ARRAY_SIZE(gpio##id##_pins), \ - .funcs = { \ + .funcs = (int[]){ \ MSM_MUX_NA, /* gpio mode */ \ MSM_MUX_##f1, \ MSM_MUX_##f2, \ @@ -351,6 +351,7 @@ static const unsigned int sdc2_data_pins[] = { 151 }; MSM_MUX_##f6, \ MSM_MUX_##f7 \ }, \ + .nfuncs = 8, \ .ctl_reg = 0x1000 + 0x10 * id, \ .io_reg = 0x1004 + 0x10 * id, \ .intr_cfg_reg = 0x1008 + 0x10 * id, \ diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 96c60d230c13e1..2e198a41c7bb42 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -329,6 +329,23 @@ static const struct pinctrl_ops rockchip_pctrl_ops = { * Hardware access */ +static int rockchip_get_mux(struct rockchip_pin_bank *bank, int pin) +{ + struct rockchip_pinctrl *info = bank->drvdata; + void __iomem *reg = info->reg_base + info->ctrl->mux_offset; + u8 bit; + + if (bank->bank_type == RK3188_BANK0 && pin < 16) + return RK_FUNC_GPIO; + + /* get basic quadrupel of mux registers and the correct reg inside */ + reg += bank->bank_num * 0x10; + reg += (pin / 8) * 4; + bit = (pin % 8) * 2; + + return ((readl(reg) >> bit) & 3); +} + /* * Set a new mux function for a pin. * @@ -687,6 +704,10 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, return false; } +static int rockchip_gpio_direction_output(struct gpio_chip *gc, + unsigned offset, int value); +static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset); + /* set the pin config settings for a specified pin */ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, unsigned long *configs, unsigned num_configs) @@ -724,6 +745,13 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, if (rc) return rc; break; + case PIN_CONFIG_OUTPUT: + rc = rockchip_gpio_direction_output(&bank->gpio_chip, + pin - bank->pin_base, + arg); + if (rc) + return rc; + break; default: return -ENOTSUPP; break; @@ -740,13 +768,15 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); struct rockchip_pin_bank *bank = pin_to_bank(info, pin); enum pin_config_param param = pinconf_to_config_param(*config); + u16 arg; + int rc; switch (param) { case PIN_CONFIG_BIAS_DISABLE: if (rockchip_get_pull(bank, pin - bank->pin_base) != param) return -EINVAL; - *config = 0; + arg = 0; break; case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN: @@ -758,13 +788,26 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, if (rockchip_get_pull(bank, pin - bank->pin_base) != param) return -EINVAL; - *config = 1; + arg = 1; + break; + case PIN_CONFIG_OUTPUT: + rc = rockchip_get_mux(bank, pin - bank->pin_base); + if (rc != RK_FUNC_GPIO) + return -EINVAL; + + rc = rockchip_gpio_get(&bank->gpio_chip, pin - bank->pin_base); + if (rc < 0) + return rc; + + arg = rc ? 1 : 0; break; default: return -ENOTSUPP; break; } + *config = pinconf_to_config_packed(param, arg); + return 0; } diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 0324d4cb19b22d..3e61d0f8f146fb 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -1114,6 +1114,8 @@ static struct syscore_ops samsung_pinctrl_syscore_ops = { static const struct of_device_id samsung_pinctrl_dt_match[] = { #ifdef CONFIG_PINCTRL_EXYNOS + { .compatible = "samsung,exynos3250-pinctrl", + .data = (void *)exynos3250_pin_ctrl }, { .compatible = "samsung,exynos4210-pinctrl", .data = (void *)exynos4210_pin_ctrl }, { .compatible = "samsung,exynos4x12-pinctrl", diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index bab9c21225562f..b3e41fa5798b41 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -251,6 +251,7 @@ struct samsung_pmx_func { }; /* list of all exported SoC specific data */ +extern struct samsung_pin_ctrl exynos3250_pin_ctrl[]; extern struct samsung_pin_ctrl exynos4210_pin_ctrl[]; extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[]; extern struct samsung_pin_ctrl exynos5250_pin_ctrl[]; diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c index bd725b0a43414b..1bd6363bc95ef2 100644 --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@ -13,10 +13,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -242,13 +238,13 @@ struct st_pio_control { }; struct st_pctl_data { - enum st_retime_style rt_style; - unsigned int *input_delays; - int ninput_delays; - unsigned int *output_delays; - int noutput_delays; + const enum st_retime_style rt_style; + const unsigned int *input_delays; + const int ninput_delays; + const unsigned int *output_delays; + const int noutput_delays; /* register offset information */ - int alt, oe, pu, od, rt; + const int alt, oe, pu, od, rt; }; struct st_pinconf { @@ -321,7 +317,6 @@ struct st_gpio_bank { struct pinctrl_gpio_range range; void __iomem *base; struct st_pio_control pc; - struct irq_domain *domain; unsigned long irq_edge_conf; spinlock_t lock; }; @@ -342,15 +337,15 @@ struct st_pinctrl { /* SOC specific data */ /* STiH415 data */ -static unsigned int stih415_input_delays[] = {0, 500, 1000, 1500}; -static unsigned int stih415_output_delays[] = {0, 1000, 2000, 3000}; +static const unsigned int stih415_input_delays[] = {0, 500, 1000, 1500}; +static const unsigned int stih415_output_delays[] = {0, 1000, 2000, 3000}; #define STIH415_PCTRL_COMMON_DATA \ .rt_style = st_retime_style_packed, \ .input_delays = stih415_input_delays, \ - .ninput_delays = 4, \ + .ninput_delays = ARRAY_SIZE(stih415_input_delays), \ .output_delays = stih415_output_delays, \ - .noutput_delays = 4 + .noutput_delays = ARRAY_SIZE(stih415_output_delays) static const struct st_pctl_data stih415_sbc_data = { STIH415_PCTRL_COMMON_DATA, @@ -378,8 +373,8 @@ static const struct st_pctl_data stih415_right_data = { }; /* STiH416 data */ -static unsigned int stih416_delays[] = {0, 300, 500, 750, 1000, 1250, 1500, - 1750, 2000, 2250, 2500, 2750, 3000, 3250 }; +static const unsigned int stih416_delays[] = {0, 300, 500, 750, 1000, 1250, + 1500, 1750, 2000, 2250, 2500, 2750, 3000, 3250 }; static const struct st_pctl_data stih416_data = { .rt_style = st_retime_style_dedicated, @@ -468,7 +463,7 @@ static void st_pctl_set_function(struct st_pio_control *pc, static unsigned long st_pinconf_delay_to_bit(unsigned int delay, const struct st_pctl_data *data, unsigned long config) { - unsigned int *delay_times; + const unsigned int *delay_times; int num_delay_times, i, closest_index = -1; unsigned int closest_divergence = UINT_MAX; @@ -501,7 +496,7 @@ static unsigned long st_pinconf_delay_to_bit(unsigned int delay, static unsigned long st_pinconf_bit_to_delay(unsigned int index, const struct st_pctl_data *data, unsigned long output) { - unsigned int *delay_times; + const unsigned int *delay_times; int num_delay_times; if (output) { @@ -1285,58 +1280,26 @@ static int st_pctl_parse_functions(struct device_node *np, return 0; } -static int st_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct st_gpio_bank *bank = gpio_chip_to_bank(chip); - int irq = -ENXIO; - - if (offset < chip->ngpio) - irq = irq_find_mapping(bank->domain, offset); - - dev_info(chip->dev, "%s: request IRQ for GPIO %d, return %d\n", - chip->label, offset + chip->base, irq); - return irq; -} - static void st_gpio_irq_mask(struct irq_data *d) { - struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct st_gpio_bank *bank = gpio_chip_to_bank(gc); writel(BIT(d->hwirq), bank->base + REG_PIO_CLR_PMASK); } static void st_gpio_irq_unmask(struct irq_data *d) { - struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct st_gpio_bank *bank = gpio_chip_to_bank(gc); writel(BIT(d->hwirq), bank->base + REG_PIO_SET_PMASK); } -static unsigned int st_gpio_irq_startup(struct irq_data *d) -{ - struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d); - - if (gpio_lock_as_irq(&bank->gpio_chip, d->hwirq)) - dev_err(bank->gpio_chip.dev, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); - - st_gpio_irq_unmask(d); - - return 0; -} - -static void st_gpio_irq_shutdown(struct irq_data *d) -{ - struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d); - - st_gpio_irq_mask(d); - gpio_unlock_as_irq(&bank->gpio_chip, d->hwirq); -} - static int st_gpio_irq_set_type(struct irq_data *d, unsigned type) { - struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct st_gpio_bank *bank = gpio_chip_to_bank(gc); unsigned long flags; int comp, pin = d->hwirq; u32 val; @@ -1440,7 +1403,7 @@ static void __gpio_irq_handler(struct st_gpio_bank *bank) continue; } - generic_handle_irq(irq_find_mapping(bank->domain, n)); + generic_handle_irq(irq_find_mapping(bank->gpio_chip.irqdomain, n)); } } } @@ -1449,7 +1412,8 @@ static void st_gpio_irq_handler(unsigned irq, struct irq_desc *desc) { /* interrupt dedicated per bank */ struct irq_chip *chip = irq_get_chip(irq); - struct st_gpio_bank *bank = irq_get_handler_data(irq); + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct st_gpio_bank *bank = gpio_chip_to_bank(gc); chained_irq_enter(chip, desc); __gpio_irq_handler(bank); @@ -1483,7 +1447,6 @@ static struct gpio_chip st_gpio_template = { .ngpio = ST_GPIO_PINS_PER_BANK, .of_gpio_n_cells = 1, .of_xlate = st_gpio_xlate, - .to_irq = st_gpio_to_irq, }; static struct irq_chip st_gpio_irqchip = { @@ -1491,26 +1454,6 @@ static struct irq_chip st_gpio_irqchip = { .irq_mask = st_gpio_irq_mask, .irq_unmask = st_gpio_irq_unmask, .irq_set_type = st_gpio_irq_set_type, - .irq_startup = st_gpio_irq_startup, - .irq_shutdown = st_gpio_irq_shutdown, -}; - -static int st_gpio_irq_domain_map(struct irq_domain *h, - unsigned int virq, irq_hw_number_t hw) -{ - struct st_gpio_bank *bank = h->host_data; - - irq_set_chip(virq, &st_gpio_irqchip); - irq_set_handler(virq, handle_simple_irq); - set_irq_flags(virq, IRQF_VALID); - irq_set_chip_data(virq, bank); - - return 0; -} - -static struct irq_domain_ops st_gpio_irq_ops = { - .map = st_gpio_irq_domain_map, - .xlate = irq_domain_xlate_twocell, }; static int st_gpiolib_register_bank(struct st_pinctrl *info, @@ -1521,7 +1464,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info, struct device *dev = info->dev; int bank_num = of_alias_get_id(np, "gpio"); struct resource res, irq_res; - int gpio_irq = 0, err, i; + int gpio_irq = 0, err; if (of_address_to_resource(np, 0, &res)) return -ENODEV; @@ -1534,6 +1477,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info, bank->gpio_chip.base = bank_num * ST_GPIO_PINS_PER_BANK; bank->gpio_chip.ngpio = ST_GPIO_PINS_PER_BANK; bank->gpio_chip.of_node = np; + bank->gpio_chip.dev = dev; spin_lock_init(&bank->lock); of_property_read_string(np, "st,bank-name", &range->name); @@ -1571,26 +1515,18 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info, if (of_irq_to_resource(np, 0, &irq_res)) { gpio_irq = irq_res.start; - irq_set_chained_handler(gpio_irq, st_gpio_irq_handler); - irq_set_handler_data(gpio_irq, bank); + gpiochip_set_chained_irqchip(&bank->gpio_chip, &st_gpio_irqchip, + gpio_irq, st_gpio_irq_handler); } if (info->irqmux_base > 0 || gpio_irq > 0) { - /* Setup IRQ domain */ - bank->domain = irq_domain_add_linear(np, - ST_GPIO_PINS_PER_BANK, - &st_gpio_irq_ops, bank); - if (!bank->domain) { - dev_err(dev, "Failed to add irq domain for %s\n", - np->full_name); - } else { - for (i = 0; i < ST_GPIO_PINS_PER_BANK; i++) { - if (irq_create_mapping(bank->domain, i) < 0) - dev_err(dev, - "Failed to map IRQ %i\n", i); - } + err = gpiochip_irqchip_add(&bank->gpio_chip, &st_gpio_irqchip, + 0, handle_simple_irq, + IRQ_TYPE_LEVEL_LOW); + if (err) { + dev_info(dev, "could not add irqchip\n"); + return err; } - } else { dev_info(dev, "No IRQ support for %s bank\n", np->full_name); } diff --git a/drivers/pinctrl/pinctrl-sunxi-pins.h b/drivers/pinctrl/pinctrl-sunxi-pins.h index 3d6066988a7251..51100caf05f934 100644 --- a/drivers/pinctrl/pinctrl-sunxi-pins.h +++ b/drivers/pinctrl/pinctrl-sunxi-pins.h @@ -2820,6 +2820,74 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = { SUNXI_FUNCTION(0x2, "nand1")), /* CE3 */ }; +static const struct sunxi_desc_pin sun6i_a31_r_pins[] = { + SUNXI_PIN(SUNXI_PINCTRL_PIN_PL0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_twi"), /* SCK */ + SUNXI_FUNCTION(0x3, "s_p2wi")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PL1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_twi"), /* SDA */ + SUNXI_FUNCTION(0x3, "s_p2wi")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PL2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_uart")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PL3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_uart")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PL4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "s_ir")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PL5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "s_jtag")), /* MS */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PL6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "s_jtag")), /* CK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PL7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "s_jtag")), /* DO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PL8, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "s_jtag")), /* DI */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PM0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN_PM1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN_PM2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "1wire")), + SUNXI_PIN(SUNXI_PINCTRL_PIN_PM3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN_PM4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN_PM5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN_PM6, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN_PM7, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "rtc")), /* CLKO */ +}; + static const struct sunxi_desc_pin sun7i_a20_pins[] = { SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0, SUNXI_FUNCTION(0x0, "gpio_in"), @@ -3855,6 +3923,12 @@ static const struct sunxi_pinctrl_desc sun6i_a31_pinctrl_data = { .npins = ARRAY_SIZE(sun6i_a31_pins), }; +static const struct sunxi_pinctrl_desc sun6i_a31_r_pinctrl_data = { + .pins = sun6i_a31_r_pins, + .npins = ARRAY_SIZE(sun6i_a31_r_pins), + .pin_base = PL_BASE, +}; + static const struct sunxi_pinctrl_desc sun7i_a20_pinctrl_data = { .pins = sun7i_a20_pins, .npins = ARRAY_SIZE(sun7i_a20_pins), diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c index f9fabe9bf47d43..f086509a28d35c 100644 --- a/drivers/pinctrl/pinctrl-sunxi.c +++ b/drivers/pinctrl/pinctrl-sunxi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "core.h" @@ -538,19 +539,6 @@ static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return irq_find_mapping(pctl->domain, desc->irqnum); } -static struct gpio_chip sunxi_pinctrl_gpio_chip = { - .owner = THIS_MODULE, - .request = sunxi_pinctrl_gpio_request, - .free = sunxi_pinctrl_gpio_free, - .direction_input = sunxi_pinctrl_gpio_direction_input, - .direction_output = sunxi_pinctrl_gpio_direction_output, - .get = sunxi_pinctrl_gpio_get, - .set = sunxi_pinctrl_gpio_set, - .of_xlate = sunxi_pinctrl_gpio_of_xlate, - .to_irq = sunxi_pinctrl_gpio_to_irq, - .of_gpio_n_cells = 3, - .can_sleep = false, -}; static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) @@ -690,6 +678,7 @@ static struct of_device_id sunxi_pinctrl_match[] = { { .compatible = "allwinner,sun5i-a10s-pinctrl", .data = (void *)&sun5i_a10s_pinctrl_data }, { .compatible = "allwinner,sun5i-a13-pinctrl", .data = (void *)&sun5i_a13_pinctrl_data }, { .compatible = "allwinner,sun6i-a31-pinctrl", .data = (void *)&sun6i_a31_pinctrl_data }, + { .compatible = "allwinner,sun6i-a31-r-pinctrl", .data = (void *)&sun6i_a31_r_pinctrl_data }, { .compatible = "allwinner,sun7i-a20-pinctrl", .data = (void *)&sun7i_a20_pinctrl_data }, {} }; @@ -804,6 +793,7 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev) const struct of_device_id *device; struct pinctrl_pin_desc *pins; struct sunxi_pinctrl *pctl; + struct reset_control *rstc; int i, ret, last_pin; struct clk *clk; @@ -858,11 +848,22 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev) } last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number; - pctl->chip = &sunxi_pinctrl_gpio_chip; - pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK); + pctl->chip->owner = THIS_MODULE; + pctl->chip->request = sunxi_pinctrl_gpio_request, + pctl->chip->free = sunxi_pinctrl_gpio_free, + pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input, + pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output, + pctl->chip->get = sunxi_pinctrl_gpio_get, + pctl->chip->set = sunxi_pinctrl_gpio_set, + pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate, + pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq, + pctl->chip->of_gpio_n_cells = 3, + pctl->chip->can_sleep = false, + pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK) - + pctl->desc->pin_base; pctl->chip->label = dev_name(&pdev->dev); pctl->chip->dev = &pdev->dev; - pctl->chip->base = 0; + pctl->chip->base = pctl->desc->pin_base; ret = gpiochip_add(pctl->chip); if (ret) @@ -884,12 +885,21 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev) goto gpiochip_error; } - clk_prepare_enable(clk); + ret = clk_prepare_enable(clk); + if (ret) + goto gpiochip_error; + + rstc = devm_reset_control_get_optional(&pdev->dev, NULL); + if (!IS_ERR(rstc)) { + ret = reset_control_deassert(rstc); + if (ret) + goto clk_error; + } pctl->irq = irq_of_parse_and_map(node, 0); if (!pctl->irq) { ret = -EINVAL; - goto gpiochip_error; + goto rstc_error; } pctl->domain = irq_domain_add_linear(node, SUNXI_IRQ_NUMBER, @@ -897,7 +907,7 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev) if (!pctl->domain) { dev_err(&pdev->dev, "Couldn't register IRQ domain\n"); ret = -ENOMEM; - goto gpiochip_error; + goto rstc_error; } for (i = 0; i < SUNXI_IRQ_NUMBER; i++) { @@ -915,6 +925,11 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev) return 0; +rstc_error: + if (!IS_ERR(rstc)) + reset_control_assert(rstc); +clk_error: + clk_disable_unprepare(clk); gpiochip_error: if (gpiochip_remove(pctl->chip)) dev_err(&pdev->dev, "failed to remove gpio chip\n"); @@ -933,6 +948,6 @@ static struct platform_driver sunxi_pinctrl_driver = { }; module_platform_driver(sunxi_pinctrl_driver); -MODULE_AUTHOR("Maxime Ripard "); MODULE_DESCRIPTION("Allwinner A1X pinctrl driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-sunxi.h b/drivers/pinctrl/pinctrl-sunxi.h index 552b0e97077a85..35d15b229a7075 100644 --- a/drivers/pinctrl/pinctrl-sunxi.h +++ b/drivers/pinctrl/pinctrl-sunxi.h @@ -25,6 +25,8 @@ #define PG_BASE 192 #define PH_BASE 224 #define PI_BASE 256 +#define PL_BASE 352 +#define PM_BASE 384 #define SUNXI_PINCTRL_PIN_PA0 PINCTRL_PIN(PA_BASE + 0, "PA0") #define SUNXI_PINCTRL_PIN_PA1 PINCTRL_PIN(PA_BASE + 1, "PA1") @@ -323,6 +325,72 @@ #define SUNXI_PINCTRL_PIN_PI30 PINCTRL_PIN(PI_BASE + 30, "PI30") #define SUNXI_PINCTRL_PIN_PI31 PINCTRL_PIN(PI_BASE + 31, "PI31") +#define SUNXI_PINCTRL_PIN_PL0 PINCTRL_PIN(PL_BASE + 0, "PL0") +#define SUNXI_PINCTRL_PIN_PL1 PINCTRL_PIN(PL_BASE + 1, "PL1") +#define SUNXI_PINCTRL_PIN_PL2 PINCTRL_PIN(PL_BASE + 2, "PL2") +#define SUNXI_PINCTRL_PIN_PL3 PINCTRL_PIN(PL_BASE + 3, "PL3") +#define SUNXI_PINCTRL_PIN_PL4 PINCTRL_PIN(PL_BASE + 4, "PL4") +#define SUNXI_PINCTRL_PIN_PL5 PINCTRL_PIN(PL_BASE + 5, "PL5") +#define SUNXI_PINCTRL_PIN_PL6 PINCTRL_PIN(PL_BASE + 6, "PL6") +#define SUNXI_PINCTRL_PIN_PL7 PINCTRL_PIN(PL_BASE + 7, "PL7") +#define SUNXI_PINCTRL_PIN_PL8 PINCTRL_PIN(PL_BASE + 8, "PL8") +#define SUNXI_PINCTRL_PIN_PL9 PINCTRL_PIN(PL_BASE + 9, "PL9") +#define SUNXI_PINCTRL_PIN_PL10 PINCTRL_PIN(PL_BASE + 10, "PL10") +#define SUNXI_PINCTRL_PIN_PL11 PINCTRL_PIN(PL_BASE + 11, "PL11") +#define SUNXI_PINCTRL_PIN_PL12 PINCTRL_PIN(PL_BASE + 12, "PL12") +#define SUNXI_PINCTRL_PIN_PL13 PINCTRL_PIN(PL_BASE + 13, "PL13") +#define SUNXI_PINCTRL_PIN_PL14 PINCTRL_PIN(PL_BASE + 14, "PL14") +#define SUNXI_PINCTRL_PIN_PL15 PINCTRL_PIN(PL_BASE + 15, "PL15") +#define SUNXI_PINCTRL_PIN_PL16 PINCTRL_PIN(PL_BASE + 16, "PL16") +#define SUNXI_PINCTRL_PIN_PL17 PINCTRL_PIN(PL_BASE + 17, "PL17") +#define SUNXI_PINCTRL_PIN_PL18 PINCTRL_PIN(PL_BASE + 18, "PL18") +#define SUNXI_PINCTRL_PIN_PL19 PINCTRL_PIN(PL_BASE + 19, "PL19") +#define SUNXI_PINCTRL_PIN_PL20 PINCTRL_PIN(PL_BASE + 20, "PL20") +#define SUNXI_PINCTRL_PIN_PL21 PINCTRL_PIN(PL_BASE + 21, "PL21") +#define SUNXI_PINCTRL_PIN_PL22 PINCTRL_PIN(PL_BASE + 22, "PL22") +#define SUNXI_PINCTRL_PIN_PL23 PINCTRL_PIN(PL_BASE + 23, "PL23") +#define SUNXI_PINCTRL_PIN_PL24 PINCTRL_PIN(PL_BASE + 24, "PL24") +#define SUNXI_PINCTRL_PIN_PL25 PINCTRL_PIN(PL_BASE + 25, "PL25") +#define SUNXI_PINCTRL_PIN_PL26 PINCTRL_PIN(PL_BASE + 26, "PL26") +#define SUNXI_PINCTRL_PIN_PL27 PINCTRL_PIN(PL_BASE + 27, "PL27") +#define SUNXI_PINCTRL_PIN_PL28 PINCTRL_PIN(PL_BASE + 28, "PL28") +#define SUNXI_PINCTRL_PIN_PL29 PINCTRL_PIN(PL_BASE + 29, "PL29") +#define SUNXI_PINCTRL_PIN_PL30 PINCTRL_PIN(PL_BASE + 30, "PL30") +#define SUNXI_PINCTRL_PIN_PL31 PINCTRL_PIN(PL_BASE + 31, "PL31") + +#define SUNXI_PINCTRL_PIN_PM0 PINCTRL_PIN(PM_BASE + 0, "PM0") +#define SUNXI_PINCTRL_PIN_PM1 PINCTRL_PIN(PM_BASE + 1, "PM1") +#define SUNXI_PINCTRL_PIN_PM2 PINCTRL_PIN(PM_BASE + 2, "PM2") +#define SUNXI_PINCTRL_PIN_PM3 PINCTRL_PIN(PM_BASE + 3, "PM3") +#define SUNXI_PINCTRL_PIN_PM4 PINCTRL_PIN(PM_BASE + 4, "PM4") +#define SUNXI_PINCTRL_PIN_PM5 PINCTRL_PIN(PM_BASE + 5, "PM5") +#define SUNXI_PINCTRL_PIN_PM6 PINCTRL_PIN(PM_BASE + 6, "PM6") +#define SUNXI_PINCTRL_PIN_PM7 PINCTRL_PIN(PM_BASE + 7, "PM7") +#define SUNXI_PINCTRL_PIN_PM8 PINCTRL_PIN(PM_BASE + 8, "PM8") +#define SUNXI_PINCTRL_PIN_PM9 PINCTRL_PIN(PM_BASE + 9, "PM9") +#define SUNXI_PINCTRL_PIN_PM10 PINCTRL_PIN(PM_BASE + 10, "PM10") +#define SUNXI_PINCTRL_PIN_PM11 PINCTRL_PIN(PM_BASE + 11, "PM11") +#define SUNXI_PINCTRL_PIN_PM12 PINCTRL_PIN(PM_BASE + 12, "PM12") +#define SUNXI_PINCTRL_PIN_PM13 PINCTRL_PIN(PM_BASE + 13, "PM13") +#define SUNXI_PINCTRL_PIN_PM14 PINCTRL_PIN(PM_BASE + 14, "PM14") +#define SUNXI_PINCTRL_PIN_PM15 PINCTRL_PIN(PM_BASE + 15, "PM15") +#define SUNXI_PINCTRL_PIN_PM16 PINCTRL_PIN(PM_BASE + 16, "PM16") +#define SUNXI_PINCTRL_PIN_PM17 PINCTRL_PIN(PM_BASE + 17, "PM17") +#define SUNXI_PINCTRL_PIN_PM18 PINCTRL_PIN(PM_BASE + 18, "PM18") +#define SUNXI_PINCTRL_PIN_PM19 PINCTRL_PIN(PM_BASE + 19, "PM19") +#define SUNXI_PINCTRL_PIN_PM20 PINCTRL_PIN(PM_BASE + 20, "PM20") +#define SUNXI_PINCTRL_PIN_PM21 PINCTRL_PIN(PM_BASE + 21, "PM21") +#define SUNXI_PINCTRL_PIN_PM22 PINCTRL_PIN(PM_BASE + 22, "PM22") +#define SUNXI_PINCTRL_PIN_PM23 PINCTRL_PIN(PM_BASE + 23, "PM23") +#define SUNXI_PINCTRL_PIN_PM24 PINCTRL_PIN(PM_BASE + 24, "PM24") +#define SUNXI_PINCTRL_PIN_PM25 PINCTRL_PIN(PM_BASE + 25, "PM25") +#define SUNXI_PINCTRL_PIN_PM26 PINCTRL_PIN(PM_BASE + 26, "PM26") +#define SUNXI_PINCTRL_PIN_PM27 PINCTRL_PIN(PM_BASE + 27, "PM27") +#define SUNXI_PINCTRL_PIN_PM28 PINCTRL_PIN(PM_BASE + 28, "PM28") +#define SUNXI_PINCTRL_PIN_PM29 PINCTRL_PIN(PM_BASE + 29, "PM29") +#define SUNXI_PINCTRL_PIN_PM30 PINCTRL_PIN(PM_BASE + 30, "PM30") +#define SUNXI_PINCTRL_PIN_PM31 PINCTRL_PIN(PM_BASE + 31, "PM31") + #define SUNXI_PIN_NAME_MAX_LEN 5 #define BANK_MEM_SIZE 0x24 @@ -382,6 +450,7 @@ struct sunxi_pinctrl_desc { int npins; struct pinctrl_gpio_range *ranges; int nranges; + unsigned pin_base; }; struct sunxi_pinctrl_function { diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c index 65458096f41e2e..2d43bff74f59bd 100644 --- a/drivers/pinctrl/pinctrl-tegra.c +++ b/drivers/pinctrl/pinctrl-tegra.c @@ -295,17 +295,11 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); const struct tegra_pingroup *g; - u32 val; g = &pmx->soc->groups[group]; if (WARN_ON(g->mux_reg < 0)) return; - - val = pmx_readl(pmx, g->mux_bank, g->mux_reg); - val &= ~(0x3 << g->mux_bit); - val |= g->func_safe << g->mux_bit; - pmx_writel(pmx, val, g->mux_bank, g->mux_reg); } static const struct pinmux_ops tegra_pinmux_ops = { @@ -336,32 +330,32 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx, *width = 1; break; case TEGRA_PINCONF_PARAM_ENABLE_INPUT: - *bank = g->einput_bank; - *reg = g->einput_reg; + *bank = g->mux_bank; + *reg = g->mux_reg; *bit = g->einput_bit; *width = 1; break; case TEGRA_PINCONF_PARAM_OPEN_DRAIN: - *bank = g->odrain_bank; - *reg = g->odrain_reg; + *bank = g->mux_bank; + *reg = g->mux_reg; *bit = g->odrain_bit; *width = 1; break; case TEGRA_PINCONF_PARAM_LOCK: - *bank = g->lock_bank; - *reg = g->lock_reg; + *bank = g->mux_bank; + *reg = g->mux_reg; *bit = g->lock_bit; *width = 1; break; case TEGRA_PINCONF_PARAM_IORESET: - *bank = g->ioreset_bank; - *reg = g->ioreset_reg; + *bank = g->mux_bank; + *reg = g->mux_reg; *bit = g->ioreset_bit; *width = 1; break; case TEGRA_PINCONF_PARAM_RCV_SEL: - *bank = g->rcv_sel_bank; - *reg = g->rcv_sel_reg; + *bank = g->mux_bank; + *reg = g->mux_reg; *bit = g->rcv_sel_bit; *width = 1; break; @@ -408,8 +402,8 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx, *width = g->slwr_width; break; case TEGRA_PINCONF_PARAM_DRIVE_TYPE: - *bank = g->drvtype_bank; - *reg = g->drvtype_reg; + *bank = g->drv_bank; + *reg = g->drv_reg; *bit = g->drvtype_bit; *width = 2; break; @@ -418,11 +412,22 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx, return -ENOTSUPP; } - if (*reg < 0) { - if (report_err) + if (*reg < 0 || *bit > 31) { + if (report_err) { + const char *prop = "unknown"; + int i; + + for (i = 0; i < ARRAY_SIZE(cfg_params); i++) { + if (cfg_params[i].param == param) { + prop = cfg_params[i].property; + break; + } + } + dev_err(pmx->dev, - "Config param %04x not supported on group %s\n", - param, g->name); + "Config param %04x (%s) not supported on group %s\n", + param, prop, g->name); + } return -ENOTSUPP; } diff --git a/drivers/pinctrl/pinctrl-tegra.h b/drivers/pinctrl/pinctrl-tegra.h index 6053832d433e7b..8d94d1332e7b48 100644 --- a/drivers/pinctrl/pinctrl-tegra.h +++ b/drivers/pinctrl/pinctrl-tegra.h @@ -78,98 +78,83 @@ struct tegra_function { /** * struct tegra_pingroup - Tegra pin group - * @mux_reg: Mux register offset. -1 if unsupported. - * @mux_bank: Mux register bank. 0 if unsupported. - * @mux_bit: Mux register bit. 0 if unsupported. - * @pupd_reg: Pull-up/down register offset. -1 if unsupported. - * @pupd_bank: Pull-up/down register bank. 0 if unsupported. - * @pupd_bit: Pull-up/down register bit. 0 if unsupported. - * @tri_reg: Tri-state register offset. -1 if unsupported. - * @tri_bank: Tri-state register bank. 0 if unsupported. - * @tri_bit: Tri-state register bit. 0 if unsupported. - * @einput_reg: Enable-input register offset. -1 if unsupported. - * @einput_bank: Enable-input register bank. 0 if unsupported. - * @einput_bit: Enable-input register bit. 0 if unsupported. - * @odrain_reg: Open-drain register offset. -1 if unsupported. - * @odrain_bank: Open-drain register bank. 0 if unsupported. - * @odrain_bit: Open-drain register bit. 0 if unsupported. - * @lock_reg: Lock register offset. -1 if unsupported. - * @lock_bank: Lock register bank. 0 if unsupported. - * @lock_bit: Lock register bit. 0 if unsupported. - * @ioreset_reg: IO reset register offset. -1 if unsupported. - * @ioreset_bank: IO reset register bank. 0 if unsupported. - * @ioreset_bit: IO reset register bit. 0 if unsupported. - * @rcv_sel_reg: Receiver select offset. -1 if unsupported. - * @rcv_sel_bank: Receiver select bank. 0 if unsupported. - * @rcv_sel_bit: Receiver select bit. 0 if unsupported. - * @drv_reg: Drive fields register offset. -1 if unsupported. - * This register contains the hsm, schmitt, lpmd, drvdn, - * drvup, slwr, and slwf parameters. - * @drv_bank: Drive fields register bank. 0 if unsupported. - * @hsm_bit: High Speed Mode register bit. 0 if unsupported. - * @schmitt_bit: Scmitt register bit. 0 if unsupported. - * @lpmd_bit: Low Power Mode register bit. 0 if unsupported. - * @drvdn_bit: Drive Down register bit. 0 if unsupported. - * @drvdn_width: Drive Down field width. 0 if unsupported. - * @drvup_bit: Drive Up register bit. 0 if unsupported. - * @drvup_width: Drive Up field width. 0 if unsupported. - * @slwr_bit: Slew Rising register bit. 0 if unsupported. - * @slwr_width: Slew Rising field width. 0 if unsupported. - * @slwf_bit: Slew Falling register bit. 0 if unsupported. - * @slwf_width: Slew Falling field width. 0 if unsupported. - * @drvtype_reg: Drive type fields register offset. -1 if unsupported. - * @drvtype_bank: Drive type fields register bank. 0 if unsupported. - * @drvtype_bit: Drive type register bit. 0 if unsupported. + * @name The name of the pin group. + * @pins An array of pin IDs included in this pin group. + * @npins The number of entries in @pins. + * @funcs The mux functions which can be muxed onto this group. + * @mux_reg: Mux register offset. + * This register contains the mux, einput, odrain, lock, + * ioreset, rcv_sel parameters. + * @mux_bank: Mux register bank. + * @mux_bit: Mux register bit. + * @pupd_reg: Pull-up/down register offset. + * @pupd_bank: Pull-up/down register bank. + * @pupd_bit: Pull-up/down register bit. + * @tri_reg: Tri-state register offset. + * @tri_bank: Tri-state register bank. + * @tri_bit: Tri-state register bit. + * @einput_bit: Enable-input register bit. + * @odrain_bit: Open-drain register bit. + * @lock_bit: Lock register bit. + * @ioreset_bit: IO reset register bit. + * @rcv_sel_bit: Receiver select bit. + * @drv_reg: Drive fields register offset. + * This register contains hsm, schmitt, lpmd, drvdn, + * drvup, slwr, slwf, and drvtype parameters. + * @drv_bank: Drive fields register bank. + * @hsm_bit: High Speed Mode register bit. + * @schmitt_bit: Scmitt register bit. + * @lpmd_bit: Low Power Mode register bit. + * @drvdn_bit: Drive Down register bit. + * @drvdn_width: Drive Down field width. + * @drvup_bit: Drive Up register bit. + * @drvup_width: Drive Up field width. + * @slwr_bit: Slew Rising register bit. + * @slwr_width: Slew Rising field width. + * @slwf_bit: Slew Falling register bit. + * @slwf_width: Slew Falling field width. + * @drvtype_bit: Drive type register bit. + * + * -1 in a *_reg field means that feature is unsupported for this group. + * *_bank and *_reg values are irrelevant when *_reg is -1. + * When *_reg is valid, *_bit may be -1 to indicate an unsupported feature. * * A representation of a group of pins (possibly just one pin) in the Tegra * pin controller. Each group allows some parameter or parameters to be * configured. The most common is mux function selection. Many others exist * such as pull-up/down, tri-state, etc. Tegra's pin controller is complex; * certain groups may only support configuring certain parameters, hence - * each parameter is optional, represented by a -1 "reg" value. + * each parameter is optional. */ struct tegra_pingroup { const char *name; const unsigned *pins; - unsigned npins; - unsigned funcs[4]; - unsigned func_safe; + u8 npins; + u8 funcs[4]; s16 mux_reg; s16 pupd_reg; s16 tri_reg; - s16 einput_reg; - s16 odrain_reg; - s16 lock_reg; - s16 ioreset_reg; - s16 rcv_sel_reg; s16 drv_reg; - s16 drvtype_reg; u32 mux_bank:2; u32 pupd_bank:2; u32 tri_bank:2; - u32 einput_bank:2; - u32 odrain_bank:2; - u32 ioreset_bank:2; - u32 rcv_sel_bank:2; - u32 lock_bank:2; u32 drv_bank:2; - u32 drvtype_bank:2; - u32 mux_bit:5; - u32 pupd_bit:5; - u32 tri_bit:5; - u32 einput_bit:5; - u32 odrain_bit:5; - u32 lock_bit:5; - u32 ioreset_bit:5; - u32 rcv_sel_bit:5; - u32 hsm_bit:5; - u32 schmitt_bit:5; - u32 lpmd_bit:5; - u32 drvdn_bit:5; - u32 drvup_bit:5; - u32 slwr_bit:5; - u32 slwf_bit:5; - u32 drvtype_bit:5; + u32 mux_bit:6; + u32 pupd_bit:6; + u32 tri_bit:6; + u32 einput_bit:6; + u32 odrain_bit:6; + u32 lock_bit:6; + u32 ioreset_bit:6; + u32 rcv_sel_bit:6; + u32 hsm_bit:6; + u32 schmitt_bit:6; + u32 lpmd_bit:6; + u32 drvdn_bit:6; + u32 drvup_bit:6; + u32 slwr_bit:6; + u32 slwf_bit:6; + u32 drvtype_bit:6; u32 drvdn_width:6; u32 drvup_width:6; u32 slwr_width:6; diff --git a/drivers/pinctrl/pinctrl-tegra114.c b/drivers/pinctrl/pinctrl-tegra114.c index 63fe7619d3ff9d..33614baab4c0a3 100644 --- a/drivers/pinctrl/pinctrl-tegra114.c +++ b/drivers/pinctrl/pinctrl-tegra114.c @@ -1547,10 +1547,12 @@ static struct tegra_function tegra114_functions[] = { #define DRV_PINGROUP_REG_A 0x868 /* bank 0 */ #define PINGROUP_REG_A 0x3000 /* bank 1 */ -#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A) -#define PINGROUP_REG_N(r) -1 +#define PINGROUP_REG(r) ((r) - PINGROUP_REG_A) -#define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior, rcv_sel) \ +#define PINGROUP_BIT_Y(b) (b) +#define PINGROUP_BIT_N(b) (-1) + +#define PINGROUP(pg_name, f0, f1, f2, f3, r, od, ior, rcv_sel) \ { \ .name = #pg_name, \ .pins = pg_name##_pins, \ @@ -1561,38 +1563,24 @@ static struct tegra_function tegra114_functions[] = { TEGRA_MUX_##f2, \ TEGRA_MUX_##f3, \ }, \ - .func_safe = TEGRA_MUX_##f_safe, \ - .mux_reg = PINGROUP_REG_Y(r), \ + .mux_reg = PINGROUP_REG(r), \ .mux_bank = 1, \ .mux_bit = 0, \ - .pupd_reg = PINGROUP_REG_Y(r), \ + .pupd_reg = PINGROUP_REG(r), \ .pupd_bank = 1, \ .pupd_bit = 2, \ - .tri_reg = PINGROUP_REG_Y(r), \ + .tri_reg = PINGROUP_REG(r), \ .tri_bank = 1, \ .tri_bit = 4, \ - .einput_reg = PINGROUP_REG_Y(r), \ - .einput_bank = 1, \ - .einput_bit = 5, \ - .odrain_reg = PINGROUP_REG_##od(r), \ - .odrain_bank = 1, \ - .odrain_bit = 6, \ - .lock_reg = PINGROUP_REG_Y(r), \ - .lock_bank = 1, \ - .lock_bit = 7, \ - .ioreset_reg = PINGROUP_REG_##ior(r), \ - .ioreset_bank = 1, \ - .ioreset_bit = 8, \ - .rcv_sel_reg = PINGROUP_REG_##rcv_sel(r), \ - .rcv_sel_bank = 1, \ - .rcv_sel_bit = 9, \ + .einput_bit = PINGROUP_BIT_Y(5), \ + .odrain_bit = PINGROUP_BIT_##od(6), \ + .lock_bit = PINGROUP_BIT_Y(7), \ + .ioreset_bit = PINGROUP_BIT_##ior(8), \ + .rcv_sel_bit = PINGROUP_BIT_##rcv_sel(9), \ .drv_reg = -1, \ - .drvtype_reg = -1, \ } -#define DRV_PINGROUP_REG_Y(r) ((r) - DRV_PINGROUP_REG_A) -#define DRV_PINGROUP_REG_N(r) -1 - +#define DRV_PINGROUP_REG(r) ((r) - DRV_PINGROUP_REG_A) #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, \ drvdn_b, drvdn_w, drvup_b, drvup_w, \ @@ -1605,12 +1593,12 @@ static struct tegra_function tegra114_functions[] = { .mux_reg = -1, \ .pupd_reg = -1, \ .tri_reg = -1, \ - .einput_reg = -1, \ - .odrain_reg = -1, \ - .lock_reg = -1, \ - .ioreset_reg = -1, \ - .rcv_sel_reg = -1, \ - .drv_reg = DRV_PINGROUP_REG_Y(r), \ + .einput_bit = -1, \ + .odrain_bit = -1, \ + .lock_bit = -1, \ + .ioreset_bit = -1, \ + .rcv_sel_bit = -1, \ + .drv_reg = DRV_PINGROUP_REG(r), \ .drv_bank = 0, \ .hsm_bit = hsm_b, \ .schmitt_bit = schmitt_b, \ @@ -1623,190 +1611,188 @@ static struct tegra_function tegra114_functions[] = { .slwr_width = slwr_w, \ .slwf_bit = slwf_b, \ .slwf_width = slwf_w, \ - .drvtype_reg = DRV_PINGROUP_REG_##drvtype(r), \ - .drvtype_bank = 0, \ - .drvtype_bit = 6, \ + .drvtype_bit = PINGROUP_BIT_##drvtype(6), \ } static const struct tegra_pingroup tegra114_groups[] = { - /* pg_name, f0, f1, f2, f3, safe, r, od, ior, rcv_sel */ - PINGROUP(ulpi_data0_po1, SPI3, HSI, UARTA, ULPI, ULPI, 0x3000, N, N, N), - PINGROUP(ulpi_data1_po2, SPI3, HSI, UARTA, ULPI, ULPI, 0x3004, N, N, N), - PINGROUP(ulpi_data2_po3, SPI3, HSI, UARTA, ULPI, ULPI, 0x3008, N, N, N), - PINGROUP(ulpi_data3_po4, SPI3, HSI, UARTA, ULPI, ULPI, 0x300c, N, N, N), - PINGROUP(ulpi_data4_po5, SPI2, HSI, UARTA, ULPI, ULPI, 0x3010, N, N, N), - PINGROUP(ulpi_data5_po6, SPI2, HSI, UARTA, ULPI, ULPI, 0x3014, N, N, N), - PINGROUP(ulpi_data6_po7, SPI2, HSI, UARTA, ULPI, ULPI, 0x3018, N, N, N), - PINGROUP(ulpi_data7_po0, SPI2, HSI, UARTA, ULPI, ULPI, 0x301c, N, N, N), - PINGROUP(ulpi_clk_py0, SPI1, SPI5, UARTD, ULPI, ULPI, 0x3020, N, N, N), - PINGROUP(ulpi_dir_py1, SPI1, SPI5, UARTD, ULPI, ULPI, 0x3024, N, N, N), - PINGROUP(ulpi_nxt_py2, SPI1, SPI5, UARTD, ULPI, ULPI, 0x3028, N, N, N), - PINGROUP(ulpi_stp_py3, SPI1, SPI5, UARTD, ULPI, ULPI, 0x302c, N, N, N), - PINGROUP(dap3_fs_pp0, I2S2, SPI5, DISPLAYA, DISPLAYB, I2S2, 0x3030, N, N, N), - PINGROUP(dap3_din_pp1, I2S2, SPI5, DISPLAYA, DISPLAYB, I2S2, 0x3034, N, N, N), - PINGROUP(dap3_dout_pp2, I2S2, SPI5, DISPLAYA, DISPLAYB, I2S2, 0x3038, N, N, N), - PINGROUP(dap3_sclk_pp3, I2S2, SPI5, DISPLAYA, DISPLAYB, I2S2, 0x303c, N, N, N), - PINGROUP(pv0, USB, RSVD2, RSVD3, RSVD4, RSVD4, 0x3040, N, N, N), - PINGROUP(pv1, RSVD1, RSVD2, RSVD3, RSVD4, RSVD4, 0x3044, N, N, N), - PINGROUP(sdmmc1_clk_pz0, SDMMC1, CLK12, RSVD3, RSVD4, RSVD4, 0x3048, N, N, N), - PINGROUP(sdmmc1_cmd_pz1, SDMMC1, SPDIF, SPI4, UARTA, SDMMC1, 0x304c, N, N, N), - PINGROUP(sdmmc1_dat3_py4, SDMMC1, SPDIF, SPI4, UARTA, SDMMC1, 0x3050, N, N, N), - PINGROUP(sdmmc1_dat2_py5, SDMMC1, PWM0, SPI4, UARTA, SDMMC1, 0x3054, N, N, N), - PINGROUP(sdmmc1_dat1_py6, SDMMC1, PWM1, SPI4, UARTA, SDMMC1, 0x3058, N, N, N), - PINGROUP(sdmmc1_dat0_py7, SDMMC1, RSVD2, SPI4, UARTA, RSVD2, 0x305c, N, N, N), - PINGROUP(clk2_out_pw5, EXTPERIPH2, RSVD2, RSVD3, RSVD4, RSVD4, 0x3068, N, N, N), - PINGROUP(clk2_req_pcc5, DAP, RSVD2, RSVD3, RSVD4, RSVD4, 0x306c, N, N, N), - PINGROUP(hdmi_int_pn7, RSVD1, RSVD2, RSVD3, RSVD4, RSVD4, 0x3110, N, N, Y), - PINGROUP(ddc_scl_pv4, I2C4, RSVD2, RSVD3, RSVD4, RSVD4, 0x3114, N, N, Y), - PINGROUP(ddc_sda_pv5, I2C4, RSVD2, RSVD3, RSVD4, RSVD4, 0x3118, N, N, Y), - PINGROUP(uart2_rxd_pc3, IRDA, SPDIF, UARTA, SPI4, IRDA, 0x3164, N, N, N), - PINGROUP(uart2_txd_pc2, IRDA, SPDIF, UARTA, SPI4, IRDA, 0x3168, N, N, N), - PINGROUP(uart2_rts_n_pj6, UARTA, UARTB, RSVD3, SPI4, RSVD3, 0x316c, N, N, N), - PINGROUP(uart2_cts_n_pj5, UARTA, UARTB, RSVD3, SPI4, RSVD3, 0x3170, N, N, N), - PINGROUP(uart3_txd_pw6, UARTC, RSVD2, RSVD3, SPI4, RSVD3, 0x3174, N, N, N), - PINGROUP(uart3_rxd_pw7, UARTC, RSVD2, RSVD3, SPI4, RSVD3, 0x3178, N, N, N), - PINGROUP(uart3_cts_n_pa1, UARTC, SDMMC1, DTV, SPI4, UARTC, 0x317c, N, N, N), - PINGROUP(uart3_rts_n_pc0, UARTC, PWM0, DTV, DISPLAYA, UARTC, 0x3180, N, N, N), - PINGROUP(pu0, OWR, UARTA, RSVD3, RSVD4, RSVD4, 0x3184, N, N, N), - PINGROUP(pu1, RSVD1, UARTA, RSVD3, RSVD4, RSVD4, 0x3188, N, N, N), - PINGROUP(pu2, RSVD1, UARTA, RSVD3, RSVD4, RSVD4, 0x318c, N, N, N), - PINGROUP(pu3, PWM0, UARTA, DISPLAYA, DISPLAYB, PWM0, 0x3190, N, N, N), - PINGROUP(pu4, PWM1, UARTA, DISPLAYA, DISPLAYB, PWM1, 0x3194, N, N, N), - PINGROUP(pu5, PWM2, UARTA, DISPLAYA, DISPLAYB, PWM2, 0x3198, N, N, N), - PINGROUP(pu6, PWM3, UARTA, USB, DISPLAYB, PWM3, 0x319c, N, N, N), - PINGROUP(gen1_i2c_sda_pc5, I2C1, RSVD2, RSVD3, RSVD4, RSVD4, 0x31a0, Y, N, N), - PINGROUP(gen1_i2c_scl_pc4, I2C1, RSVD2, RSVD3, RSVD4, RSVD4, 0x31a4, Y, N, N), - PINGROUP(dap4_fs_pp4, I2S3, RSVD2, DTV, RSVD4, RSVD4, 0x31a8, N, N, N), - PINGROUP(dap4_din_pp5, I2S3, RSVD2, RSVD3, RSVD4, RSVD4, 0x31ac, N, N, N), - PINGROUP(dap4_dout_pp6, I2S3, RSVD2, DTV, RSVD4, RSVD4, 0x31b0, N, N, N), - PINGROUP(dap4_sclk_pp7, I2S3, RSVD2, RSVD3, RSVD4, RSVD4, 0x31b4, N, N, N), - PINGROUP(clk3_out_pee0, EXTPERIPH3, RSVD2, RSVD3, RSVD4, RSVD4, 0x31b8, N, N, N), - PINGROUP(clk3_req_pee1, DEV3, RSVD2, RSVD3, RSVD4, RSVD4, 0x31bc, N, N, N), - PINGROUP(gmi_wp_n_pc7, RSVD1, NAND, GMI, GMI_ALT, RSVD1, 0x31c0, N, N, N), - PINGROUP(gmi_iordy_pi5, SDMMC2, RSVD2, GMI, TRACE, RSVD2, 0x31c4, N, N, N), - PINGROUP(gmi_wait_pi7, SPI4, NAND, GMI, DTV, NAND, 0x31c8, N, N, N), - PINGROUP(gmi_adv_n_pk0, RSVD1, NAND, GMI, TRACE, RSVD1, 0x31cc, N, N, N), - PINGROUP(gmi_clk_pk1, SDMMC2, NAND, GMI, TRACE, GMI, 0x31d0, N, N, N), - PINGROUP(gmi_cs0_n_pj0, RSVD1, NAND, GMI, USB, RSVD1, 0x31d4, N, N, N), - PINGROUP(gmi_cs1_n_pj2, RSVD1, NAND, GMI, SOC, RSVD1, 0x31d8, N, N, N), - PINGROUP(gmi_cs2_n_pk3, SDMMC2, NAND, GMI, TRACE, GMI, 0x31dc, N, N, N), - PINGROUP(gmi_cs3_n_pk4, SDMMC2, NAND, GMI, GMI_ALT, GMI, 0x31e0, N, N, N), - PINGROUP(gmi_cs4_n_pk2, USB, NAND, GMI, TRACE, GMI, 0x31e4, N, N, N), - PINGROUP(gmi_cs6_n_pi3, NAND, NAND_ALT, GMI, SPI4, NAND, 0x31e8, N, N, N), - PINGROUP(gmi_cs7_n_pi6, NAND, NAND_ALT, GMI, SDMMC2, NAND, 0x31ec, N, N, N), - PINGROUP(gmi_ad0_pg0, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31f0, N, N, N), - PINGROUP(gmi_ad1_pg1, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31f4, N, N, N), - PINGROUP(gmi_ad2_pg2, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31f8, N, N, N), - PINGROUP(gmi_ad3_pg3, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31fc, N, N, N), - PINGROUP(gmi_ad4_pg4, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x3200, N, N, N), - PINGROUP(gmi_ad5_pg5, RSVD1, NAND, GMI, SPI4, RSVD1, 0x3204, N, N, N), - PINGROUP(gmi_ad6_pg6, RSVD1, NAND, GMI, SPI4, RSVD1, 0x3208, N, N, N), - PINGROUP(gmi_ad7_pg7, RSVD1, NAND, GMI, SPI4, RSVD1, 0x320c, N, N, N), - PINGROUP(gmi_ad8_ph0, PWM0, NAND, GMI, DTV, GMI, 0x3210, N, N, N), - PINGROUP(gmi_ad9_ph1, PWM1, NAND, GMI, CLDVFS, GMI, 0x3214, N, N, N), - PINGROUP(gmi_ad10_ph2, PWM2, NAND, GMI, CLDVFS, GMI, 0x3218, N, N, N), - PINGROUP(gmi_ad11_ph3, PWM3, NAND, GMI, USB, GMI, 0x321c, N, N, N), - PINGROUP(gmi_ad12_ph4, SDMMC2, NAND, GMI, RSVD4, RSVD4, 0x3220, N, N, N), - PINGROUP(gmi_ad13_ph5, SDMMC2, NAND, GMI, RSVD4, RSVD4, 0x3224, N, N, N), - PINGROUP(gmi_ad14_ph6, SDMMC2, NAND, GMI, DTV, GMI, 0x3228, N, N, N), - PINGROUP(gmi_ad15_ph7, SDMMC2, NAND, GMI, DTV, GMI, 0x322c, N, N, N), - PINGROUP(gmi_a16_pj7, UARTD, TRACE, GMI, GMI_ALT, GMI, 0x3230, N, N, N), - PINGROUP(gmi_a17_pb0, UARTD, RSVD2, GMI, TRACE, RSVD2, 0x3234, N, N, N), - PINGROUP(gmi_a18_pb1, UARTD, RSVD2, GMI, TRACE, RSVD2, 0x3238, N, N, N), - PINGROUP(gmi_a19_pk7, UARTD, SPI4, GMI, TRACE, GMI, 0x323c, N, N, N), - PINGROUP(gmi_wr_n_pi0, RSVD1, NAND, GMI, SPI4, RSVD1, 0x3240, N, N, N), - PINGROUP(gmi_oe_n_pi1, RSVD1, NAND, GMI, SOC, RSVD1, 0x3244, N, N, N), - PINGROUP(gmi_dqs_p_pj3, SDMMC2, NAND, GMI, TRACE, NAND, 0x3248, N, N, N), - PINGROUP(gmi_rst_n_pi4, NAND, NAND_ALT, GMI, RSVD4, RSVD4, 0x324c, N, N, N), - PINGROUP(gen2_i2c_scl_pt5, I2C2, RSVD2, GMI, RSVD4, RSVD4, 0x3250, Y, N, N), - PINGROUP(gen2_i2c_sda_pt6, I2C2, RSVD2, GMI, RSVD4, RSVD4, 0x3254, Y, N, N), - PINGROUP(sdmmc4_clk_pcc4, SDMMC4, RSVD2, GMI, RSVD4, RSVD4, 0x3258, N, Y, N), - PINGROUP(sdmmc4_cmd_pt7, SDMMC4, RSVD2, GMI, RSVD4, RSVD4, 0x325c, N, Y, N), - PINGROUP(sdmmc4_dat0_paa0, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x3260, N, Y, N), - PINGROUP(sdmmc4_dat1_paa1, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x3264, N, Y, N), - PINGROUP(sdmmc4_dat2_paa2, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x3268, N, Y, N), - PINGROUP(sdmmc4_dat3_paa3, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x326c, N, Y, N), - PINGROUP(sdmmc4_dat4_paa4, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x3270, N, Y, N), - PINGROUP(sdmmc4_dat5_paa5, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x3274, N, Y, N), - PINGROUP(sdmmc4_dat6_paa6, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x3278, N, Y, N), - PINGROUP(sdmmc4_dat7_paa7, SDMMC4, RSVD2, GMI, RSVD4, RSVD4, 0x327c, N, Y, N), - PINGROUP(cam_mclk_pcc0, VI, VI_ALT1, VI_ALT3, RSVD4, RSVD4, 0x3284, N, N, N), - PINGROUP(pcc1, I2S4, RSVD2, RSVD3, RSVD4, RSVD4, 0x3288, N, N, N), - PINGROUP(pbb0, I2S4, VI, VI_ALT1, VI_ALT3, I2S4, 0x328c, N, N, N), - PINGROUP(cam_i2c_scl_pbb1, VGP1, I2C3, RSVD3, RSVD4, RSVD4, 0x3290, Y, N, N), - PINGROUP(cam_i2c_sda_pbb2, VGP2, I2C3, RSVD3, RSVD4, RSVD4, 0x3294, Y, N, N), - PINGROUP(pbb3, VGP3, DISPLAYA, DISPLAYB, RSVD4, RSVD4, 0x3298, N, N, N), - PINGROUP(pbb4, VGP4, DISPLAYA, DISPLAYB, RSVD4, RSVD4, 0x329c, N, N, N), - PINGROUP(pbb5, VGP5, DISPLAYA, DISPLAYB, RSVD4, RSVD4, 0x32a0, N, N, N), - PINGROUP(pbb6, VGP6, DISPLAYA, DISPLAYB, RSVD4, RSVD4, 0x32a4, N, N, N), - PINGROUP(pbb7, I2S4, RSVD2, RSVD3, RSVD4, RSVD4, 0x32a8, N, N, N), - PINGROUP(pcc2, I2S4, RSVD2, RSVD3, RSVD4, RSVD4, 0x32ac, N, N, N), - PINGROUP(jtag_rtck, RTCK, RSVD2, RSVD3, RSVD4, RTCK, 0x32b0, N, N, N), - PINGROUP(pwr_i2c_scl_pz6, I2CPWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x32b4, Y, N, N), - PINGROUP(pwr_i2c_sda_pz7, I2CPWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x32b8, Y, N, N), - PINGROUP(kb_row0_pr0, KBC, RSVD2, RSVD3, RSVD4, RSVD4, 0x32bc, N, N, N), - PINGROUP(kb_row1_pr1, KBC, RSVD2, RSVD3, RSVD4, RSVD4, 0x32c0, N, N, N), - PINGROUP(kb_row2_pr2, KBC, RSVD2, RSVD3, RSVD4, RSVD4, 0x32c4, N, N, N), - PINGROUP(kb_row3_pr3, KBC, DISPLAYA, RSVD3, DISPLAYB, RSVD3, 0x32c8, N, N, N), - PINGROUP(kb_row4_pr4, KBC, DISPLAYA, SPI2, DISPLAYB, KBC, 0x32cc, N, N, N), - PINGROUP(kb_row5_pr5, KBC, DISPLAYA, SPI2, DISPLAYB, KBC, 0x32d0, N, N, N), - PINGROUP(kb_row6_pr6, KBC, DISPLAYA, DISPLAYA_ALT, DISPLAYB, KBC, 0x32d4, N, N, N), - PINGROUP(kb_row7_pr7, KBC, RSVD2, CLDVFS, UARTA, RSVD2, 0x32d8, N, N, N), - PINGROUP(kb_row8_ps0, KBC, RSVD2, CLDVFS, UARTA, RSVD2, 0x32dc, N, N, N), - PINGROUP(kb_row9_ps1, KBC, RSVD2, RSVD3, UARTA, RSVD3, 0x32e0, N, N, N), - PINGROUP(kb_row10_ps2, KBC, RSVD2, RSVD3, UARTA, RSVD3, 0x32e4, N, N, N), - PINGROUP(kb_col0_pq0, KBC, USB, SPI2, EMC_DLL, KBC, 0x32fc, N, N, N), - PINGROUP(kb_col1_pq1, KBC, RSVD2, SPI2, EMC_DLL, RSVD2, 0x3300, N, N, N), - PINGROUP(kb_col2_pq2, KBC, RSVD2, SPI2, RSVD4, RSVD2, 0x3304, N, N, N), - PINGROUP(kb_col3_pq3, KBC, DISPLAYA, PWM2, UARTA, KBC, 0x3308, N, N, N), - PINGROUP(kb_col4_pq4, KBC, OWR, SDMMC3, UARTA, KBC, 0x330c, N, N, N), - PINGROUP(kb_col5_pq5, KBC, RSVD2, SDMMC1, RSVD4, RSVD4, 0x3310, N, N, N), - PINGROUP(kb_col6_pq6, KBC, RSVD2, SPI2, RSVD4, RSVD4, 0x3314, N, N, N), - PINGROUP(kb_col7_pq7, KBC, RSVD2, SPI2, RSVD4, RSVD4, 0x3318, N, N, N), - PINGROUP(clk_32k_out_pa0, BLINK, SOC, RSVD3, RSVD4, RSVD4, 0x331c, N, N, N), - PINGROUP(sys_clk_req_pz5, SYSCLK, RSVD2, RSVD3, RSVD4, RSVD4, 0x3320, N, N, N), - PINGROUP(core_pwr_req, PWRON, RSVD2, RSVD3, RSVD4, RSVD4, 0x3324, N, N, N), - PINGROUP(cpu_pwr_req, CPU, RSVD2, RSVD3, RSVD4, RSVD4, 0x3328, N, N, N), - PINGROUP(pwr_int_n, PMI, RSVD2, RSVD3, RSVD4, RSVD4, 0x332c, N, N, N), - PINGROUP(clk_32k_in, CLK, RSVD2, RSVD3, RSVD4, CLK, 0x3330, N, N, N), - PINGROUP(owr, OWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x3334, N, N, Y), - PINGROUP(dap1_fs_pn0, I2S0, HDA, GMI, RSVD4, RSVD4, 0x3338, N, N, N), - PINGROUP(dap1_din_pn1, I2S0, HDA, GMI, RSVD4, RSVD4, 0x333c, N, N, N), - PINGROUP(dap1_dout_pn2, I2S0, HDA, GMI, RSVD4, RSVD4, 0x3340, N, N, N), - PINGROUP(dap1_sclk_pn3, I2S0, HDA, GMI, RSVD4, RSVD4, 0x3344, N, N, N), - PINGROUP(clk1_req_pee2, DAP, DAP1, RSVD3, RSVD4, RSVD4, 0x3348, N, N, N), - PINGROUP(clk1_out_pw4, EXTPERIPH1, DAP2, RSVD3, RSVD4, RSVD4, 0x334c, N, N, N), - PINGROUP(spdif_in_pk6, SPDIF, USB, RSVD3, RSVD4, RSVD4, 0x3350, N, N, N), - PINGROUP(spdif_out_pk5, SPDIF, RSVD2, RSVD3, RSVD4, RSVD4, 0x3354, N, N, N), - PINGROUP(dap2_fs_pa2, I2S1, HDA, RSVD3, RSVD4, RSVD4, 0x3358, N, N, N), - PINGROUP(dap2_din_pa4, I2S1, HDA, RSVD3, RSVD4, RSVD4, 0x335c, N, N, N), - PINGROUP(dap2_dout_pa5, I2S1, HDA, RSVD3, RSVD4, RSVD4, 0x3360, N, N, N), - PINGROUP(dap2_sclk_pa3, I2S1, HDA, RSVD3, RSVD4, RSVD4, 0x3364, N, N, N), - PINGROUP(dvfs_pwm_px0, SPI6, CLDVFS, RSVD3, RSVD4, RSVD4, 0x3368, N, N, N), - PINGROUP(gpio_x1_aud_px1, SPI6, RSVD2, RSVD3, RSVD4, RSVD4, 0x336c, N, N, N), - PINGROUP(gpio_x3_aud_px3, SPI6, SPI1, RSVD3, RSVD4, RSVD4, 0x3370, N, N, N), - PINGROUP(dvfs_clk_px2, SPI6, CLDVFS, RSVD3, RSVD4, RSVD4, 0x3374, N, N, N), - PINGROUP(gpio_x4_aud_px4, RSVD1, SPI1, SPI2, DAP2, RSVD1, 0x3378, N, N, N), - PINGROUP(gpio_x5_aud_px5, RSVD1, SPI1, SPI2, RSVD4, RSVD1, 0x337c, N, N, N), - PINGROUP(gpio_x6_aud_px6, SPI6, SPI1, SPI2, RSVD4, RSVD4, 0x3380, N, N, N), - PINGROUP(gpio_x7_aud_px7, RSVD1, SPI1, SPI2, RSVD4, RSVD4, 0x3384, N, N, N), - PINGROUP(sdmmc3_clk_pa6, SDMMC3, RSVD2, RSVD3, SPI3, RSVD3, 0x3390, N, N, N), - PINGROUP(sdmmc3_cmd_pa7, SDMMC3, PWM3, UARTA, SPI3, SDMMC3, 0x3394, N, N, N), - PINGROUP(sdmmc3_dat0_pb7, SDMMC3, RSVD2, RSVD3, SPI3, RSVD3, 0x3398, N, N, N), - PINGROUP(sdmmc3_dat1_pb6, SDMMC3, PWM2, UARTA, SPI3, SDMMC3, 0x339c, N, N, N), - PINGROUP(sdmmc3_dat2_pb5, SDMMC3, PWM1, DISPLAYA, SPI3, SDMMC3, 0x33a0, N, N, N), - PINGROUP(sdmmc3_dat3_pb4, SDMMC3, PWM0, DISPLAYB, SPI3, SDMMC3, 0x33a4, N, N, N), - PINGROUP(hdmi_cec_pee3, CEC, SDMMC3, RSVD3, SOC, RSVD3, 0x33e0, Y, N, N), - PINGROUP(sdmmc1_wp_n_pv3, SDMMC1, CLK12, SPI4, UARTA, SDMMC1, 0x33e4, N, N, N), - PINGROUP(sdmmc3_cd_n_pv2, SDMMC3, OWR, RSVD3, RSVD4, RSVD4, 0x33e8, N, N, N), - PINGROUP(gpio_w2_aud_pw2, SPI6, RSVD2, SPI2, I2C1, RSVD2, 0x33ec, N, N, N), - PINGROUP(gpio_w3_aud_pw3, SPI6, SPI1, SPI2, I2C1, SPI6, 0x33f0, N, N, N), - PINGROUP(usb_vbus_en0_pn4, USB, RSVD2, RSVD3, RSVD4, RSVD4, 0x33f4, Y, N, N), - PINGROUP(usb_vbus_en1_pn5, USB, RSVD2, RSVD3, RSVD4, RSVD4, 0x33f8, Y, N, N), - PINGROUP(sdmmc3_clk_lb_in_pee5, SDMMC3, RSVD2, RSVD3, RSVD4, RSVD4, 0x33fc, N, N, N), - PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3, RSVD2, RSVD3, RSVD4, RSVD4, 0x3400, N, N, N), - PINGROUP(gmi_clk_lb, SDMMC2, NAND, GMI, RSVD4, GMI, 0x3404, N, N, N), - PINGROUP(reset_out_n, RSVD1, RSVD2, RSVD3, RESET_OUT_N, RSVD3, 0x3408, N, N, N), + /* pg_name, f0, f1, f2, f3, r, od, ior, rcv_sel */ + PINGROUP(ulpi_data0_po1, SPI3, HSI, UARTA, ULPI, 0x3000, N, N, N), + PINGROUP(ulpi_data1_po2, SPI3, HSI, UARTA, ULPI, 0x3004, N, N, N), + PINGROUP(ulpi_data2_po3, SPI3, HSI, UARTA, ULPI, 0x3008, N, N, N), + PINGROUP(ulpi_data3_po4, SPI3, HSI, UARTA, ULPI, 0x300c, N, N, N), + PINGROUP(ulpi_data4_po5, SPI2, HSI, UARTA, ULPI, 0x3010, N, N, N), + PINGROUP(ulpi_data5_po6, SPI2, HSI, UARTA, ULPI, 0x3014, N, N, N), + PINGROUP(ulpi_data6_po7, SPI2, HSI, UARTA, ULPI, 0x3018, N, N, N), + PINGROUP(ulpi_data7_po0, SPI2, HSI, UARTA, ULPI, 0x301c, N, N, N), + PINGROUP(ulpi_clk_py0, SPI1, SPI5, UARTD, ULPI, 0x3020, N, N, N), + PINGROUP(ulpi_dir_py1, SPI1, SPI5, UARTD, ULPI, 0x3024, N, N, N), + PINGROUP(ulpi_nxt_py2, SPI1, SPI5, UARTD, ULPI, 0x3028, N, N, N), + PINGROUP(ulpi_stp_py3, SPI1, SPI5, UARTD, ULPI, 0x302c, N, N, N), + PINGROUP(dap3_fs_pp0, I2S2, SPI5, DISPLAYA, DISPLAYB, 0x3030, N, N, N), + PINGROUP(dap3_din_pp1, I2S2, SPI5, DISPLAYA, DISPLAYB, 0x3034, N, N, N), + PINGROUP(dap3_dout_pp2, I2S2, SPI5, DISPLAYA, DISPLAYB, 0x3038, N, N, N), + PINGROUP(dap3_sclk_pp3, I2S2, SPI5, DISPLAYA, DISPLAYB, 0x303c, N, N, N), + PINGROUP(pv0, USB, RSVD2, RSVD3, RSVD4, 0x3040, N, N, N), + PINGROUP(pv1, RSVD1, RSVD2, RSVD3, RSVD4, 0x3044, N, N, N), + PINGROUP(sdmmc1_clk_pz0, SDMMC1, CLK12, RSVD3, RSVD4, 0x3048, N, N, N), + PINGROUP(sdmmc1_cmd_pz1, SDMMC1, SPDIF, SPI4, UARTA, 0x304c, N, N, N), + PINGROUP(sdmmc1_dat3_py4, SDMMC1, SPDIF, SPI4, UARTA, 0x3050, N, N, N), + PINGROUP(sdmmc1_dat2_py5, SDMMC1, PWM0, SPI4, UARTA, 0x3054, N, N, N), + PINGROUP(sdmmc1_dat1_py6, SDMMC1, PWM1, SPI4, UARTA, 0x3058, N, N, N), + PINGROUP(sdmmc1_dat0_py7, SDMMC1, RSVD2, SPI4, UARTA, 0x305c, N, N, N), + PINGROUP(clk2_out_pw5, EXTPERIPH2, RSVD2, RSVD3, RSVD4, 0x3068, N, N, N), + PINGROUP(clk2_req_pcc5, DAP, RSVD2, RSVD3, RSVD4, 0x306c, N, N, N), + PINGROUP(hdmi_int_pn7, RSVD1, RSVD2, RSVD3, RSVD4, 0x3110, N, N, Y), + PINGROUP(ddc_scl_pv4, I2C4, RSVD2, RSVD3, RSVD4, 0x3114, N, N, Y), + PINGROUP(ddc_sda_pv5, I2C4, RSVD2, RSVD3, RSVD4, 0x3118, N, N, Y), + PINGROUP(uart2_rxd_pc3, IRDA, SPDIF, UARTA, SPI4, 0x3164, N, N, N), + PINGROUP(uart2_txd_pc2, IRDA, SPDIF, UARTA, SPI4, 0x3168, N, N, N), + PINGROUP(uart2_rts_n_pj6, UARTA, UARTB, RSVD3, SPI4, 0x316c, N, N, N), + PINGROUP(uart2_cts_n_pj5, UARTA, UARTB, RSVD3, SPI4, 0x3170, N, N, N), + PINGROUP(uart3_txd_pw6, UARTC, RSVD2, RSVD3, SPI4, 0x3174, N, N, N), + PINGROUP(uart3_rxd_pw7, UARTC, RSVD2, RSVD3, SPI4, 0x3178, N, N, N), + PINGROUP(uart3_cts_n_pa1, UARTC, SDMMC1, DTV, SPI4, 0x317c, N, N, N), + PINGROUP(uart3_rts_n_pc0, UARTC, PWM0, DTV, DISPLAYA, 0x3180, N, N, N), + PINGROUP(pu0, OWR, UARTA, RSVD3, RSVD4, 0x3184, N, N, N), + PINGROUP(pu1, RSVD1, UARTA, RSVD3, RSVD4, 0x3188, N, N, N), + PINGROUP(pu2, RSVD1, UARTA, RSVD3, RSVD4, 0x318c, N, N, N), + PINGROUP(pu3, PWM0, UARTA, DISPLAYA, DISPLAYB, 0x3190, N, N, N), + PINGROUP(pu4, PWM1, UARTA, DISPLAYA, DISPLAYB, 0x3194, N, N, N), + PINGROUP(pu5, PWM2, UARTA, DISPLAYA, DISPLAYB, 0x3198, N, N, N), + PINGROUP(pu6, PWM3, UARTA, USB, DISPLAYB, 0x319c, N, N, N), + PINGROUP(gen1_i2c_sda_pc5, I2C1, RSVD2, RSVD3, RSVD4, 0x31a0, Y, N, N), + PINGROUP(gen1_i2c_scl_pc4, I2C1, RSVD2, RSVD3, RSVD4, 0x31a4, Y, N, N), + PINGROUP(dap4_fs_pp4, I2S3, RSVD2, DTV, RSVD4, 0x31a8, N, N, N), + PINGROUP(dap4_din_pp5, I2S3, RSVD2, RSVD3, RSVD4, 0x31ac, N, N, N), + PINGROUP(dap4_dout_pp6, I2S3, RSVD2, DTV, RSVD4, 0x31b0, N, N, N), + PINGROUP(dap4_sclk_pp7, I2S3, RSVD2, RSVD3, RSVD4, 0x31b4, N, N, N), + PINGROUP(clk3_out_pee0, EXTPERIPH3, RSVD2, RSVD3, RSVD4, 0x31b8, N, N, N), + PINGROUP(clk3_req_pee1, DEV3, RSVD2, RSVD3, RSVD4, 0x31bc, N, N, N), + PINGROUP(gmi_wp_n_pc7, RSVD1, NAND, GMI, GMI_ALT, 0x31c0, N, N, N), + PINGROUP(gmi_iordy_pi5, SDMMC2, RSVD2, GMI, TRACE, 0x31c4, N, N, N), + PINGROUP(gmi_wait_pi7, SPI4, NAND, GMI, DTV, 0x31c8, N, N, N), + PINGROUP(gmi_adv_n_pk0, RSVD1, NAND, GMI, TRACE, 0x31cc, N, N, N), + PINGROUP(gmi_clk_pk1, SDMMC2, NAND, GMI, TRACE, 0x31d0, N, N, N), + PINGROUP(gmi_cs0_n_pj0, RSVD1, NAND, GMI, USB, 0x31d4, N, N, N), + PINGROUP(gmi_cs1_n_pj2, RSVD1, NAND, GMI, SOC, 0x31d8, N, N, N), + PINGROUP(gmi_cs2_n_pk3, SDMMC2, NAND, GMI, TRACE, 0x31dc, N, N, N), + PINGROUP(gmi_cs3_n_pk4, SDMMC2, NAND, GMI, GMI_ALT, 0x31e0, N, N, N), + PINGROUP(gmi_cs4_n_pk2, USB, NAND, GMI, TRACE, 0x31e4, N, N, N), + PINGROUP(gmi_cs6_n_pi3, NAND, NAND_ALT, GMI, SPI4, 0x31e8, N, N, N), + PINGROUP(gmi_cs7_n_pi6, NAND, NAND_ALT, GMI, SDMMC2, 0x31ec, N, N, N), + PINGROUP(gmi_ad0_pg0, RSVD1, NAND, GMI, RSVD4, 0x31f0, N, N, N), + PINGROUP(gmi_ad1_pg1, RSVD1, NAND, GMI, RSVD4, 0x31f4, N, N, N), + PINGROUP(gmi_ad2_pg2, RSVD1, NAND, GMI, RSVD4, 0x31f8, N, N, N), + PINGROUP(gmi_ad3_pg3, RSVD1, NAND, GMI, RSVD4, 0x31fc, N, N, N), + PINGROUP(gmi_ad4_pg4, RSVD1, NAND, GMI, RSVD4, 0x3200, N, N, N), + PINGROUP(gmi_ad5_pg5, RSVD1, NAND, GMI, SPI4, 0x3204, N, N, N), + PINGROUP(gmi_ad6_pg6, RSVD1, NAND, GMI, SPI4, 0x3208, N, N, N), + PINGROUP(gmi_ad7_pg7, RSVD1, NAND, GMI, SPI4, 0x320c, N, N, N), + PINGROUP(gmi_ad8_ph0, PWM0, NAND, GMI, DTV, 0x3210, N, N, N), + PINGROUP(gmi_ad9_ph1, PWM1, NAND, GMI, CLDVFS, 0x3214, N, N, N), + PINGROUP(gmi_ad10_ph2, PWM2, NAND, GMI, CLDVFS, 0x3218, N, N, N), + PINGROUP(gmi_ad11_ph3, PWM3, NAND, GMI, USB, 0x321c, N, N, N), + PINGROUP(gmi_ad12_ph4, SDMMC2, NAND, GMI, RSVD4, 0x3220, N, N, N), + PINGROUP(gmi_ad13_ph5, SDMMC2, NAND, GMI, RSVD4, 0x3224, N, N, N), + PINGROUP(gmi_ad14_ph6, SDMMC2, NAND, GMI, DTV, 0x3228, N, N, N), + PINGROUP(gmi_ad15_ph7, SDMMC2, NAND, GMI, DTV, 0x322c, N, N, N), + PINGROUP(gmi_a16_pj7, UARTD, TRACE, GMI, GMI_ALT, 0x3230, N, N, N), + PINGROUP(gmi_a17_pb0, UARTD, RSVD2, GMI, TRACE, 0x3234, N, N, N), + PINGROUP(gmi_a18_pb1, UARTD, RSVD2, GMI, TRACE, 0x3238, N, N, N), + PINGROUP(gmi_a19_pk7, UARTD, SPI4, GMI, TRACE, 0x323c, N, N, N), + PINGROUP(gmi_wr_n_pi0, RSVD1, NAND, GMI, SPI4, 0x3240, N, N, N), + PINGROUP(gmi_oe_n_pi1, RSVD1, NAND, GMI, SOC, 0x3244, N, N, N), + PINGROUP(gmi_dqs_p_pj3, SDMMC2, NAND, GMI, TRACE, 0x3248, N, N, N), + PINGROUP(gmi_rst_n_pi4, NAND, NAND_ALT, GMI, RSVD4, 0x324c, N, N, N), + PINGROUP(gen2_i2c_scl_pt5, I2C2, RSVD2, GMI, RSVD4, 0x3250, Y, N, N), + PINGROUP(gen2_i2c_sda_pt6, I2C2, RSVD2, GMI, RSVD4, 0x3254, Y, N, N), + PINGROUP(sdmmc4_clk_pcc4, SDMMC4, RSVD2, GMI, RSVD4, 0x3258, N, Y, N), + PINGROUP(sdmmc4_cmd_pt7, SDMMC4, RSVD2, GMI, RSVD4, 0x325c, N, Y, N), + PINGROUP(sdmmc4_dat0_paa0, SDMMC4, SPI3, GMI, RSVD4, 0x3260, N, Y, N), + PINGROUP(sdmmc4_dat1_paa1, SDMMC4, SPI3, GMI, RSVD4, 0x3264, N, Y, N), + PINGROUP(sdmmc4_dat2_paa2, SDMMC4, SPI3, GMI, RSVD4, 0x3268, N, Y, N), + PINGROUP(sdmmc4_dat3_paa3, SDMMC4, SPI3, GMI, RSVD4, 0x326c, N, Y, N), + PINGROUP(sdmmc4_dat4_paa4, SDMMC4, SPI3, GMI, RSVD4, 0x3270, N, Y, N), + PINGROUP(sdmmc4_dat5_paa5, SDMMC4, SPI3, GMI, RSVD4, 0x3274, N, Y, N), + PINGROUP(sdmmc4_dat6_paa6, SDMMC4, SPI3, GMI, RSVD4, 0x3278, N, Y, N), + PINGROUP(sdmmc4_dat7_paa7, SDMMC4, RSVD2, GMI, RSVD4, 0x327c, N, Y, N), + PINGROUP(cam_mclk_pcc0, VI, VI_ALT1, VI_ALT3, RSVD4, 0x3284, N, N, N), + PINGROUP(pcc1, I2S4, RSVD2, RSVD3, RSVD4, 0x3288, N, N, N), + PINGROUP(pbb0, I2S4, VI, VI_ALT1, VI_ALT3, 0x328c, N, N, N), + PINGROUP(cam_i2c_scl_pbb1, VGP1, I2C3, RSVD3, RSVD4, 0x3290, Y, N, N), + PINGROUP(cam_i2c_sda_pbb2, VGP2, I2C3, RSVD3, RSVD4, 0x3294, Y, N, N), + PINGROUP(pbb3, VGP3, DISPLAYA, DISPLAYB, RSVD4, 0x3298, N, N, N), + PINGROUP(pbb4, VGP4, DISPLAYA, DISPLAYB, RSVD4, 0x329c, N, N, N), + PINGROUP(pbb5, VGP5, DISPLAYA, DISPLAYB, RSVD4, 0x32a0, N, N, N), + PINGROUP(pbb6, VGP6, DISPLAYA, DISPLAYB, RSVD4, 0x32a4, N, N, N), + PINGROUP(pbb7, I2S4, RSVD2, RSVD3, RSVD4, 0x32a8, N, N, N), + PINGROUP(pcc2, I2S4, RSVD2, RSVD3, RSVD4, 0x32ac, N, N, N), + PINGROUP(jtag_rtck, RTCK, RSVD2, RSVD3, RSVD4, 0x32b0, N, N, N), + PINGROUP(pwr_i2c_scl_pz6, I2CPWR, RSVD2, RSVD3, RSVD4, 0x32b4, Y, N, N), + PINGROUP(pwr_i2c_sda_pz7, I2CPWR, RSVD2, RSVD3, RSVD4, 0x32b8, Y, N, N), + PINGROUP(kb_row0_pr0, KBC, RSVD2, RSVD3, RSVD4, 0x32bc, N, N, N), + PINGROUP(kb_row1_pr1, KBC, RSVD2, RSVD3, RSVD4, 0x32c0, N, N, N), + PINGROUP(kb_row2_pr2, KBC, RSVD2, RSVD3, RSVD4, 0x32c4, N, N, N), + PINGROUP(kb_row3_pr3, KBC, DISPLAYA, RSVD3, DISPLAYB, 0x32c8, N, N, N), + PINGROUP(kb_row4_pr4, KBC, DISPLAYA, SPI2, DISPLAYB, 0x32cc, N, N, N), + PINGROUP(kb_row5_pr5, KBC, DISPLAYA, SPI2, DISPLAYB, 0x32d0, N, N, N), + PINGROUP(kb_row6_pr6, KBC, DISPLAYA, DISPLAYA_ALT, DISPLAYB, 0x32d4, N, N, N), + PINGROUP(kb_row7_pr7, KBC, RSVD2, CLDVFS, UARTA, 0x32d8, N, N, N), + PINGROUP(kb_row8_ps0, KBC, RSVD2, CLDVFS, UARTA, 0x32dc, N, N, N), + PINGROUP(kb_row9_ps1, KBC, RSVD2, RSVD3, UARTA, 0x32e0, N, N, N), + PINGROUP(kb_row10_ps2, KBC, RSVD2, RSVD3, UARTA, 0x32e4, N, N, N), + PINGROUP(kb_col0_pq0, KBC, USB, SPI2, EMC_DLL, 0x32fc, N, N, N), + PINGROUP(kb_col1_pq1, KBC, RSVD2, SPI2, EMC_DLL, 0x3300, N, N, N), + PINGROUP(kb_col2_pq2, KBC, RSVD2, SPI2, RSVD4, 0x3304, N, N, N), + PINGROUP(kb_col3_pq3, KBC, DISPLAYA, PWM2, UARTA, 0x3308, N, N, N), + PINGROUP(kb_col4_pq4, KBC, OWR, SDMMC3, UARTA, 0x330c, N, N, N), + PINGROUP(kb_col5_pq5, KBC, RSVD2, SDMMC1, RSVD4, 0x3310, N, N, N), + PINGROUP(kb_col6_pq6, KBC, RSVD2, SPI2, RSVD4, 0x3314, N, N, N), + PINGROUP(kb_col7_pq7, KBC, RSVD2, SPI2, RSVD4, 0x3318, N, N, N), + PINGROUP(clk_32k_out_pa0, BLINK, SOC, RSVD3, RSVD4, 0x331c, N, N, N), + PINGROUP(sys_clk_req_pz5, SYSCLK, RSVD2, RSVD3, RSVD4, 0x3320, N, N, N), + PINGROUP(core_pwr_req, PWRON, RSVD2, RSVD3, RSVD4, 0x3324, N, N, N), + PINGROUP(cpu_pwr_req, CPU, RSVD2, RSVD3, RSVD4, 0x3328, N, N, N), + PINGROUP(pwr_int_n, PMI, RSVD2, RSVD3, RSVD4, 0x332c, N, N, N), + PINGROUP(clk_32k_in, CLK, RSVD2, RSVD3, RSVD4, 0x3330, N, N, N), + PINGROUP(owr, OWR, RSVD2, RSVD3, RSVD4, 0x3334, N, N, Y), + PINGROUP(dap1_fs_pn0, I2S0, HDA, GMI, RSVD4, 0x3338, N, N, N), + PINGROUP(dap1_din_pn1, I2S0, HDA, GMI, RSVD4, 0x333c, N, N, N), + PINGROUP(dap1_dout_pn2, I2S0, HDA, GMI, RSVD4, 0x3340, N, N, N), + PINGROUP(dap1_sclk_pn3, I2S0, HDA, GMI, RSVD4, 0x3344, N, N, N), + PINGROUP(clk1_req_pee2, DAP, DAP1, RSVD3, RSVD4, 0x3348, N, N, N), + PINGROUP(clk1_out_pw4, EXTPERIPH1, DAP2, RSVD3, RSVD4, 0x334c, N, N, N), + PINGROUP(spdif_in_pk6, SPDIF, USB, RSVD3, RSVD4, 0x3350, N, N, N), + PINGROUP(spdif_out_pk5, SPDIF, RSVD2, RSVD3, RSVD4, 0x3354, N, N, N), + PINGROUP(dap2_fs_pa2, I2S1, HDA, RSVD3, RSVD4, 0x3358, N, N, N), + PINGROUP(dap2_din_pa4, I2S1, HDA, RSVD3, RSVD4, 0x335c, N, N, N), + PINGROUP(dap2_dout_pa5, I2S1, HDA, RSVD3, RSVD4, 0x3360, N, N, N), + PINGROUP(dap2_sclk_pa3, I2S1, HDA, RSVD3, RSVD4, 0x3364, N, N, N), + PINGROUP(dvfs_pwm_px0, SPI6, CLDVFS, RSVD3, RSVD4, 0x3368, N, N, N), + PINGROUP(gpio_x1_aud_px1, SPI6, RSVD2, RSVD3, RSVD4, 0x336c, N, N, N), + PINGROUP(gpio_x3_aud_px3, SPI6, SPI1, RSVD3, RSVD4, 0x3370, N, N, N), + PINGROUP(dvfs_clk_px2, SPI6, CLDVFS, RSVD3, RSVD4, 0x3374, N, N, N), + PINGROUP(gpio_x4_aud_px4, RSVD1, SPI1, SPI2, DAP2, 0x3378, N, N, N), + PINGROUP(gpio_x5_aud_px5, RSVD1, SPI1, SPI2, RSVD4, 0x337c, N, N, N), + PINGROUP(gpio_x6_aud_px6, SPI6, SPI1, SPI2, RSVD4, 0x3380, N, N, N), + PINGROUP(gpio_x7_aud_px7, RSVD1, SPI1, SPI2, RSVD4, 0x3384, N, N, N), + PINGROUP(sdmmc3_clk_pa6, SDMMC3, RSVD2, RSVD3, SPI3, 0x3390, N, N, N), + PINGROUP(sdmmc3_cmd_pa7, SDMMC3, PWM3, UARTA, SPI3, 0x3394, N, N, N), + PINGROUP(sdmmc3_dat0_pb7, SDMMC3, RSVD2, RSVD3, SPI3, 0x3398, N, N, N), + PINGROUP(sdmmc3_dat1_pb6, SDMMC3, PWM2, UARTA, SPI3, 0x339c, N, N, N), + PINGROUP(sdmmc3_dat2_pb5, SDMMC3, PWM1, DISPLAYA, SPI3, 0x33a0, N, N, N), + PINGROUP(sdmmc3_dat3_pb4, SDMMC3, PWM0, DISPLAYB, SPI3, 0x33a4, N, N, N), + PINGROUP(hdmi_cec_pee3, CEC, SDMMC3, RSVD3, SOC, 0x33e0, Y, N, N), + PINGROUP(sdmmc1_wp_n_pv3, SDMMC1, CLK12, SPI4, UARTA, 0x33e4, N, N, N), + PINGROUP(sdmmc3_cd_n_pv2, SDMMC3, OWR, RSVD3, RSVD4, 0x33e8, N, N, N), + PINGROUP(gpio_w2_aud_pw2, SPI6, RSVD2, SPI2, I2C1, 0x33ec, N, N, N), + PINGROUP(gpio_w3_aud_pw3, SPI6, SPI1, SPI2, I2C1, 0x33f0, N, N, N), + PINGROUP(usb_vbus_en0_pn4, USB, RSVD2, RSVD3, RSVD4, 0x33f4, Y, N, N), + PINGROUP(usb_vbus_en1_pn5, USB, RSVD2, RSVD3, RSVD4, 0x33f8, Y, N, N), + PINGROUP(sdmmc3_clk_lb_in_pee5, SDMMC3, RSVD2, RSVD3, RSVD4, 0x33fc, N, N, N), + PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3, RSVD2, RSVD3, RSVD4, 0x3400, N, N, N), + PINGROUP(gmi_clk_lb, SDMMC2, NAND, GMI, RSVD4, 0x3404, N, N, N), + PINGROUP(reset_out_n, RSVD1, RSVD2, RSVD3, RESET_OUT_N, 0x3408, N, N, N), /* pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w, drvtype */ DRV_PINGROUP(ao1, 0x868, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), diff --git a/drivers/pinctrl/pinctrl-tegra124.c b/drivers/pinctrl/pinctrl-tegra124.c index 73773706755b6f..e80797e200177e 100644 --- a/drivers/pinctrl/pinctrl-tegra124.c +++ b/drivers/pinctrl/pinctrl-tegra124.c @@ -1677,10 +1677,12 @@ static struct tegra_function tegra124_functions[] = { #define DRV_PINGROUP_REG_A 0x868 /* bank 0 */ #define PINGROUP_REG_A 0x3000 /* bank 1 */ -#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A) -#define PINGROUP_REG_N(r) -1 +#define PINGROUP_REG(r) ((r) - PINGROUP_REG_A) -#define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior, rcv_sel) \ +#define PINGROUP_BIT_Y(b) (b) +#define PINGROUP_BIT_N(b) (-1) + +#define PINGROUP(pg_name, f0, f1, f2, f3, r, od, ior, rcv_sel) \ { \ .name = #pg_name, \ .pins = pg_name##_pins, \ @@ -1691,38 +1693,24 @@ static struct tegra_function tegra124_functions[] = { TEGRA_MUX_##f2, \ TEGRA_MUX_##f3, \ }, \ - .func_safe = TEGRA_MUX_##f_safe, \ - .mux_reg = PINGROUP_REG_Y(r), \ + .mux_reg = PINGROUP_REG(r), \ .mux_bank = 1, \ .mux_bit = 0, \ - .pupd_reg = PINGROUP_REG_Y(r), \ + .pupd_reg = PINGROUP_REG(r), \ .pupd_bank = 1, \ .pupd_bit = 2, \ - .tri_reg = PINGROUP_REG_Y(r), \ + .tri_reg = PINGROUP_REG(r), \ .tri_bank = 1, \ .tri_bit = 4, \ - .einput_reg = PINGROUP_REG_Y(r), \ - .einput_bank = 1, \ - .einput_bit = 5, \ - .odrain_reg = PINGROUP_REG_##od(r), \ - .odrain_bank = 1, \ - .odrain_bit = 6, \ - .lock_reg = PINGROUP_REG_Y(r), \ - .lock_bank = 1, \ - .lock_bit = 7, \ - .ioreset_reg = PINGROUP_REG_##ior(r), \ - .ioreset_bank = 1, \ - .ioreset_bit = 8, \ - .rcv_sel_reg = PINGROUP_REG_##rcv_sel(r), \ - .rcv_sel_bank = 1, \ - .rcv_sel_bit = 9, \ + .einput_bit = PINGROUP_BIT_Y(5), \ + .odrain_bit = PINGROUP_BIT_##od(6), \ + .lock_bit = PINGROUP_BIT_Y(7), \ + .ioreset_bit = PINGROUP_BIT_##ior(8), \ + .rcv_sel_bit = PINGROUP_BIT_##rcv_sel(9), \ .drv_reg = -1, \ - .drvtype_reg = -1, \ } -#define DRV_PINGROUP_REG_Y(r) ((r) - DRV_PINGROUP_REG_A) -#define DRV_PINGROUP_REG_N(r) -1 - +#define DRV_PINGROUP_REG(r) ((r) - DRV_PINGROUP_REG_A) #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, \ drvdn_b, drvdn_w, drvup_b, drvup_w, \ @@ -1735,12 +1723,12 @@ static struct tegra_function tegra124_functions[] = { .mux_reg = -1, \ .pupd_reg = -1, \ .tri_reg = -1, \ - .einput_reg = -1, \ - .odrain_reg = -1, \ - .lock_reg = -1, \ - .ioreset_reg = -1, \ - .rcv_sel_reg = -1, \ - .drv_reg = DRV_PINGROUP_REG_Y(r), \ + .einput_bit = -1, \ + .odrain_bit = -1, \ + .lock_bit = -1, \ + .ioreset_bit = -1, \ + .rcv_sel_bit = -1, \ + .drv_reg = DRV_PINGROUP_REG(r), \ .drv_bank = 0, \ .hsm_bit = hsm_b, \ .schmitt_bit = schmitt_b, \ @@ -1753,246 +1741,244 @@ static struct tegra_function tegra124_functions[] = { .slwr_width = slwr_w, \ .slwf_bit = slwf_b, \ .slwf_width = slwf_w, \ - .drvtype_reg = DRV_PINGROUP_REG_##drvtype(r), \ - .drvtype_bank = 0, \ - .drvtype_bit = 6, \ + .drvtype_bit = PINGROUP_BIT_##drvtype(6), \ } static const struct tegra_pingroup tegra124_groups[] = { - /* pg_name, f0, f1, f2, f3, safe, r, od, ior, rcv_sel */ - PINGROUP(ulpi_data0_po1, SPI3, HSI, UARTA, ULPI, SPI3, 0x3000, N, N, N), - PINGROUP(ulpi_data1_po2, SPI3, HSI, UARTA, ULPI, SPI3, 0x3004, N, N, N), - PINGROUP(ulpi_data2_po3, SPI3, HSI, UARTA, ULPI, SPI3, 0x3008, N, N, N), - PINGROUP(ulpi_data3_po4, SPI3, HSI, UARTA, ULPI, SPI3, 0x300c, N, N, N), - PINGROUP(ulpi_data4_po5, SPI2, HSI, UARTA, ULPI, SPI2, 0x3010, N, N, N), - PINGROUP(ulpi_data5_po6, SPI2, HSI, UARTA, ULPI, SPI2, 0x3014, N, N, N), - PINGROUP(ulpi_data6_po7, SPI2, HSI, UARTA, ULPI, SPI2, 0x3018, N, N, N), - PINGROUP(ulpi_data7_po0, SPI2, HSI, UARTA, ULPI, SPI2, 0x301c, N, N, N), - PINGROUP(ulpi_clk_py0, SPI1, SPI5, UARTD, ULPI, SPI1, 0x3020, N, N, N), - PINGROUP(ulpi_dir_py1, SPI1, SPI5, UARTD, ULPI, SPI1, 0x3024, N, N, N), - PINGROUP(ulpi_nxt_py2, SPI1, SPI5, UARTD, ULPI, SPI1, 0x3028, N, N, N), - PINGROUP(ulpi_stp_py3, SPI1, SPI5, UARTD, ULPI, SPI1, 0x302c, N, N, N), - PINGROUP(dap3_fs_pp0, I2S2, SPI5, DISPLAYA, DISPLAYB, I2S2, 0x3030, N, N, N), - PINGROUP(dap3_din_pp1, I2S2, SPI5, DISPLAYA, DISPLAYB, I2S2, 0x3034, N, N, N), - PINGROUP(dap3_dout_pp2, I2S2, SPI5, DISPLAYA, RSVD4, I2S2, 0x3038, N, N, N), - PINGROUP(dap3_sclk_pp3, I2S2, SPI5, RSVD3, DISPLAYB, I2S2, 0x303c, N, N, N), - PINGROUP(pv0, RSVD1, RSVD2, RSVD3, RSVD4, RSVD1, 0x3040, N, N, N), - PINGROUP(pv1, RSVD1, RSVD2, RSVD3, RSVD4, RSVD1, 0x3044, N, N, N), - PINGROUP(sdmmc1_clk_pz0, SDMMC1, CLK12, RSVD3, RSVD4, RSVD3, 0x3048, N, N, N), - PINGROUP(sdmmc1_cmd_pz1, SDMMC1, SPDIF, SPI4, UARTA, SDMMC1, 0x304c, N, N, N), - PINGROUP(sdmmc1_dat3_py4, SDMMC1, SPDIF, SPI4, UARTA, SDMMC1, 0x3050, N, N, N), - PINGROUP(sdmmc1_dat2_py5, SDMMC1, PWM0, SPI4, UARTA, SDMMC1, 0x3054, N, N, N), - PINGROUP(sdmmc1_dat1_py6, SDMMC1, PWM1, SPI4, UARTA, SDMMC1, 0x3058, N, N, N), - PINGROUP(sdmmc1_dat0_py7, SDMMC1, RSVD2, SPI4, UARTA, SDMMC1, 0x305c, N, N, N), - PINGROUP(clk2_out_pw5, EXTPERIPH2, RSVD2, RSVD3, RSVD4, EXTPERIPH2, 0x3068, N, N, N), - PINGROUP(clk2_req_pcc5, DAP, RSVD2, RSVD3, RSVD4, DAP, 0x306c, N, N, N), - PINGROUP(hdmi_int_pn7, RSVD1, RSVD2, RSVD3, RSVD4, RSVD1, 0x3110, N, N, Y), - PINGROUP(ddc_scl_pv4, I2C4, RSVD2, RSVD3, RSVD4, I2C4, 0x3114, N, N, Y), - PINGROUP(ddc_sda_pv5, I2C4, RSVD2, RSVD3, RSVD4, I2C4, 0x3118, N, N, Y), - PINGROUP(uart2_rxd_pc3, IRDA, SPDIF, UARTA, SPI4, IRDA, 0x3164, N, N, N), - PINGROUP(uart2_txd_pc2, IRDA, SPDIF, UARTA, SPI4, IRDA, 0x3168, N, N, N), - PINGROUP(uart2_rts_n_pj6, UARTA, UARTB, GMI, SPI4, UARTA, 0x316c, N, N, N), - PINGROUP(uart2_cts_n_pj5, UARTA, UARTB, GMI, SPI4, UARTA, 0x3170, N, N, N), - PINGROUP(uart3_txd_pw6, UARTC, RSVD2, GMI, SPI4, UARTC, 0x3174, N, N, N), - PINGROUP(uart3_rxd_pw7, UARTC, RSVD2, GMI, SPI4, UARTC, 0x3178, N, N, N), - PINGROUP(uart3_cts_n_pa1, UARTC, SDMMC1, DTV, GMI, UARTC, 0x317c, N, N, N), - PINGROUP(uart3_rts_n_pc0, UARTC, PWM0, DTV, GMI, UARTC, 0x3180, N, N, N), - PINGROUP(pu0, OWR, UARTA, GMI, RSVD4, RSVD4, 0x3184, N, N, N), - PINGROUP(pu1, RSVD1, UARTA, GMI, RSVD4, RSVD4, 0x3188, N, N, N), - PINGROUP(pu2, RSVD1, UARTA, GMI, RSVD4, RSVD4, 0x318c, N, N, N), - PINGROUP(pu3, PWM0, UARTA, GMI, DISPLAYB, PWM0, 0x3190, N, N, N), - PINGROUP(pu4, PWM1, UARTA, GMI, DISPLAYB, PWM1, 0x3194, N, N, N), - PINGROUP(pu5, PWM2, UARTA, GMI, DISPLAYB, PWM2, 0x3198, N, N, N), - PINGROUP(pu6, PWM3, UARTA, RSVD3, GMI, RSVD3, 0x319c, N, N, N), - PINGROUP(gen1_i2c_sda_pc5, I2C1, RSVD2, RSVD3, RSVD4, I2C1, 0x31a0, Y, N, N), - PINGROUP(gen1_i2c_scl_pc4, I2C1, RSVD2, RSVD3, RSVD4, I2C1, 0x31a4, Y, N, N), - PINGROUP(dap4_fs_pp4, I2S3, GMI, DTV, RSVD4, I2S3, 0x31a8, N, N, N), - PINGROUP(dap4_din_pp5, I2S3, GMI, RSVD3, RSVD4, I2S3, 0x31ac, N, N, N), - PINGROUP(dap4_dout_pp6, I2S3, GMI, DTV, RSVD4, I2S3, 0x31b0, N, N, N), - PINGROUP(dap4_sclk_pp7, I2S3, GMI, RSVD3, RSVD4, I2S3, 0x31b4, N, N, N), - PINGROUP(clk3_out_pee0, EXTPERIPH3, RSVD2, RSVD3, RSVD4, RSVD3, 0x31b8, N, N, N), - PINGROUP(clk3_req_pee1, DEV3, RSVD2, RSVD3, RSVD4, RSVD4, 0x31bc, N, N, N), - PINGROUP(pc7, RSVD1, RSVD2, GMI, GMI_ALT, RSVD1, 0x31c0, N, N, N), - PINGROUP(pi5, SDMMC2, RSVD2, GMI, RSVD4, GMI, 0x31c4, N, N, N), - PINGROUP(pi7, RSVD1, TRACE, GMI, DTV, RSVD1, 0x31c8, N, N, N), - PINGROUP(pk0, RSVD1, SDMMC3, GMI, SOC, RSVD1, 0x31cc, N, N, N), - PINGROUP(pk1, SDMMC2, TRACE, GMI, RSVD4, GMI, 0x31d0, N, N, N), - PINGROUP(pj0, RSVD1, RSVD2, GMI, USB, RSVD1, 0x31d4, N, N, N), - PINGROUP(pj2, RSVD1, RSVD2, GMI, SOC, RSVD1, 0x31d8, N, N, N), - PINGROUP(pk3, SDMMC2, TRACE, GMI, CCLA, GMI, 0x31dc, N, N, N), - PINGROUP(pk4, SDMMC2, RSVD2, GMI, GMI_ALT, GMI, 0x31e0, N, N, N), - PINGROUP(pk2, RSVD1, RSVD2, GMI, RSVD4, RSVD4, 0x31e4, N, N, N), - PINGROUP(pi3, RSVD1, RSVD2, GMI, SPI4, RSVD1, 0x31e8, N, N, N), - PINGROUP(pi6, RSVD1, RSVD2, GMI, SDMMC2, RSVD1, 0x31ec, N, N, N), - PINGROUP(pg0, RSVD1, RSVD2, GMI, RSVD4, RSVD4, 0x31f0, N, N, N), - PINGROUP(pg1, RSVD1, RSVD2, GMI, RSVD4, RSVD4, 0x31f4, N, N, N), - PINGROUP(pg2, RSVD1, TRACE, GMI, RSVD4, RSVD4, 0x31f8, N, N, N), - PINGROUP(pg3, RSVD1, TRACE, GMI, RSVD4, RSVD4, 0x31fc, N, N, N), - PINGROUP(pg4, RSVD1, TMDS, GMI, SPI4, RSVD1, 0x3200, N, N, N), - PINGROUP(pg5, RSVD1, RSVD2, GMI, SPI4, RSVD1, 0x3204, N, N, N), - PINGROUP(pg6, RSVD1, RSVD2, GMI, SPI4, RSVD1, 0x3208, N, N, N), - PINGROUP(pg7, RSVD1, RSVD2, GMI, SPI4, RSVD1, 0x320c, N, N, N), - PINGROUP(ph0, PWM0, TRACE, GMI, DTV, GMI, 0x3210, N, N, N), - PINGROUP(ph1, PWM1, TMDS, GMI, DISPLAYA, GMI, 0x3214, N, N, N), - PINGROUP(ph2, PWM2, TMDS, GMI, CLDVFS, GMI, 0x3218, N, N, N), - PINGROUP(ph3, PWM3, SPI4, GMI, CLDVFS, GMI, 0x321c, N, N, N), - PINGROUP(ph4, SDMMC2, RSVD2, GMI, RSVD4, GMI, 0x3220, N, N, N), - PINGROUP(ph5, SDMMC2, RSVD2, GMI, RSVD4, GMI, 0x3224, N, N, N), - PINGROUP(ph6, SDMMC2, TRACE, GMI, DTV, GMI, 0x3228, N, N, N), - PINGROUP(ph7, SDMMC2, TRACE, GMI, DTV, GMI, 0x322c, N, N, N), - PINGROUP(pj7, UARTD, RSVD2, GMI, GMI_ALT, RSVD2, 0x3230, N, N, N), - PINGROUP(pb0, UARTD, RSVD2, GMI, RSVD4, RSVD2, 0x3234, N, N, N), - PINGROUP(pb1, UARTD, RSVD2, GMI, RSVD4, RSVD2, 0x3238, N, N, N), - PINGROUP(pk7, UARTD, RSVD2, GMI, RSVD4, RSVD2, 0x323c, N, N, N), - PINGROUP(pi0, RSVD1, RSVD2, GMI, RSVD4, RSVD4, 0x3240, N, N, N), - PINGROUP(pi1, RSVD1, RSVD2, GMI, RSVD4, RSVD1, 0x3244, N, N, N), - PINGROUP(pi2, SDMMC2, TRACE, GMI, RSVD4, GMI, 0x3248, N, N, N), - PINGROUP(pi4, SPI4, TRACE, GMI, DISPLAYA, GMI, 0x324c, N, N, N), - PINGROUP(gen2_i2c_scl_pt5, I2C2, RSVD2, GMI, RSVD4, RSVD2, 0x3250, Y, N, N), - PINGROUP(gen2_i2c_sda_pt6, I2C2, RSVD2, GMI, RSVD4, RSVD2, 0x3254, Y, N, N), - PINGROUP(sdmmc4_clk_pcc4, SDMMC4, RSVD2, GMI, RSVD4, RSVD2, 0x3258, N, Y, N), - PINGROUP(sdmmc4_cmd_pt7, SDMMC4, RSVD2, GMI, RSVD4, RSVD2, 0x325c, N, Y, N), - PINGROUP(sdmmc4_dat0_paa0, SDMMC4, SPI3, GMI, RSVD4, SDMMC4, 0x3260, N, Y, N), - PINGROUP(sdmmc4_dat1_paa1, SDMMC4, SPI3, GMI, RSVD4, SDMMC4, 0x3264, N, Y, N), - PINGROUP(sdmmc4_dat2_paa2, SDMMC4, SPI3, GMI, RSVD4, SDMMC4, 0x3268, N, Y, N), - PINGROUP(sdmmc4_dat3_paa3, SDMMC4, SPI3, GMI, RSVD4, SDMMC4, 0x326c, N, Y, N), - PINGROUP(sdmmc4_dat4_paa4, SDMMC4, SPI3, GMI, RSVD4, SDMMC4, 0x3270, N, Y, N), - PINGROUP(sdmmc4_dat5_paa5, SDMMC4, SPI3, RSVD3, RSVD4, SDMMC4, 0x3274, N, Y, N), - PINGROUP(sdmmc4_dat6_paa6, SDMMC4, SPI3, GMI, RSVD4, SDMMC4, 0x3278, N, Y, N), - PINGROUP(sdmmc4_dat7_paa7, SDMMC4, RSVD2, GMI, RSVD4, SDMMC4, 0x327c, N, Y, N), - PINGROUP(cam_mclk_pcc0, VI, VI_ALT1, VI_ALT3, SDMMC2, VI, 0x3284, N, N, N), - PINGROUP(pcc1, I2S4, RSVD2, RSVD3, SDMMC2, I2S4, 0x3288, N, N, N), - PINGROUP(pbb0, VGP6, VIMCLK2, SDMMC2, VIMCLK2_ALT, VGP6, 0x328c, N, N, N), - PINGROUP(cam_i2c_scl_pbb1, VGP1, I2C3, RSVD3, SDMMC2, VGP1, 0x3290, Y, N, N), - PINGROUP(cam_i2c_sda_pbb2, VGP2, I2C3, RSVD3, SDMMC2, VGP2, 0x3294, Y, N, N), - PINGROUP(pbb3, VGP3, DISPLAYA, DISPLAYB, SDMMC2, VGP3, 0x3298, N, N, N), - PINGROUP(pbb4, VGP4, DISPLAYA, DISPLAYB, SDMMC2, VGP4, 0x329c, N, N, N), - PINGROUP(pbb5, VGP5, DISPLAYA, RSVD3, SDMMC2, VGP5, 0x32a0, N, N, N), - PINGROUP(pbb6, I2S4, RSVD2, DISPLAYB, SDMMC2, I2S4, 0x32a4, N, N, N), - PINGROUP(pbb7, I2S4, RSVD2, RSVD3, SDMMC2, I2S4, 0x32a8, N, N, N), - PINGROUP(pcc2, I2S4, RSVD2, SDMMC3, SDMMC2, I2S4, 0x32ac, N, N, N), - PINGROUP(jtag_rtck, RTCK, RSVD2, RSVD3, RSVD4, RTCK, 0x32b0, N, N, N), - PINGROUP(pwr_i2c_scl_pz6, I2CPWR, RSVD2, RSVD3, RSVD4, RSVD2, 0x32b4, Y, N, N), - PINGROUP(pwr_i2c_sda_pz7, I2CPWR, RSVD2, RSVD3, RSVD4, RSVD2, 0x32b8, Y, N, N), - PINGROUP(kb_row0_pr0, KBC, RSVD2, RSVD3, RSVD4, RSVD4, 0x32bc, N, N, N), - PINGROUP(kb_row1_pr1, KBC, RSVD2, RSVD3, RSVD4, RSVD4, 0x32c0, N, N, N), - PINGROUP(kb_row2_pr2, KBC, RSVD2, RSVD3, RSVD4, RSVD4, 0x32c4, N, N, N), - PINGROUP(kb_row3_pr3, KBC, DISPLAYA, SYS, DISPLAYB, KBC, 0x32c8, N, N, N), - PINGROUP(kb_row4_pr4, KBC, DISPLAYA, RSVD3, DISPLAYB, RSVD3, 0x32cc, N, N, N), - PINGROUP(kb_row5_pr5, KBC, DISPLAYA, RSVD3, DISPLAYB, RSVD3, 0x32d0, N, N, N), - PINGROUP(kb_row6_pr6, KBC, DISPLAYA, DISPLAYA_ALT, DISPLAYB, KBC, 0x32d4, N, N, N), - PINGROUP(kb_row7_pr7, KBC, RSVD2, CLDVFS, UARTA, RSVD2, 0x32d8, N, N, N), - PINGROUP(kb_row8_ps0, KBC, RSVD2, CLDVFS, UARTA, RSVD2, 0x32dc, N, N, N), - PINGROUP(kb_row9_ps1, KBC, RSVD2, RSVD3, UARTA, KBC, 0x32e0, N, N, N), - PINGROUP(kb_row10_ps2, KBC, RSVD2, RSVD3, UARTA, KBC, 0x32e4, N, N, N), - PINGROUP(kb_row11_ps3, KBC, RSVD2, RSVD3, IRDA, RSVD3, 0x32e8, N, N, N), - PINGROUP(kb_row12_ps4, KBC, RSVD2, RSVD3, IRDA, RSVD3, 0x32ec, N, N, N), - PINGROUP(kb_row13_ps5, KBC, RSVD2, SPI2, RSVD4, RSVD4, 0x32f0, N, N, N), - PINGROUP(kb_row14_ps6, KBC, RSVD2, SPI2, RSVD4, RSVD4, 0x32f4, N, N, N), - PINGROUP(kb_row15_ps7, KBC, SOC, RSVD3, RSVD4, KBC, 0x32f8, N, N, N), - PINGROUP(kb_col0_pq0, KBC, RSVD2, SPI2, RSVD4, RSVD4, 0x32fc, N, N, N), - PINGROUP(kb_col1_pq1, KBC, RSVD2, SPI2, RSVD4, RSVD4, 0x3300, N, N, N), - PINGROUP(kb_col2_pq2, KBC, RSVD2, SPI2, RSVD4, RSVD4, 0x3304, N, N, N), - PINGROUP(kb_col3_pq3, KBC, DISPLAYA, PWM2, UARTA, KBC, 0x3308, N, N, N), - PINGROUP(kb_col4_pq4, KBC, OWR, SDMMC3, UARTA, KBC, 0x330c, N, N, N), - PINGROUP(kb_col5_pq5, KBC, RSVD2, SDMMC3, RSVD4, RSVD4, 0x3310, N, N, N), - PINGROUP(kb_col6_pq6, KBC, RSVD2, SPI2, UARTD, RSVD2, 0x3314, N, N, N), - PINGROUP(kb_col7_pq7, KBC, RSVD2, SPI2, UARTD, RSVD2, 0x3318, N, N, N), - PINGROUP(clk_32k_out_pa0, BLINK, SOC, RSVD3, RSVD4, RSVD3, 0x331c, N, N, N), - PINGROUP(core_pwr_req, PWRON, RSVD2, RSVD3, RSVD4, RSVD2, 0x3324, N, N, N), - PINGROUP(cpu_pwr_req, CPU, RSVD2, RSVD3, RSVD4, RSVD2, 0x3328, N, N, N), - PINGROUP(pwr_int_n, PMI, RSVD2, RSVD3, RSVD4, RSVD2, 0x332c, N, N, N), - PINGROUP(clk_32k_in, CLK, RSVD2, RSVD3, RSVD4, RSVD2, 0x3330, N, N, N), - PINGROUP(owr, OWR, RSVD2, RSVD3, RSVD4, RSVD2, 0x3334, N, N, Y), - PINGROUP(dap1_fs_pn0, I2S0, HDA, GMI, RSVD4, RSVD4, 0x3338, N, N, N), - PINGROUP(dap1_din_pn1, I2S0, HDA, GMI, RSVD4, RSVD4, 0x333c, N, N, N), - PINGROUP(dap1_dout_pn2, I2S0, HDA, GMI, SATA, I2S0, 0x3340, N, N, N), - PINGROUP(dap1_sclk_pn3, I2S0, HDA, GMI, RSVD4, I2S0, 0x3344, N, N, N), - PINGROUP(dap_mclk1_req_pee2, DAP, DAP1, SATA, RSVD4, DAP, 0x3348, N, N, N), - PINGROUP(dap_mclk1_pw4, EXTPERIPH1, DAP2, RSVD3, RSVD4, RSVD3, 0x334c, N, N, N), - PINGROUP(spdif_in_pk6, SPDIF, RSVD2, RSVD3, I2C3, RSVD3, 0x3350, N, N, N), - PINGROUP(spdif_out_pk5, SPDIF, RSVD2, RSVD3, I2C3, RSVD3, 0x3354, N, N, N), - PINGROUP(dap2_fs_pa2, I2S1, HDA, GMI, RSVD4, I2S1, 0x3358, N, N, N), - PINGROUP(dap2_din_pa4, I2S1, HDA, GMI, RSVD4, I2S1, 0x335c, N, N, N), - PINGROUP(dap2_dout_pa5, I2S1, HDA, GMI, RSVD4, I2S1, 0x3360, N, N, N), - PINGROUP(dap2_sclk_pa3, I2S1, HDA, GMI, RSVD4, I2S1, 0x3364, N, N, N), - PINGROUP(dvfs_pwm_px0, SPI6, CLDVFS, GMI, RSVD4, SPI6, 0x3368, N, N, N), - PINGROUP(gpio_x1_aud_px1, SPI6, RSVD2, GMI, RSVD4, SPI6, 0x336c, N, N, N), - PINGROUP(gpio_x3_aud_px3, SPI6, SPI1, GMI, RSVD4, SPI6, 0x3370, N, N, N), - PINGROUP(dvfs_clk_px2, SPI6, CLDVFS, GMI, RSVD4, SPI6, 0x3374, N, N, N), - PINGROUP(gpio_x4_aud_px4, GMI, SPI1, SPI2, DAP2, SPI1, 0x3378, N, N, N), - PINGROUP(gpio_x5_aud_px5, GMI, SPI1, SPI2, RSVD4, SPI1, 0x337c, N, N, N), - PINGROUP(gpio_x6_aud_px6, SPI6, SPI1, SPI2, GMI, SPI1, 0x3380, N, N, N), - PINGROUP(gpio_x7_aud_px7, RSVD1, SPI1, SPI2, RSVD4, SPI1, 0x3384, N, N, N), - PINGROUP(sdmmc3_clk_pa6, SDMMC3, RSVD2, RSVD3, SPI3, SDMMC3, 0x3390, N, N, N), - PINGROUP(sdmmc3_cmd_pa7, SDMMC3, PWM3, UARTA, SPI3, SDMMC3, 0x3394, N, N, N), - PINGROUP(sdmmc3_dat0_pb7, SDMMC3, RSVD2, RSVD3, SPI3, SDMMC3, 0x3398, N, N, N), - PINGROUP(sdmmc3_dat1_pb6, SDMMC3, PWM2, UARTA, SPI3, SDMMC3, 0x339c, N, N, N), - PINGROUP(sdmmc3_dat2_pb5, SDMMC3, PWM1, DISPLAYA, SPI3, SDMMC3, 0x33a0, N, N, N), - PINGROUP(sdmmc3_dat3_pb4, SDMMC3, PWM0, DISPLAYB, SPI3, SDMMC3, 0x33a4, N, N, N), - PINGROUP(pex_l0_rst_n_pdd1, PE0, RSVD2, RSVD3, RSVD4, PE0, 0x33bc, N, N, N), - PINGROUP(pex_l0_clkreq_n_pdd2, PE0, RSVD2, RSVD3, RSVD4, PE0, 0x33c0, N, N, N), - PINGROUP(pex_wake_n_pdd3, PE, RSVD2, RSVD3, RSVD4, PE, 0x33c4, N, N, N), - PINGROUP(pex_l1_rst_n_pdd5, PE1, RSVD2, RSVD3, RSVD4, PE1, 0x33cc, N, N, N), - PINGROUP(pex_l1_clkreq_n_pdd6, PE1, RSVD2, RSVD3, RSVD4, PE1, 0x33d0, N, N, N), - PINGROUP(hdmi_cec_pee3, CEC, RSVD2, RSVD3, RSVD4, CEC, 0x33e0, Y, N, N), - PINGROUP(sdmmc1_wp_n_pv3, SDMMC1, CLK12, SPI4, UARTA, SDMMC1, 0x33e4, N, N, N), - PINGROUP(sdmmc3_cd_n_pv2, SDMMC3, OWR, RSVD3, RSVD4, SDMMC3, 0x33e8, N, N, N), - PINGROUP(gpio_w2_aud_pw2, SPI6, RSVD2, SPI2, I2C1, RSVD2, 0x33ec, N, N, N), - PINGROUP(gpio_w3_aud_pw3, SPI6, SPI1, SPI2, I2C1, SPI1, 0x33f0, N, N, N), - PINGROUP(usb_vbus_en0_pn4, USB, RSVD2, RSVD3, RSVD4, USB, 0x33f4, Y, N, N), - PINGROUP(usb_vbus_en1_pn5, USB, RSVD2, RSVD3, RSVD4, USB, 0x33f8, Y, N, N), - PINGROUP(sdmmc3_clk_lb_in_pee5, SDMMC3, RSVD2, RSVD3, RSVD4, SDMMC3, 0x33fc, N, N, N), - PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3, RSVD2, RSVD3, RSVD4, SDMMC3, 0x3400, N, N, N), - PINGROUP(gmi_clk_lb, SDMMC2, RSVD2, GMI, RSVD4, SDMMC2, 0x3404, N, N, N), - PINGROUP(reset_out_n, RSVD1, RSVD2, RSVD3, RESET_OUT_N, RSVD1, 0x3408, N, N, N), - PINGROUP(kb_row16_pt0, KBC, RSVD2, RSVD3, UARTC, KBC, 0x340c, N, N, N), - PINGROUP(kb_row17_pt1, KBC, RSVD2, RSVD3, UARTC, KBC, 0x3410, N, N, N), - PINGROUP(usb_vbus_en2_pff1, USB, RSVD2, RSVD3, RSVD4, USB, 0x3414, Y, N, N), - PINGROUP(pff2, SATA, RSVD2, RSVD3, RSVD4, RSVD2, 0x3418, Y, N, N), - PINGROUP(dp_hpd_pff0, DP, RSVD2, RSVD3, RSVD4, DP, 0x3430, N, N, N), + /* pg_name, f0, f1, f2, f3, r, od, ior, rcv_sel */ + PINGROUP(ulpi_data0_po1, SPI3, HSI, UARTA, ULPI, 0x3000, N, N, N), + PINGROUP(ulpi_data1_po2, SPI3, HSI, UARTA, ULPI, 0x3004, N, N, N), + PINGROUP(ulpi_data2_po3, SPI3, HSI, UARTA, ULPI, 0x3008, N, N, N), + PINGROUP(ulpi_data3_po4, SPI3, HSI, UARTA, ULPI, 0x300c, N, N, N), + PINGROUP(ulpi_data4_po5, SPI2, HSI, UARTA, ULPI, 0x3010, N, N, N), + PINGROUP(ulpi_data5_po6, SPI2, HSI, UARTA, ULPI, 0x3014, N, N, N), + PINGROUP(ulpi_data6_po7, SPI2, HSI, UARTA, ULPI, 0x3018, N, N, N), + PINGROUP(ulpi_data7_po0, SPI2, HSI, UARTA, ULPI, 0x301c, N, N, N), + PINGROUP(ulpi_clk_py0, SPI1, SPI5, UARTD, ULPI, 0x3020, N, N, N), + PINGROUP(ulpi_dir_py1, SPI1, SPI5, UARTD, ULPI, 0x3024, N, N, N), + PINGROUP(ulpi_nxt_py2, SPI1, SPI5, UARTD, ULPI, 0x3028, N, N, N), + PINGROUP(ulpi_stp_py3, SPI1, SPI5, UARTD, ULPI, 0x302c, N, N, N), + PINGROUP(dap3_fs_pp0, I2S2, SPI5, DISPLAYA, DISPLAYB, 0x3030, N, N, N), + PINGROUP(dap3_din_pp1, I2S2, SPI5, DISPLAYA, DISPLAYB, 0x3034, N, N, N), + PINGROUP(dap3_dout_pp2, I2S2, SPI5, DISPLAYA, RSVD4, 0x3038, N, N, N), + PINGROUP(dap3_sclk_pp3, I2S2, SPI5, RSVD3, DISPLAYB, 0x303c, N, N, N), + PINGROUP(pv0, RSVD1, RSVD2, RSVD3, RSVD4, 0x3040, N, N, N), + PINGROUP(pv1, RSVD1, RSVD2, RSVD3, RSVD4, 0x3044, N, N, N), + PINGROUP(sdmmc1_clk_pz0, SDMMC1, CLK12, RSVD3, RSVD4, 0x3048, N, N, N), + PINGROUP(sdmmc1_cmd_pz1, SDMMC1, SPDIF, SPI4, UARTA, 0x304c, N, N, N), + PINGROUP(sdmmc1_dat3_py4, SDMMC1, SPDIF, SPI4, UARTA, 0x3050, N, N, N), + PINGROUP(sdmmc1_dat2_py5, SDMMC1, PWM0, SPI4, UARTA, 0x3054, N, N, N), + PINGROUP(sdmmc1_dat1_py6, SDMMC1, PWM1, SPI4, UARTA, 0x3058, N, N, N), + PINGROUP(sdmmc1_dat0_py7, SDMMC1, RSVD2, SPI4, UARTA, 0x305c, N, N, N), + PINGROUP(clk2_out_pw5, EXTPERIPH2, RSVD2, RSVD3, RSVD4, 0x3068, N, N, N), + PINGROUP(clk2_req_pcc5, DAP, RSVD2, RSVD3, RSVD4, 0x306c, N, N, N), + PINGROUP(hdmi_int_pn7, RSVD1, RSVD2, RSVD3, RSVD4, 0x3110, N, N, Y), + PINGROUP(ddc_scl_pv4, I2C4, RSVD2, RSVD3, RSVD4, 0x3114, N, N, Y), + PINGROUP(ddc_sda_pv5, I2C4, RSVD2, RSVD3, RSVD4, 0x3118, N, N, Y), + PINGROUP(uart2_rxd_pc3, IRDA, SPDIF, UARTA, SPI4, 0x3164, N, N, N), + PINGROUP(uart2_txd_pc2, IRDA, SPDIF, UARTA, SPI4, 0x3168, N, N, N), + PINGROUP(uart2_rts_n_pj6, UARTA, UARTB, GMI, SPI4, 0x316c, N, N, N), + PINGROUP(uart2_cts_n_pj5, UARTA, UARTB, GMI, SPI4, 0x3170, N, N, N), + PINGROUP(uart3_txd_pw6, UARTC, RSVD2, GMI, SPI4, 0x3174, N, N, N), + PINGROUP(uart3_rxd_pw7, UARTC, RSVD2, GMI, SPI4, 0x3178, N, N, N), + PINGROUP(uart3_cts_n_pa1, UARTC, SDMMC1, DTV, GMI, 0x317c, N, N, N), + PINGROUP(uart3_rts_n_pc0, UARTC, PWM0, DTV, GMI, 0x3180, N, N, N), + PINGROUP(pu0, OWR, UARTA, GMI, RSVD4, 0x3184, N, N, N), + PINGROUP(pu1, RSVD1, UARTA, GMI, RSVD4, 0x3188, N, N, N), + PINGROUP(pu2, RSVD1, UARTA, GMI, RSVD4, 0x318c, N, N, N), + PINGROUP(pu3, PWM0, UARTA, GMI, DISPLAYB, 0x3190, N, N, N), + PINGROUP(pu4, PWM1, UARTA, GMI, DISPLAYB, 0x3194, N, N, N), + PINGROUP(pu5, PWM2, UARTA, GMI, DISPLAYB, 0x3198, N, N, N), + PINGROUP(pu6, PWM3, UARTA, RSVD3, GMI, 0x319c, N, N, N), + PINGROUP(gen1_i2c_sda_pc5, I2C1, RSVD2, RSVD3, RSVD4, 0x31a0, Y, N, N), + PINGROUP(gen1_i2c_scl_pc4, I2C1, RSVD2, RSVD3, RSVD4, 0x31a4, Y, N, N), + PINGROUP(dap4_fs_pp4, I2S3, GMI, DTV, RSVD4, 0x31a8, N, N, N), + PINGROUP(dap4_din_pp5, I2S3, GMI, RSVD3, RSVD4, 0x31ac, N, N, N), + PINGROUP(dap4_dout_pp6, I2S3, GMI, DTV, RSVD4, 0x31b0, N, N, N), + PINGROUP(dap4_sclk_pp7, I2S3, GMI, RSVD3, RSVD4, 0x31b4, N, N, N), + PINGROUP(clk3_out_pee0, EXTPERIPH3, RSVD2, RSVD3, RSVD4, 0x31b8, N, N, N), + PINGROUP(clk3_req_pee1, DEV3, RSVD2, RSVD3, RSVD4, 0x31bc, N, N, N), + PINGROUP(pc7, RSVD1, RSVD2, GMI, GMI_ALT, 0x31c0, N, N, N), + PINGROUP(pi5, SDMMC2, RSVD2, GMI, RSVD4, 0x31c4, N, N, N), + PINGROUP(pi7, RSVD1, TRACE, GMI, DTV, 0x31c8, N, N, N), + PINGROUP(pk0, RSVD1, SDMMC3, GMI, SOC, 0x31cc, N, N, N), + PINGROUP(pk1, SDMMC2, TRACE, GMI, RSVD4, 0x31d0, N, N, N), + PINGROUP(pj0, RSVD1, RSVD2, GMI, USB, 0x31d4, N, N, N), + PINGROUP(pj2, RSVD1, RSVD2, GMI, SOC, 0x31d8, N, N, N), + PINGROUP(pk3, SDMMC2, TRACE, GMI, CCLA, 0x31dc, N, N, N), + PINGROUP(pk4, SDMMC2, RSVD2, GMI, GMI_ALT, 0x31e0, N, N, N), + PINGROUP(pk2, RSVD1, RSVD2, GMI, RSVD4, 0x31e4, N, N, N), + PINGROUP(pi3, RSVD1, RSVD2, GMI, SPI4, 0x31e8, N, N, N), + PINGROUP(pi6, RSVD1, RSVD2, GMI, SDMMC2, 0x31ec, N, N, N), + PINGROUP(pg0, RSVD1, RSVD2, GMI, RSVD4, 0x31f0, N, N, N), + PINGROUP(pg1, RSVD1, RSVD2, GMI, RSVD4, 0x31f4, N, N, N), + PINGROUP(pg2, RSVD1, TRACE, GMI, RSVD4, 0x31f8, N, N, N), + PINGROUP(pg3, RSVD1, TRACE, GMI, RSVD4, 0x31fc, N, N, N), + PINGROUP(pg4, RSVD1, TMDS, GMI, SPI4, 0x3200, N, N, N), + PINGROUP(pg5, RSVD1, RSVD2, GMI, SPI4, 0x3204, N, N, N), + PINGROUP(pg6, RSVD1, RSVD2, GMI, SPI4, 0x3208, N, N, N), + PINGROUP(pg7, RSVD1, RSVD2, GMI, SPI4, 0x320c, N, N, N), + PINGROUP(ph0, PWM0, TRACE, GMI, DTV, 0x3210, N, N, N), + PINGROUP(ph1, PWM1, TMDS, GMI, DISPLAYA, 0x3214, N, N, N), + PINGROUP(ph2, PWM2, TMDS, GMI, CLDVFS, 0x3218, N, N, N), + PINGROUP(ph3, PWM3, SPI4, GMI, CLDVFS, 0x321c, N, N, N), + PINGROUP(ph4, SDMMC2, RSVD2, GMI, RSVD4, 0x3220, N, N, N), + PINGROUP(ph5, SDMMC2, RSVD2, GMI, RSVD4, 0x3224, N, N, N), + PINGROUP(ph6, SDMMC2, TRACE, GMI, DTV, 0x3228, N, N, N), + PINGROUP(ph7, SDMMC2, TRACE, GMI, DTV, 0x322c, N, N, N), + PINGROUP(pj7, UARTD, RSVD2, GMI, GMI_ALT, 0x3230, N, N, N), + PINGROUP(pb0, UARTD, RSVD2, GMI, RSVD4, 0x3234, N, N, N), + PINGROUP(pb1, UARTD, RSVD2, GMI, RSVD4, 0x3238, N, N, N), + PINGROUP(pk7, UARTD, RSVD2, GMI, RSVD4, 0x323c, N, N, N), + PINGROUP(pi0, RSVD1, RSVD2, GMI, RSVD4, 0x3240, N, N, N), + PINGROUP(pi1, RSVD1, RSVD2, GMI, RSVD4, 0x3244, N, N, N), + PINGROUP(pi2, SDMMC2, TRACE, GMI, RSVD4, 0x3248, N, N, N), + PINGROUP(pi4, SPI4, TRACE, GMI, DISPLAYA, 0x324c, N, N, N), + PINGROUP(gen2_i2c_scl_pt5, I2C2, RSVD2, GMI, RSVD4, 0x3250, Y, N, N), + PINGROUP(gen2_i2c_sda_pt6, I2C2, RSVD2, GMI, RSVD4, 0x3254, Y, N, N), + PINGROUP(sdmmc4_clk_pcc4, SDMMC4, RSVD2, GMI, RSVD4, 0x3258, N, Y, N), + PINGROUP(sdmmc4_cmd_pt7, SDMMC4, RSVD2, GMI, RSVD4, 0x325c, N, Y, N), + PINGROUP(sdmmc4_dat0_paa0, SDMMC4, SPI3, GMI, RSVD4, 0x3260, N, Y, N), + PINGROUP(sdmmc4_dat1_paa1, SDMMC4, SPI3, GMI, RSVD4, 0x3264, N, Y, N), + PINGROUP(sdmmc4_dat2_paa2, SDMMC4, SPI3, GMI, RSVD4, 0x3268, N, Y, N), + PINGROUP(sdmmc4_dat3_paa3, SDMMC4, SPI3, GMI, RSVD4, 0x326c, N, Y, N), + PINGROUP(sdmmc4_dat4_paa4, SDMMC4, SPI3, GMI, RSVD4, 0x3270, N, Y, N), + PINGROUP(sdmmc4_dat5_paa5, SDMMC4, SPI3, RSVD3, RSVD4, 0x3274, N, Y, N), + PINGROUP(sdmmc4_dat6_paa6, SDMMC4, SPI3, GMI, RSVD4, 0x3278, N, Y, N), + PINGROUP(sdmmc4_dat7_paa7, SDMMC4, RSVD2, GMI, RSVD4, 0x327c, N, Y, N), + PINGROUP(cam_mclk_pcc0, VI, VI_ALT1, VI_ALT3, SDMMC2, 0x3284, N, N, N), + PINGROUP(pcc1, I2S4, RSVD2, RSVD3, SDMMC2, 0x3288, N, N, N), + PINGROUP(pbb0, VGP6, VIMCLK2, SDMMC2, VIMCLK2_ALT, 0x328c, N, N, N), + PINGROUP(cam_i2c_scl_pbb1, VGP1, I2C3, RSVD3, SDMMC2, 0x3290, Y, N, N), + PINGROUP(cam_i2c_sda_pbb2, VGP2, I2C3, RSVD3, SDMMC2, 0x3294, Y, N, N), + PINGROUP(pbb3, VGP3, DISPLAYA, DISPLAYB, SDMMC2, 0x3298, N, N, N), + PINGROUP(pbb4, VGP4, DISPLAYA, DISPLAYB, SDMMC2, 0x329c, N, N, N), + PINGROUP(pbb5, VGP5, DISPLAYA, RSVD3, SDMMC2, 0x32a0, N, N, N), + PINGROUP(pbb6, I2S4, RSVD2, DISPLAYB, SDMMC2, 0x32a4, N, N, N), + PINGROUP(pbb7, I2S4, RSVD2, RSVD3, SDMMC2, 0x32a8, N, N, N), + PINGROUP(pcc2, I2S4, RSVD2, SDMMC3, SDMMC2, 0x32ac, N, N, N), + PINGROUP(jtag_rtck, RTCK, RSVD2, RSVD3, RSVD4, 0x32b0, N, N, N), + PINGROUP(pwr_i2c_scl_pz6, I2CPWR, RSVD2, RSVD3, RSVD4, 0x32b4, Y, N, N), + PINGROUP(pwr_i2c_sda_pz7, I2CPWR, RSVD2, RSVD3, RSVD4, 0x32b8, Y, N, N), + PINGROUP(kb_row0_pr0, KBC, RSVD2, RSVD3, RSVD4, 0x32bc, N, N, N), + PINGROUP(kb_row1_pr1, KBC, RSVD2, RSVD3, RSVD4, 0x32c0, N, N, N), + PINGROUP(kb_row2_pr2, KBC, RSVD2, RSVD3, RSVD4, 0x32c4, N, N, N), + PINGROUP(kb_row3_pr3, KBC, DISPLAYA, SYS, DISPLAYB, 0x32c8, N, N, N), + PINGROUP(kb_row4_pr4, KBC, DISPLAYA, RSVD3, DISPLAYB, 0x32cc, N, N, N), + PINGROUP(kb_row5_pr5, KBC, DISPLAYA, RSVD3, DISPLAYB, 0x32d0, N, N, N), + PINGROUP(kb_row6_pr6, KBC, DISPLAYA, DISPLAYA_ALT, DISPLAYB, 0x32d4, N, N, N), + PINGROUP(kb_row7_pr7, KBC, RSVD2, CLDVFS, UARTA, 0x32d8, N, N, N), + PINGROUP(kb_row8_ps0, KBC, RSVD2, CLDVFS, UARTA, 0x32dc, N, N, N), + PINGROUP(kb_row9_ps1, KBC, RSVD2, RSVD3, UARTA, 0x32e0, N, N, N), + PINGROUP(kb_row10_ps2, KBC, RSVD2, RSVD3, UARTA, 0x32e4, N, N, N), + PINGROUP(kb_row11_ps3, KBC, RSVD2, RSVD3, IRDA, 0x32e8, N, N, N), + PINGROUP(kb_row12_ps4, KBC, RSVD2, RSVD3, IRDA, 0x32ec, N, N, N), + PINGROUP(kb_row13_ps5, KBC, RSVD2, SPI2, RSVD4, 0x32f0, N, N, N), + PINGROUP(kb_row14_ps6, KBC, RSVD2, SPI2, RSVD4, 0x32f4, N, N, N), + PINGROUP(kb_row15_ps7, KBC, SOC, RSVD3, RSVD4, 0x32f8, N, N, N), + PINGROUP(kb_col0_pq0, KBC, RSVD2, SPI2, RSVD4, 0x32fc, N, N, N), + PINGROUP(kb_col1_pq1, KBC, RSVD2, SPI2, RSVD4, 0x3300, N, N, N), + PINGROUP(kb_col2_pq2, KBC, RSVD2, SPI2, RSVD4, 0x3304, N, N, N), + PINGROUP(kb_col3_pq3, KBC, DISPLAYA, PWM2, UARTA, 0x3308, N, N, N), + PINGROUP(kb_col4_pq4, KBC, OWR, SDMMC3, UARTA, 0x330c, N, N, N), + PINGROUP(kb_col5_pq5, KBC, RSVD2, SDMMC3, RSVD4, 0x3310, N, N, N), + PINGROUP(kb_col6_pq6, KBC, RSVD2, SPI2, UARTD, 0x3314, N, N, N), + PINGROUP(kb_col7_pq7, KBC, RSVD2, SPI2, UARTD, 0x3318, N, N, N), + PINGROUP(clk_32k_out_pa0, BLINK, SOC, RSVD3, RSVD4, 0x331c, N, N, N), + PINGROUP(core_pwr_req, PWRON, RSVD2, RSVD3, RSVD4, 0x3324, N, N, N), + PINGROUP(cpu_pwr_req, CPU, RSVD2, RSVD3, RSVD4, 0x3328, N, N, N), + PINGROUP(pwr_int_n, PMI, RSVD2, RSVD3, RSVD4, 0x332c, N, N, N), + PINGROUP(clk_32k_in, CLK, RSVD2, RSVD3, RSVD4, 0x3330, N, N, N), + PINGROUP(owr, OWR, RSVD2, RSVD3, RSVD4, 0x3334, N, N, Y), + PINGROUP(dap1_fs_pn0, I2S0, HDA, GMI, RSVD4, 0x3338, N, N, N), + PINGROUP(dap1_din_pn1, I2S0, HDA, GMI, RSVD4, 0x333c, N, N, N), + PINGROUP(dap1_dout_pn2, I2S0, HDA, GMI, SATA, 0x3340, N, N, N), + PINGROUP(dap1_sclk_pn3, I2S0, HDA, GMI, RSVD4, 0x3344, N, N, N), + PINGROUP(dap_mclk1_req_pee2, DAP, DAP1, SATA, RSVD4, 0x3348, N, N, N), + PINGROUP(dap_mclk1_pw4, EXTPERIPH1, DAP2, RSVD3, RSVD4, 0x334c, N, N, N), + PINGROUP(spdif_in_pk6, SPDIF, RSVD2, RSVD3, I2C3, 0x3350, N, N, N), + PINGROUP(spdif_out_pk5, SPDIF, RSVD2, RSVD3, I2C3, 0x3354, N, N, N), + PINGROUP(dap2_fs_pa2, I2S1, HDA, GMI, RSVD4, 0x3358, N, N, N), + PINGROUP(dap2_din_pa4, I2S1, HDA, GMI, RSVD4, 0x335c, N, N, N), + PINGROUP(dap2_dout_pa5, I2S1, HDA, GMI, RSVD4, 0x3360, N, N, N), + PINGROUP(dap2_sclk_pa3, I2S1, HDA, GMI, RSVD4, 0x3364, N, N, N), + PINGROUP(dvfs_pwm_px0, SPI6, CLDVFS, GMI, RSVD4, 0x3368, N, N, N), + PINGROUP(gpio_x1_aud_px1, SPI6, RSVD2, GMI, RSVD4, 0x336c, N, N, N), + PINGROUP(gpio_x3_aud_px3, SPI6, SPI1, GMI, RSVD4, 0x3370, N, N, N), + PINGROUP(dvfs_clk_px2, SPI6, CLDVFS, GMI, RSVD4, 0x3374, N, N, N), + PINGROUP(gpio_x4_aud_px4, GMI, SPI1, SPI2, DAP2, 0x3378, N, N, N), + PINGROUP(gpio_x5_aud_px5, GMI, SPI1, SPI2, RSVD4, 0x337c, N, N, N), + PINGROUP(gpio_x6_aud_px6, SPI6, SPI1, SPI2, GMI, 0x3380, N, N, N), + PINGROUP(gpio_x7_aud_px7, RSVD1, SPI1, SPI2, RSVD4, 0x3384, N, N, N), + PINGROUP(sdmmc3_clk_pa6, SDMMC3, RSVD2, RSVD3, SPI3, 0x3390, N, N, N), + PINGROUP(sdmmc3_cmd_pa7, SDMMC3, PWM3, UARTA, SPI3, 0x3394, N, N, N), + PINGROUP(sdmmc3_dat0_pb7, SDMMC3, RSVD2, RSVD3, SPI3, 0x3398, N, N, N), + PINGROUP(sdmmc3_dat1_pb6, SDMMC3, PWM2, UARTA, SPI3, 0x339c, N, N, N), + PINGROUP(sdmmc3_dat2_pb5, SDMMC3, PWM1, DISPLAYA, SPI3, 0x33a0, N, N, N), + PINGROUP(sdmmc3_dat3_pb4, SDMMC3, PWM0, DISPLAYB, SPI3, 0x33a4, N, N, N), + PINGROUP(pex_l0_rst_n_pdd1, PE0, RSVD2, RSVD3, RSVD4, 0x33bc, N, N, N), + PINGROUP(pex_l0_clkreq_n_pdd2, PE0, RSVD2, RSVD3, RSVD4, 0x33c0, N, N, N), + PINGROUP(pex_wake_n_pdd3, PE, RSVD2, RSVD3, RSVD4, 0x33c4, N, N, N), + PINGROUP(pex_l1_rst_n_pdd5, PE1, RSVD2, RSVD3, RSVD4, 0x33cc, N, N, N), + PINGROUP(pex_l1_clkreq_n_pdd6, PE1, RSVD2, RSVD3, RSVD4, 0x33d0, N, N, N), + PINGROUP(hdmi_cec_pee3, CEC, RSVD2, RSVD3, RSVD4, 0x33e0, Y, N, N), + PINGROUP(sdmmc1_wp_n_pv3, SDMMC1, CLK12, SPI4, UARTA, 0x33e4, N, N, N), + PINGROUP(sdmmc3_cd_n_pv2, SDMMC3, OWR, RSVD3, RSVD4, 0x33e8, N, N, N), + PINGROUP(gpio_w2_aud_pw2, SPI6, RSVD2, SPI2, I2C1, 0x33ec, N, N, N), + PINGROUP(gpio_w3_aud_pw3, SPI6, SPI1, SPI2, I2C1, 0x33f0, N, N, N), + PINGROUP(usb_vbus_en0_pn4, USB, RSVD2, RSVD3, RSVD4, 0x33f4, Y, N, N), + PINGROUP(usb_vbus_en1_pn5, USB, RSVD2, RSVD3, RSVD4, 0x33f8, Y, N, N), + PINGROUP(sdmmc3_clk_lb_in_pee5, SDMMC3, RSVD2, RSVD3, RSVD4, 0x33fc, N, N, N), + PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3, RSVD2, RSVD3, RSVD4, 0x3400, N, N, N), + PINGROUP(gmi_clk_lb, SDMMC2, RSVD2, GMI, RSVD4, 0x3404, N, N, N), + PINGROUP(reset_out_n, RSVD1, RSVD2, RSVD3, RESET_OUT_N, 0x3408, N, N, N), + PINGROUP(kb_row16_pt0, KBC, RSVD2, RSVD3, UARTC, 0x340c, N, N, N), + PINGROUP(kb_row17_pt1, KBC, RSVD2, RSVD3, UARTC, 0x3410, N, N, N), + PINGROUP(usb_vbus_en2_pff1, USB, RSVD2, RSVD3, RSVD4, 0x3414, Y, N, N), + PINGROUP(pff2, SATA, RSVD2, RSVD3, RSVD4, 0x3418, Y, N, N), + PINGROUP(dp_hpd_pff0, DP, RSVD2, RSVD3, RSVD4, 0x3430, N, N, N), /* pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w, drvtype */ - DRV_PINGROUP(ao1, 0x868, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(ao2, 0x86c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(at1, 0x870, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), - DRV_PINGROUP(at2, 0x874, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), - DRV_PINGROUP(at3, 0x878, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), - DRV_PINGROUP(at4, 0x87c, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), - DRV_PINGROUP(at5, 0x880, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(cdev1, 0x884, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(cdev2, 0x888, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(dap1, 0x890, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(dap2, 0x894, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(dap3, 0x898, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(dap4, 0x89c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(dbg, 0x8a0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(sdio3, 0x8b0, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N), - DRV_PINGROUP(spi, 0x8b4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(uaa, 0x8b8, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(uab, 0x8bc, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(uart2, 0x8c0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(uart3, 0x8c4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(sdio1, 0x8ec, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N), - DRV_PINGROUP(ddc, 0x8fc, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(gma, 0x900, 2, 3, 4, 14, 5, 20, 5, 28, 2, 30, 2, Y), - DRV_PINGROUP(gme, 0x910, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(gmf, 0x914, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(gmg, 0x918, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(gmh, 0x91c, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(owr, 0x920, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(uda, 0x924, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(gpv, 0x928, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(dev3, 0x92c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(cec, 0x938, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(at6, 0x994, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), - DRV_PINGROUP(dap5, 0x998, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(usb_vbus_en, 0x99c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(ao3, 0x9a8, 2, 3, 4, 12, 5, -1, -1, 28, 2, -1, -1, N), - DRV_PINGROUP(ao0, 0x9b0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(hv0, 0x9b4, 2, 3, 4, 12, 5, -1, -1, 28, 2, -1, -1, N), - DRV_PINGROUP(sdio4, 0x9c4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), - DRV_PINGROUP(ao4, 0x9c8, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), + DRV_PINGROUP(ao1, 0x868, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(ao2, 0x86c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(at1, 0x870, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), + DRV_PINGROUP(at2, 0x874, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), + DRV_PINGROUP(at3, 0x878, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), + DRV_PINGROUP(at4, 0x87c, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), + DRV_PINGROUP(at5, 0x880, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(cdev1, 0x884, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(cdev2, 0x888, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(dap1, 0x890, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(dap2, 0x894, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(dap3, 0x898, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(dap4, 0x89c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(dbg, 0x8a0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(sdio3, 0x8b0, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N), + DRV_PINGROUP(spi, 0x8b4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(uaa, 0x8b8, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(uab, 0x8bc, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(uart2, 0x8c0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(uart3, 0x8c4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(sdio1, 0x8ec, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N), + DRV_PINGROUP(ddc, 0x8fc, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(gma, 0x900, 2, 3, 4, 14, 5, 20, 5, 28, 2, 30, 2, Y), + DRV_PINGROUP(gme, 0x910, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(gmf, 0x914, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(gmg, 0x918, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(gmh, 0x91c, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(owr, 0x920, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(uda, 0x924, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(gpv, 0x928, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(dev3, 0x92c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(cec, 0x938, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(at6, 0x994, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), + DRV_PINGROUP(dap5, 0x998, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(usb_vbus_en, 0x99c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(ao3, 0x9a8, 2, 3, 4, 12, 5, -1, -1, 28, 2, -1, -1, N), + DRV_PINGROUP(ao0, 0x9b0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(hv0, 0x9b4, 2, 3, 4, 12, 5, -1, -1, 28, 2, -1, -1, N), + DRV_PINGROUP(sdio4, 0x9c4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N), + DRV_PINGROUP(ao4, 0x9c8, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y), }; static const struct tegra_pinctrl_soc_data tegra124_pinctrl = { diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c index e0b5040883873e..7563ebc9c791a7 100644 --- a/drivers/pinctrl/pinctrl-tegra20.c +++ b/drivers/pinctrl/pinctrl-tegra20.c @@ -1973,7 +1973,7 @@ static struct tegra_function tegra20_functions[] = { #define PINGROUP_REG_A 0x868 /* Pin group with mux control, and typically tri-state and pull-up/down too */ -#define MUX_PG(pg_name, f0, f1, f2, f3, f_safe, \ +#define MUX_PG(pg_name, f0, f1, f2, f3, \ tri_r, tri_b, mux_r, mux_b, pupd_r, pupd_b) \ { \ .name = #pg_name, \ @@ -1985,7 +1985,6 @@ static struct tegra_function tegra20_functions[] = { TEGRA_MUX_ ## f2, \ TEGRA_MUX_ ## f3, \ }, \ - .func_safe = TEGRA_MUX_ ## f_safe, \ .mux_reg = ((mux_r) - PIN_MUX_CTL_REG_A), \ .mux_bank = 1, \ .mux_bit = mux_b, \ @@ -1995,13 +1994,12 @@ static struct tegra_function tegra20_functions[] = { .tri_reg = ((tri_r) - TRISTATE_REG_A), \ .tri_bank = 0, \ .tri_bit = tri_b, \ - .einput_reg = -1, \ - .odrain_reg = -1, \ - .lock_reg = -1, \ - .ioreset_reg = -1, \ - .rcv_sel_reg = -1, \ + .einput_bit = -1, \ + .odrain_bit = -1, \ + .lock_bit = -1, \ + .ioreset_bit = -1, \ + .rcv_sel_bit = -1, \ .drv_reg = -1, \ - .drvtype_reg = -1, \ } /* Pin groups with only pull up and pull down control */ @@ -2014,14 +2012,7 @@ static struct tegra_function tegra20_functions[] = { .pupd_reg = ((pupd_r) - PULLUPDOWN_REG_A), \ .pupd_bank = 2, \ .pupd_bit = pupd_b, \ - .tri_reg = -1, \ - .einput_reg = -1, \ - .odrain_reg = -1, \ - .lock_reg = -1, \ - .ioreset_reg = -1, \ - .rcv_sel_reg = -1, \ .drv_reg = -1, \ - .drvtype_reg = -1, \ } /* Pin groups for drive strength registers (configurable version) */ @@ -2035,11 +2026,6 @@ static struct tegra_function tegra20_functions[] = { .mux_reg = -1, \ .pupd_reg = -1, \ .tri_reg = -1, \ - .einput_reg = -1, \ - .odrain_reg = -1, \ - .lock_reg = -1, \ - .ioreset_reg = -1, \ - .rcv_sel_reg = -1, \ .drv_reg = ((r) - PINGROUP_REG_A), \ .drv_bank = 3, \ .hsm_bit = hsm_b, \ @@ -2053,7 +2039,7 @@ static struct tegra_function tegra20_functions[] = { .slwr_width = slwr_w, \ .slwf_bit = slwf_b, \ .slwf_width = slwf_w, \ - .drvtype_reg = -1, \ + .drvtype_bit = -1, \ } /* Pin groups for drive strength registers (simple version) */ @@ -2061,114 +2047,114 @@ static struct tegra_function tegra20_functions[] = { DRV_PG_EXT(pg_name, r, 2, 3, 4, 12, 20, 28, 2, 30, 2) static const struct tegra_pingroup tegra20_groups[] = { - /* name, f0, f1, f2, f3, f_safe, tri r/b, mux r/b, pupd r/b */ - MUX_PG(ata, IDE, NAND, GMI, RSVD4, IDE, 0x14, 0, 0x80, 24, 0xa0, 0), - MUX_PG(atb, IDE, NAND, GMI, SDIO4, IDE, 0x14, 1, 0x80, 16, 0xa0, 2), - MUX_PG(atc, IDE, NAND, GMI, SDIO4, IDE, 0x14, 2, 0x80, 22, 0xa0, 4), - MUX_PG(atd, IDE, NAND, GMI, SDIO4, IDE, 0x14, 3, 0x80, 20, 0xa0, 6), - MUX_PG(ate, IDE, NAND, GMI, RSVD4, IDE, 0x18, 25, 0x80, 12, 0xa0, 8), - MUX_PG(cdev1, OSC, PLLA_OUT, PLLM_OUT1, AUDIO_SYNC, OSC, 0x14, 4, 0x88, 2, 0xa8, 0), - MUX_PG(cdev2, OSC, AHB_CLK, APB_CLK, PLLP_OUT4, OSC, 0x14, 5, 0x88, 4, 0xa8, 2), - MUX_PG(crtp, CRT, RSVD2, RSVD3, RSVD4, RSVD2, 0x20, 14, 0x98, 20, 0xa4, 24), - MUX_PG(csus, PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK, PLLC_OUT1, 0x14, 6, 0x88, 6, 0xac, 24), - MUX_PG(dap1, DAP1, RSVD2, GMI, SDIO2, DAP1, 0x14, 7, 0x88, 20, 0xa0, 10), - MUX_PG(dap2, DAP2, TWC, RSVD3, GMI, DAP2, 0x14, 8, 0x88, 22, 0xa0, 12), - MUX_PG(dap3, DAP3, RSVD2, RSVD3, RSVD4, DAP3, 0x14, 9, 0x88, 24, 0xa0, 14), - MUX_PG(dap4, DAP4, RSVD2, GMI, RSVD4, DAP4, 0x14, 10, 0x88, 26, 0xa0, 16), - MUX_PG(ddc, I2C2, RSVD2, RSVD3, RSVD4, RSVD4, 0x18, 31, 0x88, 0, 0xb0, 28), - MUX_PG(dta, RSVD1, SDIO2, VI, RSVD4, RSVD4, 0x14, 11, 0x84, 20, 0xa0, 18), - MUX_PG(dtb, RSVD1, RSVD2, VI, SPI1, RSVD1, 0x14, 12, 0x84, 22, 0xa0, 20), - MUX_PG(dtc, RSVD1, RSVD2, VI, RSVD4, RSVD1, 0x14, 13, 0x84, 26, 0xa0, 22), - MUX_PG(dtd, RSVD1, SDIO2, VI, RSVD4, RSVD1, 0x14, 14, 0x84, 28, 0xa0, 24), - MUX_PG(dte, RSVD1, RSVD2, VI, SPI1, RSVD1, 0x14, 15, 0x84, 30, 0xa0, 26), - MUX_PG(dtf, I2C3, RSVD2, VI, RSVD4, RSVD4, 0x20, 12, 0x98, 30, 0xa0, 28), - MUX_PG(gma, UARTE, SPI3, GMI, SDIO4, SPI3, 0x14, 28, 0x84, 0, 0xb0, 20), - MUX_PG(gmb, IDE, NAND, GMI, GMI_INT, GMI, 0x18, 29, 0x88, 28, 0xb0, 22), - MUX_PG(gmc, UARTD, SPI4, GMI, SFLASH, SPI4, 0x14, 29, 0x84, 2, 0xb0, 24), - MUX_PG(gmd, RSVD1, NAND, GMI, SFLASH, GMI, 0x18, 30, 0x88, 30, 0xb0, 26), - MUX_PG(gme, RSVD1, DAP5, GMI, SDIO4, GMI, 0x18, 0, 0x8c, 0, 0xa8, 24), - MUX_PG(gpu, PWM, UARTA, GMI, RSVD4, RSVD4, 0x14, 16, 0x8c, 4, 0xa4, 20), - MUX_PG(gpu7, RTCK, RSVD2, RSVD3, RSVD4, RTCK, 0x20, 11, 0x98, 28, 0xa4, 6), - MUX_PG(gpv, PCIE, RSVD2, RSVD3, RSVD4, PCIE, 0x14, 17, 0x8c, 2, 0xa0, 30), - MUX_PG(hdint, HDMI, RSVD2, RSVD3, RSVD4, HDMI, 0x1c, 23, 0x84, 4, -1, -1), - MUX_PG(i2cp, I2CP, RSVD2, RSVD3, RSVD4, RSVD4, 0x14, 18, 0x88, 8, 0xa4, 2), - MUX_PG(irrx, UARTA, UARTB, GMI, SPI4, UARTB, 0x14, 20, 0x88, 18, 0xa8, 22), - MUX_PG(irtx, UARTA, UARTB, GMI, SPI4, UARTB, 0x14, 19, 0x88, 16, 0xa8, 20), - MUX_PG(kbca, KBC, NAND, SDIO2, EMC_TEST0_DLL, KBC, 0x14, 22, 0x88, 10, 0xa4, 8), - MUX_PG(kbcb, KBC, NAND, SDIO2, MIO, KBC, 0x14, 21, 0x88, 12, 0xa4, 10), - MUX_PG(kbcc, KBC, NAND, TRACE, EMC_TEST1_DLL, KBC, 0x18, 26, 0x88, 14, 0xa4, 12), - MUX_PG(kbcd, KBC, NAND, SDIO2, MIO, KBC, 0x20, 10, 0x98, 26, 0xa4, 14), - MUX_PG(kbce, KBC, NAND, OWR, RSVD4, KBC, 0x14, 26, 0x80, 28, 0xb0, 2), - MUX_PG(kbcf, KBC, NAND, TRACE, MIO, KBC, 0x14, 27, 0x80, 26, 0xb0, 0), - MUX_PG(lcsn, DISPLAYA, DISPLAYB, SPI3, RSVD4, RSVD4, 0x1c, 31, 0x90, 12, -1, -1), - MUX_PG(ld0, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 0, 0x94, 0, -1, -1), - MUX_PG(ld1, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 1, 0x94, 2, -1, -1), - MUX_PG(ld2, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 2, 0x94, 4, -1, -1), - MUX_PG(ld3, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 3, 0x94, 6, -1, -1), - MUX_PG(ld4, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 4, 0x94, 8, -1, -1), - MUX_PG(ld5, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 5, 0x94, 10, -1, -1), - MUX_PG(ld6, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 6, 0x94, 12, -1, -1), - MUX_PG(ld7, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 7, 0x94, 14, -1, -1), - MUX_PG(ld8, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 8, 0x94, 16, -1, -1), - MUX_PG(ld9, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 9, 0x94, 18, -1, -1), - MUX_PG(ld10, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 10, 0x94, 20, -1, -1), - MUX_PG(ld11, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 11, 0x94, 22, -1, -1), - MUX_PG(ld12, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 12, 0x94, 24, -1, -1), - MUX_PG(ld13, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 13, 0x94, 26, -1, -1), - MUX_PG(ld14, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 14, 0x94, 28, -1, -1), - MUX_PG(ld15, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 15, 0x94, 30, -1, -1), - MUX_PG(ld16, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 16, 0x98, 0, -1, -1), - MUX_PG(ld17, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x1c, 17, 0x98, 2, -1, -1), - MUX_PG(ldc, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x1c, 30, 0x90, 14, -1, -1), - MUX_PG(ldi, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x20, 6, 0x98, 16, -1, -1), - MUX_PG(lhp0, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x1c, 18, 0x98, 10, -1, -1), - MUX_PG(lhp1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x1c, 19, 0x98, 4, -1, -1), - MUX_PG(lhp2, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x1c, 20, 0x98, 6, -1, -1), - MUX_PG(lhs, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x20, 7, 0x90, 22, -1, -1), - MUX_PG(lm0, DISPLAYA, DISPLAYB, SPI3, RSVD4, RSVD4, 0x1c, 24, 0x90, 26, -1, -1), - MUX_PG(lm1, DISPLAYA, DISPLAYB, RSVD3, CRT, RSVD3, 0x1c, 25, 0x90, 28, -1, -1), - MUX_PG(lpp, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x20, 8, 0x98, 14, -1, -1), - MUX_PG(lpw0, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 3, 0x90, 0, -1, -1), - MUX_PG(lpw1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x20, 4, 0x90, 2, -1, -1), - MUX_PG(lpw2, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 5, 0x90, 4, -1, -1), - MUX_PG(lsc0, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 27, 0x90, 18, -1, -1), - MUX_PG(lsc1, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x1c, 28, 0x90, 20, -1, -1), - MUX_PG(lsck, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x1c, 29, 0x90, 16, -1, -1), - MUX_PG(lsda, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 1, 0x90, 8, -1, -1), - MUX_PG(lsdi, DISPLAYA, DISPLAYB, SPI3, RSVD4, DISPLAYA, 0x20, 2, 0x90, 6, -1, -1), - MUX_PG(lspi, DISPLAYA, DISPLAYB, XIO, HDMI, DISPLAYA, 0x20, 0, 0x90, 10, -1, -1), - MUX_PG(lvp0, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x1c, 21, 0x90, 30, -1, -1), - MUX_PG(lvp1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x1c, 22, 0x98, 8, -1, -1), - MUX_PG(lvs, DISPLAYA, DISPLAYB, XIO, RSVD4, RSVD4, 0x1c, 26, 0x90, 24, -1, -1), - MUX_PG(owc, OWR, RSVD2, RSVD3, RSVD4, OWR, 0x14, 31, 0x84, 8, 0xb0, 30), - MUX_PG(pmc, PWR_ON, PWR_INTR, RSVD3, RSVD4, PWR_ON, 0x14, 23, 0x98, 18, -1, -1), - MUX_PG(pta, I2C2, HDMI, GMI, RSVD4, RSVD4, 0x14, 24, 0x98, 22, 0xa4, 4), - MUX_PG(rm, I2C1, RSVD2, RSVD3, RSVD4, RSVD4, 0x14, 25, 0x80, 14, 0xa4, 0), - MUX_PG(sdb, UARTA, PWM, SDIO3, SPI2, PWM, 0x20, 15, 0x8c, 10, -1, -1), - MUX_PG(sdc, PWM, TWC, SDIO3, SPI3, TWC, 0x18, 1, 0x8c, 12, 0xac, 28), - MUX_PG(sdd, UARTA, PWM, SDIO3, SPI3, PWM, 0x18, 2, 0x8c, 14, 0xac, 30), - MUX_PG(sdio1, SDIO1, RSVD2, UARTE, UARTA, RSVD2, 0x14, 30, 0x80, 30, 0xb0, 18), - MUX_PG(slxa, PCIE, SPI4, SDIO3, SPI2, PCIE, 0x18, 3, 0x84, 6, 0xa4, 22), - MUX_PG(slxc, SPDIF, SPI4, SDIO3, SPI2, SPI4, 0x18, 5, 0x84, 10, 0xa4, 26), - MUX_PG(slxd, SPDIF, SPI4, SDIO3, SPI2, SPI4, 0x18, 6, 0x84, 12, 0xa4, 28), - MUX_PG(slxk, PCIE, SPI4, SDIO3, SPI2, PCIE, 0x18, 7, 0x84, 14, 0xa4, 30), - MUX_PG(spdi, SPDIF, RSVD2, I2C1, SDIO2, RSVD2, 0x18, 8, 0x8c, 8, 0xa4, 16), - MUX_PG(spdo, SPDIF, RSVD2, I2C1, SDIO2, RSVD2, 0x18, 9, 0x8c, 6, 0xa4, 18), - MUX_PG(spia, SPI1, SPI2, SPI3, GMI, GMI, 0x18, 10, 0x8c, 30, 0xa8, 4), - MUX_PG(spib, SPI1, SPI2, SPI3, GMI, GMI, 0x18, 11, 0x8c, 28, 0xa8, 6), - MUX_PG(spic, SPI1, SPI2, SPI3, GMI, GMI, 0x18, 12, 0x8c, 26, 0xa8, 8), - MUX_PG(spid, SPI2, SPI1, SPI2_ALT, GMI, GMI, 0x18, 13, 0x8c, 24, 0xa8, 10), - MUX_PG(spie, SPI2, SPI1, SPI2_ALT, GMI, GMI, 0x18, 14, 0x8c, 22, 0xa8, 12), - MUX_PG(spif, SPI3, SPI1, SPI2, RSVD4, RSVD4, 0x18, 15, 0x8c, 20, 0xa8, 14), - MUX_PG(spig, SPI3, SPI2, SPI2_ALT, I2C1, SPI2_ALT, 0x18, 16, 0x8c, 18, 0xa8, 16), - MUX_PG(spih, SPI3, SPI2, SPI2_ALT, I2C1, SPI2_ALT, 0x18, 17, 0x8c, 16, 0xa8, 18), - MUX_PG(uaa, SPI3, MIPI_HS, UARTA, ULPI, MIPI_HS, 0x18, 18, 0x80, 0, 0xac, 0), - MUX_PG(uab, SPI2, MIPI_HS, UARTA, ULPI, MIPI_HS, 0x18, 19, 0x80, 2, 0xac, 2), - MUX_PG(uac, OWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x18, 20, 0x80, 4, 0xac, 4), - MUX_PG(uad, IRDA, SPDIF, UARTA, SPI4, SPDIF, 0x18, 21, 0x80, 6, 0xac, 6), - MUX_PG(uca, UARTC, RSVD2, GMI, RSVD4, RSVD4, 0x18, 22, 0x84, 16, 0xac, 8), - MUX_PG(ucb, UARTC, PWM, GMI, RSVD4, RSVD4, 0x18, 23, 0x84, 18, 0xac, 10), - MUX_PG(uda, SPI1, RSVD2, UARTD, ULPI, RSVD2, 0x20, 13, 0x80, 8, 0xb0, 16), + /* name, f0, f1, f2, f3, tri r/b, mux r/b, pupd r/b */ + MUX_PG(ata, IDE, NAND, GMI, RSVD4, 0x14, 0, 0x80, 24, 0xa0, 0), + MUX_PG(atb, IDE, NAND, GMI, SDIO4, 0x14, 1, 0x80, 16, 0xa0, 2), + MUX_PG(atc, IDE, NAND, GMI, SDIO4, 0x14, 2, 0x80, 22, 0xa0, 4), + MUX_PG(atd, IDE, NAND, GMI, SDIO4, 0x14, 3, 0x80, 20, 0xa0, 6), + MUX_PG(ate, IDE, NAND, GMI, RSVD4, 0x18, 25, 0x80, 12, 0xa0, 8), + MUX_PG(cdev1, OSC, PLLA_OUT, PLLM_OUT1, AUDIO_SYNC, 0x14, 4, 0x88, 2, 0xa8, 0), + MUX_PG(cdev2, OSC, AHB_CLK, APB_CLK, PLLP_OUT4, 0x14, 5, 0x88, 4, 0xa8, 2), + MUX_PG(crtp, CRT, RSVD2, RSVD3, RSVD4, 0x20, 14, 0x98, 20, 0xa4, 24), + MUX_PG(csus, PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK, 0x14, 6, 0x88, 6, 0xac, 24), + MUX_PG(dap1, DAP1, RSVD2, GMI, SDIO2, 0x14, 7, 0x88, 20, 0xa0, 10), + MUX_PG(dap2, DAP2, TWC, RSVD3, GMI, 0x14, 8, 0x88, 22, 0xa0, 12), + MUX_PG(dap3, DAP3, RSVD2, RSVD3, RSVD4, 0x14, 9, 0x88, 24, 0xa0, 14), + MUX_PG(dap4, DAP4, RSVD2, GMI, RSVD4, 0x14, 10, 0x88, 26, 0xa0, 16), + MUX_PG(ddc, I2C2, RSVD2, RSVD3, RSVD4, 0x18, 31, 0x88, 0, 0xb0, 28), + MUX_PG(dta, RSVD1, SDIO2, VI, RSVD4, 0x14, 11, 0x84, 20, 0xa0, 18), + MUX_PG(dtb, RSVD1, RSVD2, VI, SPI1, 0x14, 12, 0x84, 22, 0xa0, 20), + MUX_PG(dtc, RSVD1, RSVD2, VI, RSVD4, 0x14, 13, 0x84, 26, 0xa0, 22), + MUX_PG(dtd, RSVD1, SDIO2, VI, RSVD4, 0x14, 14, 0x84, 28, 0xa0, 24), + MUX_PG(dte, RSVD1, RSVD2, VI, SPI1, 0x14, 15, 0x84, 30, 0xa0, 26), + MUX_PG(dtf, I2C3, RSVD2, VI, RSVD4, 0x20, 12, 0x98, 30, 0xa0, 28), + MUX_PG(gma, UARTE, SPI3, GMI, SDIO4, 0x14, 28, 0x84, 0, 0xb0, 20), + MUX_PG(gmb, IDE, NAND, GMI, GMI_INT, 0x18, 29, 0x88, 28, 0xb0, 22), + MUX_PG(gmc, UARTD, SPI4, GMI, SFLASH, 0x14, 29, 0x84, 2, 0xb0, 24), + MUX_PG(gmd, RSVD1, NAND, GMI, SFLASH, 0x18, 30, 0x88, 30, 0xb0, 26), + MUX_PG(gme, RSVD1, DAP5, GMI, SDIO4, 0x18, 0, 0x8c, 0, 0xa8, 24), + MUX_PG(gpu, PWM, UARTA, GMI, RSVD4, 0x14, 16, 0x8c, 4, 0xa4, 20), + MUX_PG(gpu7, RTCK, RSVD2, RSVD3, RSVD4, 0x20, 11, 0x98, 28, 0xa4, 6), + MUX_PG(gpv, PCIE, RSVD2, RSVD3, RSVD4, 0x14, 17, 0x8c, 2, 0xa0, 30), + MUX_PG(hdint, HDMI, RSVD2, RSVD3, RSVD4, 0x1c, 23, 0x84, 4, -1, -1), + MUX_PG(i2cp, I2CP, RSVD2, RSVD3, RSVD4, 0x14, 18, 0x88, 8, 0xa4, 2), + MUX_PG(irrx, UARTA, UARTB, GMI, SPI4, 0x14, 20, 0x88, 18, 0xa8, 22), + MUX_PG(irtx, UARTA, UARTB, GMI, SPI4, 0x14, 19, 0x88, 16, 0xa8, 20), + MUX_PG(kbca, KBC, NAND, SDIO2, EMC_TEST0_DLL, 0x14, 22, 0x88, 10, 0xa4, 8), + MUX_PG(kbcb, KBC, NAND, SDIO2, MIO, 0x14, 21, 0x88, 12, 0xa4, 10), + MUX_PG(kbcc, KBC, NAND, TRACE, EMC_TEST1_DLL, 0x18, 26, 0x88, 14, 0xa4, 12), + MUX_PG(kbcd, KBC, NAND, SDIO2, MIO, 0x20, 10, 0x98, 26, 0xa4, 14), + MUX_PG(kbce, KBC, NAND, OWR, RSVD4, 0x14, 26, 0x80, 28, 0xb0, 2), + MUX_PG(kbcf, KBC, NAND, TRACE, MIO, 0x14, 27, 0x80, 26, 0xb0, 0), + MUX_PG(lcsn, DISPLAYA, DISPLAYB, SPI3, RSVD4, 0x1c, 31, 0x90, 12, -1, -1), + MUX_PG(ld0, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 0, 0x94, 0, -1, -1), + MUX_PG(ld1, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 1, 0x94, 2, -1, -1), + MUX_PG(ld2, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 2, 0x94, 4, -1, -1), + MUX_PG(ld3, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 3, 0x94, 6, -1, -1), + MUX_PG(ld4, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 4, 0x94, 8, -1, -1), + MUX_PG(ld5, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 5, 0x94, 10, -1, -1), + MUX_PG(ld6, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 6, 0x94, 12, -1, -1), + MUX_PG(ld7, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 7, 0x94, 14, -1, -1), + MUX_PG(ld8, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 8, 0x94, 16, -1, -1), + MUX_PG(ld9, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 9, 0x94, 18, -1, -1), + MUX_PG(ld10, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 10, 0x94, 20, -1, -1), + MUX_PG(ld11, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 11, 0x94, 22, -1, -1), + MUX_PG(ld12, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 12, 0x94, 24, -1, -1), + MUX_PG(ld13, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 13, 0x94, 26, -1, -1), + MUX_PG(ld14, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 14, 0x94, 28, -1, -1), + MUX_PG(ld15, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 15, 0x94, 30, -1, -1), + MUX_PG(ld16, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 16, 0x98, 0, -1, -1), + MUX_PG(ld17, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x1c, 17, 0x98, 2, -1, -1), + MUX_PG(ldc, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x1c, 30, 0x90, 14, -1, -1), + MUX_PG(ldi, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x20, 6, 0x98, 16, -1, -1), + MUX_PG(lhp0, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x1c, 18, 0x98, 10, -1, -1), + MUX_PG(lhp1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x1c, 19, 0x98, 4, -1, -1), + MUX_PG(lhp2, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x1c, 20, 0x98, 6, -1, -1), + MUX_PG(lhs, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x20, 7, 0x90, 22, -1, -1), + MUX_PG(lm0, DISPLAYA, DISPLAYB, SPI3, RSVD4, 0x1c, 24, 0x90, 26, -1, -1), + MUX_PG(lm1, DISPLAYA, DISPLAYB, RSVD3, CRT, 0x1c, 25, 0x90, 28, -1, -1), + MUX_PG(lpp, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x20, 8, 0x98, 14, -1, -1), + MUX_PG(lpw0, DISPLAYA, DISPLAYB, SPI3, HDMI, 0x20, 3, 0x90, 0, -1, -1), + MUX_PG(lpw1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x20, 4, 0x90, 2, -1, -1), + MUX_PG(lpw2, DISPLAYA, DISPLAYB, SPI3, HDMI, 0x20, 5, 0x90, 4, -1, -1), + MUX_PG(lsc0, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 27, 0x90, 18, -1, -1), + MUX_PG(lsc1, DISPLAYA, DISPLAYB, SPI3, HDMI, 0x1c, 28, 0x90, 20, -1, -1), + MUX_PG(lsck, DISPLAYA, DISPLAYB, SPI3, HDMI, 0x1c, 29, 0x90, 16, -1, -1), + MUX_PG(lsda, DISPLAYA, DISPLAYB, SPI3, HDMI, 0x20, 1, 0x90, 8, -1, -1), + MUX_PG(lsdi, DISPLAYA, DISPLAYB, SPI3, RSVD4, 0x20, 2, 0x90, 6, -1, -1), + MUX_PG(lspi, DISPLAYA, DISPLAYB, XIO, HDMI, 0x20, 0, 0x90, 10, -1, -1), + MUX_PG(lvp0, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x1c, 21, 0x90, 30, -1, -1), + MUX_PG(lvp1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x1c, 22, 0x98, 8, -1, -1), + MUX_PG(lvs, DISPLAYA, DISPLAYB, XIO, RSVD4, 0x1c, 26, 0x90, 24, -1, -1), + MUX_PG(owc, OWR, RSVD2, RSVD3, RSVD4, 0x14, 31, 0x84, 8, 0xb0, 30), + MUX_PG(pmc, PWR_ON, PWR_INTR, RSVD3, RSVD4, 0x14, 23, 0x98, 18, -1, -1), + MUX_PG(pta, I2C2, HDMI, GMI, RSVD4, 0x14, 24, 0x98, 22, 0xa4, 4), + MUX_PG(rm, I2C1, RSVD2, RSVD3, RSVD4, 0x14, 25, 0x80, 14, 0xa4, 0), + MUX_PG(sdb, UARTA, PWM, SDIO3, SPI2, 0x20, 15, 0x8c, 10, -1, -1), + MUX_PG(sdc, PWM, TWC, SDIO3, SPI3, 0x18, 1, 0x8c, 12, 0xac, 28), + MUX_PG(sdd, UARTA, PWM, SDIO3, SPI3, 0x18, 2, 0x8c, 14, 0xac, 30), + MUX_PG(sdio1, SDIO1, RSVD2, UARTE, UARTA, 0x14, 30, 0x80, 30, 0xb0, 18), + MUX_PG(slxa, PCIE, SPI4, SDIO3, SPI2, 0x18, 3, 0x84, 6, 0xa4, 22), + MUX_PG(slxc, SPDIF, SPI4, SDIO3, SPI2, 0x18, 5, 0x84, 10, 0xa4, 26), + MUX_PG(slxd, SPDIF, SPI4, SDIO3, SPI2, 0x18, 6, 0x84, 12, 0xa4, 28), + MUX_PG(slxk, PCIE, SPI4, SDIO3, SPI2, 0x18, 7, 0x84, 14, 0xa4, 30), + MUX_PG(spdi, SPDIF, RSVD2, I2C1, SDIO2, 0x18, 8, 0x8c, 8, 0xa4, 16), + MUX_PG(spdo, SPDIF, RSVD2, I2C1, SDIO2, 0x18, 9, 0x8c, 6, 0xa4, 18), + MUX_PG(spia, SPI1, SPI2, SPI3, GMI, 0x18, 10, 0x8c, 30, 0xa8, 4), + MUX_PG(spib, SPI1, SPI2, SPI3, GMI, 0x18, 11, 0x8c, 28, 0xa8, 6), + MUX_PG(spic, SPI1, SPI2, SPI3, GMI, 0x18, 12, 0x8c, 26, 0xa8, 8), + MUX_PG(spid, SPI2, SPI1, SPI2_ALT, GMI, 0x18, 13, 0x8c, 24, 0xa8, 10), + MUX_PG(spie, SPI2, SPI1, SPI2_ALT, GMI, 0x18, 14, 0x8c, 22, 0xa8, 12), + MUX_PG(spif, SPI3, SPI1, SPI2, RSVD4, 0x18, 15, 0x8c, 20, 0xa8, 14), + MUX_PG(spig, SPI3, SPI2, SPI2_ALT, I2C1, 0x18, 16, 0x8c, 18, 0xa8, 16), + MUX_PG(spih, SPI3, SPI2, SPI2_ALT, I2C1, 0x18, 17, 0x8c, 16, 0xa8, 18), + MUX_PG(uaa, SPI3, MIPI_HS, UARTA, ULPI, 0x18, 18, 0x80, 0, 0xac, 0), + MUX_PG(uab, SPI2, MIPI_HS, UARTA, ULPI, 0x18, 19, 0x80, 2, 0xac, 2), + MUX_PG(uac, OWR, RSVD2, RSVD3, RSVD4, 0x18, 20, 0x80, 4, 0xac, 4), + MUX_PG(uad, IRDA, SPDIF, UARTA, SPI4, 0x18, 21, 0x80, 6, 0xac, 6), + MUX_PG(uca, UARTC, RSVD2, GMI, RSVD4, 0x18, 22, 0x84, 16, 0xac, 8), + MUX_PG(ucb, UARTC, PWM, GMI, RSVD4, 0x18, 23, 0x84, 18, 0xac, 10), + MUX_PG(uda, SPI1, RSVD2, UARTD, ULPI, 0x20, 13, 0x80, 8, 0xb0, 16), /* pg_name, pupd_r/b */ PULL_PG(ck32, 0xb0, 14), PULL_PG(ddrc, 0xac, 26), diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c index 41d24f5c285409..fe2d2cf78ad9f5 100644 --- a/drivers/pinctrl/pinctrl-tegra30.c +++ b/drivers/pinctrl/pinctrl-tegra30.c @@ -2108,10 +2108,12 @@ static struct tegra_function tegra30_functions[] = { #define DRV_PINGROUP_REG_A 0x868 /* bank 0 */ #define PINGROUP_REG_A 0x3000 /* bank 1 */ -#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A) -#define PINGROUP_REG_N(r) -1 +#define PINGROUP_REG(r) ((r) - PINGROUP_REG_A) -#define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior) \ +#define PINGROUP_BIT_Y(b) (b) +#define PINGROUP_BIT_N(b) (-1) + +#define PINGROUP(pg_name, f0, f1, f2, f3, r, od, ior) \ { \ .name = #pg_name, \ .pins = pg_name##_pins, \ @@ -2122,35 +2124,24 @@ static struct tegra_function tegra30_functions[] = { TEGRA_MUX_##f2, \ TEGRA_MUX_##f3, \ }, \ - .func_safe = TEGRA_MUX_##f_safe, \ - .mux_reg = PINGROUP_REG_Y(r), \ + .mux_reg = PINGROUP_REG(r), \ .mux_bank = 1, \ .mux_bit = 0, \ - .pupd_reg = PINGROUP_REG_Y(r), \ + .pupd_reg = PINGROUP_REG(r), \ .pupd_bank = 1, \ .pupd_bit = 2, \ - .tri_reg = PINGROUP_REG_Y(r), \ + .tri_reg = PINGROUP_REG(r), \ .tri_bank = 1, \ .tri_bit = 4, \ - .einput_reg = PINGROUP_REG_Y(r), \ - .einput_bank = 1, \ - .einput_bit = 5, \ - .odrain_reg = PINGROUP_REG_##od(r), \ - .odrain_bank = 1, \ - .odrain_bit = 6, \ - .lock_reg = PINGROUP_REG_Y(r), \ - .lock_bank = 1, \ - .lock_bit = 7, \ - .ioreset_reg = PINGROUP_REG_##ior(r), \ - .ioreset_bank = 1, \ - .ioreset_bit = 8, \ - .rcv_sel_reg = -1, \ + .einput_bit = PINGROUP_BIT_Y(5), \ + .odrain_bit = PINGROUP_BIT_##od(6), \ + .lock_bit = PINGROUP_BIT_Y(7), \ + .ioreset_bit = PINGROUP_BIT_##ior(8), \ + .rcv_sel_bit = -1, \ .drv_reg = -1, \ - .drvtype_reg = -1, \ } -#define DRV_PINGROUP_REG_Y(r) ((r) - DRV_PINGROUP_REG_A) -#define DRV_PINGROUP_REG_N(r) -1 +#define DRV_PINGROUP_REG(r) ((r) - DRV_PINGROUP_REG_A) #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, \ drvdn_b, drvdn_w, drvup_b, drvup_w, \ @@ -2162,12 +2153,12 @@ static struct tegra_function tegra30_functions[] = { .mux_reg = -1, \ .pupd_reg = -1, \ .tri_reg = -1, \ - .einput_reg = -1, \ - .odrain_reg = -1, \ - .lock_reg = -1, \ - .ioreset_reg = -1, \ - .rcv_sel_reg = -1, \ - .drv_reg = DRV_PINGROUP_REG_Y(r), \ + .einput_bit = -1, \ + .odrain_bit = -1, \ + .lock_bit = -1, \ + .ioreset_bit = -1, \ + .rcv_sel_bit = -1, \ + .drv_reg = DRV_PINGROUP_REG(r), \ .drv_bank = 0, \ .hsm_bit = hsm_b, \ .schmitt_bit = schmitt_b, \ @@ -2180,260 +2171,260 @@ static struct tegra_function tegra30_functions[] = { .slwr_width = slwr_w, \ .slwf_bit = slwf_b, \ .slwf_width = slwf_w, \ - .drvtype_reg = -1, \ + .drvtype_bit = -1, \ } static const struct tegra_pingroup tegra30_groups[] = { - /* pg_name, f0, f1, f2, f3, safe, r, od, ior */ - PINGROUP(clk_32k_out_pa0, BLINK, RSVD2, RSVD3, RSVD4, RSVD4, 0x331c, N, N), - PINGROUP(uart3_cts_n_pa1, UARTC, RSVD2, GMI, RSVD4, RSVD4, 0x317c, N, N), - PINGROUP(dap2_fs_pa2, I2S1, HDA, RSVD3, GMI, RSVD3, 0x3358, N, N), - PINGROUP(dap2_sclk_pa3, I2S1, HDA, RSVD3, GMI, RSVD3, 0x3364, N, N), - PINGROUP(dap2_din_pa4, I2S1, HDA, RSVD3, GMI, RSVD3, 0x335c, N, N), - PINGROUP(dap2_dout_pa5, I2S1, HDA, RSVD3, GMI, RSVD3, 0x3360, N, N), - PINGROUP(sdmmc3_clk_pa6, UARTA, PWM2, SDMMC3, SPI3, SPI3, 0x3390, N, N), - PINGROUP(sdmmc3_cmd_pa7, UARTA, PWM3, SDMMC3, SPI2, SPI2, 0x3394, N, N), - PINGROUP(gmi_a17_pb0, UARTD, SPI4, GMI, DTV, DTV, 0x3234, N, N), - PINGROUP(gmi_a18_pb1, UARTD, SPI4, GMI, DTV, DTV, 0x3238, N, N), - PINGROUP(lcd_pwr0_pb2, DISPLAYA, DISPLAYB, SPI5, HDCP, HDCP, 0x3090, N, N), - PINGROUP(lcd_pclk_pb3, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x3094, N, N), - PINGROUP(sdmmc3_dat3_pb4, RSVD1, PWM0, SDMMC3, SPI3, RSVD1, 0x33a4, N, N), - PINGROUP(sdmmc3_dat2_pb5, RSVD1, PWM1, SDMMC3, SPI3, RSVD1, 0x33a0, N, N), - PINGROUP(sdmmc3_dat1_pb6, RSVD1, RSVD2, SDMMC3, SPI3, RSVD2, 0x339c, N, N), - PINGROUP(sdmmc3_dat0_pb7, RSVD1, RSVD2, SDMMC3, SPI3, RSVD2, 0x3398, N, N), - PINGROUP(uart3_rts_n_pc0, UARTC, PWM0, GMI, RSVD4, RSVD4, 0x3180, N, N), - PINGROUP(lcd_pwr1_pc1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x3070, N, N), - PINGROUP(uart2_txd_pc2, UARTB, SPDIF, UARTA, SPI4, SPI4, 0x3168, N, N), - PINGROUP(uart2_rxd_pc3, UARTB, SPDIF, UARTA, SPI4, SPI4, 0x3164, N, N), - PINGROUP(gen1_i2c_scl_pc4, I2C1, RSVD2, RSVD3, RSVD4, RSVD4, 0x31a4, Y, N), - PINGROUP(gen1_i2c_sda_pc5, I2C1, RSVD2, RSVD3, RSVD4, RSVD4, 0x31a0, Y, N), - PINGROUP(lcd_pwr2_pc6, DISPLAYA, DISPLAYB, SPI5, HDCP, HDCP, 0x3074, N, N), - PINGROUP(gmi_wp_n_pc7, RSVD1, NAND, GMI, GMI_ALT, RSVD1, 0x31c0, N, N), - PINGROUP(sdmmc3_dat5_pd0, PWM0, SPI4, SDMMC3, SPI2, SPI2, 0x33ac, N, N), - PINGROUP(sdmmc3_dat4_pd1, PWM1, SPI4, SDMMC3, SPI2, SPI2, 0x33a8, N, N), - PINGROUP(lcd_dc1_pd2, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x310c, N, N), - PINGROUP(sdmmc3_dat6_pd3, SPDIF, SPI4, SDMMC3, SPI2, SPI2, 0x33b0, N, N), - PINGROUP(sdmmc3_dat7_pd4, SPDIF, SPI4, SDMMC3, SPI2, SPI2, 0x33b4, N, N), - PINGROUP(vi_d1_pd5, DDR, SDMMC2, VI, RSVD4, RSVD4, 0x3128, N, Y), - PINGROUP(vi_vsync_pd6, DDR, RSVD2, VI, RSVD4, RSVD4, 0x315c, N, Y), - PINGROUP(vi_hsync_pd7, DDR, RSVD2, VI, RSVD4, RSVD4, 0x3160, N, Y), - PINGROUP(lcd_d0_pe0, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30a4, N, N), - PINGROUP(lcd_d1_pe1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30a8, N, N), - PINGROUP(lcd_d2_pe2, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30ac, N, N), - PINGROUP(lcd_d3_pe3, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30b0, N, N), - PINGROUP(lcd_d4_pe4, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30b4, N, N), - PINGROUP(lcd_d5_pe5, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30b8, N, N), - PINGROUP(lcd_d6_pe6, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30bc, N, N), - PINGROUP(lcd_d7_pe7, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30c0, N, N), - PINGROUP(lcd_d8_pf0, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30c4, N, N), - PINGROUP(lcd_d9_pf1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30c8, N, N), - PINGROUP(lcd_d10_pf2, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30cc, N, N), - PINGROUP(lcd_d11_pf3, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30d0, N, N), - PINGROUP(lcd_d12_pf4, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30d4, N, N), - PINGROUP(lcd_d13_pf5, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30d8, N, N), - PINGROUP(lcd_d14_pf6, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30dc, N, N), - PINGROUP(lcd_d15_pf7, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30e0, N, N), - PINGROUP(gmi_ad0_pg0, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31f0, N, N), - PINGROUP(gmi_ad1_pg1, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31f4, N, N), - PINGROUP(gmi_ad2_pg2, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31f8, N, N), - PINGROUP(gmi_ad3_pg3, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31fc, N, N), - PINGROUP(gmi_ad4_pg4, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x3200, N, N), - PINGROUP(gmi_ad5_pg5, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x3204, N, N), - PINGROUP(gmi_ad6_pg6, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x3208, N, N), - PINGROUP(gmi_ad7_pg7, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x320c, N, N), - PINGROUP(gmi_ad8_ph0, PWM0, NAND, GMI, RSVD4, RSVD4, 0x3210, N, N), - PINGROUP(gmi_ad9_ph1, PWM1, NAND, GMI, RSVD4, RSVD4, 0x3214, N, N), - PINGROUP(gmi_ad10_ph2, PWM2, NAND, GMI, RSVD4, RSVD4, 0x3218, N, N), - PINGROUP(gmi_ad11_ph3, PWM3, NAND, GMI, RSVD4, RSVD4, 0x321c, N, N), - PINGROUP(gmi_ad12_ph4, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x3220, N, N), - PINGROUP(gmi_ad13_ph5, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x3224, N, N), - PINGROUP(gmi_ad14_ph6, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x3228, N, N), - PINGROUP(gmi_ad15_ph7, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x322c, N, N), - PINGROUP(gmi_wr_n_pi0, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x3240, N, N), - PINGROUP(gmi_oe_n_pi1, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x3244, N, N), - PINGROUP(gmi_dqs_pi2, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x3248, N, N), - PINGROUP(gmi_cs6_n_pi3, NAND, NAND_ALT, GMI, SATA, SATA, 0x31e8, N, N), - PINGROUP(gmi_rst_n_pi4, NAND, NAND_ALT, GMI, RSVD4, RSVD4, 0x324c, N, N), - PINGROUP(gmi_iordy_pi5, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31c4, N, N), - PINGROUP(gmi_cs7_n_pi6, NAND, NAND_ALT, GMI, GMI_ALT, GMI_ALT, 0x31ec, N, N), - PINGROUP(gmi_wait_pi7, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31c8, N, N), - PINGROUP(gmi_cs0_n_pj0, RSVD1, NAND, GMI, DTV, RSVD1, 0x31d4, N, N), - PINGROUP(lcd_de_pj1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x3098, N, N), - PINGROUP(gmi_cs1_n_pj2, RSVD1, NAND, GMI, DTV, RSVD1, 0x31d8, N, N), - PINGROUP(lcd_hsync_pj3, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x309c, N, N), - PINGROUP(lcd_vsync_pj4, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30a0, N, N), - PINGROUP(uart2_cts_n_pj5, UARTA, UARTB, GMI, SPI4, SPI4, 0x3170, N, N), - PINGROUP(uart2_rts_n_pj6, UARTA, UARTB, GMI, SPI4, SPI4, 0x316c, N, N), - PINGROUP(gmi_a16_pj7, UARTD, SPI4, GMI, GMI_ALT, GMI_ALT, 0x3230, N, N), - PINGROUP(gmi_adv_n_pk0, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31cc, N, N), - PINGROUP(gmi_clk_pk1, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31d0, N, N), - PINGROUP(gmi_cs4_n_pk2, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31e4, N, N), - PINGROUP(gmi_cs2_n_pk3, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31dc, N, N), - PINGROUP(gmi_cs3_n_pk4, RSVD1, NAND, GMI, GMI_ALT, RSVD1, 0x31e0, N, N), - PINGROUP(spdif_out_pk5, SPDIF, RSVD2, I2C1, SDMMC2, RSVD2, 0x3354, N, N), - PINGROUP(spdif_in_pk6, SPDIF, HDA, I2C1, SDMMC2, SDMMC2, 0x3350, N, N), - PINGROUP(gmi_a19_pk7, UARTD, SPI4, GMI, RSVD4, RSVD4, 0x323c, N, N), - PINGROUP(vi_d2_pl0, DDR, SDMMC2, VI, RSVD4, RSVD4, 0x312c, N, Y), - PINGROUP(vi_d3_pl1, DDR, SDMMC2, VI, RSVD4, RSVD4, 0x3130, N, Y), - PINGROUP(vi_d4_pl2, DDR, SDMMC2, VI, RSVD4, RSVD4, 0x3134, N, Y), - PINGROUP(vi_d5_pl3, DDR, SDMMC2, VI, RSVD4, RSVD4, 0x3138, N, Y), - PINGROUP(vi_d6_pl4, DDR, SDMMC2, VI, RSVD4, RSVD4, 0x313c, N, Y), - PINGROUP(vi_d7_pl5, DDR, SDMMC2, VI, RSVD4, RSVD4, 0x3140, N, Y), - PINGROUP(vi_d8_pl6, DDR, SDMMC2, VI, RSVD4, RSVD4, 0x3144, N, Y), - PINGROUP(vi_d9_pl7, DDR, SDMMC2, VI, RSVD4, RSVD4, 0x3148, N, Y), - PINGROUP(lcd_d16_pm0, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30e4, N, N), - PINGROUP(lcd_d17_pm1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30e8, N, N), - PINGROUP(lcd_d18_pm2, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30ec, N, N), - PINGROUP(lcd_d19_pm3, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30f0, N, N), - PINGROUP(lcd_d20_pm4, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30f4, N, N), - PINGROUP(lcd_d21_pm5, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30f8, N, N), - PINGROUP(lcd_d22_pm6, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x30fc, N, N), - PINGROUP(lcd_d23_pm7, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x3100, N, N), - PINGROUP(dap1_fs_pn0, I2S0, HDA, GMI, SDMMC2, SDMMC2, 0x3338, N, N), - PINGROUP(dap1_din_pn1, I2S0, HDA, GMI, SDMMC2, SDMMC2, 0x333c, N, N), - PINGROUP(dap1_dout_pn2, I2S0, HDA, GMI, SDMMC2, SDMMC2, 0x3340, N, N), - PINGROUP(dap1_sclk_pn3, I2S0, HDA, GMI, SDMMC2, SDMMC2, 0x3344, N, N), - PINGROUP(lcd_cs0_n_pn4, DISPLAYA, DISPLAYB, SPI5, RSVD4, RSVD4, 0x3084, N, N), - PINGROUP(lcd_sdout_pn5, DISPLAYA, DISPLAYB, SPI5, HDCP, HDCP, 0x307c, N, N), - PINGROUP(lcd_dc0_pn6, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x3088, N, N), - PINGROUP(hdmi_int_pn7, HDMI, RSVD2, RSVD3, RSVD4, RSVD4, 0x3110, N, N), - PINGROUP(ulpi_data7_po0, SPI2, HSI, UARTA, ULPI, ULPI, 0x301c, N, N), - PINGROUP(ulpi_data0_po1, SPI3, HSI, UARTA, ULPI, ULPI, 0x3000, N, N), - PINGROUP(ulpi_data1_po2, SPI3, HSI, UARTA, ULPI, ULPI, 0x3004, N, N), - PINGROUP(ulpi_data2_po3, SPI3, HSI, UARTA, ULPI, ULPI, 0x3008, N, N), - PINGROUP(ulpi_data3_po4, SPI3, HSI, UARTA, ULPI, ULPI, 0x300c, N, N), - PINGROUP(ulpi_data4_po5, SPI2, HSI, UARTA, ULPI, ULPI, 0x3010, N, N), - PINGROUP(ulpi_data5_po6, SPI2, HSI, UARTA, ULPI, ULPI, 0x3014, N, N), - PINGROUP(ulpi_data6_po7, SPI2, HSI, UARTA, ULPI, ULPI, 0x3018, N, N), - PINGROUP(dap3_fs_pp0, I2S2, RSVD2, DISPLAYA, DISPLAYB, RSVD2, 0x3030, N, N), - PINGROUP(dap3_din_pp1, I2S2, RSVD2, DISPLAYA, DISPLAYB, RSVD2, 0x3034, N, N), - PINGROUP(dap3_dout_pp2, I2S2, RSVD2, DISPLAYA, DISPLAYB, RSVD2, 0x3038, N, N), - PINGROUP(dap3_sclk_pp3, I2S2, RSVD2, DISPLAYA, DISPLAYB, RSVD2, 0x303c, N, N), - PINGROUP(dap4_fs_pp4, I2S3, RSVD2, GMI, RSVD4, RSVD4, 0x31a8, N, N), - PINGROUP(dap4_din_pp5, I2S3, RSVD2, GMI, RSVD4, RSVD4, 0x31ac, N, N), - PINGROUP(dap4_dout_pp6, I2S3, RSVD2, GMI, RSVD4, RSVD4, 0x31b0, N, N), - PINGROUP(dap4_sclk_pp7, I2S3, RSVD2, GMI, RSVD4, RSVD4, 0x31b4, N, N), - PINGROUP(kb_col0_pq0, KBC, NAND, TRACE, TEST, TEST, 0x32fc, N, N), - PINGROUP(kb_col1_pq1, KBC, NAND, TRACE, TEST, TEST, 0x3300, N, N), - PINGROUP(kb_col2_pq2, KBC, NAND, TRACE, RSVD4, RSVD4, 0x3304, N, N), - PINGROUP(kb_col3_pq3, KBC, NAND, TRACE, RSVD4, RSVD4, 0x3308, N, N), - PINGROUP(kb_col4_pq4, KBC, NAND, TRACE, RSVD4, RSVD4, 0x330c, N, N), - PINGROUP(kb_col5_pq5, KBC, NAND, TRACE, RSVD4, RSVD4, 0x3310, N, N), - PINGROUP(kb_col6_pq6, KBC, NAND, TRACE, MIO, MIO, 0x3314, N, N), - PINGROUP(kb_col7_pq7, KBC, NAND, TRACE, MIO, MIO, 0x3318, N, N), - PINGROUP(kb_row0_pr0, KBC, NAND, RSVD3, RSVD4, RSVD4, 0x32bc, N, N), - PINGROUP(kb_row1_pr1, KBC, NAND, RSVD3, RSVD4, RSVD4, 0x32c0, N, N), - PINGROUP(kb_row2_pr2, KBC, NAND, RSVD3, RSVD4, RSVD4, 0x32c4, N, N), - PINGROUP(kb_row3_pr3, KBC, NAND, RSVD3, INVALID, RSVD3, 0x32c8, N, N), - PINGROUP(kb_row4_pr4, KBC, NAND, TRACE, RSVD4, RSVD4, 0x32cc, N, N), - PINGROUP(kb_row5_pr5, KBC, NAND, TRACE, OWR, OWR, 0x32d0, N, N), - PINGROUP(kb_row6_pr6, KBC, NAND, SDMMC2, MIO, MIO, 0x32d4, N, N), - PINGROUP(kb_row7_pr7, KBC, NAND, SDMMC2, MIO, MIO, 0x32d8, N, N), - PINGROUP(kb_row8_ps0, KBC, NAND, SDMMC2, MIO, MIO, 0x32dc, N, N), - PINGROUP(kb_row9_ps1, KBC, NAND, SDMMC2, MIO, MIO, 0x32e0, N, N), - PINGROUP(kb_row10_ps2, KBC, NAND, SDMMC2, MIO, MIO, 0x32e4, N, N), - PINGROUP(kb_row11_ps3, KBC, NAND, SDMMC2, MIO, MIO, 0x32e8, N, N), - PINGROUP(kb_row12_ps4, KBC, NAND, SDMMC2, MIO, MIO, 0x32ec, N, N), - PINGROUP(kb_row13_ps5, KBC, NAND, SDMMC2, MIO, MIO, 0x32f0, N, N), - PINGROUP(kb_row14_ps6, KBC, NAND, SDMMC2, MIO, MIO, 0x32f4, N, N), - PINGROUP(kb_row15_ps7, KBC, NAND, SDMMC2, MIO, MIO, 0x32f8, N, N), - PINGROUP(vi_pclk_pt0, RSVD1, SDMMC2, VI, RSVD4, RSVD4, 0x3154, N, Y), - PINGROUP(vi_mclk_pt1, VI, VI_ALT1, VI_ALT2, VI_ALT3, VI_ALT3, 0x3158, N, Y), - PINGROUP(vi_d10_pt2, DDR, RSVD2, VI, RSVD4, RSVD4, 0x314c, N, Y), - PINGROUP(vi_d11_pt3, DDR, RSVD2, VI, RSVD4, RSVD4, 0x3150, N, Y), - PINGROUP(vi_d0_pt4, DDR, RSVD2, VI, RSVD4, RSVD4, 0x3124, N, Y), - PINGROUP(gen2_i2c_scl_pt5, I2C2, HDCP, GMI, RSVD4, RSVD4, 0x3250, Y, N), - PINGROUP(gen2_i2c_sda_pt6, I2C2, HDCP, GMI, RSVD4, RSVD4, 0x3254, Y, N), - PINGROUP(sdmmc4_cmd_pt7, I2C3, NAND, GMI, SDMMC4, SDMMC4, 0x325c, N, Y), - PINGROUP(pu0, OWR, UARTA, GMI, RSVD4, RSVD4, 0x3184, N, N), - PINGROUP(pu1, RSVD1, UARTA, GMI, RSVD4, RSVD4, 0x3188, N, N), - PINGROUP(pu2, RSVD1, UARTA, GMI, RSVD4, RSVD4, 0x318c, N, N), - PINGROUP(pu3, PWM0, UARTA, GMI, RSVD4, RSVD4, 0x3190, N, N), - PINGROUP(pu4, PWM1, UARTA, GMI, RSVD4, RSVD4, 0x3194, N, N), - PINGROUP(pu5, PWM2, UARTA, GMI, RSVD4, RSVD4, 0x3198, N, N), - PINGROUP(pu6, PWM3, UARTA, GMI, RSVD4, RSVD4, 0x319c, N, N), - PINGROUP(jtag_rtck_pu7, RTCK, RSVD2, RSVD3, RSVD4, RSVD4, 0x32b0, N, N), - PINGROUP(pv0, RSVD1, RSVD2, RSVD3, RSVD4, RSVD4, 0x3040, N, N), - PINGROUP(pv1, RSVD1, RSVD2, RSVD3, RSVD4, RSVD4, 0x3044, N, N), - PINGROUP(pv2, OWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x3060, N, N), - PINGROUP(pv3, CLK_12M_OUT, RSVD2, RSVD3, RSVD4, RSVD4, 0x3064, N, N), - PINGROUP(ddc_scl_pv4, I2C4, RSVD2, RSVD3, RSVD4, RSVD4, 0x3114, N, N), - PINGROUP(ddc_sda_pv5, I2C4, RSVD2, RSVD3, RSVD4, RSVD4, 0x3118, N, N), - PINGROUP(crt_hsync_pv6, CRT, RSVD2, RSVD3, RSVD4, RSVD4, 0x311c, N, N), - PINGROUP(crt_vsync_pv7, CRT, RSVD2, RSVD3, RSVD4, RSVD4, 0x3120, N, N), - PINGROUP(lcd_cs1_n_pw0, DISPLAYA, DISPLAYB, SPI5, RSVD4, RSVD4, 0x3104, N, N), - PINGROUP(lcd_m1_pw1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, RSVD4, 0x3108, N, N), - PINGROUP(spi2_cs1_n_pw2, SPI3, SPI2, SPI2_ALT, I2C1, I2C1, 0x3388, N, N), - PINGROUP(spi2_cs2_n_pw3, SPI3, SPI2, SPI2_ALT, I2C1, I2C1, 0x338c, N, N), - PINGROUP(clk1_out_pw4, EXTPERIPH1, RSVD2, RSVD3, RSVD4, RSVD4, 0x334c, N, N), - PINGROUP(clk2_out_pw5, EXTPERIPH2, RSVD2, RSVD3, RSVD4, RSVD4, 0x3068, N, N), - PINGROUP(uart3_txd_pw6, UARTC, RSVD2, GMI, RSVD4, RSVD4, 0x3174, N, N), - PINGROUP(uart3_rxd_pw7, UARTC, RSVD2, GMI, RSVD4, RSVD4, 0x3178, N, N), - PINGROUP(spi2_mosi_px0, SPI6, SPI2, SPI3, GMI, GMI, 0x3368, N, N), - PINGROUP(spi2_miso_px1, SPI6, SPI2, SPI3, GMI, GMI, 0x336c, N, N), - PINGROUP(spi2_sck_px2, SPI6, SPI2, SPI3, GMI, GMI, 0x3374, N, N), - PINGROUP(spi2_cs0_n_px3, SPI6, SPI2, SPI3, GMI, GMI, 0x3370, N, N), - PINGROUP(spi1_mosi_px4, SPI2, SPI1, SPI2_ALT, GMI, GMI, 0x3378, N, N), - PINGROUP(spi1_sck_px5, SPI2, SPI1, SPI2_ALT, GMI, GMI, 0x337c, N, N), - PINGROUP(spi1_cs0_n_px6, SPI2, SPI1, SPI2_ALT, GMI, GMI, 0x3380, N, N), - PINGROUP(spi1_miso_px7, SPI3, SPI1, SPI2_ALT, RSVD4, RSVD4, 0x3384, N, N), - PINGROUP(ulpi_clk_py0, SPI1, RSVD2, UARTD, ULPI, RSVD2, 0x3020, N, N), - PINGROUP(ulpi_dir_py1, SPI1, RSVD2, UARTD, ULPI, RSVD2, 0x3024, N, N), - PINGROUP(ulpi_nxt_py2, SPI1, RSVD2, UARTD, ULPI, RSVD2, 0x3028, N, N), - PINGROUP(ulpi_stp_py3, SPI1, RSVD2, UARTD, ULPI, RSVD2, 0x302c, N, N), - PINGROUP(sdmmc1_dat3_py4, SDMMC1, RSVD2, UARTE, UARTA, RSVD2, 0x3050, N, N), - PINGROUP(sdmmc1_dat2_py5, SDMMC1, RSVD2, UARTE, UARTA, RSVD2, 0x3054, N, N), - PINGROUP(sdmmc1_dat1_py6, SDMMC1, RSVD2, UARTE, UARTA, RSVD2, 0x3058, N, N), - PINGROUP(sdmmc1_dat0_py7, SDMMC1, RSVD2, UARTE, UARTA, RSVD2, 0x305c, N, N), - PINGROUP(sdmmc1_clk_pz0, SDMMC1, RSVD2, RSVD3, UARTA, RSVD3, 0x3048, N, N), - PINGROUP(sdmmc1_cmd_pz1, SDMMC1, RSVD2, RSVD3, UARTA, RSVD3, 0x304c, N, N), - PINGROUP(lcd_sdin_pz2, DISPLAYA, DISPLAYB, SPI5, RSVD4, RSVD4, 0x3078, N, N), - PINGROUP(lcd_wr_n_pz3, DISPLAYA, DISPLAYB, SPI5, HDCP, HDCP, 0x3080, N, N), - PINGROUP(lcd_sck_pz4, DISPLAYA, DISPLAYB, SPI5, HDCP, HDCP, 0x308c, N, N), - PINGROUP(sys_clk_req_pz5, SYSCLK, RSVD2, RSVD3, RSVD4, RSVD4, 0x3320, N, N), - PINGROUP(pwr_i2c_scl_pz6, I2CPWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x32b4, Y, N), - PINGROUP(pwr_i2c_sda_pz7, I2CPWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x32b8, Y, N), - PINGROUP(sdmmc4_dat0_paa0, UARTE, SPI3, GMI, SDMMC4, SDMMC4, 0x3260, N, Y), - PINGROUP(sdmmc4_dat1_paa1, UARTE, SPI3, GMI, SDMMC4, SDMMC4, 0x3264, N, Y), - PINGROUP(sdmmc4_dat2_paa2, UARTE, SPI3, GMI, SDMMC4, SDMMC4, 0x3268, N, Y), - PINGROUP(sdmmc4_dat3_paa3, UARTE, SPI3, GMI, SDMMC4, SDMMC4, 0x326c, N, Y), - PINGROUP(sdmmc4_dat4_paa4, I2C3, I2S4, GMI, SDMMC4, SDMMC4, 0x3270, N, Y), - PINGROUP(sdmmc4_dat5_paa5, VGP3, I2S4, GMI, SDMMC4, SDMMC4, 0x3274, N, Y), - PINGROUP(sdmmc4_dat6_paa6, VGP4, I2S4, GMI, SDMMC4, SDMMC4, 0x3278, N, Y), - PINGROUP(sdmmc4_dat7_paa7, VGP5, I2S4, GMI, SDMMC4, SDMMC4, 0x327c, N, Y), - PINGROUP(pbb0, I2S4, RSVD2, RSVD3, SDMMC4, RSVD3, 0x328c, N, N), - PINGROUP(cam_i2c_scl_pbb1, VGP1, I2C3, RSVD3, SDMMC4, RSVD3, 0x3290, Y, N), - PINGROUP(cam_i2c_sda_pbb2, VGP2, I2C3, RSVD3, SDMMC4, RSVD3, 0x3294, Y, N), - PINGROUP(pbb3, VGP3, DISPLAYA, DISPLAYB, SDMMC4, SDMMC4, 0x3298, N, N), - PINGROUP(pbb4, VGP4, DISPLAYA, DISPLAYB, SDMMC4, SDMMC4, 0x329c, N, N), - PINGROUP(pbb5, VGP5, DISPLAYA, DISPLAYB, SDMMC4, SDMMC4, 0x32a0, N, N), - PINGROUP(pbb6, VGP6, DISPLAYA, DISPLAYB, SDMMC4, SDMMC4, 0x32a4, N, N), - PINGROUP(pbb7, I2S4, RSVD2, RSVD3, SDMMC4, RSVD3, 0x32a8, N, N), - PINGROUP(cam_mclk_pcc0, VI, VI_ALT1, VI_ALT3, SDMMC4, SDMMC4, 0x3284, N, N), - PINGROUP(pcc1, I2S4, RSVD2, RSVD3, SDMMC4, RSVD3, 0x3288, N, N), - PINGROUP(pcc2, I2S4, RSVD2, RSVD3, RSVD4, RSVD4, 0x32ac, N, N), - PINGROUP(sdmmc4_rst_n_pcc3, VGP6, RSVD2, RSVD3, SDMMC4, RSVD3, 0x3280, N, Y), - PINGROUP(sdmmc4_clk_pcc4, INVALID, NAND, GMI, SDMMC4, SDMMC4, 0x3258, N, Y), - PINGROUP(clk2_req_pcc5, DAP, RSVD2, RSVD3, RSVD4, RSVD4, 0x306c, N, N), - PINGROUP(pex_l2_rst_n_pcc6, PCIE, HDA, RSVD3, RSVD4, RSVD4, 0x33d8, N, N), - PINGROUP(pex_l2_clkreq_n_pcc7, PCIE, HDA, RSVD3, RSVD4, RSVD4, 0x33dc, N, N), - PINGROUP(pex_l0_prsnt_n_pdd0, PCIE, HDA, RSVD3, RSVD4, RSVD4, 0x33b8, N, N), - PINGROUP(pex_l0_rst_n_pdd1, PCIE, HDA, RSVD3, RSVD4, RSVD4, 0x33bc, N, N), - PINGROUP(pex_l0_clkreq_n_pdd2, PCIE, HDA, RSVD3, RSVD4, RSVD4, 0x33c0, N, N), - PINGROUP(pex_wake_n_pdd3, PCIE, HDA, RSVD3, RSVD4, RSVD4, 0x33c4, N, N), - PINGROUP(pex_l1_prsnt_n_pdd4, PCIE, HDA, RSVD3, RSVD4, RSVD4, 0x33c8, N, N), - PINGROUP(pex_l1_rst_n_pdd5, PCIE, HDA, RSVD3, RSVD4, RSVD4, 0x33cc, N, N), - PINGROUP(pex_l1_clkreq_n_pdd6, PCIE, HDA, RSVD3, RSVD4, RSVD4, 0x33d0, N, N), - PINGROUP(pex_l2_prsnt_n_pdd7, PCIE, HDA, RSVD3, RSVD4, RSVD4, 0x33d4, N, N), - PINGROUP(clk3_out_pee0, EXTPERIPH3, RSVD2, RSVD3, RSVD4, RSVD4, 0x31b8, N, N), - PINGROUP(clk3_req_pee1, DEV3, RSVD2, RSVD3, RSVD4, RSVD4, 0x31bc, N, N), - PINGROUP(clk1_req_pee2, DAP, HDA, RSVD3, RSVD4, RSVD4, 0x3348, N, N), - PINGROUP(hdmi_cec_pee3, CEC, RSVD2, RSVD3, RSVD4, RSVD4, 0x33e0, Y, N), - PINGROUP(clk_32k_in, CLK_32K_IN, RSVD2, RSVD3, RSVD4, RSVD4, 0x3330, N, N), - PINGROUP(core_pwr_req, CORE_PWR_REQ, RSVD2, RSVD3, RSVD4, RSVD4, 0x3324, N, N), - PINGROUP(cpu_pwr_req, CPU_PWR_REQ, RSVD2, RSVD3, RSVD4, RSVD4, 0x3328, N, N), - PINGROUP(owr, OWR, CEC, RSVD3, RSVD4, RSVD4, 0x3334, N, N), - PINGROUP(pwr_int_n, PWR_INT_N, RSVD2, RSVD3, RSVD4, RSVD4, 0x332c, N, N), + /* pg_name, f0, f1, f2, f3, r, od, ior */ + PINGROUP(clk_32k_out_pa0, BLINK, RSVD2, RSVD3, RSVD4, 0x331c, N, N), + PINGROUP(uart3_cts_n_pa1, UARTC, RSVD2, GMI, RSVD4, 0x317c, N, N), + PINGROUP(dap2_fs_pa2, I2S1, HDA, RSVD3, GMI, 0x3358, N, N), + PINGROUP(dap2_sclk_pa3, I2S1, HDA, RSVD3, GMI, 0x3364, N, N), + PINGROUP(dap2_din_pa4, I2S1, HDA, RSVD3, GMI, 0x335c, N, N), + PINGROUP(dap2_dout_pa5, I2S1, HDA, RSVD3, GMI, 0x3360, N, N), + PINGROUP(sdmmc3_clk_pa6, UARTA, PWM2, SDMMC3, SPI3, 0x3390, N, N), + PINGROUP(sdmmc3_cmd_pa7, UARTA, PWM3, SDMMC3, SPI2, 0x3394, N, N), + PINGROUP(gmi_a17_pb0, UARTD, SPI4, GMI, DTV, 0x3234, N, N), + PINGROUP(gmi_a18_pb1, UARTD, SPI4, GMI, DTV, 0x3238, N, N), + PINGROUP(lcd_pwr0_pb2, DISPLAYA, DISPLAYB, SPI5, HDCP, 0x3090, N, N), + PINGROUP(lcd_pclk_pb3, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x3094, N, N), + PINGROUP(sdmmc3_dat3_pb4, RSVD1, PWM0, SDMMC3, SPI3, 0x33a4, N, N), + PINGROUP(sdmmc3_dat2_pb5, RSVD1, PWM1, SDMMC3, SPI3, 0x33a0, N, N), + PINGROUP(sdmmc3_dat1_pb6, RSVD1, RSVD2, SDMMC3, SPI3, 0x339c, N, N), + PINGROUP(sdmmc3_dat0_pb7, RSVD1, RSVD2, SDMMC3, SPI3, 0x3398, N, N), + PINGROUP(uart3_rts_n_pc0, UARTC, PWM0, GMI, RSVD4, 0x3180, N, N), + PINGROUP(lcd_pwr1_pc1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x3070, N, N), + PINGROUP(uart2_txd_pc2, UARTB, SPDIF, UARTA, SPI4, 0x3168, N, N), + PINGROUP(uart2_rxd_pc3, UARTB, SPDIF, UARTA, SPI4, 0x3164, N, N), + PINGROUP(gen1_i2c_scl_pc4, I2C1, RSVD2, RSVD3, RSVD4, 0x31a4, Y, N), + PINGROUP(gen1_i2c_sda_pc5, I2C1, RSVD2, RSVD3, RSVD4, 0x31a0, Y, N), + PINGROUP(lcd_pwr2_pc6, DISPLAYA, DISPLAYB, SPI5, HDCP, 0x3074, N, N), + PINGROUP(gmi_wp_n_pc7, RSVD1, NAND, GMI, GMI_ALT, 0x31c0, N, N), + PINGROUP(sdmmc3_dat5_pd0, PWM0, SPI4, SDMMC3, SPI2, 0x33ac, N, N), + PINGROUP(sdmmc3_dat4_pd1, PWM1, SPI4, SDMMC3, SPI2, 0x33a8, N, N), + PINGROUP(lcd_dc1_pd2, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x310c, N, N), + PINGROUP(sdmmc3_dat6_pd3, SPDIF, SPI4, SDMMC3, SPI2, 0x33b0, N, N), + PINGROUP(sdmmc3_dat7_pd4, SPDIF, SPI4, SDMMC3, SPI2, 0x33b4, N, N), + PINGROUP(vi_d1_pd5, DDR, SDMMC2, VI, RSVD4, 0x3128, N, Y), + PINGROUP(vi_vsync_pd6, DDR, RSVD2, VI, RSVD4, 0x315c, N, Y), + PINGROUP(vi_hsync_pd7, DDR, RSVD2, VI, RSVD4, 0x3160, N, Y), + PINGROUP(lcd_d0_pe0, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30a4, N, N), + PINGROUP(lcd_d1_pe1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30a8, N, N), + PINGROUP(lcd_d2_pe2, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30ac, N, N), + PINGROUP(lcd_d3_pe3, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30b0, N, N), + PINGROUP(lcd_d4_pe4, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30b4, N, N), + PINGROUP(lcd_d5_pe5, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30b8, N, N), + PINGROUP(lcd_d6_pe6, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30bc, N, N), + PINGROUP(lcd_d7_pe7, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30c0, N, N), + PINGROUP(lcd_d8_pf0, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30c4, N, N), + PINGROUP(lcd_d9_pf1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30c8, N, N), + PINGROUP(lcd_d10_pf2, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30cc, N, N), + PINGROUP(lcd_d11_pf3, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30d0, N, N), + PINGROUP(lcd_d12_pf4, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30d4, N, N), + PINGROUP(lcd_d13_pf5, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30d8, N, N), + PINGROUP(lcd_d14_pf6, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30dc, N, N), + PINGROUP(lcd_d15_pf7, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30e0, N, N), + PINGROUP(gmi_ad0_pg0, RSVD1, NAND, GMI, RSVD4, 0x31f0, N, N), + PINGROUP(gmi_ad1_pg1, RSVD1, NAND, GMI, RSVD4, 0x31f4, N, N), + PINGROUP(gmi_ad2_pg2, RSVD1, NAND, GMI, RSVD4, 0x31f8, N, N), + PINGROUP(gmi_ad3_pg3, RSVD1, NAND, GMI, RSVD4, 0x31fc, N, N), + PINGROUP(gmi_ad4_pg4, RSVD1, NAND, GMI, RSVD4, 0x3200, N, N), + PINGROUP(gmi_ad5_pg5, RSVD1, NAND, GMI, RSVD4, 0x3204, N, N), + PINGROUP(gmi_ad6_pg6, RSVD1, NAND, GMI, RSVD4, 0x3208, N, N), + PINGROUP(gmi_ad7_pg7, RSVD1, NAND, GMI, RSVD4, 0x320c, N, N), + PINGROUP(gmi_ad8_ph0, PWM0, NAND, GMI, RSVD4, 0x3210, N, N), + PINGROUP(gmi_ad9_ph1, PWM1, NAND, GMI, RSVD4, 0x3214, N, N), + PINGROUP(gmi_ad10_ph2, PWM2, NAND, GMI, RSVD4, 0x3218, N, N), + PINGROUP(gmi_ad11_ph3, PWM3, NAND, GMI, RSVD4, 0x321c, N, N), + PINGROUP(gmi_ad12_ph4, RSVD1, NAND, GMI, RSVD4, 0x3220, N, N), + PINGROUP(gmi_ad13_ph5, RSVD1, NAND, GMI, RSVD4, 0x3224, N, N), + PINGROUP(gmi_ad14_ph6, RSVD1, NAND, GMI, RSVD4, 0x3228, N, N), + PINGROUP(gmi_ad15_ph7, RSVD1, NAND, GMI, RSVD4, 0x322c, N, N), + PINGROUP(gmi_wr_n_pi0, RSVD1, NAND, GMI, RSVD4, 0x3240, N, N), + PINGROUP(gmi_oe_n_pi1, RSVD1, NAND, GMI, RSVD4, 0x3244, N, N), + PINGROUP(gmi_dqs_pi2, RSVD1, NAND, GMI, RSVD4, 0x3248, N, N), + PINGROUP(gmi_cs6_n_pi3, NAND, NAND_ALT, GMI, SATA, 0x31e8, N, N), + PINGROUP(gmi_rst_n_pi4, NAND, NAND_ALT, GMI, RSVD4, 0x324c, N, N), + PINGROUP(gmi_iordy_pi5, RSVD1, NAND, GMI, RSVD4, 0x31c4, N, N), + PINGROUP(gmi_cs7_n_pi6, NAND, NAND_ALT, GMI, GMI_ALT, 0x31ec, N, N), + PINGROUP(gmi_wait_pi7, RSVD1, NAND, GMI, RSVD4, 0x31c8, N, N), + PINGROUP(gmi_cs0_n_pj0, RSVD1, NAND, GMI, DTV, 0x31d4, N, N), + PINGROUP(lcd_de_pj1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x3098, N, N), + PINGROUP(gmi_cs1_n_pj2, RSVD1, NAND, GMI, DTV, 0x31d8, N, N), + PINGROUP(lcd_hsync_pj3, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x309c, N, N), + PINGROUP(lcd_vsync_pj4, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30a0, N, N), + PINGROUP(uart2_cts_n_pj5, UARTA, UARTB, GMI, SPI4, 0x3170, N, N), + PINGROUP(uart2_rts_n_pj6, UARTA, UARTB, GMI, SPI4, 0x316c, N, N), + PINGROUP(gmi_a16_pj7, UARTD, SPI4, GMI, GMI_ALT, 0x3230, N, N), + PINGROUP(gmi_adv_n_pk0, RSVD1, NAND, GMI, RSVD4, 0x31cc, N, N), + PINGROUP(gmi_clk_pk1, RSVD1, NAND, GMI, RSVD4, 0x31d0, N, N), + PINGROUP(gmi_cs4_n_pk2, RSVD1, NAND, GMI, RSVD4, 0x31e4, N, N), + PINGROUP(gmi_cs2_n_pk3, RSVD1, NAND, GMI, RSVD4, 0x31dc, N, N), + PINGROUP(gmi_cs3_n_pk4, RSVD1, NAND, GMI, GMI_ALT, 0x31e0, N, N), + PINGROUP(spdif_out_pk5, SPDIF, RSVD2, I2C1, SDMMC2, 0x3354, N, N), + PINGROUP(spdif_in_pk6, SPDIF, HDA, I2C1, SDMMC2, 0x3350, N, N), + PINGROUP(gmi_a19_pk7, UARTD, SPI4, GMI, RSVD4, 0x323c, N, N), + PINGROUP(vi_d2_pl0, DDR, SDMMC2, VI, RSVD4, 0x312c, N, Y), + PINGROUP(vi_d3_pl1, DDR, SDMMC2, VI, RSVD4, 0x3130, N, Y), + PINGROUP(vi_d4_pl2, DDR, SDMMC2, VI, RSVD4, 0x3134, N, Y), + PINGROUP(vi_d5_pl3, DDR, SDMMC2, VI, RSVD4, 0x3138, N, Y), + PINGROUP(vi_d6_pl4, DDR, SDMMC2, VI, RSVD4, 0x313c, N, Y), + PINGROUP(vi_d7_pl5, DDR, SDMMC2, VI, RSVD4, 0x3140, N, Y), + PINGROUP(vi_d8_pl6, DDR, SDMMC2, VI, RSVD4, 0x3144, N, Y), + PINGROUP(vi_d9_pl7, DDR, SDMMC2, VI, RSVD4, 0x3148, N, Y), + PINGROUP(lcd_d16_pm0, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30e4, N, N), + PINGROUP(lcd_d17_pm1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30e8, N, N), + PINGROUP(lcd_d18_pm2, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30ec, N, N), + PINGROUP(lcd_d19_pm3, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30f0, N, N), + PINGROUP(lcd_d20_pm4, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30f4, N, N), + PINGROUP(lcd_d21_pm5, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30f8, N, N), + PINGROUP(lcd_d22_pm6, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x30fc, N, N), + PINGROUP(lcd_d23_pm7, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x3100, N, N), + PINGROUP(dap1_fs_pn0, I2S0, HDA, GMI, SDMMC2, 0x3338, N, N), + PINGROUP(dap1_din_pn1, I2S0, HDA, GMI, SDMMC2, 0x333c, N, N), + PINGROUP(dap1_dout_pn2, I2S0, HDA, GMI, SDMMC2, 0x3340, N, N), + PINGROUP(dap1_sclk_pn3, I2S0, HDA, GMI, SDMMC2, 0x3344, N, N), + PINGROUP(lcd_cs0_n_pn4, DISPLAYA, DISPLAYB, SPI5, RSVD4, 0x3084, N, N), + PINGROUP(lcd_sdout_pn5, DISPLAYA, DISPLAYB, SPI5, HDCP, 0x307c, N, N), + PINGROUP(lcd_dc0_pn6, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x3088, N, N), + PINGROUP(hdmi_int_pn7, HDMI, RSVD2, RSVD3, RSVD4, 0x3110, N, N), + PINGROUP(ulpi_data7_po0, SPI2, HSI, UARTA, ULPI, 0x301c, N, N), + PINGROUP(ulpi_data0_po1, SPI3, HSI, UARTA, ULPI, 0x3000, N, N), + PINGROUP(ulpi_data1_po2, SPI3, HSI, UARTA, ULPI, 0x3004, N, N), + PINGROUP(ulpi_data2_po3, SPI3, HSI, UARTA, ULPI, 0x3008, N, N), + PINGROUP(ulpi_data3_po4, SPI3, HSI, UARTA, ULPI, 0x300c, N, N), + PINGROUP(ulpi_data4_po5, SPI2, HSI, UARTA, ULPI, 0x3010, N, N), + PINGROUP(ulpi_data5_po6, SPI2, HSI, UARTA, ULPI, 0x3014, N, N), + PINGROUP(ulpi_data6_po7, SPI2, HSI, UARTA, ULPI, 0x3018, N, N), + PINGROUP(dap3_fs_pp0, I2S2, RSVD2, DISPLAYA, DISPLAYB, 0x3030, N, N), + PINGROUP(dap3_din_pp1, I2S2, RSVD2, DISPLAYA, DISPLAYB, 0x3034, N, N), + PINGROUP(dap3_dout_pp2, I2S2, RSVD2, DISPLAYA, DISPLAYB, 0x3038, N, N), + PINGROUP(dap3_sclk_pp3, I2S2, RSVD2, DISPLAYA, DISPLAYB, 0x303c, N, N), + PINGROUP(dap4_fs_pp4, I2S3, RSVD2, GMI, RSVD4, 0x31a8, N, N), + PINGROUP(dap4_din_pp5, I2S3, RSVD2, GMI, RSVD4, 0x31ac, N, N), + PINGROUP(dap4_dout_pp6, I2S3, RSVD2, GMI, RSVD4, 0x31b0, N, N), + PINGROUP(dap4_sclk_pp7, I2S3, RSVD2, GMI, RSVD4, 0x31b4, N, N), + PINGROUP(kb_col0_pq0, KBC, NAND, TRACE, TEST, 0x32fc, N, N), + PINGROUP(kb_col1_pq1, KBC, NAND, TRACE, TEST, 0x3300, N, N), + PINGROUP(kb_col2_pq2, KBC, NAND, TRACE, RSVD4, 0x3304, N, N), + PINGROUP(kb_col3_pq3, KBC, NAND, TRACE, RSVD4, 0x3308, N, N), + PINGROUP(kb_col4_pq4, KBC, NAND, TRACE, RSVD4, 0x330c, N, N), + PINGROUP(kb_col5_pq5, KBC, NAND, TRACE, RSVD4, 0x3310, N, N), + PINGROUP(kb_col6_pq6, KBC, NAND, TRACE, MIO, 0x3314, N, N), + PINGROUP(kb_col7_pq7, KBC, NAND, TRACE, MIO, 0x3318, N, N), + PINGROUP(kb_row0_pr0, KBC, NAND, RSVD3, RSVD4, 0x32bc, N, N), + PINGROUP(kb_row1_pr1, KBC, NAND, RSVD3, RSVD4, 0x32c0, N, N), + PINGROUP(kb_row2_pr2, KBC, NAND, RSVD3, RSVD4, 0x32c4, N, N), + PINGROUP(kb_row3_pr3, KBC, NAND, RSVD3, INVALID, 0x32c8, N, N), + PINGROUP(kb_row4_pr4, KBC, NAND, TRACE, RSVD4, 0x32cc, N, N), + PINGROUP(kb_row5_pr5, KBC, NAND, TRACE, OWR, 0x32d0, N, N), + PINGROUP(kb_row6_pr6, KBC, NAND, SDMMC2, MIO, 0x32d4, N, N), + PINGROUP(kb_row7_pr7, KBC, NAND, SDMMC2, MIO, 0x32d8, N, N), + PINGROUP(kb_row8_ps0, KBC, NAND, SDMMC2, MIO, 0x32dc, N, N), + PINGROUP(kb_row9_ps1, KBC, NAND, SDMMC2, MIO, 0x32e0, N, N), + PINGROUP(kb_row10_ps2, KBC, NAND, SDMMC2, MIO, 0x32e4, N, N), + PINGROUP(kb_row11_ps3, KBC, NAND, SDMMC2, MIO, 0x32e8, N, N), + PINGROUP(kb_row12_ps4, KBC, NAND, SDMMC2, MIO, 0x32ec, N, N), + PINGROUP(kb_row13_ps5, KBC, NAND, SDMMC2, MIO, 0x32f0, N, N), + PINGROUP(kb_row14_ps6, KBC, NAND, SDMMC2, MIO, 0x32f4, N, N), + PINGROUP(kb_row15_ps7, KBC, NAND, SDMMC2, MIO, 0x32f8, N, N), + PINGROUP(vi_pclk_pt0, RSVD1, SDMMC2, VI, RSVD4, 0x3154, N, Y), + PINGROUP(vi_mclk_pt1, VI, VI_ALT1, VI_ALT2, VI_ALT3, 0x3158, N, Y), + PINGROUP(vi_d10_pt2, DDR, RSVD2, VI, RSVD4, 0x314c, N, Y), + PINGROUP(vi_d11_pt3, DDR, RSVD2, VI, RSVD4, 0x3150, N, Y), + PINGROUP(vi_d0_pt4, DDR, RSVD2, VI, RSVD4, 0x3124, N, Y), + PINGROUP(gen2_i2c_scl_pt5, I2C2, HDCP, GMI, RSVD4, 0x3250, Y, N), + PINGROUP(gen2_i2c_sda_pt6, I2C2, HDCP, GMI, RSVD4, 0x3254, Y, N), + PINGROUP(sdmmc4_cmd_pt7, I2C3, NAND, GMI, SDMMC4, 0x325c, N, Y), + PINGROUP(pu0, OWR, UARTA, GMI, RSVD4, 0x3184, N, N), + PINGROUP(pu1, RSVD1, UARTA, GMI, RSVD4, 0x3188, N, N), + PINGROUP(pu2, RSVD1, UARTA, GMI, RSVD4, 0x318c, N, N), + PINGROUP(pu3, PWM0, UARTA, GMI, RSVD4, 0x3190, N, N), + PINGROUP(pu4, PWM1, UARTA, GMI, RSVD4, 0x3194, N, N), + PINGROUP(pu5, PWM2, UARTA, GMI, RSVD4, 0x3198, N, N), + PINGROUP(pu6, PWM3, UARTA, GMI, RSVD4, 0x319c, N, N), + PINGROUP(jtag_rtck_pu7, RTCK, RSVD2, RSVD3, RSVD4, 0x32b0, N, N), + PINGROUP(pv0, RSVD1, RSVD2, RSVD3, RSVD4, 0x3040, N, N), + PINGROUP(pv1, RSVD1, RSVD2, RSVD3, RSVD4, 0x3044, N, N), + PINGROUP(pv2, OWR, RSVD2, RSVD3, RSVD4, 0x3060, N, N), + PINGROUP(pv3, CLK_12M_OUT, RSVD2, RSVD3, RSVD4, 0x3064, N, N), + PINGROUP(ddc_scl_pv4, I2C4, RSVD2, RSVD3, RSVD4, 0x3114, N, N), + PINGROUP(ddc_sda_pv5, I2C4, RSVD2, RSVD3, RSVD4, 0x3118, N, N), + PINGROUP(crt_hsync_pv6, CRT, RSVD2, RSVD3, RSVD4, 0x311c, N, N), + PINGROUP(crt_vsync_pv7, CRT, RSVD2, RSVD3, RSVD4, 0x3120, N, N), + PINGROUP(lcd_cs1_n_pw0, DISPLAYA, DISPLAYB, SPI5, RSVD4, 0x3104, N, N), + PINGROUP(lcd_m1_pw1, DISPLAYA, DISPLAYB, RSVD3, RSVD4, 0x3108, N, N), + PINGROUP(spi2_cs1_n_pw2, SPI3, SPI2, SPI2_ALT, I2C1, 0x3388, N, N), + PINGROUP(spi2_cs2_n_pw3, SPI3, SPI2, SPI2_ALT, I2C1, 0x338c, N, N), + PINGROUP(clk1_out_pw4, EXTPERIPH1, RSVD2, RSVD3, RSVD4, 0x334c, N, N), + PINGROUP(clk2_out_pw5, EXTPERIPH2, RSVD2, RSVD3, RSVD4, 0x3068, N, N), + PINGROUP(uart3_txd_pw6, UARTC, RSVD2, GMI, RSVD4, 0x3174, N, N), + PINGROUP(uart3_rxd_pw7, UARTC, RSVD2, GMI, RSVD4, 0x3178, N, N), + PINGROUP(spi2_mosi_px0, SPI6, SPI2, SPI3, GMI, 0x3368, N, N), + PINGROUP(spi2_miso_px1, SPI6, SPI2, SPI3, GMI, 0x336c, N, N), + PINGROUP(spi2_sck_px2, SPI6, SPI2, SPI3, GMI, 0x3374, N, N), + PINGROUP(spi2_cs0_n_px3, SPI6, SPI2, SPI3, GMI, 0x3370, N, N), + PINGROUP(spi1_mosi_px4, SPI2, SPI1, SPI2_ALT, GMI, 0x3378, N, N), + PINGROUP(spi1_sck_px5, SPI2, SPI1, SPI2_ALT, GMI, 0x337c, N, N), + PINGROUP(spi1_cs0_n_px6, SPI2, SPI1, SPI2_ALT, GMI, 0x3380, N, N), + PINGROUP(spi1_miso_px7, SPI3, SPI1, SPI2_ALT, RSVD4, 0x3384, N, N), + PINGROUP(ulpi_clk_py0, SPI1, RSVD2, UARTD, ULPI, 0x3020, N, N), + PINGROUP(ulpi_dir_py1, SPI1, RSVD2, UARTD, ULPI, 0x3024, N, N), + PINGROUP(ulpi_nxt_py2, SPI1, RSVD2, UARTD, ULPI, 0x3028, N, N), + PINGROUP(ulpi_stp_py3, SPI1, RSVD2, UARTD, ULPI, 0x302c, N, N), + PINGROUP(sdmmc1_dat3_py4, SDMMC1, RSVD2, UARTE, UARTA, 0x3050, N, N), + PINGROUP(sdmmc1_dat2_py5, SDMMC1, RSVD2, UARTE, UARTA, 0x3054, N, N), + PINGROUP(sdmmc1_dat1_py6, SDMMC1, RSVD2, UARTE, UARTA, 0x3058, N, N), + PINGROUP(sdmmc1_dat0_py7, SDMMC1, RSVD2, UARTE, UARTA, 0x305c, N, N), + PINGROUP(sdmmc1_clk_pz0, SDMMC1, RSVD2, RSVD3, UARTA, 0x3048, N, N), + PINGROUP(sdmmc1_cmd_pz1, SDMMC1, RSVD2, RSVD3, UARTA, 0x304c, N, N), + PINGROUP(lcd_sdin_pz2, DISPLAYA, DISPLAYB, SPI5, RSVD4, 0x3078, N, N), + PINGROUP(lcd_wr_n_pz3, DISPLAYA, DISPLAYB, SPI5, HDCP, 0x3080, N, N), + PINGROUP(lcd_sck_pz4, DISPLAYA, DISPLAYB, SPI5, HDCP, 0x308c, N, N), + PINGROUP(sys_clk_req_pz5, SYSCLK, RSVD2, RSVD3, RSVD4, 0x3320, N, N), + PINGROUP(pwr_i2c_scl_pz6, I2CPWR, RSVD2, RSVD3, RSVD4, 0x32b4, Y, N), + PINGROUP(pwr_i2c_sda_pz7, I2CPWR, RSVD2, RSVD3, RSVD4, 0x32b8, Y, N), + PINGROUP(sdmmc4_dat0_paa0, UARTE, SPI3, GMI, SDMMC4, 0x3260, N, Y), + PINGROUP(sdmmc4_dat1_paa1, UARTE, SPI3, GMI, SDMMC4, 0x3264, N, Y), + PINGROUP(sdmmc4_dat2_paa2, UARTE, SPI3, GMI, SDMMC4, 0x3268, N, Y), + PINGROUP(sdmmc4_dat3_paa3, UARTE, SPI3, GMI, SDMMC4, 0x326c, N, Y), + PINGROUP(sdmmc4_dat4_paa4, I2C3, I2S4, GMI, SDMMC4, 0x3270, N, Y), + PINGROUP(sdmmc4_dat5_paa5, VGP3, I2S4, GMI, SDMMC4, 0x3274, N, Y), + PINGROUP(sdmmc4_dat6_paa6, VGP4, I2S4, GMI, SDMMC4, 0x3278, N, Y), + PINGROUP(sdmmc4_dat7_paa7, VGP5, I2S4, GMI, SDMMC4, 0x327c, N, Y), + PINGROUP(pbb0, I2S4, RSVD2, RSVD3, SDMMC4, 0x328c, N, N), + PINGROUP(cam_i2c_scl_pbb1, VGP1, I2C3, RSVD3, SDMMC4, 0x3290, Y, N), + PINGROUP(cam_i2c_sda_pbb2, VGP2, I2C3, RSVD3, SDMMC4, 0x3294, Y, N), + PINGROUP(pbb3, VGP3, DISPLAYA, DISPLAYB, SDMMC4, 0x3298, N, N), + PINGROUP(pbb4, VGP4, DISPLAYA, DISPLAYB, SDMMC4, 0x329c, N, N), + PINGROUP(pbb5, VGP5, DISPLAYA, DISPLAYB, SDMMC4, 0x32a0, N, N), + PINGROUP(pbb6, VGP6, DISPLAYA, DISPLAYB, SDMMC4, 0x32a4, N, N), + PINGROUP(pbb7, I2S4, RSVD2, RSVD3, SDMMC4, 0x32a8, N, N), + PINGROUP(cam_mclk_pcc0, VI, VI_ALT1, VI_ALT3, SDMMC4, 0x3284, N, N), + PINGROUP(pcc1, I2S4, RSVD2, RSVD3, SDMMC4, 0x3288, N, N), + PINGROUP(pcc2, I2S4, RSVD2, RSVD3, RSVD4, 0x32ac, N, N), + PINGROUP(sdmmc4_rst_n_pcc3, VGP6, RSVD2, RSVD3, SDMMC4, 0x3280, N, Y), + PINGROUP(sdmmc4_clk_pcc4, INVALID, NAND, GMI, SDMMC4, 0x3258, N, Y), + PINGROUP(clk2_req_pcc5, DAP, RSVD2, RSVD3, RSVD4, 0x306c, N, N), + PINGROUP(pex_l2_rst_n_pcc6, PCIE, HDA, RSVD3, RSVD4, 0x33d8, N, N), + PINGROUP(pex_l2_clkreq_n_pcc7, PCIE, HDA, RSVD3, RSVD4, 0x33dc, N, N), + PINGROUP(pex_l0_prsnt_n_pdd0, PCIE, HDA, RSVD3, RSVD4, 0x33b8, N, N), + PINGROUP(pex_l0_rst_n_pdd1, PCIE, HDA, RSVD3, RSVD4, 0x33bc, N, N), + PINGROUP(pex_l0_clkreq_n_pdd2, PCIE, HDA, RSVD3, RSVD4, 0x33c0, N, N), + PINGROUP(pex_wake_n_pdd3, PCIE, HDA, RSVD3, RSVD4, 0x33c4, N, N), + PINGROUP(pex_l1_prsnt_n_pdd4, PCIE, HDA, RSVD3, RSVD4, 0x33c8, N, N), + PINGROUP(pex_l1_rst_n_pdd5, PCIE, HDA, RSVD3, RSVD4, 0x33cc, N, N), + PINGROUP(pex_l1_clkreq_n_pdd6, PCIE, HDA, RSVD3, RSVD4, 0x33d0, N, N), + PINGROUP(pex_l2_prsnt_n_pdd7, PCIE, HDA, RSVD3, RSVD4, 0x33d4, N, N), + PINGROUP(clk3_out_pee0, EXTPERIPH3, RSVD2, RSVD3, RSVD4, 0x31b8, N, N), + PINGROUP(clk3_req_pee1, DEV3, RSVD2, RSVD3, RSVD4, 0x31bc, N, N), + PINGROUP(clk1_req_pee2, DAP, HDA, RSVD3, RSVD4, 0x3348, N, N), + PINGROUP(hdmi_cec_pee3, CEC, RSVD2, RSVD3, RSVD4, 0x33e0, Y, N), + PINGROUP(clk_32k_in, CLK_32K_IN, RSVD2, RSVD3, RSVD4, 0x3330, N, N), + PINGROUP(core_pwr_req, CORE_PWR_REQ, RSVD2, RSVD3, RSVD4, 0x3324, N, N), + PINGROUP(cpu_pwr_req, CPU_PWR_REQ, RSVD2, RSVD3, RSVD4, 0x3328, N, N), + PINGROUP(owr, OWR, CEC, RSVD3, RSVD4, 0x3334, N, N), + PINGROUP(pwr_int_n, PWR_INT_N, RSVD2, RSVD3, RSVD4, 0x332c, N, N), /* pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */ DRV_PINGROUP(ao1, 0x868, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2), DRV_PINGROUP(ao2, 0x86c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2), diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 9248ce4efed4d4..051e8592990e9c 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -391,14 +391,16 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting) struct pinctrl_dev *pctldev = setting->pctldev; const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; const struct pinmux_ops *ops = pctldev->desc->pmxops; - int ret; - const unsigned *pins; - unsigned num_pins; + int ret = 0; + const unsigned *pins = NULL; + unsigned num_pins = 0; int i; struct pin_desc *desc; - ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, - &pins, &num_pins); + if (pctlops->get_group_pins) + ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, + &pins, &num_pins); + if (ret) { const char *gname; @@ -470,14 +472,15 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting) struct pinctrl_dev *pctldev = setting->pctldev; const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; const struct pinmux_ops *ops = pctldev->desc->pmxops; - int ret; - const unsigned *pins; - unsigned num_pins; + int ret = 0; + const unsigned *pins = NULL; + unsigned num_pins = 0; int i; struct pin_desc *desc; - ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, - &pins, &num_pins); + if (pctlops->get_group_pins) + ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, + &pins, &num_pins); if (ret) { const char *gname; diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c index f5cd3f9618083b..9a179c94b4dcd3 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c @@ -782,7 +782,8 @@ enum { USB1_PWEN_MARK, AUDIO_CLKOUT_D_MARK, USB1_OVC_MARK, TCLK1_B_MARK, - I2C3_SCL_MARK, I2C3_SDA_MARK, + IIC0_SCL_MARK, IIC0_SDA_MARK, I2C0_SCL_MARK, I2C0_SDA_MARK, + IIC3_SCL_MARK, IIC3_SDA_MARK, I2C3_SCL_MARK, I2C3_SDA_MARK, PINMUX_MARK_END, }; @@ -1722,6 +1723,13 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_DATA(IP16_7, USB1_OVC), PINMUX_IPSR_MODSEL_DATA(IP16_7, TCLK1_B, SEL_TMU1_1), + PINMUX_DATA(IIC0_SCL_MARK, FN_SEL_IIC0_0), + PINMUX_DATA(IIC0_SDA_MARK, FN_SEL_IIC0_0), + PINMUX_DATA(I2C0_SCL_MARK, FN_SEL_IIC0_1), + PINMUX_DATA(I2C0_SDA_MARK, FN_SEL_IIC0_1), + + PINMUX_DATA(IIC3_SCL_MARK, FN_SEL_IICDVFS_0), + PINMUX_DATA(IIC3_SDA_MARK, FN_SEL_IICDVFS_0), PINMUX_DATA(I2C3_SCL_MARK, FN_SEL_IICDVFS_1), PINMUX_DATA(I2C3_SDA_MARK, FN_SEL_IICDVFS_1), }; @@ -1735,8 +1743,10 @@ static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), /* Pins not associated with a GPIO port */ - SH_PFC_PIN_NAMED(ROW_GROUP_A('J'), 15, AJ15), + SH_PFC_PIN_NAMED(ROW_GROUP_A('F'), 15, AF15), + SH_PFC_PIN_NAMED(ROW_GROUP_A('G'), 15, AG15), SH_PFC_PIN_NAMED(ROW_GROUP_A('H'), 15, AH15), + SH_PFC_PIN_NAMED(ROW_GROUP_A('J'), 15, AJ15), }; /* - AUDIO CLOCK ------------------------------------------------------------ */ @@ -2054,6 +2064,14 @@ static const unsigned int hscif1_ctrl_b_pins[] = { static const unsigned int hscif1_ctrl_b_mux[] = { HRTS1_N_B_MARK, HCTS1_N_B_MARK, }; +/* - I2C0 ------------------------------------------------------------------- */ +static const unsigned int i2c0_pins[] = { + /* SCL, SDA */ + PIN_A_NUMBER('G', 15), PIN_A_NUMBER('F', 15), +}; +static const unsigned int i2c0_mux[] = { + I2C0_SCL_MARK, I2C0_SDA_MARK, +}; /* - I2C1 ------------------------------------------------------------------- */ static const unsigned int i2c1_pins[] = { /* SCL, SDA */ @@ -2120,6 +2138,80 @@ static const unsigned int i2c3_pins[] = { static const unsigned int i2c3_mux[] = { I2C3_SCL_MARK, I2C3_SDA_MARK, }; +/* - IIC0 (I2C4) ------------------------------------------------------------ */ +static const unsigned int iic0_pins[] = { + /* SCL, SDA */ + PIN_A_NUMBER('G', 15), PIN_A_NUMBER('F', 15), +}; +static const unsigned int iic0_mux[] = { + IIC0_SCL_MARK, IIC0_SDA_MARK, +}; +/* - IIC1 (I2C5) ------------------------------------------------------------ */ +static const unsigned int iic1_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(1, 16), RCAR_GP_PIN(1, 17), +}; +static const unsigned int iic1_mux[] = { + IIC1_SCL_MARK, IIC1_SDA_MARK, +}; +static const unsigned int iic1_b_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7), +}; +static const unsigned int iic1_b_mux[] = { + IIC1_SCL_B_MARK, IIC1_SDA_B_MARK, +}; +static const unsigned int iic1_c_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(4, 30), RCAR_GP_PIN(4, 27), +}; +static const unsigned int iic1_c_mux[] = { + IIC1_SCL_C_MARK, IIC1_SDA_C_MARK, +}; +/* - IIC2 (I2C6) ------------------------------------------------------------ */ +static const unsigned int iic2_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 6), +}; +static const unsigned int iic2_mux[] = { + IIC2_SCL_MARK, IIC2_SDA_MARK, +}; +static const unsigned int iic2_b_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(4, 0), RCAR_GP_PIN(4, 1), +}; +static const unsigned int iic2_b_mux[] = { + IIC2_SCL_B_MARK, IIC2_SDA_B_MARK, +}; +static const unsigned int iic2_c_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7), +}; +static const unsigned int iic2_c_mux[] = { + IIC2_SCL_C_MARK, IIC2_SDA_C_MARK, +}; +static const unsigned int iic2_d_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15), +}; +static const unsigned int iic2_d_mux[] = { + IIC2_SCL_D_MARK, IIC2_SDA_D_MARK, +}; +static const unsigned int iic2_e_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(2, 18), RCAR_GP_PIN(2, 19), +}; +static const unsigned int iic2_e_mux[] = { + IIC2_SCL_E_MARK, IIC2_SDA_E_MARK, +}; +/* - IIC3 (I2C7) ------------------------------------------------------------ */ +static const unsigned int iic3_pins[] = { +/* SCL, SDA */ + PIN_A_NUMBER('J', 15), PIN_A_NUMBER('H', 15), +}; +static const unsigned int iic3_mux[] = { + IIC3_SCL_MARK, IIC3_SDA_MARK, +}; /* - INTC ------------------------------------------------------------------- */ static const unsigned int intc_irq0_pins[] = { /* IRQ */ @@ -3757,6 +3849,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(hscif1_data_b), SH_PFC_PIN_GROUP(hscif1_clk_b), SH_PFC_PIN_GROUP(hscif1_ctrl_b), + SH_PFC_PIN_GROUP(i2c0), SH_PFC_PIN_GROUP(i2c1), SH_PFC_PIN_GROUP(i2c1_b), SH_PFC_PIN_GROUP(i2c1_c), @@ -3766,6 +3859,16 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(i2c2_d), SH_PFC_PIN_GROUP(i2c2_e), SH_PFC_PIN_GROUP(i2c3), + SH_PFC_PIN_GROUP(iic0), + SH_PFC_PIN_GROUP(iic1), + SH_PFC_PIN_GROUP(iic1_b), + SH_PFC_PIN_GROUP(iic1_c), + SH_PFC_PIN_GROUP(iic2), + SH_PFC_PIN_GROUP(iic2_b), + SH_PFC_PIN_GROUP(iic2_c), + SH_PFC_PIN_GROUP(iic2_d), + SH_PFC_PIN_GROUP(iic2_e), + SH_PFC_PIN_GROUP(iic3), SH_PFC_PIN_GROUP(intc_irq0), SH_PFC_PIN_GROUP(intc_irq1), SH_PFC_PIN_GROUP(intc_irq2), @@ -4044,6 +4147,10 @@ static const char * const hscif1_groups[] = { "hscif1_ctrl_b", }; +static const char * const i2c0_groups[] = { + "i2c0", +}; + static const char * const i2c1_groups[] = { "i2c1", "i2c1_b", @@ -4062,6 +4169,28 @@ static const char * const i2c3_groups[] = { "i2c3", }; +static const char * const iic0_groups[] = { + "iic0", +}; + +static const char * const iic1_groups[] = { + "iic1", + "iic1_b", + "iic1_c", +}; + +static const char * const iic2_groups[] = { + "iic2", + "iic2_b", + "iic2_c", + "iic2_d", + "iic2_e", +}; + +static const char * const iic3_groups[] = { + "iic3", +}; + static const char * const intc_groups[] = { "intc_irq0", "intc_irq1", @@ -4373,9 +4502,14 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(eth), SH_PFC_FUNCTION(hscif0), SH_PFC_FUNCTION(hscif1), + SH_PFC_FUNCTION(i2c0), SH_PFC_FUNCTION(i2c1), SH_PFC_FUNCTION(i2c2), SH_PFC_FUNCTION(i2c3), + SH_PFC_FUNCTION(iic0), + SH_PFC_FUNCTION(iic1), + SH_PFC_FUNCTION(iic2), + SH_PFC_FUNCTION(iic3), SH_PFC_FUNCTION(intc), SH_PFC_FUNCTION(mmc0), SH_PFC_FUNCTION(mmc1), diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index 7868bf3a0f911d..2e688dc4a3c839 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -1680,6 +1680,53 @@ static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), }; +/* - Audio Clock ------------------------------------------------------------ */ +static const unsigned int audio_clk_a_pins[] = { + /* CLK */ + RCAR_GP_PIN(2, 28), +}; + +static const unsigned int audio_clk_a_mux[] = { + AUDIO_CLKA_MARK, +}; + +static const unsigned int audio_clk_b_pins[] = { + /* CLK */ + RCAR_GP_PIN(2, 29), +}; + +static const unsigned int audio_clk_b_mux[] = { + AUDIO_CLKB_MARK, +}; + +static const unsigned int audio_clk_b_b_pins[] = { + /* CLK */ + RCAR_GP_PIN(7, 20), +}; + +static const unsigned int audio_clk_b_b_mux[] = { + AUDIO_CLKB_B_MARK, +}; + +static const unsigned int audio_clk_c_pins[] = { + /* CLK */ + RCAR_GP_PIN(2, 30), +}; + +static const unsigned int audio_clk_c_mux[] = { + AUDIO_CLKC_MARK, +}; + +static const unsigned int audio_clkout_pins[] = { + /* CLK */ + RCAR_GP_PIN(2, 31), +}; + +static const unsigned int audio_clkout_mux[] = { + AUDIO_CLKOUT_MARK, +}; + + /* - DU --------------------------------------------------------------------- */ static const unsigned int du_rgb666_pins[] = { /* R[7:2], G[7:2], B[7:2] */ @@ -1733,19 +1780,32 @@ static const unsigned int du_clk_out_1_mux[] = { DU1_DOTCLKOUT1_MARK }; static const unsigned int du_sync_pins[] = { - /* EXVSYNC/VSYNC, EXHSYNC/HSYNC, EXDISP/EXODDF/EXCDE */ - RCAR_GP_PIN(3, 29), RCAR_GP_PIN(3, 28), RCAR_GP_PIN(3, 27), + /* EXVSYNC/VSYNC, EXHSYNC/HSYNC */ + RCAR_GP_PIN(3, 28), RCAR_GP_PIN(3, 27), }; static const unsigned int du_sync_mux[] = { - DU1_EXODDF_DU1_ODDF_DISP_CDE_MARK, DU1_EXVSYNC_DU1_VSYNC_MARK, DU1_EXHSYNC_DU1_HSYNC_MARK }; -static const unsigned int du_cde_disp_pins[] = { - /* CDE DISP */ - RCAR_GP_PIN(3, 31), RCAR_GP_PIN(3, 30), +static const unsigned int du_oddf_pins[] = { + /* EXDISP/EXODDF/EXCDE */ + RCAR_GP_PIN(3, 29), +}; +static const unsigned int du_oddf_mux[] = { + DU1_EXODDF_DU1_ODDF_DISP_CDE_MARK, +}; +static const unsigned int du_cde_pins[] = { + /* CDE */ + RCAR_GP_PIN(3, 31), }; -static const unsigned int du_cde_disp_mux[] = { - DU1_CDE_MARK, DU1_DISP_MARK +static const unsigned int du_cde_mux[] = { + DU1_CDE_MARK, +}; +static const unsigned int du_disp_pins[] = { + /* DISP */ + RCAR_GP_PIN(3, 30), +}; +static const unsigned int du_disp_mux[] = { + DU1_DISP_MARK, }; static const unsigned int du0_clk_in_pins[] = { /* CLKIN */ @@ -3246,6 +3306,260 @@ static const unsigned int sdhi2_wp_pins[] = { static const unsigned int sdhi2_wp_mux[] = { SD2_WP_MARK, }; + +/* - SSI -------------------------------------------------------------------- */ +static const unsigned int ssi0_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(2, 2), +}; + +static const unsigned int ssi0_data_mux[] = { + SSI_SDATA0_MARK, +}; + +static const unsigned int ssi0_data_b_pins[] = { + /* SDATA */ + RCAR_GP_PIN(3, 4), +}; + +static const unsigned int ssi0_data_b_mux[] = { + SSI_SDATA0_B_MARK, +}; + +static const unsigned int ssi0129_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1), +}; + +static const unsigned int ssi0129_ctrl_mux[] = { + SSI_SCK0129_MARK, SSI_WS0129_MARK, +}; + +static const unsigned int ssi0129_ctrl_b_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3), +}; + +static const unsigned int ssi0129_ctrl_b_mux[] = { + SSI_SCK0129_B_MARK, SSI_WS0129_B_MARK, +}; + +static const unsigned int ssi1_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(2, 5), +}; + +static const unsigned int ssi1_data_mux[] = { + SSI_SDATA1_MARK, +}; + +static const unsigned int ssi1_data_b_pins[] = { + /* SDATA */ + RCAR_GP_PIN(3, 7), +}; + +static const unsigned int ssi1_data_b_mux[] = { + SSI_SDATA1_B_MARK, +}; + +static const unsigned int ssi1_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(2, 3), RCAR_GP_PIN(2, 4), +}; + +static const unsigned int ssi1_ctrl_mux[] = { + SSI_SCK1_MARK, SSI_WS1_MARK, +}; + +static const unsigned int ssi1_ctrl_b_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(3, 5), RCAR_GP_PIN(3, 6), +}; + +static const unsigned int ssi1_ctrl_b_mux[] = { + SSI_SCK1_B_MARK, SSI_WS1_B_MARK, +}; + +static const unsigned int ssi2_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(2, 8), +}; + +static const unsigned int ssi2_data_mux[] = { + SSI_SDATA2_MARK, +}; + +static const unsigned int ssi2_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 7), +}; + +static const unsigned int ssi2_ctrl_mux[] = { + SSI_SCK2_MARK, SSI_WS2_MARK, +}; + +static const unsigned int ssi3_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(2, 11), +}; + +static const unsigned int ssi3_data_mux[] = { + SSI_SDATA3_MARK, +}; + +static const unsigned int ssi34_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(2, 9), RCAR_GP_PIN(2, 10), +}; + +static const unsigned int ssi34_ctrl_mux[] = { + SSI_SCK34_MARK, SSI_WS34_MARK, +}; + +static const unsigned int ssi4_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(2, 14), +}; + +static const unsigned int ssi4_data_mux[] = { + SSI_SDATA4_MARK, +}; + +static const unsigned int ssi4_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(2, 12), RCAR_GP_PIN(2, 13), +}; + +static const unsigned int ssi4_ctrl_mux[] = { + SSI_SCK4_MARK, SSI_WS4_MARK, +}; + +static const unsigned int ssi5_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(2, 17), +}; + +static const unsigned int ssi5_data_mux[] = { + SSI_SDATA5_MARK, +}; + +static const unsigned int ssi5_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(2, 15), RCAR_GP_PIN(2, 16), +}; + +static const unsigned int ssi5_ctrl_mux[] = { + SSI_SCK5_MARK, SSI_WS5_MARK, +}; + +static const unsigned int ssi6_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(2, 20), +}; + +static const unsigned int ssi6_data_mux[] = { + SSI_SDATA6_MARK, +}; + +static const unsigned int ssi6_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(2, 18), RCAR_GP_PIN(2, 19), +}; + +static const unsigned int ssi6_ctrl_mux[] = { + SSI_SCK6_MARK, SSI_WS6_MARK, +}; + +static const unsigned int ssi7_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(2, 23), +}; + +static const unsigned int ssi7_data_mux[] = { + SSI_SDATA7_MARK, +}; + +static const unsigned int ssi7_data_b_pins[] = { + /* SDATA */ + RCAR_GP_PIN(3, 12), +}; + +static const unsigned int ssi7_data_b_mux[] = { + SSI_SDATA7_B_MARK, +}; + +static const unsigned int ssi78_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(2, 21), RCAR_GP_PIN(2, 22), +}; + +static const unsigned int ssi78_ctrl_mux[] = { + SSI_SCK78_MARK, SSI_WS78_MARK, +}; + +static const unsigned int ssi78_ctrl_b_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11), +}; + +static const unsigned int ssi78_ctrl_b_mux[] = { + SSI_SCK78_B_MARK, SSI_WS78_B_MARK, +}; + +static const unsigned int ssi8_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(2, 24), +}; + +static const unsigned int ssi8_data_mux[] = { + SSI_SDATA8_MARK, +}; + +static const unsigned int ssi8_data_b_pins[] = { + /* SDATA */ + RCAR_GP_PIN(3, 13), +}; + +static const unsigned int ssi8_data_b_mux[] = { + SSI_SDATA8_B_MARK, +}; + +static const unsigned int ssi9_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(2, 27), +}; + +static const unsigned int ssi9_data_mux[] = { + SSI_SDATA9_MARK, +}; + +static const unsigned int ssi9_data_b_pins[] = { + /* SDATA */ + RCAR_GP_PIN(3, 18), +}; + +static const unsigned int ssi9_data_b_mux[] = { + SSI_SDATA9_B_MARK, +}; + +static const unsigned int ssi9_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(2, 25), RCAR_GP_PIN(2, 26), +}; + +static const unsigned int ssi9_ctrl_mux[] = { + SSI_SCK9_MARK, SSI_WS9_MARK, +}; + +static const unsigned int ssi9_ctrl_b_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15), +}; + +static const unsigned int ssi9_ctrl_b_mux[] = { + SSI_SCK9_B_MARK, SSI_WS9_B_MARK, +}; + /* - USB0 ------------------------------------------------------------------- */ static const unsigned int usb0_pins[] = { RCAR_GP_PIN(7, 23), /* PWEN */ @@ -3550,12 +3864,19 @@ static const unsigned int vin2_clk_mux[] = { }; static const struct sh_pfc_pin_group pinmux_groups[] = { + SH_PFC_PIN_GROUP(audio_clk_a), + SH_PFC_PIN_GROUP(audio_clk_b), + SH_PFC_PIN_GROUP(audio_clk_b_b), + SH_PFC_PIN_GROUP(audio_clk_c), + SH_PFC_PIN_GROUP(audio_clkout), SH_PFC_PIN_GROUP(du_rgb666), SH_PFC_PIN_GROUP(du_rgb888), SH_PFC_PIN_GROUP(du_clk_out_0), SH_PFC_PIN_GROUP(du_clk_out_1), SH_PFC_PIN_GROUP(du_sync), - SH_PFC_PIN_GROUP(du_cde_disp), + SH_PFC_PIN_GROUP(du_oddf), + SH_PFC_PIN_GROUP(du_cde), + SH_PFC_PIN_GROUP(du_disp), SH_PFC_PIN_GROUP(du0_clk_in), SH_PFC_PIN_GROUP(du1_clk_in), SH_PFC_PIN_GROUP(du1_clk_in_b), @@ -3762,6 +4083,34 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(sdhi2_ctrl), SH_PFC_PIN_GROUP(sdhi2_cd), SH_PFC_PIN_GROUP(sdhi2_wp), + SH_PFC_PIN_GROUP(ssi0_data), + SH_PFC_PIN_GROUP(ssi0_data_b), + SH_PFC_PIN_GROUP(ssi0129_ctrl), + SH_PFC_PIN_GROUP(ssi0129_ctrl_b), + SH_PFC_PIN_GROUP(ssi1_data), + SH_PFC_PIN_GROUP(ssi1_data_b), + SH_PFC_PIN_GROUP(ssi1_ctrl), + SH_PFC_PIN_GROUP(ssi1_ctrl_b), + SH_PFC_PIN_GROUP(ssi2_data), + SH_PFC_PIN_GROUP(ssi2_ctrl), + SH_PFC_PIN_GROUP(ssi3_data), + SH_PFC_PIN_GROUP(ssi34_ctrl), + SH_PFC_PIN_GROUP(ssi4_data), + SH_PFC_PIN_GROUP(ssi4_ctrl), + SH_PFC_PIN_GROUP(ssi5_data), + SH_PFC_PIN_GROUP(ssi5_ctrl), + SH_PFC_PIN_GROUP(ssi6_data), + SH_PFC_PIN_GROUP(ssi6_ctrl), + SH_PFC_PIN_GROUP(ssi7_data), + SH_PFC_PIN_GROUP(ssi7_data_b), + SH_PFC_PIN_GROUP(ssi78_ctrl), + SH_PFC_PIN_GROUP(ssi78_ctrl_b), + SH_PFC_PIN_GROUP(ssi8_data), + SH_PFC_PIN_GROUP(ssi8_data_b), + SH_PFC_PIN_GROUP(ssi9_data), + SH_PFC_PIN_GROUP(ssi9_data_b), + SH_PFC_PIN_GROUP(ssi9_ctrl), + SH_PFC_PIN_GROUP(ssi9_ctrl_b), SH_PFC_PIN_GROUP(usb0), SH_PFC_PIN_GROUP(usb1), VIN_DATA_PIN_GROUP(vin0_data, 24), @@ -3798,13 +4147,23 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(vin2_clk), }; +static const char * const audio_clk_groups[] = { + "audio_clk_a", + "audio_clk_b", + "audio_clk_b_b", + "audio_clk_c", + "audio_clkout", +}; + static const char * const du_groups[] = { "du_rgb666", "du_rgb888", "du_clk_out_0", "du_clk_out_1", "du_sync", - "du_cde_disp", + "du_oddf", + "du_cde", + "du_disp", }; static const char * const du0_groups[] = { @@ -4103,6 +4462,37 @@ static const char * const sdhi2_groups[] = { "sdhi2_wp", }; +static const char * const ssi_groups[] = { + "ssi0_data", + "ssi0_data_b", + "ssi0129_ctrl", + "ssi0129_ctrl_b", + "ssi1_data", + "ssi1_data_b", + "ssi1_ctrl", + "ssi1_ctrl_b", + "ssi2_data", + "ssi2_ctrl", + "ssi3_data", + "ssi34_ctrl", + "ssi4_data", + "ssi4_ctrl", + "ssi5_data", + "ssi5_ctrl", + "ssi6_data", + "ssi6_ctrl", + "ssi7_data", + "ssi7_data_b", + "ssi78_ctrl", + "ssi78_ctrl_b", + "ssi8_data", + "ssi8_data_b", + "ssi9_data", + "ssi9_data_b", + "ssi9_ctrl", + "ssi9_ctrl_b", +}; + static const char * const usb0_groups[] = { "usb0", }; @@ -4152,6 +4542,7 @@ static const char * const vin2_groups[] = { }; static const struct sh_pfc_function pinmux_functions[] = { + SH_PFC_FUNCTION(audio_clk), SH_PFC_FUNCTION(du), SH_PFC_FUNCTION(du0), SH_PFC_FUNCTION(du1), @@ -4187,6 +4578,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(sdhi0), SH_PFC_FUNCTION(sdhi1), SH_PFC_FUNCTION(sdhi2), + SH_PFC_FUNCTION(ssi), SH_PFC_FUNCTION(usb0), SH_PFC_FUNCTION(usb1), SH_PFC_FUNCTION(vin0), diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index 76502aab2cb1ce..c03dcc7729eb5f 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include #include @@ -27,22 +25,24 @@ #include #include #include -#include #include "pinctrl-sirf.h" #define DRIVER_NAME "pinmux-sirf" struct sirfsoc_gpio_bank { - struct of_mm_gpio_chip chip; - struct irq_domain *domain; int id; int parent_irq; spinlock_t lock; +}; + +struct sirfsoc_gpio_chip { + struct of_mm_gpio_chip chip; bool is_marco; /* for marco, some registers are different with prima2 */ + struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS]; }; -static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS]; +static struct sirfsoc_gpio_chip sgpio_chip; static DEFINE_SPINLOCK(sgpio_lock); static struct sirfsoc_pin_group *sirfsoc_pin_groups; @@ -258,32 +258,12 @@ static struct pinctrl_desc sirfsoc_pinmux_desc = { /* * Todo: bind irq_chip to every pinctrl_gpio_range */ -static struct pinctrl_gpio_range sirfsoc_gpio_ranges[] = { - { - .name = "sirfsoc-gpio*", - .id = 0, - .base = 0, - .pin_base = 0, - .npins = 32, - }, { - .name = "sirfsoc-gpio*", - .id = 1, - .base = 32, - .pin_base = 32, - .npins = 32, - }, { - .name = "sirfsoc-gpio*", - .id = 2, - .base = 64, - .pin_base = 64, - .npins = 32, - }, { - .name = "sirfsoc-gpio*", - .id = 3, - .base = 96, - .pin_base = 96, - .npins = 19, - }, +static struct pinctrl_gpio_range sirfsoc_gpio_ranges = { + .name = "sirfsoc-gpio*", + .id = 0, + .base = 0, + .pin_base = 0, + .npins = SIRFSOC_GPIO_BANK_SIZE * SIRFSOC_GPIO_NO_OF_BANKS, }; static void __iomem *sirfsoc_rsc_of_iomap(void) @@ -303,19 +283,19 @@ static void __iomem *sirfsoc_rsc_of_iomap(void) } static int sirfsoc_gpio_of_xlate(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, - u32 *flags) + const struct of_phandle_args *gpiospec, + u32 *flags) { - if (gpiospec->args[0] > SIRFSOC_GPIO_NO_OF_BANKS * SIRFSOC_GPIO_BANK_SIZE) + if (gpiospec->args[0] > SIRFSOC_GPIO_NO_OF_BANKS * SIRFSOC_GPIO_BANK_SIZE) return -EINVAL; - if (gc != &sgpio_bank[gpiospec->args[0] / SIRFSOC_GPIO_BANK_SIZE].chip.gc) + if (gc != &sgpio_chip.chip.gc) return -EINVAL; - if (flags) + if (flags) *flags = gpiospec->args[1]; - return gpiospec->args[0] % SIRFSOC_GPIO_BANK_SIZE; + return gpiospec->args[0]; } static const struct of_device_id pinmux_ids[] = { @@ -331,7 +311,6 @@ static int sirfsoc_pinmux_probe(struct platform_device *pdev) struct sirfsoc_pmx *spmx; struct device_node *np = pdev->dev.of_node; const struct sirfsoc_pinctrl_data *pdata; - int i; /* Create state holders etc for this driver */ spmx = devm_kzalloc(&pdev->dev, sizeof(*spmx), GFP_KERNEL); @@ -375,10 +354,8 @@ static int sirfsoc_pinmux_probe(struct platform_device *pdev) goto out_no_pmx; } - for (i = 0; i < ARRAY_SIZE(sirfsoc_gpio_ranges); i++) { - sirfsoc_gpio_ranges[i].gc = &sgpio_bank[i].chip.gc; - pinctrl_add_gpio_range(spmx->pmx, &sirfsoc_gpio_ranges[i]); - } + sirfsoc_gpio_ranges.gc = &sgpio_chip.chip.gc; + pinctrl_add_gpio_range(spmx->pmx, &sirfsoc_gpio_ranges); dev_info(&pdev->dev, "initialized SIRFSOC pinmux driver\n"); @@ -464,33 +441,19 @@ static int __init sirfsoc_pinmux_init(void) } arch_initcall(sirfsoc_pinmux_init); -static inline int sirfsoc_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct sirfsoc_gpio_bank *bank = container_of(to_of_mm_gpio_chip(chip), - struct sirfsoc_gpio_bank, chip); - - return irq_create_mapping(bank->domain, offset + bank->id * - SIRFSOC_GPIO_BANK_SIZE); -} - -static inline int sirfsoc_gpio_to_offset(unsigned int gpio) -{ - return gpio % SIRFSOC_GPIO_BANK_SIZE; -} - static inline struct sirfsoc_gpio_bank *sirfsoc_gpio_to_bank(unsigned int gpio) { - return &sgpio_bank[gpio / SIRFSOC_GPIO_BANK_SIZE]; + return &sgpio_chip.sgpio_bank[gpio / SIRFSOC_GPIO_BANK_SIZE]; } -static inline struct sirfsoc_gpio_bank *sirfsoc_irqchip_to_bank(struct gpio_chip *chip) +static inline int sirfsoc_gpio_to_bankoff(unsigned int gpio) { - return container_of(to_of_mm_gpio_chip(chip), struct sirfsoc_gpio_bank, chip); + return gpio % SIRFSOC_GPIO_BANK_SIZE; } static void sirfsoc_gpio_irq_ack(struct irq_data *d) { - struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(d->hwirq); int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE; u32 val, offset; unsigned long flags; @@ -499,9 +462,9 @@ static void sirfsoc_gpio_irq_ack(struct irq_data *d) spin_lock_irqsave(&sgpio_lock, flags); - val = readl(bank->chip.regs + offset); + val = readl(sgpio_chip.chip.regs + offset); - writel(val, bank->chip.regs + offset); + writel(val, sgpio_chip.chip.regs + offset); spin_unlock_irqrestore(&sgpio_lock, flags); } @@ -515,24 +478,24 @@ static void __sirfsoc_gpio_irq_mask(struct sirfsoc_gpio_bank *bank, int idx) spin_lock_irqsave(&sgpio_lock, flags); - val = readl(bank->chip.regs + offset); + val = readl(sgpio_chip.chip.regs + offset); val &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK; val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK; - writel(val, bank->chip.regs + offset); + writel(val, sgpio_chip.chip.regs + offset); spin_unlock_irqrestore(&sgpio_lock, flags); } static void sirfsoc_gpio_irq_mask(struct irq_data *d) { - struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(d->hwirq); __sirfsoc_gpio_irq_mask(bank, d->hwirq % SIRFSOC_GPIO_BANK_SIZE); } static void sirfsoc_gpio_irq_unmask(struct irq_data *d) { - struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(d->hwirq); int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE; u32 val, offset; unsigned long flags; @@ -541,17 +504,17 @@ static void sirfsoc_gpio_irq_unmask(struct irq_data *d) spin_lock_irqsave(&sgpio_lock, flags); - val = readl(bank->chip.regs + offset); + val = readl(sgpio_chip.chip.regs + offset); val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK; val |= SIRFSOC_GPIO_CTL_INTR_EN_MASK; - writel(val, bank->chip.regs + offset); + writel(val, sgpio_chip.chip.regs + offset); spin_unlock_irqrestore(&sgpio_lock, flags); } static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type) { - struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(d->hwirq); int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE; u32 val, offset; unsigned long flags; @@ -560,7 +523,7 @@ static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type) spin_lock_irqsave(&sgpio_lock, flags); - val = readl(bank->chip.regs + offset); + val = readl(sgpio_chip.chip.regs + offset); val &= ~(SIRFSOC_GPIO_CTL_INTR_STS_MASK | SIRFSOC_GPIO_CTL_OUT_EN_MASK); switch (type) { @@ -588,53 +551,39 @@ static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type) break; } - writel(val, bank->chip.regs + offset); + writel(val, sgpio_chip.chip.regs + offset); spin_unlock_irqrestore(&sgpio_lock, flags); return 0; } -static int sirfsoc_gpio_irq_reqres(struct irq_data *d) -{ - struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); - - if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE)) { - dev_err(bank->chip.gc.dev, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); - return -EINVAL; - } - return 0; -} - -static void sirfsoc_gpio_irq_relres(struct irq_data *d) -{ - struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); - - gpio_unlock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE); -} - static struct irq_chip sirfsoc_irq_chip = { .name = "sirf-gpio-irq", .irq_ack = sirfsoc_gpio_irq_ack, .irq_mask = sirfsoc_gpio_irq_mask, .irq_unmask = sirfsoc_gpio_irq_unmask, .irq_set_type = sirfsoc_gpio_irq_type, - .irq_request_resources = sirfsoc_gpio_irq_reqres, - .irq_release_resources = sirfsoc_gpio_irq_relres, }; static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) { - struct sirfsoc_gpio_bank *bank = irq_get_handler_data(irq); + struct sirfsoc_gpio_bank *bank; u32 status, ctrl; int idx = 0; struct irq_chip *chip = irq_get_chip(irq); + int i; + + for (i = 0; i < SIRFSOC_GPIO_BANK_SIZE; i++) { + bank = &sgpio_chip.sgpio_bank[i]; + if (bank->parent_irq == irq) + break; + } + BUG_ON (i == SIRFSOC_GPIO_BANK_SIZE); chained_irq_enter(chip, desc); - status = readl(bank->chip.regs + SIRFSOC_GPIO_INT_STATUS(bank->id)); + status = readl(sgpio_chip.chip.regs + SIRFSOC_GPIO_INT_STATUS(bank->id)); if (!status) { printk(KERN_WARNING "%s: gpio id %d status %#x no interrupt is flaged\n", @@ -644,7 +593,7 @@ static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) } while (status) { - ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, idx)); + ctrl = readl(sgpio_chip.chip.regs + SIRFSOC_GPIO_CTRL(bank->id, idx)); /* * Here we must check whether the corresponding GPIO's interrupt @@ -653,7 +602,7 @@ static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) { pr_debug("%s: gpio id %d idx %d happens\n", __func__, bank->id, idx); - generic_handle_irq(irq_find_mapping(bank->domain, idx + + generic_handle_irq(irq_find_mapping(sgpio_chip.chip.gc.irqdomain, idx + bank->id * SIRFSOC_GPIO_BANK_SIZE)); } @@ -668,14 +617,14 @@ static inline void sirfsoc_gpio_set_input(struct sirfsoc_gpio_bank *bank, unsign { u32 val; - val = readl(bank->chip.regs + ctrl_offset); + val = readl(sgpio_chip.chip.regs + ctrl_offset); val &= ~SIRFSOC_GPIO_CTL_OUT_EN_MASK; - writel(val, bank->chip.regs + ctrl_offset); + writel(val, sgpio_chip.chip.regs + ctrl_offset); } static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset) { - struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); + struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(offset); unsigned long flags; if (pinctrl_request_gpio(chip->base + offset)) @@ -697,7 +646,7 @@ static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset) static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset) { - struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); + struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(offset); unsigned long flags; spin_lock_irqsave(&bank->lock, flags); @@ -712,8 +661,8 @@ static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset) static int sirfsoc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { - struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); - int idx = sirfsoc_gpio_to_offset(gpio); + struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(gpio); + int idx = sirfsoc_gpio_to_bankoff(gpio); unsigned long flags; unsigned offset; @@ -736,7 +685,7 @@ static inline void sirfsoc_gpio_set_output(struct sirfsoc_gpio_bank *bank, unsig spin_lock_irqsave(&bank->lock, flags); - out_ctrl = readl(bank->chip.regs + offset); + out_ctrl = readl(sgpio_chip.chip.regs + offset); if (value) out_ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK; else @@ -744,15 +693,15 @@ static inline void sirfsoc_gpio_set_output(struct sirfsoc_gpio_bank *bank, unsig out_ctrl &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK; out_ctrl |= SIRFSOC_GPIO_CTL_OUT_EN_MASK; - writel(out_ctrl, bank->chip.regs + offset); + writel(out_ctrl, sgpio_chip.chip.regs + offset); spin_unlock_irqrestore(&bank->lock, flags); } static int sirfsoc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) { - struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); - int idx = sirfsoc_gpio_to_offset(gpio); + struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(gpio); + int idx = sirfsoc_gpio_to_bankoff(gpio); u32 offset; unsigned long flags; @@ -769,13 +718,13 @@ static int sirfsoc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset) { - struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); + struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(offset); u32 val; unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - val = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); + val = readl(sgpio_chip.chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); spin_unlock_irqrestore(&bank->lock, flags); @@ -785,43 +734,22 @@ static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset) static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset, int value) { - struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); + struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(offset); u32 ctrl; unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); + ctrl = readl(sgpio_chip.chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); if (value) ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK; else ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK; - writel(ctrl, bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); + writel(ctrl, sgpio_chip.chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); spin_unlock_irqrestore(&bank->lock, flags); } -static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct sirfsoc_gpio_bank *bank = d->host_data; - - if (!bank) - return -EINVAL; - - irq_set_chip(irq, &sirfsoc_irq_chip); - irq_set_handler(irq, handle_level_irq); - irq_set_chip_data(irq, bank + hwirq / SIRFSOC_GPIO_BANK_SIZE); - set_irq_flags(irq, IRQF_VALID); - - return 0; -} - -static const struct irq_domain_ops sirfsoc_gpio_irq_simple_ops = { - .map = sirfsoc_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - static void sirfsoc_gpio_set_pullup(const u32 *pullups) { int i, n; @@ -830,10 +758,10 @@ static void sirfsoc_gpio_set_pullup(const u32 *pullups) for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { for_each_set_bit(n, p + i, BITS_PER_LONG) { u32 offset = SIRFSOC_GPIO_CTRL(i, n); - u32 val = readl(sgpio_bank[i].chip.regs + offset); + u32 val = readl(sgpio_chip.chip.regs + offset); val |= SIRFSOC_GPIO_CTL_PULL_MASK; val |= SIRFSOC_GPIO_CTL_PULL_HIGH; - writel(val, sgpio_bank[i].chip.regs + offset); + writel(val, sgpio_chip.chip.regs + offset); } } } @@ -846,10 +774,10 @@ static void sirfsoc_gpio_set_pulldown(const u32 *pulldowns) for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { for_each_set_bit(n, p + i, BITS_PER_LONG) { u32 offset = SIRFSOC_GPIO_CTRL(i, n); - u32 val = readl(sgpio_bank[i].chip.regs + offset); + u32 val = readl(sgpio_chip.chip.regs + offset); val |= SIRFSOC_GPIO_CTL_PULL_MASK; val &= ~SIRFSOC_GPIO_CTL_PULL_HIGH; - writel(val, sgpio_bank[i].chip.regs + offset); + writel(val, sgpio_chip.chip.regs + offset); } } } @@ -860,7 +788,6 @@ static int sirfsoc_gpio_probe(struct device_node *np) struct sirfsoc_gpio_bank *bank; void __iomem *regs; struct platform_device *pdev; - struct irq_domain *domain; bool is_marco = false; u32 pullups[SIRFSOC_GPIO_NO_OF_BANKS], pulldowns[SIRFSOC_GPIO_NO_OF_BANKS]; @@ -876,51 +803,52 @@ static int sirfsoc_gpio_probe(struct device_node *np) if (of_device_is_compatible(np, "sirf,marco-pinctrl")) is_marco = 1; - domain = irq_domain_add_linear(np, SIRFSOC_GPIO_BANK_SIZE * SIRFSOC_GPIO_NO_OF_BANKS, - &sirfsoc_gpio_irq_simple_ops, sgpio_bank); - if (!domain) { - pr_err("%s: Failed to create irqdomain\n", np->full_name); - err = -ENOSYS; + sgpio_chip.chip.gc.request = sirfsoc_gpio_request; + sgpio_chip.chip.gc.free = sirfsoc_gpio_free; + sgpio_chip.chip.gc.direction_input = sirfsoc_gpio_direction_input; + sgpio_chip.chip.gc.get = sirfsoc_gpio_get_value; + sgpio_chip.chip.gc.direction_output = sirfsoc_gpio_direction_output; + sgpio_chip.chip.gc.set = sirfsoc_gpio_set_value; + sgpio_chip.chip.gc.base = 0; + sgpio_chip.chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE * SIRFSOC_GPIO_NO_OF_BANKS; + sgpio_chip.chip.gc.label = kstrdup(np->full_name, GFP_KERNEL); + sgpio_chip.chip.gc.of_node = np; + sgpio_chip.chip.gc.of_xlate = sirfsoc_gpio_of_xlate; + sgpio_chip.chip.gc.of_gpio_n_cells = 2; + sgpio_chip.chip.gc.dev = &pdev->dev; + sgpio_chip.chip.regs = regs; + sgpio_chip.is_marco = is_marco; + + err = gpiochip_add(&sgpio_chip.chip.gc); + if (err) { + dev_err(&pdev->dev, "%s: error in probe function with status %d\n", + np->full_name, err); + goto out; + } + + err = gpiochip_irqchip_add(&sgpio_chip.chip.gc, + &sirfsoc_irq_chip, + 0, handle_level_irq, + IRQ_TYPE_NONE); + if (err) { + dev_err(&pdev->dev, + "could not connect irqchip to gpiochip\n"); goto out; } for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { - bank = &sgpio_bank[i]; + bank = &sgpio_chip.sgpio_bank[i]; spin_lock_init(&bank->lock); - bank->chip.gc.request = sirfsoc_gpio_request; - bank->chip.gc.free = sirfsoc_gpio_free; - bank->chip.gc.direction_input = sirfsoc_gpio_direction_input; - bank->chip.gc.get = sirfsoc_gpio_get_value; - bank->chip.gc.direction_output = sirfsoc_gpio_direction_output; - bank->chip.gc.set = sirfsoc_gpio_set_value; - bank->chip.gc.to_irq = sirfsoc_gpio_to_irq; - bank->chip.gc.base = i * SIRFSOC_GPIO_BANK_SIZE; - bank->chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE; - bank->chip.gc.label = kstrdup(np->full_name, GFP_KERNEL); - bank->chip.gc.of_node = np; - bank->chip.gc.of_xlate = sirfsoc_gpio_of_xlate; - bank->chip.gc.of_gpio_n_cells = 2; - bank->chip.gc.dev = &pdev->dev; - bank->chip.regs = regs; - bank->id = i; - bank->is_marco = is_marco; bank->parent_irq = platform_get_irq(pdev, i); if (bank->parent_irq < 0) { err = bank->parent_irq; goto out; } - err = gpiochip_add(&bank->chip.gc); - if (err) { - pr_err("%s: error in probe function with status %d\n", - np->full_name, err); - goto out; - } - - bank->domain = domain; - - irq_set_chained_handler(bank->parent_irq, sirfsoc_gpio_handle_irq); - irq_set_handler_data(bank->parent_irq, bank); + gpiochip_set_chained_irqchip(&sgpio_chip.chip.gc, + &sirfsoc_irq_chip, + bank->parent_irq, + sirfsoc_gpio_handle_irq); } if (!of_property_read_u32_array(np, "sirf,pullups", pullups, diff --git a/drivers/platform/goldfish/pdev_bus.c b/drivers/platform/goldfish/pdev_bus.c index 92cc4cfafde581..4eb2bb34790d25 100644 --- a/drivers/platform/goldfish/pdev_bus.c +++ b/drivers/platform/goldfish/pdev_bus.c @@ -184,11 +184,6 @@ static int goldfish_pdev_bus_probe(struct platform_device *pdev) pdev_bus_addr = r->start; pdev_bus_len = resource_size(r); - if (request_mem_region(pdev_bus_addr, pdev_bus_len, "goldfish")) { - dev_err(&pdev->dev, "unable to reserve Goldfish MMIO.\n"); - return -EBUSY; - } - pdev_bus_base = ioremap(pdev_bus_addr, pdev_bus_len); if (pdev_bus_base == NULL) { ret = -ENOMEM; diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index deb7f4bcdb7b6b..438d4c72c7b36c 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -37,7 +37,7 @@ __visible struct { * kernel begins at offset 3GB... */ -asmlinkage void pnp_bios_callfunc(void); +asmlinkage __visible void pnp_bios_callfunc(void); __asm__(".text \n" __ALIGN_STR "\n" diff --git a/drivers/power/tps65090-charger.c b/drivers/power/tps65090-charger.c index 8fc9d6df87f682..1685f63b9e5d03 100644 --- a/drivers/power/tps65090-charger.c +++ b/drivers/power/tps65090-charger.c @@ -28,17 +28,6 @@ #include -#define TPS65090_REG_INTR_STS 0x00 -#define TPS65090_REG_INTR_MASK 0x02 -#define TPS65090_REG_CG_CTRL0 0x04 -#define TPS65090_REG_CG_CTRL1 0x05 -#define TPS65090_REG_CG_CTRL2 0x06 -#define TPS65090_REG_CG_CTRL3 0x07 -#define TPS65090_REG_CG_CTRL4 0x08 -#define TPS65090_REG_CG_CTRL5 0x09 -#define TPS65090_REG_CG_STATUS1 0x0a -#define TPS65090_REG_CG_STATUS2 0x0b - #define TPS65090_CHARGER_ENABLE BIT(0) #define TPS65090_VACG BIT(1) #define TPS65090_NOITERM BIT(5) diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index d9a0770b6c73d2..b1cda6ffdbcc5f 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -951,7 +951,9 @@ static const struct x86_cpu_id rapl_ids[] = { { X86_VENDOR_INTEL, 6, 0x2d},/* Sandy Bridge EP */ { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */ { X86_VENDOR_INTEL, 6, 0x3a},/* Ivy Bridge */ - { X86_VENDOR_INTEL, 6, 0x45},/* Haswell */ + { X86_VENDOR_INTEL, 6, 0x3c},/* Haswell */ + { X86_VENDOR_INTEL, 6, 0x3d},/* Broadwell */ + { X86_VENDOR_INTEL, 6, 0x45},/* Haswell ULT */ /* TODO: Add more CPU IDs after testing */ {} }; @@ -1124,8 +1126,7 @@ static int rapl_register_powercap(void) static int rapl_check_domain(int cpu, int domain) { unsigned msr; - u64 val1, val2 = 0; - int retry = 0; + u64 val = 0; switch (domain) { case RAPL_DOMAIN_PACKAGE: @@ -1144,26 +1145,13 @@ static int rapl_check_domain(int cpu, int domain) pr_err("invalid domain id %d\n", domain); return -EINVAL; } - if (rdmsrl_safe_on_cpu(cpu, msr, &val1)) - return -ENODEV; - - /* PP1/uncore/graphics domain may not be active at the time of - * driver loading. So skip further checks. + /* make sure domain counters are available and contains non-zero + * values, otherwise skip it. */ - if (domain == RAPL_DOMAIN_PP1) - return 0; - /* energy counters roll slowly on some domains */ - while (++retry < 10) { - usleep_range(10000, 15000); - rdmsrl_safe_on_cpu(cpu, msr, &val2); - if ((val1 & ENERGY_STATUS_MASK) != (val2 & ENERGY_STATUS_MASK)) - return 0; - } - /* if energy counter does not change, report as bad domain */ - pr_info("domain %s energy ctr %llu:%llu not working, skip\n", - rapl_domain_names[domain], val1, val2); + if (rdmsrl_safe_on_cpu(cpu, msr, &val) || !val) + return -ENODEV; - return -ENODEV; + return 0; } /* Detect active and valid domains for the given CPU, caller must @@ -1180,6 +1168,9 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu) /* use physical package id to read counters */ if (!rapl_check_domain(cpu, i)) rp->domain_map |= 1 << i; + else + pr_warn("RAPL domain %s detection failed\n", + rapl_domain_names[i]); } rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX); if (!rp->nr_domains) { diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index e25d2bc898e5b6..296b0ec8744da9 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -142,7 +142,10 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx) delta = ktime_to_ns(kt); err = ops->adjtime(ops, delta); } else if (tx->modes & ADJ_FREQUENCY) { - err = ops->adjfreq(ops, scaled_ppm_to_ppb(tx->freq)); + s32 ppb = scaled_ppm_to_ppb(tx->freq); + if (ppb > ops->max_adj || ppb < -ops->max_adj) + return -ERANGE; + err = ops->adjfreq(ops, ppb); ptp->dialed_frequency = tx->freq; } else if (tx->modes == 0) { tx->freq = ptp->dialed_frequency; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 5b34ff29ea3804..4ad7b89a4cb44c 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -62,6 +62,15 @@ config PWM_ATMEL_TCB To compile this driver as a module, choose M here: the module will be called pwm-atmel-tcb. +config PWM_BCM_KONA + tristate "Kona PWM support" + depends on ARCH_BCM_MOBILE + help + Generic PWM framework driver for Broadcom Kona PWM block. + + To compile this driver as a module, choose M here: the module + will be called pwm-bcm-kona. + config PWM_BFIN tristate "Blackfin PWM support" depends on BFIN_GPTIMERS diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index e57d2c38a79403..5c86a19d5d39c0 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_PWM_SYSFS) += sysfs.o obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o +obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c index 1d07a6f9937541..9d53e8ef90d00c 100644 --- a/drivers/pwm/pwm-ab8500.c +++ b/drivers/pwm/pwm-ab8500.c @@ -101,10 +101,8 @@ static int ab8500_pwm_probe(struct platform_device *pdev) * device which is required for ab8500 read and write */ ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL); - if (ab8500 == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (ab8500 == NULL) return -ENOMEM; - } ab8500->chip.dev = &pdev->dev; ab8500->chip.ops = &ab8500_pwm_ops; diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c new file mode 100644 index 00000000000000..02bc048892a9f3 --- /dev/null +++ b/drivers/pwm/pwm-bcm-kona.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2014 Broadcom 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The Kona PWM has some unusual characteristics. Here are the main points. + * + * 1) There is no disable bit and the hardware docs advise programming a zero + * duty to achieve output equivalent to that of a normal disable operation. + * + * 2) Changes to prescale, duty, period, and polarity do not take effect until + * a subsequent rising edge of the trigger bit. + * + * 3) If the smooth bit and trigger bit are both low, the output is a constant + * high signal. Otherwise, the earlier waveform continues to be output. + * + * 4) If the smooth bit is set on the rising edge of the trigger bit, output + * will transition to the new settings on a period boundary (which could be + * seconds away). If the smooth bit is clear, new settings will be applied + * as soon as possible (the hardware always has a 400ns delay). + * + * 5) When the external clock that feeds the PWM is disabled, output is pegged + * high or low depending on its state at that exact instant. + */ + +#define PWM_CONTROL_OFFSET (0x00000000) +#define PWM_CONTROL_SMOOTH_SHIFT(chan) (24 + (chan)) +#define PWM_CONTROL_TYPE_SHIFT(chan) (16 + (chan)) +#define PWM_CONTROL_POLARITY_SHIFT(chan) (8 + (chan)) +#define PWM_CONTROL_TRIGGER_SHIFT(chan) (chan) + +#define PRESCALE_OFFSET (0x00000004) +#define PRESCALE_SHIFT(chan) ((chan) << 2) +#define PRESCALE_MASK(chan) (0x7 << PRESCALE_SHIFT(chan)) +#define PRESCALE_MIN (0x00000000) +#define PRESCALE_MAX (0x00000007) + +#define PERIOD_COUNT_OFFSET(chan) (0x00000008 + ((chan) << 3)) +#define PERIOD_COUNT_MIN (0x00000002) +#define PERIOD_COUNT_MAX (0x00ffffff) + +#define DUTY_CYCLE_HIGH_OFFSET(chan) (0x0000000c + ((chan) << 3)) +#define DUTY_CYCLE_HIGH_MIN (0x00000000) +#define DUTY_CYCLE_HIGH_MAX (0x00ffffff) + +struct kona_pwmc { + struct pwm_chip chip; + void __iomem *base; + struct clk *clk; +}; + +static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *_chip) +{ + return container_of(_chip, struct kona_pwmc, chip); +} + +static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan) +{ + unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET); + + /* Clear trigger bit but set smooth bit to maintain old output */ + value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan); + value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan)); + writel(value, kp->base + PWM_CONTROL_OFFSET); + + /* Set trigger bit and clear smooth bit to apply new settings */ + value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan)); + value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan); + writel(value, kp->base + PWM_CONTROL_OFFSET); +} + +static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct kona_pwmc *kp = to_kona_pwmc(chip); + u64 val, div, rate; + unsigned long prescale = PRESCALE_MIN, pc, dc; + unsigned int value, chan = pwm->hwpwm; + + /* + * Find period count, duty count and prescale to suit duty_ns and + * period_ns. This is done according to formulas described below: + * + * period_ns = 10^9 * (PRESCALE + 1) * PC / PWM_CLK_RATE + * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE + * + * PC = (PWM_CLK_RATE * period_ns) / (10^9 * (PRESCALE + 1)) + * DC = (PWM_CLK_RATE * duty_ns) / (10^9 * (PRESCALE + 1)) + */ + + rate = clk_get_rate(kp->clk); + + while (1) { + div = 1000000000; + div *= 1 + prescale; + val = rate * period_ns; + pc = div64_u64(val, div); + val = rate * duty_ns; + dc = div64_u64(val, div); + + /* If duty_ns or period_ns are not achievable then return */ + if (pc < PERIOD_COUNT_MIN || dc < DUTY_CYCLE_HIGH_MIN) + return -EINVAL; + + /* If pc and dc are in bounds, the calculation is done */ + if (pc <= PERIOD_COUNT_MAX && dc <= DUTY_CYCLE_HIGH_MAX) + break; + + /* Otherwise, increase prescale and recalculate pc and dc */ + if (++prescale > PRESCALE_MAX) + return -EINVAL; + } + + /* If the PWM channel is enabled, write the settings to the HW */ + if (test_bit(PWMF_ENABLED, &pwm->flags)) { + value = readl(kp->base + PRESCALE_OFFSET); + value &= ~PRESCALE_MASK(chan); + value |= prescale << PRESCALE_SHIFT(chan); + writel(value, kp->base + PRESCALE_OFFSET); + + writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan)); + + writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan)); + + kona_pwmc_apply_settings(kp, chan); + } + + return 0; +} + +static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, + enum pwm_polarity polarity) +{ + struct kona_pwmc *kp = to_kona_pwmc(chip); + unsigned int chan = pwm->hwpwm; + unsigned int value; + int ret; + + ret = clk_prepare_enable(kp->clk); + if (ret < 0) { + dev_err(chip->dev, "failed to enable clock: %d\n", ret); + return ret; + } + + value = readl(kp->base + PWM_CONTROL_OFFSET); + + if (polarity == PWM_POLARITY_NORMAL) + value |= 1 << PWM_CONTROL_POLARITY_SHIFT(chan); + else + value &= ~(1 << PWM_CONTROL_POLARITY_SHIFT(chan)); + + writel(value, kp->base + PWM_CONTROL_OFFSET); + + kona_pwmc_apply_settings(kp, chan); + + /* Wait for waveform to settle before gating off the clock */ + ndelay(400); + + clk_disable_unprepare(kp->clk); + + return 0; +} + +static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct kona_pwmc *kp = to_kona_pwmc(chip); + int ret; + + ret = clk_prepare_enable(kp->clk); + if (ret < 0) { + dev_err(chip->dev, "failed to enable clock: %d\n", ret); + return ret; + } + + ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period); + if (ret < 0) { + clk_disable_unprepare(kp->clk); + return ret; + } + + return 0; +} + +static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct kona_pwmc *kp = to_kona_pwmc(chip); + unsigned int chan = pwm->hwpwm; + + /* Simulate a disable by configuring for zero duty */ + writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan)); + kona_pwmc_apply_settings(kp, chan); + + /* Wait for waveform to settle before gating off the clock */ + ndelay(400); + + clk_disable_unprepare(kp->clk); +} + +static const struct pwm_ops kona_pwm_ops = { + .config = kona_pwmc_config, + .set_polarity = kona_pwmc_set_polarity, + .enable = kona_pwmc_enable, + .disable = kona_pwmc_disable, + .owner = THIS_MODULE, +}; + +static int kona_pwmc_probe(struct platform_device *pdev) +{ + struct kona_pwmc *kp; + struct resource *res; + unsigned int chan; + unsigned int value = 0; + int ret = 0; + + kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL); + if (kp == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, kp); + + kp->chip.dev = &pdev->dev; + kp->chip.ops = &kona_pwm_ops; + kp->chip.base = -1; + kp->chip.npwm = 6; + kp->chip.of_xlate = of_pwm_xlate_with_flags; + kp->chip.of_pwm_n_cells = 3; + kp->chip.can_sleep = true; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + kp->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(kp->base)) + return PTR_ERR(kp->base); + + kp->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(kp->clk)) { + dev_err(&pdev->dev, "failed to get clock: %ld\n", + PTR_ERR(kp->clk)); + return PTR_ERR(kp->clk); + } + + ret = clk_prepare_enable(kp->clk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); + return ret; + } + + /* Set smooth mode, push/pull, and normal polarity for all channels */ + for (chan = 0; chan < kp->chip.npwm; chan++) { + value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan)); + value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan)); + value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan)); + } + + writel(value, kp->base + PWM_CONTROL_OFFSET); + + clk_disable_unprepare(kp->clk); + + ret = pwmchip_add(&kp->chip); + if (ret < 0) + dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); + + return ret; +} + +static int kona_pwmc_remove(struct platform_device *pdev) +{ + struct kona_pwmc *kp = platform_get_drvdata(pdev); + unsigned int chan; + + for (chan = 0; chan < kp->chip.npwm; chan++) + if (test_bit(PWMF_ENABLED, &kp->chip.pwms[chan].flags)) + clk_disable_unprepare(kp->clk); + + return pwmchip_remove(&kp->chip); +} + +static const struct of_device_id bcm_kona_pwmc_dt[] = { + { .compatible = "brcm,kona-pwm" }, + { }, +}; +MODULE_DEVICE_TABLE(of, bcm_kona_pwmc_dt); + +static struct platform_driver kona_pwmc_driver = { + .driver = { + .name = "bcm-kona-pwm", + .of_match_table = bcm_kona_pwmc_dt, + }, + .probe = kona_pwmc_probe, + .remove = kona_pwmc_remove, +}; +module_platform_driver(kona_pwmc_driver); + +MODULE_AUTHOR("Broadcom Corporation "); +MODULE_AUTHOR("Tim Kryger "); +MODULE_DESCRIPTION("Broadcom Kona PWM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index cc477334487494..d797c7b84c3feb 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -241,10 +241,8 @@ static int imx_pwm_probe(struct platform_device *pdev) return -ENODEV; imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); - if (imx == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (imx == NULL) return -ENOMEM; - } imx->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(imx->clk_per)) { diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 449e372050a0ed..44ce6c6103ae40 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -6,6 +6,7 @@ * Author: Chew Kean Ho * Author: Chang Rebecca Swee Fun * Author: Chew Chiau Ee + * Author: Alan Cox * * 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 @@ -19,6 +20,9 @@ #include #include #include +#include + +static int pci_drv, plat_drv; /* So we know which drivers registered */ #define PWM 0x00000000 #define PWM_ENABLE BIT(31) @@ -34,6 +38,16 @@ struct pwm_lpss_chip { struct pwm_chip chip; void __iomem *regs; struct clk *clk; + unsigned long clk_rate; +}; + +struct pwm_lpss_boardinfo { + unsigned long clk_rate; +}; + +/* BayTrail */ +static const struct pwm_lpss_boardinfo byt_info = { + 25000000 }; static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) @@ -55,7 +69,7 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, /* The equation is: base_unit = ((freq / c) * 65536) + correction */ base_unit = freq * 65536; - c = clk_get_rate(lpwm->clk); + c = lpwm->clk_rate; if (!c) return -EINVAL; @@ -113,52 +127,48 @@ static const struct pwm_ops pwm_lpss_ops = { .owner = THIS_MODULE, }; -static const struct acpi_device_id pwm_lpss_acpi_match[] = { - { "80860F09", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match); - -static int pwm_lpss_probe(struct platform_device *pdev) +static struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, + struct resource *r, + const struct pwm_lpss_boardinfo *info) { struct pwm_lpss_chip *lpwm; - struct resource *r; int ret; - lpwm = devm_kzalloc(&pdev->dev, sizeof(*lpwm), GFP_KERNEL); + lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL); if (!lpwm) - return -ENOMEM; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + return ERR_PTR(-ENOMEM); - lpwm->regs = devm_ioremap_resource(&pdev->dev, r); + lpwm->regs = devm_ioremap_resource(dev, r); if (IS_ERR(lpwm->regs)) - return PTR_ERR(lpwm->regs); - - lpwm->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(lpwm->clk)) { - dev_err(&pdev->dev, "failed to get PWM clock\n"); - return PTR_ERR(lpwm->clk); + return ERR_CAST(lpwm->regs); + + if (info) { + lpwm->clk_rate = info->clk_rate; + } else { + lpwm->clk = devm_clk_get(dev, NULL); + if (IS_ERR(lpwm->clk)) { + dev_err(dev, "failed to get PWM clock\n"); + return ERR_CAST(lpwm->clk); + } + lpwm->clk_rate = clk_get_rate(lpwm->clk); } - lpwm->chip.dev = &pdev->dev; + lpwm->chip.dev = dev; lpwm->chip.ops = &pwm_lpss_ops; lpwm->chip.base = -1; lpwm->chip.npwm = 1; ret = pwmchip_add(&lpwm->chip); if (ret) { - dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); - return ret; + dev_err(dev, "failed to add PWM chip: %d\n", ret); + return ERR_PTR(ret); } - platform_set_drvdata(pdev, lpwm); - return 0; + return lpwm; } -static int pwm_lpss_remove(struct platform_device *pdev) +static int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) { - struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev); u32 ctrl; ctrl = readl(lpwm->regs + PWM); @@ -167,15 +177,104 @@ static int pwm_lpss_remove(struct platform_device *pdev) return pwmchip_remove(&lpwm->chip); } -static struct platform_driver pwm_lpss_driver = { +static int pwm_lpss_probe_pci(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + const struct pwm_lpss_boardinfo *info; + struct pwm_lpss_chip *lpwm; + int err; + + err = pci_enable_device(pdev); + if (err < 0) + return err; + + info = (struct pwm_lpss_boardinfo *)id->driver_data; + lpwm = pwm_lpss_probe(&pdev->dev, &pdev->resource[0], info); + if (IS_ERR(lpwm)) + return PTR_ERR(lpwm); + + pci_set_drvdata(pdev, lpwm); + return 0; +} + +static void pwm_lpss_remove_pci(struct pci_dev *pdev) +{ + struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev); + + pwm_lpss_remove(lpwm); + pci_disable_device(pdev); +} + +static struct pci_device_id pwm_lpss_pci_ids[] = { + { PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&byt_info}, + { PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&byt_info}, + { }, +}; +MODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids); + +static struct pci_driver pwm_lpss_driver_pci = { + .name = "pwm-lpss", + .id_table = pwm_lpss_pci_ids, + .probe = pwm_lpss_probe_pci, + .remove = pwm_lpss_remove_pci, +}; + +static int pwm_lpss_probe_platform(struct platform_device *pdev) +{ + struct pwm_lpss_chip *lpwm; + struct resource *r; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + lpwm = pwm_lpss_probe(&pdev->dev, r, NULL); + if (IS_ERR(lpwm)) + return PTR_ERR(lpwm); + + platform_set_drvdata(pdev, lpwm); + return 0; +} + +static int pwm_lpss_remove_platform(struct platform_device *pdev) +{ + struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev); + + return pwm_lpss_remove(lpwm); +} + +static const struct acpi_device_id pwm_lpss_acpi_match[] = { + { "80860F09", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match); + +static struct platform_driver pwm_lpss_driver_platform = { .driver = { .name = "pwm-lpss", .acpi_match_table = pwm_lpss_acpi_match, }, - .probe = pwm_lpss_probe, - .remove = pwm_lpss_remove, + .probe = pwm_lpss_probe_platform, + .remove = pwm_lpss_remove_platform, }; -module_platform_driver(pwm_lpss_driver); + +static int __init pwm_init(void) +{ + pci_drv = pci_register_driver(&pwm_lpss_driver_pci); + plat_drv = platform_driver_register(&pwm_lpss_driver_platform); + if (pci_drv && plat_drv) + return pci_drv; + + return 0; +} +module_init(pwm_init); + +static void __exit pwm_exit(void) +{ + if (!pci_drv) + pci_unregister_driver(&pwm_lpss_driver_pci); + if (!plat_drv) + platform_driver_unregister(&pwm_lpss_driver_platform); +} +module_exit(pwm_exit); MODULE_DESCRIPTION("PWM driver for Intel LPSS"); MODULE_AUTHOR("Mika Westerberg "); diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index cd356d87024411..0b312ec420b692 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -179,10 +179,8 @@ static int pwm_probe(struct platform_device *pdev) return -EINVAL; pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); - if (pwm == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (pwm == NULL) return -ENOMEM; - } pwm->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pwm->clk)) diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c index aff6ba9b49e7b4..cc13ff4cfab060 100644 --- a/drivers/pwm/pwm-renesas-tpu.c +++ b/drivers/pwm/pwm-renesas-tpu.c @@ -405,10 +405,8 @@ static int tpu_probe(struct platform_device *pdev) int ret; tpu = devm_kzalloc(&pdev->dev, sizeof(*tpu), GFP_KERNEL); - if (tpu == NULL) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); + if (tpu == NULL) return -ENOMEM; - } spin_lock_init(&tpu->lock); tpu->pdev = pdev; diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c index cb2d4f0f97114b..6fd93e6a4122b0 100644 --- a/drivers/pwm/pwm-spear.c +++ b/drivers/pwm/pwm-spear.c @@ -179,10 +179,8 @@ static int spear_pwm_probe(struct platform_device *pdev) u32 val; pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); - if (!pc) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (!pc) return -ENOMEM; - } r = platform_get_resource(pdev, IORESOURCE_MEM, 0); pc->mmio_base = devm_ioremap_resource(&pdev->dev, r); @@ -222,7 +220,7 @@ static int spear_pwm_probe(struct platform_device *pdev) } ret = pwmchip_add(&pc->chip); - if (!ret) { + if (ret < 0) { clk_unprepare(pc->clk); dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); } diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index 74298c561c4e57..61d86b9498caa8 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -173,10 +173,8 @@ static int tegra_pwm_probe(struct platform_device *pdev) int ret; pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); - if (!pwm) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (!pwm) return -ENOMEM; - } pwm->dev = &pdev->dev; diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index 032092c7a6ae3d..74efbe7f20c3ab 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -209,10 +209,8 @@ static int ecap_pwm_probe(struct platform_device *pdev) u16 status; pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); - if (!pc) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (!pc) return -ENOMEM; - } clk = devm_clk_get(&pdev->dev, "fck"); if (IS_ERR(clk)) { diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index aee4471424d14a..3a31c08cc6c854 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -440,10 +440,8 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev) u16 status; pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); - if (!pc) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (!pc) return -ENOMEM; - } clk = devm_clk_get(&pdev->dev, "fck"); if (IS_ERR(clk)) { diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c index b99a50e626a64f..04f76725d59158 100644 --- a/drivers/pwm/pwm-twl.c +++ b/drivers/pwm/pwm-twl.c @@ -263,14 +263,6 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR); val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN); - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG); - if (ret < 0) { - dev_err(chip->dev, "%s: Failed to read TOGGLE3\n", pwm->label); - goto out; - } - - val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN); - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG); if (ret < 0) { dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index 323125abf3f4dd..652e6b5b859b92 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -211,10 +211,8 @@ static int vt8500_pwm_probe(struct platform_device *pdev) } chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (chip == NULL) return -ENOMEM; - } chip->chip.dev = &pdev->dev; chip->chip.ops = &vt8500_pwm_ops; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 903eb37f047a91..b4f57a4dbc591d 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -139,6 +139,13 @@ config REGULATOR_AS3722 AS3722 PMIC. This will enable support for all the software controllable DCDC/LDO regulators. +config REGULATOR_AXP20X + tristate "X-POWERS AXP20X PMIC Regulators" + depends on MFD_AXP20X + help + This driver provides support for the voltage regulators on the + AXP20X PMIC. + config REGULATOR_BCM590XX tristate "Broadcom BCM590xx PMU Regulators" depends on MFD_BCM590XX @@ -266,11 +273,12 @@ config REGULATOR_LP8788 This driver supports LP8788 voltage regulator chip. config REGULATOR_MAX14577 - tristate "Maxim 14577 regulator" + tristate "Maxim 14577/77836 regulator" depends on MFD_MAX14577 help - This driver controls a Maxim 14577 regulator via I2C bus. - The regulators include safeout LDO and current regulator 'CHARGER'. + This driver controls a Maxim MAX14577/77836 regulator via I2C bus. + The MAX14577 regulators include safeout LDO and charger current + regulator. The MAX77836 has two additional LDOs. config REGULATOR_MAX1586 tristate "Maxim 1586/1587 voltage regulator" diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 12ef277a48b47c..c14696b290c0cc 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o +obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 7c397bb81e01eb..4f730af70e7c8b 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -300,7 +300,7 @@ static int anatop_regulator_probe(struct platform_device *pdev) return 0; } -static struct of_device_id of_anatop_regulator_match_tbl[] = { +static const struct of_device_id of_anatop_regulator_match_tbl[] = { { .compatible = "fsl,anatop-regulator", }, { /* end */ } }; diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index b1033d30b504c7..d3787e11f53515 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -178,6 +179,42 @@ static const struct regulator_init_data arizona_ldo1_default = { .num_consumer_supplies = 1, }; +static int arizona_ldo1_of_get_pdata(struct arizona *arizona, + struct regulator_config *config) +{ + struct arizona_pdata *pdata = &arizona->pdata; + struct arizona_ldo1 *ldo1 = config->driver_data; + struct device_node *init_node, *dcvdd_node; + struct regulator_init_data *init_data; + + pdata->ldoena = arizona_of_get_named_gpio(arizona, "wlf,ldoena", true); + + init_node = of_get_child_by_name(arizona->dev->of_node, "ldo1"); + dcvdd_node = of_parse_phandle(arizona->dev->of_node, "DCVDD-supply", 0); + + if (init_node) { + config->of_node = init_node; + + init_data = of_get_regulator_init_data(arizona->dev, init_node); + + if (init_data) { + init_data->consumer_supplies = &ldo1->supply; + init_data->num_consumer_supplies = 1; + + if (dcvdd_node && dcvdd_node != init_node) + arizona->external_dcvdd = true; + + pdata->ldo1 = init_data; + } + } else if (dcvdd_node) { + arizona->external_dcvdd = true; + } + + of_node_put(dcvdd_node); + + return 0; +} + static int arizona_ldo1_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); @@ -186,6 +223,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev) struct arizona_ldo1 *ldo1; int ret; + arizona->external_dcvdd = false; + ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL); if (!ldo1) return -ENOMEM; @@ -216,6 +255,15 @@ static int arizona_ldo1_probe(struct platform_device *pdev) config.dev = arizona->dev; config.driver_data = ldo1; config.regmap = arizona->regmap; + + if (IS_ENABLED(CONFIG_OF)) { + if (!dev_get_platdata(arizona->dev)) { + ret = arizona_ldo1_of_get_pdata(arizona, &config); + if (ret < 0) + return ret; + } + } + config.ena_gpio = arizona->pdata.ldoena; if (arizona->pdata.ldo1) @@ -223,6 +271,13 @@ static int arizona_ldo1_probe(struct platform_device *pdev) else config.init_data = &ldo1->init_data; + /* + * LDO1 can only be used to supply DCVDD so if it has no + * consumers then DCVDD is supplied externally. + */ + if (config.init_data->num_consumer_supplies == 0) + arizona->external_dcvdd = true; + ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config); if (IS_ERR(ldo1->regulator)) { ret = PTR_ERR(ldo1->regulator); @@ -231,6 +286,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev) return ret; } + of_node_put(config.of_node); + platform_set_drvdata(pdev, ldo1); return 0; diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index 6fdd9bf6927fcb..ce9aca5f8ee73b 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -16,9 +16,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -195,6 +197,32 @@ static const struct regulator_init_data arizona_micsupp_ext_default = { .num_consumer_supplies = 1, }; +static int arizona_micsupp_of_get_pdata(struct arizona *arizona, + struct regulator_config *config) +{ + struct arizona_pdata *pdata = &arizona->pdata; + struct arizona_micsupp *micsupp = config->driver_data; + struct device_node *np; + struct regulator_init_data *init_data; + + np = of_get_child_by_name(arizona->dev->of_node, "micvdd"); + + if (np) { + config->of_node = np; + + init_data = of_get_regulator_init_data(arizona->dev, np); + + if (init_data) { + init_data->consumer_supplies = &micsupp->supply; + init_data->num_consumer_supplies = 1; + + pdata->micvdd = init_data; + } + } + + return 0; +} + static int arizona_micsupp_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); @@ -234,6 +262,14 @@ static int arizona_micsupp_probe(struct platform_device *pdev) config.driver_data = micsupp; config.regmap = arizona->regmap; + if (IS_ENABLED(CONFIG_OF)) { + if (!dev_get_platdata(arizona->dev)) { + ret = arizona_micsupp_of_get_pdata(arizona, &config); + if (ret < 0) + return ret; + } + } + if (arizona->pdata.micvdd) config.init_data = arizona->pdata.micvdd; else @@ -253,6 +289,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev) return ret; } + of_node_put(config.of_node); + platform_set_drvdata(pdev, micsupp); return 0; diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c new file mode 100644 index 00000000000000..78a29e60f53a31 --- /dev/null +++ b/drivers/regulator/axp20x-regulator.c @@ -0,0 +1,285 @@ +/* + * AXP20x regulators driver. + * + * Copyright (C) 2013 Carlo Caione + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AXP20X_IO_ENABLED 0x03 +#define AXP20X_IO_DISABLED 0x07 + +#define AXP20X_WORKMODE_DCDC2_MASK BIT(2) +#define AXP20X_WORKMODE_DCDC3_MASK BIT(1) + +#define AXP20X_FREQ_DCDC_MASK 0x0f + +#define AXP20X_DESC_IO(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg, \ + _emask, _enable_val, _disable_val) \ + [AXP20X_##_id] = { \ + .name = #_id, \ + .supply_name = (_supply), \ + .type = REGULATOR_VOLTAGE, \ + .id = AXP20X_##_id, \ + .n_voltages = (((_max) - (_min)) / (_step) + 1), \ + .owner = THIS_MODULE, \ + .min_uV = (_min) * 1000, \ + .uV_step = (_step) * 1000, \ + .vsel_reg = (_vreg), \ + .vsel_mask = (_vmask), \ + .enable_reg = (_ereg), \ + .enable_mask = (_emask), \ + .enable_val = (_enable_val), \ + .disable_val = (_disable_val), \ + .ops = &axp20x_ops, \ + } + +#define AXP20X_DESC(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg, \ + _emask) \ + [AXP20X_##_id] = { \ + .name = #_id, \ + .supply_name = (_supply), \ + .type = REGULATOR_VOLTAGE, \ + .id = AXP20X_##_id, \ + .n_voltages = (((_max) - (_min)) / (_step) + 1), \ + .owner = THIS_MODULE, \ + .min_uV = (_min) * 1000, \ + .uV_step = (_step) * 1000, \ + .vsel_reg = (_vreg), \ + .vsel_mask = (_vmask), \ + .enable_reg = (_ereg), \ + .enable_mask = (_emask), \ + .ops = &axp20x_ops, \ + } + +#define AXP20X_DESC_FIXED(_id, _supply, _volt) \ + [AXP20X_##_id] = { \ + .name = #_id, \ + .supply_name = (_supply), \ + .type = REGULATOR_VOLTAGE, \ + .id = AXP20X_##_id, \ + .n_voltages = 1, \ + .owner = THIS_MODULE, \ + .min_uV = (_volt) * 1000, \ + .ops = &axp20x_ops_fixed \ + } + +#define AXP20X_DESC_TABLE(_id, _supply, _table, _vreg, _vmask, _ereg, _emask) \ + [AXP20X_##_id] = { \ + .name = #_id, \ + .supply_name = (_supply), \ + .type = REGULATOR_VOLTAGE, \ + .id = AXP20X_##_id, \ + .n_voltages = ARRAY_SIZE(_table), \ + .owner = THIS_MODULE, \ + .vsel_reg = (_vreg), \ + .vsel_mask = (_vmask), \ + .enable_reg = (_ereg), \ + .enable_mask = (_emask), \ + .volt_table = (_table), \ + .ops = &axp20x_ops_table, \ + } + +static const int axp20x_ldo4_data[] = { 1250000, 1300000, 1400000, 1500000, 1600000, + 1700000, 1800000, 1900000, 2000000, 2500000, + 2700000, 2800000, 3000000, 3100000, 3200000, + 3300000 }; + +static struct regulator_ops axp20x_ops_fixed = { + .list_voltage = regulator_list_voltage_linear, +}; + +static struct regulator_ops axp20x_ops_table = { + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_table, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static struct regulator_ops axp20x_ops = { + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_desc axp20x_regulators[] = { + AXP20X_DESC(DCDC2, "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT, 0x3f, + AXP20X_PWR_OUT_CTRL, 0x10), + AXP20X_DESC(DCDC3, "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT, 0x7f, + AXP20X_PWR_OUT_CTRL, 0x02), + AXP20X_DESC_FIXED(LDO1, "acin", 1300), + AXP20X_DESC(LDO2, "ldo24in", 1800, 3300, 100, AXP20X_LDO24_V_OUT, 0xf0, + AXP20X_PWR_OUT_CTRL, 0x04), + AXP20X_DESC(LDO3, "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT, 0x7f, + AXP20X_PWR_OUT_CTRL, 0x40), + AXP20X_DESC_TABLE(LDO4, "ldo24in", axp20x_ldo4_data, AXP20X_LDO24_V_OUT, 0x0f, + AXP20X_PWR_OUT_CTRL, 0x08), + AXP20X_DESC_IO(LDO5, "ldo5in", 1800, 3300, 100, AXP20X_LDO5_V_OUT, 0xf0, + AXP20X_GPIO0_CTRL, 0x07, AXP20X_IO_ENABLED, + AXP20X_IO_DISABLED), +}; + +#define AXP_MATCH(_name, _id) \ + [AXP20X_##_id] = { \ + .name = #_name, \ + .driver_data = (void *) &axp20x_regulators[AXP20X_##_id], \ + } + +static struct of_regulator_match axp20x_matches[] = { + AXP_MATCH(dcdc2, DCDC2), + AXP_MATCH(dcdc3, DCDC3), + AXP_MATCH(ldo1, LDO1), + AXP_MATCH(ldo2, LDO2), + AXP_MATCH(ldo3, LDO3), + AXP_MATCH(ldo4, LDO4), + AXP_MATCH(ldo5, LDO5), +}; + +static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) +{ + struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); + + if (dcdcfreq < 750) { + dcdcfreq = 750; + dev_warn(&pdev->dev, "DCDC frequency too low. Set to 750kHz\n"); + } + + if (dcdcfreq > 1875) { + dcdcfreq = 1875; + dev_warn(&pdev->dev, "DCDC frequency too high. Set to 1875kHz\n"); + } + + dcdcfreq = (dcdcfreq - 750) / 75; + + return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ, + AXP20X_FREQ_DCDC_MASK, dcdcfreq); +} + +static int axp20x_regulator_parse_dt(struct platform_device *pdev) +{ + struct device_node *np, *regulators; + int ret; + u32 dcdcfreq; + + np = of_node_get(pdev->dev.parent->of_node); + if (!np) + return 0; + + regulators = of_find_node_by_name(np, "regulators"); + if (!regulators) { + dev_warn(&pdev->dev, "regulators node not found\n"); + } else { + ret = of_regulator_match(&pdev->dev, regulators, axp20x_matches, + ARRAY_SIZE(axp20x_matches)); + if (ret < 0) { + dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); + return ret; + } + + dcdcfreq = 1500; + of_property_read_u32(regulators, "x-powers,dcdc-freq", &dcdcfreq); + ret = axp20x_set_dcdc_freq(pdev, dcdcfreq); + if (ret < 0) { + dev_err(&pdev->dev, "Error setting dcdc frequency: %d\n", ret); + return ret; + } + + of_node_put(regulators); + } + + return 0; +} + +static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode) +{ + unsigned int mask = AXP20X_WORKMODE_DCDC2_MASK; + + if ((id != AXP20X_DCDC2) && (id != AXP20X_DCDC3)) + return -EINVAL; + + if (id == AXP20X_DCDC3) + mask = AXP20X_WORKMODE_DCDC3_MASK; + + workmode <<= ffs(mask) - 1; + + return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode); +} + +static int axp20x_regulator_probe(struct platform_device *pdev) +{ + struct regulator_dev *rdev; + struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = { }; + struct regulator_init_data *init_data; + int ret, i; + u32 workmode; + + ret = axp20x_regulator_parse_dt(pdev); + if (ret) + return ret; + + for (i = 0; i < AXP20X_REG_ID_MAX; i++) { + init_data = axp20x_matches[i].init_data; + + config.dev = &pdev->dev; + config.init_data = init_data; + config.regmap = axp20x->regmap; + config.of_node = axp20x_matches[i].of_node; + + rdev = devm_regulator_register(&pdev->dev, &axp20x_regulators[i], + &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "Failed to register %s\n", + axp20x_regulators[i].name); + + return PTR_ERR(rdev); + } + + ret = of_property_read_u32(axp20x_matches[i].of_node, "x-powers,dcdc-workmode", + &workmode); + if (!ret) { + if (axp20x_set_dcdc_workmode(rdev, i, workmode)) + dev_err(&pdev->dev, "Failed to set workmode on %s\n", + axp20x_regulators[i].name); + } + } + + return 0; +} + +static struct platform_driver axp20x_regulator_driver = { + .probe = axp20x_regulator_probe, + .driver = { + .name = "axp20x-regulator", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(axp20x_regulator_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Carlo Caione "); +MODULE_DESCRIPTION("Regulator Driver for AXP20X PMIC"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 9a09f3cdbabb85..b97ffd2365d3a7 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3447,7 +3447,7 @@ regulator_register(const struct regulator_desc *regulator_desc, /* register with sysfs */ rdev->dev.class = ®ulator_class; - rdev->dev.of_node = config->of_node; + rdev->dev.of_node = of_node_get(config->of_node); rdev->dev.parent = dev; dev_set_name(&rdev->dev, "regulator.%d", atomic_inc_return(®ulator_no) - 1); @@ -3589,6 +3589,7 @@ void regulator_unregister(struct regulator_dev *rdev) list_del(&rdev->list); kfree(rdev->constraints); regulator_ena_gpio_free(rdev); + of_node_put(rdev->dev.of_node); device_unregister(&rdev->dev); mutex_unlock(®ulator_list_mutex); } diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c index ed60baaeceeca7..5d9c605cf534d9 100644 --- a/drivers/regulator/max14577.c +++ b/drivers/regulator/max14577.c @@ -1,5 +1,5 @@ /* - * max14577.c - Regulator driver for the Maxim 14577 + * max14577.c - Regulator driver for the Maxim 14577/77836 * * Copyright (C) 2013,2014 Samsung Electronics * Krzysztof Kozlowski @@ -22,6 +22,42 @@ #include #include +/* + * Valid limits of current for max14577 and max77836 chargers. + * They must correspond to MBCICHWRCL and MBCICHWRCH fields in CHGCTRL4 + * register for given chipset. + */ +struct maxim_charger_current { + /* Minimal current, set in CHGCTRL4/MBCICHWRCL, uA */ + unsigned int min; + /* + * Minimal current when high setting is active, + * set in CHGCTRL4/MBCICHWRCH, uA + */ + unsigned int high_start; + /* Value of one step in high setting, uA */ + unsigned int high_step; + /* Maximum current of high setting, uA */ + unsigned int max; +}; + +/* Table of valid charger currents for different Maxim chipsets */ +static const struct maxim_charger_current maxim_charger_currents[] = { + [MAXIM_DEVICE_TYPE_UNKNOWN] = { 0, 0, 0, 0 }, + [MAXIM_DEVICE_TYPE_MAX14577] = { + .min = MAX14577_REGULATOR_CURRENT_LIMIT_MIN, + .high_start = MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START, + .high_step = MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP, + .max = MAX14577_REGULATOR_CURRENT_LIMIT_MAX, + }, + [MAXIM_DEVICE_TYPE_MAX77836] = { + .min = MAX77836_REGULATOR_CURRENT_LIMIT_MIN, + .high_start = MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START, + .high_step = MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP, + .max = MAX77836_REGULATOR_CURRENT_LIMIT_MAX, + }, +}; + static int max14577_reg_is_enabled(struct regulator_dev *rdev) { int rid = rdev_get_id(rdev); @@ -47,6 +83,9 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev) { u8 reg_data; struct regmap *rmap = rdev->regmap; + struct max14577 *max14577 = rdev_get_drvdata(rdev); + const struct maxim_charger_current *limits = + &maxim_charger_currents[max14577->dev_type]; if (rdev_get_id(rdev) != MAX14577_CHARGER) return -EINVAL; @@ -54,12 +93,11 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev) max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, ®_data); if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0) - return MAX14577_REGULATOR_CURRENT_LIMIT_MIN; + return limits->min; reg_data = ((reg_data & CHGCTRL4_MBCICHWRCH_MASK) >> CHGCTRL4_MBCICHWRCH_SHIFT); - return MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START + - reg_data * MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP; + return limits->high_start + reg_data * limits->high_step; } static int max14577_reg_set_current_limit(struct regulator_dev *rdev, @@ -67,33 +105,39 @@ static int max14577_reg_set_current_limit(struct regulator_dev *rdev, { int i, current_bits = 0xf; u8 reg_data; + struct max14577 *max14577 = rdev_get_drvdata(rdev); + const struct maxim_charger_current *limits = + &maxim_charger_currents[max14577->dev_type]; if (rdev_get_id(rdev) != MAX14577_CHARGER) return -EINVAL; - if (min_uA > MAX14577_REGULATOR_CURRENT_LIMIT_MAX || - max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_MIN) + if (min_uA > limits->max || max_uA < limits->min) return -EINVAL; - if (max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START) { - /* Less than 200 mA, so set 90mA (turn only Low Bit off) */ + if (max_uA < limits->high_start) { + /* + * Less than high_start, + * so set the minimal current (turn only Low Bit off) + */ u8 reg_data = 0x0 << CHGCTRL4_MBCICHWRCL_SHIFT; return max14577_update_reg(rdev->regmap, MAX14577_CHG_REG_CHG_CTRL4, CHGCTRL4_MBCICHWRCL_MASK, reg_data); } - /* max_uA is in range: , so search for - * valid current starting from LIMIT_MAX. */ - for (i = MAX14577_REGULATOR_CURRENT_LIMIT_MAX; - i >= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START; - i -= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP) { + /* + * max_uA is in range: , so search for + * valid current starting from maximum current. + */ + for (i = limits->max; i >= limits->high_start; i -= limits->high_step) { if (i <= max_uA) break; current_bits--; } BUG_ON(current_bits < 0); /* Cannot happen */ - /* Turn Low Bit on (use range 200mA-950 mA) */ + + /* Turn Low Bit on (use range high_start-max)... */ reg_data = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT; /* and set proper High Bits */ reg_data |= current_bits << CHGCTRL4_MBCICHWRCH_SHIFT; @@ -118,7 +162,7 @@ static struct regulator_ops max14577_charger_ops = { .set_current_limit = max14577_reg_set_current_limit, }; -static const struct regulator_desc supported_regulators[] = { +static const struct regulator_desc max14577_supported_regulators[] = { [MAX14577_SAFEOUT] = { .name = "SAFEOUT", .id = MAX14577_SAFEOUT, @@ -141,16 +185,88 @@ static const struct regulator_desc supported_regulators[] = { }, }; +static struct regulator_ops max77836_ldo_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + /* TODO: add .set_suspend_mode */ +}; + +static const struct regulator_desc max77836_supported_regulators[] = { + [MAX14577_SAFEOUT] = { + .name = "SAFEOUT", + .id = MAX14577_SAFEOUT, + .ops = &max14577_safeout_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .n_voltages = 1, + .min_uV = MAX14577_REGULATOR_SAFEOUT_VOLTAGE, + .enable_reg = MAX14577_REG_CONTROL2, + .enable_mask = CTRL2_SFOUTORD_MASK, + }, + [MAX14577_CHARGER] = { + .name = "CHARGER", + .id = MAX14577_CHARGER, + .ops = &max14577_charger_ops, + .type = REGULATOR_CURRENT, + .owner = THIS_MODULE, + .enable_reg = MAX14577_CHG_REG_CHG_CTRL2, + .enable_mask = CHGCTRL2_MBCHOSTEN_MASK, + }, + [MAX77836_LDO1] = { + .name = "LDO1", + .id = MAX77836_LDO1, + .ops = &max77836_ldo_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .n_voltages = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM, + .min_uV = MAX77836_REGULATOR_LDO_VOLTAGE_MIN, + .uV_step = MAX77836_REGULATOR_LDO_VOLTAGE_STEP, + .enable_reg = MAX77836_LDO_REG_CNFG1_LDO1, + .enable_mask = MAX77836_CNFG1_LDO_PWRMD_MASK, + .vsel_reg = MAX77836_LDO_REG_CNFG1_LDO1, + .vsel_mask = MAX77836_CNFG1_LDO_TV_MASK, + }, + [MAX77836_LDO2] = { + .name = "LDO2", + .id = MAX77836_LDO2, + .ops = &max77836_ldo_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .n_voltages = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM, + .min_uV = MAX77836_REGULATOR_LDO_VOLTAGE_MIN, + .uV_step = MAX77836_REGULATOR_LDO_VOLTAGE_STEP, + .enable_reg = MAX77836_LDO_REG_CNFG1_LDO2, + .enable_mask = MAX77836_CNFG1_LDO_PWRMD_MASK, + .vsel_reg = MAX77836_LDO_REG_CNFG1_LDO2, + .vsel_mask = MAX77836_CNFG1_LDO_TV_MASK, + }, +}; + #ifdef CONFIG_OF static struct of_regulator_match max14577_regulator_matches[] = { { .name = "SAFEOUT", }, { .name = "CHARGER", }, }; -static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev) +static struct of_regulator_match max77836_regulator_matches[] = { + { .name = "SAFEOUT", }, + { .name = "CHARGER", }, + { .name = "LDO1", }, + { .name = "LDO2", }, +}; + +static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev, + enum maxim_device_type dev_type) { int ret; struct device_node *np; + struct of_regulator_match *regulator_matches; + unsigned int regulator_matches_size; np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); if (!np) { @@ -158,8 +274,19 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev) return -EINVAL; } - ret = of_regulator_match(&pdev->dev, np, max14577_regulator_matches, - MAX14577_REG_MAX); + switch (dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + regulator_matches = max77836_regulator_matches; + regulator_matches_size = ARRAY_SIZE(max77836_regulator_matches); + break; + case MAXIM_DEVICE_TYPE_MAX14577: + default: + regulator_matches = max14577_regulator_matches; + regulator_matches_size = ARRAY_SIZE(max14577_regulator_matches); + } + + ret = of_regulator_match(&pdev->dev, np, regulator_matches, + regulator_matches_size); if (ret < 0) dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); else @@ -170,31 +297,74 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev) return ret; } -static inline struct regulator_init_data *match_init_data(int index) +static inline struct regulator_init_data *match_init_data(int index, + enum maxim_device_type dev_type) { - return max14577_regulator_matches[index].init_data; + switch (dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + return max77836_regulator_matches[index].init_data; + + case MAXIM_DEVICE_TYPE_MAX14577: + default: + return max14577_regulator_matches[index].init_data; + } } -static inline struct device_node *match_of_node(int index) +static inline struct device_node *match_of_node(int index, + enum maxim_device_type dev_type) { - return max14577_regulator_matches[index].of_node; + switch (dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + return max77836_regulator_matches[index].of_node; + + case MAXIM_DEVICE_TYPE_MAX14577: + default: + return max14577_regulator_matches[index].of_node; + } } #else /* CONFIG_OF */ -static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev) +static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev, + enum maxim_device_type dev_type) { return 0; } -static inline struct regulator_init_data *match_init_data(int index) +static inline struct regulator_init_data *match_init_data(int index, + enum maxim_device_type dev_type) { return NULL; } -static inline struct device_node *match_of_node(int index) +static inline struct device_node *match_of_node(int index, + enum maxim_device_type dev_type) { return NULL; } #endif /* CONFIG_OF */ +/** + * Registers for regulators of max77836 use different I2C slave addresses so + * different regmaps must be used for them. + * + * Returns proper regmap for accessing regulator passed by id. + */ +static struct regmap *max14577_get_regmap(struct max14577 *max14577, + int reg_id) +{ + switch (max14577->dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + switch (reg_id) { + case MAX77836_SAFEOUT ... MAX77836_CHARGER: + return max14577->regmap; + default: + /* MAX77836_LDO1 ... MAX77836_LDO2 */ + return max14577->regmap_pmic; + } + + case MAXIM_DEVICE_TYPE_MAX14577: + default: + return max14577->regmap; + } +} static int max14577_regulator_probe(struct platform_device *pdev) { @@ -202,15 +372,29 @@ static int max14577_regulator_probe(struct platform_device *pdev) struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev); int i, ret; struct regulator_config config = {}; + const struct regulator_desc *supported_regulators; + unsigned int supported_regulators_size; + enum maxim_device_type dev_type = max14577->dev_type; - ret = max14577_regulator_dt_parse_pdata(pdev); + ret = max14577_regulator_dt_parse_pdata(pdev, dev_type); if (ret) return ret; + switch (dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + supported_regulators = max77836_supported_regulators; + supported_regulators_size = ARRAY_SIZE(max77836_supported_regulators); + break; + case MAXIM_DEVICE_TYPE_MAX14577: + default: + supported_regulators = max14577_supported_regulators; + supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators); + } + config.dev = &pdev->dev; - config.regmap = max14577->regmap; + config.driver_data = max14577; - for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) { + for (i = 0; i < supported_regulators_size; i++) { struct regulator_dev *regulator; /* * Index of supported_regulators[] is also the id and must @@ -220,17 +404,19 @@ static int max14577_regulator_probe(struct platform_device *pdev) config.init_data = pdata->regulators[i].initdata; config.of_node = pdata->regulators[i].of_node; } else { - config.init_data = match_init_data(i); - config.of_node = match_of_node(i); + config.init_data = match_init_data(i, dev_type); + config.of_node = match_of_node(i, dev_type); } + config.regmap = max14577_get_regmap(max14577, + supported_regulators[i].id); regulator = devm_regulator_register(&pdev->dev, &supported_regulators[i], &config); if (IS_ERR(regulator)) { ret = PTR_ERR(regulator); dev_err(&pdev->dev, - "Regulator init failed for ID %d with error: %d\n", - i, ret); + "Regulator init failed for %d/%s with error: %d\n", + i, supported_regulators[i].name, ret); return ret; } } @@ -238,20 +424,41 @@ static int max14577_regulator_probe(struct platform_device *pdev) return ret; } +static const struct platform_device_id max14577_regulator_id[] = { + { "max14577-regulator", MAXIM_DEVICE_TYPE_MAX14577, }, + { "max77836-regulator", MAXIM_DEVICE_TYPE_MAX77836, }, + { } +}; +MODULE_DEVICE_TABLE(platform, max14577_regulator_id); + static struct platform_driver max14577_regulator_driver = { .driver = { .owner = THIS_MODULE, .name = "max14577-regulator", }, - .probe = max14577_regulator_probe, + .probe = max14577_regulator_probe, + .id_table = max14577_regulator_id, }; static int __init max14577_regulator_init(void) { + /* Check for valid values for charger */ BUILD_BUG_ON(MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START + MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf != MAX14577_REGULATOR_CURRENT_LIMIT_MAX); - BUILD_BUG_ON(ARRAY_SIZE(supported_regulators) != MAX14577_REG_MAX); + BUILD_BUG_ON(MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START + + MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf != + MAX77836_REGULATOR_CURRENT_LIMIT_MAX); + /* Valid charger current values must be provided for each chipset */ + BUILD_BUG_ON(ARRAY_SIZE(maxim_charger_currents) != MAXIM_DEVICE_TYPE_NUM); + + BUILD_BUG_ON(ARRAY_SIZE(max14577_supported_regulators) != MAX14577_REGULATOR_NUM); + BUILD_BUG_ON(ARRAY_SIZE(max77836_supported_regulators) != MAX77836_REGULATOR_NUM); + + BUILD_BUG_ON(MAX77836_REGULATOR_LDO_VOLTAGE_MIN + + (MAX77836_REGULATOR_LDO_VOLTAGE_STEP * + (MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM - 1)) != + MAX77836_REGULATOR_LDO_VOLTAGE_MAX); return platform_driver_register(&max14577_regulator_driver); } @@ -264,6 +471,6 @@ static void __exit max14577_regulator_exit(void) module_exit(max14577_regulator_exit); MODULE_AUTHOR("Krzysztof Kozlowski "); -MODULE_DESCRIPTION("MAXIM 14577 regulator driver"); +MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:max14577-regulator"); diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index d920f5a32ec8e9..c2792f0271ab05 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -129,7 +129,7 @@ static const struct regulator_desc regulator = { }; #ifdef CONFIG_OF -static struct of_device_id max8952_dt_match[] = { +static const struct of_device_id max8952_dt_match[] = { { .compatible = "maxim,max8952" }, {}, }; diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index ea4f36f2cbe2f1..4672cd2f4632a1 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -106,6 +106,20 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, } EXPORT_SYMBOL_GPL(of_get_regulator_init_data); +struct devm_of_regulator_matches { + struct of_regulator_match *matches; + unsigned int num_matches; +}; + +static void devm_of_regulator_put_matches(struct device *dev, void *res) +{ + struct devm_of_regulator_matches *devm_matches = res; + int i; + + for (i = 0; i < devm_matches->num_matches; i++) + of_node_put(devm_matches->matches[i].of_node); +} + /** * of_regulator_match - extract multiple regulator init data from device tree. * @dev: device requesting the data @@ -119,7 +133,8 @@ EXPORT_SYMBOL_GPL(of_get_regulator_init_data); * regulator. The data parsed from a child node will be matched to a regulator * based on either the deprecated property regulator-compatible if present, * or otherwise the child node's name. Note that the match table is modified - * in place. + * in place and an additional of_node reference is taken for each matched + * regulator. * * Returns the number of matches found or a negative error code on failure. */ @@ -131,10 +146,22 @@ int of_regulator_match(struct device *dev, struct device_node *node, unsigned int i; const char *name; struct device_node *child; + struct devm_of_regulator_matches *devm_matches; if (!dev || !node) return -EINVAL; + devm_matches = devres_alloc(devm_of_regulator_put_matches, + sizeof(struct devm_of_regulator_matches), + GFP_KERNEL); + if (!devm_matches) + return -ENOMEM; + + devm_matches->matches = matches; + devm_matches->num_matches = num_matches; + + devres_add(dev, devm_matches); + for (i = 0; i < num_matches; i++) { struct of_regulator_match *match = &matches[i]; match->init_data = NULL; @@ -162,7 +189,7 @@ int of_regulator_match(struct device *dev, struct device_node *node, child->name); return -EINVAL; } - match->of_node = child; + match->of_node = of_node_get(child); count++; break; } diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 9c62b1d3468581..671cb9f32dabc8 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -1199,7 +1199,7 @@ static int palmas_regulators_probe(struct platform_device *pdev) return 0; } -static struct of_device_id of_palmas_match_tbl[] = { +static const struct of_device_id of_palmas_match_tbl[] = { { .compatible = "ti,palmas-pmic", }, { .compatible = "ti,twl6035-pmic", }, { .compatible = "ti,twl6036-pmic", }, diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c index 6d38be3d970ca7..708ddbb83e29f0 100644 --- a/drivers/regulator/pbias-regulator.c +++ b/drivers/regulator/pbias-regulator.c @@ -49,33 +49,13 @@ static const unsigned int pbias_volt_table[] = { 3000000 }; -static int pbias_regulator_enable(struct regulator_dev *rdev) -{ - struct pbias_regulator_data *data = rdev_get_drvdata(rdev); - const struct pbias_reg_info *info = data->info; - - return regmap_update_bits(data->syscon, rdev->desc->enable_reg, - info->enable_mask, info->enable); -} - -static int pbias_regulator_is_enable(struct regulator_dev *rdev) -{ - struct pbias_regulator_data *data = rdev_get_drvdata(rdev); - const struct pbias_reg_info *info = data->info; - int value; - - regmap_read(data->syscon, rdev->desc->enable_reg, &value); - - return (value & info->enable_mask) == info->enable; -} - static struct regulator_ops pbias_regulator_voltage_ops = { .list_voltage = regulator_list_voltage_table, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, - .enable = pbias_regulator_enable, + .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .is_enabled = pbias_regulator_is_enable, + .is_enabled = regulator_is_enabled_regmap, }; static const struct pbias_reg_info pbias_mmc_omap2430 = { @@ -180,6 +160,7 @@ static int pbias_regulator_probe(struct platform_device *pdev) drvdata[data_idx].desc.vsel_mask = info->vmode; drvdata[data_idx].desc.enable_reg = res->start; drvdata[data_idx].desc.enable_mask = info->enable_mask; + drvdata[data_idx].desc.enable_val = info->enable; cfg.init_data = pbias_matches[idx].init_data; cfg.driver_data = &drvdata[data_idx]; diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index e713c162fbd41b..1583d4eaf911f6 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,8 @@ struct s2mps11_info { * was enabled. */ unsigned int s2mps14_suspend_state:30; + /* Array of size rdev_num with GPIO-s for external sleep control */ + int *ext_control_gpio; }; static int get_ramp_delay(int ramp_delay) @@ -409,6 +412,8 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev) if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev))) val = S2MPS14_ENABLE_SUSPEND; + else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)])) + val = S2MPS14_ENABLE_EXT_CONTROL; else val = rdev->desc->enable_mask; @@ -565,12 +570,61 @@ static const struct regulator_desc s2mps14_regulators[] = { regulator_desc_s2mps14_buck1235(5), }; +static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11, + struct regulator_dev *rdev) +{ + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, S2MPS14_ENABLE_EXT_CONTROL); +} + +static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, + struct of_regulator_match *rdata, struct s2mps11_info *s2mps11) +{ + int *gpio = s2mps11->ext_control_gpio; + unsigned int i; + unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11, + S2MPS14_LDO12 }; + + for (i = 0; i < ARRAY_SIZE(valid_regulators); i++) { + unsigned int reg = valid_regulators[i]; + + if (!rdata[reg].init_data || !rdata[reg].of_node) + continue; + + gpio[reg] = of_get_named_gpio(rdata[reg].of_node, + "samsung,ext-control-gpios", 0); + if (gpio_is_valid(gpio[reg])) + dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n", + gpio[reg], reg, rdata[reg].name); + } +} + +static int s2mps11_pmic_dt_parse(struct platform_device *pdev, + struct of_regulator_match *rdata, struct s2mps11_info *s2mps11, + enum sec_device_type dev_type) +{ + struct device_node *reg_np; + + reg_np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); + if (!reg_np) { + dev_err(&pdev->dev, "could not find regulators sub-node\n"); + return -EINVAL; + } + + of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num); + if (dev_type == S2MPS14X) + s2mps14_pmic_dt_parse_ext_control_gpio(pdev, rdata, s2mps11); + + of_node_put(reg_np); + + return 0; +} + static int s2mps11_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct sec_platform_data *pdata = iodev->pdata; + struct sec_platform_data *pdata = NULL; struct of_regulator_match *rdata = NULL; - struct device_node *reg_np = NULL; struct regulator_config config = { }; struct s2mps11_info *s2mps11; int i, ret = 0; @@ -597,8 +651,21 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) return -EINVAL; }; + s2mps11->ext_control_gpio = devm_kzalloc(&pdev->dev, + sizeof(*s2mps11->ext_control_gpio) * s2mps11->rdev_num, + GFP_KERNEL); + if (!s2mps11->ext_control_gpio) + return -ENOMEM; + /* + * 0 is a valid GPIO so initialize all GPIO-s to negative value + * to indicate that external control won't be used for this regulator. + */ + for (i = 0; i < s2mps11->rdev_num; i++) + s2mps11->ext_control_gpio[i] = -EINVAL; + if (!iodev->dev->of_node) { - if (pdata) { + if (iodev->pdata) { + pdata = iodev->pdata; goto common_reg; } else { dev_err(pdev->dev.parent, @@ -614,15 +681,9 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) for (i = 0; i < s2mps11->rdev_num; i++) rdata[i].name = regulators[i].name; - reg_np = of_get_child_by_name(iodev->dev->of_node, "regulators"); - if (!reg_np) { - dev_err(&pdev->dev, "could not find regulators sub-node\n"); - ret = -EINVAL; + ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11, dev_type); + if (ret) goto out; - } - - of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num); - of_node_put(reg_np); common_reg: platform_set_drvdata(pdev, s2mps11); @@ -630,16 +691,18 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) config.dev = &pdev->dev; config.regmap = iodev->regmap_pmic; config.driver_data = s2mps11; + config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH; for (i = 0; i < s2mps11->rdev_num; i++) { struct regulator_dev *regulator; - if (!reg_np) { + if (pdata) { config.init_data = pdata->regulators[i].initdata; config.of_node = pdata->regulators[i].reg_node; } else { config.init_data = rdata[i].init_data; config.of_node = rdata[i].of_node; } + config.ena_gpio = s2mps11->ext_control_gpio[i]; regulator = devm_regulator_register(&pdev->dev, ®ulators[i], &config); @@ -649,6 +712,17 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) i); goto out; } + + if (gpio_is_valid(s2mps11->ext_control_gpio[i])) { + ret = s2mps14_pmic_enable_ext_control(s2mps11, + regulator); + if (ret < 0) { + dev_err(&pdev->dev, + "failed to enable GPIO control over %s: %d\n", + regulator->desc->name, ret); + goto out; + } + } } out: diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 92f19a005dc3f4..c79af943a5c03e 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -28,7 +28,6 @@ struct s5m8767_info { struct device *dev; struct sec_pmic_dev *iodev; int num_regulators; - struct regulator_dev **rdev; struct sec_opmode_data *opmode; int ramp_delay; @@ -529,16 +528,6 @@ static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev, return 0; } -static void s5m8767_pmic_dt_parse_ext_control_gpio(struct sec_pmic_dev *iodev, - struct sec_regulator_data *rdata, - struct device_node *reg_np) -{ - rdata->ext_control_gpio = of_get_named_gpio(reg_np, - "s5m8767,pmic-ext-control-gpios", 0); - if (!gpio_is_valid(rdata->ext_control_gpio)) - rdata->ext_control_gpio = 0; -} - static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, struct sec_platform_data *pdata) { @@ -587,7 +576,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, continue; } - s5m8767_pmic_dt_parse_ext_control_gpio(iodev, rdata, reg_np); + rdata->ext_control_gpio = of_get_named_gpio(reg_np, + "s5m8767,pmic-ext-control-gpios", 0); rdata->id = i; rdata->initdata = of_get_regulator_init_data( @@ -695,7 +685,6 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct sec_platform_data *pdata = iodev->pdata; struct regulator_config config = { }; - struct regulator_dev **rdev; struct s5m8767_info *s5m8767; int i, ret, size, buck_init; @@ -737,11 +726,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) return -ENOMEM; size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2); - s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (!s5m8767->rdev) - return -ENOMEM; - rdev = s5m8767->rdev; s5m8767->dev = &pdev->dev; s5m8767->iodev = iodev; s5m8767->num_regulators = pdata->num_regulators; @@ -938,6 +923,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) const struct sec_voltage_desc *desc; int id = pdata->regulators[i].id; int enable_reg, enable_val; + struct regulator_dev *rdev; desc = reg_voltage_map[id]; if (desc) { @@ -964,26 +950,27 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) config.driver_data = s5m8767; config.regmap = iodev->regmap_pmic; config.of_node = pdata->regulators[i].reg_node; - config.ena_gpio = config.ena_gpio_flags = 0; - if (pdata->regulators[i].ext_control_gpio) + config.ena_gpio = -EINVAL; + config.ena_gpio_flags = 0; + if (gpio_is_valid(pdata->regulators[i].ext_control_gpio)) s5m8767_regulator_config_ext_control(s5m8767, &pdata->regulators[i], &config); - rdev[i] = devm_regulator_register(&pdev->dev, ®ulators[id], + rdev = devm_regulator_register(&pdev->dev, ®ulators[id], &config); - if (IS_ERR(rdev[i])) { - ret = PTR_ERR(rdev[i]); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); dev_err(s5m8767->dev, "regulator init failed for %d\n", id); return ret; } - if (pdata->regulators[i].ext_control_gpio) { - ret = s5m8767_enable_ext_control(s5m8767, rdev[i]); + if (gpio_is_valid(pdata->regulators[i].ext_control_gpio)) { + ret = s5m8767_enable_ext_control(s5m8767, rdev); if (ret < 0) { dev_err(s5m8767->dev, "failed to enable gpio control over %s: %d\n", - rdev[i]->desc->name, ret); + rdev->desc->name, ret); return ret; } } diff --git a/drivers/regulator/st-pwm.c b/drivers/regulator/st-pwm.c index e367af1c5f9dca..5ea78df449f87e 100644 --- a/drivers/regulator/st-pwm.c +++ b/drivers/regulator/st-pwm.c @@ -118,7 +118,7 @@ static const struct st_pwm_regulator_pdata b2105_info = { .duty_cycle_table = b2105_duty_cycle_table, }; -static struct of_device_id st_pwm_of_match[] = { +static const struct of_device_id st_pwm_of_match[] = { { .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, }, { }, }; diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index 2e92ef68574da7..2064b3fd45f76c 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -28,49 +29,216 @@ #include #include +#define MAX_CTRL_READ_TRIES 5 +#define MAX_FET_ENABLE_TRIES 1000 + +#define CTRL_EN_BIT 0 /* Regulator enable bit, active high */ +#define CTRL_WT_BIT 2 /* Regulator wait time 0 bit */ +#define CTRL_PG_BIT 4 /* Regulator power good bit, 1=good */ +#define CTRL_TO_BIT 7 /* Regulator timeout bit, 1=wait */ + +#define MAX_OVERCURRENT_WAIT 3 /* Overcurrent wait must be <= this */ + +/** + * struct tps65090_regulator - Per-regulator data for a tps65090 regulator + * + * @dev: Pointer to our device. + * @desc: The struct regulator_desc for the regulator. + * @rdev: The struct regulator_dev for the regulator. + * @overcurrent_wait_valid: True if overcurrent_wait is valid. + * @overcurrent_wait: For FETs, the value to put in the WTFET bitfield. + */ + struct tps65090_regulator { struct device *dev; struct regulator_desc *desc; struct regulator_dev *rdev; + bool overcurrent_wait_valid; + int overcurrent_wait; }; static struct regulator_ops tps65090_ext_control_ops = { }; -static struct regulator_ops tps65090_reg_contol_ops = { +/** + * tps65090_reg_set_overcurrent_wait - Setup overcurrent wait + * + * This will set the overcurrent wait time based on what's in the regulator + * info. + * + * @ri: Overall regulator data + * @rdev: Regulator device + * + * Return: 0 if no error, non-zero if there was an error writing the register. + */ +static int tps65090_reg_set_overcurrent_wait(struct tps65090_regulator *ri, + struct regulator_dev *rdev) +{ + int ret; + + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + MAX_OVERCURRENT_WAIT << CTRL_WT_BIT, + ri->overcurrent_wait << CTRL_WT_BIT); + if (ret) { + dev_err(&rdev->dev, "Error updating overcurrent wait %#x\n", + rdev->desc->enable_reg); + } + + return ret; +} + +/** + * tps65090_try_enable_fet - Try to enable a FET + * + * @rdev: Regulator device + * + * Return: 0 if ok, -ENOTRECOVERABLE if the FET power good bit did not get + * set, or some other -ve value if another error occurred (e.g. i2c error) + */ +static int tps65090_try_enable_fet(struct regulator_dev *rdev) +{ + unsigned int control; + int ret, i; + + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + rdev->desc->enable_mask); + if (ret < 0) { + dev_err(&rdev->dev, "Error in updating reg %#x\n", + rdev->desc->enable_reg); + return ret; + } + + for (i = 0; i < MAX_CTRL_READ_TRIES; i++) { + ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, + &control); + if (ret < 0) + return ret; + + if (!(control & BIT(CTRL_TO_BIT))) + break; + + usleep_range(1000, 1500); + } + if (!(control & BIT(CTRL_PG_BIT))) + return -ENOTRECOVERABLE; + + return 0; +} + +/** + * tps65090_fet_enable - Enable a FET, trying a few times if it fails + * + * Some versions of the tps65090 have issues when turning on the FETs. + * This function goes through several steps to ensure the best chance of the + * FET going on. Specifically: + * - We'll make sure that we bump the "overcurrent wait" to the maximum, which + * increases the chances that we'll turn on properly. + * - We'll retry turning the FET on multiple times (turning off in between). + * + * @rdev: Regulator device + * + * Return: 0 if ok, non-zero if it fails. + */ +static int tps65090_fet_enable(struct regulator_dev *rdev) +{ + int ret, tries; + + /* + * Try enabling multiple times until we succeed since sometimes the + * first try times out. + */ + tries = 0; + while (true) { + ret = tps65090_try_enable_fet(rdev); + if (!ret) + break; + if (ret != -ENOTRECOVERABLE || tries == MAX_FET_ENABLE_TRIES) + goto err; + + /* Try turning the FET off (and then on again) */ + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, 0); + if (ret) + goto err; + + tries++; + } + + if (tries) + dev_warn(&rdev->dev, "reg %#x enable ok after %d tries\n", + rdev->desc->enable_reg, tries); + + return 0; +err: + dev_warn(&rdev->dev, "reg %#x enable failed\n", rdev->desc->enable_reg); + WARN_ON(1); + + return ret; +} + +static struct regulator_ops tps65090_reg_control_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, }; +static struct regulator_ops tps65090_fet_control_ops = { + .enable = tps65090_fet_enable, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + static struct regulator_ops tps65090_ldo_ops = { }; -#define tps65090_REG_DESC(_id, _sname, _en_reg, _ops) \ +#define tps65090_REG_DESC(_id, _sname, _en_reg, _en_bits, _ops) \ { \ .name = "TPS65090_RAILS"#_id, \ .supply_name = _sname, \ .id = TPS65090_REGULATOR_##_id, \ .ops = &_ops, \ .enable_reg = _en_reg, \ - .enable_mask = BIT(0), \ + .enable_val = _en_bits, \ + .enable_mask = _en_bits, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ } static struct regulator_desc tps65090_regulator_desc[] = { - tps65090_REG_DESC(DCDC1, "vsys1", 0x0C, tps65090_reg_contol_ops), - tps65090_REG_DESC(DCDC2, "vsys2", 0x0D, tps65090_reg_contol_ops), - tps65090_REG_DESC(DCDC3, "vsys3", 0x0E, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET1, "infet1", 0x0F, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET2, "infet2", 0x10, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET3, "infet3", 0x11, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET4, "infet4", 0x12, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET5, "infet5", 0x13, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET6, "infet6", 0x14, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET7, "infet7", 0x15, tps65090_reg_contol_ops), - tps65090_REG_DESC(LDO1, "vsys-l1", 0, tps65090_ldo_ops), - tps65090_REG_DESC(LDO2, "vsys-l2", 0, tps65090_ldo_ops), + tps65090_REG_DESC(DCDC1, "vsys1", 0x0C, BIT(CTRL_EN_BIT), + tps65090_reg_control_ops), + tps65090_REG_DESC(DCDC2, "vsys2", 0x0D, BIT(CTRL_EN_BIT), + tps65090_reg_control_ops), + tps65090_REG_DESC(DCDC3, "vsys3", 0x0E, BIT(CTRL_EN_BIT), + tps65090_reg_control_ops), + + tps65090_REG_DESC(FET1, "infet1", 0x0F, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + tps65090_REG_DESC(FET2, "infet2", 0x10, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + tps65090_REG_DESC(FET3, "infet3", 0x11, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + tps65090_REG_DESC(FET4, "infet4", 0x12, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + tps65090_REG_DESC(FET5, "infet5", 0x13, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + tps65090_REG_DESC(FET6, "infet6", 0x14, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + tps65090_REG_DESC(FET7, "infet7", 0x15, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + + tps65090_REG_DESC(LDO1, "vsys-l1", 0, 0, + tps65090_ldo_ops), + tps65090_REG_DESC(LDO2, "vsys-l2", 0, 0, + tps65090_ldo_ops), }; static inline bool is_dcdc(int id) @@ -209,6 +377,11 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data( rpdata->gpio = of_get_named_gpio(np, "dcdc-ext-control-gpios", 0); + if (of_property_read_u32(tps65090_matches[idx].of_node, + "ti,overcurrent-wait", + &rpdata->overcurrent_wait) == 0) + rpdata->overcurrent_wait_valid = true; + tps65090_pdata->reg_pdata[idx] = rpdata; } return tps65090_pdata; @@ -258,6 +431,11 @@ static int tps65090_regulator_probe(struct platform_device *pdev) ri = &pmic[num]; ri->dev = &pdev->dev; ri->desc = &tps65090_regulator_desc[num]; + if (tps_pdata) { + ri->overcurrent_wait_valid = + tps_pdata->overcurrent_wait_valid; + ri->overcurrent_wait = tps_pdata->overcurrent_wait; + } /* * TPS5090 DCDC support the control from external digital input. @@ -299,6 +477,12 @@ static int tps65090_regulator_probe(struct platform_device *pdev) } ri->rdev = rdev; + if (ri->overcurrent_wait_valid) { + ret = tps65090_reg_set_overcurrent_wait(ri, rdev); + if (ret < 0) + return ret; + } + /* Enable external control if it is require */ if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data && tps_pdata->enable_ext_control) { diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 10b78d2b766aa3..f7ed20a5a8b9a2 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -134,6 +134,7 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = tps65217_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, }; static const struct regulator_desc regulators[] = { @@ -257,9 +258,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev) pdev->name); return PTR_ERR(rdev); } - - /* Save regulator for cleanup */ - tps->rdev[i] = rdev; } return 0; } diff --git a/drivers/regulator/vexpress.c b/drivers/regulator/vexpress.c index f3ae28a7e66371..147ecc7c11bf2d 100644 --- a/drivers/regulator/vexpress.c +++ b/drivers/regulator/vexpress.c @@ -123,7 +123,7 @@ static int vexpress_regulator_remove(struct platform_device *pdev) return 0; } -static struct of_device_id vexpress_regulator_of_match[] = { +static const struct of_device_id vexpress_regulator_of_match[] = { { .compatible = "arm,vexpress-volt", }, { } }; diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 4f60caf750ceb9..60fed3d7820b75 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_RESET_CONTROLLER) += core.o +obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_STI) += sti/ diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c new file mode 100644 index 00000000000000..79c32ca84ef161 --- /dev/null +++ b/drivers/reset/reset-socfpga.c @@ -0,0 +1,146 @@ +/* + * Copyright 2014 Steffen Trumtrar + * + * based on + * Allwinner SoCs Reset Controller driver + * + * Copyright 2013 Maxime Ripard + * + * Maxime Ripard + * + * 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 + +#define NR_BANKS 4 +#define OFFSET_MODRST 0x10 + +struct socfpga_reset_data { + spinlock_t lock; + void __iomem *membase; + struct reset_controller_dev rcdev; +}; + +static int socfpga_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct socfpga_reset_data *data = container_of(rcdev, + struct socfpga_reset_data, + rcdev); + int bank = id / BITS_PER_LONG; + int offset = id % BITS_PER_LONG; + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&data->lock, flags); + + reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS)); + writel(reg | BIT(offset), data->membase + OFFSET_MODRST + + (bank * NR_BANKS)); + spin_unlock_irqrestore(&data->lock, flags); + + return 0; +} + +static int socfpga_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct socfpga_reset_data *data = container_of(rcdev, + struct socfpga_reset_data, + rcdev); + + int bank = id / BITS_PER_LONG; + int offset = id % BITS_PER_LONG; + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&data->lock, flags); + + reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS)); + writel(reg & ~BIT(offset), data->membase + OFFSET_MODRST + + (bank * NR_BANKS)); + + spin_unlock_irqrestore(&data->lock, flags); + + return 0; +} + +static struct reset_control_ops socfpga_reset_ops = { + .assert = socfpga_reset_assert, + .deassert = socfpga_reset_deassert, +}; + +static int socfpga_reset_probe(struct platform_device *pdev) +{ + struct socfpga_reset_data *data; + struct resource *res; + + /* + * The binding was mainlined without the required property. + * Do not continue, when we encounter an old DT. + */ + if (!of_find_property(pdev->dev.of_node, "#reset-cells", NULL)) { + dev_err(&pdev->dev, "%s missing #reset-cells property\n", + pdev->dev.of_node->full_name); + return -EINVAL; + } + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->membase)) + return PTR_ERR(data->membase); + + spin_lock_init(&data->lock); + + data->rcdev.owner = THIS_MODULE; + data->rcdev.nr_resets = NR_BANKS * BITS_PER_LONG; + data->rcdev.ops = &socfpga_reset_ops; + data->rcdev.of_node = pdev->dev.of_node; + reset_controller_register(&data->rcdev); + + return 0; +} + +static int socfpga_reset_remove(struct platform_device *pdev) +{ + struct socfpga_reset_data *data = platform_get_drvdata(pdev); + + reset_controller_unregister(&data->rcdev); + + return 0; +} + +static const struct of_device_id socfpga_reset_dt_ids[] = { + { .compatible = "altr,rst-mgr", }, + { /* sentinel */ }, +}; + +static struct platform_driver socfpga_reset_driver = { + .probe = socfpga_reset_probe, + .remove = socfpga_reset_remove, + .driver = { + .name = "socfpga-reset", + .owner = THIS_MODULE, + .of_match_table = socfpga_reset_dt_ids, + }, +}; +module_platform_driver(socfpga_reset_driver); + +MODULE_AUTHOR("Steffen Trumtrar dev.parent); struct sec_platform_data *pdata = s5m87xx->pdata; struct s5m_rtc_info *info; + const struct regmap_config *regmap_cfg; int ret; if (!pdata) { @@ -565,9 +581,37 @@ static int s5m_rtc_probe(struct platform_device *pdev) if (!info) return -ENOMEM; + switch (pdata->device_type) { + case S2MPS14X: + regmap_cfg = &s2mps14_rtc_regmap_config; + break; + case S5M8763X: + regmap_cfg = &s5m_rtc_regmap_config; + break; + case S5M8767X: + regmap_cfg = &s5m_rtc_regmap_config; + break; + default: + dev_err(&pdev->dev, "Device type is not supported by RTC driver\n"); + return -ENODEV; + } + + info->i2c = i2c_new_dummy(s5m87xx->i2c->adapter, RTC_I2C_ADDR); + if (!info->i2c) { + dev_err(&pdev->dev, "Failed to allocate I2C for RTC\n"); + return -ENODEV; + } + + info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg); + if (IS_ERR(info->regmap)) { + ret = PTR_ERR(info->regmap); + dev_err(&pdev->dev, "Failed to allocate RTC register map: %d\n", + ret); + goto err; + } + info->dev = &pdev->dev; info->s5m87xx = s5m87xx; - info->regmap = s5m87xx->regmap_rtc; info->device_type = s5m87xx->device_type; info->wtsr_smpl = s5m87xx->wtsr_smpl; @@ -585,7 +629,7 @@ static int s5m_rtc_probe(struct platform_device *pdev) default: ret = -EINVAL; dev_err(&pdev->dev, "Unsupported device type: %d\n", ret); - return ret; + goto err; } platform_set_drvdata(pdev, info); @@ -602,15 +646,24 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc", &s5m_rtc_ops, THIS_MODULE); - if (IS_ERR(info->rtc_dev)) - return PTR_ERR(info->rtc_dev); + if (IS_ERR(info->rtc_dev)) { + ret = PTR_ERR(info->rtc_dev); + goto err; + } ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, s5m_rtc_alarm_irq, 0, "rtc-alarm0", info); - if (ret < 0) + if (ret < 0) { dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", info->irq, ret); + goto err; + } + + return 0; + +err: + i2c_unregister_device(info->i2c); return ret; } @@ -639,6 +692,17 @@ static void s5m_rtc_shutdown(struct platform_device *pdev) s5m_rtc_enable_smpl(info, false); } +static int s5m_rtc_remove(struct platform_device *pdev) +{ + struct s5m_rtc_info *info = platform_get_drvdata(pdev); + + /* Perform also all shutdown steps when removing */ + s5m_rtc_shutdown(pdev); + i2c_unregister_device(info->i2c); + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int s5m_rtc_resume(struct device *dev) { @@ -676,6 +740,7 @@ static struct platform_driver s5m_rtc_driver = { .pm = &s5m_rtc_pm_ops, }, .probe = s5m_rtc_probe, + .remove = s5m_rtc_remove, .shutdown = s5m_rtc_shutdown, .id_table = s5m_rtc_id, }; diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index b69ab17f13fabe..629fcc275e923b 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -33,4 +33,4 @@ obj-$(CONFIG_MONWRITER) += monwriter.o obj-$(CONFIG_S390_VMUR) += vmur.o zcore_mod-objs := sclp_sdias.o zcore.o -obj-$(CONFIG_ZFCPDUMP) += zcore_mod.o +obj-$(CONFIG_CRASH_DUMP) += zcore_mod.o diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index 14196ea0fdf3ad..b57fe0efb4227d 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -22,7 +22,8 @@ struct read_info_sccb { u8 rnsize; /* 10 */ u8 _reserved0[16 - 11]; /* 11-15 */ u16 ncpurl; /* 16-17 */ - u8 _reserved7[24 - 18]; /* 18-23 */ + u16 cpuoff; /* 18-19 */ + u8 _reserved7[24 - 20]; /* 20-23 */ u8 loadparm[8]; /* 24-31 */ u8 _reserved1[48 - 32]; /* 32-47 */ u64 facilities; /* 48-55 */ @@ -45,6 +46,7 @@ static unsigned int sclp_con_has_linemode __initdata; static unsigned long sclp_hsa_size; static unsigned int sclp_max_cpu; static struct sclp_ipl_info sclp_ipl_info; +static unsigned char sclp_siif; u64 sclp_facilities; u8 sclp_fac84; @@ -96,6 +98,9 @@ static int __init sclp_read_info_early(struct read_info_sccb *sccb) static void __init sclp_facilities_detect(struct read_info_sccb *sccb) { + struct sclp_cpu_entry *cpue; + u16 boot_cpu_address, cpu; + if (sclp_read_info_early(sccb)) return; @@ -116,6 +121,15 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb) sclp_max_cpu = sccb->hcpua + 1; } + boot_cpu_address = stap(); + cpue = (void *)sccb + sccb->cpuoff; + for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) { + if (boot_cpu_address != cpue->address) + continue; + sclp_siif = cpue->siif; + break; + } + /* Save IPL information */ sclp_ipl_info.is_valid = 1; if (sccb->flags & 0x2) @@ -148,6 +162,12 @@ unsigned int sclp_get_max_cpu(void) return sclp_max_cpu; } +int sclp_has_siif(void) +{ + return sclp_siif; +} +EXPORT_SYMBOL(sclp_has_siif); + /* * This function will be called after sclp_facilities_detect(), which gets * called from early.c code. The sclp_facilities_detect() function retrieves diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 3d8e4d63f51418..1884653e447242 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -17,6 +17,8 @@ #include #include #include +#include + #include #include #include @@ -411,33 +413,24 @@ static ssize_t zcore_memmap_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { return simple_read_from_buffer(buf, count, ppos, filp->private_data, - MEMORY_CHUNKS * CHUNK_INFO_SIZE); + memblock.memory.cnt * CHUNK_INFO_SIZE); } static int zcore_memmap_open(struct inode *inode, struct file *filp) { - int i; + struct memblock_region *reg; char *buf; - struct mem_chunk *chunk_array; + int i = 0; - chunk_array = kzalloc(MEMORY_CHUNKS * sizeof(struct mem_chunk), - GFP_KERNEL); - if (!chunk_array) - return -ENOMEM; - detect_memory_layout(chunk_array, 0); - buf = kzalloc(MEMORY_CHUNKS * CHUNK_INFO_SIZE, GFP_KERNEL); + buf = kzalloc(memblock.memory.cnt * CHUNK_INFO_SIZE, GFP_KERNEL); if (!buf) { - kfree(chunk_array); return -ENOMEM; } - for (i = 0; i < MEMORY_CHUNKS; i++) { - sprintf(buf + (i * CHUNK_INFO_SIZE), "%016llx %016llx ", - (unsigned long long) chunk_array[i].addr, - (unsigned long long) chunk_array[i].size); - if (chunk_array[i].size == 0) - break; + for_each_memblock(memory, reg) { + sprintf(buf + (i++ * CHUNK_INFO_SIZE), "%016llx %016llx ", + (unsigned long long) reg->base, + (unsigned long long) reg->size); } - kfree(chunk_array); filp->private_data = buf; return nonseekable_open(inode, filp); } @@ -593,21 +586,12 @@ static int __init check_sdias(void) static int __init get_mem_info(unsigned long *mem, unsigned long *end) { - int i; - struct mem_chunk *chunk_array; + struct memblock_region *reg; - chunk_array = kzalloc(MEMORY_CHUNKS * sizeof(struct mem_chunk), - GFP_KERNEL); - if (!chunk_array) - return -ENOMEM; - detect_memory_layout(chunk_array, 0); - for (i = 0; i < MEMORY_CHUNKS; i++) { - if (chunk_array[i].size == 0) - break; - *mem += chunk_array[i].size; - *end = max(*end, chunk_array[i].addr + chunk_array[i].size); + for_each_memblock(memory, reg) { + *mem += reg->size; + *end = max_t(unsigned long, *end, reg->base + reg->size); } - kfree(chunk_array); return 0; } diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index ab3baa7f95082e..8eec1653c9cc44 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1803,7 +1803,7 @@ static int ap_poll_thread(void *data) int requests; struct ap_device *ap_dev; - set_user_nice(current, 19); + set_user_nice(current, MAX_NICE); while (1) { if (ap_suspend_flag) return 0; diff --git a/drivers/s390/kvm/virtio_ccw.c b/drivers/s390/kvm/virtio_ccw.c index 1e1fc671f89a4a..d2c0b442bce5fb 100644 --- a/drivers/s390/kvm/virtio_ccw.c +++ b/drivers/s390/kvm/virtio_ccw.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,7 @@ struct virtio_ccw_device { struct vq_config_block *config_block; bool is_thinint; bool going_away; + bool device_lost; void *airq_info; }; @@ -1010,11 +1012,14 @@ static void virtio_ccw_remove(struct ccw_device *cdev) unsigned long flags; struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev); - if (vcdev && cdev->online) + if (vcdev && cdev->online) { + if (vcdev->device_lost) + virtio_break_device(&vcdev->vdev); unregister_virtio_device(&vcdev->vdev); - spin_lock_irqsave(get_ccwdev_lock(cdev), flags); - dev_set_drvdata(&cdev->dev, NULL); - spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); + spin_lock_irqsave(get_ccwdev_lock(cdev), flags); + dev_set_drvdata(&cdev->dev, NULL); + spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); + } cdev->handler = NULL; } @@ -1023,12 +1028,14 @@ static int virtio_ccw_offline(struct ccw_device *cdev) unsigned long flags; struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev); - if (vcdev) { - unregister_virtio_device(&vcdev->vdev); - spin_lock_irqsave(get_ccwdev_lock(cdev), flags); - dev_set_drvdata(&cdev->dev, NULL); - spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); - } + if (!vcdev) + return 0; + if (vcdev->device_lost) + virtio_break_device(&vcdev->vdev); + unregister_virtio_device(&vcdev->vdev); + spin_lock_irqsave(get_ccwdev_lock(cdev), flags); + dev_set_drvdata(&cdev->dev, NULL); + spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); return 0; } @@ -1096,8 +1103,26 @@ static int virtio_ccw_online(struct ccw_device *cdev) static int virtio_ccw_cio_notify(struct ccw_device *cdev, int event) { - /* TODO: Check whether we need special handling here. */ - return 0; + int rc; + struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev); + + /* + * Make sure vcdev is set + * i.e. set_offline/remove callback not already running + */ + if (!vcdev) + return NOTIFY_DONE; + + switch (event) { + case CIO_GONE: + vcdev->device_lost = true; + rc = NOTIFY_DONE; + break; + default: + rc = NOTIFY_DONE; + break; + } + return rc; } static struct ccw_device_id virtio_ids[] = { diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index fd7b3bd8078965..d837c3c5330fab 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -3348,7 +3348,7 @@ static int __init claw_init(void) } CLAW_DBF_TEXT(2, setup, "init_mod"); claw_root_dev = root_device_register("claw"); - ret = PTR_RET(claw_root_dev); + ret = PTR_ERR_OR_ZERO(claw_root_dev); if (ret) goto register_err; ret = ccw_driver_register(&claw_ccw_driver); diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 70b3a023100ef7..03b6ad035577e2 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -1837,7 +1837,7 @@ static int __init ctcm_init(void) if (ret) goto out_err; ctcm_root_dev = root_device_register("ctcm"); - ret = PTR_RET(ctcm_root_dev); + ret = PTR_ERR_OR_ZERO(ctcm_root_dev); if (ret) goto register_err; ret = ccw_driver_register(&ctcm_ccw_driver); diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index c461f2aac610ea..8d5d96969c3921 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -2442,7 +2442,7 @@ __init lcs_init_module(void) if (rc) goto out_err; lcs_root_dev = root_device_register("lcs"); - rc = PTR_RET(lcs_root_dev); + rc = PTR_ERR_OR_ZERO(lcs_root_dev); if (rc) goto register_err; rc = ccw_driver_register(&lcs_ccw_driver); diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 5333b2c018e781..a2088af51cc5d8 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -268,10 +268,8 @@ static inline int qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, #define QETH_NO_PRIO_QUEUEING 0 #define QETH_PRIO_Q_ING_PREC 1 #define QETH_PRIO_Q_ING_TOS 2 -#define IP_TOS_LOWDELAY 0x10 -#define IP_TOS_HIGHTHROUGHPUT 0x08 -#define IP_TOS_HIGHRELIABILITY 0x04 -#define IP_TOS_NOTIMPORTANT 0x02 +#define QETH_PRIO_Q_ING_SKB 3 +#define QETH_PRIO_Q_ING_VLAN 4 /* Packing */ #define QETH_LOW_WATERMARK_PACK 2 diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 22470a3b182f0b..34993009a9e12d 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -3670,42 +3671,56 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev, } EXPORT_SYMBOL_GPL(qeth_qdio_output_handler); +/** + * Note: Function assumes that we have 4 outbound queues. + */ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, int ipv, int cast_type) { - if (!ipv && (card->info.type == QETH_CARD_TYPE_OSD || - card->info.type == QETH_CARD_TYPE_OSX)) - return card->qdio.default_out_queue; - switch (card->qdio.no_out_queues) { - case 4: - if (cast_type && card->info.is_multicast_different) - return card->info.is_multicast_different & - (card->qdio.no_out_queues - 1); - if (card->qdio.do_prio_queueing && (ipv == 4)) { - const u8 tos = ip_hdr(skb)->tos; - - if (card->qdio.do_prio_queueing == - QETH_PRIO_Q_ING_TOS) { - if (tos & IP_TOS_NOTIMPORTANT) - return 3; - if (tos & IP_TOS_HIGHRELIABILITY) - return 2; - if (tos & IP_TOS_HIGHTHROUGHPUT) - return 1; - if (tos & IP_TOS_LOWDELAY) - return 0; - } - if (card->qdio.do_prio_queueing == - QETH_PRIO_Q_ING_PREC) - return 3 - (tos >> 6); - } else if (card->qdio.do_prio_queueing && (ipv == 6)) { - /* TODO: IPv6!!! */ + __be16 *tci; + u8 tos; + + if (cast_type && card->info.is_multicast_different) + return card->info.is_multicast_different & + (card->qdio.no_out_queues - 1); + + switch (card->qdio.do_prio_queueing) { + case QETH_PRIO_Q_ING_TOS: + case QETH_PRIO_Q_ING_PREC: + switch (ipv) { + case 4: + tos = ipv4_get_dsfield(ip_hdr(skb)); + break; + case 6: + tos = ipv6_get_dsfield(ipv6_hdr(skb)); + break; + default: + return card->qdio.default_out_queue; } - return card->qdio.default_out_queue; - case 1: /* fallthrough for single-out-queue 1920-device */ + if (card->qdio.do_prio_queueing == QETH_PRIO_Q_ING_PREC) + return ~tos >> 6 & 3; + if (tos & IPTOS_MINCOST) + return 3; + if (tos & IPTOS_RELIABILITY) + return 2; + if (tos & IPTOS_THROUGHPUT) + return 1; + if (tos & IPTOS_LOWDELAY) + return 0; + break; + case QETH_PRIO_Q_ING_SKB: + if (skb->priority > 5) + return 0; + return ~skb->priority >> 1 & 3; + case QETH_PRIO_Q_ING_VLAN: + tci = &((struct ethhdr *)skb->data)->h_proto; + if (*tci == ETH_P_8021Q) + return ~*(tci + 1) >> (VLAN_PRIO_SHIFT + 1) & 3; + break; default: - return card->qdio.default_out_queue; + break; } + return card->qdio.default_out_queue; } EXPORT_SYMBOL_GPL(qeth_get_priority_queue); @@ -5824,7 +5839,7 @@ static int __init qeth_core_init(void) if (rc) goto out_err; qeth_core_root_dev = root_device_register("qeth"); - rc = PTR_RET(qeth_core_root_dev); + rc = PTR_ERR_OR_ZERO(qeth_core_root_dev); if (rc) goto register_err; qeth_core_header_cache = kmem_cache_create("qeth_hdr", diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 425c0ecf1f3b9f..8a25a2be9890e7 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -217,6 +217,10 @@ static ssize_t qeth_dev_prioqing_show(struct device *dev, return sprintf(buf, "%s\n", "by precedence"); case QETH_PRIO_Q_ING_TOS: return sprintf(buf, "%s\n", "by type of service"); + case QETH_PRIO_Q_ING_SKB: + return sprintf(buf, "%s\n", "by skb-priority"); + case QETH_PRIO_Q_ING_VLAN: + return sprintf(buf, "%s\n", "by VLAN headers"); default: return sprintf(buf, "always queue %i\n", card->qdio.default_out_queue); @@ -250,11 +254,23 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev, } tmp = strsep((char **) &buf, "\n"); - if (!strcmp(tmp, "prio_queueing_prec")) + if (!strcmp(tmp, "prio_queueing_prec")) { card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_PREC; - else if (!strcmp(tmp, "prio_queueing_tos")) + card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; + } else if (!strcmp(tmp, "prio_queueing_skb")) { + card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_SKB; + card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; + } else if (!strcmp(tmp, "prio_queueing_tos")) { card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_TOS; - else if (!strcmp(tmp, "no_prio_queueing:0")) { + card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; + } else if (!strcmp(tmp, "prio_queueing_vlan")) { + if (!card->options.layer2) { + rc = -ENOTSUPP; + goto out; + } + card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_VLAN; + card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; + } else if (!strcmp(tmp, "no_prio_queueing:0")) { card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; card->qdio.default_out_queue = 0; } else if (!strcmp(tmp, "no_prio_queueing:1")) { diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 8dea3f12ccc171..e232ceca38fe25 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -725,15 +725,20 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) int elements = 0; struct qeth_card *card = dev->ml_priv; struct sk_buff *new_skb = skb; - int ipv = qeth_get_ip_version(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)]; + struct qeth_qdio_out_q *queue; int tx_bytes = skb->len; int data_offset = -1; int elements_needed = 0; int hd_len = 0; + if (card->qdio.do_prio_queueing || (cast_type && + card->info.is_multicast_different)) + queue = card->qdio.out_qs[qeth_get_priority_queue(card, skb, + qeth_get_ip_version(skb), cast_type)]; + else + queue = card->qdio.out_qs[card->qdio.default_out_queue]; + if ((card->state != CARD_STATE_UP) || !card->lan_online) { card->stats.tx_carrier_errors++; goto tx_drop; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 3524d34ff694c2..c8d91d797ec8a9 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2926,8 +2926,11 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct sk_buff *new_skb = NULL; int ipv = qeth_get_ip_version(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)]; + struct qeth_qdio_out_q *queue = + card->qdio.out_qs[card->qdio.do_prio_queueing + || (cast_type && card->info.is_multicast_different) ? + qeth_get_priority_queue(card, skb, ipv, cast_type) : + card->qdio.default_out_queue]; int tx_bytes = skb->len; bool large_send; int data_offset = -1; diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index 4ccb5d869389e3..a40ee1e37486bd 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -207,7 +207,7 @@ static void jsfd_do_request(struct request_queue *q) goto end; } - jsfd_read(req->buffer, jdp->dbase + offset, len); + jsfd_read(bio_data(req->bio), jdp->dbase + offset, len); err = 0; end: if (!__blk_end_request_cur(req, err)) diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index 9b059422aacbf4..113874c1284b16 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -911,7 +911,7 @@ struct vpd_config { uint8_t length; uint8_t revision; uint8_t device_flags; - uint8_t termnation_menus[2]; + uint8_t termination_menus[2]; uint8_t fifo_threshold; uint8_t end_tag; uint8_t vpd_checksum; diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 1d41f4b9114f82..f5484302346636 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -464,7 +464,7 @@ static int bnx2fc_l2_rcv_thread(void *arg) struct fcoe_percpu_s *bg = arg; struct sk_buff *skb; - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { schedule(); @@ -602,7 +602,7 @@ int bnx2fc_percpu_io_thread(void *arg) struct bnx2fc_work *work, *tmp; LIST_HEAD(work_list); - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { schedule(); diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index b5ffd280a1aefe..d6d491c2f00463 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -1870,7 +1870,7 @@ int bnx2i_percpu_io_thread(void *arg) struct bnx2i_work *work, *tmp; LIST_HEAD(work_list); - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); while (!kthread_should_stop()) { spin_lock_bh(&p->p_work_lock); diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index d5e105b173f0cf..00ee0ed642aac7 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1872,7 +1872,7 @@ static int fcoe_percpu_receive_thread(void *arg) skb_queue_head_init(&tmp); - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); retry: while (!kthread_should_stop()) { diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 23f5ba5e647258..8dd47689d58430 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -4515,7 +4515,7 @@ static int ibmvfc_work(void *data) struct ibmvfc_host *vhost = data; int rc; - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); while (1) { rc = wait_event_interruptible(vhost->work_wait_q, diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index fa764406df6872..2ebfb2bb0f425f 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -2213,7 +2213,7 @@ static int ibmvscsi_work(void *data) struct ibmvscsi_host_data *hostdata = data; int rc; - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); while (1) { rc = wait_event_interruptible(hostdata->work_wait_q, diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index 96a26f454673cf..cc51f38b116d58 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c @@ -1541,7 +1541,7 @@ void isci_remote_device_release(struct kref *kref) clear_bit(IDEV_STOP_PENDING, &idev->flags); clear_bit(IDEV_IO_READY, &idev->flags); clear_bit(IDEV_GONE, &idev->flags); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(IDEV_ALLOCATED, &idev->flags); wake_up(&ihost->eventq); } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 59b51c529ba0f9..294c072e90835e 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -731,7 +731,7 @@ lpfc_do_work(void *p) struct lpfc_hba *phba = p; int rc; - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); current->flags |= PF_NOFREEZE; phba->data_flags = 0; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 19e99cc33724c5..afc84814e9bb3b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -4828,7 +4828,7 @@ qla2x00_do_dpc(void *data) ha = (struct qla_hw_data *)data; base_vha = pci_get_drvdata(ha->pdev); - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 9db097a28a7458..a0c95cac91f0fe 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -140,7 +140,7 @@ static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy) cmd->result = 0; spin_lock_irqsave(q->queue_lock, flags); blk_requeue_request(q, cmd->request); - kblockd_schedule_work(q, &device->requeue_work); + kblockd_schedule_work(&device->requeue_work); spin_unlock_irqrestore(q->queue_lock, flags); } @@ -1019,8 +1019,6 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb, return BLKPREP_DEFER; } - req->buffer = NULL; - /* * Next, walk the list, and fill in the addresses and sizes of * each segment. @@ -1158,7 +1156,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) BUG_ON(blk_rq_bytes(req)); memset(&cmd->sdb, 0, sizeof(cmd->sdb)); - req->buffer = NULL; } cmd->cmd_len = req->cmd_len; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index efcbcd18286331..96af195224f2b9 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -737,16 +737,14 @@ static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) goto out; } + rq->completion_data = page; blk_add_request_payload(rq, page, len); ret = scsi_setup_blk_pc_cmnd(sdp, rq); - rq->buffer = page_address(page); rq->__data_len = nr_bytes; out: - if (ret != BLKPREP_OK) { + if (ret != BLKPREP_OK) __free_page(page); - rq->buffer = NULL; - } return ret; } @@ -842,10 +840,9 @@ static void sd_unprep_fn(struct request_queue *q, struct request *rq) { struct scsi_cmnd *SCpnt = rq->special; - if (rq->cmd_flags & REQ_DISCARD) { - free_page((unsigned long)rq->buffer); - rq->buffer = NULL; - } + if (rq->cmd_flags & REQ_DISCARD) + __free_page(rq->completion_data); + if (SCpnt->cmnd != rq->cmd) { mempool_free(SCpnt->cmnd, sd_cdb_pool); SCpnt->cmnd = NULL; diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index 74727851820df4..be56b22ca941a0 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -196,17 +196,11 @@ int clk_rate_table_find(struct clk *clk, struct cpufreq_frequency_table *freq_table, unsigned long rate) { - int i; - - for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { - unsigned long freq = freq_table[i].frequency; + struct cpufreq_frequency_table *pos; - if (freq == CPUFREQ_ENTRY_INVALID) - continue; - - if (freq == rate) - return i; - } + cpufreq_for_each_valid_entry(pos, freq_table) + if (pos->frequency == rate) + return pos - freq_table; return -ENOENT; } @@ -575,11 +569,7 @@ long clk_round_parent(struct clk *clk, unsigned long target, return abs(target - *best_freq); } - for (freq = parent->freq_table; freq->frequency != CPUFREQ_TABLE_END; - freq++) { - if (freq->frequency == CPUFREQ_ENTRY_INVALID) - continue; - + cpufreq_for_each_valid_entry(freq, parent->freq_table) { if (unlikely(freq->frequency / target <= div_min - 1)) { unsigned long freq_max; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 60f2b41c731052..016557d5284da0 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -91,8 +91,8 @@ config SPI_BFIN5XX help This is the SPI controller master driver for Blackfin 5xx processor. -config SPI_BFIN_V3 - tristate "SPI controller v3 for Blackfin" +config SPI_ADI_V3 + tristate "SPI controller v3 for ADI" depends on BF60x help This is the SPI controller v3 master driver @@ -148,6 +148,13 @@ config SPI_BUTTERFLY inexpensive battery powered microcontroller evaluation board. This same cable can be used to flash new firmware. +config SPI_CADENCE + tristate "Cadence SPI controller" + depends on ARM + help + This selects the Cadence SPI controller master driver + used by Xilinx Zynq. + config SPI_CLPS711X tristate "CLPS711X host SPI controller" depends on ARCH_CLPS711X || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index bd792669e56395..929c9f5eac01d0 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -18,10 +18,11 @@ obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o -obj-$(CONFIG_SPI_BFIN_V3) += spi-bfin-v3.o +obj-$(CONFIG_SPI_ADI_V3) += spi-adi-v3.o obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o +obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-adi-v3.c similarity index 60% rename from drivers/spi/spi-bfin-v3.c rename to drivers/spi/spi-adi-v3.c index 4089d0e0d84ee6..dcb2287c7f8a5a 100644 --- a/drivers/spi/spi-bfin-v3.c +++ b/drivers/spi/spi-adi-v3.c @@ -1,7 +1,7 @@ /* * Analog Devices SPI3 controller driver * - * Copyright (c) 2013 Analog Devices Inc. + * Copyright (c) 2014 Analog Devices 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 @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -26,35 +27,34 @@ #include #include #include +#include #include -#include -#include #include #include -enum bfin_spi_state { +enum adi_spi_state { START_STATE, RUNNING_STATE, DONE_STATE, ERROR_STATE }; -struct bfin_spi_master; +struct adi_spi_master; -struct bfin_spi_transfer_ops { - void (*write) (struct bfin_spi_master *); - void (*read) (struct bfin_spi_master *); - void (*duplex) (struct bfin_spi_master *); +struct adi_spi_transfer_ops { + void (*write) (struct adi_spi_master *); + void (*read) (struct adi_spi_master *); + void (*duplex) (struct adi_spi_master *); }; /* runtime info for spi master */ -struct bfin_spi_master { +struct adi_spi_master { /* SPI framework hookup */ struct spi_master *master; /* Regs base of SPI controller */ - struct bfin_spi_regs __iomem *regs; + struct adi_spi_regs __iomem *regs; /* Pin request list */ u16 *pin_req; @@ -65,7 +65,7 @@ struct bfin_spi_master { /* Current message transfer state info */ struct spi_message *cur_msg; struct spi_transfer *cur_transfer; - struct bfin_spi_device *cur_chip; + struct adi_spi_device *cur_chip; unsigned transfer_len; /* transfer buffer */ @@ -90,12 +90,12 @@ struct bfin_spi_master { u32 ssel; unsigned long sclk; - enum bfin_spi_state state; + enum adi_spi_state state; - const struct bfin_spi_transfer_ops *ops; + const struct adi_spi_transfer_ops *ops; }; -struct bfin_spi_device { +struct adi_spi_device { u32 control; u32 clock; u32 ssel; @@ -105,17 +105,25 @@ struct bfin_spi_device { u32 cs_gpio; u32 tx_dummy_val; /* tx value for rx only transfer */ bool enable_dma; - const struct bfin_spi_transfer_ops *ops; + const struct adi_spi_transfer_ops *ops; }; -static void bfin_spi_enable(struct bfin_spi_master *drv_data) +static void adi_spi_enable(struct adi_spi_master *drv_data) { - bfin_write_or(&drv_data->regs->control, SPI_CTL_EN); + u32 ctl; + + ctl = ioread32(&drv_data->regs->control); + ctl |= SPI_CTL_EN; + iowrite32(ctl, &drv_data->regs->control); } -static void bfin_spi_disable(struct bfin_spi_master *drv_data) +static void adi_spi_disable(struct adi_spi_master *drv_data) { - bfin_write_and(&drv_data->regs->control, ~SPI_CTL_EN); + u32 ctl; + + ctl = ioread32(&drv_data->regs->control); + ctl &= ~SPI_CTL_EN; + iowrite32(ctl, &drv_data->regs->control); } /* Caculate the SPI_CLOCK register value based on input HZ */ @@ -128,35 +136,43 @@ static u32 hz_to_spi_clock(u32 sclk, u32 speed_hz) return spi_clock; } -static int bfin_spi_flush(struct bfin_spi_master *drv_data) +static int adi_spi_flush(struct adi_spi_master *drv_data) { unsigned long limit = loops_per_jiffy << 1; /* wait for stop and clear stat */ - while (!(bfin_read(&drv_data->regs->status) & SPI_STAT_SPIF) && --limit) + while (!(ioread32(&drv_data->regs->status) & SPI_STAT_SPIF) && --limit) cpu_relax(); - bfin_write(&drv_data->regs->status, 0xFFFFFFFF); + iowrite32(0xFFFFFFFF, &drv_data->regs->status); return limit; } /* Chip select operation functions for cs_change flag */ -static void bfin_spi_cs_active(struct bfin_spi_master *drv_data, struct bfin_spi_device *chip) +static void adi_spi_cs_active(struct adi_spi_master *drv_data, struct adi_spi_device *chip) { - if (likely(chip->cs < MAX_CTRL_CS)) - bfin_write_and(&drv_data->regs->ssel, ~chip->ssel); - else + if (likely(chip->cs < MAX_CTRL_CS)) { + u32 reg; + reg = ioread32(&drv_data->regs->ssel); + reg &= ~chip->ssel; + iowrite32(reg, &drv_data->regs->ssel); + } else { gpio_set_value(chip->cs_gpio, 0); + } } -static void bfin_spi_cs_deactive(struct bfin_spi_master *drv_data, - struct bfin_spi_device *chip) +static void adi_spi_cs_deactive(struct adi_spi_master *drv_data, + struct adi_spi_device *chip) { - if (likely(chip->cs < MAX_CTRL_CS)) - bfin_write_or(&drv_data->regs->ssel, chip->ssel); - else + if (likely(chip->cs < MAX_CTRL_CS)) { + u32 reg; + reg = ioread32(&drv_data->regs->ssel); + reg |= chip->ssel; + iowrite32(reg, &drv_data->regs->ssel); + } else { gpio_set_value(chip->cs_gpio, 1); + } /* Move delay here for consistency */ if (chip->cs_chg_udelay) @@ -164,187 +180,192 @@ static void bfin_spi_cs_deactive(struct bfin_spi_master *drv_data, } /* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */ -static inline void bfin_spi_cs_enable(struct bfin_spi_master *drv_data, - struct bfin_spi_device *chip) +static inline void adi_spi_cs_enable(struct adi_spi_master *drv_data, + struct adi_spi_device *chip) { - if (chip->cs < MAX_CTRL_CS) - bfin_write_or(&drv_data->regs->ssel, chip->ssel >> 8); + if (chip->cs < MAX_CTRL_CS) { + u32 reg; + reg = ioread32(&drv_data->regs->ssel); + reg |= chip->ssel >> 8; + iowrite32(reg, &drv_data->regs->ssel); + } } -static inline void bfin_spi_cs_disable(struct bfin_spi_master *drv_data, - struct bfin_spi_device *chip) +static inline void adi_spi_cs_disable(struct adi_spi_master *drv_data, + struct adi_spi_device *chip) { - if (chip->cs < MAX_CTRL_CS) - bfin_write_and(&drv_data->regs->ssel, ~(chip->ssel >> 8)); + if (chip->cs < MAX_CTRL_CS) { + u32 reg; + reg = ioread32(&drv_data->regs->ssel); + reg &= ~(chip->ssel >> 8); + iowrite32(reg, &drv_data->regs->ssel); + } } /* stop controller and re-config current chip*/ -static void bfin_spi_restore_state(struct bfin_spi_master *drv_data) +static void adi_spi_restore_state(struct adi_spi_master *drv_data) { - struct bfin_spi_device *chip = drv_data->cur_chip; + struct adi_spi_device *chip = drv_data->cur_chip; /* Clear status and disable clock */ - bfin_write(&drv_data->regs->status, 0xFFFFFFFF); - bfin_write(&drv_data->regs->rx_control, 0x0); - bfin_write(&drv_data->regs->tx_control, 0x0); - bfin_spi_disable(drv_data); - - SSYNC(); + iowrite32(0xFFFFFFFF, &drv_data->regs->status); + iowrite32(0x0, &drv_data->regs->rx_control); + iowrite32(0x0, &drv_data->regs->tx_control); + adi_spi_disable(drv_data); /* Load the registers */ - bfin_write(&drv_data->regs->control, chip->control); - bfin_write(&drv_data->regs->clock, chip->clock); + iowrite32(chip->control, &drv_data->regs->control); + iowrite32(chip->clock, &drv_data->regs->clock); - bfin_spi_enable(drv_data); + adi_spi_enable(drv_data); drv_data->tx_num = drv_data->rx_num = 0; /* we always choose tx transfer initiate */ - bfin_write(&drv_data->regs->rx_control, SPI_RXCTL_REN); - bfin_write(&drv_data->regs->tx_control, - SPI_TXCTL_TEN | SPI_TXCTL_TTI); - bfin_spi_cs_active(drv_data, chip); + iowrite32(SPI_RXCTL_REN, &drv_data->regs->rx_control); + iowrite32(SPI_TXCTL_TEN | SPI_TXCTL_TTI, &drv_data->regs->tx_control); + adi_spi_cs_active(drv_data, chip); } /* discard invalid rx data and empty rfifo */ -static inline void dummy_read(struct bfin_spi_master *drv_data) +static inline void dummy_read(struct adi_spi_master *drv_data) { - while (!(bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)) - bfin_read(&drv_data->regs->rfifo); + while (!(ioread32(&drv_data->regs->status) & SPI_STAT_RFE)) + ioread32(&drv_data->regs->rfifo); } -static void bfin_spi_u8_write(struct bfin_spi_master *drv_data) +static void adi_spi_u8_write(struct adi_spi_master *drv_data) { dummy_read(drv_data); while (drv_data->tx < drv_data->tx_end) { - bfin_write(&drv_data->regs->tfifo, (*(u8 *)(drv_data->tx++))); - while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + iowrite32(*(u8 *)(drv_data->tx++), &drv_data->regs->tfifo); + while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) cpu_relax(); - bfin_read(&drv_data->regs->rfifo); + ioread32(&drv_data->regs->rfifo); } } -static void bfin_spi_u8_read(struct bfin_spi_master *drv_data) +static void adi_spi_u8_read(struct adi_spi_master *drv_data) { u32 tx_val = drv_data->cur_chip->tx_dummy_val; dummy_read(drv_data); while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tfifo, tx_val); - while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + iowrite32(tx_val, &drv_data->regs->tfifo); + while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) cpu_relax(); - *(u8 *)(drv_data->rx++) = bfin_read(&drv_data->regs->rfifo); + *(u8 *)(drv_data->rx++) = ioread32(&drv_data->regs->rfifo); } } -static void bfin_spi_u8_duplex(struct bfin_spi_master *drv_data) +static void adi_spi_u8_duplex(struct adi_spi_master *drv_data) { dummy_read(drv_data); while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tfifo, (*(u8 *)(drv_data->tx++))); - while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + iowrite32(*(u8 *)(drv_data->tx++), &drv_data->regs->tfifo); + while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) cpu_relax(); - *(u8 *)(drv_data->rx++) = bfin_read(&drv_data->regs->rfifo); + *(u8 *)(drv_data->rx++) = ioread32(&drv_data->regs->rfifo); } } -static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u8 = { - .write = bfin_spi_u8_write, - .read = bfin_spi_u8_read, - .duplex = bfin_spi_u8_duplex, +static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u8 = { + .write = adi_spi_u8_write, + .read = adi_spi_u8_read, + .duplex = adi_spi_u8_duplex, }; -static void bfin_spi_u16_write(struct bfin_spi_master *drv_data) +static void adi_spi_u16_write(struct adi_spi_master *drv_data) { dummy_read(drv_data); while (drv_data->tx < drv_data->tx_end) { - bfin_write(&drv_data->regs->tfifo, (*(u16 *)drv_data->tx)); + iowrite32(*(u16 *)drv_data->tx, &drv_data->regs->tfifo); drv_data->tx += 2; - while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) cpu_relax(); - bfin_read(&drv_data->regs->rfifo); + ioread32(&drv_data->regs->rfifo); } } -static void bfin_spi_u16_read(struct bfin_spi_master *drv_data) +static void adi_spi_u16_read(struct adi_spi_master *drv_data) { u32 tx_val = drv_data->cur_chip->tx_dummy_val; dummy_read(drv_data); while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tfifo, tx_val); - while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + iowrite32(tx_val, &drv_data->regs->tfifo); + while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) cpu_relax(); - *(u16 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo); + *(u16 *)drv_data->rx = ioread32(&drv_data->regs->rfifo); drv_data->rx += 2; } } -static void bfin_spi_u16_duplex(struct bfin_spi_master *drv_data) +static void adi_spi_u16_duplex(struct adi_spi_master *drv_data) { dummy_read(drv_data); while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tfifo, (*(u16 *)drv_data->tx)); + iowrite32(*(u16 *)drv_data->tx, &drv_data->regs->tfifo); drv_data->tx += 2; - while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) cpu_relax(); - *(u16 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo); + *(u16 *)drv_data->rx = ioread32(&drv_data->regs->rfifo); drv_data->rx += 2; } } -static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u16 = { - .write = bfin_spi_u16_write, - .read = bfin_spi_u16_read, - .duplex = bfin_spi_u16_duplex, +static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u16 = { + .write = adi_spi_u16_write, + .read = adi_spi_u16_read, + .duplex = adi_spi_u16_duplex, }; -static void bfin_spi_u32_write(struct bfin_spi_master *drv_data) +static void adi_spi_u32_write(struct adi_spi_master *drv_data) { dummy_read(drv_data); while (drv_data->tx < drv_data->tx_end) { - bfin_write(&drv_data->regs->tfifo, (*(u32 *)drv_data->tx)); + iowrite32(*(u32 *)drv_data->tx, &drv_data->regs->tfifo); drv_data->tx += 4; - while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) cpu_relax(); - bfin_read(&drv_data->regs->rfifo); + ioread32(&drv_data->regs->rfifo); } } -static void bfin_spi_u32_read(struct bfin_spi_master *drv_data) +static void adi_spi_u32_read(struct adi_spi_master *drv_data) { u32 tx_val = drv_data->cur_chip->tx_dummy_val; dummy_read(drv_data); while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tfifo, tx_val); - while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + iowrite32(tx_val, &drv_data->regs->tfifo); + while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) cpu_relax(); - *(u32 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo); + *(u32 *)drv_data->rx = ioread32(&drv_data->regs->rfifo); drv_data->rx += 4; } } -static void bfin_spi_u32_duplex(struct bfin_spi_master *drv_data) +static void adi_spi_u32_duplex(struct adi_spi_master *drv_data) { dummy_read(drv_data); while (drv_data->rx < drv_data->rx_end) { - bfin_write(&drv_data->regs->tfifo, (*(u32 *)drv_data->tx)); + iowrite32(*(u32 *)drv_data->tx, &drv_data->regs->tfifo); drv_data->tx += 4; - while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + while (ioread32(&drv_data->regs->status) & SPI_STAT_RFE) cpu_relax(); - *(u32 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo); + *(u32 *)drv_data->rx = ioread32(&drv_data->regs->rfifo); drv_data->rx += 4; } } -static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u32 = { - .write = bfin_spi_u32_write, - .read = bfin_spi_u32_read, - .duplex = bfin_spi_u32_duplex, +static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u32 = { + .write = adi_spi_u32_write, + .read = adi_spi_u32_read, + .duplex = adi_spi_u32_duplex, }; /* test if there is more transfer to be done */ -static void bfin_spi_next_transfer(struct bfin_spi_master *drv) +static void adi_spi_next_transfer(struct adi_spi_master *drv) { struct spi_message *msg = drv->cur_msg; struct spi_transfer *t = drv->cur_transfer; @@ -360,15 +381,15 @@ static void bfin_spi_next_transfer(struct bfin_spi_master *drv) } } -static void bfin_spi_giveback(struct bfin_spi_master *drv_data) +static void adi_spi_giveback(struct adi_spi_master *drv_data) { - struct bfin_spi_device *chip = drv_data->cur_chip; + struct adi_spi_device *chip = drv_data->cur_chip; - bfin_spi_cs_deactive(drv_data, chip); + adi_spi_cs_deactive(drv_data, chip); spi_finalize_current_message(drv_data->master); } -static int bfin_spi_setup_transfer(struct bfin_spi_master *drv) +static int adi_spi_setup_transfer(struct adi_spi_master *drv) { struct spi_transfer *t = drv->cur_transfer; u32 cr, cr_width; @@ -393,34 +414,33 @@ static int bfin_spi_setup_transfer(struct bfin_spi_master *drv) switch (t->bits_per_word) { case 8: cr_width = SPI_CTL_SIZE08; - drv->ops = &bfin_bfin_spi_transfer_ops_u8; + drv->ops = &adi_spi_transfer_ops_u8; break; case 16: cr_width = SPI_CTL_SIZE16; - drv->ops = &bfin_bfin_spi_transfer_ops_u16; + drv->ops = &adi_spi_transfer_ops_u16; break; case 32: cr_width = SPI_CTL_SIZE32; - drv->ops = &bfin_bfin_spi_transfer_ops_u32; + drv->ops = &adi_spi_transfer_ops_u32; break; default: return -EINVAL; } - cr = bfin_read(&drv->regs->control) & ~SPI_CTL_SIZE; + cr = ioread32(&drv->regs->control) & ~SPI_CTL_SIZE; cr |= cr_width; - bfin_write(&drv->regs->control, cr); + iowrite32(cr, &drv->regs->control); /* speed setup */ - bfin_write(&drv->regs->clock, - hz_to_spi_clock(drv->sclk, t->speed_hz)); + iowrite32(hz_to_spi_clock(drv->sclk, t->speed_hz), &drv->regs->clock); return 0; } -static int bfin_spi_dma_xfer(struct bfin_spi_master *drv_data) +static int adi_spi_dma_xfer(struct adi_spi_master *drv_data) { struct spi_transfer *t = drv_data->cur_transfer; struct spi_message *msg = drv_data->cur_msg; - struct bfin_spi_device *chip = drv_data->cur_chip; + struct adi_spi_device *chip = drv_data->cur_chip; u32 dma_config; unsigned long word_count, word_size; void *tx_buf, *rx_buf; @@ -498,17 +518,16 @@ static int bfin_spi_dma_xfer(struct bfin_spi_master *drv_data) set_dma_config(drv_data->rx_dma, dma_config | WNR); enable_dma(drv_data->tx_dma); enable_dma(drv_data->rx_dma); - SSYNC(); - bfin_write(&drv_data->regs->rx_control, SPI_RXCTL_REN | SPI_RXCTL_RDR_NE); - SSYNC(); - bfin_write(&drv_data->regs->tx_control, - SPI_TXCTL_TEN | SPI_TXCTL_TTI | SPI_TXCTL_TDR_NF); + iowrite32(SPI_RXCTL_REN | SPI_RXCTL_RDR_NE, + &drv_data->regs->rx_control); + iowrite32(SPI_TXCTL_TEN | SPI_TXCTL_TTI | SPI_TXCTL_TDR_NF, + &drv_data->regs->tx_control); return 0; } -static int bfin_spi_pio_xfer(struct bfin_spi_master *drv_data) +static int adi_spi_pio_xfer(struct adi_spi_master *drv_data) { struct spi_message *msg = drv_data->cur_msg; @@ -529,19 +548,19 @@ static int bfin_spi_pio_xfer(struct bfin_spi_master *drv_data) return -EIO; } - if (!bfin_spi_flush(drv_data)) + if (!adi_spi_flush(drv_data)) return -EIO; msg->actual_length += drv_data->transfer_len; tasklet_schedule(&drv_data->pump_transfers); return 0; } -static void bfin_spi_pump_transfers(unsigned long data) +static void adi_spi_pump_transfers(unsigned long data) { - struct bfin_spi_master *drv_data = (struct bfin_spi_master *)data; + struct adi_spi_master *drv_data = (struct adi_spi_master *)data; struct spi_message *msg = NULL; struct spi_transfer *t = NULL; - struct bfin_spi_device *chip = NULL; + struct adi_spi_device *chip = NULL; int ret; /* Get current state information */ @@ -552,7 +571,7 @@ static void bfin_spi_pump_transfers(unsigned long data) /* Handle for abort */ if (drv_data->state == ERROR_STATE) { msg->status = -EIO; - bfin_spi_giveback(drv_data); + adi_spi_giveback(drv_data); return; } @@ -560,14 +579,14 @@ static void bfin_spi_pump_transfers(unsigned long data) if (t->delay_usecs) udelay(t->delay_usecs); if (t->cs_change) - bfin_spi_cs_deactive(drv_data, chip); - bfin_spi_next_transfer(drv_data); + adi_spi_cs_deactive(drv_data, chip); + adi_spi_next_transfer(drv_data); t = drv_data->cur_transfer; } /* Handle end of message */ if (drv_data->state == DONE_STATE) { msg->status = 0; - bfin_spi_giveback(drv_data); + adi_spi_giveback(drv_data); return; } @@ -577,34 +596,34 @@ static void bfin_spi_pump_transfers(unsigned long data) return; } - ret = bfin_spi_setup_transfer(drv_data); + ret = adi_spi_setup_transfer(drv_data); if (ret) { msg->status = ret; - bfin_spi_giveback(drv_data); + adi_spi_giveback(drv_data); } - bfin_write(&drv_data->regs->status, 0xFFFFFFFF); - bfin_spi_cs_active(drv_data, chip); + iowrite32(0xFFFFFFFF, &drv_data->regs->status); + adi_spi_cs_active(drv_data, chip); drv_data->state = RUNNING_STATE; if (chip->enable_dma) - ret = bfin_spi_dma_xfer(drv_data); + ret = adi_spi_dma_xfer(drv_data); else - ret = bfin_spi_pio_xfer(drv_data); + ret = adi_spi_pio_xfer(drv_data); if (ret) { msg->status = ret; - bfin_spi_giveback(drv_data); + adi_spi_giveback(drv_data); } } -static int bfin_spi_transfer_one_message(struct spi_master *master, +static int adi_spi_transfer_one_message(struct spi_master *master, struct spi_message *m) { - struct bfin_spi_master *drv_data = spi_master_get_devdata(master); + struct adi_spi_master *drv_data = spi_master_get_devdata(master); drv_data->cur_msg = m; drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); - bfin_spi_restore_state(drv_data); + adi_spi_restore_state(drv_data); drv_data->state = START_STATE; drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, @@ -630,15 +649,15 @@ static const u16 ssel[][MAX_SPI_SSEL] = { P_SPI2_SSEL6, P_SPI2_SSEL7}, }; -static int bfin_spi_setup(struct spi_device *spi) +static int adi_spi_setup(struct spi_device *spi) { - struct bfin_spi_master *drv_data = spi_master_get_devdata(spi->master); - struct bfin_spi_device *chip = spi_get_ctldata(spi); - u32 bfin_ctl_reg = SPI_CTL_ODM | SPI_CTL_PSSE; + struct adi_spi_master *drv_data = spi_master_get_devdata(spi->master); + struct adi_spi_device *chip = spi_get_ctldata(spi); + u32 ctl_reg = SPI_CTL_ODM | SPI_CTL_PSSE; int ret = -EINVAL; if (!chip) { - struct bfin_spi3_chip *chip_info = spi->controller_data; + struct adi_spi3_chip *chip_info = spi->controller_data; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) { @@ -646,7 +665,7 @@ static int bfin_spi_setup(struct spi_device *spi) return -ENOMEM; } if (chip_info) { - if (chip_info->control & ~bfin_ctl_reg) { + if (chip_info->control & ~ctl_reg) { dev_err(&spi->dev, "do not set bits that the SPI framework manages\n"); goto error; @@ -657,6 +676,7 @@ static int bfin_spi_setup(struct spi_device *spi) chip->enable_dma = chip_info->enable_dma; } chip->cs = spi->chip_select; + if (chip->cs < MAX_CTRL_CS) { chip->ssel = (1 << chip->cs) << 8; ret = peripheral_request(ssel[spi->master->bus_num] @@ -678,7 +698,7 @@ static int bfin_spi_setup(struct spi_device *spi) } /* force a default base state */ - chip->control &= bfin_ctl_reg; + chip->control &= ctl_reg; if (spi->mode & SPI_CPOL) chip->control |= SPI_CTL_CPOL; @@ -692,8 +712,8 @@ static int bfin_spi_setup(struct spi_device *spi) chip->clock = hz_to_spi_clock(drv_data->sclk, spi->max_speed_hz); - bfin_spi_cs_enable(drv_data, chip); - bfin_spi_cs_deactive(drv_data, chip); + adi_spi_cs_enable(drv_data, chip); + adi_spi_cs_deactive(drv_data, chip); return 0; error: @@ -705,10 +725,10 @@ static int bfin_spi_setup(struct spi_device *spi) return ret; } -static void bfin_spi_cleanup(struct spi_device *spi) +static void adi_spi_cleanup(struct spi_device *spi) { - struct bfin_spi_device *chip = spi_get_ctldata(spi); - struct bfin_spi_master *drv_data = spi_master_get_devdata(spi->master); + struct adi_spi_device *chip = spi_get_ctldata(spi); + struct adi_spi_master *drv_data = spi_master_get_devdata(spi->master); if (!chip) return; @@ -716,7 +736,7 @@ static void bfin_spi_cleanup(struct spi_device *spi) if (chip->cs < MAX_CTRL_CS) { peripheral_free(ssel[spi->master->bus_num] [chip->cs-1]); - bfin_spi_cs_disable(drv_data, chip); + adi_spi_cs_disable(drv_data, chip); } else { gpio_free(chip->cs_gpio); } @@ -725,10 +745,11 @@ static void bfin_spi_cleanup(struct spi_device *spi) spi_set_ctldata(spi, NULL); } -static irqreturn_t bfin_spi_tx_dma_isr(int irq, void *dev_id) +static irqreturn_t adi_spi_tx_dma_isr(int irq, void *dev_id) { - struct bfin_spi_master *drv_data = dev_id; + struct adi_spi_master *drv_data = dev_id; u32 dma_stat = get_dma_curr_irqstat(drv_data->tx_dma); + u32 tx_ctl; clear_dma_irqstat(drv_data->tx_dma); if (dma_stat & DMA_DONE) { @@ -739,13 +760,15 @@ static irqreturn_t bfin_spi_tx_dma_isr(int irq, void *dev_id) if (drv_data->tx) drv_data->state = ERROR_STATE; } - bfin_write_and(&drv_data->regs->tx_control, ~SPI_TXCTL_TDR_NF); + tx_ctl = ioread32(&drv_data->regs->tx_control); + tx_ctl &= ~SPI_TXCTL_TDR_NF; + iowrite32(tx_ctl, &drv_data->regs->tx_control); return IRQ_HANDLED; } -static irqreturn_t bfin_spi_rx_dma_isr(int irq, void *dev_id) +static irqreturn_t adi_spi_rx_dma_isr(int irq, void *dev_id) { - struct bfin_spi_master *drv_data = dev_id; + struct adi_spi_master *drv_data = dev_id; struct spi_message *msg = drv_data->cur_msg; u32 dma_stat = get_dma_curr_irqstat(drv_data->rx_dma); @@ -760,8 +783,8 @@ static irqreturn_t bfin_spi_rx_dma_isr(int irq, void *dev_id) dev_err(&drv_data->master->dev, "spi rx dma error: %d\n", dma_stat); } - bfin_write(&drv_data->regs->tx_control, 0); - bfin_write(&drv_data->regs->rx_control, 0); + iowrite32(0, &drv_data->regs->tx_control); + iowrite32(0, &drv_data->regs->rx_control); if (drv_data->rx_num != drv_data->tx_num) dev_dbg(&drv_data->master->dev, "dma interrupt missing: tx=%d,rx=%d\n", @@ -770,15 +793,15 @@ static irqreturn_t bfin_spi_rx_dma_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int bfin_spi_probe(struct platform_device *pdev) +static int adi_spi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct bfin_spi3_master *info = dev_get_platdata(dev); + struct adi_spi3_master *info = dev_get_platdata(dev); struct spi_master *master; - struct bfin_spi_master *drv_data; + struct adi_spi_master *drv_data; struct resource *mem, *res; unsigned int tx_dma, rx_dma; - unsigned long sclk; + struct clk *sclk; int ret; if (!info) { @@ -786,10 +809,10 @@ static int bfin_spi_probe(struct platform_device *pdev) return -ENODEV; } - sclk = get_sclk1(); - if (!sclk) { - dev_err(dev, "can not get sclk1\n"); - return -ENXIO; + sclk = devm_clk_get(dev, "spi"); + if (IS_ERR(sclk)) { + dev_err(dev, "can not get spi clock\n"); + return PTR_ERR(sclk); } res = platform_get_resource(pdev, IORESOURCE_DMA, 0); @@ -819,9 +842,9 @@ static int bfin_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->num_chipselect = info->num_chipselect; - master->cleanup = bfin_spi_cleanup; - master->setup = bfin_spi_setup; - master->transfer_one_message = bfin_spi_transfer_one_message; + master->cleanup = adi_spi_cleanup; + master->setup = adi_spi_setup; + master->transfer_one_message = adi_spi_transfer_one_message; master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8); @@ -830,7 +853,7 @@ static int bfin_spi_probe(struct platform_device *pdev) drv_data->tx_dma = tx_dma; drv_data->rx_dma = rx_dma; drv_data->pin_req = info->pin_req; - drv_data->sclk = sclk; + drv_data->sclk = clk_get_rate(sclk); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); drv_data->regs = devm_ioremap_resource(dev, mem); @@ -845,28 +868,28 @@ static int bfin_spi_probe(struct platform_device *pdev) dev_err(dev, "can not request SPI TX DMA channel\n"); goto err_put_master; } - set_dma_callback(tx_dma, bfin_spi_tx_dma_isr, drv_data); + set_dma_callback(tx_dma, adi_spi_tx_dma_isr, drv_data); ret = request_dma(rx_dma, "SPI_RX_DMA"); if (ret) { dev_err(dev, "can not request SPI RX DMA channel\n"); goto err_free_tx_dma; } - set_dma_callback(drv_data->rx_dma, bfin_spi_rx_dma_isr, drv_data); + set_dma_callback(drv_data->rx_dma, adi_spi_rx_dma_isr, drv_data); /* request CLK, MOSI and MISO */ - ret = peripheral_request_list(drv_data->pin_req, "bfin-spi3"); + ret = peripheral_request_list(drv_data->pin_req, "adi-spi3"); if (ret < 0) { dev_err(dev, "can not request spi pins\n"); goto err_free_rx_dma; } - bfin_write(&drv_data->regs->control, SPI_CTL_MSTR | SPI_CTL_CPHA); - bfin_write(&drv_data->regs->ssel, 0x0000FE00); - bfin_write(&drv_data->regs->delay, 0x0); + iowrite32(SPI_CTL_MSTR | SPI_CTL_CPHA, &drv_data->regs->control); + iowrite32(0x0000FE00, &drv_data->regs->ssel); + iowrite32(0x0, &drv_data->regs->delay); tasklet_init(&drv_data->pump_transfers, - bfin_spi_pump_transfers, (unsigned long)drv_data); + adi_spi_pump_transfers, (unsigned long)drv_data); /* register with the SPI framework */ ret = devm_spi_register_master(dev, master); if (ret) { @@ -888,43 +911,41 @@ static int bfin_spi_probe(struct platform_device *pdev) return ret; } -static int bfin_spi_remove(struct platform_device *pdev) +static int adi_spi_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); - struct bfin_spi_master *drv_data = spi_master_get_devdata(master); - - bfin_spi_disable(drv_data); + struct adi_spi_master *drv_data = spi_master_get_devdata(master); + adi_spi_disable(drv_data); peripheral_free_list(drv_data->pin_req); free_dma(drv_data->rx_dma); free_dma(drv_data->tx_dma); - return 0; } #ifdef CONFIG_PM -static int bfin_spi_suspend(struct device *dev) +static int adi_spi_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); - struct bfin_spi_master *drv_data = spi_master_get_devdata(master); + struct adi_spi_master *drv_data = spi_master_get_devdata(master); spi_master_suspend(master); - drv_data->control = bfin_read(&drv_data->regs->control); - drv_data->ssel = bfin_read(&drv_data->regs->ssel); + drv_data->control = ioread32(&drv_data->regs->control); + drv_data->ssel = ioread32(&drv_data->regs->ssel); - bfin_write(&drv_data->regs->control, SPI_CTL_MSTR | SPI_CTL_CPHA); - bfin_write(&drv_data->regs->ssel, 0x0000FE00); + iowrite32(SPI_CTL_MSTR | SPI_CTL_CPHA, &drv_data->regs->control); + iowrite32(0x0000FE00, &drv_data->regs->ssel); dma_disable_irq(drv_data->rx_dma); dma_disable_irq(drv_data->tx_dma); return 0; } -static int bfin_spi_resume(struct device *dev) +static int adi_spi_resume(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); - struct bfin_spi_master *drv_data = spi_master_get_devdata(master); + struct adi_spi_master *drv_data = spi_master_get_devdata(master); int ret = 0; /* bootrom may modify spi and dma status when resume in spi boot mode */ @@ -932,8 +953,8 @@ static int bfin_spi_resume(struct device *dev) dma_enable_irq(drv_data->rx_dma); dma_enable_irq(drv_data->tx_dma); - bfin_write(&drv_data->regs->control, drv_data->control); - bfin_write(&drv_data->regs->ssel, drv_data->ssel); + iowrite32(drv_data->control, &drv_data->regs->control); + iowrite32(drv_data->ssel, &drv_data->regs->ssel); ret = spi_master_resume(master); if (ret) { @@ -944,21 +965,21 @@ static int bfin_spi_resume(struct device *dev) return ret; } #endif -static const struct dev_pm_ops bfin_spi_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(bfin_spi_suspend, bfin_spi_resume) +static const struct dev_pm_ops adi_spi_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(adi_spi_suspend, adi_spi_resume) }; -MODULE_ALIAS("platform:bfin-spi3"); -static struct platform_driver bfin_spi_driver = { +MODULE_ALIAS("platform:adi-spi3"); +static struct platform_driver adi_spi_driver = { .driver = { - .name = "bfin-spi3", + .name = "adi-spi3", .owner = THIS_MODULE, - .pm = &bfin_spi_pm_ops, + .pm = &adi_spi_pm_ops, }, - .remove = bfin_spi_remove, + .remove = adi_spi_remove, }; -module_platform_driver_probe(bfin_spi_driver, bfin_spi_probe); +module_platform_driver_probe(adi_spi_driver, adi_spi_probe); MODULE_DESCRIPTION("Analog Devices SPI3 controller driver"); MODULE_AUTHOR("Scott Jiang "); diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 3898b0b9ee77cf..058db0fe8dc75f 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 079e6b1b0cdb6f..92a6f0d9323398 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -224,7 +224,7 @@ struct atmel_spi { struct platform_device *pdev; struct spi_transfer *current_transfer; - unsigned long current_remaining_bytes; + int current_remaining_bytes; int done_status; struct completion xfer_completion; @@ -874,8 +874,9 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer) spi_readl(as, RDR); } if (xfer->bits_per_word > 8) { - as->current_remaining_bytes -= 2; - if (as->current_remaining_bytes < 0) + if (as->current_remaining_bytes > 2) + as->current_remaining_bytes -= 2; + else as->current_remaining_bytes = 0; } else { as->current_remaining_bytes--; @@ -1110,6 +1111,8 @@ static int atmel_spi_one_transfer(struct spi_master *master, atmel_spi_next_xfer_pio(master, xfer); } else { as->current_remaining_bytes -= len; + if (as->current_remaining_bytes < 0) + as->current_remaining_bytes = 0; } } else { atmel_spi_next_xfer_pio(master, xfer); diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 5a211e98383bac..86f5a98aa7a270 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #define HSSPI_GLOBAL_CTRL_REG 0x0 diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 0250fa721cea89..8510400e7867f6 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c new file mode 100644 index 00000000000000..bb758978465dd1 --- /dev/null +++ b/drivers/spi/spi-cadence.c @@ -0,0 +1,673 @@ +/* + * Cadence SPI controller driver (master mode only) + * + * Copyright (C) 2008 - 2014 Xilinx, Inc. + * + * based on Blackfin On-Chip SPI Driver (spi_bfin5xx.c) + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Name of this driver */ +#define CDNS_SPI_NAME "cdns-spi" + +/* Register offset definitions */ +#define CDNS_SPI_CR_OFFSET 0x00 /* Configuration Register, RW */ +#define CDNS_SPI_ISR_OFFSET 0x04 /* Interrupt Status Register, RO */ +#define CDNS_SPI_IER_OFFSET 0x08 /* Interrupt Enable Register, WO */ +#define CDNS_SPI_IDR_OFFSET 0x0c /* Interrupt Disable Register, WO */ +#define CDNS_SPI_IMR_OFFSET 0x10 /* Interrupt Enabled Mask Register, RO */ +#define CDNS_SPI_ER_OFFSET 0x14 /* Enable/Disable Register, RW */ +#define CDNS_SPI_DR_OFFSET 0x18 /* Delay Register, RW */ +#define CDNS_SPI_TXD_OFFSET 0x1C /* Data Transmit Register, WO */ +#define CDNS_SPI_RXD_OFFSET 0x20 /* Data Receive Register, RO */ +#define CDNS_SPI_SICR_OFFSET 0x24 /* Slave Idle Count Register, RW */ +#define CDNS_SPI_THLD_OFFSET 0x28 /* Transmit FIFO Watermark Register,RW */ + +/* + * SPI Configuration Register bit Masks + * + * This register contains various control bits that affect the operation + * of the SPI controller + */ +#define CDNS_SPI_CR_MANSTRT_MASK 0x00010000 /* Manual TX Start */ +#define CDNS_SPI_CR_CPHA_MASK 0x00000004 /* Clock Phase Control */ +#define CDNS_SPI_CR_CPOL_MASK 0x00000002 /* Clock Polarity Control */ +#define CDNS_SPI_CR_SSCTRL_MASK 0x00003C00 /* Slave Select Mask */ +#define CDNS_SPI_CR_BAUD_DIV_MASK 0x00000038 /* Baud Rate Divisor Mask */ +#define CDNS_SPI_CR_MSTREN_MASK 0x00000001 /* Master Enable Mask */ +#define CDNS_SPI_CR_MANSTRTEN_MASK 0x00008000 /* Manual TX Enable Mask */ +#define CDNS_SPI_CR_SSFORCE_MASK 0x00004000 /* Manual SS Enable Mask */ +#define CDNS_SPI_CR_BAUD_DIV_4_MASK 0x00000008 /* Default Baud Div Mask */ +#define CDNS_SPI_CR_DEFAULT_MASK (CDNS_SPI_CR_MSTREN_MASK | \ + CDNS_SPI_CR_SSCTRL_MASK | \ + CDNS_SPI_CR_SSFORCE_MASK | \ + CDNS_SPI_CR_BAUD_DIV_4_MASK) + +/* + * SPI Configuration Register - Baud rate and slave select + * + * These are the values used in the calculation of baud rate divisor and + * setting the slave select. + */ + +#define CDNS_SPI_BAUD_DIV_MAX 7 /* Baud rate divisor maximum */ +#define CDNS_SPI_BAUD_DIV_MIN 1 /* Baud rate divisor minimum */ +#define CDNS_SPI_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift in CR */ +#define CDNS_SPI_SS_SHIFT 10 /* Slave Select field shift in CR */ +#define CDNS_SPI_SS0 0x1 /* Slave Select zero */ + +/* + * SPI Interrupt Registers bit Masks + * + * All the four interrupt registers (Status/Mask/Enable/Disable) have the same + * bit definitions. + */ +#define CDNS_SPI_IXR_TXOW_MASK 0x00000004 /* SPI TX FIFO Overwater */ +#define CDNS_SPI_IXR_MODF_MASK 0x00000002 /* SPI Mode Fault */ +#define CDNS_SPI_IXR_RXNEMTY_MASK 0x00000010 /* SPI RX FIFO Not Empty */ +#define CDNS_SPI_IXR_DEFAULT_MASK (CDNS_SPI_IXR_TXOW_MASK | \ + CDNS_SPI_IXR_MODF_MASK) +#define CDNS_SPI_IXR_TXFULL_MASK 0x00000008 /* SPI TX Full */ +#define CDNS_SPI_IXR_ALL_MASK 0x0000007F /* SPI all interrupts */ + +/* + * SPI Enable Register bit Masks + * + * This register is used to enable or disable the SPI controller + */ +#define CDNS_SPI_ER_ENABLE_MASK 0x00000001 /* SPI Enable Bit Mask */ +#define CDNS_SPI_ER_DISABLE_MASK 0x0 /* SPI Disable Bit Mask */ + +/* SPI FIFO depth in bytes */ +#define CDNS_SPI_FIFO_DEPTH 128 + +/* Default number of chip select lines */ +#define CDNS_SPI_DEFAULT_NUM_CS 4 + +/** + * struct cdns_spi - This definition defines spi driver instance + * @regs: Virtual address of the SPI controller registers + * @ref_clk: Pointer to the peripheral clock + * @pclk: Pointer to the APB clock + * @speed_hz: Current SPI bus clock speed in Hz + * @txbuf: Pointer to the TX buffer + * @rxbuf: Pointer to the RX buffer + * @tx_bytes: Number of bytes left to transfer + * @rx_bytes: Number of bytes requested + * @dev_busy: Device busy flag + * @is_decoded_cs: Flag for decoder property set or not + */ +struct cdns_spi { + void __iomem *regs; + struct clk *ref_clk; + struct clk *pclk; + u32 speed_hz; + const u8 *txbuf; + u8 *rxbuf; + int tx_bytes; + int rx_bytes; + u8 dev_busy; + u32 is_decoded_cs; +}; + +/* Macros for the SPI controller read/write */ +static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset) +{ + return readl_relaxed(xspi->regs + offset); +} + +static inline void cdns_spi_write(struct cdns_spi *xspi, u32 offset, u32 val) +{ + writel_relaxed(val, xspi->regs + offset); +} + +/** + * cdns_spi_init_hw - Initialize the hardware and configure the SPI controller + * @xspi: Pointer to the cdns_spi structure + * + * On reset the SPI controller is configured to be in master mode, baud rate + * divisor is set to 4, threshold value for TX FIFO not full interrupt is set + * to 1 and size of the word to be transferred as 8 bit. + * This function initializes the SPI controller to disable and clear all the + * interrupts, enable manual slave select and manual start, deselect all the + * chip select lines, and enable the SPI controller. + */ +static void cdns_spi_init_hw(struct cdns_spi *xspi) +{ + cdns_spi_write(xspi, CDNS_SPI_ER_OFFSET, + CDNS_SPI_ER_DISABLE_MASK); + cdns_spi_write(xspi, CDNS_SPI_IDR_OFFSET, + CDNS_SPI_IXR_ALL_MASK); + + /* Clear the RX FIFO */ + while (cdns_spi_read(xspi, CDNS_SPI_ISR_OFFSET) & + CDNS_SPI_IXR_RXNEMTY_MASK) + cdns_spi_read(xspi, CDNS_SPI_RXD_OFFSET); + + cdns_spi_write(xspi, CDNS_SPI_ISR_OFFSET, + CDNS_SPI_IXR_ALL_MASK); + cdns_spi_write(xspi, CDNS_SPI_CR_OFFSET, + CDNS_SPI_CR_DEFAULT_MASK); + cdns_spi_write(xspi, CDNS_SPI_ER_OFFSET, + CDNS_SPI_ER_ENABLE_MASK); +} + +/** + * cdns_spi_chipselect - Select or deselect the chip select line + * @spi: Pointer to the spi_device structure + * @is_on: Select(0) or deselect (1) the chip select line + */ +static void cdns_spi_chipselect(struct spi_device *spi, bool is_high) +{ + struct cdns_spi *xspi = spi_master_get_devdata(spi->master); + u32 ctrl_reg; + + ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR_OFFSET); + + if (is_high) { + /* Deselect the slave */ + ctrl_reg |= CDNS_SPI_CR_SSCTRL_MASK; + } else { + /* Select the slave */ + ctrl_reg &= ~CDNS_SPI_CR_SSCTRL_MASK; + if (!(xspi->is_decoded_cs)) + ctrl_reg |= ((~(CDNS_SPI_SS0 << spi->chip_select)) << + CDNS_SPI_SS_SHIFT) & + CDNS_SPI_CR_SSCTRL_MASK; + else + ctrl_reg |= (spi->chip_select << CDNS_SPI_SS_SHIFT) & + CDNS_SPI_CR_SSCTRL_MASK; + } + + cdns_spi_write(xspi, CDNS_SPI_CR_OFFSET, ctrl_reg); +} + +/** + * cdns_spi_config_clock_mode - Sets clock polarity and phase + * @spi: Pointer to the spi_device structure + * + * Sets the requested clock polarity and phase. + */ +static void cdns_spi_config_clock_mode(struct spi_device *spi) +{ + struct cdns_spi *xspi = spi_master_get_devdata(spi->master); + u32 ctrl_reg; + + ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR_OFFSET); + + /* Set the SPI clock phase and clock polarity */ + ctrl_reg &= ~(CDNS_SPI_CR_CPHA_MASK | CDNS_SPI_CR_CPOL_MASK); + if (spi->mode & SPI_CPHA) + ctrl_reg |= CDNS_SPI_CR_CPHA_MASK; + if (spi->mode & SPI_CPOL) + ctrl_reg |= CDNS_SPI_CR_CPOL_MASK; + + cdns_spi_write(xspi, CDNS_SPI_CR_OFFSET, ctrl_reg); +} + +/** + * cdns_spi_config_clock_freq - Sets clock frequency + * @spi: Pointer to the spi_device structure + * @transfer: Pointer to the spi_transfer structure which provides + * information about next transfer setup parameters + * + * Sets the requested clock frequency. + * Note: If the requested frequency is not an exact match with what can be + * obtained using the prescalar value the driver sets the clock frequency which + * is lower than the requested frequency (maximum lower) for the transfer. If + * the requested frequency is higher or lower than that is supported by the SPI + * controller the driver will set the highest or lowest frequency supported by + * controller. + */ +static void cdns_spi_config_clock_freq(struct spi_device *spi, + struct spi_transfer *transfer) +{ + struct cdns_spi *xspi = spi_master_get_devdata(spi->master); + u32 ctrl_reg, baud_rate_val; + unsigned long frequency; + + frequency = clk_get_rate(xspi->ref_clk); + + ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR_OFFSET); + + /* Set the clock frequency */ + if (xspi->speed_hz != transfer->speed_hz) { + /* first valid value is 1 */ + baud_rate_val = CDNS_SPI_BAUD_DIV_MIN; + while ((baud_rate_val < CDNS_SPI_BAUD_DIV_MAX) && + (frequency / (2 << baud_rate_val)) > transfer->speed_hz) + baud_rate_val++; + + ctrl_reg &= ~CDNS_SPI_CR_BAUD_DIV_MASK; + ctrl_reg |= baud_rate_val << CDNS_SPI_BAUD_DIV_SHIFT; + + xspi->speed_hz = frequency / (2 << baud_rate_val); + } + cdns_spi_write(xspi, CDNS_SPI_CR_OFFSET, ctrl_reg); +} + +/** + * cdns_spi_setup_transfer - Configure SPI controller for specified transfer + * @spi: Pointer to the spi_device structure + * @transfer: Pointer to the spi_transfer structure which provides + * information about next transfer setup parameters + * + * Sets the operational mode of SPI controller for the next SPI transfer and + * sets the requested clock frequency. + * + * Return: Always 0 + */ +static int cdns_spi_setup_transfer(struct spi_device *spi, + struct spi_transfer *transfer) +{ + struct cdns_spi *xspi = spi_master_get_devdata(spi->master); + + cdns_spi_config_clock_freq(spi, transfer); + + dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u clock speed\n", + __func__, spi->mode, spi->bits_per_word, + xspi->speed_hz); + + return 0; +} + +/** + * cdns_spi_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible + * @xspi: Pointer to the cdns_spi structure + */ +static void cdns_spi_fill_tx_fifo(struct cdns_spi *xspi) +{ + unsigned long trans_cnt = 0; + + while ((trans_cnt < CDNS_SPI_FIFO_DEPTH) && + (xspi->tx_bytes > 0)) { + if (xspi->txbuf) + cdns_spi_write(xspi, CDNS_SPI_TXD_OFFSET, + *xspi->txbuf++); + else + cdns_spi_write(xspi, CDNS_SPI_TXD_OFFSET, 0); + + xspi->tx_bytes--; + trans_cnt++; + } +} + +/** + * cdns_spi_irq - Interrupt service routine of the SPI controller + * @irq: IRQ number + * @dev_id: Pointer to the xspi structure + * + * This function handles TX empty and Mode Fault interrupts only. + * On TX empty interrupt this function reads the received data from RX FIFO and + * fills the TX FIFO if there is any data remaining to be transferred. + * On Mode Fault interrupt this function indicates that transfer is completed, + * the SPI subsystem will identify the error as the remaining bytes to be + * transferred is non-zero. + * + * Return: IRQ_HANDLED when handled; IRQ_NONE otherwise. + */ +static irqreturn_t cdns_spi_irq(int irq, void *dev_id) +{ + struct spi_master *master = dev_id; + struct cdns_spi *xspi = spi_master_get_devdata(master); + u32 intr_status, status; + + status = IRQ_NONE; + intr_status = cdns_spi_read(xspi, CDNS_SPI_ISR_OFFSET); + cdns_spi_write(xspi, CDNS_SPI_ISR_OFFSET, intr_status); + + if (intr_status & CDNS_SPI_IXR_MODF_MASK) { + /* Indicate that transfer is completed, the SPI subsystem will + * identify the error as the remaining bytes to be + * transferred is non-zero + */ + cdns_spi_write(xspi, CDNS_SPI_IDR_OFFSET, + CDNS_SPI_IXR_DEFAULT_MASK); + spi_finalize_current_transfer(master); + status = IRQ_HANDLED; + } else if (intr_status & CDNS_SPI_IXR_TXOW_MASK) { + unsigned long trans_cnt; + + trans_cnt = xspi->rx_bytes - xspi->tx_bytes; + + /* Read out the data from the RX FIFO */ + while (trans_cnt) { + u8 data; + + data = cdns_spi_read(xspi, CDNS_SPI_RXD_OFFSET); + if (xspi->rxbuf) + *xspi->rxbuf++ = data; + + xspi->rx_bytes--; + trans_cnt--; + } + + if (xspi->tx_bytes) { + /* There is more data to send */ + cdns_spi_fill_tx_fifo(xspi); + } else { + /* Transfer is completed */ + cdns_spi_write(xspi, CDNS_SPI_IDR_OFFSET, + CDNS_SPI_IXR_DEFAULT_MASK); + spi_finalize_current_transfer(master); + } + status = IRQ_HANDLED; + } + + return status; +} + +/** + * cdns_transfer_one - Initiates the SPI transfer + * @master: Pointer to spi_master structure + * @spi: Pointer to the spi_device structure + * @transfer: Pointer to the spi_transfer structure which provides + * information about next transfer parameters + * + * This function fills the TX FIFO, starts the SPI transfer and + * returns a positive transfer count so that core will wait for completion. + * + * Return: Number of bytes transferred in the last transfer + */ +static int cdns_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *transfer) +{ + struct cdns_spi *xspi = spi_master_get_devdata(master); + + xspi->txbuf = transfer->tx_buf; + xspi->rxbuf = transfer->rx_buf; + xspi->tx_bytes = transfer->len; + xspi->rx_bytes = transfer->len; + + cdns_spi_setup_transfer(spi, transfer); + + cdns_spi_fill_tx_fifo(xspi); + + cdns_spi_write(xspi, CDNS_SPI_IER_OFFSET, + CDNS_SPI_IXR_DEFAULT_MASK); + return transfer->len; +} + +/** + * cdns_prepare_transfer_hardware - Prepares hardware for transfer. + * @master: Pointer to the spi_master structure which provides + * information about the controller. + * + * This function enables SPI master controller. + * + * Return: 0 always + */ +static int cdns_prepare_transfer_hardware(struct spi_master *master) +{ + struct cdns_spi *xspi = spi_master_get_devdata(master); + + cdns_spi_config_clock_mode(master->cur_msg->spi); + + cdns_spi_write(xspi, CDNS_SPI_ER_OFFSET, + CDNS_SPI_ER_ENABLE_MASK); + + return 0; +} + +/** + * cdns_unprepare_transfer_hardware - Relaxes hardware after transfer + * @master: Pointer to the spi_master structure which provides + * information about the controller. + * + * This function disables the SPI master controller. + * + * Return: 0 always + */ +static int cdns_unprepare_transfer_hardware(struct spi_master *master) +{ + struct cdns_spi *xspi = spi_master_get_devdata(master); + + cdns_spi_write(xspi, CDNS_SPI_ER_OFFSET, + CDNS_SPI_ER_DISABLE_MASK); + + return 0; +} + +/** + * cdns_spi_probe - Probe method for the SPI driver + * @pdev: Pointer to the platform_device structure + * + * This function initializes the driver data structures and the hardware. + * + * Return: 0 on success and error value on error + */ +static int cdns_spi_probe(struct platform_device *pdev) +{ + int ret = 0, irq; + struct spi_master *master; + struct cdns_spi *xspi; + struct resource *res; + u32 num_cs; + + master = spi_alloc_master(&pdev->dev, sizeof(*xspi)); + if (master == NULL) + return -ENOMEM; + + xspi = spi_master_get_devdata(master); + master->dev.of_node = pdev->dev.of_node; + platform_set_drvdata(pdev, master); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xspi->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xspi->regs)) { + ret = PTR_ERR(xspi->regs); + goto remove_master; + } + + xspi->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(xspi->pclk)) { + dev_err(&pdev->dev, "pclk clock not found.\n"); + ret = PTR_ERR(xspi->pclk); + goto remove_master; + } + + xspi->ref_clk = devm_clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR(xspi->ref_clk)) { + dev_err(&pdev->dev, "ref_clk clock not found.\n"); + ret = PTR_ERR(xspi->ref_clk); + goto remove_master; + } + + ret = clk_prepare_enable(xspi->pclk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable APB clock.\n"); + goto remove_master; + } + + ret = clk_prepare_enable(xspi->ref_clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable device clock.\n"); + goto clk_dis_apb; + } + + /* SPI controller initializations */ + cdns_spi_init_hw(xspi); + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + ret = -ENXIO; + dev_err(&pdev->dev, "irq number is invalid\n"); + goto remove_master; + } + + ret = devm_request_irq(&pdev->dev, irq, cdns_spi_irq, + 0, pdev->name, master); + if (ret != 0) { + ret = -ENXIO; + dev_err(&pdev->dev, "request_irq failed\n"); + goto remove_master; + } + + ret = of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); + + if (ret < 0) + master->num_chipselect = CDNS_SPI_DEFAULT_NUM_CS; + else + master->num_chipselect = num_cs; + + ret = of_property_read_u32(pdev->dev.of_node, "is-decoded-cs", + &xspi->is_decoded_cs); + + if (ret < 0) + xspi->is_decoded_cs = 0; + + master->prepare_transfer_hardware = cdns_prepare_transfer_hardware; + master->transfer_one = cdns_transfer_one; + master->unprepare_transfer_hardware = cdns_unprepare_transfer_hardware; + master->set_cs = cdns_spi_chipselect; + master->mode_bits = SPI_CPOL | SPI_CPHA; + + /* Set to default valid value */ + master->max_speed_hz = clk_get_rate(xspi->ref_clk) / 4; + xspi->speed_hz = master->max_speed_hz; + + master->bits_per_word_mask = SPI_BPW_MASK(8); + + ret = spi_register_master(master); + if (ret) { + dev_err(&pdev->dev, "spi_register_master failed\n"); + goto clk_dis_all; + } + + return ret; + +clk_dis_all: + clk_disable_unprepare(xspi->ref_clk); +clk_dis_apb: + clk_disable_unprepare(xspi->pclk); +remove_master: + spi_master_put(master); + return ret; +} + +/** + * cdns_spi_remove - Remove method for the SPI driver + * @pdev: Pointer to the platform_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 all resources allocated to + * the device. + * + * Return: 0 on success and error value on error + */ +static int cdns_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct cdns_spi *xspi = spi_master_get_devdata(master); + + cdns_spi_write(xspi, CDNS_SPI_ER_OFFSET, + CDNS_SPI_ER_DISABLE_MASK); + + clk_disable_unprepare(xspi->ref_clk); + clk_disable_unprepare(xspi->pclk); + + spi_unregister_master(master); + + return 0; +} + +/** + * cdns_spi_suspend - Suspend method for the SPI driver + * @dev: Address of the platform_device structure + * + * This function disables the SPI controller and + * changes the driver state to "suspend" + * + * Return: Always 0 + */ +static int __maybe_unused cdns_spi_suspend(struct device *dev) +{ + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct cdns_spi *xspi = spi_master_get_devdata(master); + + spi_master_suspend(master); + + clk_disable_unprepare(xspi->ref_clk); + + clk_disable_unprepare(xspi->pclk); + + return 0; +} + +/** + * cdns_spi_resume - Resume method for the SPI driver + * @dev: Address of the platform_device structure + * + * This function changes the driver state to "ready" + * + * Return: 0 on success and error value on error + */ +static int __maybe_unused cdns_spi_resume(struct device *dev) +{ + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct cdns_spi *xspi = spi_master_get_devdata(master); + int ret = 0; + + ret = clk_prepare_enable(xspi->pclk); + if (ret) { + dev_err(dev, "Cannot enable APB clock.\n"); + return ret; + } + + ret = clk_prepare_enable(xspi->ref_clk); + if (ret) { + dev_err(dev, "Cannot enable device clock.\n"); + clk_disable(xspi->pclk); + return ret; + } + spi_master_resume(master); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(cdns_spi_dev_pm_ops, cdns_spi_suspend, + cdns_spi_resume); + +static struct of_device_id cdns_spi_of_match[] = { + { .compatible = "xlnx,zynq-spi-r1p6" }, + { .compatible = "cdns,spi-r1p6" }, + { /* end of table */ } +}; +MODULE_DEVICE_TABLE(of, cdns_spi_of_match); + +/* cdns_spi_driver - This structure defines the SPI subsystem platform driver */ +static struct platform_driver cdns_spi_driver = { + .probe = cdns_spi_probe, + .remove = cdns_spi_remove, + .driver = { + .name = CDNS_SPI_NAME, + .owner = THIS_MODULE, + .of_match_table = cdns_spi_of_match, + .pm = &cdns_spi_dev_pm_ops, + }, +}; + +module_platform_driver(cdns_spi_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Cadence SPI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 1492f5ee9aaad7..a5cba14ac3d2f6 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "spi-dw.h" @@ -70,6 +71,27 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) dws->num_cs = 4; dws->max_freq = clk_get_rate(dwsmmio->clk); + if (pdev->dev.of_node) { + int i; + + for (i = 0; i < dws->num_cs; i++) { + int cs_gpio = of_get_named_gpio(pdev->dev.of_node, + "cs-gpios", i); + + if (cs_gpio == -EPROBE_DEFER) { + ret = cs_gpio; + goto out; + } + + if (gpio_is_valid(cs_gpio)) { + ret = devm_gpio_request(&pdev->dev, cs_gpio, + dev_name(&pdev->dev)); + if (ret) + goto out; + } + } + } + ret = dw_spi_add_host(&pdev->dev, dws); if (ret) goto out; diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 712ac5629cd46c..9965e1b84832fc 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "spi-dw.h" @@ -36,12 +37,6 @@ #define DONE_STATE ((void *)2) #define ERROR_STATE ((void *)-1) -#define QUEUE_RUNNING 0 -#define QUEUE_STOPPED 1 - -#define MRST_SPI_DEASSERT 0 -#define MRST_SPI_ASSERT 1 - /* Slave spi_dev related */ struct chip_data { u16 cr0; @@ -263,28 +258,22 @@ static int map_dma_buffers(struct dw_spi *dws) static void giveback(struct dw_spi *dws) { struct spi_transfer *last_transfer; - unsigned long flags; struct spi_message *msg; - spin_lock_irqsave(&dws->lock, flags); msg = dws->cur_msg; dws->cur_msg = NULL; dws->cur_transfer = NULL; dws->prev_chip = dws->cur_chip; dws->cur_chip = NULL; dws->dma_mapped = 0; - queue_work(dws->workqueue, &dws->pump_messages); - spin_unlock_irqrestore(&dws->lock, flags); last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, transfer_list); - if (!last_transfer->cs_change && dws->cs_control) - dws->cs_control(MRST_SPI_DEASSERT); + if (!last_transfer->cs_change) + spi_chip_sel(dws, dws->cur_msg->spi, 0); - msg->state = NULL; - if (msg->complete) - msg->complete(msg->context); + spi_finalize_current_message(dws->master); } static void int_error_stop(struct dw_spi *dws, const char *msg) @@ -502,7 +491,7 @@ static void pump_transfers(unsigned long data) dw_writew(dws, DW_SPI_CTRL0, cr0); spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); - spi_chip_sel(dws, spi->chip_select); + spi_chip_sel(dws, spi, 1); /* Set the interrupt mask, for poll mode just disable all int */ spi_mask_intr(dws, 0xff); @@ -529,30 +518,12 @@ static void pump_transfers(unsigned long data) return; } -static void pump_messages(struct work_struct *work) +static int dw_spi_transfer_one_message(struct spi_master *master, + struct spi_message *msg) { - struct dw_spi *dws = - container_of(work, struct dw_spi, pump_messages); - unsigned long flags; - - /* Lock queue and check for queue work */ - spin_lock_irqsave(&dws->lock, flags); - if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) { - dws->busy = 0; - spin_unlock_irqrestore(&dws->lock, flags); - return; - } - - /* Make sure we are not already running a message */ - if (dws->cur_msg) { - spin_unlock_irqrestore(&dws->lock, flags); - return; - } - - /* Extract head of queue */ - dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue); - list_del_init(&dws->cur_msg->queue); + struct dw_spi *dws = spi_master_get_devdata(master); + dws->cur_msg = msg; /* Initial message state*/ dws->cur_msg->state = START_STATE; dws->cur_transfer = list_entry(dws->cur_msg->transfers.next, @@ -560,46 +531,9 @@ static void pump_messages(struct work_struct *work) transfer_list); dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi); - /* Mark as busy and launch transfers */ + /* Launch transfers */ tasklet_schedule(&dws->pump_transfers); - dws->busy = 1; - spin_unlock_irqrestore(&dws->lock, flags); -} - -/* spi_device use this to queue in their spi_msg */ -static int dw_spi_transfer(struct spi_device *spi, struct spi_message *msg) -{ - struct dw_spi *dws = spi_master_get_devdata(spi->master); - unsigned long flags; - - spin_lock_irqsave(&dws->lock, flags); - - if (dws->run == QUEUE_STOPPED) { - spin_unlock_irqrestore(&dws->lock, flags); - return -ESHUTDOWN; - } - - msg->actual_length = 0; - msg->status = -EINPROGRESS; - msg->state = START_STATE; - - list_add_tail(&msg->queue, &dws->queue); - - if (dws->run == QUEUE_RUNNING && !dws->busy) { - - if (dws->cur_transfer || dws->cur_msg) - queue_work(dws->workqueue, - &dws->pump_messages); - else { - /* If no other data transaction in air, just go */ - spin_unlock_irqrestore(&dws->lock, flags); - pump_messages(&dws->pump_messages); - return 0; - } - } - - spin_unlock_irqrestore(&dws->lock, flags); return 0; } @@ -608,6 +542,7 @@ static int dw_spi_setup(struct spi_device *spi) { struct dw_spi_chip *chip_info = NULL; struct chip_data *chip; + int ret; /* Only alloc on first setup */ chip = spi_get_ctldata(spi); @@ -661,82 +596,20 @@ static int dw_spi_setup(struct spi_device *spi) | (spi->mode << SPI_MODE_OFFSET) | (chip->tmode << SPI_TMOD_OFFSET); - return 0; -} - -static int init_queue(struct dw_spi *dws) -{ - INIT_LIST_HEAD(&dws->queue); - spin_lock_init(&dws->lock); - - dws->run = QUEUE_STOPPED; - dws->busy = 0; - - tasklet_init(&dws->pump_transfers, - pump_transfers, (unsigned long)dws); - - INIT_WORK(&dws->pump_messages, pump_messages); - dws->workqueue = create_singlethread_workqueue( - dev_name(dws->master->dev.parent)); - if (dws->workqueue == NULL) - return -EBUSY; - - return 0; -} - -static int start_queue(struct dw_spi *dws) -{ - unsigned long flags; - - spin_lock_irqsave(&dws->lock, flags); - - if (dws->run == QUEUE_RUNNING || dws->busy) { - spin_unlock_irqrestore(&dws->lock, flags); - return -EBUSY; + if (gpio_is_valid(spi->cs_gpio)) { + ret = gpio_direction_output(spi->cs_gpio, + !(spi->mode & SPI_CS_HIGH)); + if (ret) + return ret; } - dws->run = QUEUE_RUNNING; - dws->cur_msg = NULL; - dws->cur_transfer = NULL; - dws->cur_chip = NULL; - dws->prev_chip = NULL; - spin_unlock_irqrestore(&dws->lock, flags); - - queue_work(dws->workqueue, &dws->pump_messages); - return 0; } -static int stop_queue(struct dw_spi *dws) +static void dw_spi_cleanup(struct spi_device *spi) { - unsigned long flags; - unsigned limit = 50; - int status = 0; - - spin_lock_irqsave(&dws->lock, flags); - dws->run = QUEUE_STOPPED; - while ((!list_empty(&dws->queue) || dws->busy) && limit--) { - spin_unlock_irqrestore(&dws->lock, flags); - msleep(10); - spin_lock_irqsave(&dws->lock, flags); - } - - if (!list_empty(&dws->queue) || dws->busy) - status = -EBUSY; - spin_unlock_irqrestore(&dws->lock, flags); - - return status; -} - -static int destroy_queue(struct dw_spi *dws) -{ - int status; - - status = stop_queue(dws); - if (status != 0) - return status; - destroy_workqueue(dws->workqueue); - return 0; + struct chip_data *chip = spi_get_ctldata(spi); + kfree(chip); } /* Restart the controller, disable all interrupts, clean rx fifo */ @@ -794,7 +667,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) master->bus_num = dws->bus_num; master->num_chipselect = dws->num_cs; master->setup = dw_spi_setup; - master->transfer = dw_spi_transfer; + master->transfer_one_message = dw_spi_transfer_one_message; master->max_speed_hz = dws->max_freq; /* Basic HW init */ @@ -808,33 +681,21 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) } } - /* Initial and start queue */ - ret = init_queue(dws); - if (ret) { - dev_err(&master->dev, "problem initializing queue\n"); - goto err_diable_hw; - } - ret = start_queue(dws); - if (ret) { - dev_err(&master->dev, "problem starting queue\n"); - goto err_diable_hw; - } + tasklet_init(&dws->pump_transfers, pump_transfers, (unsigned long)dws); spi_master_set_devdata(master, dws); ret = devm_spi_register_master(dev, master); if (ret) { dev_err(&master->dev, "problem registering spi master\n"); - goto err_queue_alloc; + goto err_dma_exit; } mrst_spi_debugfs_init(dws); return 0; -err_queue_alloc: - destroy_queue(dws); +err_dma_exit: if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); -err_diable_hw: spi_enable_chip(dws, 0); err_free_master: spi_master_put(master); @@ -844,18 +705,10 @@ EXPORT_SYMBOL_GPL(dw_spi_add_host); void dw_spi_remove_host(struct dw_spi *dws) { - int status = 0; - if (!dws) return; mrst_spi_debugfs_remove(dws); - /* Remove the queue */ - status = destroy_queue(dws); - if (status != 0) - dev_err(&dws->master->dev, - "dw_spi_remove: workqueue will not complete, message memory not freed\n"); - if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); spi_enable_chip(dws, 0); @@ -868,7 +721,7 @@ int dw_spi_suspend_host(struct dw_spi *dws) { int ret = 0; - ret = stop_queue(dws); + ret = spi_master_suspend(dws->master); if (ret) return ret; spi_enable_chip(dws, 0); @@ -882,7 +735,7 @@ int dw_spi_resume_host(struct dw_spi *dws) int ret; spi_hw_init(dws); - ret = start_queue(dws); + ret = spi_master_resume(dws->master); if (ret) dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); return ret; diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 587643dae11e8b..6d2acad34f64f5 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -3,6 +3,7 @@ #include #include +#include /* Register offsets */ #define DW_SPI_CTRL0 0x00 @@ -104,14 +105,6 @@ struct dw_spi { u16 bus_num; u16 num_cs; /* supported slave numbers */ - /* Driver message queue */ - struct workqueue_struct *workqueue; - struct work_struct pump_messages; - spinlock_t lock; - struct list_head queue; - int busy; - int run; - /* Message Transfer pump */ struct tasklet_struct pump_transfers; @@ -186,15 +179,20 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div) dw_writel(dws, DW_SPI_BAUDR, div); } -static inline void spi_chip_sel(struct dw_spi *dws, u16 cs) +static inline void spi_chip_sel(struct dw_spi *dws, struct spi_device *spi, + int active) { - if (cs > dws->num_cs) - return; + u16 cs = spi->chip_select; + int gpio_val = active ? (spi->mode & SPI_CS_HIGH) : + !(spi->mode & SPI_CS_HIGH); if (dws->cs_control) - dws->cs_control(1); + dws->cs_control(active); + if (gpio_is_valid(spi->cs_gpio)) + gpio_set_value(spi->cs_gpio, gpio_val); - dw_writel(dws, DW_SPI_SER, 1 << cs); + if (active) + dw_writel(dws, DW_SPI_SER, 1 << cs); } /* Disable IRQ bits */ diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c index 09965f069a1c97..ba441ad9a007fc 100644 --- a/drivers/spi/spi-falcon.c +++ b/drivers/spi/spi-falcon.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index d565eeee3bd8dc..5021ddf03f6035 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -406,7 +406,7 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct of_device_id fsl_dspi_dt_ids[] = { +static const struct of_device_id fsl_dspi_dt_ids[] = { { .compatible = "fsl,vf610-dspi", .data = NULL, }, { /* sentinel */ } }; diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index e767f5831b9c7c..3936062c4915b4 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -458,7 +458,7 @@ static int fsl_espi_setup(struct spi_device *spi) return -EINVAL; if (!cs) { - cs = kzalloc(sizeof *cs, GFP_KERNEL); + cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; spi->controller_state = cs; @@ -586,8 +586,10 @@ static struct spi_master * fsl_espi_probe(struct device *dev, struct spi_master *master; struct mpc8xxx_spi *mpc8xxx_spi; struct fsl_espi_reg *reg_base; - u32 regval; - int i, ret = 0; + struct device_node *nc; + const __be32 *prop; + u32 regval, csmode; + int i, len, ret = 0; master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi)); if (!master) { @@ -634,8 +636,32 @@ static struct spi_master * fsl_espi_probe(struct device *dev, mpc8xxx_spi_write_reg(®_base->event, 0xffffffff); /* Init eSPI CS mode register */ - for (i = 0; i < pdata->max_chipselect; i++) - mpc8xxx_spi_write_reg(®_base->csmode[i], CSMODE_INIT_VAL); + for_each_available_child_of_node(master->dev.of_node, nc) { + /* get chip select */ + prop = of_get_property(nc, "reg", &len); + if (!prop || len < sizeof(*prop)) + continue; + i = be32_to_cpup(prop); + if (i < 0 || i >= pdata->max_chipselect) + continue; + + csmode = CSMODE_INIT_VAL; + /* check if CSBEF is set in device tree */ + prop = of_get_property(nc, "fsl,csbef", &len); + if (prop && len >= sizeof(*prop)) { + csmode &= ~(CSMODE_BEF(0xf)); + csmode |= CSMODE_BEF(be32_to_cpup(prop)); + } + /* check if CSAFT is set in device tree */ + prop = of_get_property(nc, "fsl,csaft", &len); + if (prop && len >= sizeof(*prop)) { + csmode &= ~(CSMODE_AFT(0xf)); + csmode |= CSMODE_AFT(be32_to_cpup(prop)); + } + mpc8xxx_spi_write_reg(®_base->csmode[i], csmode); + + dev_info(dev, "cs=%d, init_csmode=0x%x\n", i, csmode); + } /* Enable SPI interface */ regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE; diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index e5d45fca355182..95212ea96c8dc0 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -99,11 +99,6 @@ int mpc8xxx_spi_transfer(struct spi_device *spi, return 0; } -void mpc8xxx_spi_cleanup(struct spi_device *spi) -{ - kfree(spi->controller_state); -} - const char *mpc8xxx_spi_strmode(unsigned int flags) { if (flags & SPI_QE_CPU_MODE) { @@ -134,7 +129,6 @@ int mpc8xxx_spi_probe(struct device *dev, struct resource *mem, | SPI_LSB_FIRST | SPI_LOOP; master->transfer = mpc8xxx_spi_transfer; - master->cleanup = mpc8xxx_spi_cleanup; master->dev.of_node = dev->of_node; mpc8xxx_spi = spi_master_get_devdata(master); diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h index 52db6936778e70..2fcbfd01d10944 100644 --- a/drivers/spi/spi-fsl-lib.h +++ b/drivers/spi/spi-fsl-lib.h @@ -124,7 +124,6 @@ extern struct mpc8xxx_spi_probe_info *to_of_pinfo( extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t, unsigned int len); extern int mpc8xxx_spi_transfer(struct spi_device *spi, struct spi_message *m); -extern void mpc8xxx_spi_cleanup(struct spi_device *spi); extern const char *mpc8xxx_spi_strmode(unsigned int flags); extern int mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq); diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index b3e7775034dbd1..98ccd231bf009b 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -431,7 +431,7 @@ static int fsl_spi_setup(struct spi_device *spi) return -EINVAL; if (!cs) { - cs = kzalloc(sizeof *cs, GFP_KERNEL); + cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; spi->controller_state = cs; diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 09823076df889d..9f595535cf2742 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -340,7 +340,7 @@ static int spi_gpio_request(struct spi_gpio_platform_data *pdata, } #ifdef CONFIG_OF -static struct of_device_id spi_gpio_dt_ids[] = { +static const struct of_device_id spi_gpio_dt_ids[] = { { .compatible = "spi-gpio" }, {} }; diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c index 16e30de650b02a..73e91d5a43dfc2 100644 --- a/drivers/spi/spi-nuc900.c +++ b/drivers/spi/spi-nuc900.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index be2a2e108e2fc2..0f5a0aa3b871d3 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 51d99779682fc1..66d2ae21e78ec1 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1111,10 +1111,8 @@ static int pl022_dma_probe(struct pl022 *pl022) } pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!pl022->dummypage) { - dev_dbg(&pl022->adev->dev, "no DMA dummypage!\n"); + if (!pl022->dummypage) goto err_no_dummypage; - } dev_info(&pl022->adev->dev, "setup for DMA on RX %s, TX %s\n", dma_chan_name(pl022->dma_rx_channel), @@ -1809,11 +1807,8 @@ static int pl022_setup(struct spi_device *spi) if (chip == NULL) { chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); - if (!chip) { - dev_err(&spi->dev, - "cannot allocate controller state\n"); + if (!chip) return -ENOMEM; - } dev_dbg(&spi->dev, "allocated memory for controller's runtime state\n"); } @@ -2050,10 +2045,8 @@ pl022_platform_data_dt_get(struct device *dev) } pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL); - if (!pd) { - dev_err(dev, "cannot allocate platform data memory\n"); + if (!pd) return NULL; - } pd->bus_id = -1; pd->enable_dma = 1; diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 3f006d3ed2a8ba..c1865c92ccb94e 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -8,7 +8,43 @@ #include #include -static int ce4100_spi_probe(struct pci_dev *dev, +enum { + PORT_CE4100, + PORT_BYT, +}; + +struct pxa_spi_info { + enum pxa_ssp_type type; + int port_id; + int num_chipselect; + int tx_slave_id; + int tx_chan_id; + int rx_slave_id; + int rx_chan_id; +}; + +static struct pxa_spi_info spi_info_configs[] = { + [PORT_CE4100] = { + .type = PXA25x_SSP, + .port_id = -1, + .num_chipselect = -1, + .tx_slave_id = -1, + .tx_chan_id = -1, + .rx_slave_id = -1, + .rx_chan_id = -1, + }, + [PORT_BYT] = { + .type = LPSS_SSP, + .port_id = 0, + .num_chipselect = 1, + .tx_slave_id = 0, + .tx_chan_id = 0, + .rx_slave_id = 1, + .rx_chan_id = 1, + }, +}; + +static int pxa2xx_spi_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { struct platform_device_info pi; @@ -16,6 +52,7 @@ static int ce4100_spi_probe(struct pci_dev *dev, struct platform_device *pdev; struct pxa2xx_spi_master spi_pdata; struct ssp_device *ssp; + struct pxa_spi_info *c; ret = pcim_enable_device(dev); if (ret) @@ -25,8 +62,16 @@ static int ce4100_spi_probe(struct pci_dev *dev, if (ret) return ret; + c = &spi_info_configs[ent->driver_data]; + memset(&spi_pdata, 0, sizeof(spi_pdata)); - spi_pdata.num_chipselect = dev->devfn; + spi_pdata.num_chipselect = (c->num_chipselect > 0) ? + c->num_chipselect : dev->devfn; + spi_pdata.tx_slave_id = c->tx_slave_id; + spi_pdata.tx_chan_id = c->tx_chan_id; + spi_pdata.rx_slave_id = c->rx_slave_id; + spi_pdata.rx_chan_id = c->rx_chan_id; + spi_pdata.enable_dma = c->rx_slave_id >= 0 && c->tx_slave_id >= 0; ssp = &spi_pdata.ssp; ssp->phys_base = pci_resource_start(dev, 0); @@ -36,8 +81,8 @@ static int ce4100_spi_probe(struct pci_dev *dev, return -EIO; } ssp->irq = dev->irq; - ssp->port_id = dev->devfn; - ssp->type = PXA25x_SSP; + ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn; + ssp->type = c->type; memset(&pi, 0, sizeof(pi)); pi.parent = &dev->dev; @@ -55,28 +100,29 @@ static int ce4100_spi_probe(struct pci_dev *dev, return 0; } -static void ce4100_spi_remove(struct pci_dev *dev) +static void pxa2xx_spi_pci_remove(struct pci_dev *dev) { struct platform_device *pdev = pci_get_drvdata(dev); platform_device_unregister(pdev); } -static const struct pci_device_id ce4100_spi_devices[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) }, +static const struct pci_device_id pxa2xx_spi_pci_devices[] = { + { PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 }, + { PCI_VDEVICE(INTEL, 0x0f0e), PORT_BYT }, { }, }; -MODULE_DEVICE_TABLE(pci, ce4100_spi_devices); +MODULE_DEVICE_TABLE(pci, pxa2xx_spi_pci_devices); -static struct pci_driver ce4100_spi_driver = { - .name = "ce4100_spi", - .id_table = ce4100_spi_devices, - .probe = ce4100_spi_probe, - .remove = ce4100_spi_remove, +static struct pci_driver pxa2xx_spi_pci_driver = { + .name = "pxa2xx_spi_pci", + .id_table = pxa2xx_spi_pci_devices, + .probe = pxa2xx_spi_pci_probe, + .remove = pxa2xx_spi_pci_remove, }; -module_pci_driver(ce4100_spi_driver); +module_pci_driver(pxa2xx_spi_pci_driver); -MODULE_DESCRIPTION("CE4100 PCI-SPI glue code for PXA's driver"); +MODULE_DESCRIPTION("CE4100/LPSS PCI-SPI glue code for PXA's driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Sebastian Andrzej Siewior "); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 41185d0557fa55..65df9b156a0857 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -886,11 +885,8 @@ static int setup(struct spi_device *spi) chip = spi_get_ctldata(spi); if (!chip) { chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); - if (!chip) { - dev_err(&spi->dev, - "failed setup: can't allocate chip data\n"); + if (!chip) return -ENOMEM; - } if (drv_data->ssp_type == CE4100_SSP) { if (spi->chip_select > 4) { @@ -1037,11 +1033,8 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) return NULL; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(&pdev->dev, - "failed to allocate memory for platform data\n"); + if (!pdata) return NULL; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index b032e8885e2435..9ffdd8539cefd1 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -734,7 +734,7 @@ static int spi_qup_remove(struct platform_device *pdev) int ret; ret = pm_runtime_get_sync(&pdev->dev); - if (ret) + if (ret < 0) return ret; ret = spi_qup_set_state(controller, QUP_STATE_RESET); @@ -749,7 +749,7 @@ static int spi_qup_remove(struct platform_device *pdev) return 0; } -static struct of_device_id spi_qup_dt_match[] = { +static const struct of_device_id spi_qup_dt_match[] = { { .compatible = "qcom,spi-qup-v2.1.1", }, { .compatible = "qcom,spi-qup-v2.2.1", }, { } diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index bed23384dfab58..e713737d784fa0 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include @@ -183,11 +182,11 @@ static int s3c24xx_spi_setup(struct spi_device *spi) /* allocate settings on the first call */ if (!cs) { - cs = kzalloc(sizeof(struct s3c24xx_spi_devstate), GFP_KERNEL); - if (!cs) { - dev_err(&spi->dev, "no memory for controller state\n"); + cs = devm_kzalloc(&spi->dev, + sizeof(struct s3c24xx_spi_devstate), + GFP_KERNEL); + if (!cs) return -ENOMEM; - } cs->spcon = SPCON_DEFAULT; cs->hz = -1; @@ -209,11 +208,6 @@ static int s3c24xx_spi_setup(struct spi_device *spi) return 0; } -static void s3c24xx_spi_cleanup(struct spi_device *spi) -{ - kfree(spi->controller_state); -} - static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count) { return hw->tx ? hw->tx[count] : 0; @@ -543,7 +537,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) hw->bitbang.txrx_bufs = s3c24xx_spi_txrx; hw->master->setup = s3c24xx_spi_setup; - hw->master->cleanup = s3c24xx_spi_cleanup; dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang); diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index f19cd97855e8e7..75a56968b14cfa 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -773,7 +772,6 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( cs = kzalloc(sizeof(*cs), GFP_KERNEL); if (!cs) { - dev_err(&spi->dev, "could not allocate memory for controller data\n"); of_node_put(data_np); return ERR_PTR(-ENOMEM); } @@ -987,10 +985,8 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev) u32 temp; sci = devm_kzalloc(dev, sizeof(*sci), GFP_KERNEL); - if (!sci) { - dev_err(dev, "memory allocation for spi_info failed\n"); + if (!sci) return ERR_PTR(-ENOMEM); - } if (of_property_read_u32(dev->of_node, "samsung,spi-src-clk", &temp)) { dev_warn(dev, "spi bus clock parent not specified, using clock at index 0 as parent\n"); diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index e850d03e719047..45b09142afe2de 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -642,10 +642,8 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) u32 num_cs = 1; info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL); - if (!info) { - dev_err(dev, "failed to allocate setup data\n"); + if (!info) return NULL; - } /* Parse the MSIOF properties */ of_property_read_u32(np, "num-cs", &num_cs); diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 8b44b71f502445..1f56ef651d1a7a 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 67d8909dcf3946..2d238990115c82 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -309,59 +310,51 @@ static void spi_sirfsoc_dma_fini_callback(void *data) complete(dma_complete); } -static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) +static int spi_sirfsoc_cmd_transfer(struct spi_device *spi, + struct spi_transfer *t) { struct sirfsoc_spi *sspi; int timeout = t->len * 10; - sspi = spi_master_get_devdata(spi->master); + u32 cmd; - sspi->tx = t->tx_buf ? t->tx_buf : sspi->dummypage; - sspi->rx = t->rx_buf ? t->rx_buf : sspi->dummypage; - sspi->left_tx_word = sspi->left_rx_word = t->len / sspi->word_width; - reinit_completion(&sspi->rx_done); - reinit_completion(&sspi->tx_done); - - writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); - - /* - * fill tx_buf into command register and wait for its completion - */ - if (sspi->tx_by_cmd) { - u32 cmd; - memcpy(&cmd, sspi->tx, t->len); - - if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST)) - cmd = cpu_to_be32(cmd) >> - ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8); - if (sspi->word_width == 2 && t->len == 4 && - (!(spi->mode & SPI_LSB_FIRST))) - cmd = ((cmd & 0xffff) << 16) | (cmd >> 16); - - writel(cmd, sspi->base + SIRFSOC_SPI_CMD); - writel(SIRFSOC_SPI_FRM_END_INT_EN, - sspi->base + SIRFSOC_SPI_INT_EN); - writel(SIRFSOC_SPI_CMD_TX_EN, - sspi->base + SIRFSOC_SPI_TX_RX_EN); + sspi = spi_master_get_devdata(spi->master); + memcpy(&cmd, sspi->tx, t->len); + if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST)) + cmd = cpu_to_be32(cmd) >> + ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8); + if (sspi->word_width == 2 && t->len == 4 && + (!(spi->mode & SPI_LSB_FIRST))) + cmd = ((cmd & 0xffff) << 16) | (cmd >> 16); + writel(cmd, sspi->base + SIRFSOC_SPI_CMD); + writel(SIRFSOC_SPI_FRM_END_INT_EN, + sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_CMD_TX_EN, + sspi->base + SIRFSOC_SPI_TX_RX_EN); + if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { + dev_err(&spi->dev, "cmd transfer timeout\n"); + return 0; + } - if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { - dev_err(&spi->dev, "transfer timeout\n"); - return 0; - } + return t->len; +} - return t->len; - } +static void spi_sirfsoc_dma_transfer(struct spi_device *spi, + struct spi_transfer *t) +{ + struct sirfsoc_spi *sspi; + struct dma_async_tx_descriptor *rx_desc, *tx_desc; + int timeout = t->len * 10; - if (sspi->left_tx_word == 1) { - writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | - SIRFSOC_SPI_ENA_AUTO_CLR, - sspi->base + SIRFSOC_SPI_CTRL); - writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); - writel(0, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); - } else if ((sspi->left_tx_word > 1) && (sspi->left_tx_word < - SIRFSOC_SPI_DAT_FRM_LEN_MAX)) { + sspi = spi_master_get_devdata(spi->master); + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(0, sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); + if (sspi->left_tx_word < SIRFSOC_SPI_DAT_FRM_LEN_MAX) { writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | - SIRFSOC_SPI_MUL_DAT_MODE | - SIRFSOC_SPI_ENA_AUTO_CLR, + SIRFSOC_SPI_ENA_AUTO_CLR | SIRFSOC_SPI_MUL_DAT_MODE, sspi->base + SIRFSOC_SPI_CTRL); writel(sspi->left_tx_word - 1, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); @@ -373,76 +366,109 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); writel(0, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); } - - writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); - writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); - writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); - writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); - - if (IS_DMA_VALID(t)) { - struct dma_async_tx_descriptor *rx_desc, *tx_desc; - - sspi->dst_start = dma_map_single(&spi->dev, sspi->rx, t->len, DMA_FROM_DEVICE); - rx_desc = dmaengine_prep_slave_single(sspi->rx_chan, - sspi->dst_start, t->len, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - rx_desc->callback = spi_sirfsoc_dma_fini_callback; - rx_desc->callback_param = &sspi->rx_done; - - sspi->src_start = dma_map_single(&spi->dev, (void *)sspi->tx, t->len, DMA_TO_DEVICE); - tx_desc = dmaengine_prep_slave_single(sspi->tx_chan, - sspi->src_start, t->len, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - tx_desc->callback = spi_sirfsoc_dma_fini_callback; - tx_desc->callback_param = &sspi->tx_done; - - dmaengine_submit(tx_desc); - dmaengine_submit(rx_desc); - dma_async_issue_pending(sspi->tx_chan); - dma_async_issue_pending(sspi->rx_chan); - } else { - /* Send the first word to trigger the whole tx/rx process */ - sspi->tx_word(sspi); - - writel(SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN | - SIRFSOC_SPI_RXFIFO_THD_INT_EN | SIRFSOC_SPI_TXFIFO_THD_INT_EN | - SIRFSOC_SPI_FRM_END_INT_EN | SIRFSOC_SPI_RXFIFO_FULL_INT_EN | - SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN, sspi->base + SIRFSOC_SPI_INT_EN); - } - - writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, sspi->base + SIRFSOC_SPI_TX_RX_EN); - - if (!IS_DMA_VALID(t)) { /* for PIO */ - if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) - dev_err(&spi->dev, "transfer timeout\n"); - } else if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) { + sspi->dst_start = dma_map_single(&spi->dev, sspi->rx, t->len, + (t->tx_buf != t->rx_buf) ? + DMA_FROM_DEVICE : DMA_BIDIRECTIONAL); + rx_desc = dmaengine_prep_slave_single(sspi->rx_chan, + sspi->dst_start, t->len, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + rx_desc->callback = spi_sirfsoc_dma_fini_callback; + rx_desc->callback_param = &sspi->rx_done; + + sspi->src_start = dma_map_single(&spi->dev, (void *)sspi->tx, t->len, + (t->tx_buf != t->rx_buf) ? + DMA_TO_DEVICE : DMA_BIDIRECTIONAL); + tx_desc = dmaengine_prep_slave_single(sspi->tx_chan, + sspi->src_start, t->len, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + tx_desc->callback = spi_sirfsoc_dma_fini_callback; + tx_desc->callback_param = &sspi->tx_done; + + dmaengine_submit(tx_desc); + dmaengine_submit(rx_desc); + dma_async_issue_pending(sspi->tx_chan); + dma_async_issue_pending(sspi->rx_chan); + writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, + sspi->base + SIRFSOC_SPI_TX_RX_EN); + if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) { dev_err(&spi->dev, "transfer timeout\n"); dmaengine_terminate_all(sspi->rx_chan); } else sspi->left_rx_word = 0; - /* * we only wait tx-done event if transferring by DMA. for PIO, * we get rx data by writing tx data, so if rx is done, tx has * done earlier */ - if (IS_DMA_VALID(t)) { - if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { - dev_err(&spi->dev, "transfer timeout\n"); - dmaengine_terminate_all(sspi->tx_chan); - } + if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { + dev_err(&spi->dev, "transfer timeout\n"); + dmaengine_terminate_all(sspi->tx_chan); } + dma_unmap_single(&spi->dev, sspi->src_start, t->len, DMA_TO_DEVICE); + dma_unmap_single(&spi->dev, sspi->dst_start, t->len, DMA_FROM_DEVICE); + /* TX, RX FIFO stop */ + writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + if (sspi->left_tx_word >= SIRFSOC_SPI_DAT_FRM_LEN_MAX) + writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN); +} - if (IS_DMA_VALID(t)) { - dma_unmap_single(&spi->dev, sspi->src_start, t->len, DMA_TO_DEVICE); - dma_unmap_single(&spi->dev, sspi->dst_start, t->len, DMA_FROM_DEVICE); - } +static void spi_sirfsoc_pio_transfer(struct spi_device *spi, + struct spi_transfer *t) +{ + struct sirfsoc_spi *sspi; + int timeout = t->len * 10; - /* TX, RX FIFO stop */ + sspi = spi_master_get_devdata(spi->master); + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(0, sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); + writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | SIRFSOC_SPI_MUL_DAT_MODE | + SIRFSOC_SPI_ENA_AUTO_CLR, sspi->base + SIRFSOC_SPI_CTRL); + writel(sspi->left_tx_word - 1, + sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); + writel(sspi->left_rx_word - 1, + sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); + sspi->tx_word(sspi); + writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN | + SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_RXFIFO_THD_INT_EN | + SIRFSOC_SPI_TXFIFO_THD_INT_EN | SIRFSOC_SPI_FRM_END_INT_EN| + SIRFSOC_SPI_RXFIFO_FULL_INT_EN, + sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, + sspi->base + SIRFSOC_SPI_TX_RX_EN); + if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) + dev_err(&spi->dev, "transfer timeout\n"); writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP); writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP); writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN); writel(0, sspi->base + SIRFSOC_SPI_INT_EN); +} + +static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) +{ + struct sirfsoc_spi *sspi; + sspi = spi_master_get_devdata(spi->master); + + sspi->tx = t->tx_buf ? t->tx_buf : sspi->dummypage; + sspi->rx = t->rx_buf ? t->rx_buf : sspi->dummypage; + sspi->left_tx_word = sspi->left_rx_word = t->len / sspi->word_width; + reinit_completion(&sspi->rx_done); + reinit_completion(&sspi->tx_done); + /* + * in the transfer, if transfer data using command register with rx_buf + * null, just fill command data into command register and wait for its + * completion. + */ + if (sspi->tx_by_cmd) + spi_sirfsoc_cmd_transfer(spi, t); + else if (IS_DMA_VALID(t)) + spi_sirfsoc_dma_transfer(spi, t); + else + spi_sirfsoc_pio_transfer(spi, t); return t->len - sspi->left_rx_word * sspi->word_width; } @@ -512,7 +538,8 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) break; case 12: case 16: - regval |= (bits_per_word == 12) ? SIRFSOC_SPI_TRAN_DAT_FORMAT_12 : + regval |= (bits_per_word == 12) ? + SIRFSOC_SPI_TRAN_DAT_FORMAT_12 : SIRFSOC_SPI_TRAN_DAT_FORMAT_16; sspi->rx_word = spi_sirfsoc_rx_word_u16; sspi->tx_word = spi_sirfsoc_tx_word_u16; @@ -540,8 +567,8 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) regval |= SIRFSOC_SPI_CLK_IDLE_STAT; /* - * Data should be driven at least 1/2 cycle before the fetch edge to make - * sure that data gets stable at the fetch edge. + * Data should be driven at least 1/2 cycle before the fetch edge + * to make sure that data gets stable at the fetch edge. */ if (((spi->mode & SPI_CPOL) && (spi->mode & SPI_CPHA)) || (!(spi->mode & SPI_CPOL) && !(spi->mode & SPI_CPHA))) @@ -578,11 +605,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) if (IS_DMA_VALID(t)) { /* Enable DMA mode for RX, TX */ writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL); - writel(SIRFSOC_SPI_RX_DMA_FLUSH, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL); + writel(SIRFSOC_SPI_RX_DMA_FLUSH, + sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL); } else { /* Enable IO mode for RX, TX */ - writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL); - writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL); + writel(SIRFSOC_SPI_IO_MODE_SEL, + sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL); + writel(SIRFSOC_SPI_IO_MODE_SEL, + sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL); } return 0; @@ -612,7 +642,8 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) goto err_cs; } - master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs); + master = spi_alloc_master(&pdev->dev, + sizeof(*sspi) + sizeof(int) * num_cs); if (!master) { dev_err(&pdev->dev, "Unable to allocate SPI master\n"); return -ENOMEM; @@ -808,8 +839,7 @@ static struct platform_driver spi_sirfsoc_driver = { .remove = spi_sirfsoc_remove, }; module_platform_driver(spi_sirfsoc_driver); - MODULE_DESCRIPTION("SiRF SoC SPI master driver"); -MODULE_AUTHOR("Zhiwu Song , " - "Barry Song "); +MODULE_AUTHOR("Zhiwu Song "); +MODULE_AUTHOR("Barry Song "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index d266a8702067d2..85204c93f3d34b 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -19,7 +19,6 @@ #include #include #include -#include #include diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index b3e3498a7e6f92..bd24093f403864 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -20,7 +20,6 @@ #include #include #include -#include #include diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 400649595505e8..e4a85ada861d0a 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1012,7 +1012,7 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data) return IRQ_WAKE_THREAD; } -static struct of_device_id tegra_spi_of_match[] = { +static const struct of_device_id tegra_spi_of_match[] = { { .compatible = "nvidia,tegra114-spi", }, {} }; diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 47869ea636e161..3548ce25c08fbe 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -419,7 +419,7 @@ static irqreturn_t tegra_sflash_isr(int irq, void *context_data) return handle_cpu_based_xfer(tsd); } -static struct of_device_id tegra_sflash_of_match[] = { +static const struct of_device_id tegra_sflash_of_match[] = { { .compatible = "nvidia,tegra20-sflash", }, {} }; diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index e3c1b93e45d19a..0b9e32e9f493fe 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1001,7 +1001,7 @@ static const struct tegra_slink_chip_data tegra20_spi_cdata = { .cs_hold_time = false, }; -static struct of_device_id tegra_slink_of_match[] = { +static const struct of_device_id tegra_slink_of_match[] = { { .compatible = "nvidia,tegra30-slink", .data = &tegra30_spi_cdata, }, { .compatible = "nvidia,tegra20-slink", .data = &tegra20_spi_cdata, }, {} diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c index 2d4010d80824a1..daf5aa1c24c385 100644 --- a/drivers/spi/spi-tle62x0.c +++ b/drivers/spi/spi-tle62x0.c @@ -253,10 +253,8 @@ static int tle62x0_probe(struct spi_device *spi) } st = kzalloc(sizeof(struct tle62x0_state), GFP_KERNEL); - if (st == NULL) { - dev_err(&spi->dev, "no memory for device state\n"); + if (st == NULL) return -ENOMEM; - } st->us = spi; st->nr_gpio = pdata->gpio_count; diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index f406b30af961fd..f05abf89c06721 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1578,14 +1578,11 @@ static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct pch_pd_dev_save *pd_dev_save; pd_dev_save = kzalloc(sizeof(struct pch_pd_dev_save), GFP_KERNEL); - if (!pd_dev_save) { - dev_err(&pdev->dev, "%s Can't allocate pd_dev_sav\n", __func__); + if (!pd_dev_save) return -ENOMEM; - } board_dat = kzalloc(sizeof(struct pch_spi_board_data), GFP_KERNEL); if (!board_dat) { - dev_err(&pdev->dev, "%s Can't allocate board_dat\n", __func__); retval = -ENOMEM; goto err_no_mem; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 4eb9bf02996cf1..074f55f5d5ecc6 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -580,6 +580,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable) spi->master->set_cs(spi, !enable); } +#ifdef CONFIG_HAS_DMA static int spi_map_buf(struct spi_master *master, struct device *dev, struct sg_table *sgt, void *buf, size_t len, enum dma_data_direction dir) @@ -637,55 +638,12 @@ static void spi_unmap_buf(struct spi_master *master, struct device *dev, } } -static int spi_map_msg(struct spi_master *master, struct spi_message *msg) +static int __spi_map_msg(struct spi_master *master, struct spi_message *msg) { struct device *tx_dev, *rx_dev; struct spi_transfer *xfer; - void *tmp; - unsigned int max_tx, max_rx; int ret; - if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) { - max_tx = 0; - max_rx = 0; - - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - if ((master->flags & SPI_MASTER_MUST_TX) && - !xfer->tx_buf) - max_tx = max(xfer->len, max_tx); - if ((master->flags & SPI_MASTER_MUST_RX) && - !xfer->rx_buf) - max_rx = max(xfer->len, max_rx); - } - - if (max_tx) { - tmp = krealloc(master->dummy_tx, max_tx, - GFP_KERNEL | GFP_DMA); - if (!tmp) - return -ENOMEM; - master->dummy_tx = tmp; - memset(tmp, 0, max_tx); - } - - if (max_rx) { - tmp = krealloc(master->dummy_rx, max_rx, - GFP_KERNEL | GFP_DMA); - if (!tmp) - return -ENOMEM; - master->dummy_rx = tmp; - } - - if (max_tx || max_rx) { - list_for_each_entry(xfer, &msg->transfers, - transfer_list) { - if (!xfer->tx_buf) - xfer->tx_buf = master->dummy_tx; - if (!xfer->rx_buf) - xfer->rx_buf = master->dummy_rx; - } - } - } - if (!master->can_dma) return 0; @@ -742,6 +700,69 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg) return 0; } +#else /* !CONFIG_HAS_DMA */ +static inline int __spi_map_msg(struct spi_master *master, + struct spi_message *msg) +{ + return 0; +} + +static inline int spi_unmap_msg(struct spi_master *master, + struct spi_message *msg) +{ + return 0; +} +#endif /* !CONFIG_HAS_DMA */ + +static int spi_map_msg(struct spi_master *master, struct spi_message *msg) +{ + struct spi_transfer *xfer; + void *tmp; + unsigned int max_tx, max_rx; + + if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) { + max_tx = 0; + max_rx = 0; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if ((master->flags & SPI_MASTER_MUST_TX) && + !xfer->tx_buf) + max_tx = max(xfer->len, max_tx); + if ((master->flags & SPI_MASTER_MUST_RX) && + !xfer->rx_buf) + max_rx = max(xfer->len, max_rx); + } + + if (max_tx) { + tmp = krealloc(master->dummy_tx, max_tx, + GFP_KERNEL | GFP_DMA); + if (!tmp) + return -ENOMEM; + master->dummy_tx = tmp; + memset(tmp, 0, max_tx); + } + + if (max_rx) { + tmp = krealloc(master->dummy_rx, max_rx, + GFP_KERNEL | GFP_DMA); + if (!tmp) + return -ENOMEM; + master->dummy_rx = tmp; + } + + if (max_tx || max_rx) { + list_for_each_entry(xfer, &msg->transfers, + transfer_list) { + if (!xfer->tx_buf) + xfer->tx_buf = master->dummy_tx; + if (!xfer->rx_buf) + xfer->rx_buf = master->dummy_rx; + } + } + } + + return __spi_map_msg(master, msg); +} /* * spi_transfer_one_message - Default implementation of transfer_one_message() @@ -775,7 +796,7 @@ static int spi_transfer_one_message(struct spi_master *master, if (ret > 0) { ret = 0; ms = xfer->len * 8 * 1000 / xfer->speed_hz; - ms += 10; /* some tolerance */ + ms += ms + 100; /* some tolerance */ ms = wait_for_completion_timeout(&master->xfer_completion, msecs_to_jiffies(ms)); @@ -1151,7 +1172,6 @@ static int spi_master_initialize_queue(struct spi_master *master) { int ret; - master->queued = true; master->transfer = spi_queued_transfer; if (!master->transfer_one_message) master->transfer_one_message = spi_transfer_one_message; @@ -1162,6 +1182,7 @@ static int spi_master_initialize_queue(struct spi_master *master) dev_err(&master->dev, "problem initializing queue\n"); goto err_init_queue; } + master->queued = true; ret = spi_start_queue(master); if (ret) { dev_err(&master->dev, "problem starting queue\n"); @@ -1171,8 +1192,8 @@ static int spi_master_initialize_queue(struct spi_master *master) return 0; err_start_queue: -err_init_queue: spi_destroy_queue(master); +err_init_queue: return ret; } @@ -1234,6 +1255,8 @@ static void of_register_spi_devices(struct spi_master *master) spi->mode |= SPI_CS_HIGH; if (of_find_property(nc, "spi-3wire", NULL)) spi->mode |= SPI_3WIRE; + if (of_find_property(nc, "spi-lsb-first", NULL)) + spi->mode |= SPI_LSB_FIRST; /* Device DUAL/QUAD mode */ if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) { @@ -1756,7 +1779,7 @@ EXPORT_SYMBOL_GPL(spi_busnum_to_master); */ int spi_setup(struct spi_device *spi) { - unsigned bad_bits; + unsigned bad_bits, ugly_bits; int status = 0; /* check mode to prevent that DUAL and QUAD set at the same time @@ -1776,6 +1799,15 @@ int spi_setup(struct spi_device *spi) * that aren't supported with their current master */ bad_bits = spi->mode & ~spi->master->mode_bits; + ugly_bits = bad_bits & + (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD); + if (ugly_bits) { + dev_warn(&spi->dev, + "setup: ignoring unsupported mode bits %x\n", + ugly_bits); + spi->mode &= ~ugly_bits; + bad_bits &= ~ugly_bits; + } if (bad_bits) { dev_err(&spi->dev, "setup: unsupported mode bits %x\n", bad_bits); diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 22365f140bec3d..0c3887778f38b9 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -90,8 +90,6 @@ source "drivers/staging/tidspbridge/Kconfig" source "drivers/staging/quickstart/Kconfig" -source "drivers/staging/sbe-2t3e3/Kconfig" - source "drivers/staging/keucr/Kconfig" source "drivers/staging/bcm/Kconfig" @@ -144,6 +142,8 @@ source "drivers/staging/gs_fpgaboot/Kconfig" source "drivers/staging/nokia_h4p/Kconfig" +source "drivers/staging/skein/Kconfig" + source "drivers/staging/unisys/Kconfig" endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index fbe84ed2d048e4..7bf91a6160668c 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -39,7 +39,6 @@ obj-$(CONFIG_CXT1E1) += cxt1e1/ obj-$(CONFIG_FB_XGI) += xgifb/ obj-$(CONFIG_TIDSPBRIDGE) += tidspbridge/ obj-$(CONFIG_ACPI_QUICKSTART) += quickstart/ -obj-$(CONFIG_SBE_2T3E3) += sbe-2t3e3/ obj-$(CONFIG_USB_ENESTORAGE) += keucr/ obj-$(CONFIG_BCM_WIMAX) += bcm/ obj-$(CONFIG_FT1000) += ft1000/ @@ -64,4 +63,5 @@ obj-$(CONFIG_DGAP) += dgap/ obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/ obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/ obj-$(CONFIG_BT_NOKIA_H4P) += nokia_h4p/ +obj-$(CONFIG_CRYPTO_SKEIN) += skein/ obj-$(CONFIG_UNISYSSPAR) += unisys/ diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c index 2fc7cdd4c4e3b5..f200e8a843258b 100644 --- a/drivers/staging/android/alarm-dev.c +++ b/drivers/staging/android/alarm-dev.c @@ -329,6 +329,7 @@ static int alarm_release(struct inode *inode, struct file *file) if (file->private_data) { for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) { uint32_t alarm_type_mask = 1U << i; + if (alarm_enabled & alarm_type_mask) { alarm_dbg(INFO, "%s: clear alarm, pending %d\n", diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index cfe4bc8f05cb82..3a4394f3d8d0c8 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -118,6 +118,7 @@ static int binder_set_stop_on_user_error(const char *val, struct kernel_param *kp) { int ret; + ret = param_set_int(val, kp); if (binder_stop_on_user_error < 2) wake_up(&binder_user_error_wait); @@ -194,6 +195,7 @@ static struct binder_transaction_log_entry *binder_transaction_log_add( struct binder_transaction_log *log) { struct binder_transaction_log_entry *e; + e = &log->entry[log->next]; memset(e, 0, sizeof(*e)); log->next++; @@ -432,6 +434,7 @@ static inline void binder_unlock(const char *tag) static void binder_set_nice(long nice) { long min_nice; + if (can_nice(current, nice)) { set_user_nice(current, nice); return; @@ -441,7 +444,7 @@ static void binder_set_nice(long nice) "%d: nice value %ld not allowed use %ld instead\n", current->pid, nice, min_nice); set_user_nice(current, min_nice); - if (min_nice < 20) + if (min_nice <= MAX_NICE) return; binder_user_error("%d RLIMIT_NICE not set\n", current->pid); } @@ -584,6 +587,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { int ret; struct page **page_array_ptr; + page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; BUG_ON(*page); @@ -726,6 +730,7 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, binder_insert_allocated_buffer(proc, buffer); if (buffer_size != size) { struct binder_buffer *new_buffer = (void *)buffer->data + size; + list_add(&new_buffer->entry, &buffer->entry); new_buffer->free = 1; binder_insert_free_buffer(proc, new_buffer); @@ -838,6 +843,7 @@ static void binder_free_buf(struct binder_proc *proc, if (!list_is_last(&buffer->entry, &proc->buffers)) { struct binder_buffer *next = list_entry(buffer->entry.next, struct binder_buffer, entry); + if (next->free) { rb_erase(&next->rb_node, &proc->free_buffers); binder_delete_free_buffer(proc, next); @@ -846,6 +852,7 @@ static void binder_free_buf(struct binder_proc *proc, if (proc->buffers.next != &buffer->entry) { struct binder_buffer *prev = list_entry(buffer->entry.prev, struct binder_buffer, entry); + if (prev->free) { binder_delete_free_buffer(proc, buffer); rb_erase(&prev->rb_node, &proc->free_buffers); @@ -1107,6 +1114,7 @@ static int binder_inc_ref(struct binder_ref *ref, int strong, struct list_head *target_list) { int ret; + if (strong) { if (ref->strong == 0) { ret = binder_inc_node(ref->node, 1, 1, target_list); @@ -1138,6 +1146,7 @@ static int binder_dec_ref(struct binder_ref *ref, int strong) ref->strong--; if (ref->strong == 0) { int ret; + ret = binder_dec_node(ref->node, strong, 1); if (ret) return ret; @@ -1177,6 +1186,7 @@ static void binder_send_failed_reply(struct binder_transaction *t, uint32_t error_code) { struct binder_thread *target_thread; + BUG_ON(t->flags & TF_ONE_WAY); while (1) { target_thread = t->from; @@ -1247,6 +1257,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, off_end = (void *)offp + buffer->offsets_size; for (; offp < off_end; offp++) { struct flat_binder_object *fp; + if (*offp > buffer->data_size - sizeof(*fp) || buffer->data_size < sizeof(*fp) || !IS_ALIGNED(*offp, sizeof(u32))) { @@ -1259,6 +1270,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, case BINDER_TYPE_BINDER: case BINDER_TYPE_WEAK_BINDER: { struct binder_node *node = binder_get_node(proc, fp->binder); + if (node == NULL) { pr_err("transaction release %d bad node %016llx\n", debug_id, (u64)fp->binder); @@ -1272,6 +1284,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { struct binder_ref *ref = binder_get_ref(proc, fp->handle); + if (ref == NULL) { pr_err("transaction release %d bad handle %d\n", debug_id, fp->handle); @@ -1363,6 +1376,7 @@ static void binder_transaction(struct binder_proc *proc, } else { if (tr->target.handle) { struct binder_ref *ref; + ref = binder_get_ref(proc, tr->target.handle); if (ref == NULL) { binder_user_error("%d:%d got transaction to invalid handle\n", @@ -1386,6 +1400,7 @@ static void binder_transaction(struct binder_proc *proc, } if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; + tmp = thread->transaction_stack; if (tmp->to_thread != thread) { binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n", @@ -1501,6 +1516,7 @@ static void binder_transaction(struct binder_proc *proc, off_end = (void *)offp + tr->offsets_size; for (; offp < off_end; offp++) { struct flat_binder_object *fp; + if (*offp > t->buffer->data_size - sizeof(*fp) || t->buffer->data_size < sizeof(*fp) || !IS_ALIGNED(*offp, sizeof(u32))) { @@ -1515,6 +1531,7 @@ static void binder_transaction(struct binder_proc *proc, case BINDER_TYPE_WEAK_BINDER: { struct binder_ref *ref; struct binder_node *node = binder_get_node(proc, fp->binder); + if (node == NULL) { node = binder_new_node(proc, fp->binder, fp->cookie); if (node == NULL) { @@ -1553,6 +1570,7 @@ static void binder_transaction(struct binder_proc *proc, case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { struct binder_ref *ref = binder_get_ref(proc, fp->handle); + if (ref == NULL) { binder_user_error("%d:%d got transaction with invalid handle, %d\n", proc->pid, @@ -1575,6 +1593,7 @@ static void binder_transaction(struct binder_proc *proc, (u64)ref->node->ptr); } else { struct binder_ref *new_ref; + new_ref = binder_get_ref_for_node(target_proc, ref->node); if (new_ref == NULL) { return_error = BR_FAILED_REPLY; @@ -1694,6 +1713,7 @@ static void binder_transaction(struct binder_proc *proc, { struct binder_transaction_log_entry *fe; + fe = binder_transaction_log_add(&binder_transaction_log_failed); *fe = *e; } @@ -2024,12 +2044,14 @@ static int binder_thread_write(struct binder_proc *proc, struct binder_work *w; binder_uintptr_t cookie; struct binder_ref_death *death = NULL; + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(void *); list_for_each_entry(w, &proc->delivered_death, entry) { struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work); + if (tmp_death->cookie == cookie) { death = tmp_death; break; @@ -2216,6 +2238,7 @@ static int binder_thread_read(struct binder_proc *proc, const char *cmd_name; int strong = node->internal_strong_refs || node->local_strong_refs; int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong; + if (weak && !node->has_weak_ref) { cmd = BR_INCREFS; cmd_name = "BR_INCREFS"; @@ -2322,6 +2345,7 @@ static int binder_thread_read(struct binder_proc *proc, BUG_ON(t->buffer == NULL); if (t->buffer->target_node) { struct binder_node *target_node = t->buffer->target_node; + tr.target.ptr = target_node->ptr; tr.cookie = target_node->cookie; t->saved_priority = task_nice(current); @@ -2343,6 +2367,7 @@ static int binder_thread_read(struct binder_proc *proc, if (t->from) { struct task_struct *sender = t->from->proc->tsk; + tr.sender_pid = task_tgid_nr_ns(sender, task_active_pid_ns(current)); } else { @@ -2413,6 +2438,7 @@ static int binder_thread_read(struct binder_proc *proc, static void binder_release_work(struct list_head *list) { struct binder_work *w; + while (!list_empty(list)) { w = list_first_entry(list, struct binder_work, entry); list_del_init(&w->entry); @@ -2593,6 +2619,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) switch (cmd) { case BINDER_WRITE_READ: { struct binder_write_read bwr; + if (size != sizeof(struct binder_write_read)) { ret = -EINVAL; goto err; @@ -2683,16 +2710,20 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) binder_free_thread(proc, thread); thread = NULL; break; - case BINDER_VERSION: + case BINDER_VERSION: { + struct binder_version __user *ver = ubuf; + if (size != sizeof(struct binder_version)) { ret = -EINVAL; goto err; } - if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) { + if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, + &ver->protocol_version)) { ret = -EINVAL; goto err; } break; + } default: ret = -EINVAL; goto err; @@ -2713,6 +2744,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) static void binder_vma_open(struct vm_area_struct *vma) { struct binder_proc *proc = vma->vm_private_data; + binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%d open vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, @@ -2723,6 +2755,7 @@ static void binder_vma_open(struct vm_area_struct *vma) static void binder_vma_close(struct vm_area_struct *vma) { struct binder_proc *proc = vma->vm_private_data; + binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%d close vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, @@ -2865,6 +2898,7 @@ static int binder_open(struct inode *nodp, struct file *filp) if (binder_debugfs_dir_entry_proc) { char strbuf[11]; + snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO, binder_debugfs_dir_entry_proc, proc, &binder_proc_fops); @@ -2886,8 +2920,10 @@ static void binder_deferred_flush(struct binder_proc *proc) { struct rb_node *n; int wake_count = 0; + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); + thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; if (thread->looper & BINDER_LOOPER_STATE_WAITING) { wake_up_interruptible(&thread->wait); @@ -2904,6 +2940,7 @@ static void binder_deferred_flush(struct binder_proc *proc) static int binder_release(struct inode *nodp, struct file *filp) { struct binder_proc *proc = filp->private_data; + debugfs_remove(proc->debugfs_entry); binder_defer_work(proc, BINDER_DEFERRED_RELEASE); @@ -3065,6 +3102,7 @@ static void binder_deferred_func(struct work_struct *work) struct files_struct *files; int defer; + do { binder_lock(__func__); mutex_lock(&binder_deferred_lock); diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 3d5bf1472236c1..ea2c8a9addb58f 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -408,6 +408,7 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client, while (n) { struct ion_handle *entry = rb_entry(n, struct ion_handle, node); + if (buffer < entry->buffer) n = n->rb_left; else if (buffer > entry->buffer) @@ -720,9 +721,11 @@ static int ion_get_client_serial(const struct rb_root *root, { int serial = -1; struct rb_node *node; + for (node = rb_first(root); node; node = rb_next(node)) { struct ion_client *client = rb_entry(node, struct ion_client, node); + if (strcmp(client->name, name)) continue; serial = max(serial, client->display_serial); @@ -1035,12 +1038,14 @@ static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) static void ion_dma_buf_release(struct dma_buf *dmabuf) { struct ion_buffer *buffer = dmabuf->priv; + ion_buffer_put(buffer); } static void *ion_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset) { struct ion_buffer *buffer = dmabuf->priv; + return buffer->vaddr + offset * PAGE_SIZE; } @@ -1292,6 +1297,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case ION_IOC_IMPORT: { struct ion_handle *handle; + handle = ion_import_dma_buf(client, data.fd.fd); if (IS_ERR(handle)) ret = PTR_ERR(handle); @@ -1393,6 +1399,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) struct ion_client *client = rb_entry(n, struct ion_client, node); size_t size = ion_debug_heap_total(client, heap->id); + if (!size) continue; if (client->task) { @@ -1516,6 +1523,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) if (!debug_file) { char buf[256], *path; + path = dentry_path(dev->heaps_debug_root, buf, 256); pr_err("Failed to create heap debugfs at %s/%s\n", path, heap->name); @@ -1531,6 +1539,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) &debug_shrink_fops); if (!debug_file) { char buf[256], *path; + path = dentry_path(dev->heaps_debug_root, buf, 256); pr_err("Failed to create heap shrinker debugfs at %s/%s\n", path, debug_name); @@ -1606,6 +1615,7 @@ void __init ion_reserve(struct ion_platform_data *data) if (data->heaps[i].base == 0) { phys_addr_t paddr; + paddr = memblock_alloc_base(data->heaps[i].size, data->heaps[i].align, MEMBLOCK_ALLOC_ANYWHERE); diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c index 3cb05b9b0e93dd..dcb6f2196c8742 100644 --- a/drivers/staging/android/ion/ion_carveout_heap.c +++ b/drivers/staging/android/ion/ion_carveout_heap.c @@ -81,7 +81,7 @@ static int ion_carveout_heap_allocate(struct ion_heap *heap, if (align > PAGE_SIZE) return -EINVAL; - table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); if (!table) return -ENOMEM; ret = sg_alloc_table(table, 1, GFP_KERNEL); diff --git a/drivers/staging/android/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c index d40f5f831808aa..3f2c12ba4d149a 100644 --- a/drivers/staging/android/ion/ion_chunk_heap.c +++ b/drivers/staging/android/ion/ion_chunk_heap.c @@ -55,7 +55,7 @@ static int ion_chunk_heap_allocate(struct ion_heap *heap, if (allocated_size > chunk_heap->size - chunk_heap->allocated) return -ENOMEM; - table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); if (!table) return -ENOMEM; ret = sg_alloc_table(table, num_chunks, GFP_KERNEL); diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index bdc6a28ba8c9bd..4605e04712aaea 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -48,6 +48,7 @@ void *ion_heap_map_kernel(struct ion_heap *heap, for_each_sg(table->sgl, sg, table->nents, i) { int npages_this_entry = PAGE_ALIGN(sg->length) / PAGE_SIZE; struct page *page = sg_page(sg); + BUG_ON(i >= npages); for (j = 0; j < npages_this_entry; j++) *(tmp++) = page++; @@ -105,6 +106,7 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, static int ion_heap_clear_pages(struct page **pages, int num, pgprot_t pgprot) { void *addr = vm_map_ram(pages, num, -1, pgprot); + if (!addr) return -ENOMEM; memset(addr, 0, PAGE_SIZE * num); diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index 1eba3f2076a9c1..c2dc942418bfc7 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -178,6 +178,7 @@ struct ion_heap { spinlock_t free_lock; wait_queue_head_t waitqueue; struct task_struct *task; + int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *); }; diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index c92363356ae142..a14499514eb685 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -34,6 +34,7 @@ static const int num_orders = ARRAY_SIZE(orders); static int order_to_index(unsigned int order) { int i; + for (i = 0; i < num_orders; i++) if (order == orders[i]) return i; @@ -92,6 +93,7 @@ static void free_buffer_page(struct ion_system_heap *heap, if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) { struct ion_page_pool *pool = heap->pools[order_to_index(order)]; + ion_page_pool_free(pool, page); } else { __free_pages(page, order); @@ -166,7 +168,7 @@ static int ion_system_heap_allocate(struct ion_heap *heap, max_order = info->order; i++; } - table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); if (!table) goto err; @@ -242,6 +244,7 @@ static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, for (i = 0; i < num_orders; i++) { struct ion_page_pool *pool = sys_heap->pools[i]; + nr_total += ion_page_pool_shrink(pool, gfp_mask, nr_to_scan); } @@ -267,8 +270,10 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, struct ion_system_heap, heap); int i; + for (i = 0; i < num_orders; i++) { struct ion_page_pool *pool = sys_heap->pools[i]; + seq_printf(s, "%d order %u highmem pages in pool = %lu total\n", pool->high_count, pool->order, (1 << pool->order) * PAGE_SIZE * pool->high_count); @@ -356,7 +361,7 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap, for (i = len >> PAGE_SHIFT; i < (1 << order); i++) __free_page(page + i); - table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); if (!table) { ret = -ENOMEM; goto out; diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c index d42f5785f09833..2772e01b37f50e 100644 --- a/drivers/staging/android/logger.c +++ b/drivers/staging/android/logger.c @@ -108,6 +108,7 @@ static inline struct logger_log *file_get_log(struct file *file) { if (file->f_mode & FMODE_READ) { struct logger_reader *reader = file->private_data; + return reader->log; } else return file->private_data; @@ -124,6 +125,7 @@ static struct logger_entry *get_entry_header(struct logger_log *log, size_t off, struct logger_entry *scratch) { size_t len = min(sizeof(struct logger_entry), log->size - off); + if (len != sizeof(struct logger_entry)) { memcpy(((void *) scratch), log->buffer + off, len); memcpy(((void *) scratch) + len, log->buffer, @@ -642,6 +644,7 @@ static unsigned int logger_poll(struct file *file, poll_table *wait) static long logger_set_version(struct logger_reader *reader, void __user *arg) { int version; + if (copy_from_user(&version, arg, sizeof(int))) return -EFAULT; diff --git a/drivers/staging/android/ram_console.h b/drivers/staging/android/ram_console.h deleted file mode 100644 index 9f1125c110660b..00000000000000 --- a/drivers/staging/android/ram_console.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2010 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -#ifndef _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ -#define _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ - -struct ram_console_platform_data { - const char *bootinfo; -}; - -#endif /* _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ */ diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c index f24493ac65e3e6..12a136ec1ceca8 100644 --- a/drivers/staging/android/sw_sync.c +++ b/drivers/staging/android/sw_sync.c @@ -97,6 +97,7 @@ static void sw_sync_pt_value_str(struct sync_pt *sync_pt, char *str, int size) { struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt; + snprintf(str, size, "%d", pt->value); } @@ -156,6 +157,7 @@ static int sw_sync_open(struct inode *inode, struct file *file) static int sw_sync_release(struct inode *inode, struct file *file) { struct sw_sync_timeline *obj = file->private_data; + sync_timeline_destroy(&obj->obj); return 0; } diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index 3d05f662110bb0..1f88c5d0f0c7a8 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -384,6 +384,7 @@ static void sync_fence_detach_pts(struct sync_fence *fence) list_for_each_safe(pos, n, &fence->pt_list_head) { struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list); + sync_timeline_remove_pt(pt); } } @@ -394,6 +395,7 @@ static void sync_fence_free_pts(struct sync_fence *fence) list_for_each_safe(pos, n, &fence->pt_list_head) { struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list); + sync_pt_free(pt); } } @@ -827,6 +829,7 @@ static long sync_fence_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct sync_fence *fence = file->private_data; + switch (cmd) { case SYNC_IOC_WAIT: return sync_fence_ioctl_wait(fence, arg); @@ -856,18 +859,21 @@ static const char *sync_status_str(int status) static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence) { int status = pt->status; + seq_printf(s, " %s%spt %s", fence ? pt->parent->name : "", fence ? "_" : "", sync_status_str(status)); if (pt->status) { struct timeval tv = ktime_to_timeval(pt->timestamp); + seq_printf(s, "@%ld.%06ld", tv.tv_sec, tv.tv_usec); } if (pt->parent->ops->timeline_value_str && pt->parent->ops->pt_value_str) { char value[64]; + pt->parent->ops->pt_value_str(pt, value, sizeof(value)); seq_printf(s, ": %s", value); if (fence) { @@ -892,6 +898,7 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) if (obj->ops->timeline_value_str) { char value[64]; + obj->ops->timeline_value_str(obj, value, sizeof(value)); seq_printf(s, ": %s", value); } else if (obj->ops->print_obj) { @@ -1001,6 +1008,7 @@ static void sync_dump(void) for (i = 0; i < s.count; i += DUMP_CHUNK) { if ((s.count - i) > DUMP_CHUNK) { char c = s.buf[i + DUMP_CHUNK]; + s.buf[i + DUMP_CHUNK] = 0; pr_cont("%s", s.buf + i); s.buf[i + DUMP_CHUNK] = c; diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c index 0c7fdc83b3367f..f7d124da5b70e2 100644 --- a/drivers/staging/android/timed_gpio.c +++ b/drivers/staging/android/timed_gpio.c @@ -51,6 +51,7 @@ static int gpio_get_time(struct timed_output_dev *dev) if (hrtimer_active(&data->timer)) { ktime_t r = hrtimer_get_remaining(&data->timer); struct timeval t = ktime_to_timeval(r); + return t.tv_sec * 1000 + t.tv_usec / 1000; } else return 0; diff --git a/drivers/staging/android/uapi/ion.h b/drivers/staging/android/uapi/ion.h index f09e7c154d691e..6aa4956733708b 100644 --- a/drivers/staging/android/uapi/ion.h +++ b/drivers/staging/android/uapi/ion.h @@ -27,12 +27,12 @@ typedef int ion_user_handle_t; * @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc * @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved - * carveout heap, allocations are physically - * contiguous + * carveout heap, allocations are physically + * contiguous * @ION_HEAP_TYPE_DMA: memory allocated via DMA API * @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask - * is used to identify the heaps, so only 32 - * total heap types are supported + * is used to identify the heaps, so only 32 + * total heap types are supported */ enum ion_heap_type { ION_HEAP_TYPE_SYSTEM, @@ -50,7 +50,7 @@ enum ion_heap_type { #define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT) #define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA) -#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8 +#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8) /** * allocation flags - the lower 16 bits are used by core ion, the upper 16 @@ -78,7 +78,7 @@ enum ion_heap_type { * @align: required alignment of the allocation * @heap_id_mask: mask of heap ids to allocate from * @flags: flags passed to heap - * @handle: pointer that will be populated with a cookie to use to + * @handle: pointer that will be populated with a cookie to use to * refer to this allocation * * Provided by userspace as an argument to the ioctl diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index 632f81a7c63fb8..4564c63f908c95 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -460,42 +460,30 @@ static VOID CopyToAdapter(register struct bcm_mini_adapter *Adapter, /* u8CSSpecification); switch (psfLocalSet->u8CSSpecification) { case eCSPacketIPV4: - { Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV4_CS; break; - } case eCSPacketIPV6: - { Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV6_CS; break; - } case eCS802_3PacketEthernet: case eCS802_1QPacketVLAN: - { Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport = ETH_CS_802_3; break; - } case eCSPacketIPV4Over802_1QVLAN: case eCSPacketIPV4Over802_3Ethernet: - { Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV4_CS; Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport = ETH_CS_802_3; break; - } case eCSPacketIPV6Over802_1QVLAN: case eCSPacketIPV6Over802_3Ethernet: - { Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV6_CS; Adapter->PackInfo[uiSearchRuleIndex].bEthCSSupport = ETH_CS_802_3; break; - } default: - { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Error in value of CS Classification.. setting default to IP CS\n"); Adapter->PackInfo[uiSearchRuleIndex].bIPCSSupport = IPV4_CS; break; } - } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "CopyToAdapter : Queue No : %X ETH CS Support : %X , IP CS Support : %X\n", uiSearchRuleIndex, @@ -542,32 +530,23 @@ static VOID CopyToAdapter(register struct bcm_mini_adapter *Adapter, /* u8ClassfierDSCAction) { case 0: /* DSC Add Classifier */ - { eClassifierAction = eAddClassifier; - } - break; + break; case 1: /* DSC Replace Classifier */ - { eClassifierAction = eReplaceClassifier; - } - break; + break; case 2: /* DSC Delete Classifier */ - { eClassifierAction = eDeleteClassifier; - } - break; + break; default: - { eClassifierAction = eInvalidClassifierAction; } - } } u16PacketClassificationRuleIndex = ntohs(psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex); switch (eClassifierAction) { case eAddClassifier: - { /* Get a Free Classifier Index From Classifier table for this SF to add the Classifier */ /* Contained in this message */ nClassifierIndex = SearchClsid(Adapter, ulSFID, u16PacketClassificationRuleIndex); @@ -587,10 +566,8 @@ static VOID CopyToAdapter(register struct bcm_mini_adapter *Adapter, /* u8PhsDSCAction) { case eDeleteAllPHSRules: - { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Deleting All PHS Rules For VCID: 0x%X\n", uVCID); /* Delete All the PHS rules for this Service flow */ PhsDeleteSFRules(&Adapter->stBCMPhsContext, uVCID); break; - } case eDeletePHSRule: - { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "PHS DSC Action = Delete PHS Rule\n"); if (psfCSType->cPhsRule.u8PHSI) PhsDeletePHSRule(&Adapter->stBCMPhsContext, uVCID, psfCSType->cCPacketClassificationRule.u8AssociatedPHSI); break; - } default: - { if (ucDsxType == DSC_ACK) { /* BCM_DEBUG_PRINT(CONN_MSG,("Invalid PHS DSC Action For DSC\n",psfCSType->cPhsRule.u8PHSI)); */ break; /* FOr DSC ACK Case PHS DSC Action must be in valid set */ } - } /* Proceed To Add PHS rule for DSA_ACK case even if PHS DSC action is unspecified */ /* No Break Here . Intentionally! */ case eAddPHSRule: case eSetPHSRule: - { if (psfCSType->cPhsRule.u8PHSI) { /* Apply This PHS Rule to all classifiers whose Associated PHSI Match */ unsigned int uiClassifierIndex = 0; @@ -738,8 +703,7 @@ static VOID CopyToAdapter(register struct bcm_mini_adapter *Adapter, /* ucIPSourceAddressLength) return TRUE; - for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPSourceAddressLength); ucLoopIndex++) - { + for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPSourceAddressLength); ucLoopIndex++) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Mask:0x%x PacketIp:0x%x and Classification:0x%x", (UINT)pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)ulSrcIP, (UINT)pstClassifierRule->stSrcIpAddress.ulIpv6Addr[ucLoopIndex]); if ((pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex] & ulSrcIP) == (pstClassifierRule->stSrcIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex])) - { return TRUE; - } } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Not Matched"); return false; @@ -68,13 +72,10 @@ static bool MatchDestIpAddress(struct bcm_classifier_rule *pstClassifierRule, UL return TRUE; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address 0x%x 0x%x 0x%x ", (UINT)ulDestIP, (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex]); - for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPDestinationAddressLength); ucLoopIndex++) - { + for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPDestinationAddressLength); ucLoopIndex++) { if ((pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex] & ulDestIP) == (pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex])) - { return TRUE; - } } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address Not Matched"); return false; @@ -99,9 +100,8 @@ static bool MatchTos(struct bcm_classifier_rule *pstClassifierRule, UCHAR ucType return TRUE; if (((pstClassifierRule->ucTosMask & ucTypeOfService) <= pstClassifierRule->ucTosHigh) && ((pstClassifierRule->ucTosMask & ucTypeOfService) >= pstClassifierRule->ucTosLow)) - { return TRUE; - } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Type Of Service Not Matched"); return false; } @@ -123,13 +123,10 @@ bool MatchProtocol(struct bcm_classifier_rule *pstClassifierRule, UCHAR ucProtoc struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); if (0 == pstClassifierRule->ucProtocolLength) return TRUE; - for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucProtocolLength; ucLoopIndex++) - { + for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucProtocolLength; ucLoopIndex++) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol:0x%X Classification Protocol:0x%X", ucProtocol, pstClassifierRule->ucProtocol[ucLoopIndex]); if (pstClassifierRule->ucProtocol[ucLoopIndex] == ucProtocol) - { return TRUE; - } } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Not Matched"); return false; @@ -155,13 +152,10 @@ bool MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule, USHORT ushSrcPo if (0 == pstClassifierRule->ucSrcPortRangeLength) return TRUE; - for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucSrcPortRangeLength; ucLoopIndex++) - { + for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucSrcPortRangeLength; ucLoopIndex++) { if (ushSrcPort <= pstClassifierRule->usSrcPortRangeHi[ucLoopIndex] && ushSrcPort >= pstClassifierRule->usSrcPortRangeLo[ucLoopIndex]) - { return TRUE; - } } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port: %x Not Matched ", ushSrcPort); return false; @@ -186,15 +180,12 @@ bool MatchDestPort(struct bcm_classifier_rule *pstClassifierRule, USHORT ushDest if (0 == pstClassifierRule->ucDestPortRangeLength) return TRUE; - for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucDestPortRangeLength; ucLoopIndex++) - { + for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucDestPortRangeLength; ucLoopIndex++) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Matching Port:0x%X 0x%X 0x%X", ushDestPort, pstClassifierRule->usDestPortRangeLo[ucLoopIndex], pstClassifierRule->usDestPortRangeHi[ucLoopIndex]); if (ushDestPort <= pstClassifierRule->usDestPortRangeHi[ucLoopIndex] && ushDestPort >= pstClassifierRule->usDestPortRangeLo[ucLoopIndex]) - { return TRUE; - } } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dest Port: %x Not Matched", ushDestPort); return false; @@ -273,21 +264,13 @@ static USHORT IpVersion4(struct bcm_mini_adapter *Adapter, bClassificationSucceed = TRUE; } while (0); - if (TRUE == bClassificationSucceed) - { + if (TRUE == bClassificationSucceed) { INT iMatchedSFQueueIndex = 0; iMatchedSFQueueIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID); if (iMatchedSFQueueIndex >= NO_OF_QUEUES) - { bClassificationSucceed = false; - } - else - { - if (false == Adapter->PackInfo[iMatchedSFQueueIndex].bActive) - { - bClassificationSucceed = false; - } - } + else if (false == Adapter->PackInfo[iMatchedSFQueueIndex].bActive) + bClassificationSucceed = false; } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "IpVersion4 <=========="); @@ -299,8 +282,7 @@ VOID PruneQueueAllSF(struct bcm_mini_adapter *Adapter) { UINT iIndex = 0; - for (iIndex = 0; iIndex < HiPriority; iIndex++) - { + for (iIndex = 0; iIndex < HiPriority; iIndex++) { if (!Adapter->PackInfo[iIndex].bValid) continue; @@ -334,10 +316,10 @@ static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex) spin_lock_bh(&Adapter->PackInfo[iIndex].SFQueueLock); - while (1) + while (1) { // while((UINT)Adapter->PackInfo[iIndex].uiCurrentPacketsOnHost > -// SF_MAX_ALLOWED_PACKETS_TO_BACKUP) - { +// SF_MAX_ALLOWED_PACKETS_TO_BACKUP) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "uiCurrentBytesOnHost:%x uiMaxBucketSize :%x", Adapter->PackInfo[iIndex].uiCurrentBytesOnHost, Adapter->PackInfo[iIndex].uiMaxBucketSize); @@ -350,8 +332,7 @@ static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex) ((1000*(jiffies - *((B_UINT32 *)(PacketToDrop->cb)+SKB_CB_LATENCY_OFFSET))/HZ) <= Adapter->PackInfo[iIndex].uiMaxLatency)) break; - if (PacketToDrop) - { + if (PacketToDrop) { if (netif_msg_tx_err(Adapter)) pr_info(PFX "%s: tx queue %d overlimit\n", Adapter->dev->name, iIndex); @@ -394,20 +375,16 @@ VOID flush_all_queues(struct bcm_mini_adapter *Adapter) BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "=====>"); // down(&Adapter->data_packet_queue_lock); - for (iQIndex = LowPriority; iQIndex < HiPriority; iQIndex++) - { + for (iQIndex = LowPriority; iQIndex < HiPriority; iQIndex++) { struct net_device_stats *netstats = &Adapter->dev->stats; spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock); - while (Adapter->PackInfo[iQIndex].FirstTxQueue) - { + while (Adapter->PackInfo[iQIndex].FirstTxQueue) { PacketToDrop = Adapter->PackInfo[iQIndex].FirstTxQueue; - if (PacketToDrop) - { + if (PacketToDrop) { uiTotalPacketLength = PacketToDrop->len; netstats->tx_dropped++; - } - else + } else uiTotalPacketLength = 0; DEQUEUEPACKET(Adapter->PackInfo[iQIndex].FirstTxQueue, @@ -455,58 +432,42 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb) *((UINT32*) (skb->cb) +SKB_CB_TCPACK_OFFSET) = 0; EThCSGetPktInfo(Adapter, pvEThPayload, &stEthCsPktInfo); - switch (stEthCsPktInfo.eNwpktEthFrameType) - { + switch (stEthCsPktInfo.eNwpktEthFrameType) { case eEth802LLCFrame: - { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : 802LLCFrame\n"); pIpHeader = pvEThPayload + sizeof(struct bcm_eth_llc_frame); break; - } - case eEth802LLCSNAPFrame: - { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : 802LLC SNAP Frame\n"); pIpHeader = pvEThPayload + sizeof(struct bcm_eth_llc_snap_frame); break; - } case eEth802QVLANFrame: - { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : 802.1Q VLANFrame\n"); pIpHeader = pvEThPayload + sizeof(struct bcm_eth_q_frame); break; - } case eEthOtherFrame: - { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : ETH Other Frame\n"); pIpHeader = pvEThPayload + sizeof(struct bcm_ethernet2_frame); break; - } default: - { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : Unrecognized ETH Frame\n"); pIpHeader = pvEThPayload + sizeof(struct bcm_ethernet2_frame); break; - } } - if (stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet) - { + if (stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet) { usCurrFragment = (ntohs(pIpHeader->frag_off) & IP_OFFSET); if ((ntohs(pIpHeader->frag_off) & IP_MF) || usCurrFragment) bFragmentedPkt = TRUE; - if (bFragmentedPkt) - { + if (bFragmentedPkt) { //Fragmented Packet. Get Frag Classifier Entry. pstClassifierRule = GetFragIPClsEntry(Adapter, pIpHeader->id, pIpHeader->saddr); - if (pstClassifierRule) - { + if (pstClassifierRule) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "It is next Fragmented pkt"); bClassificationSucceed = TRUE; } - if (!(ntohs(pIpHeader->frag_off) & IP_MF)) - { + if (!(ntohs(pIpHeader->frag_off) & IP_MF)) { //Fragmented Last packet . Remove Frag Classifier Entry BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "This is the last fragmented Pkt"); DelFragIPClsEntry(Adapter, pIpHeader->id, pIpHeader->saddr); @@ -514,23 +475,19 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb) } } - for (uiLoopIndex = MAX_CLASSIFIERS - 1; uiLoopIndex >= 0; uiLoopIndex--) - { + for (uiLoopIndex = MAX_CLASSIFIERS - 1; uiLoopIndex >= 0; uiLoopIndex--) { if (bClassificationSucceed) break; //Iterate through all classifiers which are already in order of priority //to classify the packet until match found - do - { - if (false == Adapter->astClassifierTable[uiLoopIndex].bUsed) - { + do { + if (false == Adapter->astClassifierTable[uiLoopIndex].bUsed) { bClassificationSucceed = false; break; } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Adapter->PackInfo[%d].bvalid=True\n", uiLoopIndex); - if (0 == Adapter->astClassifierTable[uiLoopIndex].ucDirection) - { + if (0 == Adapter->astClassifierTable[uiLoopIndex].ucDirection) { bClassificationSucceed = false;//cannot be processed for classification. break; // it is a down link connection } @@ -543,11 +500,9 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb) break; } - if (Adapter->PackInfo[uiSfIndex].bEthCSSupport) - { + if (Adapter->PackInfo[uiSfIndex].bEthCSSupport) { - if (eEthUnsupportedFrame == stEthCsPktInfo.eNwpktEthFrameType) - { + if (eEthUnsupportedFrame == stEthCsPktInfo.eNwpktEthFrameType) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet Not a Valid Supported Ethernet Frame\n"); bClassificationSucceed = false; break; @@ -558,17 +513,12 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb) BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Performing ETH CS Classification on Classifier Rule ID : %x Service Flow ID : %lx\n", pstClassifierRule->uiClassifierRuleIndex, Adapter->PackInfo[uiSfIndex].ulSFID); bClassificationSucceed = EThCSClassifyPkt(Adapter, skb, &stEthCsPktInfo, pstClassifierRule, Adapter->PackInfo[uiSfIndex].bEthCSSupport); - if (!bClassificationSucceed) - { + if (!bClassificationSucceed) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : Ethernet CS Classification Failed\n"); break; } - } - - else // No ETH Supported on this SF - { - if (eEthOtherFrame != stEthCsPktInfo.eNwpktEthFrameType) - { + } else { // No ETH Supported on this SF + if (eEthOtherFrame != stEthCsPktInfo.eNwpktEthFrameType) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet Not a 802.3 Ethernet Frame... hence not allowed over non-ETH CS SF\n"); bClassificationSucceed = false; break; @@ -577,11 +527,9 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb) BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Proceeding to IP CS Clasification"); - if (Adapter->PackInfo[uiSfIndex].bIPCSSupport) - { + if (Adapter->PackInfo[uiSfIndex].bIPCSSupport) { - if (stEthCsPktInfo.eNwpktIPFrameType == eNonIPPacket) - { + if (stEthCsPktInfo.eNwpktIPFrameType == eNonIPPacket) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet is Not an IP Packet\n"); bClassificationSucceed = false; break; @@ -598,31 +546,26 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb) } while (0); } - if (bClassificationSucceed == TRUE) - { + if (bClassificationSucceed == TRUE) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "CF id : %d, SF ID is =%lu", pstClassifierRule->uiClassifierRuleIndex, pstClassifierRule->ulSFID); //Store The matched Classifier in SKB *((UINT32*)(skb->cb)+SKB_CB_CLASSIFICATION_OFFSET) = pstClassifierRule->uiClassifierRuleIndex; - if ((TCP == pIpHeader->protocol) && !bFragmentedPkt && (ETH_AND_IP_HEADER_LEN + TCP_HEADER_LEN <= skb->len)) - { + if ((TCP == pIpHeader->protocol) && !bFragmentedPkt && (ETH_AND_IP_HEADER_LEN + TCP_HEADER_LEN <= skb->len)) { IpHeaderLength = pIpHeader->ihl; pTcpHeader = (struct bcm_tcp_header *)(((PUCHAR)pIpHeader)+(IpHeaderLength*4)); TcpHeaderLength = GET_TCP_HEADER_LEN(pTcpHeader->HeaderLength); if ((pTcpHeader->ucFlags & TCP_ACK) && (ntohs(pIpHeader->tot_len) == (IpHeaderLength*4)+(TcpHeaderLength*4))) - { *((UINT32*) (skb->cb) + SKB_CB_TCPACK_OFFSET) = TCP_ACK; - } } usIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "index is =%d", usIndex); //If this is the first fragment of a Fragmented pkt, add this CF. Only This CF should be used for all other fragment of this Pkt. - if (bFragmentedPkt && (usCurrFragment == 0)) - { + if (bFragmentedPkt && (usCurrFragment == 0)) { //First Fragment of Fragmented Packet. Create Frag CLS Entry struct bcm_fragmented_packet_info stFragPktInfo; stFragPktInfo.bUsed = TRUE; @@ -649,8 +592,7 @@ static bool EthCSMatchSrcMACAddress(struct bcm_classifier_rule *pstClassifierRul if (pstClassifierRule->ucEthCSSrcMACLen == 0) return TRUE; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s\n", __FUNCTION__); - for (i = 0; i < MAC_ADDRESS_SIZE; i++) - { + for (i = 0; i < MAC_ADDRESS_SIZE; i++) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n", i, Mac[i], pstClassifierRule->au8EThCSSrcMAC[i], pstClassifierRule->au8EThCSSrcMACMask[i]); if ((pstClassifierRule->au8EThCSSrcMAC[i] & pstClassifierRule->au8EThCSSrcMACMask[i]) != (Mac[i] & pstClassifierRule->au8EThCSSrcMACMask[i])) @@ -666,8 +608,7 @@ static bool EthCSMatchDestMACAddress(struct bcm_classifier_rule *pstClassifierRu if (pstClassifierRule->ucEthCSDestMACLen == 0) return TRUE; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s\n", __FUNCTION__); - for (i = 0; i < MAC_ADDRESS_SIZE; i++) - { + for (i = 0; i < MAC_ADDRESS_SIZE; i++) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n", i, Mac[i], pstClassifierRule->au8EThCSDestMAC[i], pstClassifierRule->au8EThCSDestMACMask[i]); if ((pstClassifierRule->au8EThCSDestMAC[i] & pstClassifierRule->au8EThCSDestMACMask[i]) != (Mac[i] & pstClassifierRule->au8EThCSDestMACMask[i])) @@ -684,8 +625,7 @@ static bool EthCSMatchEThTypeSAP(struct bcm_classifier_rule *pstClassifierRule, return TRUE; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s SrcEtherType:%x CLS EtherType[0]:%x\n", __FUNCTION__, pstEthCsPktInfo->usEtherType, pstClassifierRule->au8EthCSEtherType[0]); - if (pstClassifierRule->au8EthCSEtherType[0] == 1) - { + if (pstClassifierRule->au8EthCSEtherType[0] == 1) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS EtherType[1]:%x EtherType[2]:%x\n", __FUNCTION__, pstClassifierRule->au8EthCSEtherType[1], pstClassifierRule->au8EthCSEtherType[2]); if (memcmp(&pstEthCsPktInfo->usEtherType, &pstClassifierRule->au8EthCSEtherType[1], 2) == 0) @@ -694,8 +634,7 @@ static bool EthCSMatchEThTypeSAP(struct bcm_classifier_rule *pstClassifierRule, return false; } - if (pstClassifierRule->au8EthCSEtherType[0] == 2) - { + if (pstClassifierRule->au8EthCSEtherType[0] == 2) { if (eEth802LLCFrame != pstEthCsPktInfo->eNwpktEthFrameType) return false; @@ -721,8 +660,7 @@ static bool EthCSMatchVLANRules(struct bcm_classifier_rule *pstClassifierRule, s BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS UserPrio:%x CLS VLANID:%x\n", __FUNCTION__, ntohs(*((USHORT *)pstClassifierRule->usUserPriority)), pstClassifierRule->usVLANID); /* In case FW didn't receive the TLV, the priority field should be ignored */ - if (pstClassifierRule->usValidityBitMap & (1<usValidityBitMap & (1<eNwpktEthFrameType != eEth802QVLANFrame) return false; @@ -739,8 +677,7 @@ static bool EthCSMatchVLANRules(struct bcm_classifier_rule *pstClassifierRule, s bClassificationSucceed = false; - if (pstClassifierRule->usValidityBitMap & (1<usValidityBitMap & (1<eNwpktEthFrameType != eEth802QVLANFrame) return false; @@ -800,32 +737,24 @@ static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter, PVOID pvEthPayload USHORT u16Etype = ntohs(((struct bcm_eth_header *)pvEthPayload)->u16Etype); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : Eth Hdr Type : %X\n", u16Etype); - if (u16Etype > 0x5dc) - { + if (u16Etype > 0x5dc) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : ETH2 Frame\n"); //ETH2 Frame - if (u16Etype == ETHERNET_FRAMETYPE_802QVLAN) - { + if (u16Etype == ETHERNET_FRAMETYPE_802QVLAN) { //802.1Q VLAN Header pstEthCsPktInfo->eNwpktEthFrameType = eEth802QVLANFrame; u16Etype = ((struct bcm_eth_q_frame *)pvEthPayload)->EthType; //((ETH_CS_802_Q_FRAME*)pvEthPayload)->UserPriority - } - else - { + } else { pstEthCsPktInfo->eNwpktEthFrameType = eEthOtherFrame; u16Etype = ntohs(u16Etype); } - - } - else - { + } else { //802.2 LLC BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "802.2 LLC Frame\n"); pstEthCsPktInfo->eNwpktEthFrameType = eEth802LLCFrame; pstEthCsPktInfo->ucDSAP = ((struct bcm_eth_llc_frame *)pvEthPayload)->DSAP; - if (pstEthCsPktInfo->ucDSAP == 0xAA && ((struct bcm_eth_llc_frame *)pvEthPayload)->SSAP == 0xAA) - { + if (pstEthCsPktInfo->ucDSAP == 0xAA && ((struct bcm_eth_llc_frame *)pvEthPayload)->SSAP == 0xAA) { //SNAP Frame pstEthCsPktInfo->eNwpktEthFrameType = eEth802LLCSNAPFrame; u16Etype = ((struct bcm_eth_llc_snap_frame *)pvEthPayload)->usEtherType; diff --git a/drivers/staging/bcm/hostmibs.c b/drivers/staging/bcm/hostmibs.c index 39ace5510c4360..42d9004e357d53 100644 --- a/drivers/staging/bcm/hostmibs.c +++ b/drivers/staging/bcm/hostmibs.c @@ -9,37 +9,40 @@ #include "headers.h" -INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, struct bcm_host_stats_mibs *pstHostMibs) +INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, + struct bcm_host_stats_mibs *pstHostMibs) { struct bcm_phs_entry *pstServiceFlowEntry = NULL; struct bcm_phs_rule *pstPhsRule = NULL; struct bcm_phs_classifier_table *pstClassifierTable = NULL; struct bcm_phs_classifier_entry *pstClassifierRule = NULL; - struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *) &Adapter->stBCMPhsContext; - - UINT nClassifierIndex = 0, nPhsTableIndex = 0, nSfIndex = 0, uiIndex = 0; + struct bcm_phs_extension *pDeviceExtension = &Adapter->stBCMPhsContext; + UINT nClassifierIndex = 0; + UINT nPhsTableIndex = 0; + UINT nSfIndex = 0; + UINT uiIndex = 0; if (pDeviceExtension == NULL) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, HOST_MIBS, DBG_LVL_ALL, "Invalid Device Extension\n"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, HOST_MIBS, + DBG_LVL_ALL, "Invalid Device Extension\n"); return STATUS_FAILURE; } /* Copy the classifier Table */ - for (nClassifierIndex = 0; nClassifierIndex < MAX_CLASSIFIERS; nClassifierIndex++) { + for (nClassifierIndex = 0; nClassifierIndex < MAX_CLASSIFIERS; + nClassifierIndex++) { if (Adapter->astClassifierTable[nClassifierIndex].bUsed == TRUE) - memcpy((PVOID) &pstHostMibs-> - astClassifierTable[nClassifierIndex], - (PVOID) &Adapter-> - astClassifierTable[nClassifierIndex], + memcpy(&pstHostMibs->astClassifierTable[nClassifierIndex], + &Adapter->astClassifierTable[nClassifierIndex], sizeof(struct bcm_mibs_classifier_rule)); } /* Copy the SF Table */ for (nSfIndex = 0; nSfIndex < NO_OF_QUEUES; nSfIndex++) { if (Adapter->PackInfo[nSfIndex].bValid) { - memcpy((PVOID) &pstHostMibs->astSFtable[nSfIndex], - (PVOID) &Adapter->PackInfo[nSfIndex], - sizeof(struct bcm_mibs_table)); + memcpy(&pstHostMibs->astSFtable[nSfIndex], + &Adapter->PackInfo[nSfIndex], + sizeof(struct bcm_mibs_table)); } else { /* If index in not valid, * don't process this for the PHS table. @@ -68,9 +71,9 @@ INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, struct bcm_host_stats_m pstHostMibs->astPhsRulesTable[nPhsTableIndex]. ulSFID = Adapter->PackInfo[nSfIndex].ulSFID; - memcpy(&pstHostMibs-> - astPhsRulesTable[nPhsTableIndex].u8PHSI, - &pstPhsRule->u8PHSI, sizeof(struct bcm_phs_rule)); + memcpy(&pstHostMibs->astPhsRulesTable[nPhsTableIndex].u8PHSI, + &pstPhsRule->u8PHSI, + sizeof(struct bcm_phs_rule)); nPhsTableIndex++; } @@ -82,26 +85,32 @@ INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, struct bcm_host_stats_m /* Copy other Host Statistics parameters */ pstHostMibs->stHostInfo.GoodTransmits = Adapter->dev->stats.tx_packets; pstHostMibs->stHostInfo.GoodReceives = Adapter->dev->stats.rx_packets; - pstHostMibs->stHostInfo.CurrNumFreeDesc = atomic_read(&Adapter->CurrNumFreeTxDesc); + pstHostMibs->stHostInfo.CurrNumFreeDesc = + atomic_read(&Adapter->CurrNumFreeTxDesc); pstHostMibs->stHostInfo.BEBucketSize = Adapter->BEBucketSize; pstHostMibs->stHostInfo.rtPSBucketSize = Adapter->rtPSBucketSize; pstHostMibs->stHostInfo.TimerActive = Adapter->TimerActive; pstHostMibs->stHostInfo.u32TotalDSD = Adapter->u32TotalDSD; - memcpy(pstHostMibs->stHostInfo.aTxPktSizeHist, Adapter->aTxPktSizeHist, sizeof(UINT32) * MIBS_MAX_HIST_ENTRIES); - memcpy(pstHostMibs->stHostInfo.aRxPktSizeHist, Adapter->aRxPktSizeHist, sizeof(UINT32) * MIBS_MAX_HIST_ENTRIES); + memcpy(pstHostMibs->stHostInfo.aTxPktSizeHist, Adapter->aTxPktSizeHist, + sizeof(UINT32) * MIBS_MAX_HIST_ENTRIES); + memcpy(pstHostMibs->stHostInfo.aRxPktSizeHist, Adapter->aRxPktSizeHist, + sizeof(UINT32) * MIBS_MAX_HIST_ENTRIES); return STATUS_SUCCESS; } -VOID GetDroppedAppCntrlPktMibs(struct bcm_host_stats_mibs *pstHostMibs, struct bcm_tarang_data *pTarang) +VOID GetDroppedAppCntrlPktMibs(struct bcm_host_stats_mibs *pstHostMibs, + struct bcm_tarang_data *pTarang) { memcpy(&(pstHostMibs->stDroppedAppCntrlMsgs), &(pTarang->stDroppedAppCntrlMsgs), sizeof(struct bcm_mibs_dropped_cntrl_msg)); } -VOID CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter, struct bcm_connect_mgr_params *psfLocalSet, UINT uiSearchRuleIndex) +VOID CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter, + struct bcm_connect_mgr_params *psfLocalSet, + UINT uiSearchRuleIndex) { struct bcm_mibs_parameters *t = &Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable; diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index acc80197e35ed8..0affd1f9666094 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -238,9 +238,9 @@ comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor) } static int resize_async_buffer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_async *async, unsigned new_size) + struct comedi_subdevice *s, unsigned new_size) { + struct comedi_async *async = s->async; int retval; if (new_size > async->max_bufsize) @@ -380,7 +380,7 @@ static ssize_t read_buffer_kb_store(struct device *csdev, mutex_lock(&dev->mutex); s = comedi_read_subdevice(dev, minor); if (s && (s->subdev_flags & SDF_CMD_READ) && s->async) - err = resize_async_buffer(dev, s, s->async, size); + err = resize_async_buffer(dev, s, size); else err = -EINVAL; mutex_unlock(&dev->mutex); @@ -493,7 +493,7 @@ static ssize_t write_buffer_kb_store(struct device *csdev, mutex_lock(&dev->mutex); s = comedi_write_subdevice(dev, minor); if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async) - err = resize_async_buffer(dev, s, s->async, size); + err = resize_async_buffer(dev, s, size); else err = -EINVAL; mutex_unlock(&dev->mutex); @@ -668,6 +668,7 @@ static int do_devconfig_ioctl(struct comedi_device *dev, return -EBUSY; if (dev->attached) { struct module *driver_module = dev->driver->module; + comedi_device_detach(dev); module_put(driver_module); } @@ -740,7 +741,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, } if (bc.size) { - retval = resize_async_buffer(dev, s, async, bc.size); + retval = resize_async_buffer(dev, s, bc.size); if (retval < 0) return retval; } @@ -1435,13 +1436,15 @@ static int __comedi_get_user_cmd(struct comedi_device *dev, s = &dev->subdevices[cmd->subdev]; if (s->type == COMEDI_SUBD_UNUSED) { - dev_dbg(dev->class_dev, "%d not valid subdevice\n", cmd->subdev); + dev_dbg(dev->class_dev, "%d not valid subdevice\n", + cmd->subdev); return -EIO; } if (!s->do_cmd || !s->do_cmdtest || !s->async) { dev_dbg(dev->class_dev, - "subdevice %d does not support commands\n", cmd->subdev); + "subdevice %d does not support commands\n", + cmd->subdev); return -EIO; } @@ -1597,7 +1600,6 @@ static int do_cmdtest_ioctl(struct comedi_device *dev, { struct comedi_cmd cmd; struct comedi_subdevice *s; - unsigned int *chanlist = NULL; unsigned int __user *user_chanlist; int ret; @@ -1626,8 +1628,6 @@ static int do_cmdtest_ioctl(struct comedi_device *dev, ret = -EFAULT; } - kfree(chanlist); - return ret; } @@ -2035,7 +2035,7 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait) s = comedi_write_subdevice(dev, minor); if (s && s->async) { - unsigned int bps = bytes_per_sample(s->async->subdevice); + unsigned int bps = bytes_per_sample(s); poll_wait(file, &s->async->wait_head, wait); comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz); @@ -2654,6 +2654,7 @@ static int __init comedi_init(void) /* create devices files for legacy/manual use */ for (i = 0; i < comedi_num_legacy_minors; i++) { struct comedi_device *dev; + dev = comedi_alloc_board_minor(NULL); if (IS_ERR(dev)) { comedi_cleanup_board_minors(); diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index ab0e8ed472910e..cb5d21411a0c80 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -258,6 +258,7 @@ static int insn_rw_emulate_bits(struct comedi_device *dev, const unsigned base_bitfield_channel = (chan < channels_per_bitfield) ? 0 : chan; unsigned int new_data[2]; + memset(new_data, 0, sizeof(new_data)); memset(&new_insn, 0, sizeof(new_insn)); new_insn.insn = INSN_BITS; diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h index e3d737cf730290..5829b46b757b9e 100644 --- a/drivers/staging/comedi/drivers/8253.h +++ b/drivers/staging/comedi/drivers/8253.h @@ -30,106 +30,11 @@ #define I8254_OSC_BASE_2MHZ 500 #define I8254_OSC_BASE_1MHZ 1000 -#define i8253_cascade_ns_to_timer i8253_cascade_ns_to_timer_2div - -static inline void i8253_cascade_ns_to_timer_2div_old(int i8253_osc_base, - unsigned int *d1, - unsigned int *d2, - unsigned int *nanosec, - int round_mode) -{ - int divider; - int div1, div2; - int div1_glb, div2_glb, ns_glb; - int div1_lub, div2_lub, ns_lub; - int ns; - - divider = (*nanosec + i8253_osc_base / 2) / i8253_osc_base; - - /* find 2 integers 1<={x,y}<=65536 such that x*y is - close to divider */ - - div1_lub = div2_lub = 0; - div1_glb = div2_glb = 0; - - ns_glb = 0; - ns_lub = 0xffffffff; - - div2 = 0x10000; - for (div1 = divider / 65536 + 1; div1 < div2; div1++) { - div2 = divider / div1; - - ns = i8253_osc_base * div1 * div2; - if (ns <= *nanosec && ns > ns_glb) { - ns_glb = ns; - div1_glb = div1; - div2_glb = div2; - } - - div2++; - if (div2 <= 65536) { - ns = i8253_osc_base * div1 * div2; - if (ns > *nanosec && ns < ns_lub) { - ns_lub = ns; - div1_lub = div1; - div2_lub = div2; - } - } - } - - *nanosec = div1_lub * div2_lub * i8253_osc_base; - *d1 = div1_lub & 0xffff; - *d2 = div2_lub & 0xffff; - return; -} - -static inline void i8253_cascade_ns_to_timer_power(int i8253_osc_base, - unsigned int *d1, - unsigned int *d2, - unsigned int *nanosec, - int round_mode) -{ - int div1, div2; - int base; - - for (div1 = 2; div1 <= (1 << 16); div1 <<= 1) { - base = i8253_osc_base * div1; - round_mode &= TRIG_ROUND_MASK; - switch (round_mode) { - case TRIG_ROUND_NEAREST: - default: - div2 = (*nanosec + base / 2) / base; - break; - case TRIG_ROUND_DOWN: - div2 = (*nanosec) / base; - break; - case TRIG_ROUND_UP: - div2 = (*nanosec + base - 1) / base; - break; - } - if (div2 < 2) - div2 = 2; - if (div2 <= 65536) { - *nanosec = div2 * base; - *d1 = div1 & 0xffff; - *d2 = div2 & 0xffff; - return; - } - } - - /* shouldn't get here */ - div1 = 0x10000; - div2 = 0x10000; - *nanosec = div1 * div2 * i8253_osc_base; - *d1 = div1 & 0xffff; - *d2 = div2 & 0xffff; -} - -static inline void i8253_cascade_ns_to_timer_2div(int i8253_osc_base, - unsigned int *d1, - unsigned int *d2, - unsigned int *nanosec, - int round_mode) +static inline void i8253_cascade_ns_to_timer(int i8253_osc_base, + unsigned int *d1, + unsigned int *d2, + unsigned int *nanosec, + int round_mode) { unsigned int divider; unsigned int div1, div2; @@ -386,7 +291,7 @@ static inline int i8254_set_mode(unsigned long base_address, if (counter_number > 2) return -1; - if (mode > (I8254_MODE5 | I8254_BINARY)) + if (mode > (I8254_MODE5 | I8254_BCD)) return -1; byte = counter_number << 6; @@ -406,7 +311,7 @@ static inline int i8254_mm_set_mode(void __iomem *base_address, if (counter_number > 2) return -1; - if (mode > (I8254_MODE5 | I8254_BINARY)) + if (mode > (I8254_MODE5 | I8254_BCD)) return -1; byte = counter_number << 6; diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c index 48817f087d9758..1d53e241e84d94 100644 --- a/drivers/staging/comedi/drivers/8255.c +++ b/drivers/staging/comedi/drivers/8255.c @@ -231,7 +231,7 @@ static int subdev_8255_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -298,6 +298,7 @@ int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, if (ret) return ret; + s->len_chanlist = 1; s->do_cmdtest = subdev_8255_cmdtest; s->do_cmd = subdev_8255_cmd; s->cancel = subdev_8255_cancel; diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h index 4f16ea78f86ac5..795d232a6c0230 100644 --- a/drivers/staging/comedi/drivers/8255.h +++ b/drivers/staging/comedi/drivers/8255.h @@ -22,10 +22,10 @@ #include "../comedidev.h" int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io) (int, int, int, unsigned long), + int (*io)(int, int, int, unsigned long), unsigned long iobase); int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, - int (*io) (int, int, int, unsigned long), + int (*io)(int, int, int, unsigned long), unsigned long iobase); void subdev_8255_interrupt(struct comedi_device *dev, struct comedi_subdevice *s); diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h index 2ed2da3499f44a..5c6a11c35dede4 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.h +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h @@ -118,18 +118,10 @@ struct addi_private { int i_IobaseAmcc; /* base+size for AMCC chip */ int i_IobaseAddon; /* addon base address */ int i_IobaseReserved; - unsigned char b_AiContinuous; /* we do unlimited AI */ unsigned int ui_AiActualScan; /* how many scans we finished */ unsigned int ui_AiNbrofChannels; /* how many channels is measured */ - unsigned int ui_AiScanLength; /* Length of actual scanlist */ - unsigned int *pui_AiChannelList; /* actual chanlist */ unsigned int ui_AiChannelList[32]; /* actual chanlist */ unsigned int ui_AiReadData[32]; - unsigned int ui_AiTimer0; /* Timer Constant for Timer0 */ - unsigned int ui_AiTimer1; /* Timer constant for Timer1 */ - unsigned int ui_AiFlags; - unsigned int ui_AiDataLength; - unsigned int ui_AiNbrofScans; /* number of scans to do */ unsigned short us_UseDma; /* To use Dma or not */ unsigned char b_DmaDoubleBuffer; /* we can use double buffering */ unsigned int ui_DmaActualBuffer; /* which buffer is used now */ @@ -145,7 +137,7 @@ struct addi_private { unsigned short us_OutputRegister; /* Contain data written at iobase + 0 */ unsigned char b_Timer2Mode; /* Specify the timer 2 mode */ unsigned char b_Timer2Interrupt; /* Timer2 interrupt enable or disable */ - unsigned char b_AiCyclicAcquisition; /* indicate cyclic acquisition */ + unsigned int ai_running:1; unsigned char b_InterruptMode; /* eoc eos or dma */ unsigned char b_EocEosInterrupt; /* Enable disable eoc eos interrupt */ unsigned int ui_EocEosConversionTime; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index 9c86b02eb6da4b..7976a22ae94dea 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -21,6 +21,8 @@ * */ +#include "../addi_watchdog.h" + #define APCI1564_ADDRESS_RANGE 128 /* Digital Input IRQ Function Selection */ @@ -76,7 +78,7 @@ #define APCI1564_TIMER_WARN_TIMEBASE_REG 0x64 /* - * devpriv->iobase Register Map + * dev>iobase Register Map */ #define APCI1564_TCW_REG(x) (0x00 + ((x) * 0x20)) #define APCI1564_TCW_RELOAD_REG(x) (0x04 + ((x) * 0x20)) @@ -239,13 +241,13 @@ static int apci1564_timer_config(struct comedi_device *dev, outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG); outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_IRQ_REG); outl(0x0, - devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)); + dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)); outl(0x0, - devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)); + dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)); outl(0x0, - devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)); + dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)); outl(0x0, - devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)); + dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)); } else { /* disable Timer interrupt */ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); @@ -266,13 +268,13 @@ static int apci1564_timer_config(struct comedi_device *dev, devpriv->b_ModeSelectRegister = data[5]; /* First Stop The Counter */ - ul_Command1 = inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + ul_Command1 = inl(dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; /* Stop The Timer */ - outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); /* Set the reload value */ - outl(data[3], devpriv->iobase + APCI1564_TCW_RELOAD_REG(data[5] - 1)); + outl(data[3], dev->iobase + APCI1564_TCW_RELOAD_REG(data[5] - 1)); /* Set the mode : */ /* - Disable the hardware */ @@ -285,15 +287,15 @@ static int apci1564_timer_config(struct comedi_device *dev, ul_Command1 = (ul_Command1 & 0xFFFC19E2UL) | 0x80000UL | (unsigned int) ((unsigned int) data[4] << 16UL); - outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); /* Enable or Disable Interrupt */ ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1); - outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); /* Set the Up/Down selection */ ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18); - outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); } else { dev_err(dev->class_dev, "Invalid subdevice.\n"); } @@ -349,8 +351,8 @@ static int apci1564_timer_write(struct comedi_device *dev, } if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { ul_Command1 = - inl(devpriv->iobase + - APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1)); + inl(dev->iobase + + APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1)); if (data[1] == 1) { /* Start the Counter subdevice */ ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; @@ -362,9 +364,8 @@ static int apci1564_timer_write(struct comedi_device *dev, /* Clears the Counter subdevice */ ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400; } - outl(ul_Command1, - devpriv->iobase + - APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1)); + outl(ul_Command1, dev->iobase + + APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1)); } return insn->n; } @@ -393,11 +394,11 @@ static int apci1564_timer_read(struct comedi_device *dev, } else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { /* Read the Counter Actual Value. */ data[0] = - inl(devpriv->iobase + - APCI1564_TCW_REG(devpriv->b_ModeSelectRegister - 1)); + inl(dev->iobase + + APCI1564_TCW_REG(devpriv->b_ModeSelectRegister - 1)); ul_Command1 = - inl(devpriv->iobase + - APCI1564_TCW_STATUS_REG(devpriv->b_ModeSelectRegister - 1)); + inl(dev->iobase + + APCI1564_TCW_STATUS_REG(devpriv->b_ModeSelectRegister - 1)); /* Get the software trigger status */ data[1] = (unsigned char) ((ul_Command1 >> 1) & 1); @@ -446,13 +447,13 @@ static void apci1564_interrupt(int irq, void *d) ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG) & 0x01; ui_Timer = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_IRQ_REG) & 0x01; ui_C1 = - inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)) & 0x1; + inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)) & 0x1; ui_C2 = - inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)) & 0x1; + inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)) & 0x1; ui_C3 = - inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)) & 0x1; + inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)) & 0x1; ui_C4 = - inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)) & 0x1; + inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)) & 0x1; if (ui_DI == 0 && ui_DO == 0 && ui_Timer == 0 && ui_C1 == 0 && ui_C2 == 0 && ui_C3 == 0 && ui_C4 == 0) { dev_err(dev->class_dev, "Interrupt from unknown source.\n"); @@ -506,16 +507,16 @@ static void apci1564_interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); + inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); outl(0x0, - devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); } } @@ -525,16 +526,16 @@ static void apci1564_interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); + inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); outl(0x0, - devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); } } @@ -544,16 +545,16 @@ static void apci1564_interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); + inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); outl(0x0, - devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); } } @@ -563,16 +564,16 @@ static void apci1564_interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); + inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); outl(0x0, - devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); } } return; @@ -582,26 +583,30 @@ static int apci1564_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; - /* disable the interrupts */ + ui_Type = 0; + + /* Disable the input interrupts and reset status register */ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); - /* Reset the interrupt status register */ inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG); - /* Disable the and/or interrupt */ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); - devpriv->b_DigitalOutputRegister = 0; - ui_Type = 0; - /* Resets the output channels */ + + /* Reset the output channels and disable interrupts */ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_REG); - /* Disables the interrupt. */ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_RELOAD_REG); - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_REG); + + /* Reset the watchdog registers */ + addi_watchdog_reset(devpriv->i_IobaseAmcc + APCI1564_WDOG_REG); + + /* Reset the timer registers */ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_RELOAD_REG); + + /* Reset the counter registers */ + outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); + outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); + outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); + outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); - outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); - outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); - outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); - outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c index 70e8f426285cd9..e3aa89780c2c79 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -609,11 +609,10 @@ static int apci3120_reset(struct comedi_device *dev) unsigned int i; unsigned short us_TmpValue; - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; + devpriv->ai_running = 0; devpriv->b_EocEosInterrupt = APCI3120_DISABLE; devpriv->b_InterruptMode = APCI3120_EOC_MODE; devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */ - devpriv->b_OutputMemoryStatus = 0; /* variables used in timer subdevice */ devpriv->b_Timer2Mode = 0; @@ -720,10 +719,9 @@ static int apci3120_cancel(struct comedi_device *dev, inw(dev->iobase + APCI3120_RD_STATUS); devpriv->ui_AiActualScan = 0; s->async->cur_chan = 0; - devpriv->b_AiContinuous = 0; devpriv->ui_DmaActualBuffer = 0; - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; + devpriv->ai_running = 0; devpriv->b_InterruptMode = APCI3120_EOC_MODE; devpriv->b_EocEosInterrupt = APCI3120_DISABLE; apci3120_reset(dev); @@ -734,7 +732,6 @@ static int apci3120_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct addi_board *this_board = comedi_board(dev); int err = 0; /* Step 1 : check if triggers are trivially valid */ @@ -767,20 +764,16 @@ static int apci3120_ai_cmdtest(struct comedi_device *dev, if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000); - if (cmd->convert_src == TRIG_TIMER) { /* Test Acquisition timing */ - if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->convert_arg) - err |= cfc_check_trigger_arg_min( - &cmd->convert_arg, 10000); - } else { + if (cmd->scan_begin_src == TRIG_TIMER) { + if (cmd->convert_arg) err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - 10000); - } + 10000); + } else { + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000); } err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); - err |= cfc_check_trigger_arg_max(&cmd->chanlist_len, - this_board->i_AiChannelList); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); if (cmd->stop_src == TRIG_COUNT) err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); @@ -792,15 +785,10 @@ static int apci3120_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - if (cmd->convert_src == TRIG_TIMER) { - - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; - } + if (cmd->scan_begin_src == TRIG_TIMER && + cmd->scan_begin_arg < cmd->convert_arg * cmd->scan_end_arg) { + cmd->scan_begin_arg = cmd->convert_arg * cmd->scan_end_arg; + err |= -EINVAL; } if (err) @@ -821,16 +809,13 @@ static int apci3120_cyclic_ai(int mode, { const struct addi_board *this_board = comedi_board(dev); struct addi_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned char b_Tmp; unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 = 0, dmalen1 = 0, ui_TimerValue2 = 0, ui_TimerValue0, ui_ConvertTiming; unsigned short us_TmpValue; - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */ - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - /*******************/ /* Resets the FIFO */ /*******************/ @@ -840,12 +825,7 @@ static int apci3120_cyclic_ai(int mode, /* inw(dev->iobase+APCI3120_RD_STATUS); */ /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - /***************************/ - /* Acquisition initialized */ - /***************************/ - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE; - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ + devpriv->ai_running = 1; /* clear software registers */ devpriv->b_TimerSelectMode = 0; @@ -892,17 +872,17 @@ static int apci3120_cyclic_ai(int mode, devpriv->ui_DmaActualBuffer = 0; /* value for timer2 minus -2 has to be done .....dunno y?? */ - ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2; - ui_ConvertTiming = devpriv->ui_AiTimer0; + ui_TimerValue2 = cmd->stop_arg - 2; + ui_ConvertTiming = cmd->convert_arg; if (mode == 2) - ui_DelayTiming = devpriv->ui_AiTimer1; + ui_DelayTiming = cmd->scan_begin_arg; /**********************************/ /* Initializes the sequence array */ /**********************************/ if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels, - devpriv->pui_AiChannelList, 0)) + cmd->chanlist, 0)) return -EINVAL; us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS); @@ -1039,7 +1019,7 @@ static int apci3120_cyclic_ai(int mode, outb(devpriv->b_ModeSelectRegister, dev->iobase + APCI3120_WRITE_MODE_SELECT); - if (!devpriv->b_AiContinuous) { + if (cmd->stop_src == TRIG_COUNT) { /* * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to * disable it (Set Bit D14 to 0) @@ -1107,6 +1087,7 @@ static int apci3120_cyclic_ai(int mode, } } else { /* If DMA Enabled */ + unsigned int scan_bytes = cmd->scan_end_arg * sizeof(short); /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ /* inw(dev->iobase+0); reset EOC bit */ @@ -1125,37 +1106,38 @@ static int apci3120_cyclic_ai(int mode, dmalen0 = devpriv->ui_DmaBufferSize[0]; dmalen1 = devpriv->ui_DmaBufferSize[1]; - if (!devpriv->b_AiContinuous) { - - if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { /* must we fill full first buffer? */ - dmalen0 = - devpriv->ui_AiNbrofScans * - devpriv->ui_AiScanLength * 2; - } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) /* and must we fill full second buffer when first is once filled? */ - dmalen1 = - devpriv->ui_AiNbrofScans * - devpriv->ui_AiScanLength * 2 - dmalen0; + if (cmd->stop_src == TRIG_COUNT) { + /* + * Must we fill full first buffer? And must we fill + * full second buffer when first is once filled? + */ + if (dmalen0 > (cmd->stop_arg * scan_bytes)) { + dmalen0 = cmd->stop_arg * scan_bytes; + } else if (dmalen1 > (cmd->stop_arg * scan_bytes - + dmalen0)) + dmalen1 = cmd->stop_arg * scan_bytes - + dmalen0; } - if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) { + if (cmd->flags & TRIG_WAKE_EOS) { /* don't we want wake up every scan? */ - if (dmalen0 > (devpriv->ui_AiScanLength * 2)) { - dmalen0 = devpriv->ui_AiScanLength * 2; - if (devpriv->ui_AiScanLength & 1) + if (dmalen0 > scan_bytes) { + dmalen0 = scan_bytes; + if (cmd->scan_end_arg & 1) dmalen0 += 2; } - if (dmalen1 > (devpriv->ui_AiScanLength * 2)) { - dmalen1 = devpriv->ui_AiScanLength * 2; - if (devpriv->ui_AiScanLength & 1) + if (dmalen1 > scan_bytes) { + dmalen1 = scan_bytes; + if (cmd->scan_end_arg & 1) dmalen1 -= 2; if (dmalen1 < 4) dmalen1 = 4; } } else { /* isn't output buff smaller that our DMA buff? */ - if (dmalen0 > (devpriv->ui_AiDataLength)) - dmalen0 = devpriv->ui_AiDataLength; - if (dmalen1 > (devpriv->ui_AiDataLength)) - dmalen1 = devpriv->ui_AiDataLength; + if (dmalen0 > s->async->prealloc_bufsz) + dmalen0 = s->async->prealloc_bufsz; + if (dmalen1 > s->async->prealloc_bufsz) + dmalen1 = s->async->prealloc_bufsz; } devpriv->ui_DmaBufferUsesize[0] = dmalen0; devpriv->ui_DmaBufferUsesize[1] = dmalen1; @@ -1293,8 +1275,8 @@ static int apci3120_cyclic_ai(int mode, /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ } - if ((devpriv->us_UseDma == APCI3120_DISABLE) - && !devpriv->b_AiContinuous) { + if (devpriv->us_UseDma == APCI3120_DISABLE && + cmd->stop_src == TRIG_COUNT) { /* set gate 2 to start conversion */ devpriv->us_OutputRegister = devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2; @@ -1337,50 +1319,17 @@ static int apci3120_ai_cmd(struct comedi_device *dev, struct comedi_cmd *cmd = &s->async->cmd; /* loading private structure with cmd structure inputs */ - devpriv->ui_AiFlags = cmd->flags; devpriv->ui_AiNbrofChannels = cmd->chanlist_len; - devpriv->ui_AiScanLength = cmd->scan_end_arg; - devpriv->pui_AiChannelList = cmd->chanlist; - - /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */ - devpriv->ui_AiDataLength = s->async->prealloc_bufsz; - - if (cmd->stop_src == TRIG_COUNT) - devpriv->ui_AiNbrofScans = cmd->stop_arg; - else - devpriv->ui_AiNbrofScans = 0; - - devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */ - devpriv->ui_AiTimer1 = 0; - if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1)) - devpriv->b_AiContinuous = 1; /* user want neverending analog acquisition */ - /* stopped using cancel */ if (cmd->start_src == TRIG_EXT) devpriv->b_ExttrigEnable = APCI3120_ENABLE; else devpriv->b_ExttrigEnable = APCI3120_DISABLE; - if (cmd->scan_begin_src == TRIG_FOLLOW) { - /* mode 1 or 3 */ - if (cmd->convert_src == TRIG_TIMER) { - /* mode 1 */ - - devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */ - /* return this_board->ai_cmd(1,dev,s); */ - return apci3120_cyclic_ai(1, dev, s); - } - - } - if ((cmd->scan_begin_src == TRIG_TIMER) - && (cmd->convert_src == TRIG_TIMER)) { - /* mode 2 */ - devpriv->ui_AiTimer1 = cmd->scan_begin_arg; - devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */ - /* return this_board->ai_cmd(2,dev,s); */ + if (cmd->scan_begin_src == TRIG_FOLLOW) + return apci3120_cyclic_ai(1, dev, s); + else /* TRIG_TIMER */ return apci3120_cyclic_ai(2, dev, s); - } - return -1; } /* @@ -1392,11 +1341,12 @@ static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, unsigned int num_samples) { struct addi_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; devpriv->ui_AiActualScan += - (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength; + (s->async->cur_chan + num_samples) / cmd->scan_end_arg; s->async->cur_chan += num_samples; - s->async->cur_chan %= devpriv->ui_AiScanLength; + s->async->cur_chan %= cmd->scan_end_arg; cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short)); } @@ -1412,6 +1362,7 @@ static void apci3120_interrupt_dma(int irq, void *d) struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int next_dma_buf, samplesinbuf; unsigned long low_word, high_word, var; unsigned int ui_Tmp; @@ -1427,8 +1378,6 @@ static void apci3120_interrupt_dma(int irq, void *d) if (samplesinbuf & 1) { comedi_error(dev, "Odd count of bytes in DMA ring!"); apci3120_cancel(dev, s); - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; - return; } samplesinbuf = samplesinbuf >> 1; /* number of received samples */ @@ -1489,16 +1438,15 @@ static void apci3120_interrupt_dma(int irq, void *d) devpriv->ul_DmaBufferVirtual[devpriv-> ui_DmaActualBuffer], samplesinbuf); - if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) { + if (!(cmd->flags & TRIG_WAKE_EOS)) { s->async->events |= COMEDI_CB_EOS; comedi_event(dev, s); } } - if (!devpriv->b_AiContinuous) - if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) { + if (cmd->stop_src == TRIG_COUNT) + if (devpriv->ui_AiActualScan >= cmd->stop_arg) { /* all data sampled */ apci3120_cancel(dev, s); - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); return; @@ -1648,7 +1596,7 @@ static void apci3120_interrupt(int irq, void *d) if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */ - if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) { + if (devpriv->ai_running) { ui_Check = 0; apci3120_interrupt_handle_eos(dev); devpriv->ui_AiActualScan++; @@ -1690,8 +1638,6 @@ static void apci3120_interrupt(int irq, void *d) switch (devpriv->b_Timer2Mode) { case APCI3120_COUNTER: - - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT; @@ -1707,7 +1653,6 @@ static void apci3120_interrupt(int irq, void *d) /* stop timer 0 and timer 1 */ apci3120_cancel(dev, s); - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */ s->async->events |= COMEDI_CB_EOA; @@ -1746,7 +1691,7 @@ static void apci3120_interrupt(int irq, void *d) } if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) { - if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) { + if (devpriv->ai_running) { /****************************/ /* Clear Timer Write TC int */ diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index 0536d837386165..9b8851c7e07214 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -2221,12 +2221,11 @@ static int apci3200_ai_cmdtest(struct comedi_device *dev, unsigned int ui_ConvertTimeBase = 0; unsigned int ui_DelayTime = 0; unsigned int ui_DelayTimeBase = 0; - int i_Triggermode = 0; - int i_TriggerEdge = 0; int i_NbrOfChannel = 0; int i_Cpt = 0; double d_ConversionTimeForAllChannels = 0.0; double d_SCANTimeNewUnit = 0.0; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -2253,23 +2252,37 @@ static int apci3200_ai_cmdtest(struct comedi_device *dev, /* Step 2b : and mutually compatible */ - if (cmd->start_src == TRIG_EXT) { - i_TriggerEdge = cmd->start_arg & 0xFFFF; - i_Triggermode = cmd->start_arg >> 16; - if (i_TriggerEdge < 1 || i_TriggerEdge > 3) { - err++; - printk("\nThe trigger edge selection is in error\n"); - } - if (i_Triggermode != 2) { - err++; - printk("\nThe trigger mode selection is in error\n"); - } - } - if (err) { apci3200_reset(dev); return 2; } + + /* Step 3: check if arguments are trivially valid */ + + switch (cmd->start_src) { + case TRIG_NOW: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + /* validate the trigger edge selection */ + arg = cmd->start_arg & 0xffff; + if (arg < 1 || arg > 3) { + cmd->start_arg &= ~0xffff; + cmd->start_arg |= 1; + err |= -EINVAL; + } + /* validate the trigger mode selection */ + arg = cmd->start_arg >> 16; + if (arg != 2) { + cmd->start_arg &= ~(0xffff << 16); + cmd->start_arg |= (2 << 16); + err |= -EINVAL; + } + break; + } + + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + /* i_FirstChannel=cmd->chanlist[0]; */ s_BoardInfos[dev->minor].i_FirstChannel = cmd->chanlist[0]; /* i_LastChannel=cmd->chanlist[1]; */ diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index 0daa0ea63b5ef1..c242afc9134d69 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -198,7 +198,7 @@ static int apci1032_cos_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -332,6 +332,7 @@ static int apci1032_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_config = apci1032_cos_insn_config; s->insn_bits = apci1032_cos_insn_bits; + s->len_chanlist = 1; s->do_cmdtest = apci1032_cos_cmdtest; s->do_cmd = apci1032_cos_cmd; s->cancel = apci1032_cos_cancel; @@ -379,5 +380,5 @@ static struct pci_driver apci1032_pci_driver = { module_comedi_pci_driver(apci1032_driver, apci1032_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-1032, 32 channel DI boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c index bd8e08ca14c02f..eab75eb2647816 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1500.c +++ b/drivers/staging/comedi/drivers/addi_apci_1500.c @@ -72,5 +72,5 @@ static struct pci_driver apci1500_pci_driver = { module_comedi_pci_driver(apci1500_driver, apci1500_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-1500, 16 channel DI / 16 channel DO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 27aa9ae1bdd9e3..ea22530a5cbd3d 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -3,28 +3,20 @@ #include "../comedidev.h" #include "comedi_fc.h" -#include "amcc_s5933.h" #include "addi-data/addi_common.h" -#include "addi-data/addi_eeprom.c" #include "addi-data/hwdrv_apci1564.c" -#include "addi-data/addi_common.c" static const struct addi_board apci1564_boardtypes[] = { { .pc_DriverName = "apci1564", - .i_IorangeBase1 = APCI1564_ADDRESS_RANGE, - .i_PCIEeprom = ADDIDATA_EEPROM, - .pc_EepromChip = ADDIDATA_93C76, .i_NbrDiChannel = 32, .i_NbrDoChannel = 32, .i_DoMaxdata = 0xffffffff, .i_Timer = 1, .interrupt = apci1564_interrupt, .reset = apci1564_reset, - .di_config = apci1564_di_config, - .di_bits = apci1564_di_insn_bits, .do_config = apci1564_do_config, .do_bits = apci1564_do_insn_bits, .do_read = apci1564_do_read, @@ -34,19 +26,144 @@ static const struct addi_board apci1564_boardtypes[] = { }, }; +static irqreturn_t v_ADDI_Interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + const struct addi_board *this_board = comedi_board(dev); + + this_board->interrupt(irq, d); + return IRQ_RETVAL(1); +} + +static int i_ADDI_Reset(struct comedi_device *dev) +{ + const struct addi_board *this_board = comedi_board(dev); + + this_board->reset(dev); + return 0; +} + static int apci1564_auto_attach(struct comedi_device *dev, - unsigned long context) + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct addi_board *this_board = comedi_board(dev); + struct addi_private *devpriv; + struct comedi_subdevice *s; + int ret, n_subdevices; + + dev->board_name = this_board->pc_DriverName; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 1); + devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); + + if (pcidev->irq > 0) { + ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + + n_subdevices = 7; + ret = comedi_alloc_subdevices(dev, n_subdevices); + if (ret) + return ret; + + /* Allocate and Initialise AI Subdevice Structures */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_UNUSED; + + /* Allocate and Initialise AO Subdevice Structures */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_UNUSED; + + /* Allocate and Initialise DI Subdevice Structures */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 32; + s->maxdata = 1; + s->len_chanlist = 32; + s->range_table = &range_digital; + s->insn_config = apci1564_di_config; + s->insn_bits = apci1564_di_insn_bits; + + /* Allocate and Initialise DO Subdevice Structures */ + s = &dev->subdevices[3]; + if (this_board->i_NbrDoChannel) { + s->type = COMEDI_SUBD_DO; + s->subdev_flags = + SDF_READABLE | SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = this_board->i_NbrDoChannel; + s->maxdata = this_board->i_DoMaxdata; + s->len_chanlist = this_board->i_NbrDoChannel; + s->range_table = &range_digital; + + /* insn_config - for digital output memory */ + s->insn_config = this_board->do_config; + s->insn_write = this_board->do_write; + s->insn_bits = this_board->do_bits; + s->insn_read = this_board->do_read; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* Allocate and Initialise Timer Subdevice Structures */ + s = &dev->subdevices[4]; + if (this_board->i_Timer) { + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 1; + s->maxdata = 0; + s->len_chanlist = 1; + s->range_table = &range_digital; + + s->insn_write = this_board->timer_write; + s->insn_read = this_board->timer_read; + s->insn_config = this_board->timer_config; + s->insn_bits = this_board->timer_bits; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* Allocate and Initialise TTL */ + s = &dev->subdevices[5]; + s->type = COMEDI_SUBD_UNUSED; + + /* EEPROM */ + s = &dev->subdevices[6]; + s->type = COMEDI_SUBD_UNUSED; + + i_ADDI_Reset(dev); + return 0; +} + +static void apci1564_detach(struct comedi_device *dev) { - dev->board_ptr = &apci1564_boardtypes[0]; + struct addi_private *devpriv = dev->private; - return addi_auto_attach(dev, context); + if (devpriv) { + if (dev->iobase) + i_ADDI_Reset(dev); + if (dev->irq) + free_irq(dev->irq, dev); + } + comedi_pci_disable(dev); } static struct comedi_driver apci1564_driver = { .driver_name = "addi_apci_1564", .module = THIS_MODULE, .auto_attach = apci1564_auto_attach, - .detach = i_ADDI_Detach, + .detach = apci1564_detach, }; static int apci1564_pci_probe(struct pci_dev *dev, @@ -70,5 +187,5 @@ static struct pci_driver apci1564_pci_driver = { module_comedi_pci_driver(apci1564_driver, apci1564_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-1564, 32 channel DI / 32 channel DO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c index c9b933cb5987c0..2fd14553e57c73 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -197,6 +197,7 @@ static irqreturn_t apci2032_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; struct apci2032_int_private *subpriv; unsigned int val; bool do_event = false; @@ -222,21 +223,20 @@ static irqreturn_t apci2032_interrupt(int irq, void *d) */ if (subpriv->active && (val & subpriv->enabled_isns) != 0) { - unsigned short bits; - unsigned int n, len; - unsigned int *chanlist; + unsigned short bits = 0; + int i; /* Bits in scan data correspond to indices in channel list. */ - bits = 0; - len = s->async->cmd.chanlist_len; - chanlist = &s->async->cmd.chanlist[0]; - for (n = 0; n < len; n++) - if ((val & (1U << CR_CHAN(chanlist[n]))) != 0) - bits |= 1U << n; + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (val & (1 << chan)) + bits |= (1 << i); + } if (comedi_buf_put(s->async, bits)) { s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - if (s->async->cmd.stop_src == TRIG_COUNT && + if (cmd->stop_src == TRIG_COUNT && subpriv->stop_count > 0) { subpriv->stop_count--; if (subpriv->stop_count == 0) { @@ -374,5 +374,5 @@ static struct pci_driver apci2032_pci_driver = { module_comedi_pci_driver(apci2032_driver, apci2032_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-2032, 32 channel DO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index 57ee6e5c76355a..0cfb12fa1cbc8d 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -246,5 +246,5 @@ static struct pci_driver apci3120_pci_driver = { module_comedi_pci_driver(apci3120_driver, apci3120_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-3120, Analog input board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index 6dc11c407f572e..f290be8188453b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -573,26 +573,6 @@ static int apci3xxx_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - /* - * FIXME: The hardware supports multiple scan modes but the original - * addi-data driver only supported reading a single channel with - * interrupts. Need a proper datasheet to fix this. - * - * The following scan modes are supported by the hardware: - * 1) Single software scan - * 2) Single hardware triggered scan - * 3) Continuous software scan - * 4) Continuous software scan with timer delay - * 5) Continuous hardware triggered scan - * 6) Continuous hardware triggered scan with timer delay - * - * For now, limit the chanlist to a single channel. - */ - if (cmd->chanlist_len > 1) { - cmd->chanlist_len = 1; - err |= -EINVAL; - } - tmp = cmd->convert_arg; err |= apci3xxx_ai_ns_to_timer(dev, &cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); @@ -719,7 +699,8 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev, if (chan < 16) return -EINVAL; else - /* changing any channel in port 2 changes the entire port */ + /* changing any channel in port 2 */ + /* changes the entire port */ mask = 0xff0000; } @@ -842,12 +823,30 @@ static int apci3xxx_auto_attach(struct comedi_device *dev, s->subdev_flags = SDF_READABLE | board->ai_subdev_flags; s->n_chan = board->ai_n_chan; s->maxdata = board->ai_maxdata; - s->len_chanlist = s->n_chan; s->range_table = &apci3xxx_ai_range; s->insn_read = apci3xxx_ai_insn_read; if (dev->irq) { + /* + * FIXME: The hardware supports multiple scan modes + * but the original addi-data driver only supported + * reading a single channel with interrupts. Need a + * proper datasheet to fix this. + * + * The following scan modes are supported by the + * hardware: + * 1) Single software scan + * 2) Single hardware triggered scan + * 3) Continuous software scan + * 4) Continuous software scan with timer delay + * 5) Continuous hardware triggered scan + * 6) Continuous hardware triggered scan with timer + * delay + * + * For now, limit the chanlist to a single channel. + */ dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 1; s->do_cmdtest = apci3xxx_ai_cmdtest; s->do_cmd = apci3xxx_ai_cmd; s->cancel = apci3xxx_ai_cancel; diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index a29ceacb966ddb..96b1bf84d57b79 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -314,148 +314,141 @@ static int pci9111_ai_cancel(struct comedi_device *dev, return 0; } +static int pci9111_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (chan != i) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels,counting upwards from 0\n"); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same gain\n"); + return -EINVAL; + } + + if (aref != aref0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same reference\n"); + return -EINVAL; + } + } + + return 0; +} + static int pci9111_ai_do_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { struct pci9111_private_data *dev_private = dev->private; - int tmp; - int error = 0; - int range, reference; - int i; + int err = 0; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ - error |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - error |= cfc_check_trigger_src(&cmd->scan_begin_src, + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); - error |= cfc_check_trigger_src(&cmd->convert_src, + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); - error |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - error |= cfc_check_trigger_src(&cmd->stop_src, + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - if (error) + if (err) return 1; /* Step 2a : make sure trigger sources are unique */ - error |= cfc_check_trigger_is_unique(cmd->scan_begin_src); - error |= cfc_check_trigger_is_unique(cmd->convert_src); - error |= cfc_check_trigger_is_unique(cmd->stop_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); /* Step 2b : and mutually compatible */ - if ((cmd->convert_src == TRIG_TIMER) && - !((cmd->scan_begin_src == TRIG_TIMER) || - (cmd->scan_begin_src == TRIG_FOLLOW))) - error |= -EINVAL; - if ((cmd->convert_src == TRIG_EXT) && - !((cmd->scan_begin_src == TRIG_EXT) || - (cmd->scan_begin_src == TRIG_FOLLOW))) - error |= -EINVAL; + if (cmd->scan_begin_src != TRIG_FOLLOW) { + if (cmd->scan_begin_src != cmd->convert_src) + err |= -EINVAL; + } - if (error) + if (err) return 2; /* Step 3: check if arguments are trivially valid */ - error |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); if (cmd->convert_src == TRIG_TIMER) - error |= cfc_check_trigger_arg_min(&cmd->convert_arg, + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, PCI9111_AI_ACQUISITION_PERIOD_MIN_NS); else /* TRIG_EXT */ - error |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); if (cmd->scan_begin_src == TRIG_TIMER) - error |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, PCI9111_AI_ACQUISITION_PERIOD_MIN_NS); else /* TRIG_FOLLOW || TRIG_EXT */ - error |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - error |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, - cmd->chanlist_len); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); if (cmd->stop_src == TRIG_COUNT) - error |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); else /* TRIG_NONE */ - error |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - if (error) + if (err) return 3; - /* Step 4 : fix up any arguments */ + /* Step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; + arg = cmd->convert_arg; i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, &dev_private->div1, &dev_private->div2, &cmd->convert_arg, cmd->flags); - if (tmp != cmd->convert_arg) - error++; + if (cmd->convert_arg != arg) + err |= -EINVAL; } - /* There's only one timer on this card, so the scan_begin timer must */ - /* be a multiple of chanlist_len*convert_arg */ + /* + * There's only one timer on this card, so the scan_begin timer + * must be a multiple of chanlist_len*convert_arg + */ if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->chanlist_len * cmd->convert_arg; - unsigned int scan_begin_min; - unsigned int scan_begin_arg; - unsigned int scan_factor; - - scan_begin_min = cmd->chanlist_len * cmd->convert_arg; + if (arg < cmd->scan_begin_arg) + arg *= (cmd->scan_begin_arg / arg); - if (cmd->scan_begin_arg != scan_begin_min) { - if (scan_begin_min < cmd->scan_begin_arg) { - scan_factor = - cmd->scan_begin_arg / scan_begin_min; - scan_begin_arg = scan_factor * scan_begin_min; - if (cmd->scan_begin_arg != scan_begin_arg) { - cmd->scan_begin_arg = scan_begin_arg; - error++; - } - } else { - cmd->scan_begin_arg = scan_begin_min; - error++; - } + if (cmd->scan_begin_arg != arg) { + cmd->scan_begin_arg = arg; + err |= -EINVAL; } } - if (error) + if (err) return 4; - /* Step 5 : check channel list */ - - if (cmd->chanlist) { - - range = CR_RANGE(cmd->chanlist[0]); - reference = CR_AREF(cmd->chanlist[0]); - - if (cmd->chanlist_len > 1) { - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != i) { - comedi_error(dev, - "entries in chanlist must be consecutive " - "channels,counting upwards from 0\n"); - error++; - } - if (CR_RANGE(cmd->chanlist[i]) != range) { - comedi_error(dev, - "entries in chanlist must all have the same gain\n"); - error++; - } - if (CR_AREF(cmd->chanlist[i]) != reference) { - comedi_error(dev, - "entries in chanlist must all have the same reference\n"); - error++; - } - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= pci9111_ai_check_chanlist(dev, s, cmd); - if (error) + if (err) return 5; return 0; diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index 3cfa1756fa6aa2..4be5f67cf14ad1 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -96,7 +96,7 @@ Configuration options: * correct channel number on every 12 bit sample */ -#define IORANGE_9118 64 /* I hope */ +#define IORANGE_9118 64 /* I hope */ #define PCI9118_CHANLEN 255 /* * len of chanlist, some source say 256, * but reality looks like 255 :-( @@ -383,7 +383,7 @@ struct pci9118_private { * users(0-AI, 1-AO, 2-DI, 3-DO) */ unsigned int cnt0_divisor; /* actual CNT0 divisor */ - void (*int_ai_func) (struct comedi_device *, struct comedi_subdevice *, + void (*int_ai_func)(struct comedi_device *, struct comedi_subdevice *, unsigned short, unsigned int, unsigned short); /* @@ -411,7 +411,6 @@ struct pci9118_private { */ unsigned int ai_maskerr; /* which warning was printed */ unsigned int ai_maskharderr; /* on which error bits stops */ - unsigned int ai_inttrig_start; /* TRIG_INT for start */ }; static int check_channel_list(struct comedi_device *dev, @@ -1045,7 +1044,7 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, move_block_from_dma(dev, s, devpriv->dmabuf_virt[devpriv->dma_actbuf], samplesinbuf); - m = m - sampls; /* m= how many samples was transferred */ + m = m - sampls; /* m=how many samples was transferred */ } if (!devpriv->ai_neverending) { @@ -1135,11 +1134,13 @@ static irqreturn_t interrupt_pci9118(int irq, void *d) } static int pci9118_ai_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - if (trignum != devpriv->ai_inttrig_start) + if (trig_num != cmd->start_arg) return -EINVAL; devpriv->ai12_startstop &= ~START_AI_INT; @@ -1221,8 +1222,15 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src & (TRIG_NOW | TRIG_EXT)) + switch (cmd->start_src) { + case TRIG_NOW: + case TRIG_EXT: err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_INT: + /* start_arg is the internal trigger (any value) */ + break; + } if (cmd->scan_begin_src & (TRIG_FOLLOW | TRIG_EXT)) err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); @@ -1259,8 +1267,6 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); - err |= cfc_check_trigger_arg_max(&cmd->chanlist_len, - this_board->n_aichanlist); err |= cfc_check_trigger_arg_min(&cmd->scan_end_arg, cmd->chanlist_len); @@ -1629,7 +1635,6 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } if (cmd->start_src == TRIG_INT) { devpriv->ai12_startstop |= START_AI_INT; - devpriv->ai_inttrig_start = cmd->start_arg; s->async->inttrig = pci9118_ai_inttrig; } #if 0 diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index 28ec48548317ca..0dc946eaa74357 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -51,10 +51,6 @@ Configuration options: #include "8253.h" #include "amcc_s5933.h" -#define PCI171x_PARANOIDCHECK /* if defined, then is used code which control - * correct channel number on every 12 bit - * sample */ - /* hardware types of the cards */ #define TYPE_PCI171X 0 #define TYPE_PCI1713 2 @@ -73,6 +69,9 @@ Configuration options: #define PCI171x_DAREF 14 /* W: D/A reference control */ #define PCI171x_DI 16 /* R: digi inputs */ #define PCI171x_DO 16 /* R: digi inputs */ + +#define PCI171X_TIMER_BASE 0x18 + #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */ #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */ #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */ @@ -298,29 +297,18 @@ static const struct boardtype boardtypes[] = { }; struct pci1710_private { - char neverending_ai; /* we do unlimited AI */ unsigned int CntrlReg; /* Control register */ - unsigned int i8254_osc_base; /* frequence of onboard oscilator */ - unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */ unsigned int ai_act_scan; /* how many scans we finished */ - unsigned int ai_act_chan; /* actual position in actual scan */ - unsigned int ai_buf_ptr; /* data buffer ptr in samples */ - unsigned char ai_eos; /* 1=EOS wake up */ unsigned char ai_et; unsigned int ai_et_CntrlReg; unsigned int ai_et_MuxVal; - unsigned int ai_et_div1, ai_et_div2; + unsigned int next_divisor1; + unsigned int next_divisor2; + unsigned int divisor1; + unsigned int divisor2; unsigned int act_chanlist[32]; /* list of scanned channel */ - unsigned char act_chanlist_len; /* len of scanlist */ - unsigned char act_chanlist_pos; /* actual position in MUX list */ + unsigned char saved_seglen; /* len of the non-repeating chanlist */ unsigned char da_ranges; /* copy of D/A outpit range register */ - unsigned int ai_scans; /* len of scanlist */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int *ai_chanlist; /* actaul chanlist */ - unsigned int ai_flags; /* flaglist */ - unsigned int ai_data_len; /* len of data buffer */ - unsigned int ai_timer1; /* timers */ - unsigned int ai_timer2; unsigned short ao_data[4]; /* data output buffer */ unsigned int cnt0_write_wait; /* after a write, wait for update of the * internal state */ @@ -334,62 +322,90 @@ static const unsigned int muxonechan[] = { 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f }; -/* -============================================================================== - Check if channel list from user is built correctly - If it's ok, then program scan/gain logic. - This works for all cards. -*/ -static int check_channel_list(struct comedi_device *dev, +static int pci171x_ai_dropout(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan) + unsigned int chan, + unsigned int val) +{ + const struct boardtype *board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; + + if (board->cardtype != TYPE_PCI1713) { + if ((val & 0xf000) != devpriv->act_chanlist[chan]) { + dev_err(dev->class_dev, + "A/D data droput: received from channel %d, expected %d\n", + (val >> 12) & 0xf, + (devpriv->act_chanlist[chan] >> 12) & 0xf); + return -ENODATA; + } + } + return 0; +} + +static int pci171x_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { + struct pci1710_private *devpriv = dev->private; + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int last_aref = CR_AREF(cmd->chanlist[0]); + unsigned int next_chan = (chan0 + 1) % s->n_chan; unsigned int chansegment[32]; - unsigned int i, nowmustbechan, seglen, segpos; + unsigned int seglen; + int i; - /* correct channel and range number check itself comedi/range.c */ - if (n_chan < 1) { - comedi_error(dev, "range/channel list is empty!"); + if (cmd->chanlist_len == 1) { + devpriv->saved_seglen = cmd->chanlist_len; return 0; } - if (n_chan == 1) - return 1; /* seglen=1 */ + /* first channel is always ok */ + chansegment[0] = cmd->chanlist[0]; - chansegment[0] = chanlist[0]; /* first channel is every time ok */ - for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { - if (chanlist[0] == chanlist[i]) + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (cmd->chanlist[0] == cmd->chanlist[i]) break; /* we detected a loop, stop */ - if ((CR_CHAN(chanlist[i]) & 1) && - (CR_AREF(chanlist[i]) == AREF_DIFF)) { - comedi_error(dev, "Odd channel cannot be differential input!\n"); - return 0; + + if (aref == AREF_DIFF && (chan & 1)) { + dev_err(dev->class_dev, + "Odd channel cannot be differential input!\n"); + return -EINVAL; } - nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; - if (CR_AREF(chansegment[i - 1]) == AREF_DIFF) - nowmustbechan = (nowmustbechan + 1) % s->n_chan; - if (nowmustbechan != CR_CHAN(chanlist[i])) { - printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", - i, CR_CHAN(chanlist[i]), nowmustbechan, - CR_CHAN(chanlist[0])); - return 0; + + if (last_aref == AREF_DIFF) + next_chan = (next_chan + 1) % s->n_chan; + if (chan != next_chan) { + dev_err(dev->class_dev, + "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", + i, chan, next_chan, chan0); + return -EINVAL; } - chansegment[i] = chanlist[i]; /* next correct channel in list */ - } - for (i = 0, segpos = 0; i < n_chan; i++) { - if (chanlist[i] != chansegment[i % seglen]) { - printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", - i, CR_CHAN(chansegment[i]), - CR_RANGE(chansegment[i]), - CR_AREF(chansegment[i]), - CR_CHAN(chanlist[i % seglen]), - CR_RANGE(chanlist[i % seglen]), - CR_AREF(chansegment[i % seglen])); - return 0; + /* next correct channel in list */ + chansegment[i] = cmd->chanlist[i]; + last_aref = aref; + } + seglen = i; + + for (i = 0; i < cmd->chanlist_len; i++) { + if (cmd->chanlist[i] != chansegment[i % seglen]) { + dev_err(dev->class_dev, + "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", + i, CR_CHAN(chansegment[i]), + CR_RANGE(chansegment[i]), + CR_AREF(chansegment[i]), + CR_CHAN(cmd->chanlist[i % seglen]), + CR_RANGE(cmd->chanlist[i % seglen]), + CR_AREF(chansegment[i % seglen])); + return -EINVAL; } } - return seglen; + devpriv->saved_seglen = seglen; + + return 0; } static void setup_channel_list(struct comedi_device *dev, @@ -401,9 +417,6 @@ static void setup_channel_list(struct comedi_device *dev, struct pci1710_private *devpriv = dev->private; unsigned int i, range, chanprog; - devpriv->act_chanlist_len = seglen; - devpriv->act_chanlist_pos = 0; - for (i = 0; i < seglen; i++) { /* store range list to card */ chanprog = muxonechan[CR_CHAN(chanlist[i])]; outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */ @@ -411,17 +424,13 @@ static void setup_channel_list(struct comedi_device *dev, if (CR_AREF(chanlist[i]) == AREF_DIFF) range |= 0x0020; outw(range, dev->iobase + PCI171x_RANGE); /* select gain */ -#ifdef PCI171x_PARANOIDCHECK devpriv->act_chanlist[i] = (CR_CHAN(chanlist[i]) << 12) & 0xf000; -#endif } -#ifdef PCI171x_PARANOIDCHECK for ( ; i < n_chan; i++) { /* store remainder of channel list */ devpriv->act_chanlist[i] = (CR_CHAN(chanlist[i]) << 12) & 0xf000; } -#endif devpriv->ai_et_MuxVal = CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8); @@ -447,12 +456,9 @@ static int pci171x_insn_read_ai(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { struct pci1710_private *devpriv = dev->private; - int ret; - int n; -#ifdef PCI171x_PARANOIDCHECK - const struct boardtype *this_board = comedi_board(dev); - unsigned int idata; -#endif + unsigned int chan = CR_CHAN(insn->chanspec); + int ret = 0; + int i; devpriv->CntrlReg &= Control_CNT0; devpriv->CntrlReg |= Control_SW; /* set software trigger */ @@ -462,34 +468,27 @@ static int pci171x_insn_read_ai(struct comedi_device *dev, setup_channel_list(dev, s, &insn->chanspec, 1, 1); - for (n = 0; n < insn->n; n++) { + for (i = 0; i < insn->n; i++) { + unsigned int val; + outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */ ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0); - if (ret) { - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); - return ret; - } + if (ret) + break; -#ifdef PCI171x_PARANOIDCHECK - idata = inw(dev->iobase + PCI171x_AD_DATA); - if (this_board->cardtype != TYPE_PCI1713) - if ((idata & 0xf000) != devpriv->act_chanlist[0]) { - comedi_error(dev, "A/D insn data droput!"); - return -ETIME; - } - data[n] = idata & 0x0fff; -#else - data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff; -#endif + val = inw(dev->iobase + PCI171x_AD_DATA); + ret = pci171x_ai_dropout(dev, s, chan, val); + if (ret) + break; + data[i] = val & s->maxdata; } outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); - return n; + return ret ? ret : insn->n; } /* @@ -571,20 +570,18 @@ static int pci171x_insn_bits_do(struct comedi_device *dev, return insn->n; } -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) +static void pci171x_start_pacer(struct comedi_device *dev, + bool load_counters) { - outw(0xb4, dev->iobase + PCI171x_CNTCTRL); - outw(0x74, dev->iobase + PCI171x_CNTCTRL); - - if (mode == 1) { - outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2); - outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2); - outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1); - outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1); + struct pci1710_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE; + + i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY); + + if (load_counters) { + i8254_write(timer_base, 1, 2, devpriv->divisor2); + i8254_write(timer_base, 1, 1, devpriv->divisor1); } } @@ -727,45 +724,37 @@ static int pci171x_ai_cancel(struct comedi_device *dev, devpriv->CntrlReg |= Control_SW; outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ - start_pacer(dev, -1, 0, 0); + pci171x_start_pacer(dev, false); outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); break; } - devpriv->ai_do = 0; devpriv->ai_act_scan = 0; s->async->cur_chan = 0; - devpriv->ai_buf_ptr = 0; - devpriv->neverending_ai = 0; return 0; } -/* -============================================================================== -*/ -static void interrupt_pci1710_every_sample(void *d) +static void pci1710_handle_every_sample(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pci1710_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - int m; -#ifdef PCI171x_PARANOIDCHECK - const struct boardtype *this_board = comedi_board(dev); - unsigned short sampl; -#endif + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int status; + unsigned int val; + int ret; - m = inw(dev->iobase + PCI171x_STATUS); - if (m & Status_FE) { - dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", m); + status = inw(dev->iobase + PCI171x_STATUS); + if (status & Status_FE) { + dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; cfc_handle_events(dev, s); return; } - if (m & Status_FF) { + if (status & Status_FF) { dev_dbg(dev->class_dev, - "A/D FIFO Full status (Fatal Error!) (%4x)\n", m); + "A/D FIFO Full status (Fatal Error!) (%4x)\n", status); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; cfc_handle_events(dev, s); return; @@ -774,42 +763,27 @@ static void interrupt_pci1710_every_sample(void *d) outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) { -#ifdef PCI171x_PARANOIDCHECK - sampl = inw(dev->iobase + PCI171x_AD_DATA); - if (this_board->cardtype != TYPE_PCI1713) - if ((sampl & 0xf000) != - devpriv->act_chanlist[s->async->cur_chan]) { - printk - ("comedi: A/D data dropout: received data from channel %d, expected %d!\n", - (sampl & 0xf000) >> 12, - (devpriv-> - act_chanlist[s-> - async->cur_chan] & 0xf000) >> - 12); - s->async->events |= - COMEDI_CB_EOA | COMEDI_CB_ERROR; - cfc_handle_events(dev, s); - return; - } - comedi_buf_put(s->async, sampl & 0x0fff); -#else - comedi_buf_put(s->async, - inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff); -#endif - ++s->async->cur_chan; + val = inw(dev->iobase + PCI171x_AD_DATA); + ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val); + if (ret) { + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + break; + } - if (s->async->cur_chan >= devpriv->ai_n_chan) + comedi_buf_put(s->async, val & s->maxdata); + + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) s->async->cur_chan = 0; if (s->async->cur_chan == 0) { /* one scan done */ devpriv->ai_act_scan++; - if ((!devpriv->neverending_ai) && - (devpriv->ai_act_scan >= devpriv->ai_scans)) { + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { /* all data sampled */ s->async->events |= COMEDI_CB_EOA; - cfc_handle_events(dev, s); - return; + break; } } } @@ -826,53 +800,37 @@ static int move_block_from_fifo(struct comedi_device *dev, struct comedi_subdevice *s, int n, int turn) { struct pci1710_private *devpriv = dev->private; - int i, j; -#ifdef PCI171x_PARANOIDCHECK - const struct boardtype *this_board = comedi_board(dev); - unsigned short sampl; -#endif + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int val; + int ret; + int i; - j = s->async->cur_chan; for (i = 0; i < n; i++) { -#ifdef PCI171x_PARANOIDCHECK - sampl = inw(dev->iobase + PCI171x_AD_DATA); - if (this_board->cardtype != TYPE_PCI1713) - if ((sampl & 0xf000) != devpriv->act_chanlist[j]) { - dev_dbg(dev->class_dev, - "A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n", - (sampl & 0xf000) >> 12, - (devpriv->act_chanlist[j] & 0xf000) >> 12, - i, j, devpriv->ai_act_scan, n, turn, - sampl); - s->async->events |= - COMEDI_CB_EOA | COMEDI_CB_ERROR; - cfc_handle_events(dev, s); - return 1; - } - comedi_buf_put(s->async, sampl & 0x0fff); -#else - comedi_buf_put(s->async, - inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff); -#endif - j++; - if (j >= devpriv->ai_n_chan) { - j = 0; + val = inw(dev->iobase + PCI171x_AD_DATA); + + ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val); + if (ret) { + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return ret; + } + + comedi_buf_put(s->async, val & s->maxdata); + + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; devpriv->ai_act_scan++; } } - s->async->cur_chan = j; return 0; } -/* -============================================================================== -*/ -static void interrupt_pci1710_half_fifo(void *d) +static void pci1710_handle_fifo(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; const struct boardtype *this_board = comedi_board(dev); struct pci1710_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; int m, samplesinbuf; m = inw(dev->iobase + PCI171x_STATUS); @@ -891,8 +849,8 @@ static void interrupt_pci1710_half_fifo(void *d) } samplesinbuf = this_board->fifo_half_size; - if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) { - m = devpriv->ai_data_len / sizeof(short); + if (samplesinbuf * sizeof(short) >= s->async->prealloc_bufsz) { + m = s->async->prealloc_bufsz / sizeof(short); if (move_block_from_fifo(dev, s, m, 0)) return; samplesinbuf -= m; @@ -903,13 +861,13 @@ static void interrupt_pci1710_half_fifo(void *d) return; } - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data - sampled */ - s->async->events |= COMEDI_CB_EOA; - cfc_handle_events(dev, s); - return; - } + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + cfc_handle_events(dev, s); + return; + } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ cfc_handle_events(dev, s); @@ -922,9 +880,15 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d) { struct comedi_device *dev = d; struct pci1710_private *devpriv = dev->private; + struct comedi_subdevice *s; + struct comedi_cmd *cmd; if (!dev->attached) /* is device attached? */ return IRQ_NONE; /* no, exit */ + + s = dev->read_subdev; + cmd = &s->async->cmd; + /* is this interrupt from our board? */ if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) return IRQ_NONE; /* no, exit */ @@ -939,95 +903,59 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d) outb(0, dev->iobase + PCI171x_CLRINT); outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - /* start pacer */ - start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2); + pci171x_start_pacer(dev, true); return IRQ_HANDLED; } - if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */ - interrupt_pci1710_every_sample(d); - } else { - interrupt_pci1710_half_fifo(d); - } + + if (cmd->flags & TRIG_WAKE_EOS) + pci1710_handle_every_sample(dev, s); + else + pci1710_handle_fifo(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== -*/ -static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) +static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct boardtype *this_board = comedi_board(dev); struct pci1710_private *devpriv = dev->private; - unsigned int divisor1 = 0, divisor2 = 0; - unsigned int seglen; + struct comedi_cmd *cmd = &s->async->cmd; - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pci171x_start_pacer(dev, false); - seglen = check_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan); - if (seglen < 1) - return -EINVAL; - setup_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan, seglen); + setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len, + devpriv->saved_seglen); outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); - devpriv->ai_do = mode; - devpriv->ai_act_scan = 0; s->async->cur_chan = 0; - devpriv->ai_buf_ptr = 0; - devpriv->neverending_ai = 0; devpriv->CntrlReg &= Control_CNT0; - /* don't we want wake up every scan? devpriv->ai_eos=1; */ - if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { - devpriv->ai_eos = 1; - } else { + if ((cmd->flags & TRIG_WAKE_EOS) == 0) devpriv->CntrlReg |= Control_ONEFH; - devpriv->ai_eos = 0; - } - if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) - devpriv->neverending_ai = 1; - /* well, user want neverending */ - else - devpriv->neverending_ai = 0; + devpriv->divisor1 = devpriv->next_divisor1; + devpriv->divisor2 = devpriv->next_divisor2; - switch (mode) { - case 1: - case 2: - if (devpriv->ai_timer1 < this_board->ai_ns_min) - devpriv->ai_timer1 = this_board->ai_ns_min; + if (cmd->convert_src == TRIG_TIMER) { devpriv->CntrlReg |= Control_PACER | Control_IRQEN; - if (mode == 2) { + if (cmd->start_src == TRIG_EXT) { devpriv->ai_et_CntrlReg = devpriv->CntrlReg; devpriv->CntrlReg &= ~(Control_PACER | Control_ONEFH | Control_GATE); devpriv->CntrlReg |= Control_EXT; devpriv->ai_et = 1; - } else { + } else { /* TRIG_NOW */ devpriv->ai_et = 0; } - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, - &divisor1, &divisor2, - &devpriv->ai_timer1, - devpriv->ai_flags); outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - if (mode != 2) { - /* start pacer */ - start_pacer(dev, mode, divisor1, divisor2); - } else { - devpriv->ai_et_div1 = divisor1; - devpriv->ai_et_div2 = divisor2; - } - break; - case 3: + + if (cmd->start_src == TRIG_NOW) + pci171x_start_pacer(dev, true); + } else { /* TRIG_EXT */ devpriv->CntrlReg |= Control_EXT | Control_IRQEN; outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - break; } return 0; @@ -1044,7 +972,6 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, struct pci1710_private *devpriv = dev->private; int err = 0; int tmp; - unsigned int divisor1 = 0, divisor2 = 0; /* Step 1 : check if triggers are trivially valid */ @@ -1093,8 +1020,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, - &divisor1, &divisor2, + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->next_divisor1, + &devpriv->next_divisor2, &cmd->convert_arg, cmd->flags); if (cmd->convert_arg < this_board->ai_ns_min) cmd->convert_arg = this_board->ai_ns_min; @@ -1105,51 +1033,14 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, if (err) return 4; - /* step 5: complain about special chanlist considerations */ + /* Step 5: check channel list */ - if (cmd->chanlist) { - if (!check_channel_list(dev, s, cmd->chanlist, - cmd->chanlist_len)) - return 5; /* incorrect channels list */ - } + err |= pci171x_ai_check_chanlist(dev, s, cmd); - return 0; -} - -/* -============================================================================== -*/ -static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct pci1710_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; - - devpriv->ai_n_chan = cmd->chanlist_len; - devpriv->ai_chanlist = cmd->chanlist; - devpriv->ai_flags = cmd->flags; - devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_timer1 = 0; - devpriv->ai_timer2 = 0; - - if (cmd->stop_src == TRIG_COUNT) - devpriv->ai_scans = cmd->stop_arg; - else - devpriv->ai_scans = 0; - - - if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */ - if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */ - devpriv->ai_timer1 = cmd->convert_arg; - return pci171x_ai_docmd_and_mode(cmd->start_src == - TRIG_EXT ? 2 : 1, dev, - s); - } - if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ - return pci171x_ai_docmd_and_mode(3, dev, s); - } - } + if (err) + return 5; - return -1; + return 0; } /* @@ -1165,7 +1056,7 @@ static int pci171x_reset(struct comedi_device *dev) outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ - start_pacer(dev, -1, 0, 0); /* stop 8254 */ + pci171x_start_pacer(dev, false); devpriv->da_ranges = 0; if (this_board->n_aochan) { outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */ @@ -1290,7 +1181,6 @@ static int pci1710_auto_attach(struct comedi_device *dev, s->do_cmd = pci171x_ai_cmd; s->cancel = pci171x_ai_cancel; } - devpriv->i8254_osc_base = I8254_OSC_BASE_10MHZ; subdev++; } diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c index 818a0d7e3d5808..ee18537b5a92d7 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200_common.c +++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c @@ -281,22 +281,18 @@ static int dio200_start_intr(struct comedi_device *dev, return retval; } -/* - * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. - */ -static int -dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int dio200_inttrig_start_intr(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { - struct dio200_subdev_intr *subpriv; + struct dio200_subdev_intr *subpriv = s->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int event = 0; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; - subpriv = s->private; - spin_lock_irqsave(&subpriv->spinlock, flags); s->async->inttrig = NULL; if (subpriv->active) @@ -528,16 +524,11 @@ static int dio200_subdev_intr_cmd(struct comedi_device *dev, break; } - /* Set up start of acquisition. */ - switch (cmd->start_src) { - case TRIG_INT: + if (cmd->start_src == TRIG_INT) s->async->inttrig = dio200_inttrig_start_intr; - break; - default: - /* TRIG_NOW */ + else /* TRIG_NOW */ event = dio200_start_intr(dev, s); - break; - } + spin_unlock_irqrestore(&subpriv->spinlock, flags); if (event) @@ -829,7 +820,7 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s, spin_lock_irqsave(&subpriv->spinlock, flags); switch (data[0]) { case INSN_CONFIG_SET_COUNTER_MODE: - if (data[1] > (I8254_MODE5 | I8254_BINARY)) + if (data[1] > (I8254_MODE5 | I8254_BCD)) ret = -EINVAL; else dio200_subdev_8254_set_mode(dev, s, chan, data[1]); diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index b21d7b48f1daf9..2834d0a9342afe 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c @@ -314,7 +314,7 @@ static int pc236_intr_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -402,6 +402,7 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = pc236_intr_insn; + s->len_chanlist = 1; s->do_cmdtest = pc236_intr_cmdtest; s->do_cmd = pc236_intr_cmd; s->cancel = pc236_intr_cancel; diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index 29e01e280039d2..c2b352c3c6a6dd 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -377,7 +377,6 @@ struct pci224_private { unsigned int cached_div1; unsigned int cached_div2; unsigned int ao_stop_count; - short ao_stop_continuous; unsigned short ao_enab; /* max 16 channels so 'short' will do */ unsigned char intsce; }; @@ -466,16 +465,6 @@ pci224_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -/* - * Just a wrapper for the inline function 'i8253_cascade_ns_to_timer'. - */ -static void -pci224_cascade_ns_to_timer(int osc_base, unsigned int *d1, unsigned int *d2, - unsigned int *nanosec, int round_mode) -{ - i8253_cascade_ns_to_timer(osc_base, d1, d2, nanosec, round_mode); -} - /* * Kills a command running on the AO subdevice. */ @@ -531,7 +520,7 @@ static void pci224_ao_start(struct comedi_device *dev, unsigned long flags; set_bit(AO_CMD_STARTED, &devpriv->state); - if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_stop_count == 0) { /* An empty acquisition! */ s->async->events |= COMEDI_CB_EOA; cfc_handle_events(dev, s); @@ -570,7 +559,7 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, } /* Determine number of scans available in buffer. */ num_scans = comedi_buf_read_n_available(s->async) / bytes_per_scan; - if (!devpriv->ao_stop_continuous) { + if (cmd->stop_src == TRIG_COUNT) { /* Fixed number of scans. */ if (num_scans > devpriv->ao_stop_count) num_scans = devpriv->ao_stop_count; @@ -582,7 +571,7 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, switch (dacstat & PCI224_DACCON_FIFOFL_MASK) { case PCI224_DACCON_FIFOFL_EMPTY: room = PCI224_FIFO_ROOM_EMPTY; - if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_stop_count == 0) { /* FIFO empty at end of counted acquisition. */ s->async->events |= COMEDI_CB_EOA; cfc_handle_events(dev, s); @@ -624,7 +613,7 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, dev->iobase + PCI224_DACDATA); } } - if (!devpriv->ao_stop_continuous) { + if (cmd->stop_src == TRIG_COUNT) { devpriv->ao_stop_count -= num_scans; if (devpriv->ao_stop_count == 0) { /* @@ -671,14 +660,13 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, cfc_handle_events(dev, s); } -/* - * Internal trigger function to start acquisition on AO subdevice. - */ -static int -pci224_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int pci224_ao_inttrig_start(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { - if (trignum != 0) + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_arg) return -EINVAL; s->async->inttrig = NULL; @@ -687,6 +675,37 @@ pci224_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, return 1; } +static int pci224_ao_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + unsigned int chan_mask = 0; + int i; + + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan_mask & (1 << chan)) { + dev_dbg(dev->class_dev, + "%s: entries in chanlist must contain no duplicate channels\n", + __func__); + return -EINVAL; + } + chan_mask |= (1 << chan); + + if (range != range0) { + dev_dbg(dev->class_dev, + "%s: entries in chanlist must all have the same range index\n", + __func__); + return -EINVAL; + } + } + + return 0; +} + #define MAX_SCAN_PERIOD 0xFFFFFFFFU #define MIN_SCAN_PERIOD 2500 #define CONVERT_PERIOD 625 @@ -821,98 +840,23 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 4: fix up any arguments. */ if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int div1, div2, round; - int round_mode = cmd->flags & TRIG_ROUND_MASK; - tmp = cmd->scan_begin_arg; - /* Check whether to use a single timer. */ - switch (round_mode) { - case TRIG_ROUND_NEAREST: - default: - round = I8254_OSC_BASE_10MHZ / 2; - break; - case TRIG_ROUND_DOWN: - round = 0; - break; - case TRIG_ROUND_UP: - round = I8254_OSC_BASE_10MHZ - 1; - break; - } - /* Be careful to avoid overflow! */ - div2 = cmd->scan_begin_arg / I8254_OSC_BASE_10MHZ; - div2 += (round + cmd->scan_begin_arg % I8254_OSC_BASE_10MHZ) / - I8254_OSC_BASE_10MHZ; - if (div2 <= 0x10000) { - /* A single timer will suffice. */ - if (div2 < 2) - div2 = 2; - cmd->scan_begin_arg = div2 * I8254_OSC_BASE_10MHZ; - if (cmd->scan_begin_arg < div2 || - cmd->scan_begin_arg < I8254_OSC_BASE_10MHZ) { - /* Overflow! */ - cmd->scan_begin_arg = MAX_SCAN_PERIOD; - } - } else { - /* Use two timers. */ - div1 = devpriv->cached_div1; - div2 = devpriv->cached_div2; - pci224_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, - &div1, &div2, - &cmd->scan_begin_arg, - round_mode); - devpriv->cached_div1 = div1; - devpriv->cached_div2 = div2; - } + /* Use two timers. */ + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->cached_div1, + &devpriv->cached_div2, + &cmd->scan_begin_arg, + cmd->flags); if (tmp != cmd->scan_begin_arg) err++; - } if (err) return 4; - /* Step 5: check channel list. */ - - if (cmd->chanlist && (cmd->chanlist_len > 0)) { - unsigned int range; - enum { range_err = 1, dupchan_err = 2, }; - unsigned errors; - unsigned int n; - unsigned int ch; - - /* - * Check all channels have the same range index. Don't care - * about analogue reference, as we can't configure it. - * - * Check the list has no duplicate channels. - */ - range = CR_RANGE(cmd->chanlist[0]); - errors = 0; - tmp = 0; - for (n = 0; n < cmd->chanlist_len; n++) { - ch = CR_CHAN(cmd->chanlist[n]); - if (tmp & (1U << ch)) - errors |= dupchan_err; - - tmp |= (1U << ch); - if (CR_RANGE(cmd->chanlist[n]) != range) - errors |= range_err; - - } - if (errors) { - if (errors & dupchan_err) { - dev_dbg(dev->class_dev, - "%s: entries in chanlist must contain no duplicate channels\n", - __func__); - } - if (errors & range_err) { - dev_dbg(dev->class_dev, - "%s: entries in chanlist must all have the same range index\n", - __func__); - } - err++; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= pci224_ao_check_chanlist(dev, s, cmd); if (err) return 5; @@ -920,9 +864,33 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } -/* - * 'do_cmd' function for AO subdevice. - */ +static void pci224_ao_start_pacer(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pci224_private *devpriv = dev->private; + unsigned long timer_base = devpriv->iobase1 + PCI224_Z2_CT0; + + /* + * The output of timer Z2-0 will be used as the scan trigger + * source. + */ + /* Make sure Z2-0 is gated on. */ + outb(GAT_CONFIG(0, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE); + /* Cascading with Z2-2. */ + /* Make sure Z2-2 is gated on. */ + outb(GAT_CONFIG(2, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE); + /* Z2-2 needs 10 MHz clock. */ + outb(CLK_CONFIG(2, CLK_10MHZ), devpriv->iobase1 + PCI224_ZCLK_SCE); + /* Load Z2-2 mode (2) and counter (div1). */ + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 2, devpriv->cached_div1); + /* Z2-0 is clocked from Z2-2's output. */ + outb(CLK_CONFIG(0, CLK_OUTNM1), devpriv->iobase1 + PCI224_ZCLK_SCE); + /* Load Z2-0 mode (2) and counter (div2). */ + i8254_set_mode(timer_base, 0, 0, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 0, devpriv->cached_div2); +} + static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct pci224_private *devpriv = dev->private; @@ -978,106 +946,26 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outw(devpriv->daccon | PCI224_DACCON_FIFORESET, dev->iobase + PCI224_DACCON); - if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int div1, div2, round; - unsigned int ns = cmd->scan_begin_arg; - int round_mode = cmd->flags & TRIG_ROUND_MASK; - - /* Check whether to use a single timer. */ - switch (round_mode) { - case TRIG_ROUND_NEAREST: - default: - round = I8254_OSC_BASE_10MHZ / 2; - break; - case TRIG_ROUND_DOWN: - round = 0; - break; - case TRIG_ROUND_UP: - round = I8254_OSC_BASE_10MHZ - 1; - break; - } - /* Be careful to avoid overflow! */ - div2 = cmd->scan_begin_arg / I8254_OSC_BASE_10MHZ; - div2 += (round + cmd->scan_begin_arg % I8254_OSC_BASE_10MHZ) / - I8254_OSC_BASE_10MHZ; - if (div2 <= 0x10000) { - /* A single timer will suffice. */ - if (div2 < 2) - div2 = 2; - div2 &= 0xffff; - div1 = 1; /* Flag that single timer to be used. */ - } else { - /* Use two timers. */ - div1 = devpriv->cached_div1; - div2 = devpriv->cached_div2; - pci224_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, - &div1, &div2, - &ns, round_mode); - } - - /* - * The output of timer Z2-0 will be used as the scan trigger - * source. - */ - /* Make sure Z2-0 is gated on. */ - outb(GAT_CONFIG(0, GAT_VCC), - devpriv->iobase1 + PCI224_ZGAT_SCE); - if (div1 == 1) { - /* Not cascading. Z2-0 needs 10 MHz clock. */ - outb(CLK_CONFIG(0, CLK_10MHZ), - devpriv->iobase1 + PCI224_ZCLK_SCE); - } else { - /* Cascading with Z2-2. */ - /* Make sure Z2-2 is gated on. */ - outb(GAT_CONFIG(2, GAT_VCC), - devpriv->iobase1 + PCI224_ZGAT_SCE); - /* Z2-2 needs 10 MHz clock. */ - outb(CLK_CONFIG(2, CLK_10MHZ), - devpriv->iobase1 + PCI224_ZCLK_SCE); - /* Load Z2-2 mode (2) and counter (div1). */ - i8254_load(devpriv->iobase1 + PCI224_Z2_CT0, 0, - 2, div1, 2); - /* Z2-0 is clocked from Z2-2's output. */ - outb(CLK_CONFIG(0, CLK_OUTNM1), - devpriv->iobase1 + PCI224_ZCLK_SCE); - } - /* Load Z2-0 mode (2) and counter (div2). */ - i8254_load(devpriv->iobase1 + PCI224_Z2_CT0, 0, 0, div2, 2); - } + if (cmd->scan_begin_src == TRIG_TIMER) + pci224_ao_start_pacer(dev, s); /* * Sort out end of acquisition. */ - switch (cmd->stop_src) { - case TRIG_COUNT: - /* Fixed number of scans. */ - devpriv->ao_stop_continuous = 0; + if (cmd->stop_src == TRIG_COUNT) devpriv->ao_stop_count = cmd->stop_arg; - break; - default: - /* Continuous scans. */ - devpriv->ao_stop_continuous = 1; + else /* TRIG_EXT | TRIG_NONE */ devpriv->ao_stop_count = 0; - break; - } - /* - * Sort out start of acquisition. - */ - switch (cmd->start_src) { - case TRIG_INT: - spin_lock_irqsave(&devpriv->ao_spinlock, flags); - s->async->inttrig = &pci224_ao_inttrig_start; - spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); - break; - case TRIG_EXT: + spin_lock_irqsave(&devpriv->ao_spinlock, flags); + if (cmd->start_src == TRIG_INT) { + s->async->inttrig = pci224_ao_inttrig_start; + } else { /* TRIG_EXT */ /* Enable external interrupt trigger to start acquisition. */ - spin_lock_irqsave(&devpriv->ao_spinlock, flags); devpriv->intsce |= PCI224_INTR_EXT; outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE); - spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); - break; } + spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); return 0; } diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 99e60835dc4a94..ff927c6417487e 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -519,14 +519,6 @@ struct pci230_private { * level threshold (PCI230+/260+). */ unsigned short adcg; /* ADCG register value. */ unsigned char int_en; /* Interrupt enables bits. */ - unsigned char ai_continuous; /* Flag set when cmd->stop_src == - * TRIG_NONE - user chooses to stop - * continuous conversion by - * cancelation. */ - unsigned char ao_continuous; /* Flag set when cmd->stop_src == - * TRIG_NONE - user chooses to stop - * continuous conversion by - * cancelation. */ unsigned char ai_bipolar; /* Set if bipolar input range so we * know to mangle it. */ unsigned char ao_bipolar; /* Set if bipolar output range so we @@ -953,6 +945,38 @@ static int pci230_ao_rinsn(struct comedi_device *dev, return i; } +static int pci230_ao_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int prev_chan = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan < prev_chan) { + dev_dbg(dev->class_dev, + "%s: channel numbers must increase\n", + __func__); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "%s: channels must have the same range\n", + __func__); + return -EINVAL; + } + + prev_chan = chan; + } + + return 0; +} + static int pci230_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { @@ -1065,48 +1089,9 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, if (err) return 4; - /* Step 5: check channel list if it exists. */ - - if (cmd->chanlist && cmd->chanlist_len > 0) { - enum { - seq_err = (1 << 0), - range_err = (1 << 1) - }; - unsigned int errors; - unsigned int n; - unsigned int chan, prev_chan; - unsigned int range, first_range; - - prev_chan = CR_CHAN(cmd->chanlist[0]); - first_range = CR_RANGE(cmd->chanlist[0]); - errors = 0; - for (n = 1; n < cmd->chanlist_len; n++) { - chan = CR_CHAN(cmd->chanlist[n]); - range = CR_RANGE(cmd->chanlist[n]); - /* Channel numbers must strictly increase. */ - if (chan < prev_chan) - errors |= seq_err; - - /* Ranges must be the same. */ - if (range != first_range) - errors |= range_err; - - prev_chan = chan; - } - if (errors != 0) { - err++; - if ((errors & seq_err) != 0) { - dev_dbg(dev->class_dev, - "%s: channel numbers must increase\n", - __func__); - } - if ((errors & range_err) != 0) { - dev_dbg(dev->class_dev, - "%s: channels must have the same range\n", - __func__); - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= pci230_ao_check_chanlist(dev, s, cmd); if (err) return 5; @@ -1175,7 +1160,7 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev, struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) return; for (i = 0; i < cmd->chanlist_len; i++) { /* Read sample from Comedi's circular buffer. */ @@ -1190,7 +1175,7 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev, pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i])); } async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - if (!devpriv->ao_continuous) { + if (cmd->stop_src == TRIG_COUNT) { devpriv->ao_scan_count--; if (devpriv->ao_scan_count == 0) { /* End of acquisition. */ @@ -1221,7 +1206,7 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, /* Determine number of scans available in buffer. */ bytes_per_scan = cmd->chanlist_len * sizeof(short); num_scans = comedi_buf_read_n_available(async) / bytes_per_scan; - if (!devpriv->ao_continuous) { + if (cmd->stop_src == TRIG_COUNT) { /* Fixed number of scans. */ if (num_scans > devpriv->ao_scan_count) num_scans = devpriv->ao_scan_count; @@ -1271,7 +1256,7 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, } } events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK; - if (!devpriv->ao_continuous) { + if (cmd->stop_src == TRIG_COUNT) { devpriv->ao_scan_count -= num_scans; if (devpriv->ao_scan_count == 0) { /* All data for the command has been written @@ -1349,7 +1334,7 @@ static void pci230_ao_start(struct comedi_device *dev, unsigned long irqflags; set_bit(AO_CMD_STARTED, &devpriv->state); - if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) { /* An empty acquisition! */ async->events |= COMEDI_CB_EOA; pci230_ao_stop(dev, s); @@ -1434,7 +1419,9 @@ static int pci230_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { - if (trig_num != 0) + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_src) return -EINVAL; s->async->inttrig = NULL; @@ -1460,14 +1447,10 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* Get number of scans required. */ - if (cmd->stop_src == TRIG_COUNT) { + if (cmd->stop_src == TRIG_COUNT) devpriv->ao_scan_count = cmd->stop_arg; - devpriv->ao_continuous = 0; - } else { - /* TRIG_NONE, user calls cancel. */ + else /* TRIG_NONE, user calls cancel */ devpriv->ao_scan_count = 0; - devpriv->ao_continuous = 1; - } /* Set range - see analogue output range table; 0 => unipolar 10V, * 1 => bipolar +/-10V range scale */ @@ -1552,6 +1535,109 @@ static int pci230_ai_check_scan_period(struct comedi_cmd *cmd) return !err; } +static int pci230_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + struct pci230_private *devpriv = dev->private; + unsigned int max_diff_chan = (s->n_chan / 2) - 1; + unsigned int prev_chan = 0; + unsigned int prev_range = 0; + unsigned int prev_aref = 0; + unsigned int prev_polarity = 0; + unsigned int subseq_len = 0; + int i; + + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chanspec = cmd->chanlist[i]; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + unsigned int polarity = pci230_ai_bipolar[range]; + + if (aref == AREF_DIFF && chan >= max_diff_chan) { + dev_dbg(dev->class_dev, + "%s: differential channel number out of range 0 to %u\n", + __func__, max_diff_chan); + return -EINVAL; + } + + if (i > 0) { + /* + * Channel numbers must strictly increase or + * subsequence must repeat exactly. + */ + if (chan <= prev_chan && subseq_len == 0) + subseq_len = i; + + if (subseq_len > 0 && + cmd->chanlist[i % subseq_len] != chanspec) { + dev_dbg(dev->class_dev, + "%s: channel numbers must increase or sequence must repeat exactly\n", + __func__); + return -EINVAL; + } + + if (aref != prev_aref) { + dev_dbg(dev->class_dev, + "%s: channel sequence analogue references must be all the same (single-ended or differential)\n", + __func__); + return -EINVAL; + } + + if (polarity != prev_polarity) { + dev_dbg(dev->class_dev, + "%s: channel sequence ranges must be all bipolar or all unipolar\n", + __func__); + return -EINVAL; + } + + if (aref != AREF_DIFF && range != prev_range && + ((chan ^ prev_chan) & ~1) == 0) { + dev_dbg(dev->class_dev, + "%s: single-ended channel pairs must have the same range\n", + __func__); + return -EINVAL; + } + } + prev_chan = chan; + prev_range = range; + prev_aref = aref; + prev_polarity = polarity; + } + + if (subseq_len == 0) + subseq_len = cmd->chanlist_len; + + if ((cmd->chanlist_len % subseq_len) != 0) { + dev_dbg(dev->class_dev, + "%s: sequence must repeat exactly\n", __func__); + return -EINVAL; + } + + /* + * Buggy PCI230+ or PCI260+ requires channel 0 to be (first) in the + * sequence if the sequence contains more than one channel. Hardware + * versions 1 and 2 have the bug. There is no hardware version 3. + * + * Actually, there are two firmwares that report themselves as + * hardware version 1 (the boards have different ADC chips with + * slightly different timing requirements, which was supposed to + * be invisible to software). The first one doesn't seem to have + * the bug, but the second one does, and we can't tell them apart! + */ + if (devpriv->hwver > 0 && devpriv->hwver < 4) { + if (subseq_len > 1 && CR_CHAN(cmd->chanlist[0]) != 0) { + dev_info(dev->class_dev, + "amplc_pci230: ai_cmdtest: Buggy PCI230+/260+ h/w version %u requires first channel of multi-channel sequence to be 0 (corrected in h/w version 4)\n", + devpriv->hwver); + return -EINVAL; + } + } + + return 0; +} + static int pci230_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { @@ -1740,136 +1826,9 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, if (err) return 4; - /* Step 5: check channel list if it exists. */ - - if (cmd->chanlist && cmd->chanlist_len > 0) { - enum { - seq_err = 1 << 0, - rangepair_err = 1 << 1, - polarity_err = 1 << 2, - aref_err = 1 << 3, - diffchan_err = 1 << 4, - buggy_chan0_err = 1 << 5 - }; - unsigned int errors; - unsigned int chan, prev_chan; - unsigned int range, prev_range; - unsigned int polarity, prev_polarity; - unsigned int aref, prev_aref; - unsigned int subseq_len; - unsigned int n; - - subseq_len = 0; - errors = 0; - prev_chan = prev_aref = prev_range = prev_polarity = 0; - for (n = 0; n < cmd->chanlist_len; n++) { - chan = CR_CHAN(cmd->chanlist[n]); - range = CR_RANGE(cmd->chanlist[n]); - aref = CR_AREF(cmd->chanlist[n]); - polarity = pci230_ai_bipolar[range]; - /* Only the first half of the channels are available if - * differential. (These are remapped in software. In - * hardware, only the even channels are available.) */ - if ((aref == AREF_DIFF) - && (chan >= (s->n_chan / 2))) { - errors |= diffchan_err; - } - if (n > 0) { - /* Channel numbers must strictly increase or - * subsequence must repeat exactly. */ - if ((chan <= prev_chan) - && (subseq_len == 0)) { - subseq_len = n; - } - if ((subseq_len > 0) - && (cmd->chanlist[n] != - cmd->chanlist[n % subseq_len])) { - errors |= seq_err; - } - /* Channels must have same AREF. */ - if (aref != prev_aref) - errors |= aref_err; - - /* Channel ranges must have same polarity. */ - if (polarity != prev_polarity) - errors |= polarity_err; - - /* Single-ended channel pairs must have same - * range. */ - if ((aref != AREF_DIFF) - && (((chan ^ prev_chan) & ~1) == 0) - && (range != prev_range)) { - errors |= rangepair_err; - } - } - prev_chan = chan; - prev_range = range; - prev_aref = aref; - prev_polarity = polarity; - } - if (subseq_len == 0) { - /* Subsequence is whole sequence. */ - subseq_len = n; - } - /* If channel list is a repeating subsequence, need a whole - * number of repeats. */ - if ((n % subseq_len) != 0) - errors |= seq_err; - - if ((devpriv->hwver > 0) && (devpriv->hwver < 4)) { - /* - * Buggy PCI230+ or PCI260+ requires channel 0 to be - * (first) in the sequence if the sequence contains - * more than one channel. Hardware versions 1 and 2 - * have the bug. There is no hardware version 3. - * - * Actually, there are two firmwares that report - * themselves as hardware version 1 (the boards - * have different ADC chips with slightly different - * timing requirements, which was supposed to be - * invisible to software). The first one doesn't - * seem to have the bug, but the second one - * does, and we can't tell them apart! - */ - if ((subseq_len > 1) - && (CR_CHAN(cmd->chanlist[0]) != 0)) { - errors |= buggy_chan0_err; - } - } - if (errors != 0) { - err++; - if ((errors & seq_err) != 0) { - dev_dbg(dev->class_dev, - "%s: channel numbers must increase or sequence must repeat exactly\n", - __func__); - } - if ((errors & rangepair_err) != 0) { - dev_dbg(dev->class_dev, - "%s: single-ended channel pairs must have the same range\n", - __func__); - } - if ((errors & polarity_err) != 0) { - dev_dbg(dev->class_dev, - "%s: channel sequence ranges must be all bipolar or all unipolar\n", - __func__); - } - if ((errors & aref_err) != 0) { - dev_dbg(dev->class_dev, - "%s: channel sequence analogue references must be all the same (single-ended or differential)\n", - __func__); - } - if ((errors & diffchan_err) != 0) { - dev_dbg(dev->class_dev, - "%s: differential channel number out of range 0 to %u\n", - __func__, (s->n_chan / 2) - 1); - } - if ((errors & buggy_chan0_err) != 0) { - dev_info(dev->class_dev, - "amplc_pci230: ai_cmdtest: Buggy PCI230+/260+ h/w version %u requires first channel of multi-channel sequence to be 0 (corrected in h/w version 4)\n", - devpriv->hwver); - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= pci230_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -1891,9 +1850,9 @@ static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev, /* Wake at end of scan. */ wake = scanlen - devpriv->ai_scan_pos; } else { - if (devpriv->ai_continuous - || (devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL) - || (scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL)) { + if (cmd->stop_src != TRIG_COUNT || + devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL || + scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL) { wake = PCI230_ADC_FIFOLEVEL_HALFFULL; } else { wake = (devpriv->ai_scan_count * scanlen) @@ -2044,7 +2003,7 @@ static void pci230_ai_start(struct comedi_device *dev, struct comedi_cmd *cmd = &async->cmd; set_bit(AI_CMD_STARTED, &devpriv->state); - if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ai_scan_count == 0) { /* An empty acquisition! */ async->events |= COMEDI_CB_EOA; pci230_ai_stop(dev, s); @@ -2177,7 +2136,9 @@ static int pci230_ai_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { - if (trig_num != 0) + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_arg) return -EINVAL; s->async->inttrig = NULL; @@ -2190,6 +2151,7 @@ static void pci230_handle_ai(struct comedi_device *dev, struct comedi_subdevice *s) { struct pci230_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int events = 0; unsigned int status_fifo; unsigned int i; @@ -2199,7 +2161,7 @@ static void pci230_handle_ai(struct comedi_device *dev, unsigned int scanlen = async->cmd.scan_end_arg; /* Determine number of samples to read. */ - if (devpriv->ai_continuous) { + if (cmd->stop_src != TRIG_COUNT) { todo = PCI230_ADC_FIFOLEVEL_HALFFULL; } else if (devpriv->ai_scan_count == 0) { todo = 0; @@ -2261,7 +2223,7 @@ static void pci230_handle_ai(struct comedi_device *dev, async->events |= COMEDI_CB_EOS; } } - if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ai_scan_count == 0) { /* End of acquisition. */ events |= COMEDI_CB_EOA; } else { @@ -2312,14 +2274,10 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* Get number of scans required. */ - if (cmd->stop_src == TRIG_COUNT) { + if (cmd->stop_src == TRIG_COUNT) devpriv->ai_scan_count = cmd->stop_arg; - devpriv->ai_continuous = 0; - } else { - /* TRIG_NONE, user calls cancel. */ + else /* TRIG_NONE, user calls cancel */ devpriv->ai_scan_count = 0; - devpriv->ai_continuous = 1; - } devpriv->ai_scan_pos = 0; /* Position within scan. */ /* Steps; @@ -2463,12 +2421,10 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } } - if (cmd->start_src == TRIG_INT) { + if (cmd->start_src == TRIG_INT) s->async->inttrig = pci230_ai_inttrig_start; - } else { - /* TRIG_NOW */ + else /* TRIG_NOW */ pci230_ai_start(dev, s); - } return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 83a265f3408c76..0df55dd0fb5322 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -803,6 +803,33 @@ static int trimpot_read_insn(struct comedi_device *dev, return 1; } +static int cb_pcidas_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan != (chan0 + i) % s->n_chan) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels, counting upwards\n"); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same gain\n"); + return -EINVAL; + } + } + return 0; +} + static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -811,7 +838,6 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, struct cb_pcidas_private *devpriv = dev->private; int err = 0; int tmp; - int i, gain, start_chan; /* Step 1 : check if triggers are trivially valid */ @@ -846,9 +872,12 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, if (err) return 2; - /* step 3: arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ switch (cmd->start_src) { + case TRIG_NOW: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; case TRIG_EXT: /* External trigger, only CR_EDGE and CR_INVERT flags allowed */ if ((cmd->start_arg @@ -862,9 +891,6 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, err |= -EINVAL; } break; - default: - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - break; } if (cmd->scan_begin_src == TRIG_TIMER) @@ -907,24 +933,9 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist) { - gain = CR_RANGE(cmd->chanlist[0]); - start_chan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - (start_chan + i) % s->n_chan) { - comedi_error(dev, - "entries in chanlist must be consecutive channels, counting upwards\n"); - err++; - } - if (CR_RANGE(cmd->chanlist[i]) != gain) { - comedi_error(dev, - "entries in chanlist must all have the same gain\n"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= cb_pcidas_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -932,20 +943,16 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, return 0; } -static void cb_pcidas_load_counters(struct comedi_device *dev, unsigned int *ns, - int rounding_flags) +static void cb_pcidas_ai_load_counters(struct comedi_device *dev) { struct cb_pcidas_private *devpriv = dev->private; + unsigned long timer_base = devpriv->pacer_counter_dio + ADC8254; - i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, - &devpriv->divisor1, &devpriv->divisor2, - ns, rounding_flags); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 1, - devpriv->divisor1, 2); - i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 2, - devpriv->divisor2, 2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); } static int cb_pcidas_ai_cmd(struct comedi_device *dev, @@ -983,12 +990,8 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, outw(bits, devpriv->control_status + ADCMUX_CONT); /* load counters */ - if (cmd->convert_src == TRIG_TIMER) - cb_pcidas_load_counters(dev, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - else if (cmd->scan_begin_src == TRIG_TIMER) - cb_pcidas_load_counters(dev, &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); + if (cmd->scan_begin_src == TRIG_TIMER || cmd->convert_src == TRIG_TIMER) + cb_pcidas_ai_load_counters(dev); /* set number of conversions */ if (cmd->stop_src == TRIG_COUNT) @@ -1035,6 +1038,25 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, return 0; } +static int cb_pcidas_ao_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + + if (cmd->chanlist_len > 1) { + unsigned int chan1 = CR_CHAN(cmd->chanlist[1]); + + if (chan0 != 0 || chan1 != 1) { + dev_dbg(dev->class_dev, + "channels must be ordered channel 0, channel 1 in chanlist\n"); + return -EINVAL; + } + } + + return 0; +} + static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -1097,15 +1119,9 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist && cmd->chanlist_len > 1) { - if (CR_CHAN(cmd->chanlist[0]) != 0 || - CR_CHAN(cmd->chanlist[1]) != 1) { - comedi_error(dev, - "channels must be ordered channel 0, channel 1 in chanlist\n"); - err++; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= cb_pcidas_ao_check_chanlist(dev, s, cmd); if (err) return 5; @@ -1145,7 +1161,7 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev, struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; - if (trig_num != 0) + if (trig_num != cmd->start_arg) return -EINVAL; /* load up fifo */ @@ -1180,6 +1196,18 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev, return 0; } +static void cb_pcidas_ao_load_counters(struct comedi_device *dev) +{ + struct cb_pcidas_private *devpriv = dev->private; + unsigned long timer_base = devpriv->pacer_counter_dio + DAC8254; + + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + + i8254_write(timer_base, 0, 1, devpriv->ao_divisor1); + i8254_write(timer_base, 0, 2, devpriv->ao_divisor2); +} + static int cb_pcidas_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -1209,18 +1237,9 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev, outw(0, devpriv->ao_registers + DACFIFOCLR); /* load counters */ - if (cmd->scan_begin_src == TRIG_TIMER) { - i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, - &devpriv->ao_divisor1, - &devpriv->ao_divisor2, - &cmd->scan_begin_arg, cmd->flags); + if (cmd->scan_begin_src == TRIG_TIMER) + cb_pcidas_ao_load_counters(dev); - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 1, - devpriv->ao_divisor1, 2); - i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 2, - devpriv->ao_divisor2, 2); - } /* set number of conversions */ if (cmd->stop_src == TRIG_COUNT) devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg; diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index f9afcbe1da545c..0e13ac9f34736b 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1995,14 +1995,52 @@ static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) return; } +static int cb_pcidas64_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + const struct pcidas64_board *board = comedi_board(dev); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (aref != aref0) { + dev_dbg(dev->class_dev, + "all elements in chanlist must use the same analog reference\n"); + return -EINVAL; + } + } + + if (board->layout == LAYOUT_4020) { + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (chan != (chan0 + i)) { + dev_dbg(dev->class_dev, + "chanlist must use consecutive channels\n"); + return -EINVAL; + } + } + if (cmd->chanlist_len == 3) { + dev_dbg(dev->class_dev, + "chanlist cannot be 3 channels long, use 1, 2, or 4 channels\n"); + return -EINVAL; + } + } + + return 0; +} + static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct pcidas64_board *thisboard = comedi_board(dev); int err = 0; unsigned int tmp_arg, tmp_arg2; - int i; - int aref; unsigned int triggers; /* Step 1 : check if triggers are trivially valid */ @@ -2040,15 +2078,24 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER) err |= -EINVAL; - if (cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) - err |= -EINVAL; if (err) return 2; /* Step 3: check if arguments are trivially valid */ + switch (cmd->start_src) { + case TRIG_NOW: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + /* + * start_arg is the CR_CHAN | CR_INVERT of the + * external trigger. + */ + break; + } + if (cmd->convert_src == TRIG_TIMER) { if (thisboard->layout == LAYOUT_4020) { err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); @@ -2098,36 +2145,9 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (err) return 4; - /* make sure user is doesn't change analog reference mid chanlist */ - if (cmd->chanlist) { - aref = CR_AREF(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (aref != CR_AREF(cmd->chanlist[i])) { - comedi_error(dev, - "all elements in chanlist must use the same analog reference"); - err++; - break; - } - } - /* check 4020 chanlist */ - if (thisboard->layout == LAYOUT_4020) { - unsigned int first_channel = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - first_channel + i) { - comedi_error(dev, - "chanlist must use consecutive channels"); - err++; - break; - } - } - if (cmd->chanlist_len == 3) { - comedi_error(dev, - "chanlist cannot be 3 channels long, use 1, 2, or 4 channels"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= cb_pcidas64_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -3204,7 +3224,7 @@ static int ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd = &s->async->cmd; int retval; - if (trig_num != 0) + if (trig_num != cmd->start_arg) return -EINVAL; retval = prep_ao_dma(dev, cmd); @@ -3247,13 +3267,32 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static int cb_pcidas64_ao_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (chan != (chan0 + i)) { + dev_dbg(dev->class_dev, + "chanlist must use consecutive channels\n"); + return -EINVAL; + } + } + + return 0; +} + static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct pcidas64_board *thisboard = comedi_board(dev); int err = 0; unsigned int tmp_arg; - int i; /* Step 1 : check if triggers are trivially valid */ @@ -3285,6 +3324,8 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 3: check if arguments are trivially valid */ + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + if (cmd->scan_begin_src == TRIG_TIMER) { err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, thisboard->ao_scan_speed); @@ -3315,17 +3356,9 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (err) return 4; - if (cmd->chanlist) { - unsigned int first_channel = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != first_channel + i) { - comedi_error(dev, - "chanlist must use consecutive channels"); - err++; - break; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= cb_pcidas64_ao_check_chanlist(dev, s, cmd); if (err) return 5; diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c index 9de81c7712fb91..50723b9406305c 100644 --- a/drivers/staging/comedi/drivers/comedi_parport.c +++ b/drivers/staging/comedi/drivers/comedi_parport.c @@ -181,7 +181,7 @@ static int parport_intr_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -295,6 +295,7 @@ static int parport_attach(struct comedi_device *dev, s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = parport_intr_insn_bits; + s->len_chanlist = 1; s->do_cmdtest = parport_intr_cmdtest; s->do_cmd = parport_intr_cmd; s->cancel = parport_intr_cancel; diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index cd9562556d2c81..ad5014a4074e54 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -413,11 +413,7 @@ static int waveform_attach(struct comedi_device *dev, s->n_chan = N_CHANS; s->maxdata = 0xffff; s->range_table = &waveform_ai_ranges; - s->len_chanlist = s->n_chan * 2; s->insn_write = waveform_ao_insn_write; - s->do_cmd = NULL; - s->do_cmdtest = NULL; - s->cancel = NULL; /* Our default loopback value is just a 0V flatline */ for (i = 0; i < s->n_chan; i++) diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index 6a7d652ff56476..a18c6b696ecf1a 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -600,13 +600,40 @@ static void das16_timer_interrupt(unsigned long arg) mod_timer(&devpriv->timer, jiffies + timer_period()); } +static int das16_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan != ((chan0 + i) % s->n_chan)) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels, counting upwards\n"); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same gain\n"); + return -EINVAL; + } + } + + return 0; +} + static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct das16_board *board = comedi_board(dev); struct das16_private_struct *devpriv = dev->private; int err = 0, tmp; - int gain, start_chan, i; int mask; /* Step 1 : check if triggers are trivially valid */ @@ -693,24 +720,10 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist) { - gain = CR_RANGE(cmd->chanlist[0]); - start_chan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - (start_chan + i) % s->n_chan) { - dev_err(dev->class_dev, - "entries in chanlist must be consecutive channels, counting upwards\n"); - err++; - } - if (CR_RANGE(cmd->chanlist[i]) != gain) { - dev_err(dev->class_dev, - "entries in chanlist must all have the same gain\n"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das16_ai_check_chanlist(dev, s, cmd); + if (err) return 5; @@ -727,9 +740,10 @@ static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, &devpriv->divisor1, &devpriv->divisor2, &ns, rounding_flags); - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(timer_base, 0, 1, devpriv->divisor1, 2); - i8254_load(timer_base, 0, 2, devpriv->divisor2, 2); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); return ns; } diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 779225831dc068..c97444991d892f 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -150,11 +150,39 @@ static void munge_sample_array(unsigned short *array, unsigned int num_elements) array[i] = munge_sample(array[i]); } +static int das16m1_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int i; + + if (cmd->chanlist_len == 1) + return 0; + + if ((cmd->chanlist_len % 2) != 0) { + dev_dbg(dev->class_dev, + "chanlist must be of even length or length 1\n"); + return -EINVAL; + } + + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if ((i % 2) != (chan % 2)) { + dev_dbg(dev->class_dev, + "even/odd channels must go have even/odd chanlist indices\n"); + return -EINVAL; + } + } + + return 0; +} + static int das16m1_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { struct das16m1_private_struct *devpriv = dev->private; - unsigned int err = 0, tmp, i; + unsigned int err = 0, tmp; /* Step 1 : check if triggers are trivially valid */ @@ -216,22 +244,9 @@ static int das16m1_cmd_test(struct comedi_device *dev, if (err) return 4; - /* check chanlist against board's peculiarities */ - if (cmd->chanlist && cmd->chanlist_len > 1) { - for (i = 0; i < cmd->chanlist_len; i++) { - /* even/odd channels must go into even/odd queue addresses */ - if ((i % 2) != (CR_CHAN(cmd->chanlist[i]) % 2)) { - comedi_error(dev, "bad chanlist:\n" - " even/odd channels must go have even/odd chanlist indices"); - err++; - } - } - if ((cmd->chanlist_len % 2) != 0) { - comedi_error(dev, - "chanlist must be of even length or length 1"); - err++; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das16m1_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -239,26 +254,16 @@ static int das16m1_cmd_test(struct comedi_device *dev, return 0; } -/* This function takes a time in nanoseconds and sets the * - * 2 pacer clocks to the closest frequency possible. It also * - * returns the actual sampling period. */ -static unsigned int das16m1_set_pacer(struct comedi_device *dev, - unsigned int ns, int rounding_flags) +static void das16m1_set_pacer(struct comedi_device *dev) { struct das16m1_private_struct *devpriv = dev->private; + unsigned long timer_base = dev->iobase + DAS16M1_8254_SECOND; - i8253_cascade_ns_to_timer_2div(I8254_OSC_BASE_10MHZ, - &devpriv->divisor1, - &devpriv->divisor2, - &ns, rounding_flags); - - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 1, devpriv->divisor1, - 2); - i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 2, devpriv->divisor2, - 2); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); - return ns; + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); } static int das16m1_cmd_exec(struct comedi_device *dev, @@ -267,6 +272,7 @@ static int das16m1_cmd_exec(struct comedi_device *dev, struct das16m1_private_struct *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; + unsigned long timer_base = dev->iobase + DAS16M1_8254_FIRST; unsigned int byte, i; /* disable interrupts and internal pacer */ @@ -278,11 +284,11 @@ static int das16m1_cmd_exec(struct comedi_device *dev, /* Initialize lower half of hardware counter, used to determine how * many samples are in fifo. Value doesn't actually load into counter * until counter's next clock (the next a/d conversion) */ - i8254_load(dev->iobase + DAS16M1_8254_FIRST, 0, 1, 0, 2); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 1, 0); /* remember current reading of counter so we know when counter has * actually been loaded */ - devpriv->initial_hw_count = - i8254_read(dev->iobase + DAS16M1_8254_FIRST, 0, 1); + devpriv->initial_hw_count = i8254_read(timer_base, 0, 1); /* setup channel/gain queue */ for (i = 0; i < cmd->chanlist_len; i++) { outb(i, dev->iobase + DAS16M1_QUEUE_ADDR); @@ -292,10 +298,14 @@ static int das16m1_cmd_exec(struct comedi_device *dev, outb(byte, dev->iobase + DAS16M1_QUEUE_DATA); } - /* set counter mode and counts */ - cmd->convert_arg = - das16m1_set_pacer(dev, cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + /* enable interrupts and set internal pacer counter mode and counts */ + devpriv->control_state &= ~PACER_MASK; + if (cmd->convert_src == TRIG_TIMER) { + das16m1_set_pacer(dev); + devpriv->control_state |= INT_PACER; + } else { /* TRIG_EXT */ + devpriv->control_state |= EXT_PACER; + } /* set control & status register */ byte = 0; @@ -308,13 +318,6 @@ static int das16m1_cmd_exec(struct comedi_device *dev, /* clear interrupt bit */ outb(0, dev->iobase + DAS16M1_CLEAR_INTR); - /* enable interrupts and internal pacer */ - devpriv->control_state &= ~PACER_MASK; - if (cmd->convert_src == TRIG_TIMER) - devpriv->control_state |= INT_PACER; - else - devpriv->control_state |= EXT_PACER; - devpriv->control_state |= INTE; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index 8e975d6b06db17..ba357b6ec1274c 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -731,7 +731,7 @@ static irqreturn_t das1800_interrupt(int irq, void *d) /* converts requested conversion timing to timing compatible with * hardware, used only when card is in 'burst mode' */ -static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode) +static unsigned int burst_convert_arg(unsigned int convert_arg, int flags) { unsigned int micro_sec; @@ -740,7 +740,7 @@ static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode) convert_arg = 64000; /* the conversion time must be an integral number of microseconds */ - switch (round_mode) { + switch (flags & TRIG_ROUND_MASK) { case TRIG_ROUND_NEAREST: default: micro_sec = (convert_arg + 500) / 1000; @@ -757,6 +757,26 @@ static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode) return micro_sec * 1000; } +static int das1800_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int unipolar0 = CR_RANGE(cmd->chanlist[0]) & UNIPOLAR; + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int unipolar = CR_RANGE(cmd->chanlist[i]) & UNIPOLAR; + + if (unipolar != unipolar0) { + dev_dbg(dev->class_dev, + "unipolar and bipolar ranges cannot be mixed in the chanlist\n"); + return -EINVAL; + } + } + + return 0; +} + /* test analog input cmd */ static int das1800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, @@ -765,9 +785,7 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev, const struct das1800_board *thisboard = comedi_board(dev); struct das1800_private *devpriv = dev->private; int err = 0; - unsigned int tmp_arg; - int i; - int unipolar; + unsigned int arg; /* Step 1 : check if triggers are trivially valid */ @@ -825,66 +843,48 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - if (cmd->convert_src == TRIG_TIMER) { - /* if we are not in burst mode */ - if (cmd->scan_begin_src == TRIG_FOLLOW) { - tmp_arg = cmd->convert_arg; - /* calculate counter values that give desired timing */ + if (cmd->scan_begin_src == TRIG_FOLLOW && + cmd->convert_src == TRIG_TIMER) { + /* we are not in burst mode */ + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->convert_arg, cmd->flags); + if (arg != cmd->convert_arg) + err++; + } else if (cmd->convert_src == TRIG_TIMER) { + /* we are in burst mode */ + arg = cmd->convert_arg; + cmd->convert_arg = burst_convert_arg(cmd->convert_arg, + cmd->flags); + if (arg != cmd->convert_arg) + err++; + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->chanlist_len; + if (arg > cmd->scan_begin_arg) { + cmd->scan_begin_arg = arg; + err++; + } + + arg = cmd->scan_begin_arg; i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, &devpriv->divisor1, &devpriv->divisor2, - &cmd->convert_arg, + &cmd->scan_begin_arg, cmd->flags); - if (tmp_arg != cmd->convert_arg) - err++; - } - /* if we are in burst mode */ - else { - /* check that convert_arg is compatible */ - tmp_arg = cmd->convert_arg; - cmd->convert_arg = - burst_convert_arg(cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp_arg != cmd->convert_arg) + if (arg != cmd->scan_begin_arg) err++; - - if (cmd->scan_begin_src == TRIG_TIMER) { - /* if scans are timed faster than conversion rate allows */ - if (cmd->convert_arg * cmd->chanlist_len > - cmd->scan_begin_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * - cmd->chanlist_len; - err++; - } - tmp_arg = cmd->scan_begin_arg; - /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, - &devpriv->divisor1, - &devpriv->divisor2, - &cmd->scan_begin_arg, - cmd->flags); - if (tmp_arg != cmd->scan_begin_arg) - err++; - } } } if (err) return 4; - /* make sure user is not trying to mix unipolar and bipolar ranges */ - if (cmd->chanlist) { - unipolar = CR_RANGE(cmd->chanlist[0]) & UNIPOLAR; - for (i = 1; i < cmd->chanlist_len; i++) { - if (unipolar != (CR_RANGE(cmd->chanlist[i]) & UNIPOLAR)) { - comedi_error(dev, - "unipolar and bipolar ranges cannot be mixed in the chanlist"); - err++; - break; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das1800_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -962,68 +962,29 @@ static int control_c_bits(const struct comedi_cmd *cmd) return control_c; } -/* loads counters with divisor1, divisor2 from private structure */ -static int das1800_set_frequency(struct comedi_device *dev) +static void das1800_setup_counters(struct comedi_device *dev, + const struct comedi_cmd *cmd) { struct das1800_private *devpriv = dev->private; - int err = 0; - - /* counter 1, mode 2 */ - if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 1, devpriv->divisor1, - 2)) - err++; - /* counter 2, mode 2 */ - if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 2, devpriv->divisor2, - 2)) - err++; - if (err) - return -1; + unsigned long timer_base = dev->iobase + DAS1800_COUNTER; - return 0; -} - -/* sets up counters */ -static int setup_counters(struct comedi_device *dev, - const struct comedi_cmd *cmd) -{ - struct das1800_private *devpriv = dev->private; - unsigned int period; + /* setup cascaded counters for conversion/scan frequency */ + if ((cmd->scan_begin_src == TRIG_FOLLOW || + cmd->scan_begin_src == TRIG_TIMER) && + cmd->convert_src == TRIG_TIMER) { + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); - /* setup cascaded counters for conversion/scan frequency */ - switch (cmd->scan_begin_src) { - case TRIG_FOLLOW: /* not in burst mode */ - if (cmd->convert_src == TRIG_TIMER) { - /* set conversion frequency */ - period = cmd->convert_arg; - i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, - &devpriv->divisor1, - &devpriv->divisor2, - &period, cmd->flags); - if (das1800_set_frequency(dev) < 0) - return -1; - } - break; - case TRIG_TIMER: /* in burst mode */ - /* set scan frequency */ - period = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, - &devpriv->divisor1, - &devpriv->divisor2, - &period, cmd->flags); - if (das1800_set_frequency(dev) < 0) - return -1; - break; - default: - break; + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); } - /* setup counter 0 for 'about triggering' */ + /* setup counter 0 for 'about triggering' */ if (cmd->stop_src == TRIG_EXT) { - /* load counter 0 in mode 0 */ - i8254_load(dev->iobase + DAS1800_COUNTER, 0, 0, 1, 0); - } + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); - return 0; + i8254_write(timer_base, 0, 0, 1); + } } /* utility function that suggests a dma transfer size based on the conversion period 'ns' */ @@ -1136,7 +1097,6 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct das1800_private *devpriv = dev->private; - int ret; int control_a, control_c; struct comedi_async *async = s->async; const struct comedi_cmd *cmd = &async->cmd; @@ -1167,11 +1127,7 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, /* setup card and start */ program_chanlist(dev, cmd); - ret = setup_counters(dev, cmd); - if (ret < 0) { - comedi_error(dev, "Error setting up counters"); - return ret; - } + das1800_setup_counters(dev, cmd); setup_dma(dev, cmd); outb(control_c, dev->iobase + DAS1800_CONTROL_C); /* set conversion rate and length for burst mode */ @@ -1470,7 +1426,7 @@ static int das1800_probe(struct comedi_device *dev) static int das1800_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct das1800_board *thisboard = comedi_board(dev); + const struct das1800_board *thisboard; struct das1800_private *devpriv; struct comedi_subdevice *s; unsigned int irq = it->options[1]; diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index e0cfb6cb547b90..d18eea6c01aa69 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -125,7 +125,7 @@ struct das6402_boardinfo { unsigned int maxdata; }; -struct das6402_boardinfo das6402_boards[] = { +static struct das6402_boardinfo das6402_boards[] = { { .name = "das6402-12", .maxdata = 0x0fff, diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index 3e408370dcf339..615ae3f1c6cc8d 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -275,19 +275,15 @@ static void das800_disable(struct comedi_device *dev) spin_unlock_irqrestore(&dev->spinlock, irq_flags); } -static int das800_set_frequency(struct comedi_device *dev) +static void das800_set_frequency(struct comedi_device *dev) { struct das800_private *devpriv = dev->private; - int err = 0; - - if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2)) - err++; - if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2)) - err++; - if (err) - return -1; + unsigned long timer_base = dev->iobase + DAS800_8254; - return 0; + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); } static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) @@ -300,6 +296,34 @@ static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static int das800_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan != (chan0 + i) % s->n_chan) { + dev_dbg(dev->class_dev, + "chanlist must be consecutive, counting upwards\n"); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "chanlist must all have the same gain\n"); + return -EINVAL; + } + } + + return 0; +} + static int das800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -366,27 +390,9 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev, if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist) { - unsigned int chan = CR_CHAN(cmd->chanlist[0]); - unsigned int range = CR_RANGE(cmd->chanlist[0]); - unsigned int next; - int i; - - for (i = 1; i < cmd->chanlist_len; i++) { - next = cmd->chanlist[i]; - if (CR_CHAN(next) != (chan + i) % N_CHAN_AI) { - dev_err(dev->class_dev, - "chanlist must be consecutive, counting upwards\n"); - err++; - } - if (CR_RANGE(next) != range) { - dev_err(dev->class_dev, - "chanlist must all have the same gain\n"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das800_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -438,10 +444,7 @@ static int das800_ai_do_cmd(struct comedi_device *dev, if (async->cmd.convert_src == TRIG_TIMER) { conv_bits |= CASC | ITE; /* set conversion frequency */ - if (das800_set_frequency(dev) < 0) { - comedi_error(dev, "Error setting up counters"); - return -1; - } + das800_set_frequency(dev); } spin_lock_irqsave(&dev->spinlock, irq_flags); @@ -673,7 +676,7 @@ static int das800_probe(struct comedi_device *dev) static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct das800_board *thisboard = comedi_board(dev); + const struct das800_board *thisboard; struct das800_private *devpriv; struct comedi_subdevice *s; unsigned int irq = it->options[1]; diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index c8a36eb5f01573..68260e6658e425 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -243,13 +243,39 @@ static int dmm32at_ns_to_timer(unsigned int *ns, int round) return *ns; } +static int dmm32at_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan != (chan0 + i) % s->n_chan) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels, counting upwards\n"); + return -EINVAL; + } + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same gain\n"); + return -EINVAL; + } + } + + return 0; +} + static int dmm32at_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; int tmp; - int start_chan, gain, i; /* Step 1 : check if triggers are trivially valid */ @@ -349,26 +375,9 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev, if (err) return 4; - /* step 5 check the channel list, the channel list for this - board must be consecutive and gains must be the same */ - - if (cmd->chanlist) { - gain = CR_RANGE(cmd->chanlist[0]); - start_chan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - (start_chan + i) % s->n_chan) { - comedi_error(dev, - "entries in chanlist must be consecutive channels, counting upwards\n"); - err++; - } - if (CR_RANGE(cmd->chanlist[i]) != gain) { - comedi_error(dev, - "entries in chanlist must all have the same gain\n"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= dmm32at_ai_check_chanlist(dev, s, cmd); if (err) return 5; diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c index d4d4e4b497dcdb..4263014426f83a 100644 --- a/drivers/staging/comedi/drivers/dt2801.c +++ b/drivers/staging/comedi/drivers/dt2801.c @@ -545,7 +545,7 @@ static int dt2801_dio_insn_config(struct comedi_device *dev, */ static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct dt2801_board *board = comedi_board(dev); + const struct dt2801_board *board; struct dt2801_private *devpriv; struct comedi_subdevice *s; int board_code, type; diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index 16cc100531e5db..474f52dac15de9 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -852,7 +852,7 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000); err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg, 2); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); if (cmd->stop_src == TRIG_COUNT) { /* any count is allowed */ @@ -878,12 +878,14 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev, } static int dt282x_ao_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int x) + struct comedi_subdevice *s, + unsigned int trig_num) { struct dt282x_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int size; - if (x != 0) + if (trig_num != cmd->start_src) return -EINVAL; size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf, diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index 08d7655e24e720..22333c1ad88c6f 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -360,12 +360,30 @@ static int gsc_hpdi_cmd(struct comedi_device *dev, return 0; } +static int gsc_hpdi_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int i; + + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (chan != i) { + dev_dbg(dev->class_dev, + "chanlist must be ch 0 to 31 in order\n"); + return -EINVAL; + } + } + + return 0; +} + static int gsc_hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int i; if (s->io_bits) return -EINVAL; @@ -392,6 +410,8 @@ static int gsc_hpdi_cmd_test(struct comedi_device *dev, /* Step 3: check if arguments are trivially valid */ + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + if (!cmd->chanlist_len || !cmd->chanlist) { cmd->chanlist_len = 32; err |= -EINVAL; @@ -411,17 +431,9 @@ static int gsc_hpdi_cmd_test(struct comedi_device *dev, if (err) return 4; - /* step 5: complain about special chanlist considerations */ - - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != i) { - /* XXX could support 8 or 16 channels */ - dev_err(dev->class_dev, - "chanlist must be ch 0 to 31 in order"); - err |= -EINVAL; - break; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= gsc_hpdi_check_chanlist(dev, s, cmd); if (err) return 5; diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index f02b31b317ec05..a08bc6ffad306e 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -598,67 +598,35 @@ static int me4000_ai_cancel(struct comedi_device *dev, return 0; } -static int ai_check_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) +static int me4000_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - const struct me4000_board *thisboard = comedi_board(dev); - int aref; + const struct me4000_board *board = comedi_board(dev); + unsigned int max_diff_chan = board->ai_diff_nchan; + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); int i; - /* Check whether a channel list is available */ - if (!cmd->chanlist_len) { - dev_err(dev->class_dev, "No channel list available\n"); - return -EINVAL; - } - - /* Check the channel list size */ - if (cmd->chanlist_len > ME4000_AI_CHANNEL_LIST_COUNT) { - dev_err(dev->class_dev, "Channel list is to large\n"); - return -EINVAL; - } - - /* Check the pointer */ - if (!cmd->chanlist) { - dev_err(dev->class_dev, "NULL pointer to channel list\n"); - return -EFAULT; - } - - /* Check whether aref is equal for all entries */ - aref = CR_AREF(cmd->chanlist[0]); for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_AREF(cmd->chanlist[i]) != aref) { - dev_err(dev->class_dev, + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (aref != aref0) { + dev_dbg(dev->class_dev, "Mode is not equal for all entries\n"); return -EINVAL; } - } - /* Check whether channels are available for this ending */ - if (aref == SDF_DIFF) { - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) >= - thisboard->ai_diff_nchan) { - dev_err(dev->class_dev, - "Channel number to high\n"); - return -EINVAL; - } - } - } else { - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai_nchan) { - dev_err(dev->class_dev, + if (aref == SDF_DIFF) { + if (chan >= max_diff_chan) { + dev_dbg(dev->class_dev, "Channel number to high\n"); return -EINVAL; } - } - } - /* Check if bipolar is set for all entries when in differential mode */ - if (aref == SDF_DIFF) { - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_RANGE(cmd->chanlist[i]) != 1 && - CR_RANGE(cmd->chanlist[i]) != 2) { - dev_err(dev->class_dev, + if (!comedi_range_is_bipolar(s, range)) { + dev_dbg(dev->class_dev, "Bipolar is not selected in differential mode\n"); return -EINVAL; } @@ -934,22 +902,13 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, err |= -EINVAL; } - if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_NONE) { - } else if (cmd->stop_src == TRIG_COUNT && - cmd->scan_end_src == TRIG_NONE) { - } else if (cmd->stop_src == TRIG_NONE && - cmd->scan_end_src == TRIG_COUNT) { - } else if (cmd->stop_src == TRIG_COUNT && - cmd->scan_end_src == TRIG_COUNT) { - } else { - err |= -EINVAL; - } - if (err) return 2; /* Step 3: check if arguments are trivially valid */ + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + if (cmd->chanlist_len < 1) { cmd->chanlist_len = 1; err |= -EINVAL; @@ -1091,10 +1050,11 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, if (err) return 4; - /* - * Stage 5. Check the channel list. - */ - if (ai_check_chanlist(dev, s, cmd)) + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= me4000_ai_check_chanlist(dev, s, cmd); + + if (err) return 5; return 0; @@ -1392,6 +1352,7 @@ static int me4000_cnt_insn_config(struct comedi_device *dev, unsigned int *data) { struct me4000_info *info = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int err; switch (data[0]) { @@ -1399,16 +1360,17 @@ static int me4000_cnt_insn_config(struct comedi_device *dev, if (insn->n != 1) return -EINVAL; - err = i8254_load(info->timer_regbase, 0, insn->chanspec, 0, - I8254_MODE0 | I8254_BINARY); + err = i8254_set_mode(info->timer_regbase, 0, chan, + I8254_MODE0 | I8254_BINARY); if (err) return err; + i8254_write(info->timer_regbase, 0, chan, 0); break; case GPCT_SET_OPERATION: if (insn->n != 2) return -EINVAL; - err = i8254_set_mode(info->timer_regbase, 0, insn->chanspec, + err = i8254_set_mode(info->timer_regbase, 0, chan, (data[1] << 1) | I8254_BINARY); if (err) return err; diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index 860fc81fb11c62..2b2dafe29c05f1 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -253,7 +253,7 @@ static int ni6527_intr_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -421,6 +421,7 @@ static int ni6527_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_config = ni6527_intr_insn_config; s->insn_bits = ni6527_intr_insn_bits; + s->len_chanlist = 1; s->do_cmdtest = ni6527_intr_cmdtest; s->do_cmd = ni6527_intr_cmd; s->cancel = ni6527_intr_cancel; diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index 6e42001f686e39..2051a7c5de109d 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -473,7 +473,7 @@ static int ni_65xx_intr_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -671,6 +671,7 @@ static int ni_65xx_auto_attach(struct comedi_device *dev, s->n_chan = 1; s->range_table = &range_unknown; s->maxdata = 1; + s->len_chanlist = 1; s->do_cmdtest = ni_65xx_intr_cmdtest; s->do_cmd = ni_65xx_intr_cmd; s->cancel = ni_65xx_intr_cancel; diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index 4e39b1f63d818f..f8d6bfce17e6b4 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -287,14 +287,54 @@ static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static int a2150_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); + int i; + + if (cmd->chanlist_len == 2 && (chan0 == 1 || chan0 == 3)) { + dev_dbg(dev->class_dev, + "length 2 chanlist must be channels 0,1 or channels 2,3\n"); + return -EINVAL; + } + + if (cmd->chanlist_len == 3) { + dev_dbg(dev->class_dev, + "chanlist must have 1,2 or 4 channels\n"); + return -EINVAL; + } + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (chan != (chan0 + i)) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels, counting upwards\n"); + return -EINVAL; + } + + if (chan == 2) + aref0 = aref; + if (aref != aref0) { + dev_dbg(dev->class_dev, + "channels 0/1 and 2/3 must have the same analog reference\n"); + return -EINVAL; + } + } + + return 0; +} + static int a2150_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct a2150_board *thisboard = comedi_board(dev); int err = 0; int tmp; - int startChan; - int i; /* Step 1 : check if triggers are trivially valid */ @@ -348,33 +388,9 @@ static int a2150_ai_cmdtest(struct comedi_device *dev, if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist) { - startChan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != (startChan + i)) { - comedi_error(dev, - "entries in chanlist must be consecutive channels, counting upwards\n"); - err++; - } - } - if (cmd->chanlist_len == 2 && CR_CHAN(cmd->chanlist[0]) == 1) { - comedi_error(dev, - "length 2 chanlist must be channels 0,1 or channels 2,3"); - err++; - } - if (cmd->chanlist_len == 3) { - comedi_error(dev, - "chanlist must have 1,2 or 4 channels"); - err++; - } - if (CR_AREF(cmd->chanlist[0]) != CR_AREF(cmd->chanlist[1]) || - CR_AREF(cmd->chanlist[2]) != CR_AREF(cmd->chanlist[3])) { - comedi_error(dev, - "channels 0/1 and 2/3 must have the same analog reference"); - err++; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= a2150_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -387,6 +403,7 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct a2150_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; + unsigned long timer_base = dev->iobase + I8253_BASE_REG; unsigned long lock_flags; unsigned int old_config_bits = devpriv->config_bits; unsigned int trigger_bits; @@ -454,7 +471,8 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); /* may need to wait 72 sampling periods if timing was changed */ - i8254_load(dev->iobase + I8253_BASE_REG, 0, 2, 72, 0); + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_write(timer_base, 0, 2, 72); /* setup start triggering */ trigger_bits = 0; @@ -679,7 +697,7 @@ static int a2150_probe(struct comedi_device *dev) static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct a2150_board *thisboard = comedi_board(dev); + const struct a2150_board *thisboard; struct a2150_private *devpriv; struct comedi_subdevice *s; unsigned int irq = it->options[1]; diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c index 10e3e9475ee2c5..c93b47bcca51d7 100644 --- a/drivers/staging/comedi/drivers/ni_at_ao.c +++ b/drivers/staging/comedi/drivers/ni_at_ao.c @@ -310,6 +310,7 @@ static int atao_calib_insn_read(struct comedi_device *dev, static void atao_reset(struct comedi_device *dev) { struct atao_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + ATAO_82C53_BASE; /* This is the reset sequence described in the manual */ @@ -317,10 +318,9 @@ static void atao_reset(struct comedi_device *dev) outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG); /* Put outputs of counter 1 and counter 2 in a high state */ - i8254_load(dev->iobase + ATAO_82C53_BASE, 0, - 0, 0x0003, I8254_MODE4 | I8254_BINARY); - i8254_set_mode(dev->iobase + ATAO_82C53_BASE, 0, - 1, I8254_MODE4 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 0, I8254_MODE4 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE4 | I8254_BINARY); + i8254_write(timer_base, 0, 0, 0x0003); outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG); diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index f4216e825f03a8..c6e914dc70cfcb 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -171,32 +171,39 @@ static const struct labpc_boardinfo labpc_boards[] = { }; #endif -static int labpc_counter_load(struct comedi_device *dev, - unsigned long base_address, - unsigned int counter_number, - unsigned int count, unsigned int mode) +static void labpc_counter_load(struct comedi_device *dev, + unsigned long base_address, + unsigned int counter_number, + unsigned int count, + unsigned int mode) { const struct labpc_boardinfo *board = comedi_board(dev); - if (board->has_mmio) - return i8254_mm_load((void __iomem *)base_address, 0, - counter_number, count, mode); - else - return i8254_load(base_address, 0, counter_number, count, mode); + if (board->has_mmio) { + void __iomem *mmio_base = (void __iomem *)base_address; + + i8254_mm_set_mode(mmio_base, 0, counter_number, mode); + i8254_mm_write(mmio_base, 0, counter_number, count); + } else { + i8254_set_mode(base_address, 0, counter_number, mode); + i8254_write(base_address, 0, counter_number, count); + } } -static int labpc_counter_set_mode(struct comedi_device *dev, - unsigned long base_address, - unsigned int counter_number, - unsigned int mode) +static void labpc_counter_set_mode(struct comedi_device *dev, + unsigned long base_address, + unsigned int counter_number, + unsigned int mode) { const struct labpc_boardinfo *board = comedi_board(dev); - if (board->has_mmio) - return i8254_mm_set_mode((void __iomem *)base_address, 0, - counter_number, mode); - else - return i8254_set_mode(base_address, 0, counter_number, mode); + if (board->has_mmio) { + void __iomem *mmio_base = (void __iomem *)base_address; + + i8254_mm_set_mode(mmio_base, 0, counter_number, mode); + } else { + i8254_set_mode(base_address, 0, counter_number, mode); + } } static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s) @@ -349,10 +356,8 @@ static int labpc_ai_insn_read(struct comedi_device *dev, devpriv->write_byte(devpriv->cmd4, dev->iobase + CMD4_REG); /* initialize pacer counter to prevent any problems */ - ret = labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG, - 0, I8254_MODE2); - if (ret) - return ret; + labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG, + 0, I8254_MODE2); labpc_clear_adc_fifo(dev); @@ -546,72 +551,60 @@ static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd) return 0; } -static int labpc_ai_chanlist_invalid(const struct comedi_device *dev, - const struct comedi_cmd *cmd, - enum scan_mode mode) +static int labpc_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - int channel, range, aref, i; - - if (cmd->chanlist == NULL) - return 0; + enum scan_mode mode = labpc_ai_scan_mode(cmd); + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); + int i; if (mode == MODE_SINGLE_CHAN) return 0; - if (mode == MODE_SINGLE_CHAN_INTERVAL) { - if (cmd->chanlist_len > 0xff) { - comedi_error(dev, - "ni_labpc: chanlist too long for single channel interval mode\n"); - return 1; - } - } - - channel = CR_CHAN(cmd->chanlist[0]); - range = CR_RANGE(cmd->chanlist[0]); - aref = CR_AREF(cmd->chanlist[0]); - for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); switch (mode) { + case MODE_SINGLE_CHAN: + break; case MODE_SINGLE_CHAN_INTERVAL: - if (CR_CHAN(cmd->chanlist[i]) != channel) { - comedi_error(dev, - "channel scanning order specified in chanlist is not supported by hardware.\n"); - return 1; + if (chan != chan0) { + dev_dbg(dev->class_dev, + "channel scanning order specified in chanlist is not supported by hardware\n"); + return -EINVAL; } break; case MODE_MULT_CHAN_UP: - if (CR_CHAN(cmd->chanlist[i]) != i) { - comedi_error(dev, - "channel scanning order specified in chanlist is not supported by hardware.\n"); - return 1; + if (chan != i) { + dev_dbg(dev->class_dev, + "channel scanning order specified in chanlist is not supported by hardware\n"); + return -EINVAL; } break; case MODE_MULT_CHAN_DOWN: - if (CR_CHAN(cmd->chanlist[i]) != - cmd->chanlist_len - i - 1) { - comedi_error(dev, - "channel scanning order specified in chanlist is not supported by hardware.\n"); - return 1; + if (chan != (cmd->chanlist_len - i - 1)) { + dev_dbg(dev->class_dev, + "channel scanning order specified in chanlist is not supported by hardware\n"); + return -EINVAL; } break; - default: - dev_err(dev->class_dev, - "ni_labpc: bug! in chanlist check\n"); - return 1; - break; } - if (CR_RANGE(cmd->chanlist[i]) != range) { - comedi_error(dev, - "entries in chanlist must all have the same range\n"); - return 1; + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same range\n"); + return -EINVAL; } - if (CR_AREF(cmd->chanlist[i]) != aref) { - comedi_error(dev, - "entries in chanlist must all have the same reference\n"); - return 1; + if (aref != aref0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same reference\n"); + return -EINVAL; } } @@ -661,8 +654,14 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg == TRIG_NOW) + switch (cmd->start_src) { + case TRIG_NOW: err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + /* start_arg value is ignored */ + break; + } if (!cmd->chanlist_len) err |= -EINVAL; @@ -711,7 +710,11 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, if (err) return 4; - if (labpc_ai_chanlist_invalid(dev, cmd, mode)) + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= labpc_ai_check_chanlist(dev, s, cmd); + + if (err) return 5; return 0; @@ -732,7 +735,6 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) unsigned int aref = CR_AREF(chanspec); enum transfer_type xfer; unsigned long flags; - int ret; /* make sure board is disabled before setting up acquisition */ labpc_cancel(dev, s); @@ -747,17 +749,12 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * load counter a1 with count of 3 * (pc+ manual says this is minimum allowed) using mode 0 */ - ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, - 1, 3, I8254_MODE0); + labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, + 1, 3, I8254_MODE0); } else { /* just put counter a1 in mode 0 to set its output low */ - ret = labpc_counter_set_mode(dev, - dev->iobase + COUNTER_A_BASE_REG, - 1, I8254_MODE0); - } - if (ret) { - comedi_error(dev, "error loading counter a1"); - return ret; + labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG, + 1, I8254_MODE0); } /* figure out what method we will use to transfer data */ @@ -802,38 +799,25 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* set up pacing */ labpc_adc_timing(dev, cmd, mode); /* load counter b0 in mode 3 */ - ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, - 0, devpriv->divisor_b0, I8254_MODE3); - if (ret < 0) { - comedi_error(dev, "error loading counter b0"); - return -1; - } + labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, + 0, devpriv->divisor_b0, I8254_MODE3); } /* set up conversion pacing */ if (labpc_ai_convert_period(cmd, mode)) { /* load counter a0 in mode 2 */ - ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, - 0, devpriv->divisor_a0, I8254_MODE2); + labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, + 0, devpriv->divisor_a0, I8254_MODE2); } else { /* initialize pacer counter to prevent any problems */ - ret = labpc_counter_set_mode(dev, - dev->iobase + COUNTER_A_BASE_REG, - 0, I8254_MODE2); - } - if (ret) { - comedi_error(dev, "error loading counter a0"); - return ret; + labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG, + 0, I8254_MODE2); } /* set up scan pacing */ if (labpc_ai_scan_period(cmd, mode)) { /* load counter b1 in mode 2 */ - ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, - 1, devpriv->divisor_b1, I8254_MODE2); - if (ret < 0) { - comedi_error(dev, "error loading counter b1"); - return -1; - } + labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, + 1, devpriv->divisor_b1, I8254_MODE2); } labpc_clear_adc_fifo(dev); diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 8a0e3b7236ad8d..087b533625df72 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -2080,7 +2080,7 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv = dev->private; int err = 0; - int tmp; + unsigned int tmp; unsigned int sources; /* Step 1 : check if triggers are trivially valid */ @@ -2119,17 +2119,19 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src == TRIG_EXT) { - /* external trigger */ - unsigned int tmp = CR_CHAN(cmd->start_arg); + switch (cmd->start_src) { + case TRIG_NOW: + case TRIG_INT: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + tmp = CR_CHAN(cmd->start_arg); if (tmp > 16) tmp = 16; tmp |= (cmd->start_arg & (CR_INVERT | CR_EDGE)); err |= cfc_check_trigger_arg_is(&cmd->start_arg, tmp); - } else { - /* true for both TRIG_NOW and TRIG_INT */ - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; } if (cmd->scan_begin_src == TRIG_TIMER) { @@ -2510,30 +2512,28 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } #endif - switch (cmd->start_src) { - case TRIG_NOW: + if (cmd->start_src == TRIG_NOW) { /* AI_START1_Pulse */ devpriv->stc_writew(dev, AI_START1_Pulse | devpriv->ai_cmd2, AI_Command_2_Register); s->async->inttrig = NULL; - break; - case TRIG_EXT: + } else if (cmd->start_src == TRIG_EXT) { s->async->inttrig = NULL; - break; - case TRIG_INT: - s->async->inttrig = &ni_ai_inttrig; - break; + } else { /* TRIG_INT */ + s->async->inttrig = ni_ai_inttrig; } return 0; } -static int ni_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int ni_ai_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { struct ni_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; devpriv->stc_writew(dev, AI_START1_Pulse | devpriv->ai_cmd2, @@ -2946,17 +2946,19 @@ static int ni_ao_insn_config(struct comedi_device *dev, return -EINVAL; } -static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int ni_ao_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { const struct ni_board_struct *board __maybe_unused = comedi_board(dev); struct ni_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; int interrupt_b_bits; int i; static const int timeout = 1000; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; /* Null trig at beginning prevent ao start trigger from executing more than @@ -3217,7 +3219,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) AO_BC_TC_Interrupt_Enable, 1); } - s->async->inttrig = &ni_ao_inttrig; + s->async->inttrig = ni_ao_inttrig; return 0; } @@ -3228,7 +3230,7 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv = dev->private; int err = 0; - int tmp; + unsigned int tmp; /* Step 1 : check if triggers are trivially valid */ @@ -3258,17 +3260,18 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src == TRIG_EXT) { - /* external trigger */ - unsigned int tmp = CR_CHAN(cmd->start_arg); + switch (cmd->start_src) { + case TRIG_INT: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + tmp = CR_CHAN(cmd->start_arg); if (tmp > 18) tmp = 18; tmp |= (cmd->start_arg & (CR_INVERT | CR_EDGE)); err |= cfc_check_trigger_arg_is(&cmd->start_arg, tmp); - } else { - /* true for both TRIG_NOW and TRIG_INT */ - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; } if (cmd->scan_begin_src == TRIG_TIMER) { @@ -3304,11 +3307,6 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (err) return 4; - /* step 5: fix up chanlist */ - - if (err) - return 5; - return 0; } @@ -3439,12 +3437,27 @@ static int ni_m_series_dio_insn_bits(struct comedi_device *dev, return insn->n; } +static int ni_cdio_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int i; + + for (i = 0; i < cmd->chanlist_len; ++i) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (chan != i) + return -EINVAL; + } + + return 0; +} + static int ni_cdio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; int tmp; - unsigned i; /* Step 1 : check if triggers are trivially valid */ @@ -3484,12 +3497,9 @@ static int ni_cdio_cmdtest(struct comedi_device *dev, if (err) return 4; - /* step 5: check chanlist */ - - for (i = 0; i < cmd->chanlist_len; ++i) { - if (cmd->chanlist[i] != i) - err = 1; - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= ni_cdio_check_chanlist(dev, s, cmd); if (err) return 5; @@ -3530,21 +3540,28 @@ static int ni_cdio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) retval = ni_request_cdo_mite_channel(dev); if (retval < 0) return retval; - s->async->inttrig = &ni_cdo_inttrig; + + s->async->inttrig = ni_cdo_inttrig; + return 0; } -static int ni_cdo_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int ni_cdo_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { #ifdef PCIDMA struct ni_private *devpriv = dev->private; unsigned long flags; #endif + struct comedi_cmd *cmd = &s->async->cmd; int retval = 0; unsigned i; const unsigned timeout = 1000; + if (trig_num != cmd->start_arg) + return -EINVAL; + s->async->inttrig = NULL; /* read alloc the entire buffer */ diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 85ac2d964f5c07..962c2353a79ff1 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -773,11 +773,13 @@ static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s) } static int ni_pcidio_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { struct nidio96_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; writeb(devpriv->OpModeBits, devpriv->mite->daq_io_addr + OpMode); diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index 7d64f8892f0819..b9d23db4004bf7 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -89,14 +89,16 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, static int ni_tio_input_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { + struct ni_gpct *counter = s->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int retval = 0; - struct ni_gpct *counter = s->private; BUG_ON(counter == NULL); - if (trignum != 0) + + if (trig_num != cmd->start_src) return -EINVAL; spin_lock_irqsave(&counter->lock, flags); @@ -271,8 +273,16 @@ int ni_tio_cmdtest(struct comedi_device *dev, /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src != TRIG_EXT) + switch (cmd->start_src) { + case TRIG_NOW: + case TRIG_INT: + case TRIG_OTHER: err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + /* start_arg is the start_trigger passed to ni_tio_arm() */ + break; + } if (cmd->scan_begin_src != TRIG_EXT) err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index 7c03a5d17b1b1d..2da6fec6ab4ca9 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -360,6 +360,18 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, return 0; } +static void pcl711_ai_load_counters(struct comedi_device *dev) +{ + struct pcl711_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL711_TIMER_BASE; + + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); +} + static int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl711_private *devpriv = dev->private; @@ -378,13 +390,8 @@ static int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } if (cmd->scan_begin_src == TRIG_TIMER) { - i8254_load(dev->iobase + PCL711_TIMER_BASE, 0, - 1, devpriv->divisor1, I8254_MODE2 | I8254_BINARY); - i8254_load(dev->iobase + PCL711_TIMER_BASE, 0, - 2, devpriv->divisor2, I8254_MODE2 | I8254_BINARY); - + pcl711_ai_load_counters(dev); outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG); - pcl711_ai_set_mode(dev, PCL711_MODE_PACER_IRQ); } else { pcl711_ai_set_mode(dev, PCL711_MODE_EXT_IRQ); diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c index cf9568ee46e46f..07ff1e22e61ca6 100644 --- a/drivers/staging/comedi/drivers/pcl726.c +++ b/drivers/staging/comedi/drivers/pcl726.c @@ -197,7 +197,7 @@ static int pcl726_intr_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -430,6 +430,7 @@ static int pcl726_attach(struct comedi_device *dev, s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = pcl726_intr_insn_bits; + s->len_chanlist = 1; s->do_cmdtest = pcl726_intr_cmdtest; s->do_cmd = pcl726_intr_cmd; s->cancel = pcl726_intr_cancel; diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index 160eac8083db16..0cf115e54308b3 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -761,7 +761,6 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); - err |= cfc_check_trigger_arg_max(&cmd->chanlist_len, MAX_CHANLIST_LEN); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); if (cmd->stop_src == TRIG_COUNT) @@ -811,8 +810,9 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_dma = 0; break; } - } else + } else { devpriv->ai_dma = 0; + } devpriv->ai_act_scan = 0; devpriv->ai_poll_ptr = 0; diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index e89bca8453491e..bb29ecfcfef4ba 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -464,18 +464,16 @@ static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -/* - * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. - */ -static int -pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int pcmmio_inttrig_start_intr(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { struct pcmmio_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int event = 0; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; spin_lock_irqsave(&devpriv->spinlock, flags); @@ -517,15 +515,11 @@ static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* Set up start of acquisition. */ - switch (cmd->start_src) { - case TRIG_INT: + if (cmd->start_src == TRIG_INT) s->async->inttrig = pcmmio_inttrig_start_intr; - break; - default: - /* TRIG_NOW */ + else /* TRIG_NOW */ event = pcmmio_start_intr(dev, s); - break; - } + spin_unlock_irqrestore(&devpriv->spinlock, flags); if (event) diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index a8f390f7a87418..ea45424e841078 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -460,20 +460,18 @@ static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -/* - * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. - */ -static int -pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int pcmuio_inttrig_start_intr(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { struct pcmuio_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int asic = pcmuio_subdevice_to_asic(s); struct pcmuio_asic *chip = &devpriv->asics[asic]; unsigned long flags; int event = 0; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; spin_lock_irqsave(&chip->spinlock, flags); @@ -518,15 +516,11 @@ static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* Set up start of acquisition. */ - switch (cmd->start_src) { - case TRIG_INT: + if (cmd->start_src == TRIG_INT) s->async->inttrig = pcmuio_inttrig_start_intr; - break; - default: - /* TRIG_NOW */ + else /* TRIG_NOW */ event = pcmuio_start_intr(dev, s); - break; - } + spin_unlock_irqrestore(&chip->spinlock, flags); if (event) diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index cd3fdf973bdd6b..e7c2e34624d905 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -878,6 +878,8 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9); } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + if (cmd->stop_src == TRIG_COUNT) { /* TODO check for rounding error due to counter wrap */ } else { @@ -891,10 +893,6 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - if (cmd->chanlist_len > RTD_MAX_CHANLIST) { - cmd->chanlist_len = RTD_MAX_CHANLIST; - err++; - } if (cmd->scan_begin_src == TRIG_TIMER) { tmp = cmd->scan_begin_arg; rtd_ns_to_timer(&cmd->scan_begin_arg, diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 95fadf343f2733..647b9e50bd74d6 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -295,10 +295,24 @@ static void s626_debi_replace(struct comedi_device *dev, unsigned int addr, /* ************** EEPROM ACCESS FUNCTIONS ************** */ -static uint32_t s626_i2c_handshake(struct comedi_device *dev, uint32_t val) +static int s626_i2c_handshake_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + bool status; + + status = s626_mc_test(dev, S626_MC2_UPLD_IIC, S626_P_MC2); + if (status) + return 0; + return -EBUSY; +} + +static int s626_i2c_handshake(struct comedi_device *dev, uint32_t val) { struct s626_private *devpriv = dev->private; unsigned int ctrl; + int ret; /* Write I2C command to I2C Transfer Control shadow register */ writel(val, devpriv->mmio + S626_P_I2CCTRL); @@ -308,8 +322,9 @@ static uint32_t s626_i2c_handshake(struct comedi_device *dev, uint32_t val) * wait for upload confirmation. */ s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); - while (!s626_mc_test(dev, S626_MC2_UPLD_IIC, S626_P_MC2)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0); + if (ret) + return ret; /* Wait until I2C bus transfer is finished or an error occurs */ do { @@ -2029,8 +2044,9 @@ static int s626_ai_insn_read(struct comedi_device *dev, /* Wait for the data to arrive in FB BUFFER 1 register. */ /* Wait for ADC done */ - while (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_GPIO2)) - ; + ret = comedi_timeout(dev, s, insn, s626_ai_eoc, 0); + if (ret) + return ret; /* Fetch ADC data from audio interface's input shift register. */ @@ -2060,9 +2076,12 @@ static int s626_ai_load_polllist(uint8_t *ppl, struct comedi_cmd *cmd) } static int s626_ai_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { - if (trignum != 0) + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_arg) return -EINVAL; /* Start executing the RPS program */ @@ -2298,12 +2317,18 @@ static int s626_ai_cmdtest(struct comedi_device *dev, if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src != TRIG_EXT) + switch (cmd->start_src) { + case TRIG_NOW: + case TRIG_INT: err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->start_src == TRIG_EXT) + break; + case TRIG_EXT: err |= cfc_check_trigger_arg_max(&cmd->start_arg, 39); + break; + } + if (cmd->scan_begin_src == TRIG_EXT) err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 39); if (cmd->convert_src == TRIG_EXT) @@ -2681,8 +2706,9 @@ static int s626_initialize(struct comedi_device *dev) writel(S626_I2C_CLKSEL | S626_I2C_ABORT, devpriv->mmio + S626_P_I2CSTAT); s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); - while (!(readl(devpriv->mmio + S626_P_MC2) & S626_MC2_UPLD_IIC)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0); + if (ret) + return ret; /* * Per SAA7146 data sheet, write to STATUS @@ -2691,8 +2717,9 @@ static int s626_initialize(struct comedi_device *dev) for (i = 0; i < 2; i++) { writel(S626_I2C_CLKSEL, devpriv->mmio + S626_P_I2CSTAT); s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); - while (!s626_mc_test(dev, S626_MC2_UPLD_IIC, S626_P_MC2)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0); + if (ret) + return ret; } /* diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index b59af030358190..4002f49f0082ad 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -692,15 +692,16 @@ static int receive_dux_commands(struct comedi_device *dev, unsigned int command) static int usbdux_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { struct usbdux_private *devpriv = dev->private; - int ret = -EINVAL; + struct comedi_cmd *cmd = &s->async->cmd; + int ret; - down(&devpriv->sem); + if (trig_num != cmd->start_arg) + return -EINVAL; - if (trignum != 0) - goto ai_trig_exit; + down(&devpriv->sem); if (!devpriv->ai_cmd_running) { devpriv->ai_cmd_running = 1; @@ -913,15 +914,16 @@ static int usbdux_ao_insn_write(struct comedi_device *dev, static int usbdux_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { struct usbdux_private *devpriv = dev->private; - int ret = -EINVAL; + struct comedi_cmd *cmd = &s->async->cmd; + int ret; - down(&devpriv->sem); + if (trig_num != cmd->start_arg) + return -EINVAL; - if (trignum != 0) - goto ao_trig_exit; + down(&devpriv->sem); if (!devpriv->ao_cmd_running) { devpriv->ao_cmd_running = 1; diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index d6fae11ee4e05e..a4d7bfbcc6b9f1 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -398,8 +398,7 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src == TRIG_NOW) - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); if (!cmd->chanlist_len) err |= -EINVAL; @@ -451,21 +450,20 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, static int usbduxfast_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { struct usbduxfast_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; if (!devpriv) return -EFAULT; + if (trig_num != cmd->start_arg) + return -EINVAL; + down(&devpriv->sem); - if (trignum != 0) { - dev_err(dev->class_dev, "invalid trignum\n"); - up(&devpriv->sem); - return -EINVAL; - } if (!devpriv->ai_cmd_running) { devpriv->ai_cmd_running = 1; ret = usbduxfast_submit_urb(dev); @@ -837,12 +835,7 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, return ret; } s->async->inttrig = NULL; - } else { - /* - * TRIG_INT - * don't enable the acquision operation - * wait for an internal signal - */ + } else { /* TRIG_INT */ s->async->inttrig = usbduxfast_ai_inttrig; } up(&devpriv->sem); diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 88c60b6020c48b..b57c974e5cb673 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -663,12 +663,13 @@ static int usbduxsigma_receive_cmd(struct comedi_device *dev, int command) static int usbduxsigma_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { struct usbduxsigma_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; down(&devpriv->sem); @@ -738,7 +739,6 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev, } s->async->inttrig = NULL; } else { /* TRIG_INT */ - /* wait for an internal signal and submit the urbs later */ s->async->inttrig = usbduxsigma_ai_inttrig; } @@ -856,12 +856,13 @@ static int usbduxsigma_ao_insn_write(struct comedi_device *dev, static int usbduxsigma_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { struct usbduxsigma_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; down(&devpriv->sem); @@ -1027,7 +1028,6 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev, } s->async->inttrig = NULL; } else { /* TRIG_INT */ - /* wait for an internal signal and submit the urbs later */ s->async->inttrig = usbduxsigma_ao_inttrig; } diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c index 20be9571990a30..e6fb331c673549 100644 --- a/drivers/staging/crystalhd/crystalhd_lnx.c +++ b/drivers/staging/crystalhd/crystalhd_lnx.c @@ -28,7 +28,7 @@ static struct crystalhd_adp *g_adp_info; static irqreturn_t chd_dec_isr(int irq, void *arg) { - struct crystalhd_adp *adp = (struct crystalhd_adp *) arg; + struct crystalhd_adp *adp = arg; int rc = 0; if (adp) rc = crystalhd_cmd_interrupt(&adp->cmds); @@ -112,7 +112,7 @@ static void chd_dec_free_iodata(struct crystalhd_adp *adp, } static inline int crystalhd_user_data(void __user *ud, void *dr, - int size, int set) + int size, int set) { int rc; @@ -135,7 +135,8 @@ static inline int crystalhd_user_data(void __user *ud, void *dr, } static int chd_dec_fetch_cdata(struct crystalhd_adp *adp, - struct crystalhd_ioctl_data *io, uint32_t m_sz, unsigned long ua) + struct crystalhd_ioctl_data *io, uint32_t m_sz, + unsigned long ua) { unsigned long ua_off; int rc = 0; @@ -154,7 +155,7 @@ static int chd_dec_fetch_cdata(struct crystalhd_adp *adp, io->add_cdata_sz = m_sz; ua_off = ua + sizeof(io->udata); rc = crystalhd_user_data((void __user *)ua_off, io->add_cdata, - io->add_cdata_sz, 0); + io->add_cdata_sz, 0); if (rc) { BCMLOG_ERR("failed to pull add_cdata sz:%x ua_off:%x\n", io->add_cdata_sz, (unsigned int)ua_off); @@ -167,7 +168,8 @@ static int chd_dec_fetch_cdata(struct crystalhd_adp *adp, } static int chd_dec_release_cdata(struct crystalhd_adp *adp, - struct crystalhd_ioctl_data *io, unsigned long ua) + struct crystalhd_ioctl_data *io, + unsigned long ua) { unsigned long ua_off; int rc; @@ -180,7 +182,7 @@ static int chd_dec_release_cdata(struct crystalhd_adp *adp, if (io->cmd != BCM_IOC_FW_DOWNLOAD) { ua_off = ua + sizeof(io->udata); rc = crystalhd_user_data((void __user *)ua_off, io->add_cdata, - io->add_cdata_sz, 1); + io->add_cdata_sz, 1); if (rc) { BCMLOG_ERR( "failed to push add_cdata sz:%x ua_off:%x\n", @@ -210,7 +212,7 @@ static int chd_dec_proc_user_data(struct crystalhd_adp *adp, } rc = crystalhd_user_data((void __user *)ua, &io->udata, - sizeof(io->udata), set); + sizeof(io->udata), set); if (rc) { BCMLOG_ERR("failed to %s iodata\n", (set ? "set" : "get")); return rc; @@ -382,7 +384,7 @@ static int chd_dec_init_chdev(struct crystalhd_adp *adp) } dev = device_create(crystalhd_class, NULL, - MKDEV(adp->chd_dec_major, 0), NULL, "crystalhd"); + MKDEV(adp->chd_dec_major, 0), NULL, "crystalhd"); if (IS_ERR(dev)) { rc = PTR_ERR(dev); BCMLOG_ERR("failed to create device\n"); @@ -397,8 +399,7 @@ static int chd_dec_init_chdev(struct crystalhd_adp *adp) /* Allocate general purpose ioctl pool. */ for (i = 0; i < CHD_IODATA_POOL_SZ; i++) { - temp = kzalloc(sizeof(struct crystalhd_ioctl_data), - GFP_KERNEL); + temp = kzalloc(sizeof(*temp), GFP_KERNEL); if (!temp) { BCMLOG_ERR("ioctl data pool kzalloc failed\n"); rc = -ENOMEM; @@ -549,11 +550,11 @@ static int chd_dec_pci_probe(struct pci_dev *pdev, enum BC_STATUS sts = BC_STS_SUCCESS; BCMLOG(BCMLOG_DBG, - "PCI_INFO: Vendor:0x%04x Device:0x%04x s_vendor:0x%04x s_device: 0x%04x\n", - pdev->vendor, pdev->device, pdev->subsystem_vendor, - pdev->subsystem_device); + "PCI_INFO: Vendor:0x%04x Device:0x%04x s_vendor:0x%04x s_device: 0x%04x\n", + pdev->vendor, pdev->device, pdev->subsystem_vendor, + pdev->subsystem_device); - pinfo = kzalloc(sizeof(struct crystalhd_adp), GFP_KERNEL); + pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); if (!pinfo) { BCMLOG_ERR("Failed to allocate memory\n"); return -ENOMEM; diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c index 9b4198b1e634e0..4fa27c8931b1ae 100644 --- a/drivers/staging/cxt1e1/hwprobe.c +++ b/drivers/staging/cxt1e1/hwprobe.c @@ -159,8 +159,8 @@ prep_hdw_info(void) hi->ndev = NULL; hi->addr[0] = 0L; hi->addr[1] = 0L; - hi->addr_mapped[0] = 0L; - hi->addr_mapped[1] = 0L; + hi->addr_mapped[0] = NULL; + hi->addr_mapped[1] = NULL; } } @@ -174,14 +174,14 @@ cleanup_ioremap(void) if (hi->pci_slot == 0xff) break; if (hi->addr_mapped[0]) { - iounmap((void *)(hi->addr_mapped[0])); + iounmap(hi->addr_mapped[0]); release_mem_region((long) hi->addr[0], hi->len[0]); - hi->addr_mapped[0] = 0; + hi->addr_mapped[0] = NULL; } if (hi->addr_mapped[1]) { - iounmap((void *)(hi->addr_mapped[1])); + iounmap(hi->addr_mapped[1]); release_mem_region((long) hi->addr[1], hi->len[1]); - hi->addr_mapped[1] = 0; + hi->addr_mapped[1] = NULL; } } } @@ -205,7 +205,7 @@ cleanup_devs(void) #ifdef CONFIG_SBE_PMCC4_NCOMM free_irq(hi->pdev[1]->irq, hi->ndev); #endif - OS_kfree(hi->ndev); + kfree(hi->ndev); } } @@ -329,7 +329,7 @@ c4hw_attach_all(void) return -ENOMEM; } - hi->addr_mapped[j] = (unsigned long)ioremap(hi->addr[j], hi->len[j]); + hi->addr_mapped[j] = ioremap(hi->addr[j], hi->len[j]); if (!hi->addr_mapped[j]) { pr_warning("%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n", hi->devname, hi->addr[j], hi->len[j]); diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c index b02f5ade6661b0..4b4609db9f89c2 100644 --- a/drivers/staging/cxt1e1/linux.c +++ b/drivers/staging/cxt1e1/linux.c @@ -60,7 +60,6 @@ status_t c4_chan_work_init(mpi_t *, mch_t *); void musycc_wq_chan_restart(void *); status_t __init c4_init(ci_t *, u_char *, u_char *); status_t __init c4_init2(ci_t *); -ci_t *__init c4_new(void *); int __init c4hw_attach_all(void); void __init hdw_sn_get(hdw_info_t *, int); @@ -418,7 +417,7 @@ create_chan(struct net_device *ndev, ci_t *ci, struct c4_priv *priv; /* allocate then fill in private data structure */ - priv = OS_kmalloc(sizeof(struct c4_priv)); + priv = kzalloc(sizeof(struct c4_priv), GFP_KERNEL); if (!priv) { pr_warning("%s: no memory for net_device !\n", ci->devname); @@ -428,7 +427,7 @@ create_chan(struct net_device *ndev, ci_t *ci, if (!dev) { pr_warning("%s: no memory for hdlc_device !\n", ci->devname); - OS_kfree(priv); + kfree(priv); return NULL; } priv->ci = ci; @@ -972,8 +971,8 @@ c4_add_dev(hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, if (register_netdev(ndev) || (c4_init(ci, (u_char *) f0, (u_char *) f1) != SBE_DRVR_SUCCESS)) { - OS_kfree(netdev_priv(ndev)); - OS_kfree(ndev); + kfree(netdev_priv(ndev)); + kfree(ndev); error_flag = -ENODEV; return NULL; } @@ -998,8 +997,8 @@ c4_add_dev(hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, pr_warning("%s: MUSYCC could not get irq: %d\n", ndev->name, irq0); unregister_netdev(ndev); - OS_kfree(netdev_priv(ndev)); - OS_kfree(ndev); + kfree(netdev_priv(ndev)); + kfree(ndev); error_flag = -EIO; return NULL; } @@ -1008,8 +1007,8 @@ c4_add_dev(hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, pr_warning("%s: EBUS could not get irq: %d\n", hi->devname, irq1); unregister_netdev(ndev); free_irq(irq0, ndev); - OS_kfree(netdev_priv(ndev)); - OS_kfree(ndev); + kfree(netdev_priv(ndev)); + kfree(ndev); error_flag = -EIO; return NULL; } @@ -1068,8 +1067,8 @@ c4_add_dev(hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, unregister_netdev(ndev); free_irq(irq1, ndev); free_irq(irq0, ndev); - OS_kfree(netdev_priv(ndev)); - OS_kfree(ndev); + kfree(netdev_priv(ndev)); + kfree(ndev); /* failure, error_flag is set */ return NULL; } diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c index 7b4f6f2108e3b9..872cdae0270430 100644 --- a/drivers/staging/cxt1e1/musycc.c +++ b/drivers/staging/cxt1e1/musycc.c @@ -744,7 +744,8 @@ musycc_init(ci_t *ci) #define INT_QUEUE_BOUNDARY 4 - regaddr = OS_kmalloc((INT_QUEUE_SIZE + 1) * sizeof(u_int32_t)); + regaddr = kzalloc((INT_QUEUE_SIZE + 1) * sizeof(u_int32_t), + GFP_KERNEL | GFP_DMA); if (!regaddr) return -ENOMEM; ci->iqd_p_saved = regaddr; /* save orig value for free's usage */ @@ -765,11 +766,12 @@ musycc_init(ci_t *ci) #define GROUP_BOUNDARY 0x800 - regaddr = OS_kmalloc(sizeof(struct musycc_groupr) + GROUP_BOUNDARY); + regaddr = kzalloc(sizeof(struct musycc_groupr) + GROUP_BOUNDARY, + GFP_KERNEL | GFP_DMA); if (!regaddr) { for (gchan = 0; gchan < i; gchan++) { pi = &ci->port[gchan]; - OS_kfree(pi->reg); + kfree(pi->reg); pi->reg = NULL; } return -ENOMEM; @@ -1576,10 +1578,10 @@ musycc_chan_down(ci_t *dummy, int channum) if (ch->mdr[i].mem_token) OS_mem_token_free(ch->mdr[i].mem_token); - OS_kfree(ch->mdr); + kfree(ch->mdr); ch->mdr = NULL; ch->rxd_num = 0; - OS_kfree(ch->mdt); + kfree(ch->mdt); ch->mdt = NULL; ch->txd_num = 0; diff --git a/drivers/staging/cxt1e1/pmc93x6_eeprom.c b/drivers/staging/cxt1e1/pmc93x6_eeprom.c index 78cc1709ebdb62..ba588f1b211062 100644 --- a/drivers/staging/cxt1e1/pmc93x6_eeprom.c +++ b/drivers/staging/cxt1e1/pmc93x6_eeprom.c @@ -28,6 +28,7 @@ #include "sbecom_inline_linux.h" #include "pmcc4.h" #include "sbe_promformat.h" +#include "pmc93x6_eeprom.h" #ifndef TRUE #define TRUE 1 @@ -43,38 +44,35 @@ * using. */ -#define EE_MFG (long)0 /* Index to manufacturing record */ -#define EE_FIRST 0x28 /* Index to start testing at */ -#define EE_LIMIT 128 /* Index to end testing at */ - +#define EE_MFG (long)0 /* Index to manufacturing record */ +#define EE_FIRST 0x28 /* Index to start testing at */ +#define EE_LIMIT 128 /* Index to end testing at */ /* Bit Ordering for Instructions -** -** A0, A1, A2, A3, A4, A5, A6, OP0, OP1, SB (lsb, or 1st bit out) -** -*/ - -#define EPROM_EWEN 0x0019 /* Erase/Write enable (reversed) */ -#define EPROM_EWDS 0x0001 /* Erase/Write disable (reversed) */ -#define EPROM_READ 0x0003 /* Read (reversed) */ -#define EPROM_WRITE 0x0005 /* Write (reversed) */ -#define EPROM_ERASE 0x0007 /* Erase (reversed) */ -#define EPROM_ERAL 0x0009 /* Erase All (reversed) */ -#define EPROM_WRAL 0x0011 /* Write All (reversed) */ - -#define EPROM_ADR_SZ 7 /* Number of bits in offset address */ -#define EPROM_OP_SZ 3 /* Number of bits in command */ -#define SIZE_ADDR_OP (EPROM_ADR_SZ + EPROM_OP_SZ) -#define LC46A_MAX_OPS 10 /* Number of bits in Instruction */ -#define NUM_OF_BITS 8 /* Number of bits in data */ + * + * A0, A1, A2, A3, A4, A5, A6, OP0, OP1, SB (lsb, or 1st bit out) + * + */ +#define EPROM_EWEN 0x0019 /* Erase/Write enable (reversed) */ +#define EPROM_EWDS 0x0001 /* Erase/Write disable (reversed) */ +#define EPROM_READ 0x0003 /* Read (reversed) */ +#define EPROM_WRITE 0x0005 /* Write (reversed) */ +#define EPROM_ERASE 0x0007 /* Erase (reversed) */ +#define EPROM_ERAL 0x0009 /* Erase All (reversed) */ +#define EPROM_WRAL 0x0011 /* Write All (reversed) */ -/* EEPROM signal bits */ -#define EPROM_ACTIVE_OUT_BIT 0x0001 /* Out data bit */ -#define EPROM_ACTIVE_IN_BIT 0x0002 /* In data bit */ -#define ACTIVE_IN_BIT_SHIFT 0x0001 /* Shift In data bit to LSB */ -#define EPROM_ENCS 0x0004 /* Set EEPROM CS during operation */ +#define EPROM_ADR_SZ 7 /* Number of bits in offset address */ +#define EPROM_OP_SZ 3 /* Number of bits in command */ +#define SIZE_ADDR_OP (EPROM_ADR_SZ + EPROM_OP_SZ) +#define LC46A_MAX_OPS 10 /* Number of bits in Instruction */ +#define NUM_OF_BITS 8 /* Number of bits in data */ +/* EEPROM signal bits */ +#define EPROM_ACTIVE_OUT_BIT 0x0001 /* Out data bit */ +#define EPROM_ACTIVE_IN_BIT 0x0002 /* In data bit */ +#define ACTIVE_IN_BIT_SHIFT 0x0001 /* Shift In data bit to LSB */ +#define EPROM_ENCS 0x0004 /* Set EEPROM CS during operation */ /*------------------------------------------------------------------------ * The ByteReverse table is used to reverses the 8 bits within a byte @@ -82,29 +80,26 @@ */ static unsigned char ByteReverse[256]; -static int ByteReverseBuilt = FALSE; - +static int ByteReverseBuilt = FALSE; /*------------------------------------------------------------------------ * mfg_template - initial serial EEPROM data structure *------------------------------------------------------------------------ */ -static u8 mfg_template[sizeof(FLD_TYPE2)] = -{ - PROM_FORMAT_TYPE2, /* type; */ - 0x00, 0x1A, /* length[2]; */ - 0x00, 0x00, 0x00, 0x00, /* Crc32[4]; */ - 0x11, 0x76, /* Id[2]; */ - 0x07, 0x05, /* SubId[2] E1; */ - 0x00, 0xA0, 0xD6, 0x00, 0x00, 0x00, /* Serial[6]; */ - 0x00, 0x00, 0x00, 0x00, /* CreateTime[4]; */ - 0x00, 0x00, 0x00, 0x00, /* HeatRunTime[4]; */ - 0x00, 0x00, 0x00, 0x00, /* HeatRunIterations[4]; */ - 0x00, 0x00, 0x00, 0x00, /* HeatRunErrors[4]; */ +static u8 mfg_template[sizeof(FLD_TYPE2)] = { + PROM_FORMAT_TYPE2, /* type; */ + 0x00, 0x1A, /* length[2]; */ + 0x00, 0x00, 0x00, 0x00, /* Crc32[4]; */ + 0x11, 0x76, /* Id[2]; */ + 0x07, 0x05, /* SubId[2] E1; */ + 0x00, 0xA0, 0xD6, 0x00, 0x00, 0x00, /* Serial[6]; */ + 0x00, 0x00, 0x00, 0x00, /* CreateTime[4]; */ + 0x00, 0x00, 0x00, 0x00, /* HeatRunTime[4]; */ + 0x00, 0x00, 0x00, 0x00, /* HeatRunIterations[4]; */ + 0x00, 0x00, 0x00, 0x00, /* HeatRunErrors[4]; */ }; - /*------------------------------------------------------------------------ * BuildByteReverse - build the 8-bit reverse table *------------------------------------------------------------------------ @@ -113,39 +108,35 @@ static u8 mfg_template[sizeof(FLD_TYPE2)] = * (the MSB becomes the LSB etc.). */ -static void -BuildByteReverse (void) +static void BuildByteReverse(void) { - long half; /* Used to build by powers to 2 */ - int i; + /* Used to build by powers to 2 */ + long half; + int i; - ByteReverse[0] = 0; + ByteReverse[0] = 0; - for (half = 1; half < sizeof (ByteReverse); half <<= 1) - for (i = 0; i < half; i++) - ByteReverse[half + i] = (char) (ByteReverse[i] | (0x80 / half)); + for (half = 1; half < sizeof(ByteReverse); half <<= 1) + for (i = 0; i < half; i++) + ByteReverse[half + i] = + (char)(ByteReverse[i] | (0x80 / half)); - ByteReverseBuilt = TRUE; + ByteReverseBuilt = TRUE; } - /*------------------------------------------------------------------------ * eeprom_delay - small delay for EEPROM timing *------------------------------------------------------------------------ */ -static void -eeprom_delay (void) +static void eeprom_delay(void) { - int timeout; + int timeout; - for (timeout = 20; timeout; --timeout) - { - OS_uwait_dummy (); - } + for (timeout = 20; timeout; --timeout) + OS_uwait_dummy(); } - /*------------------------------------------------------------------------ * eeprom_put_byte - Send a byte to the EEPROM serially *------------------------------------------------------------------------ @@ -154,23 +145,23 @@ eeprom_delay (void) * the data to the EEPROM. */ -void -eeprom_put_byte (long addr, long data, int count) +static void eeprom_put_byte(long addr, long data, int count) { - u_int32_t output; - - while (--count >= 0) - { - output = (data & EPROM_ACTIVE_OUT_BIT) ? 1 : 0; /* Get next data bit */ - output |= EPROM_ENCS; /* Add Chip Select */ - data >>= 1; - - eeprom_delay (); - pci_write_32 ((u_int32_t *) addr, output); /* Output it */ - } + u_int32_t output; + + while (--count >= 0) { + /* Get next data bit */ + output = (data & EPROM_ACTIVE_OUT_BIT) ? 1 : 0; + /* Add Chip Select */ + output |= EPROM_ENCS; + data >>= 1; + + eeprom_delay(); + /* Output it */ + pci_write_32((u_int32_t *) addr, output); + } } - /*------------------------------------------------------------------------ * eeprom_get_byte - Receive a byte from the EEPROM serially *------------------------------------------------------------------------ @@ -179,37 +170,35 @@ eeprom_put_byte (long addr, long data, int count) * from the EEPROM. */ -u_int32_t -eeprom_get_byte (long addr) +static u_int32_t eeprom_get_byte(long addr) { - u_int32_t input; - u_int32_t data; - int count; + u_int32_t input; + u_int32_t data; + int count; /* Start the Reading of DATA -** -** The first read is a dummy as the data is latched in the -** EPLD and read on the next read access to the EEPROM. -*/ + * + * The first read is a dummy as the data is latched in the + * EPLD and read on the next read access to the EEPROM. + */ - input = pci_read_32 ((u_int32_t *) addr); + input = pci_read_32((u_int32_t *) addr); - data = 0; - count = NUM_OF_BITS; - while (--count >= 0) - { - eeprom_delay (); - input = pci_read_32 ((u_int32_t *) addr); + data = 0; + count = NUM_OF_BITS; + while (--count >= 0) { + eeprom_delay(); + input = pci_read_32((u_int32_t *) addr); - data <<= 1; /* Shift data over */ - data |= (input & EPROM_ACTIVE_IN_BIT) ? 1 : 0; + /* Shift data over */ + data <<= 1; + data |= (input & EPROM_ACTIVE_IN_BIT) ? 1 : 0; - } + } - return data; + return data; } - /*------------------------------------------------------------------------ * disable_pmc_eeprom - Disable writes to the EEPROM *------------------------------------------------------------------------ @@ -217,16 +206,14 @@ eeprom_get_byte (long addr) * Issue the EEPROM command to disable writes. */ -static void -disable_pmc_eeprom (long addr) +static void disable_pmc_eeprom(long addr) { - eeprom_put_byte (addr, EPROM_EWDS, SIZE_ADDR_OP); + eeprom_put_byte(addr, EPROM_EWDS, SIZE_ADDR_OP); - pci_write_32 ((u_int32_t *) addr, 0); /* this removes Chip Select - * from EEPROM */ + /* this removes Chip Select from EEPROM */ + pci_write_32((u_int32_t *) addr, 0); } - /*------------------------------------------------------------------------ * enable_pmc_eeprom - Enable writes to the EEPROM *------------------------------------------------------------------------ @@ -234,16 +221,14 @@ disable_pmc_eeprom (long addr) * Issue the EEPROM command to enable writes. */ -static void -enable_pmc_eeprom (long addr) +static void enable_pmc_eeprom(long addr) { - eeprom_put_byte (addr, EPROM_EWEN, SIZE_ADDR_OP); + eeprom_put_byte(addr, EPROM_EWEN, SIZE_ADDR_OP); - pci_write_32 ((u_int32_t *) addr, 0); /* this removes Chip Select - * from EEPROM */ + /* this removes Chip Select from EEPROM */ + pci_write_32((u_int32_t *) addr, 0); } - /*------------------------------------------------------------------------ * pmc_eeprom_read - EEPROM location read *------------------------------------------------------------------------ @@ -252,34 +237,40 @@ enable_pmc_eeprom (long addr) * the contents of the specified location to the calling routine. */ -u_int32_t -pmc_eeprom_read (long addr, long mem_offset) +static u_int32_t pmc_eeprom_read(long addr, long mem_offset) { - u_int32_t data; /* Data from chip */ + /* Data from chip */ + u_int32_t data; - if (!ByteReverseBuilt) - BuildByteReverse (); + if (!ByteReverseBuilt) + BuildByteReverse(); - mem_offset = ByteReverse[0x7F & mem_offset]; /* Reverse address */ - /* - * NOTE: The max offset address is 128 or half the reversal table. So the - * LSB is always zero and counts as a built in shift of one bit. So even - * though we need to shift 3 bits to make room for the command, we only - * need to shift twice more because of the built in shift. - */ - mem_offset <<= 2; /* Shift for command */ - mem_offset |= EPROM_READ; /* Add command */ + /* Reverse address */ + mem_offset = ByteReverse[0x7F & mem_offset]; - eeprom_put_byte (addr, mem_offset, SIZE_ADDR_OP); /* Output chip address */ + /* + * NOTE: The max offset address is 128 or half the reversal table. So + * the LSB is always zero and counts as a built in shift of one bit. + * So even though we need to shift 3 bits to make room for the command, + * we only need to shift twice more because of the built in shift. + */ - data = eeprom_get_byte (addr); /* Read chip data */ + /* Shift for command */ + mem_offset <<= 2; + /* Add command */ + mem_offset |= EPROM_READ; - pci_write_32 ((u_int32_t *) addr, 0); /* Remove Chip Select from - * EEPROM */ + /* Output chip address */ + eeprom_put_byte(addr, mem_offset, SIZE_ADDR_OP); - return (data & 0x000000FF); -} + /* Read chip data */ + data = eeprom_get_byte(addr); + + /* Remove Chip Select from EEPROM */ + pci_write_32((u_int32_t *) addr, 0); + return (data & 0x000000FF); +} /*------------------------------------------------------------------------ * pmc_eeprom_write - EEPROM location write @@ -292,189 +283,181 @@ pmc_eeprom_read (long addr, long mem_offset) * operation succeeded. */ -int -pmc_eeprom_write (long addr, long mem_offset, u_int32_t data) +static int pmc_eeprom_write(long addr, long mem_offset, u_int32_t data) { - volatile u_int32_t temp; - int count; + u_int32_t temp; + int count; + + if (!ByteReverseBuilt) + BuildByteReverse(); + + /* Reverse address */ + mem_offset = ByteReverse[0x7F & mem_offset]; - if (!ByteReverseBuilt) - BuildByteReverse (); + /* + * NOTE: The max offset address is 128 or half the reversal table. So + * the LSB is always zero and counts as a built in shift of one bit. + * So even though we need to shift 3 bits to make room for the command, + * we only need to shift twice more because of the built in shift. + */ - mem_offset = ByteReverse[0x7F & mem_offset]; /* Reverse address */ - /* - * NOTE: The max offset address is 128 or half the reversal table. So the - * LSB is always zero and counts as a built in shift of one bit. So even - * though we need to shift 3 bits to make room for the command, we only - * need to shift twice more because of the built in shift. - */ - mem_offset <<= 2; /* Shift for command */ - mem_offset |= EPROM_WRITE; /* Add command */ + /* Shift for command */ + mem_offset <<= 2; + /* Add command */ + mem_offset |= EPROM_WRITE; - eeprom_put_byte (addr, mem_offset, SIZE_ADDR_OP); /* Output chip address */ + /* Output chip address */ + eeprom_put_byte(addr, mem_offset, SIZE_ADDR_OP); - data = ByteReverse[0xFF & data];/* Reverse data */ - eeprom_put_byte (addr, data, NUM_OF_BITS); /* Output chip data */ + /* Reverse data */ + data = ByteReverse[0xFF & data]; + /* Output chip data */ + eeprom_put_byte(addr, data, NUM_OF_BITS); - pci_write_32 ((u_int32_t *) addr, 0); /* Remove Chip Select from - * EEPROM */ + /* Remove Chip Select from EEPROM */ + pci_write_32((u_int32_t *) addr, 0); /* -** Must see Data In at a low state before completing this transaction. -** -** Afterwards, the data bit will return to a high state, ~6 ms, terminating -** the operation. -*/ - pci_write_32 ((u_int32_t *) addr, EPROM_ENCS); /* Re-enable Chip Select */ - temp = pci_read_32 ((u_int32_t *) addr); /* discard first read */ - temp = pci_read_32 ((u_int32_t *) addr); - if (temp & EPROM_ACTIVE_IN_BIT) - { - temp = pci_read_32 ((u_int32_t *) addr); - if (temp & EPROM_ACTIVE_IN_BIT) - { - pci_write_32 ((u_int32_t *) addr, 0); /* Remove Chip Select - * from EEPROM */ - return (1); - } - } - count = 1000; - while (count--) - { - for (temp = 0; temp < 0x10; temp++) - OS_uwait_dummy (); - - if (pci_read_32 ((u_int32_t *) addr) & EPROM_ACTIVE_IN_BIT) - break; - } - - if (count == -1) - return (2); - - return (0); + * Must see Data In at a low state before completing this transaction. + * + * Afterwards, the data bit will return to a high state, ~6 ms, terminating + * the operation. + */ + /* Re-enable Chip Select */ + pci_write_32((u_int32_t *) addr, EPROM_ENCS); + /* discard first read */ + temp = pci_read_32((u_int32_t *) addr); + temp = pci_read_32((u_int32_t *) addr); + if (temp & EPROM_ACTIVE_IN_BIT) { + temp = pci_read_32((u_int32_t *) addr); + if (temp & EPROM_ACTIVE_IN_BIT) { + /* Remove Chip Select from EEPROM */ + pci_write_32((u_int32_t *) addr, 0); + return 1; + } + } + count = 1000; + while (count--) { + for (temp = 0; temp < 0x10; temp++) + OS_uwait_dummy(); + + if (pci_read_32((u_int32_t *) addr) & EPROM_ACTIVE_IN_BIT) + break; + } + + if (count == -1) + return 2; + + return 0; } - /*------------------------------------------------------------------------ * pmcGetBuffValue - read the specified value from buffer *------------------------------------------------------------------------ */ -long -pmcGetBuffValue (char *ptr, int size) +static long pmcGetBuffValue(char *ptr, int size) { - long value = 0; - int index; + long value = 0; + int index; - for (index = 0; index < size; ++index) - { - value <<= 8; - value |= ptr[index] & 0xFF; - } + for (index = 0; index < size; ++index) { + value <<= 8; + value |= ptr[index] & 0xFF; + } - return value; + return value; } - /*------------------------------------------------------------------------ * pmcSetBuffValue - save the specified value to buffer *------------------------------------------------------------------------ */ -void -pmcSetBuffValue (char *ptr, long value, int size) +static void pmcSetBuffValue(char *ptr, long value, int size) { - int index = size; + int index = size; - while (--index >= 0) - { - ptr[index] = (char) (value & 0xFF); - value >>= 8; - } + while (--index >= 0) { + ptr[index] = (char)(value & 0xFF); + value >>= 8; + } } - /*------------------------------------------------------------------------ * pmc_eeprom_read_buffer - read EEPROM data into specified buffer *------------------------------------------------------------------------ */ void -pmc_eeprom_read_buffer (long addr, long mem_offset, char *dest_ptr, int size) +pmc_eeprom_read_buffer(long addr, long mem_offset, char *dest_ptr, int size) { - while (--size >= 0) - *dest_ptr++ = (char) pmc_eeprom_read (addr, mem_offset++); + while (--size >= 0) + *dest_ptr++ = (char)pmc_eeprom_read(addr, mem_offset++); } - /*------------------------------------------------------------------------ * pmc_eeprom_write_buffer - write EEPROM data from specified buffer *------------------------------------------------------------------------ */ void -pmc_eeprom_write_buffer (long addr, long mem_offset, char *dest_ptr, int size) +pmc_eeprom_write_buffer(long addr, long mem_offset, char *dest_ptr, int size) { - enable_pmc_eeprom (addr); + enable_pmc_eeprom(addr); - while (--size >= 0) - pmc_eeprom_write (addr, mem_offset++, *dest_ptr++); + while (--size >= 0) + pmc_eeprom_write(addr, mem_offset++, *dest_ptr++); - disable_pmc_eeprom (addr); + disable_pmc_eeprom(addr); } - /*------------------------------------------------------------------------ * pmcCalcCrc - calculate the CRC for the serial EEPROM structure *------------------------------------------------------------------------ */ -u_int32_t -pmcCalcCrc_T01 (void *bufp) +static u_int32_t pmcCalcCrc_T01(void *bufp) { - FLD_TYPE2 *buf = bufp; - u_int32_t crc; /* CRC of the structure */ + FLD_TYPE2 *buf = bufp; + /* CRC of the structure */ + u_int32_t crc; - /* Calc CRC for type and length fields */ - sbeCrc ( - (u_int8_t *) &buf->type, - (u_int32_t) STRUCT_OFFSET (FLD_TYPE1, Crc32), - (u_int32_t) 0, - (u_int32_t *) &crc); + /* Calc CRC for type and length fields */ + sbeCrc((u_int8_t *) &buf->type, + (u_int32_t) STRUCT_OFFSET(FLD_TYPE1, Crc32), + (u_int32_t) 0, (u_int32_t *) &crc); #ifdef EEPROM_TYPE_DEBUG - pr_info("sbeCrc: crc 1 calculated as %08x\n", crc); /* RLD DEBUG */ + /* RLD DEBUG */ + pr_info("sbeCrc: crc 1 calculated as %08x\n", crc); #endif - return ~crc; + return ~crc; } -u_int32_t -pmcCalcCrc_T02 (void *bufp) +static u_int32_t pmcCalcCrc_T02(void *bufp) { - FLD_TYPE2 *buf = bufp; - u_int32_t crc; /* CRC of the structure */ - - /* Calc CRC for type and length fields */ - sbeCrc ( - (u_int8_t *) &buf->type, - (u_int32_t) STRUCT_OFFSET (FLD_TYPE2, Crc32), - (u_int32_t) 0, - (u_int32_t *) &crc); - - /* Calc CRC for remaining fields */ - sbeCrc ( - (u_int8_t *) &buf->Id[0], - (u_int32_t) (sizeof (FLD_TYPE2) - STRUCT_OFFSET (FLD_TYPE2, Id)), - (u_int32_t) crc, - (u_int32_t *) &crc); + FLD_TYPE2 *buf = bufp; + /* CRC of the structure */ + u_int32_t crc; + + /* Calc CRC for type and length fields */ + sbeCrc((u_int8_t *) &buf->type, + (u_int32_t) STRUCT_OFFSET(FLD_TYPE2, Crc32), + (u_int32_t) 0, (u_int32_t *) &crc); + + /* Calc CRC for remaining fields */ + sbeCrc((u_int8_t *) &buf->Id[0], + (u_int32_t) (sizeof(FLD_TYPE2) - STRUCT_OFFSET(FLD_TYPE2, Id)), + (u_int32_t) crc, (u_int32_t *) &crc); #ifdef EEPROM_TYPE_DEBUG - pr_info("sbeCrc: crc 2 calculated as %08x\n", crc); /* RLD DEBUG */ + /* RLD DEBUG */ + pr_info("sbeCrc: crc 2 calculated as %08x\n", crc); #endif - return crc; + return crc; } - /*------------------------------------------------------------------------ * pmc_init_seeprom - initialize the serial EEPROM structure *------------------------------------------------------------------------ @@ -485,64 +468,65 @@ pmcCalcCrc_T02 (void *bufp) * serial number field. */ -void -pmc_init_seeprom (u_int32_t addr, u_int32_t serialNum) +void pmc_init_seeprom(u_int32_t addr, u_int32_t serialNum) { - PROMFORMAT buffer; /* Memory image of structure */ - u_int32_t crc; /* CRC of structure */ - time_t createTime; + /* Memory image of structure */ + PROMFORMAT buffer; + /* CRC of structure */ + u_int32_t crc; + time_t createTime; - createTime = get_seconds (); + createTime = get_seconds(); - /* use template data */ - memcpy(&buffer.fldType2, mfg_template, sizeof(buffer.fldType2)); + /* use template data */ + memcpy(&buffer.fldType2, mfg_template, sizeof(buffer.fldType2)); - /* Update serial number field in buffer */ - pmcSetBuffValue (&buffer.fldType2.Serial[3], serialNum, 3); + /* Update serial number field in buffer */ + pmcSetBuffValue(&buffer.fldType2.Serial[3], serialNum, 3); - /* Update create time field in buffer */ - pmcSetBuffValue (&buffer.fldType2.CreateTime[0], createTime, 4); + /* Update create time field in buffer */ + pmcSetBuffValue(&buffer.fldType2.CreateTime[0], createTime, 4); - /* Update CRC field in buffer */ - crc = pmcCalcCrc_T02 (&buffer); - pmcSetBuffValue (&buffer.fldType2.Crc32[0], crc, 4); + /* Update CRC field in buffer */ + crc = pmcCalcCrc_T02(&buffer); + pmcSetBuffValue(&buffer.fldType2.Crc32[0], crc, 4); #ifdef DEBUG - for (i = 0; i < sizeof (FLD_TYPE2); ++i) - pr_info("[%02X] = %02X\n", i, buffer.bytes[i] & 0xFF); + for (i = 0; i < sizeof(FLD_TYPE2); ++i) + pr_info("[%02X] = %02X\n", i, buffer.bytes[i] & 0xFF); #endif - /* Write structure to serial EEPROM */ - pmc_eeprom_write_buffer (addr, EE_MFG, (char *) &buffer, sizeof (FLD_TYPE2)); + /* Write structure to serial EEPROM */ + pmc_eeprom_write_buffer(addr, EE_MFG, (char *)&buffer, + sizeof(FLD_TYPE2)); } - -char -pmc_verify_cksum (void *bufp) +char pmc_verify_cksum(void *bufp) { - FLD_TYPE1 *buf1 = bufp; - FLD_TYPE2 *buf2 = bufp; - u_int32_t crc1, crc2; /* CRC read from EEPROM */ + FLD_TYPE1 *buf1 = bufp; + FLD_TYPE2 *buf2 = bufp; + /* CRC read from EEPROM */ + u_int32_t crc1, crc2; - /* Retrieve contents of CRC field */ - crc1 = pmcGetBuffValue (&buf1->Crc32[0], sizeof (buf1->Crc32)); + /* Retrieve contents of CRC field */ + crc1 = pmcGetBuffValue(&buf1->Crc32[0], sizeof(buf1->Crc32)); #ifdef EEPROM_TYPE_DEBUG - pr_info("EEPROM: chksum 1 reads as %08x\n", crc1); /* RLD DEBUG */ + /* RLD DEBUG */ + pr_info("EEPROM: chksum 1 reads as %08x\n", crc1); #endif - if ((buf1->type == PROM_FORMAT_TYPE1) && - (pmcCalcCrc_T01 ((void *) buf1) == crc1)) - return PROM_FORMAT_TYPE1; /* checksum type 1 verified */ + if ((buf1->type == PROM_FORMAT_TYPE1) && + (pmcCalcCrc_T01((void *)buf1) == crc1)) + return PROM_FORMAT_TYPE1; /* checksum type 1 verified */ - crc2 = pmcGetBuffValue (&buf2->Crc32[0], sizeof (buf2->Crc32)); + crc2 = pmcGetBuffValue(&buf2->Crc32[0], sizeof(buf2->Crc32)); #ifdef EEPROM_TYPE_DEBUG - pr_info("EEPROM: chksum 2 reads as %08x\n", crc2); /* RLD DEBUG */ + /* RLD DEBUG */ + pr_info("EEPROM: chksum 2 reads as %08x\n", crc2); #endif - if ((buf2->type == PROM_FORMAT_TYPE2) && - (pmcCalcCrc_T02 ((void *) buf2) == crc2)) - return PROM_FORMAT_TYPE2; /* checksum type 2 verified */ + if ((buf2->type == PROM_FORMAT_TYPE2) && + (pmcCalcCrc_T02((void *)buf2) == crc2)) + return PROM_FORMAT_TYPE2; /* checksum type 2 verified */ - return PROM_FORMAT_Unk; /* failed to validate */ + /* failed to validate */ + return PROM_FORMAT_Unk; } - - -/*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/pmcc4_drv.c b/drivers/staging/cxt1e1/pmcc4_drv.c index 621a7292647567..76bebdd18b3aa9 100644 --- a/drivers/staging/cxt1e1/pmcc4_drv.c +++ b/drivers/staging/cxt1e1/pmcc4_drv.c @@ -122,35 +122,6 @@ c4_find_chan (int channum) return NULL; } - -ci_t *__init -c4_new (void *hi) -{ - ci_t *ci; - -#ifdef SBE_MAP_DEBUG - pr_warning("c4_new() entered, ci needs %u.\n", - (unsigned int) sizeof (ci_t)); -#endif - - ci = (ci_t *) OS_kmalloc (sizeof (ci_t)); - if (ci) - { - ci->hdw_info = hi; - ci->state = C_INIT; /* mark as hardware not available */ - ci->next = c4_list; - c4_list = ci; - ci->brdno = ci->next ? ci->next->brdno + 1 : 0; - } else - pr_warning("failed CI malloc, size %u.\n", - (unsigned int) sizeof (ci_t)); - - if (!CI) - CI = ci; /* DEBUG, only board 0 usage */ - return ci; -} - - /*** * Check port state and set LED states using watchdog or ioctl... * also check for in-band SF loopback commands (& cause results if they are there) @@ -485,12 +456,12 @@ c4_cleanup (void) for (j = 0; j < MUSYCC_NCHANS; j++) { if (pi->chan[j]) - OS_kfree (pi->chan[j]); /* free mch_t struct */ + kfree(pi->chan[j]); /* free mch_t struct */ } - OS_kfree (pi->regram_saved); + kfree(pi->regram_saved); } - OS_kfree (ci->iqd_p_saved); - OS_kfree (ci); + kfree(ci->iqd_p_saved); + kfree(ci); ci = next; /* cleanup next board, if any */ } } @@ -619,7 +590,7 @@ c4_init (ci_t *ci, u_char *func0, u_char *func1) /* allocate channel structures for this port */ for (j = 0; j < MUSYCC_NCHANS; j++) { - ch = OS_kmalloc (sizeof (mch_t)); + ch = kzalloc(sizeof(mch_t), GFP_KERNEL | GFP_DMA); if (ch) { pi->chan[j] = ch; @@ -1368,8 +1339,8 @@ c4_chan_up (ci_t *ci, int channum) ch->txd_num = txnum; ch->rxix_irq_srv = 0; - ch->mdr = OS_kmalloc (sizeof (struct mdesc) * rxnum); - ch->mdt = OS_kmalloc (sizeof (struct mdesc) * txnum); + ch->mdr = kzalloc(sizeof(struct mdesc) * rxnum, GFP_KERNEL | GFP_DMA); + ch->mdt = kzalloc(sizeof(struct mdesc) * txnum, GFP_KERNEL | GFP_DMA); if (ch->p.chan_mode == CFG_CH_PROTO_TRANS) tmp = __constant_cpu_to_le32 (cxt1e1_max_mru | EOBIRQ_ENABLE); else @@ -1462,10 +1433,10 @@ c4_chan_up (ci_t *ci, int channum) i--; OS_mem_token_free (ch->mdr[i].mem_token); } - OS_kfree (ch->mdt); + kfree(ch->mdt); ch->mdt = NULL; ch->txd_num = 0; - OS_kfree (ch->mdr); + kfree(ch->mdr); ch->mdr = NULL; ch->rxd_num = 0; ch->state = DOWN; diff --git a/drivers/staging/cxt1e1/pmcc4_private.h b/drivers/staging/cxt1e1/pmcc4_private.h index eb28f095ff8c29..451f12f5b04c82 100644 --- a/drivers/staging/cxt1e1/pmcc4_private.h +++ b/drivers/staging/cxt1e1/pmcc4_private.h @@ -262,7 +262,7 @@ struct s_hdw_info struct pci_dev *pdev[2]; unsigned long addr[2]; - unsigned long addr_mapped[2]; + void __iomem *addr_mapped[2]; unsigned long len[2]; union diff --git a/drivers/staging/cxt1e1/sbecom_inline_linux.h b/drivers/staging/cxt1e1/sbecom_inline_linux.h index ba3ff3efe06343..f5835c29ef3247 100644 --- a/drivers/staging/cxt1e1/sbecom_inline_linux.h +++ b/drivers/staging/cxt1e1/sbecom_inline_linux.h @@ -39,27 +39,6 @@ void pci_write_32 (u_int32_t *p, u_int32_t v); * system dependent callbacks */ -/**********/ -/* malloc */ -/**********/ - -static inline void * -OS_kmalloc (size_t size) -{ - char *ptr = kmalloc (size, GFP_KERNEL | GFP_DMA); - - if (ptr) - memset (ptr, 0, size); - return ptr; -} - -static inline void -OS_kfree (void *x) -{ - kfree (x); -} - - /****************/ /* memory token */ /****************/ @@ -197,7 +176,7 @@ static inline int OS_free_watchdog (struct watchdog *wd) { OS_stop_watchdog (wd); - OS_kfree (wd); + kfree(wd); return 0; } diff --git a/drivers/staging/cxt1e1/sbecrc.c b/drivers/staging/cxt1e1/sbecrc.c index 81fa8a3a462cc6..a51780f6048460 100644 --- a/drivers/staging/cxt1e1/sbecrc.c +++ b/drivers/staging/cxt1e1/sbecrc.c @@ -101,7 +101,8 @@ sbeCrc(u_int8_t *buffer, /* data buffer to crc */ tbl = &CRCTable; genCrcTable(tbl); #else - tbl = (u_int32_t *) OS_kmalloc(CRC_TABLE_ENTRIES * sizeof(u_int32_t)); + tbl = kzalloc(CRC_TABLE_ENTRIES * sizeof(u_int32_t), + GFP_KERNEL); if (!tbl) { *result = 0; /* dummy up return value due to malloc * failure */ @@ -125,7 +126,7 @@ sbeCrc(u_int8_t *buffer, /* data buffer to crc */ #ifndef STATIC_CRC_TABLE crcTableInit = 0; - OS_kfree(tbl); + kfree(tbl); #endif } diff --git a/drivers/staging/cxt1e1/sbeproc.c b/drivers/staging/cxt1e1/sbeproc.c index 840c647fbf4107..1c2e52e8b5fe40 100644 --- a/drivers/staging/cxt1e1/sbeproc.c +++ b/drivers/staging/cxt1e1/sbeproc.c @@ -72,7 +72,7 @@ static int sbecom_proc_get_sbe_info(struct seq_file *m, void *v) char *spd; struct sbe_brd_info *bip; - bip = OS_kmalloc(sizeof(struct sbe_brd_info)); + bip = kzalloc(sizeof(struct sbe_brd_info), GFP_KERNEL | GFP_DMA); if (!bip) return -ENOMEM; diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c index a5fc3c75ed4e11..3c9278a224e2b8 100644 --- a/drivers/staging/dgap/dgap.c +++ b/drivers/staging/dgap/dgap.c @@ -12,21 +12,6 @@ * 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. - * - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - * */ /* @@ -78,21 +63,11 @@ #include "dgap.h" -#define init_MUTEX(sem) sema_init(sem, 1) -#define DECLARE_MUTEX(name) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Digi International, http://www.digi.com"); MODULE_DESCRIPTION("Driver for the Digi International EPCA PCI based product line"); MODULE_SUPPORTED_DEVICE("dgap"); -/************************************************************************** - * - * protos for this file - * - */ - static int dgap_start(void); static void dgap_init_globals(void); static int dgap_found_board(struct pci_dev *pdev, int id); @@ -105,7 +80,6 @@ static int dgap_probe1(struct pci_dev *pdev, int card_type); static int dgap_do_remap(struct board_t *brd); static irqreturn_t dgap_intr(int irq, void *voidbrd); -/* Our function prototypes */ static int dgap_tty_open(struct tty_struct *tty, struct file *file); static void dgap_tty_close(struct tty_struct *tty, struct file *file); static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, @@ -161,9 +135,9 @@ static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds); static int dgap_event(struct board_t *bd); static void dgap_poll_tasklet(unsigned long data); -static void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, - uchar byte2, uint ncmds); -static void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds); +static void dgap_cmdb(struct channel_t *ch, u8 cmd, u8 byte1, + u8 byte2, uint ncmds); +static void dgap_cmdw(struct channel_t *ch, u8 cmd, u16 word, uint ncmds); static void dgap_wmove(struct channel_t *ch, char *buf, uint cnt); static int dgap_param(struct tty_struct *tty); static void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, @@ -210,22 +184,21 @@ static uint dgap_config_get_useintr(struct board_t *bd); static uint dgap_config_get_altpin(struct board_t *bd); static int dgap_ms_sleep(ulong ms); -static void dgap_do_bios_load(struct board_t *brd, const uchar *ubios, int len); -static void dgap_do_fep_load(struct board_t *brd, const uchar *ufep, int len); +static void dgap_do_bios_load(struct board_t *brd, const u8 *ubios, int len); +static void dgap_do_fep_load(struct board_t *brd, const u8 *ufep, int len); #ifdef DIGI_CONCENTRATORS_SUPPORTED -static void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len); +static void dgap_do_conc_load(struct board_t *brd, u8 *uaddr, int len); #endif static int dgap_after_config_loaded(int board); static int dgap_finalize_board_init(struct board_t *brd); static void dgap_get_vpd(struct board_t *brd); static void dgap_do_reset_board(struct board_t *brd); -static int dgap_do_wait_for_bios(struct board_t *brd); -static int dgap_do_wait_for_fep(struct board_t *brd); +static int dgap_test_bios(struct board_t *brd); +static int dgap_test_fep(struct board_t *brd); static int dgap_tty_register_ports(struct board_t *brd); static int dgap_firmware_load(struct pci_dev *pdev, int card_type); -/* Driver unload function */ static void dgap_cleanup_module(void); module_exit(dgap_cleanup_module); @@ -237,22 +210,14 @@ static const struct file_operations DgapBoardFops = { .owner = THIS_MODULE, }; -/* - * Globals - */ static uint dgap_NumBoards; static struct board_t *dgap_Board[MAXBOARDS]; static ulong dgap_poll_counter; static char *dgap_config_buf; static int dgap_driver_state = DRIVER_INITIALIZED; -DEFINE_SPINLOCK(dgap_dl_lock); static wait_queue_head_t dgap_dl_wait; -static int dgap_dl_action; static int dgap_poll_tick = 20; /* Poll interval - 20 ms */ -/* - * Static vars. - */ static struct class *dgap_class; static struct board_t *dgap_BoardsByMajor[256]; @@ -310,7 +275,7 @@ MODULE_DEVICE_TABLE(pci, dgap_pci_tbl); */ struct board_id { uint config_type; - uchar *name; + u8 *name; uint maxports; uint dpatype; }; @@ -342,10 +307,10 @@ static struct pci_driver dgap_driver = { }; struct firmware_info { - uchar *conf_name; /* dgap.conf */ - uchar *bios_name; /* BIOS filename */ - uchar *fep_name; /* FEP filename */ - uchar *con_name; /* Concentrator filename FIXME*/ + u8 *conf_name; /* dgap.conf */ + u8 *bios_name; /* BIOS filename */ + u8 *fep_name; /* FEP filename */ + u8 *con_name; /* Concentrator filename FIXME*/ int num; /* sequence number */ }; @@ -655,8 +620,6 @@ static void dgap_cleanup_module(void) class_destroy(dgap_class); unregister_chrdev(DIGI_DGAP_MAJOR, "dgap"); - kfree(dgap_config_buf); - for (i = 0; i < dgap_NumBoards; ++i) { dgap_remove_ports_sysfiles(dgap_Board[i]); dgap_tty_uninit(dgap_Board[i]); @@ -819,9 +782,8 @@ static int dgap_found_board(struct pci_dev *pdev, int id) if (i) brd->state = BOARD_FAILED; - pr_info("dgap: board %d: %s (rev %d), irq %ld, %s\n", - dgap_NumBoards, brd->name, brd->rev, brd->irq, - brd->state ? "NOT READY\0" : "READY\0"); + pr_info("dgap: board %d: %s (rev %d), irq %ld\n", + dgap_NumBoards, brd->name, brd->rev, brd->irq); return 0; } @@ -863,7 +825,7 @@ static int dgap_firmware_load(struct pci_dev *pdev, int card_type) dgap_get_vpd(brd); dgap_do_reset_board(brd); - if (fw_info[card_type].conf_name) { + if ((fw_info[card_type].conf_name) && !dgap_config_buf) { ret = request_firmware(&fw, fw_info[card_type].conf_name, &pdev->dev); if (ret) { @@ -871,20 +833,22 @@ static int dgap_firmware_load(struct pci_dev *pdev, int card_type) fw_info[card_type].conf_name); return ret; } + + dgap_config_buf = kmalloc(fw->size + 1, GFP_KERNEL); if (!dgap_config_buf) { - dgap_config_buf = kmalloc(fw->size + 1, GFP_ATOMIC); - if (!dgap_config_buf) { - release_firmware(fw); - return -ENOMEM; - } + release_firmware(fw); + return -ENOMEM; } memcpy(dgap_config_buf, fw->data, fw->size); release_firmware(fw); dgap_config_buf[fw->size + 1] = '\0'; - if (dgap_parsefile(&dgap_config_buf, TRUE) != 0) + if (dgap_parsefile(&dgap_config_buf, TRUE) != 0) { + kfree(dgap_config_buf); return -EINVAL; + } + kfree(dgap_config_buf); } ret = dgap_after_config_loaded(brd->boardnum); @@ -926,8 +890,9 @@ static int dgap_firmware_load(struct pci_dev *pdev, int card_type) release_firmware(fw); /* Wait for BIOS to test board... */ - if (!dgap_do_wait_for_bios(brd)) - return -ENXIO; + ret = dgap_test_bios(brd); + if (ret) + return ret; } if (fw_info[card_type].fep_name) { @@ -942,8 +907,9 @@ static int dgap_firmware_load(struct pci_dev *pdev, int card_type) release_firmware(fw); /* Wait for FEP to load on board... */ - if (!dgap_do_wait_for_fep(brd)) - return -ENXIO; + ret = dgap_test_fep(brd); + if (ret) + return ret; } #ifdef DIGI_CONCENTRATORS_SUPPORTED @@ -1197,7 +1163,6 @@ static void dgap_init_globals(void) init_timer(&dgap_poll_timer); init_waitqueue_head(&dgap_dl_wait); - dgap_dl_action = 0; } /************************************************************************ @@ -1328,8 +1293,8 @@ static int dgap_tty_init(struct board_t *brd) int i; int tlw; uint true_count = 0; - uchar *vaddr; - uchar modem = 0; + u8 *vaddr; + u8 modem = 0; struct channel_t *ch; struct bs_t *bs; struct cm_t *cm; @@ -1540,8 +1505,8 @@ static void dgap_tty_uninit(struct board_t *brd) * dgap_sniff - Dump data out to the "sniff" buffer if the * proc sniff file is opened... */ -static void dgap_sniff_nowait_nolock(struct channel_t *ch, uchar *text, - uchar *buf, int len) +static void dgap_sniff_nowait_nolock(struct channel_t *ch, u8 *text, + u8 *buf, int len) { struct timeval tv; int n; @@ -1675,8 +1640,8 @@ static void dgap_input(struct channel_t *ch) int flip_len; int len = 0; int n = 0; - uchar *buf; - uchar tmpchar; + u8 *buf; + u8 tmpchar; int s = 0; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) @@ -2445,7 +2410,7 @@ static int dgap_tty_chars_in_buffer(struct tty_struct *tty) struct channel_t *ch = NULL; struct un_t *un = NULL; struct bs_t *bs = NULL; - uchar tbusy; + u8 tbusy; uint chars = 0; u16 thead, ttail, tmask, chead, ctail; ulong lock_flags = 0; @@ -2878,8 +2843,8 @@ static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, n -= remain; vaddr = ch->ch_taddr + head; - memcpy_toio(vaddr, (uchar *) buf, remain); - dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, + memcpy_toio(vaddr, (u8 *) buf, remain); + dgap_sniff_nowait_nolock(ch, "USER WRITE", (u8 *) buf, remain); head = ch->ch_tstart; @@ -2894,8 +2859,8 @@ static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, vaddr = ch->ch_taddr + head; remain = n; - memcpy_toio(vaddr, (uchar *) buf, remain); - dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *)buf, + memcpy_toio(vaddr, (u8 *) buf, remain); + dgap_sniff_nowait_nolock(ch, "USER WRITE", (u8 *)buf, remain); head += remain; @@ -2950,7 +2915,7 @@ static int dgap_tty_tiocmget(struct tty_struct *tty) struct channel_t *ch; struct un_t *un; int result = -EIO; - uchar mstat = 0; + u8 mstat = 0; ulong lock_flags; if (!tty || tty->magic != TTY_MAGIC) @@ -3176,7 +3141,7 @@ static void dgap_tty_send_xchar(struct tty_struct *tty, char c) static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value) { int result = 0; - uchar mstat = 0; + u8 mstat = 0; ulong lock_flags; int rc = 0; @@ -4336,9 +4301,9 @@ static int dgap_tty_register_ports(struct board_t *brd) * Copies the BIOS code from the user to the board, * and starts the BIOS running. */ -static void dgap_do_bios_load(struct board_t *brd, const uchar *ubios, int len) +static void dgap_do_bios_load(struct board_t *brd, const u8 *ubios, int len) { - uchar *addr; + u8 *addr; uint offset; int i; @@ -4369,16 +4334,15 @@ static void dgap_do_bios_load(struct board_t *brd, const uchar *ubios, int len) /* * Checks to see if the BIOS completed running on the card. */ -static int dgap_do_wait_for_bios(struct board_t *brd) +static int dgap_test_bios(struct board_t *brd) { - uchar *addr; + u8 *addr; u16 word; u16 err1; u16 err2; - int ret = 0; if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) - return ret; + return -EINVAL; addr = brd->re_map_membase; word = readw(addr + POSTAREA); @@ -4392,7 +4356,7 @@ static int dgap_do_wait_for_bios(struct board_t *brd) while (brd->wait_for_bios < 1000) { /* Check to see if BIOS thinks board is good. (GD). */ if (word == *(u16 *) "GD") - return 1; + return 0; msleep_interruptible(10); brd->wait_for_bios++; word = readw(addr + POSTAREA); @@ -4406,16 +4370,16 @@ static int dgap_do_wait_for_bios(struct board_t *brd) brd->state = BOARD_FAILED; brd->dpastatus = BD_NOBIOS; - return ret; + return -EIO; } /* * Copies the FEP code from the user to the board, * and starts the FEP running. */ -static void dgap_do_fep_load(struct board_t *brd, const uchar *ufep, int len) +static void dgap_do_fep_load(struct board_t *brd, const u8 *ufep, int len) { - uchar *addr; + u8 *addr; uint offset; if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) @@ -4434,8 +4398,8 @@ static void dgap_do_fep_load(struct board_t *brd, const uchar *ufep, int len) * it its config string describing how the concentrators look. */ if ((brd->type == PCX) || (brd->type == PEPC)) { - uchar string[100]; - uchar *config, *xconfig; + u8 string[100]; + u8 *config, *xconfig; int i = 0; xconfig = dgap_create_config_string(brd, string); @@ -4457,16 +4421,15 @@ static void dgap_do_fep_load(struct board_t *brd, const uchar *ufep, int len) /* * Waits for the FEP to report thats its ready for us to use. */ -static int dgap_do_wait_for_fep(struct board_t *brd) +static int dgap_test_fep(struct board_t *brd) { - uchar *addr; + u8 *addr; u16 word; u16 err1; u16 err2; - int ret = 0; if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) - return ret; + return -EINVAL; addr = brd->re_map_membase; word = readw(addr + FEPSTAT); @@ -4486,7 +4449,7 @@ static int dgap_do_wait_for_fep(struct board_t *brd) if (word == *(u16 *) "5A") brd->bd_flags |= BD_FEP5PLUS; - return 1; + return 0; } msleep_interruptible(10); brd->wait_for_fep++; @@ -4501,7 +4464,7 @@ static int dgap_do_wait_for_fep(struct board_t *brd) brd->state = BOARD_FAILED; brd->dpastatus = BD_NOFEP; - return ret; + return -EIO; } /* @@ -4509,7 +4472,7 @@ static int dgap_do_wait_for_fep(struct board_t *brd) */ static void dgap_do_reset_board(struct board_t *brd) { - uchar check; + u8 check; u32 check1; u32 check2; int i = 0; @@ -4557,7 +4520,7 @@ static void dgap_do_reset_board(struct board_t *brd) /* * Sends a concentrator image into the FEP5 board. */ -static void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len) +static void dgap_do_conc_load(struct board_t *brd, u8 *uaddr, int len) { char *vaddr; u16 offset = 0; @@ -4590,8 +4553,8 @@ static void dgap_get_vpd(struct board_t *brd) u16 vpd_offset; u16 image_length; u16 i; - uchar byte1; - uchar byte2; + u8 byte1; + u8 byte2; /* * Poke the magic number at the PCI Rom Address location. @@ -4770,8 +4733,8 @@ static void dgap_poll_tasklet(unsigned long data) * in the cmd buffer before returning. * *=======================================================================*/ -static void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, - uchar byte2, uint ncmds) +static void dgap_cmdb(struct channel_t *ch, u8 cmd, u8 byte1, + u8 byte2, uint ncmds) { char *vaddr = NULL; struct cm_t *cm_addr = NULL; @@ -4813,7 +4776,7 @@ static void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, * Put the data in the circular command buffer. */ writeb(cmd, (char *) (vaddr + head + CMDSTART + 0)); - writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1)); + writeb((u8) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1)); writeb(byte1, (char *) (vaddr + head + CMDSTART + 2)); writeb(byte2, (char *) (vaddr + head + CMDSTART + 3)); @@ -4856,7 +4819,7 @@ static void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, * in the cmd buffer before returning. * *=======================================================================*/ -static void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds) +static void dgap_cmdw(struct channel_t *ch, u8 cmd, u16 word, uint ncmds) { char *vaddr = NULL; struct cm_t *cm_addr = NULL; @@ -4897,7 +4860,7 @@ static void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds) * Put the data in the circular command buffer. */ writeb(cmd, (char *) (vaddr + head + CMDSTART + 0)); - writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1)); + writeb((u8) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1)); writew((u16) word, (char *) (vaddr + head + CMDSTART + 2)); head = (head + 4) & (CMDMAX - CMDSTART - 4); @@ -4981,9 +4944,9 @@ static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds) */ /* Write an FF to tell the FEP that we want an extended command */ - writeb((uchar) 0xff, (char *) (vaddr + head + CMDSTART + 0)); + writeb((u8) 0xff, (char *) (vaddr + head + CMDSTART + 0)); - writeb((uchar) ch->ch_portnum, (uchar *) (vaddr + head + CMDSTART + 1)); + writeb((u8) ch->ch_portnum, (u8 *) (vaddr + head + CMDSTART + 1)); writew((u16) cmd, (char *) (vaddr + head + CMDSTART + 2)); /* @@ -5088,7 +5051,7 @@ static void dgap_wmove(struct channel_t *ch, char *buf, uint cnt) */ static uint dgap_get_custom_baud(struct channel_t *ch) { - uchar *vaddr; + u8 *vaddr; ulong offset = 0; uint value = 0; @@ -5160,8 +5123,8 @@ static int dgap_param(struct tty_struct *tty) u16 head; u16 cflag; u16 iflag; - uchar mval; - uchar hflow; + u8 mval; + u8 hflow; if (!tty || tty->magic != TTY_MAGIC) return -ENXIO; @@ -5427,7 +5390,7 @@ static int dgap_param(struct tty_struct *tty) ch->ch_hflow = hflow; /* Okay to have channel and board locks held calling this */ - dgap_cmdb(ch, SHFLOW, (uchar) hflow, 0xff, 0); + dgap_cmdb(ch, SHFLOW, (u8) hflow, 0xff, 0); } @@ -5455,7 +5418,7 @@ static int dgap_param(struct tty_struct *tty) ch->ch_mostat = mval; /* Okay to have channel and board locks held calling this */ - dgap_cmdb(ch, SMODEM, (uchar) mval, D_RTS(ch)|D_DTR(ch), 0); + dgap_cmdb(ch, SMODEM, (u8) mval, D_RTS(ch)|D_DTR(ch), 0); } /* @@ -5609,8 +5572,8 @@ static int dgap_event(struct board_t *bd) ulong lock_flags; ulong lock_flags2; struct bs_t *bs; - uchar *event; - uchar *vaddr = NULL; + u8 *event; + u8 *vaddr = NULL; struct ev_t *eaddr = NULL; uint head; uint tail; diff --git a/drivers/staging/dgap/dgap.h b/drivers/staging/dgap/dgap.h index 6b8f5f8583272f..b23570bd183dbc 100644 --- a/drivers/staging/dgap/dgap.h +++ b/drivers/staging/dgap/dgap.h @@ -39,9 +39,6 @@ # define FALSE 0 #endif -/* Required for our shared headers! */ -typedef unsigned char uchar; - #if !defined(TTY_FLIPBUF_SIZE) # define TTY_FLIPBUF_SIZE 512 #endif @@ -61,7 +58,7 @@ typedef unsigned char uchar; /* * defines from dgap_pci.h - */ + */ #define PCIMAX 32 /* maximum number of PCI boards */ #define DIGI_VID 0x114F @@ -186,7 +183,7 @@ typedef unsigned char uchar; ECHOCTL | ECHOKE | IEXTEN) #ifndef _POSIX_VDISABLE -#define _POSIX_VDISABLE '\0' +#define _POSIX_VDISABLE ('\0') #endif #define SNIFF_MAX 65536 /* Sniff buffer size (2^n) */ @@ -207,9 +204,11 @@ typedef unsigned char uchar; #define EVSTART 0x0800L /* Start of event buffer */ #define EVMAX 0x0c00L /* End of event buffer */ #define FEP5_PLUS 0x0E40 /* ASCII '5' and ASCII 'A' is here */ -#define ECS_SEG 0x0E44 /* Segment of the extended channel structure */ -#define LINE_SPEED 0x10 /* Offset into ECS_SEG for line speed */ - /* if the fep has extended capabilities */ +#define ECS_SEG 0x0E44 /* Segment of the extended */ + /* channel structure */ +#define LINE_SPEED 0x10 /* Offset into ECS_SEG for line */ + /* speed if the fep has extended */ + /* capabilities */ /* BIOS MAGIC SPOTS */ #define ERROR 0x0C14L /* BIOS error code */ @@ -247,12 +246,12 @@ typedef unsigned char uchar; #define FEPTIMEOUT 200000 -#define ENABLE_INTR 0x0e04 /* Enable interrupts flag */ -#define FEPPOLL_MIN 1 /* minimum of 1 millisecond */ -#define FEPPOLL_MAX 20 /* maximum of 20 milliseconds */ -#define FEPPOLL 0x0c26 /* Fep event poll interval */ +#define ENABLE_INTR 0x0e04 /* Enable interrupts flag */ +#define FEPPOLL_MIN 1 /* minimum of 1 millisecond */ +#define FEPPOLL_MAX 20 /* maximum of 20 milliseconds */ +#define FEPPOLL 0x0c26 /* Fep event poll interval */ -#define IALTPIN 0x0080 /* Input flag to swap DSR <-> DCD */ +#define IALTPIN 0x0080 /* Input flag to swap DSR <-> DCD */ /************************************************************************ * FEP supported functions @@ -280,14 +279,12 @@ typedef unsigned char uchar; #define SPINTFC 0xfc /* Reserved */ #define SCOMMODE 0xfd /* Set RS232/422 mode */ - /************************************************************************ * Modes for SCOMMODE ************************************************************************/ #define MODE_232 0x00 #define MODE_422 0x01 - /************************************************************************ * Event flags. ************************************************************************/ @@ -362,13 +359,13 @@ typedef unsigned char uchar; #define MC8E8K 36 #define AVANFS 42 /* start of Avanstar family definitions */ -#define A8P 42 +#define A8P 42 #define A16P 43 #define AVANFE 43 /* end of Avanstar family definitions */ -#define DA2000FS 44 /* start of AccelePort 2000 family definitions */ -#define DA22 44 /* AccelePort 2002 */ -#define DA24 45 /* AccelePort 2004 */ +#define DA2000FS 44 /* start of AccelePort 2000 family definitions */ +#define DA22 44 /* AccelePort 2002 */ +#define DA24 45 /* AccelePort 2004 */ #define DA28 46 /* AccelePort 2008 */ #define DA216 47 /* AccelePort 2016 */ #define DAR4 48 /* AccelePort RAS 4 port */ @@ -492,8 +489,6 @@ enum { REQUESTED_CONCENTRATOR }; - - /* * Modem line constants are defined as macros because DSR and * DCD are swapable using the ditty altpin option. @@ -505,14 +500,12 @@ enum { #define D_RI(ch) DM_RI /* Ring indicator */ #define D_DTR(ch) DM_DTR /* Data terminal ready */ - /************************************************************************* * * Structures and closely related defines. * *************************************************************************/ - /* * A structure to hold a statistics counter. We also * compute moving averages for this counter. @@ -524,7 +517,6 @@ struct macounter { ulong ema; /* Exponential moving average */ }; - /************************************************************************ * Device flag definitions for bd_flags. ************************************************************************/ @@ -546,11 +538,11 @@ struct board_t { u16 device; /* PCI device ID */ u16 subvendor; /* PCI subsystem vendor ID */ u16 subdevice; /* PCI subsystem device ID */ - uchar rev; /* PCI revision ID */ + u8 rev; /* PCI revision ID */ uint pci_bus; /* PCI bus value */ uint pci_slot; /* PCI slot value */ u16 maxports; /* MAX ports this board can handle */ - uchar vpd[VPDSIZE]; /* VPD of board, if found */ + u8 vpd[VPDSIZE]; /* VPD of board, if found */ u32 bd_flags; /* Board flags */ spinlock_t bd_lock; /* Used to protect board */ @@ -571,20 +563,22 @@ struct board_t { ulong irq; /* Interrupt request number */ ulong intr_count; /* Count of interrupts */ u32 intr_used; /* Non-zero if using interrupts */ - u32 intr_running; /* Non-zero if FEP knows its doing interrupts */ + u32 intr_running; /* Non-zero if FEP knows its doing */ + /* interrupts */ ulong port; /* Start of base io port of the card */ ulong port_end; /* End of base io port of the card */ ulong membase; /* Start of base memory of the card */ ulong membase_end; /* End of base memory of the card */ - uchar *re_map_port; /* Remapped io port of the card */ - uchar *re_map_membase;/* Remapped memory of the card */ + u8 *re_map_port; /* Remapped io port of the card */ + u8 *re_map_membase;/* Remapped memory of the card */ - uchar runwait; /* # Processes waiting for FEP */ - uchar inhibit_poller; /* Tells the poller to leave us alone */ + u8 runwait; /* # Processes waiting for FEP */ + u8 inhibit_poller; /* Tells the poller to leave us alone */ - struct channel_t *channels[MAXPORTS]; /* array of pointers to our channels. */ + struct channel_t *channels[MAXPORTS]; /* array of pointers to our */ + /* channels. */ struct tty_driver *SerialDriver; struct tty_port *SerialPorts; @@ -599,20 +593,23 @@ struct board_t { u32 dgap_Serial_Major; u32 dgap_TransparentPrint_Major; - struct bs_t *bd_bs; /* Base structure pointer */ + struct bs_t *bd_bs; /* Base structure pointer */ - char *flipbuf; /* Our flip buffer, alloced if board is found */ - char *flipflagbuf; /* Our flip flag buffer, alloced if board is found */ + char *flipbuf; /* Our flip buffer, alloced if */ + /* board is found */ + char *flipflagbuf; /* Our flip flag buffer, alloced */ + /* if board is found */ - u16 dpatype; /* The board "type", as defined by DPA */ - u16 dpastatus; /* The board "status", as defined by DPA */ - wait_queue_head_t kme_wait; /* Needed for DPA support */ + u16 dpatype; /* The board "type", as defined */ + /* by DPA */ + u16 dpastatus; /* The board "status", as defined */ + /* by DPA */ + wait_queue_head_t kme_wait; /* Needed for DPA support */ - u32 conc_dl_status; /* Status of any pending conc download */ + u32 conc_dl_status; /* Status of any pending conc */ + /* download */ }; - - /************************************************************************ * Unit flag definitions for un_flags. ************************************************************************/ @@ -650,7 +647,6 @@ struct un_t { struct device *un_sysfs; }; - /************************************************************************ * Device flag definitions for ch_flags. ************************************************************************/ @@ -677,7 +673,6 @@ struct un_t { #define SNIFF_WAIT_DATA 0x2 #define SNIFF_WAIT_SPACE 0x4 - /************************************************************************ *** Definitions for Digi ditty(1) command. ************************************************************************/ @@ -689,8 +684,8 @@ struct un_t { #if !defined(TIOCMODG) -#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */ -#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */ +#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */ +#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */ #ifndef TIOCM_LE #define TIOCM_LE 0x01 /* line enable */ @@ -709,16 +704,15 @@ struct un_t { #endif #if !defined(TIOCMSET) -#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */ -#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */ +#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */ +#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */ #endif #if !defined(TIOCMBIC) -#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */ -#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */ +#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */ +#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */ #endif - #if !defined(TIOCSDTR) #define TIOCSDTR (('e'<<8) | 0) /* set DTR */ #define TIOCCDTR (('e'<<8) | 1) /* clear DTR */ @@ -737,26 +731,25 @@ struct un_t { /* Adapter Memory */ #define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */ - /* control characters */ -#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */ + /* control characters */ +#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */ /* control characters */ -#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */ - /* flow control chars */ -#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */ +#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */ + /* flow control chars */ +#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */ /* flow control chars */ -#define DIGI_GEDELAY (('d'<<8) | 246) /* Get edelay */ -#define DIGI_SEDELAY (('d'<<8) | 247) /* Set edelay */ +#define DIGI_GEDELAY (('d'<<8) | 246) /* Get edelay */ +#define DIGI_SEDELAY (('d'<<8) | 247) /* Set edelay */ struct digiflow_t { - unsigned char startc; /* flow cntl start char */ - unsigned char stopc; /* flow cntl stop char */ + unsigned char startc; /* flow cntl start char */ + unsigned char stopc; /* flow cntl stop char */ }; - #ifdef FLOW_2200 -#define F2200_GETA (('e'<<8) | 104) /* Get 2x36 flow cntl flags */ -#define F2200_SETAW (('e'<<8) | 105) /* Set 2x36 flow cntl flags */ +#define F2200_GETA (('e'<<8) | 104) /* Get 2x36 flow cntl flags */ +#define F2200_SETAW (('e'<<8) | 105) /* Set 2x36 flow cntl flags */ #define F2200_MASK 0x03 /* 2200 flow cntl bit mask */ #define FCNTL_2200 0x01 /* 2x36 terminal flow cntl */ #define PCNTL_2200 0x02 /* 2x36 printer flow cntl */ @@ -830,59 +823,6 @@ struct rw_t { unsigned char rw_data[128]; /* Data to read/write */ }; -/*********************************************************************** - * Shrink Buffer and Board Information definitions and structures. - - ************************************************************************/ - /* Board type return codes */ -#define PCXI_TYPE 1 /* Board type at the designated port is a PC/Xi */ -#define PCXM_TYPE 2 /* Board type at the designated port is a PC/Xm */ -#define PCXE_TYPE 3 /* Board type at the designated port is a PC/Xe */ -#define MCXI_TYPE 4 /* Board type at the designated port is a MC/Xi */ -#define COMXI_TYPE 5 /* Board type at the designated port is a COM/Xi */ - - /* Non-Zero Result codes. */ -#define RESULT_NOBDFND 1 /* A Digi product at that port is not config installed */ -#define RESULT_NODESCT 2 /* A memory descriptor was not obtainable */ -#define RESULT_NOOSSIG 3 /* FEP/OS signature was not detected on the board */ -#define RESULT_TOOSML 4 /* Too small an area to shrink. */ -#define RESULT_NOCHAN 5 /* Channel structure for the board was not found */ - -struct shrink_buf_struct { - unsigned long shrink_buf_vaddr; /* Virtual address of board */ - unsigned long shrink_buf_phys; /* Physical address of board */ - unsigned long shrink_buf_bseg; /* Amount of board memory */ - unsigned long shrink_buf_hseg; /* '186 Beginning of Dual-Port */ - - unsigned long shrink_buf_lseg; /* '186 Beginning of freed memory */ - unsigned long shrink_buf_mseg; /* Linear address from start of - dual-port were freed memory - begins, host viewpoint. */ - - unsigned long shrink_buf_bdparam; /* Parameter for xxmemon and - xxmemoff */ - - unsigned long shrink_buf_reserva; /* Reserved */ - unsigned long shrink_buf_reservb; /* Reserved */ - unsigned long shrink_buf_reservc; /* Reserved */ - unsigned long shrink_buf_reservd; /* Reserved */ - - unsigned char shrink_buf_result; /* Reason for call failing - Zero is Good return */ - unsigned char shrink_buf_init; /* Non-Zero if it caused an - xxinit call. */ - - unsigned char shrink_buf_anports; /* Number of async ports */ - unsigned char shrink_buf_snports; /* Number of sync ports */ - unsigned char shrink_buf_type; /* Board type 1 = PC/Xi, - 2 = PC/Xm, - 3 = PC/Xe - 4 = MC/Xi - 5 = COMX/i */ - unsigned char shrink_buf_card; /* Card number */ - -}; - /************************************************************************ * Structure to get driver status information ************************************************************************/ @@ -892,7 +832,7 @@ struct digi_dinfo { char dinfo_version[16]; /* driver version */ }; -#define DIGI_GETDD (('d'<<8) | 248) /* get driver info */ +#define DIGI_GETDD (('d'<<8) | 248) /* get driver info */ /************************************************************************ * Structure used with ioctl commands for per-board information @@ -912,7 +852,7 @@ struct digi_info { char info_reserved[7]; /* for future expansion */ }; -#define DIGI_GETBD (('d'<<8) | 249) /* get board info */ +#define DIGI_GETBD (('d'<<8) | 249) /* get board info */ struct digi_stat { unsigned int info_chan; /* Channel number (0 based) */ @@ -927,7 +867,7 @@ struct digi_stat { unsigned long info_reserved[8]; /* for future expansion */ }; -#define DIGI_GETSTAT (('d'<<8) | 244) /* get board info */ +#define DIGI_GETSTAT (('d'<<8) | 244) /* get board info */ /************************************************************************ * * Structure used with ioctl commands for per-channel information @@ -936,9 +876,9 @@ struct digi_stat { struct digi_ch { unsigned long info_bdnum; /* Board number (0 based) */ unsigned long info_channel; /* Channel index number */ - unsigned long info_ch_cflag; /* Channel cflag */ - unsigned long info_ch_iflag; /* Channel iflag */ - unsigned long info_ch_oflag; /* Channel oflag */ + unsigned long info_ch_cflag; /* Channel cflag */ + unsigned long info_ch_iflag; /* Channel iflag */ + unsigned long info_ch_oflag; /* Channel oflag */ unsigned long info_chsize; /* Channel structure size */ unsigned long info_sleep_stat; /* sleep status */ dev_t info_dev; /* device number */ @@ -970,7 +910,7 @@ struct digi_cmd { #define INFO_CH_WLOW 0x0020 #define INFO_XXBUF_BUSY 0x0040 -#define DIGI_GETCH (('d'<<8) | 245) /* get board info */ +#define DIGI_GETCH (('d'<<8) | 245) /* get board info */ /* Board type definitions */ @@ -1015,12 +955,13 @@ struct digi_cmd { #define BD_TRIBOOT 0x8 #define BD_BADKME 0x80 -#define DIGI_LOOPBACK (('d'<<8) | 252) /* Enable/disable UART internal loopback */ -#define DIGI_SPOLL (('d'<<8) | 254) /* change poller rate */ +#define DIGI_LOOPBACK (('d'<<8) | 252) /* Enable/disable UART */ + /* internal loopback */ +#define DIGI_SPOLL (('d'<<8) | 254) /* change poller rate */ -#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */ -#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */ -#define DIGI_RESET_PORT (('e'<<8) | 93) /* Reset port */ +#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */ +#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */ +#define DIGI_RESET_PORT (('e'<<8) | 93) /* Reset port */ /************************************************************************ * Channel information structure. @@ -1041,14 +982,14 @@ struct channel_t { wait_queue_head_t ch_flags_wait; u32 pscan_state; - uchar pscan_savechar; + u8 pscan_savechar; u32 ch_portnum; /* Port number, 0 offset. */ u32 ch_open_count; /* open count */ u32 ch_flags; /* Channel flags */ - - u32 ch_close_delay; /* How long we should drop RTS/DTR for */ + u32 ch_close_delay; /* How long we should drop */ + /* RTS/DTR for */ u32 ch_cpstime; /* Time for CPS calculations */ @@ -1057,7 +998,7 @@ struct channel_t { tcflag_t ch_c_oflag; /* channel oflags */ tcflag_t ch_c_lflag; /* channel lflags */ - u16 ch_fepiflag; /* FEP tty iflags */ + u16 ch_fepiflag; /* FEP tty iflags */ u16 ch_fepcflag; /* FEP tty cflags */ u16 ch_fepoflag; /* FEP tty oflags */ u16 ch_wopen; /* Waiting for open process cnt */ @@ -1071,33 +1012,33 @@ struct channel_t { u16 ch_cook; /* Output character mask */ - uchar ch_card; /* Card channel is on */ - uchar ch_stopc; /* Stop character */ - uchar ch_startc; /* Start character */ - - uchar ch_mostat; /* FEP output modem status */ - uchar ch_mistat; /* FEP input modem status */ - uchar ch_mforce; /* Modem values to be forced */ - uchar ch_mval; /* Force values */ - uchar ch_fepstopc; /* FEP stop character */ - uchar ch_fepstartc; /* FEP start character */ - - uchar ch_astopc; /* Auxiliary Stop character */ - uchar ch_astartc; /* Auxiliary Start character */ - uchar ch_fepastopc; /* Auxiliary FEP stop char */ - uchar ch_fepastartc; /* Auxiliary FEP start char */ - - uchar ch_hflow; /* FEP hardware handshake */ - uchar ch_dsr; /* stores real dsr value */ - uchar ch_cd; /* stores real cd value */ - uchar ch_tx_win; /* channel tx buffer window */ - uchar ch_rx_win; /* channel rx buffer window */ + u8 ch_card; /* Card channel is on */ + u8 ch_stopc; /* Stop character */ + u8 ch_startc; /* Start character */ + + u8 ch_mostat; /* FEP output modem status */ + u8 ch_mistat; /* FEP input modem status */ + u8 ch_mforce; /* Modem values to be forced */ + u8 ch_mval; /* Force values */ + u8 ch_fepstopc; /* FEP stop character */ + u8 ch_fepstartc; /* FEP start character */ + + u8 ch_astopc; /* Auxiliary Stop character */ + u8 ch_astartc; /* Auxiliary Start character */ + u8 ch_fepastopc; /* Auxiliary FEP stop char */ + u8 ch_fepastartc; /* Auxiliary FEP start char */ + + u8 ch_hflow; /* FEP hardware handshake */ + u8 ch_dsr; /* stores real dsr value */ + u8 ch_cd; /* stores real cd value */ + u8 ch_tx_win; /* channel tx buffer window */ + u8 ch_rx_win; /* channel rx buffer window */ uint ch_custom_speed; /* Custom baud, if set */ - uint ch_baud_info; /* Current baud info for /proc output */ - ulong ch_rxcount; /* total of data received so far */ - ulong ch_txcount; /* total of data transmitted so far */ - ulong ch_err_parity; /* Count of parity errors on channel */ - ulong ch_err_frame; /* Count of framing errors on channel */ + uint ch_baud_info; /* Current baud info for /proc output */ + ulong ch_rxcount; /* total of data received so far */ + ulong ch_txcount; /* total of data transmitted so far */ + ulong ch_err_parity; /* Count of parity errors on channel */ + ulong ch_err_frame; /* Count of framing errors on channel */ ulong ch_err_break; /* Count of breaks on channel */ ulong ch_err_overrun; /* Count of overruns on channel */ @@ -1112,34 +1053,34 @@ struct channel_t { * Command structure definition. ************************************************************************/ struct cm_t { - volatile unsigned short cm_head; /* Command buffer head offset */ - volatile unsigned short cm_tail; /* Command buffer tail offset */ - volatile unsigned short cm_start; /* start offset of buffer */ - volatile unsigned short cm_max; /* last offset of buffer */ + unsigned short cm_head; /* Command buffer head offset */ + unsigned short cm_tail; /* Command buffer tail offset */ + unsigned short cm_start; /* start offset of buffer */ + unsigned short cm_max; /* last offset of buffer */ }; /************************************************************************ * Event structure definition. ************************************************************************/ struct ev_t { - volatile unsigned short ev_head; /* Command buffer head offset */ - volatile unsigned short ev_tail; /* Command buffer tail offset */ - volatile unsigned short ev_start; /* start offset of buffer */ - volatile unsigned short ev_max; /* last offset of buffer */ + unsigned short ev_head; /* Command buffer head offset */ + unsigned short ev_tail; /* Command buffer tail offset */ + unsigned short ev_start; /* start offset of buffer */ + unsigned short ev_max; /* last offset of buffer */ }; /************************************************************************ * Download buffer structure. ************************************************************************/ struct downld_t { - uchar dl_type; /* Header */ - uchar dl_seq; /* Download sequence */ + u8 dl_type; /* Header */ + u8 dl_seq; /* Download sequence */ ushort dl_srev; /* Software revision number */ ushort dl_lrev; /* Low revision number */ ushort dl_hrev; /* High revision number */ ushort dl_seg; /* Start segment address */ ushort dl_size; /* Number of bytes to download */ - uchar dl_data[1024]; /* Download data */ + u8 dl_data[1024]; /* Download data */ }; /************************************************************************ @@ -1152,70 +1093,74 @@ struct downld_t { * U = unknown (may be changed w/o notice) * ************************************************************************/ struct bs_t { - volatile unsigned short tp_jmp; /* Transmit poll jump */ - volatile unsigned short tc_jmp; /* Cooked procedure jump */ - volatile unsigned short ri_jmp; /* Not currently used */ - volatile unsigned short rp_jmp; /* Receive poll jump */ - - volatile unsigned short tx_seg; /* W Tx segment */ - volatile unsigned short tx_head; /* W Tx buffer head offset */ - volatile unsigned short tx_tail; /* R Tx buffer tail offset */ - volatile unsigned short tx_max; /* W Tx buffer size - 1 */ - - volatile unsigned short rx_seg; /* W Rx segment */ - volatile unsigned short rx_head; /* W Rx buffer head offset */ - volatile unsigned short rx_tail; /* R Rx buffer tail offset */ - volatile unsigned short rx_max; /* W Rx buffer size - 1 */ - - volatile unsigned short tx_lw; /* W Tx buffer low water mark */ - volatile unsigned short rx_lw; /* W Rx buffer low water mark */ - volatile unsigned short rx_hw; /* W Rx buffer high water mark */ - volatile unsigned short incr; /* W Increment to next channel */ - - volatile unsigned short fepdev; /* U SCC device base address */ - volatile unsigned short edelay; /* W Exception delay */ - volatile unsigned short blen; /* W Break length */ - volatile unsigned short btime; /* U Break complete time */ - - volatile unsigned short iflag; /* C UNIX input flags */ - volatile unsigned short oflag; /* C UNIX output flags */ - volatile unsigned short cflag; /* C UNIX control flags */ - volatile unsigned short wfill[13]; /* U Reserved for expansion */ - - volatile unsigned char num; /* U Channel number */ - volatile unsigned char ract; /* U Receiver active counter */ - volatile unsigned char bstat; /* U Break status bits */ - volatile unsigned char tbusy; /* W Transmit busy */ - volatile unsigned char iempty; /* W Transmit empty event enable */ - volatile unsigned char ilow; /* W Transmit low-water event enable */ - volatile unsigned char idata; /* W Receive data interrupt enable */ - volatile unsigned char eflag; /* U Host event flags */ - - volatile unsigned char tflag; /* U Transmit flags */ - volatile unsigned char rflag; /* U Receive flags */ - volatile unsigned char xmask; /* U Transmit ready flags */ - volatile unsigned char xval; /* U Transmit ready value */ - volatile unsigned char m_stat; /* RC Modem status bits */ - volatile unsigned char m_change; /* U Modem bits which changed */ - volatile unsigned char m_int; /* W Modem interrupt enable bits */ - volatile unsigned char m_last; /* U Last modem status */ - - volatile unsigned char mtran; /* C Unreported modem trans */ - volatile unsigned char orun; /* C Buffer overrun occurred */ - volatile unsigned char astartc; /* W Auxiliary Xon char */ - volatile unsigned char astopc; /* W Auxiliary Xoff char */ - volatile unsigned char startc; /* W Xon character */ - volatile unsigned char stopc; /* W Xoff character */ - volatile unsigned char vnextc; /* W Vnext character */ - volatile unsigned char hflow; /* C Software flow control */ - - volatile unsigned char fillc; /* U Delay Fill character */ - volatile unsigned char ochar; /* U Saved output character */ - volatile unsigned char omask; /* U Output character mask */ - - volatile unsigned char bfill[13]; /* U Reserved for expansion */ - - volatile unsigned char scc[16]; /* U SCC registers */ + unsigned short tp_jmp; /* Transmit poll jump */ + unsigned short tc_jmp; /* Cooked procedure jump */ + unsigned short ri_jmp; /* Not currently used */ + unsigned short rp_jmp; /* Receive poll jump */ + + unsigned short tx_seg; /* W Tx segment */ + unsigned short tx_head; /* W Tx buffer head offset */ + unsigned short tx_tail; /* R Tx buffer tail offset */ + unsigned short tx_max; /* W Tx buffer size - 1 */ + + unsigned short rx_seg; /* W Rx segment */ + unsigned short rx_head; /* W Rx buffer head offset */ + unsigned short rx_tail; /* R Rx buffer tail offset */ + unsigned short rx_max; /* W Rx buffer size - 1 */ + + unsigned short tx_lw; /* W Tx buffer low water mark */ + unsigned short rx_lw; /* W Rx buffer low water mark */ + unsigned short rx_hw; /* W Rx buffer high water mark*/ + unsigned short incr; /* W Increment to next channel*/ + + unsigned short fepdev; /* U SCC device base address */ + unsigned short edelay; /* W Exception delay */ + unsigned short blen; /* W Break length */ + unsigned short btime; /* U Break complete time */ + + unsigned short iflag; /* C UNIX input flags */ + unsigned short oflag; /* C UNIX output flags */ + unsigned short cflag; /* C UNIX control flags */ + unsigned short wfill[13]; /* U Reserved for expansion */ + + unsigned char num; /* U Channel number */ + unsigned char ract; /* U Receiver active counter */ + unsigned char bstat; /* U Break status bits */ + unsigned char tbusy; /* W Transmit busy */ + unsigned char iempty; /* W Transmit empty event */ + /* enable */ + unsigned char ilow; /* W Transmit low-water event */ + /* enable */ + unsigned char idata; /* W Receive data interrupt */ + /* enable */ + unsigned char eflag; /* U Host event flags */ + + unsigned char tflag; /* U Transmit flags */ + unsigned char rflag; /* U Receive flags */ + unsigned char xmask; /* U Transmit ready flags */ + unsigned char xval; /* U Transmit ready value */ + unsigned char m_stat; /* RC Modem status bits */ + unsigned char m_change; /* U Modem bits which changed */ + unsigned char m_int; /* W Modem interrupt enable */ + /* bits */ + unsigned char m_last; /* U Last modem status */ + + unsigned char mtran; /* C Unreported modem trans */ + unsigned char orun; /* C Buffer overrun occurred */ + unsigned char astartc; /* W Auxiliary Xon char */ + unsigned char astopc; /* W Auxiliary Xoff char */ + unsigned char startc; /* W Xon character */ + unsigned char stopc; /* W Xoff character */ + unsigned char vnextc; /* W Vnext character */ + unsigned char hflow; /* C Software flow control */ + + unsigned char fillc; /* U Delay Fill character */ + unsigned char ochar; /* U Saved output character */ + unsigned char omask; /* U Output character mask */ + + unsigned char bfill[13]; /* U Reserved for expansion */ + + unsigned char scc[16]; /* U SCC registers */ }; struct cnode { @@ -1225,7 +1170,7 @@ struct cnode { union { struct { - char type; /* Board Type */ + char type; /* Board Type */ long port; /* I/O Address */ char *portstr; /* I/O Address in string */ long addr; /* Memory Address */ @@ -1294,29 +1239,17 @@ struct cnode { } module; char *ttyname; - char *cuname; - char *printname; - long majornumber; - long altpin; - long ttysize; - long chsize; - long bssize; - long unsize; - long f2size; - long vpixsize; - long useintr; } u; }; - #endif diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c index 0571988c58fc8a..334ba04ae44b68 100644 --- a/drivers/staging/frontier/tranzport.c +++ b/drivers/staging/frontier/tranzport.c @@ -271,8 +271,8 @@ static void usb_tranzport_interrupt_in_callback(struct urb *urb) dev->interrupt_in_buffer[6], dev->interrupt_in_buffer[7]); #if SUPPRESS_EXTRA_OFFLINE_EVENTS - if (dev->offline == 2 && dev->interrupt_in_buffer[1] == 0xff) - goto resubmit; + if (dev->offline == 2 && dev->interrupt_in_buffer[1] == 0xff) + goto resubmit; if (dev->offline == 1 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 2; goto resubmit; @@ -285,8 +285,8 @@ static void usb_tranzport_interrupt_in_callback(struct urb *urb) dev->offline = 1; #endif /* SUPPRESS_EXTRA_OFFLINE_EVENTS */ - dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", - __func__, dev->ring_head, dev->ring_tail); + dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", + __func__, dev->ring_head, dev->ring_tail); next_ring_head = (dev->ring_head + 1) % ring_buffer_size; diff --git a/drivers/staging/fwserial/dma_fifo.c b/drivers/staging/fwserial/dma_fifo.c index 5e846344550484..027906249598a4 100644 --- a/drivers/staging/fwserial/dma_fifo.c +++ b/drivers/staging/fwserial/dma_fifo.c @@ -12,10 +12,6 @@ * 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 @@ -169,9 +165,9 @@ int dma_fifo_in(struct dma_fifo *fifo, const void *src, int n) memcpy(fifo->data, src + l, n - l); if (FAIL(fifo, addr_check(fifo->done, fifo->in, fifo->in + n) || - fifo->avail < n, - "fifo corrupt: in:%u out:%u done:%u n:%d avail:%d", - fifo->in, fifo->out, fifo->done, n, fifo->avail)) + fifo->avail < n, + "fifo corrupt: in:%u out:%u done:%u n:%d avail:%d", + fifo->in, fifo->out, fifo->done, n, fifo->avail)) return -ENXIO; fifo->in += n; @@ -236,12 +232,12 @@ int dma_fifo_out_pend(struct dma_fifo *fifo, struct dma_pending *pended) ++fifo->open; if (FAIL(fifo, fifo->open > fifo->open_limit, - "past open limit:%d (limit:%d)", - fifo->open, fifo->open_limit)) + "past open limit:%d (limit:%d)", + fifo->open, fifo->open_limit)) return -ENXIO; if (FAIL(fifo, fifo->out & (fifo->align - 1), - "fifo out unaligned:%u (align:%u)", - fifo->out, fifo->align)) + "fifo out unaligned:%u (align:%u)", + fifo->out, fifo->align)) return -ENXIO; return len - n; @@ -264,8 +260,8 @@ int dma_fifo_out_complete(struct dma_fifo *fifo, struct dma_pending *complete) return -EINVAL; if (FAIL(fifo, list_empty(&fifo->pending) != (fifo->open == 0), - "pending list disagrees with open count:%d", - fifo->open)) + "pending list disagrees with open count:%d", + fifo->open)) return -ENXIO; tmp = complete->data; @@ -282,10 +278,10 @@ int dma_fifo_out_complete(struct dma_fifo *fifo, struct dma_pending *complete) } if (FAIL(fifo, pending->out != fifo->done || - addr_check(fifo->in, fifo->done, pending->next), - "in:%u out:%u done:%u saved:%u next:%u", - fifo->in, fifo->out, fifo->done, pending->out, - pending->next)) + addr_check(fifo->in, fifo->done, pending->next), + "in:%u out:%u done:%u saved:%u next:%u", + fifo->in, fifo->out, fifo->done, pending->out, + pending->next)) return -ENXIO; list_del_init(&pending->link); @@ -300,7 +296,7 @@ int dma_fifo_out_complete(struct dma_fifo *fifo, struct dma_pending *complete) if (FAIL(fifo, fifo->open < 0, "open dma:%d < 0", fifo->open)) return -ENXIO; if (FAIL(fifo, fifo->avail > fifo->size, "fifo avail:%d > size:%d", - fifo->avail, fifo->size)) + fifo->avail, fifo->size)) return -ENXIO; return 0; diff --git a/drivers/staging/fwserial/dma_fifo.h b/drivers/staging/fwserial/dma_fifo.h index a113fe1e6f1983..410988224f8902 100644 --- a/drivers/staging/fwserial/dma_fifo.h +++ b/drivers/staging/fwserial/dma_fifo.h @@ -12,10 +12,6 @@ * 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 _DMA_FIFO_H_ @@ -85,15 +81,15 @@ static inline bool dp_is_completed(struct dma_pending *dp) return (unsigned long)dp->data & 1UL; } -extern void dma_fifo_init(struct dma_fifo *fifo); -extern int dma_fifo_alloc(struct dma_fifo *fifo, int size, unsigned align, - int tx_limit, int open_limit, gfp_t gfp_mask); -extern void dma_fifo_free(struct dma_fifo *fifo); -extern void dma_fifo_reset(struct dma_fifo *fifo); -extern int dma_fifo_in(struct dma_fifo *fifo, const void *src, int n); -extern int dma_fifo_out_pend(struct dma_fifo *fifo, struct dma_pending *pended); -extern int dma_fifo_out_complete(struct dma_fifo *fifo, - struct dma_pending *complete); +void dma_fifo_init(struct dma_fifo *fifo); +int dma_fifo_alloc(struct dma_fifo *fifo, int size, unsigned align, + int tx_limit, int open_limit, gfp_t gfp_mask); +void dma_fifo_free(struct dma_fifo *fifo); +void dma_fifo_reset(struct dma_fifo *fifo); +int dma_fifo_in(struct dma_fifo *fifo, const void *src, int n); +int dma_fifo_out_pend(struct dma_fifo *fifo, struct dma_pending *pended); +int dma_fifo_out_complete(struct dma_fifo *fifo, + struct dma_pending *complete); /* returns the # of used bytes in the fifo */ static inline int dma_fifo_level(struct dma_fifo *fifo) diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index b22142ee52625c..384758b11e3c15 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c @@ -12,10 +12,6 @@ * 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. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -530,7 +526,7 @@ static void fwtty_emit_breaks(struct work_struct *work) while (n) { t = min(n, 16); c = tty_insert_flip_string_fixed_flag(&port->port, buf, - TTY_BREAK, t); + TTY_BREAK, t); n -= c; brk += c; if (c < t) @@ -638,9 +634,9 @@ static void fwtty_port_handler(struct fw_card *card, switch (tcode) { case TCODE_WRITE_QUADLET_REQUEST: - if (addr != port->rx_handler.offset || len != 4) + if (addr != port->rx_handler.offset || len != 4) { rcode = RCODE_ADDRESS_ERROR; - else { + } else { fwtty_update_port_status(port, *(unsigned *)data); rcode = RCODE_COMPLETE; } @@ -741,7 +737,7 @@ static int fwtty_tx(struct fwtty_port *port, bool drain) /* try to write as many dma transactions out as possible */ n = -EAGAIN; while (!tty->stopped && !tty->hw_stopped && - !test_bit(STOP_TX, &port->flags)) { + !test_bit(STOP_TX, &port->flags)) { txn = kmem_cache_alloc(fwtty_txn_cache, GFP_ATOMIC); if (!txn) { n = -ENOMEM; @@ -756,11 +752,11 @@ static int fwtty_tx(struct fwtty_port *port, bool drain) if (n < 0) { kmem_cache_free(fwtty_txn_cache, txn); - if (n == -EAGAIN) + if (n == -EAGAIN) { ++port->stats.tx_stall; - else if (n == -ENODATA) + } else if (n == -ENODATA) { fwtty_profile_data(port->stats.txns, 0); - else { + } else { ++port->stats.fifo_errs; fwtty_err_ratelimited(port, "fifo err: %d\n", n); @@ -884,7 +880,7 @@ static void fwserial_destroy(struct kref *kref) for (j = 0; j < num_ports; ++i, ++j) { port_table_corrupt |= port_table[i] != ports[j]; WARN_ONCE(port_table_corrupt, "port_table[%d]: %p != ports[%d]: %p", - i, port_table[i], j, ports[j]); + i, port_table[i], j, ports[j]); port_table[i] = NULL; } @@ -1257,15 +1253,16 @@ static int set_serial_info(struct fwtty_port *port, return -EFAULT; if (tmp.irq != 0 || tmp.port != 0 || tmp.custom_divisor != 0 || - tmp.baud_base != 400000000) + tmp.baud_base != 400000000) return -EPERM; if (!capable(CAP_SYS_ADMIN)) { if (((tmp.flags & ~ASYNC_USR_MASK) != (port->port.flags & ~ASYNC_USR_MASK))) return -EPERM; - } else + } else { port->port.close_delay = tmp.close_delay * HZ / 100; + } return 0; } @@ -1308,9 +1305,9 @@ static void fwtty_set_termios(struct tty_struct *tty, struct ktermios *old) spin_lock_bh(&port->lock); baud = set_termios(port, tty); - if ((baud == 0) && (old->c_cflag & CBAUD)) + if ((baud == 0) && (old->c_cflag & CBAUD)) { port->mctrl &= ~(TIOCM_DTR | TIOCM_RTS); - else if ((baud != 0) && !(old->c_cflag & CBAUD)) { + } else if ((baud != 0) && !(old->c_cflag & CBAUD)) { if (C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) port->mctrl |= TIOCM_DTR | TIOCM_RTS; else @@ -1733,8 +1730,9 @@ static inline int fwserial_send_mgmt_sync(struct fwtty_peer *peer, rcode == RCODE_GENERATION) { fwtty_dbg(&peer->unit, "mgmt write error: %d\n", rcode); continue; - } else + } else { break; + } } while (--tries > 0); return rcode; } @@ -1809,7 +1807,7 @@ static void fwserial_release_port(struct fwtty_port *port, bool reset) port->max_payload = link_speed_to_max_payload(SCODE_100); dma_fifo_change_tx_limit(&port->tx_fifo, port->max_payload); - rcu_assign_pointer(port->peer, NULL); + RCU_INIT_POINTER(port->peer, NULL); spin_unlock_bh(&port->lock); if (port->port.console && port->fwcon_ops->notify != NULL) @@ -1818,7 +1816,7 @@ static void fwserial_release_port(struct fwtty_port *port, bool reset) static void fwserial_plug_timeout(unsigned long data) { - struct fwtty_peer *peer = (struct fwtty_peer *) data; + struct fwtty_peer *peer = (struct fwtty_peer *)data; struct fwtty_port *port; spin_lock_bh(&peer->lock); @@ -2242,7 +2240,7 @@ static int fwserial_create(struct fw_unit *unit) port->max_payload = link_speed_to_max_payload(SCODE_100); dma_fifo_init(&port->tx_fifo); - rcu_assign_pointer(port->peer, NULL); + RCU_INIT_POINTER(port->peer, NULL); serial->ports[i] = port; /* get unique bus addr region for port's status & recv fifo */ @@ -2744,9 +2742,9 @@ static int fwserial_parse_mgmt_write(struct fwtty_peer *peer, break; case FWSC_VIRT_CABLE_UNPLUG_RSP: - if (peer->state != FWPS_UNPLUG_PENDING) + if (peer->state != FWPS_UNPLUG_PENDING) { rcode = RCODE_CONFLICT_ERROR; - else { + } else { if (be16_to_cpu(pkt->hdr.code) & FWSC_RSP_NACK) fwtty_notice(&peer->unit, "NACK unplug?\n"); port = peer_revert_state(peer); diff --git a/drivers/staging/goldfish/README b/drivers/staging/goldfish/README index 93d65b0f0f83d6..183af005323419 100644 --- a/drivers/staging/goldfish/README +++ b/drivers/staging/goldfish/README @@ -5,7 +5,6 @@ Audio NAND ---- -- Switch from spinlock to mutex - Remove excess checking of parameters in calls - Use dma coherent memory not kmalloc/__pa for the memory (this is just a cleanliness issue not a correctness one) diff --git a/drivers/staging/goldfish/goldfish_audio.c b/drivers/staging/goldfish/goldfish_audio.c index 7ac2602242f1f4..383bee687151fc 100644 --- a/drivers/staging/goldfish/goldfish_audio.c +++ b/drivers/staging/goldfish/goldfish_audio.c @@ -78,11 +78,18 @@ enum { /* set number of bytes in buffer to write */ AUDIO_WRITE_BUFFER_1 = 0x10, AUDIO_WRITE_BUFFER_2 = 0x14, +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + AUDIO_SET_WRITE_BUFFER_1_HIGH = 0x28, + AUDIO_SET_WRITE_BUFFER_2_HIGH = 0x30, +#endif /* true if audio input is supported */ AUDIO_READ_SUPPORTED = 0x18, /* buffer to use for audio input */ AUDIO_SET_READ_BUFFER = 0x1C, +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + AUDIO_SET_READ_BUFFER_HIGH = 0x34, +#endif /* driver writes number of bytes to read */ AUDIO_START_READ = 0x20, @@ -147,6 +154,7 @@ static ssize_t goldfish_audio_write(struct file *fp, const char __user *buf, while (count > 0) { ssize_t copy = count; + if (copy > WRITE_BUFFER_SIZE) copy = WRITE_BUFFER_SIZE; wait_event_interruptible(data->wait, (data->buffer_status & @@ -266,6 +274,9 @@ static int goldfish_audio_probe(struct platform_device *pdev) struct resource *r; struct goldfish_audio *data; dma_addr_t buf_addr; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + u32 buf_addr_high, buf_addr_low; +#endif data = kzalloc(sizeof(*data), GFP_KERNEL); if (data == NULL) { @@ -321,6 +332,28 @@ static int goldfish_audio_probe(struct platform_device *pdev) goto err_misc_register_failed; } +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + buf_addr_low = (u32)(buf_addr); + buf_addr_high = (u32)((buf_addr) >> 32); + + AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_1, buf_addr_low); + AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_1_HIGH, buf_addr_high); + + buf_addr_low = (u32)(buf_addr + WRITE_BUFFER_SIZE); + buf_addr_high = (u32)((buf_addr + WRITE_BUFFER_SIZE) >> 32); + + AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_2, buf_addr_low); + AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_2_HIGH, buf_addr_high); + + buf_addr_low = (u32)(buf_addr + 2 * WRITE_BUFFER_SIZE); + buf_addr_high = (u32)((buf_addr + 2 * WRITE_BUFFER_SIZE) >> 32); + + data->read_supported = AUDIO_READ(data, AUDIO_READ_SUPPORTED); + if (data->read_supported){ + AUDIO_WRITE(data, AUDIO_SET_READ_BUFFER, buf_addr_low); + AUDIO_WRITE(data, AUDIO_SET_READ_BUFFER_HIGH, buf_addr_high); + } +#else AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_1, buf_addr); AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_2, buf_addr + WRITE_BUFFER_SIZE); @@ -329,6 +362,7 @@ static int goldfish_audio_probe(struct platform_device *pdev) if (data->read_supported) AUDIO_WRITE(data, AUDIO_SET_READ_BUFFER, buf_addr + 2 * WRITE_BUFFER_SIZE); +#endif audio_data = data; return 0; diff --git a/drivers/staging/goldfish/goldfish_nand.c b/drivers/staging/goldfish/goldfish_nand.c index eca0873098cd5f..b8e3dd28096dc4 100644 --- a/drivers/staging/goldfish/goldfish_nand.c +++ b/drivers/staging/goldfish/goldfish_nand.c @@ -24,13 +24,14 @@ #include #include #include +#include #include #include "goldfish_nand_reg.h" struct goldfish_nand { - spinlock_t lock; + struct mutex lock; unsigned char __iomem *base; struct cmd_params *cmd_params; size_t mtd_count; @@ -66,7 +67,7 @@ static u32 goldfish_nand_cmd_with_params(struct mtd_info *mtd, cps->addr_high = (u32)(addr >> 32); cps->addr_low = (u32)addr; cps->transfer_size = len; - cps->data = (u32)ptr; + cps->data = (unsigned long)ptr; writel(cmdp, base + NAND_COMMAND); *rv = cps->result; return 0; @@ -77,20 +78,22 @@ static u32 goldfish_nand_cmd(struct mtd_info *mtd, enum nand_cmd cmd, { struct goldfish_nand *nand = mtd->priv; u32 rv; - unsigned long irq_flags; unsigned char __iomem *base = nand->base; - spin_lock_irqsave(&nand->lock, irq_flags); + mutex_lock(&nand->lock); if (goldfish_nand_cmd_with_params(mtd, cmd, addr, len, ptr, &rv)) { writel(mtd - nand->mtd, base + NAND_DEV); writel((u32)(addr >> 32), base + NAND_ADDR_HIGH); writel((u32)addr, base + NAND_ADDR_LOW); writel(len, base + NAND_TRANSFER_SIZE); writel((u32)ptr, base + NAND_DATA); +#ifdef CONFIG_64BIT + writel((u32)((u64)ptr >> 32), base + NAND_DATA_HIGH); +#endif writel(cmd, base + NAND_COMMAND); rv = readl(base + NAND_RESULT); } - spin_unlock_irqrestore(&nand->lock, irq_flags); + mutex_unlock(&nand->lock); return rv; } @@ -307,12 +310,11 @@ static int goldfish_nand_init_device(struct platform_device *pdev, u32 name_len; u32 result; u32 flags; - unsigned long irq_flags; unsigned char __iomem *base = nand->base; struct mtd_info *mtd = &nand->mtd[id]; char *name; - spin_lock_irqsave(&nand->lock, irq_flags); + mutex_lock(&nand->lock); writel(id, base + NAND_DEV); flags = readl(base + NAND_DEV_FLAGS); name_len = readl(base + NAND_DEV_NAME_LEN); @@ -329,7 +331,7 @@ static int goldfish_nand_init_device(struct platform_device *pdev, "goldfish nand dev%d: size %llx, page %d, extra %d, erase %d\n", id, mtd->size, mtd->writesize, mtd->oobsize, mtd->erasesize); - spin_unlock_irqrestore(&nand->lock, irq_flags); + mutex_unlock(&nand->lock); mtd->priv = nand; @@ -405,7 +407,7 @@ static int goldfish_nand_probe(struct platform_device *pdev) if (nand == NULL) return -ENOMEM; - spin_lock_init(&nand->lock); + mutex_init(&nand->lock); nand->base = base; nand->mtd_count = num_dev; platform_set_drvdata(pdev, nand); @@ -425,6 +427,7 @@ static int goldfish_nand_remove(struct platform_device *pdev) { struct goldfish_nand *nand = platform_get_drvdata(pdev); int i; + for (i = 0; i < nand->mtd_count; i++) { if (nand->mtd[i].name) mtd_device_unregister(&nand->mtd[i]); diff --git a/drivers/staging/goldfish/goldfish_nand_reg.h b/drivers/staging/goldfish/goldfish_nand_reg.h index ddfda71ab27aa7..60ab91f74be7ee 100644 --- a/drivers/staging/goldfish/goldfish_nand_reg.h +++ b/drivers/staging/goldfish/goldfish_nand_reg.h @@ -57,6 +57,9 @@ enum nand_reg { NAND_RESULT = 0x040, NAND_COMMAND = 0x044, NAND_DATA = 0x048, +#ifdef CONFIG_64BIT + NAND_DATA_HIGH = 0x100, +#endif NAND_TRANSFER_SIZE = 0x04c, NAND_ADDR_LOW = 0x050, NAND_ADDR_HIGH = 0x054, @@ -69,7 +72,7 @@ struct cmd_params { uint32_t addr_low; uint32_t addr_high; uint32_t transfer_size; - uint32_t data; + unsigned long data; uint32_t result; }; #endif diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 363329808a4fb8..b87e382ad76898 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -37,26 +37,6 @@ config AD7606_IFACE_SPI Say yes here to include parallel interface support on the AD7606 ADC driver. -config AD799X - tristate "Analog Devices AD799x ADC driver" - depends on I2C - select IIO_TRIGGER if IIO_BUFFER - select AD799X_RING_BUFFER - help - Say yes here to build support for Analog Devices: - ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998 - i2c analog to digital converters (ADC). Provides direct access - via sysfs. - -config AD799X_RING_BUFFER - bool "Analog Devices AD799x: use ring buffer" - depends on AD799X - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to include ring buffer support in the AD799X - ADC driver. - config AD7780 tristate "Analog Devices AD7780 and similar ADCs driver" depends on SPI diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 3e9fb143d25b4d..afdcd1ff08ff1a 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -8,10 +8,6 @@ ad7606-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o ad7606-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o obj-$(CONFIG_AD7606) += ad7606.o -ad799x-y := ad799x_core.o -ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o -obj-$(CONFIG_AD799X) += ad799x.o - obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7780) += ad7780.o obj-$(CONFIG_AD7816) += ad7816.o diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 1ac11f64827c73..d215edf66af235 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -443,7 +443,7 @@ static ssize_t ad7280_show_balance_timer(struct device *dev, msecs = (ret >> 3) * 71500; - return sprintf(buf, "%d\n", msecs); + return sprintf(buf, "%u\n", msecs); } static ssize_t ad7280_store_balance_timer(struct device *dev, @@ -619,7 +619,7 @@ static ssize_t ad7280_read_channel_config(struct device *dev, return -EINVAL; } - return sprintf(buf, "%d\n", val); + return sprintf(buf, "%u\n", val); } static ssize_t ad7280_write_channel_config(struct device *dev, diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 93c7299e83539c..ec89d055cf585b 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -14,7 +14,7 @@ */ /** - * struct ad7606_platform_data - platform/board specifc information + * struct ad7606_platform_data - platform/board specific information * @default_os: default oversampling value {0, 2, 4, 8, 16, 32, 64} * @default_range: default range +/-{5000, 10000} mVolt * @gpio_convst: number of gpio connected to the CONVST pin @@ -41,7 +41,7 @@ struct ad7606_platform_data { }; /** - * struct ad7606_chip_info - chip specifc information + * struct ad7606_chip_info - chip specific information * @name: identification string for chip * @int_vref_mv: the internal reference voltage * @channels: channel specification diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index 2369cf28412ed6..158d770f961ac2 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -40,7 +40,7 @@ /* - * struct ad7816_chip_info - chip specifc information + * struct ad7816_chip_info - chip specific information */ struct ad7816_chip_info { diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h deleted file mode 100644 index fc8c85298feb42..00000000000000 --- a/drivers/staging/iio/adc/ad799x.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc. - * Copyright (C) 2008-2010 Jonathan Cameron - * - * 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. - * - * ad799x.h - */ - -#ifndef _AD799X_H_ -#define _AD799X_H_ - -#define AD799X_CHANNEL_SHIFT 4 -#define AD799X_STORAGEBITS 16 -/* - * AD7991, AD7995 and AD7999 defines - */ - -#define AD7991_REF_SEL 0x08 -#define AD7991_FLTR 0x04 -#define AD7991_BIT_TRIAL_DELAY 0x02 -#define AD7991_SAMPLE_DELAY 0x01 - -/* - * AD7992, AD7993, AD7994, AD7997 and AD7998 defines - */ - -#define AD7998_FLTR 0x08 -#define AD7998_ALERT_EN 0x04 -#define AD7998_BUSY_ALERT 0x02 -#define AD7998_BUSY_ALERT_POL 0x01 - -#define AD7998_CONV_RES_REG 0x0 -#define AD7998_ALERT_STAT_REG 0x1 -#define AD7998_CONF_REG 0x2 -#define AD7998_CYCLE_TMR_REG 0x3 - -#define AD7998_DATALOW_REG(x) ((x) * 3 + 0x4) -#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5) -#define AD7998_HYST_REG(x) ((x) * 3 + 0x6) - -#define AD7998_CYC_MASK 0x7 -#define AD7998_CYC_DIS 0x0 -#define AD7998_CYC_TCONF_32 0x1 -#define AD7998_CYC_TCONF_64 0x2 -#define AD7998_CYC_TCONF_128 0x3 -#define AD7998_CYC_TCONF_256 0x4 -#define AD7998_CYC_TCONF_512 0x5 -#define AD7998_CYC_TCONF_1024 0x6 -#define AD7998_CYC_TCONF_2048 0x7 - -#define AD7998_ALERT_STAT_CLEAR 0xFF - -/* - * AD7997 and AD7997 defines - */ - -#define AD7997_8_READ_SINGLE 0x80 -#define AD7997_8_READ_SEQUENCE 0x70 -/* TODO: move this into a common header */ -#define RES_MASK(bits) ((1 << (bits)) - 1) - -enum { - ad7991, - ad7995, - ad7999, - ad7992, - ad7993, - ad7994, - ad7997, - ad7998 -}; - -struct ad799x_state; - -/** - * struct ad799x_chip_info - chip specifc information - * @channel: channel specification - * @num_channels: number of channels - * @monitor_mode: whether the chip supports monitor interrupts - * @default_config: device default configuration - * @event_attrs: pointer to the monitor event attribute group - */ - -struct ad799x_chip_info { - struct iio_chan_spec channel[9]; - int num_channels; - u16 default_config; - const struct iio_info *info; -}; - -struct ad799x_state { - struct i2c_client *client; - const struct ad799x_chip_info *chip_info; - struct regulator *reg; - struct regulator *vref; - unsigned id; - u16 config; - - u8 *rx_buf; - unsigned int transfer_size; -}; - -#ifdef CONFIG_AD799X_RING_BUFFER -int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev); -void ad799x_ring_cleanup(struct iio_dev *indio_dev); -#else /* CONFIG_AD799X_RING_BUFFER */ - -static inline int -ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) -{ - return 0; -} - -static inline void ad799x_ring_cleanup(struct iio_dev *indio_dev) -{ -} -#endif /* CONFIG_AD799X_RING_BUFFER */ -#endif /* _AD799X_H_ */ diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c deleted file mode 100644 index 0ff6c03a483ec0..00000000000000 --- a/drivers/staging/iio/adc/ad799x_ring.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2010-2012 Michael Hennerich, Analog Devices Inc. - * Copyright (C) 2008-2010 Jonathan Cameron - * - * 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. - * - * ad799x_ring.c - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "ad799x.h" - -/** - * ad799x_trigger_handler() bh of trigger launched polling to ring buffer - * - * Currently there is no option in this driver to disable the saving of - * timestamps within the ring. - **/ - -static irqreturn_t ad799x_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct ad799x_state *st = iio_priv(indio_dev); - int b_sent; - u8 cmd; - - switch (st->id) { - case ad7991: - case ad7995: - case ad7999: - cmd = st->config | - (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT); - break; - case ad7992: - case ad7993: - case ad7994: - cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) | - AD7998_CONV_RES_REG; - break; - case ad7997: - case ad7998: - cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG; - break; - default: - cmd = 0; - } - - b_sent = i2c_smbus_read_i2c_block_data(st->client, - cmd, st->transfer_size, st->rx_buf); - if (b_sent < 0) - goto out; - - iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns()); -out: - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} - -int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) -{ - return iio_triggered_buffer_setup(indio_dev, NULL, - &ad799x_trigger_handler, NULL); -} - -void ad799x_ring_cleanup(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); -} diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c index 970d9edc73b6cc..c5492ba50751d3 100644 --- a/drivers/staging/iio/adc/spear_adc.c +++ b/drivers/staging/iio/adc/spear_adc.c @@ -22,39 +22,36 @@ #include #include -/* - * SPEAR registers definitions - */ - -#define SCAN_RATE_LO(x) ((x) & 0xFFFF) -#define SCAN_RATE_HI(x) (((x) >> 0x10) & 0xFFFF) -#define CLK_LOW(x) (((x) & 0xf) << 0) -#define CLK_HIGH(x) (((x) & 0xf) << 4) +/* SPEAR registers definitions */ +#define SPEAR600_ADC_SCAN_RATE_LO(x) ((x) & 0xFFFF) +#define SPEAR600_ADC_SCAN_RATE_HI(x) (((x) >> 0x10) & 0xFFFF) +#define SPEAR_ADC_CLK_LOW(x) (((x) & 0xf) << 0) +#define SPEAR_ADC_CLK_HIGH(x) (((x) & 0xf) << 4) /* Bit definitions for SPEAR_ADC_STATUS */ -#define START_CONVERSION (1 << 0) -#define CHANNEL_NUM(x) ((x) << 1) -#define ADC_ENABLE (1 << 4) -#define AVG_SAMPLE(x) ((x) << 5) -#define VREF_INTERNAL (1 << 9) +#define SPEAR_ADC_STATUS_START_CONVERSION (1 << 0) +#define SPEAR_ADC_STATUS_CHANNEL_NUM(x) ((x) << 1) +#define SPEAR_ADC_STATUS_ADC_ENABLE (1 << 4) +#define SPEAR_ADC_STATUS_AVG_SAMPLE(x) ((x) << 5) +#define SPEAR_ADC_STATUS_VREF_INTERNAL (1 << 9) -#define DATA_MASK 0x03ff -#define DATA_BITS 10 +#define SPEAR_ADC_DATA_MASK 0x03ff +#define SPEAR_ADC_DATA_BITS 10 -#define MOD_NAME "spear-adc" +#define SPEAR_ADC_MOD_NAME "spear-adc" -#define ADC_CHANNEL_NUM 8 +#define SPEAR_ADC_CHANNEL_NUM 8 -#define CLK_MIN 2500000 -#define CLK_MAX 20000000 +#define SPEAR_ADC_CLK_MIN 2500000 +#define SPEAR_ADC_CLK_MAX 20000000 struct adc_regs_spear3xx { u32 status; u32 average; u32 scan_rate; u32 clk; /* Not avail for 1340 & 1310 */ - u32 ch_ctrl[ADC_CHANNEL_NUM]; - u32 ch_data[ADC_CHANNEL_NUM]; + u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM]; + u32 ch_data[SPEAR_ADC_CHANNEL_NUM]; }; struct chan_data { @@ -66,14 +63,14 @@ struct adc_regs_spear6xx { u32 status; u32 pad[2]; u32 clk; - u32 ch_ctrl[ADC_CHANNEL_NUM]; - struct chan_data ch_data[ADC_CHANNEL_NUM]; + u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM]; + struct chan_data ch_data[SPEAR_ADC_CHANNEL_NUM]; u32 scan_rate_lo; u32 scan_rate_hi; struct chan_data average; }; -struct spear_adc_info { +struct spear_adc_state { struct device_node *np; struct adc_regs_spear3xx __iomem *adc_base_spear3xx; struct adc_regs_spear6xx __iomem *adc_base_spear6xx; @@ -91,100 +88,129 @@ struct spear_adc_info { * static inline functions, because of different register offsets * on different SoC variants (SPEAr300 vs SPEAr600 etc). */ -static void spear_adc_set_status(struct spear_adc_info *info, u32 val) +static void spear_adc_set_status(struct spear_adc_state *st, u32 val) { - __raw_writel(val, &info->adc_base_spear6xx->status); + __raw_writel(val, &st->adc_base_spear6xx->status); } -static void spear_adc_set_clk(struct spear_adc_info *info, u32 val) +static void spear_adc_set_clk(struct spear_adc_state *st, u32 val) { u32 clk_high, clk_low, count; - u32 apb_clk = clk_get_rate(info->clk); + u32 apb_clk = clk_get_rate(st->clk); count = (apb_clk + val - 1) / val; clk_low = count / 2; clk_high = count - clk_low; - info->current_clk = apb_clk / count; + st->current_clk = apb_clk / count; - __raw_writel(CLK_LOW(clk_low) | CLK_HIGH(clk_high), - &info->adc_base_spear6xx->clk); + __raw_writel(SPEAR_ADC_CLK_LOW(clk_low) | SPEAR_ADC_CLK_HIGH(clk_high), + &st->adc_base_spear6xx->clk); } -static void spear_adc_set_ctrl(struct spear_adc_info *info, int n, +static void spear_adc_set_ctrl(struct spear_adc_state *st, int n, u32 val) { - __raw_writel(val, &info->adc_base_spear6xx->ch_ctrl[n]); + __raw_writel(val, &st->adc_base_spear6xx->ch_ctrl[n]); } -static u32 spear_adc_get_average(struct spear_adc_info *info) +static u32 spear_adc_get_average(struct spear_adc_state *st) { - if (of_device_is_compatible(info->np, "st,spear600-adc")) { - return __raw_readl(&info->adc_base_spear6xx->average.msb) & - DATA_MASK; + if (of_device_is_compatible(st->np, "st,spear600-adc")) { + return __raw_readl(&st->adc_base_spear6xx->average.msb) & + SPEAR_ADC_DATA_MASK; } else { - return __raw_readl(&info->adc_base_spear3xx->average) & - DATA_MASK; + return __raw_readl(&st->adc_base_spear3xx->average) & + SPEAR_ADC_DATA_MASK; } } -static void spear_adc_set_scanrate(struct spear_adc_info *info, u32 rate) +static void spear_adc_set_scanrate(struct spear_adc_state *st, u32 rate) { - if (of_device_is_compatible(info->np, "st,spear600-adc")) { - __raw_writel(SCAN_RATE_LO(rate), - &info->adc_base_spear6xx->scan_rate_lo); - __raw_writel(SCAN_RATE_HI(rate), - &info->adc_base_spear6xx->scan_rate_hi); + if (of_device_is_compatible(st->np, "st,spear600-adc")) { + __raw_writel(SPEAR600_ADC_SCAN_RATE_LO(rate), + &st->adc_base_spear6xx->scan_rate_lo); + __raw_writel(SPEAR600_ADC_SCAN_RATE_HI(rate), + &st->adc_base_spear6xx->scan_rate_hi); } else { - __raw_writel(rate, &info->adc_base_spear3xx->scan_rate); + __raw_writel(rate, &st->adc_base_spear3xx->scan_rate); } } -static int spear_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) +static int spear_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) { - struct spear_adc_info *info = iio_priv(indio_dev); + struct spear_adc_state *st = iio_priv(indio_dev); u32 status; switch (mask) { case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); - status = CHANNEL_NUM(chan->channel) | - AVG_SAMPLE(info->avg_samples) | - START_CONVERSION | ADC_ENABLE; - if (info->vref_external == 0) - status |= VREF_INTERNAL; + status = SPEAR_ADC_STATUS_CHANNEL_NUM(chan->channel) | + SPEAR_ADC_STATUS_AVG_SAMPLE(st->avg_samples) | + SPEAR_ADC_STATUS_START_CONVERSION | + SPEAR_ADC_STATUS_ADC_ENABLE; + if (st->vref_external == 0) + status |= SPEAR_ADC_STATUS_VREF_INTERNAL; - spear_adc_set_status(info, status); - wait_for_completion(&info->completion); /* set by ISR */ - *val = info->value; + spear_adc_set_status(st, status); + wait_for_completion(&st->completion); /* set by ISR */ + *val = st->value; mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = info->vref_external; - *val2 = DATA_BITS; + *val = st->vref_external; + *val2 = SPEAR_ADC_DATA_BITS; return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->current_clk; + return IIO_VAL_INT; } return -EINVAL; } +static int spear_adc_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct spear_adc_state *st = iio_priv(indio_dev); + int ret = 0; + + if (mask != IIO_CHAN_INFO_SAMP_FREQ) + return -EINVAL; + + mutex_lock(&indio_dev->mlock); + + if ((val < SPEAR_ADC_CLK_MIN) || + (val > SPEAR_ADC_CLK_MAX) || + (val2 != 0)) { + ret = -EINVAL; + goto out; + } + + spear_adc_set_clk(st, val); + +out: + mutex_unlock(&indio_dev->mlock); + return ret; +} + #define SPEAR_ADC_CHAN(idx) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ .channel = idx, \ - .scan_type = { \ - .sign = 'u', \ - .storagebits = 16, \ - }, \ } static const struct iio_chan_spec spear_adc_iio_channels[] = { @@ -200,92 +226,34 @@ static const struct iio_chan_spec spear_adc_iio_channels[] = { static irqreturn_t spear_adc_isr(int irq, void *dev_id) { - struct spear_adc_info *info = (struct spear_adc_info *)dev_id; + struct spear_adc_state *st = (struct spear_adc_state *)dev_id; /* Read value to clear IRQ */ - info->value = spear_adc_get_average(info); - complete(&info->completion); + st->value = spear_adc_get_average(st); + complete(&st->completion); return IRQ_HANDLED; } -static int spear_adc_configure(struct spear_adc_info *info) +static int spear_adc_configure(struct spear_adc_state *st) { int i; /* Reset ADC core */ - spear_adc_set_status(info, 0); - __raw_writel(0, &info->adc_base_spear6xx->clk); + spear_adc_set_status(st, 0); + __raw_writel(0, &st->adc_base_spear6xx->clk); for (i = 0; i < 8; i++) - spear_adc_set_ctrl(info, i, 0); - spear_adc_set_scanrate(info, 0); + spear_adc_set_ctrl(st, i, 0); + spear_adc_set_scanrate(st, 0); - spear_adc_set_clk(info, info->sampling_freq); + spear_adc_set_clk(st, st->sampling_freq); return 0; } -static ssize_t spear_adc_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct spear_adc_info *info = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", info->current_clk); -} - -static ssize_t spear_adc_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct spear_adc_info *info = iio_priv(indio_dev); - u32 clk_high, clk_low, count; - u32 apb_clk = clk_get_rate(info->clk); - unsigned long lval; - int ret; - - ret = kstrtoul(buf, 10, &lval); - if (ret) - return ret; - - mutex_lock(&indio_dev->mlock); - - if ((lval < CLK_MIN) || (lval > CLK_MAX)) { - ret = -EINVAL; - goto out; - } - - count = (apb_clk + lval - 1) / lval; - clk_low = count / 2; - clk_high = count - clk_low; - info->current_clk = apb_clk / count; - spear_adc_set_clk(info, lval); - -out: - mutex_unlock(&indio_dev->mlock); - - return ret ? ret : len; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - spear_adc_read_frequency, - spear_adc_write_frequency); - -static struct attribute *spear_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, - NULL -}; - -static const struct attribute_group spear_attribute_group = { - .attrs = spear_attributes, -}; - -static const struct iio_info spear_adc_iio_info = { - .read_raw = &spear_read_raw, - .attrs = &spear_attribute_group, +static const struct iio_info spear_adc_info = { + .read_raw = &spear_adc_read_raw, + .write_raw = &spear_adc_write_raw, .driver_module = THIS_MODULE, }; @@ -293,40 +261,40 @@ static int spear_adc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; - struct spear_adc_info *info; - struct iio_dev *iodev = NULL; + struct spear_adc_state *st; + struct iio_dev *indio_dev = NULL; int ret = -ENODEV; int irq; - iodev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_info)); - if (!iodev) { + indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state)); + if (!indio_dev) { dev_err(dev, "failed allocating iio device\n"); return -ENOMEM; } - info = iio_priv(iodev); - info->np = np; + st = iio_priv(indio_dev); + st->np = np; /* * SPEAr600 has a different register layout than other SPEAr SoC's * (e.g. SPEAr3xx). Let's provide two register base addresses * to support multi-arch kernels. */ - info->adc_base_spear6xx = of_iomap(np, 0); - if (!info->adc_base_spear6xx) { + st->adc_base_spear6xx = of_iomap(np, 0); + if (!st->adc_base_spear6xx) { dev_err(dev, "failed mapping memory\n"); return -ENOMEM; } - info->adc_base_spear3xx = - (struct adc_regs_spear3xx __iomem *)info->adc_base_spear6xx; + st->adc_base_spear3xx = + (struct adc_regs_spear3xx __iomem *)st->adc_base_spear6xx; - info->clk = clk_get(dev, NULL); - if (IS_ERR(info->clk)) { + st->clk = clk_get(dev, NULL); + if (IS_ERR(st->clk)) { dev_err(dev, "failed getting clock\n"); goto errout1; } - ret = clk_prepare_enable(info->clk); + ret = clk_prepare_enable(st->clk); if (ret) { dev_err(dev, "failed enabling clock\n"); goto errout2; @@ -339,14 +307,15 @@ static int spear_adc_probe(struct platform_device *pdev) goto errout3; } - ret = devm_request_irq(dev, irq, spear_adc_isr, 0, MOD_NAME, info); + ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME, + st); if (ret < 0) { dev_err(dev, "failed requesting interrupt\n"); goto errout3; } if (of_property_read_u32(np, "sampling-frequency", - &info->sampling_freq)) { + &st->sampling_freq)) { dev_err(dev, "sampling-frequency missing in DT\n"); ret = -EINVAL; goto errout3; @@ -356,28 +325,28 @@ static int spear_adc_probe(struct platform_device *pdev) * Optional avg_samples defaults to 0, resulting in single data * conversion */ - of_property_read_u32(np, "average-samples", &info->avg_samples); + of_property_read_u32(np, "average-samples", &st->avg_samples); /* * Optional vref_external defaults to 0, resulting in internal vref * selection */ - of_property_read_u32(np, "vref-external", &info->vref_external); + of_property_read_u32(np, "vref-external", &st->vref_external); - spear_adc_configure(info); + spear_adc_configure(st); - platform_set_drvdata(pdev, iodev); + platform_set_drvdata(pdev, indio_dev); - init_completion(&info->completion); + init_completion(&st->completion); - iodev->name = MOD_NAME; - iodev->dev.parent = dev; - iodev->info = &spear_adc_iio_info; - iodev->modes = INDIO_DIRECT_MODE; - iodev->channels = spear_adc_iio_channels; - iodev->num_channels = ARRAY_SIZE(spear_adc_iio_channels); + indio_dev->name = SPEAR_ADC_MOD_NAME; + indio_dev->dev.parent = dev; + indio_dev->info = &spear_adc_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = spear_adc_iio_channels; + indio_dev->num_channels = ARRAY_SIZE(spear_adc_iio_channels); - ret = iio_device_register(iodev); + ret = iio_device_register(indio_dev); if (ret) goto errout3; @@ -386,23 +355,23 @@ static int spear_adc_probe(struct platform_device *pdev) return 0; errout3: - clk_disable_unprepare(info->clk); + clk_disable_unprepare(st->clk); errout2: - clk_put(info->clk); + clk_put(st->clk); errout1: - iounmap(info->adc_base_spear6xx); + iounmap(st->adc_base_spear6xx); return ret; } static int spear_adc_remove(struct platform_device *pdev) { - struct iio_dev *iodev = platform_get_drvdata(pdev); - struct spear_adc_info *info = iio_priv(iodev); + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct spear_adc_state *st = iio_priv(indio_dev); - iio_device_unregister(iodev); - clk_disable_unprepare(info->clk); - clk_put(info->clk); - iounmap(info->adc_base_spear6xx); + iio_device_unregister(indio_dev); + clk_disable_unprepare(st->clk); + clk_put(st->clk); + iounmap(st->adc_base_spear6xx); return 0; } @@ -419,7 +388,7 @@ static struct platform_driver spear_adc_driver = { .probe = spear_adc_probe, .remove = spear_adc_remove, .driver = { - .name = MOD_NAME, + .name = SPEAR_ADC_MOD_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(spear_adc_dt_ids), }, diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 9f0ebb329008c4..5f1770e6f6c321 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -172,7 +172,7 @@ #define ID_ADT75XX 0x10 /* - * struct adt7316_chip_info - chip specifc information + * struct adt7316_chip_info - chip specific information */ struct adt7316_chip_info { @@ -208,7 +208,7 @@ struct adt7316_chip_info { (ADT7316_TEMP_INT_MASK) /* - * struct adt7316_chip_info - chip specifc information + * struct adt7316_chip_info - chip specific information */ struct adt7316_limit_regs { diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c index f2c309d1eb5945..87110d940e9a42 100644 --- a/drivers/staging/iio/cdc/ad7152.c +++ b/drivers/staging/iio/cdc/ad7152.c @@ -78,7 +78,7 @@ enum { }; /* - * struct ad7152_chip_info - chip specifc information + * struct ad7152_chip_info - chip specific information */ struct ad7152_chip_info { diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c index cbb1588d591fdb..e6e9eaa9eab547 100644 --- a/drivers/staging/iio/cdc/ad7746.c +++ b/drivers/staging/iio/cdc/ad7746.c @@ -91,7 +91,7 @@ #define AD7746_CAPDAC_DACP(x) ((x) & 0x7F) /* - * struct ad7746_chip_info - chip specifc information + * struct ad7746_chip_info - chip specific information */ struct ad7746_chip_info { diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c index 0a60def92735e1..fa9649879662f1 100644 --- a/drivers/staging/iio/light/tsl2583.c +++ b/drivers/staging/iio/light/tsl2583.c @@ -165,8 +165,9 @@ taos_i2c_read(struct i2c_client *client, u8 reg, u8 *val, unsigned int len) /* select register to write */ ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | reg)); if (ret < 0) { - dev_err(&client->dev, "taos_i2c_read failed to write" - " register %x\n", reg); + dev_err(&client->dev, + "taos_i2c_read failed to write register %x\n", + reg); return ret; } /* read the data */ @@ -211,7 +212,7 @@ static int taos_get_lux(struct iio_dev *indio_dev) if (chip->taos_chip_status != TSL258X_CHIP_WORKING) { /* device is not enabled */ dev_err(&chip->client->dev, "taos_get_lux device is not enabled\n"); - ret = -EBUSY ; + ret = -EBUSY; goto out_unlock; } @@ -231,8 +232,9 @@ static int taos_get_lux(struct iio_dev *indio_dev) int reg = TSL258X_CMD_REG | (TSL258X_ALS_CHAN0LO + i); ret = taos_i2c_read(chip->client, reg, &buf[i], 1); if (ret < 0) { - dev_err(&chip->client->dev, "taos_get_lux failed to read" - " register %x\n", reg); + dev_err(&chip->client->dev, + "taos_get_lux failed to read register %x\n", + reg); goto out_unlock; } } @@ -449,7 +451,7 @@ static int taos_chip_on(struct iio_dev *indio_dev) } } - msleep(3); + usleep_range(3000, 3500); /* NOW enable the ADC * initialize the desired mode of operation */ utmp = TSL258X_CNTL_PWR_ON | TSL258X_CNTL_ADC_ENBL; @@ -809,9 +811,7 @@ static int taos_probe(struct i2c_client *clientp, if (!i2c_check_functionality(clientp->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&clientp->dev, - "taos_probe() - i2c smbus byte data " - "functions unsupported\n"); + dev_err(&clientp->dev, "taos_probe() - i2c smbus byte data func unsupported\n"); return -EOPNOTSUPP; } @@ -830,30 +830,32 @@ static int taos_probe(struct i2c_client *clientp, ret = i2c_smbus_write_byte(clientp, (TSL258X_CMD_REG | (TSL258X_CNTRL + i))); if (ret < 0) { - dev_err(&clientp->dev, "i2c_smbus_write_bytes() to cmd " - "reg failed in taos_probe(), err = %d\n", ret); + dev_err(&clientp->dev, + "i2c_smbus_write_byte to cmd reg failed in taos_probe(), err = %d\n", + ret); return ret; } ret = i2c_smbus_read_byte(clientp); if (ret < 0) { - dev_err(&clientp->dev, "i2c_smbus_read_byte from " - "reg failed in taos_probe(), err = %d\n", ret); - + dev_err(&clientp->dev, + "i2c_smbus_read_byte from reg failed in taos_probe(), err = %d\n", + ret); return ret; } buf[i] = ret; } if (!taos_tsl258x_device(buf)) { - dev_info(&clientp->dev, "i2c device found but does not match " - "expected id in taos_probe()\n"); + dev_info(&clientp->dev, + "i2c device found but does not match expected id in taos_probe()\n"); return -EINVAL; } ret = i2c_smbus_write_byte(clientp, (TSL258X_CMD_REG | TSL258X_CNTRL)); if (ret < 0) { - dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd reg " - "failed in taos_probe(), err = %d\n", ret); + dev_err(&clientp->dev, + "i2c_smbus_write_byte() to cmd reg failed in taos_probe(), err = %d\n", + ret); return ret; } diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index 48a6afa8408805..38ecb4bb6e4c0e 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -33,7 +33,8 @@ static int iio_trig_periodic_rtc_set_state(struct iio_trigger *trig, bool state) struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig); if (trig_info->frequency == 0) return -EINVAL; - printk(KERN_INFO "trigger frequency is %d\n", trig_info->frequency); + dev_info(&trig_info->rtc->dev, "trigger frequency is %d\n", + trig_info->frequency); return rtc_irq_set_state(trig_info->rtc, &trig_info->task, state); } diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c index 4144a75e5f71bc..c270c9ae6d2771 100644 --- a/drivers/staging/imx-drm/imx-drm-core.c +++ b/drivers/staging/imx-drm/imx-drm-core.c @@ -517,7 +517,7 @@ int imx_drm_encoder_get_mux_id(struct device_node *node, of_node_put(port); if (port == imx_crtc->port) { ret = of_graph_parse_endpoint(ep, &endpoint); - return ret ? ret : endpoint.id; + return ret ? ret : endpoint.port; } } while (ep); @@ -675,6 +675,11 @@ static int imx_drm_platform_probe(struct platform_device *pdev) if (!remote || !of_device_is_available(remote)) { of_node_put(remote); continue; + } else if (!of_device_is_available(remote->parent)) { + dev_warn(&pdev->dev, "parent device of %s is not available\n", + remote->full_name); + of_node_put(remote); + continue; } ret = imx_drm_add_component(&pdev->dev, remote); diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c index d47dedd2cdb416..886a0d49031ba1 100644 --- a/drivers/staging/imx-drm/imx-hdmi.c +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -120,8 +120,6 @@ struct imx_hdmi { struct clk *isfr_clk; struct clk *iahb_clk; - enum drm_connector_status connector_status; - struct hdmi_data_info hdmi_data; int vic; @@ -659,13 +657,10 @@ static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi, static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec) { - unsigned char val = 0; - val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3; - while (!val) { - udelay(1000); + while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) { if (msec-- == 0) return false; - val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3; + udelay(1000); } return true; } @@ -1382,7 +1377,9 @@ static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector { struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, connector); - return hdmi->connector_status; + + return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ? + connector_status_connected : connector_status_disconnected; } static int imx_hdmi_connector_get_modes(struct drm_connector *connector) @@ -1524,7 +1521,6 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0); - hdmi->connector_status = connector_status_connected; imx_hdmi_poweron(hdmi); } else { dev_dbg(hdmi->dev, "EVENT=plugout\n"); @@ -1532,7 +1528,6 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, HDMI_PHY_POL0); - hdmi->connector_status = connector_status_disconnected; imx_hdmi_poweroff(hdmi); } drm_helper_hpd_irq_event(hdmi->connector.dev); @@ -1606,7 +1601,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) return -ENOMEM; hdmi->dev = dev; - hdmi->connector_status = connector_status_disconnected; hdmi->sample_rate = 48000; hdmi->ratio = 100; @@ -1628,7 +1622,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) irq = platform_get_irq(pdev, 0); if (irq < 0) - return -EINVAL; + return irq; ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq, imx_hdmi_irq, IRQF_SHARED, diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c index 575533f4fd64fc..a23f4f773146a8 100644 --- a/drivers/staging/imx-drm/imx-tve.c +++ b/drivers/staging/imx-drm/imx-tve.c @@ -582,7 +582,7 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) tve->dev = dev; spin_lock_init(&tve->lock); - ddc_node = of_parse_phandle(np, "i2c-ddc-bus", 0); + ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); if (ddc_node) { tve->ddc = of_find_i2c_adapter_by_node(ddc_node); of_node_put(ddc_node); diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h index c4d14ead5837ce..c2c6fab05eaab3 100644 --- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h +++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h @@ -76,6 +76,7 @@ enum ipu_channel_irq { IPU_IRQ_EOS = 192, }; +int ipu_map_irq(struct ipu_soc *ipu, int irq); int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, enum ipu_channel_irq irq); @@ -114,8 +115,10 @@ struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel); void ipu_dc_put(struct ipu_dc *dc); int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, u32 pixel_fmt, u32 width); +void ipu_dc_enable(struct ipu_soc *ipu); void ipu_dc_enable_channel(struct ipu_dc *dc); void ipu_dc_disable_channel(struct ipu_dc *dc); +void ipu_dc_disable(struct ipu_soc *ipu); /* * IPU Display Interface (di) functions @@ -152,8 +155,10 @@ void ipu_dmfc_put(struct dmfc_channel *dmfc); struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow); void ipu_dp_put(struct ipu_dp *); +int ipu_dp_enable(struct ipu_soc *ipu); int ipu_dp_enable_channel(struct ipu_dp *dp); void ipu_dp_disable_channel(struct ipu_dp *dp); +void ipu_dp_disable(struct ipu_soc *ipu); int ipu_dp_setup_channel(struct ipu_dp *dp, enum ipu_color_space in, enum ipu_color_space out); int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos); diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c index ca85d3d70ae3f4..a1f7b2001c8a13 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c @@ -697,6 +697,12 @@ int ipu_idmac_enable_channel(struct ipuv3_channel *channel) } EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel); +bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno) +{ + return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno)); +} +EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy); + int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms) { struct ipu_soc *ipu = channel->ipu; @@ -714,6 +720,22 @@ int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms) } EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy); +int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms) +{ + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(ms); + ipu_cm_write(ipu, BIT(irq % 32), IPU_INT_STAT(irq / 32)); + while (!(ipu_cm_read(ipu, IPU_INT_STAT(irq / 32) & BIT(irq % 32)))) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + cpu_relax(); + } + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_wait_interrupt); + int ipu_idmac_disable_channel(struct ipuv3_channel *channel) { struct ipu_soc *ipu = channel->ipu; @@ -900,7 +922,8 @@ static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs) status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i])); for_each_set_bit(bit, &status, 32) { - irq = irq_linear_revmap(ipu->domain, regs[i] * 32 + bit); + irq = irq_linear_revmap(ipu->domain, + regs[i] * 32 + bit); if (irq) generic_handle_irq(irq); } @@ -933,15 +956,22 @@ static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } -int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, - enum ipu_channel_irq irq_type) +int ipu_map_irq(struct ipu_soc *ipu, int irq) { - int irq = irq_linear_revmap(ipu->domain, irq_type + channel->num); + int virq; - if (!irq) - irq = irq_create_mapping(ipu->domain, irq_type + channel->num); + virq = irq_linear_revmap(ipu->domain, irq); + if (!virq) + virq = irq_create_mapping(ipu->domain, irq); - return irq; + return virq; +} +EXPORT_SYMBOL_GPL(ipu_map_irq); + +int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, + enum ipu_channel_irq irq_type) +{ + return ipu_map_irq(ipu, irq_type + channel->num); } EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq); @@ -1053,7 +1083,8 @@ static int ipu_irq_init(struct ipu_soc *ipu) } ret = irq_alloc_domain_generic_chips(ipu->domain, 32, 1, "IPU", - handle_level_irq, 0, IRQF_VALID, 0); + handle_level_irq, 0, + IRQF_VALID, 0); if (ret < 0) { dev_err(ipu->dev, "failed to alloc generic irq chips\n"); irq_domain_remove(ipu->domain); diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c index d5de8bb5c803f8..784a4a13eac3d0 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "../imx-drm.h" @@ -91,6 +92,7 @@ enum ipu_dc_map { IPU_DC_MAP_RGB565, IPU_DC_MAP_GBR24, /* TVEv2 */ IPU_DC_MAP_BGR666, + IPU_DC_MAP_LVDS666, IPU_DC_MAP_BGR24, }; @@ -110,6 +112,9 @@ struct ipu_dc_priv { struct device *dev; struct ipu_dc channels[IPU_DC_NUM_CHANNELS]; struct mutex mutex; + struct completion comp; + int dc_irq; + int dp_irq; }; static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority) @@ -153,6 +158,8 @@ static int ipu_pixfmt_to_map(u32 fmt) return IPU_DC_MAP_GBR24; case V4L2_PIX_FMT_BGR666: return IPU_DC_MAP_BGR666; + case v4l2_fourcc('L', 'V', 'D', '6'): + return IPU_DC_MAP_LVDS666; case V4L2_PIX_FMT_BGR24: return IPU_DC_MAP_BGR24; default: @@ -220,12 +227,16 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, writel(0x0, dc->base + DC_WR_CH_ADDR); writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di)); - ipu_module_enable(priv->ipu, IPU_CONF_DC_EN); - return 0; } EXPORT_SYMBOL_GPL(ipu_dc_init_sync); +void ipu_dc_enable(struct ipu_soc *ipu) +{ + ipu_module_enable(ipu, IPU_CONF_DC_EN); +} +EXPORT_SYMBOL_GPL(ipu_dc_enable); + void ipu_dc_enable_channel(struct ipu_dc *dc) { int di; @@ -239,41 +250,55 @@ void ipu_dc_enable_channel(struct ipu_dc *dc) } EXPORT_SYMBOL_GPL(ipu_dc_enable_channel); +static irqreturn_t dc_irq_handler(int irq, void *dev_id) +{ + struct ipu_dc *dc = dev_id; + u32 reg; + + reg = readl(dc->base + DC_WR_CH_CONF); + reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; + writel(reg, dc->base + DC_WR_CH_CONF); + + /* The Freescale BSP kernel clears DIx_COUNTER_RELEASE here */ + + complete(&dc->priv->comp); + return IRQ_HANDLED; +} + void ipu_dc_disable_channel(struct ipu_dc *dc) { struct ipu_dc_priv *priv = dc->priv; + int irq, ret; u32 val; - int irq = 0, timeout = 50; + /* TODO: Handle MEM_FG_SYNC differently from MEM_BG_SYNC */ if (dc->chno == 1) - irq = IPU_IRQ_DC_FC_1; + irq = priv->dc_irq; else if (dc->chno == 5) - irq = IPU_IRQ_DP_SF_END; + irq = priv->dp_irq; else return; - /* should wait for the interrupt here */ - mdelay(50); + init_completion(&priv->comp); + enable_irq(irq); + ret = wait_for_completion_timeout(&priv->comp, msecs_to_jiffies(50)); + disable_irq(irq); + if (ret <= 0) { + dev_warn(priv->dev, "DC stop timeout after 50 ms\n"); - if (dc->di == 0) - val = 0x00000002; - else - val = 0x00000020; - - /* Wait for DC triple buffer to empty */ - while ((readl(priv->dc_reg + DC_STAT) & val) != val) { - usleep_range(2000, 20000); - timeout -= 2; - if (timeout <= 0) - break; + val = readl(dc->base + DC_WR_CH_CONF); + val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; + writel(val, dc->base + DC_WR_CH_CONF); } - - val = readl(dc->base + DC_WR_CH_CONF); - val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; - writel(val, dc->base + DC_WR_CH_CONF); } EXPORT_SYMBOL_GPL(ipu_dc_disable_channel); +void ipu_dc_disable(struct ipu_soc *ipu) +{ + ipu_module_disable(ipu, IPU_CONF_DC_EN); +} +EXPORT_SYMBOL_GPL(ipu_dc_disable); + static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map, int byte_num, int offset, int mask) { @@ -340,7 +365,7 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, struct ipu_dc_priv *priv; static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c, 0x78, 0, 0x94, 0xb4}; - int i; + int i, ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -361,13 +386,31 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, priv->channels[i].base = priv->dc_reg + channel_offsets[i]; } + priv->dc_irq = ipu_map_irq(ipu, IPU_IRQ_DC_FC_1); + if (!priv->dc_irq) + return -EINVAL; + ret = devm_request_irq(dev, priv->dc_irq, dc_irq_handler, 0, NULL, + &priv->channels[1]); + if (ret < 0) + return ret; + disable_irq(priv->dc_irq); + priv->dp_irq = ipu_map_irq(ipu, IPU_IRQ_DP_SF_END); + if (!priv->dp_irq) + return -EINVAL; + ret = devm_request_irq(dev, priv->dp_irq, dc_irq_handler, 0, NULL, + &priv->channels[5]); + if (ret < 0) + return ret; + disable_irq(priv->dp_irq); + writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) | DC_WR_CH_CONF_PROG_DI_ID, priv->channels[1].base + DC_WR_CH_CONF); writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0), priv->channels[5].base + DC_WR_CH_CONF); - writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1, priv->dc_reg + DC_GEN); + writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1, + priv->dc_reg + DC_GEN); ipu->dc_priv = priv; @@ -398,6 +441,12 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */ ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */ + /* lvds666 */ + ipu_dc_map_clear(priv, IPU_DC_MAP_LVDS666); + ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 0, 5, 0xfc); /* blue */ + ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 1, 13, 0xfc); /* green */ + ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 2, 21, 0xfc); /* red */ + /* bgr24 */ ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24); ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */ diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c index 82a9ebad697c76..849b3e120ef089 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c @@ -595,7 +595,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) } } - if (!sig->clk_pol) + if (sig->clk_pol) di_gen |= DI_GEN_POLARITY_DISP_CLK; ipu_di_write(di, di_gen, DI_GENERAL); diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c index 45213017fa4b35..59f182b28fc1ce 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c @@ -28,7 +28,12 @@ #define DMFC_GENERAL1 0x0014 #define DMFC_GENERAL2 0x0018 #define DMFC_IC_CTRL 0x001c -#define DMFC_STAT 0x0020 +#define DMFC_WR_CHAN_ALT 0x0020 +#define DMFC_WR_CHAN_DEF_ALT 0x0024 +#define DMFC_DP_CHAN_ALT 0x0028 +#define DMFC_DP_CHAN_DEF_ALT 0x002c +#define DMFC_GENERAL1_ALT 0x0030 +#define DMFC_STAT 0x0034 #define DMFC_WR_CHAN_1_28 0 #define DMFC_WR_CHAN_2_41 8 @@ -133,6 +138,20 @@ int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc) } EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel); +static void ipu_dmfc_wait_fifos(struct ipu_dmfc_priv *priv) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + while ((readl(priv->base + DMFC_STAT) & 0x02fff000) != 0x02fff000) { + if (time_after(jiffies, timeout)) { + dev_warn(priv->dev, + "Timeout waiting for DMFC FIFOs to clear\n"); + break; + } + cpu_relax(); + } +} + void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc) { struct ipu_dmfc_priv *priv = dmfc->priv; @@ -141,8 +160,10 @@ void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc) priv->use_count--; - if (!priv->use_count) + if (!priv->use_count) { + ipu_dmfc_wait_fifos(priv); ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN); + } if (priv->use_count < 0) priv->use_count = 0; diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c index 58f87c8d7c07ad..d90f82a87d19d4 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c @@ -215,10 +215,9 @@ int ipu_dp_setup_channel(struct ipu_dp *dp, } EXPORT_SYMBOL_GPL(ipu_dp_setup_channel); -int ipu_dp_enable_channel(struct ipu_dp *dp) +int ipu_dp_enable(struct ipu_soc *ipu) { - struct ipu_flow *flow = to_flow(dp); - struct ipu_dp_priv *priv = flow->priv; + struct ipu_dp_priv *priv = ipu->dp_priv; mutex_lock(&priv->mutex); @@ -227,15 +226,28 @@ int ipu_dp_enable_channel(struct ipu_dp *dp) priv->use_count++; - if (dp->foreground) { - u32 reg; + mutex_unlock(&priv->mutex); - reg = readl(flow->base + DP_COM_CONF); - reg |= DP_COM_CONF_FG_EN; - writel(reg, flow->base + DP_COM_CONF); + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dp_enable); - ipu_srm_dp_sync_update(priv->ipu); - } +int ipu_dp_enable_channel(struct ipu_dp *dp) +{ + struct ipu_flow *flow = to_flow(dp); + struct ipu_dp_priv *priv = flow->priv; + u32 reg; + + if (!dp->foreground) + return 0; + + mutex_lock(&priv->mutex); + + reg = readl(flow->base + DP_COM_CONF); + reg |= DP_COM_CONF_FG_EN; + writel(reg, flow->base + DP_COM_CONF); + + ipu_srm_dp_sync_update(priv->ipu); mutex_unlock(&priv->mutex); @@ -247,25 +259,38 @@ void ipu_dp_disable_channel(struct ipu_dp *dp) { struct ipu_flow *flow = to_flow(dp); struct ipu_dp_priv *priv = flow->priv; + u32 reg, csc; + + if (!dp->foreground) + return; mutex_lock(&priv->mutex); - priv->use_count--; + reg = readl(flow->base + DP_COM_CONF); + csc = reg & DP_COM_CONF_CSC_DEF_MASK; + if (csc == DP_COM_CONF_CSC_DEF_FG) + reg &= ~DP_COM_CONF_CSC_DEF_MASK; - if (dp->foreground) { - u32 reg, csc; + reg &= ~DP_COM_CONF_FG_EN; + writel(reg, flow->base + DP_COM_CONF); - reg = readl(flow->base + DP_COM_CONF); - csc = reg & DP_COM_CONF_CSC_DEF_MASK; - if (csc == DP_COM_CONF_CSC_DEF_FG) - reg &= ~DP_COM_CONF_CSC_DEF_MASK; + writel(0, flow->base + DP_FG_POS); + ipu_srm_dp_sync_update(priv->ipu); - reg &= ~DP_COM_CONF_FG_EN; - writel(reg, flow->base + DP_COM_CONF); + if (ipu_idmac_channel_busy(priv->ipu, IPUV3_CHANNEL_MEM_BG_SYNC)) + ipu_wait_interrupt(priv->ipu, IPU_IRQ_DP_SF_END, 50); - writel(0, flow->base + DP_FG_POS); - ipu_srm_dp_sync_update(priv->ipu); - } + mutex_unlock(&priv->mutex); +} +EXPORT_SYMBOL_GPL(ipu_dp_disable_channel); + +void ipu_dp_disable(struct ipu_soc *ipu) +{ + struct ipu_dp_priv *priv = ipu->dp_priv; + + mutex_lock(&priv->mutex); + + priv->use_count--; if (!priv->use_count) ipu_module_disable(priv->ipu, IPU_CONF_DP_EN); @@ -275,7 +300,7 @@ void ipu_dp_disable_channel(struct ipu_dp *dp) mutex_unlock(&priv->mutex); } -EXPORT_SYMBOL_GPL(ipu_dp_disable_channel); +EXPORT_SYMBOL_GPL(ipu_dp_disable); struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow) { diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h index 4df00501adc210..bfc1b336648823 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h +++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h @@ -185,6 +185,9 @@ void ipu_srm_dp_sync_update(struct ipu_soc *ipu); int ipu_module_enable(struct ipu_soc *ipu, u32 mask); int ipu_module_disable(struct ipu_soc *ipu, u32 mask); +bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno); +int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms); + int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, unsigned long base, u32 module, struct clk *ipu_clk); void ipu_di_exit(struct ipu_soc *ipu, int id); diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c index c48f640db0061e..47bec5e1735865 100644 --- a/drivers/staging/imx-drm/ipuv3-crtc.c +++ b/drivers/staging/imx-drm/ipuv3-crtc.c @@ -60,24 +60,32 @@ struct ipu_crtc { static void ipu_fb_enable(struct ipu_crtc *ipu_crtc) { + struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); + if (ipu_crtc->enabled) return; - ipu_di_enable(ipu_crtc->di); - ipu_dc_enable_channel(ipu_crtc->dc); + ipu_dc_enable(ipu); ipu_plane_enable(ipu_crtc->plane[0]); + /* Start DC channel and DI after IDMAC */ + ipu_dc_enable_channel(ipu_crtc->dc); + ipu_di_enable(ipu_crtc->di); ipu_crtc->enabled = 1; } static void ipu_fb_disable(struct ipu_crtc *ipu_crtc) { + struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); + if (!ipu_crtc->enabled) return; - ipu_plane_disable(ipu_crtc->plane[0]); + /* Stop DC channel and DI before IDMAC */ ipu_dc_disable_channel(ipu_crtc->dc); ipu_di_disable(ipu_crtc->di); + ipu_plane_disable(ipu_crtc->plane[0]); + ipu_dc_disable(ipu); ipu_crtc->enabled = 0; } @@ -158,7 +166,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, sig_cfg.Vsync_pol = 1; sig_cfg.enable_pol = 1; - sig_cfg.clk_pol = 1; + sig_cfg.clk_pol = 0; sig_cfg.width = mode->hdisplay; sig_cfg.height = mode->vdisplay; sig_cfg.pixel_fmt = out_pixel_fmt; diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c index 27a8d735dae027..5697e59ddf1dc0 100644 --- a/drivers/staging/imx-drm/ipuv3-plane.c +++ b/drivers/staging/imx-drm/ipuv3-plane.c @@ -239,6 +239,8 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane) void ipu_plane_enable(struct ipu_plane *ipu_plane) { + if (ipu_plane->dp) + ipu_dp_enable(ipu_plane->ipu); ipu_dmfc_enable_channel(ipu_plane->dmfc); ipu_idmac_enable_channel(ipu_plane->ipu_ch); if (ipu_plane->dp) @@ -257,6 +259,8 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane) ipu_dp_disable_channel(ipu_plane->dp); ipu_idmac_disable_channel(ipu_plane->ipu_ch); ipu_dmfc_disable_channel(ipu_plane->dmfc); + if (ipu_plane->dp) + ipu_dp_disable(ipu_plane->ipu); } static void ipu_plane_dpms(struct ipu_plane *ipu_plane, int mode) diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c index c60b6c645f4200..eaf4dda1a0c442 100644 --- a/drivers/staging/imx-drm/parallel-display.c +++ b/drivers/staging/imx-drm/parallel-display.c @@ -219,6 +219,8 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565; else if (!strcmp(fmt, "bgr666")) imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666; + else if (!strcmp(fmt, "lvds666")) + imxpd->interface_pix_fmt = v4l2_fourcc('L', 'V', 'D', '6'); } panel_node = of_parse_phandle(np, "fsl,panel", 0); diff --git a/drivers/staging/keucr/init.c b/drivers/staging/keucr/init.c index e61183906548be..1e7449d6d1209d 100644 --- a/drivers/staging/keucr/init.c +++ b/drivers/staging/keucr/init.c @@ -9,6 +9,7 @@ #include "usb.h" #include "scsiglue.h" #include "transport.h" +#include "smil.h" #include "init.h" /* diff --git a/drivers/staging/keucr/init.h b/drivers/staging/keucr/init.h index 98d2e3ba854568..32c724df621d16 100644 --- a/drivers/staging/keucr/init.h +++ b/drivers/staging/keucr/init.h @@ -1,7 +1,6 @@ #include "common.h" extern u32 MediaChange; -extern int Check_D_MediaFmt(struct us_data *); diff --git a/drivers/staging/keucr/smil.h b/drivers/staging/keucr/smil.h index 39951738d231f9..f938759337e6b1 100644 --- a/drivers/staging/keucr/smil.h +++ b/drivers/staging/keucr/smil.h @@ -204,6 +204,7 @@ extern struct keucr_media_area CisArea; int Init_D_SmartMedia(void); int Pwoff_D_SmartMedia(void); int Check_D_SmartMedia(void); +int Check_D_MediaFmt(struct us_data *); int Check_D_Parameter(struct us_data *, u16 *, u8 *, u8 *); int Media_D_ReadSector(struct us_data *, u32, u16, u8 *); int Media_D_WriteSector(struct us_data *, u32, u16, u8 *); @@ -284,6 +285,4 @@ u8 correct_data(u8 *, u8 *, u8, u8, u8); int _Correct_D_SwECC(u8 *, u8 *, u8 *); void _Calculate_D_SwECC(u8 *, u8 *); -void SM_Init(void); - #endif /* already included */ diff --git a/drivers/staging/keucr/smilsub.c b/drivers/staging/keucr/smilsub.c index 44ced82650392c..e981f14f3bf95f 100644 --- a/drivers/staging/keucr/smilsub.c +++ b/drivers/staging/keucr/smilsub.c @@ -133,6 +133,7 @@ void Set_D_LogBlockAddr(u8 *redundant) void Set_D_FailBlock(u8 *redundant) { char i; + for (i = 0; i < REDTSIZE; i++) *redundant++ = (u8)((i == REDT_BLOCK) ? 0xF0 : 0xFF); } diff --git a/drivers/staging/keucr/transport.c b/drivers/staging/keucr/transport.c index ae9414755d2f9b..5e59525271f8ba 100644 --- a/drivers/staging/keucr/transport.c +++ b/drivers/staging/keucr/transport.c @@ -669,6 +669,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) /* R/W data */ if (transfer_length) { unsigned int pipe; + if (srb->sc_data_direction == DMA_FROM_DEVICE) pipe = us->recv_bulk_pipe; else diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 77f1b421e957f1..ef511c76a6e36e 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -124,6 +124,7 @@ static int line6_send_raw_message_async_part(struct message *msg, static int line6_start_listen(struct usb_line6 *line6) { int err; + usb_fill_int_urb(line6->urb_listen, line6->usbdev, usb_rcvintpipe(line6->usbdev, line6->ep_control_read), line6->buffer_listen, LINE6_BUFSIZE_LISTEN, diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index 661080b3c39df8..a3136b189ee5bc 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -475,7 +475,7 @@ int line6_init_pcm(struct usb_line6 *line6, MISSING_CASE; } - line6pcm = kzalloc(sizeof(struct snd_line6_pcm), GFP_KERNEL); + line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL); if (line6pcm == NULL) return -ENOMEM; diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c index 41869caf19a70d..0f72db5665fef4 100644 --- a/drivers/staging/line6/playback.c +++ b/drivers/staging/line6/playback.c @@ -34,6 +34,7 @@ static void change_volume(struct urb *urb_out, int volume[], if (bytes_per_frame == 4) { short *p, *buf_end; + p = (short *)urb_out->transfer_buffer; buf_end = p + urb_out->transfer_buffer_length / sizeof(*p); @@ -48,6 +49,7 @@ static void change_volume(struct urb *urb_out, int volume[], for (; p < buf_end; p += 3) { int val; + val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16); val = (val * volume[chn & 1]) >> 8; p[0] = val; @@ -116,6 +118,7 @@ static void add_monitor_signal(struct urb *urb_out, unsigned char *signal, if (bytes_per_frame == 4) { short *pi, *po, *buf_end; + pi = (short *)signal; po = (short *)urb_out->transfer_buffer; buf_end = po + urb_out->transfer_buffer_length / sizeof(*po); @@ -171,6 +174,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) if (fsize == 0) { int n; + line6pcm->count_out += frame_increment; n = line6pcm->count_out / frame_factor; line6pcm->count_out -= n * frame_factor; @@ -207,6 +211,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) copy the data to the temp buffer. */ int len; + len = runtime->buffer_size - line6pcm->pos_out; if (len > 0) { diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c index af2e7e50c13507..dcab6478a3b3fe 100644 --- a/drivers/staging/line6/toneport.c +++ b/drivers/staging/line6/toneport.c @@ -213,6 +213,7 @@ static int snd_toneport_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { const int size = ARRAY_SIZE(toneport_source_info); + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = size; diff --git a/drivers/staging/lustre/include/linux/libcfs/curproc.h b/drivers/staging/lustre/include/linux/libcfs/curproc.h index 8fd47c98fd330e..b314f34d2e680d 100644 --- a/drivers/staging/lustre/include/linux/libcfs/curproc.h +++ b/drivers/staging/lustre/include/linux/libcfs/curproc.h @@ -56,7 +56,6 @@ /* check if task is running in compat mode.*/ #define current_pid() (current->pid) #define current_comm() (current->comm) -int cfs_get_environ(const char *key, char *value, int *val_len); typedef __u32 cfs_cap_t; diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h index 4a6c7da721748d..26b53f6420e501 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h @@ -42,6 +42,7 @@ #endif #include +#include #include "curproc.h" diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h index c87efb49ebc28f..a140e5d9186020 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h @@ -128,7 +128,7 @@ struct cfs_cpt_table *cfs_cpt_table_alloc(unsigned int ncpt); int cfs_cpt_number(struct cfs_cpt_table *cptab); /** - * return number of HW cores or hypter-threadings in a CPU partition \a cpt + * return number of HW cores or hyper-threadings in a CPU partition \a cpt */ int cfs_cpt_weight(struct cfs_cpt_table *cptab, int cpt); /** @@ -152,7 +152,7 @@ int cfs_cpt_of_cpu(struct cfs_cpt_table *cptab, int cpu); */ int cfs_cpt_bind(struct cfs_cpt_table *cptab, int cpt); /** - * add \a cpu to CPU partion @cpt of \a cptab, return 1 for success, + * add \a cpu to CPU partition @cpt of \a cptab, return 1 for success, * otherwise 0 is returned */ int cfs_cpt_set_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu); @@ -202,6 +202,11 @@ void cfs_cpt_clear(struct cfs_cpt_table *cptab, int cpt); */ int cfs_cpt_spread_node(struct cfs_cpt_table *cptab, int cpt); +/** + * return number of HTs in the same core of \a cpu + */ +int cfs_cpu_ht_nsiblings(int cpu); + /** * iterate over all CPU partitions in \a cptab */ diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h index 776e9c0e48c137..9e610a9ce51f97 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h @@ -31,7 +31,7 @@ struct cfs_crypto_hash_type { char *cht_name; /**< hash algorithm name, equal to * format name for crypto api */ - unsigned int cht_key; /**< init key by default (vaild for + unsigned int cht_key; /**< init key by default (valid for * 4 bytes context like crc32, adler */ unsigned int cht_size; /**< hash digest size */ }; diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h index 2bd4885ce06cb6..b270d84def98a8 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h @@ -183,7 +183,7 @@ struct libcfs_debug_msg_data { do { \ (data)->msg_subsys = DEBUG_SUBSYSTEM; \ (data)->msg_file = __FILE__; \ - (data)->msg_fn = __FUNCTION__; \ + (data)->msg_fn = __func__; \ (data)->msg_line = __LINE__; \ (data)->msg_cdls = (cdls); \ (data)->msg_mask = (mask); \ @@ -193,7 +193,7 @@ do { \ static struct libcfs_debug_msg_data dataname = { \ .msg_subsys = DEBUG_SUBSYSTEM, \ .msg_file = __FILE__, \ - .msg_fn = __FUNCTION__, \ + .msg_fn = __func__, \ .msg_line = __LINE__, \ .msg_cdls = (cdls) }; \ dataname.msg_mask = (mask); diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h index e5d5db2556225a..954164361ca405 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h @@ -59,8 +59,8 @@ /* * Ideally we would use HAVE_HASH_LONG for this, but on linux we configure * the linux kernel and user space at the same time, so we need to differentiate - * between them explicitely. If this is not needed on other architectures, then - * we'll need to move the functions to archi specific headers. + * between them explicitly. If this is not needed on other architectures, then + * we'll need to move the functions to architecture specific headers. */ #include @@ -86,7 +86,7 @@ union cfs_hash_lock { /** * cfs_hash_bucket is a container of: - * - lock, couter ... + * - lock, counter ... * - array of hash-head starting from hsb_head[0], hash-head can be one of * . cfs_hash_head_t * . cfs_hash_head_dep_t @@ -136,7 +136,7 @@ enum cfs_hash_tag { CFS_HASH_NO_BKTLOCK = 1 << 1, /** rwlock to protect bucket */ CFS_HASH_RW_BKTLOCK = 1 << 2, - /** spinlcok to protect bucket */ + /** spinlock to protect bucket */ CFS_HASH_SPIN_BKTLOCK = 1 << 3, /** always add new item to tail */ CFS_HASH_ADD_TAIL = 1 << 4, diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h index dddccca120c90b..740bfcd2f09aad 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h @@ -153,7 +153,7 @@ do { \ * default allocator */ #define LIBCFS_ALLOC(ptr, size) \ - LIBCFS_ALLOC_GFP(ptr, size, __GFP_IO) + LIBCFS_ALLOC_GFP(ptr, size, GFP_NOFS) /** * non-sleeping allocator @@ -177,7 +177,7 @@ do { \ /** default numa allocator */ #define LIBCFS_CPT_ALLOC(ptr, cptab, cpt, size) \ - LIBCFS_CPT_ALLOC_GFP(ptr, cptab, cpt, size, __GFP_IO) + LIBCFS_CPT_ALLOC_GFP(ptr, cptab, cpt, size, GFP_NOFS) #define LIBCFS_FREE(ptr, size) \ do { \ diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h index d6e00f92e4a03b..b75e401d9a973c 100644 --- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h +++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h @@ -66,7 +66,7 @@ * - spin_unlock(x) * - spin_unlock_bh(x) * - spin_trylock(x) - * - spin_is_locked(x) + * - assert_spin_locked(x) * * - spin_lock_irq(x) * - spin_lock_irqsave(x, f) diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h index 2af15d41e77aef..ccee5c3e4142da 100644 --- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h +++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h @@ -53,6 +53,11 @@ #include #include +#ifndef HAVE_LIBCFS_CPT +/* Need this for cfs_cpt_table */ +#include +#endif + #define CFS_PAGE_MASK (~((__u64)PAGE_CACHE_SIZE-1)) #define page_index(p) ((p)->index) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index 856fcfaafafa70..06ff463e4af635 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -181,7 +181,7 @@ lnet_net_lock_current(void) #define MAX_PORTALS 64 /* these are only used by code with LNET_USE_LIB_FREELIST, but we still - * exported them to !LNET_USE_LIB_FREELIST for easy implemetation */ + * exported them to !LNET_USE_LIB_FREELIST for easy implementation */ #define LNET_FL_MAX_MES 2048 #define LNET_FL_MAX_MDS 2048 #define LNET_FL_MAX_EQS 512 diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index 1c13ef7df80e0e..a63654b660de45 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -204,7 +204,7 @@ typedef struct lnet_msg { unsigned int msg_receiving:1; /* being received */ unsigned int msg_txcredit:1; /* taken an NI send credit */ unsigned int msg_peertxcredit:1; /* taken a peer send credit */ - unsigned int msg_rtrcredit:1; /* taken a globel router credit */ + unsigned int msg_rtrcredit:1; /* taken a global router credit */ unsigned int msg_peerrtrcredit:1; /* taken a peer router credit */ unsigned int msg_onactivelist:1; /* on the activelist */ @@ -342,7 +342,7 @@ typedef struct lnet_lnd { /* Start receiving 'mlen' bytes of payload data, skipping the following * 'rlen' - 'mlen' bytes. 'private' is the 'private' passed to - * lnet_parse(). Return non-zero for immedaite failure, otherwise + * lnet_parse(). Return non-zero for immediate failure, otherwise * complete later with lnet_finalize(). This also gives back a receive * credit if the LND does flow control. */ int (*lnd_recv)(struct lnet_ni *ni, void *private, lnet_msg_t *msg, @@ -594,7 +594,7 @@ struct lnet_match_table { unsigned int mt_cpt; unsigned int mt_portal; /* portal index */ /* match table is set as "enabled" if there's non-exhausted MD - * attached on mt_mhash, it's only valide for wildcard portal */ + * attached on mt_mhash, it's only valid for wildcard portal */ unsigned int mt_enabled; /* bitmap to flag whether MEs on mt_hash are exhausted or not */ __u64 mt_exhausted[LNET_MT_EXHAUSTED_BMAP]; diff --git a/drivers/staging/lustre/include/linux/lnet/lnetst.h b/drivers/staging/lustre/include/linux/lnet/lnetst.h index e060599314d587..87fe9ac76a6ca8 100644 --- a/drivers/staging/lustre/include/linux/lnet/lnetst.h +++ b/drivers/staging/lustre/include/linux/lnet/lnetst.h @@ -402,7 +402,7 @@ typedef struct { /* add stat in session */ typedef struct { int lstio_sta_key; /* IN: session key */ - int lstio_sta_timeout; /* IN: timeout for stat requst */ + int lstio_sta_timeout; /* IN: timeout for stat request */ int lstio_sta_nmlen; /* IN: group name length */ char *lstio_sta_namep; /* IN: group name */ int lstio_sta_count; /* IN: # of pid */ diff --git a/drivers/staging/lustre/include/linux/lnet/ptllnd.h b/drivers/staging/lustre/include/linux/lnet/ptllnd.h index 564f5d3a9b4d0d..313442a7ed3e0f 100644 --- a/drivers/staging/lustre/include/linux/lnet/ptllnd.h +++ b/drivers/staging/lustre/include/linux/lnet/ptllnd.h @@ -66,7 +66,7 @@ /*#define PTL_MD_LUSTRE_COMPLETION_SEMANTICS */ /* Can compare handles directly on Cray Portals */ -#define PtlHandleIsEqual(a,b) ((a) == (b)) +#define PtlHandleIsEqual(a, b) ((a) == (b)) /* Different error types on Cray Portals*/ #define ptl_err_t ptl_ni_fail_t diff --git a/drivers/staging/lustre/include/linux/lnet/ptllnd_wire.h b/drivers/staging/lustre/include/linux/lnet/ptllnd_wire.h index 7d12b3a23a964c..0d3ec5be0a00a2 100644 --- a/drivers/staging/lustre/include/linux/lnet/ptllnd_wire.h +++ b/drivers/staging/lustre/include/linux/lnet/ptllnd_wire.h @@ -64,26 +64,22 @@ * above is for bulk data transfer */ #define LNET_MSG_MATCHBITS 0 /* the value for the message channel */ -typedef struct -{ +typedef struct { lnet_hdr_t kptlim_hdr; /* portals header */ char kptlim_payload[0]; /* piggy-backed payload */ } WIRE_ATTR kptl_immediate_msg_t; -typedef struct -{ +typedef struct { lnet_hdr_t kptlrm_hdr; /* portals header */ __u64 kptlrm_matchbits; /* matchbits */ } WIRE_ATTR kptl_rdma_msg_t; -typedef struct -{ +typedef struct { __u64 kptlhm_matchbits; /* matchbits */ __u32 kptlhm_max_msg_size; /* max message size */ } WIRE_ATTR kptl_hello_msg_t; -typedef struct -{ +typedef struct { /* First 2 fields fixed FOR ALL TIME */ __u32 ptlm_magic; /* I'm a Portals LND message */ __u16 ptlm_version; /* this is my version number */ @@ -107,7 +103,7 @@ typedef struct } kptl_msg_t; /* kptl_msg_t::ptlm_credits is only a __u8 */ -#define PTLLND_MSG_MAX_CREDITS ((typeof(((kptl_msg_t*) 0)->ptlm_credits)) -1) +#define PTLLND_MSG_MAX_CREDITS ((typeof(((kptl_msg_t*) 0)->ptlm_credits)) - 1) #define PTLLND_MSG_MAGIC LNET_PROTO_PTL_MAGIC #define PTLLND_MSG_VERSION 0x04 diff --git a/drivers/staging/lustre/include/linux/lnet/types.h b/drivers/staging/lustre/include/linux/lnet/types.h index c833ce8544d3cb..2add7976b3b225 100644 --- a/drivers/staging/lustre/include/linux/lnet/types.h +++ b/drivers/staging/lustre/include/linux/lnet/types.h @@ -112,7 +112,7 @@ static inline void LNetInvalidateHandle(lnet_handle_any_t *h) */ static inline int LNetHandleIsEqual (lnet_handle_any_t h1, lnet_handle_any_t h2) { - return (h1.cookie == h2.cookie); + return h1.cookie == h2.cookie; } /** @@ -122,7 +122,7 @@ static inline int LNetHandleIsEqual (lnet_handle_any_t h1, lnet_handle_any_t h2) */ static inline int LNetHandleIsInvalid(lnet_handle_any_t h) { - return (LNET_WIRE_HANDLE_COOKIE_NONE == h.cookie); + return LNET_WIRE_HANDLE_COOKIE_NONE == h.cookie; } /** @@ -181,7 +181,7 @@ typedef struct { * address of an array of lnet_kiov_t and the length field specifies * the number of entries in the array. The length can't be bigger * than LNET_MAX_IOV. The lnet_kiov_t is used to describe page-based - * fragments that are not necessarily mapped in virtal memory. + * fragments that are not necessarily mapped in virtual memory. * - LNET_MD_IOVEC bit set: The start field points to the starting * address of an array of struct iovec and the length field specifies * the number of entries in the array. The length can't be bigger @@ -381,7 +381,7 @@ typedef enum { #define LNET_SEQ_BASETYPE long typedef unsigned LNET_SEQ_BASETYPE lnet_seq_t; -#define LNET_SEQ_GT(a,b) (((signed LNET_SEQ_BASETYPE)((a) - (b))) > 0) +#define LNET_SEQ_GT(a, b) (((signed LNET_SEQ_BASETYPE)((a) - (b))) > 0) /** * Information about an event on a MD. diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 0061c8afa206af..892c41991f83cd 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -1141,7 +1141,7 @@ kiblnd_alloc_pages(kib_pages_t **pp, int cpt, int npages) for (i = 0; i < npages; i++) { p->ibp_pages[i] = alloc_pages_node( cfs_cpt_spread_node(lnet_cpt_table(), cpt), - __GFP_IO, 0); + GFP_NOFS, 0); if (p->ibp_pages[i] == NULL) { CERROR("Can't allocate page %d of %d\n", i, npages); kiblnd_free_pages(p); diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index 6173e74d7492b1..9bf6c949f5db67 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -2609,13 +2609,17 @@ kiblnd_rejected (kib_conn_t *conn, int reason, void *priv, int priv_nob) case IBLND_REJECT_MSG_QUEUE_SIZE: CERROR("%s rejected: incompatible message queue depth %d, %d\n", - libcfs_nid2str(peer->ibp_nid), cp->ibcp_queue_depth, + libcfs_nid2str(peer->ibp_nid), + cp != NULL ? cp->ibcp_queue_depth : + IBLND_MSG_QUEUE_SIZE(rej->ibr_version), IBLND_MSG_QUEUE_SIZE(conn->ibc_version)); break; case IBLND_REJECT_RDMA_FRAGS: CERROR("%s rejected: incompatible # of RDMA fragments %d, %d\n", - libcfs_nid2str(peer->ibp_nid), cp->ibcp_max_frags, + libcfs_nid2str(peer->ibp_nid), + cp != NULL ? cp->ibcp_max_frags : + IBLND_RDMA_FRAGS(rej->ibr_version), IBLND_RDMA_FRAGS(conn->ibc_version)); break; diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c index 21d36ee5378a1e..a391d134787bd7 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c @@ -793,8 +793,6 @@ ksocknal_select_ips(ksock_peer_t *peer, __u32 *peerips, int n_peerips) ip = peer->ksnp_passive_ips[i]; best_iface = ksocknal_ip2iface(peer->ksnp_ni, ip); - /* peer passive ips are kept up to date */ - LASSERT(best_iface != NULL); } else { /* choose a new interface */ LASSERT (i == peer->ksnp_n_passive_ips); @@ -835,8 +833,6 @@ ksocknal_select_ips(ksock_peer_t *peer, __u32 *peerips, int n_peerips) peer->ksnp_n_passive_ips = i+1; } - LASSERT (best_iface != NULL); - /* mark the best matching peer IP used */ j = ksocknal_match_peerip(best_iface, peerips, n_peerips); peerips[j] = 0; diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c index 37758d1c8a68db..82b7d9f2862ca7 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c @@ -188,7 +188,6 @@ void ksocknal_lib_eager_ack (ksock_conn_t *conn) { int opt = 1; - mm_segment_t oldmm = get_fs(); struct socket *sock = conn->ksnc_sock; /* Remind the socket to ACK eagerly. If I don't, the socket might @@ -196,10 +195,8 @@ ksocknal_lib_eager_ack (ksock_conn_t *conn) * on, introducing delay in completing zero-copy sends in my * peer. */ - set_fs(KERNEL_DS); - sock->ops->setsockopt (sock, SOL_TCP, TCP_QUICKACK, + kernel_setsockopt(sock, SOL_TCP, TCP_QUICKACK, (char *)&opt, sizeof (opt)); - set_fs(oldmm); } int @@ -428,7 +425,6 @@ ksocknal_lib_csum_tx(ksock_tx_t *tx) int ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int *nagle) { - mm_segment_t oldmm = get_fs (); struct socket *sock = conn->ksnc_sock; int len; int rc; @@ -443,10 +439,8 @@ ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int rc = libcfs_sock_getbuf(sock, txmem, rxmem); if (rc == 0) { len = sizeof(*nagle); - set_fs(KERNEL_DS); - rc = sock->ops->getsockopt(sock, SOL_TCP, TCP_NODELAY, + rc = kernel_getsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)nagle, &len); - set_fs(oldmm); } ksocknal_connsock_decref(conn); @@ -462,7 +456,6 @@ ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int int ksocknal_lib_setup_sock (struct socket *sock) { - mm_segment_t oldmm = get_fs (); int rc; int option; int keep_idle; @@ -479,20 +472,16 @@ ksocknal_lib_setup_sock (struct socket *sock) linger.l_onoff = 0; linger.l_linger = 0; - set_fs (KERNEL_DS); - rc = sock_setsockopt (sock, SOL_SOCKET, SO_LINGER, + rc = kernel_setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof (linger)); - set_fs (oldmm); if (rc != 0) { CERROR ("Can't set SO_LINGER: %d\n", rc); return (rc); } option = -1; - set_fs (KERNEL_DS); - rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_LINGER2, + rc = kernel_setsockopt(sock, SOL_TCP, TCP_LINGER2, (char *)&option, sizeof (option)); - set_fs (oldmm); if (rc != 0) { CERROR ("Can't set SO_LINGER2: %d\n", rc); return (rc); @@ -501,10 +490,8 @@ ksocknal_lib_setup_sock (struct socket *sock) if (!*ksocknal_tunables.ksnd_nagle) { option = 1; - set_fs (KERNEL_DS); - rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_NODELAY, + rc = kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&option, sizeof (option)); - set_fs (oldmm); if (rc != 0) { CERROR ("Can't disable nagle: %d\n", rc); return (rc); @@ -531,10 +518,8 @@ ksocknal_lib_setup_sock (struct socket *sock) do_keepalive = (keep_idle > 0 && keep_count > 0 && keep_intvl > 0); option = (do_keepalive ? 1 : 0); - set_fs (KERNEL_DS); - rc = sock_setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, + rc = kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&option, sizeof (option)); - set_fs (oldmm); if (rc != 0) { CERROR ("Can't set SO_KEEPALIVE: %d\n", rc); return (rc); @@ -543,28 +528,22 @@ ksocknal_lib_setup_sock (struct socket *sock) if (!do_keepalive) return (0); - set_fs (KERNEL_DS); - rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_KEEPIDLE, + rc = kernel_setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, (char *)&keep_idle, sizeof (keep_idle)); - set_fs (oldmm); if (rc != 0) { CERROR ("Can't set TCP_KEEPIDLE: %d\n", rc); return (rc); } - set_fs (KERNEL_DS); - rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_KEEPINTVL, + rc = kernel_setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, (char *)&keep_intvl, sizeof (keep_intvl)); - set_fs (oldmm); if (rc != 0) { CERROR ("Can't set TCP_KEEPINTVL: %d\n", rc); return (rc); } - set_fs (KERNEL_DS); - rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_KEEPCNT, + rc = kernel_setsockopt(sock, SOL_TCP, TCP_KEEPCNT, (char *)&keep_count, sizeof (keep_count)); - set_fs (oldmm); if (rc != 0) { CERROR ("Can't set TCP_KEEPCNT: %d\n", rc); return (rc); @@ -581,7 +560,6 @@ ksocknal_lib_push_conn (ksock_conn_t *conn) int nonagle; int val = 1; int rc; - mm_segment_t oldmm; rc = ksocknal_connsock_addref(conn); if (rc != 0) /* being shut down */ @@ -595,15 +573,10 @@ ksocknal_lib_push_conn (ksock_conn_t *conn) tp->nonagle = 1; release_sock (sk); - oldmm = get_fs (); - set_fs (KERNEL_DS); - - rc = sk->sk_prot->setsockopt (sk, SOL_TCP, TCP_NODELAY, + rc = kernel_setsockopt(conn->ksnc_sock, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof (val)); LASSERT (rc == 0); - set_fs (oldmm); - lock_sock (sk); tp->nonagle = nonagle; release_sock (sk); diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index 45c23194081b28..3f1fdaa2989185 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -127,8 +127,7 @@ lnet_create_remote_nets_table(void) static void lnet_destroy_remote_nets_table(void) { - int i; - struct list_head *hash; + int i; if (the_lnet.ln_remote_nets_hash == NULL) return; @@ -137,7 +136,8 @@ lnet_destroy_remote_nets_table(void) LASSERT(list_empty(&the_lnet.ln_remote_nets_hash[i])); LIBCFS_FREE(the_lnet.ln_remote_nets_hash, - LNET_REMOTE_NETS_HASH_SIZE * sizeof(*hash)); + LNET_REMOTE_NETS_HASH_SIZE * + sizeof(the_lnet.ln_remote_nets_hash[0])); the_lnet.ln_remote_nets_hash = NULL; } @@ -338,7 +338,7 @@ lnet_counters_get(lnet_counters_t *counters) counters->send_count += ctr->send_count; counters->recv_count += ctr->recv_count; counters->route_count += ctr->route_count; - counters->drop_length += ctr->drop_length; + counters->drop_count += ctr->drop_count; counters->send_length += ctr->send_length; counters->recv_length += ctr->recv_length; counters->route_length += ctr->route_length; @@ -986,12 +986,11 @@ lnet_shutdown_lndnis (void) break; } - while (!list_empty(&ni->ni_list)) { + if (!list_empty(&ni->ni_list)) { lnet_net_unlock(LNET_LOCK_EX); ++i; if ((i & (-i)) == i) { - CDEBUG(D_WARNING, - "Waiting for zombie LNI %s\n", + CDEBUG(D_WARNING, "Waiting for zombie LNI %s\n", libcfs_nid2str(ni->ni_nid)); } set_current_state(TASK_UNINTERRUPTIBLE); @@ -1016,6 +1015,8 @@ lnet_shutdown_lndnis (void) libcfs_nid2str(ni->ni_nid)); lnet_ni_free(ni); + i = 2; + lnet_net_lock(LNET_LOCK_EX); } diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c index 995f50976c4298..926923a104c559 100644 --- a/drivers/staging/lustre/lnet/lnet/router.c +++ b/drivers/staging/lustre/lnet/lnet/router.c @@ -145,7 +145,7 @@ lnet_ni_notify_locked(lnet_ni_t *ni, lnet_peer_t *lp) * NB individual events can be missed; the only guarantee is that you * always get the most recent news */ - if (lp->lp_notifying) + if (lp->lp_notifying || ni == NULL) return; lp->lp_notifying = 1; diff --git a/drivers/staging/lustre/lustre/fid/lproc_fid.c b/drivers/staging/lustre/lustre/fid/lproc_fid.c index ddd813cab501d9..6f5674d1aa7255 100644 --- a/drivers/staging/lustre/lustre/fid/lproc_fid.c +++ b/drivers/staging/lustre/lustre/fid/lproc_fid.c @@ -54,32 +54,49 @@ #include #include "fid_internal.h" +/* Format: [0x64BIT_INT - 0x64BIT_INT] + 32 bytes just in case */ +#define MAX_FID_RANGE_STRLEN (32 + 2 * 2 * sizeof(__u64)) /* * Note: this function is only used for testing, it is no safe for production * use. */ -static int -lprocfs_fid_write_common(const char *buffer, unsigned long count, - struct lu_seq_range *range) +static int lprocfs_fid_write_common(const char __user *buffer, size_t count, + struct lu_seq_range *range) { struct lu_seq_range tmp; int rc; + char kernbuf[MAX_FID_RANGE_STRLEN]; LASSERT(range != NULL); - rc = sscanf(buffer, "[%llx - %llx]\n", + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + + kernbuf[count] = 0; + + if (count == 5 && strcmp(kernbuf, "clear") == 0) { + memset(range, 0, sizeof(*range)); + return count; + } + + /* of the form "[0x0000000240000400 - 0x000000028000400]" */ + rc = sscanf(kernbuf, "[%llx - %llx]\n", (long long unsigned *)&tmp.lsr_start, (long long unsigned *)&tmp.lsr_end); - if (rc != 2 || !range_is_sane(&tmp) || range_is_zero(&tmp)) + if (!range_is_sane(&tmp) || range_is_zero(&tmp) || + tmp.lsr_start < range->lsr_start || tmp.lsr_end > range->lsr_end) return -EINVAL; *range = tmp; - return 0; + return count; } /* Client side procfs stuff */ -static ssize_t -lprocfs_fid_space_seq_write(struct file *file, const char *buffer, - size_t count, loff_t *off) +static ssize_t lprocfs_fid_space_seq_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *off) { struct lu_client_seq *seq = ((struct seq_file *)file->private_data)->private; int rc; @@ -114,9 +131,9 @@ lprocfs_fid_space_seq_show(struct seq_file *m, void *unused) return rc; } -static ssize_t -lprocfs_fid_width_seq_write(struct file *file, const char *buffer, - size_t count, loff_t *off) +static ssize_t lprocfs_fid_width_seq_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *off) { struct lu_client_seq *seq = ((struct seq_file *)file->private_data)->private; __u64 max; diff --git a/drivers/staging/lustre/lustre/include/dt_object.h b/drivers/staging/lustre/lustre/include/dt_object.h index 9304c269afa953..9b7921d1dea849 100644 --- a/drivers/staging/lustre/lustre/include/dt_object.h +++ b/drivers/staging/lustre/lustre/include/dt_object.h @@ -441,7 +441,8 @@ struct dt_object_operations { struct dt_object *dt, struct lustre_capa *old, __u64 opc); - int (*do_object_sync)(const struct lu_env *, struct dt_object *); + int (*do_object_sync)(const struct lu_env *env, struct dt_object *obj, + __u64 start, __u64 end); /** * Get object info of next level. Currently, only get inode from osd. * This is only used by quota b=16542 @@ -900,13 +901,13 @@ static inline int dt_object_lock(const struct lu_env *env, int dt_lookup_dir(const struct lu_env *env, struct dt_object *dir, const char *name, struct lu_fid *fid); -static inline int dt_object_sync(const struct lu_env *env, - struct dt_object *o) +static inline int dt_object_sync(const struct lu_env *env, struct dt_object *o, + __u64 start, __u64 end) { LASSERT(o); LASSERT(o->do_ops); LASSERT(o->do_ops->do_object_sync); - return o->do_ops->do_object_sync(env, o); + return o->do_ops->do_object_sync(env, o, start, end); } int dt_declare_version_set(const struct lu_env *env, struct dt_object *o, diff --git a/drivers/staging/lustre/lustre/include/ioctl.h b/drivers/staging/lustre/lustre/include/ioctl.h deleted file mode 100644 index b986920926bd30..00000000000000 --- a/drivers/staging/lustre/lustre/include/ioctl.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * 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 version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * - * GPL HEADER END - */ -/* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - */ - -#ifndef _IOWR - -/* On i386 and x86_64, _ASM_I386_IOCTL_H is defined by the kernel's ioctl.h, - * and on newer kernels this header is shared as _ASM_GENERIC_IOCTL_H. - * - * We can avoid any problems with the kernel header being included again by - * defining _ASM_I386_IOCTL_H here so that a later occurrence of - * does not include the kernel's ioctl.h after this one. b=14746 */ -#define _ASM_I386_IOCTL_H -#define _ASM_GENERIC_IOCTL_H - -/* ioctl command encoding: 32 bits total, command in lower 16 bits, - * size of the parameter structure in the lower 14 bits of the - * upper 16 bits. - * Encoding the size of the parameter structure in the ioctl request - * The highest 2 bits are reserved for indicating the ``access mode''. - * NOTE: This limits the max parameter size to 16kB -1 ! - */ - -/* - * The following is for compatibility across the various Linux - * platforms. The i386 ioctl numbering scheme doesn't really enforce - * a type field. De facto, however, the top 8 bits of the lower 16 - * bits are indeed used as a type field, so we might just as well make - * this explicit here. Please be sure to use the decoding macros - * below from now on. - */ -#define _IOC_NRBITS 8 -#define _IOC_TYPEBITS 8 -#define _IOC_SIZEBITS 14 -#define _IOC_DIRBITS 2 - -#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) -#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) -#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) -#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) - -#define _IOC_NRSHIFT 0 -#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) -#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) -#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) - -/* - * Direction bits. - */ -#define _IOC_NONE 0U -#define _IOC_WRITE 1U -#define _IOC_READ 2U - -#define _IOC(dir,type,nr,size) (((dir) << _IOC_DIRSHIFT) | ((type) << _IOC_TYPESHIFT) | ((nr) << _IOC_NRSHIFT) | ((size) << _IOC_SIZESHIFT)) - -/* used to create numbers */ -#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) -#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) -#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) -#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) - -/* used to decode ioctl numbers.. */ -#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) -#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) -#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) -#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) - -/* ...and for the drivers/sound files... */ - -#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) -#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) -#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) -#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) -#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) - -#endif /* _IOWR */ diff --git a/drivers/staging/lustre/lustre/include/lclient.h b/drivers/staging/lustre/lustre/include/lclient.h index 827209ea6bd0e9..386a36c00f572f 100644 --- a/drivers/staging/lustre/lustre/include/lclient.h +++ b/drivers/staging/lustre/lustre/include/lclient.h @@ -82,16 +82,7 @@ struct ccc_io { /** * I/O vector information to or from which read/write is going. */ - struct iovec *cui_iov; - unsigned long cui_nrsegs; - /** - * Total iov count for left IO. - */ - unsigned long cui_tot_nrsegs; - /** - * Old length for iov that was truncated partially. - */ - size_t cui_iov_olen; + struct iov_iter *cui_iter; /** * Total size for the left IO. */ diff --git a/drivers/staging/lustre/lustre/include/linux/obd.h b/drivers/staging/lustre/lustre/include/linux/obd.h index dc36f75eb6353f..fea7e6cd44c303 100644 --- a/drivers/staging/lustre/lustre/include/linux/obd.h +++ b/drivers/staging/lustre/lustre/include/linux/obd.h @@ -104,7 +104,7 @@ static inline void __client_obd_list_lock(client_obd_lock_t *lock, } #define client_obd_list_lock(lock) \ - __client_obd_list_lock(lock, __FUNCTION__, __LINE__) + __client_obd_list_lock(lock, __func__, __LINE__) static inline void client_obd_list_unlock(client_obd_lock_t *lock) { diff --git a/drivers/staging/lustre/lustre/include/lprocfs_status.h b/drivers/staging/lustre/lustre/include/lprocfs_status.h index 428e3e4ce05c1a..1b7f6a9bf62cf1 100644 --- a/drivers/staging/lustre/lustre/include/lprocfs_status.h +++ b/drivers/staging/lustre/lustre/include/lprocfs_status.h @@ -369,6 +369,7 @@ static inline void s2dhms(struct dhms *ts, time_t secs) #define JOBSTATS_JOBID_VAR_MAX_LEN 20 #define JOBSTATS_DISABLE "disable" #define JOBSTATS_PROCNAME_UID "procname_uid" +#define JOBSTATS_NODELOCAL "nodelocal" extern int lprocfs_write_frac_helper(const char *buffer, unsigned long count, int *val, int mult); @@ -687,7 +688,7 @@ static int name##_single_open(cfs_inode_t *inode, struct file *file) \ { \ return single_open(file, name##_seq_show, PDE_DATA(inode)); \ } \ -struct file_operations name##_fops = { \ +static struct file_operations name##_fops = { \ .owner = THIS_MODULE, \ .open = name##_single_open, \ .read = seq_read, \ @@ -730,7 +731,7 @@ struct file_operations name##_fops = { \ { \ return single_open(file, NULL, PDE_DATA(inode)); \ } \ - struct file_operations name##_##type##_fops = { \ + static struct file_operations name##_##type##_fops = { \ .open = name##_##type##_open, \ .write = name##_##type##_write, \ .release = lprocfs_single_release, \ diff --git a/drivers/staging/lustre/lustre/include/lu_object.h b/drivers/staging/lustre/lustre/include/lu_object.h index 6773bca1e0d834..98149f5da1538c 100644 --- a/drivers/staging/lustre/lustre/include/lu_object.h +++ b/drivers/staging/lustre/lustre/include/lu_object.h @@ -515,6 +515,10 @@ enum lu_object_header_attr { * whether object is backed by persistent storage entity. */ struct lu_object_header { + /** + * Fid, uniquely identifying this object. + */ + struct lu_fid loh_fid; /** * Object flags from enum lu_object_header_flags. Set and checked * atomically. @@ -524,10 +528,6 @@ struct lu_object_header { * Object reference count. Protected by lu_site::ls_guard. */ atomic_t loh_ref; - /** - * Fid, uniquely identifying this object. - */ - struct lu_fid loh_fid; /** * Common object attributes, cached for efficiency. From enum * lu_object_header_attr. diff --git a/drivers/staging/lustre/lustre/include/lu_ref.h b/drivers/staging/lustre/lustre/include/lu_ref.h index 50a2a7f786dc5d..b451a888ca3a54 100644 --- a/drivers/staging/lustre/lustre/include/lu_ref.h +++ b/drivers/staging/lustre/lustre/include/lu_ref.h @@ -69,12 +69,12 @@ * * // current thread acquired a temporary reference to foo. * foo_get(foo); - * lu_ref_add(&foo->reference, __FUNCTION__, current); + * lu_ref_add(&foo->reference, __func__, current); * * ... * * // temporary reference is released. - * lu_ref_del(&foo->reference, __FUNCTION__, current); + * lu_ref_del(&foo->reference, __func__, current); * foo_put(foo); * \endcode * diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h index 87905bbc68e1f6..83014c9fea6585 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h @@ -265,7 +265,7 @@ static inline __u64 range_space(const struct lu_seq_range *range) static inline void range_init(struct lu_seq_range *range) { - range->lsr_start = range->lsr_end = range->lsr_index = 0; + memset(range, 0, sizeof(*range)); } /** @@ -1682,6 +1682,30 @@ static inline __u32 lov_mds_md_size(__u16 stripes, __u32 lmm_magic) stripes * sizeof(struct lov_ost_data_v1); } +static inline __u32 +lov_mds_md_max_stripe_count(size_t buf_size, __u32 lmm_magic) +{ + switch (lmm_magic) { + case LOV_MAGIC_V1: { + struct lov_mds_md_v1 lmm; + + if (buf_size < sizeof(lmm)) + return 0; + + return (buf_size - sizeof(lmm)) / sizeof(lmm.lmm_objects[0]); + } + case LOV_MAGIC_V3: { + struct lov_mds_md_v3 lmm; + + if (buf_size < sizeof(lmm)) + return 0; + + return (buf_size - sizeof(lmm)) / sizeof(lmm.lmm_objects[0]); + } + default: + return 0; + } +} #define OBD_MD_FLID (0x00000001ULL) /* object ID */ #define OBD_MD_FLATIME (0x00000002ULL) /* access time */ @@ -2681,6 +2705,8 @@ enum seq_op { * protocol, this will limit the max number of OSTs per LOV */ #define LOV_DESC_MAGIC 0xB0CCDE5C +#define LOV_DESC_QOS_MAXAGE_DEFAULT 5 /* Seconds */ +#define LOV_DESC_STRIPE_SIZE_DEFAULT (1 << LNET_MTU_BITS) /* LOV settings descriptor (should only contain static info) */ struct lov_desc { diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h index f5f369e603def0..95c754f2075f4f 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h @@ -1106,7 +1106,8 @@ static inline struct hsm_action_item * hai_zero(struct hsm_action_list *hal) { return (struct hsm_action_item *)(hal->hal_fsname + cfs_size_round(strlen(hal-> \ - hal_fsname))); + hal_fsname) + + 1)); } /* Return pointer to next hai */ static inline struct hsm_action_item * hai_next(struct hsm_action_item *hai) @@ -1121,7 +1122,7 @@ static inline int hal_size(struct hsm_action_list *hal) int i, sz; struct hsm_action_item *hai; - sz = sizeof(*hal) + cfs_size_round(strlen(hal->hal_fsname)); + sz = sizeof(*hal) + cfs_size_round(strlen(hal->hal_fsname) + 1); hai = hai_zero(hal); for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) sz += cfs_size_round(hai->hai_len); diff --git a/drivers/staging/lustre/lustre/include/lustre_debug.h b/drivers/staging/lustre/lustre/include/lustre_debug.h index 7ec91edd680096..6146ccb8cce004 100644 --- a/drivers/staging/lustre/lustre/include/lustre_debug.h +++ b/drivers/staging/lustre/lustre/include/lustre_debug.h @@ -48,7 +48,6 @@ /* lib/debug.c */ void dump_lniobuf(struct niobuf_local *lnb); int dump_req(struct ptlrpc_request *req); -void dump_lsm(int level, struct lov_stripe_md *lsm); int block_debug_setup(void *addr, int len, __u64 off, __u64 id); int block_debug_check(char *who, void *addr, int len, __u64 off, __u64 id); diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h index 3e25f001c07d68..0c6b7841e56d09 100644 --- a/drivers/staging/lustre/lustre/include/lustre_dlm.h +++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h @@ -212,7 +212,7 @@ struct ldlm_pool_ops { int (*po_recalc)(struct ldlm_pool *pl); /** Cancel at least \a nr locks from pool \a pl */ int (*po_shrink)(struct ldlm_pool *pl, int nr, - unsigned int gfp_mask); + gfp_t gfp_mask); int (*po_setup)(struct ldlm_pool *pl, int limit); }; @@ -260,7 +260,7 @@ struct ldlm_pool { /** Recalculation period for pool. */ time_t pl_recalc_period; /** Recalculation and shrink operations. */ - struct ldlm_pool_ops *pl_ops; + const struct ldlm_pool_ops *pl_ops; /** Number of planned locks for next period. */ int pl_grant_plan; /** Pool statistics. */ @@ -1312,11 +1312,11 @@ int ldlm_lock_change_resource(struct ldlm_namespace *, struct ldlm_lock *, const struct ldlm_res_id *); #define LDLM_RESOURCE_ADDREF(res) do { \ - lu_ref_add_atomic(&(res)->lr_reference, __FUNCTION__, current); \ + lu_ref_add_atomic(&(res)->lr_reference, __func__, current); \ } while (0) #define LDLM_RESOURCE_DELREF(res) do { \ - lu_ref_del(&(res)->lr_reference, __FUNCTION__, current); \ + lu_ref_del(&(res)->lr_reference, __func__, current); \ } while (0) /* ldlm_request.c */ @@ -1445,7 +1445,7 @@ static inline void unlock_res(struct ldlm_resource *res) /** Check if resource is already locked, assert if not. */ static inline void check_res_locked(struct ldlm_resource *res) { - LASSERT(spin_is_locked(&res->lr_lock)); + assert_spin_locked(&res->lr_lock); } struct ldlm_resource * lock_res_and_lock(struct ldlm_lock *lock); @@ -1463,7 +1463,7 @@ void ldlm_pools_fini(void); int ldlm_pool_init(struct ldlm_pool *pl, struct ldlm_namespace *ns, int idx, ldlm_side_t client); int ldlm_pool_shrink(struct ldlm_pool *pl, int nr, - unsigned int gfp_mask); + gfp_t gfp_mask); void ldlm_pool_fini(struct ldlm_pool *pl); int ldlm_pool_setup(struct ldlm_pool *pl, int limit); int ldlm_pool_recalc(struct ldlm_pool *pl); diff --git a/drivers/staging/lustre/lustre/include/lustre_lib.h b/drivers/staging/lustre/lustre/include/lustre_lib.h index 0368ca6ffcc1cd..3c26bbdc44b760 100644 --- a/drivers/staging/lustre/lustre/include/lustre_lib.h +++ b/drivers/staging/lustre/lustre/include/lustre_lib.h @@ -94,19 +94,6 @@ struct obd_client_handle { void statfs_pack(struct obd_statfs *osfs, struct kstatfs *sfs); void statfs_unpack(struct kstatfs *sfs, struct obd_statfs *osfs); -/* l_lock.c */ -struct lustre_lock { - int l_depth; - struct task_struct *l_owner; - struct semaphore l_sem; - spinlock_t l_spin; -}; - -void l_lock_init(struct lustre_lock *); -void l_lock(struct lustre_lock *); -void l_unlock(struct lustre_lock *); -int l_has_lock(struct lustre_lock *); - /* * For md echo client */ @@ -192,24 +179,25 @@ static inline int obd_ioctl_packlen(struct obd_ioctl_data *data) static inline int obd_ioctl_is_invalid(struct obd_ioctl_data *data) { - if (data->ioc_len > (1<<30)) { - CERROR("OBD ioctl: ioc_len larger than 1<<30\n"); + if (data->ioc_len > OBD_MAX_IOCTL_BUFFER) { + CERROR("OBD ioctl: ioc_len larger than %d\n", + OBD_MAX_IOCTL_BUFFER); return 1; } - if (data->ioc_inllen1 > (1<<30)) { - CERROR("OBD ioctl: ioc_inllen1 larger than 1<<30\n"); + if (data->ioc_inllen1 > OBD_MAX_IOCTL_BUFFER) { + CERROR("OBD ioctl: ioc_inllen1 larger than ioc_len\n"); return 1; } - if (data->ioc_inllen2 > (1<<30)) { - CERROR("OBD ioctl: ioc_inllen2 larger than 1<<30\n"); + if (data->ioc_inllen2 > OBD_MAX_IOCTL_BUFFER) { + CERROR("OBD ioctl: ioc_inllen2 larger than ioc_len\n"); return 1; } - if (data->ioc_inllen3 > (1<<30)) { - CERROR("OBD ioctl: ioc_inllen3 larger than 1<<30\n"); + if (data->ioc_inllen3 > OBD_MAX_IOCTL_BUFFER) { + CERROR("OBD ioctl: ioc_inllen3 larger than ioc_len\n"); return 1; } - if (data->ioc_inllen4 > (1<<30)) { - CERROR("OBD ioctl: ioc_inllen4 larger than 1<<30\n"); + if (data->ioc_inllen4 > OBD_MAX_IOCTL_BUFFER) { + CERROR("OBD ioctl: ioc_inllen4 larger than ioc_len\n"); return 1; } if (data->ioc_inlbuf1 && !data->ioc_inllen1) { diff --git a/drivers/staging/lustre/lustre/include/lustre_log.h b/drivers/staging/lustre/lustre/include/lustre_log.h index 896c7576aa0fee..1a9a9228b795ef 100644 --- a/drivers/staging/lustre/lustre/include/lustre_log.h +++ b/drivers/staging/lustre/lustre/include/lustre_log.h @@ -206,11 +206,7 @@ int llog_setup(const struct lu_env *env, struct obd_device *obd, int __llog_ctxt_put(const struct lu_env *env, struct llog_ctxt *ctxt); int llog_cleanup(const struct lu_env *env, struct llog_ctxt *); int llog_sync(struct llog_ctxt *ctxt, struct obd_export *exp, int flags); -int llog_obd_add(const struct lu_env *env, struct llog_ctxt *ctxt, - struct llog_rec_hdr *rec, struct lov_stripe_md *lsm, - struct llog_cookie *logcookies, int numcookies); int llog_cancel(const struct lu_env *env, struct llog_ctxt *ctxt, - struct lov_stripe_md *lsm, int count, struct llog_cookie *cookies, int flags); int obd_llog_init(struct obd_device *obd, struct obd_llog_group *olg, @@ -242,7 +238,6 @@ struct llog_operations { int flags); int (*lop_cleanup)(const struct lu_env *env, struct llog_ctxt *ctxt); int (*lop_cancel)(const struct lu_env *env, struct llog_ctxt *ctxt, - struct lov_stripe_md *lsm, int count, struct llog_cookie *cookies, int flags); int (*lop_connect)(struct llog_ctxt *ctxt, struct llog_logid *logid, struct llog_gen *gen, struct obd_uuid *uuid); @@ -296,11 +291,6 @@ struct llog_operations { int (*lop_add)(const struct lu_env *env, struct llog_handle *lgh, struct llog_rec_hdr *rec, struct llog_cookie *cookie, void *buf, struct thandle *th); - /* Old llog_add version, used in MDS-LOV-OSC now and will gone with - * LOD/OSP replacement */ - int (*lop_obd_add)(const struct lu_env *env, struct llog_ctxt *ctxt, - struct llog_rec_hdr *rec, struct lov_stripe_md *lsm, - struct llog_cookie *logcookies, int numcookies); }; /* In-memory descriptor for a log object or log catalog */ diff --git a/drivers/staging/lustre/lustre/include/lustre_mdc.h b/drivers/staging/lustre/lustre/include/lustre_mdc.h index 468f36344a34d8..66765d4d201ddf 100644 --- a/drivers/staging/lustre/lustre/include/lustre_mdc.h +++ b/drivers/staging/lustre/lustre/include/lustre_mdc.h @@ -140,17 +140,26 @@ static inline void mdc_put_rpc_lock(struct mdc_rpc_lock *lck, mutex_unlock(&lck->rpcl_mutex); } +/* Update the maximum observed easize and cookiesize. The default easize + * and cookiesize is initialized to the minimum value but allowed to grow + * up to a single page in size if required to handle the common case. + */ static inline void mdc_update_max_ea_from_body(struct obd_export *exp, struct mdt_body *body) { if (body->valid & OBD_MD_FLMODEASIZE) { - if (exp->exp_obd->u.cli.cl_max_mds_easize < body->max_mdsize) - exp->exp_obd->u.cli.cl_max_mds_easize = - body->max_mdsize; - if (exp->exp_obd->u.cli.cl_max_mds_cookiesize < - body->max_cookiesize) - exp->exp_obd->u.cli.cl_max_mds_cookiesize = - body->max_cookiesize; + struct client_obd *cli = &exp->exp_obd->u.cli; + + if (cli->cl_max_mds_easize < body->max_mdsize) { + cli->cl_max_mds_easize = body->max_mdsize; + cli->cl_default_mds_easize = + min_t(__u32, body->max_mdsize, PAGE_CACHE_SIZE); + } + if (cli->cl_max_mds_cookiesize < body->max_cookiesize) { + cli->cl_max_mds_cookiesize = body->max_cookiesize; + cli->cl_default_mds_cookiesize = + min_t(__u32, body->max_cookiesize, PAGE_CACHE_SIZE); + } } } diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index 745adbb74cfce7..f6b7d10cb78cf6 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -264,6 +264,8 @@ #define LDLM_MAXREQSIZE (5 * 1024) #define LDLM_MAXREPSIZE (1024) +#define MDS_MAXREQSIZE (5 * 1024) /* >= 4736 */ + #define OST_MAXREQSIZE (5 * 1024) /* Macro to hide a typecast. */ @@ -717,7 +719,7 @@ struct ptlrpc_nrs_pol_ops { * \a nrq * \param[in,out] nrq The request * - * \pre spin_is_locked(&svcpt->scp_req_lock) + * \pre assert_spin_locked(&svcpt->scp_req_lock) * * \see ptlrpc_nrs_req_stop_nolock() */ diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index 72cf3fe4b0c9b5..d5c4613f182d93 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -132,6 +132,13 @@ static inline bool lsm_has_objects(struct lov_stripe_md *lsm) return true; } +static inline int lov_stripe_md_size(unsigned int stripe_count) +{ + struct lov_stripe_md lsm; + + return sizeof(lsm) + stripe_count * sizeof(lsm.lsm_oinfo[0]); +} + struct obd_info; typedef int (*obd_enqueue_update_f)(void *cookie, int rc); @@ -309,9 +316,10 @@ struct client_obd { int cl_conn_count; /* max_mds_easize is purely a performance thing so we don't have to * call obd_size_diskmd() all the time. */ - int cl_default_mds_easize; - int cl_max_mds_easize; - int cl_max_mds_cookiesize; + int cl_default_mds_easize; + int cl_max_mds_easize; + int cl_default_mds_cookiesize; + int cl_max_mds_cookiesize; enum lustre_sec_part cl_sp_me; enum lustre_sec_part cl_sp_to; @@ -398,7 +406,7 @@ struct client_obd { struct mdc_rpc_lock *cl_close_lock; /* mgc datastruct */ - struct semaphore cl_mgc_sem; + struct mutex cl_mgc_mutex; struct local_oid_storage *cl_mgc_los; struct dt_object *cl_mgc_configs_dir; atomic_t cl_mgc_refcount; @@ -598,6 +606,7 @@ struct lmv_obd { int max_easize; int max_def_easize; int max_cookiesize; + int max_def_cookiesize; int server_timeout; int tgts_size; /* size of tgts array */ @@ -989,7 +998,10 @@ enum obd_cleanup_stage { #define KEY_LOCK_TO_STRIPE "lock_to_stripe" #define KEY_LOVDESC "lovdesc" #define KEY_LOV_IDX "lov_idx" -#define KEY_MAX_EASIZE "max_easize" +#define KEY_MAX_EASIZE "max_easize" +#define KEY_DEFAULT_EASIZE "default_easize" +#define KEY_MAX_COOKIESIZE "max_cookiesize" +#define KEY_DEFAULT_COOKIESIZE "default_cookiesize" #define KEY_MDS_CONN "mds_conn" #define KEY_MGSSEC "mgssec" #define KEY_NEXT_ID "next_id" @@ -1383,7 +1395,7 @@ struct md_ops { const char *, int, int, int, struct ptlrpc_request **); - int (*m_init_ea_size)(struct obd_export *, int, int, int); + int (*m_init_ea_size)(struct obd_export *, int, int, int, int); int (*m_get_lustre_md)(struct obd_export *, struct ptlrpc_request *, struct obd_export *, struct obd_export *, diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h index 9d1f266e55e4f5..e265820c009fa3 100644 --- a/drivers/staging/lustre/lustre/include/obd_class.h +++ b/drivers/staging/lustre/lustre/include/obd_class.h @@ -711,15 +711,6 @@ static inline int obd_size_diskmd(struct obd_export *exp, return obd_packmd(exp, NULL, mem_src); } -/* helper functions */ -static inline int obd_alloc_diskmd(struct obd_export *exp, - struct lov_mds_md **disk_tgt) -{ - LASSERT(disk_tgt); - LASSERT(*disk_tgt == NULL); - return obd_packmd(exp, disk_tgt, NULL); -} - static inline int obd_free_diskmd(struct obd_export *exp, struct lov_mds_md **disk_tgt) { @@ -2055,12 +2046,13 @@ static inline ldlm_mode_t md_lock_match(struct obd_export *exp, __u64 flags, } static inline int md_init_ea_size(struct obd_export *exp, int easize, - int def_asize, int cookiesize) + int def_asize, int cookiesize, + int def_cookiesize) { EXP_CHECK_MD_OP(exp, init_ea_size); EXP_MD_COUNTER_INCREMENT(exp, init_ea_size); return MDP(exp->exp_obd, init_ea_size)(exp, easize, def_asize, - cookiesize); + cookiesize, def_cookiesize); } static inline int md_get_remote_perm(struct obd_export *exp, @@ -2133,7 +2125,7 @@ extern struct kmem_cache *obdo_cachep; #define OBDO_ALLOC(ptr) \ do { \ - OBD_SLAB_ALLOC_PTR_GFP((ptr), obdo_cachep, __GFP_IO); \ + OBD_SLAB_ALLOC_PTR_GFP((ptr), obdo_cachep, GFP_NOFS); \ } while(0) #define OBDO_FREE(ptr) \ @@ -2190,6 +2182,9 @@ void class_exit_uuidlist(void); int mea_name2idx(struct lmv_stripe_md *mea, const char *name, int namelen); int raw_name2idx(int hashtype, int count, const char *name, int namelen); +/* class_obd.c */ +extern char obd_jobid_node[]; + /* prng.c */ #define ll_generate_random_uuid(uuid_out) cfs_get_random_bytes(uuid_out, sizeof(class_uuid_t)) diff --git a/drivers/staging/lustre/lustre/include/obd_lov.h b/drivers/staging/lustre/lustre/include/obd_lov.h deleted file mode 100644 index 235718b366dc29..00000000000000 --- a/drivers/staging/lustre/lustre/include/obd_lov.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * 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 version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * - * GPL HEADER END - */ -/* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - */ - -#ifndef _OBD_LOV_H__ -#define _OBD_LOV_H__ - -#define LOV_DEFAULT_STRIPE_SIZE (1 << LNET_MTU_BITS) - -static inline int lov_stripe_md_size(__u16 stripes) -{ - return sizeof(struct lov_stripe_md) + stripes*sizeof(struct lov_oinfo*); -} - -struct lov_version_size { - __u32 lvs_magic; - size_t lvs_lmm_size; - size_t lvs_lod_size; -}; - -static inline __u32 lov_mds_md_stripecnt(int ea_size, __u32 lmm_magic) -{ - static const struct lov_version_size lmm_ver_size[] = { - { .lvs_magic = LOV_MAGIC_V3, - .lvs_lmm_size = sizeof(struct lov_mds_md_v3), - .lvs_lod_size = sizeof(struct lov_ost_data_v1) }, - { .lvs_magic = LOV_MAGIC_V1, - .lvs_lmm_size = sizeof(struct lov_mds_md_v1), - .lvs_lod_size = sizeof(struct lov_ost_data_v1)} }; - int i; - - for (i = 0; i < ARRAY_SIZE(lmm_ver_size); i++) { - if (lmm_magic == lmm_ver_size[i].lvs_magic) { - if (ea_size <= lmm_ver_size[i].lvs_lmm_size) - return 0; - return (ea_size - lmm_ver_size[i].lvs_lmm_size) / - lmm_ver_size[i].lvs_lod_size; - } - } - - /* Invalid LOV magic, so no stripes could fit */ - return 0; -} - -/* lov_do_div64(a, b) returns a % b, and a = a / b. - * The 32-bit code is LOV-specific due to knowing about stripe limits in - * order to reduce the divisor to a 32-bit number. If the divisor is - * already a 32-bit value the compiler handles this directly. */ -#if BITS_PER_LONG > 32 -# define lov_do_div64(n,base) ({ \ - uint64_t __base = (base); \ - uint64_t __rem; \ - __rem = ((uint64_t)(n)) % __base; \ - (n) = ((uint64_t)(n)) / __base; \ - __rem; \ - }) -#else -# define lov_do_div64(n,base) ({ \ - uint64_t __rem; \ - if ((sizeof(base) > 4) && (((base) & 0xffffffff00000000ULL) != 0)) { \ - int __remainder; \ - LASSERTF(!((base) & (LOV_MIN_STRIPE_SIZE - 1)), "64 bit lov " \ - "division %llu / %llu\n", (n), (uint64_t)(base)); \ - __remainder = (n) & (LOV_MIN_STRIPE_SIZE - 1); \ - (n) >>= LOV_MIN_STRIPE_BITS; \ - __rem = do_div(n, (base) >> LOV_MIN_STRIPE_BITS); \ - __rem <<= LOV_MIN_STRIPE_BITS; \ - __rem += __remainder; \ - } else { \ - __rem = do_div(n, base); \ - } \ - __rem; \ - }) -#endif - -#define IOC_LOV_TYPE 'g' -#define IOC_LOV_MIN_NR 50 -#define IOC_LOV_SET_OSC_ACTIVE _IOWR('g', 50, long) -#define IOC_LOV_MAX_NR 50 - -#define QOS_DEFAULT_THRESHOLD 10 /* MB */ -#define QOS_DEFAULT_MAXAGE 5 /* Seconds */ - -#endif diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h index 5ec336968fc876..cc5af509b2616f 100644 --- a/drivers/staging/lustre/lustre/include/obd_support.h +++ b/drivers/staging/lustre/lustre/include/obd_support.h @@ -641,8 +641,8 @@ do { \ #define OBD_ALLOC_GFP(ptr, size, gfp_mask) \ __OBD_MALLOC_VERBOSE(ptr, NULL, 0, size, gfp_mask) -#define OBD_ALLOC(ptr, size) OBD_ALLOC_GFP(ptr, size, __GFP_IO) -#define OBD_ALLOC_WAIT(ptr, size) OBD_ALLOC_GFP(ptr, size, GFP_IOFS) +#define OBD_ALLOC(ptr, size) OBD_ALLOC_GFP(ptr, size, GFP_NOFS) +#define OBD_ALLOC_WAIT(ptr, size) OBD_ALLOC_GFP(ptr, size, GFP_KERNEL) #define OBD_ALLOC_PTR(ptr) OBD_ALLOC(ptr, sizeof(*(ptr))) #define OBD_ALLOC_PTR_WAIT(ptr) OBD_ALLOC_WAIT(ptr, sizeof(*(ptr))) @@ -650,7 +650,7 @@ do { \ __OBD_MALLOC_VERBOSE(ptr, cptab, cpt, size, gfp_mask) #define OBD_CPT_ALLOC(ptr, cptab, cpt, size) \ - OBD_CPT_ALLOC_GFP(ptr, cptab, cpt, size, __GFP_IO) + OBD_CPT_ALLOC_GFP(ptr, cptab, cpt, size, GFP_NOFS) #define OBD_CPT_ALLOC_PTR(ptr, cptab, cpt) \ OBD_CPT_ALLOC(ptr, cptab, cpt, sizeof(*(ptr))) @@ -793,10 +793,10 @@ do { \ } while(0) #define OBD_SLAB_ALLOC(ptr, slab, size) \ - OBD_SLAB_ALLOC_GFP(ptr, slab, size, __GFP_IO) + OBD_SLAB_ALLOC_GFP(ptr, slab, size, GFP_NOFS) #define OBD_SLAB_CPT_ALLOC(ptr, slab, cptab, cpt, size) \ - OBD_SLAB_CPT_ALLOC_GFP(ptr, slab, cptab, cpt, size, __GFP_IO) + OBD_SLAB_CPT_ALLOC_GFP(ptr, slab, cptab, cpt, size, GFP_NOFS) #define OBD_SLAB_ALLOC_PTR(ptr, slab) \ OBD_SLAB_ALLOC(ptr, slab, sizeof(*(ptr))) diff --git a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c index 6907a16dbbd1dc..1b0c216bc56877 100644 --- a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c +++ b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c @@ -63,7 +63,7 @@ #include "../llite/llite_internal.h" -const struct cl_req_operations ccc_req_ops; +static const struct cl_req_operations ccc_req_ops; /* * ccc_ prefix stands for "Common Client Code". @@ -112,12 +112,11 @@ static struct lu_kmem_descr ccc_caches[] = { * */ -void *ccc_key_init(const struct lu_context *ctx, - struct lu_context_key *key) +void *ccc_key_init(const struct lu_context *ctx, struct lu_context_key *key) { struct ccc_thread_info *info; - OBD_SLAB_ALLOC_PTR_GFP(info, ccc_thread_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(info, ccc_thread_kmem, GFP_NOFS); if (info == NULL) info = ERR_PTR(-ENOMEM); return info; @@ -135,7 +134,7 @@ void *ccc_session_key_init(const struct lu_context *ctx, { struct ccc_session *session; - OBD_SLAB_ALLOC_PTR_GFP(session, ccc_session_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(session, ccc_session_kmem, GFP_NOFS); if (session == NULL) session = ERR_PTR(-ENOMEM); return session; @@ -251,7 +250,7 @@ int ccc_req_init(const struct lu_env *env, struct cl_device *dev, struct ccc_req *vrq; int result; - OBD_SLAB_ALLOC_PTR_GFP(vrq, ccc_req_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(vrq, ccc_req_kmem, GFP_NOFS); if (vrq != NULL) { cl_req_slice_add(req, &vrq->crq_cl, dev, &ccc_req_ops); result = 0; @@ -327,7 +326,7 @@ struct lu_object *ccc_object_alloc(const struct lu_env *env, struct ccc_object *vob; struct lu_object *obj; - OBD_SLAB_ALLOC_PTR_GFP(vob, ccc_object_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(vob, ccc_object_kmem, GFP_NOFS); if (vob != NULL) { struct cl_object_header *hdr; @@ -396,7 +395,7 @@ int ccc_lock_init(const struct lu_env *env, CLOBINVRNT(env, obj, ccc_object_invariant(obj)); - OBD_SLAB_ALLOC_PTR_GFP(clk, ccc_lock_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(clk, ccc_lock_kmem, GFP_NOFS); if (clk != NULL) { cl_lock_slice_add(lock, &clk->clk_cl, obj, lkops); result = 0; @@ -721,31 +720,12 @@ int ccc_io_one_lock_index(const struct lu_env *env, struct cl_io *io, void ccc_io_update_iov(const struct lu_env *env, struct ccc_io *cio, struct cl_io *io) { - int i; size_t size = io->u.ci_rw.crw_count; - cio->cui_iov_olen = 0; - if (!cl_is_normalio(env, io) || cio->cui_tot_nrsegs == 0) + if (!cl_is_normalio(env, io) || cio->cui_iter == NULL) return; - for (i = 0; i < cio->cui_tot_nrsegs; i++) { - struct iovec *iv = &cio->cui_iov[i]; - - if (iv->iov_len < size) - size -= iv->iov_len; - else { - if (iv->iov_len > size) { - cio->cui_iov_olen = iv->iov_len; - iv->iov_len = size; - } - break; - } - } - - cio->cui_nrsegs = i + 1; - LASSERTF(cio->cui_tot_nrsegs >= cio->cui_nrsegs, - "tot_nrsegs: %lu, nrsegs: %lu\n", - cio->cui_tot_nrsegs, cio->cui_nrsegs); + iov_iter_truncate(cio->cui_iter, size); } int ccc_io_one_lock(const struct lu_env *env, struct cl_io *io, @@ -776,30 +756,7 @@ void ccc_io_advance(const struct lu_env *env, if (!cl_is_normalio(env, io)) return; - LASSERT(cio->cui_tot_nrsegs >= cio->cui_nrsegs); - LASSERT(cio->cui_tot_count >= nob); - - cio->cui_iov += cio->cui_nrsegs; - cio->cui_tot_nrsegs -= cio->cui_nrsegs; - cio->cui_tot_count -= nob; - - /* update the iov */ - if (cio->cui_iov_olen > 0) { - struct iovec *iv; - - cio->cui_iov--; - cio->cui_tot_nrsegs++; - iv = &cio->cui_iov[0]; - if (io->ci_continue) { - iv->iov_base += iv->iov_len; - LASSERT(cio->cui_iov_olen > iv->iov_len); - iv->iov_len = cio->cui_iov_olen - iv->iov_len; - } else { - /* restore the iov_len, in case of restart io. */ - iv->iov_len = cio->cui_iov_olen; - } - cio->cui_iov_olen = 0; - } + iov_iter_reexpand(cio->cui_iter, cio->cui_tot_count -= nob); } /** @@ -963,7 +920,7 @@ void ccc_req_attr_set(const struct lu_env *env, JOBSTATS_JOBID_SIZE); } -const struct cl_req_operations ccc_req_ops = { +static const struct cl_req_operations ccc_req_ops = { .cro_attr_set = ccc_req_attr_set, .cro_completion = ccc_req_completion }; diff --git a/drivers/staging/lustre/lustre/lclient/lcommon_misc.c b/drivers/staging/lustre/lustre/lclient/lcommon_misc.c index e04c2d37c249fb..21de1cd2afbaca 100644 --- a/drivers/staging/lustre/lustre/lclient/lcommon_misc.c +++ b/drivers/staging/lustre/lustre/lclient/lcommon_misc.c @@ -56,7 +56,7 @@ int cl_init_ea_size(struct obd_export *md_exp, struct obd_export *dt_exp) __u32 valsize = sizeof(struct lov_desc); int rc, easize, def_easize, cookiesize; struct lov_desc desc; - __u16 stripes; + __u16 stripes, def_stripes; rc = obd_get_info(NULL, dt_exp, sizeof(KEY_LOVDESC), KEY_LOVDESC, &valsize, &desc, NULL); @@ -67,15 +67,20 @@ int cl_init_ea_size(struct obd_export *md_exp, struct obd_export *dt_exp) lsm.lsm_stripe_count = stripes; easize = obd_size_diskmd(dt_exp, &lsm); - lsm.lsm_stripe_count = desc.ld_default_stripe_count; + def_stripes = min_t(__u32, desc.ld_default_stripe_count, + LOV_MAX_STRIPE_COUNT); + lsm.lsm_stripe_count = def_stripes; def_easize = obd_size_diskmd(dt_exp, &lsm); cookiesize = stripes * sizeof(struct llog_cookie); - CDEBUG(D_HA, "updating max_mdsize/max_cookiesize: %d/%d\n", - easize, cookiesize); + /* default cookiesize is 0 because from 2.4 server doesn't send + * llog cookies to client. */ + CDEBUG(D_HA, + "updating def/max_easize: %d/%d def/max_cookiesize: 0/%d\n", + def_easize, easize, cookiesize); - rc = md_init_ea_size(md_exp, easize, def_easize, cookiesize); + rc = md_init_ea_size(md_exp, easize, def_easize, cookiesize, 0); return rc; } diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c index ac5d66aa7f0229..bde3a82ce0dd29 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c @@ -104,7 +104,7 @@ struct ldlm_interval *ldlm_interval_alloc(struct ldlm_lock *lock) struct ldlm_interval *node; LASSERT(lock->l_resource->lr_type == LDLM_EXTENT); - OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, GFP_NOFS); if (node == NULL) return NULL; diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h index 8cd79633dea31c..f997566ef11e1d 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h @@ -247,7 +247,7 @@ typedef enum ldlm_policy_res ldlm_policy_res_t; struct __##var##__dummy_read {;} /* semicolon catcher */ #define LDLM_POOL_PROC_WRITER(var, type) \ - int lprocfs_wr_##var(struct file *file, const char *buffer, \ + static int lprocfs_wr_##var(struct file *file, const char *buffer, \ unsigned long count, void *data) \ { \ struct ldlm_pool *pl = data; \ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c index 1a8c0d7005c7a3..8bb59155968f9e 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c @@ -325,7 +325,7 @@ int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg) } init_rwsem(&cli->cl_sem); - sema_init(&cli->cl_mgc_sem, 1); + mutex_init(&cli->cl_mgc_mutex); cli->cl_conn_count = 0; memcpy(server_uuid.uuid, lustre_cfg_buf(lcfg, 2), min_t(unsigned int, LUSTRE_CFG_BUFLEN(lcfg, 2), @@ -514,7 +514,7 @@ int client_connect_import(const struct lu_env *env, LASSERT (imp->imp_state == LUSTRE_IMP_DISCON); GOTO(out_ldlm, rc); } - LASSERT((*exp)->exp_connection); + LASSERT(*exp != NULL && (*exp)->exp_connection); if (data) { LASSERTF((ocd->ocd_connect_flags & data->ocd_connect_flags) == diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index 0548aca45e8e96..1b3f5c1eb80857 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -232,8 +232,6 @@ int ldlm_lock_remove_from_lru_nolock(struct ldlm_lock *lock) LASSERT(lock->l_resource->lr_type != LDLM_FLOCK); list_del_init(&lock->l_lru); - if (lock->l_flags & LDLM_FL_SKIPPED) - lock->l_flags &= ~LDLM_FL_SKIPPED; LASSERT(ns->ns_nr_unused > 0); ns->ns_nr_unused--; rc = 1; @@ -271,6 +269,8 @@ void ldlm_lock_add_to_lru_nolock(struct ldlm_lock *lock) LASSERT(list_empty(&lock->l_lru)); LASSERT(lock->l_resource->lr_type != LDLM_FLOCK); list_add_tail(&lock->l_lru, &ns->ns_unused_list); + if (lock->l_flags & LDLM_FL_SKIPPED) + lock->l_flags &= ~LDLM_FL_SKIPPED; LASSERT(ns->ns_nr_unused >= 0); ns->ns_nr_unused++; } @@ -437,7 +437,7 @@ static struct ldlm_lock *ldlm_lock_new(struct ldlm_resource *resource) if (resource == NULL) LBUG(); - OBD_SLAB_ALLOC_PTR_GFP(lock, ldlm_lock_slab, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(lock, ldlm_lock_slab, GFP_NOFS); if (lock == NULL) return NULL; @@ -1624,7 +1624,7 @@ ldlm_error_t ldlm_lock_enqueue(struct ldlm_namespace *ns, * have to allocate the interval node early otherwise we can't regrant * this lock in the future. - jay */ if (!local && (*flags & LDLM_FL_REPLAY) && res->lr_type == LDLM_EXTENT) - OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, GFP_NOFS); lock_res_and_lock(lock); if (local && lock->l_req_mode == lock->l_granted_mode) { @@ -2146,7 +2146,7 @@ struct ldlm_resource *ldlm_lock_convert(struct ldlm_lock *lock, int new_mode, /* I can't check the type of lock here because the bitlock of lock * is not held here, so do the allocation blindly. -jay */ - OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, GFP_NOFS); if (node == NULL) /* Actually, this causes EDEADLOCK to be returned */ return NULL; diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c index 6758646f575f7f..2cc698179b63ac 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c @@ -378,7 +378,7 @@ static int ldlm_srv_pool_recalc(struct ldlm_pool *pl) * locks smaller in next 10h. */ static int ldlm_srv_pool_shrink(struct ldlm_pool *pl, - int nr, unsigned int gfp_mask) + int nr, gfp_t gfp_mask) { __u32 limit; @@ -518,7 +518,7 @@ static int ldlm_cli_pool_recalc(struct ldlm_pool *pl) * passed \a pl according to \a nr and \a gfp_mask. */ static int ldlm_cli_pool_shrink(struct ldlm_pool *pl, - int nr, unsigned int gfp_mask) + int nr, gfp_t gfp_mask) { struct ldlm_namespace *ns; int unused; @@ -546,13 +546,13 @@ static int ldlm_cli_pool_shrink(struct ldlm_pool *pl, return ldlm_cancel_lru(ns, nr, LCF_ASYNC, LDLM_CANCEL_SHRINK); } -struct ldlm_pool_ops ldlm_srv_pool_ops = { +static const struct ldlm_pool_ops ldlm_srv_pool_ops = { .po_recalc = ldlm_srv_pool_recalc, .po_shrink = ldlm_srv_pool_shrink, .po_setup = ldlm_srv_pool_setup }; -struct ldlm_pool_ops ldlm_cli_pool_ops = { +static const struct ldlm_pool_ops ldlm_cli_pool_ops = { .po_recalc = ldlm_cli_pool_recalc, .po_shrink = ldlm_cli_pool_shrink }; @@ -603,7 +603,7 @@ int ldlm_pool_recalc(struct ldlm_pool *pl) * freeable locks. Otherwise, return the number of canceled locks. */ int ldlm_pool_shrink(struct ldlm_pool *pl, int nr, - unsigned int gfp_mask) + gfp_t gfp_mask) { int cancel = 0; @@ -718,7 +718,7 @@ LPROC_SEQ_FOPS_RO(lprocfs_grant_speed); snprintf(var_name, MAX_STRING_SIZE, #name); \ pool_vars[0].data = var; \ pool_vars[0].fops = ops; \ - lprocfs_add_vars(pl->pl_proc_dir, pool_vars, 0);\ + lprocfs_add_vars(pl->pl_proc_dir, pool_vars, NULL);\ } while (0) static int ldlm_pool_proc_init(struct ldlm_pool *pl) @@ -1029,7 +1029,7 @@ static struct completion ldlm_pools_comp; * count locks from all namespaces (if possible). Returns number of * cached locks. */ -static unsigned long ldlm_pools_count(ldlm_side_t client, unsigned int gfp_mask) +static unsigned long ldlm_pools_count(ldlm_side_t client, gfp_t gfp_mask) { int total = 0, nr_ns; struct ldlm_namespace *ns; @@ -1082,7 +1082,7 @@ static unsigned long ldlm_pools_count(ldlm_side_t client, unsigned int gfp_mask) return total; } -static unsigned long ldlm_pools_scan(ldlm_side_t client, int nr, unsigned int gfp_mask) +static unsigned long ldlm_pools_scan(ldlm_side_t client, int nr, gfp_t gfp_mask) { unsigned long freed = 0; int tmp, nr_ns; diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c index 2824d4a9a85b39..a4cec5e63ce07c 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c @@ -1014,7 +1014,7 @@ static struct ldlm_resource *ldlm_resource_new(void) struct ldlm_resource *res; int idx; - OBD_SLAB_ALLOC_PTR_GFP(res, ldlm_resource_slab, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(res, ldlm_resource_slab, GFP_NOFS); if (res == NULL) return NULL; diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c b/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c index 1fb37008cda242..a1a7bf44cccfe7 100644 --- a/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c +++ b/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c @@ -74,6 +74,22 @@ cfs_cpt_table_free(struct cfs_cpt_table *cptab) } EXPORT_SYMBOL(cfs_cpt_table_free); +#ifdef CONFIG_SMP +int +cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len) +{ + int rc = 0; + + rc = snprintf(buf, len, "%d\t: %d\n", 0, 0); + len -= rc; + if (len <= 0) + return -EFBIG; + + return rc; +} +EXPORT_SYMBOL(cfs_cpt_table_print); +#endif /* CONFIG_SMP */ + int cfs_cpt_number(struct cfs_cpt_table *cptab) { @@ -160,6 +176,13 @@ cfs_cpt_spread_node(struct cfs_cpt_table *cptab, int cpt) } EXPORT_SYMBOL(cfs_cpt_spread_node); +int +cfs_cpu_ht_nsiblings(int cpu) +{ + return 1; +} +EXPORT_SYMBOL(cfs_cpu_ht_nsiblings); + int cfs_cpt_current(struct cfs_cpt_table *cptab, int remap) { diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c index 77b1ef64ecc0c3..fc21210d77ec9a 100644 --- a/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c +++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c @@ -71,7 +71,7 @@ struct cfs_cpt_data { /* reserved for hotplug */ unsigned long cpt_version; /* mutex to protect cpt_cpumask */ - struct semaphore cpt_mutex; + struct mutex cpt_mutex; /* scratch buffer for set/unset_node */ cpumask_t *cpt_cpumask; }; @@ -420,14 +420,14 @@ cfs_cpt_set_node(struct cfs_cpt_table *cptab, int cpt, int node) return 0; } - down(&cpt_data.cpt_mutex); + mutex_lock(&cpt_data.cpt_mutex); mask = cpt_data.cpt_cpumask; cfs_node_to_cpumask(node, mask); rc = cfs_cpt_set_cpumask(cptab, cpt, mask); - up(&cpt_data.cpt_mutex); + mutex_unlock(&cpt_data.cpt_mutex); return rc; } @@ -444,14 +444,14 @@ cfs_cpt_unset_node(struct cfs_cpt_table *cptab, int cpt, int node) return; } - down(&cpt_data.cpt_mutex); + mutex_lock(&cpt_data.cpt_mutex); mask = cpt_data.cpt_cpumask; cfs_node_to_cpumask(node, mask); cfs_cpt_unset_cpumask(cptab, cpt, mask); - up(&cpt_data.cpt_mutex); + mutex_unlock(&cpt_data.cpt_mutex); } EXPORT_SYMBOL(cfs_cpt_unset_node); @@ -881,7 +881,7 @@ cfs_cpt_table_create_pattern(char *pattern) break; } - if (sscanf(str, "%u%n", &cpt, &n) < 1) { + if (sscanf(str, "%d%n", &cpt, &n) < 1) { CERROR("Invalid cpu pattern %s\n", str); goto failed; } @@ -969,11 +969,11 @@ cfs_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) break; } - down(&cpt_data.cpt_mutex); + mutex_lock(&cpt_data.cpt_mutex); /* if all HTs in a core are offline, it may break affinity */ cfs_cpu_ht_siblings(cpu, cpt_data.cpt_cpumask); warn = any_online_cpu(*cpt_data.cpt_cpumask) >= nr_cpu_ids; - up(&cpt_data.cpt_mutex); + mutex_unlock(&cpt_data.cpt_mutex); CDEBUG(warn ? D_WARNING : D_INFO, "Lustre: can't support CPU plug-out well now, " "performance and stability could be impacted " @@ -1017,7 +1017,7 @@ cfs_cpu_init(void) } spin_lock_init(&cpt_data.cpt_lock); - sema_init(&cpt_data.cpt_mutex, 1); + mutex_init(&cpt_data.cpt_mutex); #ifdef CONFIG_HOTPLUG_CPU register_hotcpu_notifier(&cfs_cpu_notifier); diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c index e74c3e28a9727e..bd301ce02255ee 100644 --- a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c +++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c @@ -100,158 +100,6 @@ cfs_cap_t cfs_curproc_cap_pack(void) return cap; } -static int cfs_access_process_vm(struct task_struct *tsk, unsigned long addr, - void *buf, int len, int write) -{ - /* Just copied from kernel for the kernels which doesn't - * have access_process_vm() exported */ - struct mm_struct *mm; - struct vm_area_struct *vma; - struct page *page; - void *old_buf = buf; - - mm = get_task_mm(tsk); - if (!mm) - return 0; - - down_read(&mm->mmap_sem); - /* ignore errors, just check how much was successfully transferred */ - while (len) { - int bytes, rc, offset; - void *maddr; - - rc = get_user_pages(tsk, mm, addr, 1, - write, 1, &page, &vma); - if (rc <= 0) - break; - - bytes = len; - offset = addr & (PAGE_SIZE-1); - if (bytes > PAGE_SIZE-offset) - bytes = PAGE_SIZE-offset; - - maddr = kmap(page); - if (write) { - copy_to_user_page(vma, page, addr, - maddr + offset, buf, bytes); - set_page_dirty_lock(page); - } else { - copy_from_user_page(vma, page, addr, - buf, maddr + offset, bytes); - } - kunmap(page); - page_cache_release(page); - len -= bytes; - buf += bytes; - addr += bytes; - } - up_read(&mm->mmap_sem); - mmput(mm); - - return buf - old_buf; -} - -/* Read the environment variable of current process specified by @key. */ -int cfs_get_environ(const char *key, char *value, int *val_len) -{ - struct mm_struct *mm; - char *buffer, *tmp_buf = NULL; - int buf_len = PAGE_CACHE_SIZE; - int key_len = strlen(key); - unsigned long addr; - int rc; - - buffer = kmalloc(buf_len, GFP_USER); - if (!buffer) - return -ENOMEM; - - mm = get_task_mm(current); - if (!mm) { - kfree(buffer); - return -EINVAL; - } - - /* Avoid deadlocks on mmap_sem if called from sys_mmap_pgoff(), - * which is already holding mmap_sem for writes. If some other - * thread gets the write lock in the meantime, this thread will - * block, but at least it won't deadlock on itself. LU-1735 */ - if (down_read_trylock(&mm->mmap_sem) == 0) { - kfree(buffer); - return -EDEADLK; - } - up_read(&mm->mmap_sem); - - addr = mm->env_start; - while (addr < mm->env_end) { - int this_len, retval, scan_len; - char *env_start, *env_end; - - memset(buffer, 0, buf_len); - - this_len = min_t(int, mm->env_end - addr, buf_len); - retval = cfs_access_process_vm(current, addr, buffer, - this_len, 0); - if (retval != this_len) - break; - - addr += retval; - - /* Parse the buffer to find out the specified key/value pair. - * The "key=value" entries are separated by '\0'. */ - env_start = buffer; - scan_len = this_len; - while (scan_len) { - char *entry; - int entry_len; - - env_end = memscan(env_start, '\0', scan_len); - LASSERT(env_end >= env_start && - env_end <= env_start + scan_len); - - /* The last entry of this buffer cross the buffer - * boundary, reread it in next cycle. */ - if (unlikely(env_end - env_start == scan_len)) { - /* This entry is too large to fit in buffer */ - if (unlikely(scan_len == this_len)) { - CERROR("Too long env variable.\n"); - GOTO(out, rc = -EINVAL); - } - addr -= scan_len; - break; - } - - entry = env_start; - entry_len = env_end - env_start; - - /* Key length + length of '=' */ - if (entry_len > key_len + 1 && - !memcmp(entry, key, key_len)) { - entry += key_len + 1; - entry_len -= key_len + 1; - /* The 'value' buffer passed in is too small.*/ - if (entry_len >= *val_len) - GOTO(out, rc = -EOVERFLOW); - - memcpy(value, entry, entry_len); - *val_len = entry_len; - GOTO(out, rc = 0); - } - - scan_len -= (env_end - env_start + 1); - env_start = env_end + 1; - } - } - GOTO(out, rc = -ENOENT); - -out: - mmput(mm); - kfree((void *)buffer); - if (tmp_buf) - kfree((void *)tmp_buf); - return rc; -} -EXPORT_SYMBOL(cfs_get_environ); - EXPORT_SYMBOL(cfs_cap_raise); EXPORT_SYMBOL(cfs_cap_lower); EXPORT_SYMBOL(cfs_cap_raised); diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c index e6eae0666f0d30..9a3b07bd2fac02 100644 --- a/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c +++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c @@ -44,6 +44,7 @@ int libcfs_ioctl_getdata(char *buf, char *end, void *arg) { struct libcfs_ioctl_hdr *hdr; struct libcfs_ioctl_data *data; + int orig_len; int err; hdr = (struct libcfs_ioctl_hdr *)buf; @@ -69,9 +70,12 @@ int libcfs_ioctl_getdata(char *buf, char *end, void *arg) return -EINVAL; } + orig_len = hdr->ioc_len; err = copy_from_user(buf, (void *)arg, hdr->ioc_len); if (err) return err; + if (orig_len != data->ioc_len) + return -EINVAL; if (libcfs_ioctl_is_invalid(data)) { CERROR("PORTALS: ioctl not correctly formatted\n"); diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c index 7539fe16d76f1d..4153b4a61396cc 100644 --- a/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c +++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c @@ -56,21 +56,8 @@ libcfs_sock_ioctl(int cmd, unsigned long arg) CERROR ("Can't create socket: %d\n", rc); return rc; } - - sock_filp = sock_alloc_file(sock, 0, NULL); - if (IS_ERR(sock_filp)) { - sock_release(sock); - rc = PTR_ERR(sock_filp); - goto out; - } - - set_fs(KERNEL_DS); - if (sock_filp->f_op->unlocked_ioctl) - rc = sock_filp->f_op->unlocked_ioctl(sock_filp, cmd, arg); - set_fs(oldmm); - - fput(sock_filp); -out: + rc = kernel_sock_ioctl(sock, cmd, arg); + sock_release(sock); return rc; } @@ -255,7 +242,6 @@ int libcfs_sock_write (struct socket *sock, void *buffer, int nob, int timeout) { int rc; - mm_segment_t oldmm = get_fs(); long ticks = timeout * HZ; unsigned long then; struct timeval tv; @@ -279,10 +265,8 @@ libcfs_sock_write (struct socket *sock, void *buffer, int nob, int timeout) .tv_sec = ticks / HZ, .tv_usec = ((ticks % HZ) * 1000000) / HZ }; - set_fs(KERNEL_DS); - rc = sock_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, + rc = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); - set_fs(oldmm); if (rc != 0) { CERROR("Can't set socket send timeout " "%ld.%06d: %d\n", @@ -321,7 +305,6 @@ int libcfs_sock_read (struct socket *sock, void *buffer, int nob, int timeout) { int rc; - mm_segment_t oldmm = get_fs(); long ticks = timeout * HZ; unsigned long then; struct timeval tv; @@ -343,10 +326,8 @@ libcfs_sock_read (struct socket *sock, void *buffer, int nob, int timeout) .tv_sec = ticks / HZ, .tv_usec = ((ticks % HZ) * 1000000) / HZ }; - set_fs(KERNEL_DS); - rc = sock_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, + rc = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); - set_fs(oldmm); if (rc != 0) { CERROR("Can't set socket recv timeout %ld.%06d: %d\n", (long)tv.tv_sec, (int)tv.tv_usec, rc); @@ -384,7 +365,6 @@ libcfs_sock_create (struct socket **sockp, int *fatal, struct socket *sock; int rc; int option; - mm_segment_t oldmm = get_fs(); /* All errors are fatal except bind failure if the port is in use */ *fatal = 1; @@ -396,11 +376,9 @@ libcfs_sock_create (struct socket **sockp, int *fatal, return (rc); } - set_fs (KERNEL_DS); option = 1; - rc = sock_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + rc = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&option, sizeof (option)); - set_fs (oldmm); if (rc != 0) { CERROR("Can't set SO_REUSEADDR for socket: %d\n", rc); goto failed; @@ -437,16 +415,13 @@ libcfs_sock_create (struct socket **sockp, int *fatal, int libcfs_sock_setbuf (struct socket *sock, int txbufsize, int rxbufsize) { - mm_segment_t oldmm = get_fs(); int option; int rc; if (txbufsize != 0) { option = txbufsize; - set_fs (KERNEL_DS); - rc = sock_setsockopt(sock, SOL_SOCKET, SO_SNDBUF, + rc = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&option, sizeof (option)); - set_fs (oldmm); if (rc != 0) { CERROR ("Can't set send buffer %d: %d\n", option, rc); @@ -456,10 +431,8 @@ libcfs_sock_setbuf (struct socket *sock, int txbufsize, int rxbufsize) if (rxbufsize != 0) { option = rxbufsize; - set_fs (KERNEL_DS); - rc = sock_setsockopt (sock, SOL_SOCKET, SO_RCVBUF, + rc = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&option, sizeof (option)); - set_fs (oldmm); if (rc != 0) { CERROR ("Can't set receive buffer %d: %d\n", option, rc); diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c index 24ae26d5def395..b16ee08fe74245 100644 --- a/drivers/staging/lustre/lustre/libcfs/module.c +++ b/drivers/staging/lustre/lustre/libcfs/module.c @@ -87,7 +87,8 @@ kportal_memhog_free (struct libcfs_device_userstate *ldu) } int -kportal_memhog_alloc (struct libcfs_device_userstate *ldu, int npages, int flags) +kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages, + gfp_t flags) { struct page **level0p; struct page **level1p; diff --git a/drivers/staging/lustre/lustre/libcfs/nidstrings.c b/drivers/staging/lustre/lustre/libcfs/nidstrings.c index cfb274fc9cbdf0..87705ae4480f25 100644 --- a/drivers/staging/lustre/lustre/libcfs/nidstrings.c +++ b/drivers/staging/lustre/lustre/libcfs/nidstrings.c @@ -227,11 +227,11 @@ libcfs_ip_addr2str(__u32 addr, char *str) int libcfs_ip_str2addr(const char *str, int nob, __u32 *addr) { - int a; - int b; - int c; - int d; - int n = nob; /* XscanfX */ + unsigned int a; + unsigned int b; + unsigned int c; + unsigned int d; + int n = nob; /* XscanfX */ /* numeric IP? */ if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 && @@ -419,7 +419,7 @@ libcfs_str2net_internal(const char *str, __u32 *net) { struct netstrfns *uninitialized_var(nf); int nob; - int netnum; + unsigned int netnum; int i; for (i = 0; i < libcfs_nnetstrfns; i++) { diff --git a/drivers/staging/lustre/lustre/libcfs/tracefile.c b/drivers/staging/lustre/lustre/libcfs/tracefile.c index c8599eefeb76de..07845e8442430e 100644 --- a/drivers/staging/lustre/lustre/libcfs/tracefile.c +++ b/drivers/staging/lustre/lustre/libcfs/tracefile.c @@ -66,7 +66,7 @@ cfs_tage_from_list(struct list_head *list) return list_entry(list, struct cfs_trace_page, linkage); } -static struct cfs_trace_page *cfs_tage_alloc(int gfp) +static struct cfs_trace_page *cfs_tage_alloc(gfp_t gfp) { struct page *page; struct cfs_trace_page *tage; @@ -114,7 +114,7 @@ static void cfs_tage_to_tail(struct cfs_trace_page *tage, list_move_tail(&tage->linkage, queue); } -int cfs_trace_refill_stock(struct cfs_trace_cpu_data *tcd, int gfp, +int cfs_trace_refill_stock(struct cfs_trace_cpu_data *tcd, gfp_t gfp, struct list_head *stock) { int i; @@ -416,13 +416,13 @@ int libcfs_debug_vmsg2(struct libcfs_debug_msg_data *msgdata, cdls->cdls_delay /= libcfs_console_backoff * 4; } else { cdls->cdls_delay *= libcfs_console_backoff; - - if (cdls->cdls_delay < libcfs_console_min_delay) - cdls->cdls_delay = libcfs_console_min_delay; - else if (cdls->cdls_delay > libcfs_console_max_delay) - cdls->cdls_delay = libcfs_console_max_delay; } + if (cdls->cdls_delay < libcfs_console_min_delay) + cdls->cdls_delay = libcfs_console_min_delay; + else if (cdls->cdls_delay > libcfs_console_max_delay) + cdls->cdls_delay = libcfs_console_max_delay; + /* ensure cdls_next is never zero after it's been seen */ cdls->cdls_next = (cfs_time_current() + cdls->cdls_delay) | 1; } diff --git a/drivers/staging/lustre/lustre/libcfs/tracefile.h b/drivers/staging/lustre/lustre/libcfs/tracefile.h index 7e8d17c12b5bf7..55ecfc9f201b3b 100644 --- a/drivers/staging/lustre/lustre/libcfs/tracefile.h +++ b/drivers/staging/lustre/lustre/libcfs/tracefile.h @@ -307,7 +307,7 @@ cfs_trace_put_tcd (struct cfs_trace_cpu_data *tcd) put_cpu(); } -int cfs_trace_refill_stock(struct cfs_trace_cpu_data *tcd, int gfp, +int cfs_trace_refill_stock(struct cfs_trace_cpu_data *tcd, gfp_t gfp, struct list_head *stock); diff --git a/drivers/staging/lustre/lustre/libcfs/workitem.c b/drivers/staging/lustre/lustre/libcfs/workitem.c index ba16fd5db704d7..0a03bf7ba3eb2e 100644 --- a/drivers/staging/lustre/lustre/libcfs/workitem.c +++ b/drivers/staging/lustre/lustre/libcfs/workitem.c @@ -75,7 +75,7 @@ typedef struct cfs_wi_sched { char ws_name[CFS_WS_NAME_LEN]; } cfs_wi_sched_t; -struct cfs_workitem_data { +static struct cfs_workitem_data { /** serialize */ spinlock_t wi_glock; /** list of all schedulers */ diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index 8b5508086174f9..7d520d8f4a6923 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -69,8 +69,7 @@ static void ll_release(struct dentry *de) ll_intent_release(lld->lld_it); OBD_FREE(lld->lld_it, sizeof(*lld->lld_it)); } - LASSERT(lld->lld_cwd_count == 0); - LASSERT(lld->lld_mnt_count == 0); + de->d_fsdata = NULL; call_rcu(&lld->lld_rcu_head, free_dentry_data); } @@ -82,8 +81,9 @@ static void ll_release(struct dentry *de) * an AST before calling d_revalidate_it(). The dentry still exists (marked * INVALID) so d_lookup() matches it, but we have no lock on it (so * lock_match() fails) and we spin around real_lookup(). */ -int ll_dcompare(const struct dentry *parent, const struct dentry *dentry, - unsigned int len, const char *str, const struct qstr *name) +static int ll_dcompare(const struct dentry *parent, const struct dentry *dentry, + unsigned int len, const char *str, + const struct qstr *name) { if (len != name->len) return 1; @@ -238,7 +238,8 @@ void ll_intent_release(struct lookup_intent *it) ll_intent_drop_lock(it); /* We are still holding extra reference on a request, need to free it */ if (it_disposition(it, DISP_ENQ_OPEN_REF)) - ptlrpc_req_finished(it->d.lustre.it_data); /* ll_file_open */ + ptlrpc_req_finished(it->d.lustre.it_data); /* ll_file_open */ + if (it_disposition(it, DISP_ENQ_CREATE_REF)) /* create rec */ ptlrpc_req_finished(it->d.lustre.it_data); @@ -316,15 +317,6 @@ void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry) } } -void ll_frob_intent(struct lookup_intent **itp, struct lookup_intent *deft) -{ - struct lookup_intent *it = *itp; - - if (!it || it->it_op == IT_GETXATTR) - it = *itp = deft; - -} - static int ll_revalidate_dentry(struct dentry *dentry, unsigned int lookup_flags) { @@ -356,7 +348,7 @@ static int ll_revalidate_dentry(struct dentry *dentry, /* * Always trust cached dentries. Update statahead window if necessary. */ -int ll_revalidate_nd(struct dentry *dentry, unsigned int flags) +static int ll_revalidate_nd(struct dentry *dentry, unsigned int flags) { int rc; @@ -368,7 +360,7 @@ int ll_revalidate_nd(struct dentry *dentry, unsigned int flags) } -void ll_d_iput(struct dentry *de, struct inode *inode) +static void ll_d_iput(struct dentry *de, struct inode *inode) { LASSERT(inode); if (!find_cbdata(inode)) @@ -376,7 +368,7 @@ void ll_d_iput(struct dentry *de, struct inode *inode) iput(inode); } -struct dentry_operations ll_d_ops = { +const struct dentry_operations ll_d_ops = { .d_revalidate = ll_revalidate_nd, .d_release = ll_release, .d_delete = ll_ddelete, diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 7fbc18e3e654a1..ae6f61aa4da6f6 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -632,7 +632,7 @@ static int ll_readdir(struct file *filp, struct dir_context *ctx) return rc; } -int ll_send_mgc_param(struct obd_export *mgc, char *string) +static int ll_send_mgc_param(struct obd_export *mgc, char *string) { struct mgs_send_param *msp; int rc = 0; @@ -795,7 +795,7 @@ int ll_dir_getstripe(struct inode *inode, struct lov_mds_md **lmmp, int rc, lmmsize; struct md_op_data *op_data; - rc = ll_get_max_mdsize(sbi, &lmmsize); + rc = ll_get_default_mdsize(sbi, &lmmsize); if (rc) return rc; @@ -1804,6 +1804,11 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg) /* Compute the whole struct size */ totalsize = hur_len(hur); OBD_FREE_PTR(hur); + + /* Final size will be more than double totalsize */ + if (totalsize >= MDS_MAXREQSIZE / 3) + return -E2BIG; + OBD_ALLOC_LARGE(hur, totalsize); if (hur == NULL) return -ENOMEM; @@ -1959,17 +1964,17 @@ static loff_t ll_dir_seek(struct file *file, loff_t offset, int origin) return ret; } -int ll_dir_open(struct inode *inode, struct file *file) +static int ll_dir_open(struct inode *inode, struct file *file) { return ll_file_open(inode, file); } -int ll_dir_release(struct inode *inode, struct file *file) +static int ll_dir_release(struct inode *inode, struct file *file) { return ll_file_release(inode, file); } -struct file_operations ll_dir_operations = { +const struct file_operations ll_dir_operations = { .llseek = ll_dir_seek, .open = ll_dir_open, .release = ll_dir_release, diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 8e844a6371e060..716e1ee0104f6f 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -50,11 +50,21 @@ #include "cl_object.h" -struct ll_file_data *ll_file_data_get(void) +static int +ll_put_grouplock(struct inode *inode, struct file *file, unsigned long arg); + +static int ll_lease_close(struct obd_client_handle *och, struct inode *inode, + bool *lease_broken); + +static enum llioc_iter +ll_iocontrol_call(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int *rcp); + +static struct ll_file_data *ll_file_data_get(void) { struct ll_file_data *fd; - OBD_SLAB_ALLOC_PTR_GFP(fd, ll_file_data_slab, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(fd, ll_file_data_slab, GFP_NOFS); if (fd == NULL) return NULL; fd->fd_write_failed = false; @@ -247,8 +257,8 @@ int ll_md_real_close(struct inode *inode, fmode_t fmode) return rc; } -int ll_md_close(struct obd_export *md_exp, struct inode *inode, - struct file *file) +static int ll_md_close(struct obd_export *md_exp, struct inode *inode, + struct file *file) { struct ll_file_data *fd = LUSTRE_FPRIVATE(file); struct ll_inode_info *lli = ll_i2info(inode); @@ -482,8 +492,8 @@ static int ll_och_fill(struct obd_export *md_exp, struct lookup_intent *it, return md_set_open_replay_data(md_exp, och, it); } -int ll_local_open(struct file *file, struct lookup_intent *it, - struct ll_file_data *fd, struct obd_client_handle *och) +static int ll_local_open(struct file *file, struct lookup_intent *it, + struct ll_file_data *fd, struct obd_client_handle *och) { struct inode *inode = file->f_dentry->d_inode; struct ll_inode_info *lli = ll_i2info(inode); @@ -733,8 +743,9 @@ static int ll_md_blocking_lease_ast(struct ldlm_lock *lock, /** * Acquire a lease and open the file. */ -struct obd_client_handle *ll_lease_open(struct inode *inode, struct file *file, - fmode_t fmode, __u64 open_flags) +static struct obd_client_handle * +ll_lease_open(struct inode *inode, struct file *file, fmode_t fmode, + __u64 open_flags) { struct lookup_intent it = { .it_op = IT_OPEN }; struct ll_sb_info *sbi = ll_i2sbi(inode); @@ -862,14 +873,13 @@ struct obd_client_handle *ll_lease_open(struct inode *inode, struct file *file, OBD_FREE_PTR(och); return ERR_PTR(rc); } -EXPORT_SYMBOL(ll_lease_open); /** * Release lease and close the file. * It will check if the lease has ever broken. */ -int ll_lease_close(struct obd_client_handle *och, struct inode *inode, - bool *lease_broken) +static int ll_lease_close(struct obd_client_handle *och, struct inode *inode, + bool *lease_broken) { struct ldlm_lock *lock; bool cancelled = true; @@ -895,7 +905,6 @@ int ll_lease_close(struct obd_client_handle *och, struct inode *inode, NULL); return rc; } -EXPORT_SYMBOL(ll_lease_close); /* Fills the obdo with the attributes for the lsm */ static int ll_lsm_getattr(struct lov_stripe_md *lsm, struct obd_export *exp, @@ -1105,9 +1114,7 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args, switch (vio->cui_io_subtype) { case IO_NORMAL: - cio->cui_iov = args->u.normal.via_iov; - cio->cui_nrsegs = args->u.normal.via_nrsegs; - cio->cui_tot_nrsegs = cio->cui_nrsegs; + cio->cui_iter = args->u.normal.via_iter; cio->cui_iocb = args->u.normal.via_iocb; if ((iot == CIT_WRITE) && !(cio->cui_fd->fd_flags & LL_FILE_GROUP_LOCKED)) { @@ -1171,58 +1178,23 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args, return result; } -static ssize_t ll_file_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct lu_env *env; struct vvp_io_args *args; - size_t count = 0; ssize_t result; int refcheck; - result = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE); - if (result) - return result; - env = cl_env_get(&refcheck); if (IS_ERR(env)) return PTR_ERR(env); args = vvp_env_args(env, IO_NORMAL); - args->u.normal.via_iov = (struct iovec *)iov; - args->u.normal.via_nrsegs = nr_segs; + args->u.normal.via_iter = to; args->u.normal.via_iocb = iocb; result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_READ, - &iocb->ki_pos, count); - cl_env_put(env, &refcheck); - return result; -} - -static ssize_t ll_file_read(struct file *file, char *buf, size_t count, - loff_t *ppos) -{ - struct lu_env *env; - struct iovec *local_iov; - struct kiocb *kiocb; - ssize_t result; - int refcheck; - - env = cl_env_get(&refcheck); - if (IS_ERR(env)) - return PTR_ERR(env); - - local_iov = &vvp_env_info(env)->vti_local_iov; - kiocb = &vvp_env_info(env)->vti_kiocb; - local_iov->iov_base = (void __user *)buf; - local_iov->iov_len = count; - init_sync_kiocb(kiocb, file); - kiocb->ki_pos = *ppos; - kiocb->ki_nbytes = count; - - result = ll_file_aio_read(kiocb, local_iov, 1, kiocb->ki_pos); - *ppos = kiocb->ki_pos; - + &iocb->ki_pos, iov_iter_count(to)); cl_env_put(env, &refcheck); return result; } @@ -1230,64 +1202,27 @@ static ssize_t ll_file_read(struct file *file, char *buf, size_t count, /* * Write to a file (through the page cache). */ -static ssize_t ll_file_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct lu_env *env; struct vvp_io_args *args; - size_t count = 0; ssize_t result; int refcheck; - result = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ); - if (result) - return result; - env = cl_env_get(&refcheck); if (IS_ERR(env)) return PTR_ERR(env); args = vvp_env_args(env, IO_NORMAL); - args->u.normal.via_iov = (struct iovec *)iov; - args->u.normal.via_nrsegs = nr_segs; + args->u.normal.via_iter = from; args->u.normal.via_iocb = iocb; result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_WRITE, - &iocb->ki_pos, count); - cl_env_put(env, &refcheck); - return result; -} - -static ssize_t ll_file_write(struct file *file, const char *buf, size_t count, - loff_t *ppos) -{ - struct lu_env *env; - struct iovec *local_iov; - struct kiocb *kiocb; - ssize_t result; - int refcheck; - - env = cl_env_get(&refcheck); - if (IS_ERR(env)) - return PTR_ERR(env); - - local_iov = &vvp_env_info(env)->vti_local_iov; - kiocb = &vvp_env_info(env)->vti_kiocb; - local_iov->iov_base = (void __user *)buf; - local_iov->iov_len = count; - init_sync_kiocb(kiocb, file); - kiocb->ki_pos = *ppos; - kiocb->ki_nbytes = count; - - result = ll_file_aio_write(kiocb, local_iov, 1, kiocb->ki_pos); - *ppos = kiocb->ki_pos; - + &iocb->ki_pos, iov_iter_count(from)); cl_env_put(env, &refcheck); return result; } - - /* * Send file content (through pagecache) somewhere with helper */ @@ -1440,7 +1375,7 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename, struct md_op_data *op_data; int rc, lmmsize; - rc = ll_get_max_mdsize(sbi, &lmmsize); + rc = ll_get_default_mdsize(sbi, &lmmsize); if (rc) return rc; @@ -1590,7 +1525,8 @@ static int ll_lov_getstripe(struct inode *inode, unsigned long arg) return rc; } -int ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg) +static int +ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg) { struct ll_inode_info *lli = ll_i2info(inode); struct ll_file_data *fd = LUSTRE_FPRIVATE(file); @@ -1710,13 +1646,13 @@ int ll_release_openhandle(struct dentry *dentry, struct lookup_intent *it) * Get size for inode for which FIEMAP mapping is requested. * Make the FIEMAP get_info call and returns the result. */ -int ll_do_fiemap(struct inode *inode, struct ll_user_fiemap *fiemap, - int num_bytes) +static int ll_do_fiemap(struct inode *inode, struct ll_user_fiemap *fiemap, + size_t num_bytes) { struct obd_export *exp = ll_i2dtexp(inode); struct lov_stripe_md *lsm = NULL; struct ll_fiemap_info_key fm_key = { .name = KEY_FIEMAP, }; - int vallen = num_bytes; + __u32 vallen = num_bytes; int rc; /* Checks for fiemap flags */ @@ -1819,6 +1755,10 @@ static int ll_ioctl_fiemap(struct inode *inode, unsigned long arg) if (get_user(extent_count, &((struct ll_user_fiemap __user *)arg)->fm_extent_count)) return -EFAULT; + + if (extent_count >= + (SIZE_MAX - sizeof(*fiemap_s)) / sizeof(struct ll_fiemap_extent)) + return -EINVAL; num_bytes = sizeof(*fiemap_s) + (extent_count * sizeof(struct ll_fiemap_extent)); @@ -2190,7 +2130,8 @@ static int ll_hsm_import(struct inode *inode, struct file *file, return rc; } -long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long +ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct inode *inode = file->f_dentry->d_inode; struct ll_file_data *fd = LUSTRE_FPRIVATE(file); @@ -2509,7 +2450,7 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } -loff_t ll_file_seek(struct file *file, loff_t offset, int origin) +static loff_t ll_file_seek(struct file *file, loff_t offset, int origin) { struct inode *inode = file->f_dentry->d_inode; loff_t retval, eof = 0; @@ -2533,7 +2474,7 @@ loff_t ll_file_seek(struct file *file, loff_t offset, int origin) return retval; } -int ll_flush(struct file *file, fl_owner_t id) +static int ll_flush(struct file *file, fl_owner_t id) { struct inode *inode = file->f_dentry->d_inode; struct ll_inode_info *lli = ll_i2info(inode); @@ -2559,7 +2500,7 @@ int ll_flush(struct file *file, fl_owner_t id) /** * Called to make sure a portion of file has been written out. - * if @local_only is not true, it will send OST_SYNC RPCs to ost. + * if @mode is not CL_FSYNC_LOCAL, it will send OST_SYNC RPCs to OST. * * Return how many pages have been written. */ @@ -2653,11 +2594,10 @@ int ll_fsync(struct file *file, loff_t start, loff_t end, int datasync) if (!err) ptlrpc_req_finished(req); - if (datasync && S_ISREG(inode->i_mode)) { + if (S_ISREG(inode->i_mode)) { struct ll_file_data *fd = LUSTRE_FPRIVATE(file); - err = cl_sync_file_range(inode, 0, OBD_OBJECT_EOF, - CL_FSYNC_ALL, 0); + err = cl_sync_file_range(inode, start, end, CL_FSYNC_ALL, 0); if (rc == 0 && err < 0) rc = err; if (rc < 0) @@ -2670,7 +2610,8 @@ int ll_fsync(struct file *file, loff_t start, loff_t end, int datasync) return rc; } -int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock) +static int +ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock) { struct inode *inode = file->f_dentry->d_inode; struct ll_sb_info *sbi = ll_i2sbi(inode); @@ -2691,20 +2632,15 @@ int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock) ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FLOCK, 1); - if (file_lock->fl_flags & FL_FLOCK) { + if (file_lock->fl_flags & FL_FLOCK) LASSERT((cmd == F_SETLKW) || (cmd == F_SETLK)); - /* flocks are whole-file locks */ - flock.l_flock.end = OFFSET_MAX; - /* For flocks owner is determined by the local file descriptor*/ - flock.l_flock.owner = (unsigned long)file_lock->fl_file; - } else if (file_lock->fl_flags & FL_POSIX) { - flock.l_flock.owner = (unsigned long)file_lock->fl_owner; - flock.l_flock.start = file_lock->fl_start; - flock.l_flock.end = file_lock->fl_end; - } else { + else if (!(file_lock->fl_flags & FL_POSIX)) return -EINVAL; - } + + flock.l_flock.owner = (unsigned long)file_lock->fl_owner; flock.l_flock.pid = file_lock->fl_pid; + flock.l_flock.start = file_lock->fl_start; + flock.l_flock.end = file_lock->fl_end; /* Somewhat ugly workaround for svc lockd. * lockd installs custom fl_lmops->lm_compare_owner that checks @@ -2799,7 +2735,8 @@ int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock) return rc; } -int ll_file_noflock(struct file *file, int cmd, struct file_lock *file_lock) +static int +ll_file_noflock(struct file *file, int cmd, struct file_lock *file_lock) { return -ENOSYS; } @@ -2882,16 +2819,16 @@ static int ll_inode_revalidate_fini(struct inode *inode, int rc) if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) return 0; } else if (rc != 0) { - CERROR("%s: revalidate FID "DFID" error: rc = %d\n", - ll_get_fsname(inode->i_sb, NULL, 0), - PFID(ll_inode2fid(inode)), rc); + CDEBUG_LIMIT((rc == -EACCES || rc == -EIDRM) ? D_INFO : D_ERROR, + "%s: revalidate FID "DFID" error: rc = %d\n", + ll_get_fsname(inode->i_sb, NULL, 0), + PFID(ll_inode2fid(inode)), rc); } return rc; } -int __ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it, - __u64 ibits) +static int __ll_inode_revalidate(struct dentry *dentry, __u64 ibits) { struct inode *inode = dentry->d_inode; struct ptlrpc_request *req = NULL; @@ -2956,7 +2893,7 @@ int __ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it, int ealen = 0; if (S_ISREG(inode->i_mode)) { - rc = ll_get_max_mdsize(sbi, &ealen); + rc = ll_get_default_mdsize(sbi, &ealen); if (rc) return rc; valid |= OBD_MD_FLEASIZE | OBD_MD_FLMODEASIZE; @@ -2986,13 +2923,12 @@ int __ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it, return rc; } -int ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it, - __u64 ibits) +static int ll_inode_revalidate(struct dentry *dentry, __u64 ibits) { struct inode *inode = dentry->d_inode; int rc; - rc = __ll_inode_revalidate_it(dentry, it, ibits); + rc = __ll_inode_revalidate(dentry, ibits); if (rc != 0) return rc; @@ -3015,16 +2951,15 @@ int ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it, return rc; } -int ll_getattr_it(struct vfsmount *mnt, struct dentry *de, - struct lookup_intent *it, struct kstat *stat) +int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) { struct inode *inode = de->d_inode; struct ll_sb_info *sbi = ll_i2sbi(inode); struct ll_inode_info *lli = ll_i2info(inode); int res = 0; - res = ll_inode_revalidate_it(de, it, MDS_INODELOCK_UPDATE | - MDS_INODELOCK_LOOKUP); + res = ll_inode_revalidate(de, MDS_INODELOCK_UPDATE | + MDS_INODELOCK_LOOKUP); ll_stats_ops_tally(sbi, LPROC_LL_GETATTR, 1); if (res) @@ -3050,15 +2985,9 @@ int ll_getattr_it(struct vfsmount *mnt, struct dentry *de, return 0; } -int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) -{ - struct lookup_intent it = { .it_op = IT_GETATTR }; - - return ll_getattr_it(mnt, de, &it, stat); -} -int ll_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - __u64 start, __u64 len) +static int ll_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, + __u64 start, __u64 len) { int rc; size_t num_bytes; @@ -3076,21 +3005,24 @@ int ll_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, fiemap->fm_extent_count = fieinfo->fi_extents_max; fiemap->fm_start = start; fiemap->fm_length = len; - memcpy(&fiemap->fm_extents[0], fieinfo->fi_extents_start, - sizeof(struct ll_fiemap_extent)); + if (extent_count > 0) + memcpy(&fiemap->fm_extents[0], fieinfo->fi_extents_start, + sizeof(struct ll_fiemap_extent)); rc = ll_do_fiemap(inode, fiemap, num_bytes); fieinfo->fi_flags = fiemap->fm_flags; fieinfo->fi_extents_mapped = fiemap->fm_mapped_extents; - memcpy(fieinfo->fi_extents_start, &fiemap->fm_extents[0], - fiemap->fm_mapped_extents * sizeof(struct ll_fiemap_extent)); + if (extent_count > 0) + memcpy(fieinfo->fi_extents_start, &fiemap->fm_extents[0], + fiemap->fm_mapped_extents * + sizeof(struct ll_fiemap_extent)); OBD_FREE_LARGE(fiemap, num_bytes); return rc; } -struct posix_acl * ll_get_acl(struct inode *inode, int type) +struct posix_acl *ll_get_acl(struct inode *inode, int type) { struct ll_inode_info *lli = ll_i2info(inode); struct posix_acl *acl = NULL; @@ -3117,10 +3049,8 @@ int ll_inode_permission(struct inode *inode, int mask) * need to do it before permission check. */ if (inode == inode->i_sb->s_root->d_inode) { - struct lookup_intent it = { .it_op = IT_LOOKUP }; - - rc = __ll_inode_revalidate_it(inode->i_sb->s_root, &it, - MDS_INODELOCK_LOOKUP); + rc = __ll_inode_revalidate(inode->i_sb->s_root, + MDS_INODELOCK_LOOKUP); if (rc) return rc; } @@ -3139,10 +3069,10 @@ int ll_inode_permission(struct inode *inode, int mask) /* -o localflock - only provides locally consistent flock locks */ struct file_operations ll_file_operations = { - .read = ll_file_read, - .aio_read = ll_file_aio_read, - .write = ll_file_write, - .aio_write = ll_file_aio_write, + .read = new_sync_read, + .read_iter = ll_file_read_iter, + .write = new_sync_write, + .write_iter = ll_file_write_iter, .unlocked_ioctl = ll_file_ioctl, .open = ll_file_open, .release = ll_file_release, @@ -3154,10 +3084,10 @@ struct file_operations ll_file_operations = { }; struct file_operations ll_file_operations_flock = { - .read = ll_file_read, - .aio_read = ll_file_aio_read, - .write = ll_file_write, - .aio_write = ll_file_aio_write, + .read = new_sync_read, + .read_iter = ll_file_read_iter, + .write = new_sync_write, + .write_iter = ll_file_write_iter, .unlocked_ioctl = ll_file_ioctl, .open = ll_file_open, .release = ll_file_release, @@ -3172,10 +3102,10 @@ struct file_operations ll_file_operations_flock = { /* These are for -o noflock - to return ENOSYS on flock calls */ struct file_operations ll_file_operations_noflock = { - .read = ll_file_read, - .aio_read = ll_file_aio_read, - .write = ll_file_write, - .aio_write = ll_file_aio_write, + .read = new_sync_read, + .read_iter = ll_file_read_iter, + .write = new_sync_write, + .write_iter = ll_file_write_iter, .unlocked_ioctl = ll_file_ioctl, .open = ll_file_open, .release = ll_file_release, @@ -3272,8 +3202,9 @@ void ll_iocontrol_unregister(void *magic) EXPORT_SYMBOL(ll_iocontrol_register); EXPORT_SYMBOL(ll_iocontrol_unregister); -enum llioc_iter ll_iocontrol_call(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int *rcp) +static enum llioc_iter +ll_iocontrol_call(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int *rcp) { enum llioc_iter ret = LLIOC_CONT; struct llioc_data *data; @@ -3358,7 +3289,7 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock) * layout here. Please note that we can't use the LVB buffer in * completion AST because it doesn't have a large enough buffer */ oc = ll_mdscapa_get(inode); - rc = ll_get_max_mdsize(sbi, &lmmsize); + rc = ll_get_default_mdsize(sbi, &lmmsize); if (rc == 0) rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc, OBD_MD_FLXATTR, XATTR_NAME_LOV, NULL, 0, @@ -3368,7 +3299,7 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock) return rc; body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); - if (body == NULL || body->eadatasize > lmmsize) + if (body == NULL) GOTO(out, rc = -EPROTO); lmmsize = body->eadatasize; @@ -3435,7 +3366,7 @@ static int ll_layout_lock_set(struct lustre_handle *lockh, ldlm_mode_t mode, if (lvb_ready) { /* layout_gen must be valid if layout lock is not * cancelled and stripe has already set */ - *gen = lli->lli_layout_gen; + *gen = ll_layout_version_get(lli); rc = 0; } GOTO(out, rc); @@ -3533,32 +3464,20 @@ int ll_layout_refresh(struct inode *inode, __u32 *gen) }; int rc; - *gen = lli->lli_layout_gen; - if (!(sbi->ll_flags & LL_SBI_LAYOUT_LOCK)) + *gen = ll_layout_version_get(lli); + if (!(sbi->ll_flags & LL_SBI_LAYOUT_LOCK) || *gen != LL_LAYOUT_GEN_NONE) return 0; /* sanity checks */ LASSERT(fid_is_sane(ll_inode2fid(inode))); LASSERT(S_ISREG(inode->i_mode)); - /* mostly layout lock is caching on the local side, so try to match - * it before grabbing layout lock mutex. */ - mode = ll_take_md_lock(inode, MDS_INODELOCK_LAYOUT, &lockh, 0, - LCK_CR | LCK_CW | LCK_PR | LCK_PW); - if (mode != 0) { /* hit cached lock */ - rc = ll_layout_lock_set(&lockh, mode, inode, gen, false); - if (rc == 0) - return 0; - - /* better hold lli_layout_mutex to try again otherwise - * it will have starvation problem. */ - } - /* take layout lock mutex to enqueue layout lock exclusively. */ mutex_lock(&lli->lli_layout_mutex); again: - /* try again. Maybe somebody else has done this. */ + /* mostly layout lock is caching on the local side, so try to match + * it before grabbing layout lock mutex. */ mode = ll_take_md_lock(inode, MDS_INODELOCK_LAYOUT, &lockh, 0, LCK_CR | LCK_CW | LCK_PR | LCK_PW); if (mode != 0) { /* hit cached lock */ diff --git a/drivers/staging/lustre/lustre/llite/llite_capa.c b/drivers/staging/lustre/lustre/llite/llite_capa.c index edd512b20ee3a6..d06d0b1ab08afe 100644 --- a/drivers/staging/lustre/lustre/llite/llite_capa.c +++ b/drivers/staging/lustre/lustre/llite/llite_capa.c @@ -68,6 +68,8 @@ static unsigned long long ll_capa_renewal_noent = 0; static unsigned long long ll_capa_renewal_failed = 0; static unsigned long long ll_capa_renewal_retries = 0; +static int ll_update_capa(struct obd_capa *ocapa, struct lustre_capa *capa); + static inline void update_capa_timer(struct obd_capa *ocapa, cfs_time_t expiry) { if (cfs_time_before(expiry, ll_capa_timer.expires) || @@ -515,7 +517,7 @@ static inline void delay_capa_renew(struct obd_capa *oc, cfs_time_t delay) oc->c_expiry = cfs_time_add(oc->c_expiry, cfs_time_seconds(delay)); } -int ll_update_capa(struct obd_capa *ocapa, struct lustre_capa *capa) +static int ll_update_capa(struct obd_capa *ocapa, struct lustre_capa *capa) { struct inode *inode = ocapa->u.cli.inode; int rc = 0; diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 69aba0afca41b2..140ee947ba4949 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -71,10 +71,6 @@ #define LUSTRE_FPRIVATE(file) ((file)->private_data) struct ll_dentry_data { - int lld_cwd_count; - int lld_mnt_count; - struct obd_client_handle lld_cwd_och; - struct obd_client_handle lld_mnt_och; struct lookup_intent *lld_it; unsigned int lld_sa_generation; unsigned int lld_invalid:1; @@ -83,8 +79,6 @@ struct ll_dentry_data { #define ll_d2d(de) ((struct ll_dentry_data*)((de)->d_fsdata)) -extern struct file_operations ll_pgcache_seq_fops; - #define LLI_INODE_MAGIC 0x111d0de5 #define LLI_INODE_DEAD 0xdeadd00d @@ -120,16 +114,12 @@ enum lli_flags { /* Sizeon-on-MDS attributes are changed. An attribute update needs to * be sent to MDS. */ LLIF_SOM_DIRTY = (1 << 3), - /* File is contented */ - LLIF_CONTENDED = (1 << 4), - /* Truncate uses server lock for this file */ - LLIF_SRVLOCK = (1 << 5), /* File data is modified. */ - LLIF_DATA_MODIFIED = (1 << 6), + LLIF_DATA_MODIFIED = (1 << 4), /* File is being restored */ - LLIF_FILE_RESTORING = (1 << 7), + LLIF_FILE_RESTORING = (1 << 5), /* Xattr cache is attached to the file */ - LLIF_XATTR_CACHE = (1 << 8), + LLIF_XATTR_CACHE = (1 << 6), }; struct ll_inode_info { @@ -194,7 +184,6 @@ struct ll_inode_info { * cleanup the dir readahead. */ void *d_opendir_key; struct ll_statahead_info *d_sai; - struct posix_acl *d_def_acl; /* protect statahead stuff. */ spinlock_t d_sa_lock; /* "opendir_pid" is the token when lookup/revalid @@ -205,14 +194,12 @@ struct ll_inode_info { #define lli_readdir_mutex u.d.d_readdir_mutex #define lli_opendir_key u.d.d_opendir_key #define lli_sai u.d.d_sai -#define lli_def_acl u.d.d_def_acl #define lli_sa_lock u.d.d_sa_lock #define lli_opendir_pid u.d.d_opendir_pid /* for non-directory */ struct { - struct semaphore f_size_sem; - void *f_size_sem_owner; + struct mutex f_size_mutex; char *f_symlink_name; __u64 f_maxbytes; /* @@ -233,11 +220,6 @@ struct ll_inode_info { /* for writepage() only to communicate to fsync */ int f_async_rc; - /* volatile file criteria is based on file name, this - * flag is used to keep the test result, so the strcmp - * is done only once - */ - bool f_volatile; /* * whenever a process try to read/write the file, the * jobid of the process will be saved here, and it'll @@ -249,8 +231,7 @@ struct ll_inode_info { char f_jobid[JOBSTATS_JOBID_SIZE]; } f; -#define lli_size_sem u.f.f_size_sem -#define lli_size_sem_owner u.f.f_size_sem_owner +#define lli_size_mutex u.f.f_size_mutex #define lli_symlink_name u.f.f_symlink_name #define lli_maxbytes u.f.f_maxbytes #define lli_trunc_sem u.f.f_trunc_sem @@ -261,7 +242,6 @@ struct ll_inode_info { #define lli_agl_index u.f.f_agl_index #define lli_async_rc u.f.f_async_rc #define lli_jobid u.f.f_jobid -#define lli_volatile u.f.f_volatile } u; @@ -280,14 +260,33 @@ struct ll_inode_info { /* mutex to request for layout lock exclusively. */ struct mutex lli_layout_mutex; - /* valid only inside LAYOUT ibits lock, protected by lli_layout_mutex */ + /* Layout version, protected by lli_layout_lock */ __u32 lli_layout_gen; + spinlock_t lli_layout_lock; struct rw_semaphore lli_xattrs_list_rwsem; struct mutex lli_xattrs_enq_lock; struct list_head lli_xattrs;/* ll_xattr_entry->xe_list */ }; +static inline __u32 ll_layout_version_get(struct ll_inode_info *lli) +{ + __u32 gen; + + spin_lock(&lli->lli_layout_lock); + gen = lli->lli_layout_gen; + spin_unlock(&lli->lli_layout_lock); + + return gen; +} + +static inline void ll_layout_version_set(struct ll_inode_info *lli, __u32 gen) +{ + spin_lock(&lli->lli_layout_lock); + lli->lli_layout_gen = gen; + spin_unlock(&lli->lli_layout_lock); +} + int ll_xattr_cache_destroy(struct inode *inode); int ll_xattr_cache_get(struct inode *inode, @@ -300,7 +299,7 @@ int ll_xattr_cache_get(struct inode *inode, * Locking to guarantee consistency of non-atomic updates to long long i_size, * consistency between file size and KMS. * - * Implemented by ->lli_size_sem and ->lsm_lock, nested in that order. + * Implemented by ->lli_size_mutex and ->lsm_lock, nested in that order. */ void ll_inode_size_lock(struct inode *inode); @@ -442,10 +441,6 @@ enum stats_track_type { "xattr", \ } -/* default value for ll_sb_info->contention_time */ -#define SBI_DEFAULT_CONTENTION_SECONDS 60 -/* default value for lockless_truncate_enable */ -#define SBI_DEFAULT_LOCKLESS_TRUNCATE_ENABLE 1 #define RCE_HASHES 32 struct rmtacl_ctl_entry { @@ -656,12 +651,6 @@ static inline struct inode *ll_info2i(struct ll_inode_info *lli) return &lli->lli_vfs_inode; } -struct it_cb_data { - struct inode *icbd_parent; - struct dentry **icbd_childp; - obd_id hash; -}; - __u32 ll_i2suppgid(struct inode *i); void ll_i2gids(__u32 *suppgids, struct inode *i1,struct inode *i2); @@ -669,21 +658,13 @@ static inline int ll_need_32bit_api(struct ll_sb_info *sbi) { #if BITS_PER_LONG == 32 return 1; +#elif defined(CONFIG_COMPAT) + return unlikely(is_compat_task() || (sbi->ll_flags & LL_SBI_32BIT_API)); #else - return unlikely( -#ifdef CONFIG_COMPAT - is_compat_task() || -#endif - (sbi->ll_flags & LL_SBI_32BIT_API) - ); + return unlikely(sbi->ll_flags & LL_SBI_32BIT_API); #endif } -#define LLAP_MAGIC 98764321 - -extern struct kmem_cache *ll_async_page_slab; -extern size_t ll_async_page_slab_size; - void ll_ra_read_in(struct file *f, struct ll_ra_read *rar); void ll_ra_read_ex(struct file *f, struct ll_ra_read *rar); struct ll_ra_read *ll_ra_read_get(struct file *f); @@ -716,14 +697,16 @@ static inline void ll_rw_stats_tally(struct ll_sb_info *sbi, pid_t pid, /* llite/dir.c */ void ll_release_page(struct page *page, int remove); -extern struct file_operations ll_dir_operations; -extern struct inode_operations ll_dir_inode_operations; +extern const struct file_operations ll_dir_operations; +extern const struct inode_operations ll_dir_inode_operations; struct page *ll_get_dir_page(struct inode *dir, __u64 hash, struct ll_dir_chain *chain); int ll_dir_read(struct inode *inode, struct dir_context *ctx); int ll_get_mdt_idx(struct inode *inode); /* llite/namei.c */ +extern const struct inode_operations ll_special_inode_operations; + int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir); struct inode *ll_iget(struct super_block *sb, ino_t hash, @@ -738,43 +721,34 @@ int ll_prepare_write(struct file *, struct page *, unsigned from, unsigned to); int ll_commit_write(struct file *, struct page *, unsigned from, unsigned to); int ll_writepage(struct page *page, struct writeback_control *wbc); int ll_writepages(struct address_space *, struct writeback_control *wbc); -void ll_removepage(struct page *page); int ll_readpage(struct file *file, struct page *page); void ll_readahead_init(struct inode *inode, struct ll_readahead_state *ras); -int ll_file_punch(struct inode *, loff_t, int); -ssize_t ll_file_lockless_io(struct file *, char *, size_t, loff_t *, int); -void ll_clear_file_contended(struct inode*); -int ll_sync_page_range(struct inode *, struct address_space *, loff_t, size_t); int ll_readahead(const struct lu_env *env, struct cl_io *io, struct ll_readahead_state *ras, struct address_space *mapping, struct cl_page_list *queue, int flags); +#ifndef MS_HAS_NEW_AOPS +extern const struct address_space_operations ll_aops; +#else +extern const struct address_space_operations_ext ll_aops; +#endif + /* llite/file.c */ extern struct file_operations ll_file_operations; extern struct file_operations ll_file_operations_flock; extern struct file_operations ll_file_operations_noflock; extern struct inode_operations ll_file_inode_operations; -extern int ll_inode_revalidate_it(struct dentry *, struct lookup_intent *, - __u64); extern int ll_have_md_lock(struct inode *inode, __u64 *bits, ldlm_mode_t l_req_mode); extern ldlm_mode_t ll_take_md_lock(struct inode *inode, __u64 bits, struct lustre_handle *lockh, __u64 flags, ldlm_mode_t mode); -int __ll_inode_revalidate_it(struct dentry *, struct lookup_intent *, - __u64 bits); -int ll_revalidate_nd(struct dentry *dentry, unsigned int flags); int ll_file_open(struct inode *inode, struct file *file); int ll_file_release(struct inode *inode, struct file *file); int ll_glimpse_ioctl(struct ll_sb_info *sbi, struct lov_stripe_md *lsm, lstat_t *st); void ll_ioepoch_open(struct ll_inode_info *lli, __u64 ioepoch); -int ll_local_open(struct file *file, - struct lookup_intent *it, struct ll_file_data *fd, - struct obd_client_handle *och); int ll_release_openhandle(struct dentry *, struct lookup_intent *); -int ll_md_close(struct obd_export *md_exp, struct inode *inode, - struct file *file); int ll_md_real_close(struct inode *inode, fmode_t fmode); void ll_ioepoch_close(struct inode *inode, struct md_op_data *op_data, struct obd_client_handle **och, unsigned long flags); @@ -782,15 +756,10 @@ void ll_done_writing_attr(struct inode *inode, struct md_op_data *op_data); int ll_som_update(struct inode *inode, struct md_op_data *op_data); int ll_inode_getattr(struct inode *inode, struct obdo *obdo, __u64 ioepoch, int sync); -int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data, - struct md_open_data **mod); void ll_pack_inode2opdata(struct inode *inode, struct md_op_data *op_data, struct lustre_handle *fh); -int ll_getattr_it(struct vfsmount *mnt, struct dentry *de, - struct lookup_intent *it, struct kstat *stat); int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat); -struct ll_file_data *ll_file_data_get(void); -struct posix_acl * ll_get_acl(struct inode *inode, int type); +struct posix_acl *ll_get_acl(struct inode *inode, int type); int ll_inode_permission(struct inode *inode, int mask); @@ -805,44 +774,30 @@ int ll_dir_setstripe(struct inode *inode, struct lov_user_md *lump, int ll_dir_getstripe(struct inode *inode, struct lov_mds_md **lmmp, int *lmm_size, struct ptlrpc_request **request); int ll_fsync(struct file *file, loff_t start, loff_t end, int data); -int ll_do_fiemap(struct inode *inode, struct ll_user_fiemap *fiemap, - int num_bytes); int ll_merge_lvb(const struct lu_env *env, struct inode *inode); -int ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg); -int ll_put_grouplock(struct inode *inode, struct file *file, unsigned long arg); int ll_fid2path(struct inode *inode, void *arg); int ll_data_version(struct inode *inode, __u64 *data_version, int extent_lock); int ll_hsm_release(struct inode *inode); -struct obd_client_handle *ll_lease_open(struct inode *inode, struct file *file, - fmode_t mode, __u64 flags); -int ll_lease_close(struct obd_client_handle *och, struct inode *inode, - bool *lease_broken); - /* llite/dcache.c */ int ll_d_init(struct dentry *de); -extern struct dentry_operations ll_d_ops; +extern const struct dentry_operations ll_d_ops; void ll_intent_drop_lock(struct lookup_intent *); void ll_intent_release(struct lookup_intent *); void ll_invalidate_aliases(struct inode *); -void ll_frob_intent(struct lookup_intent **itp, struct lookup_intent *deft); void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry); -int ll_dcompare(const struct dentry *parent, const struct dentry *dentry, - unsigned int len, const char *str, const struct qstr *d_name); int ll_revalidate_it_finish(struct ptlrpc_request *request, struct lookup_intent *it, struct dentry *de); /* llite/llite_lib.c */ extern struct super_operations lustre_super_operations; -char *ll_read_opt(const char *opt, char *data); void ll_lli_init(struct ll_inode_info *lli); int ll_fill_super(struct super_block *sb, struct vfsmount *mnt); void ll_put_super(struct super_block *sb); void ll_kill_super(struct super_block *sb); struct inode *ll_inode_from_resource_lock(struct ldlm_lock *lock); -struct inode *ll_inode_from_lock(struct ldlm_lock *lock); void ll_clear_inode(struct inode *inode); int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import); int ll_setattr(struct dentry *de, struct iattr *attr); @@ -862,9 +817,11 @@ void ll_dirty_page_discard_warn(struct page *page, int ioret); int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, struct super_block *, struct lookup_intent *); void lustre_dump_dentry(struct dentry *, int recur); -void lustre_dump_inode(struct inode *); int ll_obd_statfs(struct inode *inode, void *arg); int ll_get_max_mdsize(struct ll_sb_info *sbi, int *max_mdsize); +int ll_get_default_mdsize(struct ll_sb_info *sbi, int *default_mdsize); +int ll_get_max_cookiesize(struct ll_sb_info *sbi, int *max_cookiesize); +int ll_get_default_cookiesize(struct ll_sb_info *sbi, int *default_cookiesize); int ll_process_config(struct lustre_cfg *lcfg); struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, struct inode *i1, struct inode *i2, @@ -881,15 +838,6 @@ void get_uuid2fsid(const char *name, int len, __kernel_fsid_t *fsid); struct inode *search_inode_for_lustre(struct super_block *sb, const struct lu_fid *fid); -/* llite/special.c */ -extern struct inode_operations ll_special_inode_operations; -extern struct file_operations ll_special_chr_inode_fops; -extern struct file_operations ll_special_chr_file_fops; -extern struct file_operations ll_special_blk_inode_fops; -extern struct file_operations ll_special_fifo_inode_fops; -extern struct file_operations ll_special_fifo_file_fops; -extern struct file_operations ll_special_sock_inode_fops; - /* llite/symlink.c */ extern struct inode_operations ll_fast_symlink_inode_operations; @@ -957,11 +905,6 @@ struct vvp_io { * Set when cui_bead has been initialized. */ int cui_ra_window_set; - /** - * Partially truncated page, that vvp_io_trunc_start() keeps locked - * across truncate. - */ - struct cl_page *cui_partpage; }; /** @@ -974,8 +917,7 @@ struct vvp_io_args { union { struct { struct kiocb *via_iocb; - struct iovec *via_iov; - unsigned long via_nrsegs; + struct iov_iter *via_iter; } normal; struct { struct pipe_inode_info *via_pipe; @@ -990,12 +932,9 @@ struct ll_cl_context { struct cl_page *lcc_page; struct lu_env *lcc_env; int lcc_refcheck; - int lcc_created; }; struct vvp_thread_info { - struct ost_lvb vti_lvb; - struct cl_2queue vti_queue; struct iovec vti_local_iov; struct vvp_io_args vti_args; struct ra_io_arg vti_ria; @@ -1042,25 +981,17 @@ static inline struct vvp_io *vvp_env_io(const struct lu_env *env) return &vvp_env_session(env)->vs_ios; } +int vvp_global_init(void); +void vvp_global_fini(void); + void ll_queue_done_writing(struct inode *inode, unsigned long flags); void ll_close_thread_shutdown(struct ll_close_queue *lcq); int ll_close_thread_start(struct ll_close_queue **lcq_ret); /* llite/llite_mmap.c */ -typedef struct rb_root rb_root_t; -typedef struct rb_node rb_node_t; - -struct ll_lock_tree_node; -struct ll_lock_tree { - rb_root_t lt_root; - struct list_head lt_locked_list; - struct ll_file_data *lt_fd; -}; int ll_teardown_mmaps(struct address_space *mapping, __u64 first, __u64 last); int ll_file_mmap(struct file * file, struct vm_area_struct * vma); -struct ll_lock_tree_node * ll_node_from_inode(struct inode *inode, __u64 start, - __u64 end, ldlm_mode_t mode); void policy_from_vma(ldlm_policy_data_t *policy, struct vm_area_struct *vma, unsigned long addr, size_t count); struct vm_area_struct *our_vma(struct mm_struct *mm, unsigned long addr, @@ -1127,11 +1058,6 @@ static inline struct lu_fid *ll_inode2fid(struct inode *inode) return fid; } -static inline int ll_mds_max_easize(struct super_block *sb) -{ - return sbi2mdc(ll_s2sbi(sb))->cl_max_mds_easize; -} - static inline __u64 ll_file_maxbytes(struct inode *inode) { return ll_i2info(inode)->lli_maxbytes; @@ -1149,7 +1075,6 @@ int ll_removexattr(struct dentry *dentry, const char *name); extern struct kmem_cache *ll_remote_perm_cachep; extern struct kmem_cache *ll_rmtperm_hash_cachep; -struct hlist_head *alloc_rmtperm_hash(void); void free_rmtperm_hash(struct hlist_head *hash); int ll_update_remote_perm(struct inode *inode, struct mdt_remote_perm *perm); int lustre_check_remote_perm(struct inode *inode, int mask); @@ -1162,7 +1087,6 @@ void ll_capa_thread_stop(void); void ll_capa_timer_callback(unsigned long unused); struct obd_capa *ll_add_capa(struct inode *inode, struct obd_capa *ocapa); -int ll_update_capa(struct obd_capa *ocapa, struct lustre_capa *capa); void ll_capa_open(struct inode *inode); void ll_capa_close(struct inode *inode); @@ -1182,14 +1106,12 @@ extern struct lu_device_type vvp_device_type; */ int cl_sb_init(struct super_block *sb); int cl_sb_fini(struct super_block *sb); -enum cl_lock_mode vvp_mode_from_vma(struct vm_area_struct *vma); void ll_io_init(struct cl_io *io, const struct file *file, int write); void ras_update(struct ll_sb_info *sbi, struct inode *inode, struct ll_readahead_state *ras, unsigned long index, unsigned hit); void ll_ra_count_put(struct ll_sb_info *sbi, unsigned long len); -int ll_is_file_contended(struct file *file); void ll_ra_stats_inc(struct address_space *mapping, enum ra_stat which); /* llite/llite_rmtacl.c */ @@ -1262,7 +1184,6 @@ struct ll_statahead_info { unsigned int sai_skip_hidden;/* skipped hidden dentry count */ unsigned int sai_ls_all:1, /* "ls -al", do stat-ahead for * hidden entries */ - sai_in_readpage:1,/* statahead is in readdir()*/ sai_agl_valid:1;/* AGL is valid for the dir */ wait_queue_head_t sai_waitq; /* stat-ahead wait queue */ struct ptlrpc_thread sai_thread; /* stat-ahead thread */ @@ -1387,9 +1308,6 @@ typedef enum llioc_iter (*llioc_callback_t)(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, void *magic, int *rcp); -enum llioc_iter ll_iocontrol_call(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int *rcp); - /* export functions */ /* Register ioctl block dynamatically for a regular file. * @@ -1431,7 +1349,7 @@ static inline void cl_isize_unlock(struct inode *inode) static inline void cl_isize_write_nolock(struct inode *inode, loff_t kms) { - LASSERT(down_trylock(&ll_i2info(inode)->lli_size_sem) != 0); + LASSERT(mutex_is_locked(&ll_i2info(inode)->lli_size_mutex)); i_size_write(inode, kms); } diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 7c4fd97a7fa050..7372986ac14592 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -58,14 +58,8 @@ struct kmem_cache *ll_file_data_slab; struct proc_dir_entry *proc_lustre_fs_root; -LIST_HEAD(ll_super_blocks); -DEFINE_SPINLOCK(ll_sb_lock); - -#ifndef MS_HAS_NEW_AOPS -extern struct address_space_operations ll_aops; -#else -extern struct address_space_operations_ext ll_aops; -#endif +static LIST_HEAD(ll_super_blocks); +static DEFINE_SPINLOCK(ll_sb_lock); #ifndef log2 #define log2(n) ffz(~(n)) @@ -143,7 +137,7 @@ static struct ll_sb_info *ll_init_sbi(void) return sbi; } -void ll_free_sbi(struct super_block *sb) +static void ll_free_sbi(struct super_block *sb) { struct ll_sb_info *sbi = ll_s2sbi(sb); @@ -634,7 +628,46 @@ int ll_get_max_mdsize(struct ll_sb_info *sbi, int *lmmsize) return rc; } -void ll_dump_inode(struct inode *inode) +int ll_get_default_mdsize(struct ll_sb_info *sbi, int *lmmsize) +{ + int size, rc; + + size = sizeof(int); + rc = obd_get_info(NULL, sbi->ll_md_exp, sizeof(KEY_DEFAULT_EASIZE), + KEY_DEFAULT_EASIZE, &size, lmmsize, NULL); + if (rc) + CERROR("Get default mdsize error rc %d\n", rc); + + return rc; +} + +int ll_get_max_cookiesize(struct ll_sb_info *sbi, int *lmmsize) +{ + int size, rc; + + size = sizeof(int); + rc = obd_get_info(NULL, sbi->ll_md_exp, sizeof(KEY_MAX_COOKIESIZE), + KEY_MAX_COOKIESIZE, &size, lmmsize, NULL); + if (rc) + CERROR("Get max cookiesize error rc %d\n", rc); + + return rc; +} + +int ll_get_default_cookiesize(struct ll_sb_info *sbi, int *lmmsize) +{ + int size, rc; + + size = sizeof(int); + rc = obd_get_info(NULL, sbi->ll_md_exp, sizeof(KEY_DEFAULT_COOKIESIZE), + KEY_DEFAULT_COOKIESIZE, &size, lmmsize, NULL); + if (rc) + CERROR("Get default cookiesize error rc %d\n", rc); + + return rc; +} + +static void ll_dump_inode(struct inode *inode) { struct ll_d_hlist_node *tmp; int dentry_count = 0; @@ -677,7 +710,7 @@ void lustre_dump_dentry(struct dentry *dentry, int recur) } } -void client_common_put_super(struct super_block *sb) +static void client_common_put_super(struct super_block *sb) { struct ll_sb_info *sbi = ll_s2sbi(sb); @@ -726,30 +759,6 @@ void ll_kill_super(struct super_block *sb) } } -char *ll_read_opt(const char *opt, char *data) -{ - char *value; - char *retval; - - CDEBUG(D_SUPER, "option: %s, data %s\n", opt, data); - if (strncmp(opt, data, strlen(opt))) - return NULL; - value = strchr(data, '='); - if (value == NULL) - return NULL; - - value++; - OBD_ALLOC(retval, strlen(value) + 1); - if (!retval) { - CERROR("out of memory!\n"); - return NULL; - } - - memcpy(retval, value, strlen(value)+1); - CDEBUG(D_SUPER, "Assigned option: %s, value %s\n", opt, retval); - return retval; -} - static inline int ll_set_opt(const char *opt, char *data, int fl) { if (strncmp(opt, data, strlen(opt)) != 0) @@ -927,7 +936,8 @@ void ll_lli_init(struct ll_inode_info *lli) mutex_init(&lli->lli_och_mutex); spin_lock_init(&lli->lli_agl_lock); lli->lli_has_smd = false; - lli->lli_layout_gen = LL_LAYOUT_GEN_NONE; + spin_lock_init(&lli->lli_layout_lock); + ll_layout_version_set(lli, LL_LAYOUT_GEN_NONE); lli->lli_clob = NULL; init_rwsem(&lli->lli_xattrs_list_rwsem); @@ -938,12 +948,10 @@ void ll_lli_init(struct ll_inode_info *lli) mutex_init(&lli->lli_readdir_mutex); lli->lli_opendir_key = NULL; lli->lli_sai = NULL; - lli->lli_def_acl = NULL; spin_lock_init(&lli->lli_sa_lock); lli->lli_opendir_pid = 0; } else { - sema_init(&lli->lli_size_sem, 1); - lli->lli_size_sem_owner = NULL; + mutex_init(&lli->lli_size_mutex); lli->lli_symlink_name = NULL; init_rwsem(&lli->lli_trunc_sem); mutex_init(&lli->lli_write_mutex); @@ -952,7 +960,6 @@ void ll_lli_init(struct ll_inode_info *lli) INIT_LIST_HEAD(&lli->lli_agl_list); lli->lli_agl_index = 0; lli->lli_async_rc = 0; - lli->lli_volatile = false; } mutex_init(&lli->lli_layout_mutex); } @@ -1151,28 +1158,6 @@ struct inode *ll_inode_from_resource_lock(struct ldlm_lock *lock) return inode; } -struct inode *ll_inode_from_lock(struct ldlm_lock *lock) -{ - struct inode *inode = NULL; - /* NOTE: we depend on atomic igrab() -bzzz */ - lock_res_and_lock(lock); - if (lock->l_ast_data) { - struct ll_inode_info *lli = ll_i2info(lock->l_ast_data); - if (lli->lli_inode_magic == LLI_INODE_MAGIC) { - inode = igrab(lock->l_ast_data); - } else { - inode = lock->l_ast_data; - LDLM_DEBUG_LIMIT(inode->i_state & I_FREEING ? D_INFO : - D_WARNING, lock, "l_ast_data %p is " - "bogus: magic %08x", lock->l_ast_data, - lli->lli_inode_magic); - inode = NULL; - } - } - unlock_res_and_lock(lock); - return inode; -} - void ll_clear_inode(struct inode *inode) { struct ll_inode_info *lli = ll_i2info(inode); @@ -1449,7 +1434,6 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import) if (attr->ia_valid & ATTR_SIZE) inode_dio_write_done(inode); mutex_unlock(&inode->i_mutex); - down_write(&lli->lli_trunc_sem); } memcpy(&op_data->op_attr, attr, sizeof(*attr)); @@ -1513,7 +1497,11 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import) * excessive to send mtime/atime updates to OSTs when not * setting times to past, but it is necessary due to possible * time de-synchronization between MDT inode and OST objects */ + if (attr->ia_valid & ATTR_SIZE) + down_write(&lli->lli_trunc_sem); rc = ll_setattr_ost(inode, attr); + if (attr->ia_valid & ATTR_SIZE) + up_write(&lli->lli_trunc_sem); out: if (op_data) { if (op_data->op_ioepoch) { @@ -1524,7 +1512,6 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import) ll_finish_md_op_data(op_data); } if (!S_ISDIR(inode->i_mode)) { - up_write(&lli->lli_trunc_sem); mutex_lock(&inode->i_mutex); if ((attr->ia_valid & ATTR_SIZE) && !hsm_import) inode_dio_wait(inode); @@ -1658,10 +1645,7 @@ void ll_inode_size_lock(struct inode *inode) LASSERT(!S_ISDIR(inode->i_mode)); lli = ll_i2info(inode); - LASSERT(lli->lli_size_sem_owner != current); - down(&lli->lli_size_sem); - LASSERT(lli->lli_size_sem_owner == NULL); - lli->lli_size_sem_owner = current; + mutex_lock(&lli->lli_size_mutex); } void ll_inode_size_unlock(struct inode *inode) @@ -1669,9 +1653,7 @@ void ll_inode_size_unlock(struct inode *inode) struct ll_inode_info *lli; lli = ll_i2info(inode); - LASSERT(lli->lli_size_sem_owner == current); - lli->lli_size_sem_owner = NULL; - up(&lli->lli_size_sem); + mutex_unlock(&lli->lli_size_mutex); } void ll_update_inode(struct inode *inode, struct lustre_md *md) @@ -2420,11 +2402,12 @@ void ll_dirty_page_discard_warn(struct page *page, int ioret) path = ll_d_path(dentry, buf, PAGE_SIZE); } - CWARN("%s: dirty page discard: %s/fid: "DFID"/%s may get corrupted " - "(rc %d)\n", ll_get_fsname(page->mapping->host->i_sb, NULL, 0), - s2lsi(page->mapping->host->i_sb)->lsi_lmd->lmd_dev, - PFID(&obj->cob_header.coh_lu.loh_fid), - (path && !IS_ERR(path)) ? path : "", ioret); + CDEBUG(D_WARNING, + "%s: dirty page discard: %s/fid: "DFID"/%s may get corrupted " + "(rc %d)\n", ll_get_fsname(page->mapping->host->i_sb, NULL, 0), + s2lsi(page->mapping->host->i_sb)->lsi_lmd->lmd_dev, + PFID(&obj->cob_header.coh_lu.loh_fid), + (path && !IS_ERR(path)) ? path : "", ioret); if (dentry != NULL) dput(dentry); diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c index 90b2c0d275f9e1..426c739616653f 100644 --- a/drivers/staging/lustre/lustre/llite/llite_mmap.c +++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c @@ -51,10 +51,7 @@ #include "llite_internal.h" #include -struct page *ll_nopage(struct vm_area_struct *vma, unsigned long address, - int *type); - -static struct vm_operations_struct ll_file_vm_ops; +static const struct vm_operations_struct ll_file_vm_ops; void policy_from_vma(ldlm_policy_data_t *policy, struct vm_area_struct *vma, unsigned long addr, @@ -97,10 +94,10 @@ struct vm_area_struct *our_vma(struct mm_struct *mm, unsigned long addr, * \retval EINVAL if env can't allocated * \return other error codes from cl_io_init. */ -struct cl_io *ll_fault_io_init(struct vm_area_struct *vma, - struct lu_env **env_ret, - struct cl_env_nest *nest, - pgoff_t index, unsigned long *ra_flags) +static struct cl_io * +ll_fault_io_init(struct vm_area_struct *vma, struct lu_env **env_ret, + struct cl_env_nest *nest, pgoff_t index, + unsigned long *ra_flags) { struct file *file = vma->vm_file; struct inode *inode = file->f_dentry->d_inode; @@ -446,14 +443,6 @@ static void ll_vm_close(struct vm_area_struct *vma) LASSERT(atomic_read(&vob->cob_mmap_cnt) >= 0); } - -/* return the user space pointer that maps to a file offset via a vma */ -static inline unsigned long file_to_user(struct vm_area_struct *vma, __u64 byte) -{ - return vma->vm_start + (byte - ((__u64)vma->vm_pgoff << PAGE_CACHE_SHIFT)); - -} - /* XXX put nice comment here. talk about __free_pte -> dirty pages and * nopage's reference passing to the pte */ int ll_teardown_mmaps(struct address_space *mapping, __u64 first, __u64 last) @@ -470,7 +459,7 @@ int ll_teardown_mmaps(struct address_space *mapping, __u64 first, __u64 last) return rc; } -static struct vm_operations_struct ll_file_vm_ops = { +static const struct vm_operations_struct ll_file_vm_ops = { .fault = ll_fault, .page_mkwrite = ll_page_mkwrite, .open = ll_vm_open, diff --git a/drivers/staging/lustre/lustre/llite/llite_nfs.c b/drivers/staging/lustre/lustre/llite/llite_nfs.c index 3580069789fc1e..e0e112b710d72a 100644 --- a/drivers/staging/lustre/lustre/llite/llite_nfs.c +++ b/drivers/staging/lustre/lustre/llite/llite_nfs.c @@ -98,7 +98,7 @@ struct inode *search_inode_for_lustre(struct super_block *sb, if (inode) return inode; - rc = ll_get_max_mdsize(sbi, &eadatalen); + rc = ll_get_default_mdsize(sbi, &eadatalen); if (rc) return ERR_PTR(rc); @@ -290,7 +290,7 @@ static struct dentry *ll_get_parent(struct dentry *dchild) CDEBUG(D_INFO, "getting parent for (%lu,"DFID")\n", dir->i_ino, PFID(ll_inode2fid(dir))); - rc = ll_get_max_mdsize(sbi, &lmmsize); + rc = ll_get_default_mdsize(sbi, &lmmsize); if (rc != 0) return ERR_PTR(rc); diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c index f78eda235c7ab4..0ff8c3362a8d46 100644 --- a/drivers/staging/lustre/lustre/llite/lloop.c +++ b/drivers/staging/lustre/lustre/llite/lloop.c @@ -122,9 +122,6 @@ struct lloop_device { loff_t lo_offset; loff_t lo_sizelimit; int lo_flags; - int (*ioctl)(struct lloop_device *, int cmd, - unsigned long arg); - struct file *lo_backing_file; struct block_device *lo_device; unsigned lo_blocksize; @@ -407,7 +404,7 @@ static int loop_thread(void *data) int refcheck; int ret = 0; - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); lo->lo_state = LLOOP_BOUND; @@ -509,7 +506,6 @@ static int loop_set_fd(struct lloop_device *lo, struct file *unused, lo->lo_device = bdev; lo->lo_flags = lo_flags; lo->lo_backing_file = file; - lo->ioctl = NULL; lo->lo_sizelimit = 0; lo->old_gfp_mask = mapping_gfp_mask(mapping); mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); @@ -568,7 +564,6 @@ static int loop_clr_fd(struct lloop_device *lo, struct block_device *bdev, down(&lo->lo_sem); lo->lo_backing_file = NULL; - lo->ioctl = NULL; lo->lo_device = NULL; lo->lo_offset = 0; lo->lo_sizelimit = 0; @@ -624,7 +619,10 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, case LL_IOC_LLOOP_INFO: { struct lu_fid fid; - LASSERT(lo->lo_backing_file != NULL); + if (lo->lo_backing_file == NULL) { + err = -ENOENT; + break; + } if (inode == NULL) inode = lo->lo_backing_file->f_dentry->d_inode; if (lo->lo_state == LLOOP_BOUND) diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c index a9a104a6a4ee16..77ee9e58cf87c7 100644 --- a/drivers/staging/lustre/lustre/llite/lproc_llite.c +++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c @@ -41,12 +41,12 @@ #include #include "llite_internal.h" +#include "vvp_internal.h" /* /proc/lustre/llite mount point registration */ -extern struct file_operations vvp_dump_pgcache_file_ops; -struct file_operations ll_rw_extents_stats_fops; -struct file_operations ll_rw_extents_stats_pp_fops; -struct file_operations ll_rw_offset_stats_fops; +static struct file_operations ll_rw_extents_stats_fops; +static struct file_operations ll_rw_extents_stats_pp_fops; +static struct file_operations ll_rw_offset_stats_fops; static int ll_blksize_seq_show(struct seq_file *m, void *v) { @@ -367,8 +367,9 @@ static int ll_max_cached_mb_seq_show(struct seq_file *m, void *v) cache->ccc_lru_shrinkers); } -static ssize_t ll_max_cached_mb_seq_write(struct file *file, const char *buffer, - size_t count, loff_t *off) +static ssize_t ll_max_cached_mb_seq_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *off) { struct super_block *sb = ((struct seq_file *)file->private_data)->private; struct ll_sb_info *sbi = ll_s2sbi(sb); @@ -376,9 +377,18 @@ static ssize_t ll_max_cached_mb_seq_write(struct file *file, const char *buffer, int mult, rc, pages_number; int diff = 0; int nrpages = 0; + char kernbuf[128]; + + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; mult = 1 << (20 - PAGE_CACHE_SHIFT); - buffer = lprocfs_find_named_value(buffer, "max_cached_mb:", &count); + buffer += lprocfs_find_named_value(kernbuf, "max_cached_mb:", &count) - + kernbuf; rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult); if (rc) return rc; @@ -681,7 +691,7 @@ static ssize_t ll_lazystatfs_seq_write(struct file *file, const char *buffer, } LPROC_SEQ_FOPS(ll_lazystatfs); -static int ll_maxea_size_seq_show(struct seq_file *m, void *v) +static int ll_max_easize_seq_show(struct seq_file *m, void *v) { struct super_block *sb = m->private; struct ll_sb_info *sbi = ll_s2sbi(sb); @@ -694,7 +704,52 @@ static int ll_maxea_size_seq_show(struct seq_file *m, void *v) return seq_printf(m, "%u\n", ealen); } -LPROC_SEQ_FOPS_RO(ll_maxea_size); +LPROC_SEQ_FOPS_RO(ll_max_easize); + +static int ll_defult_easize_seq_show(struct seq_file *m, void *v) +{ + struct super_block *sb = m->private; + struct ll_sb_info *sbi = ll_s2sbi(sb); + unsigned int ealen; + int rc; + + rc = ll_get_default_mdsize(sbi, &ealen); + if (rc) + return rc; + + return seq_printf(m, "%u\n", ealen); +} +LPROC_SEQ_FOPS_RO(ll_defult_easize); + +static int ll_max_cookiesize_seq_show(struct seq_file *m, void *v) +{ + struct super_block *sb = m->private; + struct ll_sb_info *sbi = ll_s2sbi(sb); + unsigned int cookielen; + int rc; + + rc = ll_get_max_cookiesize(sbi, &cookielen); + if (rc) + return rc; + + return seq_printf(m, "%u\n", cookielen); +} +LPROC_SEQ_FOPS_RO(ll_max_cookiesize); + +static int ll_defult_cookiesize_seq_show(struct seq_file *m, void *v) +{ + struct super_block *sb = m->private; + struct ll_sb_info *sbi = ll_s2sbi(sb); + unsigned int cookielen; + int rc; + + rc = ll_get_default_cookiesize(sbi, &cookielen); + if (rc) + return rc; + + return seq_printf(m, "%u\n", cookielen); +} +LPROC_SEQ_FOPS_RO(ll_defult_cookiesize); static int ll_sbi_flags_seq_show(struct seq_file *m, void *v) { @@ -781,7 +836,10 @@ static struct lprocfs_vars lprocfs_llite_obd_vars[] = { { "statahead_agl", &ll_statahead_agl_fops, 0 }, { "statahead_stats", &ll_statahead_stats_fops, 0, 0 }, { "lazystatfs", &ll_lazystatfs_fops, 0 }, - { "max_easize", &ll_maxea_size_fops, 0, 0 }, + { "max_easize", &ll_max_easize_fops, 0, 0 }, + { "default_easize", &ll_defult_easize_fops, 0, 0 }, + { "max_cookiesize", &ll_max_cookiesize_fops, 0, 0 }, + { "default_cookiesize", &ll_defult_cookiesize_fops, 0, 0 }, { "sbi_flags", &ll_sbi_flags_fops, 0, 0 }, { "xattr_cache", &ll_xattr_cache_fops, 0, 0 }, { 0 } @@ -789,7 +847,7 @@ static struct lprocfs_vars lprocfs_llite_obd_vars[] = { #define MAX_STRING_SIZE 128 -struct llite_file_opcode { +static const struct llite_file_opcode { __u32 opcode; __u32 type; const char *opname; @@ -1115,7 +1173,8 @@ static int ll_rw_extents_stats_pp_seq_show(struct seq_file *seq, void *v) } static ssize_t ll_rw_extents_stats_pp_seq_write(struct file *file, - const char *buf, size_t len, + const char __user *buf, + size_t len, loff_t *off) { struct seq_file *seq = file->private_data; @@ -1124,10 +1183,24 @@ static ssize_t ll_rw_extents_stats_pp_seq_write(struct file *file, int i; int value = 1, rc = 0; + if (len == 0) + return -EINVAL; + rc = lprocfs_write_helper(buf, len, &value); - if (rc < 0 && (strcmp(buf, "disabled") == 0 || - strcmp(buf, "Disabled") == 0)) - value = 0; + if (rc < 0 && len < 16) { + char kernbuf[16]; + + if (copy_from_user(kernbuf, buf, len)) + return -EFAULT; + kernbuf[len] = 0; + + if (kernbuf[len - 1] == '\n') + kernbuf[len - 1] = 0; + + if (strcmp(kernbuf, "disabled") == 0 || + strcmp(kernbuf, "Disabled") == 0) + value = 0; + } if (value == 0) sbi->ll_rw_stats_on = 0; @@ -1174,8 +1247,9 @@ static int ll_rw_extents_stats_seq_show(struct seq_file *seq, void *v) return 0; } -static ssize_t ll_rw_extents_stats_seq_write(struct file *file, const char *buf, - size_t len, loff_t *off) +static ssize_t ll_rw_extents_stats_seq_write(struct file *file, + const char __user *buf, + size_t len, loff_t *off) { struct seq_file *seq = file->private_data; struct ll_sb_info *sbi = seq->private; @@ -1183,15 +1257,30 @@ static ssize_t ll_rw_extents_stats_seq_write(struct file *file, const char *buf, int i; int value = 1, rc = 0; + if (len == 0) + return -EINVAL; + rc = lprocfs_write_helper(buf, len, &value); - if (rc < 0 && (strcmp(buf, "disabled") == 0 || - strcmp(buf, "Disabled") == 0)) - value = 0; + if (rc < 0 && len < 16) { + char kernbuf[16]; + + if (copy_from_user(kernbuf, buf, len)) + return -EFAULT; + kernbuf[len] = 0; + + if (kernbuf[len - 1] == '\n') + kernbuf[len - 1] = 0; + + if (strcmp(kernbuf, "disabled") == 0 || + strcmp(kernbuf, "Disabled") == 0) + value = 0; + } if (value == 0) sbi->ll_rw_stats_on = 0; else sbi->ll_rw_stats_on = 1; + spin_lock(&sbi->ll_pp_extent_lock); for (i = 0; i <= LL_PROCESS_HIST_MAX; i++) { io_extents->pp_extents[i].pid = 0; @@ -1202,7 +1291,6 @@ static ssize_t ll_rw_extents_stats_seq_write(struct file *file, const char *buf, return len; } - LPROC_SEQ_FOPS(ll_rw_extents_stats); void ll_rw_stats_tally(struct ll_sb_info *sbi, pid_t pid, @@ -1362,8 +1450,9 @@ static int ll_rw_offset_stats_seq_show(struct seq_file *seq, void *v) return 0; } -static ssize_t ll_rw_offset_stats_seq_write(struct file *file, const char *buf, - size_t len, loff_t *off) +static ssize_t ll_rw_offset_stats_seq_write(struct file *file, + const char __user *buf, + size_t len, loff_t *off) { struct seq_file *seq = file->private_data; struct ll_sb_info *sbi = seq->private; @@ -1371,11 +1460,25 @@ static ssize_t ll_rw_offset_stats_seq_write(struct file *file, const char *buf, struct ll_rw_process_info *offset_info = sbi->ll_rw_offset_info; int value = 1, rc = 0; + if (len == 0) + return -EINVAL; + rc = lprocfs_write_helper(buf, len, &value); - if (rc < 0 && (strcmp(buf, "disabled") == 0 || - strcmp(buf, "Disabled") == 0)) - value = 0; + if (rc < 0 && len < 16) { + char kernbuf[16]; + + if (copy_from_user(kernbuf, buf, len)) + return -EFAULT; + kernbuf[len] = 0; + + if (kernbuf[len - 1] == '\n') + kernbuf[len - 1] = 0; + + if (strcmp(kernbuf, "disabled") == 0 || + strcmp(kernbuf, "Disabled") == 0) + value = 0; + } if (value == 0) sbi->ll_rw_stats_on = 0; diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 25a6ea580f000f..dfa1e745dfd684 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -75,14 +75,6 @@ static int ll_d_mountpoint(struct dentry *dparent, struct dentry *dchild, return mounted; } -int ll_unlock(__u32 mode, struct lustre_handle *lockh) -{ - ldlm_lock_decref(lockh, mode); - - return 0; -} - - /* called from iget5_locked->find_inode() under inode_hash_lock spinlock */ static int ll_test_inode(struct inode *inode, void *opaque) { @@ -433,12 +425,10 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de) return de; } -int ll_lookup_it_finish(struct ptlrpc_request *request, - struct lookup_intent *it, void *data) +static int ll_lookup_it_finish(struct ptlrpc_request *request, + struct lookup_intent *it, + struct inode *parent, struct dentry **de) { - struct it_cb_data *icbd = data; - struct dentry **de = icbd->icbd_childp; - struct inode *parent = icbd->icbd_parent; struct inode *inode = NULL; __u64 bits = 0; int rc; @@ -513,7 +503,6 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, struct dentry *save = dentry, *retval; struct ptlrpc_request *req = NULL; struct md_op_data *op_data; - struct it_cb_data icbd; __u32 opc; int rc; @@ -527,7 +516,8 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, if (d_mountpoint(dentry)) CERROR("Tell Peter, lookup on mtpt, it %s\n", LL_IT2STR(it)); - ll_frob_intent(&it, &lookup_it); + if (it == NULL || it->it_op == IT_GETXATTR) + it = &lookup_it; if (it->it_op == IT_GETATTR) { rc = ll_statahead_enter(parent, &dentry, 0); @@ -538,9 +528,6 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, } } - icbd.icbd_childp = &dentry; - icbd.icbd_parent = parent; - if (it->it_op & IT_CREAT) opc = LUSTRE_OPC_CREATE; else @@ -562,7 +549,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, if (rc < 0) GOTO(out, retval = ERR_PTR(rc)); - rc = ll_lookup_it_finish(req, it, &icbd); + rc = ll_lookup_it_finish(req, it, parent, &dentry); if (rc != 0) { ll_intent_release(it); GOTO(out, retval = ERR_PTR(rc)); @@ -697,10 +684,7 @@ static int ll_atomic_open(struct inode *dir, struct dentry *dentry, /* We depend on "mode" being set with the proper file type/umask by now */ -static struct inode *ll_create_node(struct inode *dir, const char *name, - int namelen, const void *data, int datalen, - int mode, __u64 extra, - struct lookup_intent *it) +static struct inode *ll_create_node(struct inode *dir, struct lookup_intent *it) { struct inode *inode = NULL; struct ptlrpc_request *request = NULL; @@ -757,14 +741,10 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry, int mode, if (rc) return rc; - inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len, - NULL, 0, mode, 0, it); + inode = ll_create_node(dir, it); if (IS_ERR(inode)) return PTR_ERR(inode); - if (filename_is_volatile(dentry->d_name.name, dentry->d_name.len, NULL)) - ll_i2info(inode)->lli_volatile = true; - d_instantiate(dentry, inode); return 0; } @@ -1238,7 +1218,7 @@ static int ll_rename(struct inode *old_dir, struct dentry *old_dentry, return err; } -struct inode_operations ll_dir_inode_operations = { +const struct inode_operations ll_dir_inode_operations = { .mknod = ll_mknod, .atomic_open = ll_atomic_open, .lookup = ll_lookup_nd, @@ -1260,7 +1240,7 @@ struct inode_operations ll_dir_inode_operations = { .get_acl = ll_get_acl, }; -struct inode_operations ll_special_inode_operations = { +const struct inode_operations ll_special_inode_operations = { .setattr = ll_setattr, .getattr = ll_getattr, .permission = ll_inode_permission, diff --git a/drivers/staging/lustre/lustre/llite/remote_perm.c b/drivers/staging/lustre/lustre/llite/remote_perm.c index dedd56ae1e6d52..a8b1117b8f6012 100644 --- a/drivers/staging/lustre/lustre/llite/remote_perm.c +++ b/drivers/staging/lustre/lustre/llite/remote_perm.c @@ -77,7 +77,7 @@ static inline void free_ll_remote_perm(struct ll_remote_perm *lrp) OBD_SLAB_FREE(lrp, ll_remote_perm_cachep, sizeof(*lrp)); } -struct hlist_head *alloc_rmtperm_hash(void) +static struct hlist_head *alloc_rmtperm_hash(void) { struct hlist_head *hash; int i; diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c index 416f7a094a6d2f..56162103cc79c2 100644 --- a/drivers/staging/lustre/lustre/llite/rw.c +++ b/drivers/staging/lustre/lustre/llite/rw.c @@ -77,12 +77,6 @@ static void ll_cl_fini(struct ll_cl_context *lcc) cl_page_put(env, page); } - if (io && lcc->lcc_created) { - cl_io_end(env, io); - cl_io_unlock(env, io); - cl_io_iter_fini(env, io); - cl_io_fini(env, io); - } cl_env_put(env, &lcc->lcc_refcheck); } @@ -157,8 +151,7 @@ static struct ll_cl_context *ll_cl_init(struct file *file, result = cl_io_rw_init(env, io, CIT_WRITE, pos, PAGE_CACHE_SIZE); if (result == 0) { cio->cui_fd = LUSTRE_FPRIVATE(file); - cio->cui_iov = NULL; - cio->cui_nrsegs = 0; + cio->cui_iter = NULL; result = cl_io_iter_init(env, io); if (result == 0) { result = cl_io_lock(env, io); @@ -167,7 +160,6 @@ static struct ll_cl_context *ll_cl_init(struct file *file, } } else result = io->ci_result; - lcc->lcc_created = 1; } lcc->lcc_io = io; diff --git a/drivers/staging/lustre/lustre/llite/rw26.c b/drivers/staging/lustre/lustre/llite/rw26.c index 7e3e0967993b5f..af84c1aaa5f83f 100644 --- a/drivers/staging/lustre/lustre/llite/rw26.c +++ b/drivers/staging/lustre/lustre/llite/rw26.c @@ -218,14 +218,11 @@ static void ll_free_user_pages(struct page **pages, int npages, int do_dirty) int i; for (i = 0; i < npages; i++) { - if (pages[i] == NULL) - break; if (do_dirty) set_page_dirty_lock(pages[i]); page_cache_release(pages[i]); } - - OBD_FREE_LARGE(pages, npages * sizeof(*pages)); + kvfree(pages); } ssize_t ll_direct_rw_pages(const struct lu_env *env, struct cl_io *io, @@ -363,18 +360,16 @@ static ssize_t ll_direct_IO_26_seg(const struct lu_env *env, struct cl_io *io, #define MAX_DIO_SIZE ((MAX_MALLOC / sizeof(struct brw_page) * PAGE_CACHE_SIZE) & \ ~(DT_MAX_BRW_SIZE - 1)) static ssize_t ll_direct_IO_26(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t file_offset, - unsigned long nr_segs) + struct iov_iter *iter, loff_t file_offset) { struct lu_env *env; struct cl_io *io; struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; struct ccc_object *obj = cl_inode2ccc(inode); - long count = iov_length(iov, nr_segs); - long tot_bytes = 0, result = 0; + ssize_t count = iov_iter_count(iter); + ssize_t tot_bytes = 0, result = 0; struct ll_inode_info *lli = ll_i2info(inode); - unsigned long seg = 0; long size = MAX_DIO_SIZE; int refcheck; @@ -385,18 +380,15 @@ static ssize_t ll_direct_IO_26(int rw, struct kiocb *iocb, if ((file_offset & ~CFS_PAGE_MASK) || (count & ~CFS_PAGE_MASK)) return -EINVAL; - CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), size=%lu (max %lu), " - "offset=%lld=%llx, pages %lu (max %lu)\n", + CDEBUG(D_VFSTRACE, + "VFS Op:inode=%lu/%u(%p), size=%zd (max %lu), offset=%lld=%llx, pages %zd (max %lu)\n", inode->i_ino, inode->i_generation, inode, count, MAX_DIO_SIZE, file_offset, file_offset, count >> PAGE_CACHE_SHIFT, MAX_DIO_SIZE >> PAGE_CACHE_SHIFT); /* Check that all user buffers are aligned as well */ - for (seg = 0; seg < nr_segs; seg++) { - if (((unsigned long)iov[seg].iov_base & ~CFS_PAGE_MASK) || - (iov[seg].iov_len & ~CFS_PAGE_MASK)) - return -EINVAL; - } + if (iov_iter_alignment(iter) & ~CFS_PAGE_MASK) + return -EINVAL; env = cl_env_get(&refcheck); LASSERT(!IS_ERR(env)); @@ -411,63 +403,49 @@ static ssize_t ll_direct_IO_26(int rw, struct kiocb *iocb, mutex_lock(&inode->i_mutex); LASSERT(obj->cob_transient_pages == 0); - for (seg = 0; seg < nr_segs; seg++) { - long iov_left = iov[seg].iov_len; - unsigned long user_addr = (unsigned long)iov[seg].iov_base; + while (iov_iter_count(iter)) { + struct page **pages; + size_t offs; + count = min_t(size_t, iov_iter_count(iter), size); if (rw == READ) { if (file_offset >= i_size_read(inode)) break; - if (file_offset + iov_left > i_size_read(inode)) - iov_left = i_size_read(inode) - file_offset; + if (file_offset + count > i_size_read(inode)) + count = i_size_read(inode) - file_offset; } - while (iov_left > 0) { - struct page **pages; - int page_count, max_pages = 0; - long bytes; - - bytes = min(size, iov_left); - page_count = ll_get_user_pages(rw, user_addr, bytes, - &pages, &max_pages); - if (likely(page_count > 0)) { - if (unlikely(page_count < max_pages)) - bytes = page_count << PAGE_CACHE_SHIFT; - result = ll_direct_IO_26_seg(env, io, rw, inode, - file->f_mapping, - bytes, file_offset, - pages, page_count); - ll_free_user_pages(pages, max_pages, rw==READ); - } else if (page_count == 0) { - GOTO(out, result = -EFAULT); - } else { - result = page_count; - } - if (unlikely(result <= 0)) { - /* If we can't allocate a large enough buffer - * for the request, shrink it to a smaller - * PAGE_SIZE multiple and try again. - * We should always be able to kmalloc for a - * page worth of page pointers = 4MB on i386. */ - if (result == -ENOMEM && - size > (PAGE_CACHE_SIZE / sizeof(*pages)) * - PAGE_CACHE_SIZE) { - size = ((((size / 2) - 1) | - ~CFS_PAGE_MASK) + 1) & - CFS_PAGE_MASK; - CDEBUG(D_VFSTRACE,"DIO size now %lu\n", - size); - continue; - } - - GOTO(out, result); + result = iov_iter_get_pages_alloc(iter, &pages, count, &offs); + if (likely(result > 0)) { + int n = (result + offs + PAGE_SIZE - 1) / PAGE_SIZE; + result = ll_direct_IO_26_seg(env, io, rw, inode, + file->f_mapping, + result, file_offset, + pages, n); + ll_free_user_pages(pages, n, rw==READ); + } + if (unlikely(result <= 0)) { + /* If we can't allocate a large enough buffer + * for the request, shrink it to a smaller + * PAGE_SIZE multiple and try again. + * We should always be able to kmalloc for a + * page worth of page pointers = 4MB on i386. */ + if (result == -ENOMEM && + size > (PAGE_CACHE_SIZE / sizeof(*pages)) * + PAGE_CACHE_SIZE) { + size = ((((size / 2) - 1) | + ~CFS_PAGE_MASK) + 1) & + CFS_PAGE_MASK; + CDEBUG(D_VFSTRACE,"DIO size now %lu\n", + size); + continue; } - tot_bytes += result; - file_offset += result; - iov_left -= result; - user_addr += result; + GOTO(out, result); } + iov_iter_advance(iter, result); + tot_bytes += result; + file_offset += result; } out: LASSERT(obj->cob_transient_pages == 0); @@ -529,9 +507,9 @@ static int ll_write_end(struct file *file, struct address_space *mapping, } #ifdef CONFIG_MIGRATION -int ll_migratepage(struct address_space *mapping, - struct page *newpage, struct page *page - , enum migrate_mode mode +static int ll_migratepage(struct address_space *mapping, + struct page *newpage, struct page *page, + enum migrate_mode mode ) { /* Always fail page migration until we have a proper implementation */ @@ -540,9 +518,8 @@ int ll_migratepage(struct address_space *mapping, #endif #ifndef MS_HAS_NEW_AOPS -struct address_space_operations ll_aops = { - .readpage = ll_readpage, -// .readpages = ll_readpages, +const struct address_space_operations ll_aops = { + .readpage = ll_readpage, .direct_IO = ll_direct_IO_26, .writepage = ll_writepage, .writepages = ll_writepages, @@ -554,10 +531,9 @@ struct address_space_operations ll_aops = { #ifdef CONFIG_MIGRATION .migratepage = ll_migratepage, #endif - .bmap = NULL }; #else -struct address_space_operations_ext ll_aops = { +const struct address_space_operations_ext ll_aops = { .orig_aops.readpage = ll_readpage, // .orig_aops.readpages = ll_readpages, .orig_aops.direct_IO = ll_direct_IO_26, @@ -571,7 +547,6 @@ struct address_space_operations_ext ll_aops = { #ifdef CONFIG_MIGRATION .orig_aops.migratepage = ll_migratepage, #endif - .orig_aops.bmap = NULL, .write_begin = ll_write_begin, .write_end = ll_write_end }; diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index c8624b5a987506..1b47774d7447ed 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -958,13 +958,18 @@ static int ll_agl_thread(void *arg) struct ptlrpc_thread *thread = &sai->sai_agl_thread; struct l_wait_info lwi = { 0 }; - CDEBUG(D_READA, "agl thread started: [pid %d] [parent %.*s]\n", - current_pid(), parent->d_name.len, parent->d_name.name); + thread->t_pid = current_pid(); + CDEBUG(D_READA, "agl thread started: sai %p, parent %.*s\n", + sai, parent->d_name.len, parent->d_name.name); atomic_inc(&sbi->ll_agl_total); spin_lock(&plli->lli_agl_lock); sai->sai_agl_valid = 1; - thread_set_flags(thread, SVC_RUNNING); + if (thread_is_init(thread)) + /* If someone else has changed the thread state + * (e.g. already changed to SVC_STOPPING), we can't just + * blindly overwrite that setting. */ + thread_set_flags(thread, SVC_RUNNING); spin_unlock(&plli->lli_agl_lock); wake_up(&thread->t_ctl_waitq); @@ -1004,8 +1009,8 @@ static int ll_agl_thread(void *arg) spin_unlock(&plli->lli_agl_lock); wake_up(&thread->t_ctl_waitq); ll_sai_put(sai); - CDEBUG(D_READA, "agl thread stopped: [pid %d] [parent %.*s]\n", - current_pid(), parent->d_name.len, parent->d_name.name); + CDEBUG(D_READA, "agl thread stopped: sai %p, parent %.*s\n", + sai, parent->d_name.len, parent->d_name.name); return 0; } @@ -1016,8 +1021,8 @@ static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai) struct ll_inode_info *plli; struct task_struct *task; - CDEBUG(D_READA, "start agl thread: [pid %d] [parent %.*s]\n", - current_pid(), parent->d_name.len, parent->d_name.name); + CDEBUG(D_READA, "start agl thread: sai %p, parent %.*s\n", + sai, parent->d_name.len, parent->d_name.name); plli = ll_i2info(parent->d_inode); task = kthread_run(ll_agl_thread, parent, @@ -1050,15 +1055,20 @@ static int ll_statahead_thread(void *arg) struct ll_dir_chain chain; struct l_wait_info lwi = { 0 }; - CDEBUG(D_READA, "statahead thread started: [pid %d] [parent %.*s]\n", - current_pid(), parent->d_name.len, parent->d_name.name); + thread->t_pid = current_pid(); + CDEBUG(D_READA, "statahead thread starting: sai %p, parent %.*s\n", + sai, parent->d_name.len, parent->d_name.name); if (sbi->ll_flags & LL_SBI_AGL_ENABLED) ll_start_agl(parent, sai); atomic_inc(&sbi->ll_sa_total); spin_lock(&plli->lli_sa_lock); - thread_set_flags(thread, SVC_RUNNING); + if (thread_is_init(thread)) + /* If someone else has changed the thread state + * (e.g. already changed to SVC_STOPPING), we can't just + * blindly overwrite that setting. */ + thread_set_flags(thread, SVC_RUNNING); spin_unlock(&plli->lli_sa_lock); wake_up(&thread->t_ctl_waitq); @@ -1220,9 +1230,7 @@ static int ll_statahead_thread(void *arg) */ ll_release_page(page, le32_to_cpu(dp->ldp_flags) & LDF_COLLIDE); - sai->sai_in_readpage = 1; page = ll_get_dir_page(dir, pos, &chain); - sai->sai_in_readpage = 0; } else { LASSERT(le32_to_cpu(dp->ldp_flags) & LDF_COLLIDE); ll_release_page(page, 1); @@ -1239,8 +1247,8 @@ static int ll_statahead_thread(void *arg) spin_unlock(&plli->lli_agl_lock); wake_up(&agl_thread->t_ctl_waitq); - CDEBUG(D_READA, "stop agl thread: [pid %d]\n", - current_pid()); + CDEBUG(D_READA, "stop agl thread: sai %p pid %u\n", + sai, (unsigned int)agl_thread->t_pid); l_wait_event(agl_thread->t_ctl_waitq, thread_is_stopped(agl_thread), &lwi); @@ -1266,8 +1274,8 @@ static int ll_statahead_thread(void *arg) wake_up(&thread->t_ctl_waitq); ll_sai_put(sai); dput(parent); - CDEBUG(D_READA, "statahead thread stopped: [pid %d] [parent %.*s]\n", - current_pid(), parent->d_name.len, parent->d_name.name); + CDEBUG(D_READA, "statahead thread stopped: sai %p, parent %.*s\n", + sai, parent->d_name.len, parent->d_name.name); return rc; } @@ -1298,8 +1306,8 @@ void ll_stop_statahead(struct inode *dir, void *key) spin_unlock(&lli->lli_sa_lock); wake_up(&thread->t_ctl_waitq); - CDEBUG(D_READA, "stop statahead thread: [pid %d]\n", - current_pid()); + CDEBUG(D_READA, "stop statahead thread: sai %p pid %u\n", + lli->lli_sai, (unsigned int)thread->t_pid); l_wait_event(thread->t_ctl_waitq, thread_is_stopped(thread), &lwi); @@ -1473,10 +1481,10 @@ ll_sai_unplug(struct ll_statahead_info *sai, struct ll_sa_entry *entry) CDEBUG(D_READA, "Statahead for dir "DFID" hit " "ratio too low: hit/miss "LPU64"/"LPU64 ", sent/replied "LPU64"/"LPU64", stopping " - "statahead thread: pid %d\n", + "statahead thread\n", PFID(&lli->lli_fid), sai->sai_hit, sai->sai_miss, sai->sai_sent, - sai->sai_replied, current_pid()); + sai->sai_replied); spin_lock(&lli->lli_sa_lock); if (!thread_is_stopped(thread)) thread_set_flags(thread, SVC_STOPPING); @@ -1553,12 +1561,6 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, return entry ? 1 : -EAGAIN; } - /* if statahead is busy in readdir, help it do post-work */ - while (!ll_sa_entry_stated(entry) && - sai->sai_in_readpage && - !sa_received_empty(sai)) - ll_post_statahead(sai); - if (!ll_sa_entry_stated(entry)) { sai->sai_index_wait = entry->se_index; lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(30), NULL, @@ -1655,9 +1657,15 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, GOTO(out, rc = -EAGAIN); } - CDEBUG(D_READA, "start statahead thread: [pid %d] [parent %.*s]\n", - current_pid(), parent->d_name.len, parent->d_name.name); + CDEBUG(D_READA, "start statahead thread: sai %p, parent %.*s\n", + sai, parent->d_name.len, parent->d_name.name); + /* The sai buffer already has one reference taken at allocation time, + * but as soon as we expose the sai by attaching it to the lli that + * default reference can be dropped by another thread calling + * ll_stop_statahead. We need to take a local reference to protect + * the sai buffer while we intend to access it. */ + ll_sai_get(sai); lli->lli_sai = sai; plli = ll_i2info(parent->d_inode); @@ -1670,6 +1678,9 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, lli->lli_opendir_key = NULL; thread_set_flags(thread, SVC_STOPPED); thread_set_flags(&sai->sai_agl_thread, SVC_STOPPED); + /* Drop both our own local reference and the default + * reference from allocation time. */ + ll_sai_put(sai); ll_sai_put(sai); LASSERT(lli->lli_sai == NULL); return -EAGAIN; @@ -1678,6 +1689,7 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, l_wait_event(thread->t_ctl_waitq, thread_is_running(thread) || thread_is_stopped(thread), &lwi); + ll_sai_put(sai); /* * We don't stat-ahead for the first dirent since we are already in diff --git a/drivers/staging/lustre/lustre/llite/super25.c b/drivers/staging/lustre/lustre/llite/super25.c index e21e1c760a8ec6..951fdb1265b9ad 100644 --- a/drivers/staging/lustre/lustre/llite/super25.c +++ b/drivers/staging/lustre/lustre/llite/super25.c @@ -52,7 +52,7 @@ static struct inode *ll_alloc_inode(struct super_block *sb) { struct ll_inode_info *lli; ll_stats_ops_tally(ll_s2sbi(sb), LPROC_LL_ALLOC_INODE, 1); - OBD_SLAB_ALLOC_PTR_GFP(lli, ll_inode_cachep, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(lli, ll_inode_cachep, GFP_NOFS); if (lli == NULL) return NULL; @@ -72,7 +72,7 @@ static void ll_destroy_inode(struct inode *inode) call_rcu(&inode->i_rcu, ll_inode_destroy_callback); } -int ll_init_inodecache(void) +static int ll_init_inodecache(void) { ll_inode_cachep = kmem_cache_create("lustre_inode_cache", sizeof(struct ll_inode_info), @@ -82,7 +82,7 @@ int ll_init_inodecache(void) return 0; } -void ll_destroy_inodecache(void) +static void ll_destroy_inodecache(void) { kmem_cache_destroy(ll_inode_cachep); } @@ -103,9 +103,6 @@ MODULE_ALIAS_FS("lustre"); void lustre_register_client_process_config(int (*cpc)(struct lustre_cfg *lcfg)); -int vvp_global_init(void); -void vvp_global_fini(void); - static int __init init_lustre_lite(void) { int i, rc, seed[2]; diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c index 80d48b5ae24706..129d3023dcea81 100644 --- a/drivers/staging/lustre/lustre/llite/symlink.c +++ b/drivers/staging/lustre/lustre/llite/symlink.c @@ -120,7 +120,7 @@ static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd) struct inode *inode = dentry->d_inode; struct ptlrpc_request *request = NULL; int rc; - char *symname; + char *symname = NULL; CDEBUG(D_VFSTRACE, "VFS Op\n"); /* Limit the recursive symlink depth to 5 instead of default diff --git a/drivers/staging/lustre/lustre/llite/vvp_dev.c b/drivers/staging/lustre/lustre/llite/vvp_dev.c index c4d1580b7be535..0f68c16abe30de 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_dev.c +++ b/drivers/staging/lustre/lustre/llite/vvp_dev.c @@ -43,7 +43,7 @@ #include #include - +#include "llite_internal.h" #include "vvp_internal.h" /***************************************************************************** @@ -57,7 +57,7 @@ * "llite_" (var. "ll_") prefix. */ -struct kmem_cache *vvp_thread_kmem; +static struct kmem_cache *vvp_thread_kmem; static struct kmem_cache *vvp_session_kmem; static struct lu_kmem_descr vvp_caches[] = { { @@ -80,7 +80,7 @@ static void *vvp_key_init(const struct lu_context *ctx, { struct vvp_thread_info *info; - OBD_SLAB_ALLOC_PTR_GFP(info, vvp_thread_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(info, vvp_thread_kmem, GFP_NOFS); if (info == NULL) info = ERR_PTR(-ENOMEM); return info; @@ -98,7 +98,7 @@ static void *vvp_session_key_init(const struct lu_context *ctx, { struct vvp_session *session; - OBD_SLAB_ALLOC_PTR_GFP(session, vvp_session_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(session, vvp_session_kmem, GFP_NOFS); if (session == NULL) session = ERR_PTR(-ENOMEM); return session; @@ -536,7 +536,7 @@ static int vvp_dump_pgcache_seq_open(struct inode *inode, struct file *filp) return result; } -struct file_operations vvp_dump_pgcache_file_ops = { +const struct file_operations vvp_dump_pgcache_file_ops = { .owner = THIS_MODULE, .open = vvp_dump_pgcache_seq_open, .read = seq_read, diff --git a/drivers/staging/lustre/lustre/llite/vvp_internal.h b/drivers/staging/lustre/lustre/llite/vvp_internal.h index c82bf17f55a6fb..3c9a03d99559f0 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_internal.h +++ b/drivers/staging/lustre/lustre/llite/vvp_internal.h @@ -57,6 +57,6 @@ struct lu_object *vvp_object_alloc(const struct lu_env *env, struct ccc_object *cl_inode2ccc(struct inode *inode); -extern struct kmem_cache *vvp_thread_kmem; +extern const struct file_operations vvp_dump_pgcache_file_ops; #endif /* VVP_INTERNAL_H */ diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c index c7d70091246ea2..0e0b404cb5e6cc 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_io.c +++ b/drivers/staging/lustre/lustre/llite/vvp_io.c @@ -80,7 +80,7 @@ static bool can_populate_pages(const struct lu_env *env, struct cl_io *io, case CIT_WRITE: /* don't need lock here to check lli_layout_gen as we have held * extent lock and GROUP lock has to hold to swap layout */ - if (lli->lli_layout_gen != cio->cui_layout_gen) { + if (ll_layout_version_get(lli) != cio->cui_layout_gen) { io->ci_need_restart = 1; /* this will return application a short read/write */ io->ci_continue = 0; @@ -190,7 +190,7 @@ static void vvp_io_fault_fini(const struct lu_env *env, vvp_io_fini(env, ios); } -enum cl_lock_mode vvp_mode_from_vma(struct vm_area_struct *vma) +static enum cl_lock_mode vvp_mode_from_vma(struct vm_area_struct *vma) { /* * we only want to hold PW locks if the mmap() can generate @@ -211,27 +211,26 @@ static int vvp_mmap_locks(const struct lu_env *env, struct cl_lock_descr *descr = &cti->cti_descr; ldlm_policy_data_t policy; unsigned long addr; - unsigned long seg; ssize_t count; int result; + struct iov_iter i; + struct iovec iov; LASSERT(io->ci_type == CIT_READ || io->ci_type == CIT_WRITE); if (!cl_is_normalio(env, io)) return 0; - if (vio->cui_iov == NULL) /* nfs or loop back device write */ + if (vio->cui_iter == NULL) /* nfs or loop back device write */ return 0; /* No MM (e.g. NFS)? No vmas too. */ if (mm == NULL) return 0; - for (seg = 0; seg < vio->cui_nrsegs; seg++) { - const struct iovec *iv = &vio->cui_iov[seg]; - - addr = (unsigned long)iv->iov_base; - count = iv->iov_len; + iov_for_each(iov, i, *(vio->cui_iter)) { + addr = (unsigned long)iov.iov_base; + count = iov.iov_len; if (count == 0) continue; @@ -527,9 +526,7 @@ static int vvp_io_read_start(const struct lu_env *env, switch (vio->cui_io_subtype) { case IO_NORMAL: LASSERT(cio->cui_iocb->ki_pos == pos); - result = generic_file_aio_read(cio->cui_iocb, - cio->cui_iov, cio->cui_nrsegs, - cio->cui_iocb->ki_pos); + result = generic_file_read_iter(cio->cui_iocb, cio->cui_iter); break; case IO_SPLICE: result = generic_file_splice_read(file, &pos, @@ -595,12 +592,11 @@ static int vvp_io_write_start(const struct lu_env *env, CDEBUG(D_VFSTRACE, "write: [%lli, %lli)\n", pos, pos + (long long)cnt); - if (cio->cui_iov == NULL) /* from a temp io in ll_cl_init(). */ + if (cio->cui_iter == NULL) /* from a temp io in ll_cl_init(). */ result = 0; else - result = generic_file_aio_write(cio->cui_iocb, - cio->cui_iov, cio->cui_nrsegs, - cio->cui_iocb->ki_pos); + result = generic_file_write_iter(cio->cui_iocb, cio->cui_iter); + if (result > 0) { if (result < cnt) io->ci_continue = 0; @@ -1162,10 +1158,9 @@ int vvp_io_init(const struct lu_env *env, struct cl_object *obj, * results." -- Single Unix Spec */ if (count == 0) result = 1; - else { + else cio->cui_tot_count = count; - cio->cui_tot_nrsegs = 0; - } + /* for read/write, we store the jobid in the inode, and * it'll be fetched by osc when building RPC. * diff --git a/drivers/staging/lustre/lustre/llite/vvp_object.c b/drivers/staging/lustre/lustre/llite/vvp_object.c index 25973dedd9a25b..65b6db1b71b4ff 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_object.c +++ b/drivers/staging/lustre/lustre/llite/vvp_object.c @@ -120,13 +120,28 @@ static int vvp_attr_set(const struct lu_env *env, struct cl_object *obj, return 0; } -int vvp_conf_set(const struct lu_env *env, struct cl_object *obj, - const struct cl_object_conf *conf) +static int vvp_conf_set(const struct lu_env *env, struct cl_object *obj, + const struct cl_object_conf *conf) { struct ll_inode_info *lli = ll_i2info(conf->coc_inode); if (conf->coc_opc == OBJECT_CONF_INVALIDATE) { - lli->lli_layout_gen = LL_LAYOUT_GEN_NONE; + CDEBUG(D_VFSTRACE, DFID ": losing layout lock\n", + PFID(&lli->lli_fid)); + + ll_layout_version_set(lli, LL_LAYOUT_GEN_NONE); + + /* Clean up page mmap for this inode. + * The reason for us to do this is that if the page has + * already been installed into memory space, the process + * can access it without interacting with lustre, so this + * page may be stale due to layout change, and the process + * will never be notified. + * This operation is expensive but mmap processes have to pay + * a price themselves. */ + unmap_mapping_range(conf->coc_inode->i_mapping, + 0, OBD_OBJECT_EOF, 0); + return 0; } @@ -134,18 +149,18 @@ int vvp_conf_set(const struct lu_env *env, struct cl_object *obj, return 0; if (conf->u.coc_md != NULL && conf->u.coc_md->lsm != NULL) { - CDEBUG(D_VFSTRACE, "layout lock change: %u -> %u\n", - lli->lli_layout_gen, - conf->u.coc_md->lsm->lsm_layout_gen); + CDEBUG(D_VFSTRACE, DFID ": layout version change: %u -> %u\n", + PFID(&lli->lli_fid), lli->lli_layout_gen, + conf->u.coc_md->lsm->lsm_layout_gen); lli->lli_has_smd = lsm_has_objects(conf->u.coc_md->lsm); - lli->lli_layout_gen = conf->u.coc_md->lsm->lsm_layout_gen; + ll_layout_version_set(lli, conf->u.coc_md->lsm->lsm_layout_gen); } else { - CDEBUG(D_VFSTRACE, "layout lock destroyed: %u.\n", - lli->lli_layout_gen); + CDEBUG(D_VFSTRACE, DFID ": layout nuked: %u.\n", + PFID(&lli->lli_fid), lli->lli_layout_gen); lli->lli_has_smd = false; - lli->lli_layout_gen = LL_LAYOUT_GEN_EMPTY; + ll_layout_version_set(lli, LL_LAYOUT_GEN_EMPTY); } return 0; } diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c index b1ed4d9ea6beaf..c6c27bbb43b424 100644 --- a/drivers/staging/lustre/lustre/llite/xattr.c +++ b/drivers/staging/lustre/lustre/llite/xattr.c @@ -112,8 +112,8 @@ int ll_setxattr_common(struct inode *inode, const char *name, struct ptlrpc_request *req = NULL; int xattr_type, rc; struct obd_capa *oc; - struct rmtacl_ctl_entry *rce = NULL; #ifdef CONFIG_FS_POSIX_ACL + struct rmtacl_ctl_entry *rce = NULL; posix_acl_xattr_header *new_value = NULL; ext_acl_xattr_header *acl = NULL; #endif @@ -124,6 +124,11 @@ int ll_setxattr_common(struct inode *inode, const char *name, if (rc) return rc; + if ((xattr_type == XATTR_ACL_ACCESS_T || + xattr_type == XATTR_ACL_DEFAULT_T) && + !inode_owner_or_capable(inode)) + return -EPERM; + /* b10667: ignore lustre special xattr for now */ if ((xattr_type == XATTR_TRUSTED_T && strcmp(name, "trusted.lov") == 0) || (xattr_type == XATTR_LUSTRE_T && strcmp(name, "lustre.lov") == 0)) diff --git a/drivers/staging/lustre/lustre/llite/xattr_cache.c b/drivers/staging/lustre/lustre/llite/xattr_cache.c index 4defa2fd83b356..4dd83fc0368729 100644 --- a/drivers/staging/lustre/lustre/llite/xattr_cache.c +++ b/drivers/staging/lustre/lustre/llite/xattr_cache.c @@ -120,7 +120,7 @@ static int ll_xattr_cache_add(struct list_head *cache, return -EPROTO; } - OBD_SLAB_ALLOC_PTR_GFP(xattr, xattr_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(xattr, xattr_kmem, GFP_NOFS); if (xattr == NULL) { CDEBUG(D_CACHE, "failed to allocate xattr\n"); return -ENOMEM; @@ -232,7 +232,7 @@ static int ll_xattr_cache_list(struct list_head *cache, * \retval 0 @cache is not initialized * \retval 1 @cache is initialized */ -int ll_xattr_cache_valid(struct ll_inode_info *lli) +static int ll_xattr_cache_valid(struct ll_inode_info *lli) { return !!(lli->lli_flags & LLIF_XATTR_CACHE); } diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index 3ba0a0a1d945f9..4edf8a31221c3f 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -280,7 +280,7 @@ static void lmv_set_timeouts(struct obd_device *obd) } static int lmv_init_ea_size(struct obd_export *exp, int easize, - int def_easize, int cookiesize) + int def_easize, int cookiesize, int def_cookiesize) { struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; @@ -300,6 +300,10 @@ static int lmv_init_ea_size(struct obd_export *exp, int easize, lmv->max_cookiesize = cookiesize; change = 1; } + if (lmv->max_def_cookiesize < def_cookiesize) { + lmv->max_def_cookiesize = def_cookiesize; + change = 1; + } if (change == 0) return 0; @@ -315,7 +319,7 @@ static int lmv_init_ea_size(struct obd_export *exp, int easize, } rc = md_init_ea_size(lmv->tgts[i]->ltd_exp, easize, def_easize, - cookiesize); + cookiesize, def_cookiesize); if (rc) { CERROR("%s: obd_init_ea_size() failed on MDT target %d:" " rc = %d.\n", obd->obd_name, i, rc); @@ -400,8 +404,8 @@ int lmv_connect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt) tgt->ltd_exp = mdc_exp; lmv->desc.ld_active_tgt_count++; - md_init_ea_size(tgt->ltd_exp, lmv->max_easize, - lmv->max_def_easize, lmv->max_cookiesize); + md_init_ea_size(tgt->ltd_exp, lmv->max_easize, lmv->max_def_easize, + lmv->max_cookiesize, lmv->max_def_cookiesize); CDEBUG(D_CONFIG, "Connected to %s(%s) successfully (%d)\n", mdc_obd->obd_name, mdc_obd->obd_uuid.uuid, @@ -527,9 +531,8 @@ static int lmv_add_target(struct obd_device *obd, struct obd_uuid *uuidp, spin_unlock(&lmv->lmv_lock); } else { int easize = sizeof(struct lmv_stripe_md) + - lmv->desc.ld_tgt_count * - sizeof(struct lu_fid); - lmv_init_ea_size(obd->obd_self_export, easize, 0, 0); + lmv->desc.ld_tgt_count * sizeof(struct lu_fid); + lmv_init_ea_size(obd->obd_self_export, easize, 0, 0, 0); } } @@ -578,7 +581,7 @@ int lmv_check_connect(struct obd_device *obd) class_export_put(lmv->exp); lmv->connected = 1; easize = lmv_get_easize(lmv); - lmv_init_ea_size(obd->obd_self_export, easize, 0, 0); + lmv_init_ea_size(obd->obd_self_export, easize, 0, 0, 0); lmv_init_unlock(lmv); return 0; @@ -2340,7 +2343,11 @@ static int lmv_get_info(const struct lu_env *env, struct obd_export *exp, return 0; } return -EINVAL; - } else if (KEY_IS(KEY_MAX_EASIZE) || KEY_IS(KEY_CONN_DATA)) { + } else if (KEY_IS(KEY_MAX_EASIZE) || + KEY_IS(KEY_DEFAULT_EASIZE) || + KEY_IS(KEY_MAX_COOKIESIZE) || + KEY_IS(KEY_DEFAULT_COOKIESIZE) || + KEY_IS(KEY_CONN_DATA)) { rc = lmv_check_connect(obd); if (rc) return rc; diff --git a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c index 5d5c3081c4670d..ae73c82ce499ff 100644 --- a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c +++ b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c @@ -200,19 +200,19 @@ static int lmv_target_seq_open(struct inode *inode, struct file *file) LPROC_SEQ_FOPS_RO_TYPE(lmv, uuid); struct lprocfs_vars lprocfs_lmv_obd_vars[] = { - { "numobd", &lmv_numobd_fops, 0, 0 }, - { "placement", &lmv_placement_fops, 0, 0 }, - { "activeobd", &lmv_activeobd_fops, 0, 0 }, - { "uuid", &lmv_uuid_fops, 0, 0 }, - { "desc_uuid", &lmv_desc_uuid_fops, 0, 0 }, - { 0 } + { "numobd", &lmv_numobd_fops, NULL, 0 }, + { "placement", &lmv_placement_fops, NULL, 0 }, + { "activeobd", &lmv_activeobd_fops, NULL, 0 }, + { "uuid", &lmv_uuid_fops, NULL, 0 }, + { "desc_uuid", &lmv_desc_uuid_fops, NULL, 0 }, + { NULL } }; LPROC_SEQ_FOPS_RO_TYPE(lmv, numrefs); static struct lprocfs_vars lprocfs_lmv_module_vars[] = { - { "num_refs", &lmv_numrefs_fops, 0, 0 }, - { 0 } + { "num_refs", &lmv_numrefs_fops, NULL, 0 }, + { NULL } }; struct file_operations lmv_proc_target_fops = { diff --git a/drivers/staging/lustre/lustre/lov/Makefile b/drivers/staging/lustre/lustre/lov/Makefile index 9a5f26d5558d6b..a908edb533d3c3 100644 --- a/drivers/staging/lustre/lustre/lov/Makefile +++ b/drivers/staging/lustre/lustre/lov/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_LUSTRE_FS) += lov.o -lov-y := lov_log.o lov_obd.o lov_pack.o lov_offset.o lov_merge.o \ +lov-y := lov_obd.o lov_pack.o lov_offset.o lov_merge.o \ lov_request.o lov_ea.o lov_dev.o lov_object.o lov_page.o \ lov_lock.o lov_io.o lovsub_dev.o lovsub_object.o lovsub_page.o \ lovsub_lock.o lovsub_io.o lov_pool.o diff --git a/drivers/staging/lustre/lustre/lov/lov_dev.c b/drivers/staging/lustre/lustre/lov/lov_dev.c index 1f33b04b0c38c0..53e5781ba1d9d7 100644 --- a/drivers/staging/lustre/lustre/lov/lov_dev.c +++ b/drivers/staging/lustre/lustre/lov/lov_dev.c @@ -143,7 +143,7 @@ static void *lov_key_init(const struct lu_context *ctx, { struct lov_thread_info *info; - OBD_SLAB_ALLOC_PTR_GFP(info, lov_thread_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(info, lov_thread_kmem, GFP_NOFS); if (info != NULL) INIT_LIST_HEAD(&info->lti_closure.clc_list); else @@ -170,7 +170,7 @@ static void *lov_session_key_init(const struct lu_context *ctx, { struct lov_session *info; - OBD_SLAB_ALLOC_PTR_GFP(info, lov_session_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(info, lov_session_kmem, GFP_NOFS); if (info == NULL) info = ERR_PTR(-ENOMEM); return info; @@ -260,7 +260,7 @@ static int lov_req_init(const struct lu_env *env, struct cl_device *dev, struct lov_req *lr; int result; - OBD_SLAB_ALLOC_PTR_GFP(lr, lov_req_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(lr, lov_req_kmem, GFP_NOFS); if (lr != NULL) { cl_req_slice_add(req, &lr->lr_cl, dev, &lov_req_ops); result = 0; diff --git a/drivers/staging/lustre/lustre/lov/lov_ea.c b/drivers/staging/lustre/lustre/lov/lov_ea.c index 6f356e02554373..a0c148e31f69c6 100644 --- a/drivers/staging/lustre/lustre/lov/lov_ea.c +++ b/drivers/staging/lustre/lustre/lov/lov_ea.c @@ -44,7 +44,6 @@ #include #include -#include #include #include "lov_internal.h" @@ -101,7 +100,7 @@ struct lov_stripe_md *lsm_alloc_plain(__u16 stripe_count, int *size) return NULL; for (i = 0; i < stripe_count; i++) { - OBD_SLAB_ALLOC_PTR_GFP(loi, lov_oinfo_slab, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(loi, lov_oinfo_slab, GFP_NOFS); if (loi == NULL) goto err; lsm->lsm_oinfo[i] = loi; @@ -346,3 +345,14 @@ const struct lsm_operations lsm_v3_ops = { .lsm_lmm_verify = lsm_lmm_verify_v3, .lsm_unpackmd = lsm_unpackmd_v3, }; + +void dump_lsm(unsigned int level, const struct lov_stripe_md *lsm) +{ + CDEBUG(level, "lsm %p, objid "DOSTID", maxbytes "LPX64", magic 0x%08X," + " stripe_size %u, stripe_count %u, refc: %d," + " layout_gen %u, pool ["LOV_POOLNAMEF"]\n", lsm, + POSTID(&lsm->lsm_oi), lsm->lsm_maxbytes, lsm->lsm_magic, + lsm->lsm_stripe_size, lsm->lsm_stripe_count, + atomic_read(&lsm->lsm_refc), lsm->lsm_layout_gen, + lsm->lsm_pool_name); +} diff --git a/drivers/staging/lustre/lustre/lov/lov_internal.h b/drivers/staging/lustre/lustre/lov/lov_internal.h index 2b22a03c038ea2..38508a5c827f5c 100644 --- a/drivers/staging/lustre/lustre/lov/lov_internal.h +++ b/drivers/staging/lustre/lustre/lov/lov_internal.h @@ -38,9 +38,39 @@ #define LOV_INTERNAL_H #include -#include #include +/* lov_do_div64(a, b) returns a % b, and a = a / b. + * The 32-bit code is LOV-specific due to knowing about stripe limits in + * order to reduce the divisor to a 32-bit number. If the divisor is + * already a 32-bit value the compiler handles this directly. */ +#if BITS_PER_LONG == 64 +# define lov_do_div64(n, base) ({ \ + uint64_t __base = (base); \ + uint64_t __rem; \ + __rem = ((uint64_t)(n)) % __base; \ + (n) = ((uint64_t)(n)) / __base; \ + __rem; \ +}) +#elif BITS_PER_LONG == 32 +# define lov_do_div64(n, base) ({ \ + uint64_t __rem; \ + if ((sizeof(base) > 4) && (((base) & 0xffffffff00000000ULL) != 0)) { \ + int __remainder; \ + LASSERTF(!((base) & (LOV_MIN_STRIPE_SIZE - 1)), "64 bit lov " \ + "division %llu / %llu\n", (n), (uint64_t)(base)); \ + __remainder = (n) & (LOV_MIN_STRIPE_SIZE - 1); \ + (n) >>= LOV_MIN_STRIPE_BITS; \ + __rem = do_div(n, (base) >> LOV_MIN_STRIPE_BITS); \ + __rem <<= LOV_MIN_STRIPE_BITS; \ + __rem += __remainder; \ + } else { \ + __rem = do_div(n, base); \ + } \ + __rem; \ +}) +#endif + struct lov_lock_handles { struct portals_handle llh_handle; atomic_t llh_refcount; @@ -251,10 +281,6 @@ int lov_process_config_base(struct obd_device *obd, struct lustre_cfg *lcfg, __u32 *indexp, int *genp); int lov_del_target(struct obd_device *obd, __u32 index, struct obd_uuid *uuidp, int gen); -/* lov_log.c */ -int lov_llog_init(struct obd_device *obd, struct obd_llog_group *olg, - struct obd_device *tgt, int *idx); -int lov_llog_finish(struct obd_device *obd, int count); /* lov_pack.c */ int lov_packmd(struct obd_export *exp, struct lov_mds_md **lmm, @@ -279,6 +305,7 @@ void lov_dump_lmm(int level, void *lmm); /* lov_ea.c */ struct lov_stripe_md *lsm_alloc_plain(__u16 stripe_count, int *size); void lsm_free_plain(struct lov_stripe_md *lsm); +void dump_lsm(unsigned int level, const struct lov_stripe_md *lsm); int lovea_destroy_object(struct lov_obd *lov, struct lov_stripe_md *lsm, struct obdo *oa, void *data); diff --git a/drivers/staging/lustre/lustre/lov/lov_lock.c b/drivers/staging/lustre/lustre/lov/lov_lock.c index ed2726e523e8ba..08ac3745f0dae3 100644 --- a/drivers/staging/lustre/lustre/lov/lov_lock.c +++ b/drivers/staging/lustre/lustre/lov/lov_lock.c @@ -144,7 +144,7 @@ static struct cl_lock *lov_sublock_alloc(const struct lu_env *env, LASSERT(idx < lck->lls_nr); - OBD_SLAB_ALLOC_PTR_GFP(link, lov_lock_link_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(link, lov_lock_link_kmem, GFP_NOFS); if (link != NULL) { struct lov_sublock_env *subenv; struct lov_lock_sub *lls; @@ -346,41 +346,7 @@ static int lov_lock_sub_init(const struct lu_env *env, } } LASSERT(nr == lck->lls_nr); - /* - * Then, create sub-locks. Once at least one sub-lock was created, - * top-lock can be reached by other threads. - */ - for (i = 0; i < lck->lls_nr; ++i) { - struct cl_lock *sublock; - struct lov_lock_link *link; - if (lck->lls_sub[i].sub_lock == NULL) { - sublock = lov_sublock_alloc(env, io, lck, i, &link); - if (IS_ERR(sublock)) { - result = PTR_ERR(sublock); - break; - } - cl_lock_get_trust(sublock); - cl_lock_mutex_get(env, sublock); - cl_lock_mutex_get(env, parent); - /* - * recheck under mutex that sub-lock wasn't created - * concurrently, and that top-lock is still alive. - */ - if (lck->lls_sub[i].sub_lock == NULL && - parent->cll_state < CLS_FREEING) { - lov_sublock_adopt(env, lck, sublock, i, link); - cl_lock_mutex_put(env, parent); - } else { - OBD_SLAB_FREE_PTR(link, lov_lock_link_kmem); - cl_lock_mutex_put(env, parent); - cl_lock_unhold(env, sublock, - "lov-parent", parent); - } - cl_lock_mutex_put(env, sublock); - cl_lock_put(env, sublock); - } - } /* * Some sub-locks can be missing at this point. This is not a problem, * because enqueue will create them anyway. Main duty of this function @@ -533,7 +499,7 @@ static int lov_lock_enqueue_one(const struct lu_env *env, struct lov_lock *lck, static int lov_sublock_fill(const struct lu_env *env, struct cl_lock *parent, struct cl_io *io, struct lov_lock *lck, int idx) { - struct lov_lock_link *link; + struct lov_lock_link *link = NULL; struct cl_lock *sublock; int result; @@ -1159,7 +1125,7 @@ int lov_lock_init_raid0(const struct lu_env *env, struct cl_object *obj, struct lov_lock *lck; int result; - OBD_SLAB_ALLOC_PTR_GFP(lck, lov_lock_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(lck, lov_lock_kmem, GFP_NOFS); if (lck != NULL) { cl_lock_slice_add(lock, &lck->lls_cl, obj, &lov_lock_ops); result = lov_lock_sub_init(env, lck, io); @@ -1194,7 +1160,7 @@ int lov_lock_init_empty(const struct lu_env *env, struct cl_object *obj, struct lov_lock *lck; int result = -ENOMEM; - OBD_SLAB_ALLOC_PTR_GFP(lck, lov_lock_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(lck, lov_lock_kmem, GFP_NOFS); if (lck != NULL) { cl_lock_slice_add(lock, &lck->lls_cl, obj, &lov_empty_lock_ops); lck->lls_orig = lock->cll_descr; diff --git a/drivers/staging/lustre/lustre/lov/lov_log.c b/drivers/staging/lustre/lustre/lov/lov_log.c deleted file mode 100644 index 3eedd935d1bcfd..00000000000000 --- a/drivers/staging/lustre/lustre/lov/lov_log.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * 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 version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * - * GPL HEADER END - */ -/* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/lov/lov_log.c - * - * Author: Phil Schwan - * Author: Peter Braam - * Author: Mike Shaver - */ - -#define DEBUG_SUBSYSTEM S_LOV -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "lov_internal.h" - -/* Add log records for each OSC that this object is striped over, and return - * cookies for each one. We _would_ have nice abstraction here, except that - * we need to keep cookies in stripe order, even if some are NULL, so that - * the right cookies are passed back to the right OSTs at the client side. - * Unset cookies should be all-zero (which will never occur naturally). */ -static int lov_llog_origin_add(const struct lu_env *env, - struct llog_ctxt *ctxt, - struct llog_rec_hdr *rec, - struct lov_stripe_md *lsm, - struct llog_cookie *logcookies, int numcookies) -{ - struct obd_device *obd = ctxt->loc_obd; - struct lov_obd *lov = &obd->u.lov; - int i, rc = 0, cookies = 0; - - LASSERTF(logcookies && numcookies >= lsm->lsm_stripe_count, - "logcookies %p, numcookies %d lsm->lsm_stripe_count %d \n", - logcookies, numcookies, lsm->lsm_stripe_count); - - for (i = 0; i < lsm->lsm_stripe_count; i++) { - struct lov_oinfo *loi = lsm->lsm_oinfo[i]; - struct obd_device *child = - lov->lov_tgts[loi->loi_ost_idx]->ltd_exp->exp_obd; - struct llog_ctxt *cctxt = llog_get_context(child, ctxt->loc_idx); - - /* fill mds unlink/setattr log record */ - switch (rec->lrh_type) { - case MDS_UNLINK_REC: { - struct llog_unlink_rec *lur = (struct llog_unlink_rec *)rec; - lur->lur_oid = ostid_id(&loi->loi_oi); - lur->lur_oseq = (__u32)ostid_seq(&loi->loi_oi); - break; - } - case MDS_SETATTR64_REC: { - struct llog_setattr64_rec *lsr = (struct llog_setattr64_rec *)rec; - lsr->lsr_oi = loi->loi_oi; - break; - } - default: - break; - } - - /* inject error in llog_obd_add() below */ - if (OBD_FAIL_CHECK(OBD_FAIL_MDS_FAIL_LOV_LOG_ADD)) { - llog_ctxt_put(cctxt); - cctxt = NULL; - } - rc = llog_obd_add(env, cctxt, rec, NULL, logcookies + cookies, - numcookies - cookies); - llog_ctxt_put(cctxt); - if (rc < 0) { - CERROR("Can't add llog (rc = %d) for stripe %d\n", - rc, cookies); - memset(logcookies + cookies, 0, - sizeof(struct llog_cookie)); - rc = 1; /* skip this cookie */ - } - /* Note that rc is always 1 if llog_obd_add was successful */ - cookies += rc; - } - return cookies; -} - -static int lov_llog_origin_connect(struct llog_ctxt *ctxt, - struct llog_logid *logid, - struct llog_gen *gen, - struct obd_uuid *uuid) -{ - struct obd_device *obd = ctxt->loc_obd; - struct lov_obd *lov = &obd->u.lov; - int i, rc = 0, err = 0; - - obd_getref(obd); - for (i = 0; i < lov->desc.ld_tgt_count; i++) { - struct obd_device *child; - struct llog_ctxt *cctxt; - - if (!lov->lov_tgts[i] || !lov->lov_tgts[i]->ltd_active) - continue; - if (uuid && !obd_uuid_equals(uuid, &lov->lov_tgts[i]->ltd_uuid)) - continue; - CDEBUG(D_CONFIG, "connect %d/%d\n", i, lov->desc.ld_tgt_count); - child = lov->lov_tgts[i]->ltd_exp->exp_obd; - cctxt = llog_get_context(child, ctxt->loc_idx); - rc = llog_connect(cctxt, logid, gen, uuid); - llog_ctxt_put(cctxt); - - if (rc) { - CERROR("error osc_llog_connect tgt %d (%d)\n", i, rc); - if (!err) - err = rc; - } - } - obd_putref(obd); - - return err; -} - -/* the replicators commit callback */ -static int lov_llog_repl_cancel(const struct lu_env *env, - struct llog_ctxt *ctxt, - struct lov_stripe_md *lsm, - int count, struct llog_cookie *cookies, - int flags) -{ - struct lov_obd *lov; - struct obd_device *obd = ctxt->loc_obd; - int rc = 0, i; - - LASSERT(lsm != NULL); - LASSERT(count == lsm->lsm_stripe_count); - - lov = &obd->u.lov; - obd_getref(obd); - for (i = 0; i < count; i++, cookies++) { - struct lov_oinfo *loi = lsm->lsm_oinfo[i]; - struct obd_device *child = - lov->lov_tgts[loi->loi_ost_idx]->ltd_exp->exp_obd; - struct llog_ctxt *cctxt = - llog_get_context(child, ctxt->loc_idx); - int err; - - err = llog_cancel(env, cctxt, NULL, 1, cookies, flags); - llog_ctxt_put(cctxt); - if (err && lov->lov_tgts[loi->loi_ost_idx]->ltd_active) { - CERROR("%s: objid "DOSTID" subobj "DOSTID - " on OST idx %d: rc = %d\n", - obd->obd_name, POSTID(&lsm->lsm_oi), - POSTID(&loi->loi_oi), loi->loi_ost_idx, err); - if (!rc) - rc = err; - } - } - obd_putref(obd); - return rc; -} - -static struct llog_operations lov_mds_ost_orig_logops = { - .lop_obd_add = lov_llog_origin_add, - .lop_connect = lov_llog_origin_connect, -}; - -static struct llog_operations lov_size_repl_logops = { - .lop_cancel = lov_llog_repl_cancel, -}; - -int lov_llog_init(struct obd_device *obd, struct obd_llog_group *olg, - struct obd_device *disk_obd, int *index) -{ - struct lov_obd *lov = &obd->u.lov; - struct obd_device *child; - int i, rc = 0; - - LASSERT(olg == &obd->obd_olg); - rc = llog_setup(NULL, obd, olg, LLOG_MDS_OST_ORIG_CTXT, disk_obd, - &lov_mds_ost_orig_logops); - if (rc) - return rc; - - rc = llog_setup(NULL, obd, olg, LLOG_SIZE_REPL_CTXT, disk_obd, - &lov_size_repl_logops); - if (rc) - GOTO(err_cleanup, rc); - - obd_getref(obd); - /* count may not match lov->desc.ld_tgt_count during dynamic ost add */ - for (i = 0; i < lov->desc.ld_tgt_count; i++) { - if (!lov->lov_tgts[i]) - continue; - - if (index && i != *index) - continue; - - child = lov->lov_tgts[i]->ltd_obd; - rc = obd_llog_init(child, &child->obd_olg, disk_obd, &i); - if (rc) - CERROR("error osc_llog_init idx %d osc '%s' tgt '%s' " - "(rc=%d)\n", i, child->obd_name, - disk_obd->obd_name, rc); - rc = 0; - } - obd_putref(obd); - GOTO(err_cleanup, rc); -err_cleanup: - if (rc) { - struct llog_ctxt *ctxt = - llog_get_context(obd, LLOG_SIZE_REPL_CTXT); - if (ctxt) - llog_cleanup(NULL, ctxt); - ctxt = llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT); - if (ctxt) - llog_cleanup(NULL, ctxt); - } - return rc; -} - -int lov_llog_finish(struct obd_device *obd, int count) -{ - struct llog_ctxt *ctxt; - - /* cleanup our llogs only if the ctxts have been setup - * (client lov doesn't setup, mds lov does). */ - ctxt = llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT); - if (ctxt) - llog_cleanup(NULL, ctxt); - - ctxt = llog_get_context(obd, LLOG_SIZE_REPL_CTXT); - if (ctxt) - llog_cleanup(NULL, ctxt); - - /* lov->tgt llogs are cleaned during osc_cleanup. */ - return 0; -} diff --git a/drivers/staging/lustre/lustre/lov/lov_merge.c b/drivers/staging/lustre/lustre/lov/lov_merge.c index 9defa55d9919e4..da959e90137143 100644 --- a/drivers/staging/lustre/lustre/lov/lov_merge.c +++ b/drivers/staging/lustre/lustre/lov/lov_merge.c @@ -39,8 +39,6 @@ #include #include -#include - #include "lov_internal.h" /** Merge the lock value block(&lvb) attributes and KMS from each of the @@ -60,7 +58,7 @@ int lov_merge_lvb_kms(struct lov_stripe_md *lsm, int i; int rc = 0; - LASSERT(spin_is_locked(&lsm->lsm_lock)); + assert_spin_locked(&lsm->lsm_lock); LASSERT(lsm->lsm_lock_owner == current_pid()); CDEBUG(D_INODE, "MDT ID "DOSTID" initial value: s="LPU64" m="LPU64 @@ -147,7 +145,7 @@ int lov_adjust_kms(struct obd_export *exp, struct lov_stripe_md *lsm, int stripe = 0; __u64 kms; - LASSERT(spin_is_locked(&lsm->lsm_lock)); + assert_spin_locked(&lsm->lsm_lock); LASSERT(lsm->lsm_lock_owner == current_pid()); if (shrink) { diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c index 02509d0cb10665..12e778c4225574 100644 --- a/drivers/staging/lustre/lustre/lov/lov_obd.c +++ b/drivers/staging/lustre/lustre/lov/lov_obd.c @@ -50,16 +50,13 @@ #include #include #include -#include #include -#include #include #include #include #include #include /* for cl_client_lru */ #include -#include #include #include "lov_internal.h" @@ -726,8 +723,8 @@ void lov_fix_desc_stripe_size(__u64 *val) if (*val != 0) LCONSOLE_INFO("Increasing default stripe size to " "minimum %u\n", - LOV_DEFAULT_STRIPE_SIZE); - *val = LOV_DEFAULT_STRIPE_SIZE; + LOV_DESC_STRIPE_SIZE_DEFAULT); + *val = LOV_DESC_STRIPE_SIZE_DEFAULT; } else if (*val & (LOV_MIN_STRIPE_SIZE - 1)) { *val &= ~(LOV_MIN_STRIPE_SIZE - 1); LCONSOLE_WARN("Changing default stripe size to "LPU64" (a " @@ -753,9 +750,8 @@ void lov_fix_desc_pattern(__u32 *val) void lov_fix_desc_qos_maxage(__u32 *val) { - /* fix qos_maxage */ if (*val == 0) - *val = QOS_DEFAULT_MAXAGE; + *val = LOV_DESC_QOS_MAXAGE_DEFAULT; } void lov_fix_desc(struct lov_desc *desc) @@ -861,12 +857,10 @@ static int lov_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage) } break; } - case OBD_CLEANUP_EXPORTS: - rc = obd_llog_finish(obd, 0); - if (rc != 0) - CERROR("failed to cleanup llogging subsystems\n"); + default: break; } + return rc; } @@ -2254,11 +2248,12 @@ static int lov_fiemap(struct lov_obd *lov, __u32 keylen, void *key, if (fm_end_offset == -EINVAL) GOTO(out, rc = -EINVAL); + if (fiemap_count_to_size(fiemap->fm_extent_count) > *vallen) + fiemap->fm_extent_count = fiemap_size_to_count(*vallen); if (fiemap->fm_extent_count == 0) { get_num_extents = 1; count_local = 0; } - /* Check each stripe */ for (cur_stripe = start_stripe, i = 0; i < stripe_count; i++, cur_stripe = (cur_stripe + 1) % lsm->lsm_stripe_count) { @@ -2808,8 +2803,6 @@ struct obd_ops lov_obd_ops = { .o_get_info = lov_get_info, .o_set_info_async = lov_set_info_async, .o_extent_calc = lov_extent_calc, - .o_llog_init = lov_llog_init, - .o_llog_finish = lov_llog_finish, .o_notify = lov_notify, .o_pool_new = lov_pool_new, .o_pool_rem = lov_pool_remove, diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c index d6b2cb45b938fb..992c80ab3d5380 100644 --- a/drivers/staging/lustre/lustre/lov/lov_object.c +++ b/drivers/staging/lustre/lustre/lov/lov_object.c @@ -42,7 +42,6 @@ #define DEBUG_SUBSYSTEM S_LOV #include "lov_cl_internal.h" -#include /** \addtogroup lov * @{ @@ -885,7 +884,7 @@ struct lu_object *lov_object_alloc(const struct lu_env *env, struct lov_object *lov; struct lu_object *obj; - OBD_SLAB_ALLOC_PTR_GFP(lov, lov_object_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(lov, lov_object_kmem, GFP_NOFS); if (lov != NULL) { obj = lov2lu(lov); lu_object_init(obj, NULL, dev); diff --git a/drivers/staging/lustre/lustre/lov/lov_offset.c b/drivers/staging/lustre/lustre/lov/lov_offset.c index 04863a7c5e0bd1..379568f8245cd8 100644 --- a/drivers/staging/lustre/lustre/lov/lov_offset.c +++ b/drivers/staging/lustre/lustre/lov/lov_offset.c @@ -39,7 +39,6 @@ #include #include -#include #include "lov_internal.h" diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c index 74200cf1b331b0..59ab7c30ffbfa1 100644 --- a/drivers/staging/lustre/lustre/lov/lov_pack.c +++ b/drivers/staging/lustre/lustre/lov/lov_pack.c @@ -44,7 +44,6 @@ #include #include -#include #include #include #include @@ -177,8 +176,9 @@ int lov_packmd(struct obd_export *exp, struct lov_mds_md **lmmp, * Anyway, this is pretty inaccurate since ld_tgt_count now * represents max index and we should rely on the actual number * of OSTs instead */ - stripe_count = lov_mds_md_stripecnt(lov->lov_ocd.ocd_max_easize, - lmm_magic); + stripe_count = lov_mds_md_max_stripe_count( + lov->lov_ocd.ocd_max_easize, lmm_magic); + if (stripe_count > lov->desc.ld_tgt_count) stripe_count = lov->desc.ld_tgt_count; } @@ -264,8 +264,8 @@ __u16 lov_get_stripecnt(struct lov_obd *lov, __u32 magic, __u16 stripe_count) * larger EA sizes */ if (lov->lov_ocd.ocd_connect_flags & OBD_CONNECT_MAX_EASIZE && lov->lov_ocd.ocd_max_easize) - max_stripes = lov_mds_md_stripecnt(lov->lov_ocd.ocd_max_easize, - magic); + max_stripes = lov_mds_md_max_stripe_count( + lov->lov_ocd.ocd_max_easize, magic); if (stripe_count > max_stripes) stripe_count = max_stripes; diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c index a5481d7eb5d609..bd6490d0129cc7 100644 --- a/drivers/staging/lustre/lustre/lov/lov_request.c +++ b/drivers/staging/lustre/lustre/lov/lov_request.c @@ -39,7 +39,6 @@ #include #include -#include #include #include "lov_internal.h" diff --git a/drivers/staging/lustre/lustre/lov/lovsub_dev.c b/drivers/staging/lustre/lustre/lov/lovsub_dev.c index 926c35a25ceb6e..52fb6c162ad7dc 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_dev.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_dev.c @@ -146,7 +146,7 @@ static int lovsub_req_init(const struct lu_env *env, struct cl_device *dev, struct lovsub_req *lsr; int result; - OBD_SLAB_ALLOC_PTR_GFP(lsr, lovsub_req_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(lsr, lovsub_req_kmem, GFP_NOFS); if (lsr != NULL) { cl_req_slice_add(req, &lsr->lsrq_cl, dev, &lovsub_req_ops); result = 0; diff --git a/drivers/staging/lustre/lustre/lov/lovsub_lock.c b/drivers/staging/lustre/lustre/lov/lovsub_lock.c index 80305aa6171235..62b696d25d8124 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_lock.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_lock.c @@ -453,7 +453,7 @@ int lovsub_lock_init(const struct lu_env *env, struct cl_object *obj, struct lovsub_lock *lsk; int result; - OBD_SLAB_ALLOC_PTR_GFP(lsk, lovsub_lock_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(lsk, lovsub_lock_kmem, GFP_NOFS); if (lsk != NULL) { INIT_LIST_HEAD(&lsk->lss_parents); cl_lock_slice_add(lock, &lsk->lss_cl, obj, &lovsub_lock_ops); diff --git a/drivers/staging/lustre/lustre/lov/lovsub_object.c b/drivers/staging/lustre/lustre/lov/lovsub_object.c index 89760b3bf3f7ae..57e3629fccee30 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_object.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_object.c @@ -145,7 +145,7 @@ struct lu_object *lovsub_object_alloc(const struct lu_env *env, struct lovsub_object *los; struct lu_object *obj; - OBD_SLAB_ALLOC_PTR_GFP(los, lovsub_object_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(los, lovsub_object_kmem, GFP_NOFS); if (los != NULL) { struct cl_object_header *hdr; diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index 53022ec390f07b..1a8cd98ad6d75c 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -442,9 +442,9 @@ static struct ptlrpc_request *mdc_intent_unlink_pack(struct obd_export *exp, mdc_unlink_pack(req, op_data); req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, - obddev->u.cli.cl_max_mds_easize); + obddev->u.cli.cl_default_mds_easize); req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER, - obddev->u.cli.cl_max_mds_cookiesize); + obddev->u.cli.cl_default_mds_cookiesize); ptlrpc_request_set_replen(req); return req; } @@ -462,6 +462,7 @@ static struct ptlrpc_request *mdc_intent_getattr_pack(struct obd_export *exp, OBD_MD_FLRMTPERM : OBD_MD_FLACL); struct ldlm_intent *lit; int rc; + int easize; req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_LDLM_INTENT_GETATTR); @@ -482,12 +483,15 @@ static struct ptlrpc_request *mdc_intent_getattr_pack(struct obd_export *exp, lit = req_capsule_client_get(&req->rq_pill, &RMF_LDLM_INTENT); lit->opc = (__u64)it->it_op; + if (obddev->u.cli.cl_default_mds_easize > 0) + easize = obddev->u.cli.cl_default_mds_easize; + else + easize = obddev->u.cli.cl_max_mds_easize; + /* pack the intended request */ - mdc_getattr_pack(req, valid, it->it_flags, op_data, - obddev->u.cli.cl_max_mds_easize); + mdc_getattr_pack(req, valid, it->it_flags, op_data, easize); - req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, - obddev->u.cli.cl_max_mds_easize); + req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, easize); if (client_is_remote(exp)) req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER, sizeof(struct mdt_remote_perm)); @@ -528,7 +532,7 @@ static struct ptlrpc_request *mdc_intent_layout_pack(struct obd_export *exp, layout->li_opc = LAYOUT_INTENT_ACCESS; req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER, - obd->u.cli.cl_max_mds_easize); + obd->u.cli.cl_default_mds_easize); ptlrpc_request_set_replen(req); return req; } @@ -893,7 +897,10 @@ int mdc_enqueue(struct obd_export *exp, struct ldlm_enqueue_info *einfo, mdc_put_rpc_lock(obddev->u.cli.cl_rpc_lock, it); if (rc < 0) { - CERROR("ldlm_cli_enqueue: %d\n", rc); + CDEBUG_LIMIT((rc == -EACCES || rc == -EIDRM) ? D_INFO : D_ERROR, + "%s: ldlm_cli_enqueue failed: rc = %d\n", + obddev->obd_name, rc); + mdc_clear_replay_flag(req, rc); ptlrpc_req_finished(req); return rc; diff --git a/drivers/staging/lustre/lustre/mdc/mdc_reint.c b/drivers/staging/lustre/lustre/mdc/mdc_reint.c index d79aa1641feffa..08e80940ee4dc8 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_reint.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_reint.c @@ -199,7 +199,8 @@ int mdc_setattr(struct obd_export *exp, struct md_op_data *op_data, *request = req; if (rc && req->rq_commit_cb) { /* Put an extra reference on \var mod on error case. */ - obd_mod_put(*mod); + if (mod != NULL && *mod != NULL) + obd_mod_put(*mod); req->rq_commit_cb(req); } return rc; @@ -357,9 +358,9 @@ int mdc_unlink(struct obd_export *exp, struct md_op_data *op_data, mdc_unlink_pack(req, op_data); req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, - obd->u.cli.cl_max_mds_easize); + obd->u.cli.cl_default_mds_easize); req_capsule_set_size(&req->rq_pill, &RMF_LOGCOOKIES, RCL_SERVER, - obd->u.cli.cl_max_mds_cookiesize); + obd->u.cli.cl_default_mds_cookiesize); ptlrpc_request_set_replen(req); *request = req; @@ -470,9 +471,9 @@ int mdc_rename(struct obd_export *exp, struct md_op_data *op_data, mdc_rename_pack(req, op_data, old, oldlen, new, newlen); req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, - obd->u.cli.cl_max_mds_easize); + obd->u.cli.cl_default_mds_easize); req_capsule_set_size(&req->rq_pill, &RMF_LOGCOOKIES, RCL_SERVER, - obd->u.cli.cl_max_mds_cookiesize); + obd->u.cli.cl_default_mds_cookiesize); ptlrpc_request_set_replen(req); rc = mdc_reint(req, obd->u.cli.cl_rpc_lock, LUSTRE_IMP_FULL); diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index bde9f93c149bf0..fca43cf1d67105 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -903,9 +903,9 @@ int mdc_close(struct obd_export *exp, struct md_op_data *op_data, mdc_close_pack(req, op_data); req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, - obd->u.cli.cl_max_mds_easize); + obd->u.cli.cl_default_mds_easize); req_capsule_set_size(&req->rq_pill, &RMF_LOGCOOKIES, RCL_SERVER, - obd->u.cli.cl_max_mds_cookiesize); + obd->u.cli.cl_default_mds_cookiesize); ptlrpc_request_set_replen(req); @@ -2153,12 +2153,40 @@ int mdc_get_info(const struct lu_env *env, struct obd_export *exp, if (*vallen != sizeof(int)) return -EINVAL; - mdsize = *(int*)val; + mdsize = *(int *)val; if (mdsize > exp->exp_obd->u.cli.cl_max_mds_easize) exp->exp_obd->u.cli.cl_max_mds_easize = mdsize; max_easize = val; *max_easize = exp->exp_obd->u.cli.cl_max_mds_easize; return 0; + } else if (KEY_IS(KEY_DEFAULT_EASIZE)) { + int *default_easize; + + if (*vallen != sizeof(int)) + return -EINVAL; + default_easize = val; + *default_easize = exp->exp_obd->u.cli.cl_default_mds_easize; + return 0; + } else if (KEY_IS(KEY_MAX_COOKIESIZE)) { + int mdsize, *max_cookiesize; + + if (*vallen != sizeof(int)) + return -EINVAL; + mdsize = *(int *)val; + if (mdsize > exp->exp_obd->u.cli.cl_max_mds_cookiesize) + exp->exp_obd->u.cli.cl_max_mds_cookiesize = mdsize; + max_cookiesize = val; + *max_cookiesize = exp->exp_obd->u.cli.cl_max_mds_cookiesize; + return 0; + } else if (KEY_IS(KEY_DEFAULT_COOKIESIZE)) { + int *default_cookiesize; + + if (*vallen != sizeof(int)) + return -EINVAL; + default_cookiesize = val; + *default_cookiesize = + exp->exp_obd->u.cli.cl_default_mds_cookiesize; + return 0; } else if (KEY_IS(KEY_CONN_DATA)) { struct obd_import *imp = class_exp2cliimp(exp); struct obd_connect_data *data = val; @@ -2439,11 +2467,15 @@ static int mdc_setup(struct obd_device *obd, struct lustre_cfg *cfg) } /* Initialize the default and maximum LOV EA and cookie sizes. This allows - * us to make MDS RPCs with large enough reply buffers to hold the - * maximum-sized (= maximum striped) EA and cookie without having to - * calculate this (via a call into the LOV + OSCs) each time we make an RPC. */ + * us to make MDS RPCs with large enough reply buffers to hold a default + * sized EA and cookie without having to calculate this (via a call into the + * LOV + OSCs) each time we make an RPC. The maximum size is also tracked + * but not used to avoid wastefully vmalloc()'ing large reply buffers when + * a large number of stripes is possible. If a larger reply buffer is + * required it will be reallocated in the ptlrpc layer due to overflow. + */ static int mdc_init_ea_size(struct obd_export *exp, int easize, - int def_easize, int cookiesize) + int def_easize, int cookiesize, int def_cookiesize) { struct obd_device *obd = exp->exp_obd; struct client_obd *cli = &obd->u.cli; @@ -2457,6 +2489,9 @@ static int mdc_init_ea_size(struct obd_export *exp, int easize, if (cli->cl_max_mds_cookiesize < cookiesize) cli->cl_max_mds_cookiesize = cookiesize; + if (cli->cl_default_mds_cookiesize < def_cookiesize) + cli->cl_default_mds_cookiesize = def_cookiesize; + return 0; } diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c index de9fb1433eddf7..a806aeffe02618 100644 --- a/drivers/staging/lustre/lustre/mgc/mgc_request.c +++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c @@ -672,8 +672,8 @@ static int mgc_fs_setup(struct obd_device *obd, struct super_block *sb) if (env == NULL) return -ENOMEM; - /* The mgc fs exclusion sem. Only one fs can be setup at a time. */ - down(&cli->cl_mgc_sem); + /* The mgc fs exclusion mutex. Only one fs can be setup at a time. */ + mutex_lock(&cli->cl_mgc_mutex); cfs_cleanup_group_info(); @@ -727,7 +727,7 @@ static int mgc_fs_setup(struct obd_device *obd, struct super_block *sb) if (rc < 0) { local_oid_storage_fini(env, cli->cl_mgc_los); cli->cl_mgc_los = NULL; - up(&cli->cl_mgc_sem); + mutex_unlock(&cli->cl_mgc_mutex); } out_env: lu_env_fini(env); @@ -759,7 +759,7 @@ static int mgc_fs_cleanup(struct obd_device *obd) unlock: class_decref(obd, "mgc_fs", obd); - up(&cli->cl_mgc_sem); + mutex_unlock(&cli->cl_mgc_mutex); return 0; } diff --git a/drivers/staging/lustre/lustre/obdclass/cl_lock.c b/drivers/staging/lustre/lustre/obdclass/cl_lock.c index d795cef3f16452..df77c4fc0eacdd 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_lock.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_lock.c @@ -139,7 +139,7 @@ static void cl_lock_trace0(int level, const struct lu_env *env, func, line); } #define cl_lock_trace(level, env, prefix, lock) \ - cl_lock_trace0(level, env, prefix, lock, __FUNCTION__, __LINE__) + cl_lock_trace0(level, env, prefix, lock, __func__, __LINE__) #define RETIP ((unsigned long)__builtin_return_address(0)) @@ -360,7 +360,7 @@ static struct cl_lock *cl_lock_alloc(const struct lu_env *env, struct cl_lock *lock; struct lu_object_header *head; - OBD_SLAB_ALLOC_PTR_GFP(lock, cl_lock_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(lock, cl_lock_kmem, GFP_NOFS); if (lock != NULL) { atomic_set(&lock->cll_ref, 1); lock->cll_descr = *descr; @@ -478,7 +478,7 @@ static struct cl_lock *cl_lock_lookup(const struct lu_env *env, struct cl_object_header *head; head = cl_object_header(obj); - LINVRNT(spin_is_locked(&head->coh_lock_guard)); + assert_spin_locked(&head->coh_lock_guard); CS_LOCK_INC(obj, lookup); list_for_each_entry(lock, &head->coh_locks, cll_linkage) { int matched; @@ -533,6 +533,7 @@ static struct cl_lock *cl_lock_find(const struct lu_env *env, spin_lock(&head->coh_lock_guard); ghost = cl_lock_lookup(env, obj, io, need); if (ghost == NULL) { + cl_lock_get_trust(lock); list_add_tail(&lock->cll_linkage, &head->coh_locks); spin_unlock(&head->coh_lock_guard); @@ -791,15 +792,22 @@ static void cl_lock_delete0(const struct lu_env *env, struct cl_lock *lock) LINVRNT(cl_lock_invariant(env, lock)); if (lock->cll_state < CLS_FREEING) { + bool in_cache; + LASSERT(lock->cll_state != CLS_INTRANSIT); cl_lock_state_set(env, lock, CLS_FREEING); head = cl_object_header(lock->cll_descr.cld_obj); spin_lock(&head->coh_lock_guard); - list_del_init(&lock->cll_linkage); + in_cache = !list_empty(&lock->cll_linkage); + if (in_cache) + list_del_init(&lock->cll_linkage); spin_unlock(&head->coh_lock_guard); + if (in_cache) /* coh_locks cache holds a refcount. */ + cl_lock_put(env, lock); + /* * From now on, no new references to this lock can be acquired * by cl_lock_lookup(). diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c index 0fc256f59e92ae..41cbc95b916e2d 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_object.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c @@ -220,7 +220,7 @@ int cl_object_attr_get(const struct lu_env *env, struct cl_object *obj, struct lu_object_header *top; int result; - LASSERT(spin_is_locked(cl_object_attr_guard(obj))); + assert_spin_locked(cl_object_attr_guard(obj)); top = obj->co_lu.lo_header; result = 0; @@ -251,7 +251,7 @@ int cl_object_attr_set(const struct lu_env *env, struct cl_object *obj, struct lu_object_header *top; int result; - LASSERT(spin_is_locked(cl_object_attr_guard(obj))); + assert_spin_locked(cl_object_attr_guard(obj)); top = obj->co_lu.lo_header; result = 0; @@ -684,7 +684,7 @@ static struct lu_env *cl_env_new(__u32 ctx_tags, __u32 ses_tags, void *debug) struct lu_env *env; struct cl_env *cle; - OBD_SLAB_ALLOC_PTR_GFP(cle, cl_env_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(cle, cl_env_kmem, GFP_NOFS); if (cle != NULL) { int rc; diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c index 2a5ce376e57774..1b616e4fe140b4 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c @@ -130,7 +130,7 @@ struct cl_page *cl_page_lookup(struct cl_object_header *hdr, pgoff_t index) { struct cl_page *page; - LASSERT(spin_is_locked(&hdr->coh_page_guard)); + assert_spin_locked(&hdr->coh_page_guard); page = radix_tree_lookup(&hdr->coh_tree, index); if (page != NULL) @@ -292,7 +292,7 @@ static struct cl_page *cl_page_alloc(const struct lu_env *env, struct lu_object_header *head; OBD_ALLOC_GFP(page, cl_object_header(o)->coh_page_bufsize, - __GFP_IO); + GFP_NOFS); if (page != NULL) { int result = 0; atomic_set(&page->cp_ref, 1); diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c index c93131e0d2dada..dde04b767a6d5a 100644 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c @@ -102,23 +102,17 @@ EXPORT_SYMBOL(obd_dirty_transit_pages); char obd_jobid_var[JOBSTATS_JOBID_VAR_MAX_LEN + 1] = JOBSTATS_DISABLE; EXPORT_SYMBOL(obd_jobid_var); -/* Get jobid of current process by reading the environment variable - * stored in between the "env_start" & "env_end" of task struct. - * - * TODO: - * It's better to cache the jobid for later use if there is any - * efficient way, the cl_env code probably could be reused for this - * purpose. +char obd_jobid_node[JOBSTATS_JOBID_SIZE + 1]; + +/* Get jobid of current process from stored variable or calculate + * it from pid and user_id. * - * If some job scheduler doesn't store jobid in the "env_start/end", - * then an upcall could be issued here to get the jobid by utilizing - * the userspace tools/api. Then, the jobid must be cached. + * Historically this was also done by reading the environment variable + * stored in between the "env_start" & "env_end" of task struct. + * This is now deprecated. */ int lustre_get_jobid(char *jobid) { - int jobid_len = JOBSTATS_JOBID_SIZE; - int rc = 0; - memset(jobid, 0, JOBSTATS_JOBID_SIZE); /* Jobstats isn't enabled */ if (strcmp(obd_jobid_var, JOBSTATS_DISABLE) == 0) @@ -132,31 +126,13 @@ int lustre_get_jobid(char *jobid) return 0; } - rc = cfs_get_environ(obd_jobid_var, jobid, &jobid_len); - if (rc) { - if (rc == -EOVERFLOW) { - /* For the PBS_JOBID and LOADL_STEP_ID keys (which are - * variable length strings instead of just numbers), it - * might make sense to keep the unique parts for JobID, - * instead of just returning an error. That means a - * larger temp buffer for cfs_get_environ(), then - * truncating the string at some separator to fit into - * the specified jobid_len. Fix later if needed. */ - static bool printed; - if (unlikely(!printed)) { - LCONSOLE_ERROR_MSG(0x16b, "%s value too large " - "for JobID buffer (%d)\n", - obd_jobid_var, jobid_len); - printed = true; - } - } else { - CDEBUG((rc == -ENOENT || rc == -EINVAL || - rc == -EDEADLK) ? D_INFO : D_ERROR, - "Get jobid for (%s) failed: rc = %d\n", - obd_jobid_var, rc); - } + /* Whole node dedicated to single job */ + if (strcmp(obd_jobid_var, JOBSTATS_NODELOCAL) == 0) { + strcpy(jobid, obd_jobid_node); + return 0; } - return rc; + + return -ENOENT; } EXPORT_SYMBOL(lustre_get_jobid); diff --git a/drivers/staging/lustre/lustre/obdclass/debug.c b/drivers/staging/lustre/lustre/obdclass/debug.c index 15f71bbb7276af..a4e7e754177f62 100644 --- a/drivers/staging/lustre/lustre/obdclass/debug.c +++ b/drivers/staging/lustre/lustre/obdclass/debug.c @@ -56,18 +56,6 @@ void dump_lniobuf(struct niobuf_local *nb) } EXPORT_SYMBOL(dump_lniobuf); -void dump_lsm(int level, struct lov_stripe_md *lsm) -{ - CDEBUG(level, "lsm %p, objid "DOSTID", maxbytes "LPX64", magic 0x%08X," - " stripe_size %u, stripe_count %u, refc: %d," - " layout_gen %u, pool ["LOV_POOLNAMEF"]\n", lsm, - POSTID(&lsm->lsm_oi), lsm->lsm_maxbytes, lsm->lsm_magic, - lsm->lsm_stripe_size, lsm->lsm_stripe_count, - atomic_read(&lsm->lsm_refc), lsm->lsm_layout_gen, - lsm->lsm_pool_name); -} -EXPORT_SYMBOL(dump_lsm); - #define LPDS sizeof(__u64) int block_debug_setup(void *addr, int len, __u64 off, __u64 id) { diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c index f2bdea33041da2..3210ad8184b9e6 100644 --- a/drivers/staging/lustre/lustre/obdclass/genops.c +++ b/drivers/staging/lustre/lustre/obdclass/genops.c @@ -72,7 +72,7 @@ static struct obd_device *obd_device_alloc(void) { struct obd_device *obd; - OBD_SLAB_ALLOC_PTR_GFP(obd, obd_device_cachep, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(obd, obd_device_cachep, GFP_NOFS); if (obd != NULL) { obd->obd_magic = OBD_DEVICE_MAGIC; } @@ -615,13 +615,13 @@ int class_notify_sptlrpc_conf(const char *fsname, int namelen) if (strncmp(obd->obd_name, fsname, namelen)) continue; - class_incref(obd, __FUNCTION__, obd); + class_incref(obd, __func__, obd); read_unlock(&obd_dev_lock); rc2 = obd_set_info_async(NULL, obd->obd_self_export, sizeof(KEY_SPTLRPC_CONF), KEY_SPTLRPC_CONF, 0, NULL, NULL); rc = rc ? rc : rc2; - class_decref(obd, __FUNCTION__, obd); + class_decref(obd, __func__, obd); read_lock(&obd_dev_lock); } read_unlock(&obd_dev_lock); diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c index ba20776ebfa142..bdf2eed2952ab0 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c @@ -122,6 +122,8 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg) OBD_FREE_LARGE(*buf, hdr.ioc_len); return err; } + if (hdr.ioc_len != data->ioc_len) + return -EINVAL; if (obd_ioctl_is_invalid(data)) { CERROR("ioctl not correctly formatted\n"); @@ -244,7 +246,7 @@ static int obd_proc_health_seq_show(struct seq_file *m, void *v) if (obd->obd_stopping) continue; - class_incref(obd, __FUNCTION__, current); + class_incref(obd, __func__, current); read_unlock(&obd_dev_lock); if (obd_health_check(NULL, obd)) { @@ -252,7 +254,7 @@ static int obd_proc_health_seq_show(struct seq_file *m, void *v) obd->obd_name); rc++; } - class_decref(obd, __FUNCTION__, current); + class_decref(obd, __func__, current); read_lock(&obd_dev_lock); } read_unlock(&obd_dev_lock); @@ -277,12 +279,44 @@ static ssize_t obd_proc_jobid_var_seq_write(struct file *file, const char *buffe return -EINVAL; memset(obd_jobid_var, 0, JOBSTATS_JOBID_VAR_MAX_LEN + 1); + + /* This might leave the var invalid on error, which is probably fine.*/ + if (copy_from_user(obd_jobid_var, buffer, count)) + return -EFAULT; + /* Trim the trailing '\n' if any */ - memcpy(obd_jobid_var, buffer, count - (buffer[count - 1] == '\n')); + if (obd_jobid_var[count - 1] == '\n') + obd_jobid_var[count - 1] = 0; + return count; } LPROC_SEQ_FOPS(obd_proc_jobid_var); +static int obd_proc_jobid_name_seq_show(struct seq_file *m, void *v) +{ + return seq_printf(m, "%s\n", obd_jobid_var); +} + +static ssize_t obd_proc_jobid_name_seq_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *off) +{ + if (!count || count > JOBSTATS_JOBID_SIZE) + return -EINVAL; + + if (copy_from_user(obd_jobid_node, buffer, count)) + return -EFAULT; + + obd_jobid_node[count] = 0; + + /* Trim the trailing '\n' if any */ + if (obd_jobid_node[count - 1] == '\n') + obd_jobid_node[count - 1] = 0; + + return count; +} +LPROC_SEQ_FOPS(obd_proc_jobid_name); + /* Root for /proc/fs/lustre */ struct proc_dir_entry *proc_lustre_root = NULL; EXPORT_SYMBOL(proc_lustre_root); @@ -292,6 +326,8 @@ struct lprocfs_vars lprocfs_base[] = { { "pinger", &obd_proc_pinger_fops }, { "health_check", &obd_proc_health_fops }, { "jobid_var", &obd_proc_jobid_var_fops }, + { .name = "jobid_name", + .fops = &obd_proc_jobid_name_fops}, { 0 } }; diff --git a/drivers/staging/lustre/lustre/obdclass/llog_obd.c b/drivers/staging/lustre/lustre/obdclass/llog_obd.c index 71817af75396fa..2c6d81eb5c6541 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/llog_obd.c @@ -226,34 +226,7 @@ int llog_sync(struct llog_ctxt *ctxt, struct obd_export *exp, int flags) } EXPORT_SYMBOL(llog_sync); -int llog_obd_add(const struct lu_env *env, struct llog_ctxt *ctxt, - struct llog_rec_hdr *rec, struct lov_stripe_md *lsm, - struct llog_cookie *logcookies, int numcookies) -{ - int raised, rc; - - if (!ctxt) { - CERROR("No ctxt\n"); - return -ENODEV; - } - - if (ctxt->loc_flags & LLOG_CTXT_FLAG_UNINITIALIZED) - return -ENXIO; - - CTXT_CHECK_OP(ctxt, obd_add, -EOPNOTSUPP); - raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE); - if (!raised) - cfs_cap_raise(CFS_CAP_SYS_RESOURCE); - rc = CTXTP(ctxt, obd_add)(env, ctxt, rec, lsm, logcookies, - numcookies); - if (!raised) - cfs_cap_lower(CFS_CAP_SYS_RESOURCE); - return rc; -} -EXPORT_SYMBOL(llog_obd_add); - int llog_cancel(const struct lu_env *env, struct llog_ctxt *ctxt, - struct lov_stripe_md *lsm, int count, struct llog_cookie *cookies, int flags) { int rc; @@ -264,7 +237,7 @@ int llog_cancel(const struct lu_env *env, struct llog_ctxt *ctxt, } CTXT_CHECK_OP(ctxt, cancel, -EOPNOTSUPP); - rc = CTXTP(ctxt, cancel)(env, ctxt, lsm, count, cookies, flags); + rc = CTXTP(ctxt, cancel)(env, ctxt, cookies, flags); return rc; } EXPORT_SYMBOL(llog_cancel); diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c index 6f8ba54e9667a3..419a32361359d1 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c @@ -187,7 +187,7 @@ int lustre_start_simple(char *obdname, char *type, char *uuid, int rc; CDEBUG(D_MOUNT, "Starting obd %s (typ=%s)\n", obdname, type); - rc = do_lcfg(obdname, 0, LCFG_ATTACH, type, uuid, 0, 0); + rc = do_lcfg(obdname, 0, LCFG_ATTACH, type, uuid, NULL, NULL); if (rc) { CERROR("%s attach error %d\n", obdname, rc); return rc; @@ -195,7 +195,7 @@ int lustre_start_simple(char *obdname, char *type, char *uuid, rc = do_lcfg(obdname, 0, LCFG_SETUP, s1, s2, s3, s4); if (rc) { CERROR("%s setup error %d\n", obdname, rc); - do_lcfg(obdname, 0, LCFG_DETACH, 0, 0, 0, 0); + do_lcfg(obdname, 0, LCFG_DETACH, NULL, NULL, NULL, NULL); } return rc; } @@ -337,7 +337,8 @@ int lustre_start_mgc(struct super_block *sb) lnet_process_id_t id; while ((rc = LNetGetId(i++, &id)) != -ENOENT) { rc = do_lcfg(mgcname, id.nid, - LCFG_ADD_UUID, niduuid, 0,0,0); + LCFG_ADD_UUID, niduuid, + NULL, NULL, NULL); } } else { /* Use mgsnode= nids */ @@ -351,7 +352,8 @@ int lustre_start_mgc(struct super_block *sb) } while (class_parse_nid(ptr, &nid, &ptr) == 0) { rc = do_lcfg(mgcname, nid, - LCFG_ADD_UUID, niduuid, 0,0,0); + LCFG_ADD_UUID, niduuid, + NULL, NULL, NULL); i++; } } @@ -360,7 +362,7 @@ int lustre_start_mgc(struct super_block *sb) ptr = lsi->lsi_lmd->lmd_dev; while (class_parse_nid(ptr, &nid, &ptr) == 0) { rc = do_lcfg(mgcname, nid, - LCFG_ADD_UUID, niduuid, 0,0,0); + LCFG_ADD_UUID, niduuid, NULL, NULL, NULL); i++; /* Stop at the first failover nid */ if (*ptr == ':') @@ -396,13 +398,13 @@ int lustre_start_mgc(struct super_block *sb) while (class_parse_nid_quiet(ptr, &nid, &ptr) == 0) { j++; rc = do_lcfg(mgcname, nid, - LCFG_ADD_UUID, niduuid, 0,0,0); + LCFG_ADD_UUID, niduuid, NULL, NULL, NULL); if (*ptr == ':') break; } if (j > 0) { rc = do_lcfg(mgcname, 0, LCFG_ADD_CONN, - niduuid, 0, 0, 0); + niduuid, NULL, NULL, NULL); i++; } else { /* at ":/fsname" */ @@ -532,7 +534,7 @@ static int lustre_stop_mgc(struct super_block *sb) for (i = 0; i < lsi->lsi_lmd->lmd_mgs_failnodes; i++) { sprintf(ptr, "_%x", i); rc = do_lcfg(LUSTRE_MGC_OBDNAME, 0, LCFG_DEL_UUID, - niduuid, 0, 0, 0); + niduuid, NULL, NULL, NULL); if (rc) CERROR("del MDC UUID %s failed: rc = %d\n", niduuid, rc); diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c index 754aa8e5566526..cdc46719bbd47a 100644 --- a/drivers/staging/lustre/lustre/obdecho/echo_client.c +++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c @@ -47,7 +47,6 @@ #include #include #include -#include #include "echo_internal.h" @@ -428,7 +427,7 @@ static int echo_lock_init(const struct lu_env *env, { struct echo_lock *el; - OBD_SLAB_ALLOC_PTR_GFP(el, echo_lock_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(el, echo_lock_kmem, GFP_NOFS); if (el != NULL) { cl_lock_slice_add(lock, &el->el_cl, obj, &echo_lock_ops); el->el_object = cl2echo_obj(obj); @@ -599,7 +598,7 @@ static struct lu_object *echo_object_alloc(const struct lu_env *env, /* we're the top dev. */ LASSERT(hdr == NULL); - OBD_SLAB_ALLOC_PTR_GFP(eco, echo_object_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(eco, echo_object_kmem, GFP_NOFS); if (eco != NULL) { struct cl_object_header *hdr = &eco->eo_hdr; @@ -663,7 +662,7 @@ static void *echo_thread_key_init(const struct lu_context *ctx, { struct echo_thread_info *info; - OBD_SLAB_ALLOC_PTR_GFP(info, echo_thread_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(info, echo_thread_kmem, GFP_NOFS); if (info == NULL) info = ERR_PTR(-ENOMEM); return info; @@ -693,7 +692,7 @@ static void *echo_session_key_init(const struct lu_context *ctx, { struct echo_session_info *session; - OBD_SLAB_ALLOC_PTR_GFP(session, echo_session_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(session, echo_session_kmem, GFP_NOFS); if (session == NULL) session = ERR_PTR(-ENOMEM); return session; @@ -2432,7 +2431,7 @@ static int echo_client_kbrw(struct echo_device *ed, int rw, struct obdo *oa, int i; int rc; int verify; - int gfp_mask; + gfp_t gfp_mask; int brw_flags = 0; verify = (ostid_id(&oa->o_oi) != ECHO_PERSISTENT_OBJID && diff --git a/drivers/staging/lustre/lustre/osc/lproc_osc.c b/drivers/staging/lustre/lustre/osc/lproc_osc.c index 0b59fc16c50cd9..358e32cd05d27a 100644 --- a/drivers/staging/lustre/lustre/osc/lproc_osc.c +++ b/drivers/staging/lustre/lustre/osc/lproc_osc.c @@ -174,15 +174,25 @@ static int osc_cached_mb_seq_show(struct seq_file *m, void *v) } /* shrink the number of caching pages to a specific number */ -static ssize_t osc_cached_mb_seq_write(struct file *file, const char *buffer, - size_t count, loff_t *off) +static ssize_t osc_cached_mb_seq_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *off) { struct obd_device *dev = ((struct seq_file *)file->private_data)->private; struct client_obd *cli = &dev->u.cli; int pages_number, mult, rc; + char kernbuf[128]; + + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; mult = 1 << (20 - PAGE_CACHE_SHIFT); - buffer = lprocfs_find_named_value(buffer, "used_mb:", &count); + buffer += lprocfs_find_named_value(kernbuf, "used_mb:", &count) - + kernbuf; rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult); if (rc) return rc; diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index fe9989a49f81da..00f38eeb578659 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -1311,7 +1311,7 @@ static int osc_completion(const struct lu_env *env, struct osc_async_page *oap, static void osc_consume_write_grant(struct client_obd *cli, struct brw_page *pga) { - LASSERT(spin_is_locked(&cli->cl_loi_list_lock.lock)); + assert_spin_locked(&cli->cl_loi_list_lock.lock); LASSERT(!(pga->flag & OBD_BRW_FROM_GRANT)); atomic_inc(&obd_dirty_pages); cli->cl_dirty += PAGE_CACHE_SIZE; @@ -1326,7 +1326,7 @@ static void osc_consume_write_grant(struct client_obd *cli, static void osc_release_write_grant(struct client_obd *cli, struct brw_page *pga) { - LASSERT(spin_is_locked(&cli->cl_loi_list_lock.lock)); + assert_spin_locked(&cli->cl_loi_list_lock.lock); if (!(pga->flag & OBD_BRW_FROM_GRANT)) { return; } diff --git a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h index 9e7899fa4cc491..e74b7bb9776cec 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h +++ b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h @@ -176,7 +176,16 @@ static inline void osc_object_unlock(struct osc_object *obj) static inline int osc_object_is_locked(struct osc_object *obj) { +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) return spin_is_locked(&obj->oo_lock); +#else + /* + * It is not perfect to return true all the time. + * But since this function is only used for assertion + * and checking, it seems OK. + */ + return 1; +#endif } /* diff --git a/drivers/staging/lustre/lustre/osc/osc_dev.c b/drivers/staging/lustre/lustre/osc/osc_dev.c index 35f25786763719..6a6483920c4d9b 100644 --- a/drivers/staging/lustre/lustre/osc/osc_dev.c +++ b/drivers/staging/lustre/lustre/osc/osc_dev.c @@ -122,7 +122,7 @@ static void *osc_key_init(const struct lu_context *ctx, { struct osc_thread_info *info; - OBD_SLAB_ALLOC_PTR_GFP(info, osc_thread_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(info, osc_thread_kmem, GFP_NOFS); if (info == NULL) info = ERR_PTR(-ENOMEM); return info; @@ -146,7 +146,7 @@ static void *osc_session_init(const struct lu_context *ctx, { struct osc_session *info; - OBD_SLAB_ALLOC_PTR_GFP(info, osc_session_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(info, osc_session_kmem, GFP_NOFS); if (info == NULL) info = ERR_PTR(-ENOMEM); return info; diff --git a/drivers/staging/lustre/lustre/osc/osc_io.c b/drivers/staging/lustre/lustre/osc/osc_io.c index 5f3c545418d11c..09e06eb085302b 100644 --- a/drivers/staging/lustre/lustre/osc/osc_io.c +++ b/drivers/staging/lustre/lustre/osc/osc_io.c @@ -509,12 +509,11 @@ static void osc_io_setattr_end(const struct lu_env *env, static int osc_io_read_start(const struct lu_env *env, const struct cl_io_slice *slice) { - struct osc_io *oio = cl2osc_io(env, slice); struct cl_object *obj = slice->cis_obj; struct cl_attr *attr = &osc_env_info(env)->oti_attr; int rc = 0; - if (oio->oi_lockless == 0 && !slice->cis_io->ci_noatime) { + if (!slice->cis_io->ci_noatime) { cl_object_attr_lock(obj); attr->cat_atime = LTIME_S(CURRENT_TIME); rc = cl_object_attr_set(env, obj, attr, CAT_ATIME); @@ -526,24 +525,17 @@ static int osc_io_read_start(const struct lu_env *env, static int osc_io_write_start(const struct lu_env *env, const struct cl_io_slice *slice) { - struct osc_io *oio = cl2osc_io(env, slice); struct cl_object *obj = slice->cis_obj; struct cl_attr *attr = &osc_env_info(env)->oti_attr; - int result = 0; + int rc = 0; - if (oio->oi_lockless == 0) { - OBD_FAIL_TIMEOUT(OBD_FAIL_OSC_DELAY_SETTIME, 1); - cl_object_attr_lock(obj); - result = cl_object_attr_get(env, obj, attr); - if (result == 0) { - attr->cat_mtime = attr->cat_ctime = - LTIME_S(CURRENT_TIME); - result = cl_object_attr_set(env, obj, attr, - CAT_MTIME | CAT_CTIME); - } - cl_object_attr_unlock(obj); - } - return result; + OBD_FAIL_TIMEOUT(OBD_FAIL_OSC_DELAY_SETTIME, 1); + cl_object_attr_lock(obj); + attr->cat_mtime = attr->cat_ctime = LTIME_S(CURRENT_TIME); + rc = cl_object_attr_set(env, obj, attr, CAT_MTIME | CAT_CTIME); + cl_object_attr_unlock(obj); + + return rc; } static int osc_fsync_ost(const struct lu_env *env, struct osc_object *obj, @@ -812,7 +804,7 @@ int osc_req_init(const struct lu_env *env, struct cl_device *dev, struct osc_req *or; int result; - OBD_SLAB_ALLOC_PTR_GFP(or, osc_req_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(or, osc_req_kmem, GFP_NOFS); if (or != NULL) { cl_req_slice_add(req, &or->or_cl, dev, &osc_req_ops); result = 0; diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c index ef7b9c2b208ecb..a46129bec17af7 100644 --- a/drivers/staging/lustre/lustre/osc/osc_lock.c +++ b/drivers/staging/lustre/lustre/osc/osc_lock.c @@ -1192,6 +1192,7 @@ static int osc_lock_wait(const struct lu_env *env, LASSERT(olck->ols_agl); olck->ols_agl = 0; + olck->ols_flags &= ~LDLM_FL_BLOCK_NOWAIT; rc = osc_lock_enqueue(env, slice, NULL, CEF_ASYNC | CEF_MUST); if (rc != 0) return rc; @@ -1558,7 +1559,7 @@ int osc_lock_init(const struct lu_env *env, struct osc_lock *clk; int result; - OBD_SLAB_ALLOC_PTR_GFP(clk, osc_lock_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(clk, osc_lock_kmem, GFP_NOFS); if (clk != NULL) { __u32 enqflags = lock->cll_descr.cld_enq_flags; diff --git a/drivers/staging/lustre/lustre/osc/osc_object.c b/drivers/staging/lustre/lustre/osc/osc_object.c index 9d34de873fac8e..f9bfdc82012562 100644 --- a/drivers/staging/lustre/lustre/osc/osc_object.c +++ b/drivers/staging/lustre/lustre/osc/osc_object.c @@ -260,7 +260,7 @@ struct lu_object *osc_object_alloc(const struct lu_env *env, struct osc_object *osc; struct lu_object *obj; - OBD_SLAB_ALLOC_PTR_GFP(osc, osc_object_kmem, __GFP_IO); + OBD_SLAB_ALLOC_PTR_GFP(osc, osc_object_kmem, GFP_NOFS); if (osc != NULL) { obj = osc2lu(osc); lu_object_init(obj, NULL, dev); diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index ee6953ac7353f9..294db843012b95 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index 4c9e006950878a..7246e8ce9c1965 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -379,6 +379,34 @@ static int ptlrpc_at_recv_early_reply(struct ptlrpc_request *req) return rc; } +struct kmem_cache *request_cache; + +int ptlrpc_request_cache_init(void) +{ + request_cache = kmem_cache_create("ptlrpc_cache", + sizeof(struct ptlrpc_request), + 0, SLAB_HWCACHE_ALIGN, NULL); + return request_cache == NULL ? -ENOMEM : 0; +} + +void ptlrpc_request_cache_fini(void) +{ + kmem_cache_destroy(request_cache); +} + +struct ptlrpc_request *ptlrpc_request_cache_alloc(int flags) +{ + struct ptlrpc_request *req; + + OBD_SLAB_ALLOC_PTR_GFP(req, request_cache, flags); + return req; +} + +void ptlrpc_request_cache_free(struct ptlrpc_request *req) +{ + OBD_SLAB_FREE_PTR(req, request_cache); +} + /** * Wind down request pool \a pool. * Frees all requests from the pool too @@ -397,7 +425,7 @@ void ptlrpc_free_rq_pool(struct ptlrpc_request_pool *pool) LASSERT(req->rq_reqbuf); LASSERT(req->rq_reqbuf_len == pool->prp_rq_size); OBD_FREE_LARGE(req->rq_reqbuf, pool->prp_rq_size); - OBD_FREE(req, sizeof(*req)); + ptlrpc_request_cache_free(req); } spin_unlock(&pool->prp_lock); OBD_FREE(pool, sizeof(*pool)); @@ -427,12 +455,12 @@ void ptlrpc_add_rqs_to_pool(struct ptlrpc_request_pool *pool, int num_rq) struct lustre_msg *msg; spin_unlock(&pool->prp_lock); - OBD_ALLOC(req, sizeof(struct ptlrpc_request)); + req = ptlrpc_request_cache_alloc(GFP_NOFS); if (!req) return; OBD_ALLOC_LARGE(msg, size); if (!msg) { - OBD_FREE(req, sizeof(struct ptlrpc_request)); + ptlrpc_request_cache_free(req); return; } req->rq_reqbuf = msg; @@ -668,7 +696,7 @@ struct ptlrpc_request *__ptlrpc_request_alloc(struct obd_import *imp, request = ptlrpc_prep_req_from_pool(pool); if (!request) - OBD_ALLOC_PTR(request); + request = ptlrpc_request_cache_alloc(GFP_NOFS); if (request) { LASSERTF((unsigned long)imp > 0x1000, "%p", imp); @@ -739,7 +767,7 @@ void ptlrpc_request_free(struct ptlrpc_request *request) if (request->rq_pool) __ptlrpc_free_req_to_pool(request); else - OBD_FREE_PTR(request); + ptlrpc_request_cache_free(request); } EXPORT_SYMBOL(ptlrpc_request_free); @@ -2233,7 +2261,7 @@ static void __ptlrpc_free_req(struct ptlrpc_request *request, int locked) if (request->rq_pool) __ptlrpc_free_req_to_pool(request); else - OBD_FREE(request, sizeof(*request)); + ptlrpc_request_cache_free(request); } static int __ptlrpc_req_finished(struct ptlrpc_request *request, int locked); @@ -2243,7 +2271,7 @@ static int __ptlrpc_req_finished(struct ptlrpc_request *request, int locked); */ void ptlrpc_req_finished_with_imp_lock(struct ptlrpc_request *request) { - LASSERT(spin_is_locked(&request->rq_import->imp_lock)); + assert_spin_locked(&request->rq_import->imp_lock); (void)__ptlrpc_req_finished(request, 1); } EXPORT_SYMBOL(ptlrpc_req_finished_with_imp_lock); @@ -2424,9 +2452,7 @@ void ptlrpc_free_committed(struct obd_import *imp) bool skip_committed_list = true; LASSERT(imp != NULL); - - LASSERT(spin_is_locked(&imp->imp_lock)); - + assert_spin_locked(&imp->imp_lock); if (imp->imp_peer_committed_transno == imp->imp_last_transno_checked && imp->imp_generation == imp->imp_last_generation_checked) { @@ -2557,7 +2583,7 @@ void ptlrpc_retain_replayable_request(struct ptlrpc_request *req, { struct list_head *tmp; - LASSERT(spin_is_locked(&imp->imp_lock)); + assert_spin_locked(&imp->imp_lock); if (req->rq_transno == 0) { DEBUG_REQ(D_EMERG, req, "saving request with zero transno"); @@ -3023,7 +3049,7 @@ void *ptlrpcd_alloc_work(struct obd_import *imp, return ERR_PTR(-EINVAL); /* copy some code from deprecated fakereq. */ - OBD_ALLOC_PTR(req); + req = ptlrpc_request_cache_alloc(GFP_NOFS); if (req == NULL) { CERROR("ptlrpc: run out of memory!\n"); return ERR_PTR(-ENOMEM); diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c index 6ea0a491cfb3d3..aa85239f6cd5a7 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/events.c +++ b/drivers/staging/lustre/lustre/ptlrpc/events.c @@ -307,7 +307,7 @@ void request_in_callback(lnet_event_t *ev) /* We moaned above already... */ return; } - OBD_ALLOC_GFP(req, sizeof(*req), ALLOC_ATOMIC_TRY); + req = ptlrpc_request_cache_alloc(ALLOC_ATOMIC_TRY); if (req == NULL) { CERROR("Can't allocate incoming request descriptor: " "Dropping %s RPC from %s\n", diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c index 7852bf30a3a092..93794bd928cbf7 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c +++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c @@ -176,31 +176,31 @@ int gss_cli_ctx_unwrap_bulk(struct ptlrpc_cli_ctx *ctx, switch (SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc)) { case SPTLRPC_SVC_NULL: vmsg = req->rq_repdata; + LASSERT(vmsg != NULL && vmsg->lm_bufcount >= 3); voff = vmsg->lm_bufcount - 1; - LASSERT(vmsg && vmsg->lm_bufcount >= 3); rmsg = req->rq_reqbuf; + LASSERT(rmsg != NULL && rmsg->lm_bufcount >= 3); roff = rmsg->lm_bufcount - 1; /* last segment */ - LASSERT(rmsg && rmsg->lm_bufcount >= 3); break; case SPTLRPC_SVC_AUTH: case SPTLRPC_SVC_INTG: vmsg = req->rq_repdata; + LASSERT(vmsg != NULL && vmsg->lm_bufcount >= 4); voff = vmsg->lm_bufcount - 2; - LASSERT(vmsg && vmsg->lm_bufcount >= 4); rmsg = req->rq_reqbuf; + LASSERT(rmsg != NULL && rmsg->lm_bufcount >= 4); roff = rmsg->lm_bufcount - 2; /* second last segment */ - LASSERT(rmsg && rmsg->lm_bufcount >= 4); break; case SPTLRPC_SVC_PRIV: vmsg = req->rq_repdata; + LASSERT(vmsg != NULL && vmsg->lm_bufcount >= 2); voff = vmsg->lm_bufcount - 1; - LASSERT(vmsg && vmsg->lm_bufcount >= 2); rmsg = req->rq_clrbuf; + LASSERT(rmsg != NULL && rmsg->lm_bufcount >= 2); roff = rmsg->lm_bufcount - 1; /* last segment */ - LASSERT(rmsg && rmsg->lm_bufcount >= 2); break; default: LBUG(); diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c index 7a1ff4fecbe3c3..3be5bc14c4ed58 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c +++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c @@ -137,7 +137,7 @@ void ctx_enhash_pf(struct ptlrpc_cli_ctx *ctx, struct hlist_head *hash) static void ctx_unhash_pf(struct ptlrpc_cli_ctx *ctx, struct hlist_head *freelist) { - LASSERT(spin_is_locked(&ctx->cc_sec->ps_lock)); + assert_spin_locked(&ctx->cc_sec->ps_lock); LASSERT(atomic_read(&ctx->cc_refcount) > 0); LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags)); LASSERT(!hlist_unhashed(&ctx->cc_cache)); @@ -719,7 +719,7 @@ void gss_unhash_msg_nolock(struct gss_upcall_msg *gmsg) __u32 idx = gmsg->gum_mechidx; LASSERT(idx < MECH_MAX); - LASSERT(spin_is_locked(&upcall_locks[idx])); + assert_spin_locked(&upcall_locks[idx]); if (list_empty(&gmsg->gum_list)) return; diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c index 537aa6204a516d..1c73194421a6cc 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/import.c +++ b/drivers/staging/lustre/lustre/ptlrpc/import.c @@ -194,7 +194,7 @@ int ptlrpc_set_import_discon(struct obd_import *imp, __u32 conn_cnt) /* Must be called with imp_lock held! */ static void ptlrpc_deactivate_and_unlock_import(struct obd_import *imp) { - LASSERT(spin_is_locked(&imp->imp_lock)); + assert_spin_locked(&imp->imp_lock); CDEBUG(D_HA, "setting import %s INVALID\n", obd2cli_tgt(imp->imp_obd)); imp->imp_invalid = 1; @@ -381,6 +381,11 @@ void ptlrpc_activate_import(struct obd_import *imp) struct obd_device *obd = imp->imp_obd; spin_lock(&imp->imp_lock); + if (imp->imp_deactive != 0) { + spin_unlock(&imp->imp_lock); + return; + } + imp->imp_invalid = 0; spin_unlock(&imp->imp_lock); obd_import_event(obd, imp, IMP_EVENT_ACTIVE); @@ -1399,26 +1404,33 @@ int ptlrpc_disconnect_import(struct obd_import *imp, int noclose) { struct ptlrpc_request *req; int rq_opc, rc = 0; - int nowait = imp->imp_obd->obd_force; - if (nowait) + if (imp->imp_obd->obd_force) GOTO(set_state, rc); switch (imp->imp_connect_op) { - case OST_CONNECT: rq_opc = OST_DISCONNECT; break; - case MDS_CONNECT: rq_opc = MDS_DISCONNECT; break; - case MGS_CONNECT: rq_opc = MGS_DISCONNECT; break; + case OST_CONNECT: + rq_opc = OST_DISCONNECT; + break; + case MDS_CONNECT: + rq_opc = MDS_DISCONNECT; + break; + case MGS_CONNECT: + rq_opc = MGS_DISCONNECT; + break; default: - CERROR("don't know how to disconnect from %s (connect_op %d)\n", - obd2cli_tgt(imp->imp_obd), imp->imp_connect_op); - return -EINVAL; + rc = -EINVAL; + CERROR("%s: don't know how to disconnect from %s " + "(connect_op %d): rc = %d\n", + imp->imp_obd->obd_name, obd2cli_tgt(imp->imp_obd), + imp->imp_connect_op, rc); + return rc; } if (ptlrpc_import_in_recovery(imp)) { struct l_wait_info lwi; cfs_duration_t timeout; - if (AT_OFF) { if (imp->imp_server_timeout) timeout = cfs_time_seconds(obd_timeout / 2); @@ -1441,7 +1453,6 @@ int ptlrpc_disconnect_import(struct obd_import *imp, int noclose) spin_lock(&imp->imp_lock); if (imp->imp_state != LUSTRE_IMP_FULL) GOTO(out, 0); - spin_unlock(&imp->imp_lock); req = ptlrpc_request_alloc_pack(imp, &RQF_MDS_DISCONNECT, @@ -1474,6 +1485,9 @@ int ptlrpc_disconnect_import(struct obd_import *imp, int noclose) memset(&imp->imp_remote_handle, 0, sizeof(imp->imp_remote_handle)); spin_unlock(&imp->imp_lock); + if (rc == -ETIMEDOUT || rc == -ENOTCONN || rc == -ESHUTDOWN) + rc = 0; + return rc; } EXPORT_SYMBOL(ptlrpc_disconnect_import); diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c index 58f1c8bf25b0b4..6b9c6db1f2df6d 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c @@ -449,7 +449,7 @@ void nrs_policy_get_info_locked(struct ptlrpc_nrs_policy *policy, { LASSERT(policy != NULL); LASSERT(info != NULL); - LASSERT(spin_is_locked(&policy->pol_nrs->nrs_lock)); + assert_spin_locked(&policy->pol_nrs->nrs_lock); memcpy(info->pi_name, policy->pol_desc->pd_name, NRS_POL_NAME_MAX); @@ -1190,7 +1190,7 @@ int lprocfs_wr_evict_client(struct file *file, const char *buffer, * the proc entries under the being destroyed export{}, so I have * to drop the lock at first here. * - jay, jxiong@clusterfs.com */ - class_incref(obd, __FUNCTION__, current); + class_incref(obd, __func__, current); if (strncmp(tmpbuf, "nid:", 4) == 0) obd_export_evict_by_nid(obd, tmpbuf + 4); @@ -1199,7 +1199,7 @@ int lprocfs_wr_evict_client(struct file *file, const char *buffer, else obd_export_evict_by_uuid(obd, tmpbuf); - class_decref(obd, __FUNCTION__, current); + class_decref(obd, __func__, current); out: OBD_FREE(kbuf, BUFLEN); diff --git a/drivers/staging/lustre/lustre/ptlrpc/nrs.c b/drivers/staging/lustre/lustre/ptlrpc/nrs.c index bcba1c8e8693b5..12151aa2a1e510 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/nrs.c +++ b/drivers/staging/lustre/lustre/ptlrpc/nrs.c @@ -746,7 +746,7 @@ static int nrs_policy_register(struct ptlrpc_nrs *nrs, LASSERT(desc->pd_compat != NULL); OBD_CPT_ALLOC_GFP(policy, svcpt->scp_service->srv_cptable, - svcpt->scp_cpt, sizeof(*policy), __GFP_IO); + svcpt->scp_cpt, sizeof(*policy), GFP_NOFS); if (policy == NULL) return -ENOMEM; diff --git a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c index 45c0b84621e4b6..cddeeb6bb23d82 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c @@ -300,6 +300,7 @@ lustre_get_emerg_rs(struct ptlrpc_service_part *svcpt) spin_unlock(&svcpt->scp_rep_lock); memset(rs, 0, svcpt->scp_service->srv_max_reply_size); + rs->rs_size = svcpt->scp_service->srv_max_reply_size; rs->rs_svcpt = svcpt; rs->rs_prealloc = 1; out: diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c index 6dff502ce23e6f..38099d9dfdaeb6 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c @@ -368,7 +368,7 @@ EXPORT_SYMBOL(ptlrpc_pinger_sending_on_import); void ptlrpc_pinger_commit_expected(struct obd_import *imp) { ptlrpc_update_next_ping(imp, 1); - LASSERT(spin_is_locked(&imp->imp_lock)); + assert_spin_locked(&imp->imp_lock); /* * Avoid reading stale imp_connect_data. When not sure if pings are * expected or not on next connection, we assume they are not and force diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h index e3b5a920bca2f5..7c940553059674 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h @@ -55,6 +55,10 @@ int ptlrpcd_start(int index, int max, const char *name, struct ptlrpcd_ctl *pc); /* client.c */ struct ptlrpc_bulk_desc *ptlrpc_new_bulk(unsigned npages, unsigned max_brw, unsigned type, unsigned portal); +int ptlrpc_request_cache_init(void); +void ptlrpc_request_cache_fini(void); +struct ptlrpc_request *ptlrpc_request_cache_alloc(int flags); +void ptlrpc_request_cache_free(struct ptlrpc_request *req); void ptlrpc_init_xid(void); /* events.c */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c index 0efd35887a1599..251ae75c2dd99b 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c @@ -73,29 +73,34 @@ __init int ptlrpc_init(void) return rc; cleanup_phase = 1; + rc = ptlrpc_request_cache_init(); + if (rc) + GOTO(cleanup, rc); + cleanup_phase = 2; rc = ptlrpc_init_portals(); if (rc) GOTO(cleanup, rc); - cleanup_phase = 2; + + cleanup_phase = 3; rc = ptlrpc_connection_init(); if (rc) GOTO(cleanup, rc); - cleanup_phase = 3; + cleanup_phase = 4; ptlrpc_put_connection_superhack = ptlrpc_connection_put; rc = ptlrpc_start_pinger(); if (rc) GOTO(cleanup, rc); - cleanup_phase = 4; + cleanup_phase = 5; rc = ldlm_init(); if (rc) GOTO(cleanup, rc); - cleanup_phase = 5; + cleanup_phase = 6; rc = sptlrpc_init(); if (rc) GOTO(cleanup, rc); @@ -115,19 +120,29 @@ __init int ptlrpc_init(void) switch (cleanup_phase) { case 8: ptlrpc_nrs_fini(); + /* Fall through */ case 7: sptlrpc_fini(); - case 5: + /* Fall through */ + case 6: ldlm_exit(); - case 4: + /* Fall through */ + case 5: ptlrpc_stop_pinger(); - case 3: + /* Fall through */ + case 4: ptlrpc_connection_fini(); - case 2: + /* Fall through */ + case 3: ptlrpc_exit_portals(); + /* Fall through */ + case 2: + ptlrpc_request_cache_fini(); + /* Fall through */ case 1: ptlrpc_hr_fini(); req_layout_fini(); + /* Fall through */ default: ; } @@ -142,6 +157,7 @@ static void __exit ptlrpc_exit(void) ldlm_exit(); ptlrpc_stop_pinger(); ptlrpc_exit_portals(); + ptlrpc_request_cache_fini(); ptlrpc_hr_fini(); ptlrpc_connection_fini(); } diff --git a/drivers/staging/lustre/lustre/ptlrpc/recover.c b/drivers/staging/lustre/lustre/ptlrpc/recover.c index 48ae328ce24ec1..9cec8a649dc3fb 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/recover.c +++ b/drivers/staging/lustre/lustre/ptlrpc/recover.c @@ -49,7 +49,6 @@ #include #include #include -#include /* for IOC_LOV_SET_OSC_ACTIVE */ #include #include "ptlrpc_internal.h" @@ -369,11 +368,14 @@ EXPORT_SYMBOL(ptlrpc_recover_import); int ptlrpc_import_in_recovery(struct obd_import *imp) { int in_recovery = 1; + spin_lock(&imp->imp_lock); if (imp->imp_state == LUSTRE_IMP_FULL || imp->imp_state == LUSTRE_IMP_CLOSED || - imp->imp_state == LUSTRE_IMP_DISCON) + imp->imp_state == LUSTRE_IMP_DISCON || + imp->imp_obd->obd_no_recov) in_recovery = 0; spin_unlock(&imp->imp_lock); + return in_recovery; } diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c index d80418057f296f..28ac824a73fb83 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c @@ -354,7 +354,7 @@ static int import_sec_check_expire(struct obd_import *imp) return 0; CDEBUG(D_SEC, "found delayed sec adapt expired, do it now\n"); - return sptlrpc_import_sec_adapt(imp, NULL, 0); + return sptlrpc_import_sec_adapt(imp, NULL, NULL); } static int import_sec_validate_get(struct obd_import *imp, @@ -904,7 +904,7 @@ int sptlrpc_import_check_ctx(struct obd_import *imp) return -EACCES; } - OBD_ALLOC_PTR(req); + req = ptlrpc_request_cache_alloc(GFP_NOFS); if (!req) return -ENOMEM; @@ -920,7 +920,7 @@ int sptlrpc_import_check_ctx(struct obd_import *imp) rc = sptlrpc_req_refresh_ctx(req, 0); LASSERT(list_empty(&req->rq_ctx_chain)); sptlrpc_cli_ctx_put(req->rq_cli_ctx, 1); - OBD_FREE_PTR(req); + ptlrpc_request_cache_free(req); return rc; } @@ -1088,7 +1088,7 @@ int sptlrpc_cli_unwrap_early_reply(struct ptlrpc_request *req, int early_bufsz, early_size; int rc; - OBD_ALLOC_PTR(early_req); + early_req = ptlrpc_request_cache_alloc(GFP_NOFS); if (early_req == NULL) return -ENOMEM; @@ -1160,7 +1160,7 @@ int sptlrpc_cli_unwrap_early_reply(struct ptlrpc_request *req, err_buf: OBD_FREE_LARGE(early_buf, early_bufsz); err_req: - OBD_FREE_PTR(early_req); + ptlrpc_request_cache_free(early_req); return rc; } @@ -1177,7 +1177,7 @@ void sptlrpc_cli_finish_early_reply(struct ptlrpc_request *early_req) sptlrpc_cli_ctx_put(early_req->rq_cli_ctx, 1); OBD_FREE_LARGE(early_req->rq_repbuf, early_req->rq_repbuf_len); - OBD_FREE_PTR(early_req); + ptlrpc_request_cache_free(early_req); } /************************************************** @@ -2086,8 +2086,18 @@ int sptlrpc_svc_alloc_rs(struct ptlrpc_request *req, int msglen) rc = policy->sp_sops->alloc_rs(req, msglen); if (unlikely(rc == -ENOMEM)) { + struct ptlrpc_service_part *svcpt = req->rq_rqbd->rqbd_svcpt; + if (svcpt->scp_service->srv_max_reply_size < + msglen + sizeof(struct ptlrpc_reply_state)) { + /* Just return failure if the size is too big */ + CERROR("size of message is too big (%zd), %d allowed", + msglen + sizeof(struct ptlrpc_reply_state), + svcpt->scp_service->srv_max_reply_size); + return -ENOMEM; + } + /* failed alloc, try emergency pool */ - rs = lustre_get_emerg_rs(req->rq_rqbd->rqbd_svcpt); + rs = lustre_get_emerg_rs(svcpt); if (rs == NULL) return -ENOMEM; diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c index 96566813274786..9d51badea73dbf 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c @@ -421,7 +421,7 @@ static int enc_pools_add_pages(int npages) goto out_pools; for (j = 0; j < PAGES_PER_POOL && alloced < npages; j++) { - pools[i][j] = alloc_page(__GFP_IO | + pools[i][j] = alloc_page(GFP_NOFS | __GFP_HIGHMEM); if (pools[i][j] == NULL) goto out_pools; @@ -450,7 +450,7 @@ static int enc_pools_add_pages(int npages) static inline void enc_pools_wakeup(void) { - LASSERT(spin_is_locked(&page_pools.epp_lock)); + assert_spin_locked(&page_pools.epp_lock); LASSERT(page_pools.epp_waitqlen >= 0); if (unlikely(page_pools.epp_waitqlen)) { diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c index 192adec5382a32..d278f2e2180307 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/service.c +++ b/drivers/staging/lustre/lustre/ptlrpc/service.c @@ -384,8 +384,8 @@ void ptlrpc_dispatch_difficult_reply(struct ptlrpc_reply_state *rs) void ptlrpc_schedule_difficult_reply(struct ptlrpc_reply_state *rs) { - LASSERT(spin_is_locked(&rs->rs_svcpt->scp_rep_lock)); - LASSERT(spin_is_locked(&rs->rs_lock)); + assert_spin_locked(&rs->rs_svcpt->scp_rep_lock); + assert_spin_locked(&rs->rs_lock); LASSERT(rs->rs_difficult); rs->rs_scheduled_ever = 1; /* flag any notification attempt */ @@ -842,7 +842,7 @@ static void ptlrpc_server_free_request(struct ptlrpc_request *req) /* NB request buffers use an embedded * req if the incoming req unlinked the * MD; this isn't one of them! */ - OBD_FREE(req, sizeof(*req)); + ptlrpc_request_cache_free(req); } } @@ -1042,9 +1042,6 @@ static void ptlrpc_update_export_timer(struct obd_export *exp, long extra_delay) return; exp->exp_last_request_time = new_time; - CDEBUG(D_HA, "updating export %s at "CFS_TIME_T" exp %p\n", - exp->exp_client_uuid.uuid, - exp->exp_last_request_time, exp); /* exports may get disconnected from the chain even though the export has references, so we must keep the spin lock while @@ -1308,14 +1305,12 @@ static int ptlrpc_at_send_early_reply(struct ptlrpc_request *req) } newdl = cfs_time_current_sec() + at_get(&svcpt->scp_at_estimate); - OBD_ALLOC(reqcopy, sizeof(*reqcopy)); + reqcopy = ptlrpc_request_cache_alloc(GFP_NOFS); if (reqcopy == NULL) return -ENOMEM; OBD_ALLOC_LARGE(reqmsg, req->rq_reqlen); - if (!reqmsg) { - OBD_FREE(reqcopy, sizeof(*reqcopy)); - return -ENOMEM; - } + if (!reqmsg) + GOTO(out_free, rc = -ENOMEM); *reqcopy = *req; reqcopy->rq_reply_state = NULL; @@ -1372,7 +1367,8 @@ static int ptlrpc_at_send_early_reply(struct ptlrpc_request *req) out: sptlrpc_svc_ctx_decref(reqcopy); OBD_FREE_LARGE(reqmsg, req->rq_reqlen); - OBD_FREE(reqcopy, sizeof(*reqcopy)); +out_free: + ptlrpc_request_cache_free(reqcopy); return rc; } diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index b2cd3a85166d74..bbf236e842a99f 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -737,7 +737,7 @@ static int bcm2048_set_region(struct bcm2048_device *bdev, u8 region) int err; u32 new_frequency = 0; - if (region > ARRAY_SIZE(region_configs)) + if (region >= ARRAY_SIZE(region_configs)) return -EINVAL; mutex_lock(&bdev->mutex); diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index 8c101cbbee9764..acc8184c46cde0 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c @@ -1247,9 +1247,18 @@ static int vpfe_stop_streaming(struct vb2_queue *vq) struct vpfe_fh *fh = vb2_get_drv_priv(vq); struct vpfe_video_device *video = fh->video; - if (!vb2_is_streaming(vq)) - return 0; /* release all active buffers */ + if (video->cur_frm == video->next_frm) { + vb2_buffer_done(&video->cur_frm->vb, VB2_BUF_STATE_ERROR); + } else { + if (video->cur_frm != NULL) + vb2_buffer_done(&video->cur_frm->vb, + VB2_BUF_STATE_ERROR); + if (video->next_frm != NULL) + vb2_buffer_done(&video->next_frm->vb, + VB2_BUF_STATE_ERROR); + } + while (!list_empty(&video->dma_queue)) { video->next_frm = list_entry(video->dma_queue.next, struct vpfe_cap_buffer, list); diff --git a/drivers/staging/media/sn9c102/sn9c102_devtable.h b/drivers/staging/media/sn9c102/sn9c102_devtable.h index b3d2cc729657df..4ba569258498b9 100644 --- a/drivers/staging/media/sn9c102/sn9c102_devtable.h +++ b/drivers/staging/media/sn9c102/sn9c102_devtable.h @@ -48,10 +48,8 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), }, /* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */ { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), }, -#endif { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), }, -#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), }, diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c index c83e3375104b50..75d7c63cb41328 100644 --- a/drivers/staging/netlogic/xlr_net.c +++ b/drivers/staging/netlogic/xlr_net.c @@ -268,6 +268,7 @@ static void xlr_make_tx_desc(struct nlm_fmn_msg *msg, unsigned long addr, unsigned long physkb = virt_to_phys(skb); int cpu_core = nlm_core_id(); int fr_stn_id = cpu_core * 8 + XLR_FB_STN; /* FB to 6th bucket */ + msg->msg0 = (((u64)1 << 63) | /* End of packet descriptor */ ((u64)127 << 54) | /* No Free back */ (u64)skb->len << 40 | /* Length of data */ diff --git a/drivers/staging/nokia_h4p/nokia_fw-bcm.c b/drivers/staging/nokia_h4p/nokia_fw-bcm.c index 111ae94032d1a7..b55f5ba1134efb 100644 --- a/drivers/staging/nokia_h4p/nokia_fw-bcm.c +++ b/drivers/staging/nokia_h4p/nokia_fw-bcm.c @@ -73,7 +73,8 @@ void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb) return; } - if (fw_skb->data[1] == 0x01 && fw_skb->data[2] == 0xfc && fw_skb->len >= 10) { + if (fw_skb->data[1] == 0x01 && fw_skb->data[2] == 0xfc && + fw_skb->len >= 10) { BT_DBG("Setting bluetooth address"); err = hci_h4p_bcm_set_bdaddr(info, fw_skb); if (err < 0) { diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c index 08f9a4896116a3..136671a50d6e54 100644 --- a/drivers/staging/panel/panel.c +++ b/drivers/staging/panel/panel.c @@ -867,6 +867,7 @@ static void lcd_print(char c) static void lcd_clear_fast_s(void) { int pos; + lcd_addr_x = lcd_addr_y = 0; lcd_gotoxy(); @@ -887,6 +888,7 @@ static void lcd_clear_fast_s(void) static void lcd_clear_fast_p8(void) { int pos; + lcd_addr_x = lcd_addr_y = 0; lcd_gotoxy(); @@ -922,6 +924,7 @@ static void lcd_clear_fast_p8(void) static void lcd_clear_fast_tilcd(void) { int pos; + lcd_addr_x = lcd_addr_y = 0; lcd_gotoxy(); @@ -1092,6 +1095,7 @@ static inline int handle_lcd_special_code(void) break; case 'k': { /* kill end of line */ int x; + for (x = lcd_addr_x; x < lcd_bwidth; x++) lcd_write_data(' '); @@ -1217,111 +1221,113 @@ static inline int handle_lcd_special_code(void) return processed; } +static void lcd_write_char(char c) +{ + /* first, we'll test if we're in escape mode */ + if ((c != '\n') && lcd_escape_len >= 0) { + /* yes, let's add this char to the buffer */ + lcd_escape[lcd_escape_len++] = c; + lcd_escape[lcd_escape_len] = 0; + } else { + /* aborts any previous escape sequence */ + lcd_escape_len = -1; + + switch (c) { + case LCD_ESCAPE_CHAR: + /* start of an escape sequence */ + lcd_escape_len = 0; + lcd_escape[lcd_escape_len] = 0; + break; + case '\b': + /* go back one char and clear it */ + if (lcd_addr_x > 0) { + /* check if we're not at the + end of the line */ + if (lcd_addr_x < lcd_bwidth) + /* back one char */ + lcd_write_cmd(0x10); + lcd_addr_x--; + } + /* replace with a space */ + lcd_write_data(' '); + /* back one char again */ + lcd_write_cmd(0x10); + break; + case '\014': + /* quickly clear the display */ + lcd_clear_fast(); + break; + case '\n': + /* flush the remainder of the current line and + go to the beginning of the next line */ + for (; lcd_addr_x < lcd_bwidth; lcd_addr_x++) + lcd_write_data(' '); + lcd_addr_x = 0; + lcd_addr_y = (lcd_addr_y + 1) % lcd_height; + lcd_gotoxy(); + break; + case '\r': + /* go to the beginning of the same line */ + lcd_addr_x = 0; + lcd_gotoxy(); + break; + case '\t': + /* print a space instead of the tab */ + lcd_print(' '); + break; + default: + /* simply print this char */ + lcd_print(c); + break; + } + } + + /* now we'll see if we're in an escape mode and if the current + escape sequence can be understood. */ + if (lcd_escape_len >= 2) { + int processed = 0; + + if (!strcmp(lcd_escape, "[2J")) { + /* clear the display */ + lcd_clear_fast(); + processed = 1; + } else if (!strcmp(lcd_escape, "[H")) { + /* cursor to home */ + lcd_addr_x = lcd_addr_y = 0; + lcd_gotoxy(); + processed = 1; + } + /* codes starting with ^[[L */ + else if ((lcd_escape_len >= 3) && + (lcd_escape[0] == '[') && + (lcd_escape[1] == 'L')) { + processed = handle_lcd_special_code(); + } + + /* LCD special escape codes */ + /* flush the escape sequence if it's been processed + or if it is getting too long. */ + if (processed || (lcd_escape_len >= LCD_ESCAPE_LEN)) + lcd_escape_len = -1; + } /* escape codes */ +} + static ssize_t lcd_write(struct file *file, - const char *buf, size_t count, loff_t *ppos) + const char __user *buf, size_t count, loff_t *ppos) { - const char *tmp = buf; + const char __user *tmp = buf; char c; - for (; count-- > 0; (ppos ? (*ppos)++ : 0), ++tmp) { + for (; count-- > 0; (*ppos)++, tmp++) { if (!in_interrupt() && (((count + 1) & 0x1f) == 0)) /* let's be a little nice with other processes that need some CPU */ schedule(); - if (ppos == NULL && file == NULL) - /* let's not use get_user() from the kernel ! */ - c = *tmp; - else if (get_user(c, tmp)) + if (get_user(c, buf)) return -EFAULT; - /* first, we'll test if we're in escape mode */ - if ((c != '\n') && lcd_escape_len >= 0) { - /* yes, let's add this char to the buffer */ - lcd_escape[lcd_escape_len++] = c; - lcd_escape[lcd_escape_len] = 0; - } else { - /* aborts any previous escape sequence */ - lcd_escape_len = -1; - - switch (c) { - case LCD_ESCAPE_CHAR: - /* start of an escape sequence */ - lcd_escape_len = 0; - lcd_escape[lcd_escape_len] = 0; - break; - case '\b': - /* go back one char and clear it */ - if (lcd_addr_x > 0) { - /* check if we're not at the - end of the line */ - if (lcd_addr_x < lcd_bwidth) - /* back one char */ - lcd_write_cmd(0x10); - lcd_addr_x--; - } - /* replace with a space */ - lcd_write_data(' '); - /* back one char again */ - lcd_write_cmd(0x10); - break; - case '\014': - /* quickly clear the display */ - lcd_clear_fast(); - break; - case '\n': - /* flush the remainder of the current line and - go to the beginning of the next line */ - for (; lcd_addr_x < lcd_bwidth; lcd_addr_x++) - lcd_write_data(' '); - lcd_addr_x = 0; - lcd_addr_y = (lcd_addr_y + 1) % lcd_height; - lcd_gotoxy(); - break; - case '\r': - /* go to the beginning of the same line */ - lcd_addr_x = 0; - lcd_gotoxy(); - break; - case '\t': - /* print a space instead of the tab */ - lcd_print(' '); - break; - default: - /* simply print this char */ - lcd_print(c); - break; - } - } - - /* now we'll see if we're in an escape mode and if the current - escape sequence can be understood. */ - if (lcd_escape_len >= 2) { - int processed = 0; - - if (!strcmp(lcd_escape, "[2J")) { - /* clear the display */ - lcd_clear_fast(); - processed = 1; - } else if (!strcmp(lcd_escape, "[H")) { - /* cursor to home */ - lcd_addr_x = lcd_addr_y = 0; - lcd_gotoxy(); - processed = 1; - } - /* codes starting with ^[[L */ - else if ((lcd_escape_len >= 3) && - (lcd_escape[0] == '[') && - (lcd_escape[1] == 'L')) { - processed = handle_lcd_special_code(); - } - - /* LCD special escape codes */ - /* flush the escape sequence if it's been processed - or if it is getting too long. */ - if (processed || (lcd_escape_len >= LCD_ESCAPE_LEN)) - lcd_escape_len = -1; - } /* escape codes */ + lcd_write_char(c); } return tmp - buf; @@ -1365,8 +1371,19 @@ static struct miscdevice lcd_dev = { /* public function usable from the kernel for any purpose */ static void panel_lcd_print(const char *s) { - if (lcd_enabled && lcd_initialized) - lcd_write(NULL, s, strlen(s), NULL); + const char *tmp = s; + int count = strlen(s); + + if (lcd_enabled && lcd_initialized) { + for (; count-- > 0; tmp++) { + if (!in_interrupt() && (((count + 1) & 0x1f) == 0)) + /* let's be a little nice with other processes + that need some CPU */ + schedule(); + + lcd_write_char(*tmp); + } + } } /* initialize the LCD driver */ @@ -1571,11 +1588,11 @@ static void lcd_init(void) */ static ssize_t keypad_read(struct file *file, - char *buf, size_t count, loff_t *ppos) + char __user *buf, size_t count, loff_t *ppos) { unsigned i = *ppos; - char *tmp = buf; + char __user *tmp = buf; if (keypad_buflen == 0) { if (file->f_flags & O_NONBLOCK) @@ -1747,16 +1764,20 @@ static inline int input_state_high(struct logical_input *input) if (input->high_timer == 0) { char *press_str = input->u.kbd.press_str; + if (press_str[0]) { int s = sizeof(input->u.kbd.press_str); + keypad_send_key(press_str, s); } } if (input->u.kbd.repeat_str[0]) { char *repeat_str = input->u.kbd.repeat_str; + if (input->high_timer >= KEYPAD_REP_START) { int s = sizeof(input->u.kbd.repeat_str); + input->high_timer -= KEYPAD_REP_DELAY; keypad_send_key(repeat_str, s); } @@ -1794,8 +1815,10 @@ static inline void input_state_falling(struct logical_input *input) if (input->u.kbd.repeat_str[0]) { char *repeat_str = input->u.kbd.repeat_str; + if (input->high_timer >= KEYPAD_REP_START) { int s = sizeof(input->u.kbd.repeat_str); + input->high_timer -= KEYPAD_REP_DELAY; keypad_send_key(repeat_str, s); } @@ -1811,12 +1834,15 @@ static inline void input_state_falling(struct logical_input *input) /* call release event */ if (input->type == INPUT_TYPE_STD) { void (*release_fct)(int) = input->u.std.release_fct; + if (release_fct != NULL) release_fct(input->u.std.release_data); } else if (input->type == INPUT_TYPE_KBD) { char *release_str = input->u.kbd.release_str; + if (release_str[0]) { int s = sizeof(input->u.kbd.release_str); + keypad_send_key(release_str, s); } } @@ -1933,6 +1959,7 @@ static int input_name2mask(const char *name, pmask_t *mask, pmask_t *value, om = im = m = v = 0ULL; while (*name) { int in, out, bit, neg; + for (in = 0; (in < sizeof(sigtab)) && (sigtab[in] != *name); in++) ; @@ -2040,6 +2067,7 @@ static struct logical_input *panel_bind_callback(char *name, static void keypad_init(void) { int keynum; + init_waitqueue_head(&keypad_read_wait); keypad_buflen = 0; /* flushes any eventual noisy keystroke */ @@ -2298,7 +2326,7 @@ static void __exit panel_cleanup_module(void) unregister_reboot_notifier(&panel_notifier); if (scan_timer.function != NULL) - del_timer(&scan_timer); + del_timer_sync(&scan_timer); if (pprt != NULL) { if (keypad_enabled) { diff --git a/drivers/staging/rtl8188eu/core/rtw_br_ext.c b/drivers/staging/rtl8188eu/core/rtw_br_ext.c index e843c6bd452587..f97f05f4165e70 100644 --- a/drivers/staging/rtl8188eu/core/rtw_br_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_br_ext.c @@ -442,6 +442,7 @@ static void __nat25_db_print(struct adapter *priv) void nat25_db_cleanup(struct adapter *priv) { int i; + spin_lock_bh(&priv->br_ext_lock); for (i = 0; i < NAT25_HASH_SIZE; i++) { diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c index c2fb050337d505..1e0b8b49fc1270 100644 --- a/drivers/staging/rtl8188eu/core/rtw_cmd.c +++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c @@ -1431,41 +1431,6 @@ u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue) return res; } -u8 rtw_led_blink_cmd(struct adapter *padapter, struct LED_871x *pLed) -{ - struct cmd_obj *pcmdobj; - struct LedBlink_param *ledBlink_param; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - - u8 res = _SUCCESS; - - - RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_led_blink_cmd\n")); - - pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); - if (pcmdobj == NULL) { - res = _FAIL; - goto exit; - } - - ledBlink_param = (struct LedBlink_param *)rtw_zmalloc(sizeof(struct LedBlink_param)); - if (ledBlink_param == NULL) { - kfree(pcmdobj); - res = _FAIL; - goto exit; - } - - ledBlink_param->pLed = pLed; - - init_h2fwcmd_w_parm_no_rsp(pcmdobj, ledBlink_param, GEN_CMD_CODE(_LedBlink)); - res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); - -exit: - - - return res; -} - u8 rtw_set_csa_cmd(struct adapter *padapter, u8 new_ch_no) { struct cmd_obj *pcmdobj; diff --git a/drivers/staging/rtl8188eu/core/rtw_led.c b/drivers/staging/rtl8188eu/core/rtw_led.c index 42b41ab1bce1de..87d6f063476b15 100644 --- a/drivers/staging/rtl8188eu/core/rtw_led.c +++ b/drivers/staging/rtl8188eu/core/rtw_led.c @@ -40,7 +40,6 @@ void BlinkTimerCallback(void *data) /* */ /* Description: */ /* Callback function of LED BlinkWorkItem. */ -/* We dispatch acture LED blink action according to LedStrategy. */ /* */ void BlinkWorkItemCallback(struct work_struct *work) { @@ -71,10 +70,9 @@ void ResetLedStatus(struct LED_871x *pLed) /*Description: */ /* Initialize an LED_871x object. */ -void InitLed871x(struct adapter *padapter, struct LED_871x *pLed, enum LED_PIN_871x LedPin) +void InitLed871x(struct adapter *padapter, struct LED_871x *pLed) { pLed->padapter = padapter; - pLed->LedPin = LedPin; ResetLedStatus(pLed); @@ -101,87 +99,6 @@ void DeInitLed871x(struct LED_871x *pLed) /* It toggle off LED and schedule corresponding timer if necessary. */ /* */ -static void SwLedBlink(struct LED_871x *pLed) -{ - struct adapter *padapter = pLed->padapter; - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - u8 bStopBlinking = false; - - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == RTW_LED_ON) { - SwLedOn(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); - } else { - SwLedOff(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); - } - - /* Determine if we shall change LED state again. */ - pLed->BlinkTimes--; - switch (pLed->CurrLedState) { - case LED_BLINK_NORMAL: - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - break; - case LED_BLINK_StartToBlink: - if (check_fwstate(pmlmepriv, _FW_LINKED) && check_fwstate(pmlmepriv, WIFI_STATION_STATE)) - bStopBlinking = true; - if (check_fwstate(pmlmepriv, _FW_LINKED) && - (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || - check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) - bStopBlinking = true; - else if (pLed->BlinkTimes == 0) - bStopBlinking = true; - break; - case LED_BLINK_WPS: - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - break; - default: - bStopBlinking = true; - break; - } - - if (bStopBlinking) { - /* if (padapter->pwrctrlpriv.cpwm >= PS_STATE_S2) */ - if (0) { - SwLedOff(padapter, pLed); - } else if ((check_fwstate(pmlmepriv, _FW_LINKED)) && (!pLed->bLedOn)) { - SwLedOn(padapter, pLed); - } else if ((check_fwstate(pmlmepriv, _FW_LINKED)) && pLed->bLedOn) { - SwLedOff(padapter, pLed); - } - pLed->BlinkTimes = 0; - pLed->bLedBlinkInProgress = false; - } else { - /* Assign LED state to toggle. */ - if (pLed->BlinkingLedState == RTW_LED_ON) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - - /* Schedule a timer to toggle LED state. */ - switch (pLed->CurrLedState) { - case LED_BLINK_NORMAL: - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); - break; - case LED_BLINK_SLOWLY: - case LED_BLINK_StartToBlink: - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); - break; - case LED_BLINK_WPS: - if (pLed->BlinkingLedState == RTW_LED_ON) - _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL); - else - _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL); - break; - default: - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); - break; - } - } -} - static void SwLedBlink1(struct LED_871x *pLed) { struct adapter *padapter = pLed->padapter; @@ -277,1051 +194,115 @@ static void SwLedBlink1(struct LED_871x *pLed) } pLed->BlinkTimes = 0; pLed->bLedBlinkInProgress = false; - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); - } - break; - case LED_BLINK_WPS: - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - break; - case LED_BLINK_WPS_STOP: /* WPS success */ - if (pLed->BlinkingLedState == RTW_LED_ON) - bStopBlinking = false; - else - bStopBlinking = true; - - if (bStopBlinking) { - pLed->bLedLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_NORMAL; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); - - pLed->bLedWPSBlinkInProgress = false; - } else { - pLed->BlinkingLedState = RTW_LED_OFF; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); - } - break; - default: - break; - } -} - -static void SwLedBlink2(struct LED_871x *pLed) -{ - struct adapter *padapter = pLed->padapter; - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - u8 bStopBlinking = false; - - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == RTW_LED_ON) { - SwLedOn(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); - } else { - SwLedOff(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); - } - - switch (pLed->CurrLedState) { - case LED_BLINK_SCAN: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { - SwLedOff(padapter, pLed); - } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = RTW_LED_ON; - pLed->BlinkingLedState = RTW_LED_ON; - SwLedOn(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop scan blink CurrLedState %d\n", pLed->CurrLedState)); - - } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - SwLedOff(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop scan blink CurrLedState %d\n", pLed->CurrLedState)); - } - pLed->bLedScanBlinkInProgress = false; - } else { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { - SwLedOff(padapter, pLed); - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - } - } - break; - case LED_BLINK_TXRX: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { - SwLedOff(padapter, pLed); - } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = RTW_LED_ON; - pLed->BlinkingLedState = RTW_LED_ON; - SwLedOn(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop CurrLedState %d\n", pLed->CurrLedState)); - } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - SwLedOff(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop CurrLedState %d\n", pLed->CurrLedState)); - } - pLed->bLedBlinkInProgress = false; - } else { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { - SwLedOff(padapter, pLed); - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); - } - } - break; - default: - break; - } -} - -static void SwLedBlink3(struct LED_871x *pLed) -{ - struct adapter *padapter = pLed->padapter; - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - u8 bStopBlinking = false; - - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == RTW_LED_ON) { - SwLedOn(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); - } else { - if (pLed->CurrLedState != LED_BLINK_WPS_STOP) - SwLedOff(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); - } - - switch (pLed->CurrLedState) { - case LED_BLINK_SCAN: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { - SwLedOff(padapter, pLed); - } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = RTW_LED_ON; - pLed->BlinkingLedState = RTW_LED_ON; - if (!pLed->bLedOn) - SwLedOn(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); - } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - if (pLed->bLedOn) - SwLedOff(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); - } - pLed->bLedScanBlinkInProgress = false; - } else { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { - SwLedOff(padapter, pLed); - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - } - } - break; - case LED_BLINK_TXRX: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { - SwLedOff(padapter, pLed); - } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = RTW_LED_ON; - pLed->BlinkingLedState = RTW_LED_ON; - if (!pLed->bLedOn) - SwLedOn(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); - } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - - if (pLed->bLedOn) - SwLedOff(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); - } - pLed->bLedBlinkInProgress = false; - } else { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { - SwLedOff(padapter, pLed); - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); - } - } - break; - case LED_BLINK_WPS: - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - break; - case LED_BLINK_WPS_STOP: /* WPS success */ - if (pLed->BlinkingLedState == RTW_LED_ON) { - pLed->BlinkingLedState = RTW_LED_OFF; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); - bStopBlinking = false; - } else { - bStopBlinking = true; - } - if (bStopBlinking) { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { - SwLedOff(padapter, pLed); - } else { - pLed->CurrLedState = RTW_LED_ON; - pLed->BlinkingLedState = RTW_LED_ON; - SwLedOn(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); - } - pLed->bLedWPSBlinkInProgress = false; - } - break; - default: - break; - } -} - -static void SwLedBlink4(struct LED_871x *pLed) -{ - struct adapter *padapter = pLed->padapter; - struct led_priv *ledpriv = &(padapter->ledpriv); - struct LED_871x *pLed1 = &(ledpriv->SwLed1); - u8 bStopBlinking = false; - - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == RTW_LED_ON) { - SwLedOn(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); - } else { - SwLedOff(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); - } - - if (!pLed1->bLedWPSBlinkInProgress && pLed1->BlinkingLedState == LED_UNKNOWN) { - pLed1->BlinkingLedState = RTW_LED_OFF; - pLed1->CurrLedState = RTW_LED_OFF; - SwLedOff(padapter, pLed1); - } - - switch (pLed->CurrLedState) { - case LED_BLINK_SLOWLY: - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); - break; - case LED_BLINK_StartToBlink: - if (pLed->bLedOn) { - pLed->BlinkingLedState = RTW_LED_OFF; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); - } else { - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); - } - break; - case LED_BLINK_SCAN: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = false; - if (bStopBlinking) { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { - SwLedOff(padapter, pLed); - } else { - pLed->bLedNoLinkBlinkInProgress = false; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); - } - pLed->bLedScanBlinkInProgress = false; - } else { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { - SwLedOff(padapter, pLed); - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - } - } - break; - case LED_BLINK_TXRX: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { - SwLedOff(padapter, pLed); - } else { - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); - } - pLed->bLedBlinkInProgress = false; - } else { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { - SwLedOff(padapter, pLed); - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); - } - } - break; - case LED_BLINK_WPS: - if (pLed->bLedOn) { - pLed->BlinkingLedState = RTW_LED_OFF; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); - } else { - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); - } - break; - case LED_BLINK_WPS_STOP: /* WPS authentication fail */ - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); - break; - case LED_BLINK_WPS_STOP_OVERLAP: /* WPS session overlap */ - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) { - if (pLed->bLedOn) - pLed->BlinkTimes = 1; - else - bStopBlinking = true; - } - - if (bStopBlinking) { - pLed->BlinkTimes = 10; - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); - } - break; - default: - break; - } - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("SwLedBlink4 CurrLedState %d\n", pLed->CurrLedState)); -} - -static void SwLedBlink5(struct LED_871x *pLed) -{ - struct adapter *padapter = pLed->padapter; - u8 bStopBlinking = false; - - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == RTW_LED_ON) { - SwLedOn(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); - } else { - SwLedOff(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); - } - - switch (pLed->CurrLedState) { - case LED_BLINK_SCAN: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - - if (bStopBlinking) { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - if (pLed->bLedOn) - SwLedOff(padapter, pLed); - } else { - pLed->CurrLedState = RTW_LED_ON; - pLed->BlinkingLedState = RTW_LED_ON; - if (!pLed->bLedOn) - _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); - } - - pLed->bLedScanBlinkInProgress = false; - } else { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { - SwLedOff(padapter, pLed); - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - } - } - break; - case LED_BLINK_TXRX: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - - if (bStopBlinking) { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - if (pLed->bLedOn) - SwLedOff(padapter, pLed); - } else { - pLed->CurrLedState = RTW_LED_ON; - pLed->BlinkingLedState = RTW_LED_ON; - if (!pLed->bLedOn) - _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); - } - - pLed->bLedBlinkInProgress = false; - } else { - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { - SwLedOff(padapter, pLed); - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); - } - } - break; - - default: - break; - } - - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("SwLedBlink5 CurrLedState %d\n", pLed->CurrLedState)); -} - -static void SwLedBlink6(struct LED_871x *pLed) -{ - struct adapter *padapter = pLed->padapter; - - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == RTW_LED_ON) { - SwLedOn(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); - } else { - SwLedOff(padapter, pLed); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); - } - - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("<==== blink6\n")); -} - - /* ALPHA, added by chiyoko, 20090106 */ -static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAction) -{ - struct led_priv *ledpriv = &(padapter->ledpriv); - struct LED_871x *pLed = &(ledpriv->SwLed0); - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - - switch (LedAction) { - case LED_CTL_POWER_ON: - case LED_CTL_START_TO_LINK: - case LED_CTL_NO_LINK: - if (!pLed->bLedNoLinkBlinkInProgress) { - if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); - } - break; - case LED_CTL_LINK: - if (!pLed->bLedLinkBlinkInProgress) { - if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedNoLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_NORMAL; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); - } - break; - case LED_CTL_SITE_SURVEY: - if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) { - ; - } else if (!pLed->bLedScanBlinkInProgress) { - if (IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedNoLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedScanBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SCAN; - pLed->BlinkTimes = 24; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - } - break; - case LED_CTL_TX: - case LED_CTL_RX: - if (!pLed->bLedBlinkInProgress) { - if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedNoLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedLinkBlinkInProgress = false; - } - pLed->bLedBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_TXRX; - pLed->BlinkTimes = 2; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); - } - break; - case LED_CTL_START_WPS: /* wait until xinpin finish */ - case LED_CTL_START_WPS_BOTTON: - if (!pLed->bLedWPSBlinkInProgress) { - if (pLed->bLedNoLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedScanBlinkInProgress = false; - } - pLed->bLedWPSBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_WPS; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - } - break; - case LED_CTL_STOP_WPS: - if (pLed->bLedNoLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedScanBlinkInProgress = false; - } - if (pLed->bLedWPSBlinkInProgress) - _cancel_timer_ex(&(pLed->BlinkTimer)); - else - pLed->bLedWPSBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_WPS_STOP; - if (pLed->bLedOn) { - pLed->BlinkingLedState = RTW_LED_OFF; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); - } else { - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), 0); - } - break; - case LED_CTL_STOP_WPS_FAIL: - if (pLed->bLedWPSBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedWPSBlinkInProgress = false; - } - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); - break; - case LED_CTL_POWER_OFF: - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - if (pLed->bLedNoLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedWPSBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedWPSBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedScanBlinkInProgress = false; - } - SwLedOff(padapter, pLed); - break; - default: - break; - } - - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState)); -} - - /* Arcadyan/Sitecom , added by chiyoko, 20090216 */ -static void SwLedControlMode2(struct adapter *padapter, enum LED_CTL_MODE LedAction) -{ - struct led_priv *ledpriv = &(padapter->ledpriv); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &(ledpriv->SwLed0); - - switch (LedAction) { - case LED_CTL_SITE_SURVEY: - if (pmlmepriv->LinkDetectInfo.bBusyTraffic) { - } else if (!pLed->bLedScanBlinkInProgress) { - if (IS_LED_WPS_BLINKING(pLed)) - return; - - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedScanBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SCAN; - pLed->BlinkTimes = 24; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - } - break; - case LED_CTL_TX: - case LED_CTL_RX: - if ((!pLed->bLedBlinkInProgress) && (check_fwstate(pmlmepriv, _FW_LINKED))) { - if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) - return; - pLed->bLedBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_TXRX; - pLed->BlinkTimes = 2; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); - } - break; - case LED_CTL_LINK: - pLed->CurrLedState = RTW_LED_ON; - pLed->BlinkingLedState = RTW_LED_ON; - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedScanBlinkInProgress = false; - } - _set_timer(&(pLed->BlinkTimer), 0); - break; - case LED_CTL_START_WPS: /* wait until xinpin finish */ - case LED_CTL_START_WPS_BOTTON: - if (!pLed->bLedWPSBlinkInProgress) { - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedScanBlinkInProgress = false; - } - pLed->bLedWPSBlinkInProgress = true; - pLed->CurrLedState = RTW_LED_ON; - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), 0); - } - break; - case LED_CTL_STOP_WPS: - pLed->bLedWPSBlinkInProgress = false; - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { - SwLedOff(padapter, pLed); - } else { - pLed->CurrLedState = RTW_LED_ON; - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), 0); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); - } - break; - case LED_CTL_STOP_WPS_FAIL: - pLed->bLedWPSBlinkInProgress = false; - if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { - SwLedOff(padapter, pLed); - } else { - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - _set_timer(&(pLed->BlinkTimer), 0); - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); - } - break; - case LED_CTL_START_TO_LINK: - case LED_CTL_NO_LINK: - if (!IS_LED_BLINKING(pLed)) { - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - _set_timer(&(pLed->BlinkTimer), 0); - } - break; - case LED_CTL_POWER_OFF: - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedScanBlinkInProgress = false; - } - if (pLed->bLedWPSBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedWPSBlinkInProgress = false; - } - - _set_timer(&(pLed->BlinkTimer), 0); - break; - default: - break; - } - - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -} - - /* COREGA, added by chiyoko, 20090316 */ - static void SwLedControlMode3(struct adapter *padapter, enum LED_CTL_MODE LedAction) -{ - struct led_priv *ledpriv = &(padapter->ledpriv); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &(ledpriv->SwLed0); - - switch (LedAction) { - case LED_CTL_SITE_SURVEY: - if (pmlmepriv->LinkDetectInfo.bBusyTraffic) { - } else if (!pLed->bLedScanBlinkInProgress) { - if (IS_LED_WPS_BLINKING(pLed)) - return; - - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedScanBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SCAN; - pLed->BlinkTimes = 24; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - } - break; - case LED_CTL_TX: - case LED_CTL_RX: - if ((!pLed->bLedBlinkInProgress) && (check_fwstate(pmlmepriv, _FW_LINKED))) { - if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) - return; - pLed->bLedBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_TXRX; - pLed->BlinkTimes = 2; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); - } - break; - case LED_CTL_LINK: - if (IS_LED_WPS_BLINKING(pLed)) - return; - pLed->CurrLedState = RTW_LED_ON; - pLed->BlinkingLedState = RTW_LED_ON; - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedScanBlinkInProgress = false; - } - - _set_timer(&(pLed->BlinkTimer), 0); - break; - case LED_CTL_START_WPS: /* wait until xinpin finish */ - case LED_CTL_START_WPS_BOTTON: - if (!pLed->bLedWPSBlinkInProgress) { - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedScanBlinkInProgress = false; - } - pLed->bLedWPSBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_WPS; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - } - break; - case LED_CTL_STOP_WPS: - if (pLed->bLedWPSBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedWPSBlinkInProgress = false; - } else { - pLed->bLedWPSBlinkInProgress = true; - } - - pLed->CurrLedState = LED_BLINK_WPS_STOP; - if (pLed->bLedOn) { - pLed->BlinkingLedState = RTW_LED_OFF; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); - } else { - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), 0); - } - break; - case LED_CTL_STOP_WPS_FAIL: - if (pLed->bLedWPSBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedWPSBlinkInProgress = false; - } - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - _set_timer(&(pLed->BlinkTimer), 0); - break; - case LED_CTL_START_TO_LINK: - case LED_CTL_NO_LINK: - if (!IS_LED_BLINKING(pLed)) { - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - _set_timer(&(pLed->BlinkTimer), 0); - } - break; - case LED_CTL_POWER_OFF: - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedScanBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); } - if (pLed->bLedWPSBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); + break; + case LED_BLINK_WPS: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + break; + case LED_BLINK_WPS_STOP: /* WPS success */ + if (pLed->BlinkingLedState == RTW_LED_ON) + bStopBlinking = false; + else + bStopBlinking = true; + + if (bStopBlinking) { + pLed->bLedLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + pLed->bLedWPSBlinkInProgress = false; + } else { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); } - - _set_timer(&(pLed->BlinkTimer), 0); break; default: break; } - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, - ("CurrLedState %d\n", pLed->CurrLedState)); } - /* Edimax-Belkin, added by chiyoko, 20090413 */ -static void SwLedControlMode4(struct adapter *padapter, enum LED_CTL_MODE LedAction) + /* ALPHA, added by chiyoko, 20090106 */ +static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAction) { struct led_priv *ledpriv = &(padapter->ledpriv); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct LED_871x *pLed = &(ledpriv->SwLed0); - struct LED_871x *pLed1 = &(ledpriv->SwLed1); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); switch (LedAction) { + case LED_CTL_POWER_ON: case LED_CTL_START_TO_LINK: - if (pLed1->bLedWPSBlinkInProgress) { - pLed1->bLedWPSBlinkInProgress = false; - _cancel_timer_ex(&(pLed1->BlinkTimer)); - - pLed1->BlinkingLedState = RTW_LED_OFF; - pLed1->CurrLedState = RTW_LED_OFF; - - if (pLed1->bLedOn) - _set_timer(&(pLed->BlinkTimer), 0); - } - - if (!pLed->bLedStartToLinkBlinkInProgress) { + case LED_CTL_NO_LINK: + if (!pLed->bLedNoLinkBlinkInProgress) { if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) return; - if (pLed->bLedBlinkInProgress) { + if (pLed->bLedLinkBlinkInProgress) { _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; + pLed->bLedLinkBlinkInProgress = false; } - if (pLed->bLedNoLinkBlinkInProgress) { + if (pLed->bLedBlinkInProgress) { _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedNoLinkBlinkInProgress = false; + pLed->bLedBlinkInProgress = false; } - pLed->bLedStartToLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_StartToBlink; - if (pLed->bLedOn) { + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) pLed->BlinkingLedState = RTW_LED_OFF; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); - } else { + else pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); - } + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); } break; case LED_CTL_LINK: - case LED_CTL_NO_LINK: - /* LED1 settings */ - if (LedAction == LED_CTL_LINK) { - if (pLed1->bLedWPSBlinkInProgress) { - pLed1->bLedWPSBlinkInProgress = false; - _cancel_timer_ex(&(pLed1->BlinkTimer)); - - pLed1->BlinkingLedState = RTW_LED_OFF; - pLed1->CurrLedState = RTW_LED_OFF; - - if (pLed1->bLedOn) - _set_timer(&(pLed->BlinkTimer), 0); - } - } - - if (!pLed->bLedNoLinkBlinkInProgress) { + if (!pLed->bLedLinkBlinkInProgress) { if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) return; + if (pLed->bLedNoLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = false; + } if (pLed->bLedBlinkInProgress) { _cancel_timer_ex(&(pLed->BlinkTimer)); pLed->bLedBlinkInProgress = false; } - - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; + pLed->bLedLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_NORMAL; if (pLed->bLedOn) pLed->BlinkingLedState = RTW_LED_OFF; else pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); } break; case LED_CTL_SITE_SURVEY: if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) { + ; } else if (!pLed->bLedScanBlinkInProgress) { if (IS_LED_WPS_BLINKING(pLed)) return; - if (pLed->bLedNoLinkBlinkInProgress) { _cancel_timer_ex(&(pLed->BlinkTimer)); pLed->bLedNoLinkBlinkInProgress = false; } + if (pLed->bLedLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedLinkBlinkInProgress = false; + } if (pLed->bLedBlinkInProgress) { _cancel_timer_ex(&(pLed->BlinkTimer)); pLed->bLedBlinkInProgress = false; @@ -1334,7 +315,7 @@ static void SwLedControlMode4(struct adapter *padapter, enum LED_CTL_MODE LedAct else pLed->BlinkingLedState = RTW_LED_ON; _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - } + } break; case LED_CTL_TX: case LED_CTL_RX: @@ -1345,6 +326,10 @@ static void SwLedControlMode4(struct adapter *padapter, enum LED_CTL_MODE LedAct _cancel_timer_ex(&(pLed->BlinkTimer)); pLed->bLedNoLinkBlinkInProgress = false; } + if (pLed->bLedLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedLinkBlinkInProgress = false; + } pLed->bLedBlinkInProgress = true; pLed->CurrLedState = LED_BLINK_TXRX; pLed->BlinkTimes = 2; @@ -1357,22 +342,15 @@ static void SwLedControlMode4(struct adapter *padapter, enum LED_CTL_MODE LedAct break; case LED_CTL_START_WPS: /* wait until xinpin finish */ case LED_CTL_START_WPS_BOTTON: - if (pLed1->bLedWPSBlinkInProgress) { - pLed1->bLedWPSBlinkInProgress = false; - _cancel_timer_ex(&(pLed1->BlinkTimer)); - - pLed1->BlinkingLedState = RTW_LED_OFF; - pLed1->CurrLedState = RTW_LED_OFF; - - if (pLed1->bLedOn) - _set_timer(&(pLed->BlinkTimer), 0); - } - - if (!pLed->bLedWPSBlinkInProgress) { + if (!pLed->bLedWPSBlinkInProgress) { if (pLed->bLedNoLinkBlinkInProgress) { _cancel_timer_ex(&(pLed->BlinkTimer)); pLed->bLedNoLinkBlinkInProgress = false; } + if (pLed->bLedLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedLinkBlinkInProgress = false; + } if (pLed->bLedBlinkInProgress) { _cancel_timer_ex(&(pLed->BlinkTimer)); pLed->bLedBlinkInProgress = false; @@ -1383,56 +361,44 @@ static void SwLedControlMode4(struct adapter *padapter, enum LED_CTL_MODE LedAct } pLed->bLedWPSBlinkInProgress = true; pLed->CurrLedState = LED_BLINK_WPS; - if (pLed->bLedOn) { + if (pLed->bLedOn) pLed->BlinkingLedState = RTW_LED_OFF; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); - } else { + else pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); - } - } + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } break; - case LED_CTL_STOP_WPS: /* WPS connect success */ - if (pLed->bLedWPSBlinkInProgress) { + case LED_CTL_STOP_WPS: + if (pLed->bLedNoLinkBlinkInProgress) { _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedWPSBlinkInProgress = false; + pLed->bLedNoLinkBlinkInProgress = false; } - - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); - - break; - case LED_CTL_STOP_WPS_FAIL: /* WPS authentication fail */ - if (pLed->bLedWPSBlinkInProgress) { + if (pLed->bLedLinkBlinkInProgress) { _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedWPSBlinkInProgress = false; + pLed->bLedLinkBlinkInProgress = false; } - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = false; + } + if (pLed->bLedWPSBlinkInProgress) + _cancel_timer_ex(&(pLed->BlinkTimer)); else + pLed->bLedWPSBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_WPS_STOP; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); + } else { pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); - - /* LED1 settings */ - if (pLed1->bLedWPSBlinkInProgress) - _cancel_timer_ex(&(pLed1->BlinkTimer)); - else - pLed1->bLedWPSBlinkInProgress = true; - pLed1->CurrLedState = LED_BLINK_WPS_STOP; - if (pLed1->bLedOn) - pLed1->BlinkingLedState = RTW_LED_OFF; - else - pLed1->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + _set_timer(&(pLed->BlinkTimer), 0); + } break; - case LED_CTL_STOP_WPS_FAIL_OVERLAP: /* WPS session overlap */ + case LED_CTL_STOP_WPS_FAIL: if (pLed->bLedWPSBlinkInProgress) { _cancel_timer_ex(&(pLed->BlinkTimer)); pLed->bLedWPSBlinkInProgress = false; @@ -1444,24 +410,10 @@ static void SwLedControlMode4(struct adapter *padapter, enum LED_CTL_MODE LedAct else pLed->BlinkingLedState = RTW_LED_ON; _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); - - /* LED1 settings */ - if (pLed1->bLedWPSBlinkInProgress) - _cancel_timer_ex(&(pLed1->BlinkTimer)); - else - pLed1->bLedWPSBlinkInProgress = true; - pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP; - pLed1->BlinkTimes = 10; - if (pLed1->bLedOn) - pLed1->BlinkingLedState = RTW_LED_OFF; - else - pLed1->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); break; case LED_CTL_POWER_OFF: pLed->CurrLedState = RTW_LED_OFF; pLed->BlinkingLedState = RTW_LED_OFF; - if (pLed->bLedNoLinkBlinkInProgress) { _cancel_timer_ex(&(pLed->BlinkTimer)); pLed->bLedNoLinkBlinkInProgress = false; @@ -1482,87 +434,6 @@ static void SwLedControlMode4(struct adapter *padapter, enum LED_CTL_MODE LedAct _cancel_timer_ex(&(pLed->BlinkTimer)); pLed->bLedScanBlinkInProgress = false; } - if (pLed->bLedStartToLinkBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedStartToLinkBlinkInProgress = false; - } - if (pLed1->bLedWPSBlinkInProgress) { - _cancel_timer_ex(&(pLed1->BlinkTimer)); - pLed1->bLedWPSBlinkInProgress = false; - } - pLed1->BlinkingLedState = LED_UNKNOWN; - SwLedOff(padapter, pLed); - SwLedOff(padapter, pLed1); - break; - default: - break; - } - - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState)); -} - - - - /* Sercomm-Belkin, added by chiyoko, 20090415 */ -static void -SwLedControlMode5( - struct adapter *padapter, - enum LED_CTL_MODE LedAction -) -{ - struct led_priv *ledpriv = &(padapter->ledpriv); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &(ledpriv->SwLed0); - - switch (LedAction) { - case LED_CTL_POWER_ON: - case LED_CTL_NO_LINK: - case LED_CTL_LINK: /* solid blue */ - pLed->CurrLedState = RTW_LED_ON; - pLed->BlinkingLedState = RTW_LED_ON; - - _set_timer(&(pLed->BlinkTimer), 0); - break; - case LED_CTL_SITE_SURVEY: - if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) { - } else if (!pLed->bLedScanBlinkInProgress) { - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedScanBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SCAN; - pLed->BlinkTimes = 24; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); - } - break; - case LED_CTL_TX: - case LED_CTL_RX: - if (!pLed->bLedBlinkInProgress) { - if (pLed->CurrLedState == LED_BLINK_SCAN) - return; - pLed->bLedBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_TXRX; - pLed->BlinkTimes = 2; - if (pLed->bLedOn) - pLed->BlinkingLedState = RTW_LED_OFF; - else - pLed->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); - } - break; - case LED_CTL_POWER_OFF: - pLed->CurrLedState = RTW_LED_OFF; - pLed->BlinkingLedState = RTW_LED_OFF; - - if (pLed->bLedBlinkInProgress) { - _cancel_timer_ex(&(pLed->BlinkTimer)); - pLed->bLedBlinkInProgress = false; - } SwLedOff(padapter, pLed); break; default: @@ -1572,73 +443,18 @@ SwLedControlMode5( RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState)); } - /* WNC-Corega, added by chiyoko, 20090902 */ -static void -SwLedControlMode6( - struct adapter *padapter, - enum LED_CTL_MODE LedAction -) -{ - struct led_priv *ledpriv = &(padapter->ledpriv); - struct LED_871x *pLed0 = &(ledpriv->SwLed0); - - switch (LedAction) { - case LED_CTL_POWER_ON: - case LED_CTL_LINK: - case LED_CTL_NO_LINK: - _cancel_timer_ex(&(pLed0->BlinkTimer)); - pLed0->CurrLedState = RTW_LED_ON; - pLed0->BlinkingLedState = RTW_LED_ON; - _set_timer(&(pLed0->BlinkTimer), 0); - break; - case LED_CTL_POWER_OFF: - SwLedOff(padapter, pLed0); - break; - default: - break; - } - - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("ledcontrol 6 Led %d\n", pLed0->CurrLedState)); -} - /* */ /* Description: */ /* Handler function of LED Blinking. */ -/* We dispatch acture LED blink action according to LedStrategy. */ /* */ void BlinkHandler(struct LED_871x *pLed) { struct adapter *padapter = pLed->padapter; - struct led_priv *ledpriv = &(padapter->ledpriv); if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped)) return; - switch (ledpriv->LedStrategy) { - case SW_LED_MODE0: - SwLedBlink(pLed); - break; - case SW_LED_MODE1: - SwLedBlink1(pLed); - break; - case SW_LED_MODE2: - SwLedBlink2(pLed); - break; - case SW_LED_MODE3: - SwLedBlink3(pLed); - break; - case SW_LED_MODE4: - SwLedBlink4(pLed); - break; - case SW_LED_MODE5: - SwLedBlink5(pLed); - break; - case SW_LED_MODE6: - SwLedBlink6(pLed); - break; - default: - break; - } + SwLedBlink1(pLed); } void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction) @@ -1661,32 +477,5 @@ void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction) LedAction == LED_CTL_POWER_ON)) return; - switch (ledpriv->LedStrategy) { - case SW_LED_MODE0: - break; - case SW_LED_MODE1: - SwLedControlMode1(padapter, LedAction); - break; - case SW_LED_MODE2: - SwLedControlMode2(padapter, LedAction); - break; - case SW_LED_MODE3: - SwLedControlMode3(padapter, LedAction); - break; - case SW_LED_MODE4: - SwLedControlMode4(padapter, LedAction); - break; - case SW_LED_MODE5: - SwLedControlMode5(padapter, LedAction); - break; - case SW_LED_MODE6: - SwLedControlMode6(padapter, LedAction); - break; - default: - break; - } - - RT_TRACE(_module_rtl8712_led_c_, _drv_info_, - ("LedStrategy:%d, LedAction %d\n", - ledpriv->LedStrategy, LedAction)); + SwLedControlMode1(padapter, LedAction); } diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index 3ed5941bedc3c6..55be52fb34a967 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -6600,13 +6600,13 @@ u8 collect_bss_info(struct adapter *padapter, struct recv_frame *precv_frame, st return _FAIL; } - if (*(p + 1)) { + if (len) { if (len > NDIS_802_11_LENGTH_SSID) { DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); return _FAIL; } - memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); - bssid->Ssid.SsidLength = *(p + 1); + memcpy(bssid->Ssid.Ssid, (p + 2), len); + bssid->Ssid.SsidLength = len; } else { bssid->Ssid.SsidLength = 0; } diff --git a/drivers/staging/rtl8188eu/core/rtw_p2p.c b/drivers/staging/rtl8188eu/core/rtw_p2p.c index 9425c4991ccd60..0a15f8cf0d366c 100644 --- a/drivers/staging/rtl8188eu/core/rtw_p2p.c +++ b/drivers/staging/rtl8188eu/core/rtw_p2p.c @@ -1505,9 +1505,9 @@ static void find_phase_handler(struct adapter *padapter) rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); - spin_lock_bh(&pmlmepriv->lock); - rtw_sitesurvey_cmd(padapter, &ssid, 1, NULL, 0); - spin_unlock_bh(&pmlmepriv->lock); + spin_lock_bh(&pmlmepriv->lock); + rtw_sitesurvey_cmd(padapter, &ssid, 1, NULL, 0); + spin_unlock_bh(&pmlmepriv->lock); } void p2p_concurrent_handler(struct adapter *padapter); diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index e305d43ebd0656..da26fa5cb25997 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -289,55 +289,6 @@ u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter) return cnt; } -int rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue) -{ - spin_lock_bh(&queue->lock); - - rtw_list_delete(&precvbuf->list); - rtw_list_insert_head(&precvbuf->list, get_list_head(queue)); - - spin_unlock_bh(&queue->lock); - - return _SUCCESS; -} - -int rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue) -{ - unsigned long irqL; - spin_lock_irqsave(&queue->lock, irqL); - - rtw_list_delete(&precvbuf->list); - - rtw_list_insert_tail(&precvbuf->list, get_list_head(queue)); - spin_unlock_irqrestore(&queue->lock, irqL); - return _SUCCESS; -} - -struct recv_buf *rtw_dequeue_recvbuf (struct __queue *queue) -{ - unsigned long irqL; - struct recv_buf *precvbuf; - struct list_head *plist, *phead; - - spin_lock_irqsave(&queue->lock, irqL); - - if (_rtw_queue_empty(queue)) { - precvbuf = NULL; - } else { - phead = get_list_head(queue); - - plist = phead->next; - - precvbuf = container_of(plist, struct recv_buf, list); - - rtw_list_delete(&precvbuf->list); - } - - spin_unlock_irqrestore(&queue->lock, irqL); - - return precvbuf; -} - static int recvframe_chkmic(struct adapter *adapter, struct recv_frame *precvframe) { @@ -1871,7 +1822,7 @@ static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reor return true; prhdr = container_of(plist, struct recv_frame, list); - pattrib = &prhdr->attrib; + pattrib = &prhdr->attrib; preorder_ctrl->indicate_seq = pattrib->seq_num; } diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c index c4b16ea6348aed..05335959b54340 100644 --- a/drivers/staging/rtl8188eu/core/rtw_security.c +++ b/drivers/staging/rtl8188eu/core/rtw_security.c @@ -1153,7 +1153,7 @@ static int aes_cipher(u8 *key, uint hdrlen, u8 *pframe, uint plen) /* Insert MIC into payload */ for (j = 0; j < 8; j++) - pframe[payload_index+j] = mic[j]; /* message[payload_index+j] = mic[j]; */ + pframe[payload_index+j] = mic[j]; payload_index = hdrlen + 8; for (i = 0; i < num_blocks; i++) { diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c index 3dd90599fd4be2..6c9e9a16b2e93f 100644 --- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c @@ -1599,13 +1599,18 @@ int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, uint var_ie_l pIE = (struct ndis_802_11_var_ie *)rtw_get_ie(pvar_ie, _SUPPORTEDRATES_IE_, &ie_len, var_ie_len); if (pIE == NULL) return _FAIL; + if (ie_len > NDIS_802_11_LENGTH_RATES_EX) + return _FAIL; memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, pIE->data, ie_len); supportRateNum = ie_len; pIE = (struct ndis_802_11_var_ie *)rtw_get_ie(pvar_ie, _EXT_SUPPORTEDRATES_IE_, &ie_len, var_ie_len); - if (pIE) + if (pIE) { + if (supportRateNum + ie_len > NDIS_802_11_LENGTH_RATES_EX) + return _FAIL; memcpy((pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + supportRateNum), pIE->data, ie_len); + } return _SUCCESS; } diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c index 08dfd94163e6b0..77dce584f0db29 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c @@ -35,16 +35,7 @@ void SwLedOn(struct adapter *padapter, struct LED_871x *pLed) if (padapter->bSurpriseRemoved || padapter->bDriverStopped) return; LedCfg = rtw_read8(padapter, REG_LEDCFG2); - switch (pLed->LedPin) { - case LED_PIN_LED0: - rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0xf0)|BIT5|BIT6); /* SW control led0 on. */ - break; - case LED_PIN_LED1: - rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0x0f)|BIT5); /* SW control led1 on. */ - break; - default: - break; - } + rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0xf0)|BIT5|BIT6); /* SW control led0 on. */ pLed->bLedOn = true; } @@ -60,25 +51,15 @@ void SwLedOff(struct adapter *padapter, struct LED_871x *pLed) LedCfg = rtw_read8(padapter, REG_LEDCFG2);/* 0x4E */ - switch (pLed->LedPin) { - case LED_PIN_LED0: - if (pHalData->bLedOpenDrain) { + if (pHalData->bLedOpenDrain) { /* Open-drain arrangement for controlling the LED) */ - LedCfg &= 0x90; /* Set to software control. */ - rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3)); - LedCfg = rtw_read8(padapter, REG_MAC_PINMUX_CFG); - LedCfg &= 0xFE; - rtw_write8(padapter, REG_MAC_PINMUX_CFG, LedCfg); - } else { - rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3|BIT5|BIT6)); - } - break; - case LED_PIN_LED1: - LedCfg &= 0x0f; /* Set to software control. */ + LedCfg &= 0x90; /* Set to software control. */ rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3)); - break; - default: - break; + LedCfg = rtw_read8(padapter, REG_MAC_PINMUX_CFG); + LedCfg &= 0xFE; + rtw_write8(padapter, REG_MAC_PINMUX_CFG, LedCfg); + } else { + rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3|BIT5|BIT6)); } exit: pLed->bLedOn = false; @@ -92,12 +73,13 @@ void SwLedOff(struct adapter *padapter, struct LED_871x *pLed) void rtl8188eu_InitSwLeds(struct adapter *padapter) { struct led_priv *pledpriv = &(padapter->ledpriv); + struct hal_data_8188e *haldata = GET_HAL_DATA(padapter); + pledpriv->bRegUseLed = true; pledpriv->LedControlHandler = LedControl8188eu; + haldata->bLedOpenDrain = true; - InitLed871x(padapter, &(pledpriv->SwLed0), LED_PIN_LED0); - - InitLed871x(padapter, &(pledpriv->SwLed1), LED_PIN_LED1); + InitLed871x(padapter, &(pledpriv->SwLed0)); } /* Description: */ @@ -107,5 +89,4 @@ void rtl8188eu_DeInitSwLeds(struct adapter *padapter) struct led_priv *ledpriv = &(padapter->ledpriv); DeInitLed871x(&(ledpriv->SwLed0)); - DeInitLed871x(&(ledpriv->SwLed1)); } diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c index b1b1584af1cdc3..2b4556414e8ada 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c @@ -28,22 +28,6 @@ #include -void rtl8188eu_init_recvbuf(struct adapter *padapter, struct recv_buf *precvbuf) -{ - precvbuf->transfer_len = 0; - - precvbuf->len = 0; - - precvbuf->ref_cnt = 0; - - if (precvbuf->pbuf) { - precvbuf->pdata = precvbuf->pbuf; - precvbuf->phead = precvbuf->pbuf; - precvbuf->ptail = precvbuf->pbuf; - precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ; - } -} - int rtl8188eu_init_recv_priv(struct adapter *padapter) { struct recv_priv *precvpriv = &padapter->recvpriv; @@ -71,13 +55,9 @@ int rtl8188eu_init_recv_priv(struct adapter *padapter) precvbuf = (struct recv_buf *)precvpriv->precv_buf; for (i = 0; i < NR_RECVBUFF; i++) { - _rtw_init_listhead(&precvbuf->list); - spin_lock_init(&precvbuf->recvbuf_lock); - precvbuf->alloc_sz = MAX_RECVBUF_SZ; res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf); if (res == _FAIL) break; - precvbuf->ref_cnt = 0; precvbuf->adapter = padapter; precvbuf++; } diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c index c92067f0ef1551..617e4c68dfa11e 100644 --- a/drivers/staging/rtl8188eu/hal/usb_halinit.c +++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c @@ -424,18 +424,6 @@ static void _InitBeaconMaxError(struct adapter *Adapter, bool InfraMode) { } -static void _InitHWLed(struct adapter *Adapter) -{ - struct led_priv *pledpriv = &(Adapter->ledpriv); - - if (pledpriv->LedStrategy != HW_LED) - return; - -/* HW led control */ -/* to do .... */ -/* must consider cases of antenna diversity/ commbo card/solo card/mini card */ -} - static void _InitRDGSetting(struct adapter *Adapter) { rtw_write8(Adapter, REG_RD_CTRL, 0xFF); @@ -870,8 +858,6 @@ static u32 rtl8188eu_hal_init(struct adapter *Adapter) rtw_write16(Adapter, REG_PKT_VO_VI_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */ rtw_write16(Adapter, REG_PKT_BE_BK_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */ - _InitHWLed(Adapter); - /* Keep RfRegChnlVal for later use. */ haldata->RfRegChnlVal[0] = PHY_QueryRFReg(Adapter, (enum rf_radio_path)0, RF_CHNLBW, bRFRegOffsetMask); haldata->RfRegChnlVal[1] = PHY_QueryRFReg(Adapter, (enum rf_radio_path)1, RF_CHNLBW, bRFRegOffsetMask); @@ -1129,16 +1115,6 @@ static unsigned int rtl8188eu_inirp_deinit(struct adapter *Adapter) /* EEPROM/EFUSE Content Parsing */ /* */ /* */ -static void _ReadLEDSetting(struct adapter *Adapter, u8 *PROMContent, bool AutoloadFail) -{ - struct led_priv *pledpriv = &(Adapter->ledpriv); - struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); - - pledpriv->bRegUseLed = true; - pledpriv->LedStrategy = SW_LED_MODE1; - haldata->bLedOpenDrain = true;/* Support Open-drain arrangement for controlling the LED. */ -} - static void Hal_EfuseParsePIDVID_8188EU(struct adapter *adapt, u8 *hwinfo, bool AutoLoadFail) { struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); @@ -1215,8 +1191,6 @@ readAdapterInfo_8188EU( /* */ Hal_InitChannelPlan(adapt); Hal_CustomizeByCustomerID_8188EU(adapt); - - _ReadLEDSetting(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); } static void _ReadPROMContent( diff --git a/drivers/staging/rtl8188eu/hal/usb_ops_linux.c b/drivers/staging/rtl8188eu/hal/usb_ops_linux.c index 1fa5370f1da60d..d8fc7472eb901f 100644 --- a/drivers/staging/rtl8188eu/hal/usb_ops_linux.c +++ b/drivers/staging/rtl8188eu/hal/usb_ops_linux.c @@ -518,7 +518,6 @@ static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs) } else { rtw_reset_continual_urb_error(adapter_to_dvobj(adapt)); - precvbuf->transfer_len = purb->actual_length; skb_put(precvbuf->pskb, purb->actual_length); skb_queue_tail(&precvpriv->rx_skb_queue, precvbuf->pskb); @@ -601,8 +600,6 @@ static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) precvbuf->reuse = true; } - rtl8188eu_init_recvbuf(adapter, precvbuf); - /* re-assign for linux based on skb */ if ((!precvbuf->reuse) || (precvbuf->pskb == NULL)) { precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); @@ -615,19 +612,7 @@ static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) tmpaddr = (size_t)precvbuf->pskb->data; alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); - - precvbuf->phead = precvbuf->pskb->head; - precvbuf->pdata = precvbuf->pskb->data; - precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); - precvbuf->pend = skb_end_pointer(precvbuf->pskb); - precvbuf->pbuf = precvbuf->pskb->data; } else { /* reuse skb */ - precvbuf->phead = precvbuf->pskb->head; - precvbuf->pdata = precvbuf->pskb->data; - precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); - precvbuf->pend = skb_end_pointer(precvbuf->pskb); - precvbuf->pbuf = precvbuf->pskb->data; - precvbuf->reuse = false; } @@ -639,7 +624,7 @@ static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) pipe = ffaddr2pipehdl(pdvobj, addr); usb_fill_bulk_urb(purb, pusbd, pipe, - precvbuf->pbuf, + precvbuf->pskb->data, MAX_RECVBUF_SZ, usb_read_port_complete, precvbuf);/* context is precvbuf */ diff --git a/drivers/staging/rtl8188eu/include/drv_types.h b/drivers/staging/rtl8188eu/include/drv_types.h index 936c196699af6b..10cc1a1bcab94a 100644 --- a/drivers/staging/rtl8188eu/include/drv_types.h +++ b/drivers/staging/rtl8188eu/include/drv_types.h @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/drivers/staging/rtl8188eu/include/drv_types_linux.h b/drivers/staging/rtl8188eu/include/drv_types_linux.h deleted file mode 100644 index 812b7440d4b00f..00000000000000 --- a/drivers/staging/rtl8188eu/include/drv_types_linux.h +++ /dev/null @@ -1,24 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. - * - * 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, 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, USA - * - * - ******************************************************************************/ -#ifndef __DRV_TYPES_LINUX_H__ -#define __DRV_TYPES_LINUX_H__ - - -#endif diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_recv.h b/drivers/staging/rtl8188eu/include/rtl8188e_recv.h index 07e5f522733612..5fed30d389a246 100644 --- a/drivers/staging/rtl8188eu/include/rtl8188e_recv.h +++ b/drivers/staging/rtl8188eu/include/rtl8188e_recv.h @@ -56,7 +56,6 @@ enum rx_packet_type { }; #define INTERRUPT_MSG_FORMAT_LEN 60 -void rtl8188eu_init_recvbuf(struct adapter *padapter, struct recv_buf *buf); s32 rtl8188eu_init_recv_priv(struct adapter *padapter); void rtl8188eu_free_recv_priv(struct adapter *padapter); void rtl8188eu_recv_hdl(struct adapter *padapter, struct recv_buf *precvbuf); diff --git a/drivers/staging/rtl8188eu/include/rtw_cmd.h b/drivers/staging/rtl8188eu/include/rtw_cmd.h index 3d347029ff7ab0..66467f711a5995 100644 --- a/drivers/staging/rtl8188eu/include/rtw_cmd.h +++ b/drivers/staging/rtl8188eu/include/rtw_cmd.h @@ -807,7 +807,6 @@ u8 rtw_chk_hi_queue_cmd(struct adapter *padapter); u8 rtw_set_ch_cmd(struct adapter *padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue); u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue); -u8 rtw_led_blink_cmd(struct adapter *padapter, struct LED_871x *pLed); u8 rtw_set_csa_cmd(struct adapter *padapter, u8 new_ch_no); u8 rtw_tdls_cmd(struct adapter *padapter, u8 *addr, u8 option); diff --git a/drivers/staging/rtl8188eu/include/rtw_led.h b/drivers/staging/rtl8188eu/include/rtw_led.h index 0da4e27a70faed..c5194b620da491 100644 --- a/drivers/staging/rtl8188eu/include/rtw_led.h +++ b/drivers/staging/rtl8188eu/include/rtw_led.h @@ -23,92 +23,43 @@ #include #include -#define MSECS(t) (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000) - -#define LED_BLINK_NORMAL_INTERVAL 100 -#define LED_BLINK_SLOWLY_INTERVAL 200 -#define LED_BLINK_LONG_INTERVAL 400 - #define LED_BLINK_NO_LINK_INTERVAL_ALPHA 1000 #define LED_BLINK_LINK_INTERVAL_ALPHA 500 /* 500 */ #define LED_BLINK_SCAN_INTERVAL_ALPHA 180 /* 150 */ #define LED_BLINK_FASTER_INTERVAL_ALPHA 50 #define LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA 5000 -#define LED_BLINK_NORMAL_INTERVAL_NETTRONIX 100 -#define LED_BLINK_SLOWLY_INTERVAL_NETTRONIX 2000 - -#define LED_BLINK_SLOWLY_INTERVAL_PORNET 1000 -#define LED_BLINK_NORMAL_INTERVAL_PORNET 100 - -#define LED_BLINK_FAST_INTERVAL_BITLAND 30 - -/* 060403, rcnjko: Customized for AzWave. */ -#define LED_CM2_BLINK_ON_INTERVAL 250 -#define LED_CM2_BLINK_OFF_INTERVAL 4750 - -#define LED_CM8_BLINK_INTERVAL 500 /* for QMI */ -#define LED_CM8_BLINK_OFF_INTERVAL 3750 /* for QMI */ - -/* 080124, lanhsin: Customized for RunTop */ -#define LED_RunTop_BLINK_INTERVAL 300 - -/* 060421, rcnjko: Customized for Sercomm Printer Server case. */ -#define LED_CM3_BLINK_INTERVAL 1500 - enum LED_CTL_MODE { - LED_CTL_POWER_ON = 1, - LED_CTL_LINK = 2, - LED_CTL_NO_LINK = 3, - LED_CTL_TX = 4, - LED_CTL_RX = 5, - LED_CTL_SITE_SURVEY = 6, - LED_CTL_POWER_OFF = 7, - LED_CTL_START_TO_LINK = 8, - LED_CTL_START_WPS = 9, - LED_CTL_STOP_WPS = 10, - LED_CTL_START_WPS_BOTTON = 11, /* added for runtop */ - LED_CTL_STOP_WPS_FAIL = 12, /* added for ALPHA */ - LED_CTL_STOP_WPS_FAIL_OVERLAP = 13, /* added for BELKIN */ - LED_CTL_CONNECTION_NO_TRANSFER = 14, + LED_CTL_POWER_ON, + LED_CTL_LINK, + LED_CTL_NO_LINK, + LED_CTL_TX, + LED_CTL_RX , + LED_CTL_SITE_SURVEY, + LED_CTL_POWER_OFF, + LED_CTL_START_TO_LINK, + LED_CTL_START_WPS, + LED_CTL_STOP_WPS, + LED_CTL_START_WPS_BOTTON, + LED_CTL_STOP_WPS_FAIL }; enum LED_STATE_871x { - LED_UNKNOWN = 0, - RTW_LED_ON = 1, - RTW_LED_OFF = 2, - LED_BLINK_NORMAL = 3, - LED_BLINK_SLOWLY = 4, - LED_BLINK_POWER_ON = 5, - LED_BLINK_SCAN = 6, /* LED is blinking during scanning period, - * the # of times to blink is depend on time - * for scanning. */ - LED_BLINK_NO_LINK = 7, /* LED is blinking during no link state. */ - LED_BLINK_StartToBlink = 8,/* Customzied for Sercomm Printer - * Server case */ - LED_BLINK_TXRX = 9, - LED_BLINK_WPS = 10, /* LED is blinkg during WPS communication */ - LED_BLINK_WPS_STOP = 11, /* for ALPHA */ - LED_BLINK_WPS_STOP_OVERLAP = 12, /* for BELKIN */ - LED_BLINK_RUNTOP = 13, /* Customized for RunTop */ - LED_BLINK_CAMEO = 14, - LED_BLINK_XAVI = 15, - LED_BLINK_ALWAYS_ON = 16, -}; - -enum LED_PIN_871x { - LED_PIN_NULL = 0, - LED_PIN_LED0 = 1, - LED_PIN_LED1 = 2, - LED_PIN_LED2 = 3, - LED_PIN_GPIO0 = 4, + LED_UNKNOWN, + RTW_LED_ON, + RTW_LED_OFF, + LED_BLINK_NORMAL, + LED_BLINK_SLOWLY, + LED_BLINK_POWER_ON, + LED_BLINK_SCAN, + LED_BLINK_TXRX, + LED_BLINK_WPS, + LED_BLINK_WPS_STOP }; struct LED_871x { struct adapter *padapter; - enum LED_PIN_871x LedPin; /* Identify how to implement this - * SW led. */ enum LED_STATE_871x CurrLedState; /* Current LED state. */ enum LED_STATE_871x BlinkingLedState; /* Next state for blinking, * either RTW_LED_ON or RTW_LED_OFF are. */ @@ -139,34 +90,11 @@ struct LED_871x { ((struct LED_871x *)_LED_871x)->CurrLedState == LED_BLINK_WPS_STOP || \ ((struct LED_871x *)_LED_871x)->bLedWPSBlinkInProgress) -#define IS_LED_BLINKING(_LED_871x) \ - (((struct LED_871x *)_LED_871x)->bLedWPSBlinkInProgress || \ - ((struct LED_871x *)_LED_871x)->bLedScanBlinkInProgress) - -/* LED customization. */ - -enum LED_STRATEGY_871x { - SW_LED_MODE0 = 0, /* SW control 1 LED via GPIO0. It is default option.*/ - SW_LED_MODE1 = 1, /* 2 LEDs, through LED0 and LED1. For ALPHA. */ - SW_LED_MODE2 = 2, /* SW control 1 LED via GPIO0, customized for AzWave - * 8187 minicard. */ - SW_LED_MODE3 = 3, /* SW control 1 LED via GPIO0, customized for Sercomm - * Printer Server case. */ - SW_LED_MODE4 = 4, /* for Edimax / Belkin */ - SW_LED_MODE5 = 5, /* for Sercomm / Belkin */ - SW_LED_MODE6 = 6, /* for 88CU minicard, porting from ce SW_LED_MODE7 */ - HW_LED = 50, /* HW control 2 LEDs, LED0 and LED1 (there are 4 - * different control modes, see MAC.CONFIG1 for details.)*/ - LED_ST_NONE = 99, -}; - void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction); struct led_priv{ /* add for led control */ struct LED_871x SwLed0; - struct LED_871x SwLed1; - enum LED_STRATEGY_871x LedStrategy; u8 bRegUseLed; void (*LedControlHandler)(struct adapter *padapter, enum LED_CTL_MODE LedAction); @@ -184,8 +112,7 @@ void BlinkWorkItemCallback(struct work_struct *work); void ResetLedStatus(struct LED_871x *pLed); -void InitLed871x(struct adapter *padapter, struct LED_871x *pLed, - enum LED_PIN_871x LedPin); +void InitLed871x(struct adapter *padapter, struct LED_871x *pLed); void DeInitLed871x(struct LED_871x *pLed); diff --git a/drivers/staging/rtl8188eu/include/rtw_recv.h b/drivers/staging/rtl8188eu/include/rtw_recv.h index bcbce46cec8502..971dd16d4a2792 100644 --- a/drivers/staging/rtl8188eu/include/rtw_recv.h +++ b/drivers/staging/rtl8188eu/include/rtw_recv.h @@ -235,22 +235,8 @@ struct sta_recv_priv { }; struct recv_buf { - struct list_head list; - spinlock_t recvbuf_lock; - u32 ref_cnt; struct adapter *adapter; - u8 *pbuf; - u8 *pallocated_buf; - u32 len; - u8 *phead; - u8 *pdata; - u8 *ptail; - u8 *pend; struct urb *purb; - dma_addr_t dma_transfer_addr; /* (in) dma addr for transfer_buffer */ - u32 alloc_sz; - u8 irp_pending; - int transfer_len; struct sk_buff *pskb; u8 reuse; }; @@ -302,9 +288,6 @@ int rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue); void rtw_free_recvframe_queue(struct __queue *pframequeue, struct __queue *pfree_recv_queue); u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter); -int rtw_enqueue_recvbuf_to_head(struct recv_buf *buf, struct __queue *queue); -int rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue); -struct recv_buf *rtw_dequeue_recvbuf(struct __queue *queue); void rtw_reordering_ctrl_timeout_handler(void *pcontext); diff --git a/drivers/staging/rtl8188eu/include/xmit_osdep.h b/drivers/staging/rtl8188eu/include/xmit_osdep.h index 2ff622ba24f0b4..48bc5fca996d1a 100644 --- a/drivers/staging/rtl8188eu/include/xmit_osdep.h +++ b/drivers/staging/rtl8188eu/include/xmit_osdep.h @@ -32,10 +32,6 @@ struct pkt_file { size_t buf_len; }; -extern int rtw_ht_enable; -extern int rtw_cbw40_enable; -extern int rtw_ampdu_enable;/* for enable tx_ampdu */ - #define NR_XMITFRAME 256 struct xmit_priv; diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c index b225d1c0721095..9edb8e880ae8aa 100644 --- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c +++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c @@ -84,9 +84,9 @@ static int rtw_uapsd_acbe_en; static int rtw_uapsd_acvi_en; static int rtw_uapsd_acvo_en; -int rtw_ht_enable = 1; -int rtw_cbw40_enable = 3; /* 0 :disable, bit(0): enable 2.4g, bit(1): enable 5g */ -int rtw_ampdu_enable = 1;/* for enable tx_ampdu */ +static int rtw_ht_enable = 1; +static int rtw_cbw40_enable = 3; /* 0 :disable, bit(0): enable 2.4g, bit(1): enable 5g */ +static int rtw_ampdu_enable = 1;/* for enable tx_ampdu */ static int rtw_rx_stbc = 1;/* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */ static int rtw_ampdu_amsdu;/* 0: disabled, 1:enabled, 2:auto */ diff --git a/drivers/staging/rtl8188eu/os_dep/recv_linux.c b/drivers/staging/rtl8188eu/os_dep/recv_linux.c index da397e4c6773de..29ec0148b5738b 100644 --- a/drivers/staging/rtl8188eu/os_dep/recv_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/recv_linux.c @@ -55,20 +55,11 @@ int rtw_os_recvbuf_resource_alloc(struct adapter *padapter, { int res = _SUCCESS; - precvbuf->irp_pending = false; precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); if (precvbuf->purb == NULL) res = _FAIL; precvbuf->pskb = NULL; precvbuf->reuse = false; - precvbuf->pallocated_buf = NULL; - precvbuf->pbuf = NULL; - precvbuf->pdata = NULL; - precvbuf->phead = NULL; - precvbuf->ptail = NULL; - precvbuf->pend = NULL; - precvbuf->transfer_len = 0; - precvbuf->len = 0; return res; } @@ -229,14 +220,12 @@ void rtw_os_read_port(struct adapter *padapter, struct recv_buf *precvbuf) { struct recv_priv *precvpriv = &padapter->recvpriv; - precvbuf->ref_cnt--; /* free skb in recv_buf */ dev_kfree_skb_any(precvbuf->pskb); precvbuf->pskb = NULL; precvbuf->reuse = false; - if (!precvbuf->irp_pending) - rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, - (unsigned char *)precvbuf); + rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, + (unsigned char *)precvbuf); } static void _rtw_reordering_ctrl_timeout_handler(void *func_context) diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 2e49cd583212a7..8ed2ac89f5c561 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -62,10 +62,6 @@ static struct usb_device_id rtw_usb_id_tbl[] = { MODULE_DEVICE_TABLE(usb, rtw_usb_id_tbl); -static struct specific_device_id specific_device_id_tbl[] = { - {} /* empty table for now */ -}; - struct rtw_usb_drv { struct usb_driver usbdrv; int drv_registered; @@ -84,46 +80,6 @@ static struct rtw_usb_drv rtl8188e_usb_drv = { static struct rtw_usb_drv *usb_drv = &rtl8188e_usb_drv; -static inline int RT_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) -{ - return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN; -} - -static inline int RT_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) -{ - return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; -} - -static inline int RT_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) -{ - return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT; -} - -static inline int RT_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) -{ - return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK; -} - -static inline int RT_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) -{ - return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_in(epd); -} - -static inline int RT_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) -{ - return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_out(epd); -} - -static inline int usb_endpoint_is_int(const struct usb_endpoint_descriptor *epd) -{ - return RT_usb_endpoint_xfer_int(epd) && RT_usb_endpoint_dir_in(epd); -} - -static inline int RT_usb_endpoint_num(const struct usb_endpoint_descriptor *epd) -{ - return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; -} - static u8 rtw_init_intf_priv(struct dvobj_priv *dvobj) { u8 rst = _SUCCESS; @@ -187,60 +143,35 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints; for (i = 0; i < pdvobjpriv->nr_endpoint; i++) { + int ep_num; phost_endp = phost_iface->endpoint + i; + if (phost_endp) { pendp_desc = &phost_endp->desc; + ep_num = usb_endpoint_num(pendp_desc); - DBG_88E("\nusb_endpoint_descriptor(%d):\n", i); - DBG_88E("bLength=%x\n", pendp_desc->bLength); - DBG_88E("bDescriptorType=%x\n", - pendp_desc->bDescriptorType); - DBG_88E("bEndpointAddress=%x\n", - pendp_desc->bEndpointAddress); - DBG_88E("wMaxPacketSize=%d\n", - le16_to_cpu(pendp_desc->wMaxPacketSize)); - DBG_88E("bInterval=%x\n", pendp_desc->bInterval); - - if (RT_usb_endpoint_is_bulk_in(pendp_desc)) { - DBG_88E("RT_usb_endpoint_is_bulk_in = %x\n", - RT_usb_endpoint_num(pendp_desc)); - pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = RT_usb_endpoint_num(pendp_desc); + if (usb_endpoint_is_bulk_in(pendp_desc)) { + pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = ep_num; pdvobjpriv->RtNumInPipes++; - } else if (usb_endpoint_is_int(pendp_desc)) { - DBG_88E("usb_endpoint_is_int = %x, Interval = %x\n", - RT_usb_endpoint_num(pendp_desc), - pendp_desc->bInterval); - pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = RT_usb_endpoint_num(pendp_desc); + } else if (usb_endpoint_is_int_in(pendp_desc)) { + pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = ep_num; pdvobjpriv->RtNumInPipes++; - } else if (RT_usb_endpoint_is_bulk_out(pendp_desc)) { - DBG_88E("RT_usb_endpoint_is_bulk_out = %x\n", - RT_usb_endpoint_num(pendp_desc)); - pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] = RT_usb_endpoint_num(pendp_desc); + } else if (usb_endpoint_is_bulk_out(pendp_desc)) { + pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] = ep_num; pdvobjpriv->RtNumOutPipes++; } - pdvobjpriv->ep_num[i] = RT_usb_endpoint_num(pendp_desc); + pdvobjpriv->ep_num[i] = ep_num; } } - DBG_88E("nr_endpoint=%d, in_num=%d, out_num=%d\n\n", - pdvobjpriv->nr_endpoint, pdvobjpriv->RtNumInPipes, - pdvobjpriv->RtNumOutPipes); - - if (pusbd->speed == USB_SPEED_HIGH) { + if (pusbd->speed == USB_SPEED_HIGH) pdvobjpriv->ishighspeed = true; - DBG_88E("USB_SPEED_HIGH\n"); - } else { + else pdvobjpriv->ishighspeed = false; - DBG_88E("NON USB_SPEED_HIGH\n"); - } - if (rtw_init_intf_priv(pdvobjpriv) == _FAIL) { - RT_TRACE(_module_os_intfs_c_, _drv_err_, - ("\n Can't INIT rtw_init_intf_priv\n")); + if (rtw_init_intf_priv(pdvobjpriv) == _FAIL) goto free_dvobj; - } - /* 3 misc */ sema_init(&(pdvobjpriv->usb_suspend_sema), 0); rtw_reset_continual_urb_error(pdvobjpriv); @@ -360,28 +291,6 @@ static void rtw_dev_unload(struct adapter *padapter) RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-rtw_dev_unload\n")); } -static void process_spec_devid(const struct usb_device_id *pdid) -{ - u16 vid, pid; - u32 flags; - int i; - int num = sizeof(specific_device_id_tbl) / - sizeof(struct specific_device_id); - - for (i = 0; i < num; i++) { - vid = specific_device_id_tbl[i].idVendor; - pid = specific_device_id_tbl[i].idProduct; - flags = specific_device_id_tbl[i].flags; - - if ((pdid->idVendor == vid) && (pdid->idProduct == pid) && - (flags&SPEC_DEV_ID_DISABLE_HT)) { - rtw_ht_enable = 0; - rtw_cbw40_enable = 0; - rtw_ampdu_enable = 0; - } - } -} - int rtw_hw_suspend(struct adapter *padapter) { struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; @@ -781,9 +690,6 @@ static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_init\n")); - /* step 0. */ - process_spec_devid(pdid); - /* Initialize dvobj_priv */ dvobj = usb_dvobj_init(pusb_intf); if (dvobj == NULL) { diff --git a/drivers/staging/rtl8192e/rtl8192e/Kconfig b/drivers/staging/rtl8192e/rtl8192e/Kconfig index ad82bc348a75cc..282e293da18f03 100644 --- a/drivers/staging/rtl8192e/rtl8192e/Kconfig +++ b/drivers/staging/rtl8192e/rtl8192e/Kconfig @@ -5,4 +5,5 @@ config RTL8192E select WIRELESS_EXT select WEXT_PRIV select CRYPTO + select FW_LOADER ---help--- diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c index 5f10e4075d39b6..79d86b9e80099d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c @@ -373,7 +373,7 @@ u32 cmpk_message_handle_rx(struct net_device *dev, default: RT_TRACE(COMP_CMDPKT, "---->cmpk_message_handle_rx():" - "unknow CMD Element\n"); + "unknown CMD Element\n"); return 1; } diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c index abcd22f8fdda57..1a95d1f87f9469 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c @@ -228,13 +228,6 @@ bool init_firmware(struct net_device *dev) struct r8192_priv *priv = rtllib_priv(dev); bool rt_status = true; - u8 *firmware_img_buf[3] = { &Rtl8192PciEFwBootArray[0], - &Rtl8192PciEFwMainArray[0], - &Rtl8192PciEFwDataArray[0]}; - - u32 firmware_img_len[3] = { sizeof(Rtl8192PciEFwBootArray), - sizeof(Rtl8192PciEFwMainArray), - sizeof(Rtl8192PciEFwDataArray)}; u32 file_length = 0; u8 *mapped_file = NULL; u8 init_step = 0; @@ -257,77 +250,55 @@ bool init_firmware(struct net_device *dev) " firmware state\n"); } - priv->firmware_source = FW_SOURCE_IMG_FILE; for (init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) { if (rst_opt == OPT_SYSTEM_RESET) { - switch (priv->firmware_source) { - case FW_SOURCE_IMG_FILE: - { - if (pfirmware->firmware_buf_size[init_step] == 0) { - const char *fw_name[3] = { - RTL8192E_BOOT_IMG_FW, - RTL8192E_MAIN_IMG_FW, - RTL8192E_DATA_IMG_FW - }; - const struct firmware *fw_entry; - int rc; - rc = request_firmware(&fw_entry, - fw_name[init_step], &priv->pdev->dev); - if (rc < 0) { - RT_TRACE(COMP_FIRMWARE, "request firm" - "ware fail!\n"); - goto download_firmware_fail; - } - if (fw_entry->size > + if (pfirmware->firmware_buf_size[init_step] == 0) { + const char *fw_name[3] = { + RTL8192E_BOOT_IMG_FW, + RTL8192E_MAIN_IMG_FW, + RTL8192E_DATA_IMG_FW + }; + const struct firmware *fw_entry; + int rc; + rc = request_firmware(&fw_entry, + fw_name[init_step], + &priv->pdev->dev); + if (rc < 0) { + RT_TRACE(COMP_FIRMWARE, "request firmware fail!\n"); + goto download_firmware_fail; + } + if (fw_entry->size > sizeof(pfirmware->firmware_buf[init_step])) { - RT_TRACE(COMP_FIRMWARE, "img file size " + RT_TRACE(COMP_FIRMWARE, "img file size " "exceed the container struct " "buffer fail!\n"); - goto download_firmware_fail; - } + goto download_firmware_fail; + } - if (init_step != FW_INIT_STEP1_MAIN) { - memcpy(pfirmware->firmware_buf[init_step], + if (init_step != FW_INIT_STEP1_MAIN) { + memcpy(pfirmware->firmware_buf[init_step], fw_entry->data, fw_entry->size); - pfirmware->firmware_buf_size[init_step] = - fw_entry->size; + pfirmware->firmware_buf_size[init_step] = + fw_entry->size; - } else { - memset(pfirmware->firmware_buf[init_step], + } else { + memset(pfirmware->firmware_buf[init_step], 0, 128); - memcpy(&pfirmware->firmware_buf[init_step][128], + memcpy(&pfirmware->firmware_buf[init_step][128], fw_entry->data, fw_entry->size); - pfirmware->firmware_buf_size[init_step] = - fw_entry->size + 128; - } - - if (rst_opt == OPT_SYSTEM_RESET) - release_firmware(fw_entry); + pfirmware->firmware_buf_size[init_step] = + fw_entry->size + 128; } - mapped_file = pfirmware->firmware_buf[init_step]; - file_length = pfirmware->firmware_buf_size[init_step]; - break; - } - case FW_SOURCE_HEADER_FILE: - mapped_file = firmware_img_buf[init_step]; - file_length = firmware_img_len[init_step]; - if (init_step == FW_INIT_STEP2_DATA) { - memcpy(pfirmware->firmware_buf[init_step], mapped_file, file_length); - pfirmware->firmware_buf_size[init_step] = file_length; - } - break; - default: - break; + if (rst_opt == OPT_SYSTEM_RESET) + release_firmware(fw_entry); } - - - } else if (rst_opt == OPT_FIRMWARE_RESET) { - mapped_file = pfirmware->firmware_buf[init_step]; - file_length = pfirmware->firmware_buf_size[init_step]; } + mapped_file = pfirmware->firmware_buf[init_step]; + file_length = pfirmware->firmware_buf_size[init_step]; + rt_status = fw_download_code(dev, mapped_file, file_length); if (!rt_status) { goto download_firmware_fail; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h index 06d6abc8345cee..94fa16b4993dfe 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h @@ -43,11 +43,6 @@ enum desc_packet_type { DESC_PACKET_TYPE_NORMAL = 1, }; -enum firmware_source { - FW_SOURCE_IMG_FILE = 0, - FW_SOURCE_HEADER_FILE = 1, -}; - enum firmware_status { FW_STATUS_0_INIT = 0, FW_STATUS_1_MOVE_BOOT_CODE = 1, diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c index 08e7dbb6694ba7..6767b5965c1756 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c @@ -20,2777 +20,6 @@ #include "r8192E_hwimg.h" -u8 Rtl8192PciEFwBootArray[BootArrayLengthPciE] = { -0x10,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x3c,0x08,0xbf,0xc0,0x25,0x08,0x00,0x08, -0x3c,0x09,0xb0,0x03,0xad,0x28,0x00,0x20,0x40,0x80,0x68,0x00,0x00,0x00,0x00,0x00, -0x3c,0x0a,0xd0,0x00,0x40,0x8a,0x60,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x01, -0x25,0x08,0xa8,0x04,0x24,0x09,0x00,0x01,0x3c,0x01,0x7f,0xff,0x34,0x21,0xff,0xff, -0x01,0x01,0x50,0x24,0x00,0x09,0x48,0x40,0x35,0x29,0x00,0x01,0x01,0x2a,0x10,0x2b, -0x14,0x40,0xff,0xfc,0x00,0x00,0x00,0x00,0x3c,0x0a,0x00,0x00,0x25,0x4a,0x00,0x00, -0x4c,0x8a,0x00,0x00,0x4c,0x89,0x08,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x01, -0x25,0x08,0xa8,0x04,0x3c,0x01,0x80,0x00,0x01,0x21,0x48,0x25,0x3c,0x0a,0xbf,0xc0, -0x25,0x4a,0x00,0x7c,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0xad,0x00,0x00,0x00, -0x21,0x08,0x00,0x04,0x01,0x09,0x10,0x2b,0x14,0x40,0xff,0xf8,0x00,0x00,0x00,0x00, -0x3c,0x08,0x80,0x01,0x25,0x08,0x7f,0xff,0x24,0x09,0x00,0x01,0x3c,0x01,0x7f,0xff, -0x34,0x21,0xff,0xff,0x01,0x01,0x50,0x24,0x00,0x09,0x48,0x40,0x35,0x29,0x00,0x01, -0x01,0x2a,0x10,0x2b,0x14,0x40,0xff,0xfc,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x01, -0x25,0x4a,0x00,0x00,0x3c,0x01,0x7f,0xff,0x34,0x21,0xff,0xff,0x01,0x41,0x50,0x24, -0x3c,0x09,0x00,0x01,0x35,0x29,0x7f,0xff,0x4c,0x8a,0x20,0x00,0x4c,0x89,0x28,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x08,0x04,0x10, -0x00,0x00,0x00,0x00,0x40,0x88,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3c,0x08,0xbf,0xc0,0x00,0x00,0x00,0x00,0x8d,0x09,0x00,0x00,0x00,0x00,0x00,0x00, -0x3c,0x0a,0xbf,0xc0,0x25,0x4a,0x01,0x20,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, -0x3c,0x08,0xb0,0x03,0x8d,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x29,0x00,0x10, -0xad,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x00,0x25,0x08,0x4b,0x94, -0x01,0x00,0x00,0x08,0x00,0x00,0x00,0x00,}; - -u8 Rtl8192PciEFwMainArray[MainArrayLengthPciE] = { -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x40,0x04,0x68,0x00,0x40,0x05,0x70,0x00,0x40,0x06,0x40,0x00,0x0c,0x00,0x12,0x98, -0x00,0x00,0x00,0x00,0x40,0x1a,0x68,0x00,0x33,0x5b,0x00,0x3c,0x17,0x60,0x00,0x09, -0x00,0x00,0x00,0x00,0x40,0x1b,0x60,0x00,0x00,0x00,0x00,0x00,0x03,0x5b,0xd0,0x24, -0x40,0x1a,0x70,0x00,0x03,0x40,0x00,0x08,0x42,0x00,0x00,0x10,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0xff,0x34,0x42,0xff,0xff,0x8c,0x43,0x00,0x00, -0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x00,0xd0, -0xac,0x62,0x00,0x00,0x00,0x00,0x20,0x21,0x27,0x85,0x8b,0x70,0x00,0x85,0x18,0x21, -0x24,0x84,0x00,0x01,0x28,0x82,0x00,0x0a,0x14,0x40,0xff,0xfc,0xa0,0x60,0x00,0x00, -0x27,0x82,0x8b,0x7a,0x24,0x04,0x00,0x06,0x24,0x84,0xff,0xff,0xa4,0x40,0x00,0x00, -0x04,0x81,0xff,0xfd,0x24,0x42,0x00,0x02,0x24,0x02,0x00,0x03,0xa3,0x82,0x8b,0x70, -0x24,0x02,0x00,0x0a,0x24,0x03,0x09,0xc4,0xa3,0x82,0x8b,0x72,0x24,0x02,0x00,0x04, -0x24,0x04,0x00,0x01,0x24,0x05,0x00,0x02,0xa7,0x83,0x8b,0x86,0xa3,0x82,0x8b,0x78, -0x24,0x03,0x04,0x00,0x24,0x02,0x02,0x00,0xaf,0x83,0x8b,0x8c,0xa3,0x85,0x8b,0x79, -0xa7,0x82,0x8b,0x7a,0xa7,0x84,0x8b,0x7c,0xaf,0x84,0x8b,0x88,0xa3,0x84,0x8b,0x71, -0xa3,0x80,0x8b,0x73,0xa3,0x80,0x8b,0x74,0xa3,0x80,0x8b,0x75,0xa3,0x84,0x8b,0x76, -0xa3,0x85,0x8b,0x77,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, -0x3c,0x02,0x80,0x00,0x24,0x42,0x01,0x7c,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00, -0x27,0x84,0x8b,0x98,0x00,0x00,0x10,0x21,0x24,0x42,0x00,0x01,0x00,0x02,0x16,0x00, -0x00,0x02,0x16,0x03,0x28,0x43,0x00,0x03,0xac,0x80,0xff,0xfc,0xa0,0x80,0x00,0x00, -0x14,0x60,0xff,0xf9,0x24,0x84,0x00,0x0c,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, -0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x01,0xc0, -0x3c,0x08,0xb0,0x03,0xac,0x62,0x00,0x00,0x35,0x08,0x00,0x70,0x8d,0x02,0x00,0x00, -0x00,0xa0,0x48,0x21,0x00,0x04,0x26,0x00,0x00,0x02,0x2a,0x43,0x00,0x06,0x36,0x00, -0x00,0x07,0x3e,0x00,0x00,0x02,0x12,0x03,0x29,0x23,0x00,0x03,0x00,0x04,0x56,0x03, -0x00,0x06,0x36,0x03,0x00,0x07,0x3e,0x03,0x30,0x48,0x00,0x01,0x10,0x60,0x00,0x11, -0x30,0xa5,0x00,0x07,0x24,0x02,0x00,0x02,0x00,0x49,0x10,0x23,0x00,0x45,0x10,0x07, -0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x66,0x00,0x00,0x00,0x00,0x8f,0xa2,0x00,0x10, -0x00,0x00,0x00,0x00,0x00,0x02,0x21,0x43,0x11,0x00,0x00,0x10,0x00,0x07,0x20,0x0b, -0x15,0x20,0x00,0x06,0x24,0x02,0x00,0x01,0x3c,0x02,0xb0,0x05,0x34,0x42,0x01,0x20, -0xa4,0x44,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x11,0x22,0x00,0x04, -0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05,0x08,0x00,0x00,0x94,0x34,0x42,0x01,0x24, -0x3c,0x02,0xb0,0x05,0x08,0x00,0x00,0x94,0x34,0x42,0x01,0x22,0x15,0x20,0x00,0x54, -0x24,0x02,0x00,0x01,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x74,0x90,0x43,0x00,0x00, -0x00,0x00,0x00,0x00,0xaf,0x83,0x8b,0x94,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x70, -0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x6b,0x00,0x08,0x11,0x60,0x00,0x18, -0x00,0x09,0x28,0x40,0x00,0x00,0x40,0x21,0x27,0x85,0x8b,0x90,0x8c,0xa3,0x00,0x00, -0x8c,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x62,0x38,0x23,0x00,0x43,0x10,0x2a, -0x10,0x40,0x00,0x3d,0x00,0x00,0x00,0x00,0xac,0xa7,0x00,0x00,0x25,0x02,0x00,0x01, -0x00,0x02,0x16,0x00,0x00,0x02,0x46,0x03,0x29,0x03,0x00,0x03,0x14,0x60,0xff,0xf3, -0x24,0xa5,0x00,0x0c,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x70,0x90,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x4b,0x10,0x23,0xa0,0x62,0x00,0x00,0x00,0x09,0x28,0x40, -0x00,0xa9,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x8b,0x98,0x00,0x0a,0x20,0x0b, -0x00,0x43,0x18,0x21,0x10,0xc0,0x00,0x05,0x00,0x00,0x38,0x21,0x80,0x62,0x00,0x01, -0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x80,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03,0x00,0xa9,0x10,0x21,0x24,0x07,0x00,0x01, -0x00,0xa9,0x10,0x21,0x00,0x02,0x30,0x80,0x27,0x82,0x8b,0x98,0xa0,0x67,0x00,0x01, -0x00,0xc2,0x38,0x21,0x80,0xe3,0x00,0x01,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x07, -0x00,0x00,0x00,0x00,0x27,0x83,0x8b,0x90,0x00,0xc3,0x18,0x21,0x8c,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x21,0xac,0x62,0x00,0x00,0x27,0x85,0x8b,0x94, -0x27,0x82,0x8b,0x90,0x00,0xc5,0x28,0x21,0x00,0xc2,0x10,0x21,0x8c,0x43,0x00,0x00, -0x8c,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x18,0x2a,0x14,0x60,0x00,0x03, -0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08,0xa0,0xe2,0x00,0x00,0xa0,0xe0,0x00,0x00, -0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0xb7,0xac,0xa0,0x00,0x00, -0x11,0x22,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x7c, -0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x83,0x8b,0xac,0x08,0x00,0x00,0xa7, -0x3c,0x02,0xb0,0x03,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x78,0x90,0x43,0x00,0x00, -0x00,0x00,0x00,0x00,0xaf,0x83,0x8b,0xa0,0x08,0x00,0x00,0xa7,0x3c,0x02,0xb0,0x03, -0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x04,0x10, -0x3c,0x05,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0xa5,0x00,0x70,0x8c,0xa2,0x00,0x00, -0x90,0x84,0x00,0x08,0x3c,0x06,0xb0,0x03,0x00,0x02,0x16,0x00,0x2c,0x83,0x00,0x03, -0x34,0xc6,0x00,0x72,0x24,0x07,0x00,0x01,0x10,0x60,0x00,0x11,0x00,0x02,0x2f,0xc2, -0x90,0xc2,0x00,0x00,0x00,0x00,0x18,0x21,0x00,0x02,0x16,0x00,0x10,0xa7,0x00,0x09, -0x00,0x02,0x16,0x03,0x14,0x80,0x00,0x0c,0x30,0x43,0x00,0x03,0x83,0x82,0x8b,0x98, -0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0x02,0x16,0x00, -0x00,0x02,0x1e,0x03,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x72,0xa0,0x43,0x00,0x00, -0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0x45,0x00,0x05,0x10,0x87,0x00,0x04, -0x30,0x43,0x00,0x06,0x93,0x82,0x8b,0xb0,0x08,0x00,0x01,0x1f,0x00,0x43,0x10,0x21, -0x83,0x82,0x8b,0xa4,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x40,0x08,0x00,0x01,0x1f, -0x00,0x45,0x10,0x21,0x10,0x80,0x00,0x05,0x00,0x00,0x18,0x21,0x24,0x63,0x00,0x01, -0x00,0x64,0x10,0x2b,0x14,0x40,0xff,0xfd,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, -0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x04,0xe4, -0x3c,0x04,0xb0,0x02,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00,0x34,0x84,0x00,0x08, -0x24,0x02,0x00,0x01,0xaf,0x84,0x8b,0xc0,0xa3,0x82,0x8b,0xd0,0xa7,0x80,0x8b,0xc4, -0xa7,0x80,0x8b,0xc6,0xaf,0x80,0x8b,0xc8,0xaf,0x80,0x8b,0xcc,0x03,0xe0,0x00,0x08, -0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, -0x24,0x42,0x05,0x24,0x3c,0x04,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0x84,0x00,0xac, -0x80,0xa2,0x00,0x15,0x8c,0x83,0x00,0x00,0x27,0xbd,0xff,0xf0,0x00,0x43,0x10,0x21, -0xac,0x82,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x10,0x3c,0x02,0xb0,0x03, -0x3c,0x03,0x80,0x00,0x34,0x42,0x00,0x20,0x24,0x63,0x05,0x5c,0x27,0xbd,0xff,0xe0, -0xac,0x43,0x00,0x00,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x18, -0x8f,0x90,0x8b,0xc0,0x0c,0x00,0x02,0x98,0x00,0x80,0x88,0x21,0x14,0x40,0x00,0x2a, -0x3c,0x02,0x00,0x80,0x16,0x20,0x00,0x02,0x34,0x42,0x02,0x01,0x24,0x02,0x02,0x01, -0xae,0x02,0x00,0x00,0x97,0x84,0x8b,0xc4,0x97,0x82,0x8b,0xc6,0x3c,0x03,0xb0,0x02, -0x00,0x83,0x20,0x21,0x24,0x42,0x00,0x04,0xa7,0x82,0x8b,0xc6,0xa4,0x82,0x00,0x00, -0x8f,0x84,0x8b,0xc8,0x8f,0x82,0x8b,0xc0,0x93,0x85,0x8b,0x72,0x24,0x84,0x00,0x01, -0x24,0x42,0x00,0x04,0x24,0x03,0x8f,0xff,0x3c,0x07,0xb0,0x06,0x3c,0x06,0xb0,0x03, -0x00,0x43,0x10,0x24,0x00,0x85,0x28,0x2a,0x34,0xe7,0x80,0x18,0xaf,0x82,0x8b,0xc0, -0xaf,0x84,0x8b,0xc8,0x10,0xa0,0x00,0x08,0x34,0xc6,0x01,0x08,0x8f,0x83,0x8b,0xcc, -0x8f,0x84,0x8b,0x8c,0x8c,0xc2,0x00,0x00,0x00,0x64,0x18,0x21,0x00,0x43,0x10,0x2b, -0x14,0x40,0x00,0x09,0x00,0x00,0x00,0x00,0x8c,0xe2,0x00,0x00,0x3c,0x03,0x0f,0x00, -0x3c,0x04,0x04,0x00,0x00,0x43,0x10,0x24,0x10,0x44,0x00,0x03,0x00,0x00,0x00,0x00, -0x0c,0x00,0x04,0x96,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc, -0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xd8,0x3c,0x02,0xb0,0x03, -0x3c,0x03,0x80,0x00,0x24,0x63,0x06,0x48,0xaf,0xb0,0x00,0x10,0x34,0x42,0x00,0x20, -0x8f,0x90,0x8b,0xc0,0xac,0x43,0x00,0x00,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18, -0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x20,0x00,0x80,0x88,0x21,0x00,0xa0,0x90,0x21, -0x0c,0x00,0x02,0x98,0x00,0xc0,0x98,0x21,0x24,0x07,0x8f,0xff,0x14,0x40,0x00,0x19, -0x26,0x03,0x00,0x04,0x24,0x02,0x0e,0x03,0xae,0x02,0x00,0x00,0x00,0x67,0x80,0x24, -0x26,0x02,0x00,0x04,0xae,0x11,0x00,0x00,0x00,0x47,0x80,0x24,0x97,0x86,0x8b,0xc4, -0x26,0x03,0x00,0x04,0xae,0x12,0x00,0x00,0x00,0x67,0x80,0x24,0xae,0x13,0x00,0x00, -0x8f,0x84,0x8b,0xc0,0x3c,0x02,0xb0,0x02,0x97,0x85,0x8b,0xc6,0x00,0xc2,0x30,0x21, -0x8f,0x82,0x8b,0xc8,0x24,0x84,0x00,0x10,0x24,0xa5,0x00,0x10,0x00,0x87,0x20,0x24, -0x24,0x42,0x00,0x01,0xa7,0x85,0x8b,0xc6,0xaf,0x84,0x8b,0xc0,0xaf,0x82,0x8b,0xc8, -0xa4,0xc5,0x00,0x00,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc, -0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10, -0x94,0x82,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0xe0,0x00,0x14,0x40,0x00,0x14, -0x00,0x00,0x00,0x00,0x90,0x82,0x00,0x02,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfc, -0x00,0x82,0x28,0x21,0x8c,0xa4,0x00,0x00,0x3c,0x02,0x00,0x70,0x8c,0xa6,0x00,0x08, -0x00,0x82,0x10,0x21,0x2c,0x43,0x00,0x06,0x10,0x60,0x00,0x09,0x3c,0x03,0x80,0x01, -0x00,0x02,0x10,0x80,0x24,0x63,0x01,0xe8,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0xaf,0x86,0x80,0x14, -0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, -0x8c,0xa4,0x00,0x00,0x0c,0x00,0x17,0x84,0x00,0x00,0x00,0x00,0x08,0x00,0x01,0xdc, -0x00,0x00,0x00,0x00,0x0c,0x00,0x24,0x49,0x00,0xc0,0x20,0x21,0x08,0x00,0x01,0xdc, -0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08,0x8c,0x44,0x00,0x00, -0x8f,0x82,0x80,0x18,0x3c,0x03,0x00,0x0f,0x34,0x63,0x42,0x40,0x00,0x43,0x10,0x21, -0x00,0x82,0x20,0x2b,0x10,0x80,0x00,0x09,0x24,0x03,0x00,0x05,0x8f,0x82,0x83,0x60, -0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xaf,0x82,0x83,0x60,0x10,0x43,0x00,0x03, -0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, -0x8c,0x63,0x01,0x08,0x24,0x02,0x00,0x01,0xa3,0x82,0x80,0x11,0xaf,0x80,0x83,0x60, -0xaf,0x83,0x80,0x18,0x08,0x00,0x01,0xf9,0x00,0x00,0x00,0x00,0x30,0x84,0x00,0xff, -0x14,0x80,0x00,0x2f,0x00,0x00,0x00,0x00,0x8f,0x82,0x80,0x14,0xa3,0x85,0x83,0x93, -0x10,0x40,0x00,0x2b,0x2c,0xa2,0x00,0x04,0x14,0x40,0x00,0x06,0x00,0x05,0x10,0x40, -0x24,0xa2,0xff,0xfc,0x2c,0x42,0x00,0x08,0x10,0x40,0x00,0x09,0x24,0xa2,0xff,0xf0, -0x00,0x05,0x10,0x40,0x27,0x84,0x83,0x9c,0x00,0x44,0x10,0x21,0x94,0x43,0x00,0x00, -0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0x03,0xe0,0x00,0x08,0xa4,0x43,0x00,0x00, -0x2c,0x42,0x00,0x10,0x14,0x40,0x00,0x0a,0x00,0x05,0x10,0x40,0x24,0xa2,0xff,0xe0, -0x2c,0x42,0x00,0x10,0x14,0x40,0x00,0x06,0x00,0x05,0x10,0x40,0x24,0xa2,0xff,0xd0, -0x2c,0x42,0x00,0x10,0x10,0x40,0x00,0x09,0x24,0xa2,0xff,0xc0,0x00,0x05,0x10,0x40, -0x27,0x84,0x83,0x9c,0x00,0x44,0x10,0x21,0x94,0x43,0xff,0xf8,0x00,0x00,0x00,0x00, -0x24,0x63,0x00,0x01,0x03,0xe0,0x00,0x08,0xa4,0x43,0xff,0xf8,0x2c,0x42,0x00,0x10, -0x10,0x40,0x00,0x07,0x00,0x05,0x10,0x40,0x27,0x84,0x83,0x9c,0x00,0x44,0x10,0x21, -0x94,0x43,0xff,0xf8,0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0xa4,0x43,0xff,0xf8, -0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8f,0x86,0x8b,0xc0,0x8f,0x82,0x80,0x14, -0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x10,0x40,0x00,0x2a,0x00,0xc0,0x38,0x21, -0x24,0x02,0x00,0x07,0x24,0x03,0xff,0x9c,0xa3,0x82,0x83,0x9b,0xa3,0x83,0x83,0x9a, -0x27,0x8a,0x83,0x98,0x00,0x00,0x20,0x21,0x24,0x09,0x8f,0xff,0x00,0x04,0x10,0x80, -0x00,0x4a,0x28,0x21,0x8c,0xa2,0x00,0x00,0x24,0xe3,0x00,0x04,0x24,0x88,0x00,0x01, -0xac,0xe2,0x00,0x00,0x10,0x80,0x00,0x02,0x00,0x69,0x38,0x24,0xac,0xa0,0x00,0x00, -0x31,0x04,0x00,0xff,0x2c,0x82,0x00,0x27,0x14,0x40,0xff,0xf5,0x00,0x04,0x10,0x80, -0x97,0x83,0x8b,0xc6,0x97,0x85,0x8b,0xc4,0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x9c, -0x00,0xa2,0x28,0x21,0x3c,0x04,0xb0,0x06,0xa7,0x83,0x8b,0xc6,0x34,0x84,0x80,0x18, -0xa4,0xa3,0x00,0x00,0x8c,0x85,0x00,0x00,0x24,0x02,0x8f,0xff,0x24,0xc6,0x00,0x9c, -0x3c,0x03,0x0f,0x00,0x00,0xc2,0x30,0x24,0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00, -0xaf,0x86,0x8b,0xc0,0x10,0xa2,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x96, -0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x18,0x8f,0x86,0x8b,0xc0,0x27,0xbd,0xff,0xc8,0x24,0x02,0x00,0x08, -0x24,0x03,0x00,0x20,0xaf,0xbf,0x00,0x30,0xa3,0xa2,0x00,0x13,0xa3,0xa3,0x00,0x12, -0xa7,0xa4,0x00,0x10,0x00,0xc0,0x28,0x21,0x27,0xa9,0x00,0x10,0x00,0x00,0x38,0x21, -0x24,0x08,0x8f,0xff,0x00,0x07,0x10,0x80,0x00,0x49,0x10,0x21,0x8c,0x44,0x00,0x00, -0x24,0xe3,0x00,0x01,0x30,0x67,0x00,0xff,0x24,0xa2,0x00,0x04,0x2c,0xe3,0x00,0x08, -0xac,0xa4,0x00,0x00,0x14,0x60,0xff,0xf7,0x00,0x48,0x28,0x24,0x97,0x83,0x8b,0xc6, -0x97,0x85,0x8b,0xc4,0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x20,0x00,0xa2,0x28,0x21, -0x3c,0x04,0xb0,0x06,0xa7,0x83,0x8b,0xc6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00, -0x8c,0x85,0x00,0x00,0x24,0x02,0x8f,0xff,0x24,0xc6,0x00,0x20,0x3c,0x03,0x0f,0x00, -0x00,0xc2,0x30,0x24,0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00,0xaf,0x86,0x8b,0xc0, -0x10,0xa2,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x96,0x00,0x00,0x00,0x00, -0x8f,0xbf,0x00,0x30,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38, -0x93,0x82,0x8b,0xd0,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x11,0x24,0x06,0x00,0x01, -0x8f,0x82,0x8b,0xc8,0x3c,0x05,0xb0,0x06,0x3c,0x04,0xb0,0x03,0x34,0xa5,0x80,0x18, -0x34,0x84,0x01,0x08,0x14,0x40,0x00,0x09,0x00,0x00,0x30,0x21,0x97,0x82,0x8b,0xc4, -0x8c,0x84,0x00,0x00,0x3c,0x03,0xb0,0x02,0x00,0x43,0x10,0x21,0xaf,0x84,0x8b,0xcc, -0xa7,0x80,0x8b,0xc6,0xac,0x40,0x00,0x00,0xac,0x40,0x00,0x04,0x8c,0xa2,0x00,0x00, -0x03,0xe0,0x00,0x08,0x00,0xc0,0x10,0x21,0x8f,0x86,0x8b,0xc0,0x8f,0x82,0x8b,0xc8, -0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x00,0xc0,0x40,0x21,0x14,0x40,0x00,0x0a, -0x00,0x40,0x50,0x21,0x00,0x00,0x38,0x21,0x27,0x89,0x83,0x68,0x24,0xe2,0x00,0x01, -0x00,0x07,0x18,0x80,0x30,0x47,0x00,0xff,0x00,0x69,0x18,0x21,0x2c,0xe2,0x00,0x0a, -0x14,0x40,0xff,0xfa,0xac,0x60,0x00,0x00,0x3c,0x02,0x00,0x80,0x10,0x82,0x00,0x6f, -0x00,0x00,0x00,0x00,0x97,0x82,0x83,0x6e,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01, -0xa7,0x82,0x83,0x6e,0x90,0xa3,0x00,0x15,0x97,0x82,0x83,0x70,0x00,0x03,0x1e,0x00, -0x00,0x03,0x1e,0x03,0x00,0x43,0x10,0x21,0xa7,0x82,0x83,0x70,0x8c,0xa4,0x00,0x20, -0x3c,0x02,0x00,0x60,0x3c,0x03,0x00,0x20,0x00,0x82,0x20,0x24,0x10,0x83,0x00,0x54, -0x00,0x00,0x00,0x00,0x14,0x80,0x00,0x47,0x00,0x00,0x00,0x00,0x97,0x82,0x83,0x74, -0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x83,0x74,0x84,0xa3,0x00,0x06, -0x8f,0x82,0x83,0x84,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21,0xaf,0x82,0x83,0x84, -0x25,0x42,0x00,0x01,0x28,0x43,0x27,0x10,0xaf,0x82,0x8b,0xc8,0x10,0x60,0x00,0x09, -0x24,0x02,0x00,0x04,0x93,0x83,0x80,0x11,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x05, -0x24,0x02,0x00,0x04,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x18,0x24,0x03,0x00,0x28,0xa3,0x83,0x83,0x6a,0xa3,0x82,0x83,0x6b, -0x90,0xa2,0x00,0x18,0x93,0x83,0x83,0x93,0x00,0x00,0x38,0x21,0x00,0x02,0x16,0x00, -0x00,0x02,0x16,0x03,0xa7,0x82,0x83,0x7e,0xa3,0x83,0x83,0x8c,0x27,0x89,0x83,0x68, -0x24,0x05,0x8f,0xff,0x00,0x07,0x10,0x80,0x00,0x49,0x10,0x21,0x8c,0x44,0x00,0x00, -0x24,0xe3,0x00,0x01,0x30,0x67,0x00,0xff,0x25,0x02,0x00,0x04,0x2c,0xe3,0x00,0x0a, -0xad,0x04,0x00,0x00,0x14,0x60,0xff,0xf7,0x00,0x45,0x40,0x24,0x97,0x83,0x8b,0xc6, -0x97,0x85,0x8b,0xc4,0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x28,0x00,0xa2,0x28,0x21, -0x3c,0x04,0xb0,0x06,0xa7,0x83,0x8b,0xc6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00, -0x8c,0x85,0x00,0x00,0x24,0x02,0x8f,0xff,0x24,0xc6,0x00,0x28,0x3c,0x03,0x0f,0x00, -0x00,0xc2,0x30,0x24,0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00,0xaf,0x86,0x8b,0xc0, -0x10,0xa2,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x96,0x00,0x00,0x00,0x00, -0x0c,0x00,0x02,0x36,0x00,0x00,0x00,0x00,0xa3,0x80,0x80,0x11,0x08,0x00,0x02,0xe5, -0x00,0x00,0x00,0x00,0x97,0x82,0x83,0x76,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01, -0xa7,0x82,0x83,0x76,0x84,0xa3,0x00,0x06,0x8f,0x82,0x83,0x88,0x00,0x00,0x00,0x00, -0x00,0x43,0x10,0x21,0xaf,0x82,0x83,0x88,0x08,0x00,0x02,0xdd,0x25,0x42,0x00,0x01, -0x97,0x82,0x83,0x72,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x83,0x72, -0x84,0xa3,0x00,0x06,0x8f,0x82,0x83,0x80,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21, -0xaf,0x82,0x83,0x80,0x08,0x00,0x02,0xdd,0x25,0x42,0x00,0x01,0x97,0x82,0x83,0x6c, -0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x83,0x6c,0x08,0x00,0x02,0xc5, -0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xd0,0xaf,0xbf,0x00,0x28,0x8c,0xa3,0x00,0x20, -0x8f,0x8a,0x8b,0xc0,0x3c,0x02,0x00,0x10,0x00,0x62,0x10,0x24,0x00,0xa0,0x38,0x21, -0x01,0x40,0x48,0x21,0x10,0x40,0x00,0x3d,0x00,0x80,0x28,0x21,0x8c,0xe4,0x00,0x1c, -0x34,0xa5,0x12,0x06,0xaf,0xa5,0x00,0x10,0x8c,0x82,0x00,0x08,0x00,0x03,0x1c,0x42, -0x30,0x63,0x00,0x30,0x00,0x02,0x13,0x02,0x30,0x42,0x00,0x40,0x00,0x43,0x10,0x25, -0x90,0xe6,0x00,0x10,0x90,0xe4,0x00,0x13,0x94,0xe8,0x00,0x0c,0x94,0xe3,0x00,0x1a, -0x00,0x02,0x16,0x00,0x90,0xe7,0x00,0x12,0x00,0xa2,0x28,0x25,0x24,0x02,0x12,0x34, -0xa7,0xa2,0x00,0x1c,0x24,0x02,0x56,0x78,0xaf,0xa5,0x00,0x10,0xa3,0xa6,0x00,0x18, -0xa3,0xa7,0x00,0x1f,0xa7,0xa3,0x00,0x1a,0xa3,0xa4,0x00,0x19,0xa7,0xa8,0x00,0x20, -0xa7,0xa2,0x00,0x22,0x00,0x00,0x28,0x21,0x27,0xa7,0x00,0x10,0x24,0x06,0x8f,0xff, -0x00,0x05,0x10,0x80,0x00,0x47,0x10,0x21,0x8c,0x44,0x00,0x00,0x24,0xa3,0x00,0x01, -0x30,0x65,0x00,0xff,0x25,0x22,0x00,0x04,0x2c,0xa3,0x00,0x05,0xad,0x24,0x00,0x00, -0x14,0x60,0xff,0xf7,0x00,0x46,0x48,0x24,0x97,0x83,0x8b,0xc6,0x97,0x85,0x8b,0xc4, -0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x14,0x00,0xa2,0x28,0x21,0x3c,0x04,0xb0,0x06, -0xa7,0x83,0x8b,0xc6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00,0x8c,0x85,0x00,0x00, -0x24,0x02,0x8f,0xff,0x25,0x46,0x00,0x14,0x3c,0x03,0x0f,0x00,0x00,0xc2,0x50,0x24, -0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00,0xaf,0x8a,0x8b,0xc0,0x10,0xa2,0x00,0x03, -0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x96,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x28, -0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30,0x3c,0x05,0xb0,0x03, -0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xc8,0x00,0x04,0x22,0x00,0x34,0xa5,0x00,0x20, -0x24,0x42,0x0d,0xfc,0x3c,0x03,0xb0,0x00,0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20, -0xaf,0xb2,0x00,0x18,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x30,0x00,0x83,0x80,0x21, -0xaf,0xb7,0x00,0x2c,0xaf,0xb6,0x00,0x28,0xaf,0xb3,0x00,0x1c,0xaf,0xb1,0x00,0x14, -0xac,0xa2,0x00,0x00,0x8e,0x09,0x00,0x00,0x00,0x00,0x90,0x21,0x26,0x10,0x00,0x08, -0x00,0x09,0xa6,0x02,0x12,0x80,0x00,0x13,0x00,0x00,0xa8,0x21,0x24,0x13,0x00,0x02, -0x3c,0x16,0x00,0xff,0x3c,0x17,0xff,0x00,0x8e,0x09,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x09,0x12,0x02,0x24,0x42,0x00,0x02,0x31,0x25,0x00,0xff,0x10,0xb3,0x00,0x76, -0x30,0x51,0x00,0xff,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x18,0x00,0x00,0x00,0x00, -0x02,0x51,0x10,0x21,0x30,0x52,0xff,0xff,0x02,0x54,0x18,0x2b,0x14,0x60,0xff,0xf2, -0x02,0x11,0x80,0x21,0x12,0xa0,0x00,0x0a,0x3c,0x02,0xb0,0x06,0x34,0x42,0x80,0x18, -0x8c,0x43,0x00,0x00,0x3c,0x04,0x0f,0x00,0x3c,0x02,0x04,0x00,0x00,0x64,0x18,0x24, -0x10,0x62,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x96,0x00,0x00,0x00,0x00, -0x8f,0xbf,0x00,0x30,0x7b,0xb6,0x01,0x7c,0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc, -0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0x8e,0x09,0x00,0x04, -0x24,0x15,0x00,0x01,0x8e,0x06,0x00,0x0c,0x00,0x09,0x11,0x42,0x00,0x09,0x18,0xc2, -0x30,0x48,0x00,0x03,0x00,0x09,0x14,0x02,0x30,0x6c,0x00,0x03,0x00,0x09,0x26,0x02, -0x11,0x15,0x00,0x45,0x30,0x43,0x00,0x0f,0x29,0x02,0x00,0x02,0x14,0x40,0x00,0x26, -0x00,0x00,0x00,0x00,0x11,0x13,0x00,0x0f,0x00,0x00,0x38,0x21,0x00,0x07,0x22,0x02, -0x30,0x84,0xff,0x00,0x3c,0x03,0x00,0xff,0x00,0x07,0x2e,0x02,0x00,0x07,0x12,0x00, -0x00,0x43,0x10,0x24,0x00,0xa4,0x28,0x25,0x00,0xa2,0x28,0x25,0x00,0x07,0x1e,0x00, -0x00,0xa3,0x28,0x25,0x0c,0x00,0x01,0x92,0x01,0x20,0x20,0x21,0x08,0x00,0x03,0xa5, -0x02,0x51,0x10,0x21,0x11,0x95,0x00,0x0f,0x00,0x00,0x00,0x00,0x11,0x88,0x00,0x07, -0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x80,0x27,0x83,0x8b,0x70,0x00,0x43,0x10,0x21, -0x8c,0x47,0x00,0x18,0x08,0x00,0x03,0xcc,0x00,0x07,0x22,0x02,0x00,0x04,0x10,0x40, -0x27,0x83,0x8b,0x78,0x00,0x43,0x10,0x21,0x94,0x47,0x00,0x02,0x08,0x00,0x03,0xcc, -0x00,0x07,0x22,0x02,0x27,0x82,0x8b,0x70,0x00,0x82,0x10,0x21,0x90,0x47,0x00,0x00, -0x08,0x00,0x03,0xcc,0x00,0x07,0x22,0x02,0x15,0x00,0xff,0xdc,0x00,0x00,0x38,0x21, -0x10,0x75,0x00,0x05,0x00,0x80,0x38,0x21,0x00,0x65,0x18,0x26,0x24,0x82,0x01,0x00, -0x00,0x00,0x38,0x21,0x00,0x43,0x38,0x0a,0x24,0x02,0x00,0x01,0x11,0x82,0x00,0x0e, -0x3c,0x02,0xb0,0x03,0x24,0x02,0x00,0x02,0x11,0x82,0x00,0x06,0x00,0x00,0x00,0x00, -0x3c,0x02,0xb0,0x03,0x00,0xe2,0x10,0x21,0x8c,0x47,0x00,0x00,0x08,0x00,0x03,0xcc, -0x00,0x07,0x22,0x02,0x3c,0x02,0xb0,0x03,0x00,0xe2,0x10,0x21,0x94,0x43,0x00,0x00, -0x08,0x00,0x03,0xcb,0x30,0x67,0xff,0xff,0x00,0xe2,0x10,0x21,0x90,0x43,0x00,0x00, -0x08,0x00,0x03,0xcb,0x30,0x67,0x00,0xff,0x30,0x62,0x00,0x03,0x00,0x02,0x12,0x00, -0x11,0x95,0x00,0x07,0x00,0x44,0x38,0x21,0x11,0x93,0x00,0x03,0x00,0x00,0x00,0x00, -0x08,0x00,0x03,0xfd,0x3c,0x02,0xb0,0x0a,0x08,0x00,0x04,0x02,0x3c,0x02,0xb0,0x0a, -0x08,0x00,0x04,0x06,0x3c,0x02,0xb0,0x0a,0x8e,0x09,0x00,0x04,0x8e,0x02,0x00,0x08, -0x8e,0x03,0x00,0x0c,0x00,0x09,0x41,0x42,0x00,0x02,0x22,0x02,0x00,0x03,0x3a,0x02, -0x30,0x84,0xff,0x00,0x30,0xe7,0xff,0x00,0x00,0x02,0x5e,0x02,0x00,0x02,0x32,0x00, -0x00,0x03,0x56,0x02,0x00,0x03,0x2a,0x00,0x01,0x64,0x58,0x25,0x00,0xd6,0x30,0x24, -0x01,0x47,0x50,0x25,0x00,0x02,0x16,0x00,0x00,0xb6,0x28,0x24,0x00,0x03,0x1e,0x00, -0x01,0x66,0x58,0x25,0x01,0x45,0x50,0x25,0x00,0x57,0x10,0x24,0x00,0x77,0x18,0x24, -0x01,0x62,0x38,0x25,0x01,0x43,0x30,0x25,0x00,0x09,0x10,0xc2,0x00,0x09,0x1c,0x02, -0x31,0x08,0x00,0x03,0x30,0x4c,0x00,0x03,0x30,0x63,0x00,0x0f,0x00,0x09,0x26,0x02, -0x00,0xe0,0x58,0x21,0x15,0x00,0x00,0x28,0x00,0xc0,0x50,0x21,0x24,0x02,0x00,0x01, -0x10,0x62,0x00,0x06,0x00,0x80,0x28,0x21,0x24,0x02,0x00,0x03,0x14,0x62,0xff,0x69, -0x02,0x51,0x10,0x21,0x24,0x85,0x01,0x00,0x24,0x02,0x00,0x01,0x11,0x82,0x00,0x15, -0x24,0x02,0x00,0x02,0x11,0x82,0x00,0x0a,0x3c,0x03,0xb0,0x03,0x00,0xa3,0x18,0x21, -0x8c,0x62,0x00,0x00,0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24,0x00,0x44,0x10,0x24, -0x00,0x45,0x10,0x25,0xac,0x62,0x00,0x00,0x08,0x00,0x03,0xa5,0x02,0x51,0x10,0x21, -0x00,0xa3,0x18,0x21,0x94,0x62,0x00,0x00,0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24, -0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25,0xa4,0x62,0x00,0x00,0x08,0x00,0x03,0xa5, -0x02,0x51,0x10,0x21,0x3c,0x03,0xb0,0x03,0x00,0xa3,0x18,0x21,0x90,0x62,0x00,0x00, -0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24,0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25, -0x08,0x00,0x03,0xa4,0xa0,0x62,0x00,0x00,0x24,0x02,0x00,0x01,0x11,0x02,0x00,0x21, -0x00,0x00,0x00,0x00,0x15,0x13,0xff,0x42,0x00,0x00,0x00,0x00,0x11,0x82,0x00,0x17, -0x00,0x00,0x00,0x00,0x11,0x88,0x00,0x0b,0x00,0x00,0x00,0x00,0x27,0x83,0x8b,0x70, -0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x18,0x00,0x06,0x18,0x27, -0x00,0xe6,0x28,0x24,0x00,0x43,0x10,0x24,0x00,0x45,0x10,0x25,0x08,0x00,0x03,0xa4, -0xac,0x82,0x00,0x18,0x27,0x83,0x8b,0x78,0x00,0x04,0x20,0x40,0x00,0x83,0x20,0x21, -0x94,0x82,0x00,0x02,0x00,0x06,0x18,0x27,0x00,0xe6,0x28,0x24,0x00,0x43,0x10,0x24, -0x00,0x45,0x10,0x25,0x08,0x00,0x03,0xa4,0xa4,0x82,0x00,0x02,0x27,0x83,0x8b,0x70, -0x00,0x83,0x18,0x21,0x90,0x62,0x00,0x00,0x00,0x06,0x20,0x27,0x08,0x00,0x04,0x5a, -0x00,0xe6,0x28,0x24,0x30,0x62,0x00,0x07,0x00,0x02,0x12,0x00,0x11,0x88,0x00,0x0f, -0x00,0x44,0x10,0x21,0x11,0x93,0x00,0x07,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a, -0x00,0x43,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x06,0x20,0x27,0x08,0x00,0x04,0x47, -0x00,0xe6,0x28,0x24,0x3c,0x03,0xb0,0x0a,0x00,0x43,0x18,0x21,0x94,0x62,0x00,0x00, -0x00,0x06,0x20,0x27,0x08,0x00,0x04,0x50,0x00,0xe6,0x28,0x24,0x3c,0x03,0xb0,0x0a, -0x08,0x00,0x04,0x7d,0x00,0x43,0x18,0x21,0x97,0x85,0x8b,0xc4,0x3c,0x07,0xb0,0x02, -0x3c,0x04,0xb0,0x03,0x3c,0x02,0x80,0x00,0x00,0xa7,0x28,0x21,0x34,0x84,0x00,0x20, -0x24,0x42,0x12,0x58,0x24,0x03,0xff,0x80,0xac,0x82,0x00,0x00,0xa0,0xa3,0x00,0x07, -0x97,0x82,0x8b,0xc6,0x97,0x85,0x8b,0xc4,0x3c,0x06,0xb0,0x06,0x30,0x42,0xff,0xf8, -0x24,0x42,0x00,0x10,0x00,0xa2,0x10,0x21,0x30,0x42,0x0f,0xff,0x24,0x44,0x00,0x08, -0x30,0x84,0x0f,0xff,0x00,0x05,0x28,0xc2,0x3c,0x03,0x00,0x40,0x00,0xa3,0x28,0x25, -0x00,0x87,0x20,0x21,0x34,0xc6,0x80,0x18,0xac,0xc5,0x00,0x00,0xaf,0x84,0x8b,0xc0, -0xa7,0x82,0x8b,0xc4,0xa7,0x80,0x8b,0xc6,0xaf,0x80,0x8b,0xc8,0x03,0xe0,0x00,0x08, -0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff,0x30,0x84,0x00,0xff,0x24,0x02,0x00,0x01, -0x00,0xe0,0x48,0x21,0x30,0xc6,0x00,0xff,0x8f,0xa7,0x00,0x10,0x10,0x82,0x00,0x07, -0x00,0xa0,0x40,0x21,0x24,0x02,0x00,0x03,0x10,0x82,0x00,0x03,0x00,0x00,0x00,0x00, -0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x24,0xa8,0x01,0x00,0x3c,0x03,0xb0,0x03, -0x24,0x02,0x00,0x01,0x00,0x07,0x20,0x27,0x01,0x27,0x28,0x24,0x10,0xc2,0x00,0x14, -0x01,0x03,0x18,0x21,0x24,0x02,0x00,0x02,0x10,0xc2,0x00,0x09,0x00,0x07,0x50,0x27, -0x3c,0x03,0xb0,0x03,0x01,0x03,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x4a,0x10,0x24,0x00,0x45,0x10,0x25,0x08,0x00,0x04,0xe1,0xac,0x62,0x00,0x00, -0x3c,0x03,0xb0,0x03,0x01,0x03,0x18,0x21,0x94,0x62,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x4a,0x10,0x24,0x00,0x45,0x10,0x25,0x03,0xe0,0x00,0x08,0xa4,0x62,0x00,0x00, -0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25, -0xa0,0x62,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0x84,0x00,0x07, -0x00,0x04,0x22,0x00,0x30,0xa5,0x00,0xff,0x00,0x85,0x28,0x21,0x3c,0x02,0xb0,0x0a, -0x00,0xa2,0x40,0x21,0x30,0xc6,0x00,0xff,0x24,0x02,0x00,0x01,0x8f,0xa4,0x00,0x10, -0x10,0xc2,0x00,0x14,0x24,0x02,0x00,0x02,0x00,0x04,0x50,0x27,0x10,0xc2,0x00,0x09, -0x00,0xe4,0x48,0x24,0x3c,0x03,0xb0,0x0a,0x00,0xa3,0x18,0x21,0x8c,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24,0x00,0x49,0x10,0x25,0x03,0xe0,0x00,0x08, -0xac,0x62,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x00,0xa3,0x18,0x21,0x94,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24,0x00,0x49,0x10,0x25,0x03,0xe0,0x00,0x08, -0xa4,0x62,0x00,0x00,0x91,0x02,0x00,0x00,0x00,0x04,0x18,0x27,0x00,0xe4,0x20,0x24, -0x00,0x43,0x10,0x24,0x00,0x44,0x10,0x25,0x03,0xe0,0x00,0x08,0xa1,0x02,0x00,0x00, -0x30,0xa9,0x00,0xff,0x27,0x83,0x8b,0x70,0x30,0x85,0x00,0xff,0x24,0x02,0x00,0x01, -0x00,0x07,0x50,0x27,0x00,0xc7,0x40,0x24,0x11,0x22,0x00,0x17,0x00,0xa3,0x18,0x21, -0x00,0x05,0x20,0x40,0x27,0x82,0x8b,0x70,0x00,0x05,0x28,0x80,0x27,0x83,0x8b,0x78, -0x00,0x83,0x50,0x21,0x00,0xa2,0x20,0x21,0x24,0x02,0x00,0x02,0x00,0x07,0x40,0x27, -0x11,0x22,0x00,0x07,0x00,0xc7,0x28,0x24,0x8c,0x82,0x00,0x18,0x00,0x00,0x00,0x00, -0x00,0x48,0x10,0x24,0x00,0x45,0x10,0x25,0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x18, -0x95,0x42,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x48,0x10,0x24,0x00,0x45,0x10,0x25, -0x03,0xe0,0x00,0x08,0xa5,0x42,0x00,0x02,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x4a,0x10,0x24,0x00,0x48,0x10,0x25,0x03,0xe0,0x00,0x08,0xa0,0x62,0x00,0x00, -0x00,0x04,0x32,0x02,0x30,0xc6,0xff,0x00,0x00,0x04,0x16,0x02,0x00,0x04,0x1a,0x00, -0x3c,0x05,0x00,0xff,0x00,0x65,0x18,0x24,0x00,0x46,0x10,0x25,0x00,0x43,0x10,0x25, -0x00,0x04,0x26,0x00,0x03,0xe0,0x00,0x08,0x00,0x44,0x10,0x25,0x3c,0x03,0xb0,0x03, -0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xe8,0x34,0x63,0x00,0x20,0x24,0x42,0x14,0xdc, -0x3c,0x04,0xb0,0x03,0xaf,0xbf,0x00,0x14,0xac,0x62,0x00,0x00,0xaf,0xb0,0x00,0x10, -0x34,0x84,0x00,0x2c,0x8c,0x83,0x00,0x00,0xa7,0x80,0xbc,0x00,0x00,0x03,0x12,0x02, -0x00,0x03,0x2d,0x02,0x30,0x42,0x0f,0xff,0xa3,0x83,0xbc,0x08,0xa7,0x85,0xbc,0x0c, -0xa7,0x82,0xbc,0x0a,0xa7,0x80,0xbc,0x02,0xa7,0x80,0xbc,0x04,0xa7,0x80,0xbc,0x06, -0x0c,0x00,0x06,0xd1,0x24,0x04,0x05,0x00,0x3c,0x05,0x08,0x00,0x00,0x45,0x28,0x25, -0x24,0x04,0x05,0x00,0x0c,0x00,0x06,0xbf,0x00,0x40,0x80,0x21,0x3c,0x02,0xf7,0xff, -0x34,0x42,0xff,0xff,0x02,0x02,0x80,0x24,0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xbf, -0x24,0x04,0x05,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0xb0,0x03,0x34,0x42,0x01,0x08, -0x34,0x63,0x01,0x18,0x8c,0x45,0x00,0x00,0x8c,0x64,0x00,0x00,0x3c,0x02,0x00,0x0f, -0x3c,0x03,0x00,0x4c,0x30,0x84,0x02,0x00,0x34,0x63,0x4b,0x40,0xaf,0x85,0xbc,0x10, -0x10,0x80,0x00,0x06,0x34,0x42,0x42,0x40,0xaf,0x83,0xbc,0x14,0x8f,0xbf,0x00,0x14, -0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0xaf,0x82,0xbc,0x14, -0x08,0x00,0x05,0x67,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, -0x27,0xbd,0xff,0xc8,0x34,0x63,0x00,0x20,0x24,0x42,0x15,0xb8,0x30,0x84,0x00,0xff, -0xaf,0xbf,0x00,0x30,0xaf,0xb7,0x00,0x2c,0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24, -0xaf,0xb4,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, -0xaf,0xb0,0x00,0x10,0xac,0x62,0x00,0x00,0x10,0x80,0x00,0x1c,0x24,0x02,0x00,0x02, -0x10,0x82,0x00,0x08,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x30,0x7b,0xb6,0x01,0x7c, -0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x38,0xa7,0x80,0xbc,0x00,0xa7,0x80,0xbc,0x02,0xa7,0x80,0xbc,0x04, -0xa7,0x80,0xbc,0x06,0x0c,0x00,0x06,0xd1,0x24,0x04,0x05,0x00,0x3c,0x05,0x08,0x00, -0x00,0x45,0x28,0x25,0x24,0x04,0x05,0x00,0x0c,0x00,0x06,0xbf,0x00,0x40,0x80,0x21, -0x3c,0x05,0xf7,0xff,0x34,0xa5,0xff,0xff,0x02,0x05,0x28,0x24,0x0c,0x00,0x06,0xbf, -0x24,0x04,0x05,0x00,0x08,0x00,0x05,0x82,0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xd1, -0x24,0x04,0x05,0xa0,0x24,0x04,0x05,0xa4,0x0c,0x00,0x06,0xd1,0x00,0x02,0xbc,0x02, -0x24,0x04,0x05,0xa8,0x00,0x02,0xb4,0x02,0x0c,0x00,0x06,0xd1,0x30,0x55,0xff,0xff, -0x00,0x40,0x80,0x21,0x97,0x84,0xbc,0x00,0x97,0x82,0xbc,0x02,0x97,0x83,0xbc,0x06, -0x02,0xe4,0x20,0x23,0x02,0xa2,0x10,0x23,0x00,0x82,0x20,0x21,0x97,0x82,0xbc,0x04, -0x32,0x14,0xff,0xff,0x02,0x83,0x18,0x23,0x02,0xc2,0x10,0x23,0x00,0x82,0x20,0x21, -0x93,0x82,0xbc,0x08,0x00,0x83,0x20,0x21,0x30,0x84,0xff,0xff,0x00,0x82,0x10,0x2b, -0x14,0x40,0x00,0xaa,0x00,0x00,0x00,0x00,0x97,0x82,0xbc,0x0c,0x00,0x00,0x00,0x00, -0x00,0x44,0x10,0x2b,0x14,0x40,0x00,0x7f,0x00,0x00,0x00,0x00,0x97,0x82,0xbc,0x0a, -0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x2b,0x10,0x40,0x00,0x3a,0x00,0x00,0x00,0x00, -0x0c,0x00,0x06,0xd1,0x24,0x04,0x04,0x50,0x30,0x51,0x00,0x7f,0x00,0x40,0x80,0x21, -0x2e,0x22,0x00,0x32,0x10,0x40,0x00,0x13,0x24,0x02,0x00,0x20,0x12,0x22,0x00,0x17, -0x24,0x02,0xff,0x80,0x02,0x02,0x10,0x24,0x26,0x31,0x00,0x01,0x00,0x51,0x80,0x25, -0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xbf,0x24,0x04,0x04,0x50,0x02,0x00,0x28,0x21, -0x0c,0x00,0x06,0xbf,0x24,0x04,0x04,0x58,0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xbf, -0x24,0x04,0x04,0x60,0x02,0x00,0x28,0x21,0x24,0x04,0x04,0x68,0x0c,0x00,0x06,0xbf, -0x00,0x00,0x00,0x00,0xa7,0x97,0xbc,0x00,0xa7,0x95,0xbc,0x02,0xa7,0x96,0xbc,0x04, -0xa7,0x94,0xbc,0x06,0x08,0x00,0x05,0x82,0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xd1, -0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0,0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24, -0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x03,0x10,0x43,0x00,0x07,0x00,0x00,0x00,0x00, -0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25, -0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x08,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x2c, -0x00,0x40,0x90,0x21,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24, -0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x2c,0x08,0x00,0x05,0xc9, -0x24,0x02,0xff,0x80,0x0c,0x00,0x06,0xd1,0x24,0x04,0x04,0x50,0x30,0x51,0x00,0x7f, -0x24,0x02,0x00,0x20,0x16,0x22,0xff,0xdb,0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xd1, -0x24,0x04,0x02,0x2c,0x34,0x52,0x40,0x00,0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xbf, -0x24,0x04,0x02,0x2c,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x58,0x24,0x04,0x02,0x5c, -0x0c,0x00,0x06,0xd1,0x00,0x02,0x9e,0x02,0x30,0x43,0x00,0xff,0x00,0x13,0x12,0x00, -0x00,0x43,0x10,0x25,0x2c,0x43,0x00,0x04,0x14,0x60,0x00,0x1d,0x2c,0x42,0x00,0x11, -0x10,0x40,0x00,0x0b,0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff, -0x02,0x42,0x90,0x24,0x02,0x40,0x28,0x21,0x24,0x04,0x02,0x2c,0x0c,0x00,0x06,0xbf, -0x36,0x52,0x80,0x00,0x02,0x40,0x28,0x21,0x08,0x00,0x05,0xd7,0x24,0x04,0x02,0x2c, -0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0,0x00,0x40,0x28,0x21, -0x00,0x44,0x10,0x24,0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x02,0x14,0x43,0xff,0xee, -0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25, -0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x08,0x08,0x00,0x06,0x13,0x3c,0x02,0xff,0xff, -0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x08,0x00,0x40,0x28,0x21,0x00,0x02,0x15,0x82, -0x30,0x42,0x00,0x03,0x24,0x03,0x00,0x03,0x14,0x43,0xff,0xdf,0x3c,0x02,0xff,0x3f, -0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24,0x3c,0x03,0x00,0x80,0x08,0x00,0x06,0x28, -0x00,0x43,0x28,0x25,0x0c,0x00,0x06,0xd1,0x24,0x04,0x04,0x50,0x30,0x51,0x00,0x7f, -0x00,0x40,0x80,0x21,0x2e,0x22,0x00,0x32,0x10,0x40,0xff,0x9a,0x24,0x02,0x00,0x20, -0x12,0x22,0x00,0x04,0x24,0x02,0xff,0x80,0x02,0x02,0x10,0x24,0x08,0x00,0x05,0xcb, -0x26,0x31,0x00,0x02,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0, -0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24,0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x03, -0x10,0x43,0x00,0x07,0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff, -0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25,0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x08, -0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x2c,0x00,0x40,0x90,0x21,0x3c,0x02,0xff,0xff, -0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24,0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xbf, -0x24,0x04,0x02,0x2c,0x08,0x00,0x06,0x42,0x24,0x02,0xff,0x80,0x0c,0x00,0x06,0xd1, -0x24,0x04,0x04,0x50,0x00,0x40,0x80,0x21,0x30,0x51,0x00,0x7f,0x24,0x02,0x00,0x20, -0x12,0x22,0x00,0x1d,0x2e,0x22,0x00,0x21,0x14,0x40,0xff,0x72,0x24,0x02,0xff,0x80, -0x02,0x02,0x10,0x24,0x26,0x31,0xff,0xff,0x00,0x51,0x80,0x25,0x24,0x04,0x04,0x50, -0x0c,0x00,0x06,0xbf,0x02,0x00,0x28,0x21,0x24,0x04,0x04,0x58,0x0c,0x00,0x06,0xbf, -0x02,0x00,0x28,0x21,0x24,0x04,0x04,0x60,0x0c,0x00,0x06,0xbf,0x02,0x00,0x28,0x21, -0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xbf,0x24,0x04,0x04,0x68,0x24,0x02,0x00,0x20, -0x16,0x22,0xff,0x60,0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x2c, -0x00,0x40,0x90,0x21,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x02,0x42,0x10,0x24, -0x08,0x00,0x06,0x19,0x34,0x52,0x80,0x00,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x2c, -0x34,0x52,0x40,0x00,0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x2c, -0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x58,0x24,0x04,0x02,0x5c,0x0c,0x00,0x06,0xd1, -0x00,0x02,0x9e,0x02,0x30,0x43,0x00,0xff,0x00,0x13,0x12,0x00,0x00,0x43,0x10,0x25, -0x2c,0x43,0x00,0x04,0x14,0x60,0x00,0x20,0x2c,0x42,0x00,0x11,0x10,0x40,0x00,0x0d, -0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24, -0x02,0x40,0x28,0x21,0x24,0x04,0x02,0x2c,0x0c,0x00,0x06,0xbf,0x36,0x52,0x80,0x00, -0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x2c,0x08,0x00,0x06,0x66, -0x2e,0x22,0x00,0x21,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0, -0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24,0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x02, -0x14,0x43,0xff,0xec,0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff, -0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25,0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x08, -0x08,0x00,0x06,0x96,0x3c,0x02,0xff,0xff,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x08, -0x00,0x40,0x28,0x21,0x00,0x02,0x15,0x82,0x30,0x42,0x00,0x03,0x24,0x03,0x00,0x03, -0x14,0x43,0xff,0xdc,0x3c,0x03,0x00,0x80,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff, -0x00,0xa2,0x10,0x24,0x08,0x00,0x06,0xae,0x00,0x43,0x28,0x25,0x30,0x83,0x00,0x03, -0x00,0x04,0x20,0x40,0x00,0x83,0x20,0x23,0x3c,0x02,0xb0,0x0a,0x00,0x82,0x20,0x21, -0x3c,0x06,0x00,0x01,0xac,0x85,0x00,0x00,0x24,0x07,0x00,0x01,0x00,0x00,0x28,0x21, -0x34,0xc6,0x86,0x9f,0x8c,0x82,0x10,0x00,0x24,0xa5,0x00,0x01,0x10,0x47,0x00,0x03, -0x00,0xc5,0x18,0x2b,0x10,0x60,0xff,0xfb,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, -0x00,0x00,0x00,0x00,0x30,0x83,0x00,0x03,0x00,0x04,0x20,0x40,0x3c,0x02,0xb0,0x0a, -0x00,0x83,0x20,0x23,0x00,0x82,0x20,0x21,0x3c,0x06,0x00,0x01,0x24,0x02,0xff,0xff, -0xac,0x82,0x10,0x00,0x00,0x00,0x28,0x21,0x24,0x07,0x00,0x01,0x34,0xc6,0x86,0x9f, -0x8c,0x82,0x10,0x00,0x24,0xa5,0x00,0x01,0x10,0x47,0x00,0x03,0x00,0xc5,0x18,0x2b, -0x10,0x60,0xff,0xfb,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x00,0x03,0xe0,0x00,0x08, -0x00,0x00,0x00,0x00,0x3c,0x05,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x1b,0x94, -0x24,0x03,0x00,0x01,0x34,0xa5,0x00,0x20,0x3c,0x06,0xb0,0x03,0xac,0xa2,0x00,0x00, -0x34,0xc6,0x01,0x04,0xa0,0x83,0x00,0x48,0xa0,0x80,0x00,0x04,0xa0,0x80,0x00,0x05, -0xa0,0x80,0x00,0x06,0xa0,0x80,0x00,0x07,0xa0,0x80,0x00,0x08,0xa0,0x80,0x00,0x09, -0xa0,0x80,0x00,0x0a,0xa0,0x80,0x00,0x11,0xa0,0x80,0x00,0x13,0xa0,0x80,0x00,0x49, -0x94,0xc2,0x00,0x00,0xac,0x80,0x00,0x00,0xa0,0x80,0x00,0x4e,0x00,0x02,0x14,0x00, -0x00,0x02,0x14,0x03,0x30,0x43,0x00,0xff,0x30,0x42,0xff,0x00,0xa4,0x82,0x00,0x44, -0xa4,0x83,0x00,0x46,0xac,0x80,0x00,0x24,0xac,0x80,0x00,0x28,0xac,0x80,0x00,0x2c, -0xac,0x80,0x00,0x30,0xac,0x80,0x00,0x34,0xac,0x80,0x00,0x38,0xac,0x80,0x00,0x3c, -0x03,0xe0,0x00,0x08,0xac,0x80,0x00,0x40,0x84,0x83,0x00,0x0c,0x3c,0x07,0xb0,0x03, -0x34,0xe7,0x00,0x20,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, -0x27,0x83,0x90,0x04,0x00,0x43,0x10,0x21,0x8c,0x48,0x00,0x18,0x3c,0x02,0x80,0x00, -0x24,0x42,0x1c,0x28,0xac,0xe2,0x00,0x00,0x8d,0x03,0x00,0x08,0x80,0x82,0x00,0x13, -0x00,0x05,0x2c,0x00,0x00,0x03,0x1e,0x02,0x00,0x02,0x12,0x00,0x30,0x63,0x00,0x7e, -0x00,0x62,0x18,0x21,0x00,0x65,0x18,0x21,0x3c,0x02,0xc0,0x00,0x3c,0x05,0xb0,0x05, -0x34,0x42,0x04,0x00,0x24,0x63,0x00,0x01,0x3c,0x07,0xb0,0x05,0x3c,0x08,0xb0,0x05, -0x34,0xa5,0x04,0x20,0xac,0xa3,0x00,0x00,0x00,0xc2,0x30,0x21,0x34,0xe7,0x04,0x24, -0x35,0x08,0x02,0x28,0x24,0x02,0x00,0x01,0x24,0x03,0x00,0x20,0xac,0xe6,0x00,0x00, -0xac,0x82,0x00,0x3c,0x03,0xe0,0x00,0x08,0xa1,0x03,0x00,0x00,0x27,0xbd,0xff,0xa8, -0x00,0x07,0x60,0x80,0x27,0x82,0xb4,0x00,0xaf,0xbe,0x00,0x50,0xaf,0xb7,0x00,0x4c, -0xaf,0xb5,0x00,0x44,0xaf,0xb4,0x00,0x40,0xaf,0xbf,0x00,0x54,0xaf,0xb6,0x00,0x48, -0xaf,0xb3,0x00,0x3c,0xaf,0xb2,0x00,0x38,0xaf,0xb1,0x00,0x34,0xaf,0xb0,0x00,0x30, -0x01,0x82,0x10,0x21,0x8c,0x43,0x00,0x00,0x00,0xe0,0x70,0x21,0x3c,0x02,0x80,0x00, -0x94,0x73,0x00,0x14,0x3c,0x07,0xb0,0x03,0x34,0xe7,0x00,0x20,0x24,0x42,0x1c,0xbc, -0x3c,0x03,0xb0,0x05,0xac,0xe2,0x00,0x00,0x34,0x63,0x01,0x28,0x90,0x67,0x00,0x00, -0x00,0x13,0xa8,0xc0,0x02,0xb3,0x18,0x21,0x27,0x82,0x90,0x04,0x00,0x03,0x18,0x80, -0x00,0x62,0x18,0x21,0x00,0x05,0x2c,0x00,0x00,0x07,0x3e,0x00,0x28,0xc2,0x00,0x03, -0x00,0xc0,0xa0,0x21,0x00,0x80,0x78,0x21,0x00,0x05,0xbc,0x03,0x8c,0x68,0x00,0x18, -0x02,0xa0,0x58,0x21,0x10,0x40,0x01,0x81,0x00,0x07,0xf6,0x03,0x00,0xde,0x10,0x07, -0x30,0x5e,0x00,0x01,0x01,0x73,0x10,0x21,0x27,0x83,0x90,0x08,0x00,0x02,0x10,0x80, -0x00,0x43,0x10,0x21,0x80,0x4d,0x00,0x06,0x8d,0x03,0x00,0x00,0x8d,0x02,0x00,0x04, -0x8d,0x0a,0x00,0x08,0x8d,0x03,0x00,0x0c,0xaf,0xa2,0x00,0x20,0x11,0xa0,0x01,0x71, -0xaf,0xa3,0x00,0x18,0x27,0x82,0xb4,0x00,0x01,0x82,0x10,0x21,0x8c,0x44,0x00,0x00, -0x00,0x00,0x00,0x00,0x90,0x83,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x04, -0x14,0x60,0x00,0x12,0x00,0x00,0xb0,0x21,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x46, -0x90,0x43,0x00,0x00,0x2a,0x84,0x00,0x04,0x10,0x80,0x01,0x56,0x30,0x65,0x00,0x01, -0x91,0xe2,0x00,0x09,0x00,0x00,0x00,0x00,0x12,0x82,0x00,0x02,0x00,0x00,0x00,0x00, -0x00,0x00,0x28,0x21,0x14,0xa0,0x00,0x03,0x00,0x00,0x38,0x21,0x13,0xc0,0x00,0x03, -0x38,0xf6,0x00,0x01,0x24,0x07,0x00,0x01,0x38,0xf6,0x00,0x01,0x01,0x73,0x10,0x21, -0x00,0x02,0x30,0x80,0x27,0x83,0x90,0x10,0x00,0xc3,0x48,0x21,0x91,0x25,0x00,0x00, -0x8f,0xa4,0x00,0x20,0x2c,0xa3,0x00,0x04,0x00,0x04,0x11,0xc3,0x30,0x42,0x00,0x01, -0x00,0x03,0xb0,0x0b,0x12,0xc0,0x00,0xd8,0xaf,0xa2,0x00,0x24,0x93,0x90,0xbb,0xea, -0x00,0x0a,0x16,0x42,0x30,0x52,0x00,0x3f,0x2e,0x06,0x00,0x0c,0x10,0xc0,0x00,0xc0, -0x00,0xa0,0x20,0x21,0x2c,0xa2,0x00,0x10,0x14,0x40,0x00,0x04,0x00,0x90,0x10,0x2b, -0x30,0xa2,0x00,0x07,0x24,0x44,0x00,0x04,0x00,0x90,0x10,0x2b,0x10,0x40,0x00,0x0b, -0x01,0x73,0x10,0x21,0x27,0x85,0xbb,0x1c,0x00,0x10,0x10,0x40,0x00,0x50,0x10,0x21, -0x00,0x45,0x10,0x21,0x90,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x18,0x2b, -0x14,0x60,0xff,0xfa,0x00,0x10,0x10,0x40,0x01,0x73,0x10,0x21,0x00,0x02,0x10,0x80, -0x27,0x83,0x90,0x08,0x00,0x43,0x10,0x21,0x31,0xa4,0x00,0x01,0x10,0x80,0x00,0xa5, -0xa0,0x50,0x00,0x07,0x3c,0x04,0xb0,0x05,0x34,0x84,0x00,0x08,0x24,0x02,0x00,0x01, -0x3c,0x03,0x80,0x00,0xa1,0xe2,0x00,0x4e,0xac,0x83,0x00,0x00,0x8c,0x85,0x00,0x00, -0x3c,0x02,0x00,0xf0,0x3c,0x03,0x40,0xf0,0x34,0x42,0xf0,0x00,0x34,0x63,0xf0,0x00, -0x24,0x17,0x00,0x0e,0x24,0x13,0x01,0x06,0xac,0x82,0x00,0x00,0xac,0x83,0x00,0x00, -0x27,0x82,0xb4,0x00,0x01,0x82,0x10,0x21,0x8c,0x43,0x00,0x00,0x24,0x05,0x00,0x01, -0xaf,0xa5,0x00,0x1c,0x90,0x62,0x00,0x16,0x00,0x13,0xa8,0xc0,0x32,0x51,0x00,0x02, -0x34,0x42,0x00,0x04,0xa0,0x62,0x00,0x16,0x8f,0xa3,0x00,0x20,0x8f,0xa4,0x00,0x18, -0x00,0x03,0x13,0x43,0x00,0x04,0x1a,0x02,0x30,0x47,0x00,0x01,0x12,0x20,0x00,0x04, -0x30,0x64,0x07,0xff,0x2e,0x03,0x00,0x04,0x32,0x42,0x00,0x33,0x00,0x43,0x90,0x0b, -0x8f,0xa5,0x00,0x24,0x8f,0xa6,0x00,0x1c,0x00,0x12,0x10,0x40,0x00,0x05,0x19,0xc0, -0x00,0x47,0x10,0x21,0x00,0x06,0x2a,0x80,0x00,0x43,0x10,0x21,0x00,0x10,0x32,0x00, -0x00,0x04,0x24,0x80,0x02,0x65,0x28,0x21,0x00,0xa4,0x28,0x21,0x00,0x46,0x10,0x21, -0x00,0x17,0x1c,0x00,0x3c,0x04,0xc0,0x00,0x00,0x43,0x30,0x21,0x16,0x80,0x00,0x29, -0x00,0xa4,0x28,0x21,0x3c,0x02,0xb0,0x05,0x34,0x42,0x04,0x00,0x3c,0x03,0xb0,0x05, -0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x04,0x34,0x84,0x02,0x28, -0x24,0x02,0x00,0x01,0xac,0x65,0x00,0x00,0xa0,0x82,0x00,0x00,0x3c,0x02,0xb0,0x09, -0x34,0x42,0x01,0x46,0x90,0x44,0x00,0x00,0x91,0xe3,0x00,0x09,0x30,0x86,0x00,0x01, -0x02,0x83,0x18,0x26,0x00,0x03,0x30,0x0b,0x14,0xc0,0x00,0x03,0x00,0x00,0x28,0x21, -0x13,0xc0,0x00,0x03,0x02,0xb3,0x10,0x21,0x24,0x05,0x00,0x01,0x02,0xb3,0x10,0x21, -0x27,0x83,0x90,0x08,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x84,0x48,0x00,0x04, -0x00,0xa0,0x30,0x21,0x00,0xe0,0x20,0x21,0x02,0x80,0x28,0x21,0x02,0xc0,0x38,0x21, -0x0c,0x00,0x00,0x70,0xaf,0xa8,0x00,0x10,0x7b,0xbe,0x02,0xbc,0x7b,0xb6,0x02,0x7c, -0x7b,0xb4,0x02,0x3c,0x7b,0xb2,0x01,0xfc,0x7b,0xb0,0x01,0xbc,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x58,0x24,0x02,0x00,0x01,0x12,0x82,0x00,0x3d,0x3c,0x02,0xb0,0x05, -0x24,0x02,0x00,0x02,0x12,0x82,0x00,0x31,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x03, -0x12,0x82,0x00,0x25,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x10,0x12,0x82,0x00,0x19, -0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x11,0x12,0x82,0x00,0x0d,0x3c,0x02,0xb0,0x05, -0x24,0x02,0x00,0x12,0x16,0x82,0xff,0xd1,0x3c,0x02,0xb0,0x05,0x3c,0x03,0xb0,0x05, -0x34,0x42,0x04,0x20,0x3c,0x04,0xb0,0x05,0x34,0x63,0x04,0x24,0xac,0x46,0x00,0x00, -0x34,0x84,0x02,0x28,0xac,0x65,0x00,0x00,0x08,0x00,0x07,0xe6,0x24,0x02,0x00,0x20, -0x34,0x42,0x04,0x40,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00, -0x34,0x63,0x04,0x44,0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x40,0x08,0x00,0x07,0xe6, -0xac,0x65,0x00,0x00,0x34,0x42,0x04,0x28,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05, -0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x2c,0x34,0x84,0x02,0x28,0x24,0x02,0xff,0x80, -0x08,0x00,0x07,0xe6,0xac,0x65,0x00,0x00,0x34,0x42,0x04,0x18,0x3c,0x03,0xb0,0x05, -0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x1c,0x34,0x84,0x02,0x28, -0x24,0x02,0x00,0x08,0x08,0x00,0x07,0xe6,0xac,0x65,0x00,0x00,0x34,0x42,0x04,0x10, -0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x14, -0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x04,0x08,0x00,0x07,0xe6,0xac,0x65,0x00,0x00, -0x34,0x42,0x04,0x08,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00, -0x34,0x63,0x04,0x0c,0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x02,0x08,0x00,0x07,0xe6, -0xac,0x65,0x00,0x00,0x24,0x17,0x00,0x14,0x08,0x00,0x07,0xb8,0x24,0x13,0x01,0x02, -0x30,0xa2,0x00,0x07,0x24,0x44,0x00,0x0c,0x00,0x90,0x18,0x2b,0x10,0x60,0x00,0x0c, -0x26,0x02,0x00,0x04,0x27,0x85,0xbb,0x1c,0x00,0x10,0x10,0x40,0x00,0x50,0x10,0x21, -0x00,0x45,0x10,0x21,0x90,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x18,0x2b, -0x14,0x60,0xff,0xfa,0x00,0x10,0x10,0x40,0x2e,0x06,0x00,0x0c,0x26,0x02,0x00,0x04, -0x08,0x00,0x07,0xa2,0x00,0x46,0x80,0x0a,0x27,0x82,0xb4,0x00,0x01,0x82,0x20,0x21, -0x8c,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0xe2,0x00,0x19,0x00,0x00,0x00,0x00, -0x14,0x40,0x00,0x07,0x00,0x00,0x00,0x00,0x27,0x82,0x90,0x20,0x00,0xc2,0x10,0x21, -0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x14,0x00,0x00,0x00,0x00, -0x90,0xe3,0x00,0x16,0x27,0x82,0x90,0x08,0x00,0xc2,0x10,0x21,0x34,0x63,0x00,0x20, -0x90,0x50,0x00,0x07,0xa0,0xe3,0x00,0x16,0x8c,0x84,0x00,0x00,0x00,0x0a,0x1e,0x42, -0x24,0x06,0x00,0x01,0x90,0x82,0x00,0x16,0x30,0x71,0x00,0x02,0x30,0x72,0x00,0x3f, -0x30,0x42,0x00,0xfb,0x24,0x17,0x00,0x18,0x24,0x13,0x01,0x03,0x24,0x15,0x08,0x18, -0xaf,0xa6,0x00,0x1c,0x08,0x00,0x07,0xc2,0xa0,0x82,0x00,0x16,0x8d,0x02,0x00,0x04, -0x00,0x0a,0x1c,0x42,0x30,0x42,0x00,0x10,0x14,0x40,0x00,0x15,0x30,0x72,0x00,0x3f, -0x81,0x22,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x11,0x30,0x72,0x00,0x3e, -0x27,0x83,0x90,0x18,0x00,0xc3,0x18,0x21,0x80,0x64,0x00,0x00,0x27,0x83,0xb5,0x78, -0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23, -0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x05,0x90,0x43,0x00,0x04, -0x00,0x00,0x00,0x00,0x00,0x64,0x18,0x24,0x30,0x63,0x00,0x01,0x02,0x43,0x90,0x25, -0x27,0x85,0xb4,0x00,0x01,0x85,0x28,0x21,0x8c,0xa6,0x00,0x00,0x01,0x73,0x10,0x21, -0x27,0x83,0x90,0x10,0x90,0xc4,0x00,0x16,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, -0x30,0x84,0x00,0xdf,0x90,0x50,0x00,0x00,0xa0,0xc4,0x00,0x16,0x80,0xc6,0x00,0x12, -0x8c,0xa3,0x00,0x00,0x2d,0xc4,0x00,0x02,0xaf,0xa6,0x00,0x1c,0x90,0x62,0x00,0x16, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfb,0x14,0x80,0x00,0x06,0xa0,0x62,0x00,0x16, -0x24,0x02,0x00,0x06,0x11,0xc2,0x00,0x03,0x24,0x02,0x00,0x04,0x15,0xc2,0xff,0x0e, -0x32,0x51,0x00,0x02,0x32,0x51,0x00,0x02,0x2e,0x02,0x00,0x0c,0x14,0x40,0x00,0x0f, -0x00,0x11,0x18,0x2b,0x32,0x02,0x00,0x0f,0x34,0x42,0x00,0x10,0x00,0x03,0x19,0x00, -0x00,0x43,0x18,0x21,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xe0,0xa0,0x43,0x00,0x00, -0x00,0x00,0x20,0x21,0x02,0x00,0x28,0x21,0x0c,0x00,0x02,0x03,0xaf,0xaf,0x00,0x28, -0x8f,0xaf,0x00,0x28,0x08,0x00,0x07,0xc2,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0xbd, -0x32,0x03,0x00,0xff,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x42,0x90,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x0f,0x14,0x40,0xfe,0xaa,0x00,0x00,0x00,0x00, -0x91,0xe2,0x00,0x09,0x00,0x00,0x00,0x00,0x02,0x82,0x10,0x26,0x08,0x00,0x07,0x79, -0x00,0x02,0x28,0x0b,0x08,0x00,0x07,0x7f,0x00,0x00,0xb0,0x21,0x24,0x02,0x00,0x10, -0x10,0xc2,0x00,0x08,0x24,0x02,0x00,0x11,0x10,0xc2,0xfe,0x7d,0x00,0x07,0x17,0x83, -0x24,0x02,0x00,0x12,0x14,0xc2,0xfe,0x7b,0x00,0x07,0x17,0x43,0x08,0x00,0x07,0x59, -0x30,0x5e,0x00,0x01,0x08,0x00,0x07,0x59,0x00,0x07,0xf7,0xc2,0x00,0x04,0x10,0x40, -0x27,0x83,0x80,0x1c,0x00,0x43,0x10,0x21,0x00,0x80,0x40,0x21,0x94,0x44,0x00,0x00, -0x2d,0x07,0x00,0x04,0x24,0xc2,0x00,0x03,0x00,0x47,0x30,0x0a,0x00,0x86,0x00,0x18, -0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x23,0x8c, -0xac,0x62,0x00,0x00,0x2d,0x06,0x00,0x10,0x00,0x00,0x20,0x12,0x00,0x04,0x22,0x42, -0x24,0x84,0x00,0x01,0x24,0x83,0x00,0xc0,0x10,0xe0,0x00,0x0b,0x24,0x82,0x00,0x60, -0x00,0x40,0x20,0x21,0x00,0x65,0x20,0x0a,0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x00, -0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x00,0x44,0x20,0x04, -0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x24,0x85,0x00,0x28,0x24,0x83,0x00,0x24, -0x31,0x02,0x00,0x08,0x14,0xc0,0xff,0xf4,0x24,0x84,0x00,0x14,0x00,0x60,0x20,0x21, -0x08,0x00,0x08,0xfa,0x00,0xa2,0x20,0x0b,0x27,0xbd,0xff,0xe0,0x3c,0x03,0xb0,0x03, -0x3c,0x02,0x80,0x00,0xaf,0xb0,0x00,0x10,0x24,0x42,0x24,0x28,0x00,0x80,0x80,0x21, -0x34,0x63,0x00,0x20,0x3c,0x04,0xb0,0x03,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, -0xaf,0xbf,0x00,0x1c,0x83,0xb1,0x00,0x33,0x83,0xa8,0x00,0x37,0x34,0x84,0x01,0x10, -0xac,0x62,0x00,0x00,0x2e,0x02,0x00,0x10,0x00,0xe0,0x90,0x21,0x8c,0x87,0x00,0x00, -0x14,0x40,0x00,0x0c,0x2e,0x02,0x00,0x0c,0x3c,0x02,0x00,0x0f,0x34,0x42,0xf0,0x00, -0x00,0xe2,0x10,0x24,0x14,0x40,0x00,0x37,0x32,0x02,0x00,0x08,0x32,0x02,0x00,0x07, -0x27,0x83,0x80,0xcc,0x00,0x43,0x10,0x21,0x90,0x50,0x00,0x00,0x00,0x00,0x00,0x00, -0x2e,0x02,0x00,0x0c,0x14,0x40,0x00,0x03,0x02,0x00,0x20,0x21,0x32,0x02,0x00,0x0f, -0x24,0x44,0x00,0x0c,0x00,0x87,0x10,0x06,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x07, -0x2c,0x82,0x00,0x0c,0x00,0x04,0x10,0x80,0x27,0x83,0xb4,0x50,0x00,0x43,0x10,0x21, -0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x82,0x00,0x0c,0x14,0x40,0x00,0x05, -0x00,0x05,0x10,0x40,0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0x82,0x10,0x21, -0x24,0x44,0x00,0x04,0x15,0x00,0x00,0x02,0x24,0x06,0x00,0x20,0x24,0x06,0x00,0x0e, -0x0c,0x00,0x08,0xe3,0x00,0x00,0x00,0x00,0x00,0x40,0x30,0x21,0x3c,0x02,0xb0,0x03, -0x34,0x42,0x01,0x00,0x90,0x43,0x00,0x00,0x2e,0x04,0x00,0x04,0x24,0x02,0x00,0x10, -0x24,0x05,0x00,0x0a,0x00,0x44,0x28,0x0a,0x30,0x63,0x00,0x01,0x14,0x60,0x00,0x02, -0x00,0x05,0x10,0x40,0x00,0xa0,0x10,0x21,0x30,0x45,0x00,0xff,0x00,0xc5,0x10,0x21, -0x24,0x46,0x00,0x46,0x02,0x26,0x18,0x04,0xa6,0x43,0x00,0x00,0x8f,0xbf,0x00,0x1c, -0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x00,0xc0,0x10,0x21,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x20,0x10,0x40,0xff,0xcf,0x2e,0x02,0x00,0x0c,0x32,0x02,0x00,0x07, -0x27,0x83,0x80,0xc4,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x00,0x08,0x00,0x09,0x28, -0x02,0x04,0x80,0x23,0x27,0xbd,0xff,0xb8,0x00,0x05,0x38,0x80,0x27,0x82,0xb4,0x00, -0xaf,0xbe,0x00,0x40,0xaf,0xb6,0x00,0x38,0xaf,0xb3,0x00,0x2c,0xaf,0xbf,0x00,0x44, -0xaf,0xb7,0x00,0x3c,0xaf,0xb5,0x00,0x34,0xaf,0xb4,0x00,0x30,0xaf,0xb2,0x00,0x28, -0xaf,0xb1,0x00,0x24,0xaf,0xb0,0x00,0x20,0x00,0xe2,0x38,0x21,0x8c,0xe6,0x00,0x00, -0xaf,0xa5,0x00,0x4c,0x3c,0x02,0x80,0x00,0x3c,0x05,0xb0,0x03,0x34,0xa5,0x00,0x20, -0x24,0x42,0x25,0x84,0x24,0x03,0x00,0x01,0xac,0xa2,0x00,0x00,0xa0,0xc3,0x00,0x12, -0x8c,0xe5,0x00,0x00,0x94,0xc3,0x00,0x06,0x90,0xa2,0x00,0x16,0xa4,0xc3,0x00,0x14, -0x27,0x83,0x90,0x00,0x34,0x42,0x00,0x08,0xa0,0xa2,0x00,0x16,0x8c,0xe8,0x00,0x00, -0xaf,0xa4,0x00,0x48,0x27,0x82,0x90,0x04,0x95,0x11,0x00,0x14,0x00,0x00,0x00,0x00, -0x00,0x11,0x98,0xc0,0x02,0x71,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x82,0x10,0x21, -0x8c,0x52,0x00,0x18,0x00,0x83,0x18,0x21,0x84,0x75,0x00,0x06,0x8e,0x45,0x00,0x08, -0x8e,0x46,0x00,0x04,0x8e,0x47,0x00,0x04,0x00,0x05,0x1c,0x82,0x00,0x06,0x31,0x42, -0x27,0x82,0x90,0x10,0x30,0x63,0x00,0x01,0x30,0xc6,0x00,0x01,0x00,0x82,0x20,0x21, -0xa5,0x15,0x00,0x1a,0x00,0x05,0x14,0x42,0xaf,0xa3,0x00,0x18,0xaf,0xa6,0x00,0x1c, -0x30,0xe7,0x00,0x10,0x30,0x56,0x00,0x01,0x80,0x97,0x00,0x06,0x14,0xe0,0x00,0x47, -0x00,0x05,0xf7,0xc2,0x80,0x82,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x44, -0x02,0x71,0x10,0x21,0x93,0x90,0xbb,0xe9,0x00,0x00,0x00,0x00,0x2e,0x02,0x00,0x0c, -0x14,0x40,0x00,0x06,0x02,0x00,0x20,0x21,0x00,0x16,0x10,0x40,0x00,0x43,0x10,0x21, -0x00,0x02,0x11,0x00,0x02,0x02,0x10,0x21,0x24,0x44,0x00,0x04,0x02,0x71,0x10,0x21, -0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21,0x00,0x80,0x80,0x21, -0xa0,0x44,0x00,0x03,0xa0,0x44,0x00,0x00,0x02,0x00,0x20,0x21,0x02,0xc0,0x28,0x21, -0x0c,0x00,0x08,0xe3,0x02,0xa0,0x30,0x21,0x02,0x71,0x18,0x21,0x00,0x03,0x88,0x80, -0x00,0x40,0xa0,0x21,0x27,0x82,0x90,0x20,0x02,0x22,0x10,0x21,0x8c,0x44,0x00,0x00, -0x26,0xe3,0x00,0x02,0x00,0x03,0x17,0xc2,0x00,0x62,0x18,0x21,0x00,0x04,0x25,0xc2, -0x00,0x03,0x18,0x43,0x30,0x84,0x00,0x01,0x00,0x03,0x18,0x40,0x03,0xc4,0x20,0x24, -0x14,0x80,0x00,0x15,0x02,0x43,0x38,0x21,0x3c,0x08,0xb0,0x03,0x35,0x08,0x00,0x28, -0x8d,0x03,0x00,0x00,0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x48,0x27,0x82,0x90,0x08, -0x02,0x22,0x10,0x21,0x24,0x63,0x00,0x01,0x02,0xa0,0x28,0x21,0xa4,0x54,0x00,0x04, -0x00,0xc0,0x38,0x21,0x0c,0x00,0x07,0x2f,0xad,0x03,0x00,0x00,0x7b,0xbe,0x02,0x3c, -0x7b,0xb6,0x01,0xfc,0x7b,0xb4,0x01,0xbc,0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c, -0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x48,0x8f,0xa2,0x00,0x1c,0x8f,0xa6,0x00,0x18, -0x02,0x00,0x20,0x21,0x02,0xc0,0x28,0x21,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0x0a, -0xaf,0xa0,0x00,0x14,0x08,0x00,0x09,0xc6,0x02,0x82,0xa0,0x21,0x02,0x71,0x10,0x21, -0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21,0x90,0x50,0x00,0x00, -0x08,0x00,0x09,0xb2,0xa0,0x50,0x00,0x03,0x27,0xbd,0xff,0xb8,0xaf,0xb1,0x00,0x24, -0x8f,0xb1,0x00,0x5c,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, -0x24,0x42,0x27,0xa8,0xaf,0xbe,0x00,0x40,0xaf,0xb7,0x00,0x3c,0xaf,0xb6,0x00,0x38, -0xaf,0xb5,0x00,0x34,0xaf,0xb4,0x00,0x30,0xaf,0xa5,0x00,0x4c,0x8f,0xb5,0x00,0x58, -0xaf,0xbf,0x00,0x44,0xaf,0xb3,0x00,0x2c,0xaf,0xb2,0x00,0x28,0xaf,0xb0,0x00,0x20, -0x00,0xe0,0xb0,0x21,0xac,0x62,0x00,0x00,0x00,0x80,0xf0,0x21,0x00,0x00,0xb8,0x21, -0x16,0x20,0x00,0x2b,0x00,0x00,0xa0,0x21,0x27,0x85,0xb4,0x00,0x00,0x07,0x10,0x80, -0x00,0x45,0x10,0x21,0x8c,0x53,0x00,0x00,0x00,0x15,0x18,0x80,0x00,0x65,0x18,0x21, -0x92,0x62,0x00,0x16,0x8c,0x72,0x00,0x00,0x30,0x42,0x00,0x03,0x14,0x40,0x00,0x2d, -0x00,0x00,0x00,0x00,0x92,0x42,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x03, -0x14,0x40,0x00,0x28,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x34,0x00,0x00,0x00,0x00, -0x14,0x40,0x00,0x18,0x02,0x20,0x10,0x21,0x8c,0x82,0x00,0x38,0x00,0x00,0x00,0x00, -0x14,0x40,0x00,0x14,0x02,0x20,0x10,0x21,0x8c,0x82,0x00,0x3c,0x00,0x00,0x00,0x00, -0x14,0x40,0x00,0x0f,0x3c,0x03,0xb0,0x09,0x3c,0x05,0xb0,0x05,0x34,0x63,0x01,0x44, -0x34,0xa5,0x02,0x52,0x94,0x66,0x00,0x00,0x90,0xa2,0x00,0x00,0x8f,0xa3,0x00,0x4c, -0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x06,0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x04, -0x30,0xc6,0xff,0xff,0x2c,0xc2,0x00,0x41,0x10,0x40,0x00,0x09,0x24,0x05,0x00,0x14, -0x02,0x20,0x10,0x21,0x7b,0xbe,0x02,0x3c,0x7b,0xb6,0x01,0xfc,0x7b,0xb4,0x01,0xbc, -0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x48, -0x0c,0x00,0x07,0x0a,0x24,0x06,0x01,0x07,0x24,0x02,0x00,0x01,0x08,0x00,0x0a,0x2c, -0xa3,0xc2,0x00,0x11,0x10,0xc0,0x00,0x1c,0x24,0x02,0x00,0x01,0x10,0xc2,0x00,0x17, -0x00,0xc0,0x88,0x21,0x96,0x54,0x00,0x1a,0x02,0xa0,0xb8,0x21,0x12,0x20,0xff,0xed, -0x02,0x20,0x10,0x21,0x27,0x83,0xb4,0x00,0x00,0x17,0x10,0x80,0x00,0x43,0x10,0x21, -0x8c,0x44,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x28,0x80,0x86,0x00,0x12, -0x8c,0x62,0x00,0x00,0x00,0x14,0x2c,0x00,0x00,0x05,0x2c,0x03,0x00,0x46,0x10,0x21, -0x8f,0xa6,0x00,0x4c,0x02,0xe0,0x38,0x21,0x03,0xc0,0x20,0x21,0x0c,0x00,0x07,0x2f, -0xac,0x62,0x00,0x00,0x08,0x00,0x0a,0x2c,0xaf,0xd1,0x00,0x40,0x96,0x74,0x00,0x1a, -0x08,0x00,0x0a,0x3f,0x02,0xc0,0xb8,0x21,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08, -0x8c,0x50,0x00,0x00,0x02,0x60,0x20,0x21,0x0c,0x00,0x1e,0xf3,0x02,0x00,0x28,0x21, -0x30,0x42,0x00,0xff,0x02,0x00,0x28,0x21,0x02,0x40,0x20,0x21,0x0c,0x00,0x1e,0xf3, -0xaf,0xa2,0x00,0x18,0x8f,0xa4,0x00,0x18,0x00,0x00,0x00,0x00,0x10,0x80,0x00,0xed, -0x30,0x50,0x00,0xff,0x12,0x00,0x00,0x18,0x24,0x11,0x00,0x01,0x96,0x63,0x00,0x14, -0x96,0x44,0x00,0x14,0x27,0x85,0x90,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, -0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x00,0x04,0x18,0xc0,0x8c,0x46,0x00,0x08, -0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x65,0x18,0x21,0x00,0x06,0x17,0x02, -0x24,0x04,0x00,0xff,0x8c,0x63,0x00,0x08,0x10,0x44,0x00,0xd6,0x00,0x03,0x17,0x02, -0x10,0x44,0x00,0xd5,0x3c,0x02,0x80,0x00,0x00,0x66,0x18,0x2b,0x24,0x11,0x00,0x02, -0x24,0x02,0x00,0x01,0x00,0x43,0x88,0x0a,0x24,0x02,0x00,0x01,0x12,0x22,0x00,0x5a, -0x24,0x02,0x00,0x02,0x16,0x22,0xff,0xbd,0x00,0x00,0x00,0x00,0x96,0x49,0x00,0x14, -0x27,0x82,0x90,0x04,0x02,0xa0,0xb8,0x21,0x00,0x09,0x50,0xc0,0x01,0x49,0x18,0x21, -0x00,0x03,0x40,0x80,0x01,0x02,0x10,0x21,0x8c,0x43,0x00,0x18,0x00,0x00,0x00,0x00, -0x8c,0x65,0x00,0x08,0x8c,0x62,0x00,0x0c,0x8c,0x62,0x00,0x04,0x00,0x05,0x24,0x42, -0x00,0x05,0x1c,0x82,0x30,0x42,0x00,0x10,0x30,0x66,0x00,0x01,0x14,0x40,0x00,0x41, -0x30,0x87,0x00,0x01,0x27,0x82,0x90,0x18,0x01,0x02,0x10,0x21,0x80,0x44,0x00,0x00, -0x27,0x82,0xb5,0x78,0x00,0x04,0x19,0x00,0x00,0x64,0x18,0x23,0x00,0x03,0x18,0x80, -0x00,0x64,0x18,0x23,0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21,0x90,0x45,0x00,0x05, -0x27,0x84,0xb4,0xa0,0x00,0x64,0x18,0x21,0x90,0x63,0x00,0x00,0x10,0xa0,0x00,0x2b, -0x2c,0x64,0x00,0x0c,0x14,0x80,0x00,0x04,0x00,0x60,0x10,0x21,0x00,0x06,0x11,0x00, -0x00,0x62,0x10,0x21,0x24,0x42,0x00,0x24,0x3c,0x01,0xb0,0x03,0xa0,0x22,0x00,0xe1, -0x14,0x80,0x00,0x06,0x00,0x60,0x28,0x21,0x00,0x07,0x10,0x40,0x00,0x46,0x10,0x21, -0x00,0x02,0x11,0x00,0x00,0x62,0x10,0x21,0x24,0x45,0x00,0x04,0x01,0x49,0x10,0x21, -0x27,0x83,0x90,0x10,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0xa0,0x18,0x21, -0xa0,0x45,0x00,0x03,0xa0,0x45,0x00,0x00,0x24,0x02,0x00,0x08,0x12,0x02,0x00,0x0b, -0x24,0x02,0x00,0x01,0x00,0x60,0x28,0x21,0x02,0x40,0x20,0x21,0x0c,0x00,0x1f,0x6f, -0xaf,0xa2,0x00,0x10,0x30,0x54,0xff,0xff,0x92,0x42,0x00,0x16,0x00,0x00,0x00,0x00, -0x02,0x02,0x10,0x25,0x08,0x00,0x0a,0x3f,0xa2,0x42,0x00,0x16,0x00,0x60,0x28,0x21, -0x02,0x40,0x20,0x21,0x0c,0x00,0x1f,0x20,0xaf,0xa0,0x00,0x10,0x08,0x00,0x0a,0xc2, -0x30,0x54,0xff,0xff,0x08,0x00,0x0a,0xaa,0x00,0x60,0x10,0x21,0x14,0x80,0xff,0xfd, -0x00,0x00,0x00,0x00,0x00,0x06,0x11,0x00,0x00,0x62,0x10,0x21,0x08,0x00,0x0a,0xaa, -0x24,0x42,0x00,0x04,0x27,0x82,0x90,0x10,0x01,0x02,0x10,0x21,0x90,0x43,0x00,0x00, -0x08,0x00,0x0a,0xba,0xa0,0x43,0x00,0x03,0x96,0x69,0x00,0x14,0x02,0xc0,0xb8,0x21, -0x24,0x0b,0x00,0x01,0x00,0x09,0x10,0xc0,0x00,0x49,0x18,0x21,0x00,0x03,0x40,0x80, -0x00,0x40,0x50,0x21,0x27,0x82,0x90,0x04,0x01,0x02,0x10,0x21,0x8c,0x43,0x00,0x18, -0x00,0x00,0x00,0x00,0x8c,0x65,0x00,0x08,0x8c,0x62,0x00,0x0c,0x8c,0x62,0x00,0x04, -0x00,0x05,0x24,0x42,0x00,0x05,0x1c,0x82,0x30,0x42,0x00,0x10,0x30,0x66,0x00,0x01, -0x10,0x40,0x00,0x0d,0x30,0x87,0x00,0x01,0x27,0x82,0x90,0x18,0x01,0x02,0x10,0x21, -0x80,0x43,0x00,0x00,0x00,0x00,0x58,0x21,0x00,0x03,0x11,0x00,0x00,0x43,0x10,0x23, -0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x23,0x00,0x02,0x10,0x80,0x27,0x83,0xb5,0x70, -0x00,0x43,0x10,0x21,0xa0,0x40,0x00,0x04,0x11,0x60,0x00,0x4f,0x00,0x00,0x00,0x00, -0x01,0x49,0x10,0x21,0x00,0x02,0x20,0x80,0x27,0x85,0x90,0x10,0x00,0x85,0x10,0x21, -0x80,0x43,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x42,0x01,0x49,0x10,0x21, -0x27,0x82,0x90,0x18,0x00,0x82,0x10,0x21,0x80,0x44,0x00,0x00,0x27,0x82,0xb5,0x78, -0x00,0x04,0x19,0x00,0x00,0x64,0x18,0x23,0x00,0x03,0x18,0x80,0x00,0x64,0x18,0x23, -0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21,0x90,0x45,0x00,0x05,0x27,0x84,0xb4,0xa0, -0x00,0x64,0x18,0x21,0x90,0x63,0x00,0x00,0x10,0xa0,0x00,0x2c,0x2c,0x64,0x00,0x0c, -0x14,0x80,0x00,0x04,0x00,0x60,0x10,0x21,0x00,0x06,0x11,0x00,0x00,0x62,0x10,0x21, -0x24,0x42,0x00,0x24,0x3c,0x01,0xb0,0x03,0xa0,0x22,0x00,0xe1,0x14,0x80,0x00,0x06, -0x00,0x60,0x28,0x21,0x00,0x07,0x10,0x40,0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00, -0x00,0x62,0x10,0x21,0x24,0x45,0x00,0x04,0x01,0x49,0x10,0x21,0x27,0x83,0x90,0x10, -0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0xa0,0x18,0x21,0xa0,0x45,0x00,0x03, -0xa0,0x45,0x00,0x00,0x8f,0xa4,0x00,0x18,0x24,0x02,0x00,0x08,0x10,0x82,0x00,0x0c, -0x00,0x60,0x28,0x21,0x24,0x02,0x00,0x01,0x02,0x60,0x20,0x21,0x0c,0x00,0x1f,0x6f, -0xaf,0xa2,0x00,0x10,0x8f,0xa3,0x00,0x18,0x30,0x54,0xff,0xff,0x92,0x62,0x00,0x16, -0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x25,0x08,0x00,0x0a,0x3f,0xa2,0x62,0x00,0x16, -0x02,0x60,0x20,0x21,0x0c,0x00,0x1f,0x20,0xaf,0xa0,0x00,0x10,0x08,0x00,0x0b,0x31, -0x00,0x00,0x00,0x00,0x08,0x00,0x0b,0x19,0x00,0x60,0x10,0x21,0x14,0x80,0xff,0xfd, -0x00,0x00,0x00,0x00,0x00,0x06,0x11,0x00,0x00,0x62,0x10,0x21,0x08,0x00,0x0b,0x19, -0x24,0x42,0x00,0x04,0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x90,0x43,0x00,0x00, -0x08,0x00,0x0b,0x29,0xa0,0x43,0x00,0x03,0x27,0x85,0x90,0x10,0x08,0x00,0x0b,0x45, -0x01,0x49,0x10,0x21,0x3c,0x02,0x80,0x00,0x00,0x62,0x18,0x26,0x08,0x00,0x0a,0x7a, -0x00,0xc2,0x30,0x26,0x12,0x00,0xff,0x2d,0x24,0x02,0x00,0x01,0x08,0x00,0x0a,0x7f, -0x24,0x11,0x00,0x02,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd0, -0x24,0x42,0x2d,0x54,0x34,0x63,0x00,0x20,0x3c,0x05,0xb0,0x05,0xaf,0xb3,0x00,0x24, -0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c,0xaf,0xbf,0x00,0x28,0xaf,0xb0,0x00,0x18, -0xac,0x62,0x00,0x00,0x34,0xa5,0x02,0x42,0x90,0xa2,0x00,0x00,0x00,0x80,0x90,0x21, -0x24,0x11,0x00,0x10,0x30,0x53,0x00,0xff,0x24,0x02,0x00,0x10,0x12,0x22,0x00,0xcf, -0x00,0x00,0x18,0x21,0x24,0x02,0x00,0x11,0x12,0x22,0x00,0xc1,0x24,0x02,0x00,0x12, -0x12,0x22,0x00,0xb4,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0xad,0xae,0x43,0x00,0x40, -0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c,0x8c,0x44,0x00,0x00,0x3c,0x03,0x00,0x02, -0x34,0x63,0x00,0xff,0x00,0x83,0x80,0x24,0x00,0x10,0x14,0x43,0x10,0x40,0x00,0x05, -0x00,0x00,0x00,0x00,0x8e,0x42,0x00,0x34,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x92, -0x00,0x00,0x00,0x00,0x93,0x83,0x8b,0x71,0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x02, -0x10,0x40,0x00,0x04,0x32,0x10,0x00,0xff,0x00,0x10,0x11,0xc3,0x14,0x40,0x00,0x86, -0x00,0x00,0x00,0x00,0x16,0x00,0x00,0x15,0x02,0x00,0x10,0x21,0x26,0x22,0x00,0x01, -0x30,0x51,0x00,0xff,0x2e,0x23,0x00,0x13,0x14,0x60,0xff,0xdb,0x24,0x03,0x00,0x02, -0x12,0x63,0x00,0x73,0x24,0x02,0x00,0x05,0x2a,0x62,0x00,0x03,0x10,0x40,0x00,0x58, -0x24,0x02,0x00,0x04,0x24,0x02,0x00,0x01,0x12,0x62,0x00,0x4b,0x02,0x40,0x20,0x21, -0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x70,0x00,0xff,0x12,0x00,0x00,0x06,0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x28, -0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30, -0x92,0x46,0x00,0x04,0x8e,0x43,0x00,0x24,0x24,0x02,0x00,0x07,0x02,0x40,0x20,0x21, -0x00,0x00,0x28,0x21,0x24,0x07,0x00,0x06,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xea, -0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x24,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c, -0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff,0x16,0x00,0xff,0xec,0x02,0x00,0x10,0x21, -0x92,0x46,0x00,0x05,0x8e,0x43,0x00,0x28,0x24,0x02,0x00,0x05,0x02,0x40,0x20,0x21, -0x24,0x05,0x00,0x01,0x24,0x07,0x00,0x04,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xea, -0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x28,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c, -0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff,0x16,0x00,0xff,0xdc,0x02,0x00,0x10,0x21, -0x92,0x46,0x00,0x06,0x8e,0x43,0x00,0x2c,0x24,0x02,0x00,0x03,0x02,0x40,0x20,0x21, -0x24,0x05,0x00,0x02,0x00,0x00,0x38,0x21,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xea, -0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x2c,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c, -0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff,0x16,0x00,0xff,0xcc,0x02,0x00,0x10,0x21, -0x92,0x46,0x00,0x07,0x8e,0x43,0x00,0x30,0x24,0x02,0x00,0x02,0x02,0x40,0x20,0x21, -0x24,0x05,0x00,0x03,0x24,0x07,0x00,0x01,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xea, -0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x30,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c, -0x08,0x00,0x0b,0x9b,0x30,0x42,0x00,0xff,0x92,0x46,0x00,0x04,0x8e,0x43,0x00,0x24, -0x24,0x02,0x00,0x07,0x00,0x00,0x28,0x21,0x24,0x07,0x00,0x06,0xaf,0xa2,0x00,0x10, -0x0c,0x00,0x09,0xea,0xaf,0xa3,0x00,0x14,0x08,0x00,0x0b,0x94,0xae,0x42,0x00,0x24, -0x12,0x62,0x00,0x0d,0x24,0x02,0x00,0x03,0x24,0x02,0x00,0x08,0x16,0x62,0xff,0xa8, -0x02,0x40,0x20,0x21,0x92,0x46,0x00,0x07,0x8e,0x42,0x00,0x30,0x24,0x05,0x00,0x03, -0x24,0x07,0x00,0x01,0xaf,0xa3,0x00,0x10,0x0c,0x00,0x09,0xea,0xaf,0xa2,0x00,0x14, -0x08,0x00,0x0b,0x94,0xae,0x42,0x00,0x30,0x92,0x46,0x00,0x06,0x8e,0x43,0x00,0x2c, -0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x02,0x00,0x00,0x38,0x21,0xaf,0xa2,0x00,0x10, -0x0c,0x00,0x09,0xea,0xaf,0xa3,0x00,0x14,0x08,0x00,0x0b,0x94,0xae,0x42,0x00,0x2c, -0x92,0x46,0x00,0x05,0x8e,0x43,0x00,0x28,0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x01, -0x24,0x07,0x00,0x04,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xea,0xaf,0xa3,0x00,0x14, -0x08,0x00,0x0b,0x94,0xae,0x42,0x00,0x28,0x0c,0x00,0x01,0x57,0x24,0x04,0x00,0x01, -0x08,0x00,0x0b,0x85,0x00,0x00,0x00,0x00,0x8f,0x84,0xb4,0x40,0xae,0x40,0x00,0x34, -0x94,0x85,0x00,0x14,0x0c,0x00,0x1b,0x66,0x00,0x00,0x00,0x00,0x93,0x83,0x8b,0x71, -0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x02,0x10,0x40,0xff,0x69,0x00,0x00,0x00,0x00, -0x0c,0x00,0x01,0x57,0x00,0x00,0x20,0x21,0x08,0x00,0x0b,0x7d,0x00,0x00,0x00,0x00, -0x02,0x40,0x20,0x21,0x0c,0x00,0x09,0x61,0x02,0x20,0x28,0x21,0x08,0x00,0x0b,0x71, -0x3c,0x02,0xb0,0x05,0x8e,0x42,0x00,0x3c,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x4a, -0x00,0x00,0x00,0x00,0x8f,0x82,0xb4,0x48,0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a, -0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x2b,0x08,0x00,0x0b,0x6e,0xae,0x43,0x00,0x3c, -0x8e,0x42,0x00,0x38,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x3d,0x24,0x02,0x00,0x12, -0x8f,0x82,0xb4,0x44,0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a,0x00,0x00,0x00,0x00, -0x00,0x02,0x18,0x2b,0x08,0x00,0x0b,0x6e,0xae,0x43,0x00,0x38,0x8e,0x42,0x00,0x34, -0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x30,0x24,0x02,0x00,0x11,0x8f,0x82,0xb4,0x40, -0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x2b, -0x08,0x00,0x0b,0x6e,0xae,0x43,0x00,0x34,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, -0x27,0xbd,0xff,0xe0,0x34,0x63,0x00,0x20,0x24,0x42,0x31,0x08,0x3c,0x08,0xb0,0x03, -0xaf,0xb1,0x00,0x14,0xac,0x62,0x00,0x00,0x35,0x08,0x01,0x00,0xaf,0xbf,0x00,0x18, -0xaf,0xb0,0x00,0x10,0x91,0x03,0x00,0x00,0x00,0xa0,0x48,0x21,0x24,0x11,0x00,0x0a, -0x2c,0xa5,0x00,0x04,0x24,0x02,0x00,0x10,0x00,0x45,0x88,0x0a,0x30,0x63,0x00,0x01, -0x00,0xc0,0x28,0x21,0x14,0x60,0x00,0x02,0x00,0x11,0x40,0x40,0x02,0x20,0x40,0x21, -0x84,0x83,0x00,0x0c,0x31,0x11,0x00,0xff,0x01,0x20,0x20,0x21,0x00,0x03,0x10,0xc0, -0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x08,0x00,0x43,0x10,0x21, -0x84,0x43,0x00,0x04,0x24,0x06,0x00,0x0e,0x10,0xe0,0x00,0x06,0x02,0x23,0x80,0x21, -0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x20,0x0c,0x00,0x08,0xe3,0x00,0x00,0x00,0x00,0x02,0x11,0x18,0x21, -0x08,0x00,0x0c,0x64,0x00,0x62,0x80,0x21,0x27,0xbd,0xff,0xd0,0xaf,0xbf,0x00,0x28, -0xaf,0xb4,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18,0xaf,0xb5,0x00,0x24, -0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x84,0x82,0x00,0x0c,0x3c,0x06,0xb0,0x03, -0x34,0xc6,0x00,0x20,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80, -0x27,0x82,0x90,0x04,0x00,0x62,0x10,0x21,0x8c,0x55,0x00,0x18,0x3c,0x02,0x80,0x00, -0x24,0x42,0x31,0xb8,0xac,0xc2,0x00,0x00,0x8e,0xb0,0x00,0x08,0x27,0x82,0x90,0x08, -0x00,0x62,0x18,0x21,0x90,0x71,0x00,0x07,0x00,0x10,0x86,0x43,0x32,0x10,0x00,0x01, -0x00,0xa0,0x38,0x21,0x02,0x00,0x30,0x21,0x00,0xa0,0x98,0x21,0x02,0x20,0x28,0x21, -0x0c,0x00,0x0c,0x42,0x00,0x80,0x90,0x21,0x02,0x20,0x20,0x21,0x02,0x00,0x28,0x21, -0x24,0x06,0x00,0x14,0x0c,0x00,0x08,0xe3,0x00,0x40,0xa0,0x21,0x86,0x43,0x00,0x0c, -0x3c,0x09,0xb0,0x09,0x3c,0x08,0xb0,0x09,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, -0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21,0x80,0x43,0x00,0x06, -0x3c,0x07,0xb0,0x09,0x3c,0x05,0xb0,0x09,0x28,0x62,0x00,0x00,0x24,0x64,0x00,0x03, -0x00,0x82,0x18,0x0b,0x00,0x03,0x18,0x83,0x3c,0x02,0xb0,0x09,0x00,0x03,0x18,0x80, -0x34,0x42,0x01,0x02,0x35,0x29,0x01,0x10,0x35,0x08,0x01,0x14,0x34,0xe7,0x01,0x20, -0x34,0xa5,0x01,0x24,0xa4,0x54,0x00,0x00,0x12,0x60,0x00,0x11,0x02,0xa3,0xa8,0x21, -0x8e,0xa2,0x00,0x0c,0x8e,0xa3,0x00,0x08,0x00,0x02,0x14,0x00,0x00,0x03,0x1c,0x02, -0x00,0x43,0x10,0x21,0xad,0x22,0x00,0x00,0x8e,0xa3,0x00,0x0c,0x00,0x00,0x00,0x00, -0x00,0x03,0x1c,0x02,0xa5,0x03,0x00,0x00,0x8f,0xbf,0x00,0x28,0x7b,0xb4,0x01,0x3c, -0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30, -0x8e,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0xad,0x22,0x00,0x00,0x8e,0xa4,0x00,0x08, -0x00,0x00,0x00,0x00,0xa5,0x04,0x00,0x00,0x7a,0xa2,0x00,0x7c,0x00,0x00,0x00,0x00, -0x00,0x03,0x1c,0x00,0x00,0x02,0x14,0x02,0x00,0x62,0x18,0x21,0xac,0xe3,0x00,0x00, -0x8e,0xa2,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x02,0x08,0x00,0x0c,0xb6, -0xa4,0xa2,0x00,0x00,0x27,0xbd,0xff,0xe0,0xaf,0xb2,0x00,0x18,0xaf,0xb0,0x00,0x10, -0xaf,0xbf,0x00,0x1c,0xaf,0xb1,0x00,0x14,0x84,0x82,0x00,0x0c,0x00,0x80,0x90,0x21, -0x3c,0x05,0xb0,0x03,0x00,0x02,0x20,0xc0,0x00,0x82,0x20,0x21,0x00,0x04,0x20,0x80, -0x27,0x82,0x90,0x04,0x00,0x82,0x10,0x21,0x8c,0x51,0x00,0x18,0x3c,0x02,0x80,0x00, -0x34,0xa5,0x00,0x20,0x24,0x42,0x33,0x34,0x27,0x83,0x90,0x08,0xac,0xa2,0x00,0x00, -0x00,0x83,0x20,0x21,0x3c,0x02,0xb0,0x03,0x90,0x86,0x00,0x07,0x34,0x42,0x01,0x00, -0x8e,0x23,0x00,0x08,0x90,0x44,0x00,0x00,0x2c,0xc5,0x00,0x04,0x24,0x02,0x00,0x10, -0x24,0x10,0x00,0x0a,0x00,0x45,0x80,0x0a,0x00,0x03,0x1e,0x43,0x30,0x84,0x00,0x01, -0x30,0x65,0x00,0x01,0x14,0x80,0x00,0x02,0x00,0x10,0x10,0x40,0x02,0x00,0x10,0x21, -0x00,0xc0,0x20,0x21,0x24,0x06,0x00,0x20,0x0c,0x00,0x08,0xe3,0x30,0x50,0x00,0xff, -0x86,0x44,0x00,0x0c,0x27,0x85,0x90,0x10,0x3c,0x06,0xb0,0x09,0x00,0x04,0x18,0xc0, -0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x65,0x18,0x21,0x80,0x64,0x00,0x06, -0x00,0x50,0x10,0x21,0x34,0xc6,0x01,0x02,0x24,0x85,0x00,0x03,0x28,0x83,0x00,0x00, -0x00,0xa3,0x20,0x0b,0x00,0x04,0x20,0x83,0x00,0x04,0x20,0x80,0xa4,0xc2,0x00,0x00, -0x02,0x24,0x20,0x21,0x8c,0x83,0x00,0x04,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x10, -0xac,0x43,0x00,0x00,0x8c,0x86,0x00,0x08,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x14, -0xa4,0x46,0x00,0x00,0x8c,0x85,0x00,0x0c,0x8c,0x82,0x00,0x08,0x3c,0x06,0xb0,0x09, -0x00,0x05,0x2c,0x00,0x00,0x02,0x14,0x02,0x00,0xa2,0x28,0x21,0x34,0xc6,0x01,0x20, -0xac,0xc5,0x00,0x00,0x8c,0x83,0x00,0x0c,0x3c,0x05,0xb0,0x09,0x34,0xa5,0x01,0x24, -0x00,0x03,0x1c,0x02,0xa4,0xa3,0x00,0x00,0x92,0x42,0x00,0x0a,0x3c,0x03,0xb0,0x09, -0x34,0x63,0x01,0x30,0x00,0x02,0x13,0x00,0x24,0x42,0x00,0x04,0x30,0x42,0xff,0xff, -0xa4,0x62,0x00,0x00,0x86,0x44,0x00,0x0c,0x27,0x83,0x90,0x18,0x8f,0xbf,0x00,0x1c, -0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, -0x94,0x44,0x00,0x02,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x3c,0x05,0xb0,0x09, -0x34,0xa5,0x01,0x32,0xa4,0xa4,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, -0x27,0xbd,0xff,0xe0,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00,0xaf,0xb0,0x00,0x10, -0x34,0x42,0x00,0x20,0x00,0xa0,0x80,0x21,0x24,0x63,0x34,0xc0,0x00,0x05,0x2c,0x43, -0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x18,0xac,0x43,0x00,0x00,0x10,0xa0,0x00,0x05, -0x00,0x80,0x88,0x21,0x8c,0x82,0x00,0x34,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0xb6, -0x00,0x00,0x00,0x00,0x32,0x10,0x00,0xff,0x12,0x00,0x00,0x4c,0x00,0x00,0x10,0x21, -0x24,0x02,0x00,0x08,0x12,0x02,0x00,0xa3,0x2a,0x02,0x00,0x09,0x10,0x40,0x00,0x89, -0x24,0x02,0x00,0x40,0x24,0x04,0x00,0x02,0x12,0x04,0x00,0x79,0x2a,0x02,0x00,0x03, -0x10,0x40,0x00,0x69,0x24,0x02,0x00,0x04,0x24,0x02,0x00,0x01,0x12,0x02,0x00,0x5a, -0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05,0x34,0x42,0x00,0x08,0x3c,0x03,0x80,0x00, -0xa2,0x20,0x00,0x4e,0xac,0x43,0x00,0x00,0x82,0x24,0x00,0x11,0x92,0x27,0x00,0x11, -0x10,0x80,0x00,0x4e,0x00,0x00,0x00,0x00,0x92,0x26,0x00,0x0a,0x24,0x02,0x00,0x12, -0x10,0x46,0x00,0x09,0x30,0xc2,0x00,0xff,0x27,0x83,0xb4,0x00,0x00,0x02,0x10,0x80, -0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x83,0x00,0x14, -0x00,0x00,0x00,0x00,0xa6,0x23,0x00,0x0c,0x3c,0x02,0xb0,0x09,0x34,0x42,0x00,0x40, -0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x03,0xa2,0x23,0x00,0x10, -0x14,0x60,0x00,0x2b,0x30,0x65,0x00,0x01,0x30,0xc2,0x00,0xff,0x27,0x83,0xb4,0x00, -0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x82,0x23,0x00,0x12, -0x90,0x82,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x02,0x11,0x42,0x30,0x42,0x00,0x01, -0x00,0x62,0x18,0x21,0x00,0x03,0x26,0x00,0x14,0x80,0x00,0x18,0xa2,0x23,0x00,0x12, -0x00,0x07,0x16,0x00,0x14,0x40,0x00,0x11,0x24,0x02,0x00,0x01,0x96,0x23,0x00,0x0c, -0x27,0x84,0x90,0x10,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, -0x00,0x44,0x10,0x21,0x80,0x45,0x00,0x06,0x00,0x03,0x1a,0x00,0x3c,0x02,0xb0,0x00, -0x00,0x65,0x18,0x21,0x00,0x62,0x18,0x21,0x90,0x64,0x00,0x00,0x90,0x62,0x00,0x04, -0xa2,0x20,0x00,0x15,0xa3,0x80,0x8b,0xd4,0x24,0x02,0x00,0x01,0x8f,0xbf,0x00,0x18, -0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x0c,0x00,0x0c,0xcd, -0x02,0x20,0x20,0x21,0x92,0x27,0x00,0x11,0x08,0x00,0x0d,0x7d,0x00,0x07,0x16,0x00, -0x0c,0x00,0x0c,0x6e,0x02,0x20,0x20,0x21,0x86,0x23,0x00,0x0c,0x27,0x84,0x90,0x08, -0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x44,0x20,0x21, -0x90,0x85,0x00,0x07,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21,0xa2,0x25,0x00,0x13, -0x90,0x83,0x00,0x07,0x08,0x00,0x0d,0x95,0xa0,0x43,0x00,0x02,0x92,0x26,0x00,0x0a, -0x08,0x00,0x0d,0x5e,0x30,0xc2,0x00,0xff,0x8e,0x22,0x00,0x24,0x00,0x00,0x00,0x00, -0x10,0x50,0x00,0x07,0xa2,0x20,0x00,0x08,0x24,0x02,0x00,0x07,0xa2,0x22,0x00,0x0a, -0x92,0x22,0x00,0x27,0xae,0x20,0x00,0x24,0x08,0x00,0x0d,0x51,0xa2,0x22,0x00,0x04, -0x08,0x00,0x0d,0xaf,0x24,0x02,0x00,0x06,0x16,0x02,0xff,0x9b,0x3c,0x02,0xb0,0x05, -0x8e,0x23,0x00,0x2c,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x07,0xa2,0x24,0x00,0x08, -0x24,0x02,0x00,0x03,0xa2,0x22,0x00,0x0a,0x92,0x22,0x00,0x2f,0xae,0x20,0x00,0x2c, -0x08,0x00,0x0d,0x51,0xa2,0x22,0x00,0x06,0x08,0x00,0x0d,0xbe,0xa2,0x20,0x00,0x0a, -0x8e,0x22,0x00,0x28,0x24,0x03,0x00,0x01,0x24,0x04,0x00,0x01,0x10,0x44,0x00,0x07, -0xa2,0x23,0x00,0x08,0x24,0x02,0x00,0x05,0xa2,0x22,0x00,0x0a,0x92,0x22,0x00,0x2b, -0xae,0x20,0x00,0x28,0x08,0x00,0x0d,0x51,0xa2,0x22,0x00,0x05,0x08,0x00,0x0d,0xca, -0x24,0x02,0x00,0x04,0x12,0x02,0x00,0x12,0x2a,0x02,0x00,0x41,0x10,0x40,0x00,0x09, -0x24,0x02,0x00,0x80,0x24,0x02,0x00,0x20,0x16,0x02,0xff,0x7b,0x3c,0x02,0xb0,0x05, -0x24,0x02,0x00,0x12,0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08,0x08,0x00,0x0d,0x51, -0xae,0x20,0x00,0x3c,0x16,0x02,0xff,0x74,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x10, -0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08,0x08,0x00,0x0d,0x51,0xae,0x20,0x00,0x34, -0x24,0x02,0x00,0x11,0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08,0x08,0x00,0x0d,0x51, -0xae,0x20,0x00,0x38,0x8e,0x24,0x00,0x30,0x24,0x02,0x00,0x03,0x24,0x03,0x00,0x01, -0x10,0x83,0x00,0x07,0xa2,0x22,0x00,0x08,0x24,0x02,0x00,0x02,0xa2,0x22,0x00,0x0a, -0x92,0x22,0x00,0x33,0xae,0x20,0x00,0x30,0x08,0x00,0x0d,0x51,0xa2,0x22,0x00,0x07, -0x08,0x00,0x0d,0xf0,0xa2,0x24,0x00,0x0a,0x8f,0x84,0xb4,0x40,0xae,0x20,0x00,0x34, -0x94,0x85,0x00,0x14,0x0c,0x00,0x1b,0x66,0x32,0x10,0x00,0xff,0x08,0x00,0x0d,0x42, -0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x37,0xf4, -0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00,0x80,0xa2,0x00,0x15,0x3c,0x06,0xb0,0x05, -0x10,0x40,0x00,0x0a,0x34,0xc6,0x02,0x54,0x83,0x83,0x8b,0xd4,0x00,0x00,0x00,0x00, -0xac,0x83,0x00,0x24,0x8c,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x42, -0x30,0x42,0x00,0x01,0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x28,0x8c,0x82,0x00,0x2c, -0x3c,0x06,0xb0,0x05,0x34,0xc6,0x04,0x50,0x00,0x02,0x18,0x43,0x30,0x63,0x00,0x01, -0x10,0x40,0x00,0x04,0x30,0x45,0x00,0x01,0xac,0x83,0x00,0x28,0x03,0xe0,0x00,0x08, -0xac,0x85,0x00,0x24,0x90,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff, -0x30,0x43,0x00,0x02,0x30,0x42,0x00,0x01,0xac,0x83,0x00,0x28,0x03,0xe0,0x00,0x08, -0xac,0x82,0x00,0x24,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd8, -0x34,0x63,0x00,0x20,0x24,0x42,0x38,0x84,0xac,0x62,0x00,0x00,0xaf,0xb1,0x00,0x1c, -0xaf,0xbf,0x00,0x20,0xaf,0xb0,0x00,0x18,0x90,0xa6,0x00,0x0a,0x27,0x83,0xb4,0x00, -0x00,0xa0,0x88,0x21,0x00,0x06,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x50,0x00,0x00, -0x80,0xa5,0x00,0x11,0x92,0x03,0x00,0x12,0x10,0xa0,0x00,0x04,0xa2,0x20,0x00,0x15, -0x24,0x02,0x00,0x12,0x10,0xc2,0x00,0xda,0x00,0x00,0x00,0x00,0x82,0x22,0x00,0x12, -0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x67,0x00,0x00,0x00,0x00,0xa2,0x20,0x00,0x12, -0xa2,0x00,0x00,0x19,0x86,0x23,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0, -0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x20,0x00,0x43,0x10,0x21, -0xa0,0x40,0x00,0x00,0x92,0x03,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0xdf, -0xa2,0x03,0x00,0x16,0x82,0x02,0x00,0x12,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x20, -0x00,0x00,0x00,0x00,0x92,0x23,0x00,0x08,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x45, -0x24,0x02,0x00,0x01,0xa2,0x20,0x00,0x04,0x92,0x08,0x00,0x04,0x00,0x00,0x00,0x00, -0x15,0x00,0x00,0x1e,0x24,0x02,0x00,0x01,0x92,0x07,0x00,0x0a,0xa2,0x02,0x00,0x17, -0x92,0x02,0x00,0x16,0x30,0xe3,0x00,0xff,0x30,0x42,0x00,0xe4,0x10,0x60,0x00,0x03, -0xa2,0x02,0x00,0x16,0x34,0x42,0x00,0x01,0xa2,0x02,0x00,0x16,0x11,0x00,0x00,0x05, -0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16,0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02, -0xa2,0x02,0x00,0x16,0x92,0x02,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x08, -0x00,0x00,0x00,0x00,0x96,0x02,0x00,0x06,0x00,0x00,0x00,0x00,0xa6,0x02,0x00,0x14, -0x8f,0xbf,0x00,0x20,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, -0x96,0x02,0x00,0x00,0x08,0x00,0x0e,0x6c,0xa6,0x02,0x00,0x14,0x92,0x07,0x00,0x0a, -0x00,0x00,0x00,0x00,0x14,0xe0,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x0e,0x58, -0xa2,0x00,0x00,0x17,0x96,0x04,0x00,0x00,0x96,0x05,0x00,0x06,0x27,0x86,0x90,0x00, -0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21, -0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21, -0x8c,0x66,0x00,0x08,0x8c,0x45,0x00,0x08,0x3c,0x03,0x80,0x00,0x00,0xc3,0x20,0x24, -0x10,0x80,0x00,0x08,0x00,0xa3,0x10,0x24,0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21, -0x10,0x80,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0xa6,0x18,0x2b,0x08,0x00,0x0e,0x58, -0xa2,0x03,0x00,0x17,0x10,0x40,0xff,0xfd,0x00,0xa6,0x18,0x2b,0x08,0x00,0x0e,0x8c, -0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x09,0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x05, -0x24,0x02,0x00,0x03,0x14,0x62,0xff,0xb8,0x00,0x00,0x00,0x00,0x08,0x00,0x0e,0x52, -0xa2,0x20,0x00,0x07,0x08,0x00,0x0e,0x52,0xa2,0x20,0x00,0x06,0x08,0x00,0x0e,0x52, -0xa2,0x20,0x00,0x05,0x82,0x22,0x00,0x10,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x69, -0x2c,0x62,0x00,0x02,0x10,0x40,0x00,0x49,0x3c,0x02,0xb0,0x09,0x92,0x25,0x00,0x08, -0x00,0x00,0x00,0x00,0x30,0xa6,0x00,0xff,0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x3b, -0x2c,0xc2,0x00,0x10,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, -0x24,0x02,0x00,0x01,0x00,0xc2,0x10,0x04,0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24, -0xa0,0x83,0x00,0x00,0x86,0x23,0x00,0x0c,0x96,0x26,0x00,0x0c,0x00,0x03,0x10,0xc0, -0x00,0x43,0x10,0x21,0x00,0x02,0x28,0x80,0x27,0x83,0x90,0x04,0x00,0xa3,0x18,0x21, -0x8c,0x64,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x04,0x00,0x00,0x00,0x00, -0x30,0x42,0x00,0x10,0x10,0x40,0x00,0x18,0x24,0x07,0x00,0x01,0x93,0x82,0x8b,0x71, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x0a,0x24,0x05,0x00,0x24, -0x00,0x06,0x2c,0x00,0x00,0x05,0x2c,0x03,0x0c,0x00,0x1b,0x66,0x02,0x00,0x20,0x21, -0x92,0x02,0x00,0x16,0xa2,0x00,0x00,0x12,0x30,0x42,0x00,0xe7,0x08,0x00,0x0e,0x49, -0xa2,0x02,0x00,0x16,0xf0,0xc5,0x00,0x06,0x00,0x00,0x28,0x12,0x27,0x82,0x90,0x00, -0x00,0xa2,0x28,0x21,0x0c,0x00,0x01,0x49,0x3c,0x04,0x00,0x80,0x96,0x26,0x00,0x0c, -0x08,0x00,0x0e,0xc9,0x00,0x06,0x2c,0x00,0x27,0x83,0x90,0x10,0x27,0x82,0x90,0x18, -0x00,0xa2,0x10,0x21,0x00,0xa3,0x18,0x21,0x90,0x44,0x00,0x00,0x90,0x65,0x00,0x05, -0x93,0x82,0x80,0x10,0x00,0x00,0x30,0x21,0x0c,0x00,0x21,0x9a,0xaf,0xa2,0x00,0x10, -0x96,0x26,0x00,0x0c,0x08,0x00,0x0e,0xc3,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xcd, -0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x30,0xa5,0x00,0x0f, -0x24,0x02,0x00,0x80,0x08,0x00,0x0e,0xb2,0x00,0xa2,0x10,0x07,0x86,0x26,0x00,0x0c, -0x3c,0x03,0xb0,0x09,0x34,0x42,0x01,0x72,0x34,0x63,0x01,0x78,0x94,0x47,0x00,0x00, -0x8c,0x65,0x00,0x00,0x00,0x06,0x10,0xc0,0x00,0x46,0x10,0x21,0x3c,0x04,0xb0,0x09, -0xae,0x25,0x00,0x1c,0x34,0x84,0x01,0x7c,0x27,0x83,0x90,0x04,0x00,0x02,0x10,0x80, -0x8c,0x85,0x00,0x00,0x00,0x43,0x10,0x21,0x8c,0x43,0x00,0x18,0xae,0x25,0x00,0x20, -0xa6,0x27,0x00,0x18,0x8c,0x66,0x00,0x08,0x02,0x20,0x20,0x21,0x0c,0x00,0x0f,0x19, -0x00,0x00,0x28,0x21,0x86,0x25,0x00,0x18,0x8e,0x26,0x00,0x1c,0x8e,0x27,0x00,0x20, -0x02,0x20,0x20,0x21,0x0c,0x00,0x1c,0x68,0xaf,0xa2,0x00,0x10,0x08,0x00,0x0e,0x49, -0xa2,0x02,0x00,0x12,0x92,0x22,0x00,0x08,0x08,0x00,0x0e,0x49,0xa2,0x22,0x00,0x09, -0xa2,0x20,0x00,0x11,0x80,0x82,0x00,0x50,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x03, -0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0,0xac,0x40,0x00,0x00,0x08,0x00,0x0e,0x49, -0xa0,0x80,0x00,0x50,0x94,0x8a,0x00,0x0c,0x24,0x03,0x00,0x24,0x00,0x80,0x70,0x21, -0x3c,0x02,0x80,0x00,0x3c,0x04,0xb0,0x03,0x24,0x42,0x3c,0x64,0xf1,0x43,0x00,0x06, -0x34,0x84,0x00,0x20,0x00,0x00,0x18,0x12,0x00,0xa0,0x68,0x21,0xac,0x82,0x00,0x00, -0x27,0x85,0x90,0x10,0x27,0x82,0x90,0x0f,0x27,0xbd,0xff,0xf8,0x00,0x62,0x60,0x21, -0x00,0x65,0x58,0x21,0x00,0x00,0xc0,0x21,0x11,0xa0,0x00,0xcc,0x00,0x00,0x78,0x21, -0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, -0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x91,0x87,0x00,0x00,0x80,0x48,0x00,0x04, -0x03,0xa0,0x60,0x21,0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0, -0x00,0x43,0x10,0x21,0x00,0x02,0x48,0x80,0x27,0x83,0x90,0x04,0xa3,0xa7,0x00,0x00, -0x01,0x23,0x18,0x21,0x8c,0x64,0x00,0x18,0x25,0x02,0xff,0xff,0x00,0x48,0x40,0x0b, -0x8c,0x83,0x00,0x04,0x2d,0x05,0x00,0x07,0x24,0x02,0x00,0x06,0x30,0x63,0x00,0x08, -0x14,0x60,0x00,0x35,0x00,0x45,0x40,0x0a,0x93,0xa7,0x00,0x00,0x27,0x82,0x90,0x18, -0x01,0x22,0x10,0x21,0x30,0xe3,0x00,0xf0,0x38,0x63,0x00,0x50,0x30,0xe5,0x00,0xff, -0x00,0x05,0x20,0x2b,0x00,0x03,0x18,0x2b,0x00,0x64,0x18,0x24,0x90,0x49,0x00,0x00, -0x10,0x60,0x00,0x16,0x30,0xe4,0x00,0x0f,0x24,0x02,0x00,0x04,0x10,0xa2,0x00,0x9d, -0x00,0x00,0x00,0x00,0x11,0xa0,0x00,0x3a,0x2c,0xa2,0x00,0x0c,0x10,0x40,0x00,0x02, -0x24,0x84,0x00,0x0c,0x00,0xe0,0x20,0x21,0x30,0x84,0x00,0xff,0x00,0x04,0x10,0x40, -0x27,0x83,0xbb,0x1c,0x00,0x44,0x10,0x21,0x00,0x43,0x10,0x21,0x90,0x47,0x00,0x00, -0x00,0x00,0x00,0x00,0x2c,0xe3,0x00,0x0c,0xa3,0xa7,0x00,0x00,0x10,0x60,0x00,0x02, -0x24,0xe2,0x00,0x04,0x00,0xe0,0x10,0x21,0xa3,0xa2,0x00,0x00,0x91,0x65,0x00,0x00, -0x91,0x82,0x00,0x00,0x30,0xa3,0x00,0xff,0x00,0x62,0x10,0x2b,0x10,0x40,0x00,0x0e, -0x2c,0x62,0x00,0x0c,0x14,0x40,0x00,0x03,0x00,0x60,0x20,0x21,0x30,0xa2,0x00,0x0f, -0x24,0x44,0x00,0x0c,0x00,0x04,0x10,0x40,0x00,0x44,0x20,0x21,0x27,0x83,0xbb,0x1c, -0x00,0x83,0x18,0x21,0x90,0x62,0x00,0x02,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x05, -0x00,0x09,0x11,0x00,0xa1,0x85,0x00,0x00,0x93,0xa2,0x00,0x00,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x08,0x00,0x49,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x23, -0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21,0x27,0x83,0xb4,0xa8,0x00,0x43,0x10,0x21, -0x90,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x83,0x00,0x0c,0x14,0x60,0x00,0x06, -0x00,0x80,0x10,0x21,0x00,0x18,0x10,0x40,0x00,0x4f,0x10,0x21,0x00,0x02,0x11,0x00, -0x00,0x82,0x10,0x21,0x24,0x42,0x00,0x04,0x08,0x00,0x0f,0x7a,0xa1,0x82,0x00,0x00, -0x8f,0x8d,0x81,0x5c,0x00,0x00,0x00,0x00,0x01,0xa8,0x10,0x21,0x90,0x43,0x00,0x00, -0x00,0x00,0x00,0x00,0x10,0x60,0xff,0xd1,0x00,0x00,0x28,0x21,0x00,0x06,0x74,0x82, -0x30,0xe2,0x00,0xff,0x2c,0x42,0x00,0x0c,0x14,0x40,0x00,0x03,0x00,0xe0,0x10,0x21, -0x30,0xe2,0x00,0x0f,0x24,0x42,0x00,0x0c,0x30,0x44,0x00,0xff,0xa3,0xa2,0x00,0x00, -0x24,0x02,0x00,0x0c,0x10,0x82,0x00,0x0d,0x00,0x09,0x11,0x00,0x00,0x49,0x10,0x23, -0x00,0x02,0x10,0x80,0x00,0x04,0x18,0x40,0x00,0x49,0x10,0x23,0x00,0x64,0x18,0x21, -0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x27,0x84,0xb4,0xa8,0x00,0x44,0x10,0x21, -0x90,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0xa7,0x00,0x00,0x00,0x0a,0x1c,0x00, -0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, -0x27,0x83,0x90,0x04,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x18,0x00,0x00,0x00,0x00, -0x8c,0x83,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10,0x14,0x60,0x00,0x33, -0x00,0x06,0x14,0x42,0x00,0x09,0x11,0x00,0x00,0x49,0x10,0x23,0x00,0x02,0x10,0x80, -0x00,0x49,0x10,0x23,0x27,0x83,0xb5,0x78,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, -0x90,0x44,0x00,0x04,0x90,0x43,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x64,0xc0,0x24, -0x93,0xa7,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0xe2,0x00,0x0f,0x10,0x40,0x00,0x0f, -0x31,0xcf,0x00,0x01,0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0, -0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x84,0x90,0x00,0x00,0x44,0x10,0x21, -0x84,0x43,0x00,0x06,0x00,0x00,0x00,0x00,0x28,0x63,0x06,0x41,0x14,0x60,0x00,0x04, -0x30,0xe2,0x00,0xff,0x24,0x07,0x00,0x0f,0xa3,0xa7,0x00,0x00,0x30,0xe2,0x00,0xff, -0x2c,0x42,0x00,0x0c,0x14,0x40,0x00,0x06,0x00,0xe0,0x10,0x21,0x00,0x18,0x10,0x40, -0x00,0x4f,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0x47,0x10,0x21,0x24,0x42,0x00,0x04, -0xa3,0xa2,0x00,0x00,0x00,0x40,0x38,0x21,0x01,0xa8,0x10,0x21,0x90,0x43,0x00,0x00, -0x24,0xa4,0x00,0x01,0x30,0x85,0xff,0xff,0x00,0xa3,0x18,0x2b,0x14,0x60,0xff,0xad, -0x30,0xe2,0x00,0xff,0x08,0x00,0x0f,0x67,0x00,0x00,0x00,0x00,0x08,0x00,0x0f,0xc8, -0x30,0x58,0x00,0x01,0x81,0xc2,0x00,0x48,0x00,0x00,0x00,0x00,0x10,0x40,0xff,0x73, -0x00,0x00,0x00,0x00,0x08,0x00,0x0f,0x55,0x00,0x00,0x00,0x00,0x00,0x0a,0x1c,0x00, -0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, -0x00,0x45,0x10,0x21,0x80,0x48,0x00,0x05,0x91,0x67,0x00,0x00,0x08,0x00,0x0f,0x35, -0x03,0xa0,0x58,0x21,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, -0x24,0x42,0x40,0x04,0x03,0xe0,0x00,0x08,0xac,0x62,0x00,0x00,0x27,0xbd,0xff,0xc0, -0xaf,0xb7,0x00,0x34,0xaf,0xb6,0x00,0x30,0xaf,0xb5,0x00,0x2c,0xaf,0xb4,0x00,0x28, -0xaf,0xb3,0x00,0x24,0xaf,0xb2,0x00,0x20,0xaf,0xbf,0x00,0x3c,0xaf,0xbe,0x00,0x38, -0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18,0x84,0x82,0x00,0x0c,0x27,0x93,0x90,0x04, -0x3c,0x05,0xb0,0x03,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80, -0x00,0x73,0x10,0x21,0x8c,0x5e,0x00,0x18,0x3c,0x02,0x80,0x00,0x34,0xa5,0x00,0x20, -0x24,0x42,0x40,0x1c,0xac,0xa2,0x00,0x00,0x8f,0xd0,0x00,0x08,0x27,0x95,0x90,0x10, -0x00,0x75,0x18,0x21,0x00,0x00,0x28,0x21,0x02,0x00,0x30,0x21,0x90,0x71,0x00,0x00, -0x0c,0x00,0x0f,0x19,0x00,0x80,0xb0,0x21,0x00,0x40,0x90,0x21,0x00,0x10,0x14,0x42, -0x30,0x54,0x00,0x01,0x02,0x40,0x20,0x21,0x00,0x10,0x14,0x82,0x02,0x80,0x28,0x21, -0x12,0x51,0x00,0x23,0x00,0x10,0xbf,0xc2,0x86,0xc3,0x00,0x0c,0x30,0x50,0x00,0x01, -0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x55,0x10,0x21, -0xa0,0x52,0x00,0x00,0x86,0xc3,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0, -0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x53,0x30,0x21,0x8c,0xc7,0x00,0x18, -0x27,0x83,0x90,0x00,0x00,0x43,0x10,0x21,0x8c,0xe3,0x00,0x04,0x84,0x46,0x00,0x06, -0x00,0x03,0x19,0x42,0x0c,0x00,0x08,0xe3,0x30,0x73,0x00,0x01,0x00,0x40,0x88,0x21, -0x02,0x40,0x20,0x21,0x02,0x80,0x28,0x21,0x16,0xe0,0x00,0x10,0x02,0x00,0x30,0x21, -0x86,0xc2,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21, -0x00,0x03,0x18,0x80,0x27,0x82,0x90,0x08,0x00,0x62,0x18,0x21,0xa4,0x71,0x00,0x04, -0x7b,0xbe,0x01,0xfc,0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c, -0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40,0x86,0xc3,0x00,0x0c, -0xaf,0xb3,0x00,0x10,0xaf,0xa0,0x00,0x14,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, -0x00,0x02,0x10,0x80,0x00,0x55,0x10,0x21,0x80,0x47,0x00,0x06,0x00,0x00,0x00,0x00, -0x24,0xe7,0x00,0x02,0x00,0x07,0x17,0xc2,0x00,0xe2,0x38,0x21,0x00,0x07,0x38,0x43, -0x00,0x07,0x38,0x40,0x0c,0x00,0x09,0x0a,0x03,0xc7,0x38,0x21,0x08,0x00,0x10,0x48, -0x02,0x22,0x88,0x21,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd0, -0x34,0x63,0x00,0x20,0x24,0x42,0x41,0xa4,0xaf,0xb2,0x00,0x20,0xac,0x62,0x00,0x00, -0xaf,0xbf,0x00,0x28,0xaf,0xb3,0x00,0x24,0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18, -0x3c,0x02,0xb0,0x03,0x90,0x83,0x00,0x0a,0x34,0x42,0x01,0x04,0x94,0x45,0x00,0x00, -0x00,0x03,0x18,0x80,0x27,0x82,0xb4,0x00,0x00,0x62,0x18,0x21,0x30,0xa6,0xff,0xff, -0x8c,0x71,0x00,0x00,0x80,0x85,0x00,0x12,0x30,0xc9,0x00,0xff,0x00,0x06,0x32,0x02, -0xa4,0x86,0x00,0x44,0xa4,0x89,0x00,0x46,0x82,0x22,0x00,0x12,0x00,0x80,0x90,0x21, -0x10,0xa0,0x00,0x1b,0xa0,0x80,0x00,0x15,0x00,0xc5,0x10,0x2a,0x10,0x40,0x00,0x14, -0x00,0x00,0x00,0x00,0xa2,0x20,0x00,0x19,0x84,0x83,0x00,0x0c,0x00,0x00,0x00,0x00, -0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x20, -0x00,0x43,0x10,0x21,0xa0,0x40,0x00,0x00,0xa0,0x80,0x00,0x12,0x92,0x22,0x00,0x16, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xdf,0xa2,0x22,0x00,0x16,0x8f,0xbf,0x00,0x28, -0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30, -0x0c,0x00,0x10,0x01,0x00,0x00,0x00,0x00,0x08,0x00,0x10,0x97,0x00,0x00,0x00,0x00, -0x28,0x42,0x00,0x02,0x10,0x40,0x01,0x76,0x00,0x00,0x28,0x21,0x94,0x87,0x00,0x0c, -0x00,0x00,0x00,0x00,0x00,0xe0,0x10,0x21,0x00,0x02,0x14,0x00,0x00,0x02,0x14,0x03, -0x00,0x07,0x24,0x00,0x00,0x04,0x24,0x03,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21, -0x00,0x04,0x28,0xc0,0x00,0xa4,0x28,0x21,0x27,0x82,0x90,0x20,0x00,0x03,0x18,0x80, -0x00,0x62,0x18,0x21,0x00,0x05,0x28,0x80,0x27,0x82,0x90,0x08,0x00,0xa2,0x10,0x21, -0x8c,0x68,0x00,0x00,0x80,0x44,0x00,0x06,0x27,0x82,0x90,0x10,0x00,0x08,0x1d,0x02, -0x00,0xa2,0x28,0x21,0x38,0x84,0x00,0x00,0x30,0x63,0x00,0x01,0x01,0x24,0x30,0x0b, -0x80,0xaa,0x00,0x04,0x80,0xa9,0x00,0x05,0x10,0x60,0x00,0x02,0x00,0x08,0x14,0x02, -0x30,0x46,0x00,0x0f,0x15,0x20,0x00,0x28,0x01,0x49,0x10,0x21,0x15,0x40,0x00,0x11, -0x30,0xe3,0xff,0xff,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa8,0x00,0xff, -0x2d,0x02,0x00,0x04,0x10,0x40,0x01,0x46,0x2d,0x02,0x00,0x10,0x3c,0x04,0xb0,0x05, -0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01,0x01,0x02,0x10,0x04, -0x00,0x62,0x18,0x25,0xa0,0x83,0x00,0x00,0x96,0x47,0x00,0x0c,0x00,0x00,0x00,0x00, -0x30,0xe3,0xff,0xff,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x27,0x84,0x90,0x10, -0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21,0x80,0x45,0x00,0x06,0x00,0x03,0x1a,0x00, -0x3c,0x04,0xb0,0x00,0x00,0x65,0x18,0x21,0x00,0x64,0x20,0x21,0x94,0x82,0x00,0x00, -0x82,0x43,0x00,0x10,0x00,0x02,0x14,0x00,0x14,0x60,0x00,0x06,0x00,0x02,0x3c,0x03, -0x30,0xe2,0x00,0x04,0x14,0x40,0x00,0x04,0x01,0x49,0x10,0x21,0x34,0xe2,0x08,0x00, -0xa4,0x82,0x00,0x00,0x01,0x49,0x10,0x21,0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03, -0x00,0x46,0x10,0x2a,0x10,0x40,0x00,0x7c,0x00,0x00,0x00,0x00,0x82,0x42,0x00,0x10, -0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0e,0x00,0x00,0x00,0x00,0x86,0x43,0x00,0x0c, -0x25,0x44,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, -0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21,0xa0,0x44,0x00,0x04,0x92,0x23,0x00,0x16, -0x02,0x40,0x20,0x21,0x30,0x63,0x00,0xfb,0x08,0x00,0x10,0x9c,0xa2,0x23,0x00,0x16, -0x86,0x43,0x00,0x0c,0x25,0x24,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, -0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21,0xa0,0x44,0x00,0x05, -0x86,0x45,0x00,0x0c,0x0c,0x00,0x1e,0xea,0x02,0x20,0x20,0x21,0x10,0x40,0x00,0x5a, -0x00,0x00,0x00,0x00,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa6,0x00,0xff, -0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x4c,0x2c,0xc2,0x00,0x10,0x3c,0x04,0xb0,0x05, -0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01,0x00,0xc2,0x10,0x04, -0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24,0xa0,0x83,0x00,0x00,0x92,0x45,0x00,0x08, -0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff,0x14,0xa0,0x00,0x33,0x24,0x02,0x00,0x01, -0xa2,0x40,0x00,0x04,0x92,0x22,0x00,0x04,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x0c, -0x24,0x02,0x00,0x01,0xa2,0x22,0x00,0x17,0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00, -0x10,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x96,0x22,0x00,0x06,0x08,0x00,0x10,0x97, -0xa6,0x22,0x00,0x14,0x96,0x22,0x00,0x00,0x08,0x00,0x10,0x97,0xa6,0x22,0x00,0x14, -0x92,0x22,0x00,0x0a,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03,0x00,0x00,0x00,0x00, -0x08,0x00,0x11,0x26,0xa2,0x20,0x00,0x17,0x96,0x24,0x00,0x00,0x96,0x25,0x00,0x06, -0x27,0x86,0x90,0x00,0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0, -0x00,0x45,0x10,0x21,0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80, -0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08,0x8c,0x44,0x00,0x08,0x3c,0x03,0x80,0x00, -0x00,0xa3,0x30,0x24,0x10,0xc0,0x00,0x08,0x00,0x83,0x10,0x24,0x10,0x40,0x00,0x04, -0x00,0x00,0x18,0x21,0x10,0xc0,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b, -0x08,0x00,0x11,0x26,0xa2,0x23,0x00,0x17,0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b, -0x08,0x00,0x11,0x49,0x00,0x00,0x00,0x00,0x10,0xa2,0x00,0x09,0x24,0x02,0x00,0x02, -0x10,0xa2,0x00,0x05,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xca,0x00,0x00,0x00,0x00, -0x08,0x00,0x11,0x21,0xa2,0x40,0x00,0x07,0x08,0x00,0x11,0x21,0xa2,0x40,0x00,0x06, -0x08,0x00,0x11,0x21,0xa2,0x40,0x00,0x05,0x14,0x40,0xff,0xbe,0x3c,0x04,0xb0,0x05, -0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80, -0x08,0x00,0x11,0x18,0x00,0xa2,0x10,0x07,0x0c,0x00,0x10,0x07,0x02,0x40,0x20,0x21, -0x08,0x00,0x10,0x97,0x00,0x00,0x00,0x00,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00, -0x30,0xa6,0x00,0xff,0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x99,0x2c,0xc2,0x00,0x10, -0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01, -0x00,0xc2,0x10,0x04,0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24,0xa0,0x83,0x00,0x00, -0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff,0x14,0xa0,0x00,0x80, -0x24,0x02,0x00,0x01,0xa2,0x40,0x00,0x04,0x86,0x43,0x00,0x0c,0x27,0x93,0x90,0x04, -0x96,0x47,0x00,0x0c,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x28,0x80, -0x00,0xb3,0x18,0x21,0x8c,0x64,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x04, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x10,0x10,0x40,0x00,0x64,0x00,0x00,0x30,0x21, -0x00,0x07,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, -0x00,0x02,0x10,0x80,0x00,0x53,0x10,0x21,0x8c,0x43,0x00,0x18,0x93,0x82,0x8b,0x71, -0x8c,0x64,0x00,0x04,0x30,0x42,0x00,0x01,0x00,0x04,0x21,0x42,0x14,0x40,0x00,0x4d, -0x30,0x90,0x00,0x01,0x00,0x07,0x2c,0x00,0x00,0x05,0x2c,0x03,0x0c,0x00,0x1b,0x66, -0x02,0x20,0x20,0x21,0x96,0x26,0x00,0x06,0x12,0x00,0x00,0x14,0x30,0xc5,0xff,0xff, -0x02,0x60,0x90,0x21,0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21,0x00,0x02,0x10,0x80, -0x00,0x52,0x18,0x21,0x92,0x22,0x00,0x0a,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0b, -0x02,0x20,0x20,0x21,0x8c,0x63,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x62,0x00,0x04, -0x00,0x00,0x00,0x00,0x00,0x02,0x11,0x42,0x0c,0x00,0x1b,0x66,0x30,0x50,0x00,0x01, -0x96,0x26,0x00,0x06,0x16,0x00,0xff,0xef,0x30,0xc5,0xff,0xff,0x92,0x22,0x00,0x04, -0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x0d,0x24,0x02,0x00,0x01,0xa2,0x22,0x00,0x17, -0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x05,0x00,0x00,0x00,0x00, -0xa6,0x26,0x00,0x14,0x92,0x22,0x00,0x16,0x08,0x00,0x10,0x96,0x30,0x42,0x00,0xc3, -0x96,0x22,0x00,0x00,0x08,0x00,0x11,0xbd,0xa6,0x22,0x00,0x14,0x92,0x22,0x00,0x0a, -0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x11,0xb8, -0xa2,0x20,0x00,0x17,0x96,0x24,0x00,0x00,0x30,0xc5,0xff,0xff,0x00,0x05,0x18,0xc0, -0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x00,0x65,0x18,0x21,0x27,0x84,0x90,0x00, -0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21,0x00,0x03,0x18,0x80,0x8c,0x45,0x00,0x08, -0x00,0x64,0x18,0x21,0x8c,0x64,0x00,0x08,0x3c,0x02,0x80,0x00,0x00,0xa2,0x38,0x24, -0x10,0xe0,0x00,0x08,0x00,0x82,0x10,0x24,0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21, -0x10,0xe0,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b,0x08,0x00,0x11,0xb8, -0xa2,0x23,0x00,0x17,0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b,0x08,0x00,0x11,0xdc, -0x00,0x00,0x00,0x00,0x24,0x05,0x00,0x24,0xf0,0xe5,0x00,0x06,0x00,0x00,0x28,0x12, -0x27,0x82,0x90,0x00,0x00,0xa2,0x28,0x21,0x0c,0x00,0x01,0x49,0x00,0x00,0x20,0x21, -0x96,0x47,0x00,0x0c,0x08,0x00,0x11,0x9a,0x00,0x07,0x2c,0x00,0x27,0x83,0x90,0x10, -0x27,0x82,0x90,0x18,0x00,0xa2,0x10,0x21,0x00,0xa3,0x18,0x21,0x90,0x44,0x00,0x00, -0x90,0x65,0x00,0x05,0x93,0x82,0x80,0x10,0x24,0x07,0x00,0x01,0x0c,0x00,0x21,0x9a, -0xaf,0xa2,0x00,0x10,0x96,0x47,0x00,0x0c,0x08,0x00,0x11,0x8d,0x00,0x07,0x1c,0x00, -0x10,0xa2,0x00,0x09,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x05,0x24,0x02,0x00,0x03, -0x14,0xa2,0xff,0x7d,0x00,0x00,0x00,0x00,0x08,0x00,0x11,0x7e,0xa2,0x40,0x00,0x07, -0x08,0x00,0x11,0x7e,0xa2,0x40,0x00,0x06,0x08,0x00,0x11,0x7e,0xa2,0x40,0x00,0x05, -0x14,0x40,0xff,0x71,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, -0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80,0x08,0x00,0x11,0x75,0x00,0xa2,0x10,0x07, -0x14,0x40,0xfe,0xc3,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, -0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80,0x08,0x00,0x10,0xd0,0x00,0xa2,0x10,0x07, -0x84,0x83,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, -0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x04,0x00,0x43,0x10,0x21,0x8c,0x47,0x00,0x18, -0x00,0x00,0x00,0x00,0x8c,0xe6,0x00,0x08,0x0c,0x00,0x0f,0x19,0x00,0x00,0x00,0x00, -0x02,0x40,0x20,0x21,0x00,0x00,0x28,0x21,0x00,0x00,0x30,0x21,0x00,0x00,0x38,0x21, -0x0c,0x00,0x1c,0x68,0xaf,0xa2,0x00,0x10,0x00,0x02,0x1e,0x00,0x14,0x60,0xfe,0x6b, -0xa2,0x22,0x00,0x12,0x92,0x43,0x00,0x08,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x40, -0x24,0x02,0x00,0x01,0xa2,0x40,0x00,0x04,0x92,0x28,0x00,0x04,0x00,0x00,0x00,0x00, -0x15,0x00,0x00,0x19,0x24,0x02,0x00,0x01,0x92,0x27,0x00,0x0a,0xa2,0x22,0x00,0x17, -0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x10,0x00,0x00,0x00,0x00, -0x96,0x22,0x00,0x06,0x00,0x00,0x00,0x00,0xa6,0x22,0x00,0x14,0x92,0x22,0x00,0x16, -0x30,0xe3,0x00,0xff,0x30,0x42,0x00,0xc0,0x10,0x60,0x00,0x03,0xa2,0x22,0x00,0x16, -0x34,0x42,0x00,0x01,0xa2,0x22,0x00,0x16,0x11,0x00,0xfe,0x50,0x00,0x00,0x00,0x00, -0x92,0x22,0x00,0x16,0x08,0x00,0x10,0x96,0x34,0x42,0x00,0x02,0x96,0x22,0x00,0x00, -0x08,0x00,0x12,0x3f,0xa6,0x22,0x00,0x14,0x92,0x27,0x00,0x0a,0x00,0x00,0x00,0x00, -0x14,0xe0,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x12,0x38,0xa2,0x20,0x00,0x17, -0x96,0x24,0x00,0x00,0x96,0x25,0x00,0x06,0x27,0x86,0x90,0x00,0x00,0x04,0x18,0xc0, -0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21,0x00,0x03,0x18,0x80, -0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08, -0x8c,0x44,0x00,0x08,0x3c,0x03,0x80,0x00,0x00,0xa3,0x30,0x24,0x10,0xc0,0x00,0x08, -0x00,0x83,0x10,0x24,0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21,0x10,0xc0,0x00,0x02, -0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b,0x08,0x00,0x12,0x38,0xa2,0x23,0x00,0x17, -0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b,0x08,0x00,0x12,0x67,0x00,0x00,0x00,0x00, -0x10,0x62,0x00,0x09,0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x05,0x24,0x02,0x00,0x03, -0x14,0x62,0xff,0xbd,0x00,0x00,0x00,0x00,0x08,0x00,0x12,0x32,0xa2,0x40,0x00,0x07, -0x08,0x00,0x12,0x32,0xa2,0x40,0x00,0x06,0x08,0x00,0x12,0x32,0xa2,0x40,0x00,0x05, -0x3c,0x02,0x80,0x00,0x00,0x82,0x30,0x24,0x10,0xc0,0x00,0x08,0x00,0xa2,0x18,0x24, -0x10,0x60,0x00,0x04,0x00,0x00,0x10,0x21,0x10,0xc0,0x00,0x02,0x24,0x02,0x00,0x01, -0x00,0xa4,0x10,0x2b,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x10,0x60,0xff,0xfd, -0x00,0xa4,0x10,0x2b,0x08,0x00,0x12,0x82,0x00,0x00,0x00,0x00,0x30,0x82,0xff,0xff, -0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x27,0x84,0x90,0x10,0x00,0x03,0x18,0x80, -0x00,0x64,0x18,0x21,0x80,0x66,0x00,0x06,0x00,0x02,0x12,0x00,0x3c,0x03,0xb0,0x00, -0x00,0x46,0x10,0x21,0x00,0x45,0x10,0x21,0x03,0xe0,0x00,0x08,0x00,0x43,0x10,0x21, -0x27,0xbd,0xff,0xe0,0x30,0x82,0x00,0x7c,0x30,0x84,0xff,0x00,0xaf,0xbf,0x00,0x1c, -0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x14,0x40,0x00,0x41, -0x00,0x04,0x22,0x03,0x24,0x02,0x00,0x04,0x3c,0x10,0xb0,0x03,0x8e,0x10,0x00,0x00, -0x10,0x82,0x00,0x32,0x24,0x02,0x00,0x08,0x10,0x82,0x00,0x03,0x32,0x02,0x00,0x20, -0x08,0x00,0x12,0xa8,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x17,0x3c,0x02,0xb0,0x06, -0x34,0x42,0x80,0x24,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x67,0x00,0xff, -0x10,0xe0,0x00,0x23,0x00,0x00,0x88,0x21,0x8f,0x85,0x8f,0xe0,0x00,0x40,0x30,0x21, -0x94,0xa2,0x00,0x08,0x8c,0xc3,0x00,0x00,0x26,0x31,0x00,0x01,0x24,0x42,0x00,0x02, -0x30,0x42,0x01,0xff,0x34,0x63,0x01,0x00,0x02,0x27,0x20,0x2a,0xa4,0xa2,0x00,0x08, -0x14,0x80,0xff,0xf7,0xac,0xc3,0x00,0x00,0x84,0xa3,0x00,0x08,0x3c,0x02,0xb0,0x03, -0x34,0x42,0x00,0x30,0xac,0x43,0x00,0x00,0x27,0x92,0xb4,0x00,0x24,0x11,0x00,0x12, -0x8e,0x44,0x00,0x00,0x26,0x31,0xff,0xff,0x90,0x82,0x00,0x10,0x00,0x00,0x00,0x00, -0x10,0x40,0x00,0x03,0x26,0x52,0x00,0x04,0x0c,0x00,0x18,0xd0,0x00,0x00,0x00,0x00, -0x06,0x21,0xff,0xf7,0x24,0x02,0xff,0xdf,0x02,0x02,0x80,0x24,0x3c,0x01,0xb0,0x03, -0x0c,0x00,0x13,0x1c,0xac,0x30,0x00,0x00,0x08,0x00,0x12,0xa8,0x00,0x00,0x00,0x00, -0x8f,0x85,0x8f,0xe0,0x08,0x00,0x12,0xbe,0x00,0x00,0x00,0x00,0x24,0x02,0xff,0x95, -0x3c,0x03,0xb0,0x03,0x02,0x02,0x80,0x24,0x34,0x63,0x00,0x30,0x3c,0x01,0xb0,0x03, -0xac,0x30,0x00,0x00,0x0c,0x00,0x12,0xe5,0xac,0x60,0x00,0x00,0x08,0x00,0x12,0xa8, -0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x50,0x08,0x00,0x12,0xa8, -0xac,0x46,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4b,0x94,0x3c,0x0b,0xb0,0x03, -0xad,0x6a,0x00,0x20,0x3c,0x08,0x80,0x01,0x25,0x08,0x00,0x00,0x3c,0x09,0x80,0x01, -0x25,0x29,0x03,0x50,0x11,0x09,0x00,0x10,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00, -0x25,0x4a,0x4b,0xbc,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x3c,0x08,0xb0,0x06, -0x35,0x08,0x80,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8d,0x09,0x00,0x00, -0x00,0x00,0x00,0x00,0x31,0x29,0x00,0x01,0x00,0x00,0x00,0x00,0x24,0x01,0x00,0x01, -0x15,0x21,0xff,0xf2,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4b,0xf8, -0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x3c,0x02,0xb0,0x03,0x8c,0x43,0x00,0x00, -0x00,0x00,0x00,0x00,0x34,0x63,0x00,0x40,0x00,0x00,0x00,0x00,0xac,0x43,0x00,0x00, -0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4c,0x24,0x3c,0x0b,0xb0,0x03, -0xad,0x6a,0x00,0x20,0x3c,0x02,0x80,0x01,0x24,0x42,0x00,0x00,0x3c,0x03,0x80,0x01, -0x24,0x63,0x03,0x50,0x3c,0x04,0xb0,0x00,0x8c,0x85,0x00,0x00,0x00,0x00,0x00,0x00, -0xac,0x45,0x00,0x00,0x24,0x42,0x00,0x04,0x24,0x84,0x00,0x04,0x00,0x43,0x08,0x2a, -0x14,0x20,0xff,0xf9,0x00,0x00,0x00,0x00,0x0c,0x00,0x13,0x1c,0x00,0x00,0x00,0x00, -0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4c,0x70,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, -0x3c,0x02,0x80,0x01,0x24,0x42,0x03,0x50,0x3c,0x03,0x80,0x01,0x24,0x63,0x3f,0x24, -0xac,0x40,0x00,0x00,0xac,0x40,0x00,0x04,0xac,0x40,0x00,0x08,0xac,0x40,0x00,0x0c, -0x24,0x42,0x00,0x10,0x00,0x43,0x08,0x2a,0x14,0x20,0xff,0xf9,0x00,0x00,0x00,0x00, -0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4c,0xb0,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, -0x3c,0x1c,0x80,0x01,0x27,0x9c,0x7f,0xf0,0x27,0x9d,0x8b,0xe0,0x00,0x00,0x00,0x00, -0x27,0x9d,0x8f,0xc8,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4c,0xd4,0x3c,0x0b,0xb0,0x03, -0xad,0x6a,0x00,0x20,0x40,0x80,0x68,0x00,0x40,0x08,0x60,0x00,0x00,0x00,0x00,0x00, -0x35,0x08,0xff,0x01,0x40,0x88,0x60,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x15,0x62, -0x00,0x00,0x00,0x00,0x24,0x84,0xf8,0x00,0x30,0x87,0x00,0x03,0x00,0x04,0x30,0x40, -0x00,0xc7,0x20,0x23,0x3c,0x02,0xb0,0x0a,0x27,0xbd,0xff,0xe0,0x24,0x03,0xff,0xff, -0x00,0x82,0x20,0x21,0xaf,0xb1,0x00,0x14,0xac,0x83,0x10,0x00,0xaf,0xbf,0x00,0x18, -0xaf,0xb0,0x00,0x10,0x00,0xa0,0x88,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x10,0x00, -0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0xc7,0x10,0x23,0x3c,0x03,0xb0,0x0a, -0x00,0x43,0x10,0x21,0x8c,0x50,0x00,0x00,0x0c,0x00,0x13,0x99,0x02,0x20,0x20,0x21, -0x02,0x11,0x80,0x24,0x00,0x50,0x80,0x06,0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x18, -0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xd8, -0xaf,0xb2,0x00,0x18,0x00,0xa0,0x90,0x21,0x24,0x05,0xff,0xff,0xaf,0xb3,0x00,0x1c, -0xaf,0xbf,0x00,0x20,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x00,0xc0,0x98,0x21, -0x12,0x45,0x00,0x23,0x24,0x84,0xf8,0x00,0x30,0x83,0x00,0x03,0x00,0x04,0x10,0x40, -0x00,0x40,0x88,0x21,0x00,0x60,0x20,0x21,0x00,0x43,0x10,0x23,0x3c,0x03,0xb0,0x0a, -0x00,0x43,0x10,0x21,0xac,0x45,0x10,0x00,0x00,0x40,0x18,0x21,0x24,0x05,0x00,0x01, -0x8c,0x62,0x10,0x00,0x00,0x00,0x00,0x00,0x14,0x45,0xff,0xfd,0x3c,0x02,0xb0,0x0a, -0x02,0x24,0x88,0x23,0x02,0x22,0x88,0x21,0x8e,0x30,0x00,0x00,0x0c,0x00,0x13,0x99, -0x02,0x40,0x20,0x21,0x00,0x12,0x18,0x27,0x02,0x03,0x80,0x24,0x00,0x53,0x10,0x04, -0x02,0x02,0x80,0x25,0xae,0x30,0x00,0x00,0x24,0x03,0x00,0x01,0x8e,0x22,0x10,0x00, -0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x20, -0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, -0x30,0x82,0x00,0x03,0x00,0x04,0x18,0x40,0x00,0x62,0x18,0x23,0x3c,0x04,0xb0,0x0a, -0x00,0x64,0x18,0x21,0xac,0x66,0x00,0x00,0x24,0x04,0x00,0x01,0x8c,0x62,0x10,0x00, -0x00,0x00,0x00,0x00,0x14,0x44,0xff,0xfd,0x00,0x00,0x00,0x00,0x08,0x00,0x13,0x87, -0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x21,0x00,0x64,0x10,0x06,0x30,0x42,0x00,0x01, -0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0x2c,0x62,0x00,0x20, -0x14,0x40,0xff,0xf9,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21, -0x27,0xbd,0xff,0xe0,0x3c,0x03,0xb0,0x05,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, -0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x1c,0x00,0x80,0x90,0x21,0x00,0xa0,0x80,0x21, -0x00,0xc0,0x88,0x21,0x34,0x63,0x02,0x2e,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x42,0x00,0x01,0x14,0x40,0xff,0xfc,0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0xc0, -0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0xc0, -0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x03,0x3c,0x02,0xc0,0x00,0x00,0x10,0x1c,0x00, -0x34,0x42,0x04,0x00,0x3c,0x04,0xb0,0x05,0x3c,0x05,0xb0,0x05,0x24,0x63,0x16,0x09, -0x02,0x22,0x10,0x21,0x34,0x84,0x04,0x20,0x34,0xa5,0x04,0x24,0x3c,0x06,0xb0,0x05, -0xac,0x83,0x00,0x00,0x24,0x07,0x00,0x01,0xac,0xa2,0x00,0x00,0x34,0xc6,0x02,0x28, -0x24,0x02,0x00,0x20,0xae,0x47,0x00,0x3c,0x24,0x04,0x08,0x24,0xa0,0xc2,0x00,0x00, -0x3c,0x05,0x00,0xc0,0xa2,0x47,0x00,0x11,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x01, -0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0xc0,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x01, -0x8f,0xbf,0x00,0x1c,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x20,0x24,0x02,0x00,0x06,0xac,0x82,0x00,0x0c,0xa0,0x80,0x00,0x50, -0xac,0x80,0x00,0x00,0xac,0x80,0x00,0x04,0xac,0x80,0x00,0x08,0xac,0x80,0x00,0x14, -0xac,0x80,0x00,0x18,0xac,0x80,0x00,0x1c,0xa4,0x80,0x00,0x20,0xac,0x80,0x00,0x24, -0xac,0x80,0x00,0x28,0xac,0x80,0x00,0x2c,0xa0,0x80,0x00,0x30,0xa0,0x80,0x00,0x31, -0xac,0x80,0x00,0x34,0xac,0x80,0x00,0x38,0xa0,0x80,0x00,0x3c,0xac,0x82,0x00,0x10, -0xa0,0x80,0x00,0x44,0xac,0x80,0x00,0x48,0x03,0xe0,0x00,0x08,0xac,0x80,0x00,0x4c, -0x3c,0x04,0xb0,0x06,0x34,0x84,0x80,0x00,0x8c,0x83,0x00,0x00,0x3c,0x02,0x12,0x00, -0x3c,0x05,0xb0,0x03,0x00,0x62,0x18,0x25,0x34,0xa5,0x00,0x8b,0x24,0x02,0xff,0x80, -0xac,0x83,0x00,0x00,0x03,0xe0,0x00,0x08,0xa0,0xa2,0x00,0x00,0x3c,0x04,0xb0,0x03, -0x34,0x84,0x00,0x0b,0x24,0x02,0x00,0x22,0x3c,0x05,0xb0,0x01,0x3c,0x06,0x45,0x67, -0x3c,0x0a,0xb0,0x09,0xa0,0x82,0x00,0x00,0x34,0xa5,0x00,0x04,0x34,0xc6,0x89,0xaa, -0x35,0x4a,0x00,0x04,0x24,0x02,0x01,0x23,0x3c,0x0b,0xb0,0x09,0x3c,0x07,0x01,0x23, -0x3c,0x0c,0xb0,0x09,0x3c,0x01,0xb0,0x01,0xac,0x20,0x00,0x00,0x27,0xbd,0xff,0xe0, -0xac,0xa0,0x00,0x00,0x35,0x6b,0x00,0x08,0x3c,0x01,0xb0,0x09,0xac,0x26,0x00,0x00, -0x34,0xe7,0x45,0x66,0xa5,0x42,0x00,0x00,0x35,0x8c,0x00,0x0c,0x24,0x02,0xcd,0xef, -0x3c,0x0d,0xb0,0x09,0x3c,0x08,0xcd,0xef,0x3c,0x0e,0xb0,0x09,0xad,0x67,0x00,0x00, -0xaf,0xb7,0x00,0x1c,0xa5,0x82,0x00,0x00,0xaf,0xb6,0x00,0x18,0xaf,0xb5,0x00,0x14, -0xaf,0xb4,0x00,0x10,0xaf,0xb3,0x00,0x0c,0xaf,0xb2,0x00,0x08,0xaf,0xb1,0x00,0x04, -0xaf,0xb0,0x00,0x00,0x35,0xad,0x00,0x10,0x35,0x08,0x01,0x22,0x35,0xce,0x00,0x14, -0x24,0x02,0x89,0xab,0x3c,0x0f,0xb0,0x09,0x3c,0x09,0x89,0xab,0x3c,0x10,0xb0,0x09, -0x3c,0x11,0xb0,0x09,0x3c,0x12,0xb0,0x09,0x3c,0x13,0xb0,0x09,0x3c,0x14,0xb0,0x09, -0x3c,0x15,0xb0,0x09,0x3c,0x16,0xb0,0x09,0x3c,0x17,0xb0,0x09,0xad,0xa8,0x00,0x00, -0x24,0x03,0xff,0xff,0xa5,0xc2,0x00,0x00,0x35,0xef,0x00,0x18,0x35,0x29,0xcd,0xee, -0x36,0x10,0x00,0x1c,0x36,0x31,0x00,0x20,0x36,0x52,0x00,0x24,0x36,0x73,0x00,0x28, -0x36,0x94,0x00,0x2c,0x36,0xb5,0x00,0x30,0x36,0xd6,0x00,0x34,0x36,0xf7,0x00,0x38, -0x24,0x02,0x45,0x67,0xad,0xe9,0x00,0x00,0xa6,0x02,0x00,0x00,0xae,0x23,0x00,0x00, -0x8f,0xb0,0x00,0x00,0xa6,0x43,0x00,0x00,0x8f,0xb1,0x00,0x04,0xae,0x63,0x00,0x00, -0x8f,0xb2,0x00,0x08,0xa6,0x83,0x00,0x00,0x8f,0xb3,0x00,0x0c,0xae,0xa3,0x00,0x00, -0x8f,0xb4,0x00,0x10,0xa6,0xc3,0x00,0x00,0x8f,0xb5,0x00,0x14,0xae,0xe3,0x00,0x00, -0x7b,0xb6,0x00,0xfc,0x3c,0x18,0xb0,0x09,0x37,0x18,0x00,0x3c,0xa7,0x03,0x00,0x00, -0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, -0x34,0x63,0x00,0x20,0x24,0x42,0x51,0x48,0xac,0x62,0x00,0x00,0x8c,0x83,0x00,0x34, -0x34,0x02,0xff,0xff,0x00,0x43,0x10,0x2a,0x14,0x40,0x01,0x04,0x00,0x80,0x28,0x21, -0x8c,0x86,0x00,0x08,0x24,0x02,0x00,0x03,0x10,0xc2,0x00,0xf7,0x00,0x00,0x00,0x00, -0x8c,0xa2,0x00,0x2c,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x4f,0x24,0x02,0x00,0x06, -0x3c,0x03,0xb0,0x05,0x34,0x63,0x04,0x50,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x42,0x00,0xff,0x14,0x40,0x00,0xdd,0xac,0xa2,0x00,0x2c,0x24,0x02,0x00,0x01, -0x10,0xc2,0x00,0xdc,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xc2,0x00,0xca, -0x00,0x00,0x00,0x00,0x8c,0xa7,0x00,0x04,0x24,0x02,0x00,0x02,0x10,0xe2,0x00,0xc0, -0x00,0x00,0x00,0x00,0x8c,0xa2,0x00,0x14,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x09, -0x24,0x02,0x00,0x01,0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x60,0x90,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x10,0x40,0x00,0x05,0xac,0xa2,0x00,0x14, -0x24,0x02,0x00,0x01,0xac,0xa2,0x00,0x00,0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x14, -0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00, -0x04,0x61,0x00,0x19,0x3c,0x02,0xb0,0x03,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2e, -0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x12, -0x3c,0x02,0xb0,0x03,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x42,0x90,0x43,0x00,0x00, -0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x0c,0x3c,0x02,0xb0,0x03,0x80,0xa2,0x00,0x50, -0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x08,0x3c,0x02,0xb0,0x03,0x14,0xc0,0x00,0x07, -0x34,0x42,0x00,0x3f,0x24,0x02,0x00,0x0e,0x24,0x03,0x00,0x01,0xac,0xa2,0x00,0x00, -0x03,0xe0,0x00,0x08,0xa0,0xa3,0x00,0x50,0x34,0x42,0x00,0x3f,0x90,0x44,0x00,0x00, -0x24,0x03,0x00,0x01,0x10,0x64,0x00,0x7f,0x3c,0x03,0xb0,0x05,0x80,0xa2,0x00,0x31, -0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0a,0x3c,0x02,0xb0,0x06,0x34,0x42,0x80,0x18, -0x8c,0x43,0x00,0x00,0x3c,0x04,0xf0,0x00,0x3c,0x02,0x80,0x00,0x00,0x64,0x18,0x24, -0x10,0x62,0x00,0x03,0x24,0x02,0x00,0x09,0x03,0xe0,0x00,0x08,0xac,0xa2,0x00,0x00, -0x8c,0xa2,0x00,0x40,0x00,0x00,0x00,0x00,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00, -0x10,0x60,0x00,0x09,0x3c,0x03,0xb0,0x03,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c, -0x8c,0x43,0x00,0x00,0x3c,0x04,0x00,0x02,0x00,0x64,0x18,0x24,0x14,0x60,0xff,0xf2, -0x24,0x02,0x00,0x10,0x3c,0x03,0xb0,0x03,0x34,0x63,0x02,0x01,0x90,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x80,0x10,0x40,0x00,0x0e,0x00,0x00,0x00,0x00, -0x8c,0xa3,0x00,0x0c,0x00,0x00,0x00,0x00,0xac,0xa3,0x00,0x10,0x3c,0x02,0xb0,0x03, -0x90,0x42,0x02,0x01,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x0f,0xac,0xa2,0x00,0x0c, -0x90,0xa3,0x00,0x0f,0x24,0x02,0x00,0x0d,0x3c,0x01,0xb0,0x03,0x08,0x00,0x14,0xb2, -0xa0,0x23,0x02,0x01,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x80,0x90,0x44,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x04,0x1e,0x00,0x00,0x03,0x1e,0x03,0x10,0x60,0x00,0x15, -0xa0,0xa4,0x00,0x44,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x0b,0x24,0x02,0x00,0x02, -0x10,0x62,0x00,0x03,0x24,0x03,0x00,0x0d,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, -0x8c,0xa2,0x00,0x0c,0xac,0xa3,0x00,0x00,0x24,0x03,0x00,0x04,0xac,0xa2,0x00,0x10, -0x03,0xe0,0x00,0x08,0xac,0xa3,0x00,0x0c,0x24,0x02,0x00,0x0d,0xac,0xa2,0x00,0x00, -0x24,0x03,0x00,0x04,0x24,0x02,0x00,0x06,0xac,0xa3,0x00,0x10,0x03,0xe0,0x00,0x08, -0xac,0xa2,0x00,0x0c,0x8c,0xa3,0x00,0x38,0x24,0x04,0x00,0x01,0x10,0x64,0x00,0x2d, -0x24,0x02,0x00,0x02,0x10,0x60,0x00,0x19,0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x10, -0x24,0x02,0x00,0x04,0x10,0x62,0x00,0x04,0x00,0x00,0x00,0x00,0xac,0xa0,0x00,0x38, -0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x00,0x10,0xe4,0x00,0x07,0x24,0x02,0x00,0x03, -0x80,0xa2,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x0b,0xac,0xa3,0x00,0x00, -0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x38,0x08,0x00,0x15,0x04,0xac,0xa2,0x00,0x00, -0x10,0xe4,0x00,0x02,0x24,0x02,0x00,0x03,0x24,0x02,0x00,0x0c,0xac,0xa2,0x00,0x00, -0x24,0x02,0x00,0x04,0x03,0xe0,0x00,0x08,0xac,0xa2,0x00,0x38,0x10,0xe4,0x00,0x0e, -0x3c,0x03,0xb0,0x06,0x34,0x63,0x80,0x24,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x42,0x00,0xff,0x10,0x40,0x00,0x06,0xac,0xa2,0x00,0x18,0x24,0x02,0x00,0x02, -0xac,0xa2,0x00,0x00,0xac,0xa0,0x00,0x18,0x08,0x00,0x15,0x0d,0x24,0x02,0x00,0x01, -0x08,0x00,0x15,0x1a,0xac,0xa0,0x00,0x00,0x24,0x02,0x00,0x03,0x08,0x00,0x15,0x1a, -0xac,0xa2,0x00,0x00,0x24,0x03,0x00,0x0b,0xac,0xa2,0x00,0x38,0x03,0xe0,0x00,0x08, -0xac,0xa3,0x00,0x00,0x34,0x63,0x02,0x2e,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x42,0x00,0x01,0x14,0x40,0xff,0x7d,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x42, -0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x60,0xff,0x78,0x00,0x00,0x00,0x00, -0x10,0xc0,0xff,0x81,0x24,0x02,0x00,0x0e,0x08,0x00,0x14,0xa7,0x00,0x00,0x00,0x00, -0x80,0xa2,0x00,0x30,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x3e,0x24,0x02,0x00,0x04, -0x08,0x00,0x14,0xb2,0x00,0x00,0x00,0x00,0x84,0xa2,0x00,0x20,0x00,0x00,0x00,0x00, -0x10,0x40,0xff,0x75,0x24,0x02,0x00,0x06,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e, -0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff, -0x00,0x60,0x10,0x21,0x14,0x40,0xff,0x2b,0xa4,0xa3,0x00,0x20,0x08,0x00,0x14,0xb2, -0x24,0x02,0x00,0x06,0x8c,0xa2,0x00,0x1c,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x66, -0x24,0x02,0x00,0x05,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c,0x8c,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x10,0x40,0xff,0x1b,0xac,0xa2,0x00,0x1c, -0x08,0x00,0x14,0xb2,0x24,0x02,0x00,0x05,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x42,0x30,0x42,0x00,0x01,0x14,0x40,0xff,0x56, -0x24,0x02,0x00,0x06,0x08,0x00,0x14,0x60,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x0a, -0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x00,0x27,0xbd,0xff,0xd8,0xaf,0xb0,0x00,0x10, -0x27,0x90,0x86,0x58,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18, -0x0c,0x00,0x29,0xd5,0xaf,0xb1,0x00,0x14,0xaf,0x90,0x8f,0xe0,0x48,0x02,0x00,0x00, -0x0c,0x00,0x13,0xf0,0x00,0x00,0x00,0x00,0x0c,0x00,0x18,0x1f,0x02,0x00,0x20,0x21, -0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x3a,0x94,0x43,0x00,0x00,0x00,0x00,0x00,0x00, -0xa3,0x83,0x8f,0xe4,0x0c,0x00,0x00,0x34,0x00,0x00,0x00,0x00,0x0c,0x00,0x13,0xfb, -0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x98,0x0c,0x00,0x27,0x59,0x00,0x00,0x00,0x00, -0x93,0x84,0x80,0x10,0x0c,0x00,0x21,0x3f,0x00,0x00,0x00,0x00,0x27,0x84,0x89,0x18, -0x0c,0x00,0x06,0xe5,0x00,0x00,0x00,0x00,0x0c,0x00,0x01,0x39,0x00,0x00,0x00,0x00, -0x27,0x84,0x84,0x40,0x0c,0x00,0x13,0xd9,0x00,0x00,0x00,0x00,0x27,0x82,0x89,0x4c, -0xaf,0x82,0x84,0x80,0x0c,0x00,0x00,0x5f,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, -0x34,0x63,0x01,0x08,0x3c,0x04,0xb0,0x09,0x3c,0x05,0xb0,0x09,0x8c,0x66,0x00,0x00, -0x34,0x84,0x01,0x68,0x34,0xa5,0x01,0x40,0x24,0x02,0xc8,0x80,0x24,0x03,0x00,0x0a, -0xa4,0x82,0x00,0x00,0xa4,0xa3,0x00,0x00,0x3c,0x04,0xb0,0x03,0x8c,0x82,0x00,0x00, -0x8f,0x85,0x84,0x40,0xaf,0x86,0x84,0x38,0x34,0x42,0x00,0x20,0xac,0x82,0x00,0x00, -0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x58,0x8c,0x43,0x00,0x00,0x2c,0xa4,0x00,0x11, -0x34,0x63,0x01,0x00,0xac,0x43,0x00,0x00,0x10,0x80,0xff,0xfa,0x3c,0x02,0xb0,0x03, -0x3c,0x03,0x80,0x01,0x00,0x05,0x10,0x80,0x24,0x63,0x02,0x00,0x00,0x43,0x10,0x21, -0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00, -0x27,0x84,0x84,0x98,0x0c,0x00,0x26,0x8e,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x40, -0x0c,0x00,0x14,0x52,0x00,0x00,0x00,0x00,0x93,0x83,0x81,0xf1,0x24,0x02,0x00,0x01, -0x10,0x62,0x00,0x08,0x00,0x00,0x00,0x00,0x8f,0x85,0x84,0x40,0x8f,0x82,0x84,0x74, -0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xaf,0x82,0x84,0x74,0x08,0x00,0x15,0x9d, -0x3c,0x02,0xb0,0x03,0x27,0x84,0x84,0x98,0x0c,0x00,0x27,0x0d,0x00,0x00,0x00,0x00, -0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x98,0x0c,0x00,0x28,0xdd, -0x00,0x00,0x00,0x00,0xa3,0x82,0x84,0x71,0x8f,0x82,0x84,0x74,0xaf,0x80,0x84,0x40, -0x24,0x42,0x00,0x01,0xaf,0x82,0x84,0x74,0x08,0x00,0x15,0x9c,0x00,0x00,0x28,0x21, -0x27,0x84,0x86,0x58,0x0c,0x00,0x19,0x5b,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff, -0x14,0x40,0x00,0x05,0x3c,0x03,0xb0,0x05,0xaf,0x80,0x84,0x40,0xaf,0x80,0x84,0x44, -0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00,0x34,0x63,0x04,0x50,0x90,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x6c,0x14,0x40,0x00,0x20, -0x24,0x02,0x00,0x01,0x8f,0x84,0x84,0x48,0x00,0x00,0x00,0x00,0x10,0x82,0x00,0x20, -0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x60,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x54,0x14,0x40,0x00,0x15,0x24,0x02,0x00,0x01, -0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x07,0x00,0x00,0x00,0x00,0x24,0x05,0x00,0x03, -0x24,0x02,0x00,0x01,0xaf,0x82,0x84,0x44,0xaf,0x85,0x84,0x40,0x08,0x00,0x15,0xb6, -0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00, -0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21, -0xa7,0x83,0x84,0x60,0x14,0x40,0xff,0xf1,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, -0xaf,0x82,0x84,0x44,0xaf,0x80,0x84,0x40,0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00, -0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x5c,0x14,0x40,0xff,0xf5,0x24,0x02,0x00,0x01, -0x08,0x00,0x15,0xe1,0x3c,0x03,0xb0,0x09,0x27,0x84,0x86,0x58,0x0c,0x00,0x1a,0xd1, -0x00,0x00,0x00,0x00,0x83,0x82,0x84,0x70,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xec, -0x24,0x02,0x00,0x02,0x3c,0x03,0xb0,0x05,0x34,0x63,0x04,0x50,0x90,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x6c,0x14,0x40,0xff,0xe4, -0x24,0x02,0x00,0x02,0x8f,0x84,0x84,0x48,0x24,0x02,0x00,0x01,0x10,0x82,0x00,0x12, -0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x04,0x00,0x00,0x00,0x00,0x24,0x05,0x00,0x04, -0x08,0x00,0x15,0xed,0x24,0x02,0x00,0x02,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e, -0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff, -0x00,0x60,0x10,0x21,0xa7,0x83,0x84,0x60,0x14,0x40,0xff,0xf4,0x00,0x00,0x00,0x00, -0x08,0x00,0x15,0xfc,0x24,0x02,0x00,0x02,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c, -0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x5c, -0x14,0x40,0xff,0xf7,0x00,0x00,0x00,0x00,0x08,0x00,0x16,0x1d,0x24,0x02,0x00,0x02, -0x27,0x84,0x89,0x18,0x0c,0x00,0x0b,0x55,0x00,0x00,0x00,0x00,0x8f,0x83,0x84,0x44, -0xaf,0x82,0x84,0x5c,0x38,0x64,0x00,0x02,0x00,0x04,0x18,0x0a,0xaf,0x83,0x84,0x44, -0x14,0x40,0xff,0xad,0x24,0x05,0x00,0x05,0x8f,0x82,0x89,0x58,0xaf,0x80,0x84,0x40, -0x10,0x40,0x00,0x02,0x24,0x04,0x00,0x01,0xaf,0x84,0x84,0x48,0x93,0x82,0x89,0x66, -0x00,0x00,0x00,0x00,0x10,0x40,0xff,0x6c,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05, -0x34,0x42,0x00,0x08,0x8c,0x43,0x00,0x00,0x3c,0x04,0x20,0x00,0x00,0x64,0x18,0x24, -0x10,0x60,0xff,0x65,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xa0, -0x8c,0x43,0x00,0x00,0x3c,0x04,0x80,0x00,0xaf,0x80,0x89,0x40,0x24,0x63,0x00,0x01, -0xac,0x43,0x00,0x00,0x3c,0x01,0xb0,0x05,0xac,0x24,0x00,0x08,0xaf,0x80,0x89,0x3c, -0xaf,0x80,0x89,0x44,0xaf,0x80,0x89,0x48,0xaf,0x80,0x89,0x54,0xaf,0x80,0x89,0x4c, -0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00,0x83,0x82,0x84,0x90,0x00,0x00,0x00,0x00, -0x10,0x40,0x00,0x02,0x24,0x02,0x00,0x20,0xaf,0x82,0x84,0x5c,0x8f,0x85,0x84,0x5c, -0x27,0x84,0x89,0x18,0x0c,0x00,0x0d,0x30,0x00,0x00,0x00,0x00,0x00,0x02,0x1e,0x00, -0xa3,0x82,0x84,0x70,0xaf,0x80,0x84,0x5c,0x10,0x60,0xff,0x8e,0x00,0x00,0x00,0x00, -0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21,0xa7,0x83,0x84,0x60, -0x10,0x40,0x00,0x04,0x24,0x04,0x00,0x02,0xaf,0x84,0x84,0x48,0x08,0x00,0x15,0xfd, -0x00,0x00,0x00,0x00,0x08,0x00,0x15,0xee,0x24,0x05,0x00,0x06,0x27,0x84,0x84,0x40, -0x27,0x85,0x89,0x18,0x0c,0x00,0x0d,0xfd,0x00,0x00,0x00,0x00,0x8f,0x82,0x84,0x64, -0xaf,0x80,0x84,0x6c,0x14,0x40,0x00,0x19,0x00,0x40,0x18,0x21,0x8f,0x82,0x84,0x68, -0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x15,0x24,0x02,0x00,0x02,0x8f,0x83,0x84,0x48, -0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x0b,0x3c,0x02,0x40,0x00,0x8f,0x83,0x84,0x44, -0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x02,0x24,0x05,0x00,0x03,0x24,0x05,0x00,0x06, -0xaf,0x85,0x84,0x40,0x24,0x04,0x00,0x03,0xaf,0x84,0x84,0x48,0x08,0x00,0x15,0xb6, -0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x14,0x3c,0x01,0xb0,0x05,0xac,0x22,0x00,0x00, -0xaf,0x80,0x84,0x40,0x08,0x00,0x16,0x96,0x24,0x04,0x00,0x03,0x10,0x60,0x00,0x10, -0x00,0x00,0x00,0x00,0x27,0x85,0x89,0x18,0x27,0x84,0x84,0x40,0x0c,0x00,0x0e,0x21, -0x00,0x00,0x00,0x00,0x8f,0x83,0x84,0x44,0x24,0x02,0x00,0x01,0xa3,0x80,0x84,0x70, -0xaf,0x80,0x84,0x48,0x10,0x62,0x00,0x02,0x24,0x05,0x00,0x03,0x24,0x05,0x00,0x04, -0xaf,0x85,0x84,0x40,0xaf,0x80,0x84,0x64,0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00, -0x83,0x82,0x84,0x90,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00, -0x27,0x84,0x89,0x18,0x0c,0x00,0x10,0x69,0x00,0x00,0x00,0x00,0x8f,0x82,0x84,0x44, -0xa3,0x80,0x84,0x70,0xaf,0x80,0x84,0x40,0xaf,0x80,0x84,0x48,0x14,0x40,0x00,0x03, -0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0xaf,0x82,0x84,0x44,0xaf,0x80,0x84,0x68, -0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x40,0x27,0x85,0x89,0x18, -0x0c,0x00,0x0e,0x21,0x00,0x00,0x00,0x00,0x8f,0x82,0x84,0x44,0xa3,0x80,0x84,0x70, -0xaf,0x80,0x84,0x40,0xaf,0x80,0x84,0x48,0x14,0x40,0xfe,0xeb,0x00,0x00,0x00,0x00, -0x24,0x02,0x00,0x02,0xaf,0x82,0x84,0x44,0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00, -0x27,0x84,0x89,0x18,0x0c,0x00,0x10,0x69,0x00,0x00,0x00,0x00,0x08,0x00,0x16,0xc6, -0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x98,0x0c,0x00,0x29,0x73,0x00,0x00,0x00,0x00, -0x08,0x00,0x15,0xc5,0x00,0x00,0x00,0x00,0x0c,0x00,0x24,0x05,0x00,0x00,0x00,0x00, -0x0c,0x00,0x26,0xff,0x00,0x00,0x00,0x00,0x0c,0x00,0x18,0x11,0x00,0x00,0x00,0x00, -0x93,0x83,0xbc,0x18,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x2b,0x3c,0x02,0xb0,0x03, -0x34,0x42,0x01,0x08,0x8c,0x44,0x00,0x00,0x8f,0x83,0xbc,0x10,0x8f,0x82,0xbc,0x14, -0x00,0x83,0x18,0x23,0x00,0x43,0x10,0x2b,0x10,0x40,0x00,0x23,0x3c,0x02,0xb0,0x03, -0x24,0x04,0x05,0xa0,0x34,0x42,0x01,0x18,0x8c,0x42,0x00,0x00,0x0c,0x00,0x06,0xd1, -0x00,0x00,0x00,0x00,0x24,0x04,0x05,0xa4,0x0c,0x00,0x06,0xd1,0x00,0x02,0x84,0x02, -0x30,0x51,0xff,0xff,0x24,0x04,0x05,0xa8,0x00,0x02,0x94,0x02,0x0c,0x00,0x06,0xd1, -0x3a,0x10,0xff,0xff,0x3a,0x31,0xff,0xff,0x30,0x42,0xff,0xff,0x2e,0x10,0x00,0x01, -0x2e,0x31,0x00,0x01,0x3a,0x52,0xff,0xff,0x02,0x11,0x80,0x25,0x2e,0x52,0x00,0x01, -0x38,0x42,0xff,0xff,0x02,0x12,0x80,0x25,0x2c,0x42,0x00,0x01,0x02,0x02,0x80,0x25, -0x16,0x00,0x00,0x02,0x24,0x04,0x00,0x02,0x00,0x00,0x20,0x21,0x0c,0x00,0x05,0x6e, -0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08,0x8c,0x43,0x00,0x00, -0x00,0x00,0x00,0x00,0xaf,0x83,0xbc,0x10,0x0c,0x00,0x01,0xe9,0x00,0x00,0x00,0x00, -0xaf,0x80,0x84,0x40,0xaf,0x80,0x84,0x74,0x08,0x00,0x15,0x9c,0x00,0x00,0x28,0x21, -0x27,0x90,0xb4,0x00,0x24,0x11,0x00,0x12,0x8e,0x04,0x00,0x00,0x00,0x00,0x00,0x00, -0x90,0x82,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x03,0x00,0x00,0x00,0x00, -0x0c,0x00,0x18,0xd0,0x00,0x00,0x00,0x00,0x26,0x31,0xff,0xff,0x06,0x21,0xff,0xf6, -0x26,0x10,0x00,0x04,0xaf,0x80,0x84,0x40,0x08,0x00,0x15,0xb7,0x00,0x00,0x28,0x21, -0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08,0x8c,0x44,0x00,0x00,0x8f,0x82,0x84,0x38, -0x00,0x04,0x19,0xc2,0x00,0x02,0x11,0xc2,0x10,0x62,0xff,0xf6,0x00,0x00,0x00,0x00, -0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x02,0x90,0x43,0x00,0x00,0x3c,0x12,0xb0,0x05, -0xaf,0x84,0x84,0x38,0x30,0x63,0x00,0xff,0x00,0x03,0x11,0x40,0x00,0x43,0x10,0x23, -0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0x02,0x99,0x00,0x00,0x00,0x88,0x21, -0x36,0x52,0x02,0x2c,0x27,0x90,0xb4,0x00,0x8e,0x04,0x00,0x00,0x00,0x00,0x00,0x00, -0x90,0x83,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x03,0x10,0x40,0x00,0x06, -0x30,0x62,0x00,0x1c,0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x8f,0x85,0x84,0x38, -0x0c,0x00,0x1e,0x94,0x02,0x60,0x30,0x21,0x8e,0x42,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x42,0x00,0xff,0x14,0x40,0xff,0xd7,0x00,0x00,0x00,0x00,0x26,0x31,0x00,0x01, -0x2a,0x22,0x00,0x13,0x14,0x40,0xff,0xec,0x26,0x10,0x00,0x04,0x08,0x00,0x17,0x21, -0x00,0x00,0x00,0x00,0x8f,0x84,0x84,0x4c,0x27,0x85,0x89,0x18,0x0c,0x00,0x17,0xa4, -0x00,0x00,0x00,0x00,0x8f,0x83,0x84,0x4c,0x24,0x02,0x00,0x04,0x14,0x62,0xfe,0xa5, -0x00,0x00,0x00,0x00,0x08,0x00,0x15,0xee,0x24,0x05,0x00,0x05,0x3c,0x02,0xb0,0x03, -0x34,0x42,0x00,0x3f,0x90,0x44,0x00,0x00,0x24,0x03,0x00,0x01,0x10,0x64,0x00,0x08, -0x00,0x00,0x00,0x00,0x27,0x84,0x89,0x18,0x0c,0x00,0x24,0x2c,0x00,0x00,0x00,0x00, -0x24,0x05,0x00,0x05,0xaf,0x85,0x84,0x40,0x08,0x00,0x15,0xb7,0x00,0x00,0x00,0x00, -0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x14,0x8c,0x44,0x00,0x00,0x0c,0x00,0x24,0x49, -0x00,0x00,0x00,0x00,0x08,0x00,0x17,0x65,0x24,0x05,0x00,0x05,0x8f,0x82,0x89,0x4c, -0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0d,0x00,0x00,0x00,0x00,0x8f,0x84,0xb4,0x40, -0xaf,0x80,0x89,0x4c,0x94,0x85,0x00,0x14,0x0c,0x00,0x1b,0x66,0x00,0x00,0x00,0x00, -0x93,0x82,0x8b,0x71,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x02,0x10,0x40,0x00,0x03, -0x00,0x00,0x00,0x00,0x0c,0x00,0x01,0x57,0x00,0x00,0x20,0x21,0x8f,0x84,0xb4,0x40, -0x0c,0x00,0x18,0xd0,0x00,0x00,0x00,0x00,0x08,0x00,0x17,0x21,0x00,0x00,0x00,0x00, -0x3c,0x02,0xff,0x90,0x27,0xbd,0xff,0xe8,0x00,0x80,0x18,0x21,0x34,0x42,0x00,0x01, -0x27,0x84,0x89,0x18,0x10,0x62,0x00,0x05,0xaf,0xbf,0x00,0x10,0x8f,0xbf,0x00,0x10, -0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x06,0xe5, -0x00,0x00,0x00,0x00,0x27,0x84,0x86,0x58,0x0c,0x00,0x18,0x1f,0x00,0x00,0x00,0x00, -0x27,0x84,0x84,0x40,0x0c,0x00,0x13,0xd9,0x00,0x00,0x00,0x00,0x08,0x00,0x17,0x8b, -0x00,0x00,0x00,0x00,0x8f,0x82,0x89,0x58,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05, -0x00,0x00,0x18,0x21,0x8f,0x82,0x84,0x48,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x02, -0x00,0x00,0x00,0x00,0x24,0x03,0x00,0x01,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21, -0x27,0xbd,0xff,0xe0,0x3c,0x06,0xb0,0x03,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, -0x34,0xc6,0x00,0x5f,0xaf,0xbf,0x00,0x18,0x90,0xc3,0x00,0x00,0x3c,0x07,0xb0,0x03, -0x34,0xe7,0x00,0x5d,0x34,0x63,0x00,0x01,0x3c,0x09,0xb0,0x03,0x24,0x02,0x00,0x01, -0xa0,0xc3,0x00,0x00,0x00,0x80,0x80,0x21,0xa0,0xe2,0x00,0x00,0x00,0xa0,0x88,0x21, -0x35,0x29,0x00,0x5e,0x00,0xe0,0x40,0x21,0x24,0x04,0x00,0x01,0x91,0x22,0x00,0x00, -0x91,0x03,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x83,0x00,0x03,0x30,0x42,0x00,0x01, -0x14,0x40,0xff,0xfa,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x04,0x12,0x02,0x00,0x2c, -0x24,0x05,0x0f,0x00,0x24,0x02,0x00,0x06,0x12,0x02,0x00,0x08,0x24,0x05,0x00,0x0f, -0x3c,0x02,0xb0,0x03,0x34,0x42,0x02,0x00,0xa0,0x50,0x00,0x00,0x8f,0xbf,0x00,0x18, -0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x24,0x04,0x0c,0x04, -0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x0f,0x24,0x04,0x0d,0x04,0x24,0x05,0x00,0x0f, -0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x0f,0x24,0x04,0x08,0x80,0x24,0x05,0x1e,0x00, -0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x0f,0x24,0x04,0x08,0x8c,0x24,0x05,0x0f,0x00, -0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x0f,0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0x30, -0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x02,0x24,0x04,0x08,0x2c,0x3c,0x05,0x00,0x30, -0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x02,0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0x30, -0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x02,0x24,0x04,0x08,0x3c,0x3c,0x05,0x00,0x30, -0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x02,0x08,0x00,0x17,0xc5,0x3c,0x02,0xb0,0x03, -0x24,0x04,0x08,0x8c,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x04,0x24,0x04,0x08,0x80, -0x24,0x05,0x1e,0x00,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x04,0x24,0x04,0x0c,0x04, -0x24,0x05,0x00,0x0f,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x04,0x24,0x04,0x0d,0x04, -0x24,0x05,0x00,0x0f,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x04,0x24,0x04,0x08,0x24, -0x3c,0x05,0x00,0x30,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x2c, -0x3c,0x05,0x00,0x30,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x34, -0x3c,0x05,0x00,0x30,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x02,0x3c,0x05,0x00,0x30, -0x24,0x06,0x00,0x03,0x0c,0x00,0x13,0x5f,0x24,0x04,0x08,0x3c,0x02,0x20,0x20,0x21, -0x24,0x05,0x00,0x14,0x0c,0x00,0x13,0xa4,0x24,0x06,0x01,0x07,0x08,0x00,0x17,0xc5, -0x3c,0x02,0xb0,0x03,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x73,0x90,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x02,0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00, -0xa3,0x80,0x81,0x58,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, -0xa3,0x82,0x81,0x58,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, -0x3c,0x02,0x80,0x00,0x00,0x80,0x70,0x21,0x34,0x63,0x00,0x20,0x24,0x42,0x60,0x7c, -0x3c,0x04,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0x84,0x00,0x30,0xad,0xc0,0x02,0xb8, -0x8c,0x83,0x00,0x00,0x24,0x02,0x00,0xff,0xa5,0xc0,0x00,0x0a,0x00,0x00,0x30,0x21, -0xa7,0x82,0x8f,0xf0,0x27,0x88,0x90,0x00,0xa5,0xc3,0x00,0x08,0x3c,0x07,0xb0,0x08, -0x30,0xc2,0xff,0xff,0x00,0x02,0x20,0xc0,0x24,0xc3,0x00,0x01,0x00,0x82,0x10,0x21, -0x00,0x60,0x30,0x21,0x00,0x02,0x10,0x80,0x30,0x63,0xff,0xff,0x00,0x48,0x10,0x21, -0x00,0x87,0x20,0x21,0x28,0xc5,0x00,0xff,0xac,0x83,0x00,0x00,0x14,0xa0,0xff,0xf4, -0xa4,0x43,0x00,0x00,0x3c,0x02,0xb0,0x08,0x34,0x03,0xff,0xff,0x25,0xc4,0x00,0x0c, -0x24,0x0a,0x00,0x02,0x34,0x42,0x07,0xf8,0x3c,0x06,0xb0,0x03,0xa7,0x83,0xb3,0xdc, -0xac,0x43,0x00,0x00,0xaf,0x84,0xb4,0x00,0x34,0xc6,0x00,0x64,0xa0,0x8a,0x00,0x18, -0x94,0xc5,0x00,0x00,0x8f,0x82,0xb4,0x00,0x25,0xc4,0x00,0x30,0x24,0x08,0x00,0x03, -0x3c,0x03,0xb0,0x03,0xa0,0x45,0x00,0x21,0x34,0x63,0x00,0x66,0xaf,0x84,0xb4,0x04, -0xa0,0x88,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xb4,0x04,0x25,0xc4,0x00,0x54, -0x25,0xc7,0x00,0x78,0xa0,0x45,0x00,0x21,0xaf,0x84,0xb4,0x08,0xa0,0x88,0x00,0x18, -0x94,0x65,0x00,0x00,0x8f,0x82,0xb4,0x08,0x25,0xc8,0x00,0x9c,0x24,0x09,0x00,0x01, -0xa0,0x45,0x00,0x21,0xaf,0x87,0xb4,0x0c,0xa0,0xea,0x00,0x18,0x94,0xc4,0x00,0x00, -0x8f,0x82,0xb4,0x0c,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x62,0xa0,0x44,0x00,0x21, -0xaf,0x88,0xb4,0x10,0xa1,0x09,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xb4,0x10, -0x25,0xc4,0x00,0xc0,0x3c,0x06,0xb0,0x03,0xa0,0x45,0x00,0x21,0xaf,0x84,0xb4,0x14, -0xa0,0x89,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xb4,0x14,0x25,0xc4,0x00,0xe4, -0x34,0xc6,0x00,0x60,0xa0,0x45,0x00,0x21,0xaf,0x84,0xb4,0x18,0xa0,0x80,0x00,0x18, -0x94,0xc5,0x00,0x00,0x8f,0x82,0xb4,0x18,0x25,0xc3,0x01,0x08,0x25,0xc7,0x01,0x2c, -0xa0,0x45,0x00,0x21,0xaf,0x83,0xb4,0x1c,0xa0,0x60,0x00,0x18,0x94,0xc8,0x00,0x00, -0x8f,0x82,0xb4,0x1c,0x25,0xc4,0x01,0x50,0x25,0xc5,0x01,0x74,0xa0,0x48,0x00,0x21, -0x25,0xc6,0x01,0x98,0x25,0xc9,0x01,0xbc,0x25,0xca,0x01,0xe0,0x25,0xcb,0x02,0x04, -0x25,0xcc,0x02,0x28,0x25,0xcd,0x02,0x4c,0x24,0x02,0x00,0x10,0x3c,0x03,0xb0,0x03, -0xaf,0x87,0xb4,0x20,0x34,0x63,0x00,0x38,0xa0,0xe0,0x00,0x18,0xaf,0x84,0xb4,0x24, -0xa0,0x80,0x00,0x18,0xaf,0x85,0xb4,0x28,0xa0,0xa0,0x00,0x18,0xaf,0x86,0xb4,0x2c, -0xa0,0xc0,0x00,0x18,0xaf,0x89,0xb4,0x30,0xa1,0x20,0x00,0x18,0xaf,0x8a,0xb4,0x34, -0xa1,0x40,0x00,0x18,0xaf,0x8b,0xb4,0x38,0xa1,0x60,0x00,0x18,0xaf,0x8c,0xb4,0x3c, -0xa1,0x80,0x00,0x18,0xaf,0x8d,0xb4,0x40,0xa1,0xa2,0x00,0x18,0x94,0x64,0x00,0x00, -0x8f,0x82,0xb4,0x40,0x25,0xc5,0x02,0x70,0x3c,0x03,0xb0,0x03,0xa0,0x44,0x00,0x21, -0x24,0x02,0x00,0x11,0xaf,0x85,0xb4,0x44,0x34,0x63,0x00,0x6e,0xa0,0xa2,0x00,0x18, -0x94,0x64,0x00,0x00,0x8f,0x82,0xb4,0x44,0x25,0xc5,0x02,0x94,0x3c,0x03,0xb0,0x03, -0xa0,0x44,0x00,0x21,0x24,0x02,0x00,0x12,0xaf,0x85,0xb4,0x48,0x34,0x63,0x00,0x6c, -0xa0,0xa2,0x00,0x18,0x94,0x64,0x00,0x00,0x8f,0x82,0xb4,0x48,0x24,0x05,0xff,0xff, -0x24,0x07,0x00,0x01,0xa0,0x44,0x00,0x21,0x24,0x06,0x00,0x12,0x27,0x84,0xb4,0x00, -0x8c,0x82,0x00,0x00,0x24,0xc6,0xff,0xff,0xa0,0x40,0x00,0x04,0x8c,0x83,0x00,0x00, -0xa4,0x45,0x00,0x00,0xa4,0x45,0x00,0x02,0xa0,0x60,0x00,0x0a,0x8c,0x82,0x00,0x00, -0xa4,0x65,0x00,0x06,0xa4,0x65,0x00,0x08,0xa0,0x40,0x00,0x10,0x8c,0x83,0x00,0x00, -0xa4,0x45,0x00,0x0c,0xa4,0x45,0x00,0x0e,0xa0,0x60,0x00,0x12,0x8c,0x82,0x00,0x00, -0x00,0x00,0x00,0x00,0xa0,0x40,0x00,0x16,0x8c,0x83,0x00,0x00,0xa4,0x45,0x00,0x14, -0xa0,0x67,0x00,0x17,0x8c,0x82,0x00,0x00,0x24,0x84,0x00,0x04,0xa0,0x40,0x00,0x20, -0x04,0xc1,0xff,0xe7,0xac,0x40,0x00,0x1c,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, -0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00,0x34,0x42,0x00,0x20,0x24,0x63,0x63,0x40, -0xac,0x43,0x00,0x00,0x90,0x82,0x00,0x10,0x00,0x80,0x60,0x21,0x10,0x40,0x00,0x56, -0x00,0x00,0x70,0x21,0x97,0x82,0x8f,0xf0,0x94,0x8a,0x00,0x0c,0x27,0x87,0x90,0x00, -0x00,0x02,0x40,0xc0,0x01,0x02,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x47,0x10,0x21, -0x90,0x8b,0x00,0x18,0xa4,0x4a,0x00,0x00,0x94,0x83,0x00,0x0e,0x39,0x64,0x00,0x10, -0x2c,0x84,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x34,0x85,0x00,0x02, -0x39,0x63,0x00,0x11,0x00,0x83,0x28,0x0b,0x34,0xa3,0x00,0x08,0x39,0x64,0x00,0x12, -0x00,0x02,0x10,0x80,0x00,0xa4,0x18,0x0b,0x00,0x47,0x10,0x21,0x94,0x49,0x00,0x04, -0x34,0x64,0x00,0x20,0x00,0x6b,0x20,0x0b,0x34,0x83,0x00,0x40,0x39,0x62,0x00,0x01, -0x00,0x82,0x18,0x0b,0x00,0x09,0x30,0xc0,0x34,0x64,0x00,0x80,0x00,0xc9,0x28,0x21, -0x39,0x62,0x00,0x02,0x00,0x60,0x68,0x21,0x00,0x82,0x68,0x0a,0x00,0x05,0x28,0x80, -0x3c,0x02,0xb0,0x08,0x00,0xa7,0x28,0x21,0x00,0xc2,0x30,0x21,0x01,0x02,0x40,0x21, -0x34,0x03,0xff,0xff,0x35,0xa4,0x01,0x00,0x39,0x62,0x00,0x03,0x2d,0x67,0x00,0x13, -0xad,0x0a,0x00,0x00,0xa4,0xa3,0x00,0x00,0xac,0xc3,0x00,0x00,0xa7,0x89,0x8f,0xf0, -0x10,0xe0,0x00,0x0f,0x00,0x82,0x68,0x0a,0x3c,0x03,0x80,0x01,0x00,0x0b,0x10,0x80, -0x24,0x63,0x02,0x44,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x60, -0x94,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x00,0x00,0x02,0x74,0x03, -0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x3a,0x94,0x44,0x00,0x00,0x93,0x83,0x8f,0xe4, -0x91,0x82,0x00,0x21,0x01,0xc4,0x20,0x21,0x91,0x85,0x00,0x10,0x00,0x04,0x24,0x00, -0x00,0x62,0x18,0x21,0x00,0x04,0x74,0x03,0x00,0x6e,0x18,0x23,0x00,0x65,0x10,0x2a, -0x00,0xa2,0x18,0x0a,0x00,0x0d,0x24,0x00,0x3c,0x02,0xb0,0x06,0x24,0x05,0xff,0xff, -0x00,0x64,0x18,0x25,0x34,0x42,0x80,0x20,0xac,0x43,0x00,0x00,0xa5,0x85,0x00,0x0e, -0xa1,0x80,0x00,0x10,0xa5,0x85,0x00,0x0c,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, -0x3c,0x03,0xb0,0x03,0x08,0x00,0x19,0x14,0x34,0x63,0x00,0x62,0x3c,0x03,0xb0,0x03, -0x08,0x00,0x19,0x14,0x34,0x63,0x00,0x64,0x3c,0x03,0xb0,0x03,0x08,0x00,0x19,0x14, -0x34,0x63,0x00,0x66,0x3c,0x03,0xb0,0x03,0x08,0x00,0x19,0x14,0x34,0x63,0x00,0x38, -0x3c,0x03,0xb0,0x03,0x08,0x00,0x19,0x14,0x34,0x63,0x00,0x6e,0x3c,0x03,0xb0,0x03, -0x08,0x00,0x19,0x14,0x34,0x63,0x00,0x6c,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, -0x34,0x63,0x00,0x20,0x24,0x42,0x65,0x08,0x00,0x05,0x28,0x40,0xac,0x62,0x00,0x00, -0x00,0xa6,0x28,0x21,0x2c,0xe2,0x00,0x10,0x14,0x80,0x00,0x06,0x00,0x00,0x18,0x21, -0x10,0x40,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0xe0,0x18,0x21,0x03,0xe0,0x00,0x08, -0x00,0x60,0x10,0x21,0x24,0x02,0x00,0x20,0x10,0xe2,0x00,0x06,0x2c,0xe4,0x00,0x10, -0x24,0xa2,0x00,0x01,0x10,0x80,0xff,0xf9,0x00,0x02,0x11,0x00,0x08,0x00,0x19,0x4f, -0x00,0x47,0x18,0x21,0x08,0x00,0x19,0x4f,0x24,0xa3,0x00,0x50,0x27,0xbd,0xff,0xc8, -0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x30, -0xaf,0xb7,0x00,0x2c,0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20, -0xaf,0xb0,0x00,0x10,0x00,0x80,0x88,0x21,0x84,0x84,0x00,0x08,0x3c,0x05,0xb0,0x03, -0x3c,0x02,0x80,0x00,0x34,0xa5,0x00,0x20,0x24,0x42,0x65,0x6c,0x3c,0x03,0xb0,0x06, -0x00,0x04,0x20,0x80,0xac,0xa2,0x00,0x00,0x00,0x83,0x20,0x21,0x3c,0x06,0xb0,0x06, -0x8c,0x82,0x00,0x00,0x34,0xc6,0x80,0x24,0x8c,0x88,0x00,0x00,0x8c,0xc4,0x00,0x00, -0x96,0x25,0x00,0x08,0x30,0x52,0xff,0xff,0x00,0x08,0x44,0x02,0x34,0x84,0x01,0x00, -0x3c,0x02,0xb0,0x00,0x00,0x08,0x18,0xc0,0x00,0x12,0x3a,0x00,0xac,0xc4,0x00,0x00, -0x00,0xe2,0x38,0x21,0xae,0x32,0x02,0xb8,0x00,0x68,0x18,0x21,0x24,0xa5,0x00,0x02, -0x8c,0xf6,0x00,0x00,0x30,0xa5,0x01,0xff,0x8c,0xf4,0x00,0x04,0x27,0x86,0x90,0x00, -0x00,0x03,0x18,0x80,0x00,0x12,0x98,0xc0,0xa6,0x25,0x00,0x08,0x00,0x66,0x18,0x21, -0x02,0x72,0x10,0x21,0x94,0x65,0x00,0x00,0x00,0x02,0x48,0x80,0x01,0x26,0x30,0x21, -0x24,0x02,0xff,0xff,0x00,0x14,0x1a,0x02,0x27,0x84,0x90,0x10,0xa4,0xc2,0x00,0x02, -0x30,0x63,0x00,0x1f,0x24,0x02,0x00,0x10,0x01,0x24,0x20,0x21,0xa4,0xc8,0x00,0x04, -0x8c,0xf0,0x00,0x08,0xa6,0x23,0x00,0x06,0xa6,0x25,0x00,0x0a,0xa0,0x82,0x00,0x06, -0x86,0x25,0x00,0x06,0x27,0x82,0x90,0x04,0x01,0x22,0x10,0x21,0x24,0x03,0x00,0x13, -0x10,0xa3,0x00,0xee,0xac,0x47,0x00,0x18,0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x00, -0xa6,0x20,0x00,0x02,0x3c,0x02,0xb0,0x03,0x90,0x64,0x00,0x00,0x34,0x42,0x01,0x08, -0x8c,0x45,0x00,0x00,0x00,0x10,0x1b,0xc2,0x00,0x04,0x20,0x82,0x30,0x63,0x00,0x01, -0xac,0xc5,0x00,0x08,0x10,0x60,0x00,0xc7,0x30,0x97,0x00,0x01,0x00,0x10,0x16,0x82, -0x30,0x46,0x00,0x01,0x00,0x10,0x12,0x02,0x00,0x10,0x19,0xc2,0x00,0x10,0x26,0x02, -0x00,0x10,0x2e,0x42,0x30,0x48,0x00,0x7f,0x24,0x02,0x00,0x01,0x30,0x75,0x00,0x01, -0x30,0x84,0x00,0x01,0x10,0xc2,0x00,0xb3,0x30,0xa3,0x00,0x01,0x00,0x60,0x28,0x21, -0x0c,0x00,0x19,0x42,0x01,0x00,0x38,0x21,0x02,0x72,0x18,0x21,0x00,0x03,0x18,0x80, -0x2c,0x46,0x00,0x54,0x27,0x85,0x90,0x10,0x27,0x84,0x90,0x08,0x00,0x06,0x10,0x0a, -0x00,0x65,0x28,0x21,0x26,0xa6,0x00,0x02,0x00,0x64,0x18,0x21,0xa0,0xa2,0x00,0x02, -0xa0,0x66,0x00,0x06,0xa0,0x62,0x00,0x07,0xa0,0xa2,0x00,0x01,0x02,0x72,0x28,0x21, -0x00,0x05,0x28,0x80,0x27,0x82,0x90,0x04,0x00,0xa2,0x58,0x21,0x8d,0x64,0x00,0x18, -0x00,0x10,0x15,0xc2,0x30,0x42,0x00,0x01,0x8c,0x83,0x00,0x0c,0x27,0x84,0x90,0x20, -0x00,0xa4,0x48,0x21,0xa6,0x22,0x00,0x00,0xa6,0x36,0x00,0x04,0x8d,0x26,0x00,0x00, -0x00,0x03,0x19,0x42,0x3c,0x02,0xff,0xef,0x34,0x42,0xff,0xff,0x30,0x63,0x00,0x01, -0x00,0xc2,0x40,0x24,0x00,0x03,0x1d,0x00,0x01,0x03,0x40,0x25,0x00,0x08,0x15,0x02, -0x00,0x14,0x19,0x82,0x00,0x14,0x25,0x82,0x00,0x10,0x34,0x42,0x00,0x10,0x3c,0x82, -0x00,0x10,0x2c,0x02,0x30,0x42,0x00,0x01,0x30,0xcd,0x00,0x01,0x30,0x6c,0x00,0x01, -0x30,0xe6,0x00,0x01,0x30,0x8a,0x00,0x03,0x32,0x94,0x00,0x07,0x30,0xa5,0x00,0x01, -0xad,0x28,0x00,0x00,0x10,0x40,0x00,0x0b,0x32,0x07,0x00,0x7f,0x8d,0x64,0x00,0x18, -0x3c,0x03,0xff,0xf0,0x34,0x63,0xff,0xff,0x8c,0x82,0x00,0x0c,0x01,0x03,0x18,0x24, -0x00,0x02,0x13,0x82,0x30,0x42,0x00,0x0f,0x00,0x02,0x14,0x00,0x00,0x62,0x18,0x25, -0xad,0x23,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xc2,0x00,0x6a,0x00,0x00,0x00,0x00, -0x15,0x80,0x00,0x03,0x00,0x00,0x00,0x00,0x15,0x40,0x00,0x5b,0x24,0x02,0x00,0x01, -0x96,0x22,0x00,0x04,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x04,0xa6,0x22,0x00,0x04, -0x00,0xa0,0x20,0x21,0x0c,0x00,0x19,0x42,0x01,0xa0,0x28,0x21,0x02,0x72,0x18,0x21, -0x00,0x03,0x40,0x80,0x2c,0x45,0x00,0x54,0x27,0x84,0x90,0x10,0x01,0x04,0x20,0x21, -0x00,0x05,0x10,0x0a,0xa0,0x82,0x00,0x00,0xa0,0x80,0x00,0x04,0xa0,0x80,0x00,0x05, -0x96,0x23,0x00,0x04,0x27,0x82,0x90,0x00,0x01,0x02,0x10,0x21,0xa4,0x43,0x00,0x06, -0x27,0x82,0x90,0x04,0x92,0x26,0x00,0x01,0x01,0x02,0x10,0x21,0x8c,0x45,0x00,0x18, -0x27,0x83,0x90,0x20,0x01,0x03,0x18,0x21,0xa0,0x60,0x00,0x00,0xa0,0x86,0x00,0x07, -0x94,0xa2,0x00,0x10,0x24,0x03,0x00,0x04,0x30,0x42,0x00,0x0f,0x10,0x43,0x00,0x36, -0x24,0xa5,0x00,0x10,0x94,0xa3,0x00,0x16,0x27,0x87,0x90,0x18,0x01,0x07,0x10,0x21, -0xa4,0x43,0x00,0x02,0x94,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01, -0x14,0x40,0x00,0x24,0x02,0x72,0x20,0x21,0x94,0xa2,0x00,0x00,0x24,0x03,0x00,0xa4, -0x30,0x42,0x00,0xff,0x10,0x43,0x00,0x1f,0x00,0x00,0x00,0x00,0x94,0xa2,0x00,0x00, -0x24,0x03,0x00,0x88,0x30,0x42,0x00,0x88,0x10,0x43,0x00,0x14,0x02,0x72,0x18,0x21, -0x27,0x84,0x90,0x20,0x00,0x03,0x18,0x80,0x00,0x64,0x18,0x21,0x8c,0x62,0x00,0x00, -0x3c,0x04,0x00,0x80,0x00,0x44,0x10,0x25,0xac,0x62,0x00,0x00,0x02,0x72,0x10,0x21, -0x00,0x02,0x10,0x80,0x00,0x47,0x10,0x21,0xa0,0x54,0x00,0x00,0x8f,0xbf,0x00,0x30, -0x7b,0xb6,0x01,0x7c,0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc, -0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0x94,0xa2,0x00,0x18, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x60,0x10,0x40,0xff,0xe9,0x02,0x72,0x18,0x21, -0x02,0x72,0x20,0x21,0x27,0x82,0x90,0x20,0x00,0x04,0x20,0x80,0x00,0x82,0x20,0x21, -0x8c,0x83,0x00,0x00,0x3c,0x02,0xff,0x7f,0x34,0x42,0xff,0xff,0x00,0x62,0x18,0x24, -0x08,0x00,0x1a,0x37,0xac,0x83,0x00,0x00,0x27,0x87,0x90,0x18,0x01,0x07,0x10,0x21, -0x08,0x00,0x1a,0x21,0xa4,0x40,0x00,0x02,0x11,0x42,0x00,0x07,0x00,0x00,0x00,0x00, -0x2d,0x42,0x00,0x02,0x14,0x40,0xff,0xa7,0x00,0xa0,0x20,0x21,0x96,0x22,0x00,0x04, -0x08,0x00,0x19,0xff,0x24,0x42,0x00,0x0c,0x96,0x22,0x00,0x04,0x08,0x00,0x19,0xff, -0x24,0x42,0x00,0x08,0x16,0xe6,0xff,0x96,0x3c,0x02,0xff,0xfb,0x8d,0x63,0x00,0x18, -0x34,0x42,0xff,0xff,0x02,0x02,0x10,0x24,0xac,0x62,0x00,0x08,0x08,0x00,0x19,0xf8, -0x00,0x00,0x30,0x21,0x16,0xe6,0xff,0x4e,0x00,0x60,0x28,0x21,0x3c,0x02,0xfb,0xff, -0x34,0x42,0xff,0xff,0x02,0x02,0x10,0x24,0xac,0xe2,0x00,0x08,0x08,0x00,0x19,0xb7, -0x00,0x00,0x30,0x21,0x93,0x87,0xbb,0x14,0x00,0x10,0x1e,0x42,0x00,0x10,0x26,0x82, -0x27,0x82,0x90,0x08,0x2c,0xe5,0x00,0x0c,0x01,0x22,0x48,0x21,0x30,0x63,0x00,0x01, -0x30,0x86,0x00,0x01,0x14,0xa0,0x00,0x06,0x00,0xe0,0x40,0x21,0x00,0x03,0x10,0x40, -0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0xe2,0x10,0x21,0x24,0x48,0x00,0x04, -0x02,0x72,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x84,0x90,0x10,0x27,0x83,0x90,0x08, -0x00,0x44,0x20,0x21,0x00,0x43,0x10,0x21,0xa1,0x28,0x00,0x07,0xa0,0x40,0x00,0x06, -0xa0,0x80,0x00,0x02,0x08,0x00,0x19,0xc7,0xa0,0x80,0x00,0x01,0x24,0x02,0x00,0x01, -0xa6,0x22,0x00,0x02,0x0c,0x00,0x01,0xc2,0x00,0xe0,0x20,0x21,0x08,0x00,0x1a,0x3b, -0x00,0x00,0x00,0x00,0x30,0xa7,0xff,0xff,0x00,0x07,0x18,0xc0,0x00,0x67,0x18,0x21, -0x3c,0x06,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x6a,0x44,0x27,0x85,0x90,0x10, -0x00,0x03,0x18,0x80,0x34,0xc6,0x00,0x20,0x00,0x65,0x18,0x21,0xac,0xc2,0x00,0x00, -0x80,0x62,0x00,0x07,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x29,0x00,0x80,0x28,0x21, -0x90,0x82,0x00,0x16,0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02,0x30,0x43,0x00,0x01, -0x14,0x60,0x00,0x02,0xa0,0x82,0x00,0x16,0xa0,0x80,0x00,0x17,0x90,0xa2,0x00,0x04, -0x3c,0x03,0xb0,0x03,0x27,0x86,0x90,0x00,0x14,0x40,0x00,0x06,0x34,0x63,0x00,0x20, -0x24,0x02,0x00,0x01,0xa0,0xa2,0x00,0x04,0xa4,0xa7,0x00,0x02,0x03,0xe0,0x00,0x08, -0xa4,0xa7,0x00,0x00,0x94,0xa4,0x00,0x02,0x3c,0x02,0x80,0x01,0x24,0x42,0x82,0x6c, -0xac,0x62,0x00,0x00,0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80, -0x00,0x66,0x18,0x21,0x94,0x62,0x00,0x04,0xa4,0x67,0x00,0x02,0x3c,0x03,0xb0,0x08, -0x00,0x02,0x20,0xc0,0x00,0x82,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21, -0x00,0x83,0x20,0x21,0xa4,0x47,0x00,0x00,0xac,0x87,0x00,0x00,0x90,0xa2,0x00,0x04, -0xa4,0xa7,0x00,0x02,0x24,0x42,0x00,0x01,0x03,0xe0,0x00,0x08,0xa0,0xa2,0x00,0x04, -0x90,0x82,0x00,0x16,0x24,0x85,0x00,0x06,0x34,0x42,0x00,0x01,0x30,0x43,0x00,0x02, -0x14,0x60,0xff,0xda,0xa0,0x82,0x00,0x16,0x24,0x02,0x00,0x01,0x08,0x00,0x1a,0xa7, -0xa0,0x82,0x00,0x17,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x00,0x80,0x38,0x21, -0x84,0x84,0x00,0x02,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x3c,0x0a,0xb0,0x06, -0x34,0x63,0x00,0x20,0x24,0x42,0x6b,0x44,0x3c,0x0b,0xb0,0x08,0x27,0x89,0x90,0x00, -0x34,0x0c,0xff,0xff,0x35,0x4a,0x80,0x20,0x10,0x80,0x00,0x30,0xac,0x62,0x00,0x00, -0x97,0x82,0x8f,0xf0,0x94,0xe6,0x02,0xba,0x00,0x02,0x18,0xc0,0x00,0x6b,0x28,0x21, -0xac,0xa6,0x00,0x00,0x8c,0xe4,0x02,0xb8,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80, -0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x21, -0x94,0x48,0x00,0x04,0x00,0x69,0x18,0x21,0xa4,0x66,0x00,0x00,0x00,0x08,0x28,0xc0, -0x00,0xab,0x10,0x21,0xac,0x4c,0x00,0x00,0x8c,0xe4,0x02,0xb8,0x27,0x82,0x90,0x04, -0x00,0xa8,0x28,0x21,0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80, -0x00,0x62,0x10,0x21,0x8c,0x46,0x00,0x18,0x27,0x84,0x90,0x10,0x00,0x64,0x18,0x21, -0x8c,0xc2,0x00,0x00,0x80,0x67,0x00,0x06,0x00,0x05,0x28,0x80,0x30,0x42,0xff,0xff, -0x00,0x47,0x10,0x21,0x30,0x43,0x00,0xff,0x00,0x03,0x18,0x2b,0x00,0x02,0x12,0x02, -0x00,0x43,0x10,0x21,0x3c,0x04,0x00,0x04,0x00,0xa9,0x28,0x21,0x00,0x44,0x10,0x25, -0xa4,0xac,0x00,0x00,0xad,0x42,0x00,0x00,0xa7,0x88,0x8f,0xf0,0x8f,0xbf,0x00,0x10, -0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x84,0xe3,0x00,0x06, -0x27,0x82,0xb4,0x00,0x94,0xe5,0x02,0xba,0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21, -0x8c,0x64,0x00,0x00,0x0c,0x00,0x1a,0x91,0x00,0x00,0x00,0x00,0x08,0x00,0x1b,0x0b, -0x00,0x00,0x00,0x00,0x94,0x88,0x00,0x00,0x00,0x80,0x58,0x21,0x27,0x8a,0x90,0x00, -0x00,0x08,0x18,0xc0,0x00,0x68,0x18,0x21,0x3c,0x04,0xb0,0x03,0x00,0x03,0x18,0x80, -0x3c,0x02,0x80,0x00,0x00,0x6a,0x18,0x21,0x34,0x84,0x00,0x20,0x24,0x42,0x6c,0x64, -0x30,0xa5,0xff,0xff,0xac,0x82,0x00,0x00,0x94,0x67,0x00,0x02,0x11,0x05,0x00,0x35, -0x24,0x04,0x00,0x01,0x91,0x66,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x86,0x10,0x2a, -0x10,0x40,0x00,0x10,0x00,0xc0,0x48,0x21,0x3c,0x0d,0xb0,0x03,0x01,0x40,0x60,0x21, -0x35,0xad,0x00,0x20,0x10,0xe5,0x00,0x0d,0x24,0x84,0x00,0x01,0x00,0x07,0x10,0xc0, -0x00,0x47,0x10,0x21,0x00,0x02,0x10,0x80,0x01,0x20,0x30,0x21,0x00,0x4a,0x10,0x21, -0x00,0x86,0x18,0x2a,0x00,0xe0,0x40,0x21,0x94,0x47,0x00,0x02,0x14,0x60,0xff,0xf5, -0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x10,0x21,0x00,0x08,0x20,0xc0, -0x00,0x88,0x20,0x21,0x24,0xc2,0xff,0xff,0x00,0x04,0x20,0x80,0xa1,0x62,0x00,0x04, -0x00,0x8c,0x20,0x21,0x94,0x83,0x00,0x04,0x00,0x07,0x10,0xc0,0x00,0x47,0x10,0x21, -0x00,0x02,0x10,0x80,0x00,0x4c,0x10,0x21,0x00,0x03,0x28,0xc0,0x94,0x46,0x00,0x02, -0x00,0xa3,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x6c,0x18,0x21,0xa4,0x66,0x00,0x00, -0xa4,0x86,0x00,0x02,0x95,0x64,0x00,0x02,0x3c,0x03,0xb0,0x08,0x3c,0x02,0x80,0x01, -0x00,0xa3,0x28,0x21,0x24,0x42,0x82,0x6c,0xad,0xa2,0x00,0x00,0x10,0x87,0x00,0x03, -0xac,0xa6,0x00,0x00,0x03,0xe0,0x00,0x08,0x24,0x02,0x00,0x01,0x08,0x00,0x1b,0x59, -0xa5,0x68,0x00,0x02,0x91,0x62,0x00,0x04,0xa5,0x67,0x00,0x00,0x24,0x42,0xff,0xff, -0x30,0x43,0x00,0xff,0x14,0x60,0xff,0xf7,0xa1,0x62,0x00,0x04,0x24,0x02,0xff,0xff, -0x08,0x00,0x1b,0x59,0xa5,0x62,0x00,0x02,0x00,0x05,0x40,0xc0,0x01,0x05,0x30,0x21, -0x27,0xbd,0xff,0xd8,0x00,0x06,0x30,0x80,0x27,0x82,0x90,0x04,0xaf,0xb2,0x00,0x18, -0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb0,0x00,0x10, -0x00,0xc2,0x10,0x21,0x8c,0x47,0x00,0x18,0x00,0xa0,0x90,0x21,0x3c,0x02,0x80,0x00, -0x3c,0x05,0xb0,0x03,0x34,0xa5,0x00,0x20,0x24,0x42,0x6d,0x98,0xac,0xa2,0x00,0x00, -0x27,0x83,0x90,0x10,0x00,0xc3,0x30,0x21,0x8c,0xe2,0x00,0x00,0x80,0xc5,0x00,0x06, -0x00,0x80,0x88,0x21,0x30,0x42,0xff,0xff,0x00,0x45,0x10,0x21,0x30,0x43,0x00,0xff, -0x10,0x60,0x00,0x02,0x00,0x02,0x12,0x02,0x24,0x42,0x00,0x01,0x30,0x53,0x00,0xff, -0x01,0x12,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21, -0x80,0x44,0x00,0x07,0x00,0x00,0x00,0x00,0x10,0x80,0x00,0x4b,0x26,0x24,0x00,0x06, -0x32,0x50,0xff,0xff,0x02,0x20,0x20,0x21,0x0c,0x00,0x1b,0x19,0x02,0x00,0x28,0x21, -0x92,0x22,0x00,0x10,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x2e,0x3c,0x03,0xb0,0x08, -0x3c,0x09,0x80,0x01,0x27,0x88,0x90,0x00,0xa6,0x32,0x00,0x0c,0x00,0x10,0x20,0xc0, -0x00,0x90,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x88,0x20,0x21,0x94,0x82,0x00,0x04, -0x3c,0x03,0xb0,0x08,0x3c,0x07,0xb0,0x03,0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21, -0x00,0x02,0x10,0x80,0x00,0x48,0x10,0x21,0x00,0xa3,0x28,0x21,0x25,0x26,0x82,0x6c, -0x34,0x03,0xff,0xff,0x34,0xe7,0x00,0x20,0xac,0xe6,0x00,0x00,0xa4,0x83,0x00,0x02, -0xa4,0x43,0x00,0x00,0xac,0xa3,0x00,0x00,0x92,0x22,0x00,0x10,0x92,0x23,0x00,0x0a, -0xa6,0x32,0x00,0x0e,0x02,0x62,0x10,0x21,0x14,0x60,0x00,0x05,0xa2,0x22,0x00,0x10, -0x92,0x22,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfe,0xa2,0x22,0x00,0x16, -0x92,0x22,0x00,0x04,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00, -0x92,0x22,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfd,0xa2,0x22,0x00,0x16, -0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x28,0x96,0x22,0x00,0x0e,0x27,0x88,0x90,0x00,0x00,0x02,0x20,0xc0, -0x00,0x82,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x88,0x20,0x21,0x94,0x82,0x00,0x04, -0x3c,0x06,0xb0,0x03,0x3c,0x09,0x80,0x01,0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21, -0x00,0x02,0x10,0x80,0x00,0xa3,0x28,0x21,0x00,0x48,0x10,0x21,0x34,0xc6,0x00,0x20, -0x25,0x23,0x82,0x6c,0xac,0xc3,0x00,0x00,0xa4,0x50,0x00,0x00,0xac,0xb0,0x00,0x00, -0x08,0x00,0x1b,0x97,0xa4,0x90,0x00,0x02,0x08,0x00,0x1b,0x8e,0x32,0x50,0xff,0xff, -0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x6f,0x60,0x34,0x63,0x00,0x20, -0xac,0x62,0x00,0x00,0x90,0x82,0x00,0x04,0x97,0xaa,0x00,0x12,0x00,0x80,0x60,0x21, -0x30,0xa8,0xff,0xff,0x00,0x4a,0x20,0x23,0x34,0x09,0xff,0xff,0x30,0xcf,0xff,0xff, -0x30,0xee,0xff,0xff,0x11,0x09,0x00,0x73,0xa1,0x84,0x00,0x04,0x00,0x0e,0xc0,0xc0, -0x00,0x08,0x10,0xc0,0x00,0x48,0x10,0x21,0x03,0x0e,0x20,0x21,0x27,0x8d,0x90,0x00, -0x00,0x04,0x20,0x80,0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21,0x00,0x8d,0x20,0x21, -0x94,0x86,0x00,0x02,0x94,0x43,0x00,0x04,0x3c,0x19,0x80,0x01,0xa4,0x46,0x00,0x02, -0x00,0x03,0x28,0xc0,0x00,0xa3,0x18,0x21,0x94,0x87,0x00,0x02,0x3c,0x02,0xb0,0x08, -0x00,0x03,0x18,0x80,0x00,0xa2,0x28,0x21,0x00,0x6d,0x18,0x21,0x27,0x22,0x82,0x6c, -0x3c,0x01,0xb0,0x03,0xac,0x22,0x00,0x20,0xa4,0x66,0x00,0x00,0x10,0xe9,0x00,0x57, -0xac,0xa6,0x00,0x00,0x01,0xe0,0x30,0x21,0x11,0x40,0x00,0x1d,0x00,0x00,0x48,0x21, -0x01,0x40,0x38,0x21,0x27,0x8b,0x90,0x04,0x27,0x8a,0x90,0x10,0x00,0x06,0x40,0xc0, -0x01,0x06,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x6b,0x10,0x21,0x8c,0x44,0x00,0x18, -0x00,0x6a,0x18,0x21,0x80,0x65,0x00,0x06,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x42,0xff,0xff,0x00,0x45,0x10,0x21,0x30,0x44,0x00,0xff,0x00,0x02,0x12,0x02, -0x01,0x22,0x18,0x21,0x24,0x62,0x00,0x01,0x14,0x80,0x00,0x02,0x30,0x49,0x00,0xff, -0x30,0x69,0x00,0xff,0x01,0x06,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21, -0x24,0xe7,0xff,0xff,0x94,0x46,0x00,0x02,0x14,0xe0,0xff,0xe9,0x00,0x06,0x40,0xc0, -0x91,0x82,0x00,0x10,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x20,0x3c,0x06,0xb0,0x03, -0xa5,0x8f,0x00,0x0c,0x03,0x0e,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x8d,0x20,0x21, -0x94,0x82,0x00,0x04,0x3c,0x03,0xb0,0x08,0x3c,0x07,0xb0,0x03,0x00,0x02,0x28,0xc0, -0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21,0x00,0xa3,0x28,0x21, -0x27,0x26,0x82,0x6c,0x34,0x03,0xff,0xff,0x34,0xe7,0x00,0x20,0xac,0xe6,0x00,0x00, -0xa4,0x83,0x00,0x02,0xa4,0x43,0x00,0x00,0xac,0xa3,0x00,0x00,0x91,0x82,0x00,0x10, -0x91,0x83,0x00,0x04,0xa5,0x8e,0x00,0x0e,0x01,0x22,0x10,0x21,0x14,0x60,0x00,0x05, -0xa1,0x82,0x00,0x10,0x91,0x82,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfd, -0xa1,0x82,0x00,0x16,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x95,0x82,0x00,0x0e, -0x3c,0x03,0xb0,0x08,0x00,0x02,0x20,0xc0,0x00,0x82,0x20,0x21,0x00,0x04,0x20,0x80, -0x00,0x8d,0x20,0x21,0x94,0x82,0x00,0x04,0x34,0xc6,0x00,0x20,0x27,0x27,0x82,0x6c, -0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0xa3,0x28,0x21, -0x00,0x4d,0x10,0x21,0xac,0xc7,0x00,0x00,0xa4,0x8f,0x00,0x02,0xa4,0x4f,0x00,0x00, -0xac,0xaf,0x00,0x00,0x08,0x00,0x1c,0x26,0x03,0x0e,0x20,0x21,0x08,0x00,0x1c,0x01, -0xa5,0x88,0x00,0x02,0x00,0x0e,0xc0,0xc0,0x03,0x0e,0x10,0x21,0x00,0x02,0x10,0x80, -0x27,0x8d,0x90,0x00,0x00,0x4d,0x10,0x21,0x94,0x43,0x00,0x02,0x30,0x84,0x00,0xff, -0x14,0x80,0x00,0x05,0xa5,0x83,0x00,0x00,0x24,0x02,0xff,0xff,0x3c,0x19,0x80,0x01, -0x08,0x00,0x1c,0x01,0xa5,0x82,0x00,0x02,0x08,0x00,0x1c,0x01,0x3c,0x19,0x80,0x01, -0x3c,0x08,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0x78,0x35,0x08,0x00,0x20, -0x24,0x42,0x71,0xa0,0xaf,0xb2,0x00,0x68,0xaf,0xb1,0x00,0x64,0xaf,0xb0,0x00,0x60, -0xad,0x02,0x00,0x00,0xaf,0xbf,0x00,0x84,0xaf,0xbe,0x00,0x80,0xaf,0xb7,0x00,0x7c, -0xaf,0xb6,0x00,0x78,0xaf,0xb5,0x00,0x74,0xaf,0xb4,0x00,0x70,0xaf,0xb3,0x00,0x6c, -0xaf,0xa4,0x00,0x88,0x90,0x83,0x00,0x0a,0x27,0x82,0xb4,0x00,0xaf,0xa6,0x00,0x90, -0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21,0x8c,0x63,0x00,0x00,0xaf,0xa7,0x00,0x94, -0x27,0x86,0x90,0x04,0xaf,0xa3,0x00,0x1c,0x94,0x63,0x00,0x14,0x30,0xb1,0xff,0xff, -0x24,0x08,0x00,0x01,0x00,0x03,0x20,0xc0,0xaf,0xa3,0x00,0x18,0x00,0x83,0x18,0x21, -0xaf,0xa4,0x00,0x54,0x00,0x03,0x18,0x80,0x27,0x84,0x90,0x10,0x00,0x64,0x20,0x21, -0x80,0x82,0x00,0x06,0x00,0x66,0x18,0x21,0x8c,0x66,0x00,0x18,0x24,0x42,0x00,0x02, -0x00,0x02,0x1f,0xc2,0x8c,0xc4,0x00,0x08,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43, -0x00,0x02,0x10,0x40,0x00,0x04,0x2f,0xc2,0x00,0x04,0x1c,0x82,0x00,0xc2,0x38,0x21, -0x00,0x04,0x24,0x42,0x8f,0xa2,0x00,0x1c,0x30,0x63,0x00,0x01,0x30,0x84,0x00,0x01, -0xaf,0xa5,0x00,0x3c,0xaf,0xa3,0x00,0x34,0xaf,0xa4,0x00,0x38,0xaf,0xa0,0x00,0x40, -0xaf,0xa0,0x00,0x44,0xaf,0xa0,0x00,0x50,0xaf,0xa8,0x00,0x20,0x80,0x42,0x00,0x12, -0x8f,0xb2,0x00,0x18,0xaf,0xa2,0x00,0x28,0x8c,0xd0,0x00,0x0c,0x14,0xa0,0x01,0xe4, -0x00,0x60,0x30,0x21,0x00,0x10,0x10,0x82,0x30,0x45,0x00,0x07,0x10,0xa0,0x00,0x11, -0xaf,0xa0,0x00,0x30,0x8f,0xa4,0x00,0x98,0x27,0x82,0x80,0x1c,0x00,0x04,0x18,0x40, -0x00,0x62,0x18,0x21,0x24,0xa2,0x00,0x06,0x8f,0xa5,0x00,0x20,0x94,0x64,0x00,0x00, -0x00,0x45,0x10,0x04,0x00,0x44,0x00,0x1a,0x14,0x80,0x00,0x02,0x00,0x00,0x00,0x00, -0x00,0x07,0x00,0x0d,0x00,0x00,0x10,0x12,0x24,0x42,0x00,0x20,0x30,0x42,0xff,0xfc, -0xaf,0xa2,0x00,0x30,0x8f,0xa3,0x00,0x18,0x8f,0xa4,0x00,0x28,0x34,0x02,0xff,0xff, -0xaf,0xa0,0x00,0x2c,0xaf,0xa2,0x00,0x48,0xaf,0xa3,0x00,0x4c,0x00,0x60,0xf0,0x21, -0x00,0x00,0xb8,0x21,0x18,0x80,0x00,0x48,0xaf,0xa0,0x00,0x24,0x00,0x11,0x89,0x02, -0xaf,0xb1,0x00,0x58,0x00,0x80,0xa8,0x21,0x00,0x12,0x10,0xc0,0x00,0x52,0x18,0x21, -0x00,0x03,0x80,0x80,0x27,0x85,0x90,0x00,0x02,0x40,0x20,0x21,0x00,0x40,0xa0,0x21, -0x02,0x05,0x10,0x21,0x94,0x56,0x00,0x02,0x0c,0x00,0x12,0x8b,0x00,0x00,0x28,0x21, -0x90,0x42,0x00,0x00,0x24,0x03,0x00,0x08,0x30,0x42,0x00,0x0c,0x10,0x43,0x01,0x9e, -0x24,0x04,0x00,0x01,0x24,0x02,0x00,0x01,0x10,0x82,0x01,0x7c,0x3c,0x02,0xb0,0x03, -0x8f,0xa6,0x00,0x88,0x34,0x42,0x01,0x04,0x84,0xc5,0x00,0x0c,0x02,0x92,0x18,0x21, -0x94,0x46,0x00,0x00,0x00,0x05,0x20,0xc0,0x00,0x85,0x20,0x21,0x00,0x03,0x18,0x80, -0x27,0x82,0x90,0x10,0x27,0x85,0x90,0x08,0x00,0x65,0x28,0x21,0x00,0x62,0x18,0x21, -0x80,0x71,0x00,0x05,0x80,0x73,0x00,0x04,0x8f,0xa3,0x00,0x88,0x30,0xd0,0xff,0xff, -0x00,0x10,0x3a,0x03,0x32,0x08,0x00,0xff,0x27,0x82,0x90,0x20,0x00,0x04,0x20,0x80, -0x80,0xa6,0x00,0x06,0x00,0x82,0x20,0x21,0xa4,0x67,0x00,0x44,0xa4,0x68,0x00,0x46, -0x8c,0x84,0x00,0x00,0x38,0xc6,0x00,0x00,0x01,0x00,0x80,0x21,0x00,0x04,0x15,0x02, -0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x03,0x00,0xe6,0x80,0x0a,0x00,0x04,0x14,0x02, -0x30,0x50,0x00,0x0f,0x12,0x20,0x01,0x50,0x02,0x40,0x20,0x21,0x02,0x71,0x10,0x21, -0x00,0x50,0x10,0x2a,0x14,0x40,0x00,0xed,0x02,0x92,0x10,0x21,0x93,0x82,0x8b,0x71, -0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0xe0,0x02,0x92,0x28,0x21, -0x26,0xe2,0x00,0x01,0x30,0x57,0xff,0xff,0x02,0x40,0xf0,0x21,0x26,0xb5,0xff,0xff, -0x16,0xa0,0xff,0xbd,0x02,0xc0,0x90,0x21,0x16,0xe0,0x00,0xd0,0x00,0x00,0x00,0x00, -0x8f,0xa3,0x00,0x98,0x00,0x00,0x00,0x00,0x2c,0x62,0x00,0x10,0x10,0x40,0x00,0x2e, -0x00,0x00,0x00,0x00,0x8f,0xa4,0x00,0x24,0x00,0x00,0x00,0x00,0x18,0x80,0x00,0x2a, -0x24,0x03,0x00,0x01,0x8f,0xa5,0x00,0x1c,0x27,0x84,0x90,0x04,0x94,0xb2,0x00,0x14, -0xa0,0xa3,0x00,0x12,0x8f,0xa6,0x00,0x3c,0x00,0x12,0x10,0xc0,0x00,0x52,0x10,0x21, -0x00,0x02,0x80,0x80,0x27,0x82,0x90,0x10,0x02,0x02,0x10,0x21,0x80,0x43,0x00,0x06, -0x02,0x04,0x20,0x21,0x8c,0x85,0x00,0x18,0x24,0x63,0x00,0x02,0x00,0x03,0x17,0xc2, -0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x43,0x00,0x03,0x18,0x40,0x14,0xc0,0x00,0x0e, -0x00,0xa3,0x38,0x21,0x27,0x82,0x90,0x00,0x02,0x02,0x10,0x21,0x94,0x43,0x00,0x06, -0x8f,0xa8,0x00,0x1c,0x24,0x02,0x00,0x01,0xa5,0x03,0x00,0x1a,0x7b,0xbe,0x04,0x3c, -0x7b,0xb6,0x03,0xfc,0x7b,0xb4,0x03,0xbc,0x7b,0xb2,0x03,0x7c,0x7b,0xb0,0x03,0x3c, -0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x88,0x8f,0xa4,0x00,0x98,0x8f,0xa5,0x00,0x38, -0x8f,0xa6,0x00,0x34,0xaf,0xa0,0x00,0x10,0x0c,0x00,0x09,0x0a,0xaf,0xa0,0x00,0x14, -0x08,0x00,0x1d,0x2d,0x00,0x00,0x00,0x00,0x8f,0xa3,0x00,0x44,0x93,0x82,0x81,0x58, -0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x61,0x30,0x69,0x00,0x03,0x8f,0xa4,0x00,0x24, -0x8f,0xa5,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x85,0x10,0x2a,0x10,0x40,0x00,0x8f, -0x00,0x00,0x00,0x00,0x8f,0xa6,0x00,0x1c,0x00,0x00,0x00,0x00,0x90,0xc4,0x00,0x04, -0x00,0x00,0x00,0x00,0x30,0x83,0x00,0xff,0x00,0xa3,0x10,0x2a,0x10,0x40,0x00,0x87, -0x00,0x00,0x00,0x00,0x8f,0xa8,0x00,0x24,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x83, -0x00,0x65,0x10,0x23,0x00,0xa8,0x18,0x23,0x00,0x62,0x10,0x2a,0x14,0x40,0x00,0x7d, -0x30,0x63,0x00,0xff,0x00,0x85,0x10,0x23,0x30,0x42,0x00,0xff,0xaf,0xa2,0x00,0x50, -0x8f,0xa2,0x00,0x50,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x73,0x00,0x00,0xa8,0x21, -0x27,0x8c,0x90,0x00,0x3c,0x0b,0x80,0xff,0x24,0x10,0x00,0x04,0x27,0x91,0x90,0x04, -0x35,0x6b,0xff,0xff,0x3c,0x0d,0x7f,0x00,0x27,0x8e,0x90,0x10,0x01,0x80,0x78,0x21, -0x00,0x12,0x30,0xc0,0x00,0xd2,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x4c,0x10,0x21, -0x94,0x42,0x00,0x06,0x8f,0xa3,0x00,0x2c,0x8f,0xa4,0x00,0x30,0xaf,0xa2,0x00,0x44, -0x8f,0xa5,0x00,0x44,0x30,0x49,0x00,0x03,0x02,0x09,0x10,0x23,0x30,0x42,0x00,0x03, -0x00,0xa2,0x10,0x21,0x8f,0xa8,0x00,0x30,0x24,0x42,0x00,0x04,0x30,0x42,0xff,0xff, -0x00,0x64,0x38,0x21,0x01,0x02,0x28,0x23,0x00,0x62,0x18,0x21,0x00,0x48,0x10,0x2b, -0x10,0x40,0x00,0x52,0x00,0x00,0x20,0x21,0x30,0xe7,0xff,0xff,0x30,0xa4,0xff,0xff, -0xaf,0xa7,0x00,0x2c,0x00,0xd2,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x51,0x18,0x21, -0x8c,0x65,0x00,0x18,0x00,0x04,0x25,0x40,0x00,0x8d,0x20,0x24,0x8c,0xa8,0x00,0x04, -0x00,0x4e,0x18,0x21,0x00,0x4f,0x50,0x21,0x01,0x0b,0x40,0x24,0x01,0x04,0x40,0x25, -0xac,0xa8,0x00,0x04,0x8f,0xa4,0x00,0x98,0x8f,0xa2,0x00,0x50,0x26,0xb5,0x00,0x01, -0xa0,0x64,0x00,0x00,0x8c,0xa4,0x00,0x08,0x00,0x00,0x00,0x00,0x04,0x81,0x00,0x0c, -0x02,0xa2,0x30,0x2a,0x80,0x62,0x00,0x06,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x02, -0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40, -0x00,0xa2,0x38,0x21,0x8f,0xa5,0x00,0x40,0x00,0x00,0x00,0x00,0xa4,0xe5,0x00,0x00, -0x95,0x52,0x00,0x02,0x14,0xc0,0xff,0xc7,0x00,0x12,0x30,0xc0,0x8f,0xa4,0x00,0x24, -0x8f,0xa5,0x00,0x50,0x8f,0xa6,0x00,0x1c,0x8f,0xa3,0x00,0x2c,0x00,0x85,0x80,0x21, -0xa0,0xd0,0x00,0x12,0x00,0x09,0x10,0x23,0x30,0x42,0x00,0x03,0x8f,0xa8,0x00,0x88, -0x00,0x62,0x10,0x23,0xa4,0xc2,0x00,0x1a,0x85,0x03,0x00,0x0c,0x00,0x00,0x00,0x00, -0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x04, -0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x83,0x00,0x04, -0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10,0x14,0x60,0xff,0x74,0x02,0x00,0x10,0x21, -0x8f,0xa3,0x00,0x54,0x8f,0xa4,0x00,0x18,0x8f,0xa5,0x00,0x24,0x00,0x64,0x10,0x21, -0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x18,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x00, -0x10,0xa0,0x00,0x03,0x00,0x00,0x30,0x21,0x08,0x00,0x1d,0x33,0x02,0x00,0x10,0x21, -0x93,0x82,0x80,0x10,0x00,0x00,0x28,0x21,0x00,0x00,0x38,0x21,0x0c,0x00,0x21,0x9a, -0xaf,0xa2,0x00,0x10,0x08,0x00,0x1d,0x33,0x02,0x00,0x10,0x21,0x30,0x63,0xff,0xff, -0x08,0x00,0x1d,0x85,0xaf,0xa3,0x00,0x2c,0x8f,0xa8,0x00,0x44,0x08,0x00,0x1d,0xa7, -0x31,0x09,0x00,0x03,0x08,0x00,0x1d,0x60,0xaf,0xa3,0x00,0x50,0x8f,0xa6,0x00,0x44, -0xaf,0xa0,0x00,0x50,0x08,0x00,0x1d,0xa7,0x30,0xc9,0x00,0x03,0x8f,0xa5,0x00,0x48, -0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x1c,0x03,0xc0,0x38,0x21,0x0c,0x00,0x1b,0xd8, -0xaf,0xb7,0x00,0x10,0x08,0x00,0x1d,0x10,0x00,0x00,0x00,0x00,0x00,0x05,0x28,0x80, -0x27,0x82,0x90,0x00,0x00,0xa2,0x28,0x21,0x00,0x00,0x20,0x21,0x0c,0x00,0x01,0x49, -0x00,0x00,0x00,0x00,0x08,0x00,0x1d,0x09,0x26,0xe2,0x00,0x01,0x00,0x02,0x80,0x80, -0x27,0x83,0x90,0x10,0x8f,0xa4,0x00,0x1c,0x02,0x03,0x18,0x21,0x26,0x31,0x00,0x01, -0x02,0x40,0x28,0x21,0x0c,0x00,0x1e,0xea,0xa0,0x71,0x00,0x05,0x14,0x40,0xff,0x13, -0x00,0x00,0x00,0x00,0x16,0xe0,0x00,0x4d,0x03,0xc0,0x38,0x21,0x8f,0xa4,0x00,0x24, -0x8f,0xa5,0x00,0x20,0x24,0x02,0x00,0x01,0x24,0x84,0x00,0x01,0xaf,0xb2,0x00,0x48, -0xaf,0xb6,0x00,0x4c,0x02,0xc0,0xf0,0x21,0x10,0xa2,0x00,0x41,0xaf,0xa4,0x00,0x24, -0x27,0x82,0x90,0x00,0x02,0x02,0x10,0x21,0x94,0x42,0x00,0x06,0x8f,0xa4,0x00,0x30, -0xaf,0xa0,0x00,0x20,0xaf,0xa2,0x00,0x44,0x30,0x49,0x00,0x03,0x8f,0xa8,0x00,0x44, -0x00,0x09,0x10,0x23,0x30,0x42,0x00,0x03,0x01,0x02,0x10,0x21,0x24,0x42,0x00,0x04, -0x30,0x42,0xff,0xff,0x00,0x44,0x18,0x2b,0x10,0x60,0x00,0x2b,0x00,0x00,0x00,0x00, -0x8f,0xa5,0x00,0x2c,0x00,0x82,0x10,0x23,0x00,0xa4,0x18,0x21,0x30,0x63,0xff,0xff, -0x30,0x44,0xff,0xff,0xaf,0xa3,0x00,0x2c,0x02,0x92,0x28,0x21,0x00,0x05,0x28,0x80, -0x27,0x82,0x90,0x04,0x00,0xa2,0x10,0x21,0x8c,0x46,0x00,0x18,0x3c,0x03,0x80,0xff, -0x3c,0x02,0x7f,0x00,0x8c,0xc8,0x00,0x04,0x00,0x04,0x25,0x40,0x34,0x63,0xff,0xff, -0x00,0x82,0x20,0x24,0x01,0x03,0x40,0x24,0x01,0x04,0x40,0x25,0xac,0xc8,0x00,0x04, -0x8f,0xa8,0x00,0x98,0x27,0x82,0x90,0x10,0x00,0xa2,0x10,0x21,0xa0,0x48,0x00,0x00, -0x8c,0xc4,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x04,0x27,0xc2,0x10,0x80,0xfe,0xdb, -0xaf,0xa4,0x00,0x3c,0x80,0x42,0x00,0x06,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x02, -0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40, -0x00,0xc2,0x38,0x21,0x8f,0xa2,0x00,0x40,0x00,0x00,0x00,0x00,0xa4,0xe2,0x00,0x00, -0x08,0x00,0x1d,0x0c,0x26,0xb5,0xff,0xff,0x8f,0xa6,0x00,0x2c,0x00,0x00,0x20,0x21, -0x00,0xc2,0x10,0x21,0x30,0x42,0xff,0xff,0x08,0x00,0x1e,0x1a,0xaf,0xa2,0x00,0x2c, -0x8f,0xa6,0x00,0x1c,0x08,0x00,0x1e,0x04,0xa4,0xd2,0x00,0x14,0x8f,0xa5,0x00,0x48, -0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x1c,0x0c,0x00,0x1b,0xd8,0xaf,0xb7,0x00,0x10, -0x08,0x00,0x1d,0xfb,0x00,0x00,0xb8,0x21,0x0c,0x00,0x12,0x8b,0x00,0x00,0x28,0x21, -0x00,0x40,0x18,0x21,0x94,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x42,0x08,0x00, -0xa4,0x62,0x00,0x00,0x08,0x00,0x1d,0x00,0x02,0x71,0x10,0x21,0x02,0x92,0x18,0x21, -0x00,0x03,0x80,0x80,0x27,0x82,0x90,0x04,0x02,0x02,0x10,0x21,0x8c,0x44,0x00,0x18, -0x00,0x00,0x00,0x00,0x8c,0x83,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10, -0x10,0x60,0x00,0x09,0x24,0x06,0x00,0x01,0x93,0x82,0x8b,0x71,0x00,0x00,0x00,0x00, -0x30,0x42,0x00,0x01,0x10,0x40,0xfe,0xa2,0x3c,0x04,0x00,0x80,0x27,0x85,0x90,0x00, -0x08,0x00,0x1d,0xeb,0x02,0x05,0x28,0x21,0x27,0x83,0x90,0x18,0x27,0x82,0x90,0x10, -0x02,0x03,0x18,0x21,0x02,0x02,0x10,0x21,0x90,0x64,0x00,0x00,0x90,0x45,0x00,0x05, -0x93,0x83,0x80,0x10,0x00,0x00,0x38,0x21,0x0c,0x00,0x21,0x9a,0xaf,0xa3,0x00,0x10, -0x08,0x00,0x1e,0x62,0x00,0x00,0x00,0x00,0x27,0x82,0x90,0x18,0x02,0x02,0x10,0x21, -0x94,0x43,0x00,0x02,0x8f,0xa6,0x00,0x58,0x00,0x03,0x19,0x02,0x00,0x66,0x18,0x23, -0x30,0x63,0x0f,0xff,0x28,0x62,0x00,0x20,0x10,0x40,0x00,0x06,0x28,0x62,0x00,0x40, -0x8f,0xa8,0x00,0x90,0x00,0x00,0x00,0x00,0x00,0x68,0x10,0x06,0x08,0x00,0x1c,0xd9, -0x30,0x44,0x00,0x01,0x10,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x8f,0xa4,0x00,0x94, -0x08,0x00,0x1e,0x83,0x00,0x64,0x10,0x06,0x08,0x00,0x1c,0xd9,0x00,0x00,0x20,0x21, -0x8f,0xa4,0x00,0x98,0x8f,0xa5,0x00,0x38,0xaf,0xa0,0x00,0x10,0x0c,0x00,0x09,0x0a, -0xaf,0xa8,0x00,0x14,0x30,0x42,0xff,0xff,0x08,0x00,0x1c,0xa9,0xaf,0xa2,0x00,0x40, -0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00,0x27,0xbd,0xff,0xe0,0x34,0x42,0x00,0x20, -0x24,0x63,0x7a,0x50,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x18, -0xac,0x43,0x00,0x00,0x90,0x82,0x00,0x0a,0x00,0x80,0x80,0x21,0x14,0x40,0x00,0x45, -0x00,0x00,0x88,0x21,0x92,0x02,0x00,0x04,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x3c, -0x00,0x00,0x00,0x00,0x12,0x20,0x00,0x18,0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16, -0x92,0x05,0x00,0x0a,0x30,0x42,0x00,0xfc,0x10,0xa0,0x00,0x03,0xa2,0x02,0x00,0x16, -0x34,0x42,0x00,0x01,0xa2,0x02,0x00,0x16,0x92,0x04,0x00,0x04,0x00,0x00,0x00,0x00, -0x30,0x83,0x00,0xff,0x10,0x60,0x00,0x05,0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16, -0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02,0xa2,0x02,0x00,0x16,0x10,0x60,0x00,0x0a, -0x00,0x00,0x00,0x00,0x14,0xa0,0x00,0x08,0x00,0x00,0x00,0x00,0x96,0x02,0x00,0x00, -0xa2,0x00,0x00,0x17,0xa6,0x02,0x00,0x14,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc, -0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x14,0x80,0x00,0x05,0x24,0x02,0x00,0x01, -0x96,0x03,0x00,0x06,0xa2,0x02,0x00,0x17,0x08,0x00,0x1e,0xbe,0xa6,0x03,0x00,0x14, -0x96,0x04,0x00,0x00,0x96,0x05,0x00,0x06,0x27,0x86,0x90,0x00,0x00,0x04,0x10,0xc0, -0x00,0x05,0x18,0xc0,0x00,0x44,0x10,0x21,0x00,0x65,0x18,0x21,0x00,0x02,0x10,0x80, -0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21,0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08, -0x8c,0x44,0x00,0x08,0x0c,0x00,0x12,0x7c,0x00,0x00,0x00,0x00,0x30,0x43,0x00,0xff, -0x10,0x60,0x00,0x04,0xa2,0x02,0x00,0x17,0x96,0x02,0x00,0x06,0x08,0x00,0x1e,0xbe, -0xa6,0x02,0x00,0x14,0x96,0x02,0x00,0x00,0x08,0x00,0x1e,0xbe,0xa6,0x02,0x00,0x14, -0x96,0x05,0x00,0x00,0x0c,0x00,0x1e,0xea,0x02,0x00,0x20,0x21,0x08,0x00,0x1e,0xa5, -0x02,0x22,0x88,0x21,0x94,0x85,0x00,0x06,0x0c,0x00,0x1e,0xea,0x00,0x00,0x00,0x00, -0x08,0x00,0x1e,0xa1,0x00,0x40,0x88,0x21,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, -0x34,0x63,0x00,0x20,0x24,0x42,0x7b,0xa8,0x27,0xbd,0xff,0xf0,0xac,0x62,0x00,0x00, -0x00,0x00,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x10,0x3c,0x03,0xb0,0x03, -0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x7b,0xcc,0xac,0x62,0x00,0x00, -0x90,0x89,0x00,0x0a,0x00,0x80,0x30,0x21,0x11,0x20,0x00,0x05,0x00,0xa0,0x50,0x21, -0x90,0x82,0x00,0x17,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x1b,0x00,0x00,0x00,0x00, -0x90,0xc7,0x00,0x04,0x00,0x00,0x00,0x00,0x10,0xe0,0x00,0x1b,0x00,0x00,0x00,0x00, -0x94,0xc8,0x00,0x00,0x27,0x83,0x90,0x00,0x93,0x85,0x8b,0x70,0x00,0x08,0x10,0xc0, -0x00,0x48,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x08, -0x00,0xe5,0x28,0x2b,0x10,0xa0,0x00,0x06,0x01,0x44,0x18,0x23,0x8f,0x82,0x8b,0x88, -0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x2b,0x10,0x40,0x00,0x05,0x00,0x00,0x00,0x00, -0x24,0x03,0x00,0x10,0xa4,0xc8,0x00,0x14,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21, -0x11,0x20,0x00,0x05,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x06,0x24,0x03,0x00,0x08, -0x08,0x00,0x1f,0x16,0xa4,0xc2,0x00,0x14,0x08,0x00,0x1f,0x16,0x00,0x00,0x18,0x21, -0x27,0xbd,0xff,0xc8,0xaf,0xb5,0x00,0x2c,0xaf,0xb4,0x00,0x28,0xaf,0xb3,0x00,0x24, -0xaf,0xb0,0x00,0x18,0xaf,0xbf,0x00,0x30,0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c, -0x94,0x91,0x00,0x06,0x00,0x80,0xa0,0x21,0x3c,0x02,0x80,0x00,0x3c,0x04,0xb0,0x03, -0x00,0x11,0xa8,0xc0,0x34,0x84,0x00,0x20,0x24,0x42,0x7c,0x80,0x02,0xb1,0x48,0x21, -0xac,0x82,0x00,0x00,0x00,0x09,0x48,0x80,0x24,0x03,0x00,0x01,0x27,0x82,0x90,0x10, -0xa2,0x83,0x00,0x12,0x01,0x22,0x10,0x21,0x27,0x84,0x90,0x04,0x01,0x24,0x20,0x21, -0x80,0x48,0x00,0x06,0x8c,0x8a,0x00,0x18,0x27,0x83,0x90,0x20,0x01,0x23,0x48,0x21, -0x8d,0x24,0x00,0x00,0x25,0x08,0x00,0x02,0x8d,0x42,0x00,0x00,0x8d,0x49,0x00,0x04, -0x00,0x08,0x17,0xc2,0x8d,0x43,0x00,0x08,0x01,0x02,0x40,0x21,0x00,0x04,0x25,0xc2, -0x00,0x08,0x40,0x43,0x30,0x84,0x00,0x01,0x00,0x03,0x1f,0xc2,0x00,0x08,0x40,0x40, -0x00,0xe0,0x80,0x21,0x00,0x64,0x18,0x24,0x00,0x09,0x49,0x42,0x01,0x48,0x10,0x21, -0x00,0xa0,0x98,0x21,0x00,0xa0,0x20,0x21,0x00,0x40,0x38,0x21,0x02,0x00,0x28,0x21, -0x14,0x60,0x00,0x19,0x31,0x29,0x00,0x01,0x94,0x42,0x00,0x00,0x02,0xb1,0x88,0x21, -0x02,0x00,0x28,0x21,0x00,0x11,0x88,0x80,0x27,0x90,0x90,0x00,0x02,0x30,0x80,0x21, -0x96,0x03,0x00,0x06,0x30,0x52,0xff,0xff,0x02,0x60,0x20,0x21,0x00,0x60,0x30,0x21, -0xa6,0x83,0x00,0x1a,0x27,0x82,0x90,0x08,0x0c,0x00,0x08,0xe3,0x02,0x22,0x88,0x21, -0x00,0x52,0x10,0x21,0x96,0x03,0x00,0x06,0xa6,0x22,0x00,0x04,0x8f,0xbf,0x00,0x30, -0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x00,0x60,0x10,0x21, -0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0xaf,0xa9,0x00,0x10,0x0c,0x00,0x09,0x0a, -0xaf,0xa0,0x00,0x14,0x08,0x00,0x1f,0x54,0x02,0xb1,0x88,0x21,0x27,0xbd,0xff,0xc0, -0xaf,0xbe,0x00,0x38,0xaf,0xb7,0x00,0x34,0xaf,0xb6,0x00,0x30,0xaf,0xb5,0x00,0x2c, -0xaf,0xb3,0x00,0x24,0xaf,0xb1,0x00,0x1c,0xaf,0xbf,0x00,0x3c,0xaf,0xb4,0x00,0x28, -0xaf,0xb2,0x00,0x20,0xaf,0xb0,0x00,0x18,0x94,0x90,0x00,0x00,0x3c,0x08,0xb0,0x03, -0x35,0x08,0x00,0x20,0x00,0x10,0x10,0xc0,0x00,0x50,0x18,0x21,0x00,0x40,0x88,0x21, -0x3c,0x02,0x80,0x00,0x00,0x03,0x48,0x80,0x24,0x42,0x7d,0xbc,0x00,0x80,0x98,0x21, -0x27,0x84,0x90,0x10,0x01,0x24,0x20,0x21,0x93,0xb7,0x00,0x53,0xad,0x02,0x00,0x00, -0x80,0x83,0x00,0x06,0x27,0x82,0x90,0x04,0x01,0x22,0x10,0x21,0x8c,0x44,0x00,0x18, -0x24,0x63,0x00,0x02,0x00,0x03,0x17,0xc2,0x8c,0x88,0x00,0x08,0x00,0x62,0x18,0x21, -0x00,0x03,0x18,0x43,0x00,0x03,0x18,0x40,0xaf,0xa7,0x00,0x4c,0x2c,0xa2,0x00,0x10, -0x00,0xa0,0xa8,0x21,0x00,0x83,0x50,0x21,0x00,0x08,0x47,0xc2,0x00,0xc0,0x58,0x21, -0x00,0x00,0xb0,0x21,0x8c,0x92,0x00,0x0c,0x14,0x40,0x00,0x13,0x00,0x00,0xf0,0x21, -0x92,0x67,0x00,0x04,0x24,0x14,0x00,0x01,0x12,0x87,0x00,0x10,0x02,0x30,0x10,0x21, -0x27,0x83,0x90,0x18,0x01,0x23,0x18,0x21,0x80,0x64,0x00,0x00,0x27,0x83,0xb5,0x70, -0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23, -0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x04,0x00,0x00,0x00,0x00, -0x10,0x80,0x00,0x23,0x00,0x00,0x00,0x00,0x02,0x30,0x10,0x21,0x00,0x02,0x80,0x80, -0x24,0x04,0x00,0x01,0x27,0x83,0x90,0x20,0xa2,0x64,0x00,0x12,0x02,0x03,0x18,0x21, -0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0xc2,0x30,0x42,0x00,0x01, -0x01,0x02,0x10,0x24,0x14,0x40,0x00,0x0e,0x02,0xa0,0x20,0x21,0x27,0x82,0x90,0x00, -0x02,0x02,0x10,0x21,0x94,0x43,0x00,0x06,0x00,0x00,0x00,0x00,0xa6,0x63,0x00,0x1a, -0x94,0x42,0x00,0x06,0x7b,0xbe,0x01,0xfc,0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c, -0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40, -0x8f,0xa5,0x00,0x4c,0x01,0x60,0x30,0x21,0x01,0x40,0x38,0x21,0xaf,0xa0,0x00,0x10, -0x0c,0x00,0x09,0x0a,0xaf,0xa0,0x00,0x14,0x08,0x00,0x1f,0xbb,0x00,0x00,0x00,0x00, -0x27,0x83,0x90,0x20,0x01,0x23,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x02,0x15,0xc2,0x30,0x42,0x00,0x01,0x01,0x02,0x10,0x24,0x14,0x40,0x00,0xaf, -0x00,0xa0,0x20,0x21,0x32,0x4f,0x00,0x03,0x00,0x12,0x10,0x82,0x25,0xe3,0x00,0x0d, -0x30,0x45,0x00,0x07,0x00,0x74,0x78,0x04,0x10,0xa0,0x00,0x0e,0x00,0x00,0x90,0x21, -0x27,0x82,0x80,0x1c,0x00,0x15,0x18,0x40,0x00,0x62,0x18,0x21,0x94,0x64,0x00,0x00, -0x24,0xa2,0x00,0x06,0x00,0x54,0x10,0x04,0x00,0x44,0x00,0x1a,0x14,0x80,0x00,0x02, -0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d,0x00,0x00,0x10,0x12,0x24,0x42,0x00,0x20, -0x30,0x52,0xff,0xfc,0x02,0x30,0x10,0x21,0x27,0x83,0x90,0x10,0x00,0x02,0x10,0x80, -0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x03,0x00,0x00,0x00,0x00,0x30,0x83,0x00,0xff, -0x2c,0x62,0x00,0x0c,0x14,0x40,0x00,0x04,0x2c,0x62,0x00,0x19,0x30,0x82,0x00,0x0f, -0x24,0x43,0x00,0x0c,0x2c,0x62,0x00,0x19,0x10,0x40,0x00,0x19,0x24,0x0e,0x00,0x20, -0x24,0x62,0xff,0xe9,0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0x15,0x24,0x0e,0x00,0x10, -0x24,0x62,0xff,0xeb,0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0x11,0x24,0x0e,0x00,0x08, -0x24,0x02,0x00,0x14,0x10,0x62,0x00,0x0e,0x24,0x0e,0x00,0x02,0x24,0x62,0xff,0xef, -0x2c,0x42,0x00,0x03,0x14,0x40,0x00,0x0a,0x24,0x0e,0x00,0x10,0x24,0x62,0xff,0xf1, -0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0x06,0x24,0x0e,0x00,0x08,0x24,0x62,0xff,0xf3, -0x2c,0x42,0x00,0x02,0x24,0x0e,0x00,0x04,0x24,0x03,0x00,0x02,0x00,0x62,0x70,0x0a, -0x30,0xe2,0x00,0xff,0x00,0x00,0x48,0x21,0x00,0x00,0x68,0x21,0x10,0x40,0x00,0x6d, -0x00,0x00,0x58,0x21,0x3c,0x14,0x80,0xff,0x27,0x99,0x90,0x00,0x01,0xf2,0xc0,0x23, -0x36,0x94,0xff,0xff,0x01,0xc9,0x10,0x2a,0x14,0x40,0x00,0x64,0x24,0x03,0x00,0x04, -0x00,0x10,0x28,0xc0,0x00,0xb0,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x59,0x10,0x21, -0x94,0x56,0x00,0x06,0x00,0x00,0x00,0x00,0x32,0xcc,0x00,0x03,0x00,0x6c,0x10,0x23, -0x30,0x42,0x00,0x03,0x02,0xc2,0x10,0x21,0x24,0x42,0x00,0x04,0x30,0x51,0xff,0xff, -0x02,0x32,0x18,0x2b,0x10,0x60,0x00,0x4d,0x01,0xf1,0x10,0x23,0x02,0x51,0x10,0x23, -0x01,0x78,0x18,0x2b,0x10,0x60,0x00,0x34,0x30,0x44,0xff,0xff,0x29,0x22,0x00,0x40, -0x10,0x40,0x00,0x31,0x01,0x72,0x18,0x21,0x25,0x22,0x00,0x01,0x00,0x02,0x16,0x00, -0x00,0x02,0x4e,0x03,0x00,0xb0,0x10,0x21,0x00,0x02,0x30,0x80,0x27,0x82,0x90,0x04, -0x30,0x6b,0xff,0xff,0x00,0xc2,0x18,0x21,0x8c,0x67,0x00,0x18,0x00,0x04,0x25,0x40, -0x3c,0x03,0x7f,0x00,0x8c,0xe2,0x00,0x04,0x00,0x83,0x20,0x24,0x27,0x83,0x90,0x10, -0x00,0x54,0x10,0x24,0x00,0xc3,0x28,0x21,0x00,0x44,0x10,0x25,0xac,0xe2,0x00,0x04, -0x16,0xe0,0x00,0x02,0xa0,0xb5,0x00,0x00,0xa0,0xb5,0x00,0x03,0x27,0x84,0x90,0x20, -0x00,0xc4,0x18,0x21,0x8c,0x62,0x00,0x00,0x8c,0xe8,0x00,0x08,0x00,0x02,0x15,0xc2, -0x00,0x08,0x47,0xc2,0x30,0x42,0x00,0x01,0x01,0x02,0x10,0x24,0x10,0x40,0x00,0x0a, -0x00,0x00,0x00,0x00,0x80,0xa2,0x00,0x06,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x02, -0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40, -0x00,0xe2,0x50,0x21,0xa5,0x5e,0x00,0x00,0x92,0x62,0x00,0x04,0x25,0xad,0x00,0x01, -0x27,0x84,0x90,0x00,0x00,0xc4,0x18,0x21,0x01,0xa2,0x10,0x2a,0x94,0x70,0x00,0x02, -0x14,0x40,0xff,0xb8,0x00,0x00,0x00,0x00,0x96,0x63,0x00,0x14,0x00,0x0c,0x10,0x23, -0xa2,0x69,0x00,0x12,0x30,0x42,0x00,0x03,0x01,0x62,0x10,0x23,0x00,0x03,0x80,0xc0, -0x8f,0xa5,0x00,0x4c,0x30,0x4b,0xff,0xff,0x02,0x03,0x80,0x21,0x27,0x82,0x90,0x08, -0x00,0x10,0x80,0x80,0xa6,0x6b,0x00,0x1a,0x02,0xa0,0x20,0x21,0x01,0x60,0x30,0x21, -0x01,0x60,0x88,0x21,0x0c,0x00,0x08,0xe3,0x02,0x02,0x80,0x21,0x00,0x5e,0x10,0x21, -0xa6,0x02,0x00,0x04,0x08,0x00,0x1f,0xc1,0x02,0x20,0x10,0x21,0x01,0x62,0x10,0x2b, -0x10,0x40,0xff,0xe9,0x00,0x00,0x20,0x21,0x29,0x22,0x00,0x40,0x10,0x40,0xff,0xe6, -0x01,0x71,0x18,0x21,0x08,0x00,0x20,0x37,0x25,0x22,0x00,0x01,0x08,0x00,0x20,0x66, -0x32,0xcc,0x00,0x03,0x08,0x00,0x20,0x66,0x00,0x00,0x60,0x21,0x8f,0xa5,0x00,0x4c, -0x01,0x40,0x38,0x21,0xaf,0xa0,0x00,0x10,0x0c,0x00,0x09,0x0a,0xaf,0xb4,0x00,0x14, -0x92,0x67,0x00,0x04,0x08,0x00,0x1f,0xd9,0x30,0x5e,0xff,0xff,0x30,0x84,0xff,0xff, -0x00,0x04,0x30,0xc0,0x00,0xc4,0x20,0x21,0x00,0x04,0x20,0x80,0x27,0x82,0x90,0x00, -0x3c,0x03,0xb0,0x08,0x30,0xa5,0xff,0xff,0x00,0x82,0x20,0x21,0x00,0xc3,0x30,0x21, -0xac,0xc5,0x00,0x00,0x03,0xe0,0x00,0x08,0xa4,0x85,0x00,0x00,0x30,0x84,0xff,0xff, -0x00,0x04,0x30,0xc0,0x00,0xc4,0x30,0x21,0x27,0x88,0x90,0x00,0x00,0x06,0x30,0x80, -0x00,0xc8,0x30,0x21,0x94,0xc3,0x00,0x04,0x3c,0x02,0xb0,0x08,0x3c,0x07,0xb0,0x03, -0x00,0x03,0x20,0xc0,0x00,0x83,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x82,0x20,0x21, -0x3c,0x02,0x80,0x01,0x30,0xa5,0xff,0xff,0x00,0x68,0x18,0x21,0x34,0xe7,0x00,0x20, -0x24,0x42,0x82,0x6c,0xac,0xe2,0x00,0x00,0xa4,0xc5,0x00,0x02,0xa4,0x65,0x00,0x00, -0x03,0xe0,0x00,0x08,0xac,0x85,0x00,0x00,0x30,0x84,0xff,0xff,0x00,0x04,0x10,0xc0, -0x00,0x44,0x10,0x21,0x27,0x89,0x90,0x00,0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x21, -0x97,0x83,0x8f,0xf0,0x94,0x4a,0x00,0x04,0x3c,0x02,0xb0,0x08,0x00,0x03,0x38,0xc0, -0x00,0x0a,0x40,0xc0,0x00,0xe3,0x18,0x21,0x01,0x0a,0x28,0x21,0x00,0xe2,0x38,0x21, -0x01,0x02,0x40,0x21,0x00,0x03,0x18,0x80,0x00,0x05,0x28,0x80,0x3c,0x06,0xb0,0x03, -0x3c,0x02,0x80,0x01,0x00,0xa9,0x28,0x21,0x00,0x69,0x18,0x21,0x34,0xc6,0x00,0x20, -0x34,0x09,0xff,0xff,0x24,0x42,0x82,0xc8,0xac,0xc2,0x00,0x00,0xa4,0x64,0x00,0x00, -0xac,0xe4,0x00,0x00,0xa4,0xa9,0x00,0x00,0xad,0x09,0x00,0x00,0xa7,0x8a,0x8f,0xf0, -0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01, -0x34,0x63,0x00,0x20,0x24,0x42,0x83,0x48,0x3c,0x04,0xb0,0x03,0xac,0x62,0x00,0x00, -0x34,0x84,0x01,0x10,0x8c,0x82,0x00,0x00,0x97,0x83,0x81,0x60,0x30,0x42,0xff,0xff, -0x10,0x62,0x00,0x16,0x24,0x0a,0x00,0x01,0xa7,0x82,0x81,0x60,0xaf,0x80,0xb4,0x50, -0x00,0x40,0x28,0x21,0x24,0x06,0x00,0x01,0x27,0x84,0xb4,0x54,0x25,0x43,0xff,0xff, -0x00,0x66,0x10,0x04,0x00,0xa2,0x10,0x24,0x14,0x40,0x00,0x07,0x00,0x00,0x00,0x00, -0x8c,0x83,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x66,0x10,0x04,0x00,0xa2,0x10,0x24, -0x38,0x42,0x00,0x00,0x01,0x42,0x18,0x0a,0x25,0x4a,0x00,0x01,0x2d,0x42,0x00,0x14, -0xac,0x83,0x00,0x00,0x14,0x40,0xff,0xf1,0x24,0x84,0x00,0x04,0x3c,0x0b,0xb0,0x03, -0x00,0x00,0x50,0x21,0x3c,0x0c,0x80,0x00,0x27,0x89,0xb4,0xa0,0x35,0x6b,0x01,0x20, -0x8d,0x68,0x00,0x00,0x8d,0x23,0x00,0x04,0x01,0x0c,0x10,0x24,0x00,0x02,0x17,0xc2, -0x11,0x03,0x00,0x37,0xa1,0x22,0x00,0xdc,0xa1,0x20,0x00,0xd5,0xa1,0x20,0x00,0xd6, -0x01,0x20,0x30,0x21,0x00,0x00,0x38,0x21,0x00,0x00,0x28,0x21,0x01,0x20,0x20,0x21, -0x00,0xa8,0x10,0x06,0x30,0x42,0x00,0x01,0x10,0xe0,0x00,0x10,0xa0,0x82,0x00,0x0a, -0x90,0x82,0x00,0x07,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x31,0x24,0xa2,0xff,0xff, -0xa0,0x82,0x00,0x08,0x90,0x82,0x00,0x0a,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x09, -0x00,0x00,0x00,0x00,0x90,0x83,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0x40, -0x00,0x43,0x10,0x21,0x00,0x46,0x10,0x21,0xa0,0x45,0x00,0x09,0x90,0x82,0x00,0x0a, -0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x07,0x00,0x00,0x00,0x00,0x14,0xe0,0x00,0x04, -0x00,0x00,0x00,0x00,0xa0,0xc5,0x00,0xd5,0x24,0x07,0x00,0x01,0xa0,0x85,0x00,0x08, -0xa0,0xc5,0x00,0xd6,0x24,0xa5,0x00,0x01,0x2c,0xa2,0x00,0x1c,0x14,0x40,0xff,0xe0, -0x24,0x84,0x00,0x03,0x90,0xc4,0x00,0xd5,0x00,0x00,0x28,0x21,0x00,0xa4,0x10,0x2b, -0x10,0x40,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0xc0,0x18,0x21,0xa0,0x64,0x00,0x08, -0x90,0xc2,0x00,0xd5,0x24,0xa5,0x00,0x01,0xa0,0x62,0x00,0x09,0x90,0xc4,0x00,0xd5, -0x00,0x00,0x00,0x00,0x00,0xa4,0x10,0x2b,0x14,0x40,0xff,0xf8,0x24,0x63,0x00,0x03, -0x25,0x4a,0x00,0x01,0x2d,0x42,0x00,0x08,0xad,0x28,0x00,0x04,0x25,0x6b,0x00,0x04, -0x14,0x40,0xff,0xbf,0x25,0x29,0x00,0xec,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, -0x90,0x82,0x00,0x05,0x08,0x00,0x21,0x0d,0xa0,0x82,0x00,0x08,0x97,0x85,0x8b,0x7a, -0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x63,0x00,0x20, -0x24,0x42,0x84,0xfc,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x62,0x00,0x00, -0x30,0x90,0x00,0xff,0x00,0x05,0x28,0x42,0x00,0x00,0x48,0x21,0x27,0x8f,0xb4,0xa4, -0x00,0x00,0x50,0x21,0x00,0x00,0x58,0x21,0x27,0x98,0xb5,0x84,0x27,0x99,0xb5,0x80, -0x27,0x8e,0xb5,0x7e,0x27,0x8c,0xb4,0xa8,0x27,0x8d,0xb5,0x00,0x27,0x88,0xb5,0x78, -0x00,0x0a,0x18,0x80,0x01,0x6f,0x10,0x21,0xac,0x40,0x00,0x00,0xac,0x45,0x00,0x58, -0x00,0x6e,0x20,0x21,0x00,0x78,0x10,0x21,0xa1,0x00,0xff,0xfc,0xad,0x00,0x00,0x00, -0xa1,0x00,0x00,0x04,0xa1,0x00,0x00,0x05,0xad,0x00,0xff,0xf8,0x00,0x79,0x18,0x21, -0x24,0x06,0x00,0x01,0x24,0xc6,0xff,0xff,0xa0,0x80,0x00,0x00,0xa4,0x60,0x00,0x00, -0xac,0x40,0x00,0x00,0x24,0x63,0x00,0x02,0x24,0x42,0x00,0x04,0x04,0xc1,0xff,0xf9, -0x24,0x84,0x00,0x01,0x00,0x0a,0x10,0x80,0x00,0x4d,0x20,0x21,0x00,0x00,0x30,0x21, -0x00,0x4c,0x18,0x21,0x27,0x87,0x81,0x64,0x8c,0xe2,0x00,0x00,0x24,0xe7,0x00,0x04, -0xac,0x82,0x00,0x00,0xa0,0x66,0x00,0x00,0xa0,0x66,0x00,0x01,0x24,0xc6,0x00,0x01, -0x28,0xc2,0x00,0x1c,0xa0,0x60,0x00,0x02,0x24,0x84,0x00,0x04,0x14,0x40,0xff,0xf6, -0x24,0x63,0x00,0x03,0x25,0x29,0x00,0x01,0x29,0x22,0x00,0x08,0x25,0x4a,0x00,0x3b, -0x25,0x08,0x00,0xec,0x14,0x40,0xff,0xd6,0x25,0x6b,0x00,0xec,0xa7,0x80,0x81,0x60, -0x00,0x00,0x48,0x21,0x27,0x83,0xb4,0x50,0xac,0x69,0x00,0x00,0x25,0x29,0x00,0x01, -0x29,0x22,0x00,0x0c,0x14,0x40,0xff,0xfc,0x24,0x63,0x00,0x04,0x0c,0x00,0x20,0xd2, -0x00,0x00,0x00,0x00,0x2e,0x04,0x00,0x14,0x27,0x83,0xb4,0xa0,0x24,0x09,0x00,0x07, -0x10,0x80,0x00,0x0a,0x00,0x00,0x00,0x00,0x90,0x62,0x00,0xd5,0x25,0x29,0xff,0xff, -0xa0,0x62,0x00,0x00,0x05,0x21,0xff,0xfa,0x24,0x63,0x00,0xec,0x8f,0xbf,0x00,0x14, -0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x90,0x62,0x00,0xd6, -0x08,0x00,0x21,0x90,0x25,0x29,0xff,0xff,0x30,0x84,0x00,0xff,0x00,0x04,0x11,0x00, -0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80, -0x27,0x83,0xb4,0xa0,0x00,0x43,0x60,0x21,0x3c,0x04,0xb0,0x03,0x3c,0x02,0x80,0x01, -0x34,0x84,0x00,0x20,0x24,0x42,0x86,0x68,0x30,0xc6,0x00,0xff,0x93,0xaa,0x00,0x13, -0x30,0xa5,0x00,0xff,0x30,0xe7,0x00,0xff,0xac,0x82,0x00,0x00,0x10,0xc0,0x00,0xe8, -0x25,0x8f,0x00,0xd0,0x91,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x42,0xff,0xfc, -0x2c,0x43,0x00,0x18,0x10,0x60,0x00,0xc7,0x3c,0x03,0x80,0x01,0x00,0x02,0x10,0x80, -0x24,0x63,0x02,0x90,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x30,0x14,0x40,0x00,0x1c, -0x00,0x00,0x00,0x00,0x10,0xa0,0x00,0x17,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, -0x10,0xa2,0x00,0x11,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x0c, -0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x06,0x00,0x00,0x00,0x00, -0x8d,0x82,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x42,0xff,0xe0,0x03,0xe0,0x00,0x08, -0xad,0x82,0x00,0xd0,0x8d,0x82,0x00,0xd0,0x08,0x00,0x21,0xcb,0x24,0x42,0xff,0xe8, -0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x21,0xcb, -0x24,0x42,0x00,0x01,0x8d,0x82,0x00,0xd0,0x08,0x00,0x21,0xcb,0x24,0x42,0x00,0x02, -0x10,0xa0,0xff,0xf9,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x0a, -0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xe9,0x00,0x00,0x00,0x00, -0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0xe6,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0, -0x08,0x00,0x21,0xcb,0x24,0x42,0xff,0xd0,0x8d,0x82,0x00,0xd0,0x08,0x00,0x21,0xcb, -0x24,0x42,0xff,0xfc,0x10,0xa0,0xff,0xeb,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, -0x10,0xa2,0xff,0xe5,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xe0, -0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xdb,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0, -0x08,0x00,0x21,0xcb,0x24,0x42,0xff,0xf8,0x2d,0x42,0x00,0x19,0x14,0x40,0xff,0xc5, -0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xdb,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, -0x10,0xa2,0xff,0xd5,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xd0, -0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0xf1,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0, -0x08,0x00,0x21,0xcb,0x24,0x42,0xff,0xf0,0x2d,0x42,0x00,0x1b,0x10,0x40,0xff,0xf1, -0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xcb,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, -0x10,0xa2,0xff,0xc5,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x14,0xa2,0xff,0xb5, -0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x21,0xcb,0x24,0x42,0xff,0xf4, -0x2d,0x42,0x00,0x1e,0x10,0x40,0xff,0xe3,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xbd, -0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xb5,0x24,0x02,0x00,0x02, -0x10,0xa2,0xff,0xd6,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xc6,0x24,0x02,0x00,0x03, -0x2d,0x42,0x00,0x23,0x10,0x40,0xff,0xd7,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xae, -0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xa9,0x24,0x02,0x00,0x02, -0x14,0xa2,0xff,0xb7,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x03,0x00,0x00,0x00,0x00, -0x2d,0x42,0x00,0x25,0x10,0x40,0xff,0xcb,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xd8, -0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x16,0x14,0x40,0x00,0x0e,0x00,0x00,0x00,0x00, -0x10,0xa0,0xff,0xa0,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x9a, -0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x95,0x24,0x02,0x00,0x03, -0x14,0xa2,0xff,0xb6,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x21,0xcb, -0x24,0x42,0xff,0xfa,0x10,0xa0,0xff,0x93,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, -0x10,0xa2,0xff,0x8d,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x88, -0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xf3,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x17, -0x14,0x40,0xff,0xac,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x34,0x00,0x00,0x00,0x00, -0x2d,0x42,0x00,0x19,0x10,0x40,0xff,0xe2,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0x81, -0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x7b,0x00,0x00,0x00,0x00, -0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x76,0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0x97, -0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xc8,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x51, -0x2d,0x42,0x00,0x1b,0x2d,0x42,0x00,0x1e,0x10,0x40,0xff,0xde,0x00,0x00,0x00,0x00, -0x10,0xa0,0xff,0x70,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x6a, -0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x65,0x24,0x02,0x00,0x03, -0x10,0xa2,0xff,0x96,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xc8,0x00,0x00,0x00,0x00, -0x2d,0x42,0x00,0x23,0x14,0x40,0xff,0xf2,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xf9, -0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xf7,0x2d,0x42,0x00,0x25,0x08,0x00,0x22,0x2d, -0x2d,0x42,0x00,0x27,0x10,0xa0,0xff,0x5b,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, -0x10,0xa2,0xff,0x55,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x50, -0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0x71,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xe6, -0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x27,0x14,0x40,0xff,0xad,0x00,0x00,0x00,0x00, -0x08,0x00,0x22,0x79,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x2a,0x14,0x40,0xff,0xd8, -0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xe9,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x2c, -0x14,0x40,0xff,0x78,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xbd,0x00,0x00,0x00,0x00, -0x91,0x86,0x00,0x00,0x91,0x83,0x00,0xd4,0x25,0x8d,0x00,0x5c,0x30,0xc4,0x00,0xff, -0x00,0x04,0x10,0x40,0x00,0x44,0x10,0x21,0x00,0x04,0x48,0x80,0x01,0x82,0x58,0x21, -0x01,0x89,0x40,0x21,0x25,0x78,0x00,0x08,0x10,0x60,0x00,0x37,0x25,0x0e,0x00,0x60, -0x2c,0xa2,0x00,0x03,0x14,0x40,0x00,0x25,0x00,0x00,0x00,0x00,0x91,0x82,0x00,0xdd, -0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x1e,0x00,0x00,0x00,0x00,0x27,0x87,0x81,0x64, -0x01,0x27,0x10,0x21,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x03,0x00,0x60, -0x91,0x62,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x40,0x30,0x21,0xa1,0x82,0x00,0x00, -0x30,0xc2,0x00,0xff,0x00,0x02,0x10,0x80,0x00,0x47,0x10,0x21,0x8c,0x43,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x03,0x18,0x42,0xad,0xa3,0x00,0x00,0x91,0x84,0x00,0x00, -0x8d,0xc5,0x00,0x00,0x00,0x04,0x20,0x80,0x00,0x87,0x10,0x21,0x8c,0x43,0x00,0x00, -0x00,0x05,0x28,0x40,0x00,0x8c,0x20,0x21,0x00,0x03,0x18,0x80,0x00,0xa3,0x10,0x2b, -0x00,0x62,0x28,0x0a,0xac,0x85,0x00,0x60,0x03,0xe0,0x00,0x08,0xa1,0x80,0x00,0xd4, -0x27,0x87,0x81,0x64,0x08,0x00,0x22,0xb0,0xa1,0x80,0x00,0xdd,0x27,0x82,0x81,0xd4, -0x8d,0x83,0x00,0xd8,0x00,0x82,0x10,0x21,0x90,0x44,0x00,0x00,0x24,0x63,0x00,0x01, -0x00,0x64,0x20,0x2b,0x14,0x80,0xff,0x02,0xad,0x83,0x00,0xd8,0x8d,0x02,0x00,0x60, -0xa1,0x80,0x00,0xd4,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43, -0x03,0xe0,0x00,0x08,0xad,0x82,0x00,0x5c,0x10,0xe0,0x00,0x1d,0x24,0x83,0xff,0xfc, -0x2c,0x62,0x00,0x18,0x10,0x40,0x01,0x10,0x00,0x03,0x10,0x80,0x3c,0x03,0x80,0x01, -0x24,0x63,0x02,0xf0,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x30,0x14,0x40,0x00,0x65, -0x00,0x00,0x00,0x00,0x10,0xa0,0x00,0x60,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, -0x10,0xa2,0x00,0x5a,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x08, -0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x51,0x00,0x00,0x00,0x00, -0x8d,0x82,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x42,0xff,0xe0,0xad,0x82,0x00,0xd0, -0x8d,0xe3,0x00,0x00,0x8d,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21, -0xad,0xa2,0x00,0x00,0xad,0xe0,0x00,0x00,0x8d,0xa3,0x00,0x00,0x8d,0xc4,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x83,0x10,0x2a,0x10,0x40,0x00,0x22,0x00,0x00,0x00,0x00, -0x93,0x05,0x00,0x01,0x91,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x45,0x00,0x05, -0x24,0x02,0x00,0x01,0xa1,0x85,0x00,0x00,0xa1,0x82,0x00,0xd4,0x03,0xe0,0x00,0x08, -0xad,0x80,0x00,0xd8,0x91,0x82,0x00,0xdd,0x24,0x03,0x00,0x01,0x10,0x43,0x00,0x05, -0x00,0x00,0x00,0x00,0xa1,0x83,0x00,0xd4,0xad,0x80,0x00,0xd8,0x03,0xe0,0x00,0x08, -0xa1,0x83,0x00,0xdd,0x00,0x04,0x17,0xc2,0x00,0x82,0x10,0x21,0x00,0x02,0x10,0x43, -0xad,0xa2,0x00,0x00,0x91,0x83,0x00,0x00,0x27,0x82,0x81,0x64,0x8d,0xc5,0x00,0x00, -0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21,0x8c,0x64,0x00,0x00,0x00,0x05,0x28,0x40, -0x00,0x04,0x18,0x80,0x00,0xa3,0x10,0x2b,0x00,0x62,0x28,0x0a,0x08,0x00,0x22,0xc2, -0xad,0xc5,0x00,0x00,0x97,0x82,0x8b,0x7c,0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x2a, -0x10,0x40,0xfe,0xab,0x00,0x00,0x00,0x00,0x91,0x82,0x00,0xdd,0x00,0x00,0x00,0x00, -0x14,0x40,0x00,0x15,0x00,0x00,0x00,0x00,0x91,0x83,0x00,0x00,0x27,0x82,0x81,0x64, -0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x6c,0x18,0x21, -0xac,0x64,0x00,0x60,0x93,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x10,0x80, -0x01,0x82,0x10,0x21,0x24,0x4e,0x00,0x60,0xa1,0x85,0x00,0x00,0x8d,0xc2,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43, -0x03,0xe0,0x00,0x08,0xad,0xa2,0x00,0x00,0x08,0x00,0x23,0x37,0xa1,0x80,0x00,0xdd, -0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0xf3,0x24,0x42,0xff,0xe8,0x8d,0x82,0x00,0xd0, -0x08,0x00,0x22,0xf3,0x24,0x42,0x00,0x01,0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0xf3, -0x24,0x42,0x00,0x02,0x10,0xa0,0xff,0xf9,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, -0x10,0xa2,0x00,0x0a,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xa0, -0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0x9d,0x00,0x00,0x00,0x00, -0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0xf3,0x24,0x42,0xff,0xd0,0x8d,0x82,0x00,0xd0, -0x08,0x00,0x22,0xf3,0x24,0x42,0xff,0xfc,0x10,0xa0,0xff,0xeb,0x00,0x00,0x00,0x00, -0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xe5,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, -0x10,0xa2,0xff,0x93,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xdd,0x00,0x00,0x00,0x00, -0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0xf3,0x24,0x42,0xff,0xf8,0x2d,0x42,0x00,0x19, -0x14,0x40,0xff,0x7c,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xdb,0x00,0x00,0x00,0x00, -0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xd5,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, -0x10,0xa2,0xff,0x83,0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0xf1,0x00,0x00,0x00,0x00, -0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0xf3,0x24,0x42,0xff,0xf0,0x2d,0x42,0x00,0x1b, -0x10,0x40,0xff,0xf1,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xcb,0x00,0x00,0x00,0x00, -0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xc5,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, -0x14,0xa2,0xff,0x6c,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0xf3, -0x24,0x42,0xff,0xf4,0x2d,0x42,0x00,0x1e,0x10,0x40,0xff,0xe3,0x00,0x00,0x00,0x00, -0x10,0xa0,0xff,0xbd,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x68, -0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xd6,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0xee, -0x24,0x02,0x00,0x03,0x2d,0x42,0x00,0x23,0x10,0x40,0xff,0xd7,0x00,0x00,0x00,0x00, -0x10,0xa0,0xff,0xae,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x5c, -0x24,0x02,0x00,0x02,0x14,0xa2,0xff,0xb7,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0x74, -0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x25,0x10,0x40,0xff,0xcb,0x00,0x00,0x00,0x00, -0x08,0x00,0x23,0x49,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x16,0x14,0x40,0x00,0x0e, -0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xa0,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, -0x10,0xa2,0xff,0x9a,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x48, -0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xb6,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0, -0x08,0x00,0x22,0xf3,0x24,0x42,0xff,0xfa,0x10,0xa0,0xff,0x93,0x00,0x00,0x00,0x00, -0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x8d,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, -0x10,0xa2,0xff,0x3b,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0x64,0x00,0x00,0x00,0x00, -0x2d,0x42,0x00,0x17,0x14,0x40,0xff,0xac,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0xa5, -0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x19,0x10,0x40,0xff,0xe2,0x00,0x00,0x00,0x00, -0x10,0xa0,0xff,0x81,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x7b, -0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x29,0x24,0x02,0x00,0x03, -0x10,0xa2,0xff,0x97,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0xf0,0x00,0x00,0x00,0x00, -0x08,0x00,0x23,0xc2,0x2d,0x42,0x00,0x1b,0x2d,0x42,0x00,0x1e,0x10,0x40,0xff,0xde, -0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0x70,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, -0x10,0xa2,0xff,0x6a,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x18, -0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0x96,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0xf0, -0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x23,0x14,0x40,0xff,0xf2,0x00,0x00,0x00,0x00, -0x08,0x00,0x23,0x6a,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0x68,0x2d,0x42,0x00,0x25, -0x08,0x00,0x23,0x9e,0x2d,0x42,0x00,0x27,0x10,0xa0,0xff,0x5b,0x00,0x00,0x00,0x00, -0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x55,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, -0x10,0xa2,0xff,0x03,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0x71,0x00,0x00,0x00,0x00, -0x08,0x00,0x23,0x57,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x27,0x14,0x40,0xff,0xad, -0x00,0x00,0x00,0x00,0x08,0x00,0x23,0xea,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x2a, -0x14,0x40,0xff,0xd8,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0x5a,0x00,0x00,0x00,0x00, -0x2d,0x42,0x00,0x2c,0x14,0x40,0xff,0x78,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0xe5, -0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe8,0x3c,0x02,0xb0,0x03,0xaf,0xbf,0x00,0x14, -0xaf,0xb0,0x00,0x10,0x34,0x42,0x01,0x18,0x3c,0x03,0xb0,0x03,0x8c,0x50,0x00,0x00, -0x34,0x63,0x01,0x2c,0x90,0x62,0x00,0x00,0x32,0x05,0x00,0x01,0xa3,0x82,0x80,0x10, -0x14,0xa0,0x00,0x14,0x30,0x44,0x00,0xff,0x32,0x02,0x01,0x00,0x14,0x40,0x00,0x09, -0x00,0x00,0x00,0x00,0x32,0x02,0x08,0x00,0x10,0x40,0x00,0x02,0x24,0x02,0x00,0x01, -0xa3,0x82,0xbc,0x18,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x18,0x0c,0x00,0x05,0x37,0x00,0x00,0x00,0x00,0x26,0x02,0xff,0x00, -0xa3,0x80,0xbc,0x18,0x3c,0x01,0xb0,0x03,0xac,0x22,0x01,0x18,0x08,0x00,0x24,0x16, -0x32,0x02,0x08,0x00,0x0c,0x00,0x21,0x3f,0x00,0x00,0x00,0x00,0x26,0x02,0xff,0xff, -0x3c,0x01,0xb0,0x03,0xac,0x22,0x01,0x18,0x08,0x00,0x24,0x13,0x32,0x02,0x01,0x00, -0x27,0xbd,0xff,0xe0,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0,0xaf,0xbf,0x00,0x18, -0x8c,0x43,0x00,0x00,0x3c,0x02,0x00,0x40,0x24,0x07,0x0f,0xff,0x00,0x03,0x33,0x02, -0x00,0x03,0x2d,0x02,0x00,0x03,0x43,0x02,0x30,0x69,0x0f,0xff,0x00,0x62,0x18,0x24, -0x30,0xa5,0x00,0x03,0x30,0xc6,0x00,0xff,0x10,0x60,0x00,0x08,0x31,0x08,0x00,0xff, -0x01,0x00,0x30,0x21,0x0c,0x00,0x24,0xdf,0xaf,0xa9,0x00,0x10,0x8f,0xbf,0x00,0x18, -0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x0c,0x00,0x25,0x31, -0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0xd4,0x08,0x00,0x24,0x3f, -0xac,0x62,0x00,0x00,0x27,0xbd,0xff,0xc0,0x3c,0x02,0xb0,0x03,0xaf,0xbe,0x00,0x38, -0xaf,0xb5,0x00,0x2c,0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18,0xaf,0xbf,0x00,0x3c, -0xaf,0xb7,0x00,0x34,0xaf,0xb6,0x00,0x30,0xaf,0xb4,0x00,0x28,0xaf,0xb3,0x00,0x24, -0xaf,0xb2,0x00,0x20,0x34,0x42,0x00,0x3f,0x90,0x43,0x00,0x00,0x00,0x80,0x80,0x21, -0x00,0x00,0xf0,0x21,0x00,0x00,0x88,0x21,0x10,0x60,0x00,0x76,0x00,0x00,0xa8,0x21, -0x3c,0x01,0xb0,0x03,0xa0,0x20,0x00,0x3f,0x00,0x10,0x12,0x02,0x24,0x04,0x06,0x14, -0x0c,0x00,0x06,0xd1,0x30,0x54,0x00,0x0f,0x24,0x04,0x06,0x14,0x0c,0x00,0x06,0xd1, -0xaf,0xa2,0x00,0x10,0x3c,0x03,0x00,0xff,0x34,0x63,0xff,0xff,0x32,0x10,0x00,0x7f, -0x00,0x43,0x10,0x24,0x00,0x10,0x86,0x00,0x02,0x02,0x80,0x25,0x02,0x00,0x28,0x21, -0x24,0x04,0x06,0x14,0x3c,0x13,0xbf,0xff,0x0c,0x00,0x06,0xbf,0x3c,0x16,0xb0,0x03, -0x00,0x00,0x90,0x21,0x3c,0x17,0x40,0x00,0x36,0x73,0xff,0xff,0x36,0xd6,0x00,0x3e, -0x0c,0x00,0x06,0xd1,0x24,0x04,0x04,0x00,0x00,0x57,0x10,0x25,0x00,0x40,0x28,0x21, -0x0c,0x00,0x06,0xbf,0x24,0x04,0x04,0x00,0x00,0x00,0x80,0x21,0x0c,0x00,0x25,0xf9, -0x00,0x00,0x00,0x00,0x26,0x03,0x00,0x01,0x10,0x40,0x00,0x46,0x30,0x70,0x00,0xff, -0x12,0x00,0xff,0xfa,0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xd1,0x24,0x04,0x04,0x00, -0x00,0x53,0x10,0x24,0x00,0x40,0x28,0x21,0x0c,0x00,0x06,0xbf,0x24,0x04,0x04,0x00, -0x24,0x02,0x00,0x01,0x12,0x82,0x00,0x37,0x00,0x00,0x00,0x00,0x12,0x80,0x00,0x35, -0x00,0x00,0x00,0x00,0x32,0x31,0x00,0x7f,0x12,0x20,0x00,0x04,0x24,0x03,0x00,0x04, -0x27,0xc2,0x00,0x01,0x30,0x5e,0x00,0xff,0x02,0xb1,0xa8,0x21,0x12,0x43,0x00,0x2a, -0x3c,0x03,0xb0,0x03,0x02,0x43,0x10,0x21,0xa0,0x51,0x00,0x34,0x26,0x42,0x00,0x01, -0x30,0x52,0x00,0xff,0x2e,0x43,0x00,0x05,0x14,0x60,0xff,0xd9,0x00,0x00,0x00,0x00, -0x8f,0xa5,0x00,0x10,0x0c,0x00,0x06,0xbf,0x24,0x04,0x06,0x14,0x12,0xa0,0x00,0x0e, -0x3c,0x02,0xb0,0x03,0x13,0xc0,0x00,0x0d,0x34,0x42,0x00,0x3c,0x00,0x15,0x10,0x40, -0x00,0x55,0x10,0x21,0x00,0x02,0x10,0xc0,0x00,0x55,0x10,0x21,0x00,0x02,0xa8,0x80, -0x02,0xbe,0x00,0x1b,0x17,0xc0,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d, -0x00,0x00,0xa8,0x12,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x3c,0x3c,0x03,0xb0,0x03, -0x3c,0x04,0xb0,0x03,0xa4,0x55,0x00,0x00,0x34,0x63,0x00,0x1c,0x34,0x84,0x00,0x1d, -0x24,0x02,0x00,0x01,0xa0,0x60,0x00,0x00,0xa0,0x82,0x00,0x00,0x7b,0xbe,0x01,0xfc, -0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc, -0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40,0xa2,0xd1,0x00,0x00,0x08,0x00,0x24,0x98, -0x26,0x42,0x00,0x01,0x0c,0x00,0x06,0xd1,0x24,0x04,0x04,0xfc,0x08,0x00,0x24,0x8d, -0x00,0x40,0x88,0x21,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x3c,0x3c,0x04,0xb0,0x03, -0x3c,0x05,0xb0,0x03,0xa4,0x60,0x00,0x00,0x34,0x84,0x00,0x1c,0x34,0xa5,0x00,0x1d, -0x24,0x02,0x00,0x02,0x24,0x03,0x00,0x01,0xa0,0x82,0x00,0x00,0x08,0x00,0x24,0xb7, -0xa0,0xa3,0x00,0x00,0x0c,0x00,0x17,0x99,0x00,0x00,0x00,0x00,0x10,0x40,0xff,0x8b, -0x00,0x10,0x12,0x02,0x3c,0x02,0xb0,0x03,0x3c,0x04,0xb0,0x03,0x34,0x42,0x00,0x3c, -0x34,0x84,0x00,0x14,0x24,0x03,0x00,0x01,0xa4,0x40,0x00,0x00,0x3c,0x01,0xb0,0x03, -0xa0,0x23,0x00,0x3f,0x08,0x00,0x24,0xb7,0xac,0x90,0x00,0x00,0x27,0xbd,0xff,0xd8, -0xaf,0xb0,0x00,0x10,0x30,0xd0,0x00,0xff,0x2e,0x02,0x00,0x2e,0xaf,0xb2,0x00,0x18, -0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c,0x30,0xb1,0x00,0xff, -0x14,0x40,0x00,0x06,0x00,0x80,0x90,0x21,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc, -0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x2e,0x13,0x00,0x10, -0x24,0x05,0x00,0x14,0x0c,0x00,0x13,0xa4,0x24,0x06,0x01,0x07,0x12,0x60,0x00,0x38, -0x02,0x00,0x30,0x21,0x8f,0xa2,0x00,0x38,0x30,0xc3,0x00,0x3f,0x3c,0x04,0xb0,0x09, -0x00,0x02,0x14,0x00,0x00,0x43,0x30,0x25,0x34,0x84,0x01,0x60,0x90,0x82,0x00,0x00, -0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xfd,0x24,0x02,0x00,0x01,0x12,0x22,0x00,0x2a, -0x2a,0x22,0x00,0x02,0x14,0x40,0x00,0x24,0x24,0x02,0x00,0x02,0x12,0x22,0x00,0x20, -0x24,0x02,0x00,0x03,0x12,0x22,0x00,0x19,0x00,0x00,0x00,0x00,0x16,0x60,0xff,0xe2, -0x24,0x02,0x00,0x01,0x12,0x22,0x00,0x13,0x2a,0x22,0x00,0x02,0x14,0x40,0x00,0x0d, -0x24,0x02,0x00,0x02,0x12,0x22,0x00,0x09,0x24,0x02,0x00,0x03,0x16,0x22,0xff,0xda, -0x00,0x00,0x00,0x00,0x24,0x04,0x08,0x4c,0x24,0x05,0xff,0xff,0x0c,0x00,0x13,0x5f, -0x3c,0x06,0x0c,0xb8,0x08,0x00,0x24,0xea,0x00,0x00,0x00,0x00,0x08,0x00,0x25,0x12, -0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xd0,0x00,0x00,0x00,0x00,0x08,0x00,0x25,0x12, -0x24,0x04,0x08,0x40,0x08,0x00,0x25,0x12,0x24,0x04,0x08,0x44,0x24,0x04,0x08,0x4c, -0x0c,0x00,0x13,0x5f,0x24,0x05,0xff,0xff,0x08,0x00,0x25,0x07,0x00,0x00,0x00,0x00, -0x08,0x00,0x25,0x20,0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xe0,0x00,0x00,0x00,0x00, -0x08,0x00,0x25,0x20,0x24,0x04,0x08,0x40,0x08,0x00,0x25,0x20,0x24,0x04,0x08,0x44, -0x02,0x40,0x20,0x21,0x0c,0x00,0x25,0x71,0x02,0x20,0x28,0x21,0x08,0x00,0x24,0xf5, -0x00,0x40,0x30,0x21,0x27,0xbd,0xff,0xd8,0x2c,0xc2,0x00,0x2e,0xaf,0xb2,0x00,0x18, -0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c, -0x00,0xc0,0x80,0x21,0x30,0xb1,0x00,0xff,0x00,0x80,0x90,0x21,0x14,0x40,0x00,0x07, -0x00,0x00,0x18,0x21,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc, -0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x2e,0x13,0x00,0x10, -0x24,0x05,0x00,0x14,0x0c,0x00,0x13,0xa4,0x24,0x06,0x01,0x07,0x12,0x60,0x00,0x24, -0x02,0x00,0x30,0x21,0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x60,0x90,0x62,0x00,0x00, -0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xfd,0x30,0xc5,0x00,0x3f,0x0c,0x00,0x25,0xae, -0x02,0x20,0x20,0x21,0x16,0x60,0x00,0x0a,0x00,0x40,0x80,0x21,0x24,0x02,0x00,0x01, -0x12,0x22,0x00,0x15,0x2a,0x22,0x00,0x02,0x14,0x40,0x00,0x0f,0x24,0x02,0x00,0x02, -0x12,0x22,0x00,0x0b,0x24,0x02,0x00,0x03,0x12,0x22,0x00,0x03,0x00,0x00,0x00,0x00, -0x08,0x00,0x25,0x3d,0x02,0x00,0x18,0x21,0x24,0x04,0x08,0x4c,0x24,0x05,0xff,0xff, -0x0c,0x00,0x13,0x5f,0x3c,0x06,0x0c,0xb8,0x08,0x00,0x25,0x3d,0x02,0x00,0x18,0x21, -0x08,0x00,0x25,0x5f,0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xf5,0x00,0x00,0x00,0x00, -0x08,0x00,0x25,0x5f,0x24,0x04,0x08,0x40,0x08,0x00,0x25,0x5f,0x24,0x04,0x08,0x44, -0x02,0x40,0x20,0x21,0x0c,0x00,0x25,0x71,0x02,0x20,0x28,0x21,0x08,0x00,0x25,0x49, -0x00,0x40,0x30,0x21,0x27,0xbd,0xff,0xe8,0x2c,0xc2,0x00,0x1f,0xaf,0xb0,0x00,0x10, -0xaf,0xbf,0x00,0x14,0x00,0xc0,0x80,0x21,0x14,0x40,0x00,0x1d,0x30,0xa5,0x00,0xff, -0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x18,0x28,0xa2,0x00,0x02,0x14,0x40,0x00,0x12, -0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x0e,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x07, -0x24,0x04,0x08,0x4c,0x26,0x10,0xff,0xe2,0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x14, -0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x24,0x05,0xff,0xff, -0x0c,0x00,0x13,0x5f,0x3c,0x06,0x0d,0xf8,0x08,0x00,0x25,0x82,0x26,0x10,0xff,0xe2, -0x08,0x00,0x25,0x87,0x24,0x04,0x08,0x48,0x14,0xa0,0xff,0xf2,0x24,0x04,0x08,0x40, -0x08,0x00,0x25,0x88,0x24,0x05,0xff,0xff,0x08,0x00,0x25,0x87,0x24,0x04,0x08,0x44, -0x2c,0xc2,0x00,0x10,0x14,0x40,0xff,0xec,0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x14, -0x28,0xa2,0x00,0x02,0x14,0x40,0x00,0x0e,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x0a, -0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x03,0x24,0x04,0x08,0x4c,0x08,0x00,0x25,0x82, -0x26,0x10,0xff,0xf1,0x24,0x05,0xff,0xff,0x0c,0x00,0x13,0x5f,0x3c,0x06,0x0d,0xb8, -0x08,0x00,0x25,0x82,0x26,0x10,0xff,0xf1,0x08,0x00,0x25,0xa1,0x24,0x04,0x08,0x48, -0x14,0xa0,0xff,0xf6,0x24,0x04,0x08,0x40,0x08,0x00,0x25,0xa2,0x24,0x05,0xff,0xff, -0x08,0x00,0x25,0xa1,0x24,0x04,0x08,0x44,0x27,0xbd,0xff,0xe8,0x30,0x84,0x00,0xff, -0x24,0x02,0x00,0x01,0x10,0x82,0x00,0x39,0xaf,0xbf,0x00,0x10,0x28,0x82,0x00,0x02, -0x14,0x40,0x00,0x27,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x17, -0x00,0xa0,0x30,0x21,0x24,0x02,0x00,0x03,0x10,0x82,0x00,0x05,0x24,0x04,0x08,0x3c, -0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, -0x0c,0x00,0x13,0x5f,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x3c,0x3c,0x05,0x80,0x00, -0x0c,0x00,0x13,0x5f,0x00,0x00,0x30,0x21,0x24,0x04,0x08,0x3c,0x3c,0x05,0x80,0x00, -0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x01,0x24,0x04,0x08,0xac,0x0c,0x00,0x13,0x41, -0x24,0x05,0x0f,0xff,0x08,0x00,0x25,0xbc,0x00,0x00,0x00,0x00,0x24,0x04,0x08,0x34, -0x0c,0x00,0x13,0x5f,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x34,0x3c,0x05,0x80,0x00, -0x0c,0x00,0x13,0x5f,0x00,0x00,0x30,0x21,0x24,0x04,0x08,0x34,0x3c,0x05,0x80,0x00, -0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x01,0x08,0x00,0x25,0xcb,0x24,0x04,0x08,0xa8, -0x14,0x80,0xff,0xdf,0x00,0xa0,0x30,0x21,0x24,0x04,0x08,0x24,0x0c,0x00,0x13,0x5f, -0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x24,0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5f, -0x00,0x00,0x30,0x21,0x24,0x04,0x08,0x24,0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5f, -0x24,0x06,0x00,0x01,0x08,0x00,0x25,0xcb,0x24,0x04,0x08,0xa0,0x00,0xa0,0x30,0x21, -0x24,0x04,0x08,0x2c,0x0c,0x00,0x13,0x5f,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x2c, -0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5f,0x00,0x00,0x30,0x21,0x24,0x04,0x08,0x2c, -0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x01,0x08,0x00,0x25,0xcb, -0x24,0x04,0x08,0xa4,0x3c,0x05,0x00,0x14,0x3c,0x02,0xb0,0x05,0x34,0x42,0x04,0x20, -0x3c,0x06,0xc0,0x00,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0x34,0xa5,0x17,0x09, -0xac,0x45,0x00,0x00,0x34,0xc6,0x05,0x07,0x34,0x63,0x04,0x24,0x34,0x84,0x02,0x28, -0x3c,0x07,0xb0,0x05,0x24,0x02,0x00,0x20,0xac,0x66,0x00,0x00,0x34,0xe7,0x04,0x50, -0xa0,0x82,0x00,0x00,0x90,0xe2,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x03, -0x10,0x40,0xff,0xfc,0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, -0x93,0x85,0x81,0xf1,0x24,0x02,0x00,0x01,0x14,0xa2,0x00,0x53,0x00,0x80,0x40,0x21, -0x8c,0x89,0x00,0x04,0x3c,0x02,0xb0,0x01,0x01,0x22,0x30,0x21,0x8c,0xc3,0x00,0x04, -0x3c,0x02,0x01,0x00,0x00,0x62,0x10,0x24,0x10,0x40,0x00,0x4b,0x30,0x62,0x00,0x08, -0x10,0x45,0x00,0x59,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x38,0x24,0x03,0x00,0xb4, -0x30,0x44,0x00,0xff,0x10,0x83,0x00,0x61,0x24,0x02,0x00,0xc4,0x10,0x82,0x00,0x54, -0x24,0x02,0x00,0x94,0x10,0x82,0x00,0x45,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x38, -0x00,0x00,0x00,0x00,0x30,0x47,0xff,0xff,0x30,0xe3,0x40,0xff,0x24,0x02,0x40,0x88, -0x14,0x62,0x00,0x39,0x30,0xe3,0x03,0x00,0x24,0x02,0x03,0x00,0x10,0x62,0x00,0x38, -0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x56,0x00,0x00,0x00,0x00,0x30,0x47,0xff,0xff, -0x30,0xe2,0x00,0x80,0x14,0x40,0x00,0x30,0x3c,0x02,0xb0,0x01,0x01,0x22,0x30,0x21, -0x94,0xc3,0x00,0x60,0x24,0x02,0x00,0x08,0x14,0x43,0x00,0x3b,0x00,0x00,0x00,0x00, -0x90,0xc2,0x00,0x62,0x24,0x03,0x00,0x04,0x00,0x02,0x39,0x02,0x10,0xe3,0x00,0x15, -0x24,0x02,0x00,0x06,0x14,0xe2,0x00,0x34,0x00,0x00,0x00,0x00,0x8d,0x05,0x01,0xac, -0x94,0xc4,0x00,0x66,0x27,0x82,0x89,0x68,0x00,0x05,0x28,0x80,0x30,0x87,0xff,0xff, -0x00,0xa2,0x28,0x21,0x00,0x07,0x1a,0x00,0x8c,0xa4,0x00,0x00,0x00,0x07,0x12,0x02, -0x00,0x43,0x10,0x25,0x24,0x42,0x00,0x5e,0x24,0x03,0xc0,0x00,0x30,0x47,0xff,0xff, -0x00,0x83,0x20,0x24,0x00,0x87,0x20,0x25,0xac,0xa4,0x00,0x00,0x08,0x00,0x26,0x76, -0xad,0x07,0x00,0x10,0x8d,0x05,0x01,0xac,0x94,0xc4,0x00,0x64,0x27,0x82,0x89,0x68, -0x00,0x05,0x28,0x80,0x30,0x87,0xff,0xff,0x00,0xa2,0x28,0x21,0x00,0x07,0x1a,0x00, -0x8c,0xa4,0x00,0x00,0x00,0x07,0x12,0x02,0x00,0x43,0x10,0x25,0x24,0x42,0x00,0x36, -0x3c,0x03,0xff,0xff,0x30,0x47,0xff,0xff,0x00,0x83,0x20,0x24,0x00,0x87,0x20,0x25, -0xac,0xa4,0x00,0x00,0xad,0x07,0x00,0x10,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, -0x94,0xc2,0x00,0x50,0x08,0x00,0x26,0x34,0x30,0x47,0xff,0xff,0x8d,0x04,0x01,0xac, -0x27,0x83,0x89,0x68,0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00, -0x3c,0x03,0xff,0xff,0x00,0x43,0x10,0x24,0x34,0x42,0x00,0x2e,0xac,0x82,0x00,0x00, -0x24,0x03,0x00,0x2e,0xad,0x03,0x00,0x10,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, -0x8d,0x04,0x01,0xac,0x27,0x83,0x89,0x68,0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21, -0x8c,0x82,0x00,0x00,0x3c,0x03,0xff,0xff,0x00,0x43,0x10,0x24,0x34,0x42,0x00,0x0e, -0x24,0x03,0x00,0x0e,0x08,0x00,0x26,0x75,0xac,0x82,0x00,0x00,0x8d,0x04,0x01,0xac, -0x27,0x83,0x89,0x68,0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00, -0x3c,0x03,0xff,0xff,0x00,0x43,0x10,0x24,0x34,0x42,0x00,0x14,0x24,0x03,0x00,0x14, -0x08,0x00,0x26,0x75,0xac,0x82,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, -0x30,0xc6,0x00,0xff,0x00,0x06,0x48,0x40,0x01,0x26,0x10,0x21,0x00,0x02,0x10,0x80, -0x27,0x8b,0xbc,0x30,0x27,0x83,0xbc,0x36,0x00,0x4b,0x40,0x21,0x00,0x43,0x10,0x21, -0x94,0x47,0x00,0x00,0x30,0xa2,0x3f,0xff,0x10,0xe2,0x00,0x29,0x30,0x8a,0xff,0xff, -0x95,0x02,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0x02,0x11,0x82,0x30,0x42,0x00,0x01, -0x10,0x43,0x00,0x18,0x00,0x00,0x00,0x00,0x01,0x26,0x10,0x21,0x00,0x02,0x10,0x80, -0x00,0x4b,0x30,0x21,0x94,0xc4,0x00,0x02,0x27,0x83,0xbc,0x36,0x27,0x85,0xbc,0x34, -0x00,0x45,0x28,0x21,0x30,0x84,0xff,0xdf,0x00,0x43,0x10,0x21,0xa4,0xc4,0x00,0x02, -0xa4,0x40,0x00,0x00,0xa4,0xa0,0x00,0x00,0x94,0xc3,0x00,0x02,0x3c,0x04,0xb0,0x01, -0x01,0x44,0x20,0x21,0x30,0x63,0xff,0xbf,0xa4,0xc3,0x00,0x02,0xa0,0xc0,0x00,0x00, -0x8c,0x82,0x00,0x04,0x24,0x03,0xf0,0xff,0x00,0x43,0x10,0x24,0x03,0xe0,0x00,0x08, -0xac,0x82,0x00,0x04,0x24,0x02,0xc0,0x00,0x91,0x04,0x00,0x01,0x00,0xa2,0x10,0x24, -0x00,0x47,0x28,0x25,0x3c,0x03,0xb0,0x01,0x24,0x02,0x00,0x02,0x14,0x82,0xff,0xe2, -0x01,0x43,0x18,0x21,0xac,0x65,0x00,0x00,0x08,0x00,0x26,0xa3,0x01,0x26,0x10,0x21, -0x08,0x00,0x26,0xa3,0x01,0x26,0x10,0x21,0x93,0x83,0x81,0xf1,0x24,0x02,0x00,0x01, -0x14,0x62,0x00,0x0d,0x3c,0x02,0xb0,0x01,0x8c,0x84,0x00,0x04,0x3c,0x06,0xb0,0x09, -0x00,0x82,0x20,0x21,0x8c,0x85,0x00,0x08,0x8c,0x83,0x00,0x04,0x3c,0x02,0x01,0x00, -0x34,0xc6,0x01,0x00,0x00,0x62,0x18,0x24,0x14,0x60,0x00,0x05,0x30,0xa5,0x20,0x00, -0x24,0x02,0x00,0x06,0xa0,0xc2,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, -0x3c,0x03,0xb0,0x09,0x10,0xa0,0xff,0xfc,0x34,0x63,0x01,0x00,0x24,0x02,0x00,0x0e, -0x08,0x00,0x26,0xd6,0xa0,0x62,0x00,0x00,0x3c,0x02,0xb0,0x01,0x30,0xa5,0xff,0xff, -0x00,0xa2,0x28,0x21,0x8c,0xa3,0x00,0x00,0x3c,0x02,0x10,0x00,0x00,0x80,0x30,0x21, -0x00,0x62,0x18,0x24,0x8c,0xa2,0x00,0x04,0x10,0x60,0x00,0x04,0x00,0x00,0x00,0x00, -0x30,0x42,0x80,0x00,0x10,0x40,0x00,0x13,0x00,0x00,0x00,0x00,0x8c,0xc2,0x01,0xa8, -0x00,0x00,0x00,0x00,0x24,0x44,0x00,0x01,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40, -0x00,0x83,0x10,0x0a,0x93,0x83,0x81,0xf0,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80, -0x00,0x82,0x20,0x23,0x24,0x63,0xff,0xff,0xac,0xc4,0x01,0xa8,0xa3,0x83,0x81,0xf0, -0x8c,0xc4,0x01,0xac,0x8c,0xc2,0x01,0xa8,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x26, -0x00,0x02,0x10,0x2b,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, -0x34,0x63,0x00,0x73,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01, -0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0xa3,0x80,0x81,0xf1,0x03,0xe0,0x00,0x08, -0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0xa3,0x82,0x81,0xf1,0x03,0xe0,0x00,0x08, -0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x04,0x3c,0x05,0xb0,0x01,0x00,0x80,0x50,0x21, -0x00,0x45,0x10,0x21,0x8c,0x43,0x00,0x04,0x24,0x02,0x00,0x05,0x00,0x03,0x1a,0x02, -0x30,0x69,0x00,0x0f,0x11,0x22,0x00,0x0b,0x24,0x02,0x00,0x07,0x11,0x22,0x00,0x09, -0x24,0x02,0x00,0x0a,0x11,0x22,0x00,0x07,0x24,0x02,0x00,0x0b,0x11,0x22,0x00,0x05, -0x24,0x02,0x00,0x01,0x93,0x83,0x81,0xf0,0x3c,0x04,0xb0,0x06,0x10,0x62,0x00,0x03, -0x34,0x84,0x80,0x18,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x02,0x14,0x40,0xff,0xfa,0x00,0x00,0x00,0x00, -0x8d,0x43,0x01,0xa8,0x27,0x82,0x89,0x68,0x00,0x03,0x18,0x80,0x00,0x6a,0x20,0x21, -0x8c,0x87,0x00,0xa8,0x00,0x62,0x18,0x21,0x8c,0x68,0x00,0x00,0x00,0xe5,0x28,0x21, -0x8c,0xa9,0x00,0x00,0x3c,0x02,0xff,0xff,0x27,0x83,0x8a,0x68,0x01,0x22,0x10,0x24, -0x00,0x48,0x10,0x25,0xac,0xa2,0x00,0x00,0x8d,0x44,0x01,0xa8,0x00,0x07,0x30,0xc2, -0x3c,0x02,0x00,0x80,0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x00,0x06,0x32,0x00, -0x8c,0xa9,0x00,0x04,0x00,0xc2,0x30,0x25,0x8c,0x82,0x00,0x00,0x3c,0x03,0x80,0x00, -0x01,0x22,0x10,0x25,0x00,0x43,0x10,0x25,0xac,0xa2,0x00,0x04,0xaf,0x87,0xbc,0x20, -0x8c,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x82,0xbc,0x28,0x8c,0xa3,0x00,0x04, -0x3c,0x01,0xb0,0x07,0xac,0x26,0x80,0x18,0x8d,0x42,0x01,0xa8,0xaf,0x83,0xbc,0x24, -0x93,0x85,0x81,0xf0,0x24,0x44,0x00,0x01,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40, -0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x24,0xa5,0xff,0xff, -0x00,0x82,0x20,0x23,0xad,0x44,0x01,0xa8,0xa3,0x85,0x81,0xf0,0x08,0x00,0x27,0x21, -0x00,0x00,0x00,0x00,0x3c,0x05,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0xa5,0x00,0x20, -0x24,0x42,0x9d,0x64,0xac,0xa2,0x00,0x00,0x24,0x02,0x00,0x02,0x24,0x03,0x00,0x20, -0xac,0x82,0x00,0x64,0x3c,0x02,0x80,0x01,0xac,0x83,0x00,0x60,0xac,0x80,0x00,0x00, -0xac,0x80,0x00,0x04,0xac,0x80,0x00,0x08,0xac,0x80,0x00,0x4c,0xac,0x80,0x00,0x50, -0xac,0x80,0x00,0x54,0xac,0x80,0x00,0x0c,0xac,0x80,0x00,0x58,0xa0,0x80,0x00,0x5c, -0x24,0x42,0x9e,0x28,0x24,0x83,0x00,0x68,0x24,0x05,0x00,0x0f,0x24,0xa5,0xff,0xff, -0xac,0x62,0x00,0x00,0x04,0xa1,0xff,0xfd,0x24,0x63,0x00,0x04,0x3c,0x02,0x80,0x01, -0x24,0x42,0x9f,0x10,0xac,0x82,0x00,0x78,0x3c,0x03,0x80,0x01,0x3c,0x02,0x80,0x01, -0x24,0x63,0xa0,0x9c,0x24,0x42,0xa0,0x08,0xac,0x83,0x00,0x88,0xac,0x82,0x00,0x98, -0x3c,0x03,0x80,0x01,0x3c,0x02,0x80,0x01,0x24,0x63,0xa1,0x44,0x24,0x42,0xa2,0x5c, -0xac,0x83,0x00,0xa0,0xac,0x82,0x00,0xa4,0xa0,0x80,0x01,0xba,0xac,0x80,0x01,0xa8, -0xac,0x80,0x01,0xac,0xac,0x80,0x01,0xb0,0xac,0x80,0x01,0xb4,0xa0,0x80,0x01,0xb8, -0x03,0xe0,0x00,0x08,0xa0,0x80,0x01,0xb9,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01, -0x34,0x63,0x00,0x20,0x24,0x42,0x9e,0x28,0x03,0xe0,0x00,0x08,0xac,0x62,0x00,0x00, -0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x34,0x42,0x00,0x20,0x24,0x63,0x9e,0x40, -0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x11, -0x00,0x80,0x28,0x21,0x8c,0x82,0x00,0x14,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0d, -0x00,0x00,0x00,0x00,0x8c,0x84,0x00,0x10,0x8c,0xa3,0x00,0x14,0x8c,0xa2,0x00,0x04, -0x00,0x83,0x20,0x21,0x00,0x44,0x10,0x21,0x30,0x43,0x00,0xff,0x00,0x03,0x18,0x2b, -0x00,0x02,0x12,0x02,0x00,0x43,0x10,0x21,0x00,0x02,0x12,0x00,0x30,0x42,0x3f,0xff, -0xac,0xa2,0x00,0x04,0xac,0xa0,0x00,0x00,0xac,0xa0,0x00,0x4c,0xac,0xa0,0x00,0x50, -0xac,0xa0,0x00,0x54,0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x0c,0x3c,0x03,0xb0,0x03, -0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20,0x24,0x42,0x9e,0xbc,0xac,0x62,0x00,0x00, -0x8c,0x86,0x00,0x04,0x3c,0x02,0xb0,0x01,0x24,0x03,0x00,0x01,0x00,0xc2,0x10,0x21, -0x8c,0x45,0x00,0x00,0xac,0x83,0x00,0x4c,0x00,0x05,0x14,0x02,0x30,0xa3,0x3f,0xff, -0x30,0x42,0x00,0xff,0xac,0x83,0x00,0x10,0xac,0x82,0x00,0x14,0x8c,0x83,0x00,0x14, -0xac,0x85,0x00,0x40,0x00,0xc3,0x30,0x21,0x03,0xe0,0x00,0x08,0xac,0x86,0x00,0x08, -0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20, -0x24,0x63,0x9f,0x10,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00, -0x8c,0x82,0x00,0x4c,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0a,0x00,0x80,0x80,0x21, -0xae,0x00,0x00,0x00,0xae,0x00,0x00,0x4c,0xae,0x00,0x00,0x50,0xae,0x00,0x00,0x54, -0xae,0x00,0x00,0x0c,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x18,0x0c,0x00,0x27,0xaf,0x00,0x00,0x00,0x00,0x08,0x00,0x27,0xd1, -0xae,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8, -0x34,0x42,0x00,0x20,0x24,0x63,0x9f,0x74,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, -0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x4c,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x16, -0x00,0x80,0x80,0x21,0x8e,0x03,0x00,0x08,0x3c,0x02,0xb0,0x01,0x8e,0x04,0x00,0x44, -0x00,0x62,0x18,0x21,0x90,0x65,0x00,0x00,0x24,0x02,0x00,0x01,0xae,0x02,0x00,0x50, -0x30,0xa3,0x00,0xff,0x00,0x03,0x10,0x82,0x00,0x04,0x23,0x02,0x30,0x84,0x00,0x0f, -0x30,0x42,0x00,0x03,0x00,0x03,0x19,0x02,0xae,0x04,0x00,0x34,0xae,0x02,0x00,0x2c, -0xae,0x03,0x00,0x30,0xa2,0x05,0x00,0x48,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10, -0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x27,0xaf,0x00,0x00,0x00,0x00, -0x08,0x00,0x27,0xe9,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01, -0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xa0,0x08,0xaf,0xb0,0x00,0x10, -0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x50,0x00,0x00,0x00,0x00, -0x10,0x40,0x00,0x16,0x00,0x80,0x80,0x21,0x92,0x03,0x00,0x44,0x8e,0x02,0x00,0x40, -0x83,0x85,0x8b,0xd4,0x92,0x04,0x00,0x41,0x30,0x63,0x00,0x01,0x00,0x02,0x16,0x02, -0xae,0x04,0x00,0x14,0x00,0x00,0x30,0x21,0xae,0x02,0x00,0x18,0x10,0xa0,0x00,0x04, -0xae,0x03,0x00,0x3c,0x10,0x60,0x00,0x03,0x24,0x02,0x00,0x01,0x24,0x06,0x00,0x01, -0x24,0x02,0x00,0x01,0xa3,0x86,0x8b,0xd4,0x8f,0xbf,0x00,0x14,0xae,0x02,0x00,0x54, -0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x27,0xdd, -0x00,0x00,0x00,0x00,0x08,0x00,0x28,0x0e,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, -0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xa0,0x9c, -0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x50, -0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x1b,0x00,0x80,0x80,0x21,0x3c,0x02,0xb0,0x03, -0x8c,0x42,0x00,0x00,0x92,0x04,0x00,0x44,0x8e,0x03,0x00,0x40,0x83,0x86,0x8b,0xd4, -0x92,0x05,0x00,0x41,0x30,0x42,0x08,0x00,0x30,0x84,0x00,0x01,0x00,0x02,0x12,0xc2, -0x00,0x03,0x1e,0x02,0x00,0x82,0x20,0x25,0xae,0x05,0x00,0x14,0x00,0x00,0x38,0x21, -0xae,0x03,0x00,0x18,0x10,0xc0,0x00,0x04,0xae,0x04,0x00,0x3c,0x10,0x80,0x00,0x03, -0x24,0x02,0x00,0x01,0x24,0x07,0x00,0x01,0x24,0x02,0x00,0x01,0xa3,0x87,0x8b,0xd4, -0x8f,0xbf,0x00,0x14,0xae,0x02,0x00,0x54,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x18,0x0c,0x00,0x27,0xdd,0x00,0x00,0x00,0x00,0x08,0x00,0x28,0x33, -0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8, -0x34,0x42,0x00,0x20,0x24,0x63,0xa1,0x44,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, -0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x54,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x37, -0x00,0x80,0x80,0x21,0x8e,0x04,0x00,0x04,0x8e,0x03,0x00,0x44,0x3c,0x02,0x80,0x00, -0x3c,0x05,0xb0,0x01,0x34,0x42,0x00,0x10,0x00,0x85,0x20,0x21,0x00,0x62,0x18,0x25, -0xac,0x83,0x00,0x04,0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac,0x02,0x00,0x20,0x21, -0x00,0x45,0x10,0x21,0x8c,0x46,0x00,0x00,0x00,0x03,0x18,0x80,0x27,0x82,0x89,0x68, -0x00,0x62,0x18,0x21,0xac,0x66,0x00,0x00,0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac, -0x00,0x45,0x10,0x21,0x8c,0x46,0x00,0x04,0x00,0x03,0x18,0x80,0x27,0x82,0x8a,0x68, -0x00,0x62,0x18,0x21,0x0c,0x00,0x26,0x10,0xac,0x66,0x00,0x00,0x8e,0x03,0x01,0xac, -0x8e,0x07,0x00,0x04,0x3c,0x06,0xb0,0x03,0x24,0x65,0x00,0x01,0x28,0xa4,0x00,0x00, -0x24,0x62,0x00,0x40,0x00,0xa4,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80, -0x00,0x03,0x18,0x80,0x00,0xa2,0x28,0x23,0x00,0x70,0x18,0x21,0xae,0x05,0x01,0xac, -0xac,0x67,0x00,0xa8,0x34,0xc6,0x00,0x30,0x8c,0xc3,0x00,0x00,0x93,0x82,0x81,0xf0, -0x02,0x00,0x20,0x21,0x24,0x63,0x00,0x01,0x24,0x42,0x00,0x01,0xac,0xc3,0x00,0x00, -0xa3,0x82,0x81,0xf0,0x0c,0x00,0x27,0x90,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x14, -0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x28,0x27, -0x00,0x00,0x00,0x00,0x08,0x00,0x28,0x5d,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, -0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xa2,0x5c, -0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x54, -0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x37,0x00,0x80,0x80,0x21,0x8e,0x04,0x00,0x04, -0x8e,0x03,0x00,0x44,0x3c,0x02,0x80,0x00,0x3c,0x05,0xb0,0x01,0x34,0x42,0x00,0x10, -0x00,0x85,0x20,0x21,0x00,0x62,0x18,0x25,0xac,0x83,0x00,0x04,0x8e,0x02,0x00,0x04, -0x8e,0x03,0x01,0xac,0x02,0x00,0x20,0x21,0x00,0x45,0x10,0x21,0x8c,0x46,0x00,0x00, -0x00,0x03,0x18,0x80,0x27,0x82,0x89,0x68,0x00,0x62,0x18,0x21,0xac,0x66,0x00,0x00, -0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac,0x00,0x45,0x10,0x21,0x8c,0x46,0x00,0x04, -0x00,0x03,0x18,0x80,0x27,0x82,0x8a,0x68,0x00,0x62,0x18,0x21,0x0c,0x00,0x26,0x10, -0xac,0x66,0x00,0x00,0x8e,0x03,0x01,0xac,0x8e,0x07,0x00,0x04,0x3c,0x06,0xb0,0x03, -0x24,0x65,0x00,0x01,0x28,0xa4,0x00,0x00,0x24,0x62,0x00,0x40,0x00,0xa4,0x10,0x0a, -0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x03,0x18,0x80,0x00,0xa2,0x28,0x23, -0x00,0x70,0x18,0x21,0xae,0x05,0x01,0xac,0xac,0x67,0x00,0xa8,0x34,0xc6,0x00,0x30, -0x8c,0xc3,0x00,0x00,0x93,0x82,0x81,0xf0,0x02,0x00,0x20,0x21,0x24,0x63,0x00,0x01, -0x24,0x42,0x00,0x01,0xac,0xc3,0x00,0x00,0xa3,0x82,0x81,0xf0,0x0c,0x00,0x27,0x90, -0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x18,0x0c,0x00,0x28,0x27,0x00,0x00,0x00,0x00,0x08,0x00,0x28,0xa3, -0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x34,0x42,0x00,0x20, -0x24,0x63,0xa3,0x74,0x27,0xbd,0xff,0xe0,0xac,0x43,0x00,0x00,0x3c,0x02,0x80,0x01, -0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x1c, -0x00,0x80,0x80,0x21,0x24,0x52,0x9e,0x28,0x00,0x00,0x88,0x21,0x3c,0x03,0xb0,0x09, -0x34,0x63,0x00,0x06,0x8e,0x06,0x00,0x04,0x90,0x62,0x00,0x00,0x00,0x06,0x22,0x02, -0x00,0x44,0x10,0x23,0x24,0x44,0x00,0x40,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x7f, -0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x24,0x84,0xff,0xff, -0x10,0x44,0x00,0x68,0x00,0x00,0x28,0x21,0x3c,0x02,0xb0,0x01,0x00,0xc2,0x10,0x21, -0x8c,0x44,0x00,0x04,0x3c,0x03,0x7c,0x00,0x34,0x63,0x00,0xf0,0x00,0x83,0x18,0x24, -0xae,0x04,0x00,0x44,0x8c,0x44,0x00,0x00,0x10,0x60,0x00,0x69,0x00,0x00,0x38,0x21, -0x3c,0x09,0xb0,0x03,0x3c,0x06,0x7c,0x00,0x35,0x29,0x00,0x99,0x3c,0x0a,0xb0,0x01, -0x24,0x08,0x00,0x40,0x34,0xc6,0x00,0xf0,0x3c,0x0b,0xff,0xff,0x3c,0x0c,0x28,0x38, -0x16,0x20,0x00,0x06,0x24,0xa5,0x00,0x01,0x93,0x82,0x81,0xf6,0x24,0x11,0x00,0x01, -0x24,0x42,0x00,0x01,0xa1,0x22,0x00,0x00,0xa3,0x82,0x81,0xf6,0x8e,0x02,0x00,0x04, -0x24,0x07,0x00,0x01,0x24,0x42,0x01,0x00,0x30,0x42,0x3f,0xff,0xae,0x02,0x00,0x04, -0x00,0x4a,0x10,0x21,0x8c,0x43,0x00,0x04,0x00,0x00,0x00,0x00,0xae,0x03,0x00,0x44, -0x8c,0x44,0x00,0x00,0x10,0xa8,0x00,0x2d,0x00,0x66,0x18,0x24,0x14,0x60,0xff,0xec, -0x00,0x8b,0x10,0x24,0x14,0x4c,0xff,0xea,0x24,0x02,0x00,0x01,0x10,0xe2,0x00,0x2f, -0x3c,0x03,0xb0,0x09,0x8e,0x02,0x00,0x44,0x8e,0x04,0x00,0x60,0x00,0x02,0x1e,0x42, -0x00,0x02,0x12,0x02,0x30,0x42,0x00,0x0f,0x30,0x63,0x00,0x01,0xae,0x02,0x00,0x00, -0x10,0x44,0x00,0x1a,0xae,0x03,0x00,0x58,0x8e,0x02,0x00,0x64,0x8e,0x04,0x00,0x58, -0x00,0x00,0x00,0x00,0x10,0x82,0x00,0x05,0x00,0x00,0x00,0x00,0xae,0x00,0x00,0x4c, -0xae,0x00,0x00,0x50,0xae,0x00,0x00,0x54,0xae,0x00,0x00,0x0c,0x8e,0x03,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x03,0x10,0x80,0x00,0x50,0x10,0x21,0x8c,0x42,0x00,0x68, -0x00,0x00,0x00,0x00,0x10,0x52,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x40,0xf8,0x09, -0x02,0x00,0x20,0x21,0x8e,0x04,0x00,0x58,0x8e,0x03,0x00,0x00,0x00,0x00,0x00,0x00, -0xae,0x03,0x00,0x60,0x08,0x00,0x28,0xeb,0xae,0x04,0x00,0x64,0x8e,0x02,0x00,0x64, -0x00,0x00,0x00,0x00,0x14,0x62,0xff,0xe5,0x00,0x00,0x00,0x00,0x7a,0x02,0x0d,0x7c, -0x8f,0xbf,0x00,0x1c,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x00,0x43,0x10,0x26, -0x00,0x02,0x10,0x2b,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x34,0x63,0x00,0x06, -0x8e,0x04,0x00,0x04,0x90,0x62,0x00,0x00,0x00,0x04,0x22,0x02,0x00,0x44,0x10,0x23, -0x24,0x44,0x00,0x40,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x7f,0x00,0x83,0x10,0x0a, -0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x82,0x20,0x23,0x14,0x87,0xff,0xc5, -0x00,0x00,0x00,0x00,0x8e,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x62,0x00,0x03, -0x14,0x40,0x00,0x05,0x24,0x02,0x00,0x0d,0x10,0x62,0x00,0x03,0x24,0x02,0x00,0x01, -0x08,0x00,0x29,0x4b,0xa2,0x02,0x00,0x5c,0x08,0x00,0x29,0x4b,0xa2,0x00,0x00,0x5c, -0x3c,0x02,0xff,0xff,0x00,0x82,0x10,0x24,0x3c,0x03,0x28,0x38,0x14,0x43,0xff,0x94, -0x24,0x02,0x00,0x01,0x08,0x00,0x29,0x23,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, -0x3c,0x03,0x80,0x01,0x34,0x42,0x00,0x20,0x24,0x63,0xa5,0xcc,0xac,0x43,0x00,0x00, -0x8c,0x83,0x01,0xa8,0x8c,0x82,0x01,0xac,0x00,0x80,0x40,0x21,0x10,0x62,0x00,0x20, -0x00,0x00,0x20,0x21,0x93,0x82,0x81,0xf1,0x00,0x03,0x28,0x80,0x3c,0x07,0xb0,0x06, -0x00,0xa8,0x18,0x21,0x24,0x04,0x00,0x01,0x8c,0x66,0x00,0xa8,0x10,0x44,0x00,0x1c, -0x34,0xe7,0x80,0x18,0x3c,0x05,0xb0,0x01,0xaf,0x86,0xbc,0x20,0x00,0xc5,0x28,0x21, -0x8c,0xa3,0x00,0x00,0x00,0x06,0x20,0xc2,0x3c,0x02,0x00,0x80,0x00,0x04,0x22,0x00, -0x00,0x82,0x20,0x25,0xaf,0x83,0xbc,0x28,0x8c,0xa2,0x00,0x04,0xac,0xe4,0x00,0x00, -0x8d,0x03,0x01,0xa8,0xaf,0x82,0xbc,0x24,0x24,0x64,0x00,0x01,0x04,0x80,0x00,0x0a, -0x00,0x80,0x10,0x21,0x00,0x02,0x11,0x83,0x8d,0x03,0x01,0xac,0x00,0x02,0x11,0x80, -0x00,0x82,0x10,0x23,0x00,0x43,0x18,0x26,0xad,0x02,0x01,0xa8,0x00,0x03,0x20,0x2b, -0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x08,0x00,0x29,0x95,0x24,0x62,0x00,0x40, -0x27,0x82,0x89,0x68,0x00,0x06,0x20,0xc2,0x00,0x04,0x22,0x00,0x00,0xa2,0x48,0x21, -0x3c,0x02,0x00,0x80,0x00,0x82,0x58,0x25,0x93,0x82,0x81,0xf0,0x3c,0x0a,0xb0,0x06, -0x3c,0x03,0xb0,0x01,0x2c,0x42,0x00,0x02,0x00,0xc3,0x38,0x21,0x35,0x4a,0x80,0x18, -0x14,0x40,0xff,0xef,0x00,0x00,0x20,0x21,0x8c,0xe5,0x00,0x00,0x8d,0x23,0x00,0x00, -0x24,0x02,0xc0,0x00,0x00,0xa2,0x10,0x24,0x00,0x43,0x10,0x25,0xac,0xe2,0x00,0x00, -0x8d,0x04,0x01,0xa8,0x27,0x83,0x8a,0x68,0x8c,0xe5,0x00,0x04,0x00,0x04,0x20,0x80, -0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00,0x3c,0x03,0x80,0x00,0x00,0xa2,0x10,0x25, -0x00,0x43,0x10,0x25,0xac,0xe2,0x00,0x04,0xaf,0x86,0xbc,0x20,0x8c,0xe2,0x00,0x00, -0x93,0x85,0x81,0xf0,0xaf,0x82,0xbc,0x28,0x8c,0xe3,0x00,0x04,0xad,0x4b,0x00,0x00, -0x8d,0x02,0x01,0xa8,0xaf,0x83,0xbc,0x24,0x24,0xa5,0xff,0xff,0x24,0x44,0x00,0x01, -0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40,0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83, -0x00,0x02,0x11,0x80,0x00,0x82,0x20,0x23,0xad,0x04,0x01,0xa8,0xa3,0x85,0x81,0xf0, -0x79,0x02,0x0d,0x7c,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x26,0x08,0x00,0x29,0x9c, -0x00,0x02,0x20,0x2b,0x3c,0x04,0xb0,0x03,0x3c,0x06,0xb0,0x07,0x3c,0x02,0x80,0x01, -0x34,0xc6,0x00,0x18,0x34,0x84,0x00,0x20,0x24,0x42,0xa7,0x54,0x24,0x03,0xff,0x83, -0xac,0x82,0x00,0x00,0xa0,0xc3,0x00,0x00,0x90,0xc4,0x00,0x00,0x27,0xbd,0xff,0xf8, -0x3c,0x03,0xb0,0x07,0x24,0x02,0xff,0x82,0xa3,0xa4,0x00,0x00,0xa0,0x62,0x00,0x00, -0x90,0x64,0x00,0x00,0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x08,0xa3,0xa4,0x00,0x01, -0xa0,0x40,0x00,0x00,0x90,0x43,0x00,0x00,0x24,0x02,0x00,0x03,0x3c,0x05,0xb0,0x07, -0xa3,0xa3,0x00,0x00,0xa0,0xc2,0x00,0x00,0x90,0xc4,0x00,0x00,0x34,0xa5,0x00,0x10, -0x24,0x02,0x00,0x06,0x3c,0x03,0xb0,0x07,0xa3,0xa4,0x00,0x00,0x34,0x63,0x00,0x38, -0xa0,0xa2,0x00,0x00,0x90,0x64,0x00,0x00,0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x20, -0xa3,0xa4,0x00,0x00,0xa0,0xa0,0x00,0x00,0x90,0xa3,0x00,0x00,0xaf,0x82,0xbf,0x30, -0xa3,0xa3,0x00,0x00,0xa0,0x40,0x00,0x00,0x90,0x43,0x00,0x00,0x03,0xe0,0x00,0x08, -0x27,0xbd,0x00,0x08,}; - -u8 Rtl8192PciEFwDataArray[DataArrayLengthPciE] = { -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00, -0x02,0xe9,0x01,0x74,0x02,0xab,0x01,0xc7,0x01,0x55,0x00,0xe4,0x00,0xab,0x00,0x72, -0x00,0x55,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x02,0x76,0x01,0x3b, -0x00,0xd2,0x00,0x9e,0x00,0x69,0x00,0x4f,0x00,0x46,0x00,0x3f,0x01,0x3b,0x00,0x9e, -0x00,0x69,0x00,0x4f,0x00,0x35,0x00,0x27,0x00,0x23,0x00,0x20,0x01,0x2f,0x00,0x98, -0x00,0x65,0x00,0x4c,0x00,0x33,0x00,0x26,0x00,0x22,0x00,0x1e,0x00,0x98,0x00,0x4c, -0x00,0x33,0x00,0x26,0x00,0x19,0x00,0x13,0x00,0x11,0x00,0x0f,0x02,0x39,0x01,0x1c, -0x00,0xbd,0x00,0x8e,0x00,0x5f,0x00,0x47,0x00,0x3f,0x00,0x39,0x01,0x1c,0x00,0x8e, -0x00,0x5f,0x00,0x47,0x00,0x2f,0x00,0x23,0x00,0x20,0x00,0x1c,0x01,0x11,0x00,0x89, -0x00,0x5b,0x00,0x44,0x00,0x2e,0x00,0x22,0x00,0x1e,0x00,0x1b,0x00,0x89,0x00,0x44, -0x00,0x2e,0x00,0x22,0x00,0x17,0x00,0x11,0x00,0x0f,0x00,0x0e,0x02,0xab,0x02,0xab, -0x02,0x66,0x02,0x66,0x07,0x06,0x06,0x06,0x05,0x06,0x07,0x08,0x04,0x06,0x07,0x08, -0x09,0x0a,0x0b,0x0b,0x49,0x6e,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x4c, -0x42,0x4d,0x4f,0x44,0x00,0x00,0x00,0x00,0x54,0x4c,0x42,0x4c,0x5f,0x64,0x61,0x74, -0x61,0x00,0x54,0x4c,0x42,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x64,0x45,0x4c, -0x5f,0x64,0x61,0x74,0x61,0x00,0x41,0x64,0x45,0x53,0x00,0x00,0x00,0x00,0x00,0x00, -0x45,0x78,0x63,0x43,0x6f,0x64,0x65,0x36,0x00,0x00,0x45,0x78,0x63,0x43,0x6f,0x64, -0x65,0x37,0x00,0x00,0x53,0x79,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x70, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x49,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x43,0x70,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x76,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x0b,0x63, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x2c, -0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x60, -0x00,0x00,0x00,0x90,0x00,0x00,0x00,0xc0,0x00,0x00,0x01,0x20,0x00,0x00,0x01,0x80, -0x00,0x00,0x01,0xb0,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x9c, -0x00,0x00,0x00,0xd0,0x00,0x00,0x01,0x38,0x00,0x00,0x01,0xa0,0x00,0x00,0x01,0xd4, -0x00,0x00,0x02,0x08,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0xd0,0x00,0x00,0x01,0x38, -0x00,0x00,0x01,0xa0,0x00,0x00,0x02,0x6f,0x00,0x00,0x03,0x40,0x00,0x00,0x03,0xa8, -0x00,0x00,0x04,0x10,0x01,0x01,0x01,0x02,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04, -0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x07,0x6c,0x80,0x00,0x07,0x80, -0x80,0x00,0x07,0x80,0x80,0x00,0x07,0x70,0x80,0x00,0x07,0x70,0x80,0x00,0x07,0x94, -0x80,0x00,0x56,0xb0,0x80,0x00,0x57,0x08,0x80,0x00,0x57,0x30,0x80,0x00,0x58,0x28, -0x80,0x00,0x58,0xe0,0x80,0x00,0x59,0x88,0x80,0x00,0x59,0xfc,0x80,0x00,0x5b,0x08, -0x80,0x00,0x5b,0x40,0x80,0x00,0x5b,0x54,0x80,0x00,0x5b,0x68,0x80,0x00,0x5c,0x50, -0x80,0x00,0x5c,0x90,0x80,0x00,0x5d,0x44,0x80,0x00,0x5d,0x6c,0x80,0x00,0x56,0x70, -0x80,0x00,0x5d,0xbc,0x80,0x00,0x64,0x48,0x80,0x00,0x64,0xc0,0x80,0x00,0x64,0xcc, -0x80,0x00,0x64,0xd8,0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60, -0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60, -0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60, -0x80,0x00,0x64,0x60,0x80,0x00,0x64,0xe4,0x80,0x00,0x64,0xf0,0x80,0x00,0x64,0xfc, -0x80,0x00,0x87,0xa4,0x80,0x00,0x87,0xa4,0x80,0x00,0x87,0xa4,0x80,0x00,0x87,0xd8, -0x80,0x00,0x88,0x18,0x80,0x00,0x88,0x50,0x80,0x00,0x88,0x80,0x80,0x00,0x88,0xb0, -0x80,0x00,0x88,0xc4,0x80,0x00,0x89,0x2c,0x80,0x00,0x89,0x40,0x80,0x00,0x89,0x7c, -0x80,0x00,0x89,0x84,0x80,0x00,0x89,0xc0,0x80,0x00,0x89,0xd4,0x80,0x00,0x89,0xdc, -0x80,0x00,0x89,0xe4,0x80,0x00,0x89,0xe4,0x80,0x00,0x89,0xe4,0x80,0x00,0x89,0xe4, -0x80,0x00,0x8a,0x14,0x80,0x00,0x8a,0x28,0x80,0x00,0x8a,0x3c,0x80,0x00,0x86,0xe8, -0x80,0x00,0x8d,0x68,0x80,0x00,0x8d,0x68,0x80,0x00,0x8d,0x68,0x80,0x00,0x8d,0x9c, -0x80,0x00,0x8d,0xdc,0x80,0x00,0x8e,0x14,0x80,0x00,0x8e,0x44,0x80,0x00,0x8e,0x74, -0x80,0x00,0x8e,0x88,0x80,0x00,0x8e,0xf0,0x80,0x00,0x8f,0x04,0x80,0x00,0x8f,0x40, -0x80,0x00,0x8f,0x48,0x80,0x00,0x8f,0x84,0x80,0x00,0x8f,0x98,0x80,0x00,0x8f,0xa0, -0x80,0x00,0x8f,0xa8,0x80,0x00,0x8f,0xa8,0x80,0x00,0x8f,0xa8,0x80,0x00,0x8f,0xa8, -0x80,0x00,0x8f,0xd8,0x80,0x00,0x8f,0xec,0x80,0x00,0x90,0x00,0x80,0x00,0x8b,0x88, -}; - u32 Rtl8192PciEPHY_REGArray[PHY_REGArrayLengthPciE] = {0x0,}; u32 Rtl8192PciEPHY_REG_1T2RArray[PHY_REG_1T2RArrayLengthPciE] = { diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 5d6d304c9c01c7..b4bfafe5c4a1b4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -1555,7 +1555,7 @@ static bool SetRFPowerState8190(struct net_device *dev, default: bResult = false; - RT_TRACE(COMP_ERR, "SetRFPowerState8190(): unknow state" + RT_TRACE(COMP_ERR, "SetRFPowerState8190(): unknown state" " to set: 0x%X!!!\n", eRFPowerState); break; } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index c01abc23213efd..356d5217e9d426 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2926,8 +2926,7 @@ static int rtl8192_pci_probe(struct pci_dev *pdev, dev->netdev_ops = &rtl8192_netdev_ops; - dev->wireless_handlers = (struct iw_handler_def *) - &r8192_wx_handlers_def; + dev->wireless_handlers = &r8192_wx_handlers_def; dev->ethtool_ops = &rtl819x_ethtool_ops; dev->type = ARPHRD_ETHER; @@ -3030,7 +3029,7 @@ bool NicIFEnableNIC(struct net_device *dev) RT_TRACE(COMP_ERR, "ERR!!! %s(): Driver is already down!\n", __func__); priv->bdisable_nic = false; - return RT_STATUS_FAILURE; + return false; } RT_TRACE(COMP_PS, "===========>%s()\n", __func__); @@ -3040,7 +3039,7 @@ bool NicIFEnableNIC(struct net_device *dev) RT_TRACE(COMP_ERR, "ERR!!! %s(): initialization is failed!\n", __func__); priv->bdisable_nic = false; - return -1; + return false; } RT_TRACE(COMP_INIT, "start adapter finished\n"); RT_CLEAR_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 35fc1164effd17..d1438c2f8980e3 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -582,7 +582,6 @@ struct r8192_priv { struct rt_firmware *pFirmware; enum rtl819x_loopback LoopbackMode; - enum firmware_source firmware_source; struct timer_list watch_dog_timer; struct timer_list fsync_timer; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index 498995d833e728..de7609716435db 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -19,6 +19,7 @@ #include #include "rtl_core.h" +#include "rtl_wx.h" #define RATE_COUNT 12 static u32 rtl8192_rates[] = { @@ -1213,7 +1214,7 @@ static iw_handler r8192_wx_handlers[] = { }; /* - * the following rule need to be follwing, + * the following rule need to be following, * Odd : get (world access), * even : set (root access) * */ @@ -1320,7 +1321,7 @@ static struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev) return wstats; } -struct iw_handler_def r8192_wx_handlers_def = { +const struct iw_handler_def r8192_wx_handlers_def = { .standard = r8192_wx_handlers, .num_standard = ARRAY_SIZE(r8192_wx_handlers), .private = r8192_private_handler, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h index 6a51a25ec87d6b..58398517f5b397 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h @@ -24,8 +24,7 @@ struct net_device; struct iw_handler_def; struct iw_statistics; -extern struct iw_handler_def r8192_wx_handlers_def; -struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev); +extern const struct iw_handler_def r8192_wx_handlers_def; u16 rtl8192_11n_user_show_rates(struct net_device *dev); #endif diff --git a/drivers/staging/rtl8192e/rtl819x_BAProc.c b/drivers/staging/rtl8192e/rtl819x_BAProc.c index adc6cc7ca3d6f2..48a142b82d9048 100644 --- a/drivers/staging/rtl8192e/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192e/rtl819x_BAProc.c @@ -109,9 +109,9 @@ static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst, BAReq->frame_ctl = cpu_to_le16(RTLLIB_STYPE_MANAGE_ACT); tag = (u8 *)skb_put(skb, 9); - *tag ++= ACT_CAT_BA; - *tag ++= type; - *tag ++= pBA->DialogToken; + *tag++ = ACT_CAT_BA; + *tag++ = type; + *tag++ = pBA->DialogToken; if (ACT_ADDBARSP == type) { RT_TRACE(COMP_DBG, "====>to send ADDBARSP\n"); @@ -175,8 +175,8 @@ static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst, tag = (u8 *)skb_put(skb, 6); - *tag ++= ACT_CAT_BA; - *tag ++= ACT_DELBA; + *tag++ = ACT_CAT_BA; + *tag++ = ACT_DELBA; tmp = DelbaParamSet.shortData; memcpy(tag, (u8 *)&tmp, 2); @@ -230,8 +230,8 @@ static void rtllib_send_DELBA(struct rtllib_device *ieee, u8 *dst, if (skb) softmac_mgmt_xmit(skb, ieee); else - RTLLIB_DEBUG(RTLLIB_DL_ERR, "alloc skb error in func" - "tion %s()\n", __func__); + RTLLIB_DEBUG(RTLLIB_DL_ERR, "alloc skb error in function" + " %s()\n", __func__); return ; } diff --git a/drivers/staging/rtl8192e/rtl819x_TSProc.c b/drivers/staging/rtl8192e/rtl819x_TSProc.c index 29608e5488a44d..52b297724fb1e4 100644 --- a/drivers/staging/rtl8192e/rtl819x_TSProc.c +++ b/drivers/staging/rtl8192e/rtl819x_TSProc.c @@ -79,7 +79,7 @@ static void RxPktPendingTimeout(unsigned long data) if (index > REORDER_WIN_SIZE) { RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket():" - " Rx Reorer struct buffer full!!\n"); + " Rx Reorder struct buffer full!!\n"); spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); return; diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index 6c8a8e12b2b508..7413816dd92ba0 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -712,7 +712,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee, if (index > REORDER_WIN_SIZE) { RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket():" - " Rx Reorer struct buffer full!!\n"); + " Rx Reorder struct buffer full!!\n"); spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); return; diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index 4bf72bc1ba7bb3..d65cba428941db 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -543,7 +543,7 @@ void rtllib_softmac_scan_syncro(struct rtllib_device *ieee, u8 is_mesh) goto out; /* scan completed */ } while (!ieee->active_channel_map[ch]); - /* this fuction can be called in two situations + /* this function can be called in two situations * 1- We have switched to ad-hoc mode and we are * performing a complete syncro scan before conclude * there are no interesting cell and to create a diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index 2131912113d721..9caf6fdb8eed75 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -1903,20 +1903,17 @@ static void ieee80211_process_action(struct ieee80211_device *ieee, } tmp = *act; act ++; - switch (tmp) - { - case ACT_CAT_BA: - if (*act == ACT_ADDBAREQ) + switch (tmp) { + case ACT_CAT_BA: + if (*act == ACT_ADDBAREQ) ieee80211_rx_ADDBAReq(ieee, skb); - else if (*act == ACT_ADDBARSP) + else if (*act == ACT_ADDBARSP) ieee80211_rx_ADDBARsp(ieee, skb); - else if (*act == ACT_DELBA) + else if (*act == ACT_DELBA) ieee80211_rx_DELBA(ieee, skb); - break; - default: -// if (net_ratelimit()) -// IEEE80211_DEBUG(IEEE80211_DL_BA, "unknown action frame(%d)\n", tmp); - break; + break; + default: + break; } return; diff --git a/drivers/staging/rtl8192u/r8190_rtl8256.c b/drivers/staging/rtl8192u/r8190_rtl8256.c index 40b14a2d1cdb29..08e1bc90555abb 100644 --- a/drivers/staging/rtl8192u/r8190_rtl8256.c +++ b/drivers/staging/rtl8192u/r8190_rtl8256.c @@ -32,7 +32,7 @@ void PHY_SetRF8256Bandwidth(struct net_device *dev , HT_CHANNEL_WIDTH Bandwidth) for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) { if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) - continue; + continue; pPhyReg = &priv->PHYRegDef[eRFPath]; @@ -249,7 +249,7 @@ void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel) if(priv->CustomerID == RT_CID_819x_Netcore) TxAGC = 0x22; else - TxAGC += priv->CckPwEnl; + TxAGC += priv->CckPwEnl; } if(TxAGC > 0x24) diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c index d97ad7b909bc04..9fa12e4618b139 100644 --- a/drivers/staging/rtl8192u/r8192U_dm.c +++ b/drivers/staging/rtl8192u/r8192U_dm.c @@ -183,9 +183,8 @@ void dm_CheckRxAggregation(struct net_device *dev) { curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; - if((curTxOkCnt + curRxOkCnt) < 15000000) { + if ((curTxOkCnt + curRxOkCnt) < 15000000) return; - } if(curTxOkCnt > 4*curRxOkCnt) { if (priv->bCurrentRxAggrEnable) { @@ -1646,9 +1645,8 @@ void dm_restore_dynamic_mechanism_state(struct net_device *dev) write_nic_byte(dev, UFWP, 1); } //Restore TX Power Tracking Index - if(priv->btxpower_trackingInit && priv->btxpower_tracking){ + if (priv->btxpower_trackingInit && priv->btxpower_tracking) dm_txpower_reset_recovery(dev); - } // //Restore BB Initial Gain diff --git a/drivers/staging/rtl8192u/r8192U_wx.c b/drivers/staging/rtl8192u/r8192U_wx.c index c70af014a31670..72db77317dec04 100644 --- a/drivers/staging/rtl8192u/r8192U_wx.c +++ b/drivers/staging/rtl8192u/r8192U_wx.c @@ -275,9 +275,8 @@ static int rtl8180_wx_get_range(struct net_device *dev, range->num_bitrates = RATE_COUNT; - for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) { + for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) range->bitrate[i] = rtl8180_rates[i]; - } range->min_frag = MIN_FRAG_THRESHOLD; range->max_frag = MAX_FRAG_THRESHOLD; diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c index ecfb66538eb32a..98a113a6e43953 100644 --- a/drivers/staging/rtl8192u/r819xU_firmware.c +++ b/drivers/staging/rtl8192u/r819xU_firmware.c @@ -277,13 +277,11 @@ bool init_firmware(struct net_device *dev) * and Tx descriptor info * */ rt_status = fw_download_code(dev,mapped_file,file_length); - if (rst_opt == OPT_SYSTEM_RESET) { + if (rst_opt == OPT_SYSTEM_RESET) release_firmware(fw_entry); - } - if (rt_status != TRUE) { + if (rt_status != TRUE) goto download_firmware_fail; - } switch (init_step) { case FW_INIT_STEP0_BOOT: diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c index b9f35313c7ab5b..87e07ba49ecd71 100644 --- a/drivers/staging/rtl8192u/r819xU_phy.c +++ b/drivers/staging/rtl8192u/r819xU_phy.c @@ -504,9 +504,8 @@ void rtl8192_phy_configmac(struct net_device *dev) pdwArray = rtl819XMACPHY_Array; } for (i = 0; i < dwArrayLen; i = i+3) { - if (pdwArray[i] == 0x318) { + if (pdwArray[i] == 0x318) pdwArray[i+2] = 0x00000800; - } RT_TRACE(COMP_DBG, "Rtl8190MACPHY_Array[0]=%x Rtl8190MACPHY_Array[1]=%x Rtl8190MACPHY_Array[2]=%x\n", diff --git a/drivers/staging/rtl8723au/Kconfig b/drivers/staging/rtl8723au/Kconfig index 07fb5e4e50fa7c..435f3594dabeb3 100644 --- a/drivers/staging/rtl8723au/Kconfig +++ b/drivers/staging/rtl8723au/Kconfig @@ -19,14 +19,6 @@ config 8723AU_AP_MODE will never be used as an AP, or the target system has limited memory, "Y" should be selected. -config 8723AU_P2P - bool "Realtek RTL8723AU Peer-to-peer mode" - default y - ---help--- - This option enables peer-to-peer mode for the r8723au driver. Unless you - know that peer-to-peer (P2P) mode will never be used, or the target system has - limited memory, "Y" should be selected. - config 8723AU_BT_COEXIST bool "Realtek RTL8723AU BlueTooth Coexistence" default y diff --git a/drivers/staging/rtl8723au/Makefile b/drivers/staging/rtl8723au/Makefile index 11c6dd48646215..bbf503dd437a27 100644 --- a/drivers/staging/rtl8723au/Makefile +++ b/drivers/staging/rtl8723au/Makefile @@ -8,7 +8,6 @@ r8723au-y := \ core/rtw_led.o \ core/rtw_mlme.o \ core/rtw_mlme_ext.o \ - core/rtw_p2p.o \ core/rtw_pwrctrl.o \ core/rtw_recv.o \ core/rtw_security.o \ diff --git a/drivers/staging/rtl8723au/core/rtw_ap.c b/drivers/staging/rtl8723au/core/rtw_ap.c index a357e98cb83e02..9b31412b75216a 100644 --- a/drivers/staging/rtl8723au/core/rtw_ap.c +++ b/drivers/staging/rtl8723au/core/rtw_ap.c @@ -21,7 +21,6 @@ #ifdef CONFIG_8723AU_AP_MODE -extern unsigned char RTW_WPA_OUI23A[]; extern unsigned char WMM_OUI23A[]; extern unsigned char WPS_OUI23A[]; extern unsigned char P2P_OUI23A[]; @@ -74,12 +73,13 @@ static void update_BCNTIM(struct rtw_adapter *padapter) struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network; unsigned char *pie = pnetwork_mlmeext->IEs; u8 *p, *dst_ie, *premainder_ie = NULL, *pbackup_remainder_ie = NULL; - u16 tim_bitmap_le; + __le16 tim_bitmap_le; uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen; tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap); - p = rtw_get_ie23a(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_); + p = rtw_get_ie23a(pie + _FIXED_IE_LENGTH_, WLAN_EID_TIM, &tim_ielen, + pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_); if (p != NULL && tim_ielen>0) { tim_ielen += 2; @@ -98,12 +98,16 @@ static void update_BCNTIM(struct rtw_adapter *padapter) offset = _FIXED_IE_LENGTH_; /* get ssid_ie len */ - p = rtw_get_ie23a(pie + _BEACON_IE_OFFSET_, _SSID_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)); + p = rtw_get_ie23a(pie + _BEACON_IE_OFFSET_, WLAN_EID_SSID, + &tmp_len, (pnetwork_mlmeext->IELength - + _BEACON_IE_OFFSET_)); if (p != NULL) offset += tmp_len+2; /* get supported rates len */ - p = rtw_get_ie23a(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)); + p = rtw_get_ie23a(pie + _BEACON_IE_OFFSET_, WLAN_EID_SUPP_RATES, + &tmp_len, (pnetwork_mlmeext->IELength - + _BEACON_IE_OFFSET_)); if (p != NULL) offset += tmp_len+2; @@ -124,7 +128,7 @@ static void update_BCNTIM(struct rtw_adapter *padapter) memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); } - *dst_ie++= _TIM_IE_; + *dst_ie++= WLAN_EID_TIM; if ((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fc)) tim_ielen = 5; @@ -248,7 +252,7 @@ void expire_timeout_chk23a(struct rtw_adapter *padapter) /* to update bcn with tim_bitmap for this station */ pstapriv->tim_bitmap |= CHKBIT(psta->aid); - update_beacon23a(padapter, _TIM_IE_, NULL, false); + update_beacon23a(padapter, WLAN_EID_TIM, NULL, false); if (!pmlmeext->active_keep_alive_check) continue; @@ -357,7 +361,7 @@ void add_RATid23a(struct rtw_adapter *padapter, struct sta_info *psta, u8 rssi_l unsigned int tx_ra_bitmap = 0; struct ht_priv *psta_ht = NULL; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; + struct wlan_bssid_ex *pcur_network = &pmlmepriv->cur_network.network; if (psta) psta_ht = &psta->htpriv; @@ -374,9 +378,9 @@ void add_RATid23a(struct rtw_adapter *padapter, struct sta_info *psta, u8 rssi_l tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value23a(psta->bssrateset[i]&0x7f); } /* n mode ra_bitmap */ - if (psta_ht->ht_option) - { - rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + if (psta_ht->ht_option) { + rf_type = rtl8723a_get_rf_type(padapter); + if (rf_type == RF_2T2R) limit = 16;/* 2R */ else @@ -455,7 +459,7 @@ static void update_bmc_sta(struct rtw_adapter *padapter) int i, supportRateNum = 0; unsigned int tx_ra_bitmap = 0; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; + struct wlan_bssid_ex *pcur_network = &pmlmepriv->cur_network.network; struct sta_info *psta = rtw_get_bcmc_stainfo23a(padapter); if (psta) @@ -523,8 +527,6 @@ static void update_bmc_sta(struct rtw_adapter *padapter) psta->raid = raid; psta->init_rate = init_rate; - rtw_stassoc_hw_rpt23a(padapter, psta); - spin_lock_bh(&psta->lock); psta->state = _FW_LINKED; spin_unlock_bh(&psta->lock); @@ -632,9 +634,8 @@ static void update_hw_ht_param(struct rtw_adapter *padapter) min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; - rtw_hal_set_hwreg23a(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); - - rtw_hal_set_hwreg23a(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); + rtl8723a_set_ampdu_min_space(padapter, min_MPDU_spacing); + rtl8723a_set_ampdu_factor(padapter, max_AMPDU_len); /* Config SM Power Save setting */ pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2; @@ -644,22 +645,18 @@ static void update_hw_ht_param(struct rtw_adapter *padapter) static void start_bss_network(struct rtw_adapter *padapter, u8 *pbuf) { - u8 *p; + const u8 *p; u8 val8, cur_channel, cur_bwmode, cur_ch_offset; u16 bcn_interval; u32 acparm; - int ie_len; struct registry_priv *pregpriv = &padapter->registrypriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct security_priv* psecuritypriv = &padapter->securitypriv; - struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; + struct wlan_bssid_ex *pnetwork = &pmlmepriv->cur_network.network; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network; struct HT_info_element *pht_info = NULL; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif /* CONFIG_8723AU_P2P */ bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod; cur_channel = pnetwork->Configuration.DSConfig; @@ -695,27 +692,28 @@ static void start_bss_network(struct rtw_adapter *padapter, u8 *pbuf) Set_MSR23a(padapter, _HW_STATE_AP_); /* Set BSSID REG */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, pnetwork->MacAddress); + hw_var_set_bssid(padapter, pnetwork->MacAddress); /* Set EDCA param reg */ acparm = 0x002F3217; /* VO */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm)); + rtl8723a_set_ac_param_vo(padapter, acparm); acparm = 0x005E4317; /* VI */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm)); + rtl8723a_set_ac_param_vi(padapter, acparm); acparm = 0x005ea42b; - rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); + rtl8723a_set_ac_param_be(padapter, acparm); acparm = 0x0000A444; /* BK */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm)); + rtl8723a_set_ac_param_bk(padapter, acparm); /* Set Security */ - val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)? 0xcc: 0xcf; - rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ? + 0xcc: 0xcf; + rtl8723a_set_sec_cfg(padapter, val8); /* Beacon Control related register */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval)); + rtl8723a_set_beacon_interval(padapter, bcn_interval); UpdateBrateTbl23a(padapter, pnetwork->SupportedRates); - rtw_hal_set_hwreg23a(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates); + HalSetBrateCfg23a(padapter, pnetwork->SupportedRates); if (!pmlmepriv->cur_network.join_res) { /* setting only at first time */ @@ -723,21 +721,25 @@ static void start_bss_network(struct rtw_adapter *padapter, u8 *pbuf) /* disable dynamic functions, such as high power, DIG */ /* turn on all dynamic functions */ - Switch_DM_Func23a(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); + rtl8723a_odm_support_ability_set(padapter, + DYNAMIC_ALL_FUNC_ENABLE); } /* set channel, bwmode */ - p = rtw_get_ie23a((pnetwork->IEs + sizeof(struct ndis_802_11_fixed_ies)), - _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - - sizeof(struct ndis_802_11_fixed_ies))); - if (p && ie_len) { - pht_info = (struct HT_info_element *)(p+2); - - if ((pregpriv->cbw40_enable) && (pht_info->infos[0] & BIT(2))) { + p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, + pnetwork->IEs + + sizeof(struct ndis_802_11_fixed_ies), + pnetwork->IELength - + sizeof(struct ndis_802_11_fixed_ies)); + if (p && p[1]) { + pht_info = (struct HT_info_element *)(p + 2); + + if (pregpriv->cbw40_enable && pht_info->infos[0] & BIT(2)) { /* switch to the 40M Hz mode */ cur_bwmode = HT_CHANNEL_WIDTH_40; switch (pht_info->infos[0] & 0x3) { case 1: - /* pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; */ + /* pmlmeext->cur_ch_offset = + HAL_PRIME_CHNL_OFFSET_LOWER; */ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; break; case 3: @@ -764,19 +766,13 @@ static void start_bss_network(struct rtw_adapter *padapter, u8 *pbuf) update_wireless_mode23a(padapter); /* udpate capability after cur_wireless_mode updated */ - update_capinfo23a(padapter, rtw_get_capability23a((struct wlan_bssid_ex *)pnetwork)); + update_capinfo23a(padapter, rtw_get_capability23a(pnetwork)); /* let pnetwork_mlmeext == pnetwork_mlme. */ memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length); -#ifdef CONFIG_8723AU_P2P - memcpy(pwdinfo->p2p_group_ssid, pnetwork->Ssid.ssid, - pnetwork->Ssid.ssid_len); - pwdinfo->p2p_group_ssid_len = pnetwork->Ssid.ssid_len; -#endif /* CONFIG_8723AU_P2P */ - if (pmlmeext->bstart_bss) { - update_beacon23a(padapter, _TIM_IE_, NULL, false); + update_beacon23a(padapter, WLAN_EID_TIM, NULL, false); /* issue beacon frame */ if (send_beacon23a(padapter) == _FAIL) @@ -787,19 +783,20 @@ static void start_bss_network(struct rtw_adapter *padapter, u8 *pbuf) update_bmc_sta(padapter); } -int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) +int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, + unsigned int len) { int ret = _SUCCESS; u8 *p; u8 *pHT_caps_ie = NULL; u8 *pHT_info_ie = NULL; struct sta_info *psta = NULL; + __le16 *pbeacon; u16 cap, ht_cap = false; uint ie_len = 0; int group_cipher, pairwise_cipher; u8 channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX]; int supportRateNum = 0; - u8 OUI1[] = {0x00, 0x50, 0xf2, 0x01}; u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; struct registry_priv *pregistrypriv = &padapter->registrypriv; struct security_priv *psecuritypriv = &padapter->securitypriv; @@ -823,7 +820,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) if (!check_fwstate(pmlmepriv, WIFI_AP_STATE)) return _FAIL; - if (len>MAX_IE_SZ) + if (len > MAX_IE_SZ) return _FAIL; pbss_network->IELength = len; @@ -841,14 +838,14 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) /* beacon interval */ /* ie + 8; 8: TimeStamp, 2: Beacon Interval 2:Capability */ - p = rtw_get_beacon_interval23a_from_ie(ie); - pbss_network->Configuration.BeaconPeriod = get_unaligned_le16(p); + pbeacon = rtw_get_beacon_interval23a_from_ie(ie); + pbss_network->Configuration.BeaconPeriod = get_unaligned_le16(pbeacon); /* capability */ cap = get_unaligned_le16(ie); /* SSID */ - p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, WLAN_EID_SSID, &ie_len, (pbss_network->IELength -_BEACON_IE_OFFSET_)); if (p && ie_len > 0) { memset(&pbss_network->Ssid, 0, sizeof(struct cfg80211_ssid)); @@ -859,7 +856,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) /* chnnel */ channel = 0; pbss_network->Configuration.Length = 0; - p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, WLAN_EID_DS_PARAMS, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); if (p && ie_len > 0) channel = *(p + 2); @@ -868,7 +865,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX); /* get supported rates */ - p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, WLAN_EID_SUPP_RATES, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); if (p) { memcpy(supportRate, p+2, ie_len); @@ -876,7 +873,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) } /* get ext_supported rates */ - p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, WLAN_EID_EXT_SUPP_RATES, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_); if (p) { memcpy(supportRate+supportRateNum, p+2, ie_len); @@ -889,7 +886,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) rtw_set_supported_rate23a(pbss_network->SupportedRates, network_type); /* parsing ERP_IE */ - p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, WLAN_EID_ERP_INFO, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); if (p && ie_len > 0) ERP_IE_handler23a(padapter, (struct ndis_802_11_var_ies *)p); @@ -906,7 +903,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) group_cipher = 0; pairwise_cipher = 0; psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_; psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_; - p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, WLAN_EID_RSN, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); if (p && ie_len > 0) { if (rtw_parse_wpa2_ie23a(p, ie_len+2, &group_cipher, @@ -928,10 +925,10 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) psecuritypriv->wpa_group_cipher = _NO_PRIVACY_; psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_; for (p = ie + _BEACON_IE_OFFSET_; ;p += (ie_len + 2)) { - p = rtw_get_ie23a(p, _SSN_IE_1_, &ie_len, + p = rtw_get_ie23a(p, WLAN_EID_VENDOR_SPECIFIC, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); - if ((p) && (!memcmp(p+2, OUI1, 4))) { + if ((p) && (!memcmp(p+2, RTW_WPA_OUI23A_TYPE, 4))) { if (rtw_parse_wpa_ie23a(p, ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; @@ -956,7 +953,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) pmlmepriv->qospriv.qos_option = 0; if (pregistrypriv->wmm_enable) { for (p = ie + _BEACON_IE_OFFSET_; ;p += (ie_len + 2)) { - p = rtw_get_ie23a(p, _VENDOR_SPECIFIC_IE_, &ie_len, + p = rtw_get_ie23a(p, WLAN_EID_VENDOR_SPECIFIC, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); if ((p) && !memcmp(p+2, WMM_PARA_IE, 6)) { @@ -978,7 +975,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) } } /* parsing HT_CAP_IE */ - p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, WLAN_EID_HT_CAPABILITY, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); if (p && ie_len > 0) { u8 rf_type; @@ -990,7 +987,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) ht_cap = true; network_type |= WIRELESS_11_24N; - rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + rf_type = rtl8723a_get_rf_type(padapter); if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) || (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP)) @@ -1010,7 +1007,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) } /* parsing HT_INFO_IE */ - p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, WLAN_EID_HT_OPERATION, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); if (p && ie_len > 0) pHT_info_ie = p; @@ -1050,7 +1047,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) HT_info_handler23a(padapter, (struct ndis_802_11_var_ies *)pHT_info_ie); } - pbss_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pbss_network); + pbss_network->Length = get_wlan_bssid_ex_sz(pbss_network); /* issue beacon to start bss network */ start_bss_network(padapter, (u8*)pbss_network); @@ -1200,7 +1197,7 @@ static void update_bcn_erpinfo_ie(struct rtw_adapter *padapter) return; /* parsing ERP_IE */ - p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, WLAN_EID_ERP_INFO, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); if (p && len>0) { struct ndis_802_11_var_ies * pIE = (struct ndis_802_11_var_ies *)p; @@ -1306,26 +1303,16 @@ static void update_bcn_vendor_spec_ie(struct rtw_adapter *padapter, u8*oui) { DBG_8723A("%s\n", __func__); - if (!memcmp(RTW_WPA_OUI23A, oui, 4)) - { + if (!memcmp(RTW_WPA_OUI23A_TYPE, oui, 4)) update_bcn_wpa_ie(padapter); - } else if (!memcmp(WMM_OUI23A, oui, 4)) - { update_bcn_wmm_ie(padapter); - } else if (!memcmp(WPS_OUI23A, oui, 4)) - { update_bcn_wps_ie(padapter); - } else if (!memcmp(P2P_OUI23A, oui, 4)) - { update_bcn_p2p_ie(padapter); - } else - { DBG_8723A("unknown OUI type!\n"); - } } void update_beacon23a(struct rtw_adapter *padapter, u8 ie_id, u8 *oui, u8 tx) @@ -1350,50 +1337,37 @@ void update_beacon23a(struct rtw_adapter *padapter, u8 ie_id, u8 *oui, u8 tx) switch (ie_id) { - case 0xFF: - - update_bcn_fixed_ie(padapter);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */ - - break; - - case _TIM_IE_: - - update_BCNTIM(padapter); - - break; - - case _ERPINFO_IE_: - - update_bcn_erpinfo_ie(padapter); - - break; - - case _HT_CAPABILITY_IE_: - - update_bcn_htcap_ie(padapter); - - break; - - case _RSN_IE_2_: - - update_bcn_rsn_ie(padapter); - - break; + case 0xFF: + /* 8: TimeStamp, 2: Beacon Interval 2:Capability */ + update_bcn_fixed_ie(padapter); + break; - case _HT_ADD_INFO_IE_: + case WLAN_EID_TIM: + update_BCNTIM(padapter); + break; - update_bcn_htinfo_ie(padapter); + case WLAN_EID_ERP_INFO: + update_bcn_erpinfo_ie(padapter); + break; - break; + case WLAN_EID_HT_CAPABILITY: + update_bcn_htcap_ie(padapter); + break; - case _VENDOR_SPECIFIC_IE_: + case WLAN_EID_RSN: + update_bcn_rsn_ie(padapter); + break; - update_bcn_vendor_spec_ie(padapter, oui); + case WLAN_EID_HT_OPERATION: + update_bcn_htinfo_ie(padapter); + break; - break; + case WLAN_EID_VENDOR_SPECIFIC: + update_bcn_vendor_spec_ie(padapter, oui); + break; - default: - break; + default: + break; } pmlmepriv->update_bcn = true; @@ -1465,8 +1439,9 @@ static int rtw_ht_operation_update(struct rtw_adapter *padapter) if (pmlmepriv->num_sta_no_ht || (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)) new_op_mode = OP_MODE_MIXED; - else if ((phtpriv_ap->ht_cap.cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40) - && pmlmepriv->num_sta_ht_20mhz) + else if ((le16_to_cpu(phtpriv_ap->ht_cap.cap_info) & + IEEE80211_HT_CAP_SUP_WIDTH_20_40) && + pmlmepriv->num_sta_ht_20mhz) new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED; else if (pmlmepriv->olbc_ht) new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS; @@ -1562,7 +1537,7 @@ void bss_cap_update_on_sta_join23a(struct rtw_adapter *padapter, struct sta_info if (pmlmepriv->num_sta_non_erp == 1) { beacon_updated = true; - update_beacon23a(padapter, _ERPINFO_IE_, NULL, true); + update_beacon23a(padapter, WLAN_EID_ERP_INFO, NULL, true); } } @@ -1578,7 +1553,7 @@ void bss_cap_update_on_sta_join23a(struct rtw_adapter *padapter, struct sta_info if (pmlmepriv->num_sta_non_erp == 0) { beacon_updated = true; - update_beacon23a(padapter, _ERPINFO_IE_, NULL, true); + update_beacon23a(padapter, WLAN_EID_ERP_INFO, NULL, true); } } @@ -1669,8 +1644,8 @@ void bss_cap_update_on_sta_join23a(struct rtw_adapter *padapter, struct sta_info if (rtw_ht_operation_update(padapter) > 0) { - update_beacon23a(padapter, _HT_CAPABILITY_IE_, NULL, false); - update_beacon23a(padapter, _HT_ADD_INFO_IE_, NULL, true); + update_beacon23a(padapter, WLAN_EID_HT_CAPABILITY, NULL, false); + update_beacon23a(padapter, WLAN_EID_HT_OPERATION, NULL, true); } /* update associcated stations cap. */ @@ -1705,7 +1680,8 @@ u8 bss_cap_update_on_sta_leave23a(struct rtw_adapter *padapter, struct sta_info if (pmlmepriv->num_sta_non_erp == 0) { beacon_updated = true; - update_beacon23a(padapter, _ERPINFO_IE_, NULL, true); + update_beacon23a(padapter, WLAN_EID_ERP_INFO, + NULL, true); } } @@ -1737,8 +1713,8 @@ u8 bss_cap_update_on_sta_leave23a(struct rtw_adapter *padapter, struct sta_info if (rtw_ht_operation_update(padapter) > 0) { - update_beacon23a(padapter, _HT_CAPABILITY_IE_, NULL, false); - update_beacon23a(padapter, _HT_ADD_INFO_IE_, NULL, true); + update_beacon23a(padapter, WLAN_EID_HT_CAPABILITY, NULL, false); + update_beacon23a(padapter, WLAN_EID_HT_OPERATION, NULL, true); } /* update associcated stations cap. */ diff --git a/drivers/staging/rtl8723au/core/rtw_cmd.c b/drivers/staging/rtl8723au/core/rtw_cmd.c index 5e3088a01800d5..5b3ac69011470a 100644 --- a/drivers/staging/rtl8723au/core/rtw_cmd.c +++ b/drivers/staging/rtl8723au/core/rtw_cmd.c @@ -17,8 +17,8 @@ #include #include #include -#include #include +#include #ifdef CONFIG_8723AU_BT_COEXIST #include @@ -175,13 +175,6 @@ int rtw_init_cmd_priv23a(struct cmd_priv *pcmdpriv) { int res = _SUCCESS; - sema_init(&pcmdpriv->cmd_queue_sema, 0); - sema_init(&pcmdpriv->terminate_cmdthread_sema, 0); - - _rtw_init_queue23a(&pcmdpriv->cmd_queue); - - pcmdpriv->cmd_seq = 1; - pcmdpriv->cmd_allocated_buf = kzalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ, GFP_KERNEL); @@ -208,6 +201,11 @@ int rtw_init_cmd_priv23a(struct cmd_priv *pcmdpriv) pcmdpriv->cmd_done_cnt = 0; pcmdpriv->rsp_cnt = 0; + + pcmdpriv->wq = alloc_workqueue("rtl8723au", 0, 1); + if (!pcmdpriv->wq) + res = _FAIL; + exit: return res; @@ -216,10 +214,9 @@ int rtw_init_cmd_priv23a(struct cmd_priv *pcmdpriv) /* forward definition */ static void c2h_wk_callback(struct work_struct *work); -int _rtw_init_evt_priv23a(struct evt_priv *pevtpriv) -{ - int res = _SUCCESS; +u32 rtw_init_evt_priv23a(struct evt_priv *pevtpriv) +{ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ atomic_set(&pevtpriv->event_seq, 0); pevtpriv->evt_done_cnt = 0; @@ -228,15 +225,13 @@ int _rtw_init_evt_priv23a(struct evt_priv *pevtpriv) pevtpriv->c2h_wk_alive = false; pevtpriv->c2h_queue = rtw_cbuf_alloc23a(C2H_QUEUE_MAX_LEN + 1); - return res; + return _SUCCESS; } -void _rtw_free_evt_priv23a (struct evt_priv *pevtpriv) +void rtw_free_evt_priv23a(struct evt_priv *pevtpriv) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, - ("+_rtw_free_evt_priv23a\n")); cancel_work_sync(&pevtpriv->c2h_wk); - while(pevtpriv->c2h_wk_alive) + while (pevtpriv->c2h_wk_alive) msleep(10); while (!rtw_cbuf_empty23a(pevtpriv->c2h_queue)) { @@ -246,68 +241,19 @@ void _rtw_free_evt_priv23a (struct evt_priv *pevtpriv) kfree(c2h); } } - - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, - ("-_rtw_free_evt_priv23a\n")); } -void _rtw_free_cmd_priv23a(struct cmd_priv *pcmdpriv) +void rtw_free_cmd_priv23a(struct cmd_priv *pcmdpriv) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, + ("rtw_free_cmd_priv23a\n")); + if (pcmdpriv) { kfree(pcmdpriv->cmd_allocated_buf); kfree(pcmdpriv->rsp_allocated_buf); } } -/* -Calling Context: -rtw_enqueue_cmd23a can only be called between kernel thread, -since only spin_lock is used. - -ISR/Call-Back functions can't call this sub-function. -*/ - -int _rtw_enqueue_cmd23a(struct rtw_queue *queue, struct cmd_obj *obj) -{ - unsigned long irqL; - - if (obj == NULL) - goto exit; - - spin_lock_irqsave(&queue->lock, irqL); - - list_add_tail(&obj->list, &queue->queue); - - spin_unlock_irqrestore(&queue->lock, irqL); - -exit: - - return _SUCCESS; -} - -u32 rtw_init_evt_priv23a(struct evt_priv *pevtpriv) -{ - int res; - - res = _rtw_init_evt_priv23a(pevtpriv); - - return res; -} - -void rtw_free_evt_priv23a(struct evt_priv *pevtpriv) -{ - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, - ("rtw_free_evt_priv23a\n")); - _rtw_free_evt_priv23a(pevtpriv); -} - -void rtw_free_cmd_priv23a(struct cmd_priv *pcmdpriv) -{ - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, - ("rtw_free_cmd_priv23a\n")); - _rtw_free_cmd_priv23a(pcmdpriv); -} - static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) { struct drvextra_cmd_parm *pdrvextra_cmd_parm; @@ -329,21 +275,21 @@ static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan)) bAllow = true; - if ((pcmdpriv->padapter->hw_init_completed == false && - bAllow == false) || pcmdpriv->cmdthd_running == false) + if (pcmdpriv->padapter->hw_init_completed == false && bAllow == false) return _FAIL; return _SUCCESS; } -u32 rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) +static void rtw_cmd_work(struct work_struct *work); + +int rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) { int res = _FAIL; - struct rtw_adapter *padapter = pcmdpriv->padapter; if (!cmd_obj) goto exit; - cmd_obj->padapter = padapter; + cmd_obj->padapter = pcmdpriv->padapter; res = rtw_cmd_filter(pcmdpriv, cmd_obj); if (res == _FAIL) { @@ -351,32 +297,18 @@ u32 rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) goto exit; } - res = _rtw_enqueue_cmd23a(&pcmdpriv->cmd_queue, cmd_obj); + INIT_WORK(&cmd_obj->work, rtw_cmd_work); - if (res == _SUCCESS) - up(&pcmdpriv->cmd_queue_sema); + res = queue_work(pcmdpriv->wq, &cmd_obj->work); + if (!res) { + printk(KERN_ERR "%s: Call to queue_work() failed\n", __func__); + res = _FAIL; + } else + res = _SUCCESS; exit: - return res; -} - -static struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv) -{ - struct cmd_obj *obj; - struct rtw_queue *queue = &pcmdpriv->cmd_queue; - unsigned long irqL; - - spin_lock_irqsave(&queue->lock, irqL); - if (list_empty(&queue->queue)) - obj = NULL; - else { - obj = container_of((&queue->queue)->next, struct cmd_obj, list); - list_del_init(&obj->list); - } - - spin_unlock_irqrestore(&queue->lock, irqL); - return obj; + return res; } void rtw_cmd_clr_isr23a(struct cmd_priv *pcmdpriv) @@ -403,116 +335,65 @@ void rtw_free_cmd_obj23a(struct cmd_obj *pcmd) kfree(pcmd); } -int rtw_cmd_thread23a(void *context) +static void rtw_cmd_work(struct work_struct *work) { - u8 ret; - struct cmd_obj *pcmd; - u8 *pcmdbuf, *prspbuf; - u8 (*cmd_hdl)(struct rtw_adapter *padapter, u8* pbuf); + u8 (*cmd_hdl)(struct rtw_adapter *padapter, const u8 *pbuf); void (*pcmd_callback)(struct rtw_adapter *dev, struct cmd_obj *pcmd); - struct rtw_adapter *padapter = (struct rtw_adapter *)context; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - - allow_signal(SIGTERM); + struct cmd_priv *pcmdpriv; + struct cmd_obj *pcmd = container_of(work, struct cmd_obj, work); + u8 *pcmdbuf; + pcmdpriv = &pcmd->padapter->cmdpriv; pcmdbuf = pcmdpriv->cmd_buf; - prspbuf = pcmdpriv->rsp_buf; - - pcmdpriv->cmdthd_running = true; - up(&pcmdpriv->terminate_cmdthread_sema); - - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, - ("start r871x rtw_cmd_thread23a !!!!\n")); - - while(1) { - if (down_interruptible(&pcmdpriv->cmd_queue_sema)) - break; -_next: - if ((padapter->bDriverStopped == true) || - (padapter->bSurpriseRemoved == true)) { - DBG_8723A("%s: DriverStopped(%d) SurpriseRemoved(%d) " - "break at line %d\n", __func__, - padapter->bDriverStopped, - padapter->bSurpriseRemoved, __LINE__); - break; - } - if (!(pcmd = rtw_dequeue_cmd(pcmdpriv))) - continue; - - if (rtw_cmd_filter(pcmdpriv, pcmd) == _FAIL) { - pcmd->res = H2C_DROPPED; - goto post_process; - } - - pcmdpriv->cmd_issued_cnt++; - - pcmd->cmdsz = ALIGN(pcmd->cmdsz, 4); + if (rtw_cmd_filter(pcmdpriv, pcmd) == _FAIL) { + pcmd->res = H2C_DROPPED; + goto post_process; + } - memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); + pcmdpriv->cmd_issued_cnt++; - if (pcmd->cmdcode < (sizeof(wlancmds)/sizeof(struct cmd_hdl))) { - cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns; + pcmd->cmdsz = ALIGN(pcmd->cmdsz, 4); - if (cmd_hdl) { - ret = cmd_hdl(pcmd->padapter, pcmdbuf); - pcmd->res = ret; - } + memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); - pcmdpriv->cmd_seq++; - } else - pcmd->res = H2C_PARAMETERS_ERROR; + if (pcmd->cmdcode < (sizeof(wlancmds)/sizeof(struct cmd_hdl))) { + cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns; - cmd_hdl = NULL; + if (cmd_hdl) + pcmd->res = cmd_hdl(pcmd->padapter, pcmdbuf); + else + pcmd->res = H2C_DROPPED; + } else + pcmd->res = H2C_PARAMETERS_ERROR; post_process: - /* call callback function for post-processed */ - if (pcmd->cmdcode < (sizeof(rtw_cmd_callback) / - sizeof(struct _cmd_callback))) { - pcmd_callback = - rtw_cmd_callback[pcmd->cmdcode].callback; - if (!pcmd_callback) { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, - ("mlme_cmd_hdl(): pcmd_callback = " - "0x%p, cmdcode = 0x%x\n", - pcmd_callback, pcmd->cmdcode)); - rtw_free_cmd_obj23a(pcmd); - } else { - /* todo: !!! fill rsp_buf to pcmd->rsp - if (pcmd->rsp!= NULL) */ - /* need conider that free cmd_obj in - rtw_cmd_callback */ - pcmd_callback(pcmd->padapter, pcmd); - } - } else { - RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, - ("%s: cmdcode = 0x%x callback not defined!\n", - __func__, pcmd->cmdcode)); + /* call callback function for post-processed */ + if (pcmd->cmdcode < (sizeof(rtw_cmd_callback) / + sizeof(struct _cmd_callback))) { + pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback; + if (!pcmd_callback) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, + ("mlme_cmd_hdl(): pcmd_callback = 0x%p, " + "cmdcode = 0x%x\n", + pcmd_callback, pcmd->cmdcode)); rtw_free_cmd_obj23a(pcmd); + } else { + /* todo: !!! fill rsp_buf to pcmd->rsp + if (pcmd->rsp!= NULL) */ + /* need conider that free cmd_obj in + rtw_cmd_callback */ + pcmd_callback(pcmd->padapter, pcmd); } - - if (signal_pending (current)) - flush_signals(current); - - goto _next; - - } - pcmdpriv->cmdthd_running = false; - - /* free all cmd_obj resources */ - do { - pcmd = rtw_dequeue_cmd(pcmdpriv); - if (!pcmd) - break; - + } else { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, + ("%s: cmdcode = 0x%x callback not defined!\n", + __func__, pcmd->cmdcode)); rtw_free_cmd_obj23a(pcmd); - } while(1); - - up(&pcmdpriv->terminate_cmdthread_sema); - - complete_and_exit(NULL, 0); + } } + u8 rtw_sitesurvey_cmd23a(struct rtw_adapter *padapter, struct cfg80211_ssid *ssid, int ssid_num, struct rtw_ieee80211_channel *ch, int ch_num) @@ -526,12 +407,6 @@ u8 rtw_sitesurvey_cmd23a(struct rtw_adapter *padapter, if (check_fwstate(pmlmepriv, _FW_LINKED) == true) rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_SCAN, 1); -#ifdef CONFIG_8723AU_P2P - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { - p2p_ps_wk_cmd23a(padapter, P2P_PS_SCAN, 1); - } -#endif /* CONFIG_8723AU_P2P */ - ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); if (!ph2c) return _FAIL; @@ -542,7 +417,7 @@ u8 rtw_sitesurvey_cmd23a(struct rtw_adapter *padapter, return _FAIL; } - rtw_free_network_queue23a(padapter, false); + rtw_free_network_queue23a(padapter); RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("%s: flush network queue\n", __func__)); @@ -639,10 +514,9 @@ u8 rtw_createbss_cmd23a(struct rtw_adapter *padapter) goto exit; } - INIT_LIST_HEAD(&pcmd->list); pcmd->cmdcode = _CreateBss_CMD_; pcmd->parmbuf = (unsigned char *)pdev_network; - pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex*)pdev_network); + pcmd->cmdsz = get_wlan_bssid_ex_sz(pdev_network); pcmd->rsp = NULL; pcmd->rspsz = 0; @@ -656,10 +530,9 @@ u8 rtw_createbss_cmd23a(struct rtw_adapter *padapter) } u8 rtw_joinbss_cmd23a(struct rtw_adapter *padapter, - struct wlan_network * pnetwork) + struct wlan_network *pnetwork) { u8 *auth, res = _SUCCESS; - uint t_len = 0; struct wlan_bssid_ex *psecnetwork; struct cmd_obj *pcmd; struct cmd_priv *pcmdpriv = &padapter->cmdpriv; @@ -693,8 +566,6 @@ u8 rtw_joinbss_cmd23a(struct rtw_adapter *padapter, "fail!!!\n")); goto exit; } - /* for IEs is fix buf size */ - t_len = sizeof(struct wlan_bssid_ex); /* for hidden ap to set fw_state here */ if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE)) { @@ -712,7 +583,7 @@ u8 rtw_joinbss_cmd23a(struct rtw_adapter *padapter, } } - psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss; + psecnetwork = &psecuritypriv->sec_bss; if (!psecnetwork) { if (pcmd) kfree(pcmd); @@ -725,7 +596,7 @@ u8 rtw_joinbss_cmd23a(struct rtw_adapter *padapter, goto exit; } - memset(psecnetwork, 0, t_len); + memset(psecnetwork, 0, sizeof(struct wlan_bssid_ex)); memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network)); @@ -813,7 +684,6 @@ u8 rtw_joinbss_cmd23a(struct rtw_adapter *padapter, /* get cmdsz before endian conversion */ pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork); - INIT_LIST_HEAD(&pcmd->list); pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */ pcmd->parmbuf = (unsigned char *)psecnetwork; pcmd->rsp = NULL; @@ -1213,7 +1083,7 @@ static void traffic_status_watchdog(struct rtw_adapter *padapter) pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic; } -void dynamic_chk_wk_hdl(struct rtw_adapter *padapter, u8 *pbuf, int sz) +static void dynamic_chk_wk_hdl(struct rtw_adapter *padapter, u8 *pbuf, int sz) { struct mlme_priv *pmlmepriv; @@ -1240,7 +1110,7 @@ void dynamic_chk_wk_hdl(struct rtw_adapter *padapter, u8 *pbuf, int sz) #endif } -void lps_ctrl_wk_hdl(struct rtw_adapter *padapter, u8 lps_ctrl_type) +static void lps_ctrl_wk_hdl(struct rtw_adapter *padapter, u8 lps_ctrl_type) { struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -1269,8 +1139,7 @@ void lps_ctrl_wk_hdl(struct rtw_adapter *padapter, u8 lps_ctrl_type) mstatus = 1;/* connect */ /* Reset LPS Setting */ padapter->pwrctrlpriv.LpsIdleCount = 0; - rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_JOINBSSRPT, - (u8 *)&mstatus); + rtl8723a_set_FwJoinBssReport_cmd(padapter, 1); #ifdef CONFIG_8723AU_BT_COEXIST BT_WifiMediaStatusNotify(padapter, mstatus); #endif @@ -1284,8 +1153,7 @@ void lps_ctrl_wk_hdl(struct rtw_adapter *padapter, u8 lps_ctrl_type) { LPS_Leave23a(padapter); } - rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_JOINBSSRPT, - (u8 *)&mstatus); + rtl8723a_set_FwJoinBssReport_cmd(padapter, 0); break; case LPS_CTRL_SPECIAL_PACKET: pwrpriv->DelayLPSLastTimeStamp = jiffies; @@ -1355,48 +1223,6 @@ static void power_saving_wk_hdl(struct rtw_adapter *padapter, u8 *pbuf, int sz) rtw_ps_processor23a(padapter); } -#ifdef CONFIG_8723AU_P2P -u8 p2p_protocol_wk_cmd23a(struct rtw_adapter*padapter, int intCmdType) -{ - struct cmd_obj *ph2c; - struct drvextra_cmd_parm *pdrvextra_cmd_parm; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - u8 res = _SUCCESS; - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) - { - return res; - } - - ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); - if (!ph2c) { - res = _FAIL; - goto exit; - } - - pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), - GFP_ATOMIC); - if (!pdrvextra_cmd_parm) { - kfree(ph2c); - res = _FAIL; - goto exit; - } - - pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID; - pdrvextra_cmd_parm->type_size = intCmdType; /* As the command tppe. */ - pdrvextra_cmd_parm->pbuf = NULL; /* Must be NULL here */ - - init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, - GEN_CMD_CODE(_Set_Drv_Extra)); - - res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); -exit: - - return res; -} -#endif /* CONFIG_8723AU_P2P */ - u8 rtw_ps_cmd23a(struct rtw_adapter*padapter) { struct cmd_obj *ppscmd; @@ -1443,11 +1269,11 @@ static void rtw_chk_hi_queue_hdl(struct rtw_adapter *padapter) return; if (psta_bmc->sleepq_len == 0) { - u8 val = 0; + bool val; - rtw23a_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val); + val = rtl8723a_chk_hi_queue_empty(padapter); - while(val == false) { + while (val == false) { msleep(100); cnt++; @@ -1455,15 +1281,14 @@ static void rtw_chk_hi_queue_hdl(struct rtw_adapter *padapter) if (cnt>10) break; - rtw23a_hal_get_hwreg(padapter, - HW_VAR_CHK_HI_QUEUE_EMPTY, &val); + val = rtl8723a_chk_hi_queue_empty(padapter); } if (cnt <= 10) { pstapriv->tim_bitmap &= ~BIT(0); pstapriv->sta_dz_bitmap &= ~BIT(0); - update_beacon23a(padapter, _TIM_IE_, NULL, false); + update_beacon23a(padapter, WLAN_EID_TIM, NULL, false); } else /* re check again */ rtw_chk_hi_queue_cmd23a(padapter); } @@ -1586,7 +1411,9 @@ static void c2h_wk_callback(struct work_struct *work) /* This C2H event is read, clear it */ c2h_evt_clear23a(adapter); } else if ((c2h_evt = (struct c2h_evt_hdr *) - kmalloc(16, GFP_ATOMIC))) { + kmalloc(16, GFP_KERNEL))) { + if (!c2h_evt) + continue; /* This C2H event is not read, read & clear now */ if (c2h_evt_read23a(adapter, (u8*)c2h_evt) != _SUCCESS) continue; @@ -1614,9 +1441,9 @@ static void c2h_wk_callback(struct work_struct *work) evtpriv->c2h_wk_alive = false; } -u8 rtw_drvextra_cmd_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +u8 rtw_drvextra_cmd_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { - struct drvextra_cmd_parm *pdrvextra_cmd; + const struct drvextra_cmd_parm *pdrvextra_cmd; if (!pbuf) return H2C_PARAMETERS_ERROR; @@ -1636,16 +1463,6 @@ u8 rtw_drvextra_cmd_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) case LPS_CTRL_WK_CID: lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size); break; -#ifdef CONFIG_8723AU_P2P - case P2P_PS_WK_CID: - p2p_ps_wk_hdl23a(padapter, pdrvextra_cmd->type_size); - break; - case P2P_PROTO_WK_CID: - /* Commented by Albert 2011/07/01 */ - /* I used the type_size as the type command */ - p2p_protocol_wk_hdl23a(padapter, pdrvextra_cmd->type_size); - break; -#endif /* CONFIG_8723AU_P2P */ #ifdef CONFIG_8723AU_AP_MODE case CHECK_HIQ_WK_CID: rtw_chk_hi_queue_hdl(padapter); @@ -1662,7 +1479,11 @@ u8 rtw_drvextra_cmd_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) if (pdrvextra_cmd->pbuf && (pdrvextra_cmd->type_size > 0)) { kfree(pdrvextra_cmd->pbuf); - pdrvextra_cmd->pbuf = NULL; + /* + * No need to set pdrvextra_cmd->pbuf = NULL as we were + * operating on a copy of the original pcmd->parmbuf + * created in rtw_cmd_work(). + */ } return H2C_SUCCESS; @@ -1868,9 +1689,3 @@ void rtw_setassocsta_cmdrsp_callback23a(struct rtw_adapter *padapter, exit: rtw_free_cmd_obj23a(pcmd); } - -void rtw_getrttbl_cmd_cmdrsp_callback(struct rtw_adapter *padapter, - struct cmd_obj *pcmd) -{ - rtw_free_cmd_obj23a(pcmd); -} diff --git a/drivers/staging/rtl8723au/core/rtw_ieee80211.c b/drivers/staging/rtl8723au/core/rtw_ieee80211.c index a48ab25a7d8a25..b56055eb433be2 100644 --- a/drivers/staging/rtl8723au/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8723au/core/rtw_ieee80211.c @@ -131,7 +131,7 @@ u8 *rtw_set_fixed_ie23a(unsigned char *pbuf, unsigned int len, } /* rtw_set_ie23a will update frame length */ -u8 *rtw_set_ie23a(u8 *pbuf, int index, uint len, u8 *source, uint *frlen) +u8 *rtw_set_ie23a(u8 *pbuf, int index, uint len, const u8 *source, uint *frlen) { *pbuf = (u8)index; @@ -413,7 +413,7 @@ int rtw_generate_ie23a(struct registry_priv *pregistrypriv) ie += 2; /* SSID */ - ie = rtw_set_ie23a(ie, _SSID_IE_, pdev_network->Ssid.ssid_len, + ie = rtw_set_ie23a(ie, WLAN_EID_SSID, pdev_network->Ssid.ssid_len, pdev_network->Ssid.ssid, &sz); /* supported rates */ @@ -431,25 +431,25 @@ int rtw_generate_ie23a(struct registry_priv *pregistrypriv) rateLen = rtw_get_rateset_len23a(pdev_network->SupportedRates); if (rateLen > 8) { - ie = rtw_set_ie23a(ie, _SUPPORTEDRATES_IE_, 8, + ie = rtw_set_ie23a(ie, WLAN_EID_SUPP_RATES, 8, pdev_network->SupportedRates, &sz); /* ie = rtw_set_ie23a(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); */ } else { - ie = rtw_set_ie23a(ie, _SUPPORTEDRATES_IE_, rateLen, + ie = rtw_set_ie23a(ie, WLAN_EID_SUPP_RATES, rateLen, pdev_network->SupportedRates, &sz); } /* DS parameter set */ - ie = rtw_set_ie23a(ie, _DSSET_IE_, 1, + ie = rtw_set_ie23a(ie, WLAN_EID_DS_PARAMS, 1, (u8 *)&pdev_network->Configuration.DSConfig, &sz); /* IBSS Parameter Set */ - ie = rtw_set_ie23a(ie, _IBSS_PARA_IE_, 2, + ie = rtw_set_ie23a(ie, WLAN_EID_IBSS_PARAMS, 2, (u8 *)&pdev_network->Configuration.ATIMWindow, &sz); if (rateLen > 8) { - ie = rtw_set_ie23a(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), + ie = rtw_set_ie23a(ie, WLAN_EID_EXT_SUPP_RATES, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); } @@ -460,60 +460,7 @@ int rtw_generate_ie23a(struct registry_priv *pregistrypriv) return sz; } -unsigned char *rtw_get_wpa_ie23a(unsigned char *pie, int *wpa_ie_len, int limit) -{ - int len; - u16 val16; - unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; - u8 *pbuf = pie; - int limit_new = limit; - - while(1) { - pbuf = rtw_get_ie23a(pbuf, _WPA_IE_ID_, &len, limit_new); - - if (pbuf) { - /* check if oui matches... */ - if (memcmp((pbuf + 2), wpa_oui_type, - sizeof(wpa_oui_type))) { - goto check_next_ie; - } - - /* check version... */ - memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16)); - - val16 = le16_to_cpu(val16); - if (val16 != 0x0001) - goto check_next_ie; - - *wpa_ie_len = *(pbuf + 1); - - return pbuf; - } else { - *wpa_ie_len = 0; - return NULL; - } - -check_next_ie: - - limit_new = limit - (pbuf - pie) - 2 - len; - - if (limit_new <= 0) - break; - - pbuf += (2 + len); - } - - *wpa_ie_len = 0; - - return NULL; -} - -unsigned char *rtw_get_wpa2_ie23a(unsigned char *pie, int *rsn_ie_len, int limit) -{ - return rtw_get_ie23a(pie, _WPA2_IE_ID_, rsn_ie_len, limit); -} - -int rtw_get_wpa_cipher_suite23a(u8 *s) +int rtw_get_wpa_cipher_suite23a(const u8 *s) { if (!memcmp(s, WPA_CIPHER_SUITE_NONE23A, WPA_SELECTOR_LEN)) return WPA_CIPHER_NONE; @@ -529,7 +476,7 @@ int rtw_get_wpa_cipher_suite23a(u8 *s) return 0; } -int rtw_get_wpa2_cipher_suite23a(u8 *s) +int rtw_get_wpa2_cipher_suite23a(const u8 *s) { if (!memcmp(s, RSN_CIPHER_SUITE_NONE23A, RSN_SELECTOR_LEN)) return WPA_CIPHER_NONE; @@ -545,22 +492,19 @@ int rtw_get_wpa2_cipher_suite23a(u8 *s) return 0; } -int rtw_parse_wpa_ie23a(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) +int rtw_parse_wpa_ie23a(const u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) { int i, ret = _SUCCESS; int left, count; - u8 *pos; - u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1}; + const u8 *pos; if (wpa_ie_len <= 0) { /* No WPA IE - fail silently */ return _FAIL; } - if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie+1) != (u8)(wpa_ie_len - 2)) || - memcmp(wpa_ie + 2, RTW_WPA_OUI23A_TYPE, WPA_SELECTOR_LEN)) { + if (wpa_ie[1] != (u8)(wpa_ie_len - 2)) return _FAIL; - } pos = wpa_ie; @@ -612,7 +556,7 @@ int rtw_parse_wpa_ie23a(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pair if (is_8021x) { if (left >= 6) { pos += 2; - if (!memcmp(pos, SUITE_1X, 4)) { + if (!memcmp(pos, RTW_WPA_OUI23A_TYPE, 4)) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s : there has 802.1x auth\n", __func__)); @@ -624,12 +568,12 @@ int rtw_parse_wpa_ie23a(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pair return ret; } -int rtw_parse_wpa2_ie23a(u8* rsn_ie, int rsn_ie_len, int *group_cipher, +int rtw_parse_wpa2_ie23a(const u8* rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) { int i, ret = _SUCCESS; int left, count; - u8 *pos; + const u8 *pos; u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01}; if (rsn_ie_len <= 0) { @@ -705,11 +649,9 @@ int rtw_get_sec_ie23a(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len) { u8 authmode, sec_idx, i; - u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; uint cnt; - /* Search required WPA or WPA2 IE and copy to sec_ie[ ] */ cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_); @@ -719,8 +661,8 @@ int rtw_get_sec_ie23a(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, while(cnt < in_len) { authmode = in_ie[cnt]; - if ((authmode == _WPA_IE_ID_) && - !memcmp(&in_ie[cnt+2], &wpa_oui[0], 4)) { + if ((authmode == WLAN_EID_VENDOR_SPECIFIC) && + !memcmp(&in_ie[cnt+2], RTW_WPA_OUI23A_TYPE, 4)) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\n rtw_get_wpa_ie23a: sec_idx =%d " "in_ie[cnt+1]+2 =%d\n", @@ -788,7 +730,8 @@ u8 rtw_is_wps_ie23a(u8 *ie_ptr, uint *wps_ielen) eid = ie_ptr[0]; - if ((eid == _WPA_IE_ID_) && !memcmp(&ie_ptr[2], wps_oui, 4)) { + if ((eid == WLAN_EID_VENDOR_SPECIFIC) && + !memcmp(&ie_ptr[2], wps_oui, 4)) { /* DBG_8723A("==> found WPS_IE.....\n"); */ *wps_ielen = ie_ptr[1] + 2; match = true; @@ -824,7 +767,8 @@ u8 *rtw_get_wps_ie23a(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) while (cnt < in_len) { eid = in_ie[cnt]; - if ((eid == _WPA_IE_ID_) && !memcmp(&in_ie[cnt+2], wps_oui, 4)) { + if ((eid == WLAN_EID_VENDOR_SPECIFIC) && + !memcmp(&in_ie[cnt+2], wps_oui, 4)) { wpsie_ptr = &in_ie[cnt]; if (wps_ie) @@ -866,7 +810,7 @@ u8 *rtw_get_wps_attr23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, if (len_attr) *len_attr = 0; - if ((wps_ie[0] != _VENDOR_SPECIFIC_IE_) || + if ((wps_ie[0] != WLAN_EID_VENDOR_SPECIFIC) || memcmp(wps_ie + 2, wps_oui, 4)) { return attr_ptr; } @@ -937,237 +881,6 @@ u8 *rtw_get_wps_attr_content23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, return NULL; } -static int -rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen, - struct rtw_ieee802_11_elems *elems, - int show_errors) -{ - unsigned int oui; - - /* first 3 bytes in vendor specific information element are the IEEE - * OUI of the vendor. The following byte is used a vendor specific - * sub-type. */ - if (elen < 4) { - if (show_errors) { - DBG_8723A("short vendor specific " - "information element ignored (len =%lu)\n", - (unsigned long) elen); - } - return -1; - } - - oui = RTW_GET_BE24(pos); - switch (oui) { - case WLAN_OUI_MICROSOFT: - /* Microsoft/Wi-Fi information elements are further typed and - * subtyped */ - switch (pos[3]) { - case 1: - /* Microsoft OUI (00:50:F2) with OUI Type 1: - * real WPA information element */ - elems->wpa_ie = pos; - elems->wpa_ie_len = elen; - break; - case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */ - if (elen < 5) { - DBG_8723A("short WME " - "information element ignored " - "(len =%lu)\n", - (unsigned long) elen); - return -1; - } - switch (pos[4]) { - case WME_OUI_SUBTYPE_INFORMATION_ELEMENT: - case WME_OUI_SUBTYPE_PARAMETER_ELEMENT: - elems->wme = pos; - elems->wme_len = elen; - break; - case WME_OUI_SUBTYPE_TSPEC_ELEMENT: - elems->wme_tspec = pos; - elems->wme_tspec_len = elen; - break; - default: - DBG_8723A("unknown WME " - "information element ignored " - "(subtype =%d len =%lu)\n", - pos[4], (unsigned long) elen); - return -1; - } - break; - case 4: - /* Wi-Fi Protected Setup (WPS) IE */ - elems->wps_ie = pos; - elems->wps_ie_len = elen; - break; - default: - DBG_8723A("Unknown Microsoft " - "information element ignored " - "(type =%d len =%lu)\n", - pos[3], (unsigned long) elen); - return -1; - } - break; - - case OUI_BROADCOM: - switch (pos[3]) { - case VENDOR_HT_CAPAB_OUI_TYPE: - elems->vendor_ht_cap = pos; - elems->vendor_ht_cap_len = elen; - break; - default: - DBG_8723A("Unknown Broadcom " - "information element ignored " - "(type =%d len =%lu)\n", - pos[3], (unsigned long) elen); - return -1; - } - break; - - default: - DBG_8723A("unknown vendor specific information " - "element ignored (vendor OUI %02x:%02x:%02x " - "len =%lu)\n", - pos[0], pos[1], pos[2], (unsigned long) elen); - return -1; - } - - return 0; -} - -/** - * ieee802_11_parse_elems - Parse information elements in management frames - * @start: Pointer to the start of IEs - * @len: Length of IE buffer in octets - * @elems: Data structure for parsed elements - * @show_errors: Whether to show parsing errors in debug log - * Returns: Parsing result - */ -enum parse_res rtw_ieee802_11_parse_elems23a(u8 *start, uint len, - struct rtw_ieee802_11_elems *elems, - int show_errors) -{ - uint left = len; - u8 *pos = start; - int unknown = 0; - - memset(elems, 0, sizeof(*elems)); - - while (left >= 2) { - u8 id, elen; - - id = *pos++; - elen = *pos++; - left -= 2; - - if (elen > left) { - if (show_errors) { - DBG_8723A("IEEE 802.11 element " - "parse failed (id =%d elen =%d " - "left =%lu)\n", - id, elen, (unsigned long) left); - } - return ParseFailed; - } - - switch (id) { - case WLAN_EID_SSID: - elems->ssid = pos; - elems->ssid_len = elen; - break; - case WLAN_EID_SUPP_RATES: - elems->supp_rates = pos; - elems->supp_rates_len = elen; - break; - case WLAN_EID_FH_PARAMS: - elems->fh_params = pos; - elems->fh_params_len = elen; - break; - case WLAN_EID_DS_PARAMS: - elems->ds_params = pos; - elems->ds_params_len = elen; - break; - case WLAN_EID_CF_PARAMS: - elems->cf_params = pos; - elems->cf_params_len = elen; - break; - case WLAN_EID_TIM: - elems->tim = pos; - elems->tim_len = elen; - break; - case WLAN_EID_IBSS_PARAMS: - elems->ibss_params = pos; - elems->ibss_params_len = elen; - break; - case WLAN_EID_CHALLENGE: - elems->challenge = pos; - elems->challenge_len = elen; - break; - case WLAN_EID_ERP_INFO: - elems->erp_info = pos; - elems->erp_info_len = elen; - break; - case WLAN_EID_EXT_SUPP_RATES: - elems->ext_supp_rates = pos; - elems->ext_supp_rates_len = elen; - break; - case WLAN_EID_VENDOR_SPECIFIC: - if (rtw_ieee802_11_parse_vendor_specific(pos, elen, - elems, - show_errors)) - unknown++; - break; - case WLAN_EID_RSN: - elems->rsn_ie = pos; - elems->rsn_ie_len = elen; - break; - case WLAN_EID_PWR_CAPABILITY: - elems->power_cap = pos; - elems->power_cap_len = elen; - break; - case WLAN_EID_SUPPORTED_CHANNELS: - elems->supp_channels = pos; - elems->supp_channels_len = elen; - break; - case WLAN_EID_MOBILITY_DOMAIN: - elems->mdie = pos; - elems->mdie_len = elen; - break; - case WLAN_EID_FAST_BSS_TRANSITION: - elems->ftie = pos; - elems->ftie_len = elen; - break; - case WLAN_EID_TIMEOUT_INTERVAL: - elems->timeout_int = pos; - elems->timeout_int_len = elen; - break; - case WLAN_EID_HT_CAPABILITY: - elems->ht_capabilities = pos; - elems->ht_capabilities_len = elen; - break; - case WLAN_EID_HT_OPERATION: - elems->ht_operation = pos; - elems->ht_operation_len = elen; - break; - default: - unknown++; - if (!show_errors) - break; - DBG_8723A("IEEE 802.11 element parse " - "ignored unknown element (id =%d elen =%d)\n", - id, elen); - break; - } - - left -= elen; - pos += elen; - } - - if (left) - return ParseFailed; - - return unknown ? ParseUnknown : ParseOK; -} - static u8 key_char2num(u8 ch) { if ((ch >= '0') && (ch <= '9')) @@ -1214,387 +927,26 @@ void rtw_macaddr_cfg23a(u8 *mac_addr) MAC_ARG(mac_addr)); } -void dump_ies23a(u8 *buf, u32 buf_len) { - u8* pos = (u8*)buf; - u8 id, len; - - while (pos-buf <= buf_len) { - id = *pos; - len = *(pos + 1); - - DBG_8723A("%s ID:%u, LEN:%u\n", __func__, id, len); -#ifdef CONFIG_8723AU_P2P - dump_p2p_ie23a(pos, len); -#endif - dump_wps_ie23a(pos, len); - - pos += (2 + len); - } -} - -void dump_wps_ie23a(u8 *ie, u32 ie_len) { - u8* pos = (u8*)ie; - u16 id; - u16 len; - - u8 *wps_ie; - uint wps_ielen; - - wps_ie = rtw_get_wps_ie23a(ie, ie_len, NULL, &wps_ielen); - if (wps_ie != ie || wps_ielen == 0) - return; - - pos+= 6; - while (pos-ie < ie_len) { - id = get_unaligned_be16(pos); - len = get_unaligned_be16(pos + 2); - - DBG_8723A("%s ID:0x%04x, LEN:%u\n", __func__, id, len); - - pos += (4 + len); - } -} - -#ifdef CONFIG_8723AU_P2P -void dump_p2p_ie23a(u8 *ie, u32 ie_len) { - u8* pos = (u8*)ie; - u8 id; - u16 len; - - u8 *p2p_ie; - uint p2p_ielen; - - p2p_ie = rtw_get_p2p_ie23a(ie, ie_len, NULL, &p2p_ielen); - if (p2p_ie != ie || p2p_ielen == 0) - return; - - pos += 6; - while (pos-ie < ie_len) { - id = *pos; - len = get_unaligned_le16(pos+1); - - DBG_8723A("%s ID:%u, LEN:%u\n", __func__, id, len); - - pos+= (3+len); - } -} - -/** - * rtw_get_p2p_ie23a - Search P2P IE from a series of IEs - * @in_ie: Address of IEs to search - * @in_len: Length limit from in_ie - * @p2p_ie: If not NULL and P2P IE is found, P2P IE will be copied to the - * buf starting from p2p_ie - * @p2p_ielen: If not NULL and P2P IE is found, will set to the length of - * the entire P2P IE - * - * Returns: The address of the P2P IE found, or NULL - */ -u8 *rtw_get_p2p_ie23a(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen) -{ - uint cnt = 0; - u8 *p2p_ie_ptr; - u8 eid, p2p_oui[4]={0x50, 0x6F, 0x9A, 0x09}; - - if (p2p_ielen) - *p2p_ielen = 0; - - while (cnt MAX_IE_SZ)) { - dump_stack(); - return NULL; - } - if ((eid == _VENDOR_SPECIFIC_IE_) && - !memcmp(&in_ie[cnt + 2], p2p_oui, 4)) { - p2p_ie_ptr = in_ie + cnt; - - if (p2p_ie != NULL) { - memcpy(p2p_ie, &in_ie[cnt], - in_ie[cnt + 1] + 2); - } - - if (p2p_ielen != NULL) { - *p2p_ielen = in_ie[cnt + 1] + 2; - } - - return p2p_ie_ptr; - - break; - } else { - cnt += in_ie[cnt + 1] + 2; /* goto next */ - } - } - - return NULL; -} - -/** - * rtw_get_p2p_attr23a - Search a specific P2P attribute from a given P2P IE - * @p2p_ie: Address of P2P IE to search - * @p2p_ielen: Length limit from p2p_ie - * @target_attr_id: The attribute ID of P2P attribute to search - * @buf_attr: If not NULL and the P2P attribute is found, P2P attribute will - * be copied to the buf starting from buf_attr - * @len_attr: If not NULL and the P2P attribute is found, will set to the - * length of the entire P2P attribute - * - * Returns: the address of the specific WPS attribute found, or NULL - */ -u8 *rtw_get_p2p_attr23a(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id, - u8 *buf_attr, u32 *len_attr) -{ - u8 *attr_ptr = NULL; - u8 *target_attr_ptr = NULL; - u8 p2p_oui[4]={0x50, 0x6F, 0x9A, 0x09}; - - if (len_attr) - *len_attr = 0; - - if (!p2p_ie || (p2p_ie[0] != _VENDOR_SPECIFIC_IE_) || - memcmp(p2p_ie + 2, p2p_oui, 4)) { - return attr_ptr; - } - - /* 6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) */ - attr_ptr = p2p_ie + 6; /* goto first attr */ - - while (attr_ptr - p2p_ie < p2p_ielen) { - /* 3 = 1(Attribute ID) + 2(Length) */ - u8 attr_id = *attr_ptr; - u16 attr_data_len = get_unaligned_le16(attr_ptr + 1); - u16 attr_len = attr_data_len + 3; - - /* DBG_8723A("%s attr_ptr:%p, id:%u, length:%u\n", __func__, attr_ptr, attr_id, attr_data_len); */ - if (attr_id == target_attr_id) { - target_attr_ptr = attr_ptr; - - if (buf_attr) - memcpy(buf_attr, attr_ptr, attr_len); - - if (len_attr) - *len_attr = attr_len; - - break; - } else { - attr_ptr += attr_len; /* goto next */ - } - } - - return target_attr_ptr; -} - -/** - * rtw_get_p2p_attr23a_content - Search a specific P2P attribute content from - * a given P2P IE - * @p2p_ie: Address of P2P IE to search - * @p2p_ielen: Length limit from p2p_ie - * @target_attr_id: The attribute ID of P2P attribute to search - * @buf_content: If not NULL and the P2P attribute is found, P2P attribute - * content will be copied to the buf starting from buf_content - * @len_content: If not NULL and the P2P attribute is found, will set to the - * length of the P2P attribute content - * - * Returns: the address of the specific P2P attribute content found, or NULL - */ -u8 *rtw_get_p2p_attr23a_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id, - u8 *buf_content, uint *len_content) -{ - u8 *attr_ptr; - u32 attr_len; - - if (len_content) - *len_content = 0; - - attr_ptr = rtw_get_p2p_attr23a(p2p_ie, p2p_ielen, target_attr_id, - NULL, &attr_len); - - if (attr_ptr && attr_len) { - if (buf_content) - memcpy(buf_content, attr_ptr + 3, attr_len - 3); - - if (len_content) - *len_content = attr_len - 3; - - return attr_ptr+3; - } - - return NULL; -} - -u32 rtw_set_p2p_attr_content23a(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr) -{ - u32 a_len; - - *pbuf = attr_id; - - /* u16*)(pbuf + 1) = cpu_to_le16(attr_len); */ - put_unaligned_le16(attr_len, pbuf + 1); - - if (pdata_attr) - memcpy(pbuf + 3, pdata_attr, attr_len); - - a_len = attr_len + 3; - - return a_len; -} - -static uint rtw_p2p_attr_remove(u8 *ie, uint ielen_ori, u8 attr_id) -{ - u8 *target_attr; - u32 target_attr_len; - uint ielen = ielen_ori; - - while(1) { - target_attr = rtw_get_p2p_attr23a(ie, ielen, attr_id, NULL, - &target_attr_len); - if (target_attr && target_attr_len) { - u8 *next_attr = target_attr+target_attr_len; - uint remain_len = ielen-(next_attr-ie); - /* dump_ies23a(ie, ielen); */ - - memset(target_attr, 0, target_attr_len); - memcpy(target_attr, next_attr, remain_len); - memset(target_attr+remain_len, 0, target_attr_len); - *(ie + 1) -= target_attr_len; - ielen -= target_attr_len; - } else { - /* if (index>0) */ - /* dump_ies23a(ie, ielen); */ - break; - } - } - - return ielen; -} - -void rtw_wlan_bssid_ex_remove_p2p_attr23a(struct wlan_bssid_ex *bss_ex, u8 attr_id) -{ - u8 *p2p_ie; - uint p2p_ielen, p2p_ielen_ori; - - if ((p2p_ie = rtw_get_p2p_ie23a(bss_ex->IEs + _FIXED_IE_LENGTH_, - bss_ex->IELength - _FIXED_IE_LENGTH_, - NULL, &p2p_ielen_ori))) { - p2p_ielen = rtw_p2p_attr_remove(p2p_ie, p2p_ielen_ori, attr_id); - if (p2p_ielen != p2p_ielen_ori) { - u8 *next_ie_ori = p2p_ie+p2p_ielen_ori; - u8 *next_ie = p2p_ie+p2p_ielen; - uint remain_len; - remain_len = bss_ex->IELength-(next_ie_ori-bss_ex->IEs); - - memcpy(next_ie, next_ie_ori, remain_len); - memset(next_ie+remain_len, 0, p2p_ielen_ori-p2p_ielen); - bss_ex->IELength -= p2p_ielen_ori-p2p_ielen; - } - } -} - -#endif /* CONFIG_8723AU_P2P */ - -#ifdef CONFIG_8723AU_P2P -int rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen) -{ - int match; - const u8 *ie; - - match = 0; - - if (in_len < 0) - return match; - - ie = cfg80211_find_vendor_ie(0x506F9A, 0x0A, in_ie, in_len); - if (ie && (ie[1] <= (MAX_WFD_IE_LEN - 2))) { - if (wfd_ie) { - *wfd_ielen = ie[1] + 2; - memcpy(wfd_ie, ie, ie[1] + 2); - } else - if (wfd_ielen) - *wfd_ielen = 0; - - match = 1; - } - - return match; -} - -/* attr_content: The output buffer, contains the "body field" of - WFD attribute. */ -/* attr_contentlen: The data length of the "body field" of WFD - attribute. */ -int rtw_get_wfd_attr_content(u8 *wfd_ie, uint wfd_ielen, u8 target_attr_id, - u8 *attr_content, uint *attr_contentlen) -{ - int match; - uint cnt = 0; - u8 attr_id, wfd_oui[4] = {0x50, 0x6F, 0x9A, 0x0A}; - - match = false; - - if ((wfd_ie[0] != _VENDOR_SPECIFIC_IE_) || - memcmp(wfd_ie + 2, wfd_oui, 4)) { - return match; - } - - /* 1 (WFD IE) + 1 (Length) + 3 (OUI) + 1 (OUI Type) */ - cnt = 6; - while (cnt < wfd_ielen) { - u16 attrlen = get_unaligned_be16(wfd_ie + cnt + 1); - - attr_id = wfd_ie[cnt]; - if (attr_id == target_attr_id) { - /* 3 -> 1 byte for attribute ID field, 2 - bytes for length field */ - if (attr_content) - memcpy(attr_content, &wfd_ie[cnt + 3], attrlen); - - if (attr_contentlen) - *attr_contentlen = attrlen; - - cnt += attrlen + 3; - - match = true; - break; - } else { - cnt += attrlen + 3; /* goto next */ - } - } - - return match; -} -#endif /* CONFIG_8723AU_P2P */ - -/* Baron adds to avoid FreeBSD warning */ -int ieee80211_is_empty_essid23a(const char *essid, int essid_len) -{ - /* Single white space is for Linksys APs */ - if (essid_len == 1 && essid[0] == ' ') - return 1; - - /* Otherwise, if the entire essid is 0, we assume it is hidden */ - while (essid_len) { - essid_len--; - if (essid[essid_len] != '\0') - return 0; - } - - return 1; -} - static int rtw_get_cipher_info(struct wlan_network *pnetwork) { - u32 wpa_ielen; - unsigned char *pbuf; + const u8 *pbuf; int group_cipher = 0, pairwise_cipher = 0, is8021x = 0; int ret = _FAIL; - int r; - pbuf = rtw_get_wpa_ie23a(&pnetwork->network.IEs[12], &wpa_ielen, - pnetwork->network.IELength - 12); + int r, offset, plen; + char *pie; + + offset = offsetof(struct ieee80211_mgmt, u.beacon.variable) - + offsetof(struct ieee80211_mgmt, u); + pie = &pnetwork->network.IEs[offset]; + plen = pnetwork->network.IELength - offset; - if (pbuf && (wpa_ielen > 0)) { + pbuf = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPA, pie, plen); + + if (pbuf && pbuf[1] > 0) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen)); - r = rtw_parse_wpa_ie23a(pbuf, wpa_ielen + 2, &group_cipher, + ("rtw_get_cipher_info: wpa_ielen: %d", pbuf[1])); + r = rtw_parse_wpa_ie23a(pbuf, pbuf[1] + 2, &group_cipher, &pairwise_cipher, &is8021x); if (r == _SUCCESS) { pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; @@ -1608,13 +960,12 @@ static int rtw_get_cipher_info(struct wlan_network *pnetwork) ret = _SUCCESS; } } else { - pbuf = rtw_get_wpa2_ie23a(&pnetwork->network.IEs[12], &wpa_ielen, - pnetwork->network.IELength - 12); + pbuf = cfg80211_find_ie(WLAN_EID_RSN, pie, plen); - if (pbuf && (wpa_ielen > 0)) { + if (pbuf && pbuf[1] > 0) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE\n")); - r = rtw_parse_wpa2_ie23a(pbuf, wpa_ielen + 2, + r = rtw_parse_wpa2_ie23a(pbuf, pbuf[1] + 2, &group_cipher, &pairwise_cipher, &is8021x); if (r == _SUCCESS) { @@ -1650,8 +1001,8 @@ void rtw_get_bcn_info23a(struct wlan_network *pnetwork) unsigned int len; unsigned char *p; - memcpy(&cap, rtw_get_capability23a_from_ie(pnetwork->network.IEs), 2); - cap = le16_to_cpu(cap); + cap = get_unaligned_le16( + rtw_get_capability23a_from_ie(pnetwork->network.IEs)); if (cap & WLAN_CAPABILITY_PRIVACY) { bencrypt = 1; pnetwork->network.Privacy = 1; @@ -1690,8 +1041,8 @@ void rtw_get_bcn_info23a(struct wlan_network *pnetwork) /* get bwmode and ch_offset */ /* parsing HT_CAP_IE */ p = rtw_get_ie23a(pnetwork->network.IEs + _FIXED_IE_LENGTH_, - _HT_CAPABILITY_IE_, &len, - pnetwork->network.IELength - _FIXED_IE_LENGTH_); + WLAN_EID_HT_CAPABILITY, &len, + pnetwork->network.IELength - _FIXED_IE_LENGTH_); if (p && len > 0) { pht_cap = (struct ieee80211_ht_cap *)(p + 2); pnetwork->BcnInfo.ht_cap_info = pht_cap->cap_info; @@ -1700,7 +1051,7 @@ void rtw_get_bcn_info23a(struct wlan_network *pnetwork) } /* parsing HT_INFO_IE */ p = rtw_get_ie23a(pnetwork->network.IEs + _FIXED_IE_LENGTH_, - _HT_ADD_INFO_IE_, &len, + WLAN_EID_HT_OPERATION, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_); if (p && len > 0) { pht_info = (struct HT_info_element *)(p + 2); diff --git a/drivers/staging/rtl8723au/core/rtw_io.c b/drivers/staging/rtl8723au/core/rtw_io.c index 1cae8d7659b98a..01022113950af9 100644 --- a/drivers/staging/rtl8723au/core/rtw_io.c +++ b/drivers/staging/rtl8723au/core/rtw_io.c @@ -44,10 +44,9 @@ jackson@realtek.com.tw u8 _rtw_read823a(struct rtw_adapter *adapter, u32 addr) { u8 r_val; - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + struct _io_ops *io_ops = &adapter->io_ops; - r_val = pintfhdl->io_ops._read8(pintfhdl, addr); + r_val = io_ops->_read8(adapter, addr); return r_val; } @@ -55,10 +54,9 @@ u8 _rtw_read823a(struct rtw_adapter *adapter, u32 addr) u16 _rtw_read1623a(struct rtw_adapter *adapter, u32 addr) { u16 r_val; - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + struct _io_ops *io_ops = &adapter->io_ops; - r_val = pintfhdl->io_ops._read16(pintfhdl, addr); + r_val = io_ops->_read16(adapter, addr); return le16_to_cpu(r_val); } @@ -66,95 +64,57 @@ u16 _rtw_read1623a(struct rtw_adapter *adapter, u32 addr) u32 _rtw_read3223a(struct rtw_adapter *adapter, u32 addr) { u32 r_val; - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + struct _io_ops *io_ops = &adapter->io_ops; - r_val = pintfhdl->io_ops._read32(pintfhdl, addr); + r_val = io_ops->_read32(adapter, addr); return le32_to_cpu(r_val); } int _rtw_write823a(struct rtw_adapter *adapter, u32 addr, u8 val) { - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + struct _io_ops *io_ops = &adapter->io_ops; int ret; - ret = pintfhdl->io_ops._write8(pintfhdl, addr, val); + ret = io_ops->_write8(adapter, addr, val); return RTW_STATUS_CODE23a(ret); } int _rtw_write1623a(struct rtw_adapter *adapter, u32 addr, u16 val) { - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + struct _io_ops *io_ops = &adapter->io_ops; int ret; val = cpu_to_le16(val); - ret = pintfhdl->io_ops._write16(pintfhdl, addr, val); + ret = io_ops->_write16(adapter, addr, val); return RTW_STATUS_CODE23a(ret); } + int _rtw_write3223a(struct rtw_adapter *adapter, u32 addr, u32 val) { - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + struct _io_ops *io_ops = &adapter->io_ops; int ret; val = cpu_to_le32(val); - ret = pintfhdl->io_ops._write32(pintfhdl, addr, val); + ret = io_ops->_write32(adapter, addr, val); return RTW_STATUS_CODE23a(ret); } int _rtw_writeN23a(struct rtw_adapter *adapter, u32 addr , u32 length , u8 *pdata) { - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = (struct intf_hdl*)&pio_priv->intf; - int ret; - - ret = pintfhdl->io_ops._writeN(pintfhdl, addr, length, pdata); - - return RTW_STATUS_CODE23a(ret); -} -int _rtw_write823a_async23a(struct rtw_adapter *adapter, u32 addr, u8 val) -{ - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + struct _io_ops *io_ops = &adapter->io_ops; int ret; - ret = pintfhdl->io_ops._write8_async(pintfhdl, addr, val); + ret = io_ops->_writeN(adapter, addr, length, pdata); return RTW_STATUS_CODE23a(ret); } -int _rtw_write1623a_async(struct rtw_adapter *adapter, u32 addr, u16 val) -{ - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; - int ret; - - val = cpu_to_le16(val); - ret = pintfhdl->io_ops._write16_async(pintfhdl, addr, val); - - return RTW_STATUS_CODE23a(ret); -} -int _rtw_write3223a_async23a(struct rtw_adapter *adapter, u32 addr, u32 val) -{ - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; - int ret; - - val = cpu_to_le32(val); - ret = pintfhdl->io_ops._write32_async(pintfhdl, addr, val); - - return RTW_STATUS_CODE23a(ret); -} - void _rtw_read_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) { - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + struct _io_ops *io_ops = &adapter->io_ops; if ((adapter->bDriverStopped == true) || (adapter->bSurpriseRemoved == true)) { @@ -165,22 +125,20 @@ void _rtw_read_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) return; } - pintfhdl->io_ops._read_mem(pintfhdl, addr, cnt, pmem); + io_ops->_read_mem(adapter, addr, cnt, pmem); } void _rtw_write_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) { - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + struct _io_ops *io_ops = &adapter->io_ops; - pintfhdl->io_ops._write_mem(pintfhdl, addr, cnt, pmem); + io_ops->_write_mem(adapter, addr, cnt, pmem); } void _rtw_read_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, - struct recv_buf *rbuf) + struct recv_buf *rbuf) { - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + struct _io_ops *io_ops = &adapter->io_ops; if ((adapter->bDriverStopped == true) || (adapter->bSurpriseRemoved == true)) { @@ -191,76 +149,38 @@ void _rtw_read_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, return; } - pintfhdl->io_ops._read_port(pintfhdl, addr, cnt, rbuf); + io_ops->_read_port(adapter, addr, cnt, rbuf); } void _rtw_read_port23a_cancel(struct rtw_adapter *adapter) { - void (*_read_port_cancel)(struct intf_hdl *pintfhdl); - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + void (*_read_port_cancel)(struct rtw_adapter *adapter); + struct _io_ops *io_ops = &adapter->io_ops; - _read_port_cancel = pintfhdl->io_ops._read_port_cancel; + _read_port_cancel = io_ops->_read_port_cancel; if (_read_port_cancel) - _read_port_cancel(pintfhdl); + _read_port_cancel(adapter); } u32 _rtw_write_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, struct xmit_buf *xbuf) { - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + struct _io_ops *io_ops = &adapter->io_ops; u32 ret = _SUCCESS; - ret = pintfhdl->io_ops._write_port(pintfhdl, addr, cnt, xbuf); - - return ret; -} - -u32 _rtw_write_port23a_and_wait23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, - struct xmit_buf *pxmitbuf, int timeout_ms) -{ - int ret = _SUCCESS; - struct submit_ctx sctx; - - rtw_sctx_init23a(&sctx, timeout_ms); - pxmitbuf->sctx = &sctx; - - ret = _rtw_write_port23a(adapter, addr, cnt, pxmitbuf); - - if (ret == _SUCCESS) - ret = rtw_sctx_wait23a(&sctx); + ret = io_ops->_write_port(adapter, addr, cnt, xbuf); return ret; } void _rtw_write_port23a_cancel(struct rtw_adapter *adapter) { - void (*_write_port_cancel)(struct intf_hdl *pintfhdl); - struct io_priv *pio_priv = &adapter->iopriv; - struct intf_hdl *pintfhdl = &pio_priv->intf; + void (*_write_port_cancel)(struct rtw_adapter *adapter); + struct _io_ops *io_ops = &adapter->io_ops; - _write_port_cancel = pintfhdl->io_ops._write_port_cancel; + _write_port_cancel = io_ops->_write_port_cancel; if (_write_port_cancel) - _write_port_cancel(pintfhdl); -} - -int rtw_init_io_priv23a(struct rtw_adapter *padapter, - void (*set_intf_ops)(struct _io_ops *pops)) -{ - struct io_priv *piopriv = &padapter->iopriv; - struct intf_hdl *pintf = &piopriv->intf; - - if (set_intf_ops == NULL) - return _FAIL; - - piopriv->padapter = padapter; - pintf->padapter = padapter; - pintf->pintf_dev = adapter_to_dvobj(padapter); - - set_intf_ops(&pintf->io_ops); - - return _SUCCESS; + _write_port_cancel(adapter); } diff --git a/drivers/staging/rtl8723au/core/rtw_ioctl_set.c b/drivers/staging/rtl8723au/core/rtw_ioctl_set.c index 30d7185e5637d7..b03266bc1f3c63 100644 --- a/drivers/staging/rtl8723au/core/rtw_ioctl_set.c +++ b/drivers/staging/rtl8723au/core/rtw_ioctl_set.c @@ -54,7 +54,7 @@ u8 rtw_do_join23a(struct rtw_adapter *padapter) /* we try to issue sitesurvey firstly */ if (pmlmepriv->LinkDetectInfo.bBusyTraffic == false || - rtw_to_roaming(padapter) > 0) { + padapter->mlmepriv.to_roaming > 0) { RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("rtw_do_join23a(): site survey if scanned_queue " "is empty\n.")); @@ -130,7 +130,7 @@ u8 rtw_do_join23a(struct rtw_adapter *padapter) queue */ /* we try to issue sitesurvey firstly */ if (pmlmepriv->LinkDetectInfo.bBusyTraffic == - false || rtw_to_roaming(padapter) > 0) { + false || padapter->mlmepriv.to_roaming > 0){ /* DBG_8723A("rtw_do_join23a() when no " "desired bss in scanning queue\n"); */ @@ -280,27 +280,26 @@ u8 rtw_set_802_11_ssid23a(struct rtw_adapter* padapter, struct cfg80211_ssid *ss } u8 rtw_set_802_11_infrastructure_mode23a(struct rtw_adapter* padapter, - enum ndis_802_11_net_infra networktype) + enum ndis_802_11_net_infra networktype) { - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_network *cur_network = &pmlmepriv->cur_network; - enum ndis_802_11_net_infra* pold_state = &cur_network->network.InfrastructureMode; - + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + enum ndis_802_11_net_infra* pold_state; + pold_state = &cur_network->network.InfrastructureMode; RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_notice_, - ("+rtw_set_802_11_infrastructure_mode23a: old =%d new =%d fw_state = 0x%08x\n", + ("+rtw_set_802_11_infrastructure_mode23a: old =%d new =%d " + "fw_state = 0x%08x\n", *pold_state, networktype, get_fwstate(pmlmepriv))); - if (*pold_state != networktype) - { + if (*pold_state != networktype) { spin_lock_bh(&pmlmepriv->lock); - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, (" change mode!")); - /* DBG_8723A("change mode, old_mode =%d, new_mode =%d, fw_state = 0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */ + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + (" change mode!")); - if (*pold_state == Ndis802_11APMode) - { + if (*pold_state == Ndis802_11APMode) { /* change to other mode from Ndis802_11APMode */ cur_network->join_res = -1; @@ -309,18 +308,21 @@ u8 rtw_set_802_11_infrastructure_mode23a(struct rtw_adapter* padapter, #endif } - if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) ||(*pold_state == Ndis802_11IBSS)) + if (check_fwstate(pmlmepriv, _FW_LINKED) || + *pold_state == Ndis802_11IBSS) rtw_disassoc_cmd23a(padapter, 0, true); - if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) || - (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) + if (check_fwstate(pmlmepriv, _FW_LINKED) || + check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) rtw_free_assoc_resources23a(padapter, 1); - if ((*pold_state == Ndis802_11Infrastructure) ||(*pold_state == Ndis802_11IBSS)) - { - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - rtw_indicate_disconnect23a(padapter); /* will clr Linked_state; before this function, we must have chked whether issue dis-assoc_cmd or not */ + if (*pold_state == Ndis802_11Infrastructure || + *pold_state == Ndis802_11IBSS) { + if (check_fwstate(pmlmepriv, _FW_LINKED)) { + /* will clr Linked_state; before this function, + we must have chked whether issue + dis-assoc_cmd or not */ + rtw_indicate_disconnect23a(padapter); } } @@ -330,38 +332,36 @@ u8 rtw_set_802_11_infrastructure_mode23a(struct rtw_adapter* padapter, switch (networktype) { - case Ndis802_11IBSS: - set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); - break; + case Ndis802_11IBSS: + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + break; - case Ndis802_11Infrastructure: - set_fwstate(pmlmepriv, WIFI_STATION_STATE); - break; + case Ndis802_11Infrastructure: + set_fwstate(pmlmepriv, WIFI_STATION_STATE); + break; - case Ndis802_11APMode: - set_fwstate(pmlmepriv, WIFI_AP_STATE); + case Ndis802_11APMode: + set_fwstate(pmlmepriv, WIFI_AP_STATE); #ifdef CONFIG_8723AU_AP_MODE - start_ap_mode23a(padapter); - /* rtw_indicate_connect23a(padapter); */ + start_ap_mode23a(padapter); + /* rtw_indicate_connect23a(padapter); */ #endif + break; - break; - - case Ndis802_11AutoUnknown: - case Ndis802_11InfrastructureMax: - break; + case Ndis802_11AutoUnknown: + case Ndis802_11InfrastructureMax: + break; } /* SecClearAllKeys(adapter); */ - /* RT_TRACE(COMP_OID_SET, DBG_LOUD, ("set_infrastructure: fw_state:%x after changing mode\n", */ - /* get_fwstate(pmlmepriv))); */ + /* RT_TRACE(COMP_OID_SET, DBG_LOUD, + ("set_infrastructure: fw_state:%x after changing mode\n", */ + /* get_fwstate(pmlmepriv))); */ spin_unlock_bh(&pmlmepriv->lock); } - - return true; } @@ -539,7 +539,7 @@ u8 rtw_set_802_11_add_wep23a(struct rtw_adapter* padapter, u16 rtw_get_cur_max_rate23a(struct rtw_adapter *adapter) { int i = 0; - u8 *p; + const u8 *p; u16 rate = 0, max_rate = 0; struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -550,16 +550,16 @@ u16 rtw_get_cur_max_rate23a(struct rtw_adapter *adapter) u8 rf_type = 0; u8 bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0; u16 mcs_rate = 0; - u32 ht_ielen = 0; if (!check_fwstate(pmlmepriv, _FW_LINKED) && !check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) return 0; if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N|WIRELESS_11_5N)) { - p = rtw_get_ie23a(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, - &ht_ielen, pcur_bss->IELength - 12); - if (p && ht_ielen > 0) { + p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, + &pcur_bss->IEs[12], + pcur_bss->IELength - 12); + if (p && p[1] > 0) { pht_capie = (struct ieee80211_ht_cap *)(p + 2); memcpy(&mcs_rate, &pht_capie->mcs, 2); @@ -577,8 +577,7 @@ u16 rtw_get_cur_max_rate23a(struct rtw_adapter *adapter) short_GI_20 = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info&IEEE80211_HT_CAP_SGI_20) ? 1:0; short_GI_40 = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info&IEEE80211_HT_CAP_SGI_40) ? 1:0; - rtw23a_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, - (u8 *)(&rf_type)); + rf_type = rtl8723a_get_rf_type(adapter); max_rate = rtw_mcs_rate23a(rf_type, bw_40MHz & pregistrypriv->cbw40_enable, short_GI_20, short_GI_40, diff --git a/drivers/staging/rtl8723au/core/rtw_mlme.c b/drivers/staging/rtl8723au/core/rtw_mlme.c index 6cee78785bdc67..8d64cb02ee8e88 100644 --- a/drivers/staging/rtl8723au/core/rtw_mlme.c +++ b/drivers/staging/rtl8723au/core/rtw_mlme.c @@ -45,7 +45,7 @@ static void rtw_init_mlme_timer(struct rtw_adapter *padapter) rtw_set_scan_deny_timer_hdl, (unsigned long)padapter); } -int _rtw_init_mlme_priv23a(struct rtw_adapter *padapter) +int rtw_init_mlme_priv23a(struct rtw_adapter *padapter) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; int res = _SUCCESS; @@ -53,8 +53,11 @@ int _rtw_init_mlme_priv23a(struct rtw_adapter *padapter) pmlmepriv->nic_hdl = padapter; pmlmepriv->fw_state = 0; - pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown; - pmlmepriv->scan_mode=SCAN_ACTIVE;/* 1: active, 0: pasive. Maybe someday we should rename this varable to "active_mode" (Jeff) */ + pmlmepriv->cur_network.network.InfrastructureMode = + Ndis802_11AutoUnknown; + /* 1: active, 0: pasive. Maybe someday we should rename this + varable to "active_mode" (Jeff) */ + pmlmepriv->scan_mode = SCAN_ACTIVE; spin_lock_init(&pmlmepriv->lock); _rtw_init_queue23a(&pmlmepriv->scanned_queue); @@ -72,11 +75,10 @@ int _rtw_init_mlme_priv23a(struct rtw_adapter *padapter) #ifdef CONFIG_8723AU_AP_MODE static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen) { - if(*ppie) - { + if (*ppie) { kfree(*ppie); *plen = 0; - *ppie=NULL; + *ppie = NULL; } } #endif @@ -86,30 +88,45 @@ void rtw23a_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv) #ifdef CONFIG_8723AU_AP_MODE kfree(pmlmepriv->assoc_req); kfree(pmlmepriv->assoc_rsp); - rtw_free_mlme_ie_data(&pmlmepriv->wps_beacon_ie, &pmlmepriv->wps_beacon_ie_len); - rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie, &pmlmepriv->wps_probe_req_ie_len); - rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_resp_ie, &pmlmepriv->wps_probe_resp_ie_len); - rtw_free_mlme_ie_data(&pmlmepriv->wps_assoc_resp_ie, &pmlmepriv->wps_assoc_resp_ie_len); - - rtw_free_mlme_ie_data(&pmlmepriv->p2p_beacon_ie, &pmlmepriv->p2p_beacon_ie_len); - rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_req_ie, &pmlmepriv->p2p_probe_req_ie_len); - rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, &pmlmepriv->p2p_probe_resp_ie_len); - rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, &pmlmepriv->p2p_go_probe_resp_ie_len); - rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, &pmlmepriv->p2p_assoc_req_ie_len); - - rtw_free_mlme_ie_data(&pmlmepriv->wfd_beacon_ie, &pmlmepriv->wfd_beacon_ie_len); - rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_req_ie, &pmlmepriv->wfd_probe_req_ie_len); - rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_resp_ie, &pmlmepriv->wfd_probe_resp_ie_len); - rtw_free_mlme_ie_data(&pmlmepriv->wfd_go_probe_resp_ie, &pmlmepriv->wfd_go_probe_resp_ie_len); - rtw_free_mlme_ie_data(&pmlmepriv->wfd_assoc_req_ie, &pmlmepriv->wfd_assoc_req_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wps_beacon_ie, + &pmlmepriv->wps_beacon_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie, + &pmlmepriv->wps_probe_req_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_resp_ie, + &pmlmepriv->wps_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wps_assoc_resp_ie, + &pmlmepriv->wps_assoc_resp_ie_len); + + rtw_free_mlme_ie_data(&pmlmepriv->p2p_beacon_ie, + &pmlmepriv->p2p_beacon_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_req_ie, + &pmlmepriv->p2p_probe_req_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, + &pmlmepriv->p2p_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, + &pmlmepriv->p2p_go_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, + &pmlmepriv->p2p_assoc_req_ie_len); + + rtw_free_mlme_ie_data(&pmlmepriv->wfd_beacon_ie, + &pmlmepriv->wfd_beacon_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_req_ie, + &pmlmepriv->wfd_probe_req_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_resp_ie, + &pmlmepriv->wfd_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_go_probe_resp_ie, + &pmlmepriv->wfd_go_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_assoc_req_ie, + &pmlmepriv->wfd_assoc_req_ie_len); #endif } -void _rtw_free_mlme_priv23a(struct mlme_priv *pmlmepriv) +void rtw_free_mlme_priv23a(struct mlme_priv *pmlmepriv) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("rtw_free_mlme_priv23a\n")); rtw23a_free_mlme_priv_ie_data(pmlmepriv); - } struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv) @@ -129,48 +146,27 @@ struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv) return pnetwork; } -void _rtw_free_network23a(struct mlme_priv *pmlmepriv, - struct wlan_network *pnetwork, u8 isfreeall) +static void _rtw_free_network23a(struct mlme_priv *pmlmepriv, + struct wlan_network *pnetwork) { - u32 lifetime = SCANQUEUE_LIFETIME; - if (!pnetwork) return; if (pnetwork->fixed == true) return; - if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || - (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) - lifetime = 1; - - list_del_init(&pnetwork->list); - - kfree(pnetwork); -} - -void _rtw_free_network23a_nolock23a(struct mlme_priv *pmlmepriv, - struct wlan_network *pnetwork) -{ - - if (pnetwork == NULL) - return; - - if (pnetwork->fixed == true) - return; - list_del_init(&pnetwork->list); kfree(pnetwork); } /* - return the wlan_network with the matching addr + return the wlan_network with the matching addr - Shall be calle under atomic context... to avoid possible racing condition... + Shall be calle under atomic context... to avoid possible racing condition... */ struct wlan_network * -_rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr) +rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr) { struct list_head *phead, *plist; struct wlan_network *pnetwork = NULL; @@ -194,7 +190,7 @@ _rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr) plist = plist->next; } - if(plist == phead) + if (plist == phead) pnetwork = NULL; /* spin_unlock_bh(&scanned_queue->lock); */ @@ -204,11 +200,11 @@ _rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr) return pnetwork; } -void _rtw_free_network23a_queue23a(struct rtw_adapter *padapter, u8 isfreeall) +void rtw_free_network_queue23a(struct rtw_adapter *padapter) { struct list_head *phead, *plist, *ptmp; struct wlan_network *pnetwork; - struct mlme_priv* pmlmepriv = &padapter->mlmepriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct rtw_queue *scanned_queue = &pmlmepriv->scanned_queue; spin_lock_bh(&scanned_queue->lock); @@ -218,24 +214,25 @@ void _rtw_free_network23a_queue23a(struct rtw_adapter *padapter, u8 isfreeall) list_for_each_safe(plist, ptmp, phead) { pnetwork = container_of(plist, struct wlan_network, list); - _rtw_free_network23a(pmlmepriv,pnetwork, isfreeall); + _rtw_free_network23a(pmlmepriv, pnetwork); } spin_unlock_bh(&scanned_queue->lock); - } -int rtw_if_up23a(struct rtw_adapter *padapter) { - +int rtw_if_up23a(struct rtw_adapter *padapter) +{ int res; - if(padapter->bDriverStopped || padapter->bSurpriseRemoved || - (check_fwstate(&padapter->mlmepriv, _FW_LINKED)== false)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_if_up23a:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); - res=false; - } - else - res= true; + if (padapter->bDriverStopped || padapter->bSurpriseRemoved || + check_fwstate(&padapter->mlmepriv, _FW_LINKED) == false) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("rtw_if_up23a:bDriverStopped(%d) OR " + "bSurpriseRemoved(%d)", padapter->bDriverStopped, + padapter->bSurpriseRemoved)); + res = false; + } else + res = true; return res; } @@ -247,115 +244,114 @@ void rtw_generate_random_ibss23a(u8* pibss) pibss[0] = 0x02; /* in ad-hoc mode bit1 must set to 1 */ pibss[1] = 0x11; pibss[2] = 0x87; - pibss[3] = (u8)(curtime & 0xff) ;/* p[0]; */ - pibss[4] = (u8)((curtime>>8) & 0xff) ;/* p[1]; */ - pibss[5] = (u8)((curtime>>16) & 0xff) ;/* p[2]; */ + pibss[3] = curtime & 0xff;/* p[0]; */ + pibss[4] = (curtime >> 8) & 0xff;/* p[1]; */ + pibss[5] = (curtime >> 16) & 0xff;/* p[2]; */ return; } -u8 *rtw_get_capability23a_from_ie(u8 *ie) +void rtw_set_roaming(struct rtw_adapter *adapter, u8 to_roaming) { - return ie + 8 + 2; + if (to_roaming == 0) + adapter->mlmepriv.to_join = false; + adapter->mlmepriv.to_roaming = to_roaming; } -u16 rtw_get_capability23a(struct wlan_bssid_ex *bss) +static void _rtw_roaming(struct rtw_adapter *padapter, + struct wlan_network *tgt_network) { - u16 val; - - memcpy((u8 *)&val, rtw_get_capability23a_from_ie(bss->IEs), 2); - - return le16_to_cpu(val); -} + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *pnetwork; + int do_join_r; -u8 *rtw_get_timestampe_from_ie23a(u8 *ie) -{ - return ie + 0; -} + if (tgt_network) + pnetwork = tgt_network; + else + pnetwork = &pmlmepriv->cur_network; -u8 *rtw_get_beacon_interval23a_from_ie(u8 *ie) -{ - return ie + 8; -} + if (padapter->mlmepriv.to_roaming > 0) { + DBG_8723A("roaming from %s("MAC_FMT"), length:%d\n", + pnetwork->network.Ssid.ssid, + MAC_ARG(pnetwork->network.MacAddress), + pnetwork->network.Ssid.ssid_len); + memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.Ssid, + sizeof(struct cfg80211_ssid)); -int rtw_init_mlme_priv23a (struct rtw_adapter *padapter)/* struct mlme_priv *pmlmepriv) */ -{ - int res; + pmlmepriv->assoc_by_bssid = false; - res = _rtw_init_mlme_priv23a(padapter);/* (pmlmepriv); */ + while (1) { + do_join_r = rtw_do_join23a(padapter); + if (do_join_r == _SUCCESS) + break; + else { + DBG_8723A("roaming do_join return %d\n", + do_join_r); + pmlmepriv->to_roaming--; - return res; + if (padapter->mlmepriv.to_roaming > 0) + continue; + else { + DBG_8723A("%s(%d) -to roaming fail, " + "indicate_disconnect\n", + __func__, __LINE__); + rtw_indicate_disconnect23a(padapter); + break; + } + } + } + } } -void rtw_free_mlme_priv23a (struct mlme_priv *pmlmepriv) +void rtw23a_roaming(struct rtw_adapter *padapter, + struct wlan_network *tgt_network) { + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_mlme_priv23a\n")); - _rtw_free_mlme_priv23a(pmlmepriv); - + spin_lock_bh(&pmlmepriv->lock); + _rtw_roaming(padapter, tgt_network); + spin_unlock_bh(&pmlmepriv->lock); } -void rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 is_freeall); -void rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 is_freeall)/* struct wlan_network *pnetwork, _queue *free_queue) */ +__le16 *rtw_get_capability23a_from_ie(u8 *ie) { - - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, - ("rtw_free_network ==> ssid = %s\n\n" , - pnetwork->network.Ssid.ssid)); - _rtw_free_network23a(pmlmepriv, pnetwork, is_freeall); - + return (__le16 *)(ie + 8 + 2); } -void rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork); -void rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork) +u16 rtw_get_capability23a(struct wlan_bssid_ex *bss) { + u16 val; - /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_network ==> ssid = %s\n\n" , pnetwork->network.Ssid.ssid)); */ - _rtw_free_network23a_nolock23a(pmlmepriv, pnetwork); + memcpy(&val, rtw_get_capability23a_from_ie(bss->IEs), 2); + return le16_to_cpu(val); } -void rtw_free_network_queue23a(struct rtw_adapter* dev, u8 isfreeall) +__le16 *rtw_get_beacon_interval23a_from_ie(u8 *ie) { - - _rtw_free_network23a_queue23a(dev, isfreeall); - + return (__le16 *)(ie + 8); } -/* - return the wlan_network with the matching addr - - Shall be calle under atomic context... to avoid possible racing condition... -*/ -struct wlan_network * -rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr) +static void rtw_free_network_nolock(struct mlme_priv *pmlmepriv, + struct wlan_network *pnetwork) { - struct wlan_network *pnetwork; - - pnetwork = _rtw_find_network23a(scanned_queue, addr); - - return pnetwork; + _rtw_free_network23a(pmlmepriv, pnetwork); } -int rtw_is_same_ibss23a(struct rtw_adapter *adapter, struct wlan_network *pnetwork) +int rtw_is_same_ibss23a(struct rtw_adapter *adapter, + struct wlan_network *pnetwork) { int ret = true; struct security_priv *psecuritypriv = &adapter->securitypriv; - if ((psecuritypriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) && - (pnetwork->network.Privacy == 0)) - { + if (psecuritypriv->dot11PrivacyAlgrthm != _NO_PRIVACY_ && + pnetwork->network.Privacy == 0) ret = false; - } - else if ((psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_) && - (pnetwork->network.Privacy == 1)) - { + else if (psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_ && + pnetwork->network.Privacy == 1) ret = false; - } else - { ret = true; - } return ret; } @@ -363,21 +359,16 @@ int rtw_is_same_ibss23a(struct rtw_adapter *adapter, struct wlan_network *pnetwo inline int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b); inline int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b) { - /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("(%s,%d)(%s,%d)\n", */ - /* a->Ssid.Ssid, a->Ssid.SsidLength, b->Ssid.Ssid, b->Ssid.SsidLength)); */ return (a->Ssid.ssid_len == b->Ssid.ssid_len) && !memcmp(a->Ssid.ssid, b->Ssid.ssid, a->Ssid.ssid_len); } int is_same_network23a(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst) { - u16 s_cap, d_cap; - - memcpy((u8 *)&s_cap, rtw_get_capability23a_from_ie(src->IEs), 2); - memcpy((u8 *)&d_cap, rtw_get_capability23a_from_ie(dst->IEs), 2); + u16 s_cap, d_cap; - s_cap = le16_to_cpu(s_cap); - d_cap = le16_to_cpu(d_cap); + s_cap = get_unaligned_le16(rtw_get_capability23a_from_ie(src->IEs)); + d_cap = get_unaligned_le16(rtw_get_capability23a_from_ie(dst->IEs)); return ((src->Ssid.ssid_len == dst->Ssid.ssid_len) && /* (src->Configuration.DSConfig == dst->Configuration.DSConfig) && */ @@ -389,10 +380,10 @@ int is_same_network23a(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst) (d_cap & WLAN_CAPABILITY_ESS))); } -struct wlan_network *rtw_get_oldest_wlan_network23a(struct rtw_queue *scanned_queue) +struct wlan_network * +rtw_get_oldest_wlan_network23a(struct rtw_queue *scanned_queue) { struct list_head *plist, *phead; - struct wlan_network *pwlan; struct wlan_network *oldest = NULL; @@ -412,7 +403,7 @@ struct wlan_network *rtw_get_oldest_wlan_network23a(struct rtw_queue *scanned_qu } void update_network23a(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, - struct rtw_adapter * padapter, bool update_ie) + struct rtw_adapter *padapter, bool update_ie) { u8 ss_ori = dst->PhyInfo.SignalStrength; u8 sq_ori = dst->PhyInfo.SignalQuality; @@ -426,30 +417,35 @@ void update_network23a(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, u8 sq_final; long rssi_final; - DBG_8723A("%s %s(%pM, ch%u) ss_ori:%3u, sq_ori:%3u, rssi_ori:%3ld, ss_smp:%3u, sq_smp:%3u, rssi_smp:%3ld\n", + DBG_8723A("%s %s(%pM, ch%u) ss_ori:%3u, sq_ori:%3u, rssi_ori:%3ld, " + "ss_smp:%3u, sq_smp:%3u, rssi_smp:%3ld\n", __func__, src->Ssid.ssid, src->MacAddress, src->Configuration.DSConfig, ss_ori, sq_ori, rssi_ori, ss_smp, sq_smp, rssi_smp ); /* The rule below is 1/5 for sample value, 4/5 for history value */ - if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network23a(&padapter->mlmepriv.cur_network.network, src)) { + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && + is_same_network23a(&padapter->mlmepriv.cur_network.network, src)) { /* Take the recvpriv's value for the connected AP*/ ss_final = padapter->recvpriv.signal_strength; sq_final = padapter->recvpriv.signal_qual; - /* the rssi value here is undecorated, and will be used for antenna diversity */ + /* the rssi value here is undecorated, and will be + used for antenna diversity */ if (sq_smp != 101) /* from the right channel */ rssi_final = (src->Rssi+dst->Rssi*4)/5; else rssi_final = rssi_ori; - } - else { + } else { if (sq_smp != 101) { /* from the right channel */ - ss_final = ((u32)(src->PhyInfo.SignalStrength)+(u32)(dst->PhyInfo.SignalStrength)*4)/5; - sq_final = ((u32)(src->PhyInfo.SignalQuality)+(u32)(dst->PhyInfo.SignalQuality)*4)/5; - rssi_final = (src->Rssi+dst->Rssi*4)/5; + ss_final = ((u32)src->PhyInfo.SignalStrength + + (u32)dst->PhyInfo.SignalStrength * 4) / 5; + sq_final = ((u32)src->PhyInfo.SignalQuality + + (u32)dst->PhyInfo.SignalQuality * 4) / 5; + rssi_final = src->Rssi+dst->Rssi * 4 / 5; } else { - /* bss info not receving from the right channel, use the original RX signal infos */ + /* bss info not receving from the right channel, use + the original RX signal infos */ ss_final = dst->PhyInfo.SignalStrength; sq_final = dst->PhyInfo.SignalQuality; rssi_final = dst->Rssi; @@ -458,35 +454,32 @@ void update_network23a(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, } if (update_ie) - memcpy((u8 *)dst, (u8 *)src, get_wlan_bssid_ex_sz(src)); + memcpy(dst, src, get_wlan_bssid_ex_sz(src)); dst->PhyInfo.SignalStrength = ss_final; dst->PhyInfo.SignalQuality = sq_final; dst->Rssi = rssi_final; - DBG_8723A("%s %s(%pM), SignalStrength:%u, SignalQuality:%u, RawRSSI:%ld\n", - __func__, dst->Ssid.ssid, dst->MacAddress, + DBG_8723A("%s %s(%pM), SignalStrength:%u, SignalQuality:%u, " + "RawRSSI:%ld\n", __func__, dst->Ssid.ssid, dst->MacAddress, dst->PhyInfo.SignalStrength, dst->PhyInfo.SignalQuality, dst->Rssi); - } -static void update_current_network(struct rtw_adapter *adapter, struct wlan_bssid_ex *pnetwork) +static void update_current_network(struct rtw_adapter *adapter, + struct wlan_bssid_ex *pnetwork) { - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - - if ((check_fwstate(pmlmepriv, _FW_LINKED)== true) && (is_same_network23a(&pmlmepriv->cur_network.network, pnetwork))) - { - /* RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,"Same Network\n"); */ + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - /* if(pmlmepriv->cur_network.network.IELength<= pnetwork->IELength) */ - { - update_network23a(&pmlmepriv->cur_network.network, pnetwork,adapter, true); - rtw_update_protection23a(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof (struct ndis_802_11_fixed_ies), - pmlmepriv->cur_network.network.IELength); - } + if (check_fwstate(pmlmepriv, _FW_LINKED) && + is_same_network23a(&pmlmepriv->cur_network.network, pnetwork)) { + update_network23a(&pmlmepriv->cur_network.network, + pnetwork,adapter, true); + rtw_update_protection23a(adapter, + pmlmepriv->cur_network.network.IEs + + sizeof (struct ndis_802_11_fixed_ies), + pmlmepriv->cur_network.network.IELength); } - } /* @@ -494,7 +487,8 @@ static void update_current_network(struct rtw_adapter *adapter, struct wlan_bssi Caller must hold pmlmepriv->lock first. */ -void rtw_update_scanned_network23a(struct rtw_adapter *adapter, struct wlan_bssid_ex *target) +void rtw_update_scanned_network23a(struct rtw_adapter *adapter, + struct wlan_bssid_ex *target) { struct list_head *plist, *phead; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; @@ -561,19 +555,20 @@ void rtw_update_scanned_network23a(struct rtw_adapter *adapter, struct wlan_bssi /* target.reserved == 1, means that scanned network is * a bcn frame. */ - if ((pnetwork->network.IELength>target->IELength) && - (target->reserved == 1)) + if (pnetwork->network.IELength > target->IELength && + target->reserved == 1) update_ie = false; - update_network23a(&pnetwork->network, target,adapter, update_ie); + update_network23a(&pnetwork->network, target,adapter, + update_ie); } exit: spin_unlock_bh(&queue->lock); - } -void rtw_add_network(struct rtw_adapter *adapter, struct wlan_bssid_ex *pnetwork) +static void rtw_add_network(struct rtw_adapter *adapter, + struct wlan_bssid_ex *pnetwork) { update_current_network(adapter, pnetwork); rtw_update_scanned_network23a(adapter, pnetwork); @@ -585,7 +580,8 @@ void rtw_add_network(struct rtw_adapter *adapter, struct wlan_bssid_ex *pnetwork /* (3) WMM */ /* (4) HT */ /* (5) others */ -int rtw_is_desired_network(struct rtw_adapter *adapter, struct wlan_network *pnetwork) +static int rtw_is_desired_network(struct rtw_adapter *adapter, + struct wlan_network *pnetwork) { struct security_priv *psecuritypriv = &adapter->securitypriv; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; @@ -600,31 +596,31 @@ int rtw_is_desired_network(struct rtw_adapter *adapter, struct wlan_network *pne desired_encmode = psecuritypriv->ndisencryptstatus; privacy = pnetwork->network.Privacy; - if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) - { - if (rtw_get_wps_ie23a(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen)!= NULL) - { + if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { + if (rtw_get_wps_ie23a(pnetwork->network.IEs + _FIXED_IE_LENGTH_, + pnetwork->network.IELength - + _FIXED_IE_LENGTH_, NULL, &wps_ielen)) return true; - } else - { return false; - } } - if (adapter->registrypriv.wifi_spec == 1) /* for correct flow of 8021X to do.... */ - { - if ((desired_encmode == Ndis802_11EncryptionDisabled) && (privacy != 0)) + if (adapter->registrypriv.wifi_spec == 1) { + /* for correct flow of 8021X to do.... */ + if (desired_encmode == Ndis802_11EncryptionDisabled && + privacy != 0) bselected = false; } - if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) { - DBG_8723A("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy); + if (desired_encmode != Ndis802_11EncryptionDisabled && + privacy == 0) { + DBG_8723A("desired_encmode: %d, privacy: %d\n", + desired_encmode, privacy); bselected = false; } - if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) - { - if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { + if (pnetwork->network.InfrastructureMode != + pmlmepriv->cur_network.network.InfrastructureMode) bselected = false; } @@ -632,15 +628,14 @@ int rtw_is_desired_network(struct rtw_adapter *adapter, struct wlan_network *pne } /* TODO: Perry : For Power Management */ -void rtw_atimdone_event_callback23a(struct rtw_adapter *adapter , u8 *pbuf) +void rtw_atimdone_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) { - RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("receive atimdone_evet\n")); return; } -void rtw_survey_event_cb23a(struct rtw_adapter *adapter, u8 *pbuf) +void rtw_survey_event_cb23a(struct rtw_adapter *adapter, u8 *pbuf) { u32 len; struct wlan_bssid_ex *pnetwork; @@ -648,31 +643,36 @@ void rtw_survey_event_cb23a(struct rtw_adapter *adapter, u8 *pbuf) pnetwork = (struct wlan_bssid_ex *)pbuf; - RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_survey_event_cb23a, ssid=%s\n", pnetwork->Ssid.ssid)); + RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_, + ("rtw_survey_event_cb23a, ssid=%s\n", pnetwork->Ssid.ssid)); len = get_wlan_bssid_ex_sz(pnetwork); - if(len > (sizeof(struct wlan_bssid_ex))) - { - RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n ****rtw_survey_event_cb23a: return a wrong bss ***\n")); + if (len > (sizeof(struct wlan_bssid_ex))) { + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, + ("\n ****rtw_survey_event_cb23a: return a wrong " + "bss ***\n")); return; } spin_lock_bh(&pmlmepriv->lock); /* update IBSS_network 's timestamp */ - if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) - { - /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,"rtw_survey_event_cb23a : WIFI_ADHOC_MASTER_STATE\n\n"); */ + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { + /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + "rtw_survey_event_cb23a : WIFI_ADHOC_MASTER_STATE\n\n"); */ if (ether_addr_equal(pmlmepriv->cur_network.network.MacAddress, pnetwork->MacAddress)) { - struct wlan_network* ibss_wlan = NULL; + struct wlan_network* ibss_wlan; - memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8); + memcpy(pmlmepriv->cur_network.network.IEs, + pnetwork->IEs, 8); spin_lock_bh(&pmlmepriv->scanned_queue.lock); - ibss_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, pnetwork->MacAddress); - if (ibss_wlan) - { - memcpy(ibss_wlan->network.IEs , pnetwork->IEs, 8); + ibss_wlan = rtw_find_network23a( + &pmlmepriv->scanned_queue, + pnetwork->MacAddress); + if (ibss_wlan) { + memcpy(ibss_wlan->network.IEs, + pnetwork->IEs, 8); spin_unlock_bh(&pmlmepriv->scanned_queue.lock); goto exit; } @@ -681,8 +681,7 @@ void rtw_survey_event_cb23a(struct rtw_adapter *adapter, u8 *pbuf) } /* lock pmlmepriv->lock when you accessing network_q */ - if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == false) - { + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == false) { if (pnetwork->Ssid.ssid[0] == 0) pnetwork->Ssid.ssid_len = 0; @@ -696,10 +695,12 @@ void rtw_survey_event_cb23a(struct rtw_adapter *adapter, u8 *pbuf) return; } -void rtw_surveydone_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) +void rtw_surveydone_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) { struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct wlan_bssid_ex *pdev_network; + u8 *pibss; spin_lock_bh(&pmlmepriv->lock); @@ -709,47 +710,62 @@ void rtw_surveydone_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) pmlmepriv->wps_probe_req_ie = NULL; } - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_surveydone_event_callback23a: fw_state:%x\n\n", get_fwstate(pmlmepriv))); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("rtw_surveydone_event_callback23a: fw_state:%x\n\n", + get_fwstate(pmlmepriv))); if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { del_timer_sync(&pmlmepriv->scan_to_timer); _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); } else { - - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("nic status =%x, survey done event comes too late!\n", get_fwstate(pmlmepriv))); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("nic status =%x, survey done event comes too late!\n", + get_fwstate(pmlmepriv))); } rtw_set_signal_stat_timer(&adapter->recvpriv); if (pmlmepriv->to_join == true) { - if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) { + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { if (check_fwstate(pmlmepriv, _FW_LINKED) == false) { set_fwstate(pmlmepriv, _FW_UNDER_LINKING); - if (rtw_select_and_join_from_scanned_queue23a(pmlmepriv) == _SUCCESS) { + if (rtw_select_and_join_from_scanned_queue23a( + pmlmepriv) == _SUCCESS) { mod_timer(&pmlmepriv->assoc_timer, jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT)); } else { - struct wlan_bssid_ex *pdev_network = &adapter->registrypriv.dev_network; - u8 *pibss = adapter->registrypriv.dev_network.MacAddress; + pdev_network = &adapter->registrypriv.dev_network; + pibss = adapter->registrypriv.dev_network.MacAddress; - _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); + _clr_fwstate_(pmlmepriv, + _FW_UNDER_SURVEY); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("switching to adhoc master\n")); + RT_TRACE(_module_rtl871x_mlme_c_, + _drv_err_, + ("switching to adhoc " + "master\n")); - memset(&pdev_network->Ssid, 0, sizeof(struct cfg80211_ssid)); - memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct cfg80211_ssid)); + memset(&pdev_network->Ssid, 0, + sizeof(struct cfg80211_ssid)); + memcpy(&pdev_network->Ssid, + &pmlmepriv->assoc_ssid, + sizeof(struct cfg80211_ssid)); - rtw_update_registrypriv_dev_network23a(adapter); + rtw_update_registrypriv_dev_network23a( + adapter); rtw_generate_random_ibss23a(pibss); - pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; + pmlmepriv->fw_state = + WIFI_ADHOC_MASTER_STATE; - if (rtw_createbss_cmd23a(adapter)!= _SUCCESS) - { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error =>rtw_createbss_cmd23a status FAIL\n")); - } + if (rtw_createbss_cmd23a(adapter) != + _SUCCESS) + RT_TRACE(_module_rtl871x_mlme_c_, + _drv_err_, + ("Error =>rtw_createbss_cmd23a" + " status FAIL\n")); pmlmepriv->to_join = false; } @@ -758,27 +774,32 @@ void rtw_surveydone_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) int ret; set_fwstate(pmlmepriv, _FW_UNDER_LINKING); pmlmepriv->to_join = false; - ret = rtw_select_and_join_from_scanned_queue23a(pmlmepriv); + ret = rtw_select_and_join_from_scanned_queue23a( + pmlmepriv); if (ret == _SUCCESS) { unsigned long e; e = msecs_to_jiffies(MAX_JOIN_TIMEOUT); mod_timer(&pmlmepriv->assoc_timer, jiffies + e); - } else if (ret == 2)/* there is no need to wait for join */ - { + } else if (ret == 2) {/* there is no need to wait */ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); rtw_indicate_connect23a(adapter); } else { - DBG_8723A("try_to_join, but select scanning queue fail, to_roaming:%d\n", rtw_to_roaming(adapter)); - if (rtw_to_roaming(adapter) != 0) { - if (--pmlmepriv->to_roaming == 0 - || _SUCCESS != rtw_sitesurvey_cmd23a(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0) - ) { + DBG_8723A("try_to_join, but select scanning " + "queue fail, to_roaming:%d\n", + adapter->mlmepriv.to_roaming); + if (adapter->mlmepriv.to_roaming) { + if (--pmlmepriv->to_roaming == 0 || + rtw_sitesurvey_cmd23a( + adapter, + &pmlmepriv->assoc_ssid, 1, + NULL, 0) != _SUCCESS) { rtw_set_roaming(adapter, 0); - rtw_free_assoc_resources23a(adapter, 1); - rtw_indicate_disconnect23a(adapter); - } else { + rtw_free_assoc_resources23a( + adapter, 1); + rtw_indicate_disconnect23a( + adapter); + } else pmlmepriv->to_join = true; - } } _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); } @@ -787,18 +808,12 @@ void rtw_surveydone_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) spin_unlock_bh(&pmlmepriv->lock); -#ifdef CONFIG_8723AU_P2P - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - p2p_ps_wk_cmd23a(adapter, P2P_PS_SCAN_DONE, 0); -#endif /* CONFIG_8723AU_P2P */ - rtw_os_xmit_schedule23a(adapter); - if(pmlmeext->sitesurvey_res.bss_cnt == 0) + if (pmlmeext->sitesurvey_res.bss_cnt == 0) rtw_hal_sreset_reset23a(adapter); rtw_cfg80211_surveydone_event_callback(adapter); - } void rtw_dummy_event_callback23a(struct rtw_adapter *adapter , u8 *pbuf) @@ -809,7 +824,7 @@ void rtw23a_fwdbg_event_callback(struct rtw_adapter *adapter , u8 *pbuf) { } -static void free_scanqueue(struct mlme_priv *pmlmepriv) +static void free_scanqueue(struct mlme_priv *pmlmepriv) { struct wlan_network *pnetwork; struct rtw_queue *scan_queue = &pmlmepriv->scanned_queue; @@ -827,42 +842,38 @@ static void free_scanqueue(struct mlme_priv *pmlmepriv) } spin_unlock_bh(&scan_queue->lock); - } /* -*rtw_free_assoc_resources23a: the caller has to lock pmlmepriv->lock -*/ -void rtw_free_assoc_resources23a(struct rtw_adapter *adapter, int lock_scanned_queue) + *rtw_free_assoc_resources23a: the caller has to lock pmlmepriv->lock + */ +void rtw_free_assoc_resources23a(struct rtw_adapter *adapter, + int lock_scanned_queue) { - struct wlan_network* pwlan = NULL; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - struct sta_priv *pstapriv = &adapter->stapriv; + struct wlan_network* pwlan; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct sta_priv *pstapriv = &adapter->stapriv; struct wlan_network *tgt_network = &pmlmepriv->cur_network; + struct sta_info* psta; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources23a\n")); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("tgt_network->network.MacAddress="MAC_FMT" ssid=%s\n", - MAC_ARG(tgt_network->network.MacAddress), tgt_network->network.Ssid.ssid)); - - if(check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_AP_STATE)) - { - struct sta_info* psta; - - psta = rtw_get_stainfo23a(&adapter->stapriv, tgt_network->network.MacAddress); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, + ("+rtw_free_assoc_resources23a\n")); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("tgt_network->network.MacAddress="MAC_FMT" ssid=%s\n", + MAC_ARG(tgt_network->network.MacAddress), + tgt_network->network.Ssid.ssid)); - { - spin_lock_bh(&pstapriv->sta_hash_lock); - rtw_free_stainfo23a(adapter, psta); - } + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_AP_STATE)) { + psta = rtw_get_stainfo23a(&adapter->stapriv, + tgt_network->network.MacAddress); + spin_lock_bh(&pstapriv->sta_hash_lock); + rtw_free_stainfo23a(adapter, psta); spin_unlock_bh(&pstapriv->sta_hash_lock); - } - if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE)) - { - struct sta_info* psta; - + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | + WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE)) { rtw_free_all_stainfo23a(adapter); psta = rtw_get_bcmc_stainfo23a(adapter); @@ -873,23 +884,25 @@ void rtw_free_assoc_resources23a(struct rtw_adapter *adapter, int lock_scanned_q rtw_init_bcmc_stainfo23a(adapter); } - if(lock_scanned_queue) + if (lock_scanned_queue) spin_lock_bh(&pmlmepriv->scanned_queue.lock); - pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); - if(pwlan) + pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, + tgt_network->network.MacAddress); + if (pwlan) pwlan->fixed = false; else - RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("rtw_free_assoc_resources23a : pwlan== NULL\n\n")); + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, + ("rtw_free_assoc_resources23a : pwlan== NULL\n")); - if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1)) + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && + adapter->stapriv.asoc_sta_count == 1) rtw_free_network_nolock(pmlmepriv, pwlan); - if(lock_scanned_queue) + if (lock_scanned_queue) spin_unlock_bh(&pmlmepriv->scanned_queue.lock); pmlmepriv->key_mask = 0; - } /* @@ -897,46 +910,54 @@ void rtw_free_assoc_resources23a(struct rtw_adapter *adapter, int lock_scanned_q */ void rtw_indicate_connect23a(struct rtw_adapter *padapter) { - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_connect23a\n")); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("+rtw_indicate_connect23a\n")); pmlmepriv->to_join = false; - if(!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { + if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { set_fwstate(pmlmepriv, _FW_LINKED); rtw_led_control(padapter, LED_CTL_LINK); - rtw_os_indicate_connect23a(padapter); + rtw_cfg80211_indicate_connect(padapter); + + netif_carrier_on(padapter->pnetdev); + + if (padapter->pid[2] != 0) + kill_pid(find_vpid(padapter->pid[2]), SIGALRM, 1); } rtw_set_roaming(padapter, 0); rtw_set_scan_deny(padapter, 3000); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-rtw_indicate_connect23a: fw_state=0x%08x\n", get_fwstate(pmlmepriv))); - + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("-rtw_indicate_connect23a: fw_state=0x%08x\n", + get_fwstate(pmlmepriv))); } /* -*rtw_indicate_disconnect23a: the caller has to lock pmlmepriv->lock -*/ + *rtw_indicate_disconnect23a: the caller has to lock pmlmepriv->lock + */ void rtw_indicate_disconnect23a(struct rtw_adapter *padapter) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_disconnect23a\n")); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("+rtw_indicate_disconnect23a\n")); _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING|WIFI_UNDER_WPS); /* DBG_8723A("clear wps when %s\n", __func__); */ - if (rtw_to_roaming(padapter) > 0) + if (padapter->mlmepriv.to_roaming > 0) _clr_fwstate_(pmlmepriv, _FW_LINKED); if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) || - (rtw_to_roaming(padapter) <= 0)) { + padapter->mlmepriv.to_roaming <= 0) { rtw_os_indicate_disconnect23a(padapter); /* set ips_deny_time to avoid enter IPS before LPS leave */ @@ -951,17 +972,7 @@ void rtw_indicate_disconnect23a(struct rtw_adapter *padapter) } -#ifdef CONFIG_8723AU_P2P - p2p_ps_wk_cmd23a(padapter, P2P_PS_DISABLE, 1); -#endif /* CONFIG_8723AU_P2P */ - rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_DISCONNECT, 1); - -} - -inline void rtw_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted) -{ - rtw_os_indicate_scan_done23a(padapter, aborted); } void rtw_scan_abort23a(struct rtw_adapter *adapter) @@ -974,36 +985,39 @@ void rtw_scan_abort23a(struct rtw_adapter *adapter) pmlmeext->scan_abort = true; while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) && jiffies_to_msecs(jiffies - start) <= 200) { - if (adapter->bDriverStopped || adapter->bSurpriseRemoved) break; - DBG_8723A(FUNC_NDEV_FMT"fw_state = _FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev)); + DBG_8723A(FUNC_NDEV_FMT "fw_state = _FW_UNDER_SURVEY!\n", + FUNC_NDEV_ARG(adapter->pnetdev)); msleep(20); } if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { if (!adapter->bDriverStopped && !adapter->bSurpriseRemoved) - DBG_8723A(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev)); - rtw_indicate_scan_done23a(adapter, true); + DBG_8723A(FUNC_NDEV_FMT "waiting for scan_abort time " + "out!\n", FUNC_NDEV_ARG(adapter->pnetdev)); + rtw_cfg80211_indicate_scan_done(wdev_to_priv(adapter->rtw_wdev), + true); } pmlmeext->scan_abort = false; } -static struct sta_info *rtw_joinbss_update_stainfo(struct rtw_adapter *padapter, struct wlan_network *pnetwork) +static struct sta_info * +rtw_joinbss_update_stainfo(struct rtw_adapter *padapter, + struct wlan_network *pnetwork) { int i; - struct sta_info *bmc_sta, *psta = NULL; + struct sta_info *bmc_sta, *psta; struct recv_reorder_ctrl *preorder_ctrl; struct sta_priv *pstapriv = &padapter->stapriv; psta = rtw_get_stainfo23a(pstapriv, pnetwork->network.MacAddress); - if (psta == NULL) { - psta = rtw_alloc_stainfo23a(pstapriv, pnetwork->network.MacAddress); - } + if (!psta) + psta = rtw_alloc_stainfo23a(pstapriv, + pnetwork->network.MacAddress); - if (psta) /* update ptarget_sta */ - { + if (psta) { /* update ptarget_sta */ DBG_8723A("%s\n", __func__); psta->aid = pnetwork->join_res; @@ -1013,57 +1027,63 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct rtw_adapter *padapter, rtw_hal_set_odm_var23a(padapter, HAL_ODM_STA_INFO, psta, true); /* security related */ - if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) - { + if (padapter->securitypriv.dot11AuthAlgrthm == + dot11AuthAlgrthm_8021X) { padapter->securitypriv.binstallGrpkey = false; padapter->securitypriv.busetkipkey = false; padapter->securitypriv.bgrpkey_handshake = false; psta->ieee8021x_blocked = true; - psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; + psta->dot118021XPrivacy = + padapter->securitypriv.dot11PrivacyAlgrthm; - memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof (union Keytype)); + memset(&psta->dot118021x_UncstKey, 0, + sizeof (union Keytype)); - memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof (union Keytype)); - memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof (union Keytype)); + memset(&psta->dot11tkiprxmickey, 0, + sizeof (union Keytype)); + memset(&psta->dot11tkiptxmickey, 0, + sizeof (union Keytype)); - memset((u8 *)&psta->dot11txpn, 0, sizeof (union pn48)); - memset((u8 *)&psta->dot11rxpn, 0, sizeof (union pn48)); + memset(&psta->dot11txpn, 0, sizeof (union pn48)); + memset(&psta->dot11rxpn, 0, sizeof (union pn48)); } /* Commented by Albert 2012/07/21 */ /* When doing the WPS, the wps_ie_len won't equal to 0 */ - /* And the Wi-Fi driver shouldn't allow the data packet to be tramsmitted. */ - if (padapter->securitypriv.wps_ie_len != 0) - { + /* And the Wi-Fi driver shouldn't allow the data packet + to be tramsmitted. */ + if (padapter->securitypriv.wps_ie_len != 0) { psta->ieee8021x_blocked = true; padapter->securitypriv.wps_ie_len = 0; } - /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info */ - /* if A-MPDU Rx is enabled, reseting rx_ordering_ctrl wstart_b(indicate_seq) to default value = 0xffff */ + /* for A-MPDU Rx reordering buffer control for bmc_sta & + * sta_info */ + /* if A-MPDU Rx is enabled, reseting + rx_ordering_ctrl wstart_b(indicate_seq) to default + value = 0xffff */ /* todo: check if AP can send A-MPDU packets */ - for (i = 0; i < 16 ; i++) - { + for (i = 0; i < 16 ; i++) { /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ preorder_ctrl = &psta->recvreorder_ctrl[i]; preorder_ctrl->enable = false; preorder_ctrl->indicate_seq = 0xffff; preorder_ctrl->wend_b = 0xffff; - preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */ + /* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */ + preorder_ctrl->wsize_b = 64; } bmc_sta = rtw_get_bcmc_stainfo23a(padapter); - if (bmc_sta) - { - for (i = 0; i < 16 ; i++) - { - /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ + if (bmc_sta) { + for (i = 0; i < 16 ; i++) { preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; preorder_ctrl->enable = false; preorder_ctrl->indicate_seq = 0xffff; preorder_ctrl->wend_b = 0xffff; - preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */ + /* max_ampdu_sz; ex. 32(kbytes) -> + wsize_b = 32 */ + preorder_ctrl->wsize_b = 64; } } @@ -1077,29 +1097,41 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct rtw_adapter *padapter, /* pnetwork : returns from rtw23a_joinbss_event_cb */ /* ptarget_wlan: found from scanned_queue */ -static void rtw_joinbss_update_network23a(struct rtw_adapter *padapter, struct wlan_network *ptarget_wlan, struct wlan_network *pnetwork) +static void +rtw_joinbss_update_network23a(struct rtw_adapter *padapter, + struct wlan_network *ptarget_wlan, + struct wlan_network *pnetwork) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_network *cur_network = &pmlmepriv->cur_network; DBG_8723A("%s\n", __func__); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\nfw_state:%x, BSSID:"MAC_FMT"\n" - , get_fwstate(pmlmepriv), MAC_ARG(pnetwork->network.MacAddress))); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("\nfw_state:%x, BSSID:"MAC_FMT"\n", get_fwstate(pmlmepriv), + MAC_ARG(pnetwork->network.MacAddress))); /* why not use ptarget_wlan?? */ - memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length); + memcpy(&cur_network->network, &pnetwork->network, + pnetwork->network.Length); /* some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */ cur_network->network.IELength = ptarget_wlan->network.IELength; - memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0], MAX_IE_SZ); + memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0], + MAX_IE_SZ); cur_network->aid = pnetwork->join_res; rtw_set_signal_stat_timer(&padapter->recvpriv); - padapter->recvpriv.signal_strength = ptarget_wlan->network.PhyInfo.SignalStrength; - padapter->recvpriv.signal_qual = ptarget_wlan->network.PhyInfo.SignalQuality; - /* the ptarget_wlan->network.Rssi is raw data, we use ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) */ - padapter->recvpriv.rssi = translate_percentage_to_dbm(ptarget_wlan->network.PhyInfo.SignalStrength); + padapter->recvpriv.signal_strength = + ptarget_wlan->network.PhyInfo.SignalStrength; + padapter->recvpriv.signal_qual = + ptarget_wlan->network.PhyInfo.SignalQuality; + /* + * the ptarget_wlan->network.Rssi is raw data, we use + * ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) + */ + padapter->recvpriv.rssi = translate_percentage_to_dbm( + ptarget_wlan->network.PhyInfo.SignalStrength); DBG_8723A("%s signal_strength:%3u, rssi:%3d, signal_qual:%3u\n", __func__, padapter->recvpriv.signal_strength, padapter->recvpriv.rssi, padapter->recvpriv.signal_qual); @@ -1118,40 +1150,51 @@ static void rtw_joinbss_update_network23a(struct rtw_adapter *padapter, struct w break; default: pmlmepriv->fw_state = WIFI_NULL_STATE; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Invalid network_mode\n")); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("Invalid network_mode\n")); break; } - rtw_update_protection23a(padapter, (cur_network->network.IEs) + sizeof (struct ndis_802_11_fixed_ies), - (cur_network->network.IELength)); + rtw_update_protection23a(padapter, cur_network->network.IEs + + sizeof (struct ndis_802_11_fixed_ies), + cur_network->network.IELength); - rtw_update_ht_cap23a(padapter, cur_network->network.IEs, cur_network->network.IELength); + rtw_update_ht_cap23a(padapter, cur_network->network.IEs, + cur_network->network.IELength); } -/* Notes: the fucntion could be > passive_level (the same context as Rx tasklet) */ -/* pnetwork : returns from rtw23a_joinbss_event_cb */ -/* ptarget_wlan: found from scanned_queue */ -/* if join_res > 0, for (fw_state==WIFI_STATION_STATE), we check if "ptarget_sta" & "ptarget_wlan" exist. */ -/* if join_res > 0, for (fw_state==WIFI_ADHOC_STATE), we only check if "ptarget_wlan" exist. */ -/* if join_res > 0, update "cur_network->network" from "pnetwork->network" if (ptarget_wlan !=NULL). */ +/* + * Notes: + * the fucntion could be > passive_level (the same context as Rx tasklet) + * pnetwork : returns from rtw23a_joinbss_event_cb + * ptarget_wlan: found from scanned_queue + * if join_res > 0, for (fw_state==WIFI_STATION_STATE), + * we check if "ptarget_sta" & "ptarget_wlan" exist. + * if join_res > 0, for (fw_state==WIFI_ADHOC_STATE), + * we only check if "ptarget_wlan" exist. + * if join_res > 0, update "cur_network->network" from "pnetwork->network" + * if (ptarget_wlan !=NULL). + */ void rtw_joinbss_event_prehandle23a(struct rtw_adapter *adapter, u8 *pbuf) { - static u8 retry=0; - struct sta_info *ptarget_sta= NULL, *pcur_sta = NULL; - struct sta_priv *pstapriv = &adapter->stapriv; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - struct wlan_network *pnetwork = (struct wlan_network *)pbuf; + struct sta_info *ptarget_sta, *pcur_sta; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct wlan_network *pnetwork = (struct wlan_network *)pbuf; struct wlan_network *cur_network = &pmlmepriv->cur_network; - struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL; - unsigned int the_same_macaddr = false; + struct wlan_network *pcur_wlan, *ptarget_wlan = NULL; + bool the_same_macaddr; - RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("joinbss event call back received with res=%d\n", pnetwork->join_res)); + RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_, + ("joinbss event call back received with res=%d\n", + pnetwork->join_res)); rtw_get_encrypt_decrypt_from_registrypriv23a(adapter); if (pmlmepriv->assoc_ssid.ssid_len == 0) { - RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("@@@@@ joinbss event call back for Any SSid\n")); + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, + ("@@@@@ joinbss event call back for Any SSid\n")); } else { RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, ("@@@@@ rtw23a_joinbss_event_cb for SSid:%s\n", @@ -1165,93 +1208,102 @@ void rtw_joinbss_event_prehandle23a(struct rtw_adapter *adapter, u8 *pbuf) the_same_macaddr = false; pnetwork->network.Length = get_wlan_bssid_ex_sz(&pnetwork->network); - if(pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) - { - RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n\n ***joinbss_evt_callback return a wrong bss ***\n\n")); + if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) { + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, + ("\n\n ***joinbss_evt_callback return a wrong bss " + "***\n\n")); return; } spin_lock_bh(&pmlmepriv->lock); - RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n rtw23a_joinbss_event_cb !! _enter_critical\n")); + RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_, + ("\n rtw23a_joinbss_event_cb !! _enter_critical\n")); - if(pnetwork->join_res > 0) - { + if (pnetwork->join_res > 0) { spin_lock_bh(&pmlmepriv->scanned_queue.lock); - retry = 0; - if (check_fwstate(pmlmepriv,_FW_UNDER_LINKING)) - { + if (check_fwstate(pmlmepriv,_FW_UNDER_LINKING)) { /* s1. find ptarget_wlan */ - if(check_fwstate(pmlmepriv, _FW_LINKED)) - { - if(the_same_macaddr == true) - { + if (check_fwstate(pmlmepriv, _FW_LINKED)) { + if (the_same_macaddr == true) { ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); - } - else - { + } else { pcur_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); - if(pcur_wlan) pcur_wlan->fixed = false; + if (pcur_wlan) + pcur_wlan->fixed = false; pcur_sta = rtw_get_stainfo23a(pstapriv, cur_network->network.MacAddress); - if(pcur_sta) { + if (pcur_sta) { spin_lock_bh(&pstapriv->sta_hash_lock); - rtw_free_stainfo23a(adapter, pcur_sta); + rtw_free_stainfo23a(adapter, + pcur_sta); spin_unlock_bh(&pstapriv->sta_hash_lock); } ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress); - if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { - if(ptarget_wlan) ptarget_wlan->fixed = true; + if (check_fwstate(pmlmepriv, + WIFI_STATION_STATE)) { + if (ptarget_wlan) + ptarget_wlan->fixed = + true; } } - } - else - { - ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress); - if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { - if(ptarget_wlan) ptarget_wlan->fixed = true; + } else { + ptarget_wlan = rtw_find_network23a( + &pmlmepriv->scanned_queue, + pnetwork->network.MacAddress); + if (check_fwstate(pmlmepriv, + WIFI_STATION_STATE)) { + if (ptarget_wlan) + ptarget_wlan->fixed = true; } } /* s2. update cur_network */ - if(ptarget_wlan) - { - rtw_joinbss_update_network23a(adapter, ptarget_wlan, pnetwork); - } - else - { - RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Can't find ptarget_wlan when joinbss_event callback\n")); + if (ptarget_wlan) + rtw_joinbss_update_network23a(adapter, + ptarget_wlan, + pnetwork); + else { + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, + ("Can't find ptarget_wlan when " + "joinbss_event callback\n")); spin_unlock_bh(&pmlmepriv->scanned_queue.lock); goto ignore_joinbss_callback; } - /* s3. find ptarget_sta & update ptarget_sta after update cur_network only for station mode */ - if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) - { - ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork); - if(ptarget_sta==NULL) - { - RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Can't update stainfo when joinbss_event callback\n")); + /* s3. find ptarget_sta & update ptarget_sta after + update cur_network only for station mode */ + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + ptarget_sta = rtw_joinbss_update_stainfo( + adapter, pnetwork); + if (!ptarget_sta) { + RT_TRACE(_module_rtl871x_mlme_c_, + _drv_err_, + ("Can't update stainfo when " + "joinbss_event callback\n")); spin_unlock_bh(&pmlmepriv->scanned_queue.lock); goto ignore_joinbss_callback; } } /* s4. indicate connect */ - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) - { + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) rtw_indicate_connect23a(adapter); - } else { - /* adhoc mode will rtw_indicate_connect23a when rtw_stassoc_event_callback23a */ - RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("adhoc mode, fw_state:%x", get_fwstate(pmlmepriv))); + else { + /* adhoc mode will rtw_indicate_connect23a + when rtw_stassoc_event_callback23a */ + RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_, + ("adhoc mode, fw_state:%x", + get_fwstate(pmlmepriv))); } /* s5. Cancle assoc_timer */ del_timer_sync(&pmlmepriv->assoc_timer); - RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("Cancle assoc_timer\n")); + RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_, + ("Cancle assoc_timer\n")); } else { RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw23a_joinbss_event_cb err: fw_state:%x", @@ -1260,20 +1312,19 @@ void rtw_joinbss_event_prehandle23a(struct rtw_adapter *adapter, u8 *pbuf) goto ignore_joinbss_callback; } spin_unlock_bh(&pmlmepriv->scanned_queue.lock); - } else if(pnetwork->join_res == -4) { + } else if (pnetwork->join_res == -4) { rtw_reset_securitypriv23a(adapter); mod_timer(&pmlmepriv->assoc_timer, jiffies + msecs_to_jiffies(1)); /* rtw_free_assoc_resources23a(adapter, 1); */ - if((check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) { + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, - ("fail! clear _FW_UNDER_LINKING ^^^fw_state=%x\n", - get_fwstate(pmlmepriv))); + ("fail! clear _FW_UNDER_LINKING ^^^fw_state=" + "%x\n", get_fwstate(pmlmepriv))); _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); } - } else { /* if join_res < 0 (join fails), then try again */ mod_timer(&pmlmepriv->assoc_timer, @@ -1288,46 +1339,31 @@ void rtw_joinbss_event_prehandle23a(struct rtw_adapter *adapter, u8 *pbuf) void rtw23a_joinbss_event_cb(struct rtw_adapter *adapter, u8 *pbuf) { - struct wlan_network *pnetwork = (struct wlan_network *)pbuf; + struct wlan_network *pnetwork = (struct wlan_network *)pbuf; mlmeext_joinbss_event_callback23a(adapter, pnetwork->join_res); rtw_os_xmit_schedule23a(adapter); - -} - -/* FOR AP , AD-HOC mode */ -void rtw_stassoc_hw_rpt23a(struct rtw_adapter *adapter, struct sta_info *psta) -{ - u16 media_status; - - if (psta == NULL) return; - - media_status = (psta->mac_id<<8)|1; /* MACID|OPMODE:1 connect */ - rtw_hal_set_hwreg23a(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); } void rtw_stassoc_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) { struct sta_info *psta; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - struct stassoc_event *pstassoc = (struct stassoc_event*)pbuf; + struct stassoc_event *pstassoc = (struct stassoc_event*)pbuf; struct wlan_network *cur_network = &pmlmepriv->cur_network; - struct wlan_network *ptarget_wlan = NULL; + struct wlan_network *ptarget_wlan; - if(rtw_access_ctrl23a(adapter, pstassoc->macaddr) == false) + if (rtw_access_ctrl23a(adapter, pstassoc->macaddr) == false) return; #ifdef CONFIG_8723AU_AP_MODE - if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) - { + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { psta = rtw_get_stainfo23a(&adapter->stapriv, pstassoc->macaddr); if (psta) { /* bss_cap_update_on_sta_join23a(adapter, psta); */ /* sta_info_update23a(adapter, psta); */ ap_sta_info_defer_update23a(adapter, psta); - - rtw_stassoc_hw_rpt23a(adapter,psta); } return; } @@ -1336,13 +1372,19 @@ void rtw_stassoc_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) psta = rtw_get_stainfo23a(&adapter->stapriv, pstassoc->macaddr); if (psta != NULL) { /* the sta have been in sta_info_queue => do nothing */ - RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Error: rtw_stassoc_event_callback23a: sta has been in sta_hash_queue\n")); - return; /* between drv has received this event before and fw have not yet to set key to CAM_ENTRY) */ + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, + ("Error: rtw_stassoc_event_callback23a: sta has " + "been in sta_hash_queue\n")); + /* between drv has received this event before and + fw have not yet to set key to CAM_ENTRY) */ + return; } psta = rtw_alloc_stainfo23a(&adapter->stapriv, pstassoc->macaddr); - if (psta == NULL) { - RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Can't alloc sta_info when rtw_stassoc_event_callback23a\n")); + if (!psta) { + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, + ("Can't alloc sta_info when " + "rtw_stassoc_event_callback23a\n")); return; } @@ -1352,25 +1394,25 @@ void rtw_stassoc_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) /* psta->aid = (uint)pstassoc->cam_id; */ DBG_8723A("%s\n",__func__); /* for ad-hoc mode */ - rtw_hal_set_odm_var23a(adapter,HAL_ODM_STA_INFO,psta,true); - - rtw_stassoc_hw_rpt23a(adapter,psta); + rtw_hal_set_odm_var23a(adapter, HAL_ODM_STA_INFO, psta, true); - if(adapter->securitypriv.dot11AuthAlgrthm==dot11AuthAlgrthm_8021X) - psta->dot118021XPrivacy = adapter->securitypriv.dot11PrivacyAlgrthm; + if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) + psta->dot118021XPrivacy = + adapter->securitypriv.dot11PrivacyAlgrthm; psta->ieee8021x_blocked = false; spin_lock_bh(&pmlmepriv->lock); - if ( (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)==true ) || - (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)==true ) ) - { - if(adapter->stapriv.asoc_sta_count== 2) - { + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || + check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { + if (adapter->stapriv.asoc_sta_count == 2) { spin_lock_bh(&pmlmepriv->scanned_queue.lock); - ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); - if(ptarget_wlan) ptarget_wlan->fixed = true; + ptarget_wlan = + rtw_find_network23a(&pmlmepriv->scanned_queue, + cur_network->network.MacAddress); + if (ptarget_wlan) + ptarget_wlan->fixed = true; spin_unlock_bh(&pmlmepriv->scanned_queue.lock); /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ rtw_indicate_connect23a(adapter); @@ -1384,47 +1426,40 @@ void rtw_stassoc_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) void rtw_stadel_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) { - int mac_id=-1; + int mac_id; struct sta_info *psta; - struct wlan_network* pwlan = NULL; - struct wlan_bssid_ex *pdev_network=NULL; - u8* pibss = NULL; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - struct stadel_event *pstadel = (struct stadel_event*)pbuf; - struct sta_priv *pstapriv = &adapter->stapriv; + struct wlan_network* pwlan; + struct wlan_bssid_ex *pdev_network; + u8 *pibss; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct stadel_event *pstadel = (struct stadel_event *)pbuf; + struct sta_priv *pstapriv = &adapter->stapriv; struct wlan_network *tgt_network = &pmlmepriv->cur_network; psta = rtw_get_stainfo23a(&adapter->stapriv, pstadel->macaddr); - if(psta) + if (psta) mac_id = psta->mac_id; else mac_id = pstadel->mac_id; - DBG_8723A("%s(mac_id=%d)=" MAC_FMT "\n", __func__, mac_id, MAC_ARG(pstadel->macaddr)); - - if(mac_id>=0) { - u16 media_status; - media_status = (mac_id<<8)|0; /* MACID|OPMODE:0 means disconnect */ - /* for STA,AP,ADHOC mode, report disconnect stauts to FW */ - rtw_hal_set_hwreg23a(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); - } + DBG_8723A("%s(mac_id=%d)=" MAC_FMT "\n", __func__, mac_id, + MAC_ARG(pstadel->macaddr)); if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) - { return; - } mlmeext_sta_del_event_callback23a(adapter); spin_lock_bh(&pmlmepriv->lock); - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) - { - if (rtw_to_roaming(adapter) > 0) - pmlmepriv->to_roaming--; /* this stadel_event is caused by roaming, decrease to_roaming */ - else if (rtw_to_roaming(adapter) == 0) + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + if (adapter->mlmepriv.to_roaming > 0) { + /* this stadel_event is caused by roaming, + decrease to_roaming */ + pmlmepriv->to_roaming--; + } else if (adapter->mlmepriv.to_roaming == 0) rtw_set_roaming(adapter, adapter->registrypriv.max_roaming_times); - if (*((unsigned short *)(pstadel->rsvd)) != WLAN_REASON_EXPIRATION_CHK) + if (*((u16 *)pstadel->rsvd) != WLAN_REASON_EXPIRATION_CHK) rtw_set_roaming(adapter, 0); /* don't roam */ rtw_free_uc_swdec_pending_queue23a(adapter); @@ -1433,32 +1468,33 @@ void rtw_stadel_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) rtw_indicate_disconnect23a(adapter); spin_lock_bh(&pmlmepriv->scanned_queue.lock); /* remove the network entry in scanned_queue */ - pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); + pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, + tgt_network->network.MacAddress); if (pwlan) { pwlan->fixed = false; rtw_free_network_nolock(pmlmepriv, pwlan); } spin_unlock_bh(&pmlmepriv->scanned_queue.lock); - _rtw23a_roaming(adapter, tgt_network); + _rtw_roaming(adapter, tgt_network); } if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || - check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) - { + check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { spin_lock_bh(&pstapriv->sta_hash_lock); rtw_free_stainfo23a(adapter, psta); spin_unlock_bh(&pstapriv->sta_hash_lock); - if (adapter->stapriv.asoc_sta_count == 1) /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ - { + /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ + if (adapter->stapriv.asoc_sta_count == 1) { spin_lock_bh(&pmlmepriv->scanned_queue.lock); /* free old ibss network */ - /* pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, pstadel->macaddr); */ - pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); - if (pwlan) - { + /* pwlan = rtw_find_network23a( + &pmlmepriv->scanned_queue, pstadel->macaddr); */ + pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, + tgt_network->network.MacAddress); + if (pwlan) { pwlan->fixed = false; rtw_free_network_nolock(pmlmepriv, pwlan); } @@ -1467,7 +1503,8 @@ void rtw_stadel_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) pdev_network = &adapter->registrypriv.dev_network; pibss = adapter->registrypriv.dev_network.MacAddress; - memcpy(pdev_network, &tgt_network->network, get_wlan_bssid_ex_sz(&tgt_network->network)); + memcpy(pdev_network, &tgt_network->network, + get_wlan_bssid_ex_sz(&tgt_network->network)); memset(&pdev_network->Ssid, 0, sizeof(struct cfg80211_ssid)); @@ -1478,32 +1515,28 @@ void rtw_stadel_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) rtw_generate_random_ibss23a(pibss); - if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) - { + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE); _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE); } - if (rtw_createbss_cmd23a(adapter)!= _SUCCESS) - { - - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error =>stadel_event_callback: rtw_createbss_cmd23a status FAIL***\n ")); - + if (rtw_createbss_cmd23a(adapter) != _SUCCESS) { + RT_TRACE(_module_rtl871x_ioctl_set_c_, + _drv_err_, + ("***Error =>stadel_event_callback: " + "rtw_createbss_cmd23a status " + "FAIL***\n")); } - } - } spin_unlock_bh(&pmlmepriv->lock); - } void rtw_cpwm_event_callback23a(struct rtw_adapter *padapter, u8 *pbuf) { - - RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("+rtw_cpwm_event_callback23a !!!\n")); - + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("+rtw_cpwm_event_callback23a !!!\n")); } /* @@ -1518,23 +1551,28 @@ void rtw23a_join_to_handler (unsigned long data) DBG_8723A("%s, fw_state=%x\n", __func__, get_fwstate(pmlmepriv)); - if(adapter->bDriverStopped ||adapter->bSurpriseRemoved) + if (adapter->bDriverStopped ||adapter->bSurpriseRemoved) return; spin_lock_bh(&pmlmepriv->lock); - if (rtw_to_roaming(adapter) > 0) { /* join timeout caused by roaming */ - while(1) { + if (adapter->mlmepriv.to_roaming > 0) { + /* join timeout caused by roaming */ + while (1) { pmlmepriv->to_roaming--; - if (rtw_to_roaming(adapter) != 0) { /* try another */ + if (adapter->mlmepriv.to_roaming != 0) { + /* try another */ DBG_8723A("%s try another roaming\n", __func__); - if (_SUCCESS!= (do_join_r = rtw_do_join23a(adapter))) { - DBG_8723A("%s roaming do_join return %d\n", __func__ , do_join_r); + do_join_r = rtw_do_join23a(adapter); + if (do_join_r != _SUCCESS) { + DBG_8723A("%s roaming do_join return " + "%d\n", __func__ , do_join_r); continue; } break; } else { - DBG_8723A("%s We've try roaming but fail\n", __func__); + DBG_8723A("%s We've try roaming but fail\n", + __func__); rtw_indicate_disconnect23a(adapter); break; } @@ -1543,7 +1581,8 @@ void rtw23a_join_to_handler (unsigned long data) rtw_indicate_disconnect23a(adapter); free_scanqueue(pmlmepriv);/* */ - /* indicate disconnect for the case that join_timeout and check_fwstate != FW_LINKED */ + /* indicate disconnect for the case that join_timeout and + check_fwstate != FW_LINKED */ rtw_cfg80211_indicate_disconnect(adapter); } @@ -1560,7 +1599,8 @@ void rtw_scan_timeout_handler23a(unsigned long data) struct rtw_adapter *adapter = (struct rtw_adapter *)data; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - DBG_8723A(FUNC_ADPT_FMT" fw_state =%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv)); + DBG_8723A(FUNC_ADPT_FMT" fw_state =%x\n", FUNC_ADPT_ARG(adapter), + get_fwstate(pmlmepriv)); spin_lock_bh(&pmlmepriv->lock); @@ -1568,7 +1608,7 @@ void rtw_scan_timeout_handler23a(unsigned long data) spin_unlock_bh(&pmlmepriv->lock); - rtw_indicate_scan_done23a(adapter, true); + rtw_cfg80211_indicate_scan_done(wdev_to_priv(adapter->rtw_wdev), true); } static void rtw_auto_scan_handler(struct rtw_adapter *padapter) @@ -1581,7 +1621,8 @@ static void rtw_auto_scan_handler(struct rtw_adapter *padapter) if (pmlmepriv->scan_interval == 0) { DBG_8723A("%s\n", __func__); rtw_set_802_11_bssid23a_list_scan(padapter, NULL, 0); - pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ + /* 30*2 sec = 60sec */ + pmlmepriv->scan_interval = SCAN_INTERVAL; } } } @@ -1594,7 +1635,8 @@ void rtw_dynamic_check_timer_handler(unsigned long data) if (adapter->hw_init_completed == false) goto out; - if ((adapter->bDriverStopped == true)||(adapter->bSurpriseRemoved == true)) + if (adapter->bDriverStopped == true || + adapter->bSurpriseRemoved == true) goto out; if (adapter->net_closed == true) @@ -1602,16 +1644,9 @@ void rtw_dynamic_check_timer_handler(unsigned long data) rtw_dynamic_chk_wk_cmd23a(adapter); - if (pregistrypriv->wifi_spec == 1) - { -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &adapter->wdinfo; - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -#endif - { - /* auto site survey */ - rtw_auto_scan_handler(adapter); - } + if (pregistrypriv->wifi_spec == 1) { + /* auto site survey */ + rtw_auto_scan_handler(adapter); } out: mod_timer(&adapter->mlmepriv.dynamic_chk_timer, @@ -1628,8 +1663,6 @@ void rtw_clear_scan_deny(struct rtw_adapter *adapter) { struct mlme_priv *mlmepriv = &adapter->mlmepriv; atomic_set(&mlmepriv->set_scan_deny, 0); - if (0) - DBG_8723A(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); } void rtw_set_scan_deny_timer_hdl(unsigned long data) @@ -1642,12 +1675,9 @@ void rtw_set_scan_deny(struct rtw_adapter *adapter, u32 ms) { struct mlme_priv *mlmepriv = &adapter->mlmepriv; - if (0) - DBG_8723A(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); atomic_set(&mlmepriv->set_scan_deny, 1); mod_timer(&mlmepriv->set_scan_deny_timer, jiffies + msecs_to_jiffies(ms)); - } #if defined(IEEE80211_SCAN_RESULT_EXPIRE) @@ -1657,15 +1687,19 @@ void rtw_set_scan_deny(struct rtw_adapter *adapter, u32 ms) #endif /* -* Select a new join candidate from the original @param candidate and @param competitor +* Select a new join candidate from the original @param candidate and +* @param competitor * @return true: candidate is updated * @return false: candidate is not updated */ -static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv - , struct wlan_network **candidate, struct wlan_network *competitor) +static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv, + struct wlan_network **candidate, + struct wlan_network *competitor) { int updated = false; - struct rtw_adapter *adapter = container_of(pmlmepriv, struct rtw_adapter, mlmepriv); + struct rtw_adapter *adapter; + + adapter = container_of(pmlmepriv, struct rtw_adapter, mlmepriv); /* check bssid, if needed */ if (pmlmepriv->assoc_by_bssid == true) { @@ -1684,10 +1718,10 @@ static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv goto exit; } - if (rtw_is_desired_network(adapter, competitor) == false) + if (rtw_is_desired_network(adapter, competitor) == false) goto exit; - if (rtw_to_roaming(adapter) > 0) { + if (adapter->mlmepriv.to_roaming > 0) { unsigned int passed; passed = jiffies_to_msecs(jiffies - competitor->last_scanned); @@ -1697,19 +1731,21 @@ static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv goto exit; } - if (*candidate == NULL ||(*candidate)->network.Rssinetwork.Rssi) { + if (!*candidate || + (*candidate)->network.Rssinetwork.Rssi) { *candidate = competitor; updated = true; } if (updated) { - DBG_8723A("[by_bssid:%u][assoc_ssid:%s][to_roaming:%u] new candidate: %s("MAC_FMT") rssi:%d\n", - pmlmepriv->assoc_by_bssid, - pmlmepriv->assoc_ssid.ssid, - rtw_to_roaming(adapter), - (*candidate)->network.Ssid.ssid, - MAC_ARG((*candidate)->network.MacAddress), - (int)(*candidate)->network.Rssi); + DBG_8723A("[by_bssid:%u][assoc_ssid:%s][to_roaming:%u] " + "new candidate: %s("MAC_FMT") rssi:%d\n", + pmlmepriv->assoc_by_bssid, + pmlmepriv->assoc_ssid.ssid, + adapter->mlmepriv.to_roaming, + (*candidate)->network.Ssid.ssid, + MAC_ARG((*candidate)->network.MacAddress), + (int)(*candidate)->network.Rssi); } exit: @@ -1732,8 +1768,8 @@ int rtw_select_and_join_from_scanned_queue23a(struct mlme_priv *pmlmepriv) struct list_head *phead, *plist, *ptmp; struct rtw_adapter *adapter; struct rtw_queue *queue = &pmlmepriv->scanned_queue; - struct wlan_network *pnetwork = NULL; - struct wlan_network *candidate = NULL; + struct wlan_network *pnetwork; + struct wlan_network *candidate = NULL; spin_lock_bh(&pmlmepriv->scanned_queue.lock); phead = get_list_head(queue); @@ -1764,7 +1800,7 @@ int rtw_select_and_join_from_scanned_queue23a(struct mlme_priv *pmlmepriv) } /* check for situation of _FW_LINKED */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + if (check_fwstate(pmlmepriv, _FW_LINKED)) { DBG_8723A("%s: _FW_LINKED while ask_for_joinbss!!!\n", __func__); @@ -1782,7 +1818,7 @@ int rtw_select_and_join_from_scanned_queue23a(struct mlme_priv *pmlmepriv) } int rtw_set_auth23a(struct rtw_adapter * adapter, - struct security_priv *psecuritypriv) + struct security_priv *psecuritypriv) { struct cmd_obj* pcmd; struct setauth_parm *psetauthparm; @@ -1811,8 +1847,6 @@ int rtw_set_auth23a(struct rtw_adapter * adapter, pcmd->rsp = NULL; pcmd->rspsz = 0; - INIT_LIST_HEAD(&pcmd->list); - RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, ("after enqueue set_auth_cmd, auth_mode=%x\n", psecuritypriv->dot11AuthAlgrthm)); @@ -1825,7 +1859,7 @@ int rtw_set_auth23a(struct rtw_adapter * adapter, } int rtw_set_key23a(struct rtw_adapter *adapter, - struct security_priv *psecuritypriv, int keyid, u8 set_tx) + struct security_priv *psecuritypriv, int keyid, u8 set_tx) { u8 keylen; struct cmd_obj *pcmd; @@ -1850,9 +1884,9 @@ int rtw_set_key23a(struct rtw_adapter *adapter, psetkeyparm->algorithm = (unsigned char) psecuritypriv->dot118021XGrpPrivacy; RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, - ("\n rtw_set_key23a: psetkeyparm->algorithm = (unsigned " - "char)psecuritypriv->dot118021XGrpPrivacy =%d\n", - psetkeyparm->algorithm)); + ("\n rtw_set_key23a: psetkeyparm->algorithm = " + "(unsigned char)psecuritypriv->dot118021XGrpPrivacy " + "=%d\n", psetkeyparm->algorithm)); } else { psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm; RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, @@ -1897,8 +1931,8 @@ int rtw_set_key23a(struct rtw_adapter *adapter, break; default: RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, - ("\n rtw_set_key23a:psecuritypriv->dot11PrivacyAlgrthm = " - "%x (must be 1 or 2 or 4 or 5)\n", + ("\n rtw_set_key23a:psecuritypriv->dot11PrivacyAlgrthm" + " = %x (must be 1 or 2 or 4 or 5)\n", psecuritypriv->dot11PrivacyAlgrthm)); res = _FAIL; kfree(pcmd); @@ -1912,8 +1946,6 @@ int rtw_set_key23a(struct rtw_adapter *adapter, pcmd->rsp = NULL; pcmd->rspsz = 0; - INIT_LIST_HEAD(&pcmd->list); - /* sema_init(&pcmd->cmd_sem, 0); */ res = rtw_enqueue_cmd23a(pcmdpriv, pcmd); @@ -1931,7 +1963,7 @@ int rtw_restruct_wmm_ie23a(struct rtw_adapter *adapter, u8 *in_ie, unsigned int i, j; i = 12; /* after the fixed IE */ - while(i < in_len) { + while (i < in_len) { ielength = initial_out_len; /* WMM element ID and OUI */ @@ -1982,11 +2014,11 @@ static int SecIsInPMKIDList(struct rtw_adapter *Adapter, u8 *bssid) i++; /* continue; */ } - } while(i < NUM_PMKID_CACHE); + } while (i < NUM_PMKID_CACHE); - if (i == NUM_PMKID_CACHE) { + if (i == NUM_PMKID_CACHE) i = -1;/* Could not find. */ - } else { + else { /* There is one Pre-Authentication Key for the specific BSSID. */ } @@ -2023,8 +2055,9 @@ static int rtw_append_pmkid(struct rtw_adapter *Adapter, int iEntry, } return ie_len; } + int rtw_restruct_sec_ie23a(struct rtw_adapter *adapter, u8 *in_ie, u8 *out_ie, - uint in_len) + uint in_len) { u8 authmode; uint ielength; @@ -2035,41 +2068,39 @@ int rtw_restruct_sec_ie23a(struct rtw_adapter *adapter, u8 *in_ie, u8 *out_ie, uint ndissecuritytype = psecuritypriv->ndisencryptstatus; RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, - ("+rtw_restruct_sec_ie23a: ndisauthmode=%d ndissecuritytype=%d\n", - ndisauthmode, ndissecuritytype)); + ("+rtw_restruct_sec_ie23a: ndisauthmode=%d " + "ndissecuritytype=%d\n", ndisauthmode, ndissecuritytype)); /* copy fixed ie only */ memcpy(out_ie, in_ie, 12); ielength = 12; - if ((ndisauthmode==Ndis802_11AuthModeWPA) || - (ndisauthmode==Ndis802_11AuthModeWPAPSK)) - authmode=_WPA_IE_ID_; - if ((ndisauthmode==Ndis802_11AuthModeWPA2) || - (ndisauthmode==Ndis802_11AuthModeWPA2PSK)) - authmode=_WPA2_IE_ID_; + if (ndisauthmode == Ndis802_11AuthModeWPA || + ndisauthmode == Ndis802_11AuthModeWPAPSK) + authmode = WLAN_EID_VENDOR_SPECIFIC; + if (ndisauthmode == Ndis802_11AuthModeWPA2 || + ndisauthmode == Ndis802_11AuthModeWPA2PSK) + authmode = _WPA2_IE_ID_; if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { memcpy(out_ie + ielength, psecuritypriv->wps_ie, psecuritypriv->wps_ie_len); ielength += psecuritypriv->wps_ie_len; - } else if ((authmode==_WPA_IE_ID_) || (authmode==_WPA2_IE_ID_)) { + } else if (authmode == WLAN_EID_VENDOR_SPECIFIC || + authmode == _WPA2_IE_ID_) { /* copy RSN or SSN */ memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], psecuritypriv->supplicant_ie[1] + 2); ielength += psecuritypriv->supplicant_ie[1] + 2; - rtw_report_sec_ie23a(adapter, authmode, - psecuritypriv->supplicant_ie); } iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid); - if (iEntry < 0) { + if (iEntry < 0) return ielength; - } else { - if (authmode == _WPA2_IE_ID_) { - ielength=rtw_append_pmkid(adapter, iEntry, - out_ie, ielength); - } + else { + if (authmode == _WPA2_IE_ID_) + ielength = rtw_append_pmkid(adapter, iEntry, + out_ie, ielength); } return ielength; @@ -2157,12 +2188,11 @@ void rtw_update_registrypriv_dev_network23a(struct rtw_adapter* adapter) pdev_network->IELength = sz; pdev_network->Length = - get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network); + get_wlan_bssid_ex_sz(pdev_network); /* notes: translate IELength & Length after assign the Length to cmdsz in createbss_cmd(); */ /* pdev_network->IELength = cpu_to_le32(sz); */ - } void rtw_get_encrypt_decrypt_from_registrypriv23a(struct rtw_adapter* adapter) @@ -2193,22 +2223,20 @@ void rtw_joinbss_reset23a(struct rtw_adapter *padapter) threshold = 1; else threshold = 0; - rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH, - (u8 *)(&threshold)); - } else { + } else threshold = 1; - rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH, - (u8 *)(&threshold)); - } + + rtl8723a_set_rxdma_agg_pg_th(padapter, threshold); } /* the fucntion is >= passive_level */ unsigned int rtw_restructure_ht_ie23a(struct rtw_adapter *padapter, u8 *in_ie, - u8 *out_ie, uint in_len, uint *pout_len) + u8 *out_ie, uint in_len, uint *pout_len) { - u32 ielen, out_len; + u32 out_len; int max_rx_ampdu_factor; - unsigned char *p, *pframe; + unsigned char *pframe; + const u8 *p; struct ieee80211_ht_cap ht_capie; unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -2217,14 +2245,14 @@ unsigned int rtw_restructure_ht_ie23a(struct rtw_adapter *padapter, u8 *in_ie, phtpriv->ht_option = false; - p = rtw_get_ie23a(in_ie + 12, _HT_CAPABILITY_IE_, &ielen, in_len - 12); + p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, in_ie + 12, in_len -12); - if (p && ielen > 0) { + if (p && p[1] > 0) { u32 rx_packet_offset, max_recvbuf_sz; if (pqospriv->qos_option == 0) { out_len = *pout_len; pframe = rtw_set_ie23a(out_ie + out_len, - _VENDOR_SPECIFIC_IE_, + WLAN_EID_VENDOR_SPECIFIC, _WMM_IE_Length_, WMM_IE, pout_len); pqospriv->qos_option = 1; @@ -2254,17 +2282,19 @@ unsigned int rtw_restructure_ht_ie23a(struct rtw_adapter *padapter, u8 *in_ie, ht_capie.ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_DENSITY & 0x00); - pframe = rtw_set_ie23a(out_ie + out_len, _HT_CAPABILITY_IE_, + pframe = rtw_set_ie23a(out_ie + out_len, WLAN_EID_HT_CAPABILITY, sizeof(struct ieee80211_ht_cap), (unsigned char*)&ht_capie, pout_len); phtpriv->ht_option = true; - p = rtw_get_ie23a(in_ie + 12, _HT_ADD_INFO_IE_, &ielen, in_len-12); - if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) { + p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, in_ie + 12, + in_len -12); + if (p && (p[1] == sizeof(struct ieee80211_ht_addt_info))) { out_len = *pout_len; - pframe = rtw_set_ie23a(out_ie + out_len, _HT_ADD_INFO_IE_, - ielen, p + 2 , pout_len); + pframe = rtw_set_ie23a(out_ie + out_len, + WLAN_EID_HT_OPERATION, + p[1], p + 2 , pout_len); } } @@ -2274,18 +2304,14 @@ unsigned int rtw_restructure_ht_ie23a(struct rtw_adapter *padapter, u8 *in_ie, /* the fucntion is > passive_level (in critical_section) */ void rtw_update_ht_cap23a(struct rtw_adapter *padapter, u8 *pie, uint ie_len) { - u8 *p, max_ampdu_sz; - int len; - /* struct sta_info *bmc_sta, *psta; */ + u8 max_ampdu_sz; + const u8 *p; struct ieee80211_ht_cap *pht_capie; struct ieee80211_ht_addt_info *pht_addtinfo; - /* struct recv_reorder_ctrl *preorder_ctrl; */ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; - /* struct recv_priv *precvpriv = &padapter->recvpriv; */ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; struct registry_priv *pregistrypriv = &padapter->registrypriv; - /* struct wlan_network *pcur_network = &pmlmepriv->cur_network;; */ - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; if (!phtpriv->ht_option) @@ -2296,51 +2322,51 @@ void rtw_update_ht_cap23a(struct rtw_adapter *padapter, u8 *pie, uint ie_len) DBG_8723A("+rtw_update_ht_cap23a()\n"); + /* Adjust pie + ie_len for our searches */ + pie += sizeof (struct ndis_802_11_fixed_ies); + ie_len -= sizeof (struct ndis_802_11_fixed_ies); + /* maybe needs check if ap supports rx ampdu. */ - if ((phtpriv->ampdu_enable == false) && (pregistrypriv->ampdu_enable == 1)) { + if (phtpriv->ampdu_enable == false && + pregistrypriv->ampdu_enable == 1) { if (pregistrypriv->wifi_spec == 1) phtpriv->ampdu_enable = false; else phtpriv->ampdu_enable = true; - } else if (pregistrypriv->ampdu_enable == 2) { + } else if (pregistrypriv->ampdu_enable == 2) phtpriv->ampdu_enable = true; - } /* check Max Rx A-MPDU Size */ - len = 0; - p = rtw_get_ie23a(pie+sizeof (struct ndis_802_11_fixed_ies), _HT_CAPABILITY_IE_, &len, ie_len-sizeof (struct ndis_802_11_fixed_ies)); - if (p && len > 0) { - pht_capie = (struct ieee80211_ht_cap *)(p+2); - max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_FACTOR); - max_ampdu_sz = 1 << (max_ampdu_sz+3); /* max_ampdu_sz (kbytes); */ - - /* DBG_8723A("rtw_update_ht_cap23a(): max_ampdu_sz =%d\n", max_ampdu_sz); */ - phtpriv->rx_ampdu_maxlen = max_ampdu_sz; + p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, pie, ie_len); + + if (p && p[1] > 0) { + pht_capie = (struct ieee80211_ht_cap *)(p + 2); + max_ampdu_sz = pht_capie->ampdu_params_info & + IEEE80211_HT_AMPDU_PARM_FACTOR; + /* max_ampdu_sz (kbytes); */ + max_ampdu_sz = 1 << (max_ampdu_sz + 3); + phtpriv->rx_ampdu_maxlen = max_ampdu_sz; } - len = 0; - p = rtw_get_ie23a(pie+sizeof (struct ndis_802_11_fixed_ies), _HT_ADD_INFO_IE_, &len, ie_len-sizeof (struct ndis_802_11_fixed_ies)); - if (p && len>0) - { - pht_addtinfo = (struct ieee80211_ht_addt_info *)(p+2); + p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, pie, ie_len); + if (p && p[1] > 0) { + pht_addtinfo = (struct ieee80211_ht_addt_info *)(p + 2); /* todo: */ } /* update cur_bwmode & cur_ch_offset */ - if ((pregistrypriv->cbw40_enable) && - (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & BIT(1)) && - (pmlmeinfo->HT_info.infos[0] & BIT(2))) - { + if (pregistrypriv->cbw40_enable && + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & BIT(1) && + pmlmeinfo->HT_info.infos[0] & BIT(2)) { int i; - u8 rf_type; + u8 rf_type; - padapter->HalFunc.GetHwRegHandler(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + rf_type = rtl8723a_get_rf_type(padapter); /* update the MCS rates */ - for (i = 0; i < 16; i++) - { - if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R)) + for (i = 0; i < 16; i++) { + if (rf_type == RF_1T1R || rf_type == RF_1T2R) pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R23A[i]; else pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R23A[i]; @@ -2349,24 +2375,26 @@ void rtw_update_ht_cap23a(struct rtw_adapter *padapter, u8 *pie, uint ie_len) pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) { - case HT_EXTCHNL_OFFSET_UPPER: - pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; - break; + case HT_EXTCHNL_OFFSET_UPPER: + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; + break; - case HT_EXTCHNL_OFFSET_LOWER: - pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; - break; + case HT_EXTCHNL_OFFSET_LOWER: + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; + break; - default: - pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; - break; + default: + pmlmeext->cur_ch_offset = + HAL_PRIME_CHNL_OFFSET_DONT_CARE; + break; } } /* */ /* Config SM Power Save setting */ /* */ - pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2; + pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & + 0x0C) >> 2; if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) DBG_8723A("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__); @@ -2376,124 +2404,65 @@ void rtw_update_ht_cap23a(struct rtw_adapter *padapter, u8 *pie, uint ie_len) pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; } -void rtw_issue_addbareq_cmd23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe) +void rtw_issue_addbareq_cmd23a(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe) { u8 issued; int priority; - struct sta_info *psta = NULL; + struct sta_info *psta; struct ht_priv *phtpriv; struct pkt_attrib *pattrib = &pxmitframe->attrib; s32 bmcst = is_multicast_ether_addr(pattrib->ra); - if (bmcst || (padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod<100)) + if (bmcst || padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod < 100) return; priority = pattrib->priority; if (pattrib->psta) psta = pattrib->psta; - else - { + else { DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__); psta = rtw_get_stainfo23a(&padapter->stapriv, pattrib->ra); } - if (psta == NULL) - { + if (!psta) { DBG_8723A("%s, psta == NUL\n", __func__); return; } - if (!(psta->state &_FW_LINKED)) - { - DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + if (!(psta->state &_FW_LINKED)) { + DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", + __func__, psta->state); return; } phtpriv = &psta->htpriv; - if ((phtpriv->ht_option == true) && (phtpriv->ampdu_enable == true)) - { + if (phtpriv->ht_option == true && phtpriv->ampdu_enable == true) { issued = (phtpriv->agg_enable_bitmap>>priority)&0x1; issued |= (phtpriv->candidate_tid_bitmap>>priority)&0x1; - if (0 == issued) - { - DBG_8723A("rtw_issue_addbareq_cmd23a, p =%d\n", priority); - psta->htpriv.candidate_tid_bitmap |= CHKBIT((u8)priority); - rtw_addbareq_cmd23a(padapter, (u8) priority, pattrib->ra); - } - } -} - -inline void rtw_set_roaming(struct rtw_adapter *adapter, u8 to_roaming) -{ - if (to_roaming == 0) - adapter->mlmepriv.to_join = false; - adapter->mlmepriv.to_roaming = to_roaming; -} - -inline u8 rtw_to_roaming(struct rtw_adapter *adapter) -{ - return adapter->mlmepriv.to_roaming; -} - -void rtw23a_roaming(struct rtw_adapter *padapter, struct wlan_network *tgt_network) -{ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - spin_lock_bh(&pmlmepriv->lock); - _rtw23a_roaming(padapter, tgt_network); - spin_unlock_bh(&pmlmepriv->lock); -} -void _rtw23a_roaming(struct rtw_adapter *padapter, struct wlan_network *tgt_network) -{ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_network *pnetwork; - int do_join_r; - - if (tgt_network != NULL) - pnetwork = tgt_network; - else - pnetwork = &pmlmepriv->cur_network; - - if (0 < rtw_to_roaming(padapter)) { - DBG_8723A("roaming from %s("MAC_FMT"), length:%d\n", - pnetwork->network.Ssid.ssid, - MAC_ARG(pnetwork->network.MacAddress), - pnetwork->network.Ssid.ssid_len); - memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.Ssid, - sizeof(struct cfg80211_ssid)); - - pmlmepriv->assoc_by_bssid = false; - - while(1) { - if (_SUCCESS == (do_join_r = rtw_do_join23a(padapter))) { - break; - } else { - DBG_8723A("roaming do_join return %d\n", do_join_r); - pmlmepriv->to_roaming--; - - if (0 < rtw_to_roaming(padapter)) { - continue; - } else { - DBG_8723A("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__); - rtw_indicate_disconnect23a(padapter); - break; - } - } + if (issued == 0) { + DBG_8723A("rtw_issue_addbareq_cmd23a, p =%d\n", + priority); + psta->htpriv.candidate_tid_bitmap |= + CHKBIT((u8)priority); + rtw_addbareq_cmd23a(padapter, (u8) priority, + pattrib->ra); } } } int rtw_linked_check(struct rtw_adapter *padapter) { - if ((check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE)) || - (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE))) { + if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) || + check_fwstate(&padapter->mlmepriv, + WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) { if (padapter->stapriv.asoc_sta_count > 2) return true; } else { /* Station mode */ - if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == true) + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) return true; } return false; diff --git a/drivers/staging/rtl8723au/core/rtw_mlme_ext.c b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c index 1f3e8a0aece460..eb7b98e2e5be6e 100644 --- a/drivers/staging/rtl8723au/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c @@ -21,13 +21,34 @@ #include #include #include -#include #include #ifdef CONFIG_8723AU_BT_COEXIST #include #endif +static int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnProbeReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnProbeRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int DoReserved23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnBeacon23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnAtim23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnDisassoc23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnAuth23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnAuth23aClient23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnDeAuth23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnAction23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); + +static int on_action_spct23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnAction23a_qos(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnAction23a_dls(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int on_action_public23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnAction23a_ht(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnAction23a_wmm(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +static int OnAction23a_p2p(struct rtw_adapter *padapter, struct recv_frame *precv_frame); + static struct mlme_handler mlme_sta_tbl[]={ {"OnAssocReq23a", &OnAssocReq23a}, {"OnAssocRsp23a", &OnAssocRsp23a}, @@ -66,7 +87,6 @@ static u8 null_addr[ETH_ALEN]= {0, 0, 0, 0, 0, 0}; /************************************************** OUI definitions for the vendor specific IE ***************************************************/ -unsigned char RTW_WPA_OUI23A[] = {0x00, 0x50, 0xf2, 0x01}; unsigned char WMM_OUI23A[] = {0x00, 0x50, 0xf2, 0x02}; unsigned char WPS_OUI23A[] = {0x00, 0x50, 0xf2, 0x04}; unsigned char P2P_OUI23A[] = {0x50, 0x6F, 0x9A, 0x09}; @@ -229,6 +249,17 @@ static struct fwevent wlanevents[] = }; +static void rtw_correct_TSF(struct rtw_adapter *padapter) +{ + hw_var_set_correct_tsf(padapter); +} + +static void +rtw_update_TSF(struct mlme_ext_priv *pmlmeext, struct ieee80211_mgmt *mgmt) +{ + pmlmeext->TSFValue = get_unaligned_le64(&mgmt->u.beacon.timestamp); +} + /* * Search the @param channel_num in given @param channel_set * @ch_set: the given channel set @@ -388,96 +419,88 @@ static void init_channel_list(struct rtw_adapter *padapter, channel_list->reg_classes = cla; } -static u8 init_channel_set(struct rtw_adapter* padapter, u8 ChannelPlan, - struct rt_channel_info *channel_set) +static u8 init_channel_set(struct rtw_adapter* padapter, u8 cplan, + struct rt_channel_info *c_set) { - u8 index, chanset_size = 0; - u8 b5GBand = false, b2_4GBand = false; - u8 Index2G = 0, Index5G = 0; + u8 i, ch_size = 0; + u8 b5GBand = false, b2_4GBand = false; + u8 Index2G = 0, Index5G = 0; - memset(channel_set, 0, sizeof(struct rt_channel_info)*MAX_CHANNEL_NUM); + memset(c_set, 0, sizeof(struct rt_channel_info) * MAX_CHANNEL_NUM); - if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && - ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) { - DBG_8723A("ChannelPlan ID %x error !!!!!\n", ChannelPlan); - return chanset_size; + if (cplan >= RT_CHANNEL_DOMAIN_MAX && + cplan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) { + DBG_8723A("ChannelPlan ID %x error !!!!!\n", cplan); + return ch_size; } if (padapter->registrypriv.wireless_mode & WIRELESS_11G) { b2_4GBand = true; - if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan) + if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == cplan) Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G; else - Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G; + Index2G = RTW_ChannelPlanMap[cplan].Index2G; } if (padapter->registrypriv.wireless_mode & WIRELESS_11A) { b5GBand = true; - if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan) + if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == cplan) Index5G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index5G; else - Index5G = RTW_ChannelPlanMap[ChannelPlan].Index5G; + Index5G = RTW_ChannelPlanMap[cplan].Index5G; } if (b2_4GBand) { - for (index = 0; index= 1 && - channel_set[chanset_size].ChannelNum <= 11) - channel_set[chanset_size].ScanType = - SCAN_ACTIVE; - else if ((channel_set[chanset_size].ChannelNum >= 12 && - channel_set[chanset_size].ChannelNum <= 14)) - channel_set[chanset_size].ScanType = - SCAN_PASSIVE; - } else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == - ChannelPlan || - RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == - ChannelPlan || + RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G == cplan) { + if (c_set[ch_size].ChannelNum >= 1 && + c_set[ch_size].ChannelNum <= 11) + c_set[ch_size].ScanType = SCAN_ACTIVE; + else if (c_set[ch_size].ChannelNum >= 12 && + c_set[ch_size].ChannelNum <= 14) + c_set[ch_size].ScanType = SCAN_PASSIVE; + } else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == cplan || + RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == cplan || RT_CHANNEL_DOMAIN_2G_WORLD == Index2G) { /* channel 12~13, passive scan */ - if (channel_set[chanset_size].ChannelNum <= 11) - channel_set[chanset_size].ScanType = - SCAN_ACTIVE; + if (c_set[ch_size].ChannelNum <= 11) + c_set[ch_size].ScanType = SCAN_ACTIVE; else - channel_set[chanset_size].ScanType = - SCAN_PASSIVE; + c_set[ch_size].ScanType = SCAN_PASSIVE; } else - channel_set[chanset_size].ScanType = - SCAN_ACTIVE; + c_set[ch_size].ScanType = SCAN_ACTIVE; - chanset_size++; + ch_size++; } } if (b5GBand) { - for (index = 0;index= 149) { - channel_set[chanset_size].ChannelNum = - RTW_ChannelPlan5G[Index5G].Channel[index]; - if (RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == - ChannelPlan) { + for (i = 0; i < RTW_ChannelPlan5G[Index5G].Len; i++) { + if (RTW_ChannelPlan5G[Index5G].Channel[i] <= 48 || + RTW_ChannelPlan5G[Index5G].Channel[i] >= 149) { + c_set[ch_size].ChannelNum = + RTW_ChannelPlan5G[Index5G].Channel[i]; + if (RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == cplan) { /* passive scan for all 5G channels */ - channel_set[chanset_size].ScanType = + c_set[ch_size].ScanType = SCAN_PASSIVE; } else - channel_set[chanset_size].ScanType = + c_set[ch_size].ScanType = SCAN_ACTIVE; DBG_8723A("%s(): channel_set[%d].ChannelNum = " - "%d\n", __func__, chanset_size, - channel_set[chanset_size].ChannelNum); - chanset_size++; + "%d\n", __func__, ch_size, + c_set[ch_size].ChannelNum); + ch_size++; } } } - return chanset_size; + return ch_size; } int init_mlme_ext_priv23a(struct rtw_adapter* padapter) @@ -547,28 +570,28 @@ _mgt_dispatcher23a(struct rtw_adapter *padapter, struct mlme_handler *ptable, void mgt_dispatcher23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { - int index; struct mlme_handler *ptable; #ifdef CONFIG_8723AU_AP_MODE struct mlme_priv *pmlmepriv = &padapter->mlmepriv; #endif /* CONFIG_8723AU_AP_MODE */ struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 stype; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data; struct sta_info *psta; + u16 stype; + int index; - if (!ieee80211_is_mgmt(hdr->frame_control)) + if (!ieee80211_is_mgmt(mgmt->frame_control)) return; /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ - if (!ether_addr_equal(hdr->addr1, myid(&padapter->eeprompriv)) && - !is_broadcast_ether_addr(hdr->addr1)) + if (!ether_addr_equal(mgmt->da, myid(&padapter->eeprompriv)) && + !is_broadcast_ether_addr(mgmt->da)) return; ptable = mlme_sta_tbl; - stype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE; + stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; index = stype >> 4; if (index > 13) { @@ -579,10 +602,10 @@ void mgt_dispatcher23a(struct rtw_adapter *padapter, } ptable += index; - psta = rtw_get_stainfo23a(&padapter->stapriv, hdr->addr2); + psta = rtw_get_stainfo23a(&padapter->stapriv, mgmt->sa); if (psta) { - if (ieee80211_has_retry(hdr->frame_control)) { + if (ieee80211_has_retry(mgmt->frame_control)) { if (precv_frame->attrib.seq_num == psta->RxMgmtFrameSeqNum) { /* drop the duplicate management frame */ @@ -623,8 +646,6 @@ void mgt_dispatcher23a(struct rtw_adapter *padapter, break; default: _mgt_dispatcher23a(padapter, ptable, precv_frame); - if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) - rtw_hostapd_mlme_rx23a(padapter, precv_frame); break; } #else @@ -632,186 +653,63 @@ void mgt_dispatcher23a(struct rtw_adapter *padapter, #endif } -#ifdef CONFIG_8723AU_P2P -static u32 p2p_listen_state_process(struct rtw_adapter *padapter, - unsigned char *da) -{ - bool response = true; - - if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled == false || - padapter->mlmepriv.wps_probe_resp_ie == NULL || - padapter->mlmepriv.p2p_probe_resp_ie == NULL) { - DBG_8723A("DON'T issue_probersp23a_p2p23a: p2p_enabled:%d, " - "wps_probe_resp_ie:%p, p2p_probe_resp_ie:%p\n", - wdev_to_priv(padapter->rtw_wdev)->p2p_enabled, - padapter->mlmepriv.wps_probe_resp_ie, - padapter->mlmepriv.p2p_probe_resp_ie); - response = false; - } - - if (response == true) - issue_probersp23a_p2p23a(padapter, da); - - return _SUCCESS; -} -#endif /* CONFIG_8723AU_P2P */ - /**************************************************************************** Following are the callback functions for each subtype of the management frames *****************************************************************************/ -unsigned int OnProbeReq23a(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) +static int +OnProbeReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { - unsigned int ielen; - unsigned char *p; + const u8 *ie; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *cur = &pmlmeinfo->network; struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u8 *pframe = skb->data; - uint len = skb->len; - u8 is_valid_p2p_probereq = false; - -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 wifi_test_chk_rate = 1; - - if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && - !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE) && - !rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) && - !rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) && - !rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN)) { - /* mcs_rate = 0 -> CCK 1M rate */ - /* mcs_rate = 1 -> CCK 2M rate */ - /* mcs_rate = 2 -> CCK 5.5M rate */ - /* mcs_rate = 3 -> CCK 11M rate */ - /* In the P2P mode, the driver should not support - the CCK rate */ - - /* IOT issue: Google Nexus7 use 1M rate to send - p2p_probe_req after GO nego completed and Nexus7 - is client */ - if (wifi_test_chk_rate == 1) { - if ((is_valid_p2p_probereq = - process_probe_req_p2p_ie23a(pwdinfo, pframe, - len)) == true) { - if (rtw_p2p_chk_role(pwdinfo, - P2P_ROLE_DEVICE)) { - u8 *sa = ieee80211_get_SA(hdr); - p2p_listen_state_process(padapter, sa); - return _SUCCESS; - } - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { - goto _continue; - } - } - } - } + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data; + int len = skb->len; -_continue: -#endif /* CONFIG_8723AU_P2P */ - - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) return _SUCCESS; - } - if (check_fwstate(pmlmepriv, _FW_LINKED) == false && - check_fwstate(pmlmepriv, - WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE) == false) { + if (!check_fwstate(pmlmepriv, _FW_LINKED) && + !check_fwstate(pmlmepriv, + WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE)) return _SUCCESS; - } - p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + - _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen, - len - sizeof(struct ieee80211_hdr_3addr) - - _PROBEREQ_IE_OFFSET_); + if (unlikely(!ieee80211_is_probe_req(mgmt->frame_control))) { + printk(KERN_WARNING "%s: Received non probe request frame\n", + __func__); + return _FAIL; + } - /* check (wildcard) SSID */ - if (p) { - if (is_valid_p2p_probereq == true) { - goto _issue_probersp23a; - } + len -= offsetof(struct ieee80211_mgmt, u.probe_req.variable); - if ((ielen != 0 && - memcmp((void *)(p+2), cur->Ssid.ssid, - cur->Ssid.ssid_len)) || - (ielen == 0 && pmlmeinfo->hidden_ssid_mode)) { - return _SUCCESS; - } + ie = cfg80211_find_ie(WLAN_EID_SSID, mgmt->u.probe_req.variable, len); -_issue_probersp23a: + /* check (wildcard) SSID */ + if (!ie) + goto out; - if (check_fwstate(pmlmepriv, _FW_LINKED) == true && - pmlmepriv->cur_network.join_res == true) { - /* DBG_8723A("+issue_probersp23a during ap mode\n"); */ - issue_probersp23a(padapter, ieee80211_get_SA(hdr), - is_valid_p2p_probereq); - } + if ((ie[1] && memcmp(ie + 2, cur->Ssid.ssid, cur->Ssid.ssid_len)) || + (ie[1] == 0 && pmlmeinfo->hidden_ssid_mode)) { + return _SUCCESS; } + if (check_fwstate(pmlmepriv, _FW_LINKED) && + pmlmepriv->cur_network.join_res) + issue_probersp23a(padapter, mgmt->sa, false); + +out: return _SUCCESS; } -unsigned int OnProbeRsp23a(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) +static int +OnProbeRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -#ifdef CONFIG_8723AU_P2P - struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif - -#ifdef CONFIG_8723AU_P2P - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) { - if (pwdinfo->tx_prov_disc_info.benable == true) { - if (ether_addr_equal(pwdinfo->tx_prov_disc_info.peerIFAddr, - hdr->addr2)) { - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { - pwdinfo->tx_prov_disc_info.benable = false; - issue_p2p_provision_request23a(padapter, - pwdinfo->tx_prov_disc_info.ssid.ssid, - pwdinfo->tx_prov_disc_info.ssid.ssid_len, - pwdinfo->tx_prov_disc_info.peerDevAddr); - } - else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - { - pwdinfo->tx_prov_disc_info.benable = false; - issue_p2p_provision_request23a(padapter, - NULL, - 0, - pwdinfo->tx_prov_disc_info.peerDevAddr); - } - } - } - return _SUCCESS; - } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) { - if (pwdinfo->nego_req_info.benable == true) { - DBG_8723A("[%s] P2P State is GONEGO ING!\n", __func__); - if (ether_addr_equal(pwdinfo->nego_req_info.peerDevAddr, - hdr->addr2)) { - pwdinfo->nego_req_info.benable = false; - issue_p2p_GO_request23a(padapter, pwdinfo->nego_req_info.peerDevAddr); - } - } - } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) { - if (pwdinfo->invitereq_info.benable == true) { - DBG_8723A("[%s] P2P_STATE_TX_INVITE_REQ!\n", __func__); - if (ether_addr_equal( - pwdinfo->invitereq_info.peer_macaddr, - hdr->addr2)) { - pwdinfo->invitereq_info.benable = false; - issue_p2p_invitation_request23a(padapter, pwdinfo->invitereq_info.peer_macaddr); - } - } - } -#endif if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { report_survey_event23a(padapter, precv_frame); @@ -821,30 +719,30 @@ unsigned int OnProbeRsp23a(struct rtw_adapter *padapter, return _SUCCESS; } -unsigned int OnBeacon23a(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) +static int +OnBeacon23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { int cam_idx; struct sta_info *psta; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct sta_priv *pstapriv = &padapter->stapriv; struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data; u8 *pframe = skb->data; - uint len = skb->len; + int pkt_len = skb->len; struct wlan_bssid_ex *pbss; int ret = _SUCCESS; - u8 *p = NULL; + u8 *p, *pie; + int pie_len; u32 ielen = 0; - p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + - _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ielen, - len - sizeof(struct ieee80211_hdr_3addr) - - _BEACON_IE_OFFSET_); - if ((p != NULL) && (ielen > 0)) { - if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) { + pie = mgmt->u.beacon.variable; + pie_len = pkt_len - offsetof(struct ieee80211_mgmt, u.beacon.variable); + p = rtw_get_ie23a(pie, WLAN_EID_EXT_SUPP_RATES, &ielen, pie_len); + if (p && ielen > 0) { + if (p[1 + ielen] == 0x2D && p[2 + ielen] != 0x2D) { /* Invalid value 0x2D is detected in Extended Supported * Rates (ESR) IE. Try to fix the IE length to avoid * failed Beacon parsing. @@ -852,8 +750,8 @@ unsigned int OnBeacon23a(struct rtw_adapter *padapter, DBG_8723A("[WIFIDBG] Error in ESR IE is detected in " "Beacon of BSSID: %pM. Fix the length of " "ESR IE to avoid failed Beacon parsing.\n", - hdr->addr3); - *(p + 1) = ielen - 1; + mgmt->bssid); + p[1] = ielen - 1; } } @@ -862,129 +760,130 @@ unsigned int OnBeacon23a(struct rtw_adapter *padapter, return _SUCCESS; } - if (ether_addr_equal(hdr->addr3, get_my_bssid23a(&pmlmeinfo->network))){ - if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { - /* we should update current network before auth, - or some IE is wrong */ - pbss = (struct wlan_bssid_ex *) - kmalloc(sizeof(struct wlan_bssid_ex), - GFP_ATOMIC); - if (pbss) { - if (collect_bss_info23a(padapter, precv_frame, - pbss) == _SUCCESS) { - update_network23a(&pmlmepriv->cur_network.network, pbss, padapter, true); - rtw_get_bcn_info23a(&pmlmepriv->cur_network); - } - kfree(pbss); - } + if (!ether_addr_equal(mgmt->bssid, + get_my_bssid23a(&pmlmeinfo->network))) + goto out; - /* check the vendor of the assoc AP */ - pmlmeinfo->assoc_AP_vendor = check_assoc_AP23a(pframe + sizeof(struct ieee80211_hdr_3addr), len-sizeof(struct ieee80211_hdr_3addr)); + if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { + /* we should update current network before auth, + or some IE is wrong */ + pbss = (struct wlan_bssid_ex *) + kmalloc(sizeof(struct wlan_bssid_ex), GFP_ATOMIC); + if (pbss) { + if (collect_bss_info23a(padapter, precv_frame, pbss) == + _SUCCESS) { + update_network23a( + &pmlmepriv->cur_network.network, pbss, + padapter, true); + rtw_get_bcn_info23a(&pmlmepriv->cur_network); + } + kfree(pbss); + } - /* update TSF Value */ - update_TSF23a(pmlmeext, pframe, len); + /* check the vendor of the assoc AP */ + pmlmeinfo->assoc_AP_vendor = + check_assoc_AP23a((u8 *)&mgmt->u.beacon, pkt_len - + offsetof(struct ieee80211_mgmt, u)); - /* start auth */ - start_clnt_auth23a(padapter); + /* update TSF Value */ + rtw_update_TSF(pmlmeext, mgmt); - return _SUCCESS; - } + /* start auth */ + start_clnt_auth23a(padapter); - if (((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) && - (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { - psta = rtw_get_stainfo23a(pstapriv, hdr->addr2); - if (psta) { - ret = rtw_check_bcn_info23a(padapter, pframe, - len); - if (!ret) { - DBG_8723A_LEVEL(_drv_always_, - "ap has changed, " - "disconnect now\n"); - receive_disconnect23a(padapter, pmlmeinfo->network.MacAddress, 65535); - return _SUCCESS; - } - /* update WMM, ERP in the beacon */ - /* todo: the timer is used instead of - the number of the beacon received */ - if ((sta_rx_pkts(psta) & 0xf) == 0) { - /* DBG_8723A("update_bcn_info\n"); */ - update_beacon23a_info(padapter, pframe, - len, psta); - } + return _SUCCESS; + } -#ifdef CONFIG_8723AU_P2P - process_p2p_ps_ie23a(padapter, (pframe + sizeof(struct ieee80211_hdr_3addr)), (len - sizeof(struct ieee80211_hdr_3addr))); -#endif /* CONFIG_8723AU_P2P */ + if (((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) && + (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { + psta = rtw_get_stainfo23a(pstapriv, mgmt->sa); + if (psta) { + ret = rtw_check_bcn_info23a(padapter, mgmt, pkt_len); + if (!ret) { + DBG_8723A_LEVEL(_drv_always_, "ap has changed, " + "disconnect now\n"); + receive_disconnect23a(padapter, pmlmeinfo->network.MacAddress, 65535); + return _SUCCESS; + } + /* update WMM, ERP in the beacon */ + /* todo: the timer is used instead of + the number of the beacon received */ + if ((sta_rx_pkts(psta) & 0xf) == 0) { + /* DBG_8723A("update_bcn_info\n"); */ + update_beacon23a_info(padapter, pframe, + pkt_len, psta); + } + } + } else if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { + psta = rtw_get_stainfo23a(pstapriv, mgmt->sa); + if (psta) { + /* update WMM, ERP in the beacon */ + /* todo: the timer is used instead of the + number of the beacon received */ + if ((sta_rx_pkts(psta) & 0xf) == 0) { + /* DBG_8723A("update_bcn_info\n"); */ + update_beacon23a_info(padapter, pframe, + pkt_len, psta); + } + } else { + /* allocate a new CAM entry for IBSS station */ + cam_idx = allocate_fw_sta_entry23a(padapter); + if (cam_idx == NUM_STA) + goto out; + + /* get supported rate */ + if (update_sta_support_rate23a(padapter, pie, pie_len, + cam_idx) == _FAIL) { + pmlmeinfo->FW_sta_info[cam_idx].status = 0; + goto out; } - } else if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { - psta = rtw_get_stainfo23a(pstapriv, hdr->addr2); - if (psta) { - /* update WMM, ERP in the beacon */ - /* todo: the timer is used instead of the - number of the beacon received */ - if ((sta_rx_pkts(psta) & 0xf) == 0) { - /* DBG_8723A("update_bcn_info\n"); */ - update_beacon23a_info(padapter, pframe, - len, psta); - } - } else { - /* allocate a new CAM entry for IBSS station */ - cam_idx = allocate_fw_sta_entry23a(padapter); - if (cam_idx == NUM_STA) - goto _END_ONBEACON_; - - /* get supported rate */ - if (update_sta_support_rate23a(padapter, (pframe + sizeof(struct ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_), (len - sizeof(struct ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_), cam_idx) == _FAIL) { - pmlmeinfo->FW_sta_info[cam_idx].status = 0; - goto _END_ONBEACON_; - } - /* update TSF Value */ - update_TSF23a(pmlmeext, pframe, len); + /* update TSF Value */ + rtw_update_TSF(pmlmeext, mgmt); - /* report sta add event */ - report_add_sta_event23a(padapter, hdr->addr2, - cam_idx); - } + /* report sta add event */ + report_add_sta_event23a(padapter, mgmt->sa, + cam_idx); } } -_END_ONBEACON_: +out: return _SUCCESS; } -unsigned int OnAuth23a(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) +static int +OnAuth23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { #ifdef CONFIG_8723AU_AP_MODE - unsigned int auth_mode, seq, ie_len; - unsigned char *sa, *p; - u16 algorithm; - int status; static struct sta_info stat; - struct sta_info *pstat = NULL; - struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *pstat = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; struct security_priv *psecuritypriv = &padapter->securitypriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u8 *pframe = skb->data; - uint len = skb->len; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data; + u8 *pframe; + const u8 *p; + unsigned char *sa; + u16 auth_mode, seq, algorithm; + int status, len = skb->len; - if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) + if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) return _FAIL; DBG_8723A("+OnAuth23a\n"); - sa = hdr->addr2; + sa = mgmt->sa; auth_mode = psecuritypriv->dot11AuthAlgrthm; - seq = cpu_to_le16(*(u16*)((unsigned long)pframe + - sizeof(struct ieee80211_hdr_3addr) + 2)); - algorithm = cpu_to_le16(*(u16*)((unsigned long)pframe + - sizeof(struct ieee80211_hdr_3addr))); + + pframe = mgmt->u.auth.variable; + len = skb->len - offsetof(struct ieee80211_mgmt, u.auth.variable); + + seq = le16_to_cpu(mgmt->u.auth.auth_transaction); + algorithm = le16_to_cpu(mgmt->u.auth.auth_alg); DBG_8723A("auth alg =%x, seq =%X\n", algorithm, seq); @@ -995,8 +894,8 @@ unsigned int OnAuth23a(struct rtw_adapter *padapter, /* rx a shared-key auth but shared not enabled, or */ /* rx a open-system auth but shared-key is enabled */ - if ((algorithm > 0 && auth_mode == 0) || - (algorithm == 0 && auth_mode == 1)) { + if ((algorithm != WLAN_AUTH_OPEN && auth_mode == 0) || + (algorithm == WLAN_AUTH_OPEN && auth_mode == 1)) { DBG_8723A("auth rejected due to bad alg [alg =%d, auth_mib " "=%d] %02X%02X%02X%02X%02X%02X\n", algorithm, auth_mode, @@ -1035,8 +934,7 @@ unsigned int OnAuth23a(struct rtw_adapter *padapter, if (!list_empty(&pstat->asoc_list)) { list_del_init(&pstat->asoc_list); pstapriv->asoc_list_cnt--; - if (pstat->expire_to > 0) - { + if (pstat->expire_to > 0) { /* TODO: STA re_auth within expire_to */ } } @@ -1064,7 +962,7 @@ unsigned int OnAuth23a(struct rtw_adapter *padapter, goto auth_fail; } - if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2)) { + if (algorithm == WLAN_AUTH_OPEN && (auth_mode == 0 || auth_mode == 2)) { if (seq == 1) { pstat->state &= ~WIFI_FW_AUTH_NULL; pstat->state |= WIFI_FW_AUTH_SUCCESS; @@ -1088,22 +986,16 @@ unsigned int OnAuth23a(struct rtw_adapter *padapter, /* checking for challenging txt... */ DBG_8723A("checking for challenging txt...\n"); - p = rtw_get_ie23a(pframe + - sizeof(struct ieee80211_hdr_3addr) + - 4 + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, - (int *)&ie_len, len - - sizeof(struct ieee80211_hdr_3addr) - - _AUTH_IE_OFFSET_ - 4); - - if ((p == NULL) || (ie_len<= 0)) { + p = cfg80211_find_ie(WLAN_EID_CHALLENGE, pframe, len); + if (!p || p[1] <= 0) { DBG_8723A("auth rejected because challenge " "failure!(1)\n"); status = WLAN_STATUS_CHALLENGE_FAIL; goto auth_fail; } - if (!memcmp((void *)(p + 2), pstat->chg_txt, 128)) { - pstat->state &= (~WIFI_FW_AUTH_STATE); + if (!memcmp(p + 2, pstat->chg_txt, 128)) { + pstat->state &= ~WIFI_FW_AUTH_STATE; pstat->state |= WIFI_FW_AUTH_SUCCESS; /* challenging txt is correct... */ pstat->expire_to = pstapriv->assoc_to; @@ -1125,7 +1017,7 @@ unsigned int OnAuth23a(struct rtw_adapter *padapter, /* Now, we are going to issue_auth23a... */ pstat->auth_seq = seq + 1; - issue_auth23a(padapter, pstat, (unsigned short)WLAN_STATUS_SUCCESS); + issue_auth23a(padapter, pstat, WLAN_STATUS_SUCCESS); if (pstat->state & WIFI_FW_AUTH_SUCCESS) pstat->auth_seq = 0; @@ -1148,40 +1040,39 @@ unsigned int OnAuth23a(struct rtw_adapter *padapter, return _FAIL; } -unsigned int OnAuth23aClient23a(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) +static int +OnAuth23aClient23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { - unsigned int seq, len, status, algthm, offset; - unsigned char *p; - unsigned int go2asoc = 0; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + unsigned int seq, status, algthm; + unsigned int go2asoc = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u8 *pframe = skb->data; - uint pkt_len = skb->len; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data; + const u8 *p; + u8 *pie; + int plen = skb->len; DBG_8723A("%s\n", __func__); /* check A1 matches or not */ - if (!ether_addr_equal(myid(&padapter->eeprompriv), - ieee80211_get_DA(hdr))) + if (!ether_addr_equal(myid(&padapter->eeprompriv), mgmt->da)) return _SUCCESS; if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE)) return _SUCCESS; - offset = ieee80211_has_protected(hdr->frame_control) ? 4: 0; + pie = mgmt->u.auth.variable; + plen -= offsetof(struct ieee80211_mgmt, u.auth.variable); - algthm = le16_to_cpu(*(unsigned short *)((unsigned long)pframe + sizeof(struct ieee80211_hdr_3addr) + offset)); - seq = le16_to_cpu(*(unsigned short *)((unsigned long)pframe + sizeof(struct ieee80211_hdr_3addr) + offset + 2)); - status = le16_to_cpu(*(unsigned short *)((unsigned long)pframe + sizeof(struct ieee80211_hdr_3addr) + offset + 4)); + algthm = le16_to_cpu(mgmt->u.auth.auth_alg); + seq = le16_to_cpu(mgmt->u.auth.auth_transaction); + status = le16_to_cpu(mgmt->u.auth.status_code); - if (status != 0) - { + if (status) { DBG_8723A("clnt auth fail, status: %d\n", status); - if (status == 13)/* pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */ - { + /* pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */ + if (status == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; else @@ -1193,53 +1084,39 @@ unsigned int OnAuth23aClient23a(struct rtw_adapter *padapter, goto authclnt_fail; } - if (seq == 2) - { - if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) - { - /* legendary shared system */ - p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len, - pkt_len - sizeof(struct ieee80211_hdr_3addr) - _AUTH_IE_OFFSET_); + if (seq == 2) { + if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) { + /* legendary shared system */ + p = cfg80211_find_ie(WLAN_EID_CHALLENGE, pie, plen); - if (p == NULL) - { + if (!p) { /* DBG_8723A("marc: no challenge text?\n"); */ goto authclnt_fail; } - memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len); + memcpy((void *)(pmlmeinfo->chg_txt), p + 2, p[1]); pmlmeinfo->auth_seq = 3; issue_auth23a(padapter, NULL, 0); set_link_timer(pmlmeext, REAUTH_TO); return _SUCCESS; - } - else - { + } else { /* open system */ go2asoc = 1; } - } - else if (seq == 4) - { + } else if (seq == 4) { if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) - { go2asoc = 1; - } else - { goto authclnt_fail; - } - } - else - { + } else { /* this is also illegal */ - /* DBG_8723A("marc: clnt auth failed due to illegal seq =%x\n", seq); */ + /* DBG_8723A("marc: clnt auth failed due to illegal seq =%x\n", + seq); */ goto authclnt_fail; } - if (go2asoc) - { + if (go2asoc) { DBG_8723A_LEVEL(_drv_always_, "auth success, start assoc\n"); start_clnt_assoc23a(padapter); return _SUCCESS; @@ -1252,19 +1129,153 @@ unsigned int OnAuth23aClient23a(struct rtw_adapter *padapter, return _FAIL; } -unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +#ifdef CONFIG_8723AU_AP_MODE +static int rtw_validate_vendor_specific_ies(const u8 *pos, int elen) +{ + unsigned int oui; + + /* first 3 bytes in vendor specific information element are the IEEE + * OUI of the vendor. The following byte is used a vendor specific + * sub-type. */ + if (elen < 4) { + DBG_8723A("short vendor specific information element " + "ignored (len =%i)\n", elen); + return -EINVAL; + } + + oui = RTW_GET_BE24(pos); + switch (oui) { + case WLAN_OUI_MICROSOFT: + /* Microsoft/Wi-Fi information elements are further typed and + * subtyped */ + switch (pos[3]) { + case 1: + /* Microsoft OUI (00:50:F2) with OUI Type 1: + * real WPA information element */ + break; + case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */ + if (elen < 5) { + DBG_8723A("short WME information element " + "ignored (len =%i)\n", elen); + return -EINVAL; + } + switch (pos[4]) { + case WME_OUI_SUBTYPE_INFORMATION_ELEMENT: + case WME_OUI_SUBTYPE_PARAMETER_ELEMENT: + break; + case WME_OUI_SUBTYPE_TSPEC_ELEMENT: + break; + default: + DBG_8723A("unknown WME information element " + "ignored (subtype =%d len =%i)\n", + pos[4], elen); + return -EINVAL; + } + break; + case 4: + /* Wi-Fi Protected Setup (WPS) IE */ + break; + default: + DBG_8723A("Unknown Microsoft information element " + "ignored (type =%d len =%i)\n", + pos[3], elen); + return -EINVAL; + } + break; + + case OUI_BROADCOM: + switch (pos[3]) { + case VENDOR_HT_CAPAB_OUI_TYPE: + break; + default: + DBG_8723A("Unknown Broadcom information element " + "ignored (type =%d len =%i)\n", pos[3], elen); + return -EINVAL; + } + break; + + default: + DBG_8723A("unknown vendor specific information element " + "ignored (vendor OUI %02x:%02x:%02x len =%i)\n", + pos[0], pos[1], pos[2], elen); + return -EINVAL; + } + + return 0; +} + +static int rtw_validate_frame_ies(const u8 *start, uint len) +{ + const u8 *pos = start; + int left = len; + int unknown = 0; + + while (left >= 2) { + u8 id, elen; + + id = *pos++; + elen = *pos++; + left -= 2; + + if (elen > left) { + DBG_8723A("%s: IEEE 802.11 failed (id =%d elen =%d " + "left =%i)\n", __func__, id, elen, left); + return -EINVAL; + } + + switch (id) { + case WLAN_EID_SSID: + case WLAN_EID_SUPP_RATES: + case WLAN_EID_FH_PARAMS: + case WLAN_EID_DS_PARAMS: + case WLAN_EID_CF_PARAMS: + case WLAN_EID_TIM: + case WLAN_EID_IBSS_PARAMS: + case WLAN_EID_CHALLENGE: + case WLAN_EID_ERP_INFO: + case WLAN_EID_EXT_SUPP_RATES: + case WLAN_EID_VENDOR_SPECIFIC: + if (rtw_validate_vendor_specific_ies(pos, elen)) + unknown++; + break; + case WLAN_EID_RSN: + case WLAN_EID_PWR_CAPABILITY: + case WLAN_EID_SUPPORTED_CHANNELS: + case WLAN_EID_MOBILITY_DOMAIN: + case WLAN_EID_FAST_BSS_TRANSITION: + case WLAN_EID_TIMEOUT_INTERVAL: + case WLAN_EID_HT_CAPABILITY: + case WLAN_EID_HT_OPERATION: + default: + unknown++; + DBG_8723A("%s IEEE 802.11 ignored unknown element " + "(id =%d elen =%d)\n", __func__, id, elen); + break; + } + + left -= elen; + pos += elen; + } + + if (left) + return -EINVAL; + + return 0; +} +#endif + +static int +OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { #ifdef CONFIG_8723AU_AP_MODE u16 capab_info, listen_interval; - struct rtw_ieee802_11_elems elems; struct sta_info *pstat; - unsigned char reassoc, *p, *pos, *wpa_ie; + unsigned char reassoc; unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; - int i, ie_len, wpa_ie_len, left; - unsigned char supportRate[16]; - int supportRateNum; - unsigned short status = WLAN_STATUS_SUCCESS; - unsigned short ie_offset; + int i, wpa_ie_len, left; + unsigned char supportRate[16]; + int supportRateNum; + unsigned short status = WLAN_STATUS_SUCCESS; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct security_priv *psecuritypriv = &padapter->securitypriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; @@ -1272,69 +1283,56 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec struct wlan_bssid_ex *cur = &pmlmeinfo->network; struct sta_priv *pstapriv = &padapter->stapriv; struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data; + const u8 *pos, *p, *wpa_ie, *wps_ie; u8 *pframe = skb->data; uint pkt_len = skb->len; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 frame_control; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 p2p_status_code = P2P_STATUS_SUCCESS; - u8 *p2pie; - u32 p2pielen = 0; - u8 wfd_ie[MAX_WFD_IE_LEN] = { 0x00 }; - u32 wfd_ielen = 0; -#endif /* CONFIG_8723AU_P2P */ + int r; - if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) + if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) return _FAIL; - frame_control = hdr->frame_control; - if (ieee80211_is_assoc_req(frame_control)) { + left = pkt_len - sizeof(struct ieee80211_hdr_3addr); + if (ieee80211_is_assoc_req(mgmt->frame_control)) { reassoc = 0; - ie_offset = _ASOCREQ_IE_OFFSET_; + pos = mgmt->u.assoc_req.variable; + left -= offsetof(struct ieee80211_mgmt, u.assoc_req.variable); } else { /* WIFI_REASSOCREQ */ reassoc = 1; - ie_offset = _REASOCREQ_IE_OFFSET_; + pos = mgmt->u.reassoc_req.variable; + left -= offsetof(struct ieee80211_mgmt, u.reassoc_req.variable); } - if (pkt_len < sizeof(struct ieee80211_hdr_3addr) + ie_offset) { - DBG_8723A("handle_assoc(reassoc =%d) - too short payload (len =%lu)" - "\n", reassoc, (unsigned long)pkt_len); + if (left < 0) { + DBG_8723A("handle_assoc(reassoc =%d) - too short payload " + "(len =%lu)\n", reassoc, (unsigned long)pkt_len); return _FAIL; } - pstat = rtw_get_stainfo23a(pstapriv, hdr->addr2); + pstat = rtw_get_stainfo23a(pstapriv, mgmt->sa); if (!pstat) { status = WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA; goto asoc_class2_error; } - capab_info = get_unaligned_le16(pframe + sizeof(struct ieee80211_hdr_3addr)); - /* capab_info = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr))); */ - /* listen_interval = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr)+2)); */ - listen_interval = get_unaligned_le16(pframe + sizeof(struct ieee80211_hdr_3addr)+2); - - left = pkt_len - (sizeof(struct ieee80211_hdr_3addr) + ie_offset); - pos = pframe + (sizeof(struct ieee80211_hdr_3addr) + ie_offset); + /* These two are located at the same offsets whether it's an + * assoc_req or a reassoc_req */ + capab_info = get_unaligned_le16(&mgmt->u.assoc_req.capab_info); + listen_interval = + get_unaligned_le16(&mgmt->u.assoc_req.listen_interval); DBG_8723A("%s\n", __func__); /* check if this stat has been successfully authenticated/assocated */ - if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) - { - if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) - { + if (!(pstat->state & WIFI_FW_AUTH_SUCCESS)) { + if (!(pstat->state & WIFI_FW_ASSOC_SUCCESS)) { status = WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA; goto asoc_class2_error; - } - else - { + } else { pstat->state &= (~WIFI_FW_ASSOC_SUCCESS); pstat->state |= WIFI_FW_ASSOC_STATE; } - } - else - { + } else { pstat->state &= (~WIFI_FW_AUTH_SUCCESS); pstat->state |= WIFI_FW_ASSOC_STATE; } @@ -1342,41 +1340,40 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec pstat->capability = capab_info; /* now parse all ieee802_11 ie to point to elems */ - if (rtw_ieee802_11_parse_elems23a(pos, left, &elems, 1) == ParseFailed || - !elems.ssid) { + + if (rtw_validate_frame_ies(pos, left)) { DBG_8723A("STA " MAC_FMT " sent invalid association request\n", - MAC_ARG(pstat->hwaddr)); + MAC_ARG(pstat->hwaddr)); status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto OnAssocReq23aFail; } /* now we should check all the fields... */ /* checking SSID */ - p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, _SSID_IE_, &ie_len, - pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset); - if (p == NULL) - { - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - if (ie_len == 0) /* broadcast ssid, however it is not allowed in assocreq */ + p = cfg80211_find_ie(WLAN_EID_SSID, pos, left); + if (!p || p[1] == 0) { + /* broadcast ssid, however it is not allowed in assocreq */ + DBG_8723A("STA " MAC_FMT " sent invalid association request " + "lacking an SSID\n", MAC_ARG(pstat->hwaddr)); status = WLAN_STATUS_UNSPECIFIED_FAILURE; - else { + goto OnAssocReq23aFail; + } else { /* check if ssid match */ - if (memcmp((void *)(p+2), cur->Ssid.ssid, cur->Ssid.ssid_len)) + if (memcmp(p + 2, cur->Ssid.ssid, cur->Ssid.ssid_len)) status = WLAN_STATUS_UNSPECIFIED_FAILURE; - if (ie_len != cur->Ssid.ssid_len) + if (p[1] != cur->Ssid.ssid_len) status = WLAN_STATUS_UNSPECIFIED_FAILURE; } - if (WLAN_STATUS_SUCCESS != status) + if (status != WLAN_STATUS_SUCCESS) goto OnAssocReq23aFail; /* check if the supported rate is ok */ - p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, _SUPPORTEDRATES_IE_, &ie_len, pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset); - if (p == NULL) { - DBG_8723A("Rx a sta assoc-req which supported rate is empty!\n"); + p = cfg80211_find_ie(WLAN_EID_SUPP_RATES, pos, left); + if (!p) { + DBG_8723A("Rx a sta assoc-req which supported rate is " + "empty!\n"); /* use our own rate set as statoin used */ /* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */ /* supportRateNum = AP_BSSRATE_LEN; */ @@ -1384,17 +1381,14 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto OnAssocReq23aFail; } else { - memcpy(supportRate, p+2, ie_len); - supportRateNum = ie_len; - - p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, _EXT_SUPPORTEDRATES_IE_, &ie_len, - pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset); - if (p != NULL) { - - if (supportRateNum<= sizeof(supportRate)) - { - memcpy(supportRate+supportRateNum, p+2, ie_len); - supportRateNum += ie_len; + memcpy(supportRate, p + 2, p[1]); + supportRateNum = p[1]; + + p = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, pos, left); + if (p) { + if (supportRateNum <= sizeof(supportRate)) { + memcpy(supportRate+supportRateNum, p + 2, p[1]); + supportRateNum += p[1]; } } } @@ -1415,90 +1409,97 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec pstat->wpa_pairwise_cipher = 0; pstat->wpa2_pairwise_cipher = 0; memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie)); - if ((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) { + wpa_ie = cfg80211_find_ie(WLAN_EID_RSN, pos, left); + if (!wpa_ie) + wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPA, + pos, left); + if (wpa_ie) { int group_cipher = 0, pairwise_cipher = 0; - wpa_ie = elems.rsn_ie; - wpa_ie_len = elems.rsn_ie_len; - - if (rtw_parse_wpa2_ie23a(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { - pstat->dot8021xalg = 1;/* psk, todo:802.1x */ - pstat->wpa_psk |= BIT(1); - - pstat->wpa2_group_cipher = group_cipher&psecuritypriv->wpa2_group_cipher; - pstat->wpa2_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa2_pairwise_cipher; - - if (!pstat->wpa2_group_cipher) - status = WLAN_REASON_INVALID_GROUP_CIPHER; - - if (!pstat->wpa2_pairwise_cipher) - status = WLAN_REASON_INVALID_PAIRWISE_CIPHER; + wpa_ie_len = wpa_ie[1]; + if (psecuritypriv->wpa_psk & BIT(1)) { + r = rtw_parse_wpa2_ie23a(wpa_ie, wpa_ie_len + 2, + &group_cipher, + &pairwise_cipher, NULL); + if (r == _SUCCESS) { + pstat->dot8021xalg = 1;/* psk, todo:802.1x */ + pstat->wpa_psk |= BIT(1); + + pstat->wpa2_group_cipher = group_cipher & + psecuritypriv->wpa2_group_cipher; + pstat->wpa2_pairwise_cipher = pairwise_cipher & + psecuritypriv->wpa2_pairwise_cipher; + } else + status = WLAN_STATUS_INVALID_IE; + } else if (psecuritypriv->wpa_psk & BIT(0)) { + r = rtw_parse_wpa_ie23a(wpa_ie, wpa_ie_len + 2, + &group_cipher, &pairwise_cipher, + NULL); + if (r == _SUCCESS) { + pstat->dot8021xalg = 1;/* psk, todo:802.1x */ + pstat->wpa_psk |= BIT(0); + + pstat->wpa_group_cipher = group_cipher & + psecuritypriv->wpa_group_cipher; + pstat->wpa_pairwise_cipher = pairwise_cipher & + psecuritypriv->wpa_pairwise_cipher; + } else + status = WLAN_STATUS_INVALID_IE; } else { - status = WLAN_STATUS_INVALID_IE; + wpa_ie = NULL; + wpa_ie_len = 0; } - - } else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) { - - int group_cipher = 0, pairwise_cipher = 0; - - wpa_ie = elems.wpa_ie; - wpa_ie_len = elems.wpa_ie_len; - - if (rtw_parse_wpa_ie23a(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { - pstat->dot8021xalg = 1;/* psk, todo:802.1x */ - pstat->wpa_psk |= BIT(0); - - pstat->wpa_group_cipher = group_cipher&psecuritypriv->wpa_group_cipher; - pstat->wpa_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa_pairwise_cipher; - + if (wpa_ie && status == WLAN_STATUS_SUCCESS) { if (!pstat->wpa_group_cipher) status = WLAN_STATUS_INVALID_GROUP_CIPHER; if (!pstat->wpa_pairwise_cipher) status = WLAN_STATUS_INVALID_PAIRWISE_CIPHER; - - } else { - status = WLAN_STATUS_INVALID_IE; } - - } else { - wpa_ie = NULL; - wpa_ie_len = 0; } - if (WLAN_STATUS_SUCCESS != status) + if (status != WLAN_STATUS_SUCCESS) goto OnAssocReq23aFail; pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); - if (wpa_ie == NULL) { - if (elems.wps_ie) { - DBG_8723A("STA included WPS IE in " - "(Re)Association Request - assume WPS is " - "used\n"); + + wps_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPS, + pos, left); + + if (!wpa_ie) { + if (wps_ie) { + DBG_8723A("STA included WPS IE in (Re)Association " + "Request - assume WPS is used\n"); pstat->flags |= WLAN_STA_WPS; } else { - DBG_8723A("STA did not include WPA/RSN IE " - "in (Re)Association Request - possible WPS " - "use\n"); + DBG_8723A("STA did not include WPA/RSN IE in (Re)" + "Association Request - possible WPS use\n"); pstat->flags |= WLAN_STA_MAYBE_WPS; } - /* AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */ + /* AP support WPA/RSN, and sta is going to do WPS, but AP + is not ready */ /* that the selected registrar of AP is _FLASE */ - if ((psecuritypriv->wpa_psk > 0) && - (pstat->flags & (WLAN_STA_WPS|WLAN_STA_MAYBE_WPS))) { + if (psecuritypriv->wpa_psk > 0 && + pstat->flags & (WLAN_STA_WPS|WLAN_STA_MAYBE_WPS)) { if (pmlmepriv->wps_beacon_ie) { u8 selected_registrar = 0; - rtw_get_wps_attr_content23a(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, - WPS_ATTR_SELECTED_REGISTRAR, &selected_registrar, NULL); + rtw_get_wps_attr_content23a( + pmlmepriv->wps_beacon_ie, + pmlmepriv->wps_beacon_ie_len, + WPS_ATTR_SELECTED_REGISTRAR, + &selected_registrar, NULL); if (!selected_registrar) { - DBG_8723A("selected_registrar is false , or AP is not ready to do WPS\n"); + DBG_8723A("selected_registrar is false," + "or AP is not ready to do " + "WPS\n"); status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; - goto OnAssocReq23aFail; } } @@ -1508,26 +1509,26 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec if (psecuritypriv->wpa_psk == 0) { DBG_8723A("STA " MAC_FMT ": WPA/RSN IE in association " - "request, but AP don't support WPA/RSN\n", MAC_ARG(pstat->hwaddr)); + "request, but AP don't support WPA/RSN\n", + MAC_ARG(pstat->hwaddr)); status = WLAN_STATUS_INVALID_IE; goto OnAssocReq23aFail; } - if (elems.wps_ie) { - DBG_8723A("STA included WPS IE in " - "(Re)Association Request - WPS is " - "used\n"); + if (wps_ie) { + DBG_8723A("STA included WPS IE in (Re)Association " + "Request - WPS is used\n"); pstat->flags |= WLAN_STA_WPS; copy_len = 0; } else { - copy_len = ((wpa_ie_len+2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)):(wpa_ie_len+2); + copy_len = ((wpa_ie_len + 2) > sizeof(pstat->wpa_ie)) ? + sizeof(pstat->wpa_ie) : (wpa_ie_len + 2); } - if (copy_len>0) - memcpy(pstat->wpa_ie, wpa_ie-2, copy_len); - + if (copy_len > 0) + memcpy(pstat->wpa_ie, wpa_ie - 2, copy_len); } /* check if there is WMM IE & support WWM-PS */ @@ -1539,45 +1540,45 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec pstat->uapsd_vi = 0; pstat->uapsd_be = 0; pstat->uapsd_bk = 0; - if (pmlmepriv->qospriv.qos_option) - { - p = pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset; ie_len = 0; - for (;;) - { - p = rtw_get_ie23a(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset); - if (p != NULL) { - if (!memcmp(p+2, WMM_IE, 6)) { - + if (pmlmepriv->qospriv.qos_option) { + const u8 *end = pos + left; + p = pos; + + for (;;) { + left = end - p; + p = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, p, left); + if (p) { + if (!memcmp(p + 2, WMM_IE, 6)) { pstat->flags |= WLAN_STA_WME; pstat->qos_option = 1; - pstat->qos_info = *(p+8); + pstat->qos_info = *(p + 8); - pstat->max_sp_len = (pstat->qos_info>>5)&0x3; + pstat->max_sp_len = + (pstat->qos_info >> 5) & 0x3; - if ((pstat->qos_info&0xf) != 0xf) + if ((pstat->qos_info & 0xf) != 0xf) pstat->has_legacy_ac = true; else pstat->has_legacy_ac = false; - if (pstat->qos_info&0xf) - { - if (pstat->qos_info&BIT(0)) + if (pstat->qos_info & 0xf) { + if (pstat->qos_info & BIT(0)) pstat->uapsd_vo = BIT(0)|BIT(1); else pstat->uapsd_vo = 0; - if (pstat->qos_info&BIT(1)) + if (pstat->qos_info & BIT(1)) pstat->uapsd_vi = BIT(0)|BIT(1); else pstat->uapsd_vi = 0; - if (pstat->qos_info&BIT(2)) + if (pstat->qos_info & BIT(2)) pstat->uapsd_bk = BIT(0)|BIT(1); else pstat->uapsd_bk = 0; - if (pstat->qos_info&BIT(3)) + if (pstat->qos_info & BIT(3)) pstat->uapsd_be = BIT(0)|BIT(1); else pstat->uapsd_be = 0; @@ -1586,45 +1587,42 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec break; } - } - else { + } else { break; } - p = p + ie_len + 2; + p = p + p[1] + 2; } } /* save HT capabilities in the sta object */ memset(&pstat->htpriv.ht_cap, 0, sizeof(struct ieee80211_ht_cap)); - if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct ieee80211_ht_cap)) - { + p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, pos, left); + + if (p && p[1] >= sizeof(struct ieee80211_ht_cap)) { pstat->flags |= WLAN_STA_HT; pstat->flags |= WLAN_STA_WME; - memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct ieee80211_ht_cap)); - + memcpy(&pstat->htpriv.ht_cap, p + 2, + sizeof(struct ieee80211_ht_cap)); } else pstat->flags &= ~WLAN_STA_HT; - if ((pmlmepriv->htpriv.ht_option == false) && (pstat->flags&WLAN_STA_HT)) - { + if (pmlmepriv->htpriv.ht_option == false && pstat->flags & WLAN_STA_HT){ status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto OnAssocReq23aFail; } - if ((pstat->flags & WLAN_STA_HT) && - ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) || - (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP))) - { - DBG_8723A("HT: " MAC_FMT " tried to " - "use TKIP with HT association\n", MAC_ARG(pstat->hwaddr)); + if (pstat->flags & WLAN_STA_HT && + (pstat->wpa2_pairwise_cipher & WPA_CIPHER_TKIP || + pstat->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) { + DBG_8723A("HT: " MAC_FMT " tried to use TKIP with HT " + "association\n", MAC_ARG(pstat->hwaddr)); /* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */ /* goto OnAssocReq23aFail; */ } - /* */ pstat->flags |= WLAN_STA_NONERP; for (i = 0; i < pstat->bssratelen; i++) { if ((pstat->bssrateset[i] & 0x7f) > 22) { @@ -1641,39 +1639,6 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec if (status != WLAN_STATUS_SUCCESS) goto OnAssocReq23aFail; -#ifdef CONFIG_8723AU_P2P - pstat->is_p2p_device = false; - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - { - if ((p2pie = rtw_get_p2p_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset, NULL, &p2pielen))) - { - pstat->is_p2p_device = true; - if ((p2p_status_code = (u8)process_assoc_req_p2p_ie23a(pwdinfo, pframe, pkt_len, pstat))>0) - { - pstat->p2p_status_code = p2p_status_code; - status = WLAN_STATUS_CAPS_UNSUPPORTED; - goto OnAssocReq23aFail; - } - } -#ifdef CONFIG_8723AU_P2P - if (rtw_get_wfd_ie(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset, wfd_ie, &wfd_ielen)) - { - u8 attr_content[ 10 ] = { 0x00 }; - u32 attr_contentlen = 0; - - DBG_8723A("[%s] WFD IE Found!!\n", __func__); - rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); - if (attr_contentlen) - { - pwdinfo->wfd_info->peer_rtsp_ctrlport = get_unaligned_be16(attr_content + 2); - DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport); - } - } -#endif - } - pstat->p2p_status_code = p2p_status_code; -#endif /* CONFIG_8723AU_P2P */ - /* TODO: identify_proprietary_vendor_ie(); */ /* Realtek proprietary IE */ /* identify if this is Broadcom sta */ @@ -1699,14 +1664,13 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; goto OnAssocReq23aFail; - } else { pstapriv->sta_aid[pstat->aid - 1] = pstat; DBG_8723A("allocate new AID = (%d)\n", pstat->aid); } } - pstat->state &= (~WIFI_FW_ASSOC_STATE); + pstat->state &= ~WIFI_FW_ASSOC_STATE; pstat->state |= WIFI_FW_ASSOC_SUCCESS; spin_lock_bh(&pstapriv->auth_list_lock); @@ -1725,18 +1689,20 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec spin_unlock_bh(&pstapriv->asoc_list_lock); /* now the station is qualified to join our BSS... */ - if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && - (WLAN_STATUS_SUCCESS == status)) { + if (pstat && pstat->state & WIFI_FW_ASSOC_SUCCESS && + status == WLAN_STATUS_SUCCESS) { #ifdef CONFIG_8723AU_AP_MODE /* 1 bss_cap_update & sta_info_update23a */ bss_cap_update_on_sta_join23a(padapter, pstat); sta_info_update23a(padapter, pstat); /* issue assoc rsp before notify station join event. */ - if (ieee80211_is_assoc_req(frame_control)) - issue_asocrsp23a(padapter, status, pstat, WIFI_ASSOCRSP); + if (ieee80211_is_assoc_req(mgmt->frame_control)) + issue_asocrsp23a(padapter, status, pstat, + WIFI_ASSOCRSP); else - issue_asocrsp23a(padapter, status, pstat, WIFI_REASSOCRSP); + issue_asocrsp23a(padapter, status, pstat, + WIFI_REASSOCRSP); /* 2 - report to upper layer */ DBG_8723A("indicate_sta_join_event to upper layer - hostapd\n"); @@ -1752,16 +1718,15 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec asoc_class2_error: #ifdef CONFIG_8723AU_AP_MODE - issue_deauth23a(padapter, hdr->addr2, status); + issue_deauth23a(padapter, mgmt->sa, status); #endif - return _FAIL; OnAssocReq23aFail: #ifdef CONFIG_8723AU_AP_MODE pstat->aid = 0; - if (ieee80211_is_assoc_req(frame_control)) + if (ieee80211_is_assoc_req(mgmt->frame_control)) issue_asocrsp23a(padapter, status, pstat, WIFI_ASSOCRSP); else issue_asocrsp23a(padapter, status, pstat, WIFI_REASSOCRSP); @@ -1772,25 +1737,24 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec return _FAIL; } -unsigned int OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +static int +OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { - uint i; - int res; - unsigned short status; struct ndis_802_11_var_ies *pIE; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_mgmt *pmgmt = (struct ieee80211_mgmt *) skb->data; + int res, i; + unsigned short status; u8 *pframe = skb->data; - uint pkt_len = skb->len; + int pkt_len = skb->len; DBG_8723A("%s\n", __func__); /* check A1 matches or not */ - if (!ether_addr_equal(myid(&padapter->eeprompriv), - ieee80211_get_DA(hdr))) + if (!ether_addr_equal(myid(&padapter->eeprompriv), pmgmt->da)) return _SUCCESS; if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE))) @@ -1802,8 +1766,8 @@ unsigned int OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *prec del_timer_sync(&pmlmeext->link_timer); /* status */ - if ((status = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr) + 2))) > 0) - { + status = le16_to_cpu(pmgmt->u.assoc_resp.status_code); + if (status > 0) { DBG_8723A("assoc reject, status code: %d\n", status); pmlmeinfo->state = WIFI_FW_NULL_STATE; res = -4; @@ -1811,42 +1775,37 @@ unsigned int OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *prec } /* get capabilities */ - pmlmeinfo->capability = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr))); + pmlmeinfo->capability = le16_to_cpu(pmgmt->u.assoc_resp.capab_info); /* set slot time */ pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10))? 9: 20; /* AID */ - res = pmlmeinfo->aid = (int)(le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr) + 4))&0x3fff); + res = pmlmeinfo->aid = le16_to_cpu(pmgmt->u.assoc_resp.aid) & 0x3fff; /* following are moved to join event callback function */ /* to handle HT, WMM, rate adaptive, update MAC reg */ /* for not to handle the synchronous IO in the tasklet */ - for (i = (6 + sizeof(struct ieee80211_hdr_3addr)); i < pkt_len;) { + for (i = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); + i < pkt_len;) { pIE = (struct ndis_802_11_var_ies *)(pframe + i); switch (pIE->ElementID) { - case _VENDOR_SPECIFIC_IE_: + case WLAN_EID_VENDOR_SPECIFIC: if (!memcmp(pIE->data, WMM_PARA_OUI23A, 6))/* WMM */ - WMM_param_handler23a(padapter, pIE); -#if defined(CONFIG_8723AU_P2P) - else if (!memcmp(pIE->data, WFD_OUI23A, 4)) { /* WFD */ - DBG_8723A("[%s] Found WFD IE\n", __func__); - WFD_info_handler(padapter, pIE); - } -#endif + WMM_param_handler23a(padapter, pIE); break; - case _HT_CAPABILITY_IE_: /* HT caps */ + case WLAN_EID_HT_CAPABILITY: /* HT caps */ HT_caps_handler23a(padapter, pIE); break; - case _HT_EXTRA_INFO_IE_: /* HT info */ + case WLAN_EID_HT_OPERATION: /* HT info */ HT_info_handler23a(padapter, pIE); break; - case _ERPINFO_IE_: + case WLAN_EID_ERP_INFO: ERP_IE_handler23a(padapter, pIE); default: @@ -1856,7 +1815,7 @@ unsigned int OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *prec i += (pIE->Length + 2); } - pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE); + pmlmeinfo->state &= ~WIFI_FW_ASSOC_STATE; pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; /* Update Basic Rate Table for spec, 2010-12-28 , by thomas */ @@ -1879,32 +1838,21 @@ unsigned int OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *prec return _SUCCESS; } -unsigned int OnDeAuth23a(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) +static int +OnDeAuth23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { - unsigned short reason; + unsigned short reason; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u8 *pframe = skb->data; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif /* CONFIG_8723AU_P2P */ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data; - /* check A3 */ - if (!ether_addr_equal(hdr->addr3, get_my_bssid23a(&pmlmeinfo->network))) + if (!ether_addr_equal(mgmt->bssid, + get_my_bssid23a(&pmlmeinfo->network))) return _SUCCESS; -#ifdef CONFIG_8723AU_P2P - if (pwdinfo->rx_invitereq_info.scan_op_ch_only) { - mod_timer(&pwdinfo->reset_ch_sitesurvey, - jiffies + msecs_to_jiffies(10)); - } -#endif /* CONFIG_8723AU_P2P */ - - reason = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr))); + reason = le16_to_cpu(mgmt->u.deauth.reason_code); DBG_8723A("%s Reason code(%d)\n", __func__, reason); @@ -1914,9 +1862,9 @@ unsigned int OnDeAuth23a(struct rtw_adapter *padapter, struct sta_priv *pstapriv = &padapter->stapriv; DBG_8723A_LEVEL(_drv_always_, "ap recv deauth reason code(%d) " - "sta:%pM\n", reason, hdr->addr2); + "sta:%pM\n", reason, mgmt->sa); - psta = rtw_get_stainfo23a(pstapriv, hdr->addr2); + psta = rtw_get_stainfo23a(pstapriv, mgmt->sa); if (psta) { u8 updated = 0; @@ -1933,46 +1881,34 @@ unsigned int OnDeAuth23a(struct rtw_adapter *padapter, } return _SUCCESS; - } - else + } else #endif { DBG_8723A_LEVEL(_drv_always_, "sta recv deauth reason code(%d) " - "sta:%pM\n", reason, hdr->addr3); + "sta:%pM\n", reason, mgmt->bssid); - receive_disconnect23a(padapter, hdr->addr3, reason); + receive_disconnect23a(padapter, mgmt->bssid, reason); } pmlmepriv->LinkDetectInfo.bBusyTraffic = false; + return _SUCCESS; } -unsigned int OnDisassoc23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +static int +OnDisassoc23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { unsigned short reason; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u8 *pframe = skb->data; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif /* CONFIG_8723AU_P2P */ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data; - /* check A3 */ - if (!ether_addr_equal(hdr->addr3, get_my_bssid23a(&pmlmeinfo->network))) + if (!ether_addr_equal(mgmt->bssid, + get_my_bssid23a(&pmlmeinfo->network))) return _SUCCESS; -#ifdef CONFIG_8723AU_P2P - if (pwdinfo->rx_invitereq_info.scan_op_ch_only) - { - mod_timer(&pwdinfo->reset_ch_sitesurvey, - jiffies + msecs_to_jiffies(10)); - } -#endif /* CONFIG_8723AU_P2P */ - - reason = le16_to_cpu(*(unsigned short *) - (pframe + sizeof(struct ieee80211_hdr_3addr))); + reason = le16_to_cpu(mgmt->u.disassoc.reason_code); DBG_8723A("%s Reason code(%d)\n", __func__, reason); @@ -1982,9 +1918,9 @@ unsigned int OnDisassoc23a(struct rtw_adapter *padapter, struct recv_frame *prec struct sta_priv *pstapriv = &padapter->stapriv; DBG_8723A_LEVEL(_drv_always_, "ap recv disassoc reason code(%d)" - " sta:%pM\n", reason, hdr->addr2); + " sta:%pM\n", reason, mgmt->sa); - psta = rtw_get_stainfo23a(pstapriv, hdr->addr2); + psta = rtw_get_stainfo23a(pstapriv, mgmt->sa); if (psta) { u8 updated = 0; @@ -1993,7 +1929,7 @@ unsigned int OnDisassoc23a(struct rtw_adapter *padapter, struct recv_frame *prec list_del_init(&psta->asoc_list); pstapriv->asoc_list_cnt--; updated = ap_free_sta23a(padapter, psta, - false, reason); + false, reason); } spin_unlock_bh(&pstapriv->asoc_list_lock); @@ -2001,57 +1937,59 @@ unsigned int OnDisassoc23a(struct rtw_adapter *padapter, struct recv_frame *prec } return _SUCCESS; - } - else + } else #endif { DBG_8723A_LEVEL(_drv_always_, "ap recv disassoc reason " - "code(%d) sta:%pM\n", reason, hdr->addr3); + "code(%d) sta:%pM\n", reason, mgmt->bssid); - receive_disconnect23a(padapter, hdr->addr3, reason); + receive_disconnect23a(padapter, mgmt->bssid, reason); } pmlmepriv->LinkDetectInfo.bBusyTraffic = false; return _SUCCESS; } -unsigned int OnAtim23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +static int +OnAtim23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { DBG_8723A("%s\n", __func__); return _SUCCESS; } -unsigned int on_action_spct23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +static int +on_action_spct23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { return _FAIL; } -unsigned int OnAction23a_qos(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +static int +OnAction23a_qos(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { return _SUCCESS; } -unsigned int OnAction23a_dls(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +static int +OnAction23a_dls(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { return _SUCCESS; } -unsigned int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +static int OnAction23a_back23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) { u8 *addr; struct sta_info *psta = NULL; struct recv_reorder_ctrl *preorder_ctrl; - unsigned char *frame_body; - unsigned char category, action; - unsigned short tid, status, reason_code = 0; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + unsigned char category, action; + unsigned short tid, status, capab, params, reason_code = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u8 *pframe = skb->data; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data; struct sta_priv *pstapriv = &padapter->stapriv; /* check RA matches or not */ - if (!ether_addr_equal(myid(&padapter->eeprompriv), hdr->addr1)) + if (!ether_addr_equal(myid(&padapter->eeprompriv), mgmt->da)) return _SUCCESS; DBG_8723A("%s\n", __func__); @@ -2060,24 +1998,24 @@ unsigned int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) return _SUCCESS; - addr = hdr->addr2; + addr = mgmt->sa; psta = rtw_get_stainfo23a(pstapriv, addr); if (!psta) return _SUCCESS; - frame_body = (unsigned char *) - (pframe + sizeof(struct ieee80211_hdr_3addr)); - - category = frame_body[0]; + category = mgmt->u.action.category; if (category == WLAN_CATEGORY_BACK) { /* representing Block Ack */ if (!pmlmeinfo->HT_enable) return _SUCCESS; - action = frame_body[1]; + /* action_code is located in the same place for all + action events, so pick any */ + action = mgmt->u.action.u.wme_action.action_code; DBG_8723A("%s, action =%d\n", __func__, action); switch (action) { case WLAN_ACTION_ADDBA_REQ: /* ADDBA request */ - memcpy(&pmlmeinfo->ADDBA_req, &frame_body[2], + memcpy(&pmlmeinfo->ADDBA_req, + &mgmt->u.action.u.addba_req.dialog_token, sizeof(struct ADDBA_request)); process_addba_req23a(padapter, (u8 *)&pmlmeinfo->ADDBA_req, addr); @@ -2091,8 +2029,11 @@ unsigned int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame } break; case WLAN_ACTION_ADDBA_RESP: /* ADDBA response */ - status = get_unaligned_le16(&frame_body[3]); - tid = ((frame_body[5] >> 2) & 0x7); + status = get_unaligned_le16( + &mgmt->u.action.u.addba_resp.status); + capab = get_unaligned_le16( + &mgmt->u.action.u.addba_resp.capab); + tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; if (status == 0) { /* successful */ DBG_8723A("agg_enable for TID =%d\n", tid); psta->htpriv.agg_enable_bitmap |= 1 << tid; @@ -2103,22 +2044,21 @@ unsigned int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame break; case WLAN_ACTION_DELBA: /* DELBA */ - if ((frame_body[3] & BIT(3)) == 0) { - psta->htpriv.agg_enable_bitmap &= - ~(1 << ((frame_body[3] >> 4) & 0xf)); - psta->htpriv.candidate_tid_bitmap &= - ~(1 << ((frame_body[3] >> 4) & 0xf)); - - /* reason_code = frame_body[4] | (frame_body[5] << 8); */ - reason_code = get_unaligned_le16(&frame_body[4]); - } else if ((frame_body[3] & BIT(3)) == BIT(3)) { - tid = (frame_body[3] >> 4) & 0x0F; + params = get_unaligned_le16( + &mgmt->u.action.u.delba.params); + tid = params >> 12; - preorder_ctrl = &psta->recvreorder_ctrl[tid]; + if (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) { + preorder_ctrl = &psta->recvreorder_ctrl[tid]; preorder_ctrl->enable = false; preorder_ctrl->indicate_seq = 0xffff; + } else { + psta->htpriv.agg_enable_bitmap &= ~(1 << tid); + psta->htpriv.candidate_tid_bitmap &= + ~(1 << tid); } - + reason_code = get_unaligned_le16( + &mgmt->u.action.u.delba.reason_code); DBG_8723A("%s(): DELBA: %x(%x)\n", __func__, pmlmeinfo->agg_enable_bitmap, reason_code); /* todo: how to notify the host while receiving @@ -2131,2930 +2071,166 @@ unsigned int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame return _SUCCESS; } -#ifdef CONFIG_8723AU_P2P - -static int get_reg_classes_full_count(struct p2p_channels channel_list) { - int cnt = 0; - int i; - - for (i = 0; i < channel_list.reg_classes; i++) - cnt += channel_list.reg_class[i].channels; - - return cnt; -} - -void issue_p2p_GO_request23a(struct rtw_adapter *padapter, u8* raddr) +static s32 rtw_action_public_decache(struct recv_frame *recv_frame, s32 token) { - unsigned char category = WLAN_CATEGORY_PUBLIC; - u8 action = P2P_PUB_ACTION_ACTION; - u32 p2poui = cpu_to_be32(P2POUI); - u8 oui_subtype = P2P_GO_NEGO_REQ; - u8 wpsie[ 255 ] = { 0x00 }, p2pie[ 255 ] = { 0x00 }; - u8 wpsielen = 0, p2pielen = 0; - u16 len_channellist_attr = 0; -#ifdef CONFIG_8723AU_P2P - u32 wfdielen = 0; -#endif /* CONFIG_8723AU_P2P */ - - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - return; - - DBG_8723A("[%s] In\n", __func__); - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - fctrl = &pwlanhdr->frame_control; - *fctrl = 0; - - ether_addr_copy(pwlanhdr->addr1, raddr); - ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); - ether_addr_copy(pwlanhdr->addr3, myid(&padapter->eeprompriv)); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); - - pframe += sizeof(struct ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - - pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, - &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); - pwdinfo->negotiation_dialog_token = 1; /*Initialize the dialog value*/ - pframe = rtw_set_fixed_ie23a(pframe, 1, - &pwdinfo->negotiation_dialog_token, - &pattrib->pktlen); - - /* WPS Section */ - wpsielen = 0; - /* WPS OUI */ - *(u32*) (wpsie) = cpu_to_be32(WPSOUI); - wpsielen += 4; - - /* WPS version */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); - wpsielen += 2; - - /* Value: */ - wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ - - /* Device Password ID */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); - wpsielen += 2; - - /* Value: */ - - if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) - { - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC); - } - else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN) - { - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); - } - else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) - { - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC); - } - - wpsielen += 2; - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen); - - /* P2P IE Section. */ - - /* P2P OUI */ - p2pielen = 0; - p2pie[p2pielen++] = 0x50; - p2pie[p2pielen++] = 0x6F; - p2pie[p2pielen++] = 0x9A; - p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ - - /* Commented by Albert 20110306 */ - /* According to the P2P Specification, the group negoitation request frame should contain 9 P2P attributes */ - /* 1. P2P Capability */ - /* 2. Group Owner Intent */ - /* 3. Configuration Timeout */ - /* 4. Listen Channel */ - /* 5. Extended Listen Timing */ - /* 6. Intended P2P Interface Address */ - /* 7. Channel List */ - /* 8. P2P Device Info */ - /* 9. Operating Channel */ - - /* P2P Capability */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); - p2pielen += 2; - - /* Value: */ - /* Device Capability Bitmap, 1 byte */ - p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; - - /* Group Capability Bitmap, 1 byte */ - if (pwdinfo->persistent_supported) - { - p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; - } - else - { - p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; - } - - /* Group Owner Intent */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_GO_INTENT; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001); - p2pielen += 2; - - /* Value: */ - /* Todo the tie breaker bit. */ - p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0)); - - /* Configuration Timeout */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); - p2pielen += 2; - - /* Value: */ - p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ - p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ - - /* Listen Channel */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); - p2pielen += 2; - - /* Value: */ - /* Country String */ - p2pie[p2pielen++] = 'X'; - p2pie[p2pielen++] = 'X'; - - /* The third byte should be set to 0x04. */ - /* Described in the "Operating Channel Attribute" section. */ - p2pie[p2pielen++] = 0x04; - - /* Operating Class */ - p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ - - /* Channel Number */ - p2pie[p2pielen++] = pwdinfo->listen_channel; /* listening channel number */ - - /* Extended Listen Timing ATTR */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); - p2pielen += 2; - - /* Value: */ - /* Availability Period */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); - p2pielen += 2; - - /* Availability Interval */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); - p2pielen += 2; - - /* Intended P2P Interface Address */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); - p2pielen += 2; - - /* Value: */ - memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); - p2pielen += ETH_ALEN; - - /* Channel List */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CH_LIST; - - /* Length: */ - /* Country String(3) */ - /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */ - /* + number of channels in all classes */ - len_channellist_attr = 3 - + (1 + 1) * (u16)(pmlmeext->channel_list.reg_classes) - + get_reg_classes_full_count(pmlmeext->channel_list); - - *(u16*) (p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); - p2pielen += 2; - - /* Value: */ - /* Country String */ - p2pie[p2pielen++] = 'X'; - p2pie[p2pielen++] = 'X'; - - /* The third byte should be set to 0x04. */ - /* Described in the "Operating Channel Attribute" section. */ - p2pie[p2pielen++] = 0x04; - - /* Channel Entry List */ - - { - int i, j; - for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { - /* Operating Class */ - p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + struct rtw_adapter *adapter = recv_frame->adapter; + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + struct sk_buff *skb = recv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 seq_ctrl; - /* Number of Channels */ - p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + seq_ctrl = ((recv_frame->attrib.seq_num&0xffff) << 4) | + (recv_frame->attrib.frag_num & 0xf); - /* Channel List */ - for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { - p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + if (ieee80211_has_retry(hdr->frame_control)) { + if (token >= 0) { + if ((seq_ctrl == mlmeext->action_public_rxseq) && + (token == mlmeext->action_public_dialog_token)) { + DBG_8723A(FUNC_ADPT_FMT" seq_ctrl = 0x%x, " + "rxseq = 0x%x, token:%d\n", + FUNC_ADPT_ARG(adapter), seq_ctrl, + mlmeext->action_public_rxseq, token); + return _FAIL; + } + } else { + if (seq_ctrl == mlmeext->action_public_rxseq) { + DBG_8723A(FUNC_ADPT_FMT" seq_ctrl = 0x%x, " + "rxseq = 0x%x\n", + FUNC_ADPT_ARG(adapter), seq_ctrl, + mlmeext->action_public_rxseq); + return _FAIL; } } } - /* Device Info */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; - - /* Length: */ - /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ - /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); - p2pielen += 2; - - /* Value: */ - /* P2P Device Address */ - memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); - p2pielen += ETH_ALEN; + mlmeext->action_public_rxseq = seq_ctrl; - /* Config Method */ - /* This field should be big endian. Noted by P2P specification. */ + if (token >= 0) + mlmeext->action_public_dialog_token = token; - *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); + return _SUCCESS; +} - p2pielen += 2; +static unsigned int on_action_public23a_p2p(struct recv_frame *precv_frame) +{ + struct sk_buff *skb = precv_frame->pkt; + u8 *pframe = skb->data; + u8 *frame_body; + u8 dialogToken = 0; - /* Primary Device Type */ - /* Category ID */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); - p2pielen += 2; + frame_body = (unsigned char *) + (pframe + sizeof(struct ieee80211_hdr_3addr)); - /* OUI */ - *(u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); - p2pielen += 4; + dialogToken = frame_body[7]; - /* Sub Category ID */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); - p2pielen += 2; + if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL) + return _FAIL; - /* Number of Secondary Device Types */ - p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ + return _SUCCESS; +} - /* Device Name */ - /* Type: */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); - p2pielen += 2; +static unsigned int on_action_public23a_vendor(struct recv_frame *precv_frame) +{ + unsigned int ret = _FAIL; + struct sk_buff *skb = precv_frame->pkt; + u8 *pframe = skb->data; + u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); - p2pielen += 2; + if (!memcmp(frame_body + 2, P2P_OUI23A, 4)) { + ret = on_action_public23a_p2p(precv_frame); + } - /* Value: */ - memcpy(p2pie + p2pielen, pwdinfo->device_name, - pwdinfo->device_name_len); - p2pielen += pwdinfo->device_name_len; + return ret; +} - /* Operating Channel */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; +static unsigned int +on_action_public23a_default(struct recv_frame *precv_frame, u8 action) +{ + unsigned int ret = _FAIL; + struct sk_buff *skb = precv_frame->pkt; + u8 *pframe = skb->data; + uint frame_len = skb->len; + u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); + u8 token; + struct rtw_adapter *adapter = precv_frame->adapter; + int cnt = 0; + char msg[64]; - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); - p2pielen += 2; + token = frame_body[2]; - /* Value: */ - /* Country String */ - p2pie[p2pielen++] = 'X'; - p2pie[p2pielen++] = 'X'; + if (rtw_action_public_decache(precv_frame, token) == _FAIL) + goto exit; - /* The third byte should be set to 0x04. */ - /* Described in the "Operating Channel Attribute" section. */ - p2pie[p2pielen++] = 0x04; + cnt += sprintf((msg+cnt), "%s(token:%u)", + action_public_str23a(action), token); + rtw_cfg80211_rx_action(adapter, pframe, frame_len, msg); - /* Operating Class */ - if (pwdinfo->operating_channel <= 14) - { - /* Operating Class */ - p2pie[p2pielen++] = 0x51; - } - else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) - { - /* Operating Class */ - p2pie[p2pielen++] = 0x73; - } - else - { - /* Operating Class */ - p2pie[p2pielen++] = 0x7c; - } + ret = _SUCCESS; - /* Channel Number */ - p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ +exit: + return ret; +} - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen); +static int on_action_public23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + unsigned int ret = _FAIL; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; + u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); + u8 category, action; -#ifdef CONFIG_8723AU_P2P - wfdielen = build_nego_req_wfd_ie(pwdinfo, pframe); - pframe += wfdielen; - pattrib->pktlen += wfdielen; -#endif /* CONFIG_8723AU_P2P */ + /* check RA matches or not */ + if (!ether_addr_equal(myid(&padapter->eeprompriv), hdr->addr1)) + goto exit; - pattrib->last_txcmdsz = pattrib->pktlen; + category = frame_body[0]; + if (category != WLAN_CATEGORY_PUBLIC) + goto exit; - dump_mgntframe23a(padapter, pmgntframe); + action = frame_body[1]; + switch (action) { + case ACT_PUBLIC_VENDOR: + ret = on_action_public23a_vendor(precv_frame); + break; + default: + ret = on_action_public23a_default(precv_frame, action); + break; + } - return; +exit: + return ret; } -static void issue_p2p_GO_response(struct rtw_adapter *padapter, u8* raddr, u8* frame_body, uint len, u8 result) -{ - - unsigned char category = WLAN_CATEGORY_PUBLIC; - u8 action = P2P_PUB_ACTION_ACTION; - u32 p2poui = cpu_to_be32(P2POUI); - u8 oui_subtype = P2P_GO_NEGO_RESP; - u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; - u8 p2pielen = 0; - uint wpsielen = 0; - u16 wps_devicepassword_id = 0x0000; - uint wps_devicepassword_id_len = 0; - u16 len_channellist_attr = 0; - int i, j; - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#ifdef CONFIG_8723AU_P2P - u32 wfdielen = 0; -#endif /* CONFIG_8723AU_P2P */ - - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - return; - - DBG_8723A("[%s] In, result = %d\n", __func__, result); - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - fctrl = &pwlanhdr->frame_control; - *fctrl = 0; - - ether_addr_copy(pwlanhdr->addr1, raddr); - ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); - ether_addr_copy(pwlanhdr->addr3, myid(&padapter->eeprompriv)); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); - - pframe += sizeof(struct ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - - pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui, - &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); - /* The Dialog Token of provisioning discovery request frame. */ - pwdinfo->negotiation_dialog_token = frame_body[7]; - pframe = rtw_set_fixed_ie23a(pframe, 1, - &pwdinfo->negotiation_dialog_token, - &pattrib->pktlen); - - /* Commented by Albert 20110328 */ - /* Try to get the device password ID from the WPS IE of group - negotiation request frame */ - /* WiFi Direct test plan 5.1.15 */ - rtw_get_wps_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, - len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, &wpsielen); - rtw_get_wps_attr_content23a(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, - (u8 *)&wps_devicepassword_id, - &wps_devicepassword_id_len); - wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id); - - memset(wpsie, 0x00, 255); - wpsielen = 0; - - /* WPS Section */ - wpsielen = 0; - /* WPS OUI */ - *(u32*) (wpsie) = cpu_to_be32(WPSOUI); - wpsielen += 4; - - /* WPS version */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); - wpsielen += 2; - - /* Value: */ - wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ - - /* Device Password ID */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); - wpsielen += 2; - - /* Value: */ - if (wps_devicepassword_id == WPS_DPID_USER_SPEC) { - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); - } else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) { - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC); - } else { - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC); - } - wpsielen += 2; - - /* Commented by Kurt 20120113 */ - /* If some device wants to do p2p handshake without sending prov_disc_req */ - /* We have to get peer_req_cm from here. */ - if (!memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) { - if (wps_devicepassword_id == WPS_DPID_USER_SPEC) { - memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); - } else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) { - memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); - } else { - memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); - } - } - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, - (unsigned char *) wpsie, &pattrib->pktlen); - - /* P2P IE Section. */ - - /* P2P OUI */ - p2pielen = 0; - p2pie[p2pielen++] = 0x50; - p2pie[p2pielen++] = 0x6F; - p2pie[p2pielen++] = 0x9A; - p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ - - /* Commented by Albert 20100908 */ - /* According to the P2P Specification, the group negoitation - response frame should contain 9 P2P attributes */ - /* 1. Status */ - /* 2. P2P Capability */ - /* 3. Group Owner Intent */ - /* 4. Configuration Timeout */ - /* 5. Operating Channel */ - /* 6. Intended P2P Interface Address */ - /* 7. Channel List */ - /* 8. Device Info */ - /* 9. Group ID (Only GO) */ - - /* ToDo: */ - - /* P2P Status */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_STATUS; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001); - p2pielen += 2; - - /* Value: */ - p2pie[p2pielen++] = result; - - /* P2P Capability */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); - p2pielen += 2; - - /* Value: */ - /* Device Capability Bitmap, 1 byte */ - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { - /* Commented by Albert 2011/03/08 */ - /* According to the P2P specification */ - /* if the sending device will be client, the P2P - Capability should be reserved of group negotation - response frame */ - p2pie[p2pielen++] = 0; - } else { - /* Be group owner or meet the error case */ - p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; - } - - /* Group Capability Bitmap, 1 byte */ - if (pwdinfo->persistent_supported) { - p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | - P2P_GRPCAP_PERSISTENT_GROUP; - } else { - p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; - } - - /* Group Owner Intent */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_GO_INTENT; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001); - p2pielen += 2; - - /* Value: */ - if (pwdinfo->peer_intent & 0x01) { - /* Peer's tie breaker bit is 1, our tie breaker - bit should be 0 */ - p2pie[p2pielen++] = (pwdinfo->intent << 1); - } else { - /* Peer's tie breaker bit is 0, our tie breaker bit - should be 1 */ - p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0)); - } - - /* Configuration Timeout */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); - p2pielen += 2; - - /* Value: */ - /* 2 seconds needed to be the P2P GO */ - p2pie[p2pielen++] = 200; - /* 2 seconds needed to be the P2P Client */ - p2pie[p2pielen++] = 200; - - /* Operating Channel */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); - p2pielen += 2; - - /* Value: */ - /* Country String */ - p2pie[p2pielen++] = 'X'; - p2pie[p2pielen++] = 'X'; - - /* The third byte should be set to 0x04. */ - /* Described in the "Operating Channel Attribute" section. */ - p2pie[p2pielen++] = 0x04; - - /* Operating Class */ - if (pwdinfo->operating_channel <= 14) { - /* Operating Class */ - p2pie[p2pielen++] = 0x51; - } else if ((pwdinfo->operating_channel >= 36) && - (pwdinfo->operating_channel <= 48)) { - /* Operating Class */ - p2pie[p2pielen++] = 0x73; - } else { - /* Operating Class */ - p2pie[p2pielen++] = 0x7c; - } - - /* Channel Number */ - /* operating channel number */ - p2pie[p2pielen++] = pwdinfo->operating_channel; - - /* Intended P2P Interface Address */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); - p2pielen += 2; - - /* Value: */ - memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); - p2pielen += ETH_ALEN; - - /* Channel List */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CH_LIST; - - /* Country String(3) */ - /* + (Operating Class (1) + Number of Channels(1)) * - Operation Classes (?) */ - /* + number of channels in all classes */ - len_channellist_attr = 3 + - (1 + 1) * (u16)pmlmeext->channel_list.reg_classes + - get_reg_classes_full_count(pmlmeext->channel_list); - - *(u16*) (p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); - - p2pielen += 2; - - /* Value: */ - /* Country String */ - p2pie[p2pielen++] = 'X'; - p2pie[p2pielen++] = 'X'; - - /* The third byte should be set to 0x04. */ - /* Described in the "Operating Channel Attribute" section. */ - p2pie[p2pielen++] = 0x04; - - /* Channel Entry List */ - - for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { - /* Operating Class */ - p2pie[p2pielen++] = - pmlmeext->channel_list.reg_class[j].reg_class; - - /* Number of Channels */ - p2pie[p2pielen++] = - pmlmeext->channel_list.reg_class[j].channels; - - /* Channel List */ - for (i = 0; - i < pmlmeext->channel_list.reg_class[j].channels; i++) { - p2pie[p2pielen++] = - pmlmeext->channel_list.reg_class[j].channel[i]; - } - } - - /* Device Info */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; - - /* Length: */ - /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + - Primary Device Type (8bytes) */ - /* + NumofSecondDevType (1byte) + WPS Device Name ID field - (2bytes) + WPS Device Name Len field (2bytes) */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); - p2pielen += 2; - - /* Value: */ - /* P2P Device Address */ - memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); - p2pielen += ETH_ALEN; - - /* Config Method */ - /* This field should be big endian. Noted by P2P specification. */ - - *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); - - p2pielen += 2; - - /* Primary Device Type */ - /* Category ID */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); - p2pielen += 2; - - /* OUI */ - *(u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); - p2pielen += 4; - - /* Sub Category ID */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); - p2pielen += 2; - - /* Number of Secondary Device Types */ - p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ - - /* Device Name */ - /* Type: */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); - p2pielen += 2; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); - p2pielen += 2; - - /* Value: */ - memcpy(p2pie + p2pielen, pwdinfo->device_name, - pwdinfo->device_name_len); - p2pielen += pwdinfo->device_name_len; - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - { - /* Group ID Attribute */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = - cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen); - p2pielen += 2; - - /* Value: */ - /* p2P Device Address */ - memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); - p2pielen += ETH_ALEN; - - /* SSID */ - memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, - pwdinfo->nego_ssidlen); - p2pielen += pwdinfo->nego_ssidlen; - - } - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, - (unsigned char *) p2pie, &pattrib->pktlen); - -#ifdef CONFIG_8723AU_P2P - wfdielen = build_nego_resp_wfd_ie(pwdinfo, pframe); - pframe += wfdielen; - pattrib->pktlen += wfdielen; -#endif /* CONFIG_8723AU_P2P */ - - pattrib->last_txcmdsz = pattrib->pktlen; - - dump_mgntframe23a(padapter, pmgntframe); - - return; -} - -static void issue_p2p_GO_confirm(struct rtw_adapter *padapter, u8* raddr, - u8 result) -{ - - unsigned char category = WLAN_CATEGORY_PUBLIC; - u8 action = P2P_PUB_ACTION_ACTION; - u32 p2poui = cpu_to_be32(P2POUI); - u8 oui_subtype = P2P_GO_NEGO_CONF; - u8 p2pie[ 255 ] = { 0x00 }; - u8 p2pielen = 0; - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#ifdef CONFIG_8723AU_P2P - u32 wfdielen = 0; -#endif /* CONFIG_8723AU_P2P */ - - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - return; - - DBG_8723A("[%s] In\n", __func__); - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - fctrl = &pwlanhdr->frame_control; - *fctrl = 0; - - ether_addr_copy(pwlanhdr->addr1, raddr); - ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); - ether_addr_copy(pwlanhdr->addr3, myid(&padapter->eeprompriv)); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); - - pframe += sizeof(struct ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - - pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, - &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, - &pwdinfo->negotiation_dialog_token, - &pattrib->pktlen); - /* P2P OUI */ - p2pielen = 0; - p2pie[p2pielen++] = 0x50; - p2pie[p2pielen++] = 0x6F; - p2pie[p2pielen++] = 0x9A; - p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ - - /* Commented by Albert 20110306 */ - /* According to the P2P Specification, the group negoitation - request frame should contain 5 P2P attributes */ - /* 1. Status */ - /* 2. P2P Capability */ - /* 3. Operating Channel */ - /* 4. Channel List */ - /* 5. Group ID (if this WiFi is GO) */ - - /* P2P Status */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_STATUS; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001); - p2pielen += 2; - - /* Value: */ - p2pie[p2pielen++] = result; - - /* P2P Capability */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); - p2pielen += 2; - - /* Value: */ - /* Device Capability Bitmap, 1 byte */ - p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; - - /* Group Capability Bitmap, 1 byte */ - if (pwdinfo->persistent_supported) { - p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | - P2P_GRPCAP_PERSISTENT_GROUP; - } else { - p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; - } - - /* Operating Channel */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); - p2pielen += 2; - - /* Value: */ - /* Country String */ - p2pie[p2pielen++] = 'X'; - p2pie[p2pielen++] = 'X'; - - /* The third byte should be set to 0x04. */ - /* Described in the "Operating Channel Attribute" section. */ - p2pie[p2pielen++] = 0x04; - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { - if (pwdinfo->peer_operating_ch <= 14) { - /* Operating Class */ - p2pie[p2pielen++] = 0x51; - } else if ((pwdinfo->peer_operating_ch >= 36) && - (pwdinfo->peer_operating_ch <= 48)) { - /* Operating Class */ - p2pie[p2pielen++] = 0x73; - } else { - /* Operating Class */ - p2pie[p2pielen++] = 0x7c; - } - - p2pie[p2pielen++] = pwdinfo->peer_operating_ch; - } else { - if (pwdinfo->operating_channel <= 14) { - /* Operating Class */ - p2pie[p2pielen++] = 0x51; - } - else if ((pwdinfo->operating_channel >= 36) && - (pwdinfo->operating_channel <= 48)) { - /* Operating Class */ - p2pie[p2pielen++] = 0x73; - } else { - /* Operating Class */ - p2pie[p2pielen++] = 0x7c; - } - - /* Channel Number */ - /* Use the listen channel as the operating channel */ - p2pie[p2pielen++] = pwdinfo->operating_channel; - } - - /* Channel List */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CH_LIST; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = - cpu_to_le16(pwdinfo->channel_list_attr_len); - p2pielen += 2; - - /* Value: */ - memcpy(p2pie + p2pielen, pwdinfo->channel_list_attr, - pwdinfo->channel_list_attr_len); - p2pielen += pwdinfo->channel_list_attr_len; - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { - /* Group ID Attribute */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = - cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen); - p2pielen += 2; - - /* Value: */ - /* p2P Device Address */ - memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); - p2pielen += ETH_ALEN; - - /* SSID */ - memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, - pwdinfo->nego_ssidlen); - p2pielen += pwdinfo->nego_ssidlen; - } - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, - (unsigned char *)p2pie, &pattrib->pktlen); - -#ifdef CONFIG_8723AU_P2P - wfdielen = build_nego_confirm_wfd_ie(pwdinfo, pframe); - pframe += wfdielen; - pattrib->pktlen += wfdielen; -#endif /* CONFIG_8723AU_P2P */ - - pattrib->last_txcmdsz = pattrib->pktlen; - - dump_mgntframe23a(padapter, pmgntframe); - - return; -} - -void issue_p2p_invitation_request23a(struct rtw_adapter *padapter, u8* raddr) -{ - unsigned char category = WLAN_CATEGORY_PUBLIC; - u8 action = P2P_PUB_ACTION_ACTION; - u32 p2poui = cpu_to_be32(P2POUI); - u8 oui_subtype = P2P_INVIT_REQ; - u8 p2pie[ 255 ] = { 0x00 }; - u8 p2pielen = 0; - u8 dialogToken = 3; - u16 len_channellist_attr = 0; -#ifdef CONFIG_8723AU_P2P - u32 wfdielen = 0; -#endif /* CONFIG_8723AU_P2P */ - int i, j; - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - return; - - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - fctrl = &pwlanhdr->frame_control; - *fctrl = 0; - - ether_addr_copy(pwlanhdr->addr1, raddr); - ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); - ether_addr_copy(pwlanhdr->addr3, raddr); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); - - pframe += sizeof(struct ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - - pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui, - &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); - - /* P2P IE Section. */ - - /* P2P OUI */ - p2pielen = 0; - p2pie[p2pielen++] = 0x50; - p2pie[p2pielen++] = 0x6F; - p2pie[p2pielen++] = 0x9A; - p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ - - /* Commented by Albert 20101011 */ - /* According to the P2P Specification, the P2P Invitation - request frame should contain 7 P2P attributes */ - /* 1. Configuration Timeout */ - /* 2. Invitation Flags */ - /* 3. Operating Channel (Only GO) */ - /* 4. P2P Group BSSID (Should be included if I am the GO) */ - /* 5. Channel List */ - /* 6. P2P Group ID */ - /* 7. P2P Device Info */ - - /* Configuration Timeout */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); - p2pielen += 2; - - /* Value: */ - /* 2 seconds needed to be the P2P GO */ - p2pie[p2pielen++] = 200; - /* 2 seconds needed to be the P2P Client */ - p2pie[p2pielen++] = 200; - - /* Invitation Flags */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_INVITATION_FLAGS; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001); - p2pielen += 2; - - /* Value: */ - p2pie[p2pielen++] = P2P_INVITATION_FLAGS_PERSISTENT; - - /* Operating Channel */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); - p2pielen += 2; - - /* Value: */ - /* Country String */ - p2pie[p2pielen++] = 'X'; - p2pie[p2pielen++] = 'X'; - - /* The third byte should be set to 0x04. */ - /* Described in the "Operating Channel Attribute" section. */ - p2pie[p2pielen++] = 0x04; - - /* Operating Class */ - if (pwdinfo->invitereq_info.operating_ch <= 14) - p2pie[p2pielen++] = 0x51; - else if ((pwdinfo->invitereq_info.operating_ch >= 36) && - (pwdinfo->invitereq_info.operating_ch <= 48)) - p2pie[p2pielen++] = 0x73; - else - p2pie[p2pielen++] = 0x7c; - - /* Channel Number */ - /* operating channel number */ - p2pie[p2pielen++] = pwdinfo->invitereq_info.operating_ch; - - if (ether_addr_equal(myid(&padapter->eeprompriv), - pwdinfo->invitereq_info.go_bssid)) { - /* P2P Group BSSID */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); - p2pielen += 2; - - /* Value: */ - /* P2P Device Address for GO */ - memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, - ETH_ALEN); - p2pielen += ETH_ALEN; - } - - /* Channel List */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CH_LIST; - - /* Length: */ - /* Country String(3) */ - /* + (Operating Class (1) + Number of Channels(1)) * - Operation Classes (?) */ - /* + number of channels in all classes */ - len_channellist_attr = 3 + - (1 + 1) * (u16)pmlmeext->channel_list.reg_classes + - get_reg_classes_full_count(pmlmeext->channel_list); - - *(u16*) (p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); - p2pielen += 2; - - /* Value: */ - /* Country String */ - p2pie[p2pielen++] = 'X'; - p2pie[p2pielen++] = 'X'; - - /* The third byte should be set to 0x04. */ - /* Described in the "Operating Channel Attribute" section. */ - p2pie[p2pielen++] = 0x04; - - /* Channel Entry List */ - for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { - /* Operating Class */ - p2pie[p2pielen++] = - pmlmeext->channel_list.reg_class[j].reg_class; - - /* Number of Channels */ - p2pie[p2pielen++] = - pmlmeext->channel_list.reg_class[j].channels; - - /* Channel List */ - for (i = 0; - i < pmlmeext->channel_list.reg_class[j].channels; i++) { - p2pie[p2pielen++] = - pmlmeext->channel_list.reg_class[j].channel[i]; - } - } - - /* P2P Group ID */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = - cpu_to_le16(6 + pwdinfo->invitereq_info.ssidlen); - p2pielen += 2; - - /* Value: */ - /* P2P Device Address for GO */ - memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN); - p2pielen += ETH_ALEN; - - /* SSID */ - memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_ssid, - pwdinfo->invitereq_info.ssidlen); - p2pielen += pwdinfo->invitereq_info.ssidlen; - - /* Device Info */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; - - /* Length: */ - /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + - Primary Device Type (8bytes) */ - /* + NumofSecondDevType (1byte) + WPS Device Name ID field - (2bytes) + WPS Device Name Len field (2bytes) */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); - p2pielen += 2; - - /* Value: */ - /* P2P Device Address */ - memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); - p2pielen += ETH_ALEN; - - /* Config Method */ - /* This field should be big endian. Noted by P2P specification. */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); - p2pielen += 2; - - /* Primary Device Type */ - /* Category ID */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); - p2pielen += 2; - - /* OUI */ - *(u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); - p2pielen += 4; - - /* Sub Category ID */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); - p2pielen += 2; - - /* Number of Secondary Device Types */ - p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ - - /* Device Name */ - /* Type: */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); - p2pielen += 2; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); - p2pielen += 2; - - /* Value: */ - memcpy(p2pie + p2pielen, pwdinfo->device_name, - pwdinfo->device_name_len); - p2pielen += pwdinfo->device_name_len; - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, - (unsigned char *) p2pie, &pattrib->pktlen); - -#ifdef CONFIG_8723AU_P2P - wfdielen = build_invitation_req_wfd_ie(pwdinfo, pframe); - pframe += wfdielen; - pattrib->pktlen += wfdielen; -#endif /* CONFIG_8723AU_P2P */ - - pattrib->last_txcmdsz = pattrib->pktlen; - - dump_mgntframe23a(padapter, pmgntframe); - - return; -} - -void issue_p2p_invitation_response23a(struct rtw_adapter *padapter, u8 *raddr, - u8 dialogToken, u8 status_code) -{ - unsigned char category = WLAN_CATEGORY_PUBLIC; - u8 action = P2P_PUB_ACTION_ACTION; - u32 p2poui = cpu_to_be32(P2POUI); - u8 oui_subtype = P2P_INVIT_RESP; - u8 p2pie[ 255 ] = { 0x00 }; - u8 p2pielen = 0; - u16 len_channellist_attr = 0; -#ifdef CONFIG_8723AU_P2P - u32 wfdielen = 0; -#endif /* CONFIG_8723AU_P2P */ - int i, j; - - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - return; - - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - fctrl = &pwlanhdr->frame_control; - *fctrl = 0; - - ether_addr_copy(pwlanhdr->addr1, raddr); - ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); - ether_addr_copy(pwlanhdr->addr3, raddr); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); - - pframe += sizeof(struct ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - - pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, - &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); - - /* P2P IE Section. */ - - /* P2P OUI */ - p2pielen = 0; - p2pie[p2pielen++] = 0x50; - p2pie[p2pielen++] = 0x6F; - p2pie[p2pielen++] = 0x9A; - p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ - - /* Commented by Albert 20101005 */ - /* According to the P2P Specification, the P2P Invitation - response frame should contain 5 P2P attributes */ - /* 1. Status */ - /* 2. Configuration Timeout */ - /* 3. Operating Channel (Only GO) */ - /* 4. P2P Group BSSID (Only GO) */ - /* 5. Channel List */ - - /* P2P Status */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_STATUS; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001); - p2pielen += 2; - - /* Value: */ - /* When status code is P2P_STATUS_FAIL_INFO_UNAVAILABLE. */ - /* Sent the event receiving the P2P Invitation Req frame - to DMP UI. */ - /* DMP had to compare the MAC address to find out the profile. */ - /* So, the WiFi driver will send the - P2P_STATUS_FAIL_INFO_UNAVAILABLE to NB. */ - /* If the UI found the corresponding profile, the WiFi driver - sends the P2P Invitation Req */ - /* to NB to rebuild the persistent group. */ - p2pie[p2pielen++] = status_code; - - /* Configuration Timeout */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); - p2pielen += 2; - - /* Value: */ - /* 2 seconds needed to be the P2P GO */ - p2pie[p2pielen++] = 200; - /* 2 seconds needed to be the P2P Client */ - p2pie[p2pielen++] = 200; - - if (status_code == P2P_STATUS_SUCCESS) { - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { - /* The P2P Invitation request frame asks this - Wi-Fi device to be the P2P GO */ - /* In this case, the P2P Invitation response - frame should carry the two more P2P attributes. */ - /* First one is operating channel attribute. */ - /* Second one is P2P Group BSSID attribute. */ - - /* Operating Channel */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); - p2pielen += 2; - - /* Value: */ - /* Country String */ - p2pie[p2pielen++] = 'X'; - p2pie[p2pielen++] = 'X'; - - /* The third byte should be set to 0x04. */ - /* Described in the "Operating Channel Attribute" - section. */ - p2pie[p2pielen++] = 0x04; - - /* Operating Class */ - /* Copy from SD7 */ - p2pie[p2pielen++] = 0x51; - - /* Channel Number */ - /* operating channel number */ - p2pie[p2pielen++] = pwdinfo->operating_channel; - - /* P2P Group BSSID */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); - p2pielen += 2; - - /* Value: */ - /* P2P Device Address for GO */ - memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), - ETH_ALEN); - p2pielen += ETH_ALEN; - } - - /* Channel List */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CH_LIST; - - /* Length: */ - /* Country String(3) */ - /* + (Operating Class (1) + Number of Channels(1)) * - Operation Classes (?) */ - /* + number of channels in all classes */ - len_channellist_attr = 3 + - (1 + 1) * (u16)pmlmeext->channel_list.reg_classes + - get_reg_classes_full_count(pmlmeext->channel_list); - - *(u16*) (p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); - p2pielen += 2; - - /* Value: */ - /* Country String */ - p2pie[p2pielen++] = 'X'; - p2pie[p2pielen++] = 'X'; - - /* The third byte should be set to 0x04. */ - /* Described in the "Operating Channel Attribute" section. */ - p2pie[p2pielen++] = 0x04; - - /* Channel Entry List */ - for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { - /* Operating Class */ - p2pie[p2pielen++] = - pmlmeext->channel_list.reg_class[j].reg_class; - - /* Number of Channels */ - p2pie[p2pielen++] = - pmlmeext->channel_list.reg_class[j].channels; - - /* Channel List */ - for (i = 0; - i < pmlmeext->channel_list.reg_class[j].channels; - i++) { - p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; - } - } - } - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, - (unsigned char *)p2pie, &pattrib->pktlen); - -#ifdef CONFIG_8723AU_P2P - wfdielen = build_invitation_resp_wfd_ie(pwdinfo, pframe); - pframe += wfdielen; - pattrib->pktlen += wfdielen; -#endif /* CONFIG_8723AU_P2P */ - - pattrib->last_txcmdsz = pattrib->pktlen; - - dump_mgntframe23a(padapter, pmgntframe); - - return; -} - -void issue_p2p_provision_request23a(struct rtw_adapter *padapter, u8 *pssid, - u8 ussidlen, u8 *pdev_raddr) -{ - unsigned char category = WLAN_CATEGORY_PUBLIC; - u8 action = P2P_PUB_ACTION_ACTION; - u8 dialogToken = 1; - u32 p2poui = cpu_to_be32(P2POUI); - u8 oui_subtype = P2P_PROVISION_DISC_REQ; - u8 wpsie[100] = { 0x00 }; - u8 wpsielen = 0; - u32 p2pielen = 0; -#ifdef CONFIG_8723AU_P2P - u32 wfdielen = 0; -#endif /* CONFIG_8723AU_P2P */ - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - return; - - DBG_8723A("[%s] In\n", __func__); - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - fctrl = &pwlanhdr->frame_control; - *fctrl = 0; - - ether_addr_copy(pwlanhdr->addr1, pdev_raddr); - ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); - ether_addr_copy(pwlanhdr->addr3, pdev_raddr); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); - - pframe += sizeof(struct ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - - pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, - &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); - - p2pielen = build_prov_disc_request_p2p_ie23a(pwdinfo, pframe, pssid, - ussidlen, pdev_raddr); - - pframe += p2pielen; - pattrib->pktlen += p2pielen; - - wpsielen = 0; - /* WPS OUI */ - *(u32*) (wpsie) = cpu_to_be32(WPSOUI); - wpsielen += 4; - - /* WPS version */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); - wpsielen += 2; - - /* Value: */ - wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ - - /* Config Method */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); - wpsielen += 2; - - /* Value: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request); - wpsielen += 2; - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, - (unsigned char *) wpsie, &pattrib->pktlen); - -#ifdef CONFIG_8723AU_P2P - wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe); - pframe += wfdielen; - pattrib->pktlen += wfdielen; -#endif /* CONFIG_8723AU_P2P */ - - pattrib->last_txcmdsz = pattrib->pktlen; - - dump_mgntframe23a(padapter, pmgntframe); - - return; -} - -static u8 is_matched_in_profilelist(u8 *peermacaddr, - struct profile_info *profileinfo) -{ - u8 i, match_result = 0; - - DBG_8723A("[%s] peermac = %.2X %.2X %.2X %.2X %.2X %.2X\n", __func__, - peermacaddr[0], peermacaddr[1], peermacaddr[2], - peermacaddr[3], peermacaddr[4], peermacaddr[5]); - - for (i = 0; i < P2P_MAX_PERSISTENT_GROUP_NUM; i++, profileinfo++) { - DBG_8723A("[%s] profileinfo_mac = %.2X %.2X %.2X %.2X %.2X " - "%.2X\n", __func__, profileinfo->peermac[0], - profileinfo->peermac[1], profileinfo->peermac[2], - profileinfo->peermac[3], profileinfo->peermac[4], - profileinfo->peermac[5]); - if (ether_addr_equal(peermacaddr, profileinfo->peermac)) { - match_result = 1; - DBG_8723A("[%s] Match!\n", __func__); - break; - } - } - - return match_result; -} - -void issue_probersp23a_p2p23a(struct rtw_adapter *padapter, unsigned char *da) -{ - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - unsigned char *mac; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - u16 beacon_interval = 100; - u16 capInfo = 0; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 wpsie[255] = { 0x00 }; - u32 wpsielen = 0, p2pielen = 0; -#ifdef CONFIG_8723AU_P2P - u32 wfdielen = 0; -#endif /* CONFIG_8723AU_P2P */ - struct cfg80211_wifidirect_info *pcfg80211_wdinfo = - &padapter->cfg80211_wdinfo; - struct ieee80211_channel *ieee_ch = - &pcfg80211_wdinfo->remain_on_ch_channel; - u8 listen_channel = - (u8)ieee80211_frequency_to_channel(ieee_ch->center_freq); - - /* DBG_8723A("%s\n", __func__); */ - - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - { - return; - } - - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - mac = myid(&padapter->eeprompriv); - - fctrl = &pwlanhdr->frame_control; - *fctrl = 0; - ether_addr_copy(pwlanhdr->addr1, da); - ether_addr_copy(pwlanhdr->addr2, mac); - - /* Use the device address for BSSID field. */ - ether_addr_copy(pwlanhdr->addr3, mac); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(fctrl, WIFI_PROBERSP); - - pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); - pattrib->pktlen = pattrib->hdrlen; - pframe += pattrib->hdrlen; - - /* timestamp will be inserted by hardware */ - pframe += 8; - pattrib->pktlen += 8; - - /* beacon interval: 2 bytes */ - memcpy(pframe, (unsigned char *) &beacon_interval, 2); - pframe += 2; - pattrib->pktlen += 2; - - /* capability info: 2 bytes */ - /* ESS and IBSS bits must be 0 (defined in the 3.1.2.1.1 of - WiFi Direct Spec) */ - capInfo |= cap_ShortPremble; - capInfo |= cap_ShortSlot; - - memcpy(pframe, (unsigned char *) &capInfo, 2); - pframe += 2; - pattrib->pktlen += 2; - - /* SSID */ - pframe = rtw_set_ie23a(pframe, _SSID_IE_, 7, pwdinfo->p2p_wildcard_ssid, - &pattrib->pktlen); - - /* supported rates... */ - /* Use the OFDM rate in the P2P probe response frame. - (6(B), 9(B), 12, 18, 24, 36, 48, 54) */ - pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8, - pwdinfo->support_rate, &pattrib->pktlen); - - /* DS parameter set */ - if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled && - listen_channel != 0) { - pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *) - &listen_channel, &pattrib->pktlen); - } else { - pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *) - &pwdinfo->listen_channel, - &pattrib->pktlen); - } - - if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { - if (pmlmepriv->wps_probe_resp_ie && - pmlmepriv->p2p_probe_resp_ie) { - /* WPS IE */ - memcpy(pframe, pmlmepriv->wps_probe_resp_ie, - pmlmepriv->wps_probe_resp_ie_len); - pattrib->pktlen += pmlmepriv->wps_probe_resp_ie_len; - pframe += pmlmepriv->wps_probe_resp_ie_len; - - /* P2P IE */ - memcpy(pframe, pmlmepriv->p2p_probe_resp_ie, - pmlmepriv->p2p_probe_resp_ie_len); - pattrib->pktlen += pmlmepriv->p2p_probe_resp_ie_len; - pframe += pmlmepriv->p2p_probe_resp_ie_len; - } - } else { - - /* Todo: WPS IE */ - /* Noted by Albert 20100907 */ - /* According to the WPS specification, all the WPS - attribute is presented by Big Endian. */ - - wpsielen = 0; - /* WPS OUI */ - *(u32*) (wpsie) = cpu_to_be32(WPSOUI); - wpsielen += 4; - - /* WPS version */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); - wpsielen += 2; - - /* Value: */ - wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ - - /* WiFi Simple Config State */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(WPS_ATTR_SIMPLE_CONF_STATE); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); - wpsielen += 2; - - /* Value: */ - wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG; - - /* Response Type */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_RESP_TYPE); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); - wpsielen += 2; - - /* Value: */ - wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X; - - /* UUID-E */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0010); - wpsielen += 2; - - /* Value: */ - memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), ETH_ALEN); - wpsielen += 0x10; - - /* Manufacturer */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MANUFACTURER); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0007); - wpsielen += 2; - - /* Value: */ - memcpy(wpsie + wpsielen, "Realtek", 7); - wpsielen += 7; - - /* Model Name */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NAME); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0006); - wpsielen += 2; - - /* Value: */ - memcpy(wpsie + wpsielen, "8192CU", 6); - wpsielen += 6; - - /* Model Number */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NUMBER); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); - wpsielen += 2; - - /* Value: */ - wpsie[ wpsielen++ ] = 0x31; /* character 1 */ - - /* Serial Number */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(WPS_ATTR_SERIAL_NUMBER); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(ETH_ALEN); - wpsielen += 2; - - /* Value: */ - memcpy(wpsie + wpsielen, "123456", ETH_ALEN); - wpsielen += ETH_ALEN; - - /* Primary Device Type */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0008); - wpsielen += 2; - - /* Value: */ - /* Category ID */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); - wpsielen += 2; - - /* OUI */ - *(u32*) (wpsie + wpsielen) = cpu_to_be32(WPSOUI); - wpsielen += 4; - - /* Sub Category ID */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); - wpsielen += 2; - - /* Device Name */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(pwdinfo->device_name_len); - wpsielen += 2; - - /* Value: */ - if (pwdinfo->device_name_len) { - memcpy(wpsie + wpsielen, pwdinfo->device_name, - pwdinfo->device_name_len); - wpsielen += pwdinfo->device_name_len; - } - - /* Config Method */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); - wpsielen += 2; - - /* Value: */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(pwdinfo->supported_wps_cm); - wpsielen += 2; - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, - (unsigned char *)wpsie, - &pattrib->pktlen); - - p2pielen = build_probe_resp_p2p_ie23a(pwdinfo, pframe); - pframe += p2pielen; - pattrib->pktlen += p2pielen; - } - -#ifdef CONFIG_8723AU_P2P - if (pwdinfo->wfd_info->wfd_enable) { - wfdielen = build_probe_resp_wfd_ie(pwdinfo, pframe, 0); - pframe += wfdielen; - pattrib->pktlen += wfdielen; - } else if (pmlmepriv->wfd_probe_resp_ie && - pmlmepriv->wfd_probe_resp_ie_len > 0) { - /* WFD IE */ - memcpy(pframe, pmlmepriv->wfd_probe_resp_ie, - pmlmepriv->wfd_probe_resp_ie_len); - pattrib->pktlen += pmlmepriv->wfd_probe_resp_ie_len; - pframe += pmlmepriv->wfd_probe_resp_ie_len; - } -#endif /* CONFIG_8723AU_P2P */ - - pattrib->last_txcmdsz = pattrib->pktlen; - - dump_mgntframe23a(padapter, pmgntframe); - - return; -} - -static int _issue23a_probereq_p2p(struct rtw_adapter *padapter, u8 *da, - int wait_ack) -{ - int ret = _FAIL; - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - unsigned char *mac; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 wpsie[255] = {0x00}, p2pie[255] = {0x00}; - u16 wpsielen = 0, p2pielen = 0; -#ifdef CONFIG_8723AU_P2P - u32 wfdielen = 0; -#endif /* CONFIG_8723AU_P2P */ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - goto exit; - - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - mac = myid(&padapter->eeprompriv); - - fctrl = &pwlanhdr->frame_control; - *fctrl = 0; - - if (da) { - ether_addr_copy(pwlanhdr->addr1, da); - ether_addr_copy(pwlanhdr->addr3, da); - } else { - if ((pwdinfo->p2p_info.scan_op_ch_only) || - (pwdinfo->rx_invitereq_info.scan_op_ch_only)) { - /* This two flags will be set when this is - only the P2P client mode. */ - ether_addr_copy(pwlanhdr->addr1, - pwdinfo->p2p_peer_interface_addr); - ether_addr_copy(pwlanhdr->addr3, - pwdinfo->p2p_peer_interface_addr); - } else { - /* broadcast probe request frame */ - ether_addr_copy(pwlanhdr->addr1, bc_addr); - ether_addr_copy(pwlanhdr->addr3, bc_addr); - } - } - ether_addr_copy(pwlanhdr->addr2, mac); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_PROBEREQ); - - pframe += sizeof (struct ieee80211_hdr_3addr); - pattrib->pktlen = sizeof (struct ieee80211_hdr_3addr); - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) { - pframe = rtw_set_ie23a(pframe, _SSID_IE_, - pwdinfo->tx_prov_disc_info.ssid.ssid_len, - pwdinfo->tx_prov_disc_info.ssid.ssid, - &pattrib->pktlen); - } else { - pframe = rtw_set_ie23a(pframe, _SSID_IE_, - P2P_WILDCARD_SSID_LEN, - pwdinfo->p2p_wildcard_ssid, - &pattrib->pktlen); - } - /* Use the OFDM rate in the P2P probe request frame. - (6(B), 9(B), 12(B), 24(B), 36, 48, 54) */ - pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8, - pwdinfo->support_rate, &pattrib->pktlen); - - if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { - if (pmlmepriv->wps_probe_req_ie && - pmlmepriv->p2p_probe_req_ie) { - /* WPS IE */ - memcpy(pframe, pmlmepriv->wps_probe_req_ie, - pmlmepriv->wps_probe_req_ie_len); - pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; - pframe += pmlmepriv->wps_probe_req_ie_len; - - /* P2P IE */ - memcpy(pframe, pmlmepriv->p2p_probe_req_ie, - pmlmepriv->p2p_probe_req_ie_len); - pattrib->pktlen += pmlmepriv->p2p_probe_req_ie_len; - pframe += pmlmepriv->p2p_probe_req_ie_len; - } - } else { - - /* WPS IE */ - /* Noted by Albert 20110221 */ - /* According to the WPS specification, all the WPS - attribute is presented by Big Endian. */ - - wpsielen = 0; - /* WPS OUI */ - *(u32*) (wpsie) = cpu_to_be32(WPSOUI); - wpsielen += 4; - - /* WPS version */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); - wpsielen += 2; - - /* Value: */ - wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ - - if (pmlmepriv->wps_probe_req_ie == NULL) { - /* UUID-E */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(WPS_ATTR_UUID_E); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0010); - wpsielen += 2; - - /* Value: */ - memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), - ETH_ALEN); - wpsielen += 0x10; - - /* Config Method */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(WPS_ATTR_CONF_METHOD); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); - wpsielen += 2; - - /* Value: */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(pwdinfo->supported_wps_cm); - wpsielen += 2; - } - - /* Device Name */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(pwdinfo->device_name_len); - wpsielen += 2; - - /* Value: */ - memcpy(wpsie + wpsielen, pwdinfo->device_name, - pwdinfo->device_name_len); - wpsielen += pwdinfo->device_name_len; - - /* Primary Device Type */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0008); - wpsielen += 2; - - /* Value: */ - /* Category ID */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_RTK_WIDI); - wpsielen += 2; - - /* OUI */ - *(u32*) (wpsie + wpsielen) = cpu_to_be32(WPSOUI); - wpsielen += 4; - - /* Sub Category ID */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_RTK_DMP); - wpsielen += 2; - - /* Device Password ID */ - /* Type: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); - wpsielen += 2; - - /* Length: */ - *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); - wpsielen += 2; - - /* Value: */ - /* Registrar-specified */ - *(u16*) (wpsie + wpsielen) = - cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); - wpsielen += 2; - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, - (unsigned char *)wpsie, - &pattrib->pktlen); - - /* P2P OUI */ - p2pielen = 0; - p2pie[p2pielen++] = 0x50; - p2pie[p2pielen++] = 0x6F; - p2pie[p2pielen++] = 0x9A; - p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ - - /* Commented by Albert 20110221 */ - /* According to the P2P Specification, the probe request - frame should contain 5 P2P attributes */ - /* 1. P2P Capability */ - /* 2. P2P Device ID if this probe request wants to - find the specific P2P device */ - /* 3. Listen Channel */ - /* 4. Extended Listen Timing */ - /* 5. Operating Channel if this WiFi is working as - the group owner now */ - - /* P2P Capability */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); - p2pielen += 2; - - /* Value: */ - /* Device Capability Bitmap, 1 byte */ - p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; - - /* Group Capability Bitmap, 1 byte */ - if (pwdinfo->persistent_supported) - p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | - DMP_P2P_GRPCAP_SUPPORT; - else - p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; - - /* Listen Channel */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); - p2pielen += 2; - - /* Value: */ - /* Country String */ - p2pie[p2pielen++] = 'X'; - p2pie[p2pielen++] = 'X'; - - /* The third byte should be set to 0x04. */ - /* Described in the "Operating Channel Attribute" section. */ - p2pie[p2pielen++] = 0x04; - - /* Operating Class */ - p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ - - /* Channel Number */ - /* listen channel */ - p2pie[p2pielen++] = pwdinfo->listen_channel; - - /* Extended Listen Timing */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); - p2pielen += 2; - - /* Value: */ - /* Availability Period */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); - p2pielen += 2; - - /* Availability Interval */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); - p2pielen += 2; - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { - /* Operating Channel (if this WiFi is working as - the group owner now) */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); - p2pielen += 2; - - /* Value: */ - /* Country String */ - p2pie[p2pielen++] = 'X'; - p2pie[p2pielen++] = 'X'; - - /* The third byte should be set to 0x04. */ - /* Described in the "Operating Channel Attribute" - section. */ - p2pie[p2pielen++] = 0x04; - - /* Operating Class */ - p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ - - /* Channel Number */ - /* operating channel number */ - p2pie[p2pielen++] = pwdinfo->operating_channel; - } - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, - (unsigned char *)p2pie, - &pattrib->pktlen); - - if (pmlmepriv->wps_probe_req_ie) { - /* WPS IE */ - memcpy(pframe, pmlmepriv->wps_probe_req_ie, - pmlmepriv->wps_probe_req_ie_len); - pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; - pframe += pmlmepriv->wps_probe_req_ie_len; - } - } - -#ifdef CONFIG_8723AU_P2P - if (pwdinfo->wfd_info->wfd_enable) { - wfdielen = build_probe_req_wfd_ie(pwdinfo, pframe); - pframe += wfdielen; - pattrib->pktlen += wfdielen; - } else if (pmlmepriv->wfd_probe_req_ie && - pmlmepriv->wfd_probe_req_ie_len>0) { - /* WFD IE */ - memcpy(pframe, pmlmepriv->wfd_probe_req_ie, - pmlmepriv->wfd_probe_req_ie_len); - pattrib->pktlen += pmlmepriv->wfd_probe_req_ie_len; - pframe += pmlmepriv->wfd_probe_req_ie_len; - } -#endif /* CONFIG_8723AU_P2P */ - - pattrib->last_txcmdsz = pattrib->pktlen; - - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("issuing probe_req, tx_len =%d\n", pattrib->last_txcmdsz)); - - if (wait_ack) { - ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe); - } else { - dump_mgntframe23a(padapter, pmgntframe); - ret = _SUCCESS; - } - -exit: - return ret; -} - -inline void issue23a_probereq_p2p(struct rtw_adapter *adapter, u8 *da) -{ - _issue23a_probereq_p2p(adapter, da, false); -} - -int issue23a_probereq_p2p_ex(struct rtw_adapter *adapter, u8 *da, - int try_cnt, int wait_ms) -{ - int ret; - int i = 0; - unsigned long start = jiffies; - - do { - ret = _issue23a_probereq_p2p(adapter, da, - wait_ms > 0 ? true : false); - - i++; - - if (adapter->bDriverStopped || adapter->bSurpriseRemoved) - break; - - if (i < try_cnt && wait_ms > 0 && ret == _FAIL) - msleep(wait_ms); - - } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); - - if (ret != _FAIL) { - ret = _SUCCESS; - goto exit; - } - - if (try_cnt && wait_ms) { - if (da) - DBG_8723A(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d " - "in %u ms\n", FUNC_ADPT_ARG(adapter), - MAC_ARG(da), rtw_get_oper_ch23a(adapter), - ret == _SUCCESS?", acked":"", i, try_cnt, - jiffies_to_msecs(jiffies - start)); - else - DBG_8723A(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(adapter), - rtw_get_oper_ch23a(adapter), - ret == _SUCCESS?", acked":"", i, try_cnt, - jiffies_to_msecs(jiffies - start)); - } -exit: - return ret; -} - -#endif /* CONFIG_8723AU_P2P */ - -static s32 rtw_action_public_decache(struct recv_frame *recv_frame, s32 token) -{ - struct rtw_adapter *adapter = recv_frame->adapter; - struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; - struct sk_buff *skb = recv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 seq_ctrl; - - seq_ctrl = ((recv_frame->attrib.seq_num&0xffff) << 4) | - (recv_frame->attrib.frag_num & 0xf); - - if (ieee80211_has_retry(hdr->frame_control)) { - if (token >= 0) { - if ((seq_ctrl == mlmeext->action_public_rxseq) && - (token == mlmeext->action_public_dialog_token)) { - DBG_8723A(FUNC_ADPT_FMT" seq_ctrl = 0x%x, " - "rxseq = 0x%x, token:%d\n", - FUNC_ADPT_ARG(adapter), seq_ctrl, - mlmeext->action_public_rxseq, token); - return _FAIL; - } - } else { - if (seq_ctrl == mlmeext->action_public_rxseq) { - DBG_8723A(FUNC_ADPT_FMT" seq_ctrl = 0x%x, " - "rxseq = 0x%x\n", - FUNC_ADPT_ARG(adapter), seq_ctrl, - mlmeext->action_public_rxseq); - return _FAIL; - } - } - } - - mlmeext->action_public_rxseq = seq_ctrl; - - if (token >= 0) - mlmeext->action_public_dialog_token = token; - - return _SUCCESS; -} - -static unsigned int on_action_public23a_p2p(struct recv_frame *precv_frame) -{ - struct sk_buff *skb = precv_frame->pkt; - u8 *pframe = skb->data; - u8 *frame_body; - u8 dialogToken = 0; -#ifdef CONFIG_8723AU_P2P - struct rtw_adapter *padapter = precv_frame->adapter; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - uint len = skb->len; - u8 *p2p_ie; - u32 p2p_ielen; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 result = P2P_STATUS_SUCCESS; -#endif /* CONFIG_8723AU_P2P */ - - frame_body = (unsigned char *) - (pframe + sizeof(struct ieee80211_hdr_3addr)); - - dialogToken = frame_body[7]; - - if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL) - return _FAIL; - -#ifdef CONFIG_8723AU_P2P - del_timer_sync(&pwdinfo->reset_ch_sitesurvey); - if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { - rtw_cfg80211_rx_p2p_action_public(padapter, pframe, len); - } else { - /* Do nothing if the driver doesn't enable the P2P function. */ - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) - return _SUCCESS; - - len -= sizeof(struct ieee80211_hdr_3addr); - - switch (frame_body[ 6 ])/* OUI Subtype */ - { - case P2P_GO_NEGO_REQ: - DBG_8723A("[%s] Got GO Nego Req Frame\n", __func__); - memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info)); - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) - { - rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); - } - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) - { - /* Commented by Albert 20110526 */ - /* In this case, this means the previous nego fail doesn't be reset yet. */ - del_timer_sync(&pwdinfo->restore_p2p_state_timer); - /* Restore the previous p2p state */ - rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); - DBG_8723A("[%s] Restore the previous p2p state to %d\n", __func__, rtw_p2p_state(pwdinfo)); - } - - /* Commented by Kurt 20110902 */ - /* Add if statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */ - if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) - rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); - - /* Commented by Kurt 20120113 */ - /* Get peer_dev_addr here if peer doesn't issue prov_disc frame. */ - if (is_zero_ether_addr(pwdinfo->rx_prov_disc_info.peerDevAddr)) - ether_addr_copy(pwdinfo->rx_prov_disc_info.peerDevAddr, hdr->addr2); - - result = process_p2p_group_negotation_req23a(pwdinfo, frame_body, len); - issue_p2p_GO_response(padapter, hdr->addr2, - frame_body, len, result); - - /* Commented by Albert 20110718 */ - /* No matter negotiating or negotiation failure, the driver should set up the restore P2P state timer. */ - mod_timer(&pwdinfo->restore_p2p_state_timer, - jiffies + msecs_to_jiffies(5000)); - break; - - case P2P_GO_NEGO_RESP: - DBG_8723A("[%s] Got GO Nego Resp Frame\n", __func__); - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) - { - /* Commented by Albert 20110425 */ - /* The restore timer is enabled when issuing the nego request frame of rtw_p2p_connect function. */ - del_timer_sync(&pwdinfo->restore_p2p_state_timer); - pwdinfo->nego_req_info.benable = false; - result = process_p2p_group_negotation_resp23a(pwdinfo, frame_body, len); - issue_p2p_GO_confirm(pwdinfo->padapter, - hdr->addr2, - result); - if (result == P2P_STATUS_SUCCESS) { - if (rtw_p2p_role(pwdinfo) == - P2P_ROLE_CLIENT) { - pwdinfo->p2p_info.operation_ch[ 0 ] = pwdinfo->peer_operating_ch; - pwdinfo->p2p_info.scan_op_ch_only = 1; - mod_timer(&pwdinfo->reset_ch_sitesurvey2, jiffies + msecs_to_jiffies(P2P_RESET_SCAN_CH)); - } - } - - /* Reset the dialog token for group negotiation frames. */ - pwdinfo->negotiation_dialog_token = 1; - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) - { - mod_timer(&pwdinfo->restore_p2p_state_timer, jiffies + msecs_to_jiffies(5000)); - } - } else { - DBG_8723A("[%s] Skipped GO Nego Resp Frame (p2p_state != P2P_STATE_GONEGO_ING)\n", __func__); - } - - break; - - case P2P_GO_NEGO_CONF: - - DBG_8723A("[%s] Got GO Nego Confirm Frame\n", __func__); - result = process_p2p_group_negotation_confirm23a(pwdinfo, frame_body, len); - if (P2P_STATUS_SUCCESS == result) - { - if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) - { - pwdinfo->p2p_info.operation_ch[ 0 ] = pwdinfo->peer_operating_ch; - pwdinfo->p2p_info.scan_op_ch_only = 1; - mod_timer(&pwdinfo->reset_ch_sitesurvey2, jiffies + msecs_to_jiffies(P2P_RESET_SCAN_CH)); - } - } - break; - - case P2P_INVIT_REQ: - /* Added by Albert 2010/10/05 */ - /* Received the P2P Invite Request frame. */ - - DBG_8723A("[%s] Got invite request frame!\n", __func__); - if ((p2p_ie = rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen))) - { - /* Parse the necessary information from the P2P Invitation Request frame. */ - /* For example: The MAC address of sending this P2P Invitation Request frame. */ - u32 attr_contentlen = 0; - u8 status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; - struct group_id_info group_id; - u8 invitation_flag = 0; - - rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, &invitation_flag, &attr_contentlen); - if (attr_contentlen) - { - - rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_BSSID, pwdinfo->p2p_peer_interface_addr, &attr_contentlen); - /* Commented by Albert 20120510 */ - /* Copy to the pwdinfo->p2p_peer_interface_addr. */ - /* So that the WFD UI (or Sigma) can get the peer interface address by using the following command. */ - /* #> iwpriv wlan0 p2p_get peer_ifa */ - /* After having the peer interface address, the sigma can find the correct conf file for wpa_supplicant. */ - - if (attr_contentlen) - { - DBG_8723A("[%s] GO's BSSID = %.2X %.2X %.2X %.2X %.2X %.2X\n", __func__, - pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], - pwdinfo->p2p_peer_interface_addr[2], pwdinfo->p2p_peer_interface_addr[3], - pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]); - } - - if (invitation_flag & P2P_INVITATION_FLAGS_PERSISTENT) - { - /* Re-invoke the persistent group. */ - - memset(&group_id, 0x00, sizeof(struct group_id_info)); - rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8*) &group_id, &attr_contentlen); - if (attr_contentlen) { - if (ether_addr_equal(group_id.go_device_addr, myid(&padapter->eeprompriv))) { - /* The p2p device sending this p2p invitation request wants this Wi-Fi device to be the persistent GO. */ - rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_GO); - rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); - status_code = P2P_STATUS_SUCCESS; - } - else - { - /* The p2p device sending this p2p invitation request wants to be the persistent GO. */ - if (is_matched_in_profilelist(pwdinfo->p2p_peer_interface_addr, &pwdinfo->profileinfo[ 0 ])) - { - u8 operatingch_info[5] = { 0x00 }; - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) - { - if (rtw_ch_set_search_ch23a(padapter->mlmeextpriv.channel_set, (u32)operatingch_info[4])) - { - /* The operating channel is acceptable for this device. */ - pwdinfo->rx_invitereq_info.operation_ch[0]= operatingch_info[4]; - pwdinfo->rx_invitereq_info.scan_op_ch_only = 1; - mod_timer(&pwdinfo->reset_ch_sitesurvey, jiffies + msecs_to_jiffies(P2P_RESET_SCAN_CH)); - rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH); - rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); - status_code = P2P_STATUS_SUCCESS; - } - else - { - /* The operating channel isn't supported by this device. */ - rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - status_code = P2P_STATUS_FAIL_NO_COMMON_CH; - mod_timer(&pwdinfo->restore_p2p_state_timer, jiffies + msecs_to_jiffies(3000)); - } - } - else { - /* Commented by Albert 20121130 */ - /* Intel will use the different P2P IE to store the operating channel information */ - /* Workaround for Intel WiDi 3.5 */ - rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH); - rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); - status_code = P2P_STATUS_SUCCESS; - } - } - else - { - rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); - - status_code = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP; - } - } - } - else - { - DBG_8723A("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__); - status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; - } - } - else - { - /* Received the invitation to join a P2P group. */ - - memset(&group_id, 0x00, sizeof(struct group_id_info)); - rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8*) &group_id, &attr_contentlen); - if (attr_contentlen) - { - if (ether_addr_equal(group_id.go_device_addr, myid(&padapter->eeprompriv))) { - /* In this case, the GO can't be myself. */ - rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); - status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; - } - else - { - /* The p2p device sending this p2p invitation request wants to join an existing P2P group */ - /* Commented by Albert 2012/06/28 */ - /* In this case, this Wi-Fi device should use the iwpriv command to get the peer device address. */ - /* The peer device address should be the destination address for the provisioning discovery request. */ - /* Then, this Wi-Fi device should use the iwpriv command to get the peer interface address. */ - /* The peer interface address should be the address for WPS mac address */ - ether_addr_copy(pwdinfo->p2p_peer_device_addr, group_id.go_device_addr); - rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); - rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_JOIN); - status_code = P2P_STATUS_SUCCESS; - } - } - else - { - DBG_8723A("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__); - status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; - } - } - } - else - { - DBG_8723A("[%s] P2P Invitation Flags Attribute NOT FOUND!\n", __func__); - status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; - } - - DBG_8723A("[%s] status_code = %d\n", __func__, status_code); - - pwdinfo->inviteresp_info.token = frame_body[ 7 ]; - issue_p2p_invitation_response23a(padapter, hdr->addr2, pwdinfo->inviteresp_info.token, status_code); - } - break; - - case P2P_INVIT_RESP: - { - u8 attr_content = 0x00; - u32 attr_contentlen = 0; - - DBG_8723A("[%s] Got invite response frame!\n", __func__); - del_timer_sync(&pwdinfo->restore_p2p_state_timer); - if ((p2p_ie = rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen))) - { - rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); - - if (attr_contentlen == 1) - { - DBG_8723A("[%s] Status = %d\n", __func__, attr_content); - pwdinfo->invitereq_info.benable = false; - - if (attr_content == P2P_STATUS_SUCCESS) - { - if (ether_addr_equal(pwdinfo->invitereq_info.go_bssid, myid(&padapter->eeprompriv))) { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); - } - else - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); - } - rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_OK); - } - else - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); - } - } - else - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); - } - } - else - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); - } - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL)) { - mod_timer(&pwdinfo->restore_p2p_state_timer, jiffies + msecs_to_jiffies(5000)); - } - break; - } - case P2P_DEVDISC_REQ: - - process_p2p_devdisc_req23a(pwdinfo, pframe, len); - - break; - - case P2P_DEVDISC_RESP: - - process_p2p_devdisc_resp23a(pwdinfo, pframe, len); - - break; - - case P2P_PROVISION_DISC_REQ: - DBG_8723A("[%s] Got Provisioning Discovery Request Frame\n", __func__); - process_p2p_provdisc_req23a(pwdinfo, pframe, len); - ether_addr_copy(pwdinfo->rx_prov_disc_info.peerDevAddr, hdr->addr2); - - /* 20110902 Kurt */ - /* Add the following statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */ - if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) - rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); - - rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ); - mod_timer(&pwdinfo->restore_p2p_state_timer, - jiffies + msecs_to_jiffies(P2P_PROVISION_TIMEOUT)); - break; - - case P2P_PROVISION_DISC_RESP: - /* Commented by Albert 20110707 */ - /* Should we check the pwdinfo->tx_prov_disc_info.bsent flag here?? */ - DBG_8723A("[%s] Got Provisioning Discovery Response Frame\n", __func__); - /* Commented by Albert 20110426 */ - /* The restore timer is enabled when issuing the provisioing request frame in rtw_p2p_prov_disc function. */ - del_timer_sync(&pwdinfo->restore_p2p_state_timer); - rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP); - process_p2p_provdisc_resp23a(pwdinfo, pframe); - mod_timer(&pwdinfo->restore_p2p_state_timer, - jiffies + msecs_to_jiffies(P2P_PROVISION_TIMEOUT)); - break; - - } - } -#endif /* CONFIG_8723AU_P2P */ - - return _SUCCESS; -} - -static unsigned int on_action_public23a_vendor(struct recv_frame *precv_frame) -{ - unsigned int ret = _FAIL; - struct sk_buff *skb = precv_frame->pkt; - u8 *pframe = skb->data; - u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); - - if (!memcmp(frame_body + 2, P2P_OUI23A, 4)) { - ret = on_action_public23a_p2p(precv_frame); - } - - return ret; -} - -static unsigned int -on_action_public23a_default(struct recv_frame *precv_frame, u8 action) -{ - unsigned int ret = _FAIL; - struct sk_buff *skb = precv_frame->pkt; - u8 *pframe = skb->data; - uint frame_len = skb->len; - u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); - u8 token; - struct rtw_adapter *adapter = precv_frame->adapter; - int cnt = 0; - char msg[64]; - - token = frame_body[2]; - - if (rtw_action_public_decache(precv_frame, token) == _FAIL) - goto exit; - - cnt += sprintf((msg+cnt), "%s(token:%u)", - action_public_str23a(action), token); - rtw_cfg80211_rx_action(adapter, pframe, frame_len, msg); - - ret = _SUCCESS; - -exit: - return ret; -} - -unsigned int on_action_public23a(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) -{ - unsigned int ret = _FAIL; - struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u8 *pframe = skb->data; - u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); - u8 category, action; - - /* check RA matches or not */ - if (!ether_addr_equal(myid(&padapter->eeprompriv), hdr->addr1)) - goto exit; - - category = frame_body[0]; - if (category != WLAN_CATEGORY_PUBLIC) - goto exit; - - action = frame_body[1]; - switch (action) { - case ACT_PUBLIC_VENDOR: - ret = on_action_public23a_vendor(precv_frame); - break; - default: - ret = on_action_public23a_default(precv_frame, action); - break; - } - -exit: - return ret; -} - -unsigned int OnAction23a_ht(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) -{ - return _SUCCESS; -} - -unsigned int OnAction23a_wmm(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) +static int +OnAction23a_ht(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { return _SUCCESS; -} - -unsigned int OnAction23a_p2p(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) -{ -#ifdef CONFIG_8723AU_P2P - u8 *frame_body; - u8 category, OUI_Subtype, dialogToken = 0; - struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u8 *pframe = skb->data; - uint len = skb->len; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - - DBG_8723A("%s\n", __func__); - - /* check RA matches or not */ - if (!ether_addr_equal(myid(&padapter->eeprompriv), hdr->addr1)) - return _SUCCESS; - - frame_body = (unsigned char *) - (pframe + sizeof(struct ieee80211_hdr_3addr)); - - category = frame_body[0]; - if (category != WLAN_CATEGORY_VENDOR_SPECIFIC) - return _SUCCESS; - - if (cpu_to_be32(*((u32*) (frame_body + 1))) != P2POUI) - return _SUCCESS; - - if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { - rtw_cfg80211_rx_action_p2p(padapter, pframe, len); - return _SUCCESS; - } else { - len -= sizeof(struct ieee80211_hdr_3addr); - OUI_Subtype = frame_body[5]; - dialogToken = frame_body[6]; - - switch (OUI_Subtype) - { - case P2P_NOTICE_OF_ABSENCE: - break; - - case P2P_PRESENCE_REQUEST: - process_p2p_presence_req23a(pwdinfo, pframe, len); - break; - - case P2P_PRESENCE_RESPONSE: - break; - - case P2P_GO_DISC_REQUEST: - break; +} - default: - break; - } - } -#endif /* CONFIG_8723AU_P2P */ +static int +OnAction23a_wmm(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +{ + return _SUCCESS; +} +static int +OnAction23a_p2p(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +{ return _SUCCESS; } -unsigned int OnAction23a(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) +static int +OnAction23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { int i; - unsigned char category; + u8 category; struct action_handler *ptable; - unsigned char *frame_body; struct sk_buff *skb = precv_frame->pkt; - u8 *pframe = skb->data; - - frame_body = (unsigned char *) - (pframe + sizeof(struct ieee80211_hdr_3addr)); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data; - category = frame_body[0]; + category = mgmt->u.action.category; for (i = 0; i < sizeof(OnAction23a_tbl) / sizeof(struct action_handler); i++) { @@ -5067,8 +2243,8 @@ unsigned int OnAction23a(struct rtw_adapter *padapter, return _SUCCESS; } -unsigned int DoReserved23a(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) +static int DoReserved23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) { return _SUCCESS; } @@ -5259,7 +2435,7 @@ void issue_beacon23a(struct rtw_adapter *padapter, int timeout_ms) struct pkt_attrib *pattrib; unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; + __le16 *fctrl; unsigned int rate_len; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -5267,9 +2443,6 @@ void issue_beacon23a(struct rtw_adapter *padapter, int timeout_ms) struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif /* CONFIG_8723AU_P2P */ u8 *wps_ie; u32 wps_ielen; u8 sr = 0; @@ -5311,119 +2484,7 @@ void issue_beacon23a(struct rtw_adapter *padapter, int timeout_ms) if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { /* DBG_8723A("ie len =%d\n", cur_network->IELength); */ -#ifdef CONFIG_8723AU_P2P - /* for P2P : Primary Device Type & Device Name */ - u32 insert_len = 0; - wps_ie = rtw_get_wps_ie23a(cur_network->IEs + _FIXED_IE_LENGTH_, - cur_network->IELength - - _FIXED_IE_LENGTH_, NULL, &wps_ielen); - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && wps_ie && - wps_ielen > 0) { - uint wps_offset, remainder_ielen; - u8 *premainder_ie, *pframe_wscie; - - wps_offset = (uint)(wps_ie - cur_network->IEs); - - premainder_ie = wps_ie + wps_ielen; - - remainder_ielen = cur_network->IELength - wps_offset - - wps_ielen; - - if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { - if (pmlmepriv->wps_beacon_ie && - pmlmepriv->wps_beacon_ie_len>0) { - memcpy(pframe, cur_network->IEs, - wps_offset); - pframe += wps_offset; - pattrib->pktlen += wps_offset; - - memcpy(pframe, pmlmepriv->wps_beacon_ie, - pmlmepriv->wps_beacon_ie_len); - pframe += pmlmepriv->wps_beacon_ie_len; - pattrib->pktlen += - pmlmepriv->wps_beacon_ie_len; - - /* copy remainder_ie to pframe */ - memcpy(pframe, premainder_ie, - remainder_ielen); - pframe += remainder_ielen; - pattrib->pktlen += remainder_ielen; - } else { - memcpy(pframe, cur_network->IEs, - cur_network->IELength); - pframe += cur_network->IELength; - pattrib->pktlen += - cur_network->IELength; - } - } else { - pframe_wscie = pframe + wps_offset; - memcpy(pframe, cur_network->IEs, - wps_offset + wps_ielen); - pframe += (wps_offset + wps_ielen); - pattrib->pktlen += (wps_offset + wps_ielen); - - /* now pframe is end of wsc ie, insert Primary - Device Type & Device Name */ - /* Primary Device Type */ - /* Type: */ - *(u16*) (pframe + insert_len) = - cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); - insert_len += 2; - - /* Length: */ - *(u16*) (pframe + insert_len) = - cpu_to_be16(0x0008); - insert_len += 2; - - /* Value: */ - /* Category ID */ - *(u16*) (pframe + insert_len) = - cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); - insert_len += 2; - - /* OUI */ - *(u32*) (pframe + insert_len) = - cpu_to_be32(WPSOUI); - insert_len += 4; - - /* Sub Category ID */ - *(u16*) (pframe + insert_len) = - cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); - insert_len += 2; - - /* Device Name */ - /* Type: */ - *(u16*) (pframe + insert_len) = - cpu_to_be16(WPS_ATTR_DEVICE_NAME); - insert_len += 2; - - /* Length: */ - *(u16*) (pframe + insert_len) = - cpu_to_be16(pwdinfo->device_name_len); - insert_len += 2; - - /* Value: */ - memcpy(pframe + insert_len, - pwdinfo->device_name, - pwdinfo->device_name_len); - insert_len += pwdinfo->device_name_len; - - /* update wsc ie length */ - *(pframe_wscie+1) = (wps_ielen -2) + insert_len; - - /* pframe move to end */ - pframe+= insert_len; - pattrib->pktlen += insert_len; - - /* copy remainder_ie to pframe */ - memcpy(pframe, premainder_ie, remainder_ielen); - pframe += remainder_ielen; - pattrib->pktlen += remainder_ielen; - } - } else -#endif /* CONFIG_8723AU_P2P */ - memcpy(pframe, cur_network->IEs, cur_network->IELength); + memcpy(pframe, cur_network->IEs, cur_network->IELength); len_diff = update_hidden_ssid(pframe + _BEACON_IE_OFFSET_, cur_network->IELength - _BEACON_IE_OFFSET_, @@ -5447,36 +2508,6 @@ void issue_beacon23a(struct rtw_adapter *padapter, int timeout_ms) else _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS); -#ifdef CONFIG_8723AU_P2P - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { - u32 len; - if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { - len = pmlmepriv->p2p_beacon_ie_len; - if (pmlmepriv->p2p_beacon_ie && len > 0) - memcpy(pframe, - pmlmepriv->p2p_beacon_ie, len); - } else - len = build_beacon_p2p_ie23a(pwdinfo, pframe); - - pframe += len; - pattrib->pktlen += len; - - if (true == pwdinfo->wfd_info->wfd_enable) { - len = build_beacon_wfd_ie(pwdinfo, pframe); - } else { - len = 0; - if (pmlmepriv->wfd_beacon_ie && - pmlmepriv->wfd_beacon_ie_len>0) { - len = pmlmepriv->wfd_beacon_ie_len; - memcpy(pframe, - pmlmepriv->wfd_beacon_ie, len); - } - } - pframe += len; - pattrib->pktlen += len; - } -#endif /* CONFIG_8723AU_P2P */ - goto _issue_bcn; } @@ -5503,17 +2534,18 @@ void issue_beacon23a(struct rtw_adapter *padapter, int timeout_ms) pattrib->pktlen += 2; /* SSID */ - pframe = rtw_set_ie23a(pframe, _SSID_IE_, cur_network->Ssid.ssid_len, + pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID, + cur_network->Ssid.ssid_len, cur_network->Ssid.ssid, &pattrib->pktlen); /* supported rates... */ rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates); - pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, + pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, ((rate_len > 8)? 8: rate_len), cur_network->SupportedRates, &pattrib->pktlen); /* DS parameter set */ - pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *) + pframe = rtw_set_ie23a(pframe, WLAN_EID_DS_PARAMS, 1, (unsigned char *) &cur_network->Configuration.DSConfig, &pattrib->pktlen); @@ -5524,18 +2556,18 @@ void issue_beacon23a(struct rtw_adapter *padapter, int timeout_ms) /* IBSS Parameter Set... */ /* ATIMWindow = cur->Configuration.ATIMWindow; */ ATIMWindow = 0; - pframe = rtw_set_ie23a(pframe, _IBSS_PARA_IE_, 2, + pframe = rtw_set_ie23a(pframe, WLAN_EID_IBSS_PARAMS, 2, (unsigned char *)&ATIMWindow, &pattrib->pktlen); /* ERP IE */ - pframe = rtw_set_ie23a(pframe, _ERPINFO_IE_, 1, + pframe = rtw_set_ie23a(pframe, WLAN_EID_ERP_INFO, 1, &erpinfo, &pattrib->pktlen); } /* EXTERNDED SUPPORTED RATE */ if (rate_len > 8) - pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, + pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES, rate_len - 8, cur_network->SupportedRates + 8, &pattrib->pktlen); @@ -5571,7 +2603,7 @@ void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, struct pkt_attrib *pattrib; unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; + __le16 *fctrl; unsigned char *mac, *bssid; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; #ifdef CONFIG_8723AU_AP_MODE @@ -5582,22 +2614,17 @@ void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, int ssid_ielen_diff; u8 buf[MAX_IE_SZ]; u8 *ies; -#endif -#if defined(CONFIG_8723AU_AP_MODE) || defined(CONFIG_8723AU_P2P) struct mlme_priv *pmlmepriv = &padapter->mlmepriv; #endif struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; unsigned int rate_len; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif /* CONFIG_8723AU_P2P */ /* DBG_8723A("%s\n", __func__); */ - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - { + pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); + if (!pmgntframe) { DBG_8723A("%s, alloc mgnt frame fail\n", __func__); return; } @@ -5608,7 +2635,7 @@ void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pframe = (u8 *)pmgntframe->buf_addr + TXDESC_OFFSET; pwlanhdr = (struct ieee80211_hdr *)pframe; mac = myid(&padapter->eeprompriv); @@ -5640,8 +2667,7 @@ void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, &wps_ielen); /* inerset & update wps_probe_resp_ie */ - if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie && - (wps_ielen > 0)) { + if (pmlmepriv->wps_probe_resp_ie && pwps_ie && wps_ielen > 0) { uint wps_offset, remainder_ielen; u8 *premainder_ie; @@ -5658,14 +2684,14 @@ void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, /* to get ie data len */ wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1]; - if ((wps_offset+wps_ielen+2)<= MAX_IE_SZ) { + if (wps_offset + wps_ielen + 2 <= MAX_IE_SZ) { memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen+2); pframe += wps_ielen+2; pattrib->pktlen += wps_ielen+2; } - if ((wps_offset+wps_ielen+2+remainder_ielen) <= + if (wps_offset + wps_ielen + 2 + remainder_ielen <= MAX_IE_SZ) { memcpy(pframe, premainder_ie, remainder_ielen); pframe += remainder_ielen; @@ -5681,9 +2707,9 @@ void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, ies = pmgntframe->buf_addr + TXDESC_OFFSET + sizeof(struct ieee80211_hdr_3addr); - ssid_ie = rtw_get_ie23a(ies+_FIXED_IE_LENGTH_, _SSID_IE_, + ssid_ie = rtw_get_ie23a(ies + _FIXED_IE_LENGTH_, WLAN_EID_SSID, &ssid_ielen, - (pframe-ies)-_FIXED_IE_LENGTH_); + pframe - ies - _FIXED_IE_LENGTH_); ssid_ielen_diff = cur_network->Ssid.ssid_len - ssid_ielen; @@ -5691,20 +2717,19 @@ void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, uint remainder_ielen; u8 *remainder_ie; remainder_ie = ssid_ie + 2; - remainder_ielen = (pframe-remainder_ie); + remainder_ielen = pframe - remainder_ie; DBG_8723A_LEVEL(_drv_warning_, FUNC_ADPT_FMT " remainder_ielen > MAX_IE_SZ\n", FUNC_ADPT_ARG(padapter)); - if (remainder_ielen > MAX_IE_SZ) { + if (remainder_ielen > MAX_IE_SZ) remainder_ielen = MAX_IE_SZ; - } memcpy(buf, remainder_ie, remainder_ielen); - memcpy(remainder_ie+ssid_ielen_diff, buf, + memcpy(remainder_ie + ssid_ielen_diff, buf, remainder_ielen); - *(ssid_ie+1) = cur_network->Ssid.ssid_len; - memcpy(ssid_ie+2, cur_network->Ssid.ssid, + *(ssid_ie + 1) = cur_network->Ssid.ssid_len; + memcpy(ssid_ie + 2, cur_network->Ssid.ssid, cur_network->Ssid.ssid_len); pframe += ssid_ielen_diff; @@ -5737,40 +2762,42 @@ void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, /* below for ad-hoc mode */ /* SSID */ - pframe = rtw_set_ie23a(pframe, _SSID_IE_, - cur_network->Ssid.ssid_len, - cur_network->Ssid.ssid, &pattrib->pktlen); + pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID, + cur_network->Ssid.ssid_len, + cur_network->Ssid.ssid, + &pattrib->pktlen); /* supported rates... */ rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates); - pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, + pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, ((rate_len > 8)? 8: rate_len), cur_network->SupportedRates, &pattrib->pktlen); /* DS parameter set */ - pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *) + pframe = rtw_set_ie23a(pframe, WLAN_EID_DS_PARAMS, 1, + (unsigned char *) &cur_network->Configuration.DSConfig, &pattrib->pktlen); - if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { + if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { u8 erpinfo = 0; u32 ATIMWindow; /* IBSS Parameter Set... */ /* ATIMWindow = cur->Configuration.ATIMWindow; */ ATIMWindow = 0; - pframe = rtw_set_ie23a(pframe, _IBSS_PARA_IE_, 2, + pframe = rtw_set_ie23a(pframe, WLAN_EID_IBSS_PARAMS, 2, (unsigned char *)&ATIMWindow, &pattrib->pktlen); /* ERP IE */ - pframe = rtw_set_ie23a(pframe, _ERPINFO_IE_, 1, + pframe = rtw_set_ie23a(pframe, WLAN_EID_ERP_INFO, 1, &erpinfo, &pattrib->pktlen); } /* EXTERNDED SUPPORTED RATE */ if (rate_len > 8) - pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, + pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES, rate_len - 8, cur_network->SupportedRates + 8, &pattrib->pktlen); @@ -5778,38 +2805,6 @@ void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, /* todo:HT for adhoc */ } -#ifdef CONFIG_8723AU_P2P - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && is_valid_p2p_probereq) { - u32 len; - if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { - /* if pwdinfo->role == P2P_ROLE_DEVICE will call - issue_probersp23a_p2p23a() */ - len = pmlmepriv->p2p_go_probe_resp_ie_len; - if (pmlmepriv->p2p_go_probe_resp_ie && len>0) - memcpy(pframe, pmlmepriv->p2p_go_probe_resp_ie, - len); - } else - len = build_probe_resp_p2p_ie23a(pwdinfo, pframe); - - pframe += len; - pattrib->pktlen += len; - - if (true == pwdinfo->wfd_info->wfd_enable) { - len = build_probe_resp_wfd_ie(pwdinfo, pframe, 0); - } else { - len = 0; - if (pmlmepriv->wfd_probe_resp_ie && - pmlmepriv->wfd_probe_resp_ie_len > 0) { - len = pmlmepriv->wfd_probe_resp_ie_len; - memcpy(pframe, pmlmepriv->wfd_probe_resp_ie, - len); - } - } - pframe += len; - pattrib->pktlen += len; - } -#endif /* CONFIG_8723AU_P2P */ - pattrib->last_txcmdsz = pattrib->pktlen; dump_mgntframe23a(padapter, pmgntframe); @@ -5825,7 +2820,7 @@ static int _issue_probereq23a(struct rtw_adapter *padapter, struct pkt_attrib *pattrib; unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; + __le16 *fctrl; unsigned char *mac; unsigned char bssrate[NumRates]; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; @@ -5851,7 +2846,7 @@ static int _issue_probereq23a(struct rtw_adapter *padapter, mac = myid(&padapter->eeprompriv); - fctrl = &pwlanhdr->frame_control; + fctrl = &pwlanhdr->frame_control; *fctrl = 0; if (da) { @@ -5874,22 +2869,22 @@ static int _issue_probereq23a(struct rtw_adapter *padapter, pattrib->pktlen = sizeof (struct ieee80211_hdr_3addr); if (pssid) - pframe = rtw_set_ie23a(pframe, _SSID_IE_, pssid->ssid_len, + pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID, pssid->ssid_len, pssid->ssid, &pattrib->pktlen); else - pframe = rtw_set_ie23a(pframe, _SSID_IE_, 0, NULL, + pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID, 0, NULL, &pattrib->pktlen); get_rate_set23a(padapter, bssrate, &bssrate_len); if (bssrate_len > 8) { - pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8, + pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, 8, bssrate, &pattrib->pktlen); - pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, + pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES, (bssrate_len - 8), (bssrate + 8), &pattrib->pktlen); } else { - pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, + pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, bssrate_len, bssrate, &pattrib->pktlen); } @@ -5976,7 +2971,7 @@ void issue_auth23a(struct rtw_adapter *padapter, struct sta_info *psta, struct pkt_attrib *pattrib; unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; + __le16 *fctrl; unsigned int val32; unsigned short val16; int use_shared_key = 0; @@ -6045,7 +3040,7 @@ void issue_auth23a(struct rtw_adapter *padapter, struct sta_info *psta, /* added challenging text... */ if ((psta->auth_seq == 2) && (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) - pframe = rtw_set_ie23a(pframe, _CHLGETXT_IE_, 128, + pframe = rtw_set_ie23a(pframe, WLAN_EID_CHALLENGE, 128, psta->chg_txt, &pattrib->pktlen); #endif } else { @@ -6104,7 +3099,7 @@ void issue_auth23a(struct rtw_adapter *padapter, struct sta_info *psta, if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { - pframe = rtw_set_ie23a(pframe, _CHLGETXT_IE_, 128, + pframe = rtw_set_ie23a(pframe, WLAN_EID_CHALLENGE, 128, pmlmeinfo->chg_txt, &pattrib->pktlen); @@ -6136,22 +3131,20 @@ void issue_asocrsp23a(struct rtw_adapter *padapter, unsigned short status, struct xmit_frame *pmgntframe; struct ieee80211_hdr *pwlanhdr; struct pkt_attrib *pattrib; - unsigned char *pbuf, *pframe; + unsigned char *pframe; unsigned short val; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; + const u8 *p; u8 *ie = pnetwork->IEs; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u32 wfdielen = 0; -#endif /* CONFIG_8723AU_P2P */ DBG_8723A("%s\n", __func__); - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); + if (!pmgntframe) return; /* update attribute */ @@ -6171,7 +3164,7 @@ void issue_asocrsp23a(struct rtw_adapter *padapter, unsigned short status, SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); pmlmeext->mgnt_seq++; - if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP)) + if (pkt_type == WIFI_ASSOCRSP || pkt_type == WIFI_REASSOCRSP) SetFrameSubType(pwlanhdr, pkt_type); else return; @@ -6196,69 +3189,70 @@ void issue_asocrsp23a(struct rtw_adapter *padapter, unsigned short status, &pattrib->pktlen); if (pstat->bssratelen <= 8) { - pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, + pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, pstat->bssratelen, pstat->bssrateset, &pattrib->pktlen); } else { - pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8, + pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, 8, pstat->bssrateset, &pattrib->pktlen); - pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, + pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES, pstat->bssratelen - 8, pstat->bssrateset + 8, &pattrib->pktlen); } - if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) { - uint ie_len = 0; - + if (pstat->flags & WLAN_STA_HT && pmlmepriv->htpriv.ht_option) { /* FILL HT CAP INFO IE */ /* p = hostapd_eid_ht_capabilities_info(hapd, p); */ - pbuf = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, - _HT_CAPABILITY_IE_, &ie_len, - pnetwork->IELength - _BEACON_IE_OFFSET_); - if (pbuf && ie_len>0) { - memcpy(pframe, pbuf, ie_len + 2); - pframe += (ie_len + 2); - pattrib->pktlen += (ie_len + 2); + p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, + ie + _BEACON_IE_OFFSET_, + pnetwork->IELength -_BEACON_IE_OFFSET_); + if (p && p[1]) { + memcpy(pframe, p, p[1] + 2); + pframe += (p[1] + 2); + pattrib->pktlen += (p[1] + 2); } /* FILL HT ADD INFO IE */ /* p = hostapd_eid_ht_operation(hapd, p); */ - pbuf = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, - &ie_len, + p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, + ie + _BEACON_IE_OFFSET_, pnetwork->IELength - _BEACON_IE_OFFSET_); - if (pbuf && ie_len > 0) { - memcpy(pframe, pbuf, ie_len + 2); - pframe += (ie_len + 2); - pattrib->pktlen += (ie_len + 2); + if (p && p[1] > 0) { + memcpy(pframe, p, p[1] + 2); + pframe += (p[1] + 2); + pattrib->pktlen += (p[1] + 2); } } /* FILL WMM IE */ - if ((pstat->flags & WLAN_STA_WME) && pmlmepriv->qospriv.qos_option) { - uint ie_len = 0; + if (pstat->flags & WLAN_STA_WME && pmlmepriv->qospriv.qos_option) { unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; - - for (pbuf = ie + _BEACON_IE_OFFSET_; ; pbuf += (ie_len + 2)) { - pbuf = rtw_get_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, - &ie_len, (pnetwork->IELength - - _BEACON_IE_OFFSET_ - - (ie_len + 2))); - if (pbuf && !memcmp(pbuf + 2, WMM_PARA_IE, 6)) { - memcpy(pframe, pbuf, ie_len + 2); + int ie_len = 0; + + for (p = ie + _BEACON_IE_OFFSET_; ; p += (ie_len + 2)) { + p = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, p, + pnetwork->IELength - + _BEACON_IE_OFFSET_ - (ie_len + 2)); + if (p) + ie_len = p[1]; + else + ie_len = 0; + if (p && !memcmp(p + 2, WMM_PARA_IE, 6)) { + memcpy(pframe, p, ie_len + 2); pframe += (ie_len + 2); pattrib->pktlen += (ie_len + 2); break; } - if ((!pbuf) || (ie_len == 0)) + if (!p || ie_len == 0) break; } } if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) { - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, 6, + pframe = rtw_set_ie23a(pframe, WLAN_EID_VENDOR_SPECIFIC, 6, REALTEK_96B_IE23A, &pattrib->pktlen); } @@ -6272,15 +3266,6 @@ void issue_asocrsp23a(struct rtw_adapter *padapter, unsigned short status, pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len; } -#ifdef CONFIG_8723AU_P2P - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && - pwdinfo->wfd_info->wfd_enable) { - wfdielen = build_assoc_resp_wfd_ie(pwdinfo, pframe); - pframe += wfdielen; - pattrib->pktlen += wfdielen; - } -#endif /* CONFIG_8723AU_P2P */ - pattrib->last_txcmdsz = pattrib->pktlen; dump_mgntframe23a(padapter, pmgntframe); @@ -6292,11 +3277,11 @@ void issue_assocreq23a(struct rtw_adapter *padapter) int ret = _FAIL; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - unsigned char *pframe, *p; + unsigned char *pframe; + const u8 *p; struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - unsigned short val16; - unsigned int i, j, ie_len, index = 0; + __le16 *fctrl; + unsigned int i, j, index = 0; unsigned char rf_type, bssrate[NumRates], sta_bssrate[NumRates]; struct ndis_802_11_var_ies *pIE; struct registry_priv *pregpriv = &padapter->registrypriv; @@ -6304,15 +3289,11 @@ void issue_assocreq23a(struct rtw_adapter *padapter) struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - int bssrate_len = 0, sta_bssrate_len = 0; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 p2pie[255] = { 0x00 }; - u16 p2pielen = 0; - u32 wfdielen = 0; -#endif /* CONFIG_8723AU_P2P */ + int bssrate_len = 0, sta_bssrate_len = 0, pie_len; + u8 * pie; - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); + if (!pmgntframe) goto exit; /* update attribute */ @@ -6321,7 +3302,7 @@ void issue_assocreq23a(struct rtw_adapter *padapter) memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pframe = (u8 *)pmgntframe->buf_addr + TXDESC_OFFSET; pwlanhdr = (struct ieee80211_hdr *)pframe; fctrl = &pwlanhdr->frame_control; @@ -6338,21 +3319,20 @@ void issue_assocreq23a(struct rtw_adapter *padapter) pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); /* caps */ - memcpy(pframe, rtw_get_capability23a_from_ie(pmlmeinfo->network.IEs), - 2); + memcpy(pframe, + rtw_get_capability23a_from_ie(pmlmeinfo->network.IEs), 2); pframe += 2; pattrib->pktlen += 2; /* listen interval */ /* todo: listen interval for power saving */ - val16 = cpu_to_le16(3); - memcpy(pframe, (unsigned char *)&val16, 2); + put_unaligned_le16(3, pframe); pframe += 2; pattrib->pktlen += 2; /* SSID */ - pframe = rtw_set_ie23a(pframe, _SSID_IE_, + pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID, pmlmeinfo->network.Ssid.ssid_len, pmlmeinfo->network.Ssid.ssid, &pattrib->pktlen); @@ -6387,7 +3367,7 @@ void issue_assocreq23a(struct rtw_adapter *padapter) Handlink WSG-4000 AP */ if ((pmlmeinfo->network.SupportedRates[i] | IEEE80211_BASIC_RATE_MASK) == - (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)) { + (sta_bssrate[j] | IEEE80211_BASIC_RATE_MASK)) { /* DBG_8723A("match i = %d, j =%d\n", i, j); */ break; } @@ -6414,33 +3394,31 @@ void issue_assocreq23a(struct rtw_adapter *padapter) } if (bssrate_len > 8) { - pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8, + pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, 8, bssrate, &pattrib->pktlen); - pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, + pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES, (bssrate_len - 8), (bssrate + 8), &pattrib->pktlen); } else - pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, + pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, bssrate_len, bssrate, &pattrib->pktlen); /* RSN */ - p = rtw_get_ie23a((pmlmeinfo->network.IEs + - sizeof(struct ndis_802_11_fixed_ies)), _RSN_IE_2_, - &ie_len, (pmlmeinfo->network.IELength - - sizeof(struct ndis_802_11_fixed_ies))); + pie = pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ies); + pie_len = pmlmeinfo->network.IELength - + sizeof(struct ndis_802_11_fixed_ies); + + p = cfg80211_find_ie(WLAN_EID_RSN, pie, pie_len); if (p) - pframe = rtw_set_ie23a(pframe, _RSN_IE_2_, ie_len, (p + 2), + pframe = rtw_set_ie23a(pframe, WLAN_EID_RSN, p[1], p + 2, &pattrib->pktlen); /* HT caps */ if (padapter->mlmepriv.htpriv.ht_option == true) { - p = rtw_get_ie23a((pmlmeinfo->network.IEs + - sizeof(struct ndis_802_11_fixed_ies)), - _HT_CAPABILITY_IE_, &ie_len, - (pmlmeinfo->network.IELength - - sizeof(struct ndis_802_11_fixed_ies))); - if ((p != NULL) && (!(is_ap_in_tkip23a(padapter)))) { - memcpy(&pmlmeinfo->HT_caps, (p + 2), + p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, pie, pie_len); + + if (p && !is_ap_in_tkip23a(padapter)) { + memcpy(&pmlmeinfo->HT_caps, p + 2, sizeof(struct HT_caps_element)); /* to disable 40M Hz support while gd_bw_40MHz_en = 0 */ @@ -6454,15 +3432,13 @@ void issue_assocreq23a(struct rtw_adapter *padapter) pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= 0x000c; - rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, - (u8 *)(&rf_type)); + rf_type = rtl8723a_get_rf_type(padapter); /* switch (pregpriv->rf_config) */ - switch (rf_type) - { + switch (rf_type) { case RF_1T1R: - + /* RX STBC One spatial stream */ if (pregpriv->rx_stbc) - pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0100);/* RX STBC One spatial stream */ + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0100); memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_1R23A, 16); break; @@ -6470,18 +3446,17 @@ void issue_assocreq23a(struct rtw_adapter *padapter) case RF_2T2R: case RF_1T2R: default: - /* enable for 2.4/5 GHz */ - if ((pregpriv->rx_stbc == 0x3) || - ((pmlmeext->cur_wireless_mode & - WIRELESS_11_24N) && + if (pregpriv->rx_stbc == 0x3 || + (pmlmeext->cur_wireless_mode & + WIRELESS_11_24N && /* enable for 2.4GHz */ - (pregpriv->rx_stbc == 0x1)) || - ((pmlmeext->cur_wireless_mode & - WIRELESS_11_5N) && - (pregpriv->rx_stbc == 0x2)) || + pregpriv->rx_stbc == 0x1) || + (pmlmeext->cur_wireless_mode & + WIRELESS_11_5N && + pregpriv->rx_stbc == 0x2) || /* enable for 5GHz */ - (pregpriv->wifi_spec == 1)) { + pregpriv->wifi_spec == 1) { DBG_8723A("declare supporting RX " "STBC\n"); pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0200);/* RX STBC two spatial stream */ @@ -6500,9 +3475,8 @@ void issue_assocreq23a(struct rtw_adapter *padapter) } #endif - pframe = rtw_set_ie23a(pframe, _HT_CAPABILITY_IE_, - ie_len, - (u8 *)&pmlmeinfo->HT_caps, + pframe = rtw_set_ie23a(pframe, WLAN_EID_HT_CAPABILITY, + p[1], (u8 *)&pmlmeinfo->HT_caps, &pattrib->pktlen); } } @@ -6515,8 +3489,8 @@ void issue_assocreq23a(struct rtw_adapter *padapter) switch (pIE->ElementID) { - case _VENDOR_SPECIFIC_IE_: - if (!memcmp(pIE->data, RTW_WPA_OUI23A, 4) || + case WLAN_EID_VENDOR_SPECIFIC: + if (!memcmp(pIE->data, RTW_WPA_OUI23A_TYPE, 4) || !memcmp(pIE->data, WMM_OUI23A, 4) || !memcmp(pIE->data, WPS_OUI23A, 4)) { if (!padapter->registrypriv.wifi_spec) { @@ -6528,7 +3502,7 @@ void issue_assocreq23a(struct rtw_adapter *padapter) pIE->Length = 14; } pframe = rtw_set_ie23a(pframe, - _VENDOR_SPECIFIC_IE_, + WLAN_EID_VENDOR_SPECIFIC, pIE->Length, pIE->data, &pattrib->pktlen); } @@ -6538,198 +3512,13 @@ void issue_assocreq23a(struct rtw_adapter *padapter) break; } - i += (pIE->Length + 2); + i += pIE->Length + 2; } if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, 6, + pframe = rtw_set_ie23a(pframe, WLAN_EID_VENDOR_SPECIFIC, 6, REALTEK_96B_IE23A, &pattrib->pktlen); -#ifdef CONFIG_8723AU_P2P - - if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { - if (pmlmepriv->p2p_assoc_req_ie && - pmlmepriv->p2p_assoc_req_ie_len>0) { - memcpy(pframe, pmlmepriv->p2p_assoc_req_ie, - pmlmepriv->p2p_assoc_req_ie_len); - pframe += pmlmepriv->p2p_assoc_req_ie_len; - pattrib->pktlen += pmlmepriv->p2p_assoc_req_ie_len; - } - } else { - if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && - !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) { - /* Should add the P2P IE in the association - request frame. */ - /* P2P OUI */ - - p2pielen = 0; - p2pie[p2pielen++] = 0x50; - p2pie[p2pielen++] = 0x6F; - p2pie[p2pielen++] = 0x9A; - p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ - - /* Commented by Albert 20101109 */ - /* According to the P2P Specification, the - association request frame should contain - 3 P2P attributes */ - /* 1. P2P Capability */ - /* 2. Extended Listen Timing */ - /* 3. Device Info */ - /* Commented by Albert 20110516 */ - /* 4. P2P Interface */ - - /* P2P Capability */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); - p2pielen += 2; - - /* Value: */ - /* Device Capability Bitmap, 1 byte */ - p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; - - /* Group Capability Bitmap, 1 byte */ - if (pwdinfo->persistent_supported) - p2pie[p2pielen++] = - P2P_GRPCAP_PERSISTENT_GROUP | - DMP_P2P_GRPCAP_SUPPORT; - else - p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; - - /* Extended Listen Timing */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); - p2pielen += 2; - - /* Value: */ - /* Availability Period */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); - p2pielen += 2; - - /* Availability Interval */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); - p2pielen += 2; - - /* Device Info */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; - - /* Length: */ - /* 21 -> P2P Device Address (6bytes) + Config - Methods (2bytes) + Primary Device - Type (8bytes) */ - /* + NumofSecondDevType (1byte) + WPS Device - Name ID field (2bytes) + WPS Device Name - Len field (2bytes) */ - *(u16*) (p2pie + p2pielen) = - cpu_to_le16(21 + pwdinfo->device_name_len); - p2pielen += 2; - - /* Value: */ - /* P2P Device Address */ - memcpy(p2pie + p2pielen, - myid(&padapter->eeprompriv), ETH_ALEN); - p2pielen += ETH_ALEN; - - /* Config Method */ - /* This field should be big endian. - Noted by P2P specification. */ - if ((pwdinfo->ui_got_wps_info == - P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) || - (pwdinfo->ui_got_wps_info == - P2P_GOT_WPSINFO_SELF_DISPLAY_PIN)) - *(u16*) (p2pie + p2pielen) = - cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); - else - *(u16*) (p2pie + p2pielen) = - cpu_to_be16(WPS_CONFIG_METHOD_PBC); - - p2pielen += 2; - - /* Primary Device Type */ - /* Category ID */ - *(u16*) (p2pie + p2pielen) = - cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); - p2pielen += 2; - - /* OUI */ - *(u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); - p2pielen += 4; - - /* Sub Category ID */ - *(u16*) (p2pie + p2pielen) = - cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); - p2pielen += 2; - - /* Number of Secondary Device Types */ - /* No Secondary Device Type List */ - p2pie[p2pielen++] = 0x00; - - /* Device Name */ - /* Type: */ - *(u16*) (p2pie + p2pielen) = - cpu_to_be16(WPS_ATTR_DEVICE_NAME); - p2pielen += 2; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = - cpu_to_be16(pwdinfo->device_name_len); - p2pielen += 2; - - /* Value: */ - memcpy(p2pie + p2pielen, pwdinfo->device_name, - pwdinfo->device_name_len); - p2pielen += pwdinfo->device_name_len; - - /* P2P Interface */ - /* Type: */ - p2pie[p2pielen++] = P2P_ATTR_INTERFACE; - - /* Length: */ - *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x000D); - p2pielen += 2; - - /* Value: */ - memcpy(p2pie + p2pielen, pwdinfo->device_addr, - ETH_ALEN); /* P2P Device Address */ - p2pielen += ETH_ALEN; - - /* P2P Interface Address Count */ - p2pie[p2pielen++] = 1; - - memcpy(p2pie + p2pielen, pwdinfo->device_addr, - ETH_ALEN); /* P2P Interface Address List */ - p2pielen += ETH_ALEN; - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, - p2pielen, (unsigned char *)p2pie, - &pattrib->pktlen); - - /* wfdielen = build_assoc_req_wfd_ie(pwdinfo, pframe);*/ - /* pframe += wfdielen; */ - /* pattrib->pktlen += wfdielen; */ - } - } - - if (true == pwdinfo->wfd_info->wfd_enable) { - wfdielen = build_assoc_req_wfd_ie(pwdinfo, pframe); - pframe += wfdielen; - pattrib->pktlen += wfdielen; - } else if (pmlmepriv->wfd_assoc_req_ie != NULL && - pmlmepriv->wfd_assoc_req_ie_len > 0) { - /* WFD IE */ - memcpy(pframe, pmlmepriv->wfd_assoc_req_ie, - pmlmepriv->wfd_assoc_req_ie_len); - pattrib->pktlen += pmlmepriv->wfd_assoc_req_ie_len; - pframe += pmlmepriv->wfd_assoc_req_ie_len; - } -#endif /* CONFIG_8723AU_P2P */ - pattrib->last_txcmdsz = pattrib->pktlen; dump_mgntframe23a(padapter, pmgntframe); @@ -6741,8 +3530,7 @@ void issue_assocreq23a(struct rtw_adapter *padapter) kfree(pmlmepriv->assoc_req); pmlmepriv->assoc_req = kmalloc(pattrib->pktlen, GFP_ATOMIC); if (pmlmepriv->assoc_req) { - memcpy(pmlmepriv->assoc_req, pwlanhdr, - pattrib->pktlen); + memcpy(pmlmepriv->assoc_req, pwlanhdr, pattrib->pktlen); pmlmepriv->assoc_req_len = pattrib->pktlen; } } else @@ -6760,7 +3548,7 @@ static int _issue_nulldata23a(struct rtw_adapter *padapter, unsigned char *da, struct pkt_attrib *pattrib; unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; + __le16 *fctrl; struct xmit_priv *pxmitpriv; struct mlme_ext_priv *pmlmeext; struct mlme_ext_info *pmlmeinfo; @@ -6883,7 +3671,8 @@ static int _issue_qos_nulldata23a(struct rtw_adapter *padapter, struct pkt_attrib *pattrib; unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl, *qc; + __le16 *fctrl; + u16 *qc; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -7009,25 +3798,14 @@ static int _issue_deauth23a(struct rtw_adapter *padapter, unsigned char *da, struct pkt_attrib *pattrib; unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; + __le16 *fctrl; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; int ret = _FAIL; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif /* CONFIG_8723AU_P2P */ /* DBG_8723A("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); */ -#ifdef CONFIG_8723AU_P2P - if (!(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) && - (pwdinfo->rx_invitereq_info.scan_op_ch_only)) { - mod_timer(&pwdinfo->reset_ch_sitesurvey, - jiffies + msecs_to_jiffies(10)); - } -#endif /* CONFIG_8723AU_P2P */ - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) goto exit; @@ -7131,7 +3909,7 @@ void issue_action_spct_ch_switch23a(struct rtw_adapter *padapter, struct pkt_attrib *pattrib; unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; + __le16 *fctrl; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; u8 category, action; @@ -7183,7 +3961,8 @@ void issue_action_spct_ch_switch23a(struct rtw_adapter *padapter, dump_mgntframe23a(padapter, pmgntframe); } -void issue_action_BA23a(struct rtw_adapter *padapter, unsigned char *raddr, +void issue_action_BA23a(struct rtw_adapter *padapter, + const unsigned char *raddr, unsigned char action, unsigned short status) { u8 category = WLAN_CATEGORY_BACK; @@ -7197,7 +3976,7 @@ void issue_action_BA23a(struct rtw_adapter *padapter, unsigned char *raddr, struct pkt_attrib *pattrib; u8 *pframe; struct ieee80211_hdr *pwlanhdr; - u16 *fctrl; + __le16 *fctrl; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -7373,24 +4152,26 @@ static void issue_action_BSSCoexistPacket(struct rtw_adapter *padapter) { struct list_head *plist, *phead, *ptmp; unsigned char category, action; - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - struct wlan_network *pnetwork = NULL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + u8 *pframe; + struct ieee80211_hdr *pwlanhdr; + __le16 *fctrl; + struct wlan_network *pnetwork; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - struct rtw_queue *queue = &pmlmepriv->scanned_queue; + struct rtw_queue *queue = &pmlmepriv->scanned_queue; u8 InfoContent[16] = {0}; u8 ICS[8][15]; + int i; - if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0)) + if (pmlmepriv->num_FortyMHzIntolerant == 0 || + pmlmepriv->num_sta_no_ht == 0) return; - if (true == pmlmeinfo->bwmode_updated) + if (pmlmeinfo->bwmode_updated) return; DBG_8723A("%s\n", __func__); @@ -7398,10 +4179,9 @@ static void issue_action_BSSCoexistPacket(struct rtw_adapter *padapter) category = WLAN_CATEGORY_PUBLIC; action = ACT_PUBLIC_BSSCOEXIST; - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - { + pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); + if (!pmgntframe) return; - } /* update attribute */ pattrib = &pmgntframe->attrib; @@ -7409,7 +4189,7 @@ static void issue_action_BSSCoexistPacket(struct rtw_adapter *padapter) memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pframe = (u8 *)pmgntframe->buf_addr + TXDESC_OFFSET; pwlanhdr = (struct ieee80211_hdr *)pframe; fctrl = &pwlanhdr->frame_control; @@ -7429,85 +4209,74 @@ static void issue_action_BSSCoexistPacket(struct rtw_adapter *padapter) pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); - /* */ - if (pmlmepriv->num_FortyMHzIntolerant>0) - { - u8 iedata = 0; - - iedata |= BIT(2);/* 20 MHz BSS Width Request */ - - pframe = rtw_set_ie23a(pframe, EID_BSSCoexistence, 1, &iedata, &pattrib->pktlen); + if (pmlmepriv->num_FortyMHzIntolerant > 0) { + u8 iedata = BIT(2);/* 20 MHz BSS Width Request */ + pframe = rtw_set_ie23a(pframe, WLAN_EID_BSS_COEX_2040, 1, + &iedata, &pattrib->pktlen); } - /* */ - memset(ICS, 0, sizeof(ICS)); - if (pmlmepriv->num_sta_no_ht>0) - { - int i; + if (pmlmepriv->num_sta_no_ht <= 0) + goto out; - spin_lock_bh(&pmlmepriv->scanned_queue.lock); + memset(ICS, 0, sizeof(ICS)); - phead = get_list_head(queue); - plist = phead->next; + spin_lock_bh(&pmlmepriv->scanned_queue.lock); - list_for_each_safe(plist, ptmp, phead) { - int len; - u8 *p; - struct wlan_bssid_ex *pbss_network; + phead = get_list_head(queue); + plist = phead->next; - pnetwork = container_of(plist, struct wlan_network, - list); + list_for_each_safe(plist, ptmp, phead) { + const u8 *p; + struct wlan_bssid_ex *pbss_network; - pbss_network = &pnetwork->network; + pnetwork = container_of(plist, struct wlan_network, list); - p = rtw_get_ie23a(pbss_network->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pbss_network->IELength - _FIXED_IE_LENGTH_); - if ((p == NULL) || (len == 0))/* non-HT */ - { - if ((pbss_network->Configuration.DSConfig<= 0) || (pbss_network->Configuration.DSConfig>14)) - continue; + pbss_network = &pnetwork->network; - ICS[0][pbss_network->Configuration.DSConfig]= 1; + p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, + pbss_network->IEs + _FIXED_IE_LENGTH_, + pbss_network->IELength -_FIXED_IE_LENGTH_); + if (!p || !p[1]) { /* non-HT */ + if (pbss_network->Configuration.DSConfig <= 0 || + pbss_network->Configuration.DSConfig > 14) + continue; - if (ICS[0][0] == 0) - ICS[0][0] = 1; - } + ICS[0][pbss_network->Configuration.DSConfig] = 1; + if (ICS[0][0] == 0) + ICS[0][0] = 1; } - spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + } - for (i = 0;i<8;i++) - { - if (ICS[i][0] == 1) - { - int j, k = 0; + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); - InfoContent[k] = i; - /* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent, i); */ - k++; + for (i = 0; i < 8;i++) { + if (ICS[i][0] == 1) { + int j, k = 0; - for (j = 1;j<= 14;j++) - { - if (ICS[i][j]== 1) - { - if (k<16) - { - InfoContent[k] = j; /* channel number */ - /* SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); */ - k++; - } + InfoContent[k] = i; + /* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent, i); */ + k++; + + for (j = 1; j <= 14; j++) { + if (ICS[i][j] == 1) { + if (k < 16) { + /* channel number */ + InfoContent[k] = j; + k++; } } - - pframe = rtw_set_ie23a(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &pattrib->pktlen); - } + pframe = rtw_set_ie23a(pframe, + EID_BSSIntolerantChlReport, k, + InfoContent, &pattrib->pktlen); } - } +out: pattrib->last_txcmdsz = pattrib->pktlen; dump_mgntframe23a(padapter, pmgntframe); @@ -7555,21 +4324,21 @@ unsigned int send_delba23a(struct rtw_adapter *padapter, u8 initiator, u8 *addr) unsigned int send_beacon23a(struct rtw_adapter *padapter) { - u8 bxmitok = false; + bool bxmitok; int issue = 0; int poll = 0; unsigned long start = jiffies; unsigned int passing_time; - rtw_hal_set_hwreg23a(padapter, HW_VAR_BCN_VALID, NULL); + rtl8723a_bcn_valid(padapter); do { issue_beacon23a(padapter, 100); issue++; do { yield(); - rtw23a_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok)); + bxmitok = rtl8723a_get_bcn_valid(padapter); poll++; - } while ((poll%10)!= 0 && false == bxmitok && + } while ((poll % 10) != 0 && bxmitok == false && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); @@ -7615,46 +4384,22 @@ bool IsLegal5GChannel(struct rtw_adapter *Adapter, u8 channel) void site_survey23a(struct rtw_adapter *padapter) { - unsigned char survey_channel = 0, val8; + unsigned char survey_channel = 0; enum rt_scan_type ScanType = SCAN_PASSIVE; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - u32 initialgain = 0; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - - if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || - (pwdinfo->p2p_info.scan_op_ch_only)) { - if (pwdinfo->rx_invitereq_info.scan_op_ch_only) - survey_channel = pwdinfo->rx_invitereq_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx]; - else - survey_channel = pwdinfo->p2p_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx]; - ScanType = SCAN_ACTIVE; - } else if (rtw_p2p_findphase_ex_is_social(pwdinfo)) { - /* The driver is in the find phase, it should go through the social channel. */ - int ch_set_idx; - survey_channel = pwdinfo->social_chan[pmlmeext->sitesurvey_res.channel_idx]; - ch_set_idx = rtw_ch_set_search_ch23a(pmlmeext->channel_set, survey_channel); - if (ch_set_idx >= 0) - ScanType = pmlmeext->channel_set[ch_set_idx].ScanType; - else - ScanType = SCAN_ACTIVE; - } else -#endif /* CONFIG_8723AU_P2P */ - { - struct rtw_ieee80211_channel *ch; - if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) { - ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx]; - survey_channel = ch->hw_value; - ScanType = (ch->flags & IEEE80211_CHAN_NO_IR) ? SCAN_PASSIVE : SCAN_ACTIVE; -} + struct rtw_ieee80211_channel *ch; + + if (pmlmeext->sitesurvey_res.channel_idx < + pmlmeext->sitesurvey_res.ch_num) { + ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx]; + survey_channel = ch->hw_value; + ScanType = (ch->flags & IEEE80211_CHAN_NO_IR) ? + SCAN_PASSIVE : SCAN_ACTIVE; } if (survey_channel != 0) { /* PAUSE 4-AC Queue when site_survey23a */ - /* rtw23a_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ - /* val8 |= 0x0f; */ - /* rtw_hal_set_hwreg23a(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ if (pmlmeext->sitesurvey_res.channel_idx == 0) set_channel_bwmode23a(padapter, survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, @@ -7664,276 +4409,220 @@ void site_survey23a(struct rtw_adapter *padapter) if (ScanType == SCAN_ACTIVE) /* obey the channel plan setting... */ { -#ifdef CONFIG_8723AU_P2P - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || - rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) - ) - { - issue23a_probereq_p2p(padapter, NULL); - issue23a_probereq_p2p(padapter, NULL); - issue23a_probereq_p2p(padapter, NULL); - } - else -#endif /* CONFIG_8723AU_P2P */ - { - int i; - for (i = 0;isitesurvey_res.ssid[i].ssid_len) { - /* todo: to issue two probe req??? */ - issue_probereq23a(padapter, &pmlmeext->sitesurvey_res.ssid[i], NULL); - /* msleep(SURVEY_TO>>1); */ - issue_probereq23a(padapter, &pmlmeext->sitesurvey_res.ssid[i], NULL); - } - } - - if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { + int i; + for (i = 0;isitesurvey_res.ssid[i].ssid_len) { /* todo: to issue two probe req??? */ - issue_probereq23a(padapter, NULL, NULL); + issue_probereq23a(padapter, &pmlmeext->sitesurvey_res.ssid[i], NULL); /* msleep(SURVEY_TO>>1); */ - issue_probereq23a(padapter, NULL, NULL); + issue_probereq23a(padapter, &pmlmeext->sitesurvey_res.ssid[i], NULL); } } + + if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { + /* todo: to issue two probe req??? */ + issue_probereq23a(padapter, NULL, NULL); + /* msleep(SURVEY_TO>>1); */ + issue_probereq23a(padapter, NULL, NULL); + } } set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); } else { - /* channel number is 0 or this channel is not valid. */ + pmlmeext->sitesurvey_res.state = SCAN_COMPLETE; + /* switch back to the original channel */ -#ifdef CONFIG_8723AU_P2P - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) - { - if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || (pwdinfo->p2p_info.scan_op_ch_only)) - { - /* Set the find_phase_state_exchange_cnt to P2P_FINDPHASE_EX_CNT. */ - /* This will let the following flow to run the scanning end. */ - rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX); - } - } - - if (rtw_p2p_findphase_ex_is_needed(pwdinfo)) - { - /* Set the P2P State to the listen state of find phase and set the current channel to the listen channel */ - set_channel_bwmode23a(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); - rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_LISTEN); - pmlmeext->sitesurvey_res.state = SCAN_DISABLE; - - initialgain = 0xff; /* restore RX GAIN */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); - /* turn on dynamic functions */ - Restore_DM_Func_Flag23a(padapter); - /* Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DIG|DYNAMIC_FUNC_HP|DYNAMIC_FUNC_SS, true); */ - - mod_timer(&pwdinfo->find_phase_timer, jiffies + - msecs_to_jiffies(pwdinfo->listen_dwell * 100)); - } else -#endif /* CONFIG_8723AU_P2P */ - { -#ifdef CONFIG_8723AU_P2P - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) - rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); - rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); -#endif /* CONFIG_8723AU_P2P */ - - pmlmeext->sitesurvey_res.state = SCAN_COMPLETE; - - /* switch back to the original channel */ - - set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, + pmlmeext->cur_ch_offset, + pmlmeext->cur_bwmode); - /* flush 4-AC Queue after site_survey23a */ - /* val8 = 0; */ - /* rtw_hal_set_hwreg23a(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ + /* flush 4-AC Queue after site_survey23a */ + /* val8 = 0; */ - /* config MSR */ - Set_MSR23a(padapter, (pmlmeinfo->state & 0x3)); - - initialgain = 0xff; /* restore RX GAIN */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); - /* turn on dynamic functions */ - Restore_DM_Func_Flag23a(padapter); - /* Switch_DM_Func23a(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); */ - - if (is_client_associated_to_ap23a(padapter) == true) - { - issue_nulldata23a(padapter, NULL, 0, 3, 500); + /* config MSR */ + Set_MSR23a(padapter, (pmlmeinfo->state & 0x3)); - } + /* restore RX GAIN */ + rtl8723a_set_initial_gain(padapter, 0xff); + /* turn on dynamic functions */ + rtl8723a_odm_support_ability_restore(padapter); - val8 = 0; /* survey done */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + if (is_client_associated_to_ap23a(padapter) == true) + issue_nulldata23a(padapter, NULL, 0, 3, 500); - report_surveydone_event23a(padapter); + rtl8723a_mlme_sitesurvey(padapter, 0); - pmlmeext->chan_scan_time = SURVEY_TO; - pmlmeext->sitesurvey_res.state = SCAN_DISABLE; + report_surveydone_event23a(padapter); - issue_action_BSSCoexistPacket(padapter); - issue_action_BSSCoexistPacket(padapter); - issue_action_BSSCoexistPacket(padapter); + pmlmeext->chan_scan_time = SURVEY_TO; + pmlmeext->sitesurvey_res.state = SCAN_DISABLE; - } + issue_action_BSSCoexistPacket(padapter); + issue_action_BSSCoexistPacket(padapter); + issue_action_BSSCoexistPacket(padapter); } return; } /* collect bss info from Beacon and Probe request/response frames. */ -u8 collect_bss_info23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame, struct wlan_bssid_ex *bssid) +u8 collect_bss_info23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame, + struct wlan_bssid_ex *bssid) { - int i; - u32 len; - u8 *p; - u16 val16; + int i; + const u8 *p; struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u8 *pframe = skb->data; - u32 packet_len = skb->len; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data; + unsigned int length; u8 ie_offset; - struct registry_priv *pregistrypriv = &padapter->registrypriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u16 capab_info; - len = packet_len - sizeof(struct ieee80211_hdr_3addr); + length = skb->len - sizeof(struct ieee80211_hdr_3addr); - if (len > MAX_IE_SZ) - { + if (length > MAX_IE_SZ) { /* DBG_8723A("IE too long for survey event\n"); */ return _FAIL; } memset(bssid, 0, sizeof(struct wlan_bssid_ex)); - if (ieee80211_is_beacon(hdr->frame_control)) { + if (ieee80211_is_beacon(mgmt->frame_control)) { bssid->reserved = 1; - ie_offset = _BEACON_IE_OFFSET_; + ie_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable); + capab_info = mgmt->u.beacon.capab_info; + } else if (ieee80211_is_probe_req(mgmt->frame_control)) { + ie_offset = offsetof(struct ieee80211_mgmt, + u.probe_req.variable); + bssid->reserved = 2; + capab_info = 0; + } else if (ieee80211_is_probe_resp(mgmt->frame_control)) { + ie_offset = offsetof(struct ieee80211_mgmt, + u.probe_resp.variable); + bssid->reserved = 3; + capab_info = mgmt->u.probe_resp.capab_info; } else { - /* FIXME : more type */ - if (ieee80211_is_probe_req(hdr->frame_control)) { - ie_offset = _PROBEREQ_IE_OFFSET_; - bssid->reserved = 2; - } else if (ieee80211_is_probe_resp(hdr->frame_control)) { - ie_offset = _PROBERSP_IE_OFFSET_; - bssid->reserved = 3; - } else { - bssid->reserved = 0; - ie_offset = _FIXED_IE_LENGTH_; - } + bssid->reserved = 0; + ie_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable); + capab_info = mgmt->u.beacon.capab_info; } + ie_offset -= offsetof(struct ieee80211_mgmt, u); - bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; + bssid->Length = offsetof(struct wlan_bssid_ex, IEs) + length; /* below is to copy the information element */ - bssid->IELength = len; - memcpy(bssid->IEs, (pframe + sizeof(struct ieee80211_hdr_3addr)), bssid->IELength); + bssid->IELength = length; + memcpy(bssid->IEs, &mgmt->u, bssid->IELength); /* get the signal strength */ - bssid->Rssi = precv_frame->attrib.phy_info.RecvSignalPower; /* in dBM.raw data */ - bssid->PhyInfo.SignalQuality = precv_frame->attrib.phy_info.SignalQuality;/* in percentage */ - bssid->PhyInfo.SignalStrength = precv_frame->attrib.phy_info.SignalStrength;/* in percentage */ + /* in dBM.raw data */ + bssid->Rssi = precv_frame->attrib.phy_info.RecvSignalPower; + bssid->PhyInfo.SignalQuality = + precv_frame->attrib.phy_info.SignalQuality;/* in percentage */ + bssid->PhyInfo.SignalStrength = + precv_frame->attrib.phy_info.SignalStrength;/* in percentage */ /* checking SSID */ - if ((p = rtw_get_ie23a(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset)) == NULL) - { + p = cfg80211_find_ie(WLAN_EID_SSID, bssid->IEs + ie_offset, + bssid->IELength - ie_offset); + + if (!p) { DBG_8723A("marc: cannot find SSID for survey event\n"); return _FAIL; } - if (*(p + 1)) { - if (len > IEEE80211_MAX_SSID_LEN) { - DBG_8723A("%s()-%d: IE too long (%d) for survey " - "event\n", __func__, __LINE__, len); - return _FAIL; - } - memcpy(bssid->Ssid.ssid, (p + 2), *(p + 1)); - bssid->Ssid.ssid_len = *(p + 1); - } else { - bssid->Ssid.ssid_len = 0; + if (p[1] > IEEE80211_MAX_SSID_LEN) { + DBG_8723A("%s()-%d: IE too long (%d) for survey " + "event\n", __func__, __LINE__, p[1]); + return _FAIL; } + memcpy(bssid->Ssid.ssid, p + 2, p[1]); + bssid->Ssid.ssid_len = p[1]; memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); /* checking rate info... */ i = 0; - p = rtw_get_ie23a(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); - if (p != NULL) - { - if (len > NDIS_802_11_LENGTH_RATES_EX) - { - DBG_8723A("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); + p = cfg80211_find_ie(WLAN_EID_SUPP_RATES, bssid->IEs + ie_offset, + bssid->IELength - ie_offset); + if (p) { + if (p[1] > NDIS_802_11_LENGTH_RATES_EX) { + DBG_8723A("%s()-%d: IE too long (%d) for survey " + "event\n", __func__, __LINE__, p[1]); return _FAIL; } - memcpy(bssid->SupportedRates, (p + 2), len); - i = len; + memcpy(bssid->SupportedRates, p + 2, p[1]); + i = p[1]; } - p = rtw_get_ie23a(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); - if (p != NULL) - { - if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) - { - DBG_8723A("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); + p = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, bssid->IEs + ie_offset, + bssid->IELength - ie_offset); + if (p) { + if (p[1] > (NDIS_802_11_LENGTH_RATES_EX-i)) { + DBG_8723A("%s()-%d: IE too long (%d) for survey " + "event\n", __func__, __LINE__, p[1]); return _FAIL; } - memcpy(bssid->SupportedRates + i, (p + 2), len); + memcpy(bssid->SupportedRates + i, p + 2, p[1]); } - /* todo: */ - { - bssid->NetworkTypeInUse = Ndis802_11OFDM24; - } + bssid->NetworkTypeInUse = Ndis802_11OFDM24; if (bssid->IELength < 12) return _FAIL; /* Checking for DSConfig */ - p = rtw_get_ie23a(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset); + p = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bssid->IEs + ie_offset, + bssid->IELength - ie_offset); bssid->Configuration.DSConfig = 0; bssid->Configuration.Length = 0; - if (p) - { - bssid->Configuration.DSConfig = *(p + 2); - } - else - {/* In 5G, some ap do not have DSSET IE */ + if (p) { + bssid->Configuration.DSConfig = p[2]; + } else {/* In 5G, some ap do not have DSSET IE */ /* checking HT info for channel */ - p = rtw_get_ie23a(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset); - if (p) - { - struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2); - bssid->Configuration.DSConfig = HT_info->primary_channel; - } - else - { /* use current channel */ - bssid->Configuration.DSConfig = rtw_get_oper_ch23a(padapter); + p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, + bssid->IEs + ie_offset, + bssid->IELength - ie_offset); + if (p) { + struct HT_info_element *HT_info = + (struct HT_info_element *)(p + 2); + bssid->Configuration.DSConfig = + HT_info->primary_channel; + } else { /* use current channel */ + bssid->Configuration.DSConfig = + rtw_get_oper_ch23a(padapter); } } - if (ieee80211_is_probe_req(hdr->frame_control)) { + if (ieee80211_is_probe_req(mgmt->frame_control)) { /* FIXME */ bssid->InfrastructureMode = Ndis802_11Infrastructure; - ether_addr_copy(bssid->MacAddress, hdr->addr2); + ether_addr_copy(bssid->MacAddress, mgmt->sa); bssid->Privacy = 1; return _SUCCESS; } - memcpy(&bssid->Configuration.BeaconPeriod, rtw_get_beacon_interval23a_from_ie(bssid->IEs), 2); - bssid->Configuration.BeaconPeriod = le32_to_cpu(bssid->Configuration.BeaconPeriod); + memcpy(&bssid->Configuration.BeaconPeriod, + rtw_get_beacon_interval23a_from_ie(bssid->IEs), 2); + bssid->Configuration.BeaconPeriod = + le32_to_cpu(bssid->Configuration.BeaconPeriod); - val16 = rtw_get_capability23a(bssid); - - if (val16 & BIT(0)) { + if (capab_info & BIT(0)) { bssid->InfrastructureMode = Ndis802_11Infrastructure; - ether_addr_copy(bssid->MacAddress, hdr->addr2); + ether_addr_copy(bssid->MacAddress, mgmt->sa); } else { bssid->InfrastructureMode = Ndis802_11IBSS; - ether_addr_copy(bssid->MacAddress, hdr->addr3); + ether_addr_copy(bssid->MacAddress, mgmt->bssid); } - if (val16 & BIT(4)) + if (capab_info & BIT(4)) bssid->Privacy = 1; else bssid->Privacy = 0; @@ -7941,21 +4630,21 @@ u8 collect_bss_info23a(struct rtw_adapter *padapter, struct recv_frame *precv_fr bssid->Configuration.ATIMWindow = 0; /* 20/40 BSS Coexistence check */ - if ((pregistrypriv->wifi_spec == 1) && (false == pmlmeinfo->bwmode_updated)) - { + if (pregistrypriv->wifi_spec == 1 && + pmlmeinfo->bwmode_updated == false) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - p = rtw_get_ie23a(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset); - if (p && len > 0) { - struct HT_caps_element *pHT_caps; - pHT_caps = (struct HT_caps_element *)(p + 2); + p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, + bssid->IEs + ie_offset, + bssid->IELength - ie_offset); + if (p && p[1] > 0) { + struct HT_caps_element *pHT_caps; + pHT_caps = (struct HT_caps_element *)(p + 2); if (pHT_caps->u.HT_cap_element.HT_caps_info & BIT(14)) pmlmepriv->num_FortyMHzIntolerant++; } else - { pmlmepriv->num_sta_no_ht++; - } } @@ -7969,8 +4658,6 @@ u8 collect_bss_info23a(struct rtw_adapter *padapter, struct recv_frame *precv_fr void start_create_ibss23a(struct rtw_adapter* padapter) { unsigned short caps; - u8 val8; - u8 join_type; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; @@ -7983,10 +4670,8 @@ void start_create_ibss23a(struct rtw_adapter* padapter) /* udpate capability */ caps = rtw_get_capability23a(pnetwork); update_capinfo23a(padapter, caps); - if (caps&cap_IBSS)/* adhoc master */ - { - val8 = 0xcf; - rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + if (caps&cap_IBSS) { /* adhoc master */ + rtl8723a_set_sec_cfg(padapter, 0xcf); /* switch channel */ /* SelectChannel23a(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); */ @@ -8008,9 +4693,8 @@ void start_create_ibss23a(struct rtw_adapter* padapter) } else { - rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress); - join_type = 0; - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + hw_var_set_bssid(padapter, padapter->registrypriv.dev_network.MacAddress); + hw_var_set_mlme_join(padapter, 0); report_join_res23a(padapter, 1); pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; @@ -8047,9 +4731,10 @@ void start_clnt_join23a(struct rtw_adapter* padapter) Set_MSR23a(padapter, WIFI_FW_STATION_STATE); - val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X)? 0xcc: 0xcf; + val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) ? + 0xcc: 0xcf; - rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + rtl8723a_set_sec_cfg(padapter, val8); /* switch channel */ /* set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ @@ -8062,12 +4747,10 @@ void start_clnt_join23a(struct rtw_adapter* padapter) msecs_to_jiffies((REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO*REASSOC_LIMIT) + beacon_timeout)); pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE; } - else if (caps&cap_IBSS) /* adhoc client */ - { + else if (caps&cap_IBSS) { /* adhoc client */ Set_MSR23a(padapter, WIFI_FW_ADHOC_STATE); - val8 = 0xcf; - rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + rtl8723a_set_sec_cfg(padapter, 0xcf); /* switch channel */ set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); @@ -8158,7 +4841,8 @@ unsigned int receive_disconnect23a(struct rtw_adapter *padapter, unsigned char * return _SUCCESS; } -static void process_80211d(struct rtw_adapter *padapter, struct wlan_bssid_ex *bssid) +static void process_80211d(struct rtw_adapter *padapter, + struct wlan_bssid_ex *bssid) { struct registry_priv *pregistrypriv; struct mlme_ext_priv *pmlmeext; @@ -8171,10 +4855,8 @@ static void process_80211d(struct rtw_adapter *padapter, struct wlan_bssid_ex *b /* Adjust channel plan by AP Country IE */ if (pregistrypriv->enable80211d && - (!pmlmeext->update_channel_plan_by_ap_done)) - { - u8 *ie, *p; - u32 len; + !pmlmeext->update_channel_plan_by_ap_done) { + const u8 *ie, *p; struct rt_channel_plan chplan_ap; struct rt_channel_info chplan_sta[MAX_CHANNEL_NUM]; u8 country[4]; @@ -8182,31 +4864,34 @@ static void process_80211d(struct rtw_adapter *padapter, struct wlan_bssid_ex *b u8 noc; /* number of channel */ u8 j, k; - ie = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _COUNTRY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); - if (!ie) return; - if (len < 6) return; + ie = cfg80211_find_ie(WLAN_EID_COUNTRY, + bssid->IEs + _FIXED_IE_LENGTH_, + bssid->IELength - _FIXED_IE_LENGTH_); + if (!ie || ie[1] < IEEE80211_COUNTRY_IE_MIN_LEN) + return; + p = ie + 2; + ie += ie[1]; ie += 2; - p = ie; - ie += len; - memset(country, 0, 4); memcpy(country, p, 3); + country[3] = '\0'; + p += 3; RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, - ("%s: 802.11d country =%s\n", __func__, country)); + ("%s: 802.11d country =%s\n", __func__, country)); i = 0; - while ((ie - p) >= 3) - { + while ((ie - p) >= 3) { fcn = *(p++); noc = *(p++); p++; - for (j = 0; j < noc; j++) - { - if (fcn <= 14) channel = fcn + j; /* 2.4 GHz */ - else channel = fcn + j*4; /* 5 GHz */ + for (j = 0; j < noc; j++) { + if (fcn <= 14) + channel = fcn + j; /* 2.4 GHz */ + else + channel = fcn + j * 4; /* 5 GHz */ chplan_ap.Channel[i++] = channel; } @@ -8220,45 +4905,55 @@ static void process_80211d(struct rtw_adapter *padapter, struct wlan_bssid_ex *b i = j = k = 0; if (pregistrypriv->wireless_mode & WIRELESS_11G) { do { - if ((i == MAX_CHANNEL_NUM) || - (chplan_sta[i].ChannelNum == 0) || - (chplan_sta[i].ChannelNum > 14)) + if (i == MAX_CHANNEL_NUM || + chplan_sta[i].ChannelNum == 0 || + chplan_sta[i].ChannelNum > 14) break; - if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] > 14)) + if (j == chplan_ap.Len || + chplan_ap.Channel[j] > 14) break; - if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) { - chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + if (chplan_sta[i].ChannelNum == + chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = + chplan_ap.Channel[j]; chplan_new[k].ScanType = SCAN_ACTIVE; i++; j++; k++; - } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) { - chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; - chplan_new[k].ScanType = SCAN_PASSIVE; + } else if (chplan_sta[i].ChannelNum < + chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = + chplan_sta[i].ChannelNum; + chplan_new[k].ScanType = + SCAN_PASSIVE; i++; k++; - } else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) { - chplan_new[k].ChannelNum = chplan_ap.Channel[j]; - chplan_new[k].ScanType = SCAN_ACTIVE; + } else if (chplan_sta[i].ChannelNum > + chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = + chplan_ap.Channel[j]; + chplan_new[k].ScanType = + SCAN_ACTIVE; j++; k++; } } while (1); /* change AP not support channel to Passive scan */ - while ((i < MAX_CHANNEL_NUM) && - (chplan_sta[i].ChannelNum != 0) && - (chplan_sta[i].ChannelNum <= 14)) { - chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + while (i < MAX_CHANNEL_NUM && + chplan_sta[i].ChannelNum != 0 && + chplan_sta[i].ChannelNum <= 14) { + chplan_new[k].ChannelNum = + chplan_sta[i].ChannelNum; chplan_new[k].ScanType = SCAN_PASSIVE; i++; k++; } /* add channel AP supported */ - while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) { + while (j < chplan_ap.Len && chplan_ap.Channel[j] <= 14){ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; chplan_new[k].ScanType = SCAN_ACTIVE; j++; @@ -8266,49 +4961,50 @@ static void process_80211d(struct rtw_adapter *padapter, struct wlan_bssid_ex *b } } else { /* keep original STA 2.4G channel plan */ - while ((i < MAX_CHANNEL_NUM) && - (chplan_sta[i].ChannelNum != 0) && - (chplan_sta[i].ChannelNum <= 14)) { - chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + while (i < MAX_CHANNEL_NUM && + chplan_sta[i].ChannelNum != 0 && + chplan_sta[i].ChannelNum <= 14) { + chplan_new[k].ChannelNum = + chplan_sta[i].ChannelNum; chplan_new[k].ScanType = chplan_sta[i].ScanType; i++; k++; } /* skip AP 2.4G channel plan */ - while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) { + while (j < chplan_ap.Len && chplan_ap.Channel[j] <= 14) j++; - } } if (pregistrypriv->wireless_mode & WIRELESS_11A) { do { - if ((i == MAX_CHANNEL_NUM) || - (chplan_sta[i].ChannelNum == 0)) + if (i == MAX_CHANNEL_NUM || + chplan_sta[i].ChannelNum == 0) break; - if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] == 0)) + if (j == chplan_ap.Len || + chplan_ap.Channel[j] == 0) break; - if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) - { - chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + if (chplan_sta[i].ChannelNum == + chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = + chplan_ap.Channel[j]; chplan_new[k].ScanType = SCAN_ACTIVE; i++; j++; k++; - } - else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) - { - chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; -/* chplan_new[k].ScanType = chplan_sta[i].ScanType; */ + } else if (chplan_sta[i].ChannelNum < + chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = + chplan_sta[i].ChannelNum; chplan_new[k].ScanType = SCAN_PASSIVE; i++; k++; - } - else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) - { - chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + } else if (chplan_sta[i].ChannelNum > + chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = + chplan_ap.Channel[j]; chplan_new[k].ScanType = SCAN_ACTIVE; j++; k++; @@ -8316,15 +5012,17 @@ static void process_80211d(struct rtw_adapter *padapter, struct wlan_bssid_ex *b } while (1); /* change AP not support channel to Passive scan */ - while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) { - chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + while (i < MAX_CHANNEL_NUM && + chplan_sta[i].ChannelNum != 0) { + chplan_new[k].ChannelNum = + chplan_sta[i].ChannelNum; chplan_new[k].ScanType = SCAN_PASSIVE; i++; k++; } /* add channel AP supported */ - while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] != 0)) { + while (j < chplan_ap.Len && chplan_ap.Channel[j] != 0) { chplan_new[k].ChannelNum = chplan_ap.Channel[j]; chplan_new[k].ScanType = SCAN_ACTIVE; j++; @@ -8332,8 +5030,10 @@ static void process_80211d(struct rtw_adapter *padapter, struct wlan_bssid_ex *b } } else { /* keep original STA 5G channel plan */ - while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) { - chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + while (i < MAX_CHANNEL_NUM && + chplan_sta[i].ChannelNum != 0) { + chplan_new[k].ChannelNum = + chplan_sta[i].ChannelNum; chplan_new[k].ScanType = chplan_sta[i].ScanType; i++; k++; @@ -8346,18 +5046,19 @@ static void process_80211d(struct rtw_adapter *padapter, struct wlan_bssid_ex *b channel = bssid->Configuration.DSConfig; chplan_new = pmlmeext->channel_set; i = 0; - while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) { - if (chplan_new[i].ChannelNum == channel) - { + while (i < MAX_CHANNEL_NUM && chplan_new[i].ChannelNum != 0) { + if (chplan_new[i].ChannelNum == channel) { if (chplan_new[i].ScanType == SCAN_PASSIVE) { - /* 5G Bnad 2, 3 (DFS) doesn't change to active scan */ + /* 5G Bnad 2, 3 (DFS) doesn't change + to active scan */ if (channel >= 52 && channel <= 144) break; chplan_new[i].ScanType = SCAN_ACTIVE; RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, - ("%s: change channel %d scan type from passive to active\n", - __func__, channel)); + ("%s: change channel %d scan type " + "from passive to active\n", + __func__, channel)); } break; } @@ -8399,8 +5100,6 @@ void report_survey_event23a(struct rtw_adapter *padapter, struct recv_frame *pre return; } - INIT_LIST_HEAD(&pcmd_obj->list); - pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); pcmd_obj->cmdsz = cmdsz; pcmd_obj->parmbuf = pevtcmd; @@ -8452,8 +5151,6 @@ void report_surveydone_event23a(struct rtw_adapter *padapter) return; } - INIT_LIST_HEAD(&pcmd_obj->list); - pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); pcmd_obj->cmdsz = cmdsz; pcmd_obj->parmbuf = pevtcmd; @@ -8499,8 +5196,6 @@ void report_join_res23a(struct rtw_adapter *padapter, int res) return; } - INIT_LIST_HEAD(&pcmd_obj->list); - pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); pcmd_obj->cmdsz = cmdsz; pcmd_obj->parmbuf = pevtcmd; @@ -8551,8 +5246,6 @@ void report_del_sta_event23a(struct rtw_adapter *padapter, unsigned char* MacAdd return; } - INIT_LIST_HEAD(&pcmd_obj->list); - pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); pcmd_obj->cmdsz = cmdsz; pcmd_obj->parmbuf = pevtcmd; @@ -8607,8 +5300,6 @@ void report_add_sta_event23a(struct rtw_adapter *padapter, unsigned char* MacAdd return; } - INIT_LIST_HEAD(&pcmd_obj->list); - pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); pcmd_obj->cmdsz = cmdsz; pcmd_obj->parmbuf = pevtcmd; @@ -8691,17 +5382,14 @@ void mlmeext_joinbss_event_callback23a(struct rtw_adapter *padapter, int join_re struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; struct sta_priv *pstapriv = &padapter->stapriv; - u8 join_type; - u16 media_status; - if (join_res < 0) - { - join_type = 1; - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); - rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, null_addr); + if (join_res < 0) { + hw_var_set_mlme_join(padapter, 1); + hw_var_set_bssid(padapter, null_addr); /* restore to initial setting. */ - update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode); + update_tx_basic_rate23a(padapter, + padapter->registrypriv.wireless_mode); goto exit_mlmeext_joinbss_event_callback23a; } @@ -8719,15 +5407,15 @@ void mlmeext_joinbss_event_callback23a(struct rtw_adapter *padapter, int join_re } /* turn on dynamic functions */ - Switch_DM_Func23a(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); + rtl8723a_odm_support_ability_set(padapter, DYNAMIC_ALL_FUNC_ENABLE); /* update IOT-releated issue */ update_IOT_info23a(padapter); - rtw_hal_set_hwreg23a(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates); + HalSetBrateCfg23a(padapter, cur_network->SupportedRates); /* BCN interval */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval)); + rtl8723a_set_beacon_interval(padapter, pmlmeinfo->bcn_interval); /* udpate capability */ update_capinfo23a(padapter, pmlmeinfo->capability); @@ -8752,18 +5440,13 @@ void mlmeext_joinbss_event_callback23a(struct rtw_adapter *padapter, int join_re /* set per sta rate after updating HT cap. */ set_sta_rate23a(padapter, psta); - - media_status = (psta->mac_id<<8)|1; /* MACID|OPMODE: 1 means connect */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); } - join_type = 2; - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + hw_var_set_mlme_join(padapter, 2); - if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) - { + if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) { /* correcting TSF */ - correct_TSF23a(padapter, pmlmeext); + rtw_correct_TSF(padapter); /* set_link_timer(pmlmeext, DISCONNECT_TO); */ } @@ -8778,7 +5461,6 @@ void mlmeext_sta_add_event_callback23a(struct rtw_adapter *padapter, struct sta_ { struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - u8 join_type; DBG_8723A("%s\n", __func__); @@ -8790,11 +5472,8 @@ void mlmeext_sta_add_event_callback23a(struct rtw_adapter *padapter, struct sta_ } else/* adhoc client */ { - /* update TSF Value */ - /* update_TSF23a(pmlmeext, pframe, len); */ - /* correcting TSF */ - correct_TSF23a(padapter, pmlmeext); + rtw_correct_TSF(padapter); /* start beacon */ if (send_beacon23a(padapter) == _FAIL) @@ -8810,8 +5489,7 @@ void mlmeext_sta_add_event_callback23a(struct rtw_adapter *padapter, struct sta_ } - join_type = 2; - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + hw_var_set_mlme_join(padapter, 2); } pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; @@ -8832,8 +5510,8 @@ void mlmeext_sta_del_event_callback23a(struct rtw_adapter *padapter) { /* set_opmode_cmd(padapter, infra_client_with_mlme); */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_DISCONNECT, NULL); - rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, null_addr); + hw_var_set_mlme_disconnect(padapter); + hw_var_set_bssid(padapter, null_addr); /* restore to initial setting. */ update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode); @@ -8856,28 +5534,6 @@ void mlmeext_sta_del_event_callback23a(struct rtw_adapter *padapter) } } -/**************************************************************************** - -Following are the functions for the timer handlers - -*****************************************************************************/ -void linked23a_rx_sig_stren_disp(struct rtw_adapter *padapter) -{ - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - u8 mac_id; - int UndecoratedSmoothedPWDB; - if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) - mac_id = 0; - else if ((pmlmeinfo->state&0x03) == _HW_STATE_AP_) - mac_id = 2; - - rtw_hal_get_def_var23a(padapter, HW_DEF_RA_INFO_DUMP,&mac_id); - - rtw_hal_get_def_var23a(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB); - DBG_8723A("UndecoratedSmoothedPWDB:%d\n", UndecoratedSmoothedPWDB); -} - static u8 chk_ap_is_alive(struct rtw_adapter *padapter, struct sta_info *psta) { u8 ret = false; @@ -8902,9 +5558,6 @@ void linked_status_chk23a(struct rtw_adapter *padapter) struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct sta_priv *pstapriv = &padapter->stapriv; - if (padapter->bRxRSSIDisplay) - linked23a_rx_sig_stren_disp(padapter); - rtw_hal_sreset_linked_status_check23a(padapter); if (is_client_associated_to_ap23a(padapter)) @@ -8919,9 +5572,6 @@ void linked_status_chk23a(struct rtw_adapter *padapter) if ((psta = rtw_get_stainfo23a(pstapriv, pmlmeinfo->network.MacAddress)) != NULL) { bool is_p2p_enable = false; -#ifdef CONFIG_8723AU_P2P - is_p2p_enable = !rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE); -#endif if (chk_ap_is_alive(padapter, psta) == false) rx_chk = _FAIL; @@ -9035,32 +5685,17 @@ static void survey_timer_hdl(unsigned long data) struct sitesurvey_parm *psurveyPara; struct cmd_priv *pcmdpriv = &padapter->cmdpriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif /* issue rtw_sitesurvey_cmd23a */ if (pmlmeext->sitesurvey_res.state > SCAN_START) { if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) pmlmeext->sitesurvey_res.channel_idx++; - if (pmlmeext->scan_abort == true) - { -#ifdef CONFIG_8723AU_P2P - if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE)) - { - rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX); - pmlmeext->sitesurvey_res.channel_idx = 3; - DBG_8723A("%s idx:%d, cnt:%u\n", __func__, - pmlmeext->sitesurvey_res.channel_idx, - pwdinfo->find_phase_state_exchange_cnt); - } else - #endif - { - pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num; - DBG_8723A("%s idx:%d\n", __func__, - pmlmeext->sitesurvey_res.channel_idx); - } + if (pmlmeext->scan_abort == true) { + pmlmeext->sitesurvey_res.channel_idx = + pmlmeext->sitesurvey_res.ch_num; + DBG_8723A("%s idx:%d\n", __func__, + pmlmeext->sitesurvey_res.channel_idx); pmlmeext->scan_abort = false;/* reset */ } @@ -9177,50 +5812,42 @@ void init_mlme_ext_timer23a(struct rtw_adapter *padapter) (unsigned long)padapter); } -u8 NULL_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +u8 NULL_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { return H2C_SUCCESS; } -u8 setopmode_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +u8 setopmode_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { u8 type; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf; + const struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf; - if (psetop->mode == Ndis802_11APMode) - { + if (psetop->mode == Ndis802_11APMode) { pmlmeinfo->state = WIFI_FW_AP_STATE; type = _HW_STATE_AP_; - } - else if (psetop->mode == Ndis802_11Infrastructure) - { + } else if (psetop->mode == Ndis802_11Infrastructure) { pmlmeinfo->state &= ~(BIT(0)|BIT(1));/* clear state */ pmlmeinfo->state |= WIFI_FW_STATION_STATE;/* set to STATION_STATE */ type = _HW_STATE_STATION_; - } - else if (psetop->mode == Ndis802_11IBSS) - { + } else if (psetop->mode == Ndis802_11IBSS) type = _HW_STATE_ADHOC_; - } else - { type = _HW_STATE_NOLINK_; - } - rtw_hal_set_hwreg23a(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type)); + hw_var_set_opmode(padapter, type); /* Set_NETYPE0_MSR(padapter, type); */ return H2C_SUCCESS; } -u8 createbss_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +u8 createbss_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; - struct wlan_bssid_ex *pparm = (struct wlan_bssid_ex *)pbuf; + const struct wlan_bssid_ex *pparm = (struct wlan_bssid_ex *)pbuf; /* u32 initialgain; */ if (pparm->InfrastructureMode == Ndis802_11APMode) { @@ -9249,12 +5876,10 @@ u8 createbss_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) pmlmeinfo->candidate_tid_bitmap = 0; /* disable dynamic functions, such as high power, DIG */ - Save_DM_Func_Flag23a(padapter); - Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false); + rtl8723a_odm_support_ability_backup(padapter); - /* config the initial gain under linking, need to write the BB registers */ - /* initialgain = 0x1E; */ - /* rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); */ + rtl8723a_odm_support_ability_clr(padapter, + DYNAMIC_FUNC_DISABLE); /* cancel link timer */ del_timer_sync(&pmlmeext->link_timer); @@ -9273,15 +5898,14 @@ u8 createbss_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) return H2C_SUCCESS; } -u8 join_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +u8 join_cmd_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { - u8 join_type; struct ndis_802_11_var_ies * pIE; struct registry_priv *pregpriv = &padapter->registrypriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; - struct wlan_bssid_ex *pparm = (struct wlan_bssid_ex *)pbuf; + const struct wlan_bssid_ex *pparm = (struct wlan_bssid_ex *)pbuf; struct HT_info_element *pht_info; u32 i; /* u32 initialgain; */ @@ -9305,7 +5929,7 @@ u8 join_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) /* Set_MSR23a(padapter, _HW_STATE_NOLINK_); */ Set_MSR23a(padapter, _HW_STATE_STATION_); - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_DISCONNECT, NULL); + hw_var_set_mlme_disconnect(padapter); } rtw_joinbss_reset23a(padapter); @@ -9337,16 +5961,16 @@ u8 join_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) switch (pIE->ElementID) { - case _VENDOR_SPECIFIC_IE_:/* Get WMM IE. */ + case WLAN_EID_VENDOR_SPECIFIC:/* Get WMM IE. */ if (!memcmp(pIE->data, WMM_OUI23A, 4)) pmlmeinfo->WMM_enable = 1; break; - case _HT_CAPABILITY_IE_: /* Get HT Cap IE. */ + case WLAN_EID_HT_CAPABILITY: /* Get HT Cap IE. */ pmlmeinfo->HT_caps_enable = 1; break; - case _HT_EXTRA_INFO_IE_: /* Get HT Info IE. */ + case WLAN_EID_HT_OPERATION: /* Get HT Info IE. */ pmlmeinfo->HT_info_enable = 1; /* spec case only for cisco's ap because cisco's ap @@ -9385,19 +6009,9 @@ u8 join_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) i += (pIE->Length + 2); } - /* disable dynamic functions, such as high power, DIG */ - /* Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false); */ - - /* config the initial gain under linking, need to write the BB - registers */ - /* initialgain = 0x1E; */ - /* rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, - (u8 *)(&initialgain)); */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, - pmlmeinfo->network.MacAddress); - join_type = 0; - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + hw_var_set_bssid(padapter, pmlmeinfo->network.MacAddress); + hw_var_set_mlme_join(padapter, 0); /* cancel link timer */ del_timer_sync(&pmlmeext->link_timer); @@ -9407,13 +6021,12 @@ u8 join_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) return H2C_SUCCESS; } -u8 disconnect_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +u8 disconnect_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { - struct disconnect_parm *param = (struct disconnect_parm *)pbuf; + const struct disconnect_parm *param = (struct disconnect_parm *)pbuf; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; - u8 val8; if (is_client_associated_to_ap23a(padapter)) { @@ -9424,18 +6037,15 @@ u8 disconnect_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) /* pmlmeinfo->state = WIFI_FW_NULL_STATE; */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_DISCONNECT, NULL); - rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, null_addr); + hw_var_set_mlme_disconnect(padapter); + hw_var_set_bssid(padapter, null_addr); /* restore to initial setting. */ update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode); - if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) - { - /* Stop BCN */ - val8 = 0; - rtw_hal_set_hwreg23a(padapter, HW_VAR_BCN_FUNC, (u8 *)(&val8)); - } + if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || + ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) + rtl8723a_set_bcn_func(padapter, 0); /* Stop BCN */ /* set MSR to no link state -> infra. mode */ Set_MSR23a(padapter, _HW_STATE_STATION_); @@ -9457,8 +6067,10 @@ u8 disconnect_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) return H2C_SUCCESS; } -static int rtw_scan_ch_decision(struct rtw_adapter *padapter, struct rtw_ieee80211_channel *out, - u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num) +static int +rtw_scan_ch_decision(struct rtw_adapter *padapter, + struct rtw_ieee80211_channel *out, u32 out_num, + const struct rtw_ieee80211_channel *in, u32 in_num) { int i, j; int scan_ch_num = 0; @@ -9522,19 +6134,15 @@ static int rtw_scan_ch_decision(struct rtw_adapter *padapter, struct rtw_ieee802 return j; } -u8 sitesurvey_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +u8 sitesurvey_cmd_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf; + const struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf; u8 bdelayscan = false; - u8 val8; u32 initialgain; u32 i; if (pmlmeext->sitesurvey_res.state == SCAN_DISABLE) { - /* for first time sitesurvey_cmd */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_CHECK_TXBUF, NULL); - pmlmeext->sitesurvey_res.state = SCAN_START; pmlmeext->sitesurvey_res.bss_cnt = 0; pmlmeext->sitesurvey_res.channel_idx = 0; @@ -9582,25 +6190,23 @@ u8 sitesurvey_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) if ((pmlmeext->sitesurvey_res.state == SCAN_START) || (pmlmeext->sitesurvey_res.state == SCAN_TXNULL)) { /* disable dynamic functions, such as high power, DIG */ - Save_DM_Func_Flag23a(padapter); - Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false); + rtl8723a_odm_support_ability_backup(padapter); + rtl8723a_odm_support_ability_clr(padapter, + DYNAMIC_FUNC_DISABLE); /* config the initial gain under scaning, need to write the BB registers */ - if ((wdev_to_priv(padapter->rtw_wdev))->p2p_enabled == true) { + if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled == true) initialgain = 0x30; - } else + else initialgain = 0x1E; - rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, - (u8 *)(&initialgain)); + rtl8723a_set_initial_gain(padapter, initialgain); /* set MSR to no link state */ Set_MSR23a(padapter, _HW_STATE_NOLINK_); - val8 = 1; /* under site survey */ - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_SITESURVEY, - (u8 *)(&val8)); + rtl8723a_mlme_sitesurvey(padapter, 1); pmlmeext->sitesurvey_res.state = SCAN_PROCESS; } @@ -9610,9 +6216,9 @@ u8 sitesurvey_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) return H2C_SUCCESS; } -u8 setauth_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +u8 setauth_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { - struct setauth_parm *pparm = (struct setauth_parm *)pbuf; + const struct setauth_parm *pparm = (struct setauth_parm *)pbuf; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -9624,10 +6230,10 @@ u8 setauth_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) return H2C_SUCCESS; } -u8 setkey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +u8 setkey_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { unsigned short ctrl; - struct setkey_parm *pparm = (struct setkey_parm *)pbuf; + const struct setkey_parm *pparm = (struct setkey_parm *)pbuf; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -9641,21 +6247,21 @@ u8 setkey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) DBG_8723A_LEVEL(_drv_always_, "set group key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) " "keyid:%d\n", pparm->algorithm, pparm->keyid); - write_cam23a(padapter, pparm->keyid, ctrl, null_sta, pparm->key); + rtl8723a_cam_write(padapter, pparm->keyid, ctrl, null_sta, pparm->key); /* allow multicast packets to driver */ - padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_ON_RCR_AM, null_addr); + rtl8723a_on_rcr_am(padapter); return H2C_SUCCESS; } -u8 set_stakey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +u8 set_stakey_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { u16 ctrl = 0; u8 cam_id;/* cam_entry */ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - struct set_stakey_parm *pparm = (struct set_stakey_parm *)pbuf; + const struct set_stakey_parm *pparm = (struct set_stakey_parm *)pbuf; /* cam_entry: */ /* 0~3 for default key */ @@ -9705,7 +6311,8 @@ u8 set_stakey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) pparm->addr[1], pparm->addr[2], pparm->addr[3], pparm->addr[4], pparm->addr[5], cam_id); - write_cam23a(padapter, cam_id, ctrl, pparm->addr, pparm->key); + rtl8723a_cam_write(padapter, cam_id, ctrl, + pparm->addr, pparm->key); return H2C_SUCCESS_RSP; @@ -9728,16 +6335,16 @@ u8 set_stakey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) ctrl = BIT(15) | ((pparm->algorithm) << 2); - write_cam23a(padapter, cam_id, ctrl, pparm->addr, pparm->key); + rtl8723a_cam_write(padapter, cam_id, ctrl, pparm->addr, pparm->key); pmlmeinfo->enc_algo = pparm->algorithm; return H2C_SUCCESS; } -u8 add_ba_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +u8 add_ba_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { - struct addBaReq_parm *pparm = (struct addBaReq_parm *)pbuf; + const struct addBaReq_parm *pparm = (struct addBaReq_parm *)pbuf; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -9805,11 +6412,11 @@ u8 set_tx_beacon_cmd23a(struct rtw_adapter* padapter) return res; } -u8 mlme_evt_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +u8 mlme_evt_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { u8 evt_code, evt_seq; u16 evt_sz; - uint *peventbuf; + const uint *peventbuf; void (*event_callback)(struct rtw_adapter *dev, u8 *pbuf); struct evt_priv *pevt_priv = &padapter->evtpriv; @@ -9848,7 +6455,7 @@ u8 mlme_evt_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) return H2C_SUCCESS; } -u8 h2c_msg_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +u8 h2c_msg_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { if (!pbuf) return H2C_PARAMETERS_ERROR; @@ -9856,7 +6463,7 @@ u8 h2c_msg_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) return H2C_SUCCESS; } -u8 tx_beacon_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +u8 tx_beacon_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { if (send_beacon23a(padapter) == _FAIL) { @@ -9915,9 +6522,9 @@ u8 tx_beacon_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) return H2C_SUCCESS; } -u8 set_ch_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +u8 set_ch_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { - struct set_ch_parm *set_ch_parm; + const struct set_ch_parm *set_ch_parm; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; if (!pbuf) @@ -9938,9 +6545,9 @@ u8 set_ch_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) return H2C_SUCCESS; } -u8 set_chplan_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +u8 set_chplan_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { - struct SetChannelPlan_param *setChannelPlan_param; + const struct SetChannelPlan_param *setChannelPlan_param; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; if (!pbuf) @@ -9954,7 +6561,7 @@ u8 set_chplan_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) return H2C_SUCCESS; } -u8 led_blink_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +u8 led_blink_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { struct LedBlink_param *ledBlink_param; @@ -9966,7 +6573,7 @@ u8 led_blink_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) return H2C_SUCCESS; } -u8 set_csa_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +u8 set_csa_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { return H2C_REJECTED; } @@ -9984,7 +6591,7 @@ u8 set_csa_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) /* TDLS_CKALV_PH1 : check alive timer phase1 */ /* TDLS_CKALV_PH2 : check alive timer phase2 */ /* TDLS_FREE_STA : free tdls sta */ -u8 tdls_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +u8 tdls_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf) { return H2C_REJECTED; } diff --git a/drivers/staging/rtl8723au/core/rtw_p2p.c b/drivers/staging/rtl8723au/core/rtw_p2p.c deleted file mode 100644 index 1a961e3f3a5541..00000000000000 --- a/drivers/staging/rtl8723au/core/rtw_p2p.c +++ /dev/null @@ -1,4001 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. - * - * 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, 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. - * - ******************************************************************************/ -#define _RTW_P2P_C_ - -#include -#include -#include - -#ifdef CONFIG_8723AU_P2P - -static int rtw_p2p_is_channel_list_ok(u8 desired_ch, u8* ch_list, u8 ch_cnt) -{ - int found = 0, i = 0; - - for (i = 0; i < ch_cnt; i++) - { - if (ch_list[ i ] == desired_ch) - { - found = 1; - break; - } - } - return found; -} - -static int is_any_client_associated(struct rtw_adapter *padapter) -{ - return padapter->stapriv.asoc_list_cnt ? true : false; -} - -static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - struct list_head *phead, *plist; - u32 len = 0; - u16 attr_len = 0; - u8 tmplen, *pdata_attr, *pstart, *pcur; - struct sta_info *psta; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct sta_priv *pstapriv = &padapter->stapriv; - - DBG_8723A("%s\n", __func__); - - pdata_attr = kzalloc(MAX_P2P_IE_LEN, GFP_ATOMIC); - - pstart = pdata_attr; - pcur = pdata_attr; - - spin_lock_bh(&pstapriv->asoc_list_lock); - phead = &pstapriv->asoc_list; - - list_for_each(plist, phead) { - psta = container_of(plist, struct sta_info, asoc_list); - - if (psta->is_p2p_device) - { - tmplen = 0; - - pcur++; - - /* P2P device address */ - memcpy(pcur, psta->dev_addr, ETH_ALEN); - pcur += ETH_ALEN; - - /* P2P interface address */ - memcpy(pcur, psta->hwaddr, ETH_ALEN); - pcur += ETH_ALEN; - - *pcur = psta->dev_cap; - pcur++; - - /* u16*)(pcur) = cpu_to_be16(psta->config_methods); */ - put_unaligned_be16(psta->config_methods, pcur); - pcur += 2; - - memcpy(pcur, psta->primary_dev_type, 8); - pcur += 8; - - *pcur = psta->num_of_secdev_type; - pcur++; - - memcpy(pcur, psta->secdev_types_list, psta->num_of_secdev_type*8); - pcur += psta->num_of_secdev_type*8; - - if (psta->dev_name_len>0) - { - /* u16*)(pcur) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ - put_unaligned_be16(WPS_ATTR_DEVICE_NAME, pcur); - pcur += 2; - - /* u16*)(pcur) = cpu_to_be16(psta->dev_name_len); */ - put_unaligned_be16(psta->dev_name_len, pcur); - pcur += 2; - - memcpy(pcur, psta->dev_name, psta->dev_name_len); - pcur += psta->dev_name_len; - } - - tmplen = (u8)(pcur-pstart); - - *pstart = (tmplen-1); - - attr_len += tmplen; - - /* pstart += tmplen; */ - pstart = pcur; - - } - - } - spin_unlock_bh(&pstapriv->asoc_list_lock); - - if (attr_len>0) - { - len = rtw_set_p2p_attr_content23a(pbuf, P2P_ATTR_GROUP_INFO, attr_len, pdata_attr); - } - - kfree(pdata_attr); - - return len; -} - -static void issue_group_disc_req(struct wifidirect_info *pwdinfo, u8 *da) -{ - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - unsigned char category = WLAN_CATEGORY_VENDOR_SPECIFIC;/* P2P action frame */ - u32 p2poui = cpu_to_be32(P2POUI); - u8 oui_subtype = P2P_GO_DISC_REQUEST; - u8 dialogToken = 0; - - DBG_8723A("[%s]\n", __func__); - - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - { - return; - } - - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - fctrl = &pwlanhdr->frame_control; - *fctrl = 0; - - memcpy(pwlanhdr->addr1, da, ETH_ALEN); - memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN); - memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); - - pframe += sizeof(struct ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - - /* Build P2P action frame header */ - pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); - - /* there is no IE in this P2P action frame */ - - pattrib->last_txcmdsz = pattrib->pktlen; - - dump_mgntframe23a(padapter, pmgntframe); -} - -static void issue_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken) -{ - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - unsigned char category = WLAN_CATEGORY_PUBLIC; - u8 action = P2P_PUB_ACTION_ACTION; - u32 p2poui = cpu_to_be32(P2POUI); - u8 oui_subtype = P2P_DEVDISC_RESP; - u8 p2pie[8] = { 0x00 }; - u32 p2pielen = 0; - - DBG_8723A("[%s]\n", __func__); - - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - { - return; - } - - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - fctrl = &pwlanhdr->frame_control; - *fctrl = 0; - - memcpy(pwlanhdr->addr1, da, ETH_ALEN); - memcpy(pwlanhdr->addr2, pwdinfo->device_addr, ETH_ALEN); - memcpy(pwlanhdr->addr3, pwdinfo->device_addr, ETH_ALEN); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); - - pframe += sizeof(struct ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - - /* Build P2P public action frame header */ - pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui, - &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); - - /* Build P2P IE */ - /* P2P OUI */ - p2pielen = 0; - p2pie[ p2pielen++ ] = 0x50; - p2pie[ p2pielen++ ] = 0x6F; - p2pie[ p2pielen++ ] = 0x9A; - p2pie[ p2pielen++ ] = 0x09; /* WFA P2P v1.0 */ - - /* P2P_ATTR_STATUS */ - p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status); - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &pattrib->pktlen); - - pattrib->last_txcmdsz = pattrib->pktlen; - - dump_mgntframe23a(padapter, pmgntframe); -} - -static void issue_p2p_provision_resp(struct wifidirect_info *pwdinfo, u8* raddr, u8* frame_body, u16 config_method) -{ - struct rtw_adapter *padapter = pwdinfo->padapter; - unsigned char category = WLAN_CATEGORY_PUBLIC; - u8 action = P2P_PUB_ACTION_ACTION; - u8 dialogToken = frame_body[7]; /* The Dialog Token of provisioning discovery request frame. */ - u32 p2poui = cpu_to_be32(P2POUI); - u8 oui_subtype = P2P_PROVISION_DISC_RESP; - u8 wpsie[ 100 ] = { 0x00 }; - u8 wpsielen = 0; -#ifdef CONFIG_8723AU_P2P - u32 wfdielen = 0; -#endif /* CONFIG_8723AU_P2P */ - - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - return; - - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - fctrl = &pwlanhdr->frame_control; - *fctrl = 0; - - memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); - memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); - - pframe += sizeof(struct ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - - pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui, - &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); - - wpsielen = 0; - /* WPS OUI */ - /* u32*) (wpsie) = cpu_to_be32(WPSOUI); */ - put_unaligned_be32(WPSOUI, wpsie); - wpsielen += 4; - - /* Config Method */ - /* Type: */ - /* u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); */ - put_unaligned_be16(WPS_ATTR_CONF_METHOD, wpsie + wpsielen); - wpsielen += 2; - - /* Length: */ - /* u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); */ - put_unaligned_be16(0x0002, wpsie + wpsielen); - wpsielen += 2; - - /* Value: */ - /* u16*) (wpsie + wpsielen) = cpu_to_be16(config_method); */ - put_unaligned_be16(config_method, wpsie + wpsielen); - wpsielen += 2; - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen); - -#ifdef CONFIG_8723AU_P2P - wfdielen = build_provdisc_resp_wfd_ie(pwdinfo, pframe); - pframe += wfdielen; - pattrib->pktlen += wfdielen; -#endif /* CONFIG_8723AU_P2P */ - - pattrib->last_txcmdsz = pattrib->pktlen; - - dump_mgntframe23a(padapter, pmgntframe); - - return; -} - -static void issue_p2p_presence_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken) -{ - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - unsigned char category = WLAN_CATEGORY_VENDOR_SPECIFIC;/* P2P action frame */ - u32 p2poui = cpu_to_be32(P2POUI); - u8 oui_subtype = P2P_PRESENCE_RESPONSE; - u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; - u8 noa_attr_content[32] = { 0x00 }; - u32 p2pielen = 0; - - DBG_8723A("[%s]\n", __func__); - - if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) - { - return; - } - - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - fctrl = &pwlanhdr->frame_control; - *fctrl = 0; - - memcpy(pwlanhdr->addr1, da, ETH_ALEN); - memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN); - memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); - - pframe += sizeof(struct ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - - /* Build P2P action frame header */ - pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui, - &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); - - /* Add P2P IE header */ - /* P2P OUI */ - p2pielen = 0; - p2pie[ p2pielen++ ] = 0x50; - p2pie[ p2pielen++ ] = 0x6F; - p2pie[ p2pielen++ ] = 0x9A; - p2pie[ p2pielen++ ] = 0x09; /* WFA P2P v1.0 */ - - /* Add Status attribute in P2P IE */ - p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status); - - /* Add NoA attribute in P2P IE */ - noa_attr_content[0] = 0x1;/* index */ - noa_attr_content[1] = 0x0;/* CTWindow and OppPS Parameters */ - - /* todo: Notice of Absence Descriptor(s) */ - - p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_NOA, 2, noa_attr_content); - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, - &pattrib->pktlen); - - pattrib->last_txcmdsz = pattrib->pktlen; - - dump_mgntframe23a(padapter, pmgntframe); -} - -u32 build_beacon_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; - u16 capability = 0; - u32 len = 0, p2pielen = 0; - - /* P2P OUI */ - p2pielen = 0; - p2pie[ p2pielen++ ] = 0x50; - p2pie[ p2pielen++ ] = 0x6F; - p2pie[ p2pielen++ ] = 0x9A; - p2pie[ p2pielen++ ] = 0x09; /* WFA P2P v1.0 */ - - /* According to the P2P Specification, the beacon frame should contain 3 P2P attributes */ - /* 1. P2P Capability */ - /* 2. P2P Device ID */ - /* 3. Notice of Absence (NOA) */ - - /* P2P Capability ATTR */ - /* Type: */ - /* Length: */ - /* Value: */ - /* Device Capability Bitmap, 1 byte */ - /* Be able to participate in additional P2P Groups and */ - /* support the P2P Invitation Procedure */ - /* Group Capability Bitmap, 1 byte */ - capability = P2P_DEVCAP_INVITATION_PROC|P2P_DEVCAP_CLIENT_DISCOVERABILITY; - capability |= ((P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS) << 8); - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) - capability |= (P2P_GRPCAP_GROUP_FORMATION<<8); - - capability = cpu_to_le16(capability); - - p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_CAPABILITY, 2, (u8*)&capability); - - /* P2P Device ID ATTR */ - p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_DEVICE_ID, ETH_ALEN, pwdinfo->device_addr); - - /* Notice of Absence ATTR */ - /* Type: */ - /* Length: */ - /* Value: */ - - /* go_add_noa_attr(pwdinfo); */ - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); - - return len; -} - -#ifdef CONFIG_8723AU_P2P -u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; - u32 len = 0, wfdielen = 0; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; - - /* WFD OUI */ - wfdielen = 0; - wfdie[ wfdielen++ ] = 0x50; - wfdie[ wfdielen++ ] = 0x6F; - wfdie[ wfdielen++ ] = 0x9A; - wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ - - /* Commented by Albert 20110812 */ - /* According to the WFD Specification, the beacon frame should contain 4 WFD attributes */ - /* 1. WFD Device Information */ - /* 2. Associated BSSID */ - /* 3. Coupled Sink Information */ - - /* WFD Device Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value1: */ - /* WFD device information */ - - if (P2P_ROLE_GO == pwdinfo->role) - { - if (is_any_client_associated(pwdinfo->padapter)) - { - /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_WSD, wfdie + wfdielen); - } - else - { - /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | - WFD_DEVINFO_WSD, wfdie + wfdielen); - } - - } - else - { - /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | - WFD_DEVINFO_WSD, wfdie + wfdielen); - } - - wfdielen += 2; - - /* Value2: */ - /* Session Management Control Port */ - /* Default TCP port for RTSP messages is 554 */ - put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); - wfdielen += 2; - - /* Value3: */ - /* WFD Device Maximum Throughput */ - /* 300Mbps is the maximum throughput */ - put_unaligned_be16(300, wfdie + wfdielen); - wfdielen += 2; - - /* Associated BSSID ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Associated BSSID */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); - } - else - { - memset(wfdie + wfdielen, 0x00, ETH_ALEN); - } - - wfdielen += ETH_ALEN; - - /* Coupled Sink Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0007, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Coupled Sink Status bitmap */ - /* Not coupled/available for Coupling */ - wfdie[ wfdielen++ ] = 0; - /* MAC Addr. */ - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); - - return len; -} - -u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; - u32 len = 0, wfdielen = 0; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; - - /* WFD OUI */ - wfdielen = 0; - wfdie[ wfdielen++ ] = 0x50; - wfdie[ wfdielen++ ] = 0x6F; - wfdie[ wfdielen++ ] = 0x9A; - wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ - - /* Commented by Albert 20110812 */ - /* According to the WFD Specification, the probe request frame should contain 4 WFD attributes */ - /* 1. WFD Device Information */ - /* 2. Associated BSSID */ - /* 3. Coupled Sink Information */ - - /* WFD Device Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value1: */ - /* WFD device information */ - - if (1 == pwdinfo->wfd_tdls_enable) - { - /* WFD primary sink + available for WFD session + WiFi TDLS mode + WSC (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | - WFD_DEVINFO_WSD | - WFD_DEVINFO_PC_TDLS, wfdie + wfdielen); - } - else - { - /* WFD primary sink + available for WFD session + WiFi Direct mode + WSC (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | - WFD_DEVINFO_WSD, wfdie + wfdielen); - } - - wfdielen += 2; - - /* Value2: */ - /* Session Management Control Port */ - /* Default TCP port for RTSP messages is 554 */ - put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); - wfdielen += 2; - - /* Value3: */ - /* WFD Device Maximum Throughput */ - /* 300Mbps is the maximum throughput */ - put_unaligned_be16(300, wfdie + wfdielen); - wfdielen += 2; - - /* Associated BSSID ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Associated BSSID */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); - } - else - { - memset(wfdie + wfdielen, 0x00, ETH_ALEN); - } - - wfdielen += ETH_ALEN; - - /* Coupled Sink Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0007, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Coupled Sink Status bitmap */ - /* Not coupled/available for Coupling */ - wfdie[ wfdielen++ ] = 0; - /* MAC Addr. */ - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); - - return len; -} - -u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunneled) -{ - u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; - u32 len = 0, wfdielen = 0; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; - - /* WFD OUI */ - wfdielen = 0; - wfdie[ wfdielen++ ] = 0x50; - wfdie[ wfdielen++ ] = 0x6F; - wfdie[ wfdielen++ ] = 0x9A; - wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ - - /* Commented by Albert 20110812 */ - /* According to the WFD Specification, the probe response frame should contain 4 WFD attributes */ - /* 1. WFD Device Information */ - /* 2. Associated BSSID */ - /* 3. Coupled Sink Information */ - /* 4. WFD Session Information */ - - /* WFD Device Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value1: */ - /* WFD device information */ - /* WFD primary sink + available for WFD session + WiFi Direct mode */ - - if (true == pwdinfo->session_available) - { - if (P2P_ROLE_GO == pwdinfo->role) - { - if (is_any_client_associated(pwdinfo->padapter)) - { - if (pwdinfo->wfd_tdls_enable) - { - /* TDLS mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT, wfdie + wfdielen); - } - else - { - /* WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT, wfdie + wfdielen); - } - } - else - { - if (pwdinfo->wfd_tdls_enable) - { - /* available for WFD session + TDLS mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT, wfdie + wfdielen); - } - else - { - /* available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT, wfdie + wfdielen); - } - } - } - else - { - if (pwdinfo->wfd_tdls_enable) - { - /* available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | - WFD_DEVINFO_WSD | - WFD_DEVINFO_PC_TDLS | - WFD_DEVINFO_HDCP_SUPPORT, - wfdie + wfdielen); - } - else - { - - /* available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | - WFD_DEVINFO_WSD | - WFD_DEVINFO_HDCP_SUPPORT, - wfdie + wfdielen); - } - } - } - else - { - if (pwdinfo->wfd_tdls_enable) - { - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_WSD | - WFD_DEVINFO_PC_TDLS | - WFD_DEVINFO_HDCP_SUPPORT, - wfdie + wfdielen); - } - else - { - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_WSD | - WFD_DEVINFO_HDCP_SUPPORT, - wfdie + wfdielen); - } - - } - - wfdielen += 2; - - /* Value2: */ - /* Session Management Control Port */ - /* Default TCP port for RTSP messages is 554 */ - put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); - wfdielen += 2; - - /* Value3: */ - /* WFD Device Maximum Throughput */ - /* 300Mbps is the maximum throughput */ - put_unaligned_be16(300, wfdie + wfdielen); - wfdielen += 2; - - /* Associated BSSID ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Associated BSSID */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); - } - else - { - memset(wfdie + wfdielen, 0x00, ETH_ALEN); - } - - wfdielen += ETH_ALEN; - - /* Coupled Sink Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0007, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Coupled Sink Status bitmap */ - /* Not coupled/available for Coupling */ - wfdie[ wfdielen++ ] = 0; - /* MAC Addr. */ - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - { - /* WFD Session Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_SESSION_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0000, wfdie + wfdielen); - wfdielen += 2; - - /* Todo: to add the list of WFD device info descriptor in WFD group. */ - - } - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); - - return len; -} - -u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; - u32 len = 0, wfdielen = 0; - struct rtw_adapter *padapter = NULL; - struct mlme_priv *pmlmepriv = NULL; - struct wifi_display_info *pwfd_info = NULL; - - /* WFD OUI */ - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) - { - return 0; - } - - padapter = pwdinfo->padapter; - pmlmepriv = &padapter->mlmepriv; - pwfd_info = padapter->wdinfo.wfd_info; - - wfdielen = 0; - wfdie[ wfdielen++ ] = 0x50; - wfdie[ wfdielen++ ] = 0x6F; - wfdie[ wfdielen++ ] = 0x9A; - wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ - - /* Commented by Albert 20110812 */ - /* According to the WFD Specification, the probe request frame should contain 4 WFD attributes */ - /* 1. WFD Device Information */ - /* 2. Associated BSSID */ - /* 3. Coupled Sink Information */ - - /* WFD Device Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value1: */ - /* WFD device information */ - /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | - WFD_DEVINFO_WSD, wfdie + wfdielen); - wfdielen += 2; - - /* Value2: */ - /* Session Management Control Port */ - /* Default TCP port for RTSP messages is 554 */ - put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); - wfdielen += 2; - - /* Value3: */ - /* WFD Device Maximum Throughput */ - /* 300Mbps is the maximum throughput */ - put_unaligned_be16(300, wfdie + wfdielen); - wfdielen += 2; - - /* Associated BSSID ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Associated BSSID */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); - } - else - { - memset(wfdie + wfdielen, 0x00, ETH_ALEN); - } - - wfdielen += ETH_ALEN; - - /* Coupled Sink Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0007, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Coupled Sink Status bitmap */ - /* Not coupled/available for Coupling */ - wfdie[ wfdielen++ ] = 0; - /* MAC Addr. */ - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); - - return len; -} - -u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; - u32 len = 0, wfdielen = 0; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; - - /* WFD OUI */ - wfdielen = 0; - wfdie[ wfdielen++ ] = 0x50; - wfdie[ wfdielen++ ] = 0x6F; - wfdie[ wfdielen++ ] = 0x9A; - wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ - - /* Commented by Albert 20110812 */ - /* According to the WFD Specification, the probe request frame should contain 4 WFD attributes */ - /* 1. WFD Device Information */ - /* 2. Associated BSSID */ - /* 3. Coupled Sink Information */ - - /* WFD Device Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value1: */ - /* WFD device information */ - /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | - WFD_DEVINFO_WSD, wfdie + wfdielen); - wfdielen += 2; - - /* Value2: */ - /* Session Management Control Port */ - /* Default TCP port for RTSP messages is 554 */ - put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); - wfdielen += 2; - - /* Value3: */ - /* WFD Device Maximum Throughput */ - /* 300Mbps is the maximum throughput */ - put_unaligned_be16(300, wfdie + wfdielen); - wfdielen += 2; - - /* Associated BSSID ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Associated BSSID */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); - } - else - { - memset(wfdie + wfdielen, 0x00, ETH_ALEN); - } - - wfdielen += ETH_ALEN; - - /* Coupled Sink Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0007, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Coupled Sink Status bitmap */ - /* Not coupled/available for Coupling */ - wfdie[ wfdielen++ ] = 0; - /* MAC Addr. */ - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); - - return len; -} - -u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; - u32 len = 0, wfdielen = 0; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; - - /* WFD OUI */ - wfdielen = 0; - wfdie[ wfdielen++ ] = 0x50; - wfdie[ wfdielen++ ] = 0x6F; - wfdie[ wfdielen++ ] = 0x9A; - wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ - - /* Commented by Albert 20110825 */ - /* According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */ - /* 1. WFD Device Information */ - /* 2. Associated BSSID (Optional) */ - /* 3. Local IP Adress (Optional) */ - - /* WFD Device Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value1: */ - /* WFD device information */ - /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) + WFD Session Available */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL, - wfdie + wfdielen); - wfdielen += 2; - - /* Value2: */ - /* Session Management Control Port */ - /* Default TCP port for RTSP messages is 554 */ - put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); - wfdielen += 2; - - /* Value3: */ - /* WFD Device Maximum Throughput */ - /* 300Mbps is the maximum throughput */ - put_unaligned_be16(300, wfdie + wfdielen); - wfdielen += 2; - - /* Associated BSSID ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Associated BSSID */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); - } - else - { - memset(wfdie + wfdielen, 0x00, ETH_ALEN); - } - - wfdielen += ETH_ALEN; - - /* Coupled Sink Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0007, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Coupled Sink Status bitmap */ - /* Not coupled/available for Coupling */ - wfdie[ wfdielen++ ] = 0; - /* MAC Addr. */ - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); - - return len; -} - -u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; - u32 len = 0, wfdielen = 0; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; - - /* WFD OUI */ - wfdielen = 0; - wfdie[ wfdielen++ ] = 0x50; - wfdie[ wfdielen++ ] = 0x6F; - wfdie[ wfdielen++ ] = 0x9A; - wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ - - /* Commented by Albert 20110825 */ - /* According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */ - /* 1. WFD Device Information */ - /* 2. Associated BSSID (Optional) */ - /* 3. Local IP Adress (Optional) */ - - /* WFD Device Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value1: */ - /* WFD device information */ - /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) + WFD Session Available */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL, - wfdie + wfdielen); - wfdielen += 2; - - /* Value2: */ - /* Session Management Control Port */ - /* Default TCP port for RTSP messages is 554 */ - put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); - wfdielen += 2; - - /* Value3: */ - /* WFD Device Maximum Throughput */ - /* 300Mbps is the maximum throughput */ - put_unaligned_be16(300, wfdie + wfdielen); - wfdielen += 2; - - /* Associated BSSID ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Associated BSSID */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); - } - else - { - memset(wfdie + wfdielen, 0x00, ETH_ALEN); - } - - wfdielen += ETH_ALEN; - - /* Coupled Sink Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0007, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Coupled Sink Status bitmap */ - /* Not coupled/available for Coupling */ - wfdie[ wfdielen++ ] = 0; - /* MAC Addr. */ - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); - - return len; -} - -u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; - u32 len = 0, wfdielen = 0; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; - - /* WFD OUI */ - wfdielen = 0; - wfdie[ wfdielen++ ] = 0x50; - wfdie[ wfdielen++ ] = 0x6F; - wfdie[ wfdielen++ ] = 0x9A; - wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ - - /* Commented by Albert 20110825 */ - /* According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */ - /* 1. WFD Device Information */ - /* 2. Associated BSSID (Optional) */ - /* 3. Local IP Adress (Optional) */ - - /* WFD Device Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value1: */ - /* WFD device information */ - /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) + WFD Session Available */ - put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | - WFD_DEVINFO_SESSION_AVAIL, wfdie + wfdielen); - wfdielen += 2; - - /* Value2: */ - /* Session Management Control Port */ - /* Default TCP port for RTSP messages is 554 */ - put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); - wfdielen += 2; - - /* Value3: */ - /* WFD Device Maximum Throughput */ - /* 300Mbps is the maximum throughput */ - put_unaligned_be16(300, wfdie + wfdielen); - wfdielen += 2; - - /* Associated BSSID ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Associated BSSID */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); - } - else - { - memset(wfdie + wfdielen, 0x00, ETH_ALEN); - } - - wfdielen += ETH_ALEN; - - /* Coupled Sink Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0007, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Coupled Sink Status bitmap */ - /* Not coupled/available for Coupling */ - wfdie[ wfdielen++ ] = 0; - /* MAC Addr. */ - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); - - return len; -} - -u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; - u32 len = 0, wfdielen = 0; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; - - /* WFD OUI */ - wfdielen = 0; - wfdie[ wfdielen++ ] = 0x50; - wfdie[ wfdielen++ ] = 0x6F; - wfdie[ wfdielen++ ] = 0x9A; - wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ - - /* Commented by Albert 20110825 */ - /* According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */ - /* 1. WFD Device Information */ - /* 2. Associated BSSID (Optional) */ - /* 3. Local IP Adress (Optional) */ - - /* WFD Device Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value1: */ - /* WFD device information */ - /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD, - wfdie + wfdielen); - wfdielen += 2; - - /* Value2: */ - /* Session Management Control Port */ - /* Default TCP port for RTSP messages is 554 */ - put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); - wfdielen += 2; - - /* Value3: */ - /* WFD Device Maximum Throughput */ - /* 300Mbps is the maximum throughput */ - put_unaligned_be16(300, wfdie + wfdielen); - wfdielen += 2; - - /* Associated BSSID ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Associated BSSID */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); - } - else - { - memset(wfdie + wfdielen, 0x00, ETH_ALEN); - } - - wfdielen += ETH_ALEN; - - /* Coupled Sink Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0007, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Coupled Sink Status bitmap */ - /* Not coupled/available for Coupling */ - wfdie[ wfdielen++ ] = 0; - /* MAC Addr. */ - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - - if (P2P_ROLE_GO == pwdinfo->role) - { - /* WFD Session Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_SESSION_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0000, wfdie + wfdielen); - wfdielen += 2; - - /* Todo: to add the list of WFD device info descriptor in WFD group. */ - - } - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); - - return len; -} - -u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; - u32 len = 0, wfdielen = 0; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; - - /* WFD OUI */ - wfdielen = 0; - wfdie[ wfdielen++ ] = 0x50; - wfdie[ wfdielen++ ] = 0x6F; - wfdie[ wfdielen++ ] = 0x9A; - wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ - - /* Commented by Albert 20110825 */ - /* According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */ - /* 1. WFD Device Information */ - /* 2. Associated BSSID (Optional) */ - /* 3. Local IP Adress (Optional) */ - - /* WFD Device Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value1: */ - /* WFD device information */ - /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD, - wfdie + wfdielen); - wfdielen += 2; - - /* Value2: */ - /* Session Management Control Port */ - /* Default TCP port for RTSP messages is 554 */ - put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); - wfdielen += 2; - - /* Value3: */ - /* WFD Device Maximum Throughput */ - /* 300Mbps is the maximum throughput */ - put_unaligned_be16(300, wfdie + wfdielen); - wfdielen += 2; - - /* Associated BSSID ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Associated BSSID */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); - } - else - { - memset(wfdie + wfdielen, 0x00, ETH_ALEN); - } - - wfdielen += ETH_ALEN; - - /* Coupled Sink Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0007, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Coupled Sink Status bitmap */ - /* Not coupled/available for Coupling */ - wfdie[ wfdielen++ ] = 0; - /* MAC Addr. */ - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - - if (P2P_ROLE_GO == pwdinfo->role) - { - /* WFD Session Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_SESSION_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0000, wfdie + wfdielen); - wfdielen += 2; - - /* Todo: to add the list of WFD device info descriptor in WFD group. */ - - } - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); - - return len; -} - -u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; - u32 len = 0, wfdielen = 0; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; - - /* WFD OUI */ - wfdielen = 0; - wfdie[ wfdielen++ ] = 0x50; - wfdie[ wfdielen++ ] = 0x6F; - wfdie[ wfdielen++ ] = 0x9A; - wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ - - /* Commented by Albert 20110825 */ - /* According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */ - /* 1. WFD Device Information */ - /* 2. Associated BSSID (Optional) */ - /* 3. Local IP Adress (Optional) */ - - /* WFD Device Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value1: */ - /* WFD device information */ - /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD, - wfdie + wfdielen); - wfdielen += 2; - - /* Value2: */ - /* Session Management Control Port */ - /* Default TCP port for RTSP messages is 554 */ - put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); - wfdielen += 2; - - /* Value3: */ - /* WFD Device Maximum Throughput */ - /* 300Mbps is the maximum throughput */ - put_unaligned_be16(300, wfdie + wfdielen); - wfdielen += 2; - - /* Associated BSSID ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Associated BSSID */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); - } - else - { - memset(wfdie + wfdielen, 0x00, ETH_ALEN); - } - - wfdielen += ETH_ALEN; - - /* Coupled Sink Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0007, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Coupled Sink Status bitmap */ - /* Not coupled/available for Coupling */ - wfdie[ wfdielen++ ] = 0; - /* MAC Addr. */ - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); - - return len; -} - -u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; - u32 len = 0, wfdielen = 0; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; - - /* WFD OUI */ - wfdielen = 0; - wfdie[ wfdielen++ ] = 0x50; - wfdie[ wfdielen++ ] = 0x6F; - wfdie[ wfdielen++ ] = 0x9A; - wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ - - /* Commented by Albert 20110825 */ - /* According to the WFD Specification, the provision discovery response frame should contain 3 WFD attributes */ - /* 1. WFD Device Information */ - /* 2. Associated BSSID (Optional) */ - /* 3. Local IP Adress (Optional) */ - - /* WFD Device Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value1: */ - /* WFD device information */ - /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - put_unaligned_be16(pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD, - wfdie + wfdielen); - wfdielen += 2; - - /* Value2: */ - /* Session Management Control Port */ - /* Default TCP port for RTSP messages is 554 */ - put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); - wfdielen += 2; - - /* Value3: */ - /* WFD Device Maximum Throughput */ - /* 300Mbps is the maximum throughput */ - put_unaligned_be16(300, wfdie + wfdielen); - wfdielen += 2; - - /* Associated BSSID ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0006, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Associated BSSID */ - if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - { - memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); - } - else - { - memset(wfdie + wfdielen, 0x00, ETH_ALEN); - } - - wfdielen += ETH_ALEN; - - /* Coupled Sink Information ATTR */ - /* Type: */ - wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; - - /* Length: */ - /* Note: In the WFD specification, the size of length field is 2. */ - put_unaligned_be16(0x0007, wfdie + wfdielen); - wfdielen += 2; - - /* Value: */ - /* Coupled Sink Status bitmap */ - /* Not coupled/available for Coupling */ - wfdie[ wfdielen++ ] = 0; - /* MAC Addr. */ - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - wfdie[ wfdielen++ ] = 0; - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); - - return len; -} - -#endif /* CONFIG_8723AU_P2P */ - -u32 build_probe_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; - u32 len = 0, p2pielen = 0; - - /* P2P OUI */ - p2pielen = 0; - p2pie[ p2pielen++ ] = 0x50; - p2pie[ p2pielen++ ] = 0x6F; - p2pie[ p2pielen++ ] = 0x9A; - p2pie[ p2pielen++ ] = 0x09; /* WFA P2P v1.0 */ - - /* Commented by Albert 20100907 */ - /* According to the P2P Specification, the probe response frame should contain 5 P2P attributes */ - /* 1. P2P Capability */ - /* 2. Extended Listen Timing */ - /* 3. Notice of Absence (NOA) (Only GO needs this) */ - /* 4. Device Info */ - /* 5. Group Info (Only GO need this) */ - - /* P2P Capability ATTR */ - /* Type: */ - p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY; - - /* Length: */ - /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */ - put_unaligned_le16(0x0002, p2pie + p2pielen); - p2pielen += 2; - - /* Value: */ - /* Device Capability Bitmap, 1 byte */ - p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT; - - /* Group Capability Bitmap, 1 byte */ - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - { - p2pie[ p2pielen ] = (P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS); - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) - p2pie[ p2pielen ] |= P2P_GRPCAP_GROUP_FORMATION; - - p2pielen++; - } - else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) - { - /* Group Capability Bitmap, 1 byte */ - if (pwdinfo->persistent_supported) - p2pie[ p2pielen++ ] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; - else - p2pie[ p2pielen++ ] = DMP_P2P_GRPCAP_SUPPORT; - } - - /* Extended Listen Timing ATTR */ - /* Type: */ - p2pie[ p2pielen++ ] = P2P_ATTR_EX_LISTEN_TIMING; - - /* Length: */ - /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); */ - put_unaligned_le16(0x0004, p2pie + p2pielen); - p2pielen += 2; - - /* Value: */ - /* Availability Period */ - /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */ - put_unaligned_le16(0xFFFF, p2pie + p2pielen); - p2pielen += 2; - - /* Availability Interval */ - /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */ - put_unaligned_le16(0xFFFF, p2pie + p2pielen); - p2pielen += 2; - - /* Notice of Absence ATTR */ - /* Type: */ - /* Length: */ - /* Value: */ - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - { - /* go_add_noa_attr(pwdinfo); */ - } - - /* Device Info ATTR */ - /* Type: */ - p2pie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO; - - /* Length: */ - /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ - /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ - /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */ - put_unaligned_le16(21 + pwdinfo->device_name_len, p2pie + p2pielen); - p2pielen += 2; - - /* Value: */ - /* P2P Device Address */ - memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); - p2pielen += ETH_ALEN; - - /* Config Method */ - /* This field should be big endian. Noted by P2P specification. */ - /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); */ - put_unaligned_be16(pwdinfo->supported_wps_cm, p2pie + p2pielen); - p2pielen += 2; - - /* Primary Device Type */ - /* Category ID */ - /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */ - put_unaligned_be16(WPS_PDT_CID_MULIT_MEDIA, p2pie + p2pielen); - p2pielen += 2; - - /* OUI */ - /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */ - put_unaligned_be32(WPSOUI, p2pie + p2pielen); - p2pielen += 4; - - /* Sub Category ID */ - /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */ - put_unaligned_be16(WPS_PDT_SCID_MEDIA_SERVER, p2pie + p2pielen); - p2pielen += 2; - - /* Number of Secondary Device Types */ - p2pie[ p2pielen++ ] = 0x00; /* No Secondary Device Type List */ - - /* Device Name */ - /* Type: */ - /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ - put_unaligned_be16(WPS_ATTR_DEVICE_NAME, p2pie + p2pielen); - p2pielen += 2; - - /* Length: */ - /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */ - put_unaligned_be16(pwdinfo->device_name_len, p2pie + p2pielen); - p2pielen += 2; - - /* Value: */ - memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); - p2pielen += pwdinfo->device_name_len; - - /* Group Info ATTR */ - /* Type: */ - /* Length: */ - /* Value: */ - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - { - p2pielen += go_add_group_info_attr(pwdinfo, p2pie + p2pielen); - } - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); - - return len; -} - -u32 build_prov_disc_request_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, u8* pssid, u8 ussidlen, u8* pdev_raddr) -{ - u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; - u32 len = 0, p2pielen = 0; - - /* P2P OUI */ - p2pielen = 0; - p2pie[ p2pielen++ ] = 0x50; - p2pie[ p2pielen++ ] = 0x6F; - p2pie[ p2pielen++ ] = 0x9A; - p2pie[ p2pielen++ ] = 0x09; /* WFA P2P v1.0 */ - - /* Commented by Albert 20110301 */ - /* According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */ - /* 1. P2P Capability */ - /* 2. Device Info */ - /* 3. Group ID (When joining an operating P2P Group) */ - - /* P2P Capability ATTR */ - /* Type: */ - p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY; - - /* Length: */ - /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */ - put_unaligned_le16(0x0002, p2pie + p2pielen); - p2pielen += 2; - - /* Value: */ - /* Device Capability Bitmap, 1 byte */ - p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT; - - /* Group Capability Bitmap, 1 byte */ - if (pwdinfo->persistent_supported) - p2pie[ p2pielen++ ] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; - else - p2pie[ p2pielen++ ] = DMP_P2P_GRPCAP_SUPPORT; - - /* Device Info ATTR */ - /* Type: */ - p2pie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO; - - /* Length: */ - /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ - /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ - /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */ - put_unaligned_le16(21 + pwdinfo->device_name_len, p2pie + p2pielen); - p2pielen += 2; - - /* Value: */ - /* P2P Device Address */ - memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); - p2pielen += ETH_ALEN; - - /* Config Method */ - /* This field should be big endian. Noted by P2P specification. */ - if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) - { - /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC); */ - put_unaligned_be16(WPS_CONFIG_METHOD_PBC, p2pie + p2pielen); - } - else - { - /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); */ - put_unaligned_be16(WPS_CONFIG_METHOD_DISPLAY, p2pie + p2pielen); - } - - p2pielen += 2; - - /* Primary Device Type */ - /* Category ID */ - /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */ - put_unaligned_be16(WPS_PDT_CID_MULIT_MEDIA, p2pie + p2pielen); - p2pielen += 2; - - /* OUI */ - /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */ - put_unaligned_be32(WPSOUI, p2pie + p2pielen); - p2pielen += 4; - - /* Sub Category ID */ - /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */ - put_unaligned_be16(WPS_PDT_SCID_MEDIA_SERVER, p2pie + p2pielen); - p2pielen += 2; - - /* Number of Secondary Device Types */ - p2pie[ p2pielen++ ] = 0x00; /* No Secondary Device Type List */ - - /* Device Name */ - /* Type: */ - /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ - put_unaligned_be16(WPS_ATTR_DEVICE_NAME, p2pie + p2pielen); - p2pielen += 2; - - /* Length: */ - /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */ - put_unaligned_be16(pwdinfo->device_name_len, p2pie + p2pielen); - p2pielen += 2; - - /* Value: */ - memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); - p2pielen += pwdinfo->device_name_len; - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) - { - /* Added by Albert 2011/05/19 */ - /* In this case, the pdev_raddr is the device address of the group owner. */ - - /* P2P Group ID ATTR */ - /* Type: */ - p2pie[ p2pielen++ ] = P2P_ATTR_GROUP_ID; - - /* Length: */ - /* u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + ussidlen); */ - put_unaligned_le16(ETH_ALEN + ussidlen, p2pie + p2pielen); - p2pielen += 2; - - /* Value: */ - memcpy(p2pie + p2pielen, pdev_raddr, ETH_ALEN); - p2pielen += ETH_ALEN; - - memcpy(p2pie + p2pielen, pssid, ussidlen); - p2pielen += ussidlen; - - } - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); - - return len; -} - -u32 build_assoc_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 status_code) -{ - u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; - u32 len = 0, p2pielen = 0; - - /* P2P OUI */ - p2pielen = 0; - p2pie[ p2pielen++ ] = 0x50; - p2pie[ p2pielen++ ] = 0x6F; - p2pie[ p2pielen++ ] = 0x9A; - p2pie[ p2pielen++ ] = 0x09; /* WFA P2P v1.0 */ - - /* According to the P2P Specification, the Association response frame should contain 2 P2P attributes */ - /* 1. Status */ - /* 2. Extended Listen Timing (optional) */ - - /* Status ATTR */ - p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status_code); - - /* Extended Listen Timing ATTR */ - /* Type: */ - /* Length: */ - /* Value: */ - - pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); - - return len; -} - -u32 build_deauth_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf) -{ - u32 len = 0; - - return len; -} - -u32 process_probe_req_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -{ - u8 *p; - u32 ret = false; - u8 *p2pie; - u32 p2pielen = 0; - int ssid_len = 0, rate_cnt = 0; - - p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + _PROBEREQ_IE_OFFSET_, _SUPPORTEDRATES_IE_, (int *)&rate_cnt, - len - sizeof(struct ieee80211_hdr_3addr) - _PROBEREQ_IE_OFFSET_); - - if (rate_cnt <= 4) - { - int i, g_rate = 0; - - for (i = 0; i < rate_cnt; i++) - { - if (((*(p + 2 + i) & 0xff) != 0x02) && - ((*(p + 2 + i) & 0xff) != 0x04) && - ((*(p + 2 + i) & 0xff) != 0x0B) && - ((*(p + 2 + i) & 0xff) != 0x16)) - { - g_rate = 1; - } - } - - if (g_rate == 0) - { - /* There is no OFDM rate included in SupportedRates IE of this probe request frame */ - /* The driver should response this probe request. */ - return ret; - } - } - else - { - /* rate_cnt > 4 means the SupportRates IE contains the OFDM rate because the count of CCK rates are 4. */ - /* We should proceed the following check for this probe request. */ - } - - /* Added comments by Albert 20100906 */ - /* There are several items we should check here. */ - /* 1. This probe request frame must contain the P2P IE. (Done) */ - /* 2. This probe request frame must contain the wildcard SSID. (Done) */ - /* 3. Wildcard BSSID. (Todo) */ - /* 4. Destination Address. (Done in mgt_dispatcher23a function) */ - /* 5. Requested Device Type in WSC IE. (Todo) */ - /* 6. Device ID attribute in P2P IE. (Todo) */ - - p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ssid_len, - len - sizeof(struct ieee80211_hdr_3addr) - _PROBEREQ_IE_OFFSET_); - - ssid_len &= 0xff; /* Just last 1 byte is valid for ssid len of the probe request */ - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - { - if ((p2pie = rtw_get_p2p_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + _PROBEREQ_IE_OFFSET_, len - sizeof(struct ieee80211_hdr_3addr) - _PROBEREQ_IE_OFFSET_, NULL, &p2pielen))) - { - if ((p) && !memcmp((void *)(p+2), (void *)pwdinfo->p2p_wildcard_ssid, 7)) - { - /* todo: */ - /* Check Requested Device Type attributes in WSC IE. */ - /* Check Device ID attribute in P2P IE */ - - ret = true; - } - else if ((p != NULL) && (ssid_len == 0)) - { - ret = true; - } - } - else - { - /* non -p2p device */ - } - - } - - return ret; -} - -u32 process_assoc_req_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len, struct sta_info *psta) -{ - u8 status_code = P2P_STATUS_SUCCESS; - u8 *pbuf, *pattr_content = NULL; - u32 attr_contentlen = 0; - u16 cap_attr = 0; - unsigned short ie_offset; - u8 * ies; - u32 ies_len; - u8 * p2p_ie; - u32 p2p_ielen = 0; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)pframe; - - if (!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - return P2P_STATUS_FAIL_REQUEST_UNABLE; - - if (ieee80211_is_assoc_req(hdr->frame_control)) - ie_offset = _ASOCREQ_IE_OFFSET_; - else /* WIFI_REASSOCREQ */ - ie_offset = _REASOCREQ_IE_OFFSET_; - - ies = pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset; - ies_len = len - sizeof(struct ieee80211_hdr_3addr) - ie_offset; - - p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen); - - if (!p2p_ie) - { - DBG_8723A("[%s] P2P IE not Found!!\n", __func__); - status_code = P2P_STATUS_FAIL_INVALID_PARAM; - } - else - { - DBG_8723A("[%s] P2P IE Found!!\n", __func__); - } - - while (p2p_ie) - { - /* Check P2P Capability ATTR */ - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*) &attr_contentlen)) - { - DBG_8723A("[%s] Got P2P Capability Attr!!\n", __func__); - cap_attr = le16_to_cpu(cap_attr); - psta->dev_cap = cap_attr&0xff; - } - - /* Check Extended Listen Timing ATTR */ - - /* Check P2P Device Info ATTR */ - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, NULL, (uint*)&attr_contentlen)) - { - DBG_8723A("[%s] Got P2P DEVICE INFO Attr!!\n", __func__); - pattr_content = pbuf = kzalloc(attr_contentlen, - GFP_ATOMIC); - if (pattr_content) { - u8 num_of_secdev_type; - u16 dev_name_len; - - rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, pattr_content, (uint*)&attr_contentlen); - - memcpy(psta->dev_addr, pattr_content, ETH_ALEN);/* P2P Device Address */ - - pattr_content += ETH_ALEN; - - memcpy(&psta->config_methods, pattr_content, 2);/* Config Methods */ - psta->config_methods = be16_to_cpu(psta->config_methods); - - pattr_content += 2; - - memcpy(psta->primary_dev_type, pattr_content, 8); - - pattr_content += 8; - - num_of_secdev_type = *pattr_content; - pattr_content += 1; - - if (num_of_secdev_type == 0) - { - psta->num_of_secdev_type = 0; - } - else - { - u32 len; - - psta->num_of_secdev_type = num_of_secdev_type; - - len = (sizeof(psta->secdev_types_list)<(num_of_secdev_type*8)) ? (sizeof(psta->secdev_types_list)) : (num_of_secdev_type*8); - - memcpy(psta->secdev_types_list, pattr_content, len); - - pattr_content += (num_of_secdev_type*8); - } - - /* dev_name_len = attr_contentlen - ETH_ALEN - 2 - 8 - 1 - (num_of_secdev_type*8); */ - psta->dev_name_len = 0; - if (WPS_ATTR_DEVICE_NAME == be16_to_cpu(*(u16*)pattr_content)) - { - dev_name_len = be16_to_cpu(*(u16*)(pattr_content+2)); - - psta->dev_name_len = (sizeof(psta->dev_name)dev_name):dev_name_len; - - memcpy(psta->dev_name, pattr_content+4, psta->dev_name_len); - } - - kfree(pbuf); - - } - - } - - /* Get the next P2P IE */ - p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); - - } - - return status_code; -} - -u32 process_p2p_devdisc_req23a(struct wifidirect_info *pwdinfo, u8 *pframe, - uint len) -{ - u8 *frame_body; - u8 status, dialogToken; - struct sta_info *psta = NULL; - struct rtw_adapter *padapter = pwdinfo->padapter; - struct sta_priv *pstapriv = &padapter->stapriv; - u8 *p2p_ie; - u32 p2p_ielen = 0; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) pframe; - - frame_body = (unsigned char *) - (pframe + sizeof(struct ieee80211_hdr_3addr)); - - dialogToken = frame_body[7]; - status = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP; - - if ((p2p_ie = rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, - len - _PUBLIC_ACTION_IE_OFFSET_, NULL, - &p2p_ielen))) { - u8 groupid[38] = { 0x00 }; - u8 dev_addr[ETH_ALEN] = { 0x00 }; - u32 attr_contentlen = 0; - - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, - P2P_ATTR_GROUP_ID, groupid, - &attr_contentlen)) { - if (!memcmp(pwdinfo->device_addr, groupid, ETH_ALEN) && - !memcmp(pwdinfo->p2p_group_ssid, groupid + ETH_ALEN, - pwdinfo->p2p_group_ssid_len)) { - attr_contentlen = 0; - - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, - P2P_ATTR_DEVICE_ID, - dev_addr, - &attr_contentlen)) { - struct list_head *phead, *plist, *ptmp; - - spin_lock_bh(&pstapriv->asoc_list_lock); - phead = &pstapriv->asoc_list; - - list_for_each_safe(plist, ptmp, phead) { - psta = container_of(plist, struct sta_info, asoc_list); - - if (psta->is_p2p_device && (psta->dev_cap&P2P_DEVCAP_CLIENT_DISCOVERABILITY) && - !memcmp(psta->dev_addr, dev_addr, ETH_ALEN)) - { - /* spin_unlock_bh(&pstapriv->asoc_list_lock); */ - /* issue GO Discoverability Request */ - issue_group_disc_req(pwdinfo, psta->hwaddr); - /* spin_lock_bh(&pstapriv->asoc_list_lock); */ - status = P2P_STATUS_SUCCESS; - break; - } else { - status = P2P_STATUS_FAIL_INFO_UNAVAILABLE; - } - } - spin_unlock_bh(&pstapriv->asoc_list_lock); - } else { - status = P2P_STATUS_FAIL_INVALID_PARAM; - } - } else { - status = P2P_STATUS_FAIL_INVALID_PARAM; - } - } - } - - /* issue Device Discoverability Response */ - issue_p2p_devdisc_resp(pwdinfo, hdr->addr2, status, dialogToken); - - return (status == P2P_STATUS_SUCCESS) ? true:false; -} - -u32 process_p2p_devdisc_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -{ - return true; -} - -u8 process_p2p_provdisc_req23a(struct wifidirect_info *pwdinfo, - u8 *pframe, uint len) -{ - u8 *frame_body; - u8 *wpsie; - u8 *ptr = NULL; - uint wps_ielen = 0, attr_contentlen = 0; - u16 uconfig_method = 0; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)pframe; - - frame_body = (pframe + sizeof(struct ieee80211_hdr_3addr)); - - wpsie = rtw_get_wps_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, - len - _PUBLIC_ACTION_IE_OFFSET_, NULL, - &wps_ielen); - if (!wpsie) - goto out; - - if (!rtw_get_wps_attr_content23a(wpsie, wps_ielen, WPS_ATTR_CONF_METHOD, - (u8 *)&uconfig_method, &attr_contentlen)) - goto out; - - uconfig_method = be16_to_cpu(uconfig_method); - ptr = pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req; - - switch (uconfig_method) - { - case WPS_CM_DISPLYA: - memcpy(ptr, "dis", 3); - break; - - case WPS_CM_LABEL: - memcpy(ptr, "lab", 3); - break; - - case WPS_CM_PUSH_BUTTON: - memcpy(ptr, "pbc", 3); - break; - - case WPS_CM_KEYPAD: - memcpy(ptr, "pad", 3); - break; - } - issue_p2p_provision_resp(pwdinfo, hdr->addr2, frame_body, - uconfig_method); - -out: - DBG_8723A("[%s] config method = %s\n", __func__, ptr); - - return true; -} - -u8 process_p2p_provdisc_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe) -{ - - return true; -} - -static u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 ch_cnt, u8 *peer_ch_list) -{ - u8 i = 0, j = 0; - u8 temp = 0; - u8 ch_no = 0; - ch_content += 3; - ch_cnt -= 3; - - while(ch_cnt > 0) - { - ch_content += 1; - ch_cnt -= 1; - temp = *ch_content; - for (i = 0 ; i < temp ; i++, j++) - { - peer_ch_list[j] = *(ch_content + 1 + i); - } - ch_content += (temp + 1); - ch_cnt -= (temp + 1); - ch_no += temp ; - } - - return ch_no; -} - -static u8 rtw_p2p_ch_inclusion(struct mlme_ext_priv *pmlmeext, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned) -{ - int i = 0, j = 0, temp = 0; - u8 ch_no = 0; - - for (i = 0; i < peer_ch_num; i++) - { - for (j = temp; j < pmlmeext->max_chan_nums; j++) - { - if (*(peer_ch_list + i) == pmlmeext->channel_set[ j ].ChannelNum) - { - ch_list_inclusioned[ ch_no++ ] = *(peer_ch_list + i); - temp = j; - break; - } - } - } - - return ch_no; -} - -u8 process_p2p_group_negotation_req23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -{ - struct rtw_adapter *padapter = pwdinfo->padapter; - u8 result = P2P_STATUS_SUCCESS; - u32 p2p_ielen = 0, wps_ielen = 0; - u8 * ies; - u32 ies_len; - u8 *p2p_ie; - u8 *wpsie; - u16 wps_devicepassword_id = 0x0000; - uint wps_devicepassword_id_len = 0; -#ifdef CONFIG_8723AU_P2P - u8 wfd_ie[MAX_WFD_IE_LEN] = { 0x00 }; - u32 wfd_ielen = 0; -#endif /* CONFIG_8723AU_P2P */ - - if ((wpsie = rtw_get_wps_ie23a(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen))) - { - /* Commented by Kurt 20120113 */ - /* If some device wants to do p2p handshake without sending prov_disc_req */ - /* We have to get peer_req_cm from here. */ - if (!memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) - { - rtw_get_wps_attr_content23a(wpsie, wps_ielen, WPS_ATTR_DEVICE_PWID, (u8*) &wps_devicepassword_id, &wps_devicepassword_id_len); - wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id); - - if (wps_devicepassword_id == WPS_DPID_USER_SPEC) - { - memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); - } - else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) - { - memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); - } - else - { - memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); - } - } - } - else - { - DBG_8723A("[%s] WPS IE not Found!!\n", __func__); - result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); - return result; - } - - if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO) - { - result = P2P_STATUS_FAIL_INFO_UNAVAILABLE; - rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INFOR_NOREADY); - return result; - } - - ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; - ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; - - p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen); - - if (!p2p_ie) - { - DBG_8723A("[%s] P2P IE not Found!!\n", __func__); - result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); - } - - while (p2p_ie) - { - u8 attr_content = 0x00; - u32 attr_contentlen = 0; - u8 ch_content[50] = { 0x00 }; - uint ch_cnt = 0; - u8 peer_ch_list[50] = { 0x00 }; - u8 peer_ch_num = 0; - u8 ch_list_inclusioned[50] = { 0x00 }; - u8 ch_num_inclusioned = 0; - u16 cap_attr; - - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING); - - /* Check P2P Capability ATTR */ - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*)&attr_contentlen)) - cap_attr = le16_to_cpu(cap_attr); - - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, &attr_content, &attr_contentlen)) - { - DBG_8723A("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01); - pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */ - - if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) - { - /* Try to match the tie breaker value */ - if (pwdinfo->intent == P2P_MAX_INTENT) - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - result = P2P_STATUS_FAIL_BOTH_GOINTENT_15; - } - else - { - if (attr_content & 0x01) - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); - } - else - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); - } - } - } - else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); - } - else - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); - } - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - { - /* Store the group id information. */ - memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN); - memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); - } - } - - attr_contentlen = 0; - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) - { - if (attr_contentlen != ETH_ALEN) - { - memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); - } - } - - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, ch_content, &ch_cnt)) - { - peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, ch_content, ch_cnt, peer_ch_list); - ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned); - - if (ch_num_inclusioned == 0) - { - DBG_8723A("[%s] No common channel in channel list!\n", __func__); - result = P2P_STATUS_FAIL_NO_COMMON_CH; - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); - break; - } - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - { - if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel, - ch_list_inclusioned, ch_num_inclusioned)) - { - { - u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0; - attr_contentlen = 0; - - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) - { - peer_operating_ch = operatingch_info[4]; - } - - if (rtw_p2p_is_channel_list_ok(peer_operating_ch, - ch_list_inclusioned, ch_num_inclusioned)) - { - /** - * Change our operating channel as peer's for compatibility. - */ - pwdinfo->operating_channel = peer_operating_ch; - DBG_8723A("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel); - } - else - { - /* Take first channel of ch_list_inclusioned as operating channel */ - pwdinfo->operating_channel = ch_list_inclusioned[0]; - DBG_8723A("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel); - } - } - - } - } - } - - /* Get the next P2P IE */ - p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); - } - -#ifdef CONFIG_8723AU_P2P - /* Added by Albert 20110823 */ - /* Try to get the TCP port information when receiving the negotiation request. */ - if (rtw_get_wfd_ie(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wfd_ie, &wfd_ielen)) - { - u8 attr_content[ 10 ] = { 0x00 }; - u32 attr_contentlen = 0; - - DBG_8723A("[%s] WFD IE Found!!\n", __func__); - rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); - if (attr_contentlen) - { - pwdinfo->wfd_info->peer_rtsp_ctrlport = get_unaligned_be16(attr_content + 2); - DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport); - } - } -#endif /* CONFIG_8723AU_P2P */ - - return result; -} - -u8 process_p2p_group_negotation_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -{ - struct rtw_adapter *padapter = pwdinfo->padapter; - u8 result = P2P_STATUS_SUCCESS; - u32 p2p_ielen, wps_ielen; - u8 * ies; - u32 ies_len; - u8 * p2p_ie; -#ifdef CONFIG_8723AU_P2P - u8 wfd_ie[MAX_WFD_IE_LEN] = { 0x00 }; - u32 wfd_ielen = 0; -#endif /* CONFIG_8723AU_P2P */ - - ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; - ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; - - /* Be able to know which one is the P2P GO and which one is P2P client. */ - - if (rtw_get_wps_ie23a(ies, ies_len, NULL, &wps_ielen)) - { - - } - else - { - DBG_8723A("[%s] WPS IE not Found!!\n", __func__); - result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); - } - - p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen); - if (!p2p_ie) - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); - result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; - } - else - { - - u8 attr_content = 0x00; - u32 attr_contentlen = 0; - u8 operatingch_info[5] = { 0x00 }; - u8 groupid[ 38 ]; - u16 cap_attr; - u8 peer_ch_list[50] = { 0x00 }; - u8 peer_ch_num = 0; - u8 ch_list_inclusioned[50] = { 0x00 }; - u8 ch_num_inclusioned = 0; - - while (p2p_ie) /* Found the P2P IE. */ - { - - /* Check P2P Capability ATTR */ - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*)&attr_contentlen)) - cap_attr = le16_to_cpu(cap_attr); - - rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); - if (attr_contentlen == 1) - { - DBG_8723A("[%s] Status = %d\n", __func__, attr_content); - if (attr_content == P2P_STATUS_SUCCESS) - { - /* Do nothing. */ - } - else - { - if (P2P_STATUS_FAIL_INFO_UNAVAILABLE == attr_content) { - rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INFOR_NOREADY); - } else { - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); - } - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - result = attr_content; - break; - } - } - - /* Try to get the peer's interface address */ - attr_contentlen = 0; - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) - { - if (attr_contentlen != ETH_ALEN) - { - memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); - } - } - - /* Try to get the peer's intent and tie breaker value. */ - attr_content = 0x00; - attr_contentlen = 0; - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, &attr_content, &attr_contentlen)) - { - DBG_8723A("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01); - pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */ - - if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) - { - /* Try to match the tie breaker value */ - if (pwdinfo->intent == P2P_MAX_INTENT) - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - result = P2P_STATUS_FAIL_BOTH_GOINTENT_15; - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); - } - else - { - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); - rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); - if (attr_content & 0x01) - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); - } - else - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); - } - } - } - else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) - { - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); - rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); - rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); - } - else - { - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); - rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); - rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); - } - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - { - /* Store the group id information. */ - memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN); - memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); - - } - } - - /* Try to get the operation channel information */ - - attr_contentlen = 0; - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) - { - DBG_8723A("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]); - pwdinfo->peer_operating_ch = operatingch_info[4]; - } - - /* Try to get the channel list information */ - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, pwdinfo->channel_list_attr, &pwdinfo->channel_list_attr_len)) - { - DBG_8723A("[%s] channel list attribute found, len = %d\n", __func__, pwdinfo->channel_list_attr_len); - - peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len, peer_ch_list); - ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned); - - if (ch_num_inclusioned == 0) - { - DBG_8723A("[%s] No common channel in channel list!\n", __func__); - result = P2P_STATUS_FAIL_NO_COMMON_CH; - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); - break; - } - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) - { - if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel, - ch_list_inclusioned, ch_num_inclusioned)) - { - { - u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0; - attr_contentlen = 0; - - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) - { - peer_operating_ch = operatingch_info[4]; - } - - if (rtw_p2p_is_channel_list_ok(peer_operating_ch, - ch_list_inclusioned, ch_num_inclusioned)) - { - /** - * Change our operating channel as peer's for compatibility. - */ - pwdinfo->operating_channel = peer_operating_ch; - DBG_8723A("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel); - } - else - { - /* Take first channel of ch_list_inclusioned as operating channel */ - pwdinfo->operating_channel = ch_list_inclusioned[0]; - DBG_8723A("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel); - } - } - - } - } - - } - else - { - DBG_8723A("[%s] channel list attribute not found!\n", __func__); - } - - /* Try to get the group id information if peer is GO */ - attr_contentlen = 0; - memset(groupid, 0x00, 38); - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) - { - memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN); - memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN); - } - - /* Get the next P2P IE */ - p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); - } - - } - -#ifdef CONFIG_8723AU_P2P - /* Added by Albert 20111122 */ - /* Try to get the TCP port information when receiving the negotiation response. */ - if (rtw_get_wfd_ie(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wfd_ie, &wfd_ielen)) - { - u8 attr_content[ 10 ] = { 0x00 }; - u32 attr_contentlen = 0; - - DBG_8723A("[%s] WFD IE Found!!\n", __func__); - rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); - if (attr_contentlen) - { - pwdinfo->wfd_info->peer_rtsp_ctrlport = get_unaligned_be16(attr_content + 2); - DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport); - } - } -#endif /* CONFIG_8723AU_P2P */ - - return result; -} - -u8 process_p2p_group_negotation_confirm23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -{ - u8 * ies; - u32 ies_len; - u8 * p2p_ie; - u32 p2p_ielen = 0; - u8 result = P2P_STATUS_SUCCESS; - ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; - ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; - - p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen); - while (p2p_ie) /* Found the P2P IE. */ - { - u8 attr_content = 0x00, operatingch_info[5] = { 0x00 }; - u8 groupid[ 38 ] = { 0x00 }; - u32 attr_contentlen = 0; - - pwdinfo->negotiation_dialog_token = 1; - rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); - if (attr_contentlen == 1) - { - DBG_8723A("[%s] Status = %d\n", __func__, attr_content); - result = attr_content; - - if (attr_content == P2P_STATUS_SUCCESS) - { - del_timer_sync(&pwdinfo->restore_p2p_state_timer); - - /* Commented by Albert 20100911 */ - /* Todo: Need to handle the case which both Intents are the same. */ - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); - rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); - if ((pwdinfo->intent) > (pwdinfo->peer_intent >> 1)) - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); - } - else if ((pwdinfo->intent) < (pwdinfo->peer_intent >> 1)) - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); - } - else - { - /* Have to compare the Tie Breaker */ - if (pwdinfo->peer_intent & 0x01) - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); - } - else - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); - } - } - } - else - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); - break; - } - } - - /* Try to get the group id information */ - attr_contentlen = 0; - memset(groupid, 0x00, 38); - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) - { - DBG_8723A("[%s] Ssid = %s, ssidlen = %zu\n", __func__, &groupid[ETH_ALEN], strlen(&groupid[ETH_ALEN])); - memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN); - memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN); - } - - attr_contentlen = 0; - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) - { - DBG_8723A("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]); - pwdinfo->peer_operating_ch = operatingch_info[4]; - } - - /* Get the next P2P IE */ - p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); - - } - - return result; -} - -u8 process_p2p_presence_req23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -{ - u8 *frame_body; - u8 dialogToken = 0; - u8 status = P2P_STATUS_SUCCESS; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) pframe; - - frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr)); - - dialogToken = frame_body[6]; - - /* todo: check NoA attribute */ - - issue_p2p_presence_resp(pwdinfo, hdr->addr2, status, dialogToken); - - return true; -} - -static void find_phase_handler(struct rtw_adapter *padapter) -{ - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct cfg80211_ssid ssid; - u8 _status = 0; - - - - memset((unsigned char*)&ssid, 0, sizeof(struct cfg80211_ssid)); - memcpy(ssid.ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN); - ssid.ssid_len = P2P_WILDCARD_SSID_LEN; - - rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); - - spin_lock_bh(&pmlmepriv->lock); - _status = rtw_sitesurvey_cmd23a(padapter, &ssid, 1, NULL, 0); - spin_unlock_bh(&pmlmepriv->lock); - - -} - -void p2p_concurrent_handler(struct rtw_adapter* padapter); - -static void restore_p2p_state_handler(struct rtw_adapter *padapter) -{ - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - - rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) { - /* In the P2P client mode, the driver should not switch back to its listen channel */ - /* because this P2P client should stay at the operating channel of P2P GO. */ - set_channel_bwmode23a(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); - } -} - -static void pre_tx_invitereq_handler(struct rtw_adapter *padapter) -{ - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 val8 = 1; - - set_channel_bwmode23a(padapter, pwdinfo->invitereq_info.peer_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); - padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); - issue23a_probereq_p2p(padapter, NULL); - mod_timer(&pwdinfo->pre_tx_scan_timer, - jiffies + msecs_to_jiffies(P2P_TX_PRESCAN_TIMEOUT)); - - -} - -static void pre_tx_provdisc_handler(struct rtw_adapter *padapter) -{ - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 val8 = 1; - - - set_channel_bwmode23a(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); - issue23a_probereq_p2p(padapter, NULL); - mod_timer(&pwdinfo->pre_tx_scan_timer, - jiffies + msecs_to_jiffies(P2P_TX_PRESCAN_TIMEOUT)); - - -} - -static void pre_tx_negoreq_handler(struct rtw_adapter *padapter) -{ - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 val8 = 1; - - - set_channel_bwmode23a(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); - issue23a_probereq_p2p(padapter, NULL); - mod_timer(&pwdinfo->pre_tx_scan_timer, - jiffies + msecs_to_jiffies(P2P_TX_PRESCAN_TIMEOUT)); - - -} - -static void ro_ch_handler(struct rtw_adapter *padapter) -{ - struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - - if (pcfg80211_wdinfo->restore_channel != pmlmeext->cur_channel) { - if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) - pmlmeext->cur_channel = pcfg80211_wdinfo->restore_channel; - - set_channel_bwmode23a(padapter, pmlmeext->cur_channel, - HAL_PRIME_CHNL_OFFSET_DONT_CARE, - HT_CHANNEL_WIDTH_20); - } - - rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); - - pcfg80211_wdinfo->is_ro_ch = false; - - DBG_8723A("cfg80211_remain_on_channel_expired\n"); - - rtw_cfg80211_remain_on_channel_expired(padapter, - pcfg80211_wdinfo->remain_on_ch_cookie, - &pcfg80211_wdinfo->remain_on_ch_channel, - pcfg80211_wdinfo->remain_on_ch_type, GFP_KERNEL); -} - -static void ro_ch_timer_process (unsigned long data) -{ - struct rtw_adapter *adapter = (struct rtw_adapter *)data; - - p2p_protocol_wk_cmd23a(adapter, P2P_RO_CH_WK); -} - -#ifdef CONFIG_8723AU_P2P -void rtw_append_wfd_ie(struct rtw_adapter *padapter, u8 *buf, u32* len) -{ - unsigned char *frame_body; - u8 category, action, OUI_Subtype, dialogToken = 0; - u32 wfdielen = 0; - - frame_body = (unsigned char *)(buf + sizeof(struct ieee80211_hdr_3addr)); - category = frame_body[0]; - - if (category == WLAN_CATEGORY_PUBLIC) { - action = frame_body[1]; - if (action == ACT_PUBLIC_VENDOR && - !memcmp(frame_body+2, P2P_OUI23A, 4)) { - OUI_Subtype = frame_body[6]; - dialogToken = frame_body[7]; - switch (OUI_Subtype)/* OUI Subtype */ { - case P2P_GO_NEGO_REQ: - wfdielen = build_nego_req_wfd_ie(&padapter->wdinfo, buf + (*len)); - (*len) += wfdielen; - break; - case P2P_GO_NEGO_RESP: - wfdielen = build_nego_resp_wfd_ie(&padapter->wdinfo, buf + (*len)); - (*len) += wfdielen; - break; - case P2P_GO_NEGO_CONF: - wfdielen = build_nego_confirm_wfd_ie(&padapter->wdinfo, buf + (*len)); - (*len) += wfdielen; - break; - case P2P_INVIT_REQ: - wfdielen = build_invitation_req_wfd_ie(&padapter->wdinfo, buf + (*len)); - (*len) += wfdielen; - break; - case P2P_INVIT_RESP: - wfdielen = build_invitation_resp_wfd_ie(&padapter->wdinfo, buf + (*len)); - (*len) += wfdielen; - break; - case P2P_DEVDISC_REQ: - break; - case P2P_DEVDISC_RESP: - break; - case P2P_PROVISION_DISC_REQ: - wfdielen = build_provdisc_req_wfd_ie(&padapter->wdinfo, buf + (*len)); - (*len) += wfdielen; - break; - case P2P_PROVISION_DISC_RESP: - wfdielen = build_provdisc_resp_wfd_ie(&padapter->wdinfo, buf + (*len)); - (*len) += wfdielen; - break; - default: - break; - } - } - } else if (category == WLAN_CATEGORY_VENDOR_SPECIFIC) { - OUI_Subtype = frame_body[5]; - dialogToken = frame_body[6]; - } else { - DBG_8723A("%s, action frame category =%d\n", __func__, category); - } -} -#endif - -int rtw_p2p_check_frames(struct rtw_adapter *padapter, const u8 *buf, u32 len, u8 tx) -{ - int is_p2p_frame = (-1); - unsigned char *frame_body; - u8 category, action, OUI_Subtype, dialogToken = 0; - u8 *p2p_ie = NULL; - uint p2p_ielen = 0; - struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); - - frame_body = (unsigned char *)(buf + sizeof(struct ieee80211_hdr_3addr)); - category = frame_body[0]; - /* just for check */ - if (category == WLAN_CATEGORY_PUBLIC) - { - action = frame_body[1]; - if (action == ACT_PUBLIC_VENDOR && - !memcmp(frame_body+2, P2P_OUI23A, 4)) { - OUI_Subtype = frame_body[6]; - dialogToken = frame_body[7]; - is_p2p_frame = OUI_Subtype; - p2p_ie = rtw_get_p2p_ie23a( - (u8 *)buf+sizeof(struct ieee80211_hdr_3addr)+_PUBLIC_ACTION_IE_OFFSET_, - len-sizeof(struct ieee80211_hdr_3addr)-_PUBLIC_ACTION_IE_OFFSET_, - NULL, &p2p_ielen); - - switch (OUI_Subtype) {/* OUI Subtype */ - u8 *cont; - uint cont_len; - case P2P_GO_NEGO_REQ: - DBG_8723A("RTW_%s:P2P_GO_NEGO_REQ, dialogToken =%d\n", (tx == true)?"Tx":"Rx", dialogToken); - break; - case P2P_GO_NEGO_RESP: - cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len); - DBG_8723A("RTW_%s:P2P_GO_NEGO_RESP, dialogToken =%d, status:%d\n", (tx == true)?"Tx":"Rx", dialogToken, cont?*cont:-1); - - if (!tx) - pwdev_priv->provdisc_req_issued = false; - break; - case P2P_GO_NEGO_CONF: - cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len); - DBG_8723A("RTW_%s:P2P_GO_NEGO_CONF, dialogToken =%d, status:%d\n", - (tx == true)?"Tx":"Rx", dialogToken, cont?*cont:-1); - break; - case P2P_INVIT_REQ: - { - struct rtw_wdev_invit_info* invit_info = &pwdev_priv->invit_info; - int flags = -1; - int op_ch = 0; - - if ((cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, NULL, &cont_len))) - flags = *cont; - if ((cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len))) - op_ch = *(cont+4); - - if (invit_info->token != dialogToken) - rtw_wdev_invit_info_init(invit_info); - - invit_info->token = dialogToken; - invit_info->flags = (flags ==-1) ? 0x0 : flags; - invit_info->req_op_ch = op_ch; - - DBG_8723A("RTW_%s:P2P_INVIT_REQ, dialogToken =%d, flags:0x%02x, op_ch:%d\n", - (tx) ? "Tx" : "Rx", dialogToken, flags, op_ch); - break; - } - case P2P_INVIT_RESP: - { - struct rtw_wdev_invit_info* invit_info = &pwdev_priv->invit_info; - int status = -1; - int op_ch = 0; - - if ((cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len))) - status = *cont; - if ((cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len))) - op_ch = *(cont+4); - - if (invit_info->token != dialogToken) { - rtw_wdev_invit_info_init(invit_info); - } else { - invit_info->token = 0; - invit_info->status = (status ==-1) ? 0xff : status; - invit_info->rsp_op_ch = op_ch; - } - - DBG_8723A("RTW_%s:P2P_INVIT_RESP, dialogToken =%d, status:%d, op_ch:%d\n", - (tx == true)?"Tx":"Rx", dialogToken, status, op_ch); - break; - } - case P2P_DEVDISC_REQ: - DBG_8723A("RTW_%s:P2P_DEVDISC_REQ, dialogToken =%d\n", (tx == true)?"Tx":"Rx", dialogToken); - break; - case P2P_DEVDISC_RESP: - cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len); - DBG_8723A("RTW_%s:P2P_DEVDISC_RESP, dialogToken =%d, status:%d\n", (tx == true)?"Tx":"Rx", dialogToken, cont?*cont:-1); - break; - case P2P_PROVISION_DISC_REQ: - { - size_t frame_body_len = len - sizeof(struct ieee80211_hdr_3addr); - u8 *p2p_ie; - uint p2p_ielen = 0; - uint contentlen = 0; - - DBG_8723A("RTW_%s:P2P_PROVISION_DISC_REQ, dialogToken =%d\n", (tx == true)?"Tx":"Rx", dialogToken); - - pwdev_priv->provdisc_req_issued = false; - - p2p_ie = rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, - frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, - NULL, &p2p_ielen); - if (p2p_ie) { - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, NULL, &contentlen)) - pwdev_priv->provdisc_req_issued = false;/* case: p2p_client join p2p GO */ - else - pwdev_priv->provdisc_req_issued = true;/* case: p2p_devices connection before Nego req. */ - } - } - break; - case P2P_PROVISION_DISC_RESP: - DBG_8723A("RTW_%s:P2P_PROVISION_DISC_RESP, dialogToken =%d\n", (tx == true)?"Tx":"Rx", dialogToken); - break; - default: - DBG_8723A("RTW_%s:OUI_Subtype =%d, dialogToken =%d\n", (tx == true)?"Tx":"Rx", OUI_Subtype, dialogToken); - break; - } - - } - - } - else if (category == WLAN_CATEGORY_VENDOR_SPECIFIC) - { - OUI_Subtype = frame_body[5]; - dialogToken = frame_body[6]; - - is_p2p_frame = OUI_Subtype; - - switch (OUI_Subtype) { - case P2P_NOTICE_OF_ABSENCE: - DBG_8723A("RTW_%s:P2P_NOTICE_OF_ABSENCE, dialogToken =%d\n", (tx == true)?"TX":"RX", dialogToken); - break; - case P2P_PRESENCE_REQUEST: - DBG_8723A("RTW_%s:P2P_PRESENCE_REQUEST, dialogToken =%d\n", (tx == true)?"TX":"RX", dialogToken); - break; - case P2P_PRESENCE_RESPONSE: - DBG_8723A("RTW_%s:P2P_PRESENCE_RESPONSE, dialogToken =%d\n", (tx == true)?"TX":"RX", dialogToken); - break; - case P2P_GO_DISC_REQUEST: - DBG_8723A("RTW_%s:P2P_GO_DISC_REQUEST, dialogToken =%d\n", (tx == true)?"TX":"RX", dialogToken); - break; - default: - DBG_8723A("RTW_%s:OUI_Subtype =%d, dialogToken =%d\n", (tx == true)?"TX":"RX", OUI_Subtype, dialogToken); - break; - } - - } else { - DBG_8723A("RTW_%s:action frame category =%d\n", (tx == true)?"TX":"RX", category); - } - return is_p2p_frame; -} - -void rtw_init_cfg80211_wifidirect_info(struct rtw_adapter *padapter) -{ - struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; - - memset(pcfg80211_wdinfo, 0x00, sizeof(struct cfg80211_wifidirect_info)); - - setup_timer(&pcfg80211_wdinfo->remain_on_ch_timer, - ro_ch_timer_process, (unsigned long)padapter); -} - -void p2p_protocol_wk_hdl23a(struct rtw_adapter *padapter, int intCmdType) -{ - switch (intCmdType) { - case P2P_FIND_PHASE_WK: - find_phase_handler(padapter); - break; - case P2P_RESTORE_STATE_WK: - restore_p2p_state_handler(padapter); - break; - case P2P_PRE_TX_PROVDISC_PROCESS_WK: - pre_tx_provdisc_handler(padapter); - break; - case P2P_PRE_TX_INVITEREQ_PROCESS_WK: - pre_tx_invitereq_handler(padapter); - break; - case P2P_PRE_TX_NEGOREQ_PROCESS_WK: - pre_tx_negoreq_handler(padapter); - break; - case P2P_RO_CH_WK: - ro_ch_handler(padapter); - break; - } -} - -#ifdef CONFIG_8723AU_P2P -void process_p2p_ps_ie23a(struct rtw_adapter *padapter, u8 *IEs, u32 IELength) -{ - u8 * ies; - u32 ies_len; - u8 * p2p_ie; - u32 p2p_ielen = 0; - u8 noa_attr[MAX_P2P_IE_LEN] = { 0x00 };/* NoA length should be n*(13) + 2 */ - u32 attr_contentlen = 0; - - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 find_p2p = false, find_p2p_ps = false; - u8 noa_offset, noa_num, noa_index; - - - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) - { - return; - } - if (IELength <= _BEACON_IE_OFFSET_) - return; - - ies = IEs + _BEACON_IE_OFFSET_; - ies_len = IELength - _BEACON_IE_OFFSET_; - - p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen); - - while(p2p_ie) - { - find_p2p = true; - /* Get Notice of Absence IE. */ - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_NOA, noa_attr, &attr_contentlen)) - { - find_p2p_ps = true; - noa_index = noa_attr[0]; - - if ((pwdinfo->p2p_ps_mode == P2P_PS_NONE) || - (noa_index != pwdinfo->noa_index))/* if index change, driver should reconfigure related setting. */ - { - pwdinfo->noa_index = noa_index; - pwdinfo->opp_ps = noa_attr[1] >> 7; - pwdinfo->ctwindow = noa_attr[1] & 0x7F; - - noa_offset = 2; - noa_num = 0; - /* NoA length should be n*(13) + 2 */ - if (attr_contentlen > 2) - { - while(noa_offset < attr_contentlen) - { - /* memcpy(&wifidirect_info->noa_count[noa_num], &noa_attr[noa_offset], 1); */ - pwdinfo->noa_count[noa_num] = noa_attr[noa_offset]; - noa_offset += 1; - - memcpy(&pwdinfo->noa_duration[noa_num], &noa_attr[noa_offset], 4); - noa_offset += 4; - - memcpy(&pwdinfo->noa_interval[noa_num], &noa_attr[noa_offset], 4); - noa_offset += 4; - - memcpy(&pwdinfo->noa_start_time[noa_num], &noa_attr[noa_offset], 4); - noa_offset += 4; - - noa_num++; - } - } - pwdinfo->noa_num = noa_num; - - if (pwdinfo->opp_ps == 1) - { - pwdinfo->p2p_ps_mode = P2P_PS_CTWINDOW; - /* driver should wait LPS for entering CTWindow */ - if (padapter->pwrctrlpriv.bFwCurrentInPSMode == true) - { - p2p_ps_wk_cmd23a(padapter, P2P_PS_ENABLE, 1); - } - } - else if (pwdinfo->noa_num > 0) - { - pwdinfo->p2p_ps_mode = P2P_PS_NOA; - p2p_ps_wk_cmd23a(padapter, P2P_PS_ENABLE, 1); - } - else if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) - { - p2p_ps_wk_cmd23a(padapter, P2P_PS_DISABLE, 1); - } - } - - break; /* find target, just break. */ - } - - /* Get the next P2P IE */ - p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); - - } - - if (find_p2p == true) - { - if ((pwdinfo->p2p_ps_mode > P2P_PS_NONE) && (find_p2p_ps == false)) - { - p2p_ps_wk_cmd23a(padapter, P2P_PS_DISABLE, 1); - } - } - - -} - -void p2p_ps_wk_hdl23a(struct rtw_adapter *padapter, u8 p2p_ps_state) -{ - struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - - - - /* Pre action for p2p state */ - switch (p2p_ps_state) - { - case P2P_PS_DISABLE: - pwdinfo->p2p_ps_state = p2p_ps_state; - - rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); - - pwdinfo->noa_index = 0; - pwdinfo->ctwindow = 0; - pwdinfo->opp_ps = 0; - pwdinfo->noa_num = 0; - pwdinfo->p2p_ps_mode = P2P_PS_NONE; - if (padapter->pwrctrlpriv.bFwCurrentInPSMode == true) - { - if (pwrpriv->smart_ps == 0) - { - pwrpriv->smart_ps = 2; - rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)&padapter->pwrctrlpriv.pwr_mode); - } - } - break; - case P2P_PS_ENABLE: - if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { - pwdinfo->p2p_ps_state = p2p_ps_state; - - if (pwdinfo->ctwindow > 0) - { - if (pwrpriv->smart_ps != 0) - { - pwrpriv->smart_ps = 0; - DBG_8723A("%s(): Enter CTW, change SmartPS\n", __func__); - rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)&padapter->pwrctrlpriv.pwr_mode); - } - } - rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); - } - break; - case P2P_PS_SCAN: - case P2P_PS_SCAN_DONE: - case P2P_PS_ALLSTASLEEP: - if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { - pwdinfo->p2p_ps_state = p2p_ps_state; - rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); - } - break; - default: - break; - } - - -} - -u8 p2p_ps_wk_cmd23a(struct rtw_adapter*padapter, u8 p2p_ps_state, u8 enqueue) -{ - struct cmd_obj *ph2c; - struct drvextra_cmd_parm *pdrvextra_cmd_parm; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - u8 res = _SUCCESS; - - - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) - return res; - - if (enqueue) { - ph2c = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), - GFP_ATOMIC); - if (!ph2c) { - res = _FAIL; - goto exit; - } - - pdrvextra_cmd_parm = (struct drvextra_cmd_parm *) - kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); - if (pdrvextra_cmd_parm == NULL) { - kfree(ph2c); - res = _FAIL; - goto exit; - } - - pdrvextra_cmd_parm->ec_id = P2P_PS_WK_CID; - pdrvextra_cmd_parm->type_size = p2p_ps_state; - pdrvextra_cmd_parm->pbuf = NULL; - - init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); - - res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); - } - else - { - p2p_ps_wk_hdl23a(padapter, p2p_ps_state); - } - -exit: - - - - return res; -} -#endif /* CONFIG_8723AU_P2P */ - -static void reset_ch_sitesurvey_timer_process(unsigned long data) -{ - struct rtw_adapter *adapter = (struct rtw_adapter *)data; - struct wifidirect_info *pwdinfo = &adapter->wdinfo; - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) - return; - - DBG_8723A("[%s] In\n", __func__); - /* Reset the operation channel information */ - pwdinfo->rx_invitereq_info.operation_ch[0] = 0; - pwdinfo->rx_invitereq_info.scan_op_ch_only = 0; -} - -static void reset_ch_sitesurvey_timer_process2(unsigned long data) -{ - struct rtw_adapter *adapter = (struct rtw_adapter *)data; - struct wifidirect_info *pwdinfo = &adapter->wdinfo; - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) - return; - - DBG_8723A("[%s] In\n", __func__); - /* Reset the operation channel information */ - pwdinfo->p2p_info.operation_ch[0] = 0; - pwdinfo->p2p_info.scan_op_ch_only = 0; -} - -static void restore_p2p_state_timer_process (unsigned long data) -{ - struct rtw_adapter *adapter = (struct rtw_adapter *)data; - struct wifidirect_info *pwdinfo = &adapter->wdinfo; - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) - return; - - p2p_protocol_wk_cmd23a(adapter, P2P_RESTORE_STATE_WK); -} - -static void pre_tx_scan_timer_process (unsigned long data) -{ - struct rtw_adapter *adapter = (struct rtw_adapter *)data; - struct wifidirect_info *pwdinfo = &adapter->wdinfo; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) - return; - - spin_lock_bh(&pmlmepriv->lock); - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) - { - if (true == pwdinfo->tx_prov_disc_info.benable) /* the provision discovery request frame is trigger to send or not */ - { - p2p_protocol_wk_cmd23a(adapter, P2P_PRE_TX_PROVDISC_PROCESS_WK); - /* issue23a_probereq_p2p(adapter, NULL); */ - /* _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); */ - } - } - else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) - { - if (true == pwdinfo->nego_req_info.benable) - { - p2p_protocol_wk_cmd23a(adapter, P2P_PRE_TX_NEGOREQ_PROCESS_WK); - } - } - else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) - { - if (true == pwdinfo->invitereq_info.benable) - { - p2p_protocol_wk_cmd23a(adapter, P2P_PRE_TX_INVITEREQ_PROCESS_WK); - } - } - else - { - DBG_8723A("[%s] p2p_state is %d, ignore!!\n", __func__, rtw_p2p_state(pwdinfo)); - } - - spin_unlock_bh(&pmlmepriv->lock); -} - -static void find_phase_timer_process (unsigned long data) -{ - struct rtw_adapter *adapter = (struct rtw_adapter *)data; - struct wifidirect_info *pwdinfo = &adapter->wdinfo; - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) - return; - - adapter->wdinfo.find_phase_state_exchange_cnt++; - - p2p_protocol_wk_cmd23a(adapter, P2P_FIND_PHASE_WK); -} - -void reset_global_wifidirect_info23a(struct rtw_adapter *padapter) -{ - struct wifidirect_info *pwdinfo; - - pwdinfo = &padapter->wdinfo; - pwdinfo->persistent_supported = 0; - pwdinfo->session_available = true; - pwdinfo->wfd_tdls_enable = 0; - pwdinfo->wfd_tdls_weaksec = 0; -} - -#ifdef CONFIG_8723AU_P2P -int rtw_init_wifi_display_info(struct rtw_adapter* padapter) -{ - int res = _SUCCESS; - struct wifi_display_info *pwfd_info = &padapter->wfd_info; - - /* Used in P2P and TDLS */ - pwfd_info->rtsp_ctrlport = 554; - pwfd_info->peer_rtsp_ctrlport = 0; /* Reset to 0 */ - pwfd_info->wfd_enable = false; - pwfd_info->wfd_device_type = WFD_DEVINFO_PSINK; - pwfd_info->scan_result_type = SCAN_RESULT_P2P_ONLY; - - /* Used in P2P */ - pwfd_info->peer_session_avail = true; - pwfd_info->wfd_pc = false; - - /* Used in TDLS */ - memset(pwfd_info->ip_address, 0x00, 4); - memset(pwfd_info->peer_ip_address, 0x00, 4); - return res; -} -#endif /* CONFIG_8723AU_P2P */ - -void rtw_init_wifidirect_timers23a(struct rtw_adapter* padapter) -{ - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - - setup_timer(&pwdinfo->find_phase_timer, find_phase_timer_process, - (unsigned long)padapter); - setup_timer(&pwdinfo->restore_p2p_state_timer, - restore_p2p_state_timer_process, (unsigned long)padapter); - setup_timer(&pwdinfo->pre_tx_scan_timer, pre_tx_scan_timer_process, - (unsigned long)padapter); - setup_timer(&pwdinfo->reset_ch_sitesurvey, - reset_ch_sitesurvey_timer_process, (unsigned long)padapter); - setup_timer(&pwdinfo->reset_ch_sitesurvey2, - reset_ch_sitesurvey_timer_process2, - (unsigned long)padapter); -} - -void rtw_init_wifidirect_addrs23a(struct rtw_adapter* padapter, u8 *dev_addr, u8 *iface_addr) -{ -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - - /*init device&interface address */ - if (dev_addr) { - memcpy(pwdinfo->device_addr, dev_addr, ETH_ALEN); - } - if (iface_addr) { - memcpy(pwdinfo->interface_addr, iface_addr, ETH_ALEN); - } -#endif -} - -void init_wifidirect_info23a(struct rtw_adapter *padapter, enum P2P_ROLE role) -{ - struct wifidirect_info *pwdinfo; -#ifdef CONFIG_8723AU_P2P - struct wifi_display_info *pwfd_info = &padapter->wfd_info; -#endif - - pwdinfo = &padapter->wdinfo; - - pwdinfo->padapter = padapter; - - /* 1, 6, 11 are the social channel defined in the WiFi Direct specification. */ - pwdinfo->social_chan[0] = 1; - pwdinfo->social_chan[1] = 6; - pwdinfo->social_chan[2] = 11; - pwdinfo->social_chan[3] = 0; /* channel 0 for scanning ending in site survey function. */ - - /* Use the channel 11 as the listen channel */ - pwdinfo->listen_channel = 11; - - if (role == P2P_ROLE_DEVICE) - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); - pwdinfo->intent = 1; - rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_LISTEN); - } - else if (role == P2P_ROLE_CLIENT) - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); - pwdinfo->intent = 1; - rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); - } - else if (role == P2P_ROLE_GO) - { - rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); - pwdinfo->intent = 15; - rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); - } - -/* Use the OFDM rate in the P2P probe response frame. (6(B), 9(B), 12, 18, 24, 36, 48, 54) */ - pwdinfo->support_rate[0] = 0x8c; /* 6(B) */ - pwdinfo->support_rate[1] = 0x92; /* 9(B) */ - pwdinfo->support_rate[2] = 0x18; /* 12 */ - pwdinfo->support_rate[3] = 0x24; /* 18 */ - pwdinfo->support_rate[4] = 0x30; /* 24 */ - pwdinfo->support_rate[5] = 0x48; /* 36 */ - pwdinfo->support_rate[6] = 0x60; /* 48 */ - pwdinfo->support_rate[7] = 0x6c; /* 54 */ - - memcpy((void*) pwdinfo->p2p_wildcard_ssid, "DIRECT-", 7); - - memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN); - pwdinfo->device_name_len = 0; - - memset(&pwdinfo->invitereq_info, 0x00, sizeof(struct tx_invite_req_info)); - pwdinfo->invitereq_info.token = 3; /* Token used for P2P invitation request frame. */ - - memset(&pwdinfo->inviteresp_info, 0x00, sizeof(struct tx_invite_resp_info)); - pwdinfo->inviteresp_info.token = 0; - - pwdinfo->profileindex = 0; - memset(&pwdinfo->profileinfo[ 0 ], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM); - - rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); - - pwdinfo->listen_dwell = (u8) ((jiffies % 3) + 1); - /* DBG_8723A("[%s] listen_dwell time is %d00ms\n", __func__, pwdinfo->listen_dwell); */ - - memset(&pwdinfo->tx_prov_disc_info, 0x00, sizeof(struct tx_provdisc_req_info)); - pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_NONE; - - memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info)); - - pwdinfo->device_password_id_for_nego = WPS_DPID_PBC; - pwdinfo->negotiation_dialog_token = 1; - - memset(pwdinfo->nego_ssid, 0x00, IEEE80211_MAX_SSID_LEN); - pwdinfo->nego_ssidlen = 0; - - pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO; -#ifdef CONFIG_8723AU_P2P - pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC; - pwdinfo->wfd_info = pwfd_info; -#else - pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC | WPS_CONFIG_METHOD_KEYPAD; -#endif /* CONFIG_8723AU_P2P */ - pwdinfo->channel_list_attr_len = 0; - memset(pwdinfo->channel_list_attr, 0x00, 100); - - memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, 0x00, 4); - memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, '0', 3); - memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info)); - pwdinfo->wfd_tdls_enable = 0; - memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); - memset(pwdinfo->p2p_peer_device_addr, 0x00, ETH_ALEN); - - pwdinfo->rx_invitereq_info.operation_ch[0] = 0; - pwdinfo->rx_invitereq_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */ - pwdinfo->rx_invitereq_info.scan_op_ch_only = 0; - pwdinfo->p2p_info.operation_ch[0] = 0; - pwdinfo->p2p_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */ - pwdinfo->p2p_info.scan_op_ch_only = 0; -} - -int rtw_p2p_enable23a(struct rtw_adapter *padapter, enum P2P_ROLE role) -{ - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - int ret = _SUCCESS; - - if (role == P2P_ROLE_DEVICE || role == P2P_ROLE_CLIENT || - role == P2P_ROLE_GO) { - /* leave IPS/Autosuspend */ - if (_FAIL == rtw_pwr_wakeup(padapter)) { - ret = _FAIL; - goto exit; - } - - /* Added by Albert 2011/03/22 */ - /* In the P2P mode, the driver should not support the b mode. */ - /* So, the Tx packet shouldn't use the CCK rate */ - update_tx_basic_rate23a(padapter, WIRELESS_11AGN); - - /* Enable P2P function */ - init_wifidirect_info23a(padapter, role); - - rtw_hal_set_odm_var23a(padapter, HAL_ODM_P2P_STATE, NULL, true); - #ifdef CONFIG_8723AU_P2P - rtw_hal_set_odm_var23a(padapter, HAL_ODM_WIFI_DISPLAY_STATE, NULL, true); - #endif - - } - else if (role == P2P_ROLE_DISABLE) - { - if (_FAIL == rtw_pwr_wakeup(padapter)) { - ret = _FAIL; - goto exit; - } - - /* Disable P2P function */ - if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) - { - del_timer_sync(&pwdinfo->find_phase_timer); - del_timer_sync(&pwdinfo->restore_p2p_state_timer); - del_timer_sync(&pwdinfo->pre_tx_scan_timer); - del_timer_sync(&pwdinfo->reset_ch_sitesurvey); - del_timer_sync(&pwdinfo->reset_ch_sitesurvey2); - reset_ch_sitesurvey_timer_process((unsigned long)padapter); - reset_ch_sitesurvey_timer_process2((unsigned long)padapter); - rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE); - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DISABLE); - memset(&pwdinfo->rx_prov_disc_info, 0x00, sizeof(struct rx_provdisc_req_info)); - } - - rtw_hal_set_odm_var23a(padapter, HAL_ODM_P2P_STATE, NULL, false); - #ifdef CONFIG_8723AU_P2P - rtw_hal_set_odm_var23a(padapter, HAL_ODM_WIFI_DISPLAY_STATE, NULL, false); - #endif - - /* Restore to initial setting. */ - update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode); - } - -exit: - return ret; -} - -#endif /* CONFIG_8723AU_P2P */ diff --git a/drivers/staging/rtl8723au/core/rtw_pwrctrl.c b/drivers/staging/rtl8723au/core/rtw_pwrctrl.c index 8ddd67f194ba7b..8a95ae1d353cbb 100644 --- a/drivers/staging/rtl8723au/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723au/core/rtw_pwrctrl.c @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_8723AU_BT_COEXIST #include @@ -108,33 +109,30 @@ static bool rtw_pwr_unassociated_idle(struct rtw_adapter *adapter) struct rtw_adapter *buddy = adapter->pbuddy_adapter; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct xmit_priv *pxmit_priv = &adapter->xmitpriv; - struct wifidirect_info *pwdinfo = &adapter->wdinfo; bool ret = false; if (time_after_eq(adapter->pwrctrlpriv.ips_deny_time, jiffies)) goto exit; - if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) - || check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) - || check_fwstate(pmlmepriv, WIFI_AP_STATE) - || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) - || !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) - ) { + if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) || + check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) || + check_fwstate(pmlmepriv, WIFI_AP_STATE) || + check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)){ goto exit; } /* consider buddy, if exist */ if (buddy) { struct mlme_priv *b_pmlmepriv = &buddy->mlmepriv; - struct wifidirect_info *b_pwdinfo = &buddy->wdinfo; - - if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) - || check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) - || check_fwstate(b_pmlmepriv, WIFI_AP_STATE) - || check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) - || !rtw_p2p_chk_state(b_pwdinfo, P2P_STATE_NONE) - ) { + + if (check_fwstate(b_pmlmepriv, + WIFI_ASOC_STATE|WIFI_SITE_MONITOR) || + check_fwstate(b_pmlmepriv, + WIFI_UNDER_LINKING|WIFI_UNDER_WPS) || + check_fwstate(b_pmlmepriv, WIFI_AP_STATE) || + check_fwstate(b_pmlmepriv, + WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)) { goto exit; } } @@ -263,7 +261,7 @@ void rtw_set_rpwm23a(struct rtw_adapter *padapter, u8 pslv) pwrpriv->rpwm = pslv; - rtw_hal_set_hwreg23a(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm)); + rtl8723a_set_rpwm(padapter, rpwm); pwrpriv->tog += 0x80; pwrpriv->cpwm = pslv; @@ -271,7 +269,7 @@ void rtw_set_rpwm23a(struct rtw_adapter *padapter, u8 pslv) } -u8 PS_RDY_CHECK(struct rtw_adapter * padapter) +static u8 PS_RDY_CHECK(struct rtw_adapter * padapter) { unsigned long delta_time; struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; @@ -306,11 +304,6 @@ u8 PS_RDY_CHECK(struct rtw_adapter * padapter) void rtw_set_ps_mode23a(struct rtw_adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode) { struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif /* CONFIG_8723AU_P2P */ - - RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ("%s: PowerMode =%d Smart_PS =%d\n", @@ -333,45 +326,29 @@ void rtw_set_ps_mode23a(struct rtw_adapter *padapter, u8 ps_mode, u8 smart_ps, u } if (ps_mode == PS_MODE_ACTIVE) { -#ifdef CONFIG_8723AU_P2P - if (pwdinfo->opp_ps == 0) -#endif /* CONFIG_8723AU_P2P */ - { - DBG_8723A("rtw_set_ps_mode23a: Leave 802.11 power save\n"); + DBG_8723A("rtw_set_ps_mode23a: Leave 802.11 power save\n"); - pwrpriv->pwr_mode = ps_mode; - rtw_set_rpwm23a(padapter, PS_STATE_S4); - rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); - pwrpriv->bFwCurrentInPSMode = false; - } - } - else - { + pwrpriv->pwr_mode = ps_mode; + rtw_set_rpwm23a(padapter, PS_STATE_S4); + rtl8723a_set_FwPwrMode_cmd(padapter, ps_mode); + pwrpriv->bFwCurrentInPSMode = false; + } else { if (PS_RDY_CHECK(padapter) #ifdef CONFIG_8723AU_BT_COEXIST || (BT_1Ant(padapter) == true) #endif - ) - { + ) { DBG_8723A("%s: Enter 802.11 power save\n", __func__); pwrpriv->bFwCurrentInPSMode = true; pwrpriv->pwr_mode = ps_mode; pwrpriv->smart_ps = smart_ps; pwrpriv->bcn_ant_mode = bcn_ant_mode; - rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); - -#ifdef CONFIG_8723AU_P2P - /* Set CTWindow after LPS */ - if (pwdinfo->opp_ps == 1) - p2p_ps_wk_cmd23a(padapter, P2P_PS_ENABLE, 0); -#endif /* CONFIG_8723AU_P2P */ + rtl8723a_set_FwPwrMode_cmd(padapter, ps_mode); rtw_set_rpwm23a(padapter, PS_STATE_S2); } } - - } /* @@ -391,12 +368,11 @@ s32 LPS_RF_ON_check23a(struct rtw_adapter *padapter, u32 delay_ms) while (1) { - rtw23a_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake); - if (true == bAwake) + bAwake = rtl8723a_get_fwlps_rf_on(padapter); + if (bAwake == true) break; - if (true == padapter->bSurpriseRemoved) - { + if (padapter->bSurpriseRemoved == true) { err = -2; DBG_8723A("%s: device surprise removed!!\n", __func__); break; @@ -469,10 +445,6 @@ void LeaveAllPowerSaveMode23a(struct rtw_adapter *Adapter) /* DBG_8723A("%s.....\n", __func__); */ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { /* connect */ -#ifdef CONFIG_8723AU_P2P - p2p_ps_wk_cmd23a(Adapter, P2P_PS_DISABLE, enqueue); -#endif /* CONFIG_8723AU_P2P */ - rtw_lps_ctrl_wk_cmd23a(Adapter, LPS_CTRL_LEAVE, enqueue); } @@ -525,14 +497,6 @@ void rtw_free_pwrctrl_priv(struct rtw_adapter *adapter) { } -u8 rtw_interface_ps_func23a(struct rtw_adapter *padapter, enum hal_intf_ps_func efunc_id, u8* val) -{ - u8 bResult = true; - rtw_hal_intf_ps_func23a(padapter, efunc_id, val); - - return bResult; -} - inline void rtw_set_ips_deny23a(struct rtw_adapter *padapter, u32 ms) { struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; diff --git a/drivers/staging/rtl8723au/core/rtw_recv.c b/drivers/staging/rtl8723au/core/rtw_recv.c index 0b2455e4f5b681..3791bbbdc58242 100644 --- a/drivers/staging/rtl8723au/core/rtw_recv.c +++ b/drivers/staging/rtl8723au/core/rtw_recv.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -80,8 +79,6 @@ int _rtw_init_recv_priv23a(struct recv_priv *precvpriv, list_add_tail(&precvframe->list, &precvpriv->free_recv_queue.queue); - res = rtw_os_recv_resource_alloc23a(padapter, precvframe); - precvframe->adapter = padapter; precvframe++; } @@ -569,31 +566,35 @@ struct recv_frame *decryptor(struct rtw_adapter *padapter, static struct recv_frame *portctrl(struct rtw_adapter *adapter, struct recv_frame *precv_frame) { - u8 *psta_addr = NULL, *ptr; + u8 *psta_addr, *ptr; uint auth_alg; struct recv_frame *pfhdr; struct sta_info *psta; struct sta_priv *pstapriv ; struct recv_frame *prtnframe; - u16 ether_type = 0; - u16 eapol_type = 0x888e;/* for Funia BD's WPA issue */ + u16 ether_type; + u16 eapol_type = ETH_P_PAE;/* for Funia BD's WPA issue */ struct rx_pkt_attrib *pattrib; pstapriv = &adapter->stapriv; - psta = rtw_get_stainfo23a(pstapriv, psta_addr); auth_alg = adapter->securitypriv.dot11AuthAlgrthm; - ptr = precv_frame->pkt->data; pfhdr = precv_frame; pattrib = &pfhdr->attrib; psta_addr = pattrib->ta; + psta = rtw_get_stainfo23a(pstapriv, psta_addr); RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm =" "%d\n", adapter->securitypriv.dot11AuthAlgrthm)); - if (auth_alg == 2) { + if (auth_alg == dot11AuthAlgrthm_8021X) { + /* get ether_type */ + ptr = pfhdr->pkt->data + pfhdr->attrib.hdrlen; + + ether_type = (ptr[6] << 8) | ptr[7]; + if ((psta != NULL) && (psta->ieee8021x_blocked)) { /* blocked */ /* only accept EAPOL frame */ @@ -601,13 +602,6 @@ static struct recv_frame *portctrl(struct rtw_adapter *adapter, ("########portctrl:psta->ieee8021x_blocked ==" "1\n")); - prtnframe = precv_frame; - - /* get ether_type */ - ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE; - memcpy(ðer_type, ptr, 2); - ether_type = ntohs((unsigned short)ether_type); - if (ether_type == eapol_type) { prtnframe = precv_frame; } else { @@ -651,9 +645,7 @@ static struct recv_frame *portctrl(struct rtw_adapter *adapter, prtnframe = precv_frame; } - - - return prtnframe; + return prtnframe; } int recv_decache(struct recv_frame *precv_frame, u8 bretry, @@ -1222,8 +1214,8 @@ int validate_recv_ctrl_frame(struct rtw_adapter *padapter, /* upate BCN for TIM IE */ /* update_BCNTIM(padapter); */ - update_beacon23a(padapter, _TIM_IE_, - NULL, false); + update_beacon23a(padapter, WLAN_EID_TIM, + NULL, false); } /* spin_unlock_bh(&psta->sleep_q.lock); */ @@ -1254,8 +1246,8 @@ int validate_recv_ctrl_frame(struct rtw_adapter *padapter, /* upate BCN for TIM IE */ /* update_BCNTIM(padapter); */ - update_beacon23a(padapter, _TIM_IE_, - NULL, false); + update_beacon23a(padapter, WLAN_EID_TIM, + NULL, false); } } } @@ -1942,8 +1934,8 @@ int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) return true; } -int enqueue_reorder_recvframe23a(struct recv_reorder_ctrl *preorder_ctrl, - struct recv_frame *prframe) +static int enqueue_reorder_recvframe23a(struct recv_reorder_ctrl *preorder_ctrl, + struct recv_frame *prframe) { struct rx_pkt_attrib *pattrib = &prframe->attrib; struct rtw_queue *ppending_recvframe_queue; @@ -2102,7 +2094,7 @@ int recv_indicatepkt_reorder(struct rtw_adapter *padapter, /* s1. */ wlanhdr_to_ethhdr(prframe); - if ((pattrib->qos!= 1) || (pattrib->eth_type == 0x0806) || + if ((pattrib->qos!= 1) || (pattrib->eth_type == ETH_P_ARP) || (pattrib->ack_policy != 0)) { if ((padapter->bDriverStopped == false) && (padapter->bSurpriseRemoved == false)) { diff --git a/drivers/staging/rtl8723au/core/rtw_sreset.c b/drivers/staging/rtl8723au/core/rtw_sreset.c index 4f745920339083..5bf7beb6d19cde 100644 --- a/drivers/staging/rtl8723au/core/rtw_sreset.c +++ b/drivers/staging/rtl8723au/core/rtw_sreset.c @@ -99,7 +99,8 @@ static void sreset_restore_security_station(struct rtw_adapter *padapter) val8 = 0xcc; else val8 = 0xcf; - rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + + rtl8723a_set_sec_cfg(padapter, val8); if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) || (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) { @@ -131,23 +132,16 @@ static void sreset_restore_network_station(struct rtw_adapter *padapter) threshold = 1; else threshold = 0; - rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); - } else { + } else threshold = 1; - rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); - } - set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + rtl8723a_set_rxdma_agg_pg_th(padapter, threshold); - /* disable dynamic functions, such as high power, DIG */ - /* Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false); */ + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, + pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); - rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress); - - { - u8 join_type = 0; - rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); - } + hw_var_set_bssid(padapter, pmlmeinfo->network.MacAddress); + hw_var_set_mlme_join(padapter, 0); Set_MSR23a(padapter, (pmlmeinfo->state & 0x3)); diff --git a/drivers/staging/rtl8723au/core/rtw_sta_mgt.c b/drivers/staging/rtl8723au/core/rtw_sta_mgt.c index 451b58f4728798..53dd3207ecef70 100644 --- a/drivers/staging/rtl8723au/core/rtw_sta_mgt.c +++ b/drivers/staging/rtl8723au/core/rtw_sta_mgt.c @@ -21,7 +21,7 @@ #include #include -void _rtw_init_stainfo(struct sta_info *psta) +static void _rtw_init_stainfo(struct sta_info *psta) { memset((u8 *)psta, 0, sizeof (struct sta_info)); spin_lock_init(&psta->lock); @@ -109,7 +109,7 @@ inline struct sta_info *rtw_get_stainfo23a_by_offset23a(struct sta_priv *stapriv } /* this function is used to free the memory of lock || sema for all stainfos */ -void rtw_mfree_all_stainfo(struct sta_priv *pstapriv) +static void rtw_mfree_all_stainfo(struct sta_priv *pstapriv) { struct list_head *plist, *phead; struct sta_info *psta; @@ -124,7 +124,7 @@ void rtw_mfree_all_stainfo(struct sta_priv *pstapriv) spin_unlock_bh(&pstapriv->sta_hash_lock); } -void rtw_mfree_sta_priv_lock(struct sta_priv *pstapriv) +static void rtw_mfree_sta_priv_lock(struct sta_priv *pstapriv) { rtw_mfree_all_stainfo(pstapriv); /* be done before free sta_hash_lock */ } @@ -405,12 +405,12 @@ void rtw_free_all_stainfo23a(struct rtw_adapter *padapter) } /* any station allocated can be searched by hash list */ -struct sta_info *rtw_get_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr) +struct sta_info *rtw_get_stainfo23a(struct sta_priv *pstapriv, const u8 *hwaddr) { struct list_head *plist, *phead; struct sta_info *psta = NULL; u32 index; - u8 *addr; + const u8 *addr; u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; if (hwaddr == NULL) diff --git a/drivers/staging/rtl8723au/core/rtw_wlan_util.c b/drivers/staging/rtl8723au/core/rtw_wlan_util.c index 99d81e612e7b69..09f3a66010d991 100644 --- a/drivers/staging/rtl8723au/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723au/core/rtw_wlan_util.c @@ -140,7 +140,7 @@ u8 judge_network_type23a(struct rtw_adapter *padapter, unsigned char *rate, int return network_type; } -unsigned char ratetbl_val_2wifirate(unsigned char rate) +static unsigned char ratetbl_val_2wifirate(unsigned char rate) { unsigned char val = 0; @@ -185,7 +185,7 @@ unsigned char ratetbl_val_2wifirate(unsigned char rate) return val; } -int is_basicrate(struct rtw_adapter *padapter, unsigned char rate) +static int is_basicrate(struct rtw_adapter *padapter, unsigned char rate) { int i; unsigned char val; @@ -203,7 +203,8 @@ int is_basicrate(struct rtw_adapter *padapter, unsigned char rate) return false; } -unsigned int ratetbl2rateset(struct rtw_adapter *padapter, unsigned char *rateset) +static unsigned int ratetbl2rateset(struct rtw_adapter *padapter, + unsigned char *rateset) { int i; unsigned char rate; @@ -283,35 +284,9 @@ void Update23aTblForSoftAP(u8 *bssrateset, u32 bssratelen) } } -void Save_DM_Func_Flag23a(struct rtw_adapter *padapter) -{ - u8 bSaveFlag = true; - - rtw_hal_set_hwreg23a(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&bSaveFlag)); -} - -void Restore_DM_Func_Flag23a(struct rtw_adapter *padapter) -{ - u8 bSaveFlag = false; - rtw_hal_set_hwreg23a(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&bSaveFlag)); -} - -void Switch_DM_Func23a(struct rtw_adapter *padapter, unsigned long mode, u8 enable) -{ - if (enable == true) - rtw_hal_set_hwreg23a(padapter, HW_VAR_DM_FUNC_SET, (u8 *)(&mode)); - else - rtw_hal_set_hwreg23a(padapter, HW_VAR_DM_FUNC_CLR, (u8 *)(&mode)); -} - -static void Set_NETYPE0_MSR(struct rtw_adapter *padapter, u8 type) -{ - rtw_hal_set_hwreg23a(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type)); -} - void Set_MSR23a(struct rtw_adapter *padapter, u8 type) { - Set_NETYPE0_MSR(padapter, type); + rtl8723a_set_media_status(padapter, type); } inline u8 rtw_get_oper_ch23a(struct rtw_adapter *adapter) @@ -483,51 +458,9 @@ unsigned int decide_wait_for_beacon_timeout23a(unsigned int bcn_interval) return bcn_interval << 2; } -void CAM_empty_entry23a(struct rtw_adapter *Adapter, u8 ucIndex) -{ - rtw_hal_set_hwreg23a(Adapter, HW_VAR_CAM_EMPTY_ENTRY, (u8 *)(&ucIndex)); -} - void invalidate_cam_all23a(struct rtw_adapter *padapter) { - rtw_hal_set_hwreg23a(padapter, HW_VAR_CAM_INVALID_ALL, NULL); -} - -void write_cam23a(struct rtw_adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key) -{ - unsigned int i, val, addr; - int j; - u32 cam_val[2]; - - addr = entry << 3; - - for (j = 5; j >= 0; j--) { - switch (j) { - case 0: - val = (ctrl | (mac[0] << 16) | (mac[1] << 24)); - break; - case 1: - val = (mac[2] | (mac[3] << 8) | (mac[4] << 16) | (mac[5] << 24)); - break; - default: - i = (j - 2) << 2; - val = (key[i] | (key[i+1] << 8) | (key[i+2] << 16) | (key[i+3] << 24)); - break; - } - - cam_val[0] = val; - cam_val[1] = addr + (unsigned int)j; - - rtw_hal_set_hwreg23a(padapter, HW_VAR_CAM_WRITE, (u8 *)cam_val); - - /* rtw_write32(padapter, WCAMI, val); */ - - /* cmd = CAM_POLLINIG | CAM_WRITE | (addr + j); */ - /* rtw_write32(padapter, RWCAM, cmd); */ - - /* DBG_8723A("%s => cam write: %x, %x\n", __func__, cmd, val); */ - - } + rtl8723a_cam_invalid_all(padapter); } void clear_cam_entry23a(struct rtw_adapter *padapter, u8 entry) @@ -536,7 +469,7 @@ void clear_cam_entry23a(struct rtw_adapter *padapter, u8 entry) unsigned char null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - write_cam23a(padapter, entry, 0, null_sta, null_key); + rtl8723a_cam_write(padapter, entry, 0, null_sta, null_key); } int allocate_fw_sta_entry23a(struct rtw_adapter *padapter) @@ -561,37 +494,11 @@ void flush_all_cam_entry23a(struct rtw_adapter *padapter) struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - rtw_hal_set_hwreg23a(padapter, HW_VAR_CAM_INVALID_ALL, NULL); + rtl8723a_cam_invalid_all(padapter); memset((u8 *)(pmlmeinfo->FW_sta_info), 0, sizeof(pmlmeinfo->FW_sta_info)); } -#if defined(CONFIG_8723AU_P2P) && defined(CONFIG_8723AU_P2P) -int WFD_info_handler(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE) -{ - struct wifidirect_info *pwdinfo; - u8 wfd_ie[MAX_WFD_IE_LEN] = {0x00}; - u32 wfd_ielen = 0; - - pwdinfo = &padapter->wdinfo; - if (rtw_get_wfd_ie((u8 *) pIE, pIE->Length, wfd_ie, &wfd_ielen)) { - u8 attr_content[ 10 ] = { 0x00 }; - u32 attr_contentlen = 0; - - DBG_8723A("[%s] Found WFD IE\n", __func__); - rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); - if (attr_contentlen) { - pwdinfo->wfd_info->peer_rtsp_ctrlport = get_unaligned_be16(attr_content + 2); - DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport); - return true; - } - } else { - DBG_8723A("[%s] NO WFD IE\n", __func__); - } - return _FAIL; -} -#endif - int WMM_param_handler23a(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE) { /* struct registry_priv *pregpriv = &padapter->registrypriv; */ @@ -649,22 +556,22 @@ void WMMOnAssocRsp23a(struct rtw_adapter *padapter) switch (ACI) { case 0x0: - rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm)); + rtl8723a_set_ac_param_be(padapter, acParm); acm_mask |= (ACM? BIT(1):0); edca[XMIT_BE_QUEUE] = acParm; break; case 0x1: - rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm)); + rtl8723a_set_ac_param_bk(padapter, acParm); /* acm_mask |= (ACM? BIT(0):0); */ edca[XMIT_BK_QUEUE] = acParm; break; case 0x2: - rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm)); + rtl8723a_set_ac_param_vi(padapter, acParm); acm_mask |= (ACM? BIT(2):0); edca[XMIT_VI_QUEUE] = acParm; break; case 0x3: - rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm)); + rtl8723a_set_ac_param_vo(padapter, acParm); acm_mask |= (ACM? BIT(3):0); edca[XMIT_VO_QUEUE] = acParm; break; @@ -674,7 +581,7 @@ void WMMOnAssocRsp23a(struct rtw_adapter *padapter) } if (padapter->registrypriv.acm_method == 1) - rtw_hal_set_hwreg23a(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask)); + rtl8723a_set_acm_ctrl(padapter, acm_mask); else padapter->mlmepriv.acm_mask = acm_mask; @@ -838,7 +745,7 @@ void HT_caps_handler23a(struct rtw_adapter *padapter, struct ndis_802_11_var_ies pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info = le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info); pmlmeinfo->HT_caps.u.HT_cap_element.HT_ext_caps = le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_ext_caps); - rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + rf_type = rtl8723a_get_rf_type(padapter); /* update the MCS rates */ for (i = 0; i < 16; i++) { @@ -896,9 +803,8 @@ void HTOnAssocRsp23a(struct rtw_adapter *padapter) min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; - rtw_hal_set_hwreg23a(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); - - rtw_hal_set_hwreg23a(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); + rtl8723a_set_ampdu_min_space(padapter, min_MPDU_spacing); + rtl8723a_set_ampdu_factor(padapter, max_AMPDU_len); } void ERP_IE_handler23a(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE) @@ -951,116 +857,135 @@ void VCS_update23a(struct rtw_adapter *padapter, struct sta_info *psta) } } -int rtw_check_bcn_info23a(struct rtw_adapter *Adapter, u8 *pframe, u32 packet_len) +int rtw_check_bcn_info23a(struct rtw_adapter *Adapter, + struct ieee80211_mgmt *mgmt, u32 pkt_len) { - unsigned int len; - unsigned char *p; - unsigned short val16; struct wlan_network *cur_network = &Adapter->mlmepriv.cur_network; - u16 wpa_len = 0, rsn_len = 0; - u8 encryp_protocol = 0; + struct HT_info_element *pht_info; + struct ieee80211_ht_cap *pht_cap; struct wlan_bssid_ex *bssid; - int group_cipher = 0, pairwise_cipher = 0, is_8021x = 0; - unsigned char *pbuf; - u32 wpa_ielen = 0; - u32 hidden_ssid = 0; - struct HT_info_element *pht_info = NULL; - struct ieee80211_ht_cap *pht_cap = NULL; + unsigned short val16; + u16 wpa_len = 0, rsn_len = 0; + u8 encryp_protocol; + int group_cipher = 0, pairwise_cipher = 0, is_8021x = 0, r; u32 bcn_channel; - unsigned short ht_cap_info; - unsigned char ht_info_infos_0; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) pframe; - u8 *pbssid = hdr->addr3; + unsigned short ht_cap_info; + unsigned char ht_info_infos_0; + int len, pie_len, ie_offset; + const u8 *p; + u8 *pie; if (is_client_associated_to_ap23a(Adapter) == false) return true; - len = packet_len - sizeof(struct ieee80211_hdr_3addr); + if (unlikely(!ieee80211_is_beacon(mgmt->frame_control))) { + printk(KERN_WARNING "%s: received a non beacon frame!\n", + __func__); + return false; + } + + len = pkt_len - sizeof(struct ieee80211_hdr_3addr); if (len > MAX_IE_SZ) { DBG_8723A("%s IE too long for survey event\n", __func__); return _FAIL; } - if (memcmp(cur_network->network.MacAddress, pbssid, 6)) { - DBG_8723A("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n" MAC_FMT MAC_FMT, - MAC_ARG(pbssid), MAC_ARG(cur_network->network.MacAddress)); + if (memcmp(cur_network->network.MacAddress, mgmt->bssid, 6)) { + DBG_8723A("Oops: rtw_check_network_encrypt linked but recv " + "other bssid bcn\n" MAC_FMT MAC_FMT, + MAC_ARG(mgmt->bssid), + MAC_ARG(cur_network->network.MacAddress)); return true; } bssid = (struct wlan_bssid_ex *)kzalloc(sizeof(struct wlan_bssid_ex), - GFP_ATOMIC); + GFP_ATOMIC); + if (!bssid) + return _FAIL; - if (ieee80211_is_beacon(hdr->frame_control)) - bssid->reserved = 1; + bssid->reserved = 1; - bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; + bssid->Length = offsetof(struct wlan_bssid_ex, IEs) + len; /* below is to copy the information element */ bssid->IELength = len; - memcpy(bssid->IEs, (pframe + sizeof(struct ieee80211_hdr_3addr)), bssid->IELength); + memcpy(bssid->IEs, &mgmt->u, len); /* check bw and channel offset */ /* parsing HT_CAP_IE */ - p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); - if (p && len>0) { - pht_cap = (struct ieee80211_ht_cap *)(p + 2); - ht_cap_info = pht_cap->cap_info; + ie_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable) - + offsetof(struct ieee80211_mgmt, u); + pie = bssid->IEs + ie_offset; + pie_len = pkt_len - ie_offset; + + p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, pie, pie_len); + if (p && p[1] > 0) { + pht_cap = (struct ieee80211_ht_cap *)(p + 2); + ht_cap_info = pht_cap->cap_info; } else { - ht_cap_info = 0; + pht_cap = NULL; + ht_cap_info = 0; } + /* parsing HT_INFO_IE */ - p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); - if (p && len>0) { - pht_info = (struct HT_info_element *)(p + 2); - ht_info_infos_0 = pht_info->infos[0]; + p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, pie, pie_len); + if (p && p[1] > 0) { + pht_info = (struct HT_info_element *)(p + 2); + ht_info_infos_0 = pht_info->infos[0]; } else { - ht_info_infos_0 = 0; + pht_info = NULL; + ht_info_infos_0 = 0; } + if (ht_cap_info != cur_network->BcnInfo.ht_cap_info || - ((ht_info_infos_0&0x03) != (cur_network->BcnInfo.ht_info_infos_0&0x03))) { - DBG_8723A("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, - ht_cap_info, ht_info_infos_0); - DBG_8723A("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, - cur_network->BcnInfo.ht_cap_info, cur_network->BcnInfo.ht_info_infos_0); - DBG_8723A("%s bw mode change, disconnect\n", __func__); - /* bcn_info_update */ - cur_network->BcnInfo.ht_cap_info = ht_cap_info; - cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0; - /* to do : need to check that whether modify related register of BB or not */ + ((ht_info_infos_0 & 0x03) != + (cur_network->BcnInfo.ht_info_infos_0 & 0x03))) { + DBG_8723A("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", + __func__, ht_cap_info, ht_info_infos_0); + DBG_8723A("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", + __func__, cur_network->BcnInfo.ht_cap_info, + cur_network->BcnInfo.ht_info_infos_0); + DBG_8723A("%s bw mode change, disconnect\n", __func__); + /* bcn_info_update */ + cur_network->BcnInfo.ht_cap_info = ht_cap_info; + cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0; + /* to do : need to check that whether modify related + register of BB or not */ } /* Checking for channel */ - p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _DSSET_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); - if (p) { - bcn_channel = *(p + 2); - } else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */ - p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); - if (pht_info) { - bcn_channel = pht_info->primary_channel; - } else { /* we don't find channel IE, so don't check it */ - DBG_8723A("Oops: %s we don't find channel IE, so don't check it\n", __func__); - bcn_channel = Adapter->mlmeextpriv.cur_channel; - } + p = cfg80211_find_ie(WLAN_EID_DS_PARAMS, pie, pie_len); + if (p) + bcn_channel = p[2]; + else { + /* In 5G, some ap do not have DSSET IE checking HT + info for channel */ + p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, pie, pie_len); + + if (pht_info) + bcn_channel = pht_info->primary_channel; + else { /* we don't find channel IE, so don't check it */ + DBG_8723A("Oops: %s we don't find channel IE, so don't " + "check it\n", __func__); + bcn_channel = Adapter->mlmeextpriv.cur_channel; + } } if (bcn_channel != Adapter->mlmeextpriv.cur_channel) { - DBG_8723A("%s beacon channel:%d cur channel:%d disconnect\n", __func__, - bcn_channel, Adapter->mlmeextpriv.cur_channel); - goto _mismatch; + DBG_8723A("%s beacon channel:%d cur channel:%d disconnect\n", + __func__, bcn_channel, + Adapter->mlmeextpriv.cur_channel); + goto _mismatch; } /* checking SSID */ - if ((p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _SSID_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_)) == NULL) { - DBG_8723A("%s marc: cannot find SSID for survey event\n", __func__); - hidden_ssid = true; - } else { - hidden_ssid = false; - } - - if ((NULL != p) && (false == hidden_ssid && (*(p + 1)))) { - memcpy(bssid->Ssid.ssid, (p + 2), *(p + 1)); - bssid->Ssid.ssid_len = *(p + 1); + p = cfg80211_find_ie(WLAN_EID_SSID, pie, pie_len); + if (p && p[1]) { + memcpy(bssid->Ssid.ssid, p + 2, p[1]); + bssid->Ssid.ssid_len = p[1]; } else { + DBG_8723A("%s marc: cannot find SSID for survey event\n", + __func__); bssid->Ssid.ssid_len = 0; bssid->Ssid.ssid[0] = '\0'; } @@ -1083,7 +1008,7 @@ int rtw_check_bcn_info23a(struct rtw_adapter *Adapter, u8 *pframe, u32 packet_le } /* check encryption info */ - val16 = rtw_get_capability23a((struct wlan_bssid_ex *)bssid); + val16 = rtw_get_capability23a(bssid); if (val16 & BIT(4)) bssid->Privacy = 1; @@ -1091,60 +1016,83 @@ int rtw_check_bcn_info23a(struct rtw_adapter *Adapter, u8 *pframe, u32 packet_le bssid->Privacy = 0; RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("%s(): cur_network->network.Privacy is %d, bssid.Privacy is %d\n", - __func__, cur_network->network.Privacy, bssid->Privacy)); + ("%s(): cur_network->network.Privacy is %d, bssid.Privacy " + "is %d\n", __func__, cur_network->network.Privacy, + bssid->Privacy)); if (cur_network->network.Privacy != bssid->Privacy) { DBG_8723A("%s(), privacy is not match return FAIL\n", __func__); goto _mismatch; } - rtw_get_sec_ie23a(bssid->IEs, bssid->IELength, NULL,&rsn_len, NULL,&wpa_len); + rtw_get_sec_ie23a(bssid->IEs, bssid->IELength, NULL, &rsn_len, NULL, + &wpa_len); - if (rsn_len > 0) { + if (rsn_len > 0) encryp_protocol = ENCRYP_PROTOCOL_WPA2; - } else if (wpa_len > 0) { + else if (wpa_len > 0) encryp_protocol = ENCRYP_PROTOCOL_WPA; - } else { + else { if (bssid->Privacy) encryp_protocol = ENCRYP_PROTOCOL_WEP; + else + encryp_protocol = ENCRYP_PROTOCOL_OPENSYS; } if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) { - DBG_8723A("%s(): enctyp is not match , return FAIL\n", __func__); + DBG_8723A("%s(): enctyp is not match, return FAIL\n", __func__); goto _mismatch; } - if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) { - pbuf = rtw_get_wpa_ie23a(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12); - if (pbuf && (wpa_ielen>0)) { - if (_SUCCESS == rtw_parse_wpa_ie23a(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) { + if (encryp_protocol == ENCRYP_PROTOCOL_WPA || + encryp_protocol == ENCRYP_PROTOCOL_WPA2) { + p = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPA, + pie, pie_len); + if (p && p[1] > 0) { + r = rtw_parse_wpa_ie23a(p, p[1] + 2, &group_cipher, + &pairwise_cipher, &is_8021x); + if (r == _SUCCESS) RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("%s pnetwork->pairwise_cipher: %d, group_cipher is %d, is_8021x is %d\n", __func__, - pairwise_cipher, group_cipher, is_8021x)); - } + ("%s pnetwork->pairwise_cipher: %d, " + "group_cipher is %d, is_8021x is " + "%d\n", __func__, pairwise_cipher, + group_cipher, is_8021x)); } else { - pbuf = rtw_get_wpa2_ie23a(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12); - - if (pbuf && (wpa_ielen>0)) { - if (_SUCCESS == rtw_parse_wpa2_ie23a(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("%s pnetwork->pairwise_cipher: %d, pnetwork->group_cipher is %d, is_802x is %d\n", - __func__, pairwise_cipher, group_cipher, is_8021x)); - } + p = cfg80211_find_ie(WLAN_EID_RSN, pie, pie_len); + + if (p && p[1] > 0) { + r = rtw_parse_wpa2_ie23a(p, p[1] + 2, + &group_cipher, + &pairwise_cipher, + &is_8021x); + if (r == _SUCCESS) + RT_TRACE(_module_rtl871x_mlme_c_, + _drv_info_, + ("%s pnetwork->pairwise_cipher" + ": %d, pnetwork->group_cipher" + " is %d, is_802x is %d\n", + __func__, pairwise_cipher, + group_cipher, is_8021x)); } } RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, - ("%s cur_network->group_cipher is %d: %d\n", __func__, cur_network->BcnInfo.group_cipher, group_cipher)); - if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher) { - DBG_8723A("%s pairwise_cipher(%x:%x) or group_cipher(%x:%x) is not match , return FAIL\n", __func__, - pairwise_cipher, cur_network->BcnInfo.pairwise_cipher, - group_cipher, cur_network->BcnInfo.group_cipher); + ("%s cur_network->group_cipher is %d: %d\n", __func__, + cur_network->BcnInfo.group_cipher, group_cipher)); + if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || + group_cipher != cur_network->BcnInfo.group_cipher) { + DBG_8723A("%s pairwise_cipher(%x:%x) or group_cipher " + "(%x:%x) is not match, return FAIL\n", + __func__, pairwise_cipher, + cur_network->BcnInfo.pairwise_cipher, + group_cipher, + cur_network->BcnInfo.group_cipher); goto _mismatch; } if (is_8021x != cur_network->BcnInfo.is_8021x) { - DBG_8723A("%s authentication is not match , return FAIL\n", __func__); + DBG_8723A("%s authentication is not match, return " + "FAIL\n", __func__); goto _mismatch; } } @@ -1171,11 +1119,11 @@ void update_beacon23a_info(struct rtw_adapter *padapter, u8 *pframe, uint pkt_le pIE = (struct ndis_802_11_var_ies *)(pframe + (_BEACON_IE_OFFSET_ + sizeof(struct ieee80211_hdr_3addr)) + i); switch (pIE->ElementID) { - case _HT_EXTRA_INFO_IE_: /* HT info */ + case WLAN_EID_HT_OPERATION: /* HT info */ /* HT_info_handler23a(padapter, pIE); */ bwmode_update_check(padapter, pIE); break; - case _ERPINFO_IE_: + case WLAN_EID_ERP_INFO: ERP_IE_handler23a(padapter, pIE); VCS_update23a(padapter, psta); break; @@ -1194,16 +1142,16 @@ unsigned int is_ap_in_tkip23a(struct rtw_adapter *padapter) struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; - if (rtw_get_capability23a((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) { + if (rtw_get_capability23a(cur_network) & WLAN_CAPABILITY_PRIVACY) { for (i = sizeof(struct ndis_802_11_fixed_ies); i < pmlmeinfo->network.IELength;) { pIE = (struct ndis_802_11_var_ies *)(pmlmeinfo->network.IEs + i); switch (pIE->ElementID) { - case _VENDOR_SPECIFIC_IE_: - if ((!memcmp(pIE->data, RTW_WPA_OUI23A, 4)) && (!memcmp((pIE->data + 12), WPA_TKIP_CIPHER23A, 4))) + case WLAN_EID_VENDOR_SPECIFIC: + if ((!memcmp(pIE->data, RTW_WPA_OUI23A_TYPE, 4)) && (!memcmp((pIE->data + 12), WPA_TKIP_CIPHER23A, 4))) return true; break; - case _RSN_IE_2_: + case WLAN_EID_RSN: if (!memcmp((pIE->data + 8), RSN_TKIP_CIPHER23A, 4)) return true; break; @@ -1225,18 +1173,18 @@ unsigned int should_forbid_n_rate23a(struct rtw_adapter * padapter) struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_bssid_ex *cur_network = &pmlmepriv->cur_network.network; - if (rtw_get_capability23a((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) { + if (rtw_get_capability23a(cur_network) & WLAN_CAPABILITY_PRIVACY) { for (i = sizeof(struct ndis_802_11_fixed_ies); i < cur_network->IELength;) { pIE = (struct ndis_802_11_var_ies *)(cur_network->IEs + i); switch (pIE->ElementID) { - case _VENDOR_SPECIFIC_IE_: - if (!memcmp(pIE->data, RTW_WPA_OUI23A, 4) && + case WLAN_EID_VENDOR_SPECIFIC: + if (!memcmp(pIE->data, RTW_WPA_OUI23A_TYPE, 4) && ((!memcmp((pIE->data + 12), WPA_CIPHER_SUITE_CCMP23A, 4)) || (!memcmp((pIE->data + 16), WPA_CIPHER_SUITE_CCMP23A, 4)))) return false; break; - case _RSN_IE_2_: + case WLAN_EID_RSN: if ((!memcmp((pIE->data + 8), RSN_CIPHER_SUITE_CCMP23A, 4)) || (!memcmp((pIE->data + 12), RSN_CIPHER_SUITE_CCMP23A, 4))) return false; @@ -1260,16 +1208,16 @@ unsigned int is_ap_in_wep23a(struct rtw_adapter *padapter) struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; - if (rtw_get_capability23a((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) { + if (rtw_get_capability23a(cur_network) & WLAN_CAPABILITY_PRIVACY) { for (i = sizeof(struct ndis_802_11_fixed_ies); i < pmlmeinfo->network.IELength;) { pIE = (struct ndis_802_11_var_ies *)(pmlmeinfo->network.IEs + i); switch (pIE->ElementID) { - case _VENDOR_SPECIFIC_IE_: - if (!memcmp(pIE->data, RTW_WPA_OUI23A, 4)) + case WLAN_EID_VENDOR_SPECIFIC: + if (!memcmp(pIE->data, RTW_WPA_OUI23A_TYPE, 4)) return false; break; - case _RSN_IE_2_: + case WLAN_EID_RSN: return false; default: @@ -1285,7 +1233,7 @@ unsigned int is_ap_in_wep23a(struct rtw_adapter *padapter) } } -int wifirate2_ratetbl_inx23a(unsigned char rate) +static int wifirate2_ratetbl_inx23a(unsigned char rate) { int inx = 0; rate = rate & 0x7f; @@ -1399,25 +1347,13 @@ unsigned char get_highest_rate_idx23a(u32 mask) return rate_idx; } -unsigned char get_highest_mcs_rate(struct HT_caps_element *pHT_caps) -{ - int i, mcs_rate; - - mcs_rate = (pHT_caps->u.HT_cap_element.MCS_rate[0] | (pHT_caps->u.HT_cap_element.MCS_rate[1] << 8)); - - for (i = 15; i >= 0; i--) { - if (mcs_rate & (0x1 << i)) - break; - } - return i; -} - void Update_RA_Entry23a(struct rtw_adapter *padapter, struct sta_info *psta) { rtw_hal_update_ra_mask23a(psta, 0); } -void enable_rate_adaptive(struct rtw_adapter *padapter, struct sta_info *psta) +static void enable_rate_adaptive(struct rtw_adapter *padapter, + struct sta_info *psta) { Update_RA_Entry23a(padapter, psta); } @@ -1432,15 +1368,6 @@ void set_sta_rate23a(struct rtw_adapter *padapter, struct sta_info *psta) void update_tx_basic_rate23a(struct rtw_adapter *padapter, u8 wirelessmode) { unsigned char supported_rates[NDIS_802_11_LENGTH_RATES_EX]; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info* pwdinfo = &padapter->wdinfo; - - /* Added by Albert 2011/03/22 */ - /* In the P2P mode, the driver should not support the b mode. */ - /* So, the Tx packet shouldn't use the CCK rate */ - if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) - return; -#endif /* CONFIG_8723AU_P2P */ memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX); @@ -1457,7 +1384,7 @@ void update_tx_basic_rate23a(struct rtw_adapter *padapter, u8 wirelessmode) else update_mgnt_tx_rate23a(padapter, IEEE80211_OFDM_RATE_6MB); - rtw_hal_set_hwreg23a(padapter, HW_VAR_BASIC_RATE, supported_rates); + HalSetBrateCfg23a(padapter, supported_rates); } unsigned char check_assoc_AP23a(u8 *pframe, uint len) @@ -1473,7 +1400,7 @@ unsigned char check_assoc_AP23a(u8 *pframe, uint len) pIE = (struct ndis_802_11_var_ies *)(pframe + i); switch (pIE->ElementID) { - case _VENDOR_SPECIFIC_IE_: + case WLAN_EID_VENDOR_SPECIFIC: if ((!memcmp(pIE->data, ARTHEROS_OUI1, 3)) || (!memcmp(pIE->data, ARTHEROS_OUI2, 3))) { DBG_8723A("link to Artheros AP\n"); @@ -1546,15 +1473,15 @@ void update_IOT_info23a(struct rtw_adapter *padapter) pmlmeinfo->turboMode_cts2self = 0; pmlmeinfo->turboMode_rtsen = 1; /* disable high power */ - Switch_DM_Func23a(padapter, ~DYNAMIC_BB_DYNAMIC_TXPWR, - false); + rtl8723a_odm_support_ability_clr(padapter, (u32) + ~DYNAMIC_BB_DYNAMIC_TXPWR); break; case HT_IOT_PEER_REALTEK: /* rtw_write16(padapter, 0x4cc, 0xffff); */ /* rtw_write16(padapter, 0x546, 0x01c0); */ /* disable high power */ - Switch_DM_Func23a(padapter, ~DYNAMIC_BB_DYNAMIC_TXPWR, - false); + rtl8723a_odm_support_ability_clr(padapter, (u32) + ~DYNAMIC_BB_DYNAMIC_TXPWR); break; default: pmlmeinfo->turboMode_cts2self = 0; @@ -1567,22 +1494,19 @@ void update_capinfo23a(struct rtw_adapter *Adapter, u16 updateCap) { struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - bool ShortPreamble; if (updateCap & cShortPreamble) { /* Short Preamble */ if (pmlmeinfo->preamble_mode != PREAMBLE_SHORT) { /* PREAMBLE_LONG or PREAMBLE_AUTO */ - ShortPreamble = true; pmlmeinfo->preamble_mode = PREAMBLE_SHORT; - rtw_hal_set_hwreg23a(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble); + rtl8723a_ack_preamble(Adapter, true); } } else { /* Long Preamble */ if (pmlmeinfo->preamble_mode != PREAMBLE_LONG) { /* PREAMBLE_SHORT or PREAMBLE_AUTO */ - ShortPreamble = false; pmlmeinfo->preamble_mode = PREAMBLE_LONG; - rtw_hal_set_hwreg23a(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble); + rtl8723a_ack_preamble(Adapter, false); } } if (updateCap & cIBSS) { @@ -1605,13 +1529,12 @@ void update_capinfo23a(struct rtw_adapter *Adapter, u16 updateCap) pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; } } - rtw_hal_set_hwreg23a(Adapter, HW_VAR_SLOT_TIME, &pmlmeinfo->slotTime); + rtl8723a_set_slot_time(Adapter, pmlmeinfo->slotTime); } void update_wireless_mode23a(struct rtw_adapter *padapter) { int ratelen, network_type = 0; - u32 SIFS_Timer; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; @@ -1640,10 +1563,9 @@ void update_wireless_mode23a(struct rtw_adapter *padapter) pmlmeext->cur_wireless_mode = network_type & padapter->registrypriv.wireless_mode; - SIFS_Timer = 0x0a0a0808; /* 0x0808 -> for CCK, 0x0a0a -> for OFDM */ - /* change this value if having IOT issues. */ - - padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_RESP_SIFS, (u8 *)&SIFS_Timer); + /* 0x0808 -> for CCK, 0x0a0a -> for OFDM */ + /* change this value if having IOT issues. */ + rtl8723a_set_resp_sifs(padapter, 0x08, 0x08, 0x0a, 0x0a); if (pmlmeext->cur_wireless_mode & WIRELESS_11B) update_mgnt_tx_rate23a(padapter, IEEE80211_CCK_RATE_1MB); @@ -1658,30 +1580,33 @@ void update_bmc_sta_support_rate23a(struct rtw_adapter *padapter, u32 mac_id) if (pmlmeext->cur_wireless_mode & WIRELESS_11B) { /* Only B, B/G, and B/G/N AP could use CCK rate */ - memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_cck, 4); + memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), + rtw_basic_rate_cck, 4); } else { - memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_ofdm, 4); + memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), + rtw_basic_rate_ofdm, 3); } } -int update_sta_support_rate23a(struct rtw_adapter *padapter, u8 *pvar_ie, uint var_ie_len, int cam_idx) +int update_sta_support_rate23a(struct rtw_adapter *padapter, u8 *pvar_ie, + uint var_ie_len, int cam_idx) { - unsigned int ie_len; - struct ndis_802_11_var_ies *pIE; - int supportRateNum = 0; + int supportRateNum = 0; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + const u8 *p; - pIE = (struct ndis_802_11_var_ies *)rtw_get_ie23a(pvar_ie, _SUPPORTEDRATES_IE_, &ie_len, var_ie_len); - if (pIE == NULL) + p = cfg80211_find_ie(WLAN_EID_SUPP_RATES, pvar_ie, var_ie_len); + if (!p) return _FAIL; - memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, pIE->data, ie_len); - supportRateNum = ie_len; + memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, p + 2, p[1]); + supportRateNum = p[1]; - pIE = (struct ndis_802_11_var_ies *)rtw_get_ie23a(pvar_ie, _EXT_SUPPORTEDRATES_IE_, &ie_len, var_ie_len); - if (pIE) - memcpy((pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + supportRateNum), pIE->data, ie_len); + p = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, pvar_ie, var_ie_len); + if (p) + memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + + supportRateNum, p + 2, p[1]); return _SUCCESS; } @@ -1711,26 +1636,6 @@ void process_addba_req23a(struct rtw_adapter *padapter, u8 *paddba_req, u8 *addr } } -void update_TSF23a(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) -{ - u8 *pIE; - u32 *pbuf; - - pIE = pframe + sizeof(struct ieee80211_hdr_3addr); - pbuf = (u32 *)pIE; - - pmlmeext->TSFValue = le32_to_cpu(*(pbuf+1)); - - pmlmeext->TSFValue = pmlmeext->TSFValue << 32; - - pmlmeext->TSFValue |= le32_to_cpu(*pbuf); -} - -void correct_TSF23a(struct rtw_adapter *padapter, struct mlme_ext_priv *pmlmeext) -{ - rtw_hal_set_hwreg23a(padapter, HW_VAR_CORRECT_TSF, NULL); -} - void beacon_timing_control23a(struct rtw_adapter *padapter) { rtw_hal_bcn_related_reg_setting23a(padapter); diff --git a/drivers/staging/rtl8723au/core/rtw_xmit.c b/drivers/staging/rtl8723au/core/rtw_xmit.c index 0f10cfa10d39e4..31a44feaab1d84 100644 --- a/drivers/staging/rtl8723au/core/rtw_xmit.c +++ b/drivers/staging/rtl8723au/core/rtw_xmit.c @@ -443,21 +443,17 @@ u8 qos_acm23a(u8 acm_mask, u8 priority) return change_priority; } -static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) +static void set_qos(struct sk_buff *skb, struct pkt_attrib *pattrib) { - struct ethhdr etherhdr; - struct iphdr ip_hdr; + u8 *pframe = skb->data; + struct iphdr *ip_hdr; s32 UserPriority = 0; - _rtw_open_pktfile23a(ppktfile->pkt, ppktfile); - _rtw_pktfile_read23a(ppktfile, (unsigned char*)ðerhdr, ETH_HLEN); - /* get UserPriority from IP hdr */ - if (pattrib->ether_type == 0x0800) { - _rtw_pktfile_read23a(ppktfile, (u8*)&ip_hdr, sizeof(ip_hdr)); -/* UserPriority = (ntohs(ip_hdr.tos) >> 5) & 0x3; */ - UserPriority = ip_hdr.tos >> 5; - } else if (pattrib->ether_type == 0x888e) { + if (pattrib->ether_type == ETH_P_IP) { + ip_hdr = (struct iphdr *)(pframe + ETH_HLEN); + UserPriority = ip_hdr->tos >> 5; + } else if (pattrib->ether_type == ETH_P_PAE) { /* "When priority processing of data frames is supported, */ /* a STA's SME should send EAPOL-Key frames at the highest priority." */ @@ -470,57 +466,53 @@ static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) } static s32 update_attrib(struct rtw_adapter *padapter, - struct sk_buff *pkt, struct pkt_attrib *pattrib) + struct sk_buff *skb, struct pkt_attrib *pattrib) { - uint i; - struct pkt_file pktfile; struct sta_info *psta = NULL; - struct ethhdr etherhdr; - int bmcast; struct sta_priv *pstapriv = &padapter->stapriv; struct security_priv *psecuritypriv = &padapter->securitypriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct qos_priv *pqospriv = &pmlmepriv->qospriv; int res = _SUCCESS; + struct ethhdr *ehdr = (struct ethhdr *) skb->data; - _rtw_open_pktfile23a(pkt, &pktfile); - i = _rtw_pktfile_read23a(&pktfile, (u8*)ðerhdr, ETH_HLEN); - - pattrib->ether_type = ntohs(etherhdr.h_proto); + pattrib->ether_type = ntohs(ehdr->h_proto); - memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); - memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); + ether_addr_copy(pattrib->dst, ehdr->h_dest); + ether_addr_copy(pattrib->src, ehdr->h_source); pattrib->pctrl = 0; if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { - memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); - memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + ether_addr_copy(pattrib->ra, pattrib->dst); + ether_addr_copy(pattrib->ta, pattrib->src); } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { - memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); - memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + ether_addr_copy(pattrib->ra, get_bssid(pmlmepriv)); + ether_addr_copy(pattrib->ta, pattrib->src); } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { - memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); - memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); + ether_addr_copy(pattrib->ra, pattrib->dst); + ether_addr_copy(pattrib->ta, get_bssid(pmlmepriv)); } - pattrib->pktlen = pktfile.pkt_len; + pattrib->pktlen = skb->len - ETH_HLEN; if (pattrib->ether_type == ETH_P_IP) { /* The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */ /* to prevent DHCP protocol fail */ - u8 tmp[24]; - _rtw_pktfile_read23a(&pktfile, &tmp[0], 24); pattrib->dhcp_pkt = 0; - if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */ - if (ETH_P_IP == pattrib->ether_type) {/* IP header */ - if (((tmp[21] == 68) && (tmp[23] == 67)) || - ((tmp[21] == 67) && (tmp[23] == 68))) { + /* MINIMUM_DHCP_PACKET_SIZE) { */ + if (pattrib->pktlen > 282 + 24) { + if (pattrib->ether_type == ETH_P_IP) {/* IP header */ + u8 *pframe = skb->data; + pframe += ETH_HLEN; + + if ((pframe[21] == 68 && pframe[23] == 67) || + (pframe[21] == 67 && pframe[23] == 68)) { /* 68 : UDP BOOTP client */ /* 67 : UDP BOOTP server */ RT_TRACE(_module_rtl871x_xmit_c_, @@ -532,17 +524,17 @@ static s32 update_attrib(struct rtw_adapter *padapter, } } } - } else if (0x888e == pattrib->ether_type) { + } else if (pattrib->ether_type == ETH_P_PAE) { DBG_8723A_LEVEL(_drv_always_, "send eapol packet\n"); } - if ((pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) { + if ((pattrib->ether_type == ETH_P_PAE) || (pattrib->dhcp_pkt == 1)) { rtw_set_scan_deny(padapter, 3000); } /* If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */ - if ((pattrib->ether_type == 0x0806) || - (pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) { + if ((pattrib->ether_type == ETH_P_ARP) || + (pattrib->ether_type == ETH_P_PAE) || (pattrib->dhcp_pkt == 1)) { rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_SPECIAL_PACKET, 1); } @@ -592,10 +584,10 @@ static s32 update_attrib(struct rtw_adapter *padapter, if (check_fwstate(pmlmepriv, WIFI_AP_STATE | WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) { if (psta->qos_option) - set_qos(&pktfile, pattrib); + set_qos(skb, pattrib); } else { if (pqospriv->qos_option) { - set_qos(&pktfile, pattrib); + set_qos(skb, pattrib); if (pmlmepriv->acm_mask != 0) { pattrib->priority = qos_acm23a(pmlmepriv->acm_mask, @@ -610,7 +602,7 @@ static s32 update_attrib(struct rtw_adapter *padapter, pattrib->encrypt = 0; - if ((pattrib->ether_type != 0x888e) && + if ((pattrib->ether_type != ETH_P_PAE) && (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false)) { RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\npsta->ieee8021x_blocked == true, " @@ -916,7 +908,7 @@ s32 rtw_make_wlanhdr23a(struct rtw_adapter *padapter, u8 *hdr, struct qos_priv *pqospriv = &pmlmepriv->qospriv; u8 qos_option = false; int res = _SUCCESS; - u16 *fctrl = &pwlanhdr->frame_control; + __le16 *fctrl = &pwlanhdr->frame_control; struct sta_info *psta; @@ -1116,39 +1108,40 @@ This sub-routine will perform all the following: 6. apply sw-encrypt, if necessary. */ -s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt, +s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *skb, struct xmit_frame *pxmitframe) { - struct pkt_file pktfile; - struct sta_info *psta; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_info *psta; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; u8 *pframe, *mem_start; u8 hw_hdr_offset; u8 *pbuf_start; - + u8 *pdata = skb->data; + int data_len = skb->len; s32 bmcst = is_multicast_ether_addr(pattrib->ra); s32 res = _SUCCESS; - if (pattrib->psta) { + if (pattrib->psta) psta = pattrib->psta; - } else { + else { DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__); psta = rtw_get_stainfo23a(&padapter->stapriv, pattrib->ra); } - if (psta == NULL) { + if (!psta) { DBG_8723A("%s, psta == NUL\n", __func__); return _FAIL; } if (!(psta->state &_FW_LINKED)) { - DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", + __func__, psta->state); return _FAIL; } - if (pxmitframe->buf_addr == NULL) { + if (!pxmitframe->buf_addr) { DBG_8723A("==> %s buf_addr == NULL\n", __func__); return _FAIL; } @@ -1157,7 +1150,7 @@ s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt, hw_hdr_offset = TXDESC_OFFSET; - mem_start = pbuf_start + hw_hdr_offset; + mem_start = pbuf_start + hw_hdr_offset; if (rtw_make_wlanhdr23a(padapter, mem_start, pattrib) == _FAIL) { RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, @@ -1167,8 +1160,8 @@ s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt, goto exit; } - _rtw_open_pktfile23a(pkt, &pktfile); - _rtw_pktfile_read23a(&pktfile, NULL, pattrib->pkt_hdrlen); + pdata += pattrib->pkt_hdrlen; + data_len -= pattrib->pkt_hdrlen; frg_inx = 0; frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */ @@ -1187,23 +1180,30 @@ s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt, /* adding icv, if necessary... */ if (pattrib->iv_len) { - if (psta != NULL) { + if (psta) { switch (pattrib->encrypt) { case _WEP40_: case _WEP104_: - WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + WEP_IV(pattrib->iv, psta->dot11txpn, + pattrib->key_idx); break; case _TKIP_: if (bmcst) - TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + TKIP_IV(pattrib->iv, + psta->dot11txpn, + pattrib->key_idx); else - TKIP_IV(pattrib->iv, psta->dot11txpn, 0); + TKIP_IV(pattrib->iv, + psta->dot11txpn, 0); break; case _AES_: if (bmcst) - AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + AES_IV(pattrib->iv, + psta->dot11txpn, + pattrib->key_idx); else - AES_IV(pattrib->iv, psta->dot11txpn, 0); + AES_IV(pattrib->iv, + psta->dot11txpn, 0); break; } } @@ -1225,16 +1225,20 @@ s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt, mpdu_len -= llc_sz; } - if ((pattrib->icv_len >0) && (pattrib->bswenc)) + if (pattrib->icv_len > 0 && pattrib->bswenc) mpdu_len -= pattrib->icv_len; - if (bmcst) { + if (bmcst) /* don't do fragment to broadcat/multicast packets */ - mem_sz = _rtw_pktfile_read23a(&pktfile, pframe, pattrib->pktlen); - } else { - mem_sz = _rtw_pktfile_read23a(&pktfile, pframe, mpdu_len); - } + mem_sz = min_t(s32, data_len, pattrib->pktlen); + else + mem_sz = min_t(s32, data_len, mpdu_len); + + memcpy(pframe, pdata, mem_sz); + pframe += mem_sz; + pdata += mem_sz; + data_len -= mem_sz; if ((pattrib->icv_len >0) && (pattrib->bswenc)) { memcpy(pframe, pattrib->icv, pattrib->icv_len); @@ -1243,7 +1247,7 @@ s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt, frg_inx++; - if (bmcst || (rtw_endofpktfile23a(&pktfile))) { + if (bmcst || data_len <= 0) { pattrib->nr_frags = frg_inx; pattrib->last_txcmdsz = pattrib->hdrlen + @@ -1257,16 +1261,18 @@ s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt, break; } else { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __func__)); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("%s: There're still something in packet!\n", + __func__)); } mem_start = PTR_ALIGN(pframe, 4) + hw_hdr_offset; memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen); - } if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n")); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n")); DBG_8723A("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"); res = _FAIL; goto exit; @@ -1313,11 +1319,10 @@ s32 rtw_put_snap23a(u8 *data, u16 h_proto) void rtw_update_protection23a(struct rtw_adapter *padapter, u8 *ie, uint ie_len) { - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct registry_priv *pregistrypriv = &padapter->registrypriv; - uint protection; - u8 *perp; - int erp_len; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + uint protection; + const u8 *p; switch (pxmitpriv->vcs_setting) { case DISABLE_VCS: @@ -1327,11 +1332,11 @@ void rtw_update_protection23a(struct rtw_adapter *padapter, u8 *ie, uint ie_len) break; case AUTO_VCS: default: - perp = rtw_get_ie23a(ie, _ERPINFO_IE_, &erp_len, ie_len); - if (perp == NULL) { + p = cfg80211_find_ie(WLAN_EID_ERP_INFO, ie, ie_len); + if (!p) pxmitpriv->vcs = NONE_VCS; - } else { - protection = (*(perp + 2)) & BIT(1); + else { + protection = (*(p + 2)) & BIT(1); if (protection) { if (pregistrypriv->vcs_type == RTS_CTS) pxmitpriv->vcs = RTS_CTS; @@ -2036,7 +2041,8 @@ int xmitframe_enqueue_for_sleeping_sta23a(struct rtw_adapter *padapter, struct x /* DBG_8723A("enqueue, sq_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */ - update_beacon23a(padapter, _TIM_IE_, NULL, false);/* tx bc/mc packets after upate bcn */ + /* tx bc/mc packets after upate bcn */ + update_beacon23a(padapter, WLAN_EID_TIM, NULL, false); /* spin_unlock_bh(&psta->sleep_q.lock); */ @@ -2093,7 +2099,8 @@ int xmitframe_enqueue_for_sleeping_sta23a(struct rtw_adapter *padapter, struct x if (psta->sleepq_len == 1) { /* upate BCN for TIM IE */ - update_beacon23a(padapter, _TIM_IE_, NULL, false); + update_beacon23a(padapter, WLAN_EID_TIM, + NULL, false); } } @@ -2307,7 +2314,7 @@ void wakeup_sta_to_xmit23a(struct rtw_adapter *padapter, struct sta_info *psta) } if (update_mask) - update_beacon23a(padapter, _TIM_IE_, NULL, false); + update_beacon23a(padapter, WLAN_EID_TIM, NULL, false); } void xmit_delivery_enabled_frames23a(struct rtw_adapter *padapter, @@ -2372,7 +2379,7 @@ void xmit_delivery_enabled_frames23a(struct rtw_adapter *padapter, pstapriv->tim_bitmap &= ~CHKBIT(psta->aid); /* upate BCN for TIM IE */ - update_beacon23a(padapter, _TIM_IE_, NULL, false); + update_beacon23a(padapter, WLAN_EID_TIM, NULL, false); } } spin_unlock_bh(&pxmitpriv->lock); diff --git a/drivers/staging/rtl8723au/hal/hal_com.c b/drivers/staging/rtl8723au/hal/hal_com.c index 0640f3522136d5..8e08977e929b82 100644 --- a/drivers/staging/rtl8723au/hal/hal_com.c +++ b/drivers/staging/rtl8723au/hal/hal_com.c @@ -344,12 +344,6 @@ bool Hal_MappingOutPipe23a(struct rtw_adapter *pAdapter, u8 NumOutPipe) return result; } -void hal_init_macaddr23a(struct rtw_adapter *adapter) -{ - rtw_hal_set_hwreg23a(adapter, HW_VAR_MAC_ADDR, - adapter->eeprompriv.mac_addr); -} - /* * C2H event format: * Field TRIGGER CONTENT CMD_SEQ CMD_LEN CMD_ID @@ -676,11 +670,13 @@ void rtl8723a_cam_empty_entry(struct rtw_adapter *padapter, u8 ucIndex) /* delay_ms(40); */ rtw_write32(padapter, WCAMI, ulContent); /* RT_TRACE(COMP_SEC, DBG_LOUD, - ("CAM_empty_entry23a(): WRITE A4: %lx \n", ulContent));*/ + ("rtl8723a_cam_empty_entry(): WRITE A4: %lx \n", + ulContent));*/ /* delay_ms(40); */ rtw_write32(padapter, RWCAM, ulCommand); /* RT_TRACE(COMP_SEC, DBG_LOUD, - ("CAM_empty_entry23a(): WRITE A0: %lx \n", ulCommand));*/ + ("rtl8723a_cam_empty_entry(): WRITE A0: %lx \n", + ulCommand));*/ } } @@ -689,14 +685,37 @@ void rtl8723a_cam_invalid_all(struct rtw_adapter *padapter) rtw_write32(padapter, RWCAM, BIT(31) | BIT(30)); } -void rtl8723a_cam_write(struct rtw_adapter *padapter, u32 val1, u32 val2) +void rtl8723a_cam_write(struct rtw_adapter *padapter, + u8 entry, u16 ctrl, const u8 *mac, const u8 *key) { u32 cmd; + unsigned int i, val, addr; + int j; + + addr = entry << 3; + + for (j = 5; j >= 0; j--) { + switch (j) { + case 0: + val = ctrl | (mac[0] << 16) | (mac[1] << 24); + break; + case 1: + val = mac[2] | (mac[3] << 8) | + (mac[4] << 16) | (mac[5] << 24); + break; + default: + i = (j - 2) << 2; + val = key[i] | (key[i+1] << 8) | + (key[i+2] << 16) | (key[i+3] << 24); + break; + } - rtw_write32(padapter, WCAMI, val1); + rtw_write32(padapter, WCAMI, val); + cmd = CAM_POLLINIG | CAM_WRITE | (addr + j); + rtw_write32(padapter, RWCAM, cmd); - cmd = CAM_POLLINIG | CAM_WRITE | val2; - rtw_write32(padapter, RWCAM, cmd); + /* DBG_8723A("%s => cam write: %x, %x\n", __func__, cmd, val);*/ + } } void rtl8723a_fifo_cleanup(struct rtw_adapter *padapter) @@ -736,14 +755,6 @@ void rtl8723a_fifo_cleanup(struct rtw_adapter *padapter) } } -void rtl8723a_set_apfm_on_mac(struct rtw_adapter *padapter, u8 val) -{ - struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); - - pHalData->bMacPwrCtrlOn = val; - DBG_8723A("%s: bMacPwrCtrlOn =%d\n", __func__, pHalData->bMacPwrCtrlOn); -} - void rtl8723a_bcn_valid(struct rtw_adapter *padapter) { /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2, @@ -752,9 +763,13 @@ void rtl8723a_bcn_valid(struct rtw_adapter *padapter) rtw_read8(padapter, REG_TDECTRL + 2) | BIT0); } -void rtl8723a_set_tx_pause(struct rtw_adapter *padapter, u8 pause) +bool rtl8723a_get_bcn_valid(struct rtw_adapter *padapter) { - rtw_write8(padapter, REG_TXPAUSE, pause); + bool retval; + + retval = (rtw_read8(padapter, REG_TDECTRL + 2) & BIT0) ? true : false; + + return retval; } void rtl8723a_set_beacon_interval(struct rtw_adapter *padapter, u16 interval) @@ -837,23 +852,18 @@ void rtl8723a_set_initial_gain(struct rtw_adapter *padapter, u32 rx_gain) } } -void rtl8723a_odm_support_ability_write(struct rtw_adapter *padapter, u32 val) +void rtl8723a_odm_support_ability_restore(struct rtw_adapter *padapter) { struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); - pHalData->odmpriv.SupportAbility = val; + pHalData->odmpriv.SupportAbility = pHalData->odmpriv.BK_SupportAbility; } -void rtl8723a_odm_support_ability_backup(struct rtw_adapter *padapter, u8 val) +void rtl8723a_odm_support_ability_backup(struct rtw_adapter *padapter) { struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); - if (val) /* save dm flag */ - pHalData->odmpriv.BK_SupportAbility = - pHalData->odmpriv.SupportAbility; - else /* restore dm flag */ - pHalData->odmpriv.SupportAbility = - pHalData->odmpriv.BK_SupportAbility; + pHalData->odmpriv.BK_SupportAbility = pHalData->odmpriv.SupportAbility; } void rtl8723a_odm_support_ability_set(struct rtw_adapter *padapter, u32 val) @@ -879,3 +889,42 @@ void rtl8723a_set_rpwm(struct rtw_adapter *padapter, u8 val) { rtw_write8(padapter, REG_USB_HRPWM, val); } + +u8 rtl8723a_get_rf_type(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + return pHalData->rf_type; +} + +bool rtl8723a_get_fwlps_rf_on(struct rtw_adapter *padapter) +{ + bool retval; + u32 valRCR; + + /* When we halt NIC, we should check if FW LPS is leave. */ + + if ((padapter->bSurpriseRemoved == true) || + (padapter->pwrctrlpriv.rf_pwrstate == rf_off)) { + /* If it is in HW/SW Radio OFF or IPS state, we do + not check Fw LPS Leave, because Fw is unload. */ + retval = true; + } else { + valRCR = rtw_read32(padapter, REG_RCR); + if (valRCR & 0x00070000) + retval = false; + else + retval = true; + } + + return retval; +} + +bool rtl8723a_chk_hi_queue_empty(struct rtw_adapter *padapter) +{ + u32 hgq; + + hgq = rtw_read32(padapter, REG_HGQ_INFORMATION); + + return ((hgq & 0x0000ff00) == 0) ? true : false; +} diff --git a/drivers/staging/rtl8723au/hal/hal_intf.c b/drivers/staging/rtl8723au/hal/hal_intf.c index de3608b4010aec..1931f428722f55 100644 --- a/drivers/staging/rtl8723au/hal/hal_intf.c +++ b/drivers/staging/rtl8723au/hal/hal_intf.c @@ -117,18 +117,6 @@ uint rtw_hal_deinit23a(struct rtw_adapter *padapter) return status; } -void rtw_hal_set_hwreg23a(struct rtw_adapter *padapter, u8 variable, u8 *val) -{ - if (padapter->HalFunc.SetHwRegHandler) - padapter->HalFunc.SetHwRegHandler(padapter, variable, val); -} - -void rtw23a_hal_get_hwreg(struct rtw_adapter *padapter, u8 variable, u8 *val) -{ - if (padapter->HalFunc.GetHwRegHandler) - padapter->HalFunc.GetHwRegHandler(padapter, variable, val); -} - u8 rtw_hal_set_def_var23a(struct rtw_adapter *padapter, enum hal_def_variable eVariable, void *pValue) { if (padapter->HalFunc.SetHalDefVarHandler) @@ -190,13 +178,6 @@ u32 rtw_hal_inirp_deinit23a(struct rtw_adapter *padapter) } -u8 rtw_hal_intf_ps_func23a(struct rtw_adapter *padapter, enum hal_intf_ps_func efunc_id, u8 *val) -{ - if (padapter->HalFunc.interface_ps_func) - return padapter->HalFunc.interface_ps_func(padapter, efunc_id, val); - return _FAIL; -} - s32 rtw_hal_xmit23aframe_enqueue(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe) { if (padapter->HalFunc.hal_xmitframe_enqueue) @@ -274,32 +255,6 @@ void rtw_hal_add_ra_tid23a(struct rtw_adapter *padapter, u32 bitmap, u8 arg, u8 padapter->HalFunc.Add_RateATid(padapter, bitmap, arg, rssi_level); } -/* Start specifical interface thread */ -void rtw_hal_start_thread23a(struct rtw_adapter *padapter) -{ - if (padapter->HalFunc.run_thread) - padapter->HalFunc.run_thread(padapter); -} -/* Start specifical interface thread */ -void rtw_hal_stop_thread23a(struct rtw_adapter *padapter) -{ - if (padapter->HalFunc.cancel_thread) - padapter->HalFunc.cancel_thread(padapter); -} - -u32 rtw_hal_read_bbreg23a(struct rtw_adapter *padapter, u32 RegAddr, u32 BitMask) -{ - u32 data = 0; - if (padapter->HalFunc.read_bbreg) - data = padapter->HalFunc.read_bbreg(padapter, RegAddr, BitMask); - return data; -} -void rtw_hal_write_bbreg23a(struct rtw_adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data) -{ - if (padapter->HalFunc.write_bbreg) - padapter->HalFunc.write_bbreg(padapter, RegAddr, BitMask, Data); -} - u32 rtw_hal_read_rfreg23a(struct rtw_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask) { u32 data = 0; diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c b/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c index 9d738d79de4bb7..0d1452757a09c1 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c +++ b/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c @@ -3944,7 +3944,6 @@ bthci_CmdAMPTestEnd(struct rtw_adapter *padapter, enum hci_status status = HCI_STATUS_SUCCESS; struct bt_30info *pBTInfo = GET_BT_INFO(padapter); struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; - u8 bFilterOutNonAssociatedBSSID = true; if (!pBtHciInfo->bInTestMode) { RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Not in Test mode, return status = HCI_STATUS_CMD_DISALLOW\n")); @@ -3956,7 +3955,7 @@ bthci_CmdAMPTestEnd(struct rtw_adapter *padapter, del_timer_sync(&pBTInfo->BTTestSendPacketTimer); - rtw_hal_set_hwreg23a(padapter, HW_VAR_CHECK_BSSID, (u8 *)(&bFilterOutNonAssociatedBSSID)); + rtl8723a_check_bssid(padapter, true); /* send command complete event here when all data are received. */ { @@ -4057,8 +4056,7 @@ bthci_CmdAMPTestCommand(struct rtw_adapter *padapter, jiffies + msecs_to_jiffies(50)); RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("TX Single Test \n")); } else if (pBtHciInfo->TestScenario == 0x02) { - u8 bFilterOutNonAssociatedBSSID = false; - rtw_hal_set_hwreg23a(padapter, HW_VAR_CHECK_BSSID, (u8 *)(&bFilterOutNonAssociatedBSSID)); + rtl8723a_check_bssid(padapter, false); RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Receive Frame Test \n")); } @@ -4677,7 +4675,7 @@ bthci_StateConnected(struct rtw_adapter *padapter, if (padapter->HalFunc.UpdateRAMaskHandler) padapter->HalFunc.UpdateRAMaskHandler(padapter, MAX_FW_SUPPORT_MACID_NUM-1-EntryNum, 0); - rtw_hal_set_hwreg23a(padapter, HW_VAR_BASIC_RATE, padapter->mlmepriv.cur_network.network.SupportedRates); + HalSetBrateCfg23a(padapter, padapter->mlmepriv.cur_network.network.SupportedRates); BTDM_SetFwChnlInfo(padapter, RT_MEDIA_CONNECT); break; default: @@ -5764,13 +5762,17 @@ static void btdm_1AntCoexProcessForWifiConnect(struct rtw_adapter *padapter) pBtdm8723 = &pBtCoex->btdm1Ant; BtState = pBtCoex->c2hBtInfo; - RTPRINT(FBT, BT_TRACE, ("[BTCoex], WiFi is %s\n", BTDM_IsWifiBusy(padapter)?"Busy":"IDLE")); - RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT is %s\n", BtStateString[BtState])); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], WiFi is %s\n", + BTDM_IsWifiBusy(padapter)?"Busy":"IDLE")); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT is %s\n", + BtStateString[BtState])); padapter->pwrctrlpriv.btcoex_rfon = false; - if ((!BTDM_IsWifiBusy(padapter)) && (!check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE)) && - ((BtState == BT_INFO_STATE_NO_CONNECTION) || (BtState == BT_INFO_STATE_CONNECT_IDLE))) { + if (!BTDM_IsWifiBusy(padapter) && + !check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) && + (BtState == BT_INFO_STATE_NO_CONNECTION || + BtState == BT_INFO_STATE_CONNECT_IDLE)) { switch (BtState) { case BT_INFO_STATE_NO_CONNECTION: _btdm_1AntSetPSTDMA(padapter, true, 2, 0x26, false, 9); @@ -5789,20 +5791,25 @@ static void btdm_1AntCoexProcessForWifiConnect(struct rtw_adapter *padapter) rtw_write32(padapter, 0x6c4, 0x5a5a5a5a); break; case BT_INFO_STATE_ACL_INQ_OR_PAG: - RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is BT_INFO_STATE_ACL_INQ_OR_PAG\n")); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], BT PROFILE is " + "BT_INFO_STATE_ACL_INQ_OR_PAG\n")); case BT_INFO_STATE_INQ_OR_PAG: padapter->pwrctrlpriv.btcoex_rfon = true; btdm_1AntSetPSTDMA(padapter, true, 0, true, 30); break; case BT_INFO_STATE_SCO_ONLY_BUSY: case BT_INFO_STATE_ACL_SCO_BUSY: - if (true == pBtCoex->bC2hBtInquiryPage) { - btdm_1AntSetPSTDMA(padapter, false, 0, true, 32); - } else { + if (true == pBtCoex->bC2hBtInquiryPage) + btdm_1AntSetPSTDMA(padapter, false, 0, + true, 32); + else { #ifdef BTCOEX_CMCC_TEST - btdm_1AntSetPSTDMA(padapter, false, 0, true, 23); + btdm_1AntSetPSTDMA(padapter, false, 0, + true, 23); #else /* !BTCOEX_CMCC_TEST */ - btdm_1AntSetPSTDMA(padapter, false, 0, false, 8); + btdm_1AntSetPSTDMA(padapter, false, 0, + false, 8); rtw_write32(padapter, 0x6c0, 0x5a5a5a5a); rtw_write32(padapter, 0x6c4, 0x5a5a5a5a); #endif /* !BTCOEX_CMCC_TEST */ @@ -5811,19 +5818,28 @@ static void btdm_1AntCoexProcessForWifiConnect(struct rtw_adapter *padapter) case BT_INFO_STATE_ACL_ONLY_BUSY: padapter->pwrctrlpriv.btcoex_rfon = true; if (pBtCoex->c2hBtProfile == BT_INFO_HID) { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is HID\n")); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], BT PROFILE is HID\n")); btdm_1AntSetPSTDMA(padapter, true, 0, true, 31); } else if (pBtCoex->c2hBtProfile == BT_INFO_FTP) { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is FTP/OPP\n")); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], BT PROFILE is FTP/OPP\n")); btdm_1AntSetPSTDMA(padapter, true, 0, true, 3); } else if (pBtCoex->c2hBtProfile == (BT_INFO_A2DP|BT_INFO_FTP)) { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is A2DP_FTP\n")); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], BT PROFILE is A2DP_FTP\n")); btdm_1AntSetPSTDMA(padapter, true, 0, true, 11); } else { if (pBtCoex->c2hBtProfile == BT_INFO_A2DP) - RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is A2DP\n")); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], BT PROFILE is " + "A2DP\n")); else - RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is UNKNOWN(0x%02X)! Use A2DP Profile\n", pBtCoex->c2hBtProfile)); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], BT PROFILE is " + "UNKNOWN(0x%02X)! Use A2DP " + "Profile\n", + pBtCoex->c2hBtProfile)); btdm_1AntTdmaDurationAdjustForACL(padapter); } break; @@ -5833,13 +5849,14 @@ static void btdm_1AntCoexProcessForWifiConnect(struct rtw_adapter *padapter) pBtdm8723->psTdmaGlobalCnt++; } -static void btdm_1AntUpdateHalRAMask(struct rtw_adapter *padapter, u32 mac_id, u32 filter) +static void +btdm_1AntUpdateHalRAMask(struct rtw_adapter *padapter, u32 mac_id, u32 filter) { u8 init_rate = 0; u8 raid; u32 mask; u8 shortGIrate = false; - int supportRateNum = 0; + int supportRateNum = 0; struct sta_info *psta; struct hal_data_8723a *pHalData; struct dm_priv *pdmpriv; @@ -5847,7 +5864,8 @@ static void btdm_1AntUpdateHalRAMask(struct rtw_adapter *padapter, u32 mac_id, u struct mlme_ext_info *pmlmeinfo; struct wlan_bssid_ex *cur_network; - RTPRINT(FBT, BT_TRACE, ("[BTCoex], %s, MACID =%d, filter = 0x%08x!!\n", __func__, mac_id, filter)); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], %s, MACID =%d, filter = 0x%08x!!\n", + __func__, mac_id, filter)); pHalData = GET_HAL_DATA(padapter); pdmpriv = &pHalData->dmpriv; @@ -5856,13 +5874,15 @@ static void btdm_1AntUpdateHalRAMask(struct rtw_adapter *padapter, u32 mac_id, u cur_network = &pmlmeinfo->network; if (mac_id >= NUM_STA) { /* CAM_SIZE */ - RTPRINT(FBT, BT_TRACE, ("[BTCoex], %s, MACID =%d illegal!!\n", __func__, mac_id)); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], %s, MACID =%d illegal!!\n", + __func__, mac_id)); return; } psta = pmlmeinfo->FW_sta_info[mac_id].psta; - if (psta == NULL) { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], %s, Can't find station!!\n", __func__)); + if (!psta) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], %s, Can't find station!!\n", + __func__)); return; } @@ -5870,19 +5890,26 @@ static void btdm_1AntUpdateHalRAMask(struct rtw_adapter *padapter, u32 mac_id, u switch (mac_id) { case 0:/* for infra mode */ - supportRateNum = rtw_get_rateset_len23a(cur_network->SupportedRates); - mask = update_supported_rate23a(cur_network->SupportedRates, supportRateNum); - mask |= (pmlmeinfo->HT_enable) ? update_MSC_rate23a(&pmlmeinfo->HT_caps):0; + supportRateNum = + rtw_get_rateset_len23a(cur_network->SupportedRates); + mask = update_supported_rate23a(cur_network->SupportedRates, + supportRateNum); + mask |= (pmlmeinfo->HT_enable) ? + update_MSC_rate23a(&pmlmeinfo->HT_caps):0; if (support_short_GI23a(padapter, &pmlmeinfo->HT_caps)) shortGIrate = true; break; case 1:/* for broadcast/multicast */ - supportRateNum = rtw_get_rateset_len23a(pmlmeinfo->FW_sta_info[mac_id].SupportedRates); - mask = update_basic_rate23a(cur_network->SupportedRates, supportRateNum); + supportRateNum = rtw_get_rateset_len23a( + pmlmeinfo->FW_sta_info[mac_id].SupportedRates); + mask = update_basic_rate23a(cur_network->SupportedRates, + supportRateNum); break; default: /* for each sta in IBSS */ - supportRateNum = rtw_get_rateset_len23a(pmlmeinfo->FW_sta_info[mac_id].SupportedRates); - mask = update_supported_rate23a(cur_network->SupportedRates, supportRateNum); + supportRateNum = rtw_get_rateset_len23a( + pmlmeinfo->FW_sta_info[mac_id].SupportedRates); + mask = update_supported_rate23a(cur_network->SupportedRates, + supportRateNum); break; } mask |= ((raid<<28)&0xf0000000); @@ -5899,8 +5926,8 @@ static void btdm_1AntUpdateHalRAMask(struct rtw_adapter *padapter, u32 mac_id, u arg |= BIT(5); RTPRINT(FBT, BT_TRACE, - ("[BTCoex], Update FW RAID entry, MASK = 0x%08x, arg = 0x%02x\n", - mask, arg)); + ("[BTCoex], Update FW RAID entry, MASK = 0x%08x, " + "arg = 0x%02x\n", mask, arg)); rtl8723a_set_raid_cmd(padapter, mask, arg); } else { @@ -5914,7 +5941,8 @@ static void btdm_1AntUpdateHalRAMask(struct rtw_adapter *padapter, u32 mac_id, u pdmpriv->INIDATA_RATE[mac_id] = init_rate; } -static void btdm_1AntUpdateHalRAMaskForSCO(struct rtw_adapter *padapter, u8 forceUpdate) +static void +btdm_1AntUpdateHalRAMaskForSCO(struct rtw_adapter *padapter, u8 forceUpdate) { struct btdm_8723a_1ant *pBtdm8723; struct sta_priv *pstapriv; @@ -5925,7 +5953,7 @@ static void btdm_1AntUpdateHalRAMaskForSCO(struct rtw_adapter *padapter, u8 forc pBtdm8723 = &GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant; - if ((pBtdm8723->bRAChanged == true) && (forceUpdate == false)) + if (pBtdm8723->bRAChanged == true && forceUpdate == false) return; pstapriv = &padapter->stapriv; @@ -5968,9 +5996,13 @@ static void btdm_1AntRecoverHalRAMask(struct rtw_adapter *padapter) static void btdm_1AntBTStateChangeHandler(struct rtw_adapter *padapter, - enum bt_state_1ant oldState, enum bt_state_1ant newState) + enum bt_state_1ant oldState, + enum bt_state_1ant newState) { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT state change, %s => %s\n", BtStateString[oldState], BtStateString[newState])); + struct hal_data_8723a *phaldata; + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT state change, %s => %s\n", + BtStateString[oldState], + BtStateString[newState])); /* BT default ignore wlan active, */ /* WiFi MUST disable this when BT is enable */ @@ -5987,22 +6019,23 @@ btdm_1AntBTStateChangeHandler(struct rtw_adapter *padapter, btdm_1AntRecoverHalRAMask(padapter); } } else { - GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant.bRAChanged = false; + phaldata = GET_HAL_DATA(padapter); + phaldata->bt_coexist.halCoex8723.btdm1Ant.bRAChanged = false; } if (oldState == newState) return; if (oldState == BT_INFO_STATE_ACL_ONLY_BUSY) { - struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); - pHalData->bt_coexist.halCoex8723.btdm1Ant.psTdmaMonitorCnt = 0; - pHalData->bt_coexist.halCoex8723.btdm1Ant.psTdmaMonitorCntForSCO = 0; + struct hal_data_8723a *Hal = GET_HAL_DATA(padapter); + Hal->bt_coexist.halCoex8723.btdm1Ant.psTdmaMonitorCnt = 0; + Hal->bt_coexist.halCoex8723.btdm1Ant.psTdmaMonitorCntForSCO = 0; } if ((oldState == BT_INFO_STATE_SCO_ONLY_BUSY) || (oldState == BT_INFO_STATE_ACL_SCO_BUSY)) { - struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); - pHalData->bt_coexist.halCoex8723.btdm1Ant.psTdmaMonitorCntForSCO = 0; + struct hal_data_8723a *Hal = GET_HAL_DATA(padapter); + Hal->bt_coexist.halCoex8723.btdm1Ant.psTdmaMonitorCntForSCO = 0; } /* Active 2Ant mechanism when BT Connected */ @@ -6010,14 +6043,16 @@ btdm_1AntBTStateChangeHandler(struct rtw_adapter *padapter, (oldState == BT_INFO_STATE_NO_CONNECTION)) { if ((newState != BT_INFO_STATE_DISABLED) && (newState != BT_INFO_STATE_NO_CONNECTION)) { - BTDM_SetSwRfRxLpfCorner(padapter, BT_RF_RX_LPF_CORNER_SHRINK); + BTDM_SetSwRfRxLpfCorner(padapter, + BT_RF_RX_LPF_CORNER_SHRINK); BTDM_AGCTable(padapter, BT_AGCTABLE_ON); BTDM_BBBackOffLevel(padapter, BT_BB_BACKOFF_ON); } } else { if ((newState == BT_INFO_STATE_DISABLED) || (newState == BT_INFO_STATE_NO_CONNECTION)) { - BTDM_SetSwRfRxLpfCorner(padapter, BT_RF_RX_LPF_CORNER_RESUME); + BTDM_SetSwRfRxLpfCorner(padapter, + BT_RF_RX_LPF_CORNER_RESUME); BTDM_AGCTable(padapter, BT_AGCTABLE_OFF); BTDM_BBBackOffLevel(padapter, BT_BB_BACKOFF_OFF); } @@ -6038,17 +6073,23 @@ static void btdm_1AntBtCoexistHandler(struct rtw_adapter *padapter) RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT is disabled\n")); if (BTDM_IsWifiConnectionExist(padapter)) { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is connected\n")); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], wifi is connected\n")); if (BTDM_IsWifiBusy(padapter)) { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], Wifi is busy\n")); - btdm_1AntSetPSTDMA(padapter, false, 0, false, 9); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], Wifi is busy\n")); + btdm_1AntSetPSTDMA(padapter, false, 0, + false, 9); } else { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], Wifi is idle\n")); - _btdm_1AntSetPSTDMA(padapter, true, 2, 1, false, 9); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], Wifi is idle\n")); + _btdm_1AntSetPSTDMA(padapter, true, 2, 1, + false, 9); } } else { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is disconnected\n")); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], wifi is disconnected\n")); btdm_1AntSetPSTDMA(padapter, false, 0, false, 9); } @@ -6056,24 +6097,29 @@ static void btdm_1AntBtCoexistHandler(struct rtw_adapter *padapter) RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT is enabled\n")); if (BTDM_IsWifiConnectionExist(padapter)) { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is connected\n")); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], wifi is connected\n")); btdm_1AntWifiParaAdjust(padapter, true); btdm_1AntCoexProcessForWifiConnect(padapter); } else { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is disconnected\n")); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], wifi is disconnected\n")); - /* Antenna switch at BT side(0x870 = 0x300, 0x860 = 0x210) after PSTDMA off */ + /* Antenna switch at BT side(0x870 = 0x300, + 0x860 = 0x210) after PSTDMA off */ btdm_1AntWifiParaAdjust(padapter, false); btdm_1AntSetPSTDMA(padapter, false, 0, false, 0); } } - btdm_1AntBTStateChangeHandler(padapter, pBtCoex8723->prec2hBtInfo, pBtCoex8723->c2hBtInfo); + btdm_1AntBTStateChangeHandler(padapter, pBtCoex8723->prec2hBtInfo, + pBtCoex8723->c2hBtInfo); pBtCoex8723->prec2hBtInfo = pBtCoex8723->c2hBtInfo; } -void BTDM_1AntSignalCompensation(struct rtw_adapter *padapter, u8 *rssi_wifi, u8 *rssi_bt) +void BTDM_1AntSignalCompensation(struct rtw_adapter *padapter, + u8 *rssi_wifi, u8 *rssi_bt) { struct hal_data_8723a *pHalData; struct btdm_8723a_1ant *pBtdm8723; @@ -6119,14 +6165,19 @@ void BTDM_1AntSignalCompensation(struct rtw_adapter *padapter, u8 *rssi_wifi, u8 } if (rssi_wifi && RSSI_WiFi_Cmpnstn) { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1AntSgnlCmpnstn, case %d, WiFiCmpnstn =%d(%d => %d)\n", - pBtdm8723->curPsTdma, RSSI_WiFi_Cmpnstn, *rssi_wifi, *rssi_wifi+RSSI_WiFi_Cmpnstn)); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], 1AntSgnlCmpnstn, case %d, WiFiCmpnstn " + "=%d(%d => %d)\n", pBtdm8723->curPsTdma, + RSSI_WiFi_Cmpnstn, *rssi_wifi, + *rssi_wifi+RSSI_WiFi_Cmpnstn)); *rssi_wifi += RSSI_WiFi_Cmpnstn; } if (rssi_bt && RSSI_BT_Cmpnstn) { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1AntSgnlCmpnstn, case %d, BTCmpnstn =%d(%d => %d)\n", - pBtdm8723->curPsTdma, RSSI_BT_Cmpnstn, *rssi_bt, *rssi_bt+RSSI_BT_Cmpnstn)); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], 1AntSgnlCmpnstn, case %d, BTCmpnstn " + "=%d(%d => %d)\n", pBtdm8723->curPsTdma, + RSSI_BT_Cmpnstn, *rssi_bt, *rssi_bt+RSSI_BT_Cmpnstn)); *rssi_bt += RSSI_BT_Cmpnstn; } } @@ -6162,7 +6213,8 @@ static void BTDM_1AntForHalt(struct rtw_adapter *padapter) { RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for halt\n")); - GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant.bWiFiHalt = true; + GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant.bWiFiHalt = + true; btdm_1AntWifiParaAdjust(padapter, false); @@ -6180,7 +6232,8 @@ static void BTDM_1AntLpsLeave(struct rtw_adapter *padapter) RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for LPS Leave\n")); /* Prevent from entering LPS again */ - GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant.bWiFiHalt = true; + GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant.bWiFiHalt = + true; btdm_1AntSetPSTDMA(padapter, false, 0, false, 8); /*btdm_1AntPsTdma(padapter, false, 8); */ @@ -6190,13 +6243,14 @@ static void BTDM_1AntWifiAssociateNotify(struct rtw_adapter *padapter, u8 type) { struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); - RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for associate, type =%d\n", type)); + RTPRINT(FBT, BT_TRACE, + ("\n[BTCoex], 1Ant for associate, type =%d\n", type)); if (type) { rtl8723a_CheckAntenna_Selection(padapter); - if (BT_IsBtDisabled(padapter)) { + if (BT_IsBtDisabled(padapter)) btdm_1AntSetPSTDMA(padapter, false, 0, false, 9); - } else { + else { struct bt_coexist_8723a *pBtCoex; u8 BtState; @@ -6205,20 +6259,24 @@ static void BTDM_1AntWifiAssociateNotify(struct rtw_adapter *padapter, u8 type) btdm_1AntTSFSwitch(padapter, true); - if ((BtState == BT_INFO_STATE_NO_CONNECTION) || - (BtState == BT_INFO_STATE_CONNECT_IDLE)) { - btdm_1AntSetPSTDMA(padapter, false, 0, true, 28); - } else if ((BtState == BT_INFO_STATE_SCO_ONLY_BUSY) || - (BtState == BT_INFO_STATE_ACL_SCO_BUSY)) { - btdm_1AntSetPSTDMA(padapter, false, 0, false, 8); + if (BtState == BT_INFO_STATE_NO_CONNECTION || + BtState == BT_INFO_STATE_CONNECT_IDLE) { + btdm_1AntSetPSTDMA(padapter, false, 0, + true, 28); + } else if (BtState == BT_INFO_STATE_SCO_ONLY_BUSY || + BtState == BT_INFO_STATE_ACL_SCO_BUSY) { + btdm_1AntSetPSTDMA(padapter, false, 0, + false, 8); rtw_write32(padapter, 0x6c0, 0x5a5a5a5a); rtw_write32(padapter, 0x6c4, 0x5a5a5a5a); - } else if ((BtState == BT_INFO_STATE_ACL_ONLY_BUSY) || - (BtState == BT_INFO_STATE_ACL_INQ_OR_PAG)) { + } else if (BtState == BT_INFO_STATE_ACL_ONLY_BUSY || + BtState == BT_INFO_STATE_ACL_INQ_OR_PAG) { if (pBtCoex->c2hBtProfile == BT_INFO_HID) - btdm_1AntSetPSTDMA(padapter, false, 0, true, 35); + btdm_1AntSetPSTDMA(padapter, false, 0, + true, 35); else - btdm_1AntSetPSTDMA(padapter, false, 0, true, 29); + btdm_1AntSetPSTDMA(padapter, false, 0, + true, 29); } } } else { @@ -6241,22 +6299,24 @@ BTDM_1AntMediaStatusNotify(struct rtw_adapter *padapter, pBtCoex = &GET_HAL_DATA(padapter)->bt_coexist.halCoex8723; - RTPRINT(FBT, BT_TRACE, ("\n\n[BTCoex]******************************\n")); + RTPRINT(FBT, BT_TRACE, + ("\n\n[BTCoex]******************************\n")); RTPRINT(FBT, BT_TRACE, ("[BTCoex], MediaStatus, WiFi %s !!\n", mstatus == RT_MEDIA_CONNECT?"CONNECT":"DISCONNECT")); RTPRINT(FBT, BT_TRACE, ("[BTCoex]******************************\n")); if (RT_MEDIA_CONNECT == mstatus) { if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE)) { - if ((pBtCoex->c2hBtInfo == BT_INFO_STATE_SCO_ONLY_BUSY) || - (pBtCoex->c2hBtInfo == BT_INFO_STATE_ACL_SCO_BUSY)) + if (pBtCoex->c2hBtInfo == BT_INFO_STATE_SCO_ONLY_BUSY || + pBtCoex->c2hBtInfo == BT_INFO_STATE_ACL_SCO_BUSY) btdm_1AntUpdateHalRAMaskForSCO(padapter, true); } padapter->pwrctrlpriv.DelayLPSLastTimeStamp = jiffies; BTDM_1AntForDhcp(padapter); } else { - /* DBG_8723A("%s rtl8723a_DeinitAntenna_Selection\n", __func__); */ + /* DBG_8723A("%s rtl8723a_DeinitAntenna_Selection\n", + __func__); */ rtl8723a_DeinitAntenna_Selection(padapter); btdm_1AntBtCoexistHandler(padapter); pBtCoex->btdm1Ant.bRAChanged = false; @@ -6276,8 +6336,10 @@ void BTDM_1AntForDhcp(struct rtw_adapter *padapter) pBtdm8723 = &pBtCoex->btdm1Ant; RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for DHCP\n")); - RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for DHCP, WiFi is %s\n", BTDM_IsWifiBusy(padapter)?"Busy":"IDLE")); - RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for DHCP, %s\n", BtStateString[BtState])); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for DHCP, WiFi is %s\n", + BTDM_IsWifiBusy(padapter)?"Busy":"IDLE")); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for DHCP, %s\n", + BtStateString[BtState])); BTDM_1AntWifiAssociateNotify(padapter, true); } @@ -6294,9 +6356,12 @@ static void BTDM_1AntWifiScanNotify(struct rtw_adapter *padapter, u8 scanType) pBtCoex = &pHalData->bt_coexist.halCoex8723; pBtdm8723 = &pBtCoex->btdm1Ant; - RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for wifi scan =%d!!\n", scanType)); - RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for wifi scan, WiFi is %s\n", BTDM_IsWifiBusy(padapter)?"Busy":"IDLE")); - RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for wifi scan, %s\n", BtStateString[BtState])); + RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for wifi scan =%d!!\n", + scanType)); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for wifi scan, WiFi is %s\n", + BTDM_IsWifiBusy(padapter)?"Busy":"IDLE")); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for wifi scan, %s\n", + BtStateString[BtState])); if (scanType) { rtl8723a_CheckAntenna_Selection(padapter); @@ -6308,10 +6373,13 @@ static void BTDM_1AntWifiScanNotify(struct rtw_adapter *padapter, u8 scanType) if ((BtState == BT_INFO_STATE_SCO_ONLY_BUSY) || (BtState == BT_INFO_STATE_ACL_SCO_BUSY)) { if (pBtCoex->bC2hBtInquiryPage) { - btdm_1AntSetPSTDMA(padapter, false, 0, true, 32); + btdm_1AntSetPSTDMA(padapter, false, 0, + true, 32); } else { - padapter->pwrctrlpriv.btcoex_rfon = true; - btdm_1AntSetPSTDMA(padapter, true, 0, true, 33); + padapter->pwrctrlpriv.btcoex_rfon = + true; + btdm_1AntSetPSTDMA(padapter, true, 0, + true, 33); } } else if (true == pBtCoex->bC2hBtInquiryPage) { padapter->pwrctrlpriv.btcoex_rfon = true; @@ -6319,9 +6387,11 @@ static void BTDM_1AntWifiScanNotify(struct rtw_adapter *padapter, u8 scanType) } else if (BtState == BT_INFO_STATE_ACL_ONLY_BUSY) { padapter->pwrctrlpriv.btcoex_rfon = true; if (pBtCoex->c2hBtProfile == BT_INFO_HID) - btdm_1AntSetPSTDMA(padapter, true, 0, true, 34); + btdm_1AntSetPSTDMA(padapter, true, 0, + true, 34); else - btdm_1AntSetPSTDMA(padapter, true, 0, true, 4); + btdm_1AntSetPSTDMA(padapter, true, 0, + true, 4); } else { padapter->pwrctrlpriv.btcoex_rfon = true; btdm_1AntSetPSTDMA(padapter, true, 0, true, 5); @@ -6365,16 +6435,18 @@ static void BTDM_1AntFwC2hBtInfo8723A(struct rtw_adapter *padapter) pBtCoex->bC2hBtInquiryPage = false; btState &= ~BIT(2); - if (!(btState & BIT(0))) { + if (!(btState & BIT(0))) pBtCoex->c2hBtInfo = BT_INFO_STATE_NO_CONNECTION; - } else { - if (btState == 0x1) { + else { + if (btState == 0x1) pBtCoex->c2hBtInfo = BT_INFO_STATE_CONNECT_IDLE; - } else if (btState == 0x9) { + else if (btState == 0x9) { if (pBtCoex->bC2hBtInquiryPage == true) - pBtCoex->c2hBtInfo = BT_INFO_STATE_ACL_INQ_OR_PAG; + pBtCoex->c2hBtInfo = + BT_INFO_STATE_ACL_INQ_OR_PAG; else - pBtCoex->c2hBtInfo = BT_INFO_STATE_ACL_ONLY_BUSY; + pBtCoex->c2hBtInfo = + BT_INFO_STATE_ACL_ONLY_BUSY; pBtMgnt->ExtConfig.bBTBusy = true; } else if (btState == 0x3) { pBtCoex->c2hBtInfo = BT_INFO_STATE_SCO_ONLY_BUSY; @@ -6382,15 +6454,15 @@ static void BTDM_1AntFwC2hBtInfo8723A(struct rtw_adapter *padapter) } else if (btState == 0xb) { pBtCoex->c2hBtInfo = BT_INFO_STATE_ACL_SCO_BUSY; pBtMgnt->ExtConfig.bBTBusy = true; - } else { + } else pBtCoex->c2hBtInfo = BT_INFO_STATE_MAX; - } if (pBtMgnt->ExtConfig.bBTBusy) - pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_IDLE; + pHalData->bt_coexist.CurrentState &= + ~BT_COEX_STATE_BT_IDLE; } - if ((BT_INFO_STATE_NO_CONNECTION == pBtCoex->c2hBtInfo) || - (BT_INFO_STATE_CONNECT_IDLE == pBtCoex->c2hBtInfo)) { + if (BT_INFO_STATE_NO_CONNECTION == pBtCoex->c2hBtInfo || + BT_INFO_STATE_CONNECT_IDLE == pBtCoex->c2hBtInfo) { if (pBtCoex->bC2hBtInquiryPage) pBtCoex->c2hBtInfo = BT_INFO_STATE_INQ_OR_PAG; } @@ -6413,12 +6485,14 @@ void BTDM_1AntBtCoexist8723A(struct rtw_adapter *padapter) if (check_fwstate(pmlmepriv, WIFI_SITE_MONITOR)) { /* already done in BTDM_1AntForScan() */ - RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is under scan progress!!\n")); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], wifi is under scan progress!!\n")); return; } if (check_fwstate(pmlmepriv, WIFI_UNDER_LINKING)) { - RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is under link progress!!\n")); + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], wifi is under link progress!!\n")); return; } @@ -11221,7 +11295,9 @@ void HALBT_SetKey(struct rtw_adapter *padapter, u8 EntryNum) pBtAssocEntry->HwCAMIndex = BT_HWCAM_STAR + EntryNum; usConfig = CAM_VALID | (CAM_AES << 2); - write_cam23a(padapter, pBtAssocEntry->HwCAMIndex, usConfig, pBtAssocEntry->BTRemoteMACAddr, pBtAssocEntry->PTK + TKIP_ENC_KEY_POS); + rtl8723a_cam_write(padapter, pBtAssocEntry->HwCAMIndex, usConfig, + pBtAssocEntry->BTRemoteMACAddr, + pBtAssocEntry->PTK + TKIP_ENC_KEY_POS); } void HALBT_RemoveKey(struct rtw_adapter *padapter, u8 EntryNum) @@ -11234,8 +11310,10 @@ void HALBT_RemoveKey(struct rtw_adapter *padapter, u8 EntryNum) if (pBTinfo->BtAsocEntry[EntryNum].HwCAMIndex != 0) { /* ToDo : add New HALBT_RemoveKey function !! */ - if (pBtAssocEntry->HwCAMIndex >= BT_HWCAM_STAR && pBtAssocEntry->HwCAMIndex < HALF_CAM_ENTRY) - CAM_empty_entry23a(padapter, pBtAssocEntry->HwCAMIndex); + if (pBtAssocEntry->HwCAMIndex >= BT_HWCAM_STAR && + pBtAssocEntry->HwCAMIndex < HALF_CAM_ENTRY) + rtl8723a_cam_empty_entry(padapter, + pBtAssocEntry->HwCAMIndex); pBTinfo->BtAsocEntry[EntryNum].HwCAMIndex = 0; } } diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_cmd.c b/drivers/staging/rtl8723au/hal/rtl8723a_cmd.c index 0b205e1204fc3e..ffd6b73eb6a89a 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723a_cmd.c +++ b/drivers/staging/rtl8723au/hal/rtl8723a_cmd.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -203,7 +202,7 @@ void rtl8723a_set_FwPwrMode_cmd(struct rtw_adapter *padapter, u8 Mode) static void ConstructBeacon(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength) { struct ieee80211_hdr *pwlanhdr; - u16 *fctrl; + __le16 *fctrl; u32 rate_len, pktlen; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -255,30 +254,36 @@ static void ConstructBeacon(struct rtw_adapter *padapter, u8 *pframe, u32 *pLeng /* below for ad-hoc mode */ /* SSID */ - pframe = rtw_set_ie23a(pframe, _SSID_IE_, cur_network->Ssid.ssid_len, - cur_network->Ssid.ssid, &pktlen); + pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID, + cur_network->Ssid.ssid_len, + cur_network->Ssid.ssid, &pktlen); /* supported rates... */ rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates); - pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? + pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pktlen); /* DS parameter set */ - pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *)&cur_network->Configuration.DSConfig, &pktlen); + pframe = rtw_set_ie23a(pframe, WLAN_EID_DS_PARAMS, 1, (unsigned char *) + &cur_network->Configuration.DSConfig, &pktlen); if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { u32 ATIMWindow; /* IBSS Parameter Set... */ /* ATIMWindow = cur->Configuration.ATIMWindow; */ ATIMWindow = 0; - pframe = rtw_set_ie23a(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen); + pframe = rtw_set_ie23a(pframe, WLAN_EID_IBSS_PARAMS, 2, + (unsigned char *)(&ATIMWindow), &pktlen); } /* todo: ERP IE */ /* EXTERNDED SUPPORTED RATE */ if (rate_len > 8) - pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen); + pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES, + (rate_len - 8), + (cur_network->SupportedRates + 8), + &pktlen); /* todo:HT for adhoc */ @@ -298,7 +303,7 @@ static void ConstructBeacon(struct rtw_adapter *padapter, u8 *pframe, u32 *pLeng static void ConstructPSPoll(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength) { struct ieee80211_hdr *pwlanhdr; - u16 *fctrl; + __le16 *fctrl; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -333,7 +338,7 @@ static void ConstructNullFunctionData( u8 bForcePowerSave) { struct ieee80211_hdr *pwlanhdr; - u16 *fctrl; + __le16 *fctrl; u32 pktlen; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_network *cur_network = &pmlmepriv->cur_network; @@ -397,7 +402,7 @@ static void ConstructNullFunctionData( static void ConstructProbeRsp(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID) { struct ieee80211_hdr *pwlanhdr; - u16 *fctrl; + __le16 *fctrl; u8 *mac, *bssid; u32 pktlen; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; @@ -770,76 +775,3 @@ void rtl8723a_set_BTCoex_AP_mode_FwRsvdPkt_cmd(struct rtw_adapter *padapter) } } #endif - -#ifdef CONFIG_8723AU_P2P -void rtl8723a_set_p2p_ps_offload_cmd(struct rtw_adapter *padapter, u8 p2p_ps_state) -{ - struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - struct P2P_PS_Offload_t *p2p_ps_offload = &pHalData->p2p_ps_offload; - u8 i; - - switch (p2p_ps_state) { - case P2P_PS_DISABLE: - DBG_8723A("P2P_PS_DISABLE \n"); - memset(p2p_ps_offload, 0, 1); - break; - case P2P_PS_ENABLE: - DBG_8723A("P2P_PS_ENABLE \n"); - /* update CTWindow value. */ - if (pwdinfo->ctwindow > 0) { - p2p_ps_offload->CTWindow_En = 1; - rtw_write8(padapter, REG_P2P_CTWIN, pwdinfo->ctwindow); - } - - /* hw only support 2 set of NoA */ - for (i = 0; i < pwdinfo->noa_num; i++) { - /* To control the register setting for which NOA */ - rtw_write8(padapter, REG_NOA_DESC_SEL, (i << 4)); - if (i == 0) - p2p_ps_offload->NoA0_En = 1; - else - p2p_ps_offload->NoA1_En = 1; - - /* config P2P NoA Descriptor Register */ - rtw_write32(padapter, REG_NOA_DESC_DURATION, pwdinfo->noa_duration[i]); - - rtw_write32(padapter, REG_NOA_DESC_INTERVAL, pwdinfo->noa_interval[i]); - - rtw_write32(padapter, REG_NOA_DESC_START, pwdinfo->noa_start_time[i]); - - rtw_write8(padapter, REG_NOA_DESC_COUNT, pwdinfo->noa_count[i]); - } - - if ((pwdinfo->opp_ps == 1) || (pwdinfo->noa_num > 0)) { - /* rst p2p circuit */ - rtw_write8(padapter, REG_DUAL_TSF_RST, BIT(4)); - - p2p_ps_offload->Offload_En = 1; - - if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { - p2p_ps_offload->role = 1; - p2p_ps_offload->AllStaSleep = 0; - } else { - p2p_ps_offload->role = 0; - } - - p2p_ps_offload->discovery = 0; - } - break; - case P2P_PS_SCAN: - DBG_8723A("P2P_PS_SCAN \n"); - p2p_ps_offload->discovery = 1; - break; - case P2P_PS_SCAN_DONE: - DBG_8723A("P2P_PS_SCAN_DONE \n"); - p2p_ps_offload->discovery = 0; - pwdinfo->p2p_ps_state = P2P_PS_ENABLE; - break; - default: - break; - } - - FillH2CCmd(padapter, P2P_PS_OFFLOAD_EID, 1, (u8 *)p2p_ps_offload); -} -#endif /* CONFIG_8723AU_P2P */ diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_dm.c b/drivers/staging/rtl8723au/hal/rtl8723a_dm.c index f204ab1714e7f9..4ca7b8ec7b3860 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723a_dm.c +++ b/drivers/staging/rtl8723au/hal/rtl8723a_dm.c @@ -76,7 +76,7 @@ static void dm_CheckPbcGPIO(struct rtw_adapter *padapter) return; } - rtw_signal_process(padapter->pid[0], SIGUSR1); + kill_pid(find_vpid(padapter->pid[0]), SIGUSR1, 1); } } @@ -217,14 +217,7 @@ rtl8723a_HalDmWatchDog( goto skip_dm; bFwCurrentInPSMode = Adapter->pwrctrlpriv.bFwCurrentInPSMode; - rtw23a_hal_get_hwreg(Adapter, HW_VAR_FWLPS_RF_ON, (u8 *)(&bFwPSAwake)); - -#ifdef CONFIG_8723AU_P2P - /* Fw is under p2p powersaving mode, driver should stop dynamic mechanism. */ - /* modifed by thomas. 2011.06.11. */ - if (Adapter->wdinfo.p2p_ps_mode) - bFwPSAwake = false; -#endif /* CONFIG_8723AU_P2P */ + bFwPSAwake = rtl8723a_get_fwlps_rf_on(Adapter); if ((hw_init_completed) && ((!bFwCurrentInPSMode) && bFwPSAwake)) { /* Calculate Tx/Rx statistics. */ diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c index 0982b0a4ab9b37..ee05bc00655a8c 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c +++ b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c @@ -619,6 +619,7 @@ hal_ReadEFuse_WiFi(struct rtw_adapter *padapter, u8 offset, wden; u8 efuseHeader, efuseExtHdr, efuseData; u16 i, total, used; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */ @@ -696,7 +697,7 @@ hal_ReadEFuse_WiFi(struct rtw_adapter *padapter, EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total); used = eFuse_Addr - 1; - rtw_hal_set_hwreg23a(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&used); + pHalData->EfuseUsedBytes = used; kfree(efuseTbl); } @@ -711,6 +712,7 @@ hal_ReadEFuse_BT(struct rtw_adapter *padapter, u8 efuseHeader, efuseExtHdr, efuseData; u8 offset, wden; u16 i, total, used; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */ @@ -812,7 +814,7 @@ hal_ReadEFuse_BT(struct rtw_adapter *padapter, EFUSE_GetEfuseDefinition23a(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total); used = (EFUSE_BT_REAL_BANK_CONTENT_LEN * (bank - 1)) + eFuse_Addr - 1; - rtw_hal_set_hwreg23a(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *) &used); + pHalData->BTEfuseUsedBytes = used; exit: kfree(efuseTbl); @@ -834,8 +836,9 @@ hal_EfuseGetCurrentSize_WiFi(struct rtw_adapter *padapter) u16 efuse_addr = 0; u8 hoffset = 0, hworden = 0; u8 efuse_data, word_cnts = 0; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); - rtw23a_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *) &efuse_addr); + efuse_addr = pHalData->EfuseUsedBytes; DBG_8723A("%s: start_efuse_addr = 0x%X\n", __func__, efuse_addr); @@ -872,7 +875,7 @@ hal_EfuseGetCurrentSize_WiFi(struct rtw_adapter *padapter) efuse_addr += (word_cnts * 2) + 1; } - rtw_hal_set_hwreg23a(padapter, HW_VAR_EFUSE_BYTES, (u8 *) &efuse_addr); + pHalData->EfuseUsedBytes = efuse_addr; DBG_8723A("%s: CurrentSize =%d\n", __func__, efuse_addr); @@ -888,8 +891,9 @@ hal_EfuseGetCurrentSize_BT(struct rtw_adapter *padapter) u8 hoffset = 0, hworden = 0; u8 efuse_data, word_cnts = 0; u16 retU2 = 0; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); - rtw23a_hal_get_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *) &btusedbytes); + btusedbytes = pHalData->BTEfuseUsedBytes; efuse_addr = (u16) ((btusedbytes % EFUSE_BT_REAL_BANK_CONTENT_LEN)); startBank = (u8) (1 + (btusedbytes / EFUSE_BT_REAL_BANK_CONTENT_LEN)); @@ -954,7 +958,7 @@ hal_EfuseGetCurrentSize_BT(struct rtw_adapter *padapter) } retU2 = ((bank - 1) * EFUSE_BT_REAL_BANK_CONTENT_LEN) + efuse_addr; - rtw_hal_set_hwreg23a(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *)&retU2); + pHalData->BTEfuseUsedBytes = retU2; DBG_8723A("%s: CurrentSize =%d\n", __func__, retU2); return retU2; @@ -1144,6 +1148,7 @@ static u8 hal_EfusePartialWriteCheck(struct rtw_adapter *padapter, u8 efuseType, u16 *pAddr, struct pg_pkt_struct *pTargetPkt) { + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); u8 bRet = false; u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0; u8 efuse_data = 0; @@ -1154,13 +1159,11 @@ hal_EfusePartialWriteCheck(struct rtw_adapter *padapter, u8 efuseType, EFUSE_GetEfuseDefinition23a(padapter, efuseType, TYPE_EFUSE_CONTENT_LEN_BANK, &efuse_max); - if (efuseType == EFUSE_WIFI) { - rtw23a_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, - (u8 *) &startAddr); - } else { - rtw23a_hal_get_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, - (u8 *) &startAddr); - } + if (efuseType == EFUSE_WIFI) + startAddr = pHalData->EfuseUsedBytes; + else + startAddr = pHalData->BTEfuseUsedBytes; + startAddr %= efuse_max; while (1) { @@ -1735,11 +1738,7 @@ void rtl8723a_set_hal_ops(struct hal_ops *pHalFunc) &rtl8723a_SetBeaconRelatedRegisters; pHalFunc->Add_RateATid = &rtl8723a_add_rateatid; - pHalFunc->run_thread = &rtl8723a_start_thread; - pHalFunc->cancel_thread = &rtl8723a_stop_thread; - pHalFunc->read_bbreg = &PHY_QueryBBReg; - pHalFunc->write_bbreg = &PHY_SetBBReg; pHalFunc->read_rfreg = &PHY_QueryRFReg; pHalFunc->write_rfreg = &PHY_SetRFReg; @@ -2041,7 +2040,6 @@ static void _ResetDigitalProcedure1_92C(struct rtw_adapter *padapter, are trying to enter IPS/HW&SW radio off. For S3/S4/S5/Disable, we can stop 8051 because */ /* we will init FW when power on again. */ - /* if (!pDevice->RegUsbSS) */ /* If we want to SS mode, we can not reset 8051. */ if (rtw_read8(padapter, REG_MCUFWDL) & BIT1) { /* IF fw in RAM code, do reset */ @@ -2935,7 +2933,7 @@ void rtl8723a_fill_fake_txdesc(struct rtw_adapter *padapter, u8 *pDesc, rtl8723a_cal_txdesc_chksum(ptxdesc); } -static void hw_var_set_opmode(struct rtw_adapter *padapter, u8 mode) +void hw_var_set_opmode(struct rtw_adapter *padapter, u8 mode) { u8 val8; @@ -2996,7 +2994,7 @@ static void hw_var_set_opmode(struct rtw_adapter *padapter, u8 mode) rtw_write8(padapter, MSR, val8); } -static void hw_var_set_macaddr(struct rtw_adapter *padapter, u8 *val) +void hw_var_set_macaddr(struct rtw_adapter *padapter, u8 *val) { u8 idx = 0; u32 reg_macid; @@ -3007,7 +3005,7 @@ static void hw_var_set_macaddr(struct rtw_adapter *padapter, u8 *val) rtw_write8(padapter, (reg_macid + idx), val[idx]); } -static void hw_var_set_bssid(struct rtw_adapter *padapter, u8 *val) +void hw_var_set_bssid(struct rtw_adapter *padapter, u8 *val) { u8 idx = 0; u32 reg_bssid; @@ -3018,7 +3016,7 @@ static void hw_var_set_bssid(struct rtw_adapter *padapter, u8 *val) rtw_write8(padapter, (reg_bssid + idx), val[idx]); } -static void hw_var_set_correct_tsf(struct rtw_adapter *padapter) +void hw_var_set_correct_tsf(struct rtw_adapter *padapter) { u64 tsf; u32 reg_tsftr; @@ -3028,8 +3026,8 @@ static void hw_var_set_correct_tsf(struct rtw_adapter *padapter) /* tsf = pmlmeext->TSFValue - ((u32)pmlmeext->TSFValue % (pmlmeinfo->bcn_interval*1024)) - 1024; us */ tsf = pmlmeext->TSFValue - - rtw_modular6423a(pmlmeext->TSFValue, - (pmlmeinfo->bcn_interval * 1024)) - 1024; /* us */ + do_div(pmlmeext->TSFValue, + (pmlmeinfo->bcn_interval * 1024)) - 1024; /* us */ if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { @@ -3055,7 +3053,7 @@ static void hw_var_set_correct_tsf(struct rtw_adapter *padapter) ResumeTxBeacon(padapter); } -static void hw_var_set_mlme_disconnect(struct rtw_adapter *padapter) +void hw_var_set_mlme_disconnect(struct rtw_adapter *padapter) { /* reject all data frames */ rtw_write16(padapter, REG_RXFLTMAP2, 0); @@ -3067,7 +3065,7 @@ static void hw_var_set_mlme_disconnect(struct rtw_adapter *padapter) SetBcnCtrlReg23a(padapter, DIS_TSF_UDT, 0); } -static void hw_var_set_mlme_join(struct rtw_adapter *padapter, u8 type) +void hw_var_set_mlme_join(struct rtw_adapter *padapter, u8 type) { u8 RetryLimit = 0x30; @@ -3129,264 +3127,6 @@ static void hw_var_set_mlme_join(struct rtw_adapter *padapter, u8 type) #endif } -void SetHwReg8723A(struct rtw_adapter *padapter, u8 variable, u8 *val) -{ - struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); - u32 *val32 = (u32 *)val; - - switch (variable) { - case HW_VAR_MEDIA_STATUS: - rtl8723a_set_media_status(padapter, *val); - break; - - case HW_VAR_MEDIA_STATUS1: - rtl8723a_set_media_status1(padapter, *val); - break; - - case HW_VAR_SET_OPMODE: - hw_var_set_opmode(padapter, *val); - break; - - case HW_VAR_MAC_ADDR: - hw_var_set_macaddr(padapter, val); - break; - - case HW_VAR_BSSID: - hw_var_set_bssid(padapter, val); - break; - - case HW_VAR_BASIC_RATE: - HalSetBrateCfg23a(padapter, val); - break; - - case HW_VAR_TXPAUSE: - rtl8723a_set_tx_pause(padapter, *val); - break; - - case HW_VAR_BCN_FUNC: - rtl8723a_set_bcn_func(padapter, *val); - break; - - case HW_VAR_CORRECT_TSF: - hw_var_set_correct_tsf(padapter); - break; - - case HW_VAR_CHECK_BSSID: - rtl8723a_check_bssid(padapter, *val); - break; - - case HW_VAR_MLME_DISCONNECT: - hw_var_set_mlme_disconnect(padapter); - break; - - case HW_VAR_MLME_SITESURVEY: - rtl8723a_mlme_sitesurvey(padapter, *val); - break; - - case HW_VAR_MLME_JOIN: - hw_var_set_mlme_join(padapter, *val); - break; - - case HW_VAR_ON_RCR_AM: - rtl8723a_on_rcr_am(padapter); - break; - - case HW_VAR_OFF_RCR_AM: - rtl8723a_off_rcr_am(padapter); - break; - - case HW_VAR_BEACON_INTERVAL: - rtl8723a_set_beacon_interval(padapter, *((u16 *) val)); - break; - - case HW_VAR_SLOT_TIME: - rtl8723a_set_slot_time(padapter, *val); - break; - - case HW_VAR_RESP_SIFS: - rtl8723a_set_resp_sifs(padapter, val[0], val[1], - val[2], val[3]); - break; - - case HW_VAR_ACK_PREAMBLE: - rtl8723a_ack_preamble(padapter, *val); - break; - - case HW_VAR_SEC_CFG: - rtl8723a_set_sec_cfg(padapter, *val); - break; - - case HW_VAR_DM_FLAG: - rtl8723a_odm_support_ability_write(padapter, *val32); - break; - case HW_VAR_DM_FUNC_OP: - rtl8723a_odm_support_ability_backup(padapter, *val); - break; - case HW_VAR_DM_FUNC_SET: - rtl8723a_odm_support_ability_set(padapter, *val32); - break; - - case HW_VAR_DM_FUNC_CLR: - rtl8723a_odm_support_ability_clr(padapter, *val32); - break; - - case HW_VAR_CAM_EMPTY_ENTRY: - rtl8723a_cam_empty_entry(padapter, *val); - break; - - case HW_VAR_CAM_INVALID_ALL: - rtl8723a_cam_invalid_all(padapter); - break; - - case HW_VAR_CAM_WRITE: - rtl8723a_cam_write(padapter, val32[0], val32[1]); - break; - - case HW_VAR_AC_PARAM_VO: - rtl8723a_set_ac_param_vo(padapter, *val32); - break; - - case HW_VAR_AC_PARAM_VI: - rtl8723a_set_ac_param_vi(padapter, *val32); - break; - - case HW_VAR_AC_PARAM_BE: - rtl8723a_set_ac_param_be(padapter, *val32); - break; - - case HW_VAR_AC_PARAM_BK: - rtl8723a_set_ac_param_bk(padapter, *val32); - break; - - case HW_VAR_ACM_CTRL: - rtl8723a_set_acm_ctrl(padapter, *val); - break; - - case HW_VAR_AMPDU_MIN_SPACE: - rtl8723a_set_ampdu_min_space(padapter, *val); - break; - - case HW_VAR_AMPDU_FACTOR: - rtl8723a_set_ampdu_factor(padapter, *val); - break; - - case HW_VAR_RXDMA_AGG_PG_TH: - rtl8723a_set_rxdma_agg_pg_th(padapter, *val); - break; - - case HW_VAR_H2C_FW_PWRMODE: - rtl8723a_set_FwPwrMode_cmd(padapter, *val); - break; - - case HW_VAR_H2C_FW_JOINBSSRPT: - rtl8723a_set_FwJoinBssReport_cmd(padapter, *val); - break; - -#ifdef CONFIG_8723AU_P2P - case HW_VAR_H2C_FW_P2P_PS_OFFLOAD: - rtl8723a_set_p2p_ps_offload_cmd(padapter, *val); - break; -#endif /* CONFIG_8723AU_P2P */ - - case HW_VAR_INITIAL_GAIN: - rtl8723a_set_initial_gain(padapter, *val32); - break; - case HW_VAR_EFUSE_BYTES: - pHalData->EfuseUsedBytes = *((u16 *) val); - break; - case HW_VAR_EFUSE_BT_BYTES: - pHalData->BTEfuseUsedBytes = *((u16 *) val); - break; - case HW_VAR_FIFO_CLEARN_UP: - rtl8723a_fifo_cleanup(padapter); - break; - case HW_VAR_CHECK_TXBUF: - break; - case HW_VAR_APFM_ON_MAC: - rtl8723a_set_apfm_on_mac(padapter, *val); - break; - - case HW_VAR_NAV_UPPER: - rtl8723a_set_nav_upper(padapter, *val32); - break; - case HW_VAR_BCN_VALID: - rtl8723a_bcn_valid(padapter); - break; - default: - break; - } - -} - -void GetHwReg8723A(struct rtw_adapter *padapter, u8 variable, u8 *val) -{ - struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); - - switch (variable) { - case HW_VAR_BASIC_RATE: - *((u16 *) val) = pHalData->BasicRateSet; - break; - - case HW_VAR_TXPAUSE: - *val = rtw_read8(padapter, REG_TXPAUSE); - break; - - case HW_VAR_BCN_VALID: - /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2 */ - val[0] = (BIT0 & rtw_read8(padapter, REG_TDECTRL + 2)) ? true : - false; - break; - - case HW_VAR_RF_TYPE: - *val = pHalData->rf_type; - break; - - case HW_VAR_DM_FLAG: - { - struct dm_odm_t *podmpriv = &pHalData->odmpriv; - *((u32 *) val) = podmpriv->SupportAbility; - } - break; - - case HW_VAR_FWLPS_RF_ON: - { - /* When we halt NIC, we should check if FW LPS is leave. */ - u32 valRCR; - - if ((padapter->bSurpriseRemoved == true) || - (padapter->pwrctrlpriv.rf_pwrstate == rf_off)) { - /* If it is in HW/SW Radio OFF or IPS state, we do - not check Fw LPS Leave, because Fw is unload. */ - *val = true; - } else { - valRCR = rtw_read32(padapter, REG_RCR); - valRCR &= 0x00070000; - if (valRCR) - *val = false; - else - *val = true; - } - } - break; - case HW_VAR_EFUSE_BYTES: - *((u16 *) val) = pHalData->EfuseUsedBytes; - break; - - case HW_VAR_EFUSE_BT_BYTES: - *((u16 *) val) = pHalData->BTEfuseUsedBytes; - break; - - case HW_VAR_APFM_ON_MAC: - *val = pHalData->bMacPwrCtrlOn; - break; - case HW_VAR_CHK_HI_QUEUE_EMPTY: - *val = - ((rtw_read32(padapter, REG_HGQ_INFORMATION) & 0x0000ff00) == - 0) ? true : false; - break; - } -} - #ifdef CONFIG_8723AU_BT_COEXIST void rtl8723a_SingleDualAntennaDetection(struct rtw_adapter *padapter) @@ -3442,11 +3182,3 @@ void rtl8723a_clone_haldata(struct rtw_adapter *dst_adapter, memcpy(dst_adapter->HalData, src_adapter->HalData, dst_adapter->hal_data_sz); } - -void rtl8723a_start_thread(struct rtw_adapter *padapter) -{ -} - -void rtl8723a_stop_thread(struct rtw_adapter *padapter) -{ -} diff --git a/drivers/staging/rtl8723au/hal/rtl8723au_recv.c b/drivers/staging/rtl8723au/hal/rtl8723au_recv.c index 213d1936109d01..1b5b83619c89ef 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723au_recv.c +++ b/drivers/staging/rtl8723au/hal/rtl8723au_recv.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -66,8 +65,8 @@ int rtl8723au_init_recv_priv(struct rtw_adapter *padapter) for (i = 0; i < NR_RECVBUFF; i++) { INIT_LIST_HEAD(&precvbuf->list); - res = rtw_os_recvbuf_resource_alloc23a(padapter, precvbuf); - if (res == _FAIL) + precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); + if (!precvbuf->purb) break; precvbuf->adapter = padapter; @@ -110,7 +109,11 @@ void rtl8723au_free_recv_priv(struct rtw_adapter *padapter) precvbuf = (struct recv_buf *)precvpriv->precv_buf; for (i = 0; i < NR_RECVBUFF; i++) { - rtw_os_recvbuf_resource_free23a(padapter, precvbuf); + usb_free_urb(precvbuf->purb); + + if (precvbuf->pskb) + dev_kfree_skb_any(precvbuf->pskb); + precvbuf++; } @@ -132,11 +135,20 @@ void rtl8723au_free_recv_priv(struct rtw_adapter *padapter) skb_queue_purge(&precvpriv->free_recv_skb_queue); } +struct recv_stat_cpu { + u32 rxdw0; + u32 rxdw1; + u32 rxdw2; + u32 rxdw3; + u32 rxdw4; + u32 rxdw5; +}; + void update_recvframe_attrib(struct recv_frame *precvframe, struct recv_stat *prxstat) { struct rx_pkt_attrib *pattrib; - struct recv_stat report; + struct recv_stat_cpu report; struct rxreport_8723a *prxreport; report.rxdw0 = le32_to_cpu(prxstat->rxdw0); diff --git a/drivers/staging/rtl8723au/hal/usb_halinit.c b/drivers/staging/rtl8723au/hal/usb_halinit.c index e206829d50fa37..20c11353a6106b 100644 --- a/drivers/staging/rtl8723au/hal/usb_halinit.c +++ b/drivers/staging/rtl8723au/hal/usb_halinit.c @@ -621,7 +621,6 @@ static u32 rtl8723au_hal_init(struct rtw_adapter *Adapter) struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv; struct registry_priv *pregistrypriv = &Adapter->registrypriv; - u32 NavUpper = WiFiNavUpperUs; unsigned long init_start_time = jiffies; @@ -779,7 +778,7 @@ static u32 rtl8723au_hal_init(struct rtw_adapter *Adapter) _InitDriverInfoSize(Adapter, DRVINFO_SZ); _InitInterrupt(Adapter); - hal_init_macaddr23a(Adapter);/* set mac_address */ + hw_var_set_macaddr(Adapter, Adapter->eeprompriv.mac_addr); _InitNetworkType(Adapter);/* set msr */ _InitWMACSetting(Adapter); _InitAdaptiveCtrl(Adapter); @@ -888,7 +887,7 @@ static u32 rtl8723au_hal_init(struct rtw_adapter *Adapter) rtl8723a_InitHalDm(Adapter); HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC31); - rtw_hal_set_hwreg23a(Adapter, HW_VAR_NAV_UPPER, (u8 *)&NavUpper); + rtl8723a_set_nav_upper(Adapter, WiFiNavUpperUs); /* 2011/03/09 MH debug only, UMC-B cut pass 2500 S5 test, but we need to fin root cause. */ if (((rtw_read32(Adapter, rFPGA0_RFMOD) & 0xFF000000) != 0x83000000)) { @@ -1228,14 +1227,14 @@ static unsigned int rtl8723au_inirp_init(struct rtw_adapter *Adapter) u8 i; struct recv_buf *precvbuf; uint status; - struct intf_hdl *pintfhdl = &Adapter->iopriv.intf; + struct _io_ops *io_ops = &Adapter->io_ops; struct recv_priv *precvpriv = &Adapter->recvpriv; - u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + u32 (*_read_port)(struct rtw_adapter *padapter, u32 addr, u32 cnt, struct recv_buf *rbuf); - u32 (*_read_interrupt)(struct intf_hdl *pintfhdl, u32 addr); + u32 (*_read_interrupt)(struct rtw_adapter *padapter, u32 addr); struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); - _read_port = pintfhdl->io_ops._read_port; + _read_port = io_ops->_read_port; status = _SUCCESS; @@ -1246,7 +1245,7 @@ static unsigned int rtl8723au_inirp_init(struct rtw_adapter *Adapter) /* issue Rx irp to receive data */ precvbuf = (struct recv_buf *)precvpriv->precv_buf; for (i = 0; i < NR_RECVBUFF; i++) { - if (_read_port(pintfhdl, precvpriv->ff_hwaddr, 0, precvbuf) == + if (_read_port(Adapter, precvpriv->ff_hwaddr, 0, precvbuf) == false) { RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("usb_rx_init: usb_read_port error\n")); @@ -1256,8 +1255,8 @@ static unsigned int rtl8723au_inirp_init(struct rtw_adapter *Adapter) precvbuf++; precvpriv->free_recv_buf_queue_cnt--; } - _read_interrupt = pintfhdl->io_ops._read_interrupt; - if (_read_interrupt(pintfhdl, RECV_INT_IN_ADDR) == false) { + _read_interrupt = io_ops->_read_interrupt; + if (_read_interrupt(Adapter, RECV_INT_IN_ADDR) == false) { RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("usb_rx_init: usb_read_interrupt error\n")); status = _FAIL; @@ -1497,52 +1496,6 @@ static void ReadAdapterInfo8723AU(struct rtw_adapter *Adapter) _ReadAdapterInfo8723AU(Adapter); } -#define GPIO_DEBUG_PORT_NUM 0 -static void rtl8723au_trigger_gpio_0(struct rtw_adapter *padapter) -{ - u32 gpioctrl; - DBG_8723A("==> trigger_gpio_0...\n"); - rtw_write16_async(padapter, REG_GPIO_PIN_CTRL, 0); - rtw_write8_async(padapter, REG_GPIO_PIN_CTRL+2, 0xFF); - gpioctrl = (BIT(GPIO_DEBUG_PORT_NUM) << 24)| - (BIT(GPIO_DEBUG_PORT_NUM) << 16); - rtw_write32_async(padapter, REG_GPIO_PIN_CTRL, gpioctrl); - gpioctrl |= (BIT(GPIO_DEBUG_PORT_NUM)<<8); - rtw_write32_async(padapter, REG_GPIO_PIN_CTRL, gpioctrl); - DBG_8723A("<=== trigger_gpio_0...\n"); -} - -/* - * If variable not handled here, - * some variables will be processed in SetHwReg8723A() - */ -static void SetHwReg8723AU(struct rtw_adapter *Adapter, u8 variable, u8 *val) -{ - switch (variable) { - case HW_VAR_RXDMA_AGG_PG_TH: - break; - case HW_VAR_SET_RPWM: - rtl8723a_set_rpwm(Adapter, *val); - break; - case HW_VAR_TRIGGER_GPIO_0: - rtl8723au_trigger_gpio_0(Adapter); - break; - default: - SetHwReg8723A(Adapter, variable, val); - break; - } - -} - -/* - * If variable not handled here, - * some variables will be processed in GetHwReg8723A() - */ -static void GetHwReg8723AU(struct rtw_adapter *Adapter, u8 variable, u8 *val) -{ - GetHwReg8723A(Adapter, variable, val); -} - /* */ /* Description: */ /* Query setting of specified variable. */ @@ -1786,12 +1739,6 @@ static void rtl8723au_init_default_value(struct rtw_adapter *padapter) rtl8723a_init_default_value(padapter); } -static u8 rtl8192cu_ps_func(struct rtw_adapter *Adapter, - enum hal_intf_ps_func efunc_id, u8 *val) -{ - return true; -} - int rtl8723au_set_hal_ops(struct rtw_adapter *padapter) { struct hal_ops *pHalFunc = &padapter->HalFunc; @@ -1820,15 +1767,12 @@ int rtl8723au_set_hal_ops(struct rtw_adapter *padapter) pHalFunc->init_default_value = &rtl8723au_init_default_value; pHalFunc->intf_chip_configure = &rtl8723au_interface_configure; pHalFunc->read_adapter_info = &ReadAdapterInfo8723AU; - pHalFunc->SetHwRegHandler = &SetHwReg8723AU; - pHalFunc->GetHwRegHandler = &GetHwReg8723AU; pHalFunc->GetHalDefVarHandler = &GetHalDefVar8192CUsb; pHalFunc->SetHalDefVarHandler = &SetHalDefVar8192CUsb; pHalFunc->UpdateRAMaskHandler = &UpdateHalRAMask8192CUsb; pHalFunc->hal_xmit = &rtl8723au_hal_xmit; pHalFunc->mgnt_xmit = &rtl8723au_mgnt_xmit; pHalFunc->hal_xmitframe_enqueue = &rtl8723au_hal_xmitframe_enqueue; - pHalFunc->interface_ps_func = &rtl8192cu_ps_func; rtl8723a_set_hal_ops(pHalFunc); return 0; } diff --git a/drivers/staging/rtl8723au/hal/usb_ops_linux.c b/drivers/staging/rtl8723au/hal/usb_ops_linux.c index 0311cdf77ff1b8..12997a5cd7a8e6 100644 --- a/drivers/staging/rtl8723au/hal/usb_ops_linux.c +++ b/drivers/staging/rtl8723au/hal/usb_ops_linux.c @@ -22,9 +22,10 @@ #include #include -static int usbctrl_vendorreq(struct intf_hdl *pintfhdl, u8 request, u16 value, u16 index, void *pdata, u16 len, u8 requesttype) +static int usbctrl_vendorreq(struct rtw_adapter *padapter, u8 request, + u16 value, u16 index, void *pdata, u16 len, + u8 requesttype) { - struct rtw_adapter *padapter = pintfhdl->padapter ; struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); struct usb_device *udev = pdvobjpriv->pusbdev; @@ -124,7 +125,7 @@ static int usbctrl_vendorreq(struct intf_hdl *pintfhdl, u8 request, u16 value, u return status; } -static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr) +static u8 usb_read8(struct rtw_adapter *padapter, u32 addr) { u8 request; u8 requesttype; @@ -140,12 +141,13 @@ static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr) wvalue = (u16)(addr&0x0000ffff); len = 1; - usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); + usbctrl_vendorreq(padapter, request, wvalue, index, &data, + len, requesttype); return data; } -static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr) +static u16 usb_read16(struct rtw_adapter *padapter, u32 addr) { u8 request; u8 requesttype; @@ -161,12 +163,13 @@ static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr) wvalue = (u16)(addr&0x0000ffff); len = 2; - usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); + usbctrl_vendorreq(padapter, request, wvalue, index, &data, + len, requesttype); return data; } -static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr) +static u32 usb_read32(struct rtw_adapter *padapter, u32 addr) { u8 request; u8 requesttype; @@ -182,12 +185,13 @@ static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr) wvalue = (u16)(addr&0x0000ffff); len = 4; - usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); + usbctrl_vendorreq(padapter, request, wvalue, index, &data, + len, requesttype); return data; } -static int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) +static int usb_write8(struct rtw_adapter *padapter, u32 addr, u8 val) { u8 request; u8 requesttype; @@ -206,12 +210,13 @@ static int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) data = val; - ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); + ret = usbctrl_vendorreq(padapter, request, wvalue, index, &data, + len, requesttype); return ret; } -static int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) +static int usb_write16(struct rtw_adapter *padapter, u32 addr, u16 val) { u8 request; u8 requesttype; @@ -230,11 +235,12 @@ static int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) data = val; - ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); + ret = usbctrl_vendorreq(padapter, request, wvalue, index, &data, + len, requesttype); return ret; } -static int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) +static int usb_write32(struct rtw_adapter *padapter, u32 addr, u32 val) { u8 request; u8 requesttype; @@ -252,12 +258,14 @@ static int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) len = 4; data = val; - ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); + ret = usbctrl_vendorreq(padapter, request, wvalue, index, &data, + len, requesttype); return ret; } -static int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata) +static int usb_writeN(struct rtw_adapter *padapter, + u32 addr, u32 length, u8 *pdata) { u8 request; u8 requesttype; @@ -273,9 +281,10 @@ static int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata wvalue = (u16)(addr&0x0000ffff); len = length; - memcpy(buf, pdata, len); + memcpy(buf, pdata, len); - ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, buf, len, requesttype); + ret = usbctrl_vendorreq(padapter, request, wvalue, index, buf, + len, requesttype); return ret; } @@ -423,12 +432,11 @@ static void usb_read_interrupt_complete(struct urb *purb, struct pt_regs *regs) } } -static u32 usb_read_interrupt(struct intf_hdl *pintfhdl, u32 addr) +static u32 usb_read_interrupt(struct rtw_adapter *adapter, u32 addr) { int err; unsigned int pipe; u32 ret = _SUCCESS; - struct rtw_adapter *adapter = pintfhdl->padapter; struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter); struct recv_priv *precvpriv = &adapter->recvpriv; struct usb_device *pusbd = pdvobj->pusbdev; @@ -720,7 +728,7 @@ static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs) } } -static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, +static u32 usb_read_port(struct rtw_adapter *adapter, u32 addr, u32 cnt, struct recv_buf *precvbuf) { int err; @@ -729,7 +737,6 @@ static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, unsigned long alignment = 0; u32 ret = _SUCCESS; struct urb *purb = NULL; - struct rtw_adapter *adapter = pintfhdl->padapter; struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter); struct recv_priv *precvpriv = &adapter->recvpriv; struct usb_device *pusbd = pdvobj->pusbdev; @@ -815,8 +822,9 @@ void rtl8723au_xmit_tasklet(void *priv) } } -void rtl8723au_set_intf_ops(struct _io_ops *pops) +void rtl8723au_set_intf_ops(struct rtw_adapter *padapter) { + struct _io_ops *pops = &padapter->io_ops; memset((u8 *)pops, 0, sizeof(struct _io_ops)); diff --git a/drivers/staging/rtl8723au/include/cmd_osdep.h b/drivers/staging/rtl8723au/include/cmd_osdep.h deleted file mode 100644 index 4866bee0405441..00000000000000 --- a/drivers/staging/rtl8723au/include/cmd_osdep.h +++ /dev/null @@ -1,26 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. - * - * 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, 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. - * - ******************************************************************************/ -#ifndef __CMD_OSDEP_H_ -#define __CMD_OSDEP_H_ - -#include -#include - -int _rtw_init_evt_priv23a(struct evt_priv *pevtpriv); -void _rtw_free_evt_priv23a(struct evt_priv *pevtpriv); -void _rtw_free_cmd_priv23a(struct cmd_priv *pcmdpriv); -int _rtw_enqueue_cmd23a(struct rtw_queue *queue, struct cmd_obj *obj); - -#endif diff --git a/drivers/staging/rtl8723au/include/drv_types.h b/drivers/staging/rtl8723au/include/drv_types.h index 53eecea48ceca3..bec8fd7126d1bf 100644 --- a/drivers/staging/rtl8723au/include/drv_types.h +++ b/drivers/staging/rtl8723au/include/drv_types.h @@ -55,26 +55,10 @@ enum _NIC_VERSION { #include #include #include -#include #include #include "ioctl_cfg80211.h" -#define SPEC_DEV_ID_NONE BIT(0) -#define SPEC_DEV_ID_DISABLE_HT BIT(1) -#define SPEC_DEV_ID_ENABLE_PS BIT(2) -#define SPEC_DEV_ID_RF_CONFIG_1T1R BIT(3) -#define SPEC_DEV_ID_RF_CONFIG_2T2R BIT(4) -#define SPEC_DEV_ID_ASSIGN_IFNAME BIT(5) - -struct specific_device_id { - u32 flags; - - u16 idVendor; - u16 idProduct; - -}; - struct registry_priv { u8 chip_version; u8 rfintfs; @@ -187,8 +171,6 @@ struct dvobj_priv { int RtOutPipe[3]; u8 Queue2Pipe[HW_QUEUE_ENTRY];/* for out pipe mapping */ - u8 irq_alloc; - /*-------- below is for USB INTERFACE --------*/ u8 nr_endpoint; @@ -197,8 +179,6 @@ struct dvobj_priv { u8 RtNumOutPipes; int ep_num[5]; /* endpoint number */ - int RegUsbSS; - struct semaphore usb_suspend_sema; struct mutex usb_vendor_req_mutex; @@ -243,8 +223,7 @@ struct rtw_adapter { struct mlme_ext_priv mlmeextpriv; struct cmd_priv cmdpriv; struct evt_priv evtpriv; - /* struct io_queue *pio_queue; */ - struct io_priv iopriv; + struct _io_ops io_ops; struct xmit_priv xmitpriv; struct recv_priv recvpriv; struct sta_priv stapriv; @@ -258,13 +237,7 @@ struct rtw_adapter { struct hostapd_priv *phostapdpriv; #endif - struct cfg80211_wifidirect_info cfg80211_wdinfo; u32 setband; - struct wifidirect_info wdinfo; - -#ifdef CONFIG_8723AU_P2P - struct wifi_display_info wfd_info; -#endif /* CONFIG_8723AU_P2P */ void *HalData; u32 hal_data_sz; @@ -283,28 +256,14 @@ struct rtw_adapter { u8 init_adpt_in_progress; u8 bHaltInProgress; - void *cmdThread; - void *evtThread; - void *xmitThread; - void *recvThread; - void (*intf_start)(struct rtw_adapter *adapter); void (*intf_stop)(struct rtw_adapter *adapter); struct net_device *pnetdev; /* used by rtw_rereg_nd_name related function */ - struct rereg_nd_name_data { - struct net_device *old_pnetdev; - char old_ifname[IFNAMSIZ]; - u8 old_ips_mode; - u8 old_bRegUseLed; - } rereg_nd_name_priv; - int bup; struct net_device_stats stats; - struct iw_statistics iwstats; - struct proc_dir_entry *dir_dev;/* for proc directory */ struct wireless_dev *rtw_wdev; int net_closed; @@ -313,39 +272,14 @@ struct rtw_adapter { u8 bBTFWReady; u8 bReadPortCancel; u8 bWritePortCancel; - u8 bRxRSSIDisplay; /* The driver will show the desired chan nor when this flag is 1. */ u8 bNotifyChannelChange; -#ifdef CONFIG_8723AU_P2P - /* driver will show current P2P status when the application reads it*/ - u8 bShowGetP2PState; -#endif struct rtw_adapter *pbuddy_adapter; /* extend to support multi interface */ /* IFACE_ID0 is equals to PRIMARY_ADAPTER */ /* IFACE_ID1 is equals to SECONDARY_ADAPTER */ u8 iface_id; - -#ifdef CONFIG_BR_EXT - _lock br_ext_lock; - /* unsigned int macclone_completed; */ - struct nat25_network_db_entry *nethash[NAT25_HASH_SIZE]; - int pppoe_connection_in_progress; - unsigned char pppoe_addr[MACADDRLEN]; - unsigned char scdb_mac[MACADDRLEN]; - unsigned char scdb_ip[4]; - struct nat25_network_db_entry *scdb_entry; - unsigned char br_mac[MACADDRLEN]; - unsigned char br_ip[4]; - - struct br_ext_info ethBrExtInfo; -#endif /* CONFIG_BR_EXT */ - - u8 fix_rate; - - unsigned char in_cta_test; - }; #define adapter_to_dvobj(adapter) (adapter->dvobj) diff --git a/drivers/staging/rtl8723au/include/ethernet.h b/drivers/staging/rtl8723au/include/ethernet.h deleted file mode 100644 index 39fc6df8818849..00000000000000 --- a/drivers/staging/rtl8723au/include/ethernet.h +++ /dev/null @@ -1,22 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. - * - * 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, 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. - * - * - ******************************************************************************/ -/*! \file */ -#ifndef __INC_ETHERNET_H -#define __INC_ETHERNET_H - -#define LLC_HEADER_SIZE 6 /* LLC Header Length */ - -#endif /* #ifndef __INC_ETHERNET_H */ diff --git a/drivers/staging/rtl8723au/include/hal_com.h b/drivers/staging/rtl8723au/include/hal_com.h index 20f983cfc2b7a7..4a161e26c8dc5c 100644 --- a/drivers/staging/rtl8723au/include/hal_com.h +++ b/drivers/staging/rtl8723au/include/hal_com.h @@ -165,8 +165,6 @@ void HalSetBrateCfg23a(struct rtw_adapter *padapter, u8 *mBratesOS); bool Hal_MappingOutPipe23a(struct rtw_adapter *pAdapter, u8 NumOutPipe); -void hal_init_macaddr23a(struct rtw_adapter *adapter); - void c2h_evt_clear23a(struct rtw_adapter *adapter); s32 c2h_evt_read23a(struct rtw_adapter *adapter, u8 *buf); @@ -185,11 +183,12 @@ void rtl8723a_ack_preamble(struct rtw_adapter *padapter, u8 bShortPreamble); void rtl8723a_set_sec_cfg(struct rtw_adapter *padapter, u8 sec); void rtl8723a_cam_empty_entry(struct rtw_adapter *padapter, u8 ucIndex); void rtl8723a_cam_invalid_all(struct rtw_adapter *padapter); -void rtl8723a_cam_write(struct rtw_adapter *padapter, u32 val1, u32 val2); +void rtl8723a_cam_write(struct rtw_adapter *padapter, + u8 entry, u16 ctrl, const u8 *mac, const u8 *key); void rtl8723a_fifo_cleanup(struct rtw_adapter *padapter); void rtl8723a_set_apfm_on_mac(struct rtw_adapter *padapter, u8 val); void rtl8723a_bcn_valid(struct rtw_adapter *padapter); -void rtl8723a_set_tx_pause(struct rtw_adapter *padapter, u8 pause); +bool rtl8723a_get_bcn_valid(struct rtw_adapter *padapter); void rtl8723a_set_beacon_interval(struct rtw_adapter *padapter, u16 interval); void rtl8723a_set_resp_sifs(struct rtw_adapter *padapter, u8 r2t1, u8 r2t2, u8 t2t1, u8 t2t2); @@ -202,10 +201,14 @@ void rtl8723a_set_nav_upper(struct rtw_adapter *padapter, u32 usNavUpper); void rtl8723a_set_initial_gain(struct rtw_adapter *padapter, u32 rx_gain); void rtl8723a_odm_support_ability_write(struct rtw_adapter *padapter, u32 val); -void rtl8723a_odm_support_ability_backup(struct rtw_adapter *padapter, u8 val); +void rtl8723a_odm_support_ability_backup(struct rtw_adapter *padapter); +void rtl8723a_odm_support_ability_restore(struct rtw_adapter *padapter); void rtl8723a_odm_support_ability_set(struct rtw_adapter *padapter, u32 val); void rtl8723a_odm_support_ability_clr(struct rtw_adapter *padapter, u32 val); void rtl8723a_set_rpwm(struct rtw_adapter *padapter, u8 val); +u8 rtl8723a_get_rf_type(struct rtw_adapter *padapter); +bool rtl8723a_get_fwlps_rf_on(struct rtw_adapter *padapter); +bool rtl8723a_chk_hi_queue_empty(struct rtw_adapter *padapter); #endif /* __HAL_COMMON_H__ */ diff --git a/drivers/staging/rtl8723au/include/hal_intf.h b/drivers/staging/rtl8723au/include/hal_intf.h index d183f4ba1ecb29..52b33fe61b3fef 100644 --- a/drivers/staging/rtl8723au/include/hal_intf.h +++ b/drivers/staging/rtl8723au/include/hal_intf.h @@ -35,78 +35,6 @@ enum _CHIP_TYPE { MAX_CHIP_TYPE }; -enum HW_VARIABLES { - HW_VAR_MEDIA_STATUS, - HW_VAR_MEDIA_STATUS1, - HW_VAR_SET_OPMODE, - HW_VAR_MAC_ADDR, - HW_VAR_BSSID, - HW_VAR_INIT_RTS_RATE, - HW_VAR_BASIC_RATE, - HW_VAR_TXPAUSE, - HW_VAR_BCN_FUNC, - HW_VAR_CORRECT_TSF, - HW_VAR_CHECK_BSSID, - HW_VAR_MLME_DISCONNECT, - HW_VAR_MLME_SITESURVEY, - HW_VAR_MLME_JOIN, - HW_VAR_ON_RCR_AM, - HW_VAR_OFF_RCR_AM, - HW_VAR_BEACON_INTERVAL, - HW_VAR_SLOT_TIME, - HW_VAR_RESP_SIFS, - HW_VAR_ACK_PREAMBLE, - HW_VAR_SEC_CFG, - HW_VAR_BCN_VALID, - HW_VAR_RF_TYPE, - HW_VAR_DM_FLAG, - HW_VAR_DM_FUNC_OP, - HW_VAR_DM_FUNC_SET, - HW_VAR_DM_FUNC_CLR, - HW_VAR_CAM_EMPTY_ENTRY, - HW_VAR_CAM_INVALID_ALL, - HW_VAR_CAM_WRITE, - HW_VAR_CAM_READ, - HW_VAR_AC_PARAM_VO, - HW_VAR_AC_PARAM_VI, - HW_VAR_AC_PARAM_BE, - HW_VAR_AC_PARAM_BK, - HW_VAR_ACM_CTRL, - HW_VAR_AMPDU_MIN_SPACE, - HW_VAR_AMPDU_FACTOR, - HW_VAR_RXDMA_AGG_PG_TH, - HW_VAR_SET_RPWM, - HW_VAR_H2C_FW_PWRMODE, - HW_VAR_H2C_FW_JOINBSSRPT, - HW_VAR_FWLPS_RF_ON, - HW_VAR_H2C_FW_P2P_PS_OFFLOAD, - HW_VAR_TDLS_WRCR, - HW_VAR_TDLS_INIT_CH_SEN, - HW_VAR_TDLS_RS_RCR, - HW_VAR_TDLS_DONE_CH_SEN, - HW_VAR_INITIAL_GAIN, - HW_VAR_TRIGGER_GPIO_0, - HW_VAR_BT_SET_COEXIST, - HW_VAR_BT_ISSUE_DELBA, - HW_VAR_CURRENT_ANTENNA, - HW_VAR_ANTENNA_DIVERSITY_LINK, - HW_VAR_ANTENNA_DIVERSITY_SELECT, - HW_VAR_SWITCH_EPHY_WoWLAN, - HW_VAR_EFUSE_BYTES, - HW_VAR_EFUSE_BT_BYTES, - HW_VAR_FIFO_CLEARN_UP, - HW_VAR_CHECK_TXBUF, - HW_VAR_APFM_ON_MAC, /* Auto FSM to Turn On, include clock, isolation, power control for MAC only */ - /* The valid upper nav range for the HW updating, if the true value is larger than the upper range, the HW won't update it. */ - /* Unit in microsecond. 0 means disable this function. */ - HW_VAR_NAV_UPPER, - HW_VAR_RPT_TIMER_SETTING, - HW_VAR_TX_RPT_MAX_MACID, - HW_VAR_H2C_MEDIA_STATUS_RPT, - HW_VAR_CHK_HI_QUEUE_EMPTY, - HW_VAR_READ_LLT_TAB, -}; - enum hal_def_variable { HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, HAL_DEF_IS_SUPPORT_ANT_DIV, @@ -132,11 +60,6 @@ enum hal_odm_variable { HAL_ODM_WIFI_DISPLAY_STATE, }; -enum hal_intf_ps_func { - HAL_USB_SELECT_SUSPEND, - HAL_MAX_ID, -}; - struct hal_ops { u32 (*hal_power_on)(struct rtw_adapter *padapter); u32 (*hal_init)(struct rtw_adapter *padapter); @@ -175,11 +98,6 @@ struct hal_ops { void (*hal_dm_watchdog)(struct rtw_adapter *padapter); - void (*SetHwRegHandler)(struct rtw_adapter *padapter, - u8 variable, u8 *val); - void (*GetHwRegHandler)(struct rtw_adapter *padapter, - u8 variable, u8 *val); - u8 (*GetHalDefVarHandler)(struct rtw_adapter *padapter, enum hal_def_variable eVariable, void *pValue); @@ -200,11 +118,6 @@ struct hal_ops { void (*Add_RateATid)(struct rtw_adapter *padapter, u32 bitmap, u8 arg, u8 rssi_level); - void (*run_thread)(struct rtw_adapter *padapter); - void (*cancel_thread)(struct rtw_adapter *padapter); - - u8 (*interface_ps_func)(struct rtw_adapter *padapter, - enum hal_intf_ps_func efunc_id, u8 *val); s32 (*hal_xmit)(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe); @@ -213,10 +126,6 @@ struct hal_ops { s32 (*hal_xmitframe_enqueue)(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe); - u32 (*read_bbreg)(struct rtw_adapter *padapter, u32 RegAddr, - u32 BitMask); - void (*write_bbreg)(struct rtw_adapter *padapter, u32 RegAddr, - u32 BitMask, u32 Data); u32 (*read_rfreg)(struct rtw_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask); void (*write_rfreg)(struct rtw_adapter *padapter, u32 eRFPath, @@ -291,11 +200,6 @@ enum hardware_type { }; #define GET_EEPROM_EFUSE_PRIV(adapter) (&adapter->eeprompriv) -#define is_boot_from_eeprom(adapter) (adapter->eeprompriv.EepromOrEfuse) - -extern int rtw_ht_enable23A; -extern int rtw_cbw40_enable23A; -extern int rtw_ampdu_enable23A;/* for enable tx_ampdu */ void rtw_hal_def_value_init23a(struct rtw_adapter *padapter); int pm_netdev_open23a(struct net_device *pnetdev, u8 bnormal); @@ -312,8 +216,6 @@ u32 rtw_hal_power_on23a(struct rtw_adapter *padapter); uint rtw_hal_init23a(struct rtw_adapter *padapter); uint rtw_hal_deinit23a(struct rtw_adapter *padapter); void rtw_hal_stop(struct rtw_adapter *padapter); -void rtw_hal_set_hwreg23a(struct rtw_adapter *padapter, u8 variable, u8 *val); -void rtw23a_hal_get_hwreg(struct rtw_adapter *padapter, u8 variable, u8 *val); void rtw_hal_chip_configure23a(struct rtw_adapter *padapter); void rtw_hal_read_chip_info23a(struct rtw_adapter *padapter); @@ -339,9 +241,6 @@ void rtw_hal_disable_interrupt23a(struct rtw_adapter *padapter); u32 rtw_hal_inirp_init23a(struct rtw_adapter *padapter); u32 rtw_hal_inirp_deinit23a(struct rtw_adapter *padapter); -u8 rtw_hal_intf_ps_func23a(struct rtw_adapter *padapter, - enum hal_intf_ps_func efunc_id, u8 *val); - s32 rtw_hal_xmit23aframe_enqueue(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe); s32 rtw_hal_xmit23a(struct rtw_adapter *padapter, @@ -358,13 +257,9 @@ void rtw_hal_free_recv_priv23a(struct rtw_adapter *padapter); void rtw_hal_update_ra_mask23a(struct sta_info *psta, u8 rssi_level); void rtw_hal_add_ra_tid23a(struct rtw_adapter *padapter, u32 bitmap, u8 arg, u8 rssi_level); void rtw_hal_clone_data(struct rtw_adapter *dst_padapter, struct rtw_adapter *src_padapter); -void rtw_hal_start_thread23a(struct rtw_adapter *padapter); -void rtw_hal_stop_thread23a(struct rtw_adapter *padapter); void rtw_hal_bcn_related_reg_setting23a(struct rtw_adapter *padapter); -u32 rtw_hal_read_bbreg23a(struct rtw_adapter *padapter, u32 RegAddr, u32 BitMask); -void rtw_hal_write_bbreg23a(struct rtw_adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data); u32 rtw_hal_read_rfreg23a(struct rtw_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask); void rtw_hal_write_rfreg23a(struct rtw_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data); @@ -388,5 +283,11 @@ void rtw_hal_reset_security_engine23a(struct rtw_adapter *adapter); s32 rtw_hal_c2h_handler23a(struct rtw_adapter *adapter, struct c2h_evt_hdr *c2h_evt); c2h_id_filter rtw_hal_c2h_id_filter_ccx23a(struct rtw_adapter *adapter); +void hw_var_set_correct_tsf(struct rtw_adapter *padapter); +void hw_var_set_mlme_disconnect(struct rtw_adapter *padapter); +void hw_var_set_opmode(struct rtw_adapter *padapter, u8 mode); +void hw_var_set_macaddr(struct rtw_adapter *padapter, u8 *val); +void hw_var_set_bssid(struct rtw_adapter *padapter, u8 *val); +void hw_var_set_mlme_join(struct rtw_adapter *padapter, u8 type); #endif /* __HAL_INTF_H__ */ diff --git a/drivers/staging/rtl8723au/include/ieee80211.h b/drivers/staging/rtl8723au/include/ieee80211.h index 28e4ab239fb963..76875f651d8226 100644 --- a/drivers/staging/rtl8723au/include/ieee80211.h +++ b/drivers/staging/rtl8723au/include/ieee80211.h @@ -298,53 +298,6 @@ struct ieee80211_snap_hdr { #define WEP_KEY_LEN 13 - -/* - - 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 - -*/ - -struct ieee80211_header_data { - u16 frame_ctl; - u16 duration_id; - u8 addr1[6]; - u8 addr2[6]; - u8 addr3[6]; - u16 seq_ctrl; -}; - -struct ieee80211_info_element_hdr { - u8 id; - u8 len; -} __attribute__ ((packed)); - -struct ieee80211_info_element { - u8 id; - u8 len; - u8 data[0]; -} __attribute__ ((packed)); - - -struct ieee80211_txb { - u8 nr_frags; - u8 encrypted; - u16 reserved; - u16 frag_size; - u16 payload_size; - struct sk_buff *fragments[0]; -}; - - /* 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 @@ -382,9 +335,6 @@ struct ieee80211_txb { #define IEEE_G (1<<2) #define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) -/* Baron move to ieee80211.c */ -int ieee80211_is_empty_essid23a(const char *essid, int essid_len); - enum _PUBLIC_ACTION{ ACT_PUBLIC_BSSCOEXIST = 0, /* 20/40 BSS Coexistence */ ACT_PUBLIC_DSE_ENABLE = 1, @@ -457,68 +407,8 @@ struct rtw_ieee80211_channel { /*, (channel)->orig_mag*/ \ /*, (channel)->orig_mpwr*/ \ -/* Parsed Information Elements */ -struct rtw_ieee802_11_elems { - u8 *ssid; - u8 ssid_len; - u8 *supp_rates; - u8 supp_rates_len; - u8 *fh_params; - u8 fh_params_len; - u8 *ds_params; - u8 ds_params_len; - u8 *cf_params; - u8 cf_params_len; - u8 *tim; - u8 tim_len; - u8 *ibss_params; - u8 ibss_params_len; - u8 *challenge; - u8 challenge_len; - u8 *erp_info; - u8 erp_info_len; - u8 *ext_supp_rates; - u8 ext_supp_rates_len; - u8 *wpa_ie; - u8 wpa_ie_len; - u8 *rsn_ie; - u8 rsn_ie_len; - u8 *wme; - u8 wme_len; - u8 *wme_tspec; - u8 wme_tspec_len; - u8 *wps_ie; - u8 wps_ie_len; - u8 *power_cap; - u8 power_cap_len; - u8 *supp_channels; - u8 supp_channels_len; - u8 *mdie; - u8 mdie_len; - u8 *ftie; - u8 ftie_len; - u8 *timeout_int; - u8 timeout_int_len; - u8 *ht_capabilities; - u8 ht_capabilities_len; - u8 *ht_operation; - u8 ht_operation_len; - u8 *vendor_ht_cap; - u8 vendor_ht_cap_len; -}; - -enum parse_res { - ParseOK = 0, - ParseUnknown = 1, - ParseFailed = -1 -}; - -enum parse_res rtw_ieee802_11_parse_elems23a(u8 *start, uint len, - struct rtw_ieee802_11_elems *elems, - int show_errors); - u8 *rtw_set_fixed_ie23a(unsigned char *pbuf, unsigned int len, unsigned char *source, unsigned int *frlen); -u8 *rtw_set_ie23a(u8 *pbuf, int index, uint len, u8 *source, uint *frlen); +u8 *rtw_set_ie23a(u8 *pbuf, int index, uint len, const u8 *source, uint *frlen); enum secondary_ch_offset { SCN = 0, /* no secondary channel */ @@ -537,12 +427,10 @@ int rtw_ies_remove_ie23a(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u void rtw_set_supported_rate23a(u8* SupportedRates, uint mode) ; -unsigned char *rtw_get_wpa_ie23a(unsigned char *pie, int *wpa_ie_len, int limit); -unsigned char *rtw_get_wpa2_ie23a(unsigned char *pie, int *rsn_ie_len, int limit); -int rtw_get_wpa_cipher_suite23a(u8 *s); -int rtw_get_wpa2_cipher_suite23a(u8 *s); -int rtw_parse_wpa_ie23a(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x); -int rtw_parse_wpa2_ie23a(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x); +int rtw_get_wpa_cipher_suite23a(const u8 *s); +int rtw_get_wpa2_cipher_suite23a(const u8 *s); +int rtw_parse_wpa_ie23a(const u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x); +int rtw_parse_wpa2_ie23a(const u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x); int rtw_get_sec_ie23a(u8 *in_ie,uint in_len,u8 *rsn_ie,u16 *rsn_len,u8 *wpa_ie,u16 *wpa_len); @@ -551,32 +439,6 @@ u8 *rtw_get_wps_ie23a(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen); u8 *rtw_get_wps_attr23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id ,u8 *buf_attr, u32 *len_attr); u8 *rtw_get_wps_attr_content23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id ,u8 *buf_content, uint *len_content); -/** - * for_each_ie - iterate over continuous IEs - * @ie: - * @buf: - * @buf_len: - */ -#define for_each_ie(ie, buf, buf_len) \ - for (ie = (void*)buf; (((u8*)ie) - ((u8*)buf) + 1) < buf_len; ie = (void*)(((u8*)ie) + *(((u8*)ie)+1) + 2)) - -void dump_ies23a(u8 *buf, u32 buf_len); -void dump_wps_ie23a(u8 *ie, u32 ie_len); - -#ifdef CONFIG_8723AU_P2P -void dump_p2p_ie23a(u8 *ie, u32 ie_len); -u8 *rtw_get_p2p_ie23a(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen); -u8 *rtw_get_p2p_attr23a(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id ,u8 *buf_attr, u32 *len_attr); -u8 *rtw_get_p2p_attr23a_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id ,u8 *buf_content, uint *len_content); -u32 rtw_set_p2p_attr_content23a(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr); -void rtw_wlan_bssid_ex_remove_p2p_attr23a(struct wlan_bssid_ex *bss_ex, u8 attr_id); -#endif - -#ifdef CONFIG_8723AU_P2P -int rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen); -int rtw_get_wfd_attr_content(u8 *wfd_ie, uint wfd_ielen, u8 target_attr_id ,u8 *attr_content, uint *attr_contentlen); -#endif /* CONFIG_8723AU_P2P */ - uint rtw_get_rateset_len23a(u8 *rateset); struct registry_priv; diff --git a/drivers/staging/rtl8723au/include/mlme_osdep.h b/drivers/staging/rtl8723au/include/mlme_osdep.h index b7132a9a13783f..4bb5525b7a6823 100644 --- a/drivers/staging/rtl8723au/include/mlme_osdep.h +++ b/drivers/staging/rtl8723au/include/mlme_osdep.h @@ -19,10 +19,6 @@ #include void rtw_os_indicate_disconnect23a(struct rtw_adapter *adapter); -void rtw_os_indicate_connect23a(struct rtw_adapter *adapter); -void rtw_os_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted); -void rtw_report_sec_ie23a(struct rtw_adapter *adapter, u8 authmode, u8 *sec_ie); - void rtw_reset_securitypriv23a(struct rtw_adapter *adapter); #endif /* _MLME_OSDEP_H_ */ diff --git a/drivers/staging/rtl8723au/include/osdep_intf.h b/drivers/staging/rtl8723au/include/osdep_intf.h index b603cf532900af..d3e22635e9ea2d 100644 --- a/drivers/staging/rtl8723au/include/osdep_intf.h +++ b/drivers/staging/rtl8723au/include/osdep_intf.h @@ -26,8 +26,6 @@ u8 rtw_init_drv_sw23a(struct rtw_adapter *padapter); u8 rtw_free_drv_sw23a(struct rtw_adapter *padapter); u8 rtw_reset_drv_sw23a(struct rtw_adapter *padapter); -u32 rtw_start_drv_threads23a(struct rtw_adapter *padapter); -void rtw_stop_drv_threads23a (struct rtw_adapter *padapter); void rtw_cancel_all_timer23a(struct rtw_adapter *padapter); int rtw_init_netdev23a_name23a(struct net_device *pnetdev, const char *ifname); diff --git a/drivers/staging/rtl8723au/include/osdep_service.h b/drivers/staging/rtl8723au/include/osdep_service.h index 039bc7285ed010..40445bbafe771f 100644 --- a/drivers/staging/rtl8723au/include/osdep_service.h +++ b/drivers/staging/rtl8723au/include/osdep_service.h @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -40,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -139,7 +137,6 @@ void _rtw_vmfree(u8 *pbuf, u32 sz); extern unsigned char REALTEK_96B_IE23A[]; extern unsigned char MCS_rate_2R23A[16]; -extern unsigned char RTW_WPA_OUI23A[]; extern unsigned char WPA_TKIP_CIPHER23A[4]; extern unsigned char RSN_TKIP_CIPHER23A[4]; @@ -149,16 +146,6 @@ extern unsigned char MCS_rate_1R23A[16]; void _rtw_init_queue23a(struct rtw_queue *pqueue); u32 _rtw_queue_empty23a(struct rtw_queue *pqueue); -static inline u32 bitshift(u32 bitmask) -{ - u32 i; - - for (i = 0; i <= 31; i++) - if (((bitmask>>i) & 0x1) == 1) break; - - return i; -} - void rtw_suspend_lock_init(void); void rtw_suspend_lock_uninit(void); void rtw_lock_suspend(void); @@ -174,12 +161,6 @@ void rtw_unlock_suspend(void); #define FUNC_ADPT_FMT "%s(%s)" #define FUNC_ADPT_ARG(adapter) __func__, adapter->pnetdev->name -#define rtw_signal_process(pid, sig) kill_pid(find_vpid((pid)),(sig), 1) - -u64 rtw_modular6423a(u64 x, u64 y); -u64 rtw_division6423a(u64 x, u64 y); - - /* Macros for handling unaligned memory accesses */ #define RTW_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ @@ -199,9 +180,7 @@ bool rtw_cbuf_push23a(struct rtw_cbuf *cbuf, void *buf); void *rtw_cbuf_pop23a(struct rtw_cbuf *cbuf); struct rtw_cbuf *rtw_cbuf_alloc23a(u32 size); void rtw_cbuf_free(struct rtw_cbuf *cbuf); -int rtw_change_ifname(struct rtw_adapter *padapter, const char *ifname); s32 c2h_evt_hdl(struct rtw_adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter); -void indicate_wx_scan_complete_event(struct rtw_adapter *padapter); u8 rtw_do_join23a(struct rtw_adapter *padapter); #endif diff --git a/drivers/staging/rtl8723au/include/recv_osdep.h b/drivers/staging/rtl8723au/include/recv_osdep.h index 15c94b6168bfeb..c2d3f1bd594827 100644 --- a/drivers/staging/rtl8723au/include/recv_osdep.h +++ b/drivers/staging/rtl8723au/include/recv_osdep.h @@ -23,22 +23,13 @@ void _rtw_free_recv_priv23a (struct recv_priv *precvpriv); int rtw_recv_entry23a(struct recv_frame *precv_frame); int rtw_recv_indicatepkt23a(struct rtw_adapter *adapter, struct recv_frame *precv_frame); -void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *preturnedpkt); -void rtw_hostapd_mlme_rx23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); void rtw_handle_tkip_mic_err23a(struct rtw_adapter *padapter, u8 bgroup); int rtw_init_recv_priv(struct recv_priv *precvpriv, struct rtw_adapter *padapter); void rtw_free_recv_priv (struct recv_priv *precvpriv); int rtw_os_recv_resource_init(struct recv_priv *precvpriv, struct rtw_adapter *padapter); -int rtw_os_recv_resource_alloc23a(struct rtw_adapter *padapter, struct recv_frame *precvframe); -void rtw_os_recv_resource_free(struct recv_priv *precvpriv); - -int rtw_os_recvbuf_resource_alloc23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf); -int rtw_os_recvbuf_resource_free23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf); - -void rtw_os_read_port23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf); void rtw_init_recv_timer23a(struct recv_reorder_ctrl *preorder_ctrl); diff --git a/drivers/staging/rtl8723au/include/rtl8723a_cmd.h b/drivers/staging/rtl8723au/include/rtl8723a_cmd.h index 8fccbfc3a45c65..09fa7234030258 100644 --- a/drivers/staging/rtl8723au/include/rtl8723a_cmd.h +++ b/drivers/staging/rtl8723au/include/rtl8723a_cmd.h @@ -151,10 +151,6 @@ u8 rtl8723a_set_rssi_cmd(struct rtw_adapter * padapter, u8 *param); u8 rtl8723a_set_raid_cmd(struct rtw_adapter * padapter, u32 mask, u8 arg); void rtl8723a_add_rateatid(struct rtw_adapter * padapter, u32 bitmap, u8 arg, u8 rssi_level); -#ifdef CONFIG_8723AU_P2P -void rtl8723a_set_p2p_ps_offload_cmd(struct rtw_adapter * padapter, u8 p2p_ps_state); -#endif /* CONFIG_8723AU_P2P */ - void CheckFwRsvdPageContent23a(struct rtw_adapter *padapter); #endif diff --git a/drivers/staging/rtl8723au/include/rtl8723a_hal.h b/drivers/staging/rtl8723au/include/rtl8723a_hal.h index c20248bab71742..f6b4b7c7c22dc9 100644 --- a/drivers/staging/rtl8723au/include/rtl8723a_hal.h +++ b/drivers/staging/rtl8723au/include/rtl8723a_hal.h @@ -424,11 +424,6 @@ struct hal_data_8723a { bool bMACFuncEnable; -#ifdef CONFIG_8723AU_P2P - struct P2P_PS_Offload_t p2p_ps_offload; -#endif - - /* */ /* For USB Interface HAL related */ /* */ @@ -437,14 +432,6 @@ struct hal_data_8723a { /* Interrupt related register information. */ u32 IntArray[2]; u32 IntrMask[2]; - - /* */ - /* For SDIO Interface HAL related */ - /* */ - - /* Auto FSM to Turn On, include clock, isolation, power control for MAC only */ - u8 bMacPwrCtrlOn; - }; #define GET_HAL_DATA(__pAdapter) ((struct hal_data_8723a *)((__pAdapter)->HalData)) @@ -556,8 +543,6 @@ void Hal_EfuseParseThermalMeter_8723A(struct rtw_adapter *padapter, u8 *hwinfo, void Hal_InitChannelPlan23a(struct rtw_adapter *padapter); void rtl8723a_set_hal_ops(struct hal_ops *pHalFunc); -void SetHwReg8723A(struct rtw_adapter *padapter, u8 variable, u8 *val); -void GetHwReg8723A(struct rtw_adapter *padapter, u8 variable, u8 *val); #ifdef CONFIG_8723AU_BT_COEXIST void rtl8723a_SingleDualAntennaDetection(struct rtw_adapter *padapter); #endif diff --git a/drivers/staging/rtl8723au/include/rtw_ap.h b/drivers/staging/rtl8723au/include/rtw_ap.h index 76f82d68f633d2..8d9be5a36eae76 100644 --- a/drivers/staging/rtl8723au/include/rtw_ap.h +++ b/drivers/staging/rtl8723au/include/rtw_ap.h @@ -22,8 +22,6 @@ #ifdef CONFIG_8723AU_AP_MODE /* external function */ -void rtw_indicate_sta_assoc_event23a(struct rtw_adapter *padapter, struct sta_info *psta); -void rtw_indicate_sta_disassoc_event23a(struct rtw_adapter *padapter, struct sta_info *psta); void init_mlme_ap_info23a(struct rtw_adapter *padapter); void free_mlme_ap_info23a(struct rtw_adapter *padapter); @@ -34,7 +32,7 @@ void update_beacon23a(struct rtw_adapter *padapter, u8 ie_id, u8 *oui, u8 tx); void add_RATid23a(struct rtw_adapter *padapter, struct sta_info *psta, u8 rssi_level); void expire_timeout_chk23a(struct rtw_adapter *padapter); void update_sta_info23a_apmode23a(struct rtw_adapter *padapter, struct sta_info *psta); -int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len); +int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, unsigned int len); void rtw_ap_restore_network(struct rtw_adapter *padapter); void rtw_set_macaddr_acl23a(struct rtw_adapter *padapter, int mode); int rtw_acl_add_sta23a(struct rtw_adapter *padapter, u8 *addr); diff --git a/drivers/staging/rtl8723au/include/rtw_cmd.h b/drivers/staging/rtl8723au/include/rtw_cmd.h index f9caa3e35f57d3..3ecb971c6e3995 100644 --- a/drivers/staging/rtl8723au/include/rtw_cmd.h +++ b/drivers/staging/rtl8723au/include/rtw_cmd.h @@ -25,8 +25,6 @@ #include /* */ -#define FREE_CMDOBJ_SZ 128 - #define MAX_CMDSZ 1024 #define MAX_RSPSZ 512 #define MAX_EVTSZ 1024 @@ -34,6 +32,7 @@ #define CMDBUFF_ALIGN_SZ 512 struct cmd_obj { + struct work_struct work; struct rtw_adapter *padapter; u16 cmdcode; u8 res; @@ -41,16 +40,10 @@ struct cmd_obj { u32 cmdsz; u8 *rsp; u32 rspsz; - /* struct semaphore cmd_sem; */ - struct list_head list; }; struct cmd_priv { - struct semaphore cmd_queue_sema; - /* struct semaphore cmd_done_sema; */ - struct semaphore terminate_cmdthread_sema; - struct rtw_queue cmd_queue; - u8 cmd_seq; + struct workqueue_struct *wq; u8 *cmd_buf; /* shall be non-paged, and 4 bytes aligned */ u8 *cmd_allocated_buf; u8 *rsp_buf; /* shall be non-paged, and 4 bytes aligned */ @@ -58,7 +51,6 @@ struct cmd_priv { u32 cmd_issued_cnt; u32 cmd_done_cnt; u32 rsp_cnt; - u8 cmdthd_running; struct rtw_adapter *padapter; }; @@ -77,7 +69,6 @@ struct evt_priv { #define init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code) \ do {\ - INIT_LIST_HEAD(&pcmd->list);\ pcmd->cmdcode = code;\ pcmd->parmbuf = (u8 *)(pparm);\ pcmd->cmdsz = sizeof (*pparm);\ @@ -94,7 +85,7 @@ struct c2h_evt_hdr { #define c2h_evt_exist(c2h_evt) ((c2h_evt)->id || (c2h_evt)->plen) -u32 rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *obj); +int rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *obj); void rtw_free_cmd_obj23a(struct cmd_obj *pcmd); int rtw_cmd_thread23a(void *context); @@ -106,9 +97,6 @@ u32 rtw_init_evt_priv23a (struct evt_priv *pevtpriv); void rtw_free_evt_priv23a (struct evt_priv *pevtpriv); void rtw_cmd_clr_isr23a(struct cmd_priv *pcmdpriv); void rtw_evt_notify_isr(struct evt_priv *pevtpriv); -#ifdef CONFIG_8723AU_P2P -u8 p2p_protocol_wk_cmd23a(struct rtw_adapter*padapter, int intCmdType ); -#endif /* CONFIG_8723AU_P2P */ enum rtw_drvextra_cmd_id { @@ -731,7 +719,7 @@ u8 rtw_tdls_cmd(struct rtw_adapter*padapter, u8 *addr, u8 option); u8 rtw_c2h_wk_cmd23a(struct rtw_adapter *padapter, u8 *c2h_evt); -u8 rtw_drvextra_cmd_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); +u8 rtw_drvextra_cmd_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); void rtw_survey_cmd_callback23a(struct rtw_adapter *padapter, struct cmd_obj *pcmd); void rtw_disassoc_cmd23a_callback(struct rtw_adapter *padapter, struct cmd_obj *pcmd); diff --git a/drivers/staging/rtl8723au/include/rtw_io.h b/drivers/staging/rtl8723au/include/rtw_io.h index 8d39d800267de1..fffe028750c20c 100644 --- a/drivers/staging/rtl8723au/include/rtw_io.h +++ b/drivers/staging/rtl8723au/include/rtw_io.h @@ -97,39 +97,28 @@ #define _INTF_ASYNC_ BIT(0) /* support async io */ struct intf_priv; -struct intf_hdl; -struct io_queue; struct _io_ops { - u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr); - u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr); - u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr); + u8 (*_read8)(struct rtw_adapter *adapter, u32 addr); + u16 (*_read16)(struct rtw_adapter *adapter, u32 addr); + u32 (*_read32)(struct rtw_adapter *adapter, u32 addr); - int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); - int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); - int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); - int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata); + int (*_write8)(struct rtw_adapter *adapter, u32 addr, u8 val); + int (*_write16)(struct rtw_adapter *adapter, u32 addr, u16 val); + int (*_write32)(struct rtw_adapter *adapter, u32 addr, u32 val); + int (*_writeN)(struct rtw_adapter *adapter, u32 addr, u32 length, u8 *pdata); - int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val); - int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val); - int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val); + void (*_read_mem)(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); + void (*_write_mem)(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); - void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); - void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); + u32 (*_read_interrupt)(struct rtw_adapter *adapter, u32 addr); - void (*_sync_irp_protocol_rw)(struct io_queue *pio_q); - - u32 (*_read_interrupt)(struct intf_hdl *pintfhdl, u32 addr); - - u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, struct recv_buf *rbuf); - u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, struct xmit_buf *pmem); - - u32 (*_write_scsi)(struct intf_hdl *pintfhdl,u32 cnt, u8 *pmem); - - void (*_read_port_cancel)(struct intf_hdl *pintfhdl); - void (*_write_port_cancel)(struct intf_hdl *pintfhdl); + u32 (*_read_port)(struct rtw_adapter *adapter, u32 addr, u32 cnt, struct recv_buf *rbuf); + u32 (*_write_port)(struct rtw_adapter *adapter, u32 addr, u32 cnt, struct xmit_buf *pmem); + void (*_read_port_cancel)(struct rtw_adapter *adapter); + void (*_write_port_cancel)(struct rtw_adapter *adapter); }; struct io_req { @@ -145,14 +134,6 @@ struct io_req { u8 *cnxt; }; -struct intf_hdl { - struct rtw_adapter *padapter; - struct dvobj_priv *pintf_dev;/* pointer to &(padapter->dvobjpriv); */ - - struct _io_ops io_ops; - -}; - struct reg_protocol_rd { #ifdef __LITTLE_ENDIAN @@ -266,40 +247,6 @@ struct reg_protocol_wt { }; - -/* -Below is the data structure used by _io_handler - -*/ - -struct io_queue { - spinlock_t lock; - struct list_head free_ioreqs; - struct list_head pending; /* The io_req list that will be served in the single protocol read/write. */ - struct list_head processing; - u8 *free_ioreqs_buf; /* 4-byte aligned */ - u8 *pallocated_free_ioreqs_buf; - struct intf_hdl intf; -}; - -struct io_priv{ - - struct rtw_adapter *padapter; - - struct intf_hdl intf; - -}; - -uint ioreq_flush(struct rtw_adapter *adapter, struct io_queue *ioqueue); -void sync_ioreq_enqueue(struct io_req *preq,struct io_queue *ioqueue); -uint sync_ioreq_flush(struct rtw_adapter *adapter, struct io_queue *ioqueue); - -uint free_ioreq(struct io_req *preq, struct io_queue *pio_queue); -struct io_req *alloc_ioreq(struct io_queue *pio_q); - -uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl); -void unregister_intf_hdl(struct intf_hdl *pintfhdl); - void _rtw_attrib_read(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); void _rtw_attrib_write(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); @@ -315,13 +262,8 @@ int _rtw_write1623a(struct rtw_adapter *adapter, u32 addr, u16 val); int _rtw_write3223a(struct rtw_adapter *adapter, u32 addr, u32 val); int _rtw_writeN23a(struct rtw_adapter *adapter, u32 addr, u32 length, u8 *pdata); -int _rtw_write823a_async23a(struct rtw_adapter *adapter, u32 addr, u8 val); -int _rtw_write1623a_async(struct rtw_adapter *adapter, u32 addr, u16 val); -int _rtw_write3223a_async23a(struct rtw_adapter *adapter, u32 addr, u32 val); - void _rtw_write_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); u32 _rtw_write_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, struct xmit_buf *pmem); -u32 _rtw_write_port23a_and_wait23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, struct xmit_buf *pmem, int timeout_ms); void _rtw_write_port23a_cancel(struct rtw_adapter *adapter); #ifdef DBG_IO @@ -349,13 +291,8 @@ int dbg_rtw_writeN23a(struct rtw_adapter *adapter, u32 addr ,u32 length , u8 *da #define rtw_write32(adapter, addr, val) dbg_rtw_write3223a((adapter), (addr), (val), __FUNCTION__, __LINE__) #define rtw_writeN(adapter, addr, length, data) dbg_rtw_writeN23a((adapter), (addr), (length), (data), __FUNCTION__, __LINE__) -#define rtw_write8_async(adapter, addr, val) _rtw_write823a_async23a((adapter), (addr), (val)) -#define rtw_write16_async(adapter, addr, val) _rtw_write1623a_async((adapter), (addr), (val)) -#define rtw_write32_async(adapter, addr, val) _rtw_write3223a_async23a((adapter), (addr), (val)) - #define rtw_write_mem(adapter, addr, cnt, mem) _rtw_write_mem23a((adapter), addr, cnt, mem) #define rtw_write_port(adapter, addr, cnt, mem) _rtw_write_port23a(adapter, addr, cnt, mem) -#define rtw_write_port_and_wait(adapter, addr, cnt, mem, timeout_ms) _rtw_write_port23a_and_wait23a((adapter), (addr), (cnt), (mem), (timeout_ms)) #define rtw_write_port_cancel(adapter) _rtw_write_port23a_cancel(adapter) #else /* DBG_IO */ #define rtw_read8(adapter, addr) _rtw_read823a((adapter), (addr)) @@ -370,35 +307,11 @@ int dbg_rtw_writeN23a(struct rtw_adapter *adapter, u32 addr ,u32 length , u8 *da #define rtw_write32(adapter, addr, val) _rtw_write3223a((adapter), (addr), (val)) #define rtw_writeN(adapter, addr, length, data) _rtw_writeN23a((adapter), (addr), (length), (data)) -#define rtw_write8_async(adapter, addr, val) _rtw_write823a_async23a((adapter), (addr), (val)) -#define rtw_write16_async(adapter, addr, val) _rtw_write1623a_async((adapter), (addr), (val)) -#define rtw_write32_async(adapter, addr, val) _rtw_write3223a_async23a((adapter), (addr), (val)) - #define rtw_write_mem(adapter, addr, cnt, mem) _rtw_write_mem23a((adapter), (addr), (cnt), (mem)) #define rtw_write_port(adapter, addr, cnt, mem) _rtw_write_port23a((adapter), (addr), (cnt), (mem)) -#define rtw_write_port_and_wait(adapter, addr, cnt, mem, timeout_ms) _rtw_write_port23a_and_wait23a((adapter), (addr), (cnt), (mem), (timeout_ms)) #define rtw_write_port_cancel(adapter) _rtw_write_port23a_cancel((adapter)) #endif /* DBG_IO */ -void rtw_write_scsi(struct rtw_adapter *adapter, u32 cnt, u8 *pmem); - -/* ioreq */ -void ioreq_read8(struct rtw_adapter *adapter, u32 addr, u8 *pval); -void ioreq_read16(struct rtw_adapter *adapter, u32 addr, u16 *pval); -void ioreq_read32(struct rtw_adapter *adapter, u32 addr, u32 *pval); -void ioreq_write8(struct rtw_adapter *adapter, u32 addr, u8 val); -void ioreq_write16(struct rtw_adapter *adapter, u32 addr, u16 val); -void ioreq_write32(struct rtw_adapter *adapter, u32 addr, u32 val); - -int rtw_init_io_priv23a(struct rtw_adapter *padapter, void (*set_intf_ops)(struct _io_ops *pops)); - -uint alloc_io_queue(struct rtw_adapter *adapter); -void free_io_queue(struct rtw_adapter *adapter); -void async_bus_io(struct io_queue *pio_q); -void bus_sync_io(struct io_queue *pio_q); -u32 _ioreq2rwmem(struct io_queue *pio_q); -void dev_power_down(struct rtw_adapter * Adapter, u8 bpwrup); - #define PlatformEFIOWrite1Byte(_a,_b,_c) \ rtw_write8(_a,_b,_c) #define PlatformEFIOWrite2Byte(_a,_b,_c) \ diff --git a/drivers/staging/rtl8723au/include/rtw_mlme.h b/drivers/staging/rtl8723au/include/rtw_mlme.h index 31f96f39b498dc..38203f16aee821 100644 --- a/drivers/staging/rtl8723au/include/rtw_mlme.h +++ b/drivers/staging/rtl8723au/include/rtw_mlme.h @@ -148,30 +148,6 @@ struct tx_invite_resp_info { u8 token; /* Used to record the dialog token of p2p invitation request frame. */ }; -#ifdef CONFIG_8723AU_P2P - -struct wifi_display_info { - u16 wfd_enable; /* Enable/Disable the WFD function. */ - u16 rtsp_ctrlport; /* TCP port number at which the this WFD device listens for RTSP messages */ - u16 peer_rtsp_ctrlport; /* TCP port number at which the peer WFD device listens for RTSP messages */ - /* This filed should be filled when receiving the gropu negotiation request */ - - u8 peer_session_avail; /* WFD session is available or not for the peer wfd device. */ - /* This variable will be set when sending the provisioning discovery request to peer WFD device. */ - /* And this variable will be reset when it is read by using the iwpriv p2p_get wfd_sa command. */ - u8 ip_address[4]; - u8 peer_ip_address[4]; - u8 wfd_pc; /* WFD preferred connection */ - /* 0 -> Prefer to use the P2P for WFD connection on peer side. */ - /* 1 -> Prefer to use the TDLS for WFD connection on peer side. */ - - u8 wfd_device_type;/* WFD Device Type */ - /* 0 -> WFD Source Device */ - /* 1 -> WFD Primary Sink Device */ - enum SCAN_RESULT_TYPE scan_result_type; /* Used when P2P is enable. This parameter will impact the scan result. */ -}; -#endif /* CONFIG_8723AU_P2P */ - struct tx_provdisc_req_info { u16 wps_config_method_request; /* Used when sending the provisioning request frame */ u16 peer_channel_num[2]; /* The channel number which the receiver stands. */ @@ -203,102 +179,6 @@ struct scan_limit_info { u8 operation_ch[2]; /* Store the operation channel of invitation request frame */ }; -struct cfg80211_wifidirect_info { - struct timer_list remain_on_ch_timer; - u8 restore_channel; - struct ieee80211_channel remain_on_ch_channel; - enum nl80211_channel_type remain_on_ch_type; - u64 remain_on_ch_cookie; - bool is_ro_ch; -}; - -struct wifidirect_info { - struct rtw_adapter *padapter; - struct timer_list find_phase_timer; - struct timer_list restore_p2p_state_timer; - - /* Used to do the scanning. After confirming the peer is availalble, the driver transmits the P2P frame to peer. */ - struct timer_list pre_tx_scan_timer; - struct timer_list reset_ch_sitesurvey; - struct timer_list reset_ch_sitesurvey2; /* Just for resetting the scan limit function by using p2p nego */ - struct tx_provdisc_req_info tx_prov_disc_info; - struct rx_provdisc_req_info rx_prov_disc_info; - struct tx_invite_req_info invitereq_info; - struct profile_info profileinfo[P2P_MAX_PERSISTENT_GROUP_NUM]; /* Store the profile information of persistent group */ - struct tx_invite_resp_info inviteresp_info; - struct tx_nego_req_info nego_req_info; - struct group_id_info groupid_info; /* Store the group id information when doing the group negotiation handshake. */ - struct scan_limit_info rx_invitereq_info; /* Used for get the limit scan channel from the Invitation procedure */ - struct scan_limit_info p2p_info; /* Used for get the limit scan channel from the P2P negotiation handshake */ -#ifdef CONFIG_8723AU_P2P - struct wifi_display_info *wfd_info; -#endif - enum P2P_ROLE role; - enum P2P_STATE pre_p2p_state; - enum P2P_STATE p2p_state; - u8 device_addr[ETH_ALEN]; /* The device address should be the mac address of this device. */ - u8 interface_addr[ETH_ALEN]; - u8 social_chan[4]; - u8 listen_channel; - u8 operating_channel; - u8 listen_dwell; /* This value should be between 1 and 3 */ - u8 support_rate[8]; - u8 p2p_wildcard_ssid[P2P_WILDCARD_SSID_LEN]; - u8 intent; /* should only include the intent value. */ - u8 p2p_peer_interface_addr[ETH_ALEN]; - u8 p2p_peer_device_addr[ETH_ALEN]; - u8 peer_intent; /* Included the intent value and tie breaker value. */ - u8 device_name[WPS_MAX_DEVICE_NAME_LEN]; /* Device name for displaying on searching device screen */ - u8 device_name_len; - u8 profileindex; /* Used to point to the index of profileinfo array */ - u8 peer_operating_ch; - u8 find_phase_state_exchange_cnt; - u16 device_password_id_for_nego; /* The device password ID for group negotation */ - u8 negotiation_dialog_token; - /* SSID information for group negotitation */ - u8 nego_ssid[IEEE80211_MAX_SSID_LEN]; - u8 nego_ssidlen; - u8 p2p_group_ssid[IEEE80211_MAX_SSID_LEN]; - u8 p2p_group_ssid_len; - u8 persistent_supported; /* Flag to know the persistent function should be supported or not. */ - /* In the Sigma test, the Sigma will provide this enable from the sta_set_p2p CAPI. */ - /* 0: disable */ - /* 1: enable */ - u8 session_available; /* Flag to set the WFD session available to enable or disable "by Sigma" */ - /* In the Sigma test, the Sigma will disable the session available by using the sta_preset CAPI. */ - /* 0: disable */ - /* 1: enable */ - - u8 wfd_tdls_enable; /* Flag to enable or disable the TDLS by WFD Sigma */ - /* 0: disable */ - /* 1: enable */ - u8 wfd_tdls_weaksec; /* Flag to enable or disable the weak security function for TDLS by WFD Sigma */ - /* 0: disable */ - /* In this case, the driver can't issue the tdsl setup request frame. */ - /* 1: enable */ - /* In this case, the driver can issue the tdls setup request frame */ - /* even the current security is weak security. */ - - enum P2P_WPSINFO ui_got_wps_info; /* This field will store the WPS value (PIN value or PBC) that UI had got from the user. */ - u16 supported_wps_cm; /* This field describes the WPS config method which this driver supported. */ - /* The value should be the combination of config method defined in page104 of WPS v2.0 spec. */ - uint channel_list_attr_len; /* This field will contain the length of body of P2P Channel List attribute of group negotitation response frame. */ - u8 channel_list_attr[100]; /* This field will contain the body of P2P Channel List attribute of group negotitation response frame. */ - /* We will use the channel_cnt and channel_list fields when constructing the group negotitation confirm frame. */ -#ifdef CONFIG_8723AU_P2P - enum P2P_PS_MODE p2p_ps_mode; /* indicate p2p ps mode */ - enum P2P_PS_STATE p2p_ps_state; /* indicate p2p ps state */ - u8 noa_index; /* Identifies and instance of Notice of Absence timing. */ - u8 ctwindow; /* Client traffic window. A period of time in TU after TBTT. */ - u8 opp_ps; /* opportunistic power save. */ - u8 noa_num; /* number of NoA descriptor in P2P IE. */ - u8 noa_count[P2P_MAX_NOA_NUM]; /* Count for owner, Type of client. */ - u32 noa_duration[P2P_MAX_NOA_NUM]; /* Max duration for owner, preferred or min acceptable duration for client. */ - u32 noa_interval[P2P_MAX_NOA_NUM]; /* Length of interval for owner, preferred or max acceptable interval of client. */ - u32 noa_start_time[P2P_MAX_NOA_NUM]; /* schedule expressed in terms of the lower 4 bytes of the TSF timer. */ -#endif /* CONFIG_8723AU_P2P */ -}; - struct tdls_ss_record { /* signal strength record */ u8 macaddr[ETH_ALEN]; u8 RxPWDBAll; @@ -324,9 +204,6 @@ struct tdls_info { u8 watchdog_count; u8 dev_discovered; /* WFD_TDLS: for sigma test */ u8 enable; -#ifdef CONFIG_8723AU_P2P - struct wifi_display_info *wfd_info; -#endif }; struct mlme_priv { @@ -468,7 +345,7 @@ void rtw_cpwm_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf); int event_thread(void *context); void rtw23a_join_to_handler(unsigned long); -void rtw_free_network_queue23a(struct rtw_adapter *adapter, u8 isfreeall); +void rtw_free_network_queue23a(struct rtw_adapter *adapter); int rtw_init_mlme_priv23a(struct rtw_adapter *adapter); void rtw_free_mlme_priv23a(struct mlme_priv *pmlmepriv); @@ -553,7 +430,6 @@ void rtw_free_assoc_resources23a(struct rtw_adapter *adapter, int lock_scanned_queue); void rtw_indicate_disconnect23a(struct rtw_adapter *adapter); void rtw_indicate_connect23a(struct rtw_adapter *adapter); -void rtw_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted); void rtw_scan_abort23a(struct rtw_adapter *adapter); int rtw_restruct_sec_ie23a(struct rtw_adapter *adapter, u8 *in_ie, u8 *out_ie, @@ -574,30 +450,18 @@ void rtw_clear_scan_deny(struct rtw_adapter *adapter); void rtw_set_scan_deny_timer_hdl(unsigned long data); void rtw_set_scan_deny(struct rtw_adapter *adapter, u32 ms); -int _rtw_init_mlme_priv23a(struct rtw_adapter *padapter); - void rtw23a_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv); void _rtw_free_mlme_priv23a(struct mlme_priv *pmlmepriv); struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv); -void _rtw_free_network23a(struct mlme_priv *pmlmepriv, - struct wlan_network *pnetwork, u8 isfreeall); -void _rtw_free_network23a_nolock23a(struct mlme_priv *pmlmepriv, - struct wlan_network *pnetwork); - -struct wlan_network *_rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr); - -void _rtw_free_network23a_queue23a(struct rtw_adapter *padapter, u8 isfreeall); - int rtw_if_up23a(struct rtw_adapter *padapter); int rtw_linked_check(struct rtw_adapter *padapter); -u8 *rtw_get_capability23a_from_ie(u8 *ie); -u8 *rtw_get_timestampe_from_ie23a(u8 *ie); -u8 *rtw_get_beacon_interval23a_from_ie(u8 *ie); +__le16 *rtw_get_capability23a_from_ie(u8 *ie); +__le16 *rtw_get_beacon_interval23a_from_ie(u8 *ie); void rtw_joinbss_reset23a(struct rtw_adapter *padapter); @@ -613,12 +477,8 @@ int rtw_is_same_ibss23a(struct rtw_adapter *adapter, struct wlan_network *pnetwork); int is_same_network23a(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst); -void _rtw23a_roaming(struct rtw_adapter *adapter, - struct wlan_network *tgt_network); void rtw23a_roaming(struct rtw_adapter *adapter, struct wlan_network *tgt_network); void rtw_set_roaming(struct rtw_adapter *adapter, u8 to_roaming); -u8 rtw_to_roaming(struct rtw_adapter *adapter); -void rtw_stassoc_hw_rpt23a(struct rtw_adapter *adapter, struct sta_info *psta); #endif /* __RTL871X_MLME_H_ */ diff --git a/drivers/staging/rtl8723au/include/rtw_mlme_ext.h b/drivers/staging/rtl8723au/include/rtw_mlme_ext.h index 0aaf0d5d8aeaa6..26d360178eac12 100644 --- a/drivers/staging/rtl8723au/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8723au/include/rtw_mlme_ext.h @@ -89,7 +89,6 @@ #define _54M_RATE_ 11 -extern unsigned char RTW_WPA_OUI23A[]; extern unsigned char WMM_OUI23A[]; extern unsigned char WPS_OUI23A[]; extern unsigned char WFD_OUI23A[]; @@ -262,13 +261,13 @@ enum SCAN_STATE { struct mlme_handler { char *str; - unsigned int (*func)(struct rtw_adapter *padapter, struct recv_frame *precv_frame); + int (*func)(struct rtw_adapter *padapter, struct recv_frame *precv_frame); }; struct action_handler { unsigned int num; char* str; - unsigned int (*func)(struct rtw_adapter *padapter, struct recv_frame *precv_frame); + int (*func)(struct rtw_adapter *padapter, struct recv_frame *precv_frame); }; struct ss_res @@ -474,10 +473,6 @@ void get_rate_set23a(struct rtw_adapter *padapter, unsigned char *pbssrate, void UpdateBrateTbl23a(struct rtw_adapter *padapter,u8 *mBratesOS); void Update23aTblForSoftAP(u8 *bssrateset, u32 bssratelen); -void Save_DM_Func_Flag23a(struct rtw_adapter *padapter); -void Restore_DM_Func_Flag23a(struct rtw_adapter *padapter); -void Switch_DM_Func23a(struct rtw_adapter *padapter, unsigned long mode, u8 enable); - void Set_MSR23a(struct rtw_adapter *padapter, u8 type); u8 rtw_get_oper_ch23a(struct rtw_adapter *adapter); @@ -495,12 +490,9 @@ void SetBWMode23a(struct rtw_adapter *padapter, unsigned short bwmode, unsigned int decide_wait_for_beacon_timeout23a(unsigned int bcn_interval); -void write_cam23a(struct rtw_adapter *padapter, u8 entry, u16 ctrl, - u8 *mac, u8 *key); void clear_cam_entry23a(struct rtw_adapter *padapter, u8 entry); void invalidate_cam_all23a(struct rtw_adapter *padapter); -void CAM_empty_entry23a(struct rtw_adapter *Adapter, u8 ucIndex); int allocate_fw_sta_entry23a(struct rtw_adapter *padapter); void flush_all_cam_entry23a(struct rtw_adapter *padapter); @@ -526,10 +518,6 @@ unsigned char check_assoc_AP23a(u8 *pframe, uint len); int WMM_param_handler23a(struct rtw_adapter *padapter, struct ndis_802_11_var_ies *pIE); -#ifdef CONFIG_8723AU_P2P -int WFD_info_handler(struct rtw_adapter *padapter, - struct ndis_802_11_var_ies *pIE); -#endif void WMMOnAssocRsp23a(struct rtw_adapter *padapter); void HT_caps_handler23a(struct rtw_adapter *padapter, @@ -544,7 +532,8 @@ void VCS_update23a(struct rtw_adapter *padapter, struct sta_info *psta); void update_beacon23a_info(struct rtw_adapter *padapter, u8 *pframe, uint len, struct sta_info *psta); -int rtw_check_bcn_info23a(struct rtw_adapter *Adapter, u8 *pframe, u32 packet_len); +int rtw_check_bcn_info23a(struct rtw_adapter *Adapter, + struct ieee80211_mgmt *mgmt, u32 packet_len); void update_IOT_info23a(struct rtw_adapter *padapter); void update_capinfo23a(struct rtw_adapter *Adapter, u16 updateCap); void update_wireless_mode23a(struct rtw_adapter * padapter); @@ -594,18 +583,6 @@ s32 dump_mgntframe23a_and_wait(struct rtw_adapter *padapter, s32 dump_mgntframe23a_and_wait_ack23a(struct rtw_adapter *padapter, struct xmit_frame *pmgntframe); -#ifdef CONFIG_8723AU_P2P -void issue_probersp23a_p2p23a(struct rtw_adapter *padapter, unsigned char *da); -void issue_p2p_provision_request23a(struct rtw_adapter *padapter, u8 *pssid, - u8 ussidlen, u8* pdev_raddr); -void issue_p2p_GO_request23a(struct rtw_adapter *padapter, u8* raddr); -void issue23a_probereq_p2p(struct rtw_adapter *padapter, u8 *da); -int issue23a_probereq_p2p_ex(struct rtw_adapter *adapter, u8 *da, int try_cnt, - int wait_ms); -void issue_p2p_invitation_response23a(struct rtw_adapter *padapter, u8* raddr, - u8 dialogToken, u8 success); -void issue_p2p_invitation_request23a(struct rtw_adapter *padapter, u8* raddr); -#endif /* CONFIG_8723AU_P2P */ void issue_beacon23a(struct rtw_adapter *padapter, int timeout_ms); void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq); @@ -628,8 +605,9 @@ int issue_deauth23a_ex23a(struct rtw_adapter *padapter, u8 *da, unsigned short r int try_cnt, int wait_ms); void issue_action_spct_ch_switch23a(struct rtw_adapter *padapter, u8 *ra, u8 new_ch, u8 ch_offset); -void issue_action_BA23a(struct rtw_adapter *padapter, unsigned char *raddr, - unsigned char action, unsigned short status); +void issue_action_BA23a(struct rtw_adapter *padapter, + const unsigned char *raddr, + unsigned char action, unsigned short status); unsigned int send_delba23a(struct rtw_adapter *padapter, u8 initiator, u8 *addr); unsigned int send_beacon23a(struct rtw_adapter *padapter); @@ -638,28 +616,6 @@ void start_clnt_auth23a(struct rtw_adapter *padapter); void start_clnt_join23a(struct rtw_adapter *padapter); void start_create_ibss23a(struct rtw_adapter *padapter); -unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnProbeReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnProbeRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int DoReserved23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnBeacon23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnAtim23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnDisassoc23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnAuth23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnAuth23aClient23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnDeAuth23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnAction23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); - -unsigned int on_action_spct23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnAction23a_qos(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnAction23a_dls(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int on_action_public23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnAction23a_ht(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnAction23a_wmm(struct rtw_adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnAction23a_p2p(struct rtw_adapter *padapter, struct recv_frame *precv_frame); - void mlmeext_joinbss_event_callback23a(struct rtw_adapter *padapter, int join_res); void mlmeext_sta_del_event_callback23a(struct rtw_adapter *padapter); @@ -680,12 +636,11 @@ int cckratesonly_included23a(unsigned char *rate, int ratelen); void process_addba_req23a(struct rtw_adapter *padapter, u8 *paddba_req, u8 *addr); -void update_TSF23a(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len); void correct_TSF23a(struct rtw_adapter *padapter, struct mlme_ext_priv *pmlmeext); struct cmd_hdl { uint parmsize; - u8 (*h2cfuns)(struct rtw_adapter *padapter, u8 *pbuf); + u8 (*h2cfuns)(struct rtw_adapter *padapter, const u8 *pbuf); }; @@ -697,27 +652,27 @@ u8 read_rfreg_hdl(struct rtw_adapter *padapter, u8 *pbuf); u8 write_rfreg_hdl(struct rtw_adapter *padapter, u8 *pbuf); -u8 NULL_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); -u8 join_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); -u8 disconnect_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); -u8 createbss_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); -u8 setopmode_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); -u8 sitesurvey_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); -u8 setauth_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); -u8 setkey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); -u8 set_stakey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); -u8 set_assocsta_hdl(struct rtw_adapter *padapter, u8 *pbuf); -u8 del_assocsta_hdl(struct rtw_adapter *padapter, u8 *pbuf); -u8 add_ba_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); - -u8 mlme_evt_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); -u8 h2c_msg_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); -u8 tx_beacon_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); -u8 set_ch_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); -u8 set_chplan_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); -u8 led_blink_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); -u8 set_csa_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); /* Kurt: Handling DFS channel switch announcement ie. */ -u8 tdls_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); +u8 NULL_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 join_cmd_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 disconnect_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 createbss_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 setopmode_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 sitesurvey_cmd_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 setauth_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 setkey_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 set_stakey_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 set_assocsta_hdl(struct rtw_adapter *padapter, const u8 *pbuf); +u8 del_assocsta_hdl(struct rtw_adapter *padapter, const u8 *pbuf); +u8 add_ba_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); + +u8 mlme_evt_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 h2c_msg_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 tx_beacon_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 set_ch_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 set_chplan_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 led_blink_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); +u8 set_csa_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); /* Kurt: Handling DFS channel switch announcement ie. */ +u8 tdls_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf); #define GEN_DRV_CMD_HANDLER(size, cmd) {size, &cmd ## _hdl23a}, #define GEN_MLME_EXT_HANDLER(size, cmd) {size, cmd}, diff --git a/drivers/staging/rtl8723au/include/rtw_p2p.h b/drivers/staging/rtl8723au/include/rtw_p2p.h deleted file mode 100644 index 93fdc658ff4dc6..00000000000000 --- a/drivers/staging/rtl8723au/include/rtw_p2p.h +++ /dev/null @@ -1,158 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. - * - * 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, 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. - * - ******************************************************************************/ -#ifndef __RTW_P2P_H_ -#define __RTW_P2P_H_ - -#include - -u32 build_beacon_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf); -u32 build_probe_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf); -u32 build_prov_disc_request_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, - u8 *pssid, u8 ussidlen, u8 *pdev_raddr); -u32 build_assoc_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, - u8 status_code); -u32 build_deauth_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf); -#ifdef CONFIG_8723AU_P2P -u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); -u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, - u8 tunneled); -u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); -u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); -u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); -u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); -u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); -u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); -u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); -u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); -u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); -u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); -#endif /* CONFIG_8723AU_P2P */ - -u32 process_probe_req_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pframe, - uint len); -u32 process_assoc_req_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pframe, - uint len, struct sta_info *psta); -u32 process_p2p_devdisc_req23a(struct wifidirect_info *pwdinfo, u8 *pframe, - uint len); -u32 process_p2p_devdisc_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe, - uint len); -u8 process_p2p_provdisc_req23a(struct wifidirect_info *pwdinfo, u8 *pframe, - uint len); -u8 process_p2p_provdisc_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe); -u8 process_p2p_group_negotation_req23a(struct wifidirect_info *pwdinfo, - u8 *pframe, uint len); -u8 process_p2p_group_negotation_resp23a(struct wifidirect_info *pwdinfo, - u8 *pframe, uint len); -u8 process_p2p_group_negotation_confirm23a(struct wifidirect_info *pwdinfo, - u8 *pframe, uint len); -u8 process_p2p_presence_req23a(struct wifidirect_info *pwdinfo, - u8 *pframe, uint len); - -void p2p_protocol_wk_hdl23a(struct rtw_adapter *padapter, int cmdtype); - -#ifdef CONFIG_8723AU_P2P -void process_p2p_ps_ie23a(struct rtw_adapter *padapter, u8 *IEs, u32 IELength); -void p2p_ps_wk_hdl23a(struct rtw_adapter *padapter, u8 p2p_ps_state); -u8 p2p_ps_wk_cmd23a(struct rtw_adapter *padapter, u8 p2p_ps_state, u8 enqueue); -#endif /* CONFIG_8723AU_P2P */ - -void rtw_init_cfg80211_wifidirect_info(struct rtw_adapter *padapter); -int rtw_p2p_check_frames(struct rtw_adapter *padapter, const u8 *buf, - u32 len, u8 tx); -void rtw_append_wfd_ie(struct rtw_adapter *padapter, u8 *buf, u32 *len); - -void reset_global_wifidirect_info23a(struct rtw_adapter *padapter); -int rtw_init_wifi_display_info(struct rtw_adapter *padapter); -void rtw_init_wifidirect_timers23a(struct rtw_adapter *padapter); -void rtw_init_wifidirect_addrs23a(struct rtw_adapter *padapter, u8 *dev_addr, - u8 *iface_addr); -void init_wifidirect_info23a(struct rtw_adapter *padapter, enum P2P_ROLE role); -int rtw_p2p_enable23a(struct rtw_adapter *padapter, enum P2P_ROLE role); - -static inline void _rtw_p2p_set_state(struct wifidirect_info *wdinfo, - enum P2P_STATE state) -{ - if (wdinfo->p2p_state != state) { - /* wdinfo->pre_p2p_state = wdinfo->p2p_state; */ - wdinfo->p2p_state = state; - } -} - -static inline void _rtw_p2p_set_pre_state(struct wifidirect_info *wdinfo, - enum P2P_STATE state) -{ - if (wdinfo->pre_p2p_state != state) - wdinfo->pre_p2p_state = state; -} - -static inline void _rtw_p2p_set_role(struct wifidirect_info *wdinfo, - enum P2P_ROLE role) -{ - if (wdinfo->role != role) - wdinfo->role = role; -} - -static inline int _rtw_p2p_state(struct wifidirect_info *wdinfo) -{ - return wdinfo->p2p_state; -} - -static inline int _rtw_p2p_pre_state(struct wifidirect_info *wdinfo) -{ - return wdinfo->pre_p2p_state; -} - -static inline int _rtw_p2p_role(struct wifidirect_info *wdinfo) -{ - return wdinfo->role; -} - -static inline bool _rtw_p2p_chk_state(struct wifidirect_info *wdinfo, - enum P2P_STATE state) -{ - return wdinfo->p2p_state == state; -} - -static inline bool _rtw_p2p_chk_role(struct wifidirect_info *wdinfo, - enum P2P_ROLE role) -{ - return wdinfo->role == role; -} - -#define rtw_p2p_set_state(wdinfo, state) _rtw_p2p_set_state(wdinfo, state) -#define rtw_p2p_set_pre_state(wdinfo, state) \ - _rtw_p2p_set_pre_state(wdinfo, state) -#define rtw_p2p_set_role(wdinfo, role) _rtw_p2p_set_role(wdinfo, role) - -#define rtw_p2p_state(wdinfo) _rtw_p2p_state(wdinfo) -#define rtw_p2p_pre_state(wdinfo) _rtw_p2p_pre_state(wdinfo) -#define rtw_p2p_role(wdinfo) _rtw_p2p_role(wdinfo) -#define rtw_p2p_chk_state(wdinfo, state) _rtw_p2p_chk_state(wdinfo, state) -#define rtw_p2p_chk_role(wdinfo, role) _rtw_p2p_chk_role(wdinfo, role) - -#define rtw_p2p_findphase_ex_set(wdinfo, value) \ - ((wdinfo)->find_phase_state_exchange_cnt = (value)) - -/* is this find phase exchange for social channel scan? */ -#define rtw_p2p_findphase_ex_is_social(wdinfo) \ - ((wdinfo)->find_phase_state_exchange_cnt >= \ - P2P_FINDPHASE_EX_SOCIAL_FIRST) - -/* should we need find phase exchange anymore? */ -#define rtw_p2p_findphase_ex_is_needed(wdinfo) \ - ((wdinfo)->find_phase_state_exchange_cnt < P2P_FINDPHASE_EX_MAX && \ - (wdinfo)->find_phase_state_exchange_cnt != P2P_FINDPHASE_EX_NONE) - -#endif diff --git a/drivers/staging/rtl8723au/include/rtw_pwrctrl.h b/drivers/staging/rtl8723au/include/rtw_pwrctrl.h index e0da87d4d3d6a4..44a7d4f97e0947 100644 --- a/drivers/staging/rtl8723au/include/rtw_pwrctrl.h +++ b/drivers/staging/rtl8723au/include/rtw_pwrctrl.h @@ -165,7 +165,6 @@ struct pwrctrl_priv { struct work_struct cpwm_event; u8 bpower_saving; - u8 b_hw_radio_off; u8 reg_rfoff; u8 reg_pdnmode; /* powerdown mode */ u32 rfoff_reason; @@ -250,8 +249,6 @@ s32 LPS_RF_ON_check23a(struct rtw_adapter *padapter, u32 delay_ms); void LPS_Enter23a(struct rtw_adapter *padapter); void LPS_Leave23a(struct rtw_adapter *padapter); -u8 rtw_interface_ps_func23a(struct rtw_adapter *padapter, - enum hal_intf_ps_func efunc_id, u8 *val); void rtw_set_ips_deny23a(struct rtw_adapter *padapter, u32 ms); int _rtw_pwr_wakeup23a(struct rtw_adapter *padapter, u32 ips_deffer_ms, const char *caller); diff --git a/drivers/staging/rtl8723au/include/rtw_recv.h b/drivers/staging/rtl8723au/include/rtw_recv.h index d1866a6e831f47..1f18af8dcc040a 100644 --- a/drivers/staging/rtl8723au/include/rtw_recv.h +++ b/drivers/staging/rtl8723au/include/rtw_recv.h @@ -152,12 +152,12 @@ struct rx_pkt_attrib { #define RXDESC_OFFSET RXDESC_SIZE struct recv_stat { - unsigned int rxdw0; - unsigned int rxdw1; - unsigned int rxdw2; - unsigned int rxdw3; - unsigned int rxdw4; - unsigned int rxdw5; + __le32 rxdw0; + __le32 rxdw1; + __le32 rxdw2; + __le32 rxdw3; + __le32 rxdw4; + __le32 rxdw5; }; /* accesser of recv_priv: rtw_recv_entry23a(dispatch / passive level); \ diff --git a/drivers/staging/rtl8723au/include/rtw_security.h b/drivers/staging/rtl8723au/include/rtw_security.h index 75bbb934a53cf2..702dd845a3ff03 100644 --- a/drivers/staging/rtl8723au/include/rtw_security.h +++ b/drivers/staging/rtl8723au/include/rtw_security.h @@ -30,7 +30,6 @@ #define is_wep_enc(alg) (((alg) == _WEP40_) || ((alg) == _WEP104_)) -#define _WPA_IE_ID_ 0xdd #define _WPA2_IE_ID_ 0x30 #define SHA256_MAC_LEN 32 @@ -316,22 +315,6 @@ static const unsigned long K[64] = { 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; -/* Various logical functions */ -#define RORc(x, y) \ -(((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ -((unsigned long)(x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) -#define Ch(x, y, z) (z ^ (x & (y ^ z))) -#define Maj(x, y, z) (((x | y) & z) | (x & y)) -#define S(x, n) RORc((x), (n)) -#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) -#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) -#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) -#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) -#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) -#ifndef MIN -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) -#endif - void rtw_secmicsetkey23a(struct mic_data *pmicdata, u8 *key); void rtw_secmicappend23abyte23a(struct mic_data *pmicdata, u8 b); void rtw_secmicappend23a(struct mic_data *pmicdata, u8 *src, u32 nbBytes); diff --git a/drivers/staging/rtl8723au/include/rtw_xmit.h b/drivers/staging/rtl8723au/include/rtw_xmit.h index 65a33a07c8ee27..5b879764518f1c 100644 --- a/drivers/staging/rtl8723au/include/rtw_xmit.h +++ b/drivers/staging/rtl8723au/include/rtw_xmit.h @@ -92,14 +92,14 @@ do { \ struct tx_desc { /* DWORD 0 */ - unsigned int txdw0; - unsigned int txdw1; - unsigned int txdw2; - unsigned int txdw3; - unsigned int txdw4; - unsigned int txdw5; - unsigned int txdw6; - unsigned int txdw7; + __le32 txdw0; + __le32 txdw1; + __le32 txdw2; + __le32 txdw3; + __le32 txdw4; + __le32 txdw5; + __le32 txdw6; + __le32 txdw7; }; union txdesc { diff --git a/drivers/staging/rtl8723au/include/sta_info.h b/drivers/staging/rtl8723au/include/sta_info.h index ffbc9e3f2156f9..c02947f6bd9b37 100644 --- a/drivers/staging/rtl8723au/include/sta_info.h +++ b/drivers/staging/rtl8723au/include/sta_info.h @@ -349,7 +349,7 @@ struct sta_priv { struct wlan_acl_pool acl_list; }; -static inline u32 wifi_mac_hash(u8 *mac) +static inline u32 wifi_mac_hash(const u8 *mac) { u32 x; @@ -377,7 +377,7 @@ struct sta_info *rtw_get_stainfo23a_by_offset23a(struct sta_priv *stapriv, struct sta_info *rtw_alloc_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr); u32 rtw_free_stainfo23a(struct rtw_adapter *padapter, struct sta_info *psta); void rtw_free_all_stainfo23a(struct rtw_adapter *padapter); -struct sta_info *rtw_get_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr); +struct sta_info *rtw_get_stainfo23a(struct sta_priv *pstapriv, const u8 *hwaddr); u32 rtw_init_bcmc_stainfo23a(struct rtw_adapter *padapter); struct sta_info *rtw_get_bcmc_stainfo23a(struct rtw_adapter *padapter); u8 rtw_access_ctrl23a(struct rtw_adapter *padapter, u8 *mac_addr); diff --git a/drivers/staging/rtl8723au/include/usb_ops.h b/drivers/staging/rtl8723au/include/usb_ops.h index 55d1380f903686..1013406c9c77de 100644 --- a/drivers/staging/rtl8723au/include/usb_ops.h +++ b/drivers/staging/rtl8723au/include/usb_ops.h @@ -45,8 +45,7 @@ enum { void rtl8723au_set_hw_type(struct rtw_adapter *padapter); #define hal_set_hw_type rtl8723au_set_hw_type -void rtl8723au_set_intf_ops(struct _io_ops *pops); -#define usb_set_intf_ops rtl8723au_set_intf_ops +void rtl8723au_set_intf_ops(struct rtw_adapter *padapter); void rtl8723au_recv_tasklet(void *priv); diff --git a/drivers/staging/rtl8723au/include/usb_ops_linux.h b/drivers/staging/rtl8723au/include/usb_ops_linux.h index 8f5c59eace5a18..0eb33e01c78c79 100644 --- a/drivers/staging/rtl8723au/include/usb_ops_linux.h +++ b/drivers/staging/rtl8723au/include/usb_ops_linux.h @@ -34,13 +34,13 @@ unsigned int ffaddr2pipehdl23a(struct dvobj_priv *pdvobj, u32 addr); -void usb_read_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem); -void usb_write_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem); +void usb_read_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *rmem); +void usb_write_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *wmem); -void usb_read_port_cancel23a(struct intf_hdl *pintfhdl); +void usb_read_port_cancel23a(struct rtw_adapter *adapter); -u32 usb_write_port23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, - struct xmit_buf *wmem); -void usb_write_port23a_cancel(struct intf_hdl *pintfhdl); +u32 usb_write_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, + struct xmit_buf *wmem); +void usb_write_port23a_cancel(struct rtw_adapter *adapter); #endif diff --git a/drivers/staging/rtl8723au/include/wifi.h b/drivers/staging/rtl8723au/include/wifi.h index b5034c6ef1dc7d..aebc05d8a1235e 100644 --- a/drivers/staging/rtl8723au/include/wifi.h +++ b/drivers/staging/rtl8723au/include/wifi.h @@ -82,42 +82,42 @@ enum WIFI_REG_DOMAIN { #define SetToDs(pbuf) \ - (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_TODS)) + (*(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_TODS)) #define SetFrDs(pbuf) \ - (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_FROMDS)) + (*(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_FROMDS)) #define get_tofr_ds(pframe) ((ieee80211_has_tods(pframe) << 1) | \ ieee80211_has_fromds(pframe)) #define SetMFrag(pbuf) \ - (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) + (*(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) #define ClearMFrag(pbuf) \ - (*(unsigned short *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_MOREFRAGS))) + (*(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_MOREFRAGS))) #define SetRetry(pbuf) \ - (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_RETRY)) + (*(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_RETRY)) #define SetPwrMgt(pbuf) \ - (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_PM)) + (*(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_PM)) #define SetMData(pbuf) \ - (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_MOREDATA)) + (*(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_MOREDATA)) #define SetPrivacy(pbuf) \ - (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_PROTECTED)) + (*(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_PROTECTED)) #define SetFrameType(pbuf, type) \ do { \ - *(unsigned short *)(pbuf) &= __constant_cpu_to_le16(~(BIT(3) | BIT(2))); \ - *(unsigned short *)(pbuf) |= __constant_cpu_to_le16(type); \ + *(__le16 *)(pbuf) &= __constant_cpu_to_le16(~(BIT(3) | BIT(2))); \ + *(__le16 *)(pbuf) |= __constant_cpu_to_le16(type); \ } while (0) #define SetFrameSubType(pbuf, type) \ do { \ - *(unsigned short *)(pbuf) &= cpu_to_le16(~(BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2))); \ - *(unsigned short *)(pbuf) |= cpu_to_le16(type); \ + *(__le16 *)(pbuf) &= cpu_to_le16(~(BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2))); \ + *(__le16 *)(pbuf) |= cpu_to_le16(type); \ } while (0) #define GetTupleCache(pbuf) (cpu_to_le16(*(unsigned short *)((unsigned long)(pbuf) + 22))) @@ -131,26 +131,26 @@ enum WIFI_REG_DOMAIN { #define SetSeqNum(pbuf, num) \ do { \ - *(unsigned short *)((unsigned long)(pbuf) + 22) = \ - ((*(unsigned short *)((unsigned long)(pbuf) + 22)) & le16_to_cpu((unsigned short)0x000f)) | \ - le16_to_cpu((unsigned short)(0xfff0 & (num << 4))); \ + *(__le16 *)((size_t)(pbuf) + 22) = \ + ((*(__le16 *)((size_t)(pbuf) + 22)) & cpu_to_le16((unsigned short)0x000f)) | \ + cpu_to_le16((unsigned short)(0xfff0 & (num << 4))); \ } while (0) #define SetDuration(pbuf, dur) \ - (*(unsigned short *)((unsigned long)(pbuf) + 2) = \ + (*(__le16 *)((unsigned long)(pbuf) + 2) = \ cpu_to_le16(0xffff & (dur))) #define SetPriority(pbuf, tid) \ - (*(unsigned short *)(pbuf) |= cpu_to_le16(tid & 0xf)) + (*(__le16 *)(pbuf) |= cpu_to_le16(tid & 0xf)) #define SetEOSP(pbuf, eosp) \ - (*(unsigned short *)(pbuf) |= cpu_to_le16((eosp & 1) << 4)) + (*(__le16 *)(pbuf) |= cpu_to_le16((eosp & 1) << 4)) #define SetAckpolicy(pbuf, ack) \ - (*(unsigned short *)(pbuf) |= cpu_to_le16((ack & 3) << 5)) + (*(__le16 *)(pbuf) |= cpu_to_le16((ack & 3) << 5)) #define SetAMsdu(pbuf, amsdu) \ - (*(unsigned short *)(pbuf) |= cpu_to_le16((amsdu & 1) << 7)) + (*(__le16 *)(pbuf) |= cpu_to_le16((amsdu & 1) << 7)) #define GetAid(pbuf) \ (cpu_to_le16(*(unsigned short *)((unsigned long)(pbuf) + 2)) & \ @@ -219,39 +219,8 @@ static inline unsigned char *get_hdr_bssid(unsigned char *pframe) #define _FIXED_IE_LENGTH_ _BEACON_IE_OFFSET_ -#define _SSID_IE_ 0 -#define _SUPPORTEDRATES_IE_ 1 -#define _DSSET_IE_ 3 -#define _TIM_IE_ 5 -#define _IBSS_PARA_IE_ 6 -#define _COUNTRY_IE_ 7 -#define _CHLGETXT_IE_ 16 -#define _SUPPORTED_CH_IE_ 36 -#define _CH_SWTICH_ANNOUNCE_ 37 /* Secondary Channel Offset */ -#define _RSN_IE_2_ 48 -#define _SSN_IE_1_ 221 -#define _ERPINFO_IE_ 42 -#define _EXT_SUPPORTEDRATES_IE_ 50 - -#define _HT_CAPABILITY_IE_ 45 -#define _FTIE_ 55 -#define _TIMEOUT_ITVL_IE_ 56 -#define _SRC_IE_ 59 -#define _HT_EXTRA_INFO_IE_ 61 -#define _HT_ADD_INFO_IE_ 61 /* _HT_EXTRA_INFO_IE_ */ - - -#define EID_BSSCoexistence 72 /* 20/40 BSS Coexistence */ -#define EID_BSSIntolerantChlReport 73 -#define _RIC_Descriptor_IE_ 75 - -#define _LINK_ID_IE_ 101 -#define _CH_SWITCH_TIMING_ 104 -#define _PTI_BUFFER_STATUS_ 106 -#define _EXT_CAP_IE_ 127 -#define _VENDOR_SPECIFIC_IE_ 221 -#define _RESERVED47_ 47 +#define EID_BSSIntolerantChlReport 73 /* --------------------------------------------------------------------------- Below is the fixed elements... @@ -490,72 +459,6 @@ struct ADDBA_request { #define WPS_ASSOC_STATE_ASSOCIATION_FAILURE 0x03 #define WPS_ASSOC_STATE_IP_FAILURE 0x04 -/* =====================P2P Section===================== */ -/* For P2P */ -#define P2POUI 0x506F9A09 - -/* P2P Attribute ID */ -#define P2P_ATTR_STATUS 0x00 -#define P2P_ATTR_MINOR_REASON_CODE 0x01 -#define P2P_ATTR_CAPABILITY 0x02 -#define P2P_ATTR_DEVICE_ID 0x03 -#define P2P_ATTR_GO_INTENT 0x04 -#define P2P_ATTR_CONF_TIMEOUT 0x05 -#define P2P_ATTR_LISTEN_CH 0x06 -#define P2P_ATTR_GROUP_BSSID 0x07 -#define P2P_ATTR_EX_LISTEN_TIMING 0x08 -#define P2P_ATTR_INTENTED_IF_ADDR 0x09 -#define P2P_ATTR_MANAGEABILITY 0x0A -#define P2P_ATTR_CH_LIST 0x0B -#define P2P_ATTR_NOA 0x0C -#define P2P_ATTR_DEVICE_INFO 0x0D -#define P2P_ATTR_GROUP_INFO 0x0E -#define P2P_ATTR_GROUP_ID 0x0F -#define P2P_ATTR_INTERFACE 0x10 -#define P2P_ATTR_OPERATING_CH 0x11 -#define P2P_ATTR_INVITATION_FLAGS 0x12 - -/* Value of Status Attribute */ -#define P2P_STATUS_SUCCESS 0x00 -#define P2P_STATUS_FAIL_INFO_UNAVAILABLE 0x01 -#define P2P_STATUS_FAIL_INCOMPATIBLE_PARAM 0x02 -#define P2P_STATUS_FAIL_LIMIT_REACHED 0x03 -#define P2P_STATUS_FAIL_INVALID_PARAM 0x04 -#define P2P_STATUS_FAIL_REQUEST_UNABLE 0x05 -#define P2P_STATUS_FAIL_PREVOUS_PROTO_ERR 0x06 -#define P2P_STATUS_FAIL_NO_COMMON_CH 0x07 -#define P2P_STATUS_FAIL_UNKNOWN_P2PGROUP 0x08 -#define P2P_STATUS_FAIL_BOTH_GOINTENT_15 0x09 -#define P2P_STATUS_FAIL_INCOMPATIBLE_PROVSION 0x0A -#define P2P_STATUS_FAIL_USER_REJECT 0x0B - -/* Value of Inviation Flags Attribute */ -#define P2P_INVITATION_FLAGS_PERSISTENT BIT(0) - -#define DMP_P2P_DEVCAP_SUPPORT (P2P_DEVCAP_SERVICE_DISCOVERY | \ - P2P_DEVCAP_CLIENT_DISCOVERABILITY | \ - P2P_DEVCAP_CONCURRENT_OPERATION | \ - P2P_DEVCAP_INVITATION_PROC) - -#define DMP_P2P_GRPCAP_SUPPORT (P2P_GRPCAP_INTRABSS) - -/* Value of Device Capability Bitmap */ -#define P2P_DEVCAP_SERVICE_DISCOVERY BIT(0) -#define P2P_DEVCAP_CLIENT_DISCOVERABILITY BIT(1) -#define P2P_DEVCAP_CONCURRENT_OPERATION BIT(2) -#define P2P_DEVCAP_INFRA_MANAGED BIT(3) -#define P2P_DEVCAP_DEVICE_LIMIT BIT(4) -#define P2P_DEVCAP_INVITATION_PROC BIT(5) - -/* Value of Group Capability Bitmap */ -#define P2P_GRPCAP_GO BIT(0) -#define P2P_GRPCAP_PERSISTENT_GROUP BIT(1) -#define P2P_GRPCAP_GROUP_LIMIT BIT(2) -#define P2P_GRPCAP_INTRABSS BIT(3) -#define P2P_GRPCAP_CROSS_CONN BIT(4) -#define P2P_GRPCAP_PERSISTENT_RECONN BIT(5) -#define P2P_GRPCAP_GROUP_FORMATION BIT(6) - /* P2P Public Action Frame ( Management Frame ) */ #define P2P_PUB_ACTION_ACTION 0x09 @@ -570,37 +473,6 @@ struct ADDBA_request { #define P2P_PROVISION_DISC_REQ 7 #define P2P_PROVISION_DISC_RESP 8 -/* P2P Action Frame Type */ -#define P2P_NOTICE_OF_ABSENCE 0 -#define P2P_PRESENCE_REQUEST 1 -#define P2P_PRESENCE_RESPONSE 2 -#define P2P_GO_DISC_REQUEST 3 - - -#define P2P_MAX_PERSISTENT_GROUP_NUM 10 - -#define P2P_PROVISIONING_SCAN_CNT 3 - -#define P2P_WILDCARD_SSID_LEN 7 - -#define P2P_FINDPHASE_EX_NONE 0 /* default value, used when: (1)p2p disabed or (2)p2p enabled but only do 1 scan phase */ -#define P2P_FINDPHASE_EX_FULL 1 /* used when p2p enabled and want to do 1 scan phase and P2P_FINDPHASE_EX_MAX-1 find phase */ -#define P2P_FINDPHASE_EX_SOCIAL_FIRST (P2P_FINDPHASE_EX_FULL+1) -#define P2P_FINDPHASE_EX_MAX 4 -#define P2P_FINDPHASE_EX_SOCIAL_LAST P2P_FINDPHASE_EX_MAX - -#define P2P_PROVISION_TIMEOUT 5000 /*5 sec timeout for sending the provision discovery request */ -#define P2P_CONCURRENT_PROVISION_TIMEOUT 3000 /*3 sec timeout for sending the provision discovery request under concurrent mode */ -#define P2P_GO_NEGO_TIMEOUT 5000 /*5 sec timeout for receiving the group negotation response */ -#define P2P_CONCURRENT_GO_NEGO_TIMEOUT 3000 /*3 sec timeout for sending the negotiation request under concurrent mode */ -#define P2P_TX_PRESCAN_TIMEOUT 100 /*100ms */ -#define P2P_INVITE_TIMEOUT 5000 /*5 sec timeout for sending the invitation request */ -#define P2P_CONCURRENT_INVITE_TIMEOUT 3000 /*3 sec timeout for sending the invitation request under concurrent mode */ -#define P2P_RESET_SCAN_CH 25000 /*25 sec t/o to reset the scan channel ( based on channel plan ) */ -#define P2P_MAX_INTENT 15 - -#define P2P_MAX_NOA_NUM 2 - /* WPS Configuration Method */ #define WPS_CM_NONE 0x0000 #define WPS_CM_LABEL 0x0004 @@ -615,93 +487,4 @@ struct ADDBA_request { #define WPS_CM_SW_DISPLAY_PIN 0x2008 #define WPS_CM_LCD_DISPLAY_PIN 0x4008 -enum P2P_ROLE { - P2P_ROLE_DISABLE = 0, - P2P_ROLE_DEVICE = 1, - P2P_ROLE_CLIENT = 2, - P2P_ROLE_GO = 3 -}; - -enum P2P_STATE { - P2P_STATE_NONE = 0, /*P2P disable */ - P2P_STATE_IDLE = 1, /*P2P had enabled and do nothing */ - P2P_STATE_LISTEN = 2, /*In pure listen state */ - P2P_STATE_SCAN = 3, /*In scan phase */ - P2P_STATE_FIND_PHASE_LISTEN = 4, /*In the listen state of find phase */ - P2P_STATE_FIND_PHASE_SEARCH = 5, /*In the search state of find phase */ - P2P_STATE_TX_PROVISION_DIS_REQ = 6, /*In P2P provisioning discovery */ - P2P_STATE_RX_PROVISION_DIS_RSP = 7, - P2P_STATE_RX_PROVISION_DIS_REQ = 8, - P2P_STATE_GONEGO_ING = 9, /*Doing the group owner negoitation handshake */ - P2P_STATE_GONEGO_OK = 10, /*finish the group negoitation handshake with success */ - P2P_STATE_GONEGO_FAIL = 11, /*finish the group negoitation handshake with failure */ - P2P_STATE_RECV_INVITE_REQ_MATCH = 12, /*receiving the P2P Inviation request and match with the profile. */ - P2P_STATE_PROVISIONING_ING = 13, /*Doing the P2P WPS */ - P2P_STATE_PROVISIONING_DONE = 14, /*Finish the P2P WPS */ - P2P_STATE_TX_INVITE_REQ = 15, /*Transmit the P2P Invitation request */ - P2P_STATE_RX_INVITE_RESP_OK = 16, /*Receiving the P2P Invitation response */ - P2P_STATE_RECV_INVITE_REQ_DISMATCH = 17,/*receiving the P2P Inviation request and dismatch with the profile. */ - P2P_STATE_RECV_INVITE_REQ_GO = 18, /*receiving the P2P Inviation request and this wifi is GO. */ - P2P_STATE_RECV_INVITE_REQ_JOIN = 19, /*receiving the P2P Inviation request to join an existing P2P Group. */ - P2P_STATE_RX_INVITE_RESP_FAIL = 20, /*receiving the P2P Inviation response with failure */ - P2P_STATE_RX_INFOR_NOREADY = 21, /*receiving p2p negotiation response with information is not available */ - P2P_STATE_TX_INFOR_NOREADY = 22, /*sending p2p negotiation response with information is not available */ -}; - -enum P2P_WPSINFO { - P2P_NO_WPSINFO = 0, - P2P_GOT_WPSINFO_PEER_DISPLAY_PIN = 1, - P2P_GOT_WPSINFO_SELF_DISPLAY_PIN = 2, - P2P_GOT_WPSINFO_PBC = 3, -}; - -#define P2P_PRIVATE_IOCTL_SET_LEN 64 - -enum P2P_PROTO_WK_ID { - P2P_FIND_PHASE_WK = 0, - P2P_RESTORE_STATE_WK = 1, - P2P_PRE_TX_PROVDISC_PROCESS_WK = 2, - P2P_PRE_TX_NEGOREQ_PROCESS_WK = 3, - P2P_PRE_TX_INVITEREQ_PROCESS_WK = 4, - P2P_AP_P2P_CH_SWITCH_PROCESS_WK = 5, - P2P_RO_CH_WK = 6, -}; - -#ifdef CONFIG_8723AU_P2P -enum P2P_PS_STATE { - P2P_PS_DISABLE = 0, - P2P_PS_ENABLE = 1, - P2P_PS_SCAN = 2, - P2P_PS_SCAN_DONE = 3, - P2P_PS_ALLSTASLEEP = 4, /* for P2P GO */ -}; - -enum P2P_PS_MODE { - P2P_PS_NONE = 0, - P2P_PS_CTWINDOW = 1, - P2P_PS_NOA = 2, - P2P_PS_MIX = 3, /* CTWindow and NoA */ -}; -#endif /* CONFIG_8723AU_P2P */ - -/* =====================WFD Section===================== */ -/* For Wi-Fi Display */ -#define WFD_ATTR_DEVICE_INFO 0x00 -#define WFD_ATTR_ASSOC_BSSID 0x01 -#define WFD_ATTR_COUPLED_SINK_INFO 0x06 -#define WFD_ATTR_LOCAL_IP_ADDR 0x08 -#define WFD_ATTR_SESSION_INFO 0x09 -#define WFD_ATTR_ALTER_MAC 0x0a - -/* For WFD Device Information Attribute */ -#define WFD_DEVINFO_SOURCE 0x0000 -#define WFD_DEVINFO_PSINK 0x0001 -#define WFD_DEVINFO_SSINK 0x0002 -#define WFD_DEVINFO_DUAL 0x0003 - -#define WFD_DEVINFO_SESSION_AVAIL 0x0010 -#define WFD_DEVINFO_WSD 0x0040 -#define WFD_DEVINFO_PC_TDLS 0x0080 -#define WFD_DEVINFO_HDCP_SUPPORT 0x0100 - #endif /* _WIFI_H_ */ diff --git a/drivers/staging/rtl8723au/include/xmit_osdep.h b/drivers/staging/rtl8723au/include/xmit_osdep.h index 0eca53ece75d4f..2be04c48656c45 100644 --- a/drivers/staging/rtl8723au/include/xmit_osdep.h +++ b/drivers/staging/rtl8723au/include/xmit_osdep.h @@ -18,24 +18,9 @@ #include #include -struct pkt_file { - struct sk_buff *pkt; - __kernel_size_t pkt_len; /* the remainder length of the open_file */ - unsigned char *cur_buffer; - u8 *buf_start; - u8 *cur_addr; - __kernel_size_t buf_len; -}; - #define NR_XMITFRAME 256 -struct xmit_priv; -struct pkt_attrib; -struct sta_xmit_priv; -struct xmit_frame; -struct xmit_buf; - int rtw_xmit23a_entry23a(struct sk_buff *pkt, struct net_device *pnetdev); void rtw_os_xmit_schedule23a(struct rtw_adapter *padapter); @@ -44,10 +29,6 @@ int rtw_os_xmit_resource_alloc23a(struct rtw_adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz); void rtw_os_xmit_resource_free23a(struct rtw_adapter *padapter, struct xmit_buf *pxmitbuf); -uint rtw_remainder_len23a(struct pkt_file *pfile); -void _rtw_open_pktfile23a(struct sk_buff *pkt, struct pkt_file *pfile); -uint _rtw_pktfile_read23a(struct pkt_file *pfile, u8 *rmem, uint rlen); -int rtw_endofpktfile23a(struct pkt_file *pfile); void rtw_os_pkt_complete23a(struct rtw_adapter *padapter, struct sk_buff *pkt); void rtw_os_xmit_complete23a(struct rtw_adapter *padapter, diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c index 50840b9a11fa06..ca100dcc27631d 100644 --- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c @@ -260,10 +260,9 @@ static int rtw_cfg80211_inform_bss(struct rtw_adapter *padapter, size_t notify_ielen; s32 notify_signal; u8 buf[MAX_BSSINFO_LEN], *pbuf; - size_t len, bssinf_len = 0; + size_t len; struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; - u8 bc_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + __le16 *fctrl; struct wireless_dev *wdev = padapter->rtw_wdev; struct wiphy *wiphy = wdev->wiphy; @@ -271,11 +270,9 @@ static int rtw_cfg80211_inform_bss(struct rtw_adapter *padapter, /* DBG_8723A("%s\n", __func__); */ - bssinf_len = - pnetwork->network.IELength + sizeof(struct ieee80211_hdr_3addr); - if (bssinf_len > MAX_BSSINFO_LEN) { + if (pnetwork->network.IELength > MAX_IE_SZ) { DBG_8723A("%s IE Length too long > %d byte\n", __func__, - MAX_BSSINFO_LEN); + MAX_IE_SZ); goto exit; } @@ -289,14 +286,13 @@ static int rtw_cfg80211_inform_bss(struct rtw_adapter *padapter, notify_channel = ieee80211_get_channel(wiphy, freq); - /* rtw_get_timestampe_from_ie23a() */ notify_timestamp = jiffies_to_msecs(jiffies) * 1000; /* uSec */ notify_interval = le16_to_cpu(*(u16 *) rtw_get_beacon_interval23a_from_ie(pnetwork->network.IEs)); notify_capability = - le16_to_cpu(*(u16 *) + get_unaligned_le16( rtw_get_capability23a_from_ie(pnetwork->network.IEs)); notify_ie = pnetwork->network.IEs + _FIXED_IE_LENGTH_; @@ -321,7 +317,7 @@ static int rtw_cfg80211_inform_bss(struct rtw_adapter *padapter, SetSeqNum(pwlanhdr, 0); if (pnetwork->network.reserved == 1) { /* WIFI_BEACON */ - memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + eth_broadcast_addr(pwlanhdr->addr1); SetFrameSubType(pbuf, WIFI_BEACON); } else { memcpy(pwlanhdr->addr1, myid(&padapter->eeprompriv), ETH_ALEN); @@ -357,9 +353,6 @@ void rtw_cfg80211_indicate_connect(struct rtw_adapter *padapter) struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_network *cur_network = &pmlmepriv->cur_network; struct wireless_dev *pwdev = padapter->rtw_wdev; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif DBG_8723A("%s(padapter =%p)\n", __func__, padapter); @@ -370,18 +363,7 @@ void rtw_cfg80211_indicate_connect(struct rtw_adapter *padapter) if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) return; -#ifdef CONFIG_8723AU_P2P - if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { - rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); - rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); - DBG_8723A("%s, role =%d, p2p_state =%d, pre_p2p_state =%d\n", - __func__, rtw_p2p_role(pwdinfo), - rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo)); - } -#endif /* CONFIG_8723AU_P2P */ - - if (rtw_to_roaming(padapter) > 0) { + if (padapter->mlmepriv.to_roaming > 0) { struct wiphy *wiphy = pwdev->wiphy; struct ieee80211_channel *notify_channel; u32 freq; @@ -429,9 +411,6 @@ void rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wireless_dev *pwdev = padapter->rtw_wdev; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif DBG_8723A("%s(padapter =%p)\n", __func__, padapter); @@ -442,21 +421,6 @@ void rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter) if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) return; -#ifdef CONFIG_8723AU_P2P - if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { - del_timer_sync(&pwdinfo->find_phase_timer); - del_timer_sync(&pwdinfo->restore_p2p_state_timer); - del_timer_sync(&pwdinfo->pre_tx_scan_timer); - - rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - - DBG_8723A("%s, role =%d, p2p_state =%d, pre_p2p_state =%d\n", - __func__, rtw_p2p_role(pwdinfo), - rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo)); - } -#endif /* CONFIG_8723AU_P2P */ - if (!padapter->mlmepriv.not_indic_disco) { if (check_fwstate(&padapter->mlmepriv, WIFI_UNDER_LINKING)) { cfg80211_connect_result(padapter->pnetdev, NULL, NULL, @@ -558,8 +522,6 @@ static int set_group_key(struct rtw_adapter *padapter, u8 *key, u8 alg, pcmd->rsp = NULL; pcmd->rspsz = 0; - INIT_LIST_HEAD(&pcmd->list); - res = rtw_enqueue_cmd23a(pcmdpriv, pcmd); exit: @@ -921,11 +883,6 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct rtw_adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct security_priv *psecuritypriv = &padapter->securitypriv; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif /* CONFIG_8723AU_P2P */ - - DBG_8723A("%s\n", __func__); @@ -1080,15 +1037,6 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, rtw_set_key23a(padapter, &padapter->securitypriv, param->u.crypt.idx, 1); -#ifdef CONFIG_8723AU_P2P - if (rtw_p2p_chk_state - (pwdinfo, - P2P_STATE_PROVISIONING_ING)) { - rtw_p2p_set_state(pwdinfo, - P2P_STATE_PROVISIONING_DONE); - } -#endif /* CONFIG_8723AU_P2P */ - } } @@ -1127,7 +1075,7 @@ static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev, { char *alg_name; u32 param_len; - struct ieee_param *param = NULL; + struct ieee_param *param; int ret = 0; struct wireless_dev *rtw_wdev = wiphy_to_wdev(wiphy); struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); @@ -1143,11 +1091,11 @@ static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev, param_len = sizeof(struct ieee_param) + params->key_len; param = kzalloc(param_len, GFP_KERNEL); - if (param == NULL) - return -1; + if (!param) + return -ENOMEM; param->cmd = IEEE_CMD_SET_ENCRYPTION; - memset(param->sta_addr, 0xff, ETH_ALEN); + eth_broadcast_addr(param->sta_addr); switch (params->cipher) { case IW_AUTH_CIPHER_NONE: @@ -1298,10 +1246,8 @@ static int cfg80211_rtw_get_station(struct wiphy *wiphy, ret = -ENOENT; goto exit; } -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A(FUNC_NDEV_FMT " mac =" MAC_FMT "\n", FUNC_NDEV_ARG(ndev), MAC_ARG(mac)); -#endif /* for infra./P2PClient mode */ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && @@ -1352,9 +1298,6 @@ static int cfg80211_rtw_change_iface(struct wiphy *wiphy, struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct wireless_dev *rtw_wdev = wiphy_to_wdev(wiphy); -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif int ret = 0; u8 change = false; @@ -1386,34 +1329,10 @@ static int cfg80211_rtw_change_iface(struct wiphy *wiphy, case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: networkType = Ndis802_11Infrastructure; -#ifdef CONFIG_8723AU_P2P - if (change && rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { - del_timer_sync(&pwdinfo->find_phase_timer); - del_timer_sync(&pwdinfo->restore_p2p_state_timer); - del_timer_sync(&pwdinfo->pre_tx_scan_timer); - - /* it means remove GO and change mode from AP(GO) - to station(P2P DEVICE) */ - rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); - rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); - - DBG_8723A("%s, role =%d, p2p_state =%d, pre_p2p_state =" - "%d\n", __func__, rtw_p2p_role(pwdinfo), - rtw_p2p_state(pwdinfo), - rtw_p2p_pre_state(pwdinfo)); - } -#endif /* CONFIG_8723AU_P2P */ break; case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_AP: networkType = Ndis802_11APMode; -#ifdef CONFIG_8723AU_P2P - if (change && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { - /* it means P2P Group created, we will be GO - and change mode from P2P DEVICE to AP(GO) */ - rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); - } -#endif /* CONFIG_8723AU_P2P */ break; default: return -EOPNOTSUPP; @@ -1438,9 +1357,8 @@ void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv, { spin_lock_bh(&pwdev_priv->scan_req_lock); if (pwdev_priv->scan_request != NULL) { -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A("%s with scan req\n", __func__); -#endif + if (pwdev_priv->scan_request->wiphy != pwdev_priv->rtw_wdev->wiphy) DBG_8723A("error wiphy compare\n"); @@ -1449,9 +1367,7 @@ void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv, pwdev_priv->scan_request = NULL; } else { -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A("%s without scan req\n", __func__); -#endif } spin_unlock_bh(&pwdev_priv->scan_req_lock); } @@ -1463,10 +1379,6 @@ void rtw_cfg80211_surveydone_event_callback(struct rtw_adapter *padapter) struct rtw_queue *queue = &pmlmepriv->scanned_queue; struct wlan_network *pnetwork; -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A("%s\n", __func__); -#endif - spin_lock_bh(&pmlmepriv->scanned_queue.lock); phead = get_list_head(queue); @@ -1495,23 +1407,15 @@ static int rtw_cfg80211_set_probe_req_wpsp2pie(struct rtw_adapter *padapter, int ret = 0; uint wps_ielen = 0; u8 *wps_ie; -#ifdef CONFIG_8723AU_P2P - u32 p2p_ielen = 0; - u8 *p2p_ie; - u32 wfd_ielen = 0; -#endif struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A("%s, ielen =%d\n", __func__, len); -#endif if (len > 0) { wps_ie = rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen); if (wps_ie) { -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A("probe_req_wps_ielen =%d\n", wps_ielen); -#endif + if (pmlmepriv->wps_probe_req_ie) { pmlmepriv->wps_probe_req_ie_len = 0; kfree(pmlmepriv->wps_probe_req_ie); @@ -1528,60 +1432,6 @@ static int rtw_cfg80211_set_probe_req_wpsp2pie(struct rtw_adapter *padapter, memcpy(pmlmepriv->wps_probe_req_ie, wps_ie, wps_ielen); pmlmepriv->wps_probe_req_ie_len = wps_ielen; } -#ifdef CONFIG_8723AU_P2P - p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen); - if (p2p_ie) { -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A("probe_req_p2p_ielen =%d\n", p2p_ielen); -#endif - - if (pmlmepriv->p2p_probe_req_ie) { - pmlmepriv->p2p_probe_req_ie_len = 0; - kfree(pmlmepriv->p2p_probe_req_ie); - pmlmepriv->p2p_probe_req_ie = NULL; - } - - pmlmepriv->p2p_probe_req_ie = - kmalloc(p2p_ielen, GFP_KERNEL); - if (pmlmepriv->p2p_probe_req_ie == NULL) { - DBG_8723A("%s()-%d: kmalloc() ERROR!\n", - __func__, __LINE__); - return -EINVAL; - - } - memcpy(pmlmepriv->p2p_probe_req_ie, p2p_ie, p2p_ielen); - pmlmepriv->p2p_probe_req_ie_len = p2p_ielen; - } -#endif /* CONFIG_8723AU_P2P */ - - /* buf += p2p_ielen; */ - /* len -= p2p_ielen; */ - -#ifdef CONFIG_8723AU_P2P - if (rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) { -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A("probe_req_wfd_ielen =%d\n", wfd_ielen); -#endif - - if (pmlmepriv->wfd_probe_req_ie) { - pmlmepriv->wfd_probe_req_ie_len = 0; - kfree(pmlmepriv->wfd_probe_req_ie); - pmlmepriv->wfd_probe_req_ie = NULL; - } - - pmlmepriv->wfd_probe_req_ie = - kmalloc(wfd_ielen, GFP_KERNEL); - if (pmlmepriv->wfd_probe_req_ie == NULL) { - DBG_8723A("%s()-%d: kmalloc() ERROR!\n", - __func__, __LINE__); - return -EINVAL; - - } - rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_probe_req_ie, - &pmlmepriv->wfd_probe_req_ie_len); - } -#endif /* CONFIG_8723AU_P2P */ - } return ret; @@ -1599,25 +1449,16 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy, struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); struct cfg80211_ssid *ssids = request->ssids; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - int social_channel = 0; -#endif /* CONFIG_8723AU_P2P */ bool need_indicate_scan_done = false; -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A(FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter)); -#endif spin_lock_bh(&pwdev_priv->scan_req_lock); pwdev_priv->scan_request = request; spin_unlock_bh(&pwdev_priv->scan_req_lock); if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { - -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A("%s under WIFI_AP_STATE\n", __func__); -#endif /* need_indicate_scan_done = true; */ /* goto check_need_indicate_scan_done; */ } @@ -1626,29 +1467,6 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy, need_indicate_scan_done = true; goto check_need_indicate_scan_done; } -#ifdef CONFIG_8723AU_P2P - if (!memcmp(ssids->ssid, "DIRECT-", 7) && - rtw_get_p2p_ie23a((u8 *) request->ie, request->ie_len, NULL, NULL)) { - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { - rtw_p2p_enable23a(padapter, P2P_ROLE_DEVICE); - wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = true; - } else { - rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A("%s, role =%d, p2p_state =%d\n", __func__, - rtw_p2p_role(pwdinfo), - rtw_p2p_state(pwdinfo)); -#endif - } - rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); - - if (request->n_channels == 3 && - request->channels[0]->hw_value == 1 && - request->channels[1]->hw_value == 6 && - request->channels[2]->hw_value == 11) - social_channel = 1; - } -#endif /* CONFIG_8723AU_P2P */ if (request->ie && request->ie_len > 0) { rtw_cfg80211_set_probe_req_wpsp2pie(padapter, @@ -1674,28 +1492,12 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy, need_indicate_scan_done = true; goto check_need_indicate_scan_done; } -#ifdef CONFIG_8723AU_P2P - if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && - !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) { - rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); - rtw_free_network_queue23a(padapter, true); - - if (social_channel == 0) - rtw_p2p_findphase_ex_set(pwdinfo, - P2P_FINDPHASE_EX_NONE); - else - rtw_p2p_findphase_ex_set(pwdinfo, - P2P_FINDPHASE_EX_SOCIAL_LAST); - } -#endif /* CONFIG_8723AU_P2P */ memset(ssid, 0, sizeof(struct cfg80211_ssid) * RTW_SSID_SCAN_AMOUNT); /* parsing request ssids, n_ssids */ for (i = 0; i < request->n_ssids && i < RTW_SSID_SCAN_AMOUNT; i++) { -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A("ssid =%s, len =%d\n", ssids[i].ssid, ssids[i].ssid_len); -#endif memcpy(ssid[i].ssid, ssids[i].ssid, ssids[i].ssid_len); ssid[i].ssid_len = ssids[i].ssid_len; } @@ -1707,11 +1509,9 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy, if (request->n_channels == 1) { for (i = 0; i < request->n_channels && i < RTW_CHANNEL_SCAN_AMOUNT; i++) { -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A(FUNC_ADPT_FMT CHAN_FMT "\n", FUNC_ADPT_ARG(padapter), CHAN_ARG(request->channels[i])); -#endif ch[i].hw_value = request->channels[i]->hw_value; ch[i].flags = request->channels[i]->flags; } @@ -1877,13 +1677,10 @@ static int rtw_cfg80211_set_key_mgt(struct security_priv *psecuritypriv, static int rtw_cfg80211_set_wpa_ie(struct rtw_adapter *padapter, const u8 *pie, size_t ielen) { - u8 *buf = NULL, *pos = NULL; + u8 *buf = NULL; int group_cipher = 0, pairwise_cipher = 0; int ret = 0; - int wpa_ielen = 0; - int wpa2_ielen = 0; - u8 *pwpa, *pwpa2; - u8 null_addr[] = { 0, 0, 0, 0, 0, 0 }; + const u8 *pwpa, *pwpa2; int i; if (!pie || !ielen) { @@ -1910,7 +1707,6 @@ static int rtw_cfg80211_set_wpa_ie(struct rtw_adapter *padapter, const u8 *pie, buf[i], buf[i + 1], buf[i + 2], buf[i + 3], buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]); - pos = buf; if (ielen < RSN_HEADER_LEN) { RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("Ie len too short %d\n", (int)ielen)); @@ -1918,33 +1714,35 @@ static int rtw_cfg80211_set_wpa_ie(struct rtw_adapter *padapter, const u8 *pie, goto exit; } - pwpa = rtw_get_wpa_ie23a(buf, &wpa_ielen, ielen); - if (pwpa && wpa_ielen > 0) { - if (rtw_parse_wpa_ie23a(pwpa, wpa_ielen + 2, &group_cipher, - &pairwise_cipher, NULL) == _SUCCESS) { + pwpa = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPA, + buf, ielen); + if (pwpa && pwpa[1] > 0) { + if (rtw_parse_wpa_ie23a(pwpa, pwpa[1] + 2, &group_cipher, + &pairwise_cipher, NULL) == _SUCCESS) { padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; - memcpy(padapter->securitypriv.supplicant_ie, &pwpa[0], - wpa_ielen + 2); + memcpy(padapter->securitypriv.supplicant_ie, pwpa, + pwpa[1] + 2); - DBG_8723A("got wpa_ie, wpa_ielen:%u\n", wpa_ielen); + DBG_8723A("got wpa_ie, wpa_ielen:%u\n", pwpa[1]); } } - pwpa2 = rtw_get_wpa2_ie23a(buf, &wpa2_ielen, ielen); - if (pwpa2 && wpa2_ielen > 0) { - if (rtw_parse_wpa2_ie23a (pwpa2, wpa2_ielen + 2, &group_cipher, - &pairwise_cipher, NULL) == _SUCCESS) { + pwpa2 = cfg80211_find_ie(WLAN_EID_RSN, buf, ielen); + if (pwpa2 && pwpa2[1] > 0) { + if (rtw_parse_wpa2_ie23a (pwpa2, pwpa2[1] + 2, &group_cipher, + &pairwise_cipher, NULL) == _SUCCESS) { padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK; - memcpy(padapter->securitypriv.supplicant_ie, &pwpa2[0], - wpa2_ielen + 2); + memcpy(padapter->securitypriv.supplicant_ie, pwpa2, + pwpa2[1] + 2); - DBG_8723A("got wpa2_ie, wpa2_ielen:%u\n", wpa2_ielen); + DBG_8723A("got wpa2_ie, wpa2_ielen:%u\n", pwpa2[1]); } } @@ -2029,75 +1827,13 @@ static int rtw_cfg80211_set_wpa_ie(struct rtw_adapter *padapter, const u8 *pie, } } -#ifdef CONFIG_8723AU_P2P - { /* check p2p_ie for assoc req; */ - uint p2p_ielen = 0; - u8 *p2p_ie; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - p2p_ie = rtw_get_p2p_ie23a(buf, ielen, NULL, &p2p_ielen); - if (p2p_ie) { -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A("%s p2p_assoc_req_ielen =%d\n", __func__, - p2p_ielen); -#endif - - if (pmlmepriv->p2p_assoc_req_ie) { - pmlmepriv->p2p_assoc_req_ie_len = 0; - kfree(pmlmepriv->p2p_assoc_req_ie); - pmlmepriv->p2p_assoc_req_ie = NULL; - } - - pmlmepriv->p2p_assoc_req_ie = - kmalloc(p2p_ielen, GFP_KERNEL); - if (pmlmepriv->p2p_assoc_req_ie == NULL) { - DBG_8723A("%s()-%d: kmalloc() ERROR!\n", - __func__, __LINE__); - goto exit; - } - memcpy(pmlmepriv->p2p_assoc_req_ie, p2p_ie, p2p_ielen); - pmlmepriv->p2p_assoc_req_ie_len = p2p_ielen; - } - } -#endif /* CONFIG_8723AU_P2P */ - -#ifdef CONFIG_8723AU_P2P - { /* check wfd_ie for assoc req; */ - uint wfd_ielen = 0; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - if (rtw_get_wfd_ie(buf, ielen, NULL, &wfd_ielen)) { -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A("%s wfd_assoc_req_ielen =%d\n", __func__, - wfd_ielen); -#endif - - if (pmlmepriv->wfd_assoc_req_ie) { - pmlmepriv->wfd_assoc_req_ie_len = 0; - kfree(pmlmepriv->wfd_assoc_req_ie); - pmlmepriv->wfd_assoc_req_ie = NULL; - } - - pmlmepriv->wfd_assoc_req_ie = - kmalloc(wfd_ielen, GFP_KERNEL); - if (pmlmepriv->wfd_assoc_req_ie == NULL) { - DBG_8723A("%s()-%d: kmalloc() ERROR!\n", - __func__, __LINE__); - goto exit; - } - rtw_get_wfd_ie(buf, ielen, pmlmepriv->wfd_assoc_req_ie, - &pmlmepriv->wfd_assoc_req_ie_len); - } - } -#endif /* CONFIG_8723AU_P2P */ - /* TKIP and AES disallow multicast packets until installing group key */ if (padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_ || padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_ || padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) /* WPS open need to enable multicast */ /* check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == true)*/ - rtw_hal_set_hwreg23a(padapter, HW_VAR_OFF_RCR_AM, null_addr); + rtl8723a_off_rcr_am(padapter); RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("rtw_set_wpa_ie: pairwise_cipher = 0x%08x padapter->" @@ -2513,8 +2249,7 @@ static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy, if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, pmksa->bssid, ETH_ALEN)) { /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */ - memset(psecuritypriv->PMKIDList[index].Bssid, 0x00, - ETH_ALEN); + eth_zero_addr(psecuritypriv->PMKIDList[index].Bssid); memset(psecuritypriv->PMKIDList[index].PMKID, 0x00, WLAN_PMKID_LEN); psecuritypriv->PMKIDList[index].bUsed = false; @@ -2597,7 +2332,7 @@ void rtw_cfg80211_indicate_sta_disassoc(struct rtw_adapter *padapter, u8 *pmgmt_frame; uint frame_len; struct ieee80211_hdr *pwlanhdr; - unsigned short *fctrl; + __le16 *fctrl; u8 mgmt_buf[128] = { 0 }; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -2739,9 +2474,6 @@ static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; u32 len = skb->len; u8 category, action; -#ifdef CONFIG_8723AU_P2P - int type = -1; -#endif if (rtw_action_frame_parse23a(skb->data, len, &category, &action) == false) { @@ -2753,19 +2485,12 @@ static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, DBG_8723A("RTW_Tx:da =" MAC_FMT " via " FUNC_NDEV_FMT "\n", MAC_ARG(dot11_hdr->addr1), FUNC_NDEV_ARG(ndev)); -#ifdef CONFIG_8723AU_P2P - type = rtw_p2p_check_frames(padapter, skb->data, len, true); - if (type >= 0) - goto dump; -#endif if (category == WLAN_CATEGORY_PUBLIC) DBG_8723A("RTW_Tx:%s\n", action_public_str23a(action)); else DBG_8723A("RTW_Tx:category(%u), action(%u)\n", category, action); -#ifdef CONFIG_8723AU_P2P -dump: -#endif + /* starting alloc mgmt frame to dump it */ pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); if (pmgntframe == NULL) @@ -2781,16 +2506,6 @@ static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; memcpy(pframe, skb->data, len); -#ifdef CONFIG_8723AU_P2P - if (type >= 0) { - struct wifi_display_info *pwfd_info; - - pwfd_info = padapter->wdinfo.wfd_info; - - if (pwfd_info->wfd_enable) - rtw_append_wfd_ie(padapter, pframe, &len); - } -#endif /* CONFIG_8723AU_P2P */ pattrib->pktlen = len; /* update seq number */ @@ -2976,10 +2691,6 @@ static int rtw_add_beacon(struct rtw_adapter *adapter, const u8 *head, int ret = 0; u8 *pbuf = NULL; uint len, wps_ielen = 0; -#ifdef CONFIG_8723AU_P2P - uint p2p_ielen = 0; - u8 got_p2p_ie = false; -#endif struct mlme_priv *pmlmepriv = &adapter->mlmepriv; /* struct sta_priv *pstapriv = &padapter->stapriv; */ @@ -3007,55 +2718,14 @@ static int rtw_add_beacon(struct rtw_adapter *adapter, const u8 *head, &wps_ielen)) DBG_8723A("add bcn, wps_ielen =%d\n", wps_ielen); -#ifdef CONFIG_8723AU_P2P - /* check p2p ie if inclued */ - if (rtw_get_p2p_ie23a - (pbuf + _FIXED_IE_LENGTH_, len - _FIXED_IE_LENGTH_, NULL, - &p2p_ielen)) { - DBG_8723A("got p2p_ie, len =%d\n", p2p_ielen); - got_p2p_ie = true; - } -#endif - /* pbss_network->IEs will not include p2p_ie, wfd ie */ - rtw_ies_remove_ie23a(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, - P2P_OUI23A, 4); - rtw_ies_remove_ie23a(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, - WFD_OUI23A, 4); + rtw_ies_remove_ie23a(pbuf, &len, _BEACON_IE_OFFSET_, + WLAN_EID_VENDOR_SPECIFIC, P2P_OUI23A, 4); + rtw_ies_remove_ie23a(pbuf, &len, _BEACON_IE_OFFSET_, + WLAN_EID_VENDOR_SPECIFIC, WFD_OUI23A, 4); if (rtw_check_beacon_data23a(adapter, pbuf, len) == _SUCCESS) { -#ifdef CONFIG_8723AU_P2P - /* check p2p if enable */ - if (got_p2p_ie == true) { - struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; - struct wifidirect_info *pwdinfo = &adapter->wdinfo; - - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { - DBG_8723A("Enable P2P function for the first " - "time\n"); - rtw_p2p_enable23a(adapter, P2P_ROLE_GO); - wdev_to_priv(adapter->rtw_wdev)->p2p_enabled = - true; - } else { - del_timer_sync(&pwdinfo->find_phase_timer); - del_timer_sync(&pwdinfo-> - restore_p2p_state_timer); - del_timer_sync(&pwdinfo->pre_tx_scan_timer); - - DBG_8723A("enter GO Mode, p2p_ielen =%d\n", - p2p_ielen); - - rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); - rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); - pwdinfo->intent = 15; - } - - pwdinfo->operating_channel = pmlmeext->cur_channel; - } -#endif /* CONFIG_8723AU_P2P */ - ret = 0; - } else { ret = -EINVAL; } @@ -3252,9 +2922,6 @@ static int cfg80211_rtw_change_bss(struct wiphy *wiphy, struct net_device *ndev, void rtw_cfg80211_rx_action_p2p(struct rtw_adapter *padapter, u8 *pmgmt_frame, uint frame_len) { -#ifdef CONFIG_8723AU_P2P - int type; -#endif s32 freq; int channel; u8 category, action; @@ -3262,17 +2929,9 @@ void rtw_cfg80211_rx_action_p2p(struct rtw_adapter *padapter, u8 *pmgmt_frame, channel = rtw_get_oper_ch23a(padapter); DBG_8723A("RTW_Rx:cur_ch =%d\n", channel); -#ifdef CONFIG_8723AU_P2P - type = rtw_p2p_check_frames(padapter, pmgmt_frame, frame_len, false); - if (type >= 0) - goto indicate; -#endif rtw_action_frame_parse23a(pmgmt_frame, frame_len, &category, &action); DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category, action); -#ifdef CONFIG_8723AU_P2P -indicate: -#endif if (channel <= RTW_CH_MAX_2G_CHANNEL) freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); @@ -3287,9 +2946,6 @@ void rtw_cfg80211_rx_action_p2p(struct rtw_adapter *padapter, u8 *pmgmt_frame, void rtw_cfg80211_rx_p2p_action_public(struct rtw_adapter *padapter, u8 *pmgmt_frame, uint frame_len) { -#ifdef CONFIG_8723AU_P2P - int type; -#endif s32 freq; int channel; u8 category, action; @@ -3297,23 +2953,9 @@ void rtw_cfg80211_rx_p2p_action_public(struct rtw_adapter *padapter, channel = rtw_get_oper_ch23a(padapter); DBG_8723A("RTW_Rx:cur_ch =%d\n", channel); -#ifdef CONFIG_8723AU_P2P - type = rtw_p2p_check_frames(padapter, pmgmt_frame, frame_len, false); - if (type >= 0) { - switch (type) { - case P2P_GO_NEGO_CONF: - case P2P_PROVISION_DISC_RESP: - rtw_clear_scan_deny(padapter); - } - goto indicate; - } -#endif rtw_action_frame_parse23a(pmgmt_frame, frame_len, &category, &action); DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category, action); -#ifdef CONFIG_8723AU_P2P -indicate: -#endif if (channel <= RTW_CH_MAX_2G_CHANNEL) freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); @@ -3353,350 +2995,6 @@ void rtw_cfg80211_rx_action(struct rtw_adapter *adapter, u8 *frame, rtw_cfg80211_rx_mgmt(adapter, freq, 0, frame, frame_len, GFP_ATOMIC); } -#ifdef CONFIG_8723AU_P2P -void rtw_cfg80211_issue_p2p_provision_request23a(struct rtw_adapter *padapter, - const u8 *buf, size_t len) -{ - u16 wps_devicepassword_id = 0x0000; - uint wps_devicepassword_id_len = 0; - u8 wpsie[255] = { 0x00 }, p2p_ie[255] = { 0x00 }; - uint p2p_ielen = 0; - uint wpsielen = 0; - u32 devinfo_contentlen = 0; - u8 devinfo_content[64] = { 0x00 }; - u16 capability = 0; - uint capability_len = 0; - - unsigned char category = WLAN_CATEGORY_PUBLIC; - u8 action = P2P_PUB_ACTION_ACTION; - u8 dialogToken = 1; - u32 p2poui = cpu_to_be32(P2POUI); - u8 oui_subtype = P2P_PROVISION_DISC_REQ; - u32 p2pielen = 0; -#ifdef CONFIG_8723AU_P2P - u32 wfdielen = 0; -#endif /* CONFIG_8723AU_P2P */ - - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct ieee80211_hdr *pwlanhdr, *hdr; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 *frame_body = - (unsigned char *)(buf + sizeof(struct ieee80211_hdr_3addr)); - size_t frame_body_len = len - sizeof(struct ieee80211_hdr_3addr); - - DBG_8723A("[%s] In\n", __func__); - - hdr = (struct ieee80211_hdr *)buf; - /* prepare for building provision_request frame */ - memcpy(pwdinfo->tx_prov_disc_info.peerIFAddr, hdr->addr1, ETH_ALEN); - memcpy(pwdinfo->tx_prov_disc_info.peerDevAddr, hdr->addr1, ETH_ALEN); - - pwdinfo->tx_prov_disc_info.wps_config_method_request = - WPS_CM_PUSH_BUTTON; - - rtw_get_wps_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, - frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, - &wpsielen); - rtw_get_wps_attr_content23a(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, - (u8 *)&wps_devicepassword_id, - &wps_devicepassword_id_len); - wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id); - - switch (wps_devicepassword_id) { - case WPS_DPID_PIN: - pwdinfo->tx_prov_disc_info.wps_config_method_request = - WPS_CM_LABEL; - break; - case WPS_DPID_USER_SPEC: - pwdinfo->tx_prov_disc_info.wps_config_method_request = - WPS_CM_DISPLYA; - break; - case WPS_DPID_MACHINE_SPEC: - break; - case WPS_DPID_REKEY: - break; - case WPS_DPID_PBC: - pwdinfo->tx_prov_disc_info.wps_config_method_request = - WPS_CM_PUSH_BUTTON; - break; - case WPS_DPID_REGISTRAR_SPEC: - pwdinfo->tx_prov_disc_info.wps_config_method_request = - WPS_CM_KEYPAD; - break; - default: - break; - } - - if (rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, - frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, - p2p_ie, &p2p_ielen)) { - rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, - P2P_ATTR_DEVICE_INFO, devinfo_content, - &devinfo_contentlen); - rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, - (u8 *)&capability, &capability_len); - } - - /* start to build provision_request frame */ - memset(wpsie, 0, sizeof(wpsie)); - memset(p2p_ie, 0, sizeof(p2p_ie)); - p2p_ielen = 0; - - pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); - if (pmgntframe == NULL) - return; - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib23a(padapter, pattrib); - - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - - pframe = (u8 *) (pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; - - pwlanhdr->frame_control = 0; - - memcpy(pwlanhdr->addr1, pwdinfo->tx_prov_disc_info.peerDevAddr, - ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); - memcpy(pwlanhdr->addr3, pwdinfo->tx_prov_disc_info.peerDevAddr, - ETH_ALEN); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); - - pframe += sizeof(struct ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - - pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, - &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); - pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); - - /* build_prov_disc_request_p2p_ie23a */ - /* P2P OUI */ - p2pielen = 0; - p2p_ie[p2pielen++] = 0x50; - p2p_ie[p2pielen++] = 0x6F; - p2p_ie[p2pielen++] = 0x9A; - p2p_ie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ - - /* Commented by Albert 20110301 */ - /* According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */ - /* 1. P2P Capability */ - /* 2. Device Info */ - /* 3. Group ID ( When joining an operating P2P Group ) */ - - /* P2P Capability ATTR */ - /* Type: */ - p2p_ie[p2pielen++] = P2P_ATTR_CAPABILITY; - - /* Length: */ - put_unaligned_le16(0x0002, p2p_ie + p2pielen); - p2pielen += 2; - - /* Value: */ - /* Device Capability Bitmap, 1 byte */ - /* Group Capability Bitmap, 1 byte */ - memcpy(p2p_ie + p2pielen, &capability, 2); - p2pielen += 2; - - /* Device Info ATTR */ - /* Type: */ - p2p_ie[p2pielen++] = P2P_ATTR_DEVICE_INFO; - - /* Length: */ - put_unaligned_le16(devinfo_contentlen, p2p_ie + p2pielen); - p2pielen += 2; - - /* Value: */ - memcpy(p2p_ie + p2pielen, devinfo_content, devinfo_contentlen); - p2pielen += devinfo_contentlen; - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, - (unsigned char *)p2p_ie, &p2p_ielen); - pattrib->pktlen += p2p_ielen; - - wpsielen = 0; - /* WPS OUI */ - *(u32 *)(wpsie) = cpu_to_be32(WPSOUI); - wpsielen += 4; - - /* WPS version */ - /* Type: */ - *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); - wpsielen += 2; - - /* Length: */ - *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); - wpsielen += 2; - - /* Value: */ - wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ - - /* Config Method */ - /* Type: */ - *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); - wpsielen += 2; - - /* Length: */ - *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); - wpsielen += 2; - - /* Value: */ - *(u16 *)(wpsie + wpsielen) = - cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request); - wpsielen += 2; - - pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, - (unsigned char *)wpsie, &pattrib->pktlen); - -#ifdef CONFIG_8723AU_P2P - wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe); - pframe += wfdielen; - pattrib->pktlen += wfdielen; -#endif /* CONFIG_8723AU_P2P */ - - pattrib->last_txcmdsz = pattrib->pktlen; - - /* dump_mgntframe23a(padapter, pmgntframe); */ - if (dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe) != _SUCCESS) - DBG_8723A("%s, ack to\n", __func__); -} - -static s32 cfg80211_rtw_remain_on_channel(struct wiphy *wiphy, - struct wireless_dev *wdev, - struct ieee80211_channel *channel, - unsigned int duration, u64 *cookie) -{ - s32 err = 0; - struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - struct cfg80211_wifidirect_info *pcfg80211_wdinfo = - &padapter->cfg80211_wdinfo; - u8 remain_ch = - (u8) ieee80211_frequency_to_channel(channel->center_freq); - u8 ready_on_channel = false; - - DBG_8723A(FUNC_ADPT_FMT " ch:%u duration:%d\n", FUNC_ADPT_ARG(padapter), - remain_ch, duration); - - if (pcfg80211_wdinfo->is_ro_ch == true) { - DBG_8723A("%s, cancel ro ch timer\n", __func__); - - del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer); - -#ifdef CONFIG_8723AU_P2P - p2p_protocol_wk_hdl23a(padapter, P2P_RO_CH_WK); -#endif - } - - pcfg80211_wdinfo->is_ro_ch = true; - - if (_FAIL == rtw_pwr_wakeup(padapter)) { - err = -EFAULT; - goto exit; - } - - memcpy(&pcfg80211_wdinfo->remain_on_ch_channel, channel, - sizeof(struct ieee80211_channel)); - pcfg80211_wdinfo->remain_on_ch_cookie = *cookie; - - rtw_scan_abort23a(padapter); - if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { - rtw_p2p_enable23a(padapter, P2P_ROLE_DEVICE); - wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = true; - } else { - rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A("%s, role =%d, p2p_state =%d\n", __func__, - rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo)); -#endif - } - - rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); - - if (duration < 400) - duration = duration * 3; /* extend from exper. */ - - pcfg80211_wdinfo->restore_channel = pmlmeext->cur_channel; - - if (rtw_ch_set_search_ch23a(pmlmeext->channel_set, remain_ch) >= 0) { - if (remain_ch != pmlmeext->cur_channel) { - ready_on_channel = true; - } - } else { - DBG_8723A("%s remain_ch:%u not in channel plan!!!!\n", - __func__, remain_ch); - } - - /* call this after other things have been done */ - if (ready_on_channel == true) { - if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { - pmlmeext->cur_channel = remain_ch; - - set_channel_bwmode23a(padapter, remain_ch, - HAL_PRIME_CHNL_OFFSET_DONT_CARE, - HT_CHANNEL_WIDTH_20); - } - } - DBG_8723A("%s, set ro ch timer, duration =%d\n", __func__, duration); - mod_timer(&pcfg80211_wdinfo->remain_on_ch_timer, - jiffies + msecs_to_jiffies(duration)); - - rtw_cfg80211_ready_on_channel(padapter, *cookie, channel, channel_type, - duration, GFP_KERNEL); - - pwdinfo->listen_channel = pmlmeext->cur_channel; - -exit: - if (err) - pcfg80211_wdinfo->is_ro_ch = false; - - return err; -} - -static s32 cfg80211_rtw_cancel_remain_on_channel(struct wiphy *wiphy, - struct wireless_dev *wdev, - u64 cookie) -{ - s32 err = 0; - struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); - struct wifidirect_info *pwdinfo = &padapter->wdinfo; - struct cfg80211_wifidirect_info *pcfg80211_wdinfo = - &padapter->cfg80211_wdinfo; - - DBG_8723A(FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter)); - - if (pcfg80211_wdinfo->is_ro_ch == true) { - DBG_8723A("%s, cancel ro ch timer\n", __func__); - del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer); -#ifdef CONFIG_8723AU_P2P - p2p_protocol_wk_hdl23a(padapter, P2P_RO_CH_WK); -#endif - } - - rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A("%s, role =%d, p2p_state =%d\n", __func__, - rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo)); -#endif - pcfg80211_wdinfo->is_ro_ch = false; - - return err; -} - -#endif /* CONFIG_8723AU_P2P */ - static int _cfg80211_rtw_mgmt_tx(struct rtw_adapter *padapter, u8 tx_ch, const u8 *buf, size_t len) { @@ -3708,7 +3006,6 @@ static int _cfg80211_rtw_mgmt_tx(struct rtw_adapter *padapter, u8 tx_ch, struct ieee80211_hdr *pwlanhdr; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - /* struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; */ if (_FAIL == rtw_pwr_wakeup(padapter)) { ret = -EFAULT; @@ -3753,39 +3050,21 @@ static int _cfg80211_rtw_mgmt_tx(struct rtw_adapter *padapter, u8 tx_ch, pattrib->seqnum = pmlmeext->mgnt_seq; pmlmeext->mgnt_seq++; -#ifdef CONFIG_8723AU_P2P - { - struct wifi_display_info *pwfd_info; - - pwfd_info = padapter->wdinfo.wfd_info; - - if (true == pwfd_info->wfd_enable) { - rtw_append_wfd_ie(padapter, pframe, &pattrib->pktlen); - } - } -#endif /* CONFIG_8723AU_P2P */ - pattrib->last_txcmdsz = pattrib->pktlen; if (dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe) != _SUCCESS) { ack = false; ret = _FAIL; -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A("%s, ack == _FAIL\n", __func__); -#endif } else { -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A("%s, ack =%d, ok!\n", __func__, ack); -#endif ret = _SUCCESS; } exit: -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A("%s, ret =%d\n", __func__, ret); -#endif return ret; } @@ -3824,10 +3103,8 @@ static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, /* cookie generation */ *cookie = (unsigned long)buf; -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A(FUNC_ADPT_FMT " len =%zu, ch =%d" "\n", FUNC_ADPT_ARG(padapter), len, tx_ch); -#endif /* CONFIG_DEBUG_CFG80211 */ /* indicate ack before issue frame to avoid racing with rsp frame */ rtw_cfg80211_mgmt_tx_status(padapter, *cookie, buf, len, ack, @@ -3842,20 +3119,12 @@ static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, DBG_8723A("RTW_Tx:tx_ch =%d, da =" MAC_FMT "\n", tx_ch, MAC_ARG(hdr->addr1)); -#ifdef CONFIG_8723AU_P2P - type = rtw_p2p_check_frames(padapter, buf, len, true); - if (type >= 0) - goto dump; -#endif if (category == WLAN_CATEGORY_PUBLIC) DBG_8723A("RTW_Tx:%s\n", action_public_str23a(action)); else DBG_8723A("RTW_Tx:category(%u), action(%u)\n", category, action); -#ifdef CONFIG_8723AU_P2P -dump: -#endif do { dump_cnt++; tx_ret = _cfg80211_rtw_mgmt_tx(padapter, tx_ch, buf, len); @@ -3893,12 +3162,6 @@ static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, u16 frame_type, bool reg) { - -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A(FUNC_ADPT_FMT " frame_type:%x, reg:%d\n", - FUNC_ADPT_ARG(adapter), frame_type, reg); -#endif - if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) return; @@ -3911,11 +3174,6 @@ static int rtw_cfg80211_set_beacon_wpsp2pie(struct net_device *ndev, char *buf, int ret = 0; uint wps_ielen = 0; u8 *wps_ie; -#ifdef CONFIG_8723AU_P2P - u32 p2p_ielen = 0; - u32 wfd_ielen = 0; - u8 *p2p_ie; -#endif #ifdef CONFIG_8723AU_AP_MODE u8 wps_oui[8] = { 0x0, 0x50, 0xf2, 0x04 }; #endif @@ -3928,9 +3186,7 @@ static int rtw_cfg80211_set_beacon_wpsp2pie(struct net_device *ndev, char *buf, if (len > 0) { wps_ie = rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen); if (wps_ie) { -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A("bcn_wps_ielen =%d\n", wps_ielen); -#endif if (pmlmepriv->wps_beacon_ie) { pmlmepriv->wps_beacon_ie_len = 0; @@ -3949,63 +3205,10 @@ static int rtw_cfg80211_set_beacon_wpsp2pie(struct net_device *ndev, char *buf, pmlmepriv->wps_beacon_ie_len = wps_ielen; #ifdef CONFIG_8723AU_AP_MODE - update_beacon23a(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, - true); -#endif - } -#ifdef CONFIG_8723AU_P2P - p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen); - if (p2p_ie) { -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A("bcn_p2p_ielen =%d\n", p2p_ielen); -#endif - - if (pmlmepriv->p2p_beacon_ie) { - pmlmepriv->p2p_beacon_ie_len = 0; - kfree(pmlmepriv->p2p_beacon_ie); - pmlmepriv->p2p_beacon_ie = NULL; - } - - pmlmepriv->p2p_beacon_ie = - kmalloc(p2p_ielen, GFP_KERNEL); - if (pmlmepriv->p2p_beacon_ie == NULL) { - DBG_8723A("%s()-%d: kmalloc() ERROR!\n", - __func__, __LINE__); - return -EINVAL; - } - - memcpy(pmlmepriv->p2p_beacon_ie, p2p_ie, p2p_ielen); - pmlmepriv->p2p_beacon_ie_len = p2p_ielen; - } -#endif /* CONFIG_8723AU_P2P */ - - /* buf += p2p_ielen; */ - /* len -= p2p_ielen; */ - -#ifdef CONFIG_8723AU_P2P - if (rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) { -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A("bcn_wfd_ielen =%d\n", wfd_ielen); + update_beacon23a(padapter, WLAN_EID_VENDOR_SPECIFIC, + wps_oui, true); #endif - - if (pmlmepriv->wfd_beacon_ie) { - pmlmepriv->wfd_beacon_ie_len = 0; - kfree(pmlmepriv->wfd_beacon_ie); - pmlmepriv->wfd_beacon_ie = NULL; - } - - pmlmepriv->wfd_beacon_ie = - kmalloc(wfd_ielen, GFP_KERNEL); - if (pmlmepriv->wfd_beacon_ie == NULL) { - DBG_8723A("%s()-%d: kmalloc() ERROR!\n", - __func__, __LINE__); - return -EINVAL; - - } - rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_beacon_ie, - &pmlmepriv->wfd_beacon_ie_len); } -#endif /* CONFIG_8723AU_P2P */ pmlmeext->bstart_bss = true; @@ -4019,11 +3222,6 @@ static int rtw_cfg80211_set_probe_resp_wpsp2pie(struct net_device *net, { struct rtw_adapter *padapter = netdev_priv(net); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -#ifdef CONFIG_8723AU_P2P - u32 p2p_ielen = 0; - u8 *p2p_ie; - u32 wfd_ielen = 0; -#endif int ret = 0; uint wps_ielen = 0; u8 *wps_ie; @@ -4067,104 +3265,6 @@ static int rtw_cfg80211_set_probe_resp_wpsp2pie(struct net_device *net, } - /* buf += wps_ielen; */ - /* len -= wps_ielen; */ - -#ifdef CONFIG_8723AU_P2P - p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen); - if (p2p_ie) { - u8 is_GO = false; - u32 attr_contentlen = 0; - u16 cap_attr = 0; - -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A("probe_resp_p2p_ielen =%d\n", p2p_ielen); -#endif - - /* Check P2P Capability ATTR */ - if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, - P2P_ATTR_CAPABILITY, - (u8 *) &cap_attr, - (uint *) &attr_contentlen)) { - u8 grp_cap = 0; - /* DBG_8723A( "[%s] Got P2P Capability Attr!!\n", __func__ ); */ - cap_attr = le16_to_cpu(cap_attr); - grp_cap = (u8) ((cap_attr >> 8) & 0xff); - - is_GO = (grp_cap & BIT(0)) ? true : false; - - if (is_GO) - DBG_8723A - ("Got P2P Capability Attr, grp_cap" - "= 0x%x, is_GO\n", grp_cap); - } - - if (is_GO == false) { - if (pmlmepriv->p2p_probe_resp_ie) { - pmlmepriv->p2p_probe_resp_ie_len = 0; - kfree(pmlmepriv->p2p_probe_resp_ie); - pmlmepriv->p2p_probe_resp_ie = NULL; - } - - pmlmepriv->p2p_probe_resp_ie = - kmalloc(p2p_ielen, GFP_KERNEL); - if (pmlmepriv->p2p_probe_resp_ie == NULL) { - DBG_8723A("%s()-%d: kmalloc() ERROR!\n", - __func__, __LINE__); - return -EINVAL; - } - memcpy(pmlmepriv->p2p_probe_resp_ie, p2p_ie, - p2p_ielen); - pmlmepriv->p2p_probe_resp_ie_len = p2p_ielen; - } else { - if (pmlmepriv->p2p_go_probe_resp_ie) { - pmlmepriv->p2p_go_probe_resp_ie_len = 0; - kfree(pmlmepriv->p2p_go_probe_resp_ie); - pmlmepriv->p2p_go_probe_resp_ie = NULL; - } - - pmlmepriv->p2p_go_probe_resp_ie = - kmalloc(p2p_ielen, GFP_KERNEL); - if (pmlmepriv->p2p_go_probe_resp_ie == NULL) { - DBG_8723A("%s()-%d: kmalloc() ERROR!\n", - __func__, __LINE__); - return -EINVAL; - - } - memcpy(pmlmepriv->p2p_go_probe_resp_ie, - p2p_ie, p2p_ielen); - pmlmepriv->p2p_go_probe_resp_ie_len = p2p_ielen; - } - } -#endif /* CONFIG_8723AU_P2P */ - - /* buf += p2p_ielen; */ - /* len -= p2p_ielen; */ - -#ifdef CONFIG_8723AU_P2P - if (rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) { -#ifdef CONFIG_DEBUG_CFG80211 - DBG_8723A("probe_resp_wfd_ielen =%d\n", wfd_ielen); -#endif - - if (pmlmepriv->wfd_probe_resp_ie) { - pmlmepriv->wfd_probe_resp_ie_len = 0; - kfree(pmlmepriv->wfd_probe_resp_ie); - pmlmepriv->wfd_probe_resp_ie = NULL; - } - - pmlmepriv->wfd_probe_resp_ie = - kmalloc(wfd_ielen, GFP_KERNEL); - if (pmlmepriv->wfd_probe_resp_ie == NULL) { - DBG_8723A("%s()-%d: kmalloc() ERROR!\n", - __func__, __LINE__); - return -EINVAL; - - } - rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_probe_resp_ie, - &pmlmepriv->wfd_probe_resp_ie_len); - } -#endif /* CONFIG_8723AU_P2P */ } return ret; @@ -4205,19 +3305,10 @@ int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net, char *buf, int len, { int ret = 0; uint wps_ielen = 0; -#ifdef CONFIG_8723AU_P2P - u32 p2p_ielen = 0; -#endif -#ifdef CONFIG_DEBUG_CFG80211 DBG_8723A("%s, ielen =%d\n", __func__, len); -#endif - if ((rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen) && (wps_ielen > 0)) -#ifdef CONFIG_8723AU_P2P - || (rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen) && (p2p_ielen > 0)) -#endif - ) { + if (rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen) && (wps_ielen > 0)) { if (net) { switch (type) { case 0x1: /* BEACON */ @@ -4280,11 +3371,6 @@ static struct cfg80211_ops rtw_cfg80211_ops = { .change_bss = cfg80211_rtw_change_bss, #endif /* CONFIG_8723AU_AP_MODE */ -#ifdef CONFIG_8723AU_P2P - .remain_on_channel = cfg80211_rtw_remain_on_channel, - .cancel_remain_on_channel = cfg80211_rtw_cancel_remain_on_channel, -#endif - .mgmt_tx = cfg80211_rtw_mgmt_tx, .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, }; @@ -4348,7 +3434,7 @@ void rtw_cfg80211_init_wiphy(struct rtw_adapter *padapter) struct wireless_dev *pwdev = padapter->rtw_wdev; struct wiphy *wiphy = pwdev->wiphy; - rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + rf_type = rtl8723a_get_rf_type(padapter); DBG_8723A("%s:rf_type =%d\n", __func__, rf_type); @@ -4387,9 +3473,6 @@ static void rtw_cfg80211_preinit_wiphy(struct rtw_adapter *padapter, BIT(NL80211_IFTYPE_ADHOC) | #ifdef CONFIG_8723AU_AP_MODE BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR) | -#endif -#if defined(CONFIG_8723AU_P2P) - BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | #endif 0; diff --git a/drivers/staging/rtl8723au/os_dep/mlme_linux.c b/drivers/staging/rtl8723au/os_dep/mlme_linux.c index b30d4d37556ab8..c0e79f56d2eb80 100644 --- a/drivers/staging/rtl8723au/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8723au/os_dep/mlme_linux.c @@ -20,22 +20,6 @@ #include #include -void rtw_os_indicate_connect23a(struct rtw_adapter *adapter) -{ - rtw_cfg80211_indicate_connect(adapter); - - netif_carrier_on(adapter->pnetdev); - - if (adapter->pid[2] != 0) - rtw_signal_process(adapter->pid[2], SIGALRM); -} - -void rtw_os_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted) -{ - rtw_cfg80211_indicate_scan_done(wdev_to_priv(padapter->rtw_wdev), - aborted); -} - static struct rt_pmkid_list backupPMKIDList[NUM_PMKID_CACHE]; void rtw_reset_securitypriv23a(struct rtw_adapter *adapter) @@ -52,9 +36,6 @@ void rtw_reset_securitypriv23a(struct rtw_adapter *adapter) * When the countermeasure is trigger, the driver have to * disconnect with AP for 60 seconds. */ - memset(&backupPMKIDList[0], 0x00, sizeof(struct rt_pmkid_list) * - NUM_PMKID_CACHE); - memcpy(&backupPMKIDList[0], &adapter->securitypriv.PMKIDList[0], sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; @@ -99,89 +80,3 @@ void rtw_os_indicate_disconnect23a(struct rtw_adapter *adapter) rtw_reset_securitypriv23a(adapter); } - -void rtw_report_sec_ie23a(struct rtw_adapter *adapter, u8 authmode, u8 *sec_ie) -{ - uint len; - u8 *buff, *p, i; - union iwreq_data wrqu; - - RT_TRACE(_module_mlme_osdep_c_, _drv_info_, - ("+rtw_report_sec_ie23a, authmode =%d\n", authmode)); - - buff = NULL; - if (authmode == _WPA_IE_ID_) { - RT_TRACE(_module_mlme_osdep_c_, _drv_info_, - ("rtw_report_sec_ie23a, authmode =%d\n", authmode)); - - buff = kzalloc(IW_CUSTOM_MAX, GFP_KERNEL); - if (!buff) - return; - p = buff; - - p += sprintf(p, "ASSOCINFO(ReqIEs ="); - - len = sec_ie[1]+2; - len = (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX; - - for (i = 0; i < len; i++) - p += sprintf(p, "%02x", sec_ie[i]); - - p += sprintf(p, ")"); - - memset(&wrqu, 0, sizeof(wrqu)); - - wrqu.data.length = p-buff; - - wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ? - wrqu.data.length : IW_CUSTOM_MAX; - - kfree(buff); - } -} - -#ifdef CONFIG_8723AU_AP_MODE -void rtw_indicate_sta_assoc_event23a(struct rtw_adapter *padapter, - struct sta_info *psta) -{ - struct sta_priv *pstapriv = &padapter->stapriv; - union iwreq_data wrqu; - - if (psta == NULL) - return; - - if (psta->aid > NUM_STA) - return; - - if (pstapriv->sta_aid[psta->aid - 1] != psta) - return; - - wrqu.addr.sa_family = ARPHRD_ETHER; - - memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN); - - DBG_8723A("+rtw_indicate_sta_assoc_event23a\n"); -} - -void rtw_indicate_sta_disassoc_event23a(struct rtw_adapter *padapter, - struct sta_info *psta) -{ - struct sta_priv *pstapriv = &padapter->stapriv; - union iwreq_data wrqu; - - if (psta == NULL) - return; - - if (psta->aid > NUM_STA) - return; - - if (pstapriv->sta_aid[psta->aid - 1] != psta) - return; - - wrqu.addr.sa_family = ARPHRD_ETHER; - - memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN); - - DBG_8723A("+rtw_indicate_sta_disassoc_event23a\n"); -} -#endif diff --git a/drivers/staging/rtl8723au/os_dep/os_intfs.c b/drivers/staging/rtl8723au/os_dep/os_intfs.c index 57eca7a45672b9..7c4c0a54b238c0 100644 --- a/drivers/staging/rtl8723au/os_dep/os_intfs.c +++ b/drivers/staging/rtl8723au/os_dep/os_intfs.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -66,10 +65,10 @@ static int rtw_acm_method;/* 0:By SW 1:By HW. */ static int rtw_wmm_enable = 1;/* default is set to enable the wmm. */ static int rtw_uapsd_enable; -int rtw_ht_enable23A = 1; +static int rtw_ht_enable = 1; /* 0 :diable, bit(0): enable 2.4g, bit(1): enable 5g */ -int rtw_cbw40_enable23A = 3; -int rtw_ampdu_enable23A = 1;/* for enable tx_ampdu */ +static int rtw_cbw40_enable = 3; +static int rtw_ampdu_enable = 1;/* for enable tx_ampdu */ /* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, default is set to enable * 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */ @@ -130,9 +129,9 @@ module_param(rtw_wmm_enable, int, 0644); module_param(rtw_vrtl_carrier_sense, int, 0644); module_param(rtw_vcs_type, int, 0644); module_param(rtw_busy_thresh, int, 0644); -module_param(rtw_ht_enable23A, int, 0644); -module_param(rtw_cbw40_enable23A, int, 0644); -module_param(rtw_ampdu_enable23A, int, 0644); +module_param(rtw_ht_enable, int, 0644); +module_param(rtw_cbw40_enable, int, 0644); +module_param(rtw_ampdu_enable, int, 0644); module_param(rtw_rx_stbc, int, 0644); module_param(rtw_ampdu_amsdu, int, 0644); @@ -203,9 +202,9 @@ static uint loadparam(struct rtw_adapter *padapter, struct net_device *pnetdev) /* UAPSD */ registry_par->wmm_enable = (u8)rtw_wmm_enable; registry_par->uapsd_enable = (u8)rtw_uapsd_enable; - registry_par->ht_enable = (u8)rtw_ht_enable23A; - registry_par->cbw40_enable = (u8)rtw_cbw40_enable23A; - registry_par->ampdu_enable = (u8)rtw_ampdu_enable23A; + registry_par->ht_enable = (u8)rtw_ht_enable; + registry_par->cbw40_enable = (u8)rtw_cbw40_enable; + registry_par->ampdu_enable = (u8)rtw_ampdu_enable; registry_par->rx_stbc = (u8)rtw_rx_stbc; registry_par->ampdu_amsdu = (u8)rtw_ampdu_amsdu; registry_par->lowrate_two_xmit = (u8)rtw_lowrate_two_xmit; @@ -312,14 +311,14 @@ static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, u16 rtw_recv_select_queue23a(struct sk_buff *skb) { struct iphdr *piphdr; + struct ethhdr *eth = (struct ethhdr *)skb->data; unsigned int dscp; - u16 eth_type; + u16 eth_type = get_unaligned_be16(ð->h_proto); u32 priority; u8 *pdata = skb->data; - memcpy(ð_type, pdata + (ETH_ALEN << 1), 2); switch (eth_type) { - case htons(ETH_P_IP): + case ETH_P_IP: piphdr = (struct iphdr *)(pdata + ETH_HLEN); dscp = piphdr->tos & 0xfc; priority = dscp >> 5; @@ -378,35 +377,6 @@ struct net_device *rtw_init_netdev23a(struct rtw_adapter *old_padapter) return pnetdev; } -u32 rtw_start_drv_threads23a(struct rtw_adapter *padapter) -{ - u32 _status = _SUCCESS; - - RT_TRACE(_module_os_intfs_c_, _drv_info_, - ("+rtw_start_drv_threads23a\n")); - padapter->cmdThread = kthread_run(rtw_cmd_thread23a, padapter, - "RTW_CMD_THREAD"); - if (IS_ERR(padapter->cmdThread)) { - _status = _FAIL; - } else { - /* wait for cmd_thread to run */ - down(&padapter->cmdpriv.terminate_cmdthread_sema); - } - rtw_hal_start_thread23a(padapter); - return _status; -} - -void rtw_stop_drv_threads23a(struct rtw_adapter *padapter) -{ - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_stop_drv_threads23a\n")); - - /* Below is to termindate rtw_cmd_thread23a & event_thread... */ - up(&padapter->cmdpriv.cmd_queue_sema); - if (padapter->cmdThread) - down(&padapter->cmdpriv.terminate_cmdthread_sema); - rtw_hal_stop_thread23a(padapter); -} - static u8 rtw_init_default_value(struct rtw_adapter *padapter) { struct registry_priv *pregistrypriv = &padapter->registrypriv; @@ -454,11 +424,7 @@ static u8 rtw_init_default_value(struct rtw_adapter *padapter) /* misc. */ padapter->bReadPortCancel = false; padapter->bWritePortCancel = false; - padapter->bRxRSSIDisplay = 0; padapter->bNotifyChannelChange = 0; -#ifdef CONFIG_8723AU_P2P - padapter->bShowGetP2PState = 1; -#endif return ret; } @@ -472,7 +438,6 @@ u8 rtw_reset_drv_sw23a(struct rtw_adapter *padapter) rtw_hal_def_value_init23a(padapter); padapter->bReadPortCancel = false; padapter->bWritePortCancel = false; - padapter->bRxRSSIDisplay = 0; pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ padapter->xmitpriv.tx_pkts = 0; @@ -521,17 +486,6 @@ u8 rtw_init_drv_sw23a(struct rtw_adapter *padapter) goto exit; } -#ifdef CONFIG_8723AU_P2P - rtw_init_wifidirect_timers23a(padapter); - init_wifidirect_info23a(padapter, P2P_ROLE_DISABLE); - reset_global_wifidirect_info23a(padapter); - rtw_init_cfg80211_wifidirect_info(padapter); -#ifdef CONFIG_8723AU_P2P - if (rtw_init_wifi_display_info(padapter) == _FAIL) - RT_TRACE(_module_os_intfs_c_, _drv_err_, - ("\n Can't init init_wifi_display_info\n")); -#endif -#endif /* CONFIG_8723AU_P2P */ if (init_mlme_ext_priv23a(padapter) == _FAIL) { RT_TRACE(_module_os_intfs_c_, _drv_err_, @@ -600,10 +554,6 @@ void rtw_cancel_all_timer23a(struct rtw_adapter *padapter) del_timer_sync(&padapter->pwrctrlpriv.pwr_state_check_timer); -#ifdef CONFIG_8723AU_P2P - del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer); -#endif /* CONFIG_8723AU_P2P */ - del_timer_sync(&padapter->mlmepriv.set_scan_deny_timer); rtw_clear_scan_deny(padapter); RT_TRACE(_module_os_intfs_c_, _drv_info_, @@ -616,26 +566,8 @@ void rtw_cancel_all_timer23a(struct rtw_adapter *padapter) u8 rtw_free_drv_sw23a(struct rtw_adapter *padapter) { -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo; -#endif - RT_TRACE(_module_os_intfs_c_, _drv_info_, ("==>rtw_free_drv_sw23a")); - /* we can call rtw_p2p_enable23a here, but: - * 1. rtw_p2p_enable23a may have IO operation - * 2. rtw_p2p_enable23a is bundled with wext interface - */ -#ifdef CONFIG_8723AU_P2P - pwdinfo = &padapter->wdinfo; - if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { - del_timer_sync(&pwdinfo->find_phase_timer); - del_timer_sync(&pwdinfo->restore_p2p_state_timer); - del_timer_sync(&pwdinfo->pre_tx_scan_timer); - rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE); - } -#endif - free_mlme_ext_priv23a(&padapter->mlmeextpriv); rtw_free_cmd_priv23a(&padapter->cmdpriv); @@ -656,12 +588,6 @@ u8 rtw_free_drv_sw23a(struct rtw_adapter *padapter) RT_TRACE(_module_os_intfs_c_, _drv_info_, ("<== rtw_free_drv_sw23a\n")); - /* free the old_pnetdev */ - if (padapter->rereg_nd_name_priv.old_pnetdev) { - free_netdev(padapter->rereg_nd_name_priv.old_pnetdev); - padapter->rereg_nd_name_priv.old_pnetdev = NULL; - } - /* clear pbuddy_adapter to avoid access wrong pointer. */ if (padapter->pbuddy_adapter != NULL) padapter->pbuddy_adapter->pbuddy_adapter = NULL; @@ -760,12 +686,6 @@ int netdev_open23a(struct net_device *pnetdev) DBG_8723A("MAC Address = "MAC_FMT"\n", MAC_ARG(pnetdev->dev_addr)); - status = rtw_start_drv_threads23a(padapter); - if (status == _FAIL) { - DBG_8723A("Initialize driver software resource Failed!\n"); - goto netdev_open23a_error; - } - if (init_hw_mlme_ext23a(padapter) == _FAIL) { DBG_8723A("can't init mlme_ext_priv\n"); goto netdev_open23a_error; @@ -887,7 +807,7 @@ void rtw_ips_pwr_down23a(struct rtw_adapter *padapter) void rtw_ips_dev_unload23a(struct rtw_adapter *padapter) { - rtw_hal_set_hwreg23a(padapter, HW_VAR_FIFO_CLEARN_UP, NULL); + rtl8723a_fifo_cleanup(padapter); if (padapter->intf_stop) padapter->intf_stop(padapter); @@ -941,17 +861,11 @@ static int netdev_close(struct net_device *pnetdev) /* s2-3. */ rtw_free_assoc_resources23a(padapter, 1); /* s2-4. */ - rtw_free_network_queue23a(padapter, true); + rtw_free_network_queue23a(padapter); /* Close LED */ rtw_led_control(padapter, LED_CTL_POWER_OFF); } -#ifdef CONFIG_8723AU_P2P - if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) - wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = false; - rtw_p2p_enable23a(padapter, P2P_ROLE_DISABLE); -#endif /* CONFIG_8723AU_P2P */ - rtw_scan_abort23a(padapter); /* set this at the end */ padapter->rtw_wdev->iftype = NL80211_IFTYPE_MONITOR; diff --git a/drivers/staging/rtl8723au/os_dep/osdep_service.c b/drivers/staging/rtl8723au/os_dep/osdep_service.c index 97fc27dce19c98..4a937a7f1d11fc 100644 --- a/drivers/staging/rtl8723au/os_dep/osdep_service.c +++ b/drivers/staging/rtl8723au/os_dep/osdep_service.c @@ -21,8 +21,6 @@ #include #include -#define RT_TAG ('1178') - /* * Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE23a * @return: one of RTW_STATUS_CODE23a @@ -71,17 +69,6 @@ u32 _rtw_queue_empty23a(struct rtw_queue *pqueue) return false; } -u64 rtw_modular6423a(u64 x, u64 y) -{ - return do_div(x, y); -} - -u64 rtw_division6423a(u64 x, u64 y) -{ - do_div(x, y); - return x; -} - /* rtw_cbuf_full23a - test if cbuf is full * @cbuf: pointer of struct rtw_cbuf * diff --git a/drivers/staging/rtl8723au/os_dep/recv_linux.c b/drivers/staging/rtl8723au/os_dep/recv_linux.c index 84402a589f258a..528ed9253b141e 100644 --- a/drivers/staging/rtl8723au/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723au/os_dep/recv_linux.c @@ -21,50 +21,9 @@ #include #include -#include #include -/* alloc os related resource in struct recv_frame */ -int rtw_os_recv_resource_alloc23a(struct rtw_adapter *padapter, - struct recv_frame *precvframe) -{ - int res = _SUCCESS; - - precvframe->pkt = NULL; - - return res; -} - -/* alloc os related resource in struct recv_buf */ -int rtw_os_recvbuf_resource_alloc23a(struct rtw_adapter *padapter, - struct recv_buf *precvbuf) -{ - int res = _SUCCESS; - - precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); - if (precvbuf->purb == NULL) - res = _FAIL; - - precvbuf->pskb = NULL; - - return res; -} - -/* free os related resource in struct recv_buf */ -int rtw_os_recvbuf_resource_free23a(struct rtw_adapter *padapter, - struct recv_buf *precvbuf) -{ - int ret = _SUCCESS; - - usb_free_urb(precvbuf->purb); - - if (precvbuf->pskb) - dev_kfree_skb_any(precvbuf->pskb); - - return ret; -} - void rtw_handle_tkip_mic_err23a(struct rtw_adapter *padapter, u8 bgroup) { enum nl80211_key_type key_type = 0; @@ -110,11 +69,6 @@ void rtw_handle_tkip_mic_err23a(struct rtw_adapter *padapter, u8 bgroup) wrqu.data.length = sizeof(ev); } -void rtw_hostapd_mlme_rx23a(struct rtw_adapter *padapter, - struct recv_frame *precv_frame) -{ -} - int rtw_recv_indicatepkt23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { @@ -205,18 +159,6 @@ int rtw_recv_indicatepkt23a(struct rtw_adapter *padapter, return _FAIL; } -void rtw_os_read_port23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf) -{ - struct recv_priv *precvpriv = &padapter->recvpriv; - - /* free skb in recv_buf */ - dev_kfree_skb_any(precvbuf->pskb); - - precvbuf->pskb = NULL; - - rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, precvbuf); -} - void rtw_init_recv_timer23a(struct recv_reorder_ctrl *preorder_ctrl) { setup_timer(&preorder_ctrl->reordering_ctrl_timer, diff --git a/drivers/staging/rtl8723au/os_dep/usb_intf.c b/drivers/staging/rtl8723au/os_dep/usb_intf.c index 612806e0de2e80..7d5233b993f15e 100644 --- a/drivers/staging/rtl8723au/os_dep/usb_intf.c +++ b/drivers/staging/rtl8723au/os_dep/usb_intf.c @@ -333,7 +333,7 @@ static void rtw_dev_unload(struct rtw_adapter *padapter) /* s4. */ if (!padapter->pwrctrlpriv.bInternalAutoSuspend) - rtw_stop_drv_threads23a(padapter); + flush_workqueue(padapter->cmdpriv.wq); /* s5. */ if (!padapter->bSurpriseRemoved) { @@ -353,6 +353,7 @@ int rtw_hw_suspend23a(struct rtw_adapter *padapter) { struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; struct net_device *pnetdev = padapter->pnetdev; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; if ((!padapter->bup) || (padapter->bDriverStopped) || (padapter->bSurpriseRemoved)) { @@ -380,26 +381,22 @@ int rtw_hw_suspend23a(struct rtw_adapter *padapter) /* s2-2. indicate disconnect to os */ /* rtw_indicate_disconnect23a(padapter); */ - { - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - _clr_fwstate_(pmlmepriv, _FW_LINKED); + if (check_fwstate(pmlmepriv, _FW_LINKED)) { + _clr_fwstate_(pmlmepriv, _FW_LINKED); - rtw_led_control(padapter, LED_CTL_NO_LINK); + rtw_led_control(padapter, LED_CTL_NO_LINK); - rtw_os_indicate_disconnect23a(padapter); + rtw_os_indicate_disconnect23a(padapter); - /* donnot enqueue cmd */ - rtw_lps_ctrl_wk_cmd23a(padapter, - LPS_CTRL_DISCONNECT, 0); - } + /* donnot enqueue cmd */ + rtw_lps_ctrl_wk_cmd23a(padapter, + LPS_CTRL_DISCONNECT, 0); } /* s2-3. */ rtw_free_assoc_resources23a(padapter, 1); /* s2-4. */ - rtw_free_network_queue23a(padapter, true); + rtw_free_network_queue23a(padapter); rtw_ips_dev_unload23a(padapter); pwrpriv->rf_pwrstate = rf_off; pwrpriv->bips_processing = false; @@ -503,13 +500,14 @@ static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) /* s2-3. */ rtw_free_assoc_resources23a(padapter, 1); /* s2-4. */ - rtw_free_network_queue23a(padapter, true); + rtw_free_network_queue23a(padapter); rtw_dev_unload(padapter); up(&pwrpriv->lock); if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) - rtw_indicate_scan_done23a(padapter, 1); + rtw_cfg80211_indicate_scan_done( + wdev_to_priv(padapter->rtw_wdev), true); if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) rtw_indicate_disconnect23a(padapter); @@ -565,7 +563,7 @@ int rtw_resume_process23a(struct rtw_adapter *padapter) if (padapter->pid[1] != 0) { DBG_8723A("pid[1]:%d\n", padapter->pid[1]); - rtw_signal_process(padapter->pid[1], SIGUSR2); + kill_pid(find_vpid(padapter->pid[1]), SIGUSR2, 1); } rtw23a_roaming(padapter, NULL); @@ -624,8 +622,7 @@ static struct rtw_adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, padapter->intf_start = &usb_intf_start; padapter->intf_stop = &usb_intf_stop; - /* step init_io_priv */ - rtw_init_io_priv23a(padapter, usb_set_intf_ops); + rtl8723au_set_intf_ops(padapter); /* step read_chip_version */ rtw_hal_read_chip_version23a(padapter); @@ -664,10 +661,6 @@ static struct rtw_adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, /* set mac addr */ rtw_macaddr_cfg23a(padapter->eeprompriv.mac_addr); -#ifdef CONFIG_8723AU_P2P - rtw_init_wifidirect_addrs23a(padapter, padapter->eeprompriv.mac_addr, - padapter->eeprompriv.mac_addr); -#endif DBG_8723A("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n", padapter->bDriverStopped, padapter->bSurpriseRemoved, diff --git a/drivers/staging/rtl8723au/os_dep/usb_ops_linux.c b/drivers/staging/rtl8723au/os_dep/usb_ops_linux.c index c49160e477d8d0..b88f72f0f06b53 100644 --- a/drivers/staging/rtl8723au/os_dep/usb_ops_linux.c +++ b/drivers/staging/rtl8723au/os_dep/usb_ops_linux.c @@ -41,18 +41,17 @@ struct zero_bulkout_context { void *padapter; }; -void usb_read_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) +void usb_read_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *rmem) { } -void usb_write_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) +void usb_write_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *wmem) { } -void usb_read_port_cancel23a(struct intf_hdl *pintfhdl) +void usb_read_port_cancel23a(struct rtw_adapter *padapter) { struct recv_buf *precvbuf; - struct rtw_adapter *padapter = pintfhdl->padapter; int i; precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf; @@ -161,11 +160,10 @@ static void usb_write_port23a_complete(struct urb *purb, struct pt_regs *regs) tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); } -u32 usb_write_port23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, - struct xmit_buf *pxmitbuf) +u32 usb_write_port23a(struct rtw_adapter *padapter, u32 addr, u32 cnt, + struct xmit_buf *pxmitbuf) { struct urb *purb = NULL; - struct rtw_adapter *padapter = (struct rtw_adapter *)pintfhdl->padapter; struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; @@ -255,9 +253,8 @@ u32 usb_write_port23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, return ret; } -void usb_write_port23a_cancel(struct intf_hdl *pintfhdl) +void usb_write_port23a_cancel(struct rtw_adapter *padapter) { - struct rtw_adapter *padapter = pintfhdl->padapter; struct xmit_buf *pxmitbuf; struct list_head *plist; int j; diff --git a/drivers/staging/rtl8723au/os_dep/xmit_linux.c b/drivers/staging/rtl8723au/os_dep/xmit_linux.c index e1c6fc7462333e..69f88848715abc 100644 --- a/drivers/staging/rtl8723au/os_dep/xmit_linux.c +++ b/drivers/staging/rtl8723au/os_dep/xmit_linux.c @@ -24,47 +24,6 @@ #include #include -uint rtw_remainder_len23a(struct pkt_file *pfile) -{ - return pfile->buf_len - ((unsigned long)(pfile->cur_addr) - - (unsigned long)(pfile->buf_start)); -} - -void _rtw_open_pktfile23a(struct sk_buff *pktptr, struct pkt_file *pfile) -{ - pfile->pkt = pktptr; - pfile->buf_start = pktptr->data; - pfile->cur_addr = pktptr->data; - pfile->buf_len = pktptr->len; - pfile->pkt_len = pktptr->len; - - pfile->cur_buffer = pfile->buf_start; -} - -uint _rtw_pktfile_read23a(struct pkt_file *pfile, u8 *rmem, uint rlen) -{ - uint len = 0; - - len = rtw_remainder_len23a(pfile); - len = (rlen > len) ? len : rlen; - - if (rmem) - skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, - rmem, len); - - pfile->cur_addr += len; - pfile->pkt_len -= len; - - return len; -} - -int rtw_endofpktfile23a(struct pkt_file *pfile) -{ - if (pfile->pkt_len == 0) - return true; - return false; -} - int rtw_os_xmit_resource_alloc23a(struct rtw_adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz) { diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c b/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c index 115908928ae429..d2381794ecc944 100644 --- a/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c +++ b/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c @@ -12,7 +12,7 @@ * include files **************************************************************/ #include "halbt_precomp.h" -#if 1 + /************************************************************** * Global variables, these are static variables **************************************************************/ @@ -21,14 +21,14 @@ static struct coex_dm_8192e_2ant *coex_dm = &glcoex_dm_8192e_2ant; static struct coex_sta_8192e_2ant glcoex_sta_8192e_2ant; static struct coex_sta_8192e_2ant *coex_sta = &glcoex_sta_8192e_2ant; -const char *const GLBtInfoSrc8192e2Ant[]={ +static const char *const GLBtInfoSrc8192e2Ant[] = { "BT Info[wifi fw]", "BT Info[bt rsp]", "BT Info[bt auto report]", }; -u32 glcoex_ver_date_8192e_2ant = 20130902; -u32 glcoex_ver_8192e_2ant = 0x34; +static u32 glcoex_ver_date_8192e_2ant = 20130902; +static u32 glcoex_ver_8192e_2ant = 0x34; /************************************************************** * local function proto type if needed @@ -36,13 +36,12 @@ u32 glcoex_ver_8192e_2ant = 0x34; /************************************************************** * local function start with halbtc8192e2ant_ **************************************************************/ -u8 halbtc8192e2ant_btrssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +static u8 halbtc8192e2ant_btrssi_state(u8 level_num, u8 rssi_thresh, + u8 rssi_thresh1) { - int btrssi=0; + int btrssi = coex_sta->bt_rssi; u8 btrssi_state = coex_sta->pre_bt_rssi_state; - btrssi = coex_sta->bt_rssi; - if (level_num == 2) { if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { @@ -82,7 +81,7 @@ u8 halbtc8192e2ant_btrssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, "BT Rssi pre state=LOW\n"); - if(btrssi >= (rssi_thresh + + if (btrssi >= (rssi_thresh + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { btrssi_state = BTC_RSSI_STATE_MEDIUM; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, @@ -132,8 +131,9 @@ u8 halbtc8192e2ant_btrssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) return btrssi_state; } -u8 halbtc8192e2ant_wifirssi_state(struct btc_coexist * btcoexist, u8 index, - u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +static u8 halbtc8192e2ant_wifirssi_state(struct btc_coexist *btcoexist, + u8 index, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) { int wifirssi = 0; u8 wifirssi_state = coex_sta->pre_wifi_rssi_state[index]; @@ -156,8 +156,8 @@ u8 halbtc8192e2ant_wifirssi_state(struct btc_coexist * btcoexist, u8 index, BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, "wifi RSSI state stay at Low\n"); - } - } else { + } + } else { if (wifirssi < rssi_thresh) { wifirssi_state = BTC_RSSI_STATE_LOW; BTC_PRINT(BTC_MSG_ALGORITHM, @@ -234,10 +234,10 @@ u8 halbtc8192e2ant_wifirssi_state(struct btc_coexist * btcoexist, u8 index, return wifirssi_state; } -void halbtc8192e2ant_monitor_bt_enable_disable(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_monitor_bt_enable_disable(struct btc_coexist *btcoexist) { - static bool pre_bt_disabled = false; - static u32 bt_disable_cnt = 0; + static bool pre_bt_disabled; + static u32 bt_disable_cnt; bool bt_active = true, bt_disabled = false; /* This function check if bt is disabled */ @@ -283,7 +283,7 @@ void halbtc8192e2ant_monitor_bt_enable_disable(struct btc_coexist *btcoexist) } } -u32 halbtc8192e2ant_decidera_mask(struct btc_coexist *btcoexist, +static u32 halbtc8192e2ant_decidera_mask(struct btc_coexist *btcoexist, u8 sstype, u32 ra_masktype) { u32 disra_mask = 0x0; @@ -296,13 +296,13 @@ u32 halbtc8192e2ant_decidera_mask(struct btc_coexist *btcoexist, disra_mask = 0xfff00000;/* disable 2ss */ break; case 1: /* disable cck 1/2 */ - if(sstype == 2) + if (sstype == 2) disra_mask = 0x00000003;/* enable 2ss */ else disra_mask = 0xfff00003;/* disable 2ss */ break; case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ - if(sstype == 2) + if (sstype == 2) disra_mask = 0x0001f1f7;/* enable 2ss */ else disra_mask = 0xfff1f1f7;/* disable 2ss */ @@ -314,8 +314,8 @@ u32 halbtc8192e2ant_decidera_mask(struct btc_coexist *btcoexist, return disra_mask; } -void halbtc8192e2ant_Updatera_mask(struct btc_coexist *btcoexist, - bool force_exec, u32 dis_ratemask) +static void halbtc8192e2ant_Updatera_mask(struct btc_coexist *btcoexist, + bool force_exec, u32 dis_ratemask) { coex_dm->curra_mask = dis_ratemask; @@ -325,8 +325,8 @@ void halbtc8192e2ant_Updatera_mask(struct btc_coexist *btcoexist, coex_dm->prera_mask = coex_dm->curra_mask; } -void halbtc8192e2ant_autorate_fallback_retry(struct btc_coexist *btcoexist, - bool force_exec, u8 type) +static void halbtc8192e2ant_autorate_fallback_retry(struct btc_coexist *btcoexist, + bool force_exec, u8 type) { bool wifi_under_bmode = false; @@ -364,32 +364,32 @@ void halbtc8192e2ant_autorate_fallback_retry(struct btc_coexist *btcoexist, coex_dm->pre_arfrtype = coex_dm->cur_arfrtype; } -void halbtc8192e2ant_retrylimit(struct btc_coexist *btcoexist, - bool force_exec, u8 type) +static void halbtc8192e2ant_retrylimit(struct btc_coexist *btcoexist, + bool force_exec, u8 type) { coex_dm->cur_retrylimit_type = type; if (force_exec || (coex_dm->pre_retrylimit_type != coex_dm->cur_retrylimit_type)) { switch (coex_dm->cur_retrylimit_type) { - case 0: /* normal mode */ - btcoexist->btc_write_2byte(btcoexist, 0x42a, - coex_dm->backup_retrylimit); - break; - case 1: /* retry limit=8 */ - btcoexist->btc_write_2byte(btcoexist, 0x42a, - 0x0808); - break; - default: - break; + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retrylimit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; } } coex_dm->pre_retrylimit_type = coex_dm->cur_retrylimit_type; } -void halbtc8192e2ant_ampdu_maxtime(struct btc_coexist *btcoexist, - bool force_exec, u8 type) +static void halbtc8192e2ant_ampdu_maxtime(struct btc_coexist *btcoexist, + bool force_exec, u8 type) { coex_dm->cur_ampdutime_type = type; @@ -411,9 +411,10 @@ void halbtc8192e2ant_ampdu_maxtime(struct btc_coexist *btcoexist, coex_dm->pre_ampdutime_type = coex_dm->cur_ampdutime_type; } -void halbtc8192e2ant_limited_tx(struct btc_coexist *btcoexist, - bool force_exec, u8 ra_masktype, u8 arfr_type, - u8 retrylimit_type, u8 ampdutime_type) +static void halbtc8192e2ant_limited_tx(struct btc_coexist *btcoexist, + bool force_exec, u8 ra_masktype, + u8 arfr_type, u8 retrylimit_type, + u8 ampdutime_type) { u32 disra_mask = 0x0; @@ -429,10 +430,10 @@ void halbtc8192e2ant_limited_tx(struct btc_coexist *btcoexist, halbtc8192e2ant_ampdu_maxtime(btcoexist, force_exec, ampdutime_type); } -void halbtc8192e2ant_limited_rx(struct btc_coexist *btcoexist, - bool force_exec, bool rej_ap_agg_pkt, - bool b_bt_ctrl_agg_buf_size, - u8 agg_buf_size) +static void halbtc8192e2ant_limited_rx(struct btc_coexist *btcoexist, + bool force_exec, bool rej_ap_agg_pkt, + bool b_bt_ctrl_agg_buf_size, + u8 agg_buf_size) { bool reject_rx_agg = rej_ap_agg_pkt; bool bt_ctrl_rx_agg_size = b_bt_ctrl_agg_buf_size; @@ -455,7 +456,7 @@ void halbtc8192e2ant_limited_rx(struct btc_coexist *btcoexist, } -void halbtc8192e2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) { u32 reg_hp_txrx, reg_lp_txrx, u32tmp; u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; @@ -487,9 +488,9 @@ void halbtc8192e2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); } -void halbtc8192e2ant_querybt_info(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_querybt_info(struct btc_coexist *btcoexist) { - u8 h2c_parameter[1] ={0}; + u8 h2c_parameter[1] = {0}; coex_sta->c2h_bt_info_req_sent = true; @@ -502,39 +503,7 @@ void halbtc8192e2ant_querybt_info(struct btc_coexist *btcoexist) btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); } -bool halbtc8192e2ant_iswifi_status_changed(struct btc_coexist *btcoexist) -{ - static bool pre_wifi_busy = false; - static bool pre_under_4way = false, pre_bt_hson = false; - bool wifi_busy = false, under_4way = false, bt_hson = false; - bool wifi_connected = false; - - btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, - &wifi_connected); - btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); - btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); - btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, - &under_4way); - - if (wifi_connected) { - if (wifi_busy != pre_wifi_busy) { - pre_wifi_busy = wifi_busy; - return true; - } - if (under_4way != pre_under_4way) { - pre_under_4way = under_4way; - return true; - } - if (bt_hson != pre_bt_hson) { - pre_bt_hson = bt_hson; - return true; - } - } - - return false; -} - -void halbtc8192e2ant_update_btlink_info(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_update_btlink_info(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; bool bt_hson = false; @@ -590,11 +559,11 @@ void halbtc8192e2ant_update_btlink_info(struct btc_coexist *btcoexist) bt_link_info->hid_only = false; } -u8 halbtc8192e2ant_action_algorithm(struct btc_coexist *btcoexist) +static u8 halbtc8192e2ant_action_algorithm(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; struct btc_stack_info *stack_info = &btcoexist->stack_info; - bool bt_hson=false; + bool bt_hson = false; u8 algorithm = BT_8192E_2ANT_COEX_ALGO_UNDEFINED; u8 numOfDiffProfile = 0; @@ -777,10 +746,10 @@ u8 halbtc8192e2ant_action_algorithm(struct btc_coexist *btcoexist) return algorithm; } -void halbtc8192e2ant_setfw_dac_swinglevel(struct btc_coexist *btcoexist, - u8 dac_swinglvl) +static void halbtc8192e2ant_setfw_dac_swinglevel(struct btc_coexist *btcoexist, + u8 dac_swinglvl) { - u8 h2c_parameter[1] ={0}; + u8 h2c_parameter[1] = {0}; /* There are several type of dacswing * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ @@ -794,10 +763,10 @@ void halbtc8192e2ant_setfw_dac_swinglevel(struct btc_coexist *btcoexist, btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); } -void halbtc8192e2ant_set_fwdec_btpwr(struct btc_coexist *btcoexist, - u8 dec_btpwr_lvl) +static void halbtc8192e2ant_set_fwdec_btpwr(struct btc_coexist *btcoexist, + u8 dec_btpwr_lvl) { - u8 h2c_parameter[1] ={0}; + u8 h2c_parameter[1] = {0}; h2c_parameter[0] = dec_btpwr_lvl; @@ -808,12 +777,12 @@ void halbtc8192e2ant_set_fwdec_btpwr(struct btc_coexist *btcoexist, btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); } -void halbtc8192e2ant_dec_btpwr(struct btc_coexist *btcoexist, - bool force_exec, u8 dec_btpwr_lvl) +static void halbtc8192e2ant_dec_btpwr(struct btc_coexist *btcoexist, + bool force_exec, u8 dec_btpwr_lvl) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, "[BTCoex], %s Dec BT power level = %d\n", - (force_exec? "force to":""), dec_btpwr_lvl); + (force_exec ? "force to":""), dec_btpwr_lvl); coex_dm->cur_dec_bt_pwr = dec_btpwr_lvl; if (!force_exec) { @@ -826,10 +795,10 @@ void halbtc8192e2ant_dec_btpwr(struct btc_coexist *btcoexist, coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr; } -void halbtc8192e2ant_set_bt_autoreport(struct btc_coexist *btcoexist, - bool enable_autoreport) +static void halbtc8192e2ant_set_bt_autoreport(struct btc_coexist *btcoexist, + bool enable_autoreport) { - u8 h2c_parameter[1] ={0}; + u8 h2c_parameter[1] = {0}; h2c_parameter[0] = 0; @@ -838,19 +807,20 @@ void halbtc8192e2ant_set_bt_autoreport(struct btc_coexist *btcoexist, BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, "[BTCoex], BT FW auto report : %s, FW write 0x68=0x%x\n", - (enable_autoreport? "Enabled!!":"Disabled!!"), + (enable_autoreport ? "Enabled!!":"Disabled!!"), h2c_parameter[0]); btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); } -void halbtc8192e2ant_bt_autoreport(struct btc_coexist *btcoexist, - bool force_exec, bool enable_autoreport) +static void halbtc8192e2ant_bt_autoreport(struct btc_coexist *btcoexist, + bool force_exec, + bool enable_autoreport) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, "[BTCoex], %s BT Auto report = %s\n", - (force_exec? "force to":""), - ((enable_autoreport)? "Enabled":"Disabled")); + (force_exec ? "force to":""), + ((enable_autoreport) ? "Enabled":"Disabled")); coex_dm->cur_bt_auto_report = enable_autoreport; if (!force_exec) { @@ -868,12 +838,12 @@ void halbtc8192e2ant_bt_autoreport(struct btc_coexist *btcoexist, coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; } -void halbtc8192e2ant_fw_dac_swinglvl(struct btc_coexist *btcoexist, - bool force_exec, u8 fw_dac_swinglvl) +static void halbtc8192e2ant_fw_dac_swinglvl(struct btc_coexist *btcoexist, + bool force_exec, u8 fw_dac_swinglvl) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, "[BTCoex], %s set FW Dac Swing level = %d\n", - (force_exec? "force to":""), fw_dac_swinglvl); + (force_exec ? "force to":""), fw_dac_swinglvl); coex_dm->cur_fw_dac_swing_lvl = fw_dac_swinglvl; if (!force_exec) { @@ -893,8 +863,8 @@ void halbtc8192e2ant_fw_dac_swinglvl(struct btc_coexist *btcoexist, coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; } -void halbtc8192e2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist, - bool rx_rf_shrink_on) +static void halbtc8192e2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist, + bool rx_rf_shrink_on) { if (rx_rf_shrink_on) { /* Shrink RF Rx LPF corner */ @@ -915,12 +885,12 @@ void halbtc8192e2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist, } } -void halbtc8192e2ant_rf_shrink(struct btc_coexist *btcoexist, - bool force_exec, bool rx_rf_shrink_on) +static void halbtc8192e2ant_rf_shrink(struct btc_coexist *btcoexist, + bool force_exec, bool rx_rf_shrink_on) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, "[BTCoex], %s turn Rx RF Shrink = %s\n", - (force_exec? "force to":""), ((rx_rf_shrink_on)? "ON":"OFF")); + (force_exec ? "force to":""), ((rx_rf_shrink_on) ? "ON":"OFF")); coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; if (!force_exec) { @@ -939,56 +909,8 @@ void halbtc8192e2ant_rf_shrink(struct btc_coexist *btcoexist, coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; } -void halbtc8192e2ant_set_sw_penalty_tx_rateadaptive( - struct btc_coexist *btcoexist, - bool low_penalty_ra) -{ - u8 h2c_parameter[6] ={0}; - - h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty */ - - if (low_penalty_ra) { - h2c_parameter[1] |= BIT0; - /* normal rate except MCS7/6/5, OFDM54/48/36 */ - h2c_parameter[2] = 0x00; - h2c_parameter[3] = 0xf7; /* MCS7 or OFDM54 */ - h2c_parameter[4] = 0xf8; /* MCS6 or OFDM48 */ - h2c_parameter[5] = 0xf9; /* MCS5 or OFDM36 */ - } - - BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, - "[BTCoex], set WiFi Low-Penalty Retry: %s", - (low_penalty_ra? "ON!!":"OFF!!")); - - btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); -} - -void halbtc8192e2ant_low_penalty_ra(struct btc_coexist *btcoexist, - bool force_exec, bool low_penalty_ra) -{ - BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, - "[BTCoex], %s turn LowPenaltyRA = %s\n", - (force_exec? "force to":""), ((low_penalty_ra)? "ON":"OFF")); - coex_dm->cur_low_penalty_ra = low_penalty_ra; - - if (!force_exec) { - BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, - "[BTCoex] bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", - coex_dm->pre_low_penalty_ra, - coex_dm->cur_low_penalty_ra); - - if (coex_dm->pre_low_penalty_ra == - coex_dm->cur_low_penalty_ra) - return; - } - halbtc8192e2ant_set_sw_penalty_tx_rateadaptive(btcoexist, - coex_dm->cur_low_penalty_ra); - - coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; -} - -void halbtc8192e2ant_set_dac_swingreg(struct btc_coexist *btcoexist, - u32 level) +static void halbtc8192e2ant_set_dac_swingreg(struct btc_coexist *btcoexist, + u32 level) { u8 val = (u8)level; @@ -997,9 +919,9 @@ void halbtc8192e2ant_set_dac_swingreg(struct btc_coexist *btcoexist, btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val); } -void halbtc8192e2ant_setsw_fulltime_dacswing(struct btc_coexist *btcoexist, - bool sw_dac_swingon, - u32 sw_dac_swinglvl) +static void halbtc8192e2ant_setsw_fulltime_dacswing(struct btc_coexist *btcoexist, + bool sw_dac_swingon, + u32 sw_dac_swinglvl) { if (sw_dac_swingon) halbtc8192e2ant_set_dac_swingreg(btcoexist, sw_dac_swinglvl); @@ -1007,15 +929,14 @@ void halbtc8192e2ant_setsw_fulltime_dacswing(struct btc_coexist *btcoexist, halbtc8192e2ant_set_dac_swingreg(btcoexist, 0x18); } - -void halbtc8192e2ant_DacSwing(struct btc_coexist *btcoexist, - bool force_exec, bool dac_swingon, - u32 dac_swinglvl) +static void halbtc8192e2ant_DacSwing(struct btc_coexist *btcoexist, + bool force_exec, bool dac_swingon, + u32 dac_swinglvl) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, "[BTCoex], %s turn DacSwing=%s, dac_swinglvl=0x%x\n", - (force_exec? "force to":""), - ((dac_swingon)? "ON":"OFF"), dac_swinglvl); + (force_exec ? "force to":""), + ((dac_swingon) ? "ON":"OFF"), dac_swinglvl); coex_dm->cur_dac_swing_on = dac_swingon; coex_dm->cur_dac_swing_lvl = dac_swinglvl; @@ -1041,46 +962,8 @@ void halbtc8192e2ant_DacSwing(struct btc_coexist *btcoexist, coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; } -void halbtc8192e2ant_set_adc_backoff(struct btc_coexist *btcoexist, - bool adc_backoff) -{ - if(adc_backoff) - { - BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, - "[BTCoex], BB BackOff Level On!\n"); - btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc05, 0x30, 0x3); - } - else - { - BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, - "[BTCoex], BB BackOff Level Off!\n"); - btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc05, 0x30, 0x1); - } -} - -void halbtc8192e2ant_adc_backoff(struct btc_coexist *btcoexist, - bool force_exec, bool adc_backoff) -{ - BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, - "[BTCoex], %s turn AdcBackOff = %s\n", - (force_exec? "force to":""), ((adc_backoff)? "ON":"OFF")); - coex_dm->cur_adc_back_off = adc_backoff; - - if (!force_exec) { - BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, - "[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", - coex_dm->pre_adc_back_off, coex_dm->cur_adc_back_off); - - if (coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off) - return; - } - halbtc8192e2ant_set_adc_backoff(btcoexist, coex_dm->cur_adc_back_off); - - coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off; -} - -void halbtc8192e2ant_set_agc_table(struct btc_coexist *btcoexist, - bool agc_table_en) +static void halbtc8192e2ant_set_agc_table(struct btc_coexist *btcoexist, + bool agc_table_en) { /* BB AGC Gain Table */ @@ -1096,7 +979,7 @@ void halbtc8192e2ant_set_agc_table(struct btc_coexist *btcoexist, } else { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, "[BTCoex], BB Agc Table Off!\n"); - btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001); btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001); btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001); btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001); @@ -1105,13 +988,13 @@ void halbtc8192e2ant_set_agc_table(struct btc_coexist *btcoexist, } } -void halbtc8192e2ant_AgcTable(struct btc_coexist *btcoexist, - bool force_exec, bool agc_table_en) +static void halbtc8192e2ant_AgcTable(struct btc_coexist *btcoexist, + bool force_exec, bool agc_table_en) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, "[BTCoex], %s %s Agc Table\n", - (force_exec? "force to":""), - ((agc_table_en)? "Enable":"Disable")); + (force_exec ? "force to":""), + ((agc_table_en) ? "Enable":"Disable")); coex_dm->cur_agc_table_en = agc_table_en; if (!force_exec) { @@ -1127,9 +1010,9 @@ void halbtc8192e2ant_AgcTable(struct btc_coexist *btcoexist, coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; } -void halbtc8192e2ant_set_coex_table(struct btc_coexist *btcoexist, - u32 val0x6c0, u32 val0x6c4, - u32 val0x6c8, u8 val0x6cc) +static void halbtc8192e2ant_set_coex_table(struct btc_coexist *btcoexist, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, "[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0); @@ -1148,13 +1031,14 @@ void halbtc8192e2ant_set_coex_table(struct btc_coexist *btcoexist, btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); } -void halbtc8192e2ant_coex_table(struct btc_coexist *btcoexist, bool force_exec, - u32 val0x6c0, u32 val0x6c4, - u32 val0x6c8, u8 val0x6cc) +static void halbtc8192e2ant_coex_table(struct btc_coexist *btcoexist, + bool force_exec, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, "[BTCoex], %s write Coex Table 0x6c0=0x%x, ", - (force_exec? "force to":""), val0x6c0); + (force_exec ? "force to":""), val0x6c0); BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, "0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", val0x6c4, val0x6c8, val0x6cc); @@ -1171,7 +1055,7 @@ void halbtc8192e2ant_coex_table(struct btc_coexist *btcoexist, bool force_exec, "preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc); BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, - "[BTCoex], curVal0x6c0=0x%x, curVal0x6c4=0x%x, \n", + "[BTCoex], curVal0x6c0=0x%x, curVal0x6c4=0x%x,\n", coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4); BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, "curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", @@ -1192,8 +1076,8 @@ void halbtc8192e2ant_coex_table(struct btc_coexist *btcoexist, bool force_exec, coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; } -void halbtc8192e2ant_coex_table_with_type(struct btc_coexist *btcoexist, - bool force_exec, u8 type) +static void halbtc8192e2ant_coex_table_with_type(struct btc_coexist *btcoexist, + bool force_exec, u8 type) { switch (type) { case 0: @@ -1221,10 +1105,10 @@ void halbtc8192e2ant_coex_table_with_type(struct btc_coexist *btcoexist, } } -void halbtc8192e2ant_set_fw_ignore_wlanact(struct btc_coexist *btcoexist, - bool enable) +static void halbtc8192e2ant_set_fw_ignore_wlanact(struct btc_coexist *btcoexist, + bool enable) { - u8 h2c_parameter[1] ={0}; + u8 h2c_parameter[1] = {0}; if (enable) h2c_parameter[0] |= BIT0; /* function enable */ @@ -1236,12 +1120,12 @@ void halbtc8192e2ant_set_fw_ignore_wlanact(struct btc_coexist *btcoexist, btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); } -void halbtc8192e2ant_IgnoreWlanAct(struct btc_coexist *btcoexist, - bool force_exec, bool enable) +static void halbtc8192e2ant_IgnoreWlanAct(struct btc_coexist *btcoexist, + bool force_exec, bool enable) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, "[BTCoex], %s turn Ignore WlanAct %s\n", - (force_exec? "force to":""), (enable? "ON":"OFF")); + (force_exec ? "force to":""), (enable ? "ON":"OFF")); coex_dm->cur_ignore_wlan_act = enable; if (!force_exec) { @@ -1261,10 +1145,10 @@ void halbtc8192e2ant_IgnoreWlanAct(struct btc_coexist *btcoexist, coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; } -void halbtc8192e2ant_SetFwPstdma(struct btc_coexist *btcoexist, u8 byte1, - u8 byte2, u8 byte3, u8 byte4, u8 byte5) +static void halbtc8192e2ant_SetFwPstdma(struct btc_coexist *btcoexist, u8 byte1, + u8 byte2, u8 byte3, u8 byte4, u8 byte5) { - u8 h2c_parameter[5] ={0}; + u8 h2c_parameter[5] = {0}; h2c_parameter[0] = byte1; h2c_parameter[1] = byte2; @@ -1287,29 +1171,33 @@ void halbtc8192e2ant_SetFwPstdma(struct btc_coexist *btcoexist, u8 byte1, btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); } -void halbtc8192e2ant_sw_mechanism1(struct btc_coexist *btcoexist, - bool shrink_rx_lpf, bool low_penalty_ra, - bool limited_dig, bool btlan_constrain) +static void halbtc8192e2ant_sw_mechanism1(struct btc_coexist *btcoexist, + bool shrink_rx_lpf, + bool low_penalty_ra, + bool limited_dig, + bool btlan_constrain) { halbtc8192e2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); } -void halbtc8192e2ant_sw_mechanism2(struct btc_coexist *btcoexist, - bool agc_table_shift, bool adc_backoff, - bool sw_dac_swing, u32 dac_swinglvl) +static void halbtc8192e2ant_sw_mechanism2(struct btc_coexist *btcoexist, + bool agc_table_shift, + bool adc_backoff, + bool sw_dac_swing, + u32 dac_swinglvl) { halbtc8192e2ant_AgcTable(btcoexist, NORMAL_EXEC, agc_table_shift); halbtc8192e2ant_DacSwing(btcoexist, NORMAL_EXEC, sw_dac_swing, dac_swinglvl); } -void halbtc8192e2ant_ps_tdma(struct btc_coexist *btcoexist, - bool force_exec, bool turn_on, u8 type) +static void halbtc8192e2ant_ps_tdma(struct btc_coexist *btcoexist, + bool force_exec, bool turn_on, u8 type) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, "[BTCoex], %s turn %s PS TDMA, type=%d\n", - (force_exec? "force to":""), (turn_on? "ON":"OFF"), type); + (force_exec ? "force to":""), (turn_on ? "ON":"OFF"), type); coex_dm->cur_ps_tdma_on = turn_on; coex_dm->cur_ps_tdma = type; @@ -1440,7 +1328,8 @@ void halbtc8192e2ant_ps_tdma(struct btc_coexist *btcoexist, coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; } -void halbtc8192e2ant_set_switch_sstype(struct btc_coexist *btcoexist, u8 sstype) +static void halbtc8192e2ant_set_switch_sstype(struct btc_coexist *btcoexist, + u8 sstype) { u8 mimops = BTC_MIMO_PS_DYNAMIC; u32 disra_mask = 0x0; @@ -1461,7 +1350,7 @@ void halbtc8192e2ant_set_switch_sstype(struct btc_coexist *btcoexist, u8 sstype) /* switch cck patch */ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x1); btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x81); - mimops=BTC_MIMO_PS_STATIC; + mimops = BTC_MIMO_PS_STATIC; } else if (sstype == 2) { halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x33); @@ -1469,18 +1358,18 @@ void halbtc8192e2ant_set_switch_sstype(struct btc_coexist *btcoexist, u8 sstype) btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81121313); btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x0); btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x41); - mimops=BTC_MIMO_PS_DYNAMIC; + mimops = BTC_MIMO_PS_DYNAMIC; } /* set rx 1ss or 2ss */ btcoexist->btc_set(btcoexist, BTC_SET_ACT_SEND_MIMO_PS, &mimops); } -void halbtc8192e2ant_switch_sstype(struct btc_coexist *btcoexist, +static void halbtc8192e2ant_switch_sstype(struct btc_coexist *btcoexist, bool force_exec, u8 new_sstype) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], %s Switch SS Type = %d\n", - (force_exec? "force to":""), new_sstype); + (force_exec ? "force to":""), new_sstype); coex_dm->cur_sstype = new_sstype; if (!force_exec) { @@ -1492,7 +1381,7 @@ void halbtc8192e2ant_switch_sstype(struct btc_coexist *btcoexist, coex_dm->pre_sstype = coex_dm->cur_sstype; } -void halbtc8192e2ant_coex_alloff(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_coex_alloff(struct btc_coexist *btcoexist) { /* fw all off */ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); @@ -1507,7 +1396,7 @@ void halbtc8192e2ant_coex_alloff(struct btc_coexist *btcoexist) halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); } -void halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist) { /* force to reset coex mechanism */ @@ -1522,7 +1411,7 @@ void halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist) halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); } -void halbtc8192e2ant_action_bt_inquiry(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_action_bt_inquiry(struct btc_coexist *btcoexist) { bool low_pwr_disable = true; @@ -1540,7 +1429,7 @@ void halbtc8192e2ant_action_bt_inquiry(struct btc_coexist *btcoexist) halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); } -bool halbtc8192e2ant_is_common_action(struct btc_coexist *btcoexist) +static bool halbtc8192e2ant_is_common_action(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; bool common = false, wifi_connected = false, wifi_busy = false; @@ -1586,7 +1475,7 @@ bool halbtc8192e2ant_is_common_action(struct btc_coexist *btcoexist) halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); - halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); @@ -1685,9 +1574,9 @@ bool halbtc8192e2ant_is_common_action(struct btc_coexist *btcoexist) return common; } -void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, - bool sco_hid, bool tx_pause, - u8 max_interval) +static void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, + bool sco_hid, bool tx_pause, + u8 max_interval) { static int up, dn, m, n, wait_cnt; /* 0: no change, +1: increase WiFi duration, @@ -1799,7 +1688,7 @@ void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, up = 0; dn = 0; m = 1; - n= 3; + n = 3; result = 0; wait_cnt = 0; } else { @@ -2116,7 +2005,7 @@ void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, 12; } } else if (result == 1) { - if (coex_dm->cur_ps_tdma == 4) { + if (coex_dm->cur_ps_tdma == 4) { halbtc8192e2ant_ps_tdma( btcoexist, NORMAL_EXEC, @@ -2416,21 +2305,21 @@ void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, true, 2); coex_dm->ps_tdma_du_adj_type = 2; - } else if(coex_dm->cur_ps_tdma == 12) { + } else if (coex_dm->cur_ps_tdma == 12) { halbtc8192e2ant_ps_tdma( btcoexist, NORMAL_EXEC, true, 11); coex_dm->ps_tdma_du_adj_type = 11; - } else if(coex_dm->cur_ps_tdma == 11) { + } else if (coex_dm->cur_ps_tdma == 11) { halbtc8192e2ant_ps_tdma( btcoexist, NORMAL_EXEC, true, 10); coex_dm->ps_tdma_du_adj_type = 10; - } else if(coex_dm->cur_ps_tdma == 10) { + } else if (coex_dm->cur_ps_tdma == 10) { halbtc8192e2ant_ps_tdma( btcoexist, NORMAL_EXEC, @@ -2721,7 +2610,7 @@ void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { bool scan = false, link = false, roam = false; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, - "[BTCoex], PsTdma type dismatch!!!, " ); + "[BTCoex], PsTdma type dismatch!!!, "); BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "curPsTdma=%d, recordPsTdma=%d\n", coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); @@ -2730,7 +2619,7 @@ void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); - if ( !scan && !link && !roam) + if (!scan && !link && !roam) halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, coex_dm->ps_tdma_du_adj_type); @@ -2742,7 +2631,7 @@ void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, } /* SCO only or SCO+PAN(HS) */ -void halbtc8192e2ant_action_sco(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_action_sco(struct btc_coexist *btcoexist) { u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW; u32 wifi_bw; @@ -2804,7 +2693,7 @@ void halbtc8192e2ant_action_sco(struct btc_coexist *btcoexist) } } -void halbtc8192e2ant_action_sco_pan(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_action_sco_pan(struct btc_coexist *btcoexist) { u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW; u32 wifi_bw; @@ -2866,9 +2755,9 @@ void halbtc8192e2ant_action_sco_pan(struct btc_coexist *btcoexist) } } -void halbtc8192e2ant_action_hid(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_action_hid(struct btc_coexist *btcoexist) { - u8 wifirssi_state, btrssi_state=BTC_RSSI_STATE_HIGH; + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; u32 wifi_bw; wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); @@ -2906,7 +2795,7 @@ void halbtc8192e2ant_action_hid(struct btc_coexist *btcoexist) halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, false, 0x18); } else { - halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, false, false); halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); @@ -2918,8 +2807,8 @@ void halbtc8192e2ant_action_hid(struct btc_coexist *btcoexist) false, false); halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, false, 0x18); - } else { - halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, false, false); halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); @@ -2928,7 +2817,7 @@ void halbtc8192e2ant_action_hid(struct btc_coexist *btcoexist) } /* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ -void halbtc8192e2ant_action_a2dp(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_action_a2dp(struct btc_coexist *btcoexist) { u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; u32 wifi_bw; @@ -2991,7 +2880,7 @@ void halbtc8192e2ant_action_a2dp(struct btc_coexist *btcoexist) if (BTC_WIFI_BW_HT40 == wifi_bw) { if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, false, false); halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, false, 0x18); @@ -3017,7 +2906,7 @@ void halbtc8192e2ant_action_a2dp(struct btc_coexist *btcoexist) } } -void halbtc8192e2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) { u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; u32 wifi_bw; @@ -3052,7 +2941,7 @@ void halbtc8192e2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) if (BTC_WIFI_BW_HT40 == wifi_bw) { if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, false, false); halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, true, 0x6); @@ -3078,7 +2967,7 @@ void halbtc8192e2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) } } -void halbtc8192e2ant_action_pan_edr(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_action_pan_edr(struct btc_coexist *btcoexist) { u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; u32 wifi_bw; @@ -3139,7 +3028,7 @@ void halbtc8192e2ant_action_pan_edr(struct btc_coexist *btcoexist) } /* PAN(HS) only */ -void halbtc8192e2ant_action_pan_hs(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_action_pan_hs(struct btc_coexist *btcoexist) { u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; u32 wifi_bw; @@ -3197,9 +3086,9 @@ void halbtc8192e2ant_action_pan_hs(struct btc_coexist *btcoexist) } /* PAN(EDR)+A2DP */ -void halbtc8192e2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) { - u8 wifirssi_state, btrssi_state=BTC_RSSI_STATE_HIGH; + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; u32 wifi_bw; wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); @@ -3260,7 +3149,7 @@ void halbtc8192e2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) } } -void halbtc8192e2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) { u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; u32 wifi_bw; @@ -3280,15 +3169,15 @@ void halbtc8192e2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) if ((btrssi_state == BTC_RSSI_STATE_LOW) || (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); - halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); - halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); - halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); } /* sw mechanism */ @@ -3322,7 +3211,7 @@ void halbtc8192e2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) } /* HID+A2DP+PAN(EDR) */ -void halbtc8192e2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) { u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; u32 wifi_bw; @@ -3383,7 +3272,7 @@ void halbtc8192e2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) } } -void halbtc8192e2ant_action_hid_a2dp(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_action_hid_a2dp(struct btc_coexist *btcoexist) { u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; u32 wifi_bw; @@ -3403,7 +3292,7 @@ void halbtc8192e2ant_action_hid_a2dp(struct btc_coexist *btcoexist) halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 2); } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || - (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2); } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || @@ -3442,7 +3331,7 @@ void halbtc8192e2ant_action_hid_a2dp(struct btc_coexist *btcoexist) } } -void halbtc8192e2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +static void halbtc8192e2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) { u8 algorithm = 0; @@ -3472,7 +3361,7 @@ void halbtc8192e2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) coex_dm->cur_algorithm = algorithm; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, - "[BTCoex], Algorithm = %d \n", coex_dm->cur_algorithm); + "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm); if (halbtc8192e2ant_is_common_action(btcoexist)) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, @@ -3552,7 +3441,8 @@ void halbtc8192e2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) } } -void halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist, bool backup) +static void halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist, + bool backup) { u16 u16tmp = 0; u8 u8tmp = 0; @@ -3649,7 +3539,7 @@ void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist) void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist) { struct btc_board_info *board_info = &btcoexist->board_info; - struct btc_stack_info*stack_info = &btcoexist->stack_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; u8 *cli_buf = btcoexist->cli_buf; u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; u16 u16tmp[4]; @@ -3735,9 +3625,9 @@ void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist) CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : - (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), + (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), ((!wifi_busy) ? "idle" : - ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? + ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? "uplink" : "downlink"))); CL_PRINTF(cli_buf); @@ -3766,7 +3656,7 @@ void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist) (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate"); CL_PRINTF(cli_buf); - for (i=0; ibt_info_c2h_cnt[i]) { CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x ", @@ -3911,9 +3801,6 @@ void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist) "0x774(lp rx[31:16]/tx[15:0])", coex_sta->low_priority_rx, coex_sta->low_priority_tx); CL_PRINTF(cli_buf); -#if(BT_AUTO_REPORT_ONLY_8192E_2ANT == 1) - halbtc8192e2ant_monitor_bt_ctr(btcoexist); -#endif btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); } @@ -3950,7 +3837,7 @@ void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) if (BTC_SCAN_START == type) BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], SCAN START notify\n"); - else if(BTC_SCAN_FINISH == type) + else if (BTC_SCAN_FINISH == type) BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], SCAN FINISH notify\n"); } @@ -3960,7 +3847,7 @@ void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) if (BTC_ASSOCIATE_START == type) BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], CONNECT START notify\n"); - else if(BTC_ASSOCIATE_FINISH == type) + else if (BTC_ASSOCIATE_FINISH == type) BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], CONNECT FINISH notify\n"); } @@ -3968,7 +3855,7 @@ void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist, u8 type) { - u8 h2c_parameter[3] ={0}; + u8 h2c_parameter[3] = {0}; u32 wifi_bw; u8 wifi_center_chnl; @@ -4014,12 +3901,12 @@ void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist, u8 type) { if (type == BTC_PACKET_DHCP) - BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], DHCP Packet notify\n"); - } +} void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, - u8 *tmp_buf, u8 length ) + u8 *tmp_buf, u8 length) { u8 bt_info = 0; u8 i, rspSource = 0; @@ -4089,18 +3976,16 @@ void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, * do nothing here. */ } -#if(BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) if ((coex_sta->bt_info_ext & BIT4)) { /* BT auto report already enabled, do nothing */ } else { halbtc8192e2ant_bt_autoreport(btcoexist, FORCE_EXEC, true); } -#endif } /* check BIT2 first ==> check if bt is under inquiry or page scan */ - if(bt_info & BT_INFO_8192E_2ANT_B_INQ_PAGE) + if (bt_info & BT_INFO_8192E_2ANT_B_INQ_PAGE) coex_sta->c2h_bt_inquiry_page = true; else coex_sta->c2h_bt_inquiry_page = false; @@ -4180,10 +4065,10 @@ void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist, { if (BTC_STACK_OP_INQ_PAGE_PAIR_START == type) BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, - "[BTCoex] StackOP Inquiry/page/pair start notify\n"); - else if(BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type) + "[BTCoex] StackOP Inquiry/page/pair start notify\n"); + else if (BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type) BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, - "[BTCoex] StackOP Inquiry/page/pair finish notify\n"); + "[BTCoex] StackOP Inquiry/page/pair finish notify\n"); } void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist) @@ -4196,10 +4081,10 @@ void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist) void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist) { - static u8 dis_ver_info_cnt = 0; + static u8 dis_ver_info_cnt; u32 fw_ver = 0, bt_patch_ver = 0; - struct btc_board_info *board_info=&btcoexist->board_info; - struct btc_stack_info *stack_info=&btcoexist->stack_info; + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "=======================Periodical=======================\n"); @@ -4226,17 +4111,8 @@ void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist) "************************************************\n"); } -#if(BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) halbtc8192e2ant_querybt_info(btcoexist); halbtc8192e2ant_monitor_bt_ctr(btcoexist); halbtc8192e2ant_monitor_bt_enable_disable(btcoexist); -#else - if (halbtc8192e2ant_iswifi_status_changed(btcoexist) || - coex_dm->auto_tdma_adjust) - halbtc8192e2ant_run_coexist_mechanism(btcoexist); -#endif } - -#endif - diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.h b/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.h index 6d109edb8950c6..416d3ddaed33ba 100644 --- a/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.h +++ b/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.h @@ -1,8 +1,6 @@ /***************************************************************** * The following is for 8192E 2Ant BT Co-exist definition *****************************************************************/ -#define BT_AUTO_REPORT_ONLY_8192E_2ANT 0 - #define BT_INFO_8192E_2ANT_B_FTP BIT7 #define BT_INFO_8192E_2ANT_B_A2DP BIT6 #define BT_INFO_8192E_2ANT_B_HID BIT5 diff --git a/drivers/staging/rtl8821ae/core.c b/drivers/staging/rtl8821ae/core.c index ff3139b6da656f..63ae2d1997d3c1 100644 --- a/drivers/staging/rtl8821ae/core.c +++ b/drivers/staging/rtl8821ae/core.c @@ -1414,23 +1414,15 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw) * before switch channel or power save, or tx buffer packet * maybe send after offchannel or rf sleep, this may cause * dis-association by AP */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) -static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void rtl_op_flush(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 queues, bool drop) { struct rtl_priv *rtlpriv = rtl_priv(hw); if (rtlpriv->intf_ops->flush) rtlpriv->intf_ops->flush(hw, queues, drop); } -#else -static void rtl_op_flush(struct ieee80211_hw *hw, bool drop) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - if (rtlpriv->intf_ops->flush) - rtlpriv->intf_ops->flush(hw, drop); -} -#endif const struct ieee80211_ops rtl_ops = { .start = rtl_op_start, diff --git a/drivers/staging/rtl8821ae/pci.c b/drivers/staging/rtl8821ae/pci.c index a562aa60d5955b..94f72832a83881 100644 --- a/drivers/staging/rtl8821ae/pci.c +++ b/drivers/staging/rtl8821ae/pci.c @@ -2313,16 +2313,16 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, /*shared mem start */ rtlpriv->io.pci_mem_start = - (unsigned long)pci_iomap(pdev, + pci_iomap(pdev, rtlpriv->cfg->bar_id, pmem_len); - if (rtlpriv->io.pci_mem_start == 0) { + if (rtlpriv->io.pci_mem_start == NULL) { RT_ASSERT(false, ("Can't map PCI mem\n")); goto fail2; } RT_TRACE(COMP_INIT, DBG_DMESG, ("mem mapped space: start: 0x%08lx len:%08lx " - "flags:%08lx, after map:0x%08lx\n", + "flags:%08lx, after map:0x%p\n", pmem_start, pmem_len, pmem_flags, rtlpriv->io.pci_mem_start)); @@ -2415,8 +2415,8 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, rtl_deinit_core(hw); ieee80211_free_hw(hw); - if (rtlpriv->io.pci_mem_start != 0) - pci_iounmap(pdev, (void *)rtlpriv->io.pci_mem_start); + if (rtlpriv->io.pci_mem_start != NULL) + pci_iounmap(pdev, rtlpriv->io.pci_mem_start); fail2: pci_release_regions(pdev); @@ -2478,8 +2478,8 @@ void rtl_pci_disconnect(struct pci_dev *pdev) pci_disable_msi(rtlpci->pdev); list_del(&rtlpriv->list); - if (rtlpriv->io.pci_mem_start != 0) { - pci_iounmap(pdev, (void *)rtlpriv->io.pci_mem_start); + if (rtlpriv->io.pci_mem_start != NULL) { + pci_iounmap(pdev, rtlpriv->io.pci_mem_start); pci_release_regions(pdev); } diff --git a/drivers/staging/rtl8821ae/rtl8821ae/hw.h b/drivers/staging/rtl8821ae/rtl8821ae/hw.h index 4fb6bf0d1da2de..256e514f424ab2 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/hw.h +++ b/drivers/staging/rtl8821ae/rtl8821ae/hw.h @@ -11,10 +11,6 @@ * 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, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * @@ -34,42 +30,43 @@ void rtl8821ae_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); void rtl8821ae_read_eeprom_info(struct ieee80211_hw *hw); void rtl8821ae_interrupt_recognized(struct ieee80211_hw *hw, - u32 *p_inta, u32 *p_intb); + u32 *p_inta, u32 *p_intb); int rtl8821ae_hw_init(struct ieee80211_hw *hw); void rtl8821ae_card_disable(struct ieee80211_hw *hw); void rtl8821ae_enable_interrupt(struct ieee80211_hw *hw); void rtl8821ae_disable_interrupt(struct ieee80211_hw *hw); -int rtl8821ae_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +int rtl8821ae_set_network_type(struct ieee80211_hw *hw, + enum nl80211_iftype type); void rtl8821ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); void rtl8821ae_set_qos(struct ieee80211_hw *hw, int aci); void rtl8821ae_set_beacon_related_registers(struct ieee80211_hw *hw); void rtl8821ae_set_beacon_interval(struct ieee80211_hw *hw); void rtl8821ae_update_interrupt_mask(struct ieee80211_hw *hw, - u32 add_msr, u32 rm_msr); + u32 add_msr, u32 rm_msr); void rtl8821ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); void rtl8821ae_update_hal_rate_tbl(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, - u8 rssi_level); + struct ieee80211_sta *sta, + u8 rssi_level); void rtl8821ae_update_channel_access_setting(struct ieee80211_hw *hw); bool rtl8821ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); void rtl8821ae_enable_hw_security_config(struct ieee80211_hw *hw); void rtl8821ae_set_key(struct ieee80211_hw *hw, u32 key_index, - u8 *p_macaddr, bool is_group, u8 enc_algo, - bool is_wepkey, bool clear_all); + u8 *p_macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all); void rtl8821ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8* hwinfo); + bool autoload_fail, + u8 *hwinfo); void rtl8812ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8* hwinfo); -void rtl8821ae_bt_reg_init(struct ieee80211_hw* hw); -void rtl8821ae_bt_hw_init(struct ieee80211_hw* hw); + bool autoload_fail, + u8 *hwinfo); +void rtl8821ae_bt_reg_init(struct ieee80211_hw *hw); +void rtl8821ae_bt_hw_init(struct ieee80211_hw *hw); void rtl8821ae_suspend(struct ieee80211_hw *hw); void rtl8821ae_resume(struct ieee80211_hw *hw); void rtl8821ae_allow_all_destaddr(struct ieee80211_hw *hw, - bool allow_all_da, - bool write_into_reg); + bool allow_all_da, + bool write_into_reg); void _rtl8821ae_stop_tx_beacon(struct ieee80211_hw *hw); void _rtl8821ae_resume_tx_beacon(struct ieee80211_hw *hw); #endif diff --git a/drivers/staging/rtl8821ae/wifi.h b/drivers/staging/rtl8821ae/wifi.h index 17a9d9f8781d53..e8250dad613bd7 100644 --- a/drivers/staging/rtl8821ae/wifi.h +++ b/drivers/staging/rtl8821ae/wifi.h @@ -1086,8 +1086,8 @@ struct rtl_io { struct device *dev; /*PCI MEM map */ - unsigned long pci_mem_end; /*shared mem end */ - unsigned long pci_mem_start; /*shared mem start */ + void __iomem *pci_mem_end; /*shared mem end */ + void __iomem *pci_mem_start; /*shared mem start */ /*PCI IO map */ unsigned long pci_base_addr; /*device I/O address */ diff --git a/drivers/staging/sbe-2t3e3/2t3e3.h b/drivers/staging/sbe-2t3e3/2t3e3.h deleted file mode 100644 index e7bf721f3fd183..00000000000000 --- a/drivers/staging/sbe-2t3e3/2t3e3.h +++ /dev/null @@ -1,889 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#ifndef T3E3_H -#define T3E3_H - -#include -#include -#include -#include -#include -#include "ctrl.h" - -/************************************************************** - * 21143 - **************************************************************/ - -/* CSR */ -#define SBE_2T3E3_21143_REG_BUS_MODE 0 -#define SBE_2T3E3_21143_REG_TRANSMIT_POLL_DEMAND 1 -#define SBE_2T3E3_21143_REG_RECEIVE_POLL_DEMAND 2 -#define SBE_2T3E3_21143_REG_RECEIVE_LIST_BASE_ADDRESS 3 -#define SBE_2T3E3_21143_REG_TRANSMIT_LIST_BASE_ADDRESS 4 -#define SBE_2T3E3_21143_REG_STATUS 5 -#define SBE_2T3E3_21143_REG_OPERATION_MODE 6 -#define SBE_2T3E3_21143_REG_INTERRUPT_ENABLE 7 -#define SBE_2T3E3_21143_REG_MISSED_FRAMES_AND_OVERFLOW_COUNTER 8 -#define SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT 9 -#define SBE_2T3E3_21143_REG_BOOT_ROM_PROGRAMMING_ADDRESS 10 -#define SBE_2T3E3_21143_REG_GENERAL_PURPOSE_TIMER_AND_INTERRUPT_MITIGATION_CONTROL 11 -#define SBE_2T3E3_21143_REG_SIA_STATUS 12 -#define SBE_2T3E3_21143_REG_SIA_CONNECTIVITY 13 -#define SBE_2T3E3_21143_REG_SIA_TRANSMIT_AND_RECEIVE 14 -#define SBE_2T3E3_21143_REG_SIA_AND_GENERAL_PURPOSE_PORT 15 -#define SBE_2T3E3_21143_REG_MAX 16 - -/* CSR0 - BUS_MODE */ -#define SBE_2T3E3_21143_VAL_WRITE_AND_INVALIDATE_ENABLE 0x01000000 -#define SBE_2T3E3_21143_VAL_READ_LINE_ENABLE 0x00800000 -#define SBE_2T3E3_21143_VAL_READ_MULTIPLE_ENABLE 0x00200000 -#define SBE_2T3E3_21143_VAL_TRANSMIT_AUTOMATIC_POLLING_200us 0x00020000 -#define SBE_2T3E3_21143_VAL_TRANSMIT_AUTOMATIC_POLLING_DISABLED 0x00000000 -#define SBE_2T3E3_21143_VAL_CACHE_ALIGNMENT_32 0x0000c000 -#define SBE_2T3E3_21143_VAL_CACHE_ALIGNMENT_16 0x00008000 -#define SBE_2T3E3_21143_VAL_CACHE_ALIGNMENT_8 0x00004000 -#define SBE_2T3E3_21143_VAL_BUS_ARBITRATION_RR 0x00000002 -#define SBE_2T3E3_21143_VAL_SOFTWARE_RESET 0x00000001 - -/* CSR5 - STATUS */ -#define SBE_2T3E3_21143_VAL_GENERAL_PURPOSE_PORT_INTERRUPT 0x04000000 -#define SBE_2T3E3_21143_VAL_ERROR_BITS 0x03800000 -#define SBE_2T3E3_21143_VAL_PARITY_ERROR 0x00000000 -#define SBE_2T3E3_21143_VAL_MASTER_ABORT 0x00800000 -#define SBE_2T3E3_21143_VAL_TARGET_ABORT 0x01000000 -#define SBE_2T3E3_21143_VAL_TRANSMISSION_PROCESS_STATE 0x00700000 -#define SBE_2T3E3_21143_VAL_TX_STOPPED 0x00000000 -#define SBE_2T3E3_21143_VAL_TX_SUSPENDED 0x00600000 -#define SBE_2T3E3_21143_VAL_RECEIVE_PROCESS_STATE 0x000e0000 -#define SBE_2T3E3_21143_VAL_RX_STOPPED 0x00000000 -#define SBE_2T3E3_21143_VAL_RX_SUSPENDED 0x000a0000 -#define SBE_2T3E3_21143_VAL_NORMAL_INTERRUPT_SUMMARY 0x00010000 -#define SBE_2T3E3_21143_VAL_ABNORMAL_INTERRUPT_SUMMARY 0x00008000 -#define SBE_2T3E3_21143_VAL_EARLY_RECEIVE_INTERRUPT 0x00004000 -#define SBE_2T3E3_21143_VAL_FATAL_BUS_ERROR 0x00002000 -#define SBE_2T3E3_21143_VAL_GENERAL_PURPOSE_TIMER_EXPIRED 0x00000800 -#define SBE_2T3E3_21143_VAL_EARLY_TRANSMIT_INTERRUPT 0x00000400 -#define SBE_2T3E3_21143_VAL_RECEIVE_WATCHDOG_TIMEOUT 0x00000200 -#define SBE_2T3E3_21143_VAL_RECEIVE_PROCESS_STOPPED 0x00000100 -#define SBE_2T3E3_21143_VAL_RECEIVE_BUFFER_UNAVAILABLE 0x00000080 -#define SBE_2T3E3_21143_VAL_RECEIVE_INTERRUPT 0x00000040 -#define SBE_2T3E3_21143_VAL_TRANSMIT_UNDERFLOW 0x00000020 -#define SBE_2T3E3_21143_VAL_TRANSMIT_JABBER_TIMEOUT 0x00000008 -#define SBE_2T3E3_21143_VAL_TRANSMIT_BUFFER_UNAVAILABLE 0x00000004 -#define SBE_2T3E3_21143_VAL_TRANSMIT_PROCESS_STOPPED 0x00000002 -#define SBE_2T3E3_21143_VAL_TRANSMIT_INTERRUPT 0x00000001 - -/* CSR6 - OPERATION_MODE */ -#define SBE_2T3E3_21143_VAL_SPECIAL_CAPTURE_EFFECT_ENABLE 0x80000000 -#define SBE_2T3E3_21143_VAL_RECEIVE_ALL 0x40000000 -#define SBE_2T3E3_21143_VAL_MUST_BE_ONE 0x02000000 -#define SBE_2T3E3_21143_VAL_SCRAMBLER_MODE 0x01000000 -#define SBE_2T3E3_21143_VAL_PCS_FUNCTION 0x00800000 -#define SBE_2T3E3_21143_VAL_TRANSMIT_THRESHOLD_MODE_10Mbs 0x00400000 -#define SBE_2T3E3_21143_VAL_TRANSMIT_THRESHOLD_MODE_100Mbs 0x00000000 -#define SBE_2T3E3_21143_VAL_STORE_AND_FORWARD 0x00200000 -#define SBE_2T3E3_21143_VAL_HEARTBEAT_DISABLE 0x00080000 -#define SBE_2T3E3_21143_VAL_PORT_SELECT 0x00040000 -#define SBE_2T3E3_21143_VAL_CAPTURE_EFFECT_ENABLE 0x00020000 -#define SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS 0x0000c000 -#define SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_1 0x00000000 -#define SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_2 0x00004000 -#define SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_3 0x00008000 -#define SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_4 0x0000c000 -#define SBE_2T3E3_21143_VAL_TRANSMISSION_START 0x00002000 -#define SBE_2T3E3_21143_VAL_OPERATING_MODE 0x00000c00 -#define SBE_2T3E3_21143_VAL_LOOPBACK_OFF 0x00000000 -#define SBE_2T3E3_21143_VAL_LOOPBACK_EXTERNAL 0x00000800 -#define SBE_2T3E3_21143_VAL_LOOPBACK_INTERNAL 0x00000400 -#define SBE_2T3E3_21143_VAL_FULL_DUPLEX_MODE 0x00000200 -#define SBE_2T3E3_21143_VAL_PASS_ALL_MULTICAST 0x00000080 -#define SBE_2T3E3_21143_VAL_PROMISCUOUS_MODE 0x00000040 -#define SBE_2T3E3_21143_VAL_PASS_BAD_FRAMES 0x00000008 -#define SBE_2T3E3_21143_VAL_RECEIVE_START 0x00000002 - -/* CSR7 - INTERRUPT_ENABLE */ -#define SBE_2T3E3_21143_VAL_LINK_CHANGED_ENABLE 0x08000000 -#define SBE_2T3E3_21143_VAL_GENERAL_PURPOSE_PORT_ENABLE 0x04000000 -#define SBE_2T3E3_21143_VAL_NORMAL_INTERRUPT_SUMMARY_ENABLE 0x00010000 -#define SBE_2T3E3_21143_VAL_ABNORMAL_INTERRUPT_SUMMARY_ENABLE 0x00008000 -#define SBE_2T3E3_21143_VAL_EARLY_RECEIVE_INTERRUPT_ENABLE 0x00004000 -#define SBE_2T3E3_21143_VAL_FATAL_BUS_ERROR_ENABLE 0x00002000 -#define SBE_2T3E3_21143_VAL_LINK_FAIL_ENABLE 0x00001000 -#define SBE_2T3E3_21143_VAL_GENERAL_PURPOSE_TIMER_ENABLE 0x00000800 -#define SBE_2T3E3_21143_VAL_EARLY_TRANSMIT_INTERRUPT_ENABLE 0x00000400 -#define SBE_2T3E3_21143_VAL_RECEIVE_WATCHDOG_TIMEOUT_ENABLE 0x00000200 -#define SBE_2T3E3_21143_VAL_RECEIVE_STOPPED_ENABLE 0x00000100 -#define SBE_2T3E3_21143_VAL_RECEIVE_BUFFER_UNAVAILABLE_ENABLE 0x00000080 -#define SBE_2T3E3_21143_VAL_RECEIVE_INTERRUPT_ENABLE 0x00000040 -#define SBE_2T3E3_21143_VAL_TRANSMIT_UNDERFLOW_INTERRUPT_ENABLE 0x00000020 -#define SBE_2T3E3_21143_VAL_TRANSMIT_JABBER_TIMEOUT_ENABLE 0x00000008 -#define SBE_2T3E3_21143_VAL_TRANSMIT_BUFFER_UNAVAILABLE_ENABLE 0x00000004 -#define SBE_2T3E3_21143_VAL_TRANSMIT_STOPPED_ENABLE 0x00000002 -#define SBE_2T3E3_21143_VAL_TRANSMIT_INTERRUPT_ENABLE 0x00000001 - -/* CSR8 - MISSED_FRAMES_AND_OVERFLOW_COUNTER */ -#define SBE_2T3E3_21143_VAL_OVERFLOW_COUNTER_OVERFLOW 0x10000000 -#define SBE_2T3E3_21143_VAL_OVERFLOW_COUNTER 0x0ffe0000 -#define SBE_2T3E3_21143_VAL_MISSED_FRAME_OVERFLOW 0x00010000 -#define SBE_2T3E3_21143_VAL_MISSED_FRAMES_COUNTER 0x0000ffff - -/* CSR9 - BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT */ -#define SBE_2T3E3_21143_VAL_MII_MANAGEMENT_DATA_IN 0x00080000 -#define SBE_2T3E3_21143_VAL_MII_MANAGEMENT_READ_MODE 0x00040000 -#define SBE_2T3E3_21143_VAL_MII_MANAGEMENT_DATA_OUT 0x00020000 -#define SBE_2T3E3_21143_VAL_MII_MANAGEMENT_CLOCK 0x00010000 -#define SBE_2T3E3_21143_VAL_READ_OPERATION 0x00004000 -#define SBE_2T3E3_21143_VAL_WRITE_OPERATION 0x00002000 -#define SBE_2T3E3_21143_VAL_BOOT_ROM_SELECT 0x00001000 -#define SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT 0x00000800 -#define SBE_2T3E3_21143_VAL_BOOT_ROM_DATA 0x000000ff -#define SBE_2T3E3_21143_VAL_SERIAL_ROM_DATA_OUT 0x00000008 -#define SBE_2T3E3_21143_VAL_SERIAL_ROM_DATA_IN 0x00000004 -#define SBE_2T3E3_21143_VAL_SERIAL_ROM_CLOCK 0x00000002 -#define SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT 0x00000001 - -/* CSR11 - GENERAL_PURPOSE_TIMER_AND_INTERRUPT_MITIGATION_CONTROL */ -#define SBE_2T3E3_21143_VAL_CYCLE_SIZE 0x80000000 -#define SBE_2T3E3_21143_VAL_TRANSMIT_TIMER 0x78000000 -#define SBE_2T3E3_21143_VAL_NUMBER_OF_TRANSMIT_PACKETS 0x07000000 -#define SBE_2T3E3_21143_VAL_RECEIVE_TIMER 0x00f00000 -#define SBE_2T3E3_21143_VAL_NUMBER_OF_RECEIVE_PACKETS 0x000e0000 -#define SBE_2T3E3_21143_VAL_CONTINUOUS_MODE 0x00010000 -#define SBE_2T3E3_21143_VAL_TIMER_VALUE 0x0000ffff - -/* CSR12 - SIA_STATUS */ -#define SBE_2T3E3_21143_VAL_10BASE_T_RECEIVE_PORT_ACTIVITY 0x00000200 -#define SBE_2T3E3_21143_VAL_AUI_RECEIVE_PORT_ACTIVITY 0x00000100 -#define SBE_2T3E3_21143_VAL_10Mbs_LINK_STATUS 0x00000004 -#define SBE_2T3E3_21143_VAL_100Mbs_LINK_STATUS 0x00000002 -#define SBE_2T3E3_21143_VAL_MII_RECEIVE_PORT_ACTIVITY 0x00000001 - -/* CSR13 - SIA_CONNECTIVITY */ -#define SBE_2T3E3_21143_VAL_10BASE_T_OR_AUI 0x00000008 -#define SBE_2T3E3_21143_VAL_SIA_RESET 0x00000001 - -/* CSR14 - SIA_TRANSMIT_AND_RECEIVE */ -#define SBE_2T3E3_21143_VAL_100BASE_TX_FULL_DUPLEX 0x00020000 -#define SBE_2T3E3_21143_VAL_COLLISION_DETECT_ENABLE 0x00000400 -#define SBE_2T3E3_21143_VAL_COLLISION_SQUELCH_ENABLE 0x00000200 -#define SBE_2T3E3_21143_VAL_RECEIVE_SQUELCH_ENABLE 0x00000100 -#define SBE_2T3E3_21143_VAL_LINK_PULSE_SEND_ENABLE 0x00000004 -#define SBE_2T3E3_21143_VAL_ENCODER_ENABLE 0x00000001 - -/* CSR15 - SIA_AND_GENERAL_PURPOSE_PORT */ -#define SBE_2T3E3_21143_VAL_RECEIVE_WATCHDOG_DISABLE 0x00000010 -#define SBE_2T3E3_21143_VAL_AUI_BNC_MODE 0x00000008 -#define SBE_2T3E3_21143_VAL_HOST_UNJAB 0x00000002 -#define SBE_2T3E3_21143_VAL_JABBER_DISABLE 0x00000001 - -/************************************************************** - * CPLD - **************************************************************/ - -/* reg_map indexes */ -#define SBE_2T3E3_CPLD_REG_PCRA 0 -#define SBE_2T3E3_CPLD_REG_PCRB 1 -#define SBE_2T3E3_CPLD_REG_PLCR 2 -#define SBE_2T3E3_CPLD_REG_PLTR 3 -#define SBE_2T3E3_CPLD_REG_PPFR 4 -#define SBE_2T3E3_CPLD_REG_BOARD_ID 5 -#define SBE_2T3E3_CPLD_REG_FPGA_VERSION 6 -#define SBE_2T3E3_CPLD_REG_FRAMER_BASE_ADDRESS 7 -#define SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT 8 -#define SBE_2T3E3_CPLD_REG_STATIC_RESET 9 -#define SBE_2T3E3_CPLD_REG_PULSE_RESET 10 -#define SBE_2T3E3_CPLD_REG_FPGA_RECONFIGURATION 11 -#define SBE_2T3E3_CPLD_REG_LEDR 12 -#define SBE_2T3E3_CPLD_REG_PICSR 13 -#define SBE_2T3E3_CPLD_REG_PIER 14 -#define SBE_2T3E3_CPLD_REG_PCRC 15 -#define SBE_2T3E3_CPLD_REG_PBWF 16 -#define SBE_2T3E3_CPLD_REG_PBWL 17 - -#define SBE_2T3E3_CPLD_REG_MAX 18 - -/**********/ - -/* val_map indexes */ -#define SBE_2T3E3_CPLD_VAL_LIU_SELECT 0 -#define SBE_2T3E3_CPLD_VAL_DAC_SELECT 1 -#define SBE_2T3E3_CPLD_VAL_LOOP_TIMING_SOURCE 2 -#define SBE_2T3E3_CPLD_VAL_LIU_FRAMER_RESET 3 - -/* PCRA */ -#define SBE_2T3E3_CPLD_VAL_CRC32 0x40 -#define SBE_2T3E3_CPLD_VAL_TRANSPARENT_MODE 0x20 -#define SBE_2T3E3_CPLD_VAL_REAR_PANEL 0x10 -#define SBE_2T3E3_CPLD_VAL_RAW_MODE 0x08 -#define SBE_2T3E3_CPLD_VAL_ALT 0x04 -#define SBE_2T3E3_CPLD_VAL_LOOP_TIMING 0x02 -#define SBE_2T3E3_CPLD_VAL_LOCAL_CLOCK_E3 0x01 - -/* PCRB */ -#define SBE_2T3E3_CPLD_VAL_PAD_COUNT 0x30 -#define SBE_2T3E3_CPLD_VAL_PAD_COUNT_1 0x00 -#define SBE_2T3E3_CPLD_VAL_PAD_COUNT_2 0x10 -#define SBE_2T3E3_CPLD_VAL_PAD_COUNT_3 0x20 -#define SBE_2T3E3_CPLD_VAL_PAD_COUNT_4 0x30 -#define SBE_2T3E3_CPLD_VAL_SCRAMBLER_TYPE 0x02 -#define SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE 0x01 - -/* PCRC */ -#define SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_NONE 0x00 -#define SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_0 0x01 -#define SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_1 0x11 -#define SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_2 0x21 - -/* PLTR */ -#define SBE_2T3E3_CPLD_VAL_LCV_COUNTER 0xff - -/* SCSR */ -#define SBE_2T3E3_CPLD_VAL_EEPROM_SELECT 0x10 - -/* PICSR */ -#define SBE_2T3E3_CPLD_VAL_LOSS_OF_SIGNAL_THRESHOLD_LEVEL_1 0x80 -#define SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_CHANGE 0x40 -#define SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_ETHERNET_ASSERTED 0x20 -#define SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_FRAMER_ASSERTED 0x10 -#define SBE_2T3E3_CPLD_VAL_LCV_LIMIT_EXCEEDED 0x08 -#define SBE_2T3E3_CPLD_VAL_DMO_SIGNAL_DETECTED 0x04 -#define SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_LOCK_DETECTED 0x02 -#define SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED 0x01 - -/* PIER */ -#define SBE_2T3E3_CPLD_VAL_RECEIVE_LOS_CHANGE_ENABLE 0x40 -#define SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_ETHERNET_ENABLE 0x20 -#define SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_FRAMER_ENABLE 0x10 -#define SBE_2T3E3_CPLD_VAL_LCV_INTERRUPT_ENABLE 0x08 -#define SBE_2T3E3_CPLD_VAL_DMO_ENABLE 0x04 -#define SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_LOCK_ENABLE 0x02 -#define SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_ENABLE 0x01 - -/************************************************************** - * Framer - **************************************************************/ - -/* reg_map indexes */ -/* common */ -#define SBE_2T3E3_FRAMER_REG_OPERATING_MODE 0 -#define SBE_2T3E3_FRAMER_REG_IO_CONTROL 1 -#define SBE_2T3E3_FRAMER_REG_BLOCK_INTERRUPT_ENABLE 2 -#define SBE_2T3E3_FRAMER_REG_BLOCK_INTERRUPT_STATUS 3 -#define SBE_2T3E3_FRAMER_REG_PMON_LCV_EVENT_COUNT_MSB 28 -#define SBE_2T3E3_FRAMER_REG_PMON_LCV_EVENT_COUNT_LSB 29 -#define SBE_2T3E3_FRAMER_REG_PMON_FRAMING_BIT_ERROR_EVENT_COUNT_MSB 30 -#define SBE_2T3E3_FRAMER_REG_PMON_FRAMING_BIT_ERROR_EVENT_COUNT_LSB 31 -#define SBE_2T3E3_FRAMER_REG_PMON_PARITY_ERROR_EVENT_COUNT_MSB 32 -#define SBE_2T3E3_FRAMER_REG_PMON_PARITY_ERROR_EVENT_COUNT_LSB 33 -#define SBE_2T3E3_FRAMER_REG_PMON_FEBE_EVENT_COUNT_MSB 34 -#define SBE_2T3E3_FRAMER_REG_PMON_FEBE_EVENT_COUNT_LSB 35 -#define SBE_2T3E3_FRAMER_REG_PMON_CP_BIT_ERROR_EVENT_COUNT_MSB 36 -#define SBE_2T3E3_FRAMER_REG_PMON_CP_BIT_ERROR_EVENT_COUNT_LSB 37 -#define SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER 38 -#define SBE_2T3E3_FRAMER_REG_ONE_SECOND_ERROR_STATUS 39 -#define SBE_2T3E3_FRAMER_REG_LCV_ONE_SECOND_ACCUMULATOR_MSB 40 -#define SBE_2T3E3_FRAMER_REG_LCV_ONE_SECOND_ACCUMULATOR_LSB 41 -#define SBE_2T3E3_FRAMER_REG_FRAME_PARITY_ERROR_ONE_SECOND_ACCUMULATOR_MSB 42 -#define SBE_2T3E3_FRAMER_REG_FRAME_PARITY_ERROR_ONE_SECOND_ACCUMULATOR_LSB 43 -#define SBE_2T3E3_FRAMER_REG_FRAME_CP_BIT_ERROR_ONE_SECOND_ACCUMULATOR_MSB 44 -#define SBE_2T3E3_FRAMER_REG_FRAME_CP_BIT_ERROR_ONE_SECOND_ACCUMULATOR_LSB 45 -#define SBE_2T3E3_FRAMER_REG_LINE_INTERFACE_DRIVE 46 -#define SBE_2T3E3_FRAMER_REG_LINE_INTERFACE_SCAN 47 - -/* T3 */ -#define SBE_2T3E3_FRAMER_REG_T3_RX_CONFIGURATION_STATUS 4 -#define SBE_2T3E3_FRAMER_REG_T3_RX_STATUS 5 -#define SBE_2T3E3_FRAMER_REG_T3_RX_INTERRUPT_ENABLE 6 -#define SBE_2T3E3_FRAMER_REG_T3_RX_INTERRUPT_STATUS 7 -#define SBE_2T3E3_FRAMER_REG_T3_RX_SYNC_DETECT_ENABLE 8 -#define SBE_2T3E3_FRAMER_REG_T3_RX_FEAC 10 -#define SBE_2T3E3_FRAMER_REG_T3_RX_FEAC_INTERRUPT_ENABLE_STATUS 11 -#define SBE_2T3E3_FRAMER_REG_T3_RX_LAPD_CONTROL 12 -#define SBE_2T3E3_FRAMER_REG_T3_RX_LAPD_STATUS 13 -#define SBE_2T3E3_FRAMER_REG_T3_TX_CONFIGURATION 16 -#define SBE_2T3E3_FRAMER_REG_T3_TX_FEAC_CONFIGURATION_STATUS 17 -#define SBE_2T3E3_FRAMER_REG_T3_TX_FEAC 18 -#define SBE_2T3E3_FRAMER_REG_T3_TX_LAPD_CONFIGURATION 19 -#define SBE_2T3E3_FRAMER_REG_T3_TX_LAPD_STATUS 20 -#define SBE_2T3E3_FRAMER_REG_T3_TX_MBIT_MASK 21 -#define SBE_2T3E3_FRAMER_REG_T3_TX_FBIT_MASK 22 -#define SBE_2T3E3_FRAMER_REG_T3_TX_FBIT_MASK_2 23 -#define SBE_2T3E3_FRAMER_REG_T3_TX_FBIT_MASK_3 24 - -/* E3 */ -#define SBE_2T3E3_FRAMER_REG_E3_RX_CONFIGURATION_STATUS_1 4 -#define SBE_2T3E3_FRAMER_REG_E3_RX_CONFIGURATION_STATUS_2 5 -#define SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_ENABLE_1 6 -#define SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_ENABLE_2 7 -#define SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_STATUS_1 8 -#define SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_STATUS_2 9 -#define SBE_2T3E3_FRAMER_REG_E3_RX_LAPD_CONTROL 12 -#define SBE_2T3E3_FRAMER_REG_E3_RX_LAPD_STATUS 13 -#define SBE_2T3E3_FRAMER_REG_E3_RX_NR_BYTE 14 -#define SBE_2T3E3_FRAMER_REG_E3_RX_SERVICE_BITS 14 -#define SBE_2T3E3_FRAMER_REG_E3_RX_GC_BYTE 15 -#define SBE_2T3E3_FRAMER_REG_E3_TX_CONFIGURATION 16 -#define SBE_2T3E3_FRAMER_REG_E3_TX_LAPD_CONFIGURATION 19 -#define SBE_2T3E3_FRAMER_REG_E3_TX_LAPD_STATUS 19 -#define SBE_2T3E3_FRAMER_REG_E3_TX_GC_BYTE 21 -#define SBE_2T3E3_FRAMER_REG_E3_TX_SERVICE_BITS 21 -#define SBE_2T3E3_FRAMER_REG_E3_TX_MA_BYTE 22 -#define SBE_2T3E3_FRAMER_REG_E3_TX_NR_BYTE 23 -#define SBE_2T3E3_FRAMER_REG_E3_TX_FA1_ERROR_MASK 25 -#define SBE_2T3E3_FRAMER_REG_E3_TX_FAS_ERROR_MASK_UPPER 25 -#define SBE_2T3E3_FRAMER_REG_E3_TX_FA2_ERROR_MASK 26 -#define SBE_2T3E3_FRAMER_REG_E3_TX_FAS_ERROR_MASK_LOWER 26 -#define SBE_2T3E3_FRAMER_REG_E3_TX_BIP8_MASK 27 -#define SBE_2T3E3_FRAMER_REG_E3_TX_BIP4_MASK 27 - -#define SBE_2T3E3_FRAMER_REG_MAX 48 - -/**********/ - -/* OPERATING_MODE */ -#define SBE_2T3E3_FRAMER_VAL_LOCAL_LOOPBACK_MODE 0x80 -#define SBE_2T3E3_FRAMER_VAL_T3_E3_SELECT 0x40 -#define SBE_2T3E3_FRAMER_VAL_INTERNAL_LOS_ENABLE 0x20 -#define SBE_2T3E3_FRAMER_VAL_RESET 0x10 -#define SBE_2T3E3_FRAMER_VAL_INTERRUPT_ENABLE_RESET 0x08 -#define SBE_2T3E3_FRAMER_VAL_FRAME_FORMAT_SELECT 0x04 -#define SBE_2T3E3_FRAMER_VAL_TIMING_ASYNCH_TXINCLK 0x03 -#define SBE_2T3E3_FRAMER_VAL_E3_G751 0x00 -#define SBE_2T3E3_FRAMER_VAL_E3_G832 0x04 -#define SBE_2T3E3_FRAMER_VAL_T3_CBIT 0x40 -#define SBE_2T3E3_FRAMER_VAL_T3_M13 0x44 -#define SBE_2T3E3_FRAMER_VAL_LOOPBACK_ON 0x80 -#define SBE_2T3E3_FRAMER_VAL_LOOPBACK_OFF 0x00 - -/* IO_CONTROL */ -#define SBE_2T3E3_FRAMER_VAL_DISABLE_TX_LOSS_OF_CLOCK 0x80 -#define SBE_2T3E3_FRAMER_VAL_LOSS_OF_CLOCK_STATUS 0x40 -#define SBE_2T3E3_FRAMER_VAL_DISABLE_RX_LOSS_OF_CLOCK 0x20 -#define SBE_2T3E3_FRAMER_VAL_AMI_LINE_CODE 0x10 -#define SBE_2T3E3_FRAMER_VAL_UNIPOLAR 0x08 -#define SBE_2T3E3_FRAMER_VAL_TX_LINE_CLOCK_INVERT 0x04 -#define SBE_2T3E3_FRAMER_VAL_RX_LINE_CLOCK_INVERT 0x02 -#define SBE_2T3E3_FRAMER_VAL_REFRAME 0x01 - -/* BLOCK_INTERRUPT_ENABLE */ -#define SBE_2T3E3_FRAMER_VAL_RX_INTERRUPT_ENABLE 0x80 -#define SBE_2T3E3_FRAMER_VAL_TX_INTERRUPT_ENABLE 0x02 -#define SBE_2T3E3_FRAMER_VAL_ONE_SECOND_INTERRUPT_ENABLE 0x01 - -/* BLOCK_INTERRUPT_STATUS */ -#define SBE_2T3E3_FRAMER_VAL_RX_INTERRUPT_STATUS 0x80 -#define SBE_2T3E3_FRAMER_VAL_TX_INTERRUPT_STATUS 0x02 -#define SBE_2T3E3_FRAMER_VAL_ONE_SECOND_INTERRUPT_STATUS 0x01 - -/**********/ - -/* T3_RX_CONFIGURATION_STATUS */ -#define SBE_2T3E3_FRAMER_VAL_T3_RX_AIS 0x80 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_LOS 0x40 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_IDLE 0x20 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_OOF 0x10 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_FRAMING_ON_PARITY 0x04 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_F_SYNC_ALGO 0x02 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_M_SYNC_ALGO 0x01 - -/* T3_RX_STATUS */ -#define SBE_2T3E3_FRAMER_VAL_T3_RX_FERF 0x10 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_AIC 0x04 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_FEBE 0x07 - -/* T3_RX_INTERRUPT_ENABLE */ -#define SBE_2T3E3_FRAMER_VAL_T3_RX_CP_BIT_ERROR_INTERRUPT_ENABLE 0x80 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_LOS_INTERRUPT_ENABLE 0x40 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_AIS_INTERRUPT_ENABLE 0x20 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_IDLE_INTERRUPT_ENABLE 0x10 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_FERF_INTERRUPT_ENABLE 0x08 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_AIC_INTERRUPT_ENABLE 0x04 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_OOF_INTERRUPT_ENABLE 0x02 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_P_BIT_INTERRUPT_ENABLE 0x01 - -/* T3_RX_INTERRUPT_STATUS */ -#define SBE_2T3E3_FRAMER_VAL_T3_RX_CP_BIT_ERROR_INTERRUPT_STATUS 0x80 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_LOS_INTERRUPT_STATUS 0x40 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_AIS_INTERRUPT_STATUS 0x20 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_IDLE_INTERRUPT_STATUS 0x10 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_FERF_INTERRUPT_STATUS 0x08 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_AIC_INTERRUPT_STATUS 0x04 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_OOF_INTERRUPT_STATUS 0x02 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_P_BIT_INTERRUPT_STATUS 0x01 - -/* T3_RX_FEAC_INTERRUPT_ENABLE_STATUS */ -#define SBE_2T3E3_FRAMER_VAL_T3_RX_FEAC_VALID 0x10 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_FEAC_REMOVE_INTERRUPT_ENABLE 0x08 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_FEAC_REMOVE_INTERRUPT_STATUS 0x04 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_FEAC_VALID_INTERRUPT_ENABLE 0x02 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_FEAC_VALID_INTERRUPT_STATUS 0x01 - -/* T3_RX_LAPD_CONTROL */ -#define SBE_2T3E3_FRAMER_VAL_T3_RX_LAPD_ENABLE 0x04 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_LAPD_INTERRUPT_ENABLE 0x02 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_LAPD_INTERRUPT_STATUS 0x01 - -/* T3_RX_LAPD_STATUS */ -#define SBE_2T3E3_FRAMER_VAL_T3_RX_ABORT 0x40 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_LAPD_TYPE 0x30 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_CR_TYPE 0x08 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_FCS_ERROR 0x04 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_END_OF_MESSAGE 0x02 -#define SBE_2T3E3_FRAMER_VAL_T3_RX_FLAG_PRESENT 0x01 - -/* T3_TX_CONFIGURATION */ -#define SBE_2T3E3_FRAMER_VAL_T3_TX_YELLOW_ALARM 0x80 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_X_BIT 0x40 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_IDLE 0x20 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_AIS 0x10 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_LOS 0x08 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_FERF_ON_LOS 0x04 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_FERF_ON_OOF 0x02 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_FERF_ON_AIS 0x01 - -/* T3_TX_FEAC_CONFIGURATION_STATUS */ -#define SBE_2T3E3_FRAMER_VAL_T3_TX_FEAC_INTERRUPT_ENABLE 0x10 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_FEAC_INTERRUPT_STATUS 0x08 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_FEAC_ENABLE 0x04 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_FEAC_GO 0x02 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_FEAC_BUSY 0x01 - -/* T3_TX_LAPD_STATUS */ -#define SBE_2T3E3_FRAMER_VAL_T3_TX_DL_START 0x08 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_DL_BUSY 0x04 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_LAPD_INTERRUPT_ENABLE 0x02 -#define SBE_2T3E3_FRAMER_VAL_T3_TX_LAPD_INTERRUPT_STATUS 0x01 - -/**********/ - -/* E3_RX_CONFIGURATION_STATUS_1 */ -#define SBE_2T3E3_FRAMER_VAL_E3_RX_PAYLOAD_TYPE 0xe0 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_FERF_ALGO 0x10 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_T_MARK_ALGO 0x08 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_PAYLOAD_EXPECTED 0x07 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_BIP4 0x01 - -/* E3_RX_CONFIGURATION_STATUS_2 */ -#define SBE_2T3E3_FRAMER_VAL_E3_RX_LOF_ALGO 0x80 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_LOF 0x40 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_OOF 0x20 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_LOS 0x10 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_AIS 0x08 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_PAYLOAD_UNSTABLE 0x04 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_T_MARK 0x02 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_FERF 0x01 - -/* E3_RX_INTERRUPT_ENABLE_1 */ -#define SBE_2T3E3_FRAMER_VAL_E3_RX_COFA_INTERRUPT_ENABLE 0x10 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_OOF_INTERRUPT_ENABLE 0x08 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_LOF_INTERRUPT_ENABLE 0x04 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_LOS_INTERRUPT_ENABLE 0x02 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_AIS_INTERRUPT_ENABLE 0x01 - -/* E3_RX_INTERRUPT_ENABLE_2 */ -#define SBE_2T3E3_FRAMER_VAL_E3_RX_TTB_CHANGE_INTERRUPT_ENABLE 0x40 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_FEBE_INTERRUPT_ENABLE 0x10 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_FERF_INTERRUPT_ENABLE 0x08 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_BIP8_ERROR_INTERRUPT_ENABLE 0x04 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_BIP4_ERROR_INTERRUPT_ENABLE 0x04 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_FRAMING_BYTE_ERROR_INTERRUPT_ENABLE 0x02 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_PAYLOAD_MISMATCH_INTERRUPT_ENABLE 0x01 - -/* E3_RX_INTERRUPT_STATUS_1 */ -#define SBE_2T3E3_FRAMER_VAL_E3_RX_COFA_INTERRUPT_STATUS 0x10 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_OOF_INTERRUPT_STATUS 0x08 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_LOF_INTERRUPT_STATUS 0x04 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_LOS_INTERRUPT_STATUS 0x02 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_AIS_INTERRUPT_STATUS 0x01 - -/* E3_RX_INTERRUPT_STATUS_2 */ -#define SBE_2T3E3_FRAMER_VAL_E3_RX_TTB_CHANGE_INTERRUPT_STATUS 0x40 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_FEBE_INTERRUPT_STATUS 0x10 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_FERF_INTERRUPT_STATUS 0x08 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_BIP8_ERROR_INTERRUPT_STATUS 0x04 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_BIP4_ERROR_INTERRUPT_STATUS 0x04 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_FRAMING_BYTE_ERROR_INTERRUPT_STATUS 0x02 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_PAYLOAD_MISMATCH_INTERRUPT_STATUS 0x01 - -/* E3_RX_LAPD_CONTROL */ -#define SBE_2T3E3_FRAMER_VAL_E3_RX_DL_FROM_NR 0x08 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_LAPD_ENABLE 0x04 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_LAPD_INTERRUPT_ENABLE 0x02 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_LAPD_INTERRUPT_STATUS 0x01 - -/* E3_RX_LAPD_STATUS */ -#define SBE_2T3E3_FRAMER_VAL_E3_RX_ABORT 0x40 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_LAPD_TYPE 0x30 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_CR_TYPE 0x08 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_FCS_ERROR 0x04 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_END_OF_MESSAGE 0x02 -#define SBE_2T3E3_FRAMER_VAL_E3_RX_FLAG_PRESENT 0x01 - -/* E3_TX_CONFIGURATION */ -#define SBE_2T3E3_FRAMER_VAL_E3_TX_BIP4_ENABLE 0x80 -#define SBE_2T3E3_FRAMER_VAL_E3_TX_A_SOURCE_SELECT 0x60 -#define SBE_2T3E3_FRAMER_VAL_E3_TX_DL_IN_NR 0x10 -#define SBE_2T3E3_FRAMER_VAL_E3_TX_N_SOURCE_SELECT 0x18 -#define SBE_2T3E3_FRAMER_VAL_E3_TX_AIS_ENABLE 0x04 -#define SBE_2T3E3_FRAMER_VAL_E3_TX_LOS_ENABLE 0x02 -#define SBE_2T3E3_FRAMER_VAL_E3_TX_MA_RX 0x01 -#define SBE_2T3E3_FRAMER_VAL_E3_TX_FAS_SOURCE_SELECT 0x01 - -/* E3_TX_LAPD_CONFIGURATION */ -#define SBE_2T3E3_FRAMER_VAL_E3_TX_AUTO_RETRANSMIT 0x08 -#define SBE_2T3E3_FRAMER_VAL_E3_TX_LAPD_MESSAGE_LENGTH 0x02 -#define SBE_2T3E3_FRAMER_VAL_E3_TX_LAPD_ENABLE 0x01 - -/* E3_TX_LAPD_STATUS_INTERRUPT */ -#define SBE_2T3E3_FRAMER_VAL_E3_TX_DL_START 0x08 -#define SBE_2T3E3_FRAMER_VAL_E3_TX_DL_BUSY 0x04 -#define SBE_2T3E3_FRAMER_VAL_E3_TX_LAPD_INTERRUPT_ENABLE 0x02 -#define SBE_2T3E3_FRAMER_VAL_E3_TX_LAPD_INTERRUPT_STATUS 0x01 - - - - - - -/************************************************************** - * LIU - **************************************************************/ - -/* reg_map indexes */ -#define SBE_2T3E3_LIU_REG_REG0 0 -#define SBE_2T3E3_LIU_REG_REG1 1 -#define SBE_2T3E3_LIU_REG_REG2 2 -#define SBE_2T3E3_LIU_REG_REG3 3 -#define SBE_2T3E3_LIU_REG_REG4 4 - -#define SBE_2T3E3_LIU_REG_MAX 5 - -/**********/ - -/* REG0 */ -#define SBE_2T3E3_LIU_VAL_RECEIVE_LOSS_OF_LOCK_STATUS 0x10 -#define SBE_2T3E3_LIU_VAL_RECEIVE_LOSS_OF_SIGNAL_STATUS 0x08 -#define SBE_2T3E3_LIU_VAL_ANALOG_LOSS_OF_SIGNAL_STATUS 0x04 -#define SBE_2T3E3_LIU_VAL_DIGITAL_LOSS_OF_SIGNAL_STATUS 0x02 -#define SBE_2T3E3_LIU_VAL_DMO_STATUS 0x01 - -/* REG1 */ -#define SBE_2T3E3_LIU_VAL_TRANSMITTER_OFF 0x10 -#define SBE_2T3E3_LIU_VAL_TRANSMIT_ALL_ONES 0x08 -#define SBE_2T3E3_LIU_VAL_TRANSMIT_CLOCK_INVERT 0x04 -#define SBE_2T3E3_LIU_VAL_TRANSMIT_LEVEL_SELECT 0x02 -#define SBE_2T3E3_LIU_VAL_TRANSMIT_BINARY_DATA 0x01 - -/* REG2 */ -#define SBE_2T3E3_LIU_VAL_DECODER_DISABLE 0x10 -#define SBE_2T3E3_LIU_VAL_ENCODER_DISABLE 0x08 -#define SBE_2T3E3_LIU_VAL_ANALOG_LOSS_OF_SIGNAL_DISABLE 0x04 -#define SBE_2T3E3_LIU_VAL_DIGITAL_LOSS_OF_SIGNAL_DISABLE 0x02 -#define SBE_2T3E3_LIU_VAL_RECEIVE_EQUALIZATION_DISABLE 0x01 - -/* REG3 */ -#define SBE_2T3E3_LIU_VAL_RECEIVE_BINARY_DATA 0x10 -#define SBE_2T3E3_LIU_VAL_RECOVERED_DATA_MUTING 0x08 -#define SBE_2T3E3_LIU_VAL_RECEIVE_CLOCK_OUTPUT_2 0x04 -#define SBE_2T3E3_LIU_VAL_INVERT_RECEIVE_CLOCK_2 0x02 -#define SBE_2T3E3_LIU_VAL_INVERT_RECEIVE_CLOCK_1 0x01 - -/* REG4 */ -#define SBE_2T3E3_LIU_VAL_T3_MODE_SELECT 0x00 -#define SBE_2T3E3_LIU_VAL_E3_MODE_SELECT 0x04 -#define SBE_2T3E3_LIU_VAL_LOCAL_LOOPBACK 0x02 -#define SBE_2T3E3_LIU_VAL_REMOTE_LOOPBACK 0x01 -#define SBE_2T3E3_LIU_VAL_LOOPBACK_OFF 0x00 -#define SBE_2T3E3_LIU_VAL_LOOPBACK_REMOTE 0x01 -#define SBE_2T3E3_LIU_VAL_LOOPBACK_ANALOG 0x02 -#define SBE_2T3E3_LIU_VAL_LOOPBACK_DIGITAL 0x03 - -/********************************************************************** - * - * descriptor list and data buffer - * - **********************************************************************/ -struct t3e3_rx_desc { - u32 rdes0; - u32 rdes1; - u32 rdes2; - u32 rdes3; -}; - -#define SBE_2T3E3_RX_DESC_RING_SIZE 64 - -/* RDES0 */ -#define SBE_2T3E3_RX_DESC_21143_OWN 0X80000000 -#define SBE_2T3E3_RX_DESC_FRAME_LENGTH 0x3fff0000 -#define SBE_2T3E3_RX_DESC_FRAME_LENGTH_SHIFT 16 -#define SBE_2T3E3_RX_DESC_ERROR_SUMMARY 0x00008000 -#define SBE_2T3E3_RX_DESC_DESC_ERROR 0x00004000 -#define SBE_2T3E3_RX_DESC_DATA_TYPE 0x00003000 -#define SBE_2T3E3_RX_DESC_RUNT_FRAME 0x00000800 -#define SBE_2T3E3_RX_DESC_FIRST_DESC 0x00000200 -#define SBE_2T3E3_RX_DESC_LAST_DESC 0x00000100 -#define SBE_2T3E3_RX_DESC_FRAME_TOO_LONG 0x00000080 -#define SBE_2T3E3_RX_DESC_COLLISION_SEEN 0x00000040 -#define SBE_2T3E3_RX_DESC_FRAME_TYPE 0x00000020 -#define SBE_2T3E3_RX_DESC_RECEIVE_WATCHDOG 0x00000010 -#define SBE_2T3E3_RX_DESC_MII_ERROR 0x00000008 -#define SBE_2T3E3_RX_DESC_DRIBBLING_BIT 0x00000004 -#define SBE_2T3E3_RX_DESC_CRC_ERROR 0x00000002 - -/* RDES1 */ -#define SBE_2T3E3_RX_DESC_END_OF_RING 0x02000000 -#define SBE_2T3E3_RX_DESC_SECOND_ADDRESS_CHAINED 0x01000000 -#define SBE_2T3E3_RX_DESC_BUFFER_2_SIZE 0x003ff800 -#define SBE_2T3E3_RX_DESC_BUFFER_1_SIZE 0x000007ff - -/*********************/ - -struct t3e3_tx_desc { - u32 tdes0; - u32 tdes1; - u32 tdes2; - u32 tdes3; -}; - -#define SBE_2T3E3_TX_DESC_RING_SIZE 256 - -/* TDES0 */ -#define SBE_2T3E3_TX_DESC_21143_OWN 0x80000000 -#define SBE_2T3E3_TX_DESC_ERROR_SUMMARY 0x00008000 -#define SBE_2T3E3_TX_DESC_TRANSMIT_JABBER_TIMEOUT 0x00004000 -#define SBE_2T3E3_TX_DESC_LOSS_OF_CARRIER 0x00000800 -#define SBE_2T3E3_TX_DESC_NO_CARRIER 0x00000400 -#define SBE_2T3E3_TX_DESC_LINK_FAIL_REPORT 0x00000004 -#define SBE_2T3E3_TX_DESC_UNDERFLOW_ERROR 0x00000002 -#define SBE_2T3E3_TX_DESC_DEFFERED 0x00000001 - -/* TDES1 */ -#define SBE_2T3E3_TX_DESC_INTERRUPT_ON_COMPLETION 0x80000000 -#define SBE_2T3E3_TX_DESC_LAST_SEGMENT 0x40000000 -#define SBE_2T3E3_TX_DESC_FIRST_SEGMENT 0x20000000 -#define SBE_2T3E3_TX_DESC_CRC_DISABLE 0x04000000 -#define SBE_2T3E3_TX_DESC_END_OF_RING 0x02000000 -#define SBE_2T3E3_TX_DESC_SECOND_ADDRESS_CHAINED 0x01000000 -#define SBE_2T3E3_TX_DESC_DISABLE_PADDING 0x00800000 -#define SBE_2T3E3_TX_DESC_BUFFER_2_SIZE 0x003ff800 -#define SBE_2T3E3_TX_DESC_BUFFER_1_SIZE 0x000007ff - - -#define SBE_2T3E3_MTU 1600 -#define SBE_2T3E3_CRC16_LENGTH 2 -#define SBE_2T3E3_CRC32_LENGTH 4 - -#define MCLBYTES (SBE_2T3E3_MTU + 128) - -struct channel { - struct pci_dev *pdev; - struct net_device *dev; - struct card *card; - unsigned long addr; /* DECchip */ - - int leds; - - /* pci specific */ - struct { - u32 slot; /* should be 0 or 1 */ - u32 command; - u8 cache_size; - } h; - - /* statistics */ - struct t3e3_stats s; - - /* running */ - struct { - u32 flags; - } r; - - /* parameters */ - struct t3e3_param p; - - u32 liu_regs[SBE_2T3E3_LIU_REG_MAX]; /* LIU registers */ - u32 framer_regs[SBE_2T3E3_FRAMER_REG_MAX]; /* Framer registers */ - - /* Ethernet Controller */ - struct { - u_int16_t card_serial_number[3]; - - u32 reg[SBE_2T3E3_21143_REG_MAX]; /* registers i.e. CSR */ - - u32 interrupt_enable_mask; - - /* receive chain/ring */ - struct t3e3_rx_desc *rx_ring; - struct sk_buff *rx_data[SBE_2T3E3_RX_DESC_RING_SIZE]; - u32 rx_ring_current_read; - - /* transmit chain/ring */ - struct t3e3_tx_desc *tx_ring; - struct sk_buff *tx_data[SBE_2T3E3_TX_DESC_RING_SIZE]; - u32 tx_ring_current_read; - u32 tx_ring_current_write; - int tx_full; - int tx_free_cnt; - spinlock_t tx_lock; - } ether; - - int32_t interrupt_active; - int32_t rcv_count; -}; - -struct card { - spinlock_t bootrom_lock; - unsigned long bootrom_addr; - struct timer_list timer; /* for updating LEDs */ - struct channel channels[0]; -}; - -#define SBE_2T3E3_FLAG_NETWORK_UP 0x00000001 -#define SBE_2T3E3_FLAG_NO_ERROR_MESSAGES 0x00000002 - -extern const u32 cpld_reg_map[][2]; -extern const u32 cpld_val_map[][2]; -extern const u32 t3e3_framer_reg_map[]; -extern const u32 t3e3_liu_reg_map[]; - -void t3e3_init(struct channel *); -void t3e3_if_up(struct channel *); -void t3e3_if_down(struct channel *); -int t3e3_if_start_xmit(struct sk_buff *skb, struct net_device *dev); -void t3e3_if_config(struct channel *, u32, char *, struct t3e3_resp *, int *); -void t3e3_set_frame_type(struct channel *, u32); -u32 t3e3_eeprom_read_word(struct channel *, u32); -void t3e3_read_card_serial_number(struct channel *); - -/* interrupt handlers */ -irqreturn_t t3e3_intr(int irq, void *dev_instance); -void dc_intr(struct channel *); -void dc_intr_rx(struct channel *); -void dc_intr_tx(struct channel *); -void dc_intr_tx_underflow(struct channel *); -void exar7250_intr(struct channel *); -void exar7250_E3_intr(struct channel *, u32); -void exar7250_T3_intr(struct channel *, u32); - -/* Ethernet controller */ -u32 bootrom_read(struct channel *, u32); -void bootrom_write(struct channel *, u32, u32); -void dc_init(struct channel *); -void dc_start(struct channel *); -void dc_stop(struct channel *); -void dc_start_intr(struct channel *); -void dc_stop_intr(struct channel *); -void dc_reset(struct channel *); -void dc_restart(struct channel *); -void dc_receiver_onoff(struct channel *, u32); -void dc_transmitter_onoff(struct channel *, u32); -void dc_set_loopback(struct channel *, u32); -void dc_clear_descriptor_list(struct channel *); -void dc_drop_descriptor_list(struct channel *); -void dc_set_output_port(struct channel *); -void t3e3_sc_init(struct channel *); - -/* CPLD */ -void cpld_init(struct channel *sc); -u32 cpld_read(struct channel *sc, u32 reg); -void cpld_set_crc(struct channel *, u32); -void cpld_start_intr(struct channel *); -void cpld_stop_intr(struct channel *); -void cpld_set_clock(struct channel *sc, u32 mode); -void cpld_set_scrambler(struct channel *, u32); -void cpld_select_panel(struct channel *, u32); -void cpld_set_frame_mode(struct channel *, u32); -void cpld_set_frame_type(struct channel *, u32); -void cpld_set_pad_count(struct channel *, u32); -void cpld_set_fractional_mode(struct channel *, u32, u32, u32); -void cpld_LOS_update(struct channel *); - -/* Framer */ -extern u32 exar7250_read(struct channel *, u32); -extern void exar7250_write(struct channel *, u32, u32); -void exar7250_init(struct channel *); -void exar7250_start_intr(struct channel *, u32); -void exar7250_stop_intr(struct channel *, u32); -void exar7250_set_frame_type(struct channel *, u32); -void exar7250_set_loopback(struct channel *, u32); -void exar7250_unipolar_onoff(struct channel *, u32); - -/* LIU */ -u32 exar7300_read(struct channel *, u32); -void exar7300_write(struct channel *, u32, u32); -void exar7300_init(struct channel *); -void exar7300_line_build_out_onoff(struct channel *, u32); -void exar7300_set_frame_type(struct channel *, u32); -void exar7300_set_loopback(struct channel *, u32); -void exar7300_transmit_all_ones_onoff(struct channel *, u32); -void exar7300_receive_equalization_onoff(struct channel *, u32); -void exar7300_unipolar_onoff(struct channel *, u32); - -void update_led(struct channel *, int); -int setup_device(struct net_device *dev, struct channel *sc); - -static inline int has_two_ports(struct pci_dev *pdev) -{ - return pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_2T3E3_P0; -} - -#define dev_to_priv(dev) (*(struct channel **) ((hdlc_device *)(dev) + 1)) - -static inline u32 dc_read(unsigned long addr, u32 reg) -{ - return inl(addr + (reg << 3)); -} - -static inline void dc_write(unsigned long addr, u32 reg, u32 val) -{ - outl(val, addr + (reg << 3)); -} - -static inline void dc_set_bits(unsigned long addr, u32 reg, u32 bits) -{ - dc_write(addr, reg, dc_read(addr, reg) | bits); -} - -static inline void dc_clear_bits(unsigned long addr, u32 reg, u32 bits) -{ - dc_write(addr, reg, dc_read(addr, reg) & ~bits); -} - -#define CPLD_MAP_REG(reg, sc) (cpld_reg_map[(reg)][(sc)->h.slot]) - -static inline void cpld_write(struct channel *channel, unsigned reg, u32 val) -{ - unsigned long flags; - spin_lock_irqsave(&channel->card->bootrom_lock, flags); - bootrom_write(channel, CPLD_MAP_REG(reg, channel), val); - spin_unlock_irqrestore(&channel->card->bootrom_lock, flags); -} - -#define exar7250_set_bit(sc, reg, bit) \ - exar7250_write((sc), (reg), \ - exar7250_read(sc, reg) | (bit)) - -#define exar7250_clear_bit(sc, reg, bit) \ - exar7250_write((sc), (reg), \ - exar7250_read(sc, reg) & ~(bit)) - -#define exar7300_set_bit(sc, reg, bit) \ - exar7300_write((sc), (reg), \ - exar7300_read(sc, reg) | (bit)) - -#define exar7300_clear_bit(sc, reg, bit) \ - exar7300_write((sc), (reg), \ - exar7300_read(sc, reg) & ~(bit)) - - -#endif /* T3E3_H */ diff --git a/drivers/staging/sbe-2t3e3/Kconfig b/drivers/staging/sbe-2t3e3/Kconfig deleted file mode 100644 index 8ec86cfc6bf865..00000000000000 --- a/drivers/staging/sbe-2t3e3/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config SBE_2T3E3 - tristate "SBE wanPMC-2T3E3 support" - depends on HDLC && PCI - help - Driver for wanPMC-2T3E3 cards by SBE Inc. - - If you have such a card, say Y here and see - . - - To compile this as a module, choose M here: the - module will be called sbe-2t3e3. - - If unsure, say N. diff --git a/drivers/staging/sbe-2t3e3/Makefile b/drivers/staging/sbe-2t3e3/Makefile deleted file mode 100644 index cce2a7af626b3b..00000000000000 --- a/drivers/staging/sbe-2t3e3/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-$(CONFIG_SBE_2T3E3) += sbe-2t3e3.o - -sbe-2t3e3-y := module.o netdev.o maps.o \ - main.o cpld.o intr.o ctrl.o io.o dc.o exar7250.o exar7300.o diff --git a/drivers/staging/sbe-2t3e3/TODO b/drivers/staging/sbe-2t3e3/TODO deleted file mode 100644 index 624b20f70cf8e6..00000000000000 --- a/drivers/staging/sbe-2t3e3/TODO +++ /dev/null @@ -1,6 +0,0 @@ -TODO: - - additional cleaning and tests - - wait for the new configuration interface in generic HDLC layer and - when available, convert the driver to it - -Please send patches to Krzysztof Halasa . \ No newline at end of file diff --git a/drivers/staging/sbe-2t3e3/cpld.c b/drivers/staging/sbe-2t3e3/cpld.c deleted file mode 100644 index c6370d3d637f9d..00000000000000 --- a/drivers/staging/sbe-2t3e3/cpld.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#include -#include "2t3e3.h" -#include "ctrl.h" - -#define bootrom_set_bit(sc, reg, bit) \ - bootrom_write((sc), (reg), \ - bootrom_read((sc), (reg)) | (bit)) - -#define bootrom_clear_bit(sc, reg, bit) \ - bootrom_write((sc), (reg), \ - bootrom_read((sc), (reg)) & ~(bit)) - -static inline void cpld_set_bit(struct channel *channel, unsigned reg, u32 bit) -{ - unsigned long flags; - spin_lock_irqsave(&channel->card->bootrom_lock, flags); - bootrom_set_bit(channel, CPLD_MAP_REG(reg, channel), bit); - spin_unlock_irqrestore(&channel->card->bootrom_lock, flags); -} - -static inline void cpld_clear_bit(struct channel *channel, unsigned reg, u32 bit) -{ - unsigned long flags; - spin_lock_irqsave(&channel->card->bootrom_lock, flags); - bootrom_clear_bit(channel, CPLD_MAP_REG(reg, channel), bit); - spin_unlock_irqrestore(&channel->card->bootrom_lock, flags); -} - -void cpld_init(struct channel *sc) -{ - u32 val; - - /* PCRA */ - val = SBE_2T3E3_CPLD_VAL_CRC32 | - cpld_val_map[SBE_2T3E3_CPLD_VAL_LOOP_TIMING_SOURCE][sc->h.slot]; - cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRA, val); - - /* PCRB */ - val = 0; - cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRB, val); - - /* PCRC */ - val = 0; - cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, val); - - /* PBWF */ - val = 0; - cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWF, val); - - /* PBWL */ - val = 0; - cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWL, val); - - /* PLTR */ - val = SBE_2T3E3_CPLD_VAL_LCV_COUNTER; - cpld_write(sc, SBE_2T3E3_CPLD_REG_PLTR, val); - udelay(1000); - - /* PLCR */ - val = 0; - cpld_write(sc, SBE_2T3E3_CPLD_REG_PLCR, val); - udelay(1000); - - /* PPFR */ - val = 0x55; - cpld_write(sc, SBE_2T3E3_CPLD_REG_PPFR, val); - /* TODO: this doesn't work!!! */ - - /* SERIAL_CHIP_SELECT */ - val = 0; - cpld_write(sc, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, val); - - /* PICSR */ - val = SBE_2T3E3_CPLD_VAL_DMO_SIGNAL_DETECTED | - SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_LOCK_DETECTED | - SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED; - cpld_write(sc, SBE_2T3E3_CPLD_REG_PICSR, val); - - cpld_start_intr(sc); - - udelay(1000); -} - -void cpld_start_intr(struct channel *sc) -{ - u32 val; - - /* PIER */ - val = SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_ETHERNET_ENABLE | - SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_FRAMER_ENABLE; - cpld_write(sc, SBE_2T3E3_CPLD_REG_PIER, val); -} - -void cpld_stop_intr(struct channel *sc) -{ - u32 val; - - /* PIER */ - val = 0; - cpld_write(sc, SBE_2T3E3_CPLD_REG_PIER, val); -} - -void cpld_set_frame_mode(struct channel *sc, u32 mode) -{ - if (sc->p.frame_mode == mode) - return; - - switch (mode) { - case SBE_2T3E3_FRAME_MODE_HDLC: - cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, - SBE_2T3E3_CPLD_VAL_TRANSPARENT_MODE | - SBE_2T3E3_CPLD_VAL_RAW_MODE); - exar7250_unipolar_onoff(sc, SBE_2T3E3_OFF); - exar7300_unipolar_onoff(sc, SBE_2T3E3_OFF); - break; - case SBE_2T3E3_FRAME_MODE_TRANSPARENT: - cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, - SBE_2T3E3_CPLD_VAL_RAW_MODE); - cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, - SBE_2T3E3_CPLD_VAL_TRANSPARENT_MODE); - exar7250_unipolar_onoff(sc, SBE_2T3E3_OFF); - exar7300_unipolar_onoff(sc, SBE_2T3E3_OFF); - break; - case SBE_2T3E3_FRAME_MODE_RAW: - cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, - SBE_2T3E3_CPLD_VAL_RAW_MODE); - exar7250_unipolar_onoff(sc, SBE_2T3E3_ON); - exar7300_unipolar_onoff(sc, SBE_2T3E3_ON); - break; - default: - return; - } - - sc->p.frame_mode = mode; -} - -/* set rate of the local clock */ -void cpld_set_frame_type(struct channel *sc, u32 type) -{ - switch (type) { - case SBE_2T3E3_FRAME_TYPE_E3_G751: - case SBE_2T3E3_FRAME_TYPE_E3_G832: - cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, - SBE_2T3E3_CPLD_VAL_LOCAL_CLOCK_E3); - break; - case SBE_2T3E3_FRAME_TYPE_T3_CBIT: - case SBE_2T3E3_FRAME_TYPE_T3_M13: - cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, - SBE_2T3E3_CPLD_VAL_LOCAL_CLOCK_E3); - break; - default: - return; - } -} - -void cpld_set_scrambler(struct channel *sc, u32 mode) -{ - if (sc->p.scrambler == mode) - return; - - switch (mode) { - case SBE_2T3E3_SCRAMBLER_OFF: - cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, - SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE); - break; - case SBE_2T3E3_SCRAMBLER_LARSCOM: - cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, - SBE_2T3E3_CPLD_VAL_SCRAMBLER_TYPE); - cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, - SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE); - break; - case SBE_2T3E3_SCRAMBLER_ADC_KENTROX_DIGITAL: - cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, - SBE_2T3E3_CPLD_VAL_SCRAMBLER_TYPE); - cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, - SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE); - break; - default: - return; - } - - sc->p.scrambler = mode; -} - - -void cpld_set_crc(struct channel *sc, u32 crc) -{ - if (sc->p.crc == crc) - return; - - switch (crc) { - case SBE_2T3E3_CRC_16: - cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, - SBE_2T3E3_CPLD_VAL_CRC32); - break; - case SBE_2T3E3_CRC_32: - cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, - SBE_2T3E3_CPLD_VAL_CRC32); - break; - default: - return; - } - - sc->p.crc = crc; -} - - -void cpld_select_panel(struct channel *sc, u32 panel) -{ - if (sc->p.panel == panel) - return; - switch (panel) { - case SBE_2T3E3_PANEL_FRONT: - cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, - SBE_2T3E3_CPLD_VAL_REAR_PANEL); - break; - case SBE_2T3E3_PANEL_REAR: - cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, - SBE_2T3E3_CPLD_VAL_REAR_PANEL); - break; - default: - return; - } - - udelay(100); - - sc->p.panel = panel; -} - - -void cpld_set_clock(struct channel *sc, u32 mode) -{ - if (sc->p.clock_source == mode) - return; - - switch (mode) { - case SBE_2T3E3_TIMING_LOCAL: - cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, - SBE_2T3E3_CPLD_VAL_ALT); - break; - case SBE_2T3E3_TIMING_LOOP: - cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, - SBE_2T3E3_CPLD_VAL_ALT); - break; - default: - return; - } - - sc->p.clock_source = mode; -} - -void cpld_set_pad_count(struct channel *sc, u32 count) -{ - u32 val; - - if (sc->p.pad_count == count) - return; - - switch (count) { - case SBE_2T3E3_PAD_COUNT_1: - val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_1; - break; - case SBE_2T3E3_PAD_COUNT_2: - val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_2; - break; - case SBE_2T3E3_PAD_COUNT_3: - val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_3; - break; - case SBE_2T3E3_PAD_COUNT_4: - val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_4; - break; - default: - return; - } - - cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, - SBE_2T3E3_CPLD_VAL_PAD_COUNT); - cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, val); - sc->p.pad_count = count; -} - -void cpld_LOS_update(struct channel *sc) -{ - u_int8_t los; - - cpld_write(sc, SBE_2T3E3_CPLD_REG_PICSR, - SBE_2T3E3_CPLD_VAL_DMO_SIGNAL_DETECTED | - SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_LOCK_DETECTED | - SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED); - los = cpld_read(sc, SBE_2T3E3_CPLD_REG_PICSR) & - SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED; - - if (los != sc->s.LOS) - dev_info(&sc->pdev->dev, "SBE 2T3E3: LOS status: %s\n", - los ? "Loss of signal" : "Signal OK"); - sc->s.LOS = los; -} - -void cpld_set_fractional_mode(struct channel *sc, u32 mode, - u32 start, u32 stop) -{ - if (mode == SBE_2T3E3_FRACTIONAL_MODE_NONE) { - start = 0; - stop = 0; - } - - if (sc->p.fractional_mode == mode && sc->p.bandwidth_start == start && - sc->p.bandwidth_stop == stop) - return; - - switch (mode) { - case SBE_2T3E3_FRACTIONAL_MODE_NONE: - cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, - SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_NONE); - break; - case SBE_2T3E3_FRACTIONAL_MODE_0: - cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, - SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_0); - break; - case SBE_2T3E3_FRACTIONAL_MODE_1: - cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, - SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_1); - break; - case SBE_2T3E3_FRACTIONAL_MODE_2: - cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, - SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_2); - break; - default: - netdev_err(sc->dev, "wrong mode in set_fractional_mode\n"); - return; - } - - cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWF, start); - cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWL, stop); - - sc->p.fractional_mode = mode; - sc->p.bandwidth_start = start; - sc->p.bandwidth_stop = stop; -} diff --git a/drivers/staging/sbe-2t3e3/ctrl.c b/drivers/staging/sbe-2t3e3/ctrl.c deleted file mode 100644 index e0964ac9e7d7fa..00000000000000 --- a/drivers/staging/sbe-2t3e3/ctrl.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#include -#include "2t3e3.h" -#include "ctrl.h" - -void t3e3_set_frame_type(struct channel *sc, u32 mode) -{ - if (sc->p.frame_type == mode) - return; - - if (sc->r.flags & SBE_2T3E3_FLAG_NETWORK_UP) { - dev_err(&sc->pdev->dev, "SBE 2T3E3: changing frame type during active connection\n"); - return; - } - - exar7300_set_frame_type(sc, mode); - exar7250_set_frame_type(sc, mode); - cpld_set_frame_type(sc, mode); - - sc->p.frame_type = mode; -} - -static void t3e3_set_loopback(struct channel *sc, u32 mode) -{ - u32 tx, rx; - - if (sc->p.loopback == mode) - return; - - tx = sc->p.transmitter_on; - rx = sc->p.receiver_on; - if (tx == SBE_2T3E3_ON) - dc_transmitter_onoff(sc, SBE_2T3E3_OFF); - if (rx == SBE_2T3E3_ON) - dc_receiver_onoff(sc, SBE_2T3E3_OFF); - - /* stop current loopback if any exists */ - switch (sc->p.loopback) { - case SBE_2T3E3_LOOPBACK_NONE: - break; - case SBE_2T3E3_LOOPBACK_ETHERNET: - dc_set_loopback(sc, SBE_2T3E3_21143_VAL_LOOPBACK_OFF); - break; - case SBE_2T3E3_LOOPBACK_FRAMER: - exar7250_set_loopback(sc, SBE_2T3E3_FRAMER_VAL_LOOPBACK_OFF); - break; - case SBE_2T3E3_LOOPBACK_LIU_DIGITAL: - case SBE_2T3E3_LOOPBACK_LIU_ANALOG: - case SBE_2T3E3_LOOPBACK_LIU_REMOTE: - exar7300_set_loopback(sc, SBE_2T3E3_LIU_VAL_LOOPBACK_OFF); - break; - default: - return; - } - - switch (mode) { - case SBE_2T3E3_LOOPBACK_NONE: - break; - case SBE_2T3E3_LOOPBACK_ETHERNET: - dc_set_loopback(sc, SBE_2T3E3_21143_VAL_LOOPBACK_INTERNAL); - break; - case SBE_2T3E3_LOOPBACK_FRAMER: - exar7250_set_loopback(sc, SBE_2T3E3_FRAMER_VAL_LOOPBACK_ON); - break; - case SBE_2T3E3_LOOPBACK_LIU_DIGITAL: - exar7300_set_loopback(sc, SBE_2T3E3_LIU_VAL_LOOPBACK_DIGITAL); - break; - case SBE_2T3E3_LOOPBACK_LIU_ANALOG: - exar7300_set_loopback(sc, SBE_2T3E3_LIU_VAL_LOOPBACK_ANALOG); - break; - case SBE_2T3E3_LOOPBACK_LIU_REMOTE: - exar7300_set_loopback(sc, SBE_2T3E3_LIU_VAL_LOOPBACK_REMOTE); - break; - default: - return; - } - - sc->p.loopback = mode; - - if (tx == SBE_2T3E3_ON) - dc_transmitter_onoff(sc, SBE_2T3E3_ON); - if (rx == SBE_2T3E3_ON) - dc_receiver_onoff(sc, SBE_2T3E3_ON); -} - - -static void t3e3_reg_read(struct channel *sc, u32 *reg, u32 *val) -{ - u32 i; - - *val = 0; - - switch (reg[0]) { - case SBE_2T3E3_CHIP_21143: - if (!(reg[1] & 7)) - *val = dc_read(sc->addr, reg[1] / 8); - break; - case SBE_2T3E3_CHIP_CPLD: - for (i = 0; i < SBE_2T3E3_CPLD_REG_MAX; i++) - if (cpld_reg_map[i][sc->h.slot] == reg[1]) { - *val = cpld_read(sc, i); - break; - } - break; - case SBE_2T3E3_CHIP_FRAMER: - for (i = 0; i < SBE_2T3E3_FRAMER_REG_MAX; i++) - if (t3e3_framer_reg_map[i] == reg[1]) { - *val = exar7250_read(sc, i); - break; - } - break; - case SBE_2T3E3_CHIP_LIU: - for (i = 0; i < SBE_2T3E3_LIU_REG_MAX; i++) - if (t3e3_liu_reg_map[i] == reg[1]) { - *val = exar7300_read(sc, i); - break; - } - break; - default: - break; - } -} - -static void t3e3_reg_write(struct channel *sc, u32 *reg) -{ - u32 i; - - switch (reg[0]) { - case SBE_2T3E3_CHIP_21143: - dc_write(sc->addr, reg[1], reg[2]); - break; - case SBE_2T3E3_CHIP_CPLD: - for (i = 0; i < SBE_2T3E3_CPLD_REG_MAX; i++) - if (cpld_reg_map[i][sc->h.slot] == reg[1]) { - cpld_write(sc, i, reg[2]); - break; - } - break; - case SBE_2T3E3_CHIP_FRAMER: - for (i = 0; i < SBE_2T3E3_FRAMER_REG_MAX; i++) - if (t3e3_framer_reg_map[i] == reg[1]) { - exar7250_write(sc, i, reg[2]); - break; - } - break; - case SBE_2T3E3_CHIP_LIU: - for (i = 0; i < SBE_2T3E3_LIU_REG_MAX; i++) - if (t3e3_liu_reg_map[i] == reg[1]) { - exar7300_write(sc, i, reg[2]); - break; - } - break; - } -} - -static void t3e3_port_get(struct channel *sc, struct t3e3_param *param) -{ - memcpy(param, &(sc->p), sizeof(struct t3e3_param)); -} - -static void t3e3_port_set(struct channel *sc, struct t3e3_param *param) -{ - if (param->frame_mode != 0xff) - cpld_set_frame_mode(sc, param->frame_mode); - - if (param->fractional_mode != 0xff) - cpld_set_fractional_mode(sc, param->fractional_mode, - param->bandwidth_start, - param->bandwidth_stop); - - if (param->pad_count != 0xff) - cpld_set_pad_count(sc, param->pad_count); - - if (param->crc != 0xff) - cpld_set_crc(sc, param->crc); - - if (param->receiver_on != 0xff) - dc_receiver_onoff(sc, param->receiver_on); - - if (param->transmitter_on != 0xff) - dc_transmitter_onoff(sc, param->transmitter_on); - - if (param->frame_type != 0xff) - t3e3_set_frame_type(sc, param->frame_type); - - if (param->panel != 0xff) - cpld_select_panel(sc, param->panel); - - if (param->line_build_out != 0xff) - exar7300_line_build_out_onoff(sc, param->line_build_out); - - if (param->receive_equalization != 0xff) - exar7300_receive_equalization_onoff(sc, param->receive_equalization); - - if (param->transmit_all_ones != 0xff) - exar7300_transmit_all_ones_onoff(sc, param->transmit_all_ones); - - if (param->loopback != 0xff) - t3e3_set_loopback(sc, param->loopback); - - if (param->clock_source != 0xff) - cpld_set_clock(sc, param->clock_source); - - if (param->scrambler != 0xff) - cpld_set_scrambler(sc, param->scrambler); -} - -static void t3e3_port_get_stats(struct channel *sc, struct t3e3_stats *stats) -{ - u32 result; - - sc->s.LOC = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_IO_CONTROL) - & SBE_2T3E3_FRAMER_VAL_LOSS_OF_CLOCK_STATUS ? 1 : 0; - - switch (sc->p.frame_type) { - case SBE_2T3E3_FRAME_TYPE_E3_G751: - case SBE_2T3E3_FRAME_TYPE_E3_G832: - result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_CONFIGURATION_STATUS_2); - sc->s.LOF = result & SBE_2T3E3_FRAMER_VAL_E3_RX_LOF ? 1 : 0; - sc->s.OOF = result & SBE_2T3E3_FRAMER_VAL_E3_RX_OOF ? 1 : 0; - - cpld_LOS_update(sc); - - sc->s.AIS = result & SBE_2T3E3_FRAMER_VAL_E3_RX_AIS ? 1 : 0; - sc->s.FERF = result & SBE_2T3E3_FRAMER_VAL_E3_RX_FERF ? 1 : 0; - break; - - case SBE_2T3E3_FRAME_TYPE_T3_CBIT: - case SBE_2T3E3_FRAME_TYPE_T3_M13: - result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_CONFIGURATION_STATUS); - sc->s.AIS = result & SBE_2T3E3_FRAMER_VAL_T3_RX_AIS ? 1 : 0; - - cpld_LOS_update(sc); - - sc->s.IDLE = result & SBE_2T3E3_FRAMER_VAL_T3_RX_IDLE ? 1 : 0; - sc->s.OOF = result & SBE_2T3E3_FRAMER_VAL_T3_RX_OOF ? 1 : 0; - - result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_STATUS); - sc->s.FERF = result & SBE_2T3E3_FRAMER_VAL_T3_RX_FERF ? 1 : 0; - sc->s.AIC = result & SBE_2T3E3_FRAMER_VAL_T3_RX_AIC ? 1 : 0; - sc->s.FEBE_code = result & SBE_2T3E3_FRAMER_VAL_T3_RX_FEBE; - - sc->s.FEAC = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_FEAC); - break; - - default: - break; - } - - result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_LCV_EVENT_COUNT_MSB) << 8; - result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); - sc->s.LCV += result; - - result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_FRAMING_BIT_ERROR_EVENT_COUNT_MSB) << 8; - result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); - sc->s.FRAMING_BIT += result; - - result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_PARITY_ERROR_EVENT_COUNT_MSB) << 8; - result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); - sc->s.PARITY_ERROR += result; - - result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_FEBE_EVENT_COUNT_MSB) << 8; - result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); - sc->s.FEBE_count += result; - - result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_CP_BIT_ERROR_EVENT_COUNT_MSB) << 8; - result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); - sc->s.CP_BIT += result; - - memcpy(stats, &(sc->s), sizeof(struct t3e3_stats)); -} - -static void t3e3_port_del_stats(struct channel *sc) -{ - memset(&(sc->s), 0, sizeof(struct t3e3_stats)); -} - -void t3e3_if_config(struct channel *sc, u32 cmd, char *set, - struct t3e3_resp *ret, int *rlen) -{ - struct t3e3_param *param = (struct t3e3_param *)set; - u32 *data = (u32 *)set; - - /* turn off all interrupt */ - /* cpld_stop_intr(sc); */ - - switch (cmd) { - case SBE_2T3E3_PORT_GET: - t3e3_port_get(sc, &(ret->u.param)); - *rlen = sizeof(ret->u.param); - break; - case SBE_2T3E3_PORT_SET: - t3e3_port_set(sc, param); - *rlen = 0; - break; - case SBE_2T3E3_PORT_GET_STATS: - t3e3_port_get_stats(sc, &(ret->u.stats)); - *rlen = sizeof(ret->u.stats); - break; - case SBE_2T3E3_PORT_DEL_STATS: - t3e3_port_del_stats(sc); - *rlen = 0; - break; - case SBE_2T3E3_PORT_READ_REGS: - t3e3_reg_read(sc, data, &(ret->u.data)); - *rlen = sizeof(ret->u.data); - break; - case SBE_2T3E3_PORT_WRITE_REGS: - t3e3_reg_write(sc, data); - *rlen = 0; - break; - case SBE_2T3E3_LOG_LEVEL: - *rlen = 0; - break; - default: - *rlen = 0; - break; - } -} - -void t3e3_sc_init(struct channel *sc) -{ - memset(sc, 0, sizeof(*sc)); - - sc->p.frame_mode = SBE_2T3E3_FRAME_MODE_HDLC; - sc->p.fractional_mode = SBE_2T3E3_FRACTIONAL_MODE_NONE; - sc->p.crc = SBE_2T3E3_CRC_32; - sc->p.receiver_on = SBE_2T3E3_OFF; - sc->p.transmitter_on = SBE_2T3E3_OFF; - sc->p.frame_type = SBE_2T3E3_FRAME_TYPE_T3_CBIT; - sc->p.panel = SBE_2T3E3_PANEL_FRONT; - sc->p.line_build_out = SBE_2T3E3_OFF; - sc->p.receive_equalization = SBE_2T3E3_OFF; - sc->p.transmit_all_ones = SBE_2T3E3_OFF; - sc->p.loopback = SBE_2T3E3_LOOPBACK_NONE; - sc->p.clock_source = SBE_2T3E3_TIMING_LOCAL; - sc->p.scrambler = SBE_2T3E3_SCRAMBLER_OFF; - sc->p.pad_count = SBE_2T3E3_PAD_COUNT_1; -} diff --git a/drivers/staging/sbe-2t3e3/ctrl.h b/drivers/staging/sbe-2t3e3/ctrl.h deleted file mode 100644 index 41f144d75c36ae..00000000000000 --- a/drivers/staging/sbe-2t3e3/ctrl.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#ifndef CTRL_H -#define CTRL_H - -#define SBE_2T3E3_OFF 0 -#define SBE_2T3E3_ON 1 - -#define SBE_2T3E3_LED_NONE 0 -#define SBE_2T3E3_LED_GREEN 1 -#define SBE_2T3E3_LED_YELLOW 2 - -#define SBE_2T3E3_CABLE_LENGTH_LESS_THAN_255_FEET 0 -#define SBE_2T3E3_CABLE_LENGTH_GREATER_THAN_255_FEET 1 - -#define SBE_2T3E3_CRC_16 0 -#define SBE_2T3E3_CRC_32 1 - -#define SBE_2T3E3_PANEL_FRONT 0 -#define SBE_2T3E3_PANEL_REAR 1 - -#define SBE_2T3E3_FRAME_MODE_HDLC 0 -#define SBE_2T3E3_FRAME_MODE_TRANSPARENT 1 -#define SBE_2T3E3_FRAME_MODE_RAW 2 - -#define SBE_2T3E3_FRAME_TYPE_E3_G751 0 -#define SBE_2T3E3_FRAME_TYPE_E3_G832 1 -#define SBE_2T3E3_FRAME_TYPE_T3_CBIT 2 -#define SBE_2T3E3_FRAME_TYPE_T3_M13 3 - -#define SBE_2T3E3_FRACTIONAL_MODE_NONE 0 -#define SBE_2T3E3_FRACTIONAL_MODE_0 1 -#define SBE_2T3E3_FRACTIONAL_MODE_1 2 -#define SBE_2T3E3_FRACTIONAL_MODE_2 3 - -#define SBE_2T3E3_SCRAMBLER_OFF 0 -#define SBE_2T3E3_SCRAMBLER_LARSCOM 1 -#define SBE_2T3E3_SCRAMBLER_ADC_KENTROX_DIGITAL 2 - -#define SBE_2T3E3_TIMING_LOCAL 0 -#define SBE_2T3E3_TIMING_LOOP 1 - -#define SBE_2T3E3_LOOPBACK_NONE 0 -#define SBE_2T3E3_LOOPBACK_ETHERNET 1 -#define SBE_2T3E3_LOOPBACK_FRAMER 2 -#define SBE_2T3E3_LOOPBACK_LIU_DIGITAL 3 -#define SBE_2T3E3_LOOPBACK_LIU_ANALOG 4 -#define SBE_2T3E3_LOOPBACK_LIU_REMOTE 5 - -#define SBE_2T3E3_PAD_COUNT_1 1 -#define SBE_2T3E3_PAD_COUNT_2 2 -#define SBE_2T3E3_PAD_COUNT_3 3 -#define SBE_2T3E3_PAD_COUNT_4 4 - -#define SBE_2T3E3_CHIP_21143 0 -#define SBE_2T3E3_CHIP_CPLD 1 -#define SBE_2T3E3_CHIP_FRAMER 2 -#define SBE_2T3E3_CHIP_LIU 3 - -#define SBE_2T3E3_LOG_LEVEL_NONE 0 -#define SBE_2T3E3_LOG_LEVEL_ERROR 1 -#define SBE_2T3E3_LOG_LEVEL_WARNING 2 -#define SBE_2T3E3_LOG_LEVEL_INFO 3 - -/* commands */ -#define SBE_2T3E3_PORT_GET 0 -#define SBE_2T3E3_PORT_SET 1 -#define SBE_2T3E3_PORT_GET_STATS 2 -#define SBE_2T3E3_PORT_DEL_STATS 3 -#define SBE_2T3E3_PORT_READ_REGS 4 -#define SBE_2T3E3_LOG_LEVEL 5 -#define SBE_2T3E3_PORT_WRITE_REGS 6 - -#define NG_SBE_2T3E3_NODE_TYPE "sbe2T3E3" -#define NG_SBE_2T3E3_COOKIE 0x03800891 - -struct t3e3_param { - u_int8_t frame_mode; /* FRAME_MODE_* */ - u_int8_t crc; /* CRC_* */ - u_int8_t receiver_on; /* ON/OFF */ - u_int8_t transmitter_on; /* ON/OFF */ - u_int8_t frame_type; /* FRAME_TYPE_* */ - u_int8_t panel; /* PANEL_* */ - u_int8_t line_build_out; /* ON/OFF */ - u_int8_t receive_equalization; /* ON/OFF */ - u_int8_t transmit_all_ones; /* ON/OFF */ - u_int8_t loopback; /* LOOPBACK_* */ - u_int8_t clock_source; /* TIMING_* */ - u_int8_t scrambler; /* SCRAMBLER_* */ - u_int8_t pad_count; /* PAD_COUNT_* */ - u_int8_t log_level; /* LOG_LEVEL_* - unused */ - u_int8_t fractional_mode; /* FRACTIONAL_MODE_* */ - u_int8_t bandwidth_start; /* 0-255 */ - u_int8_t bandwidth_stop; /* 0-255 */ -}; - -struct t3e3_stats { - u_int64_t in_bytes; - u32 in_packets, in_dropped; - u32 in_errors, in_error_desc, in_error_coll, in_error_drib, - in_error_crc, in_error_mii; - u_int64_t out_bytes; - u32 out_packets, out_dropped; - u32 out_errors, out_error_jab, out_error_lost_carr, - out_error_no_carr, out_error_link_fail, out_error_underflow, - out_error_dereferred; - u_int8_t LOC, LOF, OOF, LOS, AIS, FERF, IDLE, AIC, FEAC; - u_int16_t FEBE_code; - u32 LCV, FRAMING_BIT, PARITY_ERROR, FEBE_count, CP_BIT; -}; - - -struct t3e3_resp { - union { - struct t3e3_param param; - struct t3e3_stats stats; - u32 data; - } u; -}; - -#endif /* CTRL_H */ diff --git a/drivers/staging/sbe-2t3e3/dc.c b/drivers/staging/sbe-2t3e3/dc.c deleted file mode 100644 index 02510f67ac4585..00000000000000 --- a/drivers/staging/sbe-2t3e3/dc.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#include -#include -#include -#include -#include "2t3e3.h" -#include "ctrl.h" - -static int dc_init_descriptor_list(struct channel *sc); - -void dc_init(struct channel *sc) -{ - u32 val; - - dc_stop(sc); - /*dc_reset(sc);*/ /* do not want to reset here */ - - /* - * BUS_MODE (CSR0) - */ - val = SBE_2T3E3_21143_VAL_READ_LINE_ENABLE | - SBE_2T3E3_21143_VAL_READ_MULTIPLE_ENABLE | - SBE_2T3E3_21143_VAL_TRANSMIT_AUTOMATIC_POLLING_200us | - SBE_2T3E3_21143_VAL_BUS_ARBITRATION_RR; - - if (sc->h.command & 16) - val |= SBE_2T3E3_21143_VAL_WRITE_AND_INVALIDATE_ENABLE; - - switch (sc->h.cache_size) { - case 32: - val |= SBE_2T3E3_21143_VAL_CACHE_ALIGNMENT_32; - break; - case 16: - val |= SBE_2T3E3_21143_VAL_CACHE_ALIGNMENT_16; - break; - case 8: - val |= SBE_2T3E3_21143_VAL_CACHE_ALIGNMENT_8; - break; - default: - break; - } - - dc_write(sc->addr, SBE_2T3E3_21143_REG_BUS_MODE, val); - - /* OPERATION_MODE (CSR6) */ - val = SBE_2T3E3_21143_VAL_RECEIVE_ALL | - SBE_2T3E3_21143_VAL_MUST_BE_ONE | - SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_1 | - SBE_2T3E3_21143_VAL_LOOPBACK_OFF | - SBE_2T3E3_21143_VAL_PASS_ALL_MULTICAST | - SBE_2T3E3_21143_VAL_PROMISCUOUS_MODE | - SBE_2T3E3_21143_VAL_PASS_BAD_FRAMES; - dc_write(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, val); - if (sc->p.loopback == SBE_2T3E3_LOOPBACK_ETHERNET) - sc->p.loopback = SBE_2T3E3_LOOPBACK_NONE; - - /* - * GENERAL_PURPOSE_TIMER_AND_INTERRUPT_MITIGATION_CONTROL (CSR11) - */ - val = SBE_2T3E3_21143_VAL_CYCLE_SIZE | - SBE_2T3E3_21143_VAL_TRANSMIT_TIMER | - SBE_2T3E3_21143_VAL_NUMBER_OF_TRANSMIT_PACKETS | - SBE_2T3E3_21143_VAL_RECEIVE_TIMER | - SBE_2T3E3_21143_VAL_NUMBER_OF_RECEIVE_PACKETS; - dc_write(sc->addr, SBE_2T3E3_21143_REG_GENERAL_PURPOSE_TIMER_AND_INTERRUPT_MITIGATION_CONTROL, val); - - /* prepare descriptors and data for receive and transmit processes */ - if (dc_init_descriptor_list(sc) != 0) - return; - - /* clear ethernet interrupts status */ - dc_write(sc->addr, SBE_2T3E3_21143_REG_STATUS, 0xFFFFFFFF); - - /* SIA mode registers */ - dc_set_output_port(sc); -} - -void dc_start(struct channel *sc) -{ - u32 val; - - if (!(sc->r.flags & SBE_2T3E3_FLAG_NETWORK_UP)) - return; - - dc_init(sc); - - /* get actual LOS and OOF status */ - switch (sc->p.frame_type) { - case SBE_2T3E3_FRAME_TYPE_E3_G751: - case SBE_2T3E3_FRAME_TYPE_E3_G832: - val = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_CONFIGURATION_STATUS_2); - dev_dbg(&sc->pdev->dev, "Start Framer Rx Status = %02X\n", val); - sc->s.OOF = val & SBE_2T3E3_FRAMER_VAL_E3_RX_OOF ? 1 : 0; - break; - case SBE_2T3E3_FRAME_TYPE_T3_CBIT: - case SBE_2T3E3_FRAME_TYPE_T3_M13: - val = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_CONFIGURATION_STATUS); - dev_dbg(&sc->pdev->dev, "Start Framer Rx Status = %02X\n", val); - sc->s.OOF = val & SBE_2T3E3_FRAMER_VAL_T3_RX_OOF ? 1 : 0; - break; - default: - break; - } - cpld_LOS_update(sc); - - /* start receive and transmit processes */ - dc_transmitter_onoff(sc, SBE_2T3E3_ON); - dc_receiver_onoff(sc, SBE_2T3E3_ON); - - /* start interrupts */ - dc_start_intr(sc); -} - -#define MAX_INT_WAIT_CNT 12000 -void dc_stop(struct channel *sc) -{ - int wcnt; - - /* stop receive and transmit processes */ - dc_receiver_onoff(sc, SBE_2T3E3_OFF); - dc_transmitter_onoff(sc, SBE_2T3E3_OFF); - - /* turn off ethernet interrupts */ - dc_stop_intr(sc); - - /* wait to ensure the interrupts have been completed */ - for (wcnt = 0; wcnt < MAX_INT_WAIT_CNT; wcnt++) { - udelay(5); - if (!sc->interrupt_active) - break; - } - if (wcnt >= MAX_INT_WAIT_CNT) - dev_warn(&sc->pdev->dev, "SBE 2T3E3: Interrupt active too long\n"); - - /* clear all receive/transmit data */ - dc_drop_descriptor_list(sc); -} - -void dc_start_intr(struct channel *sc) -{ - if (sc->p.loopback == SBE_2T3E3_LOOPBACK_NONE && sc->s.OOF) - return; - - if (sc->p.receiver_on || sc->p.transmitter_on) { - if (!sc->ether.interrupt_enable_mask) - dc_write(sc->addr, SBE_2T3E3_21143_REG_STATUS, 0xFFFFFFFF); - - sc->ether.interrupt_enable_mask = - SBE_2T3E3_21143_VAL_NORMAL_INTERRUPT_SUMMARY_ENABLE | - SBE_2T3E3_21143_VAL_ABNORMAL_INTERRUPT_SUMMARY_ENABLE | - SBE_2T3E3_21143_VAL_RECEIVE_STOPPED_ENABLE | - SBE_2T3E3_21143_VAL_RECEIVE_BUFFER_UNAVAILABLE_ENABLE | - SBE_2T3E3_21143_VAL_RECEIVE_INTERRUPT_ENABLE | - SBE_2T3E3_21143_VAL_TRANSMIT_UNDERFLOW_INTERRUPT_ENABLE | - SBE_2T3E3_21143_VAL_TRANSMIT_BUFFER_UNAVAILABLE_ENABLE | - SBE_2T3E3_21143_VAL_TRANSMIT_STOPPED_ENABLE | - SBE_2T3E3_21143_VAL_TRANSMIT_INTERRUPT_ENABLE; - - dc_write(sc->addr, SBE_2T3E3_21143_REG_INTERRUPT_ENABLE, - sc->ether.interrupt_enable_mask); - } -} - -void dc_stop_intr(struct channel *sc) -{ - sc->ether.interrupt_enable_mask = 0; - dc_write(sc->addr, SBE_2T3E3_21143_REG_INTERRUPT_ENABLE, 0); -} - -void dc_reset(struct channel *sc) -{ - /* turn off ethernet interrupts */ - dc_write(sc->addr, SBE_2T3E3_21143_REG_INTERRUPT_ENABLE, 0); - dc_write(sc->addr, SBE_2T3E3_21143_REG_STATUS, 0xFFFFFFFF); - - /* software reset */ - dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_BUS_MODE, - SBE_2T3E3_21143_VAL_SOFTWARE_RESET); - udelay(4); /* 50 PCI cycles < 2us */ - - /* clear hardware configuration */ - dc_write(sc->addr, SBE_2T3E3_21143_REG_BUS_MODE, 0); - - /* clear software configuration */ - dc_write(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, 0); - - /* turn off SIA reset */ - dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_SIA_CONNECTIVITY, - SBE_2T3E3_21143_VAL_SIA_RESET); - dc_write(sc->addr, SBE_2T3E3_21143_REG_SIA_TRANSMIT_AND_RECEIVE, 0); - dc_write(sc->addr, SBE_2T3E3_21143_REG_SIA_AND_GENERAL_PURPOSE_PORT, 0); -} - - -void dc_receiver_onoff(struct channel *sc, u32 mode) -{ - u32 i, state = 0; - - if (sc->p.receiver_on == mode) - return; - - switch (mode) { - case SBE_2T3E3_OFF: - if (dc_read(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE) & - SBE_2T3E3_21143_VAL_RECEIVE_START) { - dc_clear_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_RECEIVE_START); - - for (i = 0; i < 16; i++) { - state = dc_read(sc->addr, SBE_2T3E3_21143_REG_STATUS) & - SBE_2T3E3_21143_VAL_RECEIVE_PROCESS_STATE; - if (state == SBE_2T3E3_21143_VAL_RX_STOPPED) - break; - udelay(5); - } - if (state != SBE_2T3E3_21143_VAL_RX_STOPPED) - dev_warn(&sc->pdev->dev, "SBE 2T3E3: Rx failed to stop\n"); - else - dev_info(&sc->pdev->dev, "SBE 2T3E3: Rx off\n"); - } - break; - case SBE_2T3E3_ON: - dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_RECEIVE_START); - udelay(100); - dc_write(sc->addr, SBE_2T3E3_21143_REG_RECEIVE_POLL_DEMAND, 0xFFFFFFFF); - break; - default: - return; - } - - sc->p.receiver_on = mode; -} - -void dc_transmitter_onoff(struct channel *sc, u32 mode) -{ - u32 i, state = 0; - - if (sc->p.transmitter_on == mode) - return; - - switch (mode) { - case SBE_2T3E3_OFF: - if (dc_read(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE) & - SBE_2T3E3_21143_VAL_TRANSMISSION_START) { - dc_clear_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_TRANSMISSION_START); - - for (i = 0; i < 16; i++) { - state = dc_read(sc->addr, SBE_2T3E3_21143_REG_STATUS) & - SBE_2T3E3_21143_VAL_TRANSMISSION_PROCESS_STATE; - if (state == SBE_2T3E3_21143_VAL_TX_STOPPED) - break; - udelay(5); - } - if (state != SBE_2T3E3_21143_VAL_TX_STOPPED) - dev_warn(&sc->pdev->dev, "SBE 2T3E3: Tx failed to stop\n"); - } - break; - case SBE_2T3E3_ON: - dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_TRANSMISSION_START); - udelay(100); - dc_write(sc->addr, SBE_2T3E3_21143_REG_TRANSMIT_POLL_DEMAND, 0xFFFFFFFF); - break; - default: - return; - } - - sc->p.transmitter_on = mode; -} - - - -void dc_set_loopback(struct channel *sc, u32 mode) -{ - u32 val; - - switch (mode) { - case SBE_2T3E3_21143_VAL_LOOPBACK_OFF: - case SBE_2T3E3_21143_VAL_LOOPBACK_INTERNAL: - break; - default: - return; - } - - /* select loopback mode */ - val = dc_read(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE) & - ~SBE_2T3E3_21143_VAL_OPERATING_MODE; - val |= mode; - dc_write(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, val); - - if (mode == SBE_2T3E3_21143_VAL_LOOPBACK_OFF) - dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_FULL_DUPLEX_MODE); - else - dc_clear_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_FULL_DUPLEX_MODE); -} - -static int dc_init_descriptor_list(struct channel *sc) -{ - u32 i, j; - struct sk_buff *m; - - if (sc->ether.rx_ring == NULL) - sc->ether.rx_ring = kcalloc(SBE_2T3E3_RX_DESC_RING_SIZE, - sizeof(struct t3e3_rx_desc), GFP_KERNEL); - if (sc->ether.rx_ring == NULL) - return -ENOMEM; - - if (sc->ether.tx_ring == NULL) - sc->ether.tx_ring = kcalloc(SBE_2T3E3_TX_DESC_RING_SIZE, - sizeof(struct t3e3_tx_desc), GFP_KERNEL); - if (sc->ether.tx_ring == NULL) { - kfree(sc->ether.rx_ring); - sc->ether.rx_ring = NULL; - return -ENOMEM; - } - - - /* - * Receive ring - */ - for (i = 0; i < SBE_2T3E3_RX_DESC_RING_SIZE; i++) { - sc->ether.rx_ring[i].rdes0 = SBE_2T3E3_RX_DESC_21143_OWN; - sc->ether.rx_ring[i].rdes1 = - SBE_2T3E3_RX_DESC_SECOND_ADDRESS_CHAINED | SBE_2T3E3_MTU; - - if (sc->ether.rx_data[i] == NULL) { - m = dev_alloc_skb(MCLBYTES); - if (!m) { - for (j = 0; j < i; j++) { - dev_kfree_skb_any(sc->ether.rx_data[j]); - sc->ether.rx_data[j] = NULL; - } - kfree(sc->ether.rx_ring); - sc->ether.rx_ring = NULL; - kfree(sc->ether.tx_ring); - sc->ether.tx_ring = NULL; - dev_err(&sc->pdev->dev, "SBE 2T3E3: token_alloc err:" - " no buffer space for RX ring\n"); - return -ENOBUFS; - } - sc->ether.rx_data[i] = m; - } - sc->ether.rx_ring[i].rdes2 = virt_to_phys(sc->ether.rx_data[i]->data); - - sc->ether.rx_ring[i].rdes3 = virt_to_phys( - &sc->ether.rx_ring[(i + 1) % SBE_2T3E3_RX_DESC_RING_SIZE]); - } - sc->ether.rx_ring[SBE_2T3E3_RX_DESC_RING_SIZE - 1].rdes1 |= - SBE_2T3E3_RX_DESC_END_OF_RING; - sc->ether.rx_ring_current_read = 0; - - dc_write(sc->addr, SBE_2T3E3_21143_REG_RECEIVE_LIST_BASE_ADDRESS, - virt_to_phys(&sc->ether.rx_ring[0])); - - /* - * Transmit ring - */ - for (i = 0; i < SBE_2T3E3_TX_DESC_RING_SIZE; i++) { - sc->ether.tx_ring[i].tdes0 = 0; - sc->ether.tx_ring[i].tdes1 = SBE_2T3E3_TX_DESC_SECOND_ADDRESS_CHAINED | - SBE_2T3E3_TX_DESC_DISABLE_PADDING; - - sc->ether.tx_ring[i].tdes2 = 0; - sc->ether.tx_data[i] = NULL; - - sc->ether.tx_ring[i].tdes3 = virt_to_phys( - &sc->ether.tx_ring[(i + 1) % SBE_2T3E3_TX_DESC_RING_SIZE]); - } - sc->ether.tx_ring[SBE_2T3E3_TX_DESC_RING_SIZE - 1].tdes1 |= - SBE_2T3E3_TX_DESC_END_OF_RING; - - dc_write(sc->addr, SBE_2T3E3_21143_REG_TRANSMIT_LIST_BASE_ADDRESS, - virt_to_phys(&sc->ether.tx_ring[0])); - sc->ether.tx_ring_current_read = 0; - sc->ether.tx_ring_current_write = 0; - sc->ether.tx_free_cnt = SBE_2T3E3_TX_DESC_RING_SIZE; - spin_lock_init(&sc->ether.tx_lock); - - return 0; -} - -void dc_clear_descriptor_list(struct channel *sc) -{ - u32 i; - - /* clear CSR3 and CSR4 */ - dc_write(sc->addr, SBE_2T3E3_21143_REG_RECEIVE_LIST_BASE_ADDRESS, 0); - dc_write(sc->addr, SBE_2T3E3_21143_REG_TRANSMIT_LIST_BASE_ADDRESS, 0); - - /* free all data buffers on TX ring */ - for (i = 0; i < SBE_2T3E3_TX_DESC_RING_SIZE; i++) { - if (sc->ether.tx_data[i] != NULL) { - dev_kfree_skb_any(sc->ether.tx_data[i]); - sc->ether.tx_data[i] = NULL; - } - } -} - -void dc_drop_descriptor_list(struct channel *sc) -{ - u32 i; - - dc_clear_descriptor_list(sc); - - /* free all data buffers on RX ring */ - for (i = 0; i < SBE_2T3E3_RX_DESC_RING_SIZE; i++) { - if (sc->ether.rx_data[i] != NULL) { - dev_kfree_skb_any(sc->ether.rx_data[i]); - sc->ether.rx_data[i] = NULL; - } - } - - kfree(sc->ether.rx_ring); - sc->ether.rx_ring = NULL; - kfree(sc->ether.tx_ring); - sc->ether.tx_ring = NULL; -} - - -void dc_set_output_port(struct channel *sc) -{ - dc_clear_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_PORT_SELECT); - - dc_write(sc->addr, SBE_2T3E3_21143_REG_SIA_STATUS, 0x00000301); - dc_write(sc->addr, SBE_2T3E3_21143_REG_SIA_CONNECTIVITY, 0); - dc_write(sc->addr, SBE_2T3E3_21143_REG_SIA_TRANSMIT_AND_RECEIVE, 0); - dc_write(sc->addr, SBE_2T3E3_21143_REG_SIA_AND_GENERAL_PURPOSE_PORT, 0x08000011); - - dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_TRANSMIT_THRESHOLD_MODE_100Mbs | - SBE_2T3E3_21143_VAL_HEARTBEAT_DISABLE | - SBE_2T3E3_21143_VAL_PORT_SELECT | - SBE_2T3E3_21143_VAL_FULL_DUPLEX_MODE); -} - -void dc_restart(struct channel *sc) -{ - dev_warn(&sc->pdev->dev, "SBE 2T3E3: 21143 restart\n"); - - dc_stop(sc); - dc_reset(sc); - dc_init(sc); /* stop + reset + init */ - dc_start(sc); -} diff --git a/drivers/staging/sbe-2t3e3/exar7250.c b/drivers/staging/sbe-2t3e3/exar7250.c deleted file mode 100644 index e3ddd140207e21..00000000000000 --- a/drivers/staging/sbe-2t3e3/exar7250.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#include "2t3e3.h" -#include "ctrl.h" - -void exar7250_init(struct channel *sc) -{ - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_OPERATING_MODE, - SBE_2T3E3_FRAMER_VAL_T3_CBIT | - SBE_2T3E3_FRAMER_VAL_INTERRUPT_ENABLE_RESET | - SBE_2T3E3_FRAMER_VAL_TIMING_ASYNCH_TXINCLK); - - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_IO_CONTROL, - SBE_2T3E3_FRAMER_VAL_DISABLE_TX_LOSS_OF_CLOCK | - SBE_2T3E3_FRAMER_VAL_DISABLE_RX_LOSS_OF_CLOCK | - SBE_2T3E3_FRAMER_VAL_AMI_LINE_CODE | - SBE_2T3E3_FRAMER_VAL_RX_LINE_CLOCK_INVERT); - - exar7250_set_frame_type(sc, SBE_2T3E3_FRAME_TYPE_T3_CBIT); -} - -void exar7250_set_frame_type(struct channel *sc, u32 type) -{ - u32 val; - - switch (type) { - case SBE_2T3E3_FRAME_TYPE_E3_G751: - case SBE_2T3E3_FRAME_TYPE_E3_G832: - case SBE_2T3E3_FRAME_TYPE_T3_CBIT: - case SBE_2T3E3_FRAME_TYPE_T3_M13: - break; - default: - return; - } - - exar7250_stop_intr(sc, type); - - val = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_OPERATING_MODE); - val &= ~(SBE_2T3E3_FRAMER_VAL_LOCAL_LOOPBACK_MODE | - SBE_2T3E3_FRAMER_VAL_T3_E3_SELECT | - SBE_2T3E3_FRAMER_VAL_FRAME_FORMAT_SELECT); - switch (type) { - case SBE_2T3E3_FRAME_TYPE_E3_G751: - val |= SBE_2T3E3_FRAMER_VAL_E3_G751; - break; - case SBE_2T3E3_FRAME_TYPE_E3_G832: - val |= SBE_2T3E3_FRAMER_VAL_E3_G832; - break; - case SBE_2T3E3_FRAME_TYPE_T3_CBIT: - val |= SBE_2T3E3_FRAMER_VAL_T3_CBIT; - break; - case SBE_2T3E3_FRAME_TYPE_T3_M13: - val |= SBE_2T3E3_FRAMER_VAL_T3_M13; - break; - default: - return; - } - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_OPERATING_MODE, val); - exar7250_start_intr(sc, type); -} - - -void exar7250_start_intr(struct channel *sc, u32 type) -{ - u32 val; - - switch (type) { - case SBE_2T3E3_FRAME_TYPE_E3_G751: - case SBE_2T3E3_FRAME_TYPE_E3_G832: - val = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_CONFIGURATION_STATUS_2); - - cpld_LOS_update(sc); - - sc->s.OOF = val & SBE_2T3E3_FRAMER_VAL_E3_RX_OOF ? 1 : 0; - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_STATUS_1); - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_ENABLE_1, - SBE_2T3E3_FRAMER_VAL_E3_RX_OOF_INTERRUPT_ENABLE | - SBE_2T3E3_FRAMER_VAL_E3_RX_LOS_INTERRUPT_ENABLE); - - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_STATUS_2); - break; - - case SBE_2T3E3_FRAME_TYPE_T3_CBIT: - case SBE_2T3E3_FRAME_TYPE_T3_M13: - val = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_CONFIGURATION_STATUS); - - cpld_LOS_update(sc); - - sc->s.OOF = val & SBE_2T3E3_FRAMER_VAL_T3_RX_OOF ? 1 : 0; - - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_INTERRUPT_STATUS); - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_T3_RX_INTERRUPT_ENABLE, - SBE_2T3E3_FRAMER_VAL_T3_RX_LOS_INTERRUPT_ENABLE | - SBE_2T3E3_FRAMER_VAL_T3_RX_OOF_INTERRUPT_ENABLE); - - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_FEAC_INTERRUPT_ENABLE_STATUS); - - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_T3_RX_LAPD_CONTROL, 0); - break; - - default: - return; - } - - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_BLOCK_INTERRUPT_STATUS); - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_BLOCK_INTERRUPT_ENABLE, - SBE_2T3E3_FRAMER_VAL_RX_INTERRUPT_ENABLE | - SBE_2T3E3_FRAMER_VAL_TX_INTERRUPT_ENABLE); -} - - -void exar7250_stop_intr(struct channel *sc, u32 type) -{ - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_BLOCK_INTERRUPT_ENABLE, 0); - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_BLOCK_INTERRUPT_STATUS); - - switch (type) { - case SBE_2T3E3_FRAME_TYPE_E3_G751: - case SBE_2T3E3_FRAME_TYPE_E3_G832: - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_ENABLE_1, 0); - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_STATUS_1); - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_ENABLE_2, 0); - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_STATUS_2); - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_E3_RX_LAPD_CONTROL, 0); - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_LAPD_CONTROL); - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_E3_TX_LAPD_STATUS, 0); - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_TX_LAPD_STATUS); - break; - - case SBE_2T3E3_FRAME_TYPE_T3_CBIT: - case SBE_2T3E3_FRAME_TYPE_T3_M13: - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_T3_RX_INTERRUPT_ENABLE, 0); - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_INTERRUPT_STATUS); - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_T3_RX_FEAC_INTERRUPT_ENABLE_STATUS, 0); - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_FEAC_INTERRUPT_ENABLE_STATUS); - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_T3_RX_LAPD_CONTROL, 0); - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_LAPD_CONTROL); - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_T3_TX_FEAC_CONFIGURATION_STATUS, 0); - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_TX_FEAC_CONFIGURATION_STATUS); - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_T3_TX_LAPD_STATUS, 0); - exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_TX_LAPD_STATUS); - break; - } -} - - - - -void exar7250_unipolar_onoff(struct channel *sc, u32 mode) -{ - switch (mode) { - case SBE_2T3E3_OFF: - exar7300_clear_bit(sc, SBE_2T3E3_FRAMER_REG_IO_CONTROL, - SBE_2T3E3_FRAMER_VAL_UNIPOLAR); - break; - case SBE_2T3E3_ON: - exar7300_set_bit(sc, SBE_2T3E3_FRAMER_REG_IO_CONTROL, - SBE_2T3E3_FRAMER_VAL_UNIPOLAR); - break; - } -} - -void exar7250_set_loopback(struct channel *sc, u32 mode) -{ - switch (mode) { - case SBE_2T3E3_FRAMER_VAL_LOOPBACK_OFF: - exar7300_clear_bit(sc, SBE_2T3E3_FRAMER_REG_OPERATING_MODE, - SBE_2T3E3_FRAMER_VAL_LOCAL_LOOPBACK_MODE); - break; - case SBE_2T3E3_FRAMER_VAL_LOOPBACK_ON: - exar7300_set_bit(sc, SBE_2T3E3_FRAMER_REG_OPERATING_MODE, - SBE_2T3E3_FRAMER_VAL_LOCAL_LOOPBACK_MODE); - break; - } -} diff --git a/drivers/staging/sbe-2t3e3/exar7300.c b/drivers/staging/sbe-2t3e3/exar7300.c deleted file mode 100644 index cd229998a62eb7..00000000000000 --- a/drivers/staging/sbe-2t3e3/exar7300.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#include "2t3e3.h" -#include "ctrl.h" - -void exar7300_init(struct channel *sc) -{ - exar7300_write(sc, SBE_2T3E3_LIU_REG_REG1, 0); - - /* enable line decodeer and encoder */ - exar7300_write(sc, SBE_2T3E3_LIU_REG_REG2, 0); - exar7300_write(sc, SBE_2T3E3_LIU_REG_REG3, 0); - exar7300_write(sc, SBE_2T3E3_LIU_REG_REG4, - SBE_2T3E3_LIU_VAL_T3_MODE_SELECT | - SBE_2T3E3_LIU_VAL_LOOPBACK_OFF); -} - -void exar7300_set_loopback(struct channel *sc, u32 mode) -{ - u32 val; - - switch (mode) { - case SBE_2T3E3_LIU_VAL_LOOPBACK_OFF: - case SBE_2T3E3_LIU_VAL_LOOPBACK_REMOTE: - case SBE_2T3E3_LIU_VAL_LOOPBACK_ANALOG: - case SBE_2T3E3_LIU_VAL_LOOPBACK_DIGITAL: - break; - default: - return; - } - - val = exar7300_read(sc, SBE_2T3E3_LIU_REG_REG4); - val &= ~(SBE_2T3E3_LIU_VAL_LOCAL_LOOPBACK | SBE_2T3E3_LIU_VAL_REMOTE_LOOPBACK); - val |= mode; - exar7300_write(sc, SBE_2T3E3_LIU_REG_REG4, val); -} - -void exar7300_set_frame_type(struct channel *sc, u32 type) -{ - u32 val; - - switch (type) { - case SBE_2T3E3_FRAME_TYPE_T3_CBIT: - case SBE_2T3E3_FRAME_TYPE_T3_M13: - case SBE_2T3E3_FRAME_TYPE_E3_G751: - case SBE_2T3E3_FRAME_TYPE_E3_G832: - break; - default: - return; - } - - val = exar7300_read(sc, SBE_2T3E3_LIU_REG_REG4); - val &= ~(SBE_2T3E3_LIU_VAL_T3_MODE_SELECT | - SBE_2T3E3_LIU_VAL_E3_MODE_SELECT); - - switch (type) { - case SBE_2T3E3_FRAME_TYPE_T3_CBIT: - case SBE_2T3E3_FRAME_TYPE_T3_M13: - val |= SBE_2T3E3_LIU_VAL_T3_MODE_SELECT; - break; - case SBE_2T3E3_FRAME_TYPE_E3_G751: - case SBE_2T3E3_FRAME_TYPE_E3_G832: - val |= SBE_2T3E3_LIU_VAL_E3_MODE_SELECT; - break; - default: - return; - } - - exar7300_write(sc, SBE_2T3E3_LIU_REG_REG4, val); -} - - -void exar7300_transmit_all_ones_onoff(struct channel *sc, u32 mode) -{ - if (sc->p.transmit_all_ones == mode) - return; - - switch (mode) { - case SBE_2T3E3_ON: - exar7300_set_bit(sc, SBE_2T3E3_LIU_REG_REG1, - SBE_2T3E3_LIU_VAL_TRANSMIT_ALL_ONES); - break; - case SBE_2T3E3_OFF: - exar7300_clear_bit(sc, SBE_2T3E3_LIU_REG_REG1, - SBE_2T3E3_LIU_VAL_TRANSMIT_ALL_ONES); - break; - default: - return; - } - - sc->p.transmit_all_ones = mode; -} - -void exar7300_receive_equalization_onoff(struct channel *sc, u32 mode) -{ - if (sc->p.receive_equalization == mode) - return; - - switch (mode) { - case SBE_2T3E3_OFF: - exar7300_set_bit(sc, SBE_2T3E3_LIU_REG_REG2, - SBE_2T3E3_LIU_VAL_RECEIVE_EQUALIZATION_DISABLE); - break; - case SBE_2T3E3_ON: - exar7300_clear_bit(sc, SBE_2T3E3_LIU_REG_REG2, - SBE_2T3E3_LIU_VAL_RECEIVE_EQUALIZATION_DISABLE); - break; - default: - return; - } - - sc->p.receive_equalization = mode; -} - -void exar7300_line_build_out_onoff(struct channel *sc, u32 mode) -{ - if (sc->p.line_build_out == mode) - return; - - switch (mode) { - case SBE_2T3E3_OFF: - exar7300_set_bit(sc, SBE_2T3E3_LIU_REG_REG1, - SBE_2T3E3_LIU_VAL_TRANSMIT_LEVEL_SELECT); - exar7300_receive_equalization_onoff(sc, SBE_2T3E3_OFF); - break; - case SBE_2T3E3_ON: - exar7300_clear_bit(sc, SBE_2T3E3_LIU_REG_REG1, - SBE_2T3E3_LIU_VAL_TRANSMIT_LEVEL_SELECT); - exar7300_receive_equalization_onoff(sc, SBE_2T3E3_ON); - break; - default: - return; - } - - sc->p.line_build_out = mode; -} - -/* TODO - what about encoder in raw mode??? disable it too? */ -void exar7300_unipolar_onoff(struct channel *sc, u32 mode) -{ - switch (mode) { - case SBE_2T3E3_OFF: - exar7300_clear_bit(sc, SBE_2T3E3_LIU_REG_REG3, - SBE_2T3E3_LIU_VAL_DECODER_DISABLE); - exar7300_clear_bit(sc, SBE_2T3E3_LIU_REG_REG1, - SBE_2T3E3_LIU_VAL_TRANSMIT_BINARY_DATA); - break; - case SBE_2T3E3_ON: - exar7300_set_bit(sc, SBE_2T3E3_LIU_REG_REG3, - SBE_2T3E3_LIU_VAL_DECODER_DISABLE); - exar7300_set_bit(sc, SBE_2T3E3_LIU_REG_REG1, - SBE_2T3E3_LIU_VAL_TRANSMIT_BINARY_DATA); - break; - } -} diff --git a/drivers/staging/sbe-2t3e3/intr.c b/drivers/staging/sbe-2t3e3/intr.c deleted file mode 100644 index 1bf74b78800850..00000000000000 --- a/drivers/staging/sbe-2t3e3/intr.c +++ /dev/null @@ -1,579 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#include -#include -#include -#include "2t3e3.h" - -irqreturn_t t3e3_intr(int irq, void *dev_instance) -{ - struct channel *sc = dev_to_priv(dev_instance); - u32 val; - irqreturn_t ret = IRQ_NONE; - - sc->interrupt_active = 1; - - val = cpld_read(sc, SBE_2T3E3_CPLD_REG_PICSR); - - if (val & SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_CHANGE) { - dev_dbg(&sc->pdev->dev, - "Rx LOS Chng Int r=%02x (LOS|OOF=%02x)\n", - val, (sc->s.LOS << 4) | sc->s.OOF); - cpld_LOS_update(sc); - ret = IRQ_HANDLED; - } - - if (val & SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_ETHERNET_ASSERTED) { - dc_intr(sc); - ret = IRQ_HANDLED; - } - - if (val & SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_FRAMER_ASSERTED) { - exar7250_intr(sc); - ret = IRQ_HANDLED; - } - - /* - we don't care about other interrupt sources (DMO, LOS, LCV) because - they are handled by Framer too - */ - - sc->interrupt_active = 0; - return ret; -} - -void dc_intr(struct channel *sc) -{ - u32 val; - - /* disable ethernet interrupts */ - /* grrr this clears interrupt summary bits !!! */ - dc_write(sc->addr, SBE_2T3E3_21143_REG_INTERRUPT_ENABLE, 0); - - while ((val = dc_read(sc->addr, SBE_2T3E3_21143_REG_STATUS)) & - (SBE_2T3E3_21143_VAL_RECEIVE_PROCESS_STOPPED | - SBE_2T3E3_21143_VAL_RECEIVE_BUFFER_UNAVAILABLE | - SBE_2T3E3_21143_VAL_RECEIVE_INTERRUPT | - SBE_2T3E3_21143_VAL_TRANSMIT_UNDERFLOW | - SBE_2T3E3_21143_VAL_TRANSMIT_BUFFER_UNAVAILABLE | - SBE_2T3E3_21143_VAL_TRANSMIT_PROCESS_STOPPED | - SBE_2T3E3_21143_VAL_TRANSMIT_INTERRUPT)) { - dc_write(sc->addr, SBE_2T3E3_21143_REG_STATUS, val); - - dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Ethernet controller interrupt! (CSR5 = %08X)\n", - val); - - if (val & (SBE_2T3E3_21143_VAL_RECEIVE_INTERRUPT | - SBE_2T3E3_21143_VAL_RECEIVE_BUFFER_UNAVAILABLE | - SBE_2T3E3_21143_VAL_RECEIVE_PROCESS_STOPPED)) { - if (val & SBE_2T3E3_21143_VAL_RECEIVE_INTERRUPT) - dev_dbg(&sc->pdev->dev, - "Receive interrupt (LOS=%d, OOF=%d)\n", - sc->s.LOS, sc->s.OOF); - if (val & SBE_2T3E3_21143_VAL_RECEIVE_BUFFER_UNAVAILABLE) - dev_dbg(&sc->pdev->dev, - "Receive buffer unavailable\n"); - if (val & SBE_2T3E3_21143_VAL_RECEIVE_PROCESS_STOPPED) - dev_dbg(&sc->pdev->dev, - "Receive process stopped\n"); - dc_intr_rx(sc); - } - - if (val & SBE_2T3E3_21143_VAL_TRANSMIT_UNDERFLOW) { - dev_dbg(&sc->pdev->dev, "Transmit underflow\n"); - dc_intr_tx_underflow(sc); - } - - if (val & (SBE_2T3E3_21143_VAL_TRANSMIT_BUFFER_UNAVAILABLE | - SBE_2T3E3_21143_VAL_TRANSMIT_INTERRUPT | - SBE_2T3E3_21143_VAL_TRANSMIT_PROCESS_STOPPED)) { - if (val & SBE_2T3E3_21143_VAL_TRANSMIT_INTERRUPT) - dev_dbg(&sc->pdev->dev, "Transmit interrupt\n"); - if (val & SBE_2T3E3_21143_VAL_TRANSMIT_BUFFER_UNAVAILABLE) - dev_dbg(&sc->pdev->dev, - "Transmit buffer unavailable\n"); - if (val & SBE_2T3E3_21143_VAL_TRANSMIT_PROCESS_STOPPED) - dev_dbg(&sc->pdev->dev, - "Transmit process stopped\n"); - dc_intr_tx(sc); - } - } - - /* enable ethernet interrupts */ - dc_write(sc->addr, SBE_2T3E3_21143_REG_INTERRUPT_ENABLE, - sc->ether.interrupt_enable_mask); -} - -void dc_intr_rx(struct channel *sc) -{ - u32 current_read; - u32 error_mask, error; - struct t3e3_rx_desc *current_desc; - struct sk_buff *m, *m2; - unsigned rcv_len; - - sc->rcv_count++; /* for the activity LED */ - - current_read = sc->ether.rx_ring_current_read; - dev_dbg(&sc->pdev->dev, "intr_rx current_read = %d\n", current_read); - - /* when ethernet loopback is set, ignore framer signals */ - if ((sc->p.loopback != SBE_2T3E3_LOOPBACK_ETHERNET) && sc->s.OOF) { - while (!(sc->ether.rx_ring[current_read].rdes0 & - SBE_2T3E3_RX_DESC_21143_OWN)) { - current_desc = &sc->ether.rx_ring[current_read]; - current_desc->rdes1 &= SBE_2T3E3_RX_DESC_END_OF_RING | - SBE_2T3E3_RX_DESC_SECOND_ADDRESS_CHAINED; - current_desc->rdes1 |= SBE_2T3E3_MTU; - current_desc->rdes0 = SBE_2T3E3_RX_DESC_21143_OWN; - current_read = (current_read + 1) % SBE_2T3E3_RX_DESC_RING_SIZE; - } - sc->ether.rx_ring_current_read = current_read; - return; - } - - while (!(sc->ether.rx_ring[current_read].rdes0 & - SBE_2T3E3_RX_DESC_21143_OWN)) { - current_desc = &sc->ether.rx_ring[current_read]; - - dev_dbg(&sc->pdev->dev, "rdes0: %08X rdes1: %08X\n", - current_desc->rdes0, current_desc->rdes1); - - m = sc->ether.rx_data[current_read]; - rcv_len = (current_desc->rdes0 & SBE_2T3E3_RX_DESC_FRAME_LENGTH) >> - SBE_2T3E3_RX_DESC_FRAME_LENGTH_SHIFT; - - dev_dbg(&sc->pdev->dev, "mbuf was received (mbuf len = %d)\n", - rcv_len); - - switch (sc->p.crc) { - case SBE_2T3E3_CRC_16: - rcv_len -= SBE_2T3E3_CRC16_LENGTH; - break; - case SBE_2T3E3_CRC_32: - rcv_len -= SBE_2T3E3_CRC32_LENGTH; - break; - default: - break; - } - - if (current_desc->rdes0 & SBE_2T3E3_RX_DESC_LAST_DESC) { - - /* TODO: is collision possible? */ - error_mask = SBE_2T3E3_RX_DESC_DESC_ERROR | - SBE_2T3E3_RX_DESC_COLLISION_SEEN | - SBE_2T3E3_RX_DESC_DRIBBLING_BIT; - - switch (sc->p.frame_mode) { - case SBE_2T3E3_FRAME_MODE_HDLC: - error_mask |= SBE_2T3E3_RX_DESC_MII_ERROR; - if (sc->p.crc == SBE_2T3E3_CRC_32) - error_mask |= SBE_2T3E3_RX_DESC_CRC_ERROR; - break; - case SBE_2T3E3_FRAME_MODE_TRANSPARENT: - case SBE_2T3E3_FRAME_MODE_RAW: - break; - default: - error_mask = 0; - } - - if (sc->s.LOS) { - error_mask &= ~(SBE_2T3E3_RX_DESC_DRIBBLING_BIT | - SBE_2T3E3_RX_DESC_MII_ERROR); - } - - error = current_desc->rdes0 & error_mask; - if (error) { - sc->s.in_errors++; - dev_dbg(&sc->pdev->dev, - "error interrupt: NO_ERROR_MESSAGE = %d\n", - sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES ? 1 : 0); - - current_desc->rdes1 &= SBE_2T3E3_RX_DESC_END_OF_RING | - SBE_2T3E3_RX_DESC_SECOND_ADDRESS_CHAINED; - current_desc->rdes1 |= SBE_2T3E3_MTU; - current_desc->rdes0 = SBE_2T3E3_RX_DESC_21143_OWN; - - if (error & SBE_2T3E3_RX_DESC_DESC_ERROR) { - if (!(sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES)) - dev_err(&sc->pdev->dev, - "SBE 2T3E3: descriptor error\n"); - sc->s.in_error_desc++; - } - - if (error & SBE_2T3E3_RX_DESC_COLLISION_SEEN) { - if (!(sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES)) - dev_err(&sc->pdev->dev, - "SBE 2T3E3: collision seen\n"); - sc->s.in_error_coll++; - } else { - if (error & SBE_2T3E3_RX_DESC_DRIBBLING_BIT) { - if (!(sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES)) - dev_err(&sc->pdev->dev, - "SBE 2T3E3: dribbling bits error\n"); - sc->s.in_error_drib++; - } - - if (error & SBE_2T3E3_RX_DESC_CRC_ERROR) { - if (!(sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES)) - dev_err(&sc->pdev->dev, - "SBE 2T3E3: crc error\n"); - sc->s.in_error_crc++; - } - } - - if (error & SBE_2T3E3_RX_DESC_MII_ERROR) { - if (!(sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES)) - dev_err(&sc->pdev->dev, "SBE 2T3E3: mii error\n"); - sc->s.in_error_mii++; - } - - current_read = (current_read + 1) % SBE_2T3E3_RX_DESC_RING_SIZE; - sc->r.flags |= SBE_2T3E3_FLAG_NO_ERROR_MESSAGES; - continue; - } - } - - current_desc->rdes1 &= SBE_2T3E3_RX_DESC_END_OF_RING | - SBE_2T3E3_RX_DESC_SECOND_ADDRESS_CHAINED; - current_desc->rdes1 |= SBE_2T3E3_MTU; - - if (rcv_len > 1600) { - sc->s.in_errors++; - sc->s.in_dropped++; - if (!(sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES)) - dev_err(&sc->pdev->dev, "SBE 2T3E3: oversized rx: rdes0 = %08X\n", - current_desc->rdes0); - } else { - m2 = dev_alloc_skb(MCLBYTES); - if (m2 != NULL) { - current_desc->rdes2 = virt_to_phys(m2->data); - sc->ether.rx_data[current_read] = m2; - sc->s.in_packets++; - sc->s.in_bytes += rcv_len; - m->dev = sc->dev; - skb_put(m, rcv_len); - skb_reset_mac_header(m); - m->protocol = hdlc_type_trans(m, m->dev); - netif_rx(m); - - /* good packet was received so we will show error messages again... */ - if (sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES) { - dev_dbg(&sc->pdev->dev, - "setting ERROR_MESSAGES->0\n"); - sc->r.flags &= ~SBE_2T3E3_FLAG_NO_ERROR_MESSAGES; - } - - } else { - sc->s.in_errors++; - sc->s.in_dropped++; - } - } - current_desc->rdes0 = SBE_2T3E3_RX_DESC_21143_OWN; - current_read = (current_read + 1) % SBE_2T3E3_RX_DESC_RING_SIZE; - } - - sc->ether.rx_ring_current_read = current_read; - - dc_write(sc->addr, SBE_2T3E3_21143_REG_RECEIVE_POLL_DEMAND, 0xFFFFFFFF); -} - -void dc_intr_tx(struct channel *sc) -{ - u32 current_read, current_write; - u32 last_segment, error; - struct t3e3_tx_desc *current_desc; - - spin_lock(&sc->ether.tx_lock); - - current_read = sc->ether.tx_ring_current_read; - current_write = sc->ether.tx_ring_current_write; - - while (current_read != current_write) { - current_desc = &sc->ether.tx_ring[current_read]; - - if (current_desc->tdes0 & SBE_2T3E3_RX_DESC_21143_OWN) - break; - - dev_dbg(&sc->pdev->dev, - "txeof: tdes0 = %08X tdes1 = %08X\n", - current_desc->tdes0, current_desc->tdes1); - - error = current_desc->tdes0 & (SBE_2T3E3_TX_DESC_ERROR_SUMMARY | - SBE_2T3E3_TX_DESC_TRANSMIT_JABBER_TIMEOUT | - SBE_2T3E3_TX_DESC_LOSS_OF_CARRIER | - SBE_2T3E3_TX_DESC_NO_CARRIER | - SBE_2T3E3_TX_DESC_LINK_FAIL_REPORT | - SBE_2T3E3_TX_DESC_UNDERFLOW_ERROR | - SBE_2T3E3_TX_DESC_DEFFERED); - - last_segment = current_desc->tdes1 & SBE_2T3E3_TX_DESC_LAST_SEGMENT; - - current_desc->tdes0 = 0; - current_desc->tdes1 &= SBE_2T3E3_TX_DESC_END_OF_RING | - SBE_2T3E3_TX_DESC_SECOND_ADDRESS_CHAINED; - current_desc->tdes2 = 0; - sc->ether.tx_free_cnt++; - - if (last_segment != SBE_2T3E3_TX_DESC_LAST_SEGMENT) { - current_read = (current_read + 1) % SBE_2T3E3_TX_DESC_RING_SIZE; - continue; - } - - - if (sc->ether.tx_data[current_read]) { - sc->s.out_packets++; - sc->s.out_bytes += sc->ether.tx_data[current_read]->len; - dev_kfree_skb_any(sc->ether.tx_data[current_read]); - sc->ether.tx_data[current_read] = NULL; - } - - if (error > 0) { - sc->s.out_errors++; - - if (error & SBE_2T3E3_TX_DESC_TRANSMIT_JABBER_TIMEOUT) { - dev_err(&sc->pdev->dev, "SBE 2T3E3: transmit jabber timeout\n"); - sc->s.out_error_jab++; - } - - if (sc->p.loopback != SBE_2T3E3_LOOPBACK_ETHERNET) { - if (error & SBE_2T3E3_TX_DESC_LOSS_OF_CARRIER) { - dev_err(&sc->pdev->dev, "SBE 2T3E3: loss of carrier\n"); - sc->s.out_error_lost_carr++; - } - - if (error & SBE_2T3E3_TX_DESC_NO_CARRIER) { - dev_err(&sc->pdev->dev, "SBE 2T3E3: no carrier\n"); - sc->s.out_error_no_carr++; - } - } - - if (error & SBE_2T3E3_TX_DESC_LINK_FAIL_REPORT) { - dev_err(&sc->pdev->dev, "SBE 2T3E3: link fail report\n"); - sc->s.out_error_link_fail++; - } - - if (error & SBE_2T3E3_TX_DESC_UNDERFLOW_ERROR) { - dev_err(&sc->pdev->dev, "SBE 2T3E3:" - " transmission underflow error\n"); - sc->s.out_error_underflow++; - spin_unlock(&sc->ether.tx_lock); - - dc_restart(sc); - return; - } - - if (error & SBE_2T3E3_TX_DESC_DEFFERED) { - dev_err(&sc->pdev->dev, "SBE 2T3E3: transmission deferred\n"); - sc->s.out_error_dereferred++; - } - } - - current_read = (current_read + 1) % SBE_2T3E3_TX_DESC_RING_SIZE; - } - - sc->ether.tx_ring_current_read = current_read; - - /* Relieve flow control when the TX queue is drained at least half way */ - if (sc->ether.tx_full && - (sc->ether.tx_free_cnt >= (SBE_2T3E3_TX_DESC_RING_SIZE / 2))) { - sc->ether.tx_full = 0; - netif_wake_queue(sc->dev); - } - spin_unlock(&sc->ether.tx_lock); -} - - -void dc_intr_tx_underflow(struct channel *sc) -{ - u32 val; - - dc_transmitter_onoff(sc, SBE_2T3E3_OFF); - - val = dc_read(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE); - dc_clear_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS); - - switch (val & SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS) { - case SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_1: - dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_2); - break; - case SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_2: - dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_3); - break; - case SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_3: - dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_4); - break; - case SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_4: - default: - dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, - SBE_2T3E3_21143_VAL_STORE_AND_FORWARD); - break; - } - - dc_transmitter_onoff(sc, SBE_2T3E3_ON); -} - - - - -void exar7250_intr(struct channel *sc) -{ - u32 status, old_OOF; - - old_OOF = sc->s.OOF; - - status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_BLOCK_INTERRUPT_STATUS); - dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Framer interrupt! (REG[0x05] = %02X)\n", status); - - switch (sc->p.frame_type) { - case SBE_2T3E3_FRAME_TYPE_E3_G751: - case SBE_2T3E3_FRAME_TYPE_E3_G832: - exar7250_E3_intr(sc, status); - break; - - case SBE_2T3E3_FRAME_TYPE_T3_CBIT: - case SBE_2T3E3_FRAME_TYPE_T3_M13: - exar7250_T3_intr(sc, status); - break; - - default: - break; - } - - if (sc->s.OOF != old_OOF) { - if (sc->s.OOF) { - if (sc->p.loopback == SBE_2T3E3_LOOPBACK_NONE) { - dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Disabling eth interrupts\n"); - /* turn off ethernet interrupts */ - dc_stop_intr(sc); - } - } else if (sc->r.flags & SBE_2T3E3_FLAG_NETWORK_UP) { - dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Enabling eth interrupts\n"); - /* start interrupts */ - sc->s.OOF = 1; - dc_intr_rx(sc); - sc->s.OOF = 0; - if (sc->p.receiver_on) { - dc_receiver_onoff(sc, SBE_2T3E3_OFF); - dc_receiver_onoff(sc, SBE_2T3E3_ON); - } - dc_start_intr(sc); - } - } -} - - -void exar7250_T3_intr(struct channel *sc, u32 block_status) -{ - u32 status, result; - - if (block_status & SBE_2T3E3_FRAMER_VAL_RX_INTERRUPT_STATUS) { - status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_INTERRUPT_STATUS); - - if (status) { - dev_dbg(&sc->pdev->dev, - "Framer interrupt T3 RX (REG[0x13] = %02X)\n", - status); - - result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_CONFIGURATION_STATUS); - - cpld_LOS_update(sc); - - if (status & SBE_2T3E3_FRAMER_VAL_T3_RX_OOF_INTERRUPT_STATUS) { - sc->s.OOF = result & SBE_2T3E3_FRAMER_VAL_T3_RX_OOF ? 1 : 0; - dev_dbg(&sc->pdev->dev, - "Framer interrupt T3: OOF (%d)\n", - sc->s.OOF); - } - - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_T3_RX_INTERRUPT_ENABLE, - SBE_2T3E3_FRAMER_VAL_T3_RX_LOS_INTERRUPT_ENABLE | - SBE_2T3E3_FRAMER_VAL_T3_RX_OOF_INTERRUPT_ENABLE); - } - - status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_FEAC_INTERRUPT_ENABLE_STATUS); - if (status) { - dev_dbg(&sc->pdev->dev, - "Framer interrupt T3 RX (REG[0x17] = %02X)\n", - status); - } - - status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_LAPD_CONTROL); - if (status) - dev_dbg(&sc->pdev->dev, - "Framer interrupt T3 RX (REG[0x18] = %02X)\n", - status); - } - - - if (block_status & SBE_2T3E3_FRAMER_VAL_TX_INTERRUPT_STATUS) { - status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_TX_FEAC_CONFIGURATION_STATUS); - dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Framer interrupt T3 TX (REG[0x31] = %02X)\n", - status); - - status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_TX_LAPD_STATUS); - dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Framer interrupt T3 TX (REG[0x34] = %02X)\n", - status); - } -} - - -void exar7250_E3_intr(struct channel *sc, u32 block_status) -{ - u32 status, result; - - if (block_status & SBE_2T3E3_FRAMER_VAL_RX_INTERRUPT_STATUS) { - status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_STATUS_1); - - if (status) { - dev_dbg(&sc->pdev->dev, - "Framer interrupt E3 RX (REG[0x14] = %02X)\n", - status); - - result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_CONFIGURATION_STATUS_2); - - cpld_LOS_update(sc); - - if (status & SBE_2T3E3_FRAMER_VAL_E3_RX_OOF_INTERRUPT_STATUS) { - sc->s.OOF = result & SBE_2T3E3_FRAMER_VAL_E3_RX_OOF ? 1 : 0; - dev_dbg(&sc->pdev->dev, - "Framer interrupt E3: OOF (%d)\n", - sc->s.OOF); - } - - exar7250_write(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_ENABLE_1, - SBE_2T3E3_FRAMER_VAL_E3_RX_OOF_INTERRUPT_ENABLE | - SBE_2T3E3_FRAMER_VAL_E3_RX_LOS_INTERRUPT_ENABLE - ); - } - - status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_STATUS_2); - if (status) { - dev_dbg(&sc->pdev->dev, - "Framer interrupt E3 RX (REG[0x15] = %02X)\n", - status); - - } - - } - - if (block_status & SBE_2T3E3_FRAMER_VAL_TX_INTERRUPT_STATUS) { - status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_TX_LAPD_STATUS); - dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Framer interrupt E3 TX (REG[0x34] = %02X)\n", - status); - } -} diff --git a/drivers/staging/sbe-2t3e3/io.c b/drivers/staging/sbe-2t3e3/io.c deleted file mode 100644 index c9947b165b3139..00000000000000 --- a/drivers/staging/sbe-2t3e3/io.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#include -#include "2t3e3.h" -#include "ctrl.h" - -/* All access to registers done via the 21143 on port 0 must be - * protected via the card->bootrom_lock. */ - -/* private define to be used here only - must be protected by card->bootrom_lock */ -#define cpld_write_nolock(channel, reg, val) \ - bootrom_write((channel), CPLD_MAP_REG(reg, channel), val) - -u32 cpld_read(struct channel *channel, u32 reg) -{ - unsigned long flags; - u32 val; - - spin_lock_irqsave(&channel->card->bootrom_lock, flags); - val = bootrom_read((channel), CPLD_MAP_REG(reg, channel)); - spin_unlock_irqrestore(&channel->card->bootrom_lock, flags); - return val; -} - -/**************************************** - * Access via BootROM port - ****************************************/ - -u32 bootrom_read(struct channel *channel, u32 reg) -{ - unsigned long addr = channel->card->bootrom_addr; - u32 result; - - /* select BootROM address */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_PROGRAMMING_ADDRESS, reg & 0x3FFFF); - - /* select reading from BootROM */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_READ_OPERATION | - SBE_2T3E3_21143_VAL_BOOT_ROM_SELECT); - - udelay(2); /* 20 PCI cycles */ - - /* read from BootROM */ - result = dc_read(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT) & 0xff; - - /* reset CSR9 */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, 0); - - return result; -} - -void bootrom_write(struct channel *channel, u32 reg, u32 val) -{ - unsigned long addr = channel->card->bootrom_addr; - - /* select BootROM address */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_PROGRAMMING_ADDRESS, reg & 0x3FFFF); - - /* select writting to BootROM */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_WRITE_OPERATION | - SBE_2T3E3_21143_VAL_BOOT_ROM_SELECT | - (val & 0xff)); - - udelay(2); /* 20 PCI cycles */ - - /* reset CSR9 */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, 0); -} - - -/**************************************** - * Access via Serial I/O port - ****************************************/ - -static u32 serialrom_read_bit(struct channel *channel) -{ - unsigned long addr = channel->card->bootrom_addr; - u32 bit; - - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_READ_OPERATION | - SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CLOCK | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock high */ - - bit = (dc_read(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT) & - SBE_2T3E3_21143_VAL_SERIAL_ROM_DATA_OUT) > 0 ? 1 : 0; - - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_READ_OPERATION | - SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */ - - return bit; -} - -static void serialrom_write_bit(struct channel *channel, u32 bit) -{ - unsigned long addr = channel->card->bootrom_addr; - u32 lastbit = -1; - - bit &= 1; - - if (bit != lastbit) { - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_WRITE_OPERATION | - SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT | - (bit << 2)); /* clock low */ - - lastbit = bit; - } - - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_WRITE_OPERATION | - SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CLOCK | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT | - (bit << 2)); /* clock high */ - - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_WRITE_OPERATION | - SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT | - (bit << 2)); /* clock low */ -} - -/**************************************** - * Access to SerialROM (eeprom) - ****************************************/ - -u32 t3e3_eeprom_read_word(struct channel *channel, u32 address) -{ - unsigned long addr = channel->card->bootrom_addr; - u32 i, val; - unsigned long flags; - - address &= 0x3f; - - spin_lock_irqsave(&channel->card->bootrom_lock, flags); - - /* select correct Serial Chip */ - cpld_write_nolock(channel, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, - SBE_2T3E3_CPLD_VAL_EEPROM_SELECT); - - /* select reading from Serial I/O Bus */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_READ_OPERATION | - SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */ - - /* select read operation */ - serialrom_write_bit(channel, 0); - serialrom_write_bit(channel, 1); - serialrom_write_bit(channel, 1); - serialrom_write_bit(channel, 0); - - for (i = 0x20; i; i >>= 1) - serialrom_write_bit(channel, address & i ? 1 : 0); - - val = 0; - for (i = 0x8000; i; i >>= 1) - val |= (serialrom_read_bit(channel) ? i : 0); - - /* Reset 21143's CSR9 */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_READ_OPERATION | - SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, 0); - - /* Unselect Serial Chip */ - cpld_write_nolock(channel, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, 0); - - spin_unlock_irqrestore(&channel->card->bootrom_lock, flags); - - return ntohs(val); -} - - -/**************************************** - * Access to Framer - ****************************************/ - -u32 exar7250_read(struct channel *channel, u32 reg) -{ - u32 result; - unsigned long flags; - - spin_lock_irqsave(&channel->card->bootrom_lock, flags); - - result = bootrom_read(channel, cpld_reg_map[SBE_2T3E3_CPLD_REG_FRAMER_BASE_ADDRESS] - [channel->h.slot] + (t3e3_framer_reg_map[reg] << 2)); - - spin_unlock_irqrestore(&channel->card->bootrom_lock, flags); - - return result; -} - -void exar7250_write(struct channel *channel, u32 reg, u32 val) -{ - unsigned long flags; - - val &= 0xff; - channel->framer_regs[reg] = val; - - spin_lock_irqsave(&channel->card->bootrom_lock, flags); - - bootrom_write(channel, cpld_reg_map[SBE_2T3E3_CPLD_REG_FRAMER_BASE_ADDRESS] - [channel->h.slot] + (t3e3_framer_reg_map[reg] << 2), val); - - spin_unlock_irqrestore(&channel->card->bootrom_lock, flags); -} - - -/**************************************** - * Access to LIU - ****************************************/ - -u32 exar7300_read(struct channel *channel, u32 reg) -{ - unsigned long addr = channel->card->bootrom_addr, flags; - u32 i, val; - - /* select correct Serial Chip */ - - spin_lock_irqsave(&channel->card->bootrom_lock, flags); - - cpld_write_nolock(channel, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, - cpld_val_map[SBE_2T3E3_CPLD_VAL_LIU_SELECT][channel->h.slot]); - - /* select reading from Serial I/O Bus */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_READ_OPERATION | - SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */ - - /* select read operation */ - serialrom_write_bit(channel, 1); - - /* Exar7300 register address is 4 bit long */ - reg = t3e3_liu_reg_map[reg]; - for (i = 0; i < 4; i++, reg >>= 1) /* 4 bits of SerialROM address */ - serialrom_write_bit(channel, reg & 1); - for (i = 0; i < 3; i++) /* remaining 3 bits of SerialROM address */ - serialrom_write_bit(channel, 0); - - val = 0; /* Exar7300 register value is 5 bit long */ - for (i = 0; i < 8; i++) /* 8 bits of SerialROM value */ - val += (serialrom_read_bit(channel) << i); - - /* Reset 21143's CSR9 */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_READ_OPERATION | - SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, 0); - - /* Unselect Serial Chip */ - cpld_write_nolock(channel, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, 0); - - spin_unlock_irqrestore(&channel->card->bootrom_lock, flags); - - return val; -} - -void exar7300_write(struct channel *channel, u32 reg, u32 val) -{ - unsigned long addr = channel->card->bootrom_addr, flags; - u32 i; - - channel->liu_regs[reg] = val; - - /* select correct Serial Chip */ - - spin_lock_irqsave(&channel->card->bootrom_lock, flags); - - cpld_write_nolock(channel, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, - cpld_val_map[SBE_2T3E3_CPLD_VAL_LIU_SELECT][channel->h.slot]); - - /* select writting to Serial I/O Bus */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_WRITE_OPERATION | - SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */ - - /* select write operation */ - serialrom_write_bit(channel, 0); - - /* Exar7300 register address is 4 bit long */ - reg = t3e3_liu_reg_map[reg]; - for (i = 0; i < 4; i++) { /* 4 bits */ - serialrom_write_bit(channel, reg & 1); - reg >>= 1; - } - for (i = 0; i < 3; i++) /* remaining 3 bits of SerialROM address */ - serialrom_write_bit(channel, 0); - - /* Exar7300 register value is 5 bit long */ - for (i = 0; i < 5; i++) { - serialrom_write_bit(channel, val & 1); - val >>= 1; - } - for (i = 0; i < 3; i++) /* remaining 3 bits of SerialROM value */ - serialrom_write_bit(channel, 0); - - /* Reset 21143_CSR9 */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, - SBE_2T3E3_21143_VAL_WRITE_OPERATION | - SBE_2T3E3_21143_VAL_SERIAL_ROM_SELECT | - SBE_2T3E3_21143_VAL_SERIAL_ROM_CHIP_SELECT); /* clock low */ - dc_write(addr, SBE_2T3E3_21143_REG_BOOT_ROM_SERIAL_ROM_AND_MII_MANAGEMENT, 0); - - /* Unselect Serial Chip */ - cpld_write_nolock(channel, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, 0); - - spin_unlock_irqrestore(&channel->card->bootrom_lock, flags); -} diff --git a/drivers/staging/sbe-2t3e3/main.c b/drivers/staging/sbe-2t3e3/main.c deleted file mode 100644 index c8e039860dc425..00000000000000 --- a/drivers/staging/sbe-2t3e3/main.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#include -#include -#include "2t3e3.h" - -void t3e3_init(struct channel *sc) -{ - cpld_init(sc); - dc_reset(sc); - dc_init(sc); - exar7250_init(sc); - exar7300_init(sc); -} - -int t3e3_if_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct channel *sc = dev_to_priv(dev); - u32 current_write, last_write; - unsigned long flags; - struct sk_buff *skb2; - - if (skb == NULL) { - sc->s.out_errors++; - return 0; - } - - if (sc->p.transmitter_on != SBE_2T3E3_ON) { - sc->s.out_errors++; - sc->s.out_dropped++; - dev_kfree_skb_any(skb); - return 0; - } - - if (sc->s.OOF && sc->p.loopback == SBE_2T3E3_LOOPBACK_NONE) { - sc->s.out_dropped++; - dev_kfree_skb_any(skb); - return 0; - } - - spin_lock_irqsave(&sc->ether.tx_lock, flags); - - current_write = sc->ether.tx_ring_current_write; - for (skb2 = skb; skb2 != NULL; skb2 = NULL) { - if (skb2->len) { - if ((sc->ether.tx_ring[current_write].tdes1 & - SBE_2T3E3_TX_DESC_BUFFER_1_SIZE) > 0) - break; - current_write = (current_write + 1) % SBE_2T3E3_TX_DESC_RING_SIZE; - /* - * Leave at least 1 tx desc free so that dc_intr_tx() can - * identify empty list - */ - if (current_write == sc->ether.tx_ring_current_read) - break; - } - } - if (skb2 != NULL) { - netif_stop_queue(sc->dev); - sc->ether.tx_full = 1; - dev_dbg(&sc->pdev->dev, "SBE 2T3E3: out of descriptors\n"); - spin_unlock_irqrestore(&sc->ether.tx_lock, flags); - return NETDEV_TX_BUSY; - } - - current_write = last_write = sc->ether.tx_ring_current_write; - dev_dbg(&sc->pdev->dev, "sending mbuf (current_write = %d)\n", - current_write); - - for (skb2 = skb; skb2 != NULL; skb2 = NULL) { - if (skb2->len) { - dev_dbg(&sc->pdev->dev, - "sending mbuf (len = %d, next = %p)\n", - skb2->len, NULL); - - sc->ether.tx_free_cnt--; - sc->ether.tx_ring[current_write].tdes0 = 0; - sc->ether.tx_ring[current_write].tdes1 &= - SBE_2T3E3_TX_DESC_END_OF_RING | - SBE_2T3E3_TX_DESC_SECOND_ADDRESS_CHAINED; -/* DISABLE_PADDING sometimes gets lost somehow, hands off... */ - sc->ether.tx_ring[current_write].tdes1 |= - SBE_2T3E3_TX_DESC_DISABLE_PADDING | skb2->len; - - if (current_write == sc->ether.tx_ring_current_write) { - sc->ether.tx_ring[current_write].tdes1 |= - SBE_2T3E3_TX_DESC_FIRST_SEGMENT; - } else { - sc->ether.tx_ring[current_write].tdes0 = - SBE_2T3E3_TX_DESC_21143_OWN; - } - - sc->ether.tx_ring[current_write].tdes2 = virt_to_phys(skb2->data); - sc->ether.tx_data[current_write] = NULL; - - last_write = current_write; - current_write = (current_write + 1) % SBE_2T3E3_TX_DESC_RING_SIZE; - } - } - - sc->ether.tx_data[last_write] = skb; - sc->ether.tx_ring[last_write].tdes1 |= - SBE_2T3E3_TX_DESC_LAST_SEGMENT | - SBE_2T3E3_TX_DESC_INTERRUPT_ON_COMPLETION; - sc->ether.tx_ring[sc->ether.tx_ring_current_write].tdes0 |= - SBE_2T3E3_TX_DESC_21143_OWN; - sc->ether.tx_ring_current_write = current_write; - - dev_dbg(&sc->pdev->dev, "txput: tdes0 = %08X tdes1 = %08X\n", - sc->ether.tx_ring[last_write].tdes0, - sc->ether.tx_ring[last_write].tdes1); - - dc_write(sc->addr, SBE_2T3E3_21143_REG_TRANSMIT_POLL_DEMAND, - 0xffffffff); - - spin_unlock_irqrestore(&sc->ether.tx_lock, flags); - return 0; -} - - -void t3e3_read_card_serial_number(struct channel *sc) -{ - u32 i; - - for (i = 0; i < 3; i++) - sc->ether.card_serial_number[i] = t3e3_eeprom_read_word(sc, 10 + i); - - netdev_info(sc->dev, "SBE wanPMC-2T3E3 serial number: %04X%04X%04X\n", - sc->ether.card_serial_number[0], - sc->ether.card_serial_number[1], - sc->ether.card_serial_number[2]); -} - -/* - bit 0 led1 (green) - bit 1 led1 (yellow) - - bit 2 led2 (green) - bit 3 led2 (yellow) - - bit 4 led3 (green) - bit 5 led3 (yellow) - - bit 6 led4 (green) - bit 7 led4 (yellow) -*/ - -void update_led(struct channel *sc, int blinker) -{ - int leds; - if (sc->s.LOS) - leds = 0; /* led1 = off */ - else if (sc->s.OOF) - leds = 2; /* led1 = yellow */ - else if ((blinker & 1) && sc->rcv_count) { - leds = 0; /* led1 = off */ - sc->rcv_count = 0; - } else - leds = 1; /* led1 = green */ - cpld_write(sc, SBE_2T3E3_CPLD_REG_LEDR, leds); - sc->leds = leds; -} diff --git a/drivers/staging/sbe-2t3e3/maps.c b/drivers/staging/sbe-2t3e3/maps.c deleted file mode 100644 index e5494502cde168..00000000000000 --- a/drivers/staging/sbe-2t3e3/maps.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#include -#include "2t3e3.h" - -const u32 cpld_reg_map[][2] = { - { 0x0000, 0x0080 }, /* 0 - Port Control Register A (PCRA) */ - { 0x0004, 0x0084 }, /* 1 - Port Control Register B (PCRB) */ - { 0x0008, 0x0088 }, /* 2 - LCV Count Register (PLCR) */ - { 0x000c, 0x008c }, /* 3 - LCV Threshold register (PLTR) */ - { 0x0010, 0x0090 }, /* 4 - Payload Fill Register (PPFR) */ - { 0x0200, 0x0200 }, /* 5 - Board ID / FPGA Programming Status Register */ - { 0x0204, 0x0204 }, /* 6 - FPGA Version Register */ - { 0x0800, 0x1000 }, /* 7 - Framer Registers Base Address */ - { 0x2000, 0x2000 }, /* 8 - Serial Chip Select Register */ - { 0x2004, 0x2004 }, /* 9 - Static Reset Register */ - { 0x2008, 0x2008 }, /* 10 - Pulse Reset Register */ - { 0x200c, 0x200c }, /* 11 - FPGA Reconfiguration Register */ - { 0x2010, 0x2014 }, /* 12 - LED Register (LEDR) */ - { 0x2018, 0x201c }, /* 13 - LIU Control and Status Register (PISCR) */ - { 0x2020, 0x2024 }, /* 14 - Interrupt Enable Register (PIER) */ - { 0x0068, 0x00e8 }, /* 15 - Port Control Register C (PCRC) */ - { 0x006c, 0x00ec }, /* 16 - Port Bandwidth Start (PBWF) */ - { 0x0070, 0x00f0 }, /* 17 - Port Bandwidth Stop (PBWL) */ -}; - -const u32 cpld_val_map[][2] = { - { 0x01, 0x02 }, /* LIU1 / LIU2 select for Serial Chip Select */ - { 0x04, 0x08 }, /* DAC1 / DAC2 select for Serial Chip Select */ - { 0x00, 0x04 }, /* LOOP1 / LOOP2 - select of loop timing source */ - { 0x01, 0x02 } /* PORT1 / PORT2 - select LIU and Framer for reset */ -}; - -const u32 t3e3_framer_reg_map[] = { - 0x00, /* 0 - OPERATING_MODE */ - 0x01, /* 1 - IO_CONTROL */ - 0x04, /* 2 - BLOCK_INTERRUPT_ENABLE */ - 0x05, /* 3 - BLOCK_INTERRUPT_STATUS */ - 0x10, /* 4 - T3_RX_CONFIGURATION_STATUS, E3_RX_CONFIGURATION_STATUS_1 */ - 0x11, /* 5 - T3_RX_STATUS, E3_RX_CONFIGURATION_STATUS_2 */ - 0x12, /* 6 - T3_RX_INTERRUPT_ENABLE, E3_RX_INTERRUPT_ENABLE_1 */ - 0x13, /* 7 - T3_RX_INTERRUPT_STATUS, E3_RX_INTERRUPT_ENABLE_2 */ - 0x14, /* 8 - T3_RX_SYNC_DETECT_ENABLE, E3_RX_INTERRUPT_STATUS_1 */ - 0x15, /* 9 - E3_RX_INTERRUPT_STATUS_2 */ - 0x16, /* 10 - T3_RX_FEAC */ - 0x17, /* 11 - T3_RX_FEAC_INTERRUPT_ENABLE_STATUS */ - 0x18, /* 12 - T3_RX_LAPD_CONTROL, E3_RX_LAPD_CONTROL */ - 0x19, /* 13 - T3_RX_LAPD_STATUS, E3_RX_LAPD_STATUS */ - 0x1a, /* 14 - E3_RX_NR_BYTE, E3_RX_SERVICE_BITS */ - 0x1b, /* 15 - E3_RX_GC_BYTE */ - 0x30, /* 16 - T3_TX_CONFIGURATION, E3_TX_CONFIGURATION */ - 0x31, /* 17 - T3_TX_FEAC_CONFIGURATION_STATUS */ - 0x32, /* 18 - T3_TX_FEAC */ - 0x33, /* 19 - T3_TX_LAPD_CONFIGURATION, E3_TX_LAPD_CONFIGURATION */ - 0x34, /* 20 - T3_TX_LAPD_STATUS, E3_TX_LAPD_STATUS_INTERRUPT */ - 0x35, /* 21 - T3_TX_MBIT_MASK, E3_TX_GC_BYTE, E3_TX_SERVICE_BITS */ - 0x36, /* 22 - T3_TX_FBIT_MASK, E3_TX_MA_BYTE */ - 0x37, /* 23 - T3_TX_FBIT_MASK_2, E3_TX_NR_BYTE */ - 0x38, /* 24 - T3_TX_FBIT_MASK_3 */ - 0x48, /* 25 - E3_TX_FA1_ERROR_MASK, E3_TX_FAS_ERROR_MASK_UPPER */ - 0x49, /* 26 - E3_TX_FA2_ERROR_MASK, E3_TX_FAS_ERROR_MASK_LOWER */ - 0x4a, /* 27 - E3_TX_BIP8_MASK, E3_TX_BIP4_MASK */ - 0x50, /* 28 - PMON_LCV_EVENT_COUNT_MSB */ - 0x51, /* 29 - PMON_LCV_EVENT_COUNT_LSB */ - 0x52, /* 30 - PMON_FRAMING_BIT_ERROR_EVENT_COUNT_MSB */ - 0x53, /* 31 - PMON_FRAMING_BIT_ERROR_EVENT_COUNT_LSB */ - 0x54, /* 32 - PMON_PARITY_ERROR_EVENT_COUNT_MSB */ - 0x55, /* 33 - PMON_PARITY_ERROR_EVENT_COUNT_LSB */ - 0x56, /* 34 - PMON_FEBE_EVENT_COUNT_MSB */ - 0x57, /* 35 - PMON_FEBE_EVENT_COUNT_LSB */ - 0x58, /* 36 - PMON_CP_BIT_ERROR_EVENT_COUNT_MSB */ - 0x59, /* 37 - PMON_CP_BIT_ERROR_EVENT_COUNT_LSB */ - 0x6c, /* 38 - PMON_HOLDING_REGISTER */ - 0x6d, /* 39 - ONE_SECOND_ERROR_STATUS */ - 0x6e, /* 40 - LCV_ONE_SECOND_ACCUMULATOR_MSB */ - 0x6f, /* 41 - LCV_ONE_SECOND_ACCUMULATOR_LSB */ - 0x70, /* 42 - FRAME_PARITY_ERROR_ONE_SECOND_ACCUMULATOR_MSB */ - 0x71, /* 43 - FRAME_PARITY_ERROR_ONE_SECOND_ACCUMULATOR_LSB */ - 0x72, /* 44 - FRAME_CP_BIT_ERROR_ONE_SECOND_ACCUMULATOR_MSB */ - 0x73, /* 45 - FRAME_CP_BIT_ERROR_ONE_SECOND_ACCUMULATOR_LSB */ - 0x80, /* 46 - LINE_INTERFACE_DRIVE */ - 0x81 /* 47 - LINE_INTERFACE_SCAN */ -}; - -const u32 t3e3_liu_reg_map[] = { - 0x00, /* REG0 */ - 0x01, /* REG1 */ - 0x02, /* REG2 */ - 0x03, /* REG3 */ - 0x04 /* REG4 */ -}; diff --git a/drivers/staging/sbe-2t3e3/module.c b/drivers/staging/sbe-2t3e3/module.c deleted file mode 100644 index a6f93a43d21635..00000000000000 --- a/drivers/staging/sbe-2t3e3/module.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include "2t3e3.h" - -static void check_leds(unsigned long arg) -{ - struct card *card = (struct card *)arg; - struct channel *channel0 = &card->channels[0]; - static int blinker; - - update_led(channel0, ++blinker); - if (has_two_ports(channel0->pdev)) - update_led(&card->channels[1], blinker); - - card->timer.expires = jiffies + HZ / 10; - add_timer(&card->timer); -} - -static void t3e3_remove_channel(struct channel *channel) -{ - struct pci_dev *pdev = channel->pdev; - struct net_device *dev = channel->dev; - - /* system hangs if board asserts irq while module is unloaded */ - cpld_stop_intr(channel); - free_irq(dev->irq, dev); - dc_drop_descriptor_list(channel); - unregister_hdlc_device(dev); - free_netdev(dev); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); -} - -static int t3e3_init_channel(struct channel *channel, struct pci_dev *pdev, struct card *card) -{ - struct net_device *dev; - unsigned int val; - int err; - - err = pci_enable_device(pdev); - if (err) - return err; - - err = pci_request_regions(pdev, "SBE 2T3E3"); - if (err) - goto disable; - - dev = alloc_hdlcdev(channel); - if (!dev) { - pr_err("Out of memory\n"); - err = -ENOMEM; - goto free_regions; - } - - t3e3_sc_init(channel); - dev_to_priv(dev) = channel; - - channel->pdev = pdev; - channel->dev = dev; - channel->card = card; - channel->addr = pci_resource_start(pdev, 0); - if (pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_2T3E3_P1) - channel->h.slot = 1; - else - channel->h.slot = 0; - - err = setup_device(dev, channel); - if (err) - goto free_dev; - - pci_read_config_dword(channel->pdev, 0x40, &val); /* mask sleep mode */ - pci_write_config_dword(channel->pdev, 0x40, val & 0x3FFFFFFF); - - pci_read_config_byte(channel->pdev, PCI_CACHE_LINE_SIZE, &channel->h.cache_size); - pci_read_config_dword(channel->pdev, PCI_COMMAND, &channel->h.command); - t3e3_init(channel); - - err = request_irq(dev->irq, &t3e3_intr, IRQF_SHARED, dev->name, dev); - if (err) { - netdev_warn(channel->dev, "%s: could not get irq: %d\n", - dev->name, dev->irq); - goto unregister_dev; - } - - pci_set_drvdata(pdev, channel); - return 0; - -unregister_dev: - unregister_hdlc_device(dev); -free_dev: - free_netdev(dev); -free_regions: - pci_release_regions(pdev); -disable: - pci_disable_device(pdev); - return err; -} - -static void t3e3_remove_card(struct pci_dev *pdev) -{ - struct channel *channel0 = pci_get_drvdata(pdev); - struct card *card = channel0->card; - - del_timer_sync(&card->timer); - if (has_two_ports(channel0->pdev)) { - t3e3_remove_channel(&card->channels[1]); - pci_dev_put(card->channels[1].pdev); - } - t3e3_remove_channel(channel0); - kfree(card); -} - -static int t3e3_init_card(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - /* pdev points to channel #0 */ - struct pci_dev *pdev1 = NULL; - struct card *card; - int channels = 1, err; - - if (has_two_ports(pdev)) { - while ((pdev1 = pci_get_subsys(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, - PCI_VENDOR_ID_SBE, PCI_SUBDEVICE_ID_SBE_2T3E3_P1, - pdev1))) - if (pdev1->bus == pdev->bus && - pdev1->devfn == pdev->devfn + 8 /* next device on the same bus */) - break; /* found the second channel */ - - if (!pdev1) { - dev_err(&pdev->dev, "Can't find the second channel\n"); - return -EFAULT; - } - channels = 2; - /* holds the reference for pdev1 */ - } - - card = kzalloc(sizeof(struct card) + channels * sizeof(struct channel), - GFP_KERNEL); - if (!card) - return -ENOBUFS; - - spin_lock_init(&card->bootrom_lock); - card->bootrom_addr = pci_resource_start(pdev, 0); - - err = t3e3_init_channel(&card->channels[0], pdev, card); - if (err) - goto free_card; - - if (channels == 2) { - err = t3e3_init_channel(&card->channels[1], pdev1, card); - if (err) { - t3e3_remove_channel(&card->channels[0]); - goto free_card; - } - } - - /* start LED timer */ - init_timer(&card->timer); - card->timer.function = check_leds; - card->timer.expires = jiffies + HZ / 10; - card->timer.data = (unsigned long)card; - add_timer(&card->timer); - return 0; - -free_card: - kfree(card); - return err; -} - -static struct pci_device_id t3e3_pci_tbl[] = { - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, - PCI_VENDOR_ID_SBE, PCI_SUBDEVICE_ID_SBE_T3E3, 0, 0, 0 }, - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, - PCI_VENDOR_ID_SBE, PCI_SUBDEVICE_ID_SBE_2T3E3_P0, 0, 0, 0 }, - /* channel 1 will be initialized after channel 0 */ - { 0, } -}; - -static struct pci_driver t3e3_pci_driver = { - .name = "SBE T3E3", - .id_table = t3e3_pci_tbl, - .probe = t3e3_init_card, - .remove = t3e3_remove_card, -}; - -module_pci_driver(t3e3_pci_driver); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, t3e3_pci_tbl); diff --git a/drivers/staging/sbe-2t3e3/netdev.c b/drivers/staging/sbe-2t3e3/netdev.c deleted file mode 100644 index fe6c9513c9cd72..00000000000000 --- a/drivers/staging/sbe-2t3e3/netdev.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * SBE 2T3E3 synchronous serial card driver for Linux - * - * Copyright (C) 2009-2010 Krzysztof Halasa - * - * 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 code is based on a driver written by SBE Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "2t3e3.h" - -static int t3e3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct channel *sc = dev_to_priv(dev); - int cmd_2t3e3, len, rlen; - struct t3e3_param param; - struct t3e3_resp resp; - void __user *data = ifr->ifr_data + sizeof(cmd_2t3e3) + sizeof(len); - - if (cmd == SIOCWANDEV) - return hdlc_ioctl(dev, ifr, cmd); - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (cmd != SIOCDEVPRIVATE + 15) - return -EINVAL; - - if (copy_from_user(&cmd_2t3e3, ifr->ifr_data, sizeof(cmd_2t3e3))) - return -EFAULT; - if (copy_from_user(&len, ifr->ifr_data + sizeof(cmd_2t3e3), sizeof(len))) - return -EFAULT; - - if (len > sizeof(param)) - return -EFAULT; - - if (len) - if (copy_from_user(¶m, data, len)) - return -EFAULT; - - t3e3_if_config(sc, cmd_2t3e3, (char *)¶m, &resp, &rlen); - - if (rlen) - if (copy_to_user(data, &resp, rlen)) - return -EFAULT; - - return 0; -} - -static struct net_device_stats *t3e3_get_stats(struct net_device *dev) -{ - struct net_device_stats *nstats = &dev->stats; - struct channel *sc = dev_to_priv(dev); - struct t3e3_stats *stats = &sc->s; - - memset(nstats, 0, sizeof(struct net_device_stats)); - nstats->rx_packets = stats->in_packets; - nstats->tx_packets = stats->out_packets; - nstats->rx_bytes = stats->in_bytes; - nstats->tx_bytes = stats->out_bytes; - - nstats->rx_errors = stats->in_errors; - nstats->tx_errors = stats->out_errors; - nstats->rx_crc_errors = stats->in_error_crc; - - - nstats->rx_dropped = stats->in_dropped; - nstats->tx_dropped = stats->out_dropped; - nstats->tx_carrier_errors = stats->out_error_lost_carr + - stats->out_error_no_carr; - - return nstats; -} - -static int t3e3_open(struct net_device *dev) -{ - struct channel *sc = dev_to_priv(dev); - int ret = hdlc_open(dev); - - if (ret) - return ret; - - sc->r.flags |= SBE_2T3E3_FLAG_NETWORK_UP; - dc_start(dev_to_priv(dev)); - netif_start_queue(dev); - try_module_get(THIS_MODULE); - return 0; -} - -static int t3e3_close(struct net_device *dev) -{ - struct channel *sc = dev_to_priv(dev); - hdlc_close(dev); - netif_stop_queue(dev); - dc_stop(sc); - sc->r.flags &= ~SBE_2T3E3_FLAG_NETWORK_UP; - module_put(THIS_MODULE); - return 0; -} - -static int t3e3_attach(struct net_device *dev, unsigned short foo1, - unsigned short foo2) -{ - return 0; -} - -static const struct net_device_ops t3e3_ops = { - .ndo_open = t3e3_open, - .ndo_stop = t3e3_close, - .ndo_change_mtu = hdlc_change_mtu, - .ndo_start_xmit = hdlc_start_xmit, - .ndo_do_ioctl = t3e3_ioctl, - .ndo_get_stats = t3e3_get_stats, -}; - -int setup_device(struct net_device *dev, struct channel *sc) -{ - hdlc_device *hdlc = dev_to_hdlc(dev); - int retval; - - dev->base_addr = pci_resource_start(sc->pdev, 0); - dev->irq = sc->pdev->irq; - dev->netdev_ops = &t3e3_ops; - dev->tx_queue_len = 100; - hdlc->xmit = t3e3_if_start_xmit; - hdlc->attach = t3e3_attach; - retval = register_hdlc_device(dev); - if (retval) { - dev_err(&sc->pdev->dev, "error registering HDLC device\n"); - return retval; - } - return 0; -} diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c index 0267dd8b84b763..998c3845421d26 100644 --- a/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/drivers/staging/serqt_usb2/serqt_usb2.c @@ -990,18 +990,10 @@ static void qt_block_until_empty(struct tty_struct *tty, static void qt_close(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - struct quatech_port *qt_port; - struct quatech_port *port0; - struct tty_struct *tty; - int status; - unsigned int index; - status = 0; - - tty = tty_port_tty_get(&port->port); - index = port->port_number; - - qt_port = qt_get_port_private(port); - port0 = qt_get_port_private(serial->port[0]); + struct tty_struct *tty = tty_port_tty_get(&port->port); + unsigned int index = port->port_number; + struct quatech_port *qt_port = qt_get_port_private(port); + struct quatech_port *port0 = qt_get_port_private(serial->port[0]); /* shutdown any bulk reads that might be going on */ if (serial->num_bulk_out) @@ -1015,8 +1007,7 @@ static void qt_close(struct usb_serial_port *port) tty_kref_put(tty); /* Close uart channel */ - status = qt_close_channel(serial, index); - if (status < 0) + if (qt_close_channel(serial, index) < 0) dev_dbg(&port->dev, "%s - qt_close_channel failed.\n", __func__); @@ -1268,9 +1259,9 @@ static void qt_set_termios(struct tty_struct *tty, if (I_IXOFF(tty) || I_IXON(tty)) { unsigned char stop_char = STOP_CHAR(tty); unsigned char start_char = START_CHAR(tty); - status = - box_set_sw_flow_ctrl(port->serial, index, stop_char, - start_char); + + status = box_set_sw_flow_ctrl(port->serial, index, stop_char, + start_char); if (status < 0) dev_dbg(&port->dev, "box_set_sw_flow_ctrl (enabled) failed\n"); diff --git a/drivers/staging/silicom/bpctl_mod.c b/drivers/staging/silicom/bpctl_mod.c index 6b9365b28e8ac3..7f3d884d4ddd41 100644 --- a/drivers/staging/silicom/bpctl_mod.c +++ b/drivers/staging/silicom/bpctl_mod.c @@ -119,7 +119,6 @@ static void if_scan_init(void); static int bypass_proc_create_dev_sd(struct bpctl_dev *pbp_device_block); static int bypass_proc_remove_dev_sd(struct bpctl_dev *pbp_device_block); -static int bp_proc_create(void); static int is_bypass_fn(struct bpctl_dev *pbpctl_dev); static int get_dev_idx_bsf(int bus, int slot, int func); @@ -220,8 +219,12 @@ static int bp_device_event(struct notifier_block *unused, if (netif_carrier_ok(dev)) return NOTIFY_DONE; - if (((dev_num = get_dev_idx(dev->ifindex)) == -1) || - (!(pbpctl_dev = &bpctl_dev_arr[dev_num]))) + dev_num = get_dev_idx(dev->ifindex); + if (dev_num == -1) + return NOTIFY_DONE; + + pbpctl_dev = &bpctl_dev_arr[dev_num]; + if (!pbpctl_dev) return NOTIFY_DONE; if ((is_bypass_fn(pbpctl_dev)) == 1) @@ -6399,25 +6402,6 @@ static int __init bypass_init_module(void) } register_netdevice_notifier(&bp_notifier_block); -#ifdef BP_PROC_SUPPORT - { - int i = 0; - /* unsigned long flags; */ - /* rcu_read_lock(); */ - bp_proc_create(); - for (i = 0; i < device_num; i++) { - if (bpctl_dev_arr[i].ifindex) { - /* spin_lock_irqsave(&bpvm_lock, flags); */ - bypass_proc_remove_dev_sd(&bpctl_dev_arr[i]); - bypass_proc_create_dev_sd(&bpctl_dev_arr[i]); - /* spin_unlock_irqrestore(&bpvm_lock, flags); */ - } - - } - /* rcu_read_unlock(); */ - } -#endif - return 0; } @@ -6431,13 +6415,6 @@ static void __exit bypass_cleanup_module(void) for (i = 0; i < device_num; i++) { /* unsigned long flags; */ -#ifdef BP_PROC_SUPPORT -/* spin_lock_irqsave(&bpvm_lock, flags); - rcu_read_lock(); */ - bypass_proc_remove_dev_sd(&bpctl_dev_arr[i]); -/* spin_unlock_irqrestore(&bpvm_lock, flags); - rcu_read_unlock(); */ -#endif remove_bypass_wd_auto(&bpctl_dev_arr[i]); bpctl_dev_arr[i].reset_time = 0; @@ -6783,18 +6760,6 @@ EXPORT_SYMBOL(bp_if_scan_sd); static struct proc_dir_entry *bp_procfs_dir; -static int bp_proc_create(void) -{ - bp_procfs_dir = proc_mkdir(BP_PROC_DIR, init_net.proc_net); - if (bp_procfs_dir == (struct proc_dir_entry *)0) { - printk(KERN_DEBUG - "Could not create procfs nicinfo directory %s\n", - BP_PROC_DIR); - return -1; - } - return 0; -} - static int procfs_add(char *proc_name, const struct file_operations *fops, struct bpctl_dev *dev) { diff --git a/drivers/staging/silicom/bypasslib/bypass.c b/drivers/staging/silicom/bypasslib/bypass.c index 09e00dac04f3a8..a58251f5a8f8f5 100644 --- a/drivers/staging/silicom/bypasslib/bypass.c +++ b/drivers/staging/silicom/bypasslib/bypass.c @@ -149,38 +149,33 @@ static int is_bypass_dev(int if_index) while ((pdev = pci_get_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) { dev = pci_get_drvdata(pdev); - if (dev != NULL) { - dev = pci_get_drvdata(pdev); - if ((dev != NULL) && (dev->ifindex == if_index)) { - if ((pdev->vendor == SILICOM_VID) && - (pdev->device >= SILICOM_BP_PID_MIN) && - (pdev->device <= SILICOM_BP_PID_MAX)) { - goto send_cmd; - } + if ((dev != NULL) && (dev->ifindex == if_index)) { + if ((pdev->vendor == SILICOM_VID) && + (pdev->device >= SILICOM_BP_PID_MIN) && + (pdev->device <= SILICOM_BP_PID_MAX)) { + goto send_cmd; + } #if defined(BP_VENDOR_SUPPORT) && defined(ETHTOOL_GDRVINFO) - else { - struct ethtool_drvinfo info; - const struct ethtool_ops *ops = - dev->ethtool_ops; - int k = 0; - - if (ops->get_drvinfo) { - memset(&info, 0, sizeof(info)); - info.cmd = ETHTOOL_GDRVINFO; - ops->get_drvinfo(dev, &info); - for (; bp_desc_array[k]; k++) - if (! - (strcmp - (bp_desc_array[k], - info.driver))) - goto send_cmd; - - } + else { + struct ethtool_drvinfo info; + const struct ethtool_ops *ops = + dev->ethtool_ops; + int k = 0; + + if (ops->get_drvinfo) { + memset(&info, 0, sizeof(info)); + info.cmd = ETHTOOL_GDRVINFO; + ops->get_drvinfo(dev, &info); + for (; bp_desc_array[k]; k++) + if (!(strcmp(bp_desc_array[k], + info.driver))) + goto send_cmd; } -#endif - return -1; + } +#endif + return -1; } } send_cmd: diff --git a/drivers/staging/skein/Kconfig b/drivers/staging/skein/Kconfig new file mode 100644 index 00000000000000..8f5a72a90ced41 --- /dev/null +++ b/drivers/staging/skein/Kconfig @@ -0,0 +1,32 @@ +config CRYPTO_SKEIN + bool "Skein digest algorithm" + depends on (X86 || UML_X86) && 64BIT + select CRYPTO_THREEFISH + select CRYPTO_HASH + help + Skein secure hash algorithm is one of 5 finalists from the NIST SHA3 + competition. + + Skein is optimized for modern, 64bit processors and is highly + customizable. See: + + http://www.skein-hash.info/sites/default/files/skein1.3.pdf + + for more information. This module depends on the threefish block + cipher module. + +config CRYPTO_THREEFISH + bool "Threefish tweakable block cipher" + depends on (X86 || UML_X86) && 64BIT + select CRYPTO_ALGAPI + help + Threefish cipher algorithm is the tweakable block cipher underneath + the Skein family of secure hash algorithms. Skein is one of 5 + finalists from the NIST SHA3 competition. + + Skein is optimized for modern, 64bit processors and is highly + customizable. See: + + http://www.skein-hash.info/sites/default/files/skein1.3.pdf + + for more information. diff --git a/drivers/staging/skein/Makefile b/drivers/staging/skein/Makefile new file mode 100644 index 00000000000000..2bb386e1e58cab --- /dev/null +++ b/drivers/staging/skein/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for the skein secure hash algorithm +# +subdir-ccflags-y := -I$(src)/include/ + +obj-$(CONFIG_CRYPTO_SKEIN) += skein.o \ + skeinApi.o \ + skein_block.o + +obj-$(CONFIG_CRYPTO_THREEFISH) += threefish1024Block.o \ + threefish256Block.o \ + threefish512Block.o \ + threefishApi.o diff --git a/drivers/staging/skein/TODO b/drivers/staging/skein/TODO new file mode 100644 index 00000000000000..f5c167a305aede --- /dev/null +++ b/drivers/staging/skein/TODO @@ -0,0 +1,11 @@ +skein/threefish TODO + + - rename camelcase vars + - rename camelcase functions + - rename files + - move macros into appropriate header files + - add / pass test vectors + - module support + +Please send patches to Jason Cooper in addition to the +staging tree mailinglist. diff --git a/drivers/staging/skein/include/skein.h b/drivers/staging/skein/include/skein.h new file mode 100644 index 00000000000000..0a2abcecd2f762 --- /dev/null +++ b/drivers/staging/skein/include/skein.h @@ -0,0 +1,344 @@ +#ifndef _SKEIN_H_ +#define _SKEIN_H_ 1 +/************************************************************************** +** +** Interface declarations and internal definitions for Skein hashing. +** +** Source code author: Doug Whiting, 2008. +** +** This algorithm and source code is released to the public domain. +** +*************************************************************************** +** +** The following compile-time switches may be defined to control some +** tradeoffs between speed, code size, error checking, and security. +** +** The "default" note explains what happens when the switch is not defined. +** +** SKEIN_DEBUG -- make callouts from inside Skein code +** to examine/display intermediate values. +** [default: no callouts (no overhead)] +** +** SKEIN_ERR_CHECK -- how error checking is handled inside Skein +** code. If not defined, most error checking +** is disabled (for performance). Otherwise, +** the switch value is interpreted as: +** 0: use assert() to flag errors +** 1: return SKEIN_FAIL to flag errors +** +***************************************************************************/ + +#ifndef RotL_64 +#define RotL_64(x, N) (((x) << (N)) | ((x) >> (64-(N)))) +#endif + +/* below two prototype assume we are handed aligned data */ +#define Skein_Put64_LSB_First(dst08, src64, bCnt) memcpy(dst08, src64, bCnt) +#define Skein_Get64_LSB_First(dst64, src08, wCnt) memcpy(dst64, src08, 8*(wCnt)) +#define Skein_Swap64(w64) (w64) + +enum { + SKEIN_SUCCESS = 0, /* return codes from Skein calls */ + SKEIN_FAIL = 1, + SKEIN_BAD_HASHLEN = 2 +}; + +#define SKEIN_MODIFIER_WORDS (2) /* number of modifier (tweak) words */ + +#define SKEIN_256_STATE_WORDS (4) +#define SKEIN_512_STATE_WORDS (8) +#define SKEIN1024_STATE_WORDS (16) +#define SKEIN_MAX_STATE_WORDS (16) + +#define SKEIN_256_STATE_BYTES (8*SKEIN_256_STATE_WORDS) +#define SKEIN_512_STATE_BYTES (8*SKEIN_512_STATE_WORDS) +#define SKEIN1024_STATE_BYTES (8*SKEIN1024_STATE_WORDS) + +#define SKEIN_256_STATE_BITS (64*SKEIN_256_STATE_WORDS) +#define SKEIN_512_STATE_BITS (64*SKEIN_512_STATE_WORDS) +#define SKEIN1024_STATE_BITS (64*SKEIN1024_STATE_WORDS) + +#define SKEIN_256_BLOCK_BYTES (8*SKEIN_256_STATE_WORDS) +#define SKEIN_512_BLOCK_BYTES (8*SKEIN_512_STATE_WORDS) +#define SKEIN1024_BLOCK_BYTES (8*SKEIN1024_STATE_WORDS) + +struct skein_ctx_hdr { + size_t hashBitLen; /* size of hash result, in bits */ + size_t bCnt; /* current byte count in buffer b[] */ + u64 T[SKEIN_MODIFIER_WORDS]; /* tweak: T[0]=byte cnt, T[1]=flags */ +}; + +struct skein_256_ctx { /* 256-bit Skein hash context structure */ + struct skein_ctx_hdr h; /* common header context variables */ + u64 X[SKEIN_256_STATE_WORDS]; /* chaining variables */ + u8 b[SKEIN_256_BLOCK_BYTES]; /* partial block buf (8-byte aligned) */ +}; + +struct skein_512_ctx { /* 512-bit Skein hash context structure */ + struct skein_ctx_hdr h; /* common header context variables */ + u64 X[SKEIN_512_STATE_WORDS]; /* chaining variables */ + u8 b[SKEIN_512_BLOCK_BYTES]; /* partial block buf (8-byte aligned) */ +}; + +struct skein1024_ctx { /* 1024-bit Skein hash context structure */ + struct skein_ctx_hdr h; /* common header context variables */ + u64 X[SKEIN1024_STATE_WORDS]; /* chaining variables */ + u8 b[SKEIN1024_BLOCK_BYTES]; /* partial block buf (8-byte aligned) */ +}; + +/* Skein APIs for (incremental) "straight hashing" */ +int Skein_256_Init(struct skein_256_ctx *ctx, size_t hashBitLen); +int Skein_512_Init(struct skein_512_ctx *ctx, size_t hashBitLen); +int Skein1024_Init(struct skein1024_ctx *ctx, size_t hashBitLen); + +int Skein_256_Update(struct skein_256_ctx *ctx, const u8 *msg, + size_t msgByteCnt); +int Skein_512_Update(struct skein_512_ctx *ctx, const u8 *msg, + size_t msgByteCnt); +int Skein1024_Update(struct skein1024_ctx *ctx, const u8 *msg, + size_t msgByteCnt); + +int Skein_256_Final(struct skein_256_ctx *ctx, u8 *hashVal); +int Skein_512_Final(struct skein_512_ctx *ctx, u8 *hashVal); +int Skein1024_Final(struct skein1024_ctx *ctx, u8 *hashVal); + +/* +** Skein APIs for "extended" initialization: MAC keys, tree hashing. +** After an InitExt() call, just use Update/Final calls as with Init(). +** +** Notes: Same parameters as _Init() calls, plus treeInfo/key/keyBytes. +** When keyBytes == 0 and treeInfo == SKEIN_SEQUENTIAL, +** the results of InitExt() are identical to calling Init(). +** The function Init() may be called once to "precompute" the IV for +** a given hashBitLen value, then by saving a copy of the context +** the IV computation may be avoided in later calls. +** Similarly, the function InitExt() may be called once per MAC key +** to precompute the MAC IV, then a copy of the context saved and +** reused for each new MAC computation. +**/ +int Skein_256_InitExt(struct skein_256_ctx *ctx, size_t hashBitLen, + u64 treeInfo, const u8 *key, size_t keyBytes); +int Skein_512_InitExt(struct skein_512_ctx *ctx, size_t hashBitLen, + u64 treeInfo, const u8 *key, size_t keyBytes); +int Skein1024_InitExt(struct skein1024_ctx *ctx, size_t hashBitLen, + u64 treeInfo, const u8 *key, size_t keyBytes); + +/* +** Skein APIs for MAC and tree hash: +** Final_Pad: pad, do final block, but no OUTPUT type +** Output: do just the output stage +*/ +int Skein_256_Final_Pad(struct skein_256_ctx *ctx, u8 *hashVal); +int Skein_512_Final_Pad(struct skein_512_ctx *ctx, u8 *hashVal); +int Skein1024_Final_Pad(struct skein1024_ctx *ctx, u8 *hashVal); + +#ifndef SKEIN_TREE_HASH +#define SKEIN_TREE_HASH (1) +#endif +#if SKEIN_TREE_HASH +int Skein_256_Output(struct skein_256_ctx *ctx, u8 *hashVal); +int Skein_512_Output(struct skein_512_ctx *ctx, u8 *hashVal); +int Skein1024_Output(struct skein1024_ctx *ctx, u8 *hashVal); +#endif + +/***************************************************************** +** "Internal" Skein definitions +** -- not needed for sequential hashing API, but will be +** helpful for other uses of Skein (e.g., tree hash mode). +** -- included here so that they can be shared between +** reference and optimized code. +******************************************************************/ + +/* tweak word T[1]: bit field starting positions */ +#define SKEIN_T1_BIT(BIT) ((BIT) - 64) /* second word */ + +#define SKEIN_T1_POS_TREE_LVL SKEIN_T1_BIT(112) /* 112..118 hash tree level */ +#define SKEIN_T1_POS_BIT_PAD SKEIN_T1_BIT(119) /* 119 part. final in byte */ +#define SKEIN_T1_POS_BLK_TYPE SKEIN_T1_BIT(120) /* 120..125 type field `*/ +#define SKEIN_T1_POS_FIRST SKEIN_T1_BIT(126) /* 126 first blk flag */ +#define SKEIN_T1_POS_FINAL SKEIN_T1_BIT(127) /* 127 final blk flag */ + +/* tweak word T[1]: flag bit definition(s) */ +#define SKEIN_T1_FLAG_FIRST (((u64) 1) << SKEIN_T1_POS_FIRST) +#define SKEIN_T1_FLAG_FINAL (((u64) 1) << SKEIN_T1_POS_FINAL) +#define SKEIN_T1_FLAG_BIT_PAD (((u64) 1) << SKEIN_T1_POS_BIT_PAD) + +/* tweak word T[1]: tree level bit field mask */ +#define SKEIN_T1_TREE_LVL_MASK (((u64)0x7F) << SKEIN_T1_POS_TREE_LVL) +#define SKEIN_T1_TREE_LEVEL(n) (((u64) (n)) << SKEIN_T1_POS_TREE_LVL) + +/* tweak word T[1]: block type field */ +#define SKEIN_BLK_TYPE_KEY (0) /* key, for MAC and KDF */ +#define SKEIN_BLK_TYPE_CFG (4) /* configuration block */ +#define SKEIN_BLK_TYPE_PERS (8) /* personalization string */ +#define SKEIN_BLK_TYPE_PK (12) /* pubkey (for digital sigs) */ +#define SKEIN_BLK_TYPE_KDF (16) /* key identifier for KDF */ +#define SKEIN_BLK_TYPE_NONCE (20) /* nonce for PRNG */ +#define SKEIN_BLK_TYPE_MSG (48) /* message processing */ +#define SKEIN_BLK_TYPE_OUT (63) /* output stage */ +#define SKEIN_BLK_TYPE_MASK (63) /* bit field mask */ + +#define SKEIN_T1_BLK_TYPE(T) (((u64) (SKEIN_BLK_TYPE_##T)) << \ + SKEIN_T1_POS_BLK_TYPE) +#define SKEIN_T1_BLK_TYPE_KEY SKEIN_T1_BLK_TYPE(KEY) /* for MAC and KDF */ +#define SKEIN_T1_BLK_TYPE_CFG SKEIN_T1_BLK_TYPE(CFG) /* config block */ +#define SKEIN_T1_BLK_TYPE_PERS SKEIN_T1_BLK_TYPE(PERS) /* personalization */ +#define SKEIN_T1_BLK_TYPE_PK SKEIN_T1_BLK_TYPE(PK) /* pubkey (for sigs) */ +#define SKEIN_T1_BLK_TYPE_KDF SKEIN_T1_BLK_TYPE(KDF) /* key ident for KDF */ +#define SKEIN_T1_BLK_TYPE_NONCE SKEIN_T1_BLK_TYPE(NONCE)/* nonce for PRNG */ +#define SKEIN_T1_BLK_TYPE_MSG SKEIN_T1_BLK_TYPE(MSG) /* message processing */ +#define SKEIN_T1_BLK_TYPE_OUT SKEIN_T1_BLK_TYPE(OUT) /* output stage */ +#define SKEIN_T1_BLK_TYPE_MASK SKEIN_T1_BLK_TYPE(MASK) /* field bit mask */ + +#define SKEIN_T1_BLK_TYPE_CFG_FINAL (SKEIN_T1_BLK_TYPE_CFG | \ + SKEIN_T1_FLAG_FINAL) +#define SKEIN_T1_BLK_TYPE_OUT_FINAL (SKEIN_T1_BLK_TYPE_OUT | \ + SKEIN_T1_FLAG_FINAL) + +#define SKEIN_VERSION (1) + +#ifndef SKEIN_ID_STRING_LE /* allow compile-time personalization */ +#define SKEIN_ID_STRING_LE (0x33414853) /* "SHA3" (little-endian)*/ +#endif + +#define SKEIN_MK_64(hi32, lo32) ((lo32) + (((u64) (hi32)) << 32)) +#define SKEIN_SCHEMA_VER SKEIN_MK_64(SKEIN_VERSION, SKEIN_ID_STRING_LE) +#define SKEIN_KS_PARITY SKEIN_MK_64(0x1BD11BDA, 0xA9FC1A22) + +#define SKEIN_CFG_STR_LEN (4*8) + +/* bit field definitions in config block treeInfo word */ +#define SKEIN_CFG_TREE_LEAF_SIZE_POS (0) +#define SKEIN_CFG_TREE_NODE_SIZE_POS (8) +#define SKEIN_CFG_TREE_MAX_LEVEL_POS (16) + +#define SKEIN_CFG_TREE_LEAF_SIZE_MSK (((u64)0xFF) << \ + SKEIN_CFG_TREE_LEAF_SIZE_POS) +#define SKEIN_CFG_TREE_NODE_SIZE_MSK (((u64)0xFF) << \ + SKEIN_CFG_TREE_NODE_SIZE_POS) +#define SKEIN_CFG_TREE_MAX_LEVEL_MSK (((u64)0xFF) << \ + SKEIN_CFG_TREE_MAX_LEVEL_POS) + +#define SKEIN_CFG_TREE_INFO(leaf, node, maxLvl) \ + ((((u64)(leaf)) << SKEIN_CFG_TREE_LEAF_SIZE_POS) | \ + (((u64)(node)) << SKEIN_CFG_TREE_NODE_SIZE_POS) | \ + (((u64)(maxLvl)) << SKEIN_CFG_TREE_MAX_LEVEL_POS)) + +/* use as treeInfo in InitExt() call for sequential processing */ +#define SKEIN_CFG_TREE_INFO_SEQUENTIAL SKEIN_CFG_TREE_INFO(0, 0, 0) + +/* +** Skein macros for getting/setting tweak words, etc. +** These are useful for partial input bytes, hash tree init/update, etc. +**/ +#define Skein_Get_Tweak(ctxPtr, TWK_NUM) ((ctxPtr)->h.T[TWK_NUM]) +#define Skein_Set_Tweak(ctxPtr, TWK_NUM, tVal) { \ + (ctxPtr)->h.T[TWK_NUM] = (tVal); \ + } + +#define Skein_Get_T0(ctxPtr) Skein_Get_Tweak(ctxPtr, 0) +#define Skein_Get_T1(ctxPtr) Skein_Get_Tweak(ctxPtr, 1) +#define Skein_Set_T0(ctxPtr, T0) Skein_Set_Tweak(ctxPtr, 0, T0) +#define Skein_Set_T1(ctxPtr, T1) Skein_Set_Tweak(ctxPtr, 1, T1) + +/* set both tweak words at once */ +#define Skein_Set_T0_T1(ctxPtr, T0, T1) \ + { \ + Skein_Set_T0(ctxPtr, (T0)); \ + Skein_Set_T1(ctxPtr, (T1)); \ + } + +#define Skein_Set_Type(ctxPtr, BLK_TYPE) \ + Skein_Set_T1(ctxPtr, SKEIN_T1_BLK_TYPE_##BLK_TYPE) + +/* + * setup for starting with a new type: + * h.T[0]=0; h.T[1] = NEW_TYPE; h.bCnt=0; + */ +#define Skein_Start_New_Type(ctxPtr, BLK_TYPE) { \ + Skein_Set_T0_T1(ctxPtr, 0, SKEIN_T1_FLAG_FIRST | \ + SKEIN_T1_BLK_TYPE_##BLK_TYPE); \ + (ctxPtr)->h.bCnt = 0; \ + } + +#define Skein_Clear_First_Flag(hdr) { \ + (hdr).T[1] &= ~SKEIN_T1_FLAG_FIRST; \ + } +#define Skein_Set_Bit_Pad_Flag(hdr) { \ + (hdr).T[1] |= SKEIN_T1_FLAG_BIT_PAD; \ + } + +#define Skein_Set_Tree_Level(hdr, height) { \ + (hdr).T[1] |= SKEIN_T1_TREE_LEVEL(height); \ + } + +/***************************************************************** +** "Internal" Skein definitions for debugging and error checking +******************************************************************/ +#ifdef SKEIN_DEBUG /* examine/display intermediate values? */ +#include "skein_debug.h" +#else /* default is no callouts */ +#define Skein_Show_Block(bits, ctx, X, blkPtr, wPtr, ksEvenPtr, ksOddPtr) +#define Skein_Show_Round(bits, ctx, r, X) +#define Skein_Show_R_Ptr(bits, ctx, r, X_ptr) +#define Skein_Show_Final(bits, ctx, cnt, outPtr) +#define Skein_Show_Key(bits, ctx, key, keyBytes) +#endif + +#define Skein_Assert(x, retCode)/* ignore all Asserts, for performance */ +#define Skein_assert(x) + +/***************************************************************** +** Skein block function constants (shared across Ref and Opt code) +******************************************************************/ +enum { + /* Skein_256 round rotation constants */ + R_256_0_0 = 14, R_256_0_1 = 16, + R_256_1_0 = 52, R_256_1_1 = 57, + R_256_2_0 = 23, R_256_2_1 = 40, + R_256_3_0 = 5, R_256_3_1 = 37, + R_256_4_0 = 25, R_256_4_1 = 33, + R_256_5_0 = 46, R_256_5_1 = 12, + R_256_6_0 = 58, R_256_6_1 = 22, + R_256_7_0 = 32, R_256_7_1 = 32, + + /* Skein_512 round rotation constants */ + R_512_0_0 = 46, R_512_0_1 = 36, R_512_0_2 = 19, R_512_0_3 = 37, + R_512_1_0 = 33, R_512_1_1 = 27, R_512_1_2 = 14, R_512_1_3 = 42, + R_512_2_0 = 17, R_512_2_1 = 49, R_512_2_2 = 36, R_512_2_3 = 39, + R_512_3_0 = 44, R_512_3_1 = 9, R_512_3_2 = 54, R_512_3_3 = 56, + R_512_4_0 = 39, R_512_4_1 = 30, R_512_4_2 = 34, R_512_4_3 = 24, + R_512_5_0 = 13, R_512_5_1 = 50, R_512_5_2 = 10, R_512_5_3 = 17, + R_512_6_0 = 25, R_512_6_1 = 29, R_512_6_2 = 39, R_512_6_3 = 43, + R_512_7_0 = 8, R_512_7_1 = 35, R_512_7_2 = 56, R_512_7_3 = 22, + + /* Skein1024 round rotation constants */ + R1024_0_0 = 24, R1024_0_1 = 13, R1024_0_2 = 8, R1024_0_3 = 47, + R1024_0_4 = 8, R1024_0_5 = 17, R1024_0_6 = 22, R1024_0_7 = 37, + R1024_1_0 = 38, R1024_1_1 = 19, R1024_1_2 = 10, R1024_1_3 = 55, + R1024_1_4 = 49, R1024_1_5 = 18, R1024_1_6 = 23, R1024_1_7 = 52, + R1024_2_0 = 33, R1024_2_1 = 4, R1024_2_2 = 51, R1024_2_3 = 13, + R1024_2_4 = 34, R1024_2_5 = 41, R1024_2_6 = 59, R1024_2_7 = 17, + R1024_3_0 = 5, R1024_3_1 = 20, R1024_3_2 = 48, R1024_3_3 = 41, + R1024_3_4 = 47, R1024_3_5 = 28, R1024_3_6 = 16, R1024_3_7 = 25, + R1024_4_0 = 41, R1024_4_1 = 9, R1024_4_2 = 37, R1024_4_3 = 31, + R1024_4_4 = 12, R1024_4_5 = 47, R1024_4_6 = 44, R1024_4_7 = 30, + R1024_5_0 = 16, R1024_5_1 = 34, R1024_5_2 = 56, R1024_5_3 = 51, + R1024_5_4 = 4, R1024_5_5 = 53, R1024_5_6 = 42, R1024_5_7 = 41, + R1024_6_0 = 31, R1024_6_1 = 44, R1024_6_2 = 47, R1024_6_3 = 46, + R1024_6_4 = 19, R1024_6_5 = 42, R1024_6_6 = 44, R1024_6_7 = 25, + R1024_7_0 = 9, R1024_7_1 = 48, R1024_7_2 = 35, R1024_7_3 = 52, + R1024_7_4 = 23, R1024_7_5 = 31, R1024_7_6 = 37, R1024_7_7 = 20 +}; + +#ifndef SKEIN_ROUNDS +#define SKEIN_256_ROUNDS_TOTAL (72) /* # rounds for diff block sizes */ +#define SKEIN_512_ROUNDS_TOTAL (72) +#define SKEIN1024_ROUNDS_TOTAL (80) +#else /* allow command-line define in range 8*(5..14) */ +#define SKEIN_256_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/100) + 5) % 10) + 5)) +#define SKEIN_512_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/10) + 5) % 10) + 5)) +#define SKEIN1024_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS) + 5) % 10) + 5)) +#endif + +#endif /* ifndef _SKEIN_H_ */ diff --git a/drivers/staging/skein/include/skeinApi.h b/drivers/staging/skein/include/skeinApi.h new file mode 100644 index 00000000000000..ace931a67c2323 --- /dev/null +++ b/drivers/staging/skein/include/skeinApi.h @@ -0,0 +1,230 @@ +/* +Copyright (c) 2010 Werner Dittmann + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#ifndef SKEINAPI_H +#define SKEINAPI_H + +/** + * @file skeinApi.h + * @brief A Skein API and its functions. + * @{ + * + * This API and the functions that implement this API simplify the usage + * of Skein. The design and the way to use the functions follow the openSSL + * design but at the same time take care of some Skein specific behaviour + * and possibilities. + * + * The functions enable applications to create a normal Skein hashes and + * message authentication codes (MAC). + * + * Using these functions is simple and straight forward: + * + * @code + * + * #include + * + * ... + * struct skein_ctx ctx; // a Skein hash or MAC context + * + * // prepare context, here for a Skein with a state size of 512 bits. + * skeinCtxPrepare(&ctx, Skein512); + * + * // Initialize the context to set the requested hash length in bits + * // here request a output hash size of 31 bits (Skein supports variable + * // output sizes even very strange sizes) + * skeinInit(&ctx, 31); + * + * // Now update Skein with any number of message bits. A function that + * // takes a number of bytes is also available. + * skeinUpdateBits(&ctx, message, msgLength); + * + * // Now get the result of the Skein hash. The output buffer must be + * // large enough to hold the request number of output bits. The application + * // may now extract the bits. + * skeinFinal(&ctx, result); + * ... + * @endcode + * + * An application may use @c skeinReset to reset a Skein context and use + * it for creation of another hash with the same Skein state size and output + * bit length. In this case the API implementation restores some internal + * internal state data and saves a full Skein initialization round. + * + * To create a MAC the application just uses @c skeinMacInit instead of + * @c skeinInit. All other functions calls remain the same. + * + */ + +#include +#include + +/** + * Which Skein size to use + */ +enum skein_size { + Skein256 = 256, /*!< Skein with 256 bit state */ + Skein512 = 512, /*!< Skein with 512 bit state */ + Skein1024 = 1024 /*!< Skein with 1024 bit state */ +}; + +/** + * Context for Skein. + * + * This structure was setup with some know-how of the internal + * Skein structures, in particular ordering of header and size dependent + * variables. If Skein implementation changes this, then adapt these + * structures as well. + */ +struct skein_ctx { + u64 skeinSize; + u64 XSave[SKEIN_MAX_STATE_WORDS]; /* save area for state variables */ + union { + struct skein_ctx_hdr h; + struct skein_256_ctx s256; + struct skein_512_ctx s512; + struct skein1024_ctx s1024; + } m; +}; + +/** + * Prepare a Skein context. + * + * An application must call this function before it can use the Skein + * context. The functions clears memory and initializes size dependent + * variables. + * + * @param ctx + * Pointer to a Skein context. + * @param size + * Which Skein size to use. + * @return + * SKEIN_SUCESS of SKEIN_FAIL + */ +int skeinCtxPrepare(struct skein_ctx *ctx, enum skein_size size); + +/** + * Initialize a Skein context. + * + * Initializes the context with this data and saves the resulting Skein + * state variables for further use. + * + * @param ctx + * Pointer to a Skein context. + * @param hashBitLen + * Number of MAC hash bits to compute + * @return + * SKEIN_SUCESS of SKEIN_FAIL + * @see skeinReset + */ +int skeinInit(struct skein_ctx *ctx, size_t hashBitLen); + +/** + * Resets a Skein context for further use. + * + * Restores the saved chaining variables to reset the Skein context. + * Thus applications can reuse the same setup to process several + * messages. This saves a complete Skein initialization cycle. + * + * @param ctx + * Pointer to a pre-initialized Skein MAC context + */ +void skeinReset(struct skein_ctx *ctx); + +/** + * Initializes a Skein context for MAC usage. + * + * Initializes the context with this data and saves the resulting Skein + * state variables for further use. + * + * Applications call the normal Skein functions to update the MAC and + * get the final result. + * + * @param ctx + * Pointer to an empty or preinitialized Skein MAC context + * @param key + * Pointer to key bytes or NULL + * @param keyLen + * Length of the key in bytes or zero + * @param hashBitLen + * Number of MAC hash bits to compute + * @return + * SKEIN_SUCESS of SKEIN_FAIL + */ +int skeinMacInit(struct skein_ctx *ctx, const u8 *key, size_t keyLen, + size_t hashBitLen); + +/** + * Update Skein with the next part of the message. + * + * @param ctx + * Pointer to initialized Skein context + * @param msg + * Pointer to the message. + * @param msgByteCnt + * Length of the message in @b bytes + * @return + * Success or error code. + */ +int skeinUpdate(struct skein_ctx *ctx, const u8 *msg, + size_t msgByteCnt); + +/** + * Update the hash with a message bit string. + * + * Skein can handle data not only as bytes but also as bit strings of + * arbitrary length (up to its maximum design size). + * + * @param ctx + * Pointer to initialized Skein context + * @param msg + * Pointer to the message. + * @param msgBitCnt + * Length of the message in @b bits. + */ +int skeinUpdateBits(struct skein_ctx *ctx, const u8 *msg, + size_t msgBitCnt); + +/** + * Finalize Skein and return the hash. + * + * Before an application can reuse a Skein setup the application must + * reset the Skein context. + * + * @param ctx + * Pointer to initialized Skein context + * @param hash + * Pointer to buffer that receives the hash. The buffer must be large + * enough to store @c hashBitLen bits. + * @return + * Success or error code. + * @see skeinReset + */ +int skeinFinal(struct skein_ctx *ctx, u8 *hash); + +/** + * @} + */ +#endif diff --git a/drivers/staging/skein/include/skein_block.h b/drivers/staging/skein/include/skein_block.h new file mode 100644 index 00000000000000..b15c079b5bd4bd --- /dev/null +++ b/drivers/staging/skein/include/skein_block.h @@ -0,0 +1,22 @@ +/*********************************************************************** +** +** Implementation of the Skein hash function. +** +** Source code author: Doug Whiting, 2008. +** +** This algorithm and source code is released to the public domain. +** +************************************************************************/ +#ifndef _SKEIN_BLOCK_H_ +#define _SKEIN_BLOCK_H_ + +#include /* get the Skein API definitions */ + +void Skein_256_Process_Block(struct skein_256_ctx *ctx, const u8 *blkPtr, + size_t blkCnt, size_t byteCntAdd); +void Skein_512_Process_Block(struct skein_512_ctx *ctx, const u8 *blkPtr, + size_t blkCnt, size_t byteCntAdd); +void Skein1024_Process_Block(struct skein1024_ctx *ctx, const u8 *blkPtr, + size_t blkCnt, size_t byteCntAdd); + +#endif diff --git a/drivers/staging/skein/include/skein_iv.h b/drivers/staging/skein/include/skein_iv.h new file mode 100644 index 00000000000000..8dd5e4d88a1d40 --- /dev/null +++ b/drivers/staging/skein/include/skein_iv.h @@ -0,0 +1,186 @@ +#ifndef _SKEIN_IV_H_ +#define _SKEIN_IV_H_ + +#include /* get Skein macros and types */ + +/* +***************** Pre-computed Skein IVs ******************* +** +** NOTE: these values are not "magic" constants, but +** are generated using the Threefish block function. +** They are pre-computed here only for speed; i.e., to +** avoid the need for a Threefish call during Init(). +** +** The IV for any fixed hash length may be pre-computed. +** Only the most common values are included here. +** +************************************************************ +**/ + +#define MK_64 SKEIN_MK_64 + +/* blkSize = 256 bits. hashSize = 128 bits */ +const u64 SKEIN_256_IV_128[] = { + MK_64(0xE1111906, 0x964D7260), + MK_64(0x883DAAA7, 0x7C8D811C), + MK_64(0x10080DF4, 0x91960F7A), + MK_64(0xCCF7DDE5, 0xB45BC1C2) +}; + +/* blkSize = 256 bits. hashSize = 160 bits */ +const u64 SKEIN_256_IV_160[] = { + MK_64(0x14202314, 0x72825E98), + MK_64(0x2AC4E9A2, 0x5A77E590), + MK_64(0xD47A5856, 0x8838D63E), + MK_64(0x2DD2E496, 0x8586AB7D) +}; + +/* blkSize = 256 bits. hashSize = 224 bits */ +const u64 SKEIN_256_IV_224[] = { + MK_64(0xC6098A8C, 0x9AE5EA0B), + MK_64(0x876D5686, 0x08C5191C), + MK_64(0x99CB88D7, 0xD7F53884), + MK_64(0x384BDDB1, 0xAEDDB5DE) +}; + +/* blkSize = 256 bits. hashSize = 256 bits */ +const u64 SKEIN_256_IV_256[] = { + MK_64(0xFC9DA860, 0xD048B449), + MK_64(0x2FCA6647, 0x9FA7D833), + MK_64(0xB33BC389, 0x6656840F), + MK_64(0x6A54E920, 0xFDE8DA69) +}; + +/* blkSize = 512 bits. hashSize = 128 bits */ +const u64 SKEIN_512_IV_128[] = { + MK_64(0xA8BC7BF3, 0x6FBF9F52), + MK_64(0x1E9872CE, 0xBD1AF0AA), + MK_64(0x309B1790, 0xB32190D3), + MK_64(0xBCFBB854, 0x3F94805C), + MK_64(0x0DA61BCD, 0x6E31B11B), + MK_64(0x1A18EBEA, 0xD46A32E3), + MK_64(0xA2CC5B18, 0xCE84AA82), + MK_64(0x6982AB28, 0x9D46982D) +}; + +/* blkSize = 512 bits. hashSize = 160 bits */ +const u64 SKEIN_512_IV_160[] = { + MK_64(0x28B81A2A, 0xE013BD91), + MK_64(0xC2F11668, 0xB5BDF78F), + MK_64(0x1760D8F3, 0xF6A56F12), + MK_64(0x4FB74758, 0x8239904F), + MK_64(0x21EDE07F, 0x7EAF5056), + MK_64(0xD908922E, 0x63ED70B8), + MK_64(0xB8EC76FF, 0xECCB52FA), + MK_64(0x01A47BB8, 0xA3F27A6E) +}; + +/* blkSize = 512 bits. hashSize = 224 bits */ +const u64 SKEIN_512_IV_224[] = { + MK_64(0xCCD06162, 0x48677224), + MK_64(0xCBA65CF3, 0xA92339EF), + MK_64(0x8CCD69D6, 0x52FF4B64), + MK_64(0x398AED7B, 0x3AB890B4), + MK_64(0x0F59D1B1, 0x457D2BD0), + MK_64(0x6776FE65, 0x75D4EB3D), + MK_64(0x99FBC70E, 0x997413E9), + MK_64(0x9E2CFCCF, 0xE1C41EF7) +}; + +/* blkSize = 512 bits. hashSize = 256 bits */ +const u64 SKEIN_512_IV_256[] = { + MK_64(0xCCD044A1, 0x2FDB3E13), + MK_64(0xE8359030, 0x1A79A9EB), + MK_64(0x55AEA061, 0x4F816E6F), + MK_64(0x2A2767A4, 0xAE9B94DB), + MK_64(0xEC06025E, 0x74DD7683), + MK_64(0xE7A436CD, 0xC4746251), + MK_64(0xC36FBAF9, 0x393AD185), + MK_64(0x3EEDBA18, 0x33EDFC13) +}; + +/* blkSize = 512 bits. hashSize = 384 bits */ +const u64 SKEIN_512_IV_384[] = { + MK_64(0xA3F6C6BF, 0x3A75EF5F), + MK_64(0xB0FEF9CC, 0xFD84FAA4), + MK_64(0x9D77DD66, 0x3D770CFE), + MK_64(0xD798CBF3, 0xB468FDDA), + MK_64(0x1BC4A666, 0x8A0E4465), + MK_64(0x7ED7D434, 0xE5807407), + MK_64(0x548FC1AC, 0xD4EC44D6), + MK_64(0x266E1754, 0x6AA18FF8) +}; + +/* blkSize = 512 bits. hashSize = 512 bits */ +const u64 SKEIN_512_IV_512[] = { + MK_64(0x4903ADFF, 0x749C51CE), + MK_64(0x0D95DE39, 0x9746DF03), + MK_64(0x8FD19341, 0x27C79BCE), + MK_64(0x9A255629, 0xFF352CB1), + MK_64(0x5DB62599, 0xDF6CA7B0), + MK_64(0xEABE394C, 0xA9D5C3F4), + MK_64(0x991112C7, 0x1A75B523), + MK_64(0xAE18A40B, 0x660FCC33) +}; + +/* blkSize = 1024 bits. hashSize = 384 bits */ +const u64 SKEIN1024_IV_384[] = { + MK_64(0x5102B6B8, 0xC1894A35), + MK_64(0xFEEBC9E3, 0xFE8AF11A), + MK_64(0x0C807F06, 0xE32BED71), + MK_64(0x60C13A52, 0xB41A91F6), + MK_64(0x9716D35D, 0xD4917C38), + MK_64(0xE780DF12, 0x6FD31D3A), + MK_64(0x797846B6, 0xC898303A), + MK_64(0xB172C2A8, 0xB3572A3B), + MK_64(0xC9BC8203, 0xA6104A6C), + MK_64(0x65909338, 0xD75624F4), + MK_64(0x94BCC568, 0x4B3F81A0), + MK_64(0x3EBBF51E, 0x10ECFD46), + MK_64(0x2DF50F0B, 0xEEB08542), + MK_64(0x3B5A6530, 0x0DBC6516), + MK_64(0x484B9CD2, 0x167BBCE1), + MK_64(0x2D136947, 0xD4CBAFEA) +}; + +/* blkSize = 1024 bits. hashSize = 512 bits */ +const u64 SKEIN1024_IV_512[] = { + MK_64(0xCAEC0E5D, 0x7C1B1B18), + MK_64(0xA01B0E04, 0x5F03E802), + MK_64(0x33840451, 0xED912885), + MK_64(0x374AFB04, 0xEAEC2E1C), + MK_64(0xDF25A0E2, 0x813581F7), + MK_64(0xE4004093, 0x8B12F9D2), + MK_64(0xA662D539, 0xC2ED39B6), + MK_64(0xFA8B85CF, 0x45D8C75A), + MK_64(0x8316ED8E, 0x29EDE796), + MK_64(0x053289C0, 0x2E9F91B8), + MK_64(0xC3F8EF1D, 0x6D518B73), + MK_64(0xBDCEC3C4, 0xD5EF332E), + MK_64(0x549A7E52, 0x22974487), + MK_64(0x67070872, 0x5B749816), + MK_64(0xB9CD28FB, 0xF0581BD1), + MK_64(0x0E2940B8, 0x15804974) +}; + +/* blkSize = 1024 bits. hashSize = 1024 bits */ +const u64 SKEIN1024_IV_1024[] = { + MK_64(0xD593DA07, 0x41E72355), + MK_64(0x15B5E511, 0xAC73E00C), + MK_64(0x5180E5AE, 0xBAF2C4F0), + MK_64(0x03BD41D3, 0xFCBCAFAF), + MK_64(0x1CAEC6FD, 0x1983A898), + MK_64(0x6E510B8B, 0xCDD0589F), + MK_64(0x77E2BDFD, 0xC6394ADA), + MK_64(0xC11E1DB5, 0x24DCB0A3), + MK_64(0xD6D14AF9, 0xC6329AB5), + MK_64(0x6A9B0BFC, 0x6EB67E0D), + MK_64(0x9243C60D, 0xCCFF1332), + MK_64(0x1A1F1DDE, 0x743F02D4), + MK_64(0x0996753C, 0x10ED0BB8), + MK_64(0x6572DD22, 0xF2B4969A), + MK_64(0x61FD3062, 0xD00A579A), + MK_64(0x1DE0536E, 0x8682E539) +}; + +#endif /* _SKEIN_IV_H_ */ diff --git a/drivers/staging/skein/include/threefishApi.h b/drivers/staging/skein/include/threefishApi.h new file mode 100644 index 00000000000000..e81675d7eac94b --- /dev/null +++ b/drivers/staging/skein/include/threefishApi.h @@ -0,0 +1,164 @@ + +#ifndef THREEFISHAPI_H +#define THREEFISHAPI_H + +/** + * @file threefishApi.h + * @brief A Threefish cipher API and its functions. + * @{ + * + * This API and the functions that implement this API simplify the usage + * of the Threefish cipher. The design and the way to use the functions + * follow the openSSL design but at the same time take care of some Threefish + * specific behaviour and possibilities. + * + * These are the low level functions that deal with Threefisch blocks only. + * Implementations for cipher modes such as ECB, CFB, or CBC may use these + * functions. + * +@code + // Threefish cipher context data + struct threefish_key keyCtx; + + // Initialize the context + threefishSetKey(&keyCtx, Threefish512, key, tweak); + + // Encrypt + threefishEncryptBlockBytes(&keyCtx, input, cipher); +@endcode + */ + +#include +#include + +#define KeyScheduleConst 0x1BD11BDAA9FC1A22L + +/** + * Which Threefish size to use + */ +enum threefish_size { + Threefish256 = 256, /*!< Skein with 256 bit state */ + Threefish512 = 512, /*!< Skein with 512 bit state */ + Threefish1024 = 1024 /*!< Skein with 1024 bit state */ +}; + +/** + * Context for Threefish key and tweak words. + * + * This structure was setup with some know-how of the internal + * Skein structures, in particular ordering of header and size dependent + * variables. If Skein implementation changes this, the adapt these + * structures as well. + */ +struct threefish_key { + u64 stateSize; + u64 key[SKEIN_MAX_STATE_WORDS+1]; /* max number of key words*/ + u64 tweak[3]; +}; + +/** + * Set Threefish key and tweak data. + * + * This function sets the key and tweak data for the Threefish cipher of + * the given size. The key data must have the same length (number of bits) + * as the state size + * + * @param keyCtx + * Pointer to a Threefish key structure. + * @param size + * Which Skein size to use. + * @param keyData + * Pointer to the key words (word has 64 bits). + * @param tweak + * Pointer to the two tweak words (word has 64 bits). + */ +void threefishSetKey(struct threefish_key *keyCtx, + enum threefish_size stateSize, + u64 *keyData, u64 *tweak); + +/** + * Encrypt Threefisch block (bytes). + * + * The buffer must have at least the same length (number of bits) aas the + * state size for this key. The function uses the first @c stateSize bits + * of the input buffer, encrypts them and stores the result in the output + * buffer. + * + * @param keyCtx + * Pointer to a Threefish key structure. + * @param in + * Poionter to plaintext data buffer. + * @param out + * Pointer to cipher buffer. + */ +void threefishEncryptBlockBytes(struct threefish_key *keyCtx, u8 *in, u8 *out); + +/** + * Encrypt Threefisch block (words). + * + * The buffer must have at least the same length (number of bits) aas the + * state size for this key. The function uses the first @c stateSize bits + * of the input buffer, encrypts them and stores the result in the output + * buffer. + * + * The wordsize ist set to 64 bits. + * + * @param keyCtx + * Pointer to a Threefish key structure. + * @param in + * Poionter to plaintext data buffer. + * @param out + * Pointer to cipher buffer. + */ +void threefishEncryptBlockWords(struct threefish_key *keyCtx, u64 *in, + u64 *out); + +/** + * Decrypt Threefisch block (bytes). + * + * The buffer must have at least the same length (number of bits) aas the + * state size for this key. The function uses the first @c stateSize bits + * of the input buffer, decrypts them and stores the result in the output + * buffer + * + * @param keyCtx + * Pointer to a Threefish key structure. + * @param in + * Poionter to cipher data buffer. + * @param out + * Pointer to plaintext buffer. + */ +void threefishDecryptBlockBytes(struct threefish_key *keyCtx, u8 *in, u8 *out); + +/** + * Decrypt Threefisch block (words). + * + * The buffer must have at least the same length (number of bits) aas the + * state size for this key. The function uses the first @c stateSize bits + * of the input buffer, encrypts them and stores the result in the output + * buffer. + * + * The wordsize ist set to 64 bits. + * + * @param keyCtx + * Pointer to a Threefish key structure. + * @param in + * Poionter to cipher data buffer. + * @param out + * Pointer to plaintext buffer. + */ +void threefishDecryptBlockWords(struct threefish_key *keyCtx, u64 *in, + u64 *out); + +void threefishEncrypt256(struct threefish_key *keyCtx, u64 *input, u64 *output); +void threefishEncrypt512(struct threefish_key *keyCtx, u64 *input, u64 *output); +void threefishEncrypt1024(struct threefish_key *keyCtx, u64 *input, + u64 *output); +void threefishDecrypt256(struct threefish_key *keyCtx, u64 *input, u64 *output); +void threefishDecrypt512(struct threefish_key *keyCtx, u64 *input, u64 *output); +void threefishDecrypt1024(struct threefish_key *keyCtx, u64 *input, + u64 *output); +/** + * @} + */ +#endif diff --git a/drivers/staging/skein/skein.c b/drivers/staging/skein/skein.c new file mode 100644 index 00000000000000..096b86bf9430fa --- /dev/null +++ b/drivers/staging/skein/skein.c @@ -0,0 +1,880 @@ +/*********************************************************************** +** +** Implementation of the Skein hash function. +** +** Source code author: Doug Whiting, 2008. +** +** This algorithm and source code is released to the public domain. +** +************************************************************************/ + +#define SKEIN_PORT_CODE /* instantiate any code in skein_port.h */ + +#include /* get the memcpy/memset functions */ +#include /* get the Skein API definitions */ +#include /* get precomputed IVs */ +#include + +/*****************************************************************/ +/* 256-bit Skein */ +/*****************************************************************/ + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a straight hashing operation */ +int Skein_256_Init(struct skein_256_ctx *ctx, size_t hashBitLen) +{ + union { + u8 b[SKEIN_256_STATE_BYTES]; + u64 w[SKEIN_256_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN); + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + + switch (hashBitLen) { /* use pre-computed values, where available */ + case 256: + memcpy(ctx->X, SKEIN_256_IV_256, sizeof(ctx->X)); + break; + case 224: + memcpy(ctx->X, SKEIN_256_IV_224, sizeof(ctx->X)); + break; + case 160: + memcpy(ctx->X, SKEIN_256_IV_160, sizeof(ctx->X)); + break; + case 128: + memcpy(ctx->X, SKEIN_256_IV_128, sizeof(ctx->X)); + break; + default: + /* here if there is no precomputed IV value available */ + /* + * build/process the config block, type == CONFIG (could be + * precomputed) + */ + /* set tweaks: T0=0; T1=CFG | FINAL */ + Skein_Start_New_Type(ctx, CFG_FINAL); + + /* set the schema, version */ + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); + /* hash result length in bits */ + cfg.w[1] = Skein_Swap64(hashBitLen); + cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); + /* zero pad config block */ + memset(&cfg.w[3], 0, sizeof(cfg) - 3*sizeof(cfg.w[0])); + + /* compute the initial chaining values from config block */ + /* zero the chaining variables */ + memset(ctx->X, 0, sizeof(ctx->X)); + Skein_256_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN); + break; + } + /* The chaining vars ctx->X are now initialized for hashBitLen. */ + /* Set up to process the data message portion of the hash (default) */ + Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */ + + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a MAC and/or tree hash operation */ +/* [identical to Skein_256_Init() when keyBytes == 0 && \ + * treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ +int Skein_256_InitExt(struct skein_256_ctx *ctx, size_t hashBitLen, + u64 treeInfo, const u8 *key, size_t keyBytes) +{ + union { + u8 b[SKEIN_256_STATE_BYTES]; + u64 w[SKEIN_256_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN); + Skein_Assert(keyBytes == 0 || key != NULL, SKEIN_FAIL); + + /* compute the initial chaining values ctx->X[], based on key */ + if (keyBytes == 0) { /* is there a key? */ + /* no key: use all zeroes as key for config block */ + memset(ctx->X, 0, sizeof(ctx->X)); + } else { /* here to pre-process a key */ + Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); + /* do a mini-Init right here */ + /* set output hash bit count = state size */ + ctx->h.hashBitLen = 8*sizeof(ctx->X); + /* set tweaks: T0 = 0; T1 = KEY type */ + Skein_Start_New_Type(ctx, KEY); + /* zero the initial chaining variables */ + memset(ctx->X, 0, sizeof(ctx->X)); + /* hash the key */ + Skein_256_Update(ctx, key, keyBytes); + /* put result into cfg.b[] */ + Skein_256_Final_Pad(ctx, cfg.b); + /* copy over into ctx->X[] */ + memcpy(ctx->X, cfg.b, sizeof(cfg.b)); + } + /* + * build/process the config block, type == CONFIG (could be + * precomputed for each key) + */ + /* output hash bit count */ + ctx->h.hashBitLen = hashBitLen; + Skein_Start_New_Type(ctx, CFG_FINAL); + + /* pre-pad cfg.w[] with zeroes */ + memset(&cfg.w, 0, sizeof(cfg.w)); + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); + /* hash result length in bits */ + cfg.w[1] = Skein_Swap64(hashBitLen); + /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ + cfg.w[2] = Skein_Swap64(treeInfo); + + Skein_Show_Key(256, &ctx->h, key, keyBytes); + + /* compute the initial chaining values from config block */ + Skein_256_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN); + + /* The chaining vars ctx->X are now initialized */ + /* Set up to process the data message portion of the hash (default) */ + Skein_Start_New_Type(ctx, MSG); + + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* process the input bytes */ +int Skein_256_Update(struct skein_256_ctx *ctx, const u8 *msg, + size_t msgByteCnt) +{ + size_t n; + + /* catch uninitialized context */ + Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL); + + /* process full blocks, if any */ + if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES) { + /* finish up any buffered message data */ + if (ctx->h.bCnt) { + /* # bytes free in buffer b[] */ + n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt; + if (n) { + /* check on our logic here */ + Skein_assert(n < msgByteCnt); + memcpy(&ctx->b[ctx->h.bCnt], msg, n); + msgByteCnt -= n; + msg += n; + ctx->h.bCnt += n; + } + Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES); + Skein_256_Process_Block(ctx, ctx->b, 1, + SKEIN_256_BLOCK_BYTES); + ctx->h.bCnt = 0; + } + /* + * now process any remaining full blocks, directly from input + * message data + */ + if (msgByteCnt > SKEIN_256_BLOCK_BYTES) { + /* number of full blocks to process */ + n = (msgByteCnt-1) / SKEIN_256_BLOCK_BYTES; + Skein_256_Process_Block(ctx, msg, n, + SKEIN_256_BLOCK_BYTES); + msgByteCnt -= n * SKEIN_256_BLOCK_BYTES; + msg += n * SKEIN_256_BLOCK_BYTES; + } + Skein_assert(ctx->h.bCnt == 0); + } + + /* copy any remaining source message data bytes into b[] */ + if (msgByteCnt) { + Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES); + memcpy(&ctx->b[ctx->h.bCnt], msg, msgByteCnt); + ctx->h.bCnt += msgByteCnt; + } + + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the result */ +int Skein_256_Final(struct skein_256_ctx *ctx, u8 *hashVal) +{ + size_t i, n, byteCnt; + u64 X[SKEIN_256_STATE_WORDS]; + /* catch uninitialized context */ + Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL); + + /* tag as the final block */ + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; + /* zero pad b[] if necessary */ + if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) + memset(&ctx->b[ctx->h.bCnt], 0, + SKEIN_256_BLOCK_BYTES - ctx->h.bCnt); + + /* process the final block */ + Skein_256_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt); + + /* now output the result */ + /* total number of output bytes */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; + + /* run Threefish in "counter mode" to generate output */ + /* zero out b[], so it can hold the counter */ + memset(ctx->b, 0, sizeof(ctx->b)); + /* keep a local copy of counter mode "key" */ + memcpy(X, ctx->X, sizeof(X)); + for (i = 0; i*SKEIN_256_BLOCK_BYTES < byteCnt; i++) { + /* build the counter block */ + ((u64 *)ctx->b)[0] = Skein_Swap64((u64) i); + Skein_Start_New_Type(ctx, OUT_FINAL); + /* run "counter mode" */ + Skein_256_Process_Block(ctx, ctx->b, 1, sizeof(u64)); + /* number of output bytes left to go */ + n = byteCnt - i*SKEIN_256_BLOCK_BYTES; + if (n >= SKEIN_256_BLOCK_BYTES) + n = SKEIN_256_BLOCK_BYTES; + /* "output" the ctr mode bytes */ + Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES, ctx->X, + n); + Skein_Show_Final(256, &ctx->h, n, + hashVal+i*SKEIN_256_BLOCK_BYTES); + /* restore the counter mode key for next time */ + memcpy(ctx->X, X, sizeof(X)); + } + return SKEIN_SUCCESS; +} + +/*****************************************************************/ +/* 512-bit Skein */ +/*****************************************************************/ + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a straight hashing operation */ +int Skein_512_Init(struct skein_512_ctx *ctx, size_t hashBitLen) +{ + union { + u8 b[SKEIN_512_STATE_BYTES]; + u64 w[SKEIN_512_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN); + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + + switch (hashBitLen) { /* use pre-computed values, where available */ + case 512: + memcpy(ctx->X, SKEIN_512_IV_512, sizeof(ctx->X)); + break; + case 384: + memcpy(ctx->X, SKEIN_512_IV_384, sizeof(ctx->X)); + break; + case 256: + memcpy(ctx->X, SKEIN_512_IV_256, sizeof(ctx->X)); + break; + case 224: + memcpy(ctx->X, SKEIN_512_IV_224, sizeof(ctx->X)); + break; + default: + /* here if there is no precomputed IV value available */ + /* + * build/process the config block, type == CONFIG (could be + * precomputed) + */ + /* set tweaks: T0=0; T1=CFG | FINAL */ + Skein_Start_New_Type(ctx, CFG_FINAL); + + /* set the schema, version */ + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); + /* hash result length in bits */ + cfg.w[1] = Skein_Swap64(hashBitLen); + cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); + /* zero pad config block */ + memset(&cfg.w[3], 0, sizeof(cfg) - 3*sizeof(cfg.w[0])); + + /* compute the initial chaining values from config block */ + /* zero the chaining variables */ + memset(ctx->X, 0, sizeof(ctx->X)); + Skein_512_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN); + break; + } + + /* + * The chaining vars ctx->X are now initialized for the given + * hashBitLen. + */ + /* Set up to process the data message portion of the hash (default) */ + Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */ + + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a MAC and/or tree hash operation */ +/* [identical to Skein_512_Init() when keyBytes == 0 && \ + * treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ +int Skein_512_InitExt(struct skein_512_ctx *ctx, size_t hashBitLen, + u64 treeInfo, const u8 *key, size_t keyBytes) +{ + union { + u8 b[SKEIN_512_STATE_BYTES]; + u64 w[SKEIN_512_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN); + Skein_Assert(keyBytes == 0 || key != NULL, SKEIN_FAIL); + + /* compute the initial chaining values ctx->X[], based on key */ + if (keyBytes == 0) { /* is there a key? */ + /* no key: use all zeroes as key for config block */ + memset(ctx->X, 0, sizeof(ctx->X)); + } else { /* here to pre-process a key */ + Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); + /* do a mini-Init right here */ + /* set output hash bit count = state size */ + ctx->h.hashBitLen = 8*sizeof(ctx->X); + /* set tweaks: T0 = 0; T1 = KEY type */ + Skein_Start_New_Type(ctx, KEY); + /* zero the initial chaining variables */ + memset(ctx->X, 0, sizeof(ctx->X)); + /* hash the key */ + Skein_512_Update(ctx, key, keyBytes); + /* put result into cfg.b[] */ + Skein_512_Final_Pad(ctx, cfg.b); + /* copy over into ctx->X[] */ + memcpy(ctx->X, cfg.b, sizeof(cfg.b)); + } + /* + * build/process the config block, type == CONFIG (could be + * precomputed for each key) + */ + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + Skein_Start_New_Type(ctx, CFG_FINAL); + + /* pre-pad cfg.w[] with zeroes */ + memset(&cfg.w, 0, sizeof(cfg.w)); + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); + /* hash result length in bits */ + cfg.w[1] = Skein_Swap64(hashBitLen); + /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ + cfg.w[2] = Skein_Swap64(treeInfo); + + Skein_Show_Key(512, &ctx->h, key, keyBytes); + + /* compute the initial chaining values from config block */ + Skein_512_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN); + + /* The chaining vars ctx->X are now initialized */ + /* Set up to process the data message portion of the hash (default) */ + Skein_Start_New_Type(ctx, MSG); + + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* process the input bytes */ +int Skein_512_Update(struct skein_512_ctx *ctx, const u8 *msg, + size_t msgByteCnt) +{ + size_t n; + + /* catch uninitialized context */ + Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL); + + /* process full blocks, if any */ + if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES) { + /* finish up any buffered message data */ + if (ctx->h.bCnt) { + /* # bytes free in buffer b[] */ + n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt; + if (n) { + /* check on our logic here */ + Skein_assert(n < msgByteCnt); + memcpy(&ctx->b[ctx->h.bCnt], msg, n); + msgByteCnt -= n; + msg += n; + ctx->h.bCnt += n; + } + Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES); + Skein_512_Process_Block(ctx, ctx->b, 1, + SKEIN_512_BLOCK_BYTES); + ctx->h.bCnt = 0; + } + /* + * now process any remaining full blocks, directly from input + * message data + */ + if (msgByteCnt > SKEIN_512_BLOCK_BYTES) { + /* number of full blocks to process */ + n = (msgByteCnt-1) / SKEIN_512_BLOCK_BYTES; + Skein_512_Process_Block(ctx, msg, n, + SKEIN_512_BLOCK_BYTES); + msgByteCnt -= n * SKEIN_512_BLOCK_BYTES; + msg += n * SKEIN_512_BLOCK_BYTES; + } + Skein_assert(ctx->h.bCnt == 0); + } + + /* copy any remaining source message data bytes into b[] */ + if (msgByteCnt) { + Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES); + memcpy(&ctx->b[ctx->h.bCnt], msg, msgByteCnt); + ctx->h.bCnt += msgByteCnt; + } + + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the result */ +int Skein_512_Final(struct skein_512_ctx *ctx, u8 *hashVal) +{ + size_t i, n, byteCnt; + u64 X[SKEIN_512_STATE_WORDS]; + /* catch uninitialized context */ + Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL); + + /* tag as the final block */ + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; + /* zero pad b[] if necessary */ + if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) + memset(&ctx->b[ctx->h.bCnt], 0, + SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); + + /* process the final block */ + Skein_512_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt); + + /* now output the result */ + /* total number of output bytes */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; + + /* run Threefish in "counter mode" to generate output */ + /* zero out b[], so it can hold the counter */ + memset(ctx->b, 0, sizeof(ctx->b)); + /* keep a local copy of counter mode "key" */ + memcpy(X, ctx->X, sizeof(X)); + for (i = 0; i*SKEIN_512_BLOCK_BYTES < byteCnt; i++) { + /* build the counter block */ + ((u64 *)ctx->b)[0] = Skein_Swap64((u64) i); + Skein_Start_New_Type(ctx, OUT_FINAL); + /* run "counter mode" */ + Skein_512_Process_Block(ctx, ctx->b, 1, sizeof(u64)); + /* number of output bytes left to go */ + n = byteCnt - i*SKEIN_512_BLOCK_BYTES; + if (n >= SKEIN_512_BLOCK_BYTES) + n = SKEIN_512_BLOCK_BYTES; + /* "output" the ctr mode bytes */ + Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES, ctx->X, + n); + Skein_Show_Final(512, &ctx->h, n, + hashVal+i*SKEIN_512_BLOCK_BYTES); + /* restore the counter mode key for next time */ + memcpy(ctx->X, X, sizeof(X)); + } + return SKEIN_SUCCESS; +} + +/*****************************************************************/ +/* 1024-bit Skein */ +/*****************************************************************/ + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a straight hashing operation */ +int Skein1024_Init(struct skein1024_ctx *ctx, size_t hashBitLen) +{ + union { + u8 b[SKEIN1024_STATE_BYTES]; + u64 w[SKEIN1024_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN); + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + + switch (hashBitLen) { /* use pre-computed values, where available */ + case 512: + memcpy(ctx->X, SKEIN1024_IV_512, sizeof(ctx->X)); + break; + case 384: + memcpy(ctx->X, SKEIN1024_IV_384, sizeof(ctx->X)); + break; + case 1024: + memcpy(ctx->X, SKEIN1024_IV_1024, sizeof(ctx->X)); + break; + default: + /* here if there is no precomputed IV value available */ + /* + * build/process the config block, type == CONFIG + * (could be precomputed) + */ + /* set tweaks: T0=0; T1=CFG | FINAL */ + Skein_Start_New_Type(ctx, CFG_FINAL); + + /* set the schema, version */ + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); + /* hash result length in bits */ + cfg.w[1] = Skein_Swap64(hashBitLen); + cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); + /* zero pad config block */ + memset(&cfg.w[3], 0, sizeof(cfg) - 3*sizeof(cfg.w[0])); + + /* compute the initial chaining values from config block */ + /* zero the chaining variables */ + memset(ctx->X, 0, sizeof(ctx->X)); + Skein1024_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN); + break; + } + + /* The chaining vars ctx->X are now initialized for the hashBitLen. */ + /* Set up to process the data message portion of the hash (default) */ + Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */ + + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a MAC and/or tree hash operation */ +/* [identical to Skein1024_Init() when keyBytes == 0 && \ + * treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ +int Skein1024_InitExt(struct skein1024_ctx *ctx, size_t hashBitLen, + u64 treeInfo, const u8 *key, size_t keyBytes) +{ + union { + u8 b[SKEIN1024_STATE_BYTES]; + u64 w[SKEIN1024_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN); + Skein_Assert(keyBytes == 0 || key != NULL, SKEIN_FAIL); + + /* compute the initial chaining values ctx->X[], based on key */ + if (keyBytes == 0) { /* is there a key? */ + /* no key: use all zeroes as key for config block */ + memset(ctx->X, 0, sizeof(ctx->X)); + } else { /* here to pre-process a key */ + Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); + /* do a mini-Init right here */ + /* set output hash bit count = state size */ + ctx->h.hashBitLen = 8*sizeof(ctx->X); + /* set tweaks: T0 = 0; T1 = KEY type */ + Skein_Start_New_Type(ctx, KEY); + /* zero the initial chaining variables */ + memset(ctx->X, 0, sizeof(ctx->X)); + /* hash the key */ + Skein1024_Update(ctx, key, keyBytes); + /* put result into cfg.b[] */ + Skein1024_Final_Pad(ctx, cfg.b); + /* copy over into ctx->X[] */ + memcpy(ctx->X, cfg.b, sizeof(cfg.b)); + } + /* + * build/process the config block, type == CONFIG (could be + * precomputed for each key) + */ + /* output hash bit count */ + ctx->h.hashBitLen = hashBitLen; + Skein_Start_New_Type(ctx, CFG_FINAL); + + /* pre-pad cfg.w[] with zeroes */ + memset(&cfg.w, 0, sizeof(cfg.w)); + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); + /* hash result length in bits */ + cfg.w[1] = Skein_Swap64(hashBitLen); + /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ + cfg.w[2] = Skein_Swap64(treeInfo); + + Skein_Show_Key(1024, &ctx->h, key, keyBytes); + + /* compute the initial chaining values from config block */ + Skein1024_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN); + + /* The chaining vars ctx->X are now initialized */ + /* Set up to process the data message portion of the hash (default) */ + Skein_Start_New_Type(ctx, MSG); + + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* process the input bytes */ +int Skein1024_Update(struct skein1024_ctx *ctx, const u8 *msg, + size_t msgByteCnt) +{ + size_t n; + + /* catch uninitialized context */ + Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL); + + /* process full blocks, if any */ + if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES) { + /* finish up any buffered message data */ + if (ctx->h.bCnt) { + /* # bytes free in buffer b[] */ + n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt; + if (n) { + /* check on our logic here */ + Skein_assert(n < msgByteCnt); + memcpy(&ctx->b[ctx->h.bCnt], msg, n); + msgByteCnt -= n; + msg += n; + ctx->h.bCnt += n; + } + Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES); + Skein1024_Process_Block(ctx, ctx->b, 1, + SKEIN1024_BLOCK_BYTES); + ctx->h.bCnt = 0; + } + /* + * now process any remaining full blocks, directly from input + * message data + */ + if (msgByteCnt > SKEIN1024_BLOCK_BYTES) { + /* number of full blocks to process */ + n = (msgByteCnt-1) / SKEIN1024_BLOCK_BYTES; + Skein1024_Process_Block(ctx, msg, n, + SKEIN1024_BLOCK_BYTES); + msgByteCnt -= n * SKEIN1024_BLOCK_BYTES; + msg += n * SKEIN1024_BLOCK_BYTES; + } + Skein_assert(ctx->h.bCnt == 0); + } + + /* copy any remaining source message data bytes into b[] */ + if (msgByteCnt) { + Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES); + memcpy(&ctx->b[ctx->h.bCnt], msg, msgByteCnt); + ctx->h.bCnt += msgByteCnt; + } + + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the result */ +int Skein1024_Final(struct skein1024_ctx *ctx, u8 *hashVal) +{ + size_t i, n, byteCnt; + u64 X[SKEIN1024_STATE_WORDS]; + /* catch uninitialized context */ + Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL); + + /* tag as the final block */ + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; + /* zero pad b[] if necessary */ + if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) + memset(&ctx->b[ctx->h.bCnt], 0, + SKEIN1024_BLOCK_BYTES - ctx->h.bCnt); + + /* process the final block */ + Skein1024_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt); + + /* now output the result */ + /* total number of output bytes */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; + + /* run Threefish in "counter mode" to generate output */ + /* zero out b[], so it can hold the counter */ + memset(ctx->b, 0, sizeof(ctx->b)); + /* keep a local copy of counter mode "key" */ + memcpy(X, ctx->X, sizeof(X)); + for (i = 0; i*SKEIN1024_BLOCK_BYTES < byteCnt; i++) { + /* build the counter block */ + ((u64 *)ctx->b)[0] = Skein_Swap64((u64) i); + Skein_Start_New_Type(ctx, OUT_FINAL); + /* run "counter mode" */ + Skein1024_Process_Block(ctx, ctx->b, 1, sizeof(u64)); + /* number of output bytes left to go */ + n = byteCnt - i*SKEIN1024_BLOCK_BYTES; + if (n >= SKEIN1024_BLOCK_BYTES) + n = SKEIN1024_BLOCK_BYTES; + /* "output" the ctr mode bytes */ + Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES, ctx->X, + n); + Skein_Show_Final(1024, &ctx->h, n, + hashVal+i*SKEIN1024_BLOCK_BYTES); + /* restore the counter mode key for next time */ + memcpy(ctx->X, X, sizeof(X)); + } + return SKEIN_SUCCESS; +} + +/**************** Functions to support MAC/tree hashing ***************/ +/* (this code is identical for Optimized and Reference versions) */ + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the block, no OUTPUT stage */ +int Skein_256_Final_Pad(struct skein_256_ctx *ctx, u8 *hashVal) +{ + /* catch uninitialized context */ + Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL); + + /* tag as the final block */ + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; + /* zero pad b[] if necessary */ + if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) + memset(&ctx->b[ctx->h.bCnt], 0, + SKEIN_256_BLOCK_BYTES - ctx->h.bCnt); + /* process the final block */ + Skein_256_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt); + + /* "output" the state bytes */ + Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN_256_BLOCK_BYTES); + + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the block, no OUTPUT stage */ +int Skein_512_Final_Pad(struct skein_512_ctx *ctx, u8 *hashVal) +{ + /* catch uninitialized context */ + Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL); + + /* tag as the final block */ + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; + /* zero pad b[] if necessary */ + if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) + memset(&ctx->b[ctx->h.bCnt], 0, + SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); + /* process the final block */ + Skein_512_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt); + + /* "output" the state bytes */ + Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN_512_BLOCK_BYTES); + + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the block, no OUTPUT stage */ +int Skein1024_Final_Pad(struct skein1024_ctx *ctx, u8 *hashVal) +{ + /* catch uninitialized context */ + Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL); + + /* tag as the final block */ + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; + /* zero pad b[] if necessary */ + if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) + memset(&ctx->b[ctx->h.bCnt], 0, + SKEIN1024_BLOCK_BYTES - ctx->h.bCnt); + /* process the final block */ + Skein1024_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt); + + /* "output" the state bytes */ + Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN1024_BLOCK_BYTES); + + return SKEIN_SUCCESS; +} + +#if SKEIN_TREE_HASH +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* just do the OUTPUT stage */ +int Skein_256_Output(struct skein_256_ctx *ctx, u8 *hashVal) +{ + size_t i, n, byteCnt; + u64 X[SKEIN_256_STATE_WORDS]; + /* catch uninitialized context */ + Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL); + + /* now output the result */ + /* total number of output bytes */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; + + /* run Threefish in "counter mode" to generate output */ + /* zero out b[], so it can hold the counter */ + memset(ctx->b, 0, sizeof(ctx->b)); + /* keep a local copy of counter mode "key" */ + memcpy(X, ctx->X, sizeof(X)); + for (i = 0; i*SKEIN_256_BLOCK_BYTES < byteCnt; i++) { + /* build the counter block */ + ((u64 *)ctx->b)[0] = Skein_Swap64((u64) i); + Skein_Start_New_Type(ctx, OUT_FINAL); + /* run "counter mode" */ + Skein_256_Process_Block(ctx, ctx->b, 1, sizeof(u64)); + /* number of output bytes left to go */ + n = byteCnt - i*SKEIN_256_BLOCK_BYTES; + if (n >= SKEIN_256_BLOCK_BYTES) + n = SKEIN_256_BLOCK_BYTES; + /* "output" the ctr mode bytes */ + Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES, ctx->X, + n); + Skein_Show_Final(256, &ctx->h, n, + hashVal+i*SKEIN_256_BLOCK_BYTES); + /* restore the counter mode key for next time */ + memcpy(ctx->X, X, sizeof(X)); + } + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* just do the OUTPUT stage */ +int Skein_512_Output(struct skein_512_ctx *ctx, u8 *hashVal) +{ + size_t i, n, byteCnt; + u64 X[SKEIN_512_STATE_WORDS]; + /* catch uninitialized context */ + Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL); + + /* now output the result */ + /* total number of output bytes */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; + + /* run Threefish in "counter mode" to generate output */ + /* zero out b[], so it can hold the counter */ + memset(ctx->b, 0, sizeof(ctx->b)); + /* keep a local copy of counter mode "key" */ + memcpy(X, ctx->X, sizeof(X)); + for (i = 0; i*SKEIN_512_BLOCK_BYTES < byteCnt; i++) { + /* build the counter block */ + ((u64 *)ctx->b)[0] = Skein_Swap64((u64) i); + Skein_Start_New_Type(ctx, OUT_FINAL); + /* run "counter mode" */ + Skein_512_Process_Block(ctx, ctx->b, 1, sizeof(u64)); + /* number of output bytes left to go */ + n = byteCnt - i*SKEIN_512_BLOCK_BYTES; + if (n >= SKEIN_512_BLOCK_BYTES) + n = SKEIN_512_BLOCK_BYTES; + /* "output" the ctr mode bytes */ + Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES, ctx->X, + n); + Skein_Show_Final(256, &ctx->h, n, + hashVal+i*SKEIN_512_BLOCK_BYTES); + /* restore the counter mode key for next time */ + memcpy(ctx->X, X, sizeof(X)); + } + return SKEIN_SUCCESS; +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* just do the OUTPUT stage */ +int Skein1024_Output(struct skein1024_ctx *ctx, u8 *hashVal) +{ + size_t i, n, byteCnt; + u64 X[SKEIN1024_STATE_WORDS]; + /* catch uninitialized context */ + Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL); + + /* now output the result */ + /* total number of output bytes */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; + + /* run Threefish in "counter mode" to generate output */ + /* zero out b[], so it can hold the counter */ + memset(ctx->b, 0, sizeof(ctx->b)); + /* keep a local copy of counter mode "key" */ + memcpy(X, ctx->X, sizeof(X)); + for (i = 0; i*SKEIN1024_BLOCK_BYTES < byteCnt; i++) { + /* build the counter block */ + ((u64 *)ctx->b)[0] = Skein_Swap64((u64) i); + Skein_Start_New_Type(ctx, OUT_FINAL); + /* run "counter mode" */ + Skein1024_Process_Block(ctx, ctx->b, 1, sizeof(u64)); + /* number of output bytes left to go */ + n = byteCnt - i*SKEIN1024_BLOCK_BYTES; + if (n >= SKEIN1024_BLOCK_BYTES) + n = SKEIN1024_BLOCK_BYTES; + /* "output" the ctr mode bytes */ + Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES, ctx->X, + n); + Skein_Show_Final(256, &ctx->h, n, + hashVal+i*SKEIN1024_BLOCK_BYTES); + /* restore the counter mode key for next time */ + memcpy(ctx->X, X, sizeof(X)); + } + return SKEIN_SUCCESS; +} +#endif diff --git a/drivers/staging/skein/skeinApi.c b/drivers/staging/skein/skeinApi.c new file mode 100644 index 00000000000000..dd109bf6f7b9f2 --- /dev/null +++ b/drivers/staging/skein/skeinApi.c @@ -0,0 +1,237 @@ +/* +Copyright (c) 2010 Werner Dittmann + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#include +#include + +int skeinCtxPrepare(struct skein_ctx *ctx, enum skein_size size) +{ + Skein_Assert(ctx && size, SKEIN_FAIL); + + memset(ctx , 0, sizeof(struct skein_ctx)); + ctx->skeinSize = size; + + return SKEIN_SUCCESS; +} + +int skeinInit(struct skein_ctx *ctx, size_t hashBitLen) +{ + int ret = SKEIN_FAIL; + size_t Xlen = 0; + u64 *X = NULL; + u64 treeInfo = SKEIN_CFG_TREE_INFO_SEQUENTIAL; + + Skein_Assert(ctx, SKEIN_FAIL); + /* + * The following two lines rely of the fact that the real Skein + * contexts are a union in out context and thus have tha maximum + * memory available. The beauty of C :-) . + */ + X = ctx->m.s256.X; + Xlen = ctx->skeinSize/8; + /* + * If size is the same and hash bit length is zero then reuse + * the save chaining variables. + */ + switch (ctx->skeinSize) { + case Skein256: + ret = Skein_256_InitExt(&ctx->m.s256, hashBitLen, + treeInfo, NULL, 0); + break; + case Skein512: + ret = Skein_512_InitExt(&ctx->m.s512, hashBitLen, + treeInfo, NULL, 0); + break; + case Skein1024: + ret = Skein1024_InitExt(&ctx->m.s1024, hashBitLen, + treeInfo, NULL, 0); + break; + } + + if (ret == SKEIN_SUCCESS) { + /* + * Save chaining variables for this combination of size and + * hashBitLen + */ + memcpy(ctx->XSave, X, Xlen); + } + return ret; +} + +int skeinMacInit(struct skein_ctx *ctx, const u8 *key, size_t keyLen, + size_t hashBitLen) +{ + int ret = SKEIN_FAIL; + u64 *X = NULL; + size_t Xlen = 0; + u64 treeInfo = SKEIN_CFG_TREE_INFO_SEQUENTIAL; + + Skein_Assert(ctx, SKEIN_FAIL); + + X = ctx->m.s256.X; + Xlen = ctx->skeinSize/8; + + Skein_Assert(hashBitLen, SKEIN_BAD_HASHLEN); + + switch (ctx->skeinSize) { + case Skein256: + ret = Skein_256_InitExt(&ctx->m.s256, hashBitLen, + treeInfo, + (const u8 *)key, keyLen); + + break; + case Skein512: + ret = Skein_512_InitExt(&ctx->m.s512, hashBitLen, + treeInfo, + (const u8 *)key, keyLen); + break; + case Skein1024: + ret = Skein1024_InitExt(&ctx->m.s1024, hashBitLen, + treeInfo, + (const u8 *)key, keyLen); + + break; + } + if (ret == SKEIN_SUCCESS) { + /* + * Save chaining variables for this combination of key, + * keyLen, hashBitLen + */ + memcpy(ctx->XSave, X, Xlen); + } + return ret; +} + +void skeinReset(struct skein_ctx *ctx) +{ + size_t Xlen = 0; + u64 *X = NULL; + + /* + * The following two lines rely of the fact that the real Skein + * contexts are a union in out context and thus have tha maximum + * memory available. The beautiy of C :-) . + */ + X = ctx->m.s256.X; + Xlen = ctx->skeinSize/8; + /* Restore the chaing variable, reset byte counter */ + memcpy(X, ctx->XSave, Xlen); + + /* Setup context to process the message */ + Skein_Start_New_Type(&ctx->m, MSG); +} + +int skeinUpdate(struct skein_ctx *ctx, const u8 *msg, + size_t msgByteCnt) +{ + int ret = SKEIN_FAIL; + Skein_Assert(ctx, SKEIN_FAIL); + + switch (ctx->skeinSize) { + case Skein256: + ret = Skein_256_Update(&ctx->m.s256, (const u8 *)msg, + msgByteCnt); + break; + case Skein512: + ret = Skein_512_Update(&ctx->m.s512, (const u8 *)msg, + msgByteCnt); + break; + case Skein1024: + ret = Skein1024_Update(&ctx->m.s1024, (const u8 *)msg, + msgByteCnt); + break; + } + return ret; + +} + +int skeinUpdateBits(struct skein_ctx *ctx, const u8 *msg, + size_t msgBitCnt) +{ + /* + * I've used the bit pad implementation from skein_test.c (see NIST CD) + * and modified it to use the convenience functions and added some + * pointer arithmetic. + */ + size_t length; + u8 mask; + u8 *up; + + /* + * only the final Update() call is allowed do partial bytes, else + * assert an error + */ + Skein_Assert((ctx->m.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 || + msgBitCnt == 0, SKEIN_FAIL); + + /* if number of bits is a multiple of bytes - that's easy */ + if ((msgBitCnt & 0x7) == 0) + return skeinUpdate(ctx, msg, msgBitCnt >> 3); + + skeinUpdate(ctx, msg, (msgBitCnt >> 3) + 1); + + /* + * The next line rely on the fact that the real Skein contexts + * are a union in our context. After the addition the pointer points to + * Skein's real partial block buffer. + * If this layout ever changes we have to adapt this as well. + */ + up = (u8 *)ctx->m.s256.X + ctx->skeinSize / 8; + + /* set tweak flag for the skeinFinal call */ + Skein_Set_Bit_Pad_Flag(ctx->m.h); + + /* now "pad" the final partial byte the way NIST likes */ + /* get the bCnt value (same location for all block sizes) */ + length = ctx->m.h.bCnt; + /* internal sanity check: there IS a partial byte in the buffer! */ + Skein_assert(length != 0); + /* partial byte bit mask */ + mask = (u8) (1u << (7 - (msgBitCnt & 7))); + /* apply bit padding on final byte (in the buffer) */ + up[length-1] = (u8)((up[length-1] & (0-mask))|mask); + + return SKEIN_SUCCESS; +} + +int skeinFinal(struct skein_ctx *ctx, u8 *hash) +{ + int ret = SKEIN_FAIL; + Skein_Assert(ctx, SKEIN_FAIL); + + switch (ctx->skeinSize) { + case Skein256: + ret = Skein_256_Final(&ctx->m.s256, (u8 *)hash); + break; + case Skein512: + ret = Skein_512_Final(&ctx->m.s512, (u8 *)hash); + break; + case Skein1024: + ret = Skein1024_Final(&ctx->m.s1024, (u8 *)hash); + break; + } + return ret; +} diff --git a/drivers/staging/skein/skeinBlockNo3F.c b/drivers/staging/skein/skeinBlockNo3F.c new file mode 100644 index 00000000000000..69176389fef905 --- /dev/null +++ b/drivers/staging/skein/skeinBlockNo3F.c @@ -0,0 +1,175 @@ + +#include +#include +#include + + +/***************************** Skein_256 ******************************/ +void Skein_256_Process_Block(struct skein_256_ctx *ctx, const u8 *blkPtr, + size_t blkCnt, size_t byteCntAdd) +{ + struct threefish_key key; + u64 tweak[2]; + int i; + u64 w[SKEIN_256_STATE_WORDS]; /* local copy of input block */ + u64 words[3]; + + Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ + tweak[0] = ctx->h.T[0]; + tweak[1] = ctx->h.T[1]; + + do { + u64 carry = byteCntAdd; + + words[0] = tweak[0] & 0xffffffffL; + words[1] = ((tweak[0] >> 32) & 0xffffffffL); + words[2] = (tweak[1] & 0xffffffffL); + + for (i = 0; i < 3; i++) { + carry += words[i]; + words[i] = carry; + carry >>= 32; + } + tweak[0] = words[0] & 0xffffffffL; + tweak[0] |= (words[1] & 0xffffffffL) << 32; + tweak[1] |= words[2] & 0xffffffffL; + + threefishSetKey(&key, Threefish256, ctx->X, tweak); + + /* get input block in little-endian format */ + Skein_Get64_LSB_First(w, blkPtr, SKEIN_256_STATE_WORDS); + + threefishEncryptBlockWords(&key, w, ctx->X); + + blkPtr += SKEIN_256_BLOCK_BYTES; + + /* do the final "feedforward" xor, update ctx chaining vars */ + ctx->X[0] = ctx->X[0] ^ w[0]; + ctx->X[1] = ctx->X[1] ^ w[1]; + ctx->X[2] = ctx->X[2] ^ w[2]; + ctx->X[3] = ctx->X[3] ^ w[3]; + + tweak[1] &= ~SKEIN_T1_FLAG_FIRST; + } while (--blkCnt); + + ctx->h.T[0] = tweak[0]; + ctx->h.T[1] = tweak[1]; +} + +void Skein_512_Process_Block(struct skein_512_ctx *ctx, const u8 *blkPtr, + size_t blkCnt, size_t byteCntAdd) +{ + struct threefish_key key; + u64 tweak[2]; + int i; + u64 words[3]; + u64 w[SKEIN_512_STATE_WORDS]; /* local copy of input block */ + + Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ + tweak[0] = ctx->h.T[0]; + tweak[1] = ctx->h.T[1]; + + do { + u64 carry = byteCntAdd; + + words[0] = tweak[0] & 0xffffffffL; + words[1] = ((tweak[0] >> 32) & 0xffffffffL); + words[2] = (tweak[1] & 0xffffffffL); + + for (i = 0; i < 3; i++) { + carry += words[i]; + words[i] = carry; + carry >>= 32; + } + tweak[0] = words[0] & 0xffffffffL; + tweak[0] |= (words[1] & 0xffffffffL) << 32; + tweak[1] |= words[2] & 0xffffffffL; + + threefishSetKey(&key, Threefish512, ctx->X, tweak); + + /* get input block in little-endian format */ + Skein_Get64_LSB_First(w, blkPtr, SKEIN_512_STATE_WORDS); + + threefishEncryptBlockWords(&key, w, ctx->X); + + blkPtr += SKEIN_512_BLOCK_BYTES; + + /* do the final "feedforward" xor, update ctx chaining vars */ + ctx->X[0] = ctx->X[0] ^ w[0]; + ctx->X[1] = ctx->X[1] ^ w[1]; + ctx->X[2] = ctx->X[2] ^ w[2]; + ctx->X[3] = ctx->X[3] ^ w[3]; + ctx->X[4] = ctx->X[4] ^ w[4]; + ctx->X[5] = ctx->X[5] ^ w[5]; + ctx->X[6] = ctx->X[6] ^ w[6]; + ctx->X[7] = ctx->X[7] ^ w[7]; + + tweak[1] &= ~SKEIN_T1_FLAG_FIRST; + } while (--blkCnt); + + ctx->h.T[0] = tweak[0]; + ctx->h.T[1] = tweak[1]; +} + +void Skein1024_Process_Block(struct skein1024_ctx *ctx, const u8 *blkPtr, + size_t blkCnt, size_t byteCntAdd) +{ + struct threefish_key key; + u64 tweak[2]; + int i; + u64 words[3]; + u64 w[SKEIN1024_STATE_WORDS]; /* local copy of input block */ + + Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ + tweak[0] = ctx->h.T[0]; + tweak[1] = ctx->h.T[1]; + + do { + u64 carry = byteCntAdd; + + words[0] = tweak[0] & 0xffffffffL; + words[1] = ((tweak[0] >> 32) & 0xffffffffL); + words[2] = (tweak[1] & 0xffffffffL); + + for (i = 0; i < 3; i++) { + carry += words[i]; + words[i] = carry; + carry >>= 32; + } + tweak[0] = words[0] & 0xffffffffL; + tweak[0] |= (words[1] & 0xffffffffL) << 32; + tweak[1] |= words[2] & 0xffffffffL; + + threefishSetKey(&key, Threefish1024, ctx->X, tweak); + + /* get input block in little-endian format */ + Skein_Get64_LSB_First(w, blkPtr, SKEIN1024_STATE_WORDS); + + threefishEncryptBlockWords(&key, w, ctx->X); + + blkPtr += SKEIN1024_BLOCK_BYTES; + + /* do the final "feedforward" xor, update ctx chaining vars */ + ctx->X[0] = ctx->X[0] ^ w[0]; + ctx->X[1] = ctx->X[1] ^ w[1]; + ctx->X[2] = ctx->X[2] ^ w[2]; + ctx->X[3] = ctx->X[3] ^ w[3]; + ctx->X[4] = ctx->X[4] ^ w[4]; + ctx->X[5] = ctx->X[5] ^ w[5]; + ctx->X[6] = ctx->X[6] ^ w[6]; + ctx->X[7] = ctx->X[7] ^ w[7]; + ctx->X[8] = ctx->X[8] ^ w[8]; + ctx->X[9] = ctx->X[9] ^ w[9]; + ctx->X[10] = ctx->X[10] ^ w[10]; + ctx->X[11] = ctx->X[11] ^ w[11]; + ctx->X[12] = ctx->X[12] ^ w[12]; + ctx->X[13] = ctx->X[13] ^ w[13]; + ctx->X[14] = ctx->X[14] ^ w[14]; + ctx->X[15] = ctx->X[15] ^ w[15]; + + tweak[1] &= ~SKEIN_T1_FLAG_FIRST; + } while (--blkCnt); + + ctx->h.T[0] = tweak[0]; + ctx->h.T[1] = tweak[1]; +} diff --git a/drivers/staging/skein/skein_block.c b/drivers/staging/skein/skein_block.c new file mode 100644 index 00000000000000..fd96ca0ad0edd7 --- /dev/null +++ b/drivers/staging/skein/skein_block.c @@ -0,0 +1,770 @@ +/*********************************************************************** +** +** Implementation of the Skein block functions. +** +** Source code author: Doug Whiting, 2008. +** +** This algorithm and source code is released to the public domain. +** +** Compile-time switches: +** +** SKEIN_USE_ASM -- set bits (256/512/1024) to select which +** versions use ASM code for block processing +** [default: use C for all block sizes] +** +************************************************************************/ + +#include +#include + +#ifndef SKEIN_USE_ASM +#define SKEIN_USE_ASM (0) /* default is all C code (no ASM) */ +#endif + +#ifndef SKEIN_LOOP +#define SKEIN_LOOP 001 /* default: unroll 256 and 512, but not 1024 */ +#endif + +#define BLK_BITS (WCNT*64) /* some useful definitions for code here */ +#define KW_TWK_BASE (0) +#define KW_KEY_BASE (3) +#define ks (kw + KW_KEY_BASE) +#define ts (kw + KW_TWK_BASE) + +#ifdef SKEIN_DEBUG +#define DebugSaveTweak(ctx) { ctx->h.T[0] = ts[0]; ctx->h.T[1] = ts[1]; } +#else +#define DebugSaveTweak(ctx) +#endif + +/***************************** Skein_256 ******************************/ +#if !(SKEIN_USE_ASM & 256) +void Skein_256_Process_Block(struct skein_256_ctx *ctx, const u8 *blkPtr, + size_t blkCnt, size_t byteCntAdd) + { /* do it in C */ + enum { + WCNT = SKEIN_256_STATE_WORDS + }; +#undef RCNT +#define RCNT (SKEIN_256_ROUNDS_TOTAL/8) + +#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ +#define SKEIN_UNROLL_256 (((SKEIN_LOOP)/100)%10) +#else +#define SKEIN_UNROLL_256 (0) +#endif + +#if SKEIN_UNROLL_256 +#if (RCNT % SKEIN_UNROLL_256) +#error "Invalid SKEIN_UNROLL_256" /* sanity check on unroll count */ +#endif + size_t r; + u64 kw[WCNT+4+RCNT*2]; /* key schedule: chaining vars + tweak + "rot"*/ +#else + u64 kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ +#endif + u64 X0, X1, X2, X3; /* local copy of context vars, for speed */ + u64 w[WCNT]; /* local copy of input block */ +#ifdef SKEIN_DEBUG + const u64 *Xptr[4]; /* use for debugging (help cc put Xn in regs) */ + Xptr[0] = &X0; Xptr[1] = &X1; Xptr[2] = &X2; Xptr[3] = &X3; +#endif + Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ + ts[0] = ctx->h.T[0]; + ts[1] = ctx->h.T[1]; + do { + /* + * this implementation only supports 2**64 input bytes + * (no carry out here) + */ + ts[0] += byteCntAdd; /* update processed length */ + + /* precompute the key schedule for this block */ + ks[0] = ctx->X[0]; + ks[1] = ctx->X[1]; + ks[2] = ctx->X[2]; + ks[3] = ctx->X[3]; + ks[4] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ SKEIN_KS_PARITY; + + ts[2] = ts[0] ^ ts[1]; + + /* get input block in little-endian format */ + Skein_Get64_LSB_First(w, blkPtr, WCNT); + DebugSaveTweak(ctx); + Skein_Show_Block(BLK_BITS, &ctx->h, ctx->X, blkPtr, w, ks, ts); + + X0 = w[0] + ks[0]; /* do the first full key injection */ + X1 = w[1] + ks[1] + ts[0]; + X2 = w[2] + ks[2] + ts[1]; + X3 = w[3] + ks[3]; + + /* show starting state values */ + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INITIAL, + Xptr); + + blkPtr += SKEIN_256_BLOCK_BYTES; + + /* run the rounds */ + +#define Round256(p0, p1, p2, p3, ROT, rNum) \ +do { \ + X##p0 += X##p1; X##p1 = RotL_64(X##p1, ROT##_0); X##p1 ^= X##p0; \ + X##p2 += X##p3; X##p3 = RotL_64(X##p3, ROT##_1); X##p3 ^= X##p2; \ +} while (0) + +#if SKEIN_UNROLL_256 == 0 +#define R256(p0, p1, p2, p3, ROT, rNum) /* fully unrolled */ \ +do { \ + Round256(p0, p1, p2, p3, ROT, rNum) \ + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, rNum, Xptr); \ +} while (0) + +#define I256(R) \ +do { \ + /* inject the key schedule value */ \ + X0 += ks[((R)+1) % 5]; \ + X1 += ks[((R)+2) % 5] + ts[((R)+1) % 3]; \ + X2 += ks[((R)+3) % 5] + ts[((R)+2) % 3]; \ + X3 += ks[((R)+4) % 5] + (R)+1; \ + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr); \ +} while (0) +#else /* looping version */ +#define R256(p0, p1, p2, p3, ROT, rNum) \ +do { \ + Round256(p0, p1, p2, p3, ROT, rNum) \ + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, 4 * (r - 1) + rNum, Xptr); \ +} while (0) + +#define I256(R) \ +do { \ + /* inject the key schedule value */ \ + X0 += ks[r+(R)+0]; \ + X1 += ks[r+(R)+1] + ts[r+(R)+0]; \ + X2 += ks[r+(R)+2] + ts[r+(R)+1]; \ + X3 += ks[r+(R)+3] + r+(R); \ + /* rotate key schedule */ \ + ks[r + (R) + 4] = ks[r + (R) - 1]; \ + ts[r + (R) + 2] = ts[r + (R) - 1]; \ + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr); \ +} while (0) + + for (r = 1; r < 2 * RCNT; r += 2 * SKEIN_UNROLL_256) +#endif + { +#define R256_8_rounds(R) \ +do { \ + R256(0, 1, 2, 3, R_256_0, 8 * (R) + 1); \ + R256(0, 3, 2, 1, R_256_1, 8 * (R) + 2); \ + R256(0, 1, 2, 3, R_256_2, 8 * (R) + 3); \ + R256(0, 3, 2, 1, R_256_3, 8 * (R) + 4); \ + I256(2 * (R)); \ + R256(0, 1, 2, 3, R_256_4, 8 * (R) + 5); \ + R256(0, 3, 2, 1, R_256_5, 8 * (R) + 6); \ + R256(0, 1, 2, 3, R_256_6, 8 * (R) + 7); \ + R256(0, 3, 2, 1, R_256_7, 8 * (R) + 8); \ + I256(2 * (R) + 1); \ +} while (0) + + R256_8_rounds(0); + +#define R256_Unroll_R(NN) \ + ((SKEIN_UNROLL_256 == 0 && \ + SKEIN_256_ROUNDS_TOTAL/8 > (NN)) || \ + (SKEIN_UNROLL_256 > (NN))) + + #if R256_Unroll_R(1) + R256_8_rounds(1); + #endif + #if R256_Unroll_R(2) + R256_8_rounds(2); + #endif + #if R256_Unroll_R(3) + R256_8_rounds(3); + #endif + #if R256_Unroll_R(4) + R256_8_rounds(4); + #endif + #if R256_Unroll_R(5) + R256_8_rounds(5); + #endif + #if R256_Unroll_R(6) + R256_8_rounds(6); + #endif + #if R256_Unroll_R(7) + R256_8_rounds(7); + #endif + #if R256_Unroll_R(8) + R256_8_rounds(8); + #endif + #if R256_Unroll_R(9) + R256_8_rounds(9); + #endif + #if R256_Unroll_R(10) + R256_8_rounds(10); + #endif + #if R256_Unroll_R(11) + R256_8_rounds(11); + #endif + #if R256_Unroll_R(12) + R256_8_rounds(12); + #endif + #if R256_Unroll_R(13) + R256_8_rounds(13); + #endif + #if R256_Unroll_R(14) + R256_8_rounds(14); + #endif + #if (SKEIN_UNROLL_256 > 14) +#error "need more unrolling in Skein_256_Process_Block" + #endif + } + /* do the final "feedforward" xor, update context chaining */ + ctx->X[0] = X0 ^ w[0]; + ctx->X[1] = X1 ^ w[1]; + ctx->X[2] = X2 ^ w[2]; + ctx->X[3] = X3 ^ w[3]; + + Skein_Show_Round(BLK_BITS, &ctx->h, SKEIN_RND_FEED_FWD, ctx->X); + + ts[1] &= ~SKEIN_T1_FLAG_FIRST; + } while (--blkCnt); + ctx->h.T[0] = ts[0]; + ctx->h.T[1] = ts[1]; +} + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +size_t Skein_256_Process_Block_CodeSize(void) +{ + return ((u8 *) Skein_256_Process_Block_CodeSize) - + ((u8 *) Skein_256_Process_Block); +} +unsigned int Skein_256_Unroll_Cnt(void) +{ + return SKEIN_UNROLL_256; +} +#endif +#endif + +/***************************** Skein_512 ******************************/ +#if !(SKEIN_USE_ASM & 512) +void Skein_512_Process_Block(struct skein_512_ctx *ctx, const u8 *blkPtr, + size_t blkCnt, size_t byteCntAdd) +{ /* do it in C */ + enum { + WCNT = SKEIN_512_STATE_WORDS + }; +#undef RCNT +#define RCNT (SKEIN_512_ROUNDS_TOTAL/8) + +#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ +#define SKEIN_UNROLL_512 (((SKEIN_LOOP)/10)%10) +#else +#define SKEIN_UNROLL_512 (0) +#endif + +#if SKEIN_UNROLL_512 +#if (RCNT % SKEIN_UNROLL_512) +#error "Invalid SKEIN_UNROLL_512" /* sanity check on unroll count */ +#endif + size_t r; + u64 kw[WCNT+4+RCNT*2]; /* key sched: chaining vars + tweak + "rot"*/ +#else + u64 kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ +#endif + u64 X0, X1, X2, X3, X4, X5, X6, X7; /* local copies, for speed */ + u64 w[WCNT]; /* local copy of input block */ +#ifdef SKEIN_DEBUG + const u64 *Xptr[8]; /* use for debugging (help cc put Xn in regs) */ + Xptr[0] = &X0; Xptr[1] = &X1; Xptr[2] = &X2; Xptr[3] = &X3; + Xptr[4] = &X4; Xptr[5] = &X5; Xptr[6] = &X6; Xptr[7] = &X7; +#endif + + Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ + ts[0] = ctx->h.T[0]; + ts[1] = ctx->h.T[1]; + do { + /* + * this implementation only supports 2**64 input bytes + * (no carry out here) + */ + ts[0] += byteCntAdd; /* update processed length */ + + /* precompute the key schedule for this block */ + ks[0] = ctx->X[0]; + ks[1] = ctx->X[1]; + ks[2] = ctx->X[2]; + ks[3] = ctx->X[3]; + ks[4] = ctx->X[4]; + ks[5] = ctx->X[5]; + ks[6] = ctx->X[6]; + ks[7] = ctx->X[7]; + ks[8] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ + ks[4] ^ ks[5] ^ ks[6] ^ ks[7] ^ SKEIN_KS_PARITY; + + ts[2] = ts[0] ^ ts[1]; + + /* get input block in little-endian format */ + Skein_Get64_LSB_First(w, blkPtr, WCNT); + DebugSaveTweak(ctx); + Skein_Show_Block(BLK_BITS, &ctx->h, ctx->X, blkPtr, w, ks, ts); + + X0 = w[0] + ks[0]; /* do the first full key injection */ + X1 = w[1] + ks[1]; + X2 = w[2] + ks[2]; + X3 = w[3] + ks[3]; + X4 = w[4] + ks[4]; + X5 = w[5] + ks[5] + ts[0]; + X6 = w[6] + ks[6] + ts[1]; + X7 = w[7] + ks[7]; + + blkPtr += SKEIN_512_BLOCK_BYTES; + + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INITIAL, + Xptr); + /* run the rounds */ +#define Round512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) \ +do { \ + X##p0 += X##p1; X##p1 = RotL_64(X##p1, ROT##_0); X##p1 ^= X##p0; \ + X##p2 += X##p3; X##p3 = RotL_64(X##p3, ROT##_1); X##p3 ^= X##p2; \ + X##p4 += X##p5; X##p5 = RotL_64(X##p5, ROT##_2); X##p5 ^= X##p4; \ + X##p6 += X##p7; X##p7 = RotL_64(X##p7, ROT##_3); X##p7 ^= X##p6; \ +} while (0) + +#if SKEIN_UNROLL_512 == 0 +#define R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) /* unrolled */ \ +do { \ + Round512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) \ + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, rNum, Xptr); \ +} while (0) + +#define I512(R) \ +do { \ + /* inject the key schedule value */ \ + X0 += ks[((R) + 1) % 9]; \ + X1 += ks[((R) + 2) % 9]; \ + X2 += ks[((R) + 3) % 9]; \ + X3 += ks[((R) + 4) % 9]; \ + X4 += ks[((R) + 5) % 9]; \ + X5 += ks[((R) + 6) % 9] + ts[((R) + 1) % 3]; \ + X6 += ks[((R) + 7) % 9] + ts[((R) + 2) % 3]; \ + X7 += ks[((R) + 8) % 9] + (R) + 1; \ + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr); \ +} while (0) +#else /* looping version */ +#define R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) \ +do { \ + Round512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) \ + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, 4 * (r - 1) + rNum, Xptr); \ +} while (0) + +#define I512(R) \ +do { \ + /* inject the key schedule value */ \ + X0 += ks[r + (R) + 0]; \ + X1 += ks[r + (R) + 1]; \ + X2 += ks[r + (R) + 2]; \ + X3 += ks[r + (R) + 3]; \ + X4 += ks[r + (R) + 4]; \ + X5 += ks[r + (R) + 5] + ts[r + (R) + 0]; \ + X6 += ks[r + (R) + 6] + ts[r + (R) + 1]; \ + X7 += ks[r + (R) + 7] + r + (R); \ + /* rotate key schedule */ \ + ks[r + (R) + 8] = ks[r + (R) - 1]; \ + ts[r + (R) + 2] = ts[r + (R) - 1]; \ + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr); \ +} while (0) + + for (r = 1; r < 2 * RCNT; r += 2 * SKEIN_UNROLL_512) +#endif /* end of looped code definitions */ + { +#define R512_8_rounds(R) /* do 8 full rounds */ \ +do { \ + R512(0, 1, 2, 3, 4, 5, 6, 7, R_512_0, 8 * (R) + 1); \ + R512(2, 1, 4, 7, 6, 5, 0, 3, R_512_1, 8 * (R) + 2); \ + R512(4, 1, 6, 3, 0, 5, 2, 7, R_512_2, 8 * (R) + 3); \ + R512(6, 1, 0, 7, 2, 5, 4, 3, R_512_3, 8 * (R) + 4); \ + I512(2 * (R)); \ + R512(0, 1, 2, 3, 4, 5, 6, 7, R_512_4, 8 * (R) + 5); \ + R512(2, 1, 4, 7, 6, 5, 0, 3, R_512_5, 8 * (R) + 6); \ + R512(4, 1, 6, 3, 0, 5, 2, 7, R_512_6, 8 * (R) + 7); \ + R512(6, 1, 0, 7, 2, 5, 4, 3, R_512_7, 8 * (R) + 8); \ + I512(2 * (R) + 1); /* and key injection */ \ +} while (0) + + R512_8_rounds(0); + +#define R512_Unroll_R(NN) \ + ((SKEIN_UNROLL_512 == 0 && \ + SKEIN_512_ROUNDS_TOTAL/8 > (NN)) || \ + (SKEIN_UNROLL_512 > (NN))) + + #if R512_Unroll_R(1) + R512_8_rounds(1); + #endif + #if R512_Unroll_R(2) + R512_8_rounds(2); + #endif + #if R512_Unroll_R(3) + R512_8_rounds(3); + #endif + #if R512_Unroll_R(4) + R512_8_rounds(4); + #endif + #if R512_Unroll_R(5) + R512_8_rounds(5); + #endif + #if R512_Unroll_R(6) + R512_8_rounds(6); + #endif + #if R512_Unroll_R(7) + R512_8_rounds(7); + #endif + #if R512_Unroll_R(8) + R512_8_rounds(8); + #endif + #if R512_Unroll_R(9) + R512_8_rounds(9); + #endif + #if R512_Unroll_R(10) + R512_8_rounds(10); + #endif + #if R512_Unroll_R(11) + R512_8_rounds(11); + #endif + #if R512_Unroll_R(12) + R512_8_rounds(12); + #endif + #if R512_Unroll_R(13) + R512_8_rounds(13); + #endif + #if R512_Unroll_R(14) + R512_8_rounds(14); + #endif + #if (SKEIN_UNROLL_512 > 14) +#error "need more unrolling in Skein_512_Process_Block" + #endif + } + + /* do the final "feedforward" xor, update context chaining */ + ctx->X[0] = X0 ^ w[0]; + ctx->X[1] = X1 ^ w[1]; + ctx->X[2] = X2 ^ w[2]; + ctx->X[3] = X3 ^ w[3]; + ctx->X[4] = X4 ^ w[4]; + ctx->X[5] = X5 ^ w[5]; + ctx->X[6] = X6 ^ w[6]; + ctx->X[7] = X7 ^ w[7]; + Skein_Show_Round(BLK_BITS, &ctx->h, SKEIN_RND_FEED_FWD, ctx->X); + + ts[1] &= ~SKEIN_T1_FLAG_FIRST; + } while (--blkCnt); + ctx->h.T[0] = ts[0]; + ctx->h.T[1] = ts[1]; +} + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +size_t Skein_512_Process_Block_CodeSize(void) +{ + return ((u8 *) Skein_512_Process_Block_CodeSize) - + ((u8 *) Skein_512_Process_Block); +} +unsigned int Skein_512_Unroll_Cnt(void) +{ + return SKEIN_UNROLL_512; +} +#endif +#endif + +/***************************** Skein1024 ******************************/ +#if !(SKEIN_USE_ASM & 1024) +void Skein1024_Process_Block(struct skein1024_ctx *ctx, const u8 *blkPtr, + size_t blkCnt, size_t byteCntAdd) +{ /* do it in C, always looping (unrolled is bigger AND slower!) */ + enum { + WCNT = SKEIN1024_STATE_WORDS + }; +#undef RCNT +#define RCNT (SKEIN1024_ROUNDS_TOTAL/8) + +#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ +#define SKEIN_UNROLL_1024 ((SKEIN_LOOP)%10) +#else +#define SKEIN_UNROLL_1024 (0) +#endif + +#if (SKEIN_UNROLL_1024 != 0) +#if (RCNT % SKEIN_UNROLL_1024) +#error "Invalid SKEIN_UNROLL_1024" /* sanity check on unroll count */ +#endif + size_t r; + u64 kw[WCNT+4+RCNT*2]; /* key sched: chaining vars + tweak + "rot" */ +#else + u64 kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ +#endif + + /* local copy of vars, for speed */ + u64 X00, X01, X02, X03, X04, X05, X06, X07, + X08, X09, X10, X11, X12, X13, X14, X15; + u64 w[WCNT]; /* local copy of input block */ +#ifdef SKEIN_DEBUG + const u64 *Xptr[16]; /* use for debugging (help cc put Xn in regs) */ + Xptr[0] = &X00; Xptr[1] = &X01; Xptr[2] = &X02; Xptr[3] = &X03; + Xptr[4] = &X04; Xptr[5] = &X05; Xptr[6] = &X06; Xptr[7] = &X07; + Xptr[8] = &X08; Xptr[9] = &X09; Xptr[10] = &X10; Xptr[11] = &X11; + Xptr[12] = &X12; Xptr[13] = &X13; Xptr[14] = &X14; Xptr[15] = &X15; +#endif + + Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ + ts[0] = ctx->h.T[0]; + ts[1] = ctx->h.T[1]; + do { + /* + * this implementation only supports 2**64 input bytes + * (no carry out here) + */ + ts[0] += byteCntAdd; /* update processed length */ + + /* precompute the key schedule for this block */ + ks[0] = ctx->X[0]; + ks[1] = ctx->X[1]; + ks[2] = ctx->X[2]; + ks[3] = ctx->X[3]; + ks[4] = ctx->X[4]; + ks[5] = ctx->X[5]; + ks[6] = ctx->X[6]; + ks[7] = ctx->X[7]; + ks[8] = ctx->X[8]; + ks[9] = ctx->X[9]; + ks[10] = ctx->X[10]; + ks[11] = ctx->X[11]; + ks[12] = ctx->X[12]; + ks[13] = ctx->X[13]; + ks[14] = ctx->X[14]; + ks[15] = ctx->X[15]; + ks[16] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ + ks[4] ^ ks[5] ^ ks[6] ^ ks[7] ^ + ks[8] ^ ks[9] ^ ks[10] ^ ks[11] ^ + ks[12] ^ ks[13] ^ ks[14] ^ ks[15] ^ SKEIN_KS_PARITY; + + ts[2] = ts[0] ^ ts[1]; + + /* get input block in little-endian format */ + Skein_Get64_LSB_First(w, blkPtr, WCNT); + DebugSaveTweak(ctx); + Skein_Show_Block(BLK_BITS, &ctx->h, ctx->X, blkPtr, w, ks, ts); + + X00 = w[0] + ks[0]; /* do the first full key injection */ + X01 = w[1] + ks[1]; + X02 = w[2] + ks[2]; + X03 = w[3] + ks[3]; + X04 = w[4] + ks[4]; + X05 = w[5] + ks[5]; + X06 = w[6] + ks[6]; + X07 = w[7] + ks[7]; + X08 = w[8] + ks[8]; + X09 = w[9] + ks[9]; + X10 = w[10] + ks[10]; + X11 = w[11] + ks[11]; + X12 = w[12] + ks[12]; + X13 = w[13] + ks[13] + ts[0]; + X14 = w[14] + ks[14] + ts[1]; + X15 = w[15] + ks[15]; + + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INITIAL, + Xptr); + +#define Round1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \ + pF, ROT, rNum) \ +do { \ + X##p0 += X##p1; X##p1 = RotL_64(X##p1, ROT##_0); X##p1 ^= X##p0; \ + X##p2 += X##p3; X##p3 = RotL_64(X##p3, ROT##_1); X##p3 ^= X##p2; \ + X##p4 += X##p5; X##p5 = RotL_64(X##p5, ROT##_2); X##p5 ^= X##p4; \ + X##p6 += X##p7; X##p7 = RotL_64(X##p7, ROT##_3); X##p7 ^= X##p6; \ + X##p8 += X##p9; X##p9 = RotL_64(X##p9, ROT##_4); X##p9 ^= X##p8; \ + X##pA += X##pB; X##pB = RotL_64(X##pB, ROT##_5); X##pB ^= X##pA; \ + X##pC += X##pD; X##pD = RotL_64(X##pD, ROT##_6); X##pD ^= X##pC; \ + X##pE += X##pF; X##pF = RotL_64(X##pF, ROT##_7); X##pF ^= X##pE; \ +} while (0) + +#if SKEIN_UNROLL_1024 == 0 +#define R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, pF, \ + ROT, rn) \ +do { \ + Round1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \ + pF, ROT, rn) \ + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, rn, Xptr); \ +} while (0) + +#define I1024(R) \ +do { \ + /* inject the key schedule value */ \ + X00 += ks[((R) + 1) % 17]; \ + X01 += ks[((R) + 2) % 17]; \ + X02 += ks[((R) + 3) % 17]; \ + X03 += ks[((R) + 4) % 17]; \ + X04 += ks[((R) + 5) % 17]; \ + X05 += ks[((R) + 6) % 17]; \ + X06 += ks[((R) + 7) % 17]; \ + X07 += ks[((R) + 8) % 17]; \ + X08 += ks[((R) + 9) % 17]; \ + X09 += ks[((R) + 10) % 17]; \ + X10 += ks[((R) + 11) % 17]; \ + X11 += ks[((R) + 12) % 17]; \ + X12 += ks[((R) + 13) % 17]; \ + X13 += ks[((R) + 14) % 17] + ts[((R) + 1) % 3]; \ + X14 += ks[((R) + 15) % 17] + ts[((R) + 2) % 3]; \ + X15 += ks[((R) + 16) % 17] + (R) + 1; \ + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr); \ +} while (0) +#else /* looping version */ +#define R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, pF, \ + ROT, rn) \ +do { \ + Round1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \ + pF, ROT, rn) \ + Skein_Show_R_Ptr(BLK_BITS, &ctx->h, 4 * (r - 1) + rn, Xptr); \ +} while (0) + +#define I1024(R) \ +do { \ + /* inject the key schedule value */ \ + X00 += ks[r + (R) + 0]; \ + X01 += ks[r + (R) + 1]; \ + X02 += ks[r + (R) + 2]; \ + X03 += ks[r + (R) + 3]; \ + X04 += ks[r + (R) + 4]; \ + X05 += ks[r + (R) + 5]; \ + X06 += ks[r + (R) + 6]; \ + X07 += ks[r + (R) + 7]; \ + X08 += ks[r + (R) + 8]; \ + X09 += ks[r + (R) + 9]; \ + X10 += ks[r + (R) + 10]; \ + X11 += ks[r + (R) + 11]; \ + X12 += ks[r + (R) + 12]; \ + X13 += ks[r + (R) + 13] + ts[r + (R) + 0]; \ + X14 += ks[r + (R) + 14] + ts[r + (R) + 1]; \ + X15 += ks[r + (R) + 15] + r + (R); \ + /* rotate key schedule */ \ + ks[r + (R) + 16] = ks[r + (R) - 1]; \ + ts[r + (R) + 2] = ts[r + (R) - 1]; \ + Skein_Show_R_Ptr(BLK_BITSi, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr); \ +} while (0) + + for (r = 1; r <= 2 * RCNT; r += 2 * SKEIN_UNROLL_1024) +#endif + { +#define R1024_8_rounds(R) \ +do { \ + R1024(00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, \ + R1024_0, 8*(R) + 1); \ + R1024(00, 09, 02, 13, 06, 11, 04, 15, 10, 07, 12, 03, 14, 05, 08, 01, \ + R1024_1, 8*(R) + 2); \ + R1024(00, 07, 02, 05, 04, 03, 06, 01, 12, 15, 14, 13, 08, 11, 10, 09, \ + R1024_2, 8*(R) + 3); \ + R1024(00, 15, 02, 11, 06, 13, 04, 09, 14, 01, 08, 05, 10, 03, 12, 07, \ + R1024_3, 8*(R) + 4); \ + I1024(2*(R)); \ + R1024(00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, \ + R1024_4, 8*(R) + 5); \ + R1024(00, 09, 02, 13, 06, 11, 04, 15, 10, 07, 12, 03, 14, 05, 08, 01, \ + R1024_5, 8*(R) + 6); \ + R1024(00, 07, 02, 05, 04, 03, 06, 01, 12, 15, 14, 13, 08, 11, 10, 09, \ + R1024_6, 8*(R) + 7); \ + R1024(00, 15, 02, 11, 06, 13, 04, 09, 14, 01, 08, 05, 10, 03, 12, 07, \ + R1024_7, 8*(R) + 8); \ + I1024(2*(R)+1); \ +} while (0) + + R1024_8_rounds(0); + +#define R1024_Unroll_R(NN) \ + ((SKEIN_UNROLL_1024 == 0 && \ + SKEIN1024_ROUNDS_TOTAL/8 > (NN)) || \ + (SKEIN_UNROLL_1024 > (NN))) + + #if R1024_Unroll_R(1) + R1024_8_rounds(1); + #endif + #if R1024_Unroll_R(2) + R1024_8_rounds(2); + #endif + #if R1024_Unroll_R(3) + R1024_8_rounds(3); + #endif + #if R1024_Unroll_R(4) + R1024_8_rounds(4); + #endif + #if R1024_Unroll_R(5) + R1024_8_rounds(5); + #endif + #if R1024_Unroll_R(6) + R1024_8_rounds(6); + #endif + #if R1024_Unroll_R(7) + R1024_8_rounds(7); + #endif + #if R1024_Unroll_R(8) + R1024_8_rounds(8); + #endif + #if R1024_Unroll_R(9) + R1024_8_rounds(9); + #endif + #if R1024_Unroll_R(10) + R1024_8_rounds(10); + #endif + #if R1024_Unroll_R(11) + R1024_8_rounds(11); + #endif + #if R1024_Unroll_R(12) + R1024_8_rounds(12); + #endif + #if R1024_Unroll_R(13) + R1024_8_rounds(13); + #endif + #if R1024_Unroll_R(14) + R1024_8_rounds(14); + #endif +#if (SKEIN_UNROLL_1024 > 14) +#error "need more unrolling in Skein_1024_Process_Block" + #endif + } + /* do the final "feedforward" xor, update context chaining */ + + ctx->X[0] = X00 ^ w[0]; + ctx->X[1] = X01 ^ w[1]; + ctx->X[2] = X02 ^ w[2]; + ctx->X[3] = X03 ^ w[3]; + ctx->X[4] = X04 ^ w[4]; + ctx->X[5] = X05 ^ w[5]; + ctx->X[6] = X06 ^ w[6]; + ctx->X[7] = X07 ^ w[7]; + ctx->X[8] = X08 ^ w[8]; + ctx->X[9] = X09 ^ w[9]; + ctx->X[10] = X10 ^ w[10]; + ctx->X[11] = X11 ^ w[11]; + ctx->X[12] = X12 ^ w[12]; + ctx->X[13] = X13 ^ w[13]; + ctx->X[14] = X14 ^ w[14]; + ctx->X[15] = X15 ^ w[15]; + + Skein_Show_Round(BLK_BITS, &ctx->h, SKEIN_RND_FEED_FWD, ctx->X); + + ts[1] &= ~SKEIN_T1_FLAG_FIRST; + blkPtr += SKEIN1024_BLOCK_BYTES; + } while (--blkCnt); + ctx->h.T[0] = ts[0]; + ctx->h.T[1] = ts[1]; +} + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +size_t Skein1024_Process_Block_CodeSize(void) +{ + return ((u8 *) Skein1024_Process_Block_CodeSize) - + ((u8 *) Skein1024_Process_Block); +} +unsigned int Skein1024_Unroll_Cnt(void) +{ + return SKEIN_UNROLL_1024; +} +#endif +#endif diff --git a/drivers/staging/skein/threefish1024Block.c b/drivers/staging/skein/threefish1024Block.c new file mode 100644 index 00000000000000..fe7517b2008c1e --- /dev/null +++ b/drivers/staging/skein/threefish1024Block.c @@ -0,0 +1,4900 @@ +#include +#include + + +void threefishEncrypt1024(struct threefish_key *keyCtx, u64 *input, u64 *output) +{ + u64 b0 = input[0], b1 = input[1], + b2 = input[2], b3 = input[3], + b4 = input[4], b5 = input[5], + b6 = input[6], b7 = input[7], + b8 = input[8], b9 = input[9], + b10 = input[10], b11 = input[11], + b12 = input[12], b13 = input[13], + b14 = input[14], b15 = input[15]; + u64 k0 = keyCtx->key[0], k1 = keyCtx->key[1], + k2 = keyCtx->key[2], k3 = keyCtx->key[3], + k4 = keyCtx->key[4], k5 = keyCtx->key[5], + k6 = keyCtx->key[6], k7 = keyCtx->key[7], + k8 = keyCtx->key[8], k9 = keyCtx->key[9], + k10 = keyCtx->key[10], k11 = keyCtx->key[11], + k12 = keyCtx->key[12], k13 = keyCtx->key[13], + k14 = keyCtx->key[14], k15 = keyCtx->key[15], + k16 = keyCtx->key[16]; + u64 t0 = keyCtx->tweak[0], t1 = keyCtx->tweak[1], + t2 = keyCtx->tweak[2]; + + b1 += k1; + b0 += b1 + k0; + b1 = ((b1 << 24) | (b1 >> (64 - 24))) ^ b0; + + b3 += k3; + b2 += b3 + k2; + b3 = ((b3 << 13) | (b3 >> (64 - 13))) ^ b2; + + b5 += k5; + b4 += b5 + k4; + b5 = ((b5 << 8) | (b5 >> (64 - 8))) ^ b4; + + b7 += k7; + b6 += b7 + k6; + b7 = ((b7 << 47) | (b7 >> (64 - 47))) ^ b6; + + b9 += k9; + b8 += b9 + k8; + b9 = ((b9 << 8) | (b9 >> (64 - 8))) ^ b8; + + b11 += k11; + b10 += b11 + k10; + b11 = ((b11 << 17) | (b11 >> (64 - 17))) ^ b10; + + b13 += k13 + t0; + b12 += b13 + k12; + b13 = ((b13 << 22) | (b13 >> (64 - 22))) ^ b12; + + b15 += k15; + b14 += b15 + k14 + t1; + b15 = ((b15 << 37) | (b15 >> (64 - 37))) ^ b14; + + b0 += b9; + b9 = ((b9 << 38) | (b9 >> (64 - 38))) ^ b0; + + b2 += b13; + b13 = ((b13 << 19) | (b13 >> (64 - 19))) ^ b2; + + b6 += b11; + b11 = ((b11 << 10) | (b11 >> (64 - 10))) ^ b6; + + b4 += b15; + b15 = ((b15 << 55) | (b15 >> (64 - 55))) ^ b4; + + b10 += b7; + b7 = ((b7 << 49) | (b7 >> (64 - 49))) ^ b10; + + b12 += b3; + b3 = ((b3 << 18) | (b3 >> (64 - 18))) ^ b12; + + b14 += b5; + b5 = ((b5 << 23) | (b5 >> (64 - 23))) ^ b14; + + b8 += b1; + b1 = ((b1 << 52) | (b1 >> (64 - 52))) ^ b8; + + b0 += b7; + b7 = ((b7 << 33) | (b7 >> (64 - 33))) ^ b0; + + b2 += b5; + b5 = ((b5 << 4) | (b5 >> (64 - 4))) ^ b2; + + b4 += b3; + b3 = ((b3 << 51) | (b3 >> (64 - 51))) ^ b4; + + b6 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b6; + + b12 += b15; + b15 = ((b15 << 34) | (b15 >> (64 - 34))) ^ b12; + + b14 += b13; + b13 = ((b13 << 41) | (b13 >> (64 - 41))) ^ b14; + + b8 += b11; + b11 = ((b11 << 59) | (b11 >> (64 - 59))) ^ b8; + + b10 += b9; + b9 = ((b9 << 17) | (b9 >> (64 - 17))) ^ b10; + + b0 += b15; + b15 = ((b15 << 5) | (b15 >> (64 - 5))) ^ b0; + + b2 += b11; + b11 = ((b11 << 20) | (b11 >> (64 - 20))) ^ b2; + + b6 += b13; + b13 = ((b13 << 48) | (b13 >> (64 - 48))) ^ b6; + + b4 += b9; + b9 = ((b9 << 41) | (b9 >> (64 - 41))) ^ b4; + + b14 += b1; + b1 = ((b1 << 47) | (b1 >> (64 - 47))) ^ b14; + + b8 += b5; + b5 = ((b5 << 28) | (b5 >> (64 - 28))) ^ b8; + + b10 += b3; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b10; + + b12 += b7; + b7 = ((b7 << 25) | (b7 >> (64 - 25))) ^ b12; + + b1 += k2; + b0 += b1 + k1; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b0; + + b3 += k4; + b2 += b3 + k3; + b3 = ((b3 << 9) | (b3 >> (64 - 9))) ^ b2; + + b5 += k6; + b4 += b5 + k5; + b5 = ((b5 << 37) | (b5 >> (64 - 37))) ^ b4; + + b7 += k8; + b6 += b7 + k7; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b6; + + b9 += k10; + b8 += b9 + k9; + b9 = ((b9 << 12) | (b9 >> (64 - 12))) ^ b8; + + b11 += k12; + b10 += b11 + k11; + b11 = ((b11 << 47) | (b11 >> (64 - 47))) ^ b10; + + b13 += k14 + t1; + b12 += b13 + k13; + b13 = ((b13 << 44) | (b13 >> (64 - 44))) ^ b12; + + b15 += k16 + 1; + b14 += b15 + k15 + t2; + b15 = ((b15 << 30) | (b15 >> (64 - 30))) ^ b14; + + b0 += b9; + b9 = ((b9 << 16) | (b9 >> (64 - 16))) ^ b0; + + b2 += b13; + b13 = ((b13 << 34) | (b13 >> (64 - 34))) ^ b2; + + b6 += b11; + b11 = ((b11 << 56) | (b11 >> (64 - 56))) ^ b6; + + b4 += b15; + b15 = ((b15 << 51) | (b15 >> (64 - 51))) ^ b4; + + b10 += b7; + b7 = ((b7 << 4) | (b7 >> (64 - 4))) ^ b10; + + b12 += b3; + b3 = ((b3 << 53) | (b3 >> (64 - 53))) ^ b12; + + b14 += b5; + b5 = ((b5 << 42) | (b5 >> (64 - 42))) ^ b14; + + b8 += b1; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b8; + + b0 += b7; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b0; + + b2 += b5; + b5 = ((b5 << 44) | (b5 >> (64 - 44))) ^ b2; + + b4 += b3; + b3 = ((b3 << 47) | (b3 >> (64 - 47))) ^ b4; + + b6 += b1; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b6; + + b12 += b15; + b15 = ((b15 << 19) | (b15 >> (64 - 19))) ^ b12; + + b14 += b13; + b13 = ((b13 << 42) | (b13 >> (64 - 42))) ^ b14; + + b8 += b11; + b11 = ((b11 << 44) | (b11 >> (64 - 44))) ^ b8; + + b10 += b9; + b9 = ((b9 << 25) | (b9 >> (64 - 25))) ^ b10; + + b0 += b15; + b15 = ((b15 << 9) | (b15 >> (64 - 9))) ^ b0; + + b2 += b11; + b11 = ((b11 << 48) | (b11 >> (64 - 48))) ^ b2; + + b6 += b13; + b13 = ((b13 << 35) | (b13 >> (64 - 35))) ^ b6; + + b4 += b9; + b9 = ((b9 << 52) | (b9 >> (64 - 52))) ^ b4; + + b14 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b14; + + b8 += b5; + b5 = ((b5 << 31) | (b5 >> (64 - 31))) ^ b8; + + b10 += b3; + b3 = ((b3 << 37) | (b3 >> (64 - 37))) ^ b10; + + b12 += b7; + b7 = ((b7 << 20) | (b7 >> (64 - 20))) ^ b12; + + b1 += k3; + b0 += b1 + k2; + b1 = ((b1 << 24) | (b1 >> (64 - 24))) ^ b0; + + b3 += k5; + b2 += b3 + k4; + b3 = ((b3 << 13) | (b3 >> (64 - 13))) ^ b2; + + b5 += k7; + b4 += b5 + k6; + b5 = ((b5 << 8) | (b5 >> (64 - 8))) ^ b4; + + b7 += k9; + b6 += b7 + k8; + b7 = ((b7 << 47) | (b7 >> (64 - 47))) ^ b6; + + b9 += k11; + b8 += b9 + k10; + b9 = ((b9 << 8) | (b9 >> (64 - 8))) ^ b8; + + b11 += k13; + b10 += b11 + k12; + b11 = ((b11 << 17) | (b11 >> (64 - 17))) ^ b10; + + b13 += k15 + t2; + b12 += b13 + k14; + b13 = ((b13 << 22) | (b13 >> (64 - 22))) ^ b12; + + b15 += k0 + 2; + b14 += b15 + k16 + t0; + b15 = ((b15 << 37) | (b15 >> (64 - 37))) ^ b14; + + b0 += b9; + b9 = ((b9 << 38) | (b9 >> (64 - 38))) ^ b0; + + b2 += b13; + b13 = ((b13 << 19) | (b13 >> (64 - 19))) ^ b2; + + b6 += b11; + b11 = ((b11 << 10) | (b11 >> (64 - 10))) ^ b6; + + b4 += b15; + b15 = ((b15 << 55) | (b15 >> (64 - 55))) ^ b4; + + b10 += b7; + b7 = ((b7 << 49) | (b7 >> (64 - 49))) ^ b10; + + b12 += b3; + b3 = ((b3 << 18) | (b3 >> (64 - 18))) ^ b12; + + b14 += b5; + b5 = ((b5 << 23) | (b5 >> (64 - 23))) ^ b14; + + b8 += b1; + b1 = ((b1 << 52) | (b1 >> (64 - 52))) ^ b8; + + b0 += b7; + b7 = ((b7 << 33) | (b7 >> (64 - 33))) ^ b0; + + b2 += b5; + b5 = ((b5 << 4) | (b5 >> (64 - 4))) ^ b2; + + b4 += b3; + b3 = ((b3 << 51) | (b3 >> (64 - 51))) ^ b4; + + b6 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b6; + + b12 += b15; + b15 = ((b15 << 34) | (b15 >> (64 - 34))) ^ b12; + + b14 += b13; + b13 = ((b13 << 41) | (b13 >> (64 - 41))) ^ b14; + + b8 += b11; + b11 = ((b11 << 59) | (b11 >> (64 - 59))) ^ b8; + + b10 += b9; + b9 = ((b9 << 17) | (b9 >> (64 - 17))) ^ b10; + + b0 += b15; + b15 = ((b15 << 5) | (b15 >> (64 - 5))) ^ b0; + + b2 += b11; + b11 = ((b11 << 20) | (b11 >> (64 - 20))) ^ b2; + + b6 += b13; + b13 = ((b13 << 48) | (b13 >> (64 - 48))) ^ b6; + + b4 += b9; + b9 = ((b9 << 41) | (b9 >> (64 - 41))) ^ b4; + + b14 += b1; + b1 = ((b1 << 47) | (b1 >> (64 - 47))) ^ b14; + + b8 += b5; + b5 = ((b5 << 28) | (b5 >> (64 - 28))) ^ b8; + + b10 += b3; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b10; + + b12 += b7; + b7 = ((b7 << 25) | (b7 >> (64 - 25))) ^ b12; + + b1 += k4; + b0 += b1 + k3; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b0; + + b3 += k6; + b2 += b3 + k5; + b3 = ((b3 << 9) | (b3 >> (64 - 9))) ^ b2; + + b5 += k8; + b4 += b5 + k7; + b5 = ((b5 << 37) | (b5 >> (64 - 37))) ^ b4; + + b7 += k10; + b6 += b7 + k9; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b6; + + b9 += k12; + b8 += b9 + k11; + b9 = ((b9 << 12) | (b9 >> (64 - 12))) ^ b8; + + b11 += k14; + b10 += b11 + k13; + b11 = ((b11 << 47) | (b11 >> (64 - 47))) ^ b10; + + b13 += k16 + t0; + b12 += b13 + k15; + b13 = ((b13 << 44) | (b13 >> (64 - 44))) ^ b12; + + b15 += k1 + 3; + b14 += b15 + k0 + t1; + b15 = ((b15 << 30) | (b15 >> (64 - 30))) ^ b14; + + b0 += b9; + b9 = ((b9 << 16) | (b9 >> (64 - 16))) ^ b0; + + b2 += b13; + b13 = ((b13 << 34) | (b13 >> (64 - 34))) ^ b2; + + b6 += b11; + b11 = ((b11 << 56) | (b11 >> (64 - 56))) ^ b6; + + b4 += b15; + b15 = ((b15 << 51) | (b15 >> (64 - 51))) ^ b4; + + b10 += b7; + b7 = ((b7 << 4) | (b7 >> (64 - 4))) ^ b10; + + b12 += b3; + b3 = ((b3 << 53) | (b3 >> (64 - 53))) ^ b12; + + b14 += b5; + b5 = ((b5 << 42) | (b5 >> (64 - 42))) ^ b14; + + b8 += b1; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b8; + + b0 += b7; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b0; + + b2 += b5; + b5 = ((b5 << 44) | (b5 >> (64 - 44))) ^ b2; + + b4 += b3; + b3 = ((b3 << 47) | (b3 >> (64 - 47))) ^ b4; + + b6 += b1; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b6; + + b12 += b15; + b15 = ((b15 << 19) | (b15 >> (64 - 19))) ^ b12; + + b14 += b13; + b13 = ((b13 << 42) | (b13 >> (64 - 42))) ^ b14; + + b8 += b11; + b11 = ((b11 << 44) | (b11 >> (64 - 44))) ^ b8; + + b10 += b9; + b9 = ((b9 << 25) | (b9 >> (64 - 25))) ^ b10; + + b0 += b15; + b15 = ((b15 << 9) | (b15 >> (64 - 9))) ^ b0; + + b2 += b11; + b11 = ((b11 << 48) | (b11 >> (64 - 48))) ^ b2; + + b6 += b13; + b13 = ((b13 << 35) | (b13 >> (64 - 35))) ^ b6; + + b4 += b9; + b9 = ((b9 << 52) | (b9 >> (64 - 52))) ^ b4; + + b14 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b14; + + b8 += b5; + b5 = ((b5 << 31) | (b5 >> (64 - 31))) ^ b8; + + b10 += b3; + b3 = ((b3 << 37) | (b3 >> (64 - 37))) ^ b10; + + b12 += b7; + b7 = ((b7 << 20) | (b7 >> (64 - 20))) ^ b12; + + b1 += k5; + b0 += b1 + k4; + b1 = ((b1 << 24) | (b1 >> (64 - 24))) ^ b0; + + b3 += k7; + b2 += b3 + k6; + b3 = ((b3 << 13) | (b3 >> (64 - 13))) ^ b2; + + b5 += k9; + b4 += b5 + k8; + b5 = ((b5 << 8) | (b5 >> (64 - 8))) ^ b4; + + b7 += k11; + b6 += b7 + k10; + b7 = ((b7 << 47) | (b7 >> (64 - 47))) ^ b6; + + b9 += k13; + b8 += b9 + k12; + b9 = ((b9 << 8) | (b9 >> (64 - 8))) ^ b8; + + b11 += k15; + b10 += b11 + k14; + b11 = ((b11 << 17) | (b11 >> (64 - 17))) ^ b10; + + b13 += k0 + t1; + b12 += b13 + k16; + b13 = ((b13 << 22) | (b13 >> (64 - 22))) ^ b12; + + b15 += k2 + 4; + b14 += b15 + k1 + t2; + b15 = ((b15 << 37) | (b15 >> (64 - 37))) ^ b14; + + b0 += b9; + b9 = ((b9 << 38) | (b9 >> (64 - 38))) ^ b0; + + b2 += b13; + b13 = ((b13 << 19) | (b13 >> (64 - 19))) ^ b2; + + b6 += b11; + b11 = ((b11 << 10) | (b11 >> (64 - 10))) ^ b6; + + b4 += b15; + b15 = ((b15 << 55) | (b15 >> (64 - 55))) ^ b4; + + b10 += b7; + b7 = ((b7 << 49) | (b7 >> (64 - 49))) ^ b10; + + b12 += b3; + b3 = ((b3 << 18) | (b3 >> (64 - 18))) ^ b12; + + b14 += b5; + b5 = ((b5 << 23) | (b5 >> (64 - 23))) ^ b14; + + b8 += b1; + b1 = ((b1 << 52) | (b1 >> (64 - 52))) ^ b8; + + b0 += b7; + b7 = ((b7 << 33) | (b7 >> (64 - 33))) ^ b0; + + b2 += b5; + b5 = ((b5 << 4) | (b5 >> (64 - 4))) ^ b2; + + b4 += b3; + b3 = ((b3 << 51) | (b3 >> (64 - 51))) ^ b4; + + b6 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b6; + + b12 += b15; + b15 = ((b15 << 34) | (b15 >> (64 - 34))) ^ b12; + + b14 += b13; + b13 = ((b13 << 41) | (b13 >> (64 - 41))) ^ b14; + + b8 += b11; + b11 = ((b11 << 59) | (b11 >> (64 - 59))) ^ b8; + + b10 += b9; + b9 = ((b9 << 17) | (b9 >> (64 - 17))) ^ b10; + + b0 += b15; + b15 = ((b15 << 5) | (b15 >> (64 - 5))) ^ b0; + + b2 += b11; + b11 = ((b11 << 20) | (b11 >> (64 - 20))) ^ b2; + + b6 += b13; + b13 = ((b13 << 48) | (b13 >> (64 - 48))) ^ b6; + + b4 += b9; + b9 = ((b9 << 41) | (b9 >> (64 - 41))) ^ b4; + + b14 += b1; + b1 = ((b1 << 47) | (b1 >> (64 - 47))) ^ b14; + + b8 += b5; + b5 = ((b5 << 28) | (b5 >> (64 - 28))) ^ b8; + + b10 += b3; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b10; + + b12 += b7; + b7 = ((b7 << 25) | (b7 >> (64 - 25))) ^ b12; + + b1 += k6; + b0 += b1 + k5; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b0; + + b3 += k8; + b2 += b3 + k7; + b3 = ((b3 << 9) | (b3 >> (64 - 9))) ^ b2; + + b5 += k10; + b4 += b5 + k9; + b5 = ((b5 << 37) | (b5 >> (64 - 37))) ^ b4; + + b7 += k12; + b6 += b7 + k11; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b6; + + b9 += k14; + b8 += b9 + k13; + b9 = ((b9 << 12) | (b9 >> (64 - 12))) ^ b8; + + b11 += k16; + b10 += b11 + k15; + b11 = ((b11 << 47) | (b11 >> (64 - 47))) ^ b10; + + b13 += k1 + t2; + b12 += b13 + k0; + b13 = ((b13 << 44) | (b13 >> (64 - 44))) ^ b12; + + b15 += k3 + 5; + b14 += b15 + k2 + t0; + b15 = ((b15 << 30) | (b15 >> (64 - 30))) ^ b14; + + b0 += b9; + b9 = ((b9 << 16) | (b9 >> (64 - 16))) ^ b0; + + b2 += b13; + b13 = ((b13 << 34) | (b13 >> (64 - 34))) ^ b2; + + b6 += b11; + b11 = ((b11 << 56) | (b11 >> (64 - 56))) ^ b6; + + b4 += b15; + b15 = ((b15 << 51) | (b15 >> (64 - 51))) ^ b4; + + b10 += b7; + b7 = ((b7 << 4) | (b7 >> (64 - 4))) ^ b10; + + b12 += b3; + b3 = ((b3 << 53) | (b3 >> (64 - 53))) ^ b12; + + b14 += b5; + b5 = ((b5 << 42) | (b5 >> (64 - 42))) ^ b14; + + b8 += b1; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b8; + + b0 += b7; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b0; + + b2 += b5; + b5 = ((b5 << 44) | (b5 >> (64 - 44))) ^ b2; + + b4 += b3; + b3 = ((b3 << 47) | (b3 >> (64 - 47))) ^ b4; + + b6 += b1; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b6; + + b12 += b15; + b15 = ((b15 << 19) | (b15 >> (64 - 19))) ^ b12; + + b14 += b13; + b13 = ((b13 << 42) | (b13 >> (64 - 42))) ^ b14; + + b8 += b11; + b11 = ((b11 << 44) | (b11 >> (64 - 44))) ^ b8; + + b10 += b9; + b9 = ((b9 << 25) | (b9 >> (64 - 25))) ^ b10; + + b0 += b15; + b15 = ((b15 << 9) | (b15 >> (64 - 9))) ^ b0; + + b2 += b11; + b11 = ((b11 << 48) | (b11 >> (64 - 48))) ^ b2; + + b6 += b13; + b13 = ((b13 << 35) | (b13 >> (64 - 35))) ^ b6; + + b4 += b9; + b9 = ((b9 << 52) | (b9 >> (64 - 52))) ^ b4; + + b14 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b14; + + b8 += b5; + b5 = ((b5 << 31) | (b5 >> (64 - 31))) ^ b8; + + b10 += b3; + b3 = ((b3 << 37) | (b3 >> (64 - 37))) ^ b10; + + b12 += b7; + b7 = ((b7 << 20) | (b7 >> (64 - 20))) ^ b12; + + b1 += k7; + b0 += b1 + k6; + b1 = ((b1 << 24) | (b1 >> (64 - 24))) ^ b0; + + b3 += k9; + b2 += b3 + k8; + b3 = ((b3 << 13) | (b3 >> (64 - 13))) ^ b2; + + b5 += k11; + b4 += b5 + k10; + b5 = ((b5 << 8) | (b5 >> (64 - 8))) ^ b4; + + b7 += k13; + b6 += b7 + k12; + b7 = ((b7 << 47) | (b7 >> (64 - 47))) ^ b6; + + b9 += k15; + b8 += b9 + k14; + b9 = ((b9 << 8) | (b9 >> (64 - 8))) ^ b8; + + b11 += k0; + b10 += b11 + k16; + b11 = ((b11 << 17) | (b11 >> (64 - 17))) ^ b10; + + b13 += k2 + t0; + b12 += b13 + k1; + b13 = ((b13 << 22) | (b13 >> (64 - 22))) ^ b12; + + b15 += k4 + 6; + b14 += b15 + k3 + t1; + b15 = ((b15 << 37) | (b15 >> (64 - 37))) ^ b14; + + b0 += b9; + b9 = ((b9 << 38) | (b9 >> (64 - 38))) ^ b0; + + b2 += b13; + b13 = ((b13 << 19) | (b13 >> (64 - 19))) ^ b2; + + b6 += b11; + b11 = ((b11 << 10) | (b11 >> (64 - 10))) ^ b6; + + b4 += b15; + b15 = ((b15 << 55) | (b15 >> (64 - 55))) ^ b4; + + b10 += b7; + b7 = ((b7 << 49) | (b7 >> (64 - 49))) ^ b10; + + b12 += b3; + b3 = ((b3 << 18) | (b3 >> (64 - 18))) ^ b12; + + b14 += b5; + b5 = ((b5 << 23) | (b5 >> (64 - 23))) ^ b14; + + b8 += b1; + b1 = ((b1 << 52) | (b1 >> (64 - 52))) ^ b8; + + b0 += b7; + b7 = ((b7 << 33) | (b7 >> (64 - 33))) ^ b0; + + b2 += b5; + b5 = ((b5 << 4) | (b5 >> (64 - 4))) ^ b2; + + b4 += b3; + b3 = ((b3 << 51) | (b3 >> (64 - 51))) ^ b4; + + b6 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b6; + + b12 += b15; + b15 = ((b15 << 34) | (b15 >> (64 - 34))) ^ b12; + + b14 += b13; + b13 = ((b13 << 41) | (b13 >> (64 - 41))) ^ b14; + + b8 += b11; + b11 = ((b11 << 59) | (b11 >> (64 - 59))) ^ b8; + + b10 += b9; + b9 = ((b9 << 17) | (b9 >> (64 - 17))) ^ b10; + + b0 += b15; + b15 = ((b15 << 5) | (b15 >> (64 - 5))) ^ b0; + + b2 += b11; + b11 = ((b11 << 20) | (b11 >> (64 - 20))) ^ b2; + + b6 += b13; + b13 = ((b13 << 48) | (b13 >> (64 - 48))) ^ b6; + + b4 += b9; + b9 = ((b9 << 41) | (b9 >> (64 - 41))) ^ b4; + + b14 += b1; + b1 = ((b1 << 47) | (b1 >> (64 - 47))) ^ b14; + + b8 += b5; + b5 = ((b5 << 28) | (b5 >> (64 - 28))) ^ b8; + + b10 += b3; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b10; + + b12 += b7; + b7 = ((b7 << 25) | (b7 >> (64 - 25))) ^ b12; + + b1 += k8; + b0 += b1 + k7; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b0; + + b3 += k10; + b2 += b3 + k9; + b3 = ((b3 << 9) | (b3 >> (64 - 9))) ^ b2; + + b5 += k12; + b4 += b5 + k11; + b5 = ((b5 << 37) | (b5 >> (64 - 37))) ^ b4; + + b7 += k14; + b6 += b7 + k13; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b6; + + b9 += k16; + b8 += b9 + k15; + b9 = ((b9 << 12) | (b9 >> (64 - 12))) ^ b8; + + b11 += k1; + b10 += b11 + k0; + b11 = ((b11 << 47) | (b11 >> (64 - 47))) ^ b10; + + b13 += k3 + t1; + b12 += b13 + k2; + b13 = ((b13 << 44) | (b13 >> (64 - 44))) ^ b12; + + b15 += k5 + 7; + b14 += b15 + k4 + t2; + b15 = ((b15 << 30) | (b15 >> (64 - 30))) ^ b14; + + b0 += b9; + b9 = ((b9 << 16) | (b9 >> (64 - 16))) ^ b0; + + b2 += b13; + b13 = ((b13 << 34) | (b13 >> (64 - 34))) ^ b2; + + b6 += b11; + b11 = ((b11 << 56) | (b11 >> (64 - 56))) ^ b6; + + b4 += b15; + b15 = ((b15 << 51) | (b15 >> (64 - 51))) ^ b4; + + b10 += b7; + b7 = ((b7 << 4) | (b7 >> (64 - 4))) ^ b10; + + b12 += b3; + b3 = ((b3 << 53) | (b3 >> (64 - 53))) ^ b12; + + b14 += b5; + b5 = ((b5 << 42) | (b5 >> (64 - 42))) ^ b14; + + b8 += b1; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b8; + + b0 += b7; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b0; + + b2 += b5; + b5 = ((b5 << 44) | (b5 >> (64 - 44))) ^ b2; + + b4 += b3; + b3 = ((b3 << 47) | (b3 >> (64 - 47))) ^ b4; + + b6 += b1; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b6; + + b12 += b15; + b15 = ((b15 << 19) | (b15 >> (64 - 19))) ^ b12; + + b14 += b13; + b13 = ((b13 << 42) | (b13 >> (64 - 42))) ^ b14; + + b8 += b11; + b11 = ((b11 << 44) | (b11 >> (64 - 44))) ^ b8; + + b10 += b9; + b9 = ((b9 << 25) | (b9 >> (64 - 25))) ^ b10; + + b0 += b15; + b15 = ((b15 << 9) | (b15 >> (64 - 9))) ^ b0; + + b2 += b11; + b11 = ((b11 << 48) | (b11 >> (64 - 48))) ^ b2; + + b6 += b13; + b13 = ((b13 << 35) | (b13 >> (64 - 35))) ^ b6; + + b4 += b9; + b9 = ((b9 << 52) | (b9 >> (64 - 52))) ^ b4; + + b14 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b14; + + b8 += b5; + b5 = ((b5 << 31) | (b5 >> (64 - 31))) ^ b8; + + b10 += b3; + b3 = ((b3 << 37) | (b3 >> (64 - 37))) ^ b10; + + b12 += b7; + b7 = ((b7 << 20) | (b7 >> (64 - 20))) ^ b12; + + b1 += k9; + b0 += b1 + k8; + b1 = ((b1 << 24) | (b1 >> (64 - 24))) ^ b0; + + b3 += k11; + b2 += b3 + k10; + b3 = ((b3 << 13) | (b3 >> (64 - 13))) ^ b2; + + b5 += k13; + b4 += b5 + k12; + b5 = ((b5 << 8) | (b5 >> (64 - 8))) ^ b4; + + b7 += k15; + b6 += b7 + k14; + b7 = ((b7 << 47) | (b7 >> (64 - 47))) ^ b6; + + b9 += k0; + b8 += b9 + k16; + b9 = ((b9 << 8) | (b9 >> (64 - 8))) ^ b8; + + b11 += k2; + b10 += b11 + k1; + b11 = ((b11 << 17) | (b11 >> (64 - 17))) ^ b10; + + b13 += k4 + t2; + b12 += b13 + k3; + b13 = ((b13 << 22) | (b13 >> (64 - 22))) ^ b12; + + b15 += k6 + 8; + b14 += b15 + k5 + t0; + b15 = ((b15 << 37) | (b15 >> (64 - 37))) ^ b14; + + b0 += b9; + b9 = ((b9 << 38) | (b9 >> (64 - 38))) ^ b0; + + b2 += b13; + b13 = ((b13 << 19) | (b13 >> (64 - 19))) ^ b2; + + b6 += b11; + b11 = ((b11 << 10) | (b11 >> (64 - 10))) ^ b6; + + b4 += b15; + b15 = ((b15 << 55) | (b15 >> (64 - 55))) ^ b4; + + b10 += b7; + b7 = ((b7 << 49) | (b7 >> (64 - 49))) ^ b10; + + b12 += b3; + b3 = ((b3 << 18) | (b3 >> (64 - 18))) ^ b12; + + b14 += b5; + b5 = ((b5 << 23) | (b5 >> (64 - 23))) ^ b14; + + b8 += b1; + b1 = ((b1 << 52) | (b1 >> (64 - 52))) ^ b8; + + b0 += b7; + b7 = ((b7 << 33) | (b7 >> (64 - 33))) ^ b0; + + b2 += b5; + b5 = ((b5 << 4) | (b5 >> (64 - 4))) ^ b2; + + b4 += b3; + b3 = ((b3 << 51) | (b3 >> (64 - 51))) ^ b4; + + b6 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b6; + + b12 += b15; + b15 = ((b15 << 34) | (b15 >> (64 - 34))) ^ b12; + + b14 += b13; + b13 = ((b13 << 41) | (b13 >> (64 - 41))) ^ b14; + + b8 += b11; + b11 = ((b11 << 59) | (b11 >> (64 - 59))) ^ b8; + + b10 += b9; + b9 = ((b9 << 17) | (b9 >> (64 - 17))) ^ b10; + + b0 += b15; + b15 = ((b15 << 5) | (b15 >> (64 - 5))) ^ b0; + + b2 += b11; + b11 = ((b11 << 20) | (b11 >> (64 - 20))) ^ b2; + + b6 += b13; + b13 = ((b13 << 48) | (b13 >> (64 - 48))) ^ b6; + + b4 += b9; + b9 = ((b9 << 41) | (b9 >> (64 - 41))) ^ b4; + + b14 += b1; + b1 = ((b1 << 47) | (b1 >> (64 - 47))) ^ b14; + + b8 += b5; + b5 = ((b5 << 28) | (b5 >> (64 - 28))) ^ b8; + + b10 += b3; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b10; + + b12 += b7; + b7 = ((b7 << 25) | (b7 >> (64 - 25))) ^ b12; + + b1 += k10; + b0 += b1 + k9; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b0; + + b3 += k12; + b2 += b3 + k11; + b3 = ((b3 << 9) | (b3 >> (64 - 9))) ^ b2; + + b5 += k14; + b4 += b5 + k13; + b5 = ((b5 << 37) | (b5 >> (64 - 37))) ^ b4; + + b7 += k16; + b6 += b7 + k15; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b6; + + b9 += k1; + b8 += b9 + k0; + b9 = ((b9 << 12) | (b9 >> (64 - 12))) ^ b8; + + b11 += k3; + b10 += b11 + k2; + b11 = ((b11 << 47) | (b11 >> (64 - 47))) ^ b10; + + b13 += k5 + t0; + b12 += b13 + k4; + b13 = ((b13 << 44) | (b13 >> (64 - 44))) ^ b12; + + b15 += k7 + 9; + b14 += b15 + k6 + t1; + b15 = ((b15 << 30) | (b15 >> (64 - 30))) ^ b14; + + b0 += b9; + b9 = ((b9 << 16) | (b9 >> (64 - 16))) ^ b0; + + b2 += b13; + b13 = ((b13 << 34) | (b13 >> (64 - 34))) ^ b2; + + b6 += b11; + b11 = ((b11 << 56) | (b11 >> (64 - 56))) ^ b6; + + b4 += b15; + b15 = ((b15 << 51) | (b15 >> (64 - 51))) ^ b4; + + b10 += b7; + b7 = ((b7 << 4) | (b7 >> (64 - 4))) ^ b10; + + b12 += b3; + b3 = ((b3 << 53) | (b3 >> (64 - 53))) ^ b12; + + b14 += b5; + b5 = ((b5 << 42) | (b5 >> (64 - 42))) ^ b14; + + b8 += b1; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b8; + + b0 += b7; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b0; + + b2 += b5; + b5 = ((b5 << 44) | (b5 >> (64 - 44))) ^ b2; + + b4 += b3; + b3 = ((b3 << 47) | (b3 >> (64 - 47))) ^ b4; + + b6 += b1; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b6; + + b12 += b15; + b15 = ((b15 << 19) | (b15 >> (64 - 19))) ^ b12; + + b14 += b13; + b13 = ((b13 << 42) | (b13 >> (64 - 42))) ^ b14; + + b8 += b11; + b11 = ((b11 << 44) | (b11 >> (64 - 44))) ^ b8; + + b10 += b9; + b9 = ((b9 << 25) | (b9 >> (64 - 25))) ^ b10; + + b0 += b15; + b15 = ((b15 << 9) | (b15 >> (64 - 9))) ^ b0; + + b2 += b11; + b11 = ((b11 << 48) | (b11 >> (64 - 48))) ^ b2; + + b6 += b13; + b13 = ((b13 << 35) | (b13 >> (64 - 35))) ^ b6; + + b4 += b9; + b9 = ((b9 << 52) | (b9 >> (64 - 52))) ^ b4; + + b14 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b14; + + b8 += b5; + b5 = ((b5 << 31) | (b5 >> (64 - 31))) ^ b8; + + b10 += b3; + b3 = ((b3 << 37) | (b3 >> (64 - 37))) ^ b10; + + b12 += b7; + b7 = ((b7 << 20) | (b7 >> (64 - 20))) ^ b12; + + b1 += k11; + b0 += b1 + k10; + b1 = ((b1 << 24) | (b1 >> (64 - 24))) ^ b0; + + b3 += k13; + b2 += b3 + k12; + b3 = ((b3 << 13) | (b3 >> (64 - 13))) ^ b2; + + b5 += k15; + b4 += b5 + k14; + b5 = ((b5 << 8) | (b5 >> (64 - 8))) ^ b4; + + b7 += k0; + b6 += b7 + k16; + b7 = ((b7 << 47) | (b7 >> (64 - 47))) ^ b6; + + b9 += k2; + b8 += b9 + k1; + b9 = ((b9 << 8) | (b9 >> (64 - 8))) ^ b8; + + b11 += k4; + b10 += b11 + k3; + b11 = ((b11 << 17) | (b11 >> (64 - 17))) ^ b10; + + b13 += k6 + t1; + b12 += b13 + k5; + b13 = ((b13 << 22) | (b13 >> (64 - 22))) ^ b12; + + b15 += k8 + 10; + b14 += b15 + k7 + t2; + b15 = ((b15 << 37) | (b15 >> (64 - 37))) ^ b14; + + b0 += b9; + b9 = ((b9 << 38) | (b9 >> (64 - 38))) ^ b0; + + b2 += b13; + b13 = ((b13 << 19) | (b13 >> (64 - 19))) ^ b2; + + b6 += b11; + b11 = ((b11 << 10) | (b11 >> (64 - 10))) ^ b6; + + b4 += b15; + b15 = ((b15 << 55) | (b15 >> (64 - 55))) ^ b4; + + b10 += b7; + b7 = ((b7 << 49) | (b7 >> (64 - 49))) ^ b10; + + b12 += b3; + b3 = ((b3 << 18) | (b3 >> (64 - 18))) ^ b12; + + b14 += b5; + b5 = ((b5 << 23) | (b5 >> (64 - 23))) ^ b14; + + b8 += b1; + b1 = ((b1 << 52) | (b1 >> (64 - 52))) ^ b8; + + b0 += b7; + b7 = ((b7 << 33) | (b7 >> (64 - 33))) ^ b0; + + b2 += b5; + b5 = ((b5 << 4) | (b5 >> (64 - 4))) ^ b2; + + b4 += b3; + b3 = ((b3 << 51) | (b3 >> (64 - 51))) ^ b4; + + b6 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b6; + + b12 += b15; + b15 = ((b15 << 34) | (b15 >> (64 - 34))) ^ b12; + + b14 += b13; + b13 = ((b13 << 41) | (b13 >> (64 - 41))) ^ b14; + + b8 += b11; + b11 = ((b11 << 59) | (b11 >> (64 - 59))) ^ b8; + + b10 += b9; + b9 = ((b9 << 17) | (b9 >> (64 - 17))) ^ b10; + + b0 += b15; + b15 = ((b15 << 5) | (b15 >> (64 - 5))) ^ b0; + + b2 += b11; + b11 = ((b11 << 20) | (b11 >> (64 - 20))) ^ b2; + + b6 += b13; + b13 = ((b13 << 48) | (b13 >> (64 - 48))) ^ b6; + + b4 += b9; + b9 = ((b9 << 41) | (b9 >> (64 - 41))) ^ b4; + + b14 += b1; + b1 = ((b1 << 47) | (b1 >> (64 - 47))) ^ b14; + + b8 += b5; + b5 = ((b5 << 28) | (b5 >> (64 - 28))) ^ b8; + + b10 += b3; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b10; + + b12 += b7; + b7 = ((b7 << 25) | (b7 >> (64 - 25))) ^ b12; + + b1 += k12; + b0 += b1 + k11; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b0; + + b3 += k14; + b2 += b3 + k13; + b3 = ((b3 << 9) | (b3 >> (64 - 9))) ^ b2; + + b5 += k16; + b4 += b5 + k15; + b5 = ((b5 << 37) | (b5 >> (64 - 37))) ^ b4; + + b7 += k1; + b6 += b7 + k0; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b6; + + b9 += k3; + b8 += b9 + k2; + b9 = ((b9 << 12) | (b9 >> (64 - 12))) ^ b8; + + b11 += k5; + b10 += b11 + k4; + b11 = ((b11 << 47) | (b11 >> (64 - 47))) ^ b10; + + b13 += k7 + t2; + b12 += b13 + k6; + b13 = ((b13 << 44) | (b13 >> (64 - 44))) ^ b12; + + b15 += k9 + 11; + b14 += b15 + k8 + t0; + b15 = ((b15 << 30) | (b15 >> (64 - 30))) ^ b14; + + b0 += b9; + b9 = ((b9 << 16) | (b9 >> (64 - 16))) ^ b0; + + b2 += b13; + b13 = ((b13 << 34) | (b13 >> (64 - 34))) ^ b2; + + b6 += b11; + b11 = ((b11 << 56) | (b11 >> (64 - 56))) ^ b6; + + b4 += b15; + b15 = ((b15 << 51) | (b15 >> (64 - 51))) ^ b4; + + b10 += b7; + b7 = ((b7 << 4) | (b7 >> (64 - 4))) ^ b10; + + b12 += b3; + b3 = ((b3 << 53) | (b3 >> (64 - 53))) ^ b12; + + b14 += b5; + b5 = ((b5 << 42) | (b5 >> (64 - 42))) ^ b14; + + b8 += b1; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b8; + + b0 += b7; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b0; + + b2 += b5; + b5 = ((b5 << 44) | (b5 >> (64 - 44))) ^ b2; + + b4 += b3; + b3 = ((b3 << 47) | (b3 >> (64 - 47))) ^ b4; + + b6 += b1; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b6; + + b12 += b15; + b15 = ((b15 << 19) | (b15 >> (64 - 19))) ^ b12; + + b14 += b13; + b13 = ((b13 << 42) | (b13 >> (64 - 42))) ^ b14; + + b8 += b11; + b11 = ((b11 << 44) | (b11 >> (64 - 44))) ^ b8; + + b10 += b9; + b9 = ((b9 << 25) | (b9 >> (64 - 25))) ^ b10; + + b0 += b15; + b15 = ((b15 << 9) | (b15 >> (64 - 9))) ^ b0; + + b2 += b11; + b11 = ((b11 << 48) | (b11 >> (64 - 48))) ^ b2; + + b6 += b13; + b13 = ((b13 << 35) | (b13 >> (64 - 35))) ^ b6; + + b4 += b9; + b9 = ((b9 << 52) | (b9 >> (64 - 52))) ^ b4; + + b14 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b14; + + b8 += b5; + b5 = ((b5 << 31) | (b5 >> (64 - 31))) ^ b8; + + b10 += b3; + b3 = ((b3 << 37) | (b3 >> (64 - 37))) ^ b10; + + b12 += b7; + b7 = ((b7 << 20) | (b7 >> (64 - 20))) ^ b12; + + b1 += k13; + b0 += b1 + k12; + b1 = ((b1 << 24) | (b1 >> (64 - 24))) ^ b0; + + b3 += k15; + b2 += b3 + k14; + b3 = ((b3 << 13) | (b3 >> (64 - 13))) ^ b2; + + b5 += k0; + b4 += b5 + k16; + b5 = ((b5 << 8) | (b5 >> (64 - 8))) ^ b4; + + b7 += k2; + b6 += b7 + k1; + b7 = ((b7 << 47) | (b7 >> (64 - 47))) ^ b6; + + b9 += k4; + b8 += b9 + k3; + b9 = ((b9 << 8) | (b9 >> (64 - 8))) ^ b8; + + b11 += k6; + b10 += b11 + k5; + b11 = ((b11 << 17) | (b11 >> (64 - 17))) ^ b10; + + b13 += k8 + t0; + b12 += b13 + k7; + b13 = ((b13 << 22) | (b13 >> (64 - 22))) ^ b12; + + b15 += k10 + 12; + b14 += b15 + k9 + t1; + b15 = ((b15 << 37) | (b15 >> (64 - 37))) ^ b14; + + b0 += b9; + b9 = ((b9 << 38) | (b9 >> (64 - 38))) ^ b0; + + b2 += b13; + b13 = ((b13 << 19) | (b13 >> (64 - 19))) ^ b2; + + b6 += b11; + b11 = ((b11 << 10) | (b11 >> (64 - 10))) ^ b6; + + b4 += b15; + b15 = ((b15 << 55) | (b15 >> (64 - 55))) ^ b4; + + b10 += b7; + b7 = ((b7 << 49) | (b7 >> (64 - 49))) ^ b10; + + b12 += b3; + b3 = ((b3 << 18) | (b3 >> (64 - 18))) ^ b12; + + b14 += b5; + b5 = ((b5 << 23) | (b5 >> (64 - 23))) ^ b14; + + b8 += b1; + b1 = ((b1 << 52) | (b1 >> (64 - 52))) ^ b8; + + b0 += b7; + b7 = ((b7 << 33) | (b7 >> (64 - 33))) ^ b0; + + b2 += b5; + b5 = ((b5 << 4) | (b5 >> (64 - 4))) ^ b2; + + b4 += b3; + b3 = ((b3 << 51) | (b3 >> (64 - 51))) ^ b4; + + b6 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b6; + + b12 += b15; + b15 = ((b15 << 34) | (b15 >> (64 - 34))) ^ b12; + + b14 += b13; + b13 = ((b13 << 41) | (b13 >> (64 - 41))) ^ b14; + + b8 += b11; + b11 = ((b11 << 59) | (b11 >> (64 - 59))) ^ b8; + + b10 += b9; + b9 = ((b9 << 17) | (b9 >> (64 - 17))) ^ b10; + + b0 += b15; + b15 = ((b15 << 5) | (b15 >> (64 - 5))) ^ b0; + + b2 += b11; + b11 = ((b11 << 20) | (b11 >> (64 - 20))) ^ b2; + + b6 += b13; + b13 = ((b13 << 48) | (b13 >> (64 - 48))) ^ b6; + + b4 += b9; + b9 = ((b9 << 41) | (b9 >> (64 - 41))) ^ b4; + + b14 += b1; + b1 = ((b1 << 47) | (b1 >> (64 - 47))) ^ b14; + + b8 += b5; + b5 = ((b5 << 28) | (b5 >> (64 - 28))) ^ b8; + + b10 += b3; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b10; + + b12 += b7; + b7 = ((b7 << 25) | (b7 >> (64 - 25))) ^ b12; + + b1 += k14; + b0 += b1 + k13; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b0; + + b3 += k16; + b2 += b3 + k15; + b3 = ((b3 << 9) | (b3 >> (64 - 9))) ^ b2; + + b5 += k1; + b4 += b5 + k0; + b5 = ((b5 << 37) | (b5 >> (64 - 37))) ^ b4; + + b7 += k3; + b6 += b7 + k2; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b6; + + b9 += k5; + b8 += b9 + k4; + b9 = ((b9 << 12) | (b9 >> (64 - 12))) ^ b8; + + b11 += k7; + b10 += b11 + k6; + b11 = ((b11 << 47) | (b11 >> (64 - 47))) ^ b10; + + b13 += k9 + t1; + b12 += b13 + k8; + b13 = ((b13 << 44) | (b13 >> (64 - 44))) ^ b12; + + b15 += k11 + 13; + b14 += b15 + k10 + t2; + b15 = ((b15 << 30) | (b15 >> (64 - 30))) ^ b14; + + b0 += b9; + b9 = ((b9 << 16) | (b9 >> (64 - 16))) ^ b0; + + b2 += b13; + b13 = ((b13 << 34) | (b13 >> (64 - 34))) ^ b2; + + b6 += b11; + b11 = ((b11 << 56) | (b11 >> (64 - 56))) ^ b6; + + b4 += b15; + b15 = ((b15 << 51) | (b15 >> (64 - 51))) ^ b4; + + b10 += b7; + b7 = ((b7 << 4) | (b7 >> (64 - 4))) ^ b10; + + b12 += b3; + b3 = ((b3 << 53) | (b3 >> (64 - 53))) ^ b12; + + b14 += b5; + b5 = ((b5 << 42) | (b5 >> (64 - 42))) ^ b14; + + b8 += b1; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b8; + + b0 += b7; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b0; + + b2 += b5; + b5 = ((b5 << 44) | (b5 >> (64 - 44))) ^ b2; + + b4 += b3; + b3 = ((b3 << 47) | (b3 >> (64 - 47))) ^ b4; + + b6 += b1; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b6; + + b12 += b15; + b15 = ((b15 << 19) | (b15 >> (64 - 19))) ^ b12; + + b14 += b13; + b13 = ((b13 << 42) | (b13 >> (64 - 42))) ^ b14; + + b8 += b11; + b11 = ((b11 << 44) | (b11 >> (64 - 44))) ^ b8; + + b10 += b9; + b9 = ((b9 << 25) | (b9 >> (64 - 25))) ^ b10; + + b0 += b15; + b15 = ((b15 << 9) | (b15 >> (64 - 9))) ^ b0; + + b2 += b11; + b11 = ((b11 << 48) | (b11 >> (64 - 48))) ^ b2; + + b6 += b13; + b13 = ((b13 << 35) | (b13 >> (64 - 35))) ^ b6; + + b4 += b9; + b9 = ((b9 << 52) | (b9 >> (64 - 52))) ^ b4; + + b14 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b14; + + b8 += b5; + b5 = ((b5 << 31) | (b5 >> (64 - 31))) ^ b8; + + b10 += b3; + b3 = ((b3 << 37) | (b3 >> (64 - 37))) ^ b10; + + b12 += b7; + b7 = ((b7 << 20) | (b7 >> (64 - 20))) ^ b12; + + b1 += k15; + b0 += b1 + k14; + b1 = ((b1 << 24) | (b1 >> (64 - 24))) ^ b0; + + b3 += k0; + b2 += b3 + k16; + b3 = ((b3 << 13) | (b3 >> (64 - 13))) ^ b2; + + b5 += k2; + b4 += b5 + k1; + b5 = ((b5 << 8) | (b5 >> (64 - 8))) ^ b4; + + b7 += k4; + b6 += b7 + k3; + b7 = ((b7 << 47) | (b7 >> (64 - 47))) ^ b6; + + b9 += k6; + b8 += b9 + k5; + b9 = ((b9 << 8) | (b9 >> (64 - 8))) ^ b8; + + b11 += k8; + b10 += b11 + k7; + b11 = ((b11 << 17) | (b11 >> (64 - 17))) ^ b10; + + b13 += k10 + t2; + b12 += b13 + k9; + b13 = ((b13 << 22) | (b13 >> (64 - 22))) ^ b12; + + b15 += k12 + 14; + b14 += b15 + k11 + t0; + b15 = ((b15 << 37) | (b15 >> (64 - 37))) ^ b14; + + b0 += b9; + b9 = ((b9 << 38) | (b9 >> (64 - 38))) ^ b0; + + b2 += b13; + b13 = ((b13 << 19) | (b13 >> (64 - 19))) ^ b2; + + b6 += b11; + b11 = ((b11 << 10) | (b11 >> (64 - 10))) ^ b6; + + b4 += b15; + b15 = ((b15 << 55) | (b15 >> (64 - 55))) ^ b4; + + b10 += b7; + b7 = ((b7 << 49) | (b7 >> (64 - 49))) ^ b10; + + b12 += b3; + b3 = ((b3 << 18) | (b3 >> (64 - 18))) ^ b12; + + b14 += b5; + b5 = ((b5 << 23) | (b5 >> (64 - 23))) ^ b14; + + b8 += b1; + b1 = ((b1 << 52) | (b1 >> (64 - 52))) ^ b8; + + b0 += b7; + b7 = ((b7 << 33) | (b7 >> (64 - 33))) ^ b0; + + b2 += b5; + b5 = ((b5 << 4) | (b5 >> (64 - 4))) ^ b2; + + b4 += b3; + b3 = ((b3 << 51) | (b3 >> (64 - 51))) ^ b4; + + b6 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b6; + + b12 += b15; + b15 = ((b15 << 34) | (b15 >> (64 - 34))) ^ b12; + + b14 += b13; + b13 = ((b13 << 41) | (b13 >> (64 - 41))) ^ b14; + + b8 += b11; + b11 = ((b11 << 59) | (b11 >> (64 - 59))) ^ b8; + + b10 += b9; + b9 = ((b9 << 17) | (b9 >> (64 - 17))) ^ b10; + + b0 += b15; + b15 = ((b15 << 5) | (b15 >> (64 - 5))) ^ b0; + + b2 += b11; + b11 = ((b11 << 20) | (b11 >> (64 - 20))) ^ b2; + + b6 += b13; + b13 = ((b13 << 48) | (b13 >> (64 - 48))) ^ b6; + + b4 += b9; + b9 = ((b9 << 41) | (b9 >> (64 - 41))) ^ b4; + + b14 += b1; + b1 = ((b1 << 47) | (b1 >> (64 - 47))) ^ b14; + + b8 += b5; + b5 = ((b5 << 28) | (b5 >> (64 - 28))) ^ b8; + + b10 += b3; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b10; + + b12 += b7; + b7 = ((b7 << 25) | (b7 >> (64 - 25))) ^ b12; + + b1 += k16; + b0 += b1 + k15; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b0; + + b3 += k1; + b2 += b3 + k0; + b3 = ((b3 << 9) | (b3 >> (64 - 9))) ^ b2; + + b5 += k3; + b4 += b5 + k2; + b5 = ((b5 << 37) | (b5 >> (64 - 37))) ^ b4; + + b7 += k5; + b6 += b7 + k4; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b6; + + b9 += k7; + b8 += b9 + k6; + b9 = ((b9 << 12) | (b9 >> (64 - 12))) ^ b8; + + b11 += k9; + b10 += b11 + k8; + b11 = ((b11 << 47) | (b11 >> (64 - 47))) ^ b10; + + b13 += k11 + t0; + b12 += b13 + k10; + b13 = ((b13 << 44) | (b13 >> (64 - 44))) ^ b12; + + b15 += k13 + 15; + b14 += b15 + k12 + t1; + b15 = ((b15 << 30) | (b15 >> (64 - 30))) ^ b14; + + b0 += b9; + b9 = ((b9 << 16) | (b9 >> (64 - 16))) ^ b0; + + b2 += b13; + b13 = ((b13 << 34) | (b13 >> (64 - 34))) ^ b2; + + b6 += b11; + b11 = ((b11 << 56) | (b11 >> (64 - 56))) ^ b6; + + b4 += b15; + b15 = ((b15 << 51) | (b15 >> (64 - 51))) ^ b4; + + b10 += b7; + b7 = ((b7 << 4) | (b7 >> (64 - 4))) ^ b10; + + b12 += b3; + b3 = ((b3 << 53) | (b3 >> (64 - 53))) ^ b12; + + b14 += b5; + b5 = ((b5 << 42) | (b5 >> (64 - 42))) ^ b14; + + b8 += b1; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b8; + + b0 += b7; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b0; + + b2 += b5; + b5 = ((b5 << 44) | (b5 >> (64 - 44))) ^ b2; + + b4 += b3; + b3 = ((b3 << 47) | (b3 >> (64 - 47))) ^ b4; + + b6 += b1; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b6; + + b12 += b15; + b15 = ((b15 << 19) | (b15 >> (64 - 19))) ^ b12; + + b14 += b13; + b13 = ((b13 << 42) | (b13 >> (64 - 42))) ^ b14; + + b8 += b11; + b11 = ((b11 << 44) | (b11 >> (64 - 44))) ^ b8; + + b10 += b9; + b9 = ((b9 << 25) | (b9 >> (64 - 25))) ^ b10; + + b0 += b15; + b15 = ((b15 << 9) | (b15 >> (64 - 9))) ^ b0; + + b2 += b11; + b11 = ((b11 << 48) | (b11 >> (64 - 48))) ^ b2; + + b6 += b13; + b13 = ((b13 << 35) | (b13 >> (64 - 35))) ^ b6; + + b4 += b9; + b9 = ((b9 << 52) | (b9 >> (64 - 52))) ^ b4; + + b14 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b14; + + b8 += b5; + b5 = ((b5 << 31) | (b5 >> (64 - 31))) ^ b8; + + b10 += b3; + b3 = ((b3 << 37) | (b3 >> (64 - 37))) ^ b10; + + b12 += b7; + b7 = ((b7 << 20) | (b7 >> (64 - 20))) ^ b12; + + b1 += k0; + b0 += b1 + k16; + b1 = ((b1 << 24) | (b1 >> (64 - 24))) ^ b0; + + b3 += k2; + b2 += b3 + k1; + b3 = ((b3 << 13) | (b3 >> (64 - 13))) ^ b2; + + b5 += k4; + b4 += b5 + k3; + b5 = ((b5 << 8) | (b5 >> (64 - 8))) ^ b4; + + b7 += k6; + b6 += b7 + k5; + b7 = ((b7 << 47) | (b7 >> (64 - 47))) ^ b6; + + b9 += k8; + b8 += b9 + k7; + b9 = ((b9 << 8) | (b9 >> (64 - 8))) ^ b8; + + b11 += k10; + b10 += b11 + k9; + b11 = ((b11 << 17) | (b11 >> (64 - 17))) ^ b10; + + b13 += k12 + t1; + b12 += b13 + k11; + b13 = ((b13 << 22) | (b13 >> (64 - 22))) ^ b12; + + b15 += k14 + 16; + b14 += b15 + k13 + t2; + b15 = ((b15 << 37) | (b15 >> (64 - 37))) ^ b14; + + b0 += b9; + b9 = ((b9 << 38) | (b9 >> (64 - 38))) ^ b0; + + b2 += b13; + b13 = ((b13 << 19) | (b13 >> (64 - 19))) ^ b2; + + b6 += b11; + b11 = ((b11 << 10) | (b11 >> (64 - 10))) ^ b6; + + b4 += b15; + b15 = ((b15 << 55) | (b15 >> (64 - 55))) ^ b4; + + b10 += b7; + b7 = ((b7 << 49) | (b7 >> (64 - 49))) ^ b10; + + b12 += b3; + b3 = ((b3 << 18) | (b3 >> (64 - 18))) ^ b12; + + b14 += b5; + b5 = ((b5 << 23) | (b5 >> (64 - 23))) ^ b14; + + b8 += b1; + b1 = ((b1 << 52) | (b1 >> (64 - 52))) ^ b8; + + b0 += b7; + b7 = ((b7 << 33) | (b7 >> (64 - 33))) ^ b0; + + b2 += b5; + b5 = ((b5 << 4) | (b5 >> (64 - 4))) ^ b2; + + b4 += b3; + b3 = ((b3 << 51) | (b3 >> (64 - 51))) ^ b4; + + b6 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b6; + + b12 += b15; + b15 = ((b15 << 34) | (b15 >> (64 - 34))) ^ b12; + + b14 += b13; + b13 = ((b13 << 41) | (b13 >> (64 - 41))) ^ b14; + + b8 += b11; + b11 = ((b11 << 59) | (b11 >> (64 - 59))) ^ b8; + + b10 += b9; + b9 = ((b9 << 17) | (b9 >> (64 - 17))) ^ b10; + + b0 += b15; + b15 = ((b15 << 5) | (b15 >> (64 - 5))) ^ b0; + + b2 += b11; + b11 = ((b11 << 20) | (b11 >> (64 - 20))) ^ b2; + + b6 += b13; + b13 = ((b13 << 48) | (b13 >> (64 - 48))) ^ b6; + + b4 += b9; + b9 = ((b9 << 41) | (b9 >> (64 - 41))) ^ b4; + + b14 += b1; + b1 = ((b1 << 47) | (b1 >> (64 - 47))) ^ b14; + + b8 += b5; + b5 = ((b5 << 28) | (b5 >> (64 - 28))) ^ b8; + + b10 += b3; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b10; + + b12 += b7; + b7 = ((b7 << 25) | (b7 >> (64 - 25))) ^ b12; + + b1 += k1; + b0 += b1 + k0; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b0; + + b3 += k3; + b2 += b3 + k2; + b3 = ((b3 << 9) | (b3 >> (64 - 9))) ^ b2; + + b5 += k5; + b4 += b5 + k4; + b5 = ((b5 << 37) | (b5 >> (64 - 37))) ^ b4; + + b7 += k7; + b6 += b7 + k6; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b6; + + b9 += k9; + b8 += b9 + k8; + b9 = ((b9 << 12) | (b9 >> (64 - 12))) ^ b8; + + b11 += k11; + b10 += b11 + k10; + b11 = ((b11 << 47) | (b11 >> (64 - 47))) ^ b10; + + b13 += k13 + t2; + b12 += b13 + k12; + b13 = ((b13 << 44) | (b13 >> (64 - 44))) ^ b12; + + b15 += k15 + 17; + b14 += b15 + k14 + t0; + b15 = ((b15 << 30) | (b15 >> (64 - 30))) ^ b14; + + b0 += b9; + b9 = ((b9 << 16) | (b9 >> (64 - 16))) ^ b0; + + b2 += b13; + b13 = ((b13 << 34) | (b13 >> (64 - 34))) ^ b2; + + b6 += b11; + b11 = ((b11 << 56) | (b11 >> (64 - 56))) ^ b6; + + b4 += b15; + b15 = ((b15 << 51) | (b15 >> (64 - 51))) ^ b4; + + b10 += b7; + b7 = ((b7 << 4) | (b7 >> (64 - 4))) ^ b10; + + b12 += b3; + b3 = ((b3 << 53) | (b3 >> (64 - 53))) ^ b12; + + b14 += b5; + b5 = ((b5 << 42) | (b5 >> (64 - 42))) ^ b14; + + b8 += b1; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b8; + + b0 += b7; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b0; + + b2 += b5; + b5 = ((b5 << 44) | (b5 >> (64 - 44))) ^ b2; + + b4 += b3; + b3 = ((b3 << 47) | (b3 >> (64 - 47))) ^ b4; + + b6 += b1; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b6; + + b12 += b15; + b15 = ((b15 << 19) | (b15 >> (64 - 19))) ^ b12; + + b14 += b13; + b13 = ((b13 << 42) | (b13 >> (64 - 42))) ^ b14; + + b8 += b11; + b11 = ((b11 << 44) | (b11 >> (64 - 44))) ^ b8; + + b10 += b9; + b9 = ((b9 << 25) | (b9 >> (64 - 25))) ^ b10; + + b0 += b15; + b15 = ((b15 << 9) | (b15 >> (64 - 9))) ^ b0; + + b2 += b11; + b11 = ((b11 << 48) | (b11 >> (64 - 48))) ^ b2; + + b6 += b13; + b13 = ((b13 << 35) | (b13 >> (64 - 35))) ^ b6; + + b4 += b9; + b9 = ((b9 << 52) | (b9 >> (64 - 52))) ^ b4; + + b14 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b14; + + b8 += b5; + b5 = ((b5 << 31) | (b5 >> (64 - 31))) ^ b8; + + b10 += b3; + b3 = ((b3 << 37) | (b3 >> (64 - 37))) ^ b10; + + b12 += b7; + b7 = ((b7 << 20) | (b7 >> (64 - 20))) ^ b12; + + b1 += k2; + b0 += b1 + k1; + b1 = ((b1 << 24) | (b1 >> (64 - 24))) ^ b0; + + b3 += k4; + b2 += b3 + k3; + b3 = ((b3 << 13) | (b3 >> (64 - 13))) ^ b2; + + b5 += k6; + b4 += b5 + k5; + b5 = ((b5 << 8) | (b5 >> (64 - 8))) ^ b4; + + b7 += k8; + b6 += b7 + k7; + b7 = ((b7 << 47) | (b7 >> (64 - 47))) ^ b6; + + b9 += k10; + b8 += b9 + k9; + b9 = ((b9 << 8) | (b9 >> (64 - 8))) ^ b8; + + b11 += k12; + b10 += b11 + k11; + b11 = ((b11 << 17) | (b11 >> (64 - 17))) ^ b10; + + b13 += k14 + t0; + b12 += b13 + k13; + b13 = ((b13 << 22) | (b13 >> (64 - 22))) ^ b12; + + b15 += k16 + 18; + b14 += b15 + k15 + t1; + b15 = ((b15 << 37) | (b15 >> (64 - 37))) ^ b14; + + b0 += b9; + b9 = ((b9 << 38) | (b9 >> (64 - 38))) ^ b0; + + b2 += b13; + b13 = ((b13 << 19) | (b13 >> (64 - 19))) ^ b2; + + b6 += b11; + b11 = ((b11 << 10) | (b11 >> (64 - 10))) ^ b6; + + b4 += b15; + b15 = ((b15 << 55) | (b15 >> (64 - 55))) ^ b4; + + b10 += b7; + b7 = ((b7 << 49) | (b7 >> (64 - 49))) ^ b10; + + b12 += b3; + b3 = ((b3 << 18) | (b3 >> (64 - 18))) ^ b12; + + b14 += b5; + b5 = ((b5 << 23) | (b5 >> (64 - 23))) ^ b14; + + b8 += b1; + b1 = ((b1 << 52) | (b1 >> (64 - 52))) ^ b8; + + b0 += b7; + b7 = ((b7 << 33) | (b7 >> (64 - 33))) ^ b0; + + b2 += b5; + b5 = ((b5 << 4) | (b5 >> (64 - 4))) ^ b2; + + b4 += b3; + b3 = ((b3 << 51) | (b3 >> (64 - 51))) ^ b4; + + b6 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b6; + + b12 += b15; + b15 = ((b15 << 34) | (b15 >> (64 - 34))) ^ b12; + + b14 += b13; + b13 = ((b13 << 41) | (b13 >> (64 - 41))) ^ b14; + + b8 += b11; + b11 = ((b11 << 59) | (b11 >> (64 - 59))) ^ b8; + + b10 += b9; + b9 = ((b9 << 17) | (b9 >> (64 - 17))) ^ b10; + + b0 += b15; + b15 = ((b15 << 5) | (b15 >> (64 - 5))) ^ b0; + + b2 += b11; + b11 = ((b11 << 20) | (b11 >> (64 - 20))) ^ b2; + + b6 += b13; + b13 = ((b13 << 48) | (b13 >> (64 - 48))) ^ b6; + + b4 += b9; + b9 = ((b9 << 41) | (b9 >> (64 - 41))) ^ b4; + + b14 += b1; + b1 = ((b1 << 47) | (b1 >> (64 - 47))) ^ b14; + + b8 += b5; + b5 = ((b5 << 28) | (b5 >> (64 - 28))) ^ b8; + + b10 += b3; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b10; + + b12 += b7; + b7 = ((b7 << 25) | (b7 >> (64 - 25))) ^ b12; + + b1 += k3; + b0 += b1 + k2; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b0; + + b3 += k5; + b2 += b3 + k4; + b3 = ((b3 << 9) | (b3 >> (64 - 9))) ^ b2; + + b5 += k7; + b4 += b5 + k6; + b5 = ((b5 << 37) | (b5 >> (64 - 37))) ^ b4; + + b7 += k9; + b6 += b7 + k8; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b6; + + b9 += k11; + b8 += b9 + k10; + b9 = ((b9 << 12) | (b9 >> (64 - 12))) ^ b8; + + b11 += k13; + b10 += b11 + k12; + b11 = ((b11 << 47) | (b11 >> (64 - 47))) ^ b10; + + b13 += k15 + t1; + b12 += b13 + k14; + b13 = ((b13 << 44) | (b13 >> (64 - 44))) ^ b12; + + b15 += k0 + 19; + b14 += b15 + k16 + t2; + b15 = ((b15 << 30) | (b15 >> (64 - 30))) ^ b14; + + b0 += b9; + b9 = ((b9 << 16) | (b9 >> (64 - 16))) ^ b0; + + b2 += b13; + b13 = ((b13 << 34) | (b13 >> (64 - 34))) ^ b2; + + b6 += b11; + b11 = ((b11 << 56) | (b11 >> (64 - 56))) ^ b6; + + b4 += b15; + b15 = ((b15 << 51) | (b15 >> (64 - 51))) ^ b4; + + b10 += b7; + b7 = ((b7 << 4) | (b7 >> (64 - 4))) ^ b10; + + b12 += b3; + b3 = ((b3 << 53) | (b3 >> (64 - 53))) ^ b12; + + b14 += b5; + b5 = ((b5 << 42) | (b5 >> (64 - 42))) ^ b14; + + b8 += b1; + b1 = ((b1 << 41) | (b1 >> (64 - 41))) ^ b8; + + b0 += b7; + b7 = ((b7 << 31) | (b7 >> (64 - 31))) ^ b0; + + b2 += b5; + b5 = ((b5 << 44) | (b5 >> (64 - 44))) ^ b2; + + b4 += b3; + b3 = ((b3 << 47) | (b3 >> (64 - 47))) ^ b4; + + b6 += b1; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b6; + + b12 += b15; + b15 = ((b15 << 19) | (b15 >> (64 - 19))) ^ b12; + + b14 += b13; + b13 = ((b13 << 42) | (b13 >> (64 - 42))) ^ b14; + + b8 += b11; + b11 = ((b11 << 44) | (b11 >> (64 - 44))) ^ b8; + + b10 += b9; + b9 = ((b9 << 25) | (b9 >> (64 - 25))) ^ b10; + + b0 += b15; + b15 = ((b15 << 9) | (b15 >> (64 - 9))) ^ b0; + + b2 += b11; + b11 = ((b11 << 48) | (b11 >> (64 - 48))) ^ b2; + + b6 += b13; + b13 = ((b13 << 35) | (b13 >> (64 - 35))) ^ b6; + + b4 += b9; + b9 = ((b9 << 52) | (b9 >> (64 - 52))) ^ b4; + + b14 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b14; + + b8 += b5; + b5 = ((b5 << 31) | (b5 >> (64 - 31))) ^ b8; + + b10 += b3; + b3 = ((b3 << 37) | (b3 >> (64 - 37))) ^ b10; + + b12 += b7; + b7 = ((b7 << 20) | (b7 >> (64 - 20))) ^ b12; + + output[0] = b0 + k3; + output[1] = b1 + k4; + output[2] = b2 + k5; + output[3] = b3 + k6; + output[4] = b4 + k7; + output[5] = b5 + k8; + output[6] = b6 + k9; + output[7] = b7 + k10; + output[8] = b8 + k11; + output[9] = b9 + k12; + output[10] = b10 + k13; + output[11] = b11 + k14; + output[12] = b12 + k15; + output[13] = b13 + k16 + t2; + output[14] = b14 + k0 + t0; + output[15] = b15 + k1 + 20; +} + +void threefishDecrypt1024(struct threefish_key *keyCtx, u64 *input, u64 *output) +{ + u64 b0 = input[0], b1 = input[1], + b2 = input[2], b3 = input[3], + b4 = input[4], b5 = input[5], + b6 = input[6], b7 = input[7], + b8 = input[8], b9 = input[9], + b10 = input[10], b11 = input[11], + b12 = input[12], b13 = input[13], + b14 = input[14], b15 = input[15]; + u64 k0 = keyCtx->key[0], k1 = keyCtx->key[1], + k2 = keyCtx->key[2], k3 = keyCtx->key[3], + k4 = keyCtx->key[4], k5 = keyCtx->key[5], + k6 = keyCtx->key[6], k7 = keyCtx->key[7], + k8 = keyCtx->key[8], k9 = keyCtx->key[9], + k10 = keyCtx->key[10], k11 = keyCtx->key[11], + k12 = keyCtx->key[12], k13 = keyCtx->key[13], + k14 = keyCtx->key[14], k15 = keyCtx->key[15], + k16 = keyCtx->key[16]; + u64 t0 = keyCtx->tweak[0], t1 = keyCtx->tweak[1], + t2 = keyCtx->tweak[2]; + u64 tmp; + + b0 -= k3; + b1 -= k4; + b2 -= k5; + b3 -= k6; + b4 -= k7; + b5 -= k8; + b6 -= k9; + b7 -= k10; + b8 -= k11; + b9 -= k12; + b10 -= k13; + b11 -= k14; + b12 -= k15; + b13 -= k16 + t2; + b14 -= k0 + t0; + b15 -= k1 + 20; + tmp = b7 ^ b12; + b7 = (tmp >> 20) | (tmp << (64 - 20)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 37) | (tmp << (64 - 37)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 31) | (tmp << (64 - 31)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 52) | (tmp << (64 - 52)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 35) | (tmp << (64 - 35)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 48) | (tmp << (64 - 48)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 25) | (tmp << (64 - 25)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 44) | (tmp << (64 - 44)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 19) | (tmp << (64 - 19)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 47) | (tmp << (64 - 47)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 44) | (tmp << (64 - 44)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 53) | (tmp << (64 - 53)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 4) | (tmp << (64 - 4)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 56) | (tmp << (64 - 56)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 34) | (tmp << (64 - 34)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 16) | (tmp << (64 - 16)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 30) | (tmp << (64 - 30)); + b14 -= b15 + k16 + t2; + b15 -= k0 + 19; + + tmp = b13 ^ b12; + b13 = (tmp >> 44) | (tmp << (64 - 44)); + b12 -= b13 + k14; + b13 -= k15 + t1; + + tmp = b11 ^ b10; + b11 = (tmp >> 47) | (tmp << (64 - 47)); + b10 -= b11 + k12; + b11 -= k13; + + tmp = b9 ^ b8; + b9 = (tmp >> 12) | (tmp << (64 - 12)); + b8 -= b9 + k10; + b9 -= k11; + + tmp = b7 ^ b6; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b6 -= b7 + k8; + b7 -= k9; + + tmp = b5 ^ b4; + b5 = (tmp >> 37) | (tmp << (64 - 37)); + b4 -= b5 + k6; + b5 -= k7; + + tmp = b3 ^ b2; + b3 = (tmp >> 9) | (tmp << (64 - 9)); + b2 -= b3 + k4; + b3 -= k5; + + tmp = b1 ^ b0; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b0 -= b1 + k2; + b1 -= k3; + + tmp = b7 ^ b12; + b7 = (tmp >> 25) | (tmp << (64 - 25)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 28) | (tmp << (64 - 28)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 47) | (tmp << (64 - 47)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 41) | (tmp << (64 - 41)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 48) | (tmp << (64 - 48)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 20) | (tmp << (64 - 20)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 59) | (tmp << (64 - 59)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 41) | (tmp << (64 - 41)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 34) | (tmp << (64 - 34)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 4) | (tmp << (64 - 4)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 33) | (tmp << (64 - 33)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 52) | (tmp << (64 - 52)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 18) | (tmp << (64 - 18)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 49) | (tmp << (64 - 49)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 55) | (tmp << (64 - 55)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 19) | (tmp << (64 - 19)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 38) | (tmp << (64 - 38)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 37) | (tmp << (64 - 37)); + b14 -= b15 + k15 + t1; + b15 -= k16 + 18; + + tmp = b13 ^ b12; + b13 = (tmp >> 22) | (tmp << (64 - 22)); + b12 -= b13 + k13; + b13 -= k14 + t0; + + tmp = b11 ^ b10; + b11 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b11 + k11; + b11 -= k12; + + tmp = b9 ^ b8; + b9 = (tmp >> 8) | (tmp << (64 - 8)); + b8 -= b9 + k9; + b9 -= k10; + + tmp = b7 ^ b6; + b7 = (tmp >> 47) | (tmp << (64 - 47)); + b6 -= b7 + k7; + b7 -= k8; + + tmp = b5 ^ b4; + b5 = (tmp >> 8) | (tmp << (64 - 8)); + b4 -= b5 + k5; + b5 -= k6; + + tmp = b3 ^ b2; + b3 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b3 + k3; + b3 -= k4; + + tmp = b1 ^ b0; + b1 = (tmp >> 24) | (tmp << (64 - 24)); + b0 -= b1 + k1; + b1 -= k2; + + tmp = b7 ^ b12; + b7 = (tmp >> 20) | (tmp << (64 - 20)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 37) | (tmp << (64 - 37)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 31) | (tmp << (64 - 31)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 52) | (tmp << (64 - 52)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 35) | (tmp << (64 - 35)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 48) | (tmp << (64 - 48)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 25) | (tmp << (64 - 25)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 44) | (tmp << (64 - 44)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 19) | (tmp << (64 - 19)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 47) | (tmp << (64 - 47)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 44) | (tmp << (64 - 44)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 53) | (tmp << (64 - 53)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 4) | (tmp << (64 - 4)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 56) | (tmp << (64 - 56)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 34) | (tmp << (64 - 34)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 16) | (tmp << (64 - 16)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 30) | (tmp << (64 - 30)); + b14 -= b15 + k14 + t0; + b15 -= k15 + 17; + + tmp = b13 ^ b12; + b13 = (tmp >> 44) | (tmp << (64 - 44)); + b12 -= b13 + k12; + b13 -= k13 + t2; + + tmp = b11 ^ b10; + b11 = (tmp >> 47) | (tmp << (64 - 47)); + b10 -= b11 + k10; + b11 -= k11; + + tmp = b9 ^ b8; + b9 = (tmp >> 12) | (tmp << (64 - 12)); + b8 -= b9 + k8; + b9 -= k9; + + tmp = b7 ^ b6; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b6 -= b7 + k6; + b7 -= k7; + + tmp = b5 ^ b4; + b5 = (tmp >> 37) | (tmp << (64 - 37)); + b4 -= b5 + k4; + b5 -= k5; + + tmp = b3 ^ b2; + b3 = (tmp >> 9) | (tmp << (64 - 9)); + b2 -= b3 + k2; + b3 -= k3; + + tmp = b1 ^ b0; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b0 -= b1 + k0; + b1 -= k1; + + tmp = b7 ^ b12; + b7 = (tmp >> 25) | (tmp << (64 - 25)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 28) | (tmp << (64 - 28)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 47) | (tmp << (64 - 47)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 41) | (tmp << (64 - 41)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 48) | (tmp << (64 - 48)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 20) | (tmp << (64 - 20)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 59) | (tmp << (64 - 59)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 41) | (tmp << (64 - 41)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 34) | (tmp << (64 - 34)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 4) | (tmp << (64 - 4)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 33) | (tmp << (64 - 33)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 52) | (tmp << (64 - 52)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 18) | (tmp << (64 - 18)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 49) | (tmp << (64 - 49)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 55) | (tmp << (64 - 55)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 19) | (tmp << (64 - 19)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 38) | (tmp << (64 - 38)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 37) | (tmp << (64 - 37)); + b14 -= b15 + k13 + t2; + b15 -= k14 + 16; + + tmp = b13 ^ b12; + b13 = (tmp >> 22) | (tmp << (64 - 22)); + b12 -= b13 + k11; + b13 -= k12 + t1; + + tmp = b11 ^ b10; + b11 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b11 + k9; + b11 -= k10; + + tmp = b9 ^ b8; + b9 = (tmp >> 8) | (tmp << (64 - 8)); + b8 -= b9 + k7; + b9 -= k8; + + tmp = b7 ^ b6; + b7 = (tmp >> 47) | (tmp << (64 - 47)); + b6 -= b7 + k5; + b7 -= k6; + + tmp = b5 ^ b4; + b5 = (tmp >> 8) | (tmp << (64 - 8)); + b4 -= b5 + k3; + b5 -= k4; + + tmp = b3 ^ b2; + b3 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b3 + k1; + b3 -= k2; + + tmp = b1 ^ b0; + b1 = (tmp >> 24) | (tmp << (64 - 24)); + b0 -= b1 + k16; + b1 -= k0; + + tmp = b7 ^ b12; + b7 = (tmp >> 20) | (tmp << (64 - 20)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 37) | (tmp << (64 - 37)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 31) | (tmp << (64 - 31)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 52) | (tmp << (64 - 52)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 35) | (tmp << (64 - 35)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 48) | (tmp << (64 - 48)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 25) | (tmp << (64 - 25)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 44) | (tmp << (64 - 44)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 19) | (tmp << (64 - 19)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 47) | (tmp << (64 - 47)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 44) | (tmp << (64 - 44)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 53) | (tmp << (64 - 53)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 4) | (tmp << (64 - 4)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 56) | (tmp << (64 - 56)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 34) | (tmp << (64 - 34)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 16) | (tmp << (64 - 16)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 30) | (tmp << (64 - 30)); + b14 -= b15 + k12 + t1; + b15 -= k13 + 15; + + tmp = b13 ^ b12; + b13 = (tmp >> 44) | (tmp << (64 - 44)); + b12 -= b13 + k10; + b13 -= k11 + t0; + + tmp = b11 ^ b10; + b11 = (tmp >> 47) | (tmp << (64 - 47)); + b10 -= b11 + k8; + b11 -= k9; + + tmp = b9 ^ b8; + b9 = (tmp >> 12) | (tmp << (64 - 12)); + b8 -= b9 + k6; + b9 -= k7; + + tmp = b7 ^ b6; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b6 -= b7 + k4; + b7 -= k5; + + tmp = b5 ^ b4; + b5 = (tmp >> 37) | (tmp << (64 - 37)); + b4 -= b5 + k2; + b5 -= k3; + + tmp = b3 ^ b2; + b3 = (tmp >> 9) | (tmp << (64 - 9)); + b2 -= b3 + k0; + b3 -= k1; + + tmp = b1 ^ b0; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b0 -= b1 + k15; + b1 -= k16; + + tmp = b7 ^ b12; + b7 = (tmp >> 25) | (tmp << (64 - 25)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 28) | (tmp << (64 - 28)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 47) | (tmp << (64 - 47)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 41) | (tmp << (64 - 41)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 48) | (tmp << (64 - 48)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 20) | (tmp << (64 - 20)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 59) | (tmp << (64 - 59)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 41) | (tmp << (64 - 41)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 34) | (tmp << (64 - 34)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 4) | (tmp << (64 - 4)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 33) | (tmp << (64 - 33)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 52) | (tmp << (64 - 52)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 18) | (tmp << (64 - 18)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 49) | (tmp << (64 - 49)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 55) | (tmp << (64 - 55)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 19) | (tmp << (64 - 19)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 38) | (tmp << (64 - 38)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 37) | (tmp << (64 - 37)); + b14 -= b15 + k11 + t0; + b15 -= k12 + 14; + + tmp = b13 ^ b12; + b13 = (tmp >> 22) | (tmp << (64 - 22)); + b12 -= b13 + k9; + b13 -= k10 + t2; + + tmp = b11 ^ b10; + b11 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b11 + k7; + b11 -= k8; + + tmp = b9 ^ b8; + b9 = (tmp >> 8) | (tmp << (64 - 8)); + b8 -= b9 + k5; + b9 -= k6; + + tmp = b7 ^ b6; + b7 = (tmp >> 47) | (tmp << (64 - 47)); + b6 -= b7 + k3; + b7 -= k4; + + tmp = b5 ^ b4; + b5 = (tmp >> 8) | (tmp << (64 - 8)); + b4 -= b5 + k1; + b5 -= k2; + + tmp = b3 ^ b2; + b3 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b3 + k16; + b3 -= k0; + + tmp = b1 ^ b0; + b1 = (tmp >> 24) | (tmp << (64 - 24)); + b0 -= b1 + k14; + b1 -= k15; + + tmp = b7 ^ b12; + b7 = (tmp >> 20) | (tmp << (64 - 20)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 37) | (tmp << (64 - 37)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 31) | (tmp << (64 - 31)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 52) | (tmp << (64 - 52)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 35) | (tmp << (64 - 35)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 48) | (tmp << (64 - 48)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 25) | (tmp << (64 - 25)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 44) | (tmp << (64 - 44)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 19) | (tmp << (64 - 19)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 47) | (tmp << (64 - 47)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 44) | (tmp << (64 - 44)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 53) | (tmp << (64 - 53)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 4) | (tmp << (64 - 4)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 56) | (tmp << (64 - 56)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 34) | (tmp << (64 - 34)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 16) | (tmp << (64 - 16)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 30) | (tmp << (64 - 30)); + b14 -= b15 + k10 + t2; + b15 -= k11 + 13; + + tmp = b13 ^ b12; + b13 = (tmp >> 44) | (tmp << (64 - 44)); + b12 -= b13 + k8; + b13 -= k9 + t1; + + tmp = b11 ^ b10; + b11 = (tmp >> 47) | (tmp << (64 - 47)); + b10 -= b11 + k6; + b11 -= k7; + + tmp = b9 ^ b8; + b9 = (tmp >> 12) | (tmp << (64 - 12)); + b8 -= b9 + k4; + b9 -= k5; + + tmp = b7 ^ b6; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b6 -= b7 + k2; + b7 -= k3; + + tmp = b5 ^ b4; + b5 = (tmp >> 37) | (tmp << (64 - 37)); + b4 -= b5 + k0; + b5 -= k1; + + tmp = b3 ^ b2; + b3 = (tmp >> 9) | (tmp << (64 - 9)); + b2 -= b3 + k15; + b3 -= k16; + + tmp = b1 ^ b0; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b0 -= b1 + k13; + b1 -= k14; + + tmp = b7 ^ b12; + b7 = (tmp >> 25) | (tmp << (64 - 25)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 28) | (tmp << (64 - 28)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 47) | (tmp << (64 - 47)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 41) | (tmp << (64 - 41)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 48) | (tmp << (64 - 48)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 20) | (tmp << (64 - 20)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 59) | (tmp << (64 - 59)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 41) | (tmp << (64 - 41)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 34) | (tmp << (64 - 34)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 4) | (tmp << (64 - 4)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 33) | (tmp << (64 - 33)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 52) | (tmp << (64 - 52)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 18) | (tmp << (64 - 18)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 49) | (tmp << (64 - 49)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 55) | (tmp << (64 - 55)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 19) | (tmp << (64 - 19)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 38) | (tmp << (64 - 38)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 37) | (tmp << (64 - 37)); + b14 -= b15 + k9 + t1; + b15 -= k10 + 12; + + tmp = b13 ^ b12; + b13 = (tmp >> 22) | (tmp << (64 - 22)); + b12 -= b13 + k7; + b13 -= k8 + t0; + + tmp = b11 ^ b10; + b11 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b11 + k5; + b11 -= k6; + + tmp = b9 ^ b8; + b9 = (tmp >> 8) | (tmp << (64 - 8)); + b8 -= b9 + k3; + b9 -= k4; + + tmp = b7 ^ b6; + b7 = (tmp >> 47) | (tmp << (64 - 47)); + b6 -= b7 + k1; + b7 -= k2; + + tmp = b5 ^ b4; + b5 = (tmp >> 8) | (tmp << (64 - 8)); + b4 -= b5 + k16; + b5 -= k0; + + tmp = b3 ^ b2; + b3 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b3 + k14; + b3 -= k15; + + tmp = b1 ^ b0; + b1 = (tmp >> 24) | (tmp << (64 - 24)); + b0 -= b1 + k12; + b1 -= k13; + + tmp = b7 ^ b12; + b7 = (tmp >> 20) | (tmp << (64 - 20)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 37) | (tmp << (64 - 37)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 31) | (tmp << (64 - 31)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 52) | (tmp << (64 - 52)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 35) | (tmp << (64 - 35)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 48) | (tmp << (64 - 48)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 25) | (tmp << (64 - 25)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 44) | (tmp << (64 - 44)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 19) | (tmp << (64 - 19)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 47) | (tmp << (64 - 47)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 44) | (tmp << (64 - 44)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 53) | (tmp << (64 - 53)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 4) | (tmp << (64 - 4)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 56) | (tmp << (64 - 56)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 34) | (tmp << (64 - 34)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 16) | (tmp << (64 - 16)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 30) | (tmp << (64 - 30)); + b14 -= b15 + k8 + t0; + b15 -= k9 + 11; + + tmp = b13 ^ b12; + b13 = (tmp >> 44) | (tmp << (64 - 44)); + b12 -= b13 + k6; + b13 -= k7 + t2; + + tmp = b11 ^ b10; + b11 = (tmp >> 47) | (tmp << (64 - 47)); + b10 -= b11 + k4; + b11 -= k5; + + tmp = b9 ^ b8; + b9 = (tmp >> 12) | (tmp << (64 - 12)); + b8 -= b9 + k2; + b9 -= k3; + + tmp = b7 ^ b6; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b6 -= b7 + k0; + b7 -= k1; + + tmp = b5 ^ b4; + b5 = (tmp >> 37) | (tmp << (64 - 37)); + b4 -= b5 + k15; + b5 -= k16; + + tmp = b3 ^ b2; + b3 = (tmp >> 9) | (tmp << (64 - 9)); + b2 -= b3 + k13; + b3 -= k14; + + tmp = b1 ^ b0; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b0 -= b1 + k11; + b1 -= k12; + + tmp = b7 ^ b12; + b7 = (tmp >> 25) | (tmp << (64 - 25)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 28) | (tmp << (64 - 28)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 47) | (tmp << (64 - 47)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 41) | (tmp << (64 - 41)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 48) | (tmp << (64 - 48)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 20) | (tmp << (64 - 20)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 59) | (tmp << (64 - 59)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 41) | (tmp << (64 - 41)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 34) | (tmp << (64 - 34)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 4) | (tmp << (64 - 4)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 33) | (tmp << (64 - 33)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 52) | (tmp << (64 - 52)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 18) | (tmp << (64 - 18)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 49) | (tmp << (64 - 49)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 55) | (tmp << (64 - 55)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 19) | (tmp << (64 - 19)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 38) | (tmp << (64 - 38)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 37) | (tmp << (64 - 37)); + b14 -= b15 + k7 + t2; + b15 -= k8 + 10; + + tmp = b13 ^ b12; + b13 = (tmp >> 22) | (tmp << (64 - 22)); + b12 -= b13 + k5; + b13 -= k6 + t1; + + tmp = b11 ^ b10; + b11 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b11 + k3; + b11 -= k4; + + tmp = b9 ^ b8; + b9 = (tmp >> 8) | (tmp << (64 - 8)); + b8 -= b9 + k1; + b9 -= k2; + + tmp = b7 ^ b6; + b7 = (tmp >> 47) | (tmp << (64 - 47)); + b6 -= b7 + k16; + b7 -= k0; + + tmp = b5 ^ b4; + b5 = (tmp >> 8) | (tmp << (64 - 8)); + b4 -= b5 + k14; + b5 -= k15; + + tmp = b3 ^ b2; + b3 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b3 + k12; + b3 -= k13; + + tmp = b1 ^ b0; + b1 = (tmp >> 24) | (tmp << (64 - 24)); + b0 -= b1 + k10; + b1 -= k11; + + tmp = b7 ^ b12; + b7 = (tmp >> 20) | (tmp << (64 - 20)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 37) | (tmp << (64 - 37)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 31) | (tmp << (64 - 31)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 52) | (tmp << (64 - 52)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 35) | (tmp << (64 - 35)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 48) | (tmp << (64 - 48)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 25) | (tmp << (64 - 25)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 44) | (tmp << (64 - 44)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 19) | (tmp << (64 - 19)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 47) | (tmp << (64 - 47)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 44) | (tmp << (64 - 44)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 53) | (tmp << (64 - 53)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 4) | (tmp << (64 - 4)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 56) | (tmp << (64 - 56)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 34) | (tmp << (64 - 34)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 16) | (tmp << (64 - 16)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 30) | (tmp << (64 - 30)); + b14 -= b15 + k6 + t1; + b15 -= k7 + 9; + + tmp = b13 ^ b12; + b13 = (tmp >> 44) | (tmp << (64 - 44)); + b12 -= b13 + k4; + b13 -= k5 + t0; + + tmp = b11 ^ b10; + b11 = (tmp >> 47) | (tmp << (64 - 47)); + b10 -= b11 + k2; + b11 -= k3; + + tmp = b9 ^ b8; + b9 = (tmp >> 12) | (tmp << (64 - 12)); + b8 -= b9 + k0; + b9 -= k1; + + tmp = b7 ^ b6; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b6 -= b7 + k15; + b7 -= k16; + + tmp = b5 ^ b4; + b5 = (tmp >> 37) | (tmp << (64 - 37)); + b4 -= b5 + k13; + b5 -= k14; + + tmp = b3 ^ b2; + b3 = (tmp >> 9) | (tmp << (64 - 9)); + b2 -= b3 + k11; + b3 -= k12; + + tmp = b1 ^ b0; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b0 -= b1 + k9; + b1 -= k10; + + tmp = b7 ^ b12; + b7 = (tmp >> 25) | (tmp << (64 - 25)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 28) | (tmp << (64 - 28)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 47) | (tmp << (64 - 47)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 41) | (tmp << (64 - 41)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 48) | (tmp << (64 - 48)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 20) | (tmp << (64 - 20)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 59) | (tmp << (64 - 59)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 41) | (tmp << (64 - 41)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 34) | (tmp << (64 - 34)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 4) | (tmp << (64 - 4)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 33) | (tmp << (64 - 33)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 52) | (tmp << (64 - 52)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 18) | (tmp << (64 - 18)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 49) | (tmp << (64 - 49)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 55) | (tmp << (64 - 55)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 19) | (tmp << (64 - 19)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 38) | (tmp << (64 - 38)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 37) | (tmp << (64 - 37)); + b14 -= b15 + k5 + t0; + b15 -= k6 + 8; + + tmp = b13 ^ b12; + b13 = (tmp >> 22) | (tmp << (64 - 22)); + b12 -= b13 + k3; + b13 -= k4 + t2; + + tmp = b11 ^ b10; + b11 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b11 + k1; + b11 -= k2; + + tmp = b9 ^ b8; + b9 = (tmp >> 8) | (tmp << (64 - 8)); + b8 -= b9 + k16; + b9 -= k0; + + tmp = b7 ^ b6; + b7 = (tmp >> 47) | (tmp << (64 - 47)); + b6 -= b7 + k14; + b7 -= k15; + + tmp = b5 ^ b4; + b5 = (tmp >> 8) | (tmp << (64 - 8)); + b4 -= b5 + k12; + b5 -= k13; + + tmp = b3 ^ b2; + b3 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b3 + k10; + b3 -= k11; + + tmp = b1 ^ b0; + b1 = (tmp >> 24) | (tmp << (64 - 24)); + b0 -= b1 + k8; + b1 -= k9; + + tmp = b7 ^ b12; + b7 = (tmp >> 20) | (tmp << (64 - 20)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 37) | (tmp << (64 - 37)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 31) | (tmp << (64 - 31)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 52) | (tmp << (64 - 52)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 35) | (tmp << (64 - 35)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 48) | (tmp << (64 - 48)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 25) | (tmp << (64 - 25)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 44) | (tmp << (64 - 44)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 19) | (tmp << (64 - 19)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 47) | (tmp << (64 - 47)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 44) | (tmp << (64 - 44)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 53) | (tmp << (64 - 53)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 4) | (tmp << (64 - 4)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 56) | (tmp << (64 - 56)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 34) | (tmp << (64 - 34)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 16) | (tmp << (64 - 16)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 30) | (tmp << (64 - 30)); + b14 -= b15 + k4 + t2; + b15 -= k5 + 7; + + tmp = b13 ^ b12; + b13 = (tmp >> 44) | (tmp << (64 - 44)); + b12 -= b13 + k2; + b13 -= k3 + t1; + + tmp = b11 ^ b10; + b11 = (tmp >> 47) | (tmp << (64 - 47)); + b10 -= b11 + k0; + b11 -= k1; + + tmp = b9 ^ b8; + b9 = (tmp >> 12) | (tmp << (64 - 12)); + b8 -= b9 + k15; + b9 -= k16; + + tmp = b7 ^ b6; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b6 -= b7 + k13; + b7 -= k14; + + tmp = b5 ^ b4; + b5 = (tmp >> 37) | (tmp << (64 - 37)); + b4 -= b5 + k11; + b5 -= k12; + + tmp = b3 ^ b2; + b3 = (tmp >> 9) | (tmp << (64 - 9)); + b2 -= b3 + k9; + b3 -= k10; + + tmp = b1 ^ b0; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b0 -= b1 + k7; + b1 -= k8; + + tmp = b7 ^ b12; + b7 = (tmp >> 25) | (tmp << (64 - 25)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 28) | (tmp << (64 - 28)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 47) | (tmp << (64 - 47)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 41) | (tmp << (64 - 41)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 48) | (tmp << (64 - 48)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 20) | (tmp << (64 - 20)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 59) | (tmp << (64 - 59)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 41) | (tmp << (64 - 41)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 34) | (tmp << (64 - 34)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 4) | (tmp << (64 - 4)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 33) | (tmp << (64 - 33)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 52) | (tmp << (64 - 52)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 18) | (tmp << (64 - 18)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 49) | (tmp << (64 - 49)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 55) | (tmp << (64 - 55)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 19) | (tmp << (64 - 19)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 38) | (tmp << (64 - 38)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 37) | (tmp << (64 - 37)); + b14 -= b15 + k3 + t1; + b15 -= k4 + 6; + + tmp = b13 ^ b12; + b13 = (tmp >> 22) | (tmp << (64 - 22)); + b12 -= b13 + k1; + b13 -= k2 + t0; + + tmp = b11 ^ b10; + b11 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b11 + k16; + b11 -= k0; + + tmp = b9 ^ b8; + b9 = (tmp >> 8) | (tmp << (64 - 8)); + b8 -= b9 + k14; + b9 -= k15; + + tmp = b7 ^ b6; + b7 = (tmp >> 47) | (tmp << (64 - 47)); + b6 -= b7 + k12; + b7 -= k13; + + tmp = b5 ^ b4; + b5 = (tmp >> 8) | (tmp << (64 - 8)); + b4 -= b5 + k10; + b5 -= k11; + + tmp = b3 ^ b2; + b3 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b3 + k8; + b3 -= k9; + + tmp = b1 ^ b0; + b1 = (tmp >> 24) | (tmp << (64 - 24)); + b0 -= b1 + k6; + b1 -= k7; + + tmp = b7 ^ b12; + b7 = (tmp >> 20) | (tmp << (64 - 20)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 37) | (tmp << (64 - 37)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 31) | (tmp << (64 - 31)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 52) | (tmp << (64 - 52)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 35) | (tmp << (64 - 35)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 48) | (tmp << (64 - 48)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 25) | (tmp << (64 - 25)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 44) | (tmp << (64 - 44)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 19) | (tmp << (64 - 19)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 47) | (tmp << (64 - 47)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 44) | (tmp << (64 - 44)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 53) | (tmp << (64 - 53)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 4) | (tmp << (64 - 4)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 56) | (tmp << (64 - 56)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 34) | (tmp << (64 - 34)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 16) | (tmp << (64 - 16)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 30) | (tmp << (64 - 30)); + b14 -= b15 + k2 + t0; + b15 -= k3 + 5; + + tmp = b13 ^ b12; + b13 = (tmp >> 44) | (tmp << (64 - 44)); + b12 -= b13 + k0; + b13 -= k1 + t2; + + tmp = b11 ^ b10; + b11 = (tmp >> 47) | (tmp << (64 - 47)); + b10 -= b11 + k15; + b11 -= k16; + + tmp = b9 ^ b8; + b9 = (tmp >> 12) | (tmp << (64 - 12)); + b8 -= b9 + k13; + b9 -= k14; + + tmp = b7 ^ b6; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b6 -= b7 + k11; + b7 -= k12; + + tmp = b5 ^ b4; + b5 = (tmp >> 37) | (tmp << (64 - 37)); + b4 -= b5 + k9; + b5 -= k10; + + tmp = b3 ^ b2; + b3 = (tmp >> 9) | (tmp << (64 - 9)); + b2 -= b3 + k7; + b3 -= k8; + + tmp = b1 ^ b0; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b0 -= b1 + k5; + b1 -= k6; + + tmp = b7 ^ b12; + b7 = (tmp >> 25) | (tmp << (64 - 25)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 28) | (tmp << (64 - 28)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 47) | (tmp << (64 - 47)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 41) | (tmp << (64 - 41)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 48) | (tmp << (64 - 48)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 20) | (tmp << (64 - 20)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 59) | (tmp << (64 - 59)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 41) | (tmp << (64 - 41)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 34) | (tmp << (64 - 34)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 4) | (tmp << (64 - 4)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 33) | (tmp << (64 - 33)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 52) | (tmp << (64 - 52)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 18) | (tmp << (64 - 18)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 49) | (tmp << (64 - 49)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 55) | (tmp << (64 - 55)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 19) | (tmp << (64 - 19)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 38) | (tmp << (64 - 38)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 37) | (tmp << (64 - 37)); + b14 -= b15 + k1 + t2; + b15 -= k2 + 4; + + tmp = b13 ^ b12; + b13 = (tmp >> 22) | (tmp << (64 - 22)); + b12 -= b13 + k16; + b13 -= k0 + t1; + + tmp = b11 ^ b10; + b11 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b11 + k14; + b11 -= k15; + + tmp = b9 ^ b8; + b9 = (tmp >> 8) | (tmp << (64 - 8)); + b8 -= b9 + k12; + b9 -= k13; + + tmp = b7 ^ b6; + b7 = (tmp >> 47) | (tmp << (64 - 47)); + b6 -= b7 + k10; + b7 -= k11; + + tmp = b5 ^ b4; + b5 = (tmp >> 8) | (tmp << (64 - 8)); + b4 -= b5 + k8; + b5 -= k9; + + tmp = b3 ^ b2; + b3 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b3 + k6; + b3 -= k7; + + tmp = b1 ^ b0; + b1 = (tmp >> 24) | (tmp << (64 - 24)); + b0 -= b1 + k4; + b1 -= k5; + + tmp = b7 ^ b12; + b7 = (tmp >> 20) | (tmp << (64 - 20)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 37) | (tmp << (64 - 37)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 31) | (tmp << (64 - 31)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 52) | (tmp << (64 - 52)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 35) | (tmp << (64 - 35)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 48) | (tmp << (64 - 48)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 25) | (tmp << (64 - 25)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 44) | (tmp << (64 - 44)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 19) | (tmp << (64 - 19)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 47) | (tmp << (64 - 47)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 44) | (tmp << (64 - 44)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 53) | (tmp << (64 - 53)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 4) | (tmp << (64 - 4)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 56) | (tmp << (64 - 56)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 34) | (tmp << (64 - 34)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 16) | (tmp << (64 - 16)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 30) | (tmp << (64 - 30)); + b14 -= b15 + k0 + t1; + b15 -= k1 + 3; + + tmp = b13 ^ b12; + b13 = (tmp >> 44) | (tmp << (64 - 44)); + b12 -= b13 + k15; + b13 -= k16 + t0; + + tmp = b11 ^ b10; + b11 = (tmp >> 47) | (tmp << (64 - 47)); + b10 -= b11 + k13; + b11 -= k14; + + tmp = b9 ^ b8; + b9 = (tmp >> 12) | (tmp << (64 - 12)); + b8 -= b9 + k11; + b9 -= k12; + + tmp = b7 ^ b6; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b6 -= b7 + k9; + b7 -= k10; + + tmp = b5 ^ b4; + b5 = (tmp >> 37) | (tmp << (64 - 37)); + b4 -= b5 + k7; + b5 -= k8; + + tmp = b3 ^ b2; + b3 = (tmp >> 9) | (tmp << (64 - 9)); + b2 -= b3 + k5; + b3 -= k6; + + tmp = b1 ^ b0; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b0 -= b1 + k3; + b1 -= k4; + + tmp = b7 ^ b12; + b7 = (tmp >> 25) | (tmp << (64 - 25)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 28) | (tmp << (64 - 28)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 47) | (tmp << (64 - 47)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 41) | (tmp << (64 - 41)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 48) | (tmp << (64 - 48)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 20) | (tmp << (64 - 20)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 59) | (tmp << (64 - 59)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 41) | (tmp << (64 - 41)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 34) | (tmp << (64 - 34)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 4) | (tmp << (64 - 4)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 33) | (tmp << (64 - 33)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 52) | (tmp << (64 - 52)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 18) | (tmp << (64 - 18)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 49) | (tmp << (64 - 49)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 55) | (tmp << (64 - 55)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 19) | (tmp << (64 - 19)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 38) | (tmp << (64 - 38)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 37) | (tmp << (64 - 37)); + b14 -= b15 + k16 + t0; + b15 -= k0 + 2; + + tmp = b13 ^ b12; + b13 = (tmp >> 22) | (tmp << (64 - 22)); + b12 -= b13 + k14; + b13 -= k15 + t2; + + tmp = b11 ^ b10; + b11 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b11 + k12; + b11 -= k13; + + tmp = b9 ^ b8; + b9 = (tmp >> 8) | (tmp << (64 - 8)); + b8 -= b9 + k10; + b9 -= k11; + + tmp = b7 ^ b6; + b7 = (tmp >> 47) | (tmp << (64 - 47)); + b6 -= b7 + k8; + b7 -= k9; + + tmp = b5 ^ b4; + b5 = (tmp >> 8) | (tmp << (64 - 8)); + b4 -= b5 + k6; + b5 -= k7; + + tmp = b3 ^ b2; + b3 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b3 + k4; + b3 -= k5; + + tmp = b1 ^ b0; + b1 = (tmp >> 24) | (tmp << (64 - 24)); + b0 -= b1 + k2; + b1 -= k3; + + tmp = b7 ^ b12; + b7 = (tmp >> 20) | (tmp << (64 - 20)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 37) | (tmp << (64 - 37)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 31) | (tmp << (64 - 31)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 52) | (tmp << (64 - 52)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 35) | (tmp << (64 - 35)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 48) | (tmp << (64 - 48)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 25) | (tmp << (64 - 25)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 44) | (tmp << (64 - 44)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 19) | (tmp << (64 - 19)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 47) | (tmp << (64 - 47)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 44) | (tmp << (64 - 44)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 42) | (tmp << (64 - 42)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 53) | (tmp << (64 - 53)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 4) | (tmp << (64 - 4)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 56) | (tmp << (64 - 56)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 34) | (tmp << (64 - 34)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 16) | (tmp << (64 - 16)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 30) | (tmp << (64 - 30)); + b14 -= b15 + k15 + t2; + b15 -= k16 + 1; + + tmp = b13 ^ b12; + b13 = (tmp >> 44) | (tmp << (64 - 44)); + b12 -= b13 + k13; + b13 -= k14 + t1; + + tmp = b11 ^ b10; + b11 = (tmp >> 47) | (tmp << (64 - 47)); + b10 -= b11 + k11; + b11 -= k12; + + tmp = b9 ^ b8; + b9 = (tmp >> 12) | (tmp << (64 - 12)); + b8 -= b9 + k9; + b9 -= k10; + + tmp = b7 ^ b6; + b7 = (tmp >> 31) | (tmp << (64 - 31)); + b6 -= b7 + k7; + b7 -= k8; + + tmp = b5 ^ b4; + b5 = (tmp >> 37) | (tmp << (64 - 37)); + b4 -= b5 + k5; + b5 -= k6; + + tmp = b3 ^ b2; + b3 = (tmp >> 9) | (tmp << (64 - 9)); + b2 -= b3 + k3; + b3 -= k4; + + tmp = b1 ^ b0; + b1 = (tmp >> 41) | (tmp << (64 - 41)); + b0 -= b1 + k1; + b1 -= k2; + + tmp = b7 ^ b12; + b7 = (tmp >> 25) | (tmp << (64 - 25)); + b12 -= b7; + + tmp = b3 ^ b10; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b10 -= b3; + + tmp = b5 ^ b8; + b5 = (tmp >> 28) | (tmp << (64 - 28)); + b8 -= b5; + + tmp = b1 ^ b14; + b1 = (tmp >> 47) | (tmp << (64 - 47)); + b14 -= b1; + + tmp = b9 ^ b4; + b9 = (tmp >> 41) | (tmp << (64 - 41)); + b4 -= b9; + + tmp = b13 ^ b6; + b13 = (tmp >> 48) | (tmp << (64 - 48)); + b6 -= b13; + + tmp = b11 ^ b2; + b11 = (tmp >> 20) | (tmp << (64 - 20)); + b2 -= b11; + + tmp = b15 ^ b0; + b15 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b15; + + tmp = b9 ^ b10; + b9 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b9; + + tmp = b11 ^ b8; + b11 = (tmp >> 59) | (tmp << (64 - 59)); + b8 -= b11; + + tmp = b13 ^ b14; + b13 = (tmp >> 41) | (tmp << (64 - 41)); + b14 -= b13; + + tmp = b15 ^ b12; + b15 = (tmp >> 34) | (tmp << (64 - 34)); + b12 -= b15; + + tmp = b1 ^ b6; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b6 -= b1; + + tmp = b3 ^ b4; + b3 = (tmp >> 51) | (tmp << (64 - 51)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 4) | (tmp << (64 - 4)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 33) | (tmp << (64 - 33)); + b0 -= b7; + + tmp = b1 ^ b8; + b1 = (tmp >> 52) | (tmp << (64 - 52)); + b8 -= b1; + + tmp = b5 ^ b14; + b5 = (tmp >> 23) | (tmp << (64 - 23)); + b14 -= b5; + + tmp = b3 ^ b12; + b3 = (tmp >> 18) | (tmp << (64 - 18)); + b12 -= b3; + + tmp = b7 ^ b10; + b7 = (tmp >> 49) | (tmp << (64 - 49)); + b10 -= b7; + + tmp = b15 ^ b4; + b15 = (tmp >> 55) | (tmp << (64 - 55)); + b4 -= b15; + + tmp = b11 ^ b6; + b11 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b11; + + tmp = b13 ^ b2; + b13 = (tmp >> 19) | (tmp << (64 - 19)); + b2 -= b13; + + tmp = b9 ^ b0; + b9 = (tmp >> 38) | (tmp << (64 - 38)); + b0 -= b9; + + tmp = b15 ^ b14; + b15 = (tmp >> 37) | (tmp << (64 - 37)); + b14 -= b15 + k14 + t1; + b15 -= k15; + + tmp = b13 ^ b12; + b13 = (tmp >> 22) | (tmp << (64 - 22)); + b12 -= b13 + k12; + b13 -= k13 + t0; + + tmp = b11 ^ b10; + b11 = (tmp >> 17) | (tmp << (64 - 17)); + b10 -= b11 + k10; + b11 -= k11; + + tmp = b9 ^ b8; + b9 = (tmp >> 8) | (tmp << (64 - 8)); + b8 -= b9 + k8; + b9 -= k9; + + tmp = b7 ^ b6; + b7 = (tmp >> 47) | (tmp << (64 - 47)); + b6 -= b7 + k6; + b7 -= k7; + + tmp = b5 ^ b4; + b5 = (tmp >> 8) | (tmp << (64 - 8)); + b4 -= b5 + k4; + b5 -= k5; + + tmp = b3 ^ b2; + b3 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b3 + k2; + b3 -= k3; + + tmp = b1 ^ b0; + b1 = (tmp >> 24) | (tmp << (64 - 24)); + b0 -= b1 + k0; + b1 -= k1; + + output[15] = b15; + output[14] = b14; + output[13] = b13; + output[12] = b12; + output[11] = b11; + output[10] = b10; + output[9] = b9; + output[8] = b8; + output[7] = b7; + output[6] = b6; + output[5] = b5; + output[4] = b4; + output[3] = b3; + output[2] = b2; + output[1] = b1; + output[0] = b0; +} diff --git a/drivers/staging/skein/threefish256Block.c b/drivers/staging/skein/threefish256Block.c new file mode 100644 index 00000000000000..2ae746a641ae07 --- /dev/null +++ b/drivers/staging/skein/threefish256Block.c @@ -0,0 +1,1137 @@ +#include +#include + + +void threefishEncrypt256(struct threefish_key *keyCtx, u64 *input, u64 *output) +{ + u64 b0 = input[0], b1 = input[1], + b2 = input[2], b3 = input[3]; + u64 k0 = keyCtx->key[0], k1 = keyCtx->key[1], + k2 = keyCtx->key[2], k3 = keyCtx->key[3], + k4 = keyCtx->key[4]; + u64 t0 = keyCtx->tweak[0], t1 = keyCtx->tweak[1], + t2 = keyCtx->tweak[2]; + + b1 += k1 + t0; + b0 += b1 + k0; + b1 = ((b1 << 14) | (b1 >> (64 - 14))) ^ b0; + + b3 += k3; + b2 += b3 + k2 + t1; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b2; + + b0 += b3; + b3 = ((b3 << 52) | (b3 >> (64 - 52))) ^ b0; + + b2 += b1; + b1 = ((b1 << 57) | (b1 >> (64 - 57))) ^ b2; + + b0 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b0; + + b2 += b3; + b3 = ((b3 << 40) | (b3 >> (64 - 40))) ^ b2; + + b0 += b3; + b3 = ((b3 << 5) | (b3 >> (64 - 5))) ^ b0; + + b2 += b1; + b1 = ((b1 << 37) | (b1 >> (64 - 37))) ^ b2; + + b1 += k2 + t1; + b0 += b1 + k1; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b0; + + b3 += k4 + 1; + b2 += b3 + k3 + t2; + b3 = ((b3 << 33) | (b3 >> (64 - 33))) ^ b2; + + b0 += b3; + b3 = ((b3 << 46) | (b3 >> (64 - 46))) ^ b0; + + b2 += b1; + b1 = ((b1 << 12) | (b1 >> (64 - 12))) ^ b2; + + b0 += b1; + b1 = ((b1 << 58) | (b1 >> (64 - 58))) ^ b0; + + b2 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b2; + + b0 += b3; + b3 = ((b3 << 32) | (b3 >> (64 - 32))) ^ b0; + + b2 += b1; + b1 = ((b1 << 32) | (b1 >> (64 - 32))) ^ b2; + + + b1 += k3 + t2; + b0 += b1 + k2; + b1 = ((b1 << 14) | (b1 >> (64 - 14))) ^ b0; + + b3 += k0 + 2; + b2 += b3 + k4 + t0; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b2; + + b0 += b3; + b3 = ((b3 << 52) | (b3 >> (64 - 52))) ^ b0; + + b2 += b1; + b1 = ((b1 << 57) | (b1 >> (64 - 57))) ^ b2; + + b0 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b0; + + b2 += b3; + b3 = ((b3 << 40) | (b3 >> (64 - 40))) ^ b2; + + b0 += b3; + b3 = ((b3 << 5) | (b3 >> (64 - 5))) ^ b0; + + b2 += b1; + b1 = ((b1 << 37) | (b1 >> (64 - 37))) ^ b2; + + b1 += k4 + t0; + b0 += b1 + k3; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b0; + + b3 += k1 + 3; + b2 += b3 + k0 + t1; + b3 = ((b3 << 33) | (b3 >> (64 - 33))) ^ b2; + + b0 += b3; + b3 = ((b3 << 46) | (b3 >> (64 - 46))) ^ b0; + + b2 += b1; + b1 = ((b1 << 12) | (b1 >> (64 - 12))) ^ b2; + + b0 += b1; + b1 = ((b1 << 58) | (b1 >> (64 - 58))) ^ b0; + + b2 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b2; + + b0 += b3; + b3 = ((b3 << 32) | (b3 >> (64 - 32))) ^ b0; + + b2 += b1; + b1 = ((b1 << 32) | (b1 >> (64 - 32))) ^ b2; + + + b1 += k0 + t1; + b0 += b1 + k4; + b1 = ((b1 << 14) | (b1 >> (64 - 14))) ^ b0; + + b3 += k2 + 4; + b2 += b3 + k1 + t2; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b2; + + b0 += b3; + b3 = ((b3 << 52) | (b3 >> (64 - 52))) ^ b0; + + b2 += b1; + b1 = ((b1 << 57) | (b1 >> (64 - 57))) ^ b2; + + b0 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b0; + + b2 += b3; + b3 = ((b3 << 40) | (b3 >> (64 - 40))) ^ b2; + + b0 += b3; + b3 = ((b3 << 5) | (b3 >> (64 - 5))) ^ b0; + + b2 += b1; + b1 = ((b1 << 37) | (b1 >> (64 - 37))) ^ b2; + + b1 += k1 + t2; + b0 += b1 + k0; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b0; + + b3 += k3 + 5; + b2 += b3 + k2 + t0; + b3 = ((b3 << 33) | (b3 >> (64 - 33))) ^ b2; + + b0 += b3; + b3 = ((b3 << 46) | (b3 >> (64 - 46))) ^ b0; + + b2 += b1; + b1 = ((b1 << 12) | (b1 >> (64 - 12))) ^ b2; + + b0 += b1; + b1 = ((b1 << 58) | (b1 >> (64 - 58))) ^ b0; + + b2 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b2; + + b0 += b3; + b3 = ((b3 << 32) | (b3 >> (64 - 32))) ^ b0; + + b2 += b1; + b1 = ((b1 << 32) | (b1 >> (64 - 32))) ^ b2; + + + b1 += k2 + t0; + b0 += b1 + k1; + b1 = ((b1 << 14) | (b1 >> (64 - 14))) ^ b0; + + b3 += k4 + 6; + b2 += b3 + k3 + t1; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b2; + + b0 += b3; + b3 = ((b3 << 52) | (b3 >> (64 - 52))) ^ b0; + + b2 += b1; + b1 = ((b1 << 57) | (b1 >> (64 - 57))) ^ b2; + + b0 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b0; + + b2 += b3; + b3 = ((b3 << 40) | (b3 >> (64 - 40))) ^ b2; + + b0 += b3; + b3 = ((b3 << 5) | (b3 >> (64 - 5))) ^ b0; + + b2 += b1; + b1 = ((b1 << 37) | (b1 >> (64 - 37))) ^ b2; + + b1 += k3 + t1; + b0 += b1 + k2; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b0; + + b3 += k0 + 7; + b2 += b3 + k4 + t2; + b3 = ((b3 << 33) | (b3 >> (64 - 33))) ^ b2; + + b0 += b3; + b3 = ((b3 << 46) | (b3 >> (64 - 46))) ^ b0; + + b2 += b1; + b1 = ((b1 << 12) | (b1 >> (64 - 12))) ^ b2; + + b0 += b1; + b1 = ((b1 << 58) | (b1 >> (64 - 58))) ^ b0; + + b2 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b2; + + b0 += b3; + b3 = ((b3 << 32) | (b3 >> (64 - 32))) ^ b0; + + b2 += b1; + b1 = ((b1 << 32) | (b1 >> (64 - 32))) ^ b2; + + + b1 += k4 + t2; + b0 += b1 + k3; + b1 = ((b1 << 14) | (b1 >> (64 - 14))) ^ b0; + + b3 += k1 + 8; + b2 += b3 + k0 + t0; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b2; + + b0 += b3; + b3 = ((b3 << 52) | (b3 >> (64 - 52))) ^ b0; + + b2 += b1; + b1 = ((b1 << 57) | (b1 >> (64 - 57))) ^ b2; + + b0 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b0; + + b2 += b3; + b3 = ((b3 << 40) | (b3 >> (64 - 40))) ^ b2; + + b0 += b3; + b3 = ((b3 << 5) | (b3 >> (64 - 5))) ^ b0; + + b2 += b1; + b1 = ((b1 << 37) | (b1 >> (64 - 37))) ^ b2; + + b1 += k0 + t0; + b0 += b1 + k4; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b0; + + b3 += k2 + 9; + b2 += b3 + k1 + t1; + b3 = ((b3 << 33) | (b3 >> (64 - 33))) ^ b2; + + b0 += b3; + b3 = ((b3 << 46) | (b3 >> (64 - 46))) ^ b0; + + b2 += b1; + b1 = ((b1 << 12) | (b1 >> (64 - 12))) ^ b2; + + b0 += b1; + b1 = ((b1 << 58) | (b1 >> (64 - 58))) ^ b0; + + b2 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b2; + + b0 += b3; + b3 = ((b3 << 32) | (b3 >> (64 - 32))) ^ b0; + + b2 += b1; + b1 = ((b1 << 32) | (b1 >> (64 - 32))) ^ b2; + + + b1 += k1 + t1; + b0 += b1 + k0; + b1 = ((b1 << 14) | (b1 >> (64 - 14))) ^ b0; + + b3 += k3 + 10; + b2 += b3 + k2 + t2; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b2; + + b0 += b3; + b3 = ((b3 << 52) | (b3 >> (64 - 52))) ^ b0; + + b2 += b1; + b1 = ((b1 << 57) | (b1 >> (64 - 57))) ^ b2; + + b0 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b0; + + b2 += b3; + b3 = ((b3 << 40) | (b3 >> (64 - 40))) ^ b2; + + b0 += b3; + b3 = ((b3 << 5) | (b3 >> (64 - 5))) ^ b0; + + b2 += b1; + b1 = ((b1 << 37) | (b1 >> (64 - 37))) ^ b2; + + b1 += k2 + t2; + b0 += b1 + k1; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b0; + + b3 += k4 + 11; + b2 += b3 + k3 + t0; + b3 = ((b3 << 33) | (b3 >> (64 - 33))) ^ b2; + + b0 += b3; + b3 = ((b3 << 46) | (b3 >> (64 - 46))) ^ b0; + + b2 += b1; + b1 = ((b1 << 12) | (b1 >> (64 - 12))) ^ b2; + + b0 += b1; + b1 = ((b1 << 58) | (b1 >> (64 - 58))) ^ b0; + + b2 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b2; + + b0 += b3; + b3 = ((b3 << 32) | (b3 >> (64 - 32))) ^ b0; + + b2 += b1; + b1 = ((b1 << 32) | (b1 >> (64 - 32))) ^ b2; + + + b1 += k3 + t0; + b0 += b1 + k2; + b1 = ((b1 << 14) | (b1 >> (64 - 14))) ^ b0; + + b3 += k0 + 12; + b2 += b3 + k4 + t1; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b2; + + b0 += b3; + b3 = ((b3 << 52) | (b3 >> (64 - 52))) ^ b0; + + b2 += b1; + b1 = ((b1 << 57) | (b1 >> (64 - 57))) ^ b2; + + b0 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b0; + + b2 += b3; + b3 = ((b3 << 40) | (b3 >> (64 - 40))) ^ b2; + + b0 += b3; + b3 = ((b3 << 5) | (b3 >> (64 - 5))) ^ b0; + + b2 += b1; + b1 = ((b1 << 37) | (b1 >> (64 - 37))) ^ b2; + + b1 += k4 + t1; + b0 += b1 + k3; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b0; + + b3 += k1 + 13; + b2 += b3 + k0 + t2; + b3 = ((b3 << 33) | (b3 >> (64 - 33))) ^ b2; + + b0 += b3; + b3 = ((b3 << 46) | (b3 >> (64 - 46))) ^ b0; + + b2 += b1; + b1 = ((b1 << 12) | (b1 >> (64 - 12))) ^ b2; + + b0 += b1; + b1 = ((b1 << 58) | (b1 >> (64 - 58))) ^ b0; + + b2 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b2; + + b0 += b3; + b3 = ((b3 << 32) | (b3 >> (64 - 32))) ^ b0; + + b2 += b1; + b1 = ((b1 << 32) | (b1 >> (64 - 32))) ^ b2; + + + b1 += k0 + t2; + b0 += b1 + k4; + b1 = ((b1 << 14) | (b1 >> (64 - 14))) ^ b0; + + b3 += k2 + 14; + b2 += b3 + k1 + t0; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b2; + + b0 += b3; + b3 = ((b3 << 52) | (b3 >> (64 - 52))) ^ b0; + + b2 += b1; + b1 = ((b1 << 57) | (b1 >> (64 - 57))) ^ b2; + + b0 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b0; + + b2 += b3; + b3 = ((b3 << 40) | (b3 >> (64 - 40))) ^ b2; + + b0 += b3; + b3 = ((b3 << 5) | (b3 >> (64 - 5))) ^ b0; + + b2 += b1; + b1 = ((b1 << 37) | (b1 >> (64 - 37))) ^ b2; + + b1 += k1 + t0; + b0 += b1 + k0; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b0; + + b3 += k3 + 15; + b2 += b3 + k2 + t1; + b3 = ((b3 << 33) | (b3 >> (64 - 33))) ^ b2; + + b0 += b3; + b3 = ((b3 << 46) | (b3 >> (64 - 46))) ^ b0; + + b2 += b1; + b1 = ((b1 << 12) | (b1 >> (64 - 12))) ^ b2; + + b0 += b1; + b1 = ((b1 << 58) | (b1 >> (64 - 58))) ^ b0; + + b2 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b2; + + b0 += b3; + b3 = ((b3 << 32) | (b3 >> (64 - 32))) ^ b0; + + b2 += b1; + b1 = ((b1 << 32) | (b1 >> (64 - 32))) ^ b2; + + + b1 += k2 + t1; + b0 += b1 + k1; + b1 = ((b1 << 14) | (b1 >> (64 - 14))) ^ b0; + + b3 += k4 + 16; + b2 += b3 + k3 + t2; + b3 = ((b3 << 16) | (b3 >> (64 - 16))) ^ b2; + + b0 += b3; + b3 = ((b3 << 52) | (b3 >> (64 - 52))) ^ b0; + + b2 += b1; + b1 = ((b1 << 57) | (b1 >> (64 - 57))) ^ b2; + + b0 += b1; + b1 = ((b1 << 23) | (b1 >> (64 - 23))) ^ b0; + + b2 += b3; + b3 = ((b3 << 40) | (b3 >> (64 - 40))) ^ b2; + + b0 += b3; + b3 = ((b3 << 5) | (b3 >> (64 - 5))) ^ b0; + + b2 += b1; + b1 = ((b1 << 37) | (b1 >> (64 - 37))) ^ b2; + + b1 += k3 + t2; + b0 += b1 + k2; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b0; + + b3 += k0 + 17; + b2 += b3 + k4 + t0; + b3 = ((b3 << 33) | (b3 >> (64 - 33))) ^ b2; + + b0 += b3; + b3 = ((b3 << 46) | (b3 >> (64 - 46))) ^ b0; + + b2 += b1; + b1 = ((b1 << 12) | (b1 >> (64 - 12))) ^ b2; + + b0 += b1; + b1 = ((b1 << 58) | (b1 >> (64 - 58))) ^ b0; + + b2 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b2; + + b0 += b3; + b3 = ((b3 << 32) | (b3 >> (64 - 32))) ^ b0; + + b2 += b1; + b1 = ((b1 << 32) | (b1 >> (64 - 32))) ^ b2; + + output[0] = b0 + k3; + output[1] = b1 + k4 + t0; + output[2] = b2 + k0 + t1; + output[3] = b3 + k1 + 18; +} + +void threefishDecrypt256(struct threefish_key *keyCtx, u64 *input, u64 *output) +{ + u64 b0 = input[0], b1 = input[1], + b2 = input[2], b3 = input[3]; + u64 k0 = keyCtx->key[0], k1 = keyCtx->key[1], + k2 = keyCtx->key[2], k3 = keyCtx->key[3], + k4 = keyCtx->key[4]; + u64 t0 = keyCtx->tweak[0], t1 = keyCtx->tweak[1], + t2 = keyCtx->tweak[2]; + + u64 tmp; + + b0 -= k3; + b1 -= k4 + t0; + b2 -= k0 + t1; + b3 -= k1 + 18; + tmp = b3 ^ b0; + b3 = (tmp >> 32) | (tmp << (64 - 32)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 32) | (tmp << (64 - 32)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 58) | (tmp << (64 - 58)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 12) | (tmp << (64 - 12)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b0 -= b1 + k2; + b1 -= k3 + t2; + + tmp = b3 ^ b2; + b3 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b3 + k4 + t0; + b3 -= k0 + 17; + + tmp = b3 ^ b0; + b3 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 37) | (tmp << (64 - 37)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 40) | (tmp << (64 - 40)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 52) | (tmp << (64 - 52)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 57) | (tmp << (64 - 57)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 14) | (tmp << (64 - 14)); + b0 -= b1 + k1; + b1 -= k2 + t1; + + tmp = b3 ^ b2; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b2 -= b3 + k3 + t2; + b3 -= k4 + 16; + + + tmp = b3 ^ b0; + b3 = (tmp >> 32) | (tmp << (64 - 32)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 32) | (tmp << (64 - 32)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 58) | (tmp << (64 - 58)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 12) | (tmp << (64 - 12)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b0 -= b1 + k0; + b1 -= k1 + t0; + + tmp = b3 ^ b2; + b3 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b3 + k2 + t1; + b3 -= k3 + 15; + + tmp = b3 ^ b0; + b3 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 37) | (tmp << (64 - 37)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 40) | (tmp << (64 - 40)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 52) | (tmp << (64 - 52)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 57) | (tmp << (64 - 57)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 14) | (tmp << (64 - 14)); + b0 -= b1 + k4; + b1 -= k0 + t2; + + tmp = b3 ^ b2; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b2 -= b3 + k1 + t0; + b3 -= k2 + 14; + + + tmp = b3 ^ b0; + b3 = (tmp >> 32) | (tmp << (64 - 32)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 32) | (tmp << (64 - 32)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 58) | (tmp << (64 - 58)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 12) | (tmp << (64 - 12)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b0 -= b1 + k3; + b1 -= k4 + t1; + + tmp = b3 ^ b2; + b3 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b3 + k0 + t2; + b3 -= k1 + 13; + + tmp = b3 ^ b0; + b3 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 37) | (tmp << (64 - 37)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 40) | (tmp << (64 - 40)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 52) | (tmp << (64 - 52)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 57) | (tmp << (64 - 57)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 14) | (tmp << (64 - 14)); + b0 -= b1 + k2; + b1 -= k3 + t0; + + tmp = b3 ^ b2; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b2 -= b3 + k4 + t1; + b3 -= k0 + 12; + + + tmp = b3 ^ b0; + b3 = (tmp >> 32) | (tmp << (64 - 32)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 32) | (tmp << (64 - 32)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 58) | (tmp << (64 - 58)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 12) | (tmp << (64 - 12)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b0 -= b1 + k1; + b1 -= k2 + t2; + + tmp = b3 ^ b2; + b3 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b3 + k3 + t0; + b3 -= k4 + 11; + + tmp = b3 ^ b0; + b3 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 37) | (tmp << (64 - 37)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 40) | (tmp << (64 - 40)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 52) | (tmp << (64 - 52)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 57) | (tmp << (64 - 57)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 14) | (tmp << (64 - 14)); + b0 -= b1 + k0; + b1 -= k1 + t1; + + tmp = b3 ^ b2; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b2 -= b3 + k2 + t2; + b3 -= k3 + 10; + + + tmp = b3 ^ b0; + b3 = (tmp >> 32) | (tmp << (64 - 32)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 32) | (tmp << (64 - 32)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 58) | (tmp << (64 - 58)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 12) | (tmp << (64 - 12)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b0 -= b1 + k4; + b1 -= k0 + t0; + + tmp = b3 ^ b2; + b3 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b3 + k1 + t1; + b3 -= k2 + 9; + + tmp = b3 ^ b0; + b3 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 37) | (tmp << (64 - 37)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 40) | (tmp << (64 - 40)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 52) | (tmp << (64 - 52)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 57) | (tmp << (64 - 57)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 14) | (tmp << (64 - 14)); + b0 -= b1 + k3; + b1 -= k4 + t2; + + tmp = b3 ^ b2; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b2 -= b3 + k0 + t0; + b3 -= k1 + 8; + + + tmp = b3 ^ b0; + b3 = (tmp >> 32) | (tmp << (64 - 32)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 32) | (tmp << (64 - 32)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 58) | (tmp << (64 - 58)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 12) | (tmp << (64 - 12)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b0 -= b1 + k2; + b1 -= k3 + t1; + + tmp = b3 ^ b2; + b3 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b3 + k4 + t2; + b3 -= k0 + 7; + + tmp = b3 ^ b0; + b3 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 37) | (tmp << (64 - 37)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 40) | (tmp << (64 - 40)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 52) | (tmp << (64 - 52)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 57) | (tmp << (64 - 57)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 14) | (tmp << (64 - 14)); + b0 -= b1 + k1; + b1 -= k2 + t0; + + tmp = b3 ^ b2; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b2 -= b3 + k3 + t1; + b3 -= k4 + 6; + + + tmp = b3 ^ b0; + b3 = (tmp >> 32) | (tmp << (64 - 32)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 32) | (tmp << (64 - 32)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 58) | (tmp << (64 - 58)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 12) | (tmp << (64 - 12)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b0 -= b1 + k0; + b1 -= k1 + t2; + + tmp = b3 ^ b2; + b3 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b3 + k2 + t0; + b3 -= k3 + 5; + + tmp = b3 ^ b0; + b3 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 37) | (tmp << (64 - 37)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 40) | (tmp << (64 - 40)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 52) | (tmp << (64 - 52)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 57) | (tmp << (64 - 57)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 14) | (tmp << (64 - 14)); + b0 -= b1 + k4; + b1 -= k0 + t1; + + tmp = b3 ^ b2; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b2 -= b3 + k1 + t2; + b3 -= k2 + 4; + + + tmp = b3 ^ b0; + b3 = (tmp >> 32) | (tmp << (64 - 32)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 32) | (tmp << (64 - 32)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 58) | (tmp << (64 - 58)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 12) | (tmp << (64 - 12)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b0 -= b1 + k3; + b1 -= k4 + t0; + + tmp = b3 ^ b2; + b3 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b3 + k0 + t1; + b3 -= k1 + 3; + + tmp = b3 ^ b0; + b3 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 37) | (tmp << (64 - 37)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 40) | (tmp << (64 - 40)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 52) | (tmp << (64 - 52)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 57) | (tmp << (64 - 57)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 14) | (tmp << (64 - 14)); + b0 -= b1 + k2; + b1 -= k3 + t2; + + tmp = b3 ^ b2; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b2 -= b3 + k4 + t0; + b3 -= k0 + 2; + + + tmp = b3 ^ b0; + b3 = (tmp >> 32) | (tmp << (64 - 32)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 32) | (tmp << (64 - 32)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 58) | (tmp << (64 - 58)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 12) | (tmp << (64 - 12)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b0 -= b1 + k1; + b1 -= k2 + t1; + + tmp = b3 ^ b2; + b3 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b3 + k3 + t2; + b3 -= k4 + 1; + + tmp = b3 ^ b0; + b3 = (tmp >> 5) | (tmp << (64 - 5)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 37) | (tmp << (64 - 37)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 23) | (tmp << (64 - 23)); + b0 -= b1; + + tmp = b3 ^ b2; + b3 = (tmp >> 40) | (tmp << (64 - 40)); + b2 -= b3; + + tmp = b3 ^ b0; + b3 = (tmp >> 52) | (tmp << (64 - 52)); + b0 -= b3; + + tmp = b1 ^ b2; + b1 = (tmp >> 57) | (tmp << (64 - 57)); + b2 -= b1; + + tmp = b1 ^ b0; + b1 = (tmp >> 14) | (tmp << (64 - 14)); + b0 -= b1 + k0; + b1 -= k1 + t0; + + tmp = b3 ^ b2; + b3 = (tmp >> 16) | (tmp << (64 - 16)); + b2 -= b3 + k2 + t1; + b3 -= k3; + + output[0] = b0; + output[1] = b1; + output[2] = b2; + output[3] = b3; +} diff --git a/drivers/staging/skein/threefish512Block.c b/drivers/staging/skein/threefish512Block.c new file mode 100644 index 00000000000000..f428fd6e1719a5 --- /dev/null +++ b/drivers/staging/skein/threefish512Block.c @@ -0,0 +1,2223 @@ +#include +#include + + +void threefishEncrypt512(struct threefish_key *keyCtx, u64 *input, u64 *output) +{ + u64 b0 = input[0], b1 = input[1], + b2 = input[2], b3 = input[3], + b4 = input[4], b5 = input[5], + b6 = input[6], b7 = input[7]; + u64 k0 = keyCtx->key[0], k1 = keyCtx->key[1], + k2 = keyCtx->key[2], k3 = keyCtx->key[3], + k4 = keyCtx->key[4], k5 = keyCtx->key[5], + k6 = keyCtx->key[6], k7 = keyCtx->key[7], + k8 = keyCtx->key[8]; + u64 t0 = keyCtx->tweak[0], t1 = keyCtx->tweak[1], + t2 = keyCtx->tweak[2]; + + b1 += k1; + b0 += b1 + k0; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b0; + + b3 += k3; + b2 += b3 + k2; + b3 = ((b3 << 36) | (b3 >> (64 - 36))) ^ b2; + + b5 += k5 + t0; + b4 += b5 + k4; + b5 = ((b5 << 19) | (b5 >> (64 - 19))) ^ b4; + + b7 += k7; + b6 += b7 + k6 + t1; + b7 = ((b7 << 37) | (b7 >> (64 - 37))) ^ b6; + + b2 += b1; + b1 = ((b1 << 33) | (b1 >> (64 - 33))) ^ b2; + + b4 += b7; + b7 = ((b7 << 27) | (b7 >> (64 - 27))) ^ b4; + + b6 += b5; + b5 = ((b5 << 14) | (b5 >> (64 - 14))) ^ b6; + + b0 += b3; + b3 = ((b3 << 42) | (b3 >> (64 - 42))) ^ b0; + + b4 += b1; + b1 = ((b1 << 17) | (b1 >> (64 - 17))) ^ b4; + + b6 += b3; + b3 = ((b3 << 49) | (b3 >> (64 - 49))) ^ b6; + + b0 += b5; + b5 = ((b5 << 36) | (b5 >> (64 - 36))) ^ b0; + + b2 += b7; + b7 = ((b7 << 39) | (b7 >> (64 - 39))) ^ b2; + + b6 += b1; + b1 = ((b1 << 44) | (b1 >> (64 - 44))) ^ b6; + + b0 += b7; + b7 = ((b7 << 9) | (b7 >> (64 - 9))) ^ b0; + + b2 += b5; + b5 = ((b5 << 54) | (b5 >> (64 - 54))) ^ b2; + + b4 += b3; + b3 = ((b3 << 56) | (b3 >> (64 - 56))) ^ b4; + + b1 += k2; + b0 += b1 + k1; + b1 = ((b1 << 39) | (b1 >> (64 - 39))) ^ b0; + + b3 += k4; + b2 += b3 + k3; + b3 = ((b3 << 30) | (b3 >> (64 - 30))) ^ b2; + + b5 += k6 + t1; + b4 += b5 + k5; + b5 = ((b5 << 34) | (b5 >> (64 - 34))) ^ b4; + + b7 += k8 + 1; + b6 += b7 + k7 + t2; + b7 = ((b7 << 24) | (b7 >> (64 - 24))) ^ b6; + + b2 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b2; + + b4 += b7; + b7 = ((b7 << 50) | (b7 >> (64 - 50))) ^ b4; + + b6 += b5; + b5 = ((b5 << 10) | (b5 >> (64 - 10))) ^ b6; + + b0 += b3; + b3 = ((b3 << 17) | (b3 >> (64 - 17))) ^ b0; + + b4 += b1; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b4; + + b6 += b3; + b3 = ((b3 << 29) | (b3 >> (64 - 29))) ^ b6; + + b0 += b5; + b5 = ((b5 << 39) | (b5 >> (64 - 39))) ^ b0; + + b2 += b7; + b7 = ((b7 << 43) | (b7 >> (64 - 43))) ^ b2; + + b6 += b1; + b1 = ((b1 << 8) | (b1 >> (64 - 8))) ^ b6; + + b0 += b7; + b7 = ((b7 << 35) | (b7 >> (64 - 35))) ^ b0; + + b2 += b5; + b5 = ((b5 << 56) | (b5 >> (64 - 56))) ^ b2; + + b4 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b4; + + b1 += k3; + b0 += b1 + k2; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b0; + + b3 += k5; + b2 += b3 + k4; + b3 = ((b3 << 36) | (b3 >> (64 - 36))) ^ b2; + + b5 += k7 + t2; + b4 += b5 + k6; + b5 = ((b5 << 19) | (b5 >> (64 - 19))) ^ b4; + + b7 += k0 + 2; + b6 += b7 + k8 + t0; + b7 = ((b7 << 37) | (b7 >> (64 - 37))) ^ b6; + + b2 += b1; + b1 = ((b1 << 33) | (b1 >> (64 - 33))) ^ b2; + + b4 += b7; + b7 = ((b7 << 27) | (b7 >> (64 - 27))) ^ b4; + + b6 += b5; + b5 = ((b5 << 14) | (b5 >> (64 - 14))) ^ b6; + + b0 += b3; + b3 = ((b3 << 42) | (b3 >> (64 - 42))) ^ b0; + + b4 += b1; + b1 = ((b1 << 17) | (b1 >> (64 - 17))) ^ b4; + + b6 += b3; + b3 = ((b3 << 49) | (b3 >> (64 - 49))) ^ b6; + + b0 += b5; + b5 = ((b5 << 36) | (b5 >> (64 - 36))) ^ b0; + + b2 += b7; + b7 = ((b7 << 39) | (b7 >> (64 - 39))) ^ b2; + + b6 += b1; + b1 = ((b1 << 44) | (b1 >> (64 - 44))) ^ b6; + + b0 += b7; + b7 = ((b7 << 9) | (b7 >> (64 - 9))) ^ b0; + + b2 += b5; + b5 = ((b5 << 54) | (b5 >> (64 - 54))) ^ b2; + + b4 += b3; + b3 = ((b3 << 56) | (b3 >> (64 - 56))) ^ b4; + + b1 += k4; + b0 += b1 + k3; + b1 = ((b1 << 39) | (b1 >> (64 - 39))) ^ b0; + + b3 += k6; + b2 += b3 + k5; + b3 = ((b3 << 30) | (b3 >> (64 - 30))) ^ b2; + + b5 += k8 + t0; + b4 += b5 + k7; + b5 = ((b5 << 34) | (b5 >> (64 - 34))) ^ b4; + + b7 += k1 + 3; + b6 += b7 + k0 + t1; + b7 = ((b7 << 24) | (b7 >> (64 - 24))) ^ b6; + + b2 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b2; + + b4 += b7; + b7 = ((b7 << 50) | (b7 >> (64 - 50))) ^ b4; + + b6 += b5; + b5 = ((b5 << 10) | (b5 >> (64 - 10))) ^ b6; + + b0 += b3; + b3 = ((b3 << 17) | (b3 >> (64 - 17))) ^ b0; + + b4 += b1; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b4; + + b6 += b3; + b3 = ((b3 << 29) | (b3 >> (64 - 29))) ^ b6; + + b0 += b5; + b5 = ((b5 << 39) | (b5 >> (64 - 39))) ^ b0; + + b2 += b7; + b7 = ((b7 << 43) | (b7 >> (64 - 43))) ^ b2; + + b6 += b1; + b1 = ((b1 << 8) | (b1 >> (64 - 8))) ^ b6; + + b0 += b7; + b7 = ((b7 << 35) | (b7 >> (64 - 35))) ^ b0; + + b2 += b5; + b5 = ((b5 << 56) | (b5 >> (64 - 56))) ^ b2; + + b4 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b4; + + b1 += k5; + b0 += b1 + k4; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b0; + + b3 += k7; + b2 += b3 + k6; + b3 = ((b3 << 36) | (b3 >> (64 - 36))) ^ b2; + + b5 += k0 + t1; + b4 += b5 + k8; + b5 = ((b5 << 19) | (b5 >> (64 - 19))) ^ b4; + + b7 += k2 + 4; + b6 += b7 + k1 + t2; + b7 = ((b7 << 37) | (b7 >> (64 - 37))) ^ b6; + + b2 += b1; + b1 = ((b1 << 33) | (b1 >> (64 - 33))) ^ b2; + + b4 += b7; + b7 = ((b7 << 27) | (b7 >> (64 - 27))) ^ b4; + + b6 += b5; + b5 = ((b5 << 14) | (b5 >> (64 - 14))) ^ b6; + + b0 += b3; + b3 = ((b3 << 42) | (b3 >> (64 - 42))) ^ b0; + + b4 += b1; + b1 = ((b1 << 17) | (b1 >> (64 - 17))) ^ b4; + + b6 += b3; + b3 = ((b3 << 49) | (b3 >> (64 - 49))) ^ b6; + + b0 += b5; + b5 = ((b5 << 36) | (b5 >> (64 - 36))) ^ b0; + + b2 += b7; + b7 = ((b7 << 39) | (b7 >> (64 - 39))) ^ b2; + + b6 += b1; + b1 = ((b1 << 44) | (b1 >> (64 - 44))) ^ b6; + + b0 += b7; + b7 = ((b7 << 9) | (b7 >> (64 - 9))) ^ b0; + + b2 += b5; + b5 = ((b5 << 54) | (b5 >> (64 - 54))) ^ b2; + + b4 += b3; + b3 = ((b3 << 56) | (b3 >> (64 - 56))) ^ b4; + + b1 += k6; + b0 += b1 + k5; + b1 = ((b1 << 39) | (b1 >> (64 - 39))) ^ b0; + + b3 += k8; + b2 += b3 + k7; + b3 = ((b3 << 30) | (b3 >> (64 - 30))) ^ b2; + + b5 += k1 + t2; + b4 += b5 + k0; + b5 = ((b5 << 34) | (b5 >> (64 - 34))) ^ b4; + + b7 += k3 + 5; + b6 += b7 + k2 + t0; + b7 = ((b7 << 24) | (b7 >> (64 - 24))) ^ b6; + + b2 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b2; + + b4 += b7; + b7 = ((b7 << 50) | (b7 >> (64 - 50))) ^ b4; + + b6 += b5; + b5 = ((b5 << 10) | (b5 >> (64 - 10))) ^ b6; + + b0 += b3; + b3 = ((b3 << 17) | (b3 >> (64 - 17))) ^ b0; + + b4 += b1; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b4; + + b6 += b3; + b3 = ((b3 << 29) | (b3 >> (64 - 29))) ^ b6; + + b0 += b5; + b5 = ((b5 << 39) | (b5 >> (64 - 39))) ^ b0; + + b2 += b7; + b7 = ((b7 << 43) | (b7 >> (64 - 43))) ^ b2; + + b6 += b1; + b1 = ((b1 << 8) | (b1 >> (64 - 8))) ^ b6; + + b0 += b7; + b7 = ((b7 << 35) | (b7 >> (64 - 35))) ^ b0; + + b2 += b5; + b5 = ((b5 << 56) | (b5 >> (64 - 56))) ^ b2; + + b4 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b4; + + b1 += k7; + b0 += b1 + k6; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b0; + + b3 += k0; + b2 += b3 + k8; + b3 = ((b3 << 36) | (b3 >> (64 - 36))) ^ b2; + + b5 += k2 + t0; + b4 += b5 + k1; + b5 = ((b5 << 19) | (b5 >> (64 - 19))) ^ b4; + + b7 += k4 + 6; + b6 += b7 + k3 + t1; + b7 = ((b7 << 37) | (b7 >> (64 - 37))) ^ b6; + + b2 += b1; + b1 = ((b1 << 33) | (b1 >> (64 - 33))) ^ b2; + + b4 += b7; + b7 = ((b7 << 27) | (b7 >> (64 - 27))) ^ b4; + + b6 += b5; + b5 = ((b5 << 14) | (b5 >> (64 - 14))) ^ b6; + + b0 += b3; + b3 = ((b3 << 42) | (b3 >> (64 - 42))) ^ b0; + + b4 += b1; + b1 = ((b1 << 17) | (b1 >> (64 - 17))) ^ b4; + + b6 += b3; + b3 = ((b3 << 49) | (b3 >> (64 - 49))) ^ b6; + + b0 += b5; + b5 = ((b5 << 36) | (b5 >> (64 - 36))) ^ b0; + + b2 += b7; + b7 = ((b7 << 39) | (b7 >> (64 - 39))) ^ b2; + + b6 += b1; + b1 = ((b1 << 44) | (b1 >> (64 - 44))) ^ b6; + + b0 += b7; + b7 = ((b7 << 9) | (b7 >> (64 - 9))) ^ b0; + + b2 += b5; + b5 = ((b5 << 54) | (b5 >> (64 - 54))) ^ b2; + + b4 += b3; + b3 = ((b3 << 56) | (b3 >> (64 - 56))) ^ b4; + + b1 += k8; + b0 += b1 + k7; + b1 = ((b1 << 39) | (b1 >> (64 - 39))) ^ b0; + + b3 += k1; + b2 += b3 + k0; + b3 = ((b3 << 30) | (b3 >> (64 - 30))) ^ b2; + + b5 += k3 + t1; + b4 += b5 + k2; + b5 = ((b5 << 34) | (b5 >> (64 - 34))) ^ b4; + + b7 += k5 + 7; + b6 += b7 + k4 + t2; + b7 = ((b7 << 24) | (b7 >> (64 - 24))) ^ b6; + + b2 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b2; + + b4 += b7; + b7 = ((b7 << 50) | (b7 >> (64 - 50))) ^ b4; + + b6 += b5; + b5 = ((b5 << 10) | (b5 >> (64 - 10))) ^ b6; + + b0 += b3; + b3 = ((b3 << 17) | (b3 >> (64 - 17))) ^ b0; + + b4 += b1; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b4; + + b6 += b3; + b3 = ((b3 << 29) | (b3 >> (64 - 29))) ^ b6; + + b0 += b5; + b5 = ((b5 << 39) | (b5 >> (64 - 39))) ^ b0; + + b2 += b7; + b7 = ((b7 << 43) | (b7 >> (64 - 43))) ^ b2; + + b6 += b1; + b1 = ((b1 << 8) | (b1 >> (64 - 8))) ^ b6; + + b0 += b7; + b7 = ((b7 << 35) | (b7 >> (64 - 35))) ^ b0; + + b2 += b5; + b5 = ((b5 << 56) | (b5 >> (64 - 56))) ^ b2; + + b4 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b4; + + b1 += k0; + b0 += b1 + k8; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b0; + + b3 += k2; + b2 += b3 + k1; + b3 = ((b3 << 36) | (b3 >> (64 - 36))) ^ b2; + + b5 += k4 + t2; + b4 += b5 + k3; + b5 = ((b5 << 19) | (b5 >> (64 - 19))) ^ b4; + + b7 += k6 + 8; + b6 += b7 + k5 + t0; + b7 = ((b7 << 37) | (b7 >> (64 - 37))) ^ b6; + + b2 += b1; + b1 = ((b1 << 33) | (b1 >> (64 - 33))) ^ b2; + + b4 += b7; + b7 = ((b7 << 27) | (b7 >> (64 - 27))) ^ b4; + + b6 += b5; + b5 = ((b5 << 14) | (b5 >> (64 - 14))) ^ b6; + + b0 += b3; + b3 = ((b3 << 42) | (b3 >> (64 - 42))) ^ b0; + + b4 += b1; + b1 = ((b1 << 17) | (b1 >> (64 - 17))) ^ b4; + + b6 += b3; + b3 = ((b3 << 49) | (b3 >> (64 - 49))) ^ b6; + + b0 += b5; + b5 = ((b5 << 36) | (b5 >> (64 - 36))) ^ b0; + + b2 += b7; + b7 = ((b7 << 39) | (b7 >> (64 - 39))) ^ b2; + + b6 += b1; + b1 = ((b1 << 44) | (b1 >> (64 - 44))) ^ b6; + + b0 += b7; + b7 = ((b7 << 9) | (b7 >> (64 - 9))) ^ b0; + + b2 += b5; + b5 = ((b5 << 54) | (b5 >> (64 - 54))) ^ b2; + + b4 += b3; + b3 = ((b3 << 56) | (b3 >> (64 - 56))) ^ b4; + + b1 += k1; + b0 += b1 + k0; + b1 = ((b1 << 39) | (b1 >> (64 - 39))) ^ b0; + + b3 += k3; + b2 += b3 + k2; + b3 = ((b3 << 30) | (b3 >> (64 - 30))) ^ b2; + + b5 += k5 + t0; + b4 += b5 + k4; + b5 = ((b5 << 34) | (b5 >> (64 - 34))) ^ b4; + + b7 += k7 + 9; + b6 += b7 + k6 + t1; + b7 = ((b7 << 24) | (b7 >> (64 - 24))) ^ b6; + + b2 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b2; + + b4 += b7; + b7 = ((b7 << 50) | (b7 >> (64 - 50))) ^ b4; + + b6 += b5; + b5 = ((b5 << 10) | (b5 >> (64 - 10))) ^ b6; + + b0 += b3; + b3 = ((b3 << 17) | (b3 >> (64 - 17))) ^ b0; + + b4 += b1; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b4; + + b6 += b3; + b3 = ((b3 << 29) | (b3 >> (64 - 29))) ^ b6; + + b0 += b5; + b5 = ((b5 << 39) | (b5 >> (64 - 39))) ^ b0; + + b2 += b7; + b7 = ((b7 << 43) | (b7 >> (64 - 43))) ^ b2; + + b6 += b1; + b1 = ((b1 << 8) | (b1 >> (64 - 8))) ^ b6; + + b0 += b7; + b7 = ((b7 << 35) | (b7 >> (64 - 35))) ^ b0; + + b2 += b5; + b5 = ((b5 << 56) | (b5 >> (64 - 56))) ^ b2; + + b4 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b4; + + b1 += k2; + b0 += b1 + k1; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b0; + + b3 += k4; + b2 += b3 + k3; + b3 = ((b3 << 36) | (b3 >> (64 - 36))) ^ b2; + + b5 += k6 + t1; + b4 += b5 + k5; + b5 = ((b5 << 19) | (b5 >> (64 - 19))) ^ b4; + + b7 += k8 + 10; + b6 += b7 + k7 + t2; + b7 = ((b7 << 37) | (b7 >> (64 - 37))) ^ b6; + + b2 += b1; + b1 = ((b1 << 33) | (b1 >> (64 - 33))) ^ b2; + + b4 += b7; + b7 = ((b7 << 27) | (b7 >> (64 - 27))) ^ b4; + + b6 += b5; + b5 = ((b5 << 14) | (b5 >> (64 - 14))) ^ b6; + + b0 += b3; + b3 = ((b3 << 42) | (b3 >> (64 - 42))) ^ b0; + + b4 += b1; + b1 = ((b1 << 17) | (b1 >> (64 - 17))) ^ b4; + + b6 += b3; + b3 = ((b3 << 49) | (b3 >> (64 - 49))) ^ b6; + + b0 += b5; + b5 = ((b5 << 36) | (b5 >> (64 - 36))) ^ b0; + + b2 += b7; + b7 = ((b7 << 39) | (b7 >> (64 - 39))) ^ b2; + + b6 += b1; + b1 = ((b1 << 44) | (b1 >> (64 - 44))) ^ b6; + + b0 += b7; + b7 = ((b7 << 9) | (b7 >> (64 - 9))) ^ b0; + + b2 += b5; + b5 = ((b5 << 54) | (b5 >> (64 - 54))) ^ b2; + + b4 += b3; + b3 = ((b3 << 56) | (b3 >> (64 - 56))) ^ b4; + + b1 += k3; + b0 += b1 + k2; + b1 = ((b1 << 39) | (b1 >> (64 - 39))) ^ b0; + + b3 += k5; + b2 += b3 + k4; + b3 = ((b3 << 30) | (b3 >> (64 - 30))) ^ b2; + + b5 += k7 + t2; + b4 += b5 + k6; + b5 = ((b5 << 34) | (b5 >> (64 - 34))) ^ b4; + + b7 += k0 + 11; + b6 += b7 + k8 + t0; + b7 = ((b7 << 24) | (b7 >> (64 - 24))) ^ b6; + + b2 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b2; + + b4 += b7; + b7 = ((b7 << 50) | (b7 >> (64 - 50))) ^ b4; + + b6 += b5; + b5 = ((b5 << 10) | (b5 >> (64 - 10))) ^ b6; + + b0 += b3; + b3 = ((b3 << 17) | (b3 >> (64 - 17))) ^ b0; + + b4 += b1; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b4; + + b6 += b3; + b3 = ((b3 << 29) | (b3 >> (64 - 29))) ^ b6; + + b0 += b5; + b5 = ((b5 << 39) | (b5 >> (64 - 39))) ^ b0; + + b2 += b7; + b7 = ((b7 << 43) | (b7 >> (64 - 43))) ^ b2; + + b6 += b1; + b1 = ((b1 << 8) | (b1 >> (64 - 8))) ^ b6; + + b0 += b7; + b7 = ((b7 << 35) | (b7 >> (64 - 35))) ^ b0; + + b2 += b5; + b5 = ((b5 << 56) | (b5 >> (64 - 56))) ^ b2; + + b4 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b4; + + b1 += k4; + b0 += b1 + k3; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b0; + + b3 += k6; + b2 += b3 + k5; + b3 = ((b3 << 36) | (b3 >> (64 - 36))) ^ b2; + + b5 += k8 + t0; + b4 += b5 + k7; + b5 = ((b5 << 19) | (b5 >> (64 - 19))) ^ b4; + + b7 += k1 + 12; + b6 += b7 + k0 + t1; + b7 = ((b7 << 37) | (b7 >> (64 - 37))) ^ b6; + + b2 += b1; + b1 = ((b1 << 33) | (b1 >> (64 - 33))) ^ b2; + + b4 += b7; + b7 = ((b7 << 27) | (b7 >> (64 - 27))) ^ b4; + + b6 += b5; + b5 = ((b5 << 14) | (b5 >> (64 - 14))) ^ b6; + + b0 += b3; + b3 = ((b3 << 42) | (b3 >> (64 - 42))) ^ b0; + + b4 += b1; + b1 = ((b1 << 17) | (b1 >> (64 - 17))) ^ b4; + + b6 += b3; + b3 = ((b3 << 49) | (b3 >> (64 - 49))) ^ b6; + + b0 += b5; + b5 = ((b5 << 36) | (b5 >> (64 - 36))) ^ b0; + + b2 += b7; + b7 = ((b7 << 39) | (b7 >> (64 - 39))) ^ b2; + + b6 += b1; + b1 = ((b1 << 44) | (b1 >> (64 - 44))) ^ b6; + + b0 += b7; + b7 = ((b7 << 9) | (b7 >> (64 - 9))) ^ b0; + + b2 += b5; + b5 = ((b5 << 54) | (b5 >> (64 - 54))) ^ b2; + + b4 += b3; + b3 = ((b3 << 56) | (b3 >> (64 - 56))) ^ b4; + + b1 += k5; + b0 += b1 + k4; + b1 = ((b1 << 39) | (b1 >> (64 - 39))) ^ b0; + + b3 += k7; + b2 += b3 + k6; + b3 = ((b3 << 30) | (b3 >> (64 - 30))) ^ b2; + + b5 += k0 + t1; + b4 += b5 + k8; + b5 = ((b5 << 34) | (b5 >> (64 - 34))) ^ b4; + + b7 += k2 + 13; + b6 += b7 + k1 + t2; + b7 = ((b7 << 24) | (b7 >> (64 - 24))) ^ b6; + + b2 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b2; + + b4 += b7; + b7 = ((b7 << 50) | (b7 >> (64 - 50))) ^ b4; + + b6 += b5; + b5 = ((b5 << 10) | (b5 >> (64 - 10))) ^ b6; + + b0 += b3; + b3 = ((b3 << 17) | (b3 >> (64 - 17))) ^ b0; + + b4 += b1; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b4; + + b6 += b3; + b3 = ((b3 << 29) | (b3 >> (64 - 29))) ^ b6; + + b0 += b5; + b5 = ((b5 << 39) | (b5 >> (64 - 39))) ^ b0; + + b2 += b7; + b7 = ((b7 << 43) | (b7 >> (64 - 43))) ^ b2; + + b6 += b1; + b1 = ((b1 << 8) | (b1 >> (64 - 8))) ^ b6; + + b0 += b7; + b7 = ((b7 << 35) | (b7 >> (64 - 35))) ^ b0; + + b2 += b5; + b5 = ((b5 << 56) | (b5 >> (64 - 56))) ^ b2; + + b4 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b4; + + b1 += k6; + b0 += b1 + k5; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b0; + + b3 += k8; + b2 += b3 + k7; + b3 = ((b3 << 36) | (b3 >> (64 - 36))) ^ b2; + + b5 += k1 + t2; + b4 += b5 + k0; + b5 = ((b5 << 19) | (b5 >> (64 - 19))) ^ b4; + + b7 += k3 + 14; + b6 += b7 + k2 + t0; + b7 = ((b7 << 37) | (b7 >> (64 - 37))) ^ b6; + + b2 += b1; + b1 = ((b1 << 33) | (b1 >> (64 - 33))) ^ b2; + + b4 += b7; + b7 = ((b7 << 27) | (b7 >> (64 - 27))) ^ b4; + + b6 += b5; + b5 = ((b5 << 14) | (b5 >> (64 - 14))) ^ b6; + + b0 += b3; + b3 = ((b3 << 42) | (b3 >> (64 - 42))) ^ b0; + + b4 += b1; + b1 = ((b1 << 17) | (b1 >> (64 - 17))) ^ b4; + + b6 += b3; + b3 = ((b3 << 49) | (b3 >> (64 - 49))) ^ b6; + + b0 += b5; + b5 = ((b5 << 36) | (b5 >> (64 - 36))) ^ b0; + + b2 += b7; + b7 = ((b7 << 39) | (b7 >> (64 - 39))) ^ b2; + + b6 += b1; + b1 = ((b1 << 44) | (b1 >> (64 - 44))) ^ b6; + + b0 += b7; + b7 = ((b7 << 9) | (b7 >> (64 - 9))) ^ b0; + + b2 += b5; + b5 = ((b5 << 54) | (b5 >> (64 - 54))) ^ b2; + + b4 += b3; + b3 = ((b3 << 56) | (b3 >> (64 - 56))) ^ b4; + + b1 += k7; + b0 += b1 + k6; + b1 = ((b1 << 39) | (b1 >> (64 - 39))) ^ b0; + + b3 += k0; + b2 += b3 + k8; + b3 = ((b3 << 30) | (b3 >> (64 - 30))) ^ b2; + + b5 += k2 + t0; + b4 += b5 + k1; + b5 = ((b5 << 34) | (b5 >> (64 - 34))) ^ b4; + + b7 += k4 + 15; + b6 += b7 + k3 + t1; + b7 = ((b7 << 24) | (b7 >> (64 - 24))) ^ b6; + + b2 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b2; + + b4 += b7; + b7 = ((b7 << 50) | (b7 >> (64 - 50))) ^ b4; + + b6 += b5; + b5 = ((b5 << 10) | (b5 >> (64 - 10))) ^ b6; + + b0 += b3; + b3 = ((b3 << 17) | (b3 >> (64 - 17))) ^ b0; + + b4 += b1; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b4; + + b6 += b3; + b3 = ((b3 << 29) | (b3 >> (64 - 29))) ^ b6; + + b0 += b5; + b5 = ((b5 << 39) | (b5 >> (64 - 39))) ^ b0; + + b2 += b7; + b7 = ((b7 << 43) | (b7 >> (64 - 43))) ^ b2; + + b6 += b1; + b1 = ((b1 << 8) | (b1 >> (64 - 8))) ^ b6; + + b0 += b7; + b7 = ((b7 << 35) | (b7 >> (64 - 35))) ^ b0; + + b2 += b5; + b5 = ((b5 << 56) | (b5 >> (64 - 56))) ^ b2; + + b4 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b4; + + b1 += k8; + b0 += b1 + k7; + b1 = ((b1 << 46) | (b1 >> (64 - 46))) ^ b0; + + b3 += k1; + b2 += b3 + k0; + b3 = ((b3 << 36) | (b3 >> (64 - 36))) ^ b2; + + b5 += k3 + t1; + b4 += b5 + k2; + b5 = ((b5 << 19) | (b5 >> (64 - 19))) ^ b4; + + b7 += k5 + 16; + b6 += b7 + k4 + t2; + b7 = ((b7 << 37) | (b7 >> (64 - 37))) ^ b6; + + b2 += b1; + b1 = ((b1 << 33) | (b1 >> (64 - 33))) ^ b2; + + b4 += b7; + b7 = ((b7 << 27) | (b7 >> (64 - 27))) ^ b4; + + b6 += b5; + b5 = ((b5 << 14) | (b5 >> (64 - 14))) ^ b6; + + b0 += b3; + b3 = ((b3 << 42) | (b3 >> (64 - 42))) ^ b0; + + b4 += b1; + b1 = ((b1 << 17) | (b1 >> (64 - 17))) ^ b4; + + b6 += b3; + b3 = ((b3 << 49) | (b3 >> (64 - 49))) ^ b6; + + b0 += b5; + b5 = ((b5 << 36) | (b5 >> (64 - 36))) ^ b0; + + b2 += b7; + b7 = ((b7 << 39) | (b7 >> (64 - 39))) ^ b2; + + b6 += b1; + b1 = ((b1 << 44) | (b1 >> (64 - 44))) ^ b6; + + b0 += b7; + b7 = ((b7 << 9) | (b7 >> (64 - 9))) ^ b0; + + b2 += b5; + b5 = ((b5 << 54) | (b5 >> (64 - 54))) ^ b2; + + b4 += b3; + b3 = ((b3 << 56) | (b3 >> (64 - 56))) ^ b4; + + b1 += k0; + b0 += b1 + k8; + b1 = ((b1 << 39) | (b1 >> (64 - 39))) ^ b0; + + b3 += k2; + b2 += b3 + k1; + b3 = ((b3 << 30) | (b3 >> (64 - 30))) ^ b2; + + b5 += k4 + t2; + b4 += b5 + k3; + b5 = ((b5 << 34) | (b5 >> (64 - 34))) ^ b4; + + b7 += k6 + 17; + b6 += b7 + k5 + t0; + b7 = ((b7 << 24) | (b7 >> (64 - 24))) ^ b6; + + b2 += b1; + b1 = ((b1 << 13) | (b1 >> (64 - 13))) ^ b2; + + b4 += b7; + b7 = ((b7 << 50) | (b7 >> (64 - 50))) ^ b4; + + b6 += b5; + b5 = ((b5 << 10) | (b5 >> (64 - 10))) ^ b6; + + b0 += b3; + b3 = ((b3 << 17) | (b3 >> (64 - 17))) ^ b0; + + b4 += b1; + b1 = ((b1 << 25) | (b1 >> (64 - 25))) ^ b4; + + b6 += b3; + b3 = ((b3 << 29) | (b3 >> (64 - 29))) ^ b6; + + b0 += b5; + b5 = ((b5 << 39) | (b5 >> (64 - 39))) ^ b0; + + b2 += b7; + b7 = ((b7 << 43) | (b7 >> (64 - 43))) ^ b2; + + b6 += b1; + b1 = ((b1 << 8) | (b1 >> (64 - 8))) ^ b6; + + b0 += b7; + b7 = ((b7 << 35) | (b7 >> (64 - 35))) ^ b0; + + b2 += b5; + b5 = ((b5 << 56) | (b5 >> (64 - 56))) ^ b2; + + b4 += b3; + b3 = ((b3 << 22) | (b3 >> (64 - 22))) ^ b4; + + output[0] = b0 + k0; + output[1] = b1 + k1; + output[2] = b2 + k2; + output[3] = b3 + k3; + output[4] = b4 + k4; + output[5] = b5 + k5 + t0; + output[6] = b6 + k6 + t1; + output[7] = b7 + k7 + 18; +} + +void threefishDecrypt512(struct threefish_key *keyCtx, u64 *input, u64 *output) +{ + u64 b0 = input[0], b1 = input[1], + b2 = input[2], b3 = input[3], + b4 = input[4], b5 = input[5], + b6 = input[6], b7 = input[7]; + u64 k0 = keyCtx->key[0], k1 = keyCtx->key[1], + k2 = keyCtx->key[2], k3 = keyCtx->key[3], + k4 = keyCtx->key[4], k5 = keyCtx->key[5], + k6 = keyCtx->key[6], k7 = keyCtx->key[7], + k8 = keyCtx->key[8]; + u64 t0 = keyCtx->tweak[0], t1 = keyCtx->tweak[1], + t2 = keyCtx->tweak[2]; + + u64 tmp; + + b0 -= k0; + b1 -= k1; + b2 -= k2; + b3 -= k3; + b4 -= k4; + b5 -= k5 + t0; + b6 -= k6 + t1; + b7 -= k7 + 18; + + tmp = b3 ^ b4; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 56) | (tmp << (64 - 56)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 35) | (tmp << (64 - 35)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 8) | (tmp << (64 - 8)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 43) | (tmp << (64 - 43)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 29) | (tmp << (64 - 29)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 17) | (tmp << (64 - 17)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 50) | (tmp << (64 - 50)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 24) | (tmp << (64 - 24)); + b6 -= b7 + k5 + t0; + b7 -= k6 + 17; + + tmp = b5 ^ b4; + b5 = (tmp >> 34) | (tmp << (64 - 34)); + b4 -= b5 + k3; + b5 -= k4 + t2; + + tmp = b3 ^ b2; + b3 = (tmp >> 30) | (tmp << (64 - 30)); + b2 -= b3 + k1; + b3 -= k2; + + tmp = b1 ^ b0; + b1 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b1 + k8; + b1 -= k0; + + tmp = b3 ^ b4; + b3 = (tmp >> 56) | (tmp << (64 - 56)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 54) | (tmp << (64 - 54)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 44) | (tmp << (64 - 44)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 39) | (tmp << (64 - 39)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 36) | (tmp << (64 - 36)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 49) | (tmp << (64 - 49)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 17) | (tmp << (64 - 17)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 42) | (tmp << (64 - 42)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 14) | (tmp << (64 - 14)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 27) | (tmp << (64 - 27)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 37) | (tmp << (64 - 37)); + b6 -= b7 + k4 + t2; + b7 -= k5 + 16; + + tmp = b5 ^ b4; + b5 = (tmp >> 19) | (tmp << (64 - 19)); + b4 -= b5 + k2; + b5 -= k3 + t1; + + tmp = b3 ^ b2; + b3 = (tmp >> 36) | (tmp << (64 - 36)); + b2 -= b3 + k0; + b3 -= k1; + + tmp = b1 ^ b0; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b1 + k7; + b1 -= k8; + + tmp = b3 ^ b4; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 56) | (tmp << (64 - 56)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 35) | (tmp << (64 - 35)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 8) | (tmp << (64 - 8)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 43) | (tmp << (64 - 43)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 29) | (tmp << (64 - 29)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 17) | (tmp << (64 - 17)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 50) | (tmp << (64 - 50)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 24) | (tmp << (64 - 24)); + b6 -= b7 + k3 + t1; + b7 -= k4 + 15; + + tmp = b5 ^ b4; + b5 = (tmp >> 34) | (tmp << (64 - 34)); + b4 -= b5 + k1; + b5 -= k2 + t0; + + tmp = b3 ^ b2; + b3 = (tmp >> 30) | (tmp << (64 - 30)); + b2 -= b3 + k8; + b3 -= k0; + + tmp = b1 ^ b0; + b1 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b1 + k6; + b1 -= k7; + + tmp = b3 ^ b4; + b3 = (tmp >> 56) | (tmp << (64 - 56)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 54) | (tmp << (64 - 54)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 44) | (tmp << (64 - 44)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 39) | (tmp << (64 - 39)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 36) | (tmp << (64 - 36)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 49) | (tmp << (64 - 49)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 17) | (tmp << (64 - 17)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 42) | (tmp << (64 - 42)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 14) | (tmp << (64 - 14)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 27) | (tmp << (64 - 27)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 37) | (tmp << (64 - 37)); + b6 -= b7 + k2 + t0; + b7 -= k3 + 14; + + tmp = b5 ^ b4; + b5 = (tmp >> 19) | (tmp << (64 - 19)); + b4 -= b5 + k0; + b5 -= k1 + t2; + + tmp = b3 ^ b2; + b3 = (tmp >> 36) | (tmp << (64 - 36)); + b2 -= b3 + k7; + b3 -= k8; + + tmp = b1 ^ b0; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b1 + k5; + b1 -= k6; + + tmp = b3 ^ b4; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 56) | (tmp << (64 - 56)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 35) | (tmp << (64 - 35)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 8) | (tmp << (64 - 8)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 43) | (tmp << (64 - 43)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 29) | (tmp << (64 - 29)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 17) | (tmp << (64 - 17)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 50) | (tmp << (64 - 50)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 24) | (tmp << (64 - 24)); + b6 -= b7 + k1 + t2; + b7 -= k2 + 13; + + tmp = b5 ^ b4; + b5 = (tmp >> 34) | (tmp << (64 - 34)); + b4 -= b5 + k8; + b5 -= k0 + t1; + + tmp = b3 ^ b2; + b3 = (tmp >> 30) | (tmp << (64 - 30)); + b2 -= b3 + k6; + b3 -= k7; + + tmp = b1 ^ b0; + b1 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b1 + k4; + b1 -= k5; + + tmp = b3 ^ b4; + b3 = (tmp >> 56) | (tmp << (64 - 56)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 54) | (tmp << (64 - 54)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 44) | (tmp << (64 - 44)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 39) | (tmp << (64 - 39)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 36) | (tmp << (64 - 36)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 49) | (tmp << (64 - 49)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 17) | (tmp << (64 - 17)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 42) | (tmp << (64 - 42)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 14) | (tmp << (64 - 14)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 27) | (tmp << (64 - 27)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 37) | (tmp << (64 - 37)); + b6 -= b7 + k0 + t1; + b7 -= k1 + 12; + + tmp = b5 ^ b4; + b5 = (tmp >> 19) | (tmp << (64 - 19)); + b4 -= b5 + k7; + b5 -= k8 + t0; + + tmp = b3 ^ b2; + b3 = (tmp >> 36) | (tmp << (64 - 36)); + b2 -= b3 + k5; + b3 -= k6; + + tmp = b1 ^ b0; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b1 + k3; + b1 -= k4; + + tmp = b3 ^ b4; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 56) | (tmp << (64 - 56)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 35) | (tmp << (64 - 35)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 8) | (tmp << (64 - 8)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 43) | (tmp << (64 - 43)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 29) | (tmp << (64 - 29)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 17) | (tmp << (64 - 17)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 50) | (tmp << (64 - 50)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 24) | (tmp << (64 - 24)); + b6 -= b7 + k8 + t0; + b7 -= k0 + 11; + + tmp = b5 ^ b4; + b5 = (tmp >> 34) | (tmp << (64 - 34)); + b4 -= b5 + k6; + b5 -= k7 + t2; + + tmp = b3 ^ b2; + b3 = (tmp >> 30) | (tmp << (64 - 30)); + b2 -= b3 + k4; + b3 -= k5; + + tmp = b1 ^ b0; + b1 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b1 + k2; + b1 -= k3; + + tmp = b3 ^ b4; + b3 = (tmp >> 56) | (tmp << (64 - 56)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 54) | (tmp << (64 - 54)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 44) | (tmp << (64 - 44)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 39) | (tmp << (64 - 39)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 36) | (tmp << (64 - 36)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 49) | (tmp << (64 - 49)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 17) | (tmp << (64 - 17)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 42) | (tmp << (64 - 42)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 14) | (tmp << (64 - 14)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 27) | (tmp << (64 - 27)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 37) | (tmp << (64 - 37)); + b6 -= b7 + k7 + t2; + b7 -= k8 + 10; + + tmp = b5 ^ b4; + b5 = (tmp >> 19) | (tmp << (64 - 19)); + b4 -= b5 + k5; + b5 -= k6 + t1; + + tmp = b3 ^ b2; + b3 = (tmp >> 36) | (tmp << (64 - 36)); + b2 -= b3 + k3; + b3 -= k4; + + tmp = b1 ^ b0; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b1 + k1; + b1 -= k2; + + tmp = b3 ^ b4; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 56) | (tmp << (64 - 56)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 35) | (tmp << (64 - 35)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 8) | (tmp << (64 - 8)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 43) | (tmp << (64 - 43)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 29) | (tmp << (64 - 29)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 17) | (tmp << (64 - 17)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 50) | (tmp << (64 - 50)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 24) | (tmp << (64 - 24)); + b6 -= b7 + k6 + t1; + b7 -= k7 + 9; + + tmp = b5 ^ b4; + b5 = (tmp >> 34) | (tmp << (64 - 34)); + b4 -= b5 + k4; + b5 -= k5 + t0; + + tmp = b3 ^ b2; + b3 = (tmp >> 30) | (tmp << (64 - 30)); + b2 -= b3 + k2; + b3 -= k3; + + tmp = b1 ^ b0; + b1 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b1 + k0; + b1 -= k1; + + tmp = b3 ^ b4; + b3 = (tmp >> 56) | (tmp << (64 - 56)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 54) | (tmp << (64 - 54)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 44) | (tmp << (64 - 44)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 39) | (tmp << (64 - 39)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 36) | (tmp << (64 - 36)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 49) | (tmp << (64 - 49)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 17) | (tmp << (64 - 17)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 42) | (tmp << (64 - 42)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 14) | (tmp << (64 - 14)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 27) | (tmp << (64 - 27)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 37) | (tmp << (64 - 37)); + b6 -= b7 + k5 + t0; + b7 -= k6 + 8; + + tmp = b5 ^ b4; + b5 = (tmp >> 19) | (tmp << (64 - 19)); + b4 -= b5 + k3; + b5 -= k4 + t2; + + tmp = b3 ^ b2; + b3 = (tmp >> 36) | (tmp << (64 - 36)); + b2 -= b3 + k1; + b3 -= k2; + + tmp = b1 ^ b0; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b1 + k8; + b1 -= k0; + + tmp = b3 ^ b4; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 56) | (tmp << (64 - 56)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 35) | (tmp << (64 - 35)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 8) | (tmp << (64 - 8)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 43) | (tmp << (64 - 43)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 29) | (tmp << (64 - 29)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 17) | (tmp << (64 - 17)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 50) | (tmp << (64 - 50)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 24) | (tmp << (64 - 24)); + b6 -= b7 + k4 + t2; + b7 -= k5 + 7; + + tmp = b5 ^ b4; + b5 = (tmp >> 34) | (tmp << (64 - 34)); + b4 -= b5 + k2; + b5 -= k3 + t1; + + tmp = b3 ^ b2; + b3 = (tmp >> 30) | (tmp << (64 - 30)); + b2 -= b3 + k0; + b3 -= k1; + + tmp = b1 ^ b0; + b1 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b1 + k7; + b1 -= k8; + + tmp = b3 ^ b4; + b3 = (tmp >> 56) | (tmp << (64 - 56)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 54) | (tmp << (64 - 54)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 44) | (tmp << (64 - 44)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 39) | (tmp << (64 - 39)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 36) | (tmp << (64 - 36)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 49) | (tmp << (64 - 49)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 17) | (tmp << (64 - 17)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 42) | (tmp << (64 - 42)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 14) | (tmp << (64 - 14)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 27) | (tmp << (64 - 27)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 37) | (tmp << (64 - 37)); + b6 -= b7 + k3 + t1; + b7 -= k4 + 6; + + tmp = b5 ^ b4; + b5 = (tmp >> 19) | (tmp << (64 - 19)); + b4 -= b5 + k1; + b5 -= k2 + t0; + + tmp = b3 ^ b2; + b3 = (tmp >> 36) | (tmp << (64 - 36)); + b2 -= b3 + k8; + b3 -= k0; + + tmp = b1 ^ b0; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b1 + k6; + b1 -= k7; + + tmp = b3 ^ b4; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 56) | (tmp << (64 - 56)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 35) | (tmp << (64 - 35)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 8) | (tmp << (64 - 8)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 43) | (tmp << (64 - 43)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 29) | (tmp << (64 - 29)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 17) | (tmp << (64 - 17)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 50) | (tmp << (64 - 50)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 24) | (tmp << (64 - 24)); + b6 -= b7 + k2 + t0; + b7 -= k3 + 5; + + tmp = b5 ^ b4; + b5 = (tmp >> 34) | (tmp << (64 - 34)); + b4 -= b5 + k0; + b5 -= k1 + t2; + + tmp = b3 ^ b2; + b3 = (tmp >> 30) | (tmp << (64 - 30)); + b2 -= b3 + k7; + b3 -= k8; + + tmp = b1 ^ b0; + b1 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b1 + k5; + b1 -= k6; + + tmp = b3 ^ b4; + b3 = (tmp >> 56) | (tmp << (64 - 56)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 54) | (tmp << (64 - 54)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 44) | (tmp << (64 - 44)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 39) | (tmp << (64 - 39)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 36) | (tmp << (64 - 36)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 49) | (tmp << (64 - 49)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 17) | (tmp << (64 - 17)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 42) | (tmp << (64 - 42)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 14) | (tmp << (64 - 14)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 27) | (tmp << (64 - 27)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 37) | (tmp << (64 - 37)); + b6 -= b7 + k1 + t2; + b7 -= k2 + 4; + + tmp = b5 ^ b4; + b5 = (tmp >> 19) | (tmp << (64 - 19)); + b4 -= b5 + k8; + b5 -= k0 + t1; + + tmp = b3 ^ b2; + b3 = (tmp >> 36) | (tmp << (64 - 36)); + b2 -= b3 + k6; + b3 -= k7; + + tmp = b1 ^ b0; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b1 + k4; + b1 -= k5; + + tmp = b3 ^ b4; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 56) | (tmp << (64 - 56)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 35) | (tmp << (64 - 35)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 8) | (tmp << (64 - 8)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 43) | (tmp << (64 - 43)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 29) | (tmp << (64 - 29)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 17) | (tmp << (64 - 17)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 50) | (tmp << (64 - 50)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 24) | (tmp << (64 - 24)); + b6 -= b7 + k0 + t1; + b7 -= k1 + 3; + + tmp = b5 ^ b4; + b5 = (tmp >> 34) | (tmp << (64 - 34)); + b4 -= b5 + k7; + b5 -= k8 + t0; + + tmp = b3 ^ b2; + b3 = (tmp >> 30) | (tmp << (64 - 30)); + b2 -= b3 + k5; + b3 -= k6; + + tmp = b1 ^ b0; + b1 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b1 + k3; + b1 -= k4; + + tmp = b3 ^ b4; + b3 = (tmp >> 56) | (tmp << (64 - 56)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 54) | (tmp << (64 - 54)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 44) | (tmp << (64 - 44)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 39) | (tmp << (64 - 39)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 36) | (tmp << (64 - 36)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 49) | (tmp << (64 - 49)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 17) | (tmp << (64 - 17)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 42) | (tmp << (64 - 42)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 14) | (tmp << (64 - 14)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 27) | (tmp << (64 - 27)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 37) | (tmp << (64 - 37)); + b6 -= b7 + k8 + t0; + b7 -= k0 + 2; + + tmp = b5 ^ b4; + b5 = (tmp >> 19) | (tmp << (64 - 19)); + b4 -= b5 + k6; + b5 -= k7 + t2; + + tmp = b3 ^ b2; + b3 = (tmp >> 36) | (tmp << (64 - 36)); + b2 -= b3 + k4; + b3 -= k5; + + tmp = b1 ^ b0; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b1 + k2; + b1 -= k3; + + tmp = b3 ^ b4; + b3 = (tmp >> 22) | (tmp << (64 - 22)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 56) | (tmp << (64 - 56)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 35) | (tmp << (64 - 35)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 8) | (tmp << (64 - 8)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 43) | (tmp << (64 - 43)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 29) | (tmp << (64 - 29)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 25) | (tmp << (64 - 25)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 17) | (tmp << (64 - 17)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 10) | (tmp << (64 - 10)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 50) | (tmp << (64 - 50)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 13) | (tmp << (64 - 13)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 24) | (tmp << (64 - 24)); + b6 -= b7 + k7 + t2; + b7 -= k8 + 1; + + tmp = b5 ^ b4; + b5 = (tmp >> 34) | (tmp << (64 - 34)); + b4 -= b5 + k5; + b5 -= k6 + t1; + + tmp = b3 ^ b2; + b3 = (tmp >> 30) | (tmp << (64 - 30)); + b2 -= b3 + k3; + b3 -= k4; + + tmp = b1 ^ b0; + b1 = (tmp >> 39) | (tmp << (64 - 39)); + b0 -= b1 + k1; + b1 -= k2; + + tmp = b3 ^ b4; + b3 = (tmp >> 56) | (tmp << (64 - 56)); + b4 -= b3; + + tmp = b5 ^ b2; + b5 = (tmp >> 54) | (tmp << (64 - 54)); + b2 -= b5; + + tmp = b7 ^ b0; + b7 = (tmp >> 9) | (tmp << (64 - 9)); + b0 -= b7; + + tmp = b1 ^ b6; + b1 = (tmp >> 44) | (tmp << (64 - 44)); + b6 -= b1; + + tmp = b7 ^ b2; + b7 = (tmp >> 39) | (tmp << (64 - 39)); + b2 -= b7; + + tmp = b5 ^ b0; + b5 = (tmp >> 36) | (tmp << (64 - 36)); + b0 -= b5; + + tmp = b3 ^ b6; + b3 = (tmp >> 49) | (tmp << (64 - 49)); + b6 -= b3; + + tmp = b1 ^ b4; + b1 = (tmp >> 17) | (tmp << (64 - 17)); + b4 -= b1; + + tmp = b3 ^ b0; + b3 = (tmp >> 42) | (tmp << (64 - 42)); + b0 -= b3; + + tmp = b5 ^ b6; + b5 = (tmp >> 14) | (tmp << (64 - 14)); + b6 -= b5; + + tmp = b7 ^ b4; + b7 = (tmp >> 27) | (tmp << (64 - 27)); + b4 -= b7; + + tmp = b1 ^ b2; + b1 = (tmp >> 33) | (tmp << (64 - 33)); + b2 -= b1; + + tmp = b7 ^ b6; + b7 = (tmp >> 37) | (tmp << (64 - 37)); + b6 -= b7 + k6 + t1; + b7 -= k7; + + tmp = b5 ^ b4; + b5 = (tmp >> 19) | (tmp << (64 - 19)); + b4 -= b5 + k4; + b5 -= k5 + t0; + + tmp = b3 ^ b2; + b3 = (tmp >> 36) | (tmp << (64 - 36)); + b2 -= b3 + k2; + b3 -= k3; + + tmp = b1 ^ b0; + b1 = (tmp >> 46) | (tmp << (64 - 46)); + b0 -= b1 + k0; + b1 -= k1; + + output[0] = b0; + output[1] = b1; + output[2] = b2; + output[3] = b3; + + output[7] = b7; + output[6] = b6; + output[5] = b5; + output[4] = b4; +} diff --git a/drivers/staging/skein/threefishApi.c b/drivers/staging/skein/threefishApi.c new file mode 100644 index 00000000000000..1e70f66b7032e0 --- /dev/null +++ b/drivers/staging/skein/threefishApi.c @@ -0,0 +1,79 @@ + + +#include +#include + +void threefishSetKey(struct threefish_key *keyCtx, + enum threefish_size stateSize, + u64 *keyData, u64 *tweak) +{ + int keyWords = stateSize / 64; + int i; + u64 parity = KeyScheduleConst; + + keyCtx->tweak[0] = tweak[0]; + keyCtx->tweak[1] = tweak[1]; + keyCtx->tweak[2] = tweak[0] ^ tweak[1]; + + for (i = 0; i < keyWords; i++) { + keyCtx->key[i] = keyData[i]; + parity ^= keyData[i]; + } + keyCtx->key[i] = parity; + keyCtx->stateSize = stateSize; +} + +void threefishEncryptBlockBytes(struct threefish_key *keyCtx, u8 *in, + u8 *out) +{ + u64 plain[SKEIN_MAX_STATE_WORDS]; /* max number of words*/ + u64 cipher[SKEIN_MAX_STATE_WORDS]; + + Skein_Get64_LSB_First(plain, in, keyCtx->stateSize / 64); + threefishEncryptBlockWords(keyCtx, plain, cipher); + Skein_Put64_LSB_First(out, cipher, keyCtx->stateSize / 8); +} + +void threefishEncryptBlockWords(struct threefish_key *keyCtx, u64 *in, + u64 *out) +{ + switch (keyCtx->stateSize) { + case Threefish256: + threefishEncrypt256(keyCtx, in, out); + break; + case Threefish512: + threefishEncrypt512(keyCtx, in, out); + break; + case Threefish1024: + threefishEncrypt1024(keyCtx, in, out); + break; + } +} + +void threefishDecryptBlockBytes(struct threefish_key *keyCtx, u8 *in, + u8 *out) +{ + u64 plain[SKEIN_MAX_STATE_WORDS]; /* max number of words*/ + u64 cipher[SKEIN_MAX_STATE_WORDS]; + + Skein_Get64_LSB_First(cipher, in, keyCtx->stateSize / 64); + threefishDecryptBlockWords(keyCtx, cipher, plain); + Skein_Put64_LSB_First(out, plain, keyCtx->stateSize / 8); +} + +void threefishDecryptBlockWords(struct threefish_key *keyCtx, u64 *in, + u64 *out) +{ + switch (keyCtx->stateSize) { + case Threefish256: + threefishDecrypt256(keyCtx, in, out); + break; + case Threefish512: + threefishDecrypt512(keyCtx, in, out); + break; + case Threefish1024: + threefishDecrypt1024(keyCtx, in, out); + break; + } +} + diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index e27b88f02ccdb5..f350e6028ed236 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -1422,8 +1422,7 @@ static void slic_cmdq_addcmdpage(struct adapter *adapter, u32 *page) spin_lock_irqsave(&adapter->handle_lock.lock, adapter->handle_lock.flags); pslic_handle = adapter->pfree_slic_handles; - if (pslic_handle) - adapter->pfree_slic_handles = pslic_handle->next; + adapter->pfree_slic_handles = pslic_handle->next; spin_unlock_irqrestore(&adapter->handle_lock.lock, adapter->handle_lock.flags); pslic_handle->type = SLIC_HANDLE_CMD; diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c index 1ca91f7092b176..7495b890b6f0a5 100644 --- a/drivers/staging/speakup/kobjects.c +++ b/drivers/staging/speakup/kobjects.c @@ -641,7 +641,7 @@ ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr, if (kstrtol(cp, 10, &value) == 0) ret = spk_set_num_var(value, param, len); else - pr_warn("overflow or parsing error has occured"); + pr_warn("overflow or parsing error has occurred"); if (ret == -ERANGE) { var_data = param->data; pr_warn("value for %s out of range, expect %d to %d\n", diff --git a/drivers/staging/unisys/channels/channel.c b/drivers/staging/unisys/channels/channel.c index f6452595b74247..7223a14082baaf 100644 --- a/drivers/staging/unisys/channels/channel.c +++ b/drivers/staging/unisys/channels/channel.c @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/channels/chanstub.c b/drivers/staging/unisys/channels/chanstub.c index f504f49a436a0e..45ac55d3fe1c93 100644 --- a/drivers/staging/unisys/channels/chanstub.c +++ b/drivers/staging/unisys/channels/chanstub.c @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/channels/chanstub.h b/drivers/staging/unisys/channels/chanstub.h index 8d727debca6704..bdee5d529f6b5b 100644 --- a/drivers/staging/unisys/channels/chanstub.h +++ b/drivers/staging/unisys/channels/chanstub.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/common-spar/include/channels/channel.h b/drivers/staging/unisys/common-spar/include/channels/channel.h index aee204172b218f..baa0e501e6b4d8 100644 --- a/drivers/staging/unisys/common-spar/include/channels/channel.h +++ b/drivers/staging/unisys/common-spar/include/channels/channel.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -24,7 +24,7 @@ */ /* define the following to prevent include nesting in kernel header - * files of similar abreviated content + * files of similar abbreviated content */ #define __SUPERVISOR_CHANNEL_H__ diff --git a/drivers/staging/unisys/common-spar/include/channels/channel_guid.h b/drivers/staging/unisys/common-spar/include/channels/channel_guid.h index ae0dc2b2ad147e..1f1f48e8f1c9eb 100644 --- a/drivers/staging/unisys/common-spar/include/channels/channel_guid.h +++ b/drivers/staging/unisys/common-spar/include/channels/channel_guid.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/common-spar/include/channels/controlframework.h b/drivers/staging/unisys/common-spar/include/channels/controlframework.h index 5126433483492c..1a1c5053fcf82b 100644 --- a/drivers/staging/unisys/common-spar/include/channels/controlframework.h +++ b/drivers/staging/unisys/common-spar/include/channels/controlframework.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h b/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h index 47f1c4fa1e7ec5..17beec231d7098 100644 --- a/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h +++ b/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/common-spar/include/channels/diagchannel.h b/drivers/staging/unisys/common-spar/include/channels/diagchannel.h index c93515eb211d85..83f1cc7b443ffe 100644 --- a/drivers/staging/unisys/common-spar/include/channels/diagchannel.h +++ b/drivers/staging/unisys/common-spar/include/channels/diagchannel.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -356,7 +356,7 @@ typedef enum { *IsChannelInitialized: 1 iff SignalInit was called for this channel; otherwise * 0, and assume the channel is not ready for use yet. * - * Reserved: Padding to allign the fields in this structure. + * Reserved: Padding to align the fields in this structure. * *SubsystemSeverityFilter: Level of severity on a subsystem basis that controls * whether events are logged. Any event's severity for a diff --git a/drivers/staging/unisys/common-spar/include/channels/iochannel.h b/drivers/staging/unisys/common-spar/include/channels/iochannel.h index 8de1d249d55f45..8cbf04d40f7865 100644 --- a/drivers/staging/unisys/common-spar/include/channels/iochannel.h +++ b/drivers/staging/unisys/common-spar/include/channels/iochannel.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION */ +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION */ /* All rights reserved. */ #ifndef __IOCHANNEL_H__ #define __IOCHANNEL_H__ @@ -192,7 +192,7 @@ typedef enum { NET_RCV_POST = 0, /* submit buffer to hold receiving /* uisnic -> virtnic */ NET_MACADDR, /* indicates the client has requested to update * its MAC addr */ - NET_MACADDR_ACK, /* Mac addres */ + NET_MACADDR_ACK, /* MAC address */ } NET_TYPES; diff --git a/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h b/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h index 99dbbcf3d11ed5..7643042c0ce2a2 100644 --- a/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h +++ b/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h b/drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h index de30d321d982d1..db77d6f626a12c 100644 --- a/drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h +++ b/drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h @@ -1,6 +1,6 @@ /* controlvmcompletionstatus.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h b/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h index 4c6294d206066a..18cc9ed2748bff 100644 --- a/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h +++ b/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h b/drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h index 7304e9a0648ca1..fe9598c941a648 100644 --- a/drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h +++ b/drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h b/drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h index ae708faaa94dc9..8c0259a2cbce20 100644 --- a/drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h +++ b/drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/common-spar/include/version.h b/drivers/staging/unisys/common-spar/include/version.h index 00b0ebb09eae54..f25208fc3ed1a6 100644 --- a/drivers/staging/unisys/common-spar/include/version.h +++ b/drivers/staging/unisys/common-spar/include/version.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/common-spar/include/vmcallinterface.h b/drivers/staging/unisys/common-spar/include/vmcallinterface.h index 14c404367fa7ea..c5c10f3f1eb4dc 100644 --- a/drivers/staging/unisys/common-spar/include/vmcallinterface.h +++ b/drivers/staging/unisys/common-spar/include/vmcallinterface.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/include/commontypes.h b/drivers/staging/unisys/include/commontypes.h index ef12af4a72db06..3a8f302c87db1c 100644 --- a/drivers/staging/unisys/include/commontypes.h +++ b/drivers/staging/unisys/include/commontypes.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -17,7 +17,7 @@ #define _COMMONTYPES_H_ /* define the following to prevent include nesting in kernel header files of - * similar abreviated content */ + * similar abbreviated content */ #define _SUPERVISOR_COMMONTYPES_H_ #ifdef __KERNEL__ diff --git a/drivers/staging/unisys/include/guestlinuxdebug.h b/drivers/staging/unisys/include/guestlinuxdebug.h index c3de8496e5d637..efc4005368b041 100644 --- a/drivers/staging/unisys/include/guestlinuxdebug.h +++ b/drivers/staging/unisys/include/guestlinuxdebug.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -17,7 +17,7 @@ #define __GUESTLINUXDEBUG_H__ /* -* This file contains supporting interface for "vmcallinterface.h", particuarly +* This file contains supporting interface for "vmcallinterface.h", particularly * regarding adding additional structure and functionality to linux * ISSUE_IO_VMCALL_POSTCODE_SEVERITY */ @@ -142,7 +142,7 @@ typedef enum { /* POSTCODE event identifier tuples */ * Please also note that the resulting postcode is in hex, so if you are * searching for the __LINE__ number, convert it first to decimal. The line * number combined with driver and type of call, will allow you to track down - * exactly what line an error occured on, or where the last driver + * exactly what line an error occurred on, or where the last driver * entered/exited from. */ diff --git a/drivers/staging/unisys/include/guidutils.h b/drivers/staging/unisys/include/guidutils.h index 75caf929cd6d41..adeb92d8dd4dca 100644 --- a/drivers/staging/unisys/include/guidutils.h +++ b/drivers/staging/unisys/include/guidutils.h @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/include/periodic_work.h b/drivers/staging/unisys/include/periodic_work.h index 6c7190bdcd66fe..418ba634e1a296 100644 --- a/drivers/staging/unisys/include/periodic_work.h +++ b/drivers/staging/unisys/include/periodic_work.h @@ -1,6 +1,6 @@ /* periodic_work.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/include/procobjecttree.h b/drivers/staging/unisys/include/procobjecttree.h index c81d11287e685c..1174056ec3d960 100644 --- a/drivers/staging/unisys/include/procobjecttree.h +++ b/drivers/staging/unisys/include/procobjecttree.h @@ -1,6 +1,6 @@ /* procobjecttree.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/include/sparstop.h b/drivers/staging/unisys/include/sparstop.h index 3603ac607643ec..05837399a741da 100644 --- a/drivers/staging/unisys/include/sparstop.h +++ b/drivers/staging/unisys/include/sparstop.h @@ -1,6 +1,6 @@ /* sparstop.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/include/timskmod.h b/drivers/staging/unisys/include/timskmod.h index 5fd5ad51446458..ecf1a6fac7a141 100644 --- a/drivers/staging/unisys/include/timskmod.h +++ b/drivers/staging/unisys/include/timskmod.h @@ -1,6 +1,6 @@ /* timskmod.h * - * Copyright � 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/include/timskmodutils.h b/drivers/staging/unisys/include/timskmodutils.h index 2d81d46bf11e7f..0045d559d1b9a1 100644 --- a/drivers/staging/unisys/include/timskmodutils.h +++ b/drivers/staging/unisys/include/timskmodutils.h @@ -1,6 +1,6 @@ /* timskmodutils.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/include/uisqueue.h b/drivers/staging/unisys/include/uisqueue.h index 6dab3900994a7e..d7793a84903e8c 100644 --- a/drivers/staging/unisys/include/uisqueue.h +++ b/drivers/staging/unisys/include/uisqueue.h @@ -1,6 +1,6 @@ /* uisqueue.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/include/uisthread.h b/drivers/staging/unisys/include/uisthread.h index 2b1fba75909867..26837771b43fe9 100644 --- a/drivers/staging/unisys/include/uisthread.h +++ b/drivers/staging/unisys/include/uisthread.h @@ -1,6 +1,6 @@ /* uisthread.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/include/uisutils.h b/drivers/staging/unisys/include/uisutils.h index 5fdab3a3464a42..f4774c05f9098d 100644 --- a/drivers/staging/unisys/include/uisutils.h +++ b/drivers/staging/unisys/include/uisutils.h @@ -1,6 +1,6 @@ /* uisutils.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/include/uniklog.h b/drivers/staging/unisys/include/uniklog.h index 4d7b87cefa61c7..6178cc46f7c1e8 100644 --- a/drivers/staging/unisys/include/uniklog.h +++ b/drivers/staging/unisys/include/uniklog.h @@ -1,6 +1,6 @@ /* uniklog.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/uislib/uislib.c b/drivers/staging/unisys/uislib/uislib.c index 3152a2180c456c..0e1a58ab28b10f 100644 --- a/drivers/staging/unisys/uislib/uislib.c +++ b/drivers/staging/unisys/uislib/uislib.c @@ -1,6 +1,6 @@ /* uislib.c * - * Copyright � 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/uislib/uisqueue.c b/drivers/staging/unisys/uislib/uisqueue.c index 40598ff1f4f2f8..d4a6074cfaf0f8 100644 --- a/drivers/staging/unisys/uislib/uisqueue.c +++ b/drivers/staging/unisys/uislib/uisqueue.c @@ -1,6 +1,6 @@ /* uisqueue.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/uislib/uisthread.c b/drivers/staging/unisys/uislib/uisthread.c index 782b06aad56d95..c93ab04c3cfc9d 100644 --- a/drivers/staging/unisys/uislib/uisthread.c +++ b/drivers/staging/unisys/uislib/uisthread.c @@ -1,6 +1,6 @@ /* uisthread.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/uislib/uisutils.c b/drivers/staging/unisys/uislib/uisutils.c index 3178f75e1ebec2..b49647ccc9d097 100644 --- a/drivers/staging/unisys/uislib/uisutils.c +++ b/drivers/staging/unisys/uislib/uisutils.c @@ -1,6 +1,6 @@ /* uisutils.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/virthba/virthba.c b/drivers/staging/unisys/virthba/virthba.c index 817b11dfa19c28..a13e79e287f400 100644 --- a/drivers/staging/unisys/virthba/virthba.c +++ b/drivers/staging/unisys/virthba/virthba.c @@ -1,6 +1,6 @@ /* virthba.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -82,6 +82,14 @@ static int virthba_ioctl(struct scsi_device *dev, int cmd, void __user *arg); static int virthba_queue_command_lck(struct scsi_cmnd *scsicmd, void (*virthba_cmnd_done)(struct scsi_cmnd *)); +static const struct x86_cpu_id unisys_spar_ids[] = { + { X86_VENDOR_INTEL, 6, 62, X86_FEATURE_ANY }, + {} +}; + +/* Autoload */ +MODULE_DEVICE_TABLE(x86cpu, unisys_spar_ids); + #ifdef DEF_SCSI_QCMD DEF_SCSI_QCMD(virthba_queue_command) #else @@ -1046,7 +1054,7 @@ static int virthba_slave_alloc(struct scsi_device *scsidev) { /* this called by the midlayer before scan for new devices - - * LLD can alloc any struc & do init if needed. + * LLD can alloc any struct & do init if needed. */ struct virtdisk_info *vdisk; struct virtdisk_info *tmpvdisk; @@ -1400,7 +1408,7 @@ info_proc_read(struct file *file, char __user *buf, size_t len, loff_t *offset) virthbainfo = VirtHbasOpen[i].virthbainfo; length += sprintf(vbuf + length, "CHANSOCK is not defined.\n"); - length += sprintf(vbuf + length, "MaxBuffLen:%d\n", MaxBuffLen); + length += sprintf(vbuf + length, "MaxBuffLen:%u\n", MaxBuffLen); length += sprintf(vbuf + length, "\nvirthba result queue poll wait:%d usecs.\n", rsltq_wait_usecs); @@ -1534,7 +1542,7 @@ virthba_serverup(struct virtpci_dev *virtpcidev) virtpcidev->deviceNo); if (!virthbainfo->serverdown) { - DBGINF("Server up message recieved while server is already up.\n"); + DBGINF("Server up message received while server is already up.\n"); return 1; } if (virthbainfo->serverchangingstate) { diff --git a/drivers/staging/unisys/virthba/virthba.h b/drivers/staging/unisys/virthba/virthba.h index 88b797439a16a5..d4b809b0c7bcc6 100644 --- a/drivers/staging/unisys/virthba/virthba.h +++ b/drivers/staging/unisys/virthba/virthba.h @@ -1,6 +1,6 @@ /* virthba.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/virtpci/virtpci.c b/drivers/staging/unisys/virtpci/virtpci.c index 8e34650b00b5c2..21f8bd5fdff94d 100644 --- a/drivers/staging/unisys/virtpci/virtpci.c +++ b/drivers/staging/unisys/virtpci/virtpci.c @@ -1,6 +1,6 @@ /* virtpci.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/virtpci/virtpci.h b/drivers/staging/unisys/virtpci/virtpci.h index b8fd07bc543506..b695c4b8e8bd23 100644 --- a/drivers/staging/unisys/virtpci/virtpci.h +++ b/drivers/staging/unisys/virtpci/virtpci.h @@ -1,6 +1,6 @@ /* virtpci.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchannel/globals.h b/drivers/staging/unisys/visorchannel/globals.h index 668f832ca56637..07653b8dea7b0f 100644 --- a/drivers/staging/unisys/visorchannel/globals.h +++ b/drivers/staging/unisys/visorchannel/globals.h @@ -1,6 +1,6 @@ /* globals.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchannel/visorchannel.h b/drivers/staging/unisys/visorchannel/visorchannel.h index 62d29a233fd05d..a8c2ebd0c99a5f 100644 --- a/drivers/staging/unisys/visorchannel/visorchannel.h +++ b/drivers/staging/unisys/visorchannel/visorchannel.h @@ -1,6 +1,6 @@ /* visorchannel.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchannel/visorchannel_funcs.c b/drivers/staging/unisys/visorchannel/visorchannel_funcs.c index 053681616ba32f..4427d01b1126a7 100644 --- a/drivers/staging/unisys/visorchannel/visorchannel_funcs.c +++ b/drivers/staging/unisys/visorchannel/visorchannel_funcs.c @@ -1,6 +1,6 @@ /* visorchannel_funcs.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchannel/visorchannel_main.c b/drivers/staging/unisys/visorchannel/visorchannel_main.c index 482ee0ac1c16b9..1a092570602e7e 100644 --- a/drivers/staging/unisys/visorchannel/visorchannel_main.c +++ b/drivers/staging/unisys/visorchannel/visorchannel_main.c @@ -1,6 +1,6 @@ /* visorchannel_main.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchipset/controlvm.h b/drivers/staging/unisys/visorchipset/controlvm.h index 873fa12dfe6f45..012891c3f21dc8 100644 --- a/drivers/staging/unisys/visorchipset/controlvm.h +++ b/drivers/staging/unisys/visorchipset/controlvm.h @@ -1,6 +1,6 @@ /* controlvm.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchipset/controlvm_direct.c b/drivers/staging/unisys/visorchipset/controlvm_direct.c index b911ea85c093ad..cd10e3a2a07f23 100644 --- a/drivers/staging/unisys/visorchipset/controlvm_direct.c +++ b/drivers/staging/unisys/visorchipset/controlvm_direct.c @@ -1,6 +1,6 @@ /* controlvm_direct.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchipset/file.c b/drivers/staging/unisys/visorchipset/file.c index e214a115328290..fccc4f0c3a49ea 100644 --- a/drivers/staging/unisys/visorchipset/file.c +++ b/drivers/staging/unisys/visorchipset/file.c @@ -1,6 +1,6 @@ /* file.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchipset/file.h b/drivers/staging/unisys/visorchipset/file.h index 597282aa9a06bd..21bb906242e161 100644 --- a/drivers/staging/unisys/visorchipset/file.h +++ b/drivers/staging/unisys/visorchipset/file.h @@ -1,6 +1,6 @@ /* file.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchipset/globals.h b/drivers/staging/unisys/visorchipset/globals.h index a0e6d4fc03ae85..0fe14599f185c4 100644 --- a/drivers/staging/unisys/visorchipset/globals.h +++ b/drivers/staging/unisys/visorchipset/globals.h @@ -1,6 +1,6 @@ /* globals.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchipset/parser.c b/drivers/staging/unisys/visorchipset/parser.c index b408d415bd8c76..948fbb8ed09cc0 100644 --- a/drivers/staging/unisys/visorchipset/parser.c +++ b/drivers/staging/unisys/visorchipset/parser.c @@ -1,6 +1,6 @@ /* parser.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchipset/parser.h b/drivers/staging/unisys/visorchipset/parser.h index a0cc50a533cd82..3e4aedc580ce5a 100644 --- a/drivers/staging/unisys/visorchipset/parser.h +++ b/drivers/staging/unisys/visorchipset/parser.h @@ -1,6 +1,6 @@ /* parser.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchipset/testing.h b/drivers/staging/unisys/visorchipset/testing.h index a44f5556cb21ef..ad378b82cf9980 100644 --- a/drivers/staging/unisys/visorchipset/testing.h +++ b/drivers/staging/unisys/visorchipset/testing.h @@ -1,6 +1,6 @@ /* testing.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchipset/visorchipset.h b/drivers/staging/unisys/visorchipset/visorchipset.h index d95825dc541494..06646e4e3f1e4b 100644 --- a/drivers/staging/unisys/visorchipset/visorchipset.h +++ b/drivers/staging/unisys/visorchipset/visorchipset.h @@ -1,6 +1,6 @@ /* visorchipset.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchipset/visorchipset_main.c b/drivers/staging/unisys/visorchipset/visorchipset_main.c index c475e256e34b63..1895dc45964389 100644 --- a/drivers/staging/unisys/visorchipset/visorchipset_main.c +++ b/drivers/staging/unisys/visorchipset/visorchipset_main.c @@ -1,6 +1,6 @@ /* visorchipset_main.c * - * Copyright � 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorchipset/visorchipset_umode.h b/drivers/staging/unisys/visorchipset/visorchipset_umode.h index 259e840376a54a..06ba5b7e4254c8 100644 --- a/drivers/staging/unisys/visorchipset/visorchipset_umode.h +++ b/drivers/staging/unisys/visorchipset/visorchipset_umode.h @@ -1,6 +1,6 @@ /* visorchipset_umode.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorutil/charqueue.c b/drivers/staging/unisys/visorutil/charqueue.c index 0ceede129e8720..61600e1955b33f 100644 --- a/drivers/staging/unisys/visorutil/charqueue.c +++ b/drivers/staging/unisys/visorutil/charqueue.c @@ -1,6 +1,6 @@ /* charqueue.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorutil/charqueue.h b/drivers/staging/unisys/visorutil/charqueue.h index e82ae0bc8959f9..d6f16587a36404 100644 --- a/drivers/staging/unisys/visorutil/charqueue.h +++ b/drivers/staging/unisys/visorutil/charqueue.h @@ -1,6 +1,6 @@ /* charqueue.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorutil/easyproc.c b/drivers/staging/unisys/visorutil/easyproc.c index 60b6b83d1b20dc..43df5988f0b8db 100644 --- a/drivers/staging/unisys/visorutil/easyproc.c +++ b/drivers/staging/unisys/visorutil/easyproc.c @@ -1,4 +1,4 @@ -/* Copyright © 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorutil/easyproc.h b/drivers/staging/unisys/visorutil/easyproc.h index 1cef1fd33d53d0..6ce7d5eb6ad1b5 100644 --- a/drivers/staging/unisys/visorutil/easyproc.h +++ b/drivers/staging/unisys/visorutil/easyproc.h @@ -1,6 +1,6 @@ /* easyproc.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorutil/memregion.h b/drivers/staging/unisys/visorutil/memregion.h index bb122dbeafbc47..796631652b7715 100644 --- a/drivers/staging/unisys/visorutil/memregion.h +++ b/drivers/staging/unisys/visorutil/memregion.h @@ -1,6 +1,6 @@ /* memregion.h * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorutil/memregion_direct.c b/drivers/staging/unisys/visorutil/memregion_direct.c index 2c1061d55ee9d2..d39fde9c1a6033 100644 --- a/drivers/staging/unisys/visorutil/memregion_direct.c +++ b/drivers/staging/unisys/visorutil/memregion_direct.c @@ -1,6 +1,6 @@ /* memregion_direct.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorutil/periodic_work.c b/drivers/staging/unisys/visorutil/periodic_work.c index 0670a3174682ee..0251b83aa55cdb 100644 --- a/drivers/staging/unisys/visorutil/periodic_work.c +++ b/drivers/staging/unisys/visorutil/periodic_work.c @@ -1,6 +1,6 @@ /* periodic_work.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorutil/procobjecttree.c b/drivers/staging/unisys/visorutil/procobjecttree.c index 67a19e1c7b0206..2f874e0ab33936 100644 --- a/drivers/staging/unisys/visorutil/procobjecttree.c +++ b/drivers/staging/unisys/visorutil/procobjecttree.c @@ -1,6 +1,6 @@ /* procobjecttree.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/unisys/visorutil/visorkmodutils.c b/drivers/staging/unisys/visorutil/visorkmodutils.c index a7d1e94ca3c30d..e802e75a46966b 100644 --- a/drivers/staging/unisys/visorutil/visorkmodutils.c +++ b/drivers/staging/unisys/visorutil/visorkmodutils.c @@ -1,6 +1,6 @@ /* timskmodutils.c * - * Copyright © 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2013 UNISYS CORPORATION * All rights reserved. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index ffb4eeefdddb37..2d8497277aae3e 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -684,7 +684,7 @@ static int vme_user_match(struct vme_dev *vdev) static int vme_user_probe(struct vme_dev *vdev) { int i, err; - char name[12]; + char *name; /* Save pointer to the bridge device */ if (vme_user_bridge != NULL) { @@ -792,15 +792,16 @@ static int vme_user_probe(struct vme_dev *vdev) /* Add sysfs Entries */ for (i = 0; i < VME_DEVS; i++) { int num; + switch (type[i]) { case MASTER_MINOR: - sprintf(name, "bus/vme/m%%d"); + name = "bus/vme/m%d"; break; case CONTROL_MINOR: - sprintf(name, "bus/vme/ctl"); + name = "bus/vme/ctl"; break; case SLAVE_MINOR: - sprintf(name, "bus/vme/s%%d"); + name = "bus/vme/s%d"; break; default: err = -EINVAL; diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index db38ca05113064..e7227954f2fe88 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -24,7 +24,6 @@ * vUpdateIFS - Update slotTime,SIFS,DIFS, and EIFS * CARDvUpdateBasicTopRate - Update BasicTopRate * CARDbAddBasicRate - Add to BasicRateSet - * CARDbSetBasicRate - Set Basic Tx Rate * CARDbIsOFDMinBasicRate - Check if any OFDM rate is in BasicRateSet * CARDvSetLoopbackMode - Set Loopback mode * CARDbSoftwareReset - Sortware reset NIC @@ -1877,19 +1876,6 @@ void CARDvUpdateBasicTopRate(void *pDeviceHandler) pDevice->byTopCCKBasicRate = byTopCCK; } -/* - * Description: Set NIC Tx Basic Rate - * - * Parameters: - * In: - * pDevice - The adapter to be set - * wBasicRate - Basic Rate to be set - * Out: - * none - * - * Return Value: true if succeeded; false if failed. - * - */ bool CARDbAddBasicRate(void *pDeviceHandler, unsigned short wRateIdx) { PSDevice pDevice = (PSDevice) pDeviceHandler; diff --git a/drivers/staging/vt6655/datarate.c b/drivers/staging/vt6655/datarate.c index c9a89cd7633cfa..2d760da626bb47 100644 --- a/drivers/staging/vt6655/datarate.c +++ b/drivers/staging/vt6655/datarate.c @@ -51,7 +51,7 @@ extern unsigned short TxRate_iwconfig; //2008-5-8 by chester /*--------------------- Static Variables --------------------------*/ //static int msglevel =MSG_LEVEL_DEBUG; static int msglevel = MSG_LEVEL_INFO; -const unsigned char acbyIERate[MAX_RATE] = +static const unsigned char acbyIERate[MAX_RATE] = {0x02, 0x04, 0x0B, 0x16, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C}; #define AUTORATE_TXOK_CNT 0x0400 diff --git a/drivers/staging/vt6655/device.h b/drivers/staging/vt6655/device.h index 062c3a374b99f7..985c3c19a4a7b7 100644 --- a/drivers/staging/vt6655/device.h +++ b/drivers/staging/vt6655/device.h @@ -148,8 +148,17 @@ /*--------------------- Export Types ------------------------------*/ -#define DBG_PRT(l, p, args...) { if (l <= msglevel) printk(p, ##args); } -#define PRINT_K(p, args...) { if (PRIVATE_Message) printk(p, ##args); } +#define DBG_PRT(l, p, args...) \ +do { \ + if (l <= msglevel) \ + printk(p, ##args); \ +} while (0) + +#define PRINT_K(p, args...) \ +do { \ + if (PRIVATE_Message) \ + printk(p, ##args); \ +} while (0) //0:11A 1:11B 2:11G typedef enum _VIA_BB_TYPE diff --git a/drivers/staging/vt6655/ioctl.c b/drivers/staging/vt6655/ioctl.c index b5cd2e44e53dac..1de5d2c907d243 100644 --- a/drivers/staging/vt6655/ioctl.c +++ b/drivers/staging/vt6655/ioctl.c @@ -305,7 +305,8 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) result = -EINVAL; break; } - pList = (PSBSSIDList)kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), (int)GFP_ATOMIC); + pList = (PSBSSIDList)kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), + GFP_ATOMIC); if (pList == NULL) { result = -ENOMEM; break; @@ -576,7 +577,8 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) result = -EINVAL; break; } - pNodeList = (PSNodeList)kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), (int)GFP_ATOMIC); + pNodeList = (PSNodeList)kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), + GFP_ATOMIC); if (pNodeList == NULL) { result = -ENOMEM; break; diff --git a/drivers/staging/vt6655/iwctl.c b/drivers/staging/vt6655/iwctl.c index ac3fc16704c1c5..a601c47a3803cb 100644 --- a/drivers/staging/vt6655/iwctl.c +++ b/drivers/staging/vt6655/iwctl.c @@ -1835,19 +1835,14 @@ int iwctl_siwencodeext(struct net_device *dev, size_t seq_len = 0, key_len = 0; // // int ii; - u8 *buf; - size_t blen; u8 key_array[64]; int ret = 0; PRINT_K("SIOCSIWENCODEEXT...... \n"); - blen = sizeof(*param); - buf = kmalloc((int)blen, (int)GFP_KERNEL); - if (buf == NULL) + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (param == NULL) return -ENOMEM; - memset(buf, 0, blen); - param = (struct viawget_wpa_param *)buf; //recover alg_name switch (ext->alg) { diff --git a/drivers/staging/vt6655/wpactl.c b/drivers/staging/vt6655/wpactl.c index d17224f39b4d52..1f72589cf71863 100644 --- a/drivers/staging/vt6655/wpactl.c +++ b/drivers/staging/vt6655/wpactl.c @@ -188,7 +188,8 @@ int wpa_set_wpadev(PSDevice pDevice, int val) * */ -int wpa_set_keys(PSDevice pDevice, void *ctx, bool fcpfkernel) +int wpa_set_keys(PSDevice pDevice, void *ctx, + bool fcpfkernel) __must_hold(&pDevice->lock) { struct viawget_wpa_param *param = ctx; PSMgmtObject pMgmt = pDevice->pMgmt; @@ -593,7 +594,7 @@ static int wpa_get_scan(PSDevice pDevice, unsigned char *ptempBSS; - ptempBSS = kmalloc(sizeof(KnownBSS), (int)GFP_ATOMIC); + ptempBSS = kmalloc(sizeof(KnownBSS), GFP_ATOMIC); if (ptempBSS == NULL) { printk(KERN_ERR "bubble sort kmalloc memory fail@@@\n"); @@ -635,7 +636,7 @@ static int wpa_get_scan(PSDevice pDevice, count++; } - pBuf = kcalloc(count, sizeof(struct viawget_scan_result), (int)GFP_ATOMIC); + pBuf = kcalloc(count, sizeof(struct viawget_scan_result), GFP_ATOMIC); if (pBuf == NULL) { ret = -ENOMEM; @@ -679,7 +680,7 @@ static int wpa_get_scan(PSDevice pDevice, ret = -EFAULT; } param->u.scan_results.scan_count = count; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " param->u.scan_results.scan_count = %d\n", count) + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " param->u.scan_results.scan_count = %d\n", count); kfree(pBuf); return ret; @@ -857,7 +858,7 @@ int wpa_ioctl(PSDevice pDevice, struct iw_point *p) p->length > VIAWGET_WPA_MAX_BUF_SIZE || !p->pointer) return -EINVAL; - param = kmalloc((int)p->length, (int)GFP_KERNEL); + param = kmalloc((int)p->length, GFP_KERNEL); if (param == NULL) return -ENOMEM; diff --git a/drivers/staging/vt6656/aes_ccmp.c b/drivers/staging/vt6656/aes_ccmp.c index e2bfa8d266cd8a..a9d51687db7f56 100644 --- a/drivers/staging/vt6656/aes_ccmp.c +++ b/drivers/staging/vt6656/aes_ccmp.c @@ -32,6 +32,7 @@ #include "device.h" #include "80211hdr.h" +#include "aes_ccmp.h" /* * SBOX Table diff --git a/drivers/staging/vt6656/firmware.c b/drivers/staging/vt6656/firmware.c index cd2ea76c8b1e1e..15c1e861c84b69 100644 --- a/drivers/staging/vt6656/firmware.c +++ b/drivers/staging/vt6656/firmware.c @@ -31,6 +31,7 @@ * */ +#include #include "firmware.h" #include "control.h" #include "rndis.h" @@ -43,7 +44,7 @@ static int msglevel = MSG_LEVEL_INFO; #define FIRMWARE_CHUNK_SIZE 0x400 -int FIRMWAREbDownload(struct vnt_private *pDevice) +int FIRMWAREbDownload(struct vnt_private *pDevice) __must_hold(&pDevice->lock) { struct device *dev = &pDevice->usb->dev; const struct firmware *fw; diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index 3840323858fcc1..1ff14469df9967 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -181,31 +181,31 @@ static void s_vFillTxKey(struct vnt_private *pDevice, struct vnt_mic_hdr *mic_hdr) { u8 *pbyBuf = (u8 *)&fifo_head->adwTxKey[0]; - u32 *pdwIV = (u32 *)pbyIVHead; - u32 *pdwExtIV = (u32 *)((u8 *)pbyIVHead + 4); + __le32 *pdwIV = (__le32 *)pbyIVHead; + __le32 *pdwExtIV = (__le32 *)((u8 *)pbyIVHead + 4); struct ieee80211_hdr *pMACHeader = (struct ieee80211_hdr *)pbyHdrBuf; - u32 dwRevIVCounter; + __le32 rev_iv_counter; /* Fill TXKEY */ if (pTransmitKey == NULL) return; - dwRevIVCounter = cpu_to_le32(pDevice->dwIVCounter); - *pdwIV = pDevice->dwIVCounter; + rev_iv_counter = cpu_to_le32(pDevice->dwIVCounter); + *pdwIV = cpu_to_le32(pDevice->dwIVCounter); pDevice->byKeyIndex = pTransmitKey->dwKeyIndex & 0xf; switch (pTransmitKey->byCipherSuite) { case KEY_CTL_WEP: if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN) { - memcpy(pDevice->abyPRNG, (u8 *)&dwRevIVCounter, 3); + memcpy(pDevice->abyPRNG, (u8 *)&rev_iv_counter, 3); memcpy(pDevice->abyPRNG + 3, pTransmitKey->abyKey, pTransmitKey->uKeyLength); } else { - memcpy(pbyBuf, (u8 *)&dwRevIVCounter, 3); + memcpy(pbyBuf, (u8 *)&rev_iv_counter, 3); memcpy(pbyBuf + 3, pTransmitKey->abyKey, pTransmitKey->uKeyLength); if (pTransmitKey->uKeyLength == WLAN_WEP40_KEYLEN) { - memcpy(pbyBuf+8, (u8 *)&dwRevIVCounter, 3); + memcpy(pbyBuf+8, (u8 *)&rev_iv_counter, 3); memcpy(pbyBuf+11, pTransmitKey->abyKey, pTransmitKey->uKeyLength); } @@ -213,9 +213,8 @@ static void s_vFillTxKey(struct vnt_private *pDevice, memcpy(pDevice->abyPRNG, pbyBuf, 16); } /* Append IV after Mac Header */ - *pdwIV &= WEP_IV_MASK; - *pdwIV |= (u32)pDevice->byKeyIndex << 30; - *pdwIV = cpu_to_le32(*pdwIV); + *pdwIV &= cpu_to_le32(WEP_IV_MASK); + *pdwIV |= cpu_to_le32((u32)pDevice->byKeyIndex << 30); pDevice->dwIVCounter++; if (pDevice->dwIVCounter > WEP_IV_MASK) @@ -256,7 +255,7 @@ static void s_vFillTxKey(struct vnt_private *pDevice, *(pbyIVHead+3) = (u8)(((pDevice->byKeyIndex << 6) & 0xc0) | 0x20); - *pdwIV |= cpu_to_le16((u16)(pTransmitKey->wTSC15_0)); + *pdwIV |= cpu_to_le32((u32)(pTransmitKey->wTSC15_0)); /* Append IV&ExtIV after Mac Header */ *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16); @@ -283,9 +282,10 @@ static void s_vFillTxKey(struct vnt_private *pDevice, /* MICHDR2 */ memcpy(mic_hdr->addr3, pMACHeader->addr3, ETH_ALEN); - mic_hdr->frame_control = cpu_to_le16(pMACHeader->frame_control - & 0xc78f); - mic_hdr->seq_ctrl = cpu_to_le16(pMACHeader->seq_ctrl & 0xf); + mic_hdr->frame_control = cpu_to_le16( + le16_to_cpu(pMACHeader->frame_control) & 0xc78f); + mic_hdr->seq_ctrl = cpu_to_le16( + le16_to_cpu(pMACHeader->seq_ctrl) & 0xf); if (ieee80211_has_a4(pMACHeader->frame_control)) memcpy(mic_hdr->addr4, pMACHeader->addr4, ETH_ALEN); @@ -551,7 +551,8 @@ static int vnt_fill_ieee80211_rts(struct vnt_private *priv, __le16 duration) { rts->duration = duration; - rts->frame_control = TYPE_CTL_RTS; + rts->frame_control = + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); if (priv->op_mode == NL80211_IFTYPE_ADHOC || priv->op_mode == NL80211_IFTYPE_AP) @@ -741,7 +742,9 @@ static u16 s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx, pDevice->tx_rate_fb1, bNeedAck, byFBOption); /* Get CTS Frame body */ pBuf->data.duration = pBuf->duration_ba; - pBuf->data.frame_control = TYPE_CTL_CTS; + pBuf->data.frame_control = + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS); + memcpy(pBuf->data.ra, pDevice->abyCurrentNetAddr, ETH_ALEN); return vnt_rxtx_datahead_g_fb(pDevice, byPktType, wCurrentRate, @@ -757,7 +760,9 @@ static u16 s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx, wCurrentRate, bNeedAck, byFBOption); /*Get CTS Frame body*/ pBuf->data.duration = pBuf->duration_ba; - pBuf->data.frame_control = TYPE_CTL_CTS; + pBuf->data.frame_control = + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS); + memcpy(pBuf->data.ra, pDevice->abyCurrentNetAddr, ETH_ALEN); return vnt_rxtx_datahead_g(pDevice, byPktType, wCurrentRate, @@ -800,7 +805,7 @@ static u16 s_vGenerateTxParameter(struct vnt_private *pDevice, u16 wFifoCtl; u8 byFBOption = AUTO_FB_NONE; - pFifoHead->wReserved = wCurrentRate; + pFifoHead->current_rate = cpu_to_le16(wCurrentRate); wFifoCtl = pFifoHead->wFIFOCtl; if (wFifoCtl & FIFOCTL_AUTO_FB_0) @@ -1008,7 +1013,7 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType, pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK; } - pTxBufHead->wTimeStamp = DEFAULT_MSDU_LIFETIME_RES_64us; + pTxBufHead->time_stamp = cpu_to_le16(DEFAULT_MSDU_LIFETIME_RES_64us); //Set FRAGCTL_MACHDCNT cbMACHdLen = WLAN_HDR_ADDR3_LEN; @@ -1431,7 +1436,7 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice, } pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN; - pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us); + pTxBufHead->time_stamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us); if (is_multicast_ether_addr(pPacket->p80211Header->sA3.abyAddr1)) { bNeedACK = false; @@ -1605,7 +1610,7 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice, } } - pTX_Buffer->wTxByteCount = cpu_to_le16((u16)(cbReqCount)); + pTX_Buffer->tx_byte_count = cpu_to_le16((u16)(cbReqCount)); pTX_Buffer->byPKTNO = (u8) (((wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F)); pTX_Buffer->byType = 0x00; @@ -1697,7 +1702,7 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice, cbReqCount = cbHeaderSize + WLAN_HDR_ADDR3_LEN + cbFrameBodySize; - pTX_Buffer->wTxByteCount = (u16)cbReqCount; + pTX_Buffer->tx_byte_count = cpu_to_le16((u16)cbReqCount); pTX_Buffer->byPKTNO = (u8) (((wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F)); pTX_Buffer->byType = 0x01; @@ -1800,7 +1805,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb) } pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN; - pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us); + pTxBufHead->time_stamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us); if (is_multicast_ether_addr(p80211Header->sA3.abyAddr1)) { bNeedACK = false; @@ -2045,7 +2050,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb) } } - pTX_Buffer->wTxByteCount = cpu_to_le16((u16)(cbReqCount)); + pTX_Buffer->tx_byte_count = cpu_to_le16((u16)(cbReqCount)); pTX_Buffer->byPKTNO = (u8) (((wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F)); pTX_Buffer->byType = 0x00; @@ -2437,7 +2442,7 @@ int nsDMA_tx_packet(struct vnt_private *pDevice, } pTX_Buffer->byPKTNO = (u8) (((pDevice->wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F)); - pTX_Buffer->wTxByteCount = (u16)BytesToWrite; + pTX_Buffer->tx_byte_count = cpu_to_le16((u16)BytesToWrite); pContext->pPacket = skb; pContext->type = CONTEXT_DATA_PACKET; @@ -2591,7 +2596,7 @@ int bRelayPacketSend(struct vnt_private *pDevice, u8 *pbySkbData, u32 uDataLen, } pTX_Buffer->byPKTNO = (u8) (((pDevice->wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F)); - pTX_Buffer->wTxByteCount = (u16)BytesToWrite; + pTX_Buffer->tx_byte_count = cpu_to_le16((u16)BytesToWrite); pContext->pPacket = NULL; pContext->type = CONTEXT_DATA_PACKET; diff --git a/drivers/staging/vt6656/rxtx.h b/drivers/staging/vt6656/rxtx.h index 6d6539d29d04ce..4dfb2e0c6ae78a 100644 --- a/drivers/staging/vt6656/rxtx.h +++ b/drivers/staging/vt6656/rxtx.h @@ -217,15 +217,15 @@ union vnt_tx_head { struct vnt_tx_fifo_head { u32 adwTxKey[4]; u16 wFIFOCtl; - u16 wTimeStamp; + __le16 time_stamp; u16 wFragCtl; - u16 wReserved; + __le16 current_rate; } __packed; struct vnt_tx_buffer { u8 byType; u8 byPKTNO; - u16 wTxByteCount; + __le16 tx_byte_count; struct vnt_tx_fifo_head fifo_head; union vnt_tx_head tx_head; } __packed; @@ -241,7 +241,7 @@ struct vnt_tx_short_buf_head { struct vnt_beacon_buffer { u8 byType; u8 byPKTNO; - u16 wTxByteCount; + __le16 tx_byte_count; struct vnt_tx_short_buf_head short_head; struct ieee80211_hdr hdr; } __packed; diff --git a/drivers/staging/vt6656/tether.h b/drivers/staging/vt6656/tether.h index aec6b568a4a926..f57fcfdc24d566 100644 --- a/drivers/staging/vt6656/tether.h +++ b/drivers/staging/vt6656/tether.h @@ -60,8 +60,6 @@ #define TYPE_DATE_NULL 0x4800 #define TYPE_CTL_PSPOLL 0xa400 -#define TYPE_CTL_RTS 0xb400 -#define TYPE_CTL_CTS 0xc400 #define TYPE_CTL_ACK 0xd400 #else //if LITTLE_ENDIAN @@ -91,8 +89,6 @@ #define TYPE_DATE_NULL 0x0048 #define TYPE_CTL_PSPOLL 0x00a4 -#define TYPE_CTL_RTS 0x00b4 -#define TYPE_CTL_CTS 0x00c4 #define TYPE_CTL_ACK 0x00d4 #endif //#ifdef __BIG_ENDIAN diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c index 4739c14d83593f..e92bbc12bb0649 100644 --- a/drivers/staging/wlan-ng/prism2usb.c +++ b/drivers/staging/wlan-ng/prism2usb.c @@ -4,103 +4,58 @@ #include "prism2sta.c" #include "prism2fw.c" -#define PRISM_USB_DEVICE(vid, pid, name) \ - USB_DEVICE(vid, pid), \ - .driver_info = (unsigned long) name +#define PRISM_DEV(vid, pid, name) \ + { USB_DEVICE(vid, pid), \ + .driver_info = (unsigned long) name } static struct usb_device_id usb_prism_tbl[] = { - {PRISM_USB_DEVICE(0x04bb, 0x0922, "IOData AirPort WN-B11/USBS")}, - {PRISM_USB_DEVICE(0x07aa, 0x0012, "Corega Wireless LAN USB Stick-11")}, - {PRISM_USB_DEVICE(0x09aa, 0x3642, "Prism2.x 11Mbps WLAN USB Adapter")}, - {PRISM_USB_DEVICE - (0x1668, 0x0408, "Actiontec Prism2.5 11Mbps WLAN USB Adapter")}, - {PRISM_USB_DEVICE - (0x1668, 0x0421, "Actiontec Prism2.5 11Mbps WLAN USB Adapter")}, - {PRISM_USB_DEVICE - (0x1915, 0x2236, "Linksys WUSB11v3.0 11Mbps WLAN USB Adapter")}, - {PRISM_USB_DEVICE - (0x066b, 0x2212, "Linksys WUSB11v2.5 11Mbps WLAN USB Adapter")}, - {PRISM_USB_DEVICE - (0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps WLAN USB Adapter")}, - {PRISM_USB_DEVICE - (0x067c, 0x1022, "Siemens SpeedStream 1022 11Mbps WLAN USB Adapter")}, - {PRISM_USB_DEVICE - (0x049f, 0x0033, - "Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter")}, - {PRISM_USB_DEVICE - (0x0411, 0x0016, "Melco WLI-USB-S11 11Mbps WLAN Adapter")}, - {PRISM_USB_DEVICE - (0x08de, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter")}, - {PRISM_USB_DEVICE - (0x8086, 0x1111, "Intel PRO/Wireless 2011B LAN USB Adapter")}, - {PRISM_USB_DEVICE - (0x0d8e, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter")}, - {PRISM_USB_DEVICE - (0x045e, 0x006e, "Microsoft MN510 Wireless USB Adapter")}, - {PRISM_USB_DEVICE(0x0967, 0x0204, "Acer Warplink USB Adapter")}, - {PRISM_USB_DEVICE - (0x0cde, 0x0002, "Z-Com 725/726 Prism2.5 USB/USB Integrated")}, - {PRISM_USB_DEVICE - (0x0cde, 0x0005, "Z-Com Xl735 Wireless 802.11b USB Adapter")}, - {PRISM_USB_DEVICE - (0x413c, 0x8100, "Dell TrueMobile 1180 Wireless USB Adapter")}, - {PRISM_USB_DEVICE - (0x0b3b, 0x1601, "ALLNET 0193 11Mbps WLAN USB Adapter")}, - {PRISM_USB_DEVICE - (0x0b3b, 0x1602, "ZyXEL ZyAIR B200 Wireless USB Adapter")}, - {PRISM_USB_DEVICE - (0x0baf, 0x00eb, "USRobotics USR1120 Wireless USB Adapter")}, - {PRISM_USB_DEVICE - (0x0411, 0x0027, "Melco WLI-USB-KS11G 11Mbps WLAN Adapter")}, - {PRISM_USB_DEVICE - (0x04f1, 0x3009, "JVC MP-XP7250 Builtin USB WLAN Adapter")}, - {PRISM_USB_DEVICE(0x0846, 0x4110, "NetGear MA111")}, - {PRISM_USB_DEVICE(0x03f3, 0x0020, "Adaptec AWN-8020 USB WLAN Adapter")}, - {PRISM_USB_DEVICE(0x2821, 0x3300, "ASUS-WL140 Wireless USB Adapter")}, - {PRISM_USB_DEVICE(0x2001, 0x3700, "DWL-122 Wireless USB Adapter")}, - {PRISM_USB_DEVICE - (0x2001, 0x3702, "DWL-120 Rev F Wireless USB Adapter")}, - {PRISM_USB_DEVICE(0x50c2, 0x4013, "Averatec USB WLAN Adapter")}, - {PRISM_USB_DEVICE(0x2c02, 0x14ea, "Planex GW-US11H WLAN USB Adapter")}, - {PRISM_USB_DEVICE(0x124a, 0x168b, "Airvast PRISM3 WLAN USB Adapter")}, - {PRISM_USB_DEVICE(0x083a, 0x3503, "T-Sinus 111 USB WLAN Adapter")}, - {PRISM_USB_DEVICE(0x2821, 0x3300, "Hawking HighDB USB Adapter")}, - {PRISM_USB_DEVICE - (0x0411, 0x0044, "Melco WLI-USB-KB11 11Mbps WLAN Adapter")}, - {PRISM_USB_DEVICE(0x1668, 0x6106, "ROPEX FreeLan 802.11b USB Adapter")}, - {PRISM_USB_DEVICE - (0x124a, 0x4017, "Pheenet WL-503IA 802.11b USB Adapter")}, - {PRISM_USB_DEVICE(0x0bb2, 0x0302, "Ambit Microsystems Corp.")}, - {PRISM_USB_DEVICE - (0x9016, 0x182d, "Sitecom WL-022 802.11b USB Adapter")}, - {PRISM_USB_DEVICE - (0x0543, 0x0f01, "ViewSonic Airsync USB Adapter 11Mbps (Prism2.5)")}, - { /* terminator */ } + PRISM_DEV(0x04bb, 0x0922, "IOData AirPort WN-B11/USBS"), + PRISM_DEV(0x07aa, 0x0012, "Corega Wireless LAN USB Stick-11"), + PRISM_DEV(0x09aa, 0x3642, "Prism2.x 11Mbps WLAN USB Adapter"), + PRISM_DEV(0x1668, 0x0408, "Actiontec Prism2.5 11Mbps WLAN USB Adapter"), + PRISM_DEV(0x1668, 0x0421, "Actiontec Prism2.5 11Mbps WLAN USB Adapter"), + PRISM_DEV(0x1915, 0x2236, "Linksys WUSB11v3.0 11Mbps WLAN USB Adapter"), + PRISM_DEV(0x066b, 0x2212, "Linksys WUSB11v2.5 11Mbps WLAN USB Adapter"), + PRISM_DEV(0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps WLAN USB Adapter"), + PRISM_DEV(0x0411, 0x0016, "Melco WLI-USB-S11 11Mbps WLAN Adapter"), + PRISM_DEV(0x08de, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter"), + PRISM_DEV(0x8086, 0x1111, "Intel PRO/Wireless 2011B LAN USB Adapter"), + PRISM_DEV(0x0d8e, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter"), + PRISM_DEV(0x045e, 0x006e, "Microsoft MN510 Wireless USB Adapter"), + PRISM_DEV(0x0967, 0x0204, "Acer Warplink USB Adapter"), + PRISM_DEV(0x0cde, 0x0002, "Z-Com 725/726 Prism2.5 USB/USB Integrated"), + PRISM_DEV(0x0cde, 0x0005, "Z-Com Xl735 Wireless 802.11b USB Adapter"), + PRISM_DEV(0x413c, 0x8100, "Dell TrueMobile 1180 Wireless USB Adapter"), + PRISM_DEV(0x0b3b, 0x1601, "ALLNET 0193 11Mbps WLAN USB Adapter"), + PRISM_DEV(0x0b3b, 0x1602, "ZyXEL ZyAIR B200 Wireless USB Adapter"), + PRISM_DEV(0x0baf, 0x00eb, "USRobotics USR1120 Wireless USB Adapter"), + PRISM_DEV(0x0411, 0x0027, "Melco WLI-USB-KS11G 11Mbps WLAN Adapter"), + PRISM_DEV(0x04f1, 0x3009, "JVC MP-XP7250 Builtin USB WLAN Adapter"), + PRISM_DEV(0x0846, 0x4110, "NetGear MA111"), + PRISM_DEV(0x03f3, 0x0020, "Adaptec AWN-8020 USB WLAN Adapter"), + PRISM_DEV(0x2821, 0x3300, "ASUS-WL140 Wireless USB Adapter"), + PRISM_DEV(0x2001, 0x3700, "DWL-122 Wireless USB Adapter"), + PRISM_DEV(0x2001, 0x3702, "DWL-120 Rev F Wireless USB Adapter"), + PRISM_DEV(0x50c2, 0x4013, "Averatec USB WLAN Adapter"), + PRISM_DEV(0x2c02, 0x14ea, "Planex GW-US11H WLAN USB Adapter"), + PRISM_DEV(0x124a, 0x168b, "Airvast PRISM3 WLAN USB Adapter"), + PRISM_DEV(0x083a, 0x3503, "T-Sinus 111 USB WLAN Adapter"), + PRISM_DEV(0x2821, 0x3300, "Hawking HighDB USB Adapter"), + PRISM_DEV(0x0411, 0x0044, "Melco WLI-USB-KB11 11Mbps WLAN Adapter"), + PRISM_DEV(0x1668, 0x6106, "ROPEX FreeLan 802.11b USB Adapter"), + PRISM_DEV(0x124a, 0x4017, "Pheenet WL-503IA 802.11b USB Adapter"), + PRISM_DEV(0x0bb2, 0x0302, "Ambit Microsystems Corp."), + PRISM_DEV(0x9016, 0x182d, "Sitecom WL-022 802.11b USB Adapter"), + PRISM_DEV(0x0543, 0x0f01, + "ViewSonic Airsync USB Adapter 11Mbps (Prism2.5)"), + PRISM_DEV(0x067c, 0x1022, + "Siemens SpeedStream 1022 11Mbps WLAN USB Adapter"), + PRISM_DEV(0x049f, 0x0033, + "Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter"), + { } /* terminator */ }; - MODULE_DEVICE_TABLE(usb, usb_prism_tbl); -/*---------------------------------------------------------------- -* prism2sta_probe_usb -* -* Probe routine called by the USB subsystem. -* -* Arguments: -* dev ptr to the usb_device struct -* ifnum interface number being offered -* -* Returns: -* NULL - we're not claiming the device+interface -* non-NULL - we are claiming the device+interface and -* this is a ptr to the data we want back -* when disconnect is called. -* -* Side effects: -* -* Call context: -* I'm not sure, assume it's interrupt. -* -----------------------------------------------------------------*/ static int prism2sta_probe_usb(struct usb_interface *interface, const struct usb_device_id *id) { @@ -141,7 +96,8 @@ static int prism2sta_probe_usb(struct usb_interface *interface, prism2_reset_settletime, 0); if (result != 0) { result = -EIO; - dev_err(&interface->dev, "hfa384x_corereset() failed.\n"); + dev_err(&interface->dev, + "hfa384x_corereset() failed.\n"); goto failed_reset; } } @@ -176,31 +132,11 @@ static int prism2sta_probe_usb(struct usb_interface *interface, return result; } -/*---------------------------------------------------------------- -* prism2sta_disconnect_usb -* -* Called when a device previously claimed by probe is removed -* from the USB. -* -* Arguments: -* dev ptr to the usb_device struct -* ptr ptr returned by probe() when the device -* was claimed. -* -* Returns: -* Nothing -* -* Side effects: -* -* Call context: -* process -----------------------------------------------------------------*/ static void prism2sta_disconnect_usb(struct usb_interface *interface) { wlandevice_t *wlandev; wlandev = (wlandevice_t *) usb_get_intfdata(interface); - if (wlandev != NULL) { LIST_HEAD(cleanlist); struct list_head *entry; @@ -292,6 +228,7 @@ static int prism2sta_suspend(struct usb_interface *interface, { hfa384x_t *hw = NULL; wlandevice_t *wlandev; + wlandev = (wlandevice_t *) usb_get_intfdata(interface); if (!wlandev) return -ENODEV; @@ -314,6 +251,7 @@ static int prism2sta_resume(struct usb_interface *interface) int result = 0; hfa384x_t *hw = NULL; wlandevice_t *wlandev; + wlandev = (wlandevice_t *) usb_get_intfdata(interface); if (!wlandev) return -ENODEV; diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c index 466804687fc04c..a62d4dd4ce8260 100644 --- a/drivers/staging/xgifb/XGI_main_26.c +++ b/drivers/staging/xgifb/XGI_main_26.c @@ -66,6 +66,7 @@ static int XGIfb_mode_rate_to_dclock(struct vb_device_info *XGI_Pr, unsigned short ModeIdIndex = 0, ClockIndex = 0; unsigned short RefreshRateTableIndex = 0; int Clock; + InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr); XGI_SearchModeID(ModeNo, &ModeIdIndex); @@ -95,6 +96,7 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr, unsigned short HRE, HBE, HRS, HDE; unsigned char sr_data, cr_data, cr_data2; int B, C, D, F, temp, j; + InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr); if (!XGI_SearchModeID(ModeNo, &ModeIdIndex)) return 0; diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c index 21541720e05ce5..ff210ddcbf9e5c 100644 --- a/drivers/staging/xgifb/vb_init.c +++ b/drivers/staging/xgifb/vb_init.c @@ -130,6 +130,7 @@ static void XGINew_DDRII_Bootup_XG27( unsigned long P3c4, struct vb_device_info *pVBInfo) { unsigned long P3d4 = P3c4 + 0x10; + pVBInfo->ram_type = XGINew_GetXG20DRAMType(HwDeviceExtension, pVBInfo); XGINew_SetMemoryClock(pVBInfo); @@ -389,6 +390,7 @@ static void XGI_SetDRAM_Helper(unsigned long P3d4, u8 seed, u8 temp2, u8 reg, u8 shift_factor, u8 mask1, u8 mask2) { u8 j; + for (j = 0; j < 4; j++) { temp2 |= (((seed >> (2 * j)) & 0x03) << shift_factor); xgifb_reg_set(P3d4, reg, temp2); diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c index 400c726753fa48..c638c8febee945 100644 --- a/drivers/staging/xgifb/vb_setmode.c +++ b/drivers/staging/xgifb/vb_setmode.c @@ -49,6 +49,7 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo) if (ChipType == XG27) { unsigned char temp; + pVBInfo->MCLKData = XGI27New_MCLKData; pVBInfo->CR40 = XGI27_cr41; pVBInfo->XGINew_CR97 = 0xc1; @@ -5222,6 +5223,7 @@ void XGI_SenseCRT1(struct vb_device_info *pVBInfo) unsigned short temp; int i; + xgifb_reg_set(pVBInfo->P3c4, 0x05, 0x86); /* to fix XG42 single LCD sense to CRT+LCD */ diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index c886ad1c39fb35..73ab75ddaf42e9 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -951,7 +951,7 @@ static int tcm_loop_port_link( struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; atomic_inc(&tl_tpg->tl_tpg_port_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); /* * Add Linux/SCSI struct scsi_device by HCTL */ @@ -986,7 +986,7 @@ static void tcm_loop_port_unlink( scsi_device_put(sd); atomic_dec(&tl_tpg->tl_tpg_port_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); pr_debug("TCM_Loop_ConfigFS: Port Unlink Successful\n"); } diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index fcbe6125b73ee5..0b79b852f4b2d9 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -393,7 +393,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) continue; atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&dev->t10_alua.tg_pt_gps_lock); @@ -404,7 +404,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) spin_lock(&dev->t10_alua.tg_pt_gps_lock); atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); break; } spin_unlock(&dev->t10_alua.tg_pt_gps_lock); @@ -990,7 +990,7 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) * TARGET PORT GROUPS command */ atomic_inc(&mem->tg_pt_gp_mem_ref_cnt); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&tg_pt_gp->tg_pt_gp_lock); spin_lock_bh(&port->sep_alua_lock); @@ -1020,7 +1020,7 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) spin_lock(&tg_pt_gp->tg_pt_gp_lock); atomic_dec(&mem->tg_pt_gp_mem_ref_cnt); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); /* @@ -1054,7 +1054,7 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_pending_state)); spin_lock(&dev->t10_alua.tg_pt_gps_lock); atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); spin_unlock(&dev->t10_alua.tg_pt_gps_lock); if (tg_pt_gp->tg_pt_gp_transition_complete) @@ -1116,7 +1116,7 @@ static int core_alua_do_transition_tg_pt( */ spin_lock(&dev->t10_alua.tg_pt_gps_lock); atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&dev->t10_alua.tg_pt_gps_lock); if (!explicit && tg_pt_gp->tg_pt_gp_implicit_trans_secs) { @@ -1159,7 +1159,7 @@ int core_alua_do_port_transition( spin_lock(&local_lu_gp_mem->lu_gp_mem_lock); lu_gp = local_lu_gp_mem->lu_gp; atomic_inc(&lu_gp->lu_gp_ref_cnt); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&local_lu_gp_mem->lu_gp_mem_lock); /* * For storage objects that are members of the 'default_lu_gp', @@ -1176,7 +1176,7 @@ int core_alua_do_port_transition( rc = core_alua_do_transition_tg_pt(l_tg_pt_gp, new_state, explicit); atomic_dec(&lu_gp->lu_gp_ref_cnt); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); return rc; } /* @@ -1190,7 +1190,7 @@ int core_alua_do_port_transition( dev = lu_gp_mem->lu_gp_mem_dev; atomic_inc(&lu_gp_mem->lu_gp_mem_ref_cnt); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&lu_gp->lu_gp_lock); spin_lock(&dev->t10_alua.tg_pt_gps_lock); @@ -1219,7 +1219,7 @@ int core_alua_do_port_transition( tg_pt_gp->tg_pt_gp_alua_nacl = NULL; } atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&dev->t10_alua.tg_pt_gps_lock); /* * core_alua_do_transition_tg_pt() will always return @@ -1230,7 +1230,7 @@ int core_alua_do_port_transition( spin_lock(&dev->t10_alua.tg_pt_gps_lock); atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); if (rc) break; } @@ -1238,7 +1238,7 @@ int core_alua_do_port_transition( spin_lock(&lu_gp->lu_gp_lock); atomic_dec(&lu_gp_mem->lu_gp_mem_ref_cnt); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); } spin_unlock(&lu_gp->lu_gp_lock); @@ -1252,7 +1252,7 @@ int core_alua_do_port_transition( } atomic_dec(&lu_gp->lu_gp_ref_cnt); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); return rc; } diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 65001e13367029..72618776ede414 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -225,7 +225,7 @@ struct se_dev_entry *core_get_se_deve_from_rtpi( continue; atomic_inc(&deve->pr_ref_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock_irq(&nacl->device_list_lock); return deve; @@ -1392,7 +1392,7 @@ int core_dev_add_initiator_node_lun_acl( spin_lock(&lun->lun_acl_lock); list_add_tail(&lacl->lacl_list, &lun->lun_acl_list); atomic_inc(&lun->lun_acl_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&lun->lun_acl_lock); pr_debug("%s_TPG[%hu]_LUN[%u->%u] - Added %s ACL for " @@ -1426,7 +1426,7 @@ int core_dev_del_initiator_node_lun_acl( spin_lock(&lun->lun_acl_lock); list_del(&lacl->lacl_list); atomic_dec(&lun->lun_acl_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); spin_unlock(&lun->lun_acl_lock); core_disable_device_list_for_node(lun, NULL, lacl->mapped_lun, diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 9e0232cca92e03..7e6b857c6b3f18 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -323,7 +323,7 @@ static void iblock_bio_done(struct bio *bio, int err) * Bump the ib_bio_err_cnt and release bio. */ atomic_inc(&ibr->ib_bio_err_cnt); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } bio_put(bio); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 3013287a2aaa19..df357862286e10 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -675,7 +675,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( spin_lock(&dev->se_port_lock); list_for_each_entry_safe(port, port_tmp, &dev->dev_sep_list, sep_list) { atomic_inc(&port->sep_tg_pt_ref_cnt); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&dev->se_port_lock); spin_lock_bh(&port->sep_alua_lock); @@ -710,7 +710,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( continue; atomic_inc(&deve_tmp->pr_ref_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock_bh(&port->sep_alua_lock); /* * Grab a configfs group dependency that is released @@ -723,9 +723,9 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( pr_err("core_scsi3_lunacl_depend" "_item() failed\n"); atomic_dec(&port->sep_tg_pt_ref_cnt); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); atomic_dec(&deve_tmp->pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); goto out; } /* @@ -740,9 +740,9 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( sa_res_key, all_tg_pt, aptpl); if (!pr_reg_atp) { atomic_dec(&port->sep_tg_pt_ref_cnt); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); atomic_dec(&deve_tmp->pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); core_scsi3_lunacl_undepend_item(deve_tmp); goto out; } @@ -755,7 +755,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( spin_lock(&dev->se_port_lock); atomic_dec(&port->sep_tg_pt_ref_cnt); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); } spin_unlock(&dev->se_port_lock); @@ -1110,7 +1110,7 @@ static struct t10_pr_registration *__core_scsi3_locate_pr_reg( continue; } atomic_inc(&pr_reg->pr_res_holders); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&pr_tmpl->registration_lock); return pr_reg; } @@ -1125,7 +1125,7 @@ static struct t10_pr_registration *__core_scsi3_locate_pr_reg( continue; atomic_inc(&pr_reg->pr_res_holders); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&pr_tmpl->registration_lock); return pr_reg; } @@ -1155,7 +1155,7 @@ static struct t10_pr_registration *core_scsi3_locate_pr_reg( static void core_scsi3_put_pr_reg(struct t10_pr_registration *pr_reg) { atomic_dec(&pr_reg->pr_res_holders); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); } static int core_scsi3_check_implicit_release( @@ -1349,7 +1349,7 @@ static void core_scsi3_tpg_undepend_item(struct se_portal_group *tpg) &tpg->tpg_group.cg_item); atomic_dec(&tpg->tpg_pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); } static int core_scsi3_nodeacl_depend_item(struct se_node_acl *nacl) @@ -1369,7 +1369,7 @@ static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl) if (nacl->dynamic_node_acl) { atomic_dec(&nacl->acl_pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); return; } @@ -1377,7 +1377,7 @@ static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl) &nacl->acl_group.cg_item); atomic_dec(&nacl->acl_pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); } static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve) @@ -1408,7 +1408,7 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) */ if (!lun_acl) { atomic_dec(&se_deve->pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); return; } nacl = lun_acl->se_lun_nacl; @@ -1418,7 +1418,7 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) &lun_acl->se_lun_group.cg_item); atomic_dec(&se_deve->pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); } static sense_reason_t @@ -1552,14 +1552,14 @@ core_scsi3_decode_spec_i_port( continue; atomic_inc(&tmp_tpg->tpg_pr_ref_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&dev->se_port_lock); if (core_scsi3_tpg_depend_item(tmp_tpg)) { pr_err(" core_scsi3_tpg_depend_item()" " for tmp_tpg\n"); atomic_dec(&tmp_tpg->tpg_pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto out_unmap; } @@ -1573,7 +1573,7 @@ core_scsi3_decode_spec_i_port( tmp_tpg, i_str); if (dest_node_acl) { atomic_inc(&dest_node_acl->acl_pr_ref_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } spin_unlock_irq(&tmp_tpg->acl_node_lock); @@ -1587,7 +1587,7 @@ core_scsi3_decode_spec_i_port( pr_err("configfs_depend_item() failed" " for dest_node_acl->acl_group\n"); atomic_dec(&dest_node_acl->acl_pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); core_scsi3_tpg_undepend_item(tmp_tpg); ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto out_unmap; @@ -1647,7 +1647,7 @@ core_scsi3_decode_spec_i_port( pr_err("core_scsi3_lunacl_depend_item()" " failed\n"); atomic_dec(&dest_se_deve->pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; @@ -3168,14 +3168,14 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, continue; atomic_inc(&dest_se_tpg->tpg_pr_ref_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&dev->se_port_lock); if (core_scsi3_tpg_depend_item(dest_se_tpg)) { pr_err("core_scsi3_tpg_depend_item() failed" " for dest_se_tpg\n"); atomic_dec(&dest_se_tpg->tpg_pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto out_put_pr_reg; } @@ -3273,7 +3273,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, initiator_str); if (dest_node_acl) { atomic_inc(&dest_node_acl->acl_pr_ref_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } spin_unlock_irq(&dest_se_tpg->acl_node_lock); @@ -3289,7 +3289,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, pr_err("core_scsi3_nodeacl_depend_item() for" " dest_node_acl\n"); atomic_dec(&dest_node_acl->acl_pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); dest_node_acl = NULL; ret = TCM_INVALID_PARAMETER_LIST; goto out; @@ -3314,7 +3314,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, if (core_scsi3_lunacl_depend_item(dest_se_deve)) { pr_err("core_scsi3_lunacl_depend_item() failed\n"); atomic_dec(&dest_se_deve->pr_ref_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); dest_se_deve = NULL; ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto out; @@ -3880,7 +3880,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) add_desc_len = 0; atomic_inc(&pr_reg->pr_res_holders); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock(&pr_tmpl->registration_lock); /* * Determine expected length of $FABRIC_MOD specific @@ -3894,7 +3894,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) " out of buffer: %d\n", cmd->data_length); spin_lock(&pr_tmpl->registration_lock); atomic_dec(&pr_reg->pr_res_holders); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); break; } /* @@ -3956,7 +3956,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) spin_lock(&pr_tmpl->registration_lock); atomic_dec(&pr_reg->pr_res_holders); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); /* * Set the ADDITIONAL DESCRIPTOR LENGTH */ diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index d4b98690a73680..4badca1cd625ce 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -736,7 +736,7 @@ void target_qf_do_work(struct work_struct *work) list_for_each_entry_safe(cmd, cmd_tmp, &qf_cmd_list, se_qf_node) { list_del(&cmd->se_qf_node); atomic_dec(&dev->dev_qf_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); pr_debug("Processing %s cmd: %p QUEUE_FULL in work queue" " context: %s\n", cmd->se_tfo->get_fabric_name(), cmd, @@ -1148,7 +1148,7 @@ transport_check_alloc_task_attr(struct se_cmd *cmd) * Dormant to Active status. */ cmd->se_ordered_id = atomic_inc_return(&dev->dev_ordered_id); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); pr_debug("Allocated se_ordered_id: %u for Task Attr: 0x%02x on %s\n", cmd->se_ordered_id, cmd->sam_task_attr, dev->transport->name); @@ -1705,7 +1705,7 @@ static bool target_handle_task_attr(struct se_cmd *cmd) return false; case MSG_ORDERED_TAG: atomic_inc(&dev->dev_ordered_sync); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); pr_debug("Added ORDERED for CDB: 0x%02x to ordered list, " " se_ordered_id: %u\n", @@ -1723,7 +1723,7 @@ static bool target_handle_task_attr(struct se_cmd *cmd) * For SIMPLE and UNTAGGED Task Attribute commands */ atomic_inc(&dev->simple_cmds); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); break; } @@ -1828,7 +1828,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd) if (cmd->sam_task_attr == MSG_SIMPLE_TAG) { atomic_dec(&dev->simple_cmds); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); dev->dev_cur_ordered_id++; pr_debug("Incremented dev->dev_cur_ordered_id: %u for" " SIMPLE: %u\n", dev->dev_cur_ordered_id, @@ -1840,7 +1840,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd) cmd->se_ordered_id); } else if (cmd->sam_task_attr == MSG_ORDERED_TAG) { atomic_dec(&dev->dev_ordered_sync); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); dev->dev_cur_ordered_id++; pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED:" @@ -1899,7 +1899,7 @@ static void transport_handle_queue_full( spin_lock_irq(&dev->qf_cmd_lock); list_add_tail(&cmd->se_qf_node, &cmd->se_dev->qf_cmd_list); atomic_inc(&dev->dev_qf_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); spin_unlock_irq(&cmd->se_dev->qf_cmd_lock); schedule_work(&cmd->se_dev->qf_work_queue); @@ -2875,7 +2875,7 @@ void transport_send_task_abort(struct se_cmd *cmd) if (cmd->se_tfo->write_pending_status(cmd) != 0) { cmd->transport_state |= CMD_T_ABORTED; cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS; - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); return; } } diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index 505519b10cb75b..101858e245b36c 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -162,7 +162,7 @@ int core_scsi3_ua_allocate( spin_unlock_irq(&nacl->device_list_lock); atomic_inc(&deve->ua_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); return 0; } list_add_tail(&ua->ua_nacl_list, &deve->ua_list); @@ -175,7 +175,7 @@ int core_scsi3_ua_allocate( asc, ascq); atomic_inc(&deve->ua_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); return 0; } @@ -190,7 +190,7 @@ void core_scsi3_ua_release_all( kmem_cache_free(se_ua_cache, ua); atomic_dec(&deve->ua_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); } spin_unlock(&deve->ua_lock); } @@ -251,7 +251,7 @@ void core_scsi3_ua_for_check_condition( kmem_cache_free(se_ua_cache, ua); atomic_dec(&deve->ua_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); } spin_unlock(&deve->ua_lock); spin_unlock_irq(&nacl->device_list_lock); @@ -310,7 +310,7 @@ int core_scsi3_ua_clear_for_request_sense( kmem_cache_free(se_ua_cache, ua); atomic_dec(&deve->ua_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); } spin_unlock(&deve->ua_lock); spin_unlock_irq(&nacl->device_list_lock); diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 4246262c4bd249..84a75f89bf74d0 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -144,11 +144,11 @@ static int get_property(unsigned int cpu, unsigned long input, unsigned int *output, enum cpufreq_cooling_property property) { - int i, j; + int i; unsigned long max_level = 0, level = 0; unsigned int freq = CPUFREQ_ENTRY_INVALID; int descend = -1; - struct cpufreq_frequency_table *table = + struct cpufreq_frequency_table *pos, *table = cpufreq_frequency_get_table(cpu); if (!output) @@ -157,20 +157,16 @@ static int get_property(unsigned int cpu, unsigned long input, if (!table) return -EINVAL; - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - /* ignore invalid entries */ - if (table[i].frequency == CPUFREQ_ENTRY_INVALID) - continue; - + cpufreq_for_each_valid_entry(pos, table) { /* ignore duplicate entry */ - if (freq == table[i].frequency) + if (freq == pos->frequency) continue; /* get the frequency order */ if (freq != CPUFREQ_ENTRY_INVALID && descend == -1) - descend = !!(freq > table[i].frequency); + descend = freq > pos->frequency; - freq = table[i].frequency; + freq = pos->frequency; max_level++; } @@ -190,29 +186,26 @@ static int get_property(unsigned int cpu, unsigned long input, if (property == GET_FREQ) level = descend ? input : (max_level - input); - for (i = 0, j = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - /* ignore invalid entry */ - if (table[i].frequency == CPUFREQ_ENTRY_INVALID) - continue; - + i = 0; + cpufreq_for_each_valid_entry(pos, table) { /* ignore duplicate entry */ - if (freq == table[i].frequency) + if (freq == pos->frequency) continue; /* now we have a valid frequency entry */ - freq = table[i].frequency; + freq = pos->frequency; if (property == GET_LEVEL && (unsigned int)input == freq) { /* get level by frequency */ - *output = descend ? j : (max_level - j); + *output = descend ? i : (max_level - i); return 0; } - if (property == GET_FREQ && level == j) { + if (property == GET_FREQ && level == i) { /* get frequency by level */ *output = freq; return 0; } - j++; + i++; } return -EINVAL; diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index fe9d129c87351b..f95569dedc88b4 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -2041,7 +2041,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, if (found) clear_bit(eol, ldata->read_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); ldata->read_tail += c; if (found) { diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 2d4bd3929e5073..053c2007b05470 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1926,13 +1926,8 @@ static void serial8250_put_poll_char(struct uart_port *port, wait_for_xmitr(up, BOTH_EMPTY); /* * Send the character out. - * If a LF, also do CR... */ serial_port_out(port, UART_TX, c); - if (c == 10) { - wait_for_xmitr(up, BOTH_EMPTY); - serial_port_out(port, UART_TX, 13); - } /* * Finally, wait for transmitter to become empty diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index ed311357674032..51b307aab75e91 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -62,6 +62,70 @@ struct dw8250_data { struct uart_8250_dma dma; }; +struct dw8250_acpi_desc { + void (*set_termios)(struct uart_port *p, struct ktermios *termios, + struct ktermios *old); +}; + +#define BYT_PRV_CLK 0x800 +#define BYT_PRV_CLK_EN (1 << 0) +#define BYT_PRV_CLK_M_VAL_SHIFT 1 +#define BYT_PRV_CLK_N_VAL_SHIFT 16 +#define BYT_PRV_CLK_UPDATE (1 << 31) + +static void byt_set_termios(struct uart_port *p, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = tty_termios_baud_rate(termios); + unsigned int m, n; + u32 reg; + + /* + * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the + * dividers must be adjusted. + * + * uartclk = (m / n) * 100 MHz, where m <= n + */ + switch (baud) { + case 500000: + case 1000000: + case 2000000: + case 4000000: + m = 64; + n = 100; + p->uartclk = 64000000; + break; + case 3500000: + m = 56; + n = 100; + p->uartclk = 56000000; + break; + case 1500000: + case 3000000: + m = 48; + n = 100; + p->uartclk = 48000000; + break; + case 2500000: + m = 40; + n = 100; + p->uartclk = 40000000; + break; + default: + m = 2304; + n = 3125; + p->uartclk = 73728000; + } + + /* Reset the clock */ + reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); + writel(reg, p->membase + BYT_PRV_CLK); + reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; + writel(reg, p->membase + BYT_PRV_CLK); + + serial8250_do_set_termios(p, termios, old); +} + static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; @@ -278,6 +342,7 @@ static int dw8250_probe_acpi(struct uart_8250_port *up, { const struct acpi_device_id *id; struct uart_port *p = &up->port; + struct dw8250_acpi_desc *acpi_desc; dw8250_setup_port(up); @@ -290,14 +355,18 @@ static int dw8250_probe_acpi(struct uart_8250_port *up, p->serial_out = dw8250_serial_out32; p->regshift = 2; - if (!p->uartclk) - p->uartclk = (unsigned int)id->driver_data; - up->dma = &data->dma; up->dma->rxconf.src_maxburst = p->fifosize / 4; up->dma->txconf.dst_maxburst = p->fifosize / 4; + acpi_desc = (struct dw8250_acpi_desc *)id->driver_data; + if (!acpi_desc) + return 0; + + if (acpi_desc->set_termios) + p->set_termios = acpi_desc->set_termios; + return 0; } @@ -445,12 +514,16 @@ static const struct of_device_id dw8250_of_match[] = { }; MODULE_DEVICE_TABLE(of, dw8250_of_match); +static struct dw8250_acpi_desc byt_8250_desc = { + .set_termios = byt_set_termios, +}; + static const struct acpi_device_id dw8250_acpi_match[] = { { "INT33C4", 0 }, { "INT33C5", 0 }, { "INT3434", 0 }, { "INT3435", 0 }, - { "80860F0A", 0 }, + { "80860F0A", (kernel_ulong_t)&byt_8250_desc}, { }, }; MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index c100d6343d508c..cfef801a49d4c8 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -35,18 +35,8 @@ #include #include #include -#ifdef CONFIG_FIX_EARLYCON_MEM -#include -#include -#endif -struct early_serial8250_device { - struct uart_port port; - char options[16]; /* e.g., 115200n8 */ - unsigned int baud; -}; - -static struct early_serial8250_device early_device; +static struct earlycon_device *early_device; unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset) { @@ -100,7 +90,7 @@ static void __init serial_putc(struct uart_port *port, int c) static void __init early_serial8250_write(struct console *console, const char *s, unsigned int count) { - struct uart_port *port = &early_device.port; + struct uart_port *port = &early_device->port; unsigned int ier; /* Save the IER and disable interrupts */ @@ -129,7 +119,7 @@ static unsigned int __init probe_baud(struct uart_port *port) return (port->uartclk / 16) / quot; } -static void __init init_port(struct early_serial8250_device *device) +static void __init init_port(struct earlycon_device *device) { struct uart_port *port = &device->port; unsigned int divisor; @@ -148,128 +138,42 @@ static void __init init_port(struct early_serial8250_device *device) serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB); } -static int __init parse_options(struct early_serial8250_device *device, - char *options) +static int __init early_serial8250_setup(struct earlycon_device *device, + const char *options) { - struct uart_port *port = &device->port; - int mmio, mmio32, length; - - if (!options) - return -ENODEV; - - port->uartclk = BASE_BAUD * 16; - - mmio = !strncmp(options, "mmio,", 5); - mmio32 = !strncmp(options, "mmio32,", 7); - if (mmio || mmio32) { - port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32); - port->mapbase = simple_strtoul(options + (mmio ? 5 : 7), - &options, 0); - if (mmio32) - port->regshift = 2; -#ifdef CONFIG_FIX_EARLYCON_MEM - set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, - port->mapbase & PAGE_MASK); - port->membase = - (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); - port->membase += port->mapbase & ~PAGE_MASK; -#else - port->membase = ioremap_nocache(port->mapbase, 64); - if (!port->membase) { - printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n", - __func__, - (unsigned long long) port->mapbase); - return -ENOMEM; - } -#endif - } else if (!strncmp(options, "io,", 3)) { - port->iotype = UPIO_PORT; - port->iobase = simple_strtoul(options + 3, &options, 0); - mmio = 0; - } else - return -EINVAL; - - options = strchr(options, ','); - if (options) { - options++; - device->baud = simple_strtoul(options, NULL, 0); - length = min(strcspn(options, " ") + 1, - (size_t)(sizeof(device->options))); - strlcpy(device->options, options, length); - } else { - device->baud = probe_baud(port); - snprintf(device->options, sizeof(device->options), "%u", - device->baud); - } - - if (mmio || mmio32) - printk(KERN_INFO - "Early serial console at MMIO%s 0x%llx (options '%s')\n", - mmio32 ? "32" : "", - (unsigned long long)port->mapbase, - device->options); - else - printk(KERN_INFO - "Early serial console at I/O port 0x%lx (options '%s')\n", - port->iobase, - device->options); - - return 0; -} - -static struct console early_serial8250_console __initdata = { - .name = "uart", - .write = early_serial8250_write, - .flags = CON_PRINTBUFFER | CON_BOOT, - .index = -1, -}; - -static int __init early_serial8250_setup(char *options) -{ - struct early_serial8250_device *device = &early_device; - int err; - - if (device->port.membase || device->port.iobase) + if (!(device->port.membase || device->port.iobase)) return 0; - err = parse_options(device, options); - if (err < 0) - return err; + if (!device->baud) + device->baud = probe_baud(&device->port); init_port(device); + + early_device = device; + device->con->write = early_serial8250_write; return 0; } +EARLYCON_DECLARE(uart8250, early_serial8250_setup); +EARLYCON_DECLARE(uart, early_serial8250_setup); int __init setup_early_serial8250_console(char *cmdline) { - char *options; - int err; + char match[] = "uart8250"; - options = strstr(cmdline, "uart8250,"); - if (!options) { - options = strstr(cmdline, "uart,"); - if (!options) - return 0; - } + if (cmdline && cmdline[4] == ',') + match[4] = '\0'; - options = strchr(cmdline, ',') + 1; - err = early_serial8250_setup(options); - if (err < 0) - return err; - - register_console(&early_serial8250_console); - - return 0; + return setup_earlycon(cmdline, match, early_serial8250_setup); } int serial8250_find_port_for_earlycon(void) { - struct early_serial8250_device *device = &early_device; - struct uart_port *port = &device->port; + struct earlycon_device *device = early_device; + struct uart_port *port = device ? &device->port : NULL; int line; int ret; - if (!device->port.membase && !device->port.iobase) + if (!port || (!port->membase && !port->iobase)) return -ENODEV; line = serial8250_find_port(port); @@ -284,5 +188,3 @@ int serial8250_find_port_for_earlycon(void) return ret; } - -early_param("earlycon", setup_early_serial8250_console); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 23329918f2292b..349ee598b34cf5 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -61,6 +61,7 @@ config SERIAL_8250_CONSOLE bool "Console on 8250/16550 and compatible serial port" depends on SERIAL_8250=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON ---help--- If you say Y here, it will be possible to use a serial port as the system console (the system console is the device which receives all @@ -90,11 +91,6 @@ config SERIAL_8250_CONSOLE If unsure, say N. -config FIX_EARLYCON_MEM - bool - depends on X86 - default y - config SERIAL_8250_GSC tristate depends on SERIAL_8250 && GSC diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 5d9b01aa54f4c0..64c565945ac3a4 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -7,6 +7,13 @@ if TTY menu "Serial drivers" depends on HAS_IOMEM +config SERIAL_EARLYCON + bool + help + Support for early consoles with the earlycon parameter. This enables + the console before standard serial driver is probed. The console is + enabled when early_param is processed. + source "drivers/tty/serial/8250/Kconfig" comment "Non-8250 serial port support" @@ -53,6 +60,7 @@ config SERIAL_AMBA_PL011_CONSOLE bool "Support for console on AMBA serial port" depends on SERIAL_AMBA_PL011=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON ---help--- Say Y here if you wish to use an AMBA PrimeCell UART as the system console (the system console is the device which receives all kernel @@ -65,6 +73,16 @@ config SERIAL_AMBA_PL011_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) +config SERIAL_EARLYCON_ARM_SEMIHOST + bool "Early console using ARM semihosting" + depends on ARM64 || ARM + select SERIAL_EARLYCON + help + Support for early debug console using ARM semihosting. This enables + the console before standard serial driver is probed. This is enabled + with "earlycon=smh" on the kernel command line. The console is + enabled when early_param is processed. + config SERIAL_SB1250_DUART tristate "BCM1xxx on-chip DUART serial support" depends on SIBYTE_SB1xxx_SOC=y @@ -1160,6 +1178,16 @@ config SERIAL_SCCNXP_CONSOLE help Support for console on SCCNXP serial ports. +config SERIAL_SC16IS7XX + tristate "SC16IS7xx serial support" + depends on I2C + select SERIAL_CORE + select REGMAP_I2C if I2C + help + This selects support for SC16IS7xx serial ports. + Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752, + SC16IS760 and SC16IS762. + config SERIAL_BFIN_SPORT tristate "Blackfin SPORT emulate UART" depends on BLACKFIN @@ -1369,18 +1397,19 @@ config SERIAL_MXS_AUART_CONSOLE Enable a MXS AUART port to be the system console. config SERIAL_XILINX_PS_UART - tristate "Xilinx PS UART support" + tristate "Cadence (Xilinx Zynq) UART support" depends on OF select SERIAL_CORE help - This driver supports the Xilinx PS UART port. + This driver supports the Cadence UART. It is found e.g. in Xilinx + Zynq. config SERIAL_XILINX_PS_UART_CONSOLE - bool "Xilinx PS UART console support" + bool "Cadence UART console support" depends on SERIAL_XILINX_PS_UART=y select SERIAL_CORE_CONSOLE help - Enable a Xilinx PS UART port to be the system console. + Enable a Cadence UART port to be the system console. config SERIAL_AR933X tristate "AR933X serial port support" @@ -1508,6 +1537,16 @@ config SERIAL_ST_ASC_CONSOLE depends on SERIAL_ST_ASC=y select SERIAL_CORE_CONSOLE +config SERIAL_MEN_Z135 + tristate "MEN 16z135 Support" + depends on MCB + help + Say yes here to enable support for the MEN 16z135 High Speed UART IP-Core + on a MCB carrier. + + This driver can also be build as a module. If so, the module will be called + men_z135_uart.ko + endmenu endif # TTY diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 3680854fef4100..712732b43917ab 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -5,6 +5,9 @@ obj-$(CONFIG_SERIAL_CORE) += serial_core.o obj-$(CONFIG_SERIAL_21285) += 21285.o +obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o +obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o + # These Sparc drivers have to appear before others such as 8250 # which share ttySx minor node space. Otherwise console device # names change and other unplesantries. @@ -48,6 +51,7 @@ obj-$(CONFIG_SERIAL_MPSC) += mpsc.o obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o +obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o obj-$(CONFIG_SERIAL_JSM) += jsm/ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o @@ -87,3 +91,4 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o obj-$(CONFIG_SERIAL_ARC) += arc_uart.o obj-$(CONFIG_SERIAL_RP2) += rp2.o obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o +obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index dacf0a09ab248c..ee3d803467803a 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -303,7 +303,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * /* Optionally make use of an RX channel as well */ chan = dma_request_slave_channel(dev, "rx"); - + if (!chan && plat->dma_rx_param) { chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param); @@ -2045,6 +2045,34 @@ static struct console amba_console = { }; #define AMBA_CONSOLE (&amba_console) + +static void pl011_putc(struct uart_port *port, int c) +{ + while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) + ; + writeb(c, port->membase + UART01x_DR); + while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY) + ; +} + +static void pl011_early_write(struct console *con, const char *s, unsigned n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, pl011_putc); +} + +static int __init pl011_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = pl011_early_write; + return 0; +} +EARLYCON_DECLARE(pl011, pl011_early_console_setup); + #else #define AMBA_CONSOLE NULL #endif diff --git a/drivers/tty/serial/earlycon-arm-semihost.c b/drivers/tty/serial/earlycon-arm-semihost.c new file mode 100644 index 00000000000000..383db10fbb499a --- /dev/null +++ b/drivers/tty/serial/earlycon-arm-semihost.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * Author: Marc Zyngier + * + * Adapted for ARM and earlycon: + * Copyright (C) 2014 Linaro Ltd. + * Author: Rob Herring + * + * 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, see . + */ +#include +#include +#include +#include + +#ifdef CONFIG_THUMB2_KERNEL +#define SEMIHOST_SWI "0xab" +#else +#define SEMIHOST_SWI "0x123456" +#endif + +/* + * Semihosting-based debug console + */ +static void smh_putc(struct uart_port *port, int c) +{ +#ifdef CONFIG_ARM64 + asm volatile("mov x1, %0\n" + "mov x0, #3\n" + "hlt 0xf000\n" + : : "r" (&c) : "x0", "x1", "memory"); +#else + asm volatile("mov r1, %0\n" + "mov r0, #3\n" + "svc " SEMIHOST_SWI "\n" + : : "r" (&c) : "r0", "r1", "memory"); +#endif +} + +static void smh_write(struct console *con, const char *s, unsigned n) +{ + struct earlycon_device *dev = con->data; + uart_console_write(&dev->port, s, n, smh_putc); +} + +int __init early_smh_setup(struct earlycon_device *device, const char *opt) +{ + device->con->write = smh_write; + return 0; +} +EARLYCON_DECLARE(smh, early_smh_setup); diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c new file mode 100644 index 00000000000000..c92e83088adb81 --- /dev/null +++ b/drivers/tty/serial/earlycon.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * Author: Rob Herring + * + * Based on 8250 earlycon: + * (c) Copyright 2004 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas + * + * 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 + +#ifdef CONFIG_FIX_EARLYCON_MEM +#include +#endif + +#include + +static struct console early_con = { + .name = "earlycon", + .flags = CON_PRINTBUFFER | CON_BOOT, + .index = -1, +}; + +static struct earlycon_device early_console_dev = { + .con = &early_con, +}; + +static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) +{ + void __iomem *base; +#ifdef CONFIG_FIX_EARLYCON_MEM + set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK); + base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); + base += paddr & ~PAGE_MASK; +#else + base = ioremap(paddr, size); +#endif + if (!base) + pr_err("%s: Couldn't map 0x%llx\n", __func__, + (unsigned long long)paddr); + + return base; +} + +static int __init parse_options(struct earlycon_device *device, + char *options) +{ + struct uart_port *port = &device->port; + int mmio, mmio32, length; + unsigned long addr; + + if (!options) + return -ENODEV; + + mmio = !strncmp(options, "mmio,", 5); + mmio32 = !strncmp(options, "mmio32,", 7); + if (mmio || mmio32) { + port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32); + options += mmio ? 5 : 7; + addr = simple_strtoul(options, NULL, 0); + port->mapbase = addr; + if (mmio32) + port->regshift = 2; + } else if (!strncmp(options, "io,", 3)) { + port->iotype = UPIO_PORT; + options += 3; + addr = simple_strtoul(options, NULL, 0); + port->iobase = addr; + mmio = 0; + } else if (!strncmp(options, "0x", 2)) { + port->iotype = UPIO_MEM; + addr = simple_strtoul(options, NULL, 0); + port->mapbase = addr; + } else { + return -EINVAL; + } + + port->uartclk = BASE_BAUD * 16; + + options = strchr(options, ','); + if (options) { + options++; + device->baud = simple_strtoul(options, NULL, 0); + length = min(strcspn(options, " ") + 1, + (size_t)(sizeof(device->options))); + strlcpy(device->options, options, length); + } + + if (mmio || mmio32) + pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n", + mmio32 ? "32" : "", + (unsigned long long)port->mapbase, + device->options); + else + pr_info("Early serial console at I/O port 0x%lx (options '%s')\n", + port->iobase, + device->options); + + return 0; +} + +int __init setup_earlycon(char *buf, const char *match, + int (*setup)(struct earlycon_device *, const char *)) +{ + int err; + size_t len; + struct uart_port *port = &early_console_dev.port; + + if (!buf || !match || !setup) + return 0; + + len = strlen(match); + if (strncmp(buf, match, len)) + return 0; + if (buf[len] && (buf[len] != ',')) + return 0; + + buf += len + 1; + + err = parse_options(&early_console_dev, buf); + /* On parsing error, pass the options buf to the setup function */ + if (!err) + buf = NULL; + + if (port->mapbase) + port->membase = earlycon_map(port->mapbase, 64); + + early_console_dev.con->data = &early_console_dev; + err = setup(&early_console_dev, buf); + if (err < 0) + return err; + if (!early_console_dev.con->write) + return -ENODEV; + + register_console(early_console_dev.con); + return 0; +} diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c new file mode 100644 index 00000000000000..d08eb5d8330dc8 --- /dev/null +++ b/drivers/tty/serial/men_z135_uart.c @@ -0,0 +1,866 @@ +/* + * MEN 16z135 High Speed UART + * + * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de) + * Author: Johannes Thumshirn + * + * 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. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MEN_Z135_MAX_PORTS 12 +#define MEN_Z135_BASECLK 29491200 +#define MEN_Z135_FIFO_SIZE 1024 +#define MEN_Z135_NUM_MSI_VECTORS 2 +#define MEN_Z135_FIFO_WATERMARK 1020 + +#define MEN_Z135_STAT_REG 0x0 +#define MEN_Z135_RX_RAM 0x4 +#define MEN_Z135_TX_RAM 0x400 +#define MEN_Z135_RX_CTRL 0x800 +#define MEN_Z135_TX_CTRL 0x804 +#define MEN_Z135_CONF_REG 0x808 +#define MEN_Z135_UART_FREQ 0x80c +#define MEN_Z135_BAUD_REG 0x810 +#define MENZ135_TIMEOUT 0x814 + +#define MEN_Z135_MEM_SIZE 0x818 + +#define IS_IRQ(x) ((x) & 1) +#define IRQ_ID(x) (((x) >> 1) & 7) + +#define MEN_Z135_IER_RXCIEN BIT(0) /* TX Space IRQ */ +#define MEN_Z135_IER_TXCIEN BIT(1) /* RX Space IRQ */ +#define MEN_Z135_IER_RLSIEN BIT(2) /* Receiver Line Status IRQ */ +#define MEN_Z135_IER_MSIEN BIT(3) /* Modem Status IRQ */ +#define MEN_Z135_ALL_IRQS (MEN_Z135_IER_RXCIEN \ + | MEN_Z135_IER_RLSIEN \ + | MEN_Z135_IER_MSIEN \ + | MEN_Z135_IER_TXCIEN) + +#define MEN_Z135_MCR_DTR BIT(24) +#define MEN_Z135_MCR_RTS BIT(25) +#define MEN_Z135_MCR_OUT1 BIT(26) +#define MEN_Z135_MCR_OUT2 BIT(27) +#define MEN_Z135_MCR_LOOP BIT(28) +#define MEN_Z135_MCR_RCFC BIT(29) + +#define MEN_Z135_MSR_DCTS BIT(0) +#define MEN_Z135_MSR_DDSR BIT(1) +#define MEN_Z135_MSR_DRI BIT(2) +#define MEN_Z135_MSR_DDCD BIT(3) +#define MEN_Z135_MSR_CTS BIT(4) +#define MEN_Z135_MSR_DSR BIT(5) +#define MEN_Z135_MSR_RI BIT(6) +#define MEN_Z135_MSR_DCD BIT(7) + +#define MEN_Z135_LCR_SHIFT 8 /* LCR shift mask */ + +#define MEN_Z135_WL5 0 /* CS5 */ +#define MEN_Z135_WL6 1 /* CS6 */ +#define MEN_Z135_WL7 2 /* CS7 */ +#define MEN_Z135_WL8 3 /* CS8 */ + +#define MEN_Z135_STB_SHIFT 2 /* Stopbits */ +#define MEN_Z135_NSTB1 0 +#define MEN_Z135_NSTB2 1 + +#define MEN_Z135_PEN_SHIFT 3 /* Parity enable */ +#define MEN_Z135_PAR_DIS 0 +#define MEN_Z135_PAR_ENA 1 + +#define MEN_Z135_PTY_SHIFT 4 /* Parity type */ +#define MEN_Z135_PTY_ODD 0 +#define MEN_Z135_PTY_EVN 1 + +#define MEN_Z135_LSR_DR BIT(0) +#define MEN_Z135_LSR_OE BIT(1) +#define MEN_Z135_LSR_PE BIT(2) +#define MEN_Z135_LSR_FE BIT(3) +#define MEN_Z135_LSR_BI BIT(4) +#define MEN_Z135_LSR_THEP BIT(5) +#define MEN_Z135_LSR_TEXP BIT(6) +#define MEN_Z135_LSR_RXFIFOERR BIT(7) + +#define MEN_Z135_IRQ_ID_MST 0 +#define MEN_Z135_IRQ_ID_TSA 1 +#define MEN_Z135_IRQ_ID_RDA 2 +#define MEN_Z135_IRQ_ID_RLS 3 +#define MEN_Z135_IRQ_ID_CTI 6 + +#define LCR(x) (((x) >> MEN_Z135_LCR_SHIFT) & 0xff) + +#define BYTES_TO_ALIGN(x) ((x) & 0x3) + +static int line; + +static int txlvl = 5; +module_param(txlvl, int, S_IRUGO); +MODULE_PARM_DESC(txlvl, "TX IRQ trigger level 0-7, default 5 (128 byte)"); + +static int rxlvl = 6; +module_param(rxlvl, int, S_IRUGO); +MODULE_PARM_DESC(rxlvl, "RX IRQ trigger level 0-7, default 6 (256 byte)"); + +static int align; +module_param(align, int, S_IRUGO); +MODULE_PARM_DESC(align, "Keep hardware FIFO write pointer aligned, default 0"); + +struct men_z135_port { + struct uart_port port; + struct mcb_device *mdev; + unsigned char *rxbuf; + u32 stat_reg; + spinlock_t lock; +}; +#define to_men_z135(port) container_of((port), struct men_z135_port, port) + +/** + * men_z135_reg_set() - Set value in register + * @uart: The UART port + * @addr: Register address + * @val: value to set + */ +static inline void men_z135_reg_set(struct men_z135_port *uart, + u32 addr, u32 val) +{ + struct uart_port *port = &uart->port; + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&uart->lock, flags); + + reg = ioread32(port->membase + addr); + reg |= val; + iowrite32(reg, port->membase + addr); + + spin_unlock_irqrestore(&uart->lock, flags); +} + +/** + * men_z135_reg_clr() - Unset value in register + * @uart: The UART port + * @addr: Register address + * @val: value to clear + */ +static inline void men_z135_reg_clr(struct men_z135_port *uart, + u32 addr, u32 val) +{ + struct uart_port *port = &uart->port; + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&uart->lock, flags); + + reg = ioread32(port->membase + addr); + reg &= ~val; + iowrite32(reg, port->membase + addr); + + spin_unlock_irqrestore(&uart->lock, flags); +} + +/** + * men_z135_handle_modem_status() - Handle change of modem status + * @port: The UART port + * + * Handle change of modem status register. This is done by reading the "delta" + * versions of DCD (Data Carrier Detect) and CTS (Clear To Send). + */ +static void men_z135_handle_modem_status(struct men_z135_port *uart) +{ + if (uart->stat_reg & MEN_Z135_MSR_DDCD) + uart_handle_dcd_change(&uart->port, + uart->stat_reg & ~MEN_Z135_MSR_DCD); + if (uart->stat_reg & MEN_Z135_MSR_DCTS) + uart_handle_cts_change(&uart->port, + uart->stat_reg & ~MEN_Z135_MSR_CTS); +} + +static void men_z135_handle_lsr(struct men_z135_port *uart) +{ + struct uart_port *port = &uart->port; + u8 lsr; + + lsr = (uart->stat_reg >> 16) & 0xff; + + if (lsr & MEN_Z135_LSR_OE) + port->icount.overrun++; + if (lsr & MEN_Z135_LSR_PE) + port->icount.parity++; + if (lsr & MEN_Z135_LSR_FE) + port->icount.frame++; + if (lsr & MEN_Z135_LSR_BI) { + port->icount.brk++; + uart_handle_break(port); + } +} + +/** + * get_rx_fifo_content() - Get the number of bytes in RX FIFO + * @uart: The UART port + * + * Read RXC register from hardware and return current FIFO fill size. + */ +static u16 get_rx_fifo_content(struct men_z135_port *uart) +{ + struct uart_port *port = &uart->port; + u32 stat_reg; + u16 rxc; + u8 rxc_lo; + u8 rxc_hi; + + stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG); + rxc_lo = stat_reg >> 24; + rxc_hi = (stat_reg & 0xC0) >> 6; + + rxc = rxc_lo | (rxc_hi << 8); + + return rxc; +} + +/** + * men_z135_handle_rx() - RX tasklet routine + * @arg: Pointer to struct men_z135_port + * + * Copy from RX FIFO and acknowledge number of bytes copied. + */ +static void men_z135_handle_rx(struct men_z135_port *uart) +{ + struct uart_port *port = &uart->port; + struct tty_port *tport = &port->state->port; + int copied; + u16 size; + int room; + + size = get_rx_fifo_content(uart); + + if (size == 0) + return; + + /* Avoid accidently accessing TX FIFO instead of RX FIFO. Last + * longword in RX FIFO cannot be read.(0x004-0x3FF) + */ + if (size > MEN_Z135_FIFO_WATERMARK) + size = MEN_Z135_FIFO_WATERMARK; + + room = tty_buffer_request_room(tport, size); + if (room != size) + dev_warn(&uart->mdev->dev, + "Not enough room in flip buffer, truncating to %d\n", + room); + + if (room == 0) + return; + + memcpy_fromio(uart->rxbuf, port->membase + MEN_Z135_RX_RAM, room); + /* Be sure to first copy all data and then acknowledge it */ + mb(); + iowrite32(room, port->membase + MEN_Z135_RX_CTRL); + + copied = tty_insert_flip_string(tport, uart->rxbuf, room); + if (copied != room) + dev_warn(&uart->mdev->dev, + "Only copied %d instead of %d bytes\n", + copied, room); + + port->icount.rx += copied; + + tty_flip_buffer_push(tport); + +} + +/** + * men_z135_handle_tx() - TX tasklet routine + * @arg: Pointer to struct men_z135_port + * + */ +static void men_z135_handle_tx(struct men_z135_port *uart) +{ + struct uart_port *port = &uart->port; + struct circ_buf *xmit = &port->state->xmit; + u32 txc; + u32 wptr; + int qlen; + int n; + int txfree; + int head; + int tail; + int s; + + if (uart_circ_empty(xmit)) + goto out; + + if (uart_tx_stopped(port)) + goto out; + + if (port->x_char) + goto out; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + /* calculate bytes to copy */ + qlen = uart_circ_chars_pending(xmit); + if (qlen <= 0) + goto out; + + wptr = ioread32(port->membase + MEN_Z135_TX_CTRL); + txc = (wptr >> 16) & 0x3ff; + wptr &= 0x3ff; + + if (txc > MEN_Z135_FIFO_WATERMARK) + txc = MEN_Z135_FIFO_WATERMARK; + + txfree = MEN_Z135_FIFO_WATERMARK - txc; + if (txfree <= 0) { + pr_err("Not enough room in TX FIFO have %d, need %d\n", + txfree, qlen); + goto irq_en; + } + + /* if we're not aligned, it's better to copy only 1 or 2 bytes and + * then the rest. + */ + if (align && qlen >= 3 && BYTES_TO_ALIGN(wptr)) + n = 4 - BYTES_TO_ALIGN(wptr); + else if (qlen > txfree) + n = txfree; + else + n = qlen; + + if (n <= 0) + goto irq_en; + + head = xmit->head & (UART_XMIT_SIZE - 1); + tail = xmit->tail & (UART_XMIT_SIZE - 1); + + s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail; + n = min(n, s); + + memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n); + xmit->tail = (xmit->tail + n) & (UART_XMIT_SIZE - 1); + mmiowb(); + + iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL); + + port->icount.tx += n; + +irq_en: + if (!uart_circ_empty(xmit)) + men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); + else + men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); + +out: + return; + +} + +/** + * men_z135_intr() - Handle legacy IRQs + * @irq: The IRQ number + * @data: Pointer to UART port + * + * Check IIR register to see which tasklet to start. + */ +static irqreturn_t men_z135_intr(int irq, void *data) +{ + struct men_z135_port *uart = (struct men_z135_port *)data; + struct uart_port *port = &uart->port; + int irq_id; + + uart->stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG); + /* IRQ pending is low active */ + if (IS_IRQ(uart->stat_reg)) + return IRQ_NONE; + + irq_id = IRQ_ID(uart->stat_reg); + switch (irq_id) { + case MEN_Z135_IRQ_ID_MST: + men_z135_handle_modem_status(uart); + break; + case MEN_Z135_IRQ_ID_TSA: + men_z135_handle_tx(uart); + break; + case MEN_Z135_IRQ_ID_CTI: + dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n"); + /* Fallthrough */ + case MEN_Z135_IRQ_ID_RDA: + /* Reading data clears RX IRQ */ + men_z135_handle_rx(uart); + break; + case MEN_Z135_IRQ_ID_RLS: + men_z135_handle_lsr(uart); + break; + default: + dev_warn(&uart->mdev->dev, "Unknown IRQ id %d\n", irq_id); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +/** + * men_z135_request_irq() - Request IRQ for 16z135 core + * @uart: z135 private uart port structure + * + * Request an IRQ for 16z135 to use. First try using MSI, if it fails + * fall back to using legacy interrupts. + */ +static int men_z135_request_irq(struct men_z135_port *uart) +{ + struct device *dev = &uart->mdev->dev; + struct uart_port *port = &uart->port; + int err = 0; + + err = request_irq(port->irq, men_z135_intr, IRQF_SHARED, + "men_z135_intr", uart); + if (err) + dev_err(dev, "Error %d getting interrupt\n", err); + + return err; +} + +/** + * men_z135_tx_empty() - Handle tx_empty call + * @port: The UART port + * + * This function tests whether the TX FIFO and shifter for the port + * described by @port is empty. + */ +static unsigned int men_z135_tx_empty(struct uart_port *port) +{ + u32 wptr; + u16 txc; + + wptr = ioread32(port->membase + MEN_Z135_TX_CTRL); + txc = (wptr >> 16) & 0x3ff; + + if (txc == 0) + return TIOCSER_TEMT; + else + return 0; +} + +/** + * men_z135_set_mctrl() - Set modem control lines + * @port: The UART port + * @mctrl: The modem control lines + * + * This function sets the modem control lines for a port described by @port + * to the state described by @mctrl + */ +static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct men_z135_port *uart = to_men_z135(port); + u32 conf_reg = 0; + + if (mctrl & TIOCM_RTS) + conf_reg |= MEN_Z135_MCR_RTS; + if (mctrl & TIOCM_DTR) + conf_reg |= MEN_Z135_MCR_DTR; + if (mctrl & TIOCM_OUT1) + conf_reg |= MEN_Z135_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + conf_reg |= MEN_Z135_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + conf_reg |= MEN_Z135_MCR_LOOP; + + men_z135_reg_set(uart, MEN_Z135_CONF_REG, conf_reg); +} + +/** + * men_z135_get_mctrl() - Get modem control lines + * @port: The UART port + * + * Retruns the current state of modem control inputs. + */ +static unsigned int men_z135_get_mctrl(struct uart_port *port) +{ + unsigned int mctrl = 0; + u32 stat_reg; + u8 msr; + + stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG); + + msr = ~((stat_reg >> 8) & 0xff); + + if (msr & MEN_Z135_MSR_CTS) + mctrl |= TIOCM_CTS; + if (msr & MEN_Z135_MSR_DSR) + mctrl |= TIOCM_DSR; + if (msr & MEN_Z135_MSR_RI) + mctrl |= TIOCM_RI; + if (msr & MEN_Z135_MSR_DCD) + mctrl |= TIOCM_CAR; + + return mctrl; +} + +/** + * men_z135_stop_tx() - Stop transmitting characters + * @port: The UART port + * + * Stop transmitting characters. This might be due to CTS line becomming + * inactive or the tty layer indicating we want to stop transmission due to + * an XOFF character. + */ +static void men_z135_stop_tx(struct uart_port *port) +{ + struct men_z135_port *uart = to_men_z135(port); + + men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); +} + +/** + * men_z135_start_tx() - Start transmitting characters + * @port: The UART port + * + * Start transmitting character. This actually doesn't transmit anything, but + * fires off the TX tasklet. + */ +static void men_z135_start_tx(struct uart_port *port) +{ + struct men_z135_port *uart = to_men_z135(port); + + men_z135_handle_tx(uart); +} + +/** + * men_z135_stop_rx() - Stop receiving characters + * @port: The UART port + * + * Stop receiving characters; the port is in the process of being closed. + */ +static void men_z135_stop_rx(struct uart_port *port) +{ + struct men_z135_port *uart = to_men_z135(port); + + men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_RXCIEN); +} + +/** + * men_z135_enable_ms() - Enable Modem Status + * port: + * + * Enable Modem Status IRQ. + */ +static void men_z135_enable_ms(struct uart_port *port) +{ + struct men_z135_port *uart = to_men_z135(port); + + men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_MSIEN); +} + +static int men_z135_startup(struct uart_port *port) +{ + struct men_z135_port *uart = to_men_z135(port); + int err; + u32 conf_reg = 0; + + err = men_z135_request_irq(uart); + if (err) + return -ENODEV; + + conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG); + + conf_reg |= MEN_Z135_ALL_IRQS; + conf_reg &= ~(0xff << 16); + conf_reg |= (txlvl << 16); + conf_reg |= (rxlvl << 20); + + iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG); + + return 0; +} + +static void men_z135_shutdown(struct uart_port *port) +{ + struct men_z135_port *uart = to_men_z135(port); + u32 conf_reg = 0; + + conf_reg |= MEN_Z135_ALL_IRQS; + + men_z135_reg_clr(uart, MEN_Z135_CONF_REG, conf_reg); + + free_irq(uart->port.irq, uart); +} + +static void men_z135_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud; + u32 conf_reg; + u32 bd_reg; + u32 uart_freq; + u8 lcr; + + conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG); + lcr = LCR(conf_reg); + + /* byte size */ + switch (termios->c_cflag & CSIZE) { + case CS5: + lcr |= MEN_Z135_WL5; + break; + case CS6: + lcr |= MEN_Z135_WL6; + break; + case CS7: + lcr |= MEN_Z135_WL7; + break; + case CS8: + lcr |= MEN_Z135_WL8; + break; + } + + /* stop bits */ + if (termios->c_cflag & CSTOPB) + lcr |= MEN_Z135_NSTB2 << MEN_Z135_STB_SHIFT; + + /* parity */ + if (termios->c_cflag & PARENB) { + lcr |= MEN_Z135_PAR_ENA << MEN_Z135_PEN_SHIFT; + + if (termios->c_cflag & PARODD) + lcr |= MEN_Z135_PTY_ODD << MEN_Z135_PTY_SHIFT; + else + lcr |= MEN_Z135_PTY_EVN << MEN_Z135_PTY_SHIFT; + } else + lcr |= MEN_Z135_PAR_DIS << MEN_Z135_PEN_SHIFT; + + termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ + + conf_reg |= lcr << MEN_Z135_LCR_SHIFT; + iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG); + + uart_freq = ioread32(port->membase + MEN_Z135_UART_FREQ); + if (uart_freq == 0) + uart_freq = MEN_Z135_BASECLK; + + baud = uart_get_baud_rate(port, termios, old, 0, uart_freq / 16); + + spin_lock(&port->lock); + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); + + bd_reg = uart_freq / (4 * baud); + iowrite32(bd_reg, port->membase + MEN_Z135_BAUD_REG); + + uart_update_timeout(port, termios->c_cflag, baud); + spin_unlock(&port->lock); +} + +static const char *men_z135_type(struct uart_port *port) +{ + return KBUILD_MODNAME; +} + +static void men_z135_release_port(struct uart_port *port) +{ + iounmap(port->membase); + port->membase = NULL; + + release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE); +} + +static int men_z135_request_port(struct uart_port *port) +{ + int size = MEN_Z135_MEM_SIZE; + + if (!request_mem_region(port->mapbase, size, "men_z135_port")) + return -EBUSY; + + port->membase = ioremap(port->mapbase, MEN_Z135_MEM_SIZE); + if (port->membase == NULL) { + release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE); + return -ENOMEM; + } + + return 0; +} + +static void men_z135_config_port(struct uart_port *port, int type) +{ + port->type = PORT_MEN_Z135; + men_z135_request_port(port); +} + +static int men_z135_verify_port(struct uart_port *port, + struct serial_struct *serinfo) +{ + return -EINVAL; +} + +static struct uart_ops men_z135_ops = { + .tx_empty = men_z135_tx_empty, + .set_mctrl = men_z135_set_mctrl, + .get_mctrl = men_z135_get_mctrl, + .stop_tx = men_z135_stop_tx, + .start_tx = men_z135_start_tx, + .stop_rx = men_z135_stop_rx, + .enable_ms = men_z135_enable_ms, + .startup = men_z135_startup, + .shutdown = men_z135_shutdown, + .set_termios = men_z135_set_termios, + .type = men_z135_type, + .release_port = men_z135_release_port, + .request_port = men_z135_request_port, + .config_port = men_z135_config_port, + .verify_port = men_z135_verify_port, +}; + +static struct uart_driver men_z135_driver = { + .owner = THIS_MODULE, + .driver_name = KBUILD_MODNAME, + .dev_name = "ttyHSU", + .major = 0, + .minor = 0, + .nr = MEN_Z135_MAX_PORTS, +}; + +/** + * men_z135_probe() - Probe a z135 instance + * @mdev: The MCB device + * @id: The MCB device ID + * + * men_z135_probe does the basic setup of hardware resources and registers the + * new uart port to the tty layer. + */ +static int men_z135_probe(struct mcb_device *mdev, + const struct mcb_device_id *id) +{ + struct men_z135_port *uart; + struct resource *mem; + struct device *dev; + int err; + + dev = &mdev->dev; + + uart = devm_kzalloc(dev, sizeof(struct men_z135_port), GFP_KERNEL); + if (!uart) + return -ENOMEM; + + uart->rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!uart->rxbuf) + return -ENOMEM; + + mem = &mdev->mem; + + mcb_set_drvdata(mdev, uart); + + uart->port.uartclk = MEN_Z135_BASECLK * 16; + uart->port.fifosize = MEN_Z135_FIFO_SIZE; + uart->port.iotype = UPIO_MEM; + uart->port.ops = &men_z135_ops; + uart->port.irq = mcb_get_irq(mdev); + uart->port.iotype = UPIO_MEM; + uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; + uart->port.line = line++; + uart->port.dev = dev; + uart->port.type = PORT_MEN_Z135; + uart->port.mapbase = mem->start; + uart->port.membase = NULL; + uart->mdev = mdev; + + spin_lock_init(&uart->port.lock); + spin_lock_init(&uart->lock); + + err = uart_add_one_port(&men_z135_driver, &uart->port); + if (err) + goto err; + + return 0; + +err: + free_page((unsigned long) uart->rxbuf); + dev_err(dev, "Failed to add UART: %d\n", err); + + return err; +} + +/** + * men_z135_remove() - Remove a z135 instance from the system + * + * @mdev: The MCB device + */ +static void men_z135_remove(struct mcb_device *mdev) +{ + struct men_z135_port *uart = mcb_get_drvdata(mdev); + + line--; + uart_remove_one_port(&men_z135_driver, &uart->port); + free_page((unsigned long) uart->rxbuf); +} + +static const struct mcb_device_id men_z135_ids[] = { + { .device = 0x87 }, +}; +MODULE_DEVICE_TABLE(mcb, men_z135_ids); + +static struct mcb_driver mcb_driver = { + .driver = { + .name = "z135-uart", + .owner = THIS_MODULE, + }, + .probe = men_z135_probe, + .remove = men_z135_remove, + .id_table = men_z135_ids, +}; + +/** + * men_z135_init() - Driver Registration Routine + * + * men_z135_init is the first routine called when the driver is loaded. All it + * does is register with the legacy MEN Chameleon subsystem. + */ +static int __init men_z135_init(void) +{ + int err; + + err = uart_register_driver(&men_z135_driver); + if (err) { + pr_err("Failed to register UART: %d\n", err); + return err; + } + + err = mcb_register_driver(&mcb_driver); + if (err) { + pr_err("Failed to register MCB driver: %d\n", err); + uart_unregister_driver(&men_z135_driver); + return err; + } + + return 0; +} +module_init(men_z135_init); + +/** + * men_z135_exit() - Driver Exit Routine + * + * men_z135_exit is called just before the driver is removed from memory. + */ +static void __exit men_z135_exit(void) +{ + mcb_unregister_driver(&mcb_driver); + uart_unregister_driver(&men_z135_driver); +} +module_exit(men_z135_exit); + +MODULE_AUTHOR("Johannes Thumshirn "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MEN 16z135 High Speed UART"); +MODULE_ALIAS("mcb:16z135"); diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 7fd6aaaacd8e53..be127d0da32ce3 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -29,7 +29,7 @@ #include #include -#ifdef CONFIG_MAGIC_SYSRQ +#if defined(CONFIG_SERIAL_MUX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #include #define SUPPORT_SYSRQ #endif @@ -613,7 +613,7 @@ static void __exit mux_exit(void) { /* Delete the Mux timer. */ if(port_cnt > 0) { - del_timer(&mux_timer); + del_timer_sync(&mux_timer); #ifdef CONFIG_SERIAL_MUX_CONSOLE unregister_console(&mux_console); #endif diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index aa97fd845b4d81..4b5b3c2fe32871 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -200,7 +200,7 @@ static void dma_tx_callback(void *param) /* clear the bit used to serialize the DMA tx. */ clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); /* wake up the possible processes. */ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -275,7 +275,7 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s) mxs_auart_dma_tx(s, i); } else { clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } return; } diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 08b6b9419f0d04..d017cec8a34a0d 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -163,10 +163,6 @@ struct uart_omap_port { u8 wakeups_enabled; u32 features; - int DTR_gpio; - int DTR_inverted; - int DTR_active; - struct serial_rs485 rs485; int rts_gpio; @@ -184,8 +180,6 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; /* Forward declaration of functions */ static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1); -static struct workqueue_struct *serial_omap_uart_wq; - static inline unsigned int serial_in(struct uart_omap_port *up, int offset) { offset <<= up->port.regshift; @@ -398,11 +392,8 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) break; } while (--count > 0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { - spin_unlock(&up->port.lock); + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&up->port); - spin_lock(&up->port.lock); - } if (uart_circ_empty(xmit)) serial_omap_stop_tx(&up->port); @@ -697,16 +688,6 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) serial_out(up, UART_MCR, up->mcr); pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); - - if (gpio_is_valid(up->DTR_gpio) && - !!(mctrl & TIOCM_DTR) != up->DTR_active) { - up->DTR_active = !up->DTR_active; - if (gpio_cansleep(up->DTR_gpio)) - schedule_work(&up->qos_work); - else - gpio_set_value(up->DTR_gpio, - up->DTR_active != up->DTR_inverted); - } } static void serial_omap_break_ctl(struct uart_port *port, int break_state) @@ -850,9 +831,6 @@ static void serial_omap_uart_qos_work(struct work_struct *work) qos_work); pm_qos_update_request(&up->pm_qos_request, up->latency); - if (gpio_is_valid(up->DTR_gpio)) - gpio_set_value_cansleep(up->DTR_gpio, - up->DTR_active != up->DTR_inverted); } static void @@ -1420,7 +1398,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg) switch (cmd) { case TIOCSRS485: - if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg, + if (copy_from_user(&rs485conf, (void __user *) arg, sizeof(rs485conf))) return -EFAULT; @@ -1428,7 +1406,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg) break; case TIOCGRS485: - if (copy_to_user((struct serial_rs485 *) arg, + if (copy_to_user((void __user *) arg, &(to_uart_omap_port(port)->rs485), sizeof(rs485conf))) return -EFAULT; @@ -1614,7 +1592,7 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, /* check for tx enable gpio */ up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags); if (gpio_is_valid(up->rts_gpio)) { - ret = gpio_request(up->rts_gpio, "omap-serial"); + ret = devm_gpio_request(up->dev, up->rts_gpio, "omap-serial"); if (ret < 0) return ret; ret = gpio_direction_output(up->rts_gpio, @@ -1644,10 +1622,13 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, static int serial_omap_probe(struct platform_device *pdev) { - struct uart_omap_port *up; - struct resource *mem, *irq; struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev); - int ret, uartirq = 0, wakeirq = 0; + struct uart_omap_port *up; + struct resource *mem; + void __iomem *base; + int uartirq = 0; + int wakeirq = 0; + int ret; /* The optional wakeirq may be specified in the board dts file */ if (pdev->dev.of_node) { @@ -1658,48 +1639,19 @@ static int serial_omap_probe(struct platform_device *pdev) omap_up_info = of_get_uart_port_info(&pdev->dev); pdev->dev.platform_data = omap_up_info; } else { - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { - dev_err(&pdev->dev, "no irq resource?\n"); - return -ENODEV; - } - uartirq = irq->start; - } - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "no mem resource?\n"); - return -ENODEV; - } - - if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), - pdev->dev.driver->name)) { - dev_err(&pdev->dev, "memory region already claimed\n"); - return -EBUSY; - } - - if (gpio_is_valid(omap_up_info->DTR_gpio) && - omap_up_info->DTR_present) { - ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial"); - if (ret < 0) - return ret; - ret = gpio_direction_output(omap_up_info->DTR_gpio, - omap_up_info->DTR_inverted); - if (ret < 0) - return ret; + uartirq = platform_get_irq(pdev, 0); + if (uartirq < 0) + return -EPROBE_DEFER; } up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL); if (!up) return -ENOMEM; - if (gpio_is_valid(omap_up_info->DTR_gpio) && - omap_up_info->DTR_present) { - up->DTR_gpio = omap_up_info->DTR_gpio; - up->DTR_inverted = omap_up_info->DTR_inverted; - } else - up->DTR_gpio = -EINVAL; - up->DTR_active = 0; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(base)) + return PTR_ERR(base); up->dev = &pdev->dev; up->port.dev = &pdev->dev; @@ -1733,14 +1685,7 @@ static int serial_omap_probe(struct platform_device *pdev) sprintf(up->name, "OMAP UART%d", up->port.line); up->port.mapbase = mem->start; - up->port.membase = devm_ioremap(&pdev->dev, mem->start, - resource_size(mem)); - if (!up->port.membase) { - dev_err(&pdev->dev, "can't ioremap UART\n"); - ret = -ENOMEM; - goto err_ioremap; - } - + up->port.membase = base; up->port.flags = omap_up_info->flags; up->port.uartclk = omap_up_info->uartclk; if (!up->port.uartclk) { @@ -1754,12 +1699,12 @@ static int serial_omap_probe(struct platform_device *pdev) up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; pm_qos_add_request(&up->pm_qos_request, PM_QOS_CPU_DMA_LATENCY, up->latency); - serial_omap_uart_wq = create_singlethread_workqueue(up->name); INIT_WORK(&up->qos_work, serial_omap_uart_qos_work); platform_set_drvdata(pdev, up); if (omap_up_info->autosuspend_timeout == 0) omap_up_info->autosuspend_timeout = -1; + device_init_wakeup(up->dev, true); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, @@ -1786,7 +1731,6 @@ static int serial_omap_probe(struct platform_device *pdev) err_add_port: pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); -err_ioremap: err_rs485: err_port_line: dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 0931b3fe9edf23..0cb6a8e52bd086 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -257,6 +257,8 @@ struct eg20t_port { dma_addr_t rx_buf_dma; struct dentry *debugfs; +#define IRQ_NAME_SIZE 17 + char irq_name[IRQ_NAME_SIZE]; /* protect the eg20t_port private structure and io access to membase */ spinlock_t lock; @@ -1343,7 +1345,7 @@ static int pch_uart_startup(struct uart_port *port) return ret; ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED, - KBUILD_MODNAME, priv); + priv->irq_name, priv); if (ret < 0) return ret; @@ -1588,13 +1590,8 @@ static void pch_uart_put_poll_char(struct uart_port *port, wait_for_xmitr(priv, UART_LSR_THRE); /* * Send the character out. - * If a LF, also do CR... */ iowrite8(c, priv->membase + PCH_UART_THR); - if (c == 10) { - wait_for_xmitr(priv, UART_LSR_THRE); - iowrite8(13, priv->membase + PCH_UART_THR); - } /* * Finally, wait for transmitter to become empty @@ -1818,6 +1815,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, priv->port.line = board->line_no; priv->trigger = PCH_UART_HAL_TRIGGER_M; + snprintf(priv->irq_name, IRQ_NAME_SIZE, + KBUILD_MODNAME ":" PCH_UART_DRIVER_DEVICE "%d", + priv->port.line); + spin_lock_init(&priv->port.lock); pci_set_drvdata(pdev, priv); diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index f9f20f38376003..9e7ee39f8b2a6c 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -711,13 +711,8 @@ static void serial_pxa_put_poll_char(struct uart_port *port, wait_for_xmitr(up); /* * Send the character out. - * If a LF, also do CR... */ serial_out(up, UART_TX, c); - if (c == 10) { - wait_for_xmitr(up); - serial_out(up, UART_TX, 13); - } /* * Finally, wait for transmitter to become empty diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c new file mode 100644 index 00000000000000..7206a64f3ff7f5 --- /dev/null +++ b/drivers/tty/serial/sc16is7xx.c @@ -0,0 +1,1280 @@ +/* + * SC16IS7xx tty serial driver - Copyright (C) 2014 GridPoint + * Author: Jon Ringle + * + * Based on max310x.c, by Alexander Shiyan + * + * 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 +#include +#include +#include +#include +#include +#include + +#define SC16IS7XX_NAME "sc16is7xx" + +/* SC16IS7XX register definitions */ +#define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */ +#define SC16IS7XX_THR_REG (0x00) /* TX FIFO */ +#define SC16IS7XX_IER_REG (0x01) /* Interrupt enable */ +#define SC16IS7XX_IIR_REG (0x02) /* Interrupt Identification */ +#define SC16IS7XX_FCR_REG (0x02) /* FIFO control */ +#define SC16IS7XX_LCR_REG (0x03) /* Line Control */ +#define SC16IS7XX_MCR_REG (0x04) /* Modem Control */ +#define SC16IS7XX_LSR_REG (0x05) /* Line Status */ +#define SC16IS7XX_MSR_REG (0x06) /* Modem Status */ +#define SC16IS7XX_SPR_REG (0x07) /* Scratch Pad */ +#define SC16IS7XX_TXLVL_REG (0x08) /* TX FIFO level */ +#define SC16IS7XX_RXLVL_REG (0x09) /* RX FIFO level */ +#define SC16IS7XX_IODIR_REG (0x0a) /* I/O Direction + * - only on 75x/76x + */ +#define SC16IS7XX_IOSTATE_REG (0x0b) /* I/O State + * - only on 75x/76x + */ +#define SC16IS7XX_IOINTENA_REG (0x0c) /* I/O Interrupt Enable + * - only on 75x/76x + */ +#define SC16IS7XX_IOCONTROL_REG (0x0e) /* I/O Control + * - only on 75x/76x + */ +#define SC16IS7XX_EFCR_REG (0x0f) /* Extra Features Control */ + +/* TCR/TLR Register set: Only if ((MCR[2] == 1) && (EFR[4] == 1)) */ +#define SC16IS7XX_TCR_REG (0x06) /* Transmit control */ +#define SC16IS7XX_TLR_REG (0x07) /* Trigger level */ + +/* Special Register set: Only if ((LCR[7] == 1) && (LCR != 0xBF)) */ +#define SC16IS7XX_DLL_REG (0x00) /* Divisor Latch Low */ +#define SC16IS7XX_DLH_REG (0x01) /* Divisor Latch High */ + +/* Enhanced Register set: Only if (LCR == 0xBF) */ +#define SC16IS7XX_EFR_REG (0x02) /* Enhanced Features */ +#define SC16IS7XX_XON1_REG (0x04) /* Xon1 word */ +#define SC16IS7XX_XON2_REG (0x05) /* Xon2 word */ +#define SC16IS7XX_XOFF1_REG (0x06) /* Xoff1 word */ +#define SC16IS7XX_XOFF2_REG (0x07) /* Xoff2 word */ + +/* IER register bits */ +#define SC16IS7XX_IER_RDI_BIT (1 << 0) /* Enable RX data interrupt */ +#define SC16IS7XX_IER_THRI_BIT (1 << 1) /* Enable TX holding register + * interrupt */ +#define SC16IS7XX_IER_RLSI_BIT (1 << 2) /* Enable RX line status + * interrupt */ +#define SC16IS7XX_IER_MSI_BIT (1 << 3) /* Enable Modem status + * interrupt */ + +/* IER register bits - write only if (EFR[4] == 1) */ +#define SC16IS7XX_IER_SLEEP_BIT (1 << 4) /* Enable Sleep mode */ +#define SC16IS7XX_IER_XOFFI_BIT (1 << 5) /* Enable Xoff interrupt */ +#define SC16IS7XX_IER_RTSI_BIT (1 << 6) /* Enable nRTS interrupt */ +#define SC16IS7XX_IER_CTSI_BIT (1 << 7) /* Enable nCTS interrupt */ + +/* FCR register bits */ +#define SC16IS7XX_FCR_FIFO_BIT (1 << 0) /* Enable FIFO */ +#define SC16IS7XX_FCR_RXRESET_BIT (1 << 1) /* Reset RX FIFO */ +#define SC16IS7XX_FCR_TXRESET_BIT (1 << 2) /* Reset TX FIFO */ +#define SC16IS7XX_FCR_RXLVLL_BIT (1 << 6) /* RX Trigger level LSB */ +#define SC16IS7XX_FCR_RXLVLH_BIT (1 << 7) /* RX Trigger level MSB */ + +/* FCR register bits - write only if (EFR[4] == 1) */ +#define SC16IS7XX_FCR_TXLVLL_BIT (1 << 4) /* TX Trigger level LSB */ +#define SC16IS7XX_FCR_TXLVLH_BIT (1 << 5) /* TX Trigger level MSB */ + +/* IIR register bits */ +#define SC16IS7XX_IIR_NO_INT_BIT (1 << 0) /* No interrupts pending */ +#define SC16IS7XX_IIR_ID_MASK 0x3e /* Mask for the interrupt ID */ +#define SC16IS7XX_IIR_THRI_SRC 0x02 /* TX holding register empty */ +#define SC16IS7XX_IIR_RDI_SRC 0x04 /* RX data interrupt */ +#define SC16IS7XX_IIR_RLSE_SRC 0x06 /* RX line status error */ +#define SC16IS7XX_IIR_RTOI_SRC 0x0c /* RX time-out interrupt */ +#define SC16IS7XX_IIR_MSI_SRC 0x00 /* Modem status interrupt + * - only on 75x/76x + */ +#define SC16IS7XX_IIR_INPIN_SRC 0x30 /* Input pin change of state + * - only on 75x/76x + */ +#define SC16IS7XX_IIR_XOFFI_SRC 0x10 /* Received Xoff */ +#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state + * from active (LOW) + * to inactive (HIGH) + */ +/* LCR register bits */ +#define SC16IS7XX_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */ +#define SC16IS7XX_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1 + * + * Word length bits table: + * 00 -> 5 bit words + * 01 -> 6 bit words + * 10 -> 7 bit words + * 11 -> 8 bit words + */ +#define SC16IS7XX_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit + * + * STOP length bit table: + * 0 -> 1 stop bit + * 1 -> 1-1.5 stop bits if + * word length is 5, + * 2 stop bits otherwise + */ +#define SC16IS7XX_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */ +#define SC16IS7XX_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */ +#define SC16IS7XX_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */ +#define SC16IS7XX_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */ +#define SC16IS7XX_LCR_DLAB_BIT (1 << 7) /* Divisor Latch enable */ +#define SC16IS7XX_LCR_WORD_LEN_5 (0x00) +#define SC16IS7XX_LCR_WORD_LEN_6 (0x01) +#define SC16IS7XX_LCR_WORD_LEN_7 (0x02) +#define SC16IS7XX_LCR_WORD_LEN_8 (0x03) +#define SC16IS7XX_LCR_CONF_MODE_A SC16IS7XX_LCR_DLAB_BIT /* Special + * reg set */ +#define SC16IS7XX_LCR_CONF_MODE_B 0xBF /* Enhanced + * reg set */ + +/* MCR register bits */ +#define SC16IS7XX_MCR_DTR_BIT (1 << 0) /* DTR complement + * - only on 75x/76x + */ +#define SC16IS7XX_MCR_RTS_BIT (1 << 1) /* RTS complement */ +#define SC16IS7XX_MCR_TCRTLR_BIT (1 << 2) /* TCR/TLR register enable */ +#define SC16IS7XX_MCR_LOOP_BIT (1 << 4) /* Enable loopback test mode */ +#define SC16IS7XX_MCR_XONANY_BIT (1 << 5) /* Enable Xon Any + * - write enabled + * if (EFR[4] == 1) + */ +#define SC16IS7XX_MCR_IRDA_BIT (1 << 6) /* Enable IrDA mode + * - write enabled + * if (EFR[4] == 1) + */ +#define SC16IS7XX_MCR_CLKSEL_BIT (1 << 7) /* Divide clock by 4 + * - write enabled + * if (EFR[4] == 1) + */ + +/* LSR register bits */ +#define SC16IS7XX_LSR_DR_BIT (1 << 0) /* Receiver data ready */ +#define SC16IS7XX_LSR_OE_BIT (1 << 1) /* Overrun Error */ +#define SC16IS7XX_LSR_PE_BIT (1 << 2) /* Parity Error */ +#define SC16IS7XX_LSR_FE_BIT (1 << 3) /* Frame Error */ +#define SC16IS7XX_LSR_BI_BIT (1 << 4) /* Break Interrupt */ +#define SC16IS7XX_LSR_BRK_ERROR_MASK 0x1E /* BI, FE, PE, OE bits */ +#define SC16IS7XX_LSR_THRE_BIT (1 << 5) /* TX holding register empty */ +#define SC16IS7XX_LSR_TEMT_BIT (1 << 6) /* Transmitter empty */ +#define SC16IS7XX_LSR_FIFOE_BIT (1 << 7) /* Fifo Error */ + +/* MSR register bits */ +#define SC16IS7XX_MSR_DCTS_BIT (1 << 0) /* Delta CTS Clear To Send */ +#define SC16IS7XX_MSR_DDSR_BIT (1 << 1) /* Delta DSR Data Set Ready + * or (IO4) + * - only on 75x/76x + */ +#define SC16IS7XX_MSR_DRI_BIT (1 << 2) /* Delta RI Ring Indicator + * or (IO7) + * - only on 75x/76x + */ +#define SC16IS7XX_MSR_DCD_BIT (1 << 3) /* Delta CD Carrier Detect + * or (IO6) + * - only on 75x/76x + */ +#define SC16IS7XX_MSR_CTS_BIT (1 << 0) /* CTS */ +#define SC16IS7XX_MSR_DSR_BIT (1 << 1) /* DSR (IO4) + * - only on 75x/76x + */ +#define SC16IS7XX_MSR_RI_BIT (1 << 2) /* RI (IO7) + * - only on 75x/76x + */ +#define SC16IS7XX_MSR_CD_BIT (1 << 3) /* CD (IO6) + * - only on 75x/76x + */ +#define SC16IS7XX_MSR_DELTA_MASK 0x0F /* Any of the delta bits! */ + +/* + * TCR register bits + * TCR trigger levels are available from 0 to 60 characters with a granularity + * of four. + * The programmer must program the TCR such that TCR[3:0] > TCR[7:4]. There is + * no built-in hardware check to make sure this condition is met. Also, the TCR + * must be programmed with this condition before auto RTS or software flow + * control is enabled to avoid spurious operation of the device. + */ +#define SC16IS7XX_TCR_RX_HALT(words) ((((words) / 4) & 0x0f) << 0) +#define SC16IS7XX_TCR_RX_RESUME(words) ((((words) / 4) & 0x0f) << 4) + +/* + * TLR register bits + * If TLR[3:0] or TLR[7:4] are logical 0, the selectable trigger levels via the + * FIFO Control Register (FCR) are used for the transmit and receive FIFO + * trigger levels. Trigger levels from 4 characters to 60 characters are + * available with a granularity of four. + * + * When the trigger level setting in TLR is zero, the SC16IS740/750/760 uses the + * trigger level setting defined in FCR. If TLR has non-zero trigger level value + * the trigger level defined in FCR is discarded. This applies to both transmit + * FIFO and receive FIFO trigger level setting. + * + * When TLR is used for RX trigger level control, FCR[7:6] should be left at the + * default state, that is, '00'. + */ +#define SC16IS7XX_TLR_TX_TRIGGER(words) ((((words) / 4) & 0x0f) << 0) +#define SC16IS7XX_TLR_RX_TRIGGER(words) ((((words) / 4) & 0x0f) << 4) + +/* IOControl register bits (Only 750/760) */ +#define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */ +#define SC16IS7XX_IOCONTROL_GPIO_BIT (1 << 1) /* Enable GPIO[7:4] */ +#define SC16IS7XX_IOCONTROL_SRESET_BIT (1 << 3) /* Software Reset */ + +/* EFCR register bits */ +#define SC16IS7XX_EFCR_9BIT_MODE_BIT (1 << 0) /* Enable 9-bit or Multidrop + * mode (RS485) */ +#define SC16IS7XX_EFCR_RXDISABLE_BIT (1 << 1) /* Disable receiver */ +#define SC16IS7XX_EFCR_TXDISABLE_BIT (1 << 2) /* Disable transmitter */ +#define SC16IS7XX_EFCR_AUTO_RS485_BIT (1 << 4) /* Auto RS485 RTS direction */ +#define SC16IS7XX_EFCR_RTS_INVERT_BIT (1 << 5) /* RTS output inversion */ +#define SC16IS7XX_EFCR_IRDA_MODE_BIT (1 << 7) /* IrDA mode + * 0 = rate upto 115.2 kbit/s + * - Only 750/760 + * 1 = rate upto 1.152 Mbit/s + * - Only 760 + */ + +/* EFR register bits */ +#define SC16IS7XX_EFR_AUTORTS_BIT (1 << 6) /* Auto RTS flow ctrl enable */ +#define SC16IS7XX_EFR_AUTOCTS_BIT (1 << 7) /* Auto CTS flow ctrl enable */ +#define SC16IS7XX_EFR_XOFF2_DETECT_BIT (1 << 5) /* Enable Xoff2 detection */ +#define SC16IS7XX_EFR_ENABLE_BIT (1 << 4) /* Enable enhanced functions + * and writing to IER[7:4], + * FCR[5:4], MCR[7:5] + */ +#define SC16IS7XX_EFR_SWFLOW3_BIT (1 << 3) /* SWFLOW bit 3 */ +#define SC16IS7XX_EFR_SWFLOW2_BIT (1 << 2) /* SWFLOW bit 2 + * + * SWFLOW bits 3 & 2 table: + * 00 -> no transmitter flow + * control + * 01 -> transmitter generates + * XON2 and XOFF2 + * 10 -> transmitter generates + * XON1 and XOFF1 + * 11 -> transmitter generates + * XON1, XON2, XOFF1 and + * XOFF2 + */ +#define SC16IS7XX_EFR_SWFLOW1_BIT (1 << 1) /* SWFLOW bit 2 */ +#define SC16IS7XX_EFR_SWFLOW0_BIT (1 << 0) /* SWFLOW bit 3 + * + * SWFLOW bits 3 & 2 table: + * 00 -> no received flow + * control + * 01 -> receiver compares + * XON2 and XOFF2 + * 10 -> receiver compares + * XON1 and XOFF1 + * 11 -> receiver compares + * XON1, XON2, XOFF1 and + * XOFF2 + */ + +/* Misc definitions */ +#define SC16IS7XX_FIFO_SIZE (64) +#define SC16IS7XX_REG_SHIFT 2 + +struct sc16is7xx_devtype { + char name[10]; + int nr_gpio; + int nr_uart; +}; + +struct sc16is7xx_one { + struct uart_port port; + struct work_struct tx_work; + struct work_struct md_work; + + struct serial_rs485 rs485; +}; + +struct sc16is7xx_port { + struct uart_driver uart; + struct sc16is7xx_devtype *devtype; + struct regmap *regmap; + struct mutex mutex; + struct clk *clk; +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio; +#endif + struct sc16is7xx_one p[0]; +}; + +#define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e))) + +static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + unsigned int val = 0; + + regmap_read(s->regmap, + (reg << SC16IS7XX_REG_SHIFT) | port->line, &val); + + return val; +} + +static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + + regmap_write(s->regmap, + (reg << SC16IS7XX_REG_SHIFT) | port->line, val); +} + +static void sc16is7xx_port_update(struct uart_port *port, u8 reg, + u8 mask, u8 val) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + + regmap_update_bits(s->regmap, + (reg << SC16IS7XX_REG_SHIFT) | port->line, + mask, val); +} + + +static void sc16is7xx_power(struct uart_port *port, int on) +{ + sc16is7xx_port_update(port, SC16IS7XX_IER_REG, + SC16IS7XX_IER_SLEEP_BIT, + on ? 0 : SC16IS7XX_IER_SLEEP_BIT); +} + +static const struct sc16is7xx_devtype sc16is74x_devtype = { + .name = "SC16IS74X", + .nr_gpio = 0, + .nr_uart = 1, +}; + +static const struct sc16is7xx_devtype sc16is750_devtype = { + .name = "SC16IS750", + .nr_gpio = 8, + .nr_uart = 1, +}; + +static const struct sc16is7xx_devtype sc16is752_devtype = { + .name = "SC16IS752", + .nr_gpio = 8, + .nr_uart = 2, +}; + +static const struct sc16is7xx_devtype sc16is760_devtype = { + .name = "SC16IS760", + .nr_gpio = 8, + .nr_uart = 1, +}; + +static const struct sc16is7xx_devtype sc16is762_devtype = { + .name = "SC16IS762", + .nr_gpio = 8, + .nr_uart = 2, +}; + +static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg) +{ + switch (reg >> SC16IS7XX_REG_SHIFT) { + case SC16IS7XX_RHR_REG: + case SC16IS7XX_IIR_REG: + case SC16IS7XX_LSR_REG: + case SC16IS7XX_MSR_REG: + case SC16IS7XX_TXLVL_REG: + case SC16IS7XX_RXLVL_REG: + case SC16IS7XX_IOSTATE_REG: + return true; + default: + break; + } + + return false; +} + +static bool sc16is7xx_regmap_precious(struct device *dev, unsigned int reg) +{ + switch (reg >> SC16IS7XX_REG_SHIFT) { + case SC16IS7XX_RHR_REG: + return true; + default: + break; + } + + return false; +} + +static int sc16is7xx_set_baud(struct uart_port *port, int baud) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + u8 lcr; + u8 prescaler = 0; + unsigned long clk = port->uartclk, div = clk / 16 / baud; + + if (div > 0xffff) { + prescaler = SC16IS7XX_MCR_CLKSEL_BIT; + div /= 4; + } + + lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); + + /* Open the LCR divisors for configuration */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_CONF_MODE_B); + + /* Enable enhanced features */ + regcache_cache_bypass(s->regmap, true); + sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_ENABLE_BIT); + regcache_cache_bypass(s->regmap, false); + + /* Put LCR back to the normal mode */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_CLKSEL_BIT, + prescaler); + + /* Open the LCR divisors for configuration */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_CONF_MODE_A); + + /* Write the new divisor */ + regcache_cache_bypass(s->regmap, true); + sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256); + sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256); + regcache_cache_bypass(s->regmap, false); + + /* Put LCR back to the normal mode */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + + return DIV_ROUND_CLOSEST(clk / 16, div); +} + +static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, + unsigned int iir) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + unsigned int lsr = 0, ch, flag, bytes_read, i; + u8 buf[port->fifosize]; + bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC) ? true : false; + + if (unlikely(rxlen >= port->fifosize)) { + dev_warn_ratelimited(port->dev, + "Port %i: Possible RX FIFO overrun: %d\n", + port->line, rxlen); + port->icount.buf_overrun++; + /* Ensure sanity of RX level */ + rxlen = port->fifosize; + } + + while (rxlen) { + /* Only read lsr if there are possible errors in FIFO */ + if (read_lsr) { + lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); + if (!(lsr & SC16IS7XX_LSR_FIFOE_BIT)) + read_lsr = false; /* No errors left in FIFO */ + } else + lsr = 0; + + if (read_lsr) { + buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG); + bytes_read = 1; + } else { + regcache_cache_bypass(s->regmap, true); + regmap_raw_read(s->regmap, SC16IS7XX_RHR_REG, + buf, rxlen); + regcache_cache_bypass(s->regmap, false); + bytes_read = rxlen; + } + + lsr &= SC16IS7XX_LSR_BRK_ERROR_MASK; + + port->icount.rx++; + flag = TTY_NORMAL; + + if (unlikely(lsr)) { + if (lsr & SC16IS7XX_LSR_BI_BIT) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (lsr & SC16IS7XX_LSR_PE_BIT) + port->icount.parity++; + else if (lsr & SC16IS7XX_LSR_FE_BIT) + port->icount.frame++; + else if (lsr & SC16IS7XX_LSR_OE_BIT) + port->icount.overrun++; + + lsr &= port->read_status_mask; + if (lsr & SC16IS7XX_LSR_BI_BIT) + flag = TTY_BREAK; + else if (lsr & SC16IS7XX_LSR_PE_BIT) + flag = TTY_PARITY; + else if (lsr & SC16IS7XX_LSR_FE_BIT) + flag = TTY_FRAME; + else if (lsr & SC16IS7XX_LSR_OE_BIT) + flag = TTY_OVERRUN; + } + + for (i = 0; i < bytes_read; ++i) { + ch = buf[i]; + if (uart_handle_sysrq_char(port, ch)) + continue; + + if (lsr & port->ignore_status_mask) + continue; + + uart_insert_char(port, lsr, SC16IS7XX_LSR_OE_BIT, ch, + flag); + } + rxlen -= bytes_read; + } + + tty_flip_buffer_push(&port->state->port); +} + +static void sc16is7xx_handle_tx(struct uart_port *port) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct circ_buf *xmit = &port->state->xmit; + unsigned int txlen, to_send, i; + u8 buf[port->fifosize]; + + if (unlikely(port->x_char)) { + sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + return; + + /* Get length of data pending in circular buffer */ + to_send = uart_circ_chars_pending(xmit); + if (likely(to_send)) { + /* Limit to size of TX FIFO */ + txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); + to_send = (to_send > txlen) ? txlen : to_send; + + /* Add data to send */ + port->icount.tx += to_send; + + /* Convert to linear buffer */ + for (i = 0; i < to_send; ++i) { + buf[i] = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } + regcache_cache_bypass(s->regmap, true); + regmap_raw_write(s->regmap, SC16IS7XX_THR_REG, buf, to_send); + regcache_cache_bypass(s->regmap, false); + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) +{ + struct uart_port *port = &s->p[portno].port; + + do { + unsigned int iir, msr, rxlen; + + iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); + if (iir & SC16IS7XX_IIR_NO_INT_BIT) + break; + + iir &= SC16IS7XX_IIR_ID_MASK; + + switch (iir) { + case SC16IS7XX_IIR_RDI_SRC: + case SC16IS7XX_IIR_RLSE_SRC: + case SC16IS7XX_IIR_RTOI_SRC: + case SC16IS7XX_IIR_XOFFI_SRC: + rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG); + if (rxlen) + sc16is7xx_handle_rx(port, rxlen, iir); + break; + + case SC16IS7XX_IIR_CTSRTS_SRC: + msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG); + uart_handle_cts_change(port, + !!(msr & SC16IS7XX_MSR_CTS_BIT)); + break; + case SC16IS7XX_IIR_THRI_SRC: + mutex_lock(&s->mutex); + sc16is7xx_handle_tx(port); + mutex_unlock(&s->mutex); + break; + default: + dev_err_ratelimited(port->dev, + "Port %i: Unexpected interrupt: %x", + port->line, iir); + break; + } + } while (1); +} + +static irqreturn_t sc16is7xx_ist(int irq, void *dev_id) +{ + struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; + int i; + + for (i = 0; i < s->uart.nr; ++i) + sc16is7xx_port_irq(s, i); + + return IRQ_HANDLED; +} + +static void sc16is7xx_wq_proc(struct work_struct *ws) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(ws, tx_work); + struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev); + + mutex_lock(&s->mutex); + sc16is7xx_handle_tx(&one->port); + mutex_unlock(&s->mutex); +} + +static void sc16is7xx_stop_tx(struct uart_port* port) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + struct circ_buf *xmit = &one->port.state->xmit; + + /* handle rs485 */ + if (one->rs485.flags & SER_RS485_ENABLED) { + /* do nothing if current tx not yet completed */ + int lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); + if (!(lsr & SC16IS7XX_LSR_TEMT_BIT)) + return; + + if (uart_circ_empty(xmit) && + (one->rs485.delay_rts_after_send > 0)) + mdelay(one->rs485.delay_rts_after_send); + } + + sc16is7xx_port_update(port, SC16IS7XX_IER_REG, + SC16IS7XX_IER_THRI_BIT, + 0); +} + +static void sc16is7xx_stop_rx(struct uart_port* port) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + one->port.read_status_mask &= ~SC16IS7XX_LSR_DR_BIT; + sc16is7xx_port_update(port, SC16IS7XX_IER_REG, + SC16IS7XX_LSR_DR_BIT, + 0); +} + +static void sc16is7xx_start_tx(struct uart_port *port) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + /* handle rs485 */ + if ((one->rs485.flags & SER_RS485_ENABLED) && + (one->rs485.delay_rts_before_send > 0)) { + mdelay(one->rs485.delay_rts_before_send); + } + + if (!work_pending(&one->tx_work)) + schedule_work(&one->tx_work); +} + +static unsigned int sc16is7xx_tx_empty(struct uart_port *port) +{ + unsigned int lvl, lsr; + + lvl = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); + lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); + + return ((lsr & SC16IS7XX_LSR_THRE_BIT) && !lvl) ? TIOCSER_TEMT : 0; +} + +static unsigned int sc16is7xx_get_mctrl(struct uart_port *port) +{ + /* DCD and DSR are not wired and CTS/RTS is handled automatically + * so just indicate DSR and CAR asserted + */ + return TIOCM_DSR | TIOCM_CAR; +} + +static void sc16is7xx_md_proc(struct work_struct *ws) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(ws, md_work); + + sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_LOOP_BIT, + (one->port.mctrl & TIOCM_LOOP) ? + SC16IS7XX_MCR_LOOP_BIT : 0); +} + +static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + schedule_work(&one->md_work); +} + +static void sc16is7xx_break_ctl(struct uart_port *port, int break_state) +{ + sc16is7xx_port_update(port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_TXBREAK_BIT, + break_state ? SC16IS7XX_LCR_TXBREAK_BIT : 0); +} + +static void sc16is7xx_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + unsigned int lcr, flow = 0; + int baud; + + /* Mask termios capabilities we don't support */ + termios->c_cflag &= ~CMSPAR; + + /* Word size */ + switch (termios->c_cflag & CSIZE) { + case CS5: + lcr = SC16IS7XX_LCR_WORD_LEN_5; + break; + case CS6: + lcr = SC16IS7XX_LCR_WORD_LEN_6; + break; + case CS7: + lcr = SC16IS7XX_LCR_WORD_LEN_7; + break; + case CS8: + lcr = SC16IS7XX_LCR_WORD_LEN_8; + break; + default: + lcr = SC16IS7XX_LCR_WORD_LEN_8; + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; + break; + } + + /* Parity */ + if (termios->c_cflag & PARENB) { + lcr |= SC16IS7XX_LCR_PARITY_BIT; + if (!(termios->c_cflag & PARODD)) + lcr |= SC16IS7XX_LCR_EVENPARITY_BIT; + } + + /* Stop bits */ + if (termios->c_cflag & CSTOPB) + lcr |= SC16IS7XX_LCR_STOPLEN_BIT; /* 2 stops */ + + /* Set read status mask */ + port->read_status_mask = SC16IS7XX_LSR_OE_BIT; + if (termios->c_iflag & INPCK) + port->read_status_mask |= SC16IS7XX_LSR_PE_BIT | + SC16IS7XX_LSR_FE_BIT; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= SC16IS7XX_LSR_BI_BIT; + + /* Set status ignore mask */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNBRK) + port->ignore_status_mask |= SC16IS7XX_LSR_BI_BIT; + if (!(termios->c_cflag & CREAD)) + port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK; + + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_CONF_MODE_B); + + /* Configure flow control */ + regcache_cache_bypass(s->regmap, true); + sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]); + sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]); + if (termios->c_cflag & CRTSCTS) + flow |= SC16IS7XX_EFR_AUTOCTS_BIT | + SC16IS7XX_EFR_AUTORTS_BIT; + if (termios->c_iflag & IXON) + flow |= SC16IS7XX_EFR_SWFLOW3_BIT; + if (termios->c_iflag & IXOFF) + flow |= SC16IS7XX_EFR_SWFLOW1_BIT; + + sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, flow); + regcache_cache_bypass(s->regmap, false); + + /* Update LCR register */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + + /* Get baud rate generator configuration */ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 4 / 0xffff, + port->uartclk / 16); + + /* Setup baudrate generator */ + baud = sc16is7xx_set_baud(port, baud); + + /* Update timeout according to new baud rate */ + uart_update_timeout(port, termios->c_cflag, baud); +} + +#if defined(TIOCSRS485) && defined(TIOCGRS485) +static void sc16is7xx_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + one->rs485 = *rs485; + + if (one->rs485.flags & SER_RS485_ENABLED) { + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_AUTO_RS485_BIT, + SC16IS7XX_EFCR_AUTO_RS485_BIT); + } else { + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_AUTO_RS485_BIT, + 0); + } +} +#endif + +static int sc16is7xx_ioctl(struct uart_port *port, unsigned int cmd, + unsigned long arg) +{ +#if defined(TIOCSRS485) && defined(TIOCGRS485) + struct serial_rs485 rs485; + + switch (cmd) { + case TIOCSRS485: + if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485))) + return -EFAULT; + + sc16is7xx_config_rs485(port, &rs485); + return 0; + case TIOCGRS485: + if (copy_to_user((void __user *)arg, + &(to_sc16is7xx_one(port, port)->rs485), + sizeof(rs485))) + return -EFAULT; + return 0; + default: + break; + } +#endif + + return -ENOIOCTLCMD; +} + +static int sc16is7xx_startup(struct uart_port *port) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + unsigned int val; + + sc16is7xx_power(port, 1); + + /* Reset FIFOs*/ + val = SC16IS7XX_FCR_RXRESET_BIT | SC16IS7XX_FCR_TXRESET_BIT; + sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, val); + udelay(5); + sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, + SC16IS7XX_FCR_FIFO_BIT); + + /* Enable EFR */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_CONF_MODE_B); + + regcache_cache_bypass(s->regmap, true); + + /* Enable write access to enhanced features and internal clock div */ + sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_ENABLE_BIT); + + /* Enable TCR/TLR */ + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_TCRTLR_BIT, + SC16IS7XX_MCR_TCRTLR_BIT); + + /* Configure flow control levels */ + /* Flow control halt level 48, resume level 24 */ + sc16is7xx_port_write(port, SC16IS7XX_TCR_REG, + SC16IS7XX_TCR_RX_RESUME(24) | + SC16IS7XX_TCR_RX_HALT(48)); + + regcache_cache_bypass(s->regmap, false); + + /* Now, initialize the UART */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8); + + /* Enable the Rx and Tx FIFO */ + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT, + 0); + + /* Enable RX, TX, CTS change interrupts */ + val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT | + SC16IS7XX_IER_CTSI_BIT; + sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); + + return 0; +} + +static void sc16is7xx_shutdown(struct uart_port *port) +{ + /* Disable all interrupts */ + sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); + /* Disable TX/RX */ + sc16is7xx_port_write(port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT); + + sc16is7xx_power(port, 0); +} + +static const char *sc16is7xx_type(struct uart_port *port) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + + return (port->type == PORT_SC16IS7XX) ? s->devtype->name : NULL; +} + +static int sc16is7xx_request_port(struct uart_port *port) +{ + /* Do nothing */ + return 0; +} + +static void sc16is7xx_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_SC16IS7XX; +} + +static int sc16is7xx_verify_port(struct uart_port *port, + struct serial_struct *s) +{ + if ((s->type != PORT_UNKNOWN) && (s->type != PORT_SC16IS7XX)) + return -EINVAL; + if (s->irq != port->irq) + return -EINVAL; + + return 0; +} + +static void sc16is7xx_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + sc16is7xx_power(port, (state == UART_PM_STATE_ON) ? 1 : 0); +} + +static void sc16is7xx_null_void(struct uart_port *port) +{ + /* Do nothing */ +} + +static const struct uart_ops sc16is7xx_ops = { + .tx_empty = sc16is7xx_tx_empty, + .set_mctrl = sc16is7xx_set_mctrl, + .get_mctrl = sc16is7xx_get_mctrl, + .stop_tx = sc16is7xx_stop_tx, + .start_tx = sc16is7xx_start_tx, + .stop_rx = sc16is7xx_stop_rx, + .enable_ms = sc16is7xx_null_void, + .break_ctl = sc16is7xx_break_ctl, + .startup = sc16is7xx_startup, + .shutdown = sc16is7xx_shutdown, + .set_termios = sc16is7xx_set_termios, + .type = sc16is7xx_type, + .request_port = sc16is7xx_request_port, + .release_port = sc16is7xx_null_void, + .config_port = sc16is7xx_config_port, + .verify_port = sc16is7xx_verify_port, + .ioctl = sc16is7xx_ioctl, + .pm = sc16is7xx_pm, +}; + +#ifdef CONFIG_GPIOLIB +static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + unsigned int val; + struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, + gpio); + struct uart_port *port = &s->p[0].port; + + val = sc16is7xx_port_read(port, SC16IS7XX_IOSTATE_REG); + + return !!(val & BIT(offset)); +} + +static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, + gpio); + struct uart_port *port = &s->p[0].port; + + sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset), + val ? BIT(offset) : 0); +} + +static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, + gpio); + struct uart_port *port = &s->p[0].port; + + sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), 0); + + return 0; +} + +static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int val) +{ + struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, + gpio); + struct uart_port *port = &s->p[0].port; + + sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset), + val ? BIT(offset) : 0); + sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), + BIT(offset)); + + return 0; +} +#endif + +static int sc16is7xx_probe(struct device *dev, + struct sc16is7xx_devtype *devtype, + struct regmap *regmap, int irq, unsigned long flags) +{ + unsigned long freq, *pfreq = dev_get_platdata(dev); + struct clk *clk; + int i, ret; + struct sc16is7xx_port *s; + + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* Alloc port structure */ + s = devm_kzalloc(dev, sizeof(*s) + + sizeof(struct sc16is7xx_one) * devtype->nr_uart, + GFP_KERNEL); + if (!s) { + dev_err(dev, "Error allocating port structure\n"); + return -ENOMEM; + } + + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + if (pfreq) + freq = *pfreq; + else + return PTR_ERR(clk); + } else { + freq = clk_get_rate(clk); + } + + s->regmap = regmap; + s->devtype = devtype; + dev_set_drvdata(dev, s); + + /* Register UART driver */ + s->uart.owner = THIS_MODULE; + s->uart.dev_name = "ttySC"; + s->uart.nr = devtype->nr_uart; + ret = uart_register_driver(&s->uart); + if (ret) { + dev_err(dev, "Registering UART driver failed\n"); + goto out_clk; + } + +#ifdef CONFIG_GPIOLIB + if (devtype->nr_gpio) { + /* Setup GPIO cotroller */ + s->gpio.owner = THIS_MODULE; + s->gpio.dev = dev; + s->gpio.label = dev_name(dev); + s->gpio.direction_input = sc16is7xx_gpio_direction_input; + s->gpio.get = sc16is7xx_gpio_get; + s->gpio.direction_output = sc16is7xx_gpio_direction_output; + s->gpio.set = sc16is7xx_gpio_set; + s->gpio.base = -1; + s->gpio.ngpio = devtype->nr_gpio; + s->gpio.can_sleep = 1; + ret = gpiochip_add(&s->gpio); + if (ret) + goto out_uart; + } +#endif + + mutex_init(&s->mutex); + + for (i = 0; i < devtype->nr_uart; ++i) { + /* Initialize port data */ + s->p[i].port.line = i; + s->p[i].port.dev = dev; + s->p[i].port.irq = irq; + s->p[i].port.type = PORT_SC16IS7XX; + s->p[i].port.fifosize = SC16IS7XX_FIFO_SIZE; + s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; + s->p[i].port.iotype = UPIO_PORT; + s->p[i].port.uartclk = freq; + s->p[i].port.ops = &sc16is7xx_ops; + /* Disable all interrupts */ + sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0); + /* Disable TX/RX */ + sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT); + /* Initialize queue for start TX */ + INIT_WORK(&s->p[i].tx_work, sc16is7xx_wq_proc); + /* Initialize queue for changing mode */ + INIT_WORK(&s->p[i].md_work, sc16is7xx_md_proc); + /* Register port */ + uart_add_one_port(&s->uart, &s->p[i].port); + /* Go to suspend mode */ + sc16is7xx_power(&s->p[i].port, 0); + } + + /* Setup interrupt */ + ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_ist, + IRQF_ONESHOT | flags, dev_name(dev), s); + if (!ret) + return 0; + + mutex_destroy(&s->mutex); + +#ifdef CONFIG_GPIOLIB + if (devtype->nr_gpio) + WARN_ON(gpiochip_remove(&s->gpio)); + +out_uart: +#endif + uart_unregister_driver(&s->uart); + +out_clk: + if (!IS_ERR(s->clk)) + clk_disable_unprepare(s->clk); + + return ret; +} + +static int sc16is7xx_remove(struct device *dev) +{ + struct sc16is7xx_port *s = dev_get_drvdata(dev); + int i, ret = 0; + +#ifdef CONFIG_GPIOLIB + if (s->devtype->nr_gpio) { + ret = gpiochip_remove(&s->gpio); + if (ret) + return ret; + } +#endif + + for (i = 0; i < s->uart.nr; i++) { + cancel_work_sync(&s->p[i].tx_work); + cancel_work_sync(&s->p[i].md_work); + uart_remove_one_port(&s->uart, &s->p[i].port); + sc16is7xx_power(&s->p[i].port, 0); + } + + mutex_destroy(&s->mutex); + uart_unregister_driver(&s->uart); + if (!IS_ERR(s->clk)) + clk_disable_unprepare(s->clk); + + return ret; +} + +static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { + { .compatible = "nxp,sc16is740", .data = &sc16is74x_devtype, }, + { .compatible = "nxp,sc16is741", .data = &sc16is74x_devtype, }, + { .compatible = "nxp,sc16is750", .data = &sc16is750_devtype, }, + { .compatible = "nxp,sc16is752", .data = &sc16is752_devtype, }, + { .compatible = "nxp,sc16is760", .data = &sc16is760_devtype, }, + { .compatible = "nxp,sc16is762", .data = &sc16is762_devtype, }, + { } +}; +MODULE_DEVICE_TABLE(of, sc16is7xx_dt_ids); + +static struct regmap_config regcfg = { + .reg_bits = 7, + .pad_bits = 1, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = sc16is7xx_regmap_volatile, + .precious_reg = sc16is7xx_regmap_precious, +}; + +#ifdef CONFIG_REGMAP_I2C +static int sc16is7xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct sc16is7xx_devtype *devtype; + unsigned long flags = 0; + struct regmap *regmap; + + if (i2c->dev.of_node) { + const struct of_device_id *of_id = + of_match_device(sc16is7xx_dt_ids, &i2c->dev); + + devtype = (struct sc16is7xx_devtype *)of_id->data; + } else { + devtype = (struct sc16is7xx_devtype *)id->driver_data; + flags = IRQF_TRIGGER_FALLING; + } + + regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | + (devtype->nr_uart - 1); + regmap = devm_regmap_init_i2c(i2c, ®cfg); + + return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq, flags); +} + +static int sc16is7xx_i2c_remove(struct i2c_client *client) +{ + return sc16is7xx_remove(&client->dev); +} + +static const struct i2c_device_id sc16is7xx_i2c_id_table[] = { + { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, + { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, + { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, + { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table); + +static struct i2c_driver sc16is7xx_i2c_uart_driver = { + .driver = { + .name = SC16IS7XX_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(sc16is7xx_dt_ids), + }, + .probe = sc16is7xx_i2c_probe, + .remove = sc16is7xx_i2c_remove, + .id_table = sc16is7xx_i2c_id_table, +}; +module_i2c_driver(sc16is7xx_i2c_uart_driver); +MODULE_ALIAS("i2c:sc16is7xx"); +#endif + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jon Ringle "); +MODULE_DESCRIPTION("SC16IS7XX serial driver"); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index b68550d95a403d..9a01ee4dda6df1 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2239,6 +2239,9 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch) return; port = state->uart_port; + + if (ch == '\n') + port->ops->poll_put_char(port, '\r'); port->ops->poll_put_char(port, ch); } #endif diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 90a080b1f9ee13..60f49b9d7e3921 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -535,13 +535,8 @@ static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c) wait_for_xmitr(up); /* * Send the character out. - * If a LF, also do CR... */ sio_out(up, TXX9_SITFIFO, c); - if (c == 10) { - wait_for_xmitr(up); - sio_out(up, TXX9_SITFIFO, 13); - } /* * Finally, wait for transmitter to become empty diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index f619ad5b5eaefc..8809775e2ba30c 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1,7 +1,7 @@ /* - * Xilinx PS UART driver + * Cadence UART driver (found in Xilinx Zynq) * - * 2011 - 2013 (C) Xilinx Inc. + * 2011 - 2014 (C) Xilinx Inc. * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General Public @@ -9,6 +9,9 @@ * either version 2 of the License, or (at your option) any * later version. * + * This driver has originally been pushed by Xilinx using a Zynq-branding. This + * still shows in the naming of this file, the kconfig symbols and some symbols + * in the code. */ #if defined(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -28,16 +31,16 @@ #include #include -#define XUARTPS_TTY_NAME "ttyPS" -#define XUARTPS_NAME "xuartps" -#define XUARTPS_MAJOR 0 /* use dynamic node allocation */ -#define XUARTPS_MINOR 0 /* works best with devtmpfs */ -#define XUARTPS_NR_PORTS 2 -#define XUARTPS_FIFO_SIZE 64 /* FIFO size */ -#define XUARTPS_REGISTER_SPACE 0xFFF +#define CDNS_UART_TTY_NAME "ttyPS" +#define CDNS_UART_NAME "xuartps" +#define CDNS_UART_MAJOR 0 /* use dynamic node allocation */ +#define CDNS_UART_MINOR 0 /* works best with devtmpfs */ +#define CDNS_UART_NR_PORTS 2 +#define CDNS_UART_FIFO_SIZE 64 /* FIFO size */ +#define CDNS_UART_REGISTER_SPACE 0xFFF -#define xuartps_readl(offset) ioread32(port->membase + offset) -#define xuartps_writel(val, offset) iowrite32(val, port->membase + offset) +#define cdns_uart_readl(offset) ioread32(port->membase + offset) +#define cdns_uart_writel(val, offset) iowrite32(val, port->membase + offset) /* Rx Trigger level */ static int rx_trigger_level = 56; @@ -49,77 +52,62 @@ static int rx_timeout = 10; module_param(rx_timeout, uint, S_IRUGO); MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); -/********************************Register Map********************************/ -/** UART - * - * Register offsets for the UART. - * - */ -#define XUARTPS_CR_OFFSET 0x00 /* Control Register [8:0] */ -#define XUARTPS_MR_OFFSET 0x04 /* Mode Register [10:0] */ -#define XUARTPS_IER_OFFSET 0x08 /* Interrupt Enable [10:0] */ -#define XUARTPS_IDR_OFFSET 0x0C /* Interrupt Disable [10:0] */ -#define XUARTPS_IMR_OFFSET 0x10 /* Interrupt Mask [10:0] */ -#define XUARTPS_ISR_OFFSET 0x14 /* Interrupt Status [10:0]*/ -#define XUARTPS_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator [15:0] */ -#define XUARTPS_RXTOUT_OFFSET 0x1C /* RX Timeout [7:0] */ -#define XUARTPS_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level [5:0] */ -#define XUARTPS_MODEMCR_OFFSET 0x24 /* Modem Control [5:0] */ -#define XUARTPS_MODEMSR_OFFSET 0x28 /* Modem Status [8:0] */ -#define XUARTPS_SR_OFFSET 0x2C /* Channel Status [11:0] */ -#define XUARTPS_FIFO_OFFSET 0x30 /* FIFO [15:0] or [7:0] */ -#define XUARTPS_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider [7:0] */ -#define XUARTPS_FLOWDEL_OFFSET 0x38 /* Flow Delay [15:0] */ -#define XUARTPS_IRRX_PWIDTH_OFFSET 0x3C /* IR Minimum Received Pulse - Width [15:0] */ -#define XUARTPS_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse - Width [7:0] */ -#define XUARTPS_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level [5:0] */ - -/** Control Register - * - * The Control register (CR) controls the major functions of the device. - * - * Control Register Bit Definitions - */ -#define XUARTPS_CR_STOPBRK 0x00000100 /* Stop TX break */ -#define XUARTPS_CR_STARTBRK 0x00000080 /* Set TX break */ -#define XUARTPS_CR_TX_DIS 0x00000020 /* TX disabled. */ -#define XUARTPS_CR_TX_EN 0x00000010 /* TX enabled */ -#define XUARTPS_CR_RX_DIS 0x00000008 /* RX disabled. */ -#define XUARTPS_CR_RX_EN 0x00000004 /* RX enabled */ -#define XUARTPS_CR_TXRST 0x00000002 /* TX logic reset */ -#define XUARTPS_CR_RXRST 0x00000001 /* RX logic reset */ -#define XUARTPS_CR_RST_TO 0x00000040 /* Restart Timeout Counter */ - -/** Mode Register - * +/* Register offsets for the UART. */ +#define CDNS_UART_CR_OFFSET 0x00 /* Control Register */ +#define CDNS_UART_MR_OFFSET 0x04 /* Mode Register */ +#define CDNS_UART_IER_OFFSET 0x08 /* Interrupt Enable */ +#define CDNS_UART_IDR_OFFSET 0x0C /* Interrupt Disable */ +#define CDNS_UART_IMR_OFFSET 0x10 /* Interrupt Mask */ +#define CDNS_UART_ISR_OFFSET 0x14 /* Interrupt Status */ +#define CDNS_UART_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator */ +#define CDNS_UART_RXTOUT_OFFSET 0x1C /* RX Timeout */ +#define CDNS_UART_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level */ +#define CDNS_UART_MODEMCR_OFFSET 0x24 /* Modem Control */ +#define CDNS_UART_MODEMSR_OFFSET 0x28 /* Modem Status */ +#define CDNS_UART_SR_OFFSET 0x2C /* Channel Status */ +#define CDNS_UART_FIFO_OFFSET 0x30 /* FIFO */ +#define CDNS_UART_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider */ +#define CDNS_UART_FLOWDEL_OFFSET 0x38 /* Flow Delay */ +#define CDNS_UART_IRRX_PWIDTH_OFFSET 0x3C /* IR Min Received Pulse Width */ +#define CDNS_UART_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse Width */ +#define CDNS_UART_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level */ + +/* Control Register Bit Definitions */ +#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */ +#define CDNS_UART_CR_STARTBRK 0x00000080 /* Set TX break */ +#define CDNS_UART_CR_TX_DIS 0x00000020 /* TX disabled. */ +#define CDNS_UART_CR_TX_EN 0x00000010 /* TX enabled */ +#define CDNS_UART_CR_RX_DIS 0x00000008 /* RX disabled. */ +#define CDNS_UART_CR_RX_EN 0x00000004 /* RX enabled */ +#define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */ +#define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */ +#define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */ + +/* + * Mode Register: * The mode register (MR) defines the mode of transfer as well as the data * format. If this register is modified during transmission or reception, * data validity cannot be guaranteed. - * - * Mode Register Bit Definitions - * */ -#define XUARTPS_MR_CLKSEL 0x00000001 /* Pre-scalar selection */ -#define XUARTPS_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */ -#define XUARTPS_MR_CHMODE_NORM 0x00000000 /* Normal mode */ +#define CDNS_UART_MR_CLKSEL 0x00000001 /* Pre-scalar selection */ +#define CDNS_UART_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */ +#define CDNS_UART_MR_CHMODE_NORM 0x00000000 /* Normal mode */ -#define XUARTPS_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */ -#define XUARTPS_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */ +#define CDNS_UART_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */ +#define CDNS_UART_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */ -#define XUARTPS_MR_PARITY_NONE 0x00000020 /* No parity mode */ -#define XUARTPS_MR_PARITY_MARK 0x00000018 /* Mark parity mode */ -#define XUARTPS_MR_PARITY_SPACE 0x00000010 /* Space parity mode */ -#define XUARTPS_MR_PARITY_ODD 0x00000008 /* Odd parity mode */ -#define XUARTPS_MR_PARITY_EVEN 0x00000000 /* Even parity mode */ +#define CDNS_UART_MR_PARITY_NONE 0x00000020 /* No parity mode */ +#define CDNS_UART_MR_PARITY_MARK 0x00000018 /* Mark parity mode */ +#define CDNS_UART_MR_PARITY_SPACE 0x00000010 /* Space parity mode */ +#define CDNS_UART_MR_PARITY_ODD 0x00000008 /* Odd parity mode */ +#define CDNS_UART_MR_PARITY_EVEN 0x00000000 /* Even parity mode */ -#define XUARTPS_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */ -#define XUARTPS_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */ -#define XUARTPS_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */ +#define CDNS_UART_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */ +#define CDNS_UART_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */ +#define CDNS_UART_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */ -/** Interrupt Registers - * +/* + * Interrupt Registers: * Interrupt control logic uses the interrupt enable register (IER) and the * interrupt disable register (IDR) to set the value of the bits in the * interrupt mask register (IMR). The IMR determines whether to pass an @@ -127,65 +115,65 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); * Writing a 1 to IER Enables an interrupt, writing a 1 to IDR disables an * interrupt. IMR and ISR are read only, and IER and IDR are write only. * Reading either IER or IDR returns 0x00. - * * All four registers have the same bit definitions. */ -#define XUARTPS_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */ -#define XUARTPS_IXR_PARITY 0x00000080 /* Parity error interrupt */ -#define XUARTPS_IXR_FRAMING 0x00000040 /* Framing error interrupt */ -#define XUARTPS_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */ -#define XUARTPS_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */ -#define XUARTPS_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */ -#define XUARTPS_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */ -#define XUARTPS_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */ -#define XUARTPS_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */ -#define XUARTPS_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ -#define XUARTPS_IXR_MASK 0x00001FFF /* Valid bit mask */ +#define CDNS_UART_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */ +#define CDNS_UART_IXR_PARITY 0x00000080 /* Parity error interrupt */ +#define CDNS_UART_IXR_FRAMING 0x00000040 /* Framing error interrupt */ +#define CDNS_UART_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */ +#define CDNS_UART_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */ +#define CDNS_UART_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */ +#define CDNS_UART_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */ +#define CDNS_UART_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */ +#define CDNS_UART_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */ +#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ +#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */ /* Goes in read_status_mask for break detection as the HW doesn't do it*/ -#define XUARTPS_IXR_BRK 0x80000000 +#define CDNS_UART_IXR_BRK 0x80000000 -/** Channel Status Register - * +/* + * Channel Status Register: * The channel status register (CSR) is provided to enable the control logic * to monitor the status of bits in the channel interrupt status register, * even if these are masked out by the interrupt mask register. */ -#define XUARTPS_SR_RXEMPTY 0x00000002 /* RX FIFO empty */ -#define XUARTPS_SR_TXEMPTY 0x00000008 /* TX FIFO empty */ -#define XUARTPS_SR_TXFULL 0x00000010 /* TX FIFO full */ -#define XUARTPS_SR_RXTRIG 0x00000001 /* Rx Trigger */ +#define CDNS_UART_SR_RXEMPTY 0x00000002 /* RX FIFO empty */ +#define CDNS_UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */ +#define CDNS_UART_SR_TXFULL 0x00000010 /* TX FIFO full */ +#define CDNS_UART_SR_RXTRIG 0x00000001 /* Rx Trigger */ /* baud dividers min/max values */ -#define XUARTPS_BDIV_MIN 4 -#define XUARTPS_BDIV_MAX 255 -#define XUARTPS_CD_MAX 65535 +#define CDNS_UART_BDIV_MIN 4 +#define CDNS_UART_BDIV_MAX 255 +#define CDNS_UART_CD_MAX 65535 /** - * struct xuartps - device data - * @port Pointer to the UART port - * @refclk Reference clock - * @aperclk APB clock - * @baud Current baud rate - * @clk_rate_change_nb Notifier block for clock changes + * struct cdns_uart - device data + * @port: Pointer to the UART port + * @uartclk: Reference clock + * @pclk: APB clock + * @baud: Current baud rate + * @clk_rate_change_nb: Notifier block for clock changes */ -struct xuartps { +struct cdns_uart { struct uart_port *port; - struct clk *refclk; - struct clk *aperclk; + struct clk *uartclk; + struct clk *pclk; unsigned int baud; struct notifier_block clk_rate_change_nb; }; -#define to_xuartps(_nb) container_of(_nb, struct xuartps, clk_rate_change_nb); +#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ + clk_rate_change_nb); /** - * xuartps_isr - Interrupt handler + * cdns_uart_isr - Interrupt handler * @irq: Irq number * @dev_id: Id of the port * - * Returns IRQHANDLED - **/ -static irqreturn_t xuartps_isr(int irq, void *dev_id) + * Return: IRQHANDLED + */ +static irqreturn_t cdns_uart_isr(int irq, void *dev_id) { struct uart_port *port = (struct uart_port *)dev_id; unsigned long flags; @@ -198,43 +186,42 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) /* Read the interrupt status register to determine which * interrupt(s) is/are active. */ - isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET); + isrstatus = cdns_uart_readl(CDNS_UART_ISR_OFFSET); /* * There is no hardware break detection, so we interpret framing * error with all-zeros data as a break sequence. Most of the time, * there's another non-zero byte at the end of the sequence. */ - - if (isrstatus & XUARTPS_IXR_FRAMING) { - while (!(xuartps_readl(XUARTPS_SR_OFFSET) & - XUARTPS_SR_RXEMPTY)) { - if (!xuartps_readl(XUARTPS_FIFO_OFFSET)) { - port->read_status_mask |= XUARTPS_IXR_BRK; - isrstatus &= ~XUARTPS_IXR_FRAMING; + if (isrstatus & CDNS_UART_IXR_FRAMING) { + while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_RXEMPTY)) { + if (!cdns_uart_readl(CDNS_UART_FIFO_OFFSET)) { + port->read_status_mask |= CDNS_UART_IXR_BRK; + isrstatus &= ~CDNS_UART_IXR_FRAMING; } } - xuartps_writel(XUARTPS_IXR_FRAMING, XUARTPS_ISR_OFFSET); + cdns_uart_writel(CDNS_UART_IXR_FRAMING, CDNS_UART_ISR_OFFSET); } /* drop byte with parity error if IGNPAR specified */ - if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY) - isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT); + if (isrstatus & port->ignore_status_mask & CDNS_UART_IXR_PARITY) + isrstatus &= ~(CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT); isrstatus &= port->read_status_mask; isrstatus &= ~port->ignore_status_mask; - if ((isrstatus & XUARTPS_IXR_TOUT) || - (isrstatus & XUARTPS_IXR_RXTRIG)) { + if ((isrstatus & CDNS_UART_IXR_TOUT) || + (isrstatus & CDNS_UART_IXR_RXTRIG)) { /* Receive Timeout Interrupt */ - while ((xuartps_readl(XUARTPS_SR_OFFSET) & - XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) { - data = xuartps_readl(XUARTPS_FIFO_OFFSET); + while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) { + data = cdns_uart_readl(CDNS_UART_FIFO_OFFSET); /* Non-NULL byte after BREAK is garbage (99%) */ if (data && (port->read_status_mask & - XUARTPS_IXR_BRK)) { - port->read_status_mask &= ~XUARTPS_IXR_BRK; + CDNS_UART_IXR_BRK)) { + port->read_status_mask &= ~CDNS_UART_IXR_BRK; port->icount.brk++; if (uart_handle_break(port)) continue; @@ -258,16 +245,17 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) port->icount.rx++; - if (isrstatus & XUARTPS_IXR_PARITY) { + if (isrstatus & CDNS_UART_IXR_PARITY) { port->icount.parity++; status = TTY_PARITY; - } else if (isrstatus & XUARTPS_IXR_FRAMING) { + } else if (isrstatus & CDNS_UART_IXR_FRAMING) { port->icount.frame++; status = TTY_FRAME; - } else if (isrstatus & XUARTPS_IXR_OVERRUN) + } else if (isrstatus & CDNS_UART_IXR_OVERRUN) { port->icount.overrun++; + } - uart_insert_char(port, isrstatus, XUARTPS_IXR_OVERRUN, + uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN, data, status); } spin_unlock(&port->lock); @@ -276,10 +264,10 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) } /* Dispatch an appropriate handler */ - if ((isrstatus & XUARTPS_IXR_TXEMPTY) == XUARTPS_IXR_TXEMPTY) { + if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) { if (uart_circ_empty(&port->state->xmit)) { - xuartps_writel(XUARTPS_IXR_TXEMPTY, - XUARTPS_IDR_OFFSET); + cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, + CDNS_UART_IDR_OFFSET); } else { numbytes = port->fifosize; /* Break if no more data available in the UART buffer */ @@ -287,12 +275,12 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) if (uart_circ_empty(&port->state->xmit)) break; /* Get the data from the UART circular buffer - * and write it to the xuartps's TX_FIFO + * and write it to the cdns_uart's TX_FIFO * register. */ - xuartps_writel( + cdns_uart_writel( port->state->xmit.buf[port->state->xmit. - tail], XUARTPS_FIFO_OFFSET); + tail], CDNS_UART_FIFO_OFFSET); port->icount.tx++; @@ -300,7 +288,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) * the buffer if it reaches limit. */ port->state->xmit.tail = - (port->state->xmit.tail + 1) & \ + (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1); } @@ -310,7 +298,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) } } - xuartps_writel(isrstatus, XUARTPS_ISR_OFFSET); + cdns_uart_writel(isrstatus, CDNS_UART_ISR_OFFSET); /* be sure to release the lock and tty before leaving */ spin_unlock_irqrestore(&port->lock, flags); @@ -319,13 +307,13 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) } /** - * xuartps_calc_baud_divs - Calculate baud rate divisors + * cdns_uart_calc_baud_divs - Calculate baud rate divisors * @clk: UART module input clock * @baud: Desired baud rate * @rbdiv: BDIV value (return value) * @rcd: CD value (return value) * @div8: Value for clk_sel bit in mod (return value) - * Returns baud rate, requested baud when possible, or actual baud when there + * Return: baud rate, requested baud when possible, or actual baud when there * was too much error, zero if no valid divisors are found. * * Formula to obtain baud rate is @@ -338,8 +326,8 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) * baud rate generate register * baud rate clock divisor register */ -static unsigned int xuartps_calc_baud_divs(unsigned int clk, unsigned int baud, - u32 *rbdiv, u32 *rcd, int *div8) +static unsigned int cdns_uart_calc_baud_divs(unsigned int clk, + unsigned int baud, u32 *rbdiv, u32 *rcd, int *div8) { u32 cd, bdiv; unsigned int calc_baud; @@ -347,16 +335,16 @@ static unsigned int xuartps_calc_baud_divs(unsigned int clk, unsigned int baud, unsigned int bauderror; unsigned int besterror = ~0; - if (baud < clk / ((XUARTPS_BDIV_MAX + 1) * XUARTPS_CD_MAX)) { + if (baud < clk / ((CDNS_UART_BDIV_MAX + 1) * CDNS_UART_CD_MAX)) { *div8 = 1; clk /= 8; } else { *div8 = 0; } - for (bdiv = XUARTPS_BDIV_MIN; bdiv <= XUARTPS_BDIV_MAX; bdiv++) { + for (bdiv = CDNS_UART_BDIV_MIN; bdiv <= CDNS_UART_BDIV_MAX; bdiv++) { cd = DIV_ROUND_CLOSEST(clk, baud * (bdiv + 1)); - if (cd < 1 || cd > XUARTPS_CD_MAX) + if (cd < 1 || cd > CDNS_UART_CD_MAX) continue; calc_baud = clk / (cd * (bdiv + 1)); @@ -381,47 +369,47 @@ static unsigned int xuartps_calc_baud_divs(unsigned int clk, unsigned int baud, } /** - * xuartps_set_baud_rate - Calculate and set the baud rate + * cdns_uart_set_baud_rate - Calculate and set the baud rate * @port: Handle to the uart port structure * @baud: Baud rate to set - * Returns baud rate, requested baud when possible, or actual baud when there + * Return: baud rate, requested baud when possible, or actual baud when there * was too much error, zero if no valid divisors are found. */ -static unsigned int xuartps_set_baud_rate(struct uart_port *port, +static unsigned int cdns_uart_set_baud_rate(struct uart_port *port, unsigned int baud) { unsigned int calc_baud; u32 cd = 0, bdiv = 0; u32 mreg; int div8; - struct xuartps *xuartps = port->private_data; + struct cdns_uart *cdns_uart = port->private_data; - calc_baud = xuartps_calc_baud_divs(port->uartclk, baud, &bdiv, &cd, + calc_baud = cdns_uart_calc_baud_divs(port->uartclk, baud, &bdiv, &cd, &div8); /* Write new divisors to hardware */ - mreg = xuartps_readl(XUARTPS_MR_OFFSET); + mreg = cdns_uart_readl(CDNS_UART_MR_OFFSET); if (div8) - mreg |= XUARTPS_MR_CLKSEL; + mreg |= CDNS_UART_MR_CLKSEL; else - mreg &= ~XUARTPS_MR_CLKSEL; - xuartps_writel(mreg, XUARTPS_MR_OFFSET); - xuartps_writel(cd, XUARTPS_BAUDGEN_OFFSET); - xuartps_writel(bdiv, XUARTPS_BAUDDIV_OFFSET); - xuartps->baud = baud; + mreg &= ~CDNS_UART_MR_CLKSEL; + cdns_uart_writel(mreg, CDNS_UART_MR_OFFSET); + cdns_uart_writel(cd, CDNS_UART_BAUDGEN_OFFSET); + cdns_uart_writel(bdiv, CDNS_UART_BAUDDIV_OFFSET); + cdns_uart->baud = baud; return calc_baud; } #ifdef CONFIG_COMMON_CLK /** - * xuartps_clk_notitifer_cb - Clock notifier callback + * cdns_uart_clk_notitifer_cb - Clock notifier callback * @nb: Notifier block * @event: Notify event * @data: Notifier data - * Returns NOTIFY_OK on success, NOTIFY_BAD on error. + * Return: NOTIFY_OK or NOTIFY_DONE on success, NOTIFY_BAD on error. */ -static int xuartps_clk_notifier_cb(struct notifier_block *nb, +static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, unsigned long event, void *data) { u32 ctrl_reg; @@ -429,35 +417,36 @@ static int xuartps_clk_notifier_cb(struct notifier_block *nb, int locked = 0; struct clk_notifier_data *ndata = data; unsigned long flags = 0; - struct xuartps *xuartps = to_xuartps(nb); + struct cdns_uart *cdns_uart = to_cdns_uart(nb); - port = xuartps->port; + port = cdns_uart->port; if (port->suspended) return NOTIFY_OK; switch (event) { case PRE_RATE_CHANGE: { - u32 bdiv; - u32 cd; + u32 bdiv, cd; int div8; /* * Find out if current baud-rate can be achieved with new clock * frequency. */ - if (!xuartps_calc_baud_divs(ndata->new_rate, xuartps->baud, - &bdiv, &cd, &div8)) + if (!cdns_uart_calc_baud_divs(ndata->new_rate, cdns_uart->baud, + &bdiv, &cd, &div8)) { + dev_warn(port->dev, "clock rate change rejected\n"); return NOTIFY_BAD; + } - spin_lock_irqsave(&xuartps->port->lock, flags); + spin_lock_irqsave(&cdns_uart->port->lock, flags); /* Disable the TX and RX to set baud rate */ - xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | - (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS), - XUARTPS_CR_OFFSET); + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); - spin_unlock_irqrestore(&xuartps->port->lock, flags); + spin_unlock_irqrestore(&cdns_uart->port->lock, flags); return NOTIFY_OK; } @@ -467,25 +456,25 @@ static int xuartps_clk_notifier_cb(struct notifier_block *nb, * frequency. */ - spin_lock_irqsave(&xuartps->port->lock, flags); + spin_lock_irqsave(&cdns_uart->port->lock, flags); locked = 1; port->uartclk = ndata->new_rate; - xuartps->baud = xuartps_set_baud_rate(xuartps->port, - xuartps->baud); + cdns_uart->baud = cdns_uart_set_baud_rate(cdns_uart->port, + cdns_uart->baud); /* fall through */ case ABORT_RATE_CHANGE: if (!locked) - spin_lock_irqsave(&xuartps->port->lock, flags); + spin_lock_irqsave(&cdns_uart->port->lock, flags); /* Set TX/RX Reset */ - xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | - (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), - XUARTPS_CR_OFFSET); + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); - while (xuartps_readl(XUARTPS_CR_OFFSET) & - (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST)) + while (cdns_uart_readl(CDNS_UART_CR_OFFSET) & + (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) cpu_relax(); /* @@ -493,14 +482,13 @@ static int xuartps_clk_notifier_cb(struct notifier_block *nb, * enable bit and RX enable bit to enable the transmitter and * receiver. */ - xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); - ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); - xuartps_writel( - (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) | - (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), - XUARTPS_CR_OFFSET); + cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); + ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); - spin_unlock_irqrestore(&xuartps->port->lock, flags); + spin_unlock_irqrestore(&cdns_uart->port->lock, flags); return NOTIFY_OK; default: @@ -509,40 +497,36 @@ static int xuartps_clk_notifier_cb(struct notifier_block *nb, } #endif -/*----------------------Uart Operations---------------------------*/ - /** - * xuartps_start_tx - Start transmitting bytes + * cdns_uart_start_tx - Start transmitting bytes * @port: Handle to the uart port structure - * - **/ -static void xuartps_start_tx(struct uart_port *port) + */ +static void cdns_uart_start_tx(struct uart_port *port) { unsigned int status, numbytes = port->fifosize; if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port)) return; - status = xuartps_readl(XUARTPS_CR_OFFSET); + status = cdns_uart_readl(CDNS_UART_CR_OFFSET); /* Set the TX enable bit and clear the TX disable bit to enable the * transmitter. */ - xuartps_writel((status & ~XUARTPS_CR_TX_DIS) | XUARTPS_CR_TX_EN, - XUARTPS_CR_OFFSET); - - while (numbytes-- && ((xuartps_readl(XUARTPS_SR_OFFSET) - & XUARTPS_SR_TXFULL)) != XUARTPS_SR_TXFULL) { + cdns_uart_writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, + CDNS_UART_CR_OFFSET); + while (numbytes-- && ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_TXFULL)) != CDNS_UART_SR_TXFULL) { /* Break if no more data available in the UART buffer */ if (uart_circ_empty(&port->state->xmit)) break; /* Get the data from the UART circular buffer and - * write it to the xuartps's TX_FIFO register. + * write it to the cdns_uart's TX_FIFO register. */ - xuartps_writel( + cdns_uart_writel( port->state->xmit.buf[port->state->xmit.tail], - XUARTPS_FIFO_OFFSET); + CDNS_UART_FIFO_OFFSET); port->icount.tx++; /* Adjust the tail of the UART buffer and wrap @@ -551,94 +535,90 @@ static void xuartps_start_tx(struct uart_port *port) port->state->xmit.tail = (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1); } - xuartps_writel(XUARTPS_IXR_TXEMPTY, XUARTPS_ISR_OFFSET); + cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_ISR_OFFSET); /* Enable the TX Empty interrupt */ - xuartps_writel(XUARTPS_IXR_TXEMPTY, XUARTPS_IER_OFFSET); + cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_IER_OFFSET); if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS) uart_write_wakeup(port); } /** - * xuartps_stop_tx - Stop TX + * cdns_uart_stop_tx - Stop TX * @port: Handle to the uart port structure - * - **/ -static void xuartps_stop_tx(struct uart_port *port) + */ +static void cdns_uart_stop_tx(struct uart_port *port) { unsigned int regval; - regval = xuartps_readl(XUARTPS_CR_OFFSET); - regval |= XUARTPS_CR_TX_DIS; + regval = cdns_uart_readl(CDNS_UART_CR_OFFSET); + regval |= CDNS_UART_CR_TX_DIS; /* Disable the transmitter */ - xuartps_writel(regval, XUARTPS_CR_OFFSET); + cdns_uart_writel(regval, CDNS_UART_CR_OFFSET); } /** - * xuartps_stop_rx - Stop RX + * cdns_uart_stop_rx - Stop RX * @port: Handle to the uart port structure - * - **/ -static void xuartps_stop_rx(struct uart_port *port) + */ +static void cdns_uart_stop_rx(struct uart_port *port) { unsigned int regval; - regval = xuartps_readl(XUARTPS_CR_OFFSET); - regval |= XUARTPS_CR_RX_DIS; + regval = cdns_uart_readl(CDNS_UART_CR_OFFSET); + regval |= CDNS_UART_CR_RX_DIS; /* Disable the receiver */ - xuartps_writel(regval, XUARTPS_CR_OFFSET); + cdns_uart_writel(regval, CDNS_UART_CR_OFFSET); } /** - * xuartps_tx_empty - Check whether TX is empty + * cdns_uart_tx_empty - Check whether TX is empty * @port: Handle to the uart port structure * - * Returns TIOCSER_TEMT on success, 0 otherwise - **/ -static unsigned int xuartps_tx_empty(struct uart_port *port) + * Return: TIOCSER_TEMT on success, 0 otherwise + */ +static unsigned int cdns_uart_tx_empty(struct uart_port *port) { unsigned int status; - status = xuartps_readl(XUARTPS_ISR_OFFSET) & XUARTPS_IXR_TXEMPTY; + status = cdns_uart_readl(CDNS_UART_ISR_OFFSET) & CDNS_UART_IXR_TXEMPTY; return status ? TIOCSER_TEMT : 0; } /** - * xuartps_break_ctl - Based on the input ctl we have to start or stop + * cdns_uart_break_ctl - Based on the input ctl we have to start or stop * transmitting char breaks * @port: Handle to the uart port structure * @ctl: Value based on which start or stop decision is taken - * - **/ -static void xuartps_break_ctl(struct uart_port *port, int ctl) + */ +static void cdns_uart_break_ctl(struct uart_port *port, int ctl) { unsigned int status; unsigned long flags; spin_lock_irqsave(&port->lock, flags); - status = xuartps_readl(XUARTPS_CR_OFFSET); + status = cdns_uart_readl(CDNS_UART_CR_OFFSET); if (ctl == -1) - xuartps_writel(XUARTPS_CR_STARTBRK | status, - XUARTPS_CR_OFFSET); + cdns_uart_writel(CDNS_UART_CR_STARTBRK | status, + CDNS_UART_CR_OFFSET); else { - if ((status & XUARTPS_CR_STOPBRK) == 0) - xuartps_writel(XUARTPS_CR_STOPBRK | status, - XUARTPS_CR_OFFSET); + if ((status & CDNS_UART_CR_STOPBRK) == 0) + cdns_uart_writel(CDNS_UART_CR_STOPBRK | status, + CDNS_UART_CR_OFFSET); } spin_unlock_irqrestore(&port->lock, flags); } /** - * xuartps_set_termios - termios operations, handling data length, parity, + * cdns_uart_set_termios - termios operations, handling data length, parity, * stop bits, flow control, baud rate * @port: Handle to the uart port structure * @termios: Handle to the input termios structure * @old: Values of the previously saved termios structure - * - **/ -static void xuartps_set_termios(struct uart_port *port, + */ +static void cdns_uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned int cval = 0; @@ -649,81 +629,79 @@ static void xuartps_set_termios(struct uart_port *port, spin_lock_irqsave(&port->lock, flags); /* Empty the receive FIFO 1st before making changes */ - while ((xuartps_readl(XUARTPS_SR_OFFSET) & - XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) { - xuartps_readl(XUARTPS_FIFO_OFFSET); + while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) { + cdns_uart_readl(CDNS_UART_FIFO_OFFSET); } /* Disable the TX and RX to set baud rate */ - xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | - (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS), - XUARTPS_CR_OFFSET); + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); /* * Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk * min and max baud should be calculated here based on port->uartclk. * this way we get a valid baud and can safely call set_baud() */ - minbaud = port->uartclk / ((XUARTPS_BDIV_MAX + 1) * XUARTPS_CD_MAX * 8); - maxbaud = port->uartclk / (XUARTPS_BDIV_MIN + 1); + minbaud = port->uartclk / + ((CDNS_UART_BDIV_MAX + 1) * CDNS_UART_CD_MAX * 8); + maxbaud = port->uartclk / (CDNS_UART_BDIV_MIN + 1); baud = uart_get_baud_rate(port, termios, old, minbaud, maxbaud); - baud = xuartps_set_baud_rate(port, baud); + baud = cdns_uart_set_baud_rate(port, baud); if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); - /* - * Update the per-port timeout. - */ + /* Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); /* Set TX/RX Reset */ - xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | - (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), - XUARTPS_CR_OFFSET); + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); - ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); - - /* Clear the RX disable and TX disable bits and then set the TX enable + /* + * Clear the RX disable and TX disable bits and then set the TX enable * bit and RX enable bit to enable the transmitter and receiver. */ - xuartps_writel( - (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) - | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), - XUARTPS_CR_OFFSET); + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); + ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); - xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); + cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); - port->read_status_mask = XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXTRIG | - XUARTPS_IXR_OVERRUN | XUARTPS_IXR_TOUT; + port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG | + CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT; port->ignore_status_mask = 0; if (termios->c_iflag & INPCK) - port->read_status_mask |= XUARTPS_IXR_PARITY | - XUARTPS_IXR_FRAMING; + port->read_status_mask |= CDNS_UART_IXR_PARITY | + CDNS_UART_IXR_FRAMING; if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= XUARTPS_IXR_PARITY | - XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN; + port->ignore_status_mask |= CDNS_UART_IXR_PARITY | + CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN; /* ignore all characters if CREAD is not set */ if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= XUARTPS_IXR_RXTRIG | - XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY | - XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN; + port->ignore_status_mask |= CDNS_UART_IXR_RXTRIG | + CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY | + CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN; - mode_reg = xuartps_readl(XUARTPS_MR_OFFSET); + mode_reg = cdns_uart_readl(CDNS_UART_MR_OFFSET); /* Handling Data Size */ switch (termios->c_cflag & CSIZE) { case CS6: - cval |= XUARTPS_MR_CHARLEN_6_BIT; + cval |= CDNS_UART_MR_CHARLEN_6_BIT; break; case CS7: - cval |= XUARTPS_MR_CHARLEN_7_BIT; + cval |= CDNS_UART_MR_CHARLEN_7_BIT; break; default: case CS8: - cval |= XUARTPS_MR_CHARLEN_8_BIT; + cval |= CDNS_UART_MR_CHARLEN_8_BIT; termios->c_cflag &= ~CSIZE; termios->c_cflag |= CS8; break; @@ -731,134 +709,135 @@ static void xuartps_set_termios(struct uart_port *port, /* Handling Parity and Stop Bits length */ if (termios->c_cflag & CSTOPB) - cval |= XUARTPS_MR_STOPMODE_2_BIT; /* 2 STOP bits */ + cval |= CDNS_UART_MR_STOPMODE_2_BIT; /* 2 STOP bits */ else - cval |= XUARTPS_MR_STOPMODE_1_BIT; /* 1 STOP bit */ + cval |= CDNS_UART_MR_STOPMODE_1_BIT; /* 1 STOP bit */ if (termios->c_cflag & PARENB) { /* Mark or Space parity */ if (termios->c_cflag & CMSPAR) { if (termios->c_cflag & PARODD) - cval |= XUARTPS_MR_PARITY_MARK; + cval |= CDNS_UART_MR_PARITY_MARK; else - cval |= XUARTPS_MR_PARITY_SPACE; + cval |= CDNS_UART_MR_PARITY_SPACE; } else { if (termios->c_cflag & PARODD) - cval |= XUARTPS_MR_PARITY_ODD; + cval |= CDNS_UART_MR_PARITY_ODD; else - cval |= XUARTPS_MR_PARITY_EVEN; + cval |= CDNS_UART_MR_PARITY_EVEN; } } else { - cval |= XUARTPS_MR_PARITY_NONE; + cval |= CDNS_UART_MR_PARITY_NONE; } cval |= mode_reg & 1; - xuartps_writel(cval, XUARTPS_MR_OFFSET); + cdns_uart_writel(cval, CDNS_UART_MR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } /** - * xuartps_startup - Called when an application opens a xuartps port + * cdns_uart_startup - Called when an application opens a cdns_uart port * @port: Handle to the uart port structure * - * Returns 0 on success, negative error otherwise - **/ -static int xuartps_startup(struct uart_port *port) + * Return: 0 on success, negative errno otherwise + */ +static int cdns_uart_startup(struct uart_port *port) { unsigned int retval = 0, status = 0; - retval = request_irq(port->irq, xuartps_isr, 0, XUARTPS_NAME, + retval = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, (void *)port); if (retval) return retval; /* Disable the TX and RX */ - xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS, - XUARTPS_CR_OFFSET); + cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, + CDNS_UART_CR_OFFSET); /* Set the Control Register with TX/RX Enable, TX/RX Reset, * no break chars. */ - xuartps_writel(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST, - XUARTPS_CR_OFFSET); + cdns_uart_writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST, + CDNS_UART_CR_OFFSET); - status = xuartps_readl(XUARTPS_CR_OFFSET); + status = cdns_uart_readl(CDNS_UART_CR_OFFSET); /* Clear the RX disable and TX disable bits and then set the TX enable * bit and RX enable bit to enable the transmitter and receiver. */ - xuartps_writel((status & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) - | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN | - XUARTPS_CR_STOPBRK), XUARTPS_CR_OFFSET); + cdns_uart_writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS)) + | (CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN | + CDNS_UART_CR_STOPBRK), CDNS_UART_CR_OFFSET); /* Set the Mode Register with normal mode,8 data bits,1 stop bit, * no parity. */ - xuartps_writel(XUARTPS_MR_CHMODE_NORM | XUARTPS_MR_STOPMODE_1_BIT - | XUARTPS_MR_PARITY_NONE | XUARTPS_MR_CHARLEN_8_BIT, - XUARTPS_MR_OFFSET); + cdns_uart_writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT + | CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT, + CDNS_UART_MR_OFFSET); /* * Set the RX FIFO Trigger level to use most of the FIFO, but it * can be tuned with a module parameter */ - xuartps_writel(rx_trigger_level, XUARTPS_RXWM_OFFSET); + cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET); /* * Receive Timeout register is enabled but it * can be tuned with a module parameter */ - xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); + cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); /* Clear out any pending interrupts before enabling them */ - xuartps_writel(xuartps_readl(XUARTPS_ISR_OFFSET), XUARTPS_ISR_OFFSET); + cdns_uart_writel(cdns_uart_readl(CDNS_UART_ISR_OFFSET), + CDNS_UART_ISR_OFFSET); /* Set the Interrupt Registers with desired interrupts */ - xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY | - XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN | - XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET); + cdns_uart_writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY | + CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN | + CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT, + CDNS_UART_IER_OFFSET); return retval; } /** - * xuartps_shutdown - Called when an application closes a xuartps port + * cdns_uart_shutdown - Called when an application closes a cdns_uart port * @port: Handle to the uart port structure - * - **/ -static void xuartps_shutdown(struct uart_port *port) + */ +static void cdns_uart_shutdown(struct uart_port *port) { int status; /* Disable interrupts */ - status = xuartps_readl(XUARTPS_IMR_OFFSET); - xuartps_writel(status, XUARTPS_IDR_OFFSET); + status = cdns_uart_readl(CDNS_UART_IMR_OFFSET); + cdns_uart_writel(status, CDNS_UART_IDR_OFFSET); /* Disable the TX and RX */ - xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS, - XUARTPS_CR_OFFSET); + cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, + CDNS_UART_CR_OFFSET); free_irq(port->irq, port); } /** - * xuartps_type - Set UART type to xuartps port + * cdns_uart_type - Set UART type to cdns_uart port * @port: Handle to the uart port structure * - * Returns string on success, NULL otherwise - **/ -static const char *xuartps_type(struct uart_port *port) + * Return: string on success, NULL otherwise + */ +static const char *cdns_uart_type(struct uart_port *port) { - return port->type == PORT_XUARTPS ? XUARTPS_NAME : NULL; + return port->type == PORT_XUARTPS ? CDNS_UART_NAME : NULL; } /** - * xuartps_verify_port - Verify the port params + * cdns_uart_verify_port - Verify the port params * @port: Handle to the uart port structure * @ser: Handle to the structure whose members are compared * - * Returns 0 if success otherwise -EINVAL - **/ -static int xuartps_verify_port(struct uart_port *port, + * Return: 0 on success, negative errno otherwise. + */ +static int cdns_uart_verify_port(struct uart_port *port, struct serial_struct *ser) { if (ser->type != PORT_UNKNOWN && ser->type != PORT_XUARTPS) @@ -875,187 +854,170 @@ static int xuartps_verify_port(struct uart_port *port, } /** - * xuartps_request_port - Claim the memory region attached to xuartps port, - * called when the driver adds a xuartps port via + * cdns_uart_request_port - Claim the memory region attached to cdns_uart port, + * called when the driver adds a cdns_uart port via * uart_add_one_port() * @port: Handle to the uart port structure * - * Returns 0, -ENOMEM if request fails - **/ -static int xuartps_request_port(struct uart_port *port) + * Return: 0 on success, negative errno otherwise. + */ +static int cdns_uart_request_port(struct uart_port *port) { - if (!request_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE, - XUARTPS_NAME)) { + if (!request_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE, + CDNS_UART_NAME)) { return -ENOMEM; } - port->membase = ioremap(port->mapbase, XUARTPS_REGISTER_SPACE); + port->membase = ioremap(port->mapbase, CDNS_UART_REGISTER_SPACE); if (!port->membase) { dev_err(port->dev, "Unable to map registers\n"); - release_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE); + release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE); return -ENOMEM; } return 0; } /** - * xuartps_release_port - Release the memory region attached to a xuartps - * port, called when the driver removes a xuartps - * port via uart_remove_one_port(). + * cdns_uart_release_port - Release UART port * @port: Handle to the uart port structure * - **/ -static void xuartps_release_port(struct uart_port *port) + * Release the memory region attached to a cdns_uart port. Called when the + * driver removes a cdns_uart port via uart_remove_one_port(). + */ +static void cdns_uart_release_port(struct uart_port *port) { - release_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE); + release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE); iounmap(port->membase); port->membase = NULL; } /** - * xuartps_config_port - Configure xuartps, called when the driver adds a - * xuartps port + * cdns_uart_config_port - Configure UART port * @port: Handle to the uart port structure * @flags: If any - * - **/ -static void xuartps_config_port(struct uart_port *port, int flags) + */ +static void cdns_uart_config_port(struct uart_port *port, int flags) { - if (flags & UART_CONFIG_TYPE && xuartps_request_port(port) == 0) + if (flags & UART_CONFIG_TYPE && cdns_uart_request_port(port) == 0) port->type = PORT_XUARTPS; } /** - * xuartps_get_mctrl - Get the modem control state - * + * cdns_uart_get_mctrl - Get the modem control state * @port: Handle to the uart port structure * - * Returns the modem control state - * - **/ -static unsigned int xuartps_get_mctrl(struct uart_port *port) + * Return: the modem control state + */ +static unsigned int cdns_uart_get_mctrl(struct uart_port *port) { return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; } -static void xuartps_set_mctrl(struct uart_port *port, unsigned int mctrl) +static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { /* N/A */ } -static void xuartps_enable_ms(struct uart_port *port) +static void cdns_uart_enable_ms(struct uart_port *port) { /* N/A */ } #ifdef CONFIG_CONSOLE_POLL -static int xuartps_poll_get_char(struct uart_port *port) +static int cdns_uart_poll_get_char(struct uart_port *port) { u32 imr; int c; /* Disable all interrupts */ - imr = xuartps_readl(XUARTPS_IMR_OFFSET); - xuartps_writel(imr, XUARTPS_IDR_OFFSET); + imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); + cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); /* Check if FIFO is empty */ - if (xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY) + if (cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY) c = NO_POLL_CHAR; else /* Read a character */ - c = (unsigned char) xuartps_readl(XUARTPS_FIFO_OFFSET); + c = (unsigned char) cdns_uart_readl(CDNS_UART_FIFO_OFFSET); /* Enable interrupts */ - xuartps_writel(imr, XUARTPS_IER_OFFSET); + cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); return c; } -static void xuartps_poll_put_char(struct uart_port *port, unsigned char c) +static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) { u32 imr; /* Disable all interrupts */ - imr = xuartps_readl(XUARTPS_IMR_OFFSET); - xuartps_writel(imr, XUARTPS_IDR_OFFSET); + imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); + cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); /* Wait until FIFO is empty */ - while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY)) + while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)) cpu_relax(); /* Write a character */ - xuartps_writel(c, XUARTPS_FIFO_OFFSET); + cdns_uart_writel(c, CDNS_UART_FIFO_OFFSET); /* Wait until FIFO is empty */ - while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY)) + while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)) cpu_relax(); /* Enable interrupts */ - xuartps_writel(imr, XUARTPS_IER_OFFSET); + cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); return; } #endif -/** The UART operations structure - */ -static struct uart_ops xuartps_ops = { - .set_mctrl = xuartps_set_mctrl, - .get_mctrl = xuartps_get_mctrl, - .enable_ms = xuartps_enable_ms, - - .start_tx = xuartps_start_tx, /* Start transmitting */ - .stop_tx = xuartps_stop_tx, /* Stop transmission */ - .stop_rx = xuartps_stop_rx, /* Stop reception */ - .tx_empty = xuartps_tx_empty, /* Transmitter busy? */ - .break_ctl = xuartps_break_ctl, /* Start/stop - * transmitting break - */ - .set_termios = xuartps_set_termios, /* Set termios */ - .startup = xuartps_startup, /* App opens xuartps */ - .shutdown = xuartps_shutdown, /* App closes xuartps */ - .type = xuartps_type, /* Set UART type */ - .verify_port = xuartps_verify_port, /* Verification of port - * params - */ - .request_port = xuartps_request_port, /* Claim resources - * associated with a - * xuartps port - */ - .release_port = xuartps_release_port, /* Release resources - * associated with a - * xuartps port - */ - .config_port = xuartps_config_port, /* Configure when driver - * adds a xuartps port - */ +static struct uart_ops cdns_uart_ops = { + .set_mctrl = cdns_uart_set_mctrl, + .get_mctrl = cdns_uart_get_mctrl, + .enable_ms = cdns_uart_enable_ms, + .start_tx = cdns_uart_start_tx, + .stop_tx = cdns_uart_stop_tx, + .stop_rx = cdns_uart_stop_rx, + .tx_empty = cdns_uart_tx_empty, + .break_ctl = cdns_uart_break_ctl, + .set_termios = cdns_uart_set_termios, + .startup = cdns_uart_startup, + .shutdown = cdns_uart_shutdown, + .type = cdns_uart_type, + .verify_port = cdns_uart_verify_port, + .request_port = cdns_uart_request_port, + .release_port = cdns_uart_release_port, + .config_port = cdns_uart_config_port, #ifdef CONFIG_CONSOLE_POLL - .poll_get_char = xuartps_poll_get_char, - .poll_put_char = xuartps_poll_put_char, + .poll_get_char = cdns_uart_poll_get_char, + .poll_put_char = cdns_uart_poll_put_char, #endif }; -static struct uart_port xuartps_port[2]; +static struct uart_port cdns_uart_port[2]; /** - * xuartps_get_port - Configure the port from the platform device resource - * info + * cdns_uart_get_port - Configure the port from platform device resource info + * @id: Port id * - * Returns a pointer to a uart_port or NULL for failure - **/ -static struct uart_port *xuartps_get_port(void) + * Return: a pointer to a uart_port or NULL for failure + */ +static struct uart_port *cdns_uart_get_port(int id) { struct uart_port *port; - int id; - /* Find the next unused port */ - for (id = 0; id < XUARTPS_NR_PORTS; id++) - if (xuartps_port[id].mapbase == 0) - break; + /* Try the given port id if failed use default method */ + if (cdns_uart_port[id].mapbase != 0) { + /* Find the next unused port */ + for (id = 0; id < CDNS_UART_NR_PORTS; id++) + if (cdns_uart_port[id].mapbase == 0) + break; + } - if (id >= XUARTPS_NR_PORTS) + if (id >= CDNS_UART_NR_PORTS) return NULL; - port = &xuartps_port[id]; + port = &cdns_uart_port[id]; /* At this point, we've got an empty uart_port struct, initialize it */ spin_lock_init(&port->lock); @@ -1065,50 +1027,46 @@ static struct uart_port *xuartps_get_port(void) port->type = PORT_UNKNOWN; port->iotype = UPIO_MEM32; port->flags = UPF_BOOT_AUTOCONF; - port->ops = &xuartps_ops; - port->fifosize = XUARTPS_FIFO_SIZE; + port->ops = &cdns_uart_ops; + port->fifosize = CDNS_UART_FIFO_SIZE; port->line = id; port->dev = NULL; return port; } -/*-----------------------Console driver operations--------------------------*/ - #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE /** - * xuartps_console_wait_tx - Wait for the TX to be full + * cdns_uart_console_wait_tx - Wait for the TX to be full * @port: Handle to the uart port structure - * - **/ -static void xuartps_console_wait_tx(struct uart_port *port) + */ +static void cdns_uart_console_wait_tx(struct uart_port *port) { - while ((xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY) - != XUARTPS_SR_TXEMPTY) + while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY) + != CDNS_UART_SR_TXEMPTY) barrier(); } /** - * xuartps_console_putchar - write the character to the FIFO buffer + * cdns_uart_console_putchar - write the character to the FIFO buffer * @port: Handle to the uart port structure * @ch: Character to be written - * - **/ -static void xuartps_console_putchar(struct uart_port *port, int ch) + */ +static void cdns_uart_console_putchar(struct uart_port *port, int ch) { - xuartps_console_wait_tx(port); - xuartps_writel(ch, XUARTPS_FIFO_OFFSET); + cdns_uart_console_wait_tx(port); + cdns_uart_writel(ch, CDNS_UART_FIFO_OFFSET); } /** - * xuartps_console_write - perform write operation - * @port: Handle to the uart port structure + * cdns_uart_console_write - perform write operation + * @co: Console handle * @s: Pointer to character array * @count: No of characters - **/ -static void xuartps_console_write(struct console *co, const char *s, + */ +static void cdns_uart_console_write(struct console *co, const char *s, unsigned int count) { - struct uart_port *port = &xuartps_port[co->index]; + struct uart_port *port = &cdns_uart_port[co->index]; unsigned long flags; unsigned int imr, ctrl; int locked = 1; @@ -1119,49 +1077,45 @@ static void xuartps_console_write(struct console *co, const char *s, spin_lock_irqsave(&port->lock, flags); /* save and disable interrupt */ - imr = xuartps_readl(XUARTPS_IMR_OFFSET); - xuartps_writel(imr, XUARTPS_IDR_OFFSET); + imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); + cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); /* * Make sure that the tx part is enabled. Set the TX enable bit and * clear the TX disable bit to enable the transmitter. */ - ctrl = xuartps_readl(XUARTPS_CR_OFFSET); - xuartps_writel((ctrl & ~XUARTPS_CR_TX_DIS) | XUARTPS_CR_TX_EN, - XUARTPS_CR_OFFSET); + ctrl = cdns_uart_readl(CDNS_UART_CR_OFFSET); + cdns_uart_writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, + CDNS_UART_CR_OFFSET); - uart_console_write(port, s, count, xuartps_console_putchar); - xuartps_console_wait_tx(port); + uart_console_write(port, s, count, cdns_uart_console_putchar); + cdns_uart_console_wait_tx(port); - xuartps_writel(ctrl, XUARTPS_CR_OFFSET); + cdns_uart_writel(ctrl, CDNS_UART_CR_OFFSET); - /* restore interrupt state, it seems like there may be a h/w bug - * in that the interrupt enable register should not need to be - * written based on the data sheet - */ - xuartps_writel(~imr, XUARTPS_IDR_OFFSET); - xuartps_writel(imr, XUARTPS_IER_OFFSET); + /* restore interrupt state */ + cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); if (locked) spin_unlock_irqrestore(&port->lock, flags); } /** - * xuartps_console_setup - Initialize the uart to default config + * cdns_uart_console_setup - Initialize the uart to default config * @co: Console handle * @options: Initial settings of uart * - * Returns 0, -ENODEV if no device - **/ -static int __init xuartps_console_setup(struct console *co, char *options) + * Return: 0 on success, negative errno otherwise. + */ +static int __init cdns_uart_console_setup(struct console *co, char *options) { - struct uart_port *port = &xuartps_port[co->index]; + struct uart_port *port = &cdns_uart_port[co->index]; int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n'; - if (co->index < 0 || co->index >= XUARTPS_NR_PORTS) + if (co->index < 0 || co->index >= CDNS_UART_NR_PORTS) return -EINVAL; if (!port->mapbase) { @@ -1175,55 +1129,53 @@ static int __init xuartps_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -static struct uart_driver xuartps_uart_driver; +static struct uart_driver cdns_uart_uart_driver; -static struct console xuartps_console = { - .name = XUARTPS_TTY_NAME, - .write = xuartps_console_write, +static struct console cdns_uart_console = { + .name = CDNS_UART_TTY_NAME, + .write = cdns_uart_console_write, .device = uart_console_device, - .setup = xuartps_console_setup, + .setup = cdns_uart_console_setup, .flags = CON_PRINTBUFFER, .index = -1, /* Specified on the cmdline (e.g. console=ttyPS ) */ - .data = &xuartps_uart_driver, + .data = &cdns_uart_uart_driver, }; /** - * xuartps_console_init - Initialization call + * cdns_uart_console_init - Initialization call * - * Returns 0 on success, negative error otherwise - **/ -static int __init xuartps_console_init(void) + * Return: 0 on success, negative errno otherwise + */ +static int __init cdns_uart_console_init(void) { - register_console(&xuartps_console); + register_console(&cdns_uart_console); return 0; } -console_initcall(xuartps_console_init); +console_initcall(cdns_uart_console_init); #endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */ -/** Structure Definitions - */ -static struct uart_driver xuartps_uart_driver = { - .owner = THIS_MODULE, /* Owner */ - .driver_name = XUARTPS_NAME, /* Driver name */ - .dev_name = XUARTPS_TTY_NAME, /* Node name */ - .major = XUARTPS_MAJOR, /* Major number */ - .minor = XUARTPS_MINOR, /* Minor number */ - .nr = XUARTPS_NR_PORTS, /* Number of UART ports */ +static struct uart_driver cdns_uart_uart_driver = { + .owner = THIS_MODULE, + .driver_name = CDNS_UART_NAME, + .dev_name = CDNS_UART_TTY_NAME, + .major = CDNS_UART_MAJOR, + .minor = CDNS_UART_MINOR, + .nr = CDNS_UART_NR_PORTS, #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE - .cons = &xuartps_console, /* Console */ + .cons = &cdns_uart_console, #endif }; #ifdef CONFIG_PM_SLEEP /** - * xuartps_suspend - suspend event + * cdns_uart_suspend - suspend event * @device: Pointer to the device structure * - * Returns 0 + * Return: 0 */ -static int xuartps_suspend(struct device *device) +static int cdns_uart_suspend(struct device *device) { struct uart_port *port = dev_get_drvdata(device); struct tty_struct *tty; @@ -1242,23 +1194,24 @@ static int xuartps_suspend(struct device *device) * Call the API provided in serial_core.c file which handles * the suspend. */ - uart_suspend_port(&xuartps_uart_driver, port); + uart_suspend_port(&cdns_uart_uart_driver, port); if (console_suspend_enabled && !may_wake) { - struct xuartps *xuartps = port->private_data; + struct cdns_uart *cdns_uart = port->private_data; - clk_disable(xuartps->refclk); - clk_disable(xuartps->aperclk); + clk_disable(cdns_uart->uartclk); + clk_disable(cdns_uart->pclk); } else { unsigned long flags = 0; spin_lock_irqsave(&port->lock, flags); /* Empty the receive FIFO 1st before making changes */ - while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY)) - xuartps_readl(XUARTPS_FIFO_OFFSET); + while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_RXEMPTY)) + cdns_uart_readl(CDNS_UART_FIFO_OFFSET); /* set RX trigger level to 1 */ - xuartps_writel(1, XUARTPS_RXWM_OFFSET); + cdns_uart_writel(1, CDNS_UART_RXWM_OFFSET); /* disable RX timeout interrups */ - xuartps_writel(XUARTPS_IXR_TOUT, XUARTPS_IDR_OFFSET); + cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IDR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } @@ -1266,12 +1219,12 @@ static int xuartps_suspend(struct device *device) } /** - * xuartps_resume - Resume after a previous suspend + * cdns_uart_resume - Resume after a previous suspend * @device: Pointer to the device structure * - * Returns 0 + * Return: 0 */ -static int xuartps_resume(struct device *device) +static int cdns_uart_resume(struct device *device) { struct uart_port *port = dev_get_drvdata(device); unsigned long flags = 0; @@ -1289,87 +1242,95 @@ static int xuartps_resume(struct device *device) } if (console_suspend_enabled && !may_wake) { - struct xuartps *xuartps = port->private_data; + struct cdns_uart *cdns_uart = port->private_data; - clk_enable(xuartps->aperclk); - clk_enable(xuartps->refclk); + clk_enable(cdns_uart->pclk); + clk_enable(cdns_uart->uartclk); spin_lock_irqsave(&port->lock, flags); /* Set TX/RX Reset */ - xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | - (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), - XUARTPS_CR_OFFSET); - while (xuartps_readl(XUARTPS_CR_OFFSET) & - (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST)) + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + while (cdns_uart_readl(CDNS_UART_CR_OFFSET) & + (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) cpu_relax(); /* restore rx timeout value */ - xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); + cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); /* Enable Tx/Rx */ - ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); - xuartps_writel( - (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) | - (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), - XUARTPS_CR_OFFSET); + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); + ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } else { spin_lock_irqsave(&port->lock, flags); /* restore original rx trigger level */ - xuartps_writel(rx_trigger_level, XUARTPS_RXWM_OFFSET); + cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET); /* enable RX timeout interrupt */ - xuartps_writel(XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET); + cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IER_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } - return uart_resume_port(&xuartps_uart_driver, port); + return uart_resume_port(&cdns_uart_uart_driver, port); } #endif /* ! CONFIG_PM_SLEEP */ -static SIMPLE_DEV_PM_OPS(xuartps_dev_pm_ops, xuartps_suspend, xuartps_resume); +static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend, + cdns_uart_resume); -/* --------------------------------------------------------------------- - * Platform bus binding - */ /** - * xuartps_probe - Platform driver probe + * cdns_uart_probe - Platform driver probe * @pdev: Pointer to the platform device structure * - * Returns 0 on success, negative error otherwise - **/ -static int xuartps_probe(struct platform_device *pdev) + * Return: 0 on success, negative errno otherwise + */ +static int cdns_uart_probe(struct platform_device *pdev) { - int rc; + int rc, id; struct uart_port *port; struct resource *res, *res2; - struct xuartps *xuartps_data; + struct cdns_uart *cdns_uart_data; - xuartps_data = devm_kzalloc(&pdev->dev, sizeof(*xuartps_data), + cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data), GFP_KERNEL); - if (!xuartps_data) + if (!cdns_uart_data) return -ENOMEM; - xuartps_data->aperclk = devm_clk_get(&pdev->dev, "aper_clk"); - if (IS_ERR(xuartps_data->aperclk)) { - dev_err(&pdev->dev, "aper_clk clock not found.\n"); - return PTR_ERR(xuartps_data->aperclk); + cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(cdns_uart_data->pclk)) { + cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk"); + if (!IS_ERR(cdns_uart_data->pclk)) + dev_err(&pdev->dev, "clock name 'aper_clk' is deprecated.\n"); } - xuartps_data->refclk = devm_clk_get(&pdev->dev, "ref_clk"); - if (IS_ERR(xuartps_data->refclk)) { - dev_err(&pdev->dev, "ref_clk clock not found.\n"); - return PTR_ERR(xuartps_data->refclk); + if (IS_ERR(cdns_uart_data->pclk)) { + dev_err(&pdev->dev, "pclk clock not found.\n"); + return PTR_ERR(cdns_uart_data->pclk); } - rc = clk_prepare_enable(xuartps_data->aperclk); + cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk"); + if (IS_ERR(cdns_uart_data->uartclk)) { + cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "ref_clk"); + if (!IS_ERR(cdns_uart_data->uartclk)) + dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n"); + } + if (IS_ERR(cdns_uart_data->uartclk)) { + dev_err(&pdev->dev, "uart_clk clock not found.\n"); + return PTR_ERR(cdns_uart_data->uartclk); + } + + rc = clk_prepare_enable(cdns_uart_data->pclk); if (rc) { - dev_err(&pdev->dev, "Unable to enable APER clock.\n"); + dev_err(&pdev->dev, "Unable to enable pclk clock.\n"); return rc; } - rc = clk_prepare_enable(xuartps_data->refclk); + rc = clk_prepare_enable(cdns_uart_data->uartclk); if (rc) { dev_err(&pdev->dev, "Unable to enable device clock.\n"); - goto err_out_clk_dis_aper; + goto err_out_clk_dis_pclk; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1385,15 +1346,19 @@ static int xuartps_probe(struct platform_device *pdev) } #ifdef CONFIG_COMMON_CLK - xuartps_data->clk_rate_change_nb.notifier_call = - xuartps_clk_notifier_cb; - if (clk_notifier_register(xuartps_data->refclk, - &xuartps_data->clk_rate_change_nb)) + cdns_uart_data->clk_rate_change_nb.notifier_call = + cdns_uart_clk_notifier_cb; + if (clk_notifier_register(cdns_uart_data->uartclk, + &cdns_uart_data->clk_rate_change_nb)) dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); #endif + /* Look for a serialN alias */ + id = of_alias_get_id(pdev->dev.of_node, "serial"); + if (id < 0) + id = 0; /* Initialize the port structure */ - port = xuartps_get_port(); + port = cdns_uart_get_port(id); if (!port) { dev_err(&pdev->dev, "Cannot get uart_port structure\n"); @@ -1407,11 +1372,11 @@ static int xuartps_probe(struct platform_device *pdev) port->mapbase = res->start; port->irq = res2->start; port->dev = &pdev->dev; - port->uartclk = clk_get_rate(xuartps_data->refclk); - port->private_data = xuartps_data; - xuartps_data->port = port; + port->uartclk = clk_get_rate(cdns_uart_data->uartclk); + port->private_data = cdns_uart_data; + cdns_uart_data->port = port; platform_set_drvdata(pdev, port); - rc = uart_add_one_port(&xuartps_uart_driver, port); + rc = uart_add_one_port(&cdns_uart_uart_driver, port); if (rc) { dev_err(&pdev->dev, "uart_add_one_port() failed; err=%i\n", rc); @@ -1422,103 +1387,89 @@ static int xuartps_probe(struct platform_device *pdev) err_out_notif_unreg: #ifdef CONFIG_COMMON_CLK - clk_notifier_unregister(xuartps_data->refclk, - &xuartps_data->clk_rate_change_nb); + clk_notifier_unregister(cdns_uart_data->uartclk, + &cdns_uart_data->clk_rate_change_nb); #endif err_out_clk_disable: - clk_disable_unprepare(xuartps_data->refclk); -err_out_clk_dis_aper: - clk_disable_unprepare(xuartps_data->aperclk); + clk_disable_unprepare(cdns_uart_data->uartclk); +err_out_clk_dis_pclk: + clk_disable_unprepare(cdns_uart_data->pclk); return rc; } /** - * xuartps_remove - called when the platform driver is unregistered + * cdns_uart_remove - called when the platform driver is unregistered * @pdev: Pointer to the platform device structure * - * Returns 0 on success, negative error otherwise - **/ -static int xuartps_remove(struct platform_device *pdev) + * Return: 0 on success, negative errno otherwise + */ +static int cdns_uart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); - struct xuartps *xuartps_data = port->private_data; + struct cdns_uart *cdns_uart_data = port->private_data; int rc; - /* Remove the xuartps port from the serial core */ + /* Remove the cdns_uart port from the serial core */ #ifdef CONFIG_COMMON_CLK - clk_notifier_unregister(xuartps_data->refclk, - &xuartps_data->clk_rate_change_nb); + clk_notifier_unregister(cdns_uart_data->uartclk, + &cdns_uart_data->clk_rate_change_nb); #endif - rc = uart_remove_one_port(&xuartps_uart_driver, port); + rc = uart_remove_one_port(&cdns_uart_uart_driver, port); port->mapbase = 0; - clk_disable_unprepare(xuartps_data->refclk); - clk_disable_unprepare(xuartps_data->aperclk); + clk_disable_unprepare(cdns_uart_data->uartclk); + clk_disable_unprepare(cdns_uart_data->pclk); return rc; } /* Match table for of_platform binding */ -static struct of_device_id xuartps_of_match[] = { +static struct of_device_id cdns_uart_of_match[] = { { .compatible = "xlnx,xuartps", }, + { .compatible = "cdns,uart-r1p8", }, {} }; -MODULE_DEVICE_TABLE(of, xuartps_of_match); +MODULE_DEVICE_TABLE(of, cdns_uart_of_match); -static struct platform_driver xuartps_platform_driver = { - .probe = xuartps_probe, /* Probe method */ - .remove = xuartps_remove, /* Detach method */ +static struct platform_driver cdns_uart_platform_driver = { + .probe = cdns_uart_probe, + .remove = cdns_uart_remove, .driver = { .owner = THIS_MODULE, - .name = XUARTPS_NAME, /* Driver name */ - .of_match_table = xuartps_of_match, - .pm = &xuartps_dev_pm_ops, + .name = CDNS_UART_NAME, + .of_match_table = cdns_uart_of_match, + .pm = &cdns_uart_dev_pm_ops, }, }; -/* --------------------------------------------------------------------- - * Module Init and Exit - */ -/** - * xuartps_init - Initial driver registration call - * - * Returns whether the registration was successful or not - **/ -static int __init xuartps_init(void) +static int __init cdns_uart_init(void) { int retval = 0; - /* Register the xuartps driver with the serial core */ - retval = uart_register_driver(&xuartps_uart_driver); + /* Register the cdns_uart driver with the serial core */ + retval = uart_register_driver(&cdns_uart_uart_driver); if (retval) return retval; /* Register the platform driver */ - retval = platform_driver_register(&xuartps_platform_driver); + retval = platform_driver_register(&cdns_uart_platform_driver); if (retval) - uart_unregister_driver(&xuartps_uart_driver); + uart_unregister_driver(&cdns_uart_uart_driver); return retval; } -/** - * xuartps_exit - Driver unregistration call - **/ -static void __exit xuartps_exit(void) +static void __exit cdns_uart_exit(void) { - /* The order of unregistration is important. Unregister the - * UART driver before the platform driver crashes the system. - */ - /* Unregister the platform driver */ - platform_driver_unregister(&xuartps_platform_driver); + platform_driver_unregister(&cdns_uart_platform_driver); - /* Unregister the xuartps driver */ - uart_unregister_driver(&xuartps_uart_driver); + /* Unregister the cdns_uart driver */ + uart_unregister_driver(&cdns_uart_uart_driver); } -module_init(xuartps_init); -module_exit(xuartps_exit); +module_init(cdns_uart_init); +module_exit(cdns_uart_exit); -MODULE_DESCRIPTION("Driver for PS UART"); +MODULE_DESCRIPTION("Driver for Cadence UART"); MODULE_AUTHOR("Xilinx Inc."); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 480bd4d5710ae5..2f099c7df7b558 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -6,6 +6,7 @@ ci_hdrc-y := core.o otg.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST) += host.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o +ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o # Glue/Bridge layers go here diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index 83d06c1455b7bd..ca57e3dcd3d57b 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -44,9 +44,14 @@ #define DEVICEADDR_USBADR (0x7FUL << 25) /* PORTSC */ +#define PORTSC_CCS BIT(0) +#define PORTSC_CSC BIT(1) +#define PORTSC_PEC BIT(3) +#define PORTSC_OCC BIT(5) #define PORTSC_FPR BIT(6) #define PORTSC_SUSP BIT(7) #define PORTSC_HSP BIT(9) +#define PORTSC_PP BIT(12) #define PORTSC_PTC (0x0FUL << 16) #define PORTSC_PHCD(d) ((d) ? BIT(22) : BIT(23)) /* PTS and PTW for non lpm version only */ @@ -56,6 +61,9 @@ #define PORTSC_PTW BIT(28) #define PORTSC_STS BIT(29) +#define PORTSC_W1C_BITS \ + (PORTSC_CSC | PORTSC_PEC | PORTSC_OCC) + /* DEVLC */ #define DEVLC_PFSC BIT(23) #define DEVLC_PSPD (0x03UL << 25) @@ -72,6 +80,8 @@ /* OTGSC */ #define OTGSC_IDPU BIT(5) +#define OTGSC_HADP BIT(6) +#define OTGSC_HABA BIT(7) #define OTGSC_ID BIT(8) #define OTGSC_AVV BIT(9) #define OTGSC_ASV BIT(10) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index e206406ae1d955..9563cb56d56430 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -17,6 +17,7 @@ #include #include #include +#include /****************************************************************************** * DEFINE @@ -139,6 +140,8 @@ struct hw_bank { * @roles: array of supported roles for this controller * @role: current role * @is_otg: if the device is otg-capable + * @fsm: otg finite state machine + * @fsm_timer: pointer to timer list of otg fsm * @work: work for role changing * @wq: workqueue thread * @qh_pool: allocation pool for queue heads @@ -174,6 +177,8 @@ struct ci_hdrc { struct ci_role_driver *roles[CI_ROLE_END]; enum ci_role role; bool is_otg; + struct otg_fsm fsm; + struct ci_otg_fsm_timer_list *fsm_timer; struct work_struct work; struct workqueue_struct *wq; @@ -319,6 +324,24 @@ static inline u32 hw_test_and_write(struct ci_hdrc *ci, enum ci_hw_regs reg, return (val & mask) >> __ffs(mask); } +/** + * ci_otg_is_fsm_mode: runtime check if otg controller + * is in otg fsm mode. + */ +static inline bool ci_otg_is_fsm_mode(struct ci_hdrc *ci) +{ +#ifdef CONFIG_USB_OTG_FSM + return ci->is_otg && ci->roles[CI_ROLE_HOST] && + ci->roles[CI_ROLE_GADGET]; +#else + return false; +#endif +} + +u32 hw_read_intr_enable(struct ci_hdrc *ci); + +u32 hw_read_intr_status(struct ci_hdrc *ci); + int hw_device_reset(struct ci_hdrc *ci, u32 mode); int hw_port_test_set(struct ci_hdrc *ci, u8 mode); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 1cd5d0ba587c8e..128b92ba58a80c 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -42,7 +42,6 @@ * - Not Supported: 15 & 16 (ISO) * * TODO List - * - OTG * - Interrupt Traffic * - GET_STATUS(device) - always reports 0 * - Gadget API (majority of optional features) @@ -74,6 +73,7 @@ #include "host.h" #include "debug.h" #include "otg.h" +#include "otg_fsm.h" /* Controller register map */ static const u8 ci_regs_nolpm[] = { @@ -139,6 +139,26 @@ static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm) return 0; } +/** + * hw_read_intr_enable: returns interrupt enable register + * + * This function returns register data + */ +u32 hw_read_intr_enable(struct ci_hdrc *ci) +{ + return hw_read(ci, OP_USBINTR, ~0); +} + +/** + * hw_read_intr_status: returns interrupt status register + * + * This function returns register data + */ +u32 hw_read_intr_status(struct ci_hdrc *ci) +{ + return hw_read(ci, OP_USBSTS, ~0); +} + /** * hw_port_test_set: writes port test mode (execute without interruption) * @mode: new value @@ -179,11 +199,10 @@ static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable) hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), 0); /* - * The controller needs at least 1ms to reflect - * PHY's status, the PHY also needs some time (less + * the PHY needs some time (less * than 1ms) to leave low power mode. */ - usleep_range(1500, 2000); + usleep_range(1000, 1100); } } @@ -392,8 +411,14 @@ static irqreturn_t ci_irq(int irq, void *data) irqreturn_t ret = IRQ_NONE; u32 otgsc = 0; - if (ci->is_otg) - otgsc = hw_read(ci, OP_OTGSC, ~0); + if (ci->is_otg) { + otgsc = hw_read_otgsc(ci, ~0); + if (ci_otg_is_fsm_mode(ci)) { + ret = ci_otg_fsm_irq(ci); + if (ret == IRQ_HANDLED) + return ret; + } + } /* * Handle id change interrupt, it indicates device/host function @@ -401,7 +426,8 @@ static irqreturn_t ci_irq(int irq, void *data) */ if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) { ci->id_event = true; - ci_clear_otg_interrupt(ci, OTGSC_IDIS); + /* Clear ID change irq status */ + hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS); disable_irq_nosync(ci->irq); queue_work(ci->wq, &ci->work); return IRQ_HANDLED; @@ -413,7 +439,8 @@ static irqreturn_t ci_irq(int irq, void *data) */ if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) { ci->b_sess_valid_event = true; - ci_clear_otg_interrupt(ci, OTGSC_BSVIS); + /* Clear BSV irq */ + hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS); disable_irq_nosync(ci->irq); queue_work(ci->wq, &ci->work); return IRQ_HANDLED; @@ -533,11 +560,8 @@ static void ci_get_otg_capable(struct ci_hdrc *ci) ci->is_otg = (hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC | DCCPARAMS_HC) == (DCCPARAMS_DC | DCCPARAMS_HC)); - if (ci->is_otg) { + if (ci->is_otg) dev_dbg(ci->dev, "It is OTG capable controller\n"); - ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS); - ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS); - } } static int ci_hdrc_probe(struct platform_device *pdev) @@ -599,6 +623,13 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "unable to init phy: %d\n", ret); return ret; + } else { + /* + * The delay to sync PHY's status, the maximum delay is + * 2ms since the otgsc uses 1ms timer to debounce the + * PHY's input + */ + usleep_range(2000, 2500); } ci->hw_bank.phys = res->start; @@ -633,6 +664,9 @@ static int ci_hdrc_probe(struct platform_device *pdev) } if (ci->is_otg) { + /* Disable and clear all OTG irq */ + hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS, + OTGSC_INT_STATUS_BITS); ret = ci_hdrc_otg_init(ci); if (ret) { dev_err(dev, "init otg fails, ret = %d\n", ret); @@ -642,13 +676,9 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { if (ci->is_otg) { - /* - * ID pin needs 1ms debouce time, - * we delay 2ms for safe. - */ - mdelay(2); ci->role = ci_otg_role(ci); - ci_enable_otg_interrupt(ci, OTGSC_IDIE); + /* Enable ID change irq */ + hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE); } else { /* * If the controller is not OTG capable, but support @@ -667,10 +697,13 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ci->role == CI_ROLE_GADGET) ci_handle_vbus_change(ci); - ret = ci_role_start(ci, ci->role); - if (ret) { - dev_err(dev, "can't start %s role\n", ci_role(ci)->name); - goto stop; + if (!ci_otg_is_fsm_mode(ci)) { + ret = ci_role_start(ci, ci->role); + if (ret) { + dev_err(dev, "can't start %s role\n", + ci_role(ci)->name); + goto stop; + } } platform_set_drvdata(pdev, ci); @@ -679,6 +712,9 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) goto stop; + if (ci_otg_is_fsm_mode(ci)) + ci_hdrc_otg_fsm_start(ci); + ret = dbg_create_files(ci); if (!ret) return 0; @@ -711,6 +747,7 @@ static struct platform_driver ci_hdrc_driver = { .remove = ci_hdrc_remove, .driver = { .name = "ci_hdrc", + .owner = THIS_MODULE, }, }; diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index 96d899aee473b9..7cccab6ff3081e 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -7,11 +7,15 @@ #include #include #include +#include +#include +#include #include "ci.h" #include "udc.h" #include "bits.h" #include "debug.h" +#include "otg.h" /** * ci_device_show: prints information about device capabilities and status @@ -204,6 +208,80 @@ static const struct file_operations ci_requests_fops = { .release = single_release, }; +int ci_otg_show(struct seq_file *s, void *unused) +{ + struct ci_hdrc *ci = s->private; + struct otg_fsm *fsm; + + if (!ci || !ci_otg_is_fsm_mode(ci)) + return 0; + + fsm = &ci->fsm; + + /* ------ State ----- */ + seq_printf(s, "OTG state: %s\n\n", + usb_otg_state_string(ci->transceiver->state)); + + /* ------ State Machine Variables ----- */ + seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop); + + seq_printf(s, "a_bus_req: %d\n", fsm->a_bus_req); + + seq_printf(s, "a_srp_det: %d\n", fsm->a_srp_det); + + seq_printf(s, "a_vbus_vld: %d\n", fsm->a_vbus_vld); + + seq_printf(s, "b_conn: %d\n", fsm->b_conn); + + seq_printf(s, "adp_change: %d\n", fsm->adp_change); + + seq_printf(s, "power_up: %d\n", fsm->power_up); + + seq_printf(s, "a_bus_resume: %d\n", fsm->a_bus_resume); + + seq_printf(s, "a_bus_suspend: %d\n", fsm->a_bus_suspend); + + seq_printf(s, "a_conn: %d\n", fsm->a_conn); + + seq_printf(s, "b_bus_req: %d\n", fsm->b_bus_req); + + seq_printf(s, "b_bus_suspend: %d\n", fsm->b_bus_suspend); + + seq_printf(s, "b_se0_srp: %d\n", fsm->b_se0_srp); + + seq_printf(s, "b_ssend_srp: %d\n", fsm->b_ssend_srp); + + seq_printf(s, "b_sess_vld: %d\n", fsm->b_sess_vld); + + seq_printf(s, "b_srp_done: %d\n", fsm->b_srp_done); + + seq_printf(s, "drv_vbus: %d\n", fsm->drv_vbus); + + seq_printf(s, "loc_conn: %d\n", fsm->loc_conn); + + seq_printf(s, "loc_sof: %d\n", fsm->loc_sof); + + seq_printf(s, "adp_prb: %d\n", fsm->adp_prb); + + seq_printf(s, "id: %d\n", fsm->id); + + seq_printf(s, "protocol: %d\n", fsm->protocol); + + return 0; +} + +static int ci_otg_open(struct inode *inode, struct file *file) +{ + return single_open(file, ci_otg_show, inode->i_private); +} + +static const struct file_operations ci_otg_fops = { + .open = ci_otg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int ci_role_show(struct seq_file *s, void *data) { struct ci_hdrc *ci = s->private; @@ -253,6 +331,50 @@ static const struct file_operations ci_role_fops = { .release = single_release, }; +int ci_registers_show(struct seq_file *s, void *unused) +{ + struct ci_hdrc *ci = s->private; + u32 tmp_reg; + + if (!ci) + return 0; + + /* ------ Registers ----- */ + tmp_reg = hw_read_intr_enable(ci); + seq_printf(s, "USBINTR reg: %08x\n", tmp_reg); + + tmp_reg = hw_read_intr_status(ci); + seq_printf(s, "USBSTS reg: %08x\n", tmp_reg); + + tmp_reg = hw_read(ci, OP_USBMODE, ~0); + seq_printf(s, "USBMODE reg: %08x\n", tmp_reg); + + tmp_reg = hw_read(ci, OP_USBCMD, ~0); + seq_printf(s, "USBCMD reg: %08x\n", tmp_reg); + + tmp_reg = hw_read(ci, OP_PORTSC, ~0); + seq_printf(s, "PORTSC reg: %08x\n", tmp_reg); + + if (ci->is_otg) { + tmp_reg = hw_read_otgsc(ci, ~0); + seq_printf(s, "OTGSC reg: %08x\n", tmp_reg); + } + + return 0; +} + +static int ci_registers_open(struct inode *inode, struct file *file) +{ + return single_open(file, ci_registers_show, inode->i_private); +} + +static const struct file_operations ci_registers_fops = { + .open = ci_registers_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /** * dbg_create_files: initializes the attribute interface * @ci: device @@ -287,8 +409,21 @@ int dbg_create_files(struct ci_hdrc *ci) if (!dent) goto err; + if (ci_otg_is_fsm_mode(ci)) { + dent = debugfs_create_file("otg", S_IRUGO, ci->debugfs, ci, + &ci_otg_fops); + if (!dent) + goto err; + } + dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci, &ci_role_fops); + if (!dent) + goto err; + + dent = debugfs_create_file("registers", S_IRUGO, ci->debugfs, ci, + &ci_registers_fops); + if (dent) return 0; err: diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index a8ac6c16dac928..a93d950e9468bd 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -67,7 +67,11 @@ static int host_start(struct ci_hdrc *ci) ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; ehci->imx28_write_fix = ci->imx28_write_fix; - if (ci->platdata->reg_vbus) { + /* + * vbus is always on if host is not in OTG FSM mode, + * otherwise should be controlled by OTG FSM + */ + if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) { ret = regulator_enable(ci->platdata->reg_vbus); if (ret) { dev_err(ci->dev, @@ -78,10 +82,17 @@ static int host_start(struct ci_hdrc *ci) } ret = usb_add_hcd(hcd, 0, 0); - if (ret) + if (ret) { goto disable_reg; - else + } else { + struct usb_otg *otg = ci->transceiver->otg; + ci->hcd = hcd; + if (otg) { + otg->host = &hcd->self; + hcd->self.otg_port = 1; + } + } if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING) hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); @@ -89,7 +100,7 @@ static int host_start(struct ci_hdrc *ci) return ret; disable_reg: - if (ci->platdata->reg_vbus) + if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) regulator_disable(ci->platdata->reg_vbus); put_hcd: @@ -105,7 +116,7 @@ static void host_stop(struct ci_hdrc *ci) if (hcd) { usb_remove_hcd(hcd); usb_put_hcd(hcd); - if (ci->platdata->reg_vbus) + if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) regulator_disable(ci->platdata->reg_vbus); } } diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 39bd7ec8bf75f5..a048b08b9d4dbb 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -11,8 +11,8 @@ */ /* - * This file mainly handles otgsc register, it may include OTG operation - * in the future. + * This file mainly handles otgsc register, OTG fsm operations for HNP and SRP + * are also included. */ #include @@ -22,6 +22,26 @@ #include "ci.h" #include "bits.h" #include "otg.h" +#include "otg_fsm.h" + +/** + * hw_read_otgsc returns otgsc register bits value. + * @mask: bitfield mask + */ +u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) +{ + return hw_read(ci, OP_OTGSC, mask); +} + +/** + * hw_write_otgsc updates target bits of OTGSC register. + * @mask: bitfield mask + * @data: to be written + */ +void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data) +{ + hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data); +} /** * ci_otg_role - pick role based on ID pin state @@ -29,8 +49,7 @@ */ enum ci_role ci_otg_role(struct ci_hdrc *ci) { - u32 sts = hw_read(ci, OP_OTGSC, ~0); - enum ci_role role = sts & OTGSC_ID + enum ci_role role = hw_read_otgsc(ci, OTGSC_ID) ? CI_ROLE_GADGET : CI_ROLE_HOST; @@ -39,14 +58,10 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci) void ci_handle_vbus_change(struct ci_hdrc *ci) { - u32 otgsc; - if (!ci->is_otg) return; - otgsc = hw_read(ci, OP_OTGSC, ~0); - - if (otgsc & OTGSC_BSV) + if (hw_read_otgsc(ci, OTGSC_BSV)) usb_gadget_vbus_connect(&ci->gadget); else usb_gadget_vbus_disconnect(&ci->gadget); @@ -76,6 +91,11 @@ static void ci_otg_work(struct work_struct *work) { struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); + if (ci_otg_is_fsm_mode(ci) && !ci_otg_fsm_work(ci)) { + enable_irq(ci->irq); + return; + } + if (ci->id_event) { ci->id_event = false; ci_handle_id_switch(ci); @@ -102,6 +122,9 @@ int ci_hdrc_otg_init(struct ci_hdrc *ci) return -ENODEV; } + if (ci_otg_is_fsm_mode(ci)) + return ci_hdrc_otg_fsm_init(ci); + return 0; } @@ -115,6 +138,9 @@ void ci_hdrc_otg_destroy(struct ci_hdrc *ci) flush_workqueue(ci->wq); destroy_workqueue(ci->wq); } - ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS); - ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS); + /* Disable all OTG irq and clear status */ + hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS, + OTGSC_INT_STATUS_BITS); + if (ci_otg_is_fsm_mode(ci)) + ci_hdrc_otg_fsm_remove(ci); } diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h index 449bee07f4fe00..7349267541130c 100644 --- a/drivers/usb/chipidea/otg.h +++ b/drivers/usb/chipidea/otg.h @@ -11,22 +11,8 @@ #ifndef __DRIVERS_USB_CHIPIDEA_OTG_H #define __DRIVERS_USB_CHIPIDEA_OTG_H -static inline void ci_clear_otg_interrupt(struct ci_hdrc *ci, u32 bits) -{ - /* Only clear request bits */ - hw_write(ci, OP_OTGSC, OTGSC_INT_STATUS_BITS, bits); -} - -static inline void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits) -{ - hw_write(ci, OP_OTGSC, bits | OTGSC_INT_STATUS_BITS, bits); -} - -static inline void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits) -{ - hw_write(ci, OP_OTGSC, bits | OTGSC_INT_STATUS_BITS, 0); -} - +u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask); +void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data); int ci_hdrc_otg_init(struct ci_hdrc *ci); void ci_hdrc_otg_destroy(struct ci_hdrc *ci); enum ci_role ci_otg_role(struct ci_hdrc *ci); diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c new file mode 100644 index 00000000000000..8d4c33dea12ef3 --- /dev/null +++ b/drivers/usb/chipidea/otg_fsm.c @@ -0,0 +1,865 @@ +/* + * otg_fsm.c - ChipIdea USB IP core OTG FSM driver + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Jun Li + * + * 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 file mainly handles OTG fsm, it includes OTG fsm operations + * for HNP and SRP. + * + * TODO List + * - ADP + * - OTG test device + */ + +#include +#include +#include +#include +#include + +#include "ci.h" +#include "bits.h" +#include "otg.h" +#include "otg_fsm.h" + +static struct ci_otg_fsm_timer *otg_timer_initializer +(struct ci_hdrc *ci, void (*function)(void *, unsigned long), + unsigned long expires, unsigned long data) +{ + struct ci_otg_fsm_timer *timer; + + timer = devm_kzalloc(ci->dev, sizeof(struct ci_otg_fsm_timer), + GFP_KERNEL); + if (!timer) + return NULL; + timer->function = function; + timer->expires = expires; + timer->data = data; + return timer; +} + +/* Add for otg: interact with user space app */ +static ssize_t +get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ + char *next; + unsigned size, t; + struct ci_hdrc *ci = dev_get_drvdata(dev); + + next = buf; + size = PAGE_SIZE; + t = scnprintf(next, size, "%d\n", ci->fsm.a_bus_req); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_a_bus_req(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + + if (count > 2) + return -1; + + mutex_lock(&ci->fsm.lock); + if (buf[0] == '0') { + ci->fsm.a_bus_req = 0; + } else if (buf[0] == '1') { + /* If a_bus_drop is TRUE, a_bus_req can't be set */ + if (ci->fsm.a_bus_drop) { + mutex_unlock(&ci->fsm.lock); + return count; + } + ci->fsm.a_bus_req = 1; + } + + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + mutex_unlock(&ci->fsm.lock); + + return count; +} +static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req); + +static ssize_t +get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf) +{ + char *next; + unsigned size, t; + struct ci_hdrc *ci = dev_get_drvdata(dev); + + next = buf; + size = PAGE_SIZE; + t = scnprintf(next, size, "%d\n", ci->fsm.a_bus_drop); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_a_bus_drop(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + + if (count > 2) + return -1; + + mutex_lock(&ci->fsm.lock); + if (buf[0] == '0') { + ci->fsm.a_bus_drop = 0; + } else if (buf[0] == '1') { + ci->fsm.a_bus_drop = 1; + ci->fsm.a_bus_req = 0; + } + + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + mutex_unlock(&ci->fsm.lock); + + return count; +} +static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop, + set_a_bus_drop); + +static ssize_t +get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ + char *next; + unsigned size, t; + struct ci_hdrc *ci = dev_get_drvdata(dev); + + next = buf; + size = PAGE_SIZE; + t = scnprintf(next, size, "%d\n", ci->fsm.b_bus_req); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_b_bus_req(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + + if (count > 2) + return -1; + + mutex_lock(&ci->fsm.lock); + if (buf[0] == '0') + ci->fsm.b_bus_req = 0; + else if (buf[0] == '1') + ci->fsm.b_bus_req = 1; + + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + mutex_unlock(&ci->fsm.lock); + + return count; +} +static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req); + +static ssize_t +set_a_clr_err(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + + if (count > 2) + return -1; + + mutex_lock(&ci->fsm.lock); + if (buf[0] == '1') + ci->fsm.a_clr_err = 1; + + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + mutex_unlock(&ci->fsm.lock); + + return count; +} +static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err); + +static struct attribute *inputs_attrs[] = { + &dev_attr_a_bus_req.attr, + &dev_attr_a_bus_drop.attr, + &dev_attr_b_bus_req.attr, + &dev_attr_a_clr_err.attr, + NULL, +}; + +static struct attribute_group inputs_attr_group = { + .name = "inputs", + .attrs = inputs_attrs, +}; + +/* + * Add timer to active timer list + */ +static void ci_otg_add_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t) +{ + struct ci_otg_fsm_timer *tmp_timer; + struct ci_otg_fsm_timer *timer = ci->fsm_timer->timer_list[t]; + struct list_head *active_timers = &ci->fsm_timer->active_timers; + + if (t >= NUM_CI_OTG_FSM_TIMERS) + return; + + /* + * Check if the timer is already in the active list, + * if so update timer count + */ + list_for_each_entry(tmp_timer, active_timers, list) + if (tmp_timer == timer) { + timer->count = timer->expires; + return; + } + + timer->count = timer->expires; + list_add_tail(&timer->list, active_timers); + + /* Enable 1ms irq */ + if (!(hw_read_otgsc(ci, OTGSC_1MSIE))) + hw_write_otgsc(ci, OTGSC_1MSIE, OTGSC_1MSIE); +} + +/* + * Remove timer from active timer list + */ +static void ci_otg_del_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t) +{ + struct ci_otg_fsm_timer *tmp_timer, *del_tmp; + struct ci_otg_fsm_timer *timer = ci->fsm_timer->timer_list[t]; + struct list_head *active_timers = &ci->fsm_timer->active_timers; + + if (t >= NUM_CI_OTG_FSM_TIMERS) + return; + + list_for_each_entry_safe(tmp_timer, del_tmp, active_timers, list) + if (tmp_timer == timer) + list_del(&timer->list); + + /* Disable 1ms irq if there is no any active timer */ + if (list_empty(active_timers)) + hw_write_otgsc(ci, OTGSC_1MSIE, 0); +} + +/* + * Reduce timer count by 1, and find timeout conditions. + * Called by otg 1ms timer interrupt + */ +static inline int ci_otg_tick_timer(struct ci_hdrc *ci) +{ + struct ci_otg_fsm_timer *tmp_timer, *del_tmp; + struct list_head *active_timers = &ci->fsm_timer->active_timers; + int expired = 0; + + list_for_each_entry_safe(tmp_timer, del_tmp, active_timers, list) { + tmp_timer->count--; + /* check if timer expires */ + if (!tmp_timer->count) { + list_del(&tmp_timer->list); + tmp_timer->function(ci, tmp_timer->data); + expired = 1; + } + } + + /* disable 1ms irq if there is no any timer active */ + if ((expired == 1) && list_empty(active_timers)) + hw_write_otgsc(ci, OTGSC_1MSIE, 0); + + return expired; +} + +/* The timeout callback function to set time out bit */ +static void set_tmout(void *ptr, unsigned long indicator) +{ + *(int *)indicator = 1; +} + +static void set_tmout_and_fsm(void *ptr, unsigned long indicator) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + + set_tmout(ci, indicator); + + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); +} + +static void a_wait_vfall_tmout_func(void *ptr, unsigned long indicator) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + + set_tmout(ci, indicator); + /* Disable port power */ + hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, 0); + /* Clear exsiting DP irq */ + hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS); + /* Enable data pulse irq */ + hw_write_otgsc(ci, OTGSC_DPIE, OTGSC_DPIE); + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); +} + +static void b_ase0_brst_tmout_func(void *ptr, unsigned long indicator) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + + set_tmout(ci, indicator); + if (!hw_read_otgsc(ci, OTGSC_BSV)) + ci->fsm.b_sess_vld = 0; + + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); +} + +static void b_ssend_srp_tmout_func(void *ptr, unsigned long indicator) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + + set_tmout(ci, indicator); + + /* only vbus fall below B_sess_vld in b_idle state */ + if (ci->transceiver->state == OTG_STATE_B_IDLE) { + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + } +} + +static void b_sess_vld_tmout_func(void *ptr, unsigned long indicator) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + + /* Check if A detached */ + if (!(hw_read_otgsc(ci, OTGSC_BSV))) { + ci->fsm.b_sess_vld = 0; + ci_otg_add_timer(ci, B_SSEND_SRP); + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + } +} + +static void b_data_pulse_end(void *ptr, unsigned long indicator) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + + ci->fsm.b_srp_done = 1; + ci->fsm.b_bus_req = 0; + if (ci->fsm.power_up) + ci->fsm.power_up = 0; + + hw_write_otgsc(ci, OTGSC_HABA, 0); + + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); +} + +/* Initialize timers */ +static int ci_otg_init_timers(struct ci_hdrc *ci) +{ + struct otg_fsm *fsm = &ci->fsm; + + /* FSM used timers */ + ci->fsm_timer->timer_list[A_WAIT_VRISE] = + otg_timer_initializer(ci, &set_tmout_and_fsm, TA_WAIT_VRISE, + (unsigned long)&fsm->a_wait_vrise_tmout); + if (ci->fsm_timer->timer_list[A_WAIT_VRISE] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[A_WAIT_VFALL] = + otg_timer_initializer(ci, &a_wait_vfall_tmout_func, + TA_WAIT_VFALL, (unsigned long)&fsm->a_wait_vfall_tmout); + if (ci->fsm_timer->timer_list[A_WAIT_VFALL] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[A_WAIT_BCON] = + otg_timer_initializer(ci, &set_tmout_and_fsm, TA_WAIT_BCON, + (unsigned long)&fsm->a_wait_bcon_tmout); + if (ci->fsm_timer->timer_list[A_WAIT_BCON] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[A_AIDL_BDIS] = + otg_timer_initializer(ci, &set_tmout_and_fsm, TA_AIDL_BDIS, + (unsigned long)&fsm->a_aidl_bdis_tmout); + if (ci->fsm_timer->timer_list[A_AIDL_BDIS] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[A_BIDL_ADIS] = + otg_timer_initializer(ci, &set_tmout_and_fsm, TA_BIDL_ADIS, + (unsigned long)&fsm->a_bidl_adis_tmout); + if (ci->fsm_timer->timer_list[A_BIDL_ADIS] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[B_ASE0_BRST] = + otg_timer_initializer(ci, &b_ase0_brst_tmout_func, TB_ASE0_BRST, + (unsigned long)&fsm->b_ase0_brst_tmout); + if (ci->fsm_timer->timer_list[B_ASE0_BRST] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[B_SE0_SRP] = + otg_timer_initializer(ci, &set_tmout_and_fsm, TB_SE0_SRP, + (unsigned long)&fsm->b_se0_srp); + if (ci->fsm_timer->timer_list[B_SE0_SRP] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[B_SSEND_SRP] = + otg_timer_initializer(ci, &b_ssend_srp_tmout_func, TB_SSEND_SRP, + (unsigned long)&fsm->b_ssend_srp); + if (ci->fsm_timer->timer_list[B_SSEND_SRP] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[B_SRP_FAIL] = + otg_timer_initializer(ci, &set_tmout, TB_SRP_FAIL, + (unsigned long)&fsm->b_srp_done); + if (ci->fsm_timer->timer_list[B_SRP_FAIL] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[B_DATA_PLS] = + otg_timer_initializer(ci, &b_data_pulse_end, TB_DATA_PLS, 0); + if (ci->fsm_timer->timer_list[B_DATA_PLS] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[B_SESS_VLD] = otg_timer_initializer(ci, + &b_sess_vld_tmout_func, TB_SESS_VLD, 0); + if (ci->fsm_timer->timer_list[B_SESS_VLD] == NULL) + return -ENOMEM; + + return 0; +} + +/* -------------------------------------------------------------*/ +/* Operations that will be called from OTG Finite State Machine */ +/* -------------------------------------------------------------*/ +static void ci_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + if (t < NUM_OTG_FSM_TIMERS) + ci_otg_add_timer(ci, t); + return; +} + +static void ci_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + if (t < NUM_OTG_FSM_TIMERS) + ci_otg_del_timer(ci, t); + return; +} + +/* + * A-device drive vbus: turn on vbus regulator and enable port power + * Data pulse irq should be disabled while vbus is on. + */ +static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on) +{ + int ret; + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + if (on) { + /* Enable power power */ + hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, + PORTSC_PP); + if (ci->platdata->reg_vbus) { + ret = regulator_enable(ci->platdata->reg_vbus); + if (ret) { + dev_err(ci->dev, + "Failed to enable vbus regulator, ret=%d\n", + ret); + return; + } + } + /* Disable data pulse irq */ + hw_write_otgsc(ci, OTGSC_DPIE, 0); + + fsm->a_srp_det = 0; + fsm->power_up = 0; + } else { + if (ci->platdata->reg_vbus) + regulator_disable(ci->platdata->reg_vbus); + + fsm->a_bus_drop = 1; + fsm->a_bus_req = 0; + } +} + +/* + * Control data line by Run Stop bit. + */ +static void ci_otg_loc_conn(struct otg_fsm *fsm, int on) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + if (on) + hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS); + else + hw_write(ci, OP_USBCMD, USBCMD_RS, 0); +} + +/* + * Generate SOF by host. + * This is controlled through suspend/resume the port. + * In host mode, controller will automatically send SOF. + * Suspend will block the data on the port. + */ +static void ci_otg_loc_sof(struct otg_fsm *fsm, int on) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + if (on) + hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_FPR, + PORTSC_FPR); + else + hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_SUSP, + PORTSC_SUSP); +} + +/* + * Start SRP pulsing by data-line pulsing, + * no v-bus pulsing followed + */ +static void ci_otg_start_pulse(struct otg_fsm *fsm) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + /* Hardware Assistant Data pulse */ + hw_write_otgsc(ci, OTGSC_HADP, OTGSC_HADP); + + ci_otg_add_timer(ci, B_DATA_PLS); +} + +static int ci_otg_start_host(struct otg_fsm *fsm, int on) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + mutex_unlock(&fsm->lock); + if (on) { + ci_role_stop(ci); + ci_role_start(ci, CI_ROLE_HOST); + } else { + ci_role_stop(ci); + hw_device_reset(ci, USBMODE_CM_DC); + ci_role_start(ci, CI_ROLE_GADGET); + } + mutex_lock(&fsm->lock); + return 0; +} + +static int ci_otg_start_gadget(struct otg_fsm *fsm, int on) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + mutex_unlock(&fsm->lock); + if (on) + usb_gadget_vbus_connect(&ci->gadget); + else + usb_gadget_vbus_disconnect(&ci->gadget); + mutex_lock(&fsm->lock); + + return 0; +} + +static struct otg_fsm_ops ci_otg_ops = { + .drv_vbus = ci_otg_drv_vbus, + .loc_conn = ci_otg_loc_conn, + .loc_sof = ci_otg_loc_sof, + .start_pulse = ci_otg_start_pulse, + .add_timer = ci_otg_fsm_add_timer, + .del_timer = ci_otg_fsm_del_timer, + .start_host = ci_otg_start_host, + .start_gadget = ci_otg_start_gadget, +}; + +int ci_otg_fsm_work(struct ci_hdrc *ci) +{ + /* + * Don't do fsm transition for B device + * when there is no gadget class driver + */ + if (ci->fsm.id && !(ci->driver) && + ci->transceiver->state < OTG_STATE_A_IDLE) + return 0; + + if (otg_statemachine(&ci->fsm)) { + if (ci->transceiver->state == OTG_STATE_A_IDLE) { + /* + * Further state change for cases: + * a_idle to b_idle; or + * a_idle to a_wait_vrise due to ID change(1->0), so + * B-dev becomes A-dev can try to start new session + * consequently; or + * a_idle to a_wait_vrise when power up + */ + if ((ci->fsm.id) || (ci->id_event) || + (ci->fsm.power_up)) { + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + } + if (ci->id_event) + ci->id_event = false; + } else if (ci->transceiver->state == OTG_STATE_B_IDLE) { + if (ci->fsm.b_sess_vld) { + ci->fsm.power_up = 0; + /* + * Further transite to b_periphearl state + * when register gadget driver with vbus on + */ + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + } + } + } + return 0; +} + +/* + * Update fsm variables in each state if catching expected interrupts, + * called by otg fsm isr. + */ +static void ci_otg_fsm_event(struct ci_hdrc *ci) +{ + u32 intr_sts, otg_bsess_vld, port_conn; + struct otg_fsm *fsm = &ci->fsm; + + intr_sts = hw_read_intr_status(ci); + otg_bsess_vld = hw_read_otgsc(ci, OTGSC_BSV); + port_conn = hw_read(ci, OP_PORTSC, PORTSC_CCS); + + switch (ci->transceiver->state) { + case OTG_STATE_A_WAIT_BCON: + if (port_conn) { + fsm->b_conn = 1; + fsm->a_bus_req = 1; + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + } + break; + case OTG_STATE_B_IDLE: + if (otg_bsess_vld && (intr_sts & USBi_PCI) && port_conn) { + fsm->b_sess_vld = 1; + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + } + break; + case OTG_STATE_B_PERIPHERAL: + if ((intr_sts & USBi_SLI) && port_conn && otg_bsess_vld) { + fsm->a_bus_suspend = 1; + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + } else if (intr_sts & USBi_PCI) { + if (fsm->a_bus_suspend == 1) + fsm->a_bus_suspend = 0; + } + break; + case OTG_STATE_B_HOST: + if ((intr_sts & USBi_PCI) && !port_conn) { + fsm->a_conn = 0; + fsm->b_bus_req = 0; + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + ci_otg_add_timer(ci, B_SESS_VLD); + } + break; + case OTG_STATE_A_PERIPHERAL: + if (intr_sts & USBi_SLI) { + fsm->b_bus_suspend = 1; + /* + * Init a timer to know how long this suspend + * will contine, if time out, indicates B no longer + * wants to be host role + */ + ci_otg_add_timer(ci, A_BIDL_ADIS); + } + + if (intr_sts & USBi_URI) + ci_otg_del_timer(ci, A_BIDL_ADIS); + + if (intr_sts & USBi_PCI) { + if (fsm->b_bus_suspend == 1) { + ci_otg_del_timer(ci, A_BIDL_ADIS); + fsm->b_bus_suspend = 0; + } + } + break; + case OTG_STATE_A_SUSPEND: + if ((intr_sts & USBi_PCI) && !port_conn) { + fsm->b_conn = 0; + + /* if gadget driver is binded */ + if (ci->driver) { + /* A device to be peripheral mode */ + ci->gadget.is_a_peripheral = 1; + } + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + } + break; + case OTG_STATE_A_HOST: + if ((intr_sts & USBi_PCI) && !port_conn) { + fsm->b_conn = 0; + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + } + break; + case OTG_STATE_B_WAIT_ACON: + if ((intr_sts & USBi_PCI) && port_conn) { + fsm->a_conn = 1; + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + } + break; + default: + break; + } +} + +/* + * ci_otg_irq - otg fsm related irq handling + * and also update otg fsm variable by monitoring usb host and udc + * state change interrupts. + * @ci: ci_hdrc + */ +irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci) +{ + irqreturn_t retval = IRQ_NONE; + u32 otgsc, otg_int_src = 0; + struct otg_fsm *fsm = &ci->fsm; + + otgsc = hw_read_otgsc(ci, ~0); + otg_int_src = otgsc & OTGSC_INT_STATUS_BITS & (otgsc >> 8); + fsm->id = (otgsc & OTGSC_ID) ? 1 : 0; + + if (otg_int_src) { + if (otg_int_src & OTGSC_1MSIS) { + hw_write_otgsc(ci, OTGSC_1MSIS, OTGSC_1MSIS); + retval = ci_otg_tick_timer(ci); + return IRQ_HANDLED; + } else if (otg_int_src & OTGSC_DPIS) { + hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS); + fsm->a_srp_det = 1; + fsm->a_bus_drop = 0; + } else if (otg_int_src & OTGSC_IDIS) { + hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS); + if (fsm->id == 0) { + fsm->a_bus_drop = 0; + fsm->a_bus_req = 1; + ci->id_event = true; + } + } else if (otg_int_src & OTGSC_BSVIS) { + hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS); + if (otgsc & OTGSC_BSV) { + fsm->b_sess_vld = 1; + ci_otg_del_timer(ci, B_SSEND_SRP); + ci_otg_del_timer(ci, B_SRP_FAIL); + fsm->b_ssend_srp = 0; + } else { + fsm->b_sess_vld = 0; + if (fsm->id) + ci_otg_add_timer(ci, B_SSEND_SRP); + } + } else if (otg_int_src & OTGSC_AVVIS) { + hw_write_otgsc(ci, OTGSC_AVVIS, OTGSC_AVVIS); + if (otgsc & OTGSC_AVV) { + fsm->a_vbus_vld = 1; + } else { + fsm->a_vbus_vld = 0; + fsm->b_conn = 0; + } + } + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + return IRQ_HANDLED; + } + + ci_otg_fsm_event(ci); + + return retval; +} + +void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci) +{ + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); +} + +int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) +{ + int retval = 0; + struct usb_otg *otg; + + otg = devm_kzalloc(ci->dev, + sizeof(struct usb_otg), GFP_KERNEL); + if (!otg) { + dev_err(ci->dev, + "Failed to allocate usb_otg structure for ci hdrc otg!\n"); + return -ENOMEM; + } + + otg->phy = ci->transceiver; + otg->gadget = &ci->gadget; + ci->fsm.otg = otg; + ci->transceiver->otg = ci->fsm.otg; + ci->fsm.power_up = 1; + ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0; + ci->transceiver->state = OTG_STATE_UNDEFINED; + ci->fsm.ops = &ci_otg_ops; + + mutex_init(&ci->fsm.lock); + + ci->fsm_timer = devm_kzalloc(ci->dev, + sizeof(struct ci_otg_fsm_timer_list), GFP_KERNEL); + if (!ci->fsm_timer) { + dev_err(ci->dev, + "Failed to allocate timer structure for ci hdrc otg!\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&ci->fsm_timer->active_timers); + retval = ci_otg_init_timers(ci); + if (retval) { + dev_err(ci->dev, "Couldn't init OTG timers\n"); + return retval; + } + + retval = sysfs_create_group(&ci->dev->kobj, &inputs_attr_group); + if (retval < 0) { + dev_dbg(ci->dev, + "Can't register sysfs attr group: %d\n", retval); + return retval; + } + + /* Enable A vbus valid irq */ + hw_write_otgsc(ci, OTGSC_AVVIE, OTGSC_AVVIE); + + if (ci->fsm.id) { + ci->fsm.b_ssend_srp = + hw_read_otgsc(ci, OTGSC_BSV) ? 0 : 1; + ci->fsm.b_sess_vld = + hw_read_otgsc(ci, OTGSC_BSV) ? 1 : 0; + /* Enable BSV irq */ + hw_write_otgsc(ci, OTGSC_BSVIE, OTGSC_BSVIE); + } + + return 0; +} + +void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci) +{ + sysfs_remove_group(&ci->dev->kobj, &inputs_attr_group); +} diff --git a/drivers/usb/chipidea/otg_fsm.h b/drivers/usb/chipidea/otg_fsm.h new file mode 100644 index 00000000000000..94c085f456a9cd --- /dev/null +++ b/drivers/usb/chipidea/otg_fsm.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Jun Li + * + * 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 __DRIVERS_USB_CHIPIDEA_OTG_FSM_H +#define __DRIVERS_USB_CHIPIDEA_OTG_FSM_H + +#include + +/* + * A-DEVICE timing constants + */ + +/* Wait for VBUS Rise */ +#define TA_WAIT_VRISE (100) /* a_wait_vrise: section 7.1.2 + * a_wait_vrise_tmr: section 7.4.5.1 + * TA_VBUS_RISE <= 100ms, section 4.4 + * Table 4-1: Electrical Characteristics + * ->DC Electrical Timing + */ +/* Wait for VBUS Fall */ +#define TA_WAIT_VFALL (1000) /* a_wait_vfall: section 7.1.7 + * a_wait_vfall_tmr: section: 7.4.5.2 + */ +/* Wait for B-Connect */ +#define TA_WAIT_BCON (10000) /* a_wait_bcon: section 7.1.3 + * TA_WAIT_BCON: should be between 1100 + * and 30000 ms, section 5.5, Table 5-1 + */ +/* A-Idle to B-Disconnect */ +#define TA_AIDL_BDIS (5000) /* a_suspend min 200 ms, section 5.2.1 + * TA_AIDL_BDIS: section 5.5, Table 5-1 + */ +/* B-Idle to A-Disconnect */ +#define TA_BIDL_ADIS (500) /* TA_BIDL_ADIS: section 5.2.1 + * 500ms is used for B switch to host + * for safe + */ + +/* + * B-device timing constants + */ + +/* Data-Line Pulse Time*/ +#define TB_DATA_PLS (10) /* b_srp_init,continue 5~10ms + * section:5.1.3 + */ +/* SRP Fail Time */ +#define TB_SRP_FAIL (6000) /* b_srp_init,fail time 5~6s + * section:5.1.6 + */ +/* A-SE0 to B-Reset */ +#define TB_ASE0_BRST (155) /* minimum 155 ms, section:5.3.1 */ +/* SE0 Time Before SRP */ +#define TB_SE0_SRP (1000) /* b_idle,minimum 1s, section:5.1.2 */ +/* SSEND time before SRP */ +#define TB_SSEND_SRP (1500) /* minimum 1.5 sec, section:5.1.2 */ + +#define TB_SESS_VLD (1000) + +enum ci_otg_fsm_timer_index { + /* + * CI specific timers, start from the end + * of standard and auxiliary OTG timers + */ + B_DATA_PLS = NUM_OTG_FSM_TIMERS, + B_SSEND_SRP, + B_SESS_VLD, + + NUM_CI_OTG_FSM_TIMERS, +}; + +struct ci_otg_fsm_timer { + unsigned long expires; /* Number of count increase to timeout */ + unsigned long count; /* Tick counter */ + void (*function)(void *, unsigned long); /* Timeout function */ + unsigned long data; /* Data passed to function */ + struct list_head list; +}; + +struct ci_otg_fsm_timer_list { + struct ci_otg_fsm_timer *timer_list[NUM_CI_OTG_FSM_TIMERS]; + struct list_head active_timers; +}; + +#ifdef CONFIG_USB_OTG_FSM + +int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci); +int ci_otg_fsm_work(struct ci_hdrc *ci); +irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci); +void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci); +void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci); + +#else + +static inline int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) +{ + return 0; +} + +static inline int ci_otg_fsm_work(struct ci_hdrc *ci) +{ + return -ENXIO; +} + +static inline irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci) +{ + return IRQ_NONE; +} + +static inline void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci) +{ + +} + +static inline void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci) +{ + +} + +#endif + +#endif /* __DRIVERS_USB_CHIPIDEA_OTG_FSM_H */ diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 7739c64ef2590a..150592f10b3d5b 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "ci.h" @@ -27,6 +28,7 @@ #include "bits.h" #include "debug.h" #include "otg.h" +#include "otg_fsm.h" /* control endpoint description */ static const struct usb_endpoint_descriptor @@ -241,26 +243,6 @@ static int hw_port_is_high_speed(struct ci_hdrc *ci) hw_read(ci, OP_PORTSC, PORTSC_HSP); } -/** - * hw_read_intr_enable: returns interrupt enable register - * - * This function returns register data - */ -static u32 hw_read_intr_enable(struct ci_hdrc *ci) -{ - return hw_read(ci, OP_USBINTR, ~0); -} - -/** - * hw_read_intr_status: returns interrupt status register - * - * This function returns register data - */ -static u32 hw_read_intr_status(struct ci_hdrc *ci) -{ - return hw_read(ci, OP_USBSTS, ~0); -} - /** * hw_test_and_clear_complete: test & clear complete status (execute without * interruption) @@ -1072,6 +1054,14 @@ __acquires(ci->lock) default: break; } + break; + case USB_DEVICE_B_HNP_ENABLE: + if (ci_otg_is_fsm_mode(ci)) { + ci->gadget.b_hnp_enable = 1; + err = isr_setup_status_phase( + ci); + } + break; default: goto delegate; } @@ -1655,6 +1645,13 @@ static int ci_udc_start(struct usb_gadget *gadget, return retval; ci->driver = driver; + + /* Start otg fsm for B-device */ + if (ci_otg_is_fsm_mode(ci) && ci->fsm.id) { + ci_hdrc_otg_fsm_start(ci); + return retval; + } + pm_runtime_get_sync(&ci->gadget.dev); if (ci->vbus_active) { spin_lock_irqsave(&ci->lock, flags); @@ -1779,7 +1776,7 @@ static int udc_start(struct ci_hdrc *ci) ci->gadget.ops = &usb_gadget_ops; ci->gadget.speed = USB_SPEED_UNKNOWN; ci->gadget.max_speed = USB_SPEED_HIGH; - ci->gadget.is_otg = 0; + ci->gadget.is_otg = ci->is_otg ? 1 : 0; ci->gadget.name = ci->platdata->name; INIT_LIST_HEAD(&ci->gadget.ep_list); @@ -1843,21 +1840,22 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci) static int udc_id_switch_for_device(struct ci_hdrc *ci) { - if (ci->is_otg) { - ci_clear_otg_interrupt(ci, OTGSC_BSVIS); - ci_enable_otg_interrupt(ci, OTGSC_BSVIE); - } + if (ci->is_otg) + /* Clear and enable BSV irq */ + hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE, + OTGSC_BSVIS | OTGSC_BSVIE); return 0; } static void udc_id_switch_for_host(struct ci_hdrc *ci) { - if (ci->is_otg) { - /* host doesn't care B_SESSION_VALID event */ - ci_clear_otg_interrupt(ci, OTGSC_BSVIS); - ci_disable_otg_interrupt(ci, OTGSC_BSVIE); - } + /* + * host doesn't care B_SESSION_VALID event + * so clear and disbale BSV irq + */ + if (ci->is_otg) + hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS); } /** diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index cd061abe35077f..419b8959d150e4 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -21,6 +21,26 @@ #define MX25_USB_PHY_CTRL_OFFSET 0x08 #define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23) +#define MX25_EHCI_INTERFACE_SINGLE_UNI (2 << 0) +#define MX25_EHCI_INTERFACE_DIFF_UNI (0 << 0) +#define MX25_EHCI_INTERFACE_MASK (0xf) + +#define MX25_OTG_SIC_SHIFT 29 +#define MX25_OTG_SIC_MASK (0x3 << MX25_OTG_SIC_SHIFT) +#define MX25_OTG_PM_BIT BIT(24) +#define MX25_OTG_PP_BIT BIT(11) +#define MX25_OTG_OCPOL_BIT BIT(3) + +#define MX25_H1_SIC_SHIFT 21 +#define MX25_H1_SIC_MASK (0x3 << MX25_H1_SIC_SHIFT) +#define MX25_H1_PP_BIT BIT(18) +#define MX25_H1_PM_BIT BIT(16) +#define MX25_H1_IPPUE_UP_BIT BIT(7) +#define MX25_H1_IPPUE_DOWN_BIT BIT(6) +#define MX25_H1_TLL_BIT BIT(5) +#define MX25_H1_USBTE_BIT BIT(4) +#define MX25_H1_OCPOL_BIT BIT(2) + #define MX27_H1_PM_BIT BIT(8) #define MX27_H2_PM_BIT BIT(16) #define MX27_OTG_PM_BIT BIT(24) @@ -50,6 +70,39 @@ struct imx_usbmisc { static struct imx_usbmisc *usbmisc; +static int usbmisc_imx25_init(struct imx_usbmisc_data *data) +{ + unsigned long flags; + u32 val = 0; + + if (data->index > 1) + return -EINVAL; + + spin_lock_irqsave(&usbmisc->lock, flags); + switch (data->index) { + case 0: + val = readl(usbmisc->base); + val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT); + val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT; + val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT); + writel(val, usbmisc->base); + break; + case 1: + val = readl(usbmisc->base); + val &= ~(MX25_H1_SIC_MASK | MX25_H1_PP_BIT | MX25_H1_IPPUE_UP_BIT); + val |= (MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT; + val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT | + MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT); + + writel(val, usbmisc->base); + + break; + } + spin_unlock_irqrestore(&usbmisc->lock, flags); + + return 0; +} + static int usbmisc_imx25_post(struct imx_usbmisc_data *data) { void __iomem *reg; @@ -159,6 +212,7 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) } static const struct usbmisc_ops imx25_usbmisc_ops = { + .init = usbmisc_imx25_init, .post = usbmisc_imx25_post, }; @@ -199,6 +253,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = { .compatible = "fsl,imx25-usbmisc", .data = &imx25_usbmisc_ops, }, + { + .compatible = "fsl,imx35-usbmisc", + .data = &imx25_usbmisc_ops, + }, { .compatible = "fsl,imx27-usbmisc", .data = &imx27_usbmisc_ops, diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig index be947d67384450..f93807b3631a82 100644 --- a/drivers/usb/dwc2/Kconfig +++ b/drivers/usb/dwc2/Kconfig @@ -1,25 +1,58 @@ config USB_DWC2 - tristate "DesignWare USB2 DRD Core Support" + bool "DesignWare USB2 DRD Core Support" depends on USB help - Say Y or M here if your system has a Dual Role HighSpeed - USB controller based on the DesignWare HSOTG IP Core. + Say Y here if your system has a Dual Role Hi-Speed USB + controller based on the DesignWare HSOTG IP Core. - If you choose to build this driver as dynamically linked - modules, the core module will be called dwc2.ko, the - PCI bus interface module (if you have a PCI bus system) - will be called dwc2_pci.ko and the platform interface module - (for controllers directly connected to the CPU) will be called - dwc2_platform.ko. + For host mode, if you choose to build the driver as dynamically + linked modules, the core module will be called dwc2.ko, the PCI + bus interface module (if you have a PCI bus system) will be + called dwc2_pci.ko, and the platform interface module (for + controllers directly connected to the CPU) will be called + dwc2_platform.ko. For gadget mode, there will be a single + module called dwc2_gadget.ko. - NOTE: This driver at present only implements the Host mode - of the controller. The existing s3c-hsotg driver supports - Peripheral mode, but only for the Samsung S3C platforms. - There are plans to merge the s3c-hsotg driver with this - driver in the near future to create a dual-role driver. + NOTE: The s3c-hsotg driver is now renamed to dwc2_gadget. The + host and gadget drivers are still currently separate drivers. + There are plans to merge the dwc2_gadget driver with the dwc2 + host driver in the near future to create a dual-role driver. if USB_DWC2 +config USB_DWC2_HOST + tristate "Host only mode" + depends on USB + help + The Designware USB2.0 high-speed host controller + integrated into many SoCs. + +config USB_DWC2_PLATFORM + bool "DWC2 Platform" + depends on USB_DWC2_HOST + default USB_DWC2_HOST + help + The Designware USB2.0 platform interface module for + controllers directly connected to the CPU. This is only + used for host mode. + +config USB_DWC2_PCI + bool "DWC2 PCI" + depends on USB_DWC2_HOST && PCI + default USB_DWC2_HOST + help + The Designware USB2.0 PCI interface module for controllers + connected to a PCI bus. This is only used for host mode. + +comment "Gadget mode requires USB Gadget support to be enabled" + +config USB_DWC2_PERIPHERAL + tristate "Gadget only mode" + depends on USB_GADGET + help + The Designware USB2.0 high-speed gadget controller + integrated into many SoCs. + config USB_DWC2_DEBUG bool "Enable Debugging Messages" help diff --git a/drivers/usb/dwc2/Makefile b/drivers/usb/dwc2/Makefile index 11529d3439b056..b73d2a527970e8 100644 --- a/drivers/usb/dwc2/Makefile +++ b/drivers/usb/dwc2/Makefile @@ -1,25 +1,28 @@ ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG -obj-$(CONFIG_USB_DWC2) += dwc2.o - -dwc2-y += core.o core_intr.o - -# NOTE: This driver at present only implements the Host mode -# of the controller. The existing s3c-hsotg driver supports -# Peripheral mode, but only for the Samsung S3C platforms. -# There are plans to merge the s3c-hsotg driver with this -# driver in the near future to create a dual-role driver. Once -# that is done, Host mode will become an optional feature that -# is selected with a config option. - +obj-$(CONFIG_USB_DWC2_HOST) += dwc2.o +dwc2-y := core.o core_intr.o dwc2-y += hcd.o hcd_intr.o dwc2-y += hcd_queue.o hcd_ddma.o -ifneq ($(CONFIG_PCI),) - obj-$(CONFIG_USB_DWC2) += dwc2_pci.o +# NOTE: The previous s3c-hsotg peripheral mode only driver has been moved to +# this location and renamed gadget.c. When building for dynamically linked +# modules, dwc2_gadget.ko will get built for peripheral mode. For host mode, +# the core module will be dwc2.ko, the PCI bus interface module will called +# dwc2_pci.ko and the platform interface module will be called dwc2_platform.ko. +# At present the host and gadget driver will be separate drivers, but there +# are plans in the near future to create a dual-role driver. + +ifneq ($(CONFIG_USB_DWC2_PCI),) + obj-$(CONFIG_USB_DWC2_HOST) += dwc2_pci.o + dwc2_pci-y := pci.o +endif + +ifneq ($(CONFIG_USB_DWC2_PLATFORM),) + obj-$(CONFIG_USB_DWC2_HOST) += dwc2_platform.o + dwc2_platform-y := platform.o endif -obj-$(CONFIG_USB_DWC2) += dwc2_platform.o -dwc2_pci-y += pci.o -dwc2_platform-y += platform.o +obj-$(CONFIG_USB_DWC2_PERIPHERAL) += dwc2_gadget.o +dwc2_gadget-y := gadget.o diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 648519c024b533..1efd10cc962918 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -37,6 +37,10 @@ #ifndef __DWC2_CORE_H__ #define __DWC2_CORE_H__ +#include +#include +#include +#include #include #include "hw.h" @@ -54,6 +58,184 @@ static inline void do_write(u32 value, void *addr) /* Maximum number of Endpoints/HostChannels */ #define MAX_EPS_CHANNELS 16 +/* s3c-hsotg declarations */ +static const char * const s3c_hsotg_supply_names[] = { + "vusb_d", /* digital USB supply, 1.2V */ + "vusb_a", /* analog USB supply, 1.1V */ +}; + +/* + * EP0_MPS_LIMIT + * + * Unfortunately there seems to be a limit of the amount of data that can + * be transferred by IN transactions on EP0. This is either 127 bytes or 3 + * packets (which practically means 1 packet and 63 bytes of data) when the + * MPS is set to 64. + * + * This means if we are wanting to move >127 bytes of data, we need to + * split the transactions up, but just doing one packet at a time does + * not work (this may be an implicit DATA0 PID on first packet of the + * transaction) and doing 2 packets is outside the controller's limits. + * + * If we try to lower the MPS size for EP0, then no transfers work properly + * for EP0, and the system will fail basic enumeration. As no cause for this + * has currently been found, we cannot support any large IN transfers for + * EP0. + */ +#define EP0_MPS_LIMIT 64 + +struct s3c_hsotg; +struct s3c_hsotg_req; + +/** + * struct s3c_hsotg_ep - driver endpoint definition. + * @ep: The gadget layer representation of the endpoint. + * @name: The driver generated name for the endpoint. + * @queue: Queue of requests for this endpoint. + * @parent: Reference back to the parent device structure. + * @req: The current request that the endpoint is processing. This is + * used to indicate an request has been loaded onto the endpoint + * and has yet to be completed (maybe due to data move, or simply + * awaiting an ack from the core all the data has been completed). + * @debugfs: File entry for debugfs file for this endpoint. + * @lock: State lock to protect contents of endpoint. + * @dir_in: Set to true if this endpoint is of the IN direction, which + * means that it is sending data to the Host. + * @index: The index for the endpoint registers. + * @mc: Multi Count - number of transactions per microframe + * @interval - Interval for periodic endpoints + * @name: The name array passed to the USB core. + * @halted: Set if the endpoint has been halted. + * @periodic: Set if this is a periodic ep, such as Interrupt + * @isochronous: Set if this is a isochronous ep + * @sent_zlp: Set if we've sent a zero-length packet. + * @total_data: The total number of data bytes done. + * @fifo_size: The size of the FIFO (for periodic IN endpoints) + * @fifo_load: The amount of data loaded into the FIFO (periodic IN) + * @last_load: The offset of data for the last start of request. + * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN + * + * This is the driver's state for each registered enpoint, allowing it + * to keep track of transactions that need doing. Each endpoint has a + * lock to protect the state, to try and avoid using an overall lock + * for the host controller as much as possible. + * + * For periodic IN endpoints, we have fifo_size and fifo_load to try + * and keep track of the amount of data in the periodic FIFO for each + * of these as we don't have a status register that tells us how much + * is in each of them. (note, this may actually be useless information + * as in shared-fifo mode periodic in acts like a single-frame packet + * buffer than a fifo) + */ +struct s3c_hsotg_ep { + struct usb_ep ep; + struct list_head queue; + struct s3c_hsotg *parent; + struct s3c_hsotg_req *req; + struct dentry *debugfs; + + unsigned long total_data; + unsigned int size_loaded; + unsigned int last_load; + unsigned int fifo_load; + unsigned short fifo_size; + + unsigned char dir_in; + unsigned char index; + unsigned char mc; + unsigned char interval; + + unsigned int halted:1; + unsigned int periodic:1; + unsigned int isochronous:1; + unsigned int sent_zlp:1; + + char name[10]; +}; + +/** + * struct s3c_hsotg - driver state. + * @dev: The parent device supplied to the probe function + * @driver: USB gadget driver + * @phy: The otg phy transceiver structure for phy control. + * @uphy: The otg phy transceiver structure for old USB phy control. + * @plat: The platform specific configuration data. This can be removed once + * all SoCs support usb transceiver. + * @regs: The memory area mapped for accessing registers. + * @irq: The IRQ number we are using + * @supplies: Definition of USB power supplies + * @phyif: PHY interface width + * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. + * @num_of_eps: Number of available EPs (excluding EP0) + * @debug_root: root directrory for debugfs. + * @debug_file: main status file for debugfs. + * @debug_fifo: FIFO status file for debugfs. + * @ep0_reply: Request used for ep0 reply. + * @ep0_buff: Buffer for EP0 reply data, if needed. + * @ctrl_buff: Buffer for EP0 control requests. + * @ctrl_req: Request for EP0 control packets. + * @setup: NAK management for EP0 SETUP + * @last_rst: Time of last reset + * @eps: The endpoints being supplied to the gadget framework + */ +struct s3c_hsotg { + struct device *dev; + struct usb_gadget_driver *driver; + struct phy *phy; + struct usb_phy *uphy; + struct s3c_hsotg_plat *plat; + + spinlock_t lock; + + void __iomem *regs; + int irq; + struct clk *clk; + + struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; + + u32 phyif; + unsigned int dedicated_fifos:1; + unsigned char num_of_eps; + + struct dentry *debug_root; + struct dentry *debug_file; + struct dentry *debug_fifo; + + struct usb_request *ep0_reply; + struct usb_request *ctrl_req; + u8 ep0_buff[8]; + u8 ctrl_buff[8]; + + struct usb_gadget gadget; + unsigned int setup; + unsigned long last_rst; + struct s3c_hsotg_ep *eps; +}; + +/** + * struct s3c_hsotg_req - data transfer request + * @req: The USB gadget request + * @queue: The list of requests for the endpoint this is queued for. + * @in_progress: Has already had size/packets written to core + * @mapped: DMA buffer for this request has been mapped via dma_map_single(). + */ +struct s3c_hsotg_req { + struct usb_request req; + struct list_head queue; + unsigned char in_progress; + unsigned char mapped; +}; + +#define call_gadget(_hs, _entry) \ +do { \ + if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ + (_hs)->driver && (_hs)->driver->_entry) { \ + spin_unlock(&_hs->lock); \ + (_hs)->driver->_entry(&(_hs)->gadget); \ + spin_lock(&_hs->lock); \ + } \ +} while (0) + struct dwc2_hsotg; struct dwc2_host_chan; diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/dwc2/gadget.c similarity index 85% rename from drivers/usb/gadget/s3c-hsotg.c rename to drivers/usb/dwc2/gadget.c index 2a9cb674926aa8..2057c380969ed9 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/dwc2/gadget.c @@ -37,175 +37,7 @@ #include #include -#include "s3c-hsotg.h" - -static const char * const s3c_hsotg_supply_names[] = { - "vusb_d", /* digital USB supply, 1.2V */ - "vusb_a", /* analog USB supply, 1.1V */ -}; - -/* - * EP0_MPS_LIMIT - * - * Unfortunately there seems to be a limit of the amount of data that can - * be transferred by IN transactions on EP0. This is either 127 bytes or 3 - * packets (which practically means 1 packet and 63 bytes of data) when the - * MPS is set to 64. - * - * This means if we are wanting to move >127 bytes of data, we need to - * split the transactions up, but just doing one packet at a time does - * not work (this may be an implicit DATA0 PID on first packet of the - * transaction) and doing 2 packets is outside the controller's limits. - * - * If we try to lower the MPS size for EP0, then no transfers work properly - * for EP0, and the system will fail basic enumeration. As no cause for this - * has currently been found, we cannot support any large IN transfers for - * EP0. - */ -#define EP0_MPS_LIMIT 64 - -struct s3c_hsotg; -struct s3c_hsotg_req; - -/** - * struct s3c_hsotg_ep - driver endpoint definition. - * @ep: The gadget layer representation of the endpoint. - * @name: The driver generated name for the endpoint. - * @queue: Queue of requests for this endpoint. - * @parent: Reference back to the parent device structure. - * @req: The current request that the endpoint is processing. This is - * used to indicate an request has been loaded onto the endpoint - * and has yet to be completed (maybe due to data move, or simply - * awaiting an ack from the core all the data has been completed). - * @debugfs: File entry for debugfs file for this endpoint. - * @lock: State lock to protect contents of endpoint. - * @dir_in: Set to true if this endpoint is of the IN direction, which - * means that it is sending data to the Host. - * @index: The index for the endpoint registers. - * @mc: Multi Count - number of transactions per microframe - * @interval - Interval for periodic endpoints - * @name: The name array passed to the USB core. - * @halted: Set if the endpoint has been halted. - * @periodic: Set if this is a periodic ep, such as Interrupt - * @isochronous: Set if this is a isochronous ep - * @sent_zlp: Set if we've sent a zero-length packet. - * @total_data: The total number of data bytes done. - * @fifo_size: The size of the FIFO (for periodic IN endpoints) - * @fifo_load: The amount of data loaded into the FIFO (periodic IN) - * @last_load: The offset of data for the last start of request. - * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN - * - * This is the driver's state for each registered enpoint, allowing it - * to keep track of transactions that need doing. Each endpoint has a - * lock to protect the state, to try and avoid using an overall lock - * for the host controller as much as possible. - * - * For periodic IN endpoints, we have fifo_size and fifo_load to try - * and keep track of the amount of data in the periodic FIFO for each - * of these as we don't have a status register that tells us how much - * is in each of them. (note, this may actually be useless information - * as in shared-fifo mode periodic in acts like a single-frame packet - * buffer than a fifo) - */ -struct s3c_hsotg_ep { - struct usb_ep ep; - struct list_head queue; - struct s3c_hsotg *parent; - struct s3c_hsotg_req *req; - struct dentry *debugfs; - - - unsigned long total_data; - unsigned int size_loaded; - unsigned int last_load; - unsigned int fifo_load; - unsigned short fifo_size; - - unsigned char dir_in; - unsigned char index; - unsigned char mc; - unsigned char interval; - - unsigned int halted:1; - unsigned int periodic:1; - unsigned int isochronous:1; - unsigned int sent_zlp:1; - - char name[10]; -}; - -/** - * struct s3c_hsotg - driver state. - * @dev: The parent device supplied to the probe function - * @driver: USB gadget driver - * @phy: The otg phy transceiver structure for phy control. - * @uphy: The otg phy transceiver structure for old USB phy control. - * @plat: The platform specific configuration data. This can be removed once - * all SoCs support usb transceiver. - * @regs: The memory area mapped for accessing registers. - * @irq: The IRQ number we are using - * @supplies: Definition of USB power supplies - * @phyif: PHY interface width - * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. - * @num_of_eps: Number of available EPs (excluding EP0) - * @debug_root: root directrory for debugfs. - * @debug_file: main status file for debugfs. - * @debug_fifo: FIFO status file for debugfs. - * @ep0_reply: Request used for ep0 reply. - * @ep0_buff: Buffer for EP0 reply data, if needed. - * @ctrl_buff: Buffer for EP0 control requests. - * @ctrl_req: Request for EP0 control packets. - * @setup: NAK management for EP0 SETUP - * @last_rst: Time of last reset - * @eps: The endpoints being supplied to the gadget framework - */ -struct s3c_hsotg { - struct device *dev; - struct usb_gadget_driver *driver; - struct phy *phy; - struct usb_phy *uphy; - struct s3c_hsotg_plat *plat; - - spinlock_t lock; - - void __iomem *regs; - int irq; - struct clk *clk; - - struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; - - u32 phyif; - unsigned int dedicated_fifos:1; - unsigned char num_of_eps; - - struct dentry *debug_root; - struct dentry *debug_file; - struct dentry *debug_fifo; - - struct usb_request *ep0_reply; - struct usb_request *ctrl_req; - u8 ep0_buff[8]; - u8 ctrl_buff[8]; - - struct usb_gadget gadget; - unsigned int setup; - unsigned long last_rst; - struct s3c_hsotg_ep *eps; -}; - -/** - * struct s3c_hsotg_req - data transfer request - * @req: The USB gadget request - * @queue: The list of requests for the endpoint this is queued for. - * @in_progress: Has already had size/packets written to core - * @mapped: DMA buffer for this request has been mapped via dma_map_single(). - */ -struct s3c_hsotg_req { - struct usb_request req; - struct list_head queue; - unsigned char in_progress; - unsigned char mapped; -}; +#include "core.h" /* conversion functions */ static inline struct s3c_hsotg_req *our_req(struct usb_request *req) @@ -340,9 +172,8 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) /* set FIFO sizes to 2048/1024 */ writel(2048, hsotg->regs + GRXFSIZ); - writel(GNPTXFSIZ_NPTxFStAddr(2048) | - GNPTXFSIZ_NPTxFDep(1024), - hsotg->regs + GNPTXFSIZ); + writel((2048 << FIFOSIZE_STARTADDR_SHIFT) | + (1024 << FIFOSIZE_DEPTH_SHIFT), hsotg->regs + GNPTXFSIZ); /* * arange all the rest of the TX FIFOs, as some versions of this @@ -362,10 +193,10 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) for (ep = 1; ep <= 15; ep++) { val = addr; - val |= size << DPTXFSIZn_DPTxFSize_SHIFT; + val |= size << FIFOSIZE_DEPTH_SHIFT; addr += size; - writel(val, hsotg->regs + DPTXFSIZn(ep)); + writel(val, hsotg->regs + DPTXFSIZN(ep)); } /* @@ -373,15 +204,15 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) * all fifos are flushed before continuing */ - writel(GRSTCTL_TxFNum(0x10) | GRSTCTL_TxFFlsh | - GRSTCTL_RxFFlsh, hsotg->regs + GRSTCTL); + writel(GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | + GRSTCTL_RXFFLSH, hsotg->regs + GRSTCTL); /* wait until the fifos are both flushed */ timeout = 100; while (1) { val = readl(hsotg->regs + GRSTCTL); - if ((val & (GRSTCTL_TxFFlsh | GRSTCTL_RxFFlsh)) == 0) + if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0) break; if (--timeout == 0) { @@ -495,14 +326,14 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, * how much data is left in the fifo. */ - size_left = DxEPTSIZ_XferSize_GET(epsize); + size_left = DXEPTSIZ_XFERSIZE_GET(epsize); /* * if shared fifo, we cannot write anything until the * previous data has been completely sent. */ if (hs_ep->fifo_load != 0) { - s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); + s3c_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); return -ENOSPC; } @@ -523,7 +354,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, __func__, can_write); if (can_write <= 0) { - s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); + s3c_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); return -ENOSPC; } } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { @@ -532,16 +363,16 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, can_write &= 0xffff; can_write *= 4; } else { - if (GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { + if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) { dev_dbg(hsotg->dev, "%s: no queue slots available (0x%08x)\n", __func__, gnptxsts); - s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTxFEmp); + s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP); return -ENOSPC; } - can_write = GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); + can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts); can_write *= 4; /* fifo size is in 32bit quantities. */ } @@ -569,8 +400,8 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, /* it's needed only when we do not use dedicated fifos */ if (!hsotg->dedicated_fifos) s3c_hsotg_en_gsint(hsotg, - periodic ? GINTSTS_PTxFEmp : - GINTSTS_NPTxFEmp); + periodic ? GINTSTS_PTXFEMP : + GINTSTS_NPTXFEMP); } /* see if we can write data */ @@ -598,8 +429,8 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, /* it's needed only when we do not use dedicated fifos */ if (!hsotg->dedicated_fifos) s3c_hsotg_en_gsint(hsotg, - periodic ? GINTSTS_PTxFEmp : - GINTSTS_NPTxFEmp); + periodic ? GINTSTS_PTXFEMP : + GINTSTS_NPTXFEMP); } dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", @@ -636,12 +467,12 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) unsigned maxpkt; if (index != 0) { - maxsize = DxEPTSIZ_XferSize_LIMIT + 1; - maxpkt = DxEPTSIZ_PktCnt_LIMIT + 1; + maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; + maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; } else { maxsize = 64+64; if (hs_ep->dir_in) - maxpkt = DIEPTSIZ0_PktCnt_LIMIT + 1; + maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; else maxpkt = 2; } @@ -710,7 +541,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, /* If endpoint is stalled, we will restart request later */ ctrl = readl(hsotg->regs + epctrl_reg); - if (ctrl & DxEPCTL_Stall) { + if (ctrl & DXEPCTL_STALL) { dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); return; } @@ -750,9 +581,9 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, if (dir_in && index != 0) if (hs_ep->isochronous) - epsize = DxEPTSIZ_MC(packets); + epsize = DXEPTSIZ_MC(packets); else - epsize = DxEPTSIZ_MC(1); + epsize = DXEPTSIZ_MC(1); else epsize = 0; @@ -766,8 +597,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, packets++; } - epsize |= DxEPTSIZ_PktCnt(packets); - epsize |= DxEPTSIZ_XferSize(length); + epsize |= DXEPTSIZ_PKTCNT(packets); + epsize |= DXEPTSIZ_XFERSIZE(length); dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", __func__, packets, length, ureq->length, epsize, epsize_reg); @@ -793,8 +624,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, __func__, &ureq->dma, dma_reg); } - ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ - ctrl |= DxEPCTL_USBActEp; + ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ + ctrl |= DXEPCTL_USBACTEP; dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup); @@ -802,7 +633,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, if (hsotg->setup && index == 0) hsotg->setup = 0; else - ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */ + ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); @@ -828,7 +659,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, * to debugging to see what is going on. */ if (dir_in) - writel(DIEPMSK_INTknTXFEmpMsk, + writel(DIEPMSK_INTKNTXFEMPMSK, hsotg->regs + DIEPINT(index)); /* @@ -837,12 +668,12 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, */ /* check ep is enabled */ - if (!(readl(hsotg->regs + epctrl_reg) & DxEPCTL_EPEna)) + if (!(readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA)) dev_warn(hsotg->dev, - "ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n", + "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", index, readl(hsotg->regs + epctrl_reg)); - dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", + dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", __func__, readl(hsotg->regs + epctrl_reg)); /* enable ep interrupts */ @@ -1205,12 +1036,12 @@ static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg) { */ ctrl = readl(hsotg->regs + reg); - ctrl |= DxEPCTL_Stall; - ctrl |= DxEPCTL_CNAK; + ctrl |= DXEPCTL_STALL; + ctrl |= DXEPCTL_CNAK; writel(ctrl, hsotg->regs + reg); dev_dbg(hsotg->dev, - "written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n", + "written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n", ctrl, reg, readl(hsotg->regs + reg)); /* @@ -1262,8 +1093,9 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, case USB_REQ_SET_ADDRESS: s3c_hsotg_disconnect(hsotg); dcfg = readl(hsotg->regs + DCFG); - dcfg &= ~DCFG_DevAddr_MASK; - dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT; + dcfg &= ~DCFG_DEVADDR_MASK; + dcfg |= (le16_to_cpu(ctrl->wValue) << + DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK; writel(dcfg, hsotg->regs + DCFG); dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); @@ -1458,7 +1290,7 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) int ptr; dev_warn(hsotg->dev, - "%s: FIFO %d bytes on ep%d but no req (DxEPCTl=0x%08x)\n", + "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", __func__, size, ep_idx, epctl); /* dump the data from the FIFO, we've nothing we can do */ @@ -1530,13 +1362,13 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, dev_dbg(hsotg->dev, "sending zero-length packet\n"); /* issue a zero-sized packet to terminate this */ - writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | - DxEPTSIZ_XferSize(0), hsotg->regs + DIEPTSIZ(0)); + writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | + DXEPTSIZ_XFERSIZE(0), hsotg->regs + DIEPTSIZ(0)); ctrl = readl(hsotg->regs + DIEPCTL0); - ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */ - ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ - ctrl |= DxEPCTL_USBActEp; + ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ + ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ + ctrl |= DXEPCTL_USBACTEP; writel(ctrl, hsotg->regs + DIEPCTL0); } @@ -1557,7 +1389,7 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum]; struct s3c_hsotg_req *hs_req = hs_ep->req; struct usb_request *req = &hs_req->req; - unsigned size_left = DxEPTSIZ_XferSize_GET(epsize); + unsigned size_left = DXEPTSIZ_XFERSIZE_GET(epsize); int result = 0; if (!hs_req) { @@ -1657,24 +1489,22 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) WARN_ON(using_dma(hsotg)); - epnum = grxstsr & GRXSTS_EPNum_MASK; - status = grxstsr & GRXSTS_PktSts_MASK; + epnum = grxstsr & GRXSTS_EPNUM_MASK; + status = grxstsr & GRXSTS_PKTSTS_MASK; - size = grxstsr & GRXSTS_ByteCnt_MASK; - size >>= GRXSTS_ByteCnt_SHIFT; + size = grxstsr & GRXSTS_BYTECNT_MASK; + size >>= GRXSTS_BYTECNT_SHIFT; if (1) dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", __func__, grxstsr, size, epnum); -#define __status(x) ((x) >> GRXSTS_PktSts_SHIFT) - - switch (status >> GRXSTS_PktSts_SHIFT) { - case __status(GRXSTS_PktSts_GlobalOutNAK): - dev_dbg(hsotg->dev, "GlobalOutNAK\n"); + switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { + case GRXSTS_PKTSTS_GLOBALOUTNAK: + dev_dbg(hsotg->dev, "GLOBALOUTNAK\n"); break; - case __status(GRXSTS_PktSts_OutDone): + case GRXSTS_PKTSTS_OUTDONE: dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", s3c_hsotg_read_frameno(hsotg)); @@ -1682,7 +1512,7 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) s3c_hsotg_handle_outdone(hsotg, epnum, false); break; - case __status(GRXSTS_PktSts_SetupDone): + case GRXSTS_PKTSTS_SETUPDONE: dev_dbg(hsotg->dev, "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", s3c_hsotg_read_frameno(hsotg), @@ -1691,11 +1521,11 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) s3c_hsotg_handle_outdone(hsotg, epnum, true); break; - case __status(GRXSTS_PktSts_OutRX): + case GRXSTS_PKTSTS_OUTRX: s3c_hsotg_rx_data(hsotg, epnum, size); break; - case __status(GRXSTS_PktSts_SetupRX): + case GRXSTS_PKTSTS_SETUPRX: dev_dbg(hsotg->dev, "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", s3c_hsotg_read_frameno(hsotg), @@ -1761,7 +1591,7 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, hs_ep->ep.maxpacket = mps; hs_ep->mc = 1; } else { - mpsval = mps & DxEPCTL_MPS_MASK; + mpsval = mps & DXEPCTL_MPS_MASK; if (mpsval > 1024) goto bad_mps; mcval = ((mps >> 11) & 0x3) + 1; @@ -1777,13 +1607,13 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, */ reg = readl(regs + DIEPCTL(ep)); - reg &= ~DxEPCTL_MPS_MASK; + reg &= ~DXEPCTL_MPS_MASK; reg |= mpsval; writel(reg, regs + DIEPCTL(ep)); if (ep) { reg = readl(regs + DOEPCTL(ep)); - reg &= ~DxEPCTL_MPS_MASK; + reg &= ~DXEPCTL_MPS_MASK; reg |= mpsval; writel(reg, regs + DOEPCTL(ep)); } @@ -1804,7 +1634,7 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) int timeout; int val; - writel(GRSTCTL_TxFNum(idx) | GRSTCTL_TxFFlsh, + writel(GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH, hsotg->regs + GRSTCTL); /* wait until the fifo is flushed */ @@ -1813,7 +1643,7 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) while (1) { val = readl(hsotg->regs + GRSTCTL); - if ((val & (GRSTCTL_TxFFlsh)) == 0) + if ((val & (GRSTCTL_TXFFLSH)) == 0) break; if (--timeout == 0) { @@ -1896,7 +1726,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, * aligned). */ - size_left = DxEPTSIZ_XferSize_GET(epsize); + size_left = DXEPTSIZ_XFERSIZE_GET(epsize); size_done = hs_ep->size_loaded - size_left; size_done += hs_ep->last_load; @@ -1963,17 +1793,17 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", __func__, idx, dir_in ? "in" : "out", ints); - if (ints & DxEPINT_XferCompl) { + if (ints & DXEPINT_XFERCOMPL) { if (hs_ep->isochronous && hs_ep->interval == 1) { - if (ctrl & DxEPCTL_EOFrNum) - ctrl |= DxEPCTL_SetEvenFr; + if (ctrl & DXEPCTL_EOFRNUM) + ctrl |= DXEPCTL_SETEVENFR; else - ctrl |= DxEPCTL_SetOddFr; + ctrl |= DXEPCTL_SETODDFR; writel(ctrl, hsotg->regs + epctl_reg); } dev_dbg(hsotg->dev, - "%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n", + "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", __func__, readl(hsotg->regs + epctl_reg), readl(hsotg->regs + epsiz_reg)); @@ -1996,7 +1826,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, } } - if (ints & DxEPINT_EPDisbld) { + if (ints & DXEPINT_EPDISBLD) { dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); if (dir_in) { @@ -2004,20 +1834,20 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, s3c_hsotg_txfifo_flush(hsotg, idx); - if ((epctl & DxEPCTL_Stall) && - (epctl & DxEPCTL_EPType_Bulk)) { + if ((epctl & DXEPCTL_STALL) && + (epctl & DXEPCTL_EPTYPE_BULK)) { int dctl = readl(hsotg->regs + DCTL); - dctl |= DCTL_CGNPInNAK; + dctl |= DCTL_CGNPINNAK; writel(dctl, hsotg->regs + DCTL); } } } - if (ints & DxEPINT_AHBErr) + if (ints & DXEPINT_AHBERR) dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); - if (ints & DxEPINT_Setup) { /* Setup or Timeout */ + if (ints & DXEPINT_SETUP) { /* Setup or Timeout */ dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); if (using_dma(hsotg) && idx == 0) { @@ -2035,25 +1865,25 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, } } - if (ints & DxEPINT_Back2BackSetup) + if (ints & DXEPINT_BACK2BACKSETUP) dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); if (dir_in && !hs_ep->isochronous) { /* not sure if this is important, but we'll clear it anyway */ - if (ints & DIEPMSK_INTknTXFEmpMsk) { + if (ints & DIEPMSK_INTKNTXFEMPMSK) { dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", __func__, idx); } /* this probably means something bad is happening */ - if (ints & DIEPMSK_INTknEPMisMsk) { + if (ints & DIEPMSK_INTKNEPMISMSK) { dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", __func__, idx); } /* FIFO has space or is empty (see GAHBCFG) */ if (hsotg->dedicated_fifos && - ints & DIEPMSK_TxFIFOEmpty) { + ints & DIEPMSK_TXFIFOEMPTY) { dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", __func__, idx); if (!using_dma(hsotg)) @@ -2089,21 +1919,21 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) */ /* catch both EnumSpd_FS and EnumSpd_FS48 */ - switch (dsts & DSTS_EnumSpd_MASK) { - case DSTS_EnumSpd_FS: - case DSTS_EnumSpd_FS48: + switch (dsts & DSTS_ENUMSPD_MASK) { + case DSTS_ENUMSPD_FS: + case DSTS_ENUMSPD_FS48: hsotg->gadget.speed = USB_SPEED_FULL; ep0_mps = EP0_MPS_LIMIT; ep_mps = 1023; break; - case DSTS_EnumSpd_HS: + case DSTS_ENUMSPD_HS: hsotg->gadget.speed = USB_SPEED_HIGH; ep0_mps = EP0_MPS_LIMIT; ep_mps = 1024; break; - case DSTS_EnumSpd_LS: + case DSTS_ENUMSPD_LS: hsotg->gadget.speed = USB_SPEED_LOW; /* * note, we don't actually support LS in this driver at the @@ -2169,16 +1999,6 @@ static void kill_all_requests(struct s3c_hsotg *hsotg, s3c_hsotg_txfifo_flush(hsotg, ep->index); } -#define call_gadget(_hs, _entry) \ -do { \ - if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ - (_hs)->driver && (_hs)->driver->_entry) { \ - spin_unlock(&_hs->lock); \ - (_hs)->driver->_entry(&(_hs)->gadget); \ - spin_lock(&_hs->lock); \ - } \ -} while (0) - /** * s3c_hsotg_disconnect - disconnect service * @hsotg: The device state. @@ -2226,9 +2046,9 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) } /* IRQ flags which will trigger a retry around the IRQ loop */ -#define IRQ_RETRY_MASK (GINTSTS_NPTxFEmp | \ - GINTSTS_PTxFEmp | \ - GINTSTS_RxFLvl) +#define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ + GINTSTS_PTXFEMP | \ + GINTSTS_RXFLVL) /** * s3c_hsotg_corereset - issue softreset to the core @@ -2244,14 +2064,14 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) dev_dbg(hsotg->dev, "resetting core\n"); /* issue soft reset */ - writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL); + writel(GRSTCTL_CSFTRST, hsotg->regs + GRSTCTL); timeout = 10000; do { grstctl = readl(hsotg->regs + GRSTCTL); - } while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0); + } while ((grstctl & GRSTCTL_CSFTRST) && timeout-- > 0); - if (grstctl & GRSTCTL_CSftRst) { + if (grstctl & GRSTCTL_CSFTRST) { dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); return -EINVAL; } @@ -2268,7 +2088,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) return -ETIMEDOUT; } - if (!(grstctl & GRSTCTL_AHBIdle)) + if (!(grstctl & GRSTCTL_AHBIDLE)) continue; break; /* reset done */ @@ -2294,14 +2114,14 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) */ /* set the PLL on, remove the HNP/SRP and set the PHY */ - writel(hsotg->phyif | GUSBCFG_TOutCal(7) | + writel(hsotg->phyif | GUSBCFG_TOUTCAL(7) | (0x5 << 10), hsotg->regs + GUSBCFG); s3c_hsotg_init_fifo(hsotg); - __orr32(hsotg->regs + DCTL, DCTL_SftDiscon); + __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); - writel(1 << 18 | DCFG_DevSpd_HS, hsotg->regs + DCFG); + writel(1 << 18 | DCFG_DEVSPD_HS, hsotg->regs + DCFG); /* Clear any pending OTG interrupts */ writel(0xffffffff, hsotg->regs + GOTGINT); @@ -2309,21 +2129,21 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) /* Clear any pending interrupts */ writel(0xffffffff, hsotg->regs + GINTSTS); - writel(GINTSTS_ErlySusp | GINTSTS_SessReqInt | - GINTSTS_GOUTNakEff | GINTSTS_GINNakEff | - GINTSTS_ConIDStsChng | GINTSTS_USBRst | - GINTSTS_EnumDone | GINTSTS_OTGInt | - GINTSTS_USBSusp | GINTSTS_WkUpInt, - hsotg->regs + GINTMSK); + writel(GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT | + GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | + GINTSTS_CONIDSTSCHNG | GINTSTS_USBRST | + GINTSTS_ENUMDONE | GINTSTS_OTGINT | + GINTSTS_USBSUSP | GINTSTS_WKUPINT, + hsotg->regs + GINTMSK); if (using_dma(hsotg)) - writel(GAHBCFG_GlblIntrEn | GAHBCFG_DMAEn | - GAHBCFG_HBstLen_Incr4, + writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN | + GAHBCFG_HBSTLEN_INCR4, hsotg->regs + GAHBCFG); else - writel(((hsotg->dedicated_fifos) ? (GAHBCFG_NPTxFEmpLvl | - GAHBCFG_PTxFEmpLvl) : 0) | - GAHBCFG_GlblIntrEn, + writel(((hsotg->dedicated_fifos) ? (GAHBCFG_NP_TXF_EMP_LVL | + GAHBCFG_P_TXF_EMP_LVL) : 0) | + GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG); /* @@ -2332,22 +2152,22 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) * interrupts. */ - writel(((hsotg->dedicated_fifos) ? DIEPMSK_TxFIFOEmpty | - DIEPMSK_INTknTXFEmpMsk : 0) | - DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk | - DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | - DIEPMSK_INTknEPMisMsk, - hsotg->regs + DIEPMSK); + writel(((hsotg->dedicated_fifos) ? DIEPMSK_TXFIFOEMPTY | + DIEPMSK_INTKNTXFEMPMSK : 0) | + DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | + DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | + DIEPMSK_INTKNEPMISMSK, + hsotg->regs + DIEPMSK); /* * don't need XferCompl, we get that from RXFIFO in slave mode. In * DMA mode we may need this. */ - writel((using_dma(hsotg) ? (DIEPMSK_XferComplMsk | - DIEPMSK_TimeOUTMsk) : 0) | - DOEPMSK_EPDisbldMsk | DOEPMSK_AHBErrMsk | - DOEPMSK_SetupMsk, - hsotg->regs + DOEPMSK); + writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK | + DIEPMSK_TIMEOUTMSK) : 0) | + DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | + DOEPMSK_SETUPMSK, + hsotg->regs + DOEPMSK); writel(0, hsotg->regs + DAINTMSK); @@ -2356,7 +2176,7 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) readl(hsotg->regs + DOEPCTL0)); /* enable in and out endpoint interrupts */ - s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPInt | GINTSTS_IEPInt); + s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT); /* * Enable the RXFIFO when in slave mode, as this is how we collect @@ -2364,15 +2184,15 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) * things we cannot process, so do not use it. */ if (!using_dma(hsotg)) - s3c_hsotg_en_gsint(hsotg, GINTSTS_RxFLvl); + s3c_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL); /* Enable interrupts for EP0 in and out */ s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1); s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1); - __orr32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); + __orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); udelay(10); /* see openiboot */ - __bic32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); + __bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL)); @@ -2382,17 +2202,17 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) */ /* set to read 1 8byte packet */ - writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | - DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0); + writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | + DXEPTSIZ_XFERSIZE(8), hsotg->regs + DOEPTSIZ0); writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | - DxEPCTL_CNAK | DxEPCTL_EPEna | - DxEPCTL_USBActEp, + DXEPCTL_CNAK | DXEPCTL_EPENA | + DXEPCTL_USBACTEP, hsotg->regs + DOEPCTL0); /* enable, but don't activate EP0in */ writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | - DxEPCTL_USBActEp, hsotg->regs + DIEPCTL0); + DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0); s3c_hsotg_enqueue_setup(hsotg); @@ -2401,14 +2221,14 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) readl(hsotg->regs + DOEPCTL0)); /* clear global NAKs */ - writel(DCTL_CGOUTNak | DCTL_CGNPInNAK, + writel(DCTL_CGOUTNAK | DCTL_CGNPINNAK, hsotg->regs + DCTL); /* must be at-least 3ms to allow bus to see disconnect */ mdelay(3); /* remove the soft-disconnect and let's go */ - __bic32(hsotg->regs + DCTL, DCTL_SftDiscon); + __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON); } /** @@ -2433,7 +2253,7 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) gintsts &= gintmsk; - if (gintsts & GINTSTS_OTGInt) { + if (gintsts & GINTSTS_OTGINT) { u32 otgint = readl(hsotg->regs + GOTGINT); dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); @@ -2441,34 +2261,34 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) writel(otgint, hsotg->regs + GOTGINT); } - if (gintsts & GINTSTS_SessReqInt) { + if (gintsts & GINTSTS_SESSREQINT) { dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__); - writel(GINTSTS_SessReqInt, hsotg->regs + GINTSTS); + writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS); } - if (gintsts & GINTSTS_EnumDone) { - writel(GINTSTS_EnumDone, hsotg->regs + GINTSTS); + if (gintsts & GINTSTS_ENUMDONE) { + writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); s3c_hsotg_irq_enumdone(hsotg); } - if (gintsts & GINTSTS_ConIDStsChng) { + if (gintsts & GINTSTS_CONIDSTSCHNG) { dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n", readl(hsotg->regs + DSTS), readl(hsotg->regs + GOTGCTL)); - writel(GINTSTS_ConIDStsChng, hsotg->regs + GINTSTS); + writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS); } - if (gintsts & (GINTSTS_OEPInt | GINTSTS_IEPInt)) { + if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { u32 daint = readl(hsotg->regs + DAINT); u32 daintmsk = readl(hsotg->regs + DAINTMSK); u32 daint_out, daint_in; int ep; daint &= daintmsk; - daint_out = daint >> DAINT_OutEP_SHIFT; - daint_in = daint & ~(daint_out << DAINT_OutEP_SHIFT); + daint_out = daint >> DAINT_OUTEP_SHIFT; + daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); @@ -2483,7 +2303,7 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) } } - if (gintsts & GINTSTS_USBRst) { + if (gintsts & GINTSTS_USBRST) { u32 usb_status = readl(hsotg->regs + GOTGCTL); @@ -2491,7 +2311,7 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", readl(hsotg->regs + GNPTXSTS)); - writel(GINTSTS_USBRst, hsotg->regs + GINTSTS); + writel(GINTSTS_USBRST, hsotg->regs + GINTSTS); if (usb_status & GOTGCTL_BSESVLD) { if (time_after(jiffies, hsotg->last_rst + @@ -2508,7 +2328,7 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) /* check both FIFOs */ - if (gintsts & GINTSTS_NPTxFEmp) { + if (gintsts & GINTSTS_NPTXFEMP) { dev_dbg(hsotg->dev, "NPTxFEmp\n"); /* @@ -2517,20 +2337,20 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) * it needs re-enabling */ - s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTxFEmp); + s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); s3c_hsotg_irq_fifoempty(hsotg, false); } - if (gintsts & GINTSTS_PTxFEmp) { + if (gintsts & GINTSTS_PTXFEMP) { dev_dbg(hsotg->dev, "PTxFEmp\n"); /* See note in GINTSTS_NPTxFEmp */ - s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTxFEmp); + s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); s3c_hsotg_irq_fifoempty(hsotg, true); } - if (gintsts & GINTSTS_RxFLvl) { + if (gintsts & GINTSTS_RXFLVL) { /* * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, * we need to retry s3c_hsotg_handle_rx if this is still @@ -2540,28 +2360,28 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) s3c_hsotg_handle_rx(hsotg); } - if (gintsts & GINTSTS_ModeMis) { + if (gintsts & GINTSTS_MODEMIS) { dev_warn(hsotg->dev, "warning, mode mismatch triggered\n"); - writel(GINTSTS_ModeMis, hsotg->regs + GINTSTS); + writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS); } - if (gintsts & GINTSTS_USBSusp) { + if (gintsts & GINTSTS_USBSUSP) { dev_info(hsotg->dev, "GINTSTS_USBSusp\n"); - writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS); + writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS); call_gadget(hsotg, suspend); } - if (gintsts & GINTSTS_WkUpInt) { + if (gintsts & GINTSTS_WKUPINT) { dev_info(hsotg->dev, "GINTSTS_WkUpIn\n"); - writel(GINTSTS_WkUpInt, hsotg->regs + GINTSTS); + writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS); call_gadget(hsotg, resume); } - if (gintsts & GINTSTS_ErlySusp) { + if (gintsts & GINTSTS_ERLYSUSP) { dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); - writel(GINTSTS_ErlySusp, hsotg->regs + GINTSTS); + writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS); } /* @@ -2570,18 +2390,18 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) * the occurrence. */ - if (gintsts & GINTSTS_GOUTNakEff) { + if (gintsts & GINTSTS_GOUTNAKEFF) { dev_info(hsotg->dev, "GOUTNakEff triggered\n"); - writel(DCTL_CGOUTNak, hsotg->regs + DCTL); + writel(DCTL_CGOUTNAK, hsotg->regs + DCTL); s3c_hsotg_dump(hsotg); } - if (gintsts & GINTSTS_GINNakEff) { + if (gintsts & GINTSTS_GINNAKEFF) { dev_info(hsotg->dev, "GINNakEff triggered\n"); - writel(DCTL_CGNPInNAK, hsotg->regs + DCTL); + writel(DCTL_CGNPINNAK, hsotg->regs + DCTL); s3c_hsotg_dump(hsotg); } @@ -2645,14 +2465,14 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, spin_lock_irqsave(&hsotg->lock, flags); - epctrl &= ~(DxEPCTL_EPType_MASK | DxEPCTL_MPS_MASK); - epctrl |= DxEPCTL_MPS(mps); + epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK); + epctrl |= DXEPCTL_MPS(mps); /* * mark the endpoint as active, otherwise the core may ignore * transactions entirely for this endpoint */ - epctrl |= DxEPCTL_USBActEp; + epctrl |= DXEPCTL_USBACTEP; /* * set the NAK status on the endpoint, otherwise we might try and @@ -2661,7 +2481,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, * size register hasn't been set. */ - epctrl |= DxEPCTL_SNAK; + epctrl |= DXEPCTL_SNAK; /* update the endpoint state */ s3c_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps); @@ -2677,15 +2497,15 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_ISOC: - epctrl |= DxEPCTL_EPType_Iso; - epctrl |= DxEPCTL_SetEvenFr; + epctrl |= DXEPCTL_EPTYPE_ISO; + epctrl |= DXEPCTL_SETEVENFR; hs_ep->isochronous = 1; if (dir_in) hs_ep->periodic = 1; break; case USB_ENDPOINT_XFER_BULK: - epctrl |= DxEPCTL_EPType_Bulk; + epctrl |= DXEPCTL_EPTYPE_BULK; break; case USB_ENDPOINT_XFER_INT: @@ -2698,14 +2518,14 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, */ hs_ep->periodic = 1; - epctrl |= DxEPCTL_TxFNum(index); + epctrl |= DXEPCTL_TXFNUM(index); } - epctrl |= DxEPCTL_EPType_Intterupt; + epctrl |= DXEPCTL_EPTYPE_INTERRUPT; break; case USB_ENDPOINT_XFER_CONTROL: - epctrl |= DxEPCTL_EPType_Control; + epctrl |= DXEPCTL_EPTYPE_CONTROL; break; } @@ -2714,11 +2534,11 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, * a unique tx-fifo even if it is non-periodic. */ if (dir_in && hsotg->dedicated_fifos) - epctrl |= DxEPCTL_TxFNum(index); + epctrl |= DXEPCTL_TXFNUM(index); /* for non control endpoints, set PID to D0 */ if (index) - epctrl |= DxEPCTL_SetD0PID; + epctrl |= DXEPCTL_SETD0PID; dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", __func__, epctrl); @@ -2763,9 +2583,9 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep) ctrl = readl(hsotg->regs + epctrl_reg); - ctrl &= ~DxEPCTL_EPEna; - ctrl &= ~DxEPCTL_USBActEp; - ctrl |= DxEPCTL_SNAK; + ctrl &= ~DXEPCTL_EPENA; + ctrl &= ~DXEPCTL_USBACTEP; + ctrl |= DXEPCTL_SNAK; dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); writel(ctrl, hsotg->regs + epctrl_reg); @@ -2852,15 +2672,15 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) epctl = readl(hs->regs + epreg); if (value) { - epctl |= DxEPCTL_Stall + DxEPCTL_SNAK; - if (epctl & DxEPCTL_EPEna) - epctl |= DxEPCTL_EPDis; + epctl |= DXEPCTL_STALL + DXEPCTL_SNAK; + if (epctl & DXEPCTL_EPENA) + epctl |= DXEPCTL_EPDIS; } else { - epctl &= ~DxEPCTL_Stall; - xfertype = epctl & DxEPCTL_EPType_MASK; - if (xfertype == DxEPCTL_EPType_Bulk || - xfertype == DxEPCTL_EPType_Intterupt) - epctl |= DxEPCTL_SetD0PID; + epctl &= ~DXEPCTL_STALL; + xfertype = epctl & DXEPCTL_EPTYPE_MASK; + if (xfertype == DXEPCTL_EPTYPE_BULK || + xfertype == DXEPCTL_EPTYPE_INTERRUPT) + epctl |= DXEPCTL_SETD0PID; } writel(epctl, hs->regs + epreg); @@ -2869,13 +2689,13 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) epctl = readl(hs->regs + epreg); if (value) - epctl |= DxEPCTL_Stall; + epctl |= DXEPCTL_STALL; else { - epctl &= ~DxEPCTL_Stall; - xfertype = epctl & DxEPCTL_EPType_MASK; - if (xfertype == DxEPCTL_EPType_Bulk || - xfertype == DxEPCTL_EPType_Intterupt) - epctl |= DxEPCTL_SetD0PID; + epctl &= ~DXEPCTL_STALL; + xfertype = epctl & DXEPCTL_EPTYPE_MASK; + if (xfertype == DXEPCTL_EPTYPE_BULK || + xfertype == DXEPCTL_EPTYPE_INTERRUPT) + epctl |= DXEPCTL_SETD0PID; } writel(epctl, hs->regs + epreg); @@ -2965,22 +2785,22 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg) { /* unmask subset of endpoint interrupts */ - writel(DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | - DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk, - hsotg->regs + DIEPMSK); + writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | + DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK, + hsotg->regs + DIEPMSK); - writel(DOEPMSK_SetupMsk | DOEPMSK_AHBErrMsk | - DOEPMSK_EPDisbldMsk | DOEPMSK_XferComplMsk, - hsotg->regs + DOEPMSK); + writel(DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | + DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK, + hsotg->regs + DOEPMSK); writel(0, hsotg->regs + DAINTMSK); /* Be in disconnected state until gadget is registered */ - __orr32(hsotg->regs + DCTL, DCTL_SftDiscon); + __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); if (0) { /* post global nak until we're ready */ - writel(DCTL_SGNPInNAK | DCTL_SGOUTNak, + writel(DCTL_SGNPINNAK | DCTL_SGOUTNAK, hsotg->regs + DCTL); } @@ -2993,10 +2813,10 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg) s3c_hsotg_init_fifo(hsotg); /* set the PLL on, remove the HNP/SRP and set the PHY */ - writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | (0x5 << 10), + writel(GUSBCFG_PHYIF16 | GUSBCFG_TOUTCAL(7) | (0x5 << 10), hsotg->regs + GUSBCFG); - writel(using_dma(hsotg) ? GAHBCFG_DMAEn : 0x0, + writel(using_dma(hsotg) ? GAHBCFG_DMA_EN : 0x0, hsotg->regs + GAHBCFG); } @@ -3187,8 +3007,8 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg, * code is changed to make each endpoint's direction changeable. */ - ptxfifo = readl(hsotg->regs + DPTXFSIZn(epnum)); - hs_ep->fifo_size = DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4; + ptxfifo = readl(hsotg->regs + DPTXFSIZN(epnum)); + hs_ep->fifo_size = FIFOSIZE_DEPTH_GET(ptxfifo) * 4; /* * if we're using dma, we need to set the next-endpoint pointer @@ -3196,7 +3016,7 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg, */ if (using_dma(hsotg)) { - u32 next = DxEPCTL_NextEp((epnum + 1) % 15); + u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); writel(next, hsotg->regs + DIEPCTL(epnum)); writel(next, hsotg->regs + DOEPCTL(epnum)); } @@ -3250,10 +3070,10 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) /* show periodic fifo settings */ for (idx = 1; idx <= 15; idx++) { - val = readl(regs + DPTXFSIZn(idx)); + val = readl(regs + DPTXFSIZN(idx)); dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, - val >> DPTXFSIZn_DPTxFSize_SHIFT, - val & DPTXFSIZn_DPTxFStAddr_MASK); + val >> FIFOSIZE_DEPTH_SHIFT, + val & FIFOSIZE_STARTADDR_MASK); } for (idx = 0; idx < 15; idx++) { @@ -3368,17 +3188,17 @@ static int fifo_show(struct seq_file *seq, void *v) val = readl(regs + GNPTXFSIZ); seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n", - val >> GNPTXFSIZ_NPTxFDep_SHIFT, - val & GNPTXFSIZ_NPTxFStAddr_MASK); + val >> FIFOSIZE_DEPTH_SHIFT, + val & FIFOSIZE_DEPTH_MASK); seq_puts(seq, "\nPeriodic TXFIFOs:\n"); for (idx = 1; idx <= 15; idx++) { - val = readl(regs + DPTXFSIZn(idx)); + val = readl(regs + DPTXFSIZN(idx)); seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx, - val >> DPTXFSIZn_DPTxFSize_SHIFT, - val & DPTXFSIZn_DPTxFStAddr_MASK); + val >> FIFOSIZE_DEPTH_SHIFT, + val & FIFOSIZE_STARTADDR_MASK); } return 0; @@ -3662,14 +3482,14 @@ static int s3c_hsotg_probe(struct platform_device *pdev) } /* Set default UTMI width */ - hsotg->phyif = GUSBCFG_PHYIf16; + hsotg->phyif = GUSBCFG_PHYIF16; /* * If using the generic PHY framework, check if the PHY bus * width is 8-bit and set the phyif appropriately. */ if (hsotg->phy && (phy_get_bus_width(phy) == 8)) - hsotg->phyif = GUSBCFG_PHYIf8; + hsotg->phyif = GUSBCFG_PHYIF8; if (hsotg->phy) phy_init(hsotg->phy); diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 9c92a3c7588a08..51248b93549321 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -109,6 +109,7 @@ #define GUSBCFG_FSINTF (1 << 5) #define GUSBCFG_ULPI_UTMI_SEL (1 << 4) #define GUSBCFG_PHYIF16 (1 << 3) +#define GUSBCFG_PHYIF8 (0 << 3) #define GUSBCFG_TOUTCAL_MASK (0x7 << 0) #define GUSBCFG_TOUTCAL_SHIFT 0 #define GUSBCFG_TOUTCAL_LIMIT 0x7 @@ -403,6 +404,7 @@ #define FIFOSIZE_DEPTH_SHIFT 16 #define FIFOSIZE_STARTADDR_MASK (0xffff << 0) #define FIFOSIZE_STARTADDR_SHIFT 0 +#define FIFOSIZE_DEPTH_GET(_x) (((_x) >> 16) & 0xffff) /* Device mode registers */ @@ -519,11 +521,11 @@ #define DXEPCTL_STALL (1 << 21) #define DXEPCTL_SNP (1 << 20) #define DXEPCTL_EPTYPE_MASK (0x3 << 18) -#define DXEPCTL_EPTYPE_SHIFT 18 -#define DXEPCTL_EPTYPE_CONTROL 0 -#define DXEPCTL_EPTYPE_ISO 1 -#define DXEPCTL_EPTYPE_BULK 2 -#define DXEPCTL_EPTYPE_INTTERUPT 3 +#define DXEPCTL_EPTYPE_CONTROL (0x0 << 18) +#define DXEPCTL_EPTYPE_ISO (0x1 << 18) +#define DXEPCTL_EPTYPE_BULK (0x2 << 18) +#define DXEPCTL_EPTYPE_INTERRUPT (0x3 << 18) + #define DXEPCTL_NAKSTS (1 << 17) #define DXEPCTL_DPID (1 << 16) #define DXEPCTL_EOFRNUM (1 << 16) diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index e2c730fc9a90c5..8eb996e4f05883 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -44,7 +44,7 @@ comment "Platform Glue Driver Support" config USB_DWC3_OMAP tristate "Texas Instruments OMAP5 and similar Platforms" - depends on EXTCON + depends on EXTCON && (ARCH_OMAP2PLUS || COMPILE_TEST) default USB_DWC3 help Some platforms from Texas Instruments like OMAP5, DRA7xxx and @@ -54,6 +54,7 @@ config USB_DWC3_OMAP config USB_DWC3_EXYNOS tristate "Samsung Exynos Platform" + depends on ARCH_EXYNOS || COMPILE_TEST default USB_DWC3 help Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside, @@ -72,6 +73,7 @@ config USB_DWC3_PCI config USB_DWC3_KEYSTONE tristate "Texas Instruments Keystone2 Platforms" + depends on ARCH_KEYSTONE || COMPILE_TEST default USB_DWC3 help Support of USB2/3 functionality in TI Keystone2 platforms. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 10aaaae9af25e8..0d1895a80671e4 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -486,70 +486,20 @@ static void dwc3_core_exit(struct dwc3 *dwc) phy_exit(dwc->usb3_generic_phy); } -#define DWC3_ALIGN_MASK (16 - 1) - -static int dwc3_probe(struct platform_device *pdev) +static int dwc3_core_get_phy(struct dwc3 *dwc) { - struct device *dev = &pdev->dev; - struct dwc3_platform_data *pdata = dev_get_platdata(dev); + struct device *dev = dwc->dev; struct device_node *node = dev->of_node; - struct resource *res; - struct dwc3 *dwc; - - int ret = -ENOMEM; - - void __iomem *regs; - void *mem; - - mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); - if (!mem) { - dev_err(dev, "not enough memory\n"); - return -ENOMEM; - } - dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); - dwc->mem = mem; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "missing IRQ\n"); - return -ENODEV; - } - dwc->xhci_resources[1].start = res->start; - dwc->xhci_resources[1].end = res->end; - dwc->xhci_resources[1].flags = res->flags; - dwc->xhci_resources[1].name = res->name; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "missing memory resource\n"); - return -ENODEV; - } + int ret; if (node) { - dwc->maximum_speed = of_usb_get_maximum_speed(node); - dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); - - dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); - dwc->dr_mode = of_usb_get_dr_mode(node); - } else if (pdata) { - dwc->maximum_speed = pdata->maximum_speed; - - dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); - dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); - - dwc->needs_fifo_resize = pdata->tx_fifo_resize; - dwc->dr_mode = pdata->dr_mode; } else { dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); } - /* default to superspeed if no maximum_speed passed */ - if (dwc->maximum_speed == USB_SPEED_UNKNOWN) - dwc->maximum_speed = USB_SPEED_SUPER; - if (IS_ERR(dwc->usb2_phy)) { ret = PTR_ERR(dwc->usb2_phy); if (ret == -ENXIO || ret == -ENODEV) { @@ -600,6 +550,132 @@ static int dwc3_probe(struct platform_device *pdev) } } + return 0; +} + +static int dwc3_core_init_mode(struct dwc3 *dwc) +{ + struct device *dev = dwc->dev; + int ret; + + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + ret = dwc3_gadget_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize gadget\n"); + return ret; + } + break; + case USB_DR_MODE_HOST: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); + ret = dwc3_host_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize host\n"); + return ret; + } + break; + case USB_DR_MODE_OTG: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); + ret = dwc3_host_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize host\n"); + return ret; + } + + ret = dwc3_gadget_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize gadget\n"); + return ret; + } + break; + default: + dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); + return -EINVAL; + } + + return 0; +} + +static void dwc3_core_exit_mode(struct dwc3 *dwc) +{ + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dwc3_gadget_exit(dwc); + break; + case USB_DR_MODE_HOST: + dwc3_host_exit(dwc); + break; + case USB_DR_MODE_OTG: + dwc3_host_exit(dwc); + dwc3_gadget_exit(dwc); + break; + default: + /* do nothing */ + break; + } +} + +#define DWC3_ALIGN_MASK (16 - 1) + +static int dwc3_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dwc3_platform_data *pdata = dev_get_platdata(dev); + struct device_node *node = dev->of_node; + struct resource *res; + struct dwc3 *dwc; + + int ret = -ENOMEM; + + void __iomem *regs; + void *mem; + + mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); + if (!mem) { + dev_err(dev, "not enough memory\n"); + return -ENOMEM; + } + dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); + dwc->mem = mem; + dwc->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "missing IRQ\n"); + return -ENODEV; + } + dwc->xhci_resources[1].start = res->start; + dwc->xhci_resources[1].end = res->end; + dwc->xhci_resources[1].flags = res->flags; + dwc->xhci_resources[1].name = res->name; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "missing memory resource\n"); + return -ENODEV; + } + + if (node) { + dwc->maximum_speed = of_usb_get_maximum_speed(node); + + dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); + dwc->dr_mode = of_usb_get_dr_mode(node); + } else if (pdata) { + dwc->maximum_speed = pdata->maximum_speed; + + dwc->needs_fifo_resize = pdata->tx_fifo_resize; + dwc->dr_mode = pdata->dr_mode; + } + + /* default to superspeed if no maximum_speed passed */ + if (dwc->maximum_speed == USB_SPEED_UNKNOWN) + dwc->maximum_speed = USB_SPEED_SUPER; + + ret = dwc3_core_get_phy(dwc); + if (ret) + return ret; + dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; @@ -621,7 +697,6 @@ static int dwc3_probe(struct platform_device *pdev) dwc->regs = regs; dwc->regs_size = resource_size(res); - dwc->dev = dev; dev->dma_mask = dev->parent->dma_mask; dev->dma_parms = dev->parent->dma_parms; @@ -670,41 +745,9 @@ static int dwc3_probe(struct platform_device *pdev) goto err_usb3phy_power; } - switch (dwc->dr_mode) { - case USB_DR_MODE_PERIPHERAL: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); - ret = dwc3_gadget_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize gadget\n"); - goto err2; - } - break; - case USB_DR_MODE_HOST: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); - ret = dwc3_host_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - goto err2; - } - break; - case USB_DR_MODE_OTG: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); - ret = dwc3_host_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - goto err2; - } - - ret = dwc3_gadget_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize gadget\n"); - goto err2; - } - break; - default: - dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); + ret = dwc3_core_init_mode(dwc); + if (ret) goto err2; - } ret = dwc3_debugfs_init(dwc); if (ret) { @@ -717,21 +760,7 @@ static int dwc3_probe(struct platform_device *pdev) return 0; err3: - switch (dwc->dr_mode) { - case USB_DR_MODE_PERIPHERAL: - dwc3_gadget_exit(dwc); - break; - case USB_DR_MODE_HOST: - dwc3_host_exit(dwc); - break; - case USB_DR_MODE_OTG: - dwc3_host_exit(dwc); - dwc3_gadget_exit(dwc); - break; - default: - /* do nothing */ - break; - } + dwc3_core_exit_mode(dwc); err2: dwc3_event_buffers_cleanup(dwc); @@ -766,23 +795,7 @@ static int dwc3_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); dwc3_debugfs_exit(dwc); - - switch (dwc->dr_mode) { - case USB_DR_MODE_PERIPHERAL: - dwc3_gadget_exit(dwc); - break; - case USB_DR_MODE_HOST: - dwc3_host_exit(dwc); - break; - case USB_DR_MODE_OTG: - dwc3_host_exit(dwc); - dwc3_gadget_exit(dwc); - break; - default: - /* do nothing */ - break; - } - + dwc3_core_exit_mode(dwc); dwc3_event_buffers_cleanup(dwc); dwc3_free_event_buffers(dwc); dwc3_core_exit(dwc); diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 28c8ad79f5e6c5..0ed85834bfec0a 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -24,9 +24,10 @@ #include #include #include -#include +#include #include #include +#include struct dwc3_exynos { struct platform_device *usb2_phy; @@ -34,17 +35,19 @@ struct dwc3_exynos { struct device *dev; struct clk *clk; + struct regulator *vdd33; + struct regulator *vdd10; }; static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) { - struct usb_phy_gen_xceiv_platform_data pdata; + struct usb_phy_generic_platform_data pdata; struct platform_device *pdev; int ret; memset(&pdata, 0x00, sizeof(pdata)); - pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); + pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO); if (!pdev) return -ENOMEM; @@ -56,7 +59,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) if (ret) goto err1; - pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); + pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO); if (!pdev) { ret = -ENOMEM; goto err1; @@ -144,20 +147,46 @@ static int dwc3_exynos_probe(struct platform_device *pdev) clk_prepare_enable(exynos->clk); + exynos->vdd33 = devm_regulator_get(dev, "vdd33"); + if (IS_ERR(exynos->vdd33)) { + ret = PTR_ERR(exynos->vdd33); + goto err2; + } + ret = regulator_enable(exynos->vdd33); + if (ret) { + dev_err(dev, "Failed to enable VDD33 supply\n"); + goto err2; + } + + exynos->vdd10 = devm_regulator_get(dev, "vdd10"); + if (IS_ERR(exynos->vdd10)) { + ret = PTR_ERR(exynos->vdd10); + goto err3; + } + ret = regulator_enable(exynos->vdd10); + if (ret) { + dev_err(dev, "Failed to enable VDD10 supply\n"); + goto err3; + } + if (node) { ret = of_platform_populate(node, NULL, NULL, dev); if (ret) { dev_err(dev, "failed to add dwc3 core\n"); - goto err2; + goto err4; } } else { dev_err(dev, "no device node, failed to add dwc3 core\n"); ret = -ENODEV; - goto err2; + goto err4; } return 0; +err4: + regulator_disable(exynos->vdd10); +err3: + regulator_disable(exynos->vdd33); err2: clk_disable_unprepare(clk); err1: @@ -174,6 +203,9 @@ static int dwc3_exynos_remove(struct platform_device *pdev) clk_disable_unprepare(exynos->clk); + regulator_disable(exynos->vdd33); + regulator_disable(exynos->vdd10); + return 0; } @@ -192,12 +224,27 @@ static int dwc3_exynos_suspend(struct device *dev) clk_disable(exynos->clk); + regulator_disable(exynos->vdd33); + regulator_disable(exynos->vdd10); + return 0; } static int dwc3_exynos_resume(struct device *dev) { struct dwc3_exynos *exynos = dev_get_drvdata(dev); + int ret; + + ret = regulator_enable(exynos->vdd33); + if (ret) { + dev_err(dev, "Failed to enable VDD33 supply\n"); + return ret; + } + ret = regulator_enable(exynos->vdd10); + if (ret) { + dev_err(dev, "Failed to enable VDD10 supply\n"); + return ret; + } clk_enable(exynos->clk); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index f393c183cc69dd..1ed95e0386ebd4 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -23,7 +23,7 @@ #include #include -#include +#include /* FIXME define these in */ #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 @@ -40,13 +40,13 @@ struct dwc3_pci { static int dwc3_pci_register_phys(struct dwc3_pci *glue) { - struct usb_phy_gen_xceiv_platform_data pdata; + struct usb_phy_generic_platform_data pdata; struct platform_device *pdev; int ret; memset(&pdata, 0x00, sizeof(pdata)); - pdev = platform_device_alloc("usb_phy_gen_xceiv", 0); + pdev = platform_device_alloc("usb_phy_generic", 0); if (!pdev) return -ENOMEM; @@ -58,7 +58,7 @@ static int dwc3_pci_register_phys(struct dwc3_pci *glue) if (ret) goto err1; - pdev = platform_device_alloc("usb_phy_gen_xceiv", 1); + pdev = platform_device_alloc("usb_phy_generic", 1); if (!pdev) { ret = -ENOMEM; goto err1; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 70715eeededda3..54da8c8b47a9cb 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -298,11 +298,76 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd) } } +static const char *dwc3_gadget_generic_cmd_string(u8 cmd) +{ + switch (cmd) { + case DWC3_DGCMD_SET_LMP: + return "Set LMP"; + case DWC3_DGCMD_SET_PERIODIC_PAR: + return "Set Periodic Parameters"; + case DWC3_DGCMD_XMIT_FUNCTION: + return "Transmit Function Wake Device Notification"; + case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO: + return "Set Scratchpad Buffer Array Address Lo"; + case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI: + return "Set Scratchpad Buffer Array Address Hi"; + case DWC3_DGCMD_SELECTED_FIFO_FLUSH: + return "Selected FIFO Flush"; + case DWC3_DGCMD_ALL_FIFO_FLUSH: + return "All FIFO Flush"; + case DWC3_DGCMD_SET_ENDPOINT_NRDY: + return "Set Endpoint NRDY"; + case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK: + return "Run SoC Bus Loopback Test"; + default: + return "UNKNOWN"; + } +} + +static const char *dwc3_gadget_link_string(enum dwc3_link_state link_state) +{ + switch (link_state) { + case DWC3_LINK_STATE_U0: + return "U0"; + case DWC3_LINK_STATE_U1: + return "U1"; + case DWC3_LINK_STATE_U2: + return "U2"; + case DWC3_LINK_STATE_U3: + return "U3"; + case DWC3_LINK_STATE_SS_DIS: + return "SS.Disabled"; + case DWC3_LINK_STATE_RX_DET: + return "RX.Detect"; + case DWC3_LINK_STATE_SS_INACT: + return "SS.Inactive"; + case DWC3_LINK_STATE_POLL: + return "Polling"; + case DWC3_LINK_STATE_RECOV: + return "Recovery"; + case DWC3_LINK_STATE_HRESET: + return "Hot Reset"; + case DWC3_LINK_STATE_CMPLY: + return "Compliance"; + case DWC3_LINK_STATE_LPBK: + return "Loopback"; + case DWC3_LINK_STATE_RESET: + return "Reset"; + case DWC3_LINK_STATE_RESUME: + return "Resume"; + default: + return "UNKNOWN link state\n"; + } +} + int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) { u32 timeout = 500; u32 reg; + dev_vdbg(dwc->dev, "generic cmd '%s' [%d] param %08x\n", + dwc3_gadget_generic_cmd_string(cmd), cmd, param); + dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param); dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); @@ -332,9 +397,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, u32 timeout = 500; u32 reg; - dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n", + dev_vdbg(dwc->dev, "%s: cmd '%s' [%d] params %08x %08x %08x\n", dep->name, - dwc3_gadget_ep_cmd_string(cmd), params->param0, + dwc3_gadget_ep_cmd_string(cmd), cmd, params->param0, params->param1, params->param2); dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); @@ -604,6 +669,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dwc3_remove_requests(dwc, dep); + /* make sure HW endpoint isn't stalled */ + if (dep->flags & DWC3_EP_STALL) + __dwc3_gadget_ep_set_halt(dep, 0); + reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); reg &= ~DWC3_DALEPENA_EP(dep->number); dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); @@ -2441,8 +2510,6 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, } } - dwc->link_state = next; - switch (next) { case DWC3_LINK_STATE_U1: if (dwc->speed == USB_SPEED_SUPER) @@ -2460,7 +2527,11 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, break; } - dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state); + dev_vdbg(dwc->dev, "link change: %s [%d] -> %s [%d]\n", + dwc3_gadget_link_string(dwc->link_state), + dwc->link_state, dwc3_gadget_link_string(next), next); + + dwc->link_state = next; } static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 3557c7e5040d33..7fca52bfe5b1ec 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -300,12 +300,6 @@ config USB_PXA27X dynamically linked module called "pxa27x_udc" and force all gadget drivers to also be dynamically linked. -config USB_S3C_HSOTG - tristate "Designware/S3C HS/OtG USB Device controller" - help - The Designware USB2.0 high-speed gadget controller - integrated into many SoCs. - config USB_S3C2410 tristate "S3C2410 USB Device Controller" depends on ARCH_S3C24XX diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 5f150bc1b4bc92..49514ea60a98a7 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -26,7 +26,6 @@ fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o obj-$(CONFIG_USB_M66592) += m66592-udc.o obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o -obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o obj-$(CONFIG_USB_EG20T) += pch_udc.o diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 7d1cc01796b60f..dcead559a61e93 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1005,7 +1005,7 @@ void unregister_gadget_item(struct config_item *item) unregister_gadget(gi); } -EXPORT_SYMBOL(unregister_gadget_item); +EXPORT_SYMBOL_GPL(unregister_gadget_item); static int __init gadget_cfs_init(void) { diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 1e12b3ee56fd83..de92bd3a4e1a65 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -190,7 +190,7 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data, /* Devices management *******************************************************/ DEFINE_MUTEX(ffs_lock); -EXPORT_SYMBOL(ffs_lock); +EXPORT_SYMBOL_GPL(ffs_lock); static struct ffs_dev *_ffs_find_dev(const char *name); static struct ffs_dev *_ffs_alloc_dev(void); @@ -2883,7 +2883,7 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name) return ret; } -EXPORT_SYMBOL(ffs_name_dev); +EXPORT_SYMBOL_GPL(ffs_name_dev); int ffs_single_dev(struct ffs_dev *dev) { @@ -2900,7 +2900,7 @@ int ffs_single_dev(struct ffs_dev *dev) ffs_dev_unlock(); return ret; } -EXPORT_SYMBOL(ffs_single_dev); +EXPORT_SYMBOL_GPL(ffs_single_dev); /* * ffs_lock must be taken by the caller of this function diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 9a4f49dc6ac4f8..004b3a1b2a7a73 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -834,7 +834,7 @@ void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net) opts->borrowed_net = opts->bound = true; opts->net = net; } -EXPORT_SYMBOL(rndis_borrow_net); +EXPORT_SYMBOL_GPL(rndis_borrow_net); static inline struct f_rndis_opts *to_f_rndis_opts(struct config_item *item) { diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index df4a0dcbc99350..1ea8baf33333be 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -276,7 +276,7 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } net = gether_connect(&geth->port); - return PTR_RET(net); + return PTR_ERR_OR_ZERO(net); } static void geth_disable(struct usb_function *f) diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c index f984ee75324d33..4966971d6978fb 100644 --- a/drivers/usb/gadget/gr_udc.c +++ b/drivers/usb/gadget/gr_udc.c @@ -143,6 +143,7 @@ static void gr_seq_ep_show(struct seq_file *seq, struct gr_ep *ep) seq_printf(seq, " wedged = %d\n", ep->wedged); seq_printf(seq, " callback = %d\n", ep->callback); seq_printf(seq, " maxpacket = %d\n", ep->ep.maxpacket); + seq_printf(seq, " maxpacket_limit = %d\n", ep->ep.maxpacket_limit); seq_printf(seq, " bytes_per_buffer = %d\n", ep->bytes_per_buffer); if (mode == 1 || mode == 3) seq_printf(seq, " nt = %d\n", @@ -1541,6 +1542,10 @@ static int gr_ep_enable(struct usb_ep *_ep, } else if (max == 0) { dev_err(dev->dev, "Max payload cannot be set to 0\n"); return -EINVAL; + } else if (max > ep->ep.maxpacket_limit) { + dev_err(dev->dev, "Requested max payload %d > limit %d\n", + max, ep->ep.maxpacket_limit); + return -EINVAL; } spin_lock(&ep->dev->lock); @@ -1985,8 +1990,8 @@ static int gr_ep_init(struct gr_udc *dev, int num, int is_in, u32 maxplimit) INIT_LIST_HEAD(&ep->queue); if (num == 0) { - _req = gr_alloc_request(&ep->ep, GFP_KERNEL); - buf = devm_kzalloc(dev->dev, PAGE_SIZE, GFP_DMA | GFP_KERNEL); + _req = gr_alloc_request(&ep->ep, GFP_ATOMIC); + buf = devm_kzalloc(dev->dev, PAGE_SIZE, GFP_DMA | GFP_ATOMIC); if (!_req || !buf) { /* possible _req freed by gr_probe via gr_remove */ return -ENOMEM; @@ -2020,9 +2025,7 @@ static int gr_udc_init(struct gr_udc *dev) u32 dmactrl_val; int i; int ret = 0; - u32 *bufsizes; u32 bufsize; - int len; gr_set_address(dev, 0); @@ -2033,19 +2036,17 @@ static int gr_udc_init(struct gr_udc *dev) INIT_LIST_HEAD(&dev->ep_list); gr_set_ep0state(dev, GR_EP0_DISCONNECT); - bufsizes = (u32 *)of_get_property(np, "epobufsizes", &len); - len /= sizeof(u32); for (i = 0; i < dev->nepo; i++) { - bufsize = (bufsizes && i < len) ? bufsizes[i] : 1024; + if (of_property_read_u32_index(np, "epobufsizes", i, &bufsize)) + bufsize = 1024; ret = gr_ep_init(dev, i, 0, bufsize); if (ret) return ret; } - bufsizes = (u32 *)of_get_property(np, "epibufsizes", &len); - len /= sizeof(u32); for (i = 0; i < dev->nepi; i++) { - bufsize = (bufsizes && i < len) ? bufsizes[i] : 1024; + if (of_property_read_u32_index(np, "epibufsizes", i, &bufsize)) + bufsize = 1024; ret = gr_ep_init(dev, i, 1, bufsize); if (ret) return ret; @@ -2065,9 +2066,9 @@ static int gr_udc_init(struct gr_udc *dev) return 0; } -static int gr_remove(struct platform_device *ofdev) +static int gr_remove(struct platform_device *pdev) { - struct gr_udc *dev = dev_get_drvdata(&ofdev->dev); + struct gr_udc *dev = platform_get_drvdata(pdev); if (dev->added) usb_del_gadget_udc(&dev->gadget); /* Shuts everything down */ @@ -2077,7 +2078,7 @@ static int gr_remove(struct platform_device *ofdev) gr_dfs_delete(dev); if (dev->desc_pool) dma_pool_destroy(dev->desc_pool); - dev_set_drvdata(&ofdev->dev, NULL); + platform_set_drvdata(pdev, NULL); gr_free_request(&dev->epi[0].ep, &dev->ep0reqi->req); gr_free_request(&dev->epo[0].ep, &dev->ep0reqo->req); @@ -2090,7 +2091,7 @@ static int gr_request_irq(struct gr_udc *dev, int irq) IRQF_SHARED, driver_name, dev); } -static int gr_probe(struct platform_device *ofdev) +static int gr_probe(struct platform_device *pdev) { struct gr_udc *dev; struct resource *res; @@ -2098,30 +2099,32 @@ static int gr_probe(struct platform_device *ofdev) int retval; u32 status; - dev = devm_kzalloc(&ofdev->dev, sizeof(*dev), GFP_KERNEL); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - dev->dev = &ofdev->dev; + dev->dev = &pdev->dev; - res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev->dev, res); if (IS_ERR(regs)) return PTR_ERR(regs); - dev->irq = irq_of_parse_and_map(dev->dev->of_node, 0); - if (!dev->irq) { + dev->irq = platform_get_irq(pdev, 0); + if (dev->irq <= 0) { dev_err(dev->dev, "No irq found\n"); return -ENODEV; } /* Some core configurations has separate irqs for IN and OUT events */ - dev->irqi = irq_of_parse_and_map(dev->dev->of_node, 1); - if (dev->irqi) { - dev->irqo = irq_of_parse_and_map(dev->dev->of_node, 2); - if (!dev->irqo) { + dev->irqi = platform_get_irq(pdev, 1); + if (dev->irqi > 0) { + dev->irqo = platform_get_irq(pdev, 2); + if (dev->irqo <= 0) { dev_err(dev->dev, "Found irqi but not irqo\n"); return -ENODEV; } + } else { + dev->irqi = 0; } dev->gadget.name = driver_name; @@ -2132,7 +2135,7 @@ static int gr_probe(struct platform_device *ofdev) spin_lock_init(&dev->lock); dev->regs = regs; - dev_set_drvdata(&ofdev->dev, dev); + platform_set_drvdata(pdev, dev); /* Determine number of endpoints and data interface mode */ status = gr_read32(&dev->regs->status); @@ -2204,7 +2207,7 @@ static int gr_probe(struct platform_device *ofdev) spin_unlock(&dev->lock); if (retval) - gr_remove(ofdev); + gr_remove(pdev); return retval; } diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 7ed452d90f4d76..95d2324f69778f 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -761,7 +761,7 @@ int rndis_signal_connect(int configNr) return rndis_indicate_status_msg(configNr, RNDIS_STATUS_MEDIA_CONNECT); } -EXPORT_SYMBOL(rndis_signal_connect); +EXPORT_SYMBOL_GPL(rndis_signal_connect); int rndis_signal_disconnect(int configNr) { @@ -770,7 +770,7 @@ int rndis_signal_disconnect(int configNr) return rndis_indicate_status_msg(configNr, RNDIS_STATUS_MEDIA_DISCONNECT); } -EXPORT_SYMBOL(rndis_signal_disconnect); +EXPORT_SYMBOL_GPL(rndis_signal_disconnect); void rndis_uninit(int configNr) { @@ -785,13 +785,13 @@ void rndis_uninit(int configNr) while ((buf = rndis_get_next_response(configNr, &length))) rndis_free_response(configNr, buf); } -EXPORT_SYMBOL(rndis_uninit); +EXPORT_SYMBOL_GPL(rndis_uninit); void rndis_set_host_mac(int configNr, const u8 *addr) { rndis_per_dev_params[configNr].host_mac = addr; } -EXPORT_SYMBOL(rndis_set_host_mac); +EXPORT_SYMBOL_GPL(rndis_set_host_mac); /* * Message Parser @@ -874,7 +874,7 @@ int rndis_msg_parser(u8 configNr, u8 *buf) return -ENOTSUPP; } -EXPORT_SYMBOL(rndis_msg_parser); +EXPORT_SYMBOL_GPL(rndis_msg_parser); int rndis_register(void (*resp_avail)(void *v), void *v) { @@ -896,7 +896,7 @@ int rndis_register(void (*resp_avail)(void *v), void *v) return -ENODEV; } -EXPORT_SYMBOL(rndis_register); +EXPORT_SYMBOL_GPL(rndis_register); void rndis_deregister(int configNr) { @@ -905,7 +905,7 @@ void rndis_deregister(int configNr) if (configNr >= RNDIS_MAX_CONFIGS) return; rndis_per_dev_params[configNr].used = 0; } -EXPORT_SYMBOL(rndis_deregister); +EXPORT_SYMBOL_GPL(rndis_deregister); int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter) { @@ -919,7 +919,7 @@ int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter) return 0; } -EXPORT_SYMBOL(rndis_set_param_dev); +EXPORT_SYMBOL_GPL(rndis_set_param_dev); int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr) { @@ -932,7 +932,7 @@ int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr) return 0; } -EXPORT_SYMBOL(rndis_set_param_vendor); +EXPORT_SYMBOL_GPL(rndis_set_param_vendor); int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed) { @@ -944,7 +944,7 @@ int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed) return 0; } -EXPORT_SYMBOL(rndis_set_param_medium); +EXPORT_SYMBOL_GPL(rndis_set_param_medium); void rndis_add_hdr(struct sk_buff *skb) { @@ -959,7 +959,7 @@ void rndis_add_hdr(struct sk_buff *skb) header->DataOffset = cpu_to_le32(36); header->DataLength = cpu_to_le32(skb->len - sizeof(*header)); } -EXPORT_SYMBOL(rndis_add_hdr); +EXPORT_SYMBOL_GPL(rndis_add_hdr); void rndis_free_response(int configNr, u8 *buf) { @@ -976,7 +976,7 @@ void rndis_free_response(int configNr, u8 *buf) } } } -EXPORT_SYMBOL(rndis_free_response); +EXPORT_SYMBOL_GPL(rndis_free_response); u8 *rndis_get_next_response(int configNr, u32 *length) { @@ -998,7 +998,7 @@ u8 *rndis_get_next_response(int configNr, u32 *length) return NULL; } -EXPORT_SYMBOL(rndis_get_next_response); +EXPORT_SYMBOL_GPL(rndis_get_next_response); static rndis_resp_t *rndis_add_response(int configNr, u32 length) { @@ -1042,7 +1042,7 @@ int rndis_rm_hdr(struct gether *port, skb_queue_tail(list, skb); return 0; } -EXPORT_SYMBOL(rndis_rm_hdr); +EXPORT_SYMBOL_GPL(rndis_rm_hdr); #ifdef CONFIG_USB_GADGET_DEBUG_FILES diff --git a/drivers/usb/gadget/s3c-hsotg.h b/drivers/usb/gadget/s3c-hsotg.h deleted file mode 100644 index 85f549ff8c1fa8..00000000000000 --- a/drivers/usb/gadget/s3c-hsotg.h +++ /dev/null @@ -1,378 +0,0 @@ -/* drivers/usb/gadget/s3c-hsotg.h - * - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * USB2.0 Highspeed/OtG Synopsis DWC2 device block registers - * - * 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 __REGS_USB_HSOTG_H -#define __REGS_USB_HSOTG_H __FILE__ - -#define HSOTG_REG(x) (x) - -#define GOTGCTL HSOTG_REG(0x000) -#define GOTGCTL_BSESVLD (1 << 19) -#define GOTGCTL_ASESVLD (1 << 18) -#define GOTGCTL_DBNC_SHORT (1 << 17) -#define GOTGCTL_CONID_B (1 << 16) -#define GOTGCTL_DEVHNPEN (1 << 11) -#define GOTGCTL_HSSETHNPEN (1 << 10) -#define GOTGCTL_HNPREQ (1 << 9) -#define GOTGCTL_HSTNEGSCS (1 << 8) -#define GOTGCTL_SESREQ (1 << 1) -#define GOTGCTL_SESREQSCS (1 << 0) - -#define GOTGINT HSOTG_REG(0x004) -#define GOTGINT_DbnceDone (1 << 19) -#define GOTGINT_ADevTOUTChg (1 << 18) -#define GOTGINT_HstNegDet (1 << 17) -#define GOTGINT_HstnegSucStsChng (1 << 9) -#define GOTGINT_SesReqSucStsChng (1 << 8) -#define GOTGINT_SesEndDet (1 << 2) - -#define GAHBCFG HSOTG_REG(0x008) -#define GAHBCFG_PTxFEmpLvl (1 << 8) -#define GAHBCFG_NPTxFEmpLvl (1 << 7) -#define GAHBCFG_DMAEn (1 << 5) -#define GAHBCFG_HBstLen_MASK (0xf << 1) -#define GAHBCFG_HBstLen_SHIFT (1) -#define GAHBCFG_HBstLen_Single (0x0 << 1) -#define GAHBCFG_HBstLen_Incr (0x1 << 1) -#define GAHBCFG_HBstLen_Incr4 (0x3 << 1) -#define GAHBCFG_HBstLen_Incr8 (0x5 << 1) -#define GAHBCFG_HBstLen_Incr16 (0x7 << 1) -#define GAHBCFG_GlblIntrEn (1 << 0) - -#define GUSBCFG HSOTG_REG(0x00C) -#define GUSBCFG_PHYLPClkSel (1 << 15) -#define GUSBCFG_HNPCap (1 << 9) -#define GUSBCFG_SRPCap (1 << 8) -#define GUSBCFG_PHYIf16 (1 << 3) -#define GUSBCFG_PHYIf8 (0 << 3) -#define GUSBCFG_TOutCal_MASK (0x7 << 0) -#define GUSBCFG_TOutCal_SHIFT (0) -#define GUSBCFG_TOutCal_LIMIT (0x7) -#define GUSBCFG_TOutCal(_x) ((_x) << 0) - -#define GRSTCTL HSOTG_REG(0x010) - -#define GRSTCTL_AHBIdle (1 << 31) -#define GRSTCTL_DMAReq (1 << 30) -#define GRSTCTL_TxFNum_MASK (0x1f << 6) -#define GRSTCTL_TxFNum_SHIFT (6) -#define GRSTCTL_TxFNum_LIMIT (0x1f) -#define GRSTCTL_TxFNum(_x) ((_x) << 6) -#define GRSTCTL_TxFFlsh (1 << 5) -#define GRSTCTL_RxFFlsh (1 << 4) -#define GRSTCTL_INTknQFlsh (1 << 3) -#define GRSTCTL_FrmCntrRst (1 << 2) -#define GRSTCTL_HSftRst (1 << 1) -#define GRSTCTL_CSftRst (1 << 0) - -#define GINTSTS HSOTG_REG(0x014) -#define GINTMSK HSOTG_REG(0x018) - -#define GINTSTS_WkUpInt (1 << 31) -#define GINTSTS_SessReqInt (1 << 30) -#define GINTSTS_DisconnInt (1 << 29) -#define GINTSTS_ConIDStsChng (1 << 28) -#define GINTSTS_PTxFEmp (1 << 26) -#define GINTSTS_HChInt (1 << 25) -#define GINTSTS_PrtInt (1 << 24) -#define GINTSTS_FetSusp (1 << 22) -#define GINTSTS_incompIP (1 << 21) -#define GINTSTS_IncomplSOIN (1 << 20) -#define GINTSTS_OEPInt (1 << 19) -#define GINTSTS_IEPInt (1 << 18) -#define GINTSTS_EPMis (1 << 17) -#define GINTSTS_EOPF (1 << 15) -#define GINTSTS_ISOutDrop (1 << 14) -#define GINTSTS_EnumDone (1 << 13) -#define GINTSTS_USBRst (1 << 12) -#define GINTSTS_USBSusp (1 << 11) -#define GINTSTS_ErlySusp (1 << 10) -#define GINTSTS_GOUTNakEff (1 << 7) -#define GINTSTS_GINNakEff (1 << 6) -#define GINTSTS_NPTxFEmp (1 << 5) -#define GINTSTS_RxFLvl (1 << 4) -#define GINTSTS_SOF (1 << 3) -#define GINTSTS_OTGInt (1 << 2) -#define GINTSTS_ModeMis (1 << 1) -#define GINTSTS_CurMod_Host (1 << 0) - -#define GRXSTSR HSOTG_REG(0x01C) -#define GRXSTSP HSOTG_REG(0x020) - -#define GRXSTS_FN_MASK (0x7f << 25) -#define GRXSTS_FN_SHIFT (25) - -#define GRXSTS_PktSts_MASK (0xf << 17) -#define GRXSTS_PktSts_SHIFT (17) -#define GRXSTS_PktSts_GlobalOutNAK (0x1 << 17) -#define GRXSTS_PktSts_OutRX (0x2 << 17) -#define GRXSTS_PktSts_OutDone (0x3 << 17) -#define GRXSTS_PktSts_SetupDone (0x4 << 17) -#define GRXSTS_PktSts_SetupRX (0x6 << 17) - -#define GRXSTS_DPID_MASK (0x3 << 15) -#define GRXSTS_DPID_SHIFT (15) -#define GRXSTS_ByteCnt_MASK (0x7ff << 4) -#define GRXSTS_ByteCnt_SHIFT (4) -#define GRXSTS_EPNum_MASK (0xf << 0) -#define GRXSTS_EPNum_SHIFT (0) - -#define GRXFSIZ HSOTG_REG(0x024) - -#define GNPTXFSIZ HSOTG_REG(0x028) - -#define GNPTXFSIZ_NPTxFDep_MASK (0xffff << 16) -#define GNPTXFSIZ_NPTxFDep_SHIFT (16) -#define GNPTXFSIZ_NPTxFDep_LIMIT (0xffff) -#define GNPTXFSIZ_NPTxFDep(_x) ((_x) << 16) -#define GNPTXFSIZ_NPTxFStAddr_MASK (0xffff << 0) -#define GNPTXFSIZ_NPTxFStAddr_SHIFT (0) -#define GNPTXFSIZ_NPTxFStAddr_LIMIT (0xffff) -#define GNPTXFSIZ_NPTxFStAddr(_x) ((_x) << 0) - -#define GNPTXSTS HSOTG_REG(0x02C) - -#define GNPTXSTS_NPtxQTop_MASK (0x7f << 24) -#define GNPTXSTS_NPtxQTop_SHIFT (24) - -#define GNPTXSTS_NPTxQSpcAvail_MASK (0xff << 16) -#define GNPTXSTS_NPTxQSpcAvail_SHIFT (16) -#define GNPTXSTS_NPTxQSpcAvail_GET(_v) (((_v) >> 16) & 0xff) - -#define GNPTXSTS_NPTxFSpcAvail_MASK (0xffff << 0) -#define GNPTXSTS_NPTxFSpcAvail_SHIFT (0) -#define GNPTXSTS_NPTxFSpcAvail_GET(_v) (((_v) >> 0) & 0xffff) - - -#define HPTXFSIZ HSOTG_REG(0x100) - -#define DPTXFSIZn(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4)) - -#define DPTXFSIZn_DPTxFSize_MASK (0xffff << 16) -#define DPTXFSIZn_DPTxFSize_SHIFT (16) -#define DPTXFSIZn_DPTxFSize_GET(_v) (((_v) >> 16) & 0xffff) -#define DPTXFSIZn_DPTxFSize_LIMIT (0xffff) -#define DPTXFSIZn_DPTxFSize(_x) ((_x) << 16) - -#define DPTXFSIZn_DPTxFStAddr_MASK (0xffff << 0) -#define DPTXFSIZn_DPTxFStAddr_SHIFT (0) - -/* Device mode registers */ -#define DCFG HSOTG_REG(0x800) - -#define DCFG_EPMisCnt_MASK (0x1f << 18) -#define DCFG_EPMisCnt_SHIFT (18) -#define DCFG_EPMisCnt_LIMIT (0x1f) -#define DCFG_EPMisCnt(_x) ((_x) << 18) - -#define DCFG_PerFrInt_MASK (0x3 << 11) -#define DCFG_PerFrInt_SHIFT (11) -#define DCFG_PerFrInt_LIMIT (0x3) -#define DCFG_PerFrInt(_x) ((_x) << 11) - -#define DCFG_DevAddr_MASK (0x7f << 4) -#define DCFG_DevAddr_SHIFT (4) -#define DCFG_DevAddr_LIMIT (0x7f) -#define DCFG_DevAddr(_x) ((_x) << 4) - -#define DCFG_NZStsOUTHShk (1 << 2) - -#define DCFG_DevSpd_MASK (0x3 << 0) -#define DCFG_DevSpd_SHIFT (0) -#define DCFG_DevSpd_HS (0x0 << 0) -#define DCFG_DevSpd_FS (0x1 << 0) -#define DCFG_DevSpd_LS (0x2 << 0) -#define DCFG_DevSpd_FS48 (0x3 << 0) - -#define DCTL HSOTG_REG(0x804) - -#define DCTL_PWROnPrgDone (1 << 11) -#define DCTL_CGOUTNak (1 << 10) -#define DCTL_SGOUTNak (1 << 9) -#define DCTL_CGNPInNAK (1 << 8) -#define DCTL_SGNPInNAK (1 << 7) -#define DCTL_TstCtl_MASK (0x7 << 4) -#define DCTL_TstCtl_SHIFT (4) -#define DCTL_GOUTNakSts (1 << 3) -#define DCTL_GNPINNakSts (1 << 2) -#define DCTL_SftDiscon (1 << 1) -#define DCTL_RmtWkUpSig (1 << 0) - -#define DSTS HSOTG_REG(0x808) - -#define DSTS_SOFFN_MASK (0x3fff << 8) -#define DSTS_SOFFN_SHIFT (8) -#define DSTS_SOFFN_LIMIT (0x3fff) -#define DSTS_SOFFN(_x) ((_x) << 8) -#define DSTS_ErraticErr (1 << 3) -#define DSTS_EnumSpd_MASK (0x3 << 1) -#define DSTS_EnumSpd_SHIFT (1) -#define DSTS_EnumSpd_HS (0x0 << 1) -#define DSTS_EnumSpd_FS (0x1 << 1) -#define DSTS_EnumSpd_LS (0x2 << 1) -#define DSTS_EnumSpd_FS48 (0x3 << 1) - -#define DSTS_SuspSts (1 << 0) - -#define DIEPMSK HSOTG_REG(0x810) - -#define DIEPMSK_TxFIFOEmpty (1 << 7) -#define DIEPMSK_INEPNakEffMsk (1 << 6) -#define DIEPMSK_INTknEPMisMsk (1 << 5) -#define DIEPMSK_INTknTXFEmpMsk (1 << 4) -#define DIEPMSK_TimeOUTMsk (1 << 3) -#define DIEPMSK_AHBErrMsk (1 << 2) -#define DIEPMSK_EPDisbldMsk (1 << 1) -#define DIEPMSK_XferComplMsk (1 << 0) - -#define DOEPMSK HSOTG_REG(0x814) - -#define DOEPMSK_Back2BackSetup (1 << 6) -#define DOEPMSK_OUTTknEPdisMsk (1 << 4) -#define DOEPMSK_SetupMsk (1 << 3) -#define DOEPMSK_AHBErrMsk (1 << 2) -#define DOEPMSK_EPDisbldMsk (1 << 1) -#define DOEPMSK_XferComplMsk (1 << 0) - -#define DAINT HSOTG_REG(0x818) -#define DAINTMSK HSOTG_REG(0x81C) - -#define DAINT_OutEP_SHIFT (16) -#define DAINT_OutEP(x) (1 << ((x) + 16)) -#define DAINT_InEP(x) (1 << (x)) - -#define DTKNQR1 HSOTG_REG(0x820) -#define DTKNQR2 HSOTG_REG(0x824) -#define DTKNQR3 HSOTG_REG(0x830) -#define DTKNQR4 HSOTG_REG(0x834) - -#define DVBUSDIS HSOTG_REG(0x828) -#define DVBUSPULSE HSOTG_REG(0x82C) - -#define DIEPCTL0 HSOTG_REG(0x900) -#define DOEPCTL0 HSOTG_REG(0xB00) -#define DIEPCTL(_a) HSOTG_REG(0x900 + ((_a) * 0x20)) -#define DOEPCTL(_a) HSOTG_REG(0xB00 + ((_a) * 0x20)) - -/* EP0 specialness: - * bits[29..28] - reserved (no SetD0PID, SetD1PID) - * bits[25..22] - should always be zero, this isn't a periodic endpoint - * bits[10..0] - MPS setting differenct for EP0 - */ -#define D0EPCTL_MPS_MASK (0x3 << 0) -#define D0EPCTL_MPS_SHIFT (0) -#define D0EPCTL_MPS_64 (0x0 << 0) -#define D0EPCTL_MPS_32 (0x1 << 0) -#define D0EPCTL_MPS_16 (0x2 << 0) -#define D0EPCTL_MPS_8 (0x3 << 0) - -#define DxEPCTL_EPEna (1 << 31) -#define DxEPCTL_EPDis (1 << 30) -#define DxEPCTL_SetD1PID (1 << 29) -#define DxEPCTL_SetOddFr (1 << 29) -#define DxEPCTL_SetD0PID (1 << 28) -#define DxEPCTL_SetEvenFr (1 << 28) -#define DxEPCTL_SNAK (1 << 27) -#define DxEPCTL_CNAK (1 << 26) -#define DxEPCTL_TxFNum_MASK (0xf << 22) -#define DxEPCTL_TxFNum_SHIFT (22) -#define DxEPCTL_TxFNum_LIMIT (0xf) -#define DxEPCTL_TxFNum(_x) ((_x) << 22) - -#define DxEPCTL_Stall (1 << 21) -#define DxEPCTL_Snp (1 << 20) -#define DxEPCTL_EPType_MASK (0x3 << 18) -#define DxEPCTL_EPType_SHIFT (18) -#define DxEPCTL_EPType_Control (0x0 << 18) -#define DxEPCTL_EPType_Iso (0x1 << 18) -#define DxEPCTL_EPType_Bulk (0x2 << 18) -#define DxEPCTL_EPType_Intterupt (0x3 << 18) - -#define DxEPCTL_NAKsts (1 << 17) -#define DxEPCTL_DPID (1 << 16) -#define DxEPCTL_EOFrNum (1 << 16) -#define DxEPCTL_USBActEp (1 << 15) -#define DxEPCTL_NextEp_MASK (0xf << 11) -#define DxEPCTL_NextEp_SHIFT (11) -#define DxEPCTL_NextEp_LIMIT (0xf) -#define DxEPCTL_NextEp(_x) ((_x) << 11) - -#define DxEPCTL_MPS_MASK (0x7ff << 0) -#define DxEPCTL_MPS_SHIFT (0) -#define DxEPCTL_MPS_LIMIT (0x7ff) -#define DxEPCTL_MPS(_x) ((_x) << 0) - -#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20)) -#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20)) - -#define DxEPINT_INEPNakEff (1 << 6) -#define DxEPINT_Back2BackSetup (1 << 6) -#define DxEPINT_INTknEPMis (1 << 5) -#define DxEPINT_INTknTXFEmp (1 << 4) -#define DxEPINT_OUTTknEPdis (1 << 4) -#define DxEPINT_Timeout (1 << 3) -#define DxEPINT_Setup (1 << 3) -#define DxEPINT_AHBErr (1 << 2) -#define DxEPINT_EPDisbld (1 << 1) -#define DxEPINT_XferCompl (1 << 0) - -#define DIEPTSIZ0 HSOTG_REG(0x910) - -#define DIEPTSIZ0_PktCnt_MASK (0x3 << 19) -#define DIEPTSIZ0_PktCnt_SHIFT (19) -#define DIEPTSIZ0_PktCnt_LIMIT (0x3) -#define DIEPTSIZ0_PktCnt(_x) ((_x) << 19) - -#define DIEPTSIZ0_XferSize_MASK (0x7f << 0) -#define DIEPTSIZ0_XferSize_SHIFT (0) -#define DIEPTSIZ0_XferSize_LIMIT (0x7f) -#define DIEPTSIZ0_XferSize(_x) ((_x) << 0) - -#define DOEPTSIZ0 HSOTG_REG(0xB10) -#define DOEPTSIZ0_SUPCnt_MASK (0x3 << 29) -#define DOEPTSIZ0_SUPCnt_SHIFT (29) -#define DOEPTSIZ0_SUPCnt_LIMIT (0x3) -#define DOEPTSIZ0_SUPCnt(_x) ((_x) << 29) - -#define DOEPTSIZ0_PktCnt (1 << 19) -#define DOEPTSIZ0_XferSize_MASK (0x7f << 0) -#define DOEPTSIZ0_XferSize_SHIFT (0) - -#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20)) -#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20)) - -#define DxEPTSIZ_MC_MASK (0x3 << 29) -#define DxEPTSIZ_MC_SHIFT (29) -#define DxEPTSIZ_MC_LIMIT (0x3) -#define DxEPTSIZ_MC(_x) ((_x) << 29) - -#define DxEPTSIZ_PktCnt_MASK (0x3ff << 19) -#define DxEPTSIZ_PktCnt_SHIFT (19) -#define DxEPTSIZ_PktCnt_GET(_v) (((_v) >> 19) & 0x3ff) -#define DxEPTSIZ_PktCnt_LIMIT (0x3ff) -#define DxEPTSIZ_PktCnt(_x) ((_x) << 19) - -#define DxEPTSIZ_XferSize_MASK (0x7ffff << 0) -#define DxEPTSIZ_XferSize_SHIFT (0) -#define DxEPTSIZ_XferSize_GET(_v) (((_v) >> 0) & 0x7ffff) -#define DxEPTSIZ_XferSize_LIMIT (0x7ffff) -#define DxEPTSIZ_XferSize(_x) ((_x) << 0) - -#define DIEPDMA(_a) HSOTG_REG(0x914 + ((_a) * 0x20)) -#define DOEPDMA(_a) HSOTG_REG(0xB14 + ((_a) * 0x20)) -#define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20)) - -#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000)) - -#endif /* __REGS_USB_HSOTG_H */ diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index ec20a1f50c2d70..648f9e489b39bb 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -43,7 +43,7 @@ struct usb_interface_descriptor fsg_intf_desc = { .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */ .iInterface = FSG_STRING_INTERFACE, }; -EXPORT_SYMBOL(fsg_intf_desc); +EXPORT_SYMBOL_GPL(fsg_intf_desc); /* * Three full-speed endpoint descriptors: bulk-in, bulk-out, and @@ -58,7 +58,7 @@ struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, /* wMaxPacketSize set by autoconfiguration */ }; -EXPORT_SYMBOL(fsg_fs_bulk_in_desc); +EXPORT_SYMBOL_GPL(fsg_fs_bulk_in_desc); struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -68,7 +68,7 @@ struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, /* wMaxPacketSize set by autoconfiguration */ }; -EXPORT_SYMBOL(fsg_fs_bulk_out_desc); +EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc); struct usb_descriptor_header *fsg_fs_function[] = { (struct usb_descriptor_header *) &fsg_intf_desc, @@ -76,7 +76,7 @@ struct usb_descriptor_header *fsg_fs_function[] = { (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, NULL, }; -EXPORT_SYMBOL(fsg_fs_function); +EXPORT_SYMBOL_GPL(fsg_fs_function); /* @@ -95,7 +95,7 @@ struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(512), }; -EXPORT_SYMBOL(fsg_hs_bulk_in_desc); +EXPORT_SYMBOL_GPL(fsg_hs_bulk_in_desc); struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -106,7 +106,7 @@ struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = { .wMaxPacketSize = cpu_to_le16(512), .bInterval = 1, /* NAK every 1 uframe */ }; -EXPORT_SYMBOL(fsg_hs_bulk_out_desc); +EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc); struct usb_descriptor_header *fsg_hs_function[] = { @@ -115,7 +115,7 @@ struct usb_descriptor_header *fsg_hs_function[] = { (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, NULL, }; -EXPORT_SYMBOL(fsg_hs_function); +EXPORT_SYMBOL_GPL(fsg_hs_function); struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -125,7 +125,7 @@ struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }; -EXPORT_SYMBOL(fsg_ss_bulk_in_desc); +EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_desc); struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { .bLength = sizeof(fsg_ss_bulk_in_comp_desc), @@ -133,7 +133,7 @@ struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { /*.bMaxBurst = DYNAMIC, */ }; -EXPORT_SYMBOL(fsg_ss_bulk_in_comp_desc); +EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_comp_desc); struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -143,7 +143,7 @@ struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }; -EXPORT_SYMBOL(fsg_ss_bulk_out_desc); +EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_desc); struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { .bLength = sizeof(fsg_ss_bulk_in_comp_desc), @@ -151,7 +151,7 @@ struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { /*.bMaxBurst = DYNAMIC, */ }; -EXPORT_SYMBOL(fsg_ss_bulk_out_comp_desc); +EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc); struct usb_descriptor_header *fsg_ss_function[] = { (struct usb_descriptor_header *) &fsg_intf_desc, @@ -161,7 +161,7 @@ struct usb_descriptor_header *fsg_ss_function[] = { (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc, NULL, }; -EXPORT_SYMBOL(fsg_ss_function); +EXPORT_SYMBOL_GPL(fsg_ss_function); /*-------------------------------------------------------------------------*/ @@ -179,7 +179,7 @@ void fsg_lun_close(struct fsg_lun *curlun) curlun->filp = NULL; } } -EXPORT_SYMBOL(fsg_lun_close); +EXPORT_SYMBOL_GPL(fsg_lun_close); int fsg_lun_open(struct fsg_lun *curlun, const char *filename) { @@ -220,11 +220,11 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename) * If we can't read the file, it's no good. * If we can't write the file, use it read-only. */ - if (!(filp->f_op->read || filp->f_op->aio_read)) { + if (!(filp->f_mode & FMODE_CAN_READ)) { LINFO(curlun, "file not readable: %s\n", filename); goto out; } - if (!(filp->f_op->write || filp->f_op->aio_write)) + if (!(filp->f_mode & FMODE_CAN_WRITE)) ro = 1; size = i_size_read(inode->i_mapping->host); @@ -278,7 +278,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename) fput(filp); return rc; } -EXPORT_SYMBOL(fsg_lun_open); +EXPORT_SYMBOL_GPL(fsg_lun_open); /*-------------------------------------------------------------------------*/ @@ -295,7 +295,7 @@ int fsg_lun_fsync_sub(struct fsg_lun *curlun) return 0; return vfs_fsync(filp, 1); } -EXPORT_SYMBOL(fsg_lun_fsync_sub); +EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub); void store_cdrom_address(u8 *dest, int msf, u32 addr) { @@ -314,7 +314,7 @@ void store_cdrom_address(u8 *dest, int msf, u32 addr) put_unaligned_be32(addr, dest); } } -EXPORT_SYMBOL(store_cdrom_address); +EXPORT_SYMBOL_GPL(store_cdrom_address); /*-------------------------------------------------------------------------*/ @@ -325,13 +325,13 @@ ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf) ? curlun->ro : curlun->initially_ro); } -EXPORT_SYMBOL(fsg_show_ro); +EXPORT_SYMBOL_GPL(fsg_show_ro); ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf) { return sprintf(buf, "%u\n", curlun->nofua); } -EXPORT_SYMBOL(fsg_show_nofua); +EXPORT_SYMBOL_GPL(fsg_show_nofua); ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, char *buf) @@ -357,19 +357,19 @@ ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, up_read(filesem); return rc; } -EXPORT_SYMBOL(fsg_show_file); +EXPORT_SYMBOL_GPL(fsg_show_file); ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf) { return sprintf(buf, "%u\n", curlun->cdrom); } -EXPORT_SYMBOL(fsg_show_cdrom); +EXPORT_SYMBOL_GPL(fsg_show_cdrom); ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf) { return sprintf(buf, "%u\n", curlun->removable); } -EXPORT_SYMBOL(fsg_show_removable); +EXPORT_SYMBOL_GPL(fsg_show_removable); /* * The caller must hold fsg->filesem for reading when calling this function. @@ -410,7 +410,7 @@ ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, return rc; } -EXPORT_SYMBOL(fsg_store_ro); +EXPORT_SYMBOL_GPL(fsg_store_ro); ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count) { @@ -429,7 +429,7 @@ ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count) return count; } -EXPORT_SYMBOL(fsg_store_nofua); +EXPORT_SYMBOL_GPL(fsg_store_nofua); ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count) @@ -460,7 +460,7 @@ ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, up_write(filesem); return (rc < 0 ? rc : count); } -EXPORT_SYMBOL(fsg_store_file); +EXPORT_SYMBOL_GPL(fsg_store_file); ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count) @@ -483,7 +483,7 @@ ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, return ret; } -EXPORT_SYMBOL(fsg_store_cdrom); +EXPORT_SYMBOL_GPL(fsg_store_cdrom); ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, size_t count) @@ -499,6 +499,6 @@ ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, return count; } -EXPORT_SYMBOL(fsg_store_removable); +EXPORT_SYMBOL_GPL(fsg_store_removable); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index f058c0368d61a4..819875c7e39417 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -1851,7 +1851,7 @@ static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun) struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); atomic_inc(&tpg->tpg_port_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); return 0; } @@ -1861,7 +1861,7 @@ static void usbg_port_unlink(struct se_portal_group *se_tpg, struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); atomic_dec(&tpg->tpg_port_count); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); } static int usbg_check_stop_free(struct se_cmd *se_cmd) diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index b7d4f82872b700..fe0880d0873e04 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -818,7 +818,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, return dev; } -EXPORT_SYMBOL(gether_setup_name); +EXPORT_SYMBOL_GPL(gether_setup_name); struct net_device *gether_setup_name_default(const char *netname) { @@ -855,7 +855,7 @@ struct net_device *gether_setup_name_default(const char *netname) return net; } -EXPORT_SYMBOL(gether_setup_name_default); +EXPORT_SYMBOL_GPL(gether_setup_name_default); int gether_register_netdev(struct net_device *net) { @@ -893,7 +893,7 @@ int gether_register_netdev(struct net_device *net) return status; } -EXPORT_SYMBOL(gether_register_netdev); +EXPORT_SYMBOL_GPL(gether_register_netdev); void gether_set_gadget(struct net_device *net, struct usb_gadget *g) { @@ -903,7 +903,7 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g) dev->gadget = g; SET_NETDEV_DEV(net, &g->dev); } -EXPORT_SYMBOL(gether_set_gadget); +EXPORT_SYMBOL_GPL(gether_set_gadget); int gether_set_dev_addr(struct net_device *net, const char *dev_addr) { @@ -916,7 +916,7 @@ int gether_set_dev_addr(struct net_device *net, const char *dev_addr) memcpy(dev->dev_mac, new_addr, ETH_ALEN); return 0; } -EXPORT_SYMBOL(gether_set_dev_addr); +EXPORT_SYMBOL_GPL(gether_set_dev_addr); int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len) { @@ -925,7 +925,7 @@ int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len) dev = netdev_priv(net); return get_ether_addr_str(dev->dev_mac, dev_addr, len); } -EXPORT_SYMBOL(gether_get_dev_addr); +EXPORT_SYMBOL_GPL(gether_get_dev_addr); int gether_set_host_addr(struct net_device *net, const char *host_addr) { @@ -938,7 +938,7 @@ int gether_set_host_addr(struct net_device *net, const char *host_addr) memcpy(dev->host_mac, new_addr, ETH_ALEN); return 0; } -EXPORT_SYMBOL(gether_set_host_addr); +EXPORT_SYMBOL_GPL(gether_set_host_addr); int gether_get_host_addr(struct net_device *net, char *host_addr, int len) { @@ -947,7 +947,7 @@ int gether_get_host_addr(struct net_device *net, char *host_addr, int len) dev = netdev_priv(net); return get_ether_addr_str(dev->host_mac, host_addr, len); } -EXPORT_SYMBOL(gether_get_host_addr); +EXPORT_SYMBOL_GPL(gether_get_host_addr); int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len) { @@ -961,7 +961,7 @@ int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len) return strlen(host_addr); } -EXPORT_SYMBOL(gether_get_host_addr_cdc); +EXPORT_SYMBOL_GPL(gether_get_host_addr_cdc); void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN]) { @@ -970,7 +970,7 @@ void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN]) dev = netdev_priv(net); memcpy(host_mac, dev->host_mac, ETH_ALEN); } -EXPORT_SYMBOL(gether_get_host_addr_u8); +EXPORT_SYMBOL_GPL(gether_get_host_addr_u8); void gether_set_qmult(struct net_device *net, unsigned qmult) { @@ -979,7 +979,7 @@ void gether_set_qmult(struct net_device *net, unsigned qmult) dev = netdev_priv(net); dev->qmult = qmult; } -EXPORT_SYMBOL(gether_set_qmult); +EXPORT_SYMBOL_GPL(gether_set_qmult); unsigned gether_get_qmult(struct net_device *net) { @@ -988,7 +988,7 @@ unsigned gether_get_qmult(struct net_device *net) dev = netdev_priv(net); return dev->qmult; } -EXPORT_SYMBOL(gether_get_qmult); +EXPORT_SYMBOL_GPL(gether_get_qmult); int gether_get_ifname(struct net_device *net, char *name, int len) { @@ -997,7 +997,7 @@ int gether_get_ifname(struct net_device *net, char *name, int len) rtnl_unlock(); return strlen(name); } -EXPORT_SYMBOL(gether_get_ifname); +EXPORT_SYMBOL_GPL(gether_get_ifname); /** * gether_cleanup - remove Ethernet-over-USB device @@ -1014,7 +1014,7 @@ void gether_cleanup(struct eth_dev *dev) flush_work(&dev->work); free_netdev(dev->net); } -EXPORT_SYMBOL(gether_cleanup); +EXPORT_SYMBOL_GPL(gether_cleanup); /** * gether_connect - notify network layer that USB link is active @@ -1095,7 +1095,7 @@ struct net_device *gether_connect(struct gether *link) return ERR_PTR(result); return dev->net; } -EXPORT_SYMBOL(gether_connect); +EXPORT_SYMBOL_GPL(gether_connect); /** * gether_disconnect - notify network layer that USB link is inactive @@ -1166,7 +1166,7 @@ void gether_disconnect(struct gether *link) dev->port_usb = NULL; spin_unlock(&dev->lock); } -EXPORT_SYMBOL(gether_disconnect); +EXPORT_SYMBOL_GPL(gether_disconnect); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Brownell"); diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c index 63b6642c162bbf..c6276f0268ae51 100644 --- a/drivers/usb/gadget/u_f.c +++ b/drivers/usb/gadget/u_f.c @@ -29,4 +29,4 @@ struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len) } return req; } -EXPORT_SYMBOL(alloc_ep_req); +EXPORT_SYMBOL_GPL(alloc_ep_req); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 7ae0c4d517417d..cc305c71ac3d48 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -33,15 +33,6 @@ #ifdef CONFIG_PM -static int ehci_hub_control( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength -); - static int persist_enabled_on_companion(struct usb_device *udev, void *unused) { return !udev->maxchild && udev->persist_enabled && @@ -865,7 +856,7 @@ static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port) #endif /* CONFIG_USB_HCD_TEST_MODE */ /*-------------------------------------------------------------------------*/ -static int ehci_hub_control ( +int ehci_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, @@ -1285,6 +1276,7 @@ static int ehci_hub_control ( spin_unlock_irqrestore (&ehci->lock, flags); return retval; } +EXPORT_SYMBOL_GPL(ehci_hub_control); static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) { diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 7ef00ecb0da10e..572634cd95d61f 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -51,10 +51,6 @@ struct tegra_ehci_soc_config { bool has_hostpc; }; -static int (*orig_hub_control)(struct usb_hcd *hcd, - u16 typeReq, u16 wValue, u16 wIndex, - char *buf, u16 wLength); - struct tegra_ehci_hcd { struct tegra_usb_phy *phy; struct clk *clk; @@ -236,7 +232,7 @@ static int tegra_ehci_hub_control( spin_unlock_irqrestore(&ehci->lock, flags); /* Handle the hub control events here */ - return orig_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); + return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); done: spin_unlock_irqrestore(&ehci->lock, flags); @@ -554,8 +550,6 @@ static int __init ehci_tegra_init(void) * too easy. */ - orig_hub_control = tegra_ehci_hc_driver.hub_control; - tegra_ehci_hc_driver.map_urb_for_dma = tegra_ehci_map_urb_for_dma; tegra_ehci_hc_driver.unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma; tegra_ehci_hc_driver.hub_control = tegra_ehci_hub_control; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 9dfc6c1394d6ac..eee228a26a0e71 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -872,4 +872,7 @@ extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup); extern int ehci_resume(struct usb_hcd *hcd, bool hibernated); #endif /* CONFIG_PM */ +extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength); + #endif /* __LINUX_EHCI_HCD_H */ diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 091ae4905cfc27..e49eb4f90f5d88 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -46,9 +46,6 @@ static const char hcd_name[] = "ohci-atmel"; static struct hc_driver __read_mostly ohci_at91_hc_driver; static int clocked; -static int (*orig_ohci_hub_control)(struct usb_hcd *hcd, u16 typeReq, - u16 wValue, u16 wIndex, char *buf, u16 wLength); -static int (*orig_ohci_hub_status_data)(struct usb_hcd *hcd, char *buf); extern int usb_disabled(void); @@ -262,7 +259,7 @@ static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) { struct at91_usbh_data *pdata = hcd->self.controller->platform_data; - int length = orig_ohci_hub_status_data(hcd, buf); + int length = ohci_hub_status_data(hcd, buf); int port; at91_for_each_port(port) { @@ -340,8 +337,7 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; } - ret = orig_ohci_hub_control(hcd, typeReq, wValue, wIndex + 1, - buf, wLength); + ret = ohci_hub_control(hcd, typeReq, wValue, wIndex + 1, buf, wLength); if (ret) goto out; @@ -690,9 +686,6 @@ static int __init ohci_at91_init(void) * too easy. */ - orig_ohci_hub_control = ohci_at91_hc_driver.hub_control; - orig_ohci_hub_status_data = ohci_at91_hc_driver.hub_status_data; - ohci_at91_hc_driver.hub_status_data = ohci_at91_hub_status_data; ohci_at91_hc_driver.hub_control = ohci_at91_hub_control; diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 68588d8a09bb60..9cf80cb7c05107 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -190,17 +190,13 @@ static int exynos_ohci_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct platform_device *pdev = to_platform_device(dev); bool do_wakeup = device_may_wakeup(dev); - unsigned long flags; int rc = ohci_suspend(hcd, do_wakeup); if (rc) return rc; - spin_lock_irqsave(&ohci->lock, flags); - if (exynos_ohci->otg) exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); @@ -208,8 +204,6 @@ static int exynos_ohci_suspend(struct device *dev) clk_disable_unprepare(exynos_ohci->clk); - spin_unlock_irqrestore(&ohci->lock, flags); - return 0; } diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index cd871b89501325..b4940de1eba34b 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -456,8 +456,7 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, /* build "status change" packet (one or two bytes) from HC registers */ -static int -ohci_hub_status_data (struct usb_hcd *hcd, char *buf) +int ohci_hub_status_data(struct usb_hcd *hcd, char *buf) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int i, changed = 0, length = 1; @@ -522,6 +521,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) return changed ? length : 0; } +EXPORT_SYMBOL_GPL(ohci_hub_status_data); /*-------------------------------------------------------------------------*/ @@ -664,7 +664,7 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) return 0; } -static int ohci_hub_control ( +int ohci_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, @@ -790,4 +790,4 @@ static int ohci_hub_control ( } return retval; } - +EXPORT_SYMBOL_GPL(ohci_hub_control); diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index d21d5fefa76c7b..e68f3d02cd1a3c 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,8 @@ static struct hc_driver __read_mostly ohci_pxa27x_hc_driver; struct pxa27x_ohci { struct clk *clk; void __iomem *mmio_base; + struct regulator *vbus[3]; + bool vbus_enabled[3]; }; #define to_pxa27x_ohci(hcd) (struct pxa27x_ohci *)(hcd_to_ohci(hcd)->priv) @@ -166,6 +169,52 @@ static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *pxa_ohci, int mode) return 0; } +static int pxa27x_ohci_set_vbus_power(struct pxa27x_ohci *pxa_ohci, + unsigned int port, bool enable) +{ + struct regulator *vbus = pxa_ohci->vbus[port]; + int ret = 0; + + if (IS_ERR_OR_NULL(vbus)) + return 0; + + if (enable && !pxa_ohci->vbus_enabled[port]) + ret = regulator_enable(vbus); + else if (!enable && pxa_ohci->vbus_enabled[port]) + ret = regulator_disable(vbus); + + if (ret < 0) + return ret; + + pxa_ohci->vbus_enabled[port] = enable; + + return 0; +} + +static int pxa27x_ohci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength) +{ + struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); + int ret; + + switch (typeReq) { + case SetPortFeature: + case ClearPortFeature: + if (!wIndex || wIndex > 3) + return -EPIPE; + + if (wValue != USB_PORT_FEAT_POWER) + break; + + ret = pxa27x_ohci_set_vbus_power(pxa_ohci, wIndex - 1, + typeReq == SetPortFeature); + if (ret) + return ret; + break; + } + + return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); +} /*-------------------------------------------------------------------------*/ static inline void pxa27x_setup_hc(struct pxa27x_ohci *pxa_ohci, @@ -372,6 +421,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device struct ohci_hcd *ohci; struct resource *r; struct clk *usb_clk; + unsigned int i; retval = ohci_pxa_of_init(pdev); if (retval) @@ -417,6 +467,16 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device pxa_ohci->clk = usb_clk; pxa_ohci->mmio_base = (void __iomem *)hcd->regs; + for (i = 0; i < 3; ++i) { + char name[6]; + + if (!(inf->flags & (ENABLE_PORT1 << i))) + continue; + + sprintf(name, "vbus%u", i + 1); + pxa_ohci->vbus[i] = devm_regulator_get(&pdev->dev, name); + } + retval = pxa27x_start_hc(pxa_ohci, &pdev->dev); if (retval < 0) { pr_debug("pxa27x_start_hc failed"); @@ -462,9 +522,14 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev) { struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); + unsigned int i; usb_remove_hcd(hcd); pxa27x_stop_hc(pxa_ohci, &pdev->dev); + + for (i = 0; i < 3; ++i) + pxa27x_ohci_set_vbus_power(pxa_ohci, i, false); + usb_put_hcd(hcd); } @@ -563,7 +628,10 @@ static int __init ohci_pxa27x_init(void) return -ENODEV; pr_info("%s: " DRIVER_DESC "\n", hcd_name); + ohci_init_driver(&ohci_pxa27x_hc_driver, &pxa27x_overrides); + ohci_pxa27x_hc_driver.hub_control = pxa27x_ohci_hub_control; + return platform_driver_register(&ohci_hcd_pxa27x_driver); } module_init(ohci_pxa27x_init); diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index ff7c8f1c48fb68..3d753a9d314113 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -45,10 +45,6 @@ static struct clk *usb_clk; /* forward definitions */ -static int (*orig_ohci_hub_control)(struct usb_hcd *hcd, u16 typeReq, - u16 wValue, u16 wIndex, char *buf, u16 wLength); -static int (*orig_ohci_hub_status_data)(struct usb_hcd *hcd, char *buf); - static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc); /* conversion functions */ @@ -110,7 +106,7 @@ ohci_s3c2410_hub_status_data(struct usb_hcd *hcd, char *buf) int orig; int portno; - orig = orig_ohci_hub_status_data(hcd, buf); + orig = ohci_hub_status_data(hcd, buf); if (info == NULL) return orig; @@ -181,7 +177,7 @@ static int ohci_s3c2410_hub_control( * process the request straight away and exit */ if (info == NULL) { - ret = orig_ohci_hub_control(hcd, typeReq, wValue, + ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); goto out; } @@ -231,7 +227,7 @@ static int ohci_s3c2410_hub_control( break; } - ret = orig_ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); + ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); if (ret) goto out; @@ -489,9 +485,6 @@ static int __init ohci_s3c2410_init(void) * override these functions by making it too easy. */ - orig_ohci_hub_control = ohci_s3c2410_hc_driver.hub_control; - orig_ohci_hub_status_data = ohci_s3c2410_hc_driver.hub_status_data; - ohci_s3c2410_hc_driver.hub_status_data = ohci_s3c2410_hub_status_data; ohci_s3c2410_hc_driver.hub_control = ohci_s3c2410_hub_control; diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 4550ce05af7fa1..05e02a709d4f11 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -729,3 +729,6 @@ extern int ohci_setup(struct usb_hcd *hcd); extern int ohci_suspend(struct usb_hcd *hcd, bool do_wakeup); extern int ohci_resume(struct usb_hcd *hcd, bool hibernated); #endif +extern int ohci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength); +extern int ohci_hub_status_data(struct usb_hcd *hcd, char *buf); diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index a4a3c7cd4a11c7..8ab1f8f3c26e6a 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -1,40 +1,43 @@ /* -* USB FTDI client driver for Elan Digital Systems's Uxxx adapters -* -* Copyright(C) 2006 Elan Digital Systems Limited -* http://www.elandigitalsystems.com -* -* Author and Maintainer - Tony Olech - Elan Digital Systems -* tony.olech@elandigitalsystems.com -* -* 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. -* -* -* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) -* based on various USB client drivers in the 2.6.15 linux kernel -* with constant reference to the 3rd Edition of Linux Device Drivers -* published by O'Reilly -* -* The U132 adapter is a USB to CardBus adapter specifically designed -* for PC cards that contain an OHCI host controller. Typical PC cards -* are the Orange Mobile 3G Option GlobeTrotter Fusion card. -* -* The U132 adapter will *NOT *work with PC cards that do not contain -* an OHCI controller. A simple way to test whether a PC card has an -* OHCI controller as an interface is to insert the PC card directly -* into a laptop(or desktop) with a CardBus slot and if "lspci" shows -* a new USB controller and "lsusb -v" shows a new OHCI Host Controller -* then there is a good chance that the U132 adapter will support the -* PC card.(you also need the specific client driver for the PC card) -* -* Please inform the Author and Maintainer about any PC cards that -* contain OHCI Host Controller and work when directly connected to -* an embedded CardBus slot but do not work when they are connected -* via an ELAN U132 adapter. -* -*/ + * USB FTDI client driver for Elan Digital Systems's Uxxx adapters + * + * Copyright(C) 2006 Elan Digital Systems Limited + * http://www.elandigitalsystems.com + * + * Author and Maintainer - Tony Olech - Elan Digital Systems + * tony.olech@elandigitalsystems.com + * + * 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. + * + * + * This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) + * based on various USB client drivers in the 2.6.15 linux kernel + * with constant reference to the 3rd Edition of Linux Device Drivers + * published by O'Reilly + * + * The U132 adapter is a USB to CardBus adapter specifically designed + * for PC cards that contain an OHCI host controller. Typical PC cards + * are the Orange Mobile 3G Option GlobeTrotter Fusion card. + * + * The U132 adapter will *NOT *work with PC cards that do not contain + * an OHCI controller. A simple way to test whether a PC card has an + * OHCI controller as an interface is to insert the PC card directly + * into a laptop(or desktop) with a CardBus slot and if "lspci" shows + * a new USB controller and "lsusb -v" shows a new OHCI Host Controller + * then there is a good chance that the U132 adapter will support the + * PC card.(you also need the specific client driver for the PC card) + * + * Please inform the Author and Maintainer about any PC cards that + * contain OHCI Host Controller and work when directly connected to + * an embedded CardBus slot but do not work when they are connected + * via an ELAN U132 adapter. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -55,31 +58,31 @@ MODULE_LICENSE("GPL"); #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) static bool distrust_firmware = 1; module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" - "t setup"); +MODULE_PARM_DESC(distrust_firmware, + "true to distrust firmware power/overcurrent setup"); extern struct platform_driver u132_platform_driver; static struct workqueue_struct *status_queue; static struct workqueue_struct *command_queue; static struct workqueue_struct *respond_queue; /* -* ftdi_module_lock exists to protect access to global variables -* -*/ + * ftdi_module_lock exists to protect access to global variables + * + */ static struct mutex ftdi_module_lock; static int ftdi_instances = 0; static struct list_head ftdi_static_list; /* -* end of the global variables protected by ftdi_module_lock -*/ + * end of the global variables protected by ftdi_module_lock + */ #include "usb_u132.h" #include #include - /* FIXME ohci.h is ONLY for internal use by the OHCI driver. - * If you're going to try stuff like this, you need to split - * out shareable stuff (register declarations?) into its own - * file, maybe name - */ +/* FIXME ohci.h is ONLY for internal use by the OHCI driver. + * If you're going to try stuff like this, you need to split + * out shareable stuff (register declarations?) into its own + * file, maybe name + */ #include "../host/ohci.h" /* Define these values to match your devices*/ @@ -87,140 +90,140 @@ static struct list_head ftdi_static_list; #define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea /* table of devices that work with this driver*/ static const struct usb_device_id ftdi_elan_table[] = { - {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)}, - { /* Terminating entry */ } + {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)}, + { /* Terminating entry */ } }; MODULE_DEVICE_TABLE(usb, ftdi_elan_table); /* only the jtag(firmware upgrade device) interface requires -* a device file and corresponding minor number, but the -* interface is created unconditionally - I suppose it could -* be configured or not according to a module parameter. -* But since we(now) require one interface per device, -* and since it unlikely that a normal installation would -* require more than a couple of elan-ftdi devices, 8 seems -* like a reasonable limit to have here, and if someone -* really requires more than 8 devices, then they can frig the -* code and recompile -*/ + * a device file and corresponding minor number, but the + * interface is created unconditionally - I suppose it could + * be configured or not according to a module parameter. + * But since we(now) require one interface per device, + * and since it unlikely that a normal installation would + * require more than a couple of elan-ftdi devices, 8 seems + * like a reasonable limit to have here, and if someone + * really requires more than 8 devices, then they can frig the + * code and recompile + */ #define USB_FTDI_ELAN_MINOR_BASE 192 #define COMMAND_BITS 5 #define COMMAND_SIZE (1<udev->dev, "FREEING ftdi=%p\n", ftdi); - usb_put_dev(ftdi->udev); - ftdi->disconnected += 1; - mutex_lock(&ftdi_module_lock); - list_del_init(&ftdi->ftdi_list); - ftdi_instances -= 1; - mutex_unlock(&ftdi_module_lock); - kfree(ftdi->bulk_in_buffer); - ftdi->bulk_in_buffer = NULL; + struct usb_ftdi *ftdi = kref_to_usb_ftdi(kref); + dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi); + usb_put_dev(ftdi->udev); + ftdi->disconnected += 1; + mutex_lock(&ftdi_module_lock); + list_del_init(&ftdi->ftdi_list); + ftdi_instances -= 1; + mutex_unlock(&ftdi_module_lock); + kfree(ftdi->bulk_in_buffer); + ftdi->bulk_in_buffer = NULL; } static void ftdi_elan_put_kref(struct usb_ftdi *ftdi) { - kref_put(&ftdi->kref, ftdi_elan_delete); + kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_elan_get_kref(struct usb_ftdi *ftdi) { - kref_get(&ftdi->kref); + kref_get(&ftdi->kref); } static void ftdi_elan_init_kref(struct usb_ftdi *ftdi) { - kref_init(&ftdi->kref); + kref_init(&ftdi->kref); } static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) @@ -237,8 +240,8 @@ static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) { - if (cancel_delayed_work(&ftdi->status_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); + if (cancel_delayed_work(&ftdi->status_work)) + kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) @@ -255,12 +258,12 @@ static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) { - if (cancel_delayed_work(&ftdi->command_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); + if (cancel_delayed_work(&ftdi->command_work)) + kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, - unsigned int delta) + unsigned int delta) { if (!queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) kref_put(&ftdi->kref, ftdi_elan_delete); @@ -274,26 +277,26 @@ static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) static void ftdi_response_cancel_work(struct usb_ftdi *ftdi) { - if (cancel_delayed_work(&ftdi->respond_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); + if (cancel_delayed_work(&ftdi->respond_work)) + kref_put(&ftdi->kref, ftdi_elan_delete); } void ftdi_elan_gone_away(struct platform_device *pdev) { - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - ftdi->gone_away += 1; - ftdi_elan_put_kref(ftdi); + struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); + ftdi->gone_away += 1; + ftdi_elan_put_kref(ftdi); } EXPORT_SYMBOL_GPL(ftdi_elan_gone_away); static void ftdi_release_platform_dev(struct device *dev) { - dev->parent = NULL; + dev->parent = NULL; } static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, - struct u132_target *target, u8 *buffer, int length); + struct u132_target *target, u8 *buffer, int length); static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi); static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi); static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi); @@ -305,421 +308,416 @@ static int ftdi_elan_command_engine(struct usb_ftdi *ftdi); static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi); static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi) { - int result; - if (ftdi->platform_dev.dev.parent) - return -EBUSY; - ftdi_elan_get_kref(ftdi); - ftdi->platform_data.potpg = 100; - ftdi->platform_data.reset = NULL; - ftdi->platform_dev.id = ftdi->sequence_num; - ftdi->platform_dev.resource = ftdi->resources; - ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources); - ftdi->platform_dev.dev.platform_data = &ftdi->platform_data; - ftdi->platform_dev.dev.parent = NULL; - ftdi->platform_dev.dev.release = ftdi_release_platform_dev; - ftdi->platform_dev.dev.dma_mask = NULL; - snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd"); - ftdi->platform_dev.name = ftdi->device_name; - dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd"); - request_module("u132_hcd"); - dev_info(&ftdi->udev->dev, "registering '%s'\n", - ftdi->platform_dev.name); - result = platform_device_register(&ftdi->platform_dev); - return result; + int result; + if (ftdi->platform_dev.dev.parent) + return -EBUSY; + ftdi_elan_get_kref(ftdi); + ftdi->platform_data.potpg = 100; + ftdi->platform_data.reset = NULL; + ftdi->platform_dev.id = ftdi->sequence_num; + ftdi->platform_dev.resource = ftdi->resources; + ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources); + ftdi->platform_dev.dev.platform_data = &ftdi->platform_data; + ftdi->platform_dev.dev.parent = NULL; + ftdi->platform_dev.dev.release = ftdi_release_platform_dev; + ftdi->platform_dev.dev.dma_mask = NULL; + snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd"); + ftdi->platform_dev.name = ftdi->device_name; + dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd"); + request_module("u132_hcd"); + dev_info(&ftdi->udev->dev, "registering '%s'\n", + ftdi->platform_dev.name); + result = platform_device_register(&ftdi->platform_dev); + return result; } static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi) { - mutex_lock(&ftdi->u132_lock); - while (ftdi->respond_next > ftdi->respond_head) { - struct u132_respond *respond = &ftdi->respond[RESPOND_MASK & - ftdi->respond_head++]; - *respond->result = -ESHUTDOWN; - *respond->value = 0; - complete(&respond->wait_completion); - } mutex_unlock(&ftdi->u132_lock); + mutex_lock(&ftdi->u132_lock); + while (ftdi->respond_next > ftdi->respond_head) { + struct u132_respond *respond = &ftdi->respond[RESPOND_MASK & + ftdi->respond_head++]; + *respond->result = -ESHUTDOWN; + *respond->value = 0; + complete(&respond->wait_completion); + } mutex_unlock(&ftdi->u132_lock); } static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi) { - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - if (target->active == 1) { - target->condition_code = TD_DEVNOTRESP; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, NULL, 0); - mutex_lock(&ftdi->u132_lock); - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); + int ed_number = 4; + mutex_lock(&ftdi->u132_lock); + while (ed_number-- > 0) { + struct u132_target *target = &ftdi->target[ed_number]; + if (target->active == 1) { + target->condition_code = TD_DEVNOTRESP; + mutex_unlock(&ftdi->u132_lock); + ftdi_elan_do_callback(ftdi, target, NULL, 0); + mutex_lock(&ftdi->u132_lock); + } + } + ftdi->received = 0; + ftdi->expected = 4; + ftdi->ed_found = 0; + mutex_unlock(&ftdi->u132_lock); } static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi) { - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - target->abandoning = 1; - wait_1:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed_number << 5) | 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_1; - } - } - wait_2:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x90 | (ed_number << 5); - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_2; - } - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); + int ed_number = 4; + mutex_lock(&ftdi->u132_lock); + while (ed_number-- > 0) { + struct u132_target *target = &ftdi->target[ed_number]; + target->abandoning = 1; + wait_1:if (target->active == 1) { + int command_size = ftdi->command_next - + ftdi->command_head; + if (command_size < COMMAND_SIZE) { + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + command->header = 0x80 | (ed_number << 5) | 0x4; + command->length = 0x00; + command->address = 0x00; + command->width = 0x00; + command->follows = 0; + command->value = 0; + command->buffer = &command->value; + ftdi->command_next += 1; + ftdi_elan_kick_command_queue(ftdi); + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + mutex_lock(&ftdi->u132_lock); + goto wait_1; + } + } + wait_2:if (target->active == 1) { + int command_size = ftdi->command_next - + ftdi->command_head; + if (command_size < COMMAND_SIZE) { + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + command->header = 0x90 | (ed_number << 5); + command->length = 0x00; + command->address = 0x00; + command->width = 0x00; + command->follows = 0; + command->value = 0; + command->buffer = &command->value; + ftdi->command_next += 1; + ftdi_elan_kick_command_queue(ftdi); + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + mutex_lock(&ftdi->u132_lock); + goto wait_2; + } + } + } + ftdi->received = 0; + ftdi->expected = 4; + ftdi->ed_found = 0; + mutex_unlock(&ftdi->u132_lock); } static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi) { - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - target->abandoning = 1; - wait:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed_number << 5) | 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait; - } - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); + int ed_number = 4; + mutex_lock(&ftdi->u132_lock); + while (ed_number-- > 0) { + struct u132_target *target = &ftdi->target[ed_number]; + target->abandoning = 1; + wait:if (target->active == 1) { + int command_size = ftdi->command_next - + ftdi->command_head; + if (command_size < COMMAND_SIZE) { + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + command->header = 0x80 | (ed_number << 5) | 0x4; + command->length = 0x00; + command->address = 0x00; + command->width = 0x00; + command->follows = 0; + command->value = 0; + command->buffer = &command->value; + ftdi->command_next += 1; + ftdi_elan_kick_command_queue(ftdi); + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + mutex_lock(&ftdi->u132_lock); + goto wait; + } + } + } + ftdi->received = 0; + ftdi->expected = 4; + ftdi->ed_found = 0; + mutex_unlock(&ftdi->u132_lock); } static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi) { - ftdi_command_queue_work(ftdi, 0); + ftdi_command_queue_work(ftdi, 0); } static void ftdi_elan_command_work(struct work_struct *work) { - struct usb_ftdi *ftdi = + struct usb_ftdi *ftdi = container_of(work, struct usb_ftdi, command_work.work); - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - int retval = ftdi_elan_command_engine(ftdi); - if (retval == -ESHUTDOWN) { - ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; - } else if (retval) - dev_err(&ftdi->udev->dev, "command error %d\n", retval); - ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10)); - return; - } + if (ftdi->disconnected > 0) { + ftdi_elan_put_kref(ftdi); + return; + } else { + int retval = ftdi_elan_command_engine(ftdi); + if (retval == -ESHUTDOWN) { + ftdi->disconnected += 1; + } else if (retval == -ENODEV) { + ftdi->disconnected += 1; + } else if (retval) + dev_err(&ftdi->udev->dev, "command error %d\n", retval); + ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10)); + return; + } } static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi) { - ftdi_respond_queue_work(ftdi, 0); + ftdi_respond_queue_work(ftdi, 0); } static void ftdi_elan_respond_work(struct work_struct *work) { - struct usb_ftdi *ftdi = + struct usb_ftdi *ftdi = container_of(work, struct usb_ftdi, respond_work.work); - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - int retval = ftdi_elan_respond_engine(ftdi); - if (retval == 0) { - } else if (retval == -ESHUTDOWN) { - ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; - } else if (retval == -EILSEQ) { - ftdi->disconnected += 1; - } else { - ftdi->disconnected += 1; - dev_err(&ftdi->udev->dev, "respond error %d\n", retval); - } - if (ftdi->disconnected > 0) { - ftdi_elan_abandon_completions(ftdi); - ftdi_elan_abandon_targets(ftdi); - } - ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10)); - return; - } + if (ftdi->disconnected > 0) { + ftdi_elan_put_kref(ftdi); + return; + } else { + int retval = ftdi_elan_respond_engine(ftdi); + if (retval == 0) { + } else if (retval == -ESHUTDOWN) { + ftdi->disconnected += 1; + } else if (retval == -ENODEV) { + ftdi->disconnected += 1; + } else if (retval == -EILSEQ) { + ftdi->disconnected += 1; + } else { + ftdi->disconnected += 1; + dev_err(&ftdi->udev->dev, "respond error %d\n", retval); + } + if (ftdi->disconnected > 0) { + ftdi_elan_abandon_completions(ftdi); + ftdi_elan_abandon_targets(ftdi); + } + ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10)); + return; + } } /* -* the sw_lock is initially held and will be freed -* after the FTDI has been synchronized -* -*/ + * the sw_lock is initially held and will be freed + * after the FTDI has been synchronized + * + */ static void ftdi_elan_status_work(struct work_struct *work) { - struct usb_ftdi *ftdi = + struct usb_ftdi *ftdi = container_of(work, struct usb_ftdi, status_work.work); - int work_delay_in_msec = 0; - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else if (ftdi->synchronized == 0) { - down(&ftdi->sw_lock); - if (ftdi_elan_synchronize(ftdi) == 0) { - ftdi->synchronized = 1; - ftdi_command_queue_work(ftdi, 1); - ftdi_respond_queue_work(ftdi, 1); - up(&ftdi->sw_lock); - work_delay_in_msec = 100; - } else { - dev_err(&ftdi->udev->dev, "synchronize failed\n"); - up(&ftdi->sw_lock); - work_delay_in_msec = 10 *1000; - } - } else if (ftdi->stuck_status > 0) { - if (ftdi_elan_stuck_waiting(ftdi) == 0) { - ftdi->stuck_status = 0; - ftdi->synchronized = 0; - } else if ((ftdi->stuck_status++ % 60) == 1) { - dev_err(&ftdi->udev->dev, "WRONG type of card inserted " - "- please remove\n"); - } else - dev_err(&ftdi->udev->dev, "WRONG type of card inserted " - "- checked %d times\n", ftdi->stuck_status); - work_delay_in_msec = 100; - } else if (ftdi->enumerated == 0) { - if (ftdi_elan_enumeratePCI(ftdi) == 0) { - ftdi->enumerated = 1; - work_delay_in_msec = 250; - } else - work_delay_in_msec = 1000; - } else if (ftdi->initialized == 0) { - if (ftdi_elan_setupOHCI(ftdi) == 0) { - ftdi->initialized = 1; - work_delay_in_msec = 500; - } else { - dev_err(&ftdi->udev->dev, "initialized failed - trying " - "again in 10 seconds\n"); - work_delay_in_msec = 1 *1000; - } - } else if (ftdi->registered == 0) { - work_delay_in_msec = 10; - if (ftdi_elan_hcd_init(ftdi) == 0) { - ftdi->registered = 1; - } else - dev_err(&ftdi->udev->dev, "register failed\n"); - work_delay_in_msec = 250; - } else { - if (ftdi_elan_checkingPCI(ftdi) == 0) { - work_delay_in_msec = 250; - } else if (ftdi->controlreg & 0x00400000) { - if (ftdi->gone_away > 0) { - dev_err(&ftdi->udev->dev, "PCI device eject con" - "firmed platform_dev.dev.parent=%p plat" - "form_dev.dev=%p\n", - ftdi->platform_dev.dev.parent, - &ftdi->platform_dev.dev); - platform_device_unregister(&ftdi->platform_dev); - ftdi->platform_dev.dev.parent = NULL; - ftdi->registered = 0; - ftdi->enumerated = 0; - ftdi->card_ejected = 0; - ftdi->initialized = 0; - ftdi->gone_away = 0; - } else - ftdi_elan_flush_targets(ftdi); - work_delay_in_msec = 250; - } else { - dev_err(&ftdi->udev->dev, "PCI device has disappeared\n" - ); - ftdi_elan_cancel_targets(ftdi); - work_delay_in_msec = 500; - ftdi->enumerated = 0; - ftdi->initialized = 0; - } - } - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - ftdi_status_requeue_work(ftdi, - msecs_to_jiffies(work_delay_in_msec)); - return; - } + int work_delay_in_msec = 0; + if (ftdi->disconnected > 0) { + ftdi_elan_put_kref(ftdi); + return; + } else if (ftdi->synchronized == 0) { + down(&ftdi->sw_lock); + if (ftdi_elan_synchronize(ftdi) == 0) { + ftdi->synchronized = 1; + ftdi_command_queue_work(ftdi, 1); + ftdi_respond_queue_work(ftdi, 1); + up(&ftdi->sw_lock); + work_delay_in_msec = 100; + } else { + dev_err(&ftdi->udev->dev, "synchronize failed\n"); + up(&ftdi->sw_lock); + work_delay_in_msec = 10 *1000; + } + } else if (ftdi->stuck_status > 0) { + if (ftdi_elan_stuck_waiting(ftdi) == 0) { + ftdi->stuck_status = 0; + ftdi->synchronized = 0; + } else if ((ftdi->stuck_status++ % 60) == 1) { + dev_err(&ftdi->udev->dev, "WRONG type of card inserted - please remove\n"); + } else + dev_err(&ftdi->udev->dev, "WRONG type of card inserted - checked %d times\n", + ftdi->stuck_status); + work_delay_in_msec = 100; + } else if (ftdi->enumerated == 0) { + if (ftdi_elan_enumeratePCI(ftdi) == 0) { + ftdi->enumerated = 1; + work_delay_in_msec = 250; + } else + work_delay_in_msec = 1000; + } else if (ftdi->initialized == 0) { + if (ftdi_elan_setupOHCI(ftdi) == 0) { + ftdi->initialized = 1; + work_delay_in_msec = 500; + } else { + dev_err(&ftdi->udev->dev, "initialized failed - trying again in 10 seconds\n"); + work_delay_in_msec = 1 *1000; + } + } else if (ftdi->registered == 0) { + work_delay_in_msec = 10; + if (ftdi_elan_hcd_init(ftdi) == 0) { + ftdi->registered = 1; + } else + dev_err(&ftdi->udev->dev, "register failed\n"); + work_delay_in_msec = 250; + } else { + if (ftdi_elan_checkingPCI(ftdi) == 0) { + work_delay_in_msec = 250; + } else if (ftdi->controlreg & 0x00400000) { + if (ftdi->gone_away > 0) { + dev_err(&ftdi->udev->dev, "PCI device eject confirmed platform_dev.dev.parent=%p platform_dev.dev=%p\n", + ftdi->platform_dev.dev.parent, + &ftdi->platform_dev.dev); + platform_device_unregister(&ftdi->platform_dev); + ftdi->platform_dev.dev.parent = NULL; + ftdi->registered = 0; + ftdi->enumerated = 0; + ftdi->card_ejected = 0; + ftdi->initialized = 0; + ftdi->gone_away = 0; + } else + ftdi_elan_flush_targets(ftdi); + work_delay_in_msec = 250; + } else { + dev_err(&ftdi->udev->dev, "PCI device has disappeared\n"); + ftdi_elan_cancel_targets(ftdi); + work_delay_in_msec = 500; + ftdi->enumerated = 0; + ftdi->initialized = 0; + } + } + if (ftdi->disconnected > 0) { + ftdi_elan_put_kref(ftdi); + return; + } else { + ftdi_status_requeue_work(ftdi, + msecs_to_jiffies(work_delay_in_msec)); + return; + } } /* -* file_operations for the jtag interface -* -* the usage count for the device is incremented on open() -* and decremented on release() -*/ + * file_operations for the jtag interface + * + * the usage count for the device is incremented on open() + * and decremented on release() + */ static int ftdi_elan_open(struct inode *inode, struct file *file) { int subminor; struct usb_interface *interface; - subminor = iminor(inode); - interface = usb_find_interface(&ftdi_elan_driver, subminor); - - if (!interface) { - printk(KERN_ERR "can't find device for minor %d\n", subminor); - return -ENODEV; - } else { - struct usb_ftdi *ftdi = usb_get_intfdata(interface); - if (!ftdi) { - return -ENODEV; - } else { - if (down_interruptible(&ftdi->sw_lock)) { - return -EINTR; - } else { - ftdi_elan_get_kref(ftdi); - file->private_data = ftdi; - return 0; - } - } - } + subminor = iminor(inode); + interface = usb_find_interface(&ftdi_elan_driver, subminor); + + if (!interface) { + pr_err("can't find device for minor %d\n", subminor); + return -ENODEV; + } else { + struct usb_ftdi *ftdi = usb_get_intfdata(interface); + if (!ftdi) { + return -ENODEV; + } else { + if (down_interruptible(&ftdi->sw_lock)) { + return -EINTR; + } else { + ftdi_elan_get_kref(ftdi); + file->private_data = ftdi; + return 0; + } + } + } } static int ftdi_elan_release(struct inode *inode, struct file *file) { - struct usb_ftdi *ftdi = file->private_data; - if (ftdi == NULL) - return -ENODEV; - up(&ftdi->sw_lock); /* decrement the count on our device */ - ftdi_elan_put_kref(ftdi); - return 0; + struct usb_ftdi *ftdi = file->private_data; + if (ftdi == NULL) + return -ENODEV; + up(&ftdi->sw_lock); /* decrement the count on our device */ + ftdi_elan_put_kref(ftdi); + return 0; } /* -* -* blocking bulk reads are used to get data from the device -* -*/ + * + * blocking bulk reads are used to get data from the device + * + */ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { - char data[30 *3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3; - int bytes_read = 0; - int retry_on_empty = 10; - int retry_on_timeout = 5; - struct usb_ftdi *ftdi = file->private_data; - if (ftdi->disconnected > 0) { - return -ENODEV; - } - data[0] = 0; - have:if (ftdi->bulk_in_left > 0) { - if (count-- > 0) { - char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer; - ftdi->bulk_in_left -= 1; - if (bytes_read < m) { - d += sprintf(d, " %02X", 0x000000FF & *p); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - if (copy_to_user(buffer++, p, 1)) { - return -EFAULT; - } else { - bytes_read += 1; - goto have; - } - } else - return bytes_read; - } - more:if (count > 0) { - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 50); - if (packet_bytes > 2) { - ftdi->bulk_in_left = packet_bytes - 2; - ftdi->bulk_in_last = 1; - goto have; - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else if (bytes_read > 0) { - return bytes_read; - } else - return retval; - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else - return bytes_read; - } else - return retval; - } else - return bytes_read; + char data[30 *3 + 4]; + char *d = data; + int m = (sizeof(data) - 1) / 3; + int bytes_read = 0; + int retry_on_empty = 10; + int retry_on_timeout = 5; + struct usb_ftdi *ftdi = file->private_data; + if (ftdi->disconnected > 0) { + return -ENODEV; + } + data[0] = 0; +have:if (ftdi->bulk_in_left > 0) { + if (count-- > 0) { + char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer; + ftdi->bulk_in_left -= 1; + if (bytes_read < m) { + d += sprintf(d, " %02X", 0x000000FF & *p); + } else if (bytes_read > m) { + } else + d += sprintf(d, " .."); + if (copy_to_user(buffer++, p, 1)) { + return -EFAULT; + } else { + bytes_read += 1; + goto have; + } + } else + return bytes_read; + } +more:if (count > 0) { + int packet_bytes = 0; + int retval = usb_bulk_msg(ftdi->udev, + usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), + ftdi->bulk_in_buffer, ftdi->bulk_in_size, + &packet_bytes, 50); + if (packet_bytes > 2) { + ftdi->bulk_in_left = packet_bytes - 2; + ftdi->bulk_in_last = 1; + goto have; + } else if (retval == -ETIMEDOUT) { + if (retry_on_timeout-- > 0) { + goto more; + } else if (bytes_read > 0) { + return bytes_read; + } else + return retval; + } else if (retval == 0) { + if (retry_on_empty-- > 0) { + goto more; + } else + return bytes_read; + } else + return retval; + } else + return bytes_read; } static void ftdi_elan_write_bulk_callback(struct urb *urb) @@ -728,467 +726,460 @@ static void ftdi_elan_write_bulk_callback(struct urb *urb) int status = urb->status; if (status && !(status == -ENOENT || status == -ECONNRESET || - status == -ESHUTDOWN)) { - dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %" - "d\n", urb, status); - } - usb_free_coherent(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); + status == -ESHUTDOWN)) { + dev_err(&ftdi->udev->dev, + "urb=%p write bulk status received: %d\n", urb, status); + } + usb_free_coherent(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); } static int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi, - char *buf, int command_size, int total_size) -{ - int ed_commands = 0; - int b = 0; - int I = command_size; - int i = ftdi->command_head; - while (I-- > 0) { - struct u132_command *command = &ftdi->command[COMMAND_MASK & - i++]; - int F = command->follows; - u8 *f = command->buffer; - if (command->header & 0x80) { - ed_commands |= 1 << (0x3 & (command->header >> 5)); - } - buf[b++] = command->header; - buf[b++] = (command->length >> 0) & 0x00FF; - buf[b++] = (command->length >> 8) & 0x00FF; - buf[b++] = command->address; - buf[b++] = command->width; - while (F-- > 0) { - buf[b++] = *f++; - } - } - return ed_commands; + char *buf, int command_size, int total_size) +{ + int ed_commands = 0; + int b = 0; + int I = command_size; + int i = ftdi->command_head; + while (I-- > 0) { + struct u132_command *command = &ftdi->command[COMMAND_MASK & + i++]; + int F = command->follows; + u8 *f = command->buffer; + if (command->header & 0x80) { + ed_commands |= 1 << (0x3 & (command->header >> 5)); + } + buf[b++] = command->header; + buf[b++] = (command->length >> 0) & 0x00FF; + buf[b++] = (command->length >> 8) & 0x00FF; + buf[b++] = command->address; + buf[b++] = command->width; + while (F-- > 0) { + buf[b++] = *f++; + } + } + return ed_commands; } static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size) { - int total_size = 0; - int I = command_size; - int i = ftdi->command_head; - while (I-- > 0) { - struct u132_command *command = &ftdi->command[COMMAND_MASK & - i++]; - total_size += 5 + command->follows; - } return total_size; + int total_size = 0; + int I = command_size; + int i = ftdi->command_head; + while (I-- > 0) { + struct u132_command *command = &ftdi->command[COMMAND_MASK & + i++]; + total_size += 5 + command->follows; + } return total_size; } static int ftdi_elan_command_engine(struct usb_ftdi *ftdi) { - int retval; - char *buf; - int ed_commands; - int total_size; - struct urb *urb; - int command_size = ftdi->command_next - ftdi->command_head; - if (command_size == 0) - return 0; - total_size = ftdi_elan_total_command_size(ftdi, command_size); - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&ftdi->udev->dev, "could not get a urb to write %d comm" - "ands totaling %d bytes to the Uxxx\n", command_size, - total_size); - return -ENOMEM; - } - buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer to write %d c" - "ommands totaling %d bytes to the Uxxx\n", command_size, - total_size); - usb_free_urb(urb); - return -ENOMEM; - } - ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf, - command_size, total_size); - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, total_size, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - if (ed_commands) { - char diag[40 *3 + 4]; - char *d = diag; - int m = total_size; - u8 *c = buf; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - } - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write " - "%d commands totaling %d bytes to the Uxxx\n", retval, - urb, command_size, total_size); - usb_free_coherent(ftdi->udev, total_size, buf, urb->transfer_dma); - usb_free_urb(urb); - return retval; - } - usb_free_urb(urb); /* release our reference to this urb, - the USB core will eventually free it entirely */ - ftdi->command_head += command_size; - ftdi_elan_kick_respond_queue(ftdi); - return 0; + int retval; + char *buf; + int ed_commands; + int total_size; + struct urb *urb; + int command_size = ftdi->command_next - ftdi->command_head; + if (command_size == 0) + return 0; + total_size = ftdi_elan_total_command_size(ftdi, command_size); + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + dev_err(&ftdi->udev->dev, "could not get a urb to write %d commands totaling %d bytes to the Uxxx\n", + command_size, total_size); + return -ENOMEM; + } + buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL, + &urb->transfer_dma); + if (!buf) { + dev_err(&ftdi->udev->dev, "could not get a buffer to write %d commands totaling %d bytes to the Uxxx\n", + command_size, total_size); + usb_free_urb(urb); + return -ENOMEM; + } + ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf, + command_size, total_size); + usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, + ftdi->bulk_out_endpointAddr), buf, total_size, + ftdi_elan_write_bulk_callback, ftdi); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + if (ed_commands) { + char diag[40 *3 + 4]; + char *d = diag; + int m = total_size; + u8 *c = buf; + int s = (sizeof(diag) - 1) / 3; + diag[0] = 0; + while (s-- > 0 && m-- > 0) { + if (s > 0 || m == 0) { + d += sprintf(d, " %02X", *c++); + } else + d += sprintf(d, " .."); + } + } + retval = usb_submit_urb(urb, GFP_KERNEL); + if (retval) { + dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write %d commands totaling %d bytes to the Uxxx\n", + retval, urb, command_size, total_size); + usb_free_coherent(ftdi->udev, total_size, buf, urb->transfer_dma); + usb_free_urb(urb); + return retval; + } + usb_free_urb(urb); /* release our reference to this urb, + the USB core will eventually free it entirely */ + ftdi->command_head += command_size; + ftdi_elan_kick_respond_queue(ftdi); + return 0; } static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, - struct u132_target *target, u8 *buffer, int length) -{ - struct urb *urb = target->urb; - int halted = target->halted; - int skipped = target->skipped; - int actual = target->actual; - int non_null = target->non_null; - int toggle_bits = target->toggle_bits; - int error_count = target->error_count; - int condition_code = target->condition_code; - int repeat_number = target->repeat_number; - void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int, - int, int, int, int) = target->callback; - target->active -= 1; - target->callback = NULL; - (*callback) (target->endp, urb, buffer, length, toggle_bits, - error_count, condition_code, repeat_number, halted, skipped, - actual, non_null); + struct u132_target *target, u8 *buffer, int length) +{ + struct urb *urb = target->urb; + int halted = target->halted; + int skipped = target->skipped; + int actual = target->actual; + int non_null = target->non_null; + int toggle_bits = target->toggle_bits; + int error_count = target->error_count; + int condition_code = target->condition_code; + int repeat_number = target->repeat_number; + void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int, + int, int, int, int) = target->callback; + target->active -= 1; + target->callback = NULL; + (*callback) (target->endp, urb, buffer, length, toggle_bits, + error_count, condition_code, repeat_number, halted, skipped, + actual, non_null); } static char *have_ed_set_response(struct usb_ftdi *ftdi, - struct u132_target *target, u16 ed_length, int ed_number, int ed_type, - char *b) -{ - int payload = (ed_length >> 0) & 0x07FF; - mutex_lock(&ftdi->u132_lock); - target->actual = 0; - target->non_null = (ed_length >> 15) & 0x0001; - target->repeat_number = (ed_length >> 11) & 0x000F; - if (ed_type == 0x02) { - if (payload == 0 || target->abandoning > 0) { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } else { - ftdi->expected = 4 + payload; - ftdi->ed_found = 1; - mutex_unlock(&ftdi->u132_lock); - return b; - } - } else if (ed_type == 0x03) { - if (payload == 0 || target->abandoning > 0) { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } else { - ftdi->expected = 4 + payload; - ftdi->ed_found = 1; - mutex_unlock(&ftdi->u132_lock); - return b; - } - } else if (ed_type == 0x01) { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } else { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } + struct u132_target *target, u16 ed_length, int ed_number, int ed_type, + char *b) +{ + int payload = (ed_length >> 0) & 0x07FF; + mutex_lock(&ftdi->u132_lock); + target->actual = 0; + target->non_null = (ed_length >> 15) & 0x0001; + target->repeat_number = (ed_length >> 11) & 0x000F; + if (ed_type == 0x02) { + if (payload == 0 || target->abandoning > 0) { + target->abandoning = 0; + mutex_unlock(&ftdi->u132_lock); + ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, + payload); + ftdi->received = 0; + ftdi->expected = 4; + ftdi->ed_found = 0; + return ftdi->response; + } else { + ftdi->expected = 4 + payload; + ftdi->ed_found = 1; + mutex_unlock(&ftdi->u132_lock); + return b; + } + } else if (ed_type == 0x03) { + if (payload == 0 || target->abandoning > 0) { + target->abandoning = 0; + mutex_unlock(&ftdi->u132_lock); + ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, + payload); + ftdi->received = 0; + ftdi->expected = 4; + ftdi->ed_found = 0; + return ftdi->response; + } else { + ftdi->expected = 4 + payload; + ftdi->ed_found = 1; + mutex_unlock(&ftdi->u132_lock); + return b; + } + } else if (ed_type == 0x01) { + target->abandoning = 0; + mutex_unlock(&ftdi->u132_lock); + ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, + payload); + ftdi->received = 0; + ftdi->expected = 4; + ftdi->ed_found = 0; + return ftdi->response; + } else { + target->abandoning = 0; + mutex_unlock(&ftdi->u132_lock); + ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, + payload); + ftdi->received = 0; + ftdi->expected = 4; + ftdi->ed_found = 0; + return ftdi->response; + } } static char *have_ed_get_response(struct usb_ftdi *ftdi, - struct u132_target *target, u16 ed_length, int ed_number, int ed_type, - char *b) + struct u132_target *target, u16 ed_length, int ed_number, int ed_type, + char *b) { - mutex_lock(&ftdi->u132_lock); - target->condition_code = TD_DEVNOTRESP; - target->actual = (ed_length >> 0) & 0x01FF; - target->non_null = (ed_length >> 15) & 0x0001; - target->repeat_number = (ed_length >> 11) & 0x000F; - mutex_unlock(&ftdi->u132_lock); - if (target->active) - ftdi_elan_do_callback(ftdi, target, NULL, 0); - target->abandoning = 0; - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; + mutex_lock(&ftdi->u132_lock); + target->condition_code = TD_DEVNOTRESP; + target->actual = (ed_length >> 0) & 0x01FF; + target->non_null = (ed_length >> 15) & 0x0001; + target->repeat_number = (ed_length >> 11) & 0x000F; + mutex_unlock(&ftdi->u132_lock); + if (target->active) + ftdi_elan_do_callback(ftdi, target, NULL, 0); + target->abandoning = 0; + ftdi->received = 0; + ftdi->expected = 4; + ftdi->ed_found = 0; + return ftdi->response; } /* -* The engine tries to empty the FTDI fifo -* -* all responses found in the fifo data are dispatched thus -* the response buffer can only ever hold a maximum sized -* response from the Uxxx. -* -*/ + * The engine tries to empty the FTDI fifo + * + * all responses found in the fifo data are dispatched thus + * the response buffer can only ever hold a maximum sized + * response from the Uxxx. + * + */ static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi) { - u8 *b = ftdi->response + ftdi->received; - int bytes_read = 0; - int retry_on_empty = 1; - int retry_on_timeout = 3; - int empty_packets = 0; - read:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 500); - char diag[30 *3 + 4]; - char *d = diag; - int m = packet_bytes; - u8 *c = ftdi->bulk_in_buffer; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - if (packet_bytes > 2) { - ftdi->bulk_in_left = packet_bytes - 2; - ftdi->bulk_in_last = 1; - goto have; - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - dev_err(&ftdi->udev->dev, "TIMED OUT with packe" - "t_bytes = %d with total %d bytes%s\n", - packet_bytes, bytes_read, diag); - goto more; - } else if (bytes_read > 0) { - dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n", - bytes_read, diag); - return -ENOMEM; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT with packe" - "t_bytes = %d with total %d bytes%s\n", - packet_bytes, bytes_read, diag); - return -ENOMEM; - } - } else if (retval == -EILSEQ) { - dev_err(&ftdi->udev->dev, "error = %d with packet_bytes" - " = %d with total %d bytes%s\n", retval, - packet_bytes, bytes_read, diag); - return retval; - } else if (retval) { - dev_err(&ftdi->udev->dev, "error = %d with packet_bytes" - " = %d with total %d bytes%s\n", retval, - packet_bytes, bytes_read, diag); - return retval; - } else if (packet_bytes == 2) { - unsigned char s0 = ftdi->bulk_in_buffer[0]; - unsigned char s1 = ftdi->bulk_in_buffer[1]; - empty_packets += 1; - if (s0 == 0x31 && s1 == 0x60) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } else if (s0 == 0x31 && s1 == 0x00) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } else { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } - } else if (packet_bytes == 1) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } else { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } - } - more:{ - goto read; - } - have:if (ftdi->bulk_in_left > 0) { - u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last]; - bytes_read += 1; - ftdi->bulk_in_left -= 1; - if (ftdi->received == 0 && c == 0xFF) { - goto have; - } else - *b++ = c; - if (++ftdi->received < ftdi->expected) { - goto have; - } else if (ftdi->ed_found) { - int ed_number = (ftdi->response[0] >> 5) & 0x03; - u16 ed_length = (ftdi->response[2] << 8) | - ftdi->response[1]; - struct u132_target *target = &ftdi->target[ed_number]; - int payload = (ed_length >> 0) & 0x07FF; - char diag[30 *3 + 4]; - char *d = diag; - int m = payload; - u8 *c = 4 + ftdi->response; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - b = ftdi->response; - goto have; - } else if (ftdi->expected == 8) { - u8 buscmd; - int respond_head = ftdi->respond_head++; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & respond_head]; - u32 data = ftdi->response[7]; - data <<= 8; - data |= ftdi->response[6]; - data <<= 8; - data |= ftdi->response[5]; - data <<= 8; - data |= ftdi->response[4]; - *respond->value = data; - *respond->result = 0; - complete(&respond->wait_completion); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - b = ftdi->response; - buscmd = (ftdi->response[0] >> 0) & 0x0F; - if (buscmd == 0x00) { - } else if (buscmd == 0x02) { - } else if (buscmd == 0x06) { - } else if (buscmd == 0x0A) { - } else - dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) va" - "lue = %08X\n", buscmd, data); - goto have; - } else { - if ((ftdi->response[0] & 0x80) == 0x00) { - ftdi->expected = 8; - goto have; - } else { - int ed_number = (ftdi->response[0] >> 5) & 0x03; - int ed_type = (ftdi->response[0] >> 0) & 0x03; - u16 ed_length = (ftdi->response[2] << 8) | - ftdi->response[1]; - struct u132_target *target = &ftdi->target[ - ed_number]; - target->halted = (ftdi->response[0] >> 3) & - 0x01; - target->skipped = (ftdi->response[0] >> 2) & - 0x01; - target->toggle_bits = (ftdi->response[3] >> 6) - & 0x03; - target->error_count = (ftdi->response[3] >> 4) - & 0x03; - target->condition_code = (ftdi->response[ - 3] >> 0) & 0x0F; - if ((ftdi->response[0] & 0x10) == 0x00) { - b = have_ed_set_response(ftdi, target, - ed_length, ed_number, ed_type, - b); - goto have; - } else { - b = have_ed_get_response(ftdi, target, - ed_length, ed_number, ed_type, - b); - goto have; - } - } - } - } else - goto more; + u8 *b = ftdi->response + ftdi->received; + int bytes_read = 0; + int retry_on_empty = 1; + int retry_on_timeout = 3; + int empty_packets = 0; +read:{ + int packet_bytes = 0; + int retval = usb_bulk_msg(ftdi->udev, + usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), + ftdi->bulk_in_buffer, ftdi->bulk_in_size, + &packet_bytes, 500); + char diag[30 *3 + 4]; + char *d = diag; + int m = packet_bytes; + u8 *c = ftdi->bulk_in_buffer; + int s = (sizeof(diag) - 1) / 3; + diag[0] = 0; + while (s-- > 0 && m-- > 0) { + if (s > 0 || m == 0) { + d += sprintf(d, " %02X", *c++); + } else + d += sprintf(d, " .."); + } + if (packet_bytes > 2) { + ftdi->bulk_in_left = packet_bytes - 2; + ftdi->bulk_in_last = 1; + goto have; + } else if (retval == -ETIMEDOUT) { + if (retry_on_timeout-- > 0) { + dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n", + packet_bytes, bytes_read, diag); + goto more; + } else if (bytes_read > 0) { + dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n", + bytes_read, diag); + return -ENOMEM; + } else { + dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n", + packet_bytes, bytes_read, diag); + return -ENOMEM; + } + } else if (retval == -EILSEQ) { + dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", + retval, packet_bytes, bytes_read, diag); + return retval; + } else if (retval) { + dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", + retval, packet_bytes, bytes_read, diag); + return retval; + } else if (packet_bytes == 2) { + unsigned char s0 = ftdi->bulk_in_buffer[0]; + unsigned char s1 = ftdi->bulk_in_buffer[1]; + empty_packets += 1; + if (s0 == 0x31 && s1 == 0x60) { + if (retry_on_empty-- > 0) { + goto more; + } else + return 0; + } else if (s0 == 0x31 && s1 == 0x00) { + if (retry_on_empty-- > 0) { + goto more; + } else + return 0; + } else { + if (retry_on_empty-- > 0) { + goto more; + } else + return 0; + } + } else if (packet_bytes == 1) { + if (retry_on_empty-- > 0) { + goto more; + } else + return 0; + } else { + if (retry_on_empty-- > 0) { + goto more; + } else + return 0; + } + } +more:{ + goto read; + } +have:if (ftdi->bulk_in_left > 0) { + u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last]; + bytes_read += 1; + ftdi->bulk_in_left -= 1; + if (ftdi->received == 0 && c == 0xFF) { + goto have; + } else + *b++ = c; + if (++ftdi->received < ftdi->expected) { + goto have; + } else if (ftdi->ed_found) { + int ed_number = (ftdi->response[0] >> 5) & 0x03; + u16 ed_length = (ftdi->response[2] << 8) | + ftdi->response[1]; + struct u132_target *target = &ftdi->target[ed_number]; + int payload = (ed_length >> 0) & 0x07FF; + char diag[30 *3 + 4]; + char *d = diag; + int m = payload; + u8 *c = 4 + ftdi->response; + int s = (sizeof(diag) - 1) / 3; + diag[0] = 0; + while (s-- > 0 && m-- > 0) { + if (s > 0 || m == 0) { + d += sprintf(d, " %02X", *c++); + } else + d += sprintf(d, " .."); + } + ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, + payload); + ftdi->received = 0; + ftdi->expected = 4; + ftdi->ed_found = 0; + b = ftdi->response; + goto have; + } else if (ftdi->expected == 8) { + u8 buscmd; + int respond_head = ftdi->respond_head++; + struct u132_respond *respond = &ftdi->respond[ + RESPOND_MASK & respond_head]; + u32 data = ftdi->response[7]; + data <<= 8; + data |= ftdi->response[6]; + data <<= 8; + data |= ftdi->response[5]; + data <<= 8; + data |= ftdi->response[4]; + *respond->value = data; + *respond->result = 0; + complete(&respond->wait_completion); + ftdi->received = 0; + ftdi->expected = 4; + ftdi->ed_found = 0; + b = ftdi->response; + buscmd = (ftdi->response[0] >> 0) & 0x0F; + if (buscmd == 0x00) { + } else if (buscmd == 0x02) { + } else if (buscmd == 0x06) { + } else if (buscmd == 0x0A) { + } else + dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) value = %08X\n", + buscmd, data); + goto have; + } else { + if ((ftdi->response[0] & 0x80) == 0x00) { + ftdi->expected = 8; + goto have; + } else { + int ed_number = (ftdi->response[0] >> 5) & 0x03; + int ed_type = (ftdi->response[0] >> 0) & 0x03; + u16 ed_length = (ftdi->response[2] << 8) | + ftdi->response[1]; + struct u132_target *target = &ftdi->target[ + ed_number]; + target->halted = (ftdi->response[0] >> 3) & + 0x01; + target->skipped = (ftdi->response[0] >> 2) & + 0x01; + target->toggle_bits = (ftdi->response[3] >> 6) + & 0x03; + target->error_count = (ftdi->response[3] >> 4) + & 0x03; + target->condition_code = (ftdi->response[ + 3] >> 0) & 0x0F; + if ((ftdi->response[0] & 0x10) == 0x00) { + b = have_ed_set_response(ftdi, target, + ed_length, ed_number, ed_type, + b); + goto have; + } else { + b = have_ed_get_response(ftdi, target, + ed_length, ed_number, ed_type, + b); + goto have; + } + } + } + } else + goto more; } /* -* create a urb, and a buffer for it, and copy the data to the urb -* -*/ + * create a urb, and a buffer for it, and copy the data to the urb + * + */ static ssize_t ftdi_elan_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos) { - int retval = 0; - struct urb *urb; - char *buf; - struct usb_ftdi *ftdi = file->private_data; - - if (ftdi->disconnected > 0) { - return -ENODEV; - } - if (count == 0) { - goto exit; - } - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - retval = -ENOMEM; - goto error_1; - } - buf = usb_alloc_coherent(ftdi->udev, count, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - retval = -ENOMEM; - goto error_2; - } - if (copy_from_user(buf, user_buffer, count)) { - retval = -EFAULT; - goto error_3; - } - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, count, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed submitting write urb, error %" - "d\n", retval); - goto error_3; - } - usb_free_urb(urb); + int retval = 0; + struct urb *urb; + char *buf; + struct usb_ftdi *ftdi = file->private_data; + + if (ftdi->disconnected > 0) { + return -ENODEV; + } + if (count == 0) { + goto exit; + } + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + retval = -ENOMEM; + goto error_1; + } + buf = usb_alloc_coherent(ftdi->udev, count, GFP_KERNEL, + &urb->transfer_dma); + if (!buf) { + retval = -ENOMEM; + goto error_2; + } + if (copy_from_user(buf, user_buffer, count)) { + retval = -EFAULT; + goto error_3; + } + usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, + ftdi->bulk_out_endpointAddr), buf, count, + ftdi_elan_write_bulk_callback, ftdi); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + retval = usb_submit_urb(urb, GFP_KERNEL); + if (retval) { + dev_err(&ftdi->udev->dev, + "failed submitting write urb, error %d\n", retval); + goto error_3; + } + usb_free_urb(urb); exit: - return count; + return count; error_3: usb_free_coherent(ftdi->udev, count, buf, urb->transfer_dma); error_2: @@ -1198,29 +1189,29 @@ static ssize_t ftdi_elan_write(struct file *file, } static const struct file_operations ftdi_elan_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = ftdi_elan_read, - .write = ftdi_elan_write, - .open = ftdi_elan_open, - .release = ftdi_elan_release, + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = ftdi_elan_read, + .write = ftdi_elan_write, + .open = ftdi_elan_open, + .release = ftdi_elan_release, }; /* -* usb class driver info in order to get a minor number from the usb core, -* and to have the device registered with the driver core -*/ + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with the driver core + */ static struct usb_class_driver ftdi_elan_jtag_class = { - .name = "ftdi-%d-jtag", - .fops = &ftdi_elan_fops, - .minor_base = USB_FTDI_ELAN_MINOR_BASE, + .name = "ftdi-%d-jtag", + .fops = &ftdi_elan_fops, + .minor_base = USB_FTDI_ELAN_MINOR_BASE, }; /* -* the following definitions are for the -* ELAN FPGA state machgine processor that -* lies on the other side of the FTDI chip -*/ + * the following definitions are for the + * ELAN FPGA state machgine processor that + * lies on the other side of the FTDI chip + */ #define cPCIu132rd 0x0 #define cPCIu132wr 0x1 #define cPCIiord 0x2 @@ -1251,1694 +1242,1663 @@ static struct usb_class_driver ftdi_elan_jtag_class = { #define cCCnotaccessed 0xF static int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data) { - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | cPCIu132wr; - command->length = 0x04; - command->address = 0x00; - command->width = 0x00; - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } +wait:if (ftdi->disconnected > 0) { + return -ENODEV; + } else { + int command_size; + mutex_lock(&ftdi->u132_lock); + command_size = ftdi->command_next - ftdi->command_head; + if (command_size < COMMAND_SIZE) { + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + command->header = 0x00 | cPCIu132wr; + command->length = 0x04; + command->address = 0x00; + command->width = 0x00; + command->follows = 4; + command->value = data; + command->buffer = &command->value; + ftdi->command_next += 1; + ftdi_elan_kick_command_queue(ftdi); + mutex_unlock(&ftdi->u132_lock); + return 0; + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + goto wait; + } + } } static int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset, - u8 width, u32 data) -{ - u8 addressofs = config_offset / 4; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | (cPCIcfgwr & 0x0F); - command->length = 0x04; - command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } + u8 width, u32 data) +{ + u8 addressofs = config_offset / 4; +wait:if (ftdi->disconnected > 0) { + return -ENODEV; + } else { + int command_size; + mutex_lock(&ftdi->u132_lock); + command_size = ftdi->command_next - ftdi->command_head; + if (command_size < COMMAND_SIZE) { + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + command->header = 0x00 | (cPCIcfgwr & 0x0F); + command->length = 0x04; + command->address = addressofs; + command->width = 0x00 | (width & 0x0F); + command->follows = 4; + command->value = data; + command->buffer = &command->value; + ftdi->command_next += 1; + ftdi_elan_kick_command_queue(ftdi); + mutex_unlock(&ftdi->u132_lock); + return 0; + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + goto wait; + } + } } static int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset, - u8 width, u32 data) -{ - u8 addressofs = mem_offset / 4; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | (cPCImemwr & 0x0F); - command->length = 0x04; - command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } + u8 width, u32 data) +{ + u8 addressofs = mem_offset / 4; +wait:if (ftdi->disconnected > 0) { + return -ENODEV; + } else { + int command_size; + mutex_lock(&ftdi->u132_lock); + command_size = ftdi->command_next - ftdi->command_head; + if (command_size < COMMAND_SIZE) { + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + command->header = 0x00 | (cPCImemwr & 0x0F); + command->length = 0x04; + command->address = addressofs; + command->width = 0x00 | (width & 0x0F); + command->follows = 4; + command->value = data; + command->buffer = &command->value; + ftdi->command_next += 1; + ftdi_elan_kick_command_queue(ftdi); + mutex_unlock(&ftdi->u132_lock); + return 0; + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + goto wait; + } + } } int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset, - u8 width, u32 data) + u8 width, u32 data) { - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data); + struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); + return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data); } EXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem); static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data) { - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | cPCIu132rd; - command->length = 0x04; - respond->address = command->address = cU132cmd_status; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } +wait:if (ftdi->disconnected > 0) { + return -ENODEV; + } else { + int command_size; + int respond_size; + mutex_lock(&ftdi->u132_lock); + command_size = ftdi->command_next - ftdi->command_head; + respond_size = ftdi->respond_next - ftdi->respond_head; + if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) + { + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + struct u132_respond *respond = &ftdi->respond[ + RESPOND_MASK & ftdi->respond_next]; + int result = -ENODEV; + respond->result = &result; + respond->header = command->header = 0x00 | cPCIu132rd; + command->length = 0x04; + respond->address = command->address = cU132cmd_status; + command->width = 0x00; + command->follows = 0; + command->value = 0; + command->buffer = NULL; + respond->value = data; + init_completion(&respond->wait_completion); + ftdi->command_next += 1; + ftdi->respond_next += 1; + ftdi_elan_kick_command_queue(ftdi); + mutex_unlock(&ftdi->u132_lock); + wait_for_completion(&respond->wait_completion); + return result; + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + goto wait; + } + } } static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset, - u8 width, u32 *data) -{ - u8 addressofs = config_offset / 4; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | (cPCIcfgrd & - 0x0F); - command->length = 0x04; - respond->address = command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } + u8 width, u32 *data) +{ + u8 addressofs = config_offset / 4; +wait:if (ftdi->disconnected > 0) { + return -ENODEV; + } else { + int command_size; + int respond_size; + mutex_lock(&ftdi->u132_lock); + command_size = ftdi->command_next - ftdi->command_head; + respond_size = ftdi->respond_next - ftdi->respond_head; + if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) + { + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + struct u132_respond *respond = &ftdi->respond[ + RESPOND_MASK & ftdi->respond_next]; + int result = -ENODEV; + respond->result = &result; + respond->header = command->header = 0x00 | (cPCIcfgrd & + 0x0F); + command->length = 0x04; + respond->address = command->address = addressofs; + command->width = 0x00 | (width & 0x0F); + command->follows = 0; + command->value = 0; + command->buffer = NULL; + respond->value = data; + init_completion(&respond->wait_completion); + ftdi->command_next += 1; + ftdi->respond_next += 1; + ftdi_elan_kick_command_queue(ftdi); + mutex_unlock(&ftdi->u132_lock); + wait_for_completion(&respond->wait_completion); + return result; + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + goto wait; + } + } } static int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset, - u8 width, u32 *data) -{ - u8 addressofs = mem_offset / 4; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | (cPCImemrd & - 0x0F); - command->length = 0x04; - respond->address = command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } + u8 width, u32 *data) +{ + u8 addressofs = mem_offset / 4; +wait:if (ftdi->disconnected > 0) { + return -ENODEV; + } else { + int command_size; + int respond_size; + mutex_lock(&ftdi->u132_lock); + command_size = ftdi->command_next - ftdi->command_head; + respond_size = ftdi->respond_next - ftdi->respond_head; + if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) + { + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + struct u132_respond *respond = &ftdi->respond[ + RESPOND_MASK & ftdi->respond_next]; + int result = -ENODEV; + respond->result = &result; + respond->header = command->header = 0x00 | (cPCImemrd & + 0x0F); + command->length = 0x04; + respond->address = command->address = addressofs; + command->width = 0x00 | (width & 0x0F); + command->follows = 0; + command->value = 0; + command->buffer = NULL; + respond->value = data; + init_completion(&respond->wait_completion); + ftdi->command_next += 1; + ftdi->respond_next += 1; + ftdi_elan_kick_command_queue(ftdi); + mutex_unlock(&ftdi->u132_lock); + wait_for_completion(&respond->wait_completion); + return result; + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + goto wait; + } + } } int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset, - u8 width, u32 *data) + u8 width, u32 *data) { - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - if (ftdi->initialized == 0) { - return -ENODEV; - } else - return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data); + struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); + if (ftdi->initialized == 0) { + return -ENODEV; + } else + return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data); } EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem); static int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed << 5); - command->length = 0x8007; - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - command->follows = 8; - command->value = 0; - command->buffer = urb->setup_packet; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } + void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) +{ + u8 ed = ed_number - 1; +wait:if (ftdi->disconnected > 0) { + return -ENODEV; + } else if (ftdi->initialized == 0) { + return -ENODEV; + } else { + int command_size; + mutex_lock(&ftdi->u132_lock); + command_size = ftdi->command_next - ftdi->command_head; + if (command_size < COMMAND_SIZE) { + struct u132_target *target = &ftdi->target[ed]; + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + command->header = 0x80 | (ed << 5); + command->length = 0x8007; + command->address = (toggle_bits << 6) | (ep_number << 2) + | (address << 0); + command->width = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + command->follows = 8; + command->value = 0; + command->buffer = urb->setup_packet; + target->callback = callback; + target->endp = endp; + target->urb = urb; + target->active = 1; + ftdi->command_next += 1; + ftdi_elan_kick_command_queue(ftdi); + mutex_unlock(&ftdi->u132_lock); + return 0; + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + goto wait; + } + } } int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) + void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) { - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); + struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); + return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address, + ep_number, toggle_bits, callback); } EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup); static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - u32 remaining_length = urb->transfer_buffer_length - - urb->actual_length; - command->header = 0x82 | (ed << 5); - if (remaining_length == 0) { - command->length = 0x0000; - } else if (remaining_length > 1024) { - command->length = 0x8000 | 1023; - } else - command->length = 0x8000 | (remaining_length - - 1); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } + void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) +{ + u8 ed = ed_number - 1; +wait:if (ftdi->disconnected > 0) { + return -ENODEV; + } else if (ftdi->initialized == 0) { + return -ENODEV; + } else { + int command_size; + mutex_lock(&ftdi->u132_lock); + command_size = ftdi->command_next - ftdi->command_head; + if (command_size < COMMAND_SIZE) { + struct u132_target *target = &ftdi->target[ed]; + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + u32 remaining_length = urb->transfer_buffer_length - + urb->actual_length; + command->header = 0x82 | (ed << 5); + if (remaining_length == 0) { + command->length = 0x0000; + } else if (remaining_length > 1024) { + command->length = 0x8000 | 1023; + } else + command->length = 0x8000 | (remaining_length - + 1); + command->address = (toggle_bits << 6) | (ep_number << 2) + | (address << 0); + command->width = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + command->follows = 0; + command->value = 0; + command->buffer = NULL; + target->callback = callback; + target->endp = endp; + target->urb = urb; + target->active = 1; + ftdi->command_next += 1; + ftdi_elan_kick_command_queue(ftdi); + mutex_unlock(&ftdi->u132_lock); + return 0; + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + goto wait; + } + } } int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) + void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) { - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); + struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); + return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address, + ep_number, toggle_bits, callback); } EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input); static int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x81 | (ed << 5); - command->length = 0x0000; - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } + void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) +{ + u8 ed = ed_number - 1; +wait:if (ftdi->disconnected > 0) { + return -ENODEV; + } else if (ftdi->initialized == 0) { + return -ENODEV; + } else { + int command_size; + mutex_lock(&ftdi->u132_lock); + command_size = ftdi->command_next - ftdi->command_head; + if (command_size < COMMAND_SIZE) { + struct u132_target *target = &ftdi->target[ed]; + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + command->header = 0x81 | (ed << 5); + command->length = 0x0000; + command->address = (toggle_bits << 6) | (ep_number << 2) + | (address << 0); + command->width = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + command->follows = 0; + command->value = 0; + command->buffer = NULL; + target->callback = callback; + target->endp = endp; + target->urb = urb; + target->active = 1; + ftdi->command_next += 1; + ftdi_elan_kick_command_queue(ftdi); + mutex_unlock(&ftdi->u132_lock); + return 0; + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + goto wait; + } + } } int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) + void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) { - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); + struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); + return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address, + ep_number, toggle_bits, callback); } EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty); static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - u8 *b; - u16 urb_size; - int i = 0; - char data[30 *3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3; - int l = 0; - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x81 | (ed << 5); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - command->follows = min_t(u32, 1024, - urb->transfer_buffer_length - - urb->actual_length); - command->value = 0; - command->buffer = urb->transfer_buffer + - urb->actual_length; - command->length = 0x8000 | (command->follows - 1); - b = command->buffer; - urb_size = command->follows; - data[0] = 0; - while (urb_size-- > 0) { - if (i > m) { - } else if (i++ < m) { - int w = sprintf(d, " %02X", *b++); - d += w; - l += w; - } else - d += sprintf(d, " .."); - } - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } + void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) +{ + u8 ed = ed_number - 1; +wait:if (ftdi->disconnected > 0) { + return -ENODEV; + } else if (ftdi->initialized == 0) { + return -ENODEV; + } else { + int command_size; + mutex_lock(&ftdi->u132_lock); + command_size = ftdi->command_next - ftdi->command_head; + if (command_size < COMMAND_SIZE) { + u8 *b; + u16 urb_size; + int i = 0; + char data[30 *3 + 4]; + char *d = data; + int m = (sizeof(data) - 1) / 3; + int l = 0; + struct u132_target *target = &ftdi->target[ed]; + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + command->header = 0x81 | (ed << 5); + command->address = (toggle_bits << 6) | (ep_number << 2) + | (address << 0); + command->width = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + command->follows = min_t(u32, 1024, + urb->transfer_buffer_length - + urb->actual_length); + command->value = 0; + command->buffer = urb->transfer_buffer + + urb->actual_length; + command->length = 0x8000 | (command->follows - 1); + b = command->buffer; + urb_size = command->follows; + data[0] = 0; + while (urb_size-- > 0) { + if (i > m) { + } else if (i++ < m) { + int w = sprintf(d, " %02X", *b++); + d += w; + l += w; + } else + d += sprintf(d, " .."); + } + target->callback = callback; + target->endp = endp; + target->urb = urb; + target->active = 1; + ftdi->command_next += 1; + ftdi_elan_kick_command_queue(ftdi); + mutex_unlock(&ftdi->u132_lock); + return 0; + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + goto wait; + } + } } int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) + void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) { - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); + struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); + return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address, + ep_number, toggle_bits, callback); } EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output); static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - u32 remaining_length = urb->transfer_buffer_length - - urb->actual_length; - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x83 | (ed << 5); - if (remaining_length == 0) { - command->length = 0x0000; - } else if (remaining_length > 1024) { - command->length = 0x8000 | 1023; - } else - command->length = 0x8000 | (remaining_length - - 1); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } + void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) +{ + u8 ed = ed_number - 1; +wait:if (ftdi->disconnected > 0) { + return -ENODEV; + } else if (ftdi->initialized == 0) { + return -ENODEV; + } else { + int command_size; + mutex_lock(&ftdi->u132_lock); + command_size = ftdi->command_next - ftdi->command_head; + if (command_size < COMMAND_SIZE) { + u32 remaining_length = urb->transfer_buffer_length - + urb->actual_length; + struct u132_target *target = &ftdi->target[ed]; + struct u132_command *command = &ftdi->command[ + COMMAND_MASK & ftdi->command_next]; + command->header = 0x83 | (ed << 5); + if (remaining_length == 0) { + command->length = 0x0000; + } else if (remaining_length > 1024) { + command->length = 0x8000 | 1023; + } else + command->length = 0x8000 | (remaining_length - + 1); + command->address = (toggle_bits << 6) | (ep_number << 2) + | (address << 0); + command->width = usb_maxpacket(urb->dev, urb->pipe, + usb_pipeout(urb->pipe)); + command->follows = 0; + command->value = 0; + command->buffer = NULL; + target->callback = callback; + target->endp = endp; + target->urb = urb; + target->active = 1; + ftdi->command_next += 1; + ftdi_elan_kick_command_queue(ftdi); + mutex_unlock(&ftdi->u132_lock); + return 0; + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + goto wait; + } + } } int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) + void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, + void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, + int toggle_bits, int error_count, int condition_code, int repeat_number, + int halted, int skipped, int actual, int non_null)) { - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); + struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); + return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address, + ep_number, toggle_bits, callback); } EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single); static int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number, - void *endp) -{ - u8 ed = ed_number - 1; - if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - struct u132_target *target = &ftdi->target[ed]; - mutex_lock(&ftdi->u132_lock); - if (target->abandoning > 0) { - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - target->abandoning = 1; - wait_1:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = - &ftdi->command[COMMAND_MASK & - ftdi->command_next]; - command->header = 0x80 | (ed << 5) | - 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_1; - } - } - mutex_unlock(&ftdi->u132_lock); - return 0; - } - } + void *endp) +{ + u8 ed = ed_number - 1; + if (ftdi->disconnected > 0) { + return -ENODEV; + } else if (ftdi->initialized == 0) { + return -ENODEV; + } else { + struct u132_target *target = &ftdi->target[ed]; + mutex_lock(&ftdi->u132_lock); + if (target->abandoning > 0) { + mutex_unlock(&ftdi->u132_lock); + return 0; + } else { + target->abandoning = 1; + wait_1:if (target->active == 1) { + int command_size = ftdi->command_next - + ftdi->command_head; + if (command_size < COMMAND_SIZE) { + struct u132_command *command = + &ftdi->command[COMMAND_MASK & + ftdi->command_next]; + command->header = 0x80 | (ed << 5) | + 0x4; + command->length = 0x00; + command->address = 0x00; + command->width = 0x00; + command->follows = 0; + command->value = 0; + command->buffer = &command->value; + ftdi->command_next += 1; + ftdi_elan_kick_command_queue(ftdi); + } else { + mutex_unlock(&ftdi->u132_lock); + msleep(100); + mutex_lock(&ftdi->u132_lock); + goto wait_1; + } + } + mutex_unlock(&ftdi->u132_lock); + return 0; + } + } } int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number, - void *endp) + void *endp) { - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_flush(ftdi, ed_number, endp); + struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); + return ftdi_elan_edset_flush(ftdi, ed_number, endp); } EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush); static int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi) { - int retry_on_empty = 10; - int retry_on_timeout = 5; - int retry_on_status = 20; - more:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 100); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - char c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", - 0x000000FF & c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - continue; - } - goto more; - } else if (packet_bytes > 1) { - char s1 = ftdi->bulk_in_buffer[0]; - char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x60) { - return 0; - } else if (retry_on_status-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" - "imit reached\n"); - return -EFAULT; - } - } else if (packet_bytes > 0) { - char b1 = ftdi->bulk_in_buffer[0]; - dev_err(&ftdi->udev->dev, "only one byte flushed from F" - "TDI = %02X\n", b1); - if (retry_on_status-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" - "imit reached\n"); - return -EFAULT; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limi" - "t reached\n"); - return -ENOMEM; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry l" - "imit reached\n"); - return -ENOMEM; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", retval); - return retval; - } - } - return -1; + int retry_on_empty = 10; + int retry_on_timeout = 5; + int retry_on_status = 20; +more:{ + int packet_bytes = 0; + int retval = usb_bulk_msg(ftdi->udev, + usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), + ftdi->bulk_in_buffer, ftdi->bulk_in_size, + &packet_bytes, 100); + if (packet_bytes > 2) { + char diag[30 *3 + 4]; + char *d = diag; + int m = (sizeof(diag) - 1) / 3; + char *b = ftdi->bulk_in_buffer; + int bytes_read = 0; + diag[0] = 0; + while (packet_bytes-- > 0) { + char c = *b++; + if (bytes_read < m) { + d += sprintf(d, " %02X", + 0x000000FF & c); + } else if (bytes_read > m) { + } else + d += sprintf(d, " .."); + bytes_read += 1; + continue; + } + goto more; + } else if (packet_bytes > 1) { + char s1 = ftdi->bulk_in_buffer[0]; + char s2 = ftdi->bulk_in_buffer[1]; + if (s1 == 0x31 && s2 == 0x60) { + return 0; + } else if (retry_on_status-- > 0) { + goto more; + } else { + dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); + return -EFAULT; + } + } else if (packet_bytes > 0) { + char b1 = ftdi->bulk_in_buffer[0]; + dev_err(&ftdi->udev->dev, "only one byte flushed from FTDI = %02X\n", + b1); + if (retry_on_status-- > 0) { + goto more; + } else { + dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); + return -EFAULT; + } + } else if (retval == -ETIMEDOUT) { + if (retry_on_timeout-- > 0) { + goto more; + } else { + dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); + return -ENOMEM; + } + } else if (retval == 0) { + if (retry_on_empty-- > 0) { + goto more; + } else { + dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); + return -ENOMEM; + } + } else { + dev_err(&ftdi->udev->dev, "error = %d\n", retval); + return retval; + } + } + return -1; } /* -* send the long flush sequence -* -*/ + * send the long flush sequence + * + */ static int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi) { - int retval; - struct urb *urb; - char *buf; - int I = 257; - int i = 0; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequ" - "ence\n"); - return -ENOMEM; - } - buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer for flush seq" - "uence\n"); - usb_free_urb(urb); - return -ENOMEM; - } - while (I-- > 0) - buf[i++] = 0x55; - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, i, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed to submit urb containing the " - "flush sequence\n"); - usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); - usb_free_urb(urb); - return -ENOMEM; - } - usb_free_urb(urb); - return 0; + int retval; + struct urb *urb; + char *buf; + int I = 257; + int i = 0; + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequence\n"); + return -ENOMEM; + } + buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); + if (!buf) { + dev_err(&ftdi->udev->dev, "could not get a buffer for flush sequence\n"); + usb_free_urb(urb); + return -ENOMEM; + } + while (I-- > 0) + buf[i++] = 0x55; + usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, + ftdi->bulk_out_endpointAddr), buf, i, + ftdi_elan_write_bulk_callback, ftdi); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + retval = usb_submit_urb(urb, GFP_KERNEL); + if (retval) { + dev_err(&ftdi->udev->dev, "failed to submit urb containing the flush sequence\n"); + usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); + usb_free_urb(urb); + return -ENOMEM; + } + usb_free_urb(urb); + return 0; } /* -* send the reset sequence -* -*/ + * send the reset sequence + * + */ static int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi) { - int retval; - struct urb *urb; - char *buf; - int I = 4; - int i = 0; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&ftdi->udev->dev, "could not get a urb for the reset se" - "quence\n"); - return -ENOMEM; - } - buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer for the reset" - " sequence\n"); - usb_free_urb(urb); - return -ENOMEM; - } - buf[i++] = 0x55; - buf[i++] = 0xAA; - buf[i++] = 0x5A; - buf[i++] = 0xA5; - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, i, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed to submit urb containing the " - "reset sequence\n"); - usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); - usb_free_urb(urb); - return -ENOMEM; - } - usb_free_urb(urb); - return 0; + int retval; + struct urb *urb; + char *buf; + int I = 4; + int i = 0; + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + dev_err(&ftdi->udev->dev, "could not get a urb for the reset sequence\n"); + return -ENOMEM; + } + buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); + if (!buf) { + dev_err(&ftdi->udev->dev, "could not get a buffer for the reset sequence\n"); + usb_free_urb(urb); + return -ENOMEM; + } + buf[i++] = 0x55; + buf[i++] = 0xAA; + buf[i++] = 0x5A; + buf[i++] = 0xA5; + usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, + ftdi->bulk_out_endpointAddr), buf, i, + ftdi_elan_write_bulk_callback, ftdi); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + retval = usb_submit_urb(urb, GFP_KERNEL); + if (retval) { + dev_err(&ftdi->udev->dev, "failed to submit urb containing the reset sequence\n"); + usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); + usb_free_urb(urb); + return -ENOMEM; + } + usb_free_urb(urb); + return 0; } static int ftdi_elan_synchronize(struct usb_ftdi *ftdi) { - int retval; - int long_stop = 10; - int retry_on_timeout = 5; - int retry_on_empty = 10; - int err_count = 0; - retval = ftdi_elan_flush_input_fifo(ftdi); - if (retval) - return retval; - ftdi->bulk_in_left = 0; - ftdi->bulk_in_last = -1; - while (long_stop-- > 0) { - int read_stop; - int read_stuck; - retval = ftdi_elan_synchronize_flush(ftdi); - if (retval) - return retval; - retval = ftdi_elan_flush_input_fifo(ftdi); - if (retval) - return retval; - reset:retval = ftdi_elan_synchronize_reset(ftdi); - if (retval) - return retval; - read_stop = 100; - read_stuck = 10; - read:{ - int packet_bytes = 0; - retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, - ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 500); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - unsigned char c = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - continue; - } - if (c == 0x7E) { - return 0; - } else { - if (c == 0x55) { - goto read; - } else if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retr" - "y limit reached\n"); - continue; - } - } - } else if (packet_bytes > 1) { - unsigned char s1 = ftdi->bulk_in_buffer[0]; - unsigned char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x00) { - if (read_stuck-- > 0) { - goto read; - } else - goto reset; - } else if (s1 == 0x31 && s2 == 0x60) { - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retr" - "y limit reached\n"); - continue; - } - } else { - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retr" - "y limit reached\n"); - continue; - } - } - } else if (packet_bytes > 0) { - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit " - "reached\n"); - continue; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT re" - "try limit reached\n"); - continue; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "empty packet" - " retry limit reached\n"); - continue; - } - } else { - err_count += 1; - dev_err(&ftdi->udev->dev, "error = %d\n", - retval); - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit " - "reached\n"); - continue; - } - } - } - } - dev_err(&ftdi->udev->dev, "failed to synchronize\n"); - return -EFAULT; + int retval; + int long_stop = 10; + int retry_on_timeout = 5; + int retry_on_empty = 10; + int err_count = 0; + retval = ftdi_elan_flush_input_fifo(ftdi); + if (retval) + return retval; + ftdi->bulk_in_left = 0; + ftdi->bulk_in_last = -1; + while (long_stop-- > 0) { + int read_stop; + int read_stuck; + retval = ftdi_elan_synchronize_flush(ftdi); + if (retval) + return retval; + retval = ftdi_elan_flush_input_fifo(ftdi); + if (retval) + return retval; + reset:retval = ftdi_elan_synchronize_reset(ftdi); + if (retval) + return retval; + read_stop = 100; + read_stuck = 10; + read:{ + int packet_bytes = 0; + retval = usb_bulk_msg(ftdi->udev, + usb_rcvbulkpipe(ftdi->udev, + ftdi->bulk_in_endpointAddr), + ftdi->bulk_in_buffer, ftdi->bulk_in_size, + &packet_bytes, 500); + if (packet_bytes > 2) { + char diag[30 *3 + 4]; + char *d = diag; + int m = (sizeof(diag) - 1) / 3; + char *b = ftdi->bulk_in_buffer; + int bytes_read = 0; + unsigned char c = 0; + diag[0] = 0; + while (packet_bytes-- > 0) { + c = *b++; + if (bytes_read < m) { + d += sprintf(d, " %02X", c); + } else if (bytes_read > m) { + } else + d += sprintf(d, " .."); + bytes_read += 1; + continue; + } + if (c == 0x7E) { + return 0; + } else { + if (c == 0x55) { + goto read; + } else if (read_stop-- > 0) { + goto read; + } else { + dev_err(&ftdi->udev->dev, "retry limit reached\n"); + continue; + } + } + } else if (packet_bytes > 1) { + unsigned char s1 = ftdi->bulk_in_buffer[0]; + unsigned char s2 = ftdi->bulk_in_buffer[1]; + if (s1 == 0x31 && s2 == 0x00) { + if (read_stuck-- > 0) { + goto read; + } else + goto reset; + } else if (s1 == 0x31 && s2 == 0x60) { + if (read_stop-- > 0) { + goto read; + } else { + dev_err(&ftdi->udev->dev, "retry limit reached\n"); + continue; + } + } else { + if (read_stop-- > 0) { + goto read; + } else { + dev_err(&ftdi->udev->dev, "retry limit reached\n"); + continue; + } + } + } else if (packet_bytes > 0) { + if (read_stop-- > 0) { + goto read; + } else { + dev_err(&ftdi->udev->dev, "retry limit reached\n"); + continue; + } + } else if (retval == -ETIMEDOUT) { + if (retry_on_timeout-- > 0) { + goto read; + } else { + dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); + continue; + } + } else if (retval == 0) { + if (retry_on_empty-- > 0) { + goto read; + } else { + dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); + continue; + } + } else { + err_count += 1; + dev_err(&ftdi->udev->dev, "error = %d\n", + retval); + if (read_stop-- > 0) { + goto read; + } else { + dev_err(&ftdi->udev->dev, "retry limit reached\n"); + continue; + } + } + } + } + dev_err(&ftdi->udev->dev, "failed to synchronize\n"); + return -EFAULT; } static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi) { - int retry_on_empty = 10; - int retry_on_timeout = 5; - int retry_on_status = 50; - more:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 1000); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - char c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", - 0x000000FF & c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - continue; - } - goto more; - } else if (packet_bytes > 1) { - char s1 = ftdi->bulk_in_buffer[0]; - char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x60) { - return 0; - } else if (retry_on_status-- > 0) { - msleep(5); - goto more; - } else - return -EFAULT; - } else if (packet_bytes > 0) { - char b1 = ftdi->bulk_in_buffer[0]; - dev_err(&ftdi->udev->dev, "only one byte flushed from F" - "TDI = %02X\n", b1); - if (retry_on_status-- > 0) { - msleep(5); - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" - "imit reached\n"); - return -EFAULT; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limi" - "t reached\n"); - return -ENOMEM; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry l" - "imit reached\n"); - return -ENOMEM; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", retval); - return -ENOMEM; - } - } - return -1; + int retry_on_empty = 10; + int retry_on_timeout = 5; + int retry_on_status = 50; +more:{ + int packet_bytes = 0; + int retval = usb_bulk_msg(ftdi->udev, + usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), + ftdi->bulk_in_buffer, ftdi->bulk_in_size, + &packet_bytes, 1000); + if (packet_bytes > 2) { + char diag[30 *3 + 4]; + char *d = diag; + int m = (sizeof(diag) - 1) / 3; + char *b = ftdi->bulk_in_buffer; + int bytes_read = 0; + diag[0] = 0; + while (packet_bytes-- > 0) { + char c = *b++; + if (bytes_read < m) { + d += sprintf(d, " %02X", + 0x000000FF & c); + } else if (bytes_read > m) { + } else + d += sprintf(d, " .."); + bytes_read += 1; + continue; + } + goto more; + } else if (packet_bytes > 1) { + char s1 = ftdi->bulk_in_buffer[0]; + char s2 = ftdi->bulk_in_buffer[1]; + if (s1 == 0x31 && s2 == 0x60) { + return 0; + } else if (retry_on_status-- > 0) { + msleep(5); + goto more; + } else + return -EFAULT; + } else if (packet_bytes > 0) { + char b1 = ftdi->bulk_in_buffer[0]; + dev_err(&ftdi->udev->dev, "only one byte flushed from FTDI = %02X\n", b1); + if (retry_on_status-- > 0) { + msleep(5); + goto more; + } else { + dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); + return -EFAULT; + } + } else if (retval == -ETIMEDOUT) { + if (retry_on_timeout-- > 0) { + goto more; + } else { + dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); + return -ENOMEM; + } + } else if (retval == 0) { + if (retry_on_empty-- > 0) { + goto more; + } else { + dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); + return -ENOMEM; + } + } else { + dev_err(&ftdi->udev->dev, "error = %d\n", retval); + return -ENOMEM; + } + } + return -1; } static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi) { - int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg); - if (UxxxStatus) - return UxxxStatus; - if (ftdi->controlreg & 0x00400000) { - if (ftdi->card_ejected) { - } else { - ftdi->card_ejected = 1; - dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = " - "%08X\n", ftdi->controlreg); - } - return -ENODEV; - } else { - u8 fn = ftdi->function - 1; - int activePCIfn = fn << 8; - u32 pcidata; - u32 pciVID; - u32 pciPID; - int reg = 0; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - pciVID = pcidata & 0xFFFF; - pciPID = (pcidata >> 16) & 0xFFFF; - if (pciVID == ftdi->platform_data.vendor && pciPID == - ftdi->platform_data.device) { - return 0; - } else { - dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X devi" - "ce=%04X pciPID=%04X\n", - ftdi->platform_data.vendor, pciVID, - ftdi->platform_data.device, pciPID); - return -ENODEV; - } - } + int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg); + if (UxxxStatus) + return UxxxStatus; + if (ftdi->controlreg & 0x00400000) { + if (ftdi->card_ejected) { + } else { + ftdi->card_ejected = 1; + dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = %08X\n", + ftdi->controlreg); + } + return -ENODEV; + } else { + u8 fn = ftdi->function - 1; + int activePCIfn = fn << 8; + u32 pcidata; + u32 pciVID; + u32 pciPID; + int reg = 0; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); + if (UxxxStatus) + return UxxxStatus; + pciVID = pcidata & 0xFFFF; + pciPID = (pcidata >> 16) & 0xFFFF; + if (pciVID == ftdi->platform_data.vendor && pciPID == + ftdi->platform_data.device) { + return 0; + } else { + dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X device=%04X pciPID=%04X\n", + ftdi->platform_data.vendor, pciVID, + ftdi->platform_data.device, pciPID); + return -ENODEV; + } + } } #define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \ - offsetof(struct ohci_regs, member), 0, data); + offsetof(struct ohci_regs, member), 0, data); #define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \ - offsetof(struct ohci_regs, member), 0, data); + offsetof(struct ohci_regs, member), 0, data); #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR -#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ - OHCI_INTR_WDH) +#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ + OHCI_INTR_WDH) static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk) { - int devices = 0; - int retval; - u32 hc_control; - int num_ports; - u32 control; - u32 rh_a = -1; - u32 status; - u32 fminterval; - u32 hc_fminterval; - u32 periodicstart; - u32 cmdstatus; - u32 roothub_a; - int mask = OHCI_INTR_INIT; - int sleep_time = 0; - int reset_timeout = 30; /* ... allow extra time */ - int temp; - retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a); - if (retval) - return retval; - num_ports = rh_a & RH_A_NDP; - retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval); - if (retval) - return retval; - hc_fminterval &= 0x3fff; - if (hc_fminterval != FI) { - } - hc_fminterval |= FSMP(hc_fminterval) << 16; - retval = ftdi_read_pcimem(ftdi, control, &hc_control); - if (retval) - return retval; - switch (hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - sleep_time = 0; - break; - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_USB_RESUME; - sleep_time = 10; - break; - default: - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_USB_RESET; - sleep_time = 50; - break; - } - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - msleep(sleep_time); - retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); - if (retval) - return retval; - if (!(roothub_a & RH_A_NPS)) { /* power down each port */ - for (temp = 0; temp < num_ports; temp++) { - retval = ftdi_write_pcimem(ftdi, - roothub.portstatus[temp], RH_PS_LSDA); - if (retval) - return retval; - } - } - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR); - if (retval) - return retval; - extra:{ - retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); - if (retval) - return retval; - if (0 != (status & OHCI_HCR)) { - if (--reset_timeout == 0) { - dev_err(&ftdi->udev->dev, "USB HC reset timed o" - "ut!\n"); - return -ENODEV; - } else { - msleep(5); - goto extra; - } - } - } - if (quirk & OHCI_QUIRK_INITRESET) { - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - } - retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, fminterval, - ((fminterval & FIT) ^ FIT) | hc_fminterval); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, periodicstart, - ((9 *hc_fminterval) / 10) & 0x3fff); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart); - if (retval) - return retval; - if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { - if (!(quirk & OHCI_QUIRK_INITRESET)) { - quirk |= OHCI_QUIRK_INITRESET; - goto retry; - } else - dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n", - fminterval, periodicstart); - } /* start controller operations */ - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, intrstatus, mask); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, intrdisable, - OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | - OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | - OHCI_INTR_SO); - if (retval) - return retval; /* handle root hub init quirks ... */ - retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); - if (retval) - return retval; - roothub_a &= ~(RH_A_PSM | RH_A_OCPM); - if (quirk & OHCI_QUIRK_SUPERIO) { - roothub_a |= RH_A_NOCP; - roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); - retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); - if (retval) - return retval; - } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) { - roothub_a |= RH_A_NPS; - retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); - if (retval) - return retval; - } - retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, roothub.b, - (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - mdelay((roothub_a >> 23) & 0x1fe); - for (temp = 0; temp < num_ports; temp++) { - u32 portstatus; - retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp], - &portstatus); - if (retval) - return retval; - if (1 & portstatus) - devices += 1; - } - return devices; + int devices = 0; + int retval; + u32 hc_control; + int num_ports; + u32 control; + u32 rh_a = -1; + u32 status; + u32 fminterval; + u32 hc_fminterval; + u32 periodicstart; + u32 cmdstatus; + u32 roothub_a; + int mask = OHCI_INTR_INIT; + int sleep_time = 0; + int reset_timeout = 30; /* ... allow extra time */ + int temp; + retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a); + if (retval) + return retval; + num_ports = rh_a & RH_A_NDP; + retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval); + if (retval) + return retval; + hc_fminterval &= 0x3fff; + if (hc_fminterval != FI) { + } + hc_fminterval |= FSMP(hc_fminterval) << 16; + retval = ftdi_read_pcimem(ftdi, control, &hc_control); + if (retval) + return retval; + switch (hc_control & OHCI_CTRL_HCFS) { + case OHCI_USB_OPER: + sleep_time = 0; + break; + case OHCI_USB_SUSPEND: + case OHCI_USB_RESUME: + hc_control &= OHCI_CTRL_RWC; + hc_control |= OHCI_USB_RESUME; + sleep_time = 10; + break; + default: + hc_control &= OHCI_CTRL_RWC; + hc_control |= OHCI_USB_RESET; + sleep_time = 50; + break; + } + retval = ftdi_write_pcimem(ftdi, control, hc_control); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + msleep(sleep_time); + retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); + if (retval) + return retval; + if (!(roothub_a & RH_A_NPS)) { /* power down each port */ + for (temp = 0; temp < num_ports; temp++) { + retval = ftdi_write_pcimem(ftdi, + roothub.portstatus[temp], RH_PS_LSDA); + if (retval) + return retval; + } + } + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; +retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR); + if (retval) + return retval; +extra:{ + retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); + if (retval) + return retval; + if (0 != (status & OHCI_HCR)) { + if (--reset_timeout == 0) { + dev_err(&ftdi->udev->dev, "USB HC reset timed out!\n"); + return -ENODEV; + } else { + msleep(5); + goto extra; + } + } + } + if (quirk & OHCI_QUIRK_INITRESET) { + retval = ftdi_write_pcimem(ftdi, control, hc_control); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + } + retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, fminterval, + ((fminterval & FIT) ^ FIT) | hc_fminterval); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, periodicstart, + ((9 *hc_fminterval) / 10) & 0x3fff); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart); + if (retval) + return retval; + if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { + if (!(quirk & OHCI_QUIRK_INITRESET)) { + quirk |= OHCI_QUIRK_INITRESET; + goto retry; + } else + dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n", + fminterval, periodicstart); + } /* start controller operations */ + hc_control &= OHCI_CTRL_RWC; + hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; + retval = ftdi_write_pcimem(ftdi, control, hc_control); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, intrstatus, mask); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, intrdisable, + OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | + OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | + OHCI_INTR_SO); + if (retval) + return retval; /* handle root hub init quirks ... */ + retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); + if (retval) + return retval; + roothub_a &= ~(RH_A_PSM | RH_A_OCPM); + if (quirk & OHCI_QUIRK_SUPERIO) { + roothub_a |= RH_A_NOCP; + roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); + retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); + if (retval) + return retval; + } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) { + roothub_a |= RH_A_NPS; + retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); + if (retval) + return retval; + } + retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, roothub.b, + (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + mdelay((roothub_a >> 23) & 0x1fe); + for (temp = 0; temp < num_ports; temp++) { + u32 portstatus; + retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp], + &portstatus); + if (retval) + return retval; + if (1 & portstatus) + devices += 1; + } + return devices; } static int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn) { - u32 latence_timer; - int UxxxStatus; - u32 pcidata; - int reg = 0; - int activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); - if (UxxxStatus) - return UxxxStatus; - reg = 16; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xFFFFFFFF); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xF0000000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 12; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &latence_timer); - if (UxxxStatus) - return UxxxStatus; - latence_timer &= 0xFFFF00FF; - latence_timer |= 0x00001600; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - latence_timer); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 4; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - 0x06); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - for (reg = 0; reg <= 0x54; reg += 4) { - UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (UxxxStatus) - return UxxxStatus; - } - return 0; + u32 latence_timer; + int UxxxStatus; + u32 pcidata; + int reg = 0; + int activePCIfn = fn << 8; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); + if (UxxxStatus) + return UxxxStatus; + reg = 16; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, + 0xFFFFFFFF); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, + 0xF0000000); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); + if (UxxxStatus) + return UxxxStatus; + reg = 12; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &latence_timer); + if (UxxxStatus) + return UxxxStatus; + latence_timer &= 0xFFFF00FF; + latence_timer |= 0x00001600; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, + latence_timer); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); + if (UxxxStatus) + return UxxxStatus; + reg = 4; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, + 0x06); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); + if (UxxxStatus) + return UxxxStatus; + for (reg = 0; reg <= 0x54; reg += 4) { + UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); + if (UxxxStatus) + return UxxxStatus; + } + return 0; } static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn) { - u32 latence_timer; - int UxxxStatus; - u32 pcidata; - int reg = 0; - int activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); - if (UxxxStatus) - return UxxxStatus; - reg = 16; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xFFFFFFFF); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0x00000000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 12; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &latence_timer); - if (UxxxStatus) - return UxxxStatus; - latence_timer &= 0xFFFF00FF; - latence_timer |= 0x00001600; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - latence_timer); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 4; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - 0x00); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - return 0; + u32 latence_timer; + int UxxxStatus; + u32 pcidata; + int reg = 0; + int activePCIfn = fn << 8; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); + if (UxxxStatus) + return UxxxStatus; + reg = 16; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, + 0xFFFFFFFF); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, + 0x00000000); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); + if (UxxxStatus) + return UxxxStatus; + reg = 12; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &latence_timer); + if (UxxxStatus) + return UxxxStatus; + latence_timer &= 0xFFFF00FF; + latence_timer |= 0x00001600; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, + latence_timer); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); + if (UxxxStatus) + return UxxxStatus; + reg = 4; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, + 0x00); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); + if (UxxxStatus) + return UxxxStatus; + return 0; } static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk) { - int result; - int UxxxStatus; - UxxxStatus = ftdi_elan_setup_controller(ftdi, fn); - if (UxxxStatus) - return UxxxStatus; - result = ftdi_elan_check_controller(ftdi, quirk); - UxxxStatus = ftdi_elan_close_controller(ftdi, fn); - if (UxxxStatus) - return UxxxStatus; - return result; + int result; + int UxxxStatus; + UxxxStatus = ftdi_elan_setup_controller(ftdi, fn); + if (UxxxStatus) + return UxxxStatus; + result = ftdi_elan_check_controller(ftdi, quirk); + UxxxStatus = ftdi_elan_close_controller(ftdi, fn); + if (UxxxStatus) + return UxxxStatus; + return result; } static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) { - u32 controlreg; - u8 sensebits; - int UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); - if (UxxxStatus) - return UxxxStatus; - msleep(750); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); - if (UxxxStatus) - return UxxxStatus; - msleep(250); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - msleep(1000); - sensebits = (controlreg >> 16) & 0x000F; - if (0x0D == sensebits) - return 0; - else + u32 controlreg; + u8 sensebits; + int UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); + if (UxxxStatus) + return UxxxStatus; + msleep(750); + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); + if (UxxxStatus) + return UxxxStatus; + msleep(250); + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + msleep(1000); + sensebits = (controlreg >> 16) & 0x000F; + if (0x0D == sensebits) + return 0; + else return - ENXIO; } static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) { - int UxxxStatus; - u32 pcidata; - int reg = 0; - u8 fn; - int activePCIfn = 0; - int max_devices = 0; - int controllers = 0; - int unrecognized = 0; - ftdi->function = 0; - for (fn = 0; (fn < 4); fn++) { - u32 pciVID = 0; - u32 pciPID = 0; - int devices = 0; - activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - pciVID = pcidata & 0xFFFF; - pciPID = (pcidata >> 16) & 0xFFFF; - if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035)) - { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802)) - { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) { - devices = ftdi_elan_found_controller(ftdi, fn, - OHCI_QUIRK_AMD756); - controllers += 1; - } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) { - devices = ftdi_elan_found_controller(ftdi, fn, - OHCI_QUIRK_ZFMICRO); - controllers += 1; - } else if (0 == pcidata) { - } else - unrecognized += 1; - if (devices > max_devices) { - max_devices = devices; - ftdi->function = fn + 1; - ftdi->platform_data.vendor = pciVID; - ftdi->platform_data.device = pciPID; - } - } - if (ftdi->function > 0) { - UxxxStatus = ftdi_elan_setup_controller(ftdi, - ftdi->function - 1); - if (UxxxStatus) - return UxxxStatus; - return 0; - } else if (controllers > 0) { - return -ENXIO; - } else if (unrecognized > 0) { - return -ENXIO; - } else { - ftdi->enumerated = 0; - return -ENXIO; - } + int UxxxStatus; + u32 pcidata; + int reg = 0; + u8 fn; + int activePCIfn = 0; + int max_devices = 0; + int controllers = 0; + int unrecognized = 0; + ftdi->function = 0; + for (fn = 0; (fn < 4); fn++) { + u32 pciVID = 0; + u32 pciPID = 0; + int devices = 0; + activePCIfn = fn << 8; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); + if (UxxxStatus) + return UxxxStatus; + pciVID = pcidata & 0xFFFF; + pciPID = (pcidata >> 16) & 0xFFFF; + if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) { + devices = ftdi_elan_found_controller(ftdi, fn, 0); + controllers += 1; + } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035)) + { + devices = ftdi_elan_found_controller(ftdi, fn, 0); + controllers += 1; + } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) { + devices = ftdi_elan_found_controller(ftdi, fn, 0); + controllers += 1; + } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802)) + { + devices = ftdi_elan_found_controller(ftdi, fn, 0); + controllers += 1; + } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) { + devices = ftdi_elan_found_controller(ftdi, fn, + OHCI_QUIRK_AMD756); + controllers += 1; + } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) { + devices = ftdi_elan_found_controller(ftdi, fn, + OHCI_QUIRK_ZFMICRO); + controllers += 1; + } else if (0 == pcidata) { + } else + unrecognized += 1; + if (devices > max_devices) { + max_devices = devices; + ftdi->function = fn + 1; + ftdi->platform_data.vendor = pciVID; + ftdi->platform_data.device = pciPID; + } + } + if (ftdi->function > 0) { + UxxxStatus = ftdi_elan_setup_controller(ftdi, + ftdi->function - 1); + if (UxxxStatus) + return UxxxStatus; + return 0; + } else if (controllers > 0) { + return -ENXIO; + } else if (unrecognized > 0) { + return -ENXIO; + } else { + ftdi->enumerated = 0; + return -ENXIO; + } } /* -* we use only the first bulk-in and bulk-out endpoints -*/ + * we use only the first bulk-in and bulk-out endpoints + */ static int ftdi_elan_probe(struct usb_interface *interface, - const struct usb_device_id *id) + const struct usb_device_id *id) { - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - size_t buffer_size; - int i; - int retval = -ENOMEM; - struct usb_ftdi *ftdi; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + size_t buffer_size; + int i; + int retval = -ENOMEM; + struct usb_ftdi *ftdi; ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); - if (!ftdi) { - printk(KERN_ERR "Out of memory\n"); - return -ENOMEM; - } - - mutex_lock(&ftdi_module_lock); - list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); - ftdi->sequence_num = ++ftdi_instances; - mutex_unlock(&ftdi_module_lock); - ftdi_elan_init_kref(ftdi); + if (!ftdi) + return -ENOMEM; + + mutex_lock(&ftdi_module_lock); + list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); + ftdi->sequence_num = ++ftdi_instances; + mutex_unlock(&ftdi_module_lock); + ftdi_elan_init_kref(ftdi); sema_init(&ftdi->sw_lock, 1); - ftdi->udev = usb_get_dev(interface_to_usbdev(interface)); - ftdi->interface = interface; - mutex_init(&ftdi->u132_lock); - ftdi->expected = 4; - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - if (!ftdi->bulk_in_endpointAddr && + ftdi->udev = usb_get_dev(interface_to_usbdev(interface)); + ftdi->interface = interface; + mutex_init(&ftdi->u132_lock); + ftdi->expected = 4; + iface_desc = interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + if (!ftdi->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) { - buffer_size = usb_endpoint_maxp(endpoint); - ftdi->bulk_in_size = buffer_size; - ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress; - ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!ftdi->bulk_in_buffer) { - dev_err(&ftdi->udev->dev, "Could not allocate b" - "ulk_in_buffer\n"); - retval = -ENOMEM; - goto error; - } - } - if (!ftdi->bulk_out_endpointAddr && + buffer_size = usb_endpoint_maxp(endpoint); + ftdi->bulk_in_size = buffer_size; + ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress; + ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!ftdi->bulk_in_buffer) { + dev_err(&ftdi->udev->dev, "Could not allocate bulk_in_buffer\n"); + retval = -ENOMEM; + goto error; + } + } + if (!ftdi->bulk_out_endpointAddr && usb_endpoint_is_bulk_out(endpoint)) { - ftdi->bulk_out_endpointAddr = - endpoint->bEndpointAddress; - } - } - if (!(ftdi->bulk_in_endpointAddr && ftdi->bulk_out_endpointAddr)) { - dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk" - "-out endpoints\n"); - retval = -ENODEV; - goto error; - } - dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n", - iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr, - ftdi->bulk_out_endpointAddr); - usb_set_intfdata(interface, ftdi); - if (iface_desc->desc.bInterfaceNumber == 0 && - ftdi->bulk_in_endpointAddr == 0x81 && - ftdi->bulk_out_endpointAddr == 0x02) { - retval = usb_register_dev(interface, &ftdi_elan_jtag_class); - if (retval) { - dev_err(&ftdi->udev->dev, "Not able to get a minor for " - "this device.\n"); - usb_set_intfdata(interface, NULL); - retval = -ENOMEM; - goto error; - } else { - ftdi->class = &ftdi_elan_jtag_class; - dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface " - "%d now attached to ftdi%d\n", ftdi, - iface_desc->desc.bInterfaceNumber, - interface->minor); - return 0; - } - } else if (iface_desc->desc.bInterfaceNumber == 1 && - ftdi->bulk_in_endpointAddr == 0x83 && - ftdi->bulk_out_endpointAddr == 0x04) { - ftdi->class = NULL; - dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a" - "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber); - INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); - INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); - INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); - ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); - return 0; - } else { - dev_err(&ftdi->udev->dev, - "Could not find ELAN's U132 device\n"); - retval = -ENODEV; - goto error; - } - error:if (ftdi) { - ftdi_elan_put_kref(ftdi); - } - return retval; + ftdi->bulk_out_endpointAddr = + endpoint->bEndpointAddress; + } + } + if (!(ftdi->bulk_in_endpointAddr && ftdi->bulk_out_endpointAddr)) { + dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk-out endpoints\n"); + retval = -ENODEV; + goto error; + } + dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n", + iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr, + ftdi->bulk_out_endpointAddr); + usb_set_intfdata(interface, ftdi); + if (iface_desc->desc.bInterfaceNumber == 0 && + ftdi->bulk_in_endpointAddr == 0x81 && + ftdi->bulk_out_endpointAddr == 0x02) { + retval = usb_register_dev(interface, &ftdi_elan_jtag_class); + if (retval) { + dev_err(&ftdi->udev->dev, "Not able to get a minor for this device\n"); + usb_set_intfdata(interface, NULL); + retval = -ENOMEM; + goto error; + } else { + ftdi->class = &ftdi_elan_jtag_class; + dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface %d now attached to ftdi%d\n", + ftdi, iface_desc->desc.bInterfaceNumber, + interface->minor); + return 0; + } + } else if (iface_desc->desc.bInterfaceNumber == 1 && + ftdi->bulk_in_endpointAddr == 0x83 && + ftdi->bulk_out_endpointAddr == 0x04) { + ftdi->class = NULL; + dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now activated\n", + ftdi, iface_desc->desc.bInterfaceNumber); + INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); + INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); + INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); + ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); + return 0; + } else { + dev_err(&ftdi->udev->dev, + "Could not find ELAN's U132 device\n"); + retval = -ENODEV; + goto error; + } +error:if (ftdi) { + ftdi_elan_put_kref(ftdi); + } + return retval; } static void ftdi_elan_disconnect(struct usb_interface *interface) { - struct usb_ftdi *ftdi = usb_get_intfdata(interface); - ftdi->disconnected += 1; - if (ftdi->class) { - int minor = interface->minor; - struct usb_class_driver *class = ftdi->class; - usb_set_intfdata(interface, NULL); - usb_deregister_dev(interface, class); - dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on min" - "or %d now disconnected\n", minor); - } else { - ftdi_status_cancel_work(ftdi); - ftdi_command_cancel_work(ftdi); - ftdi_response_cancel_work(ftdi); - ftdi_elan_abandon_completions(ftdi); - ftdi_elan_abandon_targets(ftdi); - if (ftdi->registered) { - platform_device_unregister(&ftdi->platform_dev); - ftdi->synchronized = 0; - ftdi->enumerated = 0; - ftdi->initialized = 0; - ftdi->registered = 0; - } - flush_workqueue(status_queue); - flush_workqueue(command_queue); - flush_workqueue(respond_queue); - ftdi->disconnected += 1; - usb_set_intfdata(interface, NULL); - dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller inter" - "face now disconnected\n"); - } - ftdi_elan_put_kref(ftdi); + struct usb_ftdi *ftdi = usb_get_intfdata(interface); + ftdi->disconnected += 1; + if (ftdi->class) { + int minor = interface->minor; + struct usb_class_driver *class = ftdi->class; + usb_set_intfdata(interface, NULL); + usb_deregister_dev(interface, class); + dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on minor %d now disconnected\n", + minor); + } else { + ftdi_status_cancel_work(ftdi); + ftdi_command_cancel_work(ftdi); + ftdi_response_cancel_work(ftdi); + ftdi_elan_abandon_completions(ftdi); + ftdi_elan_abandon_targets(ftdi); + if (ftdi->registered) { + platform_device_unregister(&ftdi->platform_dev); + ftdi->synchronized = 0; + ftdi->enumerated = 0; + ftdi->initialized = 0; + ftdi->registered = 0; + } + flush_workqueue(status_queue); + flush_workqueue(command_queue); + flush_workqueue(respond_queue); + ftdi->disconnected += 1; + usb_set_intfdata(interface, NULL); + dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller interface now disconnected\n"); + } + ftdi_elan_put_kref(ftdi); } static struct usb_driver ftdi_elan_driver = { - .name = "ftdi-elan", - .probe = ftdi_elan_probe, - .disconnect = ftdi_elan_disconnect, - .id_table = ftdi_elan_table, + .name = "ftdi-elan", + .probe = ftdi_elan_probe, + .disconnect = ftdi_elan_disconnect, + .id_table = ftdi_elan_table, }; static int __init ftdi_elan_init(void) { - int result; - printk(KERN_INFO "driver %s\n", ftdi_elan_driver.name); - mutex_init(&ftdi_module_lock); - INIT_LIST_HEAD(&ftdi_static_list); - status_queue = create_singlethread_workqueue("ftdi-status-control"); + int result; + pr_info("driver %s\n", ftdi_elan_driver.name); + mutex_init(&ftdi_module_lock); + INIT_LIST_HEAD(&ftdi_static_list); + status_queue = create_singlethread_workqueue("ftdi-status-control"); if (!status_queue) goto err_status_queue; - command_queue = create_singlethread_workqueue("ftdi-command-engine"); + command_queue = create_singlethread_workqueue("ftdi-command-engine"); if (!command_queue) goto err_command_queue; - respond_queue = create_singlethread_workqueue("ftdi-respond-engine"); + respond_queue = create_singlethread_workqueue("ftdi-respond-engine"); if (!respond_queue) goto err_respond_queue; - result = usb_register(&ftdi_elan_driver); - if (result) { + result = usb_register(&ftdi_elan_driver); + if (result) { destroy_workqueue(status_queue); destroy_workqueue(command_queue); destroy_workqueue(respond_queue); - printk(KERN_ERR "usb_register failed. Error number %d\n", - result); + pr_err("usb_register failed. Error number %d\n", result); } - return result; + return result; - err_respond_queue: +err_respond_queue: destroy_workqueue(command_queue); - err_command_queue: +err_command_queue: destroy_workqueue(status_queue); - err_status_queue: - printk(KERN_ERR "%s couldn't create workqueue\n", ftdi_elan_driver.name); +err_status_queue: + pr_err("%s couldn't create workqueue\n", ftdi_elan_driver.name); return -ENOMEM; } static void __exit ftdi_elan_exit(void) { - struct usb_ftdi *ftdi; - struct usb_ftdi *temp; - usb_deregister(&ftdi_elan_driver); - printk(KERN_INFO "ftdi_u132 driver deregistered\n"); - list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) { - ftdi_status_cancel_work(ftdi); - ftdi_command_cancel_work(ftdi); - ftdi_response_cancel_work(ftdi); - } flush_workqueue(status_queue); - destroy_workqueue(status_queue); - status_queue = NULL; - flush_workqueue(command_queue); - destroy_workqueue(command_queue); - command_queue = NULL; - flush_workqueue(respond_queue); - destroy_workqueue(respond_queue); - respond_queue = NULL; + struct usb_ftdi *ftdi; + struct usb_ftdi *temp; + usb_deregister(&ftdi_elan_driver); + pr_info("ftdi_u132 driver deregistered\n"); + list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) { + ftdi_status_cancel_work(ftdi); + ftdi_command_cancel_work(ftdi); + ftdi_response_cancel_work(ftdi); + } flush_workqueue(status_queue); + destroy_workqueue(status_queue); + status_queue = NULL; + flush_workqueue(command_queue); + destroy_workqueue(command_queue); + command_queue = NULL; + flush_workqueue(respond_queue); + destroy_workqueue(respond_queue); + respond_queue = NULL; } diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index b3aa0184af9ada..0a34dd8595554f 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include "musb_core.h" @@ -85,6 +85,7 @@ struct am35x_glue { struct device *dev; struct platform_device *musb; + struct platform_device *phy; struct clk *phy_clk; struct clk *clk; }; @@ -360,7 +361,6 @@ static int am35x_musb_init(struct musb *musb) if (!rev) return -ENODEV; - usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) return -EPROBE_DEFER; @@ -402,7 +402,6 @@ static int am35x_musb_exit(struct musb *musb) data->set_phy_power(0); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); return 0; } @@ -505,6 +504,9 @@ static int am35x_probe(struct platform_device *pdev) pdata->platform_ops = &am35x_ops; + glue->phy = usb_phy_generic_register(); + if (IS_ERR(glue->phy)) + goto err7; platform_set_drvdata(pdev, glue); pinfo = am35x_dev_info; @@ -518,11 +520,14 @@ static int am35x_probe(struct platform_device *pdev) if (IS_ERR(musb)) { ret = PTR_ERR(musb); dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); - goto err7; + goto err8; } return 0; +err8: + usb_phy_generic_unregister(glue->phy); + err7: clk_disable(clk); @@ -547,6 +552,7 @@ static int am35x_remove(struct platform_device *pdev) struct am35x_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(glue->phy); clk_disable(glue->clk); clk_disable(glue->phy_clk); clk_put(glue->clk); diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 796677fa9a15cf..d40d5f0b5528b6 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include @@ -29,6 +29,7 @@ struct bfin_glue { struct device *dev; struct platform_device *musb; + struct platform_device *phy; }; #define glue_to_musb(g) platform_get_drvdata(g->musb) @@ -401,7 +402,6 @@ static int bfin_musb_init(struct musb *musb) } gpio_direction_output(musb->config->gpio_vrsel, 0); - usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { gpio_free(musb->config->gpio_vrsel); @@ -424,9 +424,8 @@ static int bfin_musb_init(struct musb *musb) static int bfin_musb_exit(struct musb *musb) { gpio_free(musb->config->gpio_vrsel); - usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); + return 0; } @@ -477,6 +476,9 @@ static int bfin_probe(struct platform_device *pdev) pdata->platform_ops = &bfin_ops; + glue->phy = usb_phy_generic_register(); + if (IS_ERR(glue->phy)) + goto err2; platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -514,6 +516,9 @@ static int bfin_probe(struct platform_device *pdev) return 0; err3: + usb_phy_generic_unregister(glue->phy); + +err2: platform_device_put(musb); err1: @@ -528,6 +533,7 @@ static int bfin_remove(struct platform_device *pdev) struct bfin_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(glue->phy); kfree(glue); return 0; diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index e3486de719959a..058775e647adab 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include @@ -85,6 +85,7 @@ struct da8xx_glue { struct device *dev; struct platform_device *musb; + struct platform_device *phy; struct clk *clk; }; @@ -418,7 +419,6 @@ static int da8xx_musb_init(struct musb *musb) if (!rev) goto fail; - usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { ret = -EPROBE_DEFER; @@ -453,7 +453,6 @@ static int da8xx_musb_exit(struct musb *musb) phy_off(); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); return 0; } @@ -512,6 +511,11 @@ static int da8xx_probe(struct platform_device *pdev) pdata->platform_ops = &da8xx_ops; + glue->phy = usb_phy_generic_register(); + if (IS_ERR(glue->phy)) { + ret = PTR_ERR(glue->phy); + goto err5; + } platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -538,11 +542,14 @@ static int da8xx_probe(struct platform_device *pdev) if (IS_ERR(musb)) { ret = PTR_ERR(musb); dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); - goto err5; + goto err6; } return 0; +err6: + usb_phy_generic_unregister(glue->phy); + err5: clk_disable(clk); @@ -561,6 +568,7 @@ static int da8xx_remove(struct platform_device *pdev) struct da8xx_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(glue->phy); clk_disable(glue->clk); clk_put(glue->clk); kfree(glue); diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index c259dac9d056c9..de8492b06e467b 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include @@ -381,7 +381,6 @@ static int davinci_musb_init(struct musb *musb) u32 revision; int ret = -ENODEV; - usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { ret = -EPROBE_DEFER; @@ -439,7 +438,7 @@ static int davinci_musb_init(struct musb *musb) fail: usb_put_phy(musb->xceiv); unregister: - usb_nop_xceiv_unregister(); + usb_phy_generic_unregister(); return ret; } @@ -487,7 +486,6 @@ static int davinci_musb_exit(struct musb *musb) phy_off(); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); return 0; } @@ -545,6 +543,7 @@ static int davinci_probe(struct platform_device *pdev) pdata->platform_ops = &davinci_ops; + usb_phy_generic_register(); platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -603,6 +602,7 @@ static int davinci_remove(struct platform_device *pdev) struct davinci_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(); clk_disable(glue->clk); clk_put(glue->clk); kfree(glue); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 07576907e2c615..61da471b7aed2c 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -848,6 +848,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } } + /* handle babble condition */ + if (int_usb & MUSB_INTR_BABBLE) + schedule_work(&musb->recover_work); + #if 0 /* REVISIT ... this would be for multiplexing periodic endpoints, or * supporting transfer phasing to prevent exceeding ISO bandwidth @@ -1746,6 +1750,34 @@ static void musb_irq_work(struct work_struct *data) } } +/* Recover from babble interrupt conditions */ +static void musb_recover_work(struct work_struct *data) +{ + struct musb *musb = container_of(data, struct musb, recover_work); + int status; + + musb_platform_reset(musb); + + usb_phy_vbus_off(musb->xceiv); + udelay(100); + + usb_phy_vbus_on(musb->xceiv); + udelay(100); + + /* + * When a babble condition occurs, the musb controller removes the + * session bit and the endpoint config is lost. + */ + if (musb->dyn_fifo) + status = ep_config_from_table(musb); + else + status = ep_config_from_hw(musb); + + /* start the session again */ + if (status == 0) + musb_start(musb); +} + /* -------------------------------------------------------------------------- * Init support */ @@ -1913,6 +1945,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) /* Init IRQ workqueue before request_irq */ INIT_WORK(&musb->irq_work, musb_irq_work); + INIT_WORK(&musb->recover_work, musb_recover_work); INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); @@ -2008,6 +2041,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) fail3: cancel_work_sync(&musb->irq_work); + cancel_work_sync(&musb->recover_work); cancel_delayed_work_sync(&musb->finish_resume_work); cancel_delayed_work_sync(&musb->deassert_reset_work); if (musb->dma_controller) @@ -2073,6 +2107,7 @@ static int musb_remove(struct platform_device *pdev) dma_controller_destroy(musb->dma_controller); cancel_work_sync(&musb->irq_work); + cancel_work_sync(&musb->recover_work); cancel_delayed_work_sync(&musb->finish_resume_work); cancel_delayed_work_sync(&musb->deassert_reset_work); musb_free(musb); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 7083e82776ff63..47e88747e3a7a4 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -192,6 +192,7 @@ struct musb_platform_ops { int (*set_mode)(struct musb *musb, u8 mode); void (*try_idle)(struct musb *musb, unsigned long timeout); + void (*reset)(struct musb *musb); int (*vbus_status)(struct musb *musb); void (*set_vbus)(struct musb *musb, int on); @@ -296,6 +297,7 @@ struct musb { irqreturn_t (*isr)(int, void *); struct work_struct irq_work; + struct work_struct recover_work; struct delayed_work deassert_reset_work; struct delayed_work finish_resume_work; u16 hwvers; @@ -552,6 +554,12 @@ static inline void musb_platform_try_idle(struct musb *musb, musb->ops->try_idle(musb, timeout); } +static inline void musb_platform_reset(struct musb *musb) +{ + if (musb->ops->reset) + musb->ops->reset(musb); +} + static inline int musb_platform_get_vbus_status(struct musb *musb) { if (!musb->ops->vbus_status) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index e2fd263585de3f..51beb13c7e1a4d 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include @@ -329,9 +329,21 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. * Also, DRVVBUS pulses for SRP (but not at 5V) ... */ - if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) + if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) { pr_info("CAUTION: musb: Babble Interrupt Occurred\n"); + /* + * When a babble condition occurs, the musb controller removes + * the session and is no longer in host mode. Hence, all + * devices connected to its root hub get disconnected. + * + * Hand this error down to the musb core isr, so it can + * recover. + */ + musb->int_usb = MUSB_INTR_BABBLE | MUSB_INTR_DISCONNECT; + musb->int_tx = musb->int_rx = 0; + } + if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { int drvvbus = dsps_readl(reg_base, wrp->status); void __iomem *mregs = musb->mregs; @@ -524,6 +536,16 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode) return 0; } +static void dsps_musb_reset(struct musb *musb) +{ + struct device *dev = musb->controller; + struct dsps_glue *glue = dev_get_drvdata(dev->parent); + const struct dsps_musb_wrapper *wrp = glue->wrp; + + dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); + udelay(100); +} + static struct musb_platform_ops dsps_ops = { .init = dsps_musb_init, .exit = dsps_musb_exit, @@ -533,6 +555,7 @@ static struct musb_platform_ops dsps_ops = { .try_idle = dsps_musb_try_idle, .set_mode = dsps_musb_set_mode, + .reset = dsps_musb_reset, }; static u64 musb_dmamask = DMA_BIT_MASK(32); @@ -750,7 +773,7 @@ static const struct of_device_id musb_dsps_of_match[] = { }; MODULE_DEVICE_TABLE(of, musb_dsps_of_match); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int dsps_suspend(struct device *dev) { struct dsps_glue *glue = dev_get_drvdata(dev); diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 4e9fb1d08698ab..f38a8dbd60756e 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -24,13 +24,14 @@ #include #include #include -#include +#include #include "musb_core.h" struct tusb6010_glue { struct device *dev; struct platform_device *musb; + struct platform_device *phy; }; static void tusb_musb_set_vbus(struct musb *musb, int is_on); @@ -1065,7 +1066,6 @@ static int tusb_musb_init(struct musb *musb) void __iomem *sync = NULL; int ret; - usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) return -EPROBE_DEFER; @@ -1117,7 +1117,6 @@ static int tusb_musb_init(struct musb *musb) iounmap(sync); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); } return ret; } @@ -1133,7 +1132,6 @@ static int tusb_musb_exit(struct musb *musb) iounmap(musb->sync_va); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); return 0; } @@ -1176,6 +1174,7 @@ static int tusb_probe(struct platform_device *pdev) pdata->platform_ops = &tusb_ops; + usb_phy_generic_register(); platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -1224,6 +1223,7 @@ static int tusb_remove(struct platform_device *pdev) struct tusb6010_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(glue->phy); kfree(glue); return 0; diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 416e0c8cf6ff16..359a6c1b5c131f 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -59,14 +59,6 @@ config KEYSTONE_USB_PHY interface to interact with USB 2.0 and USB 3.0 PHY that is part of the Keystone SOC. -config MV_U3D_PHY - bool "Marvell USB 3.0 PHY controller Driver" - depends on CPU_MMP3 - select USB_PHY - help - Enable this to support Marvell USB 3.0 phy controller for Marvell - SoC. - config NOP_USB_XCEIV tristate "NOP USB Transceiver Driver" select USB_PHY @@ -171,11 +163,11 @@ config USB_ISP1301 module will be called phy-isp1301. config USB_MSM_OTG - tristate "OTG support for Qualcomm on-chip USB controller" - depends on (USB || USB_GADGET) && ARCH_MSM + tristate "Qualcomm on-chip USB OTG controller support" + depends on (USB || USB_GADGET) && (ARCH_MSM || ARCH_QCOM) select USB_PHY help - Enable this to support the USB OTG transceiver on MSM chips. It + Enable this to support the USB OTG transceiver on Qualcomm chips. It handles PHY initialization, clock management, and workarounds required after resetting the hardware and power management. This driver is required even for peripheral only or host only diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index f8fa719a31b9b9..a2d05690d9255c 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_USB_OTG_FSM) += phy-fsm-usb.o obj-$(CONFIG_AB8500_USB) += phy-ab8500-usb.o obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb.o obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o -obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o obj-$(CONFIG_NOP_USB_XCEIV) += phy-generic.o obj-$(CONFIG_TAHVO_USB) += phy-tahvo.o obj-$(CONFIG_AM335X_CONTROL_USB) += phy-am335x-control.o diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 12fc3468a01e6f..585e50cb198014 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include @@ -13,7 +13,7 @@ #include "phy-generic.h" struct am335x_phy { - struct usb_phy_gen_xceiv usb_phy_gen; + struct usb_phy_generic usb_phy_gen; struct phy_control *phy_ctrl; int id; }; diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c index d03fadd2629f14..98e8340a5bb1a8 100644 --- a/drivers/usb/phy/phy-fsm-usb.c +++ b/drivers/usb/phy/phy-fsm-usb.c @@ -364,3 +364,4 @@ int otg_statemachine(struct otg_fsm *fsm) VDBG("quit statemachine, changed = %d\n", state_changed); return state_changed; } +EXPORT_SYMBOL_GPL(otg_statemachine); diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index bb394980532b14..7594e5069ae59d 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -41,34 +41,25 @@ #include "phy-generic.h" -static struct platform_device *pd; - -void usb_nop_xceiv_register(void) +struct platform_device *usb_phy_generic_register(void) { - if (pd) - return; - pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0); - if (IS_ERR(pd)) { - pr_err("Unable to register generic usb transceiver\n"); - pd = NULL; - return; - } + return platform_device_register_simple("usb_phy_generic", + PLATFORM_DEVID_AUTO, NULL, 0); } -EXPORT_SYMBOL(usb_nop_xceiv_register); +EXPORT_SYMBOL_GPL(usb_phy_generic_register); -void usb_nop_xceiv_unregister(void) +void usb_phy_generic_unregister(struct platform_device *pdev) { - platform_device_unregister(pd); - pd = NULL; + platform_device_unregister(pdev); } -EXPORT_SYMBOL(usb_nop_xceiv_unregister); +EXPORT_SYMBOL_GPL(usb_phy_generic_unregister); static int nop_set_suspend(struct usb_phy *x, int suspend) { return 0; } -static void nop_reset_set(struct usb_phy_gen_xceiv *nop, int asserted) +static void nop_reset_set(struct usb_phy_generic *nop, int asserted) { int value; @@ -87,7 +78,7 @@ static void nop_reset_set(struct usb_phy_gen_xceiv *nop, int asserted) int usb_gen_phy_init(struct usb_phy *phy) { - struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); + struct usb_phy_generic *nop = dev_get_drvdata(phy->dev); if (!IS_ERR(nop->vcc)) { if (regulator_enable(nop->vcc)) @@ -106,7 +97,7 @@ EXPORT_SYMBOL_GPL(usb_gen_phy_init); void usb_gen_phy_shutdown(struct usb_phy *phy) { - struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); + struct usb_phy_generic *nop = dev_get_drvdata(phy->dev); /* Assert RESET */ nop_reset_set(nop, 1); @@ -150,8 +141,8 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) return 0; } -int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, - struct usb_phy_gen_xceiv_platform_data *pdata) +int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, + struct usb_phy_generic_platform_data *pdata) { enum usb_phy_type type = USB_PHY_TYPE_USB2; int err; @@ -245,10 +236,10 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, } EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy); -static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) +static int usb_phy_generic_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct usb_phy_gen_xceiv *nop; + struct usb_phy_generic *nop; int err; nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); @@ -274,9 +265,9 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) return 0; } -static int usb_phy_gen_xceiv_remove(struct platform_device *pdev) +static int usb_phy_generic_remove(struct platform_device *pdev) { - struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev); + struct usb_phy_generic *nop = platform_get_drvdata(pdev); usb_remove_phy(&nop->phy); @@ -290,29 +281,29 @@ static const struct of_device_id nop_xceiv_dt_ids[] = { MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); -static struct platform_driver usb_phy_gen_xceiv_driver = { - .probe = usb_phy_gen_xceiv_probe, - .remove = usb_phy_gen_xceiv_remove, +static struct platform_driver usb_phy_generic_driver = { + .probe = usb_phy_generic_probe, + .remove = usb_phy_generic_remove, .driver = { - .name = "usb_phy_gen_xceiv", + .name = "usb_phy_generic", .owner = THIS_MODULE, .of_match_table = nop_xceiv_dt_ids, }, }; -static int __init usb_phy_gen_xceiv_init(void) +static int __init usb_phy_generic_init(void) { - return platform_driver_register(&usb_phy_gen_xceiv_driver); + return platform_driver_register(&usb_phy_generic_driver); } -subsys_initcall(usb_phy_gen_xceiv_init); +subsys_initcall(usb_phy_generic_init); -static void __exit usb_phy_gen_xceiv_exit(void) +static void __exit usb_phy_generic_exit(void) { - platform_driver_unregister(&usb_phy_gen_xceiv_driver); + platform_driver_unregister(&usb_phy_generic_driver); } -module_exit(usb_phy_gen_xceiv_exit); +module_exit(usb_phy_generic_exit); -MODULE_ALIAS("platform:usb_phy_gen_xceiv"); +MODULE_ALIAS("platform:usb_phy_generic"); MODULE_AUTHOR("Texas Instruments Inc"); MODULE_DESCRIPTION("NOP USB Transceiver driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h index 38a81f307b8220..d8feacc0b7fb36 100644 --- a/drivers/usb/phy/phy-generic.h +++ b/drivers/usb/phy/phy-generic.h @@ -1,9 +1,9 @@ #ifndef _PHY_GENERIC_H_ #define _PHY_GENERIC_H_ -#include +#include -struct usb_phy_gen_xceiv { +struct usb_phy_generic { struct usb_phy phy; struct device *dev; struct clk *clk; @@ -15,7 +15,7 @@ struct usb_phy_gen_xceiv { int usb_gen_phy_init(struct usb_phy *phy); void usb_gen_phy_shutdown(struct usb_phy *phy); -int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, - struct usb_phy_gen_xceiv_platform_data *pdata); +int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, + struct usb_phy_generic_platform_data *pdata); #endif diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index d762003896c06b..f4d722de912b4d 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -35,7 +35,7 @@ #define PHY_REF_SSP_EN BIT(29) struct keystone_usbphy { - struct usb_phy_gen_xceiv usb_phy_gen; + struct usb_phy_generic usb_phy_gen; void __iomem *phy_ctrl; }; diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 5b37b81f2ef6f3..9dc79180b9340d 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -30,9 +30,13 @@ #include #include #include +#include +#include +#include #include #include +#include #include #include #include @@ -44,6 +48,7 @@ #define DRIVER_NAME "msm_otg" #define ULPI_IO_TIMEOUT_USEC (10 * 1000) +#define LINK_RESET_TIMEOUT_USEC (250 * 1000) #define USB_PHY_3P3_VOL_MIN 3050000 /* uV */ #define USB_PHY_3P3_VOL_MAX 3300000 /* uV */ @@ -57,48 +62,38 @@ #define USB_PHY_VDD_DIG_VOL_MIN 1000000 /* uV */ #define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */ +#define USB_PHY_SUSP_DIG_VOL 500000 /* uV */ -static struct regulator *hsusb_3p3; -static struct regulator *hsusb_1p8; -static struct regulator *hsusb_vddcx; +enum vdd_levels { + VDD_LEVEL_NONE = 0, + VDD_LEVEL_MIN, + VDD_LEVEL_MAX, +}; static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init) { int ret = 0; if (init) { - hsusb_vddcx = regulator_get(motg->phy.dev, "HSUSB_VDDCX"); - if (IS_ERR(hsusb_vddcx)) { - dev_err(motg->phy.dev, "unable to get hsusb vddcx\n"); - return PTR_ERR(hsusb_vddcx); - } - - ret = regulator_set_voltage(hsusb_vddcx, - USB_PHY_VDD_DIG_VOL_MIN, - USB_PHY_VDD_DIG_VOL_MAX); + ret = regulator_set_voltage(motg->vddcx, + motg->vdd_levels[VDD_LEVEL_MIN], + motg->vdd_levels[VDD_LEVEL_MAX]); if (ret) { - dev_err(motg->phy.dev, "unable to set the voltage " - "for hsusb vddcx\n"); - regulator_put(hsusb_vddcx); + dev_err(motg->phy.dev, "Cannot set vddcx voltage\n"); return ret; } - ret = regulator_enable(hsusb_vddcx); - if (ret) { + ret = regulator_enable(motg->vddcx); + if (ret) dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n"); - regulator_put(hsusb_vddcx); - } } else { - ret = regulator_set_voltage(hsusb_vddcx, 0, - USB_PHY_VDD_DIG_VOL_MAX); + ret = regulator_set_voltage(motg->vddcx, 0, + motg->vdd_levels[VDD_LEVEL_MAX]); if (ret) - dev_err(motg->phy.dev, "unable to set the voltage " - "for hsusb vddcx\n"); - ret = regulator_disable(hsusb_vddcx); + dev_err(motg->phy.dev, "Cannot set vddcx voltage\n"); + ret = regulator_disable(motg->vddcx); if (ret) dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n"); - - regulator_put(hsusb_vddcx); } return ret; @@ -109,98 +104,67 @@ static int msm_hsusb_ldo_init(struct msm_otg *motg, int init) int rc = 0; if (init) { - hsusb_3p3 = regulator_get(motg->phy.dev, "HSUSB_3p3"); - if (IS_ERR(hsusb_3p3)) { - dev_err(motg->phy.dev, "unable to get hsusb 3p3\n"); - return PTR_ERR(hsusb_3p3); - } - - rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN, + rc = regulator_set_voltage(motg->v3p3, USB_PHY_3P3_VOL_MIN, USB_PHY_3P3_VOL_MAX); if (rc) { - dev_err(motg->phy.dev, "unable to set voltage level " - "for hsusb 3p3\n"); - goto put_3p3; + dev_err(motg->phy.dev, "Cannot set v3p3 voltage\n"); + goto exit; } - rc = regulator_enable(hsusb_3p3); + rc = regulator_enable(motg->v3p3); if (rc) { dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n"); - goto put_3p3; + goto exit; } - hsusb_1p8 = regulator_get(motg->phy.dev, "HSUSB_1p8"); - if (IS_ERR(hsusb_1p8)) { - dev_err(motg->phy.dev, "unable to get hsusb 1p8\n"); - rc = PTR_ERR(hsusb_1p8); - goto disable_3p3; - } - rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN, + rc = regulator_set_voltage(motg->v1p8, USB_PHY_1P8_VOL_MIN, USB_PHY_1P8_VOL_MAX); if (rc) { - dev_err(motg->phy.dev, "unable to set voltage level " - "for hsusb 1p8\n"); - goto put_1p8; + dev_err(motg->phy.dev, "Cannot set v1p8 voltage\n"); + goto disable_3p3; } - rc = regulator_enable(hsusb_1p8); + rc = regulator_enable(motg->v1p8); if (rc) { dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n"); - goto put_1p8; + goto disable_3p3; } return 0; } - regulator_disable(hsusb_1p8); -put_1p8: - regulator_put(hsusb_1p8); + regulator_disable(motg->v1p8); disable_3p3: - regulator_disable(hsusb_3p3); -put_3p3: - regulator_put(hsusb_3p3); + regulator_disable(motg->v3p3); +exit: return rc; } -static int msm_hsusb_ldo_set_mode(int on) +static int msm_hsusb_ldo_set_mode(struct msm_otg *motg, int on) { int ret = 0; - if (!hsusb_1p8 || IS_ERR(hsusb_1p8)) { - pr_err("%s: HSUSB_1p8 is not initialized\n", __func__); - return -ENODEV; - } - - if (!hsusb_3p3 || IS_ERR(hsusb_3p3)) { - pr_err("%s: HSUSB_3p3 is not initialized\n", __func__); - return -ENODEV; - } - if (on) { - ret = regulator_set_optimum_mode(hsusb_1p8, + ret = regulator_set_optimum_mode(motg->v1p8, USB_PHY_1P8_HPM_LOAD); if (ret < 0) { - pr_err("%s: Unable to set HPM of the regulator " - "HSUSB_1p8\n", __func__); + pr_err("Could not set HPM for v1p8\n"); return ret; } - ret = regulator_set_optimum_mode(hsusb_3p3, + ret = regulator_set_optimum_mode(motg->v3p3, USB_PHY_3P3_HPM_LOAD); if (ret < 0) { - pr_err("%s: Unable to set HPM of the regulator " - "HSUSB_3p3\n", __func__); - regulator_set_optimum_mode(hsusb_1p8, + pr_err("Could not set HPM for v3p3\n"); + regulator_set_optimum_mode(motg->v1p8, USB_PHY_1P8_LPM_LOAD); return ret; } } else { - ret = regulator_set_optimum_mode(hsusb_1p8, + ret = regulator_set_optimum_mode(motg->v1p8, USB_PHY_1P8_LPM_LOAD); if (ret < 0) - pr_err("%s: Unable to set LPM of the regulator " - "HSUSB_1p8\n", __func__); - ret = regulator_set_optimum_mode(hsusb_3p3, + pr_err("Could not set LPM for v1p8\n"); + ret = regulator_set_optimum_mode(motg->v3p3, USB_PHY_3P3_LPM_LOAD); if (ret < 0) - pr_err("%s: Unable to set LPM of the regulator " - "HSUSB_3p3\n", __func__); + pr_err("Could not set LPM for v3p3\n"); } pr_debug("reg (%s)\n", on ? "HPM" : "LPM"); @@ -265,27 +229,47 @@ static struct usb_phy_io_ops msm_otg_io_ops = { static void ulpi_init(struct msm_otg *motg) { struct msm_otg_platform_data *pdata = motg->pdata; - int *seq = pdata->phy_init_seq; + int *seq = pdata->phy_init_seq, idx; + u32 addr = ULPI_EXT_VENDOR_SPECIFIC; - if (!seq) - return; + for (idx = 0; idx < pdata->phy_init_sz; idx++) { + if (seq[idx] == -1) + continue; - while (seq[0] >= 0) { dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n", - seq[0], seq[1]); - ulpi_write(&motg->phy, seq[0], seq[1]); - seq += 2; + seq[idx], addr + idx); + ulpi_write(&motg->phy, seq[idx], addr + idx); } } +static int msm_phy_notify_disconnect(struct usb_phy *phy, + enum usb_device_speed speed) +{ + int val; + + /* + * Put the transceiver in non-driving mode. Otherwise host + * may not detect soft-disconnection. + */ + val = ulpi_read(phy, ULPI_FUNC_CTRL); + val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; + val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; + ulpi_write(phy, val, ULPI_FUNC_CTRL); + + return 0; +} + static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert) { - int ret = 0; + int ret; - if (!motg->pdata->link_clk_reset) - return ret; + if (motg->pdata->link_clk_reset) + ret = motg->pdata->link_clk_reset(motg->clk, assert); + else if (assert) + ret = reset_control_assert(motg->link_rst); + else + ret = reset_control_deassert(motg->link_rst); - ret = motg->pdata->link_clk_reset(motg->clk, assert); if (ret) dev_err(motg->phy.dev, "usb link clk reset %s failed\n", assert ? "assert" : "deassert"); @@ -295,111 +279,150 @@ static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert) static int msm_otg_phy_clk_reset(struct msm_otg *motg) { - int ret = 0; + int ret; - if (!motg->pdata->phy_clk_reset) - return ret; + if (motg->pdata->phy_clk_reset) + ret = motg->pdata->phy_clk_reset(motg->phy_reset_clk); + else + ret = reset_control_reset(motg->phy_rst); - ret = motg->pdata->phy_clk_reset(motg->phy_reset_clk); if (ret) dev_err(motg->phy.dev, "usb phy clk reset failed\n"); return ret; } -static int msm_otg_phy_reset(struct msm_otg *motg) +static int msm_link_reset(struct msm_otg *motg) { u32 val; int ret; - int retries; ret = msm_otg_link_clk_reset(motg, 1); if (ret) return ret; - ret = msm_otg_phy_clk_reset(motg); - if (ret) - return ret; + + /* wait for 1ms delay as suggested in HPG. */ + usleep_range(1000, 1200); + ret = msm_otg_link_clk_reset(motg, 0); if (ret) return ret; + if (motg->phy_number) + writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); + + /* put transceiver in serial mode as part of reset */ val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK; - writel(val | PORTSC_PTS_ULPI, USB_PORTSC); + writel(val | PORTSC_PTS_SERIAL, USB_PORTSC); - for (retries = 3; retries > 0; retries--) { - ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM, - ULPI_CLR(ULPI_FUNC_CTRL)); - if (!ret) - break; - ret = msm_otg_phy_clk_reset(motg); - if (ret) - return ret; - } - if (!retries) - return -ETIMEDOUT; + return 0; +} - /* This reset calibrates the phy, if the above write succeeded */ - ret = msm_otg_phy_clk_reset(motg); - if (ret) - return ret; +static int msm_otg_reset(struct usb_phy *phy) +{ + struct msm_otg *motg = container_of(phy, struct msm_otg, phy); + int cnt = 0; - for (retries = 3; retries > 0; retries--) { - ret = ulpi_read(&motg->phy, ULPI_DEBUG); - if (ret != -ETIMEDOUT) + writel(USBCMD_RESET, USB_USBCMD); + while (cnt < LINK_RESET_TIMEOUT_USEC) { + if (!(readl(USB_USBCMD) & USBCMD_RESET)) break; - ret = msm_otg_phy_clk_reset(motg); - if (ret) - return ret; + udelay(1); + cnt++; } - if (!retries) + if (cnt >= LINK_RESET_TIMEOUT_USEC) return -ETIMEDOUT; - dev_info(motg->phy.dev, "phy_reset: success\n"); + /* select ULPI phy and clear other status/control bits in PORTSC */ + writel(PORTSC_PTS_ULPI, USB_PORTSC); + + writel(0x0, USB_AHBBURST); + writel(0x08, USB_AHBMODE); + + if (motg->phy_number) + writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); return 0; } -#define LINK_RESET_TIMEOUT_USEC (250 * 1000) -static int msm_otg_reset(struct usb_phy *phy) +static void msm_phy_reset(struct msm_otg *motg) +{ + void __iomem *addr; + + if (motg->pdata->phy_type != SNPS_28NM_INTEGRATED_PHY) { + msm_otg_phy_clk_reset(motg); + return; + } + + addr = USB_PHY_CTRL; + if (motg->phy_number) + addr = USB_PHY_CTRL2; + + /* Assert USB PHY_POR */ + writel(readl(addr) | PHY_POR_ASSERT, addr); + + /* + * wait for minimum 10 microseconds as suggested in HPG. + * Use a slightly larger value since the exact value didn't + * work 100% of the time. + */ + udelay(12); + + /* Deassert USB PHY_POR */ + writel(readl(addr) & ~PHY_POR_ASSERT, addr); +} + +static int msm_usb_reset(struct usb_phy *phy) { struct msm_otg *motg = container_of(phy, struct msm_otg, phy); - struct msm_otg_platform_data *pdata = motg->pdata; - int cnt = 0; int ret; - u32 val = 0; - u32 ulpi_val = 0; - ret = msm_otg_phy_reset(motg); + if (!IS_ERR(motg->core_clk)) + clk_prepare_enable(motg->core_clk); + + ret = msm_link_reset(motg); if (ret) { dev_err(phy->dev, "phy_reset failed\n"); return ret; } - ulpi_init(motg); - - writel(USBCMD_RESET, USB_USBCMD); - while (cnt < LINK_RESET_TIMEOUT_USEC) { - if (!(readl(USB_USBCMD) & USBCMD_RESET)) - break; - udelay(1); - cnt++; + ret = msm_otg_reset(&motg->phy); + if (ret) { + dev_err(phy->dev, "link reset failed\n"); + return ret; } - if (cnt >= LINK_RESET_TIMEOUT_USEC) - return -ETIMEDOUT; - - /* select ULPI phy */ - writel(0x80000000, USB_PORTSC); msleep(100); - writel(0x0, USB_AHBBURST); - writel(0x00, USB_AHBMODE); + /* Reset USB PHY after performing USB Link RESET */ + msm_phy_reset(motg); + + if (!IS_ERR(motg->core_clk)) + clk_disable_unprepare(motg->core_clk); + + return 0; +} + +static int msm_phy_init(struct usb_phy *phy) +{ + struct msm_otg *motg = container_of(phy, struct msm_otg, phy); + struct msm_otg_platform_data *pdata = motg->pdata; + u32 val, ulpi_val = 0; + + /* Program USB PHY Override registers. */ + ulpi_init(motg); + + /* + * It is recommended in HPG to reset USB PHY after programming + * USB PHY Override registers. + */ + msm_phy_reset(motg); if (pdata->otg_control == OTG_PHY_CONTROL) { val = readl(USB_OTGSC); - if (pdata->mode == USB_OTG) { + if (pdata->mode == USB_DR_MODE_OTG) { ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID; val |= OTGSC_IDIE | OTGSC_BSVIE; - } else if (pdata->mode == USB_PERIPHERAL) { + } else if (pdata->mode == USB_DR_MODE_PERIPHERAL) { ulpi_val = ULPI_INT_SESS_VALID; val |= OTGSC_BSVIE; } @@ -408,6 +431,9 @@ static int msm_otg_reset(struct usb_phy *phy) ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL); } + if (motg->phy_number) + writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); + return 0; } @@ -416,22 +442,20 @@ static int msm_otg_reset(struct usb_phy *phy) #ifdef CONFIG_PM -#define USB_PHY_SUSP_DIG_VOL 500000 -static int msm_hsusb_config_vddcx(int high) +static int msm_hsusb_config_vddcx(struct msm_otg *motg, int high) { - int max_vol = USB_PHY_VDD_DIG_VOL_MAX; + int max_vol = motg->vdd_levels[VDD_LEVEL_MAX]; int min_vol; int ret; if (high) - min_vol = USB_PHY_VDD_DIG_VOL_MIN; + min_vol = motg->vdd_levels[VDD_LEVEL_MIN]; else - min_vol = USB_PHY_SUSP_DIG_VOL; + min_vol = motg->vdd_levels[VDD_LEVEL_NONE]; - ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol); + ret = regulator_set_voltage(motg->vddcx, min_vol, max_vol); if (ret) { - pr_err("%s: unable to set the voltage for regulator " - "HSUSB_VDDCX\n", __func__); + pr_err("Cannot set vddcx voltage\n"); return ret; } @@ -445,6 +469,7 @@ static int msm_otg_suspend(struct msm_otg *motg) struct usb_phy *phy = &motg->phy; struct usb_bus *bus = phy->otg->host; struct msm_otg_platform_data *pdata = motg->pdata; + void __iomem *addr; int cnt = 0; if (atomic_read(&motg->in_lpm)) @@ -504,22 +529,23 @@ static int msm_otg_suspend(struct msm_otg *motg) */ writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD); + addr = USB_PHY_CTRL; + if (motg->phy_number) + addr = USB_PHY_CTRL2; + if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && motg->pdata->otg_control == OTG_PMIC_CONTROL) - writel(readl(USB_PHY_CTRL) | PHY_RETEN, USB_PHY_CTRL); + writel(readl(addr) | PHY_RETEN, addr); clk_disable_unprepare(motg->pclk); clk_disable_unprepare(motg->clk); - if (motg->core_clk) + if (!IS_ERR(motg->core_clk)) clk_disable_unprepare(motg->core_clk); - if (!IS_ERR(motg->pclk_src)) - clk_disable_unprepare(motg->pclk_src); - if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && motg->pdata->otg_control == OTG_PMIC_CONTROL) { - msm_hsusb_ldo_set_mode(0); - msm_hsusb_config_vddcx(0); + msm_hsusb_ldo_set_mode(motg, 0); + msm_hsusb_config_vddcx(motg, 0); } if (device_may_wakeup(phy->dev)) @@ -539,25 +565,28 @@ static int msm_otg_resume(struct msm_otg *motg) { struct usb_phy *phy = &motg->phy; struct usb_bus *bus = phy->otg->host; + void __iomem *addr; int cnt = 0; unsigned temp; if (!atomic_read(&motg->in_lpm)) return 0; - if (!IS_ERR(motg->pclk_src)) - clk_prepare_enable(motg->pclk_src); - clk_prepare_enable(motg->pclk); clk_prepare_enable(motg->clk); - if (motg->core_clk) + if (!IS_ERR(motg->core_clk)) clk_prepare_enable(motg->core_clk); if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && motg->pdata->otg_control == OTG_PMIC_CONTROL) { - msm_hsusb_ldo_set_mode(1); - msm_hsusb_config_vddcx(1); - writel(readl(USB_PHY_CTRL) & ~PHY_RETEN, USB_PHY_CTRL); + + addr = USB_PHY_CTRL; + if (motg->phy_number) + addr = USB_PHY_CTRL2; + + msm_hsusb_ldo_set_mode(motg, 1); + msm_hsusb_config_vddcx(motg, 1); + writel(readl(addr) & ~PHY_RETEN, addr); } temp = readl(USB_USBCMD); @@ -586,8 +615,7 @@ static int msm_otg_resume(struct msm_otg *motg) * PHY. USB state can not be restored. Re-insertion * of USB cable is the only way to get USB working. */ - dev_err(phy->dev, "Unable to resume USB." - "Re-plugin the cable\n"); + dev_err(phy->dev, "Unable to resume USB. Re-plugin the cable\n"); msm_otg_reset(phy); } @@ -687,7 +715,7 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host) * Fail host registration if this board can support * only peripheral configuration. */ - if (motg->pdata->mode == USB_PERIPHERAL) { + if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL) { dev_info(otg->phy->dev, "Host mode is not supported\n"); return -ENODEV; } @@ -716,7 +744,7 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host) * Kick the state machine work, if peripheral is not supported * or peripheral is already registered with us. */ - if (motg->pdata->mode == USB_HOST || otg->gadget) { + if (motg->pdata->mode == USB_DR_MODE_HOST || otg->gadget) { pm_runtime_get_sync(otg->phy->dev); schedule_work(&motg->sm_work); } @@ -760,7 +788,7 @@ static int msm_otg_set_peripheral(struct usb_otg *otg, * Fail peripheral registration if this board can support * only host configuration. */ - if (motg->pdata->mode == USB_HOST) { + if (motg->pdata->mode == USB_DR_MODE_HOST) { dev_info(otg->phy->dev, "Peripheral mode is not supported\n"); return -ENODEV; } @@ -785,7 +813,7 @@ static int msm_otg_set_peripheral(struct usb_otg *otg, * Kick the state machine work, if host is not supported * or host is already registered with us. */ - if (motg->pdata->mode == USB_PERIPHERAL || otg->host) { + if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL || otg->host) { pm_runtime_get_sync(otg->phy->dev); schedule_work(&motg->sm_work); } @@ -1106,7 +1134,7 @@ static void msm_otg_init_sm(struct msm_otg *motg) u32 otgsc = readl(USB_OTGSC); switch (pdata->mode) { - case USB_OTG: + case USB_DR_MODE_OTG: if (pdata->otg_control == OTG_PHY_CONTROL) { if (otgsc & OTGSC_ID) set_bit(ID, &motg->inputs); @@ -1118,21 +1146,14 @@ static void msm_otg_init_sm(struct msm_otg *motg) else clear_bit(B_SESS_VLD, &motg->inputs); } else if (pdata->otg_control == OTG_USER_CONTROL) { - if (pdata->default_mode == USB_HOST) { - clear_bit(ID, &motg->inputs); - } else if (pdata->default_mode == USB_PERIPHERAL) { - set_bit(ID, &motg->inputs); - set_bit(B_SESS_VLD, &motg->inputs); - } else { set_bit(ID, &motg->inputs); clear_bit(B_SESS_VLD, &motg->inputs); - } } break; - case USB_HOST: + case USB_DR_MODE_HOST: clear_bit(ID, &motg->inputs); break; - case USB_PERIPHERAL: + case USB_DR_MODE_PERIPHERAL: set_bit(ID, &motg->inputs); if (otgsc & OTGSC_BSV) set_bit(B_SESS_VLD, &motg->inputs); @@ -1282,13 +1303,13 @@ static int msm_otg_mode_show(struct seq_file *s, void *unused) switch (otg->phy->state) { case OTG_STATE_A_HOST: - seq_printf(s, "host\n"); + seq_puts(s, "host\n"); break; case OTG_STATE_B_PERIPHERAL: - seq_printf(s, "peripheral\n"); + seq_puts(s, "peripheral\n"); break; default: - seq_printf(s, "none\n"); + seq_puts(s, "none\n"); break; } @@ -1308,7 +1329,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, char buf[16]; struct usb_otg *otg = motg->phy.otg; int status = count; - enum usb_mode_type req_mode; + enum usb_dr_mode req_mode; memset(buf, 0x00, sizeof(buf)); @@ -1318,18 +1339,18 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, } if (!strncmp(buf, "host", 4)) { - req_mode = USB_HOST; + req_mode = USB_DR_MODE_HOST; } else if (!strncmp(buf, "peripheral", 10)) { - req_mode = USB_PERIPHERAL; + req_mode = USB_DR_MODE_PERIPHERAL; } else if (!strncmp(buf, "none", 4)) { - req_mode = USB_NONE; + req_mode = USB_DR_MODE_UNKNOWN; } else { status = -EINVAL; goto out; } switch (req_mode) { - case USB_NONE: + case USB_DR_MODE_UNKNOWN: switch (otg->phy->state) { case OTG_STATE_A_HOST: case OTG_STATE_B_PERIPHERAL: @@ -1340,7 +1361,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, goto out; } break; - case USB_PERIPHERAL: + case USB_DR_MODE_PERIPHERAL: switch (otg->phy->state) { case OTG_STATE_B_IDLE: case OTG_STATE_A_HOST: @@ -1351,7 +1372,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, goto out; } break; - case USB_HOST: + case USB_DR_MODE_HOST: switch (otg->phy->state) { case OTG_STATE_B_IDLE: case OTG_STATE_B_PERIPHERAL: @@ -1406,74 +1427,154 @@ static void msm_otg_debugfs_cleanup(void) debugfs_remove(msm_otg_dbg_root); } -static int __init msm_otg_probe(struct platform_device *pdev) +static struct of_device_id msm_otg_dt_match[] = { + { + .compatible = "qcom,usb-otg-ci", + .data = (void *) CI_45NM_INTEGRATED_PHY + }, + { + .compatible = "qcom,usb-otg-snps", + .data = (void *) SNPS_28NM_INTEGRATED_PHY + }, + { } +}; +MODULE_DEVICE_TABLE(of, msm_otg_dt_match); + +static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) { + struct msm_otg_platform_data *pdata; + const struct of_device_id *id; + struct device_node *node = pdev->dev.of_node; + struct property *prop; + int len, ret, words; + u32 val, tmp[3]; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + motg->pdata = pdata; + + id = of_match_device(msm_otg_dt_match, &pdev->dev); + pdata->phy_type = (int) id->data; + + motg->link_rst = devm_reset_control_get(&pdev->dev, "link"); + if (IS_ERR(motg->link_rst)) + return PTR_ERR(motg->link_rst); + + motg->phy_rst = devm_reset_control_get(&pdev->dev, "phy"); + if (IS_ERR(motg->phy_rst)) + return PTR_ERR(motg->phy_rst); + + pdata->mode = of_usb_get_dr_mode(node); + if (pdata->mode == USB_DR_MODE_UNKNOWN) + pdata->mode = USB_DR_MODE_OTG; + + pdata->otg_control = OTG_PHY_CONTROL; + if (!of_property_read_u32(node, "qcom,otg-control", &val)) + if (val == OTG_PMIC_CONTROL) + pdata->otg_control = val; + + if (!of_property_read_u32(node, "qcom,phy-num", &val) && val < 2) + motg->phy_number = val; + + motg->vdd_levels[VDD_LEVEL_NONE] = USB_PHY_SUSP_DIG_VOL; + motg->vdd_levels[VDD_LEVEL_MIN] = USB_PHY_VDD_DIG_VOL_MIN; + motg->vdd_levels[VDD_LEVEL_MAX] = USB_PHY_VDD_DIG_VOL_MAX; + + if (of_get_property(node, "qcom,vdd-levels", &len) && + len == sizeof(tmp)) { + of_property_read_u32_array(node, "qcom,vdd-levels", + tmp, len / sizeof(*tmp)); + motg->vdd_levels[VDD_LEVEL_NONE] = tmp[VDD_LEVEL_NONE]; + motg->vdd_levels[VDD_LEVEL_MIN] = tmp[VDD_LEVEL_MIN]; + motg->vdd_levels[VDD_LEVEL_MAX] = tmp[VDD_LEVEL_MAX]; + } + + prop = of_find_property(node, "qcom,phy-init-sequence", &len); + if (!prop || !len) + return 0; + + words = len / sizeof(u32); + + if (words >= ULPI_EXT_VENDOR_SPECIFIC) { + dev_warn(&pdev->dev, "Too big PHY init sequence %d\n", words); + return 0; + } + + pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); + if (!pdata->phy_init_seq) { + dev_warn(&pdev->dev, "No space for PHY init sequence\n"); + return 0; + } + + ret = of_property_read_u32_array(node, "qcom,phy-init-sequence", + pdata->phy_init_seq, words); + if (!ret) + pdata->phy_init_sz = words; + + return 0; +} + +static int msm_otg_probe(struct platform_device *pdev) +{ + struct regulator_bulk_data regs[3]; int ret = 0; + struct device_node *np = pdev->dev.of_node; + struct msm_otg_platform_data *pdata; struct resource *res; struct msm_otg *motg; struct usb_phy *phy; + void __iomem *phy_select; - dev_info(&pdev->dev, "msm_otg probe\n"); - if (!dev_get_platdata(&pdev->dev)) { - dev_err(&pdev->dev, "No platform data given. Bailing out\n"); - return -ENODEV; - } - - motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL); + motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL); if (!motg) { dev_err(&pdev->dev, "unable to allocate msm_otg\n"); return -ENOMEM; } - motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL); + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + if (!np) + return -ENXIO; + ret = msm_otg_read_dt(pdev, motg); + if (ret) + return ret; + } + + motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), + GFP_KERNEL); if (!motg->phy.otg) { dev_err(&pdev->dev, "unable to allocate msm_otg\n"); - ret = -ENOMEM; - goto free_motg; + return -ENOMEM; } - motg->pdata = dev_get_platdata(&pdev->dev); phy = &motg->phy; phy->dev = &pdev->dev; - motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk"); + motg->phy_reset_clk = devm_clk_get(&pdev->dev, + np ? "phy" : "usb_phy_clk"); if (IS_ERR(motg->phy_reset_clk)) { dev_err(&pdev->dev, "failed to get usb_phy_clk\n"); - ret = PTR_ERR(motg->phy_reset_clk); - goto free_motg; + return PTR_ERR(motg->phy_reset_clk); } - motg->clk = clk_get(&pdev->dev, "usb_hs_clk"); + motg->clk = devm_clk_get(&pdev->dev, np ? "core" : "usb_hs_clk"); if (IS_ERR(motg->clk)) { dev_err(&pdev->dev, "failed to get usb_hs_clk\n"); - ret = PTR_ERR(motg->clk); - goto put_phy_reset_clk; + return PTR_ERR(motg->clk); } - clk_set_rate(motg->clk, 60000000); /* * If USB Core is running its protocol engine based on CORE CLK, * CORE CLK must be running at >55Mhz for correct HSUSB * operation and USB core cannot tolerate frequency changes on - * CORE CLK. For such USB cores, vote for maximum clk frequency - * on pclk source + * CORE CLK. */ - if (motg->pdata->pclk_src_name) { - motg->pclk_src = clk_get(&pdev->dev, - motg->pdata->pclk_src_name); - if (IS_ERR(motg->pclk_src)) - goto put_clk; - clk_set_rate(motg->pclk_src, INT_MAX); - clk_prepare_enable(motg->pclk_src); - } else - motg->pclk_src = ERR_PTR(-ENOENT); - - - motg->pclk = clk_get(&pdev->dev, "usb_hs_pclk"); + motg->pclk = devm_clk_get(&pdev->dev, np ? "iface" : "usb_hs_pclk"); if (IS_ERR(motg->pclk)) { dev_err(&pdev->dev, "failed to get usb_hs_pclk\n"); - ret = PTR_ERR(motg->pclk); - goto put_pclk_src; + return PTR_ERR(motg->pclk); } /* @@ -1481,69 +1582,88 @@ static int __init msm_otg_probe(struct platform_device *pdev) * clock is introduced to remove the dependency on AXI * bus frequency. */ - motg->core_clk = clk_get(&pdev->dev, "usb_hs_core_clk"); - if (IS_ERR(motg->core_clk)) - motg->core_clk = NULL; + motg->core_clk = devm_clk_get(&pdev->dev, + np ? "alt_core" : "usb_hs_core_clk"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get platform resource mem\n"); - ret = -ENODEV; - goto put_core_clk; - } + motg->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (IS_ERR(motg->regs)) + return PTR_ERR(motg->regs); - motg->regs = ioremap(res->start, resource_size(res)); - if (!motg->regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto put_core_clk; + /* + * NOTE: The PHYs can be multiplexed between the chipidea controller + * and the dwc3 controller, using a single bit. It is important that + * the dwc3 driver does not set this bit in an incompatible way. + */ + if (motg->phy_number) { + phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4); + if (IS_ERR(phy_select)) + return PTR_ERR(phy_select); + /* Enable second PHY with the OTG port */ + writel_relaxed(0x1, phy_select); } + dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs); motg->irq = platform_get_irq(pdev, 0); - if (!motg->irq) { + if (motg->irq < 0) { dev_err(&pdev->dev, "platform_get_irq failed\n"); - ret = -ENODEV; - goto free_regs; + return motg->irq; } + regs[0].supply = "vddcx"; + regs[1].supply = "v3p3"; + regs[2].supply = "v1p8"; + + ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs); + if (ret) + return ret; + + motg->vddcx = regs[0].consumer; + motg->v3p3 = regs[1].consumer; + motg->v1p8 = regs[2].consumer; + + clk_set_rate(motg->clk, 60000000); + clk_prepare_enable(motg->clk); clk_prepare_enable(motg->pclk); + if (!IS_ERR(motg->core_clk)) + clk_prepare_enable(motg->core_clk); + ret = msm_hsusb_init_vddcx(motg, 1); if (ret) { dev_err(&pdev->dev, "hsusb vddcx configuration failed\n"); - goto free_regs; + goto disable_clks; } ret = msm_hsusb_ldo_init(motg, 1); if (ret) { dev_err(&pdev->dev, "hsusb vreg configuration failed\n"); - goto vddcx_exit; + goto disable_vddcx; } - ret = msm_hsusb_ldo_set_mode(1); + ret = msm_hsusb_ldo_set_mode(motg, 1); if (ret) { dev_err(&pdev->dev, "hsusb vreg enable failed\n"); - goto ldo_exit; + goto disable_ldo; } - if (motg->core_clk) - clk_prepare_enable(motg->core_clk); - writel(0, USB_USBINTR); writel(0, USB_OTGSC); INIT_WORK(&motg->sm_work, msm_otg_sm_work); INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work); - ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED, + ret = devm_request_irq(&pdev->dev, motg->irq, msm_otg_irq, IRQF_SHARED, "msm_otg", motg); if (ret) { dev_err(&pdev->dev, "request irq failed\n"); - goto disable_clks; + goto disable_ldo; } - phy->init = msm_otg_reset; + phy->init = msm_phy_init; phy->set_power = msm_otg_set_power; + phy->notify_disconnect = msm_phy_notify_disconnect; + phy->type = USB_PHY_TYPE_USB2; phy->io_ops = &msm_otg_io_ops; @@ -1551,54 +1671,38 @@ static int __init msm_otg_probe(struct platform_device *pdev) phy->otg->set_host = msm_otg_set_host; phy->otg->set_peripheral = msm_otg_set_peripheral; - ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2); + msm_usb_reset(phy); + + ret = usb_add_phy_dev(&motg->phy); if (ret) { dev_err(&pdev->dev, "usb_add_phy failed\n"); - goto free_irq; + goto disable_ldo; } platform_set_drvdata(pdev, motg); device_init_wakeup(&pdev->dev, 1); - if (motg->pdata->mode == USB_OTG && - motg->pdata->otg_control == OTG_USER_CONTROL) { + if (motg->pdata->mode == USB_DR_MODE_OTG && + motg->pdata->otg_control == OTG_USER_CONTROL) { ret = msm_otg_debugfs_init(motg); if (ret) - dev_dbg(&pdev->dev, "mode debugfs file is" - "not available\n"); + dev_dbg(&pdev->dev, "Can not create mode change file\n"); } pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); return 0; -free_irq: - free_irq(motg->irq, motg); + +disable_ldo: + msm_hsusb_ldo_init(motg, 0); +disable_vddcx: + msm_hsusb_init_vddcx(motg, 0); disable_clks: clk_disable_unprepare(motg->pclk); clk_disable_unprepare(motg->clk); -ldo_exit: - msm_hsusb_ldo_init(motg, 0); -vddcx_exit: - msm_hsusb_init_vddcx(motg, 0); -free_regs: - iounmap(motg->regs); -put_core_clk: - if (motg->core_clk) - clk_put(motg->core_clk); - clk_put(motg->pclk); -put_pclk_src: - if (!IS_ERR(motg->pclk_src)) { - clk_disable_unprepare(motg->pclk_src); - clk_put(motg->pclk_src); - } -put_clk: - clk_put(motg->clk); -put_phy_reset_clk: - clk_put(motg->phy_reset_clk); -free_motg: - kfree(motg->phy.otg); - kfree(motg); + if (!IS_ERR(motg->core_clk)) + clk_disable_unprepare(motg->core_clk); return ret; } @@ -1621,7 +1725,7 @@ static int msm_otg_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); usb_remove_phy(phy); - free_irq(motg->irq, motg); + disable_irq(motg->irq); /* * Put PHY in low power mode. @@ -1641,26 +1745,12 @@ static int msm_otg_remove(struct platform_device *pdev) clk_disable_unprepare(motg->pclk); clk_disable_unprepare(motg->clk); - if (motg->core_clk) + if (!IS_ERR(motg->core_clk)) clk_disable_unprepare(motg->core_clk); - if (!IS_ERR(motg->pclk_src)) { - clk_disable_unprepare(motg->pclk_src); - clk_put(motg->pclk_src); - } msm_hsusb_ldo_init(motg, 0); - iounmap(motg->regs); pm_runtime_set_suspended(&pdev->dev); - clk_put(motg->phy_reset_clk); - clk_put(motg->pclk); - clk_put(motg->clk); - if (motg->core_clk) - clk_put(motg->core_clk); - - kfree(motg->phy.otg); - kfree(motg); - return 0; } @@ -1740,15 +1830,17 @@ static const struct dev_pm_ops msm_otg_dev_pm_ops = { }; static struct platform_driver msm_otg_driver = { + .probe = msm_otg_probe, .remove = msm_otg_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .pm = &msm_otg_dev_pm_ops, + .of_match_table = msm_otg_dt_match, }, }; -module_platform_driver_probe(msm_otg_driver, msm_otg_probe); +module_platform_driver(msm_otg_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MSM USB transceiver driver"); diff --git a/drivers/usb/phy/phy-mv-u3d-usb.c b/drivers/usb/phy/phy-mv-u3d-usb.c deleted file mode 100644 index d317903022bf17..00000000000000 --- a/drivers/usb/phy/phy-mv-u3d-usb.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (C) 2011 Marvell International Ltd. 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, - * version 2, as published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "phy-mv-u3d-usb.h" - -/* - * struct mv_u3d_phy - transceiver driver state - * @phy: transceiver structure - * @dev: The parent device supplied to the probe function - * @clk: usb phy clock - * @base: usb phy register memory base - */ -struct mv_u3d_phy { - struct usb_phy phy; - struct mv_usb_platform_data *plat; - struct device *dev; - struct clk *clk; - void __iomem *base; -}; - -static u32 mv_u3d_phy_read(void __iomem *base, u32 reg) -{ - void __iomem *addr, *data; - - addr = base; - data = base + 0x4; - - writel_relaxed(reg, addr); - return readl_relaxed(data); -} - -static void mv_u3d_phy_set(void __iomem *base, u32 reg, u32 value) -{ - void __iomem *addr, *data; - u32 tmp; - - addr = base; - data = base + 0x4; - - writel_relaxed(reg, addr); - tmp = readl_relaxed(data); - tmp |= value; - writel_relaxed(tmp, data); -} - -static void mv_u3d_phy_clear(void __iomem *base, u32 reg, u32 value) -{ - void __iomem *addr, *data; - u32 tmp; - - addr = base; - data = base + 0x4; - - writel_relaxed(reg, addr); - tmp = readl_relaxed(data); - tmp &= ~value; - writel_relaxed(tmp, data); -} - -static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value) -{ - void __iomem *addr, *data; - - addr = base; - data = base + 0x4; - - writel_relaxed(reg, addr); - writel_relaxed(value, data); -} - -static void mv_u3d_phy_shutdown(struct usb_phy *phy) -{ - struct mv_u3d_phy *mv_u3d_phy; - void __iomem *base; - u32 val; - - mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy); - base = mv_u3d_phy->base; - - /* Power down Reference Analog current, bit 15 - * Power down PLL, bit 14 - * Power down Receiver, bit 13 - * Power down Transmitter, bit 12 - * of USB3_POWER_PLL_CONTROL register - */ - val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL); - val &= ~(USB3_POWER_PLL_CONTROL_PU); - mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val); - - if (mv_u3d_phy->clk) - clk_disable(mv_u3d_phy->clk); -} - -static int mv_u3d_phy_init(struct usb_phy *phy) -{ - struct mv_u3d_phy *mv_u3d_phy; - void __iomem *base; - u32 val, count; - - /* enable usb3 phy */ - mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy); - - if (mv_u3d_phy->clk) - clk_enable(mv_u3d_phy->clk); - - base = mv_u3d_phy->base; - - val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL); - val &= ~(USB3_POWER_PLL_CONTROL_PU_MASK); - val |= 0xF << USB3_POWER_PLL_CONTROL_PU_SHIFT; - mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val); - udelay(100); - - mv_u3d_phy_write(base, USB3_RESET_CONTROL, - USB3_RESET_CONTROL_RESET_PIPE); - udelay(100); - - mv_u3d_phy_write(base, USB3_RESET_CONTROL, - USB3_RESET_CONTROL_RESET_PIPE - | USB3_RESET_CONTROL_RESET_PHY); - udelay(100); - - val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL); - val &= ~(USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK - | USB3_POWER_PLL_CONTROL_PHY_MODE_MASK); - val |= (USB3_PLL_25MHZ << USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT) - | (0x5 << USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT); - mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val); - udelay(100); - - mv_u3d_phy_clear(base, USB3_KVCO_CALI_CONTROL, - USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK); - udelay(100); - - val = mv_u3d_phy_read(base, USB3_SQUELCH_FFE); - val &= ~(USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK - | USB3_SQUELCH_FFE_FFE_RES_SEL_MASK - | USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK); - val |= ((0xD << USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT) - | (0x7 << USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT) - | (0x8 << USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT)); - mv_u3d_phy_write(base, USB3_SQUELCH_FFE, val); - udelay(100); - - val = mv_u3d_phy_read(base, USB3_GEN1_SET0); - val &= ~USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK; - val |= 1 << USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT; - mv_u3d_phy_write(base, USB3_GEN1_SET0, val); - udelay(100); - - val = mv_u3d_phy_read(base, USB3_GEN2_SET0); - val &= ~(USB3_GEN2_SET0_G2_TX_AMP_MASK - | USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK - | USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK); - val |= ((0x14 << USB3_GEN2_SET0_G2_TX_AMP_SHIFT) - | (1 << USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT) - | (0xA << USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT) - | (1 << USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT)); - mv_u3d_phy_write(base, USB3_GEN2_SET0, val); - udelay(100); - - mv_u3d_phy_read(base, USB3_TX_EMPPH); - val &= ~(USB3_TX_EMPPH_AMP_MASK - | USB3_TX_EMPPH_EN_MASK - | USB3_TX_EMPPH_AMP_FORCE_MASK - | USB3_TX_EMPPH_PAR1_MASK - | USB3_TX_EMPPH_PAR2_MASK); - val |= ((0xB << USB3_TX_EMPPH_AMP_SHIFT) - | (1 << USB3_TX_EMPPH_EN_SHIFT) - | (1 << USB3_TX_EMPPH_AMP_FORCE_SHIFT) - | (0x1C << USB3_TX_EMPPH_PAR1_SHIFT) - | (1 << USB3_TX_EMPPH_PAR2_SHIFT)); - - mv_u3d_phy_write(base, USB3_TX_EMPPH, val); - udelay(100); - - val = mv_u3d_phy_read(base, USB3_GEN2_SET1); - val &= ~(USB3_GEN2_SET1_G2_RX_SELMUPI_MASK - | USB3_GEN2_SET1_G2_RX_SELMUPF_MASK - | USB3_GEN2_SET1_G2_RX_SELMUFI_MASK - | USB3_GEN2_SET1_G2_RX_SELMUFF_MASK); - val |= ((1 << USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT) - | (1 << USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT) - | (1 << USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT) - | (1 << USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT)); - mv_u3d_phy_write(base, USB3_GEN2_SET1, val); - udelay(100); - - val = mv_u3d_phy_read(base, USB3_DIGITAL_LOOPBACK_EN); - val &= ~USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK; - val |= 1 << USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT; - mv_u3d_phy_write(base, USB3_DIGITAL_LOOPBACK_EN, val); - udelay(100); - - val = mv_u3d_phy_read(base, USB3_IMPEDANCE_TX_SSC); - val &= ~USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK; - val |= 0xC << USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT; - mv_u3d_phy_write(base, USB3_IMPEDANCE_TX_SSC, val); - udelay(100); - - val = mv_u3d_phy_read(base, USB3_IMPEDANCE_CALI_CTRL); - val &= ~USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK; - val |= 0x4 << USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT; - mv_u3d_phy_write(base, USB3_IMPEDANCE_CALI_CTRL, val); - udelay(100); - - val = mv_u3d_phy_read(base, USB3_PHY_ISOLATION_MODE); - val &= ~(USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK - | USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK - | USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK); - val |= ((1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT) - | (1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT)); - mv_u3d_phy_write(base, USB3_PHY_ISOLATION_MODE, val); - udelay(100); - - val = mv_u3d_phy_read(base, USB3_TXDETRX); - val &= ~(USB3_TXDETRX_VTHSEL_MASK); - val |= 0x1 << USB3_TXDETRX_VTHSEL_SHIFT; - mv_u3d_phy_write(base, USB3_TXDETRX, val); - udelay(100); - - dev_dbg(mv_u3d_phy->dev, "start calibration\n"); - -calstart: - /* Perform Manual Calibration */ - mv_u3d_phy_set(base, USB3_KVCO_CALI_CONTROL, - 1 << USB3_KVCO_CALI_CONTROL_CAL_START_SHIFT); - - mdelay(1); - - count = 0; - while (1) { - val = mv_u3d_phy_read(base, USB3_KVCO_CALI_CONTROL); - if (val & (1 << USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT)) - break; - else if (count > 50) { - dev_dbg(mv_u3d_phy->dev, "calibration failure, retry...\n"); - goto calstart; - } - count++; - mdelay(1); - } - - /* active PIPE interface */ - mv_u3d_phy_write(base, USB3_PIPE_SM_CTRL, - 1 << USB3_PIPE_SM_CTRL_PHY_INIT_DONE); - - return 0; -} - -static int mv_u3d_phy_probe(struct platform_device *pdev) -{ - struct mv_u3d_phy *mv_u3d_phy; - struct mv_usb_platform_data *pdata; - struct device *dev = &pdev->dev; - struct resource *res; - void __iomem *phy_base; - int ret; - - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - dev_err(&pdev->dev, "%s: no platform data defined\n", __func__); - return -EINVAL; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - phy_base = devm_ioremap_resource(dev, res); - if (IS_ERR(phy_base)) - return PTR_ERR(phy_base); - - mv_u3d_phy = devm_kzalloc(dev, sizeof(*mv_u3d_phy), GFP_KERNEL); - if (!mv_u3d_phy) - return -ENOMEM; - - mv_u3d_phy->dev = &pdev->dev; - mv_u3d_phy->plat = pdata; - mv_u3d_phy->base = phy_base; - mv_u3d_phy->phy.dev = mv_u3d_phy->dev; - mv_u3d_phy->phy.label = "mv-u3d-phy"; - mv_u3d_phy->phy.init = mv_u3d_phy_init; - mv_u3d_phy->phy.shutdown = mv_u3d_phy_shutdown; - - ret = usb_add_phy(&mv_u3d_phy->phy, USB_PHY_TYPE_USB3); - if (ret) - goto err; - - if (!mv_u3d_phy->clk) - mv_u3d_phy->clk = clk_get(mv_u3d_phy->dev, "u3dphy"); - - platform_set_drvdata(pdev, mv_u3d_phy); - - dev_info(&pdev->dev, "Initialized Marvell USB 3.0 PHY\n"); -err: - return ret; -} - -static int mv_u3d_phy_remove(struct platform_device *pdev) -{ - struct mv_u3d_phy *mv_u3d_phy = platform_get_drvdata(pdev); - - usb_remove_phy(&mv_u3d_phy->phy); - - if (mv_u3d_phy->clk) { - clk_put(mv_u3d_phy->clk); - mv_u3d_phy->clk = NULL; - } - - return 0; -} - -static struct platform_driver mv_u3d_phy_driver = { - .probe = mv_u3d_phy_probe, - .remove = mv_u3d_phy_remove, - .driver = { - .name = "mv-u3d-phy", - .owner = THIS_MODULE, - }, -}; - -module_platform_driver(mv_u3d_phy_driver); -MODULE_DESCRIPTION("Marvell USB 3.0 PHY controller"); -MODULE_AUTHOR("Yu Xu "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:mv-u3d-phy"); diff --git a/drivers/usb/phy/phy-mv-u3d-usb.h b/drivers/usb/phy/phy-mv-u3d-usb.h deleted file mode 100644 index 2a658cb9a527e1..00000000000000 --- a/drivers/usb/phy/phy-mv-u3d-usb.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2011 Marvell International Ltd. 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, - * version 2, as published by the Free Software Foundation. - */ - -#ifndef __MV_U3D_PHY_H -#define __MV_U3D_PHY_H - -#define USB3_POWER_PLL_CONTROL 0x1 -#define USB3_KVCO_CALI_CONTROL 0x2 -#define USB3_IMPEDANCE_CALI_CTRL 0x3 -#define USB3_IMPEDANCE_TX_SSC 0x4 -#define USB3_SQUELCH_FFE 0x6 -#define USB3_GEN1_SET0 0xD -#define USB3_GEN2_SET0 0xF -#define USB3_GEN2_SET1 0x10 -#define USB3_DIGITAL_LOOPBACK_EN 0x23 -#define USB3_PHY_ISOLATION_MODE 0x26 -#define USB3_TXDETRX 0x48 -#define USB3_TX_EMPPH 0x5E -#define USB3_RESET_CONTROL 0x90 -#define USB3_PIPE_SM_CTRL 0x91 - -#define USB3_RESET_CONTROL_RESET_PIPE 0x1 -#define USB3_RESET_CONTROL_RESET_PHY 0x2 - -#define USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK (0x1F << 0) -#define USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT 0 -#define USB3_PLL_25MHZ 0x2 -#define USB3_PLL_26MHZ 0x5 -#define USB3_POWER_PLL_CONTROL_PHY_MODE_MASK (0x7 << 5) -#define USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT 5 -#define USB3_POWER_PLL_CONTROL_PU_MASK (0xF << 12) -#define USB3_POWER_PLL_CONTROL_PU_SHIFT 12 -#define USB3_POWER_PLL_CONTROL_PU (0xF << 12) - -#define USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK (0x1 << 12) -#define USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_SHIFT 12 -#define USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT 14 -#define USB3_KVCO_CALI_CONTROL_CAL_START_SHIFT 15 - -#define USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK 0xF -#define USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT 0 -#define USB3_SQUELCH_FFE_FFE_RES_SEL_MASK (0x7 << 4) -#define USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT 4 -#define USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK (0x1F << 8) -#define USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT 8 - -#define USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK (0x1 << 15) -#define USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT 11 - -#define USB3_GEN2_SET0_G2_TX_AMP_MASK (0x1F << 1) -#define USB3_GEN2_SET0_G2_TX_AMP_SHIFT 1 -#define USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT 6 -#define USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK (0xF << 7) -#define USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT 7 -#define USB3_GEN2_SET0_G2_TX_EMPH_EN_MASK (0x1 << 11) -#define USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT 11 -#define USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK (0x1 << 15) -#define USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_SHIFT 15 - -#define USB3_GEN2_SET1_G2_RX_SELMUPI_MASK (0x7 << 0) -#define USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT 0 -#define USB3_GEN2_SET1_G2_RX_SELMUPF_MASK (0x7 << 3) -#define USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT 3 -#define USB3_GEN2_SET1_G2_RX_SELMUFI_MASK (0x3 << 6) -#define USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT 6 -#define USB3_GEN2_SET1_G2_RX_SELMUFF_MASK (0x3 << 8) -#define USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT 8 - -#define USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK (0x3 << 10) -#define USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT 10 - -#define USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK (0x7 << 12) -#define USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT 12 - -#define USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK (0x3F << 0) -#define USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT 0 - -#define USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK 0xF -#define USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT 0 -#define USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK (0xF << 4) -#define USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT 4 -#define USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK (0x1 << 8) - -#define USB3_TXDETRX_VTHSEL_MASK (0x3 << 4) -#define USB3_TXDETRX_VTHSEL_SHIFT 4 - -#define USB3_TX_EMPPH_AMP_MASK (0xF << 0) -#define USB3_TX_EMPPH_AMP_SHIFT 0 -#define USB3_TX_EMPPH_EN_MASK (0x1 << 6) -#define USB3_TX_EMPPH_EN_SHIFT 6 -#define USB3_TX_EMPPH_AMP_FORCE_MASK (0x1 << 7) -#define USB3_TX_EMPPH_AMP_FORCE_SHIFT 7 -#define USB3_TX_EMPPH_PAR1_MASK (0x1F << 8) -#define USB3_TX_EMPPH_PAR1_SHIFT 8 -#define USB3_TX_EMPPH_PAR2_MASK (0x1 << 13) -#define USB3_TX_EMPPH_PAR2_SHIFT 13 - -#define USB3_PIPE_SM_CTRL_PHY_INIT_DONE 15 - -#endif /* __MV_U3D_PHY_H */ diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index b078440e822f2b..88e302bd28d596 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -325,7 +325,7 @@ static void usb_wwan_outdat_callback(struct urb *urb) for (i = 0; i < N_OUT_URB; ++i) { if (portdata->out_urbs[i] == urb) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(i, &portdata->out_busy); break; } diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index cf50ce93975bcd..aeb513108448d7 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1255,7 +1255,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, tpg->tv_tpg_vhost_count++; tpg->vhost_scsi = vs; vs_tpg[tpg->tport_tpgt] = tpg; - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); match = true; } mutex_unlock(&tpg->tv_tpg_mutex); diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index b75201ff46f6d1..cc49347bbcc076 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -10,8 +10,8 @@ * published by the Free Software Foundation. */ +#include #include -#include #include #include #include @@ -32,8 +32,7 @@ struct pwm_bl_data { unsigned int *levels; bool enabled; struct regulator *power_supply; - int enable_gpio; - unsigned long enable_gpio_flags; + struct gpio_desc *enable_gpio; unsigned int scale; int (*notify)(struct device *, int brightness); @@ -54,12 +53,8 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness) if (err < 0) dev_err(pb->dev, "failed to enable power supply\n"); - if (gpio_is_valid(pb->enable_gpio)) { - if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW) - gpio_set_value(pb->enable_gpio, 0); - else - gpio_set_value(pb->enable_gpio, 1); - } + if (pb->enable_gpio) + gpiod_set_value(pb->enable_gpio, 1); pwm_enable(pb->pwm); pb->enabled = true; @@ -73,12 +68,8 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb) pwm_config(pb->pwm, 0, pb->period); pwm_disable(pb->pwm); - if (gpio_is_valid(pb->enable_gpio)) { - if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW) - gpio_set_value(pb->enable_gpio, 1); - else - gpio_set_value(pb->enable_gpio, 0); - } + if (pb->enable_gpio) + gpiod_set_value(pb->enable_gpio, 0); regulator_disable(pb->power_supply); pb->enabled = false; @@ -148,7 +139,6 @@ static int pwm_backlight_parse_dt(struct device *dev, struct platform_pwm_backlight_data *data) { struct device_node *node = dev->of_node; - enum of_gpio_flags flags; struct property *prop; int length; u32 value; @@ -189,14 +179,6 @@ static int pwm_backlight_parse_dt(struct device *dev, data->max_brightness--; } - data->enable_gpio = of_get_named_gpio_flags(node, "enable-gpios", 0, - &flags); - if (data->enable_gpio == -EPROBE_DEFER) - return -EPROBE_DEFER; - - if (gpio_is_valid(data->enable_gpio) && (flags & OF_GPIO_ACTIVE_LOW)) - data->enable_gpio_flags |= PWM_BACKLIGHT_GPIO_ACTIVE_LOW; - return 0; } @@ -256,8 +238,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) } else pb->scale = data->max_brightness; - pb->enable_gpio = data->enable_gpio; - pb->enable_gpio_flags = data->enable_gpio_flags; pb->notify = data->notify; pb->notify_after = data->notify_after; pb->check_fb = data->check_fb; @@ -265,26 +245,38 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->dev = &pdev->dev; pb->enabled = false; - if (gpio_is_valid(pb->enable_gpio)) { - unsigned long flags; - - if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW) - flags = GPIOF_OUT_INIT_HIGH; + pb->enable_gpio = devm_gpiod_get(&pdev->dev, "enable"); + if (IS_ERR(pb->enable_gpio)) { + ret = PTR_ERR(pb->enable_gpio); + if (ret == -ENOENT) + pb->enable_gpio = NULL; else - flags = GPIOF_OUT_INIT_LOW; + goto err_alloc; + } - ret = gpio_request_one(pb->enable_gpio, flags, "enable"); + /* + * Compatibility fallback for drivers still using the integer GPIO + * platform data. Must go away soon. + */ + if (!pb->enable_gpio && gpio_is_valid(data->enable_gpio)) { + ret = devm_gpio_request_one(&pdev->dev, data->enable_gpio, + GPIOF_OUT_INIT_HIGH, "enable"); if (ret < 0) { dev_err(&pdev->dev, "failed to request GPIO#%d: %d\n", - pb->enable_gpio, ret); + data->enable_gpio, ret); goto err_alloc; } + + pb->enable_gpio = gpio_to_desc(data->enable_gpio); } + if (pb->enable_gpio) + gpiod_direction_output(pb->enable_gpio, 1); + pb->power_supply = devm_regulator_get(&pdev->dev, "power"); if (IS_ERR(pb->power_supply)) { ret = PTR_ERR(pb->power_supply); - goto err_gpio; + goto err_alloc; } pb->pwm = devm_pwm_get(&pdev->dev, NULL); @@ -295,7 +287,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) if (IS_ERR(pb->pwm)) { dev_err(&pdev->dev, "unable to request legacy PWM\n"); ret = PTR_ERR(pb->pwm); - goto err_gpio; + goto err_alloc; } } @@ -320,7 +312,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); ret = PTR_ERR(bl); - goto err_gpio; + goto err_alloc; } if (data->dft_brightness > data->max_brightness) { @@ -336,9 +328,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) platform_set_drvdata(pdev, bl); return 0; -err_gpio: - if (gpio_is_valid(pb->enable_gpio)) - gpio_free(pb->enable_gpio); err_alloc: if (data->exit) data->exit(&pdev->dev); @@ -359,6 +348,14 @@ static int pwm_backlight_remove(struct platform_device *pdev) return 0; } +static void pwm_backlight_shutdown(struct platform_device *pdev) +{ + struct backlight_device *bl = platform_get_drvdata(pdev); + struct pwm_bl_data *pb = bl_get_data(bl); + + pwm_backlight_power_off(pb); +} + #ifdef CONFIG_PM_SLEEP static int pwm_backlight_suspend(struct device *dev) { @@ -404,6 +401,7 @@ static struct platform_driver pwm_backlight_driver = { }, .probe = pwm_backlight_probe, .remove = pwm_backlight_remove, + .shutdown = pwm_backlight_shutdown, }; module_platform_driver(pwm_backlight_driver); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index f447734b09b48a..57b1d44acbfe3d 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -748,6 +748,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, fbcon_del_cursor_timer(oldinfo); kfree(ops->cursor_state.mask); kfree(ops->cursor_data); + kfree(ops->cursor_src); kfree(ops->fontbuffer); kfree(oldinfo->fbcon_par); oldinfo->fbcon_par = NULL; diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index e1f47272fdea0d..96f0f42d53bcd1 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -360,6 +360,7 @@ config FB_CYBER2000_DDC config FB_CYBER2000_I2C bool "CyberPro 2000/2010/5000 I2C support" depends on FB_CYBER2000 && I2C && ARCH_NETWINDER + depends on I2C=y || FB_CYBER2000=m select I2C_ALGOBIT help Enable support for the I2C video decoder interface on the @@ -966,6 +967,7 @@ config FB_S1D13XXX config FB_ATMEL tristate "AT91/AT32 LCD Controller support" depends on FB && HAVE_FB_ATMEL + select FB_BACKLIGHT select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1971,6 +1973,7 @@ config FB_W100 config FB_SH_MOBILE_LCDC tristate "SuperH Mobile LCDC framebuffer support" depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK + depends on FB_SH_MOBILE_MERAM || !FB_SH_MOBILE_MERAM select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT @@ -1993,7 +1996,7 @@ config FB_SH_MOBILE_HDMI config FB_TMIO tristate "Toshiba Mobile IO FrameBuffer support" - depends on FB && MFD_CORE + depends on FB && (MFD_TMIO || COMPILE_TEST) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -2062,7 +2065,7 @@ config FB_S3C2410_DEBUG through sysfs config FB_NUC900 - bool "NUC900 LCD framebuffer support" + tristate "NUC900 LCD framebuffer support" depends on FB && ARCH_W90X900 select FB_CFB_FILLRECT select FB_CFB_COPYAREA @@ -2169,7 +2172,7 @@ config FB_XILINX config FB_GOLDFISH tristate "Goldfish Framebuffer" - depends on FB && HAS_DMA + depends on FB && HAS_DMA && (GOLDFISH || COMPILE_TEST) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -2295,6 +2298,7 @@ endchoice config FB_MB862XX_I2C bool "Support I2C bus on MB862XX GDC" depends on FB_MB862XX && I2C + depends on FB_MB862XX=m || I2C=y default y help Selecting this option adds Coral-P(A)/Lime GDC I2C bus adapter diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index b6d5008f361f99..479fe2a5269cc7 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -674,6 +674,7 @@ int fb_show_logo(struct fb_info *info, int rotate) int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } int fb_show_logo(struct fb_info *info, int rotate) { return 0; } #endif /* CONFIG_LOGO */ +EXPORT_SYMBOL(fb_prepare_logo); EXPORT_SYMBOL(fb_show_logo); static void *fb_seq_start(struct seq_file *m, loff_t *pos) diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c index c204ebe6187e9f..5b0e313849bd22 100644 --- a/drivers/video/fbdev/core/fbmon.c +++ b/drivers/video/fbdev/core/fbmon.c @@ -1012,13 +1012,20 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) while (pos < edid[2]) { u8 len = edid[pos] & 0x1f, type = (edid[pos] >> 5) & 7; pr_debug("Data block %u of %u bytes\n", type, len); - if (type == 2) + if (type == 2) { for (i = pos; i < pos + len; i++) { u8 idx = edid[pos + i] & 0x7f; svd[svd_n++] = idx; pr_debug("N%sative mode #%d\n", edid[pos + i] & 0x80 ? "" : "on-n", idx); } + } else if (type == 3 && len >= 3) { + /* Check Vendor Specific Data Block. For HDMI, + it is always 00-0C-03 for HDMI Licensing, LLC. */ + if (edid[pos + 1] == 3 && edid[pos + 2] == 0xc && + edid[pos + 3] == 0) + specs->misc |= FB_MISC_HDMI; + } pos += len + 1; } diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c index 6b23508ff0a5f5..a8484f768d04e1 100644 --- a/drivers/video/fbdev/da8xx-fb.c +++ b/drivers/video/fbdev/da8xx-fb.c @@ -242,6 +242,20 @@ static struct fb_videomode known_lcd_panels[] = { .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .flag = 0, }, + [3] = { + /* Densitron 84-0023-001T */ + .name = "Densitron_84-0023-001T", + .xres = 320, + .yres = 240, + .pixclock = KHZ2PICOS(6400), + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .hsync_len = 30, + .vsync_len = 3, + .sync = 0, + }, }; static bool da8xx_fb_is_raster_enabled(void) diff --git a/drivers/video/fbdev/exynos/Kconfig b/drivers/video/fbdev/exynos/Kconfig index fcf2d48ac6d16b..1f16b4678c714a 100644 --- a/drivers/video/fbdev/exynos/Kconfig +++ b/drivers/video/fbdev/exynos/Kconfig @@ -4,6 +4,7 @@ menuconfig EXYNOS_VIDEO bool "Exynos Video driver support" + depends on ARCH_S5PV210 || ARCH_EXYNOS help This enables support for EXYNOS Video device. @@ -15,7 +16,6 @@ if EXYNOS_VIDEO config EXYNOS_MIPI_DSI bool "EXYNOS MIPI DSI driver support." - depends on ARCH_S5PV210 || ARCH_EXYNOS select GENERIC_PHY help This enables support for MIPI-DSI device. diff --git a/drivers/video/fbdev/gbefb.c b/drivers/video/fbdev/gbefb.c index 3ec65a878ac8cf..4aa56ba78f321e 100644 --- a/drivers/video/fbdev/gbefb.c +++ b/drivers/video/fbdev/gbefb.c @@ -1068,7 +1068,7 @@ static struct fb_ops gbefb_ops = { static ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", gbe_mem_size); + return snprintf(buf, PAGE_SIZE, "%u\n", gbe_mem_size); } static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL); diff --git a/drivers/video/fbdev/mbx/Makefile b/drivers/video/fbdev/mbx/Makefile index 16c1165cf9c78c..d7ae5a9bb376e8 100644 --- a/drivers/video/fbdev/mbx/Makefile +++ b/drivers/video/fbdev/mbx/Makefile @@ -1,4 +1,3 @@ # Makefile for the 2700G controller driver. -obj-$(CONFIG_FB_MBX) += mbxfb.o -obj-$(CONFIG_FB_MBX_DEBUG) += mbxfbdebugfs.o +obj-y += mbxfb.o diff --git a/drivers/video/fbdev/mbx/mbxdebugfs.c b/drivers/video/fbdev/mbx/mbxdebugfs.c index 4449f249b0e7ce..e3bc00a7529655 100644 --- a/drivers/video/fbdev/mbx/mbxdebugfs.c +++ b/drivers/video/fbdev/mbx/mbxdebugfs.c @@ -17,7 +17,7 @@ struct mbxfb_debugfs_data { static int open_file_generic(struct inode *inode, struct file *file) { - file->private_data = inode->u.generic_ip; + file->private_data = inode->i_private; return 0; } diff --git a/drivers/video/fbdev/mbx/mbxfb.c b/drivers/video/fbdev/mbx/mbxfb.c index f0a5392f5fd33b..2bd52ed8832cfa 100644 --- a/drivers/video/fbdev/mbx/mbxfb.c +++ b/drivers/video/fbdev/mbx/mbxfb.c @@ -877,6 +877,8 @@ static int mbxfb_resume(struct platform_device *dev) #ifndef CONFIG_FB_MBX_DEBUG #define mbxfb_debugfs_init(x) do {} while(0) #define mbxfb_debugfs_remove(x) do {} while(0) +#else +#include "mbxdebugfs.c" #endif #define res_size(_r) (((_r)->end - (_r)->start) + 1) diff --git a/drivers/video/fbdev/mmp/Kconfig b/drivers/video/fbdev/mmp/Kconfig index d4a4ffc24749e1..f56a7e2e8136ad 100644 --- a/drivers/video/fbdev/mmp/Kconfig +++ b/drivers/video/fbdev/mmp/Kconfig @@ -1,6 +1,6 @@ menuconfig MMP_DISP tristate "Marvell MMP Display Subsystem support" - depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988 + depends on CPU_PXA910 || CPU_MMP2 help Marvell Display Subsystem support. diff --git a/drivers/video/fbdev/mmp/fb/mmpfb.c b/drivers/video/fbdev/mmp/fb/mmpfb.c index 7ab31eb76a8c35..910fcc6ececeed 100644 --- a/drivers/video/fbdev/mmp/fb/mmpfb.c +++ b/drivers/video/fbdev/mmp/fb/mmpfb.c @@ -554,8 +554,8 @@ static void fb_info_clear(struct fb_info *info) static int mmpfb_probe(struct platform_device *pdev) { struct mmp_buffer_driver_mach_info *mi; - struct fb_info *info = 0; - struct mmpfb_info *fbi = 0; + struct fb_info *info; + struct mmpfb_info *fbi; int ret, modes_num; mi = pdev->dev.platform_data; @@ -569,10 +569,6 @@ static int mmpfb_probe(struct platform_device *pdev) if (info == NULL) return -ENOMEM; fbi = info->par; - if (!fbi) { - ret = -EINVAL; - goto failed; - } /* init fb */ fbi->fb_info = info; @@ -667,7 +663,6 @@ static int mmpfb_probe(struct platform_device *pdev) fbi->fb_start_dma); failed_destroy_mutex: mutex_destroy(&fbi->access_ok); -failed: dev_err(fbi->dev, "mmp-fb: frame buffer device init failed\n"); framebuffer_release(info); diff --git a/drivers/video/fbdev/mmp/hw/Kconfig b/drivers/video/fbdev/mmp/hw/Kconfig index 02f109a20cd010..c735d133895c5d 100644 --- a/drivers/video/fbdev/mmp/hw/Kconfig +++ b/drivers/video/fbdev/mmp/hw/Kconfig @@ -2,12 +2,12 @@ if MMP_DISP config MMP_DISP_CONTROLLER bool "mmp display controller hw support" - depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988 + depends on CPU_PXA910 || CPU_MMP2 default n help Marvell MMP display hw controller support - this controller is used on Marvell PXA910, - MMP2, MMP3, PXA988 chips + this controller is used on Marvell PXA910 and + MMP2 chips config MMP_DISP_SPI bool "mmp display controller spi port" diff --git a/drivers/video/fbdev/mmp/hw/mmp_ctrl.h b/drivers/video/fbdev/mmp/hw/mmp_ctrl.h index 53301cfdb1aeb6..56fdeab3435583 100644 --- a/drivers/video/fbdev/mmp/hw/mmp_ctrl.h +++ b/drivers/video/fbdev/mmp/hw/mmp_ctrl.h @@ -167,11 +167,7 @@ struct lcd_regs { PN2_IOPAD_CONTROL) : LCD_TOP_CTRL) /* dither configure */ -#ifdef CONFIG_CPU_PXA988 -#define LCD_DITHER_CTRL (0x01EC) -#else #define LCD_DITHER_CTRL (0x00A0) -#endif #define DITHER_TBL_INDEX_SEL(s) ((s) << 16) #define DITHER_MODE2(m) ((m) << 12) @@ -186,15 +182,6 @@ struct lcd_regs { #define DITHER_EN1 (1) /* dither table data was fixed by video bpp of input and output*/ -#ifdef CONFIG_CPU_PXA988 -#define DITHER_TB_4X4_INDEX0 (0x6e4ca280) -#define DITHER_TB_4X4_INDEX1 (0x5d7f91b3) -#define DITHER_TB_4X8_INDEX0 (0xb391a280) -#define DITHER_TB_4X8_INDEX1 (0x7f5d6e4c) -#define DITHER_TB_4X8_INDEX2 (0x80a291b3) -#define DITHER_TB_4X8_INDEX3 (0x4c6e5d7f) -#define LCD_DITHER_TBL_DATA (0x01F0) -#else #define DITHER_TB_4X4_INDEX0 (0x3b19f7d5) #define DITHER_TB_4X4_INDEX1 (0x082ac4e6) #define DITHER_TB_4X8_INDEX0 (0xf7d508e6) @@ -202,7 +189,6 @@ struct lcd_regs { #define DITHER_TB_4X8_INDEX2 (0xc4e6d5f7) #define DITHER_TB_4X8_INDEX3 (0x082a193b) #define LCD_DITHER_TBL_DATA (0x00A4) -#endif /* Video Frame 0&1 start address registers */ #define LCD_SPU_DMA_START_ADDR_Y0 0x00C0 @@ -933,16 +919,9 @@ struct lcd_regs { #define LCD_PN2_SQULN2_CTRL (0x02F0) #define ALL_LAYER_ALPHA_SEL (0x02F4) -/* pxa988 has different MASTER_CTRL from MMP3/MMP2 */ -#ifdef CONFIG_CPU_PXA988 -#define TIMING_MASTER_CONTROL (0x01F4) -#define MASTER_ENH(id) (1 << ((id) + 5)) -#define MASTER_ENV(id) (1 << ((id) + 6)) -#else #define TIMING_MASTER_CONTROL (0x02F8) #define MASTER_ENH(id) (1 << (id)) #define MASTER_ENV(id) (1 << ((id) + 4)) -#endif #define DSI_START_SEL_SHIFT(id) (((id) << 1) + 8) #define timing_master_config(path, dsi_id, lcd_id) \ @@ -1312,19 +1291,8 @@ struct dsi_regs { #define DSI_PHY_TIME_3_CFG_CSR_TIME_REQRDY_MASK (0xff) #define DSI_PHY_TIME_3_CFG_CSR_TIME_REQRDY_SHIFT 0 -/* - * DSI timings - * PXA988 has diffrent ESC CLK with MMP2/MMP3 - * it will be used in dsi_set_dphy() in pxa688_phy.c - * as low power mode clock. - */ -#ifdef CONFIG_CPU_PXA988 -#define DSI_ESC_CLK 52 /* Unit: Mhz */ -#define DSI_ESC_CLK_T 19 /* Unit: ns */ -#else #define DSI_ESC_CLK 66 /* Unit: Mhz */ #define DSI_ESC_CLK_T 15 /* Unit: ns */ -#endif /* LVDS */ /* LVDS_PHY_CTRL */ diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c index 142e860fb527bd..ee95de80a48747 100644 --- a/drivers/video/fbdev/mx3fb.c +++ b/drivers/video/fbdev/mx3fb.c @@ -1496,7 +1496,7 @@ static int mx3fb_probe(struct platform_device *pdev) if (!sdc_reg) return -EINVAL; - mx3fb = kzalloc(sizeof(*mx3fb), GFP_KERNEL); + mx3fb = devm_kzalloc(&pdev->dev, sizeof(*mx3fb), GFP_KERNEL); if (!mx3fb) return -ENOMEM; @@ -1542,7 +1542,6 @@ static int mx3fb_probe(struct platform_device *pdev) dmaengine_put(); iounmap(mx3fb->reg_base); eremap: - kfree(mx3fb); dev_err(dev, "mx3fb: failed to register fb\n"); return ret; } @@ -1561,7 +1560,6 @@ static int mx3fb_remove(struct platform_device *dev) dmaengine_put(); iounmap(mx3fb->reg_base); - kfree(mx3fb); return 0; } diff --git a/drivers/video/fbdev/omap/Kconfig b/drivers/video/fbdev/omap/Kconfig index 0bc3a936ce2be0..18c4cb0d569078 100644 --- a/drivers/video/fbdev/omap/Kconfig +++ b/drivers/video/fbdev/omap/Kconfig @@ -39,6 +39,15 @@ config FB_OMAP_LCD_MIPID the Mobile Industry Processor Interface DBI-C/DCS specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3) +config FB_OMAP_LCD_H3 + bool "TPS65010 LCD controller on OMAP-H3" + depends on MACH_OMAP_H3 + depends on TPS65010 + default y + help + Say Y here if you want to have support for the LCD on the + H3 board. + config FB_OMAP_DMA_TUNE bool "Set DMA SDRAM access priority high" depends on FB_OMAP diff --git a/drivers/video/fbdev/omap/Makefile b/drivers/video/fbdev/omap/Makefile index 1927faffb5bc71..732e0718be5309 100644 --- a/drivers/video/fbdev/omap/Makefile +++ b/drivers/video/fbdev/omap/Makefile @@ -10,17 +10,18 @@ objs-y$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o -objs-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o -objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o -objs-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o -objs-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o -objs-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o -objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o -objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o -objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o - -objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o -objs-y$(CONFIG_MACH_HERALD) += lcd_htcherald.o +lcds-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o +lcds-y$(CONFIG_FB_OMAP_LCD_H3) += lcd_h3.o +lcds-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o +lcds-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o +lcds-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o +lcds-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o +lcds-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o +lcds-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o + +lcds-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o +lcds-y$(CONFIG_MACH_HERALD) += lcd_htcherald.o omapfb-objs := $(objs-yy) +obj-$(CONFIG_FB_OMAP) += $(lcds-yy) diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c index e4fc6d9b53718a..d8d028d98711bf 100644 --- a/drivers/video/fbdev/omap/omapfb_main.c +++ b/drivers/video/fbdev/omap/omapfb_main.c @@ -1823,6 +1823,7 @@ void omapfb_register_panel(struct lcd_panel *panel) if (fbdev_pdev != NULL) omapfb_do_probe(fbdev_pdev, fbdev_panel); } +EXPORT_SYMBOL_GPL(omapfb_register_panel); /* Called when the device is being detached from the driver */ static int omapfb_remove(struct platform_device *pdev) diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c index f18397c33e8fed..4fe143166b74dd 100644 --- a/drivers/video/fbdev/omap2/dss/dispc.c +++ b/drivers/video/fbdev/omap2/dss/dispc.c @@ -2577,9 +2577,9 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, channel = dispc_ovl_get_channel_out(plane); - DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " - "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n", - plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x, + DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->" + " %dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n", + plane, &oi->paddr, &oi->p_uv_addr, oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, oi->color_mode, oi->rotation, oi->mirror, channel, replication); diff --git a/drivers/video/fbdev/pxa3xx-gcu.c b/drivers/video/fbdev/pxa3xx-gcu.c index 417f9a27eb7d3b..4df3657fe22114 100644 --- a/drivers/video/fbdev/pxa3xx-gcu.c +++ b/drivers/video/fbdev/pxa3xx-gcu.c @@ -612,11 +612,9 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev) /* handle IO resources */ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->mmio_base = devm_request_and_ioremap(dev, r); - if (IS_ERR(priv->mmio_base)) { - dev_err(dev, "failed to map I/O memory\n"); + priv->mmio_base = devm_ioremap_resource(dev, r); + if (IS_ERR(priv->mmio_base)) return PTR_ERR(priv->mmio_base); - } /* enable the clock */ priv->clk = devm_clk_get(dev, NULL); diff --git a/drivers/video/fbdev/wm8505fb.c b/drivers/video/fbdev/wm8505fb.c index 537d199612af2b..d2fafbbcd7f814 100644 --- a/drivers/video/fbdev/wm8505fb.c +++ b/drivers/video/fbdev/wm8505fb.c @@ -162,7 +162,7 @@ static ssize_t contrast_show(struct device *dev, struct fb_info *info = dev_get_drvdata(dev); struct wm8505fb_info *fbi = to_wm8505fb_info(info); - return sprintf(buf, "%d\n", fbi->contrast); + return sprintf(buf, "%u\n", fbi->contrast); } static ssize_t contrast_store(struct device *dev, diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 1e443629f76d72..4d08f45a9c29ae 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -865,4 +865,19 @@ bool virtqueue_is_broken(struct virtqueue *_vq) } EXPORT_SYMBOL_GPL(virtqueue_is_broken); +/* + * This should prevent the device from being used, allowing drivers to + * recover. You may need to grab appropriate locks to flush. + */ +void virtio_break_device(struct virtio_device *dev) +{ + struct virtqueue *_vq; + + list_for_each_entry(_vq, &dev->vqs, list) { + struct vring_virtqueue *vq = to_vvq(_vq); + vq->broken = true; + } +} +EXPORT_SYMBOL_GPL(virtio_break_device); + MODULE_LICENSE("GPL"); diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c index 3bff6b37b4727f..3651ec801f453d 100644 --- a/drivers/w1/w1_family.c +++ b/drivers/w1/w1_family.c @@ -139,9 +139,9 @@ void w1_family_get(struct w1_family *f) void __w1_family_get(struct w1_family *f) { - smp_mb__before_atomic_inc(); + smp_mb__before_atomic(); atomic_inc(&f->refcnt); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } EXPORT_SYMBOL(w1_unregister_family); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 74ec8fc5cc0303..2b4c1fc8765340 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -835,7 +835,7 @@ config 60XX_WDT config SBC8360_WDT tristate "SBC8360 Watchdog Timer" - depends on X86 + depends on X86_32 ---help--- This is the driver for the hardware watchdog on the SBC8360 Single diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c index d2cd9f0bcb9a2d..56369c4f1961d0 100644 --- a/drivers/watchdog/via_wdt.c +++ b/drivers/watchdog/via_wdt.c @@ -232,7 +232,7 @@ static int wdt_probe(struct pci_dev *pdev, static void wdt_remove(struct pci_dev *pdev) { watchdog_unregister_device(&wdt_dev); - del_timer(&timer); + del_timer_sync(&timer); iounmap(wdt_mem); release_mem_region(mmio, VIA_WDT_MMIO_LEN); release_resource(&wdt_res); diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index 82358d14ecf18a..59fc190f1e927d 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -127,7 +127,7 @@ static int push_cxx_to_hypervisor(struct acpi_processor *_pr) pr_debug(" C%d: %s %d uS\n", cx->type, cx->desc, (u32)cx->latency); } - } else if (ret != -EINVAL) + } else if ((ret != -EINVAL) && (ret != -ENOSYS)) /* EINVAL means the ACPI ID is incorrect - meaning the ACPI * table is referencing a non-existing CPU - which can happen * with broken ACPI tables. */ @@ -259,7 +259,7 @@ static int push_pxx_to_hypervisor(struct acpi_processor *_pr) (u32) perf->states[i].power, (u32) perf->states[i].transition_latency); } - } else if (ret != -EINVAL) + } else if ((ret != -EINVAL) && (ret != -ENOSYS)) /* EINVAL means the ACPI ID is incorrect - meaning the ACPI * table is referencing a non-existing CPU - which can happen * with broken ACPI tables. */ diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c index 607e41460c0d7e..c4a0666de6f5e0 100644 --- a/drivers/xen/xen-pciback/pciback_ops.c +++ b/drivers/xen/xen-pciback/pciback_ops.c @@ -348,9 +348,9 @@ void xen_pcibk_do_op(struct work_struct *data) notify_remote_via_irq(pdev->evtchn_irq); /* Mark that we're done. */ - smp_mb__before_clear_bit(); /* /after/ clearing PCIF_active */ + smp_mb__before_atomic(); /* /after/ clearing PCIF_active */ clear_bit(_PDEVF_op_active, &pdev->flags); - smp_mb__after_clear_bit(); /* /before/ final check for work */ + smp_mb__after_atomic(); /* /before/ final check for work */ /* Check to see if the driver domain tried to start another request in * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active. diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index c71e88602ff49a..cc1cfae726b38f 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c @@ -259,8 +259,7 @@ static int v9fs_launder_page(struct page *page) * */ static ssize_t -v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, - loff_t pos, unsigned long nr_segs) +v9fs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos) { /* * FIXME @@ -269,7 +268,7 @@ v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, */ p9_debug(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%s) off/no(%lld/%lu) EINVAL\n", iocb->ki_filp->f_path.dentry->d_name.name, - (long long)pos, nr_segs); + (long long)pos, iter->nr_segs); return -EINVAL; } diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 81f1bd9e613d16..520c11c2dcca4c 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -352,9 +352,6 @@ static int v9fs_file_flock_dotl(struct file *filp, int cmd, invalidate_mapping_pages(&inode->i_data, 0, -1); } /* Convert flock to posix lock */ - fl->fl_owner = (fl_owner_t)filp; - fl->fl_start = 0; - fl->fl_end = OFFSET_MAX; fl->fl_flags |= FL_POSIX; fl->fl_flags ^= FL_FLOCK; @@ -695,7 +692,7 @@ v9fs_cached_file_read(struct file *filp, char __user *data, size_t count, { if (filp->f_flags & O_DIRECT) return v9fs_direct_read(filp, data, count, offset); - return do_sync_read(filp, data, count, offset); + return new_sync_read(filp, data, count, offset); } /** @@ -763,7 +760,7 @@ v9fs_direct_write(struct file *filp, const char __user * data, buff_write: mutex_unlock(&inode->i_mutex); - return do_sync_write(filp, data, count, offsetp); + return new_sync_write(filp, data, count, offsetp); } /** @@ -781,7 +778,7 @@ v9fs_cached_file_write(struct file *filp, const char __user * data, if (filp->f_flags & O_DIRECT) return v9fs_direct_write(filp, data, count, offset); - return do_sync_write(filp, data, count, offset); + return new_sync_write(filp, data, count, offset); } @@ -850,8 +847,8 @@ const struct file_operations v9fs_cached_file_operations = { .llseek = generic_file_llseek, .read = v9fs_cached_file_read, .write = v9fs_cached_file_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .open = v9fs_file_open, .release = v9fs_dir_release, .lock = v9fs_file_lock, @@ -863,8 +860,8 @@ const struct file_operations v9fs_cached_file_operations_dotl = { .llseek = generic_file_llseek, .read = v9fs_cached_file_read, .write = v9fs_cached_file_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .open = v9fs_file_open, .release = v9fs_dir_release, .lock = v9fs_file_lock_dotl, diff --git a/fs/adfs/file.c b/fs/adfs/file.c index a36da5382b40dc..07c9edce5aa768 100644 --- a/fs/adfs/file.c +++ b/fs/adfs/file.c @@ -23,12 +23,12 @@ const struct file_operations adfs_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, + .read = new_sync_read, + .read_iter = generic_file_read_iter, .mmap = generic_file_mmap, .fsync = generic_file_fsync, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .splice_read = generic_file_splice_read, }; diff --git a/fs/affs/file.c b/fs/affs/file.c index 0270303388ee66..a7fe57d2cd9a0a 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -27,10 +27,10 @@ static int affs_file_release(struct inode *inode, struct file *filp); const struct file_operations affs_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .open = affs_file_open, .release = affs_file_release, diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 529300327f4574..a1645b88fe8a47 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -669,7 +669,6 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) out_valid: dentry->d_fsdata = dir_version; -out_skip: dput(parent); key_put(key); _leave(" = 1 [valid]"); @@ -682,10 +681,6 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) spin_unlock(&dentry->d_lock); out_bad: - /* don't unhash if we have submounts */ - if (check_submounts_and_drop(dentry) != 0) - goto out_skip; - _debug("dropping dentry %s/%s", parent->d_name.name, dentry->d_name.name); dput(parent); diff --git a/fs/afs/file.c b/fs/afs/file.c index 66d50fe2ee459a..932ce07948b387 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -31,10 +31,10 @@ const struct file_operations afs_file_operations = { .open = afs_open, .release = afs_release, .llseek = generic_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = afs_file_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = afs_file_write, .mmap = generic_file_readonly_mmap, .splice_read = generic_file_splice_read, .fsync = afs_fsync, diff --git a/fs/afs/flock.c b/fs/afs/flock.c index a8cf2cff836c33..4baf1d2b39e410 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -555,10 +555,6 @@ int afs_flock(struct file *file, int cmd, struct file_lock *fl) return -ENOLCK; /* we're simulating flock() locks using posix locks on the server */ - fl->fl_owner = (fl_owner_t) file; - fl->fl_start = 0; - fl->fl_end = OFFSET_MAX; - if (fl->fl_type == F_UNLCK) return afs_do_unlk(file, fl); return afs_do_setlk(file, fl); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index be75b500005d0d..d2f91bd615a930 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -747,8 +747,7 @@ extern int afs_write_end(struct file *file, struct address_space *mapping, extern int afs_writepage(struct page *, struct writeback_control *); extern int afs_writepages(struct address_space *, struct writeback_control *); extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *); -extern ssize_t afs_file_write(struct kiocb *, const struct iovec *, - unsigned long, loff_t); +extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *); extern int afs_writeback_all(struct afs_vnode *); extern int afs_fsync(struct file *, loff_t, loff_t, int); diff --git a/fs/afs/write.c b/fs/afs/write.c index a890db4b9898fc..ab6adfd5251688 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -625,15 +625,14 @@ void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call) /* * write to an AFS file */ -ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +ssize_t afs_file_write(struct kiocb *iocb, struct iov_iter *from) { struct afs_vnode *vnode = AFS_FS_I(file_inode(iocb->ki_filp)); ssize_t result; - size_t count = iov_length(iov, nr_segs); + size_t count = iov_iter_count(from); - _enter("{%x.%u},{%zu},%lu,", - vnode->fid.vid, vnode->fid.vnode, count, nr_segs); + _enter("{%x.%u},{%zu},", + vnode->fid.vid, vnode->fid.vnode, count); if (IS_SWAPFILE(&vnode->vfs_inode)) { printk(KERN_INFO @@ -644,7 +643,7 @@ ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov, if (!count) return 0; - result = generic_file_aio_write(iocb, iov, nr_segs, pos); + result = generic_file_write_iter(iocb, from); if (IS_ERR_VALUE(result)) { _leave(" = %zd", result); return result; diff --git a/fs/aio.c b/fs/aio.c index a0ed6c7d2cd2a3..4f078c054b4160 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -477,7 +477,7 @@ void kiocb_set_cancel_fn(struct kiocb *req, kiocb_cancel_fn *cancel) } EXPORT_SYMBOL(kiocb_set_cancel_fn); -static int kiocb_cancel(struct kioctx *ctx, struct kiocb *kiocb) +static int kiocb_cancel(struct kiocb *kiocb) { kiocb_cancel_fn *old, *cancel; @@ -538,7 +538,7 @@ static void free_ioctx_users(struct percpu_ref *ref) struct kiocb, ki_list); list_del_init(&req->ki_list); - kiocb_cancel(ctx, req); + kiocb_cancel(req); } spin_unlock_irq(&ctx->ctx_lock); @@ -727,42 +727,42 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) * when the processes owning a context have all exited to encourage * the rapid destruction of the kioctx. */ -static void kill_ioctx(struct mm_struct *mm, struct kioctx *ctx, +static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx, struct completion *requests_done) { - if (!atomic_xchg(&ctx->dead, 1)) { - struct kioctx_table *table; + struct kioctx_table *table; - spin_lock(&mm->ioctx_lock); - rcu_read_lock(); - table = rcu_dereference(mm->ioctx_table); + if (atomic_xchg(&ctx->dead, 1)) + return -EINVAL; - WARN_ON(ctx != table->table[ctx->id]); - table->table[ctx->id] = NULL; - rcu_read_unlock(); - spin_unlock(&mm->ioctx_lock); - /* percpu_ref_kill() will do the necessary call_rcu() */ - wake_up_all(&ctx->wait); + spin_lock(&mm->ioctx_lock); + rcu_read_lock(); + table = rcu_dereference(mm->ioctx_table); - /* - * It'd be more correct to do this in free_ioctx(), after all - * the outstanding kiocbs have finished - but by then io_destroy - * has already returned, so io_setup() could potentially return - * -EAGAIN with no ioctxs actually in use (as far as userspace - * could tell). - */ - aio_nr_sub(ctx->max_reqs); + WARN_ON(ctx != table->table[ctx->id]); + table->table[ctx->id] = NULL; + rcu_read_unlock(); + spin_unlock(&mm->ioctx_lock); - if (ctx->mmap_size) - vm_munmap(ctx->mmap_base, ctx->mmap_size); + /* percpu_ref_kill() will do the necessary call_rcu() */ + wake_up_all(&ctx->wait); - ctx->requests_done = requests_done; - percpu_ref_kill(&ctx->users); - } else { - if (requests_done) - complete(requests_done); - } + /* + * It'd be more correct to do this in free_ioctx(), after all + * the outstanding kiocbs have finished - but by then io_destroy + * has already returned, so io_setup() could potentially return + * -EAGAIN with no ioctxs actually in use (as far as userspace + * could tell). + */ + aio_nr_sub(ctx->max_reqs); + + if (ctx->mmap_size) + vm_munmap(ctx->mmap_base, ctx->mmap_size); + + ctx->requests_done = requests_done; + percpu_ref_kill(&ctx->users); + return 0; } /* wait_on_sync_kiocb: @@ -1219,21 +1219,23 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx) if (likely(NULL != ioctx)) { struct completion requests_done = COMPLETION_INITIALIZER_ONSTACK(requests_done); + int ret; /* Pass requests_done to kill_ioctx() where it can be set * in a thread-safe way. If we try to set it here then we have * a race condition if two io_destroy() called simultaneously. */ - kill_ioctx(current->mm, ioctx, &requests_done); + ret = kill_ioctx(current->mm, ioctx, &requests_done); percpu_ref_put(&ioctx->users); /* Wait until all IO for the context are done. Otherwise kernel * keep using user-space buffers even if user thinks the context * is destroyed. */ - wait_for_completion(&requests_done); + if (!ret) + wait_for_completion(&requests_done); - return 0; + return ret; } pr_debug("EINVAL: io_destroy: invalid context id\n"); return -EINVAL; @@ -1241,6 +1243,7 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx) typedef ssize_t (aio_rw_op)(struct kiocb *, const struct iovec *, unsigned long, loff_t); +typedef ssize_t (rw_iter_op)(struct kiocb *, struct iov_iter *); static ssize_t aio_setup_vectored_rw(struct kiocb *kiocb, int rw, char __user *buf, @@ -1298,7 +1301,9 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode, int rw; fmode_t mode; aio_rw_op *rw_op; + rw_iter_op *iter_op; struct iovec inline_vec, *iovec = &inline_vec; + struct iov_iter iter; switch (opcode) { case IOCB_CMD_PREAD: @@ -1306,6 +1311,7 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode, mode = FMODE_READ; rw = READ; rw_op = file->f_op->aio_read; + iter_op = file->f_op->read_iter; goto rw_common; case IOCB_CMD_PWRITE: @@ -1313,12 +1319,13 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode, mode = FMODE_WRITE; rw = WRITE; rw_op = file->f_op->aio_write; + iter_op = file->f_op->write_iter; goto rw_common; rw_common: if (unlikely(!(file->f_mode & mode))) return -EBADF; - if (!rw_op) + if (!rw_op && !iter_op) return -EINVAL; ret = (opcode == IOCB_CMD_PREADV || @@ -1347,7 +1354,12 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode, if (rw == WRITE) file_start_write(file); - ret = rw_op(req, iovec, nr_segs, req->ki_pos); + if (iter_op) { + iov_iter_init(&iter, rw, iovec, nr_segs, req->ki_nbytes); + ret = iter_op(req, &iter); + } else { + ret = rw_op(req, iovec, nr_segs, req->ki_pos); + } if (rw == WRITE) file_end_write(file); @@ -1585,7 +1597,7 @@ SYSCALL_DEFINE3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb, kiocb = lookup_kiocb(ctx, iocb, key); if (kiocb) - ret = kiocb_cancel(ctx, kiocb); + ret = kiocb_cancel(kiocb); else ret = -EINVAL; diff --git a/fs/bfs/file.c b/fs/bfs/file.c index ae28922183357d..e7f88ace1a2508 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c @@ -23,10 +23,10 @@ const struct file_operations bfs_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .splice_read = generic_file_splice_read, }; diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index 1c2ce0c8771133..9e241063a616f2 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c @@ -617,7 +617,7 @@ int bioset_integrity_create(struct bio_set *bs, int pool_size) if (!bs->bio_integrity_pool) return -1; - bs->bvec_integrity_pool = biovec_create_pool(bs, pool_size); + bs->bvec_integrity_pool = biovec_create_pool(pool_size); if (!bs->bvec_integrity_pool) { mempool_destroy(bs->bio_integrity_pool); return -1; diff --git a/fs/bio.c b/fs/bio.c index 9bf512e0b75adc..24918b38b293f7 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -305,6 +305,8 @@ static void bio_chain_endio(struct bio *bio, int error) /** * bio_chain - chain bio completions + * @bio: the target bio + * @parent: the @bio's parent bio * * The caller won't have a bi_end_io called when @bio completes - instead, * @parent's bi_end_io won't be called until both @parent and @bio have @@ -1015,8 +1017,7 @@ static void bio_set_map_data(struct bio_map_data *bmd, struct bio *bio, bio->bi_private = bmd; } -static struct bio_map_data *bio_alloc_map_data(int nr_segs, - unsigned int iov_count, +static struct bio_map_data *bio_alloc_map_data(unsigned int iov_count, gfp_t gfp_mask) { if (iov_count > UIO_MAXIOV) @@ -1158,7 +1159,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q, if (offset) nr_pages++; - bmd = bio_alloc_map_data(nr_pages, iov_count, gfp_mask); + bmd = bio_alloc_map_data(iov_count, gfp_mask); if (!bmd) return ERR_PTR(-ENOMEM); @@ -1863,7 +1864,7 @@ EXPORT_SYMBOL_GPL(bio_trim); * create memory pools for biovec's in a bio_set. * use the global biovec slabs created for general use. */ -mempool_t *biovec_create_pool(struct bio_set *bs, int pool_entries) +mempool_t *biovec_create_pool(int pool_entries) { struct biovec_slab *bp = bvec_slabs + BIOVEC_MAX_IDX; @@ -1926,7 +1927,7 @@ struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad) if (!bs->bio_pool) goto bad; - bs->bvec_pool = biovec_create_pool(bs, pool_size); + bs->bvec_pool = biovec_create_pool(pool_size); if (!bs->bvec_pool) goto bad; diff --git a/fs/block_dev.c b/fs/block_dev.c index 83fba15cc39407..6d7274619bf916 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -165,14 +165,15 @@ blkdev_get_block(struct inode *inode, sector_t iblock, } static ssize_t -blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, - loff_t offset, unsigned long nr_segs) +blkdev_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset, - nr_segs, blkdev_get_block, NULL, NULL, 0); + return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iter, + offset, blkdev_get_block, + NULL, NULL, 0); } int __sync_blockdev(struct block_device *bdev, int wait) @@ -1571,43 +1572,38 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) * Does not take i_mutex for the write and thus is not for general purpose * use. */ -ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct blk_plug plug; ssize_t ret; - BUG_ON(iocb->ki_pos != pos); - blk_start_plug(&plug); - ret = __generic_file_aio_write(iocb, iov, nr_segs); + ret = __generic_file_write_iter(iocb, from); if (ret > 0) { ssize_t err; - - err = generic_write_sync(file, pos, ret); + err = generic_write_sync(file, iocb->ki_pos - ret, ret); if (err < 0) ret = err; } blk_finish_plug(&plug); return ret; } -EXPORT_SYMBOL_GPL(blkdev_aio_write); +EXPORT_SYMBOL_GPL(blkdev_write_iter); -static ssize_t blkdev_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct file *file = iocb->ki_filp; struct inode *bd_inode = file->f_mapping->host; loff_t size = i_size_read(bd_inode); + loff_t pos = iocb->ki_pos; if (pos >= size) return 0; size -= pos; - if (size < iocb->ki_nbytes) - nr_segs = iov_shorten((struct iovec *)iov, nr_segs, size); - return generic_file_aio_read(iocb, iov, nr_segs, pos); + iov_iter_truncate(to, size); + return generic_file_read_iter(iocb, to); } /* @@ -1639,10 +1635,10 @@ const struct file_operations def_blk_fops = { .open = blkdev_open, .release = blkdev_close, .llseek = block_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = blkdev_aio_read, - .aio_write = blkdev_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = blkdev_read_iter, + .write_iter = blkdev_write_iter, .mmap = generic_file_mmap, .fsync = blkdev_fsync, .unlocked_ioctl = block_ioctl, @@ -1650,7 +1646,7 @@ const struct file_operations def_blk_fops = { .compat_ioctl = compat_blkdev_ioctl, #endif .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, }; int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg) diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index c9a24444ec9a31..2256e9cceec54d 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -279,7 +279,7 @@ static inline void btrfs_inode_block_unlocked_dio(struct inode *inode) static inline void btrfs_inode_resume_unlocked_dio(struct inode *inode) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(BTRFS_INODE_READDIO_NEED_LOCK, &BTRFS_I(inode)->runtime_flags); } diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 3955e475ceece2..f29a54e454d4f8 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -3458,7 +3458,7 @@ static int lock_extent_buffer_for_io(struct extent_buffer *eb, static void end_extent_buffer_writeback(struct extent_buffer *eb) { clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK); } diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index ae6af072b635e1..17e7393c50f0a9 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -447,7 +447,7 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages, write_bytes -= copied; total_copied += copied; - /* Return to btrfs_file_aio_write to fault page */ + /* Return to btrfs_file_write_iter to fault page */ if (unlikely(copied == 0)) break; @@ -1658,27 +1658,22 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, } static ssize_t __btrfs_direct_write(struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, loff_t pos, - size_t count, size_t ocount) + struct iov_iter *from, + loff_t pos) { struct file *file = iocb->ki_filp; - struct iov_iter i; ssize_t written; ssize_t written_buffered; loff_t endbyte; int err; - written = generic_file_direct_write(iocb, iov, &nr_segs, pos, - count, ocount); + written = generic_file_direct_write(iocb, from, pos); - if (written < 0 || written == count) + if (written < 0 || !iov_iter_count(from)) return written; pos += written; - count -= written; - iov_iter_init(&i, iov, nr_segs, count, written); - written_buffered = __btrfs_buffered_write(file, &i, pos); + written_buffered = __btrfs_buffered_write(file, from, pos); if (written_buffered < 0) { err = written_buffered; goto out; @@ -1713,9 +1708,8 @@ static void update_time_for_write(struct inode *inode) inode_inc_iversion(inode); } -static ssize_t btrfs_file_aio_write(struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t btrfs_file_write_iter(struct kiocb *iocb, + struct iov_iter *from) { struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); @@ -1724,18 +1718,12 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, u64 end_pos; ssize_t num_written = 0; ssize_t err = 0; - size_t count, ocount; + size_t count = iov_iter_count(from); bool sync = (file->f_flags & O_DSYNC) || IS_SYNC(file->f_mapping->host); + loff_t pos = iocb->ki_pos; mutex_lock(&inode->i_mutex); - err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ); - if (err) { - mutex_unlock(&inode->i_mutex); - goto out; - } - count = ocount; - current->backing_dev_info = inode->i_mapping->backing_dev_info; err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); if (err) { @@ -1748,6 +1736,8 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, goto out; } + iov_iter_truncate(from, count); + err = file_remove_suid(file); if (err) { mutex_unlock(&inode->i_mutex); @@ -1789,14 +1779,9 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, atomic_inc(&BTRFS_I(inode)->sync_writers); if (unlikely(file->f_flags & O_DIRECT)) { - num_written = __btrfs_direct_write(iocb, iov, nr_segs, - pos, count, ocount); + num_written = __btrfs_direct_write(iocb, from, pos); } else { - struct iov_iter i; - - iov_iter_init(&i, iov, nr_segs, count, num_written); - - num_written = __btrfs_buffered_write(file, &i, pos); + num_written = __btrfs_buffered_write(file, from, pos); if (num_written > 0) iocb->ki_pos = pos + num_written; } @@ -2633,11 +2618,11 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence) const struct file_operations btrfs_file_operations = { .llseek = btrfs_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, .splice_read = generic_file_splice_read, - .aio_write = btrfs_file_aio_write, + .write_iter = btrfs_file_write_iter, .mmap = btrfs_file_mmap, .open = generic_file_open, .release = btrfs_release_file, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5f805bc944fad0..2ac3036be0457c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -7126,7 +7126,7 @@ static void btrfs_end_dio_bio(struct bio *bio, int err) * before atomic variable goto zero, we must make sure * dip->errors is perceived to be set. */ - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); } /* if there are more bios still pending for this dio, just exit */ @@ -7306,7 +7306,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, * before atomic variable goto zero, we must * make sure dip->errors is perceived to be set. */ - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); if (atomic_dec_and_test(&dip->pending_bios)) bio_io_error(dip->orig_bio); @@ -7391,39 +7391,30 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio, } static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, - unsigned long nr_segs) + const struct iov_iter *iter, loff_t offset) { int seg; int i; - size_t size; - unsigned long addr; unsigned blocksize_mask = root->sectorsize - 1; ssize_t retval = -EINVAL; - loff_t end = offset; if (offset & blocksize_mask) goto out; - /* Check the memory alignment. Blocks cannot straddle pages */ - for (seg = 0; seg < nr_segs; seg++) { - addr = (unsigned long)iov[seg].iov_base; - size = iov[seg].iov_len; - end += size; - if ((addr & blocksize_mask) || (size & blocksize_mask)) - goto out; - - /* If this is a write we don't need to check anymore */ - if (rw & WRITE) - continue; + if (iov_iter_alignment(iter) & blocksize_mask) + goto out; - /* - * Check to make sure we don't have duplicate iov_base's in this - * iovec, if so return EINVAL, otherwise we'll get csum errors - * when reading back. - */ - for (i = seg + 1; i < nr_segs; i++) { - if (iov[seg].iov_base == iov[i].iov_base) + /* If this is a write we don't need to check anymore */ + if (rw & WRITE) + return 0; + /* + * Check to make sure we don't have duplicate iov_base's in this + * iovec, if so return EINVAL, otherwise we'll get csum errors + * when reading back. + */ + for (seg = 0; seg < iter->nr_segs; seg++) { + for (i = seg + 1; i < iter->nr_segs; i++) { + if (iter->iov[seg].iov_base == iter->iov[i].iov_base) goto out; } } @@ -7433,8 +7424,7 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io } static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, - unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; @@ -7444,12 +7434,11 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, bool relock = false; ssize_t ret; - if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iov, - offset, nr_segs)) + if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iter, offset)) return 0; atomic_inc(&inode->i_dio_count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); /* * The generic stuff only does filemap_write_and_wait_range, which @@ -7457,7 +7446,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, * we need to flush the dirty pages again to make absolutely sure * that any outstanding dirty pages are on disk. */ - count = iov_length(iov, nr_segs); + count = iov_iter_count(iter); if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, &BTRFS_I(inode)->runtime_flags)) filemap_fdatawrite_range(inode->i_mapping, offset, count); @@ -7484,7 +7473,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, ret = __blockdev_direct_IO(rw, iocb, inode, BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev, - iov, offset, nr_segs, btrfs_get_blocks_direct, NULL, + iter, offset, btrfs_get_blocks_direct, NULL, btrfs_submit_direct, flags); if (rw & WRITE) { if (ret < 0 && ret != -EIOCBQUEUED) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 2ad7de94efef71..1939cdcf2985fc 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -642,7 +642,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, return -EINVAL; atomic_inc(&root->will_be_snapshoted); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); btrfs_wait_nocow_write(root); ret = btrfs_start_delalloc_inodes(root, 0); @@ -2301,9 +2301,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, } mutex_lock(&inode->i_mutex); - err = d_invalidate(dentry); - if (err) - goto out_unlock; + d_invalidate(dentry); down_write(&root->fs_info->subvol_sem); @@ -2388,7 +2386,6 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, btrfs_subvolume_release_metadata(root, &block_rsv, qgroup_reserved); out_up_write: up_write(&root->fs_info->subvol_sem); -out_unlock: mutex_unlock(&inode->i_mutex); if (!err) { shrink_dcache_sb(root->fs_info->sb); diff --git a/fs/buffer.c b/fs/buffer.c index 7b5bb90bd0700b..e33f8d5452ad82 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -77,7 +77,7 @@ EXPORT_SYMBOL(__lock_buffer); void unlock_buffer(struct buffer_head *bh) { clear_bit_unlock(BH_Lock, &bh->b_state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&bh->b_state, BH_Lock); } EXPORT_SYMBOL(unlock_buffer); diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 65a30e817dd80a..4f3f69079f3622 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1187,8 +1187,8 @@ static int ceph_write_end(struct file *file, struct address_space *mapping, * never get called. */ static ssize_t ceph_direct_io(int rw, struct kiocb *iocb, - const struct iovec *iov, - loff_t pos, unsigned long nr_segs) + struct iov_iter *iter, + loff_t pos) { WARN_ON(1); return -EINVAL; diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index c29d6ae6887489..b6c59eaa4f6435 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -1069,7 +1069,6 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags) ceph_dentry_lru_touch(dentry); } else { ceph_dir_clear_complete(dir); - d_drop(dentry); } iput(dir); return valid; diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 88a6df4cbe6d8a..302085100c28af 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -418,7 +418,7 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i, struct page **pages; u64 off = iocb->ki_pos; int num_pages, ret; - size_t len = i->count; + size_t len = iov_iter_count(i); dout("sync_read on file %p %llu~%u %s\n", file, off, (unsigned)len, @@ -436,25 +436,26 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i, if (file->f_flags & O_DIRECT) { while (iov_iter_count(i)) { - void __user *data = i->iov[0].iov_base + i->iov_offset; - size_t len = i->iov[0].iov_len - i->iov_offset; + size_t start; + ssize_t n; - num_pages = calc_pages_for((unsigned long)data, len); - pages = ceph_get_direct_page_vector(data, - num_pages, true); - if (IS_ERR(pages)) - return PTR_ERR(pages); + n = iov_iter_get_pages_alloc(i, &pages, INT_MAX, &start); + if (n < 0) + return n; - ret = striped_read(inode, off, len, + num_pages = (n + start + PAGE_SIZE - 1) / PAGE_SIZE; + + ret = striped_read(inode, off, n, pages, num_pages, checkeof, - 1, (unsigned long)data & ~PAGE_MASK); + 1, start); + ceph_put_page_vector(pages, num_pages, true); if (ret <= 0) break; off += ret; iov_iter_advance(i, ret); - if (ret < len) + if (ret < n) break; } } else { @@ -466,25 +467,14 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i, num_pages, checkeof, 0, 0); if (ret > 0) { int l, k = 0; - size_t left = len = ret; + size_t left = ret; while (left) { - void __user *data = i->iov[0].iov_base - + i->iov_offset; - l = min(i->iov[0].iov_len - i->iov_offset, - left); - - ret = ceph_copy_page_vector_to_user(&pages[k], - data, off, - l); - if (ret > 0) { - iov_iter_advance(i, ret); - left -= ret; - off += ret; - k = calc_pages_for(iocb->ki_pos, - len - left + 1) - 1; - BUG_ON(k >= num_pages && left); - } else + int copy = min_t(size_t, PAGE_SIZE, left); + l = copy_page_to_iter(pages[k++], 0, copy, i); + off += l; + left -= l; + if (l < copy) break; } } @@ -541,8 +531,7 @@ static void ceph_sync_write_unsafe(struct ceph_osd_request *req, bool unsafe) * objects, rollback on failure, etc.) */ static ssize_t -ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, size_t count) +ceph_sync_direct_write(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); @@ -556,11 +545,10 @@ ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov, int written = 0; int flags; int check_caps = 0; - int page_align; int ret; struct timespec mtime = CURRENT_TIME; loff_t pos = iocb->ki_pos; - struct iov_iter i; + size_t count = iov_iter_count(from); if (ceph_snap(file_inode(file)) != CEPH_NOSNAP) return -EROFS; @@ -582,13 +570,10 @@ ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov, CEPH_OSD_FLAG_ONDISK | CEPH_OSD_FLAG_WRITE; - iov_iter_init(&i, iov, nr_segs, count, 0); - - while (iov_iter_count(&i) > 0) { - void __user *data = i.iov->iov_base + i.iov_offset; - u64 len = i.iov->iov_len - i.iov_offset; - - page_align = (unsigned long)data & ~PAGE_MASK; + while (iov_iter_count(from) > 0) { + u64 len = iov_iter_single_seg_count(from); + size_t start; + ssize_t n; snapc = ci->i_snap_realm->cached_context; vino = ceph_vino(inode); @@ -604,20 +589,21 @@ ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov, break; } - num_pages = calc_pages_for(page_align, len); - pages = ceph_get_direct_page_vector(data, num_pages, false); - if (IS_ERR(pages)) { - ret = PTR_ERR(pages); - goto out; + n = iov_iter_get_pages_alloc(from, &pages, len, &start); + if (unlikely(n < 0)) { + ret = n; + ceph_osdc_put_request(req); + break; } + num_pages = (n + start + PAGE_SIZE - 1) / PAGE_SIZE; /* * throw out any page cache pages in this range. this * may block. */ truncate_inode_pages_range(inode->i_mapping, pos, - (pos+len) | (PAGE_CACHE_SIZE-1)); - osd_req_op_extent_osd_data_pages(req, 0, pages, len, page_align, + (pos+n) | (PAGE_CACHE_SIZE-1)); + osd_req_op_extent_osd_data_pages(req, 0, pages, n, start, false, false); /* BUG_ON(vino.snap != CEPH_NOSNAP); */ @@ -629,22 +615,20 @@ ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov, ceph_put_page_vector(pages, num_pages, false); -out: ceph_osdc_put_request(req); - if (ret == 0) { - pos += len; - written += len; - iov_iter_advance(&i, (size_t)len); - - if (pos > i_size_read(inode)) { - check_caps = ceph_inode_set_size(inode, pos); - if (check_caps) - ceph_check_caps(ceph_inode(inode), - CHECK_CAPS_AUTHONLY, - NULL); - } - } else + if (ret) break; + pos += n; + written += n; + iov_iter_advance(from, n); + + if (pos > i_size_read(inode)) { + check_caps = ceph_inode_set_size(inode, pos); + if (check_caps) + ceph_check_caps(ceph_inode(inode), + CHECK_CAPS_AUTHONLY, + NULL); + } } if (ret != -EOLDSNAPC && written > 0) { @@ -662,8 +646,7 @@ ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov, * correct atomic write, we should e.g. take write locks on all * objects, rollback on failure, etc.) */ -static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, size_t count) +static ssize_t ceph_sync_write(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); @@ -681,7 +664,7 @@ static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov, int ret; struct timespec mtime = CURRENT_TIME; loff_t pos = iocb->ki_pos; - struct iov_iter i; + size_t count = iov_iter_count(from); if (ceph_snap(file_inode(file)) != CEPH_NOSNAP) return -EROFS; @@ -703,9 +686,7 @@ static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov, CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ACK; - iov_iter_init(&i, iov, nr_segs, count, 0); - - while ((len = iov_iter_count(&i)) > 0) { + while ((len = iov_iter_count(from)) > 0) { size_t left; int n; @@ -737,13 +718,12 @@ static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov, left = len; for (n = 0; n < num_pages; n++) { size_t plen = min_t(size_t, left, PAGE_SIZE); - ret = iov_iter_copy_from_user(pages[n], &i, 0, plen); + ret = copy_page_from_iter(pages[n], 0, plen, from); if (ret != plen) { ret = -EFAULT; break; } left -= ret; - iov_iter_advance(&i, ret); } if (ret < 0) { @@ -796,8 +776,7 @@ static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov, * * Hmm, the sync read case isn't actually async... should it be? */ -static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct file *filp = iocb->ki_filp; struct ceph_file_info *fi = filp->private_data; @@ -823,40 +802,20 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov, if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 || (iocb->ki_filp->f_flags & O_DIRECT) || (fi->flags & CEPH_F_SYNC)) { - struct iov_iter i; dout("aio_sync_read %p %llx.%llx %llu~%u got cap refs on %s\n", inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len, ceph_cap_string(got)); - if (!read) { - ret = generic_segment_checks(iov, &nr_segs, - &len, VERIFY_WRITE); - if (ret) - goto out; - } - - iov_iter_init(&i, iov, nr_segs, len, read); - /* hmm, this isn't really async... */ - ret = ceph_sync_read(iocb, &i, &checkeof); + ret = ceph_sync_read(iocb, to, &checkeof); } else { - /* - * We can't modify the content of iov, - * so we only read from beginning. - */ - if (read) { - iocb->ki_pos = pos; - len = iocb->ki_nbytes; - read = 0; - } dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n", - inode, ceph_vinop(inode), pos, (unsigned)len, + inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len, ceph_cap_string(got)); - ret = generic_file_aio_read(iocb, iov, nr_segs, pos); + ret = generic_file_read_iter(iocb, to); } -out: dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n", inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret); ceph_put_cap_refs(ci, got); @@ -872,6 +831,7 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov, ", reading more\n", iocb->ki_pos, inode->i_size); + iov_iter_advance(to, ret); read += ret; len -= ret; checkeof = 0; @@ -895,8 +855,7 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov, * * If we are near ENOSPC, write synchronously. */ -static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct ceph_file_info *fi = file->private_data; @@ -904,18 +863,15 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov, struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->client->osdc; - ssize_t count, written = 0; + ssize_t count = iov_iter_count(from), written = 0; int err, want, got; + loff_t pos = iocb->ki_pos; if (ceph_snap(inode) != CEPH_NOSNAP) return -EROFS; mutex_lock(&inode->i_mutex); - err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ); - if (err) - goto out; - /* We can write back this queue in page reclaim */ current->backing_dev_info = file->f_mapping->backing_dev_info; @@ -925,6 +881,7 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov, if (count == 0) goto out; + iov_iter_truncate(from, count); err = file_remove_suid(file); if (err) @@ -956,23 +913,26 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov, if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 || (file->f_flags & O_DIRECT) || (fi->flags & CEPH_F_SYNC)) { + struct iov_iter data; mutex_unlock(&inode->i_mutex); + /* we might need to revert back to that point */ + data = *from; if (file->f_flags & O_DIRECT) - written = ceph_sync_direct_write(iocb, iov, - nr_segs, count); + written = ceph_sync_direct_write(iocb, &data); else - written = ceph_sync_write(iocb, iov, nr_segs, count); + written = ceph_sync_write(iocb, &data); if (written == -EOLDSNAPC) { dout("aio_write %p %llx.%llx %llu~%u" "got EOLDSNAPC, retrying\n", inode, ceph_vinop(inode), - pos, (unsigned)iov->iov_len); + pos, (unsigned)count); mutex_lock(&inode->i_mutex); goto retry_snap; } + if (written > 0) + iov_iter_advance(from, written); } else { loff_t old_size = inode->i_size; - struct iov_iter from; /* * No need to acquire the i_truncate_mutex. Because * the MDS revokes Fwb caps before sending truncate @@ -980,8 +940,7 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov, * are pending vmtruncate. So write and vmtruncate * can not run at the same time */ - iov_iter_init(&from, iov, nr_segs, count, 0); - written = generic_perform_write(file, &from, pos); + written = generic_perform_write(file, from, pos); if (likely(written >= 0)) iocb->ki_pos = pos + written; if (inode->i_size > old_size) @@ -999,7 +958,7 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov, } dout("aio_write %p %llx.%llx %llu~%u dropping cap refs on %s\n", - inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len, + inode, ceph_vinop(inode), pos, (unsigned)count, ceph_cap_string(got)); ceph_put_cap_refs(ci, got); @@ -1276,16 +1235,16 @@ const struct file_operations ceph_file_fops = { .open = ceph_open, .release = ceph_release, .llseek = ceph_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = ceph_aio_read, - .aio_write = ceph_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = ceph_read_iter, + .write_iter = ceph_write_iter, .mmap = ceph_mmap, .fsync = ceph_fsync, .lock = ceph_lock, .flock = ceph_flock, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, .unlocked_ioctl = ceph_ioctl, .compat_ioctl = ceph_ioctl, .fallocate = ceph_fallocate, diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 191398852a2e89..fbc39c47bacd17 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -53,10 +53,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, else length = fl->fl_end - fl->fl_start + 1; - if (lock_type == CEPH_LOCK_FCNTL) - owner = secure_addr(fl->fl_owner); - else - owner = secure_addr(fl->fl_file); + owner = secure_addr(fl->fl_owner); dout("ceph_lock_message: rule: %d, op: %d, owner: %llx, pid: %llu, " "start: %llu, length: %llu, wait: %d, type: %d", (int)lock_type, @@ -314,10 +311,7 @@ int lock_to_ceph_filelock(struct file_lock *lock, cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1); cephlock->client = cpu_to_le64(0); cephlock->pid = cpu_to_le64((u64)lock->fl_pid); - if (lock->fl_flags & FL_POSIX) - cephlock->owner = cpu_to_le64(secure_addr(lock->fl_owner)); - else - cephlock->owner = cpu_to_le64(secure_addr(lock->fl_file)); + cephlock->owner = cpu_to_le64(secure_addr(lock->fl_owner)); switch (lock->fl_type) { case F_RDLCK: diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5be1f997ecdeff..496b520934e01a 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -733,8 +733,7 @@ cifs_do_mount(struct file_system_type *fs_type, goto out; } -static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct inode *inode = file_inode(iocb->ki_filp); struct cifsInodeInfo *cinode = CIFS_I(inode); @@ -745,14 +744,14 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, if (written) return written; - written = generic_file_aio_write(iocb, iov, nr_segs, pos); + written = generic_file_write_iter(iocb, from); if (CIFS_CACHE_WRITE(CIFS_I(inode))) goto out; rc = filemap_fdatawrite(inode->i_mapping); if (rc) - cifs_dbg(FYI, "cifs_file_aio_write: %d rc on %p inode\n", + cifs_dbg(FYI, "cifs_file_write_iter: %d rc on %p inode\n", rc, inode); out: @@ -888,10 +887,10 @@ const struct inode_operations cifs_symlink_inode_ops = { }; const struct file_operations cifs_file_ops = { - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = cifs_file_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = cifs_file_write_iter, .open = cifs_open, .release = cifs_close, .lock = cifs_lock, @@ -907,10 +906,10 @@ const struct file_operations cifs_file_ops = { }; const struct file_operations cifs_file_strict_ops = { - .read = do_sync_read, - .write = do_sync_write, - .aio_read = cifs_strict_readv, - .aio_write = cifs_strict_writev, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = cifs_strict_readv, + .write_iter = cifs_strict_writev, .open = cifs_open, .release = cifs_close, .lock = cifs_lock, @@ -927,10 +926,10 @@ const struct file_operations cifs_file_strict_ops = { const struct file_operations cifs_file_direct_ops = { /* BB reevaluate whether they can be done with directio, no cache */ - .read = do_sync_read, - .write = do_sync_write, - .aio_read = cifs_user_readv, - .aio_write = cifs_user_writev, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = cifs_user_readv, + .write_iter = cifs_user_writev, .open = cifs_open, .release = cifs_close, .lock = cifs_lock, @@ -946,10 +945,10 @@ const struct file_operations cifs_file_direct_ops = { }; const struct file_operations cifs_file_nobrl_ops = { - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = cifs_file_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = cifs_file_write_iter, .open = cifs_open, .release = cifs_close, .fsync = cifs_fsync, @@ -964,10 +963,10 @@ const struct file_operations cifs_file_nobrl_ops = { }; const struct file_operations cifs_file_strict_nobrl_ops = { - .read = do_sync_read, - .write = do_sync_write, - .aio_read = cifs_strict_readv, - .aio_write = cifs_strict_writev, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = cifs_strict_readv, + .write_iter = cifs_strict_writev, .open = cifs_open, .release = cifs_close, .fsync = cifs_strict_fsync, @@ -983,10 +982,10 @@ const struct file_operations cifs_file_strict_nobrl_ops = { const struct file_operations cifs_file_direct_nobrl_ops = { /* BB reevaluate whether they can be done with directio, no cache */ - .read = do_sync_read, - .write = do_sync_write, - .aio_read = cifs_user_readv, - .aio_write = cifs_user_writev, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = cifs_user_readv, + .write_iter = cifs_user_writev, .open = cifs_open, .release = cifs_close, .fsync = cifs_fsync, diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 26a754f49ba193..c9e91886f0cfd0 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -85,14 +85,10 @@ extern const struct file_operations cifs_file_strict_nobrl_ops; extern int cifs_open(struct inode *inode, struct file *file); extern int cifs_close(struct inode *inode, struct file *file); extern int cifs_closedir(struct inode *inode, struct file *file); -extern ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos); -extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos); -extern ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos); -extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos); +extern ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to); +extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to); +extern ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from); +extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from); extern int cifs_lock(struct file *, int, struct file_lock *); extern int cifs_fsync(struct file *, loff_t, loff_t, int); extern int cifs_strict_fsync(struct file *, loff_t, loff_t, int); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5ed03e0b8b40e2..60e9b5fa22128f 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -2385,14 +2385,12 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata) } static ssize_t -cifs_iovec_write(struct file *file, const struct iovec *iov, - unsigned long nr_segs, loff_t *poffset) +cifs_iovec_write(struct file *file, struct iov_iter *from, loff_t *poffset) { unsigned long nr_pages, i; size_t bytes, copied, len, cur_len; ssize_t total_written = 0; loff_t offset; - struct iov_iter it; struct cifsFileInfo *open_file; struct cifs_tcon *tcon; struct cifs_sb_info *cifs_sb; @@ -2401,14 +2399,16 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, int rc; pid_t pid; - len = iov_length(iov, nr_segs); - if (!len) - return 0; - + len = iov_iter_count(from); rc = generic_write_checks(file, poffset, &len, 0); if (rc) return rc; + if (!len) + return 0; + + iov_iter_truncate(from, len); + INIT_LIST_HEAD(&wdata_list); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); open_file = file->private_data; @@ -2424,7 +2424,6 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, else pid = current->tgid; - iov_iter_init(&it, iov, nr_segs, len, 0); do { size_t save_len; @@ -2444,11 +2443,10 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, save_len = cur_len; for (i = 0; i < nr_pages; i++) { - bytes = min_t(const size_t, cur_len, PAGE_SIZE); - copied = iov_iter_copy_from_user(wdata->pages[i], &it, - 0, bytes); + bytes = min_t(size_t, cur_len, PAGE_SIZE); + copied = copy_page_from_iter(wdata->pages[i], 0, bytes, + from); cur_len -= copied; - iov_iter_advance(&it, copied); /* * If we didn't copy as much as we expected, then that * may mean we trod into an unmapped area. Stop copying @@ -2546,11 +2544,11 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, return total_written ? total_written : (ssize_t)rc; } -ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from) { ssize_t written; struct inode *inode; + loff_t pos = iocb->ki_pos; inode = file_inode(iocb->ki_filp); @@ -2560,7 +2558,7 @@ ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, * write request. */ - written = cifs_iovec_write(iocb->ki_filp, iov, nr_segs, &pos); + written = cifs_iovec_write(iocb->ki_filp, from, &pos); if (written > 0) { CIFS_I(inode)->invalid_mapping = true; iocb->ki_pos = pos; @@ -2570,8 +2568,7 @@ ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, } static ssize_t -cifs_writev(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +cifs_writev(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; @@ -2589,10 +2586,10 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov, mutex_lock(&inode->i_mutex); if (file->f_flags & O_APPEND) lock_pos = i_size_read(inode); - if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs), + if (!cifs_find_lock_conflict(cfile, lock_pos, iov_iter_count(from), server->vals->exclusive_lock_type, NULL, CIFS_WRITE_OP)) { - rc = __generic_file_aio_write(iocb, iov, nr_segs); + rc = __generic_file_write_iter(iocb, from); mutex_unlock(&inode->i_mutex); if (rc > 0) { @@ -2610,8 +2607,7 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov, } ssize_t -cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from) { struct inode *inode = file_inode(iocb->ki_filp); struct cifsInodeInfo *cinode = CIFS_I(inode); @@ -2629,11 +2625,10 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, if (cap_unix(tcon->ses) && (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) { - written = generic_file_aio_write( - iocb, iov, nr_segs, pos); + written = generic_file_write_iter(iocb, from); goto out; } - written = cifs_writev(iocb, iov, nr_segs, pos); + written = cifs_writev(iocb, from); goto out; } /* @@ -2642,7 +2637,7 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, * affected pages because it may cause a error with mandatory locks on * these pages but not on the region from pos to ppos+len-1. */ - written = cifs_user_writev(iocb, iov, nr_segs, pos); + written = cifs_user_writev(iocb, from); if (written > 0 && CIFS_CACHE_READ(cinode)) { /* * Windows 7 server can delay breaking level2 oplock if a write @@ -2831,32 +2826,25 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server, return total_read > 0 ? total_read : result; } -ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to) { struct file *file = iocb->ki_filp; ssize_t rc; size_t len, cur_len; ssize_t total_read = 0; - loff_t offset = pos; + loff_t offset = iocb->ki_pos; unsigned int npages; struct cifs_sb_info *cifs_sb; struct cifs_tcon *tcon; struct cifsFileInfo *open_file; struct cifs_readdata *rdata, *tmp; struct list_head rdata_list; - struct iov_iter to; pid_t pid; - if (!nr_segs) - return 0; - - len = iov_length(iov, nr_segs); + len = iov_iter_count(to); if (!len) return 0; - iov_iter_init(&to, iov, nr_segs, len, 0); - INIT_LIST_HEAD(&rdata_list); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); open_file = file->private_data; @@ -2914,7 +2902,7 @@ ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, if (!list_empty(&rdata_list)) rc = 0; - len = iov_iter_count(&to); + len = iov_iter_count(to); /* the loop below should proceed in the order of increasing offsets */ list_for_each_entry_safe(rdata, tmp, &rdata_list, list) { again: @@ -2931,7 +2919,7 @@ ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, goto again; } } else { - rc = cifs_readdata_to_iov(rdata, &to); + rc = cifs_readdata_to_iov(rdata, to); } } @@ -2939,7 +2927,7 @@ ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, kref_put(&rdata->refcount, cifs_uncached_readdata_release); } - total_read = len - iov_iter_count(&to); + total_read = len - iov_iter_count(to); cifs_stats_bytes_read(tcon, total_read); @@ -2948,15 +2936,14 @@ ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, rc = 0; if (total_read) { - iocb->ki_pos = pos + total_read; + iocb->ki_pos += total_read; return total_read; } return rc; } ssize_t -cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to) { struct inode *inode = file_inode(iocb->ki_filp); struct cifsInodeInfo *cinode = CIFS_I(inode); @@ -2975,22 +2962,22 @@ cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, * pos+len-1. */ if (!CIFS_CACHE_READ(cinode)) - return cifs_user_readv(iocb, iov, nr_segs, pos); + return cifs_user_readv(iocb, to); if (cap_unix(tcon->ses) && (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) - return generic_file_aio_read(iocb, iov, nr_segs, pos); + return generic_file_read_iter(iocb, to); /* * We need to hold the sem to be sure nobody modifies lock list * with a brlock that prevents reading. */ down_read(&cinode->lock_sem); - if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), + if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(to), tcon->ses->server->vals->shared_lock_type, NULL, CIFS_READ_OP)) - rc = generic_file_aio_read(iocb, iov, nr_segs, pos); + rc = generic_file_read_iter(iocb, to); up_read(&cinode->lock_sem); return rc; } @@ -3703,8 +3690,8 @@ void cifs_oplock_break(struct work_struct *work) * Direct IO is not yet supported in the cached mode. */ static ssize_t -cifs_direct_io(int rw, struct kiocb *iocb, const struct iovec *iov, - loff_t pos, unsigned long nr_segs) +cifs_direct_io(int rw, struct kiocb *iocb, struct iov_iter *iter, + loff_t pos) { /* * FIXME diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index aadc2b68678b7d..a22d667f1069e5 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1737,6 +1737,9 @@ cifs_inode_needs_reval(struct inode *inode) if (cifs_i->time == 0) return true; + if (!cifs_sb->actimeo) + return true; + if (!time_in_range(jiffies, cifs_i->time, cifs_i->time + cifs_sb->actimeo)) return true; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index b15862e0f68c3c..d0e9d0169b37e2 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -87,8 +87,6 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, return; if (dentry) { - int err; - inode = dentry->d_inode; if (inode) { /* @@ -105,10 +103,8 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, goto out; } } - err = d_invalidate(dentry); + d_invalidate(dentry); dput(dentry); - if (err) - return; } /* diff --git a/fs/dcache.c b/fs/dcache.c index 42ae01eefc0767..17010fd1cecd22 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -585,62 +585,6 @@ void dput(struct dentry *dentry) } EXPORT_SYMBOL(dput); -/** - * d_invalidate - invalidate a dentry - * @dentry: dentry to invalidate - * - * Try to invalidate the dentry if it turns out to be - * possible. If there are other dentries that can be - * reached through this one we can't delete it and we - * return -EBUSY. On success we return 0. - * - * no dcache lock. - */ - -int d_invalidate(struct dentry * dentry) -{ - /* - * If it's already been dropped, return OK. - */ - spin_lock(&dentry->d_lock); - if (d_unhashed(dentry)) { - spin_unlock(&dentry->d_lock); - return 0; - } - /* - * Check whether to do a partial shrink_dcache - * to get rid of unused child entries. - */ - if (!list_empty(&dentry->d_subdirs)) { - spin_unlock(&dentry->d_lock); - shrink_dcache_parent(dentry); - spin_lock(&dentry->d_lock); - } - - /* - * Somebody else still using it? - * - * If it's a directory, we can't drop it - * for fear of somebody re-populating it - * with children (even though dropping it - * would make it unreachable from the root, - * we might still populate it if it was a - * working directory or similar). - * We also need to leave mountpoints alone, - * directory or not. - */ - if (dentry->d_lockref.count > 1 && dentry->d_inode) { - if (S_ISDIR(dentry->d_inode->i_mode) || d_mountpoint(dentry)) { - spin_unlock(&dentry->d_lock); - return -EBUSY; - } - } - - __d_drop(dentry); - spin_unlock(&dentry->d_lock); - return 0; -} -EXPORT_SYMBOL(d_invalidate); /* This must be called with d_lock held */ static inline void __dget_dlock(struct dentry *dentry) @@ -703,7 +647,8 @@ EXPORT_SYMBOL(dget_parent); * acquire the reference to alias and return it. Otherwise return NULL. * Notice that if inode is a directory there can be only one alias and * it can be unhashed only if it has no children, or if it is the root - * of a filesystem. + * of a filesystem, or if the directory was renamed and d_revalidate + * was the first vfs operation to notice. * * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer * any other hashed alias over that one unless @want_discon is set, @@ -1137,7 +1082,7 @@ EXPORT_SYMBOL(have_submounts); * reachable (e.g. NFS can unhash a directory dentry and then the complete * subtree can become unreachable). * - * Only one of check_submounts_and_drop() and d_set_mounted() must succeed. For + * Only one of d_invalidate() and d_set_mounted() must succeed. For * this reason take rename_lock and d_lock on dentry and ancestors. */ int d_set_mounted(struct dentry *dentry) @@ -1146,7 +1091,7 @@ int d_set_mounted(struct dentry *dentry) int ret = -ENOENT; write_seqlock(&rename_lock); for (p = dentry->d_parent; !IS_ROOT(p); p = p->d_parent) { - /* Need exclusion wrt. check_submounts_and_drop() */ + /* Need exclusion wrt. d_invalidate() */ spin_lock(&p->d_lock); if (unlikely(d_unhashed(p))) { spin_unlock(&p->d_lock); @@ -1290,40 +1235,52 @@ void shrink_dcache_for_umount(struct super_block *sb) } } -static enum d_walk_ret check_and_collect(void *_data, struct dentry *dentry) +struct detach_data { + struct select_data select; + struct dentry *mountpoint; +}; +static enum d_walk_ret detach_and_collect(void *_data, struct dentry *dentry) { - struct select_data *data = _data; + struct detach_data *data = _data; if (d_mountpoint(dentry)) { - data->found = -EBUSY; + __dget_dlock(dentry); + data->mountpoint = dentry; return D_WALK_QUIT; } - return select_collect(_data, dentry); + return select_collect(&data->select, dentry); } static void check_and_drop(void *_data) { - struct select_data *data = _data; + struct detach_data *data = _data; - if (d_mountpoint(data->start)) - data->found = -EBUSY; - if (!data->found) - __d_drop(data->start); + if (!data->mountpoint && !data->select.found) + __d_drop(data->select.start); } /** - * check_submounts_and_drop - prune dcache, check for submounts and drop + * d_invalidate - detach submounts, prune dcache, and drop + * @dentry: dentry to invalidate (aka detach, prune and drop) * - * All done as a single atomic operation relative to has_unlinked_ancestor(). - * Returns 0 if successfully unhashed @parent. If there were submounts then - * return -EBUSY. + * no dcache lock. * - * @dentry: dentry to prune and drop + * The final d_drop is done as an atomic operation relative to + * rename_lock ensuring there are no races with d_set_mounted. This + * ensures there are no unhashed dentries on the path to a mountpoint. */ -int check_submounts_and_drop(struct dentry *dentry) +void d_invalidate(struct dentry *dentry) { - int ret = 0; + /* + * If it's already been dropped, return OK. + */ + spin_lock(&dentry->d_lock); + if (d_unhashed(dentry)) { + spin_unlock(&dentry->d_lock); + return; + } + spin_unlock(&dentry->d_lock); /* Negative dentries can be dropped without further checks */ if (!dentry->d_inode) { @@ -1332,28 +1289,33 @@ int check_submounts_and_drop(struct dentry *dentry) } for (;;) { - struct select_data data; + struct detach_data data; - INIT_LIST_HEAD(&data.dispose); - data.start = dentry; - data.found = 0; + data.mountpoint = NULL; + INIT_LIST_HEAD(&data.select.dispose); + data.select.start = dentry; + data.select.found = 0; + + d_walk(dentry, &data, detach_and_collect, check_and_drop); - d_walk(dentry, &data, check_and_collect, check_and_drop); - ret = data.found; + if (data.select.found) + shrink_dentry_list(&data.select.dispose); - if (!list_empty(&data.dispose)) - shrink_dentry_list(&data.dispose); + if (data.mountpoint) { + detach_mounts(data.mountpoint); + dput(data.mountpoint); + } - if (ret <= 0) + if (!data.mountpoint && !data.select.found) break; cond_resched(); } out: - return ret; + return; } -EXPORT_SYMBOL(check_submounts_and_drop); +EXPORT_SYMBOL(d_invalidate); /** * __d_alloc - allocate a dcache entry @@ -2587,10 +2549,8 @@ static struct dentry *__d_unalias(struct inode *inode, goto out_err; m2 = &alias->d_parent->d_inode->i_mutex; out_unalias: - if (likely(!d_mountpoint(alias))) { - __d_move(alias, dentry, false); - ret = alias; - } + __d_move(alias, dentry, false); + ret = alias; out_err: spin_unlock(&inode->i_lock); if (m2) diff --git a/fs/direct-io.c b/fs/direct-io.c index 31ba0935e32ed2..98040ba388ac1e 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -77,7 +77,6 @@ struct dio_submit { unsigned blocks_available; /* At block_in_file. changes */ int reap_counter; /* rate limit reaping */ sector_t final_block_in_request;/* doesn't change */ - unsigned first_block_in_page; /* doesn't change, Used only once */ int boundary; /* prev block is at a boundary */ get_block_t *get_block; /* block mapping function */ dio_submit_t *submit_io; /* IO submition function */ @@ -98,19 +97,14 @@ struct dio_submit { sector_t cur_page_block; /* Where it starts */ loff_t cur_page_fs_offset; /* Offset in file */ - /* - * Page fetching state. These variables belong to dio_refill_pages(). - */ - int curr_page; /* changes */ - int total_pages; /* doesn't change */ - unsigned long curr_user_address;/* changes */ - + struct iov_iter *iter; /* * Page queue. These variables belong to dio_refill_pages() and * dio_get_page(). */ unsigned head; /* next page to process */ unsigned tail; /* last valid page + 1 */ + size_t from, to; }; /* dio_state communicated between submission path and end_io */ @@ -163,15 +157,10 @@ static inline unsigned dio_pages_present(struct dio_submit *sdio) */ static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio) { - int ret; - int nr_pages; + ssize_t ret; - nr_pages = min(sdio->total_pages - sdio->curr_page, DIO_PAGES); - ret = get_user_pages_fast( - sdio->curr_user_address, /* Where from? */ - nr_pages, /* How many pages? */ - dio->rw == READ, /* Write to memory? */ - &dio->pages[0]); /* Put results here */ + ret = iov_iter_get_pages(sdio->iter, dio->pages, DIO_PAGES * PAGE_SIZE, + &sdio->from); if (ret < 0 && sdio->blocks_available && (dio->rw & WRITE)) { struct page *page = ZERO_PAGE(0); @@ -186,18 +175,19 @@ static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio) dio->pages[0] = page; sdio->head = 0; sdio->tail = 1; - ret = 0; - goto out; + sdio->from = 0; + sdio->to = PAGE_SIZE; + return 0; } if (ret >= 0) { - sdio->curr_user_address += ret * PAGE_SIZE; - sdio->curr_page += ret; + iov_iter_advance(sdio->iter, ret); + ret += sdio->from; sdio->head = 0; - sdio->tail = ret; - ret = 0; + sdio->tail = (ret + PAGE_SIZE - 1) / PAGE_SIZE; + sdio->to = ((ret - 1) & (PAGE_SIZE - 1)) + 1; + return 0; } -out: return ret; } @@ -208,8 +198,9 @@ static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio) * L1 cache. */ static inline struct page *dio_get_page(struct dio *dio, - struct dio_submit *sdio) + struct dio_submit *sdio, size_t *from, size_t *to) { + int n; if (dio_pages_present(sdio) == 0) { int ret; @@ -218,7 +209,10 @@ static inline struct page *dio_get_page(struct dio *dio, return ERR_PTR(ret); BUG_ON(dio_pages_present(sdio) == 0); } - return dio->pages[sdio->head++]; + n = sdio->head++; + *from = n ? 0 : sdio->from; + *to = (n == sdio->tail - 1) ? sdio->to : PAGE_SIZE; + return dio->pages[n]; } /** @@ -422,8 +416,8 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio) */ static inline void dio_cleanup(struct dio *dio, struct dio_submit *sdio) { - while (dio_pages_present(sdio)) - page_cache_release(dio_get_page(dio, sdio)); + while (sdio->head < sdio->tail) + page_cache_release(dio->pages[sdio->head++]); } /* @@ -912,23 +906,18 @@ static int do_direct_IO(struct dio *dio, struct dio_submit *sdio, struct buffer_head *map_bh) { const unsigned blkbits = sdio->blkbits; - const unsigned blocks_per_page = PAGE_SIZE >> blkbits; - struct page *page; - unsigned block_in_page; int ret = 0; - /* The I/O can start at any block offset within the first page */ - block_in_page = sdio->first_block_in_page; - while (sdio->block_in_file < sdio->final_block_in_request) { - page = dio_get_page(dio, sdio); + struct page *page; + size_t from, to; + page = dio_get_page(dio, sdio, &from, &to); if (IS_ERR(page)) { ret = PTR_ERR(page); goto out; } - while (block_in_page < blocks_per_page) { - unsigned offset_in_page = block_in_page << blkbits; + while (from < to) { unsigned this_chunk_bytes; /* # of bytes mapped */ unsigned this_chunk_blocks; /* # of blocks */ unsigned u; @@ -999,10 +988,10 @@ static int do_direct_IO(struct dio *dio, struct dio_submit *sdio, page_cache_release(page); goto out; } - zero_user(page, block_in_page << blkbits, - 1 << blkbits); + zero_user(page, from, 1 << blkbits); sdio->block_in_file++; - block_in_page++; + from += 1 << blkbits; + dio->result += 1 << blkbits; goto next_block; } @@ -1019,7 +1008,7 @@ static int do_direct_IO(struct dio *dio, struct dio_submit *sdio, * can add to this page */ this_chunk_blocks = sdio->blocks_available; - u = (PAGE_SIZE - offset_in_page) >> blkbits; + u = (to - from) >> blkbits; if (this_chunk_blocks > u) this_chunk_blocks = u; u = sdio->final_block_in_request - sdio->block_in_file; @@ -1031,7 +1020,7 @@ static int do_direct_IO(struct dio *dio, struct dio_submit *sdio, if (this_chunk_blocks == sdio->blocks_available) sdio->boundary = buffer_boundary(map_bh); ret = submit_page_section(dio, sdio, page, - offset_in_page, + from, this_chunk_bytes, sdio->next_block_for_io, map_bh); @@ -1042,7 +1031,8 @@ static int do_direct_IO(struct dio *dio, struct dio_submit *sdio, sdio->next_block_for_io += this_chunk_blocks; sdio->block_in_file += this_chunk_blocks; - block_in_page += this_chunk_blocks; + from += this_chunk_bytes; + dio->result += this_chunk_bytes; sdio->blocks_available -= this_chunk_blocks; next_block: BUG_ON(sdio->block_in_file > sdio->final_block_in_request); @@ -1052,7 +1042,6 @@ static int do_direct_IO(struct dio *dio, struct dio_submit *sdio, /* Drop the ref which was taken in get_user_pages() */ page_cache_release(page); - block_in_page = 0; } out: return ret; @@ -1107,24 +1096,20 @@ static inline int drop_refcount(struct dio *dio) */ static inline ssize_t do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, - struct block_device *bdev, const struct iovec *iov, loff_t offset, - unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io, + struct block_device *bdev, struct iov_iter *iter, loff_t offset, + get_block_t get_block, dio_iodone_t end_io, dio_submit_t submit_io, int flags) { - int seg; - size_t size; - unsigned long addr; unsigned i_blkbits = ACCESS_ONCE(inode->i_blkbits); unsigned blkbits = i_blkbits; unsigned blocksize_mask = (1 << blkbits) - 1; ssize_t retval = -EINVAL; - loff_t end = offset; + loff_t end = offset + iov_iter_count(iter); struct dio *dio; struct dio_submit sdio = { 0, }; - unsigned long user_addr; - size_t bytes; struct buffer_head map_bh = { 0, }; struct blk_plug plug; + unsigned long align = offset | iov_iter_alignment(iter); if (rw & WRITE) rw = WRITE_ODIRECT; @@ -1134,32 +1119,16 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, * the early prefetch in the caller enough time. */ - if (offset & blocksize_mask) { + if (align & blocksize_mask) { if (bdev) blkbits = blksize_bits(bdev_logical_block_size(bdev)); blocksize_mask = (1 << blkbits) - 1; - if (offset & blocksize_mask) + if (align & blocksize_mask) goto out; } - /* Check the memory alignment. Blocks cannot straddle pages */ - for (seg = 0; seg < nr_segs; seg++) { - addr = (unsigned long)iov[seg].iov_base; - size = iov[seg].iov_len; - end += size; - if (unlikely((addr & blocksize_mask) || - (size & blocksize_mask))) { - if (bdev) - blkbits = blksize_bits( - bdev_logical_block_size(bdev)); - blocksize_mask = (1 << blkbits) - 1; - if ((addr & blocksize_mask) || (size & blocksize_mask)) - goto out; - } - } - /* watch out for a 0 len io from a tricksy fs */ - if (rw == READ && end == offset) + if (rw == READ && !iov_iter_count(iter)) return 0; dio = kmem_cache_alloc(dio_cache, GFP_KERNEL); @@ -1249,6 +1218,10 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, spin_lock_init(&dio->bio_lock); dio->refcount = 1; + sdio.iter = iter; + sdio.final_block_in_request = + (offset + iov_iter_count(iter)) >> blkbits; + /* * In case of non-aligned buffers, we may need 2 more * pages since we need to zero out first and last block. @@ -1256,47 +1229,13 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, if (unlikely(sdio.blkfactor)) sdio.pages_in_io = 2; - for (seg = 0; seg < nr_segs; seg++) { - user_addr = (unsigned long)iov[seg].iov_base; - sdio.pages_in_io += - ((user_addr + iov[seg].iov_len + PAGE_SIZE-1) / - PAGE_SIZE - user_addr / PAGE_SIZE); - } + sdio.pages_in_io += iov_iter_npages(iter, INT_MAX); blk_start_plug(&plug); - for (seg = 0; seg < nr_segs; seg++) { - user_addr = (unsigned long)iov[seg].iov_base; - sdio.size += bytes = iov[seg].iov_len; - - /* Index into the first page of the first block */ - sdio.first_block_in_page = (user_addr & ~PAGE_MASK) >> blkbits; - sdio.final_block_in_request = sdio.block_in_file + - (bytes >> blkbits); - /* Page fetching state */ - sdio.head = 0; - sdio.tail = 0; - sdio.curr_page = 0; - - sdio.total_pages = 0; - if (user_addr & (PAGE_SIZE-1)) { - sdio.total_pages++; - bytes -= PAGE_SIZE - (user_addr & (PAGE_SIZE - 1)); - } - sdio.total_pages += (bytes + PAGE_SIZE - 1) / PAGE_SIZE; - sdio.curr_user_address = user_addr; - - retval = do_direct_IO(dio, &sdio, &map_bh); - - dio->result += iov[seg].iov_len - - ((sdio.final_block_in_request - sdio.block_in_file) << - blkbits); - - if (retval) { - dio_cleanup(dio, &sdio); - break; - } - } /* end iovec loop */ + retval = do_direct_IO(dio, &sdio, &map_bh); + if (retval) + dio_cleanup(dio, &sdio); if (retval == -ENOTBLK) { /* @@ -1365,8 +1304,8 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, - struct block_device *bdev, const struct iovec *iov, loff_t offset, - unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io, + struct block_device *bdev, struct iov_iter *iter, loff_t offset, + get_block_t get_block, dio_iodone_t end_io, dio_submit_t submit_io, int flags) { /* @@ -1381,9 +1320,8 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, prefetch(bdev->bd_queue); prefetch((char *)bdev->bd_queue + SMP_CACHE_BYTES); - return do_blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset, - nr_segs, get_block, end_io, - submit_io, flags); + return do_blockdev_direct_IO(rw, iocb, inode, bdev, iter, offset, + get_block, end_io, submit_io, flags); } EXPORT_SYMBOL(__blockdev_direct_IO); diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index b1eaa7a1f82cd0..b4b6ab9873ae42 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -45,14 +45,13 @@ * The function to be used for directory reads is ecryptfs_read. */ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, loff_t pos) + struct iov_iter *to) { ssize_t rc; struct path *path; struct file *file = iocb->ki_filp; - rc = generic_file_aio_read(iocb, iov, nr_segs, pos); + rc = generic_file_read_iter(iocb, to); /* * Even though this is a async interface, we need to wait * for IO to finish to update atime @@ -230,8 +229,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file) if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " - "[%s]; rc = [%d]\n", __func__, - ecryptfs_dentry->d_name.name, rc); + "[%pd]; rc = [%d]\n", __func__, + ecryptfs_dentry, rc); goto out_free; } if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE) @@ -352,10 +351,10 @@ const struct file_operations ecryptfs_dir_fops = { const struct file_operations ecryptfs_main_fops = { .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = ecryptfs_read_update_atime, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .read_iter = ecryptfs_read_update_atime, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .iterate = ecryptfs_readdir, .unlocked_ioctl = ecryptfs_unlocked_ioctl, #ifdef CONFIG_COMPAT diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index d4a9431ec73ce0..4d6c7e48828d5e 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -250,8 +250,8 @@ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " - "[%s]; rc = [%d]\n", __func__, - ecryptfs_dentry->d_name.name, rc); + "[%pd]; rc = [%d]\n", __func__, + ecryptfs_dentry, rc); goto out; } rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode); @@ -313,8 +313,8 @@ static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode) if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " - "[%s]; rc = [%d]\n", __func__, - dentry->d_name.name, rc); + "[%pd]; rc = [%d]\n", __func__, + dentry, rc); return rc; } @@ -418,8 +418,8 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " - "[%d] on lower_dentry = [%s]\n", __func__, rc, - ecryptfs_dentry->d_name.name); + "[%d] on lower_dentry = [%pd]\n", __func__, rc, + ecryptfs_dentry); goto out; } if (lower_dentry->d_inode) diff --git a/fs/exofs/file.c b/fs/exofs/file.c index 491c6c078e7f5e..71bf8e4fb5d427 100644 --- a/fs/exofs/file.c +++ b/fs/exofs/file.c @@ -67,17 +67,17 @@ static int exofs_flush(struct file *file, fl_owner_t id) const struct file_operations exofs_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .open = generic_file_open, .release = exofs_release_file, .fsync = exofs_file_fsync, .flush = exofs_flush, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, }; const struct inode_operations exofs_file_inode_operations = { diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index d1c244d676679c..3f9cafd739312b 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -964,7 +964,7 @@ static void exofs_invalidatepage(struct page *page, unsigned int offset, /* TODO: Should be easy enough to do proprly */ static ssize_t exofs_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { return 0; } diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 44c36e59076559..7c87b22a7228c4 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -62,10 +62,10 @@ int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync) */ const struct file_operations ext2_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .unlocked_ioctl = ext2_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext2_compat_ioctl, @@ -75,7 +75,7 @@ const struct file_operations ext2_file_operations = { .release = ext2_release_file, .fsync = ext2_fsync, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, }; #ifdef CONFIG_EXT2_FS_XIP diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index b1d2a4675d4280..36d35c36311d69 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -850,18 +850,18 @@ static sector_t ext2_bmap(struct address_space *mapping, sector_t block) } static ssize_t -ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, - loff_t offset, unsigned long nr_segs) +ext2_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; + size_t count = iov_iter_count(iter); ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - ext2_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, ext2_get_block); if (ret < 0 && (rw & WRITE)) - ext2_write_failed(mapping, offset + iov_length(iov, nr_segs)); + ext2_write_failed(mapping, offset + count); return ret; } diff --git a/fs/ext3/file.c b/fs/ext3/file.c index aad05311392a04..a062fa1e1b113e 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -50,10 +50,10 @@ static int ext3_release_file (struct inode * inode, struct file * filp) const struct file_operations ext3_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .unlocked_ioctl = ext3_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext3_compat_ioctl, @@ -63,7 +63,7 @@ const struct file_operations ext3_file_operations = { .release = ext3_release_file, .fsync = ext3_sync_file, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, }; const struct inode_operations ext3_file_inode_operations = { diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index f5157d0d1b4377..4d32133a76c4bb 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1820,8 +1820,7 @@ static int ext3_releasepage(struct page *page, gfp_t wait) * VFS code falls back into buffered path in that case so we are safe. */ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, - unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; @@ -1829,10 +1828,10 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, handle_t *handle; ssize_t ret; int orphan = 0; - size_t count = iov_length(iov, nr_segs); + size_t count = iov_iter_count(iter); int retries = 0; - trace_ext3_direct_IO_enter(inode, offset, iov_length(iov, nr_segs), rw); + trace_ext3_direct_IO_enter(inode, offset, count, rw); if (rw == WRITE) { loff_t final_size = offset + count; @@ -1856,15 +1855,14 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, } retry: - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - ext3_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, ext3_get_block); /* * In case of error extending write may have instantiated a few * blocks outside i_size. Trim these off again. */ if (unlikely((rw & WRITE) && ret < 0)) { loff_t isize = i_size_read(inode); - loff_t end = offset + iov_length(iov, nr_segs); + loff_t end = offset + count; if (end > isize) ext3_truncate_failed_direct_write(inode); @@ -1909,8 +1907,7 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, ret = err; } out: - trace_ext3_direct_IO_exit(inode, offset, - iov_length(iov, nr_segs), rw, ret); + trace_ext3_direct_IO_exit(inode, offset, count, rw, ret); return ret; } diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 66946aa6212707..6b45afa4961003 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -158,7 +158,6 @@ struct ext4_allocation_request { #define EXT4_MAP_MAPPED (1 << BH_Mapped) #define EXT4_MAP_UNWRITTEN (1 << BH_Unwritten) #define EXT4_MAP_BOUNDARY (1 << BH_Boundary) -#define EXT4_MAP_UNINIT (1 << BH_Uninit) /* Sometimes (in the bigalloc case, from ext4_da_get_block_prep) the caller of * ext4_map_blocks wants to know whether or not the underlying cluster has * already been accounted for. EXT4_MAP_FROM_CLUSTER conveys to the caller that @@ -169,7 +168,7 @@ struct ext4_allocation_request { #define EXT4_MAP_FROM_CLUSTER (1 << BH_AllocFromCluster) #define EXT4_MAP_FLAGS (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\ EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY |\ - EXT4_MAP_UNINIT | EXT4_MAP_FROM_CLUSTER) + EXT4_MAP_FROM_CLUSTER) struct ext4_map_blocks { ext4_fsblk_t m_pblk; @@ -184,7 +183,7 @@ struct ext4_map_blocks { #define EXT4_IO_END_UNWRITTEN 0x0001 /* - * For converting uninitialized extents on a work queue. 'handle' is used for + * For converting unwritten extents on a work queue. 'handle' is used for * buffered writeback. */ typedef struct ext4_io_end { @@ -537,26 +536,26 @@ enum { /* * Flags used by ext4_map_blocks() */ - /* Allocate any needed blocks and/or convert an unitialized + /* Allocate any needed blocks and/or convert an unwritten extent to be an initialized ext4 */ #define EXT4_GET_BLOCKS_CREATE 0x0001 - /* Request the creation of an unitialized extent */ -#define EXT4_GET_BLOCKS_UNINIT_EXT 0x0002 -#define EXT4_GET_BLOCKS_CREATE_UNINIT_EXT (EXT4_GET_BLOCKS_UNINIT_EXT|\ + /* Request the creation of an unwritten extent */ +#define EXT4_GET_BLOCKS_UNWRIT_EXT 0x0002 +#define EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT (EXT4_GET_BLOCKS_UNWRIT_EXT|\ EXT4_GET_BLOCKS_CREATE) /* Caller is from the delayed allocation writeout path * finally doing the actual allocation of delayed blocks */ #define EXT4_GET_BLOCKS_DELALLOC_RESERVE 0x0004 /* caller is from the direct IO path, request to creation of an - unitialized extents if not allocated, split the uninitialized + unwritten extents if not allocated, split the unwritten extent if blocks has been preallocated already*/ #define EXT4_GET_BLOCKS_PRE_IO 0x0008 #define EXT4_GET_BLOCKS_CONVERT 0x0010 #define EXT4_GET_BLOCKS_IO_CREATE_EXT (EXT4_GET_BLOCKS_PRE_IO|\ - EXT4_GET_BLOCKS_CREATE_UNINIT_EXT) + EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT) /* Convert extent to initialized after IO complete */ #define EXT4_GET_BLOCKS_IO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\ - EXT4_GET_BLOCKS_CREATE_UNINIT_EXT) + EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT) /* Eventual metadata allocation (due to growing extent tree) * should not fail, so try to use reserved blocks for that.*/ #define EXT4_GET_BLOCKS_METADATA_NOFAIL 0x0020 @@ -876,6 +875,8 @@ struct ext4_inode_info { struct inode vfs_inode; struct jbd2_inode *jinode; + spinlock_t i_raw_lock; /* protects updates to the raw inode */ + /* * File creation time. Its function is same as that of * struct timespec i_{a,c,m}time in the generic inode. @@ -2150,8 +2151,7 @@ extern void ext4_da_update_reserve_space(struct inode *inode, extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, int flags); extern ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, - unsigned long nr_segs); + struct iov_iter *iter, loff_t offset); extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock); extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks); extern void ext4_ind_truncate(handle_t *, struct inode *inode); @@ -2784,10 +2784,9 @@ extern int ext4_mmp_csum_verify(struct super_block *sb, * See EXT4_MAP_... to see where this is used. */ enum ext4_state_bits { - BH_Uninit /* blocks are allocated but uninitialized on disk */ - = BH_JBDPrivateStart, - BH_AllocFromCluster, /* allocated blocks were part of already + BH_AllocFromCluster /* allocated blocks were part of already * allocated cluster. */ + = BH_JBDPrivateStart }; /* diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index 5074fe23f19e5a..a867f5ca99919d 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h @@ -137,21 +137,21 @@ struct ext4_ext_path { * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an * initialized extent. This is 2^15 and not (2^16 - 1), since we use the * MSB of ee_len field in the extent datastructure to signify if this - * particular extent is an initialized extent or an uninitialized (i.e. + * particular extent is an initialized extent or an unwritten (i.e. * preallocated). - * EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an - * uninitialized extent. + * EXT_UNWRITTEN_MAX_LEN is the maximum number of blocks we can have in an + * unwritten extent. * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an - * uninitialized one. In other words, if MSB of ee_len is set, it is an - * uninitialized extent with only one special scenario when ee_len = 0x8000. - * In this case we can not have an uninitialized extent of zero length and + * unwritten one. In other words, if MSB of ee_len is set, it is an + * unwritten extent with only one special scenario when ee_len = 0x8000. + * In this case we can not have an unwritten extent of zero length and * thus we make it as a special case of initialized extent with 0x8000 length. * This way we get better extent-to-group alignment for initialized extents. * Hence, the maximum number of blocks we can have in an *initialized* - * extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767). + * extent is 2^15 (32768) and in an *unwritten* extent is 2^15-1 (32767). */ #define EXT_INIT_MAX_LEN (1UL << 15) -#define EXT_UNINIT_MAX_LEN (EXT_INIT_MAX_LEN - 1) +#define EXT_UNWRITTEN_MAX_LEN (EXT_INIT_MAX_LEN - 1) #define EXT_FIRST_EXTENT(__hdr__) \ @@ -187,14 +187,14 @@ static inline unsigned short ext_depth(struct inode *inode) return le16_to_cpu(ext_inode_hdr(inode)->eh_depth); } -static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext) +static inline void ext4_ext_mark_unwritten(struct ext4_extent *ext) { - /* We can not have an uninitialized extent of zero length! */ + /* We can not have an unwritten extent of zero length! */ BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0); ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN); } -static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext) +static inline int ext4_ext_is_unwritten(struct ext4_extent *ext) { /* Extent with ee_len of 0x8000 is treated as an initialized extent */ return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN); diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 01b0c208f62507..086baa9b5983f5 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -29,6 +29,7 @@ * - smart tree reduction */ +#include #include #include #include @@ -50,8 +51,8 @@ */ #define EXT4_EXT_MAY_ZEROOUT 0x1 /* safe to zeroout if split fails \ due to ENOSPC */ -#define EXT4_EXT_MARK_UNINIT1 0x2 /* mark first half uninitialized */ -#define EXT4_EXT_MARK_UNINIT2 0x4 /* mark second half uninitialized */ +#define EXT4_EXT_MARK_UNWRIT1 0x2 /* mark first half unwritten */ +#define EXT4_EXT_MARK_UNWRIT2 0x4 /* mark second half unwritten */ #define EXT4_EXT_DATA_VALID1 0x8 /* first half contains valid data */ #define EXT4_EXT_DATA_VALID2 0x10 /* second half contains valid data */ @@ -524,7 +525,7 @@ __read_extent_tree_block(const char *function, unsigned int line, lblk - prev, ~0, EXTENT_STATUS_HOLE); - if (ext4_ext_is_uninitialized(ex)) + if (ext4_ext_is_unwritten(ex)) status = EXTENT_STATUS_UNWRITTEN; ext4_es_cache_extent(inode, lblk, len, ext4_ext_pblock(ex), status); @@ -620,7 +621,7 @@ static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) } else if (path->p_ext) { ext_debug(" %d:[%d]%d:%llu ", le32_to_cpu(path->p_ext->ee_block), - ext4_ext_is_uninitialized(path->p_ext), + ext4_ext_is_unwritten(path->p_ext), ext4_ext_get_actual_len(path->p_ext), ext4_ext_pblock(path->p_ext)); } else @@ -646,7 +647,7 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path) for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) { ext_debug("%d:[%d]%d:%llu ", le32_to_cpu(ex->ee_block), - ext4_ext_is_uninitialized(ex), + ext4_ext_is_unwritten(ex), ext4_ext_get_actual_len(ex), ext4_ext_pblock(ex)); } ext_debug("\n"); @@ -677,7 +678,7 @@ static void ext4_ext_show_move(struct inode *inode, struct ext4_ext_path *path, ext_debug("move %d:%llu:[%d]%d in new leaf %llu\n", le32_to_cpu(ex->ee_block), ext4_ext_pblock(ex), - ext4_ext_is_uninitialized(ex), + ext4_ext_is_unwritten(ex), ext4_ext_get_actual_len(ex), newblock); ex++; @@ -802,7 +803,7 @@ ext4_ext_binsearch(struct inode *inode, ext_debug(" -> %d:%llu:[%d]%d ", le32_to_cpu(path->p_ext->ee_block), ext4_ext_pblock(path->p_ext), - ext4_ext_is_uninitialized(path->p_ext), + ext4_ext_is_unwritten(path->p_ext), ext4_ext_get_actual_len(path->p_ext)); #ifdef CHECK_BINSEARCH @@ -1686,11 +1687,11 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, /* * Make sure that both extents are initialized. We don't merge - * uninitialized extents so that we can be sure that end_io code has + * unwritten extents so that we can be sure that end_io code has * the extent that was written properly split out and conversion to * initialized is trivial. */ - if (ext4_ext_is_uninitialized(ex1) != ext4_ext_is_uninitialized(ex2)) + if (ext4_ext_is_unwritten(ex1) != ext4_ext_is_unwritten(ex2)) return 0; ext1_ee_len = ext4_ext_get_actual_len(ex1); @@ -1707,10 +1708,10 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, */ if (ext1_ee_len + ext2_ee_len > EXT_INIT_MAX_LEN) return 0; - if (ext4_ext_is_uninitialized(ex1) && + if (ext4_ext_is_unwritten(ex1) && (ext4_test_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN) || atomic_read(&EXT4_I(inode)->i_unwritten) || - (ext1_ee_len + ext2_ee_len > EXT_UNINIT_MAX_LEN))) + (ext1_ee_len + ext2_ee_len > EXT_UNWRITTEN_MAX_LEN))) return 0; #ifdef AGGRESSIVE_TEST if (ext1_ee_len >= 4) @@ -1735,7 +1736,7 @@ static int ext4_ext_try_to_merge_right(struct inode *inode, { struct ext4_extent_header *eh; unsigned int depth, len; - int merge_done = 0, uninit; + int merge_done = 0, unwritten; depth = ext_depth(inode); BUG_ON(path[depth].p_hdr == NULL); @@ -1745,11 +1746,11 @@ static int ext4_ext_try_to_merge_right(struct inode *inode, if (!ext4_can_extents_be_merged(inode, ex, ex + 1)) break; /* merge with next extent! */ - uninit = ext4_ext_is_uninitialized(ex); + unwritten = ext4_ext_is_unwritten(ex); ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) + ext4_ext_get_actual_len(ex + 1)); - if (uninit) - ext4_ext_mark_uninitialized(ex); + if (unwritten) + ext4_ext_mark_unwritten(ex); if (ex + 1 < EXT_LAST_EXTENT(eh)) { len = (EXT_LAST_EXTENT(eh) - ex - 1) @@ -1903,7 +1904,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, struct ext4_ext_path *npath = NULL; int depth, len, err; ext4_lblk_t next; - int mb_flags = 0, uninit; + int mb_flags = 0, unwritten; if (unlikely(ext4_ext_get_actual_len(newext) == 0)) { EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0"); @@ -1943,21 +1944,21 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, if (ext4_can_extents_be_merged(inode, ex, newext)) { ext_debug("append [%d]%d block to %u:[%d]%d" "(from %llu)\n", - ext4_ext_is_uninitialized(newext), + ext4_ext_is_unwritten(newext), ext4_ext_get_actual_len(newext), le32_to_cpu(ex->ee_block), - ext4_ext_is_uninitialized(ex), + ext4_ext_is_unwritten(ex), ext4_ext_get_actual_len(ex), ext4_ext_pblock(ex)); err = ext4_ext_get_access(handle, inode, path + depth); if (err) return err; - uninit = ext4_ext_is_uninitialized(ex); + unwritten = ext4_ext_is_unwritten(ex); ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) + ext4_ext_get_actual_len(newext)); - if (uninit) - ext4_ext_mark_uninitialized(ex); + if (unwritten) + ext4_ext_mark_unwritten(ex); eh = path[depth].p_hdr; nearex = ex; goto merge; @@ -1969,10 +1970,10 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, ext_debug("prepend %u[%d]%d block to %u:[%d]%d" "(from %llu)\n", le32_to_cpu(newext->ee_block), - ext4_ext_is_uninitialized(newext), + ext4_ext_is_unwritten(newext), ext4_ext_get_actual_len(newext), le32_to_cpu(ex->ee_block), - ext4_ext_is_uninitialized(ex), + ext4_ext_is_unwritten(ex), ext4_ext_get_actual_len(ex), ext4_ext_pblock(ex)); err = ext4_ext_get_access(handle, inode, @@ -1980,13 +1981,13 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, if (err) return err; - uninit = ext4_ext_is_uninitialized(ex); + unwritten = ext4_ext_is_unwritten(ex); ex->ee_block = newext->ee_block; ext4_ext_store_pblock(ex, ext4_ext_pblock(newext)); ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) + ext4_ext_get_actual_len(newext)); - if (uninit) - ext4_ext_mark_uninitialized(ex); + if (unwritten) + ext4_ext_mark_unwritten(ex); eh = path[depth].p_hdr; nearex = ex; goto merge; @@ -2046,7 +2047,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, ext_debug("first extent in the leaf: %u:%llu:[%d]%d\n", le32_to_cpu(newext->ee_block), ext4_ext_pblock(newext), - ext4_ext_is_uninitialized(newext), + ext4_ext_is_unwritten(newext), ext4_ext_get_actual_len(newext)); nearex = EXT_FIRST_EXTENT(eh); } else { @@ -2057,7 +2058,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, "nearest %p\n", le32_to_cpu(newext->ee_block), ext4_ext_pblock(newext), - ext4_ext_is_uninitialized(newext), + ext4_ext_is_unwritten(newext), ext4_ext_get_actual_len(newext), nearex); nearex++; @@ -2068,7 +2069,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, "nearest %p\n", le32_to_cpu(newext->ee_block), ext4_ext_pblock(newext), - ext4_ext_is_uninitialized(newext), + ext4_ext_is_unwritten(newext), ext4_ext_get_actual_len(newext), nearex); } @@ -2078,7 +2079,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, "move %d extents from 0x%p to 0x%p\n", le32_to_cpu(newext->ee_block), ext4_ext_pblock(newext), - ext4_ext_is_uninitialized(newext), + ext4_ext_is_unwritten(newext), ext4_ext_get_actual_len(newext), len, nearex, nearex + 1); memmove(nearex + 1, nearex, @@ -2200,7 +2201,7 @@ static int ext4_fill_fiemap_extents(struct inode *inode, es.es_lblk = le32_to_cpu(ex->ee_block); es.es_len = ext4_ext_get_actual_len(ex); es.es_pblk = ext4_ext_pblock(ex); - if (ext4_ext_is_uninitialized(ex)) + if (ext4_ext_is_unwritten(ex)) flags |= FIEMAP_EXTENT_UNWRITTEN; } @@ -2576,7 +2577,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, unsigned num; ext4_lblk_t ex_ee_block; unsigned short ex_ee_len; - unsigned uninitialized = 0; + unsigned unwritten = 0; struct ext4_extent *ex; ext4_fsblk_t pblk; @@ -2623,13 +2624,13 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, while (ex >= EXT_FIRST_EXTENT(eh) && ex_ee_block + ex_ee_len > start) { - if (ext4_ext_is_uninitialized(ex)) - uninitialized = 1; + if (ext4_ext_is_unwritten(ex)) + unwritten = 1; else - uninitialized = 0; + unwritten = 0; ext_debug("remove ext %u:[%d]%d\n", ex_ee_block, - uninitialized, ex_ee_len); + unwritten, ex_ee_len); path[depth].p_ext = ex; a = ex_ee_block > start ? ex_ee_block : start; @@ -2701,11 +2702,11 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, ex->ee_len = cpu_to_le16(num); /* - * Do not mark uninitialized if all the blocks in the + * Do not mark unwritten if all the blocks in the * extent have been removed. */ - if (uninitialized && num) - ext4_ext_mark_uninitialized(ex); + if (unwritten && num) + ext4_ext_mark_unwritten(ex); /* * If the extent was completely released, * we need to remove it from the leaf @@ -2854,9 +2855,9 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, end < ee_block + ext4_ext_get_actual_len(ex) - 1) { int split_flag = 0; - if (ext4_ext_is_uninitialized(ex)) - split_flag = EXT4_EXT_MARK_UNINIT1 | - EXT4_EXT_MARK_UNINIT2; + if (ext4_ext_is_unwritten(ex)) + split_flag = EXT4_EXT_MARK_UNWRIT1 | + EXT4_EXT_MARK_UNWRIT2; /* * Split the extent in two so that 'end' is the last @@ -3113,7 +3114,7 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex) * @path: the path to the extent * @split: the logical block where the extent is splitted. * @split_flags: indicates if the extent could be zeroout if split fails, and - * the states(init or uninit) of new extents. + * the states(init or unwritten) of new extents. * @flags: flags used to insert new extent to extent tree. * * @@ -3155,10 +3156,10 @@ static int ext4_split_extent_at(handle_t *handle, newblock = split - ee_block + ext4_ext_pblock(ex); BUG_ON(split < ee_block || split >= (ee_block + ee_len)); - BUG_ON(!ext4_ext_is_uninitialized(ex) && + BUG_ON(!ext4_ext_is_unwritten(ex) && split_flag & (EXT4_EXT_MAY_ZEROOUT | - EXT4_EXT_MARK_UNINIT1 | - EXT4_EXT_MARK_UNINIT2)); + EXT4_EXT_MARK_UNWRIT1 | + EXT4_EXT_MARK_UNWRIT2)); err = ext4_ext_get_access(handle, inode, path + depth); if (err) @@ -3170,8 +3171,8 @@ static int ext4_split_extent_at(handle_t *handle, * then we just change the state of the extent, and splitting * is not needed. */ - if (split_flag & EXT4_EXT_MARK_UNINIT2) - ext4_ext_mark_uninitialized(ex); + if (split_flag & EXT4_EXT_MARK_UNWRIT2) + ext4_ext_mark_unwritten(ex); else ext4_ext_mark_initialized(ex); @@ -3185,8 +3186,8 @@ static int ext4_split_extent_at(handle_t *handle, /* case a */ memcpy(&orig_ex, ex, sizeof(orig_ex)); ex->ee_len = cpu_to_le16(split - ee_block); - if (split_flag & EXT4_EXT_MARK_UNINIT1) - ext4_ext_mark_uninitialized(ex); + if (split_flag & EXT4_EXT_MARK_UNWRIT1) + ext4_ext_mark_unwritten(ex); /* * path may lead to new leaf, not to original leaf any more @@ -3200,8 +3201,8 @@ static int ext4_split_extent_at(handle_t *handle, ex2->ee_block = cpu_to_le32(split); ex2->ee_len = cpu_to_le16(ee_len - (split - ee_block)); ext4_ext_store_pblock(ex2, newblock); - if (split_flag & EXT4_EXT_MARK_UNINIT2) - ext4_ext_mark_uninitialized(ex2); + if (split_flag & EXT4_EXT_MARK_UNWRIT2) + ext4_ext_mark_unwritten(ex2); err = ext4_ext_insert_extent(handle, inode, path, &newex, flags); if (err == -ENOSPC && (EXT4_EXT_MAY_ZEROOUT & split_flag)) { @@ -3278,7 +3279,7 @@ static int ext4_split_extent(handle_t *handle, struct ext4_extent *ex; unsigned int ee_len, depth; int err = 0; - int uninitialized; + int unwritten; int split_flag1, flags1; int allocated = map->m_len; @@ -3286,14 +3287,14 @@ static int ext4_split_extent(handle_t *handle, ex = path[depth].p_ext; ee_block = le32_to_cpu(ex->ee_block); ee_len = ext4_ext_get_actual_len(ex); - uninitialized = ext4_ext_is_uninitialized(ex); + unwritten = ext4_ext_is_unwritten(ex); if (map->m_lblk + map->m_len < ee_block + ee_len) { split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT; flags1 = flags | EXT4_GET_BLOCKS_PRE_IO; - if (uninitialized) - split_flag1 |= EXT4_EXT_MARK_UNINIT1 | - EXT4_EXT_MARK_UNINIT2; + if (unwritten) + split_flag1 |= EXT4_EXT_MARK_UNWRIT1 | + EXT4_EXT_MARK_UNWRIT2; if (split_flag & EXT4_EXT_DATA_VALID2) split_flag1 |= EXT4_EXT_DATA_VALID1; err = ext4_split_extent_at(handle, inode, path, @@ -3318,15 +3319,15 @@ static int ext4_split_extent(handle_t *handle, (unsigned long) map->m_lblk); return -EIO; } - uninitialized = ext4_ext_is_uninitialized(ex); + unwritten = ext4_ext_is_unwritten(ex); split_flag1 = 0; if (map->m_lblk >= ee_block) { split_flag1 = split_flag & EXT4_EXT_DATA_VALID2; - if (uninitialized) { - split_flag1 |= EXT4_EXT_MARK_UNINIT1; + if (unwritten) { + split_flag1 |= EXT4_EXT_MARK_UNWRIT1; split_flag1 |= split_flag & (EXT4_EXT_MAY_ZEROOUT | - EXT4_EXT_MARK_UNINIT2); + EXT4_EXT_MARK_UNWRIT2); } err = ext4_split_extent_at(handle, inode, path, map->m_lblk, split_flag1, flags); @@ -3341,16 +3342,16 @@ static int ext4_split_extent(handle_t *handle, /* * This function is called by ext4_ext_map_blocks() if someone tries to write - * to an uninitialized extent. It may result in splitting the uninitialized + * to an unwritten extent. It may result in splitting the unwritten * extent into multiple extents (up to three - one initialized and two - * uninitialized). + * unwritten). * There are three possibilities: * a> There is no split required: Entire extent should be initialized * b> Splits in two extents: Write is happening at either end of the extent * c> Splits in three extents: Somone is writing in middle of the extent * * Pre-conditions: - * - The extent pointed to by 'path' is uninitialized. + * - The extent pointed to by 'path' is unwritten. * - The extent pointed to by 'path' contains a superset * of the logical span [map->m_lblk, map->m_lblk + map->m_len). * @@ -3396,12 +3397,12 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, trace_ext4_ext_convert_to_initialized_enter(inode, map, ex); /* Pre-conditions */ - BUG_ON(!ext4_ext_is_uninitialized(ex)); + BUG_ON(!ext4_ext_is_unwritten(ex)); BUG_ON(!in_range(map->m_lblk, ee_block, ee_len)); /* * Attempt to transfer newly initialized blocks from the currently - * uninitialized extent to its neighbor. This is much cheaper + * unwritten extent to its neighbor. This is much cheaper * than an insertion followed by a merge as those involve costly * memmove() calls. Transferring to the left is the common case in * steady state for workloads doing fallocate(FALLOC_FL_KEEP_SIZE) @@ -3437,7 +3438,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, * - C4: abut_ex can receive the additional blocks without * overflowing the (initialized) length limit. */ - if ((!ext4_ext_is_uninitialized(abut_ex)) && /*C1*/ + if ((!ext4_ext_is_unwritten(abut_ex)) && /*C1*/ ((prev_lblk + prev_len) == ee_block) && /*C2*/ ((prev_pblk + prev_len) == ee_pblk) && /*C3*/ (prev_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/ @@ -3452,7 +3453,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, ex->ee_block = cpu_to_le32(ee_block + map_len); ext4_ext_store_pblock(ex, ee_pblk + map_len); ex->ee_len = cpu_to_le16(ee_len - map_len); - ext4_ext_mark_uninitialized(ex); /* Restore the flag */ + ext4_ext_mark_unwritten(ex); /* Restore the flag */ /* Extend abut_ex by 'map_len' blocks */ abut_ex->ee_len = cpu_to_le16(prev_len + map_len); @@ -3483,7 +3484,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, * - C4: abut_ex can receive the additional blocks without * overflowing the (initialized) length limit. */ - if ((!ext4_ext_is_uninitialized(abut_ex)) && /*C1*/ + if ((!ext4_ext_is_unwritten(abut_ex)) && /*C1*/ ((map->m_lblk + map_len) == next_lblk) && /*C2*/ ((ee_pblk + ee_len) == next_pblk) && /*C3*/ (next_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/ @@ -3498,7 +3499,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, abut_ex->ee_block = cpu_to_le32(next_lblk - map_len); ext4_ext_store_pblock(abut_ex, next_pblk - map_len); ex->ee_len = cpu_to_le16(ee_len - map_len); - ext4_ext_mark_uninitialized(ex); /* Restore the flag */ + ext4_ext_mark_unwritten(ex); /* Restore the flag */ /* Extend abut_ex by 'map_len' blocks */ abut_ex->ee_len = cpu_to_le16(next_len + map_len); @@ -3603,26 +3604,26 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, /* * This function is called by ext4_ext_map_blocks() from * ext4_get_blocks_dio_write() when DIO to write - * to an uninitialized extent. + * to an unwritten extent. * - * Writing to an uninitialized extent may result in splitting the uninitialized - * extent into multiple initialized/uninitialized extents (up to three) + * Writing to an unwritten extent may result in splitting the unwritten + * extent into multiple initialized/unwritten extents (up to three) * There are three possibilities: - * a> There is no split required: Entire extent should be uninitialized + * a> There is no split required: Entire extent should be unwritten * b> Splits in two extents: Write is happening at either end of the extent * c> Splits in three extents: Somone is writing in middle of the extent * * This works the same way in the case of initialized -> unwritten conversion. * * One of more index blocks maybe needed if the extent tree grow after - * the uninitialized extent split. To prevent ENOSPC occur at the IO - * complete, we need to split the uninitialized extent before DIO submit - * the IO. The uninitialized extent called at this time will be split - * into three uninitialized extent(at most). After IO complete, the part + * the unwritten extent split. To prevent ENOSPC occur at the IO + * complete, we need to split the unwritten extent before DIO submit + * the IO. The unwritten extent called at this time will be split + * into three unwritten extent(at most). After IO complete, the part * being filled will be convert to initialized by the end_io callback function * via ext4_convert_unwritten_extents(). * - * Returns the size of uninitialized extent to be written on success. + * Returns the size of unwritten extent to be written on success. */ static int ext4_split_convert_extents(handle_t *handle, struct inode *inode, @@ -3660,7 +3661,7 @@ static int ext4_split_convert_extents(handle_t *handle, } else if (flags & EXT4_GET_BLOCKS_CONVERT) { split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0; - split_flag |= (EXT4_EXT_MARK_UNINIT2 | EXT4_EXT_DATA_VALID2); + split_flag |= (EXT4_EXT_MARK_UNWRIT2 | EXT4_EXT_DATA_VALID2); } flags |= EXT4_GET_BLOCKS_PRE_IO; return ext4_split_extent(handle, inode, path, map, split_flag, flags); @@ -3710,8 +3711,8 @@ static int ext4_convert_initialized_extents(handle_t *handle, err = ext4_ext_get_access(handle, inode, path + depth); if (err) goto out; - /* first mark the extent as uninitialized */ - ext4_ext_mark_uninitialized(ex); + /* first mark the extent as unwritten */ + ext4_ext_mark_unwritten(ex); /* note: ext4_ext_correct_indexes() isn't needed here because * borders are not changed @@ -3971,10 +3972,10 @@ ext4_ext_convert_initialized_extent(handle_t *handle, struct inode *inode, /* * Make sure that the extent is no bigger than we support with - * uninitialized extent + * unwritten extent */ - if (map->m_len > EXT_UNINIT_MAX_LEN) - map->m_len = EXT_UNINIT_MAX_LEN / 2; + if (map->m_len > EXT_UNWRITTEN_MAX_LEN) + map->m_len = EXT_UNWRITTEN_MAX_LEN / 2; ret = ext4_convert_initialized_extents(handle, inode, map, path); @@ -3993,7 +3994,7 @@ ext4_ext_convert_initialized_extent(handle_t *handle, struct inode *inode, } static int -ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, +ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, struct ext4_ext_path *path, int flags, unsigned int allocated, ext4_fsblk_t newblock) @@ -4002,19 +4003,19 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, int err = 0; ext4_io_end_t *io = ext4_inode_aio(inode); - ext_debug("ext4_ext_handle_uninitialized_extents: inode %lu, logical " + ext_debug("ext4_ext_handle_unwritten_extents: inode %lu, logical " "block %llu, max_blocks %u, flags %x, allocated %u\n", inode->i_ino, (unsigned long long)map->m_lblk, map->m_len, flags, allocated); ext4_ext_show_leaf(inode, path); /* - * When writing into uninitialized space, we should not fail to + * When writing into unwritten space, we should not fail to * allocate metadata blocks for the new extent block if needed. */ flags |= EXT4_GET_BLOCKS_METADATA_NOFAIL; - trace_ext4_ext_handle_uninitialized_extents(inode, map, flags, + trace_ext4_ext_handle_unwritten_extents(inode, map, flags, allocated, newblock); /* get_block() before submit the IO, split the extent */ @@ -4033,8 +4034,6 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, else ext4_set_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN); map->m_flags |= EXT4_MAP_UNWRITTEN; - if (ext4_should_dioread_nolock(inode)) - map->m_flags |= EXT4_MAP_UNINIT; goto out; } /* IO end_io complete, convert the filled extent to written */ @@ -4059,7 +4058,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, * repeat fallocate creation request * we already have an unwritten extent */ - if (flags & EXT4_GET_BLOCKS_UNINIT_EXT) { + if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT) { map->m_flags |= EXT4_MAP_UNWRITTEN; goto map_out; } @@ -4310,7 +4309,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, /* - * Uninitialized extents are treated as holes, except that + * unwritten extents are treated as holes, except that * we split out initialized portions during a write. */ ee_len = ext4_ext_get_actual_len(ex); @@ -4329,16 +4328,16 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, * If the extent is initialized check whether the * caller wants to convert it to unwritten. */ - if ((!ext4_ext_is_uninitialized(ex)) && + if ((!ext4_ext_is_unwritten(ex)) && (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) { allocated = ext4_ext_convert_initialized_extent( handle, inode, map, path, flags, allocated, newblock); goto out2; - } else if (!ext4_ext_is_uninitialized(ex)) + } else if (!ext4_ext_is_unwritten(ex)) goto out; - ret = ext4_ext_handle_uninitialized_extents( + ret = ext4_ext_handle_unwritten_extents( handle, inode, map, path, flags, allocated, newblock); if (ret < 0) @@ -4410,15 +4409,15 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, /* * See if request is beyond maximum number of blocks we can have in * a single extent. For an initialized extent this limit is - * EXT_INIT_MAX_LEN and for an uninitialized extent this limit is - * EXT_UNINIT_MAX_LEN. + * EXT_INIT_MAX_LEN and for an unwritten extent this limit is + * EXT_UNWRITTEN_MAX_LEN. */ if (map->m_len > EXT_INIT_MAX_LEN && - !(flags & EXT4_GET_BLOCKS_UNINIT_EXT)) + !(flags & EXT4_GET_BLOCKS_UNWRIT_EXT)) map->m_len = EXT_INIT_MAX_LEN; - else if (map->m_len > EXT_UNINIT_MAX_LEN && - (flags & EXT4_GET_BLOCKS_UNINIT_EXT)) - map->m_len = EXT_UNINIT_MAX_LEN; + else if (map->m_len > EXT_UNWRITTEN_MAX_LEN && + (flags & EXT4_GET_BLOCKS_UNWRIT_EXT)) + map->m_len = EXT_UNWRITTEN_MAX_LEN; /* Check if we can really insert (m_lblk)::(m_lblk + m_len) extent */ newex.ee_len = cpu_to_le16(map->m_len); @@ -4466,21 +4465,19 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, /* try to insert new extent into found leaf and return */ ext4_ext_store_pblock(&newex, newblock + offset); newex.ee_len = cpu_to_le16(ar.len); - /* Mark uninitialized */ - if (flags & EXT4_GET_BLOCKS_UNINIT_EXT){ - ext4_ext_mark_uninitialized(&newex); + /* Mark unwritten */ + if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT){ + ext4_ext_mark_unwritten(&newex); map->m_flags |= EXT4_MAP_UNWRITTEN; /* * io_end structure was created for every IO write to an - * uninitialized extent. To avoid unnecessary conversion, + * unwritten extent. To avoid unnecessary conversion, * here we flag the IO that really needs the conversion. * For non asycn direct IO case, flag the inode state * that we need to perform conversion when IO is done. */ if ((flags & EXT4_GET_BLOCKS_PRE_IO)) set_unwritten = 1; - if (ext4_should_dioread_nolock(inode)) - map->m_flags |= EXT4_MAP_UNINIT; } err = 0; @@ -4607,9 +4604,9 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, /* * Cache the extent and update transaction to commit on fdatasync only - * when it is _not_ an uninitialized extent. + * when it is _not_ an unwritten extent. */ - if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) + if ((flags & EXT4_GET_BLOCKS_UNWRIT_EXT) == 0) ext4_update_inode_fsync_trans(handle, inode, 1); else ext4_update_inode_fsync_trans(handle, inode, 0); @@ -4683,7 +4680,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, * that it doesn't get unnecessarily split into multiple * extents. */ - if (len <= EXT_UNINIT_MAX_LEN) + if (len <= EXT_UNWRITTEN_MAX_LEN) flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; /* @@ -4775,7 +4772,7 @@ static long ext4_zero_range(struct file *file, loff_t offset, else max_blocks -= lblk; - flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT | + flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT | EXT4_GET_BLOCKS_CONVERT_UNWRITTEN; if (mode & FALLOC_FL_KEEP_SIZE) flags |= EXT4_GET_BLOCKS_KEEP_SIZE; @@ -4865,6 +4862,14 @@ static long ext4_zero_range(struct file *file, loff_t offset, return ret; } +#ifdef CONFIG_EXT4_DEBUG +int ext4_fallocate_mode_block __read_mostly; + +module_param_named(fallocate_mode_block, ext4_fallocate_mode_block, int, 0644); +MODULE_PARM_DESC(fallocate_mode_block, + "Fallocate modes which are blocked for debugging purposes"); +#endif + /* * preallocate space for a file. This implements ext4's fallocate file * operation, which gets called from sys_fallocate system call. @@ -4884,6 +4889,15 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) struct timespec tv; unsigned int blkbits = inode->i_blkbits; +#ifdef CONFIG_EXT4_DEBUG + /* + * For debugging purposes, allow certain fallocate operations + * to be disabled + */ + if (unlikely(mode & ext4_fallocate_mode_block)) + return -EOPNOTSUPP; +#endif + /* Return error if mode is not supported */ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE)) @@ -4918,7 +4932,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) - lblk; - flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT; + flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT; if (mode & FALLOC_FL_KEEP_SIZE) flags |= EXT4_GET_BLOCKS_KEEP_SIZE; diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index 0ebc21204b5184..98c90f5834eec1 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c @@ -433,7 +433,7 @@ static void ext4_es_insert_extent_ext_check(struct inode *inode, ee_start = ext4_ext_pblock(ex); ee_len = ext4_ext_get_actual_len(ex); - ee_status = ext4_ext_is_uninitialized(ex) ? 1 : 0; + ee_status = ext4_ext_is_unwritten(ex) ? 1 : 0; es_status = ext4_es_is_unwritten(es) ? 1 : 0; /* diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 063fc153835597..708aad76819913 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -74,79 +74,105 @@ void ext4_unwritten_wait(struct inode *inode) * or one thread will zero the other's data, causing corruption. */ static int -ext4_unaligned_aio(struct inode *inode, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +ext4_unaligned_aio(struct inode *inode, struct iov_iter *from, loff_t pos) { struct super_block *sb = inode->i_sb; int blockmask = sb->s_blocksize - 1; - size_t count = iov_length(iov, nr_segs); - loff_t final_size = pos + count; if (pos >= i_size_read(inode)) return 0; - if ((pos & blockmask) || (final_size & blockmask)) + if ((pos | iov_iter_alignment(from)) & blockmask) return 1; return 0; } static ssize_t -ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; + struct inode *inode = file_inode(iocb->ki_filp); + struct mutex *aio_mutex = NULL; struct blk_plug plug; - int unaligned_aio = 0; - ssize_t ret; + int o_direct = file->f_flags & O_DIRECT; int overwrite = 0; - size_t length = iov_length(iov, nr_segs); - - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && - !is_sync_kiocb(iocb)) - unaligned_aio = ext4_unaligned_aio(inode, iov, nr_segs, pos); + size_t length = iov_iter_count(from); + ssize_t ret; + loff_t pos = iocb->ki_pos; - /* Unaligned direct AIO must be serialized; see comment above */ - if (unaligned_aio) { - mutex_lock(ext4_aio_mutex(inode)); + /* + * Unaligned direct AIO must be serialized; see comment above + * In the case of O_APPEND, assume that we must always serialize + */ + if (o_direct && + ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && + !is_sync_kiocb(iocb) && + (file->f_flags & O_APPEND || + ext4_unaligned_aio(inode, from, pos))) { + aio_mutex = ext4_aio_mutex(inode); + mutex_lock(aio_mutex); ext4_unwritten_wait(inode); } - BUG_ON(iocb->ki_pos != pos); - mutex_lock(&inode->i_mutex); - blk_start_plug(&plug); + if (file->f_flags & O_APPEND) + iocb->ki_pos = pos = i_size_read(inode); + + /* + * If we have encountered a bitmap-format file, the size limit + * is smaller than s_maxbytes, which is for extent-mapped files. + */ + if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - iocb->private = &overwrite; + if ((pos > sbi->s_bitmap_maxbytes) || + (pos == sbi->s_bitmap_maxbytes && length > 0)) { + mutex_unlock(&inode->i_mutex); + ret = -EFBIG; + goto errout; + } - /* check whether we do a DIO overwrite or not */ - if (ext4_should_dioread_nolock(inode) && !unaligned_aio && - !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { - struct ext4_map_blocks map; - unsigned int blkbits = inode->i_blkbits; - int err, len; + if (pos + length > sbi->s_bitmap_maxbytes) + iov_iter_truncate(from, sbi->s_bitmap_maxbytes - pos); + } - map.m_lblk = pos >> blkbits; - map.m_len = (EXT4_BLOCK_ALIGN(pos + length, blkbits) >> blkbits) - - map.m_lblk; - len = map.m_len; + if (o_direct) { + blk_start_plug(&plug); - err = ext4_map_blocks(NULL, inode, &map, 0); - /* - * 'err==len' means that all of blocks has been preallocated no - * matter they are initialized or not. For excluding - * uninitialized extents, we need to check m_flags. There are - * two conditions that indicate for initialized extents. - * 1) If we hit extent cache, EXT4_MAP_MAPPED flag is returned; - * 2) If we do a real lookup, non-flags are returned. - * So we should check these two conditions. - */ - if (err == len && (map.m_flags & EXT4_MAP_MAPPED)) - overwrite = 1; + iocb->private = &overwrite; + + /* check whether we do a DIO overwrite or not */ + if (ext4_should_dioread_nolock(inode) && !aio_mutex && + !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { + struct ext4_map_blocks map; + unsigned int blkbits = inode->i_blkbits; + int err, len; + + map.m_lblk = pos >> blkbits; + map.m_len = (EXT4_BLOCK_ALIGN(pos + length, blkbits) >> blkbits) + - map.m_lblk; + len = map.m_len; + + err = ext4_map_blocks(NULL, inode, &map, 0); + /* + * 'err==len' means that all of blocks has + * been preallocated no matter they are + * initialized or not. For excluding + * unwritten extents, we need to check + * m_flags. There are two conditions that + * indicate for initialized extents. 1) If we + * hit extent cache, EXT4_MAP_MAPPED flag is + * returned; 2) If we do a real lookup, + * non-flags are returned. So we should check + * these two conditions. + */ + if (err == len && (map.m_flags & EXT4_MAP_MAPPED)) + overwrite = 1; + } } - ret = __generic_file_aio_write(iocb, iov, nr_segs); + ret = __generic_file_write_iter(iocb, from); mutex_unlock(&inode->i_mutex); if (ret > 0) { @@ -156,45 +182,12 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, if (err < 0) ret = err; } - blk_finish_plug(&plug); - - if (unaligned_aio) - mutex_unlock(ext4_aio_mutex(inode)); - - return ret; -} - -static ssize_t -ext4_file_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) -{ - struct inode *inode = file_inode(iocb->ki_filp); - ssize_t ret; - - /* - * If we have encountered a bitmap-format file, the size limit - * is smaller than s_maxbytes, which is for extent-mapped files. - */ - - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - size_t length = iov_length(iov, nr_segs); - - if ((pos > sbi->s_bitmap_maxbytes || - (pos == sbi->s_bitmap_maxbytes && length > 0))) - return -EFBIG; - - if (pos + length > sbi->s_bitmap_maxbytes) { - nr_segs = iov_shorten((struct iovec *)iov, nr_segs, - sbi->s_bitmap_maxbytes - pos); - } - } - - if (unlikely(iocb->ki_filp->f_flags & O_DIRECT)) - ret = ext4_file_dio_write(iocb, iov, nr_segs, pos); - else - ret = generic_file_aio_write(iocb, iov, nr_segs, pos); + if (o_direct) + blk_finish_plug(&plug); +errout: + if (aio_mutex) + mutex_unlock(aio_mutex); return ret; } @@ -593,10 +586,10 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int whence) const struct file_operations ext4_file_operations = { .llseek = ext4_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = ext4_file_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = ext4_file_write_iter, .unlocked_ioctl = ext4_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext4_compat_ioctl, @@ -606,7 +599,7 @@ const struct file_operations ext4_file_operations = { .release = ext4_release_file, .fsync = ext4_sync_file, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, .fallocate = ext4_fallocate, }; diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index 594009f5f523f0..8a57e9fcd1b987 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c @@ -639,8 +639,7 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, * VFS code falls back into buffered path in that case so we are safe. */ ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, - unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; @@ -648,7 +647,7 @@ ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, handle_t *handle; ssize_t ret; int orphan = 0; - size_t count = iov_length(iov, nr_segs); + size_t count = iov_iter_count(iter); int retries = 0; if (rw == WRITE) { @@ -687,18 +686,17 @@ ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, goto locked; } ret = __blockdev_direct_IO(rw, iocb, inode, - inode->i_sb->s_bdev, iov, - offset, nr_segs, + inode->i_sb->s_bdev, iter, offset, ext4_get_block, NULL, NULL, 0); inode_dio_done(inode); } else { locked: - ret = blockdev_direct_IO(rw, iocb, inode, iov, - offset, nr_segs, ext4_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, iter, + offset, ext4_get_block); if (unlikely((rw & WRITE) && ret < 0)) { loff_t isize = i_size_read(inode); - loff_t end = offset + iov_length(iov, nr_segs); + loff_t end = offset + count; if (end > isize) ext4_truncate_failed_write(inode); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index d7b7462a0e13e1..b1dc33423cf2c4 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -489,8 +489,8 @@ static void ext4_map_blocks_es_recheck(handle_t *handle, * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping * based files * - * On success, it returns the number of blocks being mapped or allocate. - * if create==0 and the blocks are pre-allocated and uninitialized block, + * On success, it returns the number of blocks being mapped or allocated. + * if create==0 and the blocks are pre-allocated and unwritten block, * the result buffer head is unmapped. If the create ==1, it will make sure * the buffer head is mapped. * @@ -622,7 +622,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, map->m_flags &= ~EXT4_MAP_FLAGS; /* - * New blocks allocate and/or writing to uninitialized extent + * New blocks allocate and/or writing to unwritten extent * will possibly result in updating i_data, so we take * the write lock of i_data_sem, and call get_blocks() * with create == 1 flag. @@ -2032,7 +2032,7 @@ static int mpage_process_page_bufs(struct mpage_da_data *mpd, * Scan buffers corresponding to changed extent (we expect corresponding pages * to be already locked) and update buffer state according to new extent state. * We map delalloc buffers to their physical location, clear unwritten bits, - * and mark buffers as uninit when we perform writes to uninitialized extents + * and mark buffers as uninit when we perform writes to unwritten extents * and do extent conversion after IO is finished. If the last page is not fully * mapped, we update @map to the next extent in the last page that needs * mapping. Otherwise we submit the page for IO. @@ -2126,12 +2126,12 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd) struct inode *inode = mpd->inode; struct ext4_map_blocks *map = &mpd->map; int get_blocks_flags; - int err; + int err, dioread_nolock; trace_ext4_da_write_pages_extent(inode, map); /* * Call ext4_map_blocks() to allocate any delayed allocation blocks, or - * to convert an uninitialized extent to be initialized (in the case + * to convert an unwritten extent to be initialized (in the case * where we have written into one or more preallocated blocks). It is * possible that we're going to need more metadata blocks than * previously reserved. However we must not fail because we're in @@ -2148,7 +2148,8 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd) */ get_blocks_flags = EXT4_GET_BLOCKS_CREATE | EXT4_GET_BLOCKS_METADATA_NOFAIL; - if (ext4_should_dioread_nolock(inode)) + dioread_nolock = ext4_should_dioread_nolock(inode); + if (dioread_nolock) get_blocks_flags |= EXT4_GET_BLOCKS_IO_CREATE_EXT; if (map->m_flags & (1 << BH_Delay)) get_blocks_flags |= EXT4_GET_BLOCKS_DELALLOC_RESERVE; @@ -2156,7 +2157,7 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd) err = ext4_map_blocks(handle, inode, map, get_blocks_flags); if (err < 0) return err; - if (map->m_flags & EXT4_MAP_UNINIT) { + if (dioread_nolock && (map->m_flags & EXT4_MAP_UNWRITTEN)) { if (!mpd->io_submit.io_end->handle && ext4_handle_valid(handle)) { mpd->io_submit.io_end->handle = handle->h_rsv_handle; @@ -3070,9 +3071,9 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, * preallocated extents, and those write extend the file, no need to * fall back to buffered IO. * - * For holes, we fallocate those blocks, mark them as uninitialized + * For holes, we fallocate those blocks, mark them as unwritten * If those blocks were preallocated, we mark sure they are split, but - * still keep the range to write as uninitialized. + * still keep the range to write as unwritten. * * The unwritten extents will be converted to written when DIO is completed. * For async direct IO, since the IO may still pending when return, we @@ -3085,13 +3086,12 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, * */ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, - unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; ssize_t ret; - size_t count = iov_length(iov, nr_segs); + size_t count = iov_iter_count(iter); int overwrite = 0; get_block_t *get_block_func = NULL; int dio_flags = 0; @@ -3100,7 +3100,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, /* Use the old path for reads and writes beyond i_size. */ if (rw != WRITE || final_size > inode->i_size) - return ext4_ind_direct_IO(rw, iocb, iov, offset, nr_segs); + return ext4_ind_direct_IO(rw, iocb, iter, offset); BUG_ON(iocb->private == NULL); @@ -3124,12 +3124,12 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, * We could direct write to holes and fallocate. * * Allocated blocks to fill the hole are marked as - * uninitialized to prevent parallel buffered read to expose + * unwritten to prevent parallel buffered read to expose * the stale data before DIO complete the data IO. * * As to previously fallocated extents, ext4 get_block will * just simply mark the buffer mapped but still keep the - * extents uninitialized. + * extents unwritten. * * For non AIO case, we will convert those unwritten extents * to written after return back from blockdev_direct_IO. @@ -3167,8 +3167,8 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, dio_flags = DIO_LOCKING; } ret = __blockdev_direct_IO(rw, iocb, inode, - inode->i_sb->s_bdev, iov, - offset, nr_segs, + inode->i_sb->s_bdev, iter, + offset, get_block_func, ext4_end_io_dio, NULL, @@ -3222,11 +3222,11 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, } static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, - unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; + size_t count = iov_iter_count(iter); ssize_t ret; /* @@ -3239,13 +3239,12 @@ static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, if (ext4_has_inline_data(inode)) return 0; - trace_ext4_direct_IO_enter(inode, offset, iov_length(iov, nr_segs), rw); + trace_ext4_direct_IO_enter(inode, offset, count, rw); if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - ret = ext4_ext_direct_IO(rw, iocb, iov, offset, nr_segs); + ret = ext4_ext_direct_IO(rw, iocb, iter, offset); else - ret = ext4_ind_direct_IO(rw, iocb, iov, offset, nr_segs); - trace_ext4_direct_IO_exit(inode, offset, - iov_length(iov, nr_segs), rw, ret); + ret = ext4_ind_direct_IO(rw, iocb, iter, offset); + trace_ext4_direct_IO_exit(inode, offset, count, rw, ret); return ret; } @@ -4304,12 +4303,15 @@ static int ext4_do_update_inode(handle_t *handle, struct ext4_inode *raw_inode = ext4_raw_inode(iloc); struct ext4_inode_info *ei = EXT4_I(inode); struct buffer_head *bh = iloc->bh; + struct super_block *sb = inode->i_sb; int err = 0, rc, block; - int need_datasync = 0; + int need_datasync = 0, set_large_file = 0; uid_t i_uid; gid_t i_gid; - /* For fields not not tracking in the in-memory inode, + spin_lock(&ei->i_raw_lock); + + /* For fields not tracked in the in-memory inode, * initialise them to zero for new inodes. */ if (ext4_test_inode_state(inode, EXT4_STATE_NEW)) memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); @@ -4347,8 +4349,10 @@ static int ext4_do_update_inode(handle_t *handle, EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode); EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode); - if (ext4_inode_blocks_set(handle, raw_inode, ei)) + if (ext4_inode_blocks_set(handle, raw_inode, ei)) { + spin_unlock(&ei->i_raw_lock); goto out_brelse; + } raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); raw_inode->i_flags = cpu_to_le32(ei->i_flags & 0xFFFFFFFF); if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) @@ -4360,24 +4364,11 @@ static int ext4_do_update_inode(handle_t *handle, need_datasync = 1; } if (ei->i_disksize > 0x7fffffffULL) { - struct super_block *sb = inode->i_sb; if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_LARGE_FILE) || EXT4_SB(sb)->s_es->s_rev_level == - cpu_to_le32(EXT4_GOOD_OLD_REV)) { - /* If this is the first large file - * created, add a flag to the superblock. - */ - err = ext4_journal_get_write_access(handle, - EXT4_SB(sb)->s_sbh); - if (err) - goto out_brelse; - ext4_update_dynamic_rev(sb); - EXT4_SET_RO_COMPAT_FEATURE(sb, - EXT4_FEATURE_RO_COMPAT_LARGE_FILE); - ext4_handle_sync(handle); - err = ext4_handle_dirty_super(handle, sb); - } + cpu_to_le32(EXT4_GOOD_OLD_REV)) + set_large_file = 1; } raw_inode->i_generation = cpu_to_le32(inode->i_generation); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { @@ -4409,12 +4400,23 @@ static int ext4_do_update_inode(handle_t *handle, ext4_inode_csum_set(inode, raw_inode, ei); + spin_unlock(&ei->i_raw_lock); + BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); rc = ext4_handle_dirty_metadata(handle, NULL, bh); if (!err) err = rc; ext4_clear_inode_state(inode, EXT4_STATE_NEW); - + if (set_large_file) { + err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); + if (err) + goto out_brelse; + ext4_update_dynamic_rev(sb); + EXT4_SET_RO_COMPAT_FEATURE(sb, + EXT4_FEATURE_RO_COMPAT_LARGE_FILE); + ext4_handle_sync(handle); + err = ext4_handle_dirty_super(handle, sb); + } ext4_update_inode_fsync_trans(handle, inode, need_datasync); out_brelse: brelse(bh); diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index 58ee7dc87669d9..1b809fe51da18d 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c @@ -57,8 +57,8 @@ get_ext_path(struct inode *inode, ext4_lblk_t lblock, static void copy_extent_status(struct ext4_extent *src, struct ext4_extent *dest) { - if (ext4_ext_is_uninitialized(src)) - ext4_ext_mark_uninitialized(dest); + if (ext4_ext_is_unwritten(src)) + ext4_ext_mark_unwritten(dest); else dest->ee_len = cpu_to_le16(ext4_ext_get_actual_len(dest)); } @@ -593,14 +593,14 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext, * @inode: inode in question * @from: block offset of inode * @count: block count to be checked - * @uninit: extents expected to be uninitialized + * @unwritten: extents expected to be unwritten * @err: pointer to save error value * * Return 1 if all extents in range has expected type, and zero otherwise. */ static int mext_check_coverage(struct inode *inode, ext4_lblk_t from, ext4_lblk_t count, - int uninit, int *err) + int unwritten, int *err) { struct ext4_ext_path *path = NULL; struct ext4_extent *ext; @@ -611,7 +611,7 @@ mext_check_coverage(struct inode *inode, ext4_lblk_t from, ext4_lblk_t count, if (*err) goto out; ext = path[ext_depth(inode)].p_ext; - if (uninit != ext4_ext_is_uninitialized(ext)) + if (unwritten != ext4_ext_is_unwritten(ext)) goto out; from += ext4_ext_get_actual_len(ext); ext4_ext_drop_refs(path); @@ -894,7 +894,7 @@ mext_page_mkuptodate(struct page *page, unsigned from, unsigned to) * @orig_page_offset: page index on original file * @data_offset_in_page: block index where data swapping starts * @block_len_in_page: the number of blocks to be swapped - * @uninit: orig extent is uninitialized or not + * @unwritten: orig extent is unwritten or not * @err: pointer to save return value * * Save the data in original inode blocks and replace original inode extents @@ -905,7 +905,7 @@ mext_page_mkuptodate(struct page *page, unsigned from, unsigned to) static int move_extent_per_page(struct file *o_filp, struct inode *donor_inode, pgoff_t orig_page_offset, int data_offset_in_page, - int block_len_in_page, int uninit, int *err) + int block_len_in_page, int unwritten, int *err) { struct inode *orig_inode = file_inode(o_filp); struct page *pagep[2] = {NULL, NULL}; @@ -962,27 +962,27 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, if (unlikely(*err < 0)) goto stop_journal; /* - * If orig extent was uninitialized it can become initialized + * If orig extent was unwritten it can become initialized * at any time after i_data_sem was dropped, in order to * serialize with delalloc we have recheck extent while we * hold page's lock, if it is still the case data copy is not * necessary, just swap data blocks between orig and donor. */ - if (uninit) { + if (unwritten) { ext4_double_down_write_data_sem(orig_inode, donor_inode); /* If any of extents in range became initialized we have to * fallback to data copying */ - uninit = mext_check_coverage(orig_inode, orig_blk_offset, - block_len_in_page, 1, err); + unwritten = mext_check_coverage(orig_inode, orig_blk_offset, + block_len_in_page, 1, err); if (*err) goto drop_data_sem; - uninit &= mext_check_coverage(donor_inode, orig_blk_offset, - block_len_in_page, 1, err); + unwritten &= mext_check_coverage(donor_inode, orig_blk_offset, + block_len_in_page, 1, err); if (*err) goto drop_data_sem; - if (!uninit) { + if (!unwritten) { ext4_double_up_write_data_sem(orig_inode, donor_inode); goto data_copy; } @@ -1259,7 +1259,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; int data_offset_in_page; int block_len_in_page; - int uninit; + int unwritten; if (orig_inode->i_sb != donor_inode->i_sb) { ext4_debug("ext4 move extent: The argument files " @@ -1391,8 +1391,8 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, !last_extent) continue; - /* Is original extent is uninitialized */ - uninit = ext4_ext_is_uninitialized(ext_prev); + /* Is original extent is unwritten */ + unwritten = ext4_ext_is_unwritten(ext_prev); data_offset_in_page = seq_start % blocks_per_page; @@ -1432,8 +1432,8 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, o_filp, donor_inode, orig_page_offset, data_offset_in_page, - block_len_in_page, uninit, - &ret); + block_len_in_page, + unwritten, &ret); /* Count how many blocks we have exchanged */ *moved_len += block_len_in_page; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 1cb84f78909ee2..a683f958f12859 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2510,8 +2510,7 @@ static int empty_dir(struct inode *inode) ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize); de = ext4_next_entry(de1, sb->s_blocksize); while (offset < inode->i_size) { - if (!bh || - (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { + if ((void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { unsigned int lblock; err = 0; brelse(bh); diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index f3b84cd9de566f..08b3c116915b82 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -42,7 +42,7 @@ int ext4_resize_begin(struct super_block *sb) void ext4_resize_end(struct super_block *sb) { clear_bit_unlock(EXT4_RESIZING, &EXT4_SB(sb)->s_resize_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } static ext4_group_t ext4_meta_bg_first_group(struct super_block *sb, diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 6f9e6fadac04e1..1f8cb1812723a1 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -879,6 +879,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) return NULL; ei->vfs_inode.i_version = 1; + spin_lock_init(&ei->i_raw_lock); INIT_LIST_HEAD(&ei->i_prealloc_list); spin_lock_init(&ei->i_prealloc_lock); ext4_es_init_tree(&ei->i_es_tree); @@ -3337,7 +3338,7 @@ static ext4_fsblk_t ext4_calculate_resv_clusters(struct super_block *sb) * By default we reserve 2% or 4096 clusters, whichever is smaller. * This should cover the situations where we can not afford to run * out of space like for example punch hole, or converting - * uninitialized extents in delalloc path. In most cases such + * unwritten extents in delalloc path. In most cases such * allocation would require 1, or 2 blocks, higher numbers are * very rare. */ diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index e93e4ec7d165af..dbe2141d10ad7d 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -240,7 +240,7 @@ static int __f2fs_set_acl(struct inode *inode, int type, } } - error = f2fs_setxattr(inode, name_index, "", value, size, ipage); + error = f2fs_setxattr(inode, name_index, "", value, size, ipage, 0); kfree(value); if (!error) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 4aa521aa9bc3a7..fe968c7bfc90e8 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -33,12 +33,12 @@ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) struct address_space *mapping = META_MAPPING(sbi); struct page *page = NULL; repeat: - page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS); + page = grab_cache_page(mapping, index); if (!page) { cond_resched(); goto repeat; } - + f2fs_wait_on_page_writeback(page, META); SetPageUptodate(page); return page; } @@ -73,7 +73,7 @@ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) return page; } -inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type) +static inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type) { switch (type) { case META_NAT: @@ -157,6 +157,8 @@ static int f2fs_write_meta_page(struct page *page, struct inode *inode = page->mapping->host; struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + trace_f2fs_writepage(page, META); + if (unlikely(sbi->por_doing)) goto redirty_out; if (wbc->for_reclaim) @@ -174,10 +176,7 @@ static int f2fs_write_meta_page(struct page *page, return 0; redirty_out: - dec_page_count(sbi, F2FS_DIRTY_META); - wbc->pages_skipped++; - account_page_redirty(page); - set_page_dirty(page); + redirty_page_for_writepage(wbc, page); return AOP_WRITEPAGE_ACTIVATE; } @@ -187,6 +186,8 @@ static int f2fs_write_meta_pages(struct address_space *mapping, struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); long diff, written; + trace_f2fs_writepages(mapping->host, wbc, META); + /* collect a number of dirty meta pages and write together */ if (wbc->for_kupdate || get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META)) @@ -555,14 +556,13 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct list_head *head = &sbi->dir_inode_list; - struct dir_inode_entry *entry; - list_for_each_entry(entry, head, list) - if (unlikely(entry->inode == inode)) - return -EEXIST; + if (is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) + return -EEXIST; - list_add_tail(&new->list, head); + set_inode_flag(F2FS_I(inode), FI_DIRTY_DIR); + F2FS_I(inode)->dirty_dir = new; + list_add_tail(&new->list, &sbi->dir_inode_list); stat_inc_dirty_dir(sbi); return 0; } @@ -611,31 +611,26 @@ void add_dirty_dir_inode(struct inode *inode) void remove_dirty_dir_inode(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct list_head *head; struct dir_inode_entry *entry; if (!S_ISDIR(inode->i_mode)) return; spin_lock(&sbi->dir_inode_lock); - if (get_dirty_dents(inode)) { + if (get_dirty_dents(inode) || + !is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) { spin_unlock(&sbi->dir_inode_lock); return; } - head = &sbi->dir_inode_list; - list_for_each_entry(entry, head, list) { - if (entry->inode == inode) { - list_del(&entry->list); - stat_dec_dirty_dir(sbi); - spin_unlock(&sbi->dir_inode_lock); - kmem_cache_free(inode_entry_slab, entry); - goto done; - } - } + entry = F2FS_I(inode)->dirty_dir; + list_del(&entry->list); + F2FS_I(inode)->dirty_dir = NULL; + clear_inode_flag(F2FS_I(inode), FI_DIRTY_DIR); + stat_dec_dirty_dir(sbi); spin_unlock(&sbi->dir_inode_lock); + kmem_cache_free(inode_entry_slab, entry); -done: /* Only from the recovery routine */ if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) { clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT); @@ -643,26 +638,6 @@ void remove_dirty_dir_inode(struct inode *inode) } } -struct inode *check_dirty_dir_inode(struct f2fs_sb_info *sbi, nid_t ino) -{ - - struct list_head *head; - struct inode *inode = NULL; - struct dir_inode_entry *entry; - - spin_lock(&sbi->dir_inode_lock); - - head = &sbi->dir_inode_list; - list_for_each_entry(entry, head, list) { - if (entry->inode->i_ino == ino) { - inode = entry->inode; - break; - } - } - spin_unlock(&sbi->dir_inode_lock); - return inode; -} - void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) { struct list_head *head; @@ -762,6 +737,12 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) void *kaddr; int i; + /* + * This avoids to conduct wrong roll-forward operations and uses + * metapages, so should be called prior to sync_meta_pages below. + */ + discard_next_dnode(sbi); + /* Flush all the NAT/SIT pages */ while (get_pages(sbi, F2FS_DIRTY_META)) sync_meta_pages(sbi, META, LONG_MAX); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 45abd60e2bff54..ba14195f604080 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -417,7 +417,7 @@ struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync) if (unlikely(dn.data_blkaddr == NEW_ADDR)) return ERR_PTR(-EINVAL); - page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS); + page = grab_cache_page(mapping, index); if (!page) return ERR_PTR(-ENOMEM); @@ -455,7 +455,7 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index) int err; repeat: - page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS); + page = grab_cache_page(mapping, index); if (!page) return ERR_PTR(-ENOMEM); @@ -652,8 +652,7 @@ static int get_data_block(struct inode *inode, sector_t iblock, goto put_out; } - end_offset = IS_INODE(dn.node_page) ? - ADDRS_PER_INODE(F2FS_I(inode)) : ADDRS_PER_BLOCK; + end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); bh_result->b_size = (((size_t)1) << blkbits); dn.ofs_in_node++; pgofs++; @@ -675,8 +674,7 @@ static int get_data_block(struct inode *inode, sector_t iblock, if (dn.data_blkaddr == NEW_ADDR) goto put_out; - end_offset = IS_INODE(dn.node_page) ? - ADDRS_PER_INODE(F2FS_I(inode)) : ADDRS_PER_BLOCK; + end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); } if (maxblocks > (bh_result->b_size >> blkbits)) { @@ -715,6 +713,8 @@ static int f2fs_read_data_page(struct file *file, struct page *page) struct inode *inode = page->mapping->host; int ret; + trace_f2fs_readpage(page, DATA); + /* If the file has inline data, try to read it directlly */ if (f2fs_has_inline_data(inode)) ret = f2fs_read_inline_data(inode, page); @@ -790,6 +790,8 @@ static int f2fs_write_data_page(struct page *page, .rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE, }; + trace_f2fs_writepage(page, DATA); + if (page->index < end_index) goto write; @@ -798,10 +800,8 @@ static int f2fs_write_data_page(struct page *page, * this page does not have to be written to disk. */ offset = i_size & (PAGE_CACHE_SIZE - 1); - if ((page->index >= end_index + 1) || !offset) { - inode_dec_dirty_dents(inode); + if ((page->index >= end_index + 1) || !offset) goto out; - } zero_user_segment(page, offset, PAGE_CACHE_SIZE); write: @@ -810,7 +810,6 @@ static int f2fs_write_data_page(struct page *page, /* Dentry blocks are controlled by checkpoint */ if (S_ISDIR(inode->i_mode)) { - inode_dec_dirty_dents(inode); err = do_write_data_page(page, &fio); goto done; } @@ -832,15 +831,16 @@ static int f2fs_write_data_page(struct page *page, clear_cold_data(page); out: + inode_dec_dirty_dents(inode); unlock_page(page); if (need_balance_fs) f2fs_balance_fs(sbi); + if (wbc->for_reclaim) + f2fs_submit_merged_bio(sbi, DATA, WRITE); return 0; redirty_out: - wbc->pages_skipped++; - account_page_redirty(page); - set_page_dirty(page); + redirty_page_for_writepage(wbc, page); return AOP_WRITEPAGE_ACTIVATE; } @@ -862,12 +862,15 @@ static int f2fs_write_data_pages(struct address_space *mapping, int ret; long diff; + trace_f2fs_writepages(mapping->host, wbc, DATA); + /* deal with chardevs and other special file */ if (!mapping->a_ops->writepage) return 0; if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE && - get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA)) + get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA) && + available_free_memory(sbi, DIRTY_DENTS)) goto skip_write; diff = nr_pages_to_write(sbi, DATA, wbc); @@ -903,6 +906,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, struct dnode_of_data dn; int err = 0; + trace_f2fs_write_begin(inode, pos, len, flags); + f2fs_balance_fs(sbi); repeat: err = f2fs_convert_inline_data(inode, pos + len); @@ -912,6 +917,10 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, page = grab_cache_page_write_begin(mapping, index, flags); if (!page) return -ENOMEM; + + /* to avoid latency during memory pressure */ + unlock_page(page); + *pagep = page; if (f2fs_has_inline_data(inode) && (pos + len) <= MAX_INLINE_DATA) @@ -923,10 +932,18 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, f2fs_unlock_op(sbi); if (err) { - f2fs_put_page(page, 1); + f2fs_put_page(page, 0); return err; } inline_data: + lock_page(page); + if (unlikely(page->mapping != mapping)) { + f2fs_put_page(page, 1); + goto repeat; + } + + f2fs_wait_on_page_writeback(page, DATA); + if ((len == PAGE_CACHE_SIZE) || PageUptodate(page)) return 0; @@ -978,6 +995,8 @@ static int f2fs_write_end(struct file *file, { struct inode *inode = page->mapping->host; + trace_f2fs_write_end(inode, pos, len, copied); + SetPageUptodate(page); set_page_dirty(page); @@ -992,10 +1011,9 @@ static int f2fs_write_end(struct file *file, } static int check_direct_IO(struct inode *inode, int rw, - const struct iovec *iov, loff_t offset, unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { unsigned blocksize_mask = inode->i_sb->s_blocksize - 1; - int i; if (rw == READ) return 0; @@ -1003,14 +1021,14 @@ static int check_direct_IO(struct inode *inode, int rw, if (offset & blocksize_mask) return -EINVAL; - for (i = 0; i < nr_segs; i++) - if (iov[i].iov_len & blocksize_mask) - return -EINVAL; + if (iov_iter_alignment(iter) & blocksize_mask) + return -EINVAL; + return 0; } static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; @@ -1019,11 +1037,11 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, if (f2fs_has_inline_data(inode)) return 0; - if (check_direct_IO(inode, rw, iov, offset, nr_segs)) + if (check_direct_IO(inode, rw, iter, offset)) return 0; - return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - get_data_block); + return blockdev_direct_IO(rw, iocb, inode, iter, offset, + get_data_block); } static void f2fs_invalidate_data_page(struct page *page, unsigned int offset, @@ -1061,6 +1079,11 @@ static int f2fs_set_data_page_dirty(struct page *page) static sector_t f2fs_bmap(struct address_space *mapping, sector_t block) { + struct inode *inode = mapping->host; + + if (f2fs_has_inline_data(inode)) + return 0; + return generic_block_bmap(mapping, block, get_data_block); } diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 972fd0ef230f9a..c3f148555c378c 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -268,6 +268,8 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage) { struct f2fs_inode *ri; + f2fs_wait_on_page_writeback(ipage, NODE); + /* copy name info. to this inode page */ ri = F2FS_INODE(ipage); ri->i_namelen = cpu_to_le32(name->len); @@ -637,11 +639,17 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) struct f2fs_dentry_block *dentry_blk = NULL; struct f2fs_dir_entry *de = NULL; struct page *dentry_page = NULL; + struct file_ra_state *ra = &file->f_ra; unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK); unsigned char d_type = DT_UNKNOWN; bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK); + /* readahead for multi pages of dir */ + if (npages - n > 1 && !ra_has_index(ra, n)) + page_cache_sync_readahead(inode->i_mapping, ra, file, n, + min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES)); + for (; n < npages; n++) { dentry_page = get_lock_data_page(inode, n); if (IS_ERR(dentry_page)) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 2ecac831235906..676a2c6ccec744 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -182,6 +182,8 @@ enum { #define F2FS_LINK_MAX 32000 /* maximum link count per file */ +#define MAX_DIR_RA_PAGES 4 /* maximum ra pages of dir */ + /* for in-memory extent cache entry */ #define F2FS_MIN_EXTENT_LEN 16 /* minimum extent length */ @@ -218,6 +220,7 @@ struct f2fs_inode_info { nid_t i_xattr_nid; /* node id that contains xattrs */ unsigned long long xattr_ver; /* cp version of xattr modification */ struct extent_info ext; /* in-memory extent cache entry */ + struct dir_inode_entry *dirty_dir; /* the pointer of dirty dir */ }; static inline void get_extent_info(struct extent_info *ext, @@ -243,6 +246,7 @@ static inline void set_raw_extent(struct extent_info *ext, struct f2fs_nm_info { block_t nat_blkaddr; /* base disk address of NAT */ nid_t max_nid; /* maximum possible node ids */ + nid_t available_nids; /* maximum available node ids */ nid_t next_scan_nid; /* the next nid to be scanned */ unsigned int ram_thresh; /* control the memory footprint */ @@ -323,6 +327,15 @@ struct flush_cmd { int ret; }; +struct flush_cmd_control { + struct task_struct *f2fs_issue_flush; /* flush thread */ + wait_queue_head_t flush_wait_queue; /* waiting queue for wake-up */ + struct flush_cmd *issue_list; /* list for command issue */ + struct flush_cmd *dispatch_list; /* list for command dispatch */ + spinlock_t issue_lock; /* for issue list lock */ + struct flush_cmd *issue_tail; /* list tail of issue list */ +}; + struct f2fs_sm_info { struct sit_info *sit_info; /* whole segment information */ struct free_segmap_info *free_info; /* free segment information */ @@ -353,12 +366,8 @@ struct f2fs_sm_info { unsigned int min_ipu_util; /* in-place-update threshold */ /* for flush command control */ - struct task_struct *f2fs_issue_flush; /* flush thread */ - wait_queue_head_t flush_wait_queue; /* waiting queue for wake-up */ - struct flush_cmd *issue_list; /* list for command issue */ - struct flush_cmd *dispatch_list; /* list for command dispatch */ - spinlock_t issue_lock; /* for issue list lock */ - struct flush_cmd *issue_tail; /* list tail of issue list */ + struct flush_cmd_control *cmd_control_info; + }; /* @@ -958,6 +967,7 @@ static inline int f2fs_clear_bit(unsigned int nr, char *addr) enum { FI_NEW_INODE, /* indicate newly allocated inode */ FI_DIRTY_INODE, /* indicate inode is dirty or not */ + FI_DIRTY_DIR, /* indicate directory has dirty pages */ FI_INC_LINK, /* need to increment i_nlink */ FI_ACL_MODE, /* indicate acl mode */ FI_NO_ALLOC, /* should not allocate any blocks */ @@ -1071,6 +1081,12 @@ static inline void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi) ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ (F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) +/* get offset of first page in next direct node */ +#define PGOFS_OF_NEXT_DNODE(pgofs, fi) \ + ((pgofs < ADDRS_PER_INODE(fi)) ? ADDRS_PER_INODE(fi) : \ + (pgofs - ADDRS_PER_INODE(fi) + ADDRS_PER_BLOCK) / \ + ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi)) + /* * file.c */ @@ -1140,6 +1156,7 @@ f2fs_hash_t f2fs_dentry_hash(const char *, size_t); struct dnode_of_data; struct node_info; +bool available_free_memory(struct f2fs_sb_info *, int); int is_checkpointed_node(struct f2fs_sb_info *, nid_t); bool fsync_mark_done(struct f2fs_sb_info *, nid_t); void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *); @@ -1176,9 +1193,12 @@ void destroy_node_manager_caches(void); void f2fs_balance_fs(struct f2fs_sb_info *); void f2fs_balance_fs_bg(struct f2fs_sb_info *); int f2fs_issue_flush(struct f2fs_sb_info *); +int create_flush_cmd_control(struct f2fs_sb_info *); +void destroy_flush_cmd_control(struct f2fs_sb_info *); void invalidate_blocks(struct f2fs_sb_info *, block_t); void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t); void clear_prefree_segments(struct f2fs_sb_info *); +void discard_next_dnode(struct f2fs_sb_info *); int npages_for_summary_flush(struct f2fs_sb_info *); void allocate_new_segments(struct f2fs_sb_info *); struct page *get_sum_page(struct f2fs_sb_info *, unsigned int); @@ -1221,7 +1241,6 @@ int get_valid_checkpoint(struct f2fs_sb_info *); void set_dirty_dir_page(struct inode *, struct page *); void add_dirty_dir_inode(struct inode *); void remove_dirty_dir_inode(struct inode *); -struct inode *check_dirty_dir_inode(struct f2fs_sb_info *, nid_t); void sync_dirty_dir_inodes(struct f2fs_sb_info *); void write_checkpoint(struct f2fs_sb_info *, bool); void init_orphan_info(struct f2fs_sb_info *); @@ -1391,5 +1410,6 @@ bool f2fs_may_inline(struct inode *); int f2fs_read_inline_data(struct inode *, struct page *); int f2fs_convert_inline_data(struct inode *, pgoff_t); int f2fs_write_inline_data(struct inode *, struct page *, unsigned int); +void truncate_inline_data(struct inode *, u64); int recover_inline_data(struct inode *, struct page *); #endif diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 60e7d5448a1d8b..37d0e1f512a993 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "f2fs.h" #include "node.h" @@ -194,6 +195,132 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) return ret; } +static pgoff_t __get_first_dirty_index(struct address_space *mapping, + pgoff_t pgofs, int whence) +{ + struct pagevec pvec; + int nr_pages; + + if (whence != SEEK_DATA) + return 0; + + /* find first dirty page index */ + pagevec_init(&pvec, 0); + nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs, PAGECACHE_TAG_DIRTY, 1); + pgofs = nr_pages ? pvec.pages[0]->index: LONG_MAX; + pagevec_release(&pvec); + return pgofs; +} + +static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs, + int whence) +{ + switch (whence) { + case SEEK_DATA: + if ((blkaddr == NEW_ADDR && dirty == pgofs) || + (blkaddr != NEW_ADDR && blkaddr != NULL_ADDR)) + return true; + break; + case SEEK_HOLE: + if (blkaddr == NULL_ADDR) + return true; + break; + } + return false; +} + +static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence) +{ + struct inode *inode = file->f_mapping->host; + loff_t maxbytes = inode->i_sb->s_maxbytes; + struct dnode_of_data dn; + pgoff_t pgofs, end_offset, dirty; + loff_t data_ofs = offset; + loff_t isize; + int err = 0; + + mutex_lock(&inode->i_mutex); + + isize = i_size_read(inode); + if (offset >= isize) + goto fail; + + /* handle inline data case */ + if (f2fs_has_inline_data(inode)) { + if (whence == SEEK_HOLE) + data_ofs = isize; + goto found; + } + + pgofs = (pgoff_t)(offset >> PAGE_CACHE_SHIFT); + + dirty = __get_first_dirty_index(inode->i_mapping, pgofs, whence); + + for (; data_ofs < isize; data_ofs = pgofs << PAGE_CACHE_SHIFT) { + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, pgofs, LOOKUP_NODE_RA); + if (err && err != -ENOENT) { + goto fail; + } else if (err == -ENOENT) { + /* direct node is not exist */ + if (whence == SEEK_DATA) { + pgofs = PGOFS_OF_NEXT_DNODE(pgofs, + F2FS_I(inode)); + continue; + } else { + goto found; + } + } + + end_offset = IS_INODE(dn.node_page) ? + ADDRS_PER_INODE(F2FS_I(inode)) : ADDRS_PER_BLOCK; + + /* find data/hole in dnode block */ + for (; dn.ofs_in_node < end_offset; + dn.ofs_in_node++, pgofs++, + data_ofs = pgofs << PAGE_CACHE_SHIFT) { + block_t blkaddr; + blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); + + if (__found_offset(blkaddr, dirty, pgofs, whence)) { + f2fs_put_dnode(&dn); + goto found; + } + } + f2fs_put_dnode(&dn); + } + + if (whence == SEEK_DATA) + goto fail; +found: + if (whence == SEEK_HOLE && data_ofs > isize) + data_ofs = isize; + mutex_unlock(&inode->i_mutex); + return vfs_setpos(file, data_ofs, maxbytes); +fail: + mutex_unlock(&inode->i_mutex); + return -ENXIO; +} + +static loff_t f2fs_llseek(struct file *file, loff_t offset, int whence) +{ + struct inode *inode = file->f_mapping->host; + loff_t maxbytes = inode->i_sb->s_maxbytes; + + switch (whence) { + case SEEK_SET: + case SEEK_CUR: + case SEEK_END: + return generic_file_llseek_size(file, offset, whence, + maxbytes, i_size_read(inode)); + case SEEK_DATA: + case SEEK_HOLE: + return f2fs_seek_block(file, offset, whence); + } + + return -EINVAL; +} + static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) { file_accessed(file); @@ -242,6 +369,9 @@ static void truncate_partial_data_page(struct inode *inode, u64 from) unsigned offset = from & (PAGE_CACHE_SIZE - 1); struct page *page; + if (f2fs_has_inline_data(inode)) + return truncate_inline_data(inode, from); + if (!offset) return; @@ -288,10 +418,7 @@ int truncate_blocks(struct inode *inode, u64 from) return err; } - if (IS_INODE(dn.node_page)) - count = ADDRS_PER_INODE(F2FS_I(inode)); - else - count = ADDRS_PER_BLOCK; + count = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); count -= dn.ofs_in_node; f2fs_bug_on(count < 0); @@ -678,11 +805,11 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) #endif const struct file_operations f2fs_file_operations = { - .llseek = generic_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .llseek = f2fs_llseek, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .open = generic_file_open, .mmap = f2fs_file_mmap, .fsync = f2fs_sync_file, @@ -692,5 +819,5 @@ const struct file_operations f2fs_file_operations = { .compat_ioctl = f2fs_compat_ioctl, #endif .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, }; diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 383db1fabcf444..1bba5228c19744 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -81,8 +81,10 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page) f2fs_lock_op(sbi); ipage = get_node_page(sbi, inode->i_ino); - if (IS_ERR(ipage)) - return PTR_ERR(ipage); + if (IS_ERR(ipage)) { + err = PTR_ERR(ipage); + goto out; + } /* * i_addr[0] is not used for inline data, @@ -90,11 +92,10 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page) */ set_new_dnode(&dn, inode, ipage, NULL, 0); err = f2fs_reserve_block(&dn, 0); - if (err) { - f2fs_unlock_op(sbi); - return err; - } + if (err) + goto out; + f2fs_wait_on_page_writeback(page, DATA); zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE); /* Copy the whole inline data block */ @@ -118,6 +119,7 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page) sync_inode_page(&dn); f2fs_put_dnode(&dn); +out: f2fs_unlock_op(sbi); return err; } @@ -132,7 +134,7 @@ int f2fs_convert_inline_data(struct inode *inode, pgoff_t to_size) else if (to_size <= MAX_INLINE_DATA) return 0; - page = grab_cache_page_write_begin(inode->i_mapping, 0, AOP_FLAG_NOFS); + page = grab_cache_page(inode->i_mapping, 0); if (!page) return -ENOMEM; @@ -155,6 +157,7 @@ int f2fs_write_inline_data(struct inode *inode, return err; ipage = dn.inode_page; + f2fs_wait_on_page_writeback(ipage, NODE); zero_user_segment(ipage, INLINE_DATA_OFFSET, INLINE_DATA_OFFSET + MAX_INLINE_DATA); src_addr = kmap(page); @@ -175,6 +178,26 @@ int f2fs_write_inline_data(struct inode *inode, return 0; } +void truncate_inline_data(struct inode *inode, u64 from) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct page *ipage; + + if (from >= MAX_INLINE_DATA) + return; + + ipage = get_node_page(sbi, inode->i_ino); + if (IS_ERR(ipage)) + return; + + f2fs_wait_on_page_writeback(ipage, NODE); + + zero_user_segment(ipage, INLINE_DATA_OFFSET + from, + INLINE_DATA_OFFSET + MAX_INLINE_DATA); + set_page_dirty(ipage); + f2fs_put_page(ipage, 1); +} + int recover_inline_data(struct inode *inode, struct page *npage) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); @@ -199,6 +222,8 @@ int recover_inline_data(struct inode *inode, struct page *npage) ipage = get_node_page(sbi, inode->i_ino); f2fs_bug_on(IS_ERR(ipage)); + f2fs_wait_on_page_writeback(ipage, NODE); + src_addr = inline_data_addr(npage); dst_addr = inline_data_addr(ipage); memcpy(dst_addr, src_addr, MAX_INLINE_DATA); @@ -210,6 +235,7 @@ int recover_inline_data(struct inode *inode, struct page *npage) if (f2fs_has_inline_data(inode)) { ipage = get_node_page(sbi, inode->i_ino); f2fs_bug_on(IS_ERR(ipage)); + f2fs_wait_on_page_writeback(ipage, NODE); zero_user_segment(ipage, INLINE_DATA_OFFSET, INLINE_DATA_OFFSET + MAX_INLINE_DATA); clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA); diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index ee829d36046859..adc622c6bdce68 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "f2fs.h" #include "node.h" @@ -21,20 +22,20 @@ void f2fs_set_inode_flags(struct inode *inode) { unsigned int flags = F2FS_I(inode)->i_flags; - - inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | - S_NOATIME | S_DIRSYNC); + unsigned int new_fl = 0; if (flags & FS_SYNC_FL) - inode->i_flags |= S_SYNC; + new_fl |= S_SYNC; if (flags & FS_APPEND_FL) - inode->i_flags |= S_APPEND; + new_fl |= S_APPEND; if (flags & FS_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; + new_fl |= S_IMMUTABLE; if (flags & FS_NOATIME_FL) - inode->i_flags |= S_NOATIME; + new_fl |= S_NOATIME; if (flags & FS_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; + new_fl |= S_DIRSYNC; + set_mask_bits(&inode->i_flags, + S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC, new_fl); } static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri) @@ -294,4 +295,5 @@ void f2fs_evict_inode(struct inode *inode) sb_end_intwrite(inode->i_sb); no_delete: clear_inode(inode); + invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino); } diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index a161e955c4c808..3d60d3d34ed292 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -26,20 +26,26 @@ static struct kmem_cache *nat_entry_slab; static struct kmem_cache *free_nid_slab; -static inline bool available_free_memory(struct f2fs_nm_info *nm_i, int type) +bool available_free_memory(struct f2fs_sb_info *sbi, int type) { + struct f2fs_nm_info *nm_i = NM_I(sbi); struct sysinfo val; unsigned long mem_size = 0; + bool res = false; si_meminfo(&val); - if (type == FREE_NIDS) - mem_size = nm_i->fcnt * sizeof(struct free_nid); - else if (type == NAT_ENTRIES) - mem_size += nm_i->nat_cnt * sizeof(struct nat_entry); - mem_size >>= 12; - - /* give 50:50 memory for free nids and nat caches respectively */ - return (mem_size < ((val.totalram * nm_i->ram_thresh) >> 11)); + /* give 25%, 25%, 50% memory for each components respectively */ + if (type == FREE_NIDS) { + mem_size = (nm_i->fcnt * sizeof(struct free_nid)) >> 12; + res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2); + } else if (type == NAT_ENTRIES) { + mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >> 12; + res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2); + } else if (type == DIRTY_DENTS) { + mem_size = get_pages(sbi, F2FS_DIRTY_DENTS); + res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 1); + } + return res; } static void clear_node_page_dirty(struct page *page) @@ -179,9 +185,7 @@ static void cache_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid, write_unlock(&nm_i->nat_tree_lock); goto retry; } - nat_set_blkaddr(e, le32_to_cpu(ne->block_addr)); - nat_set_ino(e, le32_to_cpu(ne->ino)); - nat_set_version(e, ne->version); + node_info_from_raw_nat(&e->ni, ne); } write_unlock(&nm_i->nat_tree_lock); } @@ -243,7 +247,7 @@ int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink) { struct f2fs_nm_info *nm_i = NM_I(sbi); - if (available_free_memory(nm_i, NAT_ENTRIES)) + if (available_free_memory(sbi, NAT_ENTRIES)) return 0; write_lock(&nm_i->nat_tree_lock); @@ -849,8 +853,7 @@ struct page *new_node_page(struct dnode_of_data *dn, if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC))) return ERR_PTR(-EPERM); - page = grab_cache_page_write_begin(NODE_MAPPING(sbi), - dn->nid, AOP_FLAG_NOFS); + page = grab_cache_page(NODE_MAPPING(sbi), dn->nid); if (!page) return ERR_PTR(-ENOMEM); @@ -867,6 +870,7 @@ struct page *new_node_page(struct dnode_of_data *dn, new_ni.ino = dn->inode->i_ino; set_node_addr(sbi, &new_ni, NEW_ADDR, false); + f2fs_wait_on_page_writeback(page, NODE); fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true); set_cold_node(dn->inode, page); SetPageUptodate(page); @@ -946,8 +950,7 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) struct page *page; int err; repeat: - page = grab_cache_page_write_begin(NODE_MAPPING(sbi), - nid, AOP_FLAG_NOFS); + page = grab_cache_page(NODE_MAPPING(sbi), nid); if (!page) return ERR_PTR(-ENOMEM); @@ -1196,6 +1199,8 @@ static int f2fs_write_node_page(struct page *page, .rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE, }; + trace_f2fs_writepage(page, NODE); + if (unlikely(sbi->por_doing)) goto redirty_out; @@ -1227,10 +1232,7 @@ static int f2fs_write_node_page(struct page *page, return 0; redirty_out: - dec_page_count(sbi, F2FS_DIRTY_NODES); - wbc->pages_skipped++; - account_page_redirty(page); - set_page_dirty(page); + redirty_page_for_writepage(wbc, page); return AOP_WRITEPAGE_ACTIVATE; } @@ -1240,6 +1242,8 @@ static int f2fs_write_node_pages(struct address_space *mapping, struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); long diff; + trace_f2fs_writepages(mapping->host, wbc, NODE); + /* balancing f2fs's metadata in background */ f2fs_balance_fs_bg(sbi); @@ -1315,13 +1319,14 @@ static void __del_from_free_nid_list(struct f2fs_nm_info *nm_i, radix_tree_delete(&nm_i->free_nid_root, i->nid); } -static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build) +static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build) { + struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *i; struct nat_entry *ne; bool allocated = false; - if (!available_free_memory(nm_i, FREE_NIDS)) + if (!available_free_memory(sbi, FREE_NIDS)) return -1; /* 0 nid should not be used */ @@ -1374,9 +1379,10 @@ static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid) kmem_cache_free(free_nid_slab, i); } -static void scan_nat_page(struct f2fs_nm_info *nm_i, +static void scan_nat_page(struct f2fs_sb_info *sbi, struct page *nat_page, nid_t start_nid) { + struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nat_block *nat_blk = page_address(nat_page); block_t blk_addr; int i; @@ -1391,7 +1397,7 @@ static void scan_nat_page(struct f2fs_nm_info *nm_i, blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr); f2fs_bug_on(blk_addr == NEW_ADDR); if (blk_addr == NULL_ADDR) { - if (add_free_nid(nm_i, start_nid, true) < 0) + if (add_free_nid(sbi, start_nid, true) < 0) break; } } @@ -1415,7 +1421,7 @@ static void build_free_nids(struct f2fs_sb_info *sbi) while (1) { struct page *page = get_current_nat_page(sbi, nid); - scan_nat_page(nm_i, page, nid); + scan_nat_page(sbi, page, nid); f2fs_put_page(page, 1); nid += (NAT_ENTRY_PER_BLOCK - (nid % NAT_ENTRY_PER_BLOCK)); @@ -1435,7 +1441,7 @@ static void build_free_nids(struct f2fs_sb_info *sbi) block_t addr = le32_to_cpu(nat_in_journal(sum, i).block_addr); nid = le32_to_cpu(nid_in_journal(sum, i)); if (addr == NULL_ADDR) - add_free_nid(nm_i, nid, true); + add_free_nid(sbi, nid, true); else remove_free_nid(nm_i, nid); } @@ -1452,7 +1458,7 @@ bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid) struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *i = NULL; retry: - if (unlikely(sbi->total_valid_node_count + 1 >= nm_i->max_nid)) + if (unlikely(sbi->total_valid_node_count + 1 > nm_i->available_nids)) return false; spin_lock(&nm_i->free_nid_list_lock); @@ -1512,7 +1518,7 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid) spin_lock(&nm_i->free_nid_list_lock); i = __lookup_free_nid_list(nm_i, nid); f2fs_bug_on(!i || i->state != NID_ALLOC); - if (!available_free_memory(nm_i, FREE_NIDS)) { + if (!available_free_memory(sbi, FREE_NIDS)) { __del_from_free_nid_list(nm_i, i); need_free = true; } else { @@ -1534,7 +1540,7 @@ void recover_node_page(struct f2fs_sb_info *sbi, struct page *page, clear_node_page_dirty(page); } -void recover_inline_xattr(struct inode *inode, struct page *page) +static void recover_inline_xattr(struct inode *inode, struct page *page) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); void *src_addr, *dst_addr; @@ -1559,6 +1565,7 @@ void recover_inline_xattr(struct inode *inode, struct page *page) src_addr = inline_xattr_addr(page); inline_size = inline_xattr_size(inode); + f2fs_wait_on_page_writeback(ipage, NODE); memcpy(dst_addr, src_addr, inline_size); update_inode(inode, ipage); @@ -1614,6 +1621,11 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) struct node_info old_ni, new_ni; struct page *ipage; + get_node_info(sbi, ino, &old_ni); + + if (unlikely(old_ni.blk_addr != NULL_ADDR)) + return -EINVAL; + ipage = grab_cache_page(NODE_MAPPING(sbi), ino); if (!ipage) return -ENOMEM; @@ -1621,7 +1633,6 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) /* Should not use this inode from free nid list */ remove_free_nid(NM_I(sbi), ino); - get_node_info(sbi, ino, &old_ni); SetPageUptodate(ipage); fill_node_footer(ipage, ino, ino, 0, true); @@ -1758,9 +1769,7 @@ static bool flush_nats_in_journal(struct f2fs_sb_info *sbi) write_unlock(&nm_i->nat_tree_lock); goto retry; } - nat_set_blkaddr(ne, le32_to_cpu(raw_ne.block_addr)); - nat_set_ino(ne, le32_to_cpu(raw_ne.ino)); - nat_set_version(ne, raw_ne.version); + node_info_from_raw_nat(&ne->ni, &raw_ne); __set_nat_cache_dirty(nm_i, ne); write_unlock(&nm_i->nat_tree_lock); } @@ -1793,7 +1802,6 @@ void flush_nat_entries(struct f2fs_sb_info *sbi) nid_t nid; struct f2fs_nat_entry raw_ne; int offset = -1; - block_t new_blkaddr; if (nat_get_blkaddr(ne) == NEW_ADDR) continue; @@ -1829,11 +1837,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi) f2fs_bug_on(!nat_blk); raw_ne = nat_blk->entries[nid - start_nid]; flush_now: - new_blkaddr = nat_get_blkaddr(ne); - - raw_ne.ino = cpu_to_le32(nat_get_ino(ne)); - raw_ne.block_addr = cpu_to_le32(new_blkaddr); - raw_ne.version = nat_get_version(ne); + raw_nat_from_node_info(&raw_ne, &ne->ni); if (offset < 0) { nat_blk->entries[nid - start_nid] = raw_ne; @@ -1843,7 +1847,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi) } if (nat_get_blkaddr(ne) == NULL_ADDR && - add_free_nid(NM_I(sbi), nid, false) <= 0) { + add_free_nid(sbi, nid, false) <= 0) { write_lock(&nm_i->nat_tree_lock); __del_from_nat_cache(nm_i, ne); write_unlock(&nm_i->nat_tree_lock); @@ -1871,8 +1875,10 @@ static int init_node_manager(struct f2fs_sb_info *sbi) nat_segs = le32_to_cpu(sb_raw->segment_count_nat) >> 1; nat_blocks = nat_segs << le32_to_cpu(sb_raw->log_blocks_per_seg); + nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks; + /* not used nids: 0, node, meta, (and root counted as valid node) */ - nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks - 3; + nm_i->available_nids = nm_i->max_nid - 3; nm_i->fcnt = 0; nm_i->nat_cnt = 0; nm_i->ram_thresh = DEF_RAM_THRESHOLD; diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 5decc1a375f007..7281112cd1c814 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -59,12 +59,12 @@ struct nat_entry { do { \ ne->checkpointed = false; \ list_move_tail(&ne->list, &nm_i->dirty_nat_entries); \ - } while (0); + } while (0) #define __clear_nat_cache_dirty(nm_i, ne) \ do { \ ne->checkpointed = true; \ list_move_tail(&ne->list, &nm_i->nat_entries); \ - } while (0); + } while (0) #define inc_node_version(version) (++version) static inline void node_info_from_raw_nat(struct node_info *ni, @@ -75,9 +75,18 @@ static inline void node_info_from_raw_nat(struct node_info *ni, ni->version = raw_ne->version; } -enum nid_type { +static inline void raw_nat_from_node_info(struct f2fs_nat_entry *raw_ne, + struct node_info *ni) +{ + raw_ne->ino = cpu_to_le32(ni->ino); + raw_ne->block_addr = cpu_to_le32(ni->blk_addr); + raw_ne->version = ni->version; +} + +enum mem_type { FREE_NIDS, /* indicates the free nid list */ - NAT_ENTRIES /* indicates the cached nat entry */ + NAT_ENTRIES, /* indicates the cached nat entry */ + DIRTY_DENTS /* indicates dirty dentry pages */ }; /* @@ -263,7 +272,7 @@ static inline void set_nid(struct page *p, int off, nid_t nid, bool i) { struct f2fs_node *rn = F2FS_NODE(p); - wait_on_page_writeback(p); + f2fs_wait_on_page_writeback(p, NODE); if (i) rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid); diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index b1ae89f0f44e53..e950a2f50ac117 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -46,15 +46,17 @@ static int recover_dentry(struct page *ipage, struct inode *inode) struct inode *dir, *einode; int err = 0; - dir = check_dirty_dir_inode(F2FS_SB(inode->i_sb), pino); - if (!dir) { - dir = f2fs_iget(inode->i_sb, pino); - if (IS_ERR(dir)) { - err = PTR_ERR(dir); - goto out; - } - set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT); + dir = f2fs_iget(inode->i_sb, pino); + if (IS_ERR(dir)) { + err = PTR_ERR(dir); + goto out; + } + + if (is_inode_flag_set(F2FS_I(dir), FI_DIRTY_DIR)) { + iput(dir); + } else { add_dirty_dir_inode(dir); + set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT); } name.len = le32_to_cpu(raw_inode->i_namelen); @@ -73,7 +75,8 @@ static int recover_dentry(struct page *ipage, struct inode *inode) einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino)); if (IS_ERR(einode)) { WARN_ON(1); - if (PTR_ERR(einode) == -ENOENT) + err = PTR_ERR(einode); + if (err == -ENOENT) err = -EEXIST; goto out_unmap_put; } @@ -299,10 +302,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, goto out; start = start_bidx_of_node(ofs_of_node(page), fi); - if (IS_INODE(page)) - end = start + ADDRS_PER_INODE(fi); - else - end = start + ADDRS_PER_BLOCK; + end = start + ADDRS_PER_PAGE(page, fi); f2fs_lock_op(sbi); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 085f548be7a31e..2ecbffb91f370f 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -200,20 +200,20 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) static int issue_flush_thread(void *data) { struct f2fs_sb_info *sbi = data; - struct f2fs_sm_info *sm_i = SM_I(sbi); - wait_queue_head_t *q = &sm_i->flush_wait_queue; + struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info; + wait_queue_head_t *q = &fcc->flush_wait_queue; repeat: if (kthread_should_stop()) return 0; - spin_lock(&sm_i->issue_lock); - if (sm_i->issue_list) { - sm_i->dispatch_list = sm_i->issue_list; - sm_i->issue_list = sm_i->issue_tail = NULL; + spin_lock(&fcc->issue_lock); + if (fcc->issue_list) { + fcc->dispatch_list = fcc->issue_list; + fcc->issue_list = fcc->issue_tail = NULL; } - spin_unlock(&sm_i->issue_lock); + spin_unlock(&fcc->issue_lock); - if (sm_i->dispatch_list) { + if (fcc->dispatch_list) { struct bio *bio = bio_alloc(GFP_NOIO, 0); struct flush_cmd *cmd, *next; int ret; @@ -221,42 +221,42 @@ static int issue_flush_thread(void *data) bio->bi_bdev = sbi->sb->s_bdev; ret = submit_bio_wait(WRITE_FLUSH, bio); - for (cmd = sm_i->dispatch_list; cmd; cmd = next) { + for (cmd = fcc->dispatch_list; cmd; cmd = next) { cmd->ret = ret; next = cmd->next; complete(&cmd->wait); } - sm_i->dispatch_list = NULL; + bio_put(bio); + fcc->dispatch_list = NULL; } - wait_event_interruptible(*q, kthread_should_stop() || sm_i->issue_list); + wait_event_interruptible(*q, + kthread_should_stop() || fcc->issue_list); goto repeat; } int f2fs_issue_flush(struct f2fs_sb_info *sbi) { - struct f2fs_sm_info *sm_i = SM_I(sbi); + struct flush_cmd_control *fcc = SM_I(sbi)->cmd_control_info; struct flush_cmd *cmd; int ret; if (!test_opt(sbi, FLUSH_MERGE)) return blkdev_issue_flush(sbi->sb->s_bdev, GFP_KERNEL, NULL); - cmd = f2fs_kmem_cache_alloc(flush_cmd_slab, GFP_ATOMIC); - cmd->next = NULL; - cmd->ret = 0; + cmd = f2fs_kmem_cache_alloc(flush_cmd_slab, GFP_ATOMIC | __GFP_ZERO); init_completion(&cmd->wait); - spin_lock(&sm_i->issue_lock); - if (sm_i->issue_list) - sm_i->issue_tail->next = cmd; + spin_lock(&fcc->issue_lock); + if (fcc->issue_list) + fcc->issue_tail->next = cmd; else - sm_i->issue_list = cmd; - sm_i->issue_tail = cmd; - spin_unlock(&sm_i->issue_lock); + fcc->issue_list = cmd; + fcc->issue_tail = cmd; + spin_unlock(&fcc->issue_lock); - if (!sm_i->dispatch_list) - wake_up(&sm_i->flush_wait_queue); + if (!fcc->dispatch_list) + wake_up(&fcc->flush_wait_queue); wait_for_completion(&cmd->wait); ret = cmd->ret; @@ -264,6 +264,40 @@ int f2fs_issue_flush(struct f2fs_sb_info *sbi) return ret; } +int create_flush_cmd_control(struct f2fs_sb_info *sbi) +{ + dev_t dev = sbi->sb->s_bdev->bd_dev; + struct flush_cmd_control *fcc; + int err = 0; + + fcc = kzalloc(sizeof(struct flush_cmd_control), GFP_KERNEL); + if (!fcc) + return -ENOMEM; + spin_lock_init(&fcc->issue_lock); + init_waitqueue_head(&fcc->flush_wait_queue); + fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi, + "f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev)); + if (IS_ERR(fcc->f2fs_issue_flush)) { + err = PTR_ERR(fcc->f2fs_issue_flush); + kfree(fcc); + return err; + } + sbi->sm_info->cmd_control_info = fcc; + + return err; +} + +void destroy_flush_cmd_control(struct f2fs_sb_info *sbi) +{ + struct flush_cmd_control *fcc = + sbi->sm_info->cmd_control_info; + + if (fcc && fcc->f2fs_issue_flush) + kthread_stop(fcc->f2fs_issue_flush); + kfree(fcc); + sbi->sm_info->cmd_control_info = NULL; +} + static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, enum dirty_type dirty_type) { @@ -336,13 +370,26 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) mutex_unlock(&dirty_i->seglist_lock); } -static void f2fs_issue_discard(struct f2fs_sb_info *sbi, +static int f2fs_issue_discard(struct f2fs_sb_info *sbi, block_t blkstart, block_t blklen) { sector_t start = SECTOR_FROM_BLOCK(sbi, blkstart); sector_t len = SECTOR_FROM_BLOCK(sbi, blklen); - blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0); trace_f2fs_issue_discard(sbi->sb, blkstart, blklen); + return blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0); +} + +void discard_next_dnode(struct f2fs_sb_info *sbi) +{ + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); + block_t blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); + + if (f2fs_issue_discard(sbi, blkaddr, 1)) { + struct page *page = grab_meta_page(sbi, blkaddr); + /* zero-filled page */ + set_page_dirty(page); + f2fs_put_page(page, 1); + } } static void add_discard_addrs(struct f2fs_sb_info *sbi, @@ -1832,7 +1879,6 @@ int build_segment_manager(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); - dev_t dev = sbi->sb->s_bdev->bd_dev; struct f2fs_sm_info *sm_info; int err; @@ -1860,14 +1906,10 @@ int build_segment_manager(struct f2fs_sb_info *sbi) sm_info->nr_discards = 0; sm_info->max_discards = 0; - if (test_opt(sbi, FLUSH_MERGE)) { - spin_lock_init(&sm_info->issue_lock); - init_waitqueue_head(&sm_info->flush_wait_queue); - - sm_info->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi, - "f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev)); - if (IS_ERR(sm_info->f2fs_issue_flush)) - return PTR_ERR(sm_info->f2fs_issue_flush); + if (test_opt(sbi, FLUSH_MERGE) && !f2fs_readonly(sbi->sb)) { + err = create_flush_cmd_control(sbi); + if (err) + return err; } err = build_sit_info(sbi); @@ -1976,10 +2018,10 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi) void destroy_segment_manager(struct f2fs_sb_info *sbi) { struct f2fs_sm_info *sm_info = SM_I(sbi); + if (!sm_info) return; - if (sm_info->f2fs_issue_flush) - kthread_stop(sm_info->f2fs_issue_flush); + destroy_flush_cmd_control(sbi); destroy_dirty_segmap(sbi); destroy_curseg(sbi); destroy_free_segmap(sbi); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index c756923a7302cc..b2b18637cb9eff 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -514,7 +514,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) { struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb); - if (!(root->d_sb->s_flags & MS_RDONLY) && test_opt(sbi, BG_GC)) + if (!f2fs_readonly(sbi->sb) && test_opt(sbi, BG_GC)) seq_printf(seq, ",background_gc=%s", "on"); else seq_printf(seq, ",background_gc=%s", "off"); @@ -542,7 +542,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",disable_ext_identify"); if (test_opt(sbi, INLINE_DATA)) seq_puts(seq, ",inline_data"); - if (test_opt(sbi, FLUSH_MERGE)) + if (!f2fs_readonly(sbi->sb) && test_opt(sbi, FLUSH_MERGE)) seq_puts(seq, ",flush_merge"); seq_printf(seq, ",active_logs=%u", sbi->active_logs); @@ -594,6 +594,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) struct f2fs_sb_info *sbi = F2FS_SB(sb); struct f2fs_mount_info org_mount_opt; int err, active_logs; + bool need_restart_gc = false; + bool need_stop_gc = false; sync_filesystem(sb); @@ -611,7 +613,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) /* * Previous and new state of filesystem is RO, - * so no point in checking GC conditions. + * so skip checking GC and FLUSH_MERGE conditions. */ if ((sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) goto skip; @@ -625,18 +627,40 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) if (sbi->gc_thread) { stop_gc_thread(sbi); f2fs_sync_fs(sb, 1); + need_restart_gc = true; } } else if (test_opt(sbi, BG_GC) && !sbi->gc_thread) { err = start_gc_thread(sbi); if (err) goto restore_opts; + need_stop_gc = true; + } + + /* + * We stop issue flush thread if FS is mounted as RO + * or if flush_merge is not passed in mount option. + */ + if ((*flags & MS_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) { + destroy_flush_cmd_control(sbi); + } else if (test_opt(sbi, FLUSH_MERGE) && + !sbi->sm_info->cmd_control_info) { + err = create_flush_cmd_control(sbi); + if (err) + goto restore_gc; } skip: /* Update the POSIXACL Flag */ sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0); return 0; - +restore_gc: + if (need_restart_gc) { + if (start_gc_thread(sbi)) + f2fs_msg(sbi->sb, KERN_WARNING, + "background gc thread is stop"); + } else if (need_stop_gc) { + stop_gc_thread(sbi); + } restore_opts: sbi->mount_opt = org_mount_opt; sbi->active_logs = active_logs; diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 503c2451131e5b..1f546b4b6b6191 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -26,7 +26,7 @@ #include "xattr.h" static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list, - size_t list_size, const char *name, size_t name_len, int type) + size_t list_size, const char *name, size_t len, int type) { struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); int total_len, prefix_len = 0; @@ -53,11 +53,11 @@ static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list, return -EINVAL; } - total_len = prefix_len + name_len + 1; + total_len = prefix_len + len + 1; if (list && total_len <= list_size) { memcpy(list, prefix, prefix_len); - memcpy(list + prefix_len, name, name_len); - list[prefix_len + name_len] = '\0'; + memcpy(list + prefix_len, name, len); + list[prefix_len + len] = '\0'; } return total_len; } @@ -108,11 +108,12 @@ static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, if (strcmp(name, "") == 0) return -EINVAL; - return f2fs_setxattr(dentry->d_inode, type, name, value, size, NULL); + return f2fs_setxattr(dentry->d_inode, type, name, + value, size, NULL, flags); } static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list, - size_t list_size, const char *name, size_t name_len, int type) + size_t list_size, const char *name, size_t len, int type) { const char *xname = F2FS_SYSTEM_ADVISE_PREFIX; size_t size; @@ -155,9 +156,10 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name, } #ifdef CONFIG_F2FS_FS_SECURITY -static int __f2fs_setxattr(struct inode *inode, int name_index, - const char *name, const void *value, size_t value_len, - struct page *ipage); +static int __f2fs_setxattr(struct inode *inode, int index, + const char *name, const void *value, size_t size, + struct page *ipage, int); + static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array, void *page) { @@ -167,7 +169,7 @@ static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array, for (xattr = xattr_array; xattr->name != NULL; xattr++) { err = __f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY, xattr->name, xattr->value, - xattr->value_len, (struct page *)page); + xattr->value_len, (struct page *)page, 0); if (err < 0) break; } @@ -241,26 +243,26 @@ const struct xattr_handler *f2fs_xattr_handlers[] = { NULL, }; -static inline const struct xattr_handler *f2fs_xattr_handler(int name_index) +static inline const struct xattr_handler *f2fs_xattr_handler(int index) { const struct xattr_handler *handler = NULL; - if (name_index > 0 && name_index < ARRAY_SIZE(f2fs_xattr_handler_map)) - handler = f2fs_xattr_handler_map[name_index]; + if (index > 0 && index < ARRAY_SIZE(f2fs_xattr_handler_map)) + handler = f2fs_xattr_handler_map[index]; return handler; } -static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int name_index, - size_t name_len, const char *name) +static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index, + size_t len, const char *name) { struct f2fs_xattr_entry *entry; list_for_each_xattr(entry, base_addr) { - if (entry->e_name_index != name_index) + if (entry->e_name_index != index) continue; - if (entry->e_name_len != name_len) + if (entry->e_name_len != len) continue; - if (!memcmp(entry->e_name, name, name_len)) + if (!memcmp(entry->e_name, name, len)) break; } return entry; @@ -347,6 +349,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, if (ipage) { inline_addr = inline_xattr_addr(ipage); + f2fs_wait_on_page_writeback(ipage, NODE); } else { page = get_node_page(sbi, inode->i_ino); if (IS_ERR(page)) { @@ -354,6 +357,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, return PTR_ERR(page); } inline_addr = inline_xattr_addr(page); + f2fs_wait_on_page_writeback(page, NODE); } memcpy(inline_addr, txattr_addr, inline_size); f2fs_put_page(page, 1); @@ -374,6 +378,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, return PTR_ERR(xpage); } f2fs_bug_on(new_nid); + f2fs_wait_on_page_writeback(xpage, NODE); } else { struct dnode_of_data dn; set_new_dnode(&dn, inode, NULL, NULL, new_nid); @@ -396,42 +401,43 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, return 0; } -int f2fs_getxattr(struct inode *inode, int name_index, const char *name, +int f2fs_getxattr(struct inode *inode, int index, const char *name, void *buffer, size_t buffer_size) { struct f2fs_xattr_entry *entry; void *base_addr; int error = 0; - size_t value_len, name_len; + size_t size, len; if (name == NULL) return -EINVAL; - name_len = strlen(name); - if (name_len > F2FS_NAME_LEN) + + len = strlen(name); + if (len > F2FS_NAME_LEN) return -ERANGE; base_addr = read_all_xattrs(inode, NULL); if (!base_addr) return -ENOMEM; - entry = __find_xattr(base_addr, name_index, name_len, name); + entry = __find_xattr(base_addr, index, len, name); if (IS_XATTR_LAST_ENTRY(entry)) { error = -ENODATA; goto cleanup; } - value_len = le16_to_cpu(entry->e_value_size); + size = le16_to_cpu(entry->e_value_size); - if (buffer && value_len > buffer_size) { + if (buffer && size > buffer_size) { error = -ERANGE; goto cleanup; } if (buffer) { char *pval = entry->e_name + entry->e_name_len; - memcpy(buffer, pval, value_len); + memcpy(buffer, pval, size); } - error = value_len; + error = size; cleanup: kzfree(base_addr); @@ -475,15 +481,15 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) return error; } -static int __f2fs_setxattr(struct inode *inode, int name_index, - const char *name, const void *value, size_t value_len, - struct page *ipage) +static int __f2fs_setxattr(struct inode *inode, int index, + const char *name, const void *value, size_t size, + struct page *ipage, int flags) { struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_xattr_entry *here, *last; void *base_addr; int found, newsize; - size_t name_len; + size_t len; __u32 new_hsize; int error = -ENOMEM; @@ -491,11 +497,11 @@ static int __f2fs_setxattr(struct inode *inode, int name_index, return -EINVAL; if (value == NULL) - value_len = 0; + size = 0; - name_len = strlen(name); + len = strlen(name); - if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN(inode)) + if (len > F2FS_NAME_LEN || size > MAX_VALUE_LEN(inode)) return -ERANGE; base_addr = read_all_xattrs(inode, ipage); @@ -503,16 +509,23 @@ static int __f2fs_setxattr(struct inode *inode, int name_index, goto exit; /* find entry with wanted name. */ - here = __find_xattr(base_addr, name_index, name_len, name); + here = __find_xattr(base_addr, index, len, name); found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1; - last = here; + if ((flags & XATTR_REPLACE) && !found) { + error = -ENODATA; + goto exit; + } else if ((flags & XATTR_CREATE) && found) { + error = -EEXIST; + goto exit; + } + + last = here; while (!IS_XATTR_LAST_ENTRY(last)) last = XATTR_NEXT_ENTRY(last); - newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + - name_len + value_len); + newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size); /* 1. Check space */ if (value) { @@ -555,12 +568,12 @@ static int __f2fs_setxattr(struct inode *inode, int name_index, * We just write new entry. */ memset(last, 0, newsize); - last->e_name_index = name_index; - last->e_name_len = name_len; - memcpy(last->e_name, name, name_len); - pval = last->e_name + name_len; - memcpy(pval, value, value_len); - last->e_value_size = cpu_to_le16(value_len); + last->e_name_index = index; + last->e_name_len = len; + memcpy(last->e_name, name, len); + pval = last->e_name + len; + memcpy(pval, value, size); + last->e_value_size = cpu_to_le16(size); new_hsize += newsize; } @@ -583,8 +596,9 @@ static int __f2fs_setxattr(struct inode *inode, int name_index, return error; } -int f2fs_setxattr(struct inode *inode, int name_index, const char *name, - const void *value, size_t value_len, struct page *ipage) +int f2fs_setxattr(struct inode *inode, int index, const char *name, + const void *value, size_t size, + struct page *ipage, int flags) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); int err; @@ -594,7 +608,7 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name, f2fs_lock_op(sbi); /* protect xattr_ver */ down_write(&F2FS_I(inode)->i_sem); - err = __f2fs_setxattr(inode, name_index, name, value, value_len, ipage); + err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags); up_write(&F2FS_I(inode)->i_sem); f2fs_unlock_op(sbi); diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index b21d9ebdeff39e..34ab7dbcf5e3f0 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h @@ -114,18 +114,18 @@ extern const struct xattr_handler f2fs_xattr_security_handler; extern const struct xattr_handler *f2fs_xattr_handlers[]; extern int f2fs_setxattr(struct inode *, int, const char *, - const void *, size_t, struct page *); + const void *, size_t, struct page *, int); extern int f2fs_getxattr(struct inode *, int, const char *, void *, size_t); extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t); #else #define f2fs_xattr_handlers NULL -static inline int f2fs_setxattr(struct inode *inode, int name_index, - const char *name, const void *value, size_t value_len) +static inline int f2fs_setxattr(struct inode *inode, int index, + const char *name, const void *value, size_t size, int flags) { return -EOPNOTSUPP; } -static inline int f2fs_getxattr(struct inode *inode, int name_index, +static inline int f2fs_getxattr(struct inode *inode, int index, const char *name, void *buffer, size_t buffer_size) { return -EOPNOTSUPP; diff --git a/fs/fat/file.c b/fs/fat/file.c index e33c8a2cb99c0d..92e9e753b554df 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -174,10 +174,10 @@ int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) const struct file_operations fat_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .release = fat_file_release, .unlocked_ioctl = fat_generic_ioctl, diff --git a/fs/fat/inode.c b/fs/fat/inode.c index d44c5107535afd..e72afce295f36b 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -270,12 +270,13 @@ static int fat_write_end(struct file *file, struct address_space *mapping, } static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, - loff_t offset, unsigned long nr_segs) + struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; + size_t count = iov_iter_count(iter); ssize_t ret; if (rw == WRITE) { @@ -288,7 +289,7 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, * * Return 0, and fallback to normal buffered write. */ - loff_t size = offset + iov_length(iov, nr_segs); + loff_t size = offset + count; if (MSDOS_I(inode)->mmu_private < size) return 0; @@ -304,10 +305,9 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, * FAT need to use the DIO_LOCKING for avoiding the race * condition of fat_get_block() and ->truncate(). */ - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - fat_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, fat_get_block); if (ret < 0 && (rw & WRITE)) - fat_write_failed(mapping, offset + iov_length(iov, nr_segs)); + fat_write_failed(mapping, offset + count); return ret; } diff --git a/fs/file.c b/fs/file.c index 8f294cfac69749..66923fe3176e49 100644 --- a/fs/file.c +++ b/fs/file.c @@ -44,15 +44,10 @@ static void *alloc_fdmem(size_t size) return vmalloc(size); } -static void free_fdmem(void *ptr) -{ - is_vmalloc_addr(ptr) ? vfree(ptr) : kfree(ptr); -} - static void __free_fdtable(struct fdtable *fdt) { - free_fdmem(fdt->fd); - free_fdmem(fdt->open_fds); + kvfree(fdt->fd); + kvfree(fdt->open_fds); kfree(fdt); } @@ -130,7 +125,7 @@ static struct fdtable * alloc_fdtable(unsigned int nr) return fdt; out_arr: - free_fdmem(fdt->fd); + kvfree(fdt->fd); out_fdt: kfree(fdt); out: diff --git a/fs/file_table.c b/fs/file_table.c index a374f5033e97ba..f8cc881fbbfb3f 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -175,6 +175,12 @@ struct file *alloc_file(struct path *path, fmode_t mode, file->f_path = *path; file->f_inode = path->dentry->d_inode; file->f_mapping = path->dentry->d_inode->i_mapping; + if ((mode & FMODE_READ) && + likely(fop->read || fop->aio_read || fop->read_iter)) + mode |= FMODE_CAN_READ; + if ((mode & FMODE_WRITE) && + likely(fop->write || fop->aio_write || fop->write_iter)) + mode |= FMODE_CAN_WRITE; file->f_mode = mode; file->f_op = fop; if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index 13b691a8a7d2ea..966ace8b243fa3 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c @@ -94,8 +94,10 @@ static ssize_t cuse_read(struct file *file, char __user *buf, size_t count, loff_t pos = 0; struct iovec iov = { .iov_base = buf, .iov_len = count }; struct fuse_io_priv io = { .async = 0, .file = file }; + struct iov_iter ii; + iov_iter_init(&ii, READ, &iov, 1, count); - return fuse_direct_io(&io, &iov, 1, count, &pos, FUSE_DIO_CUSE); + return fuse_direct_io(&io, &ii, &pos, FUSE_DIO_CUSE); } static ssize_t cuse_write(struct file *file, const char __user *buf, @@ -104,12 +106,14 @@ static ssize_t cuse_write(struct file *file, const char __user *buf, loff_t pos = 0; struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count }; struct fuse_io_priv io = { .async = 0, .file = file }; + struct iov_iter ii; + iov_iter_init(&ii, WRITE, &iov, 1, count); /* * No locking or generic_write_checks(), the server is * responsible for locking and sanity checks. */ - return fuse_direct_io(&io, &iov, 1, count, &pos, + return fuse_direct_io(&io, &ii, &pos, FUSE_DIO_WRITE | FUSE_DIO_CUSE); } diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 42198359fa1b47..3c0d41a43c67f9 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -273,9 +273,6 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) invalid: ret = 0; - - if (!(flags & LOOKUP_RCU) && check_submounts_and_drop(entry) != 0) - ret = 1; goto out; } @@ -1288,9 +1285,7 @@ static int fuse_direntplus_link(struct file *file, d_drop(dentry); } else if (get_node_id(inode) != o->nodeid || ((o->attr.mode ^ inode->i_mode) & S_IFMT)) { - err = d_invalidate(dentry); - if (err) - goto out; + d_invalidate(dentry); } else if (is_bad_inode(inode)) { err = -EIO; goto out; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 96d513e01a5d53..9828cf227f8af0 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -933,8 +933,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, return err; } -static ssize_t fuse_file_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct inode *inode = iocb->ki_filp->f_mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); @@ -945,14 +944,14 @@ static ssize_t fuse_file_aio_read(struct kiocb *iocb, const struct iovec *iov, * i_size is up to date). */ if (fc->auto_inval_data || - (pos + iov_length(iov, nr_segs) > i_size_read(inode))) { + (iocb->ki_pos + iov_iter_count(to) > i_size_read(inode))) { int err; err = fuse_update_attributes(inode, NULL, iocb->ki_filp, NULL); if (err) return err; } - return generic_file_aio_read(iocb, iov, nr_segs, pos); + return generic_file_read_iter(iocb, to); } static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff, @@ -1183,19 +1182,17 @@ static ssize_t fuse_perform_write(struct file *file, return res > 0 ? res : err; } -static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; - size_t count = 0; - size_t ocount = 0; + size_t count = iov_iter_count(from); ssize_t written = 0; ssize_t written_buffered = 0; struct inode *inode = mapping->host; ssize_t err; - struct iov_iter i; loff_t endbyte = 0; + loff_t pos = iocb->ki_pos; if (get_fuse_conn(inode)->writeback_cache) { /* Update size (EOF optimization) and mode (SUID clearing) */ @@ -1203,17 +1200,9 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov, if (err) return err; - return generic_file_aio_write(iocb, iov, nr_segs, pos); + return generic_file_write_iter(iocb, from); } - WARN_ON(iocb->ki_pos != pos); - - ocount = 0; - err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ); - if (err) - return err; - - count = ocount; mutex_lock(&inode->i_mutex); /* We can write back this queue in page reclaim */ @@ -1226,6 +1215,7 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov, if (count == 0) goto out; + iov_iter_truncate(from, count); err = file_remove_suid(file); if (err) goto out; @@ -1235,16 +1225,13 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov, goto out; if (file->f_flags & O_DIRECT) { - written = generic_file_direct_write(iocb, iov, &nr_segs, pos, - count, ocount); - if (written < 0 || written == count) + written = generic_file_direct_write(iocb, from, pos); + if (written < 0 || !iov_iter_count(from)) goto out; pos += written; - count -= written; - iov_iter_init(&i, iov, nr_segs, count, written); - written_buffered = fuse_perform_write(file, mapping, &i, pos); + written_buffered = fuse_perform_write(file, mapping, from, pos); if (written_buffered < 0) { err = written_buffered; goto out; @@ -1263,8 +1250,7 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov, written += written_buffered; iocb->ki_pos = pos + written_buffered; } else { - iov_iter_init(&i, iov, nr_segs, count, 0); - written = fuse_perform_write(file, mapping, &i, pos); + written = fuse_perform_write(file, mapping, from, pos); if (written >= 0) iocb->ki_pos = pos + written; } @@ -1302,7 +1288,7 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii, size_t nbytes = 0; /* # bytes already packed in req */ /* Special case for kernel I/O: can copy directly into the buffer */ - if (segment_eq(get_fs(), KERNEL_DS)) { + if (ii->type & ITER_KVEC) { unsigned long user_addr = fuse_get_user_addr(ii); size_t frag_size = fuse_get_frag_size(ii, *nbytesp); @@ -1318,35 +1304,26 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii, while (nbytes < *nbytesp && req->num_pages < req->max_pages) { unsigned npages; - unsigned long user_addr = fuse_get_user_addr(ii); - unsigned offset = user_addr & ~PAGE_MASK; - size_t frag_size = fuse_get_frag_size(ii, *nbytesp - nbytes); - int ret; - + size_t start; unsigned n = req->max_pages - req->num_pages; - frag_size = min_t(size_t, frag_size, n << PAGE_SHIFT); - - npages = (frag_size + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; - npages = clamp(npages, 1U, n); - - ret = get_user_pages_fast(user_addr, npages, !write, - &req->pages[req->num_pages]); + ssize_t ret = iov_iter_get_pages(ii, + &req->pages[req->num_pages], + n * PAGE_SIZE, &start); if (ret < 0) return ret; - npages = ret; - frag_size = min_t(size_t, frag_size, - (npages << PAGE_SHIFT) - offset); - iov_iter_advance(ii, frag_size); + iov_iter_advance(ii, ret); + nbytes += ret; + + ret += start; + npages = (ret + PAGE_SIZE - 1) / PAGE_SIZE; - req->page_descs[req->num_pages].offset = offset; + req->page_descs[req->num_pages].offset = start; fuse_page_descs_length_init(req, req->num_pages, npages); req->num_pages += npages; req->page_descs[req->num_pages - 1].length -= - (npages << PAGE_SHIFT) - offset - frag_size; - - nbytes += frag_size; + (PAGE_SIZE - ret) & (PAGE_SIZE - 1); } if (write) @@ -1361,24 +1338,11 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii, static inline int fuse_iter_npages(const struct iov_iter *ii_p) { - struct iov_iter ii = *ii_p; - int npages = 0; - - while (iov_iter_count(&ii) && npages < FUSE_MAX_PAGES_PER_REQ) { - unsigned long user_addr = fuse_get_user_addr(&ii); - unsigned offset = user_addr & ~PAGE_MASK; - size_t frag_size = iov_iter_single_seg_count(&ii); - - npages += (frag_size + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; - iov_iter_advance(&ii, frag_size); - } - - return min(npages, FUSE_MAX_PAGES_PER_REQ); + return iov_iter_npages(ii_p, FUSE_MAX_PAGES_PER_REQ); } -ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, - unsigned long nr_segs, size_t count, loff_t *ppos, - int flags) +ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, + loff_t *ppos, int flags) { int write = flags & FUSE_DIO_WRITE; int cuse = flags & FUSE_DIO_CUSE; @@ -1388,18 +1352,16 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, struct fuse_conn *fc = ff->fc; size_t nmax = write ? fc->max_write : fc->max_read; loff_t pos = *ppos; + size_t count = iov_iter_count(iter); pgoff_t idx_from = pos >> PAGE_CACHE_SHIFT; pgoff_t idx_to = (pos + count - 1) >> PAGE_CACHE_SHIFT; ssize_t res = 0; struct fuse_req *req; - struct iov_iter ii; - - iov_iter_init(&ii, iov, nr_segs, count, 0); if (io->async) - req = fuse_get_req_for_background(fc, fuse_iter_npages(&ii)); + req = fuse_get_req_for_background(fc, fuse_iter_npages(iter)); else - req = fuse_get_req(fc, fuse_iter_npages(&ii)); + req = fuse_get_req(fc, fuse_iter_npages(iter)); if (IS_ERR(req)) return PTR_ERR(req); @@ -1415,7 +1377,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, size_t nres; fl_owner_t owner = current->files; size_t nbytes = min(count, nmax); - int err = fuse_get_user_pages(req, &ii, &nbytes, write); + int err = fuse_get_user_pages(req, iter, &nbytes, write); if (err) { res = err; break; @@ -1445,9 +1407,9 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, fuse_put_request(fc, req); if (io->async) req = fuse_get_req_for_background(fc, - fuse_iter_npages(&ii)); + fuse_iter_npages(iter)); else - req = fuse_get_req(fc, fuse_iter_npages(&ii)); + req = fuse_get_req(fc, fuse_iter_npages(iter)); if (IS_ERR(req)) break; } @@ -1462,9 +1424,8 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, EXPORT_SYMBOL_GPL(fuse_direct_io); static ssize_t __fuse_direct_read(struct fuse_io_priv *io, - const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos, - size_t count) + struct iov_iter *iter, + loff_t *ppos) { ssize_t res; struct file *file = io->file; @@ -1473,7 +1434,7 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io, if (is_bad_inode(inode)) return -EIO; - res = fuse_direct_io(io, iov, nr_segs, count, ppos, 0); + res = fuse_direct_io(io, iter, ppos, 0); fuse_invalidate_attr(inode); @@ -1485,22 +1446,26 @@ static ssize_t fuse_direct_read(struct file *file, char __user *buf, { struct fuse_io_priv io = { .async = 0, .file = file }; struct iovec iov = { .iov_base = buf, .iov_len = count }; - return __fuse_direct_read(&io, &iov, 1, ppos, count); + struct iov_iter ii; + iov_iter_init(&ii, READ, &iov, 1, count); + return __fuse_direct_read(&io, &ii, ppos); } static ssize_t __fuse_direct_write(struct fuse_io_priv *io, - const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) + struct iov_iter *iter, + loff_t *ppos) { struct file *file = io->file; struct inode *inode = file_inode(file); - size_t count = iov_length(iov, nr_segs); + size_t count = iov_iter_count(iter); ssize_t res; + res = generic_write_checks(file, ppos, &count, 0); - if (!res) - res = fuse_direct_io(io, iov, nr_segs, count, ppos, - FUSE_DIO_WRITE); + if (!res) { + iov_iter_truncate(iter, count); + res = fuse_direct_io(io, iter, ppos, FUSE_DIO_WRITE); + } fuse_invalidate_attr(inode); @@ -1514,13 +1479,15 @@ static ssize_t fuse_direct_write(struct file *file, const char __user *buf, struct inode *inode = file_inode(file); ssize_t res; struct fuse_io_priv io = { .async = 0, .file = file }; + struct iov_iter ii; + iov_iter_init(&ii, WRITE, &iov, 1, count); if (is_bad_inode(inode)) return -EIO; /* Don't allow parallel writes to the same file */ mutex_lock(&inode->i_mutex); - res = __fuse_direct_write(&io, &iov, 1, ppos); + res = __fuse_direct_write(&io, &ii, ppos); if (res > 0) fuse_write_update_size(inode, *ppos); mutex_unlock(&inode->i_mutex); @@ -2304,7 +2271,6 @@ static int fuse_file_flock(struct file *file, int cmd, struct file_lock *fl) struct fuse_file *ff = file->private_data; /* emulate flock with POSIX locks */ - fl->fl_owner = (fl_owner_t) file; ff->flock = true; err = fuse_setlk(file, fl, 1); } @@ -2375,7 +2341,7 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov, if (!bytes) return 0; - iov_iter_init(&ii, iov, nr_segs, bytes, 0); + iov_iter_init(&ii, to_user ? READ : WRITE, iov, nr_segs, bytes); while (iov_iter_count(&ii)) { struct page *page = pages[page_idx++]; @@ -2897,8 +2863,8 @@ static inline loff_t fuse_round_up(loff_t off) } static ssize_t -fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, - loff_t offset, unsigned long nr_segs) +fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { ssize_t ret = 0; struct file *file = iocb->ki_filp; @@ -2907,7 +2873,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t pos = 0; struct inode *inode; loff_t i_size; - size_t count = iov_length(iov, nr_segs); + size_t count = iov_iter_count(iter); struct fuse_io_priv *io; pos = offset; @@ -2922,6 +2888,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, if (offset >= i_size) return 0; count = min_t(loff_t, count, fuse_round_up(i_size - offset)); + iov_iter_truncate(iter, count); } io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL); @@ -2951,9 +2918,9 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, io->async = false; if (rw == WRITE) - ret = __fuse_direct_write(io, iov, nr_segs, &pos); + ret = __fuse_direct_write(io, iter, &pos); else - ret = __fuse_direct_read(io, iov, nr_segs, &pos, count); + ret = __fuse_direct_read(io, iter, &pos); if (io->async) { fuse_aio_complete(io, ret < 0 ? ret : 0, -1); @@ -3064,10 +3031,10 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, static const struct file_operations fuse_file_operations = { .llseek = fuse_file_llseek, - .read = do_sync_read, - .aio_read = fuse_file_aio_read, - .write = do_sync_write, - .aio_write = fuse_file_aio_write, + .read = new_sync_read, + .read_iter = fuse_file_read_iter, + .write = new_sync_write, + .write_iter = fuse_file_write_iter, .mmap = fuse_file_mmap, .open = fuse_open, .flush = fuse_flush, diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 7aa5c75e0de13d..e8e47a6ab5186b 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -880,9 +880,8 @@ int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, /** CUSE pass fuse_direct_io() a file which f_mapping->host is not from FUSE */ #define FUSE_DIO_CUSE (1 << 1) -ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, - unsigned long nr_segs, size_t count, loff_t *ppos, - int flags); +ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, + loff_t *ppos, int flags); long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, unsigned int flags); long fuse_ioctl_common(struct file *file, unsigned int cmd, diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index ce62dcac90b6ff..910838951d66c3 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -1041,8 +1041,7 @@ static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset) static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, - unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; @@ -1082,7 +1081,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, */ if (mapping->nrpages) { loff_t lstart = offset & (PAGE_CACHE_SIZE - 1); - loff_t len = iov_length(iov, nr_segs); + loff_t len = iov_iter_count(iter); loff_t end = PAGE_ALIGN(offset + len) - 1; rv = 0; @@ -1097,9 +1096,9 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, truncate_inode_pages_range(mapping, lstart, end); } - rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, - offset, nr_segs, gfs2_get_block_direct, - NULL, NULL, 0); + rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, + iter, offset, + gfs2_get_block_direct, NULL, NULL, 0); out: gfs2_glock_dq(&gh); gfs2_holder_uninit(&gh); diff --git a/fs/gfs2/dentry.c b/fs/gfs2/dentry.c index d3a5d4e29ba5f3..589f4ea9381c45 100644 --- a/fs/gfs2/dentry.c +++ b/fs/gfs2/dentry.c @@ -93,9 +93,6 @@ static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags) if (!had_lock) gfs2_glock_dq_uninit(&d_gh); invalid: - if (check_submounts_and_drop(dentry) != 0) - goto valid; - dput(parent); return 0; diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 80d67253623cb2..01b4c5b1bff8dd 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -684,7 +684,7 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end, } /** - * gfs2_file_aio_write - Perform a write to a file + * gfs2_file_write_iter - Perform a write to a file * @iocb: The io context * @iov: The data to write * @nr_segs: Number of @iov segments @@ -697,11 +697,9 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end, * */ -static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; - size_t writesize = iov_length(iov, nr_segs); struct gfs2_inode *ip = GFS2_I(file_inode(file)); int ret; @@ -709,7 +707,7 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov, if (ret) return ret; - gfs2_size_hint(file, pos, writesize); + gfs2_size_hint(file, iocb->ki_pos, iov_iter_count(from)); if (file->f_flags & O_APPEND) { struct gfs2_holder gh; @@ -720,7 +718,7 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov, gfs2_glock_dq_uninit(&gh); } - return generic_file_aio_write(iocb, iov, nr_segs, pos); + return generic_file_write_iter(iocb, from); } static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, @@ -1058,10 +1056,10 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) const struct file_operations gfs2_file_fops = { .llseek = gfs2_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = gfs2_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = gfs2_file_write_iter, .unlocked_ioctl = gfs2_ioctl, .mmap = gfs2_mmap, .open = gfs2_open, @@ -1070,7 +1068,7 @@ const struct file_operations gfs2_file_fops = { .lock = gfs2_lock, .flock = gfs2_flock, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, .setlease = gfs2_setlease, .fallocate = gfs2_fallocate, }; @@ -1090,17 +1088,17 @@ const struct file_operations gfs2_dir_fops = { const struct file_operations gfs2_file_fops_nolock = { .llseek = gfs2_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = gfs2_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = gfs2_file_write_iter, .unlocked_ioctl = gfs2_ioctl, .mmap = gfs2_mmap, .open = gfs2_open, .release = gfs2_release, .fsync = gfs2_fsync, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, .setlease = generic_setlease, .fallocate = gfs2_fallocate, }; diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index aec7f73832f080..c355f7320e448b 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -277,7 +277,7 @@ static inline int may_grant(const struct gfs2_glock *gl, const struct gfs2_holde static void gfs2_holder_wake(struct gfs2_holder *gh) { clear_bit(HIF_WAIT, &gh->gh_iflags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&gh->gh_iflags, HIF_WAIT); } @@ -411,7 +411,7 @@ static void gfs2_demote_wake(struct gfs2_glock *gl) { gl->gl_demote_state = LM_ST_EXCLUSIVE; clear_bit(GLF_DEMOTE, &gl->gl_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&gl->gl_flags, GLF_DEMOTE); } @@ -620,7 +620,7 @@ __acquires(&gl->gl_spin) out_sched: clear_bit(GLF_LOCK, &gl->gl_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); gl->gl_lockref.count++; if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) gl->gl_lockref.count--; @@ -628,7 +628,7 @@ __acquires(&gl->gl_spin) out_unlock: clear_bit(GLF_LOCK, &gl->gl_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return; } diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 54b66809e818e4..74d9a3dbf16fe8 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -221,7 +221,7 @@ static void inode_go_sync(struct gfs2_glock *gl) * Writeback of the data mapping may cause the dirty flag to be set * so we have to clear it again here. */ - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(GLF_DIRTY, &gl->gl_flags); } diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index c1eb555dc588e1..91f274de1246ca 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c @@ -1134,7 +1134,7 @@ static void gdlm_recover_done(void *arg, struct dlm_slot *slots, int num_slots, queue_delayed_work(gfs2_control_wq, &sdp->sd_control_work, 0); clear_bit(DFL_DLM_RECOVERY, &ls->ls_recover_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&ls->ls_recover_flags, DFL_DLM_RECOVERY); spin_unlock(&ls->ls_recover_spin); } @@ -1271,7 +1271,7 @@ static int gdlm_mount(struct gfs2_sbd *sdp, const char *table) ls->ls_first = !!test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags); clear_bit(SDF_NOJOURNALID, &sdp->sd_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&sdp->sd_flags, SDF_NOJOURNALID); return 0; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index a294d8d8bcd47f..2c1ae861dc9442 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -75,7 +75,7 @@ static void maybe_release_space(struct gfs2_bufdata *bd) unsigned int index = bd->bd_bh->b_blocknr - gl->gl_name.ln_number; struct gfs2_bitmap *bi = rgd->rd_bits + index; - if (bi->bi_clone == 0) + if (bi->bi_clone == NULL) return; if (sdp->sd_args.ar_discard) gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi, 1, NULL); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index c4effff7cf559c..619389649d03f5 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -778,6 +778,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, i_size_write(inode, size); inode->i_mtime = inode->i_atime = CURRENT_TIME; mark_inode_dirty(inode); + set_bit(QDF_REFRESH, &qd->qd_flags); return 0; unlock_out: diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 7ad4094d68c024..fe7a56fb608476 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -587,7 +587,7 @@ void gfs2_recover_func(struct work_struct *work) gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); done: clear_bit(JDF_RECOVERY, &jd->jd_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&jd->jd_flags, JDF_RECOVERY); } diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index de25d5577e5dd4..529d9a9eb89765 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -333,7 +333,7 @@ static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len) set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); else if (val == 0) { clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); gfs2_glock_thaw(sdp); } else { ret = -EINVAL; @@ -482,7 +482,7 @@ static ssize_t jid_store(struct gfs2_sbd *sdp, const char *buf, size_t len) rv = jid = -EINVAL; sdp->sd_lockstruct.ls_jid = jid; clear_bit(SDF_NOJOURNALID, &sdp->sd_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&sdp->sd_flags, SDF_NOJOURNALID); out: spin_unlock(&sdp->sd_jindex_spin); diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 9e2fecd62f6245..d0929bc817826e 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -125,15 +125,15 @@ static int hfs_releasepage(struct page *page, gfp_t mask) } static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = file_inode(file)->i_mapping->host; + size_t count = iov_iter_count(iter); ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - hfs_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, hfs_get_block); /* * In case of error extending write may have instantiated a few @@ -141,7 +141,7 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, */ if (unlikely((rw & WRITE) && ret < 0)) { loff_t isize = i_size_read(inode); - loff_t end = offset + iov_length(iov, nr_segs); + loff_t end = offset + count; if (end > isize) hfs_write_failed(mapping, end); @@ -674,10 +674,10 @@ static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end, static const struct file_operations hfs_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .splice_read = generic_file_splice_read, .fsync = hfs_file_fsync, diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index a4f45bd88a631a..0cf786f2d046f9 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -123,14 +123,15 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask) } static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = file_inode(file)->i_mapping->host; + size_t count = iov_iter_count(iter); ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, + ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, hfsplus_get_block); /* @@ -139,7 +140,7 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, */ if (unlikely((rw & WRITE) && ret < 0)) { loff_t isize = i_size_read(inode); - loff_t end = offset + iov_length(iov, nr_segs); + loff_t end = offset + count; if (end > isize) hfsplus_write_failed(mapping, end); @@ -340,10 +341,10 @@ static const struct inode_operations hfsplus_file_inode_operations = { static const struct file_operations hfsplus_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .splice_read = generic_file_splice_read, .fsync = hfsplus_file_fsync, diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 9c470fde9878ea..bb529f3b7f2bf8 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -378,11 +378,11 @@ static int hostfs_fsync(struct file *file, loff_t start, loff_t end, static const struct file_operations hostfs_file_fops = { .llseek = generic_file_llseek, - .read = do_sync_read, + .read = new_sync_read, .splice_read = generic_file_splice_read, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, - .write = do_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, + .write = new_sync_write, .mmap = generic_file_mmap, .open = hostfs_file_open, .release = hostfs_file_release, diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 67c1a61e09558e..7f54e5f76cecec 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -197,10 +197,10 @@ const struct address_space_operations hpfs_aops = { const struct file_operations hpfs_file_ops = { .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .release = hpfs_file_release, .fsync = hpfs_file_fsync, diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 5f26139a165a70..6fac7434985657 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -43,7 +43,7 @@ static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate) clear_buffer_uptodate(bh); if (orig_bh) { clear_bit_unlock(BH_Shadow, &orig_bh->b_state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&orig_bh->b_state, BH_Shadow); } unlock_buffer(bh); @@ -239,7 +239,7 @@ static int journal_submit_data_buffers(journal_t *journal, spin_lock(&journal->j_list_lock); J_ASSERT(jinode->i_transaction == commit_transaction); clear_bit(__JI_COMMIT_RUNNING, &jinode->i_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING); } spin_unlock(&journal->j_list_lock); @@ -277,7 +277,7 @@ static int journal_finish_inode_data_buffers(journal_t *journal, } spin_lock(&journal->j_list_lock); clear_bit(__JI_COMMIT_RUNNING, &jinode->i_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING); } diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 256cd19a3b78c0..64989ca9ba90b7 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -51,10 +51,10 @@ const struct file_operations jffs2_file_operations = { .llseek = generic_file_llseek, .open = generic_file_open, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .unlocked_ioctl=jffs2_ioctl, .mmap = generic_file_readonly_mmap, .fsync = jffs2_fsync, diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 794da944d5cd29..33aa0cc1f8b863 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -151,13 +151,13 @@ const struct inode_operations jfs_file_inode_operations = { const struct file_operations jfs_file_operations = { .open = jfs_open, .llseek = generic_file_llseek, - .write = do_sync_write, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .write = new_sync_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, .fsync = jfs_fsync, .release = jfs_release, .unlocked_ioctl = jfs_ioctl, diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 6f8fe72c2a7ae2..bd3df1ca3c9b7f 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -331,15 +331,15 @@ static sector_t jfs_bmap(struct address_space *mapping, sector_t block) } static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = file->f_mapping->host; + size_t count = iov_iter_count(iter); ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - jfs_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, jfs_get_block); /* * In case of error extending write may have instantiated a few @@ -347,7 +347,7 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, */ if (unlikely((rw & WRITE) && ret < 0)) { loff_t isize = i_size_read(inode); - loff_t end = offset + iov_length(iov, nr_segs); + loff_t end = offset + count; if (end > isize) jfs_write_failed(mapping, end); diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c index 7f464c513ba0a8..6b0f816201a229 100644 --- a/fs/jfs/jfs_inode.c +++ b/fs/jfs/jfs_inode.c @@ -29,20 +29,20 @@ void jfs_set_inode_flags(struct inode *inode) { unsigned int flags = JFS_IP(inode)->mode2; - - inode->i_flags &= ~(S_IMMUTABLE | S_APPEND | - S_NOATIME | S_DIRSYNC | S_SYNC); + unsigned int new_fl = 0; if (flags & JFS_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; + new_fl |= S_IMMUTABLE; if (flags & JFS_APPEND_FL) - inode->i_flags |= S_APPEND; + new_fl |= S_APPEND; if (flags & JFS_NOATIME_FL) - inode->i_flags |= S_NOATIME; + new_fl |= S_NOATIME; if (flags & JFS_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; + new_fl |= S_DIRSYNC; if (flags & JFS_SYNC_FL) - inode->i_flags |= S_SYNC; + new_fl |= S_SYNC; + inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND | S_NOATIME | + S_DIRSYNC | S_SYNC); } void jfs_get_inode_flags(struct jfs_inode_info *jfs_ip) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index ac127cd008bfeb..1c771931bb6024 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -463,21 +463,10 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) goto out_bad; mutex_unlock(&kernfs_mutex); -out_valid: return 1; out_bad: mutex_unlock(&kernfs_mutex); out_bad_unlocked: - /* - * @dentry doesn't match the underlying kernfs node, drop the - * dentry and force lookup. If we have submounts we must allow the - * vfs caches to lie about the state of the filesystem to prevent - * leaks and other nasty things, so use check_submounts_and_drop() - * instead of d_drop(). - */ - if (check_submounts_and_drop(dentry) != 0) - goto out_valid; - return 0; } @@ -714,6 +703,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, return ERR_PTR(-ENOMEM); ida_init(&root->ino_ida); + INIT_LIST_HEAD(&root->supers); kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO, KERNFS_DIR); diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index e01ea4a14a014b..40251cd741a083 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "kernfs-internal.h" @@ -787,20 +788,48 @@ static unsigned int kernfs_fop_poll(struct file *filp, poll_table *wait) */ void kernfs_notify(struct kernfs_node *kn) { + struct kernfs_root *root = kernfs_root(kn); struct kernfs_open_node *on; + struct kernfs_super_info *info; unsigned long flags; + if (WARN_ON(kernfs_type(kn) != KERNFS_FILE)) + return; + + /* kick poll */ spin_lock_irqsave(&kernfs_open_node_lock, flags); - if (!WARN_ON(kernfs_type(kn) != KERNFS_FILE)) { - on = kn->attr.open; - if (on) { - atomic_inc(&on->event); - wake_up_interruptible(&on->poll); - } + on = kn->attr.open; + if (on) { + atomic_inc(&on->event); + wake_up_interruptible(&on->poll); } spin_unlock_irqrestore(&kernfs_open_node_lock, flags); + + /* kick fsnotify */ + mutex_lock(&kernfs_mutex); + + list_for_each_entry(info, &root->supers, node) { + struct inode *inode; + struct dentry *dentry; + + inode = ilookup(info->sb, kn->ino); + if (!inode) + continue; + + dentry = d_find_any_alias(inode); + if (dentry) { + fsnotify_parent(NULL, dentry, FS_MODIFY); + fsnotify(inode, FS_MODIFY, inode, FSNOTIFY_EVENT_INODE, + NULL, 0); + dput(dentry); + } + + iput(inode); + } + + mutex_unlock(&kernfs_mutex); } EXPORT_SYMBOL_GPL(kernfs_notify); diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 8be13b2a079ba2..dc84a3ef9ca204 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -49,6 +49,8 @@ static inline struct kernfs_root *kernfs_root(struct kernfs_node *kn) * mount.c */ struct kernfs_super_info { + struct super_block *sb; + /* * The root associated with this super_block. Each super_block is * identified by the root and ns it's associated with. @@ -62,6 +64,9 @@ struct kernfs_super_info { * an array and compare kernfs_node tag against every entry. */ const void *ns; + + /* anchored at kernfs_root->supers, protected by kernfs_mutex */ + struct list_head node; }; #define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info)) diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 6a5f04ac87040d..f25a7c0c3cdc31 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -68,6 +68,7 @@ static int kernfs_fill_super(struct super_block *sb) struct inode *inode; struct dentry *root; + info->sb = sb; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = SYSFS_MAGIC; @@ -166,12 +167,18 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, *new_sb_created = !sb->s_root; if (!sb->s_root) { + struct kernfs_super_info *info = kernfs_info(sb); + error = kernfs_fill_super(sb); if (error) { deactivate_locked_super(sb); return ERR_PTR(error); } sb->s_flags |= MS_ACTIVE; + + mutex_lock(&kernfs_mutex); + list_add(&info->node, &root->supers); + mutex_unlock(&kernfs_mutex); } return dget(sb->s_root); @@ -190,6 +197,10 @@ void kernfs_kill_sb(struct super_block *sb) struct kernfs_super_info *info = kernfs_info(sb); struct kernfs_node *root_kn = sb->s_root->d_fsdata; + mutex_lock(&kernfs_mutex); + list_del(&info->node); + mutex_unlock(&kernfs_mutex); + /* * Remove the superblock from fs_supers/s_instances * so we can't find it, before freeing kernfs_super_info. diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c index 00ec0b9c94d116..d3e40db289302b 100644 --- a/fs/lockd/clnt4xdr.c +++ b/fs/lockd/clnt4xdr.c @@ -14,6 +14,8 @@ #include #include +#include + #define NLMDBG_FACILITY NLMDBG_XDR #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) diff --git a/fs/lockd/clntxdr.c b/fs/lockd/clntxdr.c index 9a55797a1cd420..3e9f7874b97554 100644 --- a/fs/lockd/clntxdr.c +++ b/fs/lockd/clntxdr.c @@ -15,6 +15,8 @@ #include #include +#include + #define NLMDBG_FACILITY NLMDBG_XDR #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 6bf06a07f3e00b..2b431f7266c391 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -622,8 +622,8 @@ static int __init init_nlm(void) err_pernet: #ifdef CONFIG_SYSCTL unregister_sysctl_table(nlm_sysctl_table); -#endif err_sysctl: +#endif return err; } diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index dc5c75930f0fea..b6f3b84b6e9975 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -14,12 +14,11 @@ #include #include #include -#include -#include #include #include #include #include +#include #define NLMDBG_FACILITY NLMDBG_SVCSUBS diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 964666c68a868a..9340e7e10ef60b 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -16,6 +16,8 @@ #include #include +#include + #define NLMDBG_FACILITY NLMDBG_XDR diff --git a/fs/locks.c b/fs/locks.c index e663aeac579e5d..2367f31186626b 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -130,6 +130,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + #include #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) @@ -322,6 +325,7 @@ static int flock_make_lock(struct file *filp, struct file_lock **lock, return -ENOMEM; fl->fl_file = filp; + fl->fl_owner = (fl_owner_t)filp; fl->fl_pid = current->tgid; fl->fl_flags = FL_FLOCK; fl->fl_type = type; @@ -439,7 +443,7 @@ static int lease_init(struct file *filp, long type, struct file_lock *fl) if (assign_type(fl, type) != 0) return -EINVAL; - fl->fl_owner = current->files; + fl->fl_owner = (fl_owner_t)filp; fl->fl_pid = current->tgid; fl->fl_file = filp; @@ -1385,6 +1389,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) } if (i_have_this_lease || (mode & O_NONBLOCK)) { + trace_break_lease_noblock(inode, new_fl); error = -EWOULDBLOCK; goto out; } @@ -1396,10 +1401,12 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) if (break_time == 0) break_time++; locks_insert_block(flock, new_fl); + trace_break_lease_block(inode, new_fl); spin_unlock(&inode->i_lock); error = wait_event_interruptible_timeout(new_fl->fl_wait, !new_fl->fl_next, break_time); spin_lock(&inode->i_lock); + trace_break_lease_unblock(inode, new_fl); locks_delete_block(new_fl); if (error >= 0) { if (error == 0) @@ -1521,6 +1528,8 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp int error; lease = *flp; + trace_generic_add_lease(inode, lease); + /* * In the delegation case we need mutual exclusion with * a number of operations that take the i_mutex. We trylock @@ -1610,6 +1619,8 @@ static int generic_delete_lease(struct file *filp, struct file_lock **flp) struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; + trace_generic_delete_lease(inode, *flp); + for (before = &inode->i_flock; ((fl = *before) != NULL) && IS_LEASE(fl); before = &fl->fl_next) { @@ -2304,6 +2315,7 @@ void locks_remove_file(struct file *filp) if (filp->f_op->flock) { struct file_lock fl = { + .fl_owner = (fl_owner_t)filp, .fl_pid = current->tgid, .fl_file = filp, .fl_flags = FL_FLOCK, @@ -2411,31 +2423,31 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, seq_printf(f, "%lld:%s ", id, pfx); if (IS_POSIX(fl)) { if (fl->fl_flags & FL_ACCESS) - seq_printf(f, "ACCESS"); + seq_puts(f, "ACCESS"); else if (IS_OFDLCK(fl)) - seq_printf(f, "OFDLCK"); + seq_puts(f, "OFDLCK"); else - seq_printf(f, "POSIX "); + seq_puts(f, "POSIX "); seq_printf(f, " %s ", (inode == NULL) ? "*NOINODE*" : mandatory_lock(inode) ? "MANDATORY" : "ADVISORY "); } else if (IS_FLOCK(fl)) { if (fl->fl_type & LOCK_MAND) { - seq_printf(f, "FLOCK MSNFS "); + seq_puts(f, "FLOCK MSNFS "); } else { - seq_printf(f, "FLOCK ADVISORY "); + seq_puts(f, "FLOCK ADVISORY "); } } else if (IS_LEASE(fl)) { - seq_printf(f, "LEASE "); + seq_puts(f, "LEASE "); if (lease_breaking(fl)) - seq_printf(f, "BREAKING "); + seq_puts(f, "BREAKING "); else if (fl->fl_file) - seq_printf(f, "ACTIVE "); + seq_puts(f, "ACTIVE "); else - seq_printf(f, "BREAKER "); + seq_puts(f, "BREAKER "); } else { - seq_printf(f, "UNKNOWN UNKNOWN "); + seq_puts(f, "UNKNOWN UNKNOWN "); } if (fl->fl_type & LOCK_MAND) { seq_printf(f, "%s ", @@ -2467,7 +2479,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, else seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end); } else { - seq_printf(f, "0 EOF\n"); + seq_puts(f, "0 EOF\n"); } } diff --git a/fs/logfs/dev_mtd.c b/fs/logfs/dev_mtd.c index 9c501449450dc9..427bb73e298f19 100644 --- a/fs/logfs/dev_mtd.c +++ b/fs/logfs/dev_mtd.c @@ -245,8 +245,8 @@ static int logfs_mtd_can_write_buf(struct super_block *sb, u64 ofs) goto out; if (memchr_inv(buf, 0xff, super->s_writesize)) err = -EIO; - kfree(buf); out: + kfree(buf); return err; } diff --git a/fs/logfs/file.c b/fs/logfs/file.c index 57914fc32b6253..8538752df2f6a7 100644 --- a/fs/logfs/file.c +++ b/fs/logfs/file.c @@ -264,15 +264,15 @@ const struct inode_operations logfs_reg_iops = { }; const struct file_operations logfs_reg_fops = { - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .fsync = logfs_fsync, .unlocked_ioctl = logfs_ioctl, .llseek = generic_file_llseek, .mmap = generic_file_readonly_mmap, .open = generic_file_open, - .read = do_sync_read, - .write = do_sync_write, + .read = new_sync_read, + .write = new_sync_write, }; const struct address_space_operations logfs_reg_aops = { diff --git a/fs/logfs/super.c b/fs/logfs/super.c index 54360293bcb5cd..b256c0690e5b66 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c @@ -287,14 +287,14 @@ static int logfs_make_writeable(struct super_block *sb) if (err) return err; + /* Do one GC pass before any data gets dirtied */ + logfs_gc_pass(sb); + /* Check areas for trailing unaccounted data */ err = logfs_check_areas(sb); if (err) return err; - /* Do one GC pass before any data gets dirtied */ - logfs_gc_pass(sb); - /* after all initializations are done, replay the journal * for rw-mounts, if necessary */ err = logfs_replay_journal(sb); diff --git a/fs/minix/file.c b/fs/minix/file.c index adc6f5494231bc..a967de085ac0f4 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c @@ -14,10 +14,10 @@ */ const struct file_operations minix_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .fsync = generic_file_fsync, .splice_read = generic_file_splice_read, diff --git a/fs/mount.h b/fs/mount.h index d55297f2fa058c..84c282321d6764 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -21,6 +21,7 @@ struct mnt_pcp { struct mountpoint { struct hlist_node m_hash; struct dentry *m_dentry; + struct list_head m_list; int m_count; }; @@ -48,6 +49,7 @@ struct mount { struct mount *mnt_master; /* slave is on master->mnt_slave_list */ struct mnt_namespace *mnt_ns; /* containing namespace */ struct mountpoint *mnt_mp; /* where is it mounted */ + struct list_head mnt_mp_list; /* list mounts with the same mountpoint */ #ifdef CONFIG_FSNOTIFY struct hlist_head mnt_fsnotify_marks; __u32 mnt_fsnotify_mask; @@ -57,6 +59,8 @@ struct mount { int mnt_expiry_mark; /* true if marked for expiry */ int mnt_pinned; struct path mnt_ex_mountpoint; + struct work_struct mnt_cleanup_work; + struct completion *mnt_undone; }; #define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */ @@ -82,6 +86,15 @@ extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *); extern bool legitimize_mnt(struct vfsmount *, unsigned); +extern void __detach_mounts(struct dentry *dentry); + +static inline void detach_mounts(struct dentry *dentry) +{ + if (!d_mountpoint(dentry)) + return; + __detach_mounts(dentry); +} + static inline void get_mnt_ns(struct mnt_namespace *ns) { atomic_inc(&ns->count); @@ -112,3 +125,12 @@ struct proc_mounts { #define proc_mounts(p) (container_of((p), struct proc_mounts, m)) extern const struct seq_operations mounts_op; + +extern bool __is_local_mountpoint(struct dentry *dentry); +static inline bool is_local_mountpoint(struct dentry *dentry) +{ + if (!d_mountpoint(dentry)) + return false; + + return __is_local_mountpoint(dentry); +} diff --git a/fs/namei.c b/fs/namei.c index 80168273396bba..322069384b5ea9 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1291,7 +1291,8 @@ static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir, if (error < 0) { dput(dentry); return ERR_PTR(error); - } else if (!d_invalidate(dentry)) { + } else { + d_invalidate(dentry); dput(dentry); dentry = NULL; } @@ -1423,10 +1424,9 @@ static int lookup_fast(struct nameidata *nd, dput(dentry); return status; } - if (!d_invalidate(dentry)) { - dput(dentry); - goto need_lookup; - } + d_invalidate(dentry); + dput(dentry); + goto need_lookup; } path->mnt = mnt; @@ -3548,7 +3548,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) mutex_lock(&dentry->d_inode->i_mutex); error = -EBUSY; - if (d_mountpoint(dentry)) + if (is_local_mountpoint(dentry)) goto out; error = security_inode_rmdir(dir, dentry); @@ -3562,6 +3562,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) dentry->d_inode->i_flags |= S_DEAD; dont_mount(dentry); + detach_mounts(dentry); out: mutex_unlock(&dentry->d_inode->i_mutex); @@ -3664,7 +3665,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate return -EPERM; mutex_lock(&target->i_mutex); - if (d_mountpoint(dentry)) + if (is_local_mountpoint(dentry)) error = -EBUSY; else { error = security_inode_unlink(dir, dentry); @@ -3673,8 +3674,10 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate if (error) goto out; error = dir->i_op->unlink(dir, dentry); - if (!error) + if (!error) { dont_mount(dentry); + detach_mounts(dentry); + } } } out: @@ -4109,7 +4112,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, mutex_lock(&target->i_mutex); error = -EBUSY; - if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry)) + if (is_local_mountpoint(old_dentry) || is_local_mountpoint(new_dentry)) goto out; if (max_links && new_dir != old_dir) { @@ -4146,6 +4149,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (is_dir) target->i_flags |= S_DEAD; dont_mount(new_dentry); + detach_mounts(new_dentry); } if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) { if (!(flags & RENAME_EXCHANGE)) diff --git a/fs/namespace.c b/fs/namespace.c index 182bc41cd88711..b10db3d699431d 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -225,6 +225,7 @@ static struct mount *alloc_vfsmnt(const char *name) INIT_LIST_HEAD(&mnt->mnt_share); INIT_LIST_HEAD(&mnt->mnt_slave_list); INIT_LIST_HEAD(&mnt->mnt_slave); + INIT_LIST_HEAD(&mnt->mnt_mp_list); #ifdef CONFIG_FSNOTIFY INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks); #endif @@ -667,11 +668,45 @@ struct vfsmount *lookup_mnt(struct path *path) return m; } -static struct mountpoint *new_mountpoint(struct dentry *dentry) +/* + * __is_local_mountpoint - Test to see if dentry is a mountpoint in the + * current mount namespace. + * + * The common case is dentries are not mountpoints at all and that + * test is handled inline. For the slow case when we are actually + * dealing with a mountpoint of some kind, walk through all of the + * mounts in the current mount namespace and test to see if the dentry + * is a mountpoint. + * + * The mount_hashtable is not usable in the context because we + * need to identify all mounts that may be in the current mount + * namespace not just a mount that happens to have some specified + * parent mount. + */ +bool __is_local_mountpoint(struct dentry *dentry) +{ + struct mnt_namespace *ns = current->nsproxy->mnt_ns; + struct mount *mnt; + bool is_covered = false; + + if (!d_mountpoint(dentry)) + goto out; + + down_read(&namespace_sem); + list_for_each_entry(mnt, &ns->list, mnt_list) { + is_covered = (mnt->mnt_mountpoint == dentry); + if (is_covered) + break; + } + up_read(&namespace_sem); +out: + return is_covered; +} + +static struct mountpoint *lookup_mountpoint(struct dentry *dentry) { struct hlist_head *chain = mp_hash(dentry); struct mountpoint *mp; - int ret; hlist_for_each_entry(mp, chain, m_hash) { if (mp->m_dentry == dentry) { @@ -682,6 +717,14 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry) return mp; } } + return NULL; +} + +static struct mountpoint *new_mountpoint(struct dentry *dentry) +{ + struct hlist_head *chain = mp_hash(dentry); + struct mountpoint *mp; + int ret; mp = kmalloc(sizeof(struct mountpoint), GFP_KERNEL); if (!mp) @@ -696,6 +739,7 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry) mp->m_dentry = dentry; mp->m_count = 1; hlist_add_head(&mp->m_hash, chain); + INIT_LIST_HEAD(&mp->m_list); return mp; } @@ -703,6 +747,7 @@ static void put_mountpoint(struct mountpoint *mp) { if (!--mp->m_count) { struct dentry *dentry = mp->m_dentry; + BUG_ON(!list_empty(&mp->m_list)); spin_lock(&dentry->d_lock); dentry->d_flags &= ~DCACHE_MOUNTED; spin_unlock(&dentry->d_lock); @@ -749,6 +794,7 @@ static void detach_mnt(struct mount *mnt, struct path *old_path) mnt->mnt_mountpoint = mnt->mnt.mnt_root; list_del_init(&mnt->mnt_child); hlist_del_init_rcu(&mnt->mnt_hash); + list_del_init(&mnt->mnt_mp_list); put_mountpoint(mnt->mnt_mp); mnt->mnt_mp = NULL; } @@ -765,6 +811,7 @@ void mnt_set_mountpoint(struct mount *mnt, child_mnt->mnt_mountpoint = dget(mp->m_dentry); child_mnt->mnt_parent = mnt; child_mnt->mnt_mp = mp; + list_add_tail(&child_mnt->mnt_mp_list, &mp->m_list); } /* @@ -936,9 +983,25 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, return ERR_PTR(err); } +static void cleanup_mnt(struct mount *mnt) +{ + fsnotify_vfsmount_delete(&mnt->mnt); + dput(mnt->mnt.mnt_root); + deactivate_super(mnt->mnt.mnt_sb); + mnt_free_id(mnt); + complete(mnt->mnt_undone); + call_rcu(&mnt->mnt_rcu, delayed_free_vfsmnt); +} + +static void cleanup_mnt_work(struct work_struct *work) +{ + cleanup_mnt(container_of(work, struct mount, mnt_cleanup_work)); +} + static void mntput_no_expire(struct mount *mnt) { -put_again: + struct completion undone; + rcu_read_lock(); mnt_add_count(mnt, -1); if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */ @@ -952,12 +1015,15 @@ static void mntput_no_expire(struct mount *mnt) return; } if (unlikely(mnt->mnt_pinned)) { - mnt_add_count(mnt, mnt->mnt_pinned + 1); + init_completion(&undone); + mnt->mnt_undone = &undone; + mnt_add_count(mnt, mnt->mnt_pinned); mnt->mnt_pinned = 0; rcu_read_unlock(); unlock_mount_hash(); acct_auto_close_mnt(&mnt->mnt); - goto put_again; + wait_for_completion(&undone); + return; } if (unlikely(mnt->mnt.mnt_flags & MNT_DOOMED)) { rcu_read_unlock(); @@ -981,11 +1047,19 @@ static void mntput_no_expire(struct mount *mnt) * so mnt_get_writers() below is safe. */ WARN_ON(mnt_get_writers(mnt)); - fsnotify_vfsmount_delete(&mnt->mnt); - dput(mnt->mnt.mnt_root); - deactivate_super(mnt->mnt.mnt_sb); - mnt_free_id(mnt); - call_rcu(&mnt->mnt_rcu, delayed_free_vfsmnt); + /* The stack may be deep here, cleanup the mount on a work + * queue where the stack is guaranteed to be shallow. + */ + init_completion(&undone); + if (!mnt->mnt_undone) + mnt->mnt_undone = &undone; + else + complete(&undone); + + INIT_WORK(&mnt->mnt_cleanup_work, cleanup_mnt_work); + schedule_work(&mnt->mnt_cleanup_work); + + wait_for_completion(&undone); } void mntput(struct vfsmount *mnt) @@ -1261,6 +1335,7 @@ void umount_tree(struct mount *mnt, int how) p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; list_del_init(&p->mnt_child); if (mnt_has_parent(p)) { + list_del_init(&p->mnt_mp_list); put_mountpoint(p->mnt_mp); /* move the reference to mountpoint into ->mnt_ex_mountpoint */ p->mnt_ex_mountpoint.dentry = p->mnt_mountpoint; @@ -1373,6 +1448,37 @@ static int do_umount(struct mount *mnt, int flags) return retval; } +/* + * __detach_mounts - lazily unmount all mounts on the specified dentry + * + * During unlink, rmdir, and d_drop it is possible to loose the path + * to an existing mountpoint, and wind up leaking the mount. + * detach_mounts allows lazily unmounting those mounts instead of + * leaking them. + * + * The caller may hold dentry->d_inode->i_mutex. + */ +void __detach_mounts(struct dentry *dentry) +{ + struct mountpoint *mp; + struct mount *mnt; + + namespace_lock(); + mp = lookup_mountpoint(dentry); + if (!mp) + goto out_unlock; + + lock_mount_hash(); + while (!list_empty(&mp->m_list)) { + mnt = list_first_entry(&mp->m_list, struct mount, mnt_mp_list); + umount_tree(mnt, 2); + } + unlock_mount_hash(); + put_mountpoint(mp); +out_unlock: + namespace_unlock(); +} + /* * Is the caller allowed to modify his namespace? */ @@ -1722,7 +1828,9 @@ static struct mountpoint *lock_mount(struct path *path) namespace_lock(); mnt = lookup_mnt(path); if (likely(!mnt)) { - struct mountpoint *mp = new_mountpoint(dentry); + struct mountpoint *mp = lookup_mountpoint(dentry); + if (!mp) + mp = new_mountpoint(dentry); if (IS_ERR(mp)) { namespace_unlock(); mutex_unlock(&dentry->d_inode->i_mutex); diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d9f3d067cd1563..6af4cdc824fe75 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -486,8 +486,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) nfs_setsecurity(dentry->d_inode, entry->fattr, entry->label); goto out; } else { - if (d_invalidate(dentry) != 0) - goto out; + d_invalidate(dentry); dput(dentry); } } @@ -1176,10 +1175,6 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) if (IS_ROOT(dentry)) goto out_valid; } - /* If we have submounts, don't unhash ! */ - if (check_submounts_and_drop(dentry) != 0) - goto out_valid; - dput(parent); dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n", __func__, dentry); @@ -2032,9 +2027,9 @@ static void nfs_access_free_entry(struct nfs_access_entry *entry) { put_rpccred(entry->cred); kfree(entry); - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_long_dec(&nfs_access_nr_entries); - smp_mb__after_atomic_dec(); + smp_mb__after_atomic(); } static void nfs_access_free_list(struct list_head *head) @@ -2082,9 +2077,9 @@ nfs_access_cache_scan(struct shrinker *shrink, struct shrink_control *sc) else { remove_lru_entry: list_del_init(&nfsi->access_cache_inode_lru); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } spin_unlock(&inode->i_lock); } @@ -2232,9 +2227,9 @@ void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) nfs_access_add_rbtree(inode, cache); /* Update accounting */ - smp_mb__before_atomic_inc(); + smp_mb__before_atomic(); atomic_long_inc(&nfs_access_nr_entries); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); /* Add inode to global LRU list */ if (!test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index b8797ae6831ff3..b122fe21fea0dc 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -121,20 +121,20 @@ static inline int put_dreq(struct nfs_direct_req *dreq) * shunt off direct read and write requests before the VFS gets them, * so this method is only ever called for swap. */ -ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t pos, unsigned long nr_segs) +ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos) { #ifndef CONFIG_NFS_SWAP dprintk("NFS: nfs_direct_IO (%pD) off/no(%Ld/%lu) EINVAL\n", - iocb->ki_filp, (long long) pos, nr_segs); + iocb->ki_filp, (long long) pos, iter->nr_segs); return -EINVAL; #else VM_BUG_ON(iocb->ki_nbytes != PAGE_SIZE); if (rw == READ || rw == KERNEL_READ) - return nfs_file_direct_read(iocb, iov, nr_segs, pos, + return nfs_file_direct_read(iocb, iter, pos, rw == READ ? true : false); - return nfs_file_direct_write(iocb, iov, nr_segs, pos, + return nfs_file_direct_write(iocb, iter, pos, rw == WRITE ? true : false); #endif /* CONFIG_NFS_SWAP */ } @@ -322,60 +322,37 @@ static const struct nfs_pgio_completion_ops nfs_direct_read_completion_ops = { * handled automatically by nfs_direct_read_result(). Otherwise, if * no requests have been sent, just return an error. */ -static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *desc, - const struct iovec *iov, - loff_t pos, bool uio) -{ - struct nfs_direct_req *dreq = desc->pg_dreq; - struct nfs_open_context *ctx = dreq->ctx; - struct inode *inode = ctx->dentry->d_inode; - unsigned long user_addr = (unsigned long)iov->iov_base; - size_t count = iov->iov_len; - size_t rsize = NFS_SERVER(inode)->rsize; - unsigned int pgbase; - int result; - ssize_t started = 0; - struct page **pagevec = NULL; - unsigned int npages; - - do { - size_t bytes; - int i; - pgbase = user_addr & ~PAGE_MASK; - bytes = min(max_t(size_t, rsize, PAGE_SIZE), count); +static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, + struct iov_iter *iter, + loff_t pos) +{ + struct nfs_pageio_descriptor desc; + struct inode *inode = dreq->inode; + ssize_t result = -EINVAL; + size_t requested_bytes = 0; + size_t rsize = max_t(size_t, NFS_SERVER(inode)->rsize, PAGE_SIZE); - result = -ENOMEM; - npages = nfs_page_array_len(pgbase, bytes); - if (!pagevec) - pagevec = kmalloc(npages * sizeof(struct page *), - GFP_KERNEL); - if (!pagevec) - break; - if (uio) { - down_read(¤t->mm->mmap_sem); - result = get_user_pages(current, current->mm, user_addr, - npages, 1, 0, pagevec, NULL); - up_read(¤t->mm->mmap_sem); - if (result < 0) - break; - } else { - WARN_ON(npages != 1); - result = get_kernel_page(user_addr, 1, pagevec); - if (WARN_ON(result != 1)) - break; - } + NFS_PROTO(dreq->inode)->read_pageio_init(&desc, dreq->inode, + &nfs_direct_read_completion_ops); + get_dreq(dreq); + desc.pg_dreq = dreq; + atomic_inc(&inode->i_dio_count); - if ((unsigned)result < npages) { - bytes = result * PAGE_SIZE; - if (bytes <= pgbase) { - nfs_direct_release_pages(pagevec, result); - break; - } - bytes -= pgbase; - npages = result; - } + while (iov_iter_count(iter)) { + struct page **pagevec; + size_t bytes; + size_t pgbase; + unsigned npages, i; + result = iov_iter_get_pages_alloc(iter, &pagevec, + rsize, &pgbase); + if (result < 0) + break; + + bytes = result; + iov_iter_advance(iter, bytes); + npages = (result + pgbase + PAGE_SIZE - 1) / PAGE_SIZE; for (i = 0; i < npages; i++) { struct nfs_page *req; unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase); @@ -389,56 +366,21 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *de } req->wb_index = pos >> PAGE_SHIFT; req->wb_offset = pos & ~PAGE_MASK; - if (!nfs_pageio_add_request(desc, req)) { - result = desc->pg_error; + if (!nfs_pageio_add_request(&desc, req)) { + result = desc.pg_error; nfs_release_request(req); break; } pgbase = 0; bytes -= req_len; - started += req_len; - user_addr += req_len; + requested_bytes += req_len; pos += req_len; - count -= req_len; dreq->bytes_left -= req_len; } - /* The nfs_page now hold references to these pages */ nfs_direct_release_pages(pagevec, npages); - } while (count != 0 && result >= 0); - - kfree(pagevec); - - if (started) - return started; - return result < 0 ? (ssize_t) result : -EFAULT; -} - -static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, - const struct iovec *iov, - unsigned long nr_segs, - loff_t pos, bool uio) -{ - struct nfs_pageio_descriptor desc; - struct inode *inode = dreq->inode; - ssize_t result = -EINVAL; - size_t requested_bytes = 0; - unsigned long seg; - - NFS_PROTO(dreq->inode)->read_pageio_init(&desc, dreq->inode, - &nfs_direct_read_completion_ops); - get_dreq(dreq); - desc.pg_dreq = dreq; - atomic_inc(&inode->i_dio_count); - - for (seg = 0; seg < nr_segs; seg++) { - const struct iovec *vec = &iov[seg]; - result = nfs_direct_read_schedule_segment(&desc, vec, pos, uio); + kvfree(pagevec); if (result < 0) break; - requested_bytes += result; - if ((size_t)result < vec->iov_len) - break; - pos += vec->iov_len; } nfs_pageio_complete(&desc); @@ -461,8 +403,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, /** * nfs_file_direct_read - file direct read operation for NFS files * @iocb: target I/O control block - * @iov: vector of user buffers into which to read data - * @nr_segs: size of iov vector + * @iter: vector of user buffers into which to read data * @pos: byte offset in file where reading starts * * We use this function for direct reads instead of calling @@ -479,8 +420,8 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, * client must read the updated atime from the server back into its * cache. */ -ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos, bool uio) +ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter, + loff_t pos, bool uio) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -488,9 +429,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, struct nfs_direct_req *dreq; struct nfs_lock_context *l_ctx; ssize_t result = -EINVAL; - size_t count; - - count = iov_length(iov, nr_segs); + size_t count = iov_iter_count(iter); nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count); dfprintk(FILE, "NFS: direct read(%pD2, %zd@%Ld)\n", @@ -513,7 +452,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, goto out_unlock; dreq->inode = inode; - dreq->bytes_left = iov_length(iov, nr_segs); + dreq->bytes_left = count; dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); l_ctx = nfs_get_lock_context(dreq->ctx); if (IS_ERR(l_ctx)) { @@ -524,8 +463,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; - NFS_I(inode)->read_io += iov_length(iov, nr_segs); - result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos, uio); + NFS_I(inode)->read_io += count; + result = nfs_direct_read_schedule_iovec(dreq, iter, pos); mutex_unlock(&inode->i_mutex); @@ -681,109 +620,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode } #endif -/* - * NB: Return the value of the first error return code. Subsequent - * errors after the first one are ignored. - */ -/* - * For each wsize'd chunk of the user's buffer, dispatch an NFS WRITE - * operation. If nfs_writedata_alloc() or get_user_pages() fails, - * bail and stop sending more writes. Write length accounting is - * handled automatically by nfs_direct_write_result(). Otherwise, if - * no requests have been sent, just return an error. - */ -static ssize_t nfs_direct_write_schedule_segment(struct nfs_pageio_descriptor *desc, - const struct iovec *iov, - loff_t pos, bool uio) -{ - struct nfs_direct_req *dreq = desc->pg_dreq; - struct nfs_open_context *ctx = dreq->ctx; - struct inode *inode = ctx->dentry->d_inode; - unsigned long user_addr = (unsigned long)iov->iov_base; - size_t count = iov->iov_len; - size_t wsize = NFS_SERVER(inode)->wsize; - unsigned int pgbase; - int result; - ssize_t started = 0; - struct page **pagevec = NULL; - unsigned int npages; - - do { - size_t bytes; - int i; - - pgbase = user_addr & ~PAGE_MASK; - bytes = min(max_t(size_t, wsize, PAGE_SIZE), count); - - result = -ENOMEM; - npages = nfs_page_array_len(pgbase, bytes); - if (!pagevec) - pagevec = kmalloc(npages * sizeof(struct page *), GFP_KERNEL); - if (!pagevec) - break; - - if (uio) { - down_read(¤t->mm->mmap_sem); - result = get_user_pages(current, current->mm, user_addr, - npages, 0, 0, pagevec, NULL); - up_read(¤t->mm->mmap_sem); - if (result < 0) - break; - } else { - WARN_ON(npages != 1); - result = get_kernel_page(user_addr, 0, pagevec); - if (WARN_ON(result != 1)) - break; - } - - if ((unsigned)result < npages) { - bytes = result * PAGE_SIZE; - if (bytes <= pgbase) { - nfs_direct_release_pages(pagevec, result); - break; - } - bytes -= pgbase; - npages = result; - } - - for (i = 0; i < npages; i++) { - struct nfs_page *req; - unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase); - - req = nfs_create_request(dreq->ctx, dreq->inode, - pagevec[i], - pgbase, req_len); - if (IS_ERR(req)) { - result = PTR_ERR(req); - break; - } - nfs_lock_request(req); - req->wb_index = pos >> PAGE_SHIFT; - req->wb_offset = pos & ~PAGE_MASK; - if (!nfs_pageio_add_request(desc, req)) { - result = desc->pg_error; - nfs_unlock_and_release_request(req); - break; - } - pgbase = 0; - bytes -= req_len; - started += req_len; - user_addr += req_len; - pos += req_len; - count -= req_len; - dreq->bytes_left -= req_len; - } - /* The nfs_page now hold references to these pages */ - nfs_direct_release_pages(pagevec, npages); - } while (count != 0 && result >= 0); - - kfree(pagevec); - - if (started) - return started; - return result < 0 ? (ssize_t) result : -EFAULT; -} - static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) { struct nfs_direct_req *dreq = hdr->dreq; @@ -863,16 +699,27 @@ static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = { .completion = nfs_direct_write_completion, }; + +/* + * NB: Return the value of the first error return code. Subsequent + * errors after the first one are ignored. + */ +/* + * For each wsize'd chunk of the user's buffer, dispatch an NFS WRITE + * operation. If nfs_writedata_alloc() or get_user_pages() fails, + * bail and stop sending more writes. Write length accounting is + * handled automatically by nfs_direct_write_result(). Otherwise, if + * no requests have been sent, just return an error. + */ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, - const struct iovec *iov, - unsigned long nr_segs, - loff_t pos, bool uio) + struct iov_iter *iter, + loff_t pos) { struct nfs_pageio_descriptor desc; struct inode *inode = dreq->inode; ssize_t result = 0; size_t requested_bytes = 0; - unsigned long seg; + size_t wsize = max_t(size_t, NFS_SERVER(inode)->wsize, PAGE_SIZE); NFS_PROTO(inode)->write_pageio_init(&desc, inode, FLUSH_COND_STABLE, &nfs_direct_write_completion_ops); @@ -880,16 +727,50 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, get_dreq(dreq); atomic_inc(&inode->i_dio_count); - NFS_I(dreq->inode)->write_io += iov_length(iov, nr_segs); - for (seg = 0; seg < nr_segs; seg++) { - const struct iovec *vec = &iov[seg]; - result = nfs_direct_write_schedule_segment(&desc, vec, pos, uio); + NFS_I(inode)->write_io += iov_iter_count(iter); + while (iov_iter_count(iter)) { + struct page **pagevec; + size_t bytes; + size_t pgbase; + unsigned npages, i; + + result = iov_iter_get_pages_alloc(iter, &pagevec, + wsize, &pgbase); if (result < 0) break; - requested_bytes += result; - if ((size_t)result < vec->iov_len) + + bytes = result; + iov_iter_advance(iter, bytes); + npages = (result + pgbase + PAGE_SIZE - 1) / PAGE_SIZE; + for (i = 0; i < npages; i++) { + struct nfs_page *req; + unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase); + + req = nfs_create_request(dreq->ctx, inode, + pagevec[i], + pgbase, req_len); + if (IS_ERR(req)) { + result = PTR_ERR(req); + break; + } + nfs_lock_request(req); + req->wb_index = pos >> PAGE_SHIFT; + req->wb_offset = pos & ~PAGE_MASK; + if (!nfs_pageio_add_request(&desc, req)) { + result = desc.pg_error; + nfs_unlock_and_release_request(req); + break; + } + pgbase = 0; + bytes -= req_len; + requested_bytes += req_len; + pos += req_len; + dreq->bytes_left -= req_len; + } + nfs_direct_release_pages(pagevec, npages); + kvfree(pagevec); + if (result < 0) break; - pos += vec->iov_len; } nfs_pageio_complete(&desc); @@ -911,8 +792,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, /** * nfs_file_direct_write - file direct write operation for NFS files * @iocb: target I/O control block - * @iov: vector of user buffers from which to write data - * @nr_segs: size of iov vector + * @iter: vector of user buffers from which to write data * @pos: byte offset in file where writing starts * * We use this function for direct writes instead of calling @@ -930,8 +810,8 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, * Note that O_APPEND is not supported for NFS direct writes, as there * is no atomic O_APPEND write facility in the NFS protocol. */ -ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos, bool uio) +ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter, + loff_t pos, bool uio) { ssize_t result = -EINVAL; struct file *file = iocb->ki_filp; @@ -940,9 +820,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, struct nfs_direct_req *dreq; struct nfs_lock_context *l_ctx; loff_t end; - size_t count; - - count = iov_length(iov, nr_segs); + size_t count = iov_iter_count(iter); end = (pos + count - 1) >> PAGE_CACHE_SHIFT; nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count); @@ -993,7 +871,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; - result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, uio); + result = nfs_direct_write_schedule_iovec(dreq, iter, pos); if (mapping->nrpages) { invalidate_inode_pages2_range(mapping, diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 284ca901fe16cd..4042ff58fe3f3d 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -165,22 +165,21 @@ nfs_file_flush(struct file *file, fl_owner_t id) EXPORT_SYMBOL_GPL(nfs_file_flush); ssize_t -nfs_file_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +nfs_file_read(struct kiocb *iocb, struct iov_iter *to) { struct inode *inode = file_inode(iocb->ki_filp); ssize_t result; if (iocb->ki_filp->f_flags & O_DIRECT) - return nfs_file_direct_read(iocb, iov, nr_segs, pos, true); + return nfs_file_direct_read(iocb, to, iocb->ki_pos, true); - dprintk("NFS: read(%pD2, %lu@%lu)\n", + dprintk("NFS: read(%pD2, %zu@%lu)\n", iocb->ki_filp, - (unsigned long) iov_length(iov, nr_segs), (unsigned long) pos); + iov_iter_count(to), (unsigned long) iocb->ki_pos); result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); if (!result) { - result = generic_file_aio_read(iocb, iov, nr_segs, pos); + result = generic_file_read_iter(iocb, to); if (result > 0) nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result); } @@ -635,24 +634,24 @@ static int nfs_need_sync_write(struct file *filp, struct inode *inode) return 0; } -ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); unsigned long written = 0; ssize_t result; - size_t count = iov_length(iov, nr_segs); + size_t count = iov_iter_count(from); + loff_t pos = iocb->ki_pos; result = nfs_key_timeout_notify(file, inode); if (result) return result; if (file->f_flags & O_DIRECT) - return nfs_file_direct_write(iocb, iov, nr_segs, pos, true); + return nfs_file_direct_write(iocb, from, pos, true); - dprintk("NFS: write(%pD2, %lu@%Ld)\n", - file, (unsigned long) count, (long long) pos); + dprintk("NFS: write(%pD2, %zu@%Ld)\n", + file, count, (long long) pos); result = -EBUSY; if (IS_SWAPFILE(inode)) @@ -670,7 +669,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, if (!count) goto out; - result = generic_file_aio_write(iocb, iov, nr_segs, pos); + result = generic_file_write_iter(iocb, from); if (result > 0) written = result; @@ -691,36 +690,6 @@ ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, } EXPORT_SYMBOL_GPL(nfs_file_write); -ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, - struct file *filp, loff_t *ppos, - size_t count, unsigned int flags) -{ - struct inode *inode = file_inode(filp); - unsigned long written = 0; - ssize_t ret; - - dprintk("NFS splice_write(%pD2, %lu@%llu)\n", - filp, (unsigned long) count, (unsigned long long) *ppos); - - /* - * The combination of splice and an O_APPEND destination is disallowed. - */ - - ret = generic_file_splice_write(pipe, filp, ppos, count, flags); - if (ret > 0) - written = ret; - - if (ret >= 0 && nfs_need_sync_write(filp, inode)) { - int err = vfs_fsync(filp, 0); - if (err < 0) - ret = err; - } - if (ret > 0) - nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written); - return ret; -} -EXPORT_SYMBOL_GPL(nfs_file_splice_write); - static int do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) { @@ -916,10 +885,6 @@ int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) is_local = 1; /* We're simulating flock() locks using posix locks on the server */ - fl->fl_owner = (fl_owner_t)filp; - fl->fl_start = 0; - fl->fl_end = OFFSET_MAX; - if (fl->fl_type == F_UNLCK) return do_unlk(filp, cmd, fl, is_local); return do_setlk(filp, cmd, fl, is_local); @@ -939,10 +904,10 @@ EXPORT_SYMBOL_GPL(nfs_setlease); const struct file_operations nfs_file_operations = { .llseek = nfs_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = nfs_file_read, - .aio_write = nfs_file_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = nfs_file_read, + .write_iter = nfs_file_write, .mmap = nfs_file_mmap, .open = nfs_file_open, .flush = nfs_file_flush, @@ -951,7 +916,7 @@ const struct file_operations nfs_file_operations = { .lock = nfs_lock, .flock = nfs_flock, .splice_read = nfs_file_splice_read, - .splice_write = nfs_file_splice_write, + .splice_write = iter_file_splice_write, .check_flags = nfs_check_flags, .setlease = nfs_setlease, }; diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 66984a9aafaad9..b94f80420a584e 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -120,7 +120,8 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, security_d_instantiate(ret, inode); spin_lock(&ret->d_lock); - if (IS_ROOT(ret) && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { + if (IS_ROOT(ret) && !ret->d_fsdata && + !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { ret->d_fsdata = name; name = NULL; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 0c438973f3c868..c496f8a746393f 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1085,7 +1085,7 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) trace_nfs_invalidate_mapping_exit(inode, ret); clear_bit_unlock(NFS_INO_INVALIDATING, bitlock); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(bitlock, NFS_INO_INVALIDATING); out: return ret; @@ -1575,18 +1575,20 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) inode->i_version = fattr->change_attr; } } else if (server->caps & NFS_CAP_CHANGE_ATTR) - invalid |= save_cache_validity; + nfsi->cache_validity |= save_cache_validity; if (fattr->valid & NFS_ATTR_FATTR_MTIME) { memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); } else if (server->caps & NFS_CAP_MTIME) - invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + nfsi->cache_validity |= save_cache_validity & + (NFS_INO_INVALID_ATTR | NFS_INO_REVAL_FORCED); if (fattr->valid & NFS_ATTR_FATTR_CTIME) { memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); } else if (server->caps & NFS_CAP_CTIME) - invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + nfsi->cache_validity |= save_cache_validity & + (NFS_INO_INVALID_ATTR | NFS_INO_REVAL_FORCED); /* Check if our cached file size is stale */ @@ -1608,7 +1610,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) (long long)new_isize); } } else - invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + nfsi->cache_validity |= save_cache_validity & + (NFS_INO_INVALID_ATTR | NFS_INO_REVAL_PAGECACHE | NFS_INO_REVAL_FORCED); @@ -1616,7 +1619,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) if (fattr->valid & NFS_ATTR_FATTR_ATIME) memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); else if (server->caps & NFS_CAP_ATIME) - invalid |= save_cache_validity & (NFS_INO_INVALID_ATIME + nfsi->cache_validity |= save_cache_validity & + (NFS_INO_INVALID_ATIME | NFS_INO_REVAL_FORCED); if (fattr->valid & NFS_ATTR_FATTR_MODE) { @@ -1627,7 +1631,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; } } else if (server->caps & NFS_CAP_MODE) - invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + nfsi->cache_validity |= save_cache_validity & + (NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL | NFS_INO_REVAL_FORCED); @@ -1638,7 +1643,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) inode->i_uid = fattr->uid; } } else if (server->caps & NFS_CAP_OWNER) - invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + nfsi->cache_validity |= save_cache_validity & + (NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL | NFS_INO_REVAL_FORCED); @@ -1649,7 +1655,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) inode->i_gid = fattr->gid; } } else if (server->caps & NFS_CAP_OWNER_GROUP) - invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + nfsi->cache_validity |= save_cache_validity & + (NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL | NFS_INO_REVAL_FORCED); @@ -1662,7 +1669,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) set_nlink(inode, fattr->nlink); } } else if (server->caps & NFS_CAP_NLINK) - invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + nfsi->cache_validity |= save_cache_validity & + (NFS_INO_INVALID_ATTR | NFS_INO_REVAL_FORCED); if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index dd8bfc2e246460..0e4e8049c9f531 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -320,16 +320,14 @@ int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *) int nfs_file_fsync_commit(struct file *, loff_t, loff_t, int); loff_t nfs_file_llseek(struct file *, loff_t, int); int nfs_file_flush(struct file *, fl_owner_t); -ssize_t nfs_file_read(struct kiocb *, const struct iovec *, unsigned long, loff_t); +ssize_t nfs_file_read(struct kiocb *, struct iov_iter *); ssize_t nfs_file_splice_read(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int nfs_file_mmap(struct file *, struct vm_area_struct *); -ssize_t nfs_file_write(struct kiocb *, const struct iovec *, unsigned long, loff_t); +ssize_t nfs_file_write(struct kiocb *, struct iov_iter *); int nfs_file_release(struct inode *, struct file *); int nfs_lock(struct file *, int, struct file_lock *); int nfs_flock(struct file *, int, struct file_lock *); -ssize_t nfs_file_splice_write(struct pipe_inode_info *, struct file *, loff_t *, - size_t, unsigned int); int nfs_check_flags(int); int nfs_setlease(struct file *, long, struct file_lock **); diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 8de3407e036082..50de2cdea08258 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -118,10 +118,10 @@ nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) const struct file_operations nfs4_file_operations = { .llseek = nfs_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = nfs_file_read, - .aio_write = nfs_file_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = nfs_file_read, + .write_iter = nfs_file_write, .mmap = nfs_file_mmap, .open = nfs4_file_open, .flush = nfs_file_flush, @@ -130,7 +130,7 @@ const struct file_operations nfs4_file_operations = { .lock = nfs_lock, .flock = nfs_flock, .splice_read = nfs_file_splice_read, - .splice_write = nfs_file_splice_write, + .splice_write = iter_file_splice_write, .check_flags = nfs_check_flags, .setlease = nfs_setlease, }; diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index efac602edb3702..b9c61efe966004 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c @@ -789,9 +789,9 @@ static void nfs4_wait_ds_connect(struct nfs4_pnfs_ds *ds) static void nfs4_clear_ds_conn_bit(struct nfs4_pnfs_ds *ds) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(NFS4DS_CONNECTING, &ds->ds_state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&ds->ds_state, NFS4DS_CONNECTING); } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 2349518eef2c28..c0583b9bef716a 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1140,9 +1140,9 @@ static int nfs4_run_state_manager(void *); static void nfs4_clear_state_manager_bit(struct nfs_client *clp) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING); rpc_wake_up(&clp->cl_rpcwaitq); } diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 2ffebf2081ceb5..03ed984ab4d801 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -95,7 +95,7 @@ nfs_iocounter_dec(struct nfs_io_counter *c) { if (atomic_dec_and_test(&c->io_count)) { clear_bit(NFS_IO_INPROGRESS, &c->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&c->flags, NFS_IO_INPROGRESS); } } @@ -193,9 +193,9 @@ void nfs_unlock_request(struct nfs_page *req) printk(KERN_ERR "NFS: Invalid unlock attempted\n"); BUG(); } - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(PG_BUSY, &req->wb_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&req->wb_flags, PG_BUSY); } diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index cb53d450ae321e..fd9536e494bc20 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1810,7 +1810,7 @@ static void pnfs_clear_layoutcommitting(struct inode *inode) unsigned long *bitlock = &NFS_I(inode)->flags; clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); } diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 023793909778ef..c3058a076596f9 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -275,7 +275,7 @@ pnfs_get_lseg(struct pnfs_layout_segment *lseg) { if (lseg) { atomic_inc(&lseg->pls_refcount); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } return lseg; } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 9a3b6a4cd6b958..4c4a4beb140800 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -405,7 +405,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) nfs_pageio_complete(&pgio); clear_bit_unlock(NFS_INO_FLUSHING, bitlock); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(bitlock, NFS_INO_FLUSHING); if (err < 0) @@ -1353,6 +1353,30 @@ static const struct rpc_call_ops nfs_write_common_ops = { .rpc_release = nfs_writeback_release_common, }; +/* + * Special version of should_remove_suid() that ignores capabilities. + */ +static int nfs_should_remove_suid(const struct inode *inode) +{ + umode_t mode = inode->i_mode; + int kill = 0; + + /* suid always must be killed */ + if (unlikely(mode & S_ISUID)) + kill = ATTR_KILL_SUID; + + /* + * sgid without any exec bits is just a mandatory locking mark; leave + * it alone. If some exec bits are set, it's a real sgid; kill it. + */ + if (unlikely((mode & S_ISGID) && (mode & S_IXGRP))) + kill |= ATTR_KILL_SGID; + + if (unlikely(kill && S_ISREG(mode))) + return kill; + + return 0; +} /* * This function is called when the WRITE call is complete. @@ -1401,9 +1425,16 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) } } #endif - if (task->tk_status < 0) + if (task->tk_status < 0) { nfs_set_pgio_error(data->header, task->tk_status, argp->offset); - else if (resp->count < argp->count) { + return; + } + + /* Deal with the suid/sgid bit corner case */ + if (nfs_should_remove_suid(inode)) + nfs_mark_for_revalidate(inode); + + if (resp->count < argp->count) { static unsigned long complain; /* This a short write! */ @@ -1458,7 +1489,7 @@ static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) static void nfs_commit_clear_lock(struct nfs_inode *nfsi) { clear_bit(NFS_INO_COMMIT, &nfsi->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&nfsi->flags, NFS_INO_COMMIT); } diff --git a/include/linux/nfsd/export.h b/fs/nfsd/export.h similarity index 94% rename from include/linux/nfsd/export.h rename to fs/nfsd/export.h index 7898c997dfea40..d7939a62a0ae64 100644 --- a/include/linux/nfsd/export.h +++ b/fs/nfsd/export.h @@ -1,17 +1,16 @@ /* - * include/linux/nfsd/export.h - * - * Public declarations for NFS exports. The definitions for the - * syscall interface are in nfsctl.h - * * Copyright (C) 1995-1997 Olaf Kirch */ #ifndef NFSD_EXPORT_H #define NFSD_EXPORT_H -# include +#include #include +struct knfsd_fh; +struct svc_fh; +struct svc_rqst; + /* * FS Locations */ diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index d620e7f8142903..2ed05c3cd43dee 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -97,25 +97,14 @@ static ssize_t fault_inject_read(struct file *file, char __user *buf, { static u64 val; char read_buf[25]; - size_t size, ret; + size_t size; loff_t pos = *ppos; if (!pos) nfsd_inject_get(file_inode(file)->i_private, &val); size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val); - if (pos < 0) - return -EINVAL; - if (pos >= size || !len) - return 0; - if (len > size - pos) - len = size - pos; - ret = copy_to_user(buf, read_buf + pos, len); - if (ret == len) - return -EFAULT; - len -= ret; - *ppos = pos + len; - return len; + return simple_read_from_buffer(buf, len, ppos, read_buf, size); } static ssize_t fault_inject_write(struct file *file, const char __user *buf, diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 6f3f392d48af76..05c9b2f9427b71 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -36,7 +36,6 @@ #include #include -#include #include "nfsfh.h" #include "nfsd.h" #include "acl.h" @@ -402,8 +401,10 @@ sort_pacl(struct posix_acl *pacl) * by uid/gid. */ int i, j; - if (pacl->a_count <= 4) - return; /* no users or groups */ + /* no users or groups */ + if (!pacl || pacl->a_count <= 4) + return; + i = 1; while (pacl->a_entries[i].e_tag == ACL_USER) i++; @@ -530,13 +531,12 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) /* * ACLs with no ACEs are treated differently in the inheritable - * and effective cases: when there are no inheritable ACEs, we - * set a zero-length default posix acl: + * and effective cases: when there are no inheritable ACEs, + * calls ->set_acl with a NULL ACL structure. */ - if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT)) { - pacl = posix_acl_alloc(0, GFP_KERNEL); - return pacl ? pacl : ERR_PTR(-ENOMEM); - } + if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT)) + return NULL; + /* * When there are no effective ACEs, the following will end * up setting a 3-element effective posix ACL with all diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index d543222babf36b..ac837783b37dac 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -786,7 +786,6 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (!nfsd4_last_compound_op(rqstp)) rqstp->rq_splice_ok = false; - nfs4_lock_state(); /* check stateid */ if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate, &read->rd_stateid, @@ -794,11 +793,8 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); goto out; } - if (read->rd_filp) - get_file(read->rd_filp); status = nfs_ok; out: - nfs4_unlock_state(); read->rd_rqstp = rqstp; read->rd_fhp = &cstate->current_fh; return status; @@ -937,10 +933,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, int err; if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { - nfs4_lock_state(); status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate, &setattr->sa_stateid, WR_STATE, NULL); - nfs4_unlock_state(); if (status) { dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); return status; @@ -1006,17 +1000,12 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (write->wr_offset >= OFFSET_MAX) return nfserr_inval; - nfs4_lock_state(); status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate, stateid, WR_STATE, &filp); if (status) { - nfs4_unlock_state(); dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); return status; } - if (filp) - get_file(filp); - nfs4_unlock_state(); cnt = write->wr_buflen; write->wr_how_written = write->wr_stable_how; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3ba65979a3cde0..fac26836e4ac29 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -645,6 +645,12 @@ static void unhash_lockowner(struct nfs4_lockowner *lo) } } +static void nfs4_free_lockowner(struct nfs4_lockowner *lo) +{ + kfree(lo->lo_owner.so_owner.data); + kmem_cache_free(lockowner_slab, lo); +} + static void release_lockowner(struct nfs4_lockowner *lo) { unhash_lockowner(lo); @@ -699,6 +705,12 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo) } } +static void nfs4_free_openowner(struct nfs4_openowner *oo) +{ + kfree(oo->oo_owner.so_owner.data); + kmem_cache_free(openowner_slab, oo); +} + static void release_openowner(struct nfs4_openowner *oo) { unhash_openowner(oo); @@ -1078,10 +1090,22 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) return NULL; } clp->cl_name.len = name.len; + INIT_LIST_HEAD(&clp->cl_sessions); + idr_init(&clp->cl_stateids); + atomic_set(&clp->cl_refcount, 0); + clp->cl_cb_state = NFSD4_CB_UNKNOWN; + INIT_LIST_HEAD(&clp->cl_idhash); + INIT_LIST_HEAD(&clp->cl_openowners); + INIT_LIST_HEAD(&clp->cl_delegations); + INIT_LIST_HEAD(&clp->cl_lru); + INIT_LIST_HEAD(&clp->cl_callbacks); + INIT_LIST_HEAD(&clp->cl_revoked); + spin_lock_init(&clp->cl_lock); + rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); return clp; } -static inline void +static void free_client(struct nfs4_client *clp) { struct nfsd_net __maybe_unused *nn = net_generic(clp->net, nfsd_net_id); @@ -1095,6 +1119,7 @@ free_client(struct nfs4_client *clp) WARN_ON_ONCE(atomic_read(&ses->se_ref)); free_session(ses); } + rpc_destroy_wait_queue(&clp->cl_cb_waitq); free_svc_cred(&clp->cl_cred); kfree(clp->cl_name.data); idr_destroy(&clp->cl_stateids); @@ -1347,7 +1372,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name, if (clp == NULL) return NULL; - INIT_LIST_HEAD(&clp->cl_sessions); ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); if (ret) { spin_lock(&nn->client_lock); @@ -1355,20 +1379,9 @@ static struct nfs4_client *create_client(struct xdr_netobj name, spin_unlock(&nn->client_lock); return NULL; } - idr_init(&clp->cl_stateids); - atomic_set(&clp->cl_refcount, 0); - clp->cl_cb_state = NFSD4_CB_UNKNOWN; - INIT_LIST_HEAD(&clp->cl_idhash); - INIT_LIST_HEAD(&clp->cl_openowners); - INIT_LIST_HEAD(&clp->cl_delegations); - INIT_LIST_HEAD(&clp->cl_lru); - INIT_LIST_HEAD(&clp->cl_callbacks); - INIT_LIST_HEAD(&clp->cl_revoked); - spin_lock_init(&clp->cl_lock); nfsd4_init_callback(&clp->cl_cb_null); clp->cl_time = get_seconds(); clear_bit(0, &clp->cl_cb_slot_busy); - rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); copy_verf(clp, verf); rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); gen_confirm(clp); @@ -2552,18 +2565,6 @@ nfsd4_init_slabs(void) return -ENOMEM; } -void nfs4_free_openowner(struct nfs4_openowner *oo) -{ - kfree(oo->oo_owner.so_owner.data); - kmem_cache_free(openowner_slab, oo); -} - -void nfs4_free_lockowner(struct nfs4_lockowner *lo) -{ - kfree(lo->lo_owner.so_owner.data); - kmem_cache_free(lockowner_slab, lo); -} - static void init_nfs4_replay(struct nfs4_replay *rp) { rp->rp_status = nfserr_serverfault; @@ -3653,6 +3654,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, struct svc_fh *current_fh = &cstate->current_fh; struct inode *ino = current_fh->fh_dentry->d_inode; struct nfsd_net *nn = net_generic(net, nfsd_net_id); + struct file *file = NULL; __be32 status; if (filpp) @@ -3664,10 +3666,12 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) return check_special_stateids(net, current_fh, stateid, flags); + nfs4_lock_state(); + status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s, cstate->minorversion, nn); if (status) - return status; + goto out; status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); if (status) goto out; @@ -3678,8 +3682,8 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, if (status) goto out; if (filpp) { - *filpp = dp->dl_file->fi_deleg_file; - if (!*filpp) { + file = dp->dl_file->fi_deleg_file; + if (!file) { WARN_ON_ONCE(1); status = nfserr_serverfault; goto out; @@ -3700,16 +3704,20 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, goto out; if (filpp) { if (flags & RD_STATE) - *filpp = find_readable_file(stp->st_file); + file = find_readable_file(stp->st_file); else - *filpp = find_writeable_file(stp->st_file); + file = find_writeable_file(stp->st_file); } break; default: - return nfserr_bad_stateid; + status = nfserr_bad_stateid; + goto out; } status = nfs_ok; + if (file) + *filpp = get_file(file); out: + nfs4_unlock_state(); return status; } @@ -4971,13 +4979,6 @@ struct nfs4_client *nfsd_find_client(struct sockaddr_storage *addr, size_t addr_ #endif /* CONFIG_NFSD_FAULT_INJECTION */ -/* initialization to perform at module load time: */ - -void -nfs4_state_init(void) -{ -} - /* * Since the lifetime of a delegation isn't limited to that of an open, a * client may quite reasonably hang on to a delegation as long as it has diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index f34d9de802abc7..51844048937ff3 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1179,7 +1179,6 @@ static int __init init_nfsd(void) retval = nfsd4_init_slabs(); if (retval) goto out_unregister_pernet; - nfs4_state_init(); retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */ if (retval) goto out_free_slabs; diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 479eb681c27c31..847daf37e56641 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -15,11 +15,20 @@ #include #include #include +#include #include -#include -#include -#include +#include + +#include "stats.h" +#include "export.h" + +#undef ifdebug +#ifdef NFSD_DEBUG +# define ifdebug(flag) if (nfsd_debug & NFSDDBG_##flag) +#else +# define ifdebug(flag) if (0) +#endif /* * nfsd version @@ -106,7 +115,6 @@ static inline int nfsd_v4client(struct svc_rqst *rq) */ #ifdef CONFIG_NFSD_V4 extern unsigned long max_delegations; -void nfs4_state_init(void); int nfsd4_init_slabs(void); void nfsd4_free_slabs(void); int nfs4_state_start(void); @@ -117,7 +125,6 @@ void nfs4_reset_lease(time_t leasetime); int nfs4_reset_recoverydir(char *recdir); char * nfs4_recoverydir(void); #else -static inline void nfs4_state_init(void) { } static inline int nfsd4_init_slabs(void) { return 0; } static inline void nfsd4_free_slabs(void) { } static inline int nfs4_state_start(void) { return 0; } diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 3c37b160dcad22..a337106d687523 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -169,8 +169,8 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) data_left -= len; if (data_left < 0) return error; - exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_auth); - fid = (struct fid *)(fh->fh_auth + len); + exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_fsid); + fid = (struct fid *)(fh->fh_fsid + len); } else { __u32 tfh[2]; dev_t xdev; @@ -385,7 +385,7 @@ static void _fh_update(struct svc_fh *fhp, struct svc_export *exp, { if (dentry != exp->ex_path.dentry) { struct fid *fid = (struct fid *) - (fhp->fh_handle.fh_auth + fhp->fh_handle.fh_size/4 - 1); + (fhp->fh_handle.fh_fsid + fhp->fh_handle.fh_size/4 - 1); int maxsize = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4; int subtreecheck = !(exp->ex_flags & NFSEXP_NOSUBTREECHECK); @@ -513,7 +513,6 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, */ struct inode * inode = dentry->d_inode; - __u32 *datap; dev_t ex_dev = exp_sb(exp)->s_dev; dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %pd2, ino=%ld)\n", @@ -557,17 +556,16 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, if (inode) _fh_update_old(dentry, exp, &fhp->fh_handle); } else { - int len; + fhp->fh_handle.fh_size = + key_len(fhp->fh_handle.fh_fsid_type) + 4; fhp->fh_handle.fh_auth_type = 0; - datap = fhp->fh_handle.fh_auth+0; - mk_fsid(fhp->fh_handle.fh_fsid_type, datap, ex_dev, + + mk_fsid(fhp->fh_handle.fh_fsid_type, + fhp->fh_handle.fh_fsid, + ex_dev, exp->ex_path.dentry->d_inode->i_ino, exp->ex_fsid, exp->ex_uuid); - len = key_len(fhp->fh_handle.fh_fsid_type); - datap += len/4; - fhp->fh_handle.fh_size = 4 + len; - if (inode) _fh_update(fhp, exp, dentry); if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) { diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index ad67964d0bb198..2e89e70ac15c8f 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -1,9 +1,58 @@ -/* Copyright (C) 1995, 1996, 1997 Olaf Kirch */ +/* + * Copyright (C) 1995, 1996, 1997 Olaf Kirch + * + * This file describes the layout of the file handles as passed + * over the wire. + */ +#ifndef _LINUX_NFSD_NFSFH_H +#define _LINUX_NFSD_NFSFH_H + +#include +#include + +static inline __u32 ino_t_to_u32(ino_t ino) +{ + return (__u32) ino; +} + +static inline ino_t u32_to_ino_t(__u32 uino) +{ + return (ino_t) uino; +} -#ifndef _LINUX_NFSD_FH_INT_H -#define _LINUX_NFSD_FH_INT_H +/* + * This is the internal representation of an NFS handle used in knfsd. + * pre_mtime/post_version will be used to support wcc_attr's in NFSv3. + */ +typedef struct svc_fh { + struct knfsd_fh fh_handle; /* FH data */ + struct dentry * fh_dentry; /* validated dentry */ + struct svc_export * fh_export; /* export pointer */ + int fh_maxsize; /* max size for fh_handle */ + + unsigned char fh_locked; /* inode locked by us */ + unsigned char fh_want_write; /* remount protection taken */ + +#ifdef CONFIG_NFSD_V3 + unsigned char fh_post_saved; /* post-op attrs saved */ + unsigned char fh_pre_saved; /* pre-op attrs saved */ + + /* Pre-op attributes saved during fh_lock */ + __u64 fh_pre_size; /* size before operation */ + struct timespec fh_pre_mtime; /* mtime before oper */ + struct timespec fh_pre_ctime; /* ctime before oper */ + /* + * pre-op nfsv4 change attr: note must check IS_I_VERSION(inode) + * to find out if it is valid. + */ + u64 fh_pre_change; + + /* Post-op attributes saved in fh_unlock */ + struct kstat fh_post_attr; /* full attrs after operation */ + u64 fh_post_change; /* nfsv4 change; see above */ +#endif /* CONFIG_NFSD_V3 */ -#include +} svc_fh; enum nfsd_fsid { FSID_DEV = 0, @@ -215,4 +264,4 @@ fh_unlock(struct svc_fh *fhp) } } -#endif /* _LINUX_NFSD_FH_INT_H */ +#endif /* _LINUX_NFSD_NFSFH_H */ diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 424d8f5f231737..fda9ce28b1b24d 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -37,7 +37,6 @@ #include #include -#include #include "nfsfh.h" typedef struct { @@ -464,8 +463,6 @@ extern void nfs4_release_reclaim(struct nfsd_net *); extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn); extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn); -extern void nfs4_free_openowner(struct nfs4_openowner *); -extern void nfs4_free_lockowner(struct nfs4_lockowner *); extern int set_callback_cred(void); extern void nfsd4_init_callback(struct nfsd4_callback *); extern void nfsd4_probe_callback(struct nfs4_client *clp); diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c index 6d4521feb6e339..cd90878a76aaa8 100644 --- a/fs/nfsd/stats.c +++ b/fs/nfsd/stats.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include "nfsd.h" diff --git a/include/linux/nfsd/stats.h b/fs/nfsd/stats.h similarity index 91% rename from include/linux/nfsd/stats.h rename to fs/nfsd/stats.h index e75b2544ff12f3..a5c944b771c60d 100644 --- a/include/linux/nfsd/stats.h +++ b/fs/nfsd/stats.h @@ -1,12 +1,10 @@ /* - * linux/include/linux/nfsd/stats.h - * * Statistics for NFS server. * * Copyright (C) 1995, 1996 Olaf Kirch */ -#ifndef LINUX_NFSD_STATS_H -#define LINUX_NFSD_STATS_H +#ifndef _NFSD_STATS_H +#define _NFSD_STATS_H #include @@ -42,4 +40,4 @@ extern struct svc_stat nfsd_svcstats; void nfsd_stat_init(void); void nfsd_stat_shutdown(void); -#endif /* LINUX_NFSD_STATS_H */ +#endif /* _NFSD_STATS_H */ diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c index f3a82fbcae0263..24978153c0c4da 100644 --- a/fs/nilfs2/file.c +++ b/fs/nilfs2/file.c @@ -152,10 +152,10 @@ static int nilfs_file_mmap(struct file *file, struct vm_area_struct *vma) */ const struct file_operations nilfs_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .unlocked_ioctl = nilfs_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = nilfs_compat_ioctl, diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index b9c5726120e32a..6252b173a46590 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -298,19 +298,20 @@ static int nilfs_write_end(struct file *file, struct address_space *mapping, } static ssize_t -nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, - loff_t offset, unsigned long nr_segs) +nilfs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = file->f_mapping->host; + size_t count = iov_iter_count(iter); ssize_t size; if (rw == WRITE) return 0; /* Needs synchronization with the cleaner */ - size = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, + size = blockdev_direct_IO(rw, iocb, inode, iter, offset, nilfs_get_block); /* @@ -319,7 +320,7 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, */ if (unlikely((rw & WRITE) && size < 0)) { loff_t isize = i_size_read(inode); - loff_t end = offset + iov_length(iov, nr_segs); + loff_t end = offset + count; if (end > isize) nilfs_write_failed(mapping, end); diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index db9bd8a3172547..89b4d666377527 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -2091,10 +2091,7 @@ static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb, size_t count; /* after file limit checks */ ssize_t written, err; - count = 0; - err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ); - if (err) - return err; + count = iov_length(iov, nr_segs); pos = *ppos; /* We can write back this queue in page reclaim. */ current->backing_dev_info = mapping->backing_dev_info; @@ -2203,8 +2200,8 @@ static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end, const struct file_operations ntfs_file_ops = { .llseek = generic_file_llseek, /* Seek inside file. */ - .read = do_sync_read, /* Read from file. */ - .aio_read = generic_file_aio_read, /* Async read from file. */ + .read = new_sync_read, /* Read from file. */ + .read_iter = generic_file_read_iter, /* Async read from file. */ #ifdef NTFS_RW .write = do_sync_write, /* Write to file. */ .aio_write = ntfs_file_aio_write, /* Async write to file. */ diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index d310d12a9adc48..4a231a166cf88d 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -599,9 +599,8 @@ static int ocfs2_releasepage(struct page *page, gfp_t wait) static ssize_t ocfs2_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, - loff_t offset, - unsigned long nr_segs) + struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file)->i_mapping->host; @@ -618,7 +617,7 @@ static ssize_t ocfs2_direct_IO(int rw, return 0; return __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, - iov, offset, nr_segs, + iter, offset, ocfs2_direct_IO_get_blocks, ocfs2_dio_end_io, NULL, 0); } diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index bf482dfed14fec..73039295d0d1f3 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -1107,7 +1107,7 @@ static int o2hb_thread(void *data) mlog(ML_HEARTBEAT|ML_KTHREAD, "hb thread running\n"); - set_user_nice(current, -20); + set_user_nice(current, MIN_NICE); /* Pin node */ o2nm_depend_this_node(); diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 8eb6e5732d3b73..2930e231f3f9fb 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2233,16 +2233,13 @@ static int ocfs2_prepare_inode_for_write(struct file *file, return ret; } -static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, - loff_t pos) +static ssize_t ocfs2_file_write_iter(struct kiocb *iocb, + struct iov_iter *from) { int ret, direct_io, appending, rw_level, have_alloc_sem = 0; int can_do_direct, has_refcount = 0; ssize_t written = 0; - size_t ocount; /* original count */ - size_t count; /* after file limit checks */ + size_t count = iov_iter_count(from); loff_t old_size, *ppos = &iocb->ki_pos; u32 old_clusters; struct file *file = iocb->ki_filp; @@ -2256,7 +2253,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, (unsigned long long)OCFS2_I(inode)->ip_blkno, file->f_path.dentry->d_name.len, file->f_path.dentry->d_name.name, - (unsigned int)nr_segs); + (unsigned int)from->nr_segs); /* GRRRRR */ if (iocb->ki_nbytes == 0) return 0; @@ -2354,29 +2351,21 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, /* communicate with ocfs2_dio_end_io */ ocfs2_iocb_set_rw_locked(iocb, rw_level); - ret = generic_segment_checks(iov, &nr_segs, &ocount, - VERIFY_READ); - if (ret) - goto out_dio; - - count = ocount; ret = generic_write_checks(file, ppos, &count, S_ISBLK(inode->i_mode)); if (ret) goto out_dio; + iov_iter_truncate(from, count); if (direct_io) { - written = generic_file_direct_write(iocb, iov, &nr_segs, *ppos, - count, ocount); + written = generic_file_direct_write(iocb, from, *ppos); if (written < 0) { ret = written; goto out_dio; } } else { - struct iov_iter from; - iov_iter_init(&from, iov, nr_segs, count, 0); current->backing_dev_info = file->f_mapping->backing_dev_info; - written = generic_perform_write(file, &from, *ppos); + written = generic_perform_write(file, from, *ppos); if (likely(written >= 0)) iocb->ki_pos = *ppos + written; current->backing_dev_info = NULL; @@ -2441,84 +2430,6 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, return ret; } -static int ocfs2_splice_to_file(struct pipe_inode_info *pipe, - struct file *out, - struct splice_desc *sd) -{ - int ret; - - ret = ocfs2_prepare_inode_for_write(out, &sd->pos, - sd->total_len, 0, NULL, NULL); - if (ret < 0) { - mlog_errno(ret); - return ret; - } - - return splice_from_pipe_feed(pipe, sd, pipe_to_file); -} - -static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, - struct file *out, - loff_t *ppos, - size_t len, - unsigned int flags) -{ - int ret; - struct address_space *mapping = out->f_mapping; - struct inode *inode = mapping->host; - struct splice_desc sd = { - .total_len = len, - .flags = flags, - .pos = *ppos, - .u.file = out, - }; - - - trace_ocfs2_file_splice_write(inode, out, out->f_path.dentry, - (unsigned long long)OCFS2_I(inode)->ip_blkno, - out->f_path.dentry->d_name.len, - out->f_path.dentry->d_name.name, len); - - pipe_lock(pipe); - - splice_from_pipe_begin(&sd); - do { - ret = splice_from_pipe_next(pipe, &sd); - if (ret <= 0) - break; - - mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); - ret = ocfs2_rw_lock(inode, 1); - if (ret < 0) - mlog_errno(ret); - else { - ret = ocfs2_splice_to_file(pipe, out, &sd); - ocfs2_rw_unlock(inode, 1); - } - mutex_unlock(&inode->i_mutex); - } while (ret > 0); - splice_from_pipe_end(pipe, &sd); - - pipe_unlock(pipe); - - if (sd.num_spliced) - ret = sd.num_spliced; - - if (ret > 0) { - int err; - - err = generic_write_sync(out, *ppos, ret); - if (err) - ret = err; - else - *ppos += ret; - - balance_dirty_pages_ratelimited(mapping); - } - - return ret; -} - static ssize_t ocfs2_file_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, @@ -2534,7 +2445,7 @@ static ssize_t ocfs2_file_splice_read(struct file *in, in->f_path.dentry->d_name.name, len); /* - * See the comment in ocfs2_file_aio_read() + * See the comment in ocfs2_file_read_iter() */ ret = ocfs2_inode_lock_atime(inode, in->f_path.mnt, &lock_level); if (ret < 0) { @@ -2549,10 +2460,8 @@ static ssize_t ocfs2_file_splice_read(struct file *in, return ret; } -static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, - loff_t pos) +static ssize_t ocfs2_file_read_iter(struct kiocb *iocb, + struct iov_iter *to) { int ret = 0, rw_level = -1, have_alloc_sem = 0, lock_level = 0; struct file *filp = iocb->ki_filp; @@ -2561,7 +2470,8 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, trace_ocfs2_file_aio_read(inode, filp, filp->f_path.dentry, (unsigned long long)OCFS2_I(inode)->ip_blkno, filp->f_path.dentry->d_name.len, - filp->f_path.dentry->d_name.name, nr_segs); + filp->f_path.dentry->d_name.name, + to->nr_segs); /* GRRRRR */ if (!inode) { @@ -2606,13 +2516,13 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, } ocfs2_inode_unlock(inode, lock_level); - ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos); + ret = generic_file_read_iter(iocb, to); trace_generic_file_aio_read_ret(ret); /* buffered aio wouldn't have proper lock coverage today */ BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT)); - /* see ocfs2_file_aio_write */ + /* see ocfs2_file_write_iter */ if (ret == -EIOCBQUEUED || !ocfs2_iocb_is_rw_locked(iocb)) { rw_level = -1; have_alloc_sem = 0; @@ -2705,14 +2615,14 @@ const struct inode_operations ocfs2_special_file_iops = { */ const struct file_operations ocfs2_fops = { .llseek = ocfs2_file_llseek, - .read = do_sync_read, - .write = do_sync_write, + .read = new_sync_read, + .write = new_sync_write, .mmap = ocfs2_mmap, .fsync = ocfs2_sync_file, .release = ocfs2_file_release, .open = ocfs2_file_open, - .aio_read = ocfs2_file_aio_read, - .aio_write = ocfs2_file_aio_write, + .read_iter = ocfs2_file_read_iter, + .write_iter = ocfs2_file_write_iter, .unlocked_ioctl = ocfs2_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ocfs2_compat_ioctl, @@ -2720,7 +2630,7 @@ const struct file_operations ocfs2_fops = { .lock = ocfs2_lock, .flock = ocfs2_flock, .splice_read = ocfs2_file_splice_read, - .splice_write = ocfs2_file_splice_write, + .splice_write = iter_file_splice_write, .fallocate = ocfs2_fallocate, }; @@ -2753,21 +2663,21 @@ const struct file_operations ocfs2_dops = { */ const struct file_operations ocfs2_fops_no_plocks = { .llseek = ocfs2_file_llseek, - .read = do_sync_read, - .write = do_sync_write, + .read = new_sync_read, + .write = new_sync_write, .mmap = ocfs2_mmap, .fsync = ocfs2_sync_file, .release = ocfs2_file_release, .open = ocfs2_file_open, - .aio_read = ocfs2_file_aio_read, - .aio_write = ocfs2_file_aio_write, + .read_iter = ocfs2_file_read_iter, + .write_iter = ocfs2_file_write_iter, .unlocked_ioctl = ocfs2_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ocfs2_compat_ioctl, #endif .flock = ocfs2_flock, .splice_read = ocfs2_file_splice_read, - .splice_write = ocfs2_file_splice_write, + .splice_write = iter_file_splice_write, .fallocate = ocfs2_fallocate, }; diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 54d57d6ba68dd5..902e88527fcec4 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c @@ -337,10 +337,10 @@ static sector_t omfs_bmap(struct address_space *mapping, sector_t block) const struct file_operations omfs_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .fsync = generic_file_fsync, .splice_read = generic_file_splice_read, diff --git a/fs/open.c b/fs/open.c index 9d64679cec73b0..36662d03623796 100644 --- a/fs/open.c +++ b/fs/open.c @@ -725,6 +725,12 @@ static int do_dentry_open(struct file *f, } if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(inode); + if ((f->f_mode & FMODE_READ) && + likely(f->f_op->read || f->f_op->aio_read || f->f_op->read_iter)) + f->f_mode |= FMODE_CAN_READ; + if ((f->f_mode & FMODE_WRITE) && + likely(f->f_op->write || f->f_op->aio_write || f->f_op->write_iter)) + f->f_mode |= FMODE_CAN_WRITE; f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); diff --git a/fs/pipe.c b/fs/pipe.c index 034bffac3f9724..21981e58e2a634 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -116,50 +116,6 @@ void pipe_wait(struct pipe_inode_info *pipe) pipe_lock(pipe); } -static int -pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len, - int atomic) -{ - unsigned long copy; - - while (len > 0) { - while (!iov->iov_len) - iov++; - copy = min_t(unsigned long, len, iov->iov_len); - - if (atomic) { - if (__copy_from_user_inatomic(to, iov->iov_base, copy)) - return -EFAULT; - } else { - if (copy_from_user(to, iov->iov_base, copy)) - return -EFAULT; - } - to += copy; - len -= copy; - iov->iov_base += copy; - iov->iov_len -= copy; - } - return 0; -} - -/* - * Pre-fault in the user memory, so we can use atomic copies. - */ -static void iov_fault_in_pages_read(struct iovec *iov, unsigned long len) -{ - while (!iov->iov_len) - iov++; - - while (len > 0) { - unsigned long this_len; - - this_len = min_t(unsigned long, len, iov->iov_len); - fault_in_pages_readable(iov->iov_base, this_len); - len -= this_len; - iov++; - } -} - static void anon_pipe_buf_release(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { @@ -271,24 +227,18 @@ static const struct pipe_buf_operations packet_pipe_buf_ops = { }; static ssize_t -pipe_read(struct kiocb *iocb, const struct iovec *_iov, - unsigned long nr_segs, loff_t pos) +pipe_read(struct kiocb *iocb, struct iov_iter *to) { + size_t total_len = iov_iter_count(to); struct file *filp = iocb->ki_filp; struct pipe_inode_info *pipe = filp->private_data; int do_wakeup; ssize_t ret; - struct iovec *iov = (struct iovec *)_iov; - size_t total_len; - struct iov_iter iter; - total_len = iov_length(iov, nr_segs); /* Null read succeeds. */ if (unlikely(total_len == 0)) return 0; - iov_iter_init(&iter, iov, nr_segs, total_len, 0); - do_wakeup = 0; ret = 0; __pipe_lock(pipe); @@ -312,7 +262,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, break; } - written = copy_page_to_iter(buf->page, buf->offset, chars, &iter); + written = copy_page_to_iter(buf->page, buf->offset, chars, to); if (unlikely(written < chars)) { if (!ret) ret = -EFAULT; @@ -386,24 +336,19 @@ static inline int is_packetized(struct file *file) } static ssize_t -pipe_write(struct kiocb *iocb, const struct iovec *_iov, - unsigned long nr_segs, loff_t ppos) +pipe_write(struct kiocb *iocb, struct iov_iter *from) { struct file *filp = iocb->ki_filp; struct pipe_inode_info *pipe = filp->private_data; - ssize_t ret; - int do_wakeup; - struct iovec *iov = (struct iovec *)_iov; - size_t total_len; + ssize_t ret = 0; + int do_wakeup = 0; + size_t total_len = iov_iter_count(from); ssize_t chars; - total_len = iov_length(iov, nr_segs); /* Null write succeeds. */ if (unlikely(total_len == 0)) return 0; - do_wakeup = 0; - ret = 0; __pipe_lock(pipe); if (!pipe->readers) { @@ -422,38 +367,19 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, int offset = buf->offset + buf->len; if (ops->can_merge && offset + chars <= PAGE_SIZE) { - int error, atomic = 1; - void *addr; - - error = ops->confirm(pipe, buf); + int error = ops->confirm(pipe, buf); if (error) goto out; - iov_fault_in_pages_read(iov, chars); -redo1: - if (atomic) - addr = kmap_atomic(buf->page); - else - addr = kmap(buf->page); - error = pipe_iov_copy_from_user(offset + addr, iov, - chars, atomic); - if (atomic) - kunmap_atomic(addr); - else - kunmap(buf->page); - ret = error; - do_wakeup = 1; - if (error) { - if (atomic) { - atomic = 0; - goto redo1; - } + ret = copy_page_from_iter(buf->page, offset, chars, from); + if (unlikely(ret < chars)) { + error = -EFAULT; goto out; } + do_wakeup = 1; buf->len += chars; - total_len -= chars; ret = chars; - if (!total_len) + if (!iov_iter_count(from)) goto out; } } @@ -472,8 +398,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, int newbuf = (pipe->curbuf + bufs) & (pipe->buffers-1); struct pipe_buffer *buf = pipe->bufs + newbuf; struct page *page = pipe->tmp_page; - char *src; - int error, atomic = 1; + int copied; if (!page) { page = alloc_page(GFP_HIGHUSER); @@ -489,40 +414,19 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, * FIXME! Is this really true? */ do_wakeup = 1; - chars = PAGE_SIZE; - if (chars > total_len) - chars = total_len; - - iov_fault_in_pages_read(iov, chars); -redo2: - if (atomic) - src = kmap_atomic(page); - else - src = kmap(page); - - error = pipe_iov_copy_from_user(src, iov, chars, - atomic); - if (atomic) - kunmap_atomic(src); - else - kunmap(page); - - if (unlikely(error)) { - if (atomic) { - atomic = 0; - goto redo2; - } + copied = copy_page_from_iter(page, 0, PAGE_SIZE, from); + if (unlikely(copied < PAGE_SIZE && iov_iter_count(from))) { if (!ret) - ret = error; + ret = -EFAULT; break; } - ret += chars; + ret += copied; /* Insert it into the buffer array */ buf->page = page; buf->ops = &anon_pipe_buf_ops; buf->offset = 0; - buf->len = chars; + buf->len = copied; buf->flags = 0; if (is_packetized(filp)) { buf->ops = &packet_pipe_buf_ops; @@ -531,8 +435,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, pipe->nrbufs = ++bufs; pipe->tmp_page = NULL; - total_len -= chars; - if (!total_len) + if (!iov_iter_count(from)) break; } if (bufs < pipe->buffers) @@ -1044,10 +947,10 @@ static int fifo_open(struct inode *inode, struct file *filp) const struct file_operations pipefifo_fops = { .open = fifo_open, .llseek = no_llseek, - .read = do_sync_read, - .aio_read = pipe_read, - .write = do_sync_write, - .aio_write = pipe_write, + .read = new_sync_read, + .read_iter = pipe_read, + .write = new_sync_write, + .write_iter = pipe_write, .poll = pipe_poll, .unlocked_ioctl = pipe_ioctl, .release = pipe_release, diff --git a/fs/proc/base.c b/fs/proc/base.c index 2d696b0c93bfbe..e442784ef74a96 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1625,7 +1625,6 @@ int pid_revalidate(struct dentry *dentry, unsigned int flags) put_task_struct(task); return 1; } - d_drop(dentry); return 0; } @@ -1762,9 +1761,6 @@ static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags) put_task_struct(task); out_notask: - if (status <= 0) - d_drop(dentry); - return status; } @@ -2676,8 +2672,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) /* no ->d_hash() rejects on procfs */ dentry = d_hash_and_lookup(mnt->mnt_root, &name); if (dentry) { - shrink_dcache_parent(dentry); - d_drop(dentry); + d_invalidate(dentry); dput(dentry); } @@ -2697,8 +2692,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) name.len = snprintf(buf, sizeof(buf), "%d", pid); dentry = d_hash_and_lookup(dir, &name); if (dentry) { - shrink_dcache_parent(dentry); - d_drop(dentry); + d_invalidate(dentry); dput(dentry); } diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 0788d093f5d86a..eb82e9f00f5867 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -129,8 +129,6 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) } put_task_struct(task); } - - d_drop(dentry); return 0; } diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 2b363e23f36e73..ff3f0b3cfdb31b 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -278,6 +278,17 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id, return ret; } +static int quota_rmxquota(struct super_block *sb, void __user *addr) +{ + __u32 flags; + + if (copy_from_user(&flags, addr, sizeof(flags))) + return -EFAULT; + if (!sb->s_qcop->rm_xquota) + return -ENOSYS; + return sb->s_qcop->rm_xquota(sb, flags); +} + /* Copy parameters and call proper function */ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void __user *addr, struct path *path) @@ -316,8 +327,9 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, return sb->s_qcop->quota_sync(sb, type); case Q_XQUOTAON: case Q_XQUOTAOFF: - case Q_XQUOTARM: return quota_setxstate(sb, cmd, addr); + case Q_XQUOTARM: + return quota_rmxquota(sb, addr); case Q_XGETQSTAT: return quota_getxstate(sb, addr); case Q_XGETQSTATV: diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c index 1e56a4e8cf7cd4..4f56de822d2f59 100644 --- a/fs/ramfs/file-mmu.c +++ b/fs/ramfs/file-mmu.c @@ -31,14 +31,14 @@ #include "internal.h" const struct file_operations ramfs_file_operations = { - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .fsync = noop_fsync, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, .llseek = generic_file_llseek, }; diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index 0b3d8e4cb2fa00..dda012ad4208d3 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -37,13 +37,13 @@ static int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma); const struct file_operations ramfs_file_operations = { .mmap = ramfs_nommu_mmap, .get_unmapped_area = ramfs_nommu_get_unmapped_area, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .fsync = noop_fsync, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, .llseek = generic_file_llseek, }; diff --git a/fs/read_write.c b/fs/read_write.c index 31c6efa431839e..009d8542a889c7 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -25,11 +25,12 @@ typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *); typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *, unsigned long, loff_t); +typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *); const struct file_operations generic_ro_fops = { .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, + .read = new_sync_read, + .read_iter = generic_file_read_iter, .mmap = generic_file_readonly_mmap, .splice_read = generic_file_splice_read, }; @@ -390,13 +391,34 @@ ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *pp EXPORT_SYMBOL(do_sync_read); +ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) +{ + struct iovec iov = { .iov_base = buf, .iov_len = len }; + struct kiocb kiocb; + struct iov_iter iter; + ssize_t ret; + + init_sync_kiocb(&kiocb, filp); + kiocb.ki_pos = *ppos; + kiocb.ki_nbytes = len; + iov_iter_init(&iter, READ, &iov, 1, len); + + ret = filp->f_op->read_iter(&kiocb, &iter); + if (-EIOCBQUEUED == ret) + ret = wait_on_sync_kiocb(&kiocb); + *ppos = kiocb.ki_pos; + return ret; +} + +EXPORT_SYMBOL(new_sync_read); + ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t ret; if (!(file->f_mode & FMODE_READ)) return -EBADF; - if (!file->f_op->read && !file->f_op->aio_read) + if (!(file->f_mode & FMODE_CAN_READ)) return -EINVAL; if (unlikely(!access_ok(VERIFY_WRITE, buf, count))) return -EFAULT; @@ -406,8 +428,10 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) count = ret; if (file->f_op->read) ret = file->f_op->read(file, buf, count, pos); - else + else if (file->f_op->aio_read) ret = do_sync_read(file, buf, count, pos); + else + ret = new_sync_read(file, buf, count, pos); if (ret > 0) { fsnotify_access(file); add_rchar(current, ret); @@ -439,13 +463,34 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof EXPORT_SYMBOL(do_sync_write); +ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) +{ + struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len }; + struct kiocb kiocb; + struct iov_iter iter; + ssize_t ret; + + init_sync_kiocb(&kiocb, filp); + kiocb.ki_pos = *ppos; + kiocb.ki_nbytes = len; + iov_iter_init(&iter, WRITE, &iov, 1, len); + + ret = filp->f_op->write_iter(&kiocb, &iter); + if (-EIOCBQUEUED == ret) + ret = wait_on_sync_kiocb(&kiocb); + *ppos = kiocb.ki_pos; + return ret; +} + +EXPORT_SYMBOL(new_sync_write); + ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos) { mm_segment_t old_fs; const char __user *p; ssize_t ret; - if (!file->f_op->write && !file->f_op->aio_write) + if (!(file->f_mode & FMODE_CAN_WRITE)) return -EINVAL; old_fs = get_fs(); @@ -455,8 +500,10 @@ ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t count = MAX_RW_COUNT; if (file->f_op->write) ret = file->f_op->write(file, p, count, pos); - else + else if (file->f_op->aio_write) ret = do_sync_write(file, p, count, pos); + else + ret = new_sync_write(file, p, count, pos); set_fs(old_fs); if (ret > 0) { fsnotify_modify(file); @@ -472,7 +519,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ if (!(file->f_mode & FMODE_WRITE)) return -EBADF; - if (!file->f_op->write && !file->f_op->aio_write) + if (!(file->f_mode & FMODE_CAN_WRITE)) return -EINVAL; if (unlikely(!access_ok(VERIFY_READ, buf, count))) return -EFAULT; @@ -483,8 +530,10 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ file_start_write(file); if (file->f_op->write) ret = file->f_op->write(file, buf, count, pos); - else + else if (file->f_op->aio_write) ret = do_sync_write(file, buf, count, pos); + else + ret = new_sync_write(file, buf, count, pos); if (ret > 0) { fsnotify_modify(file); add_wchar(current, ret); @@ -601,6 +650,25 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to) } EXPORT_SYMBOL(iov_shorten); +static ssize_t do_iter_readv_writev(struct file *filp, int rw, const struct iovec *iov, + unsigned long nr_segs, size_t len, loff_t *ppos, iter_fn_t fn) +{ + struct kiocb kiocb; + struct iov_iter iter; + ssize_t ret; + + init_sync_kiocb(&kiocb, filp); + kiocb.ki_pos = *ppos; + kiocb.ki_nbytes = len; + + iov_iter_init(&iter, rw, iov, nr_segs, len); + ret = fn(&kiocb, &iter); + if (ret == -EIOCBQUEUED) + ret = wait_on_sync_kiocb(&kiocb); + *ppos = kiocb.ki_pos; + return ret; +} + static ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov, unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn) { @@ -738,6 +806,7 @@ static ssize_t do_readv_writev(int type, struct file *file, ssize_t ret; io_fn_t fn; iov_fn_t fnv; + iter_fn_t iter_fn; ret = rw_copy_check_uvector(type, uvector, nr_segs, ARRAY_SIZE(iovstack), iovstack, &iov); @@ -753,13 +822,18 @@ static ssize_t do_readv_writev(int type, struct file *file, if (type == READ) { fn = file->f_op->read; fnv = file->f_op->aio_read; + iter_fn = file->f_op->read_iter; } else { fn = (io_fn_t)file->f_op->write; fnv = file->f_op->aio_write; + iter_fn = file->f_op->write_iter; file_start_write(file); } - if (fnv) + if (iter_fn) + ret = do_iter_readv_writev(file, type, iov, nr_segs, tot_len, + pos, iter_fn); + else if (fnv) ret = do_sync_readv_writev(file, iov, nr_segs, tot_len, pos, fnv); else @@ -785,7 +859,7 @@ ssize_t vfs_readv(struct file *file, const struct iovec __user *vec, { if (!(file->f_mode & FMODE_READ)) return -EBADF; - if (!file->f_op->aio_read && !file->f_op->read) + if (!(file->f_mode & FMODE_CAN_READ)) return -EINVAL; return do_readv_writev(READ, file, vec, vlen, pos); @@ -798,7 +872,7 @@ ssize_t vfs_writev(struct file *file, const struct iovec __user *vec, { if (!(file->f_mode & FMODE_WRITE)) return -EBADF; - if (!file->f_op->aio_write && !file->f_op->write) + if (!(file->f_mode & FMODE_CAN_WRITE)) return -EINVAL; return do_readv_writev(WRITE, file, vec, vlen, pos); @@ -912,6 +986,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, ssize_t ret; io_fn_t fn; iov_fn_t fnv; + iter_fn_t iter_fn; ret = compat_rw_copy_check_uvector(type, uvector, nr_segs, UIO_FASTIOV, iovstack, &iov); @@ -927,13 +1002,18 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, if (type == READ) { fn = file->f_op->read; fnv = file->f_op->aio_read; + iter_fn = file->f_op->read_iter; } else { fn = (io_fn_t)file->f_op->write; fnv = file->f_op->aio_write; + iter_fn = file->f_op->write_iter; file_start_write(file); } - if (fnv) + if (iter_fn) + ret = do_iter_readv_writev(file, type, iov, nr_segs, tot_len, + pos, iter_fn); + else if (fnv) ret = do_sync_readv_writev(file, iov, nr_segs, tot_len, pos, fnv); else @@ -964,7 +1044,7 @@ static size_t compat_readv(struct file *file, goto out; ret = -EINVAL; - if (!file->f_op->aio_read && !file->f_op->read) + if (!(file->f_mode & FMODE_CAN_READ)) goto out; ret = compat_do_readv_writev(READ, file, vec, vlen, pos); @@ -1041,7 +1121,7 @@ static size_t compat_writev(struct file *file, goto out; ret = -EINVAL; - if (!file->f_op->aio_write && !file->f_op->write) + if (!(file->f_mode & FMODE_CAN_WRITE)) goto out; ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos); diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index ed58d843d57856..f070cc827456b6 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -235,8 +235,8 @@ int reiserfs_commit_page(struct inode *inode, struct page *page, } const struct file_operations reiserfs_file_operations = { - .read = do_sync_read, - .write = do_sync_write, + .read = new_sync_read, + .write = new_sync_write, .unlocked_ioctl = reiserfs_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = reiserfs_compat_ioctl, @@ -245,10 +245,10 @@ const struct file_operations reiserfs_file_operations = { .open = reiserfs_file_open, .release = reiserfs_file_release, .fsync = reiserfs_sync_file, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, .llseek = generic_file_llseek, }; diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index bc8b8009897df3..b8003e8dd1f47b 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -3083,15 +3083,15 @@ static int reiserfs_releasepage(struct page *page, gfp_t unused_gfp_flags) /* We thank Mingming Cao for helping us understand in great detail what to do in this section of the code. */ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, - unsigned long nr_segs) + struct iov_iter *iter, loff_t offset) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; + size_t count = iov_iter_count(iter); ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - reiserfs_get_blocks_direct_io); + ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, + reiserfs_get_blocks_direct_io); /* * In case of error extending write may have instantiated a few @@ -3099,7 +3099,7 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, */ if (unlikely((rw & WRITE) && ret < 0)) { loff_t isize = i_size_read(inode); - loff_t end = offset + iov_length(iov, nr_segs); + loff_t end = offset + count; if ((end > isize) && inode_newsize_ok(inode, isize) == 0) { truncate_setsize(inode, isize); diff --git a/fs/romfs/mmap-nommu.c b/fs/romfs/mmap-nommu.c index f373bde8f545da..ea06c7554860d7 100644 --- a/fs/romfs/mmap-nommu.c +++ b/fs/romfs/mmap-nommu.c @@ -72,8 +72,8 @@ static int romfs_mmap(struct file *file, struct vm_area_struct *vma) const struct file_operations romfs_ro_fops = { .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, + .read = new_sync_read, + .read_iter = generic_file_read_iter, .splice_read = generic_file_splice_read, .mmap = romfs_mmap, .get_unmapped_area = romfs_get_unmapped_area, diff --git a/fs/splice.c b/fs/splice.c index 9bc07d2b53cf3a..9dc23de0f146cb 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "internal.h" /* @@ -717,63 +718,6 @@ static int pipe_to_sendpage(struct pipe_inode_info *pipe, sd->len, &pos, more); } -/* - * This is a little more tricky than the file -> pipe splicing. There are - * basically three cases: - * - * - Destination page already exists in the address space and there - * are users of it. For that case we have no other option that - * copying the data. Tough luck. - * - Destination page already exists in the address space, but there - * are no users of it. Make sure it's uptodate, then drop it. Fall - * through to last case. - * - Destination page does not exist, we can add the pipe page to - * the page cache and avoid the copy. - * - * If asked to move pages to the output file (SPLICE_F_MOVE is set in - * sd->flags), we attempt to migrate pages from the pipe to the output - * file address space page cache. This is possible if no one else has - * the pipe page referenced outside of the pipe and page cache. If - * SPLICE_F_MOVE isn't set, or we cannot move the page, we simply create - * a new page in the output file page cache and fill/dirty that. - */ -int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, - struct splice_desc *sd) -{ - struct file *file = sd->u.file; - struct address_space *mapping = file->f_mapping; - unsigned int offset, this_len; - struct page *page; - void *fsdata; - int ret; - - offset = sd->pos & ~PAGE_CACHE_MASK; - - this_len = sd->len; - if (this_len + offset > PAGE_CACHE_SIZE) - this_len = PAGE_CACHE_SIZE - offset; - - ret = pagecache_write_begin(file, mapping, sd->pos, this_len, - AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata); - if (unlikely(ret)) - goto out; - - if (buf->page != page) { - char *src = kmap_atomic(buf->page); - char *dst = kmap_atomic(page); - - memcpy(dst + offset, src + buf->offset, this_len); - flush_dcache_page(page); - kunmap_atomic(dst); - kunmap_atomic(src); - } - ret = pagecache_write_end(file, mapping, sd->pos, this_len, this_len, - page, fsdata); -out: - return ret; -} -EXPORT_SYMBOL(pipe_to_file); - static void wakeup_pipe_writers(struct pipe_inode_info *pipe) { smp_mb(); @@ -802,7 +746,7 @@ static void wakeup_pipe_writers(struct pipe_inode_info *pipe) * locking is required around copying the pipe buffers to the * destination. */ -int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd, +static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd, splice_actor *actor) { int ret; @@ -849,7 +793,6 @@ int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd, return 1; } -EXPORT_SYMBOL(splice_from_pipe_feed); /** * splice_from_pipe_next - wait for some data to splice from @@ -861,7 +804,7 @@ EXPORT_SYMBOL(splice_from_pipe_feed); * value (one) if pipe buffers are available. It will return zero * or -errno if no more data needs to be spliced. */ -int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd) +static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd) { while (!pipe->nrbufs) { if (!pipe->writers) @@ -886,7 +829,6 @@ int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd) return 1; } -EXPORT_SYMBOL(splice_from_pipe_next); /** * splice_from_pipe_begin - start splicing from pipe @@ -897,12 +839,11 @@ EXPORT_SYMBOL(splice_from_pipe_next); * splice_from_pipe_next() and splice_from_pipe_feed() to * initialize the necessary fields of @sd. */ -void splice_from_pipe_begin(struct splice_desc *sd) +static void splice_from_pipe_begin(struct splice_desc *sd) { sd->num_spliced = 0; sd->need_wakeup = false; } -EXPORT_SYMBOL(splice_from_pipe_begin); /** * splice_from_pipe_end - finish splicing from pipe @@ -914,12 +855,11 @@ EXPORT_SYMBOL(splice_from_pipe_begin); * be called after a loop containing splice_from_pipe_next() and * splice_from_pipe_feed(). */ -void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd) +static void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd) { if (sd->need_wakeup) wakeup_pipe_writers(pipe); } -EXPORT_SYMBOL(splice_from_pipe_end); /** * __splice_from_pipe - splice data from a pipe to given actor @@ -985,7 +925,7 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, } /** - * generic_file_splice_write - splice data from a pipe to a file + * iter_file_splice_write - splice data from a pipe to a file * @pipe: pipe info * @out: file to write to * @ppos: position in @out @@ -995,40 +935,121 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, * Description: * Will either move or copy pages (determined by @flags options) from * the given pipe inode to the given file. + * This one is ->write_iter-based. * */ ssize_t -generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, +iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags) { - struct address_space *mapping = out->f_mapping; - struct inode *inode = mapping->host; struct splice_desc sd = { .total_len = len, .flags = flags, .pos = *ppos, .u.file = out, }; + int nbufs = pipe->buffers; + struct bio_vec *array = kcalloc(nbufs, sizeof(struct bio_vec), + GFP_KERNEL); ssize_t ret; + if (unlikely(!array)) + return -ENOMEM; + pipe_lock(pipe); splice_from_pipe_begin(&sd); - do { + while (sd.total_len) { + struct iov_iter from; + struct kiocb kiocb; + size_t count = 0; + int n, idx; + ret = splice_from_pipe_next(pipe, &sd); if (ret <= 0) break; - mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); - ret = file_remove_suid(out); - if (!ret) { - ret = file_update_time(out); - if (!ret) - ret = splice_from_pipe_feed(pipe, &sd, - pipe_to_file); + if (unlikely(nbufs < pipe->buffers)) { + kfree(array); + nbufs = pipe->buffers; + array = kcalloc(nbufs, sizeof(struct bio_vec), + GFP_KERNEL); + if (!array) { + ret = -ENOMEM; + break; + } } - mutex_unlock(&inode->i_mutex); - } while (ret > 0); + + /* build the vector */ + for (n = 0, idx = pipe->curbuf; n < pipe->nrbufs; n++, idx++) { + struct pipe_buffer *buf = pipe->bufs + idx; + size_t this_len = buf->len; + + if (this_len > sd.total_len) + this_len = sd.total_len; + + if (idx == pipe->buffers - 1) + idx = -1; + + ret = buf->ops->confirm(pipe, buf); + if (unlikely(ret)) { + if (ret == -ENODATA) + ret = 0; + goto done; + } + + array[n].bv_page = buf->page; + array[n].bv_len = this_len; + array[n].bv_offset = buf->offset; + count += this_len; + } + + /* ... iov_iter */ + from.type = ITER_BVEC | WRITE; + from.bvec = array; + from.nr_segs = n; + from.count = count; + from.iov_offset = 0; + + /* ... and iocb */ + init_sync_kiocb(&kiocb, out); + kiocb.ki_pos = sd.pos; + kiocb.ki_nbytes = count; + + /* now, send it */ + ret = out->f_op->write_iter(&kiocb, &from); + if (-EIOCBQUEUED == ret) + ret = wait_on_sync_kiocb(&kiocb); + + if (ret <= 0) + break; + + sd.num_spliced += ret; + sd.total_len -= ret; + *ppos = sd.pos = kiocb.ki_pos; + + /* dismiss the fully eaten buffers, adjust the partial one */ + while (ret) { + struct pipe_buffer *buf = pipe->bufs + pipe->curbuf; + if (ret >= buf->len) { + const struct pipe_buf_operations *ops = buf->ops; + ret -= buf->len; + buf->len = 0; + buf->ops = NULL; + ops->release(pipe, buf); + pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1); + pipe->nrbufs--; + if (pipe->files) + sd.need_wakeup = true; + } else { + buf->offset += ret; + buf->len -= ret; + ret = 0; + } + } + } +done: + kfree(array); splice_from_pipe_end(pipe, &sd); pipe_unlock(pipe); @@ -1036,21 +1057,10 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, if (sd.num_spliced) ret = sd.num_spliced; - if (ret > 0) { - int err; - - err = generic_write_sync(out, *ppos, ret); - if (err) - ret = err; - else - *ppos += ret; - balance_dirty_pages_ratelimited(mapping); - } - return ret; } -EXPORT_SYMBOL(generic_file_splice_write); +EXPORT_SYMBOL(iter_file_splice_write); static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf, struct splice_desc *sd) @@ -1548,7 +1558,7 @@ static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov, if (ret <= 0) return ret; - iov_iter_init(&iter, iov, nr_segs, count, 0); + iov_iter_init(&iter, READ, iov, nr_segs, count); sd.len = 0; sd.total_len = count; diff --git a/fs/sysv/file.c b/fs/sysv/file.c index 9d4dc6831792a2..b00811c75b24f6 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c @@ -21,10 +21,10 @@ */ const struct file_operations sysv_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .fsync = generic_file_fsync, .splice_read = generic_file_splice_read, diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 4f34dbae823dc9..0888502a604152 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1363,17 +1363,17 @@ static inline int mctime_update_needed(const struct inode *inode, /** * update_ctime - update mtime and ctime of an inode. - * @c: UBIFS file-system description object * @inode: inode to update * * This function updates mtime and ctime of the inode if it is not equivalent to * current time. Returns zero in case of success and a negative error code in * case of failure. */ -static int update_mctime(struct ubifs_info *c, struct inode *inode) +static int update_mctime(struct inode *inode) { struct timespec now = ubifs_current_time(inode); struct ubifs_inode *ui = ubifs_inode(inode); + struct ubifs_info *c = inode->i_sb->s_fs_info; if (mctime_update_needed(inode, &now)) { int err, release; @@ -1396,18 +1396,13 @@ static int update_mctime(struct ubifs_info *c, struct inode *inode) return 0; } -static ssize_t ubifs_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t ubifs_write_iter(struct kiocb *iocb, struct iov_iter *from) { - int err; - struct inode *inode = iocb->ki_filp->f_mapping->host; - struct ubifs_info *c = inode->i_sb->s_fs_info; - - err = update_mctime(c, inode); + int err = update_mctime(file_inode(iocb->ki_filp)); if (err) return err; - return generic_file_aio_write(iocb, iov, nr_segs, pos); + return generic_file_write_iter(iocb, from); } static int ubifs_set_page_dirty(struct page *page) @@ -1582,15 +1577,15 @@ const struct inode_operations ubifs_symlink_inode_operations = { const struct file_operations ubifs_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = ubifs_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = generic_file_read_iter, + .write_iter = ubifs_write_iter, .mmap = ubifs_file_mmap, .fsync = ubifs_fsync, .unlocked_ioctl = ubifs_ioctl, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, #ifdef CONFIG_COMPAT .compat_ioctl = ubifs_compat_ioctl, #endif diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c index 4b826abb1528f5..45d4e96a6bac0f 100644 --- a/fs/ubifs/lpt_commit.c +++ b/fs/ubifs/lpt_commit.c @@ -460,9 +460,9 @@ static int write_cnodes(struct ubifs_info *c) * important. */ clear_bit(DIRTY_CNODE, &cnode->flags); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(COW_CNODE, &cnode->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); offs += len; dbg_chk_lpt_sz(c, 1, len); cnode = cnode->cnext; diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c index 52a6559275c43e..3600994f84112e 100644 --- a/fs/ubifs/tnc_commit.c +++ b/fs/ubifs/tnc_commit.c @@ -895,9 +895,9 @@ static int write_index(struct ubifs_info *c) * the reason for the second barrier. */ clear_bit(DIRTY_ZNODE, &znode->flags); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(COW_ZNODE, &znode->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); /* * We have marked the znode as clean but have not updated the diff --git a/fs/udf/file.c b/fs/udf/file.c index d2c170f8b035a4..d80738fdf424cd 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -119,8 +119,8 @@ static int udf_adinicb_write_end(struct file *file, } static ssize_t udf_adinicb_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, - loff_t offset, unsigned long nr_segs) + struct iov_iter *iter, + loff_t offset) { /* Fallback to buffered I/O. */ return 0; @@ -134,8 +134,7 @@ const struct address_space_operations udf_adinicb_aops = { .direct_IO = udf_adinicb_direct_IO, }; -static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t ppos) +static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { ssize_t retval; struct file *file = iocb->ki_filp; @@ -150,7 +149,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, if (file->f_flags & O_APPEND) pos = inode->i_size; else - pos = ppos; + pos = iocb->ki_pos; if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) + @@ -171,7 +170,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, } else up_write(&iinfo->i_data_sem); - retval = __generic_file_aio_write(iocb, iov, nr_segs); + retval = __generic_file_write_iter(iocb, from); mutex_unlock(&inode->i_mutex); if (retval > 0) { @@ -252,13 +251,13 @@ static int udf_release_file(struct inode *inode, struct file *filp) } const struct file_operations udf_file_operations = { - .read = do_sync_read, - .aio_read = generic_file_aio_read, + .read = new_sync_read, + .read_iter = generic_file_read_iter, .unlocked_ioctl = udf_ioctl, .open = generic_file_open, .mmap = generic_file_mmap, - .write = do_sync_write, - .aio_write = udf_file_aio_write, + .write = new_sync_write, + .write_iter = udf_file_write_iter, .release = udf_release_file, .fsync = generic_file_fsync, .splice_read = generic_file_splice_read, diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 5d643706212f41..236cd48184c2df 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -217,18 +217,18 @@ static int udf_write_begin(struct file *file, struct address_space *mapping, } static ssize_t udf_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, - loff_t offset, unsigned long nr_segs) + struct iov_iter *iter, + loff_t offset) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; + size_t count = iov_iter_count(iter); ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - udf_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, udf_get_block); if (unlikely(ret < 0 && (rw & WRITE))) - udf_write_failed(mapping, offset + iov_length(iov, nr_segs)); + udf_write_failed(mapping, offset + count); return ret; } diff --git a/fs/ufs/file.c b/fs/ufs/file.c index 33afa20d450982..c84ec010a6761f 100644 --- a/fs/ufs/file.c +++ b/fs/ufs/file.c @@ -35,10 +35,10 @@ const struct file_operations ufs_file_operations = { .llseek = generic_file_llseek, - .read = do_sync_read, - .aio_read = generic_file_aio_read, - .write = do_sync_write, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .read_iter = generic_file_read_iter, + .write = new_sync_write, + .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .open = generic_file_open, .fsync = generic_file_fsync, diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index 0fdd4109c62439..6e247a99f5dbce 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h @@ -160,30 +160,38 @@ typedef struct xfs_agi { * still being referenced. */ __be32 agi_unlinked[XFS_AGI_UNLINKED_BUCKETS]; - + /* + * This marks the end of logging region 1 and start of logging region 2. + */ uuid_t agi_uuid; /* uuid of filesystem */ __be32 agi_crc; /* crc of agi sector */ __be32 agi_pad32; __be64 agi_lsn; /* last write sequence */ + __be32 agi_free_root; /* root of the free inode btree */ + __be32 agi_free_level;/* levels in free inode btree */ + /* structure must be padded to 64 bit alignment */ } xfs_agi_t; #define XFS_AGI_CRC_OFF offsetof(struct xfs_agi, agi_crc) -#define XFS_AGI_MAGICNUM 0x00000001 -#define XFS_AGI_VERSIONNUM 0x00000002 -#define XFS_AGI_SEQNO 0x00000004 -#define XFS_AGI_LENGTH 0x00000008 -#define XFS_AGI_COUNT 0x00000010 -#define XFS_AGI_ROOT 0x00000020 -#define XFS_AGI_LEVEL 0x00000040 -#define XFS_AGI_FREECOUNT 0x00000080 -#define XFS_AGI_NEWINO 0x00000100 -#define XFS_AGI_DIRINO 0x00000200 -#define XFS_AGI_UNLINKED 0x00000400 -#define XFS_AGI_NUM_BITS 11 -#define XFS_AGI_ALL_BITS ((1 << XFS_AGI_NUM_BITS) - 1) +#define XFS_AGI_MAGICNUM (1 << 0) +#define XFS_AGI_VERSIONNUM (1 << 1) +#define XFS_AGI_SEQNO (1 << 2) +#define XFS_AGI_LENGTH (1 << 3) +#define XFS_AGI_COUNT (1 << 4) +#define XFS_AGI_ROOT (1 << 5) +#define XFS_AGI_LEVEL (1 << 6) +#define XFS_AGI_FREECOUNT (1 << 7) +#define XFS_AGI_NEWINO (1 << 8) +#define XFS_AGI_DIRINO (1 << 9) +#define XFS_AGI_UNLINKED (1 << 10) +#define XFS_AGI_NUM_BITS_R1 11 /* end of the 1st agi logging region */ +#define XFS_AGI_ALL_BITS_R1 ((1 << XFS_AGI_NUM_BITS_R1) - 1) +#define XFS_AGI_FREE_ROOT (1 << 11) +#define XFS_AGI_FREE_LEVEL (1 << 12) +#define XFS_AGI_NUM_BITS_R2 13 /* disk block (xfs_daddr_t) in the AG */ #define XFS_AGI_DADDR(mp) ((xfs_daddr_t)(2 << (mp)->m_sectbb_log)) diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index cc1eadcbb0497e..8358f1ded94df6 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c @@ -70,7 +70,6 @@ xfs_allocbt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, - int length, int *stat) { int error; diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 0479c32c5eb170..08d13e3952524f 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -1449,9 +1449,8 @@ STATIC ssize_t xfs_vm_direct_IO( int rw, struct kiocb *iocb, - const struct iovec *iov, - loff_t offset, - unsigned long nr_segs) + struct iov_iter *iter, + loff_t offset) { struct inode *inode = iocb->ki_filp->f_mapping->host; struct block_device *bdev = xfs_find_bdev_for_inode(inode); @@ -1459,7 +1458,7 @@ xfs_vm_direct_IO( ssize_t ret; if (rw & WRITE) { - size_t size = iov_length(iov, nr_segs); + size_t size = iov_iter_count(iter); /* * We cannot preallocate a size update transaction here as we @@ -1471,17 +1470,15 @@ xfs_vm_direct_IO( if (offset + size > XFS_I(inode)->i_d.di_size) ioend->io_isdirect = 1; - ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov, - offset, nr_segs, - xfs_get_blocks_direct, + ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iter, + offset, xfs_get_blocks_direct, xfs_end_io_direct_write, NULL, DIO_ASYNC_EXTEND); if (ret != -EIOCBQUEUED && iocb->private) goto out_destroy_ioend; } else { - ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov, - offset, nr_segs, - xfs_get_blocks_direct, + ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iter, + offset, xfs_get_blocks_direct, NULL, NULL, 0); } diff --git a/fs/xfs/xfs_attr_remote.c b/fs/xfs/xfs_attr_remote.c index d2e6e948cec7be..0f0679a134e2af 100644 --- a/fs/xfs/xfs_attr_remote.c +++ b/fs/xfs/xfs_attr_remote.c @@ -68,7 +68,6 @@ xfs_attr3_rmt_blocks( */ static bool xfs_attr3_rmt_hdr_ok( - struct xfs_mount *mp, void *ptr, xfs_ino_t ino, uint32_t offset, @@ -251,7 +250,7 @@ xfs_attr_rmtval_copyout( byte_cnt = min(*valuelen, byte_cnt); if (xfs_sb_version_hascrc(&mp->m_sb)) { - if (!xfs_attr3_rmt_hdr_ok(mp, src, ino, *offset, + if (!xfs_attr3_rmt_hdr_ok(src, ino, *offset, byte_cnt, bno)) { xfs_alert(mp, "remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)", diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index f0efc7e970ef10..1ff0da6e2bf901 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -94,7 +94,7 @@ xfs_bmap_compute_maxlevels( maxleafents = MAXAEXTNUM; sz = XFS_BMDR_SPACE_CALC(MINABTPTRS); } - maxrootrecs = xfs_bmdr_maxrecs(mp, sz, 0); + maxrootrecs = xfs_bmdr_maxrecs(sz, 0); minleafrecs = mp->m_bmap_dmnr[0]; minnoderecs = mp->m_bmap_dmnr[1]; maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; @@ -233,7 +233,6 @@ xfs_default_attroffset( */ STATIC void xfs_bmap_forkoff_reset( - xfs_mount_t *mp, xfs_inode_t *ip, int whichfork) { @@ -905,7 +904,7 @@ xfs_bmap_local_to_extents_empty( ASSERT(ifp->if_bytes == 0); ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); - xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork); + xfs_bmap_forkoff_reset(ip, whichfork); ifp->if_flags &= ~XFS_IFINLINE; ifp->if_flags |= XFS_IFEXTENTS; XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); @@ -1675,7 +1674,6 @@ xfs_bmap_isaeof( */ int xfs_bmap_last_offset( - struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t *last_block, int whichfork) @@ -3517,6 +3515,67 @@ xfs_bmap_adjacent( #undef ISVALID } +static int +xfs_bmap_longest_free_extent( + struct xfs_trans *tp, + xfs_agnumber_t ag, + xfs_extlen_t *blen, + int *notinit) +{ + struct xfs_mount *mp = tp->t_mountp; + struct xfs_perag *pag; + xfs_extlen_t longest; + int error = 0; + + pag = xfs_perag_get(mp, ag); + if (!pag->pagf_init) { + error = xfs_alloc_pagf_init(mp, tp, ag, XFS_ALLOC_FLAG_TRYLOCK); + if (error) + goto out; + + if (!pag->pagf_init) { + *notinit = 1; + goto out; + } + } + + longest = xfs_alloc_longest_free_extent(mp, pag); + if (*blen < longest) + *blen = longest; + +out: + xfs_perag_put(pag); + return error; +} + +static void +xfs_bmap_select_minlen( + struct xfs_bmalloca *ap, + struct xfs_alloc_arg *args, + xfs_extlen_t *blen, + int notinit) +{ + if (notinit || *blen < ap->minlen) { + /* + * Since we did a BUF_TRYLOCK above, it is possible that + * there is space for this request. + */ + args->minlen = ap->minlen; + } else if (*blen < args->maxlen) { + /* + * If the best seen length is less than the request length, + * use the best as the minimum. + */ + args->minlen = *blen; + } else { + /* + * Otherwise we've seen an extent as big as maxlen, use that + * as the minimum. + */ + args->minlen = args->maxlen; + } +} + STATIC int xfs_bmap_btalloc_nullfb( struct xfs_bmalloca *ap, @@ -3524,111 +3583,74 @@ xfs_bmap_btalloc_nullfb( xfs_extlen_t *blen) { struct xfs_mount *mp = ap->ip->i_mount; - struct xfs_perag *pag; xfs_agnumber_t ag, startag; int notinit = 0; int error; - if (ap->userdata && xfs_inode_is_filestream(ap->ip)) - args->type = XFS_ALLOCTYPE_NEAR_BNO; - else - args->type = XFS_ALLOCTYPE_START_BNO; + args->type = XFS_ALLOCTYPE_START_BNO; args->total = ap->total; - /* - * Search for an allocation group with a single extent large enough - * for the request. If one isn't found, then adjust the minimum - * allocation size to the largest space found. - */ startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno); if (startag == NULLAGNUMBER) startag = ag = 0; - pag = xfs_perag_get(mp, ag); while (*blen < args->maxlen) { - if (!pag->pagf_init) { - error = xfs_alloc_pagf_init(mp, args->tp, ag, - XFS_ALLOC_FLAG_TRYLOCK); - if (error) { - xfs_perag_put(pag); - return error; - } - } - - /* - * See xfs_alloc_fix_freelist... - */ - if (pag->pagf_init) { - xfs_extlen_t longest; - longest = xfs_alloc_longest_free_extent(mp, pag); - if (*blen < longest) - *blen = longest; - } else - notinit = 1; - - if (xfs_inode_is_filestream(ap->ip)) { - if (*blen >= args->maxlen) - break; - - if (ap->userdata) { - /* - * If startag is an invalid AG, we've - * come here once before and - * xfs_filestream_new_ag picked the - * best currently available. - * - * Don't continue looping, since we - * could loop forever. - */ - if (startag == NULLAGNUMBER) - break; - - error = xfs_filestream_new_ag(ap, &ag); - xfs_perag_put(pag); - if (error) - return error; + error = xfs_bmap_longest_free_extent(args->tp, ag, blen, + ¬init); + if (error) + return error; - /* loop again to set 'blen'*/ - startag = NULLAGNUMBER; - pag = xfs_perag_get(mp, ag); - continue; - } - } if (++ag == mp->m_sb.sb_agcount) ag = 0; if (ag == startag) break; - xfs_perag_put(pag); - pag = xfs_perag_get(mp, ag); } - xfs_perag_put(pag); - /* - * Since the above loop did a BUF_TRYLOCK, it is - * possible that there is space for this request. - */ - if (notinit || *blen < ap->minlen) - args->minlen = ap->minlen; - /* - * If the best seen length is less than the request - * length, use the best as the minimum. - */ - else if (*blen < args->maxlen) - args->minlen = *blen; - /* - * Otherwise we've seen an extent as big as maxlen, - * use that as the minimum. - */ - else - args->minlen = args->maxlen; + xfs_bmap_select_minlen(ap, args, blen, notinit); + return 0; +} + +STATIC int +xfs_bmap_btalloc_filestreams( + struct xfs_bmalloca *ap, + struct xfs_alloc_arg *args, + xfs_extlen_t *blen) +{ + struct xfs_mount *mp = ap->ip->i_mount; + xfs_agnumber_t ag; + int notinit = 0; + int error; + + args->type = XFS_ALLOCTYPE_NEAR_BNO; + args->total = ap->total; + + ag = XFS_FSB_TO_AGNO(mp, args->fsbno); + if (ag == NULLAGNUMBER) + ag = 0; + + error = xfs_bmap_longest_free_extent(args->tp, ag, blen, ¬init); + if (error) + return error; + + if (*blen < args->maxlen) { + error = xfs_filestream_new_ag(ap, &ag); + if (error) + return error; + + error = xfs_bmap_longest_free_extent(args->tp, ag, blen, + ¬init); + if (error) + return error; + + } + + xfs_bmap_select_minlen(ap, args, blen, notinit); /* - * set the failure fallback case to look in the selected - * AG as the stream may have moved. + * Set the failure fallback case to look in the selected AG as stream + * may have moved. */ - if (xfs_inode_is_filestream(ap->ip)) - ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0); - + ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0); return 0; } @@ -3708,7 +3730,15 @@ xfs_bmap_btalloc( args.firstblock = *ap->firstblock; blen = 0; if (nullfb) { - error = xfs_bmap_btalloc_nullfb(ap, &args, &blen); + /* + * Search for an allocation group with a single extent large + * enough for the request. If one isn't found, then adjust + * the minimum allocation size to the largest space found. + */ + if (ap->userdata && xfs_inode_is_filestream(ap->ip)) + error = xfs_bmap_btalloc_filestreams(ap, &args, &blen); + else + error = xfs_bmap_btalloc_nullfb(ap, &args, &blen); if (error) return error; } else if (ap->flist->xbf_low) { diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h index f84bd7af43bec3..38ba36e9b2f0c5 100644 --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h @@ -156,8 +156,8 @@ int xfs_bmap_first_unused(struct xfs_trans *tp, struct xfs_inode *ip, xfs_extlen_t len, xfs_fileoff_t *unused, int whichfork); int xfs_bmap_last_before(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t *last_block, int whichfork); -int xfs_bmap_last_offset(struct xfs_trans *tp, struct xfs_inode *ip, - xfs_fileoff_t *unused, int whichfork); +int xfs_bmap_last_offset(struct xfs_inode *ip, xfs_fileoff_t *unused, + int whichfork); int xfs_bmap_one_block(struct xfs_inode *ip, int whichfork); int xfs_bmap_read_extents(struct xfs_trans *tp, struct xfs_inode *ip, int whichfork); diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 818d546664e757..948836c4fd90de 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c @@ -84,7 +84,7 @@ xfs_bmdr_to_bmbt( rblock->bb_level = dblock->bb_level; ASSERT(be16_to_cpu(rblock->bb_level) > 0); rblock->bb_numrecs = dblock->bb_numrecs; - dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0); + dmxr = xfs_bmdr_maxrecs(dblocklen, 0); fkp = XFS_BMDR_KEY_ADDR(dblock, 1); tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); @@ -443,7 +443,7 @@ xfs_bmbt_to_bmdr( ASSERT(rblock->bb_level != 0); dblock->bb_level = rblock->bb_level; dblock->bb_numrecs = rblock->bb_numrecs; - dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0); + dmxr = xfs_bmdr_maxrecs(dblocklen, 0); fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); tkp = XFS_BMDR_KEY_ADDR(dblock, 1); fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); @@ -519,7 +519,6 @@ xfs_bmbt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, - int length, int *stat) { xfs_alloc_arg_t args; /* block allocation args */ @@ -672,8 +671,7 @@ xfs_bmbt_get_dmaxrecs( { if (level != cur->bc_nlevels - 1) return cur->bc_mp->m_bmap_dmxr[level != 0]; - return xfs_bmdr_maxrecs(cur->bc_mp, cur->bc_private.b.forksize, - level == 0); + return xfs_bmdr_maxrecs(cur->bc_private.b.forksize, level == 0); } STATIC void @@ -914,7 +912,6 @@ xfs_bmbt_maxrecs( */ int xfs_bmdr_maxrecs( - struct xfs_mount *mp, int blocklen, int leaf) { diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h index 6e42e1e50b8939..819a8a4dee952d 100644 --- a/fs/xfs/xfs_bmap_btree.h +++ b/fs/xfs/xfs_bmap_btree.h @@ -130,7 +130,7 @@ extern void xfs_bmbt_to_bmdr(struct xfs_mount *, struct xfs_btree_block *, int, xfs_bmdr_block_t *, int); extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level); -extern int xfs_bmdr_maxrecs(struct xfs_mount *, int blocklen, int leaf); +extern int xfs_bmdr_maxrecs(int blocklen, int leaf); extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf); extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip, diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index e80d59fdf89a8b..182bac2bb276f5 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c @@ -43,9 +43,10 @@ kmem_zone_t *xfs_btree_cur_zone; * Btree magic numbers. */ static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = { - { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC }, + { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC, + XFS_FIBT_MAGIC }, { XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC, - XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC } + XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC, XFS_FIBT_CRC_MAGIC } }; #define xfs_btree_magic(cur) \ xfs_magics[!!((cur)->bc_flags & XFS_BTREE_CRC_BLOCKS)][cur->bc_btnum] @@ -1115,6 +1116,7 @@ xfs_btree_set_refs( xfs_buf_set_ref(bp, XFS_ALLOC_BTREE_REF); break; case XFS_BTNUM_INO: + case XFS_BTNUM_FINO: xfs_buf_set_ref(bp, XFS_INO_BTREE_REF); break; case XFS_BTNUM_BMAP: @@ -1159,7 +1161,6 @@ STATIC int xfs_btree_read_buf_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, - int level, int flags, struct xfs_btree_block **block, struct xfs_buf **bpp) @@ -1517,8 +1518,8 @@ xfs_btree_increment( union xfs_btree_ptr *ptrp; ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block); - error = xfs_btree_read_buf_block(cur, ptrp, --lev, - 0, &block, &bp); + --lev; + error = xfs_btree_read_buf_block(cur, ptrp, 0, &block, &bp); if (error) goto error0; @@ -1616,8 +1617,8 @@ xfs_btree_decrement( union xfs_btree_ptr *ptrp; ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block); - error = xfs_btree_read_buf_block(cur, ptrp, --lev, - 0, &block, &bp); + --lev; + error = xfs_btree_read_buf_block(cur, ptrp, 0, &block, &bp); if (error) goto error0; xfs_btree_setbuf(cur, lev, bp); @@ -1667,7 +1668,7 @@ xfs_btree_lookup_get_block( return 0; } - error = xfs_btree_read_buf_block(cur, pp, level, 0, blkp, &bp); + error = xfs_btree_read_buf_block(cur, pp, 0, blkp, &bp); if (error) return error; @@ -2018,7 +2019,7 @@ xfs_btree_lshift( goto out0; /* Set up the left neighbor as "left". */ - error = xfs_btree_read_buf_block(cur, &lptr, level, 0, &left, &lbp); + error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); if (error) goto error0; @@ -2202,7 +2203,7 @@ xfs_btree_rshift( goto out0; /* Set up the right neighbor as "right". */ - error = xfs_btree_read_buf_block(cur, &rptr, level, 0, &right, &rbp); + error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); if (error) goto error0; @@ -2372,7 +2373,7 @@ xfs_btree_split( xfs_btree_buf_to_ptr(cur, lbp, &lptr); /* Allocate the new block. If we can't do it, we're toast. Give up. */ - error = cur->bc_ops->alloc_block(cur, &lptr, &rptr, 1, stat); + error = cur->bc_ops->alloc_block(cur, &lptr, &rptr, stat); if (error) goto error0; if (*stat == 0) @@ -2470,7 +2471,7 @@ xfs_btree_split( * point back to right instead of to left. */ if (!xfs_btree_ptr_is_null(cur, &rrptr)) { - error = xfs_btree_read_buf_block(cur, &rrptr, level, + error = xfs_btree_read_buf_block(cur, &rrptr, 0, &rrblock, &rrbp); if (error) goto error0; @@ -2545,7 +2546,7 @@ xfs_btree_new_iroot( pp = xfs_btree_ptr_addr(cur, 1, block); /* Allocate the new block. If we can't do it, we're toast. Give up. */ - error = cur->bc_ops->alloc_block(cur, pp, &nptr, 1, stat); + error = cur->bc_ops->alloc_block(cur, pp, &nptr, stat); if (error) goto error0; if (*stat == 0) { @@ -2649,7 +2650,7 @@ xfs_btree_new_root( cur->bc_ops->init_ptr_from_cur(cur, &rptr); /* Allocate the new block. If we can't do it, we're toast. Give up. */ - error = cur->bc_ops->alloc_block(cur, &rptr, &lptr, 1, stat); + error = cur->bc_ops->alloc_block(cur, &rptr, &lptr, stat); if (error) goto error0; if (*stat == 0) @@ -2684,8 +2685,7 @@ xfs_btree_new_root( lbp = bp; xfs_btree_buf_to_ptr(cur, lbp, &lptr); left = block; - error = xfs_btree_read_buf_block(cur, &rptr, - cur->bc_nlevels - 1, 0, &right, &rbp); + error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); if (error) goto error0; bp = rbp; @@ -2696,8 +2696,7 @@ xfs_btree_new_root( xfs_btree_buf_to_ptr(cur, rbp, &rptr); right = block; xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); - error = xfs_btree_read_buf_block(cur, &lptr, - cur->bc_nlevels - 1, 0, &left, &lbp); + error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); if (error) goto error0; bp = lbp; @@ -3649,8 +3648,7 @@ xfs_btree_delrec( rptr = cptr; right = block; rbp = bp; - error = xfs_btree_read_buf_block(cur, &lptr, level, - 0, &left, &lbp); + error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); if (error) goto error0; @@ -3667,8 +3665,7 @@ xfs_btree_delrec( lptr = cptr; left = block; lbp = bp; - error = xfs_btree_read_buf_block(cur, &rptr, level, - 0, &right, &rbp); + error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); if (error) goto error0; @@ -3740,8 +3737,7 @@ xfs_btree_delrec( /* If there is a right sibling, point it to the remaining block. */ xfs_btree_get_sibling(cur, left, &cptr, XFS_BB_RIGHTSIB); if (!xfs_btree_ptr_is_null(cur, &cptr)) { - error = xfs_btree_read_buf_block(cur, &cptr, level, - 0, &rrblock, &rrbp); + error = xfs_btree_read_buf_block(cur, &cptr, 0, &rrblock, &rrbp); if (error) goto error0; xfs_btree_set_sibling(cur, rrblock, &lptr, XFS_BB_LEFTSIB); diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h index 91e34f21bacea7..a04b69422f676c 100644 --- a/fs/xfs/xfs_btree.h +++ b/fs/xfs/xfs_btree.h @@ -62,6 +62,7 @@ union xfs_btree_rec { #define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi) #define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi) #define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi) +#define XFS_BTNUM_FINO ((xfs_btnum_t)XFS_BTNUM_FINOi) /* * For logging record fields. @@ -92,6 +93,7 @@ do { \ case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break; \ case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break; \ case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break; \ + case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(fibt, stat); break; \ case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \ } \ } while (0) @@ -105,6 +107,7 @@ do { \ case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \ case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \ case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \ + case XFS_BTNUM_FINO: __XFS_BTREE_STATS_ADD(fibt, stat, val); break; \ case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \ } \ } while (0) @@ -129,7 +132,7 @@ struct xfs_btree_ops { int (*alloc_block)(struct xfs_btree_cur *cur, union xfs_btree_ptr *start_bno, union xfs_btree_ptr *new_bno, - int length, int *stat); + int *stat); int (*free_block)(struct xfs_btree_cur *cur, struct xfs_buf *bp); /* update last record information */ diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index cb10a0aaab3aa7..7a34a1ae655246 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -216,8 +216,7 @@ _xfs_buf_alloc( STATIC int _xfs_buf_get_pages( xfs_buf_t *bp, - int page_count, - xfs_buf_flags_t flags) + int page_count) { /* Make sure that we have a page list */ if (bp->b_pages == NULL) { @@ -330,7 +329,7 @@ xfs_buf_allocate_memory( end = (BBTOB(bp->b_maps[0].bm_bn + bp->b_length) + PAGE_SIZE - 1) >> PAGE_SHIFT; page_count = end - start; - error = _xfs_buf_get_pages(bp, page_count, flags); + error = _xfs_buf_get_pages(bp, page_count); if (unlikely(error)) return error; @@ -778,7 +777,7 @@ xfs_buf_associate_memory( bp->b_pages = NULL; bp->b_addr = mem; - rval = _xfs_buf_get_pages(bp, page_count, 0); + rval = _xfs_buf_get_pages(bp, page_count); if (rval) return rval; @@ -811,7 +810,7 @@ xfs_buf_get_uncached( goto fail; page_count = PAGE_ALIGN(numblks << BBSHIFT) >> PAGE_SHIFT; - error = _xfs_buf_get_pages(bp, page_count, 0); + error = _xfs_buf_get_pages(bp, page_count); if (error) goto fail_free_buf; @@ -1615,7 +1614,6 @@ xfs_free_buftarg( int xfs_setsize_buftarg( xfs_buftarg_t *btp, - unsigned int blocksize, unsigned int sectorsize) { /* Set up metadata sector size info */ @@ -1650,16 +1648,13 @@ xfs_setsize_buftarg_early( xfs_buftarg_t *btp, struct block_device *bdev) { - return xfs_setsize_buftarg(btp, PAGE_SIZE, - bdev_logical_block_size(bdev)); + return xfs_setsize_buftarg(btp, bdev_logical_block_size(bdev)); } xfs_buftarg_t * xfs_alloc_buftarg( struct xfs_mount *mp, - struct block_device *bdev, - int external, - const char *fsname) + struct block_device *bdev) { xfs_buftarg_t *btp; diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h index b8a3abf6cf475e..0e47fd1fedbaa1 100644 --- a/fs/xfs/xfs_buf.h +++ b/fs/xfs/xfs_buf.h @@ -387,10 +387,10 @@ xfs_buf_update_cksum(struct xfs_buf *bp, unsigned long cksum_offset) * Handling of buftargs. */ extern xfs_buftarg_t *xfs_alloc_buftarg(struct xfs_mount *, - struct block_device *, int, const char *); + struct block_device *); extern void xfs_free_buftarg(struct xfs_mount *, struct xfs_buftarg *); extern void xfs_wait_buftarg(xfs_buftarg_t *); -extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); +extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int); #define xfs_getsize_buftarg(buftarg) block_size((buftarg)->bt_bdev) #define xfs_readonly_buftarg(buftarg) bdev_read_only((buftarg)->bt_bdev) diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 8752821443bee0..64b17f5bed9a73 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -812,7 +812,6 @@ xfs_buf_item_init( */ static void xfs_buf_item_log_segment( - struct xfs_buf_log_item *bip, uint first, uint last, uint *map) @@ -920,7 +919,7 @@ xfs_buf_item_log( if (end > last) end = last; - xfs_buf_item_log_segment(bip, first, end, + xfs_buf_item_log_segment(first, end, &bip->bli_formats[i].blf_data_map[0]); start += bp->b_maps[i].bm_len; diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index 6cc5f6785a7740..9eec594cc25a38 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c @@ -2462,7 +2462,6 @@ xfs_buf_map_from_irec( */ static int xfs_dabuf_map( - struct xfs_trans *trans, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, @@ -2558,7 +2557,7 @@ xfs_da_get_buf( *bpp = NULL; mapp = ↦ nmap = 1; - error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork, + error = xfs_dabuf_map(dp, bno, mappedbno, whichfork, &mapp, &nmap); if (error) { /* mapping a hole is not an error, but we don't continue */ @@ -2606,7 +2605,7 @@ xfs_da_read_buf( *bpp = NULL; mapp = ↦ nmap = 1; - error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork, + error = xfs_dabuf_map(dp, bno, mappedbno, whichfork, &mapp, &nmap); if (error) { /* mapping a hole is not an error, but we don't continue */ @@ -2679,7 +2678,6 @@ xfs_da_read_buf( */ xfs_daddr_t xfs_da_reada_buf( - struct xfs_trans *trans, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, @@ -2693,7 +2691,7 @@ xfs_da_reada_buf( mapp = ↦ nmap = 1; - error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork, + error = xfs_dabuf_map(dp, bno, mappedbno, whichfork, &mapp, &nmap); if (error) { /* mapping a hole is not an error, but we don't continue */ diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h index 201c6091d26abf..c824a0aa039f35 100644 --- a/fs/xfs/xfs_da_btree.h +++ b/fs/xfs/xfs_da_btree.h @@ -185,9 +185,9 @@ int xfs_da_read_buf(struct xfs_trans *trans, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp, int whichfork, const struct xfs_buf_ops *ops); -xfs_daddr_t xfs_da_reada_buf(struct xfs_trans *trans, struct xfs_inode *dp, - xfs_dablk_t bno, xfs_daddr_t mapped_bno, - int whichfork, const struct xfs_buf_ops *ops); +xfs_daddr_t xfs_da_reada_buf(struct xfs_inode *dp, xfs_dablk_t bno, + xfs_daddr_t mapped_bno, int whichfork, + const struct xfs_buf_ops *ops); int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, struct xfs_buf *dead_buf); diff --git a/fs/xfs/xfs_da_format.h b/fs/xfs/xfs_da_format.h index a19d3f8f639cf3..1432b576b4a779 100644 --- a/fs/xfs/xfs_da_format.h +++ b/fs/xfs/xfs_da_format.h @@ -541,7 +541,7 @@ xfs_dir2_leaf_bests_p(struct xfs_dir2_leaf_tail *ltp) * Convert dataptr to byte in file space */ static inline xfs_dir2_off_t -xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp) +xfs_dir2_dataptr_to_byte(xfs_dir2_dataptr_t dp) { return (xfs_dir2_off_t)dp << XFS_DIR2_DATA_ALIGN_LOG; } @@ -550,7 +550,7 @@ xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp) * Convert byte in file space to dataptr. It had better be aligned. */ static inline xfs_dir2_dataptr_t -xfs_dir2_byte_to_dataptr(struct xfs_mount *mp, xfs_dir2_off_t by) +xfs_dir2_byte_to_dataptr(xfs_dir2_off_t by) { return (xfs_dir2_dataptr_t)(by >> XFS_DIR2_DATA_ALIGN_LOG); } @@ -571,7 +571,7 @@ xfs_dir2_byte_to_db(struct xfs_mount *mp, xfs_dir2_off_t by) static inline xfs_dir2_db_t xfs_dir2_dataptr_to_db(struct xfs_mount *mp, xfs_dir2_dataptr_t dp) { - return xfs_dir2_byte_to_db(mp, xfs_dir2_dataptr_to_byte(mp, dp)); + return xfs_dir2_byte_to_db(mp, xfs_dir2_dataptr_to_byte(dp)); } /* @@ -590,7 +590,7 @@ xfs_dir2_byte_to_off(struct xfs_mount *mp, xfs_dir2_off_t by) static inline xfs_dir2_data_aoff_t xfs_dir2_dataptr_to_off(struct xfs_mount *mp, xfs_dir2_dataptr_t dp) { - return xfs_dir2_byte_to_off(mp, xfs_dir2_dataptr_to_byte(mp, dp)); + return xfs_dir2_byte_to_off(mp, xfs_dir2_dataptr_to_byte(dp)); } /* @@ -629,7 +629,7 @@ static inline xfs_dir2_dataptr_t xfs_dir2_db_off_to_dataptr(struct xfs_mount *mp, xfs_dir2_db_t db, xfs_dir2_data_aoff_t o) { - return xfs_dir2_byte_to_dataptr(mp, xfs_dir2_db_off_to_byte(mp, db, o)); + return xfs_dir2_byte_to_dataptr(xfs_dir2_db_off_to_byte(mp, db, o)); } /* diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index fda46253966a5c..e365c98c0f1ea9 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c @@ -244,7 +244,7 @@ xfs_dir_createname( goto out_free; } - rval = xfs_dir2_isblock(tp, dp, &v); + rval = xfs_dir2_isblock(dp, &v); if (rval) goto out_free; if (v) { @@ -252,7 +252,7 @@ xfs_dir_createname( goto out_free; } - rval = xfs_dir2_isleaf(tp, dp, &v); + rval = xfs_dir2_isleaf(dp, &v); if (rval) goto out_free; if (v) @@ -336,7 +336,7 @@ xfs_dir_lookup( goto out_check_rval; } - rval = xfs_dir2_isblock(tp, dp, &v); + rval = xfs_dir2_isblock(dp, &v); if (rval) goto out_free; if (v) { @@ -344,7 +344,7 @@ xfs_dir_lookup( goto out_check_rval; } - rval = xfs_dir2_isleaf(tp, dp, &v); + rval = xfs_dir2_isleaf(dp, &v); if (rval) goto out_free; if (v) @@ -408,7 +408,7 @@ xfs_dir_removename( goto out_free; } - rval = xfs_dir2_isblock(tp, dp, &v); + rval = xfs_dir2_isblock(dp, &v); if (rval) goto out_free; if (v) { @@ -416,7 +416,7 @@ xfs_dir_removename( goto out_free; } - rval = xfs_dir2_isleaf(tp, dp, &v); + rval = xfs_dir2_isleaf(dp, &v); if (rval) goto out_free; if (v) @@ -472,7 +472,7 @@ xfs_dir_replace( goto out_free; } - rval = xfs_dir2_isblock(tp, dp, &v); + rval = xfs_dir2_isblock(dp, &v); if (rval) goto out_free; if (v) { @@ -480,7 +480,7 @@ xfs_dir_replace( goto out_free; } - rval = xfs_dir2_isleaf(tp, dp, &v); + rval = xfs_dir2_isleaf(dp, &v); if (rval) goto out_free; if (v) @@ -531,7 +531,7 @@ xfs_dir_canenter( goto out_free; } - rval = xfs_dir2_isblock(tp, dp, &v); + rval = xfs_dir2_isblock(dp, &v); if (rval) goto out_free; if (v) { @@ -539,7 +539,7 @@ xfs_dir_canenter( goto out_free; } - rval = xfs_dir2_isleaf(tp, dp, &v); + rval = xfs_dir2_isleaf(dp, &v); if (rval) goto out_free; if (v) @@ -607,7 +607,6 @@ xfs_dir2_grow_inode( */ int xfs_dir2_isblock( - xfs_trans_t *tp, xfs_inode_t *dp, int *vp) /* out: 1 is block, 0 is not block */ { @@ -616,7 +615,7 @@ xfs_dir2_isblock( int rval; mp = dp->i_mount; - if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) + if ((rval = xfs_bmap_last_offset(dp, &last, XFS_DATA_FORK))) return rval; rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize; ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize); @@ -629,7 +628,6 @@ xfs_dir2_isblock( */ int xfs_dir2_isleaf( - xfs_trans_t *tp, xfs_inode_t *dp, int *vp) /* out: 1 is leaf, 0 is not leaf */ { @@ -638,7 +636,7 @@ xfs_dir2_isleaf( int rval; mp = dp->i_mount; - if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) + if ((rval = xfs_bmap_last_offset(dp, &last, XFS_DATA_FORK))) return rval; *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog); return 0; diff --git a/fs/xfs/xfs_dir2.h b/fs/xfs/xfs_dir2.h index cec70e0781ab66..64a6b19c2fd0b0 100644 --- a/fs/xfs/xfs_dir2.h +++ b/fs/xfs/xfs_dir2.h @@ -142,8 +142,8 @@ extern int xfs_dir2_sf_to_block(struct xfs_da_args *args); /* * Interface routines used by userspace utilities */ -extern int xfs_dir2_isblock(struct xfs_trans *tp, struct xfs_inode *dp, int *r); -extern int xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp, int *r); +extern int xfs_dir2_isblock(struct xfs_inode *dp, int *r); +extern int xfs_dir2_isleaf(struct xfs_inode *dp, int *r); extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, struct xfs_buf *bp); diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c index 4f6a38cb83a4ee..dd9d00515582e3 100644 --- a/fs/xfs/xfs_dir2_block.c +++ b/fs/xfs/xfs_dir2_block.c @@ -319,7 +319,6 @@ xfs_dir2_block_compact( (xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr), (xfs_dir2_data_aoff_t)((be32_to_cpu(btp->stale) - 1) * sizeof(*blp)), needlog, &needscan); - blp += be32_to_cpu(btp->stale) - 1; btp->stale = cpu_to_be32(1); /* * If we now need to rebuild the bestfree map, do so. @@ -537,7 +536,7 @@ xfs_dir2_block_addname( * Fill in the leaf entry. */ blp[mid].hashval = cpu_to_be32(args->hashval); - blp[mid].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, + blp[mid].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( (char *)dep - (char *)hdr)); xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh); /* @@ -1170,7 +1169,7 @@ xfs_dir2_sf_to_block( *tagp = cpu_to_be16((char *)dep - (char *)hdr); xfs_dir2_data_log_entry(tp, dp, bp, dep); blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot); - blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, + blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( (char *)dep - (char *)hdr)); /* * Create entry for .. @@ -1184,7 +1183,7 @@ xfs_dir2_sf_to_block( *tagp = cpu_to_be16((char *)dep - (char *)hdr); xfs_dir2_data_log_entry(tp, dp, bp, dep); blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot); - blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, + blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( (char *)dep - (char *)hdr)); offset = dp->d_ops->data_first_offset; /* @@ -1238,7 +1237,7 @@ xfs_dir2_sf_to_block( name.len = sfep->namelen; blp[2 + i].hashval = cpu_to_be32(mp->m_dirnameops-> hashname(&name)); - blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, + blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( (char *)dep - (char *)hdr)); offset = (int)((char *)(tagp + 1) - (char *)hdr); if (++i == sfp->count) diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c index afa4ad523f3f02..bae8b5b8d1c2c7 100644 --- a/fs/xfs/xfs_dir2_data.c +++ b/fs/xfs/xfs_dir2_data.c @@ -329,12 +329,11 @@ xfs_dir3_data_read( int xfs_dir3_data_readahead( - struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mapped_bno) { - return xfs_da_reada_buf(tp, dp, bno, mapped_bno, + return xfs_da_reada_buf(dp, bno, mapped_bno, XFS_DATA_FORK, &xfs_dir3_data_reada_buf_ops); } diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index d36e97df1187eb..f571723e237855 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c @@ -1708,7 +1708,7 @@ xfs_dir2_node_to_leaf( /* * Get the last offset in the file. */ - if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) { + if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK))) { return error; } fo -= mp->m_dirblkfsbs; diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c index cb434d732681a3..9cb91ee0914b8c 100644 --- a/fs/xfs/xfs_dir2_node.c +++ b/fs/xfs/xfs_dir2_node.c @@ -1727,7 +1727,7 @@ xfs_dir2_node_addname_int( if (dbno == -1) { xfs_fileoff_t fo; /* freespace block number */ - if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) + if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK))) return error; lastfbno = xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo); fbno = ifbno; diff --git a/fs/xfs/xfs_dir2_priv.h b/fs/xfs/xfs_dir2_priv.h index 8b9d2281f85b3c..2429960739e984 100644 --- a/fs/xfs/xfs_dir2_priv.h +++ b/fs/xfs/xfs_dir2_priv.h @@ -54,8 +54,8 @@ extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args, extern int __xfs_dir3_data_check(struct xfs_inode *dp, struct xfs_buf *bp); extern int xfs_dir3_data_read(struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mapped_bno, struct xfs_buf **bpp); -extern int xfs_dir3_data_readahead(struct xfs_trans *tp, struct xfs_inode *dp, - xfs_dablk_t bno, xfs_daddr_t mapped_bno); +extern int xfs_dir3_data_readahead(struct xfs_inode *dp, xfs_dablk_t bno, + xfs_daddr_t mapped_bno); extern struct xfs_dir2_data_free * xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr, diff --git a/fs/xfs/xfs_dir2_readdir.c b/fs/xfs/xfs_dir2_readdir.c index aead369e1c3047..bf7a5cee7adc00 100644 --- a/fs/xfs/xfs_dir2_readdir.c +++ b/fs/xfs/xfs_dir2_readdir.c @@ -434,7 +434,7 @@ xfs_dir2_leaf_readbuf( */ if (i > mip->ra_current && map[mip->ra_index].br_blockcount >= mp->m_dirblkfsbs) { - xfs_dir3_data_readahead(NULL, dp, + xfs_dir3_data_readahead(dp, map[mip->ra_index].br_startoff + mip->ra_offset, XFS_FSB_TO_DADDR(mp, map[mip->ra_index].br_startblock + @@ -447,7 +447,7 @@ xfs_dir2_leaf_readbuf( * use our mapping, but this is a very rare case. */ else if (i > mip->ra_current) { - xfs_dir3_data_readahead(NULL, dp, + xfs_dir3_data_readahead(dp, map[mip->ra_index].br_startoff + mip->ra_offset, -1); mip->ra_current = i; @@ -456,7 +456,7 @@ xfs_dir2_leaf_readbuf( /* * Advance offset through the mapping table. */ - for (j = 0; j < mp->m_dirblkfsbs; j++) { + for (j = 0; j < mp->m_dirblkfsbs; j += length ) { /* * The rest of this extent but not more than a dir * block. @@ -464,7 +464,6 @@ xfs_dir2_leaf_readbuf( length = min_t(int, mp->m_dirblkfsbs, map[mip->ra_index].br_blockcount - mip->ra_offset); - j += length; mip->ra_offset += length; /* @@ -531,7 +530,7 @@ xfs_dir2_leaf_getdents( * Inside the loop we keep the main offset value as a byte offset * in the directory file. */ - curoff = xfs_dir2_dataptr_to_byte(mp, ctx->pos); + curoff = xfs_dir2_dataptr_to_byte(ctx->pos); /* * Force this conversion through db so we truncate the offset @@ -635,7 +634,7 @@ xfs_dir2_leaf_getdents( length = dp->d_ops->data_entsize(dep->namelen); filetype = dp->d_ops->data_get_ftype(dep); - ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff; + ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff; if (!dir_emit(ctx, (char *)dep->name, dep->namelen, be64_to_cpu(dep->inumber), xfs_dir3_get_dtype(mp, filetype))) @@ -653,10 +652,10 @@ xfs_dir2_leaf_getdents( /* * All done. Set output offset value to current offset. */ - if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR)) + if (curoff > xfs_dir2_dataptr_to_byte(XFS_DIR2_MAX_DATAPTR)) ctx->pos = XFS_DIR2_MAX_DATAPTR & 0x7fffffff; else - ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff; + ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff; kmem_free(map_info); if (bp) xfs_trans_brelse(NULL, bp); @@ -687,7 +686,7 @@ xfs_readdir( lock_mode = xfs_ilock_data_map_shared(dp); if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) rval = xfs_dir2_sf_getdents(dp, ctx); - else if ((rval = xfs_dir2_isblock(NULL, dp, &v))) + else if ((rval = xfs_dir2_isblock(dp, &v))) ; else if (v) rval = xfs_dir2_block_getdents(dp, ctx); diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c index 3725fb1b902b8b..7aab8ec117ad65 100644 --- a/fs/xfs/xfs_dir2_sf.c +++ b/fs/xfs/xfs_dir2_sf.c @@ -285,14 +285,12 @@ int /* error */ xfs_dir2_sf_addname( xfs_da_args_t *args) /* operation arguments */ { - int add_entsize; /* size of the new entry */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ int incr_isize; /* total change in size */ int new_isize; /* di_size after adding name */ int objchange; /* changing to 8-byte inodes */ xfs_dir2_data_aoff_t offset = 0; /* offset for new entry */ - int old_isize; /* di_size before adding name */ int pick; /* which algorithm to use */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ xfs_dir2_sf_entry_t *sfep = NULL; /* shortform entry */ @@ -316,8 +314,7 @@ xfs_dir2_sf_addname( /* * Compute entry (and change in) size. */ - add_entsize = dp->d_ops->sf_entsize(sfp, args->namelen); - incr_isize = add_entsize; + incr_isize = dp->d_ops->sf_entsize(sfp, args->namelen); objchange = 0; #if XFS_BIG_INUMS /* @@ -325,11 +322,8 @@ xfs_dir2_sf_addname( */ if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) { /* - * Yes, adjust the entry size and the total size. + * Yes, adjust the inode size. old count + (parent + new) */ - add_entsize += - (uint)sizeof(xfs_dir2_ino8_t) - - (uint)sizeof(xfs_dir2_ino4_t); incr_isize += (sfp->count + 2) * ((uint)sizeof(xfs_dir2_ino8_t) - @@ -337,8 +331,7 @@ xfs_dir2_sf_addname( objchange = 1; } #endif - old_isize = (int)dp->i_d.di_size; - new_isize = old_isize + incr_isize; + new_isize = (int)dp->i_d.di_size + incr_isize; /* * Won't fit as shortform any more (due to size), * or the pick routine says it won't (due to offset values). @@ -1110,9 +1103,9 @@ xfs_dir2_sf_toino4( } /* - * Convert from 4-byte inode numbers to 8-byte inode numbers. - * The new 8-byte inode number is not there yet, we leave with the - * count 1 but no corresponding entry. + * Convert existing entries from 4-byte inode numbers to 8-byte inode numbers. + * The new entry w/ an 8-byte inode number is not there yet; we leave with + * i8count set to 1, but no corresponding 8-byte entry. */ static void xfs_dir2_sf_toino8( @@ -1145,7 +1138,7 @@ xfs_dir2_sf_toino8( ASSERT(oldsfp->i8count == 0); memcpy(buf, oldsfp, oldsize); /* - * Compute the new inode size. + * Compute the new inode size (nb: entry count + 1 for parent) */ newsize = oldsize + diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c index 868b19f096bfa4..5fec738f1f2e1b 100644 --- a/fs/xfs/xfs_dquot.c +++ b/fs/xfs/xfs_dquot.c @@ -832,47 +832,6 @@ xfs_qm_dqget( return (0); } - -STATIC void -xfs_qm_dqput_final( - struct xfs_dquot *dqp) -{ - struct xfs_quotainfo *qi = dqp->q_mount->m_quotainfo; - struct xfs_dquot *gdqp; - struct xfs_dquot *pdqp; - - trace_xfs_dqput_free(dqp); - - if (list_lru_add(&qi->qi_lru, &dqp->q_lru)) - XFS_STATS_INC(xs_qm_dquot_unused); - - /* - * If we just added a udquot to the freelist, then we want to release - * the gdquot/pdquot reference that it (probably) has. Otherwise it'll - * keep the gdquot/pdquot from getting reclaimed. - */ - gdqp = dqp->q_gdquot; - if (gdqp) { - xfs_dqlock(gdqp); - dqp->q_gdquot = NULL; - } - - pdqp = dqp->q_pdquot; - if (pdqp) { - xfs_dqlock(pdqp); - dqp->q_pdquot = NULL; - } - xfs_dqunlock(dqp); - - /* - * If we had a group/project quota hint, release it now. - */ - if (gdqp) - xfs_qm_dqput(gdqp); - if (pdqp) - xfs_qm_dqput(pdqp); -} - /* * Release a reference to the dquot (decrement ref-count) and unlock it. * @@ -888,10 +847,14 @@ xfs_qm_dqput( trace_xfs_dqput(dqp); - if (--dqp->q_nrefs > 0) - xfs_dqunlock(dqp); - else - xfs_qm_dqput_final(dqp); + if (--dqp->q_nrefs == 0) { + struct xfs_quotainfo *qi = dqp->q_mount->m_quotainfo; + trace_xfs_dqput_free(dqp); + + if (list_lru_add(&qi->qi_lru, &dqp->q_lru)) + XFS_STATS_INC(xs_qm_dquot_unused); + } + xfs_dqunlock(dqp); } /* diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h index d22ed0053c32ea..68a68f7048374a 100644 --- a/fs/xfs/xfs_dquot.h +++ b/fs/xfs/xfs_dquot.h @@ -52,8 +52,6 @@ typedef struct xfs_dquot { int q_bufoffset; /* off of dq in buffer (# dquots) */ xfs_fileoff_t q_fileoffset; /* offset in quotas file */ - struct xfs_dquot*q_gdquot; /* group dquot, hint only */ - struct xfs_dquot*q_pdquot; /* project dquot, hint only */ xfs_disk_dquot_t q_core; /* actual usage & quotas */ xfs_dq_logitem_t q_logitem; /* dquot log item */ xfs_qcnt_t q_res_bcount; /* total regular nblks used+reserved */ diff --git a/fs/xfs/xfs_dquot_buf.c b/fs/xfs/xfs_dquot_buf.c index 610da817773745..c2ac0c611ad877 100644 --- a/fs/xfs/xfs_dquot_buf.c +++ b/fs/xfs/xfs_dquot_buf.c @@ -35,7 +35,6 @@ int xfs_calc_dquots_per_chunk( - struct xfs_mount *mp, unsigned int nbblks) /* basic block units */ { unsigned int ndquots; @@ -194,7 +193,7 @@ xfs_dquot_buf_verify_crc( if (mp->m_quotainfo) ndquots = mp->m_quotainfo->qi_dqperchunk; else - ndquots = xfs_calc_dquots_per_chunk(mp, + ndquots = xfs_calc_dquots_per_chunk( XFS_BB_TO_FSB(mp, bp->b_length)); for (i = 0; i < ndquots; i++, d++) { @@ -225,7 +224,7 @@ xfs_dquot_buf_verify( if (mp->m_quotainfo) ndquots = mp->m_quotainfo->qi_dqperchunk; else - ndquots = xfs_calc_dquots_per_chunk(mp, bp->b_length); + ndquots = xfs_calc_dquots_per_chunk(bp->b_length); /* * On the first read of the buffer, verify that each dquot is valid. diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 951a2321ee010f..97855c559bcbae 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -229,34 +229,27 @@ xfs_file_fsync( } STATIC ssize_t -xfs_file_aio_read( +xfs_file_read_iter( struct kiocb *iocb, - const struct iovec *iovp, - unsigned long nr_segs, - loff_t pos) + struct iov_iter *to) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; - size_t size = 0; + size_t size = iov_iter_count(to); ssize_t ret = 0; int ioflags = 0; xfs_fsize_t n; + loff_t pos = iocb->ki_pos; XFS_STATS_INC(xs_read_calls); - BUG_ON(iocb->ki_pos != pos); - if (unlikely(file->f_flags & O_DIRECT)) ioflags |= IO_ISDIRECT; if (file->f_mode & FMODE_NOCMTIME) ioflags |= IO_INVIS; - ret = generic_segment_checks(iovp, &nr_segs, &size, VERIFY_WRITE); - if (ret < 0) - return ret; - if (unlikely(ioflags & IO_ISDIRECT)) { xfs_buftarg_t *target = XFS_IS_REALTIME_INODE(ip) ? @@ -309,7 +302,7 @@ xfs_file_aio_read( trace_xfs_file_read(ip, size, pos, ioflags); - ret = generic_file_aio_read(iocb, iovp, nr_segs, pos); + ret = generic_file_read_iter(iocb, to); if (ret > 0) XFS_STATS_ADD(xs_read_bytes, ret); @@ -349,47 +342,6 @@ xfs_file_splice_read( return ret; } -/* - * xfs_file_splice_write() does not use xfs_rw_ilock() because - * generic_file_splice_write() takes the i_mutex itself. This, in theory, - * couuld cause lock inversions between the aio_write path and the splice path - * if someone is doing concurrent splice(2) based writes and write(2) based - * writes to the same inode. The only real way to fix this is to re-implement - * the generic code here with correct locking orders. - */ -STATIC ssize_t -xfs_file_splice_write( - struct pipe_inode_info *pipe, - struct file *outfilp, - loff_t *ppos, - size_t count, - unsigned int flags) -{ - struct inode *inode = outfilp->f_mapping->host; - struct xfs_inode *ip = XFS_I(inode); - int ioflags = 0; - ssize_t ret; - - XFS_STATS_INC(xs_write_calls); - - if (outfilp->f_mode & FMODE_NOCMTIME) - ioflags |= IO_INVIS; - - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) - return -EIO; - - xfs_ilock(ip, XFS_IOLOCK_EXCL); - - trace_xfs_file_splice_write(ip, count, *ppos, ioflags); - - ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); - if (ret > 0) - XFS_STATS_ADD(xs_write_bytes, ret); - - xfs_iunlock(ip, XFS_IOLOCK_EXCL); - return ret; -} - /* * This routine is called to handle zeroing any space in the last block of the * file that is beyond the EOF. We do this since the size is being increased @@ -625,10 +577,7 @@ xfs_file_aio_write_checks( STATIC ssize_t xfs_file_dio_aio_write( struct kiocb *iocb, - const struct iovec *iovp, - unsigned long nr_segs, - loff_t pos, - size_t ocount) + struct iov_iter *from) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -636,9 +585,10 @@ xfs_file_dio_aio_write( struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; ssize_t ret = 0; - size_t count = ocount; int unaligned_io = 0; int iolock; + size_t count = iov_iter_count(from); + loff_t pos = iocb->ki_pos; struct xfs_buftarg *target = XFS_IS_REALTIME_INODE(ip) ? mp->m_rtdev_targp : mp->m_ddev_targp; @@ -677,6 +627,7 @@ xfs_file_dio_aio_write( ret = xfs_file_aio_write_checks(file, &pos, &count, &iolock); if (ret) goto out; + iov_iter_truncate(from, count); if (mapping->nrpages) { ret = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, @@ -698,8 +649,7 @@ xfs_file_dio_aio_write( } trace_xfs_file_direct_write(ip, count, iocb->ki_pos, 0); - ret = generic_file_direct_write(iocb, iovp, - &nr_segs, pos, count, ocount); + ret = generic_file_direct_write(iocb, from, pos); out: xfs_rw_iunlock(ip, iolock); @@ -712,10 +662,7 @@ xfs_file_dio_aio_write( STATIC ssize_t xfs_file_buffered_aio_write( struct kiocb *iocb, - const struct iovec *iovp, - unsigned long nr_segs, - loff_t pos, - size_t count) + struct iov_iter *from) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -724,7 +671,8 @@ xfs_file_buffered_aio_write( ssize_t ret; int enospc = 0; int iolock = XFS_IOLOCK_EXCL; - struct iov_iter from; + loff_t pos = iocb->ki_pos; + size_t count = iov_iter_count(from); xfs_rw_ilock(ip, iolock); @@ -732,13 +680,13 @@ xfs_file_buffered_aio_write( if (ret) goto out; - iov_iter_init(&from, iovp, nr_segs, count, 0); + iov_iter_truncate(from, count); /* We can write back this queue in page reclaim */ current->backing_dev_info = mapping->backing_dev_info; write_retry: trace_xfs_file_buffered_write(ip, count, iocb->ki_pos, 0); - ret = generic_perform_write(file, &from, pos); + ret = generic_perform_write(file, from, pos); if (likely(ret >= 0)) iocb->ki_pos = pos + ret; /* @@ -759,40 +707,29 @@ xfs_file_buffered_aio_write( } STATIC ssize_t -xfs_file_aio_write( +xfs_file_write_iter( struct kiocb *iocb, - const struct iovec *iovp, - unsigned long nr_segs, - loff_t pos) + struct iov_iter *from) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; struct xfs_inode *ip = XFS_I(inode); ssize_t ret; - size_t ocount = 0; + size_t ocount = iov_iter_count(from); XFS_STATS_INC(xs_write_calls); - BUG_ON(iocb->ki_pos != pos); - - ret = generic_segment_checks(iovp, &nr_segs, &ocount, VERIFY_READ); - if (ret) - return ret; - if (ocount == 0) return 0; - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { - ret = -EIO; - goto out; - } + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) + return -EIO; if (unlikely(file->f_flags & O_DIRECT)) - ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos, ocount); + ret = xfs_file_dio_aio_write(iocb, from); else - ret = xfs_file_buffered_aio_write(iocb, iovp, nr_segs, pos, - ocount); + ret = xfs_file_buffered_aio_write(iocb, from); if (ret > 0) { ssize_t err; @@ -804,8 +741,6 @@ xfs_file_aio_write( if (err < 0) ret = err; } - -out: return ret; } @@ -944,7 +879,7 @@ xfs_dir_open( */ mode = xfs_ilock_data_map_shared(ip); if (ip->i_d.di_nextents > 0) - xfs_dir3_data_readahead(NULL, ip, 0, -1); + xfs_dir3_data_readahead(ip, 0, -1); xfs_iunlock(ip, mode); return 0; } @@ -1461,12 +1396,12 @@ xfs_file_llseek( const struct file_operations xfs_file_operations = { .llseek = xfs_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = xfs_file_aio_read, - .aio_write = xfs_file_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = xfs_file_read_iter, + .write_iter = xfs_file_write_iter, .splice_read = xfs_file_splice_read, - .splice_write = xfs_file_splice_write, + .splice_write = iter_file_splice_write, .unlocked_ioctl = xfs_file_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = xfs_file_compat_ioctl, diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c index 12b6e770198537..8ec81bed799214 100644 --- a/fs/xfs/xfs_filestream.c +++ b/fs/xfs/xfs_filestream.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2007 Silicon Graphics, Inc. + * Copyright (c) 2014 Christoph Hellwig. * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -32,100 +33,20 @@ #include "xfs_filestream.h" #include "xfs_trace.h" -#ifdef XFS_FILESTREAMS_TRACE - -ktrace_t *xfs_filestreams_trace_buf; - -STATIC void -xfs_filestreams_trace( - xfs_mount_t *mp, /* mount point */ - int type, /* type of trace */ - const char *func, /* source function */ - int line, /* source line number */ - __psunsigned_t arg0, - __psunsigned_t arg1, - __psunsigned_t arg2, - __psunsigned_t arg3, - __psunsigned_t arg4, - __psunsigned_t arg5) -{ - ktrace_enter(xfs_filestreams_trace_buf, - (void *)(__psint_t)(type | (line << 16)), - (void *)func, - (void *)(__psunsigned_t)current_pid(), - (void *)mp, - (void *)(__psunsigned_t)arg0, - (void *)(__psunsigned_t)arg1, - (void *)(__psunsigned_t)arg2, - (void *)(__psunsigned_t)arg3, - (void *)(__psunsigned_t)arg4, - (void *)(__psunsigned_t)arg5, - NULL, NULL, NULL, NULL, NULL, NULL); -} - -#define TRACE0(mp,t) TRACE6(mp,t,0,0,0,0,0,0) -#define TRACE1(mp,t,a0) TRACE6(mp,t,a0,0,0,0,0,0) -#define TRACE2(mp,t,a0,a1) TRACE6(mp,t,a0,a1,0,0,0,0) -#define TRACE3(mp,t,a0,a1,a2) TRACE6(mp,t,a0,a1,a2,0,0,0) -#define TRACE4(mp,t,a0,a1,a2,a3) TRACE6(mp,t,a0,a1,a2,a3,0,0) -#define TRACE5(mp,t,a0,a1,a2,a3,a4) TRACE6(mp,t,a0,a1,a2,a3,a4,0) -#define TRACE6(mp,t,a0,a1,a2,a3,a4,a5) \ - xfs_filestreams_trace(mp, t, __func__, __LINE__, \ - (__psunsigned_t)a0, (__psunsigned_t)a1, \ - (__psunsigned_t)a2, (__psunsigned_t)a3, \ - (__psunsigned_t)a4, (__psunsigned_t)a5) - -#define TRACE_AG_SCAN(mp, ag, ag2) \ - TRACE2(mp, XFS_FSTRM_KTRACE_AGSCAN, ag, ag2); -#define TRACE_AG_PICK1(mp, max_ag, maxfree) \ - TRACE2(mp, XFS_FSTRM_KTRACE_AGPICK1, max_ag, maxfree); -#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag) \ - TRACE6(mp, XFS_FSTRM_KTRACE_AGPICK2, ag, ag2, \ - cnt, free, scan, flag) -#define TRACE_UPDATE(mp, ip, ag, cnt, ag2, cnt2) \ - TRACE5(mp, XFS_FSTRM_KTRACE_UPDATE, ip, ag, cnt, ag2, cnt2) -#define TRACE_FREE(mp, ip, pip, ag, cnt) \ - TRACE4(mp, XFS_FSTRM_KTRACE_FREE, ip, pip, ag, cnt) -#define TRACE_LOOKUP(mp, ip, pip, ag, cnt) \ - TRACE4(mp, XFS_FSTRM_KTRACE_ITEM_LOOKUP, ip, pip, ag, cnt) -#define TRACE_ASSOCIATE(mp, ip, pip, ag, cnt) \ - TRACE4(mp, XFS_FSTRM_KTRACE_ASSOCIATE, ip, pip, ag, cnt) -#define TRACE_MOVEAG(mp, ip, pip, oag, ocnt, nag, ncnt) \ - TRACE6(mp, XFS_FSTRM_KTRACE_MOVEAG, ip, pip, oag, ocnt, nag, ncnt) -#define TRACE_ORPHAN(mp, ip, ag) \ - TRACE2(mp, XFS_FSTRM_KTRACE_ORPHAN, ip, ag); - - -#else -#define TRACE_AG_SCAN(mp, ag, ag2) -#define TRACE_AG_PICK1(mp, max_ag, maxfree) -#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag) -#define TRACE_UPDATE(mp, ip, ag, cnt, ag2, cnt2) -#define TRACE_FREE(mp, ip, pip, ag, cnt) -#define TRACE_LOOKUP(mp, ip, pip, ag, cnt) -#define TRACE_ASSOCIATE(mp, ip, pip, ag, cnt) -#define TRACE_MOVEAG(mp, ip, pip, oag, ocnt, nag, ncnt) -#define TRACE_ORPHAN(mp, ip, ag) -#endif - -static kmem_zone_t *item_zone; +struct xfs_fstrm_item { + struct xfs_mru_cache_elem mru; + struct xfs_inode *ip; + xfs_agnumber_t ag; /* AG in use for this directory */ +}; -/* - * Structure for associating a file or a directory with an allocation group. - * The parent directory pointer is only needed for files, but since there will - * generally be vastly more files than directories in the cache, using the same - * data structure simplifies the code with very little memory overhead. - */ -typedef struct fstrm_item -{ - xfs_agnumber_t ag; /* AG currently in use for the file/directory. */ - xfs_inode_t *ip; /* inode self-pointer. */ - xfs_inode_t *pip; /* Parent directory inode pointer. */ -} fstrm_item_t; +enum xfs_fstrm_alloc { + XFS_PICK_USERDATA = 1, + XFS_PICK_LOWSPACE = 2, +}; /* * Allocation group filestream associations are tracked with per-ag atomic - * counters. These counters allow _xfs_filestream_pick_ag() to tell whether a + * counters. These counters allow xfs_filestream_pick_ag() to tell whether a * particular AG already has active filestreams associated with it. The mount * point's m_peraglock is used to protect these counters from per-ag array * re-allocation during a growfs operation. When xfs_growfs_data_private() is @@ -160,7 +81,7 @@ typedef struct fstrm_item * the cache that reference per-ag array elements that have since been * reallocated. */ -static int +int xfs_filestream_peek_ag( xfs_mount_t *mp, xfs_agnumber_t agno) @@ -200,23 +121,40 @@ xfs_filestream_put_ag( xfs_perag_put(pag); } +static void +xfs_fstrm_free_func( + struct xfs_mru_cache_elem *mru) +{ + struct xfs_fstrm_item *item = + container_of(mru, struct xfs_fstrm_item, mru); + + xfs_filestream_put_ag(item->ip->i_mount, item->ag); + + trace_xfs_filestream_free(item->ip, item->ag); + + kmem_free(item); +} + /* * Scan the AGs starting at startag looking for an AG that isn't in use and has * at least minlen blocks free. */ static int -_xfs_filestream_pick_ag( - xfs_mount_t *mp, - xfs_agnumber_t startag, - xfs_agnumber_t *agp, - int flags, - xfs_extlen_t minlen) +xfs_filestream_pick_ag( + struct xfs_inode *ip, + xfs_agnumber_t startag, + xfs_agnumber_t *agp, + int flags, + xfs_extlen_t minlen) { - int streams, max_streams; - int err, trylock, nscan; - xfs_extlen_t longest, free, minfree, maxfree = 0; - xfs_agnumber_t ag, max_ag = NULLAGNUMBER; - struct xfs_perag *pag; + struct xfs_mount *mp = ip->i_mount; + struct xfs_fstrm_item *item; + struct xfs_perag *pag; + xfs_extlen_t longest, free = 0, minfree, maxfree = 0; + xfs_agnumber_t ag, max_ag = NULLAGNUMBER; + int err, trylock, nscan; + + ASSERT(S_ISDIR(ip->i_d.di_mode)); /* 2% of an AG's blocks must be free for it to be chosen. */ minfree = mp->m_sb.sb_agblocks / 50; @@ -228,8 +166,9 @@ _xfs_filestream_pick_ag( trylock = XFS_ALLOC_FLAG_TRYLOCK; for (nscan = 0; 1; nscan++) { + trace_xfs_filestream_scan(ip, ag); + pag = xfs_perag_get(mp, ag); - TRACE_AG_SCAN(mp, ag, atomic_read(&pag->pagf_fstrms)); if (!pag->pagf_init) { err = xfs_alloc_pagf_init(mp, NULL, ag, trylock); @@ -246,7 +185,6 @@ _xfs_filestream_pick_ag( /* Keep track of the AG with the most free blocks. */ if (pag->pagf_freeblks > maxfree) { maxfree = pag->pagf_freeblks; - max_streams = atomic_read(&pag->pagf_fstrms); max_ag = ag; } @@ -269,7 +207,6 @@ _xfs_filestream_pick_ag( /* Break out, retaining the reference on the AG. */ free = pag->pagf_freeblks; - streams = atomic_read(&pag->pagf_fstrms); xfs_perag_put(pag); *agp = ag; break; @@ -305,317 +242,98 @@ _xfs_filestream_pick_ag( */ if (max_ag != NULLAGNUMBER) { xfs_filestream_get_ag(mp, max_ag); - TRACE_AG_PICK1(mp, max_ag, maxfree); - streams = max_streams; free = maxfree; *agp = max_ag; break; } /* take AG 0 if none matched */ - TRACE_AG_PICK1(mp, max_ag, maxfree); + trace_xfs_filestream_pick(ip, *agp, free, nscan); *agp = 0; return 0; } - TRACE_AG_PICK2(mp, startag, *agp, streams, free, nscan, flags); - - return 0; -} + trace_xfs_filestream_pick(ip, *agp, free, nscan); -/* - * Set the allocation group number for a file or a directory, updating inode - * references and per-AG references as appropriate. - */ -static int -_xfs_filestream_update_ag( - xfs_inode_t *ip, - xfs_inode_t *pip, - xfs_agnumber_t ag) -{ - int err = 0; - xfs_mount_t *mp; - xfs_mru_cache_t *cache; - fstrm_item_t *item; - xfs_agnumber_t old_ag; - xfs_inode_t *old_pip; - - /* - * Either ip is a regular file and pip is a directory, or ip is a - * directory and pip is NULL. - */ - ASSERT(ip && ((S_ISREG(ip->i_d.di_mode) && pip && - S_ISDIR(pip->i_d.di_mode)) || - (S_ISDIR(ip->i_d.di_mode) && !pip))); - - mp = ip->i_mount; - cache = mp->m_filestream; - - item = xfs_mru_cache_lookup(cache, ip->i_ino); - if (item) { - ASSERT(item->ip == ip); - old_ag = item->ag; - item->ag = ag; - old_pip = item->pip; - item->pip = pip; - xfs_mru_cache_done(cache); - - /* - * If the AG has changed, drop the old ref and take a new one, - * effectively transferring the reference from old to new AG. - */ - if (ag != old_ag) { - xfs_filestream_put_ag(mp, old_ag); - xfs_filestream_get_ag(mp, ag); - } - - /* - * If ip is a file and its pip has changed, drop the old ref and - * take a new one. - */ - if (pip && pip != old_pip) { - IRELE(old_pip); - IHOLD(pip); - } - - TRACE_UPDATE(mp, ip, old_ag, xfs_filestream_peek_ag(mp, old_ag), - ag, xfs_filestream_peek_ag(mp, ag)); + if (*agp == NULLAGNUMBER) return 0; - } - item = kmem_zone_zalloc(item_zone, KM_MAYFAIL); + err = ENOMEM; + item = kmem_alloc(sizeof(*item), KM_MAYFAIL); if (!item) - return ENOMEM; + goto out_put_ag; - item->ag = ag; + item->ag = *agp; item->ip = ip; - item->pip = pip; - err = xfs_mru_cache_insert(cache, ip->i_ino, item); + err = xfs_mru_cache_insert(mp->m_filestream, ip->i_ino, &item->mru); if (err) { - kmem_zone_free(item_zone, item); - return err; + if (err == EEXIST) + err = 0; + goto out_free_item; } - /* Take a reference on the AG. */ - xfs_filestream_get_ag(mp, ag); - - /* - * Take a reference on the inode itself regardless of whether it's a - * regular file or a directory. - */ - IHOLD(ip); - - /* - * In the case of a regular file, take a reference on the parent inode - * as well to ensure it remains in-core. - */ - if (pip) - IHOLD(pip); - - TRACE_UPDATE(mp, ip, ag, xfs_filestream_peek_ag(mp, ag), - ag, xfs_filestream_peek_ag(mp, ag)); - return 0; -} - -/* xfs_fstrm_free_func(): callback for freeing cached stream items. */ -STATIC void -xfs_fstrm_free_func( - unsigned long ino, - void *data) -{ - fstrm_item_t *item = (fstrm_item_t *)data; - xfs_inode_t *ip = item->ip; - - ASSERT(ip->i_ino == ino); - - xfs_iflags_clear(ip, XFS_IFILESTREAM); - - /* Drop the reference taken on the AG when the item was added. */ - xfs_filestream_put_ag(ip->i_mount, item->ag); - - TRACE_FREE(ip->i_mount, ip, item->pip, item->ag, - xfs_filestream_peek_ag(ip->i_mount, item->ag)); - - /* - * _xfs_filestream_update_ag() always takes a reference on the inode - * itself, whether it's a file or a directory. Release it here. - * This can result in the inode being freed and so we must - * not hold any inode locks when freeing filesstreams objects - * otherwise we can deadlock here. - */ - IRELE(ip); - - /* - * In the case of a regular file, _xfs_filestream_update_ag() also - * takes a ref on the parent inode to keep it in-core. Release that - * too. - */ - if (item->pip) - IRELE(item->pip); - - /* Finally, free the memory allocated for the item. */ - kmem_zone_free(item_zone, item); -} - -/* - * xfs_filestream_init() is called at xfs initialisation time to set up the - * memory zone that will be used for filestream data structure allocation. - */ -int -xfs_filestream_init(void) -{ - item_zone = kmem_zone_init(sizeof(fstrm_item_t), "fstrm_item"); - if (!item_zone) - return -ENOMEM; - - return 0; -} - -/* - * xfs_filestream_uninit() is called at xfs termination time to destroy the - * memory zone that was used for filestream data structure allocation. - */ -void -xfs_filestream_uninit(void) -{ - kmem_zone_destroy(item_zone); -} - -/* - * xfs_filestream_mount() is called when a file system is mounted with the - * filestream option. It is responsible for allocating the data structures - * needed to track the new file system's file streams. - */ -int -xfs_filestream_mount( - xfs_mount_t *mp) -{ - int err; - unsigned int lifetime, grp_count; - - /* - * The filestream timer tunable is currently fixed within the range of - * one second to four minutes, with five seconds being the default. The - * group count is somewhat arbitrary, but it'd be nice to adhere to the - * timer tunable to within about 10 percent. This requires at least 10 - * groups. - */ - lifetime = xfs_fstrm_centisecs * 10; - grp_count = 10; - - err = xfs_mru_cache_create(&mp->m_filestream, lifetime, grp_count, - xfs_fstrm_free_func); +out_free_item: + kmem_free(item); +out_put_ag: + xfs_filestream_put_ag(mp, *agp); return err; } -/* - * xfs_filestream_unmount() is called when a file system that was mounted with - * the filestream option is unmounted. It drains the data structures created - * to track the file system's file streams and frees all the memory that was - * allocated. - */ -void -xfs_filestream_unmount( - xfs_mount_t *mp) +static struct xfs_inode * +xfs_filestream_get_parent( + struct xfs_inode *ip) { - xfs_mru_cache_destroy(mp->m_filestream); -} + struct inode *inode = VFS_I(ip), *dir = NULL; + struct dentry *dentry, *parent; -/* - * Return the AG of the filestream the file or directory belongs to, or - * NULLAGNUMBER otherwise. - */ -xfs_agnumber_t -xfs_filestream_lookup_ag( - xfs_inode_t *ip) -{ - xfs_mru_cache_t *cache; - fstrm_item_t *item; - xfs_agnumber_t ag; - int ref; - - if (!S_ISREG(ip->i_d.di_mode) && !S_ISDIR(ip->i_d.di_mode)) { - ASSERT(0); - return NULLAGNUMBER; - } + dentry = d_find_alias(inode); + if (!dentry) + goto out; - cache = ip->i_mount->m_filestream; - item = xfs_mru_cache_lookup(cache, ip->i_ino); - if (!item) { - TRACE_LOOKUP(ip->i_mount, ip, NULL, NULLAGNUMBER, 0); - return NULLAGNUMBER; - } + parent = dget_parent(dentry); + if (!parent) + goto out_dput; - ASSERT(ip == item->ip); - ag = item->ag; - ref = xfs_filestream_peek_ag(ip->i_mount, ag); - xfs_mru_cache_done(cache); + dir = igrab(parent->d_inode); + dput(parent); - TRACE_LOOKUP(ip->i_mount, ip, item->pip, ag, ref); - return ag; +out_dput: + dput(dentry); +out: + return dir ? XFS_I(dir) : NULL; } /* - * xfs_filestream_associate() should only be called to associate a regular file - * with its parent directory. Calling it with a child directory isn't - * appropriate because filestreams don't apply to entire directory hierarchies. - * Creating a file in a child directory of an existing filestream directory - * starts a new filestream with its own allocation group association. + * Find the right allocation group for a file, either by finding an + * existing file stream or creating a new one. * - * Returns < 0 on error, 0 if successful association occurred, > 0 if - * we failed to get an association because of locking issues. + * Returns NULLAGNUMBER in case of an error. */ -int -xfs_filestream_associate( - xfs_inode_t *pip, - xfs_inode_t *ip) +xfs_agnumber_t +xfs_filestream_lookup_ag( + struct xfs_inode *ip) { - xfs_mount_t *mp; - xfs_mru_cache_t *cache; - fstrm_item_t *item; - xfs_agnumber_t ag, rotorstep, startag; - int err = 0; + struct xfs_mount *mp = ip->i_mount; + struct xfs_inode *pip = NULL; + xfs_agnumber_t startag, ag = NULLAGNUMBER; + struct xfs_mru_cache_elem *mru; - ASSERT(S_ISDIR(pip->i_d.di_mode)); ASSERT(S_ISREG(ip->i_d.di_mode)); - if (!S_ISDIR(pip->i_d.di_mode) || !S_ISREG(ip->i_d.di_mode)) - return -EINVAL; - mp = pip->i_mount; - cache = mp->m_filestream; + pip = xfs_filestream_get_parent(ip); + if (!pip) + goto out; - /* - * We have a problem, Houston. - * - * Taking the iolock here violates inode locking order - we already - * hold the ilock. Hence if we block getting this lock we may never - * wake. Unfortunately, that means if we can't get the lock, we're - * screwed in terms of getting a stream association - we can't spin - * waiting for the lock because someone else is waiting on the lock we - * hold and we cannot drop that as we are in a transaction here. - * - * Lucky for us, this inversion is not a problem because it's a - * directory inode that we are trying to lock here. - * - * So, if we can't get the iolock without sleeping then just give up - */ - if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL)) - return 1; - - /* If the parent directory is already in the cache, use its AG. */ - item = xfs_mru_cache_lookup(cache, pip->i_ino); - if (item) { - ASSERT(item->ip == pip); - ag = item->ag; - xfs_mru_cache_done(cache); - - TRACE_LOOKUP(mp, pip, pip, ag, xfs_filestream_peek_ag(mp, ag)); - err = _xfs_filestream_update_ag(ip, pip, ag); + mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino); + if (mru) { + ag = container_of(mru, struct xfs_fstrm_item, mru)->ag; + xfs_mru_cache_done(mp->m_filestream); - goto exit; + trace_xfs_filestream_lookup(ip, ag); + goto out; } /* @@ -623,202 +341,94 @@ xfs_filestream_associate( * use the directory inode's AG. */ if (mp->m_flags & XFS_MOUNT_32BITINODES) { - rotorstep = xfs_rotorstep; + xfs_agnumber_t rotorstep = xfs_rotorstep; startag = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount; mp->m_agfrotor = (mp->m_agfrotor + 1) % (mp->m_sb.sb_agcount * rotorstep); } else startag = XFS_INO_TO_AGNO(mp, pip->i_ino); - /* Pick a new AG for the parent inode starting at startag. */ - err = _xfs_filestream_pick_ag(mp, startag, &ag, 0, 0); - if (err || ag == NULLAGNUMBER) - goto exit_did_pick; - - /* Associate the parent inode with the AG. */ - err = _xfs_filestream_update_ag(pip, NULL, ag); - if (err) - goto exit_did_pick; - - /* Associate the file inode with the AG. */ - err = _xfs_filestream_update_ag(ip, pip, ag); - if (err) - goto exit_did_pick; - - TRACE_ASSOCIATE(mp, ip, pip, ag, xfs_filestream_peek_ag(mp, ag)); - -exit_did_pick: - /* - * If _xfs_filestream_pick_ag() returned a valid AG, remove the - * reference it took on it, since the file and directory will have taken - * their own now if they were successfully cached. - */ - if (ag != NULLAGNUMBER) - xfs_filestream_put_ag(mp, ag); - -exit: - xfs_iunlock(pip, XFS_IOLOCK_EXCL); - return -err; + if (xfs_filestream_pick_ag(pip, startag, &ag, 0, 0)) + ag = NULLAGNUMBER; +out: + IRELE(pip); + return ag; } /* - * Pick a new allocation group for the current file and its file stream. This - * function is called by xfs_bmap_filestreams() with the mount point's per-ag - * lock held. + * Pick a new allocation group for the current file and its file stream. + * + * This is called when the allocator can't find a suitable extent in the + * current AG, and we have to move the stream into a new AG with more space. */ int xfs_filestream_new_ag( struct xfs_bmalloca *ap, xfs_agnumber_t *agp) { - int flags, err; - xfs_inode_t *ip, *pip = NULL; - xfs_mount_t *mp; - xfs_mru_cache_t *cache; - xfs_extlen_t minlen; - fstrm_item_t *dir, *file; - xfs_agnumber_t ag = NULLAGNUMBER; - - ip = ap->ip; - mp = ip->i_mount; - cache = mp->m_filestream; - minlen = ap->length; - *agp = NULLAGNUMBER; + struct xfs_inode *ip = ap->ip, *pip; + struct xfs_mount *mp = ip->i_mount; + xfs_extlen_t minlen = ap->length; + xfs_agnumber_t startag = 0; + int flags, err = 0; + struct xfs_mru_cache_elem *mru; - /* - * Look for the file in the cache, removing it if it's found. Doing - * this allows it to be held across the dir lookup that follows. - */ - file = xfs_mru_cache_remove(cache, ip->i_ino); - if (file) { - ASSERT(ip == file->ip); - - /* Save the file's parent inode and old AG number for later. */ - pip = file->pip; - ag = file->ag; - - /* Look for the file's directory in the cache. */ - dir = xfs_mru_cache_lookup(cache, pip->i_ino); - if (dir) { - ASSERT(pip == dir->ip); - - /* - * If the directory has already moved on to a new AG, - * use that AG as the new AG for the file. Don't - * forget to twiddle the AG refcounts to match the - * movement. - */ - if (dir->ag != file->ag) { - xfs_filestream_put_ag(mp, file->ag); - xfs_filestream_get_ag(mp, dir->ag); - *agp = file->ag = dir->ag; - } - - xfs_mru_cache_done(cache); - } + *agp = NULLAGNUMBER; - /* - * Put the file back in the cache. If this fails, the free - * function needs to be called to tidy up in the same way as if - * the item had simply expired from the cache. - */ - err = xfs_mru_cache_insert(cache, ip->i_ino, file); - if (err) { - xfs_fstrm_free_func(ip->i_ino, file); - return err; - } + pip = xfs_filestream_get_parent(ip); + if (!pip) + goto exit; - /* - * If the file's AG was moved to the directory's new AG, there's - * nothing more to be done. - */ - if (*agp != NULLAGNUMBER) { - TRACE_MOVEAG(mp, ip, pip, - ag, xfs_filestream_peek_ag(mp, ag), - *agp, xfs_filestream_peek_ag(mp, *agp)); - return 0; - } + mru = xfs_mru_cache_remove(mp->m_filestream, pip->i_ino); + if (mru) { + struct xfs_fstrm_item *item = + container_of(mru, struct xfs_fstrm_item, mru); + startag = (item->ag + 1) % mp->m_sb.sb_agcount; } - /* - * If the file's parent directory is known, take its iolock in exclusive - * mode to prevent two sibling files from racing each other to migrate - * themselves and their parent to different AGs. - * - * Note that we lock the parent directory iolock inside the child - * iolock here. That's fine as we never hold both parent and child - * iolock in any other place. This is different from the ilock, - * which requires locking of the child after the parent for namespace - * operations. - */ - if (pip) - xfs_ilock(pip, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT); - - /* - * A new AG needs to be found for the file. If the file's parent - * directory is also known, it will be moved to the new AG as well to - * ensure that files created inside it in future use the new AG. - */ - ag = (ag == NULLAGNUMBER) ? 0 : (ag + 1) % mp->m_sb.sb_agcount; flags = (ap->userdata ? XFS_PICK_USERDATA : 0) | (ap->flist->xbf_low ? XFS_PICK_LOWSPACE : 0); - err = _xfs_filestream_pick_ag(mp, ag, agp, flags, minlen); - if (err || *agp == NULLAGNUMBER) - goto exit; + err = xfs_filestream_pick_ag(pip, startag, agp, flags, minlen); /* - * If the file wasn't found in the file cache, then its parent directory - * inode isn't known. For this to have happened, the file must either - * be pre-existing, or it was created long enough ago that its cache - * entry has expired. This isn't the sort of usage that the filestreams - * allocator is trying to optimise, so there's no point trying to track - * its new AG somehow in the filestream data structures. + * Only free the item here so we skip over the old AG earlier. */ - if (!pip) { - TRACE_ORPHAN(mp, ip, *agp); - goto exit; - } - - /* Associate the parent inode with the AG. */ - err = _xfs_filestream_update_ag(pip, NULL, *agp); - if (err) - goto exit; - - /* Associate the file inode with the AG. */ - err = _xfs_filestream_update_ag(ip, pip, *agp); - if (err) - goto exit; - - TRACE_MOVEAG(mp, ip, pip, NULLAGNUMBER, 0, - *agp, xfs_filestream_peek_ag(mp, *agp)); + if (mru) + xfs_fstrm_free_func(mru); + IRELE(pip); exit: - /* - * If _xfs_filestream_pick_ag() returned a valid AG, remove the - * reference it took on it, since the file and directory will have taken - * their own now if they were successfully cached. - */ - if (*agp != NULLAGNUMBER) - xfs_filestream_put_ag(mp, *agp); - else + if (*agp == NULLAGNUMBER) *agp = 0; - - if (pip) - xfs_iunlock(pip, XFS_IOLOCK_EXCL); - return err; } -/* - * Remove an association between an inode and a filestream object. - * Typically this is done on last close of an unlinked file. - */ void xfs_filestream_deassociate( - xfs_inode_t *ip) + struct xfs_inode *ip) { - xfs_mru_cache_t *cache = ip->i_mount->m_filestream; + xfs_mru_cache_delete(ip->i_mount->m_filestream, ip->i_ino); +} + +int +xfs_filestream_mount( + xfs_mount_t *mp) +{ + /* + * The filestream timer tunable is currently fixed within the range of + * one second to four minutes, with five seconds being the default. The + * group count is somewhat arbitrary, but it'd be nice to adhere to the + * timer tunable to within about 10 percent. This requires at least 10 + * groups. + */ + return xfs_mru_cache_create(&mp->m_filestream, xfs_fstrm_centisecs * 10, + 10, xfs_fstrm_free_func); +} - xfs_mru_cache_delete(cache, ip->i_ino); +void +xfs_filestream_unmount( + xfs_mount_t *mp) +{ + xfs_mru_cache_destroy(mp->m_filestream); } diff --git a/fs/xfs/xfs_filestream.h b/fs/xfs/xfs_filestream.h index 6d61dbee8564b1..2ef43406e53bd9 100644 --- a/fs/xfs/xfs_filestream.h +++ b/fs/xfs/xfs_filestream.h @@ -20,50 +20,20 @@ struct xfs_mount; struct xfs_inode; -struct xfs_perag; struct xfs_bmalloca; -#ifdef XFS_FILESTREAMS_TRACE -#define XFS_FSTRM_KTRACE_INFO 1 -#define XFS_FSTRM_KTRACE_AGSCAN 2 -#define XFS_FSTRM_KTRACE_AGPICK1 3 -#define XFS_FSTRM_KTRACE_AGPICK2 4 -#define XFS_FSTRM_KTRACE_UPDATE 5 -#define XFS_FSTRM_KTRACE_FREE 6 -#define XFS_FSTRM_KTRACE_ITEM_LOOKUP 7 -#define XFS_FSTRM_KTRACE_ASSOCIATE 8 -#define XFS_FSTRM_KTRACE_MOVEAG 9 -#define XFS_FSTRM_KTRACE_ORPHAN 10 - -#define XFS_FSTRM_KTRACE_SIZE 16384 -extern ktrace_t *xfs_filestreams_trace_buf; - -#endif - -/* allocation selection flags */ -typedef enum xfs_fstrm_alloc { - XFS_PICK_USERDATA = 1, - XFS_PICK_LOWSPACE = 2, -} xfs_fstrm_alloc_t; - -/* prototypes for filestream.c */ -int xfs_filestream_init(void); -void xfs_filestream_uninit(void); int xfs_filestream_mount(struct xfs_mount *mp); void xfs_filestream_unmount(struct xfs_mount *mp); -xfs_agnumber_t xfs_filestream_lookup_ag(struct xfs_inode *ip); -int xfs_filestream_associate(struct xfs_inode *dip, struct xfs_inode *ip); void xfs_filestream_deassociate(struct xfs_inode *ip); +xfs_agnumber_t xfs_filestream_lookup_ag(struct xfs_inode *ip); int xfs_filestream_new_ag(struct xfs_bmalloca *ap, xfs_agnumber_t *agp); +int xfs_filestream_peek_ag(struct xfs_mount *mp, xfs_agnumber_t agno); - -/* filestreams for the inode? */ static inline int xfs_inode_is_filestream( struct xfs_inode *ip) { return (ip->i_mount->m_flags & XFS_MOUNT_FILESTREAMS) || - xfs_iflags_test(ip, XFS_IFILESTREAM) || (ip->i_d.di_flags & XFS_DIFLAG_FILESTREAM); } diff --git a/fs/xfs/xfs_format.h b/fs/xfs/xfs_format.h index 9898f31d05d8c2..34d85aca305801 100644 --- a/fs/xfs/xfs_format.h +++ b/fs/xfs/xfs_format.h @@ -202,6 +202,8 @@ typedef __be32 xfs_alloc_ptr_t; */ #define XFS_IBT_MAGIC 0x49414254 /* 'IABT' */ #define XFS_IBT_CRC_MAGIC 0x49414233 /* 'IAB3' */ +#define XFS_FIBT_MAGIC 0x46494254 /* 'FIBT' */ +#define XFS_FIBT_CRC_MAGIC 0x46494233 /* 'FIB3' */ typedef __uint64_t xfs_inofree_t; #define XFS_INODES_PER_CHUNK (NBBY * sizeof(xfs_inofree_t)) @@ -244,7 +246,17 @@ typedef __be32 xfs_inobt_ptr_t; * block numbers in the AG. */ #define XFS_IBT_BLOCK(mp) ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1)) -#define XFS_PREALLOC_BLOCKS(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1)) +#define XFS_FIBT_BLOCK(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1)) + +/* + * The first data block of an AG depends on whether the filesystem was formatted + * with the finobt feature. If so, account for the finobt reserved root btree + * block. + */ +#define XFS_PREALLOC_BLOCKS(mp) \ + (xfs_sb_version_hasfinobt(&((mp)->m_sb)) ? \ + XFS_FIBT_BLOCK(mp) + 1 : \ + XFS_IBT_BLOCK(mp) + 1) diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index c5fc116dfaa307..d34703dbcb423b 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h @@ -238,6 +238,7 @@ typedef struct xfs_fsop_resblks { #define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */ #define XFS_FSOP_GEOM_FLAGS_V5SB 0x8000 /* version 5 superblock */ #define XFS_FSOP_GEOM_FLAGS_FTYPE 0x10000 /* inode directory types */ +#define XFS_FSOP_GEOM_FLAGS_FINOBT 0x20000 /* free inode btree */ /* * Minimum and maximum sizes need for growth checks. diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 02fb943cbf22b3..3445ead7c1fcfb 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -104,7 +104,9 @@ xfs_fs_geometry( (xfs_sb_version_hascrc(&mp->m_sb) ? XFS_FSOP_GEOM_FLAGS_V5SB : 0) | (xfs_sb_version_hasftype(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_FTYPE : 0); + XFS_FSOP_GEOM_FLAGS_FTYPE : 0) | + (xfs_sb_version_hasfinobt(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_FINOBT : 0); geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ? mp->m_sb.sb_logsectsize : BBSIZE; geo->rtsectsize = mp->m_sb.sb_blocksize; @@ -316,6 +318,10 @@ xfs_growfs_data_private( agi->agi_dirino = cpu_to_be32(NULLAGINO); if (xfs_sb_version_hascrc(&mp->m_sb)) uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid); + if (xfs_sb_version_hasfinobt(&mp->m_sb)) { + agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp)); + agi->agi_free_level = cpu_to_be32(1); + } for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO); @@ -407,6 +413,34 @@ xfs_growfs_data_private( xfs_buf_relse(bp); if (error) goto error0; + + /* + * FINO btree root block + */ + if (xfs_sb_version_hasfinobt(&mp->m_sb)) { + bp = xfs_growfs_get_hdr_buf(mp, + XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)), + BTOBB(mp->m_sb.sb_blocksize), 0, + &xfs_inobt_buf_ops); + if (!bp) { + error = ENOMEM; + goto error0; + } + + if (xfs_sb_version_hascrc(&mp->m_sb)) + xfs_btree_init_block(mp, bp, XFS_FIBT_CRC_MAGIC, + 0, 0, agno, + XFS_BTREE_CRC_BLOCKS); + else + xfs_btree_init_block(mp, bp, XFS_FIBT_MAGIC, 0, + 0, agno, 0); + + error = xfs_bwrite(bp); + xfs_buf_relse(bp); + if (error) + goto error0; + } + } xfs_trans_agblocks_delta(tp, nfree); /* diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 8f711db61a0c21..6ac0c2986c32ef 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -111,6 +111,66 @@ xfs_inobt_get_rec( return error; } +/* + * Insert a single inobt record. Cursor must already point to desired location. + */ +STATIC int +xfs_inobt_insert_rec( + struct xfs_btree_cur *cur, + __int32_t freecount, + xfs_inofree_t free, + int *stat) +{ + cur->bc_rec.i.ir_freecount = freecount; + cur->bc_rec.i.ir_free = free; + return xfs_btree_insert(cur, stat); +} + +/* + * Insert records describing a newly allocated inode chunk into the inobt. + */ +STATIC int +xfs_inobt_insert( + struct xfs_mount *mp, + struct xfs_trans *tp, + struct xfs_buf *agbp, + xfs_agino_t newino, + xfs_agino_t newlen, + xfs_btnum_t btnum) +{ + struct xfs_btree_cur *cur; + struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); + xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); + xfs_agino_t thisino; + int i; + int error; + + cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum); + + for (thisino = newino; + thisino < newino + newlen; + thisino += XFS_INODES_PER_CHUNK) { + error = xfs_inobt_lookup(cur, thisino, XFS_LOOKUP_EQ, &i); + if (error) { + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; + } + ASSERT(i == 0); + + error = xfs_inobt_insert_rec(cur, XFS_INODES_PER_CHUNK, + XFS_INOBT_ALL_FREE, &i); + if (error) { + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; + } + ASSERT(i == 1); + } + + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + + return 0; +} + /* * Verify that the number of free inodes in the AGI is correct. */ @@ -303,13 +363,10 @@ xfs_ialloc_ag_alloc( { xfs_agi_t *agi; /* allocation group header */ xfs_alloc_arg_t args; /* allocation argument structure */ - xfs_btree_cur_t *cur; /* inode btree cursor */ xfs_agnumber_t agno; int error; - int i; xfs_agino_t newino; /* new first inode's number */ xfs_agino_t newlen; /* new number of inodes */ - xfs_agino_t thisino; /* current inode number, for loop */ int isaligned = 0; /* inode allocation at stripe unit */ /* boundary */ struct xfs_perag *pag; @@ -459,29 +516,19 @@ xfs_ialloc_ag_alloc( agi->agi_newino = cpu_to_be32(newino); /* - * Insert records describing the new inode chunk into the btree. + * Insert records describing the new inode chunk into the btrees. */ - cur = xfs_inobt_init_cursor(args.mp, tp, agbp, agno); - for (thisino = newino; - thisino < newino + newlen; - thisino += XFS_INODES_PER_CHUNK) { - cur->bc_rec.i.ir_startino = thisino; - cur->bc_rec.i.ir_freecount = XFS_INODES_PER_CHUNK; - cur->bc_rec.i.ir_free = XFS_INOBT_ALL_FREE; - error = xfs_btree_lookup(cur, XFS_LOOKUP_EQ, &i); - if (error) { - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - return error; - } - ASSERT(i == 0); - error = xfs_btree_insert(cur, &i); - if (error) { - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen, + XFS_BTNUM_INO); + if (error) + return error; + + if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) { + error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen, + XFS_BTNUM_FINO); + if (error) return error; - } - ASSERT(i == 1); } - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); /* * Log allocation group header fields */ @@ -675,13 +722,10 @@ xfs_ialloc_get_rec( } /* - * Allocate an inode. - * - * The caller selected an AG for us, and made sure that free inodes are - * available. + * Allocate an inode using the inobt-only algorithm. */ STATIC int -xfs_dialloc_ag( +xfs_dialloc_ag_inobt( struct xfs_trans *tp, struct xfs_buf *agbp, xfs_ino_t parent, @@ -707,7 +751,7 @@ xfs_dialloc_ag( ASSERT(pag->pagi_freecount > 0); restart_pagno: - cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); + cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); /* * If pagino is 0 (this is the root inode allocation) use newino. * This must work because we've just allocated some. @@ -939,6 +983,294 @@ xfs_dialloc_ag( return error; } +/* + * Use the free inode btree to allocate an inode based on distance from the + * parent. Note that the provided cursor may be deleted and replaced. + */ +STATIC int +xfs_dialloc_ag_finobt_near( + xfs_agino_t pagino, + struct xfs_btree_cur **ocur, + struct xfs_inobt_rec_incore *rec) +{ + struct xfs_btree_cur *lcur = *ocur; /* left search cursor */ + struct xfs_btree_cur *rcur; /* right search cursor */ + struct xfs_inobt_rec_incore rrec; + int error; + int i, j; + + error = xfs_inobt_lookup(lcur, pagino, XFS_LOOKUP_LE, &i); + if (error) + return error; + + if (i == 1) { + error = xfs_inobt_get_rec(lcur, rec, &i); + if (error) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + + /* + * See if we've landed in the parent inode record. The finobt + * only tracks chunks with at least one free inode, so record + * existence is enough. + */ + if (pagino >= rec->ir_startino && + pagino < (rec->ir_startino + XFS_INODES_PER_CHUNK)) + return 0; + } + + error = xfs_btree_dup_cursor(lcur, &rcur); + if (error) + return error; + + error = xfs_inobt_lookup(rcur, pagino, XFS_LOOKUP_GE, &j); + if (error) + goto error_rcur; + if (j == 1) { + error = xfs_inobt_get_rec(rcur, &rrec, &j); + if (error) + goto error_rcur; + XFS_WANT_CORRUPTED_GOTO(j == 1, error_rcur); + } + + XFS_WANT_CORRUPTED_GOTO(i == 1 || j == 1, error_rcur); + if (i == 1 && j == 1) { + /* + * Both the left and right records are valid. Choose the closer + * inode chunk to the target. + */ + if ((pagino - rec->ir_startino + XFS_INODES_PER_CHUNK - 1) > + (rrec.ir_startino - pagino)) { + *rec = rrec; + xfs_btree_del_cursor(lcur, XFS_BTREE_NOERROR); + *ocur = rcur; + } else { + xfs_btree_del_cursor(rcur, XFS_BTREE_NOERROR); + } + } else if (j == 1) { + /* only the right record is valid */ + *rec = rrec; + xfs_btree_del_cursor(lcur, XFS_BTREE_NOERROR); + *ocur = rcur; + } else if (i == 1) { + /* only the left record is valid */ + xfs_btree_del_cursor(rcur, XFS_BTREE_NOERROR); + } + + return 0; + +error_rcur: + xfs_btree_del_cursor(rcur, XFS_BTREE_ERROR); + return error; +} + +/* + * Use the free inode btree to find a free inode based on a newino hint. If + * the hint is NULL, find the first free inode in the AG. + */ +STATIC int +xfs_dialloc_ag_finobt_newino( + struct xfs_agi *agi, + struct xfs_btree_cur *cur, + struct xfs_inobt_rec_incore *rec) +{ + int error; + int i; + + if (agi->agi_newino != cpu_to_be32(NULLAGINO)) { + error = xfs_inobt_lookup(cur, agi->agi_newino, XFS_LOOKUP_EQ, + &i); + if (error) + return error; + if (i == 1) { + error = xfs_inobt_get_rec(cur, rec, &i); + if (error) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + + return 0; + } + } + + /* + * Find the first inode available in the AG. + */ + error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); + if (error) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + + error = xfs_inobt_get_rec(cur, rec, &i); + if (error) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + + return 0; +} + +/* + * Update the inobt based on a modification made to the finobt. Also ensure that + * the records from both trees are equivalent post-modification. + */ +STATIC int +xfs_dialloc_ag_update_inobt( + struct xfs_btree_cur *cur, /* inobt cursor */ + struct xfs_inobt_rec_incore *frec, /* finobt record */ + int offset) /* inode offset */ +{ + struct xfs_inobt_rec_incore rec; + int error; + int i; + + error = xfs_inobt_lookup(cur, frec->ir_startino, XFS_LOOKUP_EQ, &i); + if (error) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + + error = xfs_inobt_get_rec(cur, &rec, &i); + if (error) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + ASSERT((XFS_AGINO_TO_OFFSET(cur->bc_mp, rec.ir_startino) % + XFS_INODES_PER_CHUNK) == 0); + + rec.ir_free &= ~XFS_INOBT_MASK(offset); + rec.ir_freecount--; + + XFS_WANT_CORRUPTED_RETURN((rec.ir_free == frec->ir_free) && + (rec.ir_freecount == frec->ir_freecount)); + + error = xfs_inobt_update(cur, &rec); + if (error) + return error; + + return 0; +} + +/* + * Allocate an inode using the free inode btree, if available. Otherwise, fall + * back to the inobt search algorithm. + * + * The caller selected an AG for us, and made sure that free inodes are + * available. + */ +STATIC int +xfs_dialloc_ag( + struct xfs_trans *tp, + struct xfs_buf *agbp, + xfs_ino_t parent, + xfs_ino_t *inop) +{ + struct xfs_mount *mp = tp->t_mountp; + struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); + xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); + xfs_agnumber_t pagno = XFS_INO_TO_AGNO(mp, parent); + xfs_agino_t pagino = XFS_INO_TO_AGINO(mp, parent); + struct xfs_perag *pag; + struct xfs_btree_cur *cur; /* finobt cursor */ + struct xfs_btree_cur *icur; /* inobt cursor */ + struct xfs_inobt_rec_incore rec; + xfs_ino_t ino; + int error; + int offset; + int i; + + if (!xfs_sb_version_hasfinobt(&mp->m_sb)) + return xfs_dialloc_ag_inobt(tp, agbp, parent, inop); + + pag = xfs_perag_get(mp, agno); + + /* + * If pagino is 0 (this is the root inode allocation) use newino. + * This must work because we've just allocated some. + */ + if (!pagino) + pagino = be32_to_cpu(agi->agi_newino); + + cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO); + + error = xfs_check_agi_freecount(cur, agi); + if (error) + goto error_cur; + + /* + * The search algorithm depends on whether we're in the same AG as the + * parent. If so, find the closest available inode to the parent. If + * not, consider the agi hint or find the first free inode in the AG. + */ + if (agno == pagno) + error = xfs_dialloc_ag_finobt_near(pagino, &cur, &rec); + else + error = xfs_dialloc_ag_finobt_newino(agi, cur, &rec); + if (error) + goto error_cur; + + offset = xfs_lowbit64(rec.ir_free); + ASSERT(offset >= 0); + ASSERT(offset < XFS_INODES_PER_CHUNK); + ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) % + XFS_INODES_PER_CHUNK) == 0); + ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); + + /* + * Modify or remove the finobt record. + */ + rec.ir_free &= ~XFS_INOBT_MASK(offset); + rec.ir_freecount--; + if (rec.ir_freecount) + error = xfs_inobt_update(cur, &rec); + else + error = xfs_btree_delete(cur, &i); + if (error) + goto error_cur; + + /* + * The finobt has now been updated appropriately. We haven't updated the + * agi and superblock yet, so we can create an inobt cursor and validate + * the original freecount. If all is well, make the equivalent update to + * the inobt using the finobt record and offset information. + */ + icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); + + error = xfs_check_agi_freecount(icur, agi); + if (error) + goto error_icur; + + error = xfs_dialloc_ag_update_inobt(icur, &rec, offset); + if (error) + goto error_icur; + + /* + * Both trees have now been updated. We must update the perag and + * superblock before we can check the freecount for each btree. + */ + be32_add_cpu(&agi->agi_freecount, -1); + xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); + pag->pagi_freecount--; + + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); + + error = xfs_check_agi_freecount(icur, agi); + if (error) + goto error_icur; + error = xfs_check_agi_freecount(cur, agi); + if (error) + goto error_icur; + + xfs_btree_del_cursor(icur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + xfs_perag_put(pag); + *inop = ino; + return 0; + +error_icur: + xfs_btree_del_cursor(icur, XFS_BTREE_ERROR); +error_cur: + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + xfs_perag_put(pag); + return error; +} + /* * Allocate an inode on disk. * @@ -1098,78 +1430,34 @@ xfs_dialloc( return XFS_ERROR(error); } -/* - * Free disk inode. Carefully avoids touching the incore inode, all - * manipulations incore are the caller's responsibility. - * The on-disk inode is not changed by this operation, only the - * btree (free inode mask) is changed. - */ -int -xfs_difree( - xfs_trans_t *tp, /* transaction pointer */ - xfs_ino_t inode, /* inode to be freed */ - xfs_bmap_free_t *flist, /* extents to free */ - int *delete, /* set if inode cluster was deleted */ - xfs_ino_t *first_ino) /* first inode in deleted cluster */ +STATIC int +xfs_difree_inobt( + struct xfs_mount *mp, + struct xfs_trans *tp, + struct xfs_buf *agbp, + xfs_agino_t agino, + struct xfs_bmap_free *flist, + int *delete, + xfs_ino_t *first_ino, + struct xfs_inobt_rec_incore *orec) { - /* REFERENCED */ - xfs_agblock_t agbno; /* block number containing inode */ - xfs_buf_t *agbp; /* buffer containing allocation group header */ - xfs_agino_t agino; /* inode number relative to allocation group */ - xfs_agnumber_t agno; /* allocation group number */ - xfs_agi_t *agi; /* allocation group header */ - xfs_btree_cur_t *cur; /* inode btree cursor */ - int error; /* error return value */ - int i; /* result code */ - int ilen; /* inodes in an inode cluster */ - xfs_mount_t *mp; /* mount structure for filesystem */ - int off; /* offset of inode in inode chunk */ - xfs_inobt_rec_incore_t rec; /* btree record */ - struct xfs_perag *pag; - - mp = tp->t_mountp; + struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); + xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); + struct xfs_perag *pag; + struct xfs_btree_cur *cur; + struct xfs_inobt_rec_incore rec; + int ilen; + int error; + int i; + int off; - /* - * Break up inode number into its components. - */ - agno = XFS_INO_TO_AGNO(mp, inode); - if (agno >= mp->m_sb.sb_agcount) { - xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).", - __func__, agno, mp->m_sb.sb_agcount); - ASSERT(0); - return XFS_ERROR(EINVAL); - } - agino = XFS_INO_TO_AGINO(mp, inode); - if (inode != XFS_AGINO_TO_INO(mp, agno, agino)) { - xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).", - __func__, (unsigned long long)inode, - (unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino)); - ASSERT(0); - return XFS_ERROR(EINVAL); - } - agbno = XFS_AGINO_TO_AGBNO(mp, agino); - if (agbno >= mp->m_sb.sb_agblocks) { - xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).", - __func__, agbno, mp->m_sb.sb_agblocks); - ASSERT(0); - return XFS_ERROR(EINVAL); - } - /* - * Get the allocation group header. - */ - error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); - if (error) { - xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.", - __func__, error); - return error; - } - agi = XFS_BUF_TO_AGI(agbp); ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC)); - ASSERT(agbno < be32_to_cpu(agi->agi_length)); + ASSERT(XFS_AGINO_TO_AGBNO(mp, agino) < be32_to_cpu(agi->agi_length)); + /* * Initialize the cursor. */ - cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); + cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); error = xfs_check_agi_freecount(cur, agi); if (error) @@ -1261,6 +1549,7 @@ xfs_difree( if (error) goto error0; + *orec = rec; xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return 0; @@ -1269,6 +1558,182 @@ xfs_difree( return error; } +/* + * Free an inode in the free inode btree. + */ +STATIC int +xfs_difree_finobt( + struct xfs_mount *mp, + struct xfs_trans *tp, + struct xfs_buf *agbp, + xfs_agino_t agino, + struct xfs_inobt_rec_incore *ibtrec) /* inobt record */ +{ + struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); + xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); + struct xfs_btree_cur *cur; + struct xfs_inobt_rec_incore rec; + int offset = agino - ibtrec->ir_startino; + int error; + int i; + + cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO); + + error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i); + if (error) + goto error; + if (i == 0) { + /* + * If the record does not exist in the finobt, we must have just + * freed an inode in a previously fully allocated chunk. If not, + * something is out of sync. + */ + XFS_WANT_CORRUPTED_GOTO(ibtrec->ir_freecount == 1, error); + + error = xfs_inobt_insert_rec(cur, ibtrec->ir_freecount, + ibtrec->ir_free, &i); + if (error) + goto error; + ASSERT(i == 1); + + goto out; + } + + /* + * Read and update the existing record. We could just copy the ibtrec + * across here, but that would defeat the purpose of having redundant + * metadata. By making the modifications independently, we can catch + * corruptions that we wouldn't see if we just copied from one record + * to another. + */ + error = xfs_inobt_get_rec(cur, &rec, &i); + if (error) + goto error; + XFS_WANT_CORRUPTED_GOTO(i == 1, error); + + rec.ir_free |= XFS_INOBT_MASK(offset); + rec.ir_freecount++; + + XFS_WANT_CORRUPTED_GOTO((rec.ir_free == ibtrec->ir_free) && + (rec.ir_freecount == ibtrec->ir_freecount), + error); + + /* + * The content of inobt records should always match between the inobt + * and finobt. The lifecycle of records in the finobt is different from + * the inobt in that the finobt only tracks records with at least one + * free inode. Hence, if all of the inodes are free and we aren't + * keeping inode chunks permanently on disk, remove the record. + * Otherwise, update the record with the new information. + */ + if (rec.ir_freecount == mp->m_ialloc_inos && + !(mp->m_flags & XFS_MOUNT_IKEEP)) { + error = xfs_btree_delete(cur, &i); + if (error) + goto error; + ASSERT(i == 1); + } else { + error = xfs_inobt_update(cur, &rec); + if (error) + goto error; + } + +out: + error = xfs_check_agi_freecount(cur, agi); + if (error) + goto error; + + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + return 0; + +error: + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Free disk inode. Carefully avoids touching the incore inode, all + * manipulations incore are the caller's responsibility. + * The on-disk inode is not changed by this operation, only the + * btree (free inode mask) is changed. + */ +int +xfs_difree( + struct xfs_trans *tp, /* transaction pointer */ + xfs_ino_t inode, /* inode to be freed */ + struct xfs_bmap_free *flist, /* extents to free */ + int *delete,/* set if inode cluster was deleted */ + xfs_ino_t *first_ino)/* first inode in deleted cluster */ +{ + /* REFERENCED */ + xfs_agblock_t agbno; /* block number containing inode */ + struct xfs_buf *agbp; /* buffer for allocation group header */ + xfs_agino_t agino; /* allocation group inode number */ + xfs_agnumber_t agno; /* allocation group number */ + int error; /* error return value */ + struct xfs_mount *mp; /* mount structure for filesystem */ + struct xfs_inobt_rec_incore rec;/* btree record */ + + mp = tp->t_mountp; + + /* + * Break up inode number into its components. + */ + agno = XFS_INO_TO_AGNO(mp, inode); + if (agno >= mp->m_sb.sb_agcount) { + xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).", + __func__, agno, mp->m_sb.sb_agcount); + ASSERT(0); + return XFS_ERROR(EINVAL); + } + agino = XFS_INO_TO_AGINO(mp, inode); + if (inode != XFS_AGINO_TO_INO(mp, agno, agino)) { + xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).", + __func__, (unsigned long long)inode, + (unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino)); + ASSERT(0); + return XFS_ERROR(EINVAL); + } + agbno = XFS_AGINO_TO_AGBNO(mp, agino); + if (agbno >= mp->m_sb.sb_agblocks) { + xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).", + __func__, agbno, mp->m_sb.sb_agblocks); + ASSERT(0); + return XFS_ERROR(EINVAL); + } + /* + * Get the allocation group header. + */ + error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); + if (error) { + xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.", + __func__, error); + return error; + } + + /* + * Fix up the inode allocation btree. + */ + error = xfs_difree_inobt(mp, tp, agbp, agino, flist, delete, first_ino, + &rec); + if (error) + goto error0; + + /* + * Fix up the free inode btree. + */ + if (xfs_sb_version_hasfinobt(&mp->m_sb)) { + error = xfs_difree_finobt(mp, tp, agbp, agino, &rec); + if (error) + goto error0; + } + + return 0; + +error0: + return error; +} + STATIC int xfs_imap_lookup( struct xfs_mount *mp, @@ -1300,7 +1765,7 @@ xfs_imap_lookup( * we have a record, we need to ensure it contains the inode number * we are looking up. */ - cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); + cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i); if (!error) { if (i) @@ -1488,7 +1953,16 @@ xfs_ialloc_compute_maxlevels( } /* - * Log specified fields for the ag hdr (inode section) + * Log specified fields for the ag hdr (inode section). The growth of the agi + * structure over time requires that we interpret the buffer as two logical + * regions delineated by the end of the unlinked list. This is due to the size + * of the hash table and its location in the middle of the agi. + * + * For example, a request to log a field before agi_unlinked and a field after + * agi_unlinked could cause us to log the entire hash table and use an excessive + * amount of log space. To avoid this behavior, log the region up through + * agi_unlinked in one call and the region after agi_unlinked through the end of + * the structure in another. */ void xfs_ialloc_log_agi( @@ -1511,6 +1985,8 @@ xfs_ialloc_log_agi( offsetof(xfs_agi_t, agi_newino), offsetof(xfs_agi_t, agi_dirino), offsetof(xfs_agi_t, agi_unlinked), + offsetof(xfs_agi_t, agi_free_root), + offsetof(xfs_agi_t, agi_free_level), sizeof(xfs_agi_t) }; #ifdef DEBUG @@ -1519,15 +1995,30 @@ xfs_ialloc_log_agi( agi = XFS_BUF_TO_AGI(bp); ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC)); #endif + + xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF); + /* - * Compute byte offsets for the first and last fields. + * Compute byte offsets for the first and last fields in the first + * region and log the agi buffer. This only logs up through + * agi_unlinked. */ - xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS, &first, &last); + if (fields & XFS_AGI_ALL_BITS_R1) { + xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R1, + &first, &last); + xfs_trans_log_buf(tp, bp, first, last); + } + /* - * Log the allocation group inode header buffer. + * Mask off the bits in the first region and calculate the first and + * last field offsets for any bits in the second region. */ - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF); - xfs_trans_log_buf(tp, bp, first, last); + fields &= ~XFS_AGI_ALL_BITS_R1; + if (fields) { + xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R2, + &first, &last); + xfs_trans_log_buf(tp, bp, first, last); + } } #ifdef DEBUG diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c index 7e309b11e87d75..726f83a681a594 100644 --- a/fs/xfs/xfs_ialloc_btree.c +++ b/fs/xfs/xfs_ialloc_btree.c @@ -49,7 +49,8 @@ xfs_inobt_dup_cursor( struct xfs_btree_cur *cur) { return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp, - cur->bc_private.a.agbp, cur->bc_private.a.agno); + cur->bc_private.a.agbp, cur->bc_private.a.agno, + cur->bc_btnum); } STATIC void @@ -66,12 +67,26 @@ xfs_inobt_set_root( xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL); } +STATIC void +xfs_finobt_set_root( + struct xfs_btree_cur *cur, + union xfs_btree_ptr *nptr, + int inc) /* level change */ +{ + struct xfs_buf *agbp = cur->bc_private.a.agbp; + struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); + + agi->agi_free_root = nptr->s; + be32_add_cpu(&agi->agi_free_level, inc); + xfs_ialloc_log_agi(cur->bc_tp, agbp, + XFS_AGI_FREE_ROOT | XFS_AGI_FREE_LEVEL); +} + STATIC int xfs_inobt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, - int length, int *stat) { xfs_alloc_arg_t args; /* block allocation args */ @@ -173,6 +188,17 @@ xfs_inobt_init_ptr_from_cur( ptr->s = agi->agi_root; } +STATIC void +xfs_finobt_init_ptr_from_cur( + struct xfs_btree_cur *cur, + union xfs_btree_ptr *ptr) +{ + struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); + + ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno)); + ptr->s = agi->agi_free_root; +} + STATIC __int64_t xfs_inobt_key_diff( struct xfs_btree_cur *cur, @@ -203,6 +229,7 @@ xfs_inobt_verify( */ switch (block->bb_magic) { case cpu_to_be32(XFS_IBT_CRC_MAGIC): + case cpu_to_be32(XFS_FIBT_CRC_MAGIC): if (!xfs_sb_version_hascrc(&mp->m_sb)) return false; if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid)) @@ -214,6 +241,7 @@ xfs_inobt_verify( return false; /* fall through */ case cpu_to_be32(XFS_IBT_MAGIC): + case cpu_to_be32(XFS_FIBT_MAGIC): break; default: return 0; @@ -317,6 +345,28 @@ static const struct xfs_btree_ops xfs_inobt_ops = { #endif }; +static const struct xfs_btree_ops xfs_finobt_ops = { + .rec_len = sizeof(xfs_inobt_rec_t), + .key_len = sizeof(xfs_inobt_key_t), + + .dup_cursor = xfs_inobt_dup_cursor, + .set_root = xfs_finobt_set_root, + .alloc_block = xfs_inobt_alloc_block, + .free_block = xfs_inobt_free_block, + .get_minrecs = xfs_inobt_get_minrecs, + .get_maxrecs = xfs_inobt_get_maxrecs, + .init_key_from_rec = xfs_inobt_init_key_from_rec, + .init_rec_from_key = xfs_inobt_init_rec_from_key, + .init_rec_from_cur = xfs_inobt_init_rec_from_cur, + .init_ptr_from_cur = xfs_finobt_init_ptr_from_cur, + .key_diff = xfs_inobt_key_diff, + .buf_ops = &xfs_inobt_buf_ops, +#if defined(DEBUG) || defined(XFS_WARN) + .keys_inorder = xfs_inobt_keys_inorder, + .recs_inorder = xfs_inobt_recs_inorder, +#endif +}; + /* * Allocate a new inode btree cursor. */ @@ -325,7 +375,8 @@ xfs_inobt_init_cursor( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *agbp, /* buffer for agi structure */ - xfs_agnumber_t agno) /* allocation group number */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_btnum_t btnum) /* ialloc or free ino btree */ { struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); struct xfs_btree_cur *cur; @@ -334,11 +385,17 @@ xfs_inobt_init_cursor( cur->bc_tp = tp; cur->bc_mp = mp; - cur->bc_nlevels = be32_to_cpu(agi->agi_level); - cur->bc_btnum = XFS_BTNUM_INO; + cur->bc_btnum = btnum; + if (btnum == XFS_BTNUM_INO) { + cur->bc_nlevels = be32_to_cpu(agi->agi_level); + cur->bc_ops = &xfs_inobt_ops; + } else { + cur->bc_nlevels = be32_to_cpu(agi->agi_free_level); + cur->bc_ops = &xfs_finobt_ops; + } + cur->bc_blocklog = mp->m_sb.sb_blocklog; - cur->bc_ops = &xfs_inobt_ops; if (xfs_sb_version_hascrc(&mp->m_sb)) cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; diff --git a/fs/xfs/xfs_ialloc_btree.h b/fs/xfs/xfs_ialloc_btree.h index f38b22011c4e46..d7ebea72c2d012 100644 --- a/fs/xfs/xfs_ialloc_btree.h +++ b/fs/xfs/xfs_ialloc_btree.h @@ -58,7 +58,8 @@ struct xfs_mount; ((index) - 1) * sizeof(xfs_inobt_ptr_t))) extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *, - struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t); + struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t, + xfs_btnum_t); extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int); #endif /* __XFS_IALLOC_BTREE_H__ */ diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 98d35244eecc93..c48df5f25b9f46 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -507,8 +507,7 @@ STATIC int xfs_inode_ag_walk( struct xfs_mount *mp, struct xfs_perag *pag, - int (*execute)(struct xfs_inode *ip, - struct xfs_perag *pag, int flags, + int (*execute)(struct xfs_inode *ip, int flags, void *args), int flags, void *args, @@ -582,7 +581,7 @@ xfs_inode_ag_walk( for (i = 0; i < nr_found; i++) { if (!batch[i]) continue; - error = execute(batch[i], pag, flags, args); + error = execute(batch[i], flags, args); IRELE(batch[i]); if (error == EAGAIN) { skipped++; @@ -636,8 +635,7 @@ xfs_eofblocks_worker( int xfs_inode_ag_iterator( struct xfs_mount *mp, - int (*execute)(struct xfs_inode *ip, - struct xfs_perag *pag, int flags, + int (*execute)(struct xfs_inode *ip, int flags, void *args), int flags, void *args) @@ -664,8 +662,7 @@ xfs_inode_ag_iterator( int xfs_inode_ag_iterator_tag( struct xfs_mount *mp, - int (*execute)(struct xfs_inode *ip, - struct xfs_perag *pag, int flags, + int (*execute)(struct xfs_inode *ip, int flags, void *args), int flags, void *args, @@ -1209,7 +1206,6 @@ xfs_inode_match_id( STATIC int xfs_inode_free_eofblocks( struct xfs_inode *ip, - struct xfs_perag *pag, int flags, void *args) { diff --git a/fs/xfs/xfs_icache.h b/fs/xfs/xfs_icache.h index 9ed68bb750f508..9cf017b899be9d 100644 --- a/fs/xfs/xfs_icache.h +++ b/fs/xfs/xfs_icache.h @@ -60,12 +60,10 @@ int xfs_icache_free_eofblocks(struct xfs_mount *, struct xfs_eofblocks *); void xfs_eofblocks_worker(struct work_struct *); int xfs_inode_ag_iterator(struct xfs_mount *mp, - int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, - int flags, void *args), + int (*execute)(struct xfs_inode *ip, int flags, void *args), int flags, void *args); int xfs_inode_ag_iterator_tag(struct xfs_mount *mp, - int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, - int flags, void *args), + int (*execute)(struct xfs_inode *ip, int flags, void *args), int flags, void *args, int tag); static inline int diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 768087bedbac58..6d6b44a508f951 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -655,7 +655,6 @@ xfs_ialloc( uint flags; int error; timespec_t tv; - int filestreams = 0; /* * Call the space management code to pick @@ -772,13 +771,6 @@ xfs_ialloc( flags |= XFS_ILOG_DEV; break; case S_IFREG: - /* - * we can't set up filestreams until after the VFS inode - * is set up properly. - */ - if (pip && xfs_inode_is_filestream(pip)) - filestreams = 1; - /* fall through */ case S_IFDIR: if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) { uint di_flags = 0; @@ -844,15 +836,6 @@ xfs_ialloc( /* now that we have an i_mode we can setup inode ops and unlock */ xfs_setup_inode(ip); - /* now we have set up the vfs inode we can associate the filestream */ - if (filestreams) { - error = xfs_filestream_associate(pip, ip); - if (error < 0) - return -error; - if (!error) - xfs_iflags_set(ip, XFS_IFILESTREAM); - } - *ipp = ip; return 0; } @@ -1698,16 +1681,6 @@ xfs_release( if (!XFS_FORCED_SHUTDOWN(mp)) { int truncated; - /* - * If we are using filestreams, and we have an unlinked - * file that we are processing the last close on, then nothing - * will be able to reopen and write to this file. Purge this - * inode from the filestreams cache so that it doesn't delay - * teardown of the inode. - */ - if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip)) - xfs_filestream_deassociate(ip); - /* * If we previously truncated this file and removed old data * in the process, we want to initiate "early" writeout on @@ -1838,9 +1811,33 @@ xfs_inactive_ifree( int error; tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); - error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree, 0, 0); + + /* + * The ifree transaction might need to allocate blocks for record + * insertion to the finobt. We don't want to fail here at ENOSPC, so + * allow ifree to dip into the reserved block pool if necessary. + * + * Freeing large sets of inodes generally means freeing inode chunks, + * directory and file data blocks, so this should be relatively safe. + * Only under severe circumstances should it be possible to free enough + * inodes to exhaust the reserve block pool via finobt expansion while + * at the same time not creating free space in the filesystem. + * + * Send a warning if the reservation does happen to fail, as the inode + * now remains allocated and sits on the unlinked list until the fs is + * repaired. + */ + tp->t_flags |= XFS_TRANS_RESERVE; + error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree, + XFS_IFREE_SPACE_RES(mp), 0); if (error) { - ASSERT(XFS_FORCED_SHUTDOWN(mp)); + if (error == ENOSPC) { + xfs_warn_ratelimited(mp, + "Failed to remove inode(s) from unlinked list. " + "Please free space, unmount and run xfs_repair."); + } else { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + } xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES); return error; } @@ -2664,13 +2661,7 @@ xfs_remove( if (error) goto std_return; - /* - * If we are using filestreams, kill the stream association. - * If the file is still open it may get a new one but that - * will get killed on last close in xfs_close() so we don't - * have to worry about that. - */ - if (!is_dir && link_zero && xfs_inode_is_filestream(ip)) + if (is_dir && xfs_inode_is_filestream(ip)) xfs_filestream_deassociate(ip); return 0; @@ -3372,9 +3363,9 @@ xfs_iflush_int( } } - xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp); + xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK); if (XFS_IFORK_Q(ip)) - xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp); + xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK); xfs_inobp_check(mp, bp); /* diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index f2fcde52b66db9..13aea548206c50 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -209,7 +209,6 @@ xfs_get_initial_prid(struct xfs_inode *dp) #define XFS_ISTALE (1 << 1) /* inode has been staled */ #define XFS_IRECLAIMABLE (1 << 2) /* inode can be reclaimed */ #define XFS_INEW (1 << 3) /* inode has just been allocated */ -#define XFS_IFILESTREAM (1 << 4) /* inode is in a filestream dir. */ #define XFS_ITRUNCATED (1 << 5) /* truncated down so flush-on-close */ #define XFS_IDIRTY_RELEASE (1 << 6) /* dirty release already seen */ #define __XFS_IFLOCK_BIT 7 /* inode is being flushed right now */ @@ -225,8 +224,7 @@ xfs_get_initial_prid(struct xfs_inode *dp) */ #define XFS_IRECLAIM_RESET_FLAGS \ (XFS_IRECLAIMABLE | XFS_IRECLAIM | \ - XFS_IDIRTY_RELEASE | XFS_ITRUNCATED | \ - XFS_IFILESTREAM); + XFS_IDIRTY_RELEASE | XFS_ITRUNCATED) /* * Synchronize processes attempting to flush the in-core inode back to disk. diff --git a/fs/xfs/xfs_inode_fork.c b/fs/xfs/xfs_inode_fork.c index 73514c0486b710..b031e8d0d9287d 100644 --- a/fs/xfs/xfs_inode_fork.c +++ b/fs/xfs/xfs_inode_fork.c @@ -798,8 +798,7 @@ xfs_iflush_fork( xfs_inode_t *ip, xfs_dinode_t *dip, xfs_inode_log_item_t *iip, - int whichfork, - xfs_buf_t *bp) + int whichfork) { char *cp; xfs_ifork_t *ifp; diff --git a/fs/xfs/xfs_inode_fork.h b/fs/xfs/xfs_inode_fork.h index eb329a1ea8886a..7d3b1ed6dcbe93 100644 --- a/fs/xfs/xfs_inode_fork.h +++ b/fs/xfs/xfs_inode_fork.h @@ -127,8 +127,7 @@ typedef struct xfs_ifork { int xfs_iformat_fork(struct xfs_inode *, struct xfs_dinode *); void xfs_iflush_fork(struct xfs_inode *, struct xfs_dinode *, - struct xfs_inode_log_item *, int, - struct xfs_buf *); + struct xfs_inode_log_item *, int); void xfs_idestroy_fork(struct xfs_inode *, int); void xfs_idata_realloc(struct xfs_inode *, int, int); void xfs_iroot_realloc(struct xfs_inode *, int, int); diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 0b18776b075e44..2d8f4fdf07f9b3 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -543,10 +543,11 @@ xfs_attrmulti_by_handle( ops = memdup_user(am_hreq.ops, size); if (IS_ERR(ops)) { - error = PTR_ERR(ops); + error = -PTR_ERR(ops); goto out_dput; } + error = ENOMEM; attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL); if (!attr_name) goto out_kfree_ops; @@ -556,7 +557,7 @@ xfs_attrmulti_by_handle( ops[i].am_error = strncpy_from_user((char *)attr_name, ops[i].am_attrname, MAXNAMELEN); if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN) - error = -ERANGE; + error = ERANGE; if (ops[i].am_error < 0) break; diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c index a7992f8de9d3fa..944d5baa710a39 100644 --- a/fs/xfs/xfs_ioctl32.c +++ b/fs/xfs/xfs_ioctl32.c @@ -424,10 +424,11 @@ xfs_compat_attrmulti_by_handle( ops = memdup_user(compat_ptr(am_hreq.ops), size); if (IS_ERR(ops)) { - error = PTR_ERR(ops); + error = -PTR_ERR(ops); goto out_dput; } + error = ENOMEM; attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL); if (!attr_name) goto out_kfree_ops; @@ -438,7 +439,7 @@ xfs_compat_attrmulti_by_handle( compat_ptr(ops[i].am_attrname), MAXNAMELEN); if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN) - error = -ERANGE; + error = ERANGE; if (ops[i].am_error < 0) break; diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 3b80ebae05f52e..6c5eb4c551e3f5 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -730,7 +730,7 @@ xfs_iomap_write_allocate( */ nimaps = 1; end_fsb = XFS_B_TO_FSB(mp, XFS_ISIZE(ip)); - error = xfs_bmap_last_offset(NULL, ip, &last_block, + error = xfs_bmap_last_offset(ip, &last_block, XFS_DATA_FORK); if (error) goto trans_cancel; diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 301ecbfcc0bee4..699d5a119bd5ed 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -829,22 +829,34 @@ xfs_setattr_size( */ inode_dio_wait(inode); + /* + * Do all the page cache truncate work outside the transaction context + * as the "lock" order is page lock->log space reservation. i.e. + * locking pages inside the transaction can ABBA deadlock with + * writeback. We have to do the VFS inode size update before we truncate + * the pagecache, however, to avoid racing with page faults beyond the + * new EOF they are not serialised against truncate operations except by + * page locks and size updates. + * + * Hence we are in a situation where a truncate can fail with ENOMEM + * from xfs_trans_reserve(), but having already truncated the in-memory + * version of the file (i.e. made user visible changes). There's not + * much we can do about this, except to hope that the caller sees ENOMEM + * and retries the truncate operation. + */ error = -block_truncate_page(inode->i_mapping, newsize, xfs_get_blocks); if (error) return error; + truncate_setsize(inode, newsize); tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0); if (error) goto out_trans_cancel; - truncate_setsize(inode, newsize); - commit_flags = XFS_TRANS_RELEASE_LOG_RES; lock_flags |= XFS_ILOCK_EXCL; - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); /* diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index f4633828515242..cb64f222d60743 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c @@ -270,7 +270,8 @@ xfs_bulkstat( /* * Allocate and initialize a btree cursor for ialloc btree. */ - cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno); + cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno, + XFS_BTNUM_INO); irbp = irbuf; irbufend = irbuf + nirbuf; end_of_ag = 0; @@ -621,7 +622,8 @@ xfs_inumbers( agino = 0; continue; } - cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno); + cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno, + XFS_BTNUM_INO); error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE, &tmp); if (error) { diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index a5f8bd9899d37a..3554098692d86e 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -3952,11 +3952,14 @@ xfs_log_force_umount( retval = xlog_state_ioerror(log); spin_unlock(&log->l_icloglock); } + /* - * Wake up everybody waiting on xfs_log_force. - * Callback all log item committed functions as if the - * log writes were completed. + * Wake up everybody waiting on xfs_log_force. Wake the CIL push first + * as if the log writes were completed. The abort handling in the log + * item committed callback functions will do this again under lock to + * avoid races. */ + wake_up_all(&log->l_cilp->xc_commit_wait); xlog_state_do_callback(log, XFS_LI_ABORTED, NULL); #ifdef XFSERRORDEBUG diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index 7e54553911764e..039c873e6fb20e 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c @@ -385,7 +385,15 @@ xlog_cil_committed( xfs_extent_busy_clear(mp, &ctx->busy_extents, (mp->m_flags & XFS_MOUNT_DISCARD) && !abort); + /* + * If we are aborting the commit, wake up anyone waiting on the + * committing list. If we don't, then a shutdown we can leave processes + * waiting in xlog_cil_force_lsn() waiting on a sequence commit that + * will never happen because we aborted it. + */ spin_lock(&ctx->cil->xc_push_lock); + if (abort) + wake_up_all(&ctx->cil->xc_commit_wait); list_del(&ctx->committing); spin_unlock(&ctx->cil->xc_push_lock); @@ -563,9 +571,19 @@ xlog_cil_push( restart: spin_lock(&cil->xc_push_lock); list_for_each_entry(new_ctx, &cil->xc_committing, committing) { + /* + * Avoid getting stuck in this loop because we were woken by the + * shutdown, but then went back to sleep once already in the + * shutdown state. + */ + if (XLOG_FORCED_SHUTDOWN(log)) { + spin_unlock(&cil->xc_push_lock); + goto out_abort_free_ticket; + } + /* * Higher sequences will wait for this one so skip them. - * Don't wait for own own sequence, either. + * Don't wait for our own sequence, either. */ if (new_ctx->sequence >= ctx->sequence) continue; @@ -810,6 +828,13 @@ xlog_cil_force_lsn( */ spin_lock(&cil->xc_push_lock); list_for_each_entry(ctx, &cil->xc_committing, committing) { + /* + * Avoid getting stuck in this loop because we were woken by the + * shutdown, but then went back to sleep once already in the + * shutdown state. + */ + if (XLOG_FORCED_SHUTDOWN(log)) + goto out_shutdown; if (ctx->sequence > sequence) continue; if (!ctx->commit_lsn) { @@ -833,14 +858,12 @@ xlog_cil_force_lsn( * push sequence after the above wait loop and the CIL still contains * dirty objects. * - * When the push occurs, it will empty the CIL and - * atomically increment the currect sequence past the push sequence and - * move it into the committing list. Of course, if the CIL is clean at - * the time of the push, it won't have pushed the CIL at all, so in that - * case we should try the push for this sequence again from the start - * just in case. + * When the push occurs, it will empty the CIL and atomically increment + * the currect sequence past the push sequence and move it into the + * committing list. Of course, if the CIL is clean at the time of the + * push, it won't have pushed the CIL at all, so in that case we should + * try the push for this sequence again from the start just in case. */ - if (sequence == cil->xc_current_sequence && !list_empty(&cil->xc_cil)) { spin_unlock(&cil->xc_push_lock); @@ -849,6 +872,17 @@ xlog_cil_force_lsn( spin_unlock(&cil->xc_push_lock); return commit_lsn; + + /* + * We detected a shutdown in progress. We need to trigger the log force + * to pass through it's iclog state machine error handling, even though + * we are already in a shutdown state. Hence we can't return + * NULLCOMMITLSN here as that has special meaning to log forces (i.e. + * LSN is already stable), so we return a zero LSN instead. + */ +out_shutdown: + spin_unlock(&cil->xc_push_lock); + return 0; } /* diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index bce53ac81096af..981af0f6504b1e 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -2138,7 +2138,9 @@ xlog_recover_validate_buf_type( bp->b_ops = &xfs_allocbt_buf_ops; break; case XFS_IBT_CRC_MAGIC: + case XFS_FIBT_CRC_MAGIC: case XFS_IBT_MAGIC: + case XFS_FIBT_MAGIC: bp->b_ops = &xfs_inobt_buf_ops; break; case XFS_BMAP_CRC_MAGIC: @@ -3145,7 +3147,7 @@ xlog_recover_efd_pass2( } lip = xfs_trans_ail_cursor_next(ailp, &cur); } - xfs_trans_ail_cursor_done(ailp, &cur); + xfs_trans_ail_cursor_done(&cur); spin_unlock(&ailp->xa_lock); return 0; @@ -3520,8 +3522,7 @@ xlog_recover_commit_trans( STATIC int xlog_recover_unmount_trans( - struct xlog *log, - struct xlog_recover *trans) + struct xlog *log) { /* Do nothing now */ xfs_warn(log->l_mp, "%s: Unmount LR", __func__); @@ -3595,7 +3596,7 @@ xlog_recover_process_data( trans, pass); break; case XLOG_UNMOUNT_TRANS: - error = xlog_recover_unmount_trans(log, trans); + error = xlog_recover_unmount_trans(log); break; case XLOG_WAS_CONT_TRANS: error = xlog_recover_add_to_cont_trans(log, @@ -3757,7 +3758,7 @@ xlog_recover_process_efis( lip = xfs_trans_ail_cursor_next(ailp, &cur); } out: - xfs_trans_ail_cursor_done(ailp, &cur); + xfs_trans_ail_cursor_done(&cur); spin_unlock(&ailp->xa_lock); return error; } diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c index 4aff5639573259..f99b4933dc2262 100644 --- a/fs/xfs/xfs_mru_cache.c +++ b/fs/xfs/xfs_mru_cache.c @@ -100,14 +100,20 @@ * likely result in a loop in one of the lists. That's a sure-fire recipe for * an infinite loop in the code. */ -typedef struct xfs_mru_cache_elem -{ - struct list_head list_node; - unsigned long key; - void *value; -} xfs_mru_cache_elem_t; +struct xfs_mru_cache { + struct radix_tree_root store; /* Core storage data structure. */ + struct list_head *lists; /* Array of lists, one per grp. */ + struct list_head reap_list; /* Elements overdue for reaping. */ + spinlock_t lock; /* Lock to protect this struct. */ + unsigned int grp_count; /* Number of discrete groups. */ + unsigned int grp_time; /* Time period spanned by grps. */ + unsigned int lru_grp; /* Group containing time zero. */ + unsigned long time_zero; /* Time first element was added. */ + xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */ + struct delayed_work work; /* Workqueue data for reaping. */ + unsigned int queued; /* work has been queued */ +}; -static kmem_zone_t *xfs_mru_elem_zone; static struct workqueue_struct *xfs_mru_reap_wq; /* @@ -129,12 +135,12 @@ static struct workqueue_struct *xfs_mru_reap_wq; */ STATIC unsigned long _xfs_mru_cache_migrate( - xfs_mru_cache_t *mru, - unsigned long now) + struct xfs_mru_cache *mru, + unsigned long now) { - unsigned int grp; - unsigned int migrated = 0; - struct list_head *lru_list; + unsigned int grp; + unsigned int migrated = 0; + struct list_head *lru_list; /* Nothing to do if the data store is empty. */ if (!mru->time_zero) @@ -193,11 +199,11 @@ _xfs_mru_cache_migrate( */ STATIC void _xfs_mru_cache_list_insert( - xfs_mru_cache_t *mru, - xfs_mru_cache_elem_t *elem) + struct xfs_mru_cache *mru, + struct xfs_mru_cache_elem *elem) { - unsigned int grp = 0; - unsigned long now = jiffies; + unsigned int grp = 0; + unsigned long now = jiffies; /* * If the data store is empty, initialise time zero, leave grp set to @@ -231,10 +237,10 @@ _xfs_mru_cache_list_insert( */ STATIC void _xfs_mru_cache_clear_reap_list( - xfs_mru_cache_t *mru) __releases(mru->lock) __acquires(mru->lock) - + struct xfs_mru_cache *mru) + __releases(mru->lock) __acquires(mru->lock) { - xfs_mru_cache_elem_t *elem, *next; + struct xfs_mru_cache_elem *elem, *next; struct list_head tmp; INIT_LIST_HEAD(&tmp); @@ -252,15 +258,8 @@ _xfs_mru_cache_clear_reap_list( spin_unlock(&mru->lock); list_for_each_entry_safe(elem, next, &tmp, list_node) { - - /* Remove the element from the reap list. */ list_del_init(&elem->list_node); - - /* Call the client's free function with the key and value pointer. */ - mru->free_func(elem->key, elem->value); - - /* Free the element structure. */ - kmem_zone_free(xfs_mru_elem_zone, elem); + mru->free_func(elem); } spin_lock(&mru->lock); @@ -277,7 +276,8 @@ STATIC void _xfs_mru_cache_reap( struct work_struct *work) { - xfs_mru_cache_t *mru = container_of(work, xfs_mru_cache_t, work.work); + struct xfs_mru_cache *mru = + container_of(work, struct xfs_mru_cache, work.work); unsigned long now, next; ASSERT(mru && mru->lists); @@ -304,28 +304,16 @@ _xfs_mru_cache_reap( int xfs_mru_cache_init(void) { - xfs_mru_elem_zone = kmem_zone_init(sizeof(xfs_mru_cache_elem_t), - "xfs_mru_cache_elem"); - if (!xfs_mru_elem_zone) - goto out; - xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache", WQ_MEM_RECLAIM, 1); if (!xfs_mru_reap_wq) - goto out_destroy_mru_elem_zone; - + return -ENOMEM; return 0; - - out_destroy_mru_elem_zone: - kmem_zone_destroy(xfs_mru_elem_zone); - out: - return -ENOMEM; } void xfs_mru_cache_uninit(void) { destroy_workqueue(xfs_mru_reap_wq); - kmem_zone_destroy(xfs_mru_elem_zone); } /* @@ -336,14 +324,14 @@ xfs_mru_cache_uninit(void) */ int xfs_mru_cache_create( - xfs_mru_cache_t **mrup, + struct xfs_mru_cache **mrup, unsigned int lifetime_ms, unsigned int grp_count, xfs_mru_cache_free_func_t free_func) { - xfs_mru_cache_t *mru = NULL; - int err = 0, grp; - unsigned int grp_time; + struct xfs_mru_cache *mru = NULL; + int err = 0, grp; + unsigned int grp_time; if (mrup) *mrup = NULL; @@ -400,7 +388,7 @@ xfs_mru_cache_create( */ static void xfs_mru_cache_flush( - xfs_mru_cache_t *mru) + struct xfs_mru_cache *mru) { if (!mru || !mru->lists) return; @@ -420,7 +408,7 @@ xfs_mru_cache_flush( void xfs_mru_cache_destroy( - xfs_mru_cache_t *mru) + struct xfs_mru_cache *mru) { if (!mru || !mru->lists) return; @@ -438,38 +426,30 @@ xfs_mru_cache_destroy( */ int xfs_mru_cache_insert( - xfs_mru_cache_t *mru, - unsigned long key, - void *value) + struct xfs_mru_cache *mru, + unsigned long key, + struct xfs_mru_cache_elem *elem) { - xfs_mru_cache_elem_t *elem; + int error; ASSERT(mru && mru->lists); if (!mru || !mru->lists) return EINVAL; - elem = kmem_zone_zalloc(xfs_mru_elem_zone, KM_SLEEP); - if (!elem) + if (radix_tree_preload(GFP_KERNEL)) return ENOMEM; - if (radix_tree_preload(GFP_KERNEL)) { - kmem_zone_free(xfs_mru_elem_zone, elem); - return ENOMEM; - } - INIT_LIST_HEAD(&elem->list_node); elem->key = key; - elem->value = value; spin_lock(&mru->lock); - - radix_tree_insert(&mru->store, key, elem); + error = -radix_tree_insert(&mru->store, key, elem); radix_tree_preload_end(); - _xfs_mru_cache_list_insert(mru, elem); - + if (!error) + _xfs_mru_cache_list_insert(mru, elem); spin_unlock(&mru->lock); - return 0; + return error; } /* @@ -478,13 +458,12 @@ xfs_mru_cache_insert( * the client data pointer for the removed element is returned, otherwise this * function will return a NULL pointer. */ -void * +struct xfs_mru_cache_elem * xfs_mru_cache_remove( - xfs_mru_cache_t *mru, - unsigned long key) + struct xfs_mru_cache *mru, + unsigned long key) { - xfs_mru_cache_elem_t *elem; - void *value = NULL; + struct xfs_mru_cache_elem *elem; ASSERT(mru && mru->lists); if (!mru || !mru->lists) @@ -492,17 +471,11 @@ xfs_mru_cache_remove( spin_lock(&mru->lock); elem = radix_tree_delete(&mru->store, key); - if (elem) { - value = elem->value; + if (elem) list_del(&elem->list_node); - } - spin_unlock(&mru->lock); - if (elem) - kmem_zone_free(xfs_mru_elem_zone, elem); - - return value; + return elem; } /* @@ -511,13 +484,14 @@ xfs_mru_cache_remove( */ void xfs_mru_cache_delete( - xfs_mru_cache_t *mru, - unsigned long key) + struct xfs_mru_cache *mru, + unsigned long key) { - void *value = xfs_mru_cache_remove(mru, key); + struct xfs_mru_cache_elem *elem; - if (value) - mru->free_func(key, value); + elem = xfs_mru_cache_remove(mru, key); + if (elem) + mru->free_func(elem); } /* @@ -540,12 +514,12 @@ xfs_mru_cache_delete( * status, we need to help it get it right by annotating the path that does * not release the lock. */ -void * +struct xfs_mru_cache_elem * xfs_mru_cache_lookup( - xfs_mru_cache_t *mru, - unsigned long key) + struct xfs_mru_cache *mru, + unsigned long key) { - xfs_mru_cache_elem_t *elem; + struct xfs_mru_cache_elem *elem; ASSERT(mru && mru->lists); if (!mru || !mru->lists) @@ -560,7 +534,7 @@ xfs_mru_cache_lookup( } else spin_unlock(&mru->lock); - return elem ? elem->value : NULL; + return elem; } /* @@ -570,7 +544,8 @@ xfs_mru_cache_lookup( */ void xfs_mru_cache_done( - xfs_mru_cache_t *mru) __releases(mru->lock) + struct xfs_mru_cache *mru) + __releases(mru->lock) { spin_unlock(&mru->lock); } diff --git a/fs/xfs/xfs_mru_cache.h b/fs/xfs/xfs_mru_cache.h index 36dd3ec8b4eb17..fb5245ba5ff744 100644 --- a/fs/xfs/xfs_mru_cache.h +++ b/fs/xfs/xfs_mru_cache.h @@ -18,24 +18,15 @@ #ifndef __XFS_MRU_CACHE_H__ #define __XFS_MRU_CACHE_H__ +struct xfs_mru_cache; -/* Function pointer type for callback to free a client's data pointer. */ -typedef void (*xfs_mru_cache_free_func_t)(unsigned long, void*); +struct xfs_mru_cache_elem { + struct list_head list_node; + unsigned long key; +}; -typedef struct xfs_mru_cache -{ - struct radix_tree_root store; /* Core storage data structure. */ - struct list_head *lists; /* Array of lists, one per grp. */ - struct list_head reap_list; /* Elements overdue for reaping. */ - spinlock_t lock; /* Lock to protect this struct. */ - unsigned int grp_count; /* Number of discrete groups. */ - unsigned int grp_time; /* Time period spanned by grps. */ - unsigned int lru_grp; /* Group containing time zero. */ - unsigned long time_zero; /* Time first element was added. */ - xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */ - struct delayed_work work; /* Workqueue data for reaping. */ - unsigned int queued; /* work has been queued */ -} xfs_mru_cache_t; +/* Function pointer type for callback to free a client's data pointer. */ +typedef void (*xfs_mru_cache_free_func_t)(struct xfs_mru_cache_elem *elem); int xfs_mru_cache_init(void); void xfs_mru_cache_uninit(void); @@ -44,10 +35,12 @@ int xfs_mru_cache_create(struct xfs_mru_cache **mrup, unsigned int lifetime_ms, xfs_mru_cache_free_func_t free_func); void xfs_mru_cache_destroy(struct xfs_mru_cache *mru); int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key, - void *value); -void * xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key); + struct xfs_mru_cache_elem *elem); +struct xfs_mru_cache_elem * +xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key); void xfs_mru_cache_delete(struct xfs_mru_cache *mru, unsigned long key); -void *xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key); +struct xfs_mru_cache_elem * +xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key); void xfs_mru_cache_done(struct xfs_mru_cache *mru); #endif /* __XFS_MRU_CACHE_H__ */ diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index 348e4d2ed6e6e9..1811a98da95649 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -192,47 +192,6 @@ xfs_qm_dqpurge( return 0; } -/* - * Release the group or project dquot pointers the user dquots maybe carrying - * around as a hint, and proceed to purge the user dquot cache if requested. -*/ -STATIC int -xfs_qm_dqpurge_hints( - struct xfs_dquot *dqp, - void *data) -{ - struct xfs_dquot *gdqp = NULL; - struct xfs_dquot *pdqp = NULL; - uint flags = *((uint *)data); - - xfs_dqlock(dqp); - if (dqp->dq_flags & XFS_DQ_FREEING) { - xfs_dqunlock(dqp); - return EAGAIN; - } - - /* If this quota has a hint attached, prepare for releasing it now */ - gdqp = dqp->q_gdquot; - if (gdqp) - dqp->q_gdquot = NULL; - - pdqp = dqp->q_pdquot; - if (pdqp) - dqp->q_pdquot = NULL; - - xfs_dqunlock(dqp); - - if (gdqp) - xfs_qm_dqrele(gdqp); - if (pdqp) - xfs_qm_dqrele(pdqp); - - if (flags & XFS_QMOPT_UQUOTA) - return xfs_qm_dqpurge(dqp, NULL); - - return 0; -} - /* * Purge the dquot cache. */ @@ -241,18 +200,8 @@ xfs_qm_dqpurge_all( struct xfs_mount *mp, uint flags) { - /* - * We have to release group/project dquot hint(s) from the user dquot - * at first if they are there, otherwise we would run into an infinite - * loop while walking through radix tree to purge other type of dquots - * since their refcount is not zero if the user dquot refers to them - * as hint. - * - * Call the special xfs_qm_dqpurge_hints() will end up go through the - * general xfs_qm_dqpurge() against user dquot cache if requested. - */ - xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge_hints, &flags); - + if (flags & XFS_QMOPT_UQUOTA) + xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge, NULL); if (flags & XFS_QMOPT_GQUOTA) xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_dqpurge, NULL); if (flags & XFS_QMOPT_PQUOTA) @@ -409,7 +358,6 @@ xfs_qm_dqattach_one( xfs_dqid_t id, uint type, uint doalloc, - xfs_dquot_t *udqhint, /* hint */ xfs_dquot_t **IO_idqpp) { xfs_dquot_t *dqp; @@ -419,9 +367,9 @@ xfs_qm_dqattach_one( error = 0; /* - * See if we already have it in the inode itself. IO_idqpp is - * &i_udquot or &i_gdquot. This made the code look weird, but - * made the logic a lot simpler. + * See if we already have it in the inode itself. IO_idqpp is &i_udquot + * or &i_gdquot. This made the code look weird, but made the logic a lot + * simpler. */ dqp = *IO_idqpp; if (dqp) { @@ -430,49 +378,10 @@ xfs_qm_dqattach_one( } /* - * udqhint is the i_udquot field in inode, and is non-NULL only - * when the type arg is group/project. Its purpose is to save a - * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside - * the user dquot. - */ - if (udqhint) { - ASSERT(type == XFS_DQ_GROUP || type == XFS_DQ_PROJ); - xfs_dqlock(udqhint); - - /* - * No need to take dqlock to look at the id. - * - * The ID can't change until it gets reclaimed, and it won't - * be reclaimed as long as we have a ref from inode and we - * hold the ilock. - */ - if (type == XFS_DQ_GROUP) - dqp = udqhint->q_gdquot; - else - dqp = udqhint->q_pdquot; - if (dqp && be32_to_cpu(dqp->q_core.d_id) == id) { - ASSERT(*IO_idqpp == NULL); - - *IO_idqpp = xfs_qm_dqhold(dqp); - xfs_dqunlock(udqhint); - return 0; - } - - /* - * We can't hold a dquot lock when we call the dqget code. - * We'll deadlock in no time, because of (not conforming to) - * lock ordering - the inodelock comes before any dquot lock, - * and we may drop and reacquire the ilock in xfs_qm_dqget(). - */ - xfs_dqunlock(udqhint); - } - - /* - * Find the dquot from somewhere. This bumps the - * reference count of dquot and returns it locked. - * This can return ENOENT if dquot didn't exist on - * disk and we didn't ask it to allocate; - * ESRCH if quotas got turned off suddenly. + * Find the dquot from somewhere. This bumps the reference count of + * dquot and returns it locked. This can return ENOENT if dquot didn't + * exist on disk and we didn't ask it to allocate; ESRCH if quotas got + * turned off suddenly. */ error = xfs_qm_dqget(ip->i_mount, ip, id, type, doalloc | XFS_QMOPT_DOWARN, &dqp); @@ -490,48 +399,6 @@ xfs_qm_dqattach_one( return 0; } - -/* - * Given a udquot and group/project type, attach the group/project - * dquot pointer to the udquot as a hint for future lookups. - */ -STATIC void -xfs_qm_dqattach_hint( - struct xfs_inode *ip, - int type) -{ - struct xfs_dquot **dqhintp; - struct xfs_dquot *dqp; - struct xfs_dquot *udq = ip->i_udquot; - - ASSERT(type == XFS_DQ_GROUP || type == XFS_DQ_PROJ); - - xfs_dqlock(udq); - - if (type == XFS_DQ_GROUP) { - dqp = ip->i_gdquot; - dqhintp = &udq->q_gdquot; - } else { - dqp = ip->i_pdquot; - dqhintp = &udq->q_pdquot; - } - - if (*dqhintp) { - struct xfs_dquot *tmp; - - if (*dqhintp == dqp) - goto done; - - tmp = *dqhintp; - *dqhintp = NULL; - xfs_qm_dqrele(tmp); - } - - *dqhintp = xfs_qm_dqhold(dqp); -done: - xfs_dqunlock(udq); -} - static bool xfs_qm_need_dqattach( struct xfs_inode *ip) @@ -562,7 +429,6 @@ xfs_qm_dqattach_locked( uint flags) { xfs_mount_t *mp = ip->i_mount; - uint nquotas = 0; int error = 0; if (!xfs_qm_need_dqattach(ip)) @@ -570,77 +436,39 @@ xfs_qm_dqattach_locked( ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - if (XFS_IS_UQUOTA_ON(mp)) { + if (XFS_IS_UQUOTA_ON(mp) && !ip->i_udquot) { error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER, flags & XFS_QMOPT_DQALLOC, - NULL, &ip->i_udquot); + &ip->i_udquot); if (error) goto done; - nquotas++; + ASSERT(ip->i_udquot); } - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - if (XFS_IS_GQUOTA_ON(mp)) { + if (XFS_IS_GQUOTA_ON(mp) && !ip->i_gdquot) { error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP, flags & XFS_QMOPT_DQALLOC, - ip->i_udquot, &ip->i_gdquot); - /* - * Don't worry about the udquot that we may have - * attached above. It'll get detached, if not already. - */ + &ip->i_gdquot); if (error) goto done; - nquotas++; + ASSERT(ip->i_gdquot); } - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - if (XFS_IS_PQUOTA_ON(mp)) { + if (XFS_IS_PQUOTA_ON(mp) && !ip->i_pdquot) { error = xfs_qm_dqattach_one(ip, xfs_get_projid(ip), XFS_DQ_PROJ, flags & XFS_QMOPT_DQALLOC, - ip->i_udquot, &ip->i_pdquot); - /* - * Don't worry about the udquot that we may have - * attached above. It'll get detached, if not already. - */ + &ip->i_pdquot); if (error) goto done; - nquotas++; + ASSERT(ip->i_pdquot); } +done: /* - * Attach this group/project quota to the user quota as a hint. - * This WON'T, in general, result in a thrash. + * Don't worry about the dquots that we may have attached before any + * error - they'll get detached later if it has not already been done. */ - if (nquotas > 1 && ip->i_udquot) { - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - ASSERT(ip->i_gdquot || !XFS_IS_GQUOTA_ON(mp)); - ASSERT(ip->i_pdquot || !XFS_IS_PQUOTA_ON(mp)); - - /* - * We do not have i_udquot locked at this point, but this check - * is OK since we don't depend on the i_gdquot to be accurate - * 100% all the time. It is just a hint, and this will - * succeed in general. - */ - if (ip->i_udquot->q_gdquot != ip->i_gdquot) - xfs_qm_dqattach_hint(ip, XFS_DQ_GROUP); - - if (ip->i_udquot->q_pdquot != ip->i_pdquot) - xfs_qm_dqattach_hint(ip, XFS_DQ_PROJ); - } - - done: -#ifdef DEBUG - if (!error) { - if (XFS_IS_UQUOTA_ON(mp)) - ASSERT(ip->i_udquot); - if (XFS_IS_GQUOTA_ON(mp)) - ASSERT(ip->i_gdquot); - if (XFS_IS_PQUOTA_ON(mp)) - ASSERT(ip->i_pdquot); - } ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); -#endif return error; } @@ -870,8 +698,7 @@ xfs_qm_init_quotainfo( /* Precalc some constants */ qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB); - qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(mp, - qinf->qi_dqchunklen); + qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(qinf->qi_dqchunklen); mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD); diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c index 3daf5ea1eb8d73..bbc813caba4c88 100644 --- a/fs/xfs/xfs_qm_syscalls.c +++ b/fs/xfs/xfs_qm_syscalls.c @@ -278,9 +278,10 @@ xfs_qm_scall_trunc_qfiles( xfs_mount_t *mp, uint flags) { - int error; + int error = EINVAL; - if (!xfs_sb_version_hasquota(&mp->m_sb) || flags == 0) { + if (!xfs_sb_version_hasquota(&mp->m_sb) || flags == 0 || + (flags & ~XFS_DQ_ALLTYPES)) { xfs_debug(mp, "%s: flags=%x m_qflags=%x", __func__, flags, mp->m_qflags); return XFS_ERROR(EINVAL); @@ -959,7 +960,6 @@ xfs_qm_export_flags( STATIC int xfs_dqrele_inode( struct xfs_inode *ip, - struct xfs_perag *pag, int flags, void *args) { diff --git a/fs/xfs/xfs_quota_defs.h b/fs/xfs/xfs_quota_defs.h index b3b2b1065c0f4d..137e20937077a0 100644 --- a/fs/xfs/xfs_quota_defs.h +++ b/fs/xfs/xfs_quota_defs.h @@ -156,6 +156,6 @@ typedef __uint16_t xfs_qwarncnt_t; extern int xfs_dqcheck(struct xfs_mount *mp, xfs_disk_dquot_t *ddq, xfs_dqid_t id, uint type, uint flags, char *str); -extern int xfs_calc_dquots_per_chunk(struct xfs_mount *mp, unsigned int nbblks); +extern int xfs_calc_dquots_per_chunk(unsigned int nbblks); #endif /* __XFS_QUOTA_H__ */ diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c index af33cafe69b641..2ad1b9822e92f5 100644 --- a/fs/xfs/xfs_quotaops.c +++ b/fs/xfs/xfs_quotaops.c @@ -100,15 +100,35 @@ xfs_fs_set_xstate( if (!XFS_IS_QUOTA_ON(mp)) return -EINVAL; return -xfs_qm_scall_quotaoff(mp, flags); - case Q_XQUOTARM: - if (XFS_IS_QUOTA_ON(mp)) - return -EINVAL; - return -xfs_qm_scall_trunc_qfiles(mp, flags); } return -EINVAL; } +STATIC int +xfs_fs_rm_xquota( + struct super_block *sb, + unsigned int uflags) +{ + struct xfs_mount *mp = XFS_M(sb); + unsigned int flags = 0; + + if (sb->s_flags & MS_RDONLY) + return -EROFS; + + if (XFS_IS_QUOTA_ON(mp)) + return -EINVAL; + + if (uflags & FS_USER_QUOTA) + flags |= XFS_DQ_USER; + if (uflags & FS_GROUP_QUOTA) + flags |= XFS_DQ_GROUP; + if (uflags & FS_USER_QUOTA) + flags |= XFS_DQ_PROJ; + + return -xfs_qm_scall_trunc_qfiles(mp, flags); +} + STATIC int xfs_fs_get_dqblk( struct super_block *sb, @@ -149,6 +169,7 @@ const struct quotactl_ops xfs_quotactl_operations = { .get_xstatev = xfs_fs_get_xstatev, .get_xstate = xfs_fs_get_xstate, .set_xstate = xfs_fs_set_xstate, + .rm_xquota = xfs_fs_rm_xquota, .get_dqblk = xfs_fs_get_dqblk, .set_dqblk = xfs_fs_set_dqblk, }; diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h index f7b2fe77c5a5bf..950d1ea058b236 100644 --- a/fs/xfs/xfs_sb.h +++ b/fs/xfs/xfs_sb.h @@ -587,7 +587,9 @@ xfs_sb_has_compat_feature( return (sbp->sb_features_compat & feature) != 0; } -#define XFS_SB_FEAT_RO_COMPAT_ALL 0 +#define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */ +#define XFS_SB_FEAT_RO_COMPAT_ALL \ + (XFS_SB_FEAT_RO_COMPAT_FINOBT) #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL static inline bool xfs_sb_has_ro_compat_feature( @@ -641,6 +643,12 @@ static inline int xfs_sb_version_hasftype(struct xfs_sb *sbp) (sbp->sb_features2 & XFS_SB_VERSION2_FTYPE)); } +static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp) +{ + return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) && + (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_FINOBT); +} + /* * end of superblock version macros */ diff --git a/fs/xfs/xfs_shared.h b/fs/xfs/xfs_shared.h index 4484e515139507..82404da2ca6747 100644 --- a/fs/xfs/xfs_shared.h +++ b/fs/xfs/xfs_shared.h @@ -238,7 +238,7 @@ int xfs_log_calc_minimum_size(struct xfs_mount *); int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen); int xfs_symlink_hdr_set(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset, uint32_t size, struct xfs_buf *bp); -bool xfs_symlink_hdr_ok(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset, +bool xfs_symlink_hdr_ok(xfs_ino_t ino, uint32_t offset, uint32_t size, struct xfs_buf *bp); void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp, struct xfs_inode *ip, struct xfs_ifork *ifp); diff --git a/fs/xfs/xfs_stats.c b/fs/xfs/xfs_stats.c index ce372b7d564460..f2240383d4bba7 100644 --- a/fs/xfs/xfs_stats.c +++ b/fs/xfs/xfs_stats.c @@ -59,6 +59,7 @@ static int xfs_stat_proc_show(struct seq_file *m, void *v) { "abtc2", XFSSTAT_END_ABTC_V2 }, { "bmbt2", XFSSTAT_END_BMBT_V2 }, { "ibt2", XFSSTAT_END_IBT_V2 }, + { "fibt2", XFSSTAT_END_FIBT_V2 }, /* we print both series of quota information together */ { "qm", XFSSTAT_END_QM }, }; diff --git a/fs/xfs/xfs_stats.h b/fs/xfs/xfs_stats.h index c03ad38ceaebae..c8f238b8299a1b 100644 --- a/fs/xfs/xfs_stats.h +++ b/fs/xfs/xfs_stats.h @@ -183,7 +183,23 @@ struct xfsstats { __uint32_t xs_ibt_2_alloc; __uint32_t xs_ibt_2_free; __uint32_t xs_ibt_2_moves; -#define XFSSTAT_END_XQMSTAT (XFSSTAT_END_IBT_V2+6) +#define XFSSTAT_END_FIBT_V2 (XFSSTAT_END_IBT_V2+15) + __uint32_t xs_fibt_2_lookup; + __uint32_t xs_fibt_2_compare; + __uint32_t xs_fibt_2_insrec; + __uint32_t xs_fibt_2_delrec; + __uint32_t xs_fibt_2_newroot; + __uint32_t xs_fibt_2_killroot; + __uint32_t xs_fibt_2_increment; + __uint32_t xs_fibt_2_decrement; + __uint32_t xs_fibt_2_lshift; + __uint32_t xs_fibt_2_rshift; + __uint32_t xs_fibt_2_split; + __uint32_t xs_fibt_2_join; + __uint32_t xs_fibt_2_alloc; + __uint32_t xs_fibt_2_free; + __uint32_t xs_fibt_2_moves; +#define XFSSTAT_END_XQMSTAT (XFSSTAT_END_FIBT_V2+6) __uint32_t xs_qm_dqreclaims; __uint32_t xs_qm_dqreclaim_misses; __uint32_t xs_qm_dquot_dups; diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 2053767763773b..ac24372a607f60 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -765,20 +765,18 @@ xfs_open_devices( * Setup xfs_mount buffer target pointers */ error = ENOMEM; - mp->m_ddev_targp = xfs_alloc_buftarg(mp, ddev, 0, mp->m_fsname); + mp->m_ddev_targp = xfs_alloc_buftarg(mp, ddev); if (!mp->m_ddev_targp) goto out_close_rtdev; if (rtdev) { - mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev, 1, - mp->m_fsname); + mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev); if (!mp->m_rtdev_targp) goto out_free_ddev_targ; } if (logdev && logdev != ddev) { - mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev, 1, - mp->m_fsname); + mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev); if (!mp->m_logdev_targp) goto out_free_rtdev_targ; } else { @@ -811,8 +809,7 @@ xfs_setup_devices( { int error; - error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_blocksize, - mp->m_sb.sb_sectsize); + error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_sectsize); if (error) return error; @@ -822,14 +819,12 @@ xfs_setup_devices( if (xfs_sb_version_hassector(&mp->m_sb)) log_sector_size = mp->m_sb.sb_logsectsize; error = xfs_setsize_buftarg(mp->m_logdev_targp, - mp->m_sb.sb_blocksize, log_sector_size); if (error) return error; } if (mp->m_rtdev_targp) { error = xfs_setsize_buftarg(mp->m_rtdev_targp, - mp->m_sb.sb_blocksize, mp->m_sb.sb_sectsize); if (error) return error; @@ -1754,13 +1749,9 @@ init_xfs_fs(void) if (error) goto out_destroy_wq; - error = xfs_filestream_init(); - if (error) - goto out_mru_cache_uninit; - error = xfs_buf_init(); if (error) - goto out_filestream_uninit; + goto out_mru_cache_uninit; error = xfs_init_procfs(); if (error) @@ -1787,8 +1778,6 @@ init_xfs_fs(void) xfs_cleanup_procfs(); out_buf_terminate: xfs_buf_terminate(); - out_filestream_uninit: - xfs_filestream_uninit(); out_mru_cache_uninit: xfs_mru_cache_uninit(); out_destroy_wq: @@ -1807,7 +1796,6 @@ exit_xfs_fs(void) xfs_sysctl_unregister(); xfs_cleanup_procfs(); xfs_buf_terminate(); - xfs_filestream_uninit(); xfs_mru_cache_uninit(); xfs_destroy_workqueues(); xfs_destroy_zones(); diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index 52979aa90986ca..0816b4018dfcd7 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c @@ -92,7 +92,7 @@ xfs_readlink_bmap( cur_chunk = bp->b_addr; if (xfs_sb_version_hascrc(&mp->m_sb)) { - if (!xfs_symlink_hdr_ok(mp, ip->i_ino, offset, + if (!xfs_symlink_hdr_ok(ip->i_ino, offset, byte_cnt, bp)) { error = EFSCORRUPTED; xfs_alert(mp, diff --git a/fs/xfs/xfs_symlink_remote.c b/fs/xfs/xfs_symlink_remote.c index 9b32052ff65e77..23c2f2577c8d75 100644 --- a/fs/xfs/xfs_symlink_remote.c +++ b/fs/xfs/xfs_symlink_remote.c @@ -80,7 +80,6 @@ xfs_symlink_hdr_set( */ bool xfs_symlink_hdr_ok( - struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset, uint32_t size, diff --git a/fs/xfs/xfs_trace.c b/fs/xfs/xfs_trace.c index dee3279c095e6a..1e85bcd0e41862 100644 --- a/fs/xfs/xfs_trace.c +++ b/fs/xfs/xfs_trace.c @@ -46,6 +46,7 @@ #include "xfs_log_recover.h" #include "xfs_inode_item.h" #include "xfs_bmap_btree.h" +#include "xfs_filestream.h" /* * We include this last to have the helpers above available for the trace diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 65d8c793a25cb1..152f8278263022 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -538,6 +538,64 @@ DEFINE_BUF_ITEM_EVENT(xfs_trans_bhold_release); DEFINE_BUF_ITEM_EVENT(xfs_trans_binval); DEFINE_BUF_ITEM_EVENT(xfs_trans_buf_ordered); +DECLARE_EVENT_CLASS(xfs_filestream_class, + TP_PROTO(struct xfs_inode *ip, xfs_agnumber_t agno), + TP_ARGS(ip, agno), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(xfs_agnumber_t, agno) + __field(int, streams) + ), + TP_fast_assign( + __entry->dev = VFS_I(ip)->i_sb->s_dev; + __entry->ino = ip->i_ino; + __entry->agno = agno; + __entry->streams = xfs_filestream_peek_ag(ip->i_mount, agno); + ), + TP_printk("dev %d:%d ino 0x%llx agno %u streams %d", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __entry->agno, + __entry->streams) +) +#define DEFINE_FILESTREAM_EVENT(name) \ +DEFINE_EVENT(xfs_filestream_class, name, \ + TP_PROTO(struct xfs_inode *ip, xfs_agnumber_t agno), \ + TP_ARGS(ip, agno)) +DEFINE_FILESTREAM_EVENT(xfs_filestream_free); +DEFINE_FILESTREAM_EVENT(xfs_filestream_lookup); +DEFINE_FILESTREAM_EVENT(xfs_filestream_scan); + +TRACE_EVENT(xfs_filestream_pick, + TP_PROTO(struct xfs_inode *ip, xfs_agnumber_t agno, + xfs_extlen_t free, int nscan), + TP_ARGS(ip, agno, free, nscan), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(xfs_agnumber_t, agno) + __field(int, streams) + __field(xfs_extlen_t, free) + __field(int, nscan) + ), + TP_fast_assign( + __entry->dev = VFS_I(ip)->i_sb->s_dev; + __entry->ino = ip->i_ino; + __entry->agno = agno; + __entry->streams = xfs_filestream_peek_ag(ip->i_mount, agno); + __entry->free = free; + __entry->nscan = nscan; + ), + TP_printk("dev %d:%d ino 0x%llx agno %u streams %d free %d nscan %d", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __entry->agno, + __entry->streams, + __entry->free, + __entry->nscan) +); + DECLARE_EVENT_CLASS(xfs_lock_class, TP_PROTO(struct xfs_inode *ip, unsigned lock_flags, unsigned long caller_ip), @@ -1060,7 +1118,6 @@ DEFINE_RW_EVENT(xfs_file_read); DEFINE_RW_EVENT(xfs_file_buffered_write); DEFINE_RW_EVENT(xfs_file_direct_write); DEFINE_RW_EVENT(xfs_file_splice_read); -DEFINE_RW_EVENT(xfs_file_splice_write); DECLARE_EVENT_CLASS(xfs_page_class, TP_PROTO(struct inode *inode, struct page *page, unsigned long off, diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 54a57326d85b1e..d03932564ccb3a 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -827,7 +827,7 @@ xfs_trans_committed_bulk( xfs_log_item_batch_insert(ailp, &cur, log_items, i, commit_lsn); spin_lock(&ailp->xa_lock); - xfs_trans_ail_cursor_done(ailp, &cur); + xfs_trans_ail_cursor_done(&cur); spin_unlock(&ailp->xa_lock); } diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index a7287354e53534..cb0f3a84cc6845 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -173,7 +173,6 @@ xfs_trans_ail_cursor_next( */ void xfs_trans_ail_cursor_done( - struct xfs_ail *ailp, struct xfs_ail_cursor *cur) { cur->item = NULL; @@ -368,7 +367,7 @@ xfsaild_push( * If the AIL is empty or our push has reached the end we are * done now. */ - xfs_trans_ail_cursor_done(ailp, &cur); + xfs_trans_ail_cursor_done(&cur); spin_unlock(&ailp->xa_lock); goto out_done; } @@ -453,7 +452,7 @@ xfsaild_push( break; lsn = lip->li_lsn; } - xfs_trans_ail_cursor_done(ailp, &cur); + xfs_trans_ail_cursor_done(&cur); spin_unlock(&ailp->xa_lock); if (xfs_buf_delwri_submit_nowait(&ailp->xa_buf_list)) diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h index 12e86af9d9b943..bd1281862ad795 100644 --- a/fs/xfs/xfs_trans_priv.h +++ b/fs/xfs/xfs_trans_priv.h @@ -133,8 +133,7 @@ struct xfs_log_item * xfs_trans_ail_cursor_last(struct xfs_ail *ailp, xfs_lsn_t lsn); struct xfs_log_item * xfs_trans_ail_cursor_next(struct xfs_ail *ailp, struct xfs_ail_cursor *cur); -void xfs_trans_ail_cursor_done(struct xfs_ail *ailp, - struct xfs_ail_cursor *cur); +void xfs_trans_ail_cursor_done(struct xfs_ail_cursor *cur); #if BITS_PER_LONG != 64 static inline void diff --git a/fs/xfs/xfs_trans_resv.c b/fs/xfs/xfs_trans_resv.c index ae368165244d49..52b6c3e3203e16 100644 --- a/fs/xfs/xfs_trans_resv.c +++ b/fs/xfs/xfs_trans_resv.c @@ -105,6 +105,47 @@ xfs_calc_inode_res( 2 * XFS_BMBT_BLOCK_LEN(mp)); } +/* + * The free inode btree is a conditional feature and the log reservation + * requirements differ slightly from that of the traditional inode allocation + * btree. The finobt tracks records for inode chunks with at least one free + * inode. A record can be removed from the tree for an inode allocation + * or free and thus the finobt reservation is unconditional across: + * + * - inode allocation + * - inode free + * - inode chunk allocation + * + * The 'modify' param indicates to include the record modification scenario. The + * 'alloc' param indicates to include the reservation for free space btree + * modifications on behalf of finobt modifications. This is required only for + * transactions that do not already account for free space btree modifications. + * + * the free inode btree: max depth * block size + * the allocation btrees: 2 trees * (max depth - 1) * block size + * the free inode btree entry: block size + */ +STATIC uint +xfs_calc_finobt_res( + struct xfs_mount *mp, + int alloc, + int modify) +{ + uint res; + + if (!xfs_sb_version_hasfinobt(&mp->m_sb)) + return 0; + + res = xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)); + if (alloc) + res += xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), + XFS_FSB_TO_B(mp, 1)); + if (modify) + res += (uint)XFS_FSB_TO_B(mp, 1); + + return res; +} + /* * Various log reservation values. * @@ -302,6 +343,7 @@ xfs_calc_remove_reservation( * the superblock for the nlink flag: sector size * the directory btree: (max depth + v2) * dir block size * the directory inode's bmap btree: (max depth + v2) * block size + * the finobt (record modification and allocation btrees) */ STATIC uint xfs_calc_create_resv_modify( @@ -310,7 +352,8 @@ xfs_calc_create_resv_modify( return xfs_calc_inode_res(mp, 2) + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + (uint)XFS_FSB_TO_B(mp, 1) + - xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)); + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)) + + xfs_calc_finobt_res(mp, 1, 1); } /* @@ -348,6 +391,7 @@ __xfs_calc_create_reservation( * the superblock for the nlink flag: sector size * the inode btree: max depth * blocksize * the allocation btrees: 2 trees * (max depth - 1) * block size + * the finobt (record insertion) */ STATIC uint xfs_calc_icreate_resv_alloc( @@ -357,7 +401,8 @@ xfs_calc_icreate_resv_alloc( mp->m_sb.sb_sectsize + xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), - XFS_FSB_TO_B(mp, 1)); + XFS_FSB_TO_B(mp, 1)) + + xfs_calc_finobt_res(mp, 0, 0); } STATIC uint @@ -425,6 +470,7 @@ xfs_calc_symlink_reservation( * the on disk inode before ours in the agi hash list: inode cluster size * the inode btree: max depth * blocksize * the allocation btrees: 2 trees * (max depth - 1) * block size + * the finobt (record insertion, removal or modification) */ STATIC uint xfs_calc_ifree_reservation( @@ -439,7 +485,8 @@ xfs_calc_ifree_reservation( xfs_calc_buf_res(2 + mp->m_ialloc_blks + mp->m_in_maxlevels, 0) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), - XFS_FSB_TO_B(mp, 1)); + XFS_FSB_TO_B(mp, 1)) + + xfs_calc_finobt_res(mp, 0, 1); } /* diff --git a/fs/xfs/xfs_trans_space.h b/fs/xfs/xfs_trans_space.h index af5dbe06cb6588..df4c1f81884cbd 100644 --- a/fs/xfs/xfs_trans_space.h +++ b/fs/xfs/xfs_trans_space.h @@ -47,7 +47,9 @@ #define XFS_DIRREMOVE_SPACE_RES(mp) \ XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK) #define XFS_IALLOC_SPACE_RES(mp) \ - ((mp)->m_ialloc_blks + (mp)->m_in_maxlevels - 1) + ((mp)->m_ialloc_blks + \ + (xfs_sb_version_hasfinobt(&mp->m_sb) ? 2 : 1 * \ + ((mp)->m_in_maxlevels - 1))) /* * Space reservation values for various transactions. @@ -82,5 +84,8 @@ (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) +#define XFS_IFREE_SPACE_RES(mp) \ + (xfs_sb_version_hasfinobt(&mp->m_sb) ? (mp)->m_in_maxlevels : 0) + #endif /* __XFS_TRANS_SPACE_H__ */ diff --git a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h index 82bbc34d54a3b3..65c6e6650b1a5e 100644 --- a/fs/xfs/xfs_types.h +++ b/fs/xfs/xfs_types.h @@ -134,7 +134,7 @@ typedef enum { typedef enum { XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi, - XFS_BTNUM_MAX + XFS_BTNUM_FINOi, XFS_BTNUM_MAX } xfs_btnum_t; struct xfs_name { diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index 3dd6e838dc300b..f0e713fadb1f5a 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -55,6 +55,7 @@ #define METHOD_NAME__HID "_HID" #define METHOD_NAME__INI "_INI" #define METHOD_NAME__PLD "_PLD" +#define METHOD_NAME__PRP "_PRP" #define METHOD_NAME__PRS "_PRS" #define METHOD_NAME__PRT "_PRT" #define METHOD_NAME__PRW "_PRW" diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index d504613bbf8081..ea6428b7dacb69 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -96,7 +96,12 @@ struct pci_dev *acpi_get_pci_dev(acpi_handle); /* Arch-defined function to add a bus to the system */ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root); + +#ifdef CONFIG_X86 void pci_acpi_crs_quirks(void); +#else +static inline void pci_acpi_crs_quirks(void) { } +#endif /* -------------------------------------------------------------------------- Processor diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 44f5e974960150..4e3044ca48552b 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20140214 +#define ACPI_CA_VERSION 0x20140424 #include #include @@ -55,233 +55,469 @@ extern u8 acpi_gbl_permanent_mmap; +/***************************************************************************** + * + * Macros used for ACPICA globals and configuration + * + ****************************************************************************/ + /* - * Globals that are publically available + * Ensure that global variables are defined and initialized only once. + * + * The use of these macros allows for a single list of globals (here) + * in order to simplify maintenance of the code. */ -extern u32 acpi_current_gpe_count; -extern struct acpi_table_fadt acpi_gbl_FADT; -extern u8 acpi_gbl_system_awake_and_running; -extern u8 acpi_gbl_reduced_hardware; /* ACPI 5.0 */ -extern u8 acpi_gbl_osi_data; +#ifdef DEFINE_ACPI_GLOBALS +#define ACPI_GLOBAL(type,name) \ + extern type name; \ + type name -/* Runtime configuration of debug print levels */ +#define ACPI_INIT_GLOBAL(type,name,value) \ + type name=value -extern u32 acpi_dbg_level; -extern u32 acpi_dbg_layer; - -/* ACPICA runtime options */ +#else +#ifndef ACPI_GLOBAL +#define ACPI_GLOBAL(type,name) \ + extern type name +#endif -extern u8 acpi_gbl_auto_serialize_methods; -extern u8 acpi_gbl_copy_dsdt_locally; -extern u8 acpi_gbl_create_osi_method; -extern u8 acpi_gbl_disable_auto_repair; -extern u8 acpi_gbl_disable_ssdt_table_load; -extern u8 acpi_gbl_do_not_use_xsdt; -extern u8 acpi_gbl_enable_aml_debug_object; -extern u8 acpi_gbl_enable_interpreter_slack; -extern u32 acpi_gbl_trace_flags; -extern acpi_name acpi_gbl_trace_method_name; -extern u8 acpi_gbl_truncate_io_addresses; -extern u8 acpi_gbl_use32_bit_fadt_addresses; -extern u8 acpi_gbl_use_default_register_widths; +#ifndef ACPI_INIT_GLOBAL +#define ACPI_INIT_GLOBAL(type,name,value) \ + extern type name +#endif +#endif /* - * Hardware-reduced prototypes. All interfaces that use these macros will - * be configured out of the ACPICA build if the ACPI_REDUCED_HARDWARE flag - * is set to TRUE. + * These macros configure the various ACPICA interfaces. They are + * useful for generating stub inline functions for features that are + * configured out of the current kernel or ACPICA application. */ -#if (!ACPI_REDUCED_HARDWARE) -#define ACPI_HW_DEPENDENT_RETURN_STATUS(prototype) \ +#ifndef ACPI_EXTERNAL_RETURN_STATUS +#define ACPI_EXTERNAL_RETURN_STATUS(prototype) \ prototype; +#endif -#define ACPI_HW_DEPENDENT_RETURN_OK(prototype) \ +#ifndef ACPI_EXTERNAL_RETURN_OK +#define ACPI_EXTERNAL_RETURN_OK(prototype) \ prototype; +#endif -#define ACPI_HW_DEPENDENT_RETURN_VOID(prototype) \ +#ifndef ACPI_EXTERNAL_RETURN_VOID +#define ACPI_EXTERNAL_RETURN_VOID(prototype) \ prototype; +#endif -#else -#define ACPI_HW_DEPENDENT_RETURN_STATUS(prototype) \ - static ACPI_INLINE prototype {return(AE_NOT_CONFIGURED);} - -#define ACPI_HW_DEPENDENT_RETURN_OK(prototype) \ - static ACPI_INLINE prototype {return(AE_OK);} +#ifndef ACPI_EXTERNAL_RETURN_UINT32 +#define ACPI_EXTERNAL_RETURN_UINT32(prototype) \ + prototype; +#endif -#define ACPI_HW_DEPENDENT_RETURN_VOID(prototype) \ - static ACPI_INLINE prototype {return;} +#ifndef ACPI_EXTERNAL_RETURN_PTR +#define ACPI_EXTERNAL_RETURN_PTR(prototype) \ + prototype; +#endif -#endif /* !ACPI_REDUCED_HARDWARE */ +/***************************************************************************** + * + * Public globals and runtime configuration options + * + ****************************************************************************/ /* - * Initialization + * Enable "slack mode" of the AML interpreter? Default is FALSE, and the + * interpreter strictly follows the ACPI specification. Setting to TRUE + * allows the interpreter to ignore certain errors and/or bad AML constructs. + * + * Currently, these features are enabled by this flag: + * + * 1) Allow "implicit return" of last value in a control method + * 2) Allow access beyond the end of an operation region + * 3) Allow access to uninitialized locals/args (auto-init to integer 0) + * 4) Allow ANY object type to be a source operand for the Store() operator + * 5) Allow unresolved references (invalid target name) in package objects + * 6) Enable warning messages for behavior that is not ACPI spec compliant */ -acpi_status __init -acpi_initialize_tables(struct acpi_table_desc *initial_storage, - u32 initial_table_count, u8 allow_resize); - -acpi_status __init acpi_initialize_subsystem(void); - -acpi_status __init acpi_enable_subsystem(u32 flags); +ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE); -acpi_status __init acpi_initialize_objects(u32 flags); - -acpi_status __init acpi_terminate(void); +/* + * Automatically serialize all methods that create named objects? Default + * is TRUE, meaning that all non_serialized methods are scanned once at + * table load time to determine those that create named objects. Methods + * that create named objects are marked Serialized in order to prevent + * possible run-time problems if they are entered by more than one thread. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, TRUE); /* - * Miscellaneous global interfaces + * Create the predefined _OSI method in the namespace? Default is TRUE + * because ACPICA is fully compatible with other ACPI implementations. + * Changing this will revert ACPICA (and machine ASL) to pre-OSI behavior. */ -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable(void)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable(void)) -#ifdef ACPI_FUTURE_USAGE -acpi_status acpi_subsystem_status(void); -#endif +ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE); -#ifdef ACPI_FUTURE_USAGE -acpi_status acpi_get_system_info(struct acpi_buffer *ret_buffer); -#endif +/* + * Optionally use default values for the ACPI register widths. Set this to + * TRUE to use the defaults, if an FADT contains incorrect widths/lengths. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_use_default_register_widths, TRUE); -acpi_status acpi_get_statistics(struct acpi_statistics *stats); +/* + * Optionally enable output from the AML Debug Object. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_aml_debug_object, FALSE); -const char *acpi_format_exception(acpi_status exception); +/* + * Optionally copy the entire DSDT to local memory (instead of simply + * mapping it.) There are some BIOSs that corrupt or replace the original + * DSDT, creating the need for this option. Default is FALSE, do not copy + * the DSDT. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_copy_dsdt_locally, FALSE); -acpi_status acpi_purge_cached_objects(void); +/* + * Optionally ignore an XSDT if present and use the RSDT instead. + * Although the ACPI specification requires that an XSDT be used instead + * of the RSDT, the XSDT has been found to be corrupt or ill-formed on + * some machines. Default behavior is to use the XSDT if present. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE); -acpi_status acpi_install_interface(acpi_string interface_name); +/* + * Optionally use 32-bit FADT addresses if and when there is a conflict + * (address mismatch) between the 32-bit and 64-bit versions of the + * address. Although ACPICA adheres to the ACPI specification which + * requires the use of the corresponding 64-bit address if it is non-zero, + * some machines have been found to have a corrupted non-zero 64-bit + * address. Default is FALSE, do not favor the 32-bit addresses. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, FALSE); -acpi_status acpi_remove_interface(acpi_string interface_name); +/* + * Optionally truncate I/O addresses to 16 bits. Provides compatibility + * with other ACPI implementations. NOTE: During ACPICA initialization, + * this value is set to TRUE if any Windows OSI strings have been + * requested by the BIOS. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_truncate_io_addresses, FALSE); -acpi_status acpi_update_interfaces(u8 action); +/* + * Disable runtime checking and repair of values returned by control methods. + * Use only if the repair is causing a problem on a particular machine. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE); -u32 -acpi_check_address_range(acpi_adr_space_type space_id, - acpi_physical_address address, - acpi_size length, u8 warn); +/* + * Optionally do not install any SSDTs from the RSDT/XSDT during initialization. + * This can be useful for debugging ACPI problems on some machines. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_install, FALSE); -acpi_status -acpi_decode_pld_buffer(u8 *in_buffer, - acpi_size length, struct acpi_pld_info **return_buffer); +/* + * We keep track of the latest version of Windows that has been requested by + * the BIOS. ACPI 5.0. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0); /* - * ACPI table load/unload interfaces + * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning + * that the ACPI hardware is no longer required. A flag in the FADT indicates + * a reduced HW machine, and that flag is duplicated here for convenience. */ -acpi_status acpi_load_table(struct acpi_table_header *table); +ACPI_INIT_GLOBAL(u8, acpi_gbl_reduced_hardware, FALSE); -acpi_status acpi_unload_parent_table(acpi_handle object); +/* + * This mechanism is used to trace a specified AML method. The method is + * traced each time it is executed. + */ +ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_flags, 0); +ACPI_INIT_GLOBAL(acpi_name, acpi_gbl_trace_method_name, 0); -acpi_status __init acpi_load_tables(void); +/* + * Runtime configuration of debug output control masks. We want the debug + * switches statically initialized so they are already set when the debugger + * is entered. + */ +ACPI_INIT_GLOBAL(u32, acpi_dbg_level, ACPI_DEBUG_DEFAULT); +ACPI_INIT_GLOBAL(u32, acpi_dbg_layer, 0); /* - * ACPI table manipulation interfaces + * Other miscellaneous globals */ -acpi_status __init acpi_reallocate_root_table(void); +ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT); +ACPI_GLOBAL(u32, acpi_current_gpe_count); +ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); -acpi_status __init acpi_find_root_pointer(acpi_size *rsdp_address); +/***************************************************************************** + * + * ACPICA public interface configuration. + * + * Interfaces that are configured out of the ACPICA build are replaced + * by inlined stubs by default. + * + ****************************************************************************/ -acpi_status acpi_unload_table_id(acpi_owner_id id); +/* + * Hardware-reduced prototypes (default: Not hardware reduced). + * + * All ACPICA hardware-related interfaces that use these macros will be + * configured out of the ACPICA build if the ACPI_REDUCED_HARDWARE flag + * is set to TRUE. + * + * Note: This static build option for reduced hardware is intended to + * reduce ACPICA code size if desired or necessary. However, even if this + * option is not specified, the runtime behavior of ACPICA is dependent + * on the actual FADT reduced hardware flag (HW_REDUCED_ACPI). If set, + * the flag will enable similar behavior -- ACPICA will not attempt + * to access any ACPI-relate hardware (SCI, GPEs, Fixed Events, etc.) + */ +#if (!ACPI_REDUCED_HARDWARE) +#define ACPI_HW_DEPENDENT_RETURN_STATUS(prototype) \ + ACPI_EXTERNAL_RETURN_STATUS(prototype) -acpi_status -acpi_get_table_header(acpi_string signature, - u32 instance, struct acpi_table_header *out_table_header); +#define ACPI_HW_DEPENDENT_RETURN_OK(prototype) \ + ACPI_EXTERNAL_RETURN_OK(prototype) -acpi_status -acpi_get_table_with_size(acpi_string signature, - u32 instance, struct acpi_table_header **out_table, - acpi_size *tbl_size); +#define ACPI_HW_DEPENDENT_RETURN_VOID(prototype) \ + ACPI_EXTERNAL_RETURN_VOID(prototype) -acpi_status -acpi_get_table(acpi_string signature, - u32 instance, struct acpi_table_header **out_table); +#else +#define ACPI_HW_DEPENDENT_RETURN_STATUS(prototype) \ + static ACPI_INLINE prototype {return(AE_NOT_CONFIGURED);} -acpi_status -acpi_get_table_by_index(u32 table_index, struct acpi_table_header **out_table); +#define ACPI_HW_DEPENDENT_RETURN_OK(prototype) \ + static ACPI_INLINE prototype {return(AE_OK);} -acpi_status -acpi_install_table_handler(acpi_table_handler handler, void *context); +#define ACPI_HW_DEPENDENT_RETURN_VOID(prototype) \ + static ACPI_INLINE prototype {return;} -acpi_status acpi_remove_table_handler(acpi_table_handler handler); +#endif /* !ACPI_REDUCED_HARDWARE */ /* - * Namespace and name interfaces + * Error message prototypes (default: error messages enabled). + * + * All interfaces related to error and warning messages + * will be configured out of the ACPICA build if the + * ACPI_NO_ERROR_MESSAGE flag is defined. */ -acpi_status -acpi_walk_namespace(acpi_object_type type, - acpi_handle start_object, - u32 max_depth, - acpi_walk_callback descending_callback, - acpi_walk_callback ascending_callback, - void *context, void **return_value); +#ifndef ACPI_NO_ERROR_MESSAGES +#define ACPI_MSG_DEPENDENT_RETURN_VOID(prototype) \ + prototype; -acpi_status -acpi_get_devices(const char *HID, - acpi_walk_callback user_function, - void *context, void **return_value); +#else +#define ACPI_MSG_DEPENDENT_RETURN_VOID(prototype) \ + static ACPI_INLINE prototype {return;} -acpi_status -acpi_get_name(acpi_handle object, - u32 name_type, struct acpi_buffer *ret_path_ptr); +#endif /* ACPI_NO_ERROR_MESSAGES */ -acpi_status -acpi_get_handle(acpi_handle parent, - acpi_string pathname, acpi_handle * ret_handle); +/* + * Debugging output prototypes (default: no debug output). + * + * All interfaces related to debug output messages + * will be configured out of the ACPICA build unless the + * ACPI_DEBUG_OUTPUT flag is defined. + */ +#ifdef ACPI_DEBUG_OUTPUT +#define ACPI_DBG_DEPENDENT_RETURN_VOID(prototype) \ + prototype; -acpi_status -acpi_attach_data(acpi_handle object, acpi_object_handler handler, void *data); +#else +#define ACPI_DBG_DEPENDENT_RETURN_VOID(prototype) \ + static ACPI_INLINE prototype {return;} -acpi_status acpi_detach_data(acpi_handle object, acpi_object_handler handler); +#endif /* ACPI_DEBUG_OUTPUT */ -acpi_status -acpi_get_data_full(acpi_handle object, acpi_object_handler handler, void **data, - void (*callback)(void *)); +/***************************************************************************** + * + * ACPICA public interface prototypes + * + ****************************************************************************/ -acpi_status -acpi_get_data(acpi_handle object, acpi_object_handler handler, void **data); +/* + * Initialization + */ +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init + acpi_initialize_tables(struct acpi_table_desc + *initial_storage, + u32 initial_table_count, + u8 allow_resize)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_initialize_subsystem(void)) -acpi_status -acpi_debug_trace(char *name, u32 debug_level, u32 debug_layer, u32 flags); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_enable_subsystem(u32 flags)) + +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init + acpi_initialize_objects(u32 flags)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_terminate(void)) /* - * Object manipulation and enumeration + * Miscellaneous global interfaces */ -acpi_status -acpi_evaluate_object(acpi_handle object, - acpi_string pathname, - struct acpi_object_list *parameter_objects, - struct acpi_buffer *return_object_buffer); +ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable(void)) +ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable(void)) +#ifdef ACPI_FUTURE_USAGE +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_subsystem_status(void)) +#endif -acpi_status -acpi_evaluate_object_typed(acpi_handle object, - acpi_string pathname, - struct acpi_object_list *external_params, - struct acpi_buffer *return_buffer, - acpi_object_type return_type); +#ifdef ACPI_FUTURE_USAGE +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_system_info(struct acpi_buffer + *ret_buffer)) +#endif +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_statistics(struct acpi_statistics *stats)) +ACPI_EXTERNAL_RETURN_PTR(const char + *acpi_format_exception(acpi_status exception)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_purge_cached_objects(void)) + +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_interface(acpi_string interface_name)) + +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_remove_interface(acpi_string interface_name)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_update_interfaces(u8 action)) + +ACPI_EXTERNAL_RETURN_UINT32(u32 + acpi_check_address_range(acpi_adr_space_type + space_id, + acpi_physical_address + address, acpi_size length, + u8 warn)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_decode_pld_buffer(u8 *in_buffer, + acpi_size length, + struct acpi_pld_info + **return_buffer)) -acpi_status -acpi_get_object_info(acpi_handle object, - struct acpi_device_info **return_buffer); +/* + * ACPI table load/unload interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init + acpi_install_table(acpi_physical_address address, + u8 physical)) -acpi_status acpi_install_method(u8 *buffer); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_load_table(struct acpi_table_header *table)) -acpi_status -acpi_get_next_object(acpi_object_type type, - acpi_handle parent, - acpi_handle child, acpi_handle * out_handle); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_unload_parent_table(acpi_handle object)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_load_tables(void)) -acpi_status acpi_get_type(acpi_handle object, acpi_object_type * out_type); +/* + * ACPI table manipulation interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_reallocate_root_table(void)) + +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init + acpi_find_root_pointer(acpi_size * rsdp_address)) + +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_table_header(acpi_string signature, + u32 instance, + struct acpi_table_header + *out_table_header)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_table(acpi_string signature, u32 instance, + struct acpi_table_header + **out_table)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_table_by_index(u32 table_index, + struct acpi_table_header + **out_table)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_table_handler(acpi_table_handler + handler, void *context)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_remove_table_handler(acpi_table_handler + handler)) -acpi_status acpi_get_id(acpi_handle object, acpi_owner_id * out_type); +/* + * Namespace and name interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_walk_namespace(acpi_object_type type, + acpi_handle start_object, + u32 max_depth, + acpi_walk_callback + descending_callback, + acpi_walk_callback + ascending_callback, + void *context, + void **return_value)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_devices(const char *HID, + acpi_walk_callback user_function, + void *context, + void **return_value)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_name(acpi_handle object, u32 name_type, + struct acpi_buffer *ret_path_ptr)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_handle(acpi_handle parent, + acpi_string pathname, + acpi_handle * ret_handle)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_attach_data(acpi_handle object, + acpi_object_handler handler, + void *data)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_detach_data(acpi_handle object, + acpi_object_handler handler)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_data(acpi_handle object, + acpi_object_handler handler, + void **data)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_debug_trace(char *name, u32 debug_level, + u32 debug_layer, u32 flags)) -acpi_status acpi_get_parent(acpi_handle object, acpi_handle * out_handle); +/* + * Object manipulation and enumeration + */ +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_evaluate_object(acpi_handle object, + acpi_string pathname, + struct acpi_object_list + *parameter_objects, + struct acpi_buffer + *return_object_buffer)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_evaluate_object_typed(acpi_handle object, + acpi_string pathname, + struct acpi_object_list + *external_params, + struct acpi_buffer + *return_buffer, + acpi_object_type + return_type)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_object_info(acpi_handle object, + struct acpi_device_info + **return_buffer)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_install_method(u8 *buffer)) + +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_next_object(acpi_object_type type, + acpi_handle parent, + acpi_handle child, + acpi_handle * out_handle)) + +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_type(acpi_handle object, + acpi_object_type * out_type)) + +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_parent(acpi_handle object, + acpi_handle * out_handle)) /* * Handler interfaces */ -acpi_status -acpi_install_initialization_handler(acpi_init_handler handler, u32 function); - +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_initialization_handler + (acpi_init_handler handler, u32 function)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_install_sci_handler(acpi_sci_handler - address, - void *context)) + acpi_install_sci_handler(acpi_sci_handler + address, + void *context)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_remove_sci_handler(acpi_sci_handler address)) @@ -313,30 +549,42 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status u32 gpe_number, acpi_gpe_handler address)) -acpi_status acpi_install_notify_handler(acpi_handle device, u32 handler_type, - acpi_notify_handler handler, - void *context); - -acpi_status -acpi_remove_notify_handler(acpi_handle device, - u32 handler_type, acpi_notify_handler handler); - -acpi_status -acpi_install_address_space_handler(acpi_handle device, - acpi_adr_space_type space_id, - acpi_adr_space_handler handler, - acpi_adr_space_setup setup, void *context); - -acpi_status -acpi_remove_address_space_handler(acpi_handle device, - acpi_adr_space_type space_id, - acpi_adr_space_handler handler); - +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_notify_handler(acpi_handle device, + u32 handler_type, + acpi_notify_handler + handler, + void *context)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_remove_notify_handler(acpi_handle device, + u32 handler_type, + acpi_notify_handler + handler)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_address_space_handler(acpi_handle + device, + acpi_adr_space_type + space_id, + acpi_adr_space_handler + handler, + acpi_adr_space_setup + setup, + void *context)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_remove_address_space_handler(acpi_handle + device, + acpi_adr_space_type + space_id, + acpi_adr_space_handler + handler)) #ifdef ACPI_FUTURE_USAGE -acpi_status acpi_install_exception_handler(acpi_exception_handler handler); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_exception_handler + (acpi_exception_handler handler)) #endif - -acpi_status acpi_install_interface_handler(acpi_interface_handler handler); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_interface_handler + (acpi_interface_handler handler)) /* * Global Lock interfaces @@ -351,10 +599,14 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status /* * Interfaces to AML mutex objects */ -acpi_status -acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_acquire_mutex(acpi_handle handle, + acpi_string pathname, + u16 timeout)) -acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_release_mutex(acpi_handle handle, + acpi_string pathname)) /* * Fixed Event interfaces @@ -434,57 +686,69 @@ typedef acpi_status(*acpi_walk_resource_callback) (struct acpi_resource * resource, void *context); -acpi_status -acpi_get_vendor_resource(acpi_handle device, - char *name, - struct acpi_vendor_uuid *uuid, - struct acpi_buffer *ret_buffer); - -acpi_status -acpi_get_current_resources(acpi_handle device, struct acpi_buffer *ret_buffer); - +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_vendor_resource(acpi_handle device, + char *name, + struct acpi_vendor_uuid + *uuid, + struct acpi_buffer + *ret_buffer)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_current_resources(acpi_handle device, + struct acpi_buffer + *ret_buffer)) #ifdef ACPI_FUTURE_USAGE -acpi_status -acpi_get_possible_resources(acpi_handle device, struct acpi_buffer *ret_buffer); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_possible_resources(acpi_handle device, + struct acpi_buffer + *ret_buffer)) #endif - -acpi_status -acpi_get_event_resources(acpi_handle device_handle, - struct acpi_buffer *ret_buffer); - -acpi_status -acpi_walk_resource_buffer(struct acpi_buffer *buffer, - acpi_walk_resource_callback user_function, - void *context); - -acpi_status -acpi_walk_resources(acpi_handle device, - char *name, - acpi_walk_resource_callback user_function, void *context); - -acpi_status -acpi_set_current_resources(acpi_handle device, struct acpi_buffer *in_buffer); - -acpi_status -acpi_get_irq_routing_table(acpi_handle device, struct acpi_buffer *ret_buffer); - -acpi_status -acpi_resource_to_address64(struct acpi_resource *resource, - struct acpi_resource_address64 *out); - -acpi_status -acpi_buffer_to_resource(u8 *aml_buffer, - u16 aml_buffer_length, - struct acpi_resource **resource_ptr); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_event_resources(acpi_handle device_handle, + struct acpi_buffer + *ret_buffer)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_walk_resource_buffer(struct acpi_buffer + *buffer, + acpi_walk_resource_callback + user_function, + void *context)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_walk_resources(acpi_handle device, char *name, + acpi_walk_resource_callback + user_function, void *context)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_set_current_resources(acpi_handle device, + struct acpi_buffer + *in_buffer)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_irq_routing_table(acpi_handle device, + struct acpi_buffer + *ret_buffer)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_resource_to_address64(struct acpi_resource + *resource, + struct + acpi_resource_address64 + *out)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_buffer_to_resource(u8 *aml_buffer, + u16 aml_buffer_length, + struct acpi_resource + **resource_ptr)) /* * Hardware (ACPI device) interfaces */ -acpi_status acpi_reset(void); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_reset(void)) -acpi_status acpi_read(u64 *value, struct acpi_generic_address *reg); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_read(u64 *value, + struct acpi_generic_address *reg)) -acpi_status acpi_write(u64 value, struct acpi_generic_address *reg); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_write(u64 value, + struct acpi_generic_address *reg)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_read_bit_register(u32 register_id, @@ -497,18 +761,20 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status /* * Sleep/Wake interfaces */ -acpi_status -acpi_get_sleep_type_data(u8 sleep_state, u8 *slp_typ_a, u8 *slp_typ_b); - -acpi_status acpi_enter_sleep_state_prep(u8 sleep_state); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_sleep_type_data(u8 sleep_state, + u8 *slp_typ_a, + u8 *slp_typ_b)) -acpi_status acpi_enter_sleep_state(u8 sleep_state); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_enter_sleep_state_prep(u8 sleep_state)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_enter_sleep_state(u8 sleep_state)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enter_sleep_state_s4bios(void)) -acpi_status acpi_leave_sleep_state_prep(u8 sleep_state); - -acpi_status acpi_leave_sleep_state(u8 sleep_state); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_leave_sleep_state_prep(u8 sleep_state)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_leave_sleep_state(u8 sleep_state)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_set_firmware_waking_vector(u32 @@ -535,53 +801,72 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status /* * Error/Warning output */ -ACPI_PRINTF_LIKE(3) -void ACPI_INTERNAL_VAR_XFACE -acpi_error(const char *module_name, u32 line_number, const char *format, ...); - -ACPI_PRINTF_LIKE(4) -void ACPI_INTERNAL_VAR_XFACE -acpi_exception(const char *module_name, - u32 line_number, acpi_status status, const char *format, ...); - -ACPI_PRINTF_LIKE(3) -void ACPI_INTERNAL_VAR_XFACE -acpi_warning(const char *module_name, u32 line_number, const char *format, ...); - -ACPI_PRINTF_LIKE(3) -void ACPI_INTERNAL_VAR_XFACE -acpi_info(const char *module_name, u32 line_number, const char *format, ...); - -ACPI_PRINTF_LIKE(3) -void ACPI_INTERNAL_VAR_XFACE -acpi_bios_error(const char *module_name, - u32 line_number, const char *format, ...); - -ACPI_PRINTF_LIKE(3) -void ACPI_INTERNAL_VAR_XFACE -acpi_bios_warning(const char *module_name, - u32 line_number, const char *format, ...); +ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) + void ACPI_INTERNAL_VAR_XFACE + acpi_error(const char *module_name, + u32 line_number, + const char *format, ...)) +ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(4) + void ACPI_INTERNAL_VAR_XFACE + acpi_exception(const char *module_name, + u32 line_number, + acpi_status status, + const char *format, ...)) +ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) + void ACPI_INTERNAL_VAR_XFACE + acpi_warning(const char *module_name, + u32 line_number, + const char *format, ...)) +ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) + void ACPI_INTERNAL_VAR_XFACE + acpi_info(const char *module_name, + u32 line_number, + const char *format, ...)) +ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) + void ACPI_INTERNAL_VAR_XFACE + acpi_bios_error(const char *module_name, + u32 line_number, + const char *format, ...)) +ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) + void ACPI_INTERNAL_VAR_XFACE + acpi_bios_warning(const char *module_name, + u32 line_number, + const char *format, ...)) /* * Debug output */ -#ifdef ACPI_DEBUG_OUTPUT +ACPI_DBG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(6) + void ACPI_INTERNAL_VAR_XFACE + acpi_debug_print(u32 requested_debug_level, + u32 line_number, + const char *function_name, + const char *module_name, + u32 component_id, + const char *format, ...)) +ACPI_DBG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(6) + void ACPI_INTERNAL_VAR_XFACE + acpi_debug_print_raw(u32 requested_debug_level, + u32 line_number, + const char *function_name, + const char *module_name, + u32 component_id, + const char *format, ...)) -ACPI_PRINTF_LIKE(6) -void ACPI_INTERNAL_VAR_XFACE -acpi_debug_print(u32 requested_debug_level, - u32 line_number, - const char *function_name, - const char *module_name, - u32 component_id, const char *format, ...); - -ACPI_PRINTF_LIKE(6) -void ACPI_INTERNAL_VAR_XFACE -acpi_debug_print_raw(u32 requested_debug_level, - u32 line_number, - const char *function_name, - const char *module_name, - u32 component_id, const char *format, ...); -#endif +/* + * Divergences + */ +acpi_status acpi_get_id(acpi_handle object, acpi_owner_id * out_type); + +acpi_status acpi_unload_table_id(acpi_owner_id id); + +acpi_status +acpi_get_table_with_size(acpi_string signature, + u32 instance, struct acpi_table_header **out_table, + acpi_size *tbl_size); + +acpi_status +acpi_get_data_full(acpi_handle object, acpi_object_handler handler, void **data, + void (*callback)(void *)); #endif /* __ACXFACE_H__ */ diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index 3b30e36b53b509..1cc7ef13c01a66 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -367,12 +367,11 @@ struct acpi_table_desc { /* Masks for Flags field above */ -#define ACPI_TABLE_ORIGIN_UNKNOWN (0) -#define ACPI_TABLE_ORIGIN_MAPPED (1) -#define ACPI_TABLE_ORIGIN_ALLOCATED (2) -#define ACPI_TABLE_ORIGIN_OVERRIDE (4) -#define ACPI_TABLE_ORIGIN_MASK (7) -#define ACPI_TABLE_IS_LOADED (8) +#define ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL (0) /* Virtual address, external maintained */ +#define ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL (1) /* Physical address, internally mapped */ +#define ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL (2) /* Virtual address, internallly allocated */ +#define ACPI_TABLE_ORIGIN_MASK (3) +#define ACPI_TABLE_IS_LOADED (8) /* * Get the remaining ACPI tables diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index 212c65de75df98..4ad7da8051802a 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -675,7 +675,7 @@ enum acpi_madt_type { }; /* - * MADT Sub-tables, correspond to Type in struct acpi_subtable_header + * MADT Subtables, correspond to Type in struct acpi_subtable_header */ /* 0: Processor Local APIC */ @@ -918,7 +918,7 @@ enum acpi_srat_type { }; /* - * SRAT Sub-tables, correspond to Type in struct acpi_subtable_header + * SRAT Subtables, correspond to Type in struct acpi_subtable_header */ /* 0: Processor Local APIC/SAPIC Affinity */ diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index c8adad9c6b6a73..860e5c883eb3cd 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -70,6 +70,7 @@ #define ACPI_SIG_HPET "HPET" /* High Precision Event Timer table */ #define ACPI_SIG_IBFT "IBFT" /* iSCSI Boot Firmware Table */ #define ACPI_SIG_IVRS "IVRS" /* I/O Virtualization Reporting Structure */ +#define ACPI_SIG_LPIT "LPIT" /* Low Power Idle Table */ #define ACPI_SIG_MCFG "MCFG" /* PCI Memory Mapped Configuration table */ #define ACPI_SIG_MCHI "MCHI" /* Management Controller Host Interface table */ #define ACPI_SIG_MTMR "MTMR" /* MID Timer table */ @@ -456,7 +457,7 @@ struct acpi_dmar_pci_path { }; /* - * DMAR Sub-tables, correspond to Type in struct acpi_dmar_header + * DMAR Subtables, correspond to Type in struct acpi_dmar_header */ /* 0: Hardware Unit Definition */ @@ -820,7 +821,71 @@ struct acpi_ivrs_memory { /******************************************************************************* * - * MCFG - PCI Memory Mapped Configuration table and sub-table + * LPIT - Low Power Idle Table + * + * Conforms to "ACPI Low Power Idle Table (LPIT) and _LPD Proposal (DRAFT)" + * + ******************************************************************************/ + +struct acpi_table_lpit { + struct acpi_table_header header; /* Common ACPI table header */ +}; + +/* LPIT subtable header */ + +struct acpi_lpit_header { + u32 type; /* Subtable type */ + u32 length; /* Subtable length */ + u16 unique_id; + u16 reserved; + u32 flags; +}; + +/* Values for subtable Type above */ + +enum acpi_lpit_type { + ACPI_LPIT_TYPE_NATIVE_CSTATE = 0x00, + ACPI_LPIT_TYPE_SIMPLE_IO = 0x01 +}; + +/* Masks for Flags field above */ + +#define ACPI_LPIT_STATE_DISABLED (1) +#define ACPI_LPIT_NO_COUNTER (1<<1) + +/* + * LPIT subtables, correspond to Type in struct acpi_lpit_header + */ + +/* 0x00: Native C-state instruction based LPI structure */ + +struct acpi_lpit_native { + struct acpi_lpit_header header; + struct acpi_generic_address entry_trigger; + u32 residency; + u32 latency; + struct acpi_generic_address residency_counter; + u64 counter_frequency; +}; + +/* 0x01: Simple I/O based LPI structure */ + +struct acpi_lpit_io { + struct acpi_lpit_header header; + struct acpi_generic_address entry_trigger; + u32 trigger_action; + u64 trigger_value; + u64 trigger_mask; + struct acpi_generic_address minimum_idle_state; + u32 residency; + u32 latency; + struct acpi_generic_address residency_counter; + u64 counter_frequency; +}; + +/******************************************************************************* + * + * MCFG - PCI Memory Mapped Configuration table and subtable * Version 1 * * Conforms to "PCI Firmware Specification", Revision 3.0, June 20, 2005 @@ -923,7 +988,7 @@ enum acpi_slic_type { }; /* - * SLIC Sub-tables, correspond to Type in struct acpi_slic_header + * SLIC Subtables, correspond to Type in struct acpi_slic_header */ /* 0: Public Key Structure */ diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index e76356574374d4..19b26bb69a70b6 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -329,6 +329,15 @@ typedef u32 acpi_physical_address; * ******************************************************************************/ +#ifdef ACPI_NO_MEM_ALLOCATIONS + +#define ACPI_ALLOCATE(a) NULL +#define ACPI_ALLOCATE_ZEROED(a) NULL +#define ACPI_FREE(a) +#define ACPI_MEM_TRACKING(a) + +#else /* ACPI_NO_MEM_ALLOCATIONS */ + #ifdef ACPI_DBG_TRACK_ALLOCATIONS /* * Memory allocation tracking (used by acpi_exec to detect memory leaks) @@ -350,6 +359,8 @@ typedef u32 acpi_physical_address; #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ +#endif /* ACPI_NO_MEM_ALLOCATIONS */ + /****************************************************************************** * * ACPI Specification constants (Do not change unless the specification changes) @@ -928,9 +939,19 @@ struct acpi_object_list { * Miscellaneous common Data Structures used by the interfaces */ #define ACPI_NO_BUFFER 0 + +#ifdef ACPI_NO_MEM_ALLOCATIONS + +#define ACPI_ALLOCATE_BUFFER (acpi_size) (0) +#define ACPI_ALLOCATE_LOCAL_BUFFER (acpi_size) (0) + +#else /* ACPI_NO_MEM_ALLOCATIONS */ + #define ACPI_ALLOCATE_BUFFER (acpi_size) (-1) /* Let ACPICA allocate buffer */ #define ACPI_ALLOCATE_LOCAL_BUFFER (acpi_size) (-2) /* For internal use only (enables tracking) */ +#endif /* ACPI_NO_MEM_ALLOCATIONS */ + struct acpi_buffer { acpi_size length; /* Length in bytes of the buffer */ void *pointer; /* pointer to buffer */ diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h index a476b9118b49bb..384875da37137b 100644 --- a/include/acpi/platform/acgcc.h +++ b/include/acpi/platform/acgcc.h @@ -64,4 +64,15 @@ */ #define ACPI_UNUSED_VAR __attribute__ ((unused)) +/* + * Some versions of gcc implement strchr() with a buggy macro. So, + * undef it here. Prevents error messages of this form (usually from the + * file getopt.c): + * + * error: logical '&&' with non-zero constant will always evaluate as true + */ +#ifdef strchr +#undef strchr +#endif + #endif /* __ACGCC_H__ */ diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 93c55ed7c53d88..4c2f9e78001ce3 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -73,6 +73,37 @@ #endif #include +#ifndef CONFIG_ACPI + +/* External globals for __KERNEL__, stubs is needed */ + +#define ACPI_GLOBAL(t,a) +#define ACPI_INIT_GLOBAL(t,a,b) + +/* Generating stubs for configurable ACPICA macros */ + +#define ACPI_NO_MEM_ALLOCATIONS + +/* Generating stubs for configurable ACPICA functions */ + +#define ACPI_NO_ERROR_MESSAGES +#undef ACPI_DEBUG_OUTPUT + +/* External interface for __KERNEL__, stub is needed */ + +#define ACPI_EXTERNAL_RETURN_STATUS(prototype) \ + static ACPI_INLINE prototype {return(AE_NOT_CONFIGURED);} +#define ACPI_EXTERNAL_RETURN_OK(prototype) \ + static ACPI_INLINE prototype {return(AE_OK);} +#define ACPI_EXTERNAL_RETURN_VOID(prototype) \ + static ACPI_INLINE prototype {return;} +#define ACPI_EXTERNAL_RETURN_UINT32(prototype) \ + static ACPI_INLINE prototype {return(0);} +#define ACPI_EXTERNAL_RETURN_PTR(prototype) \ + static ACPI_INLINE prototype {return(NULL);} + +#endif /* CONFIG_ACPI */ + /* Host-dependent types and defines for in-kernel ACPICA */ #define ACPI_MACHINE_WIDTH BITS_PER_LONG @@ -91,7 +122,7 @@ #include #include -/* Disable kernel specific declarators */ +/* Define/disable kernel-specific declarators */ #ifndef __init #define __init @@ -106,7 +137,8 @@ #define ACPI_FLUSH_CPU_CACHE() #define ACPI_CAST_PTHREAD_T(pthread) ((acpi_thread_id) (pthread)) -#if defined(__ia64__) || defined(__x86_64__) || defined(__aarch64__) +#if defined(__ia64__) || defined(__x86_64__) ||\ + defined(__aarch64__) || defined(__PPC64__) #define ACPI_MACHINE_WIDTH 64 #define COMPILER_DEPENDENT_INT64 long #define COMPILER_DEPENDENT_UINT64 unsigned long diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index 33bd2de3bc1e93..9c79e7603459ed 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h @@ -16,6 +16,7 @@ #define __ASM_GENERIC_ATOMIC_H #include +#include #ifdef CONFIG_SMP /* Force people to define core atomics */ @@ -182,11 +183,5 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v) } #endif -/* Assume that atomic operations are already serializing */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif /* __KERNEL__ */ #endif /* __ASM_GENERIC_ATOMIC_H */ diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h index 6f692f8ac66456..1402fa85538898 100644 --- a/include/asm-generic/barrier.h +++ b/include/asm-generic/barrier.h @@ -62,6 +62,14 @@ #define set_mb(var, value) do { (var) = (value); mb(); } while (0) #endif +#ifndef smp_mb__before_atomic +#define smp_mb__before_atomic() smp_mb() +#endif + +#ifndef smp_mb__after_atomic +#define smp_mb__after_atomic() smp_mb() +#endif + #define smp_store_release(p, v) \ do { \ compiletime_assert_atomic_type(*p); \ diff --git a/include/asm-generic/bitops.h b/include/asm-generic/bitops.h index 280ca7a96f7507..dcdcacf2fd2b8d 100644 --- a/include/asm-generic/bitops.h +++ b/include/asm-generic/bitops.h @@ -11,14 +11,7 @@ #include #include - -/* - * clear_bit may not imply a memory barrier - */ -#ifndef smp_mb__before_clear_bit -#define smp_mb__before_clear_bit() smp_mb() -#define smp_mb__after_clear_bit() smp_mb() -#endif +#include #include #include diff --git a/include/asm-generic/bitops/atomic.h b/include/asm-generic/bitops/atomic.h index 9ae6c34dc191e7..49673510b48415 100644 --- a/include/asm-generic/bitops/atomic.h +++ b/include/asm-generic/bitops/atomic.h @@ -80,7 +80,7 @@ static inline void set_bit(int nr, volatile unsigned long *addr) * * clear_bit() is atomic and may not be reordered. However, it does * not contain a memory barrier, so if it is used for locking purposes, - * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic() * in order to ensure changes are visible on other processors. */ static inline void clear_bit(int nr, volatile unsigned long *addr) diff --git a/include/asm-generic/bitops/lock.h b/include/asm-generic/bitops/lock.h index 308a9e22c80219..c30266e9480650 100644 --- a/include/asm-generic/bitops/lock.h +++ b/include/asm-generic/bitops/lock.h @@ -20,7 +20,7 @@ */ #define clear_bit_unlock(nr, addr) \ do { \ - smp_mb__before_clear_bit(); \ + smp_mb__before_atomic(); \ clear_bit(nr, addr); \ } while (0) diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h index d401e5463fb02d..0c938a4354f6f5 100644 --- a/include/asm-generic/syscall.h +++ b/include/asm-generic/syscall.h @@ -147,7 +147,7 @@ void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, * * Returns the AUDIT_ARCH_* based on the system call convention in use. * - * It's only valid to call this when @task is stopped on entry to a system + * It's only valid to call this when current is stopped on entry to a system * call, due to %TIF_SYSCALL_TRACE, %TIF_SYSCALL_AUDIT, or %TIF_SECCOMP. * * Architectures which permit CONFIG_HAVE_ARCH_SECCOMP_FILTER must diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 146e4fffd710ca..8e0204a68c742e 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -109,6 +109,15 @@ #define BRANCH_PROFILE() #endif +#ifdef CONFIG_KPROBES +#define KPROBE_BLACKLIST() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \ + *(_kprobe_blacklist) \ + VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .; +#else +#define KPROBE_BLACKLIST() +#endif + #ifdef CONFIG_EVENT_TRACING #define FTRACE_EVENTS() . = ALIGN(8); \ VMLINUX_SYMBOL(__start_ftrace_events) = .; \ @@ -507,6 +516,7 @@ *(.init.rodata) \ FTRACE_EVENTS() \ TRACE_SYSCALLS() \ + KPROBE_BLACKLIST() \ MEM_DISCARD(init.rodata) \ CLK_OF_TABLES() \ RESERVEDMEM_OF_TABLES() \ diff --git a/include/drm/drmP.h b/include/drm/drmP.h index a7c2a862b4f48a..12f10bc2395f9a 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -143,11 +143,6 @@ int drm_err(const char *func, const char *format, ...); #define DRIVER_PRIME 0x4000 #define DRIVER_RENDER 0x8000 -#define DRIVER_BUS_PCI 0x1 -#define DRIVER_BUS_PLATFORM 0x2 -#define DRIVER_BUS_USB 0x3 -#define DRIVER_BUS_HOST1X 0x4 - /***********************************************************************/ /** \name Begin the DRM... */ /*@{*/ @@ -731,13 +726,7 @@ struct drm_master { #define DRM_SCANOUTPOS_ACCURATE (1 << 2) struct drm_bus { - int bus_type; - int (*get_irq)(struct drm_device *dev); - const char *(*get_name)(struct drm_device *dev); int (*set_busid)(struct drm_device *dev, struct drm_master *master); - int (*set_unique)(struct drm_device *dev, struct drm_master *master, - struct drm_unique *unique); - int (*irq_by_busid)(struct drm_device *dev, struct drm_irq_busid *p); }; /** @@ -974,11 +963,6 @@ struct drm_driver { const struct drm_ioctl_desc *ioctls; int num_ioctls; const struct file_operations *fops; - union { - struct pci_driver *pci; - struct platform_device *platform_device; - struct usb_driver *usb; - } kdriver; struct drm_bus *bus; /* List of devices hanging off this driver with stealth attach. */ @@ -1058,7 +1042,6 @@ struct drm_vblank_crtc { */ struct drm_device { struct list_head legacy_dev_list;/**< list of devices per driver for stealth attach cleanup */ - char *devname; /**< For /proc/interrupts */ int if_version; /**< Highest interface version set */ /** \name Lifetime Management */ @@ -1076,14 +1059,14 @@ struct drm_device { /** \name Locks */ /*@{ */ - spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ struct mutex struct_mutex; /**< For others */ struct mutex master_mutex; /**< For drm_minor::master and drm_file::is_master */ /*@} */ /** \name Usage Counters */ /*@{ */ - int open_count; /**< Outstanding files open */ + int open_count; /**< Outstanding files open, protected by drm_global_mutex. */ + spinlock_t buf_lock; /**< For drm_device::buf_use and a few other things. */ int buf_use; /**< Buffers in use -- cannot alloc */ atomic_t buf_alloc; /**< Buffer allocation in progress */ /*@} */ @@ -1114,6 +1097,8 @@ struct drm_device { /** \name Context support */ /*@{ */ bool irq_enabled; /**< True if irq handler is enabled */ + int irq; + __volatile__ long context_flag; /**< Context swapping flag */ int last_context; /**< Last current context */ /*@} */ @@ -1186,11 +1171,6 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev, return ((dev->driver->driver_features & feature) ? 1 : 0); } -static inline int drm_dev_to_irq(struct drm_device *dev) -{ - return dev->driver->bus->get_irq(dev); -} - static inline void drm_device_set_unplugged(struct drm_device *dev) { smp_wmb(); @@ -1310,7 +1290,7 @@ extern int drm_remove_magic(struct drm_master *master, drm_magic_t magic); /* Cache management (drm_cache.c) */ void drm_clflush_pages(struct page *pages[], unsigned long num_pages); void drm_clflush_sg(struct sg_table *st); -void drm_clflush_virt_range(char *addr, unsigned long length); +void drm_clflush_virt_range(void *addr, unsigned long length); /* Locking IOCTL support (drm_lock.h) */ extern int drm_lock(struct drm_device *dev, void *data, @@ -1363,7 +1343,7 @@ extern void drm_core_reclaim_buffers(struct drm_device *dev, /* IRQ support (drm_irq.h) */ extern int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_irq_install(struct drm_device *dev); +extern int drm_irq_install(struct drm_device *dev, int irq); extern int drm_irq_uninstall(struct drm_device *dev); extern int drm_vblank_init(struct drm_device *dev, int num_crtcs); @@ -1522,6 +1502,9 @@ extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size, size_t align); extern void __drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); +extern int drm_pci_set_unique(struct drm_device *dev, + struct drm_master *master, + struct drm_unique *u); /* sysfs support (drm_sysfs.c) */ struct drm_sysfs_class; diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 36a5febac2a600..f51c8393e9a81a 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -165,6 +165,10 @@ extern void drm_helper_resume_force_mode(struct drm_device *dev); extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); +extern int drm_helper_probe_single_connector_modes_nomerge(struct drm_connector + *connector, + uint32_t maxX, + uint32_t maxY); extern void drm_kms_helper_poll_init(struct drm_device *dev); extern void drm_kms_helper_poll_fini(struct drm_device *dev); extern bool drm_helper_hpd_irq_event(struct drm_device *dev); diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 2dbbf997666937..91d0582f924e3e 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -223,7 +223,7 @@ void drm_mode_validate_size(struct drm_device *dev, void drm_mode_prune_invalid(struct drm_device *dev, struct list_head *mode_list, bool verbose); void drm_mode_sort(struct list_head *mode_list); -void drm_mode_connector_list_update(struct drm_connector *connector); +void drm_mode_connector_list_update(struct drm_connector *connector, bool merge_type_bits); /* parsing cmdline modes */ bool diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 012d58fa8ff0eb..5cd9165685bbe2 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -223,14 +223,26 @@ _INTEL_BDW_D(gt, 0x160A, info), /* Server */ \ _INTEL_BDW_D(gt, 0x160D, info) /* Workstation */ -#define INTEL_BDW_M_IDS(info) \ +#define INTEL_BDW_GT12M_IDS(info) \ _INTEL_BDW_M_IDS(1, info), \ - _INTEL_BDW_M_IDS(2, info), \ - _INTEL_BDW_M_IDS(3, info) + _INTEL_BDW_M_IDS(2, info) -#define INTEL_BDW_D_IDS(info) \ +#define INTEL_BDW_GT12D_IDS(info) \ _INTEL_BDW_D_IDS(1, info), \ - _INTEL_BDW_D_IDS(2, info), \ + _INTEL_BDW_D_IDS(2, info) + +#define INTEL_BDW_GT3M_IDS(info) \ + _INTEL_BDW_M_IDS(3, info) + +#define INTEL_BDW_GT3D_IDS(info) \ _INTEL_BDW_D_IDS(3, info) +#define INTEL_BDW_M_IDS(info) \ + INTEL_BDW_GT12M_IDS(info), \ + INTEL_BDW_GT3M_IDS(info) + +#define INTEL_BDW_D_IDS(info) \ + INTEL_BDW_GT12D_IDS(info), \ + INTEL_BDW_GT3D_IDS(info) + #endif /* _I915_PCIIDS_H */ diff --git a/include/dt-bindings/clk/at91.h b/include/dt-bindings/clock/at91.h similarity index 100% rename from include/dt-bindings/clk/at91.h rename to include/dt-bindings/clock/at91.h diff --git a/include/dt-bindings/clock/bcm21664.h b/include/dt-bindings/clock/bcm21664.h new file mode 100644 index 00000000000000..5a7f0e4750a844 --- /dev/null +++ b/include/dt-bindings/clock/bcm21664.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2013 Broadcom Corporation + * Copyright 2013 Linaro Limited + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CLOCK_BCM21664_H +#define _CLOCK_BCM21664_H + +/* + * This file defines the values used to specify clocks provided by + * the clock control units (CCUs) on Broadcom BCM21664 family SoCs. + */ + +/* bcm21664 CCU device tree "compatible" strings */ +#define BCM21664_DT_ROOT_CCU_COMPAT "brcm,bcm21664-root-ccu" +#define BCM21664_DT_AON_CCU_COMPAT "brcm,bcm21664-aon-ccu" +#define BCM21664_DT_MASTER_CCU_COMPAT "brcm,bcm21664-master-ccu" +#define BCM21664_DT_SLAVE_CCU_COMPAT "brcm,bcm21664-slave-ccu" + +/* root CCU clock ids */ + +#define BCM21664_ROOT_CCU_FRAC_1M 0 +#define BCM21664_ROOT_CCU_CLOCK_COUNT 1 + +/* aon CCU clock ids */ + +#define BCM21664_AON_CCU_HUB_TIMER 0 +#define BCM21664_AON_CCU_CLOCK_COUNT 1 + +/* master CCU clock ids */ + +#define BCM21664_MASTER_CCU_SDIO1 0 +#define BCM21664_MASTER_CCU_SDIO2 1 +#define BCM21664_MASTER_CCU_SDIO3 2 +#define BCM21664_MASTER_CCU_SDIO4 3 +#define BCM21664_MASTER_CCU_SDIO1_SLEEP 4 +#define BCM21664_MASTER_CCU_SDIO2_SLEEP 5 +#define BCM21664_MASTER_CCU_SDIO3_SLEEP 6 +#define BCM21664_MASTER_CCU_SDIO4_SLEEP 7 +#define BCM21664_MASTER_CCU_CLOCK_COUNT 8 + +/* slave CCU clock ids */ + +#define BCM21664_SLAVE_CCU_UARTB 0 +#define BCM21664_SLAVE_CCU_UARTB2 1 +#define BCM21664_SLAVE_CCU_UARTB3 2 +#define BCM21664_SLAVE_CCU_BSC1 3 +#define BCM21664_SLAVE_CCU_BSC2 4 +#define BCM21664_SLAVE_CCU_BSC3 5 +#define BCM21664_SLAVE_CCU_BSC4 6 +#define BCM21664_SLAVE_CCU_CLOCK_COUNT 7 + +#endif /* _CLOCK_BCM21664_H */ diff --git a/include/dt-bindings/clock/bcm281xx.h b/include/dt-bindings/clock/bcm281xx.h index e0096940886d71..a763460cf1afcc 100644 --- a/include/dt-bindings/clock/bcm281xx.h +++ b/include/dt-bindings/clock/bcm281xx.h @@ -20,6 +20,18 @@ * the clock control units (CCUs) on Broadcom BCM281XX family SoCs. */ +/* + * These are the bcm281xx CCU device tree "compatible" strings. + * We're stuck with using "bcm11351" in the string because wild + * cards aren't allowed, and that name was the first one defined + * in this family of devices. + */ +#define BCM281XX_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu" +#define BCM281XX_DT_AON_CCU_COMPAT "brcm,bcm11351-aon-ccu" +#define BCM281XX_DT_HUB_CCU_COMPAT "brcm,bcm11351-hub-ccu" +#define BCM281XX_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu" +#define BCM281XX_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu" + /* root CCU clock ids */ #define BCM281XX_ROOT_CCU_FRAC_1M 0 diff --git a/include/dt-bindings/clock/qcom,gcc-msm8960.h b/include/dt-bindings/clock/qcom,gcc-msm8960.h index 03bbf49d43b7dd..f9f547146a153b 100644 --- a/include/dt-bindings/clock/qcom,gcc-msm8960.h +++ b/include/dt-bindings/clock/qcom,gcc-msm8960.h @@ -51,7 +51,7 @@ #define QDSS_TSCTR_CLK 34 #define SFAB_ADM0_M0_A_CLK 35 #define SFAB_ADM0_M1_A_CLK 36 -#define SFAB_ADM0_M2_A_CLK 37 +#define SFAB_ADM0_M2_H_CLK 37 #define ADM0_CLK 38 #define ADM0_PBUS_CLK 39 #define MSS_XPU_CLK 40 @@ -99,7 +99,7 @@ #define CFPB2_H_CLK 82 #define SFAB_CFPB_M_H_CLK 83 #define CFPB_MASTER_H_CLK 84 -#define SFAB_CFPB_S_HCLK 85 +#define SFAB_CFPB_S_H_CLK 85 #define CFPB_SPLITTER_H_CLK 86 #define TSIF_H_CLK 87 #define TSIF_INACTIVITY_TIMERS_CLK 88 @@ -110,7 +110,6 @@ #define CE1_SLEEP_CLK 93 #define CE2_H_CLK 94 #define CE2_CORE_CLK 95 -#define CE2_SLEEP_CLK 96 #define SFPB_H_CLK_SRC 97 #define SFPB_H_CLK 98 #define SFAB_SFPB_M_H_CLK 99 @@ -252,7 +251,7 @@ #define MSS_S_H_CLK 235 #define MSS_CXO_SRC_CLK 236 #define SATA_H_CLK 237 -#define SATA_SRC_CLK 238 +#define SATA_CLK_SRC 238 #define SATA_RXOOB_CLK 239 #define SATA_PMALIVE_CLK 240 #define SATA_PHY_REF_CLK 241 diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h index 6548a5fbcf4a48..1118f7a4bca611 100644 --- a/include/dt-bindings/clock/r8a7790-clock.h +++ b/include/dt-bindings/clock/r8a7790-clock.h @@ -33,8 +33,8 @@ #define R8A7790_CLK_TMU0 25 #define R8A7790_CLK_VSP1_DU1 27 #define R8A7790_CLK_VSP1_DU0 28 -#define R8A7790_CLK_VSP1_RT 30 -#define R8A7790_CLK_VSP1_SY 31 +#define R8A7790_CLK_VSP1_R 30 +#define R8A7790_CLK_VSP1_S 31 /* MSTP2 */ #define R8A7790_CLK_SCIFA2 2 @@ -50,6 +50,7 @@ #define R8A7790_CLK_SYS_DMAC0 19 /* MSTP3 */ +#define R8A7790_CLK_IIC2 0 #define R8A7790_CLK_TPU0 4 #define R8A7790_CLK_MMCIF1 5 #define R8A7790_CLK_SDHI3 11 @@ -57,6 +58,8 @@ #define R8A7790_CLK_SDHI1 13 #define R8A7790_CLK_SDHI0 14 #define R8A7790_CLK_MMCIF0 15 +#define R8A7790_CLK_IIC0 18 +#define R8A7790_CLK_IIC1 23 #define R8A7790_CLK_SSUSB 28 #define R8A7790_CLK_CMT1 29 #define R8A7790_CLK_USBDMAC0 30 diff --git a/include/dt-bindings/clock/r8a7791-clock.h b/include/dt-bindings/clock/r8a7791-clock.h index 30f82f286e295d..29b0f3355ffb34 100644 --- a/include/dt-bindings/clock/r8a7791-clock.h +++ b/include/dt-bindings/clock/r8a7791-clock.h @@ -32,7 +32,7 @@ #define R8A7791_CLK_TMU0 25 #define R8A7791_CLK_VSP1_DU1 27 #define R8A7791_CLK_VSP1_DU0 28 -#define R8A7791_CLK_VSP1_SY 31 +#define R8A7791_CLK_VSP1_S 31 /* MSTP2 */ #define R8A7791_CLK_SCIFA2 2 @@ -51,6 +51,8 @@ #define R8A7791_CLK_SDHI1 12 #define R8A7791_CLK_SDHI0 14 #define R8A7791_CLK_MMCIF0 15 +#define R8A7791_CLK_IIC0 18 +#define R8A7791_CLK_IIC1 23 #define R8A7791_CLK_SSUSB 28 #define R8A7791_CLK_CMT1 29 #define R8A7791_CLK_USBDMAC0 30 @@ -61,6 +63,7 @@ #define R8A7791_CLK_PWM 23 /* MSTP7 */ +#define R8A7791_CLK_EHCI 3 #define R8A7791_CLK_HSUSB 4 #define R8A7791_CLK_HSCIF2 13 #define R8A7791_CLK_SCIF5 14 diff --git a/include/dt-bindings/clock/s3c2410.h b/include/dt-bindings/clock/s3c2410.h new file mode 100644 index 00000000000000..352a7673fc6993 --- /dev/null +++ b/include/dt-bindings/clock/s3c2410.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013 Heiko Stuebner + * + * 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. + * + * Device Tree binding constants clock controllers of Samsung S3C2410 and later. + */ + +#ifndef _DT_BINDINGS_CLOCK_SAMSUNG_S3C2410_CLOCK_H +#define _DT_BINDINGS_CLOCK_SAMSUNG_S3C2410_CLOCK_H + +/* + * Let each exported clock get a unique index, which is used on DT-enabled + * platforms to lookup the clock from a clock specifier. These indices are + * therefore considered an ABI and so must not be changed. This implies + * that new clocks should be added either in free spaces between clock groups + * or at the end. + */ + +/* Core clocks. */ + +/* id 1 is reserved */ +#define MPLL 2 +#define UPLL 3 +#define FCLK 4 +#define HCLK 5 +#define PCLK 6 +#define UCLK 7 +#define ARMCLK 8 + +/* pclk-gates */ +#define PCLK_UART0 16 +#define PCLK_UART1 17 +#define PCLK_UART2 18 +#define PCLK_I2C 19 +#define PCLK_SDI 20 +#define PCLK_SPI 21 +#define PCLK_ADC 22 +#define PCLK_AC97 23 +#define PCLK_I2S 24 +#define PCLK_PWM 25 +#define PCLK_RTC 26 +#define PCLK_GPIO 27 + + +/* hclk-gates */ +#define HCLK_LCD 32 +#define HCLK_USBH 33 +#define HCLK_USBD 34 +#define HCLK_NAND 35 +#define HCLK_CAM 36 + + +#define CAMIF 40 + + +/* Total number of clocks. */ +#define NR_CLKS (CAMIF + 1) + +#endif /* _DT_BINDINGS_CLOCK_SAMSUNG_S3C2443_CLOCK_H */ diff --git a/include/dt-bindings/clock/s3c2412.h b/include/dt-bindings/clock/s3c2412.h new file mode 100644 index 00000000000000..aac1dcfda81cdb --- /dev/null +++ b/include/dt-bindings/clock/s3c2412.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013 Heiko Stuebner + * + * 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. + * + * Device Tree binding constants clock controllers of Samsung S3C2412. + */ + +#ifndef _DT_BINDINGS_CLOCK_SAMSUNG_S3C2412_CLOCK_H +#define _DT_BINDINGS_CLOCK_SAMSUNG_S3C2412_CLOCK_H + +/* + * Let each exported clock get a unique index, which is used on DT-enabled + * platforms to lookup the clock from a clock specifier. These indices are + * therefore considered an ABI and so must not be changed. This implies + * that new clocks should be added either in free spaces between clock groups + * or at the end. + */ + +/* Core clocks. */ + +/* id 1 is reserved */ +#define MPLL 2 +#define UPLL 3 +#define MDIVCLK 4 +#define MSYSCLK 5 +#define USYSCLK 6 +#define HCLK 7 +#define PCLK 8 +#define ARMDIV 9 +#define ARMCLK 10 + + +/* Special clocks */ +#define SCLK_CAM 16 +#define SCLK_UART 17 +#define SCLK_I2S 18 +#define SCLK_USBD 19 +#define SCLK_USBH 20 + +/* pclk-gates */ +#define PCLK_WDT 32 +#define PCLK_SPI 33 +#define PCLK_I2S 34 +#define PCLK_I2C 35 +#define PCLK_ADC 36 +#define PCLK_RTC 37 +#define PCLK_GPIO 38 +#define PCLK_UART2 39 +#define PCLK_UART1 40 +#define PCLK_UART0 41 +#define PCLK_SDI 42 +#define PCLK_PWM 43 +#define PCLK_USBD 44 + +/* hclk-gates */ +#define HCLK_HALF 48 +#define HCLK_X2 49 +#define HCLK_SDRAM 50 +#define HCLK_USBH 51 +#define HCLK_LCD 52 +#define HCLK_NAND 53 +#define HCLK_DMA3 54 +#define HCLK_DMA2 55 +#define HCLK_DMA1 56 +#define HCLK_DMA0 57 + +/* Total number of clocks. */ +#define NR_CLKS (HCLK_DMA0 + 1) + +#endif /* _DT_BINDINGS_CLOCK_SAMSUNG_S3C2412_CLOCK_H */ diff --git a/include/dt-bindings/clock/s3c2443.h b/include/dt-bindings/clock/s3c2443.h new file mode 100644 index 00000000000000..37e66b054d64a1 --- /dev/null +++ b/include/dt-bindings/clock/s3c2443.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013 Heiko Stuebner + * + * 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. + * + * Device Tree binding constants clock controllers of Samsung S3C2443 and later. + */ + +#ifndef _DT_BINDINGS_CLOCK_SAMSUNG_S3C2443_CLOCK_H +#define _DT_BINDINGS_CLOCK_SAMSUNG_S3C2443_CLOCK_H + +/* + * Let each exported clock get a unique index, which is used on DT-enabled + * platforms to lookup the clock from a clock specifier. These indices are + * therefore considered an ABI and so must not be changed. This implies + * that new clocks should be added either in free spaces between clock groups + * or at the end. + */ + +/* Core clocks. */ +#define MSYSCLK 1 +#define ESYSCLK 2 +#define ARMDIV 3 +#define ARMCLK 4 +#define HCLK 5 +#define PCLK 6 + +/* Special clocks */ +#define SCLK_HSSPI0 16 +#define SCLK_FIMD 17 +#define SCLK_I2S0 18 +#define SCLK_I2S1 19 +#define SCLK_HSMMC1 20 +#define SCLK_HSMMC_EXT 21 +#define SCLK_CAM 22 +#define SCLK_UART 23 +#define SCLK_USBH 24 + +/* Muxes */ +#define MUX_HSSPI0 32 +#define MUX_HSSPI1 33 +#define MUX_HSMMC0 34 +#define MUX_HSMMC1 35 + +/* hclk-gates */ +#define HCLK_DMA0 48 +#define HCLK_DMA1 49 +#define HCLK_DMA2 50 +#define HCLK_DMA3 51 +#define HCLK_DMA4 52 +#define HCLK_DMA5 53 +#define HCLK_DMA6 54 +#define HCLK_DMA7 55 +#define HCLK_CAM 56 +#define HCLK_LCD 57 +#define HCLK_USBH 58 +#define HCLK_USBD 59 +#define HCLK_IROM 60 +#define HCLK_HSMMC0 61 +#define HCLK_HSMMC1 62 +#define HCLK_CFC 63 +#define HCLK_SSMC 64 +#define HCLK_DRAM 65 +#define HCLK_2D 66 + +/* pclk-gates */ +#define PCLK_UART0 72 +#define PCLK_UART1 73 +#define PCLK_UART2 74 +#define PCLK_UART3 75 +#define PCLK_I2C0 76 +#define PCLK_SDI 77 +#define PCLK_SPI0 78 +#define PCLK_ADC 79 +#define PCLK_AC97 80 +#define PCLK_I2S0 81 +#define PCLK_PWM 82 +#define PCLK_WDT 83 +#define PCLK_RTC 84 +#define PCLK_GPIO 85 +#define PCLK_SPI1 86 +#define PCLK_CHIPID 87 +#define PCLK_I2C1 88 +#define PCLK_I2S1 89 +#define PCLK_PCM 90 + +/* Total number of clocks. */ +#define NR_CLKS (PCLK_PCM + 1) + +#endif /* _DT_BINDINGS_CLOCK_SAMSUNG_S3C2443_CLOCK_H */ diff --git a/include/dt-bindings/reset/qcom,gcc-msm8960.h b/include/dt-bindings/reset/qcom,gcc-msm8960.h index a840e680323c44..07edd0e65eed0e 100644 --- a/include/dt-bindings/reset/qcom,gcc-msm8960.h +++ b/include/dt-bindings/reset/qcom,gcc-msm8960.h @@ -58,7 +58,7 @@ #define PPSS_PROC_RESET 41 #define PPSS_RESET 42 #define DMA_BAM_RESET 43 -#define SIC_TIC_RESET 44 +#define SPS_TIC_H_RESET 44 #define SLIMBUS_H_RESET 45 #define SFAB_CFPB_M_RESET 46 #define SFAB_CFPB_S_RESET 47 diff --git a/include/linux/amba/xilinx_dma.h b/include/linux/amba/xilinx_dma.h new file mode 100644 index 00000000000000..34b98f276ed03c --- /dev/null +++ b/include/linux/amba/xilinx_dma.h @@ -0,0 +1,47 @@ +/* + * Xilinx DMA Engine drivers support header file + * + * Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved. + * + * This 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. + */ + +#ifndef __DMA_XILINX_DMA_H +#define __DMA_XILINX_DMA_H + +#include +#include + +/** + * struct xilinx_vdma_config - VDMA Configuration structure + * @frm_dly: Frame delay + * @gen_lock: Whether in gen-lock mode + * @master: Master that it syncs to + * @frm_cnt_en: Enable frame count enable + * @park: Whether wants to park + * @park_frm: Frame to park on + * @coalesc: Interrupt coalescing threshold + * @delay: Delay counter + * @reset: Reset Channel + * @ext_fsync: External Frame Sync source + */ +struct xilinx_vdma_config { + int frm_dly; + int gen_lock; + int master; + int frm_cnt_en; + int park; + int park_frm; + int coalesc; + int delay; + int reset; + int ext_fsync; +}; + +int xilinx_vdma_channel_set_config(struct dma_chan *dchan, + struct xilinx_vdma_config *cfg); + +#endif diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h index 8598f8eacb20e1..a495a959e8a754 100644 --- a/include/linux/ath9k_platform.h +++ b/include/linux/ath9k_platform.h @@ -36,6 +36,8 @@ struct ath9k_platform_data { int (*get_mac_revision)(void); int (*external_reset)(void); + + bool use_eeprom; }; #endif /* _LINUX_ATH9K_PLATFORM_H */ diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 5b08a8540ecfc3..fef3a809e7cf04 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -3,6 +3,42 @@ #define _LINUX_ATOMIC_H #include +/* + * Provide __deprecated wrappers for the new interface, avoid flag day changes. + * We need the ugly external functions to break header recursion hell. + */ +#ifndef smp_mb__before_atomic_inc +static inline void __deprecated smp_mb__before_atomic_inc(void) +{ + extern void __smp_mb__before_atomic(void); + __smp_mb__before_atomic(); +} +#endif + +#ifndef smp_mb__after_atomic_inc +static inline void __deprecated smp_mb__after_atomic_inc(void) +{ + extern void __smp_mb__after_atomic(void); + __smp_mb__after_atomic(); +} +#endif + +#ifndef smp_mb__before_atomic_dec +static inline void __deprecated smp_mb__before_atomic_dec(void) +{ + extern void __smp_mb__before_atomic(void); + __smp_mb__before_atomic(); +} +#endif + +#ifndef smp_mb__after_atomic_dec +static inline void __deprecated smp_mb__after_atomic_dec(void) +{ + extern void __smp_mb__after_atomic(void); + __smp_mb__after_atomic(); +} +#endif + /** * atomic_add_unless - add unless the number is already a given value * @v: pointer of type atomic_t diff --git a/include/linux/audit.h b/include/linux/audit.h index 22cfddb7556631..1ae00891aff9ba 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -109,12 +109,13 @@ extern void audit_log_session_info(struct audit_buffer *ab); #endif #ifdef CONFIG_AUDITSYSCALL +#include /* for syscall_get_arch() */ + /* These are defined in auditsc.c */ /* Public API */ extern int audit_alloc(struct task_struct *task); extern void __audit_free(struct task_struct *task); -extern void __audit_syscall_entry(int arch, - int major, unsigned long a0, unsigned long a1, +extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3); extern void __audit_syscall_exit(int ret_success, long ret_value); extern struct filename *__audit_reusename(const __user char *uptr); @@ -141,12 +142,12 @@ static inline void audit_free(struct task_struct *task) if (unlikely(task->audit_context)) __audit_free(task); } -static inline void audit_syscall_entry(int arch, int major, unsigned long a0, +static inline void audit_syscall_entry(int major, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3) { if (unlikely(current->audit_context)) - __audit_syscall_entry(arch, major, a0, a1, a2, a3); + __audit_syscall_entry(major, a0, a1, a2, a3); } static inline void audit_syscall_exit(void *pt_regs) { @@ -322,7 +323,7 @@ static inline int audit_alloc(struct task_struct *task) } static inline void audit_free(struct task_struct *task) { } -static inline void audit_syscall_entry(int arch, int major, unsigned long a0, +static inline void audit_syscall_entry(int major, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3) { } diff --git a/include/linux/bio.h b/include/linux/bio.h index bba5508269219a..5a645769f020f9 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -333,7 +333,7 @@ static inline struct bio *bio_next_split(struct bio *bio, int sectors, extern struct bio_set *bioset_create(unsigned int, unsigned int); extern void bioset_free(struct bio_set *); -extern mempool_t *biovec_create_pool(struct bio_set *bs, int pool_entries); +extern mempool_t *biovec_create_pool(int pool_entries); extern struct bio *bio_alloc_bioset(gfp_t, int, struct bio_set *); extern void bio_put(struct bio *); diff --git a/include/linux/bitops.h b/include/linux/bitops.h index be5fd38bd5a05d..cbc5833fb2216e 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -32,6 +32,26 @@ extern unsigned long __sw_hweight64(__u64 w); */ #include +/* + * Provide __deprecated wrappers for the new interface, avoid flag day changes. + * We need the ugly external functions to break header recursion hell. + */ +#ifndef smp_mb__before_clear_bit +static inline void __deprecated smp_mb__before_clear_bit(void) +{ + extern void __smp_mb__before_atomic(void); + __smp_mb__before_atomic(); +} +#endif + +#ifndef smp_mb__after_clear_bit +static inline void __deprecated smp_mb__after_clear_bit(void) +{ + extern void __smp_mb__after_atomic(void); + __smp_mb__after_atomic(); +} +#endif + #define for_each_set_bit(bit, addr, size) \ for ((bit) = find_first_bit((addr), (size)); \ (bit) < (size); \ diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 0120451545d8d2..f83d15f6e1c184 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -18,7 +18,11 @@ struct blk_mq_hw_ctx { } ____cacheline_aligned_in_smp; unsigned long state; /* BLK_MQ_S_* flags */ - struct delayed_work delayed_work; + struct delayed_work run_work; + struct delayed_work delay_work; + cpumask_var_t cpumask; + int next_cpu; + int next_cpu_batch; unsigned long flags; /* BLK_MQ_F_* flags */ @@ -27,13 +31,13 @@ struct blk_mq_hw_ctx { void *driver_data; - unsigned int nr_ctx; - struct blk_mq_ctx **ctxs; unsigned int nr_ctx_map; unsigned long *ctx_map; + unsigned int nr_ctx; + struct blk_mq_ctx **ctxs; + + unsigned int wait_index; - struct request **rqs; - struct list_head page_list; struct blk_mq_tags *tags; unsigned long queued; @@ -41,7 +45,6 @@ struct blk_mq_hw_ctx { #define BLK_MQ_MAX_DISPATCH_ORDER 10 unsigned long dispatched[BLK_MQ_MAX_DISPATCH_ORDER]; - unsigned int queue_depth; unsigned int numa_node; unsigned int cmd_size; /* per-request extra data */ @@ -49,7 +52,7 @@ struct blk_mq_hw_ctx { struct kobject kobj; }; -struct blk_mq_reg { +struct blk_mq_tag_set { struct blk_mq_ops *ops; unsigned int nr_hw_queues; unsigned int queue_depth; @@ -58,14 +61,22 @@ struct blk_mq_reg { int numa_node; unsigned int timeout; unsigned int flags; /* BLK_MQ_F_* */ + void *driver_data; + + struct blk_mq_tags **tags; }; typedef int (queue_rq_fn)(struct blk_mq_hw_ctx *, struct request *); typedef struct blk_mq_hw_ctx *(map_queue_fn)(struct request_queue *, const int); -typedef struct blk_mq_hw_ctx *(alloc_hctx_fn)(struct blk_mq_reg *,unsigned int); +typedef struct blk_mq_hw_ctx *(alloc_hctx_fn)(struct blk_mq_tag_set *, + unsigned int); typedef void (free_hctx_fn)(struct blk_mq_hw_ctx *, unsigned int); typedef int (init_hctx_fn)(struct blk_mq_hw_ctx *, void *, unsigned int); typedef void (exit_hctx_fn)(struct blk_mq_hw_ctx *, unsigned int); +typedef int (init_request_fn)(void *, struct request *, unsigned int, + unsigned int, unsigned int); +typedef void (exit_request_fn)(void *, struct request *, unsigned int, + unsigned int); struct blk_mq_ops { /* @@ -98,6 +109,14 @@ struct blk_mq_ops { */ init_hctx_fn *init_hctx; exit_hctx_fn *exit_hctx; + + /* + * Called for every command allocated by the block layer to allow + * the driver to set up driver specific data. + * Ditto for exit/teardown. + */ + init_request_fn *init_request; + exit_request_fn *exit_request; }; enum { @@ -107,18 +126,20 @@ enum { BLK_MQ_F_SHOULD_MERGE = 1 << 0, BLK_MQ_F_SHOULD_SORT = 1 << 1, - BLK_MQ_F_SHOULD_IPI = 1 << 2, BLK_MQ_S_STOPPED = 0, BLK_MQ_MAX_DEPTH = 2048, + + BLK_MQ_CPU_WORK_BATCH = 8, }; -struct request_queue *blk_mq_init_queue(struct blk_mq_reg *, void *); +struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *); int blk_mq_register_disk(struct gendisk *); void blk_mq_unregister_disk(struct gendisk *); -int blk_mq_init_commands(struct request_queue *, int (*init)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data); -void blk_mq_free_commands(struct request_queue *, void (*free)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data); + +int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set); +void blk_mq_free_tag_set(struct blk_mq_tag_set *set); void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule); @@ -128,26 +149,25 @@ void blk_mq_free_request(struct request *rq); bool blk_mq_can_queue(struct blk_mq_hw_ctx *); struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp); struct request *blk_mq_alloc_reserved_request(struct request_queue *q, int rw, gfp_t gfp); -struct request *blk_mq_rq_from_tag(struct request_queue *q, unsigned int tag); +struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag); struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *, const int ctx_index); -struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_reg *, unsigned int); +struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_tag_set *, unsigned int); void blk_mq_free_single_hw_queue(struct blk_mq_hw_ctx *, unsigned int); -bool blk_mq_end_io_partial(struct request *rq, int error, - unsigned int nr_bytes); -static inline void blk_mq_end_io(struct request *rq, int error) -{ - bool done = !blk_mq_end_io_partial(rq, error, blk_rq_bytes(rq)); - BUG_ON(!done); -} +void blk_mq_end_io(struct request *rq, int error); +void __blk_mq_end_io(struct request *rq, int error); + +void blk_mq_requeue_request(struct request *rq); void blk_mq_complete_request(struct request *rq); void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx); void blk_mq_start_hw_queue(struct blk_mq_hw_ctx *hctx); void blk_mq_stop_hw_queues(struct request_queue *q); -void blk_mq_start_stopped_hw_queues(struct request_queue *q); +void blk_mq_start_hw_queues(struct request_queue *q); +void blk_mq_start_stopped_hw_queues(struct request_queue *q, bool async); +void blk_mq_delay_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs); /* * Driver command data is immediately after the request. So subtract request @@ -162,12 +182,6 @@ static inline void *blk_mq_rq_to_pdu(struct request *rq) return (void *) rq + sizeof(*rq); } -static inline struct request *blk_mq_tag_to_rq(struct blk_mq_hw_ctx *hctx, - unsigned int tag) -{ - return hctx->rqs[tag]; -} - #define queue_for_each_hw_ctx(q, hctx, i) \ for ((i) = 0; (i) < (q)->nr_hw_queues && \ ({ hctx = (q)->queue_hw_ctx[i]; 1; }); (i)++) diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index aa0eaa2d0bd858..86df13b97160eb 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -5,8 +5,6 @@ #ifndef __LINUX_BLK_TYPES_H #define __LINUX_BLK_TYPES_H -#ifdef CONFIG_BLOCK - #include struct bio_set; @@ -28,6 +26,8 @@ struct bio_vec { unsigned int bv_offset; }; +#ifdef CONFIG_BLOCK + struct bvec_iter { sector_t bi_sector; /* device address in 512 byte sectors */ diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 6d2de38445ec04..1f1ecc71161212 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -90,15 +90,16 @@ enum rq_cmd_type_bits { #define BLK_MAX_CDB 16 /* - * try to put the fields that are referenced together in the same cacheline. - * if you modify this structure, be sure to check block/blk-core.c:blk_rq_init() - * as well! + * Try to put the fields that are referenced together in the same cacheline. + * + * If you modify this structure, make sure to update blk_rq_init() and + * especially blk_mq_rq_ctx_init() to take care of the added fields. */ struct request { struct list_head queuelist; union { struct call_single_data csd; - struct work_struct mq_flush_work; + struct work_struct requeue_work; unsigned long fifo_time; }; @@ -178,7 +179,6 @@ struct request { unsigned short ioprio; void *special; /* opaque pointer available for LLD use */ - char *buffer; /* kaddr of the current segment if available */ int tag; int errors; @@ -613,6 +613,15 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define rq_data_dir(rq) (((rq)->cmd_flags & 1) != 0) +/* + * Driver can handle struct request, if it either has an old style + * request_fn defined, or is blk-mq based. + */ +static inline bool queue_is_rq_based(struct request_queue *q) +{ + return q->request_fn || q->mq_ops; +} + static inline unsigned int blk_queue_cluster(struct request_queue *q) { return q->limits.cluster; @@ -937,6 +946,7 @@ extern struct request *blk_fetch_request(struct request_queue *q); */ extern bool blk_update_request(struct request *rq, int error, unsigned int nr_bytes); +extern void blk_finish_request(struct request *rq, int error); extern bool blk_end_request(struct request *rq, int error, unsigned int nr_bytes); extern void blk_end_request_all(struct request *rq, int error); @@ -1102,7 +1112,8 @@ static inline bool blk_needs_flush_plug(struct task_struct *tsk) /* * tag stuff */ -#define blk_rq_tagged(rq) ((rq)->cmd_flags & REQ_QUEUED) +#define blk_rq_tagged(rq) \ + ((rq)->mq_ctx || ((rq)->cmd_flags & REQ_QUEUED)) extern int blk_queue_start_tag(struct request_queue *, struct request *); extern struct request *blk_queue_find_tag(struct request_queue *, int); extern void blk_queue_end_tag(struct request_queue *, struct request *); @@ -1370,8 +1381,9 @@ static inline void put_dev_sector(Sector p) } struct work_struct; -int kblockd_schedule_work(struct request_queue *q, struct work_struct *work); -int kblockd_schedule_delayed_work(struct request_queue *q, struct delayed_work *dwork, unsigned long delay); +int kblockd_schedule_work(struct work_struct *work); +int kblockd_schedule_delayed_work(struct delayed_work *dwork, unsigned long delay); +int kblockd_schedule_delayed_work_on(int cpu, struct delayed_work *dwork, unsigned long delay); #ifdef CONFIG_BLK_CGROUP /* diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index e05c7ecdb24d13..324329ceea1e89 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -276,7 +276,7 @@ static inline void get_bh(struct buffer_head *bh) static inline void put_bh(struct buffer_head *bh) { - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_dec(&bh->b_count); } diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 2f49aa4c4f7f1d..279b0afac1c112 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -222,8 +222,6 @@ extern void ceph_copy_to_page_vector(struct page **pages, extern void ceph_copy_from_page_vector(struct page **pages, void *data, loff_t off, size_t len); -extern int ceph_copy_page_vector_to_user(struct page **pages, void __user *data, - loff_t off, size_t len); extern void ceph_zero_page_vector_range(int off, int len, struct page **pages); diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index c2515851c1aa20..f482f95c2c7281 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -21,6 +21,7 @@ #include #include #include +#include #ifdef CONFIG_CGROUPS @@ -61,7 +62,13 @@ struct cgroup_subsys_state { /* the parent css */ struct cgroup_subsys_state *parent; - unsigned long flags; + /* + * Subsys-unique ID. 0 is unused and root is always 1. The + * matching css can be looked up using css_from_id(). + */ + int id; + + unsigned int flags; /* percpu_ref killing and RCU release */ struct rcu_head rcu_head; @@ -133,8 +140,6 @@ enum { * specified at mount time and thus is implemented here. */ CGRP_CPUSET_CLONE_CHILDREN, - /* see the comment above CGRP_ROOT_SANE_BEHAVIOR for details */ - CGRP_SANE_BEHAVIOR, }; struct cgroup { @@ -143,8 +148,8 @@ struct cgroup { /* * idr allocated in-hierarchy ID. * - * The ID of the root cgroup is always 0, and a new cgroup - * will be assigned with a smallest available ID. + * ID 0 is not used, the ID of the root cgroup is always 1, and a + * new cgroup will be assigned with a smallest available ID. * * Allocating/Removing ID must be protected by cgroup_mutex. */ @@ -153,6 +158,14 @@ struct cgroup { /* the number of attached css's */ int nr_css; + /* + * If this cgroup contains any tasks, it contributes one to + * populated_cnt. All children with non-zero popuplated_cnt of + * their own contribute one. The count is zero iff there's no task + * in this cgroup or its subtree. + */ + int populated_cnt; + atomic_t refcnt; /* @@ -164,6 +177,8 @@ struct cgroup { struct cgroup *parent; /* my parent */ struct kernfs_node *kn; /* cgroup kernfs entry */ + struct kernfs_node *control_kn; /* kn for "cgroup.subtree_control" */ + struct kernfs_node *populated_kn; /* kn for "cgroup.subtree_populated" */ /* * Monotonically increasing unique serial number which defines a @@ -173,8 +188,8 @@ struct cgroup { */ u64 serial_nr; - /* The bitmask of subsystems attached to this cgroup */ - unsigned long subsys_mask; + /* the bitmask of subsystems enabled on the child cgroups */ + unsigned int child_subsys_mask; /* Private pointers for each registered subsystem */ struct cgroup_subsys_state __rcu *subsys[CGROUP_SUBSYS_COUNT]; @@ -187,6 +202,15 @@ struct cgroup { */ struct list_head cset_links; + /* + * On the default hierarchy, a css_set for a cgroup with some + * susbsys disabled will point to css's which are associated with + * the closest ancestor which has the subsys enabled. The + * following lists all css_sets which point to this cgroup's css + * for the given subsystem. + */ + struct list_head e_csets[CGROUP_SUBSYS_COUNT]; + /* * Linked list running through all cgroups that can * potentially be reaped by the release agent. Protected by @@ -207,6 +231,9 @@ struct cgroup { /* For css percpu_ref killing and RCU-protected deletion */ struct rcu_head rcu_head; struct work_struct destroy_work; + + /* used to wait for offlining of csses */ + wait_queue_head_t offline_waitq; }; #define MAX_CGROUP_ROOT_NAMELEN 64 @@ -250,6 +277,12 @@ enum { * * - "cgroup.clone_children" is removed. * + * - "cgroup.subtree_populated" is available. Its value is 0 if + * the cgroup and its descendants contain no task; otherwise, 1. + * The file also generates kernfs notification which can be + * monitored through poll and [di]notify when the value of the + * file changes. + * * - If mount is requested with sane_behavior but without any * subsystem, the default unified hierarchy is mounted. * @@ -282,6 +315,9 @@ enum { struct cgroup_root { struct kernfs_root *kf_root; + /* The bitmask of subsystems attached to this hierarchy */ + unsigned int subsys_mask; + /* Unique id for this hierarchy. */ int hierarchy_id; @@ -295,7 +331,7 @@ struct cgroup_root { struct list_head root_list; /* Hierarchy-specific flags */ - unsigned long flags; + unsigned int flags; /* IDs for cgroups in this hierarchy */ struct idr cgroup_idr; @@ -342,6 +378,9 @@ struct css_set { */ struct list_head cgrp_links; + /* the default cgroup associated with this css_set */ + struct cgroup *dfl_cgrp; + /* * Set of subsystem states, one for each subsystem. This array is * immutable after creation apart from the init_css_set during @@ -366,6 +405,15 @@ struct css_set { struct cgroup *mg_src_cgrp; struct css_set *mg_dst_cset; + /* + * On the default hierarhcy, ->subsys[ssid] may point to a css + * attached to an ancestor instead of the cgroup this css_set is + * associated with. The following node is anchored at + * ->subsys[ssid]->cgroup->e_csets[ssid] and provides a way to + * iterate through all css's attached to a given cgroup. + */ + struct list_head e_cset_node[CGROUP_SUBSYS_COUNT]; + /* For RCU-protected deletion */ struct rcu_head rcu_head; }; @@ -611,6 +659,9 @@ struct cgroup_subsys { /* link to parent, protected by cgroup_lock() */ struct cgroup_root *root; + /* idr for css->id */ + struct idr css_idr; + /* * List of cftypes. Each entry is the first entry of an array * terminated by zero length name. @@ -821,9 +872,14 @@ css_next_descendant_post(struct cgroup_subsys_state *pos, /* A css_task_iter should be treated as an opaque object */ struct css_task_iter { - struct cgroup_subsys_state *origin_css; - struct list_head *cset_link; - struct list_head *task; + struct cgroup_subsys *ss; + + struct list_head *cset_pos; + struct list_head *cset_head; + + struct list_head *task_pos; + struct list_head *tasks_head; + struct list_head *mg_tasks_head; }; void css_task_iter_start(struct cgroup_subsys_state *css, diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 511917416fb003..59e2eb58f555ef 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -312,6 +312,8 @@ struct clk_div_table { * of this register, and mask of divider bits are in higher 16-bit of this * register. While setting the divider bits, higher 16-bit should also be * updated to indicate changing divider bits. + * CLK_DIVIDER_ROUND_CLOSEST - Makes the best calculated divider to be rounded + * to the closest integer instead of the up one. */ struct clk_divider { struct clk_hw hw; @@ -327,6 +329,7 @@ struct clk_divider { #define CLK_DIVIDER_POWER_OF_TWO BIT(1) #define CLK_DIVIDER_ALLOW_ZERO BIT(2) #define CLK_DIVIDER_HIWORD_MASK BIT(3) +#define CLK_DIVIDER_ROUND_CLOSEST BIT(4) extern const struct clk_ops clk_divider_ops; struct clk *clk_register_divider(struct device *dev, const char *name, diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h new file mode 100644 index 00000000000000..1ef5c899e45803 --- /dev/null +++ b/include/linux/clk/sunxi.h @@ -0,0 +1,22 @@ +/* + * Copyright 2013 - Hans de Goede + * + * 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. + */ + +#ifndef __LINUX_CLK_SUNXI_H_ +#define __LINUX_CLK_SUNXI_H_ + +#include + +void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output); + +#endif diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h index 5529c52394219a..ba147a1727e6d2 100644 --- a/include/linux/compiler-intel.h +++ b/include/linux/compiler-intel.h @@ -13,12 +13,9 @@ /* Intel ECC compiler doesn't support gcc specific asm stmts. * It uses intrinsics to do the equivalent things. */ -#undef barrier #undef RELOC_HIDE #undef OPTIMIZER_HIDE_VAR -#define barrier() __memory_barrier() - #define RELOC_HIDE(ptr, off) \ ({ unsigned long __ptr; \ __ptr = (unsigned long) (ptr); \ diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 5ac9218ac78bb6..0d9d485de79b3b 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -373,7 +373,9 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); /* Ignore/forbid kprobes attach on very low level functions marked by this attribute: */ #ifdef CONFIG_KPROBES # define __kprobes __attribute__((__section__(".kprobes.text"))) +# define nokprobe_inline __always_inline #else # define __kprobes +# define nokprobe_inline inline #endif #endif /* __LINUX_COMPILER_H */ diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 5ae5100c1f2457..3f458896d45c97 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -110,6 +110,7 @@ struct cpufreq_policy { bool transition_ongoing; /* Tracks transition status */ spinlock_t transition_lock; wait_queue_head_t transition_wait; + struct task_struct *transition_task; /* Task which is doing the transition */ }; /* Only for ACPI */ @@ -468,6 +469,55 @@ struct cpufreq_frequency_table { * order */ }; +#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_PM_OPP) +int dev_pm_opp_init_cpufreq_table(struct device *dev, + struct cpufreq_frequency_table **table); +void dev_pm_opp_free_cpufreq_table(struct device *dev, + struct cpufreq_frequency_table **table); +#else +static inline int dev_pm_opp_init_cpufreq_table(struct device *dev, + struct cpufreq_frequency_table + **table) +{ + return -EINVAL; +} + +static inline void dev_pm_opp_free_cpufreq_table(struct device *dev, + struct cpufreq_frequency_table + **table) +{ +} +#endif + +static inline bool cpufreq_next_valid(struct cpufreq_frequency_table **pos) +{ + while ((*pos)->frequency != CPUFREQ_TABLE_END) + if ((*pos)->frequency != CPUFREQ_ENTRY_INVALID) + return true; + else + (*pos)++; + return false; +} + +/* + * cpufreq_for_each_entry - iterate over a cpufreq_frequency_table + * @pos: the cpufreq_frequency_table * to use as a loop cursor. + * @table: the cpufreq_frequency_table * to iterate over. + */ + +#define cpufreq_for_each_entry(pos, table) \ + for (pos = table; pos->frequency != CPUFREQ_TABLE_END; pos++) + +/* + * cpufreq_for_each_valid_entry - iterate over a cpufreq_frequency_table + * excluding CPUFREQ_ENTRY_INVALID frequencies. + * @pos: the cpufreq_frequency_table * to use as a loop cursor. + * @table: the cpufreq_frequency_table * to iterate over. + */ + +#define cpufreq_for_each_valid_entry(pos, table) \ + for (pos = table; cpufreq_next_valid(&pos); pos++) + int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table); diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index b0238cba440b4d..c51a436135c485 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -120,8 +120,6 @@ struct cpuidle_driver { #ifdef CONFIG_CPU_IDLE extern void disable_cpuidle(void); -extern int cpuidle_enabled(struct cpuidle_driver *drv, - struct cpuidle_device *dev); extern int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev); extern int cpuidle_enter(struct cpuidle_driver *drv, @@ -145,13 +143,11 @@ extern void cpuidle_resume(void); extern int cpuidle_enable_device(struct cpuidle_device *dev); extern void cpuidle_disable_device(struct cpuidle_device *dev); extern int cpuidle_play_dead(void); +extern void cpuidle_use_deepest_state(bool enable); extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev); #else static inline void disable_cpuidle(void) { } -static inline int cpuidle_enabled(struct cpuidle_driver *drv, - struct cpuidle_device *dev) -{return -ENODEV; } static inline int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) {return -ENODEV; } @@ -180,6 +176,7 @@ static inline int cpuidle_enable_device(struct cpuidle_device *dev) {return -ENODEV; } static inline void cpuidle_disable_device(struct cpuidle_device *dev) { } static inline int cpuidle_play_dead(void) {return -ENODEV; } +static inline void cpuidle_use_deepest_state(bool enable) {} static inline struct cpuidle_driver *cpuidle_get_cpu_driver( struct cpuidle_device *dev) {return NULL; } #endif diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 3c7ec327ebd2ee..844289d8a48bc7 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -252,7 +252,7 @@ extern struct dentry * d_obtain_alias(struct inode *); extern void shrink_dcache_sb(struct super_block *); extern void shrink_dcache_parent(struct dentry *); extern void shrink_dcache_for_umount(struct super_block *); -extern int d_invalidate(struct dentry *); +extern void d_invalidate(struct dentry *); /* only used at mount-time */ extern struct dentry * d_make_root(struct inode *); @@ -267,7 +267,6 @@ extern void d_prune_aliases(struct inode *); /* test whether we have any submounts in a subdir tree */ extern int have_submounts(struct dentry *); -extern int check_submounts_and_drop(struct dentry *); /* * This adds the entry to the hash queues. diff --git a/include/linux/dell-led.h b/include/linux/dell-led.h new file mode 100644 index 00000000000000..7009b8bec77bb4 --- /dev/null +++ b/include/linux/dell-led.h @@ -0,0 +1,10 @@ +#ifndef __DELL_LED_H__ +#define __DELL_LED_H__ + +enum { + DELL_LED_MICMUTE, +}; + +int dell_app_wmi_led_set(int whichled, int on); + +#endif diff --git a/include/linux/device.h b/include/linux/device.h index d1d1c055b48e2e..67f003a18220c8 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -623,6 +623,8 @@ static inline void *devm_kcalloc(struct device *dev, } extern void devm_kfree(struct device *dev, void *p); extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp); +extern void *devm_kmemdup(struct device *dev, const void *src, size_t len, + gfp_t gfp); void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res); void __iomem *devm_request_and_ioremap(struct device *dev, @@ -685,6 +687,7 @@ struct acpi_dev_node { * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all * hardware supports 64-bit addresses for consistent allocations * such descriptors. + * @dma_pfn_offset: offset of DMA memory range relatively of RAM * @dma_parms: A low level driver may set these to teach IOMMU code about * segment limitations. * @dma_pools: Dma pools (if dma'ble device). @@ -750,6 +753,7 @@ struct device { not all hardware supports 64 bit addresses for consistent allocations such descriptors. */ + unsigned long dma_pfn_offset; struct device_dma_parameters *dma_parms; diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index fd4aee29ad10ca..c7d9b1b14ce73c 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -123,6 +123,13 @@ static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask) extern u64 dma_get_required_mask(struct device *dev); +#ifndef set_arch_dma_coherent_ops +static inline int set_arch_dma_coherent_ops(struct device *dev) +{ + return 0; +} +#endif + static inline unsigned int dma_get_max_seg_size(struct device *dev) { return dev->dma_parms ? dev->dma_parms->max_segment_size : 65536; diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 8300fb87b84ac1..72cb0ddb9678d2 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -429,6 +429,7 @@ typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param); typedef void (*dma_async_tx_callback)(void *dma_async_param); struct dmaengine_unmap_data { + u8 map_cnt; u8 to_cnt; u8 from_cnt; u8 bidi_cnt; diff --git a/include/linux/efi.h b/include/linux/efi.h index 6c100ff0cae4b6..6a4d8e27d1d7f2 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -863,6 +863,12 @@ extern int efi_set_rtc_mmss(const struct timespec *now); extern void efi_reserve_boot_services(void); extern struct efi_memory_map memmap; +/* Iterate through an efi_memory_map */ +#define for_each_efi_memory_desc(m, md) \ + for ((md) = (m)->map; \ + (md) <= (efi_memory_desc_t *)((m)->map_end - (m)->desc_size); \ + (md) = (void *)(md) + (m)->desc_size) + /** * efi_range_is_wc - check the WC bit on an address range * @start: starting kvirt address @@ -1033,8 +1039,10 @@ struct efivars { * and we use a page for reading/writing. */ +#define EFI_VAR_NAME_LEN 1024 + struct efi_variable { - efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; + efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)]; efi_guid_t VendorGuid; unsigned long DataSize; __u8 Data[1024]; @@ -1116,7 +1124,7 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, struct list_head *head, bool remove); -bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len); +bool efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len); extern struct work_struct efivar_work; void efivar_run_worker(void); diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 0a114d05f68d35..212f537fc686a8 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -154,13 +154,23 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings) * @reset: Reset (part of) the device, as specified by a bitmask of * flags from &enum ethtool_reset_flags. Returns a negative * error code or zero. + * @get_rxfh_key_size: Get the size of the RX flow hash key. + * Returns zero if not supported for this specific device. * @get_rxfh_indir_size: Get the size of the RX flow hash indirection table. * Returns zero if not supported for this specific device. * @get_rxfh_indir: Get the contents of the RX flow hash indirection table. * Will not be called if @get_rxfh_indir_size returns zero. + * @get_rxfh: Get the contents of the RX flow hash indirection table and hash + * key. + * Will not be called if @get_rxfh_indir_size and @get_rxfh_key_size + * returns zero. * Returns a negative error code or zero. * @set_rxfh_indir: Set the contents of the RX flow hash indirection table. * Will not be called if @get_rxfh_indir_size returns zero. + * @set_rxfh: Set the contents of the RX flow hash indirection table and + * hash key. + * Will not be called if @get_rxfh_indir_size and @get_rxfh_key_size + * returns zero. * Returns a negative error code or zero. * @get_channels: Get number of channels. * @set_channels: Set number of channels. Returns a negative error code or @@ -232,7 +242,10 @@ struct ethtool_ops { int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); int (*flash_device)(struct net_device *, struct ethtool_flash *); int (*reset)(struct net_device *, u32 *); + u32 (*get_rxfh_key_size)(struct net_device *); u32 (*get_rxfh_indir_size)(struct net_device *); + int (*get_rxfh)(struct net_device *, u32 *, u8 *); + int (*set_rxfh)(struct net_device *, u32 *, u8 *); int (*get_rxfh_indir)(struct net_device *, u32 *); int (*set_rxfh_indir)(struct net_device *, const u32 *); void (*get_channels)(struct net_device *, struct ethtool_channels *); diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index df53e1753a76bf..8c03f71307c6d2 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -146,6 +146,9 @@ struct f2fs_extent { #define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */ #define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */ +#define ADDRS_PER_PAGE(page, fi) \ + (IS_INODE(page) ? ADDRS_PER_INODE(fi) : ADDRS_PER_BLOCK) + #define NODE_DIR1_BLOCK (DEF_ADDRS_PER_INODE + 1) #define NODE_DIR2_BLOCK (DEF_ADDRS_PER_INODE + 2) #define NODE_IND1_BLOCK (DEF_ADDRS_PER_INODE + 3) diff --git a/include/linux/fb.h b/include/linux/fb.h index fe6ac956550e4e..b6bfda99add3c7 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -47,6 +47,7 @@ struct device_node; #define FB_MISC_PRIM_COLOR 1 #define FB_MISC_1ST_DETAIL 2 /* First Detailed Timing is preferred */ +#define FB_MISC_HDMI 4 struct fb_chroma { __u32 redx; /* in fraction of 1024 */ __u32 greenx; @@ -641,7 +642,7 @@ static inline void unlock_fb_info(struct fb_info *info) static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height) { - int i, j; + u32 i, j; d_pitch -= s_pitch; diff --git a/include/linux/filter.h b/include/linux/filter.h index 024fd03e5d182d..ed1efab10b8fb7 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -37,16 +37,50 @@ #define BPF_CALL 0x80 /* function call */ #define BPF_EXIT 0x90 /* function return */ +/* Placeholder/dummy for 0 */ +#define BPF_0 0 + +/* Register numbers */ +enum { + BPF_REG_0 = 0, + BPF_REG_1, + BPF_REG_2, + BPF_REG_3, + BPF_REG_4, + BPF_REG_5, + BPF_REG_6, + BPF_REG_7, + BPF_REG_8, + BPF_REG_9, + BPF_REG_10, + __MAX_BPF_REG, +}; + /* BPF has 10 general purpose 64-bit registers and stack frame. */ -#define MAX_BPF_REG 11 +#define MAX_BPF_REG __MAX_BPF_REG + +/* ArgX, context and stack frame pointer register positions. Note, + * Arg1, Arg2, Arg3, etc are used as argument mappings of function + * calls in BPF_CALL instruction. + */ +#define BPF_REG_ARG1 BPF_REG_1 +#define BPF_REG_ARG2 BPF_REG_2 +#define BPF_REG_ARG3 BPF_REG_3 +#define BPF_REG_ARG4 BPF_REG_4 +#define BPF_REG_ARG5 BPF_REG_5 +#define BPF_REG_CTX BPF_REG_6 +#define BPF_REG_FP BPF_REG_10 + +/* Additional register mappings for converted user programs. */ +#define BPF_REG_A BPF_REG_0 +#define BPF_REG_X BPF_REG_7 +#define BPF_REG_TMP BPF_REG_8 /* BPF program can access up to 512 bytes of stack space. */ #define MAX_BPF_STACK 512 -/* Arg1, context and stack frame pointer register positions. */ -#define ARG1_REG 1 -#define CTX_REG 6 -#define FP_REG 10 +/* Macro to invoke filter function. */ +#define SK_RUN_FILTER(filter, ctx) (*filter->bpf_func)(ctx, filter->insnsi) struct sock_filter_int { __u8 code; /* opcode */ @@ -97,9 +131,6 @@ static inline unsigned int sk_filter_size(unsigned int proglen) #define sk_filter_proglen(fprog) \ (fprog->len * sizeof(fprog->filter[0])) -#define SK_RUN_FILTER(filter, ctx) \ - (*filter->bpf_func)(ctx, filter->insnsi) - int sk_filter(struct sock *sk, struct sk_buff *skb); u32 sk_run_filter_int_seccomp(const struct seccomp_data *ctx, @@ -223,6 +254,7 @@ enum { BPF_S_ANC_VLAN_TAG, BPF_S_ANC_VLAN_TAG_PRESENT, BPF_S_ANC_PAY_OFFSET, + BPF_S_ANC_RANDOM, }; #endif /* __LINUX_FILTER_H__ */ diff --git a/include/linux/fs.h b/include/linux/fs.h index b7cda7d95ea0da..7d8978dfc48173 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -128,6 +128,10 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, #define FMODE_ATOMIC_POS ((__force fmode_t)0x8000) /* Write access to underlying fs */ #define FMODE_WRITER ((__force fmode_t)0x10000) +/* Has read method(s) */ +#define FMODE_CAN_READ ((__force fmode_t)0x20000) +/* Has write method(s) */ +#define FMODE_CAN_WRITE ((__force fmode_t)0x40000) /* File was opened by fanotify and shouldn't generate fanotify events */ #define FMODE_NONOTIFY ((__force fmode_t)0x1000000) @@ -343,8 +347,7 @@ struct address_space_operations { void (*invalidatepage) (struct page *, unsigned int, unsigned int); int (*releasepage) (struct page *, gfp_t); void (*freepage)(struct page *); - ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov, - loff_t offset, unsigned long nr_segs); + ssize_t (*direct_IO)(int, struct kiocb *, struct iov_iter *iter, loff_t offset); int (*get_xip_mem)(struct address_space *, pgoff_t, int, void **, unsigned long *); /* @@ -1448,6 +1451,8 @@ struct block_device_operations; #define HAVE_COMPAT_IOCTL 1 #define HAVE_UNLOCKED_IOCTL 1 +struct iov_iter; + struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); @@ -1455,6 +1460,8 @@ struct file_operations { ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); + ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); + ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); @@ -2408,20 +2415,18 @@ static inline int generic_file_remap_pages(struct vm_area_struct *vma, return 0; } int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk); -extern ssize_t generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t); -extern ssize_t __generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long); -extern ssize_t generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long, loff_t); -extern ssize_t generic_file_direct_write(struct kiocb *, const struct iovec *, - unsigned long *, loff_t, size_t, size_t); +extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *); +extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *); +extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *); +extern ssize_t generic_file_direct_write(struct kiocb *, struct iov_iter *, loff_t); extern ssize_t generic_perform_write(struct file *, struct iov_iter *, loff_t); extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos); extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); -extern int generic_segment_checks(const struct iovec *iov, - unsigned long *nr_segs, size_t *count, int access_flags); +extern ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos); +extern ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); /* fs/block_dev.c */ -extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos); +extern ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from); extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync); extern void block_sync_page(struct page *page); @@ -2431,7 +2436,7 @@ extern ssize_t generic_file_splice_read(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); extern ssize_t default_file_splice_read(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); -extern ssize_t generic_file_splice_write(struct pipe_inode_info *, +extern ssize_t iter_file_splice_write(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out, loff_t *, size_t len, unsigned int flags); @@ -2481,16 +2486,16 @@ enum { void dio_end_io(struct bio *bio, int error); ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, - struct block_device *bdev, const struct iovec *iov, loff_t offset, - unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io, + struct block_device *bdev, struct iov_iter *iter, loff_t offset, + get_block_t get_block, dio_iodone_t end_io, dio_submit_t submit_io, int flags); static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb, - struct inode *inode, const struct iovec *iov, loff_t offset, - unsigned long nr_segs, get_block_t get_block) + struct inode *inode, struct iov_iter *iter, loff_t offset, + get_block_t get_block) { - return __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, - offset, nr_segs, get_block, NULL, NULL, + return __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iter, + offset, get_block, NULL, NULL, DIO_LOCKING | DIO_SKIP_HOLES); } #endif diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index ae9504b4b67d30..7fe3ef15b625e6 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -62,9 +62,6 @@ typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip, * set in the flags member. * * ENABLED - set/unset when ftrace_ops is registered/unregistered - * GLOBAL - set manualy by ftrace_ops user to denote the ftrace_ops - * is part of the global tracers sharing the same filter - * via set_ftrace_* debugfs files. * DYNAMIC - set when ftrace_ops is registered to denote dynamically * allocated ftrace_ops which need special care * CONTROL - set manualy by ftrace_ops user to denote the ftrace_ops @@ -96,15 +93,14 @@ typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip, */ enum { FTRACE_OPS_FL_ENABLED = 1 << 0, - FTRACE_OPS_FL_GLOBAL = 1 << 1, - FTRACE_OPS_FL_DYNAMIC = 1 << 2, - FTRACE_OPS_FL_CONTROL = 1 << 3, - FTRACE_OPS_FL_SAVE_REGS = 1 << 4, - FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED = 1 << 5, - FTRACE_OPS_FL_RECURSION_SAFE = 1 << 6, - FTRACE_OPS_FL_STUB = 1 << 7, - FTRACE_OPS_FL_INITIALIZED = 1 << 8, - FTRACE_OPS_FL_DELETED = 1 << 9, + FTRACE_OPS_FL_DYNAMIC = 1 << 1, + FTRACE_OPS_FL_CONTROL = 1 << 2, + FTRACE_OPS_FL_SAVE_REGS = 1 << 3, + FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED = 1 << 4, + FTRACE_OPS_FL_RECURSION_SAFE = 1 << 5, + FTRACE_OPS_FL_STUB = 1 << 6, + FTRACE_OPS_FL_INITIALIZED = 1 << 7, + FTRACE_OPS_FL_DELETED = 1 << 8, }; /* diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 9f3c275e053efb..ec274e0f4ed28d 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -649,7 +649,7 @@ static inline void hd_ref_init(struct hd_struct *part) static inline void hd_struct_get(struct hd_struct *part) { atomic_inc(&part->ref); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } static inline int hd_struct_try_get(struct hd_struct *part) diff --git a/include/linux/goldfish.h b/include/linux/goldfish.h new file mode 100644 index 00000000000000..9cc28902b54cc6 --- /dev/null +++ b/include/linux/goldfish.h @@ -0,0 +1,15 @@ +#ifndef __LINUX_GOLDFISH_H +#define __LINUX_GOLDFISH_H + +/* Helpers for Goldfish virtual platform */ + +static inline void gf_write64(unsigned long data, + void __iomem *portl, void __iomem *porth) +{ + writel((u32)data, portl); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + writel(data>>32, porth); +#endif +} + +#endif /* __LINUX_GOLDFISH_H */ diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 1827b43966d96b..573e4f3243d052 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -51,7 +51,10 @@ struct seq_file; * format specifier for an unsigned int. It is substituted by the actual * number of the gpio. * @can_sleep: flag must be set iff get()/set() methods sleep, as they - * must while accessing GPIO expander chips over I2C or SPI + * must while accessing GPIO expander chips over I2C or SPI. This + * implies that if the chip supports IRQs, these IRQs need to be threaded + * as the chip access may sleep when e.g. reading out the IRQ status + * registers. * @exported: flags if the gpiochip is exported for use from sysfs. Private. * * A gpio_chip can help platforms abstract various sources of GPIOs so diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index a7e977ff4abf06..8b622468952c42 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -3,29 +3,53 @@ struct device; +/** + * struct gpio_keys_button - configuration parameters + * @code: input event code (KEY_*, SW_*) + * @gpio: %-1 if this key does not support gpio + * @active_low: %true indicates that button is considered + * depressed when gpio is low + * @desc: label that will be attached to button's gpio + * @type: input event type (%EV_KEY, %EV_SW, %EV_ABS) + * @wakeup: configure the button as a wake-up source + * @debounce_interval: debounce ticks interval in msecs + * @can_disable: %true indicates that userspace is allowed to + * disable button via sysfs + * @value: axis value for %EV_ABS + * @irq: Irq number in case of interrupt keys + */ struct gpio_keys_button { - /* Configuration parameters */ - unsigned int code; /* input event code (KEY_*, SW_*) */ - int gpio; /* -1 if this key does not support gpio */ + unsigned int code; + int gpio; int active_low; const char *desc; - unsigned int type; /* input event type (EV_KEY, EV_SW, EV_ABS) */ - int wakeup; /* configure the button as a wake-up source */ - int debounce_interval; /* debounce ticks interval in msecs */ + unsigned int type; + int wakeup; + int debounce_interval; bool can_disable; - int value; /* axis value for EV_ABS */ - unsigned int irq; /* Irq number in case of interrupt keys */ + int value; + unsigned int irq; }; +/** + * struct gpio_keys_platform_data - platform data for gpio_keys driver + * @buttons: pointer to array of &gpio_keys_button structures + * describing buttons attached to the device + * @nbuttons: number of elements in @buttons array + * @poll_interval: polling interval in msecs - for polling driver only + * @rep: enable input subsystem auto repeat + * @enable: platform hook for enabling the device + * @disable: platform hook for disabling the device + * @name: input device name + */ struct gpio_keys_platform_data { struct gpio_keys_button *buttons; int nbuttons; - unsigned int poll_interval; /* polling interval in msecs - - for polling driver only */ - unsigned int rep:1; /* enable input subsystem auto repeat */ + unsigned int poll_interval; + unsigned int rep:1; int (*enable)(struct device *dev); void (*disable)(struct device *dev); - const char *name; /* input device name */ + const char *name; }; #endif diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index b70cfd7ff29cab..51f7ccadf923c3 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -189,7 +189,7 @@ struct hid_sensor_common { struct hid_sensor_hub_device *hsdev; struct platform_device *pdev; unsigned usage_id; - bool data_ready; + atomic_t data_ready; struct iio_trigger *trigger; struct hid_sensor_hub_attribute_info poll; struct hid_sensor_hub_attribute_info report_state; @@ -223,4 +223,10 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, int hid_sensor_get_usage_index(struct hid_sensor_hub_device *hsdev, u32 report_id, int field_index, u32 usage_id); +int hid_sensor_format_scale(u32 usage_id, + struct hid_sensor_hub_attribute_info *attr_info, + int *val0, int *val1); + +s32 hid_sensor_read_poll_value(struct hid_sensor_common *st); + #endif diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 14ead9e8eda886..109f0e633e01f1 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -76,6 +76,7 @@ #define HID_USAGE_SENSOR_ORIENT_TILT_Y 0x200480 #define HID_USAGE_SENSOR_ORIENT_TILT_Z 0x200481 +#define HID_USAGE_SENSOR_DEVICE_ORIENTATION 0x20008A #define HID_USAGE_SENSOR_ORIENT_ROTATION_MATRIX 0x200482 #define HID_USAGE_SENSOR_ORIENT_QUATERNION 0x200483 #define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX 0x200484 diff --git a/include/linux/hid.h b/include/linux/hid.h index 720e3a10608cec..54f855b2c902eb 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -570,6 +570,8 @@ struct hid_descriptor { .bus = BUS_USB, .vendor = (ven), .product = (prod) #define HID_BLUETOOTH_DEVICE(ven, prod) \ .bus = BUS_BLUETOOTH, .vendor = (ven), .product = (prod) +#define HID_I2C_DEVICE(ven, prod) \ + .bus = BUS_I2C, .vendor = (ven), .product = (prod) #define HID_REPORT_ID(rep) \ .report_type = (rep) diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 2d7b4f139c32fa..08cfaff8a07231 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -696,6 +696,8 @@ struct vmbus_channel { * preserve the earlier behavior. */ u32 target_vp; + /* The corresponding CPUID in the guest */ + u32 target_cpu; /* * Support for sub-channels. For high performance devices, * it will be useful to have multiple sub-channels to support @@ -732,6 +734,11 @@ struct vmbus_channel { * Support per-channel state for use by vmbus drivers. */ void *per_channel_state; + /* + * To support per-cpu lookup mapping of relid to channel, + * link up channels based on their CPU affinity. + */ + struct list_head percpu_list; }; static inline void set_channel_read_state(struct vmbus_channel *c, bool state) diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 3c005eb3a0a4ba..96f51f0e00961c 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -269,6 +269,10 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable); int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable); +void st_sensors_power_enable(struct iio_dev *indio_dev); + +void st_sensors_power_disable(struct iio_dev *indio_dev); + int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr); int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable); diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 2752b1fd12be3e..651f9a0e2765fa 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -122,6 +122,19 @@ struct iio_channel int iio_read_channel_raw(struct iio_channel *chan, int *val); +/** + * iio_read_channel_average_raw() - read from a given channel + * @chan: The channel being queried. + * @val: Value read back. + * + * Note raw reads from iio channels are in adc counts and hence + * scale will need to be applied if standard units required. + * + * In opposit to the normal iio_read_channel_raw this function + * returns the average of multiple reads. + */ +int iio_read_channel_average_raw(struct iio_channel *chan, int *val); + /** * iio_read_channel_processed() - read processed value from a given channel * @chan: The channel being queried. diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 5f2d00e7e488a7..ccde91725f98c3 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -177,6 +177,12 @@ struct iio_event_spec { * shift: Shift right by this before masking out * realbits. * endianness: little or big endian + * repeat: Number of times real/storage bits + * repeats. When the repeat element is + * more than 1, then the type element in + * sysfs will show a repeat value. + * Otherwise, the number of repetitions is + * omitted. * @info_mask_separate: What information is to be exported that is specific to * this channel. * @info_mask_shared_by_type: What information is to be exported that is shared @@ -219,6 +225,7 @@ struct iio_chan_spec { u8 realbits; u8 storagebits; u8 shift; + u8 repeat; enum iio_endian endianness; } scan_type; long info_mask_separate; @@ -288,6 +295,8 @@ static inline s64 iio_get_time_ns(void) #define INDIO_ALL_BUFFER_MODES \ (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE) +#define INDIO_MAX_RAW_ELEMENTS 4 + struct iio_trigger; /* forward declaration */ struct iio_dev; @@ -302,6 +311,14 @@ struct iio_dev; * the channel in question. Return value will specify the * type of value returned by the device. val and val2 will * contain the elements making up the returned value. + * @read_raw_multi: function to return values from the device. + * mask specifies which value. Note 0 means a reading of + * the channel in question. Return value will specify the + * type of value returned by the device. vals pointer + * contain the elements making up the returned value. + * max_len specifies maximum number of elements + * vals pointer can contain. val_len is used to return + * length of valid elements in vals. * @write_raw: function to write a value to the device. * Parameters are the same as for read_raw. * @write_raw_get_fmt: callback function to query the expected @@ -328,6 +345,13 @@ struct iio_info { int *val2, long mask); + int (*read_raw_multi)(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int max_len, + int *vals, + int *val_len, + long mask); + int (*write_raw)(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 084d882fe01b9d..d480631eabc2a2 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -53,6 +53,9 @@ enum iio_modifier { IIO_MOD_LIGHT_RED, IIO_MOD_LIGHT_GREEN, IIO_MOD_LIGHT_BLUE, + IIO_MOD_QUATERNION, + IIO_MOD_TEMP_AMBIENT, + IIO_MOD_TEMP_OBJECT, }; enum iio_event_type { @@ -79,6 +82,7 @@ enum iio_event_direction { #define IIO_VAL_INT_PLUS_MICRO 2 #define IIO_VAL_INT_PLUS_NANO 3 #define IIO_VAL_INT_PLUS_MICRO_DB 4 +#define IIO_VAL_INT_MULTIPLE 5 #define IIO_VAL_FRACTIONAL 10 #define IIO_VAL_FRACTIONAL_LOG2 11 diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 97ac926c78a707..cb19f09d7e3e7b 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -272,6 +272,11 @@ static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m) return -EINVAL; } +static inline int irq_force_affinity(unsigned int irq, const struct cpumask *cpumask) +{ + return 0; +} + static inline int irq_can_set_affinity(unsigned int irq) { return 0; @@ -486,7 +491,7 @@ static inline int tasklet_trylock(struct tasklet_struct *t) static inline void tasklet_unlock(struct tasklet_struct *t) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(TASKLET_STATE_RUN, &(t)->state); } @@ -534,7 +539,7 @@ static inline void tasklet_hi_schedule_first(struct tasklet_struct *t) static inline void tasklet_disable_nosync(struct tasklet_struct *t) { atomic_inc(&t->count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } static inline void tasklet_disable(struct tasklet_struct *t) @@ -546,13 +551,13 @@ static inline void tasklet_disable(struct tasklet_struct *t) static inline void tasklet_enable(struct tasklet_struct *t) { - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_dec(&t->count); } static inline void tasklet_hi_enable(struct tasklet_struct *t) { - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_dec(&t->count); } diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 26e2661d393569..472c021a2d4f09 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -27,6 +27,8 @@ struct irq_desc; * @irq_count: stats field to detect stalled irqs * @last_unhandled: aging timer for unhandled count * @irqs_unhandled: stats field for spurious unhandled interrupts + * @threads_handled: stats field for deferred spurious detection of threaded handlers + * @threads_handled_last: comparator field for deferred spurious detection of theraded handlers * @lock: locking for SMP * @affinity_hint: hint to user space for preferred irq affinity * @affinity_notify: context for notification of affinity changes @@ -52,6 +54,8 @@ struct irq_desc { unsigned int irq_count; /* For detecting broken IRQs */ unsigned long last_unhandled; /* Aging timer for unhandled count */ unsigned int irqs_unhandled; + atomic_t threads_handled; + int threads_handled_last; raw_spinlock_t lock; struct cpumask *percpu_enabled; #ifdef CONFIG_SMP diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index b0122dc6f96a0a..589318b73e6155 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -144,6 +144,10 @@ struct kernfs_root { /* private fields, do not use outside kernfs proper */ struct ida ino_ida; struct kernfs_syscall_ops *syscall_ops; + + /* list of kernfs_super_info of this root, protected by kernfs_mutex */ + struct list_head supers; + wait_queue_head_t deactivate_waitq; }; diff --git a/include/linux/key.h b/include/linux/key.h index 80d677483e31f9..cd0abb8c9c33de 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -309,6 +309,17 @@ static inline key_serial_t key_serial(const struct key *key) extern void key_set_timeout(struct key *, unsigned); +/* + * The permissions required on a key that we're looking up. + */ +#define KEY_NEED_VIEW 0x01 /* Require permission to view attributes */ +#define KEY_NEED_READ 0x02 /* Require permission to read content */ +#define KEY_NEED_WRITE 0x04 /* Require permission to update / modify */ +#define KEY_NEED_SEARCH 0x08 /* Require permission to search (keyring) or find (key) */ +#define KEY_NEED_LINK 0x10 /* Require permission to link */ +#define KEY_NEED_SETATTR 0x20 /* Require permission to change attributes */ +#define KEY_NEED_ALL 0x3f /* All the above permissions */ + /** * key_is_instantiated - Determine if a key has been positively instantiated * @key: The key to check. diff --git a/include/linux/kobject.h b/include/linux/kobject.h index f896a33e8341e1..2d61b909f414f6 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -32,8 +32,10 @@ #define UEVENT_NUM_ENVP 32 /* number of env pointers */ #define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ +#ifdef CONFIG_UEVENT_HELPER /* path to the userspace helper executed on an event */ extern char uevent_helper[]; +#endif /* counter to tag the uevent, read only except for the kobject core */ extern u64 uevent_seqnum; diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 925eaf28fca9cc..e059507c465dcc 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -205,10 +205,10 @@ struct kretprobe_blackpoint { void *addr; }; -struct kprobe_blackpoint { - const char *name; +struct kprobe_blacklist_entry { + struct list_head list; unsigned long start_addr; - unsigned long range; + unsigned long end_addr; }; #ifdef CONFIG_KPROBES @@ -265,6 +265,7 @@ extern void arch_disarm_kprobe(struct kprobe *p); extern int arch_init_kprobes(void); extern void show_registers(struct pt_regs *regs); extern void kprobes_inc_nmissed_count(struct kprobe *p); +extern bool arch_within_kprobe_blacklist(unsigned long addr); struct kprobe_insn_cache { struct mutex mutex; @@ -476,4 +477,18 @@ static inline int enable_jprobe(struct jprobe *jp) return enable_kprobe(&jp->kp); } +#ifdef CONFIG_KPROBES +/* + * Blacklist ganerating macro. Specify functions which is not probed + * by using this macro. + */ +#define __NOKPROBE_SYMBOL(fname) \ +static unsigned long __used \ + __attribute__((section("_kprobe_blacklist"))) \ + _kbl_addr_##fname = (unsigned long)fname; +#define NOKPROBE_SYMBOL(fname) __NOKPROBE_SYMBOL(fname) +#else +#define NOKPROBE_SYMBOL(fname) +#endif + #endif /* _LINUX_KPROBES_H */ diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 7d21cf9f43806c..1e125b05532795 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -134,6 +134,8 @@ static inline bool is_error_page(struct page *page) #define KVM_REQ_EPR_EXIT 20 #define KVM_REQ_SCAN_IOAPIC 21 #define KVM_REQ_GLOBAL_CLOCK_UPDATE 22 +#define KVM_REQ_ENABLE_IBS 23 +#define KVM_REQ_DISABLE_IBS 24 #define KVM_USERSPACE_IRQ_SOURCE_ID 0 #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1 @@ -163,6 +165,7 @@ enum kvm_bus { KVM_MMIO_BUS, KVM_PIO_BUS, KVM_VIRTIO_CCW_NOTIFY_BUS, + KVM_FAST_MMIO_BUS, KVM_NR_BUSES }; @@ -410,9 +413,7 @@ struct kvm { unsigned long mmu_notifier_seq; long mmu_notifier_count; #endif - /* Protected by mmu_lock */ - bool tlbs_dirty; - + long tlbs_dirty; struct list_head devices; }; @@ -879,6 +880,13 @@ static inline hpa_t pfn_to_hpa(pfn_t pfn) return (hpa_t)pfn << PAGE_SHIFT; } +static inline bool kvm_is_error_gpa(struct kvm *kvm, gpa_t gpa) +{ + unsigned long hva = gfn_to_hva(kvm, gpa_to_gfn(gpa)); + + return kvm_is_error_hva(hva); +} + static inline void kvm_migrate_timers(struct kvm_vcpu *vcpu) { set_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests); diff --git a/include/linux/linkage.h b/include/linux/linkage.h index 34a513a2727bbe..a6a42dd0246613 100644 --- a/include/linux/linkage.h +++ b/include/linux/linkage.h @@ -12,9 +12,9 @@ #endif #ifdef __cplusplus -#define CPP_ASMLINKAGE extern "C" __visible +#define CPP_ASMLINKAGE extern "C" #else -#define CPP_ASMLINKAGE __visible +#define CPP_ASMLINKAGE #endif #ifndef asmlinkage diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index dcaad79f54ed5e..219d79627c05af 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -17,13 +17,13 @@ #include #include #include -#include #include #include #ifdef CONFIG_LOCKD_V4 #include #endif #include +#include /* * Version string diff --git a/include/linux/mbus.h b/include/linux/mbus.h index 345b8c53b8974d..550c88fb0267f1 100644 --- a/include/linux/mbus.h +++ b/include/linux/mbus.h @@ -73,6 +73,6 @@ int mvebu_mbus_del_window(phys_addr_t base, size_t size); int mvebu_mbus_init(const char *soc, phys_addr_t mbus_phys_base, size_t mbus_size, phys_addr_t sdram_phys_base, size_t sdram_size); -int mvebu_mbus_dt_init(void); +int mvebu_mbus_dt_init(bool is_coherent); #endif /* __LINUX_MBUS_H */ diff --git a/include/linux/memblock.h b/include/linux/memblock.h index c5a61d993e128f..b660e05b63d4fb 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -18,6 +18,7 @@ #include #define INIT_MEMBLOCK_REGIONS 128 +#define INIT_PHYSMEM_REGIONS 4 /* Definition of memblock flags. */ #define MEMBLOCK_HOTPLUG 0x1 /* hotpluggable region */ @@ -43,6 +44,9 @@ struct memblock { phys_addr_t current_limit; struct memblock_type memory; struct memblock_type reserved; +#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP + struct memblock_type physmem; +#endif }; extern struct memblock memblock; @@ -71,6 +75,63 @@ int memblock_reserve(phys_addr_t base, phys_addr_t size); void memblock_trim_memory(phys_addr_t align); int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size); int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size); + +/* Low level functions */ +int memblock_add_range(struct memblock_type *type, + phys_addr_t base, phys_addr_t size, + int nid, unsigned long flags); + +int memblock_remove_range(struct memblock_type *type, + phys_addr_t base, + phys_addr_t size); + +void __next_mem_range(u64 *idx, int nid, struct memblock_type *type_a, + struct memblock_type *type_b, phys_addr_t *out_start, + phys_addr_t *out_end, int *out_nid); + +void __next_mem_range_rev(u64 *idx, int nid, struct memblock_type *type_a, + struct memblock_type *type_b, phys_addr_t *out_start, + phys_addr_t *out_end, int *out_nid); + +/** + * for_each_mem_range - iterate through memblock areas from type_a and not + * included in type_b. Or just type_a if type_b is NULL. + * @i: u64 used as loop variable + * @type_a: ptr to memblock_type to iterate + * @type_b: ptr to memblock_type which excludes from the iteration + * @nid: node selector, %NUMA_NO_NODE for all nodes + * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL + * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL + * @p_nid: ptr to int for nid of the range, can be %NULL + */ +#define for_each_mem_range(i, type_a, type_b, nid, \ + p_start, p_end, p_nid) \ + for (i = 0, __next_mem_range(&i, nid, type_a, type_b, \ + p_start, p_end, p_nid); \ + i != (u64)ULLONG_MAX; \ + __next_mem_range(&i, nid, type_a, type_b, \ + p_start, p_end, p_nid)) + +/** + * for_each_mem_range_rev - reverse iterate through memblock areas from + * type_a and not included in type_b. Or just type_a if type_b is NULL. + * @i: u64 used as loop variable + * @type_a: ptr to memblock_type to iterate + * @type_b: ptr to memblock_type which excludes from the iteration + * @nid: node selector, %NUMA_NO_NODE for all nodes + * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL + * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL + * @p_nid: ptr to int for nid of the range, can be %NULL + */ +#define for_each_mem_range_rev(i, type_a, type_b, nid, \ + p_start, p_end, p_nid) \ + for (i = (u64)ULLONG_MAX, \ + __next_mem_range_rev(&i, nid, type_a, type_b, \ + p_start, p_end, p_nid); \ + i != (u64)ULLONG_MAX; \ + __next_mem_range_rev(&i, nid, type_a, type_b, \ + p_start, p_end, p_nid)) + #ifdef CONFIG_MOVABLE_NODE static inline bool memblock_is_hotpluggable(struct memblock_region *m) { @@ -113,9 +174,6 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn, i >= 0; __next_mem_pfn_range(&i, nid, p_start, p_end, p_nid)) #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ -void __next_free_mem_range(u64 *idx, int nid, phys_addr_t *out_start, - phys_addr_t *out_end, int *out_nid); - /** * for_each_free_mem_range - iterate through free memblock areas * @i: u64 used as loop variable @@ -128,13 +186,8 @@ void __next_free_mem_range(u64 *idx, int nid, phys_addr_t *out_start, * soon as memblock is initialized. */ #define for_each_free_mem_range(i, nid, p_start, p_end, p_nid) \ - for (i = 0, \ - __next_free_mem_range(&i, nid, p_start, p_end, p_nid); \ - i != (u64)ULLONG_MAX; \ - __next_free_mem_range(&i, nid, p_start, p_end, p_nid)) - -void __next_free_mem_range_rev(u64 *idx, int nid, phys_addr_t *out_start, - phys_addr_t *out_end, int *out_nid); + for_each_mem_range(i, &memblock.memory, &memblock.reserved, \ + nid, p_start, p_end, p_nid) /** * for_each_free_mem_range_reverse - rev-iterate through free memblock areas @@ -148,10 +201,8 @@ void __next_free_mem_range_rev(u64 *idx, int nid, phys_addr_t *out_start, * order. Available as soon as memblock is initialized. */ #define for_each_free_mem_range_reverse(i, nid, p_start, p_end, p_nid) \ - for (i = (u64)ULLONG_MAX, \ - __next_free_mem_range_rev(&i, nid, p_start, p_end, p_nid); \ - i != (u64)ULLONG_MAX; \ - __next_free_mem_range_rev(&i, nid, p_start, p_end, p_nid)) + for_each_mem_range_rev(i, &memblock.memory, &memblock.reserved, \ + nid, p_start, p_end, p_nid) static inline void memblock_set_region_flags(struct memblock_region *r, unsigned long flags) diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h index 5cf8b91ce996c2..6d9371f88875d4 100644 --- a/include/linux/mfd/arizona/core.h +++ b/include/linux/mfd/arizona/core.h @@ -124,4 +124,7 @@ int wm5102_patch(struct arizona *arizona); int wm5110_patch(struct arizona *arizona); int wm8997_patch(struct arizona *arizona); +extern int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop, + bool mandatory); + #endif diff --git a/include/linux/mfd/ipaq-micro.h b/include/linux/mfd/ipaq-micro.h new file mode 100644 index 00000000000000..5c4d29f6674f11 --- /dev/null +++ b/include/linux/mfd/ipaq-micro.h @@ -0,0 +1,148 @@ +/* + * Header file for the compaq Micro MFD + */ + +#ifndef _MFD_IPAQ_MICRO_H_ +#define _MFD_IPAQ_MICRO_H_ + +#include +#include +#include + +#define TX_BUF_SIZE 32 +#define RX_BUF_SIZE 16 +#define CHAR_SOF 0x02 + +/* + * These are the different messages that can be sent to the microcontroller + * to control various aspects. + */ +#define MSG_VERSION 0x0 +#define MSG_KEYBOARD 0x2 +#define MSG_TOUCHSCREEN 0x3 +#define MSG_EEPROM_READ 0x4 +#define MSG_EEPROM_WRITE 0x5 +#define MSG_THERMAL_SENSOR 0x6 +#define MSG_NOTIFY_LED 0x8 +#define MSG_BATTERY 0x9 +#define MSG_SPI_READ 0xb +#define MSG_SPI_WRITE 0xc +#define MSG_BACKLIGHT 0xd /* H3600 only */ +#define MSG_CODEC_CTRL 0xe /* H3100 only */ +#define MSG_DISPLAY_CTRL 0xf /* H3100 only */ + +/* state of receiver parser */ +enum rx_state { + STATE_SOF = 0, /* Next byte should be start of frame */ + STATE_ID, /* Next byte is ID & message length */ + STATE_DATA, /* Next byte is a data byte */ + STATE_CHKSUM /* Next byte should be checksum */ +}; + +/** + * struct ipaq_micro_txdev - TX state + * @len: length of message in TX buffer + * @index: current index into TX buffer + * @buf: TX buffer + */ +struct ipaq_micro_txdev { + u8 len; + u8 index; + u8 buf[TX_BUF_SIZE]; +}; + +/** + * struct ipaq_micro_rxdev - RX state + * @state: context of RX state machine + * @chksum: calculated checksum + * @id: message ID from packet + * @len: RX buffer length + * @index: RX buffer index + * @buf: RX buffer + */ +struct ipaq_micro_rxdev { + enum rx_state state; + unsigned char chksum; + u8 id; + unsigned int len; + unsigned int index; + u8 buf[RX_BUF_SIZE]; +}; + +/** + * struct ipaq_micro_msg - message to the iPAQ microcontroller + * @id: 4-bit ID of the message + * @tx_len: length of TX data + * @tx_data: TX data to send + * @rx_len: length of receieved RX data + * @rx_data: RX data to recieve + * @ack: a completion that will be completed when RX is complete + * @node: list node if message gets queued + */ +struct ipaq_micro_msg { + u8 id; + u8 tx_len; + u8 tx_data[TX_BUF_SIZE]; + u8 rx_len; + u8 rx_data[RX_BUF_SIZE]; + struct completion ack; + struct list_head node; +}; + +/** + * struct ipaq_micro - iPAQ microcontroller state + * @dev: corresponding platform device + * @base: virtual memory base for underlying serial device + * @sdlc: virtual memory base for Synchronous Data Link Controller + * @version: version string + * @tx: TX state + * @rx: RX state + * @lock: lock for this state container + * @msg: current message + * @queue: message queue + * @key: callback for asynchronous key events + * @key_data: data to pass along with key events + * @ts: callback for asynchronous touchscreen events + * @ts_data: data to pass along with key events + */ +struct ipaq_micro { + struct device *dev; + void __iomem *base; + void __iomem *sdlc; + char version[5]; + struct ipaq_micro_txdev tx; /* transmit ISR state */ + struct ipaq_micro_rxdev rx; /* receive ISR state */ + spinlock_t lock; + struct ipaq_micro_msg *msg; + struct list_head queue; + void (*key) (void *data, int len, unsigned char *rxdata); + void *key_data; + void (*ts) (void *data, int len, unsigned char *rxdata); + void *ts_data; +}; + +extern int +ipaq_micro_tx_msg(struct ipaq_micro *micro, struct ipaq_micro_msg *msg); + +static inline int +ipaq_micro_tx_msg_sync(struct ipaq_micro *micro, + struct ipaq_micro_msg *msg) +{ + int ret; + + init_completion(&msg->ack); + ret = ipaq_micro_tx_msg(micro, msg); + wait_for_completion(&msg->ack); + + return ret; +} + +static inline int +ipaq_micro_tx_msg_async(struct ipaq_micro *micro, + struct ipaq_micro_msg *msg) +{ + init_completion(&msg->ack); + return ipaq_micro_tx_msg(micro, msg); +} + +#endif /* _MFD_IPAQ_MICRO_H_ */ diff --git a/include/linux/mfd/kempld.h b/include/linux/mfd/kempld.h index b911ef3add03de..26e0b469e5678d 100644 --- a/include/linux/mfd/kempld.h +++ b/include/linux/mfd/kempld.h @@ -51,6 +51,8 @@ #define KEMPLD_TYPE_DEBUG 0x1 #define KEMPLD_TYPE_CUSTOM 0x2 +#define KEMPLD_VERSION_LEN 10 + /** * struct kempld_info - PLD device information structure * @major: PLD major revision @@ -60,6 +62,7 @@ * @type: PLD type * @spec_major: PLD FW specification major revision * @spec_minor: PLD FW specification minor revision + * @version: PLD version string */ struct kempld_info { unsigned int major; @@ -69,6 +72,7 @@ struct kempld_info { unsigned int type; unsigned int spec_major; unsigned int spec_minor; + char version[KEMPLD_VERSION_LEN]; }; /** diff --git a/include/linux/mfd/max14577-private.h b/include/linux/mfd/max14577-private.h index c9b332fb0d5da1..499253604026cf 100644 --- a/include/linux/mfd/max14577-private.h +++ b/include/linux/mfd/max14577-private.h @@ -1,7 +1,7 @@ /* - * max14577-private.h - Common API for the Maxim 14577 internal sub chip + * max14577-private.h - Common API for the Maxim 14577/77836 internal sub chip * - * Copyright (C) 2013 Samsung Electrnoics + * Copyright (C) 2014 Samsung Electrnoics * Chanwoo Choi * Krzysztof Kozlowski * @@ -22,9 +22,19 @@ #include #include -#define MAX14577_REG_INVALID (0xff) +#define I2C_ADDR_PMIC (0x46 >> 1) +#define I2C_ADDR_MUIC (0x4A >> 1) +#define I2C_ADDR_FG (0x6C >> 1) -/* Slave addr = 0x4A: Interrupt */ +enum maxim_device_type { + MAXIM_DEVICE_TYPE_UNKNOWN = 0, + MAXIM_DEVICE_TYPE_MAX14577, + MAXIM_DEVICE_TYPE_MAX77836, + + MAXIM_DEVICE_TYPE_NUM, +}; + +/* Slave addr = 0x4A: MUIC and Charger */ enum max14577_reg { MAX14577_REG_DEVICEID = 0x00, MAX14577_REG_INT1 = 0x01, @@ -74,20 +84,22 @@ enum max14577_muic_charger_type { }; /* MAX14577 interrupts */ -#define INT1_ADC_MASK (0x1 << 0) -#define INT1_ADCLOW_MASK (0x1 << 1) -#define INT1_ADCERR_MASK (0x1 << 2) - -#define INT2_CHGTYP_MASK (0x1 << 0) -#define INT2_CHGDETRUN_MASK (0x1 << 1) -#define INT2_DCDTMR_MASK (0x1 << 2) -#define INT2_DBCHG_MASK (0x1 << 3) -#define INT2_VBVOLT_MASK (0x1 << 4) - -#define INT3_EOC_MASK (0x1 << 0) -#define INT3_CGMBC_MASK (0x1 << 1) -#define INT3_OVP_MASK (0x1 << 2) -#define INT3_MBCCHGERR_MASK (0x1 << 3) +#define MAX14577_INT1_ADC_MASK BIT(0) +#define MAX14577_INT1_ADCLOW_MASK BIT(1) +#define MAX14577_INT1_ADCERR_MASK BIT(2) +#define MAX77836_INT1_ADC1K_MASK BIT(3) + +#define MAX14577_INT2_CHGTYP_MASK BIT(0) +#define MAX14577_INT2_CHGDETRUN_MASK BIT(1) +#define MAX14577_INT2_DCDTMR_MASK BIT(2) +#define MAX14577_INT2_DBCHG_MASK BIT(3) +#define MAX14577_INT2_VBVOLT_MASK BIT(4) +#define MAX77836_INT2_VIDRM_MASK BIT(5) + +#define MAX14577_INT3_EOC_MASK BIT(0) +#define MAX14577_INT3_CGMBC_MASK BIT(1) +#define MAX14577_INT3_OVP_MASK BIT(2) +#define MAX14577_INT3_MBCCHGERR_MASK BIT(3) /* MAX14577 DEVICE ID register */ #define DEVID_VENDORID_SHIFT 0 @@ -99,9 +111,11 @@ enum max14577_muic_charger_type { #define STATUS1_ADC_SHIFT 0 #define STATUS1_ADCLOW_SHIFT 5 #define STATUS1_ADCERR_SHIFT 6 +#define MAX77836_STATUS1_ADC1K_SHIFT 7 #define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT) -#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT) -#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT) +#define STATUS1_ADCLOW_MASK BIT(STATUS1_ADCLOW_SHIFT) +#define STATUS1_ADCERR_MASK BIT(STATUS1_ADCERR_SHIFT) +#define MAX77836_STATUS1_ADC1K_MASK BIT(MAX77836_STATUS1_ADC1K_SHIFT) /* MAX14577 STATUS2 register */ #define STATUS2_CHGTYP_SHIFT 0 @@ -109,11 +123,13 @@ enum max14577_muic_charger_type { #define STATUS2_DCDTMR_SHIFT 4 #define STATUS2_DBCHG_SHIFT 5 #define STATUS2_VBVOLT_SHIFT 6 +#define MAX77836_STATUS2_VIDRM_SHIFT 7 #define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT) -#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT) -#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT) -#define STATUS2_DBCHG_MASK (0x1 << STATUS2_DBCHG_SHIFT) -#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT) +#define STATUS2_CHGDETRUN_MASK BIT(STATUS2_CHGDETRUN_SHIFT) +#define STATUS2_DCDTMR_MASK BIT(STATUS2_DCDTMR_SHIFT) +#define STATUS2_DBCHG_MASK BIT(STATUS2_DBCHG_SHIFT) +#define STATUS2_VBVOLT_MASK BIT(STATUS2_VBVOLT_SHIFT) +#define MAX77836_STATUS2_VIDRM_MASK BIT(MAX77836_STATUS2_VIDRM_SHIFT) /* MAX14577 CONTROL1 register */ #define COMN1SW_SHIFT 0 @@ -122,8 +138,8 @@ enum max14577_muic_charger_type { #define IDBEN_SHIFT 7 #define COMN1SW_MASK (0x7 << COMN1SW_SHIFT) #define COMP2SW_MASK (0x7 << COMP2SW_SHIFT) -#define MICEN_MASK (0x1 << MICEN_SHIFT) -#define IDBEN_MASK (0x1 << IDBEN_SHIFT) +#define MICEN_MASK BIT(MICEN_SHIFT) +#define IDBEN_MASK BIT(IDBEN_SHIFT) #define CLEAR_IDBEN_MICEN_MASK (COMN1SW_MASK | COMP2SW_MASK) #define CTRL1_SW_USB ((1 << COMP2SW_SHIFT) \ | (1 << COMN1SW_SHIFT)) @@ -143,14 +159,14 @@ enum max14577_muic_charger_type { #define CTRL2_ACCDET_SHIFT (5) #define CTRL2_USBCPINT_SHIFT (6) #define CTRL2_RCPS_SHIFT (7) -#define CTRL2_LOWPWR_MASK (0x1 << CTRL2_LOWPWR_SHIFT) -#define CTRL2_ADCEN_MASK (0x1 << CTRL2_ADCEN_SHIFT) -#define CTRL2_CPEN_MASK (0x1 << CTRL2_CPEN_SHIFT) -#define CTRL2_SFOUTASRT_MASK (0x1 << CTRL2_SFOUTASRT_SHIFT) -#define CTRL2_SFOUTORD_MASK (0x1 << CTRL2_SFOUTORD_SHIFT) -#define CTRL2_ACCDET_MASK (0x1 << CTRL2_ACCDET_SHIFT) -#define CTRL2_USBCPINT_MASK (0x1 << CTRL2_USBCPINT_SHIFT) -#define CTRL2_RCPS_MASK (0x1 << CTR2_RCPS_SHIFT) +#define CTRL2_LOWPWR_MASK BIT(CTRL2_LOWPWR_SHIFT) +#define CTRL2_ADCEN_MASK BIT(CTRL2_ADCEN_SHIFT) +#define CTRL2_CPEN_MASK BIT(CTRL2_CPEN_SHIFT) +#define CTRL2_SFOUTASRT_MASK BIT(CTRL2_SFOUTASRT_SHIFT) +#define CTRL2_SFOUTORD_MASK BIT(CTRL2_SFOUTORD_SHIFT) +#define CTRL2_ACCDET_MASK BIT(CTRL2_ACCDET_SHIFT) +#define CTRL2_USBCPINT_MASK BIT(CTRL2_USBCPINT_SHIFT) +#define CTRL2_RCPS_MASK BIT(CTRL2_RCPS_SHIFT) #define CTRL2_CPEN1_LOWPWR0 ((1 << CTRL2_CPEN_SHIFT) | \ (0 << CTRL2_LOWPWR_SHIFT)) @@ -198,14 +214,14 @@ enum max14577_charger_reg { #define CDETCTRL1_DBEXIT_SHIFT 5 #define CDETCTRL1_DBIDLE_SHIFT 6 #define CDETCTRL1_CDPDET_SHIFT 7 -#define CDETCTRL1_CHGDETEN_MASK (0x1 << CDETCTRL1_CHGDETEN_SHIFT) -#define CDETCTRL1_CHGTYPMAN_MASK (0x1 << CDETCTRL1_CHGTYPMAN_SHIFT) -#define CDETCTRL1_DCDEN_MASK (0x1 << CDETCTRL1_DCDEN_SHIFT) -#define CDETCTRL1_DCD2SCT_MASK (0x1 << CDETCTRL1_DCD2SCT_SHIFT) -#define CDETCTRL1_DCHKTM_MASK (0x1 << CDETCTRL1_DCHKTM_SHIFT) -#define CDETCTRL1_DBEXIT_MASK (0x1 << CDETCTRL1_DBEXIT_SHIFT) -#define CDETCTRL1_DBIDLE_MASK (0x1 << CDETCTRL1_DBIDLE_SHIFT) -#define CDETCTRL1_CDPDET_MASK (0x1 << CDETCTRL1_CDPDET_SHIFT) +#define CDETCTRL1_CHGDETEN_MASK BIT(CDETCTRL1_CHGDETEN_SHIFT) +#define CDETCTRL1_CHGTYPMAN_MASK BIT(CDETCTRL1_CHGTYPMAN_SHIFT) +#define CDETCTRL1_DCDEN_MASK BIT(CDETCTRL1_DCDEN_SHIFT) +#define CDETCTRL1_DCD2SCT_MASK BIT(CDETCTRL1_DCD2SCT_SHIFT) +#define CDETCTRL1_DCHKTM_MASK BIT(CDETCTRL1_DCHKTM_SHIFT) +#define CDETCTRL1_DBEXIT_MASK BIT(CDETCTRL1_DBEXIT_SHIFT) +#define CDETCTRL1_DBIDLE_MASK BIT(CDETCTRL1_DBIDLE_SHIFT) +#define CDETCTRL1_CDPDET_MASK BIT(CDETCTRL1_CDPDET_SHIFT) /* MAX14577 CHGCTRL1 register */ #define CHGCTRL1_TCHW_SHIFT 4 @@ -213,9 +229,9 @@ enum max14577_charger_reg { /* MAX14577 CHGCTRL2 register */ #define CHGCTRL2_MBCHOSTEN_SHIFT 6 -#define CHGCTRL2_MBCHOSTEN_MASK (0x1 << CHGCTRL2_MBCHOSTEN_SHIFT) +#define CHGCTRL2_MBCHOSTEN_MASK BIT(CHGCTRL2_MBCHOSTEN_SHIFT) #define CHGCTRL2_VCHGR_RC_SHIFT 7 -#define CHGCTRL2_VCHGR_RC_MASK (0x1 << CHGCTRL2_VCHGR_RC_SHIFT) +#define CHGCTRL2_VCHGR_RC_MASK BIT(CHGCTRL2_VCHGR_RC_SHIFT) /* MAX14577 CHGCTRL3 register */ #define CHGCTRL3_MBCCVWRC_SHIFT 0 @@ -225,7 +241,7 @@ enum max14577_charger_reg { #define CHGCTRL4_MBCICHWRCH_SHIFT 0 #define CHGCTRL4_MBCICHWRCH_MASK (0xf << CHGCTRL4_MBCICHWRCH_SHIFT) #define CHGCTRL4_MBCICHWRCL_SHIFT 4 -#define CHGCTRL4_MBCICHWRCL_MASK (0x1 << CHGCTRL4_MBCICHWRCL_SHIFT) +#define CHGCTRL4_MBCICHWRCL_MASK BIT(CHGCTRL4_MBCICHWRCL_SHIFT) /* MAX14577 CHGCTRL5 register */ #define CHGCTRL5_EOCS_SHIFT 0 @@ -233,7 +249,7 @@ enum max14577_charger_reg { /* MAX14577 CHGCTRL6 register */ #define CHGCTRL6_AUTOSTOP_SHIFT 5 -#define CHGCTRL6_AUTOSTOP_MASK (0x1 << CHGCTRL6_AUTOSTOP_SHIFT) +#define CHGCTRL6_AUTOSTOP_MASK BIT(CHGCTRL6_AUTOSTOP_SHIFT) /* MAX14577 CHGCTRL7 register */ #define CHGCTRL7_OTPCGHCVS_SHIFT 0 @@ -245,14 +261,111 @@ enum max14577_charger_reg { #define MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP 50000 #define MAX14577_REGULATOR_CURRENT_LIMIT_MAX 950000 +/* MAX77836 regulator current limits (as in CHGCTRL4 register), uA */ +#define MAX77836_REGULATOR_CURRENT_LIMIT_MIN 45000 +#define MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START 100000 +#define MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP 25000 +#define MAX77836_REGULATOR_CURRENT_LIMIT_MAX 475000 + /* MAX14577 regulator SFOUT LDO voltage, fixed, uV */ #define MAX14577_REGULATOR_SAFEOUT_VOLTAGE 4900000 +/* MAX77836 regulator LDOx voltage, uV */ +#define MAX77836_REGULATOR_LDO_VOLTAGE_MIN 800000 +#define MAX77836_REGULATOR_LDO_VOLTAGE_MAX 3950000 +#define MAX77836_REGULATOR_LDO_VOLTAGE_STEP 50000 +#define MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM 64 + +/* Slave addr = 0x46: PMIC */ +enum max77836_pmic_reg { + MAX77836_PMIC_REG_PMIC_ID = 0x20, + MAX77836_PMIC_REG_PMIC_REV = 0x21, + MAX77836_PMIC_REG_INTSRC = 0x22, + MAX77836_PMIC_REG_INTSRC_MASK = 0x23, + MAX77836_PMIC_REG_TOPSYS_INT = 0x24, + MAX77836_PMIC_REG_TOPSYS_INT_MASK = 0x26, + MAX77836_PMIC_REG_TOPSYS_STAT = 0x28, + MAX77836_PMIC_REG_MRSTB_CNTL = 0x2A, + MAX77836_PMIC_REG_LSCNFG = 0x2B, + + MAX77836_LDO_REG_CNFG1_LDO1 = 0x51, + MAX77836_LDO_REG_CNFG2_LDO1 = 0x52, + MAX77836_LDO_REG_CNFG1_LDO2 = 0x53, + MAX77836_LDO_REG_CNFG2_LDO2 = 0x54, + MAX77836_LDO_REG_CNFG_LDO_BIAS = 0x55, + + MAX77836_COMP_REG_COMP1 = 0x60, + + MAX77836_PMIC_REG_END, +}; + +#define MAX77836_INTSRC_MASK_TOP_INT_SHIFT 1 +#define MAX77836_INTSRC_MASK_MUIC_CHG_INT_SHIFT 3 +#define MAX77836_INTSRC_MASK_TOP_INT_MASK BIT(MAX77836_INTSRC_MASK_TOP_INT_SHIFT) +#define MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK BIT(MAX77836_INTSRC_MASK_MUIC_CHG_INT_SHIFT) + +/* MAX77836 PMIC interrupts */ +#define MAX77836_TOPSYS_INT_T120C_SHIFT 0 +#define MAX77836_TOPSYS_INT_T140C_SHIFT 1 +#define MAX77836_TOPSYS_INT_T120C_MASK BIT(MAX77836_TOPSYS_INT_T120C_SHIFT) +#define MAX77836_TOPSYS_INT_T140C_MASK BIT(MAX77836_TOPSYS_INT_T140C_SHIFT) + +/* LDO1/LDO2 CONFIG1 register */ +#define MAX77836_CNFG1_LDO_PWRMD_SHIFT 6 +#define MAX77836_CNFG1_LDO_TV_SHIFT 0 +#define MAX77836_CNFG1_LDO_PWRMD_MASK (0x3 << MAX77836_CNFG1_LDO_PWRMD_SHIFT) +#define MAX77836_CNFG1_LDO_TV_MASK (0x3f << MAX77836_CNFG1_LDO_TV_SHIFT) + +/* LDO1/LDO2 CONFIG2 register */ +#define MAX77836_CNFG2_LDO_OVCLMPEN_SHIFT 7 +#define MAX77836_CNFG2_LDO_ALPMEN_SHIFT 6 +#define MAX77836_CNFG2_LDO_COMP_SHIFT 4 +#define MAX77836_CNFG2_LDO_POK_SHIFT 3 +#define MAX77836_CNFG2_LDO_ADE_SHIFT 1 +#define MAX77836_CNFG2_LDO_SS_SHIFT 0 +#define MAX77836_CNFG2_LDO_OVCLMPEN_MASK BIT(MAX77836_CNFG2_LDO_OVCLMPEN_SHIFT) +#define MAX77836_CNFG2_LDO_ALPMEN_MASK BIT(MAX77836_CNFG2_LDO_ALPMEN_SHIFT) +#define MAX77836_CNFG2_LDO_COMP_MASK (0x3 << MAX77836_CNFG2_LDO_COMP_SHIFT) +#define MAX77836_CNFG2_LDO_POK_MASK BIT(MAX77836_CNFG2_LDO_POK_SHIFT) +#define MAX77836_CNFG2_LDO_ADE_MASK BIT(MAX77836_CNFG2_LDO_ADE_SHIFT) +#define MAX77836_CNFG2_LDO_SS_MASK BIT(MAX77836_CNFG2_LDO_SS_SHIFT) + +/* Slave addr = 0x6C: Fuel-Gauge/Battery */ +enum max77836_fg_reg { + MAX77836_FG_REG_VCELL_MSB = 0x02, + MAX77836_FG_REG_VCELL_LSB = 0x03, + MAX77836_FG_REG_SOC_MSB = 0x04, + MAX77836_FG_REG_SOC_LSB = 0x05, + MAX77836_FG_REG_MODE_H = 0x06, + MAX77836_FG_REG_MODE_L = 0x07, + MAX77836_FG_REG_VERSION_MSB = 0x08, + MAX77836_FG_REG_VERSION_LSB = 0x09, + MAX77836_FG_REG_HIBRT_H = 0x0A, + MAX77836_FG_REG_HIBRT_L = 0x0B, + MAX77836_FG_REG_CONFIG_H = 0x0C, + MAX77836_FG_REG_CONFIG_L = 0x0D, + MAX77836_FG_REG_VALRT_MIN = 0x14, + MAX77836_FG_REG_VALRT_MAX = 0x15, + MAX77836_FG_REG_CRATE_MSB = 0x16, + MAX77836_FG_REG_CRATE_LSB = 0x17, + MAX77836_FG_REG_VRESET = 0x18, + MAX77836_FG_REG_FGID = 0x19, + MAX77836_FG_REG_STATUS_H = 0x1A, + MAX77836_FG_REG_STATUS_L = 0x1B, + /* + * TODO: TABLE registers + * TODO: CMD register + */ + + MAX77836_FG_REG_END, +}; + enum max14577_irq { /* INT1 */ MAX14577_IRQ_INT1_ADC, MAX14577_IRQ_INT1_ADCLOW, MAX14577_IRQ_INT1_ADCERR, + MAX77836_IRQ_INT1_ADC1K, /* INT2 */ MAX14577_IRQ_INT2_CHGTYP, @@ -260,6 +373,7 @@ enum max14577_irq { MAX14577_IRQ_INT2_DCDTMR, MAX14577_IRQ_INT2_DBCHG, MAX14577_IRQ_INT2_VBVOLT, + MAX77836_IRQ_INT2_VIDRM, /* INT3 */ MAX14577_IRQ_INT3_EOC, @@ -267,21 +381,25 @@ enum max14577_irq { MAX14577_IRQ_INT3_OVP, MAX14577_IRQ_INT3_MBCCHGERR, + /* TOPSYS_INT, only MAX77836 */ + MAX77836_IRQ_TOPSYS_T140C, + MAX77836_IRQ_TOPSYS_T120C, + MAX14577_IRQ_NUM, }; struct max14577 { struct device *dev; struct i2c_client *i2c; /* Slave addr = 0x4A */ + struct i2c_client *i2c_pmic; /* Slave addr = 0x46 */ + enum maxim_device_type dev_type; - struct regmap *regmap; + struct regmap *regmap; /* For MUIC and Charger */ + struct regmap *regmap_pmic; - struct regmap_irq_chip_data *irq_data; + struct regmap_irq_chip_data *irq_data; /* For MUIC and Charger */ + struct regmap_irq_chip_data *irq_data_pmic; int irq; - - /* Device ID */ - u8 vendor_id; /* Vendor Identification */ - u8 device_id; /* Chip Version */ }; /* MAX14577 shared regmap API function */ diff --git a/include/linux/mfd/max14577.h b/include/linux/mfd/max14577.h index 736d39c3ec0d7a..c83fbed1c7b64a 100644 --- a/include/linux/mfd/max14577.h +++ b/include/linux/mfd/max14577.h @@ -1,7 +1,7 @@ /* - * max14577.h - Driver for the Maxim 14577 + * max14577.h - Driver for the Maxim 14577/77836 * - * Copyright (C) 2013 Samsung Electrnoics + * Copyright (C) 2014 Samsung Electrnoics * Chanwoo Choi * Krzysztof Kozlowski * @@ -20,6 +20,9 @@ * MAX14577 has MUIC, Charger devices. * The devices share the same I2C bus and interrupt line * included in this mfd driver. + * + * MAX77836 has additional PMIC and Fuel-Gauge on different I2C slave + * addresses. */ #ifndef __MAX14577_H__ @@ -32,7 +35,17 @@ enum max14577_regulators { MAX14577_SAFEOUT = 0, MAX14577_CHARGER, - MAX14577_REG_MAX, + MAX14577_REGULATOR_NUM, +}; + +/* MAX77836 regulator IDs */ +enum max77836_regulators { + MAX77836_SAFEOUT = 0, + MAX77836_CHARGER, + MAX77836_LDO1, + MAX77836_LDO2, + + MAX77836_REGULATOR_NUM, }; struct max14577_regulator_platform_data { diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h index a326c850f0468a..d63b1d3091061a 100644 --- a/include/linux/mfd/mc13xxx.h +++ b/include/linux/mfd/mc13xxx.h @@ -117,10 +117,6 @@ struct mc13xxx_led_platform_data { #define MAX_LED_CONTROL_REGS 6 -struct mc13xxx_leds_platform_data { - struct mc13xxx_led_platform_data *led; - int num_leds; - /* MC13783 LED Control 0 */ #define MC13783_LED_C0_ENABLE (1 << 0) #define MC13783_LED_C0_TRIODE_MD (1 << 7) @@ -169,10 +165,13 @@ struct mc13xxx_leds_platform_data { /* MC34708 LED Control 0 */ #define MC34708_LED_C0_CURRENT_R(x) (((x) & 0x3) << 9) #define MC34708_LED_C0_CURRENT_G(x) (((x) & 0x3) << 21) + +struct mc13xxx_leds_platform_data { + struct mc13xxx_led_platform_data *led; + int num_leds; u32 led_control[MAX_LED_CONTROL_REGS]; }; -struct mc13xxx_buttons_platform_data { #define MC13783_BUTTON_DBNC_0MS 0 #define MC13783_BUTTON_DBNC_30MS 1 #define MC13783_BUTTON_DBNC_150MS 2 @@ -180,6 +179,8 @@ struct mc13xxx_buttons_platform_data { #define MC13783_BUTTON_ENABLE (1 << 2) #define MC13783_BUTTON_POL_INVERT (1 << 3) #define MC13783_BUTTON_RESET_EN (1 << 4) + +struct mc13xxx_buttons_platform_data { int b1on_flags; unsigned short b1on_key; int b2on_flags; @@ -188,14 +189,14 @@ struct mc13xxx_buttons_platform_data { unsigned short b3on_key; }; +#define MC13783_TS_ATO_FIRST false +#define MC13783_TS_ATO_EACH true + struct mc13xxx_ts_platform_data { /* Delay between Touchscreen polarization and ADC Conversion. * Given in clock ticks of a 32 kHz clock which gives a granularity of * about 30.5ms */ u8 ato; - -#define MC13783_TS_ATO_FIRST false -#define MC13783_TS_ATO_EACH true /* Use the ATO delay only for the first conversion or for each one */ bool atox; }; @@ -210,11 +211,12 @@ struct mc13xxx_codec_platform_data { enum mc13783_ssi_port dac_ssi_port; }; -struct mc13xxx_platform_data { -#define MC13XXX_USE_TOUCHSCREEN (1 << 0) +#define MC13XXX_USE_TOUCHSCREEN (1 << 0) #define MC13XXX_USE_CODEC (1 << 1) #define MC13XXX_USE_ADC (1 << 2) #define MC13XXX_USE_RTC (1 << 3) + +struct mc13xxx_platform_data { unsigned int flags; struct mc13xxx_regulator_platform_data regulators; diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index 157e32b6ca2879..e7e12ebacb9b33 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -28,7 +28,6 @@ enum sec_device_type { * @dev: master device of the chip (can be used to access platform data) * @pdata: pointer to private data used to pass platform data to child * @i2c: i2c client private data for regulator - * @rtc: i2c client private data for rtc * @iolock: mutex for serializing io access * @irqlock: mutex for buslock * @irq_base: base IRQ number for sec-pmic, required for IRQs @@ -42,17 +41,14 @@ struct sec_pmic_dev { struct device *dev; struct sec_platform_data *pdata; struct regmap *regmap_pmic; - struct regmap *regmap_rtc; struct i2c_client *i2c; - struct i2c_client *rtc; - int device_type; + unsigned long device_type; int irq_base; int irq; struct regmap_irq_chip_data *irq_data; int ono; - unsigned long type; bool wakeup; bool wtsr_smpl; }; diff --git a/include/linux/mfd/samsung/s2mps14.h b/include/linux/mfd/samsung/s2mps14.h index 4b449b8ac548bb..900cd7a04314d3 100644 --- a/include/linux/mfd/samsung/s2mps14.h +++ b/include/linux/mfd/samsung/s2mps14.h @@ -148,6 +148,8 @@ enum s2mps14_regulators { #define S2MPS14_ENABLE_SHIFT 6 /* On/Off controlled by PWREN */ #define S2MPS14_ENABLE_SUSPEND (0x01 << S2MPS14_ENABLE_SHIFT) +/* On/Off controlled by LDO10EN or EMMCEN */ +#define S2MPS14_ENABLE_EXT_CONTROL (0x00 << S2MPS14_ENABLE_SHIFT) #define S2MPS14_LDO_N_VOLTAGES (S2MPS14_LDO_VSEL_MASK + 1) #define S2MPS14_BUCK_N_VOLTAGES (S2MPS14_BUCK_VSEL_MASK + 1) diff --git a/include/linux/mfd/tc3589x.h b/include/linux/mfd/tc3589x.h index 6b8e1ff4672b0a..e6088c2e2092f0 100644 --- a/include/linux/mfd/tc3589x.h +++ b/include/linux/mfd/tc3589x.h @@ -111,7 +111,6 @@ enum tx3589x_block { #define TC3589x_INT_PORIRQ 7 #define TC3589x_NR_INTERNAL_IRQS 8 -#define TC3589x_INT_GPIO(x) (TC3589x_NR_INTERNAL_IRQS + (x)) struct tc3589x { struct mutex lock; diff --git a/include/linux/mfd/tps65090.h b/include/linux/mfd/tps65090.h index 3f43069413e72d..0bf2708df150d0 100644 --- a/include/linux/mfd/tps65090.h +++ b/include/linux/mfd/tps65090.h @@ -64,6 +64,20 @@ enum { TPS65090_REGULATOR_MAX, }; +/* Register addresses */ +#define TPS65090_REG_INTR_STS 0x00 +#define TPS65090_REG_INTR_STS2 0x01 +#define TPS65090_REG_INTR_MASK 0x02 +#define TPS65090_REG_INTR_MASK2 0x03 +#define TPS65090_REG_CG_CTRL0 0x04 +#define TPS65090_REG_CG_CTRL1 0x05 +#define TPS65090_REG_CG_CTRL2 0x06 +#define TPS65090_REG_CG_CTRL3 0x07 +#define TPS65090_REG_CG_CTRL4 0x08 +#define TPS65090_REG_CG_CTRL5 0x09 +#define TPS65090_REG_CG_STATUS1 0x0a +#define TPS65090_REG_CG_STATUS2 0x0b + struct tps65090 { struct device *dev; struct regmap *rmap; @@ -78,11 +92,16 @@ struct tps65090 { * DCDC1, DCDC2 and DCDC3. * @gpio: Gpio number if external control is enabled and controlled through * gpio. + * @overcurrent_wait_valid: True if the overcurrent_wait should be applied. + * @overcurrent_wait: Value to set as the overcurrent wait time. This is the + * actual bitfield value, not a time in ms (valid value are 0 - 3). */ struct tps65090_regulator_plat_data { struct regulator_init_data *reg_init_data; bool enable_ext_control; int gpio; + bool overcurrent_wait_valid; + int overcurrent_wait; }; struct tps65090_platform_data { diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h index 54b5458ec084a5..95d6938737fd29 100644 --- a/include/linux/mfd/tps65217.h +++ b/include/linux/mfd/tps65217.h @@ -254,7 +254,6 @@ struct tps65217 { struct tps65217_board *pdata; unsigned long id; struct regulator_desc desc[TPS65217_NUM_REGULATOR]; - struct regulator_dev *rdev[TPS65217_NUM_REGULATOR]; struct regmap *regmap; }; diff --git a/include/linux/mfd/tps65218.h b/include/linux/mfd/tps65218.h index d2e357df5a0e49..2f9b593246ee69 100644 --- a/include/linux/mfd/tps65218.h +++ b/include/linux/mfd/tps65218.h @@ -267,7 +267,6 @@ struct tps65218 { u32 irq_mask; struct regmap_irq_chip_data *irq_data; struct regulator_desc desc[TPS65218_NUM_REGULATOR]; - struct regulator_dev *rdev[TPS65218_NUM_REGULATOR]; struct tps_info *info[TPS65218_NUM_REGULATOR]; struct regmap *regmap; }; diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index b73027298b3a68..aa7e57f60fb260 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -353,7 +353,7 @@ struct mmc_fixup { #define CID_OEMID_ANY ((unsigned short) -1) #define CID_NAME_ANY (NULL) -#define END_FIXUP { 0 } +#define END_FIXUP { NULL } #define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end, \ _cis_vendor, _cis_device, \ diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index 6ce7d2cd3c7ad7..babaea93bca646 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -248,20 +248,6 @@ struct dw_mci_board { /* delay in mS before detecting cards after interrupt */ u32 detect_delay_ms; - int (*init)(u32 slot_id, irq_handler_t , void *); - int (*get_ro)(u32 slot_id); - int (*get_cd)(u32 slot_id); - int (*get_ocr)(u32 slot_id); - int (*get_bus_wd)(u32 slot_id); - /* - * Enable power to selected slot and set voltage to desired level. - * Voltage levels are specified using MMC_VDD_xxx defines defined - * in linux/mmc/host.h file. - */ - void (*setpower)(u32 slot_id, u32 volt); - void (*exit)(u32 slot_id); - void (*select_slot)(u32 slot_id); - struct dw_mci_dma_ops *dma_ops; struct dma_pdata *data; struct block_settings *blk_settings; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index cb61ea4d694553..0cf705c839985a 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -58,7 +58,8 @@ struct mmc_ios { #define MMC_TIMING_UHS_SDR50 5 #define MMC_TIMING_UHS_SDR104 6 #define MMC_TIMING_UHS_DDR50 7 -#define MMC_TIMING_MMC_HS200 8 +#define MMC_TIMING_MMC_DDR52 8 +#define MMC_TIMING_MMC_HS200 9 #define MMC_SDR_MODE 0 #define MMC_1_2V_DDR_MODE 1 @@ -318,6 +319,8 @@ struct mmc_host { int rescan_disable; /* disable card detection */ int rescan_entered; /* used with nonremovable devices */ + bool trigger_card_event; /* card_event necessary */ + struct mmc_card *card; /* device attached to this host */ wait_queue_head_t wq; diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 204a677438049b..b1990c5524e1ce 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -321,7 +321,7 @@ extern bool parameq(const char *name1, const char *name2); extern bool parameqn(const char *name1, const char *name2, size_t n); /* Called on module insert or kernel boot */ -extern int parse_args(const char *name, +extern char *parse_args(const char *name, char *args, const struct kernel_param *params, unsigned num, diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 450d61ec7f0609..7a922e6c4e4b9a 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -552,8 +552,7 @@ struct nand_buffers { * @ecc: [BOARDSPECIFIC] ECC control structure * @buffers: buffer structure for read/write * @hwcontrol: platform-specific hardware control structure - * @erase_cmd: [INTERN] erase command write function, selectable due - * to AND support. + * @erase: [REPLACEABLE] erase function * @scan_bbt: [REPLACEABLE] function to scan bad block table * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transferring * data from array to read regs (tR). @@ -637,7 +636,7 @@ struct nand_chip { void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); - void (*erase_cmd)(struct mtd_info *mtd, int page); + int (*erase)(struct mtd_info *mtd, int page); int (*scan_bbt)(struct mtd_info *mtd); int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h new file mode 100644 index 00000000000000..53241842a7ab4d --- /dev/null +++ b/include/linux/mtd/spi-nor.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor, 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. + */ + +#ifndef __LINUX_MTD_SPI_NOR_H +#define __LINUX_MTD_SPI_NOR_H + +/* + * Note on opcode nomenclature: some opcodes have a format like + * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number + * of I/O lines used for the opcode, address, and data (respectively). The + * FUNCTION has an optional suffix of '4', to represent an opcode which + * requires a 4-byte (32-bit) address. + */ + +/* Flash opcodes. */ +#define SPINOR_OP_WREN 0x06 /* Write enable */ +#define SPINOR_OP_RDSR 0x05 /* Read status register */ +#define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */ +#define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */ +#define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */ +#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */ +#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */ +#define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */ +#define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */ +#define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ +#define SPINOR_OP_BE_32K 0x52 /* Erase 32KiB block */ +#define SPINOR_OP_CHIP_ERASE 0xc7 /* Erase whole flash chip */ +#define SPINOR_OP_SE 0xd8 /* Sector erase (usually 64KiB) */ +#define SPINOR_OP_RDID 0x9f /* Read JEDEC ID */ +#define SPINOR_OP_RDCR 0x35 /* Read configuration register */ + +/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ +#define SPINOR_OP_READ4 0x13 /* Read data bytes (low frequency) */ +#define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */ +#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */ +#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */ +#define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */ +#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */ + +/* Used for SST flashes only. */ +#define SPINOR_OP_BP 0x02 /* Byte program */ +#define SPINOR_OP_WRDI 0x04 /* Write disable */ +#define SPINOR_OP_AAI_WP 0xad /* Auto address increment word program */ + +/* Used for Macronix and Winbond flashes. */ +#define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */ +#define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */ + +/* Used for Spansion flashes only. */ +#define SPINOR_OP_BRWR 0x17 /* Bank register write */ + +/* Status Register bits. */ +#define SR_WIP 1 /* Write in progress */ +#define SR_WEL 2 /* Write enable latch */ +/* meaning of other SR_* bits may differ between vendors */ +#define SR_BP0 4 /* Block protect 0 */ +#define SR_BP1 8 /* Block protect 1 */ +#define SR_BP2 0x10 /* Block protect 2 */ +#define SR_SRWD 0x80 /* SR write protect */ + +#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ + +/* Configuration Register bits. */ +#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */ + +enum read_mode { + SPI_NOR_NORMAL = 0, + SPI_NOR_FAST, + SPI_NOR_DUAL, + SPI_NOR_QUAD, +}; + +/** + * struct spi_nor_xfer_cfg - Structure for defining a Serial Flash transfer + * @wren: command for "Write Enable", or 0x00 for not required + * @cmd: command for operation + * @cmd_pins: number of pins to send @cmd (1, 2, 4) + * @addr: address for operation + * @addr_pins: number of pins to send @addr (1, 2, 4) + * @addr_width: number of address bytes + * (3,4, or 0 for address not required) + * @mode: mode data + * @mode_pins: number of pins to send @mode (1, 2, 4) + * @mode_cycles: number of mode cycles (0 for mode not required) + * @dummy_cycles: number of dummy cycles (0 for dummy not required) + */ +struct spi_nor_xfer_cfg { + u8 wren; + u8 cmd; + u8 cmd_pins; + u32 addr; + u8 addr_pins; + u8 addr_width; + u8 mode; + u8 mode_pins; + u8 mode_cycles; + u8 dummy_cycles; +}; + +#define SPI_NOR_MAX_CMD_SIZE 8 +enum spi_nor_ops { + SPI_NOR_OPS_READ = 0, + SPI_NOR_OPS_WRITE, + SPI_NOR_OPS_ERASE, + SPI_NOR_OPS_LOCK, + SPI_NOR_OPS_UNLOCK, +}; + +/** + * struct spi_nor - Structure for defining a the SPI NOR layer + * @mtd: point to a mtd_info structure + * @lock: the lock for the read/write/erase/lock/unlock operations + * @dev: point to a spi device, or a spi nor controller device. + * @page_size: the page size of the SPI NOR + * @addr_width: number of address bytes + * @erase_opcode: the opcode for erasing a sector + * @read_opcode: the read opcode + * @read_dummy: the dummy needed by the read operation + * @program_opcode: the program opcode + * @flash_read: the mode of the read + * @sst_write_second: used by the SST write operation + * @cfg: used by the read_xfer/write_xfer + * @cmd_buf: used by the write_reg + * @prepare: [OPTIONAL] do some preparations for the + * read/write/erase/lock/unlock operations + * @unprepare: [OPTIONAL] do some post work after the + * read/write/erase/lock/unlock operations + * @read_xfer: [OPTIONAL] the read fundamental primitive + * @write_xfer: [OPTIONAL] the writefundamental primitive + * @read_reg: [DRIVER-SPECIFIC] read out the register + * @write_reg: [DRIVER-SPECIFIC] write data to the register + * @read_id: [REPLACEABLE] read out the ID data, and find + * the proper spi_device_id + * @wait_till_ready: [REPLACEABLE] wait till the NOR becomes ready + * @read: [DRIVER-SPECIFIC] read data from the SPI NOR + * @write: [DRIVER-SPECIFIC] write data to the SPI NOR + * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR + * at the offset @offs + * @priv: the private data + */ +struct spi_nor { + struct mtd_info *mtd; + struct mutex lock; + struct device *dev; + u32 page_size; + u8 addr_width; + u8 erase_opcode; + u8 read_opcode; + u8 read_dummy; + u8 program_opcode; + enum read_mode flash_read; + bool sst_write_second; + struct spi_nor_xfer_cfg cfg; + u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE]; + + int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops); + void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops); + int (*read_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg, + u8 *buf, size_t len); + int (*write_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg, + u8 *buf, size_t len); + int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len); + int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len, + int write_enable); + const struct spi_device_id *(*read_id)(struct spi_nor *nor); + int (*wait_till_ready)(struct spi_nor *nor); + + int (*read)(struct spi_nor *nor, loff_t from, + size_t len, size_t *retlen, u_char *read_buf); + void (*write)(struct spi_nor *nor, loff_t to, + size_t len, size_t *retlen, const u_char *write_buf); + int (*erase)(struct spi_nor *nor, loff_t offs); + + void *priv; +}; + +/** + * spi_nor_scan() - scan the SPI NOR + * @nor: the spi_nor structure + * @id: the spi_device_id provided by the driver + * @mode: the read mode supported by the driver + * + * The drivers can use this fuction to scan the SPI NOR. + * In the scanning, it will try to get all the necessary information to + * fill the mtd_info{} and the spi_nor{}. + * + * The board may assigns a spi_device_id with @id which be used to compared with + * the spi_device_id detected by the scanning. + * + * Return: 0 for success, others for failure. + */ +int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, + enum read_mode mode); +extern const struct spi_device_id spi_nor_ids[]; + +/** + * spi_nor_match_id() - find the spi_device_id by the name + * @name: the name of the spi_device_id + * + * The drivers use this function to find the spi_device_id + * specified by the @name. + * + * Return: returns the right spi_device_id pointer on success, + * and returns NULL on failure. + */ +const struct spi_device_id *spi_nor_match_id(char *name); + +#endif diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7ed3a3aa6604b7..17cc791ed95e11 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -493,7 +493,7 @@ static inline void napi_disable(struct napi_struct *n) static inline void napi_enable(struct napi_struct *n) { BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(NAPI_STATE_SCHED, &n->state); } @@ -2633,6 +2633,7 @@ int dev_get_phys_port_id(struct net_device *dev, struct netdev_phys_port_id *ppid); int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq); +int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb); int dev_forward_skb(struct net_device *dev, struct sk_buff *skb); bool is_skb_forwardable(struct net_device *dev, struct sk_buff *skb); @@ -3180,12 +3181,7 @@ void netdev_change_features(struct net_device *dev); void netif_stacked_transfer_operstate(const struct net_device *rootdev, struct net_device *dev); -netdev_features_t netif_skb_dev_features(struct sk_buff *skb, - const struct net_device *dev); -static inline netdev_features_t netif_skb_features(struct sk_buff *skb) -{ - return netif_skb_dev_features(skb, skb->dev); -} +netdev_features_t netif_skb_features(struct sk_buff *skb); static inline bool net_gso_ok(netdev_features_t features, int gso_type) { diff --git a/include/linux/netlink.h b/include/linux/netlink.h index f64b01787ddc27..7a28115dd3965a 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -45,7 +45,8 @@ struct netlink_kernel_cfg { unsigned int flags; void (*input)(struct sk_buff *skb); struct mutex *cb_mutex; - void (*bind)(int group); + int (*bind)(int group); + void (*unbind)(int group); bool (*compare)(struct net *net, struct sock *sk); }; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index fa6918b0f82952..0a82b6fbae8a4d 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -459,13 +459,12 @@ extern int nfs3_removexattr (struct dentry *, const char *name); /* * linux/fs/nfs/direct.c */ -extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t, - unsigned long); +extern ssize_t nfs_direct_IO(int, struct kiocb *, struct iov_iter *, loff_t); extern ssize_t nfs_file_direct_read(struct kiocb *iocb, - const struct iovec *iov, unsigned long nr_segs, + struct iov_iter *iter, loff_t pos, bool uio); extern ssize_t nfs_file_direct_write(struct kiocb *iocb, - const struct iovec *iov, unsigned long nr_segs, + struct iov_iter *iter, loff_t pos, bool uio); /* diff --git a/include/linux/nfsd/debug.h b/include/linux/nfsd/debug.h deleted file mode 100644 index 19ef8375b57722..00000000000000 --- a/include/linux/nfsd/debug.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * linux/include/linux/nfsd/debug.h - * - * Debugging-related stuff for nfsd - * - * Copyright (C) 1995 Olaf Kirch - */ -#ifndef LINUX_NFSD_DEBUG_H -#define LINUX_NFSD_DEBUG_H - -#include - -# undef ifdebug -# ifdef NFSD_DEBUG -# define ifdebug(flag) if (nfsd_debug & NFSDDBG_##flag) -# else -# define ifdebug(flag) if (0) -# endif -#endif /* LINUX_NFSD_DEBUG_H */ diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h deleted file mode 100644 index a93593f1fa4ea7..00000000000000 --- a/include/linux/nfsd/nfsfh.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * include/linux/nfsd/nfsfh.h - * - * This file describes the layout of the file handles as passed - * over the wire. - * - * Earlier versions of knfsd used to sign file handles using keyed MD5 - * or SHA. I've removed this code, because it doesn't give you more - * security than blocking external access to port 2049 on your firewall. - * - * Copyright (C) 1995, 1996, 1997 Olaf Kirch - */ -#ifndef _LINUX_NFSD_FH_H -#define _LINUX_NFSD_FH_H - -# include -#include - -static inline __u32 ino_t_to_u32(ino_t ino) -{ - return (__u32) ino; -} - -static inline ino_t u32_to_ino_t(__u32 uino) -{ - return (ino_t) uino; -} - -/* - * This is the internal representation of an NFS handle used in knfsd. - * pre_mtime/post_version will be used to support wcc_attr's in NFSv3. - */ -typedef struct svc_fh { - struct knfsd_fh fh_handle; /* FH data */ - struct dentry * fh_dentry; /* validated dentry */ - struct svc_export * fh_export; /* export pointer */ - int fh_maxsize; /* max size for fh_handle */ - - unsigned char fh_locked; /* inode locked by us */ - unsigned char fh_want_write; /* remount protection taken */ - -#ifdef CONFIG_NFSD_V3 - unsigned char fh_post_saved; /* post-op attrs saved */ - unsigned char fh_pre_saved; /* pre-op attrs saved */ - - /* Pre-op attributes saved during fh_lock */ - __u64 fh_pre_size; /* size before operation */ - struct timespec fh_pre_mtime; /* mtime before oper */ - struct timespec fh_pre_ctime; /* ctime before oper */ - /* - * pre-op nfsv4 change attr: note must check IS_I_VERSION(inode) - * to find out if it is valid. - */ - u64 fh_pre_change; - - /* Post-op attributes saved in fh_unlock */ - struct kstat fh_post_attr; /* full attrs after operation */ - u64 fh_post_change; /* nfsv4 change; see above */ -#endif /* CONFIG_NFSD_V3 */ - -} svc_fh; - -#endif /* _LINUX_NFSD_FH_H */ diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 5f6ed6b182b8ef..839a3521b28ebf 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -63,6 +63,9 @@ extern int of_pci_range_parser_init(struct of_pci_range_parser *parser, extern struct of_pci_range *of_pci_range_parser_one( struct of_pci_range_parser *parser, struct of_pci_range *range); +extern int of_dma_get_range(struct device_node *np, u64 *dma_addr, + u64 *paddr, u64 *size); +extern bool of_dma_is_coherent(struct device_node *np); #else /* CONFIG_OF_ADDRESS */ static inline struct device_node *of_find_matching_node_by_address( struct device_node *from, @@ -90,6 +93,17 @@ static inline struct of_pci_range *of_pci_range_parser_one( { return NULL; } + +static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr, + u64 *paddr, u64 *size) +{ + return -ENODEV; +} + +static inline bool of_dma_is_coherent(struct device_node *np) +{ + return false; +} #endif /* CONFIG_OF_ADDRESS */ #ifdef CONFIG_OF diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index ddd7219af8ac4c..5c0ab057eecf7c 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -17,60 +17,23 @@ /* Definitions used by the flattened device tree */ #define OF_DT_HEADER 0xd00dfeed /* marker */ -#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ -#define OF_DT_END_NODE 0x2 /* End node */ -#define OF_DT_PROP 0x3 /* Property: name off, size, - * content */ -#define OF_DT_NOP 0x4 /* nop */ -#define OF_DT_END 0x9 - -#define OF_DT_VERSION 0x10 #ifndef __ASSEMBLY__ -/* - * This is what gets passed to the kernel by prom_init or kexec - * - * The dt struct contains the device tree structure, full pathes and - * property contents. The dt strings contain a separate block with just - * the strings for the property names, and is fully page aligned and - * self contained in a page, so that it can be kept around by the kernel, - * each property name appears only once in this page (cheap compression) - * - * the mem_rsvmap contains a map of reserved ranges of physical memory, - * passing it here instead of in the device-tree itself greatly simplifies - * the job of everybody. It's just a list of u64 pairs (base/size) that - * ends when size is 0 - */ -struct boot_param_header { - __be32 magic; /* magic word OF_DT_HEADER */ - __be32 totalsize; /* total size of DT block */ - __be32 off_dt_struct; /* offset to structure */ - __be32 off_dt_strings; /* offset to strings */ - __be32 off_mem_rsvmap; /* offset to memory reserve map */ - __be32 version; /* format version */ - __be32 last_comp_version; /* last compatible version */ - /* version 2 fields below */ - __be32 boot_cpuid_phys; /* Physical CPU id we're booting on */ - /* version 3 fields below */ - __be32 dt_strings_size; /* size of the DT strings block */ - /* version 17 fields below */ - __be32 dt_struct_size; /* size of the DT structure block */ -}; #if defined(CONFIG_OF_FLATTREE) struct device_node; /* For scanning an arbitrary device-tree at any time */ -extern char *of_fdt_get_string(struct boot_param_header *blob, u32 offset); -extern void *of_fdt_get_property(struct boot_param_header *blob, +extern char *of_fdt_get_string(const void *blob, u32 offset); +extern void *of_fdt_get_property(const void *blob, unsigned long node, const char *name, - unsigned long *size); -extern int of_fdt_is_compatible(struct boot_param_header *blob, + int *size); +extern int of_fdt_is_compatible(const void *blob, unsigned long node, const char *compat); -extern int of_fdt_match(struct boot_param_header *blob, unsigned long node, +extern int of_fdt_match(const void *blob, unsigned long node, const char *const *compat); extern void of_fdt_unflatten_tree(unsigned long *blob, struct device_node **mynodes); @@ -78,21 +41,21 @@ extern void of_fdt_unflatten_tree(unsigned long *blob, /* TBD: Temporary export of fdt globals - remove when code fully merged */ extern int __initdata dt_root_addr_cells; extern int __initdata dt_root_size_cells; -extern struct boot_param_header *initial_boot_params; +extern void *initial_boot_params; + +extern char __dtb_start[]; +extern char __dtb_end[]; /* For scanning the flat device-tree at boot time */ -extern char *find_flat_dt_string(u32 offset); extern int of_scan_flat_dt(int (*it)(unsigned long node, const char *uname, int depth, void *data), void *data); -extern void *of_get_flat_dt_prop(unsigned long node, const char *name, - unsigned long *size); +extern const void *of_get_flat_dt_prop(unsigned long node, const char *name, + int *size); extern int of_flat_dt_is_compatible(unsigned long node, const char *name); extern int of_flat_dt_match(unsigned long node, const char *const *matches); extern unsigned long of_get_flat_dt_root(void); -extern int of_scan_flat_dt_by_path(const char *path, - int (*it)(unsigned long node, const char *name, int depth, void *data), - void *data); +extern int of_get_flat_dt_size(void); extern int early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data); @@ -103,7 +66,7 @@ extern void early_init_dt_add_memory_arch(u64 base, u64 size); extern int early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size, bool no_map); extern void * early_init_dt_alloc_memory_arch(u64 size, u64 align); -extern u64 dt_mem_next_cell(int s, __be32 **cellp); +extern u64 dt_mem_next_cell(int s, const __be32 **cellp); /* Early flat tree scan hooks */ extern int early_init_dt_scan_root(unsigned long node, const char *uname, diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h index 6fe8464ed767f0..881a7c3571f461 100644 --- a/include/linux/of_mdio.h +++ b/include/linux/of_mdio.h @@ -31,7 +31,12 @@ extern struct mii_bus *of_mdio_find_bus(struct device_node *mdio_np); #else /* CONFIG_OF */ static inline int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) { - return -ENOSYS; + /* + * Fall back to the non-DT function to register a bus. + * This way, we don't have to keep compat bits around in drivers. + */ + + return mdiobus_register(mdio); } static inline struct phy_device *of_phy_find_device(struct device_node *phy_np) diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index 05cb4a92825225..8cdd53bf1114a8 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -37,7 +37,7 @@ * Note: Using an auxdata lookup table should be considered a last resort when * converting a platform to use the DT. Normally the automatically generated * device name will not matter, and drivers should obtain data from the device - * node instead of from an anonymouns platform_data pointer. + * node instead of from an anonymous platform_data pointer. */ struct of_dev_auxdata { char *compatible; diff --git a/include/linux/omap-dma.h b/include/linux/omap-dma.h index 41a13e70f41f5a..0a1a2e2d5c217a 100644 --- a/include/linux/omap-dma.h +++ b/include/linux/omap-dma.h @@ -393,7 +393,7 @@ extern int omap_modify_dma_chain_params(int chain_id, extern int omap_dma_chain_status(int chain_id); #endif -#if defined(CONFIG_ARCH_OMAP1) && defined(CONFIG_FB_OMAP) +#if defined(CONFIG_ARCH_OMAP1) && IS_ENABLED(CONFIG_FB_OMAP) #include #else static inline int omap_lcd_dma_running(void) diff --git a/include/linux/pci.h b/include/linux/pci.h index aab57b4abe7fce..a95aac7ad37fd5 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -680,8 +680,8 @@ struct pci_driver { /** * PCI_VDEVICE - macro used to describe a specific pci device in short form - * @vendor: the vendor name - * @device: the 16 bit PCI Device ID + * @vend: the vendor name + * @dev: the 16 bit PCI Device ID * * This macro is used to create a struct pci_device_id that matches a * specific PCI device. The subvendor, and subdevice fields will be set @@ -689,9 +689,9 @@ struct pci_driver { * private data. */ -#define PCI_VDEVICE(vendor, device) \ - PCI_VENDOR_ID_##vendor, (device), \ - PCI_ANY_ID, PCI_ANY_ID, 0, 0 +#define PCI_VDEVICE(vend, dev) \ + .vendor = PCI_VENDOR_ID_##vend, .device = (dev), \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0 /* these external functions are only available when PCI support is enabled */ #ifdef CONFIG_PCI diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index d4de24b4d4c64a..7fa31731c8548e 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1631,8 +1631,6 @@ #define PCI_DEVICE_ID_ATT_VENUS_MODEM 0x480 #define PCI_VENDOR_ID_SPECIALIX 0x11cb -#define PCI_DEVICE_ID_SPECIALIX_IO8 0x2000 -#define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000 #define PCI_SUBDEVICE_ID_SPECIALIX_SPEED4 0xa004 #define PCI_VENDOR_ID_ANALOG_DEVICES 0x11d4 @@ -2874,7 +2872,6 @@ #define PCI_DEVICE_ID_SCALEMP_VSMP_CTL 0x1010 #define PCI_VENDOR_ID_COMPUTONE 0x8e0e -#define PCI_DEVICE_ID_COMPUTONE_IP2EX 0x0291 #define PCI_DEVICE_ID_COMPUTONE_PG 0x0302 #define PCI_SUBVENDOR_ID_COMPUTONE 0x8e0e #define PCI_SUBDEVICE_ID_COMPUTONE_PG4 0x0001 diff --git a/include/linux/percpu.h b/include/linux/percpu.h index e7a0b95ed5279b..8419053d0f2e88 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -29,7 +29,7 @@ */ #define get_cpu_var(var) (*({ \ preempt_disable(); \ - &__get_cpu_var(var); })) + this_cpu_ptr(&var); })) /* * The weird & is necessary because sparse considers (void)(var) to be @@ -639,7 +639,7 @@ do { \ # define raw_cpu_add_return_8(pcp, val) raw_cpu_generic_add_return(pcp, val) # endif # define raw_cpu_add_return(pcp, val) \ - __pcpu_size_call_return2(raw_add_return_, pcp, val) + __pcpu_size_call_return2(raw_cpu_add_return_, pcp, val) #endif #define raw_cpu_sub_return(pcp, val) raw_cpu_add_return(pcp, -(typeof(pcp))(val)) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 3356abcfff184e..af6dcf1d9e476c 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -172,6 +172,7 @@ struct perf_event; struct pmu { struct list_head entry; + struct module *module; struct device *dev; const struct attribute_group **attr_groups; const char *name; diff --git a/include/linux/phy.h b/include/linux/phy.h index 4d0221fd0688df..864ddafad8cc2f 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -198,6 +198,13 @@ static inline struct mii_bus *mdiobus_alloc(void) int mdiobus_register(struct mii_bus *bus); void mdiobus_unregister(struct mii_bus *bus); void mdiobus_free(struct mii_bus *bus); +struct mii_bus *devm_mdiobus_alloc_size(struct device *dev, int sizeof_priv); +static inline struct mii_bus *devm_mdiobus_alloc(struct device *dev) +{ + return devm_mdiobus_alloc_size(dev, 0); +} + +void devm_mdiobus_free(struct device *dev, struct mii_bus *bus); struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr); int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum); int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val); @@ -666,6 +673,7 @@ static inline int phy_read_status(struct phy_device *phydev) return phydev->drv->read_status(phydev); } +int genphy_config_init(struct phy_device *phydev); int genphy_setup_forced(struct phy_device *phydev); int genphy_restart_aneg(struct phy_device *phydev); int genphy_config_aneg(struct phy_device *phydev); diff --git a/include/linux/platform_data/edma.h b/include/linux/platform_data/edma.h index f50821cb64be8c..12f134b1493c40 100644 --- a/include/linux/platform_data/edma.h +++ b/include/linux/platform_data/edma.h @@ -43,15 +43,15 @@ /* PaRAM slots are laid out like this */ struct edmacc_param { - unsigned int opt; - unsigned int src; - unsigned int a_b_cnt; - unsigned int dst; - unsigned int src_dst_bidx; - unsigned int link_bcntrld; - unsigned int src_dst_cidx; - unsigned int ccnt; -}; + u32 opt; + u32 src; + u32 a_b_cnt; + u32 dst; + u32 src_dst_bidx; + u32 link_bcntrld; + u32 src_dst_cidx; + u32 ccnt; +} __packed; /* fields in edmacc_param.opt */ #define SAM BIT(0) @@ -130,7 +130,7 @@ void edma_set_src(unsigned slot, dma_addr_t src_port, enum address_mode mode, enum fifo_width); void edma_set_dest(unsigned slot, dma_addr_t dest_port, enum address_mode mode, enum fifo_width); -void edma_get_position(unsigned slot, dma_addr_t *src, dma_addr_t *dst); +dma_addr_t edma_get_position(unsigned slot, bool dst); void edma_set_src_index(unsigned slot, s16 src_bidx, s16 src_cidx); void edma_set_dest_index(unsigned slot, s16 dest_bidx, s16 dest_cidx); void edma_set_transfer_params(unsigned slot, u16 acnt, u16 bcnt, u16 ccnt, diff --git a/include/linux/platform_data/leds-pca9685.h b/include/linux/platform_data/leds-pca9685.h deleted file mode 100644 index 778e9e4249cc96..00000000000000 --- a/include/linux/platform_data/leds-pca9685.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013 Maximilian Güntner - * - * This file is subject to the terms and conditions of version 2 of - * the GNU General Public License. See the file COPYING in the main - * directory of this archive for more details. - * - * Based on leds-pca963x.h by Peter Meerwald - * - * LED driver for the NXP PCA9685 PWM chip - * - */ - -#ifndef __LINUX_PCA9685_H -#define __LINUX_PCA9685_H - -#include - -enum pca9685_outdrv { - PCA9685_OPEN_DRAIN, - PCA9685_TOTEM_POLE, -}; - -enum pca9685_inverted { - PCA9685_NOT_INVERTED, - PCA9685_INVERTED, -}; - -struct pca9685_platform_data { - struct led_platform_data leds; - enum pca9685_outdrv outdrv; - enum pca9685_inverted inverted; -}; - -#endif /* __LINUX_PCA9685_H */ diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 5151b005958500..0330217abfad91 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -15,7 +15,6 @@ #define __LINUX_OPP_H__ #include -#include #include struct dev_pm_opp; @@ -117,23 +116,4 @@ static inline int of_init_opp_table(struct device *dev) } #endif -#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_PM_OPP) -int dev_pm_opp_init_cpufreq_table(struct device *dev, - struct cpufreq_frequency_table **table); -void dev_pm_opp_free_cpufreq_table(struct device *dev, - struct cpufreq_frequency_table **table); -#else -static inline int dev_pm_opp_init_cpufreq_table(struct device *dev, - struct cpufreq_frequency_table **table) -{ - return -EINVAL; -} - -static inline -void dev_pm_opp_free_cpufreq_table(struct device *dev, - struct cpufreq_frequency_table **table) -{ -} -#endif /* CONFIG_CPU_FREQ */ - #endif /* __LINUX_OPP_H__ */ diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h index 2de2e275b2cbd1..efdd9227a49c9c 100644 --- a/include/linux/pwm_backlight.h +++ b/include/linux/pwm_backlight.h @@ -6,9 +6,6 @@ #include -/* TODO: convert to gpiod_*() API once it has been merged */ -#define PWM_BACKLIGHT_GPIO_ACTIVE_LOW (1 << 0) - struct platform_pwm_backlight_data { int pwm_id; unsigned int max_brightness; @@ -16,8 +13,8 @@ struct platform_pwm_backlight_data { unsigned int lth_brightness; unsigned int pwm_period_ns; unsigned int *levels; + /* TODO remove once all users are switched to gpiod_* API */ int enable_gpio; - unsigned long enable_gpio_flags; int (*init)(struct device *dev); int (*notify)(struct device *dev, int brightness); void (*notify_after)(struct device *dev, int brightness); diff --git a/include/linux/quota.h b/include/linux/quota.h index cc7494a3542983..0f3c5d38da1fb2 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -329,6 +329,7 @@ struct quotactl_ops { int (*get_xstate)(struct super_block *, struct fs_quota_stat *); int (*set_xstate)(struct super_block *, unsigned int, int); int (*get_xstatev)(struct super_block *, struct fs_quota_statv *); + int (*rm_xquota)(struct super_block *, unsigned int); }; struct quota_format_type { diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index ec3959b5b24352..ca6fe55913b77e 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -44,6 +44,7 @@ #include #include #include +#include #include extern int rcu_expedited; /* for sysctl */ @@ -51,7 +52,17 @@ extern int rcu_expedited; /* for sysctl */ extern int rcutorture_runnable; /* for sysctl */ #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */ +enum rcutorture_type { + RTORT_BUSTED, + RTORT_RCU, + RTORT_RCU_BH, + RTORT_RCU_SCHED, + RTORT_SRCU +}; + #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) +void rcutorture_get_gp_data(enum rcutorture_type test_type, int *flags, + unsigned long *gpnum, unsigned long *completed); void rcutorture_record_test_transition(void); void rcutorture_record_progress(unsigned long vernum); void do_trace_rcu_torture_read(const char *rcutorturename, @@ -60,6 +71,15 @@ void do_trace_rcu_torture_read(const char *rcutorturename, unsigned long c_old, unsigned long c); #else +static inline void rcutorture_get_gp_data(enum rcutorture_type test_type, + int *flags, + unsigned long *gpnum, + unsigned long *completed) +{ + *flags = 0; + *gpnum = 0; + *completed = 0; +} static inline void rcutorture_record_test_transition(void) { } @@ -279,6 +299,41 @@ static inline void rcu_user_hooks_switch(struct task_struct *prev, bool __rcu_is_watching(void); #endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP) */ +/* + * Hooks for cond_resched() and friends to avoid RCU CPU stall warnings. + */ + +#define RCU_COND_RESCHED_LIM 256 /* ms vs. 100s of ms. */ +DECLARE_PER_CPU(int, rcu_cond_resched_count); +void rcu_resched(void); + +/* + * Is it time to report RCU quiescent states? + * + * Note unsynchronized access to rcu_cond_resched_count. Yes, we might + * increment some random CPU's count, and possibly also load the result from + * yet another CPU's count. We might even clobber some other CPU's attempt + * to zero its counter. This is all OK because the goal is not precision, + * but rather reasonable amortization of rcu_note_context_switch() overhead + * and extremely high probability of avoiding RCU CPU stall warnings. + * Note that this function has to be preempted in just the wrong place, + * many thousands of times in a row, for anything bad to happen. + */ +static inline bool rcu_should_resched(void) +{ + return raw_cpu_inc_return(rcu_cond_resched_count) >= + RCU_COND_RESCHED_LIM; +} + +/* + * Report quiscent states to RCU if it is time to do so. + */ +static inline void rcu_cond_resched(void) +{ + if (unlikely(rcu_should_resched())) + rcu_resched(); +} + /* * Infrastructure to implement the synchronize_() primitives in * TREE_RCU and rcu_barrier_() primitives in TINY_RCU. @@ -340,7 +395,7 @@ extern struct lockdep_map rcu_lock_map; extern struct lockdep_map rcu_bh_lock_map; extern struct lockdep_map rcu_sched_lock_map; extern struct lockdep_map rcu_callback_map; -extern int debug_lockdep_rcu_enabled(void); +int debug_lockdep_rcu_enabled(void); /** * rcu_read_lock_held() - might we be in RCU read-side critical section? @@ -961,6 +1016,9 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) * pointers, but you must use rcu_assign_pointer() to initialize the * external-to-structure pointer -after- you have completely initialized * the reader-accessible portions of the linked structure. + * + * Note that unlike rcu_assign_pointer(), RCU_INIT_POINTER() provides no + * ordering guarantees for either the CPU or the compiler. */ #define RCU_INIT_POINTER(p, v) \ do { \ diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 425c659d54e576..d40a6a45133040 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -119,6 +119,10 @@ static inline void rcu_sched_force_quiescent_state(void) { } +static inline void show_rcu_gp_kthreads(void) +{ +} + static inline void rcu_cpu_stall_reset(void) { } diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index a59ca05fd4e36e..3e2f5d432743cc 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -84,6 +84,7 @@ extern unsigned long rcutorture_vernum; long rcu_batches_completed(void); long rcu_batches_completed_bh(void); long rcu_batches_completed_sched(void); +void show_rcu_gp_kthreads(void); void rcu_force_quiescent_state(void); void rcu_bh_force_quiescent_state(void); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 85691b9b4fa76a..7b0e4b425cdf3e 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -276,6 +276,10 @@ typedef int (*regmap_hw_async_write)(void *context, typedef int (*regmap_hw_read)(void *context, const void *reg_buf, size_t reg_size, void *val_buf, size_t val_size); +typedef int (*regmap_hw_reg_read)(void *context, unsigned int reg, + unsigned int *val); +typedef int (*regmap_hw_reg_write)(void *context, unsigned int reg, + unsigned int val); typedef struct regmap_async *(*regmap_hw_async_alloc)(void); typedef void (*regmap_hw_free_context)(void *context); @@ -309,7 +313,9 @@ struct regmap_bus { regmap_hw_write write; regmap_hw_gather_write gather_write; regmap_hw_async_write async_write; + regmap_hw_reg_write reg_write; regmap_hw_read read; + regmap_hw_reg_read reg_read; regmap_hw_free_context free_context; regmap_hw_async_alloc async_alloc; u8 read_flag_mask; diff --git a/include/linux/rfkill-gpio.h b/include/linux/rfkill-gpio.h index 4d09f6eab359f8..20bcb55498cd57 100644 --- a/include/linux/rfkill-gpio.h +++ b/include/linux/rfkill-gpio.h @@ -27,21 +27,11 @@ * struct rfkill_gpio_platform_data - platform data for rfkill gpio device. * for unused gpio's, the expected value is -1. * @name: name for the gpio rf kill instance - * @reset_gpio: GPIO which is used for reseting rfkill switch - * @shutdown_gpio: GPIO which is used for shutdown of rfkill switch - * @power_clk_name: [optional] name of clk to turn off while blocked - * @gpio_runtime_close: clean up platform specific gpio configuration - * @gpio_runtime_setup: set up platform specific gpio configuration */ struct rfkill_gpio_platform_data { char *name; - int reset_gpio; - int shutdown_gpio; - const char *power_clk_name; enum rfkill_type type; - void (*gpio_runtime_close)(struct platform_device *); - int (*gpio_runtime_setup)(struct platform_device *); }; #endif /* __RFKILL_GPIO_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index d7c5ba9c864eea..9112646911bcff 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -863,6 +863,7 @@ enum cpu_idle_type { #define SD_BALANCE_WAKE 0x0010 /* Balance on wakeup */ #define SD_WAKE_AFFINE 0x0020 /* Wake task to waking CPU */ #define SD_SHARE_CPUPOWER 0x0080 /* Domain members share cpu power */ +#define SD_SHARE_POWERDOMAIN 0x0100 /* Domain members share power domain */ #define SD_SHARE_PKG_RESOURCES 0x0200 /* Domain members share cpu pkg resources */ #define SD_SERIALIZE 0x0400 /* Only a single load balancing instance */ #define SD_ASYM_PACKING 0x0800 /* Place busy groups earlier in the domain */ @@ -870,7 +871,26 @@ enum cpu_idle_type { #define SD_OVERLAP 0x2000 /* sched_domains of this level overlap */ #define SD_NUMA 0x4000 /* cross-node balancing */ -extern int __weak arch_sd_sibiling_asym_packing(void); +#ifdef CONFIG_SCHED_SMT +static inline const int cpu_smt_flags(void) +{ + return SD_SHARE_CPUPOWER | SD_SHARE_PKG_RESOURCES; +} +#endif + +#ifdef CONFIG_SCHED_MC +static inline const int cpu_core_flags(void) +{ + return SD_SHARE_PKG_RESOURCES; +} +#endif + +#ifdef CONFIG_NUMA +static inline const int cpu_numa_flags(void) +{ + return SD_NUMA; +} +#endif struct sched_domain_attr { int relax_domain_level; @@ -978,6 +998,38 @@ void free_sched_domains(cpumask_var_t doms[], unsigned int ndoms); bool cpus_share_cache(int this_cpu, int that_cpu); +typedef const struct cpumask *(*sched_domain_mask_f)(int cpu); +typedef const int (*sched_domain_flags_f)(void); + +#define SDTL_OVERLAP 0x01 + +struct sd_data { + struct sched_domain **__percpu sd; + struct sched_group **__percpu sg; + struct sched_group_power **__percpu sgp; +}; + +struct sched_domain_topology_level { + sched_domain_mask_f mask; + sched_domain_flags_f sd_flags; + int flags; + int numa_level; + struct sd_data data; +#ifdef CONFIG_SCHED_DEBUG + char *name; +#endif +}; + +extern struct sched_domain_topology_level *sched_domain_topology; + +extern void set_sched_topology(struct sched_domain_topology_level *tl); + +#ifdef CONFIG_SCHED_DEBUG +# define SD_INIT_NAME(type) .name = #type +#else +# define SD_INIT_NAME(type) +#endif + #else /* CONFIG_SMP */ struct sched_domain_attr; @@ -1146,9 +1198,12 @@ struct sched_dl_entity { * * @dl_boosted tells if we are boosted due to DI. If so we are * outside bandwidth enforcement mechanism (but only until we - * exit the critical section). + * exit the critical section); + * + * @dl_yielded tells if task gave up the cpu before consuming + * all its available runtime during the last job. */ - int dl_throttled, dl_new, dl_boosted; + int dl_throttled, dl_new, dl_boosted, dl_yielded; /* * Bandwidth enforcement timer. Each -deadline task has its @@ -2710,51 +2765,9 @@ static inline int spin_needbreak(spinlock_t *lock) /* * Idle thread specific functions to determine the need_resched - * polling state. We have two versions, one based on TS_POLLING in - * thread_info.status and one based on TIF_POLLING_NRFLAG in - * thread_info.flags + * polling state. */ -#ifdef TS_POLLING -static inline int tsk_is_polling(struct task_struct *p) -{ - return task_thread_info(p)->status & TS_POLLING; -} -static inline void __current_set_polling(void) -{ - current_thread_info()->status |= TS_POLLING; -} - -static inline bool __must_check current_set_polling_and_test(void) -{ - __current_set_polling(); - - /* - * Polling state must be visible before we test NEED_RESCHED, - * paired by resched_task() - */ - smp_mb(); - - return unlikely(tif_need_resched()); -} - -static inline void __current_clr_polling(void) -{ - current_thread_info()->status &= ~TS_POLLING; -} - -static inline bool __must_check current_clr_polling_and_test(void) -{ - __current_clr_polling(); - - /* - * Polling state must be visible before we test NEED_RESCHED, - * paired by resched_task() - */ - smp_mb(); - - return unlikely(tif_need_resched()); -} -#elif defined(TIF_POLLING_NRFLAG) +#ifdef TIF_POLLING_NRFLAG static inline int tsk_is_polling(struct task_struct *p) { return test_tsk_thread_flag(p, TIF_POLLING_NRFLAG); @@ -2772,10 +2785,8 @@ static inline bool __must_check current_set_polling_and_test(void) /* * Polling state must be visible before we test NEED_RESCHED, * paired by resched_task() - * - * XXX: assumes set/clear bit are identical barrier wise. */ - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return unlikely(tif_need_resched()); } @@ -2793,7 +2804,7 @@ static inline bool __must_check current_clr_polling_and_test(void) * Polling state must be visible before we test NEED_RESCHED, * paired by resched_task() */ - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return unlikely(tif_need_resched()); } diff --git a/include/linux/security.h b/include/linux/security.h index 6478ce3252c7d8..9c6b9722ff48d5 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1708,7 +1708,7 @@ struct security_operations { void (*key_free) (struct key *key); int (*key_permission) (key_ref_t key_ref, const struct cred *cred, - key_perm_t perm); + unsigned perm); int (*key_getsecurity)(struct key *key, char **_buffer); #endif /* CONFIG_KEYS */ @@ -3034,7 +3034,7 @@ static inline int security_path_chroot(struct path *path) int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags); void security_key_free(struct key *key); int security_key_permission(key_ref_t key_ref, - const struct cred *cred, key_perm_t perm); + const struct cred *cred, unsigned perm); int security_key_getsecurity(struct key *key, char **_buffer); #else @@ -3052,7 +3052,7 @@ static inline void security_key_free(struct key *key) static inline int security_key_permission(key_ref_t key_ref, const struct cred *cred, - key_perm_t perm) + unsigned perm) { return 0; } diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index f729be981da086..7a15b5b24c0bec 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -285,6 +285,22 @@ static inline int uart_poll_timeout(struct uart_port *port) /* * Console helpers. */ +struct earlycon_device { + struct console *con; + struct uart_port port; + char options[16]; /* e.g., 115200n8 */ + unsigned int baud; +}; +int setup_earlycon(char *buf, const char *match, + int (*setup)(struct earlycon_device *, const char *)); + +#define EARLYCON_DECLARE(name, func) \ +static int __init name ## _setup_earlycon(char *buf) \ +{ \ + return setup_earlycon(buf, __stringify(name), func); \ +} \ +early_param("earlycon", name ## _setup_earlycon); + struct uart_port *uart_get_console(struct uart_port *ports, int nr, struct console *c); void uart_parse_options(char *options, int *baud, int *parity, int *bits, diff --git a/include/linux/shdma-base.h b/include/linux/shdma-base.h index f92c0a43c54cb9..abdf1f229dc3d0 100644 --- a/include/linux/shdma-base.h +++ b/include/linux/shdma-base.h @@ -54,6 +54,7 @@ struct shdma_desc { dma_cookie_t cookie; int chunks; int mark; + bool cyclic; /* used as cyclic transfer */ }; struct shdma_chan { diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 08074a8101646d..3ca0dda5a42e8c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2741,6 +2741,99 @@ static inline __sum16 skb_checksum_complete(struct sk_buff *skb) 0 : __skb_checksum_complete(skb); } +/* Check if we need to perform checksum complete validation. + * + * Returns true if checksum complete is needed, false otherwise + * (either checksum is unnecessary or zero checksum is allowed). + */ +static inline bool __skb_checksum_validate_needed(struct sk_buff *skb, + bool zero_okay, + __sum16 check) +{ + if (skb_csum_unnecessary(skb)) { + return false; + } else if (zero_okay && !check) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + return false; + } + + return true; +} + +/* For small packets <= CHECKSUM_BREAK peform checksum complete directly + * in checksum_init. + */ +#define CHECKSUM_BREAK 76 + +/* Validate (init) checksum based on checksum complete. + * + * Return values: + * 0: checksum is validated or try to in skb_checksum_complete. In the latter + * case the ip_summed will not be CHECKSUM_UNNECESSARY and the pseudo + * checksum is stored in skb->csum for use in __skb_checksum_complete + * non-zero: value of invalid checksum + * + */ +static inline __sum16 __skb_checksum_validate_complete(struct sk_buff *skb, + bool complete, + __wsum psum) +{ + if (skb->ip_summed == CHECKSUM_COMPLETE) { + if (!csum_fold(csum_add(psum, skb->csum))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + return 0; + } + } + + skb->csum = psum; + + if (complete || skb->len <= CHECKSUM_BREAK) + return __skb_checksum_complete(skb); + + return 0; +} + +static inline __wsum null_compute_pseudo(struct sk_buff *skb, int proto) +{ + return 0; +} + +/* Perform checksum validate (init). Note that this is a macro since we only + * want to calculate the pseudo header which is an input function if necessary. + * First we try to validate without any computation (checksum unnecessary) and + * then calculate based on checksum complete calling the function to compute + * pseudo header. + * + * Return values: + * 0: checksum is validated or try to in skb_checksum_complete + * non-zero: value of invalid checksum + */ +#define __skb_checksum_validate(skb, proto, complete, \ + zero_okay, check, compute_pseudo) \ +({ \ + __sum16 __ret = 0; \ + if (__skb_checksum_validate_needed(skb, zero_okay, check)) \ + __ret = __skb_checksum_validate_complete(skb, \ + complete, compute_pseudo(skb, proto)); \ + __ret; \ +}) + +#define skb_checksum_init(skb, proto, compute_pseudo) \ + __skb_checksum_validate(skb, proto, false, false, 0, compute_pseudo) + +#define skb_checksum_init_zero_check(skb, proto, check, compute_pseudo) \ + __skb_checksum_validate(skb, proto, false, true, check, compute_pseudo) + +#define skb_checksum_validate(skb, proto, compute_pseudo) \ + __skb_checksum_validate(skb, proto, true, false, 0, compute_pseudo) + +#define skb_checksum_validate_zero_check(skb, proto, check, \ + compute_pseudo) \ + __skb_checksum_validate_(skb, proto, true, true, check, compute_pseudo) + +#define skb_checksum_simple_validate(skb) \ + __skb_checksum_validate(skb, 0, true, false, 0, null_compute_pseudo) + #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) void nf_conntrack_destroy(struct nf_conntrack *nfct); static inline void nf_conntrack_put(struct nf_conntrack *nfct) diff --git a/include/linux/smp.h b/include/linux/smp.h index 633f5edd7470c0..0de1effbdd76d8 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -29,6 +29,17 @@ extern unsigned int total_cpus; int smp_call_function_single(int cpuid, smp_call_func_t func, void *info, int wait); +struct queue_single_data; +typedef void (*smp_queue_func_t)(struct queue_single_data *qsd); + +struct queue_single_data { + struct call_single_data data; + smp_queue_func_t func; + int pending; +}; + +int smp_queue_function_single(int cpu, struct queue_single_data *qsd); + /* * Call a function on all processors */ diff --git a/arch/blackfin/include/asm/bfin_spi3.h b/include/linux/spi/adi_spi3.h similarity index 97% rename from arch/blackfin/include/asm/bfin_spi3.h rename to include/linux/spi/adi_spi3.h index 0957e65a54be39..c84123aa1d06ac 100644 --- a/arch/blackfin/include/asm/bfin_spi3.h +++ b/include/linux/spi/adi_spi3.h @@ -1,7 +1,7 @@ /* * Analog Devices SPI3 controller driver * - * Copyright (c) 2011 Analog Devices Inc. + * Copyright (c) 2014 Analog Devices 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 @@ -11,14 +11,10 @@ * 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 _SPI_CHANNEL_H_ -#define _SPI_CHANNEL_H_ +#ifndef _ADI_SPI3_H_ +#define _ADI_SPI3_H_ #include @@ -209,9 +205,9 @@ #define SPI_ILAT_CLR_TFI 0x00000800 /* Transmit Finish Indication */ /* - * bfin spi3 registers layout + * adi spi3 registers layout */ -struct bfin_spi_regs { +struct adi_spi_regs { u32 revid; u32 control; u32 rx_control; @@ -240,7 +236,7 @@ struct bfin_spi_regs { #define MAX_CTRL_CS 8 /* cs in spi controller */ /* device.platform_data for SSP controller devices */ -struct bfin_spi3_master { +struct adi_spi3_master { u16 num_chipselect; u16 pin_req[7]; }; @@ -248,11 +244,11 @@ struct bfin_spi3_master { /* spi_board_info.controller_data for SPI slave devices, * copied to spi_device.platform_data ... mostly for dma tuning */ -struct bfin_spi3_chip { +struct adi_spi3_chip { u32 control; u16 cs_chg_udelay; /* Some devices require 16-bit delays */ u32 tx_dummy_val; /* tx value for rx only transfer */ bool enable_dma; }; -#endif /* _SPI_CHANNEL_H_ */ +#endif /* _ADI_SPI3_H_ */ diff --git a/include/linux/spi/at86rf230.h b/include/linux/spi/at86rf230.h index aa327a8105ada0..b2b1afbb32024e 100644 --- a/include/linux/spi/at86rf230.h +++ b/include/linux/spi/at86rf230.h @@ -26,20 +26,6 @@ struct at86rf230_platform_data { int rstn; int slp_tr; int dig2; - - /* Setting the irq_type will configure the driver to request - * the platform irq trigger type according to the given value - * and configure the interrupt polarity of the device to the - * corresponding polarity. - * - * Allowed values are: IRQF_TRIGGER_RISING, IRQF_TRIGGER_FALLING, - * IRQF_TRIGGER_HIGH and IRQF_TRIGGER_LOW - * - * Setting it to 0, the driver does not touch the trigger type - * configuration of the interrupt and sets the interrupt polarity - * of the device to high active (the default value). - */ - int irq_type; }; #endif diff --git a/include/linux/splice.h b/include/linux/splice.h index 0e43906d2fda6d..da2751d3b93db5 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h @@ -70,16 +70,6 @@ extern ssize_t splice_from_pipe(struct pipe_inode_info *, struct file *, splice_actor *); extern ssize_t __splice_from_pipe(struct pipe_inode_info *, struct splice_desc *, splice_actor *); -extern int splice_from_pipe_feed(struct pipe_inode_info *, struct splice_desc *, - splice_actor *); -extern int splice_from_pipe_next(struct pipe_inode_info *, - struct splice_desc *); -extern void splice_from_pipe_begin(struct splice_desc *); -extern void splice_from_pipe_end(struct pipe_inode_info *, - struct splice_desc *); -extern int pipe_to_file(struct pipe_inode_info *, struct pipe_buffer *, - struct splice_desc *); - extern ssize_t splice_to_pipe(struct pipe_inode_info *, struct splice_pipe_desc *); extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 3a847de83fabd5..ad7dbe2cfecd84 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -142,18 +142,18 @@ struct rpc_task_setup { test_and_set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) #define rpc_clear_running(t) \ do { \ - smp_mb__before_clear_bit(); \ + smp_mb__before_atomic(); \ clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate); \ - smp_mb__after_clear_bit(); \ + smp_mb__after_atomic(); \ } while (0) #define RPC_IS_QUEUED(t) test_bit(RPC_TASK_QUEUED, &(t)->tk_runstate) #define rpc_set_queued(t) set_bit(RPC_TASK_QUEUED, &(t)->tk_runstate) #define rpc_clear_queued(t) \ do { \ - smp_mb__before_clear_bit(); \ + smp_mb__before_atomic(); \ clear_bit(RPC_TASK_QUEUED, &(t)->tk_runstate); \ - smp_mb__after_clear_bit(); \ + smp_mb__after_atomic(); \ } while (0) #define RPC_IS_ACTIVATED(t) test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 3e5efb2b236e21..3876f0f1dfd381 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -379,9 +379,9 @@ static inline int xprt_test_and_clear_connected(struct rpc_xprt *xprt) static inline void xprt_clear_connecting(struct rpc_xprt *xprt) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(XPRT_CONNECTING, &xprt->state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } static inline int xprt_connecting(struct rpc_xprt *xprt) @@ -411,9 +411,9 @@ static inline void xprt_clear_bound(struct rpc_xprt *xprt) static inline void xprt_clear_binding(struct rpc_xprt *xprt) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(XPRT_BINDING, &xprt->state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } static inline int xprt_test_and_set_binding(struct rpc_xprt *xprt) diff --git a/include/linux/suspend.h b/include/linux/suspend.h index f73cabf59012f1..38bbf95109daba 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -320,6 +320,8 @@ extern unsigned long get_safe_page(gfp_t gfp_mask); extern void hibernation_set_ops(const struct platform_hibernation_ops *ops); extern int hibernate(void); extern bool system_entering_hibernation(void); +asmlinkage int swsusp_save(void); +extern struct pbe *restore_pblist; #else /* CONFIG_HIBERNATION */ static inline void register_nosave_region(unsigned long b, unsigned long e) {} static inline void register_nosave_region_late(unsigned long b, unsigned long e) {} diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 239946868142ce..4e37c71ecd746c 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -230,6 +230,7 @@ struct tcp_sock { u32 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */ u32 snd_cwnd_used; u32 snd_cwnd_stamp; + u32 lsnd_pending; /* packets inflight or unsent since last xmit */ u32 prior_cwnd; /* Congestion window at start of Recovery. */ u32 prr_delivered; /* Number of newly delivered packets to * receiver in Recovery. */ diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 1807bb19481697..ff307b548ed3c9 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -102,20 +102,6 @@ static inline int test_ti_thread_flag(struct thread_info *ti, int flag) #define test_thread_flag(flag) \ test_ti_thread_flag(current_thread_info(), flag) -static inline __deprecated void set_need_resched(void) -{ - /* - * Use of this function in deprecated. - * - * As of this writing there are only a few users in the DRM tree left - * all of which are wrong and can be removed without causing too much - * grief. - * - * The DRM people are aware and are working on removing the last few - * instances. - */ -} - #define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED) #if defined TIF_RESTORE_SIGMASK && !defined HAVE_SET_RESTORE_SIGMASK diff --git a/include/linux/topology.h b/include/linux/topology.h index 53261e285889f5..dda6ee521e74e3 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -67,121 +67,6 @@ int arch_update_cpu_topology(void); #define PENALTY_FOR_NODE_WITH_CPUS (1) #endif -/* - * Below are the 3 major initializers used in building sched_domains: - * SD_SIBLING_INIT, for SMT domains - * SD_CPU_INIT, for SMP domains - * - * Any architecture that cares to do any tuning to these values should do so - * by defining their own arch-specific initializer in include/asm/topology.h. - * A definition there will automagically override these default initializers - * and allow arch-specific performance tuning of sched_domains. - * (Only non-zero and non-null fields need be specified.) - */ - -#ifdef CONFIG_SCHED_SMT -/* MCD - Do we really need this? It is always on if CONFIG_SCHED_SMT is, - * so can't we drop this in favor of CONFIG_SCHED_SMT? - */ -#define ARCH_HAS_SCHED_WAKE_IDLE -/* Common values for SMT siblings */ -#ifndef SD_SIBLING_INIT -#define SD_SIBLING_INIT (struct sched_domain) { \ - .min_interval = 1, \ - .max_interval = 2, \ - .busy_factor = 64, \ - .imbalance_pct = 110, \ - \ - .flags = 1*SD_LOAD_BALANCE \ - | 1*SD_BALANCE_NEWIDLE \ - | 1*SD_BALANCE_EXEC \ - | 1*SD_BALANCE_FORK \ - | 0*SD_BALANCE_WAKE \ - | 1*SD_WAKE_AFFINE \ - | 1*SD_SHARE_CPUPOWER \ - | 1*SD_SHARE_PKG_RESOURCES \ - | 0*SD_SERIALIZE \ - | 0*SD_PREFER_SIBLING \ - | arch_sd_sibling_asym_packing() \ - , \ - .last_balance = jiffies, \ - .balance_interval = 1, \ - .smt_gain = 1178, /* 15% */ \ - .max_newidle_lb_cost = 0, \ - .next_decay_max_lb_cost = jiffies, \ -} -#endif -#endif /* CONFIG_SCHED_SMT */ - -#ifdef CONFIG_SCHED_MC -/* Common values for MC siblings. for now mostly derived from SD_CPU_INIT */ -#ifndef SD_MC_INIT -#define SD_MC_INIT (struct sched_domain) { \ - .min_interval = 1, \ - .max_interval = 4, \ - .busy_factor = 64, \ - .imbalance_pct = 125, \ - .cache_nice_tries = 1, \ - .busy_idx = 2, \ - .wake_idx = 0, \ - .forkexec_idx = 0, \ - \ - .flags = 1*SD_LOAD_BALANCE \ - | 1*SD_BALANCE_NEWIDLE \ - | 1*SD_BALANCE_EXEC \ - | 1*SD_BALANCE_FORK \ - | 0*SD_BALANCE_WAKE \ - | 1*SD_WAKE_AFFINE \ - | 0*SD_SHARE_CPUPOWER \ - | 1*SD_SHARE_PKG_RESOURCES \ - | 0*SD_SERIALIZE \ - , \ - .last_balance = jiffies, \ - .balance_interval = 1, \ - .max_newidle_lb_cost = 0, \ - .next_decay_max_lb_cost = jiffies, \ -} -#endif -#endif /* CONFIG_SCHED_MC */ - -/* Common values for CPUs */ -#ifndef SD_CPU_INIT -#define SD_CPU_INIT (struct sched_domain) { \ - .min_interval = 1, \ - .max_interval = 4, \ - .busy_factor = 64, \ - .imbalance_pct = 125, \ - .cache_nice_tries = 1, \ - .busy_idx = 2, \ - .idle_idx = 1, \ - .newidle_idx = 0, \ - .wake_idx = 0, \ - .forkexec_idx = 0, \ - \ - .flags = 1*SD_LOAD_BALANCE \ - | 1*SD_BALANCE_NEWIDLE \ - | 1*SD_BALANCE_EXEC \ - | 1*SD_BALANCE_FORK \ - | 0*SD_BALANCE_WAKE \ - | 1*SD_WAKE_AFFINE \ - | 0*SD_SHARE_CPUPOWER \ - | 0*SD_SHARE_PKG_RESOURCES \ - | 0*SD_SERIALIZE \ - | 1*SD_PREFER_SIBLING \ - , \ - .last_balance = jiffies, \ - .balance_interval = 1, \ - .max_newidle_lb_cost = 0, \ - .next_decay_max_lb_cost = jiffies, \ -} -#endif - -#ifdef CONFIG_SCHED_BOOK -#ifndef SD_BOOK_INIT -#error Please define an appropriate SD_BOOK_INIT in include/asm/topology.h!!! -#endif -#endif /* CONFIG_SCHED_BOOK */ - #ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID DECLARE_PER_CPU(int, numa_node); @@ -296,4 +181,17 @@ static inline int cpu_to_mem(int cpu) #define topology_core_cpumask(cpu) cpumask_of(cpu) #endif +#ifdef CONFIG_SCHED_SMT +static inline const struct cpumask *cpu_smt_mask(int cpu) +{ + return topology_thread_cpumask(cpu); +} +#endif + +static inline const struct cpumask *cpu_cpu_mask(int cpu) +{ + return cpumask_of_node(cpu_to_node(cpu)); +} + + #endif /* _LINUX_TOPOLOGY_H */ diff --git a/include/linux/torture.h b/include/linux/torture.h index b2e2b468e511d4..5ca58fcbaf1b3b 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -49,12 +49,6 @@ #define VERBOSE_TOROUT_ERRSTRING(s) \ do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! %s\n", torture_type, s); } while (0) -/* Definitions for a non-string torture-test module parameter. */ -#define torture_parm(type, name, init, msg) \ - static type name = init; \ - module_param(name, type, 0444); \ - MODULE_PARM_DESC(name, msg); - /* Definitions for online/offline exerciser. */ int torture_onoff_init(long ooholdoff, long oointerval); char *torture_onoff_stats(char *page); @@ -81,7 +75,7 @@ void stutter_wait(const char *title); int torture_stutter_init(int s); /* Initialization and cleanup. */ -void torture_init_begin(char *ttype, bool v, int *runnable); +bool torture_init_begin(char *ttype, bool v, int *runnable); void torture_init_end(void); bool torture_cleanup(void); bool torture_must_stop(void); diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h index 1e98b553042598..6f8ab7da27c43c 100644 --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h @@ -191,7 +191,7 @@ static inline void tracehook_notify_resume(struct pt_regs *regs) * pairs with task_work_add()->set_notify_resume() after * hlist_add_head(task->task_works); */ - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); if (unlikely(current->task_works)) task_work_run(); } diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index add26da2faeb2a..00c9d688d7b718 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -92,7 +92,10 @@ * This function is called by the low-level tty driver to signal * that line discpline should try to send more characters to the * low-level driver for transmission. If the line discpline does - * not have any more data to send, it can just return. + * not have any more data to send, it can just return. If the line + * discipline does have some data to send, please arise a tasklet + * or workqueue to do the real data transfer. Do not send data in + * this hook, it may leads to a deadlock. * * int (*hangup)(struct tty_struct *) * diff --git a/include/linux/uio.h b/include/linux/uio.h index 199bcc34241ba0..e2231e47cec131 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -19,11 +19,21 @@ struct kvec { size_t iov_len; }; +enum { + ITER_IOVEC = 0, + ITER_KVEC = 2, + ITER_BVEC = 4, +}; + struct iov_iter { - const struct iovec *iov; - unsigned long nr_segs; + int type; size_t iov_offset; size_t count; + union { + const struct iovec *iov; + const struct bio_vec *bvec; + }; + unsigned long nr_segs; }; /* @@ -53,6 +63,7 @@ static inline struct iovec iov_iter_iovec(const struct iov_iter *iter) } #define iov_for_each(iov, iter, start) \ + if (!((start).type & ITER_BVEC)) \ for (iter = (start); \ (iter).count && \ ((iov = iov_iter_iovec(&(iter))), 1); \ @@ -62,32 +73,44 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to); size_t iov_iter_copy_from_user_atomic(struct page *page, struct iov_iter *i, unsigned long offset, size_t bytes); -size_t iov_iter_copy_from_user(struct page *page, - struct iov_iter *i, unsigned long offset, size_t bytes); void iov_iter_advance(struct iov_iter *i, size_t bytes); int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes); size_t iov_iter_single_seg_count(const struct iov_iter *i); size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, struct iov_iter *i); +size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, + struct iov_iter *i); +unsigned long iov_iter_alignment(const struct iov_iter *i); +void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov, + unsigned long nr_segs, size_t count); +ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages, + size_t maxsize, size_t *start); +ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages, + size_t maxsize, size_t *start); +int iov_iter_npages(const struct iov_iter *i, int maxpages); -static inline void iov_iter_init(struct iov_iter *i, - const struct iovec *iov, unsigned long nr_segs, - size_t count, size_t written) +static inline size_t iov_iter_count(struct iov_iter *i) { - i->iov = iov; - i->nr_segs = nr_segs; - i->iov_offset = 0; - i->count = count + written; + return i->count; +} - iov_iter_advance(i, written); +static inline void iov_iter_truncate(struct iov_iter *i, size_t count) +{ + if (i->count > count) + i->count = count; } -static inline size_t iov_iter_count(struct iov_iter *i) +/* + * reexpand a previously truncated iterator; count must be no more than how much + * we had shrunk it. + */ +static inline void iov_iter_reexpand(struct iov_iter *i, size_t count) { - return i->count; + i->count = count; } int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len); + #endif diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 32754835a39ba8..b0a39243295a32 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -22,21 +22,6 @@ #include #include -/** - * Supported USB modes - * - * USB_PERIPHERAL Only peripheral mode is supported. - * USB_HOST Only host mode is supported. - * USB_OTG OTG mode is supported. - * - */ -enum usb_mode_type { - USB_NONE = 0, - USB_PERIPHERAL, - USB_HOST, - USB_OTG, -}; - /** * OTG control * @@ -115,27 +100,23 @@ enum usb_chg_type { /** * struct msm_otg_platform_data - platform device data * for msm_otg driver. - * @phy_init_seq: PHY configuration sequence. val, reg pairs - * terminated by -1. + * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as + * "do not overwrite default vaule at this address". + * @phy_init_sz: PHY configuration sequence size. * @vbus_power: VBUS power on/off routine. * @power_budget: VBUS power budget in mA (0 will be treated as 500mA). * @mode: Supported mode (OTG/peripheral/host). * @otg_control: OTG switch controlled by user/Id pin - * @default_mode: Default operational mode. Applicable only if - * OTG switch is controller by user. - * @pclk_src_name: pclk is derived from ebi1_usb_clk in case of 7x27 and 8k - * dfab_usb_hs_clk in case of 8660 and 8960. */ struct msm_otg_platform_data { int *phy_init_seq; + int phy_init_sz; void (*vbus_power)(bool on); unsigned power_budget; - enum usb_mode_type mode; + enum usb_dr_mode mode; enum otg_control_type otg_control; - enum usb_mode_type default_mode; enum msm_usb_phy_type phy_type; void (*setup_gpio)(enum usb_otg_state state); - char *pclk_src_name; int (*link_clk_reset)(struct clk *link_clk, bool assert); int (*phy_clk_reset)(struct clk *phy_clk); }; @@ -147,7 +128,6 @@ struct msm_otg_platform_data { * @irq: IRQ number assigned for HSUSB controller. * @clk: clock struct of usb_hs_clk. * @pclk: clock struct of usb_hs_pclk. - * @pclk_src: pclk source for voting. * @phy_reset_clk: clock struct of usb_phy_clk. * @core_clk: clock struct of usb_hs_core_clk. * @regs: ioremapped register base address. @@ -168,7 +148,6 @@ struct msm_otg { int irq; struct clk *clk; struct clk *pclk; - struct clk *pclk_src; struct clk *phy_reset_clk; struct clk *core_clk; void __iomem *regs; @@ -179,10 +158,18 @@ struct msm_otg { atomic_t in_lpm; int async_int; unsigned cur_power; + int phy_number; struct delayed_work chg_work; enum usb_chg_state chg_state; enum usb_chg_type chg_type; u8 dcd_retries; + struct regulator *v3p3; + struct regulator *v1p8; + struct regulator *vddcx; + + struct reset_control *phy_rst; + struct reset_control *link_rst; + int vdd_levels[3]; }; #endif diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h index 6e97a2d3d39fbb..a29f6030afb167 100644 --- a/include/linux/usb/msm_hsusb_hw.h +++ b/include/linux/usb/msm_hsusb_hw.h @@ -16,6 +16,9 @@ #ifndef __LINUX_USB_GADGET_MSM72K_UDC_H__ #define __LINUX_USB_GADGET_MSM72K_UDC_H__ +/* USB phy selector - in TCSR address range */ +#define USB2_PHY_SEL 0xfd4ab000 + #define USB_AHBBURST (MSM_USB_BASE + 0x0090) #define USB_AHBMODE (MSM_USB_BASE + 0x0098) #define USB_CAPLENGTH (MSM_USB_BASE + 0x0100) /* 8 bit */ @@ -25,13 +28,15 @@ #define USB_OTGSC (MSM_USB_BASE + 0x01A4) #define USB_USBMODE (MSM_USB_BASE + 0x01A8) #define USB_PHY_CTRL (MSM_USB_BASE + 0x0240) +#define USB_PHY_CTRL2 (MSM_USB_BASE + 0x0278) #define USBCMD_RESET 2 #define USB_USBINTR (MSM_USB_BASE + 0x0148) #define PORTSC_PHCD (1 << 23) /* phy suspend mode */ -#define PORTSC_PTS_MASK (3 << 30) -#define PORTSC_PTS_ULPI (3 << 30) +#define PORTSC_PTS_MASK (3 << 30) +#define PORTSC_PTS_ULPI (2 << 30) +#define PORTSC_PTS_SERIAL (3 << 30) #define USB_ULPI_VIEWPORT (MSM_USB_BASE + 0x0170) #define ULPI_RUN (1 << 30) @@ -41,9 +46,14 @@ #define ULPI_DATA(n) ((n) & 255) #define ULPI_DATA_READ(n) (((n) >> 8) & 255) +/* synopsys 28nm phy registers */ +#define ULPI_PWR_CLK_MNG_REG 0x88 +#define OTG_COMP_DISABLE BIT(0) + #define ASYNC_INTR_CTRL (1 << 29) /* Enable async interrupt */ #define ULPI_STP_CTRL (1 << 30) /* Block communication with PHY */ #define PHY_RETEN (1 << 1) /* PHY retention enable/disable */ +#define PHY_POR_ASSERT (1 << 0) /* USB2 28nm PHY POR ASSERT */ /* OTG definitions */ #define OTGSC_INTSTS_MASK (0x7f << 16) diff --git a/include/linux/usb/usb_phy_gen_xceiv.h b/include/linux/usb/usb_phy_generic.h similarity index 53% rename from include/linux/usb/usb_phy_gen_xceiv.h rename to include/linux/usb/usb_phy_generic.h index cc8d818a83be40..68adae83affcd0 100644 --- a/include/linux/usb/usb_phy_gen_xceiv.h +++ b/include/linux/usb/usb_phy_generic.h @@ -3,7 +3,7 @@ #include -struct usb_phy_gen_xceiv_platform_data { +struct usb_phy_generic_platform_data { enum usb_phy_type type; unsigned long clk_rate; @@ -13,16 +13,17 @@ struct usb_phy_gen_xceiv_platform_data { int gpio_reset; }; -#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_NOP_USB_XCEIV) /* sometimes transceivers are accessed only through e.g. ULPI */ -extern void usb_nop_xceiv_register(void); -extern void usb_nop_xceiv_unregister(void); +extern struct platform_device *usb_phy_generic_register(void); +extern void usb_phy_generic_unregister(struct platform_device *); #else -static inline void usb_nop_xceiv_register(void) +static inline struct platform_device *usb_phy_generic_register(void) { + return NULL; } -static inline void usb_nop_xceiv_unregister(void) +static inline void usb_phy_generic_unregister(struct platform_device *pdev) { } #endif diff --git a/include/linux/virtio.h b/include/linux/virtio.h index e4abb84199bea7..b46671e28de29a 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -106,6 +106,8 @@ static inline struct virtio_device *dev_to_virtio(struct device *_dev) int register_virtio_device(struct virtio_device *dev); void unregister_virtio_device(struct virtio_device *dev); +void virtio_break_device(struct virtio_device *dev); + /** * virtio_driver - operations for a virtio I/O driver * @driver: underlying device driver (populate name and owner). diff --git a/include/linux/wait.h b/include/linux/wait.h index bd68819f081592..5be161e84bc3c2 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -818,8 +818,8 @@ do { \ /* * Waitqueues which are removed from the waitqueue_head at wakeup time */ -void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state); -void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state); +bool prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state); +bool prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state); long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state); void finish_wait(wait_queue_head_t *q, wait_queue_t *wait); void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait, unsigned int mode, void *key); diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h index f7d372b7d4ff67..79b530fb2c4dd4 100644 --- a/include/net/6lowpan.h +++ b/include/net/6lowpan.h @@ -54,6 +54,7 @@ #define __6LOWPAN_H__ #include +#include #define UIP_802154_SHORTADDR_LEN 2 /* compressed ipv6 address length */ #define UIP_IPH_LEN 40 /* ipv6 fixed header size */ diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 933a9f22a05ff6..f679877bb6017d 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -306,11 +306,6 @@ static inline void addrconf_addr_solict_mult(const struct in6_addr *addr, htonl(0xFF000000) | addr->s6_addr32[3]); } -static inline bool ipv6_addr_is_multicast(const struct in6_addr *addr) -{ - return (addr->s6_addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000); -} - static inline bool ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr) { #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index be150cf8cd4322..ad2ecc92380ddf 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -367,6 +367,7 @@ enum { #define HCI_ERROR_REMOTE_POWER_OFF 0x15 #define HCI_ERROR_LOCAL_HOST_TERM 0x16 #define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18 +#define HCI_ERROR_ADVERTISING_TIMEOUT 0x3c /* Flow control modes */ #define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00 @@ -1063,6 +1064,16 @@ struct hci_rp_read_page_scan_type { #define PAGE_SCAN_TYPE_STANDARD 0x00 #define PAGE_SCAN_TYPE_INTERLACED 0x01 +#define HCI_OP_READ_RSSI 0x1405 +struct hci_cp_read_rssi { + __le16 handle; +} __packed; +struct hci_rp_read_rssi { + __u8 status; + __le16 handle; + __s8 rssi; +} __packed; + #define HCI_OP_READ_LOCAL_AMP_INFO 0x1409 struct hci_rp_read_local_amp_info { __u8 status; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5f8bc05694ac66..0318d5263837cc 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -68,6 +68,11 @@ struct discovery_state { struct list_head unknown; /* Name state not known */ struct list_head resolve; /* Name needs to be resolved */ __u32 timestamp; + bdaddr_t last_adv_addr; + u8 last_adv_addr_type; + s8 last_adv_rssi; + u8 last_adv_data[HCI_MAX_AD_LENGTH]; + u8 last_adv_data_len; }; struct hci_conn_hash { @@ -194,6 +199,7 @@ struct hci_dev { __u16 le_scan_window; __u16 le_conn_min_interval; __u16 le_conn_max_interval; + __u16 discov_interleaved_timeout; __u8 ssp_debug_mode; __u16 devid_source; @@ -368,6 +374,7 @@ struct hci_conn { __u16 setting; __u16 le_conn_min_interval; __u16 le_conn_max_interval; + __s8 rssi; unsigned long flags; __u8 remote_cap; @@ -1204,8 +1211,8 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event); */ #define DISCOV_LE_SCAN_WIN 0x12 #define DISCOV_LE_SCAN_INT 0x12 -#define DISCOV_LE_TIMEOUT msecs_to_jiffies(10240) -#define DISCOV_INTERLEAVED_TIMEOUT msecs_to_jiffies(5120) +#define DISCOV_LE_TIMEOUT 10240 /* msec */ +#define DISCOV_INTERLEAVED_TIMEOUT 5120 /* msec */ #define DISCOV_INTERLEAVED_INQUIRY_LEN 0x04 #define DISCOV_BREDR_INQUIRY_LEN 0x08 @@ -1265,7 +1272,8 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, u8 *randomizer256, u8 status); void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, - u8 ssp, u8 *eir, u16 eir_len); + u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp, + u8 scan_rsp_len); void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, s8 rssi, u8 *name, u8 name_len); void mgmt_discovering(struct hci_dev *hdev, u8 discovering); diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index 2611cc389d7d65..578b83127af185 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -173,7 +173,7 @@ struct rfcomm_dlc { struct sk_buff_head tx_queue; struct timer_list timer; - spinlock_t lock; + struct mutex lock; unsigned long state; unsigned long flags; atomic_t refcnt; @@ -244,8 +244,8 @@ int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); void rfcomm_dlc_accept(struct rfcomm_dlc *d); struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel); -#define rfcomm_dlc_lock(d) spin_lock(&d->lock) -#define rfcomm_dlc_unlock(d) spin_unlock(&d->lock) +#define rfcomm_dlc_lock(d) mutex_lock(&d->lock) +#define rfcomm_dlc_unlock(d) mutex_unlock(&d->lock) static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d) { diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f3539a15c41103..f2c3186555192c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -109,6 +109,13 @@ enum ieee80211_band { * channel as the control or any of the secondary channels. * This may be due to the driver or due to regulatory bandwidth * restrictions. + * @IEEE80211_CHAN_INDOOR_ONLY: see %NL80211_FREQUENCY_ATTR_INDOOR_ONLY + * @IEEE80211_CHAN_GO_CONCURRENT: see %NL80211_FREQUENCY_ATTR_GO_CONCURRENT + * @IEEE80211_CHAN_NO_20MHZ: 20 MHz bandwidth is not permitted + * on this channel. + * @IEEE80211_CHAN_NO_10MHZ: 10 MHz bandwidth is not permitted + * on this channel. + * */ enum ieee80211_channel_flags { IEEE80211_CHAN_DISABLED = 1<<0, @@ -120,6 +127,10 @@ enum ieee80211_channel_flags { IEEE80211_CHAN_NO_OFDM = 1<<6, IEEE80211_CHAN_NO_80MHZ = 1<<7, IEEE80211_CHAN_NO_160MHZ = 1<<8, + IEEE80211_CHAN_INDOOR_ONLY = 1<<9, + IEEE80211_CHAN_GO_CONCURRENT = 1<<10, + IEEE80211_CHAN_NO_20MHZ = 1<<11, + IEEE80211_CHAN_NO_10MHZ = 1<<12, }; #define IEEE80211_CHAN_NO_HT40 \ @@ -441,10 +452,13 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, * cfg80211_chandef_dfs_required - checks if radar detection is required * @wiphy: the wiphy to validate against * @chandef: the channel definition to check - * Return: 1 if radar detection is required, 0 if it is not, < 0 on error + * @iftype: the interface type as specified in &enum nl80211_iftype + * Returns: + * 1 if radar detection is required, 0 if it is not, < 0 on error */ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, - const struct cfg80211_chan_def *chandef); + const struct cfg80211_chan_def *chandef, + enum nl80211_iftype); /** * ieee80211_chandef_rate_flags - returns rate flags for a channel @@ -654,7 +668,6 @@ struct cfg80211_acl_data { * @p2p_opp_ps: P2P opportunistic PS * @acl: ACL configuration used by the drivers which has support for * MAC address based access control - * @radar_required: set if radar detection is required */ struct cfg80211_ap_settings { struct cfg80211_chan_def chandef; @@ -672,7 +685,6 @@ struct cfg80211_ap_settings { u8 p2p_ctwindow; bool p2p_opp_ps; const struct cfg80211_acl_data *acl; - bool radar_required; }; /** @@ -2278,6 +2290,10 @@ struct cfg80211_qos_map { * @channel_switch: initiate channel-switch procedure (with CSA) * * @set_qos_map: Set QoS mapping information to the driver + * + * @set_ap_chanwidth: Set the AP (including P2P GO) mode channel width for the + * given interface This is used e.g. for dynamic HT 20/40 MHz channel width + * changes during the lifetime of the BSS. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -2521,9 +2537,13 @@ struct cfg80211_ops { int (*channel_switch)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_csa_settings *params); + int (*set_qos_map)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_qos_map *qos_map); + + int (*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_chan_def *chandef); }; /* @@ -3194,6 +3214,7 @@ struct cfg80211_cached_keys; * @ibss_dfs_possible: (private) IBSS may change to a DFS channel * @event_list: (private) list for internal event processing * @event_lock: (private) lock for event list + * @owner_nlportid: (private) owner socket port ID */ struct wireless_dev { struct wiphy *wiphy; @@ -3241,6 +3262,8 @@ struct wireless_dev { unsigned long cac_start_time; unsigned int cac_time_ms; + u32 owner_nlportid; + #ifdef CONFIG_CFG80211_WEXT /* wext data */ struct { @@ -3600,7 +3623,7 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2); * default channel settings will be disregarded. If no rule is found for a * channel on the regulatory domain the channel will be disabled. * Drivers using this for a wiphy should also set the wiphy flag - * WIPHY_FLAG_CUSTOM_REGULATORY or cfg80211 will set it for the wiphy + * REGULATORY_CUSTOM_REG or cfg80211 will set it for the wiphy * that called this helper. */ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, @@ -3668,6 +3691,18 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy); */ void cfg80211_sched_scan_stopped(struct wiphy *wiphy); +/** + * cfg80211_sched_scan_stopped_rtnl - notify that the scheduled scan has stopped + * + * @wiphy: the wiphy on which the scheduled scan stopped + * + * The driver can call this function to inform cfg80211 that the + * scheduled scan had to be stopped, for whatever reason. The driver + * is then called back via the sched_scan_stop operation when done. + * This function should be called with rtnl locked. + */ +void cfg80211_sched_scan_stopped_rtnl(struct wiphy *wiphy); + /** * cfg80211_inform_bss_width_frame - inform cfg80211 of a received BSS frame * @@ -4531,12 +4566,14 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, * cfg80211_reg_can_beacon - check if beaconing is allowed * @wiphy: the wiphy * @chandef: the channel definition + * @iftype: interface type * * Return: %true if there is no secondary channel or the secondary channel(s) * can be used for beaconing (i.e. is not a radar channel etc.) */ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef); + struct cfg80211_chan_def *chandef, + enum nl80211_iftype iftype); /* * cfg80211_ch_switch_notify - update wdev channel and notify userspace @@ -4682,6 +4719,55 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp); */ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy); +/** + * cfg80211_check_combinations - check interface combinations + * + * @wiphy: the wiphy + * @num_different_channels: the number of different channels we want + * to use for verification + * @radar_detect: a bitmap where each bit corresponds to a channel + * width where radar detection is needed, as in the definition of + * &struct ieee80211_iface_combination.@radar_detect_widths + * @iftype_num: array with the numbers of interfaces of each interface + * type. The index is the interface type as specified in &enum + * nl80211_iftype. + * + * This function can be called by the driver to check whether a + * combination of interfaces and their types are allowed according to + * the interface combinations. + */ +int cfg80211_check_combinations(struct wiphy *wiphy, + const int num_different_channels, + const u8 radar_detect, + const int iftype_num[NUM_NL80211_IFTYPES]); + +/** + * cfg80211_iter_combinations - iterate over matching combinations + * + * @wiphy: the wiphy + * @num_different_channels: the number of different channels we want + * to use for verification + * @radar_detect: a bitmap where each bit corresponds to a channel + * width where radar detection is needed, as in the definition of + * &struct ieee80211_iface_combination.@radar_detect_widths + * @iftype_num: array with the numbers of interfaces of each interface + * type. The index is the interface type as specified in &enum + * nl80211_iftype. + * @iter: function to call for each matching combination + * @data: pointer to pass to iter function + * + * This function can be called by the driver to check what possible + * combinations it fits in at a given moment, e.g. for channel switching + * purposes. + */ +int cfg80211_iter_combinations(struct wiphy *wiphy, + const int num_different_channels, + const u8 radar_detect, + const int iftype_num[NUM_NL80211_IFTYPES], + void (*iter)(const struct ieee80211_iface_combination *c, + void *data), + void *data); + /* Logging, debugging and troubleshooting/diagnostic helpers. */ /* wiphy_printk helpers, similar to dev_printk */ diff --git a/include/net/checksum.h b/include/net/checksum.h index a28f4e0f625193..87cb1903640d63 100644 --- a/include/net/checksum.h +++ b/include/net/checksum.h @@ -57,12 +57,14 @@ static __inline__ __wsum csum_and_copy_to_user } #endif +#ifndef HAVE_ARCH_CSUM_ADD static inline __wsum csum_add(__wsum csum, __wsum addend) { u32 res = (__force u32)csum; res += (__force u32)addend; return (__force __wsum)(res + (res < (__force u32)addend)); } +#endif static inline __wsum csum_sub(__wsum csum, __wsum addend) { diff --git a/include/net/dsa.h b/include/net/dsa.h index 7828ebf99ee132..6efce384451e56 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -181,6 +181,11 @@ struct dsa_switch_driver { void register_switch_driver(struct dsa_switch_driver *type); void unregister_switch_driver(struct dsa_switch_driver *type); +static inline void *ds_to_priv(struct dsa_switch *ds) +{ + return (void *)(ds + 1); +} + /* * The original DSA tag format and some other tag formats have no * ethertype, which means that we need to add a little hack to the diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h index 3bd22795c3e259..84b20835b736c5 100644 --- a/include/net/inet_ecn.h +++ b/include/net/inet_ecn.h @@ -150,7 +150,7 @@ static inline int INET_ECN_set_ce(struct sk_buff *skb) } /* - * RFC 6080 4.2 + * RFC 6040 4.2 * To decapsulate the inner header at the tunnel egress, a compliant * tunnel egress MUST set the outgoing ECN field to the codepoint at the * intersection of the appropriate arriving inner header (row) and outer diff --git a/include/net/ip.h b/include/net/ip.h index 3ec2b0fb9d8395..16146b667ddb08 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -196,27 +196,15 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr, #define NET_ADD_STATS_BH(net, field, adnd) SNMP_ADD_STATS_BH((net)->mib.net_statistics, field, adnd) #define NET_ADD_STATS_USER(net, field, adnd) SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd) -unsigned long snmp_fold_field(void __percpu *mib[], int offt); +unsigned long snmp_fold_field(void __percpu *mib, int offt); #if BITS_PER_LONG==32 -u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t sync_off); +u64 snmp_fold_field64(void __percpu *mib, int offt, size_t sync_off); #else -static inline u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_off) +static inline u64 snmp_fold_field64(void __percpu *mib, int offt, size_t syncp_off) { return snmp_fold_field(mib, offt); } #endif -int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align); - -static inline void snmp_mib_free(void __percpu *ptr[SNMP_ARRAY_SZ]) -{ - int i; - - BUG_ON(ptr == NULL); - for (i = 0; i < SNMP_ARRAY_SZ; i++) { - free_percpu(ptr[i]); - ptr[i] = NULL; - } -} void inet_get_local_port_range(struct net *net, int *low, int *high); @@ -342,6 +330,12 @@ static inline void ip_select_ident_more(struct sk_buff *skb, struct dst_entry *d __ip_select_ident(iph, dst, more); } +static inline __wsum inet_compute_pseudo(struct sk_buff *skb, int proto) +{ + return csum_tcpudp_nofold(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, + skb->len, proto, 0); +} + /* * Map a multicast IP onto multicast MAC for type ethernet. */ diff --git a/include/net/ip6_checksum.h b/include/net/ip6_checksum.h index 9e3c540c1b110c..8ac5c21f84563f 100644 --- a/include/net/ip6_checksum.h +++ b/include/net/ip6_checksum.h @@ -41,6 +41,13 @@ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, __wsum csum); #endif +static inline __wsum ip6_compute_pseudo(struct sk_buff *skb, int proto) +{ + return ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + skb->len, proto, 0)); +} + static __inline__ __sum16 tcp_v6_check(int len, const struct in6_addr *saddr, const struct in6_addr *daddr, diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 5679d927562be7..624a8a54806d4c 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -1204,7 +1204,7 @@ static inline bool __ip_vs_conn_get(struct ip_vs_conn *cp) /* put back the conn without restarting its timer */ static inline void __ip_vs_conn_put(struct ip_vs_conn *cp) { - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_dec(&cp->refcnt); } void ip_vs_conn_put(struct ip_vs_conn *cp); @@ -1408,7 +1408,7 @@ static inline void ip_vs_dest_hold(struct ip_vs_dest *dest) static inline void ip_vs_dest_put(struct ip_vs_dest *dest) { - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_dec(&dest->refcnt); } diff --git a/include/net/ipv6.h b/include/net/ipv6.h index d640925bc4543b..5b40ad297b8ce2 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -583,6 +583,11 @@ static inline bool ipv6_addr_orchid(const struct in6_addr *a) return (a->s6_addr32[0] & htonl(0xfffffff0)) == htonl(0x20010010); } +static inline bool ipv6_addr_is_multicast(const struct in6_addr *addr) +{ + return (addr->s6_addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000); +} + static inline void ipv6_addr_set_v4mapped(const __be32 addr, struct in6_addr *v4mapped) { @@ -664,6 +669,20 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt); int ip6_dst_hoplimit(struct dst_entry *dst); +static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6, + struct dst_entry *dst) +{ + int hlimit; + + if (ipv6_addr_is_multicast(&fl6->daddr)) + hlimit = np->mcast_hops; + else + hlimit = np->hop_limit; + if (hlimit < 0) + hlimit = ip6_dst_hoplimit(dst); + return hlimit; +} + /* * Header manipulation */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8248e3909fdf7d..451c1bf00df933 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1202,14 +1202,18 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev); * fall back to software crypto. Note that this flag deals only with * RX, if your crypto engine can't deal with TX you can also set the * %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW. + * @IEEE80211_KEY_FLAG_GENERATE_IV_MGMT: This flag should be set by the + * driver for a CCMP key to indicate that is requires IV generation + * only for managment frames (MFP). */ enum ieee80211_key_flags { - IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1, - IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2, - IEEE80211_KEY_FLAG_PAIRWISE = 1<<3, - IEEE80211_KEY_FLAG_SW_MGMT_TX = 1<<4, - IEEE80211_KEY_FLAG_PUT_IV_SPACE = 1<<5, - IEEE80211_KEY_FLAG_RX_MGMT = 1<<6, + IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0), + IEEE80211_KEY_FLAG_GENERATE_IV = BIT(1), + IEEE80211_KEY_FLAG_GENERATE_MMIC = BIT(2), + IEEE80211_KEY_FLAG_PAIRWISE = BIT(3), + IEEE80211_KEY_FLAG_SW_MGMT_TX = BIT(4), + IEEE80211_KEY_FLAG_PUT_IV_SPACE = BIT(5), + IEEE80211_KEY_FLAG_RX_MGMT = BIT(6), }; /** @@ -1555,6 +1559,12 @@ struct ieee80211_tx_control { * for a single active channel while using channel contexts. When support * is not enabled the default action is to disconnect when getting the * CSA frame. + * + * @IEEE80211_HW_CHANGE_RUNNING_CHANCTX: The hardware can change a + * channel context on-the-fly. This is needed for channel switch + * on single-channel hardware. It can also be used as an + * optimization in certain channel switch cases with + * multi-channel. */ enum ieee80211_hw_flags { IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, @@ -1586,6 +1596,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26, IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27, IEEE80211_HW_CHANCTX_STA_CSA = 1<<28, + IEEE80211_HW_CHANGE_RUNNING_CHANCTX = 1<<29, }; /** @@ -2609,6 +2620,7 @@ enum ieee80211_roc_type { * of queues to flush, which is useful if different virtual interfaces * use different hardware queues; it may also indicate all queues. * If the parameter @drop is set to %true, pending frames may be dropped. + * Note that vif can be NULL. * The callback can sleep. * * @channel_switch: Drivers that need (or want) to offload the channel @@ -2871,7 +2883,8 @@ struct ieee80211_ops { struct netlink_callback *cb, void *data, int len); #endif - void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop); + void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); void (*channel_switch)(struct ieee80211_hw *hw, struct ieee80211_channel_switch *ch_switch); int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); @@ -4576,7 +4589,9 @@ conf_is_ht40(struct ieee80211_conf *conf) static inline bool conf_is_ht(struct ieee80211_conf *conf) { - return conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT; + return (conf->chandef.width != NL80211_CHAN_WIDTH_5) && + (conf->chandef.width != NL80211_CHAN_WIDTH_10) && + (conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT); } static inline enum nl80211_iftype diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 5f9eb260990f65..361d2607719667 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -373,6 +373,14 @@ static inline void rt_genid_bump_ipv6(struct net *net) } #endif +#if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN) +static inline struct netns_ieee802154_lowpan * +net_ieee802154_lowpan(struct net *net) +{ + return &net->ieee802154_lowpan; +} +#endif + /* For callers who don't really care about whether it's IPv4 or IPv6 */ static inline void rt_genid_bump_all(struct net *net) { diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index a2441fb1428f3f..6da46dcf104978 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -136,7 +136,7 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts, int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, struct nlattr *rate_tlv, - struct tcf_exts *exts); + struct tcf_exts *exts, bool ovr); void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts); void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, struct tcf_exts *src); diff --git a/include/net/regulatory.h b/include/net/regulatory.h index 75fc1f5a948d68..259992444e80ae 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -131,6 +131,11 @@ struct regulatory_request { * all country IE information processed by the regulatory core. This will * override %REGULATORY_COUNTRY_IE_FOLLOW_POWER as all country IEs will * be ignored. + * @REGULATORY_ENABLE_RELAX_NO_IR: for devices that wish to allow the + * NO_IR relaxation, which enables transmissions on channels on which + * otherwise initiating radiation is not allowed. This will enable the + * relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration + * option */ enum ieee80211_regulatory_flags { REGULATORY_CUSTOM_REG = BIT(0), @@ -138,6 +143,7 @@ enum ieee80211_regulatory_flags { REGULATORY_DISABLE_BEACON_HINTS = BIT(2), REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3), REGULATORY_COUNTRY_IE_IGNORE = BIT(4), + REGULATORY_ENABLE_RELAX_NO_IR = BIT(5), }; struct ieee80211_freq_range { diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index d062f81c692f1e..624f9857c83e3d 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -199,7 +199,7 @@ struct tcf_proto_ops { int (*change)(struct net *net, struct sk_buff *, struct tcf_proto*, unsigned long, u32 handle, struct nlattr **, - unsigned long *); + unsigned long *, bool); int (*delete)(struct tcf_proto*, unsigned long); void (*walk)(struct tcf_proto*, struct tcf_walker *arg); diff --git a/include/net/snmp.h b/include/net/snmp.h index 71596261fa997e..f1f27fdbb0d573 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h @@ -116,51 +116,49 @@ struct linux_xfrm_mib { unsigned long mibs[LINUX_MIB_XFRMMAX]; }; -#define SNMP_ARRAY_SZ 1 - #define DEFINE_SNMP_STAT(type, name) \ - __typeof__(type) __percpu *name[SNMP_ARRAY_SZ] + __typeof__(type) __percpu *name #define DEFINE_SNMP_STAT_ATOMIC(type, name) \ __typeof__(type) *name #define DECLARE_SNMP_STAT(type, name) \ - extern __typeof__(type) __percpu *name[SNMP_ARRAY_SZ] + extern __typeof__(type) __percpu *name #define SNMP_INC_STATS_BH(mib, field) \ - __this_cpu_inc(mib[0]->mibs[field]) + __this_cpu_inc(mib->mibs[field]) #define SNMP_INC_STATS_USER(mib, field) \ - this_cpu_inc(mib[0]->mibs[field]) + this_cpu_inc(mib->mibs[field]) #define SNMP_INC_STATS_ATOMIC_LONG(mib, field) \ atomic_long_inc(&mib->mibs[field]) #define SNMP_INC_STATS(mib, field) \ - this_cpu_inc(mib[0]->mibs[field]) + this_cpu_inc(mib->mibs[field]) #define SNMP_DEC_STATS(mib, field) \ - this_cpu_dec(mib[0]->mibs[field]) + this_cpu_dec(mib->mibs[field]) #define SNMP_ADD_STATS_BH(mib, field, addend) \ - __this_cpu_add(mib[0]->mibs[field], addend) + __this_cpu_add(mib->mibs[field], addend) #define SNMP_ADD_STATS_USER(mib, field, addend) \ - this_cpu_add(mib[0]->mibs[field], addend) + this_cpu_add(mib->mibs[field], addend) #define SNMP_ADD_STATS(mib, field, addend) \ - this_cpu_add(mib[0]->mibs[field], addend) + this_cpu_add(mib->mibs[field], addend) /* - * Use "__typeof__(*mib[0]) *ptr" instead of "__typeof__(mib[0]) ptr" + * Use "__typeof__(*mib) *ptr" instead of "__typeof__(mib) ptr" * to make @ptr a non-percpu pointer. */ #define SNMP_UPD_PO_STATS(mib, basefield, addend) \ do { \ - __typeof__(*mib[0]->mibs) *ptr = mib[0]->mibs; \ + __typeof__(*mib->mibs) *ptr = mib->mibs; \ this_cpu_inc(ptr[basefield##PKTS]); \ this_cpu_add(ptr[basefield##OCTETS], addend); \ } while (0) #define SNMP_UPD_PO_STATS_BH(mib, basefield, addend) \ do { \ - __typeof__(*mib[0]->mibs) *ptr = mib[0]->mibs; \ + __typeof__(*mib->mibs) *ptr = mib->mibs; \ __this_cpu_inc(ptr[basefield##PKTS]); \ __this_cpu_add(ptr[basefield##OCTETS], addend); \ } while (0) @@ -170,7 +168,7 @@ struct linux_xfrm_mib { #define SNMP_ADD_STATS64_BH(mib, field, addend) \ do { \ - __typeof__(*mib[0]) *ptr = __this_cpu_ptr((mib)[0]); \ + __typeof__(*mib) *ptr = __this_cpu_ptr(mib); \ u64_stats_update_begin(&ptr->syncp); \ ptr->mibs[field] += addend; \ u64_stats_update_end(&ptr->syncp); \ @@ -191,8 +189,8 @@ struct linux_xfrm_mib { #define SNMP_INC_STATS64(mib, field) SNMP_ADD_STATS64(mib, field, 1) #define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) \ do { \ - __typeof__(*mib[0]) *ptr; \ - ptr = __this_cpu_ptr((mib)[0]); \ + __typeof__(*mib) *ptr; \ + ptr = __this_cpu_ptr(mib); \ u64_stats_update_begin(&ptr->syncp); \ ptr->mibs[basefield##PKTS]++; \ ptr->mibs[basefield##OCTETS] += addend; \ diff --git a/include/net/tcp.h b/include/net/tcp.h index 87d87740818867..3c941845664081 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -558,7 +558,6 @@ void tcp_send_loss_probe(struct sock *sk); bool tcp_schedule_loss_probe(struct sock *sk); /* tcp_input.c */ -void tcp_cwnd_application_limited(struct sock *sk); void tcp_resume_early_retransmit(struct sock *sk); void tcp_rearm_rto(struct sock *sk); void tcp_reset(struct sock *sk); @@ -797,7 +796,7 @@ struct tcp_congestion_ops { /* return slow start threshold (required) */ u32 (*ssthresh)(struct sock *sk); /* do new cwnd calculation (required) */ - void (*cong_avoid)(struct sock *sk, u32 ack, u32 acked, u32 in_flight); + void (*cong_avoid)(struct sock *sk, u32 ack, u32 acked); /* call before changing ca_state (optional) */ void (*set_state)(struct sock *sk, u8 new_state); /* call when cwnd event occurs (optional) */ @@ -829,7 +828,7 @@ void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w); extern struct tcp_congestion_ops tcp_init_congestion_ops; u32 tcp_reno_ssthresh(struct sock *sk); -void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked, u32 in_flight); +void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked); extern struct tcp_congestion_ops tcp_reno; static inline void tcp_set_ca_state(struct sock *sk, const u8 ca_state) @@ -975,7 +974,25 @@ static inline u32 tcp_wnd_end(const struct tcp_sock *tp) { return tp->snd_una + tp->snd_wnd; } -bool tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight); + +/* We follow the spirit of RFC2861 to validate cwnd but implement a more + * flexible approach. The RFC suggests cwnd should not be raised unless + * it was fully used previously. But we allow cwnd to grow as long as the + * application has used half the cwnd. + * Example : + * cwnd is 10 (IW10), but application sends 9 frames. + * We allow cwnd to reach 18 when all frames are ACKed. + * This check is safe because it's as aggressive as slow start which already + * risks 100% overshoot. The advantage is that we discourage application to + * either send more filler packets or data to artificially blow up the cwnd + * usage, and allow application-limited process to probe bw more aggressively. + */ +static inline bool tcp_is_cwnd_limited(const struct sock *sk) +{ + const struct tcp_sock *tp = tcp_sk(sk); + + return tp->snd_cwnd < 2 * tp->lsnd_pending; +} static inline void tcp_check_probe_timer(struct sock *sk) { diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 5deef1ae78c964..7bb4084b1bd0c0 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -33,7 +33,7 @@ void vxlan_sock_release(struct vxlan_sock *vs); int vxlan_xmit_skb(struct vxlan_sock *vs, struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, - __be16 src_port, __be16 dst_port, __be32 vni); + __be16 src_port, __be16 dst_port, __be32 vni, bool xnet); __be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb); diff --git a/include/net/wimax.h b/include/net/wimax.h index 98498e1daa0605..e52ef5357e088b 100644 --- a/include/net/wimax.h +++ b/include/net/wimax.h @@ -483,8 +483,8 @@ void wimax_report_rfkill_sw(struct wimax_dev *, enum wimax_rf_state); * Be sure not to modify skb->data in the middle (ie: don't use * skb_push()/skb_pull()/skb_reserve() on the skb). * - * "pipe_name" is any string, than can be interpreted as the name of - * the pipe or destinatary; the interpretation of it is driver + * "pipe_name" is any string, that can be interpreted as the name of + * the pipe or recipient; the interpretation of it is driver * specific, so the recipient can multiplex it as wished. It can be * NULL, it won't be used - an example is using a "diagnostics" tag to * send diagnostics information that a device-specific diagnostics diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 116e9c7e19cbbe..721e9c3b11bddb 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -691,13 +691,6 @@ struct xfrm_spi_skb_cb { #define XFRM_SPI_SKB_CB(__skb) ((struct xfrm_spi_skb_cb *)&((__skb)->cb[0])) -/* Audit Information */ -struct xfrm_audit { - u32 secid; - kuid_t loginuid; - unsigned int sessionid; -}; - #ifdef CONFIG_AUDITSYSCALL static inline struct audit_buffer *xfrm_audit_start(const char *op) { @@ -713,30 +706,24 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op) return audit_buf; } -static inline void xfrm_audit_helper_usrinfo(kuid_t auid, unsigned int ses, u32 secid, +static inline void xfrm_audit_helper_usrinfo(bool task_valid, struct audit_buffer *audit_buf) { - char *secctx; - u32 secctx_len; - - audit_log_format(audit_buf, " auid=%u ses=%u", - from_kuid(&init_user_ns, auid), ses); - if (secid != 0 && - security_secid_to_secctx(secid, &secctx, &secctx_len) == 0) { - audit_log_format(audit_buf, " subj=%s", secctx); - security_release_secctx(secctx, secctx_len); - } else - audit_log_task_context(audit_buf); -} - -void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, kuid_t auid, - unsigned int ses, u32 secid); -void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, kuid_t auid, - unsigned int ses, u32 secid); -void xfrm_audit_state_add(struct xfrm_state *x, int result, kuid_t auid, - unsigned int ses, u32 secid); -void xfrm_audit_state_delete(struct xfrm_state *x, int result, kuid_t auid, - unsigned int ses, u32 secid); + const unsigned int auid = from_kuid(&init_user_ns, task_valid ? + audit_get_loginuid(current) : + INVALID_UID); + const unsigned int ses = task_valid ? audit_get_sessionid(current) : + (unsigned int) -1; + + audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses); + audit_log_task_context(audit_buf); +} + +void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid); +void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, + bool task_valid); +void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid); +void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid); void xfrm_audit_state_replay_overflow(struct xfrm_state *x, struct sk_buff *skb); void xfrm_audit_state_replay(struct xfrm_state *x, struct sk_buff *skb, @@ -749,22 +736,22 @@ void xfrm_audit_state_icvfail(struct xfrm_state *x, struct sk_buff *skb, #else static inline void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, - kuid_t auid, unsigned int ses, u32 secid) + bool task_valid) { } static inline void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, - kuid_t auid, unsigned int ses, u32 secid) + bool task_valid) { } static inline void xfrm_audit_state_add(struct xfrm_state *x, int result, - kuid_t auid, unsigned int ses, u32 secid) + bool task_valid) { } static inline void xfrm_audit_state_delete(struct xfrm_state *x, int result, - kuid_t auid, unsigned int ses, u32 secid) + bool task_valid) { } @@ -1508,7 +1495,7 @@ struct xfrmk_spdinfo { struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); int xfrm_state_delete(struct xfrm_state *x); -int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info); +int xfrm_state_flush(struct net *net, u8 proto, bool task_valid); void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si); void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si); u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq); @@ -1603,7 +1590,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, int *err); struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir, u32 id, int delete, int *err); -int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info); +int xfrm_policy_flush(struct net *net, u8 type, bool task_valid); u32 xfrm_get_acqseq(void); int verify_spi_info(u8 proto, u32 min, u32 max); int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); diff --git a/include/sound/atmel-ac97c.h b/include/sound/atmel-ac97c.h index e6aabdb458653f..00e6c289a9363c 100644 --- a/include/sound/atmel-ac97c.h +++ b/include/sound/atmel-ac97c.h @@ -23,7 +23,6 @@ * @reset_pin: GPIO pin wired to the reset input on the external AC97 codec, * optional to use, set to -ENODEV if not in use. AC97 layer will * try to do a software reset of the external codec anyway. - * @flags: Flags for which directions should be enabled. * * If the user do not want to use a DMA channel for playback or capture, i.e. * only one feature is required on the board. The slave for playback or capture @@ -33,7 +32,6 @@ struct ac97c_platform_data { struct dw_dma_slave rx_dws; struct dw_dma_slave tx_dws; - unsigned int flags; int reset_pin; }; diff --git a/include/sound/cs42l56.h b/include/sound/cs42l56.h new file mode 100644 index 00000000000000..2467c8ff132c71 --- /dev/null +++ b/include/sound/cs42l56.h @@ -0,0 +1,48 @@ +/* + * linux/sound/cs42l56.h -- Platform data for CS42L56 + * + * Copyright (c) 2014 Cirrus Logic 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 __CS42L56_H +#define __CS42L56_H + +struct cs42l56_platform_data { + + /* GPIO for Reset */ + unsigned int gpio_nreset; + + /* MICBIAS Level. Check datasheet Pg48 */ + unsigned int micbias_lvl; + + /* Analog Input 1A Reference 0=Single 1=Pseudo-Differential */ + unsigned int ain1a_ref_cfg; + + /* Analog Input 2A Reference 0=Single 1=Pseudo-Differential */ + unsigned int ain2a_ref_cfg; + + /* Analog Input 1B Reference 0=Single 1=Pseudo-Differential */ + unsigned int ain1b_ref_cfg; + + /* Analog Input 2B Reference 0=Single 1=Pseudo-Differential */ + unsigned int ain2b_ref_cfg; + + /* Charge Pump Freq. Check datasheet Pg62 */ + unsigned int chgfreq; + + /* HighPass Filter Right Channel Corner Frequency */ + unsigned int hpfb_freq; + + /* HighPass Filter Left Channel Corner Frequency */ + unsigned int hpfa_freq; + + /* Adaptive Power Control for LO/HP */ + unsigned int adaptive_pwr; + +}; + +#endif /* __CS42L56_H */ diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index 34a3c02a4576d5..a03268ec59c373 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h @@ -34,40 +34,24 @@ * B : SSI direction */ #define RSND_SSI_CLK_PIN_SHARE (1 << 31) -#define RSND_SSI_PLAY (1 << 24) #define RSND_SSI(_dma_id, _pio_irq, _flags) \ { .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags } -#define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags) \ -{ .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags } #define RSND_SSI_UNUSED \ -{ .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 } +{ .dma_id = -1, .pio_irq = -1, .flags = 0 } struct rsnd_ssi_platform_info { - int dai_id; /* will be removed */ int dma_id; int pio_irq; u32 flags; }; -/* - * flags - */ -#define RSND_SCU_USE_HPBIF (1 << 31) /* it needs RSND_SSI_DEPENDENT */ - #define RSND_SRC(rate, _dma_id) \ -{ .flags = RSND_SCU_USE_HPBIF, .convert_rate = rate, .dma_id = _dma_id, } -#define RSND_SRC_SET(rate, _dma_id) \ - { .flags = RSND_SCU_USE_HPBIF, .convert_rate = rate, .dma_id = _dma_id, } +{ .convert_rate = rate, .dma_id = _dma_id, } #define RSND_SRC_UNUSED \ - { .flags = 0, .convert_rate = 0, .dma_id = 0, } - -#define rsnd_scu_platform_info rsnd_src_platform_info -#define src_info scu_info -#define src_info_nr scu_info_nr +{ .convert_rate = 0, .dma_id = -1, } struct rsnd_src_platform_info { - u32 flags; u32 convert_rate; /* sampling rate convert */ int dma_id; /* for Gen2 SCU */ }; diff --git a/include/sound/rt5640.h b/include/sound/rt5640.h index 27cc75ed67f87a..59d26dd81e4533 100644 --- a/include/sound/rt5640.h +++ b/include/sound/rt5640.h @@ -16,6 +16,10 @@ struct rt5640_platform_data { bool in1_diff; bool in2_diff; + bool dmic_en; + bool dmic1_data_pin; /* 0 = IN1P; 1 = GPIO3 */ + bool dmic2_data_pin; /* 0 = IN1N; 1 = GPIO4 */ + int ldo1_en; /* GPIO for LDO1_EN */ }; diff --git a/include/sound/rt5645.h b/include/sound/rt5645.h new file mode 100644 index 00000000000000..1de744c242f62f --- /dev/null +++ b/include/sound/rt5645.h @@ -0,0 +1,25 @@ +/* + * linux/sound/rt5645.h -- Platform data for RT5645 + * + * Copyright 2013 Realtek Microelectronics + * + * 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 __LINUX_SND_RT5645_H +#define __LINUX_SND_RT5645_H + +struct rt5645_platform_data { + /* IN2 can optionally be differential */ + bool in2_diff; + + bool dmic_en; + unsigned int dmic1_data_pin; + /* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */ + unsigned int dmic2_data_pin; + /* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */ +}; + +#endif diff --git a/include/sound/rt5651.h b/include/sound/rt5651.h new file mode 100644 index 00000000000000..d35de758dfb553 --- /dev/null +++ b/include/sound/rt5651.h @@ -0,0 +1,21 @@ +/* + * linux/sound/rt286.h -- Platform data for RT286 + * + * Copyright 2013 Realtek Microelectronics + * + * 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 __LINUX_SND_RT5651_H +#define __LINUX_SND_RT5651_H + +struct rt5651_platform_data { + /* IN2 can optionally be differential */ + bool in2_diff; + + bool dmic_en; +}; + +#endif diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index fad76769f153d8..e2c3e45d06560c 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -277,7 +277,6 @@ struct snd_soc_dai { struct snd_soc_card *card; struct list_head list; - struct list_head card_list; }; static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai, diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index ef78f562f4a88b..b041fc6778517d 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -107,10 +107,6 @@ struct device; { .id = snd_soc_dapm_mux, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = 1} -#define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \ - SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) -#define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \ - SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ @@ -166,10 +162,6 @@ struct device; SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = 1, \ .event = wevent, .event_flags = wflags} -#define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ - wevent, wflags) \ - SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, wevent, \ - wflags) /* additional sequencing control within an event type */ #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \ @@ -305,16 +297,12 @@ struct device; .get = snd_soc_dapm_get_enum_double, \ .put = snd_soc_dapm_put_enum_double, \ .private_value = (unsigned long)&xenum } -#define SOC_DAPM_ENUM_VIRT(xname, xenum) \ - SOC_DAPM_ENUM(xname, xenum) #define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_enum_double, \ .get = xget, \ .put = xput, \ .private_value = (unsigned long)&xenum } -#define SOC_DAPM_VALUE_ENUM(xname, xenum) \ - SOC_DAPM_ENUM(xname, xenum) #define SOC_DAPM_PIN_SWITCH(xname) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname " Switch", \ .info = snd_soc_dapm_info_pin_switch, \ @@ -606,6 +594,7 @@ struct snd_soc_dapm_context { enum snd_soc_dapm_type, int); struct device *dev; /* from parent - for debug */ + struct snd_soc_component *component; /* parent component */ struct snd_soc_codec *codec; /* parent codec */ struct snd_soc_platform *platform; /* parent platform */ struct snd_soc_card *card; /* parent card */ diff --git a/include/sound/soc.h b/include/sound/soc.h index 0b83168d8ff45a..dcdcc95efd1d4a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -196,8 +196,6 @@ .info = snd_soc_info_enum_double, \ .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ .private_value = (unsigned long)&xenum } -#define SOC_VALUE_ENUM(xname, xenum) \ - SOC_ENUM(xname, xenum) #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ xhandler_get, xhandler_put) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ @@ -266,6 +264,13 @@ {.base = xbase, .num_regs = xregs, \ .mask = xmask }) } +#define SND_SOC_BYTES_EXT(xname, xcount, xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_bytes_info_ext, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = (unsigned long)&(struct soc_bytes_ext) \ + {.max = xcount} } + #define SOC_SINGLE_XR_SX(xname, xregbase, xregcount, xnbits, \ xmin, xmax, xinvert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ @@ -377,6 +382,8 @@ int snd_soc_resume(struct device *dev); int snd_soc_poweroff(struct device *dev); int snd_soc_register_platform(struct device *dev, const struct snd_soc_platform_driver *platform_drv); +int devm_snd_soc_register_platform(struct device *dev, + const struct snd_soc_platform_driver *platform_drv); void snd_soc_unregister_platform(struct device *dev); int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, const struct snd_soc_platform_driver *platform_drv); @@ -393,14 +400,6 @@ int devm_snd_soc_register_component(struct device *dev, const struct snd_soc_component_driver *cmpnt_drv, struct snd_soc_dai_driver *dai_drv, int num_dai); void snd_soc_unregister_component(struct device *dev); -int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, - unsigned int reg); -int snd_soc_codec_readable_register(struct snd_soc_codec *codec, - unsigned int reg); -int snd_soc_codec_writable_register(struct snd_soc_codec *codec, - unsigned int reg); -int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, - struct regmap *regmap); int snd_soc_cache_sync(struct snd_soc_codec *codec); int snd_soc_cache_init(struct snd_soc_codec *codec); int snd_soc_cache_exit(struct snd_soc_codec *codec); @@ -469,12 +468,12 @@ static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, #endif /* codec register bit access */ -int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, +int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned int reg, unsigned int mask, unsigned int value); int snd_soc_update_bits_locked(struct snd_soc_codec *codec, - unsigned short reg, unsigned int mask, + unsigned int reg, unsigned int mask, unsigned int value); -int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, +int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg, unsigned int mask, unsigned int value); int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, @@ -540,6 +539,8 @@ int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *ucontrol); int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, @@ -668,6 +669,7 @@ struct snd_soc_component { unsigned int active; unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ + unsigned int registered_as_component:1; struct list_head list; @@ -677,6 +679,14 @@ struct snd_soc_component { const struct snd_soc_component_driver *driver; struct list_head dai_list; + + int (*read)(struct snd_soc_component *, unsigned int, unsigned int *); + int (*write)(struct snd_soc_component *, unsigned int, unsigned int); + + struct regmap *regmap; + int val_bytes; + + struct mutex io_mutex; }; /* SoC Audio Codec device */ @@ -691,10 +701,6 @@ struct snd_soc_codec { struct snd_soc_card *card; struct list_head list; struct list_head card_list; - int num_dai; - int (*volatile_register)(struct snd_soc_codec *, unsigned int); - int (*readable_register)(struct snd_soc_codec *, unsigned int); - int (*writable_register)(struct snd_soc_codec *, unsigned int); /* runtime */ struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ @@ -704,18 +710,14 @@ struct snd_soc_codec { unsigned int ac97_registered:1; /* Codec has been AC97 registered */ unsigned int ac97_created:1; /* Codec has been created by SoC */ unsigned int cache_init:1; /* codec cache has been initialized */ - unsigned int using_regmap:1; /* using regmap access */ u32 cache_only; /* Suppress writes to hardware */ u32 cache_sync; /* Cache needs to be synced to hardware */ /* codec IO */ void *control_data; /* codec control (i2c/3wire) data */ hw_write_t hw_write; - unsigned int (*read)(struct snd_soc_codec *, unsigned int); - int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); void *reg_cache; struct mutex cache_rw_mutex; - int val_bytes; /* component */ struct snd_soc_component component; @@ -754,13 +756,9 @@ struct snd_soc_codec_driver { unsigned int freq_in, unsigned int freq_out); /* codec IO */ + struct regmap *(*get_regmap)(struct device *); unsigned int (*read)(struct snd_soc_codec *, unsigned int); int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); - int (*display_register)(struct snd_soc_codec *, char *, - size_t, unsigned int); - int (*volatile_register)(struct snd_soc_codec *, unsigned int); - int (*readable_register)(struct snd_soc_codec *, unsigned int); - int (*writable_register)(struct snd_soc_codec *, unsigned int); unsigned int reg_cache_size; short reg_cache_step; short reg_word_size; @@ -791,6 +789,7 @@ struct snd_soc_platform_driver { int (*remove)(struct snd_soc_platform *); int (*suspend)(struct snd_soc_dai *dai); int (*resume)(struct snd_soc_dai *dai); + struct snd_soc_component_driver component_driver; /* pcm creation and destruction */ int (*pcm_new)(struct snd_soc_pcm_runtime *); @@ -835,7 +834,6 @@ struct snd_soc_platform { int id; struct device *dev; const struct snd_soc_platform_driver *driver; - struct mutex mutex; unsigned int suspended:1; /* platform is suspended */ unsigned int probed:1; @@ -844,6 +842,8 @@ struct snd_soc_platform { struct list_head list; struct list_head card_list; + struct snd_soc_component component; + struct snd_soc_dapm_context dapm; #ifdef CONFIG_DEBUG_FS @@ -931,7 +931,12 @@ struct snd_soc_dai_link { }; struct snd_soc_codec_conf { + /* + * specify device either by device name, or by + * DT/OF node, but not both. + */ const char *dev_name; + const struct device_node *of_node; /* * optional map of kcontrol, widget and path name prefixes that are @@ -942,7 +947,13 @@ struct snd_soc_codec_conf { struct snd_soc_aux_dev { const char *name; /* Codec name */ - const char *codec_name; /* for multi-codec */ + + /* + * specify multi-codec either by device name, or by + * DT/OF node, but not both. + */ + const char *codec_name; + const struct device_node *codec_of_node; /* codec/machine specific init - e.g. add machine controls */ int (*init)(struct snd_soc_dapm_context *dapm); @@ -957,7 +968,6 @@ struct snd_soc_card { struct snd_card *snd_card; struct module *owner; - struct list_head list; struct mutex mutex; struct mutex dapm_mutex; @@ -1020,7 +1030,6 @@ struct snd_soc_card { /* lists of probed devices belonging to this card */ struct list_head codec_dev_list; struct list_head platform_dev_list; - struct list_head dai_dev_list; struct list_head widgets; struct list_head paths; @@ -1090,6 +1099,10 @@ struct soc_bytes { u32 mask; }; +struct soc_bytes_ext { + int max; +}; + /* multi register control */ struct soc_mreg_control { long min, max; @@ -1120,10 +1133,39 @@ static inline struct snd_soc_codec *snd_soc_component_to_codec( return container_of(component, struct snd_soc_codec, component); } +/** + * snd_soc_component_to_platform() - Casts a component to the platform it is embedded in + * @component: The component to cast to a platform + * + * This function must only be used on components that are known to be platforms. + * Otherwise the behavior is undefined. + */ +static inline struct snd_soc_platform *snd_soc_component_to_platform( + struct snd_soc_component *component) +{ + return container_of(component, struct snd_soc_platform, component); +} + /* codec IO */ unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg); -unsigned int snd_soc_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int val); +int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int val); + +/* component IO */ +int snd_soc_component_read(struct snd_soc_component *component, + unsigned int reg, unsigned int *val); +int snd_soc_component_write(struct snd_soc_component *component, + unsigned int reg, unsigned int val); +int snd_soc_component_update_bits(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, unsigned int val); +int snd_soc_component_update_bits_async(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, unsigned int val); +void snd_soc_component_async_complete(struct snd_soc_component *component); +int snd_soc_component_test_bits(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, unsigned int value); + +int snd_soc_component_init_io(struct snd_soc_component *component, + struct regmap *regmap); /* device driver data */ @@ -1173,7 +1215,6 @@ static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd) static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) { - INIT_LIST_HEAD(&card->dai_dev_list); INIT_LIST_HEAD(&card->codec_dev_list); INIT_LIST_HEAD(&card->platform_dev_list); INIT_LIST_HEAD(&card->widgets); @@ -1228,6 +1269,50 @@ static inline bool snd_soc_codec_is_active(struct snd_soc_codec *codec) return snd_soc_component_is_active(&codec->component); } +/** + * snd_soc_kcontrol_component() - Returns the component that registered the + * control + * @kcontrol: The control for which to get the component + * + * Note: This function will work correctly if the control has been registered + * for a component. Either with snd_soc_add_codec_controls() or + * snd_soc_add_platform_controls() or via table based setup for either a + * CODEC, a platform or component driver. Otherwise the behavior is undefined. + */ +static inline struct snd_soc_component *snd_soc_kcontrol_component( + struct snd_kcontrol *kcontrol) +{ + return snd_kcontrol_chip(kcontrol); +} + +/** + * snd_soc_kcontrol_codec() - Returns the CODEC that registered the control + * @kcontrol: The control for which to get the CODEC + * + * Note: This function will only work correctly if the control has been + * registered with snd_soc_add_codec_controls() or via table based setup of + * snd_soc_codec_driver. Otherwise the behavior is undefined. + */ +static inline struct snd_soc_codec *snd_soc_kcontrol_codec( + struct snd_kcontrol *kcontrol) +{ + return snd_soc_component_to_codec(snd_soc_kcontrol_component(kcontrol)); +} + +/** + * snd_soc_kcontrol_platform() - Returns the platform that registerd the control + * @kcontrol: The control for which to get the platform + * + * Note: This function will only work correctly if the control has been + * registered with snd_soc_add_platform_controls() or via table based setup of + * a snd_soc_platform_driver. Otherwise the behavior is undefined. + */ +static inline struct snd_soc_platform *snd_soc_kcontrol_platform( + struct snd_kcontrol *kcontrol) +{ + return snd_soc_component_to_platform(snd_soc_kcontrol_component(kcontrol)); +} + int snd_soc_util_init(void); void snd_soc_util_exit(void); @@ -1241,7 +1326,9 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, - const char *prefix); + const char *prefix, + struct device_node **bitclkmaster, + struct device_node **framemaster); int snd_soc_of_get_dai_name(struct device_node *of_node, const char **dai_name); diff --git a/include/sound/sta350.h b/include/sound/sta350.h new file mode 100644 index 00000000000000..42edceb096a007 --- /dev/null +++ b/include/sound/sta350.h @@ -0,0 +1,57 @@ +/* + * Platform data for ST STA350 ASoC codec driver. + * + * Copyright: 2014 Raumfeld GmbH + * Author: Sven Brandau + * + * 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. + */ +#ifndef __LINUX_SND__STA350_H +#define __LINUX_SND__STA350_H + +#define STA350_OCFG_2CH 0 +#define STA350_OCFG_2_1CH 1 +#define STA350_OCFG_1CH 3 + +#define STA350_OM_CH1 0 +#define STA350_OM_CH2 1 +#define STA350_OM_CH3 2 + +#define STA350_THERMAL_ADJUSTMENT_ENABLE 1 +#define STA350_THERMAL_RECOVERY_ENABLE 2 +#define STA350_FAULT_DETECT_RECOVERY_BYPASS 1 + +#define STA350_FFX_PM_DROP_COMP 0 +#define STA350_FFX_PM_TAPERED_COMP 1 +#define STA350_FFX_PM_FULL_POWER 2 +#define STA350_FFX_PM_VARIABLE_DROP_COMP 3 + + +struct sta350_platform_data { + u8 output_conf; + u8 ch1_output_mapping; + u8 ch2_output_mapping; + u8 ch3_output_mapping; + u8 ffx_power_output_mode; + u8 drop_compensation_ns; + u8 powerdown_delay_divider; + unsigned int thermal_warning_recovery:1; + unsigned int thermal_warning_adjustment:1; + unsigned int fault_detect_recovery:1; + unsigned int oc_warning_adjustment:1; + unsigned int max_power_use_mpcc:1; + unsigned int max_power_correction:1; + unsigned int am_reduction_mode:1; + unsigned int odd_pwm_speed_mode:1; + unsigned int distortion_compensation:1; + unsigned int invalid_input_detect_mute:1; + unsigned int activate_mute_output:1; + unsigned int bridge_immediate_off:1; + unsigned int noise_shape_dc_cut:1; + unsigned int powerdown_master_vol:1; +}; + +#endif /* __LINUX_SND__STA350_H */ diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h index 03996b2bb04f86..c75c795a377b5c 100644 --- a/include/trace/events/asoc.h +++ b/include/trace/events/asoc.h @@ -11,102 +11,10 @@ struct snd_soc_jack; struct snd_soc_codec; -struct snd_soc_platform; struct snd_soc_card; struct snd_soc_dapm_widget; struct snd_soc_dapm_path; -/* - * Log register events - */ -DECLARE_EVENT_CLASS(snd_soc_reg, - - TP_PROTO(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val), - - TP_ARGS(codec, reg, val), - - TP_STRUCT__entry( - __string( name, codec->name ) - __field( int, id ) - __field( unsigned int, reg ) - __field( unsigned int, val ) - ), - - TP_fast_assign( - __assign_str(name, codec->name); - __entry->id = codec->id; - __entry->reg = reg; - __entry->val = val; - ), - - TP_printk("codec=%s.%d reg=%x val=%x", __get_str(name), - (int)__entry->id, (unsigned int)__entry->reg, - (unsigned int)__entry->val) -); - -DEFINE_EVENT(snd_soc_reg, snd_soc_reg_write, - - TP_PROTO(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val), - - TP_ARGS(codec, reg, val) - -); - -DEFINE_EVENT(snd_soc_reg, snd_soc_reg_read, - - TP_PROTO(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val), - - TP_ARGS(codec, reg, val) - -); - -DECLARE_EVENT_CLASS(snd_soc_preg, - - TP_PROTO(struct snd_soc_platform *platform, unsigned int reg, - unsigned int val), - - TP_ARGS(platform, reg, val), - - TP_STRUCT__entry( - __string( name, platform->name ) - __field( int, id ) - __field( unsigned int, reg ) - __field( unsigned int, val ) - ), - - TP_fast_assign( - __assign_str(name, platform->name); - __entry->id = platform->id; - __entry->reg = reg; - __entry->val = val; - ), - - TP_printk("platform=%s.%d reg=%x val=%x", __get_str(name), - (int)__entry->id, (unsigned int)__entry->reg, - (unsigned int)__entry->val) -); - -DEFINE_EVENT(snd_soc_preg, snd_soc_preg_write, - - TP_PROTO(struct snd_soc_platform *platform, unsigned int reg, - unsigned int val), - - TP_ARGS(platform, reg, val) - -); - -DEFINE_EVENT(snd_soc_preg, snd_soc_preg_read, - - TP_PROTO(struct snd_soc_platform *platform, unsigned int reg, - unsigned int val), - - TP_ARGS(platform, reg, val) - -); - DECLARE_EVENT_CLASS(snd_soc_card, TP_PROTO(struct snd_soc_card *card, int val), diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 6a1a0245474fee..d4f70a7fe8761a 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -36,7 +36,7 @@ struct extent_status; #define show_map_flags(flags) __print_flags(flags, "|", \ { EXT4_GET_BLOCKS_CREATE, "CREATE" }, \ - { EXT4_GET_BLOCKS_UNINIT_EXT, "UNINIT" }, \ + { EXT4_GET_BLOCKS_UNWRIT_EXT, "UNWRIT" }, \ { EXT4_GET_BLOCKS_DELALLOC_RESERVE, "DELALLOC" }, \ { EXT4_GET_BLOCKS_PRE_IO, "PRE_IO" }, \ { EXT4_GET_BLOCKS_CONVERT, "CONVERT" }, \ @@ -51,7 +51,6 @@ struct extent_status; { EXT4_MAP_MAPPED, "M" }, \ { EXT4_MAP_UNWRITTEN, "U" }, \ { EXT4_MAP_BOUNDARY, "B" }, \ - { EXT4_MAP_UNINIT, "u" }, \ { EXT4_MAP_FROM_CLUSTER, "C" }) #define show_free_flags(flags) __print_flags(flags, "|", \ @@ -1497,7 +1496,7 @@ DEFINE_EVENT(ext4__truncate, ext4_truncate_exit, TP_ARGS(inode) ); -/* 'ux' is the uninitialized extent. */ +/* 'ux' is the unwritten extent. */ TRACE_EVENT(ext4_ext_convert_to_initialized_enter, TP_PROTO(struct inode *inode, struct ext4_map_blocks *map, struct ext4_extent *ux), @@ -1533,7 +1532,7 @@ TRACE_EVENT(ext4_ext_convert_to_initialized_enter, ); /* - * 'ux' is the uninitialized extent. + * 'ux' is the unwritten extent. * 'ix' is the initialized extent to which blocks are transferred. */ TRACE_EVENT(ext4_ext_convert_to_initialized_fastpath, @@ -1811,7 +1810,7 @@ DEFINE_EVENT(ext4__trim, ext4_trim_all_free, TP_ARGS(sb, group, start, len) ); -TRACE_EVENT(ext4_ext_handle_uninitialized_extents, +TRACE_EVENT(ext4_ext_handle_unwritten_extents, TP_PROTO(struct inode *inode, struct ext4_map_blocks *map, int flags, unsigned int allocated, ext4_fsblk_t newblock), diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 67f38faac589ad..b983990b4a9f06 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -659,6 +659,66 @@ DEFINE_EVENT_CONDITION(f2fs__submit_bio, f2fs_submit_read_bio, TP_CONDITION(bio) ); +TRACE_EVENT(f2fs_write_begin, + + TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, + unsigned int flags), + + TP_ARGS(inode, pos, len, flags), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(loff_t, pos) + __field(unsigned int, len) + __field(unsigned int, flags) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->pos = pos; + __entry->len = len; + __entry->flags = flags; + ), + + TP_printk("dev = (%d,%d), ino = %lu, pos = %llu, len = %u, flags = %u", + show_dev_ino(__entry), + (unsigned long long)__entry->pos, + __entry->len, + __entry->flags) +); + +TRACE_EVENT(f2fs_write_end, + + TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, + unsigned int copied), + + TP_ARGS(inode, pos, len, copied), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(loff_t, pos) + __field(unsigned int, len) + __field(unsigned int, copied) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->pos = pos; + __entry->len = len; + __entry->copied = copied; + ), + + TP_printk("dev = (%d,%d), ino = %lu, pos = %llu, len = %u, copied = %u", + show_dev_ino(__entry), + (unsigned long long)__entry->pos, + __entry->len, + __entry->copied) +); + DECLARE_EVENT_CLASS(f2fs__page, TP_PROTO(struct page *page, int type), @@ -672,6 +732,7 @@ DECLARE_EVENT_CLASS(f2fs__page, __field(int, dir) __field(pgoff_t, index) __field(int, dirty) + __field(int, uptodate) ), TP_fast_assign( @@ -681,14 +742,31 @@ DECLARE_EVENT_CLASS(f2fs__page, __entry->dir = S_ISDIR(page->mapping->host->i_mode); __entry->index = page->index; __entry->dirty = PageDirty(page); + __entry->uptodate = PageUptodate(page); ), - TP_printk("dev = (%d,%d), ino = %lu, %s, %s, index = %lu, dirty = %d", + TP_printk("dev = (%d,%d), ino = %lu, %s, %s, index = %lu, " + "dirty = %d, uptodate = %d", show_dev_ino(__entry), show_block_type(__entry->type), show_file_type(__entry->dir), (unsigned long)__entry->index, - __entry->dirty) + __entry->dirty, + __entry->uptodate) +); + +DEFINE_EVENT(f2fs__page, f2fs_writepage, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type) +); + +DEFINE_EVENT(f2fs__page, f2fs_readpage, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type) ); DEFINE_EVENT(f2fs__page, f2fs_set_page_dirty, @@ -705,6 +783,70 @@ DEFINE_EVENT(f2fs__page, f2fs_vm_page_mkwrite, TP_ARGS(page, type) ); +TRACE_EVENT(f2fs_writepages, + + TP_PROTO(struct inode *inode, struct writeback_control *wbc, int type), + + TP_ARGS(inode, wbc, type), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(int, type) + __field(int, dir) + __field(long, nr_to_write) + __field(long, pages_skipped) + __field(loff_t, range_start) + __field(loff_t, range_end) + __field(pgoff_t, writeback_index) + __field(int, sync_mode) + __field(char, for_kupdate) + __field(char, for_background) + __field(char, tagged_writepages) + __field(char, for_reclaim) + __field(char, range_cyclic) + __field(char, for_sync) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->type = type; + __entry->dir = S_ISDIR(inode->i_mode); + __entry->nr_to_write = wbc->nr_to_write; + __entry->pages_skipped = wbc->pages_skipped; + __entry->range_start = wbc->range_start; + __entry->range_end = wbc->range_end; + __entry->writeback_index = inode->i_mapping->writeback_index; + __entry->sync_mode = wbc->sync_mode; + __entry->for_kupdate = wbc->for_kupdate; + __entry->for_background = wbc->for_background; + __entry->tagged_writepages = wbc->tagged_writepages; + __entry->for_reclaim = wbc->for_reclaim; + __entry->range_cyclic = wbc->range_cyclic; + __entry->for_sync = wbc->for_sync; + ), + + TP_printk("dev = (%d,%d), ino = %lu, %s, %s, nr_to_write %ld, " + "skipped %ld, start %lld, end %lld, wb_idx %lu, sync_mode %d, " + "kupdate %u background %u tagged %u reclaim %u cyclic %u sync %u", + show_dev_ino(__entry), + show_block_type(__entry->type), + show_file_type(__entry->dir), + __entry->nr_to_write, + __entry->pages_skipped, + __entry->range_start, + __entry->range_end, + (unsigned long)__entry->writeback_index, + __entry->sync_mode, + __entry->for_kupdate, + __entry->for_background, + __entry->tagged_writepages, + __entry->for_reclaim, + __entry->range_cyclic, + __entry->for_sync) +); + TRACE_EVENT(f2fs_submit_page_mbio, TP_PROTO(struct page *page, int rw, int type, block_t blk_addr), diff --git a/include/trace/events/filelock.h b/include/trace/events/filelock.h new file mode 100644 index 00000000000000..d1e9d3eaa8ceb4 --- /dev/null +++ b/include/trace/events/filelock.h @@ -0,0 +1,93 @@ +/* + * Events for filesystem locks + * + * Copyright 2013 Jeff Layton + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM filelock + +#if !defined(_TRACE_FILELOCK_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_FILELOCK_H + +#include +#include +#include +#include + +#define show_fl_flags(val) \ + __print_flags(val, "|", \ + { FL_POSIX, "FL_POSIX" }, \ + { FL_FLOCK, "FL_FLOCK" }, \ + { FL_DELEG, "FL_DELEG" }, \ + { FL_ACCESS, "FL_ACCESS" }, \ + { FL_EXISTS, "FL_EXISTS" }, \ + { FL_LEASE, "FL_LEASE" }, \ + { FL_CLOSE, "FL_CLOSE" }, \ + { FL_SLEEP, "FL_SLEEP" }, \ + { FL_DOWNGRADE_PENDING, "FL_DOWNGRADE_PENDING" }, \ + { FL_UNLOCK_PENDING, "FL_UNLOCK_PENDING" }, \ + { FL_OFDLCK, "FL_OFDLCK" }) + +#define show_fl_type(val) \ + __print_symbolic(val, \ + { F_RDLCK, "F_RDLCK" }, \ + { F_WRLCK, "F_WRLCK" }, \ + { F_UNLCK, "F_UNLCK" }) + +DECLARE_EVENT_CLASS(filelock_lease, + + TP_PROTO(struct inode *inode, struct file_lock *fl), + + TP_ARGS(inode, fl), + + TP_STRUCT__entry( + __field(struct file_lock *, fl) + __field(unsigned long, i_ino) + __field(dev_t, s_dev) + __field(struct file_lock *, fl_next) + __field(fl_owner_t, fl_owner) + __field(unsigned int, fl_flags) + __field(unsigned char, fl_type) + __field(unsigned long, fl_break_time) + __field(unsigned long, fl_downgrade_time) + ), + + TP_fast_assign( + __entry->fl = fl; + __entry->s_dev = inode->i_sb->s_dev; + __entry->i_ino = inode->i_ino; + __entry->fl_next = fl->fl_next; + __entry->fl_owner = fl->fl_owner; + __entry->fl_flags = fl->fl_flags; + __entry->fl_type = fl->fl_type; + __entry->fl_break_time = fl->fl_break_time; + __entry->fl_downgrade_time = fl->fl_downgrade_time; + ), + + TP_printk("fl=0x%p dev=0x%x:0x%x ino=0x%lx fl_next=0x%p fl_owner=0x%p fl_flags=%s fl_type=%s fl_break_time=%lu fl_downgrade_time=%lu", + __entry->fl, MAJOR(__entry->s_dev), MINOR(__entry->s_dev), + __entry->i_ino, __entry->fl_next, __entry->fl_owner, + show_fl_flags(__entry->fl_flags), + show_fl_type(__entry->fl_type), + __entry->fl_break_time, __entry->fl_downgrade_time) +); + +DEFINE_EVENT(filelock_lease, break_lease_noblock, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, break_lease_block, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, break_lease_unblock, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, generic_add_lease, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +DEFINE_EVENT(filelock_lease, generic_delete_lease, TP_PROTO(struct inode *inode, struct file_lock *fl), + TP_ARGS(inode, fl)); + +#endif /* _TRACE_FILELOCK_H */ + +/* This part must be outside protection */ +#include diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 126bfaa8bb6be4..8a3e4ef00c3db4 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -337,6 +337,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_EXEC_NO_RELOC 25 #define I915_PARAM_HAS_EXEC_HANDLE_LUT 26 #define I915_PARAM_HAS_WT 27 +#define I915_PARAM_CMD_PARSER_VERSION 28 typedef struct drm_i915_getparam { int param; diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 6929571b79b0c3..24e9033f8b3f9f 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -317,6 +317,7 @@ header-y += ppp-ioctl.h header-y += ppp_defs.h header-y += pps.h header-y += prctl.h +header-y += psci.h header-y += ptp_clock.h header-y += ptrace.h header-y += qnx4_fs.h diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index 11917f747cb401..a8eff44a89d5ab 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -343,6 +343,7 @@ enum { #define AUDIT_ARCH_IA64 (EM_IA_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) #define AUDIT_ARCH_M32R (EM_M32R) #define AUDIT_ARCH_M68K (EM_68K) +#define AUDIT_ARCH_MICROBLAZE (EM_MICROBLAZE) #define AUDIT_ARCH_MIPS (EM_MIPS) #define AUDIT_ARCH_MIPSEL (EM_MIPS|__AUDIT_ARCH_LE) #define AUDIT_ARCH_MIPS64 (EM_MIPS|__AUDIT_ARCH_64BIT) @@ -373,6 +374,14 @@ enum { */ #define AUDIT_MESSAGE_TEXT_MAX 8560 +/* Multicast Netlink socket groups (default up to 32) */ +enum audit_nlgrps { + AUDIT_NLGRP_NONE, /* Group 0 not used */ + AUDIT_NLGRP_READLOG, /* "best effort" read only socket */ + __AUDIT_NLGRP_MAX +}; +#define AUDIT_NLGRP_MAX (__AUDIT_NLGRP_MAX - 1) + struct audit_status { __u32 mask; /* Bit mask for valid entries */ __u32 enabled; /* 1 = enabled, 0 = disabled */ @@ -424,17 +433,4 @@ struct audit_rule_data { char buf[0]; /* string fields buffer */ }; -/* audit_rule is supported to maintain backward compatibility with - * userspace. It supports integer fields only and corresponds to - * AUDIT_ADD, AUDIT_DEL and AUDIT_LIST requests. - */ -struct audit_rule { /* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */ - __u32 flags; /* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */ - __u32 action; /* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */ - __u32 field_count; - __u32 mask[AUDIT_BITMASK_SIZE]; - __u32 fields[AUDIT_MAX_FIELDS]; - __u32 values[AUDIT_MAX_FIELDS]; -}; - #endif /* _UAPI_LINUX_AUDIT_H_ */ diff --git a/include/uapi/linux/capability.h b/include/uapi/linux/capability.h index 154dd6d3c8feda..12c37a197d247c 100644 --- a/include/uapi/linux/capability.h +++ b/include/uapi/linux/capability.h @@ -347,7 +347,12 @@ struct vfs_cap_data { #define CAP_BLOCK_SUSPEND 36 -#define CAP_LAST_CAP CAP_BLOCK_SUSPEND +/* Allow reading the audit log via multicast netlink socket */ + +#define CAP_AUDIT_READ 37 + + +#define CAP_LAST_CAP CAP_AUDIT_READ #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index fd161e91b6d7e7..d47d31d6fa0edc 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -846,6 +846,35 @@ struct ethtool_rxfh_indir { __u32 ring_index[0]; }; +/** + * struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key. + * @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH + * @rss_context: RSS context identifier. + * @indir_size: On entry, the array size of the user buffer, which may be zero. + * On return from %ETHTOOL_GRSSH, the array size of the hardware + * indirection table. + * @key_size: On entry, the array size of the user buffer in bytes, + * which may be zero. + * On return from %ETHTOOL_GRSSH, the size of the RSS hash key. + * @rsvd: Reserved for future extensions. + * @rss_config: RX ring/queue index for each hash value i.e., indirection table + * of size @indir_size followed by hash key of size @key_size. + * + * For %ETHTOOL_GRSSH, a @indir_size and key_size of zero means that only the + * size should be returned. For %ETHTOOL_SRSSH, a @indir_size of 0xDEADBEEF + * means that indir table setting is not requested and a @indir_size of zero + * means the indir table should be reset to default values. This last feature + * is not supported by the original implementations. + */ +struct ethtool_rxfh { + __u32 cmd; + __u32 rss_context; + __u32 indir_size; + __u32 key_size; + __u32 rsvd[2]; + __u32 rss_config[0]; +}; + /** * struct ethtool_rx_ntuple_flow_spec - specification for RX flow filter * @flow_type: Type of match to perform, e.g. %TCP_V4_FLOW @@ -1118,6 +1147,9 @@ enum ethtool_sfeatures_retval_bits { #define ETHTOOL_GEEE 0x00000044 /* Get EEE settings */ #define ETHTOOL_SEEE 0x00000045 /* Set EEE settings */ +#define ETHTOOL_GRSSH 0x00000046 /* Get RX flow hash configuration */ +#define ETHTOOL_SRSSH 0x00000047 /* Set RX flow hash configuration */ + /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET #define SPARC_ETH_SSET ETHTOOL_SSET diff --git a/include/uapi/linux/filter.h b/include/uapi/linux/filter.h index 8eb9ccaa5b4812..253b4d42cf2bb3 100644 --- a/include/uapi/linux/filter.h +++ b/include/uapi/linux/filter.h @@ -130,7 +130,8 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */ #define SKF_AD_VLAN_TAG 44 #define SKF_AD_VLAN_TAG_PRESENT 48 #define SKF_AD_PAY_OFFSET 52 -#define SKF_AD_MAX 56 +#define SKF_AD_RANDOM 56 +#define SKF_AD_MAX 60 #define SKF_NET_OFF (-0x100000) #define SKF_LL_OFF (-0x200000) diff --git a/include/uapi/linux/if_fddi.h b/include/uapi/linux/if_fddi.h index 0d36909c3aefa2..1086cd9f675473 100644 --- a/include/uapi/linux/if_fddi.h +++ b/include/uapi/linux/if_fddi.h @@ -30,74 +30,76 @@ * Define max and min legal sizes. The frame sizes do not include * 4 byte FCS/CRC (frame check sequence). */ -#define FDDI_K_ALEN 6 /* Octets in one FDDI address */ -#define FDDI_K_8022_HLEN 16 /* Total octets in 802.2 header */ -#define FDDI_K_SNAP_HLEN 21 /* Total octets in 802.2 SNAP header */ -#define FDDI_K_8022_ZLEN 16 /* Min octets in 802.2 frame sans FCS */ -#define FDDI_K_SNAP_ZLEN 21 /* Min octets in 802.2 SNAP frame sans FCS */ +#define FDDI_K_ALEN 6 /* Octets in one FDDI address */ +#define FDDI_K_8022_HLEN 16 /* Total octets in 802.2 header */ +#define FDDI_K_SNAP_HLEN 21 /* Total octets in 802.2 SNAP header */ +#define FDDI_K_8022_ZLEN 16 /* Min octets in 802.2 frame sans + FCS */ +#define FDDI_K_SNAP_ZLEN 21 /* Min octets in 802.2 SNAP frame sans + FCS */ #define FDDI_K_8022_DLEN 4475 /* Max octets in 802.2 payload */ #define FDDI_K_SNAP_DLEN 4470 /* Max octets in 802.2 SNAP payload */ -#define FDDI_K_LLC_ZLEN 13 /* Min octets in LLC frame sans FCS */ +#define FDDI_K_LLC_ZLEN 13 /* Min octets in LLC frame sans FCS */ #define FDDI_K_LLC_LEN 4491 /* Max octets in LLC frame sans FCS */ +#define FDDI_K_OUI_LEN 3 /* Octets in OUI in 802.2 SNAP + header */ /* Define FDDI Frame Control (FC) Byte values */ -#define FDDI_FC_K_VOID 0x00 -#define FDDI_FC_K_NON_RESTRICTED_TOKEN 0x80 -#define FDDI_FC_K_RESTRICTED_TOKEN 0xC0 -#define FDDI_FC_K_SMT_MIN 0x41 -#define FDDI_FC_K_SMT_MAX 0x4F -#define FDDI_FC_K_MAC_MIN 0xC1 -#define FDDI_FC_K_MAC_MAX 0xCF -#define FDDI_FC_K_ASYNC_LLC_MIN 0x50 -#define FDDI_FC_K_ASYNC_LLC_DEF 0x54 -#define FDDI_FC_K_ASYNC_LLC_MAX 0x5F -#define FDDI_FC_K_SYNC_LLC_MIN 0xD0 -#define FDDI_FC_K_SYNC_LLC_MAX 0xD7 -#define FDDI_FC_K_IMPLEMENTOR_MIN 0x60 -#define FDDI_FC_K_IMPLEMENTOR_MAX 0x6F -#define FDDI_FC_K_RESERVED_MIN 0x70 -#define FDDI_FC_K_RESERVED_MAX 0x7F +#define FDDI_FC_K_VOID 0x00 +#define FDDI_FC_K_NON_RESTRICTED_TOKEN 0x80 +#define FDDI_FC_K_RESTRICTED_TOKEN 0xC0 +#define FDDI_FC_K_SMT_MIN 0x41 +#define FDDI_FC_K_SMT_MAX 0x4F +#define FDDI_FC_K_MAC_MIN 0xC1 +#define FDDI_FC_K_MAC_MAX 0xCF +#define FDDI_FC_K_ASYNC_LLC_MIN 0x50 +#define FDDI_FC_K_ASYNC_LLC_DEF 0x54 +#define FDDI_FC_K_ASYNC_LLC_MAX 0x5F +#define FDDI_FC_K_SYNC_LLC_MIN 0xD0 +#define FDDI_FC_K_SYNC_LLC_MAX 0xD7 +#define FDDI_FC_K_IMPLEMENTOR_MIN 0x60 +#define FDDI_FC_K_IMPLEMENTOR_MAX 0x6F +#define FDDI_FC_K_RESERVED_MIN 0x70 +#define FDDI_FC_K_RESERVED_MAX 0x7F /* Define LLC and SNAP constants */ -#define FDDI_EXTENDED_SAP 0xAA +#define FDDI_EXTENDED_SAP 0xAA #define FDDI_UI_CMD 0x03 /* Define 802.2 Type 1 header */ struct fddi_8022_1_hdr { - __u8 dsap; /* destination service access point */ - __u8 ssap; /* source service access point */ - __u8 ctrl; /* control byte #1 */ + __u8 dsap; /* destination service access point */ + __u8 ssap; /* source service access point */ + __u8 ctrl; /* control byte #1 */ } __attribute__((packed)); /* Define 802.2 Type 2 header */ struct fddi_8022_2_hdr { - __u8 dsap; /* destination service access point */ - __u8 ssap; /* source service access point */ - __u8 ctrl_1; /* control byte #1 */ - __u8 ctrl_2; /* control byte #2 */ + __u8 dsap; /* destination service access point */ + __u8 ssap; /* source service access point */ + __u8 ctrl_1; /* control byte #1 */ + __u8 ctrl_2; /* control byte #2 */ } __attribute__((packed)); /* Define 802.2 SNAP header */ -#define FDDI_K_OUI_LEN 3 struct fddi_snap_hdr { - __u8 dsap; /* always 0xAA */ - __u8 ssap; /* always 0xAA */ - __u8 ctrl; /* always 0x03 */ + __u8 dsap; /* always 0xAA */ + __u8 ssap; /* always 0xAA */ + __u8 ctrl; /* always 0x03 */ __u8 oui[FDDI_K_OUI_LEN]; /* organizational universal id */ - __be16 ethertype; /* packet type ID field */ + __be16 ethertype; /* packet type ID field */ } __attribute__((packed)); /* Define FDDI LLC frame header */ struct fddihdr { - __u8 fc; /* frame control */ - __u8 daddr[FDDI_K_ALEN]; /* destination address */ - __u8 saddr[FDDI_K_ALEN]; /* source address */ - union - { - struct fddi_8022_1_hdr llc_8022_1; - struct fddi_8022_2_hdr llc_8022_2; - struct fddi_snap_hdr llc_snap; - } hdr; + __u8 fc; /* frame control */ + __u8 daddr[FDDI_K_ALEN]; /* destination address */ + __u8 saddr[FDDI_K_ALEN]; /* source address */ + union { + struct fddi_8022_1_hdr llc_8022_1; + struct fddi_8022_2_hdr llc_8022_2; + struct fddi_snap_hdr llc_snap; + } hdr; } __attribute__((packed)); diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index f4849525519c7a..19df18c9b8be37 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -462,7 +462,10 @@ struct input_keymap_entry { #define KEY_VIDEO_NEXT 241 /* drive next video source */ #define KEY_VIDEO_PREV 242 /* drive previous video source */ #define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */ -#define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */ +#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual + brightness control is off, + rely on ambient */ +#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO #define KEY_DISPLAY_OFF 245 /* display device to off state */ #define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */ @@ -632,6 +635,7 @@ struct input_keymap_entry { #define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ #define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ #define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ +#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE #define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ #define KEY_LOGOFF 0x1b1 /* AL Logoff */ @@ -723,6 +727,17 @@ struct input_keymap_entry { #define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ +#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */ +#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */ +#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */ +#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */ +#define KEY_APPSELECT 0x244 /* AL Select Task/Application */ +#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */ +#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */ + +#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ +#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ + #define BTN_TRIGGER_HAPPY 0x2c0 #define BTN_TRIGGER_HAPPY1 0x2c0 #define BTN_TRIGGER_HAPPY2 0x2c1 diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index a8f4ee5d2e8242..16cb1a14993bd7 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -171,6 +171,7 @@ struct kvm_pit_config { #define KVM_EXIT_WATCHDOG 21 #define KVM_EXIT_S390_TSCH 22 #define KVM_EXIT_EPR 23 +#define KVM_EXIT_SYSTEM_EVENT 24 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -301,6 +302,13 @@ struct kvm_run { struct { __u32 epr; } epr; + /* KVM_EXIT_SYSTEM_EVENT */ + struct { +#define KVM_SYSTEM_EVENT_SHUTDOWN 1 +#define KVM_SYSTEM_EVENT_RESET 2 + __u32 type; + __u64 flags; + } system_event; /* Fix the size of the union. */ char padding[256]; }; @@ -515,6 +523,7 @@ enum { kvm_ioeventfd_flag_nr_pio, kvm_ioeventfd_flag_nr_deassign, kvm_ioeventfd_flag_nr_virtio_ccw_notify, + kvm_ioeventfd_flag_nr_fast_mmio, kvm_ioeventfd_flag_nr_max, }; @@ -529,7 +538,7 @@ enum { struct kvm_ioeventfd { __u64 datamatch; __u64 addr; /* legal pio/mmio address */ - __u32 len; /* 1, 2, 4, or 8 bytes */ + __u32 len; /* 1, 2, 4, or 8 bytes; or 0 to ignore length */ __s32 fd; __u32 flags; __u8 pad[36]; @@ -743,6 +752,9 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_IOAPIC_POLARITY_IGNORED 97 #define KVM_CAP_ENABLE_CAP_VM 98 #define KVM_CAP_S390_IRQCHIP 99 +#define KVM_CAP_IOEVENTFD_NO_LENGTH 100 +#define KVM_CAP_VM_ATTRIBUTES 101 +#define KVM_CAP_ARM_PSCI_0_2 102 #ifdef KVM_CAP_IRQ_ROUTING diff --git a/include/uapi/linux/nfsd/nfsfh.h b/include/uapi/linux/nfsd/nfsfh.h index 616e3b39647683..20391235d08891 100644 --- a/include/uapi/linux/nfsd/nfsfh.h +++ b/include/uapi/linux/nfsd/nfsfh.h @@ -1,13 +1,7 @@ /* - * include/linux/nfsd/nfsfh.h - * * This file describes the layout of the file handles as passed * over the wire. * - * Earlier versions of knfsd used to sign file handles using keyed MD5 - * or SHA. I've removed this code, because it doesn't give you more - * security than blocking external access to port 2049 on your firewall. - * * Copyright (C) 1995, 1996, 1997 Olaf Kirch */ @@ -37,7 +31,7 @@ struct nfs_fhbase_old { }; /* - * This is the new flexible, extensible style NFSv2/v3 file handle. + * This is the new flexible, extensible style NFSv2/v3/v4 file handle. * by Neil Brown - March 2000 * * The file handle starts with a sequence of four-byte words. @@ -47,14 +41,7 @@ struct nfs_fhbase_old { * * All four-byte values are in host-byte-order. * - * The auth_type field specifies how the filehandle can be authenticated - * This might allow a file to be confirmed to be in a writable part of a - * filetree without checking the path from it up to the root. - * Current values: - * 0 - No authentication. fb_auth is 0 bytes long - * Possible future values: - * 1 - 4 bytes taken from MD5 hash of the remainer of the file handle - * prefixed by a secret and with the important export flags. + * The auth_type field is deprecated and must be set to 0. * * The fsid_type identifies how the filesystem (or export point) is * encoded. @@ -71,14 +58,9 @@ struct nfs_fhbase_old { * 7 - 8 byte inode number and 16 byte uuid * * The fileid_type identified how the file within the filesystem is encoded. - * This is (will be) passed to, and set by, the underlying filesystem if it supports - * filehandle operations. The filesystem must not use the value '0' or '0xff' and may - * only use the values 1 and 2 as defined below: - * Current values: - * 0 - The root, or export point, of the filesystem. fb_fileid is 0 bytes. - * 1 - 32bit inode number, 32 bit generation number. - * 2 - 32bit inode number, 32 bit generation number, 32 bit parent directory inode number. - * + * The values for this field are filesystem specific, exccept that + * filesystems must not use the values '0' or '0xff'. 'See enum fid_type' + * in include/linux/exportfs.h for currently registered values. */ struct nfs_fhbase_new { __u8 fb_version; /* == 1, even => nfs_fhbase_old */ @@ -114,9 +96,9 @@ struct knfsd_fh { #define fh_fsid_type fh_base.fh_new.fb_fsid_type #define fh_auth_type fh_base.fh_new.fb_auth_type #define fh_fileid_type fh_base.fh_new.fb_fileid_type -#define fh_auth fh_base.fh_new.fb_auth #define fh_fsid fh_base.fh_new.fb_auth - +/* Do not use, provided for userspace compatiblity. */ +#define fh_auth fh_base.fh_new.fb_auth #endif /* _UAPI_LINUX_NFSD_FH_H */ diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 1ba9d626aa833d..406010d4def049 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1579,6 +1579,10 @@ enum nl80211_commands { * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32. * As specified in the &enum nl80211_tdls_peer_capability. * + * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface + * creation then the new interface will be owned by the netlink socket + * that created it and will be destroyed when the socket is closed + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1914,6 +1918,8 @@ enum nl80211_attrs { NL80211_ATTR_TDLS_PEER_CAPABILITY, + NL80211_ATTR_IFACE_SOCKET_OWNER, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2336,9 +2342,34 @@ enum nl80211_band_attr { * using this channel as the primary or any of the secondary channels * isn't possible * @NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds. + * @NL80211_FREQUENCY_ATTR_INDOOR_ONLY: Only indoor use is permitted on this + * channel. A channel that has the INDOOR_ONLY attribute can only be + * used when there is a clear assessment that the device is operating in + * an indoor surroundings, i.e., it is connected to AC power (and not + * through portable DC inverters) or is under the control of a master + * that is acting as an AP and is connected to AC power. + * @NL80211_FREQUENCY_ATTR_GO_CONCURRENT: GO operation is allowed on this + * channel if it's connected concurrently to a BSS on the same channel on + * the 2 GHz band or to a channel in the same UNII band (on the 5 GHz + * band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO on a + * channel that has the GO_CONCURRENT attribute set can be done when there + * is a clear assessment that the device is operating under the guidance of + * an authorized master, i.e., setting up a GO while the device is also + * connected to an AP with DFS and radar detection on the UNII band (it is + * up to user-space, i.e., wpa_supplicant to perform the required + * verifications) + * @NL80211_FREQUENCY_ATTR_NO_20MHZ: 20 MHz operation is not allowed + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed + * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number * currently defined * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use + * + * See https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn=528122 + * for more information on the FCC description of the relaxations allowed + * by NL80211_FREQUENCY_ATTR_INDOOR_ONLY and + * NL80211_FREQUENCY_ATTR_GO_CONCURRENT. */ enum nl80211_frequency_attr { __NL80211_FREQUENCY_ATTR_INVALID, @@ -2355,6 +2386,10 @@ enum nl80211_frequency_attr { NL80211_FREQUENCY_ATTR_NO_80MHZ, NL80211_FREQUENCY_ATTR_NO_160MHZ, NL80211_FREQUENCY_ATTR_DFS_CAC_TIME, + NL80211_FREQUENCY_ATTR_INDOOR_ONLY, + NL80211_FREQUENCY_ATTR_GO_CONCURRENT, + NL80211_FREQUENCY_ATTR_NO_20MHZ, + NL80211_FREQUENCY_ATTR_NO_10MHZ, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, @@ -2573,10 +2608,13 @@ enum nl80211_dfs_regions { * present has been registered with the wireless core that * has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a * supported feature. + * @NL80211_USER_REG_HINT_INDOOR: a user sent an hint indicating that the + * platform is operating in an indoor environment. */ enum nl80211_user_reg_hint_type { NL80211_USER_REG_HINT_USER = 0, NL80211_USER_REG_HINT_CELL_BASE = 1, + NL80211_USER_REG_HINT_INDOOR = 2, }; /** @@ -3891,6 +3929,9 @@ enum nl80211_ap_sme_features { * interface. An active monitor interface behaves like a normal monitor * interface, but gets added to the driver. It ensures that incoming * unicast packets directed at the configured interface address get ACKed. + * @NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE: This driver supports dynamic + * channel bandwidth change (e.g., HT 20 <-> 40 MHz channel) during the + * lifetime of a BSS. */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, @@ -3911,6 +3952,7 @@ enum nl80211_feature_flags { NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15, NL80211_FEATURE_USERSPACE_MPM = 1 << 16, NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17, + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE = 1 << 18, }; /** diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h new file mode 100644 index 00000000000000..310d83e0a91b6b --- /dev/null +++ b/include/uapi/linux/psci.h @@ -0,0 +1,90 @@ +/* + * ARM Power State and Coordination Interface (PSCI) header + * + * This header holds common PSCI defines and macros shared + * by: ARM kernel, ARM64 kernel, KVM ARM/ARM64 and user space. + * + * Copyright (C) 2014 Linaro Ltd. + * Author: Anup Patel + */ + +#ifndef _UAPI_LINUX_PSCI_H +#define _UAPI_LINUX_PSCI_H + +/* + * PSCI v0.1 interface + * + * The PSCI v0.1 function numbers are implementation defined. + * + * Only PSCI return values such as: SUCCESS, NOT_SUPPORTED, + * INVALID_PARAMS, and DENIED defined below are applicable + * to PSCI v0.1. + */ + +/* PSCI v0.2 interface */ +#define PSCI_0_2_FN_BASE 0x84000000 +#define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n)) +#define PSCI_0_2_64BIT 0x40000000 +#define PSCI_0_2_FN64_BASE \ + (PSCI_0_2_FN_BASE + PSCI_0_2_64BIT) +#define PSCI_0_2_FN64(n) (PSCI_0_2_FN64_BASE + (n)) + +#define PSCI_0_2_FN_PSCI_VERSION PSCI_0_2_FN(0) +#define PSCI_0_2_FN_CPU_SUSPEND PSCI_0_2_FN(1) +#define PSCI_0_2_FN_CPU_OFF PSCI_0_2_FN(2) +#define PSCI_0_2_FN_CPU_ON PSCI_0_2_FN(3) +#define PSCI_0_2_FN_AFFINITY_INFO PSCI_0_2_FN(4) +#define PSCI_0_2_FN_MIGRATE PSCI_0_2_FN(5) +#define PSCI_0_2_FN_MIGRATE_INFO_TYPE PSCI_0_2_FN(6) +#define PSCI_0_2_FN_MIGRATE_INFO_UP_CPU PSCI_0_2_FN(7) +#define PSCI_0_2_FN_SYSTEM_OFF PSCI_0_2_FN(8) +#define PSCI_0_2_FN_SYSTEM_RESET PSCI_0_2_FN(9) + +#define PSCI_0_2_FN64_CPU_SUSPEND PSCI_0_2_FN64(1) +#define PSCI_0_2_FN64_CPU_ON PSCI_0_2_FN64(3) +#define PSCI_0_2_FN64_AFFINITY_INFO PSCI_0_2_FN64(4) +#define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5) +#define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7) + +/* PSCI v0.2 power state encoding for CPU_SUSPEND function */ +#define PSCI_0_2_POWER_STATE_ID_MASK 0xffff +#define PSCI_0_2_POWER_STATE_ID_SHIFT 0 +#define PSCI_0_2_POWER_STATE_TYPE_SHIFT 16 +#define PSCI_0_2_POWER_STATE_TYPE_MASK \ + (0x1 << PSCI_0_2_POWER_STATE_TYPE_SHIFT) +#define PSCI_0_2_POWER_STATE_AFFL_SHIFT 24 +#define PSCI_0_2_POWER_STATE_AFFL_MASK \ + (0x3 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) + +/* PSCI v0.2 affinity level state returned by AFFINITY_INFO */ +#define PSCI_0_2_AFFINITY_LEVEL_ON 0 +#define PSCI_0_2_AFFINITY_LEVEL_OFF 1 +#define PSCI_0_2_AFFINITY_LEVEL_ON_PENDING 2 + +/* PSCI v0.2 multicore support in Trusted OS returned by MIGRATE_INFO_TYPE */ +#define PSCI_0_2_TOS_UP_MIGRATE 0 +#define PSCI_0_2_TOS_UP_NO_MIGRATE 1 +#define PSCI_0_2_TOS_MP 2 + +/* PSCI version decoding (independent of PSCI version) */ +#define PSCI_VERSION_MAJOR_SHIFT 16 +#define PSCI_VERSION_MINOR_MASK \ + ((1U << PSCI_VERSION_MAJOR_SHIFT) - 1) +#define PSCI_VERSION_MAJOR_MASK ~PSCI_VERSION_MINOR_MASK +#define PSCI_VERSION_MAJOR(ver) \ + (((ver) & PSCI_VERSION_MAJOR_MASK) >> PSCI_VERSION_MAJOR_SHIFT) +#define PSCI_VERSION_MINOR(ver) \ + ((ver) & PSCI_VERSION_MINOR_MASK) + +/* PSCI return values (inclusive of all PSCI versions) */ +#define PSCI_RET_SUCCESS 0 +#define PSCI_RET_NOT_SUPPORTED -1 +#define PSCI_RET_INVALID_PARAMS -2 +#define PSCI_RET_DENIED -3 +#define PSCI_RET_ALREADY_ON -4 +#define PSCI_RET_ON_PENDING -5 +#define PSCI_RET_INTERNAL_FAILURE -6 +#define PSCI_RET_NOT_PRESENT -7 +#define PSCI_RET_DISABLED -8 + +#endif /* _UAPI_LINUX_PSCI_H */ diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index b47dba2c1e6f7a..5820269aa1322a 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -211,7 +211,7 @@ /* VIA VT8500 SoC */ #define PORT_VT8500 97 -/* Xilinx PSS UART */ +/* Cadence (Xilinx Zynq) UART */ #define PORT_XUARTPS 98 /* Atheros AR933X SoC */ @@ -238,4 +238,10 @@ /* Tilera TILE-Gx UART */ #define PORT_TILEGX 106 +/* MEN 16z135 UART */ +#define PORT_MEN_Z135 107 + +/* SC16IS74xx */ +#define PORT_SC16IS7XX 108 + #endif /* _UAPILINUX_SERIAL_CORE_H */ diff --git a/include/uapi/linux/serial_reg.h b/include/uapi/linux/serial_reg.h index e6322605b1380e..99b47058816a88 100644 --- a/include/uapi/linux/serial_reg.h +++ b/include/uapi/linux/serial_reg.h @@ -32,7 +32,7 @@ #define UART_IIR 2 /* In: Interrupt ID Register */ #define UART_IIR_NO_INT 0x01 /* No interrupts pending */ -#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ +#define UART_IIR_ID 0x0e /* Mask for the interrupt ID */ #define UART_IIR_MSI 0x00 /* Modem status interrupt */ #define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ #define UART_IIR_RDI 0x04 /* Receiver data interrupt */ diff --git a/include/uapi/linux/tipc.h b/include/uapi/linux/tipc.h index 852373d27dbb2b..6f71b9b4159581 100644 --- a/include/uapi/linux/tipc.h +++ b/include/uapi/linux/tipc.h @@ -38,6 +38,7 @@ #define _LINUX_TIPC_H_ #include +#include /* * TIPC addressing primitives @@ -87,6 +88,7 @@ static inline unsigned int tipc_node(__u32 addr) #define TIPC_CFG_SRV 0 /* configuration service name type */ #define TIPC_TOP_SRV 1 /* topology service name type */ +#define TIPC_LINK_STATE 2 /* link state name type */ #define TIPC_RESERVED_TYPES 64 /* lowest user-publishable name type */ /* @@ -206,4 +208,25 @@ struct sockaddr_tipc { #define TIPC_NODE_RECVQ_DEPTH 131 /* Default: none (read only) */ #define TIPC_SOCK_RECVQ_DEPTH 132 /* Default: none (read only) */ +/* + * Maximum sizes of TIPC bearer-related names (including terminating NULL) + * The string formatting for each name element is: + * media: media + * interface: media:interface name + * link: Z.C.N:interface-Z.C.N:interface + * + */ + +#define TIPC_MAX_MEDIA_NAME 16 +#define TIPC_MAX_IF_NAME 16 +#define TIPC_MAX_BEARER_NAME 32 +#define TIPC_MAX_LINK_NAME 60 + +#define SIOCGETLINKNAME SIOCPROTOPRIVATE + +struct tipc_sioc_ln_req { + __u32 peer; + __u32 bearer_id; + char linkname[TIPC_MAX_LINK_NAME]; +}; #endif diff --git a/include/uapi/linux/tipc_config.h b/include/uapi/linux/tipc_config.h index 6b0bff09b3a7ce..41a76acbb305f8 100644 --- a/include/uapi/linux/tipc_config.h +++ b/include/uapi/linux/tipc_config.h @@ -39,6 +39,7 @@ #include #include +#include #include #ifndef __KERNEL__ @@ -154,15 +155,6 @@ #define TIPC_TLV_NAME_TBL_QUERY 25 /* struct tipc_name_table_query */ #define TIPC_TLV_PORT_REF 26 /* 32-bit port reference */ -/* - * Maximum sizes of TIPC bearer-related names (including terminating NUL) - */ - -#define TIPC_MAX_MEDIA_NAME 16 /* format = media */ -#define TIPC_MAX_IF_NAME 16 /* format = interface */ -#define TIPC_MAX_BEARER_NAME 32 /* format = media:interface */ -#define TIPC_MAX_LINK_NAME 60 /* format = Z.C.N:interface-Z.C.N:interface */ - /* * Link priority limits (min, default, max, media default) */ diff --git a/include/video/omapdss.h b/include/video/omapdss.h index 6adb445346064e..ded61a9e521944 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -388,8 +388,8 @@ struct omap_dss_cpr_coefs { }; struct omap_overlay_info { - u32 paddr; - u32 p_uv_addr; /* for NV12 format */ + dma_addr_t paddr; + dma_addr_t p_uv_addr; /* for NV12 format */ u16 screen_width; u16 width; u16 height; diff --git a/init/Kconfig b/init/Kconfig index f77e13bea4f962..66aa1802449d5b 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1254,6 +1254,77 @@ config CC_OPTIMIZE_FOR_SIZE If unsure, say N. +config LTO_MENU + bool "Enable gcc link time optimization (LTO)" + # Only tested on X86 for now. For other architectures you likely + # have to fix some things first, like adding asmlinkages etc. + depends on X86 + # lto does not support excluding flags for specific files + # right now. Can be removed if that is fixed. + depends on !FUNCTION_TRACER + help + With this option gcc will do whole program optimizations for + the whole kernel and module. This increases compile time, but can + lead to better code. It allows gcc to inline functions between + different files and do other optimization. It might also trigger + bugs due to more aggressive optimization. It allows gcc to drop unused + code. On smaller monolithic kernel configurations + it usually leads to smaller kernels, especially when modules + are disabled. + + With this option gcc will also do some global checking over + different source files. It also disables a number of kernel + features. + + This option is recommended for release builds. With LTO + the kernel always has to be re-optimized (but not re-parsed) + on each build. + + This requires a gcc 4.8 or later compiler and + Linux binutils 2.21.51.0.3 or later. gcc 4.9 builds significantly + faster than 4.8 It does not currently work with a FSF release of + binutils or with the gold linker. + + On larger configurations this may need more than 4GB of RAM. + It will likely not work on those with a 32bit compiler. + + When the toolchain support is not available this will (hopefully) + be automatically disabled. + + For more information see Documentation/lto-build + +config LTO_DISABLE + bool "Disable LTO again" + depends on LTO_MENU + default n + help + This option is merely here so that allyesconfig or allmodconfig do + not enable LTO. If you want to actually use LTO do not enable. + +config LTO + bool + default y + depends on LTO_MENU && !LTO_DISABLE + +config LTO_DEBUG + bool "Enable LTO compile time debugging" + depends on LTO + help + Enable LTO debugging in the compiler. The compiler dumps + some log files that make it easier to figure out LTO + behavior. The log files also allow to reconstruct + the global inlining and a global callgraph. + They however add some (single threaded) cost to the + compilation. When in doubt do not enable. + +config LTO_CP_CLONE + bool "Allow aggressive cloning for function specialization" + depends on LTO + help + Allow the compiler to clone and specialize functions for specific + arguments when it determines these arguments are very commonly + called. Experimential. Will increase text size. + config SYSCTL bool @@ -1753,6 +1824,8 @@ config MODULE_FORCE_UNLOAD config MODVERSIONS bool "Module versioning support" + # LTO should work with gcc 4.9 + depends on !LTO help Usually, you have to use modules compiled with your kernel. Saying Y here makes it sometimes possible to use modules diff --git a/init/main.c b/init/main.c index df49549a0c14c2..855c601fbc7064 100644 --- a/init/main.c +++ b/init/main.c @@ -253,6 +253,27 @@ static int __init repair_env_string(char *param, char *val, const char *unused) return 0; } +/* Anything after -- gets handed straight to init. */ +static int __init set_init_arg(char *param, char *val, const char *unused) +{ + unsigned int i; + + if (panic_later) + return 0; + + repair_env_string(param, val, unused); + + for (i = 0; argv_init[i]; i++) { + if (i == MAX_INIT_ARGS) { + panic_later = "init"; + panic_param = param; + return 0; + } + } + argv_init[i] = param; + return 0; +} + /* * Unknown boot options get handed to init, unless they look like * unused parameters (modprobe will find them in /proc/cmdline). @@ -477,9 +498,9 @@ static void __init mm_init(void) vmalloc_init(); } -asmlinkage void __init start_kernel(void) +asmlinkage __visible void __init start_kernel(void) { - char * command_line; + char * command_line, *after_dashes; extern const struct kernel_param __start___param[], __stop___param[]; /* @@ -519,9 +540,13 @@ asmlinkage void __init start_kernel(void) pr_notice("Kernel command line: %s\n", boot_command_line); parse_early_param(); - parse_args("Booting kernel", static_command_line, __start___param, - __stop___param - __start___param, - -1, -1, &unknown_bootoption); + after_dashes = parse_args("Booting kernel", + static_command_line, __start___param, + __stop___param - __start___param, + -1, -1, &unknown_bootoption); + if (after_dashes) + parse_args("Setting init args", after_dashes, NULL, 0, -1, -1, + set_init_arg); jump_label_init(); @@ -616,6 +641,10 @@ asmlinkage void __init start_kernel(void) #ifdef CONFIG_X86 if (efi_enabled(EFI_RUNTIME_SERVICES)) efi_enter_virtual_mode(); +#endif +#ifdef CONFIG_X86_ESPFIX64 + /* Should be run before the first non-init thread is created */ + init_espfix_bsp(); #endif thread_info_cache_init(); cred_init(); diff --git a/kernel/acct.c b/kernel/acct.c index 808a86ff229d70..d17810f056cfee 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -93,6 +93,7 @@ struct bsd_acct_struct { static DEFINE_SPINLOCK(acct_lock); static LIST_HEAD(acct_list); +static LIST_HEAD(acct_close_list); /* * Check the amount of free space and suspend/resume accordingly. @@ -280,6 +281,20 @@ SYSCALL_DEFINE1(acct, const char __user *, name) return error; } +static void acct_close_mnts(struct work_struct *unused) +{ + struct bsd_acct_struct *acct; + + spin_lock(&acct_lock); +restart: + list_for_each_entry(acct, &acct_close_list, list) { + acct_file_reopen(acct, NULL, NULL); + goto restart; + } + spin_unlock(&acct_lock); +} +static DECLARE_WORK(acct_close_work, acct_close_mnts); + /** * acct_auto_close - turn off a filesystem's accounting if it is on * @m: vfsmount being shut down @@ -289,15 +304,15 @@ SYSCALL_DEFINE1(acct, const char __user *, name) */ void acct_auto_close_mnt(struct vfsmount *m) { - struct bsd_acct_struct *acct; + struct bsd_acct_struct *acct, *tmp; spin_lock(&acct_lock); -restart: - list_for_each_entry(acct, &acct_list, list) + list_for_each_entry_safe(acct, tmp, &acct_list, list) { if (acct->file && acct->file->f_path.mnt == m) { - acct_file_reopen(acct, NULL, NULL); - goto restart; + list_move_tail(&acct->list, &acct_close_list); + schedule_work(&acct_close_work); } + } spin_unlock(&acct_lock); } diff --git a/kernel/audit.c b/kernel/audit.c index f30106459a3243..3ef2e0e797e8e5 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -423,6 +423,38 @@ static void kauditd_send_skb(struct sk_buff *skb) consume_skb(skb); } +/* + * kauditd_send_multicast_skb - send the skb to multicast userspace listeners + * + * This function doesn't consume an skb as might be expected since it has to + * copy it anyways. + */ +static void kauditd_send_multicast_skb(struct sk_buff *skb) +{ + struct sk_buff *copy; + struct audit_net *aunet = net_generic(&init_net, audit_net_id); + struct sock *sock = aunet->nlsk; + + if (!netlink_has_listeners(sock, AUDIT_NLGRP_READLOG)) + return; + + /* + * The seemingly wasteful skb_copy() rather than bumping the refcount + * using skb_get() is necessary because non-standard mods are made to + * the skb by the original kaudit unicast socket send routine. The + * existing auditd daemon assumes this breakage. Fixing this would + * require co-ordinating a change in the established protocol between + * the kaudit kernel subsystem and the auditd userspace code. There is + * no reason for new multicast clients to continue with this + * non-compliance. + */ + copy = skb_copy(skb, GFP_KERNEL); + if (!copy) + return; + + nlmsg_multicast(sock, copy, 0, AUDIT_NLGRP_READLOG, GFP_KERNEL); +} + /* * flush_hold_queue - empty the hold queue if auditd appears * @@ -1076,10 +1108,22 @@ static void audit_receive(struct sk_buff *skb) mutex_unlock(&audit_cmd_mutex); } +/* Run custom bind function on netlink socket group connect or bind requests. */ +static int audit_bind(int group) +{ + if (!capable(CAP_AUDIT_READ)) + return -EPERM; + + return 0; +} + static int __net_init audit_net_init(struct net *net) { struct netlink_kernel_cfg cfg = { .input = audit_receive, + .bind = audit_bind, + .flags = NL_CFG_F_NONROOT_RECV, + .groups = AUDIT_NLGRP_MAX, }; struct audit_net *aunet = net_generic(net, audit_net_id); @@ -1901,10 +1945,10 @@ void audit_log_link_denied(const char *operation, struct path *link) * audit_log_end - end one audit record * @ab: the audit_buffer * - * The netlink_* functions cannot be called inside an irq context, so - * the audit buffer is placed on a queue and a tasklet is scheduled to - * remove them from the queue outside the irq context. May be called in - * any context. + * netlink_unicast() cannot be called inside an irq context because it blocks + * (last arg, flags, is not set to MSG_DONTWAIT), so the audit buffer is placed + * on a queue and a tasklet is scheduled to remove them from the queue outside + * the irq context. May be called in any context. */ void audit_log_end(struct audit_buffer *ab) { @@ -1914,6 +1958,18 @@ void audit_log_end(struct audit_buffer *ab) audit_log_lost("rate limit exceeded"); } else { struct nlmsghdr *nlh = nlmsg_hdr(ab->skb); + + kauditd_send_multicast_skb(ab->skb); + + /* + * The original kaudit unicast socket sends up messages with + * nlmsg_len set to the payload length rather than the entire + * message length. This breaks the standard set by netlink. + * The existing auditd daemon assumes this breakage. Fixing + * this would require co-ordinating a change in the established + * protocol between the kaudit kernel subsystem and the auditd + * userspace code. + */ nlh->nlmsg_len = ab->skb->len - NLMSG_HDRLEN; if (audit_pid) { diff --git a/kernel/auditsc.c b/kernel/auditsc.c index f251a5e8d17ad2..b12a712f38cbb2 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -67,6 +67,7 @@ #include #include #include +#include #include #include #include @@ -1496,7 +1497,6 @@ void __audit_free(struct task_struct *tsk) /** * audit_syscall_entry - fill in an audit record at syscall entry - * @arch: architecture type * @major: major syscall type (function) * @a1: additional syscall register 1 * @a2: additional syscall register 2 @@ -1511,9 +1511,8 @@ void __audit_free(struct task_struct *tsk) * will only be written if another part of the kernel requests that it * be written). */ -void __audit_syscall_entry(int arch, int major, - unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4) +void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2, + unsigned long a3, unsigned long a4) { struct task_struct *tsk = current; struct audit_context *context = tsk->audit_context; @@ -1527,7 +1526,7 @@ void __audit_syscall_entry(int arch, int major, if (!audit_enabled) return; - context->arch = arch; + context->arch = syscall_get_arch(); context->major = major; context->argv[0] = a1; context->argv[1] = a2; @@ -2479,11 +2478,9 @@ void __audit_seccomp(unsigned long syscall, long signr, int code) if (unlikely(!ab)) return; audit_log_task(ab); - audit_log_format(ab, " sig=%ld", signr); - audit_log_format(ab, " syscall=%ld", syscall); - audit_log_format(ab, " compat=%d", is_compat_task()); - audit_log_format(ab, " ip=0x%lx", KSTK_EIP(current)); - audit_log_format(ab, " code=0x%x", code); + audit_log_format(ab, " sig=%ld arch=%x syscall=%ld compat=%d ip=0x%lx code=0x%x", + signr, syscall_get_arch(), syscall, is_compat_task(), + KSTK_EIP(current), code); audit_log_end(ab); } diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 9fcdaa705b6cb7..07815ef7b1f6eb 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -26,6 +26,8 @@ * distribution for more details. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -97,6 +99,12 @@ static DEFINE_MUTEX(cgroup_mutex); static DECLARE_RWSEM(css_set_rwsem); #endif +/* + * Protects cgroup_idr and css_idr so that IDs can be released without + * grabbing cgroup_mutex. + */ +static DEFINE_SPINLOCK(cgroup_idr_lock); + /* * Protects cgroup_subsys->release_agent_path. Modifying it also requires * cgroup_mutex. Reading requires either cgroup_mutex or this spinlock. @@ -179,13 +187,46 @@ static struct cftype cgroup_base_files[]; static void cgroup_put(struct cgroup *cgrp); static int rebind_subsystems(struct cgroup_root *dst_root, - unsigned long ss_mask); + unsigned int ss_mask); static void cgroup_destroy_css_killed(struct cgroup *cgrp); static int cgroup_destroy_locked(struct cgroup *cgrp); +static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss); +static void kill_css(struct cgroup_subsys_state *css); static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], bool is_add); static void cgroup_pidlist_destroy_all(struct cgroup *cgrp); +/* IDR wrappers which synchronize using cgroup_idr_lock */ +static int cgroup_idr_alloc(struct idr *idr, void *ptr, int start, int end, + gfp_t gfp_mask) +{ + int ret; + + idr_preload(gfp_mask); + spin_lock(&cgroup_idr_lock); + ret = idr_alloc(idr, ptr, start, end, gfp_mask); + spin_unlock(&cgroup_idr_lock); + idr_preload_end(); + return ret; +} + +static void *cgroup_idr_replace(struct idr *idr, void *ptr, int id) +{ + void *ret; + + spin_lock(&cgroup_idr_lock); + ret = idr_replace(idr, ptr, id); + spin_unlock(&cgroup_idr_lock); + return ret; +} + +static void cgroup_idr_remove(struct idr *idr, int id) +{ + spin_lock(&cgroup_idr_lock); + idr_remove(idr, id); + spin_unlock(&cgroup_idr_lock); +} + /** * cgroup_css - obtain a cgroup's css for the specified subsystem * @cgrp: the cgroup of interest @@ -208,6 +249,34 @@ static struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, return &cgrp->dummy_css; } +/** + * cgroup_e_css - obtain a cgroup's effective css for the specified subsystem + * @cgrp: the cgroup of interest + * @ss: the subsystem of interest (%NULL returns the dummy_css) + * + * Similar to cgroup_css() but returns the effctive css, which is defined + * as the matching css of the nearest ancestor including self which has @ss + * enabled. If @ss is associated with the hierarchy @cgrp is on, this + * function is guaranteed to return non-NULL css. + */ +static struct cgroup_subsys_state *cgroup_e_css(struct cgroup *cgrp, + struct cgroup_subsys *ss) +{ + lockdep_assert_held(&cgroup_mutex); + + if (!ss) + return &cgrp->dummy_css; + + if (!(cgrp->root->subsys_mask & (1 << ss->id))) + return NULL; + + while (cgrp->parent && + !(cgrp->parent->child_subsys_mask & (1 << ss->id))) + cgrp = cgrp->parent; + + return cgroup_css(cgrp, ss); +} + /* convenient tests for these bits */ static inline bool cgroup_is_dead(const struct cgroup *cgrp) { @@ -273,7 +342,7 @@ static int notify_on_release(const struct cgroup *cgrp) * @ssid: the index of the subsystem, CGROUP_SUBSYS_COUNT after reaching the end * @cgrp: the target cgroup to iterate css's of * - * Should be called under cgroup_mutex. + * Should be called under cgroup_[tree_]mutex. */ #define for_each_css(css, ssid, cgrp) \ for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ @@ -283,6 +352,20 @@ static int notify_on_release(const struct cgroup *cgrp) lockdep_is_held(&cgroup_mutex)))) { } \ else +/** + * for_each_e_css - iterate all effective css's of a cgroup + * @css: the iteration cursor + * @ssid: the index of the subsystem, CGROUP_SUBSYS_COUNT after reaching the end + * @cgrp: the target cgroup to iterate css's of + * + * Should be called under cgroup_[tree_]mutex. + */ +#define for_each_e_css(css, ssid, cgrp) \ + for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ + if (!((css) = cgroup_e_css(cgrp, cgroup_subsys[(ssid)]))) \ + ; \ + else + /** * for_each_subsys - iterate all enabled cgroup subsystems * @ss: the iteration cursor @@ -296,6 +379,14 @@ static int notify_on_release(const struct cgroup *cgrp) #define for_each_root(root) \ list_for_each_entry((root), &cgroup_roots, root_list) +/* iterate over child cgrps, lock should be held throughout iteration */ +#define cgroup_for_each_live_child(child, cgrp) \ + list_for_each_entry((child), &(cgrp)->children, sibling) \ + if (({ lockdep_assert_held(&cgroup_tree_mutex); \ + cgroup_is_dead(child); })) \ + ; \ + else + /** * cgroup_lock_live_group - take cgroup_mutex and check that cgrp is alive. * @cgrp: the cgroup to be checked for liveness @@ -359,6 +450,43 @@ static struct css_set init_css_set = { static int css_set_count = 1; /* 1 for init_css_set */ +/** + * cgroup_update_populated - updated populated count of a cgroup + * @cgrp: the target cgroup + * @populated: inc or dec populated count + * + * @cgrp is either getting the first task (css_set) or losing the last. + * Update @cgrp->populated_cnt accordingly. The count is propagated + * towards root so that a given cgroup's populated_cnt is zero iff the + * cgroup and all its descendants are empty. + * + * @cgrp's interface file "cgroup.populated" is zero if + * @cgrp->populated_cnt is zero and 1 otherwise. When @cgrp->populated_cnt + * changes from or to zero, userland is notified that the content of the + * interface file has changed. This can be used to detect when @cgrp and + * its descendants become populated or empty. + */ +static void cgroup_update_populated(struct cgroup *cgrp, bool populated) +{ + lockdep_assert_held(&css_set_rwsem); + + do { + bool trigger; + + if (populated) + trigger = !cgrp->populated_cnt++; + else + trigger = !--cgrp->populated_cnt; + + if (!trigger) + break; + + if (cgrp->populated_kn) + kernfs_notify(cgrp->populated_kn); + cgrp = cgrp->parent; + } while (cgrp); +} + /* * hash table for cgroup groups. This improves the performance to find * an existing css_set. This hash doesn't (currently) take into @@ -383,6 +511,8 @@ static unsigned long css_set_hash(struct cgroup_subsys_state *css[]) static void put_css_set_locked(struct css_set *cset, bool taskexit) { struct cgrp_cset_link *link, *tmp_link; + struct cgroup_subsys *ss; + int ssid; lockdep_assert_held(&css_set_rwsem); @@ -390,6 +520,8 @@ static void put_css_set_locked(struct css_set *cset, bool taskexit) return; /* This css_set is dead. unlink it and release cgroup refcounts */ + for_each_subsys(ss, ssid) + list_del(&cset->e_cset_node[ssid]); hash_del(&cset->hlist); css_set_count--; @@ -400,10 +532,13 @@ static void put_css_set_locked(struct css_set *cset, bool taskexit) list_del(&link->cgrp_link); /* @cgrp can't go away while we're holding css_set_rwsem */ - if (list_empty(&cgrp->cset_links) && notify_on_release(cgrp)) { - if (taskexit) - set_bit(CGRP_RELEASABLE, &cgrp->flags); - check_for_release(cgrp); + if (list_empty(&cgrp->cset_links)) { + cgroup_update_populated(cgrp, false); + if (notify_on_release(cgrp)) { + if (taskexit) + set_bit(CGRP_RELEASABLE, &cgrp->flags); + check_for_release(cgrp); + } } kfree(link); @@ -452,20 +587,20 @@ static bool compare_css_sets(struct css_set *cset, { struct list_head *l1, *l2; - if (memcmp(template, cset->subsys, sizeof(cset->subsys))) { - /* Not all subsystems matched */ + /* + * On the default hierarchy, there can be csets which are + * associated with the same set of cgroups but different csses. + * Let's first ensure that csses match. + */ + if (memcmp(template, cset->subsys, sizeof(cset->subsys))) return false; - } /* * Compare cgroup pointers in order to distinguish between - * different cgroups in heirarchies with no subsystems. We - * could get by with just this check alone (and skip the - * memcmp above) but on most setups the memcmp check will - * avoid the need for this more expensive check on almost all - * candidates. + * different cgroups in hierarchies. As different cgroups may + * share the same effective css, this comparison is always + * necessary. */ - l1 = &cset->cgrp_links; l2 = &old_cset->cgrp_links; while (1) { @@ -529,14 +664,17 @@ static struct css_set *find_existing_css_set(struct css_set *old_cset, * won't change, so no need for locking. */ for_each_subsys(ss, i) { - if (root->cgrp.subsys_mask & (1UL << i)) { - /* Subsystem is in this hierarchy. So we want - * the subsystem state from the new - * cgroup */ - template[i] = cgroup_css(cgrp, ss); + if (root->subsys_mask & (1UL << i)) { + /* + * @ss is in this hierarchy, so we want the + * effective css from @cgrp. + */ + template[i] = cgroup_e_css(cgrp, ss); } else { - /* Subsystem is not in this hierarchy, so we - * don't want to change the subsystem state */ + /* + * @ss is not in this hierarchy, so we don't want + * to change the css. + */ template[i] = old_cset->subsys[i]; } } @@ -602,10 +740,18 @@ static void link_css_set(struct list_head *tmp_links, struct css_set *cset, struct cgrp_cset_link *link; BUG_ON(list_empty(tmp_links)); + + if (cgroup_on_dfl(cgrp)) + cset->dfl_cgrp = cgrp; + link = list_first_entry(tmp_links, struct cgrp_cset_link, cset_link); link->cset = cset; link->cgrp = cgrp; + + if (list_empty(&cgrp->cset_links)) + cgroup_update_populated(cgrp, true); list_move(&link->cset_link, &cgrp->cset_links); + /* * Always add links to the tail of the list so that the list * is sorted by order of hierarchy creation @@ -628,7 +774,9 @@ static struct css_set *find_css_set(struct css_set *old_cset, struct css_set *cset; struct list_head tmp_links; struct cgrp_cset_link *link; + struct cgroup_subsys *ss; unsigned long key; + int ssid; lockdep_assert_held(&cgroup_mutex); @@ -679,10 +827,14 @@ static struct css_set *find_css_set(struct css_set *old_cset, css_set_count++; - /* Add this cgroup group to the hash table */ + /* Add @cset to the hash table */ key = css_set_hash(cset->subsys); hash_add(css_set_table, &cset->hlist, key); + for_each_subsys(ss, ssid) + list_add_tail(&cset->e_cset_node[ssid], + &cset->subsys[ssid]->cgroup->e_csets[ssid]); + up_write(&css_set_rwsem); return cset; @@ -742,7 +894,7 @@ static void cgroup_destroy_root(struct cgroup_root *root) BUG_ON(!list_empty(&cgrp->children)); /* Rebind all subsystems back to the default hierarchy */ - rebind_subsystems(&cgrp_dfl_root, cgrp->subsys_mask); + rebind_subsystems(&cgrp_dfl_root, root->subsys_mask); /* * Release all the links from cset_links to this hierarchy's @@ -848,7 +1000,7 @@ static struct cgroup *task_cgroup_from_root(struct task_struct *task, * update of a tasks cgroup pointer by cgroup_attach_task() */ -static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask); +static int cgroup_populate_dir(struct cgroup *cgrp, unsigned int subsys_mask); static struct kernfs_syscall_ops cgroup_kf_syscall_ops; static const struct file_operations proc_cgroupstats_operations; @@ -937,15 +1089,7 @@ static void cgroup_put(struct cgroup *cgrp) if (WARN_ON_ONCE(cgrp->parent && !cgroup_is_dead(cgrp))) return; - /* - * XXX: cgrp->id is only used to look up css's. As cgroup and - * css's lifetimes will be decoupled, it should be made - * per-subsystem and moved to css->id so that lookups are - * successful until the target css is released. - */ - mutex_lock(&cgroup_mutex); - idr_remove(&cgrp->root->cgroup_idr, cgrp->id); - mutex_unlock(&cgroup_mutex); + cgroup_idr_remove(&cgrp->root->cgroup_idr, cgrp->id); cgrp->id = -1; call_rcu(&cgrp->rcu_head, cgroup_free_rcu); @@ -964,7 +1108,7 @@ static void cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft) * @cgrp: target cgroup * @subsys_mask: mask of the subsystem ids whose files should be removed */ -static void cgroup_clear_dir(struct cgroup *cgrp, unsigned long subsys_mask) +static void cgroup_clear_dir(struct cgroup *cgrp, unsigned int subsys_mask) { struct cgroup_subsys *ss; int i; @@ -972,18 +1116,17 @@ static void cgroup_clear_dir(struct cgroup *cgrp, unsigned long subsys_mask) for_each_subsys(ss, i) { struct cftype *cfts; - if (!test_bit(i, &subsys_mask)) + if (!(subsys_mask & (1 << i))) continue; list_for_each_entry(cfts, &ss->cfts, node) cgroup_addrm_files(cgrp, cfts, false); } } -static int rebind_subsystems(struct cgroup_root *dst_root, - unsigned long ss_mask) +static int rebind_subsystems(struct cgroup_root *dst_root, unsigned int ss_mask) { struct cgroup_subsys *ss; - int ssid, ret; + int ssid, i, ret; lockdep_assert_held(&cgroup_tree_mutex); lockdep_assert_held(&cgroup_mutex); @@ -992,16 +1135,12 @@ static int rebind_subsystems(struct cgroup_root *dst_root, if (!(ss_mask & (1 << ssid))) continue; - /* if @ss is on the dummy_root, we can always move it */ - if (ss->root == &cgrp_dfl_root) - continue; - - /* if @ss has non-root cgroups attached to it, can't move */ - if (!list_empty(&ss->root->cgrp.children)) + /* if @ss has non-root csses attached to it, can't move */ + if (css_next_child(NULL, cgroup_css(&ss->root->cgrp, ss))) return -EBUSY; /* can't move between two non-dummy roots either */ - if (dst_root != &cgrp_dfl_root) + if (ss->root != &cgrp_dfl_root && dst_root != &cgrp_dfl_root) return -EBUSY; } @@ -1017,9 +1156,9 @@ static int rebind_subsystems(struct cgroup_root *dst_root, * Just warn about it and continue. */ if (cgrp_dfl_root_visible) { - pr_warning("cgroup: failed to create files (%d) while rebinding 0x%lx to default root\n", - ret, ss_mask); - pr_warning("cgroup: you may retry by moving them to a different hierarchy and unbinding\n"); + pr_warn("failed to create files (%d) while rebinding 0x%x to default root\n", + ret, ss_mask); + pr_warn("you may retry by moving them to a different hierarchy and unbinding\n"); } } @@ -1036,6 +1175,7 @@ static int rebind_subsystems(struct cgroup_root *dst_root, for_each_subsys(ss, ssid) { struct cgroup_root *src_root; struct cgroup_subsys_state *css; + struct css_set *cset; if (!(ss_mask & (1 << ssid))) continue; @@ -1050,8 +1190,19 @@ static int rebind_subsystems(struct cgroup_root *dst_root, ss->root = dst_root; css->cgroup = &dst_root->cgrp; - src_root->cgrp.subsys_mask &= ~(1 << ssid); - dst_root->cgrp.subsys_mask |= 1 << ssid; + down_write(&css_set_rwsem); + hash_for_each(css_set_table, i, cset, hlist) + list_move_tail(&cset->e_cset_node[ss->id], + &dst_root->cgrp.e_csets[ss->id]); + up_write(&css_set_rwsem); + + src_root->subsys_mask &= ~(1 << ssid); + src_root->cgrp.child_subsys_mask &= ~(1 << ssid); + + /* default hierarchy doesn't enable controllers by default */ + dst_root->subsys_mask |= 1 << ssid; + if (dst_root != &cgrp_dfl_root) + dst_root->cgrp.child_subsys_mask |= 1 << ssid; if (ss->bind) ss->bind(css); @@ -1069,7 +1220,7 @@ static int cgroup_show_options(struct seq_file *seq, int ssid; for_each_subsys(ss, ssid) - if (root->cgrp.subsys_mask & (1 << ssid)) + if (root->subsys_mask & (1 << ssid)) seq_printf(seq, ",%s", ss->name); if (root->flags & CGRP_ROOT_SANE_BEHAVIOR) seq_puts(seq, ",sane_behavior"); @@ -1091,8 +1242,8 @@ static int cgroup_show_options(struct seq_file *seq, } struct cgroup_sb_opts { - unsigned long subsys_mask; - unsigned long flags; + unsigned int subsys_mask; + unsigned int flags; char *release_agent; bool cpuset_clone_children; char *name; @@ -1100,24 +1251,16 @@ struct cgroup_sb_opts { bool none; }; -/* - * Convert a hierarchy specifier into a bitmask of subsystems and - * flags. Call with cgroup_mutex held to protect the cgroup_subsys[] - * array. This function takes refcounts on subsystems to be used, unless it - * returns error, in which case no refcounts are taken. - */ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) { char *token, *o = data; bool all_ss = false, one_ss = false; - unsigned long mask = (unsigned long)-1; + unsigned int mask = -1U; struct cgroup_subsys *ss; int i; - BUG_ON(!mutex_is_locked(&cgroup_mutex)); - #ifdef CONFIG_CPUSETS - mask = ~(1UL << cpuset_cgrp_id); + mask = ~(1U << cpuset_cgrp_id); #endif memset(opts, 0, sizeof(*opts)); @@ -1198,7 +1341,7 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) /* Mutually exclusive option 'all' + subsystem name */ if (all_ss) return -EINVAL; - set_bit(i, &opts->subsys_mask); + opts->subsys_mask |= (1 << i); one_ss = true; break; @@ -1210,12 +1353,12 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) /* Consistency checks */ if (opts->flags & CGRP_ROOT_SANE_BEHAVIOR) { - pr_warning("cgroup: sane_behavior: this is still under development and its behaviors will change, proceed at your own risk\n"); + pr_warn("sane_behavior: this is still under development and its behaviors will change, proceed at your own risk\n"); if ((opts->flags & (CGRP_ROOT_NOPREFIX | CGRP_ROOT_XATTR)) || opts->cpuset_clone_children || opts->release_agent || opts->name) { - pr_err("cgroup: sane_behavior: noprefix, xattr, clone_children, release_agent and name are not allowed\n"); + pr_err("sane_behavior: noprefix, xattr, clone_children, release_agent and name are not allowed\n"); return -EINVAL; } } else { @@ -1227,7 +1370,7 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) if (all_ss || (!one_ss && !opts->none && !opts->name)) for_each_subsys(ss, i) if (!ss->disabled) - set_bit(i, &opts->subsys_mask); + opts->subsys_mask |= (1 << i); /* * We either have to specify by name or by subsystems. (So @@ -1258,10 +1401,10 @@ static int cgroup_remount(struct kernfs_root *kf_root, int *flags, char *data) int ret = 0; struct cgroup_root *root = cgroup_root_from_kf(kf_root); struct cgroup_sb_opts opts; - unsigned long added_mask, removed_mask; + unsigned int added_mask, removed_mask; if (root->flags & CGRP_ROOT_SANE_BEHAVIOR) { - pr_err("cgroup: sane_behavior: remount is not allowed\n"); + pr_err("sane_behavior: remount is not allowed\n"); return -EINVAL; } @@ -1273,17 +1416,17 @@ static int cgroup_remount(struct kernfs_root *kf_root, int *flags, char *data) if (ret) goto out_unlock; - if (opts.subsys_mask != root->cgrp.subsys_mask || opts.release_agent) - pr_warning("cgroup: option changes via remount are deprecated (pid=%d comm=%s)\n", - task_tgid_nr(current), current->comm); + if (opts.subsys_mask != root->subsys_mask || opts.release_agent) + pr_warn("option changes via remount are deprecated (pid=%d comm=%s)\n", + task_tgid_nr(current), current->comm); - added_mask = opts.subsys_mask & ~root->cgrp.subsys_mask; - removed_mask = root->cgrp.subsys_mask & ~opts.subsys_mask; + added_mask = opts.subsys_mask & ~root->subsys_mask; + removed_mask = root->subsys_mask & ~opts.subsys_mask; /* Don't allow flags or name to change at remount */ if (((opts.flags ^ root->flags) & CGRP_ROOT_OPTION_MASK) || (opts.name && strcmp(opts.name, root->name))) { - pr_err("cgroup: option or name mismatch, new: 0x%lx \"%s\", old: 0x%lx \"%s\"\n", + pr_err("option or name mismatch, new: 0x%x \"%s\", old: 0x%x \"%s\"\n", opts.flags & CGRP_ROOT_OPTION_MASK, opts.name ?: "", root->flags & CGRP_ROOT_OPTION_MASK, root->name); ret = -EINVAL; @@ -1369,6 +1512,9 @@ static void cgroup_enable_task_cg_lists(void) static void init_cgroup_housekeeping(struct cgroup *cgrp) { + struct cgroup_subsys *ss; + int ssid; + atomic_set(&cgrp->refcnt, 1); INIT_LIST_HEAD(&cgrp->sibling); INIT_LIST_HEAD(&cgrp->children); @@ -1377,6 +1523,11 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp) INIT_LIST_HEAD(&cgrp->pidlists); mutex_init(&cgrp->pidlist_mutex); cgrp->dummy_css.cgroup = cgrp; + + for_each_subsys(ss, ssid) + INIT_LIST_HEAD(&cgrp->e_csets[ssid]); + + init_waitqueue_head(&cgrp->offline_waitq); } static void init_cgroup_root(struct cgroup_root *root, @@ -1399,7 +1550,7 @@ static void init_cgroup_root(struct cgroup_root *root, set_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags); } -static int cgroup_setup_root(struct cgroup_root *root, unsigned long ss_mask) +static int cgroup_setup_root(struct cgroup_root *root, unsigned int ss_mask) { LIST_HEAD(tmp_links); struct cgroup *root_cgrp = &root->cgrp; @@ -1409,7 +1560,7 @@ static int cgroup_setup_root(struct cgroup_root *root, unsigned long ss_mask) lockdep_assert_held(&cgroup_tree_mutex); lockdep_assert_held(&cgroup_mutex); - ret = idr_alloc(&root->cgroup_idr, root_cgrp, 0, 1, GFP_KERNEL); + ret = cgroup_idr_alloc(&root->cgroup_idr, root_cgrp, 1, 2, GFP_NOWAIT); if (ret < 0) goto out; root_cgrp->id = ret; @@ -1495,7 +1646,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, */ if (!use_task_css_set_links) cgroup_enable_task_cg_lists(); -retry: + mutex_lock(&cgroup_tree_mutex); mutex_lock(&cgroup_mutex); @@ -1503,7 +1654,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, ret = parse_cgroupfs_options(data, &opts); if (ret) goto out_unlock; - +retry: /* look for a matching existing root */ if (!opts.subsys_mask && !opts.none && !opts.name) { cgrp_dfl_root_visible = true; @@ -1535,7 +1686,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, * subsystems) then they must match. */ if ((opts.subsys_mask || opts.none) && - (opts.subsys_mask != root->cgrp.subsys_mask)) { + (opts.subsys_mask != root->subsys_mask)) { if (!name_match) continue; ret = -EBUSY; @@ -1544,11 +1695,11 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, if ((root->flags ^ opts.flags) & CGRP_ROOT_OPTION_MASK) { if ((root->flags | opts.flags) & CGRP_ROOT_SANE_BEHAVIOR) { - pr_err("cgroup: sane_behavior: new mount options should match the existing superblock\n"); + pr_err("sane_behavior: new mount options should match the existing superblock\n"); ret = -EINVAL; goto out_unlock; } else { - pr_warning("cgroup: new mount options do not match the existing superblock, will be ignored\n"); + pr_warn("new mount options do not match the existing superblock, will be ignored\n"); } } @@ -1562,9 +1713,9 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, if (!atomic_inc_not_zero(&root->cgrp.refcnt)) { mutex_unlock(&cgroup_mutex); mutex_unlock(&cgroup_tree_mutex); - kfree(opts.release_agent); - kfree(opts.name); msleep(10); + mutex_lock(&cgroup_tree_mutex); + mutex_lock(&cgroup_mutex); goto retry; } @@ -1737,7 +1888,7 @@ struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset) /** * cgroup_task_migrate - move a task from one cgroup to another. - * @old_cgrp; the cgroup @tsk is being migrated from + * @old_cgrp: the cgroup @tsk is being migrated from * @tsk: the task being migrated * @new_cset: the new css_set @tsk is being attached to * @@ -1829,10 +1980,6 @@ static void cgroup_migrate_add_src(struct css_set *src_cset, src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root); - /* nothing to do if this cset already belongs to the cgroup */ - if (src_cgrp == dst_cgrp) - return; - if (!list_empty(&src_cset->mg_preload_node)) return; @@ -1847,13 +1994,14 @@ static void cgroup_migrate_add_src(struct css_set *src_cset, /** * cgroup_migrate_prepare_dst - prepare destination css_sets for migration - * @dst_cgrp: the destination cgroup + * @dst_cgrp: the destination cgroup (may be %NULL) * @preloaded_csets: list of preloaded source css_sets * * Tasks are about to be moved to @dst_cgrp and all the source css_sets * have been preloaded to @preloaded_csets. This function looks up and - * pins all destination css_sets, links each to its source, and put them on - * @preloaded_csets. + * pins all destination css_sets, links each to its source, and append them + * to @preloaded_csets. If @dst_cgrp is %NULL, the destination of each + * source css_set is assumed to be its cgroup on the default hierarchy. * * This function must be called after cgroup_migrate_add_src() has been * called on each migration source css_set. After migration is performed @@ -1864,19 +2012,42 @@ static int cgroup_migrate_prepare_dst(struct cgroup *dst_cgrp, struct list_head *preloaded_csets) { LIST_HEAD(csets); - struct css_set *src_cset; + struct css_set *src_cset, *tmp_cset; lockdep_assert_held(&cgroup_mutex); + /* + * Except for the root, child_subsys_mask must be zero for a cgroup + * with tasks so that child cgroups don't compete against tasks. + */ + if (dst_cgrp && cgroup_on_dfl(dst_cgrp) && dst_cgrp->parent && + dst_cgrp->child_subsys_mask) + return -EBUSY; + /* look up the dst cset for each src cset and link it to src */ - list_for_each_entry(src_cset, preloaded_csets, mg_preload_node) { + list_for_each_entry_safe(src_cset, tmp_cset, preloaded_csets, mg_preload_node) { struct css_set *dst_cset; - dst_cset = find_css_set(src_cset, dst_cgrp); + dst_cset = find_css_set(src_cset, + dst_cgrp ?: src_cset->dfl_cgrp); if (!dst_cset) goto err; WARN_ON_ONCE(src_cset->mg_dst_cset || dst_cset->mg_dst_cset); + + /* + * If src cset equals dst, it's noop. Drop the src. + * cgroup_migrate() will skip the cset too. Note that we + * can't handle src == dst as some nodes are used by both. + */ + if (src_cset == dst_cset) { + src_cset->mg_src_cgrp = NULL; + list_del_init(&src_cset->mg_preload_node); + put_css_set(src_cset, false); + put_css_set(dst_cset, false); + continue; + } + src_cset->mg_dst_cset = dst_cset; if (list_empty(&dst_cset->mg_preload_node)) @@ -1885,7 +2056,7 @@ static int cgroup_migrate_prepare_dst(struct cgroup *dst_cgrp, put_css_set(dst_cset, false); } - list_splice(&csets, preloaded_csets); + list_splice_tail(&csets, preloaded_csets); return 0; err: cgroup_migrate_finish(&csets); @@ -1966,7 +2137,7 @@ static int cgroup_migrate(struct cgroup *cgrp, struct task_struct *leader, return 0; /* check that we can legitimately attach to the cgroup */ - for_each_css(css, i, cgrp) { + for_each_e_css(css, i, cgrp) { if (css->ss->can_attach) { ret = css->ss->can_attach(css, &tset); if (ret) { @@ -1996,7 +2167,7 @@ static int cgroup_migrate(struct cgroup *cgrp, struct task_struct *leader, */ tset.csets = &tset.dst_csets; - for_each_css(css, i, cgrp) + for_each_e_css(css, i, cgrp) if (css->ss->attach) css->ss->attach(css, &tset); @@ -2004,7 +2175,7 @@ static int cgroup_migrate(struct cgroup *cgrp, struct task_struct *leader, goto out_release_tset; out_cancel_attach: - for_each_css(css, i, cgrp) { + for_each_e_css(css, i, cgrp) { if (css == failed_css) break; if (css->ss->cancel_attach) @@ -2218,6 +2389,332 @@ static int cgroup_sane_behavior_show(struct seq_file *seq, void *v) return 0; } +static void cgroup_print_ss_mask(struct seq_file *seq, unsigned int ss_mask) +{ + struct cgroup_subsys *ss; + bool printed = false; + int ssid; + + for_each_subsys(ss, ssid) { + if (ss_mask & (1 << ssid)) { + if (printed) + seq_putc(seq, ' '); + seq_printf(seq, "%s", ss->name); + printed = true; + } + } + if (printed) + seq_putc(seq, '\n'); +} + +/* show controllers which are currently attached to the default hierarchy */ +static int cgroup_root_controllers_show(struct seq_file *seq, void *v) +{ + struct cgroup *cgrp = seq_css(seq)->cgroup; + + cgroup_print_ss_mask(seq, cgrp->root->subsys_mask); + return 0; +} + +/* show controllers which are enabled from the parent */ +static int cgroup_controllers_show(struct seq_file *seq, void *v) +{ + struct cgroup *cgrp = seq_css(seq)->cgroup; + + cgroup_print_ss_mask(seq, cgrp->parent->child_subsys_mask); + return 0; +} + +/* show controllers which are enabled for a given cgroup's children */ +static int cgroup_subtree_control_show(struct seq_file *seq, void *v) +{ + struct cgroup *cgrp = seq_css(seq)->cgroup; + + cgroup_print_ss_mask(seq, cgrp->child_subsys_mask); + return 0; +} + +/** + * cgroup_update_dfl_csses - update css assoc of a subtree in default hierarchy + * @cgrp: root of the subtree to update csses for + * + * @cgrp's child_subsys_mask has changed and its subtree's (self excluded) + * css associations need to be updated accordingly. This function looks up + * all css_sets which are attached to the subtree, creates the matching + * updated css_sets and migrates the tasks to the new ones. + */ +static int cgroup_update_dfl_csses(struct cgroup *cgrp) +{ + LIST_HEAD(preloaded_csets); + struct cgroup_subsys_state *css; + struct css_set *src_cset; + int ret; + + lockdep_assert_held(&cgroup_tree_mutex); + lockdep_assert_held(&cgroup_mutex); + + /* look up all csses currently attached to @cgrp's subtree */ + down_read(&css_set_rwsem); + css_for_each_descendant_pre(css, cgroup_css(cgrp, NULL)) { + struct cgrp_cset_link *link; + + /* self is not affected by child_subsys_mask change */ + if (css->cgroup == cgrp) + continue; + + list_for_each_entry(link, &css->cgroup->cset_links, cset_link) + cgroup_migrate_add_src(link->cset, cgrp, + &preloaded_csets); + } + up_read(&css_set_rwsem); + + /* NULL dst indicates self on default hierarchy */ + ret = cgroup_migrate_prepare_dst(NULL, &preloaded_csets); + if (ret) + goto out_finish; + + list_for_each_entry(src_cset, &preloaded_csets, mg_preload_node) { + struct task_struct *last_task = NULL, *task; + + /* src_csets precede dst_csets, break on the first dst_cset */ + if (!src_cset->mg_src_cgrp) + break; + + /* + * All tasks in src_cset need to be migrated to the + * matching dst_cset. Empty it process by process. We + * walk tasks but migrate processes. The leader might even + * belong to a different cset but such src_cset would also + * be among the target src_csets because the default + * hierarchy enforces per-process membership. + */ + while (true) { + down_read(&css_set_rwsem); + task = list_first_entry_or_null(&src_cset->tasks, + struct task_struct, cg_list); + if (task) { + task = task->group_leader; + WARN_ON_ONCE(!task_css_set(task)->mg_src_cgrp); + get_task_struct(task); + } + up_read(&css_set_rwsem); + + if (!task) + break; + + /* guard against possible infinite loop */ + if (WARN(last_task == task, + "cgroup: update_dfl_csses failed to make progress, aborting in inconsistent state\n")) + goto out_finish; + last_task = task; + + threadgroup_lock(task); + /* raced against de_thread() from another thread? */ + if (!thread_group_leader(task)) { + threadgroup_unlock(task); + put_task_struct(task); + continue; + } + + ret = cgroup_migrate(src_cset->dfl_cgrp, task, true); + + threadgroup_unlock(task); + put_task_struct(task); + + if (WARN(ret, "cgroup: failed to update controllers for the default hierarchy (%d), further operations may crash or hang\n", ret)) + goto out_finish; + } + } + +out_finish: + cgroup_migrate_finish(&preloaded_csets); + return ret; +} + +/* change the enabled child controllers for a cgroup in the default hierarchy */ +static int cgroup_subtree_control_write(struct cgroup_subsys_state *dummy_css, + struct cftype *cft, char *buffer) +{ + unsigned int enable_req = 0, disable_req = 0, enable, disable; + struct cgroup *cgrp = dummy_css->cgroup, *child; + struct cgroup_subsys *ss; + char *tok, *p; + int ssid, ret; + + /* + * Parse input - white space separated list of subsystem names + * prefixed with either + or -. + */ + p = buffer; + while ((tok = strsep(&p, " \t\n"))) { + for_each_subsys(ss, ssid) { + if (ss->disabled || strcmp(tok + 1, ss->name)) + continue; + + if (*tok == '+') { + enable_req |= 1 << ssid; + disable_req &= ~(1 << ssid); + } else if (*tok == '-') { + disable_req |= 1 << ssid; + enable_req &= ~(1 << ssid); + } else { + return -EINVAL; + } + break; + } + if (ssid == CGROUP_SUBSYS_COUNT) + return -EINVAL; + } + + /* + * We're gonna grab cgroup_tree_mutex which nests outside kernfs + * active_ref. cgroup_lock_live_group() already provides enough + * protection. Ensure @cgrp stays accessible and break the + * active_ref protection. + */ + cgroup_get(cgrp); + kernfs_break_active_protection(cgrp->control_kn); +retry: + enable = enable_req; + disable = disable_req; + + mutex_lock(&cgroup_tree_mutex); + + for_each_subsys(ss, ssid) { + if (enable & (1 << ssid)) { + if (cgrp->child_subsys_mask & (1 << ssid)) { + enable &= ~(1 << ssid); + continue; + } + + /* + * Because css offlining is asynchronous, userland + * might try to re-enable the same controller while + * the previous instance is still around. In such + * cases, wait till it's gone using offline_waitq. + */ + cgroup_for_each_live_child(child, cgrp) { + wait_queue_t wait; + + if (!cgroup_css(child, ss)) + continue; + + prepare_to_wait(&child->offline_waitq, &wait, + TASK_UNINTERRUPTIBLE); + mutex_unlock(&cgroup_tree_mutex); + schedule(); + finish_wait(&child->offline_waitq, &wait); + goto retry; + } + + /* unavailable or not enabled on the parent? */ + if (!(cgrp_dfl_root.subsys_mask & (1 << ssid)) || + (cgrp->parent && + !(cgrp->parent->child_subsys_mask & (1 << ssid)))) { + ret = -ENOENT; + goto out_unlock_tree; + } + } else if (disable & (1 << ssid)) { + if (!(cgrp->child_subsys_mask & (1 << ssid))) { + disable &= ~(1 << ssid); + continue; + } + + /* a child has it enabled? */ + cgroup_for_each_live_child(child, cgrp) { + if (child->child_subsys_mask & (1 << ssid)) { + ret = -EBUSY; + goto out_unlock_tree; + } + } + } + } + + if (!enable && !disable) { + ret = 0; + goto out_unlock_tree; + } + + if (!cgroup_lock_live_group(cgrp)) { + ret = -ENODEV; + goto out_unlock_tree; + } + + /* + * Except for the root, child_subsys_mask must be zero for a cgroup + * with tasks so that child cgroups don't compete against tasks. + */ + if (enable && cgrp->parent && !list_empty(&cgrp->cset_links)) { + ret = -EBUSY; + goto out_unlock; + } + + /* + * Create csses for enables and update child_subsys_mask. This + * changes cgroup_e_css() results which in turn makes the + * subsequent cgroup_update_dfl_csses() associate all tasks in the + * subtree to the updated csses. + */ + for_each_subsys(ss, ssid) { + if (!(enable & (1 << ssid))) + continue; + + cgroup_for_each_live_child(child, cgrp) { + ret = create_css(child, ss); + if (ret) + goto err_undo_css; + } + } + + cgrp->child_subsys_mask |= enable; + cgrp->child_subsys_mask &= ~disable; + + ret = cgroup_update_dfl_csses(cgrp); + if (ret) + goto err_undo_css; + + /* all tasks are now migrated away from the old csses, kill them */ + for_each_subsys(ss, ssid) { + if (!(disable & (1 << ssid))) + continue; + + cgroup_for_each_live_child(child, cgrp) + kill_css(cgroup_css(child, ss)); + } + + kernfs_activate(cgrp->kn); + ret = 0; +out_unlock: + mutex_unlock(&cgroup_mutex); +out_unlock_tree: + mutex_unlock(&cgroup_tree_mutex); + kernfs_unbreak_active_protection(cgrp->control_kn); + cgroup_put(cgrp); + return ret; + +err_undo_css: + cgrp->child_subsys_mask &= ~enable; + cgrp->child_subsys_mask |= disable; + + for_each_subsys(ss, ssid) { + if (!(enable & (1 << ssid))) + continue; + + cgroup_for_each_live_child(child, cgrp) { + struct cgroup_subsys_state *css = cgroup_css(child, ss); + if (css) + kill_css(css); + } + } + goto out_unlock; +} + +static int cgroup_populated_show(struct seq_file *seq, void *v) +{ + seq_printf(seq, "%d\n", (bool)seq_css(seq)->cgroup->populated_cnt); + return 0; +} + static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { @@ -2377,9 +2874,16 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cftype *cft) return PTR_ERR(kn); ret = cgroup_kn_set_ugid(kn); - if (ret) + if (ret) { kernfs_remove(kn); - return ret; + return ret; + } + + if (cft->seq_show == cgroup_subtree_control_show) + cgrp->control_kn = kn; + else if (cft->seq_show == cgroup_populated_show) + cgrp->populated_kn = kn; + return 0; } /** @@ -2415,8 +2919,8 @@ static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], if (is_add) { ret = cgroup_add_file(cgrp, cft); if (ret) { - pr_warn("cgroup_addrm_files: failed to add %s, err=%d\n", - cft->name, ret); + pr_warn("%s: failed to add %s, err=%d\n", + __func__, cft->name, ret); return ret; } } else { @@ -2436,10 +2940,6 @@ static int cgroup_apply_cftypes(struct cftype *cfts, bool is_add) lockdep_assert_held(&cgroup_tree_mutex); - /* don't bother if @ss isn't attached */ - if (ss->root == &cgrp_dfl_root) - return 0; - /* add/rm files for all cgroups created before */ css_for_each_descendant_pre(css, cgroup_css(root, ss)) { struct cgroup *cgrp = css->cgroup; @@ -2641,10 +3141,19 @@ css_next_child(struct cgroup_subsys_state *pos_css, break; } - if (&next->sibling == &cgrp->children) - return NULL; + /* + * @next, if not pointing to the head, can be dereferenced and is + * the next sibling; however, it might have @ss disabled. If so, + * fast-forward to the next enabled one. + */ + while (&next->sibling != &cgrp->children) { + struct cgroup_subsys_state *next_css = cgroup_css(next, parent_css->ss); - return cgroup_css(next, parent_css->ss); + if (next_css) + return next_css; + next = list_entry_rcu(next->sibling.next, struct cgroup, sibling); + } + return NULL; } /** @@ -2781,27 +3290,36 @@ css_next_descendant_post(struct cgroup_subsys_state *pos, */ static void css_advance_task_iter(struct css_task_iter *it) { - struct list_head *l = it->cset_link; + struct list_head *l = it->cset_pos; struct cgrp_cset_link *link; struct css_set *cset; /* Advance to the next non-empty css_set */ do { l = l->next; - if (l == &it->origin_css->cgroup->cset_links) { - it->cset_link = NULL; + if (l == it->cset_head) { + it->cset_pos = NULL; return; } - link = list_entry(l, struct cgrp_cset_link, cset_link); - cset = link->cset; + + if (it->ss) { + cset = container_of(l, struct css_set, + e_cset_node[it->ss->id]); + } else { + link = list_entry(l, struct cgrp_cset_link, cset_link); + cset = link->cset; + } } while (list_empty(&cset->tasks) && list_empty(&cset->mg_tasks)); - it->cset_link = l; + it->cset_pos = l; if (!list_empty(&cset->tasks)) - it->task = cset->tasks.next; + it->task_pos = cset->tasks.next; else - it->task = cset->mg_tasks.next; + it->task_pos = cset->mg_tasks.next; + + it->tasks_head = &cset->tasks; + it->mg_tasks_head = &cset->mg_tasks; } /** @@ -2827,8 +3345,14 @@ void css_task_iter_start(struct cgroup_subsys_state *css, down_read(&css_set_rwsem); - it->origin_css = css; - it->cset_link = &css->cgroup->cset_links; + it->ss = css->ss; + + if (it->ss) + it->cset_pos = &css->cgroup->e_csets[css->ss->id]; + else + it->cset_pos = &css->cgroup->cset_links; + + it->cset_head = it->cset_pos; css_advance_task_iter(it); } @@ -2844,12 +3368,10 @@ void css_task_iter_start(struct cgroup_subsys_state *css, struct task_struct *css_task_iter_next(struct css_task_iter *it) { struct task_struct *res; - struct list_head *l = it->task; - struct cgrp_cset_link *link = list_entry(it->cset_link, - struct cgrp_cset_link, cset_link); + struct list_head *l = it->task_pos; /* If the iterator cg is NULL, we have no tasks */ - if (!it->cset_link) + if (!it->cset_pos) return NULL; res = list_entry(l, struct task_struct, cg_list); @@ -2860,13 +3382,13 @@ struct task_struct *css_task_iter_next(struct css_task_iter *it) */ l = l->next; - if (l == &link->cset->tasks) - l = link->cset->mg_tasks.next; + if (l == it->tasks_head) + l = it->mg_tasks_head->next; - if (l == &link->cset->mg_tasks) + if (l == it->mg_tasks_head) css_advance_task_iter(it); else - it->task = l; + it->task_pos = l; return res; } @@ -3388,17 +3910,6 @@ static int cgroup_pidlist_show(struct seq_file *s, void *v) return seq_printf(s, "%d\n", *(int *)v); } -/* - * seq_operations functions for iterating on pidlists through seq_file - - * independent of whether it's tasks or procs - */ -static const struct seq_operations cgroup_pidlist_seq_operations = { - .start = cgroup_pidlist_start, - .stop = cgroup_pidlist_stop, - .next = cgroup_pidlist_next, - .show = cgroup_pidlist_show, -}; - static u64 cgroup_read_notify_on_release(struct cgroup_subsys_state *css, struct cftype *cft) { @@ -3454,6 +3965,27 @@ static struct cftype cgroup_base_files[] = { .flags = CFTYPE_ONLY_ON_ROOT, .seq_show = cgroup_sane_behavior_show, }, + { + .name = "cgroup.controllers", + .flags = CFTYPE_ONLY_ON_DFL | CFTYPE_ONLY_ON_ROOT, + .seq_show = cgroup_root_controllers_show, + }, + { + .name = "cgroup.controllers", + .flags = CFTYPE_ONLY_ON_DFL | CFTYPE_NOT_ON_ROOT, + .seq_show = cgroup_controllers_show, + }, + { + .name = "cgroup.subtree_control", + .flags = CFTYPE_ONLY_ON_DFL, + .seq_show = cgroup_subtree_control_show, + .write_string = cgroup_subtree_control_write, + }, + { + .name = "cgroup.populated", + .flags = CFTYPE_ONLY_ON_DFL | CFTYPE_NOT_ON_ROOT, + .seq_show = cgroup_populated_show, + }, /* * Historical crazy stuff. These don't have "cgroup." prefix and @@ -3494,7 +4026,7 @@ static struct cftype cgroup_base_files[] = { * * On failure, no file is added. */ -static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask) +static int cgroup_populate_dir(struct cgroup *cgrp, unsigned int subsys_mask) { struct cgroup_subsys *ss; int i, ret = 0; @@ -3503,7 +4035,7 @@ static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask) for_each_subsys(ss, i) { struct cftype *cfts; - if (!test_bit(i, &subsys_mask)) + if (!(subsys_mask & (1 << i))) continue; list_for_each_entry(cfts, &ss->cfts, node) { @@ -3566,22 +4098,29 @@ static void css_release(struct percpu_ref *ref) { struct cgroup_subsys_state *css = container_of(ref, struct cgroup_subsys_state, refcnt); + struct cgroup_subsys *ss = css->ss; + + RCU_INIT_POINTER(css->cgroup->subsys[ss->id], NULL); + cgroup_idr_remove(&ss->css_idr, css->id); - RCU_INIT_POINTER(css->cgroup->subsys[css->ss->id], NULL); call_rcu(&css->rcu_head, css_free_rcu_fn); } -static void init_css(struct cgroup_subsys_state *css, struct cgroup_subsys *ss, - struct cgroup *cgrp) +static void init_and_link_css(struct cgroup_subsys_state *css, + struct cgroup_subsys *ss, struct cgroup *cgrp) { + cgroup_get(cgrp); + css->cgroup = cgrp; css->ss = ss; css->flags = 0; - if (cgrp->parent) + if (cgrp->parent) { css->parent = cgroup_css(cgrp->parent, ss); - else + css_get(css->parent); + } else { css->flags |= CSS_ROOT; + } BUG_ON(cgroup_css(cgrp, ss)); } @@ -3621,7 +4160,9 @@ static void offline_css(struct cgroup_subsys_state *css) css->flags &= ~CSS_ONLINE; css->cgroup->nr_css--; - RCU_INIT_POINTER(css->cgroup->subsys[ss->id], css); + RCU_INIT_POINTER(css->cgroup->subsys[ss->id], NULL); + + wake_up_all(&css->cgroup->offline_waitq); } /** @@ -3645,31 +4186,34 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss) if (IS_ERR(css)) return PTR_ERR(css); + init_and_link_css(css, ss, cgrp); + err = percpu_ref_init(&css->refcnt, css_release); if (err) goto err_free_css; - init_css(css, ss, cgrp); + err = cgroup_idr_alloc(&ss->css_idr, NULL, 2, 0, GFP_NOWAIT); + if (err < 0) + goto err_free_percpu_ref; + css->id = err; err = cgroup_populate_dir(cgrp, 1 << ss->id); if (err) - goto err_free_percpu_ref; + goto err_free_id; + + /* @css is ready to be brought online now, make it visible */ + cgroup_idr_replace(&ss->css_idr, css, css->id); err = online_css(css); if (err) goto err_clear_dir; - cgroup_get(cgrp); - css_get(css->parent); - - cgrp->subsys_mask |= 1 << ss->id; - if (ss->broken_hierarchy && !ss->warned_broken_hierarchy && parent->parent) { - pr_warning("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n", - current->comm, current->pid, ss->name); + pr_warn("%s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n", + current->comm, current->pid, ss->name); if (!strcmp(ss->name, "memory")) - pr_warning("cgroup: \"memory\" requires setting use_hierarchy to 1 on the root.\n"); + pr_warn("\"memory\" requires setting use_hierarchy to 1 on the root\n"); ss->warned_broken_hierarchy = true; } @@ -3677,10 +4221,12 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss) err_clear_dir: cgroup_clear_dir(css->cgroup, 1 << css->ss->id); +err_free_id: + cgroup_idr_remove(&ss->css_idr, css->id); err_free_percpu_ref: percpu_ref_cancel_init(&css->refcnt); err_free_css: - ss->css_free(css); + call_rcu(&css->rcu_head, css_free_rcu_fn); return err; } @@ -3699,13 +4245,6 @@ static long cgroup_create(struct cgroup *parent, const char *name, struct cgroup_subsys *ss; struct kernfs_node *kn; - /* - * XXX: The default hierarchy isn't fully implemented yet. Block - * !root cgroup creation on it for now. - */ - if (root == &cgrp_dfl_root) - return -EINVAL; - /* allocate the cgroup and its ID, 0 is reserved for the root */ cgrp = kzalloc(sizeof(*cgrp), GFP_KERNEL); if (!cgrp) @@ -3729,7 +4268,7 @@ static long cgroup_create(struct cgroup *parent, const char *name, * Temporarily set the pointer to NULL, so idr_find() won't return * a half-baked cgroup. */ - cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL); + cgrp->id = cgroup_idr_alloc(&root->cgroup_idr, NULL, 2, 0, GFP_NOWAIT); if (cgrp->id < 0) { err = -ENOMEM; goto err_unlock; @@ -3772,7 +4311,7 @@ static long cgroup_create(struct cgroup *parent, const char *name, * @cgrp is now fully operational. If something fails after this * point, it'll be released via the normal destruction path. */ - idr_replace(&root->cgroup_idr, cgrp, cgrp->id); + cgroup_idr_replace(&root->cgroup_idr, cgrp, cgrp->id); err = cgroup_kn_set_ugid(kn); if (err) @@ -3784,13 +4323,20 @@ static long cgroup_create(struct cgroup *parent, const char *name, /* let's create and online css's */ for_each_subsys(ss, ssid) { - if (root->cgrp.subsys_mask & (1 << ssid)) { + if (parent->child_subsys_mask & (1 << ssid)) { err = create_css(cgrp, ss); if (err) goto err_destroy; } } + /* + * On the default hierarchy, a child doesn't automatically inherit + * child_subsys_mask from the parent. Each is configured manually. + */ + if (!cgroup_on_dfl(cgrp)) + cgrp->child_subsys_mask = parent->child_subsys_mask; + kernfs_activate(kn); mutex_unlock(&cgroup_mutex); @@ -3799,7 +4345,7 @@ static long cgroup_create(struct cgroup *parent, const char *name, return 0; err_free_id: - idr_remove(&root->cgroup_idr, cgrp->id); + cgroup_idr_remove(&root->cgroup_idr, cgrp->id); err_unlock: mutex_unlock(&cgroup_mutex); err_unlock_tree: @@ -3886,7 +4432,16 @@ static void css_killed_ref_fn(struct percpu_ref *ref) queue_work(cgroup_destroy_wq, &css->destroy_work); } -static void __kill_css(struct cgroup_subsys_state *css) +/** + * kill_css - destroy a css + * @css: css to destroy + * + * This function initiates destruction of @css by removing cgroup interface + * files and putting its base reference. ->css_offline() will be invoked + * asynchronously once css_tryget() is guaranteed to fail and when the + * reference count reaches zero, @css will be released. + */ +static void kill_css(struct cgroup_subsys_state *css) { lockdep_assert_held(&cgroup_tree_mutex); @@ -3915,28 +4470,6 @@ static void __kill_css(struct cgroup_subsys_state *css) percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn); } -/** - * kill_css - destroy a css - * @css: css to destroy - * - * This function initiates destruction of @css by removing cgroup interface - * files and putting its base reference. ->css_offline() will be invoked - * asynchronously once css_tryget() is guaranteed to fail and when the - * reference count reaches zero, @css will be released. - */ -static void kill_css(struct cgroup_subsys_state *css) -{ - struct cgroup *cgrp = css->cgroup; - - lockdep_assert_held(&cgroup_tree_mutex); - - /* if already killed, noop */ - if (cgrp->subsys_mask & (1 << css->ss->id)) { - cgrp->subsys_mask &= ~(1 << css->ss->id); - __kill_css(css); - } -} - /** * cgroup_destroy_locked - the first stage of cgroup destruction * @cgrp: cgroup to be destroyed @@ -4053,7 +4586,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) /** * cgroup_destroy_css_killed - the second step of cgroup destruction - * @work: cgroup->destroy_free_work + * @cgrp: the cgroup whose csses have just finished offlining * * This function is invoked from a work item for a cgroup which is being * destroyed after all css's are offlined and performs the rest of @@ -4116,7 +4649,7 @@ static struct kernfs_syscall_ops cgroup_kf_syscall_ops = { .rename = cgroup_rename, }; -static void __init cgroup_init_subsys(struct cgroup_subsys *ss) +static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early) { struct cgroup_subsys_state *css; @@ -4125,6 +4658,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) mutex_lock(&cgroup_tree_mutex); mutex_lock(&cgroup_mutex); + idr_init(&ss->css_idr); INIT_LIST_HEAD(&ss->cfts); /* Create the root cgroup state for this subsystem */ @@ -4132,7 +4666,14 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) css = ss->css_alloc(cgroup_css(&cgrp_dfl_root.cgrp, ss)); /* We don't handle early failures gracefully */ BUG_ON(IS_ERR(css)); - init_css(css, ss, &cgrp_dfl_root.cgrp); + init_and_link_css(css, ss, &cgrp_dfl_root.cgrp); + if (early) { + /* idr_alloc() can't be called safely during early init */ + css->id = 1; + } else { + css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2, GFP_KERNEL); + BUG_ON(css->id < 0); + } /* Update the init_css_set to contain a subsys * pointer to this state - since the subsystem is @@ -4149,7 +4690,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) BUG_ON(online_css(css)); - cgrp_dfl_root.cgrp.subsys_mask |= 1 << ss->id; + cgrp_dfl_root.subsys_mask |= 1 << ss->id; mutex_unlock(&cgroup_mutex); mutex_unlock(&cgroup_tree_mutex); @@ -4183,7 +4724,7 @@ int __init cgroup_init_early(void) ss->name = cgroup_subsys_name[i]; if (ss->early_init) - cgroup_init_subsys(ss); + cgroup_init_subsys(ss, true); } return 0; } @@ -4215,8 +4756,19 @@ int __init cgroup_init(void) mutex_unlock(&cgroup_tree_mutex); for_each_subsys(ss, ssid) { - if (!ss->early_init) - cgroup_init_subsys(ss); + if (ss->early_init) { + struct cgroup_subsys_state *css = + init_css_set.subsys[ss->id]; + + css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2, + GFP_KERNEL); + BUG_ON(css->id < 0); + } else { + cgroup_init_subsys(ss, false); + } + + list_add_tail(&init_css_set.e_cset_node[ssid], + &cgrp_dfl_root.cgrp.e_csets[ssid]); /* * cftype registration needs kmalloc and can't be done @@ -4306,7 +4858,7 @@ int proc_cgroup_show(struct seq_file *m, void *v) seq_printf(m, "%d:", root->hierarchy_id); for_each_subsys(ss, ssid) - if (root->cgrp.subsys_mask & (1 << ssid)) + if (root->subsys_mask & (1 << ssid)) seq_printf(m, "%s%s", count++ ? "," : "", ss->name); if (strlen(root->name)) seq_printf(m, "%sname=%s", count ? "," : "", @@ -4667,14 +5219,8 @@ struct cgroup_subsys_state *css_tryget_from_dir(struct dentry *dentry, */ struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss) { - struct cgroup *cgrp; - - cgroup_assert_mutexes_or_rcu_locked(); - - cgrp = idr_find(&ss->root->cgroup_idr, id); - if (cgrp) - return cgroup_css(cgrp, ss); - return NULL; + WARN_ON_ONCE(!rcu_read_lock_held()); + return idr_find(&ss->css_idr, id); } #ifdef CONFIG_CGROUP_DEBUG diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c index 6cb20d2e7ee0d2..019d45008448cc 100644 --- a/kernel/context_tracking.c +++ b/kernel/context_tracking.c @@ -120,7 +120,7 @@ void context_tracking_user_enter(void) * instead of preempt_schedule() to exit user context if needed before * calling the scheduler. */ -asmlinkage void __sched notrace preempt_schedule_context(void) +asmlinkage __visible void __sched notrace preempt_schedule_context(void) { enum ctx_state prev_ctx; diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 3d54c418bd0604..7c0e8da59e26df 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -696,11 +696,8 @@ static int generate_sched_domains(cpumask_var_t **domains, if (nslot == ndoms) { static int warnings = 10; if (warnings) { - printk(KERN_WARNING - "rebuild_sched_domains confused:" - " nslot %d, ndoms %d, csn %d, i %d," - " apn %d\n", - nslot, ndoms, csn, i, apn); + pr_warn("rebuild_sched_domains confused: nslot %d, ndoms %d, csn %d, i %d, apn %d\n", + nslot, ndoms, csn, i, apn); warnings--; } continue; @@ -890,6 +887,7 @@ static void update_tasks_cpumask_hier(struct cpuset *root_cs, bool update_root) /** * update_cpumask - update the cpus_allowed mask of a cpuset and all tasks in it * @cs: the cpuset to consider + * @trialcs: trial cpuset * @buf: buffer of cpu numbers written to this cpuset */ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, @@ -2017,7 +2015,7 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs) parent = parent_cs(parent); if (cgroup_transfer_tasks(parent->css.cgroup, cs->css.cgroup)) { - printk(KERN_ERR "cpuset: failed to transfer tasks out of empty cpuset "); + pr_err("cpuset: failed to transfer tasks out of empty cpuset "); pr_cont_cgroup_name(cs->css.cgroup); pr_cont("\n"); } @@ -2536,7 +2534,7 @@ int cpuset_mems_allowed_intersects(const struct task_struct *tsk1, /** * cpuset_print_task_mems_allowed - prints task's cpuset and mems_allowed - * @task: pointer to task_struct of some task. + * @tsk: pointer to task_struct of some task. * * Description: Prints @task's name, cpuset name, and cached copy of its * mems_allowed to the kernel log. @@ -2554,7 +2552,7 @@ void cpuset_print_task_mems_allowed(struct task_struct *tsk) cgrp = task_cs(tsk)->css.cgroup; nodelist_scnprintf(cpuset_nodelist, CPUSET_NODELIST_LEN, tsk->mems_allowed); - printk(KERN_INFO "%s cpuset=", tsk->comm); + pr_info("%s cpuset=", tsk->comm); pr_cont_cgroup_name(cgrp); pr_cont(" mems_allowed=%s\n", cpuset_nodelist); @@ -2646,10 +2644,10 @@ int proc_cpuset_show(struct seq_file *m, void *unused_v) /* Display task mems_allowed in /proc//status file. */ void cpuset_task_status_allowed(struct seq_file *m, struct task_struct *task) { - seq_printf(m, "Mems_allowed:\t"); + seq_puts(m, "Mems_allowed:\t"); seq_nodemask(m, &task->mems_allowed); - seq_printf(m, "\n"); - seq_printf(m, "Mems_allowed_list:\t"); + seq_puts(m, "\n"); + seq_puts(m, "Mems_allowed_list:\t"); seq_nodemask_list(m, &task->mems_allowed); - seq_printf(m, "\n"); + seq_puts(m, "\n"); } diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 2956c8da16055a..1adf62b39b96b4 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c @@ -534,7 +534,7 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs, kgdb_info[cpu].exception_state &= ~(DCPU_WANT_MASTER | DCPU_IS_SLAVE); kgdb_info[cpu].enter_kgdb--; - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_dec(&slaves_in_kgdb); dbg_touch_watchdogs(); local_irq_restore(flags); @@ -662,7 +662,7 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs, kgdb_info[cpu].exception_state &= ~(DCPU_WANT_MASTER | DCPU_IS_SLAVE); kgdb_info[cpu].enter_kgdb--; - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_dec(&masters_in_kgdb); /* Free kgdb_active */ atomic_set(&kgdb_active, -1); diff --git a/kernel/events/core.c b/kernel/events/core.c index f83a71a3e46d75..7ab734fbaeeb0c 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "internal.h" @@ -1443,6 +1444,11 @@ group_sched_out(struct perf_event *group_event, cpuctx->exclusive = 0; } +struct remove_event { + struct perf_event *event; + bool detach_group; +}; + /* * Cross CPU call to remove a performance event * @@ -1451,12 +1457,15 @@ group_sched_out(struct perf_event *group_event, */ static int __perf_remove_from_context(void *info) { - struct perf_event *event = info; + struct remove_event *re = info; + struct perf_event *event = re->event; struct perf_event_context *ctx = event->ctx; struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); raw_spin_lock(&ctx->lock); event_sched_out(event, cpuctx, ctx); + if (re->detach_group) + perf_group_detach(event); list_del_event(event, ctx); if (!ctx->nr_events && cpuctx->task_ctx == ctx) { ctx->is_active = 0; @@ -1481,10 +1490,14 @@ static int __perf_remove_from_context(void *info) * When called from perf_event_exit_task, it's OK because the * context has been detached from its task. */ -static void perf_remove_from_context(struct perf_event *event) +static void perf_remove_from_context(struct perf_event *event, bool detach_group) { struct perf_event_context *ctx = event->ctx; struct task_struct *task = ctx->task; + struct remove_event re = { + .event = event, + .detach_group = detach_group, + }; lockdep_assert_held(&ctx->mutex); @@ -1493,12 +1506,12 @@ static void perf_remove_from_context(struct perf_event *event) * Per cpu events are removed via an smp call and * the removal is always successful. */ - cpu_function_call(event->cpu, __perf_remove_from_context, event); + cpu_function_call(event->cpu, __perf_remove_from_context, &re); return; } retry: - if (!task_function_call(task, __perf_remove_from_context, event)) + if (!task_function_call(task, __perf_remove_from_context, &re)) return; raw_spin_lock_irq(&ctx->lock); @@ -1515,6 +1528,8 @@ static void perf_remove_from_context(struct perf_event *event) * Since the task isn't running, its safe to remove the event, us * holding the ctx->lock ensures the task won't get scheduled in. */ + if (detach_group) + perf_group_detach(event); list_del_event(event, ctx); raw_spin_unlock_irq(&ctx->lock); } @@ -1663,6 +1678,8 @@ event_sched_in(struct perf_event *event, u64 tstamp = perf_event_time(event); int ret = 0; + lockdep_assert_held(&ctx->lock); + if (event->state <= PERF_EVENT_STATE_OFF) return 0; @@ -3229,9 +3246,13 @@ static void __free_event(struct perf_event *event) if (event->ctx) put_ctx(event->ctx); + if (event->pmu) + module_put(event->pmu->module); + call_rcu(&event->rcu_head, free_event_rcu); } -static void free_event(struct perf_event *event) + +static void _free_event(struct perf_event *event) { irq_work_sync(&event->pending); @@ -3259,45 +3280,31 @@ static void free_event(struct perf_event *event) if (is_cgroup_event(event)) perf_detach_cgroup(event); - __free_event(event); } -int perf_event_release_kernel(struct perf_event *event) +/* + * Used to free events which have a known refcount of 1, such as in error paths + * where the event isn't exposed yet and inherited events. + */ +static void free_event(struct perf_event *event) { - struct perf_event_context *ctx = event->ctx; - - WARN_ON_ONCE(ctx->parent_ctx); - /* - * There are two ways this annotation is useful: - * - * 1) there is a lock recursion from perf_event_exit_task - * see the comment there. - * - * 2) there is a lock-inversion with mmap_sem through - * perf_event_read_group(), which takes faults while - * holding ctx->mutex, however this is called after - * the last filedesc died, so there is no possibility - * to trigger the AB-BA case. - */ - mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING); - raw_spin_lock_irq(&ctx->lock); - perf_group_detach(event); - raw_spin_unlock_irq(&ctx->lock); - perf_remove_from_context(event); - mutex_unlock(&ctx->mutex); - - free_event(event); + if (WARN(atomic_long_cmpxchg(&event->refcount, 1, 0) != 1, + "unexpected event refcount: %ld; ptr=%p\n", + atomic_long_read(&event->refcount), event)) { + /* leak to avoid use-after-free */ + return; + } - return 0; + _free_event(event); } -EXPORT_SYMBOL_GPL(perf_event_release_kernel); /* * Called when the last reference to the file is gone. */ static void put_event(struct perf_event *event) { + struct perf_event_context *ctx = event->ctx; struct task_struct *owner; if (!atomic_long_dec_and_test(&event->refcount)) @@ -3336,9 +3343,33 @@ static void put_event(struct perf_event *event) put_task_struct(owner); } - perf_event_release_kernel(event); + WARN_ON_ONCE(ctx->parent_ctx); + /* + * There are two ways this annotation is useful: + * + * 1) there is a lock recursion from perf_event_exit_task + * see the comment there. + * + * 2) there is a lock-inversion with mmap_sem through + * perf_event_read_group(), which takes faults while + * holding ctx->mutex, however this is called after + * the last filedesc died, so there is no possibility + * to trigger the AB-BA case. + */ + mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING); + perf_remove_from_context(event, true); + mutex_unlock(&ctx->mutex); + + _free_event(event); } +int perf_event_release_kernel(struct perf_event *event) +{ + put_event(event); + return 0; +} +EXPORT_SYMBOL_GPL(perf_event_release_kernel); + static int perf_release(struct inode *inode, struct file *file) { put_event(file->private_data); @@ -6551,6 +6582,7 @@ int perf_pmu_register(struct pmu *pmu, const char *name, int type) free_percpu(pmu->pmu_disable_count); goto unlock; } +EXPORT_SYMBOL_GPL(perf_pmu_register); void perf_pmu_unregister(struct pmu *pmu) { @@ -6572,6 +6604,7 @@ void perf_pmu_unregister(struct pmu *pmu) put_device(pmu->dev); free_pmu_context(pmu); } +EXPORT_SYMBOL_GPL(perf_pmu_unregister); struct pmu *perf_init_event(struct perf_event *event) { @@ -6585,6 +6618,10 @@ struct pmu *perf_init_event(struct perf_event *event) pmu = idr_find(&pmu_idr, event->attr.type); rcu_read_unlock(); if (pmu) { + if (!try_module_get(pmu->module)) { + pmu = ERR_PTR(-ENODEV); + goto unlock; + } event->pmu = pmu; ret = pmu->event_init(event); if (ret) @@ -6593,6 +6630,10 @@ struct pmu *perf_init_event(struct perf_event *event) } list_for_each_entry_rcu(pmu, &pmus, entry) { + if (!try_module_get(pmu->module)) { + pmu = ERR_PTR(-ENODEV); + goto unlock; + } event->pmu = pmu; ret = pmu->event_init(event); if (!ret) @@ -6771,6 +6812,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, err_pmu: if (event->destroy) event->destroy(event); + module_put(pmu->module); err_ns: if (event->ns) put_pid_ns(event->ns); @@ -7055,20 +7097,26 @@ SYSCALL_DEFINE5(perf_event_open, } } + if (task && group_leader && + group_leader->attr.inherit != attr.inherit) { + err = -EINVAL; + goto err_task; + } + get_online_cpus(); event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, NULL, NULL); if (IS_ERR(event)) { err = PTR_ERR(event); - goto err_task; + goto err_cpus; } if (flags & PERF_FLAG_PID_CGROUP) { err = perf_cgroup_connect(pid, event, &attr, group_leader); if (err) { __free_event(event); - goto err_task; + goto err_cpus; } } @@ -7165,7 +7213,7 @@ SYSCALL_DEFINE5(perf_event_open, struct perf_event_context *gctx = group_leader->ctx; mutex_lock(&gctx->mutex); - perf_remove_from_context(group_leader); + perf_remove_from_context(group_leader, false); /* * Removing from the context ends up with disabled @@ -7175,7 +7223,7 @@ SYSCALL_DEFINE5(perf_event_open, perf_event__state_init(group_leader); list_for_each_entry(sibling, &group_leader->sibling_list, group_entry) { - perf_remove_from_context(sibling); + perf_remove_from_context(sibling, false); perf_event__state_init(sibling); put_ctx(gctx); } @@ -7230,8 +7278,9 @@ SYSCALL_DEFINE5(perf_event_open, put_ctx(ctx); err_alloc: free_event(event); -err_task: +err_cpus: put_online_cpus(); +err_task: if (task) put_task_struct(task); err_group_fd: @@ -7305,7 +7354,7 @@ void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu) mutex_lock(&src_ctx->mutex); list_for_each_entry_safe(event, tmp, &src_ctx->event_list, event_entry) { - perf_remove_from_context(event); + perf_remove_from_context(event, false); unaccount_event_cpu(event, src_cpu); put_ctx(src_ctx); list_add(&event->migrate_entry, &events); @@ -7367,13 +7416,7 @@ __perf_event_exit_task(struct perf_event *child_event, struct perf_event_context *child_ctx, struct task_struct *child) { - if (child_event->parent) { - raw_spin_lock_irq(&child_ctx->lock); - perf_group_detach(child_event); - raw_spin_unlock_irq(&child_ctx->lock); - } - - perf_remove_from_context(child_event); + perf_remove_from_context(child_event, true); /* * It can happen that the parent exits first, and has events @@ -7442,24 +7485,9 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn) */ mutex_lock(&child_ctx->mutex); -again: - list_for_each_entry_safe(child_event, tmp, &child_ctx->pinned_groups, - group_entry) + list_for_each_entry_rcu(child_event, &child_ctx->event_list, event_entry) __perf_event_exit_task(child_event, child_ctx, child); - list_for_each_entry_safe(child_event, tmp, &child_ctx->flexible_groups, - group_entry) - __perf_event_exit_task(child_event, child_ctx, child); - - /* - * If the last event was a group event, it will have appended all - * its siblings to the list, but we obtained 'tmp' before that which - * will still point to the list head terminating the iteration. - */ - if (!list_empty(&child_ctx->pinned_groups) || - !list_empty(&child_ctx->flexible_groups)) - goto again; - mutex_unlock(&child_ctx->mutex); put_ctx(child_ctx); @@ -7724,6 +7752,8 @@ int perf_event_init_context(struct task_struct *child, int ctxn) * swapped under us. */ parent_ctx = perf_pin_task_context(parent, ctxn); + if (!parent_ctx) + return 0; /* * No need to check if parent_ctx != NULL here; since we saw @@ -7857,14 +7887,14 @@ static void perf_pmu_rotate_stop(struct pmu *pmu) static void __perf_event_exit_context(void *__info) { + struct remove_event re = { .detach_group = false }; struct perf_event_context *ctx = __info; - struct perf_event *event; perf_pmu_rotate_stop(ctx->pmu); rcu_read_lock(); - list_for_each_entry_rcu(event, &ctx->event_list, event_entry) - __perf_remove_from_context(event); + list_for_each_entry_rcu(re.event, &ctx->event_list, event_entry) + __perf_remove_from_context(&re); rcu_read_unlock(); } diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 04709b66369d83..7716c40f2c5040 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -60,8 +60,6 @@ static struct percpu_rw_semaphore dup_mmap_sem; /* Have a copy of original instruction */ #define UPROBE_COPY_INSN 0 -/* Can skip singlestep */ -#define UPROBE_SKIP_SSTEP 1 struct uprobe { struct rb_node rb_node; /* node in the rb tree */ @@ -129,7 +127,7 @@ struct xol_area { */ static bool valid_vma(struct vm_area_struct *vma, bool is_register) { - vm_flags_t flags = VM_HUGETLB | VM_MAYEXEC | VM_SHARED; + vm_flags_t flags = VM_HUGETLB | VM_MAYEXEC | VM_MAYSHARE; if (is_register) flags |= VM_WRITE; @@ -491,12 +489,9 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) uprobe->offset = offset; init_rwsem(&uprobe->register_rwsem); init_rwsem(&uprobe->consumer_rwsem); - /* For now assume that the instruction need not be single-stepped */ - __set_bit(UPROBE_SKIP_SSTEP, &uprobe->flags); /* add to uprobes_tree, sorted on inode:offset */ cur_uprobe = insert_uprobe(uprobe); - /* a uprobe exists for this inode:offset combination */ if (cur_uprobe) { kfree(uprobe); @@ -1628,20 +1623,6 @@ bool uprobe_deny_signal(void) return true; } -/* - * Avoid singlestepping the original instruction if the original instruction - * is a NOP or can be emulated. - */ -static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs) -{ - if (test_bit(UPROBE_SKIP_SSTEP, &uprobe->flags)) { - if (arch_uprobe_skip_sstep(&uprobe->arch, regs)) - return true; - clear_bit(UPROBE_SKIP_SSTEP, &uprobe->flags); - } - return false; -} - static void mmf_recalc_uprobes(struct mm_struct *mm) { struct vm_area_struct *vma; @@ -1868,13 +1849,13 @@ static void handle_swbp(struct pt_regs *regs) handler_chain(uprobe, regs); - if (can_skip_sstep(uprobe, regs)) + if (arch_uprobe_skip_sstep(&uprobe->arch, regs)) goto out; if (!pre_ssout(uprobe, regs, bp_vaddr)) return; - /* can_skip_sstep() succeeded, or restart if can't singlestep */ + /* arch_uprobe_skip_sstep() succeeded, or restart if can't singlestep */ out: put_uprobe(uprobe); } @@ -1886,10 +1867,11 @@ static void handle_swbp(struct pt_regs *regs) static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) { struct uprobe *uprobe; + int err = 0; uprobe = utask->active_uprobe; if (utask->state == UTASK_SSTEP_ACK) - arch_uprobe_post_xol(&uprobe->arch, regs); + err = arch_uprobe_post_xol(&uprobe->arch, regs); else if (utask->state == UTASK_SSTEP_TRAPPED) arch_uprobe_abort_xol(&uprobe->arch, regs); else @@ -1903,6 +1885,11 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) spin_lock_irq(¤t->sighand->siglock); recalc_sigpending(); /* see uprobe_deny_signal() */ spin_unlock_irq(¤t->sighand->siglock); + + if (unlikely(err)) { + uprobe_warn(current, "execute the probed insn, sending SIGILL."); + force_sig_info(SIGILL, SEND_SIG_FORCED, current); + } } /* diff --git a/kernel/futex.c b/kernel/futex.c index 5f589279e4626c..b991ec05b8f931 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -267,7 +267,7 @@ static inline void futex_get_mm(union futex_key *key) * get_futex_key() implies a full barrier. This is relied upon * as full barrier (B), see the ordering comment above. */ - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } /* @@ -280,7 +280,7 @@ static inline void hb_waiters_inc(struct futex_hash_bucket *hb) /* * Full barrier (A), see the ordering comment above. */ - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); #endif } diff --git a/kernel/gcov/Kconfig b/kernel/gcov/Kconfig index d04ce8ac439926..32f65b7aed46ab 100644 --- a/kernel/gcov/Kconfig +++ b/kernel/gcov/Kconfig @@ -2,7 +2,7 @@ menu "GCOV-based kernel profiling" config GCOV_KERNEL bool "Enable gcov-based kernel profiling" - depends on DEBUG_FS + depends on DEBUG_FS && !LTO select CONSTRUCTORS if !UML default n ---help--- diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 6b715c0af1b117..d10eba8089d164 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -1039,6 +1039,7 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, return ret; } +EXPORT_SYMBOL_GPL(__hrtimer_start_range_ns); /** * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index d34131ca372bae..3dc6a61bf06a44 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -886,8 +886,8 @@ static int irq_thread(void *data) irq_thread_check_affinity(desc, action); action_ret = handler_fn(desc, action); - if (!noirqdebug) - note_interrupt(action->irq, desc, action_ret); + if (action_ret == IRQ_HANDLED) + atomic_inc(&desc->threads_handled); wake_threads_waitq(desc); } diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index a1d8cc63b56e55..e2514b0e439e94 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -270,6 +270,8 @@ try_misrouted_irq(unsigned int irq, struct irq_desc *desc, return action && (action->flags & IRQF_IRQPOLL); } +#define SPURIOUS_DEFERRED 0x80000000 + void note_interrupt(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret) { @@ -277,15 +279,111 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc, irq_settings_is_polled(desc)) return; - /* we get here again via the threaded handler */ - if (action_ret == IRQ_WAKE_THREAD) - return; - if (bad_action_ret(action_ret)) { report_bad_irq(irq, desc, action_ret); return; } + /* + * We cannot call note_interrupt from the threaded handler + * because we need to look at the compound of all handlers + * (primary and threaded). Aside of that in the threaded + * shared case we have no serialization against an incoming + * hardware interrupt while we are dealing with a threaded + * result. + * + * So in case a thread is woken, we just note the fact and + * defer the analysis to the next hardware interrupt. + * + * The threaded handlers store whether they sucessfully + * handled an interrupt and we check whether that number + * changed versus the last invocation. + * + * We could handle all interrupts with the delayed by one + * mechanism, but for the non forced threaded case we'd just + * add pointless overhead to the straight hardirq interrupts + * for the sake of a few lines less code. + */ + if (action_ret & IRQ_WAKE_THREAD) { + /* + * There is a thread woken. Check whether one of the + * shared primary handlers returned IRQ_HANDLED. If + * not we defer the spurious detection to the next + * interrupt. + */ + if (action_ret == IRQ_WAKE_THREAD) { + int handled; + /* + * We use bit 31 of thread_handled_last to + * denote the deferred spurious detection + * active. No locking necessary as + * thread_handled_last is only accessed here + * and we have the guarantee that hard + * interrupts are not reentrant. + */ + if (!(desc->threads_handled_last & SPURIOUS_DEFERRED)) { + desc->threads_handled_last |= SPURIOUS_DEFERRED; + return; + } + /* + * Check whether one of the threaded handlers + * returned IRQ_HANDLED since the last + * interrupt happened. + * + * For simplicity we just set bit 31, as it is + * set in threads_handled_last as well. So we + * avoid extra masking. And we really do not + * care about the high bits of the handled + * count. We just care about the count being + * different than the one we saw before. + */ + handled = atomic_read(&desc->threads_handled); + handled |= SPURIOUS_DEFERRED; + if (handled != desc->threads_handled_last) { + action_ret = IRQ_HANDLED; + /* + * Note: We keep the SPURIOUS_DEFERRED + * bit set. We are handling the + * previous invocation right now. + * Keep it for the current one, so the + * next hardware interrupt will + * account for it. + */ + desc->threads_handled_last = handled; + } else { + /* + * None of the threaded handlers felt + * responsible for the last interrupt + * + * We keep the SPURIOUS_DEFERRED bit + * set in threads_handled_last as we + * need to account for the current + * interrupt as well. + */ + action_ret = IRQ_NONE; + } + } else { + /* + * One of the primary handlers returned + * IRQ_HANDLED. So we don't care about the + * threaded handlers on the same line. Clear + * the deferred detection bit. + * + * In theory we could/should check whether the + * deferred bit is set and take the result of + * the previous run into account here as + * well. But it's really not worth the + * trouble. If every other interrupt is + * handled we never trigger the spurious + * detector. And if this is just the one out + * of 100k unhandled ones which is handled + * then we merily delay the spurious detection + * by one hard interrupt. Not a real problem. + */ + desc->threads_handled_last &= ~SPURIOUS_DEFERRED; + } + } + if (unlikely(action_ret == IRQ_NONE)) { /* * If we are seeing only the odd spurious IRQ caused by diff --git a/kernel/kmod.c b/kernel/kmod.c index c18c891766b565..8637e041a24722 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -495,7 +495,7 @@ int __usermodehelper_disable(enum umh_disable_depth depth) static void helper_lock(void) { atomic_inc(&running_helpers); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); } static void helper_unlock(void) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index ceeadfcabb7611..3214289df5a7a8 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -86,21 +86,8 @@ static raw_spinlock_t *kretprobe_table_lock_ptr(unsigned long hash) return &(kretprobe_table_locks[hash].lock); } -/* - * Normally, functions that we'd want to prohibit kprobes in, are marked - * __kprobes. But, there are cases where such functions already belong to - * a different section (__sched for preempt_schedule) - * - * For such cases, we now have a blacklist - */ -static struct kprobe_blackpoint kprobe_blacklist[] = { - {"preempt_schedule",}, - {"native_get_debugreg",}, - {"irq_entries_start",}, - {"common_interrupt",}, - {"mcount",}, /* mcount can be called from everywhere */ - {NULL} /* Terminator */ -}; +/* Blacklist -- list of struct kprobe_blacklist_entry */ +static LIST_HEAD(kprobe_blacklist); #ifdef __ARCH_WANT_KPROBES_INSN_SLOT /* @@ -151,13 +138,13 @@ struct kprobe_insn_cache kprobe_insn_slots = { .insn_size = MAX_INSN_SIZE, .nr_garbage = 0, }; -static int __kprobes collect_garbage_slots(struct kprobe_insn_cache *c); +static int collect_garbage_slots(struct kprobe_insn_cache *c); /** * __get_insn_slot() - Find a slot on an executable page for an instruction. * We allocate an executable page if there's no room on existing ones. */ -kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c) +kprobe_opcode_t *__get_insn_slot(struct kprobe_insn_cache *c) { struct kprobe_insn_page *kip; kprobe_opcode_t *slot = NULL; @@ -214,7 +201,7 @@ kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c) } /* Return 1 if all garbages are collected, otherwise 0. */ -static int __kprobes collect_one_slot(struct kprobe_insn_page *kip, int idx) +static int collect_one_slot(struct kprobe_insn_page *kip, int idx) { kip->slot_used[idx] = SLOT_CLEAN; kip->nused--; @@ -235,7 +222,7 @@ static int __kprobes collect_one_slot(struct kprobe_insn_page *kip, int idx) return 0; } -static int __kprobes collect_garbage_slots(struct kprobe_insn_cache *c) +static int collect_garbage_slots(struct kprobe_insn_cache *c) { struct kprobe_insn_page *kip, *next; @@ -257,8 +244,8 @@ static int __kprobes collect_garbage_slots(struct kprobe_insn_cache *c) return 0; } -void __kprobes __free_insn_slot(struct kprobe_insn_cache *c, - kprobe_opcode_t *slot, int dirty) +void __free_insn_slot(struct kprobe_insn_cache *c, + kprobe_opcode_t *slot, int dirty) { struct kprobe_insn_page *kip; @@ -314,7 +301,7 @@ static inline void reset_kprobe_instance(void) * OR * - with preemption disabled - from arch/xxx/kernel/kprobes.c */ -struct kprobe __kprobes *get_kprobe(void *addr) +struct kprobe *get_kprobe(void *addr) { struct hlist_head *head; struct kprobe *p; @@ -327,8 +314,9 @@ struct kprobe __kprobes *get_kprobe(void *addr) return NULL; } +NOKPROBE_SYMBOL(get_kprobe); -static int __kprobes aggr_pre_handler(struct kprobe *p, struct pt_regs *regs); +static int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs); /* Return true if the kprobe is an aggregator */ static inline int kprobe_aggrprobe(struct kprobe *p) @@ -360,7 +348,7 @@ static bool kprobes_allow_optimization; * Call all pre_handler on the list, but ignores its return value. * This must be called from arch-dep optimized caller. */ -void __kprobes opt_pre_handler(struct kprobe *p, struct pt_regs *regs) +void opt_pre_handler(struct kprobe *p, struct pt_regs *regs) { struct kprobe *kp; @@ -372,9 +360,10 @@ void __kprobes opt_pre_handler(struct kprobe *p, struct pt_regs *regs) reset_kprobe_instance(); } } +NOKPROBE_SYMBOL(opt_pre_handler); /* Free optimized instructions and optimized_kprobe */ -static __kprobes void free_aggr_kprobe(struct kprobe *p) +static void free_aggr_kprobe(struct kprobe *p) { struct optimized_kprobe *op; @@ -412,7 +401,7 @@ static inline int kprobe_disarmed(struct kprobe *p) } /* Return true(!0) if the probe is queued on (un)optimizing lists */ -static int __kprobes kprobe_queued(struct kprobe *p) +static int kprobe_queued(struct kprobe *p) { struct optimized_kprobe *op; @@ -428,7 +417,7 @@ static int __kprobes kprobe_queued(struct kprobe *p) * Return an optimized kprobe whose optimizing code replaces * instructions including addr (exclude breakpoint). */ -static struct kprobe *__kprobes get_optimized_kprobe(unsigned long addr) +static struct kprobe *get_optimized_kprobe(unsigned long addr) { int i; struct kprobe *p = NULL; @@ -460,7 +449,7 @@ static DECLARE_DELAYED_WORK(optimizing_work, kprobe_optimizer); * Optimize (replace a breakpoint with a jump) kprobes listed on * optimizing_list. */ -static __kprobes void do_optimize_kprobes(void) +static void do_optimize_kprobes(void) { /* Optimization never be done when disarmed */ if (kprobes_all_disarmed || !kprobes_allow_optimization || @@ -488,7 +477,7 @@ static __kprobes void do_optimize_kprobes(void) * Unoptimize (replace a jump with a breakpoint and remove the breakpoint * if need) kprobes listed on unoptimizing_list. */ -static __kprobes void do_unoptimize_kprobes(void) +static void do_unoptimize_kprobes(void) { struct optimized_kprobe *op, *tmp; @@ -520,7 +509,7 @@ static __kprobes void do_unoptimize_kprobes(void) } /* Reclaim all kprobes on the free_list */ -static __kprobes void do_free_cleaned_kprobes(void) +static void do_free_cleaned_kprobes(void) { struct optimized_kprobe *op, *tmp; @@ -532,13 +521,13 @@ static __kprobes void do_free_cleaned_kprobes(void) } /* Start optimizer after OPTIMIZE_DELAY passed */ -static __kprobes void kick_kprobe_optimizer(void) +static void kick_kprobe_optimizer(void) { schedule_delayed_work(&optimizing_work, OPTIMIZE_DELAY); } /* Kprobe jump optimizer */ -static __kprobes void kprobe_optimizer(struct work_struct *work) +static void kprobe_optimizer(struct work_struct *work) { mutex_lock(&kprobe_mutex); /* Lock modules while optimizing kprobes */ @@ -574,7 +563,7 @@ static __kprobes void kprobe_optimizer(struct work_struct *work) } /* Wait for completing optimization and unoptimization */ -static __kprobes void wait_for_kprobe_optimizer(void) +static void wait_for_kprobe_optimizer(void) { mutex_lock(&kprobe_mutex); @@ -593,7 +582,7 @@ static __kprobes void wait_for_kprobe_optimizer(void) } /* Optimize kprobe if p is ready to be optimized */ -static __kprobes void optimize_kprobe(struct kprobe *p) +static void optimize_kprobe(struct kprobe *p) { struct optimized_kprobe *op; @@ -627,7 +616,7 @@ static __kprobes void optimize_kprobe(struct kprobe *p) } /* Short cut to direct unoptimizing */ -static __kprobes void force_unoptimize_kprobe(struct optimized_kprobe *op) +static void force_unoptimize_kprobe(struct optimized_kprobe *op) { get_online_cpus(); arch_unoptimize_kprobe(op); @@ -637,7 +626,7 @@ static __kprobes void force_unoptimize_kprobe(struct optimized_kprobe *op) } /* Unoptimize a kprobe if p is optimized */ -static __kprobes void unoptimize_kprobe(struct kprobe *p, bool force) +static void unoptimize_kprobe(struct kprobe *p, bool force) { struct optimized_kprobe *op; @@ -697,7 +686,7 @@ static void reuse_unused_kprobe(struct kprobe *ap) } /* Remove optimized instructions */ -static void __kprobes kill_optimized_kprobe(struct kprobe *p) +static void kill_optimized_kprobe(struct kprobe *p) { struct optimized_kprobe *op; @@ -723,7 +712,7 @@ static void __kprobes kill_optimized_kprobe(struct kprobe *p) } /* Try to prepare optimized instructions */ -static __kprobes void prepare_optimized_kprobe(struct kprobe *p) +static void prepare_optimized_kprobe(struct kprobe *p) { struct optimized_kprobe *op; @@ -732,7 +721,7 @@ static __kprobes void prepare_optimized_kprobe(struct kprobe *p) } /* Allocate new optimized_kprobe and try to prepare optimized instructions */ -static __kprobes struct kprobe *alloc_aggr_kprobe(struct kprobe *p) +static struct kprobe *alloc_aggr_kprobe(struct kprobe *p) { struct optimized_kprobe *op; @@ -747,13 +736,13 @@ static __kprobes struct kprobe *alloc_aggr_kprobe(struct kprobe *p) return &op->kp; } -static void __kprobes init_aggr_kprobe(struct kprobe *ap, struct kprobe *p); +static void init_aggr_kprobe(struct kprobe *ap, struct kprobe *p); /* * Prepare an optimized_kprobe and optimize it * NOTE: p must be a normal registered kprobe */ -static __kprobes void try_to_optimize_kprobe(struct kprobe *p) +static void try_to_optimize_kprobe(struct kprobe *p) { struct kprobe *ap; struct optimized_kprobe *op; @@ -787,7 +776,7 @@ static __kprobes void try_to_optimize_kprobe(struct kprobe *p) } #ifdef CONFIG_SYSCTL -static void __kprobes optimize_all_kprobes(void) +static void optimize_all_kprobes(void) { struct hlist_head *head; struct kprobe *p; @@ -810,7 +799,7 @@ static void __kprobes optimize_all_kprobes(void) mutex_unlock(&kprobe_mutex); } -static void __kprobes unoptimize_all_kprobes(void) +static void unoptimize_all_kprobes(void) { struct hlist_head *head; struct kprobe *p; @@ -861,7 +850,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write, #endif /* CONFIG_SYSCTL */ /* Put a breakpoint for a probe. Must be called with text_mutex locked */ -static void __kprobes __arm_kprobe(struct kprobe *p) +static void __arm_kprobe(struct kprobe *p) { struct kprobe *_p; @@ -876,7 +865,7 @@ static void __kprobes __arm_kprobe(struct kprobe *p) } /* Remove the breakpoint of a probe. Must be called with text_mutex locked */ -static void __kprobes __disarm_kprobe(struct kprobe *p, bool reopt) +static void __disarm_kprobe(struct kprobe *p, bool reopt) { struct kprobe *_p; @@ -911,13 +900,13 @@ static void reuse_unused_kprobe(struct kprobe *ap) BUG_ON(kprobe_unused(ap)); } -static __kprobes void free_aggr_kprobe(struct kprobe *p) +static void free_aggr_kprobe(struct kprobe *p) { arch_remove_kprobe(p); kfree(p); } -static __kprobes struct kprobe *alloc_aggr_kprobe(struct kprobe *p) +static struct kprobe *alloc_aggr_kprobe(struct kprobe *p) { return kzalloc(sizeof(struct kprobe), GFP_KERNEL); } @@ -931,7 +920,7 @@ static struct ftrace_ops kprobe_ftrace_ops __read_mostly = { static int kprobe_ftrace_enabled; /* Must ensure p->addr is really on ftrace */ -static int __kprobes prepare_kprobe(struct kprobe *p) +static int prepare_kprobe(struct kprobe *p) { if (!kprobe_ftrace(p)) return arch_prepare_kprobe(p); @@ -940,7 +929,7 @@ static int __kprobes prepare_kprobe(struct kprobe *p) } /* Caller must lock kprobe_mutex */ -static void __kprobes arm_kprobe_ftrace(struct kprobe *p) +static void arm_kprobe_ftrace(struct kprobe *p) { int ret; @@ -955,7 +944,7 @@ static void __kprobes arm_kprobe_ftrace(struct kprobe *p) } /* Caller must lock kprobe_mutex */ -static void __kprobes disarm_kprobe_ftrace(struct kprobe *p) +static void disarm_kprobe_ftrace(struct kprobe *p) { int ret; @@ -975,7 +964,7 @@ static void __kprobes disarm_kprobe_ftrace(struct kprobe *p) #endif /* Arm a kprobe with text_mutex */ -static void __kprobes arm_kprobe(struct kprobe *kp) +static void arm_kprobe(struct kprobe *kp) { if (unlikely(kprobe_ftrace(kp))) { arm_kprobe_ftrace(kp); @@ -992,7 +981,7 @@ static void __kprobes arm_kprobe(struct kprobe *kp) } /* Disarm a kprobe with text_mutex */ -static void __kprobes disarm_kprobe(struct kprobe *kp, bool reopt) +static void disarm_kprobe(struct kprobe *kp, bool reopt) { if (unlikely(kprobe_ftrace(kp))) { disarm_kprobe_ftrace(kp); @@ -1008,7 +997,7 @@ static void __kprobes disarm_kprobe(struct kprobe *kp, bool reopt) * Aggregate handlers for multiple kprobes support - these handlers * take care of invoking the individual kprobe handlers on p->list */ -static int __kprobes aggr_pre_handler(struct kprobe *p, struct pt_regs *regs) +static int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs) { struct kprobe *kp; @@ -1022,9 +1011,10 @@ static int __kprobes aggr_pre_handler(struct kprobe *p, struct pt_regs *regs) } return 0; } +NOKPROBE_SYMBOL(aggr_pre_handler); -static void __kprobes aggr_post_handler(struct kprobe *p, struct pt_regs *regs, - unsigned long flags) +static void aggr_post_handler(struct kprobe *p, struct pt_regs *regs, + unsigned long flags) { struct kprobe *kp; @@ -1036,9 +1026,10 @@ static void __kprobes aggr_post_handler(struct kprobe *p, struct pt_regs *regs, } } } +NOKPROBE_SYMBOL(aggr_post_handler); -static int __kprobes aggr_fault_handler(struct kprobe *p, struct pt_regs *regs, - int trapnr) +static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs, + int trapnr) { struct kprobe *cur = __this_cpu_read(kprobe_instance); @@ -1052,8 +1043,9 @@ static int __kprobes aggr_fault_handler(struct kprobe *p, struct pt_regs *regs, } return 0; } +NOKPROBE_SYMBOL(aggr_fault_handler); -static int __kprobes aggr_break_handler(struct kprobe *p, struct pt_regs *regs) +static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs) { struct kprobe *cur = __this_cpu_read(kprobe_instance); int ret = 0; @@ -1065,9 +1057,10 @@ static int __kprobes aggr_break_handler(struct kprobe *p, struct pt_regs *regs) reset_kprobe_instance(); return ret; } +NOKPROBE_SYMBOL(aggr_break_handler); /* Walks the list and increments nmissed count for multiprobe case */ -void __kprobes kprobes_inc_nmissed_count(struct kprobe *p) +void kprobes_inc_nmissed_count(struct kprobe *p) { struct kprobe *kp; if (!kprobe_aggrprobe(p)) { @@ -1078,9 +1071,10 @@ void __kprobes kprobes_inc_nmissed_count(struct kprobe *p) } return; } +NOKPROBE_SYMBOL(kprobes_inc_nmissed_count); -void __kprobes recycle_rp_inst(struct kretprobe_instance *ri, - struct hlist_head *head) +void recycle_rp_inst(struct kretprobe_instance *ri, + struct hlist_head *head) { struct kretprobe *rp = ri->rp; @@ -1095,8 +1089,9 @@ void __kprobes recycle_rp_inst(struct kretprobe_instance *ri, /* Unregistering */ hlist_add_head(&ri->hlist, head); } +NOKPROBE_SYMBOL(recycle_rp_inst); -void __kprobes kretprobe_hash_lock(struct task_struct *tsk, +void kretprobe_hash_lock(struct task_struct *tsk, struct hlist_head **head, unsigned long *flags) __acquires(hlist_lock) { @@ -1107,17 +1102,19 @@ __acquires(hlist_lock) hlist_lock = kretprobe_table_lock_ptr(hash); raw_spin_lock_irqsave(hlist_lock, *flags); } +NOKPROBE_SYMBOL(kretprobe_hash_lock); -static void __kprobes kretprobe_table_lock(unsigned long hash, - unsigned long *flags) +static void kretprobe_table_lock(unsigned long hash, + unsigned long *flags) __acquires(hlist_lock) { raw_spinlock_t *hlist_lock = kretprobe_table_lock_ptr(hash); raw_spin_lock_irqsave(hlist_lock, *flags); } +NOKPROBE_SYMBOL(kretprobe_table_lock); -void __kprobes kretprobe_hash_unlock(struct task_struct *tsk, - unsigned long *flags) +void kretprobe_hash_unlock(struct task_struct *tsk, + unsigned long *flags) __releases(hlist_lock) { unsigned long hash = hash_ptr(tsk, KPROBE_HASH_BITS); @@ -1126,14 +1123,16 @@ __releases(hlist_lock) hlist_lock = kretprobe_table_lock_ptr(hash); raw_spin_unlock_irqrestore(hlist_lock, *flags); } +NOKPROBE_SYMBOL(kretprobe_hash_unlock); -static void __kprobes kretprobe_table_unlock(unsigned long hash, - unsigned long *flags) +static void kretprobe_table_unlock(unsigned long hash, + unsigned long *flags) __releases(hlist_lock) { raw_spinlock_t *hlist_lock = kretprobe_table_lock_ptr(hash); raw_spin_unlock_irqrestore(hlist_lock, *flags); } +NOKPROBE_SYMBOL(kretprobe_table_unlock); /* * This function is called from finish_task_switch when task tk becomes dead, @@ -1141,7 +1140,7 @@ __releases(hlist_lock) * with this task. These left over instances represent probed functions * that have been called but will never return. */ -void __kprobes kprobe_flush_task(struct task_struct *tk) +void kprobe_flush_task(struct task_struct *tk) { struct kretprobe_instance *ri; struct hlist_head *head, empty_rp; @@ -1166,6 +1165,7 @@ void __kprobes kprobe_flush_task(struct task_struct *tk) kfree(ri); } } +NOKPROBE_SYMBOL(kprobe_flush_task); static inline void free_rp_inst(struct kretprobe *rp) { @@ -1178,7 +1178,7 @@ static inline void free_rp_inst(struct kretprobe *rp) } } -static void __kprobes cleanup_rp_inst(struct kretprobe *rp) +static void cleanup_rp_inst(struct kretprobe *rp) { unsigned long flags, hash; struct kretprobe_instance *ri; @@ -1197,12 +1197,13 @@ static void __kprobes cleanup_rp_inst(struct kretprobe *rp) } free_rp_inst(rp); } +NOKPROBE_SYMBOL(cleanup_rp_inst); /* * Add the new probe to ap->list. Fail if this is the * second jprobe at the address - two jprobes can't coexist */ -static int __kprobes add_new_kprobe(struct kprobe *ap, struct kprobe *p) +static int add_new_kprobe(struct kprobe *ap, struct kprobe *p) { BUG_ON(kprobe_gone(ap) || kprobe_gone(p)); @@ -1226,7 +1227,7 @@ static int __kprobes add_new_kprobe(struct kprobe *ap, struct kprobe *p) * Fill in the required fields of the "manager kprobe". Replace the * earlier kprobe in the hlist with the manager kprobe */ -static void __kprobes init_aggr_kprobe(struct kprobe *ap, struct kprobe *p) +static void init_aggr_kprobe(struct kprobe *ap, struct kprobe *p) { /* Copy p's insn slot to ap */ copy_kprobe(p, ap); @@ -1252,8 +1253,7 @@ static void __kprobes init_aggr_kprobe(struct kprobe *ap, struct kprobe *p) * This is the second or subsequent kprobe at the address - handle * the intricacies */ -static int __kprobes register_aggr_kprobe(struct kprobe *orig_p, - struct kprobe *p) +static int register_aggr_kprobe(struct kprobe *orig_p, struct kprobe *p) { int ret = 0; struct kprobe *ap = orig_p; @@ -1324,25 +1324,29 @@ static int __kprobes register_aggr_kprobe(struct kprobe *orig_p, return ret; } -static int __kprobes in_kprobes_functions(unsigned long addr) +bool __weak arch_within_kprobe_blacklist(unsigned long addr) { - struct kprobe_blackpoint *kb; + /* The __kprobes marked functions and entry code must not be probed */ + return addr >= (unsigned long)__kprobes_text_start && + addr < (unsigned long)__kprobes_text_end; +} - if (addr >= (unsigned long)__kprobes_text_start && - addr < (unsigned long)__kprobes_text_end) - return -EINVAL; +static bool within_kprobe_blacklist(unsigned long addr) +{ + struct kprobe_blacklist_entry *ent; + + if (arch_within_kprobe_blacklist(addr)) + return true; /* * If there exists a kprobe_blacklist, verify and * fail any probe registration in the prohibited area */ - for (kb = kprobe_blacklist; kb->name != NULL; kb++) { - if (kb->start_addr) { - if (addr >= kb->start_addr && - addr < (kb->start_addr + kb->range)) - return -EINVAL; - } + list_for_each_entry(ent, &kprobe_blacklist, list) { + if (addr >= ent->start_addr && addr < ent->end_addr) + return true; } - return 0; + + return false; } /* @@ -1351,7 +1355,7 @@ static int __kprobes in_kprobes_functions(unsigned long addr) * This returns encoded errors if it fails to look up symbol or invalid * combination of parameters. */ -static kprobe_opcode_t __kprobes *kprobe_addr(struct kprobe *p) +static kprobe_opcode_t *kprobe_addr(struct kprobe *p) { kprobe_opcode_t *addr = p->addr; @@ -1374,7 +1378,7 @@ static kprobe_opcode_t __kprobes *kprobe_addr(struct kprobe *p) } /* Check passed kprobe is valid and return kprobe in kprobe_table. */ -static struct kprobe * __kprobes __get_valid_kprobe(struct kprobe *p) +static struct kprobe *__get_valid_kprobe(struct kprobe *p) { struct kprobe *ap, *list_p; @@ -1406,8 +1410,8 @@ static inline int check_kprobe_rereg(struct kprobe *p) return ret; } -static __kprobes int check_kprobe_address_safe(struct kprobe *p, - struct module **probed_mod) +static int check_kprobe_address_safe(struct kprobe *p, + struct module **probed_mod) { int ret = 0; unsigned long ftrace_addr; @@ -1433,7 +1437,7 @@ static __kprobes int check_kprobe_address_safe(struct kprobe *p, /* Ensure it is not in reserved area nor out of text */ if (!kernel_text_address((unsigned long) p->addr) || - in_kprobes_functions((unsigned long) p->addr) || + within_kprobe_blacklist((unsigned long) p->addr) || jump_label_text_reserved(p->addr, p->addr)) { ret = -EINVAL; goto out; @@ -1469,7 +1473,7 @@ static __kprobes int check_kprobe_address_safe(struct kprobe *p, return ret; } -int __kprobes register_kprobe(struct kprobe *p) +int register_kprobe(struct kprobe *p) { int ret; struct kprobe *old_p; @@ -1531,7 +1535,7 @@ int __kprobes register_kprobe(struct kprobe *p) EXPORT_SYMBOL_GPL(register_kprobe); /* Check if all probes on the aggrprobe are disabled */ -static int __kprobes aggr_kprobe_disabled(struct kprobe *ap) +static int aggr_kprobe_disabled(struct kprobe *ap) { struct kprobe *kp; @@ -1547,7 +1551,7 @@ static int __kprobes aggr_kprobe_disabled(struct kprobe *ap) } /* Disable one kprobe: Make sure called under kprobe_mutex is locked */ -static struct kprobe *__kprobes __disable_kprobe(struct kprobe *p) +static struct kprobe *__disable_kprobe(struct kprobe *p) { struct kprobe *orig_p; @@ -1574,7 +1578,7 @@ static struct kprobe *__kprobes __disable_kprobe(struct kprobe *p) /* * Unregister a kprobe without a scheduler synchronization. */ -static int __kprobes __unregister_kprobe_top(struct kprobe *p) +static int __unregister_kprobe_top(struct kprobe *p) { struct kprobe *ap, *list_p; @@ -1631,7 +1635,7 @@ static int __kprobes __unregister_kprobe_top(struct kprobe *p) return 0; } -static void __kprobes __unregister_kprobe_bottom(struct kprobe *p) +static void __unregister_kprobe_bottom(struct kprobe *p) { struct kprobe *ap; @@ -1647,7 +1651,7 @@ static void __kprobes __unregister_kprobe_bottom(struct kprobe *p) /* Otherwise, do nothing. */ } -int __kprobes register_kprobes(struct kprobe **kps, int num) +int register_kprobes(struct kprobe **kps, int num) { int i, ret = 0; @@ -1665,13 +1669,13 @@ int __kprobes register_kprobes(struct kprobe **kps, int num) } EXPORT_SYMBOL_GPL(register_kprobes); -void __kprobes unregister_kprobe(struct kprobe *p) +void unregister_kprobe(struct kprobe *p) { unregister_kprobes(&p, 1); } EXPORT_SYMBOL_GPL(unregister_kprobe); -void __kprobes unregister_kprobes(struct kprobe **kps, int num) +void unregister_kprobes(struct kprobe **kps, int num) { int i; @@ -1700,7 +1704,7 @@ unsigned long __weak arch_deref_entry_point(void *entry) return (unsigned long)entry; } -int __kprobes register_jprobes(struct jprobe **jps, int num) +int register_jprobes(struct jprobe **jps, int num) { struct jprobe *jp; int ret = 0, i; @@ -1731,19 +1735,19 @@ int __kprobes register_jprobes(struct jprobe **jps, int num) } EXPORT_SYMBOL_GPL(register_jprobes); -int __kprobes register_jprobe(struct jprobe *jp) +int register_jprobe(struct jprobe *jp) { return register_jprobes(&jp, 1); } EXPORT_SYMBOL_GPL(register_jprobe); -void __kprobes unregister_jprobe(struct jprobe *jp) +void unregister_jprobe(struct jprobe *jp) { unregister_jprobes(&jp, 1); } EXPORT_SYMBOL_GPL(unregister_jprobe); -void __kprobes unregister_jprobes(struct jprobe **jps, int num) +void unregister_jprobes(struct jprobe **jps, int num) { int i; @@ -1768,8 +1772,7 @@ EXPORT_SYMBOL_GPL(unregister_jprobes); * This kprobe pre_handler is registered with every kretprobe. When probe * hits it will set up the return probe. */ -static int __kprobes pre_handler_kretprobe(struct kprobe *p, - struct pt_regs *regs) +static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs) { struct kretprobe *rp = container_of(p, struct kretprobe, kp); unsigned long hash, flags = 0; @@ -1807,8 +1810,9 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p, } return 0; } +NOKPROBE_SYMBOL(pre_handler_kretprobe); -int __kprobes register_kretprobe(struct kretprobe *rp) +int register_kretprobe(struct kretprobe *rp) { int ret = 0; struct kretprobe_instance *inst; @@ -1861,7 +1865,7 @@ int __kprobes register_kretprobe(struct kretprobe *rp) } EXPORT_SYMBOL_GPL(register_kretprobe); -int __kprobes register_kretprobes(struct kretprobe **rps, int num) +int register_kretprobes(struct kretprobe **rps, int num) { int ret = 0, i; @@ -1879,13 +1883,13 @@ int __kprobes register_kretprobes(struct kretprobe **rps, int num) } EXPORT_SYMBOL_GPL(register_kretprobes); -void __kprobes unregister_kretprobe(struct kretprobe *rp) +void unregister_kretprobe(struct kretprobe *rp) { unregister_kretprobes(&rp, 1); } EXPORT_SYMBOL_GPL(unregister_kretprobe); -void __kprobes unregister_kretprobes(struct kretprobe **rps, int num) +void unregister_kretprobes(struct kretprobe **rps, int num) { int i; @@ -1908,38 +1912,38 @@ void __kprobes unregister_kretprobes(struct kretprobe **rps, int num) EXPORT_SYMBOL_GPL(unregister_kretprobes); #else /* CONFIG_KRETPROBES */ -int __kprobes register_kretprobe(struct kretprobe *rp) +int register_kretprobe(struct kretprobe *rp) { return -ENOSYS; } EXPORT_SYMBOL_GPL(register_kretprobe); -int __kprobes register_kretprobes(struct kretprobe **rps, int num) +int register_kretprobes(struct kretprobe **rps, int num) { return -ENOSYS; } EXPORT_SYMBOL_GPL(register_kretprobes); -void __kprobes unregister_kretprobe(struct kretprobe *rp) +void unregister_kretprobe(struct kretprobe *rp) { } EXPORT_SYMBOL_GPL(unregister_kretprobe); -void __kprobes unregister_kretprobes(struct kretprobe **rps, int num) +void unregister_kretprobes(struct kretprobe **rps, int num) { } EXPORT_SYMBOL_GPL(unregister_kretprobes); -static int __kprobes pre_handler_kretprobe(struct kprobe *p, - struct pt_regs *regs) +static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs) { return 0; } +NOKPROBE_SYMBOL(pre_handler_kretprobe); #endif /* CONFIG_KRETPROBES */ /* Set the kprobe gone and remove its instruction buffer. */ -static void __kprobes kill_kprobe(struct kprobe *p) +static void kill_kprobe(struct kprobe *p) { struct kprobe *kp; @@ -1963,7 +1967,7 @@ static void __kprobes kill_kprobe(struct kprobe *p) } /* Disable one kprobe */ -int __kprobes disable_kprobe(struct kprobe *kp) +int disable_kprobe(struct kprobe *kp) { int ret = 0; @@ -1979,7 +1983,7 @@ int __kprobes disable_kprobe(struct kprobe *kp) EXPORT_SYMBOL_GPL(disable_kprobe); /* Enable one kprobe */ -int __kprobes enable_kprobe(struct kprobe *kp) +int enable_kprobe(struct kprobe *kp) { int ret = 0; struct kprobe *p; @@ -2012,16 +2016,49 @@ int __kprobes enable_kprobe(struct kprobe *kp) } EXPORT_SYMBOL_GPL(enable_kprobe); -void __kprobes dump_kprobe(struct kprobe *kp) +void dump_kprobe(struct kprobe *kp) { printk(KERN_WARNING "Dumping kprobe:\n"); printk(KERN_WARNING "Name: %s\nAddress: %p\nOffset: %x\n", kp->symbol_name, kp->addr, kp->offset); } +NOKPROBE_SYMBOL(dump_kprobe); + +/* + * Lookup and populate the kprobe_blacklist. + * + * Unlike the kretprobe blacklist, we'll need to determine + * the range of addresses that belong to the said functions, + * since a kprobe need not necessarily be at the beginning + * of a function. + */ +static int __init populate_kprobe_blacklist(unsigned long *start, + unsigned long *end) +{ + unsigned long *iter; + struct kprobe_blacklist_entry *ent; + unsigned long offset = 0, size = 0; + + for (iter = start; iter < end; iter++) { + if (!kallsyms_lookup_size_offset(*iter, &size, &offset)) { + pr_err("Failed to find blacklist %p\n", (void *)*iter); + continue; + } + + ent = kmalloc(sizeof(*ent), GFP_KERNEL); + if (!ent) + return -ENOMEM; + ent->start_addr = *iter; + ent->end_addr = *iter + size; + INIT_LIST_HEAD(&ent->list); + list_add_tail(&ent->list, &kprobe_blacklist); + } + return 0; +} /* Module notifier call back, checking kprobes on the module */ -static int __kprobes kprobes_module_callback(struct notifier_block *nb, - unsigned long val, void *data) +static int kprobes_module_callback(struct notifier_block *nb, + unsigned long val, void *data) { struct module *mod = data; struct hlist_head *head; @@ -2062,14 +2099,13 @@ static struct notifier_block kprobe_module_nb = { .priority = 0 }; +/* Markers of _kprobe_blacklist section */ +extern unsigned long __start_kprobe_blacklist[]; +extern unsigned long __stop_kprobe_blacklist[]; + static int __init init_kprobes(void) { int i, err = 0; - unsigned long offset = 0, size = 0; - char *modname, namebuf[KSYM_NAME_LEN]; - const char *symbol_name; - void *addr; - struct kprobe_blackpoint *kb; /* FIXME allocate the probe table, currently defined statically */ /* initialize all list heads */ @@ -2079,26 +2115,11 @@ static int __init init_kprobes(void) raw_spin_lock_init(&(kretprobe_table_locks[i].lock)); } - /* - * Lookup and populate the kprobe_blacklist. - * - * Unlike the kretprobe blacklist, we'll need to determine - * the range of addresses that belong to the said functions, - * since a kprobe need not necessarily be at the beginning - * of a function. - */ - for (kb = kprobe_blacklist; kb->name != NULL; kb++) { - kprobe_lookup_name(kb->name, addr); - if (!addr) - continue; - - kb->start_addr = (unsigned long)addr; - symbol_name = kallsyms_lookup(kb->start_addr, - &size, &offset, &modname, namebuf); - if (!symbol_name) - kb->range = 0; - else - kb->range = size; + err = populate_kprobe_blacklist(__start_kprobe_blacklist, + __stop_kprobe_blacklist); + if (err) { + pr_err("kprobes: failed to populate blacklist: %d\n", err); + pr_err("Please take care of using kprobes.\n"); } if (kretprobe_blacklist_size) { @@ -2138,7 +2159,7 @@ static int __init init_kprobes(void) } #ifdef CONFIG_DEBUG_FS -static void __kprobes report_probe(struct seq_file *pi, struct kprobe *p, +static void report_probe(struct seq_file *pi, struct kprobe *p, const char *sym, int offset, char *modname, struct kprobe *pp) { char *kprobe_type; @@ -2167,12 +2188,12 @@ static void __kprobes report_probe(struct seq_file *pi, struct kprobe *p, (kprobe_ftrace(pp) ? "[FTRACE]" : "")); } -static void __kprobes *kprobe_seq_start(struct seq_file *f, loff_t *pos) +static void *kprobe_seq_start(struct seq_file *f, loff_t *pos) { return (*pos < KPROBE_TABLE_SIZE) ? pos : NULL; } -static void __kprobes *kprobe_seq_next(struct seq_file *f, void *v, loff_t *pos) +static void *kprobe_seq_next(struct seq_file *f, void *v, loff_t *pos) { (*pos)++; if (*pos >= KPROBE_TABLE_SIZE) @@ -2180,12 +2201,12 @@ static void __kprobes *kprobe_seq_next(struct seq_file *f, void *v, loff_t *pos) return pos; } -static void __kprobes kprobe_seq_stop(struct seq_file *f, void *v) +static void kprobe_seq_stop(struct seq_file *f, void *v) { /* Nothing to do */ } -static int __kprobes show_kprobe_addr(struct seq_file *pi, void *v) +static int show_kprobe_addr(struct seq_file *pi, void *v) { struct hlist_head *head; struct kprobe *p, *kp; @@ -2216,7 +2237,7 @@ static const struct seq_operations kprobes_seq_ops = { .show = show_kprobe_addr }; -static int __kprobes kprobes_open(struct inode *inode, struct file *filp) +static int kprobes_open(struct inode *inode, struct file *filp) { return seq_open(filp, &kprobes_seq_ops); } @@ -2228,7 +2249,47 @@ static const struct file_operations debugfs_kprobes_operations = { .release = seq_release, }; -static void __kprobes arm_all_kprobes(void) +/* kprobes/blacklist -- shows which functions can not be probed */ +static void *kprobe_blacklist_seq_start(struct seq_file *m, loff_t *pos) +{ + return seq_list_start(&kprobe_blacklist, *pos); +} + +static void *kprobe_blacklist_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + return seq_list_next(v, &kprobe_blacklist, pos); +} + +static int kprobe_blacklist_seq_show(struct seq_file *m, void *v) +{ + struct kprobe_blacklist_entry *ent = + list_entry(v, struct kprobe_blacklist_entry, list); + + seq_printf(m, "0x%p-0x%p\t%ps\n", (void *)ent->start_addr, + (void *)ent->end_addr, (void *)ent->start_addr); + return 0; +} + +static const struct seq_operations kprobe_blacklist_seq_ops = { + .start = kprobe_blacklist_seq_start, + .next = kprobe_blacklist_seq_next, + .stop = kprobe_seq_stop, /* Reuse void function */ + .show = kprobe_blacklist_seq_show, +}; + +static int kprobe_blacklist_open(struct inode *inode, struct file *filp) +{ + return seq_open(filp, &kprobe_blacklist_seq_ops); +} + +static const struct file_operations debugfs_kprobe_blacklist_ops = { + .open = kprobe_blacklist_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static void arm_all_kprobes(void) { struct hlist_head *head; struct kprobe *p; @@ -2256,7 +2317,7 @@ static void __kprobes arm_all_kprobes(void) return; } -static void __kprobes disarm_all_kprobes(void) +static void disarm_all_kprobes(void) { struct hlist_head *head; struct kprobe *p; @@ -2340,7 +2401,7 @@ static const struct file_operations fops_kp = { .llseek = default_llseek, }; -static int __kprobes debugfs_kprobe_init(void) +static int __init debugfs_kprobe_init(void) { struct dentry *dir, *file; unsigned int value = 1; @@ -2351,19 +2412,24 @@ static int __kprobes debugfs_kprobe_init(void) file = debugfs_create_file("list", 0444, dir, NULL, &debugfs_kprobes_operations); - if (!file) { - debugfs_remove(dir); - return -ENOMEM; - } + if (!file) + goto error; file = debugfs_create_file("enabled", 0600, dir, &value, &fops_kp); - if (!file) { - debugfs_remove(dir); - return -ENOMEM; - } + if (!file) + goto error; + + file = debugfs_create_file("blacklist", 0444, dir, NULL, + &debugfs_kprobe_blacklist_ops); + if (!file) + goto error; return 0; + +error: + debugfs_remove(dir); + return -ENOMEM; } late_initcall(debugfs_kprobe_init); diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 2495a9b14ac8f1..6683ccef9fffb2 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -37,6 +37,7 @@ static ssize_t uevent_seqnum_show(struct kobject *kobj, } KERNEL_ATTR_RO(uevent_seqnum); +#ifdef CONFIG_UEVENT_HELPER /* uevent helper program, used during early boot */ static ssize_t uevent_helper_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -56,7 +57,7 @@ static ssize_t uevent_helper_store(struct kobject *kobj, return count; } KERNEL_ATTR_RW(uevent_helper); - +#endif #ifdef CONFIG_PROFILING static ssize_t profiling_show(struct kobject *kobj, @@ -189,7 +190,9 @@ EXPORT_SYMBOL_GPL(kernel_kobj); static struct attribute * kernel_attrs[] = { &fscaps_attr.attr, &uevent_seqnum_attr.attr, +#ifdef CONFIG_UEVENT_HELPER &uevent_helper_attr.attr, +#endif #ifdef CONFIG_PROFILING &profiling_attr.attr, #endif diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index b0e9467922e1a4..d24e4339b46d3c 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -4188,7 +4188,7 @@ void debug_show_held_locks(struct task_struct *task) } EXPORT_SYMBOL_GPL(debug_show_held_locks); -asmlinkage void lockdep_sys_exit(void) +asmlinkage __visible void lockdep_sys_exit(void) { struct task_struct *curr = current; diff --git a/kernel/locking/lockdep_internals.h b/kernel/locking/lockdep_internals.h index 4f560cfedc8fd0..51c4b24b632860 100644 --- a/kernel/locking/lockdep_internals.h +++ b/kernel/locking/lockdep_internals.h @@ -54,9 +54,9 @@ enum { * table (if it's not there yet), and we check it for lock order * conflicts and deadlocks. */ -#define MAX_LOCKDEP_ENTRIES 16384UL +#define MAX_LOCKDEP_ENTRIES 32768UL -#define MAX_LOCKDEP_CHAINS_BITS 15 +#define MAX_LOCKDEP_CHAINS_BITS 16 #define MAX_LOCKDEP_CHAINS (1UL << MAX_LOCKDEP_CHAINS_BITS) #define MAX_LOCKDEP_CHAIN_HLOCKS (MAX_LOCKDEP_CHAINS*5) @@ -65,7 +65,7 @@ enum { * Stack-trace: tightly packed array of stack backtrace * addresses. Protected by the hash_lock. */ -#define MAX_STACK_TRACE_ENTRIES 262144UL +#define MAX_STACK_TRACE_ENTRIES 524288UL extern struct list_head all_lock_classes; extern struct lock_chain lock_chains[]; diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c index f26b1a18e34e03..0955b885d0dc8e 100644 --- a/kernel/locking/locktorture.c +++ b/kernel/locking/locktorture.c @@ -82,14 +82,14 @@ struct lock_writer_stress_stats { }; static struct lock_writer_stress_stats *lwsa; -#if defined(MODULE) || defined(CONFIG_LOCK_TORTURE_TEST_RUNNABLE) +#if defined(MODULE) #define LOCKTORTURE_RUNNABLE_INIT 1 #else #define LOCKTORTURE_RUNNABLE_INIT 0 #endif int locktorture_runnable = LOCKTORTURE_RUNNABLE_INIT; module_param(locktorture_runnable, int, 0444); -MODULE_PARM_DESC(locktorture_runnable, "Start locktorture at boot"); +MODULE_PARM_DESC(locktorture_runnable, "Start locktorture at module init"); /* Forward reference. */ static void lock_torture_cleanup(void); @@ -216,10 +216,11 @@ static int lock_torture_writer(void *arg) static DEFINE_TORTURE_RANDOM(rand); VERBOSE_TOROUT_STRING("lock_torture_writer task started"); - set_user_nice(current, 19); + set_user_nice(current, MAX_NICE); do { - schedule_timeout_uninterruptible(1); + if ((torture_random(&rand) & 0xfffff) == 0) + schedule_timeout_uninterruptible(1); cur_ops->writelock(); if (WARN_ON_ONCE(lock_is_write_held)) lwsp->n_write_lock_fail++; @@ -354,7 +355,8 @@ static int __init lock_torture_init(void) &lock_busted_ops, &spin_lock_ops, &spin_lock_irq_ops, }; - torture_init_begin(torture_type, verbose, &locktorture_runnable); + if (!torture_init_begin(torture_type, verbose, &locktorture_runnable)) + return -EBUSY; /* Process args and tell the world that the torturer is on the job. */ for (i = 0; i < ARRAY_SIZE(torture_ops); i++) { diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index 1d66e08e897d16..b4219ff87b8c6d 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -11,6 +11,55 @@ #include #include +/* + * Guide to the rw_semaphore's count field for common values. + * (32-bit case illustrated, similar for 64-bit) + * + * 0x0000000X (1) X readers active or attempting lock, no writer waiting + * X = #active_readers + #readers attempting to lock + * (X*ACTIVE_BIAS) + * + * 0x00000000 rwsem is unlocked, and no one is waiting for the lock or + * attempting to read lock or write lock. + * + * 0xffff000X (1) X readers active or attempting lock, with waiters for lock + * X = #active readers + # readers attempting lock + * (X*ACTIVE_BIAS + WAITING_BIAS) + * (2) 1 writer attempting lock, no waiters for lock + * X-1 = #active readers + #readers attempting lock + * ((X-1)*ACTIVE_BIAS + ACTIVE_WRITE_BIAS) + * (3) 1 writer active, no waiters for lock + * X-1 = #active readers + #readers attempting lock + * ((X-1)*ACTIVE_BIAS + ACTIVE_WRITE_BIAS) + * + * 0xffff0001 (1) 1 reader active or attempting lock, waiters for lock + * (WAITING_BIAS + ACTIVE_BIAS) + * (2) 1 writer active or attempting lock, no waiters for lock + * (ACTIVE_WRITE_BIAS) + * + * 0xffff0000 (1) There are writers or readers queued but none active + * or in the process of attempting lock. + * (WAITING_BIAS) + * Note: writer can attempt to steal lock for this count by adding + * ACTIVE_WRITE_BIAS in cmpxchg and checking the old count + * + * 0xfffe0001 (1) 1 writer active, or attempting lock. Waiters on queue. + * (ACTIVE_WRITE_BIAS + WAITING_BIAS) + * + * Note: Readers attempt to lock by adding ACTIVE_BIAS in down_read and checking + * the count becomes more than 0 for successful lock acquisition, + * i.e. the case where there are only readers or nobody has lock. + * (1st and 2nd case above). + * + * Writers attempt to lock by adding ACTIVE_WRITE_BIAS in down_write and + * checking the count becomes ACTIVE_WRITE_BIAS for successful lock + * acquisition (i.e. nobody else has lock or attempts lock). If + * unsuccessful, in rwsem_down_write_failed, we'll check to see if there + * are only waiters but none active (5th case above), and attempt to + * steal the lock. + * + */ + /* * Initialize an rwsem: */ diff --git a/kernel/module.c b/kernel/module.c index 079c4615607d6e..626d164dcf83f6 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3190,6 +3190,7 @@ static int load_module(struct load_info *info, const char __user *uargs, { struct module *mod; long err; + char *after_dashes; err = module_sig_check(info); if (err) @@ -3277,10 +3278,15 @@ static int load_module(struct load_info *info, const char __user *uargs, goto ddebug_cleanup; /* Module is ready to execute: parsing args may do that. */ - err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, - -32768, 32767, unknown_module_param_cb); - if (err < 0) + after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, + -32768, 32767, unknown_module_param_cb); + if (IS_ERR(after_dashes)) { + err = PTR_ERR(after_dashes); goto bug_cleanup; + } else if (after_dashes) { + pr_warn("%s: parameters '%s' after `--' ignored\n", + mod->name, after_dashes); + } /* Link in to syfs. */ err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp); diff --git a/kernel/notifier.c b/kernel/notifier.c index db4c8b08a50cef..4803da6eab62f1 100644 --- a/kernel/notifier.c +++ b/kernel/notifier.c @@ -71,9 +71,9 @@ static int notifier_chain_unregister(struct notifier_block **nl, * @returns: notifier_call_chain returns the value returned by the * last notifier function called. */ -static int __kprobes notifier_call_chain(struct notifier_block **nl, - unsigned long val, void *v, - int nr_to_call, int *nr_calls) +static int notifier_call_chain(struct notifier_block **nl, + unsigned long val, void *v, + int nr_to_call, int *nr_calls) { int ret = NOTIFY_DONE; struct notifier_block *nb, *next_nb; @@ -102,6 +102,7 @@ static int __kprobes notifier_call_chain(struct notifier_block **nl, } return ret; } +NOKPROBE_SYMBOL(notifier_call_chain); /* * Atomic notifier chain routines. Registration and unregistration @@ -172,9 +173,9 @@ EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); * Otherwise the return value is the return value * of the last notifier function called. */ -int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh, - unsigned long val, void *v, - int nr_to_call, int *nr_calls) +int __atomic_notifier_call_chain(struct atomic_notifier_head *nh, + unsigned long val, void *v, + int nr_to_call, int *nr_calls) { int ret; @@ -184,13 +185,15 @@ int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh, return ret; } EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain); +NOKPROBE_SYMBOL(__atomic_notifier_call_chain); -int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh, - unsigned long val, void *v) +int atomic_notifier_call_chain(struct atomic_notifier_head *nh, + unsigned long val, void *v) { return __atomic_notifier_call_chain(nh, val, v, -1, NULL); } EXPORT_SYMBOL_GPL(atomic_notifier_call_chain); +NOKPROBE_SYMBOL(atomic_notifier_call_chain); /* * Blocking notifier chain routines. All access to the chain is @@ -527,7 +530,7 @@ EXPORT_SYMBOL_GPL(srcu_init_notifier_head); static ATOMIC_NOTIFIER_HEAD(die_chain); -int notrace __kprobes notify_die(enum die_val val, const char *str, +int notrace notify_die(enum die_val val, const char *str, struct pt_regs *regs, long err, int trap, int sig) { struct die_args args = { @@ -540,6 +543,7 @@ int notrace __kprobes notify_die(enum die_val val, const char *str, }; return atomic_notifier_call_chain(&die_chain, val, &args); } +NOKPROBE_SYMBOL(notify_die); int register_die_notifier(struct notifier_block *nb) { diff --git a/kernel/params.c b/kernel/params.c index b00142e7f3ba18..1e52ca233fd9a4 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -177,13 +177,13 @@ static char *next_arg(char *args, char **param, char **val) } /* Args looks like "foo=bar,bar2 baz=fuz wiz". */ -int parse_args(const char *doing, - char *args, - const struct kernel_param *params, - unsigned num, - s16 min_level, - s16 max_level, - int (*unknown)(char *param, char *val, const char *doing)) +char *parse_args(const char *doing, + char *args, + const struct kernel_param *params, + unsigned num, + s16 min_level, + s16 max_level, + int (*unknown)(char *param, char *val, const char *doing)) { char *param, *val; @@ -198,6 +198,9 @@ int parse_args(const char *doing, int irq_was_disabled; args = next_arg(args, ¶m, &val); + /* Stop at -- */ + if (!val && strcmp(param, "--") == 0) + return args; irq_was_disabled = irqs_disabled(); ret = parse_one(param, val, doing, params, num, min_level, max_level, unknown); @@ -208,22 +211,22 @@ int parse_args(const char *doing, switch (ret) { case -ENOENT: pr_err("%s: Unknown parameter `%s'\n", doing, param); - return ret; + return ERR_PTR(ret); case -ENOSPC: pr_err("%s: `%s' too large for parameter `%s'\n", doing, val ?: "", param); - return ret; + return ERR_PTR(ret); case 0: break; default: pr_err("%s: `%s' invalid for parameter `%s'\n", doing, val ?: "", param); - return ret; + return ERR_PTR(ret); } } /* All parsed OK. */ - return 0; + return NULL; } /* Lazy bastard, eh? */ diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index f4f2073711d348..1f08ac7f55d818 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -228,19 +228,23 @@ static void platform_recover(int platform_mode) void swsusp_show_speed(struct timeval *start, struct timeval *stop, unsigned nr_pages, char *msg) { - s64 elapsed_centisecs64; - int centisecs; - int k; - int kps; + u64 elapsed_centisecs64; + unsigned int centisecs; + unsigned int k; + unsigned int kps; elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start); + /* + * If "(s64)elapsed_centisecs64 < 0", it will print long elapsed time, + * it is obvious enough for what went wrong. + */ do_div(elapsed_centisecs64, NSEC_PER_SEC / 100); centisecs = elapsed_centisecs64; if (centisecs == 0) centisecs = 1; /* avoid div-by-zero */ k = nr_pages * (PAGE_SIZE / 1024); kps = (k * 100) / centisecs; - printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", + printk(KERN_INFO "PM: %s %u kbytes in %u.%02u seconds (%u.%02u MB/s)\n", msg, k, centisecs / 100, centisecs % 100, kps / 1000, (kps % 1000) / 10); @@ -595,7 +599,8 @@ static void power_down(void) case HIBERNATION_PLATFORM: hibernation_platform_enter(); case HIBERNATION_SHUTDOWN: - kernel_power_off(); + if (pm_power_off) + kernel_power_off(); break; #ifdef CONFIG_SUSPEND case HIBERNATION_SUSPEND: @@ -623,7 +628,8 @@ static void power_down(void) * corruption after resume. */ printk(KERN_CRIT "PM: Please power down manually\n"); - while(1); + while (1) + cpu_relax(); } /** diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 18fb7a2fb14b31..1ea328aafdc9a7 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1586,7 +1586,7 @@ swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm, return -ENOMEM; } -asmlinkage int swsusp_save(void) +asmlinkage __visible int swsusp_save(void) { unsigned int nr_pages, nr_highmem; diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 8233cd4047d776..155721f7f9090d 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -54,9 +54,11 @@ static void freeze_begin(void) static void freeze_enter(void) { + cpuidle_use_deepest_state(true); cpuidle_resume(); wait_event(suspend_freeze_wait_head, suspend_freeze_wake); cpuidle_pause(); + cpuidle_use_deepest_state(false); } void freeze_wake(void) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 13d50d137cbc71..b030cb2843b6bd 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1792,7 +1792,7 @@ EXPORT_SYMBOL(printk_emit); * * See the vsnprintf() documentation for format string extensions over C99. */ -asmlinkage int printk(const char *fmt, ...) +asmlinkage __visible int printk(const char *fmt, ...) { va_list args; int r; @@ -1855,7 +1855,7 @@ void early_vprintk(const char *fmt, va_list ap) } } -asmlinkage void early_printk(const char *fmt, ...) +asmlinkage __visible void early_printk(const char *fmt, ...) { va_list ap; diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index bd30bc61bc05c2..1d8559198bd5d4 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -58,9 +58,11 @@ torture_param(int, fqs_duration, 0, "Duration of fqs bursts (us), 0 to disable"); torture_param(int, fqs_holdoff, 0, "Holdoff time within fqs bursts (us)"); torture_param(int, fqs_stutter, 3, "Wait time between fqs bursts (s)"); +torture_param(bool, gp_cond, false, "Use conditional/async GP wait primitives"); torture_param(bool, gp_exp, false, "Use expedited GP wait primitives"); torture_param(bool, gp_normal, false, "Use normal (non-expedited) GP wait primitives"); +torture_param(bool, gp_sync, false, "Use synchronous GP wait primitives"); torture_param(int, irqreader, 1, "Allow RCU readers from irq handlers"); torture_param(int, n_barrier_cbs, 0, "# of callbacks/kthreads for barrier testing"); @@ -138,6 +140,18 @@ static long n_barrier_attempts; static long n_barrier_successes; static struct list_head rcu_torture_removed; +static int rcu_torture_writer_state; +#define RTWS_FIXED_DELAY 0 +#define RTWS_DELAY 1 +#define RTWS_REPLACE 2 +#define RTWS_DEF_FREE 3 +#define RTWS_EXP_SYNC 4 +#define RTWS_COND_GET 5 +#define RTWS_COND_SYNC 6 +#define RTWS_SYNC 7 +#define RTWS_STUTTER 8 +#define RTWS_STOPPING 9 + #if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE) #define RCUTORTURE_RUNNABLE_INIT 1 #else @@ -214,6 +228,7 @@ rcu_torture_free(struct rcu_torture *p) */ struct rcu_torture_ops { + int ttype; void (*init)(void); int (*readlock)(void); void (*read_delay)(struct torture_random_state *rrsp); @@ -222,6 +237,8 @@ struct rcu_torture_ops { void (*deferred_free)(struct rcu_torture *p); void (*sync)(void); void (*exp_sync)(void); + unsigned long (*get_state)(void); + void (*cond_sync)(unsigned long oldstate); void (*call)(struct rcu_head *head, void (*func)(struct rcu_head *rcu)); void (*cb_barrier)(void); void (*fqs)(void); @@ -273,10 +290,48 @@ static int rcu_torture_completed(void) return rcu_batches_completed(); } +/* + * Update callback in the pipe. This should be invoked after a grace period. + */ +static bool +rcu_torture_pipe_update_one(struct rcu_torture *rp) +{ + int i; + + i = rp->rtort_pipe_count; + if (i > RCU_TORTURE_PIPE_LEN) + i = RCU_TORTURE_PIPE_LEN; + atomic_inc(&rcu_torture_wcount[i]); + if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) { + rp->rtort_mbtest = 0; + return true; + } + return false; +} + +/* + * Update all callbacks in the pipe. Suitable for synchronous grace-period + * primitives. + */ +static void +rcu_torture_pipe_update(struct rcu_torture *old_rp) +{ + struct rcu_torture *rp; + struct rcu_torture *rp1; + + if (old_rp) + list_add(&old_rp->rtort_free, &rcu_torture_removed); + list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) { + if (rcu_torture_pipe_update_one(rp)) { + list_del(&rp->rtort_free); + rcu_torture_free(rp); + } + } +} + static void rcu_torture_cb(struct rcu_head *p) { - int i; struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu); if (torture_must_stop_irq()) { @@ -284,16 +339,10 @@ rcu_torture_cb(struct rcu_head *p) /* The next initialization will pick up the pieces. */ return; } - i = rp->rtort_pipe_count; - if (i > RCU_TORTURE_PIPE_LEN) - i = RCU_TORTURE_PIPE_LEN; - atomic_inc(&rcu_torture_wcount[i]); - if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) { - rp->rtort_mbtest = 0; + if (rcu_torture_pipe_update_one(rp)) rcu_torture_free(rp); - } else { + else cur_ops->deferred_free(rp); - } } static int rcu_no_completed(void) @@ -312,6 +361,7 @@ static void rcu_sync_torture_init(void) } static struct rcu_torture_ops rcu_ops = { + .ttype = RTORT_RCU, .init = rcu_sync_torture_init, .readlock = rcu_torture_read_lock, .read_delay = rcu_read_delay, @@ -320,6 +370,8 @@ static struct rcu_torture_ops rcu_ops = { .deferred_free = rcu_torture_deferred_free, .sync = synchronize_rcu, .exp_sync = synchronize_rcu_expedited, + .get_state = get_state_synchronize_rcu, + .cond_sync = cond_synchronize_rcu, .call = call_rcu, .cb_barrier = rcu_barrier, .fqs = rcu_force_quiescent_state, @@ -355,6 +407,7 @@ static void rcu_bh_torture_deferred_free(struct rcu_torture *p) } static struct rcu_torture_ops rcu_bh_ops = { + .ttype = RTORT_RCU_BH, .init = rcu_sync_torture_init, .readlock = rcu_bh_torture_read_lock, .read_delay = rcu_read_delay, /* just reuse rcu's version. */ @@ -397,6 +450,7 @@ call_rcu_busted(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) } static struct rcu_torture_ops rcu_busted_ops = { + .ttype = RTORT_BUSTED, .init = rcu_sync_torture_init, .readlock = rcu_torture_read_lock, .read_delay = rcu_read_delay, /* just reuse rcu's version. */ @@ -473,15 +527,16 @@ static void srcu_torture_barrier(void) static void srcu_torture_stats(char *page) { + long c0, c1; int cpu; int idx = srcu_ctl.completed & 0x1; page += sprintf(page, "%s%s per-CPU(idx=%d):", torture_type, TORTURE_FLAG, idx); for_each_possible_cpu(cpu) { - page += sprintf(page, " %d(%lu,%lu)", cpu, - per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx], - per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx]); + c0 = (long)per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx]; + c1 = (long)per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx]; + page += sprintf(page, " %d(%ld,%ld)", cpu, c0, c1); } sprintf(page, "\n"); } @@ -492,6 +547,7 @@ static void srcu_torture_synchronize_expedited(void) } static struct rcu_torture_ops srcu_ops = { + .ttype = RTORT_SRCU, .init = rcu_sync_torture_init, .readlock = srcu_torture_read_lock, .read_delay = srcu_read_delay, @@ -527,6 +583,7 @@ static void rcu_sched_torture_deferred_free(struct rcu_torture *p) } static struct rcu_torture_ops sched_ops = { + .ttype = RTORT_RCU_SCHED, .init = rcu_sync_torture_init, .readlock = sched_torture_read_lock, .read_delay = rcu_read_delay, /* just reuse rcu's version. */ @@ -688,23 +745,59 @@ rcu_torture_fqs(void *arg) static int rcu_torture_writer(void *arg) { - bool exp; + unsigned long gp_snap; + bool gp_cond1 = gp_cond, gp_exp1 = gp_exp, gp_normal1 = gp_normal; + bool gp_sync1 = gp_sync; int i; struct rcu_torture *rp; - struct rcu_torture *rp1; struct rcu_torture *old_rp; static DEFINE_TORTURE_RANDOM(rand); + int synctype[] = { RTWS_DEF_FREE, RTWS_EXP_SYNC, + RTWS_COND_GET, RTWS_SYNC }; + int nsynctypes = 0; VERBOSE_TOROUT_STRING("rcu_torture_writer task started"); - set_user_nice(current, MAX_NICE); + + /* Initialize synctype[] array. If none set, take default. */ + if (!gp_cond1 && !gp_exp1 && !gp_normal1 && !gp_sync) + gp_cond1 = gp_exp1 = gp_normal1 = gp_sync1 = true; + if (gp_cond1 && cur_ops->get_state && cur_ops->cond_sync) + synctype[nsynctypes++] = RTWS_COND_GET; + else if (gp_cond && (!cur_ops->get_state || !cur_ops->cond_sync)) + pr_alert("rcu_torture_writer: gp_cond without primitives.\n"); + if (gp_exp1 && cur_ops->exp_sync) + synctype[nsynctypes++] = RTWS_EXP_SYNC; + else if (gp_exp && !cur_ops->exp_sync) + pr_alert("rcu_torture_writer: gp_exp without primitives.\n"); + if (gp_normal1 && cur_ops->deferred_free) + synctype[nsynctypes++] = RTWS_DEF_FREE; + else if (gp_normal && !cur_ops->deferred_free) + pr_alert("rcu_torture_writer: gp_normal without primitives.\n"); + if (gp_sync1 && cur_ops->sync) + synctype[nsynctypes++] = RTWS_SYNC; + else if (gp_sync && !cur_ops->sync) + pr_alert("rcu_torture_writer: gp_sync without primitives.\n"); + if (WARN_ONCE(nsynctypes == 0, + "rcu_torture_writer: No update-side primitives.\n")) { + /* + * No updates primitives, so don't try updating. + * The resulting test won't be testing much, hence the + * above WARN_ONCE(). + */ + rcu_torture_writer_state = RTWS_STOPPING; + torture_kthread_stopping("rcu_torture_writer"); + } do { + rcu_torture_writer_state = RTWS_FIXED_DELAY; schedule_timeout_uninterruptible(1); rp = rcu_torture_alloc(); if (rp == NULL) continue; rp->rtort_pipe_count = 0; + rcu_torture_writer_state = RTWS_DELAY; udelay(torture_random(&rand) & 0x3ff); + rcu_torture_writer_state = RTWS_REPLACE; old_rp = rcu_dereference_check(rcu_torture_current, current == writer_task); rp->rtort_mbtest = 1; @@ -716,35 +809,42 @@ rcu_torture_writer(void *arg) i = RCU_TORTURE_PIPE_LEN; atomic_inc(&rcu_torture_wcount[i]); old_rp->rtort_pipe_count++; - if (gp_normal == gp_exp) - exp = !!(torture_random(&rand) & 0x80); - else - exp = gp_exp; - if (!exp) { + switch (synctype[torture_random(&rand) % nsynctypes]) { + case RTWS_DEF_FREE: + rcu_torture_writer_state = RTWS_DEF_FREE; cur_ops->deferred_free(old_rp); - } else { + break; + case RTWS_EXP_SYNC: + rcu_torture_writer_state = RTWS_EXP_SYNC; cur_ops->exp_sync(); - list_add(&old_rp->rtort_free, - &rcu_torture_removed); - list_for_each_entry_safe(rp, rp1, - &rcu_torture_removed, - rtort_free) { - i = rp->rtort_pipe_count; - if (i > RCU_TORTURE_PIPE_LEN) - i = RCU_TORTURE_PIPE_LEN; - atomic_inc(&rcu_torture_wcount[i]); - if (++rp->rtort_pipe_count >= - RCU_TORTURE_PIPE_LEN) { - rp->rtort_mbtest = 0; - list_del(&rp->rtort_free); - rcu_torture_free(rp); - } - } + rcu_torture_pipe_update(old_rp); + break; + case RTWS_COND_GET: + rcu_torture_writer_state = RTWS_COND_GET; + gp_snap = cur_ops->get_state(); + i = torture_random(&rand) % 16; + if (i != 0) + schedule_timeout_interruptible(i); + udelay(torture_random(&rand) % 1000); + rcu_torture_writer_state = RTWS_COND_SYNC; + cur_ops->cond_sync(gp_snap); + rcu_torture_pipe_update(old_rp); + break; + case RTWS_SYNC: + rcu_torture_writer_state = RTWS_SYNC; + cur_ops->sync(); + rcu_torture_pipe_update(old_rp); + break; + default: + WARN_ON_ONCE(1); + break; } } rcutorture_record_progress(++rcu_torture_current_version); + rcu_torture_writer_state = RTWS_STUTTER; stutter_wait("rcu_torture_writer"); } while (!torture_must_stop()); + rcu_torture_writer_state = RTWS_STOPPING; torture_kthread_stopping("rcu_torture_writer"); return 0; } @@ -784,7 +884,7 @@ rcu_torture_fakewriter(void *arg) return 0; } -void rcutorture_trace_dump(void) +static void rcutorture_trace_dump(void) { static atomic_t beenhere = ATOMIC_INIT(0); @@ -918,11 +1018,13 @@ rcu_torture_reader(void *arg) __this_cpu_inc(rcu_torture_batch[completed]); preempt_enable(); cur_ops->readunlock(idx); - schedule(); + cond_resched(); stutter_wait("rcu_torture_reader"); } while (!torture_must_stop()); - if (irqreader && cur_ops->irq_capable) + if (irqreader && cur_ops->irq_capable) { del_timer_sync(&t); + destroy_timer_on_stack(&t); + } torture_kthread_stopping("rcu_torture_reader"); return 0; } @@ -937,6 +1039,7 @@ rcu_torture_printk(char *page) int i; long pipesummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 }; long batchsummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 }; + static unsigned long rtcv_snap = ULONG_MAX; for_each_possible_cpu(cpu) { for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) { @@ -997,6 +1100,22 @@ rcu_torture_printk(char *page) page += sprintf(page, "\n"); if (cur_ops->stats) cur_ops->stats(page); + if (rtcv_snap == rcu_torture_current_version && + rcu_torture_current != NULL) { + int __maybe_unused flags; + unsigned long __maybe_unused gpnum; + unsigned long __maybe_unused completed; + + rcutorture_get_gp_data(cur_ops->ttype, + &flags, &gpnum, &completed); + page += sprintf(page, + "??? Writer stall state %d g%lu c%lu f%#x\n", + rcu_torture_writer_state, + gpnum, completed, flags); + show_rcu_gp_kthreads(); + rcutorture_trace_dump(); + } + rtcv_snap = rcu_torture_current_version; } /* @@ -1146,7 +1265,7 @@ static int __init rcu_torture_stall_init(void) } /* Callback function for RCU barrier testing. */ -void rcu_torture_barrier_cbf(struct rcu_head *rcu) +static void rcu_torture_barrier_cbf(struct rcu_head *rcu) { atomic_inc(&barrier_cbs_invoked); } @@ -1416,7 +1535,8 @@ rcu_torture_init(void) &rcu_ops, &rcu_bh_ops, &rcu_busted_ops, &srcu_ops, &sched_ops, }; - torture_init_begin(torture_type, verbose, &rcutorture_runnable); + if (!torture_init_begin(torture_type, verbose, &rcutorture_runnable)) + return -EBUSY; /* Process args and tell the world that the torturer is on the job. */ for (i = 0; i < ARRAY_SIZE(torture_ops); i++) { @@ -1441,10 +1561,13 @@ rcu_torture_init(void) if (cur_ops->init) cur_ops->init(); /* no "goto unwind" prior to this point!!! */ - if (nreaders >= 0) + if (nreaders >= 0) { nrealreaders = nreaders; - else - nrealreaders = 2 * num_online_cpus(); + } else { + nrealreaders = num_online_cpus() - 1; + if (nrealreaders <= 0) + nrealreaders = 1; + } rcu_torture_print_module_parms(cur_ops, "Start of test"); /* Set up the freelist. */ @@ -1533,7 +1656,8 @@ rcu_torture_init(void) fqs_duration = 0; if (fqs_duration) { /* Create the fqs thread */ - torture_create_kthread(rcu_torture_fqs, NULL, fqs_task); + firsterr = torture_create_kthread(rcu_torture_fqs, NULL, + fqs_task); if (firsterr) goto unwind; } diff --git a/kernel/rcu/tiny_plugin.h b/kernel/rcu/tiny_plugin.h index 4315285205626f..858c5656912724 100644 --- a/kernel/rcu/tiny_plugin.h +++ b/kernel/rcu/tiny_plugin.h @@ -144,7 +144,7 @@ static void check_cpu_stall(struct rcu_ctrlblk *rcp) return; rcp->ticks_this_gp++; j = jiffies; - js = rcp->jiffies_stall; + js = ACCESS_ONCE(rcp->jiffies_stall); if (*rcp->curtail && ULONG_CMP_GE(j, js)) { pr_err("INFO: %s stall on CPU (%lu ticks this GP) idle=%llx (t=%lu jiffies q=%ld)\n", rcp->name, rcp->ticks_this_gp, rcu_dynticks_nesting, @@ -152,17 +152,17 @@ static void check_cpu_stall(struct rcu_ctrlblk *rcp) dump_stack(); } if (*rcp->curtail && ULONG_CMP_GE(j, js)) - rcp->jiffies_stall = jiffies + + ACCESS_ONCE(rcp->jiffies_stall) = jiffies + 3 * rcu_jiffies_till_stall_check() + 3; else if (ULONG_CMP_GE(j, js)) - rcp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check(); + ACCESS_ONCE(rcp->jiffies_stall) = jiffies + rcu_jiffies_till_stall_check(); } static void reset_cpu_stall_ticks(struct rcu_ctrlblk *rcp) { rcp->ticks_this_gp = 0; rcp->gp_start = jiffies; - rcp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check(); + ACCESS_ONCE(rcp->jiffies_stall) = jiffies + rcu_jiffies_till_stall_check(); } static void check_cpu_stalls(void) diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 0c47e300210ad6..a3959a15058a8a 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -101,7 +101,7 @@ DEFINE_PER_CPU(struct rcu_data, sname##_data) RCU_STATE_INITIALIZER(rcu_sched, 's', call_rcu_sched); RCU_STATE_INITIALIZER(rcu_bh, 'b', call_rcu_bh); -static struct rcu_state *rcu_state; +static struct rcu_state *rcu_state_p; LIST_HEAD(rcu_struct_flavors); /* Increase (but not decrease) the CONFIG_RCU_FANOUT_LEAF at boot time. */ @@ -243,7 +243,7 @@ static ulong jiffies_till_next_fqs = ULONG_MAX; module_param(jiffies_till_first_fqs, ulong, 0644); module_param(jiffies_till_next_fqs, ulong, 0644); -static void rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp, +static bool rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp); static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *rsp, bool *isidle, @@ -270,6 +270,15 @@ long rcu_batches_completed_bh(void) } EXPORT_SYMBOL_GPL(rcu_batches_completed_bh); +/* + * Force a quiescent state. + */ +void rcu_force_quiescent_state(void) +{ + force_quiescent_state(rcu_state_p); +} +EXPORT_SYMBOL_GPL(rcu_force_quiescent_state); + /* * Force a quiescent state for RCU BH. */ @@ -279,6 +288,21 @@ void rcu_bh_force_quiescent_state(void) } EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state); +/* + * Show the state of the grace-period kthreads. + */ +void show_rcu_gp_kthreads(void) +{ + struct rcu_state *rsp; + + for_each_rcu_flavor(rsp) { + pr_info("%s: wait state: %d ->state: %#lx\n", + rsp->name, rsp->gp_state, rsp->gp_kthread->state); + /* sched_show_task(rsp->gp_kthread); */ + } +} +EXPORT_SYMBOL_GPL(show_rcu_gp_kthreads); + /* * Record the number of times rcutorture tests have been initiated and * terminated. This information allows the debugfs tracing stats to be @@ -293,6 +317,24 @@ void rcutorture_record_test_transition(void) } EXPORT_SYMBOL_GPL(rcutorture_record_test_transition); +/* + * Send along grace-period-related data for rcutorture diagnostics. + */ +void rcutorture_get_gp_data(enum rcutorture_type test_type, int *flags, + unsigned long *gpnum, unsigned long *completed) +{ + if (test_type == RTORT_SRCU || test_type == RTORT_BUSTED) { + *flags = 0; + *gpnum = 0; + *completed = 0; + return; + } + *flags = ACCESS_ONCE(rcu_state_p->gp_flags); + *gpnum = ACCESS_ONCE(rcu_state_p->gpnum); + *completed = ACCESS_ONCE(rcu_state_p->completed); +} +EXPORT_SYMBOL_GPL(rcutorture_get_gp_data); + /* * Record the number of writer passes through the current rcutorture test. * This is also used to correlate debugfs tracing stats with the rcutorture @@ -323,6 +365,28 @@ cpu_has_callbacks_ready_to_invoke(struct rcu_data *rdp) rdp->nxttail[RCU_DONE_TAIL] != NULL; } +/* + * Return the root node of the specified rcu_state structure. + */ +static struct rcu_node *rcu_get_root(struct rcu_state *rsp) +{ + return &rsp->node[0]; +} + +/* + * Is there any need for future grace periods? + * Interrupts must be disabled. If the caller does not hold the root + * rnp_node structure's ->lock, the results are advisory only. + */ +static int rcu_future_needs_gp(struct rcu_state *rsp) +{ + struct rcu_node *rnp = rcu_get_root(rsp); + int idx = (ACCESS_ONCE(rnp->completed) + 1) & 0x1; + int *fp = &rnp->need_future_gp[idx]; + + return ACCESS_ONCE(*fp); +} + /* * Does the current CPU require a not-yet-started grace period? * The caller must have disabled interrupts to prevent races with @@ -335,7 +399,7 @@ cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp) if (rcu_gp_in_progress(rsp)) return 0; /* No, a grace period is already in progress. */ - if (rcu_nocb_needs_gp(rsp)) + if (rcu_future_needs_gp(rsp)) return 1; /* Yes, a no-CBs CPU needs one. */ if (!rdp->nxttail[RCU_NEXT_TAIL]) return 0; /* No, this is a no-CBs (or offline) CPU. */ @@ -349,14 +413,6 @@ cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp) return 0; /* No grace period needed. */ } -/* - * Return the root node of the specified rcu_state structure. - */ -static struct rcu_node *rcu_get_root(struct rcu_state *rsp) -{ - return &rsp->node[0]; -} - /* * rcu_eqs_enter_common - current CPU is moving towards extended quiescent state * @@ -387,9 +443,9 @@ static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval, } rcu_prepare_for_idle(smp_processor_id()); /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ - smp_mb__before_atomic_inc(); /* See above. */ + smp_mb__before_atomic(); /* See above. */ atomic_inc(&rdtp->dynticks); - smp_mb__after_atomic_inc(); /* Force ordering with next sojourn. */ + smp_mb__after_atomic(); /* Force ordering with next sojourn. */ WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1); /* @@ -507,10 +563,10 @@ void rcu_irq_exit(void) static void rcu_eqs_exit_common(struct rcu_dynticks *rdtp, long long oldval, int user) { - smp_mb__before_atomic_inc(); /* Force ordering w/previous sojourn. */ + smp_mb__before_atomic(); /* Force ordering w/previous sojourn. */ atomic_inc(&rdtp->dynticks); /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ - smp_mb__after_atomic_inc(); /* See above. */ + smp_mb__after_atomic(); /* See above. */ WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); rcu_cleanup_after_idle(smp_processor_id()); trace_rcu_dyntick(TPS("End"), oldval, rdtp->dynticks_nesting); @@ -635,10 +691,10 @@ void rcu_nmi_enter(void) (atomic_read(&rdtp->dynticks) & 0x1)) return; rdtp->dynticks_nmi_nesting++; - smp_mb__before_atomic_inc(); /* Force delay from prior write. */ + smp_mb__before_atomic(); /* Force delay from prior write. */ atomic_inc(&rdtp->dynticks); /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ - smp_mb__after_atomic_inc(); /* See above. */ + smp_mb__after_atomic(); /* See above. */ WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); } @@ -657,9 +713,9 @@ void rcu_nmi_exit(void) --rdtp->dynticks_nmi_nesting != 0) return; /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ - smp_mb__before_atomic_inc(); /* See above. */ + smp_mb__before_atomic(); /* See above. */ atomic_inc(&rdtp->dynticks); - smp_mb__after_atomic_inc(); /* Force delay to next write. */ + smp_mb__after_atomic(); /* Force delay to next write. */ WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1); } @@ -758,7 +814,12 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp, { rdp->dynticks_snap = atomic_add_return(0, &rdp->dynticks->dynticks); rcu_sysidle_check_cpu(rdp, isidle, maxj); - return (rdp->dynticks_snap & 0x1) == 0; + if ((rdp->dynticks_snap & 0x1) == 0) { + trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("dti")); + return 1; + } else { + return 0; + } } /* @@ -834,7 +895,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp, * we will beat on the first one until it gets unstuck, then move * to the next. Only do this for the primary flavor of RCU. */ - if (rdp->rsp == rcu_state && + if (rdp->rsp == rcu_state_p && ULONG_CMP_GE(jiffies, rdp->rsp->jiffies_resched)) { rdp->rsp->jiffies_resched += 5; resched_cpu(rdp->cpu); @@ -851,7 +912,7 @@ static void record_gp_stall_check_time(struct rcu_state *rsp) rsp->gp_start = j; smp_wmb(); /* Record start time before stall time. */ j1 = rcu_jiffies_till_stall_check(); - rsp->jiffies_stall = j + j1; + ACCESS_ONCE(rsp->jiffies_stall) = j + j1; rsp->jiffies_resched = j + j1 / 2; } @@ -890,12 +951,12 @@ static void print_other_cpu_stall(struct rcu_state *rsp) /* Only let one CPU complain about others per time interval. */ raw_spin_lock_irqsave(&rnp->lock, flags); - delta = jiffies - rsp->jiffies_stall; + delta = jiffies - ACCESS_ONCE(rsp->jiffies_stall); if (delta < RCU_STALL_RAT_DELAY || !rcu_gp_in_progress(rsp)) { raw_spin_unlock_irqrestore(&rnp->lock, flags); return; } - rsp->jiffies_stall = jiffies + 3 * rcu_jiffies_till_stall_check() + 3; + ACCESS_ONCE(rsp->jiffies_stall) = jiffies + 3 * rcu_jiffies_till_stall_check() + 3; raw_spin_unlock_irqrestore(&rnp->lock, flags); /* @@ -932,9 +993,9 @@ static void print_other_cpu_stall(struct rcu_state *rsp) print_cpu_stall_info_end(); for_each_possible_cpu(cpu) totqlen += per_cpu_ptr(rsp->rda, cpu)->qlen; - pr_cont("(detected by %d, t=%ld jiffies, g=%lu, c=%lu, q=%lu)\n", + pr_cont("(detected by %d, t=%ld jiffies, g=%ld, c=%ld, q=%lu)\n", smp_processor_id(), (long)(jiffies - rsp->gp_start), - rsp->gpnum, rsp->completed, totqlen); + (long)rsp->gpnum, (long)rsp->completed, totqlen); if (ndetected == 0) pr_err("INFO: Stall ended before state dump start\n"); else if (!trigger_all_cpu_backtrace()) @@ -947,12 +1008,6 @@ static void print_other_cpu_stall(struct rcu_state *rsp) force_quiescent_state(rsp); /* Kick them all. */ } -/* - * This function really isn't for public consumption, but RCU is special in - * that context switches can allow the state machine to make progress. - */ -extern void resched_cpu(int cpu); - static void print_cpu_stall(struct rcu_state *rsp) { int cpu; @@ -971,14 +1026,15 @@ static void print_cpu_stall(struct rcu_state *rsp) print_cpu_stall_info_end(); for_each_possible_cpu(cpu) totqlen += per_cpu_ptr(rsp->rda, cpu)->qlen; - pr_cont(" (t=%lu jiffies g=%lu c=%lu q=%lu)\n", - jiffies - rsp->gp_start, rsp->gpnum, rsp->completed, totqlen); + pr_cont(" (t=%lu jiffies g=%ld c=%ld q=%lu)\n", + jiffies - rsp->gp_start, + (long)rsp->gpnum, (long)rsp->completed, totqlen); if (!trigger_all_cpu_backtrace()) dump_stack(); raw_spin_lock_irqsave(&rnp->lock, flags); - if (ULONG_CMP_GE(jiffies, rsp->jiffies_stall)) - rsp->jiffies_stall = jiffies + + if (ULONG_CMP_GE(jiffies, ACCESS_ONCE(rsp->jiffies_stall))) + ACCESS_ONCE(rsp->jiffies_stall) = jiffies + 3 * rcu_jiffies_till_stall_check() + 3; raw_spin_unlock_irqrestore(&rnp->lock, flags); @@ -1062,7 +1118,7 @@ void rcu_cpu_stall_reset(void) struct rcu_state *rsp; for_each_rcu_flavor(rsp) - rsp->jiffies_stall = jiffies + ULONG_MAX / 2; + ACCESS_ONCE(rsp->jiffies_stall) = jiffies + ULONG_MAX / 2; } /* @@ -1123,15 +1179,18 @@ static void trace_rcu_future_gp(struct rcu_node *rnp, struct rcu_data *rdp, /* * Start some future grace period, as needed to handle newly arrived * callbacks. The required future grace periods are recorded in each - * rcu_node structure's ->need_future_gp field. + * rcu_node structure's ->need_future_gp field. Returns true if there + * is reason to awaken the grace-period kthread. * * The caller must hold the specified rcu_node structure's ->lock. */ -static unsigned long __maybe_unused -rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp) +static bool __maybe_unused +rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp, + unsigned long *c_out) { unsigned long c; int i; + bool ret = false; struct rcu_node *rnp_root = rcu_get_root(rdp->rsp); /* @@ -1142,7 +1201,7 @@ rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp) trace_rcu_future_gp(rnp, rdp, c, TPS("Startleaf")); if (rnp->need_future_gp[c & 0x1]) { trace_rcu_future_gp(rnp, rdp, c, TPS("Prestartleaf")); - return c; + goto out; } /* @@ -1156,7 +1215,7 @@ rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp) ACCESS_ONCE(rnp->gpnum) != ACCESS_ONCE(rnp->completed)) { rnp->need_future_gp[c & 0x1]++; trace_rcu_future_gp(rnp, rdp, c, TPS("Startedleaf")); - return c; + goto out; } /* @@ -1197,12 +1256,15 @@ rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp) trace_rcu_future_gp(rnp, rdp, c, TPS("Startedleafroot")); } else { trace_rcu_future_gp(rnp, rdp, c, TPS("Startedroot")); - rcu_start_gp_advanced(rdp->rsp, rnp_root, rdp); + ret = rcu_start_gp_advanced(rdp->rsp, rnp_root, rdp); } unlock_out: if (rnp != rnp_root) raw_spin_unlock(&rnp_root->lock); - return c; +out: + if (c_out != NULL) + *c_out = c; + return ret; } /* @@ -1225,6 +1287,22 @@ static int rcu_future_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) return needmore; } +/* + * Awaken the grace-period kthread for the specified flavor of RCU. + * Don't do a self-awaken, and don't bother awakening when there is + * nothing for the grace-period kthread to do (as in several CPUs + * raced to awaken, and we lost), and finally don't try to awaken + * a kthread that has not yet been created. + */ +static void rcu_gp_kthread_wake(struct rcu_state *rsp) +{ + if (current == rsp->gp_kthread || + !ACCESS_ONCE(rsp->gp_flags) || + !rsp->gp_kthread) + return; + wake_up(&rsp->gp_wq); +} + /* * If there is room, assign a ->completed number to any callbacks on * this CPU that have not already been assigned. Also accelerate any @@ -1232,19 +1310,21 @@ static int rcu_future_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) * since proven to be too conservative, which can happen if callbacks get * assigned a ->completed number while RCU is idle, but with reference to * a non-root rcu_node structure. This function is idempotent, so it does - * not hurt to call it repeatedly. + * not hurt to call it repeatedly. Returns an flag saying that we should + * awaken the RCU grace-period kthread. * * The caller must hold rnp->lock with interrupts disabled. */ -static void rcu_accelerate_cbs(struct rcu_state *rsp, struct rcu_node *rnp, +static bool rcu_accelerate_cbs(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) { unsigned long c; int i; + bool ret; /* If the CPU has no callbacks, nothing to do. */ if (!rdp->nxttail[RCU_NEXT_TAIL] || !*rdp->nxttail[RCU_DONE_TAIL]) - return; + return false; /* * Starting from the sublist containing the callbacks most @@ -1273,7 +1353,7 @@ static void rcu_accelerate_cbs(struct rcu_state *rsp, struct rcu_node *rnp, * be grouped into. */ if (++i >= RCU_NEXT_TAIL) - return; + return false; /* * Assign all subsequent callbacks' ->completed number to the next @@ -1285,13 +1365,14 @@ static void rcu_accelerate_cbs(struct rcu_state *rsp, struct rcu_node *rnp, rdp->nxtcompleted[i] = c; } /* Record any needed additional grace periods. */ - rcu_start_future_gp(rnp, rdp); + ret = rcu_start_future_gp(rnp, rdp, NULL); /* Trace depending on how much we were able to accelerate. */ if (!*rdp->nxttail[RCU_WAIT_TAIL]) trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("AccWaitCB")); else trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("AccReadyCB")); + return ret; } /* @@ -1300,17 +1381,18 @@ static void rcu_accelerate_cbs(struct rcu_state *rsp, struct rcu_node *rnp, * assign ->completed numbers to any callbacks in the RCU_NEXT_TAIL * sublist. This function is idempotent, so it does not hurt to * invoke it repeatedly. As long as it is not invoked -too- often... + * Returns true if the RCU grace-period kthread needs to be awakened. * * The caller must hold rnp->lock with interrupts disabled. */ -static void rcu_advance_cbs(struct rcu_state *rsp, struct rcu_node *rnp, +static bool rcu_advance_cbs(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) { int i, j; /* If the CPU has no callbacks, nothing to do. */ if (!rdp->nxttail[RCU_NEXT_TAIL] || !*rdp->nxttail[RCU_DONE_TAIL]) - return; + return false; /* * Find all callbacks whose ->completed numbers indicate that they @@ -1334,26 +1416,30 @@ static void rcu_advance_cbs(struct rcu_state *rsp, struct rcu_node *rnp, } /* Classify any remaining callbacks. */ - rcu_accelerate_cbs(rsp, rnp, rdp); + return rcu_accelerate_cbs(rsp, rnp, rdp); } /* * Update CPU-local rcu_data state to record the beginnings and ends of * grace periods. The caller must hold the ->lock of the leaf rcu_node * structure corresponding to the current CPU, and must have irqs disabled. + * Returns true if the grace-period kthread needs to be awakened. */ -static void __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) +static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp, + struct rcu_data *rdp) { + bool ret; + /* Handle the ends of any preceding grace periods first. */ if (rdp->completed == rnp->completed) { /* No grace period end, so just accelerate recent callbacks. */ - rcu_accelerate_cbs(rsp, rnp, rdp); + ret = rcu_accelerate_cbs(rsp, rnp, rdp); } else { /* Advance callbacks. */ - rcu_advance_cbs(rsp, rnp, rdp); + ret = rcu_advance_cbs(rsp, rnp, rdp); /* Remember that we saw this grace-period completion. */ rdp->completed = rnp->completed; @@ -1372,11 +1458,13 @@ static void __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp, struc rdp->qs_pending = !!(rnp->qsmask & rdp->grpmask); zero_cpu_stall_ticks(rdp); } + return ret; } static void note_gp_changes(struct rcu_state *rsp, struct rcu_data *rdp) { unsigned long flags; + bool needwake; struct rcu_node *rnp; local_irq_save(flags); @@ -1388,8 +1476,10 @@ static void note_gp_changes(struct rcu_state *rsp, struct rcu_data *rdp) return; } smp_mb__after_unlock_lock(); - __note_gp_changes(rsp, rnp, rdp); + needwake = __note_gp_changes(rsp, rnp, rdp); raw_spin_unlock_irqrestore(&rnp->lock, flags); + if (needwake) + rcu_gp_kthread_wake(rsp); } /* @@ -1403,12 +1493,12 @@ static int rcu_gp_init(struct rcu_state *rsp) rcu_bind_gp_kthread(); raw_spin_lock_irq(&rnp->lock); smp_mb__after_unlock_lock(); - if (rsp->gp_flags == 0) { + if (!ACCESS_ONCE(rsp->gp_flags)) { /* Spurious wakeup, tell caller to go back to sleep. */ raw_spin_unlock_irq(&rnp->lock); return 0; } - rsp->gp_flags = 0; /* Clear all flags: New grace period. */ + ACCESS_ONCE(rsp->gp_flags) = 0; /* Clear all flags: New grace period. */ if (WARN_ON_ONCE(rcu_gp_in_progress(rsp))) { /* @@ -1453,7 +1543,7 @@ static int rcu_gp_init(struct rcu_state *rsp) WARN_ON_ONCE(rnp->completed != rsp->completed); ACCESS_ONCE(rnp->completed) = rsp->completed; if (rnp == rdp->mynode) - __note_gp_changes(rsp, rnp, rdp); + (void)__note_gp_changes(rsp, rnp, rdp); rcu_preempt_boost_start_gp(rnp); trace_rcu_grace_period_init(rsp->name, rnp->gpnum, rnp->level, rnp->grplo, @@ -1501,7 +1591,7 @@ static int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in) if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) { raw_spin_lock_irq(&rnp->lock); smp_mb__after_unlock_lock(); - rsp->gp_flags &= ~RCU_GP_FLAG_FQS; + ACCESS_ONCE(rsp->gp_flags) &= ~RCU_GP_FLAG_FQS; raw_spin_unlock_irq(&rnp->lock); } return fqs_state; @@ -1513,6 +1603,7 @@ static int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in) static void rcu_gp_cleanup(struct rcu_state *rsp) { unsigned long gp_duration; + bool needgp = false; int nocb = 0; struct rcu_data *rdp; struct rcu_node *rnp = rcu_get_root(rsp); @@ -1548,7 +1639,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp) ACCESS_ONCE(rnp->completed) = rsp->gpnum; rdp = this_cpu_ptr(rsp->rda); if (rnp == rdp->mynode) - __note_gp_changes(rsp, rnp, rdp); + needgp = __note_gp_changes(rsp, rnp, rdp) || needgp; /* smp_mb() provided by prior unlock-lock pair. */ nocb += rcu_future_gp_cleanup(rsp, rnp); raw_spin_unlock_irq(&rnp->lock); @@ -1564,9 +1655,10 @@ static void rcu_gp_cleanup(struct rcu_state *rsp) trace_rcu_grace_period(rsp->name, rsp->completed, TPS("end")); rsp->fqs_state = RCU_GP_IDLE; rdp = this_cpu_ptr(rsp->rda); - rcu_advance_cbs(rsp, rnp, rdp); /* Reduce false positives below. */ - if (cpu_needs_another_gp(rsp, rdp)) { - rsp->gp_flags = RCU_GP_FLAG_INIT; + /* Advance CBs to reduce false positives below. */ + needgp = rcu_advance_cbs(rsp, rnp, rdp) || needgp; + if (needgp || cpu_needs_another_gp(rsp, rdp)) { + ACCESS_ONCE(rsp->gp_flags) = RCU_GP_FLAG_INIT; trace_rcu_grace_period(rsp->name, ACCESS_ONCE(rsp->gpnum), TPS("newreq")); @@ -1593,6 +1685,7 @@ static int __noreturn rcu_gp_kthread(void *arg) trace_rcu_grace_period(rsp->name, ACCESS_ONCE(rsp->gpnum), TPS("reqwait")); + rsp->gp_state = RCU_GP_WAIT_GPS; wait_event_interruptible(rsp->gp_wq, ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_INIT); @@ -1620,6 +1713,7 @@ static int __noreturn rcu_gp_kthread(void *arg) trace_rcu_grace_period(rsp->name, ACCESS_ONCE(rsp->gpnum), TPS("fqswait")); + rsp->gp_state = RCU_GP_WAIT_FQS; ret = wait_event_interruptible_timeout(rsp->gp_wq, ((gf = ACCESS_ONCE(rsp->gp_flags)) & RCU_GP_FLAG_FQS) || @@ -1665,14 +1759,6 @@ static int __noreturn rcu_gp_kthread(void *arg) } } -static void rsp_wakeup(struct irq_work *work) -{ - struct rcu_state *rsp = container_of(work, struct rcu_state, wakeup_work); - - /* Wake up rcu_gp_kthread() to start the grace period. */ - wake_up(&rsp->gp_wq); -} - /* * Start a new RCU grace period if warranted, re-initializing the hierarchy * in preparation for detecting the next grace period. The caller must hold @@ -1681,8 +1767,10 @@ static void rsp_wakeup(struct irq_work *work) * Note that it is legal for a dying CPU (which is marked as offline) to * invoke this function. This can happen when the dying CPU reports its * quiescent state. + * + * Returns true if the grace-period kthread must be awakened. */ -static void +static bool rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) { @@ -1693,20 +1781,18 @@ rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp, * or a grace period is already in progress. * Either way, don't start a new grace period. */ - return; + return false; } - rsp->gp_flags = RCU_GP_FLAG_INIT; + ACCESS_ONCE(rsp->gp_flags) = RCU_GP_FLAG_INIT; trace_rcu_grace_period(rsp->name, ACCESS_ONCE(rsp->gpnum), TPS("newreq")); /* * We can't do wakeups while holding the rnp->lock, as that * could cause possible deadlocks with the rq->lock. Defer - * the wakeup to interrupt context. And don't bother waking - * up the running kthread. + * the wakeup to our caller. */ - if (current != rsp->gp_kthread) - irq_work_queue(&rsp->wakeup_work); + return true; } /* @@ -1715,12 +1801,14 @@ rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp, * is invoked indirectly from rcu_advance_cbs(), which would result in * endless recursion -- or would do so if it wasn't for the self-deadlock * that is encountered beforehand. + * + * Returns true if the grace-period kthread needs to be awakened. */ -static void -rcu_start_gp(struct rcu_state *rsp) +static bool rcu_start_gp(struct rcu_state *rsp) { struct rcu_data *rdp = this_cpu_ptr(rsp->rda); struct rcu_node *rnp = rcu_get_root(rsp); + bool ret = false; /* * If there is no grace period in progress right now, any @@ -1730,8 +1818,9 @@ rcu_start_gp(struct rcu_state *rsp) * resulting in pointless grace periods. So, advance callbacks * then start the grace period! */ - rcu_advance_cbs(rsp, rnp, rdp); - rcu_start_gp_advanced(rsp, rnp, rdp); + ret = rcu_advance_cbs(rsp, rnp, rdp) || ret; + ret = rcu_start_gp_advanced(rsp, rnp, rdp) || ret; + return ret; } /* @@ -1820,6 +1909,7 @@ rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp) { unsigned long flags; unsigned long mask; + bool needwake; struct rcu_node *rnp; rnp = rdp->mynode; @@ -1848,9 +1938,11 @@ rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp) * This GP can't end until cpu checks in, so all of our * callbacks can be processed during the next GP. */ - rcu_accelerate_cbs(rsp, rnp, rdp); + needwake = rcu_accelerate_cbs(rsp, rnp, rdp); rcu_report_qs_rnp(mask, rsp, rnp, flags); /* rlses rnp->lock */ + if (needwake) + rcu_gp_kthread_wake(rsp); } } @@ -1951,7 +2043,7 @@ rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp, static void rcu_adopt_orphan_cbs(struct rcu_state *rsp, unsigned long flags) { int i; - struct rcu_data *rdp = __this_cpu_ptr(rsp->rda); + struct rcu_data *rdp = raw_cpu_ptr(rsp->rda); /* No-CBs CPUs are handled specially. */ if (rcu_nocb_adopt_orphan_cbs(rsp, rdp, flags)) @@ -2320,7 +2412,7 @@ static void force_quiescent_state(struct rcu_state *rsp) raw_spin_unlock_irqrestore(&rnp_old->lock, flags); return; /* Someone beat us to it. */ } - rsp->gp_flags |= RCU_GP_FLAG_FQS; + ACCESS_ONCE(rsp->gp_flags) |= RCU_GP_FLAG_FQS; raw_spin_unlock_irqrestore(&rnp_old->lock, flags); wake_up(&rsp->gp_wq); /* Memory barrier implied by wake_up() path. */ } @@ -2334,7 +2426,8 @@ static void __rcu_process_callbacks(struct rcu_state *rsp) { unsigned long flags; - struct rcu_data *rdp = __this_cpu_ptr(rsp->rda); + bool needwake; + struct rcu_data *rdp = raw_cpu_ptr(rsp->rda); WARN_ON_ONCE(rdp->beenonline == 0); @@ -2345,8 +2438,10 @@ __rcu_process_callbacks(struct rcu_state *rsp) local_irq_save(flags); if (cpu_needs_another_gp(rsp, rdp)) { raw_spin_lock(&rcu_get_root(rsp)->lock); /* irqs disabled. */ - rcu_start_gp(rsp); + needwake = rcu_start_gp(rsp); raw_spin_unlock_irqrestore(&rcu_get_root(rsp)->lock, flags); + if (needwake) + rcu_gp_kthread_wake(rsp); } else { local_irq_restore(flags); } @@ -2404,6 +2499,8 @@ static void invoke_rcu_core(void) static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp, struct rcu_head *head, unsigned long flags) { + bool needwake; + /* * If called from an extended quiescent state, invoke the RCU * core in order to force a re-evaluation of RCU's idleness. @@ -2433,8 +2530,10 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp, raw_spin_lock(&rnp_root->lock); smp_mb__after_unlock_lock(); - rcu_start_gp(rsp); + needwake = rcu_start_gp(rsp); raw_spin_unlock(&rnp_root->lock); + if (needwake) + rcu_gp_kthread_wake(rsp); } else { /* Give the grace period a kick. */ rdp->blimit = LONG_MAX; @@ -2536,6 +2635,20 @@ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) } EXPORT_SYMBOL_GPL(call_rcu_bh); +/* + * Queue an RCU callback for lazy invocation after a grace period. + * This will likely be later named something like "call_rcu_lazy()", + * but this change will require some way of tagging the lazy RCU + * callbacks in the list of pending callbacks. Until then, this + * function may only be called from __kfree_rcu(). + */ +void kfree_call_rcu(struct rcu_head *head, + void (*func)(struct rcu_head *rcu)) +{ + __call_rcu(head, func, rcu_state_p, -1, 1); +} +EXPORT_SYMBOL_GPL(kfree_call_rcu); + /* * Because a context switch is a grace period for RCU-sched and RCU-bh, * any blocking grace-period wait automatically implies a grace period @@ -2659,7 +2772,7 @@ unsigned long get_state_synchronize_rcu(void) * time-consuming work between get_state_synchronize_rcu() * and cond_synchronize_rcu(). */ - return smp_load_acquire(&rcu_state->gpnum); + return smp_load_acquire(&rcu_state_p->gpnum); } EXPORT_SYMBOL_GPL(get_state_synchronize_rcu); @@ -2685,7 +2798,7 @@ void cond_synchronize_rcu(unsigned long oldstate) * Ensure that this load happens before any RCU-destructive * actions the caller might carry out after we return. */ - newstate = smp_load_acquire(&rcu_state->completed); + newstate = smp_load_acquire(&rcu_state_p->completed); if (ULONG_CMP_GE(oldstate, newstate)) synchronize_rcu(); } @@ -2790,7 +2903,7 @@ void synchronize_sched_expedited(void) s = atomic_long_read(&rsp->expedited_done); if (ULONG_CMP_GE((ulong)s, (ulong)firstsnap)) { /* ensure test happens before caller kfree */ - smp_mb__before_atomic_inc(); /* ^^^ */ + smp_mb__before_atomic(); /* ^^^ */ atomic_long_inc(&rsp->expedited_workdone1); return; } @@ -2808,7 +2921,7 @@ void synchronize_sched_expedited(void) s = atomic_long_read(&rsp->expedited_done); if (ULONG_CMP_GE((ulong)s, (ulong)firstsnap)) { /* ensure test happens before caller kfree */ - smp_mb__before_atomic_inc(); /* ^^^ */ + smp_mb__before_atomic(); /* ^^^ */ atomic_long_inc(&rsp->expedited_workdone2); return; } @@ -2837,7 +2950,7 @@ void synchronize_sched_expedited(void) s = atomic_long_read(&rsp->expedited_done); if (ULONG_CMP_GE((ulong)s, (ulong)snap)) { /* ensure test happens before caller kfree */ - smp_mb__before_atomic_inc(); /* ^^^ */ + smp_mb__before_atomic(); /* ^^^ */ atomic_long_inc(&rsp->expedited_done_lost); break; } @@ -2988,7 +3101,7 @@ static void rcu_barrier_callback(struct rcu_head *rhp) static void rcu_barrier_func(void *type) { struct rcu_state *rsp = type; - struct rcu_data *rdp = __this_cpu_ptr(rsp->rda); + struct rcu_data *rdp = raw_cpu_ptr(rsp->rda); _rcu_barrier_trace(rsp, "IRQ", -1, rsp->n_barrier_done); atomic_inc(&rsp->barrier_cpu_count); @@ -3160,7 +3273,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp) * that this CPU cannot possibly have any RCU callbacks in flight yet. */ static void -rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible) +rcu_init_percpu_data(int cpu, struct rcu_state *rsp) { unsigned long flags; unsigned long mask; @@ -3173,7 +3286,6 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible) /* Set up local state, ensuring consistent view of global state. */ raw_spin_lock_irqsave(&rnp->lock, flags); rdp->beenonline = 1; /* We have now been online. */ - rdp->preemptible = preemptible; rdp->qlen_last_fqs_check = 0; rdp->n_force_qs_snap = rsp->n_force_qs; rdp->blimit = blimit; @@ -3217,8 +3329,7 @@ static void rcu_prepare_cpu(int cpu) struct rcu_state *rsp; for_each_rcu_flavor(rsp) - rcu_init_percpu_data(cpu, rsp, - strcmp(rsp->name, "rcu_preempt") == 0); + rcu_init_percpu_data(cpu, rsp); } /* @@ -3228,7 +3339,7 @@ static int rcu_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { long cpu = (long)hcpu; - struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu); + struct rcu_data *rdp = per_cpu_ptr(rcu_state_p->rda, cpu); struct rcu_node *rnp = rdp->mynode; struct rcu_state *rsp; @@ -3402,8 +3513,8 @@ static void __init rcu_init_one(struct rcu_state *rsp, rnp->qsmaskinit = 0; rnp->grplo = j * cpustride; rnp->grphi = (j + 1) * cpustride - 1; - if (rnp->grphi >= NR_CPUS) - rnp->grphi = NR_CPUS - 1; + if (rnp->grphi >= nr_cpu_ids) + rnp->grphi = nr_cpu_ids - 1; if (i == 0) { rnp->grpnum = 0; rnp->grpmask = 0; @@ -3422,7 +3533,6 @@ static void __init rcu_init_one(struct rcu_state *rsp, rsp->rda = rda; init_waitqueue_head(&rsp->gp_wq); - init_irq_work(&rsp->wakeup_work, rsp_wakeup); rnp = rsp->level[rcu_num_lvls - 1]; for_each_possible_cpu(i) { while (i > rnp->grphi) diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 75dc3c39a02a11..bf2c1e66969172 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -252,7 +252,6 @@ struct rcu_data { bool passed_quiesce; /* User-mode/idle loop etc. */ bool qs_pending; /* Core waits for quiesc state. */ bool beenonline; /* CPU online at least once. */ - bool preemptible; /* Preemptible RCU? */ struct rcu_node *mynode; /* This CPU's leaf of hierarchy */ unsigned long grpmask; /* Mask to apply to leaf qsmask. */ #ifdef CONFIG_RCU_CPU_STALL_INFO @@ -406,7 +405,8 @@ struct rcu_state { unsigned long completed; /* # of last completed gp. */ struct task_struct *gp_kthread; /* Task for grace periods. */ wait_queue_head_t gp_wq; /* Where GP task waits. */ - int gp_flags; /* Commands for GP task. */ + short gp_flags; /* Commands for GP task. */ + short gp_state; /* GP kthread sleep state. */ /* End of fields guarded by root rcu_node's lock. */ @@ -462,13 +462,17 @@ struct rcu_state { const char *name; /* Name of structure. */ char abbr; /* Abbreviated name. */ struct list_head flavors; /* List of RCU flavors. */ - struct irq_work wakeup_work; /* Postponed wakeups */ }; /* Values for rcu_state structure's gp_flags field. */ #define RCU_GP_FLAG_INIT 0x1 /* Need grace-period initialization. */ #define RCU_GP_FLAG_FQS 0x2 /* Need grace-period quiescent-state forcing. */ +/* Values for rcu_state structure's gp_flags field. */ +#define RCU_GP_WAIT_INIT 0 /* Initial state. */ +#define RCU_GP_WAIT_GPS 1 /* Wait for grace-period start. */ +#define RCU_GP_WAIT_FQS 2 /* Wait for force-quiescent-state time. */ + extern struct list_head rcu_struct_flavors; /* Sequence through rcu_state structures for each RCU flavor. */ @@ -547,7 +551,6 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu); static void print_cpu_stall_info_end(void); static void zero_cpu_stall_ticks(struct rcu_data *rdp); static void increment_cpu_stall_ticks(void); -static int rcu_nocb_needs_gp(struct rcu_state *rsp); static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq); static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp); static void rcu_init_one_nocb(struct rcu_node *rnp); diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 962d1d589929e2..cbc2c45265e2a7 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -116,7 +116,7 @@ static void __init rcu_bootup_announce_oddness(void) #ifdef CONFIG_TREE_PREEMPT_RCU RCU_STATE_INITIALIZER(rcu_preempt, 'p', call_rcu); -static struct rcu_state *rcu_state = &rcu_preempt_state; +static struct rcu_state *rcu_state_p = &rcu_preempt_state; static int rcu_preempted_readers_exp(struct rcu_node *rnp); @@ -148,15 +148,6 @@ long rcu_batches_completed(void) } EXPORT_SYMBOL_GPL(rcu_batches_completed); -/* - * Force a quiescent state for preemptible RCU. - */ -void rcu_force_quiescent_state(void) -{ - force_quiescent_state(&rcu_preempt_state); -} -EXPORT_SYMBOL_GPL(rcu_force_quiescent_state); - /* * Record a preemptible-RCU quiescent state for the specified CPU. Note * that this just means that the task currently running on the CPU is @@ -688,20 +679,6 @@ void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) } EXPORT_SYMBOL_GPL(call_rcu); -/* - * Queue an RCU callback for lazy invocation after a grace period. - * This will likely be later named something like "call_rcu_lazy()", - * but this change will require some way of tagging the lazy RCU - * callbacks in the list of pending callbacks. Until then, this - * function may only be called from __kfree_rcu(). - */ -void kfree_call_rcu(struct rcu_head *head, - void (*func)(struct rcu_head *rcu)) -{ - __call_rcu(head, func, &rcu_preempt_state, -1, 1); -} -EXPORT_SYMBOL_GPL(kfree_call_rcu); - /** * synchronize_rcu - wait until a grace period has elapsed. * @@ -970,7 +947,7 @@ void exit_rcu(void) #else /* #ifdef CONFIG_TREE_PREEMPT_RCU */ -static struct rcu_state *rcu_state = &rcu_sched_state; +static struct rcu_state *rcu_state_p = &rcu_sched_state; /* * Tell them what RCU they are running. @@ -990,16 +967,6 @@ long rcu_batches_completed(void) } EXPORT_SYMBOL_GPL(rcu_batches_completed); -/* - * Force a quiescent state for RCU, which, because there is no preemptible - * RCU, becomes the same as rcu-sched. - */ -void rcu_force_quiescent_state(void) -{ - rcu_sched_force_quiescent_state(); -} -EXPORT_SYMBOL_GPL(rcu_force_quiescent_state); - /* * Because preemptible RCU does not exist, we never have to check for * CPUs being in quiescent states. @@ -1079,22 +1046,6 @@ static void rcu_preempt_check_callbacks(int cpu) { } -/* - * Queue an RCU callback for lazy invocation after a grace period. - * This will likely be later named something like "call_rcu_lazy()", - * but this change will require some way of tagging the lazy RCU - * callbacks in the list of pending callbacks. Until then, this - * function may only be called from __kfree_rcu(). - * - * Because there is no preemptible RCU, we use RCU-sched instead. - */ -void kfree_call_rcu(struct rcu_head *head, - void (*func)(struct rcu_head *rcu)) -{ - __call_rcu(head, func, &rcu_sched_state, -1, 1); -} -EXPORT_SYMBOL_GPL(kfree_call_rcu); - /* * Wait for an rcu-preempt grace period, but make it happen quickly. * But because preemptible RCU does not exist, map to rcu-sched. @@ -1517,11 +1468,11 @@ static int __init rcu_spawn_kthreads(void) for_each_possible_cpu(cpu) per_cpu(rcu_cpu_has_work, cpu) = 0; BUG_ON(smpboot_register_percpu_thread(&rcu_cpu_thread_spec)); - rnp = rcu_get_root(rcu_state); - (void)rcu_spawn_one_boost_kthread(rcu_state, rnp); + rnp = rcu_get_root(rcu_state_p); + (void)rcu_spawn_one_boost_kthread(rcu_state_p, rnp); if (NUM_RCU_NODES > 1) { - rcu_for_each_leaf_node(rcu_state, rnp) - (void)rcu_spawn_one_boost_kthread(rcu_state, rnp); + rcu_for_each_leaf_node(rcu_state_p, rnp) + (void)rcu_spawn_one_boost_kthread(rcu_state_p, rnp); } return 0; } @@ -1529,12 +1480,12 @@ early_initcall(rcu_spawn_kthreads); static void rcu_prepare_kthreads(int cpu) { - struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu); + struct rcu_data *rdp = per_cpu_ptr(rcu_state_p->rda, cpu); struct rcu_node *rnp = rdp->mynode; /* Fire up the incoming CPU's kthread and leaf rcu_node kthread. */ if (rcu_scheduler_fully_active) - (void)rcu_spawn_one_boost_kthread(rcu_state, rnp); + (void)rcu_spawn_one_boost_kthread(rcu_state_p, rnp); } #else /* #ifdef CONFIG_RCU_BOOST */ @@ -1744,6 +1695,7 @@ int rcu_needs_cpu(int cpu, unsigned long *dj) static void rcu_prepare_for_idle(int cpu) { #ifndef CONFIG_RCU_NOCB_CPU_ALL + bool needwake; struct rcu_data *rdp; struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu); struct rcu_node *rnp; @@ -1792,8 +1744,10 @@ static void rcu_prepare_for_idle(int cpu) rnp = rdp->mynode; raw_spin_lock(&rnp->lock); /* irqs already disabled. */ smp_mb__after_unlock_lock(); - rcu_accelerate_cbs(rsp, rnp, rdp); + needwake = rcu_accelerate_cbs(rsp, rnp, rdp); raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ + if (needwake) + rcu_gp_kthread_wake(rsp); } #endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */ } @@ -1855,7 +1809,7 @@ static void rcu_oom_notify_cpu(void *unused) struct rcu_data *rdp; for_each_rcu_flavor(rsp) { - rdp = __this_cpu_ptr(rsp->rda); + rdp = raw_cpu_ptr(rsp->rda); if (rdp->qlen_lazy != 0) { atomic_inc(&oom_callback_count); rsp->call(&rdp->oom_head, rcu_oom_callback); @@ -1997,7 +1951,7 @@ static void increment_cpu_stall_ticks(void) struct rcu_state *rsp; for_each_rcu_flavor(rsp) - __this_cpu_ptr(rsp->rda)->ticks_this_gp++; + raw_cpu_inc(rsp->rda->ticks_this_gp); } #else /* #ifdef CONFIG_RCU_CPU_STALL_INFO */ @@ -2067,19 +2021,6 @@ static int __init parse_rcu_nocb_poll(char *arg) } early_param("rcu_nocb_poll", parse_rcu_nocb_poll); -/* - * Do any no-CBs CPUs need another grace period? - * - * Interrupts must be disabled. If the caller does not hold the root - * rnp_node structure's ->lock, the results are advisory only. - */ -static int rcu_nocb_needs_gp(struct rcu_state *rsp) -{ - struct rcu_node *rnp = rcu_get_root(rsp); - - return rnp->need_future_gp[(ACCESS_ONCE(rnp->completed) + 1) & 0x1]; -} - /* * Wake up any no-CBs CPUs' kthreads that were waiting on the just-ended * grace period. @@ -2109,7 +2050,7 @@ static void rcu_init_one_nocb(struct rcu_node *rnp) } #ifndef CONFIG_RCU_NOCB_CPU_ALL -/* Is the specified CPU a no-CPUs CPU? */ +/* Is the specified CPU a no-CBs CPU? */ bool rcu_is_nocb_cpu(int cpu) { if (have_rcu_nocb_mask) @@ -2243,12 +2184,15 @@ static void rcu_nocb_wait_gp(struct rcu_data *rdp) unsigned long c; bool d; unsigned long flags; + bool needwake; struct rcu_node *rnp = rdp->mynode; raw_spin_lock_irqsave(&rnp->lock, flags); smp_mb__after_unlock_lock(); - c = rcu_start_future_gp(rnp, rdp); + needwake = rcu_start_future_gp(rnp, rdp, &c); raw_spin_unlock_irqrestore(&rnp->lock, flags); + if (needwake) + rcu_gp_kthread_wake(rdp->rsp); /* * Wait for the grace period. Do so interruptibly to avoid messing @@ -2402,11 +2346,6 @@ static bool init_nocb_callback_list(struct rcu_data *rdp) #else /* #ifdef CONFIG_RCU_NOCB_CPU */ -static int rcu_nocb_needs_gp(struct rcu_state *rsp) -{ - return 0; -} - static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) { } @@ -2523,9 +2462,9 @@ static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq) /* Record start of fully idle period. */ j = jiffies; ACCESS_ONCE(rdtp->dynticks_idle_jiffies) = j; - smp_mb__before_atomic_inc(); + smp_mb__before_atomic(); atomic_inc(&rdtp->dynticks_idle); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); WARN_ON_ONCE(atomic_read(&rdtp->dynticks_idle) & 0x1); } @@ -2590,9 +2529,9 @@ static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq) } /* Record end of idle period. */ - smp_mb__before_atomic_inc(); + smp_mb__before_atomic(); atomic_inc(&rdtp->dynticks_idle); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks_idle) & 0x1)); /* @@ -2656,20 +2595,6 @@ static bool is_sysidle_rcu_state(struct rcu_state *rsp) return rsp == rcu_sysidle_state; } -/* - * Bind the grace-period kthread for the sysidle flavor of RCU to the - * timekeeping CPU. - */ -static void rcu_bind_gp_kthread(void) -{ - int cpu = ACCESS_ONCE(tick_do_timer_cpu); - - if (cpu < 0 || cpu >= nr_cpu_ids) - return; - if (raw_smp_processor_id() != cpu) - set_cpus_allowed_ptr(current, cpumask_of(cpu)); -} - /* * Return a delay in jiffies based on the number of CPUs, rcu_node * leaf fanout, and jiffies tick rate. The idea is to allow larger @@ -2734,7 +2659,8 @@ static void rcu_sysidle(unsigned long j) static void rcu_sysidle_cancel(void) { smp_mb(); - ACCESS_ONCE(full_sysidle_state) = RCU_SYSIDLE_NOT; + if (full_sysidle_state > RCU_SYSIDLE_SHORT) + ACCESS_ONCE(full_sysidle_state) = RCU_SYSIDLE_NOT; } /* @@ -2880,10 +2806,6 @@ static bool is_sysidle_rcu_state(struct rcu_state *rsp) return false; } -static void rcu_bind_gp_kthread(void) -{ -} - static void rcu_sysidle_report_gp(struct rcu_state *rsp, int isidle, unsigned long maxj) { @@ -2914,3 +2836,19 @@ static bool rcu_nohz_full_cpu(struct rcu_state *rsp) #endif /* #ifdef CONFIG_NO_HZ_FULL */ return 0; } + +/* + * Bind the grace-period kthread for the sysidle flavor of RCU to the + * timekeeping CPU. + */ +static void rcu_bind_gp_kthread(void) +{ +#ifdef CONFIG_NO_HZ_FULL + int cpu = ACCESS_ONCE(tick_do_timer_cpu); + + if (cpu < 0 || cpu >= nr_cpu_ids) + return; + if (raw_smp_processor_id() != cpu) + set_cpus_allowed_ptr(current, cpumask_of(cpu)); +#endif /* #ifdef CONFIG_NO_HZ_FULL */ +} diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index d22309cae9f5a9..a2aeb4df0f603e 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -350,3 +350,21 @@ static int __init check_cpu_stall_init(void) early_initcall(check_cpu_stall_init); #endif /* #ifdef CONFIG_RCU_STALL_COMMON */ + +/* + * Hooks for cond_resched() and friends to avoid RCU CPU stall warnings. + */ + +DEFINE_PER_CPU(int, rcu_cond_resched_count); + +/* + * Report a set of RCU quiescent states, for use by cond_resched() + * and friends. Out of line due to being called infrequently. + */ +void rcu_resched(void) +{ + preempt_disable(); + __this_cpu_write(rcu_cond_resched_count, 0); + rcu_note_context_switch(smp_processor_id()); + preempt_enable(); +} diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 423704c0484969..1e5c71ca3011c3 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -90,6 +90,22 @@ #define CREATE_TRACE_POINTS #include +#ifdef smp_mb__before_atomic +void __smp_mb__before_atomic(void) +{ + smp_mb__before_atomic(); +} +EXPORT_SYMBOL(__smp_mb__before_atomic); +#endif + +#ifdef smp_mb__after_atomic +void __smp_mb__after_atomic(void) +{ + smp_mb__after_atomic(); +} +EXPORT_SYMBOL(__smp_mb__after_atomic); +#endif + void start_bandwidth_timer(struct hrtimer *period_timer, ktime_t period) { unsigned long delta; @@ -505,6 +521,39 @@ static inline void init_hrtick(void) } #endif /* CONFIG_SCHED_HRTICK */ +/* + * cmpxchg based fetch_or, macro so it works for different integer types + */ +#define fetch_or(ptr, val) \ +({ typeof(*(ptr)) __old, __val = *(ptr); \ + for (;;) { \ + __old = cmpxchg((ptr), __val, __val | (val)); \ + if (__old == __val) \ + break; \ + __val = __old; \ + } \ + __old; \ +}) + +#ifdef TIF_POLLING_NRFLAG +/* + * Atomically set TIF_NEED_RESCHED and test for TIF_POLLING_NRFLAG, + * this avoids any races wrt polling state changes and thereby avoids + * spurious IPIs. + */ +static bool set_nr_and_not_polling(struct task_struct *p) +{ + struct thread_info *ti = task_thread_info(p); + return !(fetch_or(&ti->flags, _TIF_NEED_RESCHED) & _TIF_POLLING_NRFLAG); +} +#else +static bool set_nr_and_not_polling(struct task_struct *p) +{ + set_tsk_need_resched(p); + return true; +} +#endif + /* * resched_task - mark a task 'to be rescheduled now'. * @@ -521,17 +570,15 @@ void resched_task(struct task_struct *p) if (test_tsk_need_resched(p)) return; - set_tsk_need_resched(p); - cpu = task_cpu(p); + if (cpu == smp_processor_id()) { + set_tsk_need_resched(p); set_preempt_need_resched(); return; } - /* NEED_RESCHED must be visible before we test polling */ - smp_mb(); - if (!tsk_is_polling(p)) + if (set_nr_and_not_polling(p)) smp_send_reschedule(cpu); } @@ -2192,7 +2239,7 @@ static inline void post_schedule(struct rq *rq) * schedule_tail - first thing a freshly forked thread must call. * @prev: the thread we just switched away from. */ -asmlinkage void schedule_tail(struct task_struct *prev) +asmlinkage __visible void schedule_tail(struct task_struct *prev) __releases(rq->lock) { struct rq *rq = this_rq(); @@ -2480,7 +2527,7 @@ notrace unsigned long get_parent_ip(unsigned long addr) #if defined(CONFIG_PREEMPT) && (defined(CONFIG_DEBUG_PREEMPT) || \ defined(CONFIG_PREEMPT_TRACER)) -void __kprobes preempt_count_add(int val) +void preempt_count_add(int val) { #ifdef CONFIG_DEBUG_PREEMPT /* @@ -2506,8 +2553,9 @@ void __kprobes preempt_count_add(int val) } } EXPORT_SYMBOL(preempt_count_add); +NOKPROBE_SYMBOL(preempt_count_add); -void __kprobes preempt_count_sub(int val) +void preempt_count_sub(int val) { #ifdef CONFIG_DEBUG_PREEMPT /* @@ -2528,6 +2576,7 @@ void __kprobes preempt_count_sub(int val) __preempt_count_sub(val); } EXPORT_SYMBOL(preempt_count_sub); +NOKPROBE_SYMBOL(preempt_count_sub); #endif @@ -2592,8 +2641,14 @@ pick_next_task(struct rq *rq, struct task_struct *prev) if (likely(prev->sched_class == class && rq->nr_running == rq->cfs.h_nr_running)) { p = fair_sched_class.pick_next_task(rq, prev); - if (likely(p && p != RETRY_TASK)) - return p; + if (unlikely(p == RETRY_TASK)) + goto again; + + /* assumes fair_sched_class->next == idle_sched_class */ + if (unlikely(!p)) + p = idle_sched_class.pick_next_task(rq, prev); + + return p; } again: @@ -2741,7 +2796,7 @@ static inline void sched_submit_work(struct task_struct *tsk) blk_schedule_flush_plug(tsk); } -asmlinkage void __sched schedule(void) +asmlinkage __visible void __sched schedule(void) { struct task_struct *tsk = current; @@ -2751,7 +2806,7 @@ asmlinkage void __sched schedule(void) EXPORT_SYMBOL(schedule); #ifdef CONFIG_CONTEXT_TRACKING -asmlinkage void __sched schedule_user(void) +asmlinkage __visible void __sched schedule_user(void) { /* * If we come here after a random call to set_need_resched(), @@ -2783,7 +2838,7 @@ void __sched schedule_preempt_disabled(void) * off of preempt_enable. Kernel preemptions off return from interrupt * occur there and call schedule directly. */ -asmlinkage void __sched notrace preempt_schedule(void) +asmlinkage __visible void __sched notrace preempt_schedule(void) { /* * If there is a non-zero preempt_count or interrupts are disabled, @@ -2804,6 +2859,7 @@ asmlinkage void __sched notrace preempt_schedule(void) barrier(); } while (need_resched()); } +NOKPROBE_SYMBOL(preempt_schedule); EXPORT_SYMBOL(preempt_schedule); #endif /* CONFIG_PREEMPT */ @@ -2813,7 +2869,7 @@ EXPORT_SYMBOL(preempt_schedule); * Note, that this is called and return with irqs disabled. This will * protect us against recursive calling from irq. */ -asmlinkage void __sched preempt_schedule_irq(void) +asmlinkage __visible void __sched preempt_schedule_irq(void) { enum ctx_state prev_state; @@ -3124,6 +3180,7 @@ __setparam_dl(struct task_struct *p, const struct sched_attr *attr) dl_se->dl_bw = to_ratio(dl_se->dl_period, dl_se->dl_runtime); dl_se->dl_throttled = 0; dl_se->dl_new = 1; + dl_se->dl_yielded = 0; } static void __setscheduler_params(struct task_struct *p, @@ -3639,6 +3696,7 @@ SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param) * sys_sched_setattr - same as above, but with extended sched_attr * @pid: the pid in question. * @uattr: structure containing the extended parameters. + * @flags: for future extension. */ SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr, unsigned int, flags) @@ -3783,6 +3841,7 @@ static int sched_read_attr(struct sched_attr __user *uattr, * @pid: the pid in question. * @uattr: structure containing the extended parameters. * @size: sizeof(attr) for fwd/bwd comp. + * @flags: for future extension. */ SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, unsigned int, size, unsigned int, flags) @@ -4051,6 +4110,7 @@ static void __cond_resched(void) int __sched _cond_resched(void) { + rcu_cond_resched(); if (should_resched()) { __cond_resched(); return 1; @@ -4069,15 +4129,18 @@ EXPORT_SYMBOL(_cond_resched); */ int __cond_resched_lock(spinlock_t *lock) { + bool need_rcu_resched = rcu_should_resched(); int resched = should_resched(); int ret = 0; lockdep_assert_held(lock); - if (spin_needbreak(lock) || resched) { + if (spin_needbreak(lock) || resched || need_rcu_resched) { spin_unlock(lock); if (resched) __cond_resched(); + else if (unlikely(need_rcu_resched)) + rcu_resched(); else cpu_relax(); ret = 1; @@ -4091,6 +4154,7 @@ int __sched __cond_resched_softirq(void) { BUG_ON(!in_softirq()); + rcu_cond_resched(); /* BH disabled OK, just recording QSes. */ if (should_resched()) { local_bh_enable(); __cond_resched(); @@ -5252,7 +5316,8 @@ static int sd_degenerate(struct sched_domain *sd) SD_BALANCE_FORK | SD_BALANCE_EXEC | SD_SHARE_CPUPOWER | - SD_SHARE_PKG_RESOURCES)) { + SD_SHARE_PKG_RESOURCES | + SD_SHARE_POWERDOMAIN)) { if (sd->groups != sd->groups->next) return 0; } @@ -5283,7 +5348,8 @@ sd_parent_degenerate(struct sched_domain *sd, struct sched_domain *parent) SD_BALANCE_EXEC | SD_SHARE_CPUPOWER | SD_SHARE_PKG_RESOURCES | - SD_PREFER_SIBLING); + SD_PREFER_SIBLING | + SD_SHARE_POWERDOMAIN); if (nr_node_ids == 1) pflags &= ~SD_SERIALIZE; } @@ -5557,17 +5623,6 @@ static int __init isolated_cpu_setup(char *str) __setup("isolcpus=", isolated_cpu_setup); -static const struct cpumask *cpu_cpu_mask(int cpu) -{ - return cpumask_of_node(cpu_to_node(cpu)); -} - -struct sd_data { - struct sched_domain **__percpu sd; - struct sched_group **__percpu sg; - struct sched_group_power **__percpu sgp; -}; - struct s_data { struct sched_domain ** __percpu sd; struct root_domain *rd; @@ -5580,21 +5635,6 @@ enum s_alloc { sa_none, }; -struct sched_domain_topology_level; - -typedef struct sched_domain *(*sched_domain_init_f)(struct sched_domain_topology_level *tl, int cpu); -typedef const struct cpumask *(*sched_domain_mask_f)(int cpu); - -#define SDTL_OVERLAP 0x01 - -struct sched_domain_topology_level { - sched_domain_init_f init; - sched_domain_mask_f mask; - int flags; - int numa_level; - struct sd_data data; -}; - /* * Build an iteration mask that can exclude certain CPUs from the upwards * domain traversal. @@ -5813,44 +5853,11 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) atomic_set(&sg->sgp->nr_busy_cpus, sg->group_weight); } -int __weak arch_sd_sibling_asym_packing(void) -{ - return 0*SD_ASYM_PACKING; -} - /* * Initializers for schedule domains * Non-inlined to reduce accumulated stack pressure in build_sched_domains() */ -#ifdef CONFIG_SCHED_DEBUG -# define SD_INIT_NAME(sd, type) sd->name = #type -#else -# define SD_INIT_NAME(sd, type) do { } while (0) -#endif - -#define SD_INIT_FUNC(type) \ -static noinline struct sched_domain * \ -sd_init_##type(struct sched_domain_topology_level *tl, int cpu) \ -{ \ - struct sched_domain *sd = *per_cpu_ptr(tl->data.sd, cpu); \ - *sd = SD_##type##_INIT; \ - SD_INIT_NAME(sd, type); \ - sd->private = &tl->data; \ - return sd; \ -} - -SD_INIT_FUNC(CPU) -#ifdef CONFIG_SCHED_SMT - SD_INIT_FUNC(SIBLING) -#endif -#ifdef CONFIG_SCHED_MC - SD_INIT_FUNC(MC) -#endif -#ifdef CONFIG_SCHED_BOOK - SD_INIT_FUNC(BOOK) -#endif - static int default_relax_domain_level = -1; int sched_domain_level_max; @@ -5938,97 +5945,154 @@ static void claim_allocations(int cpu, struct sched_domain *sd) *per_cpu_ptr(sdd->sgp, cpu) = NULL; } -#ifdef CONFIG_SCHED_SMT -static const struct cpumask *cpu_smt_mask(int cpu) -{ - return topology_thread_cpumask(cpu); -} -#endif - -/* - * Topology list, bottom-up. - */ -static struct sched_domain_topology_level default_topology[] = { -#ifdef CONFIG_SCHED_SMT - { sd_init_SIBLING, cpu_smt_mask, }, -#endif -#ifdef CONFIG_SCHED_MC - { sd_init_MC, cpu_coregroup_mask, }, -#endif -#ifdef CONFIG_SCHED_BOOK - { sd_init_BOOK, cpu_book_mask, }, -#endif - { sd_init_CPU, cpu_cpu_mask, }, - { NULL, }, -}; - -static struct sched_domain_topology_level *sched_domain_topology = default_topology; - -#define for_each_sd_topology(tl) \ - for (tl = sched_domain_topology; tl->init; tl++) - #ifdef CONFIG_NUMA - static int sched_domains_numa_levels; static int *sched_domains_numa_distance; static struct cpumask ***sched_domains_numa_masks; static int sched_domains_curr_level; +#endif -static inline int sd_local_flags(int level) -{ - if (sched_domains_numa_distance[level] > RECLAIM_DISTANCE) - return 0; - - return SD_BALANCE_EXEC | SD_BALANCE_FORK | SD_WAKE_AFFINE; -} +/* + * SD_flags allowed in topology descriptions. + * + * SD_SHARE_CPUPOWER - describes SMT topologies + * SD_SHARE_PKG_RESOURCES - describes shared caches + * SD_NUMA - describes NUMA topologies + * SD_SHARE_POWERDOMAIN - describes shared power domain + * + * Odd one out: + * SD_ASYM_PACKING - describes SMT quirks + */ +#define TOPOLOGY_SD_FLAGS \ + (SD_SHARE_CPUPOWER | \ + SD_SHARE_PKG_RESOURCES | \ + SD_NUMA | \ + SD_ASYM_PACKING | \ + SD_SHARE_POWERDOMAIN) static struct sched_domain * -sd_numa_init(struct sched_domain_topology_level *tl, int cpu) +sd_init(struct sched_domain_topology_level *tl, int cpu) { struct sched_domain *sd = *per_cpu_ptr(tl->data.sd, cpu); - int level = tl->numa_level; - int sd_weight = cpumask_weight( - sched_domains_numa_masks[level][cpu_to_node(cpu)]); + int sd_weight, sd_flags = 0; + +#ifdef CONFIG_NUMA + /* + * Ugly hack to pass state to sd_numa_mask()... + */ + sched_domains_curr_level = tl->numa_level; +#endif + + sd_weight = cpumask_weight(tl->mask(cpu)); + + if (tl->sd_flags) + sd_flags = (*tl->sd_flags)(); + if (WARN_ONCE(sd_flags & ~TOPOLOGY_SD_FLAGS, + "wrong sd_flags in topology description\n")) + sd_flags &= ~TOPOLOGY_SD_FLAGS; *sd = (struct sched_domain){ .min_interval = sd_weight, .max_interval = 2*sd_weight, .busy_factor = 32, .imbalance_pct = 125, - .cache_nice_tries = 2, - .busy_idx = 3, - .idle_idx = 2, + + .cache_nice_tries = 0, + .busy_idx = 0, + .idle_idx = 0, .newidle_idx = 0, .wake_idx = 0, .forkexec_idx = 0, .flags = 1*SD_LOAD_BALANCE | 1*SD_BALANCE_NEWIDLE - | 0*SD_BALANCE_EXEC - | 0*SD_BALANCE_FORK + | 1*SD_BALANCE_EXEC + | 1*SD_BALANCE_FORK | 0*SD_BALANCE_WAKE - | 0*SD_WAKE_AFFINE + | 1*SD_WAKE_AFFINE | 0*SD_SHARE_CPUPOWER | 0*SD_SHARE_PKG_RESOURCES - | 1*SD_SERIALIZE + | 0*SD_SERIALIZE | 0*SD_PREFER_SIBLING - | 1*SD_NUMA - | sd_local_flags(level) + | 0*SD_NUMA + | sd_flags , + .last_balance = jiffies, .balance_interval = sd_weight, + .smt_gain = 0, + .max_newidle_lb_cost = 0, + .next_decay_max_lb_cost = jiffies, +#ifdef CONFIG_SCHED_DEBUG + .name = tl->name, +#endif }; - SD_INIT_NAME(sd, NUMA); - sd->private = &tl->data; /* - * Ugly hack to pass state to sd_numa_mask()... + * Convert topological properties into behaviour. */ - sched_domains_curr_level = tl->numa_level; + + if (sd->flags & SD_SHARE_CPUPOWER) { + sd->imbalance_pct = 110; + sd->smt_gain = 1178; /* ~15% */ + + } else if (sd->flags & SD_SHARE_PKG_RESOURCES) { + sd->imbalance_pct = 117; + sd->cache_nice_tries = 1; + sd->busy_idx = 2; + +#ifdef CONFIG_NUMA + } else if (sd->flags & SD_NUMA) { + sd->cache_nice_tries = 2; + sd->busy_idx = 3; + sd->idle_idx = 2; + + sd->flags |= SD_SERIALIZE; + if (sched_domains_numa_distance[tl->numa_level] > RECLAIM_DISTANCE) { + sd->flags &= ~(SD_BALANCE_EXEC | + SD_BALANCE_FORK | + SD_WAKE_AFFINE); + } + +#endif + } else { + sd->flags |= SD_PREFER_SIBLING; + sd->cache_nice_tries = 1; + sd->busy_idx = 2; + sd->idle_idx = 1; + } + + sd->private = &tl->data; return sd; } +/* + * Topology list, bottom-up. + */ +static struct sched_domain_topology_level default_topology[] = { +#ifdef CONFIG_SCHED_SMT + { cpu_smt_mask, cpu_smt_flags, SD_INIT_NAME(SMT) }, +#endif +#ifdef CONFIG_SCHED_MC + { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, +#endif + { cpu_cpu_mask, SD_INIT_NAME(DIE) }, + { NULL, }, +}; + +struct sched_domain_topology_level *sched_domain_topology = default_topology; + +#define for_each_sd_topology(tl) \ + for (tl = sched_domain_topology; tl->mask; tl++) + +void set_sched_topology(struct sched_domain_topology_level *tl) +{ + sched_domain_topology = tl; +} + +#ifdef CONFIG_NUMA + static const struct cpumask *sd_numa_mask(int cpu) { return sched_domains_numa_masks[sched_domains_curr_level][cpu_to_node(cpu)]; @@ -6172,7 +6236,10 @@ static void sched_init_numa(void) } } - tl = kzalloc((ARRAY_SIZE(default_topology) + level) * + /* Compute default topology size */ + for (i = 0; sched_domain_topology[i].mask; i++); + + tl = kzalloc((i + level) * sizeof(struct sched_domain_topology_level), GFP_KERNEL); if (!tl) return; @@ -6180,18 +6247,19 @@ static void sched_init_numa(void) /* * Copy the default topology bits.. */ - for (i = 0; default_topology[i].init; i++) - tl[i] = default_topology[i]; + for (i = 0; sched_domain_topology[i].mask; i++) + tl[i] = sched_domain_topology[i]; /* * .. and append 'j' levels of NUMA goodness. */ for (j = 0; j < level; i++, j++) { tl[i] = (struct sched_domain_topology_level){ - .init = sd_numa_init, .mask = sd_numa_mask, + .sd_flags = cpu_numa_flags, .flags = SDTL_OVERLAP, .numa_level = j, + SD_INIT_NAME(NUMA) }; } @@ -6349,7 +6417,7 @@ struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl, const struct cpumask *cpu_map, struct sched_domain_attr *attr, struct sched_domain *child, int cpu) { - struct sched_domain *sd = tl->init(tl, cpu); + struct sched_domain *sd = sd_init(tl, cpu); if (!sd) return child; diff --git a/kernel/sched/cpudeadline.c b/kernel/sched/cpudeadline.c index 5b9bb42b2d47e7..ab001b5d504878 100644 --- a/kernel/sched/cpudeadline.c +++ b/kernel/sched/cpudeadline.c @@ -210,7 +210,5 @@ int cpudl_init(struct cpudl *cp) */ void cpudl_cleanup(struct cpudl *cp) { - /* - * nothing to do for the moment - */ + free_cpumask_var(cp->free_cpus); } diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c index 8b836b376d9129..a5635adb87ebd5 100644 --- a/kernel/sched/cpupri.c +++ b/kernel/sched/cpupri.c @@ -70,8 +70,7 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p, int idx = 0; int task_pri = convert_prio(p->prio); - if (task_pri >= MAX_RT_PRIO) - return 0; + BUG_ON(task_pri >= CPUPRI_NR_PRIORITIES); for (idx = 0; idx < task_pri; idx++) { struct cpupri_vec *vec = &cp->pri_to_cpu[idx]; @@ -165,7 +164,7 @@ void cpupri_set(struct cpupri *cp, int cpu, int newpri) * do a write memory barrier, and then update the count, to * make sure the vector is visible when count is set. */ - smp_mb__before_atomic_inc(); + smp_mb__before_atomic(); atomic_inc(&(vec)->count); do_mb = 1; } @@ -185,14 +184,14 @@ void cpupri_set(struct cpupri *cp, int cpu, int newpri) * the new priority vec. */ if (do_mb) - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); /* * When removing from the vector, we decrement the counter first * do a memory barrier and then clear the mask. */ atomic_dec(&(vec)->count); - smp_mb__after_atomic_inc(); + smp_mb__after_atomic(); cpumask_clear_cpu(cpu, vec->mask); } diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index a95097cb4591b5..72fdf06ef8652d 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -332,50 +332,50 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times) * softirq as those do not count in task exec_runtime any more. */ static void irqtime_account_process_tick(struct task_struct *p, int user_tick, - struct rq *rq) + struct rq *rq, int ticks) { - cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy); + cputime_t scaled = cputime_to_scaled(cputime_one_jiffy); + u64 cputime = (__force u64) cputime_one_jiffy; u64 *cpustat = kcpustat_this_cpu->cpustat; if (steal_account_process_tick()) return; + cputime *= ticks; + scaled *= ticks; + if (irqtime_account_hi_update()) { - cpustat[CPUTIME_IRQ] += (__force u64) cputime_one_jiffy; + cpustat[CPUTIME_IRQ] += cputime; } else if (irqtime_account_si_update()) { - cpustat[CPUTIME_SOFTIRQ] += (__force u64) cputime_one_jiffy; + cpustat[CPUTIME_SOFTIRQ] += cputime; } else if (this_cpu_ksoftirqd() == p) { /* * ksoftirqd time do not get accounted in cpu_softirq_time. * So, we have to handle it separately here. * Also, p->stime needs to be updated for ksoftirqd. */ - __account_system_time(p, cputime_one_jiffy, one_jiffy_scaled, - CPUTIME_SOFTIRQ); + __account_system_time(p, cputime, scaled, CPUTIME_SOFTIRQ); } else if (user_tick) { - account_user_time(p, cputime_one_jiffy, one_jiffy_scaled); + account_user_time(p, cputime, scaled); } else if (p == rq->idle) { - account_idle_time(cputime_one_jiffy); + account_idle_time(cputime); } else if (p->flags & PF_VCPU) { /* System time or guest time */ - account_guest_time(p, cputime_one_jiffy, one_jiffy_scaled); + account_guest_time(p, cputime, scaled); } else { - __account_system_time(p, cputime_one_jiffy, one_jiffy_scaled, - CPUTIME_SYSTEM); + __account_system_time(p, cputime, scaled, CPUTIME_SYSTEM); } } static void irqtime_account_idle_ticks(int ticks) { - int i; struct rq *rq = this_rq(); - for (i = 0; i < ticks; i++) - irqtime_account_process_tick(current, 0, rq); + irqtime_account_process_tick(current, 0, rq, ticks); } #else /* CONFIG_IRQ_TIME_ACCOUNTING */ static inline void irqtime_account_idle_ticks(int ticks) {} static inline void irqtime_account_process_tick(struct task_struct *p, int user_tick, - struct rq *rq) {} + struct rq *rq, int nr_ticks) {} #endif /* CONFIG_IRQ_TIME_ACCOUNTING */ /* @@ -464,7 +464,7 @@ void account_process_tick(struct task_struct *p, int user_tick) return; if (sched_clock_irqtime) { - irqtime_account_process_tick(p, user_tick, rq); + irqtime_account_process_tick(p, user_tick, rq, 1); return; } diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 80837e9a081c59..3fa3fac9d81937 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -523,6 +523,7 @@ static enum hrtimer_restart dl_task_timer(struct hrtimer *timer) sched_clock_tick(); update_rq_clock(rq); dl_se->dl_throttled = 0; + dl_se->dl_yielded = 0; if (p->on_rq) { enqueue_task_dl(rq, p, ENQUEUE_REPLENISH); if (task_has_dl_policy(rq->curr)) @@ -888,10 +889,10 @@ static void yield_task_dl(struct rq *rq) * We make the task go to sleep until its current deadline by * forcing its runtime to zero. This way, update_curr_dl() stops * it and the bandwidth timer will wake it up and will give it - * new scheduling parameters (thanks to dl_new=1). + * new scheduling parameters (thanks to dl_yielded=1). */ if (p->dl.runtime > 0) { - rq->curr->dl.dl_new = 1; + rq->curr->dl.dl_yielded = 1; p->dl.runtime = 0; } update_curr_dl(rq); diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 7570dd969c2838..28ccf502c63ca4 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -1301,7 +1301,16 @@ static int task_numa_migrate(struct task_struct *p) if (env.best_cpu == -1) return -EAGAIN; - sched_setnuma(p, env.dst_nid); + /* + * If the task is part of a workload that spans multiple NUMA nodes, + * and is migrating into one of the workload's active nodes, remember + * this node as the task's preferred numa node, so the workload can + * settle down. + * A task that migrated to a second choice node will be better off + * trying for a better one later. Do not set the preferred node here. + */ + if (p->numa_group && node_isset(env.dst_nid, p->numa_group->active_nodes)) + sched_setnuma(p, env.dst_nid); /* * Reset the scan period if the task is being rescheduled on an @@ -1326,12 +1335,15 @@ static int task_numa_migrate(struct task_struct *p) /* Attempt to migrate a task to a CPU on the preferred node. */ static void numa_migrate_preferred(struct task_struct *p) { + unsigned long interval = HZ; + /* This task has no NUMA fault statistics yet */ if (unlikely(p->numa_preferred_nid == -1 || !p->numa_faults_memory)) return; /* Periodically retry migrating the task to the preferred node */ - p->numa_migrate_retry = jiffies + HZ; + interval = min(interval, msecs_to_jiffies(p->numa_scan_period) / 16); + p->numa_migrate_retry = jiffies + interval; /* Success if task is already running on preferred CPU */ if (task_node(p) == p->numa_preferred_nid) @@ -1738,6 +1750,7 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags) struct task_struct *p = current; bool migrated = flags & TNF_MIGRATED; int cpu_node = task_node(current); + int local = !!(flags & TNF_FAULT_LOCAL); int priv; if (!numabalancing_enabled) @@ -1786,6 +1799,17 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags) task_numa_group(p, last_cpupid, flags, &priv); } + /* + * If a workload spans multiple NUMA nodes, a shared fault that + * occurs wholly within the set of nodes that the workload is + * actively using should be counted as local. This allows the + * scan rate to slow down when a workload has settled down. + */ + if (!priv && !local && p->numa_group && + node_isset(cpu_node, p->numa_group->active_nodes) && + node_isset(mem_node, p->numa_group->active_nodes)) + local = 1; + task_numa_placement(p); /* @@ -1800,7 +1824,7 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags) p->numa_faults_buffer_memory[task_faults_idx(mem_node, priv)] += pages; p->numa_faults_buffer_cpu[task_faults_idx(cpu_node, priv)] += pages; - p->numa_faults_locality[!!(flags & TNF_FAULT_LOCAL)] += pages; + p->numa_faults_locality[local] += pages; } static void reset_ptenuma_scan(struct task_struct *p) @@ -5564,6 +5588,7 @@ static unsigned long scale_rt_power(int cpu) { struct rq *rq = cpu_rq(cpu); u64 total, available, age_stamp, avg; + s64 delta; /* * Since we're reading these variables without serialization make sure @@ -5572,7 +5597,11 @@ static unsigned long scale_rt_power(int cpu) age_stamp = ACCESS_ONCE(rq->age_stamp); avg = ACCESS_ONCE(rq->rt_avg); - total = sched_avg_period() + (rq_clock(rq) - age_stamp); + delta = rq_clock(rq) - age_stamp; + if (unlikely(delta < 0)) + delta = 0; + + total = sched_avg_period() + delta; if (unlikely(total < avg)) { /* Ensures that power won't end up being negative */ @@ -6653,6 +6682,7 @@ static int idle_balance(struct rq *this_rq) int this_cpu = this_rq->cpu; idle_enter_fair(this_rq); + /* * We must set idle_stamp _before_ calling idle_balance(), such that we * measure the duration of idle_balance() as idle time. @@ -6683,7 +6713,6 @@ static int idle_balance(struct rq *this_rq) if (sd->flags & SD_BALANCE_NEWIDLE) { t0 = sched_clock_cpu(this_cpu); - /* If we've pulled tasks over stop searching: */ pulled_task = load_balance(this_cpu, this_rq, sd, CPU_NEWLY_IDLE, &continue_balancing); @@ -6698,21 +6727,28 @@ static int idle_balance(struct rq *this_rq) interval = msecs_to_jiffies(sd->balance_interval); if (time_after(next_balance, sd->last_balance + interval)) next_balance = sd->last_balance + interval; - if (pulled_task) + + /* + * Stop searching for tasks to pull if there are + * now runnable tasks on this rq. + */ + if (pulled_task || this_rq->nr_running > 0) break; } rcu_read_unlock(); raw_spin_lock(&this_rq->lock); + if (curr_cost > this_rq->max_idle_balance_cost) + this_rq->max_idle_balance_cost = curr_cost; + /* - * While browsing the domains, we released the rq lock. - * A task could have be enqueued in the meantime + * While browsing the domains, we released the rq lock, a task could + * have been enqueued in the meantime. Since we're not going idle, + * pretend we pulled a task. */ - if (this_rq->cfs.h_nr_running && !pulled_task) { + if (this_rq->cfs.h_nr_running && !pulled_task) pulled_task = 1; - goto out; - } if (pulled_task || time_after(jiffies, this_rq->next_balance)) { /* @@ -6722,15 +6758,9 @@ static int idle_balance(struct rq *this_rq) this_rq->next_balance = next_balance; } - if (curr_cost > this_rq->max_idle_balance_cost) - this_rq->max_idle_balance_cost = curr_cost; - out: /* Is there a task of a high priority class? */ - if (this_rq->nr_running != this_rq->cfs.h_nr_running && - ((this_rq->stop && this_rq->stop->on_rq) || - this_rq->dl.dl_nr_running || - (this_rq->rt.rt_nr_running && !rt_rq_throttled(&this_rq->rt)))) + if (this_rq->nr_running != this_rq->cfs.h_nr_running) pulled_task = -1; if (pulled_task) { diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 8f4390a079c77d..acce6c0f84b8fd 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -67,24 +67,21 @@ void __weak arch_cpu_idle(void) * cpuidle_idle_call - the main idle function * * NOTE: no locks or semaphores should be used here - * return non-zero on failure */ -static int cpuidle_idle_call(void) +static void cpuidle_idle_call(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); - int next_state, entered_state, ret; + int next_state, entered_state; bool broadcast; /* * Check if the idle task must be rescheduled. If it is the - * case, exit the function after re-enabling the local irq and - * set again the polling flag + * case, exit the function after re-enabling the local irq. */ - if (current_clr_polling_and_test()) { + if (need_resched()) { local_irq_enable(); - __current_set_polling(); - return 0; + return; } /* @@ -101,96 +98,79 @@ static int cpuidle_idle_call(void) rcu_idle_enter(); /* - * Check if the cpuidle framework is ready, otherwise fallback - * to the default arch specific idle method + * Ask the cpuidle framework to choose a convenient idle state. + * Fall back to the default arch specific idle method on errors. */ - ret = cpuidle_enabled(drv, dev); - - if (!ret) { - /* - * Ask the governor to choose an idle state it thinks - * it is convenient to go to. There is *always* a - * convenient idle state - */ - next_state = cpuidle_select(drv, dev); + next_state = cpuidle_select(drv, dev); + if (next_state < 0) { +use_default: /* - * The idle task must be scheduled, it is pointless to - * go to idle, just update no idle residency and get - * out of this function + * We can't use the cpuidle framework, let's use the default + * idle routine. */ - if (current_clr_polling_and_test()) { - dev->last_residency = 0; - entered_state = next_state; + if (current_clr_polling_and_test()) local_irq_enable(); - } else { - broadcast = !!(drv->states[next_state].flags & - CPUIDLE_FLAG_TIMER_STOP); - - if (broadcast) - /* - * Tell the time framework to switch - * to a broadcast timer because our - * local timer will be shutdown. If a - * local timer is used from another - * cpu as a broadcast timer, this call - * may fail if it is not available - */ - ret = clockevents_notify( - CLOCK_EVT_NOTIFY_BROADCAST_ENTER, - &dev->cpu); - - if (!ret) { - trace_cpu_idle_rcuidle(next_state, dev->cpu); - - /* - * Enter the idle state previously - * returned by the governor - * decision. This function will block - * until an interrupt occurs and will - * take care of re-enabling the local - * interrupts - */ - entered_state = cpuidle_enter(drv, dev, - next_state); - - trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, - dev->cpu); - - if (broadcast) - clockevents_notify( - CLOCK_EVT_NOTIFY_BROADCAST_EXIT, - &dev->cpu); - - /* - * Give the governor an opportunity to reflect on the - * outcome - */ - cpuidle_reflect(dev, entered_state); - } - } + else + arch_cpu_idle(); + + goto exit_idle; } /* - * We can't use the cpuidle framework, let's use the default - * idle routine + * The idle task must be scheduled, it is pointless to + * go to idle, just update no idle residency and get + * out of this function */ - if (ret) - arch_cpu_idle(); + if (current_clr_polling_and_test()) { + dev->last_residency = 0; + entered_state = next_state; + local_irq_enable(); + goto exit_idle; + } + broadcast = !!(drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP); + + /* + * Tell the time framework to switch to a broadcast timer + * because our local timer will be shutdown. If a local timer + * is used from another cpu as a broadcast timer, this call may + * fail if it is not available + */ + if (broadcast && + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu) < 0) + goto use_default; + + trace_cpu_idle_rcuidle(next_state, dev->cpu); + + /* + * Enter the idle state previously returned by the governor decision. + * This function will block until an interrupt occurs and will take + * care of re-enabling the local interrupts + */ + entered_state = cpuidle_enter(drv, dev, next_state); + + trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); + + if (broadcast) + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); + + /* + * Give the governor an opportunity to reflect on the outcome + */ + cpuidle_reflect(dev, entered_state); + +exit_idle: __current_set_polling(); /* - * It is up to the idle functions to enable back the local - * interrupt + * It is up to the idle functions to reenable local interrupts */ if (WARN_ON_ONCE(irqs_disabled())) local_irq_enable(); rcu_idle_exit(); start_critical_timings(); - - return 0; } /* diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 1e9e8395c7a2b3..ea4d50089631b5 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -79,6 +79,8 @@ void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq) rt_rq->overloaded = 0; plist_head_init(&rt_rq->pushable_tasks); #endif + /* We start is dequeued state, because no RT tasks are queued */ + rt_rq->rt_queued = 0; rt_rq->rt_time = 0; rt_rq->rt_throttled = 0; @@ -112,6 +114,13 @@ static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se) return rt_se->rt_rq; } +static inline struct rq *rq_of_rt_se(struct sched_rt_entity *rt_se) +{ + struct rt_rq *rt_rq = rt_se->rt_rq; + + return rt_rq->rq; +} + void free_rt_sched_group(struct task_group *tg) { int i; @@ -211,10 +220,16 @@ static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq) return container_of(rt_rq, struct rq, rt); } -static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se) +static inline struct rq *rq_of_rt_se(struct sched_rt_entity *rt_se) { struct task_struct *p = rt_task_of(rt_se); - struct rq *rq = task_rq(p); + + return task_rq(p); +} + +static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se) +{ + struct rq *rq = rq_of_rt_se(rt_se); return &rq->rt; } @@ -391,6 +406,9 @@ static inline void set_post_schedule(struct rq *rq) } #endif /* CONFIG_SMP */ +static void enqueue_top_rt_rq(struct rt_rq *rt_rq); +static void dequeue_top_rt_rq(struct rt_rq *rt_rq); + static inline int on_rt_rq(struct sched_rt_entity *rt_se) { return !list_empty(&rt_se->run_list); @@ -452,8 +470,11 @@ static void sched_rt_rq_enqueue(struct rt_rq *rt_rq) rt_se = rt_rq->tg->rt_se[cpu]; if (rt_rq->rt_nr_running) { - if (rt_se && !on_rt_rq(rt_se)) + if (!rt_se) + enqueue_top_rt_rq(rt_rq); + else if (!on_rt_rq(rt_se)) enqueue_rt_entity(rt_se, false); + if (rt_rq->highest_prio.curr < curr->prio) resched_task(curr); } @@ -466,10 +487,17 @@ static void sched_rt_rq_dequeue(struct rt_rq *rt_rq) rt_se = rt_rq->tg->rt_se[cpu]; - if (rt_se && on_rt_rq(rt_se)) + if (!rt_se) + dequeue_top_rt_rq(rt_rq); + else if (on_rt_rq(rt_se)) dequeue_rt_entity(rt_se); } +static inline int rt_rq_throttled(struct rt_rq *rt_rq) +{ + return rt_rq->rt_throttled && !rt_rq->rt_nr_boosted; +} + static int rt_se_boosted(struct sched_rt_entity *rt_se) { struct rt_rq *rt_rq = group_rt_rq(rt_se); @@ -532,12 +560,23 @@ static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se) static inline void sched_rt_rq_enqueue(struct rt_rq *rt_rq) { - if (rt_rq->rt_nr_running) - resched_task(rq_of_rt_rq(rt_rq)->curr); + struct rq *rq = rq_of_rt_rq(rt_rq); + + if (!rt_rq->rt_nr_running) + return; + + enqueue_top_rt_rq(rt_rq); + resched_task(rq->curr); } static inline void sched_rt_rq_dequeue(struct rt_rq *rt_rq) { + dequeue_top_rt_rq(rt_rq); +} + +static inline int rt_rq_throttled(struct rt_rq *rt_rq) +{ + return rt_rq->rt_throttled; } static inline const struct cpumask *sched_rt_period_mask(void) @@ -916,6 +955,38 @@ static void update_curr_rt(struct rq *rq) } } +static void +dequeue_top_rt_rq(struct rt_rq *rt_rq) +{ + struct rq *rq = rq_of_rt_rq(rt_rq); + + BUG_ON(&rq->rt != rt_rq); + + if (!rt_rq->rt_queued) + return; + + BUG_ON(!rq->nr_running); + + rq->nr_running -= rt_rq->rt_nr_running; + rt_rq->rt_queued = 0; +} + +static void +enqueue_top_rt_rq(struct rt_rq *rt_rq) +{ + struct rq *rq = rq_of_rt_rq(rt_rq); + + BUG_ON(&rq->rt != rt_rq); + + if (rt_rq->rt_queued) + return; + if (rt_rq_throttled(rt_rq) || !rt_rq->rt_nr_running) + return; + + rq->nr_running += rt_rq->rt_nr_running; + rt_rq->rt_queued = 1; +} + #if defined CONFIG_SMP static void @@ -1038,13 +1109,24 @@ void dec_rt_group(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) {} #endif /* CONFIG_RT_GROUP_SCHED */ +static inline +unsigned int rt_se_nr_running(struct sched_rt_entity *rt_se) +{ + struct rt_rq *group_rq = group_rt_rq(rt_se); + + if (group_rq) + return group_rq->rt_nr_running; + else + return 1; +} + static inline void inc_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) { int prio = rt_se_prio(rt_se); WARN_ON(!rt_prio(prio)); - rt_rq->rt_nr_running++; + rt_rq->rt_nr_running += rt_se_nr_running(rt_se); inc_rt_prio(rt_rq, prio); inc_rt_migration(rt_se, rt_rq); @@ -1056,7 +1138,7 @@ void dec_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) { WARN_ON(!rt_prio(rt_se_prio(rt_se))); WARN_ON(!rt_rq->rt_nr_running); - rt_rq->rt_nr_running--; + rt_rq->rt_nr_running -= rt_se_nr_running(rt_se); dec_rt_prio(rt_rq, rt_se_prio(rt_se)); dec_rt_migration(rt_se, rt_rq); @@ -1113,6 +1195,8 @@ static void dequeue_rt_stack(struct sched_rt_entity *rt_se) back = rt_se; } + dequeue_top_rt_rq(rt_rq_of_se(back)); + for (rt_se = back; rt_se; rt_se = rt_se->back) { if (on_rt_rq(rt_se)) __dequeue_rt_entity(rt_se); @@ -1121,13 +1205,18 @@ static void dequeue_rt_stack(struct sched_rt_entity *rt_se) static void enqueue_rt_entity(struct sched_rt_entity *rt_se, bool head) { + struct rq *rq = rq_of_rt_se(rt_se); + dequeue_rt_stack(rt_se); for_each_sched_rt_entity(rt_se) __enqueue_rt_entity(rt_se, head); + enqueue_top_rt_rq(&rq->rt); } static void dequeue_rt_entity(struct sched_rt_entity *rt_se) { + struct rq *rq = rq_of_rt_se(rt_se); + dequeue_rt_stack(rt_se); for_each_sched_rt_entity(rt_se) { @@ -1136,6 +1225,7 @@ static void dequeue_rt_entity(struct sched_rt_entity *rt_se) if (rt_rq && rt_rq->rt_nr_running) __enqueue_rt_entity(rt_se, false); } + enqueue_top_rt_rq(&rq->rt); } /* @@ -1153,8 +1243,6 @@ enqueue_task_rt(struct rq *rq, struct task_struct *p, int flags) if (!task_current(rq, p) && p->nr_cpus_allowed > 1) enqueue_pushable_task(rq, p); - - inc_nr_running(rq); } static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags) @@ -1165,8 +1253,6 @@ static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags) dequeue_rt_entity(rt_se); dequeue_pushable_task(rq, p); - - dec_nr_running(rq); } /* @@ -1371,10 +1457,7 @@ pick_next_task_rt(struct rq *rq, struct task_struct *prev) if (prev->sched_class == &rt_sched_class) update_curr_rt(rq); - if (!rt_rq->rt_nr_running) - return NULL; - - if (rt_rq_throttled(rt_rq)) + if (!rt_rq->rt_queued) return NULL; put_prev_task(rq, prev); @@ -1886,9 +1969,9 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p) */ if (p->on_rq && rq->curr != p) { #ifdef CONFIG_SMP - if (rq->rt.overloaded && push_rt_task(rq) && + if (p->nr_cpus_allowed > 1 && rq->rt.overloaded && /* Don't resched if we changed runqueues */ - rq != task_rq(p)) + push_rt_task(rq) && rq != task_rq(p)) check_resched = 0; #endif /* CONFIG_SMP */ if (check_resched && p->prio < rq->curr->prio) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 456e492a3dca37..b2cbe81308afe7 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -409,6 +409,8 @@ struct rt_rq { int overloaded; struct plist_head pushable_tasks; #endif + int rt_queued; + int rt_throttled; u64 rt_time; u64 rt_runtime; @@ -423,18 +425,6 @@ struct rt_rq { #endif }; -#ifdef CONFIG_RT_GROUP_SCHED -static inline int rt_rq_throttled(struct rt_rq *rt_rq) -{ - return rt_rq->rt_throttled && !rt_rq->rt_nr_boosted; -} -#else -static inline int rt_rq_throttled(struct rt_rq *rt_rq) -{ - return rt_rq->rt_throttled; -} -#endif - /* Deadline class' related fields in a runqueue */ struct dl_rq { /* runqueue is an rbtree, ordered by deadline */ diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c index 7d50f794e24802..c5a744fa388181 100644 --- a/kernel/sched/wait.c +++ b/kernel/sched/wait.c @@ -167,31 +167,41 @@ EXPORT_SYMBOL_GPL(__wake_up_sync); /* For internal use only */ * stops them from bleeding out - it would still allow subsequent * loads to move into the critical region). */ -void +bool prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state) { unsigned long flags; + bool ret = false; wait->flags &= ~WQ_FLAG_EXCLUSIVE; spin_lock_irqsave(&q->lock, flags); - if (list_empty(&wait->task_list)) + if (list_empty(&wait->task_list)) { __add_wait_queue(q, wait); + ret = true; + } set_current_state(state); spin_unlock_irqrestore(&q->lock, flags); + + return ret; } EXPORT_SYMBOL(prepare_to_wait); -void +bool prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state) { unsigned long flags; + bool ret = false; wait->flags |= WQ_FLAG_EXCLUSIVE; spin_lock_irqsave(&q->lock, flags); - if (list_empty(&wait->task_list)) + if (list_empty(&wait->task_list)) { __add_wait_queue_tail(q, wait); + ret = true; + } set_current_state(state); spin_unlock_irqrestore(&q->lock, flags); + + return ret; } EXPORT_SYMBOL(prepare_to_wait_exclusive); @@ -394,7 +404,7 @@ EXPORT_SYMBOL(__wake_up_bit); * * In order for this to function properly, as it uses waitqueue_active() * internally, some kind of memory barrier must be done prior to calling - * this. Typically, this will be smp_mb__after_clear_bit(), but in some + * this. Typically, this will be smp_mb__after_atomic(), but in some * cases where bitflags are manipulated non-atomically under a lock, one * may need to use a less regular barrier, such fs/inode.c's smp_mb(), * because spin_unlock() does not guarantee a memory barrier. diff --git a/kernel/smp.c b/kernel/smp.c index f864921fc82c15..6fc6dedda5387c 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -275,6 +275,48 @@ int smp_call_function_single_async(int cpu, struct call_single_data *csd) } EXPORT_SYMBOL_GPL(smp_call_function_single_async); +void generic_smp_queue_function_single_interrupt(void *info) +{ + struct queue_single_data *qsd = info; + + WARN_ON_ONCE(xchg(&qsd->pending, 0) != 1); + qsd->func(qsd); +} + +/** + * smp_queue_function_single - Queue an asynchronous function to run on a + * specific CPU unless it's already pending. + * @cpu: The CPU to run on. + * @qsd: Pre-allocated and setup data structure + * + * Like smp_call_function_single_async() but the call to the function is + * serialized and won't be queued if it is already pending. In the latter case, + * ordering is still guaranteed such that the pending call will see the new + * data we expect it to. + * + * This must not be called on offline CPUs. + * + * Returns 0 when function is successfully queued or already pending, else a + * negative status code. + */ +int smp_queue_function_single(int cpu, struct queue_single_data *qsd) +{ + int err; + + if (cmpxchg(&qsd->pending, 0, 1)) + return 0; + + preempt_disable(); + err = generic_exec_single(cpu, &qsd->data, generic_smp_queue_function_single_interrupt, qsd, 0); + preempt_enable(); + + /* Reset in case of error. This must not be called on offline CPUs */ + if (err) + qsd->pending = 0; + + return err; +} + /* * smp_call_function_any - Run a function on any of the given cpus * @mask: The mask of cpus it can run on. diff --git a/kernel/softirq.c b/kernel/softirq.c index 33e4648ae0e7cd..5918d227730f33 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -223,7 +223,7 @@ static inline bool lockdep_softirq_start(void) { return false; } static inline void lockdep_softirq_end(bool in_hardirq) { } #endif -asmlinkage void __do_softirq(void) +asmlinkage __visible void __do_softirq(void) { unsigned long end = jiffies + MAX_SOFTIRQ_TIME; unsigned long old_flags = current->flags; @@ -232,7 +232,6 @@ asmlinkage void __do_softirq(void) bool in_hardirq; __u32 pending; int softirq_bit; - int cpu; /* * Mask out PF_MEMALLOC s current task context is borrowed for the @@ -247,7 +246,6 @@ asmlinkage void __do_softirq(void) __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET); in_hardirq = lockdep_softirq_start(); - cpu = smp_processor_id(); restart: /* Reset the pending bitmask before enabling irqs */ set_softirq_pending(0); @@ -276,11 +274,11 @@ asmlinkage void __do_softirq(void) prev_count, preempt_count()); preempt_count_set(prev_count); } - rcu_bh_qs(cpu); h++; pending >>= softirq_bit; } + rcu_bh_qs(smp_processor_id()); local_irq_disable(); pending = local_softirq_pending(); @@ -299,7 +297,7 @@ asmlinkage void __do_softirq(void) tsk_restore_flags(current, old_flags, PF_MEMALLOC); } -asmlinkage void do_softirq(void) +asmlinkage __visible void do_softirq(void) { __u32 pending; unsigned long flags; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 27e19ba04049bf..e55c5ac69c9fe1 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -659,7 +659,7 @@ static struct ctl_table kern_table[] = { .extra2 = &one, }, #endif - +#ifdef CONFIG_UEVENT_HELPER { .procname = "hotplug", .data = &uevent_helper, @@ -667,7 +667,7 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dostring, }, - +#endif #ifdef CONFIG_CHR_DEV_SG { .procname = "sg-big-buff", @@ -1434,8 +1434,13 @@ static struct ctl_table vm_table[] = { (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL)) { .procname = "vdso_enabled", +#ifdef CONFIG_X86_32 + .data = &vdso32_enabled, + .maxlen = sizeof(vdso32_enabled), +#else .data = &vdso_enabled, .maxlen = sizeof(vdso_enabled), +#endif .mode = 0644, .proc_handler = proc_dointvec, .extra1 = &zero, diff --git a/kernel/torture.c b/kernel/torture.c index acc9afc2f26e44..db8de702abbc62 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -335,13 +335,8 @@ static void torture_shuffle_tasks(void) shuffle_idle_cpu = cpumask_next(shuffle_idle_cpu, shuffle_tmp_mask); if (shuffle_idle_cpu >= nr_cpu_ids) shuffle_idle_cpu = -1; - if (shuffle_idle_cpu != -1) { + else cpumask_clear_cpu(shuffle_idle_cpu, shuffle_tmp_mask); - if (cpumask_empty(shuffle_tmp_mask)) { - put_online_cpus(); - return; - } - } mutex_lock(&shuffle_task_mutex); list_for_each_entry(stp, &shuffle_task_list, st_l) @@ -533,7 +528,11 @@ void stutter_wait(const char *title) while (ACCESS_ONCE(stutter_pause_test) || (torture_runnable && !ACCESS_ONCE(*torture_runnable))) { if (stutter_pause_test) - schedule_timeout_interruptible(1); + if (ACCESS_ONCE(stutter_pause_test) == 1) + schedule_timeout_interruptible(1); + else + while (ACCESS_ONCE(stutter_pause_test)) + cond_resched(); else schedule_timeout_interruptible(round_jiffies_relative(HZ)); torture_shutdown_absorb(title); @@ -550,7 +549,11 @@ static int torture_stutter(void *arg) VERBOSE_TOROUT_STRING("torture_stutter task started"); do { if (!torture_must_stop()) { - schedule_timeout_interruptible(stutter); + if (stutter > 1) { + schedule_timeout_interruptible(stutter - 1); + ACCESS_ONCE(stutter_pause_test) = 2; + } + schedule_timeout_interruptible(1); ACCESS_ONCE(stutter_pause_test) = 1; } if (!torture_must_stop()) @@ -596,21 +599,27 @@ static void torture_stutter_cleanup(void) * The runnable parameter points to a flag that controls whether or not * the test is currently runnable. If there is no such flag, pass in NULL. */ -void __init torture_init_begin(char *ttype, bool v, int *runnable) +bool torture_init_begin(char *ttype, bool v, int *runnable) { mutex_lock(&fullstop_mutex); + if (torture_type != NULL) { + pr_alert("torture_init_begin: refusing %s init: %s running", + ttype, torture_type); + mutex_unlock(&fullstop_mutex); + return false; + } torture_type = ttype; verbose = v; torture_runnable = runnable; fullstop = FULLSTOP_DONTSTOP; - + return true; } EXPORT_SYMBOL_GPL(torture_init_begin); /* * Tell the torture module that initialization is complete. */ -void __init torture_init_end(void) +void torture_init_end(void) { mutex_unlock(&fullstop_mutex); register_reboot_notifier(&torture_shutdown_nb); @@ -642,6 +651,9 @@ bool torture_cleanup(void) torture_shuffle_cleanup(); torture_stutter_cleanup(); torture_onoff_cleanup(); + mutex_lock(&fullstop_mutex); + torture_type = NULL; + mutex_unlock(&fullstop_mutex); return false; } EXPORT_SYMBOL_GPL(torture_cleanup); @@ -674,8 +686,11 @@ EXPORT_SYMBOL_GPL(torture_must_stop_irq); */ void torture_kthread_stopping(char *title) { + char buf[128]; + + snprintf(buf, sizeof(buf), "Stopping %s", title); if (verbose) - VERBOSE_TOROUT_STRING(title); + VERBOSE_TOROUT_STRING(buf); while (!kthread_should_stop()) { torture_shutdown_absorb(title); schedule_timeout_uninterruptible(1); diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 4a54a25afa2fe6..5973827ff60e2f 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -62,7 +62,7 @@ #define FTRACE_HASH_DEFAULT_BITS 10 #define FTRACE_HASH_MAX_BITS 12 -#define FL_GLOBAL_CONTROL_MASK (FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_CONTROL) +#define FL_GLOBAL_CONTROL_MASK (FTRACE_OPS_FL_CONTROL) #ifdef CONFIG_DYNAMIC_FTRACE #define INIT_REGEX_LOCK(opsname) \ @@ -103,7 +103,6 @@ static int ftrace_disabled __read_mostly; static DEFINE_MUTEX(ftrace_lock); -static struct ftrace_ops *ftrace_global_list __read_mostly = &ftrace_list_end; static struct ftrace_ops *ftrace_control_list __read_mostly = &ftrace_list_end; static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end; ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; @@ -171,23 +170,6 @@ int ftrace_nr_registered_ops(void) return cnt; } -static void -ftrace_global_list_func(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct pt_regs *regs) -{ - int bit; - - bit = trace_test_and_set_recursion(TRACE_GLOBAL_START, TRACE_GLOBAL_MAX); - if (bit < 0) - return; - - do_for_each_ftrace_op(op, ftrace_global_list) { - op->func(ip, parent_ip, op, regs); - } while_for_each_ftrace_op(op); - - trace_clear_recursion(bit); -} - static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs) { @@ -237,43 +219,6 @@ static int control_ops_alloc(struct ftrace_ops *ops) return 0; } -static void update_global_ops(void) -{ - ftrace_func_t func = ftrace_global_list_func; - void *private = NULL; - - /* The list has its own recursion protection. */ - global_ops.flags |= FTRACE_OPS_FL_RECURSION_SAFE; - - /* - * If there's only one function registered, then call that - * function directly. Otherwise, we need to iterate over the - * registered callers. - */ - if (ftrace_global_list == &ftrace_list_end || - ftrace_global_list->next == &ftrace_list_end) { - func = ftrace_global_list->func; - private = ftrace_global_list->private; - /* - * As we are calling the function directly. - * If it does not have recursion protection, - * the function_trace_op needs to be updated - * accordingly. - */ - if (!(ftrace_global_list->flags & FTRACE_OPS_FL_RECURSION_SAFE)) - global_ops.flags &= ~FTRACE_OPS_FL_RECURSION_SAFE; - } - - /* If we filter on pids, update to use the pid function */ - if (!list_empty(&ftrace_pids)) { - set_ftrace_pid_function(func); - func = ftrace_pid_func; - } - - global_ops.func = func; - global_ops.private = private; -} - static void ftrace_sync(struct work_struct *work) { /* @@ -301,8 +246,6 @@ static void update_ftrace_function(void) { ftrace_func_t func; - update_global_ops(); - /* * If we are at the end of the list and this ops is * recursion safe and not dynamic and the arch supports passing ops, @@ -314,10 +257,7 @@ static void update_ftrace_function(void) (ftrace_ops_list->flags & FTRACE_OPS_FL_RECURSION_SAFE) && !FTRACE_FORCE_LIST_FUNC)) { /* Set the ftrace_ops that the arch callback uses */ - if (ftrace_ops_list == &global_ops) - set_function_trace_op = ftrace_global_list; - else - set_function_trace_op = ftrace_ops_list; + set_function_trace_op = ftrace_ops_list; func = ftrace_ops_list->func; } else { /* Just use the default ftrace_ops */ @@ -373,6 +313,11 @@ static void update_ftrace_function(void) ftrace_trace_function = func; } +int using_ftrace_ops_list_func(void) +{ + return ftrace_trace_function == ftrace_ops_list_func; +} + static void add_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops) { ops->next = *list; @@ -434,16 +379,9 @@ static int __register_ftrace_function(struct ftrace_ops *ops) if (ops->flags & FTRACE_OPS_FL_DELETED) return -EINVAL; - if (FTRACE_WARN_ON(ops == &global_ops)) - return -EINVAL; - if (WARN_ON(ops->flags & FTRACE_OPS_FL_ENABLED)) return -EBUSY; - /* We don't support both control and global flags set. */ - if ((ops->flags & FL_GLOBAL_CONTROL_MASK) == FL_GLOBAL_CONTROL_MASK) - return -EINVAL; - #ifndef CONFIG_DYNAMIC_FTRACE_WITH_REGS /* * If the ftrace_ops specifies SAVE_REGS, then it only can be used @@ -461,10 +399,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops) if (!core_kernel_data((unsigned long)ops)) ops->flags |= FTRACE_OPS_FL_DYNAMIC; - if (ops->flags & FTRACE_OPS_FL_GLOBAL) { - add_ftrace_list_ops(&ftrace_global_list, &global_ops, ops); - ops->flags |= FTRACE_OPS_FL_ENABLED; - } else if (ops->flags & FTRACE_OPS_FL_CONTROL) { + if (ops->flags & FTRACE_OPS_FL_CONTROL) { if (control_ops_alloc(ops)) return -ENOMEM; add_ftrace_list_ops(&ftrace_control_list, &control_ops, ops); @@ -484,15 +419,7 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) if (WARN_ON(!(ops->flags & FTRACE_OPS_FL_ENABLED))) return -EBUSY; - if (FTRACE_WARN_ON(ops == &global_ops)) - return -EINVAL; - - if (ops->flags & FTRACE_OPS_FL_GLOBAL) { - ret = remove_ftrace_list_ops(&ftrace_global_list, - &global_ops, ops); - if (!ret) - ops->flags &= ~FTRACE_OPS_FL_ENABLED; - } else if (ops->flags & FTRACE_OPS_FL_CONTROL) { + if (ops->flags & FTRACE_OPS_FL_CONTROL) { ret = remove_ftrace_list_ops(&ftrace_control_list, &control_ops, ops); } else @@ -2128,15 +2055,6 @@ static int ftrace_startup(struct ftrace_ops *ops, int command) ftrace_start_up++; command |= FTRACE_UPDATE_CALLS; - /* ops marked global share the filter hashes */ - if (ops->flags & FTRACE_OPS_FL_GLOBAL) { - ops = &global_ops; - /* Don't update hash if global is already set */ - if (global_start_up) - hash_enable = false; - global_start_up++; - } - ops->flags |= FTRACE_OPS_FL_ENABLED; if (hash_enable) ftrace_hash_rec_enable(ops, 1); @@ -2166,21 +2084,10 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command) */ WARN_ON_ONCE(ftrace_start_up < 0); - if (ops->flags & FTRACE_OPS_FL_GLOBAL) { - ops = &global_ops; - global_start_up--; - WARN_ON_ONCE(global_start_up < 0); - /* Don't update hash if global still has users */ - if (global_start_up) { - WARN_ON_ONCE(!ftrace_start_up); - hash_disable = false; - } - } - if (hash_disable) ftrace_hash_rec_disable(ops, 1); - if (ops != &global_ops || !global_start_up) + if (!global_start_up) ops->flags &= ~FTRACE_OPS_FL_ENABLED; command |= FTRACE_UPDATE_CALLS; @@ -3524,10 +3431,6 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, struct ftrace_hash *hash; int ret; - /* All global ops uses the global ops filters */ - if (ops->flags & FTRACE_OPS_FL_GLOBAL) - ops = &global_ops; - if (unlikely(ftrace_disabled)) return -ENODEV; @@ -3639,8 +3542,7 @@ int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, } EXPORT_SYMBOL_GPL(ftrace_set_notrace); /** - * ftrace_set_filter - set a function to filter on in ftrace - * @ops - the ops to set the filter with + * ftrace_set_global_filter - set a function to filter on with global tracers * @buf - the string that holds the function filter text. * @len - the length of the string. * @reset - non zero to reset all filters before applying this filter. @@ -3655,8 +3557,7 @@ void ftrace_set_global_filter(unsigned char *buf, int len, int reset) EXPORT_SYMBOL_GPL(ftrace_set_global_filter); /** - * ftrace_set_notrace - set a function to not trace in ftrace - * @ops - the ops to set the notrace filter with + * ftrace_set_global_notrace - set a function to not trace with global tracers * @buf - the string that holds the function notrace text. * @len - the length of the string. * @reset - non zero to reset all filters before applying this filter. @@ -4443,6 +4344,34 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs) #endif /* CONFIG_DYNAMIC_FTRACE */ +__init void ftrace_init_global_array_ops(struct trace_array *tr) +{ + tr->ops = &global_ops; + tr->ops->private = tr; +} + +void ftrace_init_array_ops(struct trace_array *tr, ftrace_func_t func) +{ + /* If we filter on pids, update to use the pid function */ + if (tr->flags & TRACE_ARRAY_FL_GLOBAL) { + if (WARN_ON(tr->ops->func != ftrace_stub)) + printk("ftrace ops had %pS for function\n", + tr->ops->func); + /* Only the top level instance does pid tracing */ + if (!list_empty(&ftrace_pids)) { + set_ftrace_pid_function(func); + func = ftrace_pid_func; + } + } + tr->ops->func = func; + tr->ops->private = tr; +} + +void ftrace_reset_array_ops(struct trace_array *tr) +{ + tr->ops->func = ftrace_stub; +} + static void ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs) @@ -4501,9 +4430,16 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, */ preempt_disable_notrace(); do_for_each_ftrace_op(op, ftrace_ops_list) { - if (ftrace_ops_test(op, ip, regs)) + if (ftrace_ops_test(op, ip, regs)) { + if (WARN_ON(!op->func)) { + function_trace_stop = 1; + printk("op=%p %pS\n", op, op); + goto out; + } op->func(ip, parent_ip, op, regs); + } } while_for_each_ftrace_op(op); +out: preempt_enable_notrace(); trace_clear_recursion(bit); } @@ -4908,7 +4844,6 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, #ifdef CONFIG_FUNCTION_GRAPH_TRACER static int ftrace_graph_active; -static struct notifier_block ftrace_suspend_notifier; int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace) { @@ -5057,8 +4992,7 @@ ftrace_suspend_notifier_call(struct notifier_block *bl, unsigned long state, /* Just a place holder for function graph */ static struct ftrace_ops fgraph_ops __read_mostly = { .func = ftrace_stub, - .flags = FTRACE_OPS_FL_STUB | FTRACE_OPS_FL_GLOBAL | - FTRACE_OPS_FL_RECURSION_SAFE, + .flags = FTRACE_OPS_FL_STUB | FTRACE_OPS_FL_RECURSION_SAFE, }; static int ftrace_graph_entry_test(struct ftrace_graph_ent *trace) @@ -5085,6 +5019,10 @@ static void update_function_graph_func(void) ftrace_graph_entry = ftrace_graph_entry_test; } +static struct notifier_block ftrace_suspend_notifier = { + .notifier_call = ftrace_suspend_notifier_call, +}; + int register_ftrace_graph(trace_func_graph_ret_t retfunc, trace_func_graph_ent_t entryfunc) { @@ -5098,7 +5036,6 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc, goto out; } - ftrace_suspend_notifier.notifier_call = ftrace_suspend_notifier_call; register_pm_notifier(&ftrace_suspend_notifier); ftrace_graph_active++; diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 737b0efa1a624a..4c392c8238bf95 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -275,7 +275,7 @@ int call_filter_check_discard(struct ftrace_event_call *call, void *rec, } EXPORT_SYMBOL_GPL(call_filter_check_discard); -cycle_t buffer_ftrace_now(struct trace_buffer *buf, int cpu) +static cycle_t buffer_ftrace_now(struct trace_buffer *buf, int cpu) { u64 ts; @@ -599,7 +599,7 @@ static int alloc_snapshot(struct trace_array *tr) return 0; } -void free_snapshot(struct trace_array *tr) +static void free_snapshot(struct trace_array *tr) { /* * We don't free the ring buffer. instead, resize it because @@ -963,27 +963,9 @@ static ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt) return cnt; } -/* - * ftrace_max_lock is used to protect the swapping of buffers - * when taking a max snapshot. The buffers themselves are - * protected by per_cpu spinlocks. But the action of the swap - * needs its own lock. - * - * This is defined as a arch_spinlock_t in order to help - * with performance when lockdep debugging is enabled. - * - * It is also used in other places outside the update_max_tr - * so it needs to be defined outside of the - * CONFIG_TRACER_MAX_TRACE. - */ -static arch_spinlock_t ftrace_max_lock = - (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; - unsigned long __read_mostly tracing_thresh; #ifdef CONFIG_TRACER_MAX_TRACE -unsigned long __read_mostly tracing_max_latency; - /* * Copy the new maximum trace into the separate maximum-trace * structure. (this way the maximum trace is permanently saved, @@ -1000,7 +982,7 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) max_buf->cpu = cpu; max_buf->time_start = data->preempt_timestamp; - max_data->saved_latency = tracing_max_latency; + max_data->saved_latency = tr->max_latency; max_data->critical_start = data->critical_start; max_data->critical_end = data->critical_end; @@ -1048,14 +1030,14 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) return; } - arch_spin_lock(&ftrace_max_lock); + arch_spin_lock(&tr->max_lock); buf = tr->trace_buffer.buffer; tr->trace_buffer.buffer = tr->max_buffer.buffer; tr->max_buffer.buffer = buf; __update_max_tr(tr, tsk, cpu); - arch_spin_unlock(&ftrace_max_lock); + arch_spin_unlock(&tr->max_lock); } /** @@ -1081,7 +1063,7 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu) return; } - arch_spin_lock(&ftrace_max_lock); + arch_spin_lock(&tr->max_lock); ret = ring_buffer_swap_cpu(tr->max_buffer.buffer, tr->trace_buffer.buffer, cpu); @@ -1099,11 +1081,11 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu) WARN_ON_ONCE(ret && ret != -EAGAIN && ret != -EBUSY); __update_max_tr(tr, tsk, cpu); - arch_spin_unlock(&ftrace_max_lock); + arch_spin_unlock(&tr->max_lock); } #endif /* CONFIG_TRACER_MAX_TRACE */ -static void default_wait_pipe(struct trace_iterator *iter) +static void wait_on_pipe(struct trace_iterator *iter) { /* Iterators are static, they should be filled or empty */ if (trace_buffer_iter(iter, iter->cpu_file)) @@ -1220,8 +1202,6 @@ int register_tracer(struct tracer *type) else if (!type->flags->opts) type->flags->opts = dummy_tracer_opt; - if (!type->wait_pipe) - type->wait_pipe = default_wait_pipe; ret = run_tracer_selftest(type); if (ret < 0) @@ -1353,7 +1333,7 @@ void tracing_start(void) } /* Prevent the buffers from switching */ - arch_spin_lock(&ftrace_max_lock); + arch_spin_lock(&global_trace.max_lock); buffer = global_trace.trace_buffer.buffer; if (buffer) @@ -1365,7 +1345,7 @@ void tracing_start(void) ring_buffer_record_enable(buffer); #endif - arch_spin_unlock(&ftrace_max_lock); + arch_spin_unlock(&global_trace.max_lock); ftrace_start(); out: @@ -1420,7 +1400,7 @@ void tracing_stop(void) goto out; /* Prevent the buffers from switching */ - arch_spin_lock(&ftrace_max_lock); + arch_spin_lock(&global_trace.max_lock); buffer = global_trace.trace_buffer.buffer; if (buffer) @@ -1432,7 +1412,7 @@ void tracing_stop(void) ring_buffer_record_disable(buffer); #endif - arch_spin_unlock(&ftrace_max_lock); + arch_spin_unlock(&global_trace.max_lock); out: raw_spin_unlock_irqrestore(&global_trace.start_lock, flags); @@ -3333,7 +3313,7 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf, mutex_lock(&tracing_cpumask_update_lock); local_irq_disable(); - arch_spin_lock(&ftrace_max_lock); + arch_spin_lock(&tr->max_lock); for_each_tracing_cpu(cpu) { /* * Increase/decrease the disabled counter if we are @@ -3350,7 +3330,7 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf, ring_buffer_record_enable_cpu(tr->trace_buffer.buffer, cpu); } } - arch_spin_unlock(&ftrace_max_lock); + arch_spin_unlock(&tr->max_lock); local_irq_enable(); cpumask_copy(tr->tracing_cpumask, tracing_cpumask_new); @@ -4225,25 +4205,6 @@ tracing_poll_pipe(struct file *filp, poll_table *poll_table) return trace_poll(iter, filp, poll_table); } -/* - * This is a make-shift waitqueue. - * A tracer might use this callback on some rare cases: - * - * 1) the current tracer might hold the runqueue lock when it wakes up - * a reader, hence a deadlock (sched, function, and function graph tracers) - * 2) the function tracers, trace all functions, we don't want - * the overhead of calling wake_up and friends - * (and tracing them too) - * - * Anyway, this is really very primitive wakeup. - */ -void poll_wait_pipe(struct trace_iterator *iter) -{ - set_current_state(TASK_INTERRUPTIBLE); - /* sleep for 100 msecs, and try again. */ - schedule_timeout(HZ / 10); -} - /* Must be called with trace_types_lock mutex held. */ static int tracing_wait_pipe(struct file *filp) { @@ -4255,15 +4216,6 @@ static int tracing_wait_pipe(struct file *filp) return -EAGAIN; } - mutex_unlock(&iter->mutex); - - iter->trace->wait_pipe(iter); - - mutex_lock(&iter->mutex); - - if (signal_pending(current)) - return -EINTR; - /* * We block until we read something and tracing is disabled. * We still block if tracing is disabled, but we have never @@ -4275,6 +4227,15 @@ static int tracing_wait_pipe(struct file *filp) */ if (!tracing_is_on() && iter->pos) break; + + mutex_unlock(&iter->mutex); + + wait_on_pipe(iter); + + mutex_lock(&iter->mutex); + + if (signal_pending(current)) + return -EINTR; } return 1; @@ -5197,7 +5158,7 @@ tracing_buffers_read(struct file *filp, char __user *ubuf, goto out_unlock; } mutex_unlock(&trace_types_lock); - iter->trace->wait_pipe(iter); + wait_on_pipe(iter); mutex_lock(&trace_types_lock); if (signal_pending(current)) { size = -EINTR; @@ -5408,7 +5369,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, goto out; } mutex_unlock(&trace_types_lock); - iter->trace->wait_pipe(iter); + wait_on_pipe(iter); mutex_lock(&trace_types_lock); if (signal_pending(current)) { ret = -EINTR; @@ -6131,6 +6092,8 @@ static int new_instance_create(const char *name) raw_spin_lock_init(&tr->start_lock); + tr->max_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; + tr->current_trace = &nop_trace; INIT_LIST_HEAD(&tr->systems); @@ -6328,6 +6291,11 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer) trace_create_file("tracing_on", 0644, d_tracer, tr, &rb_simple_fops); +#ifdef CONFIG_TRACER_MAX_TRACE + trace_create_file("tracing_max_latency", 0644, d_tracer, + &tr->max_latency, &tracing_max_lat_fops); +#endif + if (ftrace_create_function_files(tr, d_tracer)) WARN(1, "Could not allocate function filter files"); @@ -6353,11 +6321,6 @@ static __init int tracer_init_debugfs(void) init_tracer_debugfs(&global_trace, d_tracer); -#ifdef CONFIG_TRACER_MAX_TRACE - trace_create_file("tracing_max_latency", 0644, d_tracer, - &tracing_max_latency, &tracing_max_lat_fops); -#endif - trace_create_file("tracing_thresh", 0644, d_tracer, &tracing_thresh, &tracing_max_lat_fops); @@ -6629,6 +6592,10 @@ __init static int tracer_alloc_buffers(void) */ global_trace.current_trace = &nop_trace; + global_trace.max_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; + + ftrace_init_global_array_ops(&global_trace); + register_tracer(&nop_trace); /* All seems OK, enable tracing */ diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 2e29d7ba5a52b0..3b3e09e61f338d 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -190,7 +190,22 @@ struct trace_array { */ struct trace_buffer max_buffer; bool allocated_snapshot; + unsigned long max_latency; #endif + /* + * max_lock is used to protect the swapping of buffers + * when taking a max snapshot. The buffers themselves are + * protected by per_cpu spinlocks. But the action of the swap + * needs its own lock. + * + * This is defined as a arch_spinlock_t in order to help + * with performance when lockdep debugging is enabled. + * + * It is also used in other places outside the update_max_tr + * so it needs to be defined outside of the + * CONFIG_TRACER_MAX_TRACE. + */ + arch_spinlock_t max_lock; int buffer_disabled; #ifdef CONFIG_FTRACE_SYSCALLS int sys_refcount_enter; @@ -323,7 +338,6 @@ struct tracer_flags { * @stop: called when tracing is paused (echo 0 > tracing_enabled) * @open: called when the trace file is opened * @pipe_open: called when the trace_pipe file is opened - * @wait_pipe: override how the user waits for traces on trace_pipe * @close: called when the trace file is released * @pipe_close: called when the trace_pipe file is released * @read: override the default read callback on trace_pipe @@ -342,7 +356,6 @@ struct tracer { void (*stop)(struct trace_array *tr); void (*open)(struct trace_iterator *iter); void (*pipe_open)(struct trace_iterator *iter); - void (*wait_pipe)(struct trace_iterator *iter); void (*close)(struct trace_iterator *iter); void (*pipe_close)(struct trace_iterator *iter); ssize_t (*read)(struct trace_iterator *iter, @@ -416,13 +429,7 @@ enum { TRACE_FTRACE_IRQ_BIT, TRACE_FTRACE_SIRQ_BIT, - /* GLOBAL_BITs must be greater than FTRACE_BITs */ - TRACE_GLOBAL_BIT, - TRACE_GLOBAL_NMI_BIT, - TRACE_GLOBAL_IRQ_BIT, - TRACE_GLOBAL_SIRQ_BIT, - - /* INTERNAL_BITs must be greater than GLOBAL_BITs */ + /* INTERNAL_BITs must be greater than FTRACE_BITs */ TRACE_INTERNAL_BIT, TRACE_INTERNAL_NMI_BIT, TRACE_INTERNAL_IRQ_BIT, @@ -449,9 +456,6 @@ enum { #define TRACE_FTRACE_START TRACE_FTRACE_BIT #define TRACE_FTRACE_MAX ((1 << (TRACE_FTRACE_START + TRACE_CONTEXT_BITS)) - 1) -#define TRACE_GLOBAL_START TRACE_GLOBAL_BIT -#define TRACE_GLOBAL_MAX ((1 << (TRACE_GLOBAL_START + TRACE_CONTEXT_BITS)) - 1) - #define TRACE_LIST_START TRACE_INTERNAL_BIT #define TRACE_LIST_MAX ((1 << (TRACE_LIST_START + TRACE_CONTEXT_BITS)) - 1) @@ -560,8 +564,6 @@ void trace_init_global_iter(struct trace_iterator *iter); void tracing_iter_reset(struct trace_iterator *iter, int cpu); -void poll_wait_pipe(struct trace_iterator *iter); - void tracing_sched_switch_trace(struct trace_array *tr, struct task_struct *prev, struct task_struct *next, @@ -608,8 +610,6 @@ extern unsigned long nsecs_to_usecs(unsigned long nsecs); extern unsigned long tracing_thresh; #ifdef CONFIG_TRACER_MAX_TRACE -extern unsigned long tracing_max_latency; - void update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu); void update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu); @@ -823,6 +823,10 @@ extern int ftrace_is_dead(void); int ftrace_create_function_files(struct trace_array *tr, struct dentry *parent); void ftrace_destroy_function_files(struct trace_array *tr); +void ftrace_init_global_array_ops(struct trace_array *tr); +void ftrace_init_array_ops(struct trace_array *tr, ftrace_func_t func); +void ftrace_reset_array_ops(struct trace_array *tr); +int using_ftrace_ops_list_func(void); #else static inline int ftrace_trace_task(struct task_struct *task) { @@ -836,6 +840,11 @@ ftrace_create_function_files(struct trace_array *tr, return 0; } static inline void ftrace_destroy_function_files(struct trace_array *tr) { } +static inline __init void +ftrace_init_global_array_ops(struct trace_array *tr) { } +static inline void ftrace_reset_array_ops(struct trace_array *tr) { } +/* ftace_func_t type is not defined, use macro instead of static inline */ +#define ftrace_init_array_ops(tr, func) do { } while (0) #endif /* CONFIG_FUNCTION_TRACER */ #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_DYNAMIC_FTRACE) diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index c894614de14d8e..5d12bb407b4429 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -248,8 +248,8 @@ void perf_trace_del(struct perf_event *p_event, int flags) tp_event->class->reg(tp_event, TRACE_REG_PERF_DEL, p_event); } -__kprobes void *perf_trace_buf_prepare(int size, unsigned short type, - struct pt_regs *regs, int *rctxp) +void *perf_trace_buf_prepare(int size, unsigned short type, + struct pt_regs *regs, int *rctxp) { struct trace_entry *entry; unsigned long flags; @@ -281,6 +281,7 @@ __kprobes void *perf_trace_buf_prepare(int size, unsigned short type, return raw_data; } EXPORT_SYMBOL_GPL(perf_trace_buf_prepare); +NOKPROBE_SYMBOL(perf_trace_buf_prepare); #ifdef CONFIG_FUNCTION_TRACER static void diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index ffd56351b5217d..57f0ec962d2cae 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c @@ -26,8 +26,6 @@ function_trace_call(unsigned long ip, unsigned long parent_ip, static void function_stack_trace_call(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *pt_regs); -static struct ftrace_ops trace_ops; -static struct ftrace_ops trace_stack_ops; static struct tracer_flags func_flags; /* Our option */ @@ -83,28 +81,24 @@ void ftrace_destroy_function_files(struct trace_array *tr) static int function_trace_init(struct trace_array *tr) { - struct ftrace_ops *ops; - - if (tr->flags & TRACE_ARRAY_FL_GLOBAL) { - /* There's only one global tr */ - if (!trace_ops.private) { - trace_ops.private = tr; - trace_stack_ops.private = tr; - } + ftrace_func_t func; - if (func_flags.val & TRACE_FUNC_OPT_STACK) - ops = &trace_stack_ops; - else - ops = &trace_ops; - tr->ops = ops; - } else if (!tr->ops) { - /* - * Instance trace_arrays get their ops allocated - * at instance creation. Unless it failed - * the allocation. - */ + /* + * Instance trace_arrays get their ops allocated + * at instance creation. Unless it failed + * the allocation. + */ + if (!tr->ops) return -ENOMEM; - } + + /* Currently only the global instance can do stack tracing */ + if (tr->flags & TRACE_ARRAY_FL_GLOBAL && + func_flags.val & TRACE_FUNC_OPT_STACK) + func = function_stack_trace_call; + else + func = function_trace_call; + + ftrace_init_array_ops(tr, func); tr->trace_buffer.cpu = get_cpu(); put_cpu(); @@ -118,6 +112,7 @@ static void function_trace_reset(struct trace_array *tr) { tracing_stop_function_trace(tr); tracing_stop_cmdline_record(); + ftrace_reset_array_ops(tr); } static void function_trace_start(struct trace_array *tr) @@ -199,18 +194,6 @@ function_stack_trace_call(unsigned long ip, unsigned long parent_ip, local_irq_restore(flags); } -static struct ftrace_ops trace_ops __read_mostly = -{ - .func = function_trace_call, - .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE, -}; - -static struct ftrace_ops trace_stack_ops __read_mostly = -{ - .func = function_stack_trace_call, - .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE, -}; - static struct tracer_opt func_opts[] = { #ifdef CONFIG_STACKTRACE { TRACER_OPT(func_stack_trace, TRACE_FUNC_OPT_STACK) }, @@ -248,10 +231,10 @@ func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) unregister_ftrace_function(tr->ops); if (set) { - tr->ops = &trace_stack_ops; + tr->ops->func = function_stack_trace_call; register_ftrace_function(tr->ops); } else { - tr->ops = &trace_ops; + tr->ops->func = function_trace_call; register_ftrace_function(tr->ops); } @@ -269,7 +252,6 @@ static struct tracer function_trace __tracer_data = .init = function_trace_init, .reset = function_trace_reset, .start = function_trace_start, - .wait_pipe = poll_wait_pipe, .flags = &func_flags, .set_flag = func_set_flag, .allow_instances = true, diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index deff11200261b5..b86dd4d8c6a67e 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -1505,7 +1505,6 @@ static struct tracer graph_trace __tracer_data = { .pipe_open = graph_trace_open, .close = graph_trace_close, .pipe_close = graph_trace_close, - .wait_pipe = poll_wait_pipe, .init = graph_trace_init, .reset = graph_trace_reset, .print_line = print_graph_function, diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index 8ff02cbb892fb4..9bb104f748d0c0 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c @@ -151,12 +151,6 @@ irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip, atomic_dec(&data->disabled); } - -static struct ftrace_ops trace_ops __read_mostly = -{ - .func = irqsoff_tracer_call, - .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE, -}; #endif /* CONFIG_FUNCTION_TRACER */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER @@ -176,7 +170,7 @@ irqsoff_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) for_each_possible_cpu(cpu) per_cpu(tracing_cpu, cpu) = 0; - tracing_max_latency = 0; + tr->max_latency = 0; tracing_reset_online_cpus(&irqsoff_trace->trace_buffer); return start_irqsoff_tracer(irqsoff_trace, set); @@ -303,13 +297,13 @@ static void irqsoff_print_header(struct seq_file *s) /* * Should this new latency be reported/recorded? */ -static int report_latency(cycle_t delta) +static int report_latency(struct trace_array *tr, cycle_t delta) { if (tracing_thresh) { if (delta < tracing_thresh) return 0; } else { - if (delta <= tracing_max_latency) + if (delta <= tr->max_latency) return 0; } return 1; @@ -333,13 +327,13 @@ check_critical_timing(struct trace_array *tr, pc = preempt_count(); - if (!report_latency(delta)) + if (!report_latency(tr, delta)) goto out; raw_spin_lock_irqsave(&max_trace_lock, flags); /* check if we are still the max latency */ - if (!report_latency(delta)) + if (!report_latency(tr, delta)) goto out_unlock; __trace_function(tr, CALLER_ADDR0, parent_ip, flags, pc); @@ -352,7 +346,7 @@ check_critical_timing(struct trace_array *tr, data->critical_end = parent_ip; if (likely(!is_tracing_stopped())) { - tracing_max_latency = delta; + tr->max_latency = delta; update_max_tr_single(tr, current, cpu); } @@ -531,7 +525,7 @@ void trace_preempt_off(unsigned long a0, unsigned long a1) } #endif /* CONFIG_PREEMPT_TRACER */ -static int register_irqsoff_function(int graph, int set) +static int register_irqsoff_function(struct trace_array *tr, int graph, int set) { int ret; @@ -543,7 +537,7 @@ static int register_irqsoff_function(int graph, int set) ret = register_ftrace_graph(&irqsoff_graph_return, &irqsoff_graph_entry); else - ret = register_ftrace_function(&trace_ops); + ret = register_ftrace_function(tr->ops); if (!ret) function_enabled = true; @@ -551,7 +545,7 @@ static int register_irqsoff_function(int graph, int set) return ret; } -static void unregister_irqsoff_function(int graph) +static void unregister_irqsoff_function(struct trace_array *tr, int graph) { if (!function_enabled) return; @@ -559,17 +553,17 @@ static void unregister_irqsoff_function(int graph) if (graph) unregister_ftrace_graph(); else - unregister_ftrace_function(&trace_ops); + unregister_ftrace_function(tr->ops); function_enabled = false; } -static void irqsoff_function_set(int set) +static void irqsoff_function_set(struct trace_array *tr, int set) { if (set) - register_irqsoff_function(is_graph(), 1); + register_irqsoff_function(tr, is_graph(), 1); else - unregister_irqsoff_function(is_graph()); + unregister_irqsoff_function(tr, is_graph()); } static int irqsoff_flag_changed(struct trace_array *tr, u32 mask, int set) @@ -577,7 +571,7 @@ static int irqsoff_flag_changed(struct trace_array *tr, u32 mask, int set) struct tracer *tracer = tr->current_trace; if (mask & TRACE_ITER_FUNCTION) - irqsoff_function_set(set); + irqsoff_function_set(tr, set); return trace_keep_overwrite(tracer, mask, set); } @@ -586,7 +580,7 @@ static int start_irqsoff_tracer(struct trace_array *tr, int graph) { int ret; - ret = register_irqsoff_function(graph, 0); + ret = register_irqsoff_function(tr, graph, 0); if (!ret && tracing_is_enabled()) tracer_enabled = 1; @@ -600,25 +594,37 @@ static void stop_irqsoff_tracer(struct trace_array *tr, int graph) { tracer_enabled = 0; - unregister_irqsoff_function(graph); + unregister_irqsoff_function(tr, graph); } -static void __irqsoff_tracer_init(struct trace_array *tr) +static bool irqsoff_busy; + +static int __irqsoff_tracer_init(struct trace_array *tr) { + if (irqsoff_busy) + return -EBUSY; + save_flags = trace_flags; /* non overwrite screws up the latency tracers */ set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1); set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1); - tracing_max_latency = 0; + tr->max_latency = 0; irqsoff_trace = tr; /* make sure that the tracer is visible */ smp_wmb(); tracing_reset_online_cpus(&tr->trace_buffer); - if (start_irqsoff_tracer(tr, is_graph())) + ftrace_init_array_ops(tr, irqsoff_tracer_call); + + /* Only toplevel instance supports graph tracing */ + if (start_irqsoff_tracer(tr, (tr->flags & TRACE_ARRAY_FL_GLOBAL && + is_graph()))) printk(KERN_ERR "failed to start irqsoff tracer\n"); + + irqsoff_busy = true; + return 0; } static void irqsoff_tracer_reset(struct trace_array *tr) @@ -630,6 +636,9 @@ static void irqsoff_tracer_reset(struct trace_array *tr) set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag); set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag); + ftrace_reset_array_ops(tr); + + irqsoff_busy = false; } static void irqsoff_tracer_start(struct trace_array *tr) @@ -647,8 +656,7 @@ static int irqsoff_tracer_init(struct trace_array *tr) { trace_type = TRACER_IRQS_OFF; - __irqsoff_tracer_init(tr); - return 0; + return __irqsoff_tracer_init(tr); } static struct tracer irqsoff_tracer __read_mostly = { @@ -668,6 +676,7 @@ static struct tracer irqsoff_tracer __read_mostly = #endif .open = irqsoff_trace_open, .close = irqsoff_trace_close, + .allow_instances = true, .use_max_tr = true, }; # define register_irqsoff(trace) register_tracer(&trace) @@ -680,8 +689,7 @@ static int preemptoff_tracer_init(struct trace_array *tr) { trace_type = TRACER_PREEMPT_OFF; - __irqsoff_tracer_init(tr); - return 0; + return __irqsoff_tracer_init(tr); } static struct tracer preemptoff_tracer __read_mostly = @@ -702,6 +710,7 @@ static struct tracer preemptoff_tracer __read_mostly = #endif .open = irqsoff_trace_open, .close = irqsoff_trace_close, + .allow_instances = true, .use_max_tr = true, }; # define register_preemptoff(trace) register_tracer(&trace) @@ -716,8 +725,7 @@ static int preemptirqsoff_tracer_init(struct trace_array *tr) { trace_type = TRACER_IRQS_OFF | TRACER_PREEMPT_OFF; - __irqsoff_tracer_init(tr); - return 0; + return __irqsoff_tracer_init(tr); } static struct tracer preemptirqsoff_tracer __read_mostly = @@ -738,6 +746,7 @@ static struct tracer preemptirqsoff_tracer __read_mostly = #endif .open = irqsoff_trace_open, .close = irqsoff_trace_close, + .allow_instances = true, .use_max_tr = true, }; diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 903ae28962be7f..242e4ec97d94b0 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -40,27 +40,27 @@ struct trace_kprobe { (sizeof(struct probe_arg) * (n))) -static __kprobes bool trace_kprobe_is_return(struct trace_kprobe *tk) +static nokprobe_inline bool trace_kprobe_is_return(struct trace_kprobe *tk) { return tk->rp.handler != NULL; } -static __kprobes const char *trace_kprobe_symbol(struct trace_kprobe *tk) +static nokprobe_inline const char *trace_kprobe_symbol(struct trace_kprobe *tk) { return tk->symbol ? tk->symbol : "unknown"; } -static __kprobes unsigned long trace_kprobe_offset(struct trace_kprobe *tk) +static nokprobe_inline unsigned long trace_kprobe_offset(struct trace_kprobe *tk) { return tk->rp.kp.offset; } -static __kprobes bool trace_kprobe_has_gone(struct trace_kprobe *tk) +static nokprobe_inline bool trace_kprobe_has_gone(struct trace_kprobe *tk) { return !!(kprobe_gone(&tk->rp.kp)); } -static __kprobes bool trace_kprobe_within_module(struct trace_kprobe *tk, +static nokprobe_inline bool trace_kprobe_within_module(struct trace_kprobe *tk, struct module *mod) { int len = strlen(mod->name); @@ -68,7 +68,7 @@ static __kprobes bool trace_kprobe_within_module(struct trace_kprobe *tk, return strncmp(mod->name, name, len) == 0 && name[len] == ':'; } -static __kprobes bool trace_kprobe_is_on_module(struct trace_kprobe *tk) +static nokprobe_inline bool trace_kprobe_is_on_module(struct trace_kprobe *tk) { return !!strchr(trace_kprobe_symbol(tk), ':'); } @@ -132,19 +132,21 @@ struct symbol_cache *alloc_symbol_cache(const char *sym, long offset) * Kprobes-specific fetch functions */ #define DEFINE_FETCH_stack(type) \ -static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\ +static void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs, \ void *offset, void *dest) \ { \ *(type *)dest = (type)regs_get_kernel_stack_nth(regs, \ (unsigned int)((unsigned long)offset)); \ -} +} \ +NOKPROBE_SYMBOL(FETCH_FUNC_NAME(stack, type)); + DEFINE_BASIC_FETCH_FUNCS(stack) /* No string on the stack entry */ #define fetch_stack_string NULL #define fetch_stack_string_size NULL #define DEFINE_FETCH_memory(type) \ -static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ +static void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs, \ void *addr, void *dest) \ { \ type retval; \ @@ -152,14 +154,16 @@ static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ *(type *)dest = 0; \ else \ *(type *)dest = retval; \ -} +} \ +NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, type)); + DEFINE_BASIC_FETCH_FUNCS(memory) /* * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max * length and relative data location. */ -static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, - void *addr, void *dest) +static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, + void *addr, void *dest) { long ret; int maxlen = get_rloc_len(*(u32 *)dest); @@ -193,10 +197,11 @@ static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, get_rloc_offs(*(u32 *)dest)); } } +NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string)); /* Return the length of string -- including null terminal byte */ -static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, - void *addr, void *dest) +static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, + void *addr, void *dest) { mm_segment_t old_fs; int ret, len = 0; @@ -219,17 +224,19 @@ static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, else *(u32 *)dest = len; } +NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string_size)); #define DEFINE_FETCH_symbol(type) \ -__kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, \ - void *data, void *dest) \ +void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, void *data, void *dest)\ { \ struct symbol_cache *sc = data; \ if (sc->addr) \ fetch_memory_##type(regs, (void *)sc->addr, dest); \ else \ *(type *)dest = 0; \ -} +} \ +NOKPROBE_SYMBOL(FETCH_FUNC_NAME(symbol, type)); + DEFINE_BASIC_FETCH_FUNCS(symbol) DEFINE_FETCH_symbol(string) DEFINE_FETCH_symbol(string_size) @@ -907,7 +914,7 @@ static const struct file_operations kprobe_profile_ops = { }; /* Kprobe handler */ -static __kprobes void +static nokprobe_inline void __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs, struct ftrace_event_file *ftrace_file) { @@ -943,7 +950,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs, entry, irq_flags, pc, regs); } -static __kprobes void +static void kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs) { struct event_file_link *link; @@ -951,9 +958,10 @@ kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs) list_for_each_entry_rcu(link, &tk->tp.files, list) __kprobe_trace_func(tk, regs, link->file); } +NOKPROBE_SYMBOL(kprobe_trace_func); /* Kretprobe handler */ -static __kprobes void +static nokprobe_inline void __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, struct pt_regs *regs, struct ftrace_event_file *ftrace_file) @@ -991,7 +999,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, entry, irq_flags, pc, regs); } -static __kprobes void +static void kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, struct pt_regs *regs) { @@ -1000,6 +1008,7 @@ kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, list_for_each_entry_rcu(link, &tk->tp.files, list) __kretprobe_trace_func(tk, ri, regs, link->file); } +NOKPROBE_SYMBOL(kretprobe_trace_func); /* Event entry printers */ static enum print_line_t @@ -1131,7 +1140,7 @@ static int kretprobe_event_define_fields(struct ftrace_event_call *event_call) #ifdef CONFIG_PERF_EVENTS /* Kprobe profile handler */ -static __kprobes void +static void kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs) { struct ftrace_event_call *call = &tk->tp.call; @@ -1158,9 +1167,10 @@ kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs) store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize); perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); } +NOKPROBE_SYMBOL(kprobe_perf_func); /* Kretprobe profile handler */ -static __kprobes void +static void kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, struct pt_regs *regs) { @@ -1188,6 +1198,7 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize); perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); } +NOKPROBE_SYMBOL(kretprobe_perf_func); #endif /* CONFIG_PERF_EVENTS */ /* @@ -1196,9 +1207,8 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, * kprobe_trace_self_tests_init() does enable_trace_probe/disable_trace_probe * lockless, but we can't race with this __init function. */ -static __kprobes -int kprobe_register(struct ftrace_event_call *event, - enum trace_reg type, void *data) +static int kprobe_register(struct ftrace_event_call *event, + enum trace_reg type, void *data) { struct trace_kprobe *tk = (struct trace_kprobe *)event->data; struct ftrace_event_file *file = data; @@ -1224,8 +1234,7 @@ int kprobe_register(struct ftrace_event_call *event, return 0; } -static __kprobes -int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) +static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) { struct trace_kprobe *tk = container_of(kp, struct trace_kprobe, rp.kp); @@ -1239,9 +1248,10 @@ int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) #endif return 0; /* We don't tweek kernel, so just return 0 */ } +NOKPROBE_SYMBOL(kprobe_dispatcher); -static __kprobes -int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs) +static int +kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs) { struct trace_kprobe *tk = container_of(ri->rp, struct trace_kprobe, rp); @@ -1255,6 +1265,7 @@ int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs) #endif return 0; /* We don't tweek kernel, so just return 0 */ } +NOKPROBE_SYMBOL(kretprobe_dispatcher); static struct trace_event_functions kretprobe_funcs = { .trace = print_kretprobe_event diff --git a/kernel/trace/trace_nop.c b/kernel/trace/trace_nop.c index 69a5cc94c01a36..fcf0a9e4891620 100644 --- a/kernel/trace/trace_nop.c +++ b/kernel/trace/trace_nop.c @@ -91,7 +91,6 @@ struct tracer nop_trace __read_mostly = .name = "nop", .init = nop_trace_init, .reset = nop_trace_reset, - .wait_pipe = poll_wait_pipe, #ifdef CONFIG_FTRACE_SELFTEST .selftest = trace_selftest_startup_nop, #endif diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 8364a421b4dfc7..d4b9fc22cd27fb 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -37,13 +37,13 @@ const char *reserved_field_names[] = { /* Printing in basic type function template */ #define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt) \ -__kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \ - const char *name, \ - void *data, void *ent) \ +int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, const char *name, \ + void *data, void *ent) \ { \ return trace_seq_printf(s, " %s=" fmt, name, *(type *)data); \ } \ -const char PRINT_TYPE_FMT_NAME(type)[] = fmt; +const char PRINT_TYPE_FMT_NAME(type)[] = fmt; \ +NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(type)); DEFINE_BASIC_PRINT_TYPE_FUNC(u8 , "0x%x") DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "0x%x") @@ -55,9 +55,8 @@ DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%d") DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%Ld") /* Print type function for string type */ -__kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, - const char *name, - void *data, void *ent) +int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, const char *name, + void *data, void *ent) { int len = *(u32 *)data >> 16; @@ -67,6 +66,7 @@ __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, return trace_seq_printf(s, " %s=\"%s\"", name, (const char *)get_loc_data(data, ent)); } +NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(string)); const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; @@ -81,23 +81,24 @@ const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; /* Data fetch function templates */ #define DEFINE_FETCH_reg(type) \ -__kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, \ - void *offset, void *dest) \ +void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, void *offset, void *dest) \ { \ *(type *)dest = (type)regs_get_register(regs, \ (unsigned int)((unsigned long)offset)); \ -} +} \ +NOKPROBE_SYMBOL(FETCH_FUNC_NAME(reg, type)); DEFINE_BASIC_FETCH_FUNCS(reg) /* No string on the register */ #define fetch_reg_string NULL #define fetch_reg_string_size NULL #define DEFINE_FETCH_retval(type) \ -__kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs, \ - void *dummy, void *dest) \ +void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs, \ + void *dummy, void *dest) \ { \ *(type *)dest = (type)regs_return_value(regs); \ -} +} \ +NOKPROBE_SYMBOL(FETCH_FUNC_NAME(retval, type)); DEFINE_BASIC_FETCH_FUNCS(retval) /* No string on the retval */ #define fetch_retval_string NULL @@ -112,8 +113,8 @@ struct deref_fetch_param { }; #define DEFINE_FETCH_deref(type) \ -__kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs, \ - void *data, void *dest) \ +void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs, \ + void *data, void *dest) \ { \ struct deref_fetch_param *dprm = data; \ unsigned long addr; \ @@ -123,12 +124,13 @@ __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs, \ dprm->fetch(regs, (void *)addr, dest); \ } else \ *(type *)dest = 0; \ -} +} \ +NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, type)); DEFINE_BASIC_FETCH_FUNCS(deref) DEFINE_FETCH_deref(string) -__kprobes void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs, - void *data, void *dest) +void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs, + void *data, void *dest) { struct deref_fetch_param *dprm = data; unsigned long addr; @@ -140,16 +142,18 @@ __kprobes void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs, } else *(string_size *)dest = 0; } +NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, string_size)); -static __kprobes void update_deref_fetch_param(struct deref_fetch_param *data) +static void update_deref_fetch_param(struct deref_fetch_param *data) { if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) update_deref_fetch_param(data->orig.data); else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) update_symbol_cache(data->orig.data); } +NOKPROBE_SYMBOL(update_deref_fetch_param); -static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data) +static void free_deref_fetch_param(struct deref_fetch_param *data) { if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) free_deref_fetch_param(data->orig.data); @@ -157,6 +161,7 @@ static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data) free_symbol_cache(data->orig.data); kfree(data); } +NOKPROBE_SYMBOL(free_deref_fetch_param); /* Bitfield fetch function */ struct bitfield_fetch_param { @@ -166,8 +171,8 @@ struct bitfield_fetch_param { }; #define DEFINE_FETCH_bitfield(type) \ -__kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs, \ - void *data, void *dest) \ +void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs, \ + void *data, void *dest) \ { \ struct bitfield_fetch_param *bprm = data; \ type buf = 0; \ @@ -177,13 +182,13 @@ __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs, \ buf >>= bprm->low_shift; \ } \ *(type *)dest = buf; \ -} - +} \ +NOKPROBE_SYMBOL(FETCH_FUNC_NAME(bitfield, type)); DEFINE_BASIC_FETCH_FUNCS(bitfield) #define fetch_bitfield_string NULL #define fetch_bitfield_string_size NULL -static __kprobes void +static void update_bitfield_fetch_param(struct bitfield_fetch_param *data) { /* @@ -196,7 +201,7 @@ update_bitfield_fetch_param(struct bitfield_fetch_param *data) update_symbol_cache(data->orig.data); } -static __kprobes void +static void free_bitfield_fetch_param(struct bitfield_fetch_param *data) { /* @@ -255,17 +260,17 @@ static const struct fetch_type *find_fetch_type(const char *type, } /* Special function : only accept unsigned long */ -static __kprobes void fetch_kernel_stack_address(struct pt_regs *regs, - void *dummy, void *dest) +static void fetch_kernel_stack_address(struct pt_regs *regs, void *dummy, void *dest) { *(unsigned long *)dest = kernel_stack_pointer(regs); } +NOKPROBE_SYMBOL(fetch_kernel_stack_address); -static __kprobes void fetch_user_stack_address(struct pt_regs *regs, - void *dummy, void *dest) +static void fetch_user_stack_address(struct pt_regs *regs, void *dummy, void *dest) { *(unsigned long *)dest = user_stack_pointer(regs); } +NOKPROBE_SYMBOL(fetch_user_stack_address); static fetch_func_t get_fetch_size_function(const struct fetch_type *type, fetch_func_t orig_fn, diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index fb1ab5dfbd42f6..4f815fbce16d26 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -81,13 +81,13 @@ */ #define convert_rloc_to_loc(dl, offs) ((u32)(dl) + (offs)) -static inline void *get_rloc_data(u32 *dl) +static nokprobe_inline void *get_rloc_data(u32 *dl) { return (u8 *)dl + get_rloc_offs(*dl); } /* For data_loc conversion */ -static inline void *get_loc_data(u32 *dl, void *ent) +static nokprobe_inline void *get_loc_data(u32 *dl, void *ent) { return (u8 *)ent + get_rloc_offs(*dl); } @@ -136,9 +136,8 @@ typedef u32 string_size; /* Printing in basic type function template */ #define DECLARE_BASIC_PRINT_TYPE_FUNC(type) \ -__kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \ - const char *name, \ - void *data, void *ent); \ +int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, const char *name, \ + void *data, void *ent); \ extern const char PRINT_TYPE_FMT_NAME(type)[] DECLARE_BASIC_PRINT_TYPE_FUNC(u8); @@ -303,7 +302,7 @@ static inline bool trace_probe_is_registered(struct trace_probe *tp) return !!(tp->flags & TP_FLAG_REGISTERED); } -static inline __kprobes void call_fetch(struct fetch_param *fprm, +static nokprobe_inline void call_fetch(struct fetch_param *fprm, struct pt_regs *regs, void *dest) { return fprm->fn(regs, fprm->data, dest); @@ -351,7 +350,7 @@ extern ssize_t traceprobe_probes_write(struct file *file, extern int traceprobe_command(const char *buf, int (*createfn)(int, char**)); /* Sum up total data length for dynamic arraies (strings) */ -static inline __kprobes int +static nokprobe_inline int __get_data_size(struct trace_probe *tp, struct pt_regs *regs) { int i, ret = 0; @@ -367,7 +366,7 @@ __get_data_size(struct trace_probe *tp, struct pt_regs *regs) } /* Store the value of each argument */ -static inline __kprobes void +static nokprobe_inline void store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs, u8 *data, int maxlen) { diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c index e14da5e97a69d8..19bd8928ce944d 100644 --- a/kernel/trace/trace_sched_wakeup.c +++ b/kernel/trace/trace_sched_wakeup.c @@ -130,15 +130,9 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip, atomic_dec(&data->disabled); preempt_enable_notrace(); } - -static struct ftrace_ops trace_ops __read_mostly = -{ - .func = wakeup_tracer_call, - .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE, -}; #endif /* CONFIG_FUNCTION_TRACER */ -static int register_wakeup_function(int graph, int set) +static int register_wakeup_function(struct trace_array *tr, int graph, int set) { int ret; @@ -150,7 +144,7 @@ static int register_wakeup_function(int graph, int set) ret = register_ftrace_graph(&wakeup_graph_return, &wakeup_graph_entry); else - ret = register_ftrace_function(&trace_ops); + ret = register_ftrace_function(tr->ops); if (!ret) function_enabled = true; @@ -158,7 +152,7 @@ static int register_wakeup_function(int graph, int set) return ret; } -static void unregister_wakeup_function(int graph) +static void unregister_wakeup_function(struct trace_array *tr, int graph) { if (!function_enabled) return; @@ -166,17 +160,17 @@ static void unregister_wakeup_function(int graph) if (graph) unregister_ftrace_graph(); else - unregister_ftrace_function(&trace_ops); + unregister_ftrace_function(tr->ops); function_enabled = false; } -static void wakeup_function_set(int set) +static void wakeup_function_set(struct trace_array *tr, int set) { if (set) - register_wakeup_function(is_graph(), 1); + register_wakeup_function(tr, is_graph(), 1); else - unregister_wakeup_function(is_graph()); + unregister_wakeup_function(tr, is_graph()); } static int wakeup_flag_changed(struct trace_array *tr, u32 mask, int set) @@ -184,16 +178,16 @@ static int wakeup_flag_changed(struct trace_array *tr, u32 mask, int set) struct tracer *tracer = tr->current_trace; if (mask & TRACE_ITER_FUNCTION) - wakeup_function_set(set); + wakeup_function_set(tr, set); return trace_keep_overwrite(tracer, mask, set); } -static int start_func_tracer(int graph) +static int start_func_tracer(struct trace_array *tr, int graph) { int ret; - ret = register_wakeup_function(graph, 0); + ret = register_wakeup_function(tr, graph, 0); if (!ret && tracing_is_enabled()) tracer_enabled = 1; @@ -203,11 +197,11 @@ static int start_func_tracer(int graph) return ret; } -static void stop_func_tracer(int graph) +static void stop_func_tracer(struct trace_array *tr, int graph) { tracer_enabled = 0; - unregister_wakeup_function(graph); + unregister_wakeup_function(tr, graph); } #ifdef CONFIG_FUNCTION_GRAPH_TRACER @@ -221,12 +215,12 @@ wakeup_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) if (!(is_graph() ^ set)) return 0; - stop_func_tracer(!set); + stop_func_tracer(tr, !set); wakeup_reset(wakeup_trace); - tracing_max_latency = 0; + tr->max_latency = 0; - return start_func_tracer(set); + return start_func_tracer(tr, set); } static int wakeup_graph_entry(struct ftrace_graph_ent *trace) @@ -350,13 +344,13 @@ static void wakeup_print_header(struct seq_file *s) /* * Should this new latency be reported/recorded? */ -static int report_latency(cycle_t delta) +static int report_latency(struct trace_array *tr, cycle_t delta) { if (tracing_thresh) { if (delta < tracing_thresh) return 0; } else { - if (delta <= tracing_max_latency) + if (delta <= tr->max_latency) return 0; } return 1; @@ -424,11 +418,11 @@ probe_wakeup_sched_switch(void *ignore, T1 = ftrace_now(cpu); delta = T1-T0; - if (!report_latency(delta)) + if (!report_latency(wakeup_trace, delta)) goto out_unlock; if (likely(!is_tracing_stopped())) { - tracing_max_latency = delta; + wakeup_trace->max_latency = delta; update_max_tr(wakeup_trace, wakeup_task, wakeup_cpu); } @@ -587,7 +581,7 @@ static void start_wakeup_tracer(struct trace_array *tr) */ smp_wmb(); - if (start_func_tracer(is_graph())) + if (start_func_tracer(tr, is_graph())) printk(KERN_ERR "failed to start wakeup tracer\n"); return; @@ -600,13 +594,15 @@ static void start_wakeup_tracer(struct trace_array *tr) static void stop_wakeup_tracer(struct trace_array *tr) { tracer_enabled = 0; - stop_func_tracer(is_graph()); + stop_func_tracer(tr, is_graph()); unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL); unregister_trace_sched_wakeup_new(probe_wakeup, NULL); unregister_trace_sched_wakeup(probe_wakeup, NULL); unregister_trace_sched_migrate_task(probe_wakeup_migrate_task, NULL); } +static bool wakeup_busy; + static int __wakeup_tracer_init(struct trace_array *tr) { save_flags = trace_flags; @@ -615,14 +611,20 @@ static int __wakeup_tracer_init(struct trace_array *tr) set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1); set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1); - tracing_max_latency = 0; + tr->max_latency = 0; wakeup_trace = tr; + ftrace_init_array_ops(tr, wakeup_tracer_call); start_wakeup_tracer(tr); + + wakeup_busy = true; return 0; } static int wakeup_tracer_init(struct trace_array *tr) { + if (wakeup_busy) + return -EBUSY; + wakeup_dl = 0; wakeup_rt = 0; return __wakeup_tracer_init(tr); @@ -630,6 +632,9 @@ static int wakeup_tracer_init(struct trace_array *tr) static int wakeup_rt_tracer_init(struct trace_array *tr) { + if (wakeup_busy) + return -EBUSY; + wakeup_dl = 0; wakeup_rt = 1; return __wakeup_tracer_init(tr); @@ -637,6 +642,9 @@ static int wakeup_rt_tracer_init(struct trace_array *tr) static int wakeup_dl_tracer_init(struct trace_array *tr) { + if (wakeup_busy) + return -EBUSY; + wakeup_dl = 1; wakeup_rt = 0; return __wakeup_tracer_init(tr); @@ -653,6 +661,8 @@ static void wakeup_tracer_reset(struct trace_array *tr) set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag); set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag); + ftrace_reset_array_ops(tr); + wakeup_busy = false; } static void wakeup_tracer_start(struct trace_array *tr) @@ -684,6 +694,7 @@ static struct tracer wakeup_tracer __read_mostly = #endif .open = wakeup_trace_open, .close = wakeup_trace_close, + .allow_instances = true, .use_max_tr = true, }; @@ -694,7 +705,6 @@ static struct tracer wakeup_rt_tracer __read_mostly = .reset = wakeup_tracer_reset, .start = wakeup_tracer_start, .stop = wakeup_tracer_stop, - .wait_pipe = poll_wait_pipe, .print_max = true, .print_header = wakeup_print_header, .print_line = wakeup_print_line, @@ -706,6 +716,7 @@ static struct tracer wakeup_rt_tracer __read_mostly = #endif .open = wakeup_trace_open, .close = wakeup_trace_close, + .allow_instances = true, .use_max_tr = true, }; @@ -716,7 +727,6 @@ static struct tracer wakeup_dl_tracer __read_mostly = .reset = wakeup_tracer_reset, .start = wakeup_tracer_start, .stop = wakeup_tracer_stop, - .wait_pipe = poll_wait_pipe, .print_max = true, .print_header = wakeup_print_header, .print_line = wakeup_print_line, diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index e98fca60974f57..5ef60499dc8e6c 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c @@ -65,7 +65,7 @@ static int trace_test_buffer(struct trace_buffer *buf, unsigned long *count) /* Don't allow flipping of max traces now */ local_irq_save(flags); - arch_spin_lock(&ftrace_max_lock); + arch_spin_lock(&buf->tr->max_lock); cnt = ring_buffer_entries(buf->buffer); @@ -83,7 +83,7 @@ static int trace_test_buffer(struct trace_buffer *buf, unsigned long *count) break; } tracing_on(); - arch_spin_unlock(&ftrace_max_lock); + arch_spin_unlock(&buf->tr->max_lock); local_irq_restore(flags); if (count) @@ -161,11 +161,6 @@ static struct ftrace_ops test_probe3 = { .flags = FTRACE_OPS_FL_RECURSION_SAFE, }; -static struct ftrace_ops test_global = { - .func = trace_selftest_test_global_func, - .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE, -}; - static void print_counts(void) { printk("(%d %d %d %d %d) ", @@ -185,7 +180,7 @@ static void reset_counts(void) trace_selftest_test_dyn_cnt = 0; } -static int trace_selftest_ops(int cnt) +static int trace_selftest_ops(struct trace_array *tr, int cnt) { int save_ftrace_enabled = ftrace_enabled; struct ftrace_ops *dyn_ops; @@ -220,7 +215,11 @@ static int trace_selftest_ops(int cnt) register_ftrace_function(&test_probe1); register_ftrace_function(&test_probe2); register_ftrace_function(&test_probe3); - register_ftrace_function(&test_global); + /* First time we are running with main function */ + if (cnt > 1) { + ftrace_init_array_ops(tr, trace_selftest_test_global_func); + register_ftrace_function(tr->ops); + } DYN_FTRACE_TEST_NAME(); @@ -232,8 +231,10 @@ static int trace_selftest_ops(int cnt) goto out; if (trace_selftest_test_probe3_cnt != 1) goto out; - if (trace_selftest_test_global_cnt == 0) - goto out; + if (cnt > 1) { + if (trace_selftest_test_global_cnt == 0) + goto out; + } DYN_FTRACE_TEST_NAME2(); @@ -269,8 +270,10 @@ static int trace_selftest_ops(int cnt) goto out_free; if (trace_selftest_test_probe3_cnt != 3) goto out_free; - if (trace_selftest_test_global_cnt == 0) - goto out; + if (cnt > 1) { + if (trace_selftest_test_global_cnt == 0) + goto out; + } if (trace_selftest_test_dyn_cnt == 0) goto out_free; @@ -295,7 +298,9 @@ static int trace_selftest_ops(int cnt) unregister_ftrace_function(&test_probe1); unregister_ftrace_function(&test_probe2); unregister_ftrace_function(&test_probe3); - unregister_ftrace_function(&test_global); + if (cnt > 1) + unregister_ftrace_function(tr->ops); + ftrace_reset_array_ops(tr); /* Make sure everything is off */ reset_counts(); @@ -315,9 +320,9 @@ static int trace_selftest_ops(int cnt) } /* Test dynamic code modification and ftrace filters */ -int trace_selftest_startup_dynamic_tracing(struct tracer *trace, - struct trace_array *tr, - int (*func)(void)) +static int trace_selftest_startup_dynamic_tracing(struct tracer *trace, + struct trace_array *tr, + int (*func)(void)) { int save_ftrace_enabled = ftrace_enabled; unsigned long count; @@ -388,7 +393,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, } /* Test the ops with global tracing running */ - ret = trace_selftest_ops(1); + ret = trace_selftest_ops(tr, 1); trace->reset(tr); out: @@ -399,7 +404,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, /* Test the ops with global tracing off */ if (!ret) - ret = trace_selftest_ops(2); + ret = trace_selftest_ops(tr, 2); return ret; } @@ -802,7 +807,7 @@ trace_selftest_startup_function_graph(struct tracer *trace, int trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr) { - unsigned long save_max = tracing_max_latency; + unsigned long save_max = tr->max_latency; unsigned long count; int ret; @@ -814,7 +819,7 @@ trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr) } /* reset the max latency */ - tracing_max_latency = 0; + tr->max_latency = 0; /* disable interrupts for a bit */ local_irq_disable(); udelay(100); @@ -841,7 +846,7 @@ trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr) ret = -1; } - tracing_max_latency = save_max; + tr->max_latency = save_max; return ret; } @@ -851,7 +856,7 @@ trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr) int trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr) { - unsigned long save_max = tracing_max_latency; + unsigned long save_max = tr->max_latency; unsigned long count; int ret; @@ -876,7 +881,7 @@ trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr) } /* reset the max latency */ - tracing_max_latency = 0; + tr->max_latency = 0; /* disable preemption for a bit */ preempt_disable(); udelay(100); @@ -903,7 +908,7 @@ trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr) ret = -1; } - tracing_max_latency = save_max; + tr->max_latency = save_max; return ret; } @@ -913,7 +918,7 @@ trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr) int trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *tr) { - unsigned long save_max = tracing_max_latency; + unsigned long save_max = tr->max_latency; unsigned long count; int ret; @@ -938,7 +943,7 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array * } /* reset the max latency */ - tracing_max_latency = 0; + tr->max_latency = 0; /* disable preemption and interrupts for a bit */ preempt_disable(); @@ -973,7 +978,7 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array * } /* do the test by disabling interrupts first this time */ - tracing_max_latency = 0; + tr->max_latency = 0; tracing_start(); trace->start(tr); @@ -1004,7 +1009,7 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array * tracing_start(); out_no_start: trace->reset(tr); - tracing_max_latency = save_max; + tr->max_latency = save_max; return ret; } @@ -1057,7 +1062,7 @@ static int trace_wakeup_test_thread(void *data) int trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr) { - unsigned long save_max = tracing_max_latency; + unsigned long save_max = tr->max_latency; struct task_struct *p; struct completion is_ready; unsigned long count; @@ -1083,7 +1088,7 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr) } /* reset the max latency */ - tracing_max_latency = 0; + tr->max_latency = 0; while (p->on_rq) { /* @@ -1113,7 +1118,7 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr) trace->reset(tr); tracing_start(); - tracing_max_latency = save_max; + tr->max_latency = save_max; /* kill the thread */ kthread_stop(p); diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 21b320e5d163c6..5aa9a5b9b6e2b1 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -85,8 +85,12 @@ check_stack(unsigned long ip, unsigned long *stack) max_stack_size = this_size; - max_stack_trace.nr_entries = 0; - max_stack_trace.skip = 3; + max_stack_trace.nr_entries = 0; + + if (using_ftrace_ops_list_func()) + max_stack_trace.skip = 4; + else + max_stack_trace.skip = 3; save_stack_trace(&max_stack_trace); diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index c082a74413455d..04fdb5de823c5d 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -108,8 +108,8 @@ static unsigned long get_user_stack_nth(struct pt_regs *regs, unsigned int n) * Uprobes-specific fetch functions */ #define DEFINE_FETCH_stack(type) \ -static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\ - void *offset, void *dest) \ +static void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs, \ + void *offset, void *dest) \ { \ *(type *)dest = (type)get_user_stack_nth(regs, \ ((unsigned long)offset)); \ @@ -120,8 +120,8 @@ DEFINE_BASIC_FETCH_FUNCS(stack) #define fetch_stack_string_size NULL #define DEFINE_FETCH_memory(type) \ -static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ - void *addr, void *dest) \ +static void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs, \ + void *addr, void *dest) \ { \ type retval; \ void __user *vaddr = (void __force __user *) addr; \ @@ -136,8 +136,8 @@ DEFINE_BASIC_FETCH_FUNCS(memory) * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max * length and relative data location. */ -static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, - void *addr, void *dest) +static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, + void *addr, void *dest) { long ret; u32 rloc = *(u32 *)dest; @@ -158,8 +158,8 @@ static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, } } -static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, - void *addr, void *dest) +static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, + void *addr, void *dest) { int len; void __user *vaddr = (void __force __user *) addr; @@ -184,8 +184,8 @@ static unsigned long translate_user_vaddr(void *file_offset) } #define DEFINE_FETCH_file_offset(type) \ -static __kprobes void FETCH_FUNC_NAME(file_offset, type)(struct pt_regs *regs,\ - void *offset, void *dest) \ +static void FETCH_FUNC_NAME(file_offset, type)(struct pt_regs *regs, \ + void *offset, void *dest)\ { \ void *vaddr = (void *)translate_user_vaddr(offset); \ \ @@ -1009,56 +1009,60 @@ uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event) return __uprobe_perf_filter(&tu->filter, event->hw.tp_target->mm); } -static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event) +static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event) { bool done; write_lock(&tu->filter.rwlock); if (event->hw.tp_target) { - /* - * event->parent != NULL means copy_process(), we can avoid - * uprobe_apply(). current->mm must be probed and we can rely - * on dup_mmap() which preserves the already installed bp's. - * - * attr.enable_on_exec means that exec/mmap will install the - * breakpoints we need. - */ + list_del(&event->hw.tp_list); done = tu->filter.nr_systemwide || - event->parent || event->attr.enable_on_exec || + (event->hw.tp_target->flags & PF_EXITING) || uprobe_filter_event(tu, event); - list_add(&event->hw.tp_list, &tu->filter.perf_events); } else { + tu->filter.nr_systemwide--; done = tu->filter.nr_systemwide; - tu->filter.nr_systemwide++; } write_unlock(&tu->filter.rwlock); if (!done) - uprobe_apply(tu->inode, tu->offset, &tu->consumer, true); + return uprobe_apply(tu->inode, tu->offset, &tu->consumer, false); return 0; } -static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event) +static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event) { bool done; + int err; write_lock(&tu->filter.rwlock); if (event->hw.tp_target) { - list_del(&event->hw.tp_list); + /* + * event->parent != NULL means copy_process(), we can avoid + * uprobe_apply(). current->mm must be probed and we can rely + * on dup_mmap() which preserves the already installed bp's. + * + * attr.enable_on_exec means that exec/mmap will install the + * breakpoints we need. + */ done = tu->filter.nr_systemwide || - (event->hw.tp_target->flags & PF_EXITING) || + event->parent || event->attr.enable_on_exec || uprobe_filter_event(tu, event); + list_add(&event->hw.tp_list, &tu->filter.perf_events); } else { - tu->filter.nr_systemwide--; done = tu->filter.nr_systemwide; + tu->filter.nr_systemwide++; } write_unlock(&tu->filter.rwlock); - if (!done) - uprobe_apply(tu->inode, tu->offset, &tu->consumer, false); - - return 0; + err = 0; + if (!done) { + err = uprobe_apply(tu->inode, tu->offset, &tu->consumer, true); + if (err) + uprobe_perf_close(tu, event); + } + return err; } static bool uprobe_perf_filter(struct uprobe_consumer *uc, diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 0ee63af30bd14a..508ade5098f763 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -100,10 +100,10 @@ enum { /* * Rescue workers are used only on emergencies and shared by - * all cpus. Give -20. + * all cpus. Give MIN_NICE. */ - RESCUER_NICE_LEVEL = -20, - HIGHPRI_NICE_LEVEL = -20, + RESCUER_NICE_LEVEL = MIN_NICE, + HIGHPRI_NICE_LEVEL = MIN_NICE, WQ_NAME_LEN = 24, }; @@ -1916,6 +1916,12 @@ static void send_mayday(struct work_struct *work) /* mayday mayday mayday */ if (list_empty(&pwq->mayday_node)) { + /* + * If @pwq is for an unbound wq, its base ref may be put at + * any time due to an attribute change. Pin @pwq until the + * rescuer is done with it. + */ + get_pwq(pwq); list_add_tail(&pwq->mayday_node, &wq->maydays); wake_up_process(wq->rescuer->task); } @@ -2398,6 +2404,7 @@ static int rescuer_thread(void *__rescuer) struct worker *rescuer = __rescuer; struct workqueue_struct *wq = rescuer->rescue_wq; struct list_head *scheduled = &rescuer->scheduled; + bool should_stop; set_user_nice(current, RESCUER_NICE_LEVEL); @@ -2409,11 +2416,15 @@ static int rescuer_thread(void *__rescuer) repeat: set_current_state(TASK_INTERRUPTIBLE); - if (kthread_should_stop()) { - __set_current_state(TASK_RUNNING); - rescuer->task->flags &= ~PF_WQ_WORKER; - return 0; - } + /* + * By the time the rescuer is requested to stop, the workqueue + * shouldn't have any work pending, but @wq->maydays may still have + * pwq(s) queued. This can happen by non-rescuer workers consuming + * all the work items before the rescuer got to them. Go through + * @wq->maydays processing before acting on should_stop so that the + * list is always empty on exit. + */ + should_stop = kthread_should_stop(); /* see whether any pwq is asking for help */ spin_lock_irq(&wq_mayday_lock); @@ -2444,6 +2455,12 @@ static int rescuer_thread(void *__rescuer) process_scheduled_works(rescuer); + /* + * Put the reference grabbed by send_mayday(). @pool won't + * go away while we're holding its lock. + */ + put_pwq(pwq); + /* * Leave this pool. If keep_working() is %true, notify a * regular worker; otherwise, we end up with 0 concurrency @@ -2459,6 +2476,12 @@ static int rescuer_thread(void *__rescuer) spin_unlock_irq(&wq_mayday_lock); + if (should_stop) { + __set_current_state(TASK_RUNNING); + rescuer->task->flags &= ~PF_WQ_WORKER; + return 0; + } + /* rescuers should never participate in concurrency management */ WARN_ON_ONCE(!(rescuer->flags & WORKER_NOT_RUNNING)); schedule(); @@ -4080,17 +4103,13 @@ static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, * Let's determine what needs to be done. If the target cpumask is * different from wq's, we need to compare it to @pwq's and create * a new one if they don't match. If the target cpumask equals - * wq's, the default pwq should be used. If @pwq is already the - * default one, nothing to do; otherwise, install the default one. + * wq's, the default pwq should be used. */ if (wq_calc_node_cpumask(wq->unbound_attrs, node, cpu_off, cpumask)) { if (cpumask_equal(cpumask, pwq->pool->attrs->cpumask)) goto out_unlock; } else { - if (pwq == wq->dfl_pwq) - goto out_unlock; - else - goto use_dfl_pwq; + goto use_dfl_pwq; } mutex_unlock(&wq->mutex); @@ -4100,7 +4119,8 @@ static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, if (!pwq) { pr_warning("workqueue: allocation failed while updating NUMA affinity of \"%s\"\n", wq->name); - goto out_unlock; + mutex_lock(&wq->mutex); + goto use_dfl_pwq; } /* diff --git a/lib/Kconfig b/lib/Kconfig index e5ae36dcbf0147..325a8d4efda21a 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -338,6 +338,20 @@ config TEXTSEARCH_FSM config BTREE boolean +config INTERVAL_TREE + boolean + help + Simple, embeddable, interval-tree. Can find the start of an + overlapping range in log(n) time and then iterate over all + overlapping nodes. The algorithm is implemented as an + augmented rbtree. + + See: + + Documentation/rbtree.txt + + for more information. + config ASSOCIATIVE_ARRAY bool help diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index d1c90da95e2f2c..23b701954c5286 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -180,7 +180,7 @@ config STRIP_ASM_SYMS config READABLE_ASM bool "Generate readable assembler code" - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && !LTO help Disable some compiler optimizations that tend to generate human unreadable assembler output. This may make the kernel slightly slower, but it helps @@ -585,8 +585,8 @@ config DEBUG_HIGHMEM bool "Highmem debugging" depends on DEBUG_KERNEL && HIGHMEM help - This options enables addition error checking for high memory systems. - Disable for production systems. + This option enables additional error checking for high memory + systems. Disable for production systems. config HAVE_DEBUG_STACKOVERFLOW bool @@ -1511,6 +1511,7 @@ config RBTREE_TEST config INTERVAL_TREE_TEST tristate "Interval tree test" depends on m && DEBUG_KERNEL + select INTERVAL_TREE help A benchmark measuring the performance of the interval tree library diff --git a/lib/Makefile b/lib/Makefile index 02da5b614a8052..1fc42c9adf4952 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -50,6 +50,7 @@ CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS)) obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o obj-$(CONFIG_BTREE) += btree.o +obj-$(CONFIG_INTERVAL_TREE) += interval_tree.o obj-$(CONFIG_ASSOCIATIVE_ARRAY) += assoc_array.o obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o obj-$(CONFIG_DEBUG_LIST) += list_debug.o @@ -157,8 +158,6 @@ lib-$(CONFIG_LIBFDT) += $(libfdt_files) obj-$(CONFIG_RBTREE_TEST) += rbtree_test.o obj-$(CONFIG_INTERVAL_TREE_TEST) += interval_tree_test.o -interval_tree_test-objs := interval_tree_test_main.o interval_tree.o - obj-$(CONFIG_PERCPU_TEST) += percpu_test.o obj-$(CONFIG_ASN1) += asn1_decoder.o diff --git a/lib/dump_stack.c b/lib/dump_stack.c index f23b63f0a1c391..6745c6230db340 100644 --- a/lib/dump_stack.c +++ b/lib/dump_stack.c @@ -23,7 +23,7 @@ static void __dump_stack(void) #ifdef CONFIG_SMP static atomic_t dump_lock = ATOMIC_INIT(-1); -asmlinkage void dump_stack(void) +asmlinkage __visible void dump_stack(void) { int was_locked; int old; @@ -55,7 +55,7 @@ asmlinkage void dump_stack(void) preempt_enable(); } #else -asmlinkage void dump_stack(void) +asmlinkage __visible void dump_stack(void) { __dump_stack(); } diff --git a/lib/interval_tree.c b/lib/interval_tree.c index e6eb406f2d65dd..f367f9ad544c39 100644 --- a/lib/interval_tree.c +++ b/lib/interval_tree.c @@ -1,6 +1,7 @@ #include #include #include +#include #define START(node) ((node)->start) #define LAST(node) ((node)->last) @@ -8,3 +9,8 @@ INTERVAL_TREE_DEFINE(struct interval_tree_node, rb, unsigned long, __subtree_last, START, LAST,, interval_tree) + +EXPORT_SYMBOL_GPL(interval_tree_insert); +EXPORT_SYMBOL_GPL(interval_tree_remove); +EXPORT_SYMBOL_GPL(interval_tree_iter_first); +EXPORT_SYMBOL_GPL(interval_tree_iter_next); diff --git a/lib/interval_tree_test_main.c b/lib/interval_tree_test.c similarity index 100% rename from lib/interval_tree_test_main.c rename to lib/interval_tree_test.c diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 4e3bd71bd9495c..9ebf9e20de53db 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -29,7 +29,9 @@ u64 uevent_seqnum; +#ifdef CONFIG_UEVENT_HELPER char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; +#endif #ifdef CONFIG_NET struct uevent_sock { struct list_head list; @@ -109,6 +111,7 @@ static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data) } #endif +#ifdef CONFIG_UEVENT_HELPER static int kobj_usermode_filter(struct kobject *kobj) { const struct kobj_ns_type_operations *ops; @@ -147,6 +150,7 @@ static void cleanup_uevent_env(struct subprocess_info *info) { kfree(info->data); } +#endif /** * kobject_uevent_env - send an uevent with environmental data @@ -323,6 +327,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, #endif mutex_unlock(&uevent_sock_mutex); +#ifdef CONFIG_UEVENT_HELPER /* call uevent_helper, usually only enabled during early boot */ if (uevent_helper[0] && !kobj_usermode_filter(kobj)) { struct subprocess_info *info; @@ -347,6 +352,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, env = NULL; /* freed by cleanup_uevent_env */ } } +#endif exit: kfree(devpath); diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c index 569985d522d518..e3edc5f3f5ee4d 100644 --- a/lib/lzo/lzo1x_decompress_safe.c +++ b/lib/lzo/lzo1x_decompress_safe.c @@ -72,9 +72,11 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, COPY8(op, ip); op += 8; ip += 8; +# if !defined(__arm__) COPY8(op, ip); op += 8; ip += 8; +# endif } while (ip < ie); ip = ie; op = oe; @@ -159,9 +161,11 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, COPY8(op, m_pos); op += 8; m_pos += 8; +# if !defined(__arm__) COPY8(op, m_pos); op += 8; m_pos += 8; +# endif } while (op < oe); op = oe; if (HAVE_IP(6)) { diff --git a/lib/lzo/lzodefs.h b/lib/lzo/lzodefs.h index 6710b83ce72ed0..db756ccb275694 100644 --- a/lib/lzo/lzodefs.h +++ b/lib/lzo/lzodefs.h @@ -12,8 +12,14 @@ */ +#if 1 && defined(__arm__) && ((__LINUX_ARM_ARCH__ >= 6) || defined(__ARM_FEATURE_UNALIGNED)) +#define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1 +#define COPY4(dst, src) \ + * (u32 *) (void *) (dst) = * (const u32 *) (const void *) (src) +#else #define COPY4(dst, src) \ put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst)) +#endif #if defined(__x86_64__) #define COPY8(dst, src) \ put_unaligned(get_unaligned((const u64 *)(src)), (u64 *)(dst)) diff --git a/mm/Kconfig b/mm/Kconfig index ebe5880c29d6cb..30cb6cb008f5b9 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -134,6 +134,9 @@ config HAVE_MEMBLOCK config HAVE_MEMBLOCK_NODE_MAP boolean +config HAVE_MEMBLOCK_PHYS_MAP + boolean + config ARCH_DISCARD_MEMBLOCK boolean diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 09d9591b770806..1706cbbdf5f038 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -557,7 +557,7 @@ void clear_bdi_congested(struct backing_dev_info *bdi, int sync) bit = sync ? BDI_sync_congested : BDI_async_congested; if (test_and_clear_bit(bit, &bdi->state)) atomic_dec(&nr_bdi_congested[sync]); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); if (waitqueue_active(wqh)) wake_up(wqh); } diff --git a/mm/dmapool.c b/mm/dmapool.c index 38dfcddc0595ea..a3a1bfe91110d2 100644 --- a/mm/dmapool.c +++ b/mm/dmapool.c @@ -333,10 +333,10 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, continue; if (pool->dev) dev_err(pool->dev, - "dma_pool_alloc %s, %p (corruped)\n", + "dma_pool_alloc %s, %p (corrupted)\n", pool->name, retval); else - pr_err("dma_pool_alloc %s, %p (corruped)\n", + pr_err("dma_pool_alloc %s, %p (corrupted)\n", pool->name, retval); /* diff --git a/mm/filemap.c b/mm/filemap.c index 2f88e2413ef31a..067c3c02998594 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -740,7 +740,7 @@ void unlock_page(struct page *page) { VM_BUG_ON_PAGE(!PageLocked(page), page); clear_bit_unlock(PG_locked, &page->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_page(page, PG_locked); } EXPORT_SYMBOL(unlock_page); @@ -757,7 +757,7 @@ void end_page_writeback(struct page *page) if (!test_clear_page_writeback(page)) BUG(); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_page(page, PG_writeback); } EXPORT_SYMBOL(end_page_writeback); @@ -1688,96 +1688,42 @@ static ssize_t do_generic_file_read(struct file *filp, loff_t *ppos, return written ? written : error; } -/* - * Performs necessary checks before doing a write - * @iov: io vector request - * @nr_segs: number of segments in the iovec - * @count: number of bytes to write - * @access_flags: type of access: %VERIFY_READ or %VERIFY_WRITE - * - * Adjust number of segments and amount of bytes to write (nr_segs should be - * properly initialized first). Returns appropriate error code that caller - * should return or zero in case that write should be allowed. - */ -int generic_segment_checks(const struct iovec *iov, - unsigned long *nr_segs, size_t *count, int access_flags) -{ - unsigned long seg; - size_t cnt = 0; - for (seg = 0; seg < *nr_segs; seg++) { - const struct iovec *iv = &iov[seg]; - - /* - * If any segment has a negative length, or the cumulative - * length ever wraps negative then return -EINVAL. - */ - cnt += iv->iov_len; - if (unlikely((ssize_t)(cnt|iv->iov_len) < 0)) - return -EINVAL; - if (access_ok(access_flags, iv->iov_base, iv->iov_len)) - continue; - if (seg == 0) - return -EFAULT; - *nr_segs = seg; - cnt -= iv->iov_len; /* This segment is no good */ - break; - } - *count = cnt; - return 0; -} -EXPORT_SYMBOL(generic_segment_checks); - /** - * generic_file_aio_read - generic filesystem read routine + * generic_file_read_iter - generic filesystem read routine * @iocb: kernel I/O control block - * @iov: io vector request - * @nr_segs: number of segments in the iovec - * @pos: current file position + * @iter: destination for the data read * - * This is the "read()" routine for all filesystems + * This is the "read_iter()" routine for all filesystems * that can use the page cache directly. */ ssize_t -generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) { - struct file *filp = iocb->ki_filp; - ssize_t retval; - size_t count; + struct file *file = iocb->ki_filp; + ssize_t retval = 0; loff_t *ppos = &iocb->ki_pos; - struct iov_iter i; - - count = 0; - retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE); - if (retval) - return retval; - iov_iter_init(&i, iov, nr_segs, count, 0); + loff_t pos = *ppos; /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ - if (filp->f_flags & O_DIRECT) { + if (file->f_flags & O_DIRECT) { + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + size_t count = iov_iter_count(iter); loff_t size; - struct address_space *mapping; - struct inode *inode; - mapping = filp->f_mapping; - inode = mapping->host; if (!count) goto out; /* skip atime */ size = i_size_read(inode); retval = filemap_write_and_wait_range(mapping, pos, - pos + iov_length(iov, nr_segs) - 1); + pos + count - 1); if (!retval) { - retval = mapping->a_ops->direct_IO(READ, iocb, - iov, pos, nr_segs); + struct iov_iter data = *iter; + retval = mapping->a_ops->direct_IO(READ, iocb, &data, pos); } + if (retval > 0) { *ppos = pos + retval; - count -= retval; - /* - * If we did a short DIO read we need to skip the - * section of the iov that we've already read data into. - */ - iov_iter_advance(&i, retval); + iov_iter_advance(iter, retval); } /* @@ -1788,17 +1734,17 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, * and return. Otherwise fallthrough to buffered io for * the rest of the read. */ - if (retval < 0 || !count || *ppos >= size) { - file_accessed(filp); + if (retval < 0 || !iov_iter_count(iter) || *ppos >= size) { + file_accessed(file); goto out; } } - retval = do_generic_file_read(filp, ppos, &i, retval); + retval = do_generic_file_read(file, ppos, iter, retval); out: return retval; } -EXPORT_SYMBOL(generic_file_aio_read); +EXPORT_SYMBOL(generic_file_read_iter); #ifdef CONFIG_MMU /** @@ -2410,9 +2356,7 @@ int pagecache_write_end(struct file *file, struct address_space *mapping, EXPORT_SYMBOL(pagecache_write_end); ssize_t -generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long *nr_segs, loff_t pos, - size_t count, size_t ocount) +generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -2420,11 +2364,9 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov, ssize_t written; size_t write_len; pgoff_t end; + struct iov_iter data; - if (count != ocount) - *nr_segs = iov_shorten((struct iovec *)iov, *nr_segs, count); - - write_len = iov_length(iov, *nr_segs); + write_len = iov_iter_count(from); end = (pos + write_len - 1) >> PAGE_CACHE_SHIFT; written = filemap_write_and_wait_range(mapping, pos, pos + write_len - 1); @@ -2451,7 +2393,8 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov, } } - written = mapping->a_ops->direct_IO(WRITE, iocb, iov, pos, *nr_segs); + data = *from; + written = mapping->a_ops->direct_IO(WRITE, iocb, &data, pos); /* * Finally, try again to invalidate clean pages which might have been @@ -2468,6 +2411,7 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov, if (written > 0) { pos += written; + iov_iter_advance(from, written); if (pos > i_size_read(inode) && !S_ISBLK(inode->i_mode)) { i_size_write(inode, pos); mark_inode_dirty(inode); @@ -2609,10 +2553,9 @@ ssize_t generic_perform_write(struct file *file, EXPORT_SYMBOL(generic_perform_write); /** - * __generic_file_aio_write - write data to a file + * __generic_file_write_iter - write data to a file * @iocb: IO state structure (file, offset, etc.) - * @iov: vector with data to write - * @nr_segs: number of segments in the vector + * @from: iov_iter with data to write * * This function does all the work needed for actually writing data to a * file. It does all basic checks, removes SUID from the file, updates @@ -2626,26 +2569,16 @@ EXPORT_SYMBOL(generic_perform_write); * A caller has to handle it. This is mainly due to the fact that we want to * avoid syncing under i_mutex. */ -ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs) +ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct address_space * mapping = file->f_mapping; - size_t ocount; /* original count */ - size_t count; /* after file limit checks */ struct inode *inode = mapping->host; loff_t pos = iocb->ki_pos; ssize_t written = 0; ssize_t err; ssize_t status; - struct iov_iter from; - - ocount = 0; - err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ); - if (err) - return err; - - count = ocount; + size_t count = iov_iter_count(from); /* We can write back this queue in page reclaim */ current->backing_dev_info = mapping->backing_dev_info; @@ -2656,6 +2589,8 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, if (count == 0) goto out; + iov_iter_truncate(from, count); + err = file_remove_suid(file); if (err) goto out; @@ -2664,17 +2599,13 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, if (err) goto out; - iov_iter_init(&from, iov, nr_segs, count, 0); - /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ if (unlikely(file->f_flags & O_DIRECT)) { loff_t endbyte; - written = generic_file_direct_write(iocb, iov, &from.nr_segs, pos, - count, ocount); + written = generic_file_direct_write(iocb, from, pos); if (written < 0 || written == count) goto out; - iov_iter_advance(&from, written); /* * direct-io write to a hole: fall through to buffered I/O @@ -2683,7 +2614,7 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, pos += written; count -= written; - status = generic_perform_write(file, &from, pos); + status = generic_perform_write(file, from, pos); /* * If generic_perform_write() returned a synchronous error * then we want to return the number of bytes which were @@ -2715,7 +2646,7 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, */ } } else { - written = generic_perform_write(file, &from, pos); + written = generic_perform_write(file, from, pos); if (likely(written >= 0)) iocb->ki_pos = pos + written; } @@ -2723,30 +2654,25 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, current->backing_dev_info = NULL; return written ? written : err; } -EXPORT_SYMBOL(__generic_file_aio_write); +EXPORT_SYMBOL(__generic_file_write_iter); /** - * generic_file_aio_write - write data to a file + * generic_file_write_iter - write data to a file * @iocb: IO state structure - * @iov: vector with data to write - * @nr_segs: number of segments in the vector - * @pos: position in file where to write + * @from: iov_iter with data to write * - * This is a wrapper around __generic_file_aio_write() to be used by most + * This is a wrapper around __generic_file_write_iter() to be used by most * filesystems. It takes care of syncing the file in case of O_SYNC file * and acquires i_mutex as needed. */ -ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +ssize_t generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; ssize_t ret; - BUG_ON(iocb->ki_pos != pos); - mutex_lock(&inode->i_mutex); - ret = __generic_file_aio_write(iocb, iov, nr_segs); + ret = __generic_file_write_iter(iocb, from); mutex_unlock(&inode->i_mutex); if (ret > 0) { @@ -2758,7 +2684,7 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, } return ret; } -EXPORT_SYMBOL(generic_file_aio_write); +EXPORT_SYMBOL(generic_file_write_iter); /** * try_to_release_page() - release old fs-specific metadata on a page diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 6fd0668d4e1d35..c5ff461e025377 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2742,7 +2742,7 @@ static int khugepaged(void *none) struct mm_slot *mm_slot; set_freezable(); - set_user_nice(current, 19); + set_user_nice(current, MAX_NICE); while (!kthread_should_stop()) { khugepaged_do_scan(); diff --git a/mm/iov_iter.c b/mm/iov_iter.c index 10e46cd721de58..7b5dbd1517b559 100644 --- a/mm/iov_iter.c +++ b/mm/iov_iter.c @@ -1,8 +1,10 @@ #include #include #include +#include +#include -size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, +static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes, struct iov_iter *i) { size_t skip, copy, left, wanted; @@ -72,13 +74,97 @@ size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, } kunmap(page); done: + if (skip == iov->iov_len) { + iov++; + skip = 0; + } + i->count -= wanted - bytes; + i->nr_segs -= iov - i->iov; + i->iov = iov; + i->iov_offset = skip; + return wanted - bytes; +} + +static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t bytes, + struct iov_iter *i) +{ + size_t skip, copy, left, wanted; + const struct iovec *iov; + char __user *buf; + void *kaddr, *to; + + if (unlikely(bytes > i->count)) + bytes = i->count; + + if (unlikely(!bytes)) + return 0; + + wanted = bytes; + iov = i->iov; + skip = i->iov_offset; + buf = iov->iov_base + skip; + copy = min(bytes, iov->iov_len - skip); + + if (!fault_in_pages_readable(buf, copy)) { + kaddr = kmap_atomic(page); + to = kaddr + offset; + + /* first chunk, usually the only one */ + left = __copy_from_user_inatomic(to, buf, copy); + copy -= left; + skip += copy; + to += copy; + bytes -= copy; + + while (unlikely(!left && bytes)) { + iov++; + buf = iov->iov_base; + copy = min(bytes, iov->iov_len); + left = __copy_from_user_inatomic(to, buf, copy); + copy -= left; + skip = copy; + to += copy; + bytes -= copy; + } + if (likely(!bytes)) { + kunmap_atomic(kaddr); + goto done; + } + offset = to - kaddr; + buf += copy; + kunmap_atomic(kaddr); + copy = min(bytes, iov->iov_len - skip); + } + /* Too bad - revert to non-atomic kmap */ + kaddr = kmap(page); + to = kaddr + offset; + left = __copy_from_user(to, buf, copy); + copy -= left; + skip += copy; + to += copy; + bytes -= copy; + while (unlikely(!left && bytes)) { + iov++; + buf = iov->iov_base; + copy = min(bytes, iov->iov_len); + left = __copy_from_user(to, buf, copy); + copy -= left; + skip = copy; + to += copy; + bytes -= copy; + } + kunmap(page); +done: + if (skip == iov->iov_len) { + iov++; + skip = 0; + } i->count -= wanted - bytes; i->nr_segs -= iov - i->iov; i->iov = iov; i->iov_offset = skip; return wanted - bytes; } -EXPORT_SYMBOL(copy_page_to_iter); static size_t __iovec_copy_from_user_inatomic(char *vaddr, const struct iovec *iov, size_t base, size_t bytes) @@ -107,7 +193,7 @@ static size_t __iovec_copy_from_user_inatomic(char *vaddr, * were successfully copied. If a fault is encountered then return the number of * bytes which were copied. */ -size_t iov_iter_copy_from_user_atomic(struct page *page, +static size_t copy_from_user_atomic_iovec(struct page *page, struct iov_iter *i, unsigned long offset, size_t bytes) { char *kaddr; @@ -127,36 +213,8 @@ size_t iov_iter_copy_from_user_atomic(struct page *page, return copied; } -EXPORT_SYMBOL(iov_iter_copy_from_user_atomic); - -/* - * This has the same sideeffects and return value as - * iov_iter_copy_from_user_atomic(). - * The difference is that it attempts to resolve faults. - * Page must not be locked. - */ -size_t iov_iter_copy_from_user(struct page *page, - struct iov_iter *i, unsigned long offset, size_t bytes) -{ - char *kaddr; - size_t copied; - - kaddr = kmap(page); - if (likely(i->nr_segs == 1)) { - int left; - char __user *buf = i->iov->iov_base + i->iov_offset; - left = __copy_from_user(kaddr + offset, buf, bytes); - copied = bytes - left; - } else { - copied = __iovec_copy_from_user_inatomic(kaddr + offset, - i->iov, i->iov_offset, bytes); - } - kunmap(page); - return copied; -} -EXPORT_SYMBOL(iov_iter_copy_from_user); -void iov_iter_advance(struct iov_iter *i, size_t bytes) +static void advance_iovec(struct iov_iter *i, size_t bytes) { BUG_ON(i->count < bytes); @@ -191,7 +249,6 @@ void iov_iter_advance(struct iov_iter *i, size_t bytes) i->nr_segs = nr_segs; } } -EXPORT_SYMBOL(iov_iter_advance); /* * Fault in the first iovec of the given iov_iter, to a maximum length @@ -204,21 +261,483 @@ EXPORT_SYMBOL(iov_iter_advance); */ int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes) { - char __user *buf = i->iov->iov_base + i->iov_offset; - bytes = min(bytes, i->iov->iov_len - i->iov_offset); - return fault_in_pages_readable(buf, bytes); + if (!(i->type & ITER_BVEC)) { + char __user *buf = i->iov->iov_base + i->iov_offset; + bytes = min(bytes, i->iov->iov_len - i->iov_offset); + return fault_in_pages_readable(buf, bytes); + } + return 0; } EXPORT_SYMBOL(iov_iter_fault_in_readable); +static unsigned long alignment_iovec(const struct iov_iter *i) +{ + const struct iovec *iov = i->iov; + unsigned long res; + size_t size = i->count; + size_t n; + + if (!size) + return 0; + + res = (unsigned long)iov->iov_base + i->iov_offset; + n = iov->iov_len - i->iov_offset; + if (n >= size) + return res | size; + size -= n; + res |= n; + while (size > (++iov)->iov_len) { + res |= (unsigned long)iov->iov_base | iov->iov_len; + size -= iov->iov_len; + } + res |= (unsigned long)iov->iov_base | size; + return res; +} + +void iov_iter_init(struct iov_iter *i, int direction, + const struct iovec *iov, unsigned long nr_segs, + size_t count) +{ + /* It will get better. Eventually... */ + if (segment_eq(get_fs(), KERNEL_DS)) + direction |= ITER_KVEC; + i->type = direction; + i->iov = iov; + i->nr_segs = nr_segs; + i->iov_offset = 0; + i->count = count; +} +EXPORT_SYMBOL(iov_iter_init); + +static ssize_t get_pages_iovec(struct iov_iter *i, + struct page **pages, size_t maxsize, + size_t *start) +{ + size_t offset = i->iov_offset; + const struct iovec *iov = i->iov; + size_t len; + unsigned long addr; + int n; + int res; + + len = iov->iov_len - offset; + if (len > i->count) + len = i->count; + if (len > maxsize) + len = maxsize; + addr = (unsigned long)iov->iov_base + offset; + len += *start = addr & (PAGE_SIZE - 1); + addr &= ~(PAGE_SIZE - 1); + n = (len + PAGE_SIZE - 1) / PAGE_SIZE; + res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages); + if (unlikely(res < 0)) + return res; + return (res == n ? len : res * PAGE_SIZE) - *start; +} + +static ssize_t get_pages_alloc_iovec(struct iov_iter *i, + struct page ***pages, size_t maxsize, + size_t *start) +{ + size_t offset = i->iov_offset; + const struct iovec *iov = i->iov; + size_t len; + unsigned long addr; + void *p; + int n; + int res; + + len = iov->iov_len - offset; + if (len > i->count) + len = i->count; + if (len > maxsize) + len = maxsize; + addr = (unsigned long)iov->iov_base + offset; + len += *start = addr & (PAGE_SIZE - 1); + addr &= ~(PAGE_SIZE - 1); + n = (len + PAGE_SIZE - 1) / PAGE_SIZE; + + p = kmalloc(n * sizeof(struct page *), GFP_KERNEL); + if (!p) + p = vmalloc(n * sizeof(struct page *)); + if (!p) + return -ENOMEM; + + res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p); + if (unlikely(res < 0)) { + kvfree(p); + return res; + } + *pages = p; + return (res == n ? len : res * PAGE_SIZE) - *start; +} + +static int iov_iter_npages_iovec(const struct iov_iter *i, int maxpages) +{ + size_t offset = i->iov_offset; + size_t size = i->count; + const struct iovec *iov = i->iov; + int npages = 0; + int n; + + for (n = 0; size && n < i->nr_segs; n++, iov++) { + unsigned long addr = (unsigned long)iov->iov_base + offset; + size_t len = iov->iov_len - offset; + offset = 0; + if (unlikely(!len)) /* empty segment */ + continue; + if (len > size) + len = size; + npages += (addr + len + PAGE_SIZE - 1) / PAGE_SIZE + - addr / PAGE_SIZE; + if (npages >= maxpages) /* don't bother going further */ + return maxpages; + size -= len; + offset = 0; + } + return min(npages, maxpages); +} + +static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t len) +{ + char *from = kmap_atomic(page); + memcpy(to, from + offset, len); + kunmap_atomic(from); +} + +static void memcpy_to_page(struct page *page, size_t offset, char *from, size_t len) +{ + char *to = kmap_atomic(page); + memcpy(to + offset, from, len); + kunmap_atomic(to); +} + +static size_t copy_page_to_iter_bvec(struct page *page, size_t offset, size_t bytes, + struct iov_iter *i) +{ + size_t skip, copy, wanted; + const struct bio_vec *bvec; + void *kaddr, *from; + + if (unlikely(bytes > i->count)) + bytes = i->count; + + if (unlikely(!bytes)) + return 0; + + wanted = bytes; + bvec = i->bvec; + skip = i->iov_offset; + copy = min_t(size_t, bytes, bvec->bv_len - skip); + + kaddr = kmap_atomic(page); + from = kaddr + offset; + memcpy_to_page(bvec->bv_page, skip + bvec->bv_offset, from, copy); + skip += copy; + from += copy; + bytes -= copy; + while (bytes) { + bvec++; + copy = min(bytes, (size_t)bvec->bv_len); + memcpy_to_page(bvec->bv_page, bvec->bv_offset, from, copy); + skip = copy; + from += copy; + bytes -= copy; + } + kunmap_atomic(kaddr); + if (skip == bvec->bv_len) { + bvec++; + skip = 0; + } + i->count -= wanted - bytes; + i->nr_segs -= bvec - i->bvec; + i->bvec = bvec; + i->iov_offset = skip; + return wanted - bytes; +} + +static size_t copy_page_from_iter_bvec(struct page *page, size_t offset, size_t bytes, + struct iov_iter *i) +{ + size_t skip, copy, wanted; + const struct bio_vec *bvec; + void *kaddr, *to; + + if (unlikely(bytes > i->count)) + bytes = i->count; + + if (unlikely(!bytes)) + return 0; + + wanted = bytes; + bvec = i->bvec; + skip = i->iov_offset; + + kaddr = kmap_atomic(page); + + to = kaddr + offset; + + copy = min(bytes, bvec->bv_len - skip); + + memcpy_from_page(to, bvec->bv_page, bvec->bv_offset + skip, copy); + + to += copy; + skip += copy; + bytes -= copy; + + while (bytes) { + bvec++; + copy = min(bytes, (size_t)bvec->bv_len); + memcpy_from_page(to, bvec->bv_page, bvec->bv_offset, copy); + skip = copy; + to += copy; + bytes -= copy; + } + kunmap_atomic(kaddr); + if (skip == bvec->bv_len) { + bvec++; + skip = 0; + } + i->count -= wanted; + i->nr_segs -= bvec - i->bvec; + i->bvec = bvec; + i->iov_offset = skip; + return wanted; +} + +static size_t copy_from_user_bvec(struct page *page, + struct iov_iter *i, unsigned long offset, size_t bytes) +{ + char *kaddr; + size_t left; + const struct bio_vec *bvec; + size_t base = i->iov_offset; + + kaddr = kmap_atomic(page); + for (left = bytes, bvec = i->bvec; left; bvec++, base = 0) { + size_t copy = min(left, bvec->bv_len - base); + if (!bvec->bv_len) + continue; + memcpy_from_page(kaddr + offset, bvec->bv_page, + bvec->bv_offset + base, copy); + offset += copy; + left -= copy; + } + kunmap_atomic(kaddr); + return bytes; +} + +static void advance_bvec(struct iov_iter *i, size_t bytes) +{ + BUG_ON(i->count < bytes); + + if (likely(i->nr_segs == 1)) { + i->iov_offset += bytes; + i->count -= bytes; + } else { + const struct bio_vec *bvec = i->bvec; + size_t base = i->iov_offset; + unsigned long nr_segs = i->nr_segs; + + /* + * The !iov->iov_len check ensures we skip over unlikely + * zero-length segments (without overruning the iovec). + */ + while (bytes || unlikely(i->count && !bvec->bv_len)) { + int copy; + + copy = min(bytes, bvec->bv_len - base); + BUG_ON(!i->count || i->count < copy); + i->count -= copy; + bytes -= copy; + base += copy; + if (bvec->bv_len == base) { + bvec++; + nr_segs--; + base = 0; + } + } + i->bvec = bvec; + i->iov_offset = base; + i->nr_segs = nr_segs; + } +} + +static unsigned long alignment_bvec(const struct iov_iter *i) +{ + const struct bio_vec *bvec = i->bvec; + unsigned long res; + size_t size = i->count; + size_t n; + + if (!size) + return 0; + + res = bvec->bv_offset + i->iov_offset; + n = bvec->bv_len - i->iov_offset; + if (n >= size) + return res | size; + size -= n; + res |= n; + while (size > (++bvec)->bv_len) { + res |= bvec->bv_offset | bvec->bv_len; + size -= bvec->bv_len; + } + res |= bvec->bv_offset | size; + return res; +} + +static ssize_t get_pages_bvec(struct iov_iter *i, + struct page **pages, size_t maxsize, + size_t *start) +{ + const struct bio_vec *bvec = i->bvec; + size_t len = bvec->bv_len - i->iov_offset; + if (len > i->count) + len = i->count; + if (len > maxsize) + len = maxsize; + *start = bvec->bv_offset + i->iov_offset; + + get_page(*pages = bvec->bv_page); + + return len; +} + +static ssize_t get_pages_alloc_bvec(struct iov_iter *i, + struct page ***pages, size_t maxsize, + size_t *start) +{ + const struct bio_vec *bvec = i->bvec; + size_t len = bvec->bv_len - i->iov_offset; + if (len > i->count) + len = i->count; + if (len > maxsize) + len = maxsize; + *start = bvec->bv_offset + i->iov_offset; + + *pages = kmalloc(sizeof(struct page *), GFP_KERNEL); + if (!*pages) + return -ENOMEM; + + get_page(**pages = bvec->bv_page); + + return len; +} + +static int iov_iter_npages_bvec(const struct iov_iter *i, int maxpages) +{ + size_t offset = i->iov_offset; + size_t size = i->count; + const struct bio_vec *bvec = i->bvec; + int npages = 0; + int n; + + for (n = 0; size && n < i->nr_segs; n++, bvec++) { + size_t len = bvec->bv_len - offset; + offset = 0; + if (unlikely(!len)) /* empty segment */ + continue; + if (len > size) + len = size; + npages++; + if (npages >= maxpages) /* don't bother going further */ + return maxpages; + size -= len; + offset = 0; + } + return min(npages, maxpages); +} + +size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, + struct iov_iter *i) +{ + if (i->type & ITER_BVEC) + return copy_page_to_iter_bvec(page, offset, bytes, i); + else + return copy_page_to_iter_iovec(page, offset, bytes, i); +} +EXPORT_SYMBOL(copy_page_to_iter); + +size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, + struct iov_iter *i) +{ + if (i->type & ITER_BVEC) + return copy_page_from_iter_bvec(page, offset, bytes, i); + else + return copy_page_from_iter_iovec(page, offset, bytes, i); +} +EXPORT_SYMBOL(copy_page_from_iter); + +size_t iov_iter_copy_from_user_atomic(struct page *page, + struct iov_iter *i, unsigned long offset, size_t bytes) +{ + if (i->type & ITER_BVEC) + return copy_from_user_bvec(page, i, offset, bytes); + else + return copy_from_user_atomic_iovec(page, i, offset, bytes); +} +EXPORT_SYMBOL(iov_iter_copy_from_user_atomic); + +void iov_iter_advance(struct iov_iter *i, size_t size) +{ + if (i->type & ITER_BVEC) + advance_bvec(i, size); + else + advance_iovec(i, size); +} +EXPORT_SYMBOL(iov_iter_advance); + /* * Return the count of just the current iov_iter segment. */ size_t iov_iter_single_seg_count(const struct iov_iter *i) { - const struct iovec *iov = i->iov; if (i->nr_segs == 1) return i->count; + else if (i->type & ITER_BVEC) + return min(i->count, i->iov->iov_len - i->iov_offset); else - return min(i->count, iov->iov_len - i->iov_offset); + return min(i->count, i->bvec->bv_len - i->iov_offset); } EXPORT_SYMBOL(iov_iter_single_seg_count); + +unsigned long iov_iter_alignment(const struct iov_iter *i) +{ + if (i->type & ITER_BVEC) + return alignment_bvec(i); + else + return alignment_iovec(i); +} +EXPORT_SYMBOL(iov_iter_alignment); + +ssize_t iov_iter_get_pages(struct iov_iter *i, + struct page **pages, size_t maxsize, + size_t *start) +{ + if (i->type & ITER_BVEC) + return get_pages_bvec(i, pages, maxsize, start); + else + return get_pages_iovec(i, pages, maxsize, start); +} +EXPORT_SYMBOL(iov_iter_get_pages); + +ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, + struct page ***pages, size_t maxsize, + size_t *start) +{ + if (i->type & ITER_BVEC) + return get_pages_alloc_bvec(i, pages, maxsize, start); + else + return get_pages_alloc_iovec(i, pages, maxsize, start); +} +EXPORT_SYMBOL(iov_iter_get_pages_alloc); + +int iov_iter_npages(const struct iov_iter *i, int maxpages) +{ + if (i->type & ITER_BVEC) + return iov_iter_npages_bvec(i, maxpages); + else + return iov_iter_npages_iovec(i, maxpages); +} +EXPORT_SYMBOL(iov_iter_npages); diff --git a/mm/memblock.c b/mm/memblock.c index fc212b5fc1ace8..6fdfc290fd2cad 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -27,6 +27,9 @@ static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock; static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock; +#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP +static struct memblock_region memblock_physmem_init_regions[INIT_PHYSMEM_REGIONS] __initdata_memblock; +#endif struct memblock memblock __initdata_memblock = { .memory.regions = memblock_memory_init_regions, @@ -37,6 +40,12 @@ struct memblock memblock __initdata_memblock = { .reserved.cnt = 1, /* empty dummy entry */ .reserved.max = INIT_MEMBLOCK_REGIONS, +#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP + .physmem.regions = memblock_physmem_init_regions, + .physmem.cnt = 1, /* empty dummy entry */ + .physmem.max = INIT_PHYSMEM_REGIONS, +#endif + .bottom_up = false, .current_limit = MEMBLOCK_ALLOC_ANYWHERE, }; @@ -472,7 +481,7 @@ static void __init_memblock memblock_insert_region(struct memblock_type *type, } /** - * memblock_add_region - add new memblock region + * memblock_add_range - add new memblock region * @type: memblock type to add new region into * @base: base address of the new region * @size: size of the new region @@ -487,7 +496,7 @@ static void __init_memblock memblock_insert_region(struct memblock_type *type, * RETURNS: * 0 on success, -errno on failure. */ -static int __init_memblock memblock_add_region(struct memblock_type *type, +int __init_memblock memblock_add_range(struct memblock_type *type, phys_addr_t base, phys_addr_t size, int nid, unsigned long flags) { @@ -569,12 +578,12 @@ static int __init_memblock memblock_add_region(struct memblock_type *type, int __init_memblock memblock_add_node(phys_addr_t base, phys_addr_t size, int nid) { - return memblock_add_region(&memblock.memory, base, size, nid, 0); + return memblock_add_range(&memblock.memory, base, size, nid, 0); } int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size) { - return memblock_add_region(&memblock.memory, base, size, + return memblock_add_range(&memblock.memory, base, size, MAX_NUMNODES, 0); } @@ -654,8 +663,8 @@ static int __init_memblock memblock_isolate_range(struct memblock_type *type, return 0; } -static int __init_memblock __memblock_remove(struct memblock_type *type, - phys_addr_t base, phys_addr_t size) +int __init_memblock memblock_remove_range(struct memblock_type *type, + phys_addr_t base, phys_addr_t size) { int start_rgn, end_rgn; int i, ret; @@ -671,9 +680,10 @@ static int __init_memblock __memblock_remove(struct memblock_type *type, int __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size) { - return __memblock_remove(&memblock.memory, base, size); + return memblock_remove_range(&memblock.memory, base, size); } + int __init_memblock memblock_free(phys_addr_t base, phys_addr_t size) { memblock_dbg(" memblock_free: [%#016llx-%#016llx] %pF\n", @@ -697,7 +707,7 @@ static int __init_memblock memblock_reserve_region(phys_addr_t base, (unsigned long long)base + size - 1, flags, (void *)_RET_IP_); - return memblock_add_region(_rgn, base, size, nid, flags); + return memblock_add_range(_rgn, base, size, nid, flags); } int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size) @@ -759,17 +769,19 @@ int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size) } /** - * __next_free_mem_range - next function for for_each_free_mem_range() + * __next__mem_range - next function for for_each_free_mem_range() etc. * @idx: pointer to u64 loop variable * @nid: node selector, %NUMA_NO_NODE for all nodes + * @type_a: pointer to memblock_type from where the range is taken + * @type_b: pointer to memblock_type which excludes memory from being taken * @out_start: ptr to phys_addr_t for start address of the range, can be %NULL * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL * @out_nid: ptr to int for nid of the range, can be %NULL * - * Find the first free area from *@idx which matches @nid, fill the out + * Find the first area from *@idx which matches @nid, fill the out * parameters, and update *@idx for the next iteration. The lower 32bit of - * *@idx contains index into memory region and the upper 32bit indexes the - * areas before each reserved region. For example, if reserved regions + * *@idx contains index into type_a and the upper 32bit indexes the + * areas before each region in type_b. For example, if type_b regions * look like the following, * * 0:[0-16), 1:[32-48), 2:[128-130) @@ -781,53 +793,77 @@ int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size) * As both region arrays are sorted, the function advances the two indices * in lockstep and returns each intersection. */ -void __init_memblock __next_free_mem_range(u64 *idx, int nid, - phys_addr_t *out_start, - phys_addr_t *out_end, int *out_nid) +void __init_memblock __next_mem_range(u64 *idx, int nid, + struct memblock_type *type_a, + struct memblock_type *type_b, + phys_addr_t *out_start, + phys_addr_t *out_end, int *out_nid) { - struct memblock_type *mem = &memblock.memory; - struct memblock_type *rsv = &memblock.reserved; - int mi = *idx & 0xffffffff; - int ri = *idx >> 32; + int idx_a = *idx & 0xffffffff; + int idx_b = *idx >> 32; - if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n")) + if (WARN_ONCE(nid == MAX_NUMNODES, + "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n")) nid = NUMA_NO_NODE; - for ( ; mi < mem->cnt; mi++) { - struct memblock_region *m = &mem->regions[mi]; + for (; idx_a < type_a->cnt; idx_a++) { + struct memblock_region *m = &type_a->regions[idx_a]; + phys_addr_t m_start = m->base; phys_addr_t m_end = m->base + m->size; + int m_nid = memblock_get_region_node(m); /* only memory regions are associated with nodes, check it */ - if (nid != NUMA_NO_NODE && nid != memblock_get_region_node(m)) + if (nid != NUMA_NO_NODE && nid != m_nid) continue; - /* scan areas before each reservation for intersection */ - for ( ; ri < rsv->cnt + 1; ri++) { - struct memblock_region *r = &rsv->regions[ri]; - phys_addr_t r_start = ri ? r[-1].base + r[-1].size : 0; - phys_addr_t r_end = ri < rsv->cnt ? r->base : ULLONG_MAX; + if (!type_b) { + if (out_start) + *out_start = m_start; + if (out_end) + *out_end = m_end; + if (out_nid) + *out_nid = m_nid; + idx_a++; + *idx = (u32)idx_a | (u64)idx_b << 32; + return; + } - /* if ri advanced past mi, break out to advance mi */ + /* scan areas before each reservation */ + for (; idx_b < type_b->cnt + 1; idx_b++) { + struct memblock_region *r; + phys_addr_t r_start; + phys_addr_t r_end; + + r = &type_b->regions[idx_b]; + r_start = idx_b ? r[-1].base + r[-1].size : 0; + r_end = idx_b < type_b->cnt ? + r->base : ULLONG_MAX; + + /* + * if idx_b advanced past idx_a, + * break out to advance idx_a + */ if (r_start >= m_end) break; /* if the two regions intersect, we're done */ if (m_start < r_end) { if (out_start) - *out_start = max(m_start, r_start); + *out_start = + max(m_start, r_start); if (out_end) *out_end = min(m_end, r_end); if (out_nid) - *out_nid = memblock_get_region_node(m); + *out_nid = m_nid; /* - * The region which ends first is advanced - * for the next iteration. + * The region which ends first is + * advanced for the next iteration. */ if (m_end <= r_end) - mi++; + idx_a++; else - ri++; - *idx = (u32)mi | (u64)ri << 32; + idx_b++; + *idx = (u32)idx_a | (u64)idx_b << 32; return; } } @@ -838,57 +874,80 @@ void __init_memblock __next_free_mem_range(u64 *idx, int nid, } /** - * __next_free_mem_range_rev - next function for for_each_free_mem_range_reverse() + * __next_mem_range_rev - generic next function for for_each_*_range_rev() + * + * Finds the next range from type_a which is not marked as unsuitable + * in type_b. + * * @idx: pointer to u64 loop variable * @nid: nid: node selector, %NUMA_NO_NODE for all nodes + * @type_a: pointer to memblock_type from where the range is taken + * @type_b: pointer to memblock_type which excludes memory from being taken * @out_start: ptr to phys_addr_t for start address of the range, can be %NULL * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL * @out_nid: ptr to int for nid of the range, can be %NULL * - * Reverse of __next_free_mem_range(). - * - * Linux kernel cannot migrate pages used by itself. Memory hotplug users won't - * be able to hot-remove hotpluggable memory used by the kernel. So this - * function skip hotpluggable regions if needed when allocating memory for the - * kernel. + * Reverse of __next_mem_range(). */ -void __init_memblock __next_free_mem_range_rev(u64 *idx, int nid, - phys_addr_t *out_start, - phys_addr_t *out_end, int *out_nid) +void __init_memblock __next_mem_range_rev(u64 *idx, int nid, + struct memblock_type *type_a, + struct memblock_type *type_b, + phys_addr_t *out_start, + phys_addr_t *out_end, int *out_nid) { - struct memblock_type *mem = &memblock.memory; - struct memblock_type *rsv = &memblock.reserved; - int mi = *idx & 0xffffffff; - int ri = *idx >> 32; + int idx_a = *idx & 0xffffffff; + int idx_b = *idx >> 32; if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n")) nid = NUMA_NO_NODE; if (*idx == (u64)ULLONG_MAX) { - mi = mem->cnt - 1; - ri = rsv->cnt; + idx_a = type_a->cnt - 1; + idx_b = type_b->cnt; } - for ( ; mi >= 0; mi--) { - struct memblock_region *m = &mem->regions[mi]; + for (; idx_a >= 0; idx_a--) { + struct memblock_region *m = &type_a->regions[idx_a]; + phys_addr_t m_start = m->base; phys_addr_t m_end = m->base + m->size; + int m_nid = memblock_get_region_node(m); /* only memory regions are associated with nodes, check it */ - if (nid != NUMA_NO_NODE && nid != memblock_get_region_node(m)) + if (nid != NUMA_NO_NODE && nid != m_nid) continue; /* skip hotpluggable memory regions if needed */ if (movable_node_is_enabled() && memblock_is_hotpluggable(m)) continue; - /* scan areas before each reservation for intersection */ - for ( ; ri >= 0; ri--) { - struct memblock_region *r = &rsv->regions[ri]; - phys_addr_t r_start = ri ? r[-1].base + r[-1].size : 0; - phys_addr_t r_end = ri < rsv->cnt ? r->base : ULLONG_MAX; + if (!type_b) { + if (out_start) + *out_start = m_start; + if (out_end) + *out_end = m_end; + if (out_nid) + *out_nid = m_nid; + idx_a++; + *idx = (u32)idx_a | (u64)idx_b << 32; + return; + } + + /* scan areas before each reservation */ + for (; idx_b >= 0; idx_b--) { + struct memblock_region *r; + phys_addr_t r_start; + phys_addr_t r_end; + + r = &type_b->regions[idx_b]; + r_start = idx_b ? r[-1].base + r[-1].size : 0; + r_end = idx_b < type_b->cnt ? + r->base : ULLONG_MAX; + /* + * if idx_b advanced past idx_a, + * break out to advance idx_a + */ - /* if ri advanced past mi, break out to advance mi */ if (r_end <= m_start) break; /* if the two regions intersect, we're done */ @@ -898,18 +957,17 @@ void __init_memblock __next_free_mem_range_rev(u64 *idx, int nid, if (out_end) *out_end = min(m_end, r_end); if (out_nid) - *out_nid = memblock_get_region_node(m); - + *out_nid = m_nid; if (m_start >= r_start) - mi--; + idx_a--; else - ri--; - *idx = (u32)mi | (u64)ri << 32; + idx_b--; + *idx = (u32)idx_a | (u64)idx_b << 32; return; } } } - + /* signal end of iteration */ *idx = ULLONG_MAX; } @@ -1220,7 +1278,7 @@ void __init __memblock_free_early(phys_addr_t base, phys_addr_t size) __func__, (u64)base, (u64)base + size - 1, (void *)_RET_IP_); kmemleak_free_part(__va(base), size); - __memblock_remove(&memblock.reserved, base, size); + memblock_remove_range(&memblock.reserved, base, size); } /* @@ -1306,8 +1364,10 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit) } /* truncate both memory and reserved regions */ - __memblock_remove(&memblock.memory, max_addr, (phys_addr_t)ULLONG_MAX); - __memblock_remove(&memblock.reserved, max_addr, (phys_addr_t)ULLONG_MAX); + memblock_remove_range(&memblock.memory, max_addr, + (phys_addr_t)ULLONG_MAX); + memblock_remove_range(&memblock.reserved, max_addr, + (phys_addr_t)ULLONG_MAX); } static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr) @@ -1520,6 +1580,9 @@ static int __init memblock_init_debugfs(void) return -ENXIO; debugfs_create_file("memory", S_IRUGO, root, &memblock.memory, &memblock_debug_fops); debugfs_create_file("reserved", S_IRUGO, root, &memblock.reserved, &memblock_debug_fops); +#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP + debugfs_create_file("physmem", S_IRUGO, root, &memblock.physmem, &memblock_debug_fops); +#endif return 0; } diff --git a/mm/memcontrol.c b/mm/memcontrol.c index bbab99228f6633..f5ea266f4d9a53 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -526,18 +526,14 @@ static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg) static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg) { - /* - * The ID of the root cgroup is 0, but memcg treat 0 as an - * invalid ID, so we return (cgroup_id + 1). - */ - return memcg->css.cgroup->id + 1; + return memcg->css.id; } static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id) { struct cgroup_subsys_state *css; - css = css_from_id(id - 1, &memory_cgrp_subsys); + css = css_from_id(id, &memory_cgrp_subsys); return mem_cgroup_from_css(css); } @@ -6318,7 +6314,7 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css) struct mem_cgroup *memcg = mem_cgroup_from_css(css); struct mem_cgroup *parent = mem_cgroup_from_css(css_parent(css)); - if (css->cgroup->id > MEM_CGROUP_ID_MAX) + if (css->id > MEM_CGROUP_ID_MAX) return -ENOSPC; if (!parent) diff --git a/mm/memory.c b/mm/memory.c index 71e7bb9d527780..b256439cd23700 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3284,9 +3284,6 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, } } - /* THP should already have been handled */ - BUG_ON(pmd_numa(*pmd)); - /* * Use __pte_alloc instead of pte_alloc_map, because we can't * run pte_offset_map on the pmd, if an huge pmd could diff --git a/mm/page_io.c b/mm/page_io.c index 58b50d2901fe2a..243a9b76e5cee9 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -264,9 +264,17 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc, struct kiocb kiocb; struct file *swap_file = sis->swap_file; struct address_space *mapping = swap_file->f_mapping; - struct iovec iov = { - .iov_base = kmap(page), - .iov_len = PAGE_SIZE, + struct bio_vec bv = { + .bv_page = page, + .bv_len = PAGE_SIZE, + .bv_offset = 0 + }; + struct iov_iter from = { + .type = ITER_BVEC | WRITE, + .count = PAGE_SIZE, + .iov_offset = 0, + .nr_segs = 1, + .bvec = &bv }; init_sync_kiocb(&kiocb, swap_file); @@ -275,10 +283,9 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc, set_page_writeback(page); unlock_page(page); - ret = mapping->a_ops->direct_IO(KERNEL_WRITE, - &kiocb, &iov, - kiocb.ki_pos, 1); - kunmap(page); + ret = mapping->a_ops->direct_IO(ITER_BVEC | WRITE, + &kiocb, &from, + kiocb.ki_pos); if (ret == PAGE_SIZE) { count_vm_event(PSWPOUT); ret = 0; diff --git a/mm/percpu.c b/mm/percpu.c index 63e24fb4387b6d..2ddf9a990dbd05 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -610,7 +610,7 @@ static struct pcpu_chunk *pcpu_alloc_chunk(void) chunk->map = pcpu_mem_zalloc(PCPU_DFL_MAP_ALLOC * sizeof(chunk->map[0])); if (!chunk->map) { - kfree(chunk); + pcpu_mem_free(chunk, pcpu_chunk_struct_size); return NULL; } diff --git a/mm/process_vm_access.c b/mm/process_vm_access.c index 8505c9262b3585..5077afcd9e116b 100644 --- a/mm/process_vm_access.c +++ b/mm/process_vm_access.c @@ -46,11 +46,7 @@ static int process_vm_rw_pages(struct page **pages, copy = len; if (vm_write) { - if (copy > iov_iter_count(iter)) - copy = iov_iter_count(iter); - copied = iov_iter_copy_from_user(page, iter, - offset, copy); - iov_iter_advance(iter, copied); + copied = copy_page_from_iter(page, offset, copy, iter); set_page_dirty_lock(page); } else { copied = copy_page_to_iter(page, offset, copy, iter); @@ -278,7 +274,7 @@ static ssize_t process_vm_rw(pid_t pid, if (rc <= 0) goto free_iovecs; - iov_iter_init(&iter, iov_l, liovcnt, rc, 0); + iov_iter_init(&iter, vm_write ? WRITE : READ, iov_l, liovcnt, rc); rc = rw_copy_check_uvector(CHECK_IOVEC_ONLY, rvec, riovcnt, UIO_FASTIOV, iovstack_r, &iov_r); @@ -341,7 +337,7 @@ compat_process_vm_rw(compat_pid_t pid, &iov_l); if (rc <= 0) goto free_iovecs; - iov_iter_init(&iter, iov_l, liovcnt, rc, 0); + iov_iter_init(&iter, vm_write ? WRITE : READ, iov_l, liovcnt, rc); rc = compat_rw_copy_check_uvector(CHECK_IOVEC_ONLY, rvec, riovcnt, UIO_FASTIOV, iovstack_r, &iov_r); diff --git a/mm/shmem.c b/mm/shmem.c index 9f70e02111c6ad..de834ab8b6b90a 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1402,8 +1402,7 @@ shmem_write_end(struct file *file, struct address_space *mapping, return copied; } -static ssize_t shmem_file_aio_read(struct kiocb *iocb, - const struct iovec *iov, unsigned long nr_segs, loff_t pos) +static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); @@ -1412,15 +1411,8 @@ static ssize_t shmem_file_aio_read(struct kiocb *iocb, unsigned long offset; enum sgp_type sgp = SGP_READ; int error = 0; - ssize_t retval; - size_t count; + ssize_t retval = 0; loff_t *ppos = &iocb->ki_pos; - struct iov_iter iter; - - retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE); - if (retval) - return retval; - iov_iter_init(&iter, iov, nr_segs, count, 0); /* * Might this read be for a stacking filesystem? Then when reading @@ -1496,14 +1488,14 @@ static ssize_t shmem_file_aio_read(struct kiocb *iocb, * Ok, we have the page, and it's up-to-date, so * now we can copy it to user space... */ - ret = copy_page_to_iter(page, offset, nr, &iter); + ret = copy_page_to_iter(page, offset, nr, to); retval += ret; offset += ret; index += offset >> PAGE_CACHE_SHIFT; offset &= ~PAGE_CACHE_MASK; page_cache_release(page); - if (!iov_iter_count(&iter)) + if (!iov_iter_count(to)) break; if (ret < nr) { error = -EFAULT; @@ -2625,13 +2617,13 @@ static const struct file_operations shmem_file_operations = { .mmap = shmem_mmap, #ifdef CONFIG_TMPFS .llseek = shmem_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = shmem_file_aio_read, - .aio_write = generic_file_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = shmem_file_read_iter, + .write_iter = generic_file_write_iter, .fsync = noop_fsync, .splice_read = shmem_file_splice_read, - .splice_write = generic_file_splice_write, + .splice_write = iter_file_splice_write, .fallocate = shmem_fallocate, #endif }; diff --git a/mm/vmscan.c b/mm/vmscan.c index 10dcd401774b5a..3dc829a220e54c 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -464,7 +464,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping, * stalls if we need to run get_block(). We could test * PagePrivate for that. * - * If this process is currently in __generic_file_aio_write() against + * If this process is currently in __generic_file_write_iter() against * this page's queue, we can perform writeback even if that * will block. * diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 733ec283ed1b9e..8f025afa29fdac 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -706,38 +706,36 @@ static void vlan_ethtool_get_drvinfo(struct net_device *dev, static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { + struct vlan_pcpu_stats *p; + u32 rx_errors = 0, tx_dropped = 0; + int i; - if (vlan_dev_priv(dev)->vlan_pcpu_stats) { - struct vlan_pcpu_stats *p; - u32 rx_errors = 0, tx_dropped = 0; - int i; - - for_each_possible_cpu(i) { - u64 rxpackets, rxbytes, rxmulticast, txpackets, txbytes; - unsigned int start; - - p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i); - do { - start = u64_stats_fetch_begin_irq(&p->syncp); - rxpackets = p->rx_packets; - rxbytes = p->rx_bytes; - rxmulticast = p->rx_multicast; - txpackets = p->tx_packets; - txbytes = p->tx_bytes; - } while (u64_stats_fetch_retry_irq(&p->syncp, start)); - - stats->rx_packets += rxpackets; - stats->rx_bytes += rxbytes; - stats->multicast += rxmulticast; - stats->tx_packets += txpackets; - stats->tx_bytes += txbytes; - /* rx_errors & tx_dropped are u32 */ - rx_errors += p->rx_errors; - tx_dropped += p->tx_dropped; - } - stats->rx_errors = rx_errors; - stats->tx_dropped = tx_dropped; + for_each_possible_cpu(i) { + u64 rxpackets, rxbytes, rxmulticast, txpackets, txbytes; + unsigned int start; + + p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i); + do { + start = u64_stats_fetch_begin_irq(&p->syncp); + rxpackets = p->rx_packets; + rxbytes = p->rx_bytes; + rxmulticast = p->rx_multicast; + txpackets = p->tx_packets; + txbytes = p->tx_bytes; + } while (u64_stats_fetch_retry_irq(&p->syncp, start)); + + stats->rx_packets += rxpackets; + stats->rx_bytes += rxbytes; + stats->multicast += rxmulticast; + stats->tx_packets += txpackets; + stats->tx_bytes += txbytes; + /* rx_errors & tx_dropped are u32 */ + rx_errors += p->rx_errors; + tx_dropped += p->tx_dropped; } + stats->rx_errors = rx_errors; + stats->tx_dropped = tx_dropped; + return stats; } diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index 8c93267ce96910..c4e09846d1dea2 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c @@ -252,7 +252,7 @@ static int pppoatm_may_send(struct pppoatm_vcc *pvcc, int size) * we need to ensure there's a memory barrier after it. The bit * *must* be set before we do the atomic_inc() on pvcc->inflight. * There's no smp_mb__after_set_bit(), so it's this or abuse - * smp_mb__after_clear_bit(). + * smp_mb__after_atomic(). */ test_and_set_bit(BLOCKED, &pvcc->blocked); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 521fd4f3985e11..095943c02d6e4a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -367,9 +367,23 @@ static void le_conn_timeout(struct work_struct *work) { struct hci_conn *conn = container_of(work, struct hci_conn, le_conn_timeout.work); + struct hci_dev *hdev = conn->hdev; BT_DBG(""); + /* We could end up here due to having done directed advertising, + * so clean up the state if necessary. This should however only + * happen with broken hardware or if low duty cycle was used + * (which doesn't have a timeout of its own). + */ + if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) { + u8 enable = 0x00; + hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), + &enable); + hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT); + return; + } + hci_le_create_connection_cancel(conn); } @@ -401,6 +415,10 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) case ACL_LINK: conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; break; + case LE_LINK: + /* conn->src should reflect the local identity address */ + hci_copy_identity_address(hdev, &conn->src, &conn->src_type); + break; case SCO_LINK: if (lmp_esco_capable(hdev)) conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) | @@ -545,6 +563,11 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) * favor of connection establishment, we should restart it. */ hci_update_background_scan(hdev); + + /* Re-enable advertising in case this was a failed connection + * attempt as a peripheral. + */ + mgmt_reenable_advertising(hdev); } static void create_le_conn_complete(struct hci_dev *hdev, u8 status) @@ -605,6 +628,45 @@ static void hci_req_add_le_create_conn(struct hci_request *req, conn->state = BT_CONNECT; } +static void hci_req_directed_advertising(struct hci_request *req, + struct hci_conn *conn) +{ + struct hci_dev *hdev = req->hdev; + struct hci_cp_le_set_adv_param cp; + u8 own_addr_type; + u8 enable; + + enable = 0x00; + hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); + + /* Clear the HCI_ADVERTISING bit temporarily so that the + * hci_update_random_address knows that it's safe to go ahead + * and write a new random address. The flag will be set back on + * as soon as the SET_ADV_ENABLE HCI command completes. + */ + clear_bit(HCI_ADVERTISING, &hdev->dev_flags); + + /* Set require_privacy to false so that the remote device has a + * chance of identifying us. + */ + if (hci_update_random_address(req, false, &own_addr_type) < 0) + return; + + memset(&cp, 0, sizeof(cp)); + cp.type = LE_ADV_DIRECT_IND; + cp.own_address_type = own_addr_type; + cp.direct_addr_type = conn->dst_type; + bacpy(&cp.direct_addr, &conn->dst); + cp.channel_map = hdev->le_adv_channel_map; + + hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp); + + enable = 0x01; + hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); + + conn->state = BT_CONNECT; +} + struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u8 auth_type) { @@ -614,9 +676,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, struct hci_request req; int err; - if (test_bit(HCI_ADVERTISING, &hdev->flags)) - return ERR_PTR(-ENOTSUPP); - /* Some devices send ATT messages as soon as the physical link is * established. To be able to handle these ATT messages, the user- * space first establishes the connection and then starts the pairing @@ -664,13 +723,20 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, return ERR_PTR(-ENOMEM); conn->dst_type = dst_type; - - conn->out = true; - conn->link_mode |= HCI_LM_MASTER; conn->sec_level = BT_SECURITY_LOW; conn->pending_sec_level = sec_level; conn->auth_type = auth_type; + hci_req_init(&req, hdev); + + if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) { + hci_req_directed_advertising(&req, conn); + goto create_conn; + } + + conn->out = true; + conn->link_mode |= HCI_LM_MASTER; + params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); if (params) { conn->le_conn_min_interval = params->conn_min_interval; @@ -680,8 +746,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, conn->le_conn_max_interval = hdev->le_conn_max_interval; } - hci_req_init(&req, hdev); - /* If controller is scanning, we stop it since some controllers are * not able to scan and connect at the same time. Also set the * HCI_LE_SCAN_INTERRUPTED flag so that the command complete @@ -695,6 +759,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, hci_req_add_le_create_conn(&req, conn); +create_conn: err = hci_req_run(&req, create_le_conn_complete); if (err) { hci_conn_del(conn); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1c6ffaa8902f5e..d31f144860d127 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -955,14 +955,9 @@ static ssize_t le_auto_conn_write(struct file *file, const char __user *data, if (count < 3) return -EINVAL; - buf = kzalloc(count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (copy_from_user(buf, data, count)) { - err = -EFAULT; - goto done; - } + buf = memdup_user(data, count); + if (IS_ERR(buf)) + return PTR_ERR(buf); if (memcmp(buf, "add", 3) == 0) { n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu", @@ -1828,6 +1823,9 @@ static int __hci_init(struct hci_dev *hdev) &lowpan_debugfs_fops); debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev, &le_auto_conn_fops); + debugfs_create_u16("discov_interleaved_timeout", 0644, + hdev->debugfs, + &hdev->discov_interleaved_timeout); } return 0; @@ -2033,12 +2031,11 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, hci_remove_remote_oob_data(hdev, &data->bdaddr); - if (ssp) - *ssp = data->ssp_mode; + *ssp = data->ssp_mode; ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr); if (ie) { - if (ie->data.ssp_mode && ssp) + if (ie->data.ssp_mode) *ssp = true; if (ie->name_state == NAME_NEEDED && @@ -3791,6 +3788,7 @@ struct hci_dev *hci_alloc_dev(void) hdev->le_conn_max_interval = 0x0038; hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT; + hdev->discov_interleaved_timeout = DISCOV_INTERLEAVED_TIMEOUT; mutex_init(&hdev->lock); mutex_init(&hdev->req_lock); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 15010a230b6d5f..0974697ae7c4bc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -45,7 +45,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) return; clear_bit(HCI_INQUIRY, &hdev->flags); - smp_mb__after_clear_bit(); /* wake_up_bit advises about this barrier */ + smp_mb__after_atomic(); /* wake_up_bit advises about this barrier */ wake_up_bit(&hdev->flags, HCI_INQUIRY); hci_conn_check_pending(hdev); @@ -991,10 +991,25 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) if (!sent) return; + if (status) + return; + hci_dev_lock(hdev); - if (!status) - mgmt_advertising(hdev, *sent); + /* If we're doing connection initation as peripheral. Set a + * timeout in case something goes wrong. + */ + if (*sent) { + struct hci_conn *conn; + + conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); + if (conn) + queue_delayed_work(hdev->workqueue, + &conn->le_conn_timeout, + HCI_LE_CONN_TIMEOUT); + } + + mgmt_advertising(hdev, *sent); hci_dev_unlock(hdev); } @@ -1018,6 +1033,33 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_unlock(hdev); } +static bool has_pending_adv_report(struct hci_dev *hdev) +{ + struct discovery_state *d = &hdev->discovery; + + return bacmp(&d->last_adv_addr, BDADDR_ANY); +} + +static void clear_pending_adv_report(struct hci_dev *hdev) +{ + struct discovery_state *d = &hdev->discovery; + + bacpy(&d->last_adv_addr, BDADDR_ANY); + d->last_adv_data_len = 0; +} + +static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 bdaddr_type, s8 rssi, u8 *data, u8 len) +{ + struct discovery_state *d = &hdev->discovery; + + bacpy(&d->last_adv_addr, bdaddr); + d->last_adv_addr_type = bdaddr_type; + d->last_adv_rssi = rssi; + memcpy(d->last_adv_data, data, len); + d->last_adv_data_len = len; +} + static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) { @@ -1036,9 +1078,25 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, switch (cp->enable) { case LE_SCAN_ENABLE: set_bit(HCI_LE_SCAN, &hdev->dev_flags); + if (hdev->le_scan_type == LE_SCAN_ACTIVE) + clear_pending_adv_report(hdev); break; case LE_SCAN_DISABLE: + /* We do this here instead of when setting DISCOVERY_STOPPED + * since the latter would potentially require waiting for + * inquiry to stop too. + */ + if (has_pending_adv_report(hdev)) { + struct discovery_state *d = &hdev->discovery; + + mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, + d->last_adv_addr_type, NULL, + d->last_adv_rssi, 0, 1, + d->last_adv_data, + d->last_adv_data_len, NULL, 0); + } + /* Cancel this timer so that we don't try to disable scanning * when it's already disabled. */ @@ -1187,6 +1245,25 @@ static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev, amp_write_rem_assoc_continue(hdev, rp->phy_handle); } +static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_rp_read_rssi *rp = (void *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); + + if (rp->status) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle)); + if (conn) + conn->rssi = rp->rssi; + + hci_dev_unlock(hdev); +} + static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) { BT_DBG("%s status 0x%2.2x", hdev->name, status); @@ -1768,7 +1845,7 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) return; - smp_mb__after_clear_bit(); /* wake_up_bit advises about this barrier */ + smp_mb__after_atomic(); /* wake_up_bit advises about this barrier */ wake_up_bit(&hdev->flags, HCI_INQUIRY); if (!test_bit(HCI_MGMT, &hdev->dev_flags)) @@ -1827,7 +1904,7 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, 0, !name_known, ssp, NULL, - 0); + 0, NULL, 0); } hci_dev_unlock(hdev); @@ -2579,6 +2656,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_write_remote_amp_assoc(hdev, skb); break; + case HCI_OP_READ_RSSI: + hci_cc_read_rssi(hdev, skb); + break; + default: BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); break; @@ -3102,7 +3183,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, ssp, NULL, 0); + !name_known, ssp, NULL, 0, NULL, 0); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); @@ -3120,7 +3201,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, ssp, NULL, 0); + !name_known, ssp, NULL, 0, NULL, 0); } } @@ -3309,7 +3390,7 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev, eir_len = eir_get_length(info->data, sizeof(info->data)); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, !name_known, - ssp, info->data, eir_len); + ssp, info->data, eir_len, NULL, 0); } hci_dev_unlock(hdev); @@ -3367,24 +3448,20 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev, static u8 hci_get_auth_req(struct hci_conn *conn) { - /* If remote requests dedicated bonding follow that lead */ - if (conn->remote_auth == HCI_AT_DEDICATED_BONDING || - conn->remote_auth == HCI_AT_DEDICATED_BONDING_MITM) { - /* If both remote and local IO capabilities allow MITM - * protection then require it, otherwise don't */ - if (conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT || - conn->io_capability == HCI_IO_NO_INPUT_OUTPUT) - return HCI_AT_DEDICATED_BONDING; - else - return HCI_AT_DEDICATED_BONDING_MITM; - } - /* If remote requests no-bonding follow that lead */ if (conn->remote_auth == HCI_AT_NO_BONDING || conn->remote_auth == HCI_AT_NO_BONDING_MITM) return conn->remote_auth | (conn->auth_type & 0x01); - return conn->auth_type; + /* If both remote and local have enough IO capabilities, require + * MITM protection + */ + if (conn->remote_cap != HCI_IO_NO_INPUT_OUTPUT && + conn->io_capability != HCI_IO_NO_INPUT_OUTPUT) + return conn->remote_auth | 0x01; + + /* No MITM protection possible so ignore remote requirement */ + return (conn->remote_auth & ~0x01) | (conn->auth_type & 0x01); } static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) @@ -3414,8 +3491,21 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) * to DisplayYesNo as it is not supported by BT spec. */ cp.capability = (conn->io_capability == 0x04) ? HCI_IO_DISPLAY_YESNO : conn->io_capability; - conn->auth_type = hci_get_auth_req(conn); - cp.authentication = conn->auth_type; + + /* If we are initiators, there is no remote information yet */ + if (conn->remote_auth == 0xff) { + cp.authentication = conn->auth_type; + + /* Request MITM protection if our IO caps allow it + * except for the no-bonding case + */ + if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && + cp.authentication != HCI_AT_NO_BONDING) + cp.authentication |= 0x01; + } else { + conn->auth_type = hci_get_auth_req(conn); + cp.authentication = conn->auth_type; + } if (hci_find_remote_oob_data(hdev, &conn->dst) && (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags))) @@ -3483,12 +3573,9 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, rem_mitm = (conn->remote_auth & 0x01); /* If we require MITM but the remote device can't provide that - * (it has NoInputNoOutput) then reject the confirmation - * request. The only exception is when we're dedicated bonding - * initiators (connect_cfm_cb set) since then we always have the MITM - * bit set. */ - if (!conn->connect_cfm_cb && loc_mitm && - conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) { + * (it has NoInputNoOutput) then reject the confirmation request + */ + if (loc_mitm && conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) { BT_DBG("Rejecting request: remote device can't provide MITM"); hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); @@ -3846,17 +3933,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->dst_type = ev->bdaddr_type; - /* The advertising parameters for own address type - * define which source address and source address - * type this connections has. - */ - if (bacmp(&conn->src, BDADDR_ANY)) { - conn->src_type = ADDR_LE_DEV_PUBLIC; - } else { - bacpy(&conn->src, &hdev->static_addr); - conn->src_type = ADDR_LE_DEV_RANDOM; - } - if (ev->role == LE_CONN_ROLE_MASTER) { conn->out = true; conn->link_mode |= HCI_LM_MASTER; @@ -3881,27 +3957,24 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) &conn->init_addr, &conn->init_addr_type); } - } else { - /* Set the responder (our side) address type based on - * the advertising address type. - */ - conn->resp_addr_type = hdev->adv_addr_type; - if (hdev->adv_addr_type == ADDR_LE_DEV_RANDOM) - bacpy(&conn->resp_addr, &hdev->random_addr); - else - bacpy(&conn->resp_addr, &hdev->bdaddr); - - conn->init_addr_type = ev->bdaddr_type; - bacpy(&conn->init_addr, &ev->bdaddr); } } else { cancel_delayed_work(&conn->le_conn_timeout); } - /* Ensure that the hci_conn contains the identity address type - * regardless of which address the connection was made with. - */ - hci_copy_identity_address(hdev, &conn->src, &conn->src_type); + if (!conn->out) { + /* Set the responder (our side) address type based on + * the advertising address type. + */ + conn->resp_addr_type = hdev->adv_addr_type; + if (hdev->adv_addr_type == ADDR_LE_DEV_RANDOM) + bacpy(&conn->resp_addr, &hdev->random_addr); + else + bacpy(&conn->resp_addr, &hdev->bdaddr); + + conn->init_addr_type = ev->bdaddr_type; + bacpy(&conn->init_addr, &ev->bdaddr); + } /* Lookup the identity address from the stored connection * address and address type. @@ -3981,25 +4054,97 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, } } +static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, + u8 bdaddr_type, s8 rssi, u8 *data, u8 len) +{ + struct discovery_state *d = &hdev->discovery; + bool match; + + /* Passive scanning shouldn't trigger any device found events */ + if (hdev->le_scan_type == LE_SCAN_PASSIVE) { + if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND) + check_pending_le_conn(hdev, bdaddr, bdaddr_type); + return; + } + + /* If there's nothing pending either store the data from this + * event or send an immediate device found event if the data + * should not be stored for later. + */ + if (!has_pending_adv_report(hdev)) { + /* If the report will trigger a SCAN_REQ store it for + * later merging. + */ + if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) { + store_pending_adv_report(hdev, bdaddr, bdaddr_type, + rssi, data, len); + return; + } + + mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, + rssi, 0, 1, data, len, NULL, 0); + return; + } + + /* Check if the pending report is for the same device as the new one */ + match = (!bacmp(bdaddr, &d->last_adv_addr) && + bdaddr_type == d->last_adv_addr_type); + + /* If the pending data doesn't match this report or this isn't a + * scan response (e.g. we got a duplicate ADV_IND) then force + * sending of the pending data. + */ + if (type != LE_ADV_SCAN_RSP || !match) { + /* Send out whatever is in the cache, but skip duplicates */ + if (!match) + mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, + d->last_adv_addr_type, NULL, + d->last_adv_rssi, 0, 1, + d->last_adv_data, + d->last_adv_data_len, NULL, 0); + + /* If the new report will trigger a SCAN_REQ store it for + * later merging. + */ + if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) { + store_pending_adv_report(hdev, bdaddr, bdaddr_type, + rssi, data, len); + return; + } + + /* The advertising reports cannot be merged, so clear + * the pending report and send out a device found event. + */ + clear_pending_adv_report(hdev); + mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, + rssi, 0, 1, data, len, NULL, 0); + return; + } + + /* If we get here we've got a pending ADV_IND or ADV_SCAN_IND and + * the new event is a SCAN_RSP. We can therefore proceed with + * sending a merged device found event. + */ + mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, + d->last_adv_addr_type, NULL, rssi, 0, 1, data, len, + d->last_adv_data, d->last_adv_data_len); + clear_pending_adv_report(hdev); +} + static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) { u8 num_reports = skb->data[0]; void *ptr = &skb->data[1]; - s8 rssi; hci_dev_lock(hdev); while (num_reports--) { struct hci_ev_le_advertising_info *ev = ptr; - - if (ev->evt_type == LE_ADV_IND || - ev->evt_type == LE_ADV_DIRECT_IND) - check_pending_le_conn(hdev, &ev->bdaddr, - ev->bdaddr_type); + s8 rssi; rssi = ev->data[ev->length]; - mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type, - NULL, rssi, 0, 1, ev->data, ev->length); + process_adv_report(hdev, ev->evt_type, &ev->bdaddr, + ev->bdaddr_type, rssi, ev->data, ev->length); ptr += sizeof(*ev) + ev->length + 1; } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index b9a418e578e000..f608bffdb8b940 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -524,16 +524,7 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, case HCISETRAW: if (!capable(CAP_NET_ADMIN)) return -EPERM; - - if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) - return -EPERM; - - if (arg) - set_bit(HCI_RAW, &hdev->flags); - else - clear_bit(HCI_RAW, &hdev->flags); - - return 0; + return -EOPNOTSUPP; case HCIGETCONNINFO: return hci_get_conn_info(hdev, (void __user *) arg); diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c index b3fbc73516c415..941ad7530eda48 100644 --- a/net/bluetooth/lib.c +++ b/net/bluetooth/lib.c @@ -58,6 +58,7 @@ int bt_to_errno(__u16 code) return EIO; case 0x04: + case 0x3c: return EHOSTDOWN; case 0x05: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d2d4e0d5aed017..54abbce3a39e8b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2850,10 +2850,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, } sec_level = BT_SECURITY_MEDIUM; - if (cp->io_cap == 0x03) - auth_type = HCI_AT_DEDICATED_BONDING; - else - auth_type = HCI_AT_DEDICATED_BONDING_MITM; + auth_type = HCI_AT_DEDICATED_BONDING; if (cp->addr.type == BDADDR_BREDR) { conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level, @@ -3351,6 +3348,8 @@ static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) static void start_discovery_complete(struct hci_dev *hdev, u8 status) { + unsigned long timeout = 0; + BT_DBG("status %d", status); if (status) { @@ -3366,13 +3365,11 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status) switch (hdev->discovery.type) { case DISCOV_TYPE_LE: - queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, - DISCOV_LE_TIMEOUT); + timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT); break; case DISCOV_TYPE_INTERLEAVED: - queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, - DISCOV_INTERLEAVED_TIMEOUT); + timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout); break; case DISCOV_TYPE_BREDR: @@ -3381,6 +3378,11 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status) default: BT_ERR("Invalid discovery type %d", hdev->discovery.type); } + + if (!timeout) + return; + + queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, timeout); } static int start_discovery(struct sock *sk, struct hci_dev *hdev, @@ -5668,8 +5670,9 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, } void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8 - ssp, u8 *eir, u16 eir_len) + u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, + u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp, + u8 scan_rsp_len) { char buf[512]; struct mgmt_ev_device_found *ev = (void *) buf; @@ -5679,8 +5682,10 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, if (!hci_discovery_active(hdev)) return; - /* Leave 5 bytes for a potential CoD field */ - if (sizeof(*ev) + eir_len + 5 > sizeof(buf)) + /* Make sure that the buffer is big enough. The 5 extra bytes + * are for the potential CoD field. + */ + if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf)) return; memset(buf, 0, sizeof(buf)); @@ -5707,8 +5712,11 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, dev_class, 3); - ev->eir_len = cpu_to_le16(eir_len); - ev_size = sizeof(*ev) + eir_len; + if (scan_rsp_len > 0) + memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len); + + ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len); + ev_size = sizeof(*ev) + eir_len + scan_rsp_len; mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL); } diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index cf620260affaea..754b6fe4f742af 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -307,7 +307,7 @@ struct rfcomm_dlc *rfcomm_dlc_alloc(gfp_t prio) setup_timer(&d->timer, rfcomm_dlc_timeout, (unsigned long)d); skb_queue_head_init(&d->tx_queue); - spin_lock_init(&d->lock); + mutex_init(&d->lock); atomic_set(&d->refcnt, 1); rfcomm_dlc_clear_state(d); diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 403ec09f480a2a..8e385a0ae60e0b 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -70,7 +70,7 @@ struct rfcomm_dev { }; static LIST_HEAD(rfcomm_dev_list); -static DEFINE_SPINLOCK(rfcomm_dev_lock); +static DEFINE_MUTEX(rfcomm_dev_lock); static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb); static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err); @@ -96,9 +96,9 @@ static void rfcomm_dev_destruct(struct tty_port *port) if (dev->tty_dev) tty_unregister_device(rfcomm_tty_driver, dev->id); - spin_lock(&rfcomm_dev_lock); + mutex_lock(&rfcomm_dev_lock); list_del(&dev->list); - spin_unlock(&rfcomm_dev_lock); + mutex_unlock(&rfcomm_dev_lock); kfree(dev); @@ -161,14 +161,14 @@ static struct rfcomm_dev *rfcomm_dev_get(int id) { struct rfcomm_dev *dev; - spin_lock(&rfcomm_dev_lock); + mutex_lock(&rfcomm_dev_lock); dev = __rfcomm_dev_lookup(id); if (dev && !tty_port_get(&dev->port)) dev = NULL; - spin_unlock(&rfcomm_dev_lock); + mutex_unlock(&rfcomm_dev_lock); return dev; } @@ -224,7 +224,7 @@ static struct rfcomm_dev *__rfcomm_dev_add(struct rfcomm_dev_req *req, if (!dev) return ERR_PTR(-ENOMEM); - spin_lock(&rfcomm_dev_lock); + mutex_lock(&rfcomm_dev_lock); if (req->dev_id < 0) { dev->id = 0; @@ -305,11 +305,11 @@ static struct rfcomm_dev *__rfcomm_dev_add(struct rfcomm_dev_req *req, holds reference to this module. */ __module_get(THIS_MODULE); - spin_unlock(&rfcomm_dev_lock); + mutex_unlock(&rfcomm_dev_lock); return dev; out: - spin_unlock(&rfcomm_dev_lock); + mutex_unlock(&rfcomm_dev_lock); kfree(dev); return ERR_PTR(err); } @@ -524,7 +524,7 @@ static int rfcomm_get_dev_list(void __user *arg) di = dl->dev_info; - spin_lock(&rfcomm_dev_lock); + mutex_lock(&rfcomm_dev_lock); list_for_each_entry(dev, &rfcomm_dev_list, list) { if (!tty_port_get(&dev->port)) @@ -540,7 +540,7 @@ static int rfcomm_get_dev_list(void __user *arg) break; } - spin_unlock(&rfcomm_dev_lock); + mutex_unlock(&rfcomm_dev_lock); dl->dev_num = n; size = sizeof(*dl) + n * sizeof(*di); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index dfb4e1161c10fb..b5b926399e76e9 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -663,7 +663,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); if (skb->len < sizeof(*req)) - return SMP_UNSPECIFIED; + return SMP_INVALID_PARAMS; if (conn->hcon->link_mode & HCI_LM_MASTER) return SMP_CMD_NOTSUPP; @@ -720,7 +720,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); if (skb->len < sizeof(*rsp)) - return SMP_UNSPECIFIED; + return SMP_INVALID_PARAMS; if (!(conn->hcon->link_mode & HCI_LM_MASTER)) return SMP_CMD_NOTSUPP; @@ -770,7 +770,7 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); if (skb->len < sizeof(smp->pcnf)) - return SMP_UNSPECIFIED; + return SMP_INVALID_PARAMS; memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf)); skb_pull(skb, sizeof(smp->pcnf)); @@ -794,7 +794,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); if (skb->len < sizeof(smp->rrnd)) - return SMP_UNSPECIFIED; + return SMP_INVALID_PARAMS; memcpy(smp->rrnd, skb->data, sizeof(smp->rrnd)); skb_pull(skb, sizeof(smp->rrnd)); @@ -836,7 +836,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); if (skb->len < sizeof(*rp)) - return SMP_UNSPECIFIED; + return SMP_INVALID_PARAMS; if (!(conn->hcon->link_mode & HCI_LM_MASTER)) return SMP_CMD_NOTSUPP; @@ -944,7 +944,7 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); if (skb->len < sizeof(*rp)) - return SMP_UNSPECIFIED; + return SMP_INVALID_PARAMS; /* Ignore this PDU if it wasn't requested */ if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY)) @@ -969,7 +969,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); if (skb->len < sizeof(*rp)) - return SMP_UNSPECIFIED; + return SMP_INVALID_PARAMS; /* Ignore this PDU if it wasn't requested */ if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY)) @@ -1001,7 +1001,7 @@ static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG(""); if (skb->len < sizeof(*info)) - return SMP_UNSPECIFIED; + return SMP_INVALID_PARAMS; /* Ignore this PDU if it wasn't requested */ if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) @@ -1025,7 +1025,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, BT_DBG(""); if (skb->len < sizeof(*info)) - return SMP_UNSPECIFIED; + return SMP_INVALID_PARAMS; /* Ignore this PDU if it wasn't requested */ if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) @@ -1075,7 +1075,7 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); if (skb->len < sizeof(*rp)) - return SMP_UNSPECIFIED; + return SMP_INVALID_PARAMS; /* Ignore this PDU if it wasn't requested */ if (!(smp->remote_key_dist & SMP_DIST_SIGN)) diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 1277147a915070..afd16231db1372 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -111,6 +111,7 @@ struct smp_cmd_security_req { #define SMP_CMD_NOTSUPP 0x07 #define SMP_UNSPECIFIED 0x08 #define SMP_REPEATED_ATTEMPTS 0x09 +#define SMP_INVALID_PARAMS 0x0a #define SMP_MIN_ENC_KEY_SIZE 7 #define SMP_MAX_ENC_KEY_SIZE 16 diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c index 815a2249cfa937..555013034f7a89 100644 --- a/net/ceph/pagevec.c +++ b/net/ceph/pagevec.c @@ -53,7 +53,10 @@ void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty) set_page_dirty_lock(pages[i]); put_page(pages[i]); } - kfree(pages); + if (is_vmalloc_addr(pages)) + vfree(pages); + else + kfree(pages); } EXPORT_SYMBOL(ceph_put_page_vector); @@ -164,36 +167,6 @@ void ceph_copy_from_page_vector(struct page **pages, } EXPORT_SYMBOL(ceph_copy_from_page_vector); -/* - * copy user data from a page vector into a user pointer - */ -int ceph_copy_page_vector_to_user(struct page **pages, - void __user *data, - loff_t off, size_t len) -{ - int i = 0; - int po = off & ~PAGE_CACHE_MASK; - int left = len; - int l, bad; - - while (left > 0) { - l = min_t(int, left, PAGE_CACHE_SIZE-po); - bad = copy_to_user(data, page_address(pages[i]) + po, l); - if (bad == l) - return -EFAULT; - data += l - bad; - left -= l - bad; - if (po) { - po += l - bad; - if (po == PAGE_CACHE_SIZE) - po = 0; - } - i++; - } - return len; -} -EXPORT_SYMBOL(ceph_copy_page_vector_to_user); - /* * Zero an extent within a page vector. Offset is relative to the * start of the first page. diff --git a/net/core/dev.c b/net/core/dev.c index d2c8a06b3a9883..1a266ac82c1adc 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1326,7 +1326,7 @@ static int __dev_close_many(struct list_head *head) * dev->stop() will invoke napi_disable() on all of it's * napi_struct instances on this device. */ - smp_mb__after_clear_bit(); /* Commit netif_running(). */ + smp_mb__after_atomic(); /* Commit netif_running(). */ } dev_deactivate_many(head); @@ -1661,6 +1661,29 @@ bool is_skb_forwardable(struct net_device *dev, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(is_skb_forwardable); +int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb) +{ + if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { + if (skb_copy_ubufs(skb, GFP_ATOMIC)) { + atomic_long_inc(&dev->rx_dropped); + kfree_skb(skb); + return NET_RX_DROP; + } + } + + if (unlikely(!is_skb_forwardable(dev, skb))) { + atomic_long_inc(&dev->rx_dropped); + kfree_skb(skb); + return NET_RX_DROP; + } + + skb_scrub_packet(skb, true); + skb->protocol = eth_type_trans(skb, dev); + + return 0; +} +EXPORT_SYMBOL_GPL(__dev_forward_skb); + /** * dev_forward_skb - loopback an skb to another netif * @@ -1681,24 +1704,7 @@ EXPORT_SYMBOL_GPL(is_skb_forwardable); */ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) { - if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { - if (skb_copy_ubufs(skb, GFP_ATOMIC)) { - atomic_long_inc(&dev->rx_dropped); - kfree_skb(skb); - return NET_RX_DROP; - } - } - - if (unlikely(!is_skb_forwardable(dev, skb))) { - atomic_long_inc(&dev->rx_dropped); - kfree_skb(skb); - return NET_RX_DROP; - } - - skb_scrub_packet(skb, true); - skb->protocol = eth_type_trans(skb, dev); - - return netif_rx_internal(skb); + return __dev_forward_skb(dev, skb) ?: netif_rx_internal(skb); } EXPORT_SYMBOL_GPL(dev_forward_skb); @@ -2418,7 +2424,7 @@ EXPORT_SYMBOL(netdev_rx_csum_fault); * 2. No high memory really exists on this machine. */ -static int illegal_highdma(const struct net_device *dev, struct sk_buff *skb) +static int illegal_highdma(struct net_device *dev, struct sk_buff *skb) { #ifdef CONFIG_HIGHMEM int i; @@ -2493,38 +2499,36 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features) } static netdev_features_t harmonize_features(struct sk_buff *skb, - const struct net_device *dev, - netdev_features_t features) + netdev_features_t features) { int tmp; if (skb->ip_summed != CHECKSUM_NONE && !can_checksum_protocol(features, skb_network_protocol(skb, &tmp))) { features &= ~NETIF_F_ALL_CSUM; - } else if (illegal_highdma(dev, skb)) { + } else if (illegal_highdma(skb->dev, skb)) { features &= ~NETIF_F_SG; } return features; } -netdev_features_t netif_skb_dev_features(struct sk_buff *skb, - const struct net_device *dev) +netdev_features_t netif_skb_features(struct sk_buff *skb) { __be16 protocol = skb->protocol; - netdev_features_t features = dev->features; + netdev_features_t features = skb->dev->features; - if (skb_shinfo(skb)->gso_segs > dev->gso_max_segs) + if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs) features &= ~NETIF_F_GSO_MASK; if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) { struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; protocol = veh->h_vlan_encapsulated_proto; } else if (!vlan_tx_tag_present(skb)) { - return harmonize_features(skb, dev, features); + return harmonize_features(skb, features); } - features &= (dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX | + features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX); if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) @@ -2532,9 +2536,9 @@ netdev_features_t netif_skb_dev_features(struct sk_buff *skb, NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; - return harmonize_features(skb, dev, features); + return harmonize_features(skb, features); } -EXPORT_SYMBOL(netif_skb_dev_features); +EXPORT_SYMBOL(netif_skb_features); int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq) @@ -3343,7 +3347,7 @@ static void net_tx_action(struct softirq_action *h) root_lock = qdisc_lock(q); if (spin_trylock(root_lock)) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(__QDISC_STATE_SCHED, &q->state); qdisc_run(q); @@ -3353,7 +3357,7 @@ static void net_tx_action(struct softirq_action *h) &q->state)) { __netif_reschedule(q); } else { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(__QDISC_STATE_SCHED, &q->state); } @@ -4244,7 +4248,7 @@ void __napi_complete(struct napi_struct *n) BUG_ON(n->gro_list); list_del(&n->poll_list); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(NAPI_STATE_SCHED, &n->state); } EXPORT_SYMBOL(__napi_complete); @@ -5600,10 +5604,6 @@ static void rollback_registered_many(struct list_head *head) */ call_netdevice_notifiers(NETDEV_UNREGISTER, dev); - if (!dev->rtnl_link_ops || - dev->rtnl_link_state == RTNL_LINK_INITIALIZED) - rtmsg_ifinfo(RTM_DELLINK, dev, ~0U, GFP_KERNEL); - /* * Flush the unicast and multicast chains */ @@ -5613,6 +5613,10 @@ static void rollback_registered_many(struct list_head *head) if (dev->netdev_ops->ndo_uninit) dev->netdev_ops->ndo_uninit(dev); + if (!dev->rtnl_link_ops || + dev->rtnl_link_state == RTNL_LINK_INITIALIZED) + rtmsg_ifinfo(RTM_DELLINK, dev, ~0U, GFP_KERNEL); + /* Notifier chain MUST detach us all upper devices. */ WARN_ON(netdev_has_any_upper_dev(dev)); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 640ba0e5831ce0..aa8978ac47d28b 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -557,6 +557,25 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, return ret; } +static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr, + struct ethtool_rxnfc *rx_rings, + u32 size) +{ + int ret = 0, i; + + if (copy_from_user(indir, useraddr, size * sizeof(indir[0]))) + ret = -EFAULT; + + /* Validate ring indices */ + for (i = 0; i < size; i++) { + if (indir[i] >= rx_rings->data) { + ret = -EINVAL; + break; + } + } + return ret; +} + static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, void __user *useraddr) { @@ -613,6 +632,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, u32 *indir; const struct ethtool_ops *ops = dev->ethtool_ops; int ret; + u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]); if (!ops->get_rxfh_indir_size || !ops->set_rxfh_indir || !ops->get_rxnfc) @@ -643,28 +663,196 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, for (i = 0; i < dev_size; i++) indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); } else { - if (copy_from_user(indir, - useraddr + - offsetof(struct ethtool_rxfh_indir, - ring_index[0]), - dev_size * sizeof(indir[0]))) { + ret = ethtool_copy_validate_indir(indir, + useraddr + ringidx_offset, + &rx_rings, + dev_size); + if (ret) + goto out; + } + + ret = ops->set_rxfh_indir(dev, indir); + +out: + kfree(indir); + return ret; +} + +static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev, + void __user *useraddr) +{ + int ret; + const struct ethtool_ops *ops = dev->ethtool_ops; + u32 user_indir_size = 0, user_key_size = 0; + u32 dev_indir_size = 0, dev_key_size = 0; + u32 total_size; + u32 indir_offset, indir_bytes; + u32 key_offset; + u32 *indir = NULL; + u8 *hkey = NULL; + u8 *rss_config; + + if (!(dev->ethtool_ops->get_rxfh_indir_size || + dev->ethtool_ops->get_rxfh_key_size) || + !dev->ethtool_ops->get_rxfh) + return -EOPNOTSUPP; + + if (ops->get_rxfh_indir_size) + dev_indir_size = ops->get_rxfh_indir_size(dev); + + indir_offset = offsetof(struct ethtool_rxfh, indir_size); + + if (copy_from_user(&user_indir_size, + useraddr + indir_offset, + sizeof(user_indir_size))) + return -EFAULT; + + if (copy_to_user(useraddr + indir_offset, + &dev_indir_size, sizeof(dev_indir_size))) + return -EFAULT; + + if (ops->get_rxfh_key_size) + dev_key_size = ops->get_rxfh_key_size(dev); + + if ((dev_key_size + dev_indir_size) == 0) + return -EOPNOTSUPP; + + key_offset = offsetof(struct ethtool_rxfh, key_size); + + if (copy_from_user(&user_key_size, + useraddr + key_offset, + sizeof(user_key_size))) + return -EFAULT; + + if (copy_to_user(useraddr + key_offset, + &dev_key_size, sizeof(dev_key_size))) + return -EFAULT; + + /* If the user buffer size is 0, this is just a query for the + * device table size and key size. Otherwise, if the User size is + * not equal to device table size or key size it's an error. + */ + if (!user_indir_size && !user_key_size) + return 0; + + if ((user_indir_size && (user_indir_size != dev_indir_size)) || + (user_key_size && (user_key_size != dev_key_size))) + return -EINVAL; + + indir_bytes = user_indir_size * sizeof(indir[0]); + total_size = indir_bytes + user_key_size; + rss_config = kzalloc(total_size, GFP_USER); + if (!rss_config) + return -ENOMEM; + + if (user_indir_size) + indir = (u32 *)rss_config; + + if (user_key_size) + hkey = rss_config + indir_bytes; + + ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey); + if (!ret) { + if (copy_to_user(useraddr + + offsetof(struct ethtool_rxfh, rss_config[0]), + rss_config, total_size)) ret = -EFAULT; + } + + kfree(rss_config); + + return ret; +} + +static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, + void __user *useraddr) +{ + int ret; + const struct ethtool_ops *ops = dev->ethtool_ops; + struct ethtool_rxnfc rx_rings; + u32 user_indir_size = 0, dev_indir_size = 0, i; + u32 user_key_size = 0, dev_key_size = 0; + u32 *indir = NULL, indir_bytes = 0; + u8 *hkey = NULL; + u8 *rss_config; + u32 indir_offset, key_offset; + u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]); + + if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) || + !ops->get_rxnfc || !ops->set_rxfh) + return -EOPNOTSUPP; + + if (ops->get_rxfh_indir_size) + dev_indir_size = ops->get_rxfh_indir_size(dev); + + indir_offset = offsetof(struct ethtool_rxfh, indir_size); + if (copy_from_user(&user_indir_size, + useraddr + indir_offset, + sizeof(user_indir_size))) + return -EFAULT; + + if (ops->get_rxfh_key_size) + dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev); + + if ((dev_key_size + dev_indir_size) == 0) + return -EOPNOTSUPP; + + key_offset = offsetof(struct ethtool_rxfh, key_size); + if (copy_from_user(&user_key_size, + useraddr + key_offset, + sizeof(user_key_size))) + return -EFAULT; + + /* If either indir or hash key is valid, proceed further. + */ + if ((user_indir_size && ((user_indir_size != 0xDEADBEEF) && + user_indir_size != dev_indir_size)) || + (user_key_size && (user_key_size != dev_key_size))) + return -EINVAL; + + if (user_indir_size != 0xDEADBEEF) + indir_bytes = dev_indir_size * sizeof(indir[0]); + + rss_config = kzalloc(indir_bytes + user_key_size, GFP_USER); + if (!rss_config) + return -ENOMEM; + + rx_rings.cmd = ETHTOOL_GRXRINGS; + ret = ops->get_rxnfc(dev, &rx_rings, NULL); + if (ret) + goto out; + + /* user_indir_size == 0 means reset the indir table to default. + * user_indir_size == 0xDEADBEEF means indir setting is not requested. + */ + if (user_indir_size && user_indir_size != 0xDEADBEEF) { + indir = (u32 *)rss_config; + ret = ethtool_copy_validate_indir(indir, + useraddr + rss_cfg_offset, + &rx_rings, + user_indir_size); + if (ret) goto out; - } + } else if (user_indir_size == 0) { + indir = (u32 *)rss_config; + for (i = 0; i < dev_indir_size; i++) + indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); + } - /* Validate ring indices */ - for (i = 0; i < dev_size; i++) { - if (indir[i] >= rx_rings.data) { - ret = -EINVAL; - goto out; - } + if (user_key_size) { + hkey = rss_config + indir_bytes; + if (copy_from_user(hkey, + useraddr + rss_cfg_offset + indir_bytes, + user_key_size)) { + ret = -EFAULT; + goto out; } } - ret = ops->set_rxfh_indir(dev, indir); + ret = ops->set_rxfh(dev, indir, hkey); out: - kfree(indir); + kfree(rss_config); return ret; } @@ -1491,6 +1679,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_GRXCLSRULE: case ETHTOOL_GRXCLSRLALL: case ETHTOOL_GRXFHINDIR: + case ETHTOOL_GRSSH: case ETHTOOL_GFEATURES: case ETHTOOL_GCHANNELS: case ETHTOOL_GET_TS_INFO: @@ -1628,6 +1817,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_SRXFHINDIR: rc = ethtool_set_rxfh_indir(dev, useraddr); break; + case ETHTOOL_GRSSH: + rc = ethtool_get_rxfh(dev, useraddr); + break; + case ETHTOOL_SRSSH: + rc = ethtool_set_rxfh(dev, useraddr); + break; case ETHTOOL_GFEATURES: rc = ethtool_get_features(dev, useraddr); break; diff --git a/net/core/filter.c b/net/core/filter.c index 9d79ca0a6e8e93..eb020a7d6f55f9 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -45,6 +45,27 @@ #include #include +/* Registers */ +#define R0 regs[BPF_REG_0] +#define R1 regs[BPF_REG_1] +#define R2 regs[BPF_REG_2] +#define R3 regs[BPF_REG_3] +#define R4 regs[BPF_REG_4] +#define R5 regs[BPF_REG_5] +#define R6 regs[BPF_REG_6] +#define R7 regs[BPF_REG_7] +#define R8 regs[BPF_REG_8] +#define R9 regs[BPF_REG_9] +#define R10 regs[BPF_REG_10] + +/* Named registers */ +#define A regs[insn->a_reg] +#define X regs[insn->x_reg] +#define FP regs[BPF_REG_FP] +#define ARG1 regs[BPF_REG_ARG1] +#define CTX regs[BPF_REG_CTX] +#define K insn->imm + /* No hurry in this branch * * Exported for the bpf jit load helper. @@ -57,9 +78,9 @@ void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, uns ptr = skb_network_header(skb) + k - SKF_NET_OFF; else if (k >= SKF_LL_OFF) ptr = skb_mac_header(skb) + k - SKF_LL_OFF; - if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb)) return ptr; + return NULL; } @@ -68,6 +89,7 @@ static inline void *load_pointer(const struct sk_buff *skb, int k, { if (k >= 0) return skb_header_pointer(skb, k, size, buffer); + return bpf_internal_load_pointer_neg_helper(skb, k, size); } @@ -122,13 +144,6 @@ noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) return 0; } -/* Register mappings for user programs. */ -#define A_REG 0 -#define X_REG 7 -#define TMP_REG 8 -#define ARG2_REG 2 -#define ARG3_REG 3 - /** * __sk_run_filter - run a filter on a given context * @ctx: buffer to run the filter on @@ -142,208 +157,204 @@ unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn) { u64 stack[MAX_BPF_STACK / sizeof(u64)]; u64 regs[MAX_BPF_REG], tmp; - void *ptr; - int off; - -#define K insn->imm -#define A regs[insn->a_reg] -#define X regs[insn->x_reg] -#define R0 regs[0] - -#define CONT ({insn++; goto select_insn; }) -#define CONT_JMP ({insn++; goto select_insn; }) - static const void *jumptable[256] = { [0 ... 255] = &&default_label, /* Now overwrite non-defaults ... */ -#define DL(A, B, C) [A|B|C] = &&A##_##B##_##C - DL(BPF_ALU, BPF_ADD, BPF_X), - DL(BPF_ALU, BPF_ADD, BPF_K), - DL(BPF_ALU, BPF_SUB, BPF_X), - DL(BPF_ALU, BPF_SUB, BPF_K), - DL(BPF_ALU, BPF_AND, BPF_X), - DL(BPF_ALU, BPF_AND, BPF_K), - DL(BPF_ALU, BPF_OR, BPF_X), - DL(BPF_ALU, BPF_OR, BPF_K), - DL(BPF_ALU, BPF_LSH, BPF_X), - DL(BPF_ALU, BPF_LSH, BPF_K), - DL(BPF_ALU, BPF_RSH, BPF_X), - DL(BPF_ALU, BPF_RSH, BPF_K), - DL(BPF_ALU, BPF_XOR, BPF_X), - DL(BPF_ALU, BPF_XOR, BPF_K), - DL(BPF_ALU, BPF_MUL, BPF_X), - DL(BPF_ALU, BPF_MUL, BPF_K), - DL(BPF_ALU, BPF_MOV, BPF_X), - DL(BPF_ALU, BPF_MOV, BPF_K), - DL(BPF_ALU, BPF_DIV, BPF_X), - DL(BPF_ALU, BPF_DIV, BPF_K), - DL(BPF_ALU, BPF_MOD, BPF_X), - DL(BPF_ALU, BPF_MOD, BPF_K), - DL(BPF_ALU, BPF_NEG, 0), - DL(BPF_ALU, BPF_END, BPF_TO_BE), - DL(BPF_ALU, BPF_END, BPF_TO_LE), - DL(BPF_ALU64, BPF_ADD, BPF_X), - DL(BPF_ALU64, BPF_ADD, BPF_K), - DL(BPF_ALU64, BPF_SUB, BPF_X), - DL(BPF_ALU64, BPF_SUB, BPF_K), - DL(BPF_ALU64, BPF_AND, BPF_X), - DL(BPF_ALU64, BPF_AND, BPF_K), - DL(BPF_ALU64, BPF_OR, BPF_X), - DL(BPF_ALU64, BPF_OR, BPF_K), - DL(BPF_ALU64, BPF_LSH, BPF_X), - DL(BPF_ALU64, BPF_LSH, BPF_K), - DL(BPF_ALU64, BPF_RSH, BPF_X), - DL(BPF_ALU64, BPF_RSH, BPF_K), - DL(BPF_ALU64, BPF_XOR, BPF_X), - DL(BPF_ALU64, BPF_XOR, BPF_K), - DL(BPF_ALU64, BPF_MUL, BPF_X), - DL(BPF_ALU64, BPF_MUL, BPF_K), - DL(BPF_ALU64, BPF_MOV, BPF_X), - DL(BPF_ALU64, BPF_MOV, BPF_K), - DL(BPF_ALU64, BPF_ARSH, BPF_X), - DL(BPF_ALU64, BPF_ARSH, BPF_K), - DL(BPF_ALU64, BPF_DIV, BPF_X), - DL(BPF_ALU64, BPF_DIV, BPF_K), - DL(BPF_ALU64, BPF_MOD, BPF_X), - DL(BPF_ALU64, BPF_MOD, BPF_K), - DL(BPF_ALU64, BPF_NEG, 0), - DL(BPF_JMP, BPF_CALL, 0), - DL(BPF_JMP, BPF_JA, 0), - DL(BPF_JMP, BPF_JEQ, BPF_X), - DL(BPF_JMP, BPF_JEQ, BPF_K), - DL(BPF_JMP, BPF_JNE, BPF_X), - DL(BPF_JMP, BPF_JNE, BPF_K), - DL(BPF_JMP, BPF_JGT, BPF_X), - DL(BPF_JMP, BPF_JGT, BPF_K), - DL(BPF_JMP, BPF_JGE, BPF_X), - DL(BPF_JMP, BPF_JGE, BPF_K), - DL(BPF_JMP, BPF_JSGT, BPF_X), - DL(BPF_JMP, BPF_JSGT, BPF_K), - DL(BPF_JMP, BPF_JSGE, BPF_X), - DL(BPF_JMP, BPF_JSGE, BPF_K), - DL(BPF_JMP, BPF_JSET, BPF_X), - DL(BPF_JMP, BPF_JSET, BPF_K), - DL(BPF_JMP, BPF_EXIT, 0), - DL(BPF_STX, BPF_MEM, BPF_B), - DL(BPF_STX, BPF_MEM, BPF_H), - DL(BPF_STX, BPF_MEM, BPF_W), - DL(BPF_STX, BPF_MEM, BPF_DW), - DL(BPF_STX, BPF_XADD, BPF_W), - DL(BPF_STX, BPF_XADD, BPF_DW), - DL(BPF_ST, BPF_MEM, BPF_B), - DL(BPF_ST, BPF_MEM, BPF_H), - DL(BPF_ST, BPF_MEM, BPF_W), - DL(BPF_ST, BPF_MEM, BPF_DW), - DL(BPF_LDX, BPF_MEM, BPF_B), - DL(BPF_LDX, BPF_MEM, BPF_H), - DL(BPF_LDX, BPF_MEM, BPF_W), - DL(BPF_LDX, BPF_MEM, BPF_DW), - DL(BPF_LD, BPF_ABS, BPF_W), - DL(BPF_LD, BPF_ABS, BPF_H), - DL(BPF_LD, BPF_ABS, BPF_B), - DL(BPF_LD, BPF_IND, BPF_W), - DL(BPF_LD, BPF_IND, BPF_H), - DL(BPF_LD, BPF_IND, BPF_B), +#define DL(A, B, C) [BPF_##A|BPF_##B|BPF_##C] = &&A##_##B##_##C + DL(ALU, ADD, X), + DL(ALU, ADD, K), + DL(ALU, SUB, X), + DL(ALU, SUB, K), + DL(ALU, AND, X), + DL(ALU, AND, K), + DL(ALU, OR, X), + DL(ALU, OR, K), + DL(ALU, LSH, X), + DL(ALU, LSH, K), + DL(ALU, RSH, X), + DL(ALU, RSH, K), + DL(ALU, XOR, X), + DL(ALU, XOR, K), + DL(ALU, MUL, X), + DL(ALU, MUL, K), + DL(ALU, MOV, X), + DL(ALU, MOV, K), + DL(ALU, DIV, X), + DL(ALU, DIV, K), + DL(ALU, MOD, X), + DL(ALU, MOD, K), + DL(ALU, NEG, 0), + DL(ALU, END, TO_BE), + DL(ALU, END, TO_LE), + DL(ALU64, ADD, X), + DL(ALU64, ADD, K), + DL(ALU64, SUB, X), + DL(ALU64, SUB, K), + DL(ALU64, AND, X), + DL(ALU64, AND, K), + DL(ALU64, OR, X), + DL(ALU64, OR, K), + DL(ALU64, LSH, X), + DL(ALU64, LSH, K), + DL(ALU64, RSH, X), + DL(ALU64, RSH, K), + DL(ALU64, XOR, X), + DL(ALU64, XOR, K), + DL(ALU64, MUL, X), + DL(ALU64, MUL, K), + DL(ALU64, MOV, X), + DL(ALU64, MOV, K), + DL(ALU64, ARSH, X), + DL(ALU64, ARSH, K), + DL(ALU64, DIV, X), + DL(ALU64, DIV, K), + DL(ALU64, MOD, X), + DL(ALU64, MOD, K), + DL(ALU64, NEG, 0), + DL(JMP, CALL, 0), + DL(JMP, JA, 0), + DL(JMP, JEQ, X), + DL(JMP, JEQ, K), + DL(JMP, JNE, X), + DL(JMP, JNE, K), + DL(JMP, JGT, X), + DL(JMP, JGT, K), + DL(JMP, JGE, X), + DL(JMP, JGE, K), + DL(JMP, JSGT, X), + DL(JMP, JSGT, K), + DL(JMP, JSGE, X), + DL(JMP, JSGE, K), + DL(JMP, JSET, X), + DL(JMP, JSET, K), + DL(JMP, EXIT, 0), + DL(STX, MEM, B), + DL(STX, MEM, H), + DL(STX, MEM, W), + DL(STX, MEM, DW), + DL(STX, XADD, W), + DL(STX, XADD, DW), + DL(ST, MEM, B), + DL(ST, MEM, H), + DL(ST, MEM, W), + DL(ST, MEM, DW), + DL(LDX, MEM, B), + DL(LDX, MEM, H), + DL(LDX, MEM, W), + DL(LDX, MEM, DW), + DL(LD, ABS, W), + DL(LD, ABS, H), + DL(LD, ABS, B), + DL(LD, IND, W), + DL(LD, IND, H), + DL(LD, IND, B), #undef DL }; + void *ptr; + int off; + +#define CONT ({ insn++; goto select_insn; }) +#define CONT_JMP ({ insn++; goto select_insn; }) - regs[FP_REG] = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; - regs[ARG1_REG] = (u64) (unsigned long) ctx; - regs[A_REG] = 0; - regs[X_REG] = 0; + FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; + ARG1 = (u64) (unsigned long) ctx; + + /* Register for user BPF programs need to be reset first. */ + regs[BPF_REG_A] = 0; + regs[BPF_REG_X] = 0; select_insn: goto *jumptable[insn->code]; /* ALU */ #define ALU(OPCODE, OP) \ - BPF_ALU64_##OPCODE##_BPF_X: \ + ALU64_##OPCODE##_X: \ A = A OP X; \ CONT; \ - BPF_ALU_##OPCODE##_BPF_X: \ + ALU_##OPCODE##_X: \ A = (u32) A OP (u32) X; \ CONT; \ - BPF_ALU64_##OPCODE##_BPF_K: \ + ALU64_##OPCODE##_K: \ A = A OP K; \ CONT; \ - BPF_ALU_##OPCODE##_BPF_K: \ + ALU_##OPCODE##_K: \ A = (u32) A OP (u32) K; \ CONT; - ALU(BPF_ADD, +) - ALU(BPF_SUB, -) - ALU(BPF_AND, &) - ALU(BPF_OR, |) - ALU(BPF_LSH, <<) - ALU(BPF_RSH, >>) - ALU(BPF_XOR, ^) - ALU(BPF_MUL, *) + ALU(ADD, +) + ALU(SUB, -) + ALU(AND, &) + ALU(OR, |) + ALU(LSH, <<) + ALU(RSH, >>) + ALU(XOR, ^) + ALU(MUL, *) #undef ALU - BPF_ALU_BPF_NEG_0: + ALU_NEG_0: A = (u32) -A; CONT; - BPF_ALU64_BPF_NEG_0: + ALU64_NEG_0: A = -A; CONT; - BPF_ALU_BPF_MOV_BPF_X: + ALU_MOV_X: A = (u32) X; CONT; - BPF_ALU_BPF_MOV_BPF_K: + ALU_MOV_K: A = (u32) K; CONT; - BPF_ALU64_BPF_MOV_BPF_X: + ALU64_MOV_X: A = X; CONT; - BPF_ALU64_BPF_MOV_BPF_K: + ALU64_MOV_K: A = K; CONT; - BPF_ALU64_BPF_ARSH_BPF_X: + ALU64_ARSH_X: (*(s64 *) &A) >>= X; CONT; - BPF_ALU64_BPF_ARSH_BPF_K: + ALU64_ARSH_K: (*(s64 *) &A) >>= K; CONT; - BPF_ALU64_BPF_MOD_BPF_X: + ALU64_MOD_X: if (unlikely(X == 0)) return 0; tmp = A; A = do_div(tmp, X); CONT; - BPF_ALU_BPF_MOD_BPF_X: + ALU_MOD_X: if (unlikely(X == 0)) return 0; tmp = (u32) A; A = do_div(tmp, (u32) X); CONT; - BPF_ALU64_BPF_MOD_BPF_K: + ALU64_MOD_K: tmp = A; A = do_div(tmp, K); CONT; - BPF_ALU_BPF_MOD_BPF_K: + ALU_MOD_K: tmp = (u32) A; A = do_div(tmp, (u32) K); CONT; - BPF_ALU64_BPF_DIV_BPF_X: + ALU64_DIV_X: if (unlikely(X == 0)) return 0; do_div(A, X); CONT; - BPF_ALU_BPF_DIV_BPF_X: + ALU_DIV_X: if (unlikely(X == 0)) return 0; tmp = (u32) A; do_div(tmp, (u32) X); A = (u32) tmp; CONT; - BPF_ALU64_BPF_DIV_BPF_K: + ALU64_DIV_K: do_div(A, K); CONT; - BPF_ALU_BPF_DIV_BPF_K: + ALU_DIV_K: tmp = (u32) A; do_div(tmp, (u32) K); A = (u32) tmp; CONT; - BPF_ALU_BPF_END_BPF_TO_BE: + ALU_END_TO_BE: switch (K) { case 16: A = (__force u16) cpu_to_be16(A); @@ -356,7 +367,7 @@ unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn) break; } CONT; - BPF_ALU_BPF_END_BPF_TO_LE: + ALU_END_TO_LE: switch (K) { case 16: A = (__force u16) cpu_to_le16(A); @@ -371,136 +382,135 @@ unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn) CONT; /* CALL */ - BPF_JMP_BPF_CALL_0: + JMP_CALL_0: /* Function call scratches R1-R5 registers, preserves R6-R9, * and stores return value into R0. */ - R0 = (__bpf_call_base + insn->imm)(regs[1], regs[2], regs[3], - regs[4], regs[5]); + R0 = (__bpf_call_base + insn->imm)(R1, R2, R3, R4, R5); CONT; /* JMP */ - BPF_JMP_BPF_JA_0: + JMP_JA_0: insn += insn->off; CONT; - BPF_JMP_BPF_JEQ_BPF_X: + JMP_JEQ_X: if (A == X) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JEQ_BPF_K: + JMP_JEQ_K: if (A == K) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JNE_BPF_X: + JMP_JNE_X: if (A != X) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JNE_BPF_K: + JMP_JNE_K: if (A != K) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JGT_BPF_X: + JMP_JGT_X: if (A > X) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JGT_BPF_K: + JMP_JGT_K: if (A > K) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JGE_BPF_X: + JMP_JGE_X: if (A >= X) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JGE_BPF_K: + JMP_JGE_K: if (A >= K) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JSGT_BPF_X: - if (((s64)A) > ((s64)X)) { + JMP_JSGT_X: + if (((s64) A) > ((s64) X)) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JSGT_BPF_K: - if (((s64)A) > ((s64)K)) { + JMP_JSGT_K: + if (((s64) A) > ((s64) K)) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JSGE_BPF_X: - if (((s64)A) >= ((s64)X)) { + JMP_JSGE_X: + if (((s64) A) >= ((s64) X)) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JSGE_BPF_K: - if (((s64)A) >= ((s64)K)) { + JMP_JSGE_K: + if (((s64) A) >= ((s64) K)) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JSET_BPF_X: + JMP_JSET_X: if (A & X) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_JSET_BPF_K: + JMP_JSET_K: if (A & K) { insn += insn->off; CONT_JMP; } CONT; - BPF_JMP_BPF_EXIT_0: + JMP_EXIT_0: return R0; /* STX and ST and LDX*/ #define LDST(SIZEOP, SIZE) \ - BPF_STX_BPF_MEM_##SIZEOP: \ + STX_MEM_##SIZEOP: \ *(SIZE *)(unsigned long) (A + insn->off) = X; \ CONT; \ - BPF_ST_BPF_MEM_##SIZEOP: \ + ST_MEM_##SIZEOP: \ *(SIZE *)(unsigned long) (A + insn->off) = K; \ CONT; \ - BPF_LDX_BPF_MEM_##SIZEOP: \ + LDX_MEM_##SIZEOP: \ A = *(SIZE *)(unsigned long) (X + insn->off); \ CONT; - LDST(BPF_B, u8) - LDST(BPF_H, u16) - LDST(BPF_W, u32) - LDST(BPF_DW, u64) + LDST(B, u8) + LDST(H, u16) + LDST(W, u32) + LDST(DW, u64) #undef LDST - BPF_STX_BPF_XADD_BPF_W: /* lock xadd *(u32 *)(A + insn->off) += X */ + STX_XADD_W: /* lock xadd *(u32 *)(A + insn->off) += X */ atomic_add((u32) X, (atomic_t *)(unsigned long) (A + insn->off)); CONT; - BPF_STX_BPF_XADD_BPF_DW: /* lock xadd *(u64 *)(A + insn->off) += X */ + STX_XADD_DW: /* lock xadd *(u64 *)(A + insn->off) += X */ atomic64_add((u64) X, (atomic64_t *)(unsigned long) (A + insn->off)); CONT; - BPF_LD_BPF_ABS_BPF_W: /* R0 = ntohl(*(u32 *) (skb->data + K)) */ + LD_ABS_W: /* R0 = ntohl(*(u32 *) (skb->data + K)) */ off = K; load_word: /* BPF_LD + BPD_ABS and BPF_LD + BPF_IND insns are only * appearing in the programs where ctx == skb. All programs - * keep 'ctx' in regs[CTX_REG] == R6, sk_convert_filter() + * keep 'ctx' in regs[BPF_REG_CTX] == R6, sk_convert_filter() * saves it in R6, internal BPF verifier will check that * R6 == ctx. * @@ -524,7 +534,7 @@ unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn) CONT; } return 0; - BPF_LD_BPF_ABS_BPF_H: /* R0 = ntohs(*(u16 *) (skb->data + K)) */ + LD_ABS_H: /* R0 = ntohs(*(u16 *) (skb->data + K)) */ off = K; load_half: ptr = load_pointer((struct sk_buff *) ctx, off, 2, &tmp); @@ -533,7 +543,7 @@ unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn) CONT; } return 0; - BPF_LD_BPF_ABS_BPF_B: /* R0 = *(u8 *) (ctx + K) */ + LD_ABS_B: /* R0 = *(u8 *) (ctx + K) */ off = K; load_byte: ptr = load_pointer((struct sk_buff *) ctx, off, 1, &tmp); @@ -542,13 +552,13 @@ unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn) CONT; } return 0; - BPF_LD_BPF_IND_BPF_W: /* R0 = ntohl(*(u32 *) (skb->data + X + K)) */ + LD_IND_W: /* R0 = ntohl(*(u32 *) (skb->data + X + K)) */ off = K + X; goto load_word; - BPF_LD_BPF_IND_BPF_H: /* R0 = ntohs(*(u16 *) (skb->data + X + K)) */ + LD_IND_H: /* R0 = ntohs(*(u16 *) (skb->data + X + K)) */ off = K + X; goto load_half; - BPF_LD_BPF_IND_BPF_B: /* R0 = *(u8 *) (skb->data + X + K) */ + LD_IND_B: /* R0 = *(u8 *) (skb->data + X + K) */ off = K + X; goto load_byte; @@ -556,13 +566,6 @@ unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn) /* If we ever reach this, we have a bug somewhere. */ WARN_RATELIMIT(1, "unknown opcode %02x\n", insn->code); return 0; -#undef CONT_JMP -#undef CONT - -#undef R0 -#undef X -#undef A -#undef K } u32 sk_run_filter_int_seccomp(const struct seccomp_data *ctx, @@ -594,16 +597,14 @@ static unsigned int pkt_type_offset(void) return -1; } -static u64 __skb_get_pay_offset(u64 ctx, u64 A, u64 X, u64 r4, u64 r5) +static u64 __skb_get_pay_offset(u64 ctx, u64 a, u64 x, u64 r4, u64 r5) { - struct sk_buff *skb = (struct sk_buff *)(long) ctx; - - return __skb_get_poff(skb); + return __skb_get_poff((struct sk_buff *)(unsigned long) ctx); } -static u64 __skb_get_nlattr(u64 ctx, u64 A, u64 X, u64 r4, u64 r5) +static u64 __skb_get_nlattr(u64 ctx, u64 a, u64 x, u64 r4, u64 r5) { - struct sk_buff *skb = (struct sk_buff *)(long) ctx; + struct sk_buff *skb = (struct sk_buff *)(unsigned long) ctx; struct nlattr *nla; if (skb_is_nonlinear(skb)) @@ -612,19 +613,19 @@ static u64 __skb_get_nlattr(u64 ctx, u64 A, u64 X, u64 r4, u64 r5) if (skb->len < sizeof(struct nlattr)) return 0; - if (A > skb->len - sizeof(struct nlattr)) + if (a > skb->len - sizeof(struct nlattr)) return 0; - nla = nla_find((struct nlattr *) &skb->data[A], skb->len - A, X); + nla = nla_find((struct nlattr *) &skb->data[a], skb->len - a, x); if (nla) return (void *) nla - (void *) skb->data; return 0; } -static u64 __skb_get_nlattr_nest(u64 ctx, u64 A, u64 X, u64 r4, u64 r5) +static u64 __skb_get_nlattr_nest(u64 ctx, u64 a, u64 x, u64 r4, u64 r5) { - struct sk_buff *skb = (struct sk_buff *)(long) ctx; + struct sk_buff *skb = (struct sk_buff *)(unsigned long) ctx; struct nlattr *nla; if (skb_is_nonlinear(skb)) @@ -633,25 +634,31 @@ static u64 __skb_get_nlattr_nest(u64 ctx, u64 A, u64 X, u64 r4, u64 r5) if (skb->len < sizeof(struct nlattr)) return 0; - if (A > skb->len - sizeof(struct nlattr)) + if (a > skb->len - sizeof(struct nlattr)) return 0; - nla = (struct nlattr *) &skb->data[A]; - if (nla->nla_len > skb->len - A) + nla = (struct nlattr *) &skb->data[a]; + if (nla->nla_len > skb->len - a) return 0; - nla = nla_find_nested(nla, X); + nla = nla_find_nested(nla, x); if (nla) return (void *) nla - (void *) skb->data; return 0; } -static u64 __get_raw_cpu_id(u64 ctx, u64 A, u64 X, u64 r4, u64 r5) +static u64 __get_raw_cpu_id(u64 ctx, u64 a, u64 x, u64 r4, u64 r5) { return raw_smp_processor_id(); } +/* note that this only generates 32-bit random numbers */ +static u64 __get_random_u32(u64 ctx, u64 a, u64 x, u64 r4, u64 r5) +{ + return prandom_u32(); +} + static bool convert_bpf_extensions(struct sock_filter *fp, struct sock_filter_int **insnp) { @@ -662,28 +669,28 @@ static bool convert_bpf_extensions(struct sock_filter *fp, BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2); insn->code = BPF_LDX | BPF_MEM | BPF_H; - insn->a_reg = A_REG; - insn->x_reg = CTX_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_CTX; insn->off = offsetof(struct sk_buff, protocol); insn++; /* A = ntohs(A) [emitting a nop or swap16] */ insn->code = BPF_ALU | BPF_END | BPF_FROM_BE; - insn->a_reg = A_REG; + insn->a_reg = BPF_REG_A; insn->imm = 16; break; case SKF_AD_OFF + SKF_AD_PKTTYPE: insn->code = BPF_LDX | BPF_MEM | BPF_B; - insn->a_reg = A_REG; - insn->x_reg = CTX_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_CTX; insn->off = pkt_type_offset(); if (insn->off < 0) return false; insn++; insn->code = BPF_ALU | BPF_AND | BPF_K; - insn->a_reg = A_REG; + insn->a_reg = BPF_REG_A; insn->imm = PKT_TYPE_MAX; break; @@ -693,13 +700,13 @@ static bool convert_bpf_extensions(struct sock_filter *fp, insn->code = BPF_LDX | BPF_MEM | BPF_DW; else insn->code = BPF_LDX | BPF_MEM | BPF_W; - insn->a_reg = TMP_REG; - insn->x_reg = CTX_REG; + insn->a_reg = BPF_REG_TMP; + insn->x_reg = BPF_REG_CTX; insn->off = offsetof(struct sk_buff, dev); insn++; insn->code = BPF_JMP | BPF_JNE | BPF_K; - insn->a_reg = TMP_REG; + insn->a_reg = BPF_REG_TMP; insn->imm = 0; insn->off = 1; insn++; @@ -710,8 +717,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp, BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4); BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, type) != 2); - insn->a_reg = A_REG; - insn->x_reg = TMP_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_TMP; if (fp->k == SKF_AD_OFF + SKF_AD_IFINDEX) { insn->code = BPF_LDX | BPF_MEM | BPF_W; @@ -726,8 +733,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp, BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4); insn->code = BPF_LDX | BPF_MEM | BPF_W; - insn->a_reg = A_REG; - insn->x_reg = CTX_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_CTX; insn->off = offsetof(struct sk_buff, mark); break; @@ -735,8 +742,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp, BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4); insn->code = BPF_LDX | BPF_MEM | BPF_W; - insn->a_reg = A_REG; - insn->x_reg = CTX_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_CTX; insn->off = offsetof(struct sk_buff, hash); break; @@ -744,8 +751,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp, BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2); insn->code = BPF_LDX | BPF_MEM | BPF_H; - insn->a_reg = A_REG; - insn->x_reg = CTX_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_CTX; insn->off = offsetof(struct sk_buff, queue_mapping); break; @@ -754,8 +761,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp, BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2); insn->code = BPF_LDX | BPF_MEM | BPF_H; - insn->a_reg = A_REG; - insn->x_reg = CTX_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_CTX; insn->off = offsetof(struct sk_buff, vlan_tci); insn++; @@ -763,16 +770,16 @@ static bool convert_bpf_extensions(struct sock_filter *fp, if (fp->k == SKF_AD_OFF + SKF_AD_VLAN_TAG) { insn->code = BPF_ALU | BPF_AND | BPF_K; - insn->a_reg = A_REG; + insn->a_reg = BPF_REG_A; insn->imm = ~VLAN_TAG_PRESENT; } else { insn->code = BPF_ALU | BPF_RSH | BPF_K; - insn->a_reg = A_REG; + insn->a_reg = BPF_REG_A; insn->imm = 12; insn++; insn->code = BPF_ALU | BPF_AND | BPF_K; - insn->a_reg = A_REG; + insn->a_reg = BPF_REG_A; insn->imm = 1; } break; @@ -781,22 +788,23 @@ static bool convert_bpf_extensions(struct sock_filter *fp, case SKF_AD_OFF + SKF_AD_NLATTR: case SKF_AD_OFF + SKF_AD_NLATTR_NEST: case SKF_AD_OFF + SKF_AD_CPU: + case SKF_AD_OFF + SKF_AD_RANDOM: /* arg1 = ctx */ insn->code = BPF_ALU64 | BPF_MOV | BPF_X; - insn->a_reg = ARG1_REG; - insn->x_reg = CTX_REG; + insn->a_reg = BPF_REG_ARG1; + insn->x_reg = BPF_REG_CTX; insn++; /* arg2 = A */ insn->code = BPF_ALU64 | BPF_MOV | BPF_X; - insn->a_reg = ARG2_REG; - insn->x_reg = A_REG; + insn->a_reg = BPF_REG_ARG2; + insn->x_reg = BPF_REG_A; insn++; /* arg3 = X */ insn->code = BPF_ALU64 | BPF_MOV | BPF_X; - insn->a_reg = ARG3_REG; - insn->x_reg = X_REG; + insn->a_reg = BPF_REG_ARG3; + insn->x_reg = BPF_REG_X; insn++; /* Emit call(ctx, arg2=A, arg3=X) */ @@ -814,13 +822,16 @@ static bool convert_bpf_extensions(struct sock_filter *fp, case SKF_AD_OFF + SKF_AD_CPU: insn->imm = __get_raw_cpu_id - __bpf_call_base; break; + case SKF_AD_OFF + SKF_AD_RANDOM: + insn->imm = __get_random_u32 - __bpf_call_base; + break; } break; case SKF_AD_OFF + SKF_AD_ALU_XOR_X: insn->code = BPF_ALU | BPF_XOR | BPF_X; - insn->a_reg = A_REG; - insn->x_reg = X_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_X; break; default: @@ -870,7 +881,7 @@ int sk_convert_filter(struct sock_filter *prog, int len, u8 bpf_src; BUILD_BUG_ON(BPF_MEMWORDS * sizeof(u32) > MAX_BPF_STACK); - BUILD_BUG_ON(FP_REG + 1 != MAX_BPF_REG); + BUILD_BUG_ON(BPF_REG_FP + 1 != MAX_BPF_REG); if (len <= 0 || len >= BPF_MAXINSNS) return -EINVAL; @@ -887,8 +898,8 @@ int sk_convert_filter(struct sock_filter *prog, int len, if (new_insn) { new_insn->code = BPF_ALU64 | BPF_MOV | BPF_X; - new_insn->a_reg = CTX_REG; - new_insn->x_reg = ARG1_REG; + new_insn->a_reg = BPF_REG_CTX; + new_insn->x_reg = BPF_REG_ARG1; } new_insn++; @@ -938,8 +949,8 @@ int sk_convert_filter(struct sock_filter *prog, int len, break; insn->code = fp->code; - insn->a_reg = A_REG; - insn->x_reg = X_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_X; insn->imm = fp->k; break; @@ -973,16 +984,16 @@ int sk_convert_filter(struct sock_filter *prog, int len, * in compare insn. */ insn->code = BPF_ALU | BPF_MOV | BPF_K; - insn->a_reg = TMP_REG; + insn->a_reg = BPF_REG_TMP; insn->imm = fp->k; insn++; - insn->a_reg = A_REG; - insn->x_reg = TMP_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_TMP; bpf_src = BPF_X; } else { - insn->a_reg = A_REG; - insn->x_reg = X_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_X; insn->imm = fp->k; bpf_src = BPF_SRC(fp->code); } @@ -1017,33 +1028,33 @@ int sk_convert_filter(struct sock_filter *prog, int len, /* ldxb 4 * ([14] & 0xf) is remaped into 6 insns. */ case BPF_LDX | BPF_MSH | BPF_B: insn->code = BPF_ALU64 | BPF_MOV | BPF_X; - insn->a_reg = TMP_REG; - insn->x_reg = A_REG; + insn->a_reg = BPF_REG_TMP; + insn->x_reg = BPF_REG_A; insn++; insn->code = BPF_LD | BPF_ABS | BPF_B; - insn->a_reg = A_REG; + insn->a_reg = BPF_REG_A; insn->imm = fp->k; insn++; insn->code = BPF_ALU | BPF_AND | BPF_K; - insn->a_reg = A_REG; + insn->a_reg = BPF_REG_A; insn->imm = 0xf; insn++; insn->code = BPF_ALU | BPF_LSH | BPF_K; - insn->a_reg = A_REG; + insn->a_reg = BPF_REG_A; insn->imm = 2; insn++; insn->code = BPF_ALU64 | BPF_MOV | BPF_X; - insn->a_reg = X_REG; - insn->x_reg = A_REG; + insn->a_reg = BPF_REG_X; + insn->x_reg = BPF_REG_A; insn++; insn->code = BPF_ALU64 | BPF_MOV | BPF_X; - insn->a_reg = A_REG; - insn->x_reg = TMP_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_TMP; break; /* RET_K, RET_A are remaped into 2 insns. */ @@ -1053,7 +1064,7 @@ int sk_convert_filter(struct sock_filter *prog, int len, (BPF_RVAL(fp->code) == BPF_K ? BPF_K : BPF_X); insn->a_reg = 0; - insn->x_reg = A_REG; + insn->x_reg = BPF_REG_A; insn->imm = fp->k; insn++; @@ -1064,8 +1075,9 @@ int sk_convert_filter(struct sock_filter *prog, int len, case BPF_ST: case BPF_STX: insn->code = BPF_STX | BPF_MEM | BPF_W; - insn->a_reg = FP_REG; - insn->x_reg = fp->code == BPF_ST ? A_REG : X_REG; + insn->a_reg = BPF_REG_FP; + insn->x_reg = fp->code == BPF_ST ? + BPF_REG_A : BPF_REG_X; insn->off = -(BPF_MEMWORDS - fp->k) * 4; break; @@ -1074,8 +1086,8 @@ int sk_convert_filter(struct sock_filter *prog, int len, case BPF_LDX | BPF_MEM: insn->code = BPF_LDX | BPF_MEM | BPF_W; insn->a_reg = BPF_CLASS(fp->code) == BPF_LD ? - A_REG : X_REG; - insn->x_reg = FP_REG; + BPF_REG_A : BPF_REG_X; + insn->x_reg = BPF_REG_FP; insn->off = -(BPF_MEMWORDS - fp->k) * 4; break; @@ -1084,22 +1096,22 @@ int sk_convert_filter(struct sock_filter *prog, int len, case BPF_LDX | BPF_IMM: insn->code = BPF_ALU | BPF_MOV | BPF_K; insn->a_reg = BPF_CLASS(fp->code) == BPF_LD ? - A_REG : X_REG; + BPF_REG_A : BPF_REG_X; insn->imm = fp->k; break; /* X = A */ case BPF_MISC | BPF_TAX: insn->code = BPF_ALU64 | BPF_MOV | BPF_X; - insn->a_reg = X_REG; - insn->x_reg = A_REG; + insn->a_reg = BPF_REG_X; + insn->x_reg = BPF_REG_A; break; /* A = X */ case BPF_MISC | BPF_TXA: insn->code = BPF_ALU64 | BPF_MOV | BPF_X; - insn->a_reg = A_REG; - insn->x_reg = X_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_X; break; /* A = skb->len or X = skb->len */ @@ -1107,16 +1119,16 @@ int sk_convert_filter(struct sock_filter *prog, int len, case BPF_LDX | BPF_W | BPF_LEN: insn->code = BPF_LDX | BPF_MEM | BPF_W; insn->a_reg = BPF_CLASS(fp->code) == BPF_LD ? - A_REG : X_REG; - insn->x_reg = CTX_REG; + BPF_REG_A : BPF_REG_X; + insn->x_reg = BPF_REG_CTX; insn->off = offsetof(struct sk_buff, len); break; /* access seccomp_data fields */ case BPF_LDX | BPF_ABS | BPF_W: insn->code = BPF_LDX | BPF_MEM | BPF_W; - insn->a_reg = A_REG; - insn->x_reg = CTX_REG; + insn->a_reg = BPF_REG_A; + insn->x_reg = BPF_REG_CTX; insn->off = fp->k; break; @@ -1364,6 +1376,7 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen) ANCILLARY(VLAN_TAG); ANCILLARY(VLAN_TAG_PRESENT); ANCILLARY(PAY_OFFSET); + ANCILLARY(RANDOM); } /* ancillary operation unknown or unsupported */ @@ -1461,7 +1474,7 @@ static struct sk_filter *__sk_migrate_realloc(struct sk_filter *fp, fp_new = sock_kmalloc(sk, len, GFP_KERNEL); if (fp_new) { - memcpy(fp_new, fp, sizeof(struct sk_filter)); + *fp_new = *fp; /* As we're kepping orig_prog in fp_new along, * we need to make sure we're not evicting it * from the old fp. @@ -1748,6 +1761,7 @@ void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to) [BPF_S_ANC_VLAN_TAG] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_VLAN_TAG_PRESENT] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_PAY_OFFSET] = BPF_LD|BPF_B|BPF_ABS, + [BPF_S_ANC_RANDOM] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_LD_W_LEN] = BPF_LD|BPF_W|BPF_LEN, [BPF_S_LD_W_IND] = BPF_LD|BPF_W|BPF_IND, [BPF_S_LD_H_IND] = BPF_LD|BPF_H|BPF_IND, diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 9c3a839322bacc..bd0767e6b2b317 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -147,7 +147,7 @@ static void linkwatch_do_dev(struct net_device *dev) * Make sure the above read is complete since it can be * rewritten as soon as we clear the bit below. */ - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); /* We are about to handle this device, * so new events can be accepted diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 81d3a9a0845365..05e949d482049b 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -273,7 +273,7 @@ static void cleanup_net(struct work_struct *work) { const struct pernet_operations *ops; struct net *net, *tmp; - LIST_HEAD(net_kill_list); + struct list_head net_kill_list; LIST_HEAD(net_exit_list); /* Atomically snapshot the list of namespaces to cleanup */ diff --git a/net/dccp/proto.c b/net/dccp/proto.c index eb892b4f481449..de2c1e7193057d 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -1084,14 +1084,15 @@ EXPORT_SYMBOL_GPL(dccp_shutdown); static inline int dccp_mib_init(void) { - return snmp_mib_init((void __percpu **)dccp_statistics, - sizeof(struct dccp_mib), - __alignof__(struct dccp_mib)); + dccp_statistics = alloc_percpu(struct dccp_mib); + if (!dccp_statistics) + return -ENOMEM; + return 0; } static inline void dccp_mib_exit(void) { - snmp_mib_free((void __percpu **)dccp_statistics); + free_percpu(dccp_statistics); } static int thash_entries; diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index ef2d54372b1343..6f1428c4870b11 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -36,7 +36,7 @@ struct lowpan_frag_info { u8 d_offset; }; -struct lowpan_frag_info *lowpan_cb(struct sk_buff *skb) +static struct lowpan_frag_info *lowpan_cb(struct sk_buff *skb) { return (struct lowpan_frag_info *)skb->cb; } @@ -120,6 +120,8 @@ fq_find(struct net *net, const struct lowpan_frag_info *frag_info, struct inet_frag_queue *q; struct lowpan_create_arg arg; unsigned int hash; + struct netns_ieee802154_lowpan *ieee802154_lowpan = + net_ieee802154_lowpan(net); arg.tag = frag_info->d_tag; arg.d_size = frag_info->d_size; @@ -129,7 +131,7 @@ fq_find(struct net *net, const struct lowpan_frag_info *frag_info, read_lock(&lowpan_frags.lock); hash = lowpan_hash_frag(frag_info->d_tag, frag_info->d_size, src, dst); - q = inet_frag_find(&net->ieee802154_lowpan.frags, + q = inet_frag_find(&ieee802154_lowpan->frags, &lowpan_frags, &arg, hash); if (IS_ERR_OR_NULL(q)) { inet_frag_maybe_warn_overflow(q, pr_fmt()); @@ -357,6 +359,8 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type) struct net *net = dev_net(skb->dev); struct lowpan_frag_info *frag_info = lowpan_cb(skb); struct ieee802154_addr source, dest; + struct netns_ieee802154_lowpan *ieee802154_lowpan = + net_ieee802154_lowpan(net); int err; source = mac_cb(skb)->source; @@ -366,10 +370,10 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type) if (err < 0) goto err; - if (frag_info->d_size > net->ieee802154_lowpan.max_dsize) + if (frag_info->d_size > ieee802154_lowpan->max_dsize) goto err; - inet_frag_evictor(&net->ieee802154_lowpan.frags, &lowpan_frags, false); + inet_frag_evictor(&ieee802154_lowpan->frags, &lowpan_frags, false); fq = fq_find(net, frag_info, &source, &dest); if (fq != NULL) { @@ -436,6 +440,8 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net) { struct ctl_table *table; struct ctl_table_header *hdr; + struct netns_ieee802154_lowpan *ieee802154_lowpan = + net_ieee802154_lowpan(net); table = lowpan_frags_ns_ctl_table; if (!net_eq(net, &init_net)) { @@ -444,10 +450,10 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net) if (table == NULL) goto err_alloc; - table[0].data = &net->ieee802154_lowpan.frags.high_thresh; - table[1].data = &net->ieee802154_lowpan.frags.low_thresh; - table[2].data = &net->ieee802154_lowpan.frags.timeout; - table[3].data = &net->ieee802154_lowpan.max_dsize; + table[0].data = &ieee802154_lowpan->frags.high_thresh; + table[1].data = &ieee802154_lowpan->frags.low_thresh; + table[2].data = &ieee802154_lowpan->frags.timeout; + table[3].data = &ieee802154_lowpan->max_dsize; /* Don't export sysctls to unprivileged users */ if (net->user_ns != &init_user_ns) @@ -458,7 +464,7 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net) if (hdr == NULL) goto err_reg; - net->ieee802154_lowpan.sysctl.frags_hdr = hdr; + ieee802154_lowpan->sysctl.frags_hdr = hdr; return 0; err_reg: @@ -471,9 +477,11 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net) static void __net_exit lowpan_frags_ns_sysctl_unregister(struct net *net) { struct ctl_table *table; + struct netns_ieee802154_lowpan *ieee802154_lowpan = + net_ieee802154_lowpan(net); - table = net->ieee802154_lowpan.sysctl.frags_hdr->ctl_table_arg; - unregister_net_sysctl_table(net->ieee802154_lowpan.sysctl.frags_hdr); + table = ieee802154_lowpan->sysctl.frags_hdr->ctl_table_arg; + unregister_net_sysctl_table(ieee802154_lowpan->sysctl.frags_hdr); if (!net_eq(net, &init_net)) kfree(table); } @@ -514,20 +522,26 @@ static inline void lowpan_frags_sysctl_unregister(void) static int __net_init lowpan_frags_init_net(struct net *net) { - net->ieee802154_lowpan.frags.high_thresh = IPV6_FRAG_HIGH_THRESH; - net->ieee802154_lowpan.frags.low_thresh = IPV6_FRAG_LOW_THRESH; - net->ieee802154_lowpan.frags.timeout = IPV6_FRAG_TIMEOUT; - net->ieee802154_lowpan.max_dsize = 0xFFFF; + struct netns_ieee802154_lowpan *ieee802154_lowpan = + net_ieee802154_lowpan(net); - inet_frags_init_net(&net->ieee802154_lowpan.frags); + ieee802154_lowpan->frags.high_thresh = IPV6_FRAG_HIGH_THRESH; + ieee802154_lowpan->frags.low_thresh = IPV6_FRAG_LOW_THRESH; + ieee802154_lowpan->frags.timeout = IPV6_FRAG_TIMEOUT; + ieee802154_lowpan->max_dsize = 0xFFFF; + + inet_frags_init_net(&ieee802154_lowpan->frags); return lowpan_frags_ns_sysctl_register(net); } static void __net_exit lowpan_frags_exit_net(struct net *net) { + struct netns_ieee802154_lowpan *ieee802154_lowpan = + net_ieee802154_lowpan(net); + lowpan_frags_ns_sysctl_unregister(net); - inet_frags_exit_net(&net->ieee802154_lowpan.frags, &lowpan_frags); + inet_frags_exit_net(&ieee802154_lowpan->frags, &lowpan_frags); } static struct pernet_operations lowpan_frags_ops = { diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 8c54870db792ca..6765d91b8e7554 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1476,22 +1476,20 @@ int inet_ctl_sock_create(struct sock **sk, unsigned short family, } EXPORT_SYMBOL_GPL(inet_ctl_sock_create); -unsigned long snmp_fold_field(void __percpu *mib[], int offt) +unsigned long snmp_fold_field(void __percpu *mib, int offt) { unsigned long res = 0; - int i, j; + int i; - for_each_possible_cpu(i) { - for (j = 0; j < SNMP_ARRAY_SZ; j++) - res += *(((unsigned long *) per_cpu_ptr(mib[j], i)) + offt); - } + for_each_possible_cpu(i) + res += *(((unsigned long *) per_cpu_ptr(mib, i)) + offt); return res; } EXPORT_SYMBOL_GPL(snmp_fold_field); #if BITS_PER_LONG==32 -u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_offset) +u64 snmp_fold_field64(void __percpu *mib, int offt, size_t syncp_offset) { u64 res = 0; int cpu; @@ -1502,7 +1500,7 @@ u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_offset) u64 v; unsigned int start; - bhptr = per_cpu_ptr(mib[0], cpu); + bhptr = per_cpu_ptr(mib, cpu); syncp = (struct u64_stats_sync *)(bhptr + syncp_offset); do { start = u64_stats_fetch_begin_irq(syncp); @@ -1516,25 +1514,6 @@ u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_offset) EXPORT_SYMBOL_GPL(snmp_fold_field64); #endif -int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align) -{ - BUG_ON(ptr == NULL); - ptr[0] = __alloc_percpu(mibsize, align); - if (!ptr[0]) - return -ENOMEM; - -#if SNMP_ARRAY_SZ == 2 - ptr[1] = __alloc_percpu(mibsize, align); - if (!ptr[1]) { - free_percpu(ptr[0]); - ptr[0] = NULL; - return -ENOMEM; - } -#endif - return 0; -} -EXPORT_SYMBOL_GPL(snmp_mib_init); - #ifdef CONFIG_IP_MULTICAST static const struct net_protocol igmp_protocol = { .handler = igmp_rcv, @@ -1570,40 +1549,30 @@ static __net_init int ipv4_mib_init_net(struct net *net) { int i; - if (snmp_mib_init((void __percpu **)net->mib.tcp_statistics, - sizeof(struct tcp_mib), - __alignof__(struct tcp_mib)) < 0) + net->mib.tcp_statistics = alloc_percpu(struct tcp_mib); + if (!net->mib.tcp_statistics) goto err_tcp_mib; - if (snmp_mib_init((void __percpu **)net->mib.ip_statistics, - sizeof(struct ipstats_mib), - __alignof__(struct ipstats_mib)) < 0) + net->mib.ip_statistics = alloc_percpu(struct ipstats_mib); + if (!net->mib.ip_statistics) goto err_ip_mib; for_each_possible_cpu(i) { struct ipstats_mib *af_inet_stats; - af_inet_stats = per_cpu_ptr(net->mib.ip_statistics[0], i); + af_inet_stats = per_cpu_ptr(net->mib.ip_statistics, i); u64_stats_init(&af_inet_stats->syncp); -#if SNMP_ARRAY_SZ == 2 - af_inet_stats = per_cpu_ptr(net->mib.ip_statistics[1], i); - u64_stats_init(&af_inet_stats->syncp); -#endif } - if (snmp_mib_init((void __percpu **)net->mib.net_statistics, - sizeof(struct linux_mib), - __alignof__(struct linux_mib)) < 0) + net->mib.net_statistics = alloc_percpu(struct linux_mib); + if (!net->mib.net_statistics) goto err_net_mib; - if (snmp_mib_init((void __percpu **)net->mib.udp_statistics, - sizeof(struct udp_mib), - __alignof__(struct udp_mib)) < 0) + net->mib.udp_statistics = alloc_percpu(struct udp_mib); + if (!net->mib.udp_statistics) goto err_udp_mib; - if (snmp_mib_init((void __percpu **)net->mib.udplite_statistics, - sizeof(struct udp_mib), - __alignof__(struct udp_mib)) < 0) + net->mib.udplite_statistics = alloc_percpu(struct udp_mib); + if (!net->mib.udplite_statistics) goto err_udplite_mib; - if (snmp_mib_init((void __percpu **)net->mib.icmp_statistics, - sizeof(struct icmp_mib), - __alignof__(struct icmp_mib)) < 0) + net->mib.icmp_statistics = alloc_percpu(struct icmp_mib); + if (!net->mib.icmp_statistics) goto err_icmp_mib; net->mib.icmpmsg_statistics = kzalloc(sizeof(struct icmpmsg_mib), GFP_KERNEL); @@ -1614,17 +1583,17 @@ static __net_init int ipv4_mib_init_net(struct net *net) return 0; err_icmpmsg_mib: - snmp_mib_free((void __percpu **)net->mib.icmp_statistics); + free_percpu(net->mib.icmp_statistics); err_icmp_mib: - snmp_mib_free((void __percpu **)net->mib.udplite_statistics); + free_percpu(net->mib.udplite_statistics); err_udplite_mib: - snmp_mib_free((void __percpu **)net->mib.udp_statistics); + free_percpu(net->mib.udp_statistics); err_udp_mib: - snmp_mib_free((void __percpu **)net->mib.net_statistics); + free_percpu(net->mib.net_statistics); err_net_mib: - snmp_mib_free((void __percpu **)net->mib.ip_statistics); + free_percpu(net->mib.ip_statistics); err_ip_mib: - snmp_mib_free((void __percpu **)net->mib.tcp_statistics); + free_percpu(net->mib.tcp_statistics); err_tcp_mib: return -ENOMEM; } @@ -1632,12 +1601,12 @@ static __net_init int ipv4_mib_init_net(struct net *net) static __net_exit void ipv4_mib_exit_net(struct net *net) { kfree(net->mib.icmpmsg_statistics); - snmp_mib_free((void __percpu **)net->mib.icmp_statistics); - snmp_mib_free((void __percpu **)net->mib.udplite_statistics); - snmp_mib_free((void __percpu **)net->mib.udp_statistics); - snmp_mib_free((void __percpu **)net->mib.net_statistics); - snmp_mib_free((void __percpu **)net->mib.ip_statistics); - snmp_mib_free((void __percpu **)net->mib.tcp_statistics); + free_percpu(net->mib.icmp_statistics); + free_percpu(net->mib.udplite_statistics); + free_percpu(net->mib.udp_statistics); + free_percpu(net->mib.net_statistics); + free_percpu(net->mib.ip_statistics); + free_percpu(net->mib.tcp_statistics); } static __net_initdata struct pernet_operations ipv4_mib_ops = { diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 8a043f03c88ecb..b10cd43a472273 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -821,13 +821,13 @@ struct fib_info *fib_create_info(struct fib_config *cfg) fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); if (fi == NULL) goto failure; + fib_info_cnt++; if (cfg->fc_mx) { fi->fib_metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL); if (!fi->fib_metrics) goto failure; } else fi->fib_metrics = (u32 *) dst_default_metrics; - fib_info_cnt++; fi->fib_net = hold_net(net); fi->fib_protocol = cfg->fc_protocol; diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 48f4244651125f..d3e2265944c62a 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -120,7 +120,7 @@ int inet_peer_maxttl __read_mostly = 10 * 60 * HZ; /* usual time to live: 10 min static void inetpeer_gc_worker(struct work_struct *work) { struct inet_peer *p, *n, *c; - LIST_HEAD(list); + struct list_head list; spin_lock_bh(&gc_lock); list_replace_init(&gc_list, &list); @@ -522,7 +522,7 @@ EXPORT_SYMBOL_GPL(inet_getpeer); void inet_putpeer(struct inet_peer *p) { p->dtime = (__u32)jiffies; - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_dec(&p->refcnt); } EXPORT_SYMBOL_GPL(inet_putpeer); diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index be8abe73bb9f46..6f111e48e11c15 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -42,12 +42,12 @@ static bool ip_may_fragment(const struct sk_buff *skb) { return unlikely((ip_hdr(skb)->frag_off & htons(IP_DF)) == 0) || - !skb->local_df; + skb->local_df; } static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) { - if (skb->len <= mtu || skb->local_df) + if (skb->len <= mtu) return false; if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) @@ -56,53 +56,6 @@ static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) return true; } -static bool ip_gso_exceeds_dst_mtu(const struct sk_buff *skb) -{ - unsigned int mtu; - - if (skb->local_df || !skb_is_gso(skb)) - return false; - - mtu = ip_dst_mtu_maybe_forward(skb_dst(skb), true); - - /* if seglen > mtu, do software segmentation for IP fragmentation on - * output. DF bit cannot be set since ip_forward would have sent - * icmp error. - */ - return skb_gso_network_seglen(skb) > mtu; -} - -/* called if GSO skb needs to be fragmented on forward */ -static int ip_forward_finish_gso(struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - netdev_features_t features; - struct sk_buff *segs; - int ret = 0; - - features = netif_skb_dev_features(skb, dst->dev); - segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); - if (IS_ERR(segs)) { - kfree_skb(skb); - return -ENOMEM; - } - - consume_skb(skb); - - do { - struct sk_buff *nskb = segs->next; - int err; - - segs->next = NULL; - err = dst_output(segs); - - if (err && ret == 0) - ret = err; - segs = nskb; - } while (segs); - - return ret; -} static int ip_forward_finish(struct sk_buff *skb) { @@ -114,9 +67,6 @@ static int ip_forward_finish(struct sk_buff *skb) if (unlikely(opt->optlen)) ip_forward_options(skb); - if (ip_gso_exceeds_dst_mtu(skb)) - return ip_forward_finish_gso(skb); - return dst_output(skb); } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 94213c89156511..c5a557a06a31ae 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -410,7 +410,7 @@ static int ipgre_open(struct net_device *dev) struct flowi4 fl4; struct rtable *rt; - rt = ip_route_output_gre(dev_net(dev), &fl4, + rt = ip_route_output_gre(t->net, &fl4, t->parms.iph.daddr, t->parms.iph.saddr, t->parms.o_key, @@ -434,7 +434,7 @@ static int ipgre_close(struct net_device *dev) if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) { struct in_device *in_dev; - in_dev = inetdev_by_index(dev_net(dev), t->mlink); + in_dev = inetdev_by_index(t->net, t->mlink); if (in_dev) ip_mc_dec_group(in_dev, t->parms.iph.daddr); } @@ -478,7 +478,7 @@ static void __gre_tunnel_init(struct net_device *dev) dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4; dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4; - dev->features |= NETIF_F_NETNS_LOCAL | GRE_FEATURES; + dev->features |= GRE_FEATURES; dev->hw_features |= GRE_FEATURES; if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) { diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index f4ab72e19af923..5e7aecea05cd2a 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -364,7 +364,7 @@ int ip_options_compile(struct net *net, } if (optptr[2] <= optlen) { unsigned char *timeptr = NULL; - if (optptr[2]+3 > optptr[1]) { + if (optptr[2]+3 > optlen) { pp_ptr = optptr + 2; goto error; } @@ -376,7 +376,7 @@ int ip_options_compile(struct net *net, optptr[2] += 4; break; case IPOPT_TS_TSANDADDR: - if (optptr[2]+7 > optptr[1]) { + if (optptr[2]+7 > optlen) { pp_ptr = optptr + 2; goto error; } @@ -390,7 +390,7 @@ int ip_options_compile(struct net *net, optptr[2] += 8; break; case IPOPT_TS_PRESPEC: - if (optptr[2]+7 > optptr[1]) { + if (optptr[2]+7 > optlen) { pp_ptr = optptr + 2; goto error; } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 1cbeba5edff90f..a52f50187b5495 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -211,6 +211,48 @@ static inline int ip_finish_output2(struct sk_buff *skb) return -EINVAL; } +static int ip_finish_output_gso(struct sk_buff *skb) +{ + netdev_features_t features; + struct sk_buff *segs; + int ret = 0; + + /* common case: locally created skb or seglen is <= mtu */ + if (((IPCB(skb)->flags & IPSKB_FORWARDED) == 0) || + skb_gso_network_seglen(skb) <= ip_skb_dst_mtu(skb)) + return ip_finish_output2(skb); + + /* Slowpath - GSO segment length is exceeding the dst MTU. + * + * This can happen in two cases: + * 1) TCP GRO packet, DF bit not set + * 2) skb arrived via virtio-net, we thus get TSO/GSO skbs directly + * from host network stack. + */ + features = netif_skb_features(skb); + segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); + if (IS_ERR(segs)) { + kfree_skb(skb); + return -ENOMEM; + } + + consume_skb(skb); + + do { + struct sk_buff *nskb = segs->next; + int err; + + segs->next = NULL; + err = ip_fragment(segs, ip_finish_output2); + + if (err && ret == 0) + ret = err; + segs = nskb; + } while (segs); + + return ret; +} + static int ip_finish_output(struct sk_buff *skb) { #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) @@ -220,10 +262,13 @@ static int ip_finish_output(struct sk_buff *skb) return dst_output(skb); } #endif - if (skb->len > ip_skb_dst_mtu(skb) && !skb_is_gso(skb)) + if (skb_is_gso(skb)) + return ip_finish_output_gso(skb); + + if (skb->len > ip_skb_dst_mtu(skb)) return ip_fragment(skb, ip_finish_output2); - else - return ip_finish_output2(skb); + + return ip_finish_output2(skb); } int ip_mc_output(struct sock *sk, struct sk_buff *skb) diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index afcee51b90ede3..dbaa3d3901775f 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -349,7 +349,6 @@ static int vti_tunnel_init(struct net_device *dev) memcpy(dev->dev_addr, &iph->saddr, 4); memcpy(dev->broadcast, &iph->daddr, 4); - dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); dev->mtu = ETH_DATA_LEN; dev->flags = IFF_NOARP; dev->iflink = 0; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index ad737fad6d8b82..ae0af9386f7ccf 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -345,15 +345,15 @@ static void icmp_put(struct seq_file *seq) for (i = 0; icmpmibmap[i].name != NULL; i++) seq_printf(seq, " Out%s", icmpmibmap[i].name); seq_printf(seq, "\nIcmp: %lu %lu %lu", - snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INMSGS), - snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INERRORS), - snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_CSUMERRORS)); + snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_INMSGS), + snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_INERRORS), + snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_CSUMERRORS)); for (i = 0; icmpmibmap[i].name != NULL; i++) seq_printf(seq, " %lu", atomic_long_read(ptr + icmpmibmap[i].index)); seq_printf(seq, " %lu %lu", - snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTMSGS), - snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTERRORS)); + snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_OUTMSGS), + snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_OUTERRORS)); for (i = 0; icmpmibmap[i].name != NULL; i++) seq_printf(seq, " %lu", atomic_long_read(ptr + (icmpmibmap[i].index | 0x100))); @@ -379,7 +379,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) BUILD_BUG_ON(offsetof(struct ipstats_mib, mibs) != 0); for (i = 0; snmp4_ipstats_list[i].name != NULL; i++) seq_printf(seq, " %llu", - snmp_fold_field64((void __percpu **)net->mib.ip_statistics, + snmp_fold_field64(net->mib.ip_statistics, snmp4_ipstats_list[i].entry, offsetof(struct ipstats_mib, syncp))); @@ -395,11 +395,11 @@ static int snmp_seq_show(struct seq_file *seq, void *v) /* MaxConn field is signed, RFC 2012 */ if (snmp4_tcp_list[i].entry == TCP_MIB_MAXCONN) seq_printf(seq, " %ld", - snmp_fold_field((void __percpu **)net->mib.tcp_statistics, + snmp_fold_field(net->mib.tcp_statistics, snmp4_tcp_list[i].entry)); else seq_printf(seq, " %lu", - snmp_fold_field((void __percpu **)net->mib.tcp_statistics, + snmp_fold_field(net->mib.tcp_statistics, snmp4_tcp_list[i].entry)); } @@ -410,7 +410,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "\nUdp:"); for (i = 0; snmp4_udp_list[i].name != NULL; i++) seq_printf(seq, " %lu", - snmp_fold_field((void __percpu **)net->mib.udp_statistics, + snmp_fold_field(net->mib.udp_statistics, snmp4_udp_list[i].entry)); /* the UDP and UDP-Lite MIBs are the same */ @@ -421,7 +421,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "\nUdpLite:"); for (i = 0; snmp4_udp_list[i].name != NULL; i++) seq_printf(seq, " %lu", - snmp_fold_field((void __percpu **)net->mib.udplite_statistics, + snmp_fold_field(net->mib.udplite_statistics, snmp4_udp_list[i].entry)); seq_putc(seq, '\n'); @@ -458,7 +458,7 @@ static int netstat_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "\nTcpExt:"); for (i = 0; snmp4_net_list[i].name != NULL; i++) seq_printf(seq, " %lu", - snmp_fold_field((void __percpu **)net->mib.net_statistics, + snmp_fold_field(net->mib.net_statistics, snmp4_net_list[i].entry)); seq_puts(seq, "\nIpExt:"); @@ -468,7 +468,7 @@ static int netstat_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "\nIpExt:"); for (i = 0; snmp4_ipextstats_list[i].name != NULL; i++) seq_printf(seq, " %llu", - snmp_fold_field64((void __percpu **)net->mib.ip_statistics, + snmp_fold_field64(net->mib.ip_statistics, snmp4_ipextstats_list[i].entry, offsetof(struct ipstats_mib, syncp))); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 4bd6d52eeffb6c..eb1dde37e678f6 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2916,6 +2916,14 @@ static int do_tcp_getsockopt(struct sock *sk, int level, case TCP_USER_TIMEOUT: val = jiffies_to_msecs(icsk->icsk_user_timeout); break; + + case TCP_FASTOPEN: + if (icsk->icsk_accept_queue.fastopenq != NULL) + val = icsk->icsk_accept_queue.fastopenq->max_qlen; + else + val = 0; + break; + case TCP_TIMESTAMP: val = tcp_time_stamp + tp->tsoffset; break; diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c index 821846fb0a7e21..d5de69bc04f581 100644 --- a/net/ipv4/tcp_bic.c +++ b/net/ipv4/tcp_bic.c @@ -140,13 +140,12 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) ca->cnt = 1; } -static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked, - u32 in_flight) +static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked) { struct tcp_sock *tp = tcp_sk(sk); struct bictcp *ca = inet_csk_ca(sk); - if (!tcp_is_cwnd_limited(sk, in_flight)) + if (!tcp_is_cwnd_limited(sk)) return; if (tp->snd_cwnd <= tp->snd_ssthresh) diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 2b9464c93b8859..7b09d8b49fa512 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -276,26 +276,6 @@ int tcp_set_congestion_control(struct sock *sk, const char *name) return err; } -/* RFC2861 Check whether we are limited by application or congestion window - * This is the inverse of cwnd check in tcp_tso_should_defer - */ -bool tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight) -{ - const struct tcp_sock *tp = tcp_sk(sk); - u32 left; - - if (in_flight >= tp->snd_cwnd) - return true; - - left = tp->snd_cwnd - in_flight; - if (sk_can_gso(sk) && - left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd && - left < tp->xmit_size_goal_segs) - return true; - return left <= tcp_max_tso_deferred_mss(tp); -} -EXPORT_SYMBOL_GPL(tcp_is_cwnd_limited); - /* Slow start is used when congestion window is no greater than the slow start * threshold. We base on RFC2581 and also handle stretch ACKs properly. * We do not implement RFC3465 Appropriate Byte Counting (ABC) per se but @@ -337,11 +317,11 @@ EXPORT_SYMBOL_GPL(tcp_cong_avoid_ai); /* This is Jacobson's slow start and congestion avoidance. * SIGCOMM '88, p. 328. */ -void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked, u32 in_flight) +void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked) { struct tcp_sock *tp = tcp_sk(sk); - if (!tcp_is_cwnd_limited(sk, in_flight)) + if (!tcp_is_cwnd_limited(sk)) return; /* In "safe" area, increase. */ diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index b4f1b29b08bdf1..a9bd8a4828a9e5 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -304,13 +304,12 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) ca->cnt = 1; } -static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked, - u32 in_flight) +static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked) { struct tcp_sock *tp = tcp_sk(sk); struct bictcp *ca = inet_csk_ca(sk); - if (!tcp_is_cwnd_limited(sk, in_flight)) + if (!tcp_is_cwnd_limited(sk)) return; if (tp->snd_cwnd <= tp->snd_ssthresh) { diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c index 8b9e7bad77c09a..1c4908280d921f 100644 --- a/net/ipv4/tcp_highspeed.c +++ b/net/ipv4/tcp_highspeed.c @@ -109,12 +109,12 @@ static void hstcp_init(struct sock *sk) tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128); } -static void hstcp_cong_avoid(struct sock *sk, u32 ack, u32 acked, u32 in_flight) +static void hstcp_cong_avoid(struct sock *sk, u32 ack, u32 acked) { struct tcp_sock *tp = tcp_sk(sk); struct hstcp *ca = inet_csk_ca(sk); - if (!tcp_is_cwnd_limited(sk, in_flight)) + if (!tcp_is_cwnd_limited(sk)) return; if (tp->snd_cwnd <= tp->snd_ssthresh) diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c index 4a194acfd9237f..031361311a8b92 100644 --- a/net/ipv4/tcp_htcp.c +++ b/net/ipv4/tcp_htcp.c @@ -227,12 +227,12 @@ static u32 htcp_recalc_ssthresh(struct sock *sk) return max((tp->snd_cwnd * ca->beta) >> 7, 2U); } -static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 acked, u32 in_flight) +static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 acked) { struct tcp_sock *tp = tcp_sk(sk); struct htcp *ca = inet_csk_ca(sk); - if (!tcp_is_cwnd_limited(sk, in_flight)) + if (!tcp_is_cwnd_limited(sk)) return; if (tp->snd_cwnd <= tp->snd_ssthresh) diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c index a15a799bf76888..d8f8f05a49516e 100644 --- a/net/ipv4/tcp_hybla.c +++ b/net/ipv4/tcp_hybla.c @@ -87,8 +87,7 @@ static inline u32 hybla_fraction(u32 odds) * o Give cwnd a new value based on the model proposed * o remember increments <1 */ -static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 acked, - u32 in_flight) +static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 acked) { struct tcp_sock *tp = tcp_sk(sk); struct hybla *ca = inet_csk_ca(sk); @@ -101,11 +100,11 @@ static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 acked, ca->minrtt_us = tp->srtt_us; } - if (!tcp_is_cwnd_limited(sk, in_flight)) + if (!tcp_is_cwnd_limited(sk)) return; if (!ca->hybla_en) { - tcp_reno_cong_avoid(sk, ack, acked, in_flight); + tcp_reno_cong_avoid(sk, ack, acked); return; } diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c index 863d105e301503..5999b3972e6449 100644 --- a/net/ipv4/tcp_illinois.c +++ b/net/ipv4/tcp_illinois.c @@ -255,8 +255,7 @@ static void tcp_illinois_state(struct sock *sk, u8 new_state) /* * Increase window in response to successful acknowledgment. */ -static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 acked, - u32 in_flight) +static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 acked) { struct tcp_sock *tp = tcp_sk(sk); struct illinois *ca = inet_csk_ca(sk); @@ -265,7 +264,7 @@ static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 acked, update_params(sk); /* RFC2861 only increase cwnd if fully utilized */ - if (!tcp_is_cwnd_limited(sk, in_flight)) + if (!tcp_is_cwnd_limited(sk)) return; /* In slow start */ diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d6b46eb2f94c5e..350b2072f0ab82 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2938,10 +2938,11 @@ static void tcp_synack_rtt_meas(struct sock *sk, const u32 synack_stamp) tcp_ack_update_rtt(sk, FLAG_SYN_ACKED, seq_rtt_us, -1L); } -static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 acked, u32 in_flight) +static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 acked) { const struct inet_connection_sock *icsk = inet_csk(sk); - icsk->icsk_ca_ops->cong_avoid(sk, ack, acked, in_flight); + + icsk->icsk_ca_ops->cong_avoid(sk, ack, acked); tcp_sk(sk)->snd_cwnd_stamp = tcp_time_stamp; } @@ -3364,7 +3365,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) u32 ack_seq = TCP_SKB_CB(skb)->seq; u32 ack = TCP_SKB_CB(skb)->ack_seq; bool is_dupack = false; - u32 prior_in_flight; u32 prior_fackets; int prior_packets = tp->packets_out; const int prior_unsacked = tp->packets_out - tp->sacked_out; @@ -3397,7 +3397,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) flag |= FLAG_SND_UNA_ADVANCED; prior_fackets = tp->fackets_out; - prior_in_flight = tcp_packets_in_flight(tp); /* ts_recent update must be made after we are sure that the packet * is in window. @@ -3452,7 +3451,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) /* Advance cwnd if state allows */ if (tcp_may_raise_cwnd(sk, flag)) - tcp_cong_avoid(sk, ack, acked, prior_in_flight); + tcp_cong_avoid(sk, ack, acked); if (tcp_ack_is_dubious(sk, flag)) { is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)); @@ -4703,28 +4702,6 @@ static int tcp_prune_queue(struct sock *sk) return -1; } -/* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. - * As additional protections, we do not touch cwnd in retransmission phases, - * and if application hit its sndbuf limit recently. - */ -void tcp_cwnd_application_limited(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (inet_csk(sk)->icsk_ca_state == TCP_CA_Open && - sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - /* Limited by application or receiver window. */ - u32 init_win = tcp_init_cwnd(tp, __sk_dst_get(sk)); - u32 win_used = max(tp->snd_cwnd_used, init_win); - if (win_used < tp->snd_cwnd) { - tp->snd_ssthresh = tcp_current_ssthresh(sk); - tp->snd_cwnd = (tp->snd_cwnd + win_used) >> 1; - } - tp->snd_cwnd_used = 0; - } - tp->snd_cwnd_stamp = tcp_time_stamp; -} - static bool tcp_should_expand_sndbuf(const struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 438f3b95143df0..ad166dcc278fe4 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1744,28 +1744,6 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) return sk; } -static __sum16 tcp_v4_checksum_init(struct sk_buff *skb) -{ - const struct iphdr *iph = ip_hdr(skb); - - if (skb->ip_summed == CHECKSUM_COMPLETE) { - if (!tcp_v4_check(skb->len, iph->saddr, - iph->daddr, skb->csum)) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - return 0; - } - } - - skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, - skb->len, IPPROTO_TCP, 0); - - if (skb->len <= 76) { - return __skb_checksum_complete(skb); - } - return 0; -} - - /* The socket must have it's spinlock held when we get * here. * @@ -1960,7 +1938,8 @@ int tcp_v4_rcv(struct sk_buff *skb) * Packet length and doff are validated by header prediction, * provided case of th->doff==0 is eliminated. * So, we defer the checks. */ - if (!skb_csum_unnecessary(skb) && tcp_v4_checksum_init(skb)) + + if (skb_checksum_init(skb, IPPROTO_TCP, inet_compute_pseudo)) goto csum_error; th = tcp_hdr(skb); diff --git a/net/ipv4/tcp_lp.c b/net/ipv4/tcp_lp.c index c9aecae313276d..1e70fa8fa793fd 100644 --- a/net/ipv4/tcp_lp.c +++ b/net/ipv4/tcp_lp.c @@ -115,13 +115,12 @@ static void tcp_lp_init(struct sock *sk) * Will only call newReno CA when away from inference. * From TCP-LP's paper, this will be handled in additive increasement. */ -static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 acked, - u32 in_flight) +static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 acked) { struct lp *lp = inet_csk_ca(sk); if (!(lp->flag & LP_WITHIN_INF)) - tcp_reno_cong_avoid(sk, ack, acked, in_flight); + tcp_reno_cong_avoid(sk, ack, acked); } /** diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 12d6016bdd9a67..c2c64b2728109e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -878,15 +878,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, BUG_ON(!skb || !tcp_skb_pcount(skb)); if (clone_it) { - const struct sk_buff *fclone = skb + 1; - skb_mstamp_get(&skb->skb_mstamp); - if (unlikely(skb->fclone == SKB_FCLONE_ORIG && - fclone->fclone == SKB_FCLONE_CLONE)) - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES); - if (unlikely(skb_cloned(skb))) skb = pskb_copy(skb, gfp_mask); else @@ -1387,12 +1380,35 @@ unsigned int tcp_current_mss(struct sock *sk) return mss_now; } -/* Congestion window validation. (RFC2861) */ -static void tcp_cwnd_validate(struct sock *sk) +/* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. + * As additional protections, we do not touch cwnd in retransmission phases, + * and if application hit its sndbuf limit recently. + */ +static void tcp_cwnd_application_limited(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); - if (tp->packets_out >= tp->snd_cwnd) { + if (inet_csk(sk)->icsk_ca_state == TCP_CA_Open && + sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { + /* Limited by application or receiver window. */ + u32 init_win = tcp_init_cwnd(tp, __sk_dst_get(sk)); + u32 win_used = max(tp->snd_cwnd_used, init_win); + if (win_used < tp->snd_cwnd) { + tp->snd_ssthresh = tcp_current_ssthresh(sk); + tp->snd_cwnd = (tp->snd_cwnd + win_used) >> 1; + } + tp->snd_cwnd_used = 0; + } + tp->snd_cwnd_stamp = tcp_time_stamp; +} + +static void tcp_cwnd_validate(struct sock *sk, u32 unsent_segs) +{ + struct tcp_sock *tp = tcp_sk(sk); + + tp->lsnd_pending = tp->packets_out + unsent_segs; + + if (tcp_is_cwnd_limited(sk)) { /* Network is feed fully. */ tp->snd_cwnd_used = 0; tp->snd_cwnd_stamp = tcp_time_stamp; @@ -1865,7 +1881,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; - unsigned int tso_segs, sent_pkts; + unsigned int tso_segs, sent_pkts, unsent_segs = 0; int cwnd_quota; int result; @@ -1909,7 +1925,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, break; } else { if (!push_one && tcp_tso_should_defer(sk, skb)) - break; + goto compute_unsent_segs; } /* TCP Small Queues : @@ -1930,12 +1946,16 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, /* It is possible TX completion already happened * before we set TSQ_THROTTLED, so we must * test again the condition. - * We abuse smp_mb__after_clear_bit() because - * there is no smp_mb__after_set_bit() yet */ - smp_mb__after_clear_bit(); - if (atomic_read(&sk->sk_wmem_alloc) > limit) + smp_mb__after_atomic(); + if (atomic_read(&sk->sk_wmem_alloc) > limit) { + u32 unsent_bytes; + +compute_unsent_segs: + unsent_bytes = tp->write_seq - tp->snd_nxt; + unsent_segs = DIV_ROUND_UP(unsent_bytes, mss_now); break; + } } limit = mss_now; @@ -1975,7 +1995,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, /* Send one loss probe per tail loss episode. */ if (push_one != 2) tcp_schedule_loss_probe(sk); - tcp_cwnd_validate(sk); + tcp_cwnd_validate(sk, unsent_segs); return false; } return (push_one == 2) || (!tp->packets_out && tcp_send_head(sk)); @@ -2039,6 +2059,25 @@ bool tcp_schedule_loss_probe(struct sock *sk) return true; } +/* Thanks to skb fast clones, we can detect if a prior transmit of + * a packet is still in a qdisc or driver queue. + * In this case, there is very little point doing a retransmit ! + * Note: This is called from BH context only. + */ +static bool skb_still_in_host_queue(const struct sock *sk, + const struct sk_buff *skb) +{ + const struct sk_buff *fclone = skb + 1; + + if (unlikely(skb->fclone == SKB_FCLONE_ORIG && + fclone->fclone == SKB_FCLONE_CLONE)) { + NET_INC_STATS_BH(sock_net(sk), + LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES); + return true; + } + return false; +} + /* When probe timeout (PTO) fires, send a new segment if one exists, else * retransmit the last segment. */ @@ -2064,6 +2103,9 @@ void tcp_send_loss_probe(struct sock *sk) if (WARN_ON(!skb)) goto rearm_timer; + if (skb_still_in_host_queue(sk, skb)) + goto rearm_timer; + pcount = tcp_skb_pcount(skb); if (WARN_ON(!pcount)) goto rearm_timer; @@ -2385,6 +2427,9 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) min(sk->sk_wmem_queued + (sk->sk_wmem_queued >> 2), sk->sk_sndbuf)) return -EAGAIN; + if (skb_still_in_host_queue(sk, skb)) + return -EBUSY; + if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) { if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) BUG(); @@ -2478,7 +2523,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) * see tcp_input.c tcp_sacktag_write_queue(). */ TCP_SKB_CB(skb)->ack_seq = tp->snd_nxt; - } else { + } else if (err != -EBUSY) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRETRANSFAIL); } return err; diff --git a/net/ipv4/tcp_scalable.c b/net/ipv4/tcp_scalable.c index 0ac50836da4d42..8250949b88538d 100644 --- a/net/ipv4/tcp_scalable.c +++ b/net/ipv4/tcp_scalable.c @@ -15,12 +15,11 @@ #define TCP_SCALABLE_AI_CNT 50U #define TCP_SCALABLE_MD_SCALE 3 -static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked, - u32 in_flight) +static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked) { struct tcp_sock *tp = tcp_sk(sk); - if (!tcp_is_cwnd_limited(sk, in_flight)) + if (!tcp_is_cwnd_limited(sk)) return; if (tp->snd_cwnd <= tp->snd_ssthresh) diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index 48539fff6357a4..9a5e05f27f4f7c 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c @@ -163,14 +163,13 @@ static inline u32 tcp_vegas_ssthresh(struct tcp_sock *tp) return min(tp->snd_ssthresh, tp->snd_cwnd-1); } -static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked, - u32 in_flight) +static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) { struct tcp_sock *tp = tcp_sk(sk); struct vegas *vegas = inet_csk_ca(sk); if (!vegas->doing_vegas_now) { - tcp_reno_cong_avoid(sk, ack, acked, in_flight); + tcp_reno_cong_avoid(sk, ack, acked); return; } @@ -195,7 +194,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked, /* We don't have enough RTT samples to do the Vegas * calculation, so we'll behave like Reno. */ - tcp_reno_cong_avoid(sk, ack, acked, in_flight); + tcp_reno_cong_avoid(sk, ack, acked); } else { u32 rtt, diff; u64 target_cwnd; diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c index 1b8e28fcd7e1ca..27b9825753d15d 100644 --- a/net/ipv4/tcp_veno.c +++ b/net/ipv4/tcp_veno.c @@ -114,19 +114,18 @@ static void tcp_veno_cwnd_event(struct sock *sk, enum tcp_ca_event event) tcp_veno_init(sk); } -static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked, - u32 in_flight) +static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked) { struct tcp_sock *tp = tcp_sk(sk); struct veno *veno = inet_csk_ca(sk); if (!veno->doing_veno_now) { - tcp_reno_cong_avoid(sk, ack, acked, in_flight); + tcp_reno_cong_avoid(sk, ack, acked); return; } /* limited by applications */ - if (!tcp_is_cwnd_limited(sk, in_flight)) + if (!tcp_is_cwnd_limited(sk)) return; /* We do the Veno calculations only if we got enough rtt samples */ @@ -134,7 +133,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked, /* We don't have enough rtt samples to do the Veno * calculation, so we'll behave like Reno. */ - tcp_reno_cong_avoid(sk, ack, acked, in_flight); + tcp_reno_cong_avoid(sk, ack, acked); } else { u64 target_cwnd; u32 rtt; diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c index 5ede0e727945ad..599b79b8eac072 100644 --- a/net/ipv4/tcp_yeah.c +++ b/net/ipv4/tcp_yeah.c @@ -69,13 +69,12 @@ static void tcp_yeah_pkts_acked(struct sock *sk, u32 pkts_acked, s32 rtt_us) tcp_vegas_pkts_acked(sk, pkts_acked, rtt_us); } -static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked, - u32 in_flight) +static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked) { struct tcp_sock *tp = tcp_sk(sk); struct yeah *yeah = inet_csk_ca(sk); - if (!tcp_is_cwnd_limited(sk, in_flight)) + if (!tcp_is_cwnd_limited(sk)) return; if (tp->snd_cwnd <= tp->snd_ssthresh) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 4468e1adc094a1..f2d05d7be743d0 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1672,7 +1672,6 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) { - const struct iphdr *iph; int err; UDP_SKB_CB(skb)->partial_cov = 0; @@ -1684,22 +1683,8 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, return err; } - iph = ip_hdr(skb); - if (uh->check == 0) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else if (skb->ip_summed == CHECKSUM_COMPLETE) { - if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, - proto, skb->csum)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - } - if (!skb_csum_unnecessary(skb)) - skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, - skb->len, proto, 0); - /* Probably, we should checksum udp header (it should be in cache - * in any case) and data in tiny packets (< rx copybreak). - */ - - return 0; + return skb_checksum_init_zero_check(skb, proto, uh->check, + inet_compute_pseudo); } /* diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 40e701f2e1e032..186a8ecf92fa84 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -62,10 +62,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) if (err) return err; - memset(IPCB(skb), 0, sizeof(*IPCB(skb))); - IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED; - - skb->protocol = htons(ETH_P_IP); + IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; return x->outer_mode->output2(x, skb); } @@ -73,27 +70,34 @@ EXPORT_SYMBOL(xfrm4_prepare_output); int xfrm4_output_finish(struct sk_buff *skb) { + memset(IPCB(skb), 0, sizeof(*IPCB(skb))); + skb->protocol = htons(ETH_P_IP); + +#ifdef CONFIG_NETFILTER + IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; +#endif + + return xfrm_output(skb); +} + +static int __xfrm4_output(struct sk_buff *skb) +{ + struct xfrm_state *x = skb_dst(skb)->xfrm; + #ifdef CONFIG_NETFILTER - if (!skb_dst(skb)->xfrm) { + if (!x) { IPCB(skb)->flags |= IPSKB_REROUTED; return dst_output(skb); } - - IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; #endif - skb->protocol = htons(ETH_P_IP); - return xfrm_output(skb); + return x->outer_mode->afinfo->output_finish(skb); } int xfrm4_output(struct sock *sk, struct sk_buff *skb) { - struct dst_entry *dst = skb_dst(skb); - struct xfrm_state *x = dst->xfrm; - return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, - NULL, dst->dev, - x->outer_mode->afinfo->output_finish, + NULL, skb_dst(skb)->dev, __xfrm4_output, !(IPCB(skb)->flags & IPSKB_REROUTED)); } diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c index 7f7b243e8139de..a2ce0101eaac84 100644 --- a/net/ipv4/xfrm4_protocol.c +++ b/net/ipv4/xfrm4_protocol.c @@ -50,8 +50,12 @@ int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err) { int ret; struct xfrm4_protocol *handler; + struct xfrm4_protocol __rcu **head = proto_handlers(protocol); - for_each_protocol_rcu(*proto_handlers(protocol), handler) + if (!head) + return 0; + + for_each_protocol_rcu(*head, handler) if ((ret = handler->cb_handler(skb, err)) <= 0) return ret; @@ -64,15 +68,20 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, { int ret; struct xfrm4_protocol *handler; + struct xfrm4_protocol __rcu **head = proto_handlers(nexthdr); XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; XFRM_SPI_SKB_CB(skb)->family = AF_INET; XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); - for_each_protocol_rcu(*proto_handlers(nexthdr), handler) + if (!head) + goto out; + + for_each_protocol_rcu(*head, handler) if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL) return ret; +out: icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); kfree_skb(skb); @@ -208,6 +217,9 @@ int xfrm4_protocol_register(struct xfrm4_protocol *handler, int ret = -EEXIST; int priority = handler->priority; + if (!proto_handlers(protocol) || !netproto(protocol)) + return -EINVAL; + mutex_lock(&xfrm4_protocol_mutex); if (!rcu_dereference_protected(*proto_handlers(protocol), @@ -250,6 +262,9 @@ int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, struct xfrm4_protocol *t; int ret = -ENOENT; + if (!proto_handlers(protocol) || !netproto(protocol)) + return -EINVAL; + mutex_lock(&xfrm4_protocol_mutex); for (pprev = proto_handlers(protocol); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 6c7fa0853fc74e..5667b3003af9b5 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -275,19 +275,14 @@ static int snmp6_alloc_dev(struct inet6_dev *idev) { int i; - if (snmp_mib_init((void __percpu **)idev->stats.ipv6, - sizeof(struct ipstats_mib), - __alignof__(struct ipstats_mib)) < 0) + idev->stats.ipv6 = alloc_percpu(struct ipstats_mib); + if (!idev->stats.ipv6) goto err_ip; for_each_possible_cpu(i) { struct ipstats_mib *addrconf_stats; - addrconf_stats = per_cpu_ptr(idev->stats.ipv6[0], i); + addrconf_stats = per_cpu_ptr(idev->stats.ipv6, i); u64_stats_init(&addrconf_stats->syncp); -#if SNMP_ARRAY_SZ == 2 - addrconf_stats = per_cpu_ptr(idev->stats.ipv6[1], i); - u64_stats_init(&addrconf_stats->syncp); -#endif } @@ -305,7 +300,7 @@ static int snmp6_alloc_dev(struct inet6_dev *idev) err_icmpmsg: kfree(idev->stats.icmpv6dev); err_icmp: - snmp_mib_free((void __percpu **)idev->stats.ipv6); + free_percpu(idev->stats.ipv6); err_ip: return -ENOMEM; } @@ -2504,8 +2499,8 @@ static int inet6_addr_add(struct net *net, int ifindex, return PTR_ERR(ifp); } -static int inet6_addr_del(struct net *net, int ifindex, const struct in6_addr *pfx, - unsigned int plen) +static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags, + const struct in6_addr *pfx, unsigned int plen) { struct inet6_ifaddr *ifp; struct inet6_dev *idev; @@ -2528,7 +2523,12 @@ static int inet6_addr_del(struct net *net, int ifindex, const struct in6_addr *p in6_ifa_hold(ifp); read_unlock_bh(&idev->lock); + if (!(ifp->flags & IFA_F_TEMPORARY) && + (ifa_flags & IFA_F_MANAGETEMPADDR)) + manage_tempaddrs(idev, ifp, 0, 0, false, + jiffies); ipv6_del_addr(ifp); + addrconf_verify_rtnl(); return 0; } } @@ -2568,7 +2568,7 @@ int addrconf_del_ifaddr(struct net *net, void __user *arg) return -EFAULT; rtnl_lock(); - err = inet6_addr_del(net, ireq.ifr6_ifindex, &ireq.ifr6_addr, + err = inet6_addr_del(net, ireq.ifr6_ifindex, 0, &ireq.ifr6_addr, ireq.ifr6_prefixlen); rtnl_unlock(); return err; @@ -2813,18 +2813,6 @@ static void addrconf_gre_config(struct net_device *dev) } #endif -static inline int -ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev) -{ - struct in6_addr lladdr; - - if (!ipv6_get_lladdr(link_dev, &lladdr, IFA_F_TENTATIVE)) { - addrconf_add_linklocal(idev, &lladdr); - return 0; - } - return -1; -} - static int addrconf_notify(struct notifier_block *this, unsigned long event, void *ptr) { @@ -3743,6 +3731,7 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) struct ifaddrmsg *ifm; struct nlattr *tb[IFA_MAX+1]; struct in6_addr *pfx, *peer_pfx; + u32 ifa_flags; int err; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); @@ -3754,7 +3743,13 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) if (pfx == NULL) return -EINVAL; - return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen); + ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags; + + /* We ignore other flags so far. */ + ifa_flags &= IFA_F_MANAGETEMPADDR; + + return inet6_addr_del(net, ifm->ifa_index, ifa_flags, pfx, + ifm->ifa_prefixlen); } static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags, @@ -4363,7 +4358,7 @@ static inline void __snmp6_fill_statsdev(u64 *stats, atomic_long_t *mib, memset(&stats[items], 0, pad); } -static inline void __snmp6_fill_stats64(u64 *stats, void __percpu **mib, +static inline void __snmp6_fill_stats64(u64 *stats, void __percpu *mib, int items, int bytes, size_t syncpoff) { int i; @@ -4383,7 +4378,7 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, { switch (attrtype) { case IFLA_INET6_STATS: - __snmp6_fill_stats64(stats, (void __percpu **)idev->stats.ipv6, + __snmp6_fill_stats64(stats, idev->stats.ipv6, IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp)); break; case IFLA_INET6_ICMP6STATS: diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c index 4c11cbcf830891..e6960457f62582 100644 --- a/net/ipv6/addrconf_core.c +++ b/net/ipv6/addrconf_core.c @@ -123,7 +123,7 @@ static void snmp6_free_dev(struct inet6_dev *idev) { kfree(idev->stats.icmpv6msgdev); kfree(idev->stats.icmpv6dev); - snmp_mib_free((void __percpu **)idev->stats.ipv6); + free_percpu(idev->stats.ipv6); } /* Nobody refers to this device, we may destroy it. */ diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index d935889f1008ae..dc47cc757b80b6 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -715,33 +715,25 @@ static int __net_init ipv6_init_mibs(struct net *net) { int i; - if (snmp_mib_init((void __percpu **)net->mib.udp_stats_in6, - sizeof(struct udp_mib), - __alignof__(struct udp_mib)) < 0) + net->mib.udp_stats_in6 = alloc_percpu(struct udp_mib); + if (!net->mib.udp_stats_in6) return -ENOMEM; - if (snmp_mib_init((void __percpu **)net->mib.udplite_stats_in6, - sizeof(struct udp_mib), - __alignof__(struct udp_mib)) < 0) + net->mib.udplite_stats_in6 = alloc_percpu(struct udp_mib); + if (!net->mib.udplite_stats_in6) goto err_udplite_mib; - if (snmp_mib_init((void __percpu **)net->mib.ipv6_statistics, - sizeof(struct ipstats_mib), - __alignof__(struct ipstats_mib)) < 0) + net->mib.ipv6_statistics = alloc_percpu(struct ipstats_mib); + if (!net->mib.ipv6_statistics) goto err_ip_mib; for_each_possible_cpu(i) { struct ipstats_mib *af_inet6_stats; - af_inet6_stats = per_cpu_ptr(net->mib.ipv6_statistics[0], i); + af_inet6_stats = per_cpu_ptr(net->mib.ipv6_statistics, i); u64_stats_init(&af_inet6_stats->syncp); -#if SNMP_ARRAY_SZ == 2 - af_inet6_stats = per_cpu_ptr(net->mib.ipv6_statistics[1], i); - u64_stats_init(&af_inet6_stats->syncp); -#endif } - if (snmp_mib_init((void __percpu **)net->mib.icmpv6_statistics, - sizeof(struct icmpv6_mib), - __alignof__(struct icmpv6_mib)) < 0) + net->mib.icmpv6_statistics = alloc_percpu(struct icmpv6_mib); + if (!net->mib.icmpv6_statistics) goto err_icmp_mib; net->mib.icmpv6msg_statistics = kzalloc(sizeof(struct icmpv6msg_mib), GFP_KERNEL); @@ -750,22 +742,22 @@ static int __net_init ipv6_init_mibs(struct net *net) return 0; err_icmpmsg_mib: - snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics); + free_percpu(net->mib.icmpv6_statistics); err_icmp_mib: - snmp_mib_free((void __percpu **)net->mib.ipv6_statistics); + free_percpu(net->mib.ipv6_statistics); err_ip_mib: - snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6); + free_percpu(net->mib.udplite_stats_in6); err_udplite_mib: - snmp_mib_free((void __percpu **)net->mib.udp_stats_in6); + free_percpu(net->mib.udp_stats_in6); return -ENOMEM; } static void ipv6_cleanup_mibs(struct net *net) { - snmp_mib_free((void __percpu **)net->mib.udp_stats_in6); - snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6); - snmp_mib_free((void __percpu **)net->mib.ipv6_statistics); - snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics); + free_percpu(net->mib.udp_stats_in6); + free_percpu(net->mib.udplite_stats_in6); + free_percpu(net->mib.ipv6_statistics); + free_percpu(net->mib.icmpv6_statistics); kfree(net->mib.icmpv6msg_statistics); } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 7b326529e6a2cb..3b0905b77127d9 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -493,12 +493,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) if (IS_ERR(dst)) goto out; - if (ipv6_addr_is_multicast(&fl6.daddr)) - hlimit = np->mcast_hops; - else - hlimit = np->hop_limit; - if (hlimit < 0) - hlimit = ip6_dst_hoplimit(dst); + hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); msg.skb = skb; msg.offset = skb_network_offset(skb); @@ -593,12 +588,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) if (IS_ERR(dst)) goto out; - if (ipv6_addr_is_multicast(&fl6.daddr)) - hlimit = np->mcast_hops; - else - hlimit = np->hop_limit; - if (hlimit < 0) - hlimit = ip6_dst_hoplimit(dst); + hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); idev = __in6_dev_get(skb->dev); diff --git a/net/ipv6/ip6_checksum.c b/net/ipv6/ip6_checksum.c index ee7a97f510cbd9..da26224a599323 100644 --- a/net/ipv6/ip6_checksum.c +++ b/net/ipv6/ip6_checksum.c @@ -75,25 +75,12 @@ int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) return err; } - if (uh->check == 0) { - /* RFC 2460 section 8.1 says that we SHOULD log - this error. Well, it is reasonable. - */ - LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n", - &ipv6_hdr(skb)->saddr, ntohs(uh->source), - &ipv6_hdr(skb)->daddr, ntohs(uh->dest)); - return 1; - } - if (skb->ip_summed == CHECKSUM_COMPLETE && - !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, - skb->len, proto, skb->csum)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - - if (!skb_csum_unnecessary(skb)) - skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - skb->len, proto, 0)); - - return 0; + /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels) + * we accept a checksum of zero here. When we find the socket + * for the UDP packet we'll check if that socket allows zero checksum + * for IPv6 (set by socket option). + */ + return skb_checksum_init_zero_check(skb, proto, uh->check, + ip6_compute_pseudo); } EXPORT_SYMBOL(udp6_csum_init); diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 0961b5ef866d04..4052694c6f2cb1 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -26,7 +26,6 @@ #include #include -#include #include #include diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 9d921462b57f29..75277b739b0424 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -72,6 +72,7 @@ struct ip6gre_net { }; static struct rtnl_link_ops ip6gre_link_ops __read_mostly; +static struct rtnl_link_ops ip6gre_tap_ops __read_mostly; static int ip6gre_tunnel_init(struct net_device *dev); static void ip6gre_tunnel_setup(struct net_device *dev); static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t); @@ -353,10 +354,10 @@ static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net, static void ip6gre_tunnel_uninit(struct net_device *dev) { - struct net *net = dev_net(dev); - struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); + struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id); - ip6gre_tunnel_unlink(ign, netdev_priv(dev)); + ip6gre_tunnel_unlink(ign, t); dev_put(dev); } @@ -611,8 +612,8 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, int encap_limit, __u32 *pmtu) { - struct net *net = dev_net(dev); struct ip6_tnl *tunnel = netdev_priv(dev); + struct net *net = tunnel->net; struct net_device *tdev; /* Device to other host */ struct ipv6hdr *ipv6h; /* Our new IP header */ unsigned int max_headroom = 0; /* The extra header space needed */ @@ -979,7 +980,7 @@ static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu) int strict = (ipv6_addr_type(&p->raddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL)); - struct rt6_info *rt = rt6_lookup(dev_net(dev), + struct rt6_info *rt = rt6_lookup(t->net, &p->raddr, &p->laddr, p->link, strict); @@ -1063,13 +1064,12 @@ static int ip6gre_tunnel_ioctl(struct net_device *dev, int err = 0; struct ip6_tnl_parm2 p; struct __ip6_tnl_parm p1; - struct ip6_tnl *t; - struct net *net = dev_net(dev); + struct ip6_tnl *t = netdev_priv(dev); + struct net *net = t->net; struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); switch (cmd) { case SIOCGETTUNNEL: - t = NULL; if (dev == ign->fb_tunnel_dev) { if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { err = -EFAULT; @@ -1077,9 +1077,9 @@ static int ip6gre_tunnel_ioctl(struct net_device *dev, } ip6gre_tnl_parm_from_user(&p1, &p); t = ip6gre_tunnel_locate(net, &p1, 0); + if (t == NULL) + t = netdev_priv(dev); } - if (t == NULL) - t = netdev_priv(dev); memset(&p, 0, sizeof(p)); ip6gre_tnl_parm_to_user(&p, &t->parms); if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) @@ -1242,7 +1242,6 @@ static void ip6gre_tunnel_setup(struct net_device *dev) dev->flags |= IFF_NOARP; dev->iflink = 0; dev->addr_len = sizeof(struct in6_addr); - dev->features |= NETIF_F_NETNS_LOCAL; dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } @@ -1297,11 +1296,17 @@ static struct inet6_protocol ip6gre_protocol __read_mostly = { .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; -static void ip6gre_destroy_tunnels(struct ip6gre_net *ign, - struct list_head *head) +static void ip6gre_destroy_tunnels(struct net *net, struct list_head *head) { + struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); + struct net_device *dev, *aux; int prio; + for_each_netdev_safe(net, dev, aux) + if (dev->rtnl_link_ops == &ip6gre_link_ops || + dev->rtnl_link_ops == &ip6gre_tap_ops) + unregister_netdevice_queue(dev, head); + for (prio = 0; prio < 4; prio++) { int h; for (h = 0; h < HASH_SIZE; h++) { @@ -1310,7 +1315,12 @@ static void ip6gre_destroy_tunnels(struct ip6gre_net *ign, t = rtnl_dereference(ign->tunnels[prio][h]); while (t != NULL) { - unregister_netdevice_queue(t->dev, head); + /* If dev is in the same netns, it has already + * been added to the list by the previous loop. + */ + if (!net_eq(dev_net(t->dev), net)) + unregister_netdevice_queue(t->dev, + head); t = rtnl_dereference(t->next); } } @@ -1329,6 +1339,11 @@ static int __net_init ip6gre_init_net(struct net *net) goto err_alloc_dev; } dev_net_set(ign->fb_tunnel_dev, net); + /* FB netdevice is special: we have one, and only one per netns. + * Allowing to move it to another netns is clearly unsafe. + */ + ign->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL; + ip6gre_fb_tunnel_init(ign->fb_tunnel_dev); ign->fb_tunnel_dev->rtnl_link_ops = &ip6gre_link_ops; @@ -1349,12 +1364,10 @@ static int __net_init ip6gre_init_net(struct net *net) static void __net_exit ip6gre_exit_net(struct net *net) { - struct ip6gre_net *ign; LIST_HEAD(list); - ign = net_generic(net, ip6gre_net_id); rtnl_lock(); - ip6gre_destroy_tunnels(ign, &list); + ip6gre_destroy_tunnels(net, &list); unregister_netdevice_many(&list); rtnl_unlock(); } @@ -1531,15 +1544,14 @@ static int ip6gre_newlink(struct net *src_net, struct net_device *dev, static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { - struct ip6_tnl *t, *nt; - struct net *net = dev_net(dev); + struct ip6_tnl *t, *nt = netdev_priv(dev); + struct net *net = nt->net; struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); struct __ip6_tnl_parm p; if (dev == ign->fb_tunnel_dev) return -EINVAL; - nt = netdev_priv(dev); ip6gre_netlink_parms(data, &p); t = ip6gre_tunnel_locate(net, &p, 0); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 40e7581374f700..31a38bde69ef17 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -344,12 +344,16 @@ static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) { - if (skb->len <= mtu || skb->local_df) + if (skb->len <= mtu) return false; + /* ipv6 conntrack defrag sets max_frag_size + local_df */ if (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu) return true; + if (skb->local_df) + return false; + if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) return false; diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index bda74291c3e0d0..a2a1d80dfe0c0e 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -168,12 +168,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, pfh.wcheck = 0; pfh.family = AF_INET6; - if (ipv6_addr_is_multicast(&fl6.daddr)) - hlimit = np->mcast_hops; - else - hlimit = np->hop_limit; - if (hlimit < 0) - hlimit = ip6_dst_hoplimit(dst); + hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); lock_sock(sk); err = ip6_append_data(sk, ping_getfrag, &pfh, len, diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 091d066a57b371..69cb47625df735 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -201,7 +201,7 @@ static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **pcpumib, } } -static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu **mib, +static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu *mib, const struct snmp_mib *itemlist, size_t syncpoff) { int i; @@ -215,7 +215,7 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) { struct net *net = (struct net *)seq->private; - snmp6_seq_show_item64(seq, (void __percpu **)net->mib.ipv6_statistics, + snmp6_seq_show_item64(seq, net->mib.ipv6_statistics, snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics, NULL, snmp6_icmp6_list); @@ -245,7 +245,7 @@ static int snmp6_dev_seq_show(struct seq_file *seq, void *v) struct inet6_dev *idev = (struct inet6_dev *)seq->private; seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); - snmp6_seq_show_item64(seq, (void __percpu **)idev->stats.ipv6, + snmp6_seq_show_item64(seq, idev->stats.ipv6, snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); snmp6_seq_show_item(seq, NULL, idev->stats.icmpv6dev->mibs, snmp6_icmp6_list); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 1f29996e368a23..dddfb5fa2b7a28 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -873,14 +873,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, err = PTR_ERR(dst); goto out; } - if (hlimit < 0) { - if (ipv6_addr_is_multicast(&fl6.daddr)) - hlimit = np->mcast_hops; - else - hlimit = np->hop_limit; - if (hlimit < 0) - hlimit = ip6_dst_hoplimit(dst); - } + if (hlimit < 0) + hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); if (tclass < 0) tclass = np->tclass; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index e289830ed6e35a..7fa67439f4d6a9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1294,25 +1294,6 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, return NULL; } -static __sum16 tcp_v6_checksum_init(struct sk_buff *skb) -{ - if (skb->ip_summed == CHECKSUM_COMPLETE) { - if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, skb->csum)) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - return 0; - } - } - - skb->csum = ~csum_unfold(tcp_v6_check(skb->len, - &ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, 0)); - - if (skb->len <= 76) - return __skb_checksum_complete(skb); - return 0; -} - /* The socket must have it's spinlock held when we get * here. * @@ -1486,7 +1467,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) if (!pskb_may_pull(skb, th->doff*4)) goto discard_it; - if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb)) + if (skb_checksum_init(skb, IPPROTO_TCP, ip6_compute_pseudo)) goto csum_error; th = tcp_hdr(skb); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 1e586d92260e1e..fc2be63e32d586 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -760,6 +760,17 @@ static void flush_stack(struct sock **stack, unsigned int count, if (unlikely(skb1)) kfree_skb(skb1); } + +static void udp6_csum_zero_error(struct sk_buff *skb) +{ + /* RFC 2460 section 8.1 says that we SHOULD log + * this error. Well, it is reasonable. + */ + LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n", + &ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source), + &ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest)); +} + /* * Note: called only from the BH handler context, * so we don't need to lock the hashes. @@ -779,7 +790,12 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, dif = inet6_iif(skb); sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); while (sk) { - stack[count++] = sk; + /* If zero checksum and sk_no_check is not on for + * the socket then skip it. + */ + if (uh->check || sk->sk_no_check) + stack[count++] = sk; + sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr, uh->source, saddr, dif); if (unlikely(count == ARRAY_SIZE(stack))) { @@ -867,6 +883,12 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, if (sk != NULL) { int ret; + if (!uh->check && !sk->sk_no_check) { + sock_put(sk); + udp6_csum_zero_error(skb); + goto csum_error; + } + ret = udpv6_queue_rcv_skb(sk, skb); sock_put(sk); @@ -879,6 +901,11 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, return 0; } + if (!uh->check) { + udp6_csum_zero_error(skb); + goto csum_error; + } + if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) goto discard; @@ -1006,7 +1033,10 @@ static int udp_v6_push_pending_frames(struct sock *sk) if (is_udplite) csum = udplite_csum_outgoing(sk, skb); - else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ + else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ + skb->ip_summed = CHECKSUM_NONE; + goto send; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, up->len); goto send; @@ -1232,14 +1262,8 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, goto out; } - if (hlimit < 0) { - if (ipv6_addr_is_multicast(&fl6.daddr)) - hlimit = np->mcast_hops; - else - hlimit = np->hop_limit; - if (hlimit < 0) - hlimit = ip6_dst_hoplimit(dst); - } + if (hlimit < 0) + hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); if (tclass < 0) tclass = np->tclass; diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 19ef329bdbf8e7..b930d080c66f23 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -114,12 +114,6 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) if (err) return err; - memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); -#ifdef CONFIG_NETFILTER - IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; -#endif - - skb->protocol = htons(ETH_P_IPV6); skb->local_df = 1; return x->outer_mode->output2(x, skb); @@ -128,11 +122,13 @@ EXPORT_SYMBOL(xfrm6_prepare_output); int xfrm6_output_finish(struct sk_buff *skb) { + memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); + skb->protocol = htons(ETH_P_IPV6); + #ifdef CONFIG_NETFILTER IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; #endif - skb->protocol = htons(ETH_P_IPV6); return xfrm_output(skb); } @@ -142,6 +138,13 @@ static int __xfrm6_output(struct sk_buff *skb) struct xfrm_state *x = dst->xfrm; int mtu; +#ifdef CONFIG_NETFILTER + if (!x) { + IP6CB(skb)->flags |= IP6SKB_REROUTED; + return dst_output(skb); + } +#endif + if (skb->protocol == htons(ETH_P_IPV6)) mtu = ip6_skb_dst_mtu(skb); else @@ -165,6 +168,7 @@ static int __xfrm6_output(struct sk_buff *skb) int xfrm6_output(struct sock *sk, struct sk_buff *skb) { - return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, - skb_dst(skb)->dev, __xfrm6_output); + return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, + NULL, skb_dst(skb)->dev, __xfrm6_output, + !(IP6CB(skb)->flags & IP6SKB_REROUTED)); } diff --git a/net/ipv6/xfrm6_protocol.c b/net/ipv6/xfrm6_protocol.c index 6ab989c486f7ee..54d13f8dbbae10 100644 --- a/net/ipv6/xfrm6_protocol.c +++ b/net/ipv6/xfrm6_protocol.c @@ -50,6 +50,10 @@ int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err) { int ret; struct xfrm6_protocol *handler; + struct xfrm6_protocol __rcu **head = proto_handlers(protocol); + + if (!head) + return 0; for_each_protocol_rcu(*proto_handlers(protocol), handler) if ((ret = handler->cb_handler(skb, err)) <= 0) @@ -184,10 +188,12 @@ int xfrm6_protocol_register(struct xfrm6_protocol *handler, struct xfrm6_protocol __rcu **pprev; struct xfrm6_protocol *t; bool add_netproto = false; - int ret = -EEXIST; int priority = handler->priority; + if (!proto_handlers(protocol) || !netproto(protocol)) + return -EINVAL; + mutex_lock(&xfrm6_protocol_mutex); if (!rcu_dereference_protected(*proto_handlers(protocol), @@ -230,6 +236,9 @@ int xfrm6_protocol_deregister(struct xfrm6_protocol *handler, struct xfrm6_protocol *t; int ret = -ENOENT; + if (!proto_handlers(protocol) || !netproto(protocol)) + return -EINVAL; + mutex_lock(&xfrm6_protocol_mutex); for (pprev = proto_handlers(protocol); diff --git a/net/key/af_key.c b/net/key/af_key.c index f3c83073afc49f..b47f8e542aae96 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1476,9 +1476,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, const struct sadb_msg else err = xfrm_state_update(x); - xfrm_audit_state_add(x, err ? 0 : 1, - audit_get_loginuid(current), - audit_get_sessionid(current), 0); + xfrm_audit_state_add(x, err ? 0 : 1, true); if (err < 0) { x->km.state = XFRM_STATE_DEAD; @@ -1532,9 +1530,7 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, const struct sadb_ c.event = XFRM_MSG_DELSA; km_state_notify(x, &c); out: - xfrm_audit_state_delete(x, err ? 0 : 1, - audit_get_loginuid(current), - audit_get_sessionid(current), 0); + xfrm_audit_state_delete(x, err ? 0 : 1, true); xfrm_state_put(x); return err; @@ -1726,17 +1722,13 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, const struct sadb_m struct net *net = sock_net(sk); unsigned int proto; struct km_event c; - struct xfrm_audit audit_info; int err, err2; proto = pfkey_satype2proto(hdr->sadb_msg_satype); if (proto == 0) return -EINVAL; - audit_info.loginuid = audit_get_loginuid(current); - audit_info.sessionid = audit_get_sessionid(current); - audit_info.secid = 0; - err = xfrm_state_flush(net, proto, &audit_info); + err = xfrm_state_flush(net, proto, true); err2 = unicast_flush_resp(sk, hdr); if (err || err2) { if (err == -ESRCH) /* empty table - go quietly */ @@ -2288,9 +2280,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, const struct sadb_ err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp, hdr->sadb_msg_type != SADB_X_SPDUPDATE); - xfrm_audit_policy_add(xp, err ? 0 : 1, - audit_get_loginuid(current), - audit_get_sessionid(current), 0); + xfrm_audit_policy_add(xp, err ? 0 : 1, true); if (err) goto out; @@ -2372,9 +2362,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sa if (xp == NULL) return -ENOENT; - xfrm_audit_policy_delete(xp, err ? 0 : 1, - audit_get_loginuid(current), - audit_get_sessionid(current), 0); + xfrm_audit_policy_delete(xp, err ? 0 : 1, true); if (err) goto out; @@ -2622,9 +2610,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, const struct sadb_ return -ENOENT; if (delete) { - xfrm_audit_policy_delete(xp, err ? 0 : 1, - audit_get_loginuid(current), - audit_get_sessionid(current), 0); + xfrm_audit_policy_delete(xp, err ? 0 : 1, true); if (err) goto out; @@ -2733,13 +2719,9 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, const struct sad { struct net *net = sock_net(sk); struct km_event c; - struct xfrm_audit audit_info; int err, err2; - audit_info.loginuid = audit_get_loginuid(current); - audit_info.sessionid = audit_get_sessionid(current); - audit_info.secid = 0; - err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); + err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, true); err2 = unicast_flush_resp(sk, hdr); if (err || err2) { if (err == -ESRCH) /* empty table - old silent behavior */ diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 7704ea9502fdc9..e472d44a3b91eb 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -605,14 +605,8 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk, goto out; } - if (hlimit < 0) { - if (ipv6_addr_is_multicast(&fl6.daddr)) - hlimit = np->mcast_hops; - else - hlimit = np->hop_limit; - if (hlimit < 0) - hlimit = ip6_dst_hoplimit(dst); - } + if (hlimit < 0) + hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); if (tclass < 0) tclass = np->tclass; diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index 7c7df475a40169..ec24378caaafaf 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c @@ -23,12 +23,13 @@ void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, u8 *data, size_t data_len, u8 *mic) { struct scatterlist assoc, pt, ct[2]; - struct { - struct aead_request req; - u8 priv[crypto_aead_reqsize(tfm)]; - } aead_req; - memset(&aead_req, 0, sizeof(aead_req)); + char aead_req_data[sizeof(struct aead_request) + + crypto_aead_reqsize(tfm)] + __aligned(__alignof__(struct aead_request)); + struct aead_request *aead_req = (void *) aead_req_data; + + memset(aead_req, 0, sizeof(aead_req_data)); sg_init_one(&pt, data, data_len); sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); @@ -36,23 +37,23 @@ void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, sg_set_buf(&ct[0], data, data_len); sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN); - aead_request_set_tfm(&aead_req.req, tfm); - aead_request_set_assoc(&aead_req.req, &assoc, assoc.length); - aead_request_set_crypt(&aead_req.req, &pt, ct, data_len, b_0); + aead_request_set_tfm(aead_req, tfm); + aead_request_set_assoc(aead_req, &assoc, assoc.length); + aead_request_set_crypt(aead_req, &pt, ct, data_len, b_0); - crypto_aead_encrypt(&aead_req.req); + crypto_aead_encrypt(aead_req); } int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, u8 *data, size_t data_len, u8 *mic) { struct scatterlist assoc, pt, ct[2]; - struct { - struct aead_request req; - u8 priv[crypto_aead_reqsize(tfm)]; - } aead_req; + char aead_req_data[sizeof(struct aead_request) + + crypto_aead_reqsize(tfm)] + __aligned(__alignof__(struct aead_request)); + struct aead_request *aead_req = (void *) aead_req_data; - memset(&aead_req, 0, sizeof(aead_req)); + memset(aead_req, 0, sizeof(aead_req_data)); sg_init_one(&pt, data, data_len); sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); @@ -60,12 +61,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, sg_set_buf(&ct[0], data, data_len); sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN); - aead_request_set_tfm(&aead_req.req, tfm); - aead_request_set_assoc(&aead_req.req, &assoc, assoc.length); - aead_request_set_crypt(&aead_req.req, ct, &pt, + aead_request_set_tfm(aead_req, tfm); + aead_request_set_assoc(aead_req, &assoc, assoc.length); + aead_request_set_crypt(aead_req, ct, &pt, data_len + IEEE80211_CCMP_MIC_LEN, b_0); - return crypto_aead_decrypt(&aead_req.req); + return crypto_aead_decrypt(aead_req); } struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[]) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index aaa59d719592c0..7b8d3cf8957407 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -109,6 +109,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, static int ieee80211_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) { + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + int ret; + + mutex_lock(&sdata->local->chanctx_mtx); + ret = ieee80211_check_combinations(sdata, NULL, 0, 0); + mutex_unlock(&sdata->local->chanctx_mtx); + if (ret < 0) + return ret; + return ieee80211_do_open(wdev, true); } @@ -972,13 +981,13 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, sdata->needed_rx_chains = sdata->local->rx_chains; mutex_lock(&local->mtx); - sdata->radar_required = params->radar_required; err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, IEEE80211_CHANCTX_SHARED); + if (!err) + ieee80211_vif_copy_chanctx_to_vlans(sdata, false); mutex_unlock(&local->mtx); if (err) return err; - ieee80211_vif_copy_chanctx_to_vlans(sdata, false); /* * Apply control port protocol, this allows us to @@ -1131,8 +1140,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); skb_queue_purge(&sdata->u.ap.ps.bc_buf); - ieee80211_vif_copy_chanctx_to_vlans(sdata, true); mutex_lock(&local->mtx); + ieee80211_vif_copy_chanctx_to_vlans(sdata, true); ieee80211_vif_release_channel(sdata); mutex_unlock(&local->mtx); @@ -1566,7 +1575,7 @@ static int ieee80211_change_station(struct wiphy *wiphy, if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sta->sdata->u.vlan.sta) { - rcu_assign_pointer(sta->sdata->u.vlan.sta, NULL); + RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL); prev_4addr = true; } @@ -2930,7 +2939,6 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, /* whatever, but channel contexts should not complain about that one */ sdata->smps_mode = IEEE80211_SMPS_OFF; sdata->needed_rx_chains = local->rx_chains; - sdata->radar_required = true; err = ieee80211_vif_use_channel(sdata, chandef, IEEE80211_CHANCTX_SHARED); @@ -3217,7 +3225,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; - struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *chanctx; int err, num_chanctx, changed = 0; @@ -3233,23 +3241,24 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, &sdata->vif.bss_conf.chandef)) return -EINVAL; - rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); - if (!chanctx_conf) { - rcu_read_unlock(); + mutex_lock(&local->chanctx_mtx); + conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (!conf) { + mutex_unlock(&local->chanctx_mtx); return -EBUSY; } /* don't handle for multi-VIF cases */ - chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); - if (chanctx->refcount > 1) { - rcu_read_unlock(); + chanctx = container_of(conf, struct ieee80211_chanctx, conf); + if (ieee80211_chanctx_refcount(local, chanctx) > 1) { + mutex_unlock(&local->chanctx_mtx); return -EBUSY; } num_chanctx = 0; list_for_each_entry_rcu(chanctx, &local->chanctx_list, list) num_chanctx++; - rcu_read_unlock(); + mutex_unlock(&local->chanctx_mtx); if (num_chanctx > 1) return -EBUSY; @@ -3949,6 +3958,21 @@ static int ieee80211_set_qos_map(struct wiphy *wiphy, return 0; } +static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int ret; + u32 changed = 0; + + ret = ieee80211_vif_change_bandwidth(sdata, chandef, &changed); + if (ret == 0) + ieee80211_bss_info_change_notify(sdata, changed); + + return ret; +} + const struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -4029,4 +4053,5 @@ const struct cfg80211_ops mac80211_config_ops = { .start_radar_detection = ieee80211_start_radar_detection, .channel_switch = ieee80211_channel_switch, .set_qos_map = ieee80211_set_qos_map, + .set_ap_chanwidth = ieee80211_set_ap_chanwidth, }; diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 75b5dd2c9267f1..48e6d6f010cd0f 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -9,6 +9,170 @@ #include "ieee80211_i.h" #include "driver-ops.h" +static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) +{ + struct ieee80211_sub_if_data *sdata; + int num = 0; + + lockdep_assert_held(&local->chanctx_mtx); + + list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list) + num++; + + return num; +} + +static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) +{ + struct ieee80211_sub_if_data *sdata; + int num = 0; + + lockdep_assert_held(&local->chanctx_mtx); + + list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) + num++; + + return num; +} + +int ieee80211_chanctx_refcount(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) +{ + return ieee80211_chanctx_num_assigned(local, ctx) + + ieee80211_chanctx_num_reserved(local, ctx); +} + +static int ieee80211_num_chanctx(struct ieee80211_local *local) +{ + struct ieee80211_chanctx *ctx; + int num = 0; + + lockdep_assert_held(&local->chanctx_mtx); + + list_for_each_entry(ctx, &local->chanctx_list, list) + num++; + + return num; +} + +static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local) +{ + lockdep_assert_held(&local->chanctx_mtx); + return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local); +} + +static const struct cfg80211_chan_def * +ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx, + const struct cfg80211_chan_def *compat) +{ + struct ieee80211_sub_if_data *sdata; + + lockdep_assert_held(&local->chanctx_mtx); + + list_for_each_entry(sdata, &ctx->reserved_vifs, + reserved_chanctx_list) { + if (!compat) + compat = &sdata->reserved_chandef; + + compat = cfg80211_chandef_compatible(&sdata->reserved_chandef, + compat); + if (!compat) + break; + } + + return compat; +} + +static const struct cfg80211_chan_def * +ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx, + const struct cfg80211_chan_def *compat) +{ + struct ieee80211_sub_if_data *sdata; + + lockdep_assert_held(&local->chanctx_mtx); + + list_for_each_entry(sdata, &ctx->assigned_vifs, + assigned_chanctx_list) { + if (sdata->reserved_chanctx != NULL) + continue; + + if (!compat) + compat = &sdata->vif.bss_conf.chandef; + + compat = cfg80211_chandef_compatible( + &sdata->vif.bss_conf.chandef, compat); + if (!compat) + break; + } + + return compat; +} + +static const struct cfg80211_chan_def * +ieee80211_chanctx_combined_chandef(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx, + const struct cfg80211_chan_def *compat) +{ + lockdep_assert_held(&local->chanctx_mtx); + + compat = ieee80211_chanctx_reserved_chandef(local, ctx, compat); + if (!compat) + return NULL; + + compat = ieee80211_chanctx_non_reserved_chandef(local, ctx, compat); + if (!compat) + return NULL; + + return compat; +} + +static bool +ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx, + const struct cfg80211_chan_def *def) +{ + lockdep_assert_held(&local->chanctx_mtx); + + if (ieee80211_chanctx_combined_chandef(local, ctx, def)) + return true; + + if (!list_empty(&ctx->reserved_vifs) && + ieee80211_chanctx_reserved_chandef(local, ctx, def)) + return true; + + return false; +} + +static struct ieee80211_chanctx * +ieee80211_find_reservation_chanctx(struct ieee80211_local *local, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode) +{ + struct ieee80211_chanctx *ctx; + + lockdep_assert_held(&local->chanctx_mtx); + + if (mode == IEEE80211_CHANCTX_EXCLUSIVE) + return NULL; + + list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) + continue; + + if (!ieee80211_chanctx_can_reserve_chandef(local, ctx, + chandef)) + continue; + + return ctx; + } + + return NULL; +} + static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta) { switch (sta->bandwidth) { @@ -190,6 +354,11 @@ ieee80211_find_chanctx(struct ieee80211_local *local, if (!compat) continue; + compat = ieee80211_chanctx_reserved_chandef(local, ctx, + compat); + if (!compat) + continue; + ieee80211_change_chanctx(local, ctx, compat); return ctx; @@ -217,62 +386,91 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local) } static struct ieee80211_chanctx * -ieee80211_new_chanctx(struct ieee80211_local *local, - const struct cfg80211_chan_def *chandef, - enum ieee80211_chanctx_mode mode) +ieee80211_alloc_chanctx(struct ieee80211_local *local, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode) { struct ieee80211_chanctx *ctx; - u32 changed; - int err; lockdep_assert_held(&local->chanctx_mtx); ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL); if (!ctx) - return ERR_PTR(-ENOMEM); + return NULL; + INIT_LIST_HEAD(&ctx->assigned_vifs); + INIT_LIST_HEAD(&ctx->reserved_vifs); ctx->conf.def = *chandef; ctx->conf.rx_chains_static = 1; ctx->conf.rx_chains_dynamic = 1; ctx->mode = mode; ctx->conf.radar_enabled = ieee80211_is_radar_required(local); ieee80211_recalc_chanctx_min_def(local, ctx); + + return ctx; +} + +static int ieee80211_add_chanctx(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) +{ + u32 changed; + int err; + + lockdep_assert_held(&local->mtx); + lockdep_assert_held(&local->chanctx_mtx); + if (!local->use_chanctx) local->hw.conf.radar_enabled = ctx->conf.radar_enabled; - /* we hold the mutex to prevent idle from changing */ - lockdep_assert_held(&local->mtx); /* turn idle off *before* setting channel -- some drivers need that */ changed = ieee80211_idle_off(local); if (changed) ieee80211_hw_config(local, changed); if (!local->use_chanctx) { - local->_oper_chandef = *chandef; + local->_oper_chandef = ctx->conf.def; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); } else { err = drv_add_chanctx(local, ctx); if (err) { - kfree(ctx); ieee80211_recalc_idle(local); - return ERR_PTR(err); + return err; } } - /* and keep the mutex held until the new chanctx is on the list */ - list_add_rcu(&ctx->list, &local->chanctx_list); + return 0; +} + +static struct ieee80211_chanctx * +ieee80211_new_chanctx(struct ieee80211_local *local, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode) +{ + struct ieee80211_chanctx *ctx; + int err; + + lockdep_assert_held(&local->mtx); + lockdep_assert_held(&local->chanctx_mtx); + ctx = ieee80211_alloc_chanctx(local, chandef, mode); + if (!ctx) + return ERR_PTR(-ENOMEM); + + err = ieee80211_add_chanctx(local, ctx); + if (err) { + kfree(ctx); + return ERR_PTR(err); + } + + list_add_rcu(&ctx->list, &local->chanctx_list); return ctx; } -static void ieee80211_free_chanctx(struct ieee80211_local *local, - struct ieee80211_chanctx *ctx) +static void ieee80211_del_chanctx(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) { - bool check_single_channel = false; lockdep_assert_held(&local->chanctx_mtx); - WARN_ON_ONCE(ctx->refcount != 0); - if (!local->use_chanctx) { struct cfg80211_chan_def *chandef = &local->_oper_chandef; chandef->width = NL80211_CHAN_WIDTH_20_NOHT; @@ -282,8 +480,9 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, /* NOTE: Disabling radar is only valid here for * single channel context. To be sure, check it ... */ - if (local->hw.conf.radar_enabled) - check_single_channel = true; + WARN_ON(local->hw.conf.radar_enabled && + !list_empty(&local->chanctx_list)); + local->hw.conf.radar_enabled = false; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); @@ -291,39 +490,19 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, drv_remove_chanctx(local, ctx); } - list_del_rcu(&ctx->list); - kfree_rcu(ctx, rcu_head); - - /* throw a warning if this wasn't the only channel context. */ - WARN_ON(check_single_channel && !list_empty(&local->chanctx_list)); - ieee80211_recalc_idle(local); } -static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, - struct ieee80211_chanctx *ctx) +static void ieee80211_free_chanctx(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) { - struct ieee80211_local *local = sdata->local; - int ret; - lockdep_assert_held(&local->chanctx_mtx); - ret = drv_assign_vif_chanctx(local, sdata, ctx); - if (ret) - return ret; - - rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); - ctx->refcount++; - - ieee80211_recalc_txpower(sdata); - ieee80211_recalc_chanctx_min_def(local, ctx); - sdata->vif.bss_conf.idle = false; + WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0); - if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && - sdata->vif.type != NL80211_IFTYPE_MONITOR) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); - - return 0; + list_del_rcu(&ctx->list); + ieee80211_del_chanctx(local, ctx); + kfree_rcu(ctx, rcu_head); } static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, @@ -384,30 +563,58 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR); } -static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, - struct ieee80211_chanctx *ctx) +static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, + struct ieee80211_chanctx *new_ctx) { struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *conf; + struct ieee80211_chanctx *curr_ctx = NULL; + int ret = 0; - lockdep_assert_held(&local->chanctx_mtx); + conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); - ctx->refcount--; - rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); + if (conf) { + curr_ctx = container_of(conf, struct ieee80211_chanctx, conf); - sdata->vif.bss_conf.idle = true; + drv_unassign_vif_chanctx(local, sdata, curr_ctx); + conf = NULL; + list_del(&sdata->assigned_chanctx_list); + } - if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && - sdata->vif.type != NL80211_IFTYPE_MONITOR) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); + if (new_ctx) { + ret = drv_assign_vif_chanctx(local, sdata, new_ctx); + if (ret) + goto out; - drv_unassign_vif_chanctx(local, sdata, ctx); + conf = &new_ctx->conf; + list_add(&sdata->assigned_chanctx_list, + &new_ctx->assigned_vifs); + } - if (ctx->refcount > 0) { - ieee80211_recalc_chanctx_chantype(sdata->local, ctx); - ieee80211_recalc_smps_chanctx(local, ctx); - ieee80211_recalc_radar_chanctx(local, ctx); - ieee80211_recalc_chanctx_min_def(local, ctx); +out: + rcu_assign_pointer(sdata->vif.chanctx_conf, conf); + + sdata->vif.bss_conf.idle = !conf; + + if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) { + ieee80211_recalc_chanctx_chantype(local, curr_ctx); + ieee80211_recalc_smps_chanctx(local, curr_ctx); + ieee80211_recalc_radar_chanctx(local, curr_ctx); + ieee80211_recalc_chanctx_min_def(local, curr_ctx); } + + if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) { + ieee80211_recalc_txpower(sdata); + ieee80211_recalc_chanctx_min_def(local, new_ctx); + } + + if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && + sdata->vif.type != NL80211_IFTYPE_MONITOR) + ieee80211_bss_info_change_notify(sdata, + BSS_CHANGED_IDLE); + + return ret; } static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) @@ -425,8 +632,11 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) ctx = container_of(conf, struct ieee80211_chanctx, conf); - ieee80211_unassign_vif_chanctx(sdata, ctx); - if (ctx->refcount == 0) + if (sdata->reserved_chanctx) + ieee80211_vif_unreserve_chanctx(sdata); + + ieee80211_assign_vif_chanctx(sdata, NULL); + if (ieee80211_chanctx_refcount(local, ctx) == 0) ieee80211_free_chanctx(local, ctx); } @@ -526,6 +736,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *ctx; + u8 radar_detect_width = 0; int ret; lockdep_assert_held(&local->mtx); @@ -533,6 +744,22 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); mutex_lock(&local->chanctx_mtx); + + ret = cfg80211_chandef_dfs_required(local->hw.wiphy, + chandef, + sdata->wdev.iftype); + if (ret < 0) + goto out; + if (ret > 0) + radar_detect_width = BIT(chandef->width); + + sdata->radar_required = ret; + + ret = ieee80211_check_combinations(sdata, chandef, mode, + radar_detect_width); + if (ret < 0) + goto out; + __ieee80211_vif_release_channel(sdata); ctx = ieee80211_find_chanctx(local, chandef, mode); @@ -548,7 +775,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, ret = ieee80211_assign_vif_chanctx(sdata, ctx); if (ret) { /* if assign fails refcount stays the same */ - if (ctx->refcount == 0) + if (ieee80211_chanctx_refcount(local, ctx) == 0) ieee80211_free_chanctx(local, ctx); goto out; } @@ -560,15 +787,47 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, return ret; } +static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, + struct ieee80211_chanctx *ctx, + u32 *changed) +{ + struct ieee80211_local *local = sdata->local; + const struct cfg80211_chan_def *chandef = &sdata->csa_chandef; + u32 chanctx_changed = 0; + + if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, + IEEE80211_CHAN_DISABLED)) + return -EINVAL; + + if (ieee80211_chanctx_refcount(local, ctx) != 1) + return -EINVAL; + + if (sdata->vif.bss_conf.chandef.width != chandef->width) { + chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH; + *changed |= BSS_CHANGED_BANDWIDTH; + } + + sdata->vif.bss_conf.chandef = *chandef; + ctx->conf.def = *chandef; + + chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; + drv_change_chanctx(local, ctx, chanctx_changed); + + ieee80211_recalc_chanctx_chantype(local, ctx); + ieee80211_recalc_smps_chanctx(local, ctx); + ieee80211_recalc_radar_chanctx(local, ctx); + ieee80211_recalc_chanctx_min_def(local, ctx); + + return 0; +} + int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, u32 *changed) { struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; - const struct cfg80211_chan_def *chandef = &sdata->csa_chandef; int ret; - u32 chanctx_changed = 0; lockdep_assert_held(&local->mtx); @@ -576,11 +835,94 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!sdata->vif.csa_active)) return -EINVAL; - if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, - IEEE80211_CHAN_DISABLED)) + mutex_lock(&local->chanctx_mtx); + conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (!conf) { + ret = -EINVAL; + goto out; + } + + ctx = container_of(conf, struct ieee80211_chanctx, conf); + + ret = __ieee80211_vif_change_channel(sdata, ctx, changed); + out: + mutex_unlock(&local->chanctx_mtx); + return ret; +} + +static void +__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, + bool clear) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_sub_if_data *vlan; + struct ieee80211_chanctx_conf *conf; + + if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP)) + return; + + lockdep_assert_held(&local->mtx); + + /* Check that conf exists, even when clearing this function + * must be called with the AP's channel context still there + * as it would otherwise cause VLANs to have an invalid + * channel context pointer for a while, possibly pointing + * to a channel context that has already been freed. + */ + conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + WARN_ON(!conf); + + if (clear) + conf = NULL; + + list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) + rcu_assign_pointer(vlan->vif.chanctx_conf, conf); +} + +void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, + bool clear) +{ + struct ieee80211_local *local = sdata->local; + + mutex_lock(&local->chanctx_mtx); + + __ieee80211_vif_copy_chanctx_to_vlans(sdata, clear); + + mutex_unlock(&local->chanctx_mtx); +} + +int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_chanctx *ctx = sdata->reserved_chanctx; + + lockdep_assert_held(&sdata->local->chanctx_mtx); + + if (WARN_ON(!ctx)) return -EINVAL; + list_del(&sdata->reserved_chanctx_list); + sdata->reserved_chanctx = NULL; + + if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) + ieee80211_free_chanctx(sdata->local, ctx); + + return 0; +} + +int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode, + bool radar_required) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *conf; + struct ieee80211_chanctx *new_ctx, *curr_ctx; + int ret = 0; + mutex_lock(&local->chanctx_mtx); + conf = rcu_dereference_protected(sdata->vif.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) { @@ -588,30 +930,108 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, goto out; } - ctx = container_of(conf, struct ieee80211_chanctx, conf); - if (ctx->refcount != 1) { + curr_ctx = container_of(conf, struct ieee80211_chanctx, conf); + + new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode); + if (!new_ctx) { + if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 && + (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) { + /* if we're the only users of the chanctx and + * the driver supports changing a running + * context, reserve our current context + */ + new_ctx = curr_ctx; + } else if (ieee80211_can_create_new_chanctx(local)) { + /* create a new context and reserve it */ + new_ctx = ieee80211_new_chanctx(local, chandef, mode); + if (IS_ERR(new_ctx)) { + ret = PTR_ERR(new_ctx); + goto out; + } + } else { + ret = -EBUSY; + goto out; + } + } + + list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs); + sdata->reserved_chanctx = new_ctx; + sdata->reserved_chandef = *chandef; + sdata->reserved_radar_required = radar_required; +out: + mutex_unlock(&local->chanctx_mtx); + return ret; +} + +int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata, + u32 *changed) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx *ctx; + struct ieee80211_chanctx *old_ctx; + struct ieee80211_chanctx_conf *conf; + int ret; + u32 tmp_changed = *changed; + + /* TODO: need to recheck if the chandef is usable etc.? */ + + lockdep_assert_held(&local->mtx); + + mutex_lock(&local->chanctx_mtx); + + ctx = sdata->reserved_chanctx; + if (WARN_ON(!ctx)) { ret = -EINVAL; goto out; } - if (sdata->vif.bss_conf.chandef.width != chandef->width) { - chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH; - *changed |= BSS_CHANGED_BANDWIDTH; + conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (!conf) { + ret = -EINVAL; + goto out; } - sdata->vif.bss_conf.chandef = *chandef; - ctx->conf.def = *chandef; + old_ctx = container_of(conf, struct ieee80211_chanctx, conf); - chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; - drv_change_chanctx(local, ctx, chanctx_changed); + if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width) + tmp_changed |= BSS_CHANGED_BANDWIDTH; + + sdata->vif.bss_conf.chandef = sdata->reserved_chandef; + + /* unref our reservation */ + sdata->reserved_chanctx = NULL; + sdata->radar_required = sdata->reserved_radar_required; + list_del(&sdata->reserved_chanctx_list); + + if (old_ctx == ctx) { + /* This is our own context, just change it */ + ret = __ieee80211_vif_change_channel(sdata, old_ctx, + &tmp_changed); + if (ret) + goto out; + } else { + ret = ieee80211_assign_vif_chanctx(sdata, ctx); + if (ieee80211_chanctx_refcount(local, old_ctx) == 0) + ieee80211_free_chanctx(local, old_ctx); + if (ret) { + /* if assign fails refcount stays the same */ + if (ieee80211_chanctx_refcount(local, ctx) == 0) + ieee80211_free_chanctx(local, ctx); + goto out; + } + + if (sdata->vif.type == NL80211_IFTYPE_AP) + __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); + } + + *changed = tmp_changed; ieee80211_recalc_chanctx_chantype(local, ctx); ieee80211_recalc_smps_chanctx(local, ctx); ieee80211_recalc_radar_chanctx(local, ctx); ieee80211_recalc_chanctx_min_def(local, ctx); - - ret = 0; - out: +out: mutex_unlock(&local->chanctx_mtx); return ret; } @@ -695,40 +1115,6 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata) mutex_unlock(&local->chanctx_mtx); } -void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, - bool clear) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_sub_if_data *vlan; - struct ieee80211_chanctx_conf *conf; - - ASSERT_RTNL(); - - if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP)) - return; - - mutex_lock(&local->chanctx_mtx); - - /* - * Check that conf exists, even when clearing this function - * must be called with the AP's channel context still there - * as it would otherwise cause VLANs to have an invalid - * channel context pointer for a while, possibly pointing - * to a channel context that has already been freed. - */ - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, - lockdep_is_held(&local->chanctx_mtx)); - WARN_ON(!conf); - - if (clear) - conf = NULL; - - list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) - rcu_assign_pointer(vlan->vif.chanctx_conf, conf); - - mutex_unlock(&local->chanctx_mtx); -} - void ieee80211_iter_chan_contexts_atomic( struct ieee80211_hw *hw, void (*iter)(struct ieee80211_hw *hw, diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index fa16e54980a1d3..0e963bc1ceac31 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -128,7 +128,7 @@ static ssize_t sta_tx_latency_stat_write(struct file *file, if (!strcmp(buf, TX_LATENCY_DISABLED)) { if (!tx_latency) goto unlock; - rcu_assign_pointer(local->tx_latency, NULL); + RCU_INIT_POINTER(local->tx_latency, NULL); synchronize_rcu(); kfree(tx_latency); goto unlock; diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h index 214ed4ecd739f1..60c35afee29d55 100644 --- a/net/mac80211/debugfs.h +++ b/net/mac80211/debugfs.h @@ -1,6 +1,8 @@ #ifndef __MAC80211_DEBUGFS_H #define __MAC80211_DEBUGFS_H +#include "ieee80211_i.h" + #ifdef CONFIG_MAC80211_DEBUGFS void debugfs_hw_add(struct ieee80211_local *local); int __printf(4, 5) mac80211_format_buffer(char __user *userbuf, size_t count, diff --git a/net/mac80211/debugfs_netdev.h b/net/mac80211/debugfs_netdev.h index 79025e79f4d645..9f5501a9a79506 100644 --- a/net/mac80211/debugfs_netdev.h +++ b/net/mac80211/debugfs_netdev.h @@ -3,6 +3,8 @@ #ifndef __IEEE80211_DEBUGFS_NETDEV_H #define __IEEE80211_DEBUGFS_NETDEV_H +#include "ieee80211_i.h" + #ifdef CONFIG_MAC80211_DEBUGFS void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata); void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index fc689f5d971e25..5331582a2c8171 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -726,13 +726,19 @@ static inline void drv_rfkill_poll(struct ieee80211_local *local) } static inline void drv_flush(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, u32 queues, bool drop) { + struct ieee80211_vif *vif = sdata ? &sdata->vif : NULL; + might_sleep(); + if (sdata) + check_sdata_in_driver(sdata); + trace_drv_flush(local, queues, drop); if (local->ops->flush) - local->ops->flush(&local->hw, queues, drop); + local->ops->flush(&local->hw, vif, queues, drop); trace_drv_return_void(local); } diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index c150b68436d78a..15702ff64a4c89 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -31,6 +31,18 @@ static void __check_htcap_disable(struct ieee80211_ht_cap *ht_capa, } } +static void __check_htcap_enable(struct ieee80211_ht_cap *ht_capa, + struct ieee80211_ht_cap *ht_capa_mask, + struct ieee80211_sta_ht_cap *ht_cap, + u16 flag) +{ + __le16 le_flag = cpu_to_le16(flag); + + if ((ht_capa_mask->cap_info & le_flag) && + (ht_capa->cap_info & le_flag)) + ht_cap->cap |= flag; +} + void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, struct ieee80211_sta_ht_cap *ht_cap) { @@ -59,7 +71,7 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, smask = (u8 *)(&ht_capa_mask->mcs.rx_mask); /* NOTE: If you add more over-rides here, update register_hw - * ht_capa_mod_msk logic in main.c as well. + * ht_capa_mod_mask logic in main.c as well. * And, if this method can ever change ht_cap.ht_supported, fix * the check in ieee80211_add_ht_ie. */ @@ -86,6 +98,14 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap, IEEE80211_HT_CAP_MAX_AMSDU); + /* Allow user to disable LDPC */ + __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap, + IEEE80211_HT_CAP_LDPC_CODING); + + /* Allow user to enable 40 MHz intolerant bit. */ + __check_htcap_enable(ht_capa, ht_capa_mask, ht_cap, + IEEE80211_HT_CAP_40MHZ_INTOLERANT); + /* Allow user to decrease AMPDU factor */ if (ht_capa_mask->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_FACTOR) { diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 06d28787945b51..ff4d4155a84d26 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -228,7 +228,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct beacon_data *presp; enum nl80211_bss_scan_width scan_width; bool have_higher_than_11mbit; - bool radar_required = false; + bool radar_required; int err; sdata_assert_lock(sdata); @@ -253,7 +253,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, presp = rcu_dereference_protected(ifibss->presp, lockdep_is_held(&sdata->wdev.mtx)); - rcu_assign_pointer(ifibss->presp, NULL); + RCU_INIT_POINTER(ifibss->presp, NULL); if (presp) kfree_rcu(presp, rcu_head); @@ -262,7 +262,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, /* make a copy of the chandef, it could be modified below. */ chandef = *req_chandef; chan = chandef.chan; - if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { + if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef, + NL80211_IFTYPE_ADHOC)) { if (chandef.width == NL80211_CHAN_WIDTH_5 || chandef.width == NL80211_CHAN_WIDTH_10 || chandef.width == NL80211_CHAN_WIDTH_20_NOHT || @@ -274,7 +275,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, chandef.width = NL80211_CHAN_WIDTH_20; chandef.center_freq1 = chan->center_freq; /* check again for downgraded chandef */ - if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { + if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef, + NL80211_IFTYPE_ADHOC)) { sdata_info(sdata, "Failed to join IBSS, beacons forbidden\n"); return; @@ -282,21 +284,20 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, } err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, - &chandef); + &chandef, NL80211_IFTYPE_ADHOC); if (err < 0) { sdata_info(sdata, "Failed to join IBSS, invalid chandef\n"); return; } - if (err > 0) { - if (!ifibss->userspace_handles_dfs) { - sdata_info(sdata, - "Failed to join IBSS, DFS channel without control program\n"); - return; - } - radar_required = true; + if (err > 0 && !ifibss->userspace_handles_dfs) { + sdata_info(sdata, + "Failed to join IBSS, DFS channel without control program\n"); + return; } + radar_required = err; + mutex_lock(&local->mtx); if (ieee80211_vif_use_channel(sdata, &chandef, ifibss->fixed_channel ? @@ -775,7 +776,8 @@ static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata) * unavailable. */ err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, - &ifibss->chandef); + &ifibss->chandef, + NL80211_IFTYPE_ADHOC); if (err > 0) cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef, GFP_ATOMIC); @@ -861,7 +863,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, goto disconnect; } - if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, ¶ms.chandef)) { + if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, ¶ms.chandef, + NL80211_IFTYPE_ADHOC)) { sdata_info(sdata, "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", ifibss->bssid, @@ -873,17 +876,17 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, } err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, - ¶ms.chandef); + ¶ms.chandef, + NL80211_IFTYPE_ADHOC); if (err < 0) goto disconnect; - if (err) { + if (err > 0 && !ifibss->userspace_handles_dfs) { /* IBSS-DFS only allowed with a control program */ - if (!ifibss->userspace_handles_dfs) - goto disconnect; - - params.radar_required = true; + goto disconnect; } + params.radar_required = err; + if (cfg80211_chandef_identical(¶ms.chandef, &sdata->vif.bss_conf.chandef)) { ibss_dbg(sdata, @@ -1636,7 +1639,33 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, u32 changed = 0; u32 rate_flags; struct ieee80211_supported_band *sband; + enum ieee80211_chanctx_mode chanmode; + struct ieee80211_local *local = sdata->local; + int radar_detect_width = 0; int i; + int ret; + + ret = cfg80211_chandef_dfs_required(local->hw.wiphy, + ¶ms->chandef, + sdata->wdev.iftype); + if (ret < 0) + return ret; + + if (ret > 0) { + if (!params->userspace_handles_dfs) + return -EINVAL; + radar_detect_width = BIT(params->chandef.width); + } + + chanmode = (params->channel_fixed && !ret) ? + IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE; + + mutex_lock(&local->chanctx_mtx); + ret = ieee80211_check_combinations(sdata, ¶ms->chandef, chanmode, + radar_detect_width); + mutex_unlock(&local->chanctx_mtx); + if (ret < 0) + return ret; if (params->bssid) { memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); @@ -1651,7 +1680,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, /* fix basic_rates if channel does not support these rates */ rate_flags = ieee80211_chandef_rate_flags(¶ms->chandef); - sband = sdata->local->hw.wiphy->bands[params->chandef.chan->band]; + sband = local->hw.wiphy->bands[params->chandef.chan->band]; for (i = 0; i < sband->n_bitrates; i++) { if ((rate_flags & sband->bitrates[i].flags) != rate_flags) sdata->u.ibss.basic_rates &= ~BIT(i); @@ -1700,9 +1729,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, ieee80211_bss_info_change_notify(sdata, changed); sdata->smps_mode = IEEE80211_SMPS_OFF; - sdata->needed_rx_chains = sdata->local->rx_chains; + sdata->needed_rx_chains = local->rx_chains; - ieee80211_queue_work(&sdata->local->hw, &sdata->work); + ieee80211_queue_work(&local->hw, &sdata->work); return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 222c28b75315f1..b455f62d357ad6 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -260,7 +260,7 @@ struct ieee80211_if_ap { /* to be used after channel switch. */ struct cfg80211_beacon_data *next_beacon; - struct list_head vlans; + struct list_head vlans; /* write-protected with RTNL and local->mtx */ struct ps_data ps; atomic_t num_mcast_sta; /* number of stations receiving multicast */ @@ -276,7 +276,7 @@ struct ieee80211_if_wds { }; struct ieee80211_if_vlan { - struct list_head list; + struct list_head list; /* write-protected with RTNL and local->mtx */ /* used for all tx if the VLAN is configured to 4-addr mode */ struct sta_info __rcu *sta; @@ -691,8 +691,10 @@ struct ieee80211_chanctx { struct list_head list; struct rcu_head rcu_head; + struct list_head assigned_vifs; + struct list_head reserved_vifs; + enum ieee80211_chanctx_mode mode; - int refcount; bool driver_present; struct ieee80211_chanctx_conf conf; @@ -756,6 +758,14 @@ struct ieee80211_sub_if_data { bool csa_radar_required; struct cfg80211_chan_def csa_chandef; + struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */ + struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */ + + /* context reservation -- protected with chanctx_mtx */ + struct ieee80211_chanctx *reserved_chanctx; + struct cfg80211_chan_def reserved_chandef; + bool reserved_radar_required; + /* used to reconfigure hardware SM PS */ struct work_struct recalc_smps; @@ -1770,6 +1780,16 @@ int __must_check ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode mode); +int __must_check +ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode, + bool radar_required); +int __must_check +ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata, + u32 *changed); +int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata); + int __must_check ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, const struct cfg80211_chan_def *chandef, @@ -1782,6 +1802,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, bool clear); +int ieee80211_chanctx_refcount(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx); void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, struct ieee80211_chanctx *chanctx); @@ -1805,6 +1827,11 @@ int ieee80211_cs_headroom(struct ieee80211_local *local, enum nl80211_iftype iftype); void ieee80211_recalc_dtim(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); +int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode chanmode, + u8 radar_detect); +int ieee80211_max_num_channels(struct ieee80211_local *local); #ifdef CONFIG_MAC80211_NOINLINE #define debug_noinline noinline diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b8d331e7d883d5..7fff3dcaac43fb 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -250,6 +250,7 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_sub_if_data *nsdata; + int ret; ASSERT_RTNL(); @@ -300,7 +301,10 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, } } - return 0; + mutex_lock(&local->chanctx_mtx); + ret = ieee80211_check_combinations(sdata, NULL, 0, 0); + mutex_unlock(&local->chanctx_mtx); + return ret; } static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata, @@ -423,7 +427,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) mutex_unlock(&local->mtx); if (ret) { mutex_lock(&local->iflist_mtx); - rcu_assign_pointer(local->monitor_sdata, NULL); + RCU_INIT_POINTER(local->monitor_sdata, NULL); mutex_unlock(&local->iflist_mtx); synchronize_net(); drv_remove_interface(local, sdata); @@ -452,7 +456,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local) return; } - rcu_assign_pointer(local->monitor_sdata, NULL); + RCU_INIT_POINTER(local->monitor_sdata, NULL); mutex_unlock(&local->iflist_mtx); synchronize_net(); @@ -492,7 +496,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) if (!sdata->bss) return -ENOLINK; + mutex_lock(&local->mtx); list_add(&sdata->u.vlan.list, &sdata->bss->vlans); + mutex_unlock(&local->mtx); master = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); @@ -722,8 +728,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) drv_stop(local); err_del_bss: sdata->bss = NULL; - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { + mutex_lock(&local->mtx); list_del(&sdata->u.vlan.list); + mutex_unlock(&local->mtx); + } /* might already be clear but that doesn't matter */ clear_bit(SDATA_STATE_RUNNING, &sdata->state); return res; @@ -875,8 +884,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: + mutex_lock(&local->mtx); list_del(&sdata->u.vlan.list); - rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); + mutex_unlock(&local->mtx); + RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL); /* no need to tell driver */ break; case NL80211_IFTYPE_MONITOR: @@ -895,7 +906,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, break; case NL80211_IFTYPE_P2P_DEVICE: /* relies on synchronize_rcu() below */ - rcu_assign_pointer(local->p2p_sdata, NULL); + RCU_INIT_POINTER(local->p2p_sdata, NULL); /* fall through */ default: cancel_work_sync(&sdata->work); @@ -1280,6 +1291,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, INIT_WORK(&sdata->work, ieee80211_iface_work); INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work); + INIT_LIST_HEAD(&sdata->assigned_chanctx_list); + INIT_LIST_HEAD(&sdata->reserved_chanctx_list); switch (type) { case NL80211_IFTYPE_P2P_GO: @@ -1774,20 +1787,19 @@ static int netdev_notify(struct notifier_block *nb, struct ieee80211_sub_if_data *sdata; if (state != NETDEV_CHANGENAME) - return 0; + return NOTIFY_DONE; if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) - return 0; + return NOTIFY_DONE; if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) - return 0; + return NOTIFY_DONE; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - memcpy(sdata->name, dev->name, IFNAMSIZ); - ieee80211_debugfs_rename_netdev(sdata); - return 0; + + return NOTIFY_OK; } static struct notifier_block mac80211_netdev_notifier = { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 4c1bf61bc77868..27b9364cdf177d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -340,7 +340,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, sdata_unlock(sdata); - return NOTIFY_DONE; + return NOTIFY_OK; } #endif @@ -371,7 +371,7 @@ static int ieee80211_ifa6_changed(struct notifier_block *nb, drv_ipv6_addr_change(local, sdata, idev); - return NOTIFY_DONE; + return NOTIFY_OK; } #endif @@ -446,7 +446,9 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_MAX_AMSDU | IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_SGI_40), + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_40MHZ_INTOLERANT), .mcs = { .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index f70e9cd10552da..b06ddc9519ce07 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -366,20 +366,15 @@ int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) return 0; /* find RSN IE */ - data = ifmsh->ie; - while (data < ifmsh->ie + ifmsh->ie_len) { - if (*data == WLAN_EID_RSN) { - len = data[1] + 2; - break; - } - data++; - } + data = cfg80211_find_ie(WLAN_EID_RSN, ifmsh->ie, ifmsh->ie_len); + if (!data) + return 0; - if (len) { - if (skb_tailroom(skb) < len) - return -ENOMEM; - memcpy(skb_put(skb, len), data, len); - } + len = data[1] + 2; + + if (skb_tailroom(skb) < len) + return -ENOMEM; + memcpy(skb_put(skb, len), data, len); return 0; } @@ -829,7 +824,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); bcn = rcu_dereference_protected(ifmsh->beacon, lockdep_is_held(&sdata->wdev.mtx)); - rcu_assign_pointer(ifmsh->beacon, NULL); + RCU_INIT_POINTER(ifmsh->beacon, NULL); kfree_rcu(bcn, rcu_head); /* flush STAs and mpaths on this iface */ @@ -903,14 +898,15 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, } err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, - ¶ms.chandef); + ¶ms.chandef, + NL80211_IFTYPE_MESH_POINT); if (err < 0) return false; - if (err) { - params.radar_required = true; + if (err > 0) /* TODO: DFS not (yet) supported */ return false; - } + + params.radar_required = err; if (cfg80211_chandef_identical(¶ms.chandef, &sdata->vif.bss_conf.chandef)) { @@ -1068,7 +1064,7 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) /* Remove the CSA and MCSP elements from the beacon */ tmp_csa_settings = rcu_dereference(ifmsh->csa); - rcu_assign_pointer(ifmsh->csa, NULL); + RCU_INIT_POINTER(ifmsh->csa, NULL); if (tmp_csa_settings) kfree_rcu(tmp_csa_settings, rcu_head); ret = ieee80211_mesh_rebuild_beacon(sdata); @@ -1102,7 +1098,7 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, ret = ieee80211_mesh_rebuild_beacon(sdata); if (ret) { tmp_csa_settings = rcu_dereference(ifmsh->csa); - rcu_assign_pointer(ifmsh->csa, NULL); + RCU_INIT_POINTER(ifmsh->csa, NULL); kfree_rcu(tmp_csa_settings, rcu_head); return ret; } diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index f9514685d45a54..94758b9c9ed48a 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -37,7 +37,7 @@ static inline u32 u32_field_get(const u8 *preq_elem, int offset, bool ae) return get_unaligned_le32(preq_elem + offset); } -static inline u32 u16_field_get(const u8 *preq_elem, int offset, bool ae) +static inline u16 u16_field_get(const u8 *preq_elem, int offset, bool ae) { if (ae) offset += 6; @@ -544,9 +544,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, if (time_after(jiffies, ifmsh->last_sn_update + net_traversal_jiffies(sdata)) || time_before(jiffies, ifmsh->last_sn_update)) { - target_sn = ++ifmsh->sn; + ++ifmsh->sn; ifmsh->last_sn_update = jiffies; } + target_sn = ifmsh->sn; } else if (is_broadcast_ether_addr(target_addr) && (target_flags & IEEE80211_PREQ_TO_FLAG)) { rcu_read_lock(); diff --git a/net/mac80211/michael.h b/net/mac80211/michael.h index 3b848dad958762..0e4886f881f1e4 100644 --- a/net/mac80211/michael.h +++ b/net/mac80211/michael.h @@ -11,6 +11,7 @@ #define MICHAEL_H #include +#include #define MICHAEL_MIC_LEN 8 diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index dee50aefd6e868..488826f188a7a8 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1089,7 +1089,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, } chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), struct ieee80211_chanctx, conf); - if (chanctx->refcount > 1) { + if (ieee80211_chanctx_refcount(local, chanctx) > 1) { sdata_info(sdata, "channel switch with multiple interfaces on the same channel, disconnecting\n"); ieee80211_queue_work(&local->hw, @@ -3701,7 +3701,7 @@ int ieee80211_max_network_latency(struct notifier_block *nb, ieee80211_recalc_ps(local, latency_usec); mutex_unlock(&local->iflist_mtx); - return 0; + return NOTIFY_OK; } static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 216c45b949e513..394e201cde6d3b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -54,24 +54,25 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, return skb; } -static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len) +static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_hdr *hdr; - - hdr = (void *)(skb->data); + struct ieee80211_hdr *hdr = (void *)skb->data; if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC | RX_FLAG_AMPDU_IS_ZEROLEN)) - return 1; + return true; + if (unlikely(skb->len < 16 + present_fcs_len)) - return 1; + return true; + if (ieee80211_is_ctl(hdr->frame_control) && !ieee80211_is_pspoll(hdr->frame_control) && !ieee80211_is_back_req(hdr->frame_control)) - return 1; - return 0; + return true; + + return false; } static int @@ -1231,7 +1232,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) && test_sta_flag(sta, WLAN_STA_AUTHORIZED)) { sta->last_rx = jiffies; - if (ieee80211_is_data(hdr->frame_control)) { + if (ieee80211_is_data(hdr->frame_control) && + !is_multicast_ether_addr(hdr->addr1)) { sta->last_rx_rate_idx = status->rate_idx; sta->last_rx_rate_flag = status->flag; sta->last_rx_rate_vht_flag = status->vht_flag; @@ -3190,7 +3192,7 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, } /* - * This is the actual Rx frames handler. as it blongs to Rx path it must + * This is the actual Rx frames handler. as it belongs to Rx path it must * be called with rcu_read_lock protection. */ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 3ce7f2c8539a1f..28185c8dc19a30 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -309,7 +309,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (local->scan_req != local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; - rcu_assign_pointer(local->scan_sdata, NULL); + RCU_INIT_POINTER(local->scan_sdata, NULL); local->scanning = 0; local->scan_chandef.chan = NULL; @@ -559,7 +559,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_idle(local); local->scan_req = NULL; - rcu_assign_pointer(local->scan_sdata, NULL); + RCU_INIT_POINTER(local->scan_sdata, NULL); } return rc; @@ -773,7 +773,7 @@ void ieee80211_scan_work(struct work_struct *work) int rc; local->scan_req = NULL; - rcu_assign_pointer(local->scan_sdata, NULL); + RCU_INIT_POINTER(local->scan_sdata, NULL); rc = __ieee80211_start_scan(sdata, req); if (rc) { @@ -1014,7 +1014,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, if (ret) { /* Clean in case of failure after HW restart or upon resume. */ - rcu_assign_pointer(local->sched_scan_sdata, NULL); + RCU_INIT_POINTER(local->sched_scan_sdata, NULL); local->sched_scan_req = NULL; } @@ -1089,7 +1089,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) return; } - rcu_assign_pointer(local->sched_scan_sdata, NULL); + RCU_INIT_POINTER(local->sched_scan_sdata, NULL); /* If sched scan was aborted by the driver. */ local->sched_scan_req = NULL; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 137a192e64bc3c..632d372bb5117f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -552,7 +552,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) { struct ieee80211_local *local = sta->local; - int err = 0; + int err; might_sleep(); @@ -570,7 +570,6 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) return 0; out_free: - BUG_ON(!err); sta_info_free(local, sta); return err; } @@ -1148,7 +1147,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) atomic_dec(&ps->num_sta_ps); /* This station just woke up and isn't aware of our SMPS state */ - if (!ieee80211_smps_is_restrictive(sta->known_smps_mode, + if (!ieee80211_vif_is_mesh(&sdata->vif) && + !ieee80211_smps_is_restrictive(sta->known_smps_mode, sdata->smps_mode) && sta->known_smps_mode != sdata->bss->req_smps && sta_info_tx_streams(sta) != 1) { diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 00ba90b02ab2ab..60cb7a665976e1 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -314,10 +314,9 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_local *local, !is_multicast_ether_addr(hdr->addr1)) txflags |= IEEE80211_RADIOTAP_F_TX_FAIL; - if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || - (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) + if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) txflags |= IEEE80211_RADIOTAP_F_TX_CTS; - else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) txflags |= IEEE80211_RADIOTAP_F_TX_RTS; put_unaligned_le16(txflags, pos); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 275c94f995f7c8..c08bd4aca6bb8b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -554,7 +554,7 @@ void ieee80211_flush_queues(struct ieee80211_local *local, ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, IEEE80211_QUEUE_STOP_REASON_FLUSH); - drv_flush(local, queues, false); + drv_flush(local, sdata, queues, false); ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, IEEE80211_QUEUE_STOP_REASON_FLUSH); @@ -1546,7 +1546,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) WARN_ON(local->resuming); res = drv_add_interface(local, sdata); if (WARN_ON(res)) { - rcu_assign_pointer(local->monitor_sdata, NULL); + RCU_INIT_POINTER(local->monitor_sdata, NULL); synchronize_net(); kfree(sdata); } @@ -1565,17 +1565,17 @@ int ieee80211_reconfig(struct ieee80211_local *local) list_for_each_entry(ctx, &local->chanctx_list, list) WARN_ON(drv_add_chanctx(local, ctx)); mutex_unlock(&local->chanctx_mtx); - } - list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - ieee80211_assign_chanctx(local, sdata); - } + list_for_each_entry(sdata, &local->interfaces, list) { + if (!ieee80211_sdata_running(sdata)) + continue; + ieee80211_assign_chanctx(local, sdata); + } - sdata = rtnl_dereference(local->monitor_sdata); - if (sdata && ieee80211_sdata_running(sdata)) - ieee80211_assign_chanctx(local, sdata); + sdata = rtnl_dereference(local->monitor_sdata); + if (sdata && ieee80211_sdata_running(sdata)) + ieee80211_assign_chanctx(local, sdata); + } /* add STAs back */ mutex_lock(&local->sta_mtx); @@ -1671,13 +1671,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) } break; case NL80211_IFTYPE_WDS: - break; case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_MONITOR: - /* ignore virtual */ - break; case NL80211_IFTYPE_P2P_DEVICE: - changed = BSS_CHANGED_IDLE; + /* nothing to do */ break; case NL80211_IFTYPE_UNSPECIFIED: case NUM_NL80211_IFTYPES: @@ -1780,7 +1777,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) mutex_unlock(&local->mtx); if (sched_scan_stopped) - cfg80211_sched_scan_stopped(local->hw.wiphy); + cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy); /* * If this is for hw restart things are still running. @@ -2797,3 +2794,121 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local, ps->dtim_count = dtim_count; } + +int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode chanmode, + u8 radar_detect) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_sub_if_data *sdata_iter; + enum nl80211_iftype iftype = sdata->wdev.iftype; + int num[NUM_NL80211_IFTYPES]; + struct ieee80211_chanctx *ctx; + int num_different_channels = 0; + int total = 1; + + lockdep_assert_held(&local->chanctx_mtx); + + if (WARN_ON(hweight32(radar_detect) > 1)) + return -EINVAL; + + if (WARN_ON(chandef && chanmode == IEEE80211_CHANCTX_SHARED && + !chandef->chan)) + return -EINVAL; + + if (chandef) + num_different_channels = 1; + + if (WARN_ON(iftype >= NUM_NL80211_IFTYPES)) + return -EINVAL; + + /* Always allow software iftypes */ + if (local->hw.wiphy->software_iftypes & BIT(iftype)) { + if (radar_detect) + return -EINVAL; + return 0; + } + + memset(num, 0, sizeof(num)); + + if (iftype != NL80211_IFTYPE_UNSPECIFIED) + num[iftype] = 1; + + list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->conf.radar_enabled) + radar_detect |= BIT(ctx->conf.def.width); + if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { + num_different_channels++; + continue; + } + if (chandef && chanmode == IEEE80211_CHANCTX_SHARED && + cfg80211_chandef_compatible(chandef, + &ctx->conf.def)) + continue; + num_different_channels++; + } + + list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) { + struct wireless_dev *wdev_iter; + + wdev_iter = &sdata_iter->wdev; + + if (sdata_iter == sdata || + rcu_access_pointer(sdata_iter->vif.chanctx_conf) == NULL || + local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype)) + continue; + + num[wdev_iter->iftype]++; + total++; + } + + if (total == 1 && !radar_detect) + return 0; + + return cfg80211_check_combinations(local->hw.wiphy, + num_different_channels, + radar_detect, num); +} + +static void +ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c, + void *data) +{ + u32 *max_num_different_channels = data; + + *max_num_different_channels = max(*max_num_different_channels, + c->num_different_channels); +} + +int ieee80211_max_num_channels(struct ieee80211_local *local) +{ + struct ieee80211_sub_if_data *sdata; + int num[NUM_NL80211_IFTYPES] = {}; + struct ieee80211_chanctx *ctx; + int num_different_channels = 0; + u8 radar_detect = 0; + u32 max_num_different_channels = 1; + int err; + + lockdep_assert_held(&local->chanctx_mtx); + + list_for_each_entry(ctx, &local->chanctx_list, list) { + num_different_channels++; + + if (ctx->conf.radar_enabled) + radar_detect |= BIT(ctx->conf.def.width); + } + + list_for_each_entry_rcu(sdata, &local->interfaces, list) + num[sdata->wdev.iftype]++; + + err = cfg80211_iter_combinations(local->hw.wiphy, + num_different_channels, radar_detect, + num, ieee80211_iter_max_chans, + &max_num_different_channels); + if (err < 0) + return err; + + return max_num_different_channels; +} diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index b8600e3c29c828..9b3dcc201145dd 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -406,7 +406,10 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) if (info->control.hw_key && !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && - !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { + !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && + !((info->control.hw_key->flags & + IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) && + ieee80211_is_mgmt(hdr->frame_control))) { /* * hwaccel has no need for preallocated room for CCMP * header or MIC fields diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 75421f2ba8bee3..1f4f954c4b47c7 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -914,7 +914,7 @@ void nf_conntrack_free(struct nf_conn *ct) nf_ct_ext_destroy(ct); nf_ct_ext_free(ct); kmem_cache_free(net->ct.nf_conntrack_cachep, ct); - smp_mb__before_atomic_dec(); + smp_mb__before_atomic(); atomic_dec(&net->ct.count); } EXPORT_SYMBOL_GPL(nf_conntrack_free); diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index e009087620e30e..81df6ce23cbc37 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -399,19 +399,17 @@ static void nfnetlink_rcv(struct sk_buff *skb) } #ifdef CONFIG_MODULES -static void nfnetlink_bind(int group) +static int nfnetlink_bind(int group) { const struct nfnetlink_subsystem *ss; int type = nfnl_group2type[group]; rcu_read_lock(); ss = nfnetlink_get_subsys(type); - if (!ss) { - rcu_read_unlock(); - request_module("nfnetlink-subsys-%d", type); - return; - } rcu_read_unlock(); + if (!ss) + request_module("nfnetlink-subsys-%d", type); + return 0; } #endif diff --git a/net/netfilter/xt_repldata.h b/net/netfilter/xt_repldata.h index 6efe4e5a81c62b..8fd324116e6f12 100644 --- a/net/netfilter/xt_repldata.h +++ b/net/netfilter/xt_repldata.h @@ -5,23 +5,35 @@ * they serve as the hanging-off data accessed through repl.data[]. */ +/* tbl has the following structure equivalent, but is C99 compliant: + * struct { + * struct type##_replace repl; + * struct type##_standard entries[nhooks]; + * struct type##_error term; + * } *tbl; + */ + #define xt_alloc_initial_table(type, typ2) ({ \ unsigned int hook_mask = info->valid_hooks; \ unsigned int nhooks = hweight32(hook_mask); \ unsigned int bytes = 0, hooknum = 0, i = 0; \ struct { \ struct type##_replace repl; \ - struct type##_standard entries[nhooks]; \ - struct type##_error term; \ - } *tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); \ + struct type##_standard entries[]; \ + } *tbl; \ + struct type##_error *term; \ + size_t term_offset = (offsetof(typeof(*tbl), entries[nhooks]) + \ + __alignof__(*term) - 1) & ~(__alignof__(*term) - 1); \ + tbl = kzalloc(term_offset + sizeof(*term), GFP_KERNEL); \ if (tbl == NULL) \ return NULL; \ + term = (struct type##_error *)&(((char *)tbl)[term_offset]); \ strncpy(tbl->repl.name, info->name, sizeof(tbl->repl.name)); \ - tbl->term = (struct type##_error)typ2##_ERROR_INIT; \ + *term = (struct type##_error)typ2##_ERROR_INIT; \ tbl->repl.valid_hooks = hook_mask; \ tbl->repl.num_entries = nhooks + 1; \ tbl->repl.size = nhooks * sizeof(struct type##_standard) + \ - sizeof(struct type##_error); \ + sizeof(struct type##_error); \ for (; hook_mask != 0; hook_mask >>= 1, ++hooknum) { \ if (!(hook_mask & 1)) \ continue; \ diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 81dca96d2be682..e0ccd84d4d6781 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1206,7 +1206,8 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, struct module *module = NULL; struct mutex *cb_mutex; struct netlink_sock *nlk; - void (*bind)(int group); + int (*bind)(int group); + void (*unbind)(int group); int err = 0; sock->state = SS_UNCONNECTED; @@ -1232,6 +1233,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, err = -EPROTONOSUPPORT; cb_mutex = nl_table[protocol].cb_mutex; bind = nl_table[protocol].bind; + unbind = nl_table[protocol].unbind; netlink_unlock_table(); if (err < 0) @@ -1248,6 +1250,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, nlk = nlk_sk(sock->sk); nlk->module = module; nlk->netlink_bind = bind; + nlk->netlink_unbind = unbind; out: return err; @@ -1301,6 +1304,7 @@ static int netlink_release(struct socket *sock) kfree_rcu(old, rcu); nl_table[sk->sk_protocol].module = NULL; nl_table[sk->sk_protocol].bind = NULL; + nl_table[sk->sk_protocol].unbind = NULL; nl_table[sk->sk_protocol].flags = 0; nl_table[sk->sk_protocol].registered = 0; } @@ -1476,6 +1480,19 @@ static int netlink_realloc_groups(struct sock *sk) return err; } +static void netlink_unbind(int group, long unsigned int groups, + struct netlink_sock *nlk) +{ + int undo; + + if (!nlk->netlink_unbind) + return; + + for (undo = 0; undo < group; undo++) + if (test_bit(group, &groups)) + nlk->netlink_unbind(undo); +} + static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) { @@ -1484,6 +1501,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, struct netlink_sock *nlk = nlk_sk(sk); struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; int err; + long unsigned int groups = nladdr->nl_groups; if (addr_len < sizeof(struct sockaddr_nl)) return -EINVAL; @@ -1492,7 +1510,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, return -EINVAL; /* Only superuser is allowed to listen multicasts */ - if (nladdr->nl_groups) { + if (groups) { if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV)) return -EPERM; err = netlink_realloc_groups(sk); @@ -1500,37 +1518,45 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, return err; } - if (nlk->portid) { + if (nlk->portid) if (nladdr->nl_pid != nlk->portid) return -EINVAL; - } else { + + if (nlk->netlink_bind && groups) { + int group; + + for (group = 0; group < nlk->ngroups; group++) { + if (!test_bit(group, &groups)) + continue; + err = nlk->netlink_bind(group); + if (!err) + continue; + netlink_unbind(group, groups, nlk); + return err; + } + } + + if (!nlk->portid) { err = nladdr->nl_pid ? netlink_insert(sk, net, nladdr->nl_pid) : netlink_autobind(sock); - if (err) + if (err) { + netlink_unbind(nlk->ngroups - 1, groups, nlk); return err; + } } - if (!nladdr->nl_groups && (nlk->groups == NULL || !(u32)nlk->groups[0])) + if (!groups && (nlk->groups == NULL || !(u32)nlk->groups[0])) return 0; netlink_table_grab(); netlink_update_subscriptions(sk, nlk->subscriptions + - hweight32(nladdr->nl_groups) - + hweight32(groups) - hweight32(nlk->groups[0])); - nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; + nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | groups; netlink_update_listeners(sk); netlink_table_ungrab(); - if (nlk->netlink_bind && nlk->groups[0]) { - int i; - - for (i = 0; i < nlk->ngroups; i++) { - if (test_bit(i, nlk->groups)) - nlk->netlink_bind(i); - } - } - return 0; } @@ -2168,13 +2194,17 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, return err; if (!val || val - 1 >= nlk->ngroups) return -EINVAL; + if (optname == NETLINK_ADD_MEMBERSHIP && nlk->netlink_bind) { + err = nlk->netlink_bind(val); + if (err) + return err; + } netlink_table_grab(); netlink_update_socket_mc(nlk, val, optname == NETLINK_ADD_MEMBERSHIP); netlink_table_ungrab(); - - if (nlk->netlink_bind) - nlk->netlink_bind(val); + if (optname == NETLINK_DROP_MEMBERSHIP && nlk->netlink_unbind) + nlk->netlink_unbind(val); err = 0; break; diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index ed13a790b00e16..0b59d441f5b6bc 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h @@ -38,7 +38,8 @@ struct netlink_sock { struct mutex *cb_mutex; struct mutex cb_def_mutex; void (*netlink_rcv)(struct sk_buff *skb); - void (*netlink_bind)(int group); + int (*netlink_bind)(int group); + void (*netlink_unbind)(int group); struct module *module; #ifdef CONFIG_NETLINK_MMAP struct mutex pg_vec_lock; @@ -74,7 +75,8 @@ struct netlink_table { unsigned int groups; struct mutex *cb_mutex; struct module *module; - void (*bind)(int group); + int (*bind)(int group); + void (*unbind)(int group); bool (*compare)(struct net *net, struct sock *sock); int registered; }; diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index e797a50ac2beec..21cceb3bdf7871 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c @@ -180,7 +180,8 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) OVS_CB(skb)->tun_key->ipv4_tos, OVS_CB(skb)->tun_key->ipv4_ttl, df, src_port, dst_port, - htonl(be64_to_cpu(OVS_CB(skb)->tun_key->tun_id) << 8)); + htonl(be64_to_cpu(OVS_CB(skb)->tun_key->tun_id) << 8), + false); if (err < 0) ip_rt_put(rt); error: diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index b7ebe23cdedfb5..d67de453c35aae 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -598,7 +598,7 @@ static void rds_ib_set_ack(struct rds_ib_connection *ic, u64 seq, { atomic64_set(&ic->i_ack_next, seq); if (ack_required) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags); } } @@ -606,7 +606,7 @@ static void rds_ib_set_ack(struct rds_ib_connection *ic, u64 seq, static u64 rds_ib_get_ack(struct rds_ib_connection *ic) { clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return atomic64_read(&ic->i_ack_next); } diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c index 45033358358e7e..aa8bf6786008af 100644 --- a/net/rds/iw_recv.c +++ b/net/rds/iw_recv.c @@ -429,7 +429,7 @@ static void rds_iw_set_ack(struct rds_iw_connection *ic, u64 seq, { atomic64_set(&ic->i_ack_next, seq); if (ack_required) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags); } } @@ -437,7 +437,7 @@ static void rds_iw_set_ack(struct rds_iw_connection *ic, u64 seq, static u64 rds_iw_get_ack(struct rds_iw_connection *ic) { clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return atomic64_read(&ic->i_ack_next); } diff --git a/net/rds/send.c b/net/rds/send.c index a82fb660ec0090..23718160d71ec9 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -107,7 +107,7 @@ static int acquire_in_xmit(struct rds_connection *conn) static void release_in_xmit(struct rds_connection *conn) { clear_bit(RDS_IN_XMIT, &conn->c_flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); /* * We don't use wait_on_bit()/wake_up_bit() because our waking is in a * hot path and finding waiters is very rare. We don't want to walk @@ -661,7 +661,7 @@ void rds_send_drop_acked(struct rds_connection *conn, u64 ack, /* order flag updates with spin locks */ if (!list_empty(&list)) - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); spin_unlock_irqrestore(&conn->c_lock, flags); @@ -691,7 +691,7 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest) } /* order flag updates with the rs lock */ - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); spin_unlock_irqrestore(&rs->rs_lock, flags); diff --git a/net/rds/tcp_send.c b/net/rds/tcp_send.c index 81cf5a4c5e40c3..53b17ca0dff5a5 100644 --- a/net/rds/tcp_send.c +++ b/net/rds/tcp_send.c @@ -93,7 +93,7 @@ int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm, rm->m_ack_seq = tc->t_last_sent_nxt + sizeof(struct rds_header) + be32_to_cpu(rm->m_inc.i_hdr.h_len) - 1; - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); set_bit(RDS_MSG_HAS_ACK_SEQ, &rm->m_flags); tc->t_last_expected_una = rm->m_ack_seq + 1; diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index bd2a5b90400cdf..9c4a5eb91cbfd6 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c @@ -36,8 +36,6 @@ struct rfkill_gpio_data { struct gpio_desc *shutdown_gpio; struct rfkill *rfkill_dev; - char *reset_name; - char *shutdown_name; struct clk *clk; bool clk_enabled; @@ -87,10 +85,8 @@ static int rfkill_gpio_probe(struct platform_device *pdev) { struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data; struct rfkill_gpio_data *rfkill; - const char *clk_name = NULL; struct gpio_desc *gpio; int ret; - int len; rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL); if (!rfkill) @@ -101,28 +97,15 @@ static int rfkill_gpio_probe(struct platform_device *pdev) if (ret) return ret; } else if (pdata) { - clk_name = pdata->power_clk_name; rfkill->name = pdata->name; rfkill->type = pdata->type; } else { return -ENODEV; } - len = strlen(rfkill->name); - rfkill->reset_name = devm_kzalloc(&pdev->dev, len + 7, GFP_KERNEL); - if (!rfkill->reset_name) - return -ENOMEM; - - rfkill->shutdown_name = devm_kzalloc(&pdev->dev, len + 10, GFP_KERNEL); - if (!rfkill->shutdown_name) - return -ENOMEM; - - snprintf(rfkill->reset_name, len + 6 , "%s_reset", rfkill->name); - snprintf(rfkill->shutdown_name, len + 9, "%s_shutdown", rfkill->name); - - rfkill->clk = devm_clk_get(&pdev->dev, clk_name); + rfkill->clk = devm_clk_get(&pdev->dev, NULL); - gpio = devm_gpiod_get_index(&pdev->dev, rfkill->reset_name, 0); + gpio = devm_gpiod_get_index(&pdev->dev, "reset", 0); if (!IS_ERR(gpio)) { ret = gpiod_direction_output(gpio, 0); if (ret) @@ -130,7 +113,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev) rfkill->reset_gpio = gpio; } - gpio = devm_gpiod_get_index(&pdev->dev, rfkill->shutdown_name, 1); + gpio = devm_gpiod_get_index(&pdev->dev, "shutdown", 1); if (!IS_ERR(gpio)) { ret = gpiod_direction_output(gpio, 0); if (ret) @@ -146,14 +129,6 @@ static int rfkill_gpio_probe(struct platform_device *pdev) return -EINVAL; } - if (pdata && pdata->gpio_runtime_setup) { - ret = pdata->gpio_runtime_setup(pdev); - if (ret) { - dev_err(&pdev->dev, "can't set up gpio\n"); - return ret; - } - } - rfkill->rfkill_dev = rfkill_alloc(rfkill->name, &pdev->dev, rfkill->type, &rfkill_gpio_ops, rfkill); @@ -174,20 +149,23 @@ static int rfkill_gpio_probe(struct platform_device *pdev) static int rfkill_gpio_remove(struct platform_device *pdev) { struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev); - struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data; - if (pdata && pdata->gpio_runtime_close) - pdata->gpio_runtime_close(pdev); rfkill_unregister(rfkill->rfkill_dev); rfkill_destroy(rfkill->rfkill_dev); return 0; } +#ifdef CONFIG_ACPI static const struct acpi_device_id rfkill_acpi_match[] = { + { "BCM2E1A", RFKILL_TYPE_BLUETOOTH }, + { "BCM2E39", RFKILL_TYPE_BLUETOOTH }, + { "BCM2E3D", RFKILL_TYPE_BLUETOOTH }, { "BCM4752", RFKILL_TYPE_GPS }, + { "LNV4752", RFKILL_TYPE_GPS }, { }, }; +#endif static struct platform_driver rfkill_gpio_driver = { .probe = rfkill_gpio_probe, diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index bdbdb1a7920af9..45527e6b52dbf3 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -134,7 +134,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n) int err; int tp_created = 0; - if ((n->nlmsg_type != RTM_GETTFILTER) && !netlink_capable(skb, CAP_NET_ADMIN)) + if ((n->nlmsg_type != RTM_GETTFILTER) && + !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) return -EPERM; replay: @@ -317,7 +318,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n) } } - err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh); + err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh, + n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE); if (err == 0) { if (tp_created) { spin_lock_bh(root_lock); @@ -504,7 +506,7 @@ void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) EXPORT_SYMBOL(tcf_exts_destroy); int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, - struct nlattr *rate_tlv, struct tcf_exts *exts) + struct nlattr *rate_tlv, struct tcf_exts *exts, bool ovr) { #ifdef CONFIG_NET_CLS_ACT { @@ -513,7 +515,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, INIT_LIST_HEAD(&exts->actions); if (exts->police && tb[exts->police]) { act = tcf_action_init_1(net, tb[exts->police], rate_tlv, - "police", TCA_ACT_NOREPLACE, + "police", ovr, TCA_ACT_BIND); if (IS_ERR(act)) return PTR_ERR(act); @@ -523,7 +525,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, } else if (exts->action && tb[exts->action]) { int err; err = tcf_action_init(net, tb[exts->action], rate_tlv, - NULL, TCA_ACT_NOREPLACE, + NULL, ovr, TCA_ACT_BIND, &exts->actions); if (err) return err; @@ -543,14 +545,12 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, struct tcf_exts *src) { #ifdef CONFIG_NET_CLS_ACT - if (!list_empty(&src->actions)) { - LIST_HEAD(tmp); - tcf_tree_lock(tp); - list_splice_init(&dst->actions, &tmp); - list_splice(&src->actions, &dst->actions); - tcf_tree_unlock(tp); - tcf_action_destroy(&tmp, TCA_ACT_UNBIND); - } + LIST_HEAD(tmp); + tcf_tree_lock(tp); + list_splice_init(&dst->actions, &tmp); + list_splice(&src->actions, &dst->actions); + tcf_tree_unlock(tp); + tcf_action_destroy(&tmp, TCA_ACT_UNBIND); #endif } EXPORT_SYMBOL(tcf_exts_change); diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c index e98ca99c202bb5..0ae1813e3e90d5 100644 --- a/net/sched/cls_basic.c +++ b/net/sched/cls_basic.c @@ -130,14 +130,14 @@ static const struct nla_policy basic_policy[TCA_BASIC_MAX + 1] = { static int basic_set_parms(struct net *net, struct tcf_proto *tp, struct basic_filter *f, unsigned long base, struct nlattr **tb, - struct nlattr *est) + struct nlattr *est, bool ovr) { int err; struct tcf_exts e; struct tcf_ematch_tree t; tcf_exts_init(&e, TCA_BASIC_ACT, TCA_BASIC_POLICE); - err = tcf_exts_validate(net, tp, tb, est, &e); + err = tcf_exts_validate(net, tp, tb, est, &e, ovr); if (err < 0) return err; @@ -161,7 +161,7 @@ static int basic_set_parms(struct net *net, struct tcf_proto *tp, static int basic_change(struct net *net, struct sk_buff *in_skb, struct tcf_proto *tp, unsigned long base, u32 handle, - struct nlattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg, bool ovr) { int err; struct basic_head *head = tp->root; @@ -179,7 +179,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb, if (f != NULL) { if (handle && f->handle != handle) return -EINVAL; - return basic_set_parms(net, tp, f, base, tb, tca[TCA_RATE]); + return basic_set_parms(net, tp, f, base, tb, tca[TCA_RATE], ovr); } err = -ENOBUFS; @@ -206,7 +206,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb, f->handle = head->hgenerator; } - err = basic_set_parms(net, tp, f, base, tb, tca[TCA_RATE]); + err = basic_set_parms(net, tp, f, base, tb, tca[TCA_RATE], ovr); if (err < 0) goto errout; diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c index 8e3cf49118e3a2..16186965af97fd 100644 --- a/net/sched/cls_bpf.c +++ b/net/sched/cls_bpf.c @@ -156,7 +156,7 @@ static void cls_bpf_put(struct tcf_proto *tp, unsigned long f) static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, struct cls_bpf_prog *prog, unsigned long base, struct nlattr **tb, - struct nlattr *est) + struct nlattr *est, bool ovr) { struct sock_filter *bpf_ops, *bpf_old; struct tcf_exts exts; @@ -170,7 +170,7 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, return -EINVAL; tcf_exts_init(&exts, TCA_BPF_ACT, TCA_BPF_POLICE); - ret = tcf_exts_validate(net, tp, tb, est, &exts); + ret = tcf_exts_validate(net, tp, tb, est, &exts, ovr); if (ret < 0) return ret; @@ -242,7 +242,7 @@ static u32 cls_bpf_grab_new_handle(struct tcf_proto *tp, static int cls_bpf_change(struct net *net, struct sk_buff *in_skb, struct tcf_proto *tp, unsigned long base, u32 handle, struct nlattr **tca, - unsigned long *arg) + unsigned long *arg, bool ovr) { struct cls_bpf_head *head = tp->root; struct cls_bpf_prog *prog = (struct cls_bpf_prog *) *arg; @@ -260,7 +260,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb, if (handle && prog->handle != handle) return -EINVAL; return cls_bpf_modify_existing(net, tp, prog, base, tb, - tca[TCA_RATE]); + tca[TCA_RATE], ovr); } prog = kzalloc(sizeof(*prog), GFP_KERNEL); @@ -277,7 +277,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb, goto errout; } - ret = cls_bpf_modify_existing(net, tp, prog, base, tb, tca[TCA_RATE]); + ret = cls_bpf_modify_existing(net, tp, prog, base, tb, tca[TCA_RATE], ovr); if (ret < 0) goto errout; diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index 8e2158ab551c0c..cacf01bd04f0a9 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c @@ -83,7 +83,7 @@ static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = { static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, struct tcf_proto *tp, unsigned long base, u32 handle, struct nlattr **tca, - unsigned long *arg) + unsigned long *arg, bool ovr) { struct nlattr *tb[TCA_CGROUP_MAX + 1]; struct cls_cgroup_head *head = tp->root; @@ -119,7 +119,7 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, return err; tcf_exts_init(&e, TCA_CGROUP_ACT, TCA_CGROUP_POLICE); - err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e); + err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr); if (err < 0) return err; diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 257029c5433298..35be16f7c192dc 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -349,7 +349,7 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = { static int flow_change(struct net *net, struct sk_buff *in_skb, struct tcf_proto *tp, unsigned long base, u32 handle, struct nlattr **tca, - unsigned long *arg) + unsigned long *arg, bool ovr) { struct flow_head *head = tp->root; struct flow_filter *f; @@ -393,7 +393,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb, } tcf_exts_init(&e, TCA_FLOW_ACT, TCA_FLOW_POLICE); - err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e); + err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr); if (err < 0) return err; diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index 63a3ce75c02ee9..861b03ccfed0a5 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -169,7 +169,7 @@ static const struct nla_policy fw_policy[TCA_FW_MAX + 1] = { static int fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f, - struct nlattr **tb, struct nlattr **tca, unsigned long base) + struct nlattr **tb, struct nlattr **tca, unsigned long base, bool ovr) { struct fw_head *head = tp->root; struct tcf_exts e; @@ -177,7 +177,7 @@ fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f, int err; tcf_exts_init(&e, TCA_FW_ACT, TCA_FW_POLICE); - err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e); + err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr); if (err < 0) return err; @@ -218,7 +218,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, struct tcf_proto *tp, unsigned long base, u32 handle, struct nlattr **tca, - unsigned long *arg) + unsigned long *arg, bool ovr) { struct fw_head *head = tp->root; struct fw_filter *f = (struct fw_filter *) *arg; @@ -236,7 +236,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, if (f != NULL) { if (f->id != handle && handle) return -EINVAL; - return fw_change_attrs(net, tp, f, tb, tca, base); + return fw_change_attrs(net, tp, f, tb, tca, base, ovr); } if (!handle) @@ -264,7 +264,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, tcf_exts_init(&f->exts, TCA_FW_ACT, TCA_FW_POLICE); f->id = handle; - err = fw_change_attrs(net, tp, f, tb, tca, base); + err = fw_change_attrs(net, tp, f, tb, tca, base, ovr); if (err < 0) goto errout; diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index 1ad3068f2ce16e..dd9fc2523c76a2 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -333,7 +333,8 @@ static const struct nla_policy route4_policy[TCA_ROUTE4_MAX + 1] = { static int route4_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, struct route4_filter *f, u32 handle, struct route4_head *head, - struct nlattr **tb, struct nlattr *est, int new) + struct nlattr **tb, struct nlattr *est, int new, + bool ovr) { int err; u32 id = 0, to = 0, nhandle = 0x8000; @@ -343,7 +344,7 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp, struct tcf_exts e; tcf_exts_init(&e, TCA_ROUTE4_ACT, TCA_ROUTE4_POLICE); - err = tcf_exts_validate(net, tp, tb, est, &e); + err = tcf_exts_validate(net, tp, tb, est, &e, ovr); if (err < 0) return err; @@ -428,7 +429,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, struct tcf_proto *tp, unsigned long base, u32 handle, struct nlattr **tca, - unsigned long *arg) + unsigned long *arg, bool ovr) { struct route4_head *head = tp->root; struct route4_filter *f, *f1, **fp; @@ -455,7 +456,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, old_handle = f->handle; err = route4_set_parms(net, tp, base, f, handle, head, tb, - tca[TCA_RATE], 0); + tca[TCA_RATE], 0, ovr); if (err < 0) return err; @@ -479,7 +480,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, tcf_exts_init(&f->exts, TCA_ROUTE4_ACT, TCA_ROUTE4_POLICE); err = route4_set_parms(net, tp, base, f, handle, head, tb, - tca[TCA_RATE], 1); + tca[TCA_RATE], 1, ovr); if (err < 0) goto errout; diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index 19f8e5dfa8bdae..1020e233a5d6c7 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h @@ -415,7 +415,7 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb, struct tcf_proto *tp, unsigned long base, u32 handle, struct nlattr **tca, - unsigned long *arg) + unsigned long *arg, bool ovr) { struct rsvp_head *data = tp->root; struct rsvp_filter *f, **fp; @@ -436,7 +436,7 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb, return err; tcf_exts_init(&e, TCA_RSVP_ACT, TCA_RSVP_POLICE); - err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e); + err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr); if (err < 0) return err; diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index eed8404443d8f0..d11d0a4fbe34f6 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -192,7 +192,7 @@ static int tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, u32 handle, struct tcindex_data *p, struct tcindex_filter_result *r, struct nlattr **tb, - struct nlattr *est) + struct nlattr *est, bool ovr) { int err, balloc = 0; struct tcindex_filter_result new_filter_result, *old_r = r; @@ -202,7 +202,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, struct tcf_exts e; tcf_exts_init(&e, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); - err = tcf_exts_validate(net, tp, tb, est, &e); + err = tcf_exts_validate(net, tp, tb, est, &e, ovr); if (err < 0) return err; @@ -331,7 +331,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, static int tcindex_change(struct net *net, struct sk_buff *in_skb, struct tcf_proto *tp, unsigned long base, u32 handle, - struct nlattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg, bool ovr) { struct nlattr *opt = tca[TCA_OPTIONS]; struct nlattr *tb[TCA_TCINDEX_MAX + 1]; @@ -351,7 +351,7 @@ tcindex_change(struct net *net, struct sk_buff *in_skb, return err; return tcindex_set_parms(net, tp, base, handle, p, r, tb, - tca[TCA_RATE]); + tca[TCA_RATE], ovr); } diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 84c28daff8484f..c39b583ace3229 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -486,13 +486,13 @@ static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = { static int u32_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, struct tc_u_hnode *ht, struct tc_u_knode *n, struct nlattr **tb, - struct nlattr *est) + struct nlattr *est, bool ovr) { int err; struct tcf_exts e; tcf_exts_init(&e, TCA_U32_ACT, TCA_U32_POLICE); - err = tcf_exts_validate(net, tp, tb, est, &e); + err = tcf_exts_validate(net, tp, tb, est, &e, ovr); if (err < 0) return err; @@ -545,7 +545,7 @@ static int u32_set_parms(struct net *net, struct tcf_proto *tp, static int u32_change(struct net *net, struct sk_buff *in_skb, struct tcf_proto *tp, unsigned long base, u32 handle, struct nlattr **tca, - unsigned long *arg) + unsigned long *arg, bool ovr) { struct tc_u_common *tp_c = tp->data; struct tc_u_hnode *ht; @@ -569,7 +569,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, return -EINVAL; return u32_set_parms(net, tp, base, n->ht_up, n, tb, - tca[TCA_RATE]); + tca[TCA_RATE], ovr); } if (tb[TCA_U32_DIVISOR]) { @@ -656,7 +656,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, } #endif - err = u32_set_parms(net, tp, base, ht, n, tb, tca[TCA_RATE]); + err = u32_set_parms(net, tp, base, ht, n, tb, tca[TCA_RATE], ovr); if (err == 0) { struct tc_u_knode **ins; for (ins = &ht->ht[TC_U32_HASH(handle)]; *ins; ins = &(*ins)->next) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 400769014bbde8..fd14df56e5ffdc 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1084,7 +1084,8 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n) struct Qdisc *p = NULL; int err; - if ((n->nlmsg_type != RTM_GETQDISC) && !netlink_capable(skb, CAP_NET_ADMIN)) + if ((n->nlmsg_type != RTM_GETQDISC) && + !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) return -EPERM; err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); @@ -1151,7 +1152,7 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n) struct Qdisc *q, *p; int err; - if (!netlink_capable(skb, CAP_NET_ADMIN)) + if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) return -EPERM; replay: @@ -1490,7 +1491,8 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n) u32 qid; int err; - if ((n->nlmsg_type != RTM_GETTCLASS) && !netlink_capable(skb, CAP_NET_ADMIN)) + if ((n->nlmsg_type != RTM_GETTCLASS) && + !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) return -EPERM; err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 44cbb54c85746a..af5afca4b85a2d 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1105,14 +1105,15 @@ int sctp_register_pf(struct sctp_pf *pf, sa_family_t family) static inline int init_sctp_mibs(struct net *net) { - return snmp_mib_init((void __percpu **)net->sctp.sctp_statistics, - sizeof(struct sctp_mib), - __alignof__(struct sctp_mib)); + net->sctp.sctp_statistics = alloc_percpu(struct sctp_mib); + if (!net->sctp.sctp_statistics) + return -ENOMEM; + return 0; } static inline void cleanup_sctp_mibs(struct net *net) { - snmp_mib_free((void __percpu **)net->sctp.sctp_statistics); + free_percpu(net->sctp.sctp_statistics); } static void sctp_v4_pf_init(void) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index fee06b99a4da8d..e37b2cbbf177da 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -71,6 +71,7 @@ #include #include #include +#include #include /* for sa_family_t */ #include @@ -6557,6 +6558,10 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, if (sk->sk_shutdown & RCV_SHUTDOWN) break; + if (sk_can_busy_loop(sk) && + sk_busy_loop(sk, noblock)) + continue; + /* User doesn't want to wait. */ error = -EAGAIN; if (!timeo) diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 7144eb6a1b95cc..d49dc2ed30adb9 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -204,6 +205,9 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event) if (sock_flag(sk, SOCK_DEAD) || (sk->sk_shutdown & RCV_SHUTDOWN)) goto out_free; + if (!sctp_ulpevent_is_notification(event)) + sk_mark_napi_id(sk, skb); + /* Check if the user wishes to receive this event. */ if (!sctp_ulpevent_is_enabled(event, &sctp_sk(sk)->subscribe)) goto out_free; diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 5285ead196c06d..247e973544bfe3 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -296,7 +296,7 @@ static void rpcauth_unhash_cred_locked(struct rpc_cred *cred) { hlist_del_rcu(&cred->cr_hash); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); } diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 36e431ee1c902e..b6e440baccc373 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -143,7 +143,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) gss_get_ctx(ctx); rcu_assign_pointer(gss_cred->gc_ctx, ctx); set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); } diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 3513d559bc453d..9761a0da964d81 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -244,10 +244,10 @@ void xprt_free_bc_request(struct rpc_rqst *req) dprintk("RPC: free backchannel req=%p\n", req); req->rq_connect_cookie = xprt->connect_cookie - 1; - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); WARN_ON_ONCE(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); if (!xprt_need_to_requeue(xprt)) { /* diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index ae333c1845bb42..06636214113304 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -374,7 +374,7 @@ void sunrpc_destroy_cache_detail(struct cache_detail *cd) } return; out: - printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name); + printk(KERN_ERR "RPC: failed to unregister %s cache\n", cd->name); } EXPORT_SYMBOL_GPL(sunrpc_destroy_cache_detail); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index d173f79947c6bc..89d051de6b3e8d 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -230,9 +230,9 @@ static void xprt_clear_locked(struct rpc_xprt *xprt) { xprt->snd_task = NULL; if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state)) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(XPRT_LOCKED, &xprt->state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } else queue_work(rpciod_workqueue, &xprt->task_cleanup); } diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 25a3dcf15cae97..402a7e9a16b7cd 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -893,11 +893,11 @@ static void xs_close(struct rpc_xprt *xprt) xs_reset_transport(transport); xprt->reestablish_timeout = 0; - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); clear_bit(XPRT_CLOSE_WAIT, &xprt->state); clear_bit(XPRT_CLOSING, &xprt->state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); xprt_disconnect_done(xprt); } @@ -1497,12 +1497,12 @@ static void xs_tcp_cancel_linger_timeout(struct rpc_xprt *xprt) static void xs_sock_reset_connection_flags(struct rpc_xprt *xprt) { - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); clear_bit(XPRT_CONNECTION_CLOSE, &xprt->state); clear_bit(XPRT_CLOSE_WAIT, &xprt->state); clear_bit(XPRT_CLOSING, &xprt->state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } static void xs_sock_mark_closed(struct rpc_xprt *xprt) @@ -1556,10 +1556,10 @@ static void xs_tcp_state_change(struct sock *sk) xprt->connect_cookie++; xprt->reestablish_timeout = 0; set_bit(XPRT_CLOSING, &xprt->state); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(XPRT_CONNECTED, &xprt->state); clear_bit(XPRT_CLOSE_WAIT, &xprt->state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); xs_tcp_schedule_linger_timeout(xprt, xs_tcp_fin_timeout); break; case TCP_CLOSE_WAIT: @@ -1578,9 +1578,9 @@ static void xs_tcp_state_change(struct sock *sk) case TCP_LAST_ACK: set_bit(XPRT_CLOSING, &xprt->state); xs_tcp_schedule_linger_timeout(xprt, xs_tcp_fin_timeout); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(XPRT_CONNECTED, &xprt->state); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); break; case TCP_CLOSE: xs_tcp_cancel_linger_timeout(xprt); diff --git a/net/tipc/Makefile b/net/tipc/Makefile index b282f7130d2bb5..a080c66d819a03 100644 --- a/net/tipc/Makefile +++ b/net/tipc/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_TIPC) := tipc.o tipc-y += addr.o bcast.o bearer.o config.o \ - core.o handler.o link.o discover.o msg.o \ + core.o link.o discover.o msg.o \ name_distr.o subscr.o name_table.o net.o \ netlink.o node.o node_subscr.o port.o ref.o \ socket.o log.o eth_media.o server.o diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 95ab5ef92920fd..a0978d0890cb33 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -71,7 +71,7 @@ struct tipc_bcbearer_pair { * Note: The fields labelled "temporary" are incorporated into the bearer * to avoid consuming potentially limited stack space through the use of * large local variables within multicast routines. Concurrent access is - * prevented through use of the spinlock "bc_lock". + * prevented through use of the spinlock "bclink_lock". */ struct tipc_bcbearer { struct tipc_bearer bearer; @@ -84,34 +84,64 @@ struct tipc_bcbearer { /** * struct tipc_bclink - link used for broadcast messages + * @lock: spinlock governing access to structure * @link: (non-standard) broadcast link structure * @node: (non-standard) node structure representing b'cast link's peer node + * @flags: represent bclink states * @bcast_nodes: map of broadcast-capable nodes * @retransmit_to: node that most recently requested a retransmit * * Handles sequence numbering, fragmentation, bundling, etc. */ struct tipc_bclink { + spinlock_t lock; struct tipc_link link; struct tipc_node node; + unsigned int flags; struct tipc_node_map bcast_nodes; struct tipc_node *retransmit_to; }; -static struct tipc_bcbearer bcast_bearer; -static struct tipc_bclink bcast_link; - -static struct tipc_bcbearer *bcbearer = &bcast_bearer; -static struct tipc_bclink *bclink = &bcast_link; -static struct tipc_link *bcl = &bcast_link.link; - -static DEFINE_SPINLOCK(bc_lock); +static struct tipc_bcbearer *bcbearer; +static struct tipc_bclink *bclink; +static struct tipc_link *bcl; const char tipc_bclink_name[] = "broadcast-link"; static void tipc_nmap_diff(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b, struct tipc_node_map *nm_diff); +static void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node); +static void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node); + +static void tipc_bclink_lock(void) +{ + spin_lock_bh(&bclink->lock); +} + +static void tipc_bclink_unlock(void) +{ + struct tipc_node *node = NULL; + + if (likely(!bclink->flags)) { + spin_unlock_bh(&bclink->lock); + return; + } + + if (bclink->flags & TIPC_BCLINK_RESET) { + bclink->flags &= ~TIPC_BCLINK_RESET; + node = tipc_bclink_retransmit_to(); + } + spin_unlock_bh(&bclink->lock); + + if (node) + tipc_link_reset_all(node); +} + +void tipc_bclink_set_flags(unsigned int flags) +{ + bclink->flags |= flags; +} static u32 bcbuf_acks(struct sk_buff *buf) { @@ -130,16 +160,16 @@ static void bcbuf_decr_acks(struct sk_buff *buf) void tipc_bclink_add_node(u32 addr) { - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); tipc_nmap_add(&bclink->bcast_nodes, addr); - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); } void tipc_bclink_remove_node(u32 addr) { - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); tipc_nmap_remove(&bclink->bcast_nodes, addr); - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); } static void bclink_set_last_sent(void) @@ -165,7 +195,7 @@ static void bclink_update_last_sent(struct tipc_node *node, u32 seqno) /** * tipc_bclink_retransmit_to - get most recent node to request retransmission * - * Called with bc_lock locked + * Called with bclink_lock locked */ struct tipc_node *tipc_bclink_retransmit_to(void) { @@ -177,7 +207,7 @@ struct tipc_node *tipc_bclink_retransmit_to(void) * @after: sequence number of last packet to *not* retransmit * @to: sequence number of last packet to retransmit * - * Called with bc_lock locked + * Called with bclink_lock locked */ static void bclink_retransmit_pkt(u32 after, u32 to) { @@ -194,7 +224,7 @@ static void bclink_retransmit_pkt(u32 after, u32 to) * @n_ptr: node that sent acknowledgement info * @acked: broadcast sequence # that has been acknowledged * - * Node is locked, bc_lock unlocked. + * Node is locked, bclink_lock unlocked. */ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked) { @@ -202,8 +232,7 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked) struct sk_buff *next; unsigned int released = 0; - spin_lock_bh(&bc_lock); - + tipc_bclink_lock(); /* Bail out if tx queue is empty (no clean up is required) */ crs = bcl->first_out; if (!crs) @@ -267,13 +296,13 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked) if (unlikely(released && !list_empty(&bcl->waiting_ports))) tipc_link_wakeup_ports(bcl, 0); exit: - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); } /** * tipc_bclink_update_link_state - update broadcast link state * - * tipc_net_lock and node lock set + * RCU and node lock set */ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent) { @@ -320,10 +349,10 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent) ? buf_seqno(n_ptr->bclink.deferred_head) - 1 : n_ptr->bclink.last_sent); - spin_lock_bh(&bc_lock); - tipc_bearer_send(&bcbearer->bearer, buf, NULL); + tipc_bclink_lock(); + tipc_bearer_send(MAX_BEARERS, buf, NULL); bcl->stats.sent_nacks++; - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); kfree_skb(buf); n_ptr->bclink.oos_state++; @@ -335,8 +364,6 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent) * * Delay any upcoming NACK by this node if another node has already * requested the first message this node is going to ask for. - * - * Only tipc_net_lock set. */ static void bclink_peek_nack(struct tipc_msg *msg) { @@ -362,7 +389,7 @@ int tipc_bclink_xmit(struct sk_buff *buf) { int res; - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); if (!bclink->bcast_nodes.count) { res = msg_data_sz(buf_msg(buf)); @@ -377,14 +404,14 @@ int tipc_bclink_xmit(struct sk_buff *buf) bcl->stats.accu_queue_sz += bcl->out_queue_size; } exit: - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); return res; } /** * bclink_accept_pkt - accept an incoming, in-sequence broadcast packet * - * Called with both sending node's lock and bc_lock taken. + * Called with both sending node's lock and bclink_lock taken. */ static void bclink_accept_pkt(struct tipc_node *node, u32 seqno) { @@ -408,7 +435,7 @@ static void bclink_accept_pkt(struct tipc_node *node, u32 seqno) /** * tipc_bclink_rcv - receive a broadcast packet, and deliver upwards * - * tipc_net_lock is read_locked, no other locks set + * RCU is locked, no other locks set */ void tipc_bclink_rcv(struct sk_buff *buf) { @@ -439,12 +466,12 @@ void tipc_bclink_rcv(struct sk_buff *buf) if (msg_destnode(msg) == tipc_own_addr) { tipc_bclink_acknowledge(node, msg_bcast_ack(msg)); tipc_node_unlock(node); - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); bcl->stats.recv_nacks++; bclink->retransmit_to = node; bclink_retransmit_pkt(msg_bcgap_after(msg), msg_bcgap_to(msg)); - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); } else { tipc_node_unlock(node); bclink_peek_nack(msg); @@ -462,20 +489,20 @@ void tipc_bclink_rcv(struct sk_buff *buf) /* Deliver message to destination */ if (likely(msg_isdata(msg))) { - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); bclink_accept_pkt(node, seqno); - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); tipc_node_unlock(node); if (likely(msg_mcast(msg))) tipc_port_mcast_rcv(buf, NULL); else kfree_skb(buf); } else if (msg_user(msg) == MSG_BUNDLER) { - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); bclink_accept_pkt(node, seqno); bcl->stats.recv_bundles++; bcl->stats.recv_bundled += msg_msgcnt(msg); - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); tipc_node_unlock(node); tipc_link_bundle_rcv(buf); } else if (msg_user(msg) == MSG_FRAGMENTER) { @@ -485,28 +512,28 @@ void tipc_bclink_rcv(struct sk_buff *buf) &buf); if (ret == LINK_REASM_ERROR) goto unlock; - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); bclink_accept_pkt(node, seqno); bcl->stats.recv_fragments++; if (ret == LINK_REASM_COMPLETE) { bcl->stats.recv_fragmented++; /* Point msg to inner header */ msg = buf_msg(buf); - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); goto receive; } - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); tipc_node_unlock(node); } else if (msg_user(msg) == NAME_DISTRIBUTOR) { - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); bclink_accept_pkt(node, seqno); - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); tipc_node_unlock(node); tipc_named_rcv(buf); } else { - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); bclink_accept_pkt(node, seqno); - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); tipc_node_unlock(node); kfree_skb(buf); } @@ -552,14 +579,14 @@ void tipc_bclink_rcv(struct sk_buff *buf) } else deferred = 0; - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); if (deferred) bcl->stats.deferred_recv++; else bcl->stats.duplicates++; - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); unlock: tipc_node_unlock(node); @@ -627,13 +654,13 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, if (bp_index == 0) { /* Use original buffer for first bearer */ - tipc_bearer_send(b, buf, &b->bcast_addr); + tipc_bearer_send(b->identity, buf, &b->bcast_addr); } else { /* Avoid concurrent buffer access */ tbuf = pskb_copy(buf, GFP_ATOMIC); if (!tbuf) break; - tipc_bearer_send(b, tbuf, &b->bcast_addr); + tipc_bearer_send(b->identity, tbuf, &b->bcast_addr); kfree_skb(tbuf); /* Bearer keeps a clone */ } @@ -655,20 +682,27 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, /** * tipc_bcbearer_sort - create sets of bearer pairs used by broadcast bearer */ -void tipc_bcbearer_sort(void) +void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action) { struct tipc_bcbearer_pair *bp_temp = bcbearer->bpairs_temp; struct tipc_bcbearer_pair *bp_curr; + struct tipc_bearer *b; int b_index; int pri; - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); + + if (action) + tipc_nmap_add(nm_ptr, node); + else + tipc_nmap_remove(nm_ptr, node); /* Group bearers by priority (can assume max of two per priority) */ memset(bp_temp, 0, sizeof(bcbearer->bpairs_temp)); + rcu_read_lock(); for (b_index = 0; b_index < MAX_BEARERS; b_index++) { - struct tipc_bearer *b = bearer_list[b_index]; + b = rcu_dereference_rtnl(bearer_list[b_index]); if (!b || !b->nodes.count) continue; @@ -677,6 +711,7 @@ void tipc_bcbearer_sort(void) else bp_temp[b->priority].secondary = b; } + rcu_read_unlock(); /* Create array of bearer pairs for broadcasting */ bp_curr = bcbearer->bpairs; @@ -702,7 +737,7 @@ void tipc_bcbearer_sort(void) bp_curr++; } - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); } @@ -714,7 +749,7 @@ int tipc_bclink_stats(char *buf, const u32 buf_size) if (!bcl) return 0; - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); s = &bcl->stats; @@ -743,7 +778,7 @@ int tipc_bclink_stats(char *buf, const u32 buf_size) s->queue_sz_counts ? (s->accu_queue_sz / s->queue_sz_counts) : 0); - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); return ret; } @@ -752,9 +787,9 @@ int tipc_bclink_reset_stats(void) if (!bcl) return -ENOPROTOOPT; - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); memset(&bcl->stats, 0, sizeof(bcl->stats)); - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); return 0; } @@ -765,46 +800,59 @@ int tipc_bclink_set_queue_limits(u32 limit) if ((limit < TIPC_MIN_LINK_WIN) || (limit > TIPC_MAX_LINK_WIN)) return -EINVAL; - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); tipc_link_set_queue_limits(bcl, limit); - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); return 0; } -void tipc_bclink_init(void) +int tipc_bclink_init(void) { + bcbearer = kzalloc(sizeof(*bcbearer), GFP_ATOMIC); + if (!bcbearer) + return -ENOMEM; + + bclink = kzalloc(sizeof(*bclink), GFP_ATOMIC); + if (!bclink) { + kfree(bcbearer); + return -ENOMEM; + } + + bcl = &bclink->link; bcbearer->bearer.media = &bcbearer->media; bcbearer->media.send_msg = tipc_bcbearer_send; sprintf(bcbearer->media.name, "tipc-broadcast"); + spin_lock_init(&bclink->lock); INIT_LIST_HEAD(&bcl->waiting_ports); bcl->next_out_no = 1; spin_lock_init(&bclink->node.lock); bcl->owner = &bclink->node; bcl->max_pkt = MAX_PKT_DEFAULT_MCAST; tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT); - bcl->b_ptr = &bcbearer->bearer; - bearer_list[BCBEARER] = &bcbearer->bearer; + bcl->bearer_id = MAX_BEARERS; + rcu_assign_pointer(bearer_list[MAX_BEARERS], &bcbearer->bearer); bcl->state = WORKING_WORKING; strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME); + return 0; } void tipc_bclink_stop(void) { - spin_lock_bh(&bc_lock); + tipc_bclink_lock(); tipc_link_purge_queues(bcl); - spin_unlock_bh(&bc_lock); + tipc_bclink_unlock(); - bearer_list[BCBEARER] = NULL; - memset(bclink, 0, sizeof(*bclink)); - memset(bcbearer, 0, sizeof(*bcbearer)); + RCU_INIT_POINTER(bearer_list[BCBEARER], NULL); + synchronize_net(); + kfree(bcbearer); + kfree(bclink); } - /** * tipc_nmap_add - add a node to a node map */ -void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node) +static void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node) { int n = tipc_node(node); int w = n / WSIZE; @@ -819,7 +867,7 @@ void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node) /** * tipc_nmap_remove - remove a node from a node map */ -void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node) +static void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node) { int n = tipc_node(node); int w = n / WSIZE; diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index a80ef54b818e22..00330c45df3e04 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -39,6 +39,7 @@ #define MAX_NODES 4096 #define WSIZE 32 +#define TIPC_BCLINK_RESET 1 /** * struct tipc_node_map - set of node identifiers @@ -69,9 +70,6 @@ struct tipc_node; extern const char tipc_bclink_name[]; -void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node); -void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node); - /** * tipc_nmap_equal - test for equality of node maps */ @@ -84,8 +82,9 @@ static inline int tipc_nmap_equal(struct tipc_node_map *nm_a, void tipc_port_list_add(struct tipc_port_list *pl_ptr, u32 port); void tipc_port_list_free(struct tipc_port_list *pl_ptr); -void tipc_bclink_init(void); +int tipc_bclink_init(void); void tipc_bclink_stop(void); +void tipc_bclink_set_flags(unsigned int flags); void tipc_bclink_add_node(u32 addr); void tipc_bclink_remove_node(u32 addr); struct tipc_node *tipc_bclink_retransmit_to(void); @@ -98,6 +97,6 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent); int tipc_bclink_stats(char *stats_buf, const u32 buf_size); int tipc_bclink_reset_stats(void); int tipc_bclink_set_queue_limits(u32 limit); -void tipc_bcbearer_sort(void); +void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action); #endif diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 3fef7eb776dc12..f3259d4133b62f 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -49,7 +49,7 @@ static struct tipc_media * const media_info_array[] = { NULL }; -struct tipc_bearer *bearer_list[MAX_BEARERS + 1]; +struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1]; static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down); @@ -178,7 +178,7 @@ struct tipc_bearer *tipc_bearer_find(const char *name) u32 i; for (i = 0; i < MAX_BEARERS; i++) { - b_ptr = bearer_list[i]; + b_ptr = rtnl_dereference(bearer_list[i]); if (b_ptr && (!strcmp(b_ptr->name, name))) return b_ptr; } @@ -198,10 +198,9 @@ struct sk_buff *tipc_bearer_get_names(void) if (!buf) return NULL; - read_lock_bh(&tipc_net_lock); for (i = 0; media_info_array[i] != NULL; i++) { for (j = 0; j < MAX_BEARERS; j++) { - b = bearer_list[j]; + b = rtnl_dereference(bearer_list[j]); if (!b) continue; if (b->media == media_info_array[i]) { @@ -211,22 +210,33 @@ struct sk_buff *tipc_bearer_get_names(void) } } } - read_unlock_bh(&tipc_net_lock); return buf; } -void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest) +void tipc_bearer_add_dest(u32 bearer_id, u32 dest) { - tipc_nmap_add(&b_ptr->nodes, dest); - tipc_bcbearer_sort(); - tipc_disc_add_dest(b_ptr->link_req); + struct tipc_bearer *b_ptr; + + rcu_read_lock(); + b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]); + if (b_ptr) { + tipc_bcbearer_sort(&b_ptr->nodes, dest, true); + tipc_disc_add_dest(b_ptr->link_req); + } + rcu_read_unlock(); } -void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest) +void tipc_bearer_remove_dest(u32 bearer_id, u32 dest) { - tipc_nmap_remove(&b_ptr->nodes, dest); - tipc_bcbearer_sort(); - tipc_disc_remove_dest(b_ptr->link_req); + struct tipc_bearer *b_ptr; + + rcu_read_lock(); + b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]); + if (b_ptr) { + tipc_bcbearer_sort(&b_ptr->nodes, dest, false); + tipc_disc_remove_dest(b_ptr->link_req); + } + rcu_read_unlock(); } /** @@ -271,13 +281,11 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) return -EINVAL; } - write_lock_bh(&tipc_net_lock); - m_ptr = tipc_media_find(b_names.media_name); if (!m_ptr) { pr_warn("Bearer <%s> rejected, media <%s> not registered\n", name, b_names.media_name); - goto exit; + return -EINVAL; } if (priority == TIPC_MEDIA_LINK_PRI) @@ -287,7 +295,7 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) bearer_id = MAX_BEARERS; with_this_prio = 1; for (i = MAX_BEARERS; i-- != 0; ) { - b_ptr = bearer_list[i]; + b_ptr = rtnl_dereference(bearer_list[i]); if (!b_ptr) { bearer_id = i; continue; @@ -295,14 +303,14 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) if (!strcmp(name, b_ptr->name)) { pr_warn("Bearer <%s> rejected, already enabled\n", name); - goto exit; + return -EINVAL; } if ((b_ptr->priority == priority) && (++with_this_prio > 2)) { if (priority-- == 0) { pr_warn("Bearer <%s> rejected, duplicate priority\n", name); - goto exit; + return -EINVAL; } pr_warn("Bearer <%s> priority adjustment required %u->%u\n", name, priority + 1, priority); @@ -312,21 +320,20 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) if (bearer_id >= MAX_BEARERS) { pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n", name, MAX_BEARERS); - goto exit; + return -EINVAL; } b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC); - if (!b_ptr) { - res = -ENOMEM; - goto exit; - } + if (!b_ptr) + return -ENOMEM; + strcpy(b_ptr->name, name); b_ptr->media = m_ptr; res = m_ptr->enable_media(b_ptr); if (res) { pr_warn("Bearer <%s> rejected, enable failure (%d)\n", name, -res); - goto exit; + return -EINVAL; } b_ptr->identity = bearer_id; @@ -341,16 +348,14 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) bearer_disable(b_ptr, false); pr_warn("Bearer <%s> rejected, discovery object creation failed\n", name); - goto exit; + return -EINVAL; } - bearer_list[bearer_id] = b_ptr; + rcu_assign_pointer(bearer_list[bearer_id], b_ptr); pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n", name, tipc_addr_string_fill(addr_string, disc_domain), priority); -exit: - write_unlock_bh(&tipc_net_lock); return res; } @@ -359,19 +364,16 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) */ static int tipc_reset_bearer(struct tipc_bearer *b_ptr) { - read_lock_bh(&tipc_net_lock); pr_info("Resetting bearer <%s>\n", b_ptr->name); - tipc_disc_delete(b_ptr->link_req); tipc_link_reset_list(b_ptr->identity); - tipc_disc_create(b_ptr, &b_ptr->bcast_addr); - read_unlock_bh(&tipc_net_lock); + tipc_disc_reset(b_ptr); return 0; } /** * bearer_disable * - * Note: This routine assumes caller holds tipc_net_lock. + * Note: This routine assumes caller holds RTNL lock. */ static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down) { @@ -385,12 +387,12 @@ static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down) tipc_disc_delete(b_ptr->link_req); for (i = 0; i < MAX_BEARERS; i++) { - if (b_ptr == bearer_list[i]) { - bearer_list[i] = NULL; + if (b_ptr == rtnl_dereference(bearer_list[i])) { + RCU_INIT_POINTER(bearer_list[i], NULL); break; } } - kfree(b_ptr); + kfree_rcu(b_ptr, rcu); } int tipc_disable_bearer(const char *name) @@ -398,7 +400,6 @@ int tipc_disable_bearer(const char *name) struct tipc_bearer *b_ptr; int res; - write_lock_bh(&tipc_net_lock); b_ptr = tipc_bearer_find(name); if (b_ptr == NULL) { pr_warn("Attempt to disable unknown bearer <%s>\n", name); @@ -407,7 +408,6 @@ int tipc_disable_bearer(const char *name) bearer_disable(b_ptr, false); res = 0; } - write_unlock_bh(&tipc_net_lock); return res; } @@ -444,7 +444,7 @@ int tipc_enable_l2_media(struct tipc_bearer *b) return -ENODEV; /* Associate TIPC bearer with Ethernet bearer */ - b->media_ptr = dev; + rcu_assign_pointer(b->media_ptr, dev); memset(b->bcast_addr.value, 0, sizeof(b->bcast_addr.value)); memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len); b->bcast_addr.media_id = b->media->type_id; @@ -463,8 +463,12 @@ int tipc_enable_l2_media(struct tipc_bearer *b) */ void tipc_disable_l2_media(struct tipc_bearer *b) { - struct net_device *dev = (struct net_device *)b->media_ptr; + struct net_device *dev; + + dev = (struct net_device *)rtnl_dereference(b->media_ptr); + RCU_INIT_POINTER(b->media_ptr, NULL); RCU_INIT_POINTER(dev->tipc_ptr, NULL); + synchronize_net(); dev_put(dev); } @@ -478,8 +482,12 @@ int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b, struct tipc_media_addr *dest) { struct sk_buff *clone; + struct net_device *dev; int delta; - struct net_device *dev = (struct net_device *)b->media_ptr; + + dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr); + if (!dev) + return 0; clone = skb_clone(buf, GFP_ATOMIC); if (!clone) @@ -507,10 +515,16 @@ int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b, * The media send routine must not alter the buffer being passed in * as it may be needed for later retransmission! */ -void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf, +void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf, struct tipc_media_addr *dest) { - b->media->send_msg(buf, b, dest); + struct tipc_bearer *b_ptr; + + rcu_read_lock(); + b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]); + if (likely(b_ptr)) + b_ptr->media->send_msg(buf, b_ptr, dest); + rcu_read_unlock(); } /** @@ -535,7 +549,7 @@ static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev, } rcu_read_lock(); - b_ptr = rcu_dereference(dev->tipc_ptr); + b_ptr = rcu_dereference_rtnl(dev->tipc_ptr); if (likely(b_ptr)) { if (likely(buf->pkt_type <= PACKET_BROADCAST)) { buf->next = NULL; @@ -568,12 +582,9 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt, if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; - rcu_read_lock(); - b_ptr = rcu_dereference(dev->tipc_ptr); - if (!b_ptr) { - rcu_read_unlock(); + b_ptr = rtnl_dereference(dev->tipc_ptr); + if (!b_ptr) return NOTIFY_DONE; - } b_ptr->mtu = dev->mtu; @@ -592,11 +603,9 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt, break; case NETDEV_UNREGISTER: case NETDEV_CHANGENAME: - tipc_disable_bearer(b_ptr->name); + bearer_disable(b_ptr, false); break; } - rcu_read_unlock(); - return NOTIFY_OK; } @@ -633,7 +642,7 @@ void tipc_bearer_stop(void) u32 i; for (i = 0; i < MAX_BEARERS; i++) { - b_ptr = bearer_list[i]; + b_ptr = rtnl_dereference(bearer_list[i]); if (b_ptr) { bearer_disable(b_ptr, true); bearer_list[i] = NULL; diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index ba48145e871dd8..a983b3005e715b 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -113,6 +113,7 @@ struct tipc_media { * @name: bearer name (format = media:interface) * @media: ptr to media structure associated with bearer * @bcast_addr: media address used in broadcasting + * @rcu: rcu struct for tipc_bearer * @priority: default link priority for bearer * @window: default window size for bearer * @tolerance: default link tolerance for bearer @@ -127,12 +128,13 @@ struct tipc_media { * care of initializing all other fields. */ struct tipc_bearer { - void *media_ptr; /* initalized by media */ + void __rcu *media_ptr; /* initalized by media */ u32 mtu; /* initalized by media */ struct tipc_media_addr addr; /* initalized by media */ char name[TIPC_MAX_BEARER_NAME]; struct tipc_media *media; struct tipc_media_addr bcast_addr; + struct rcu_head rcu; u32 priority; u32 window; u32 tolerance; @@ -150,7 +152,7 @@ struct tipc_bearer_names { struct tipc_link; -extern struct tipc_bearer *bearer_list[]; +extern struct tipc_bearer __rcu *bearer_list[]; /* * TIPC routines available to supported media types @@ -181,14 +183,14 @@ int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b, struct tipc_media_addr *dest); struct sk_buff *tipc_bearer_get_names(void); -void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest); -void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest); +void tipc_bearer_add_dest(u32 bearer_id, u32 dest); +void tipc_bearer_remove_dest(u32 bearer_id, u32 dest); struct tipc_bearer *tipc_bearer_find(const char *name); struct tipc_media *tipc_media_find(const char *name); int tipc_bearer_setup(void); void tipc_bearer_cleanup(void); void tipc_bearer_stop(void); -void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf, +void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf, struct tipc_media_addr *dest); #endif /* _TIPC_BEARER_H */ diff --git a/net/tipc/config.c b/net/tipc/config.c index 4b981c053823e9..2b42403ad33a69 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c @@ -42,8 +42,6 @@ #define REPLY_TRUNCATED "\n" -static DEFINE_MUTEX(config_mutex); - static const void *req_tlv_area; /* request message TLV area */ static int req_tlv_space; /* request message TLV area size */ static int rep_headroom; /* reply message headroom to use */ @@ -179,8 +177,10 @@ static struct sk_buff *cfg_set_own_addr(void) if (tipc_own_addr) return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (cannot change node address once assigned)"); - tipc_net_start(addr); - return tipc_cfg_reply_none(); + if (!tipc_net_start(addr)) + return tipc_cfg_reply_none(); + + return tipc_cfg_reply_error_string("cannot change to network mode"); } static struct sk_buff *cfg_set_max_ports(void) @@ -223,7 +223,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area { struct sk_buff *rep_tlv_buf; - mutex_lock(&config_mutex); + rtnl_lock(); /* Save request and reply details in a well-known location */ req_tlv_area = request_area; @@ -337,6 +337,6 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area /* Return reply buffer */ exit: - mutex_unlock(&config_mutex); + rtnl_unlock(); return rep_tlv_buf; } diff --git a/net/tipc/core.c b/net/tipc/core.c index 50d57429ebcaf8..57f8ae9aa46666 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -80,7 +80,6 @@ struct sk_buff *tipc_buf_acquire(u32 size) */ static void tipc_core_stop(void) { - tipc_handler_stop(); tipc_net_stop(); tipc_bearer_cleanup(); tipc_netlink_stop(); @@ -100,10 +99,6 @@ static int tipc_core_start(void) get_random_bytes(&tipc_random, sizeof(tipc_random)); - err = tipc_handler_start(); - if (err) - goto out_handler; - err = tipc_ref_table_init(tipc_max_ports, tipc_random); if (err) goto out_reftbl; @@ -146,8 +141,6 @@ static int tipc_core_start(void) out_nametbl: tipc_ref_table_stop(); out_reftbl: - tipc_handler_stop(); -out_handler: return err; } diff --git a/net/tipc/core.h b/net/tipc/core.h index 8985bbcb942bdb..ae55d37267e6a3 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -56,7 +56,7 @@ #include #include #include - +#include #define TIPC_MOD_VER "2.0.0" @@ -89,8 +89,6 @@ extern int tipc_random __read_mostly; /* * Routines available to privileged subsystems */ -int tipc_handler_start(void); -void tipc_handler_stop(void); int tipc_netlink_start(void); void tipc_netlink_stop(void); int tipc_socket_init(void); @@ -109,12 +107,10 @@ void tipc_unregister_sysctl(void); #endif /* - * TIPC timer and signal code + * TIPC timer code */ typedef void (*Handler) (unsigned long); -u32 tipc_k_signal(Handler routine, unsigned long argument); - /** * k_init_timer - initialize a timer * @timer: pointer to timer structure diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 542fe3413dc4e8..bd35c4a0746f3a 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -46,8 +46,9 @@ /** * struct tipc_link_req - information about an ongoing link setup request - * @bearer: bearer issuing requests + * @bearer_id: identity of bearer issuing requests * @dest: destination address for request messages + * @domain: network domain to which links can be established * @num_nodes: number of nodes currently discovered (i.e. with an active link) * @lock: spinlock for controlling access to requests * @buf: request message to be (repeatedly) sent @@ -55,8 +56,9 @@ * @timer_intv: current interval between requests (in ms) */ struct tipc_link_req { - struct tipc_bearer *bearer; + u32 bearer_id; struct tipc_media_addr dest; + u32 domain; int num_nodes; spinlock_t lock; struct sk_buff *buf; @@ -69,22 +71,19 @@ struct tipc_link_req { * @type: message type (request or response) * @b_ptr: ptr to bearer issuing message */ -static struct sk_buff *tipc_disc_init_msg(u32 type, struct tipc_bearer *b_ptr) +static void tipc_disc_init_msg(struct sk_buff *buf, u32 type, + struct tipc_bearer *b_ptr) { - struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE); struct tipc_msg *msg; u32 dest_domain = b_ptr->domain; - if (buf) { - msg = buf_msg(buf); - tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain); - msg_set_non_seq(msg, 1); - msg_set_node_sig(msg, tipc_random); - msg_set_dest_domain(msg, dest_domain); - msg_set_bc_netid(msg, tipc_net_id); - b_ptr->media->addr2msg(&b_ptr->addr, msg_media_addr(msg)); - } - return buf; + msg = buf_msg(buf); + tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain); + msg_set_non_seq(msg, 1); + msg_set_node_sig(msg, tipc_random); + msg_set_dest_domain(msg, dest_domain); + msg_set_bc_netid(msg, tipc_net_id); + b_ptr->media->addr2msg(&b_ptr->addr, msg_media_addr(msg)); } /** @@ -239,9 +238,10 @@ void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr) link_fully_up = link_working_working(link); if ((type == DSC_REQ_MSG) && !link_fully_up) { - rbuf = tipc_disc_init_msg(DSC_RESP_MSG, b_ptr); + rbuf = tipc_buf_acquire(INT_H_SIZE); if (rbuf) { - tipc_bearer_send(b_ptr, rbuf, &media_addr); + tipc_disc_init_msg(rbuf, DSC_RESP_MSG, b_ptr); + tipc_bearer_send(b_ptr->identity, rbuf, &media_addr); kfree_skb(rbuf); } } @@ -303,7 +303,7 @@ static void disc_timeout(struct tipc_link_req *req) spin_lock_bh(&req->lock); /* Stop searching if only desired node has been found */ - if (tipc_node(req->bearer->domain) && req->num_nodes) { + if (tipc_node(req->domain) && req->num_nodes) { req->timer_intv = TIPC_LINK_REQ_INACTIVE; goto exit; } @@ -315,7 +315,7 @@ static void disc_timeout(struct tipc_link_req *req) * hold at fast polling rate if don't have any associated nodes, * otherwise hold at slow polling rate */ - tipc_bearer_send(req->bearer, req->buf, &req->dest); + tipc_bearer_send(req->bearer_id, req->buf, &req->dest); req->timer_intv *= 2; @@ -347,21 +347,23 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest) if (!req) return -ENOMEM; - req->buf = tipc_disc_init_msg(DSC_REQ_MSG, b_ptr); + req->buf = tipc_buf_acquire(INT_H_SIZE); if (!req->buf) { kfree(req); - return -ENOMSG; + return -ENOMEM; } + tipc_disc_init_msg(req->buf, DSC_REQ_MSG, b_ptr); memcpy(&req->dest, dest, sizeof(*dest)); - req->bearer = b_ptr; + req->bearer_id = b_ptr->identity; + req->domain = b_ptr->domain; req->num_nodes = 0; req->timer_intv = TIPC_LINK_REQ_INIT; spin_lock_init(&req->lock); k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); k_start_timer(&req->timer, req->timer_intv); b_ptr->link_req = req; - tipc_bearer_send(req->bearer, req->buf, &req->dest); + tipc_bearer_send(req->bearer_id, req->buf, &req->dest); return 0; } @@ -376,3 +378,23 @@ void tipc_disc_delete(struct tipc_link_req *req) kfree_skb(req->buf); kfree(req); } + +/** + * tipc_disc_reset - reset object to send periodic link setup requests + * @b_ptr: ptr to bearer issuing requests + * @dest_domain: network domain to which links can be established + */ +void tipc_disc_reset(struct tipc_bearer *b_ptr) +{ + struct tipc_link_req *req = b_ptr->link_req; + + spin_lock_bh(&req->lock); + tipc_disc_init_msg(req->buf, DSC_REQ_MSG, b_ptr); + req->bearer_id = b_ptr->identity; + req->domain = b_ptr->domain; + req->num_nodes = 0; + req->timer_intv = TIPC_LINK_REQ_INIT; + k_start_timer(&req->timer, req->timer_intv); + tipc_bearer_send(req->bearer_id, req->buf, &req->dest); + spin_unlock_bh(&req->lock); +} diff --git a/net/tipc/discover.h b/net/tipc/discover.h index 07f34729459dca..515b57392f4d88 100644 --- a/net/tipc/discover.h +++ b/net/tipc/discover.h @@ -41,6 +41,7 @@ struct tipc_link_req; int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest); void tipc_disc_delete(struct tipc_link_req *req); +void tipc_disc_reset(struct tipc_bearer *b_ptr); void tipc_disc_add_dest(struct tipc_link_req *req); void tipc_disc_remove_dest(struct tipc_link_req *req); void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr); diff --git a/net/tipc/handler.c b/net/tipc/handler.c deleted file mode 100644 index 1fabf160501f4f..00000000000000 --- a/net/tipc/handler.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * net/tipc/handler.c: TIPC signal handling - * - * Copyright (c) 2000-2006, Ericsson AB - * Copyright (c) 2005, Wind River Systems - * 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. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the names of the copyright holders nor the names of its - * contributors may 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") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "core.h" - -struct queue_item { - struct list_head next_signal; - void (*handler) (unsigned long); - unsigned long data; -}; - -static struct kmem_cache *tipc_queue_item_cache; -static struct list_head signal_queue_head; -static DEFINE_SPINLOCK(qitem_lock); -static int handler_enabled __read_mostly; - -static void process_signal_queue(unsigned long dummy); - -static DECLARE_TASKLET_DISABLED(tipc_tasklet, process_signal_queue, 0); - - -unsigned int tipc_k_signal(Handler routine, unsigned long argument) -{ - struct queue_item *item; - - spin_lock_bh(&qitem_lock); - if (!handler_enabled) { - spin_unlock_bh(&qitem_lock); - return -ENOPROTOOPT; - } - - item = kmem_cache_alloc(tipc_queue_item_cache, GFP_ATOMIC); - if (!item) { - pr_err("Signal queue out of memory\n"); - spin_unlock_bh(&qitem_lock); - return -ENOMEM; - } - item->handler = routine; - item->data = argument; - list_add_tail(&item->next_signal, &signal_queue_head); - spin_unlock_bh(&qitem_lock); - tasklet_schedule(&tipc_tasklet); - return 0; -} - -static void process_signal_queue(unsigned long dummy) -{ - struct queue_item *__volatile__ item; - struct list_head *l, *n; - - spin_lock_bh(&qitem_lock); - list_for_each_safe(l, n, &signal_queue_head) { - item = list_entry(l, struct queue_item, next_signal); - list_del(&item->next_signal); - spin_unlock_bh(&qitem_lock); - item->handler(item->data); - spin_lock_bh(&qitem_lock); - kmem_cache_free(tipc_queue_item_cache, item); - } - spin_unlock_bh(&qitem_lock); -} - -int tipc_handler_start(void) -{ - tipc_queue_item_cache = - kmem_cache_create("tipc_queue_items", sizeof(struct queue_item), - 0, SLAB_HWCACHE_ALIGN, NULL); - if (!tipc_queue_item_cache) - return -ENOMEM; - - INIT_LIST_HEAD(&signal_queue_head); - tasklet_enable(&tipc_tasklet); - handler_enabled = 1; - return 0; -} - -void tipc_handler_stop(void) -{ - struct list_head *l, *n; - struct queue_item *item; - - spin_lock_bh(&qitem_lock); - if (!handler_enabled) { - spin_unlock_bh(&qitem_lock); - return; - } - handler_enabled = 0; - spin_unlock_bh(&qitem_lock); - - tasklet_kill(&tipc_tasklet); - - spin_lock_bh(&qitem_lock); - list_for_each_safe(l, n, &signal_queue_head) { - item = list_entry(l, struct queue_item, next_signal); - list_del(&item->next_signal); - kmem_cache_free(tipc_queue_item_cache, item); - } - spin_unlock_bh(&qitem_lock); - - kmem_cache_destroy(tipc_queue_item_cache); -} diff --git a/net/tipc/link.c b/net/tipc/link.c index c5190ab75290d0..dce2bef817206d 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -101,9 +101,18 @@ static unsigned int align(unsigned int i) static void link_init_max_pkt(struct tipc_link *l_ptr) { + struct tipc_bearer *b_ptr; u32 max_pkt; - max_pkt = (l_ptr->b_ptr->mtu & ~3); + rcu_read_lock(); + b_ptr = rcu_dereference_rtnl(bearer_list[l_ptr->bearer_id]); + if (!b_ptr) { + rcu_read_unlock(); + return; + } + max_pkt = (b_ptr->mtu & ~3); + rcu_read_unlock(); + if (max_pkt > MAX_MSG_SIZE) max_pkt = MAX_MSG_SIZE; @@ -248,7 +257,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, l_ptr->owner = n_ptr; l_ptr->checkpoint = 1; l_ptr->peer_session = INVALID_SESSION; - l_ptr->b_ptr = b_ptr; + l_ptr->bearer_id = b_ptr->identity; link_set_supervision_props(l_ptr, b_ptr->tolerance); l_ptr->state = RESET_UNKNOWN; @@ -263,6 +272,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, l_ptr->priority = b_ptr->priority; tipc_link_set_queue_limits(l_ptr, b_ptr->window); + l_ptr->net_plane = b_ptr->net_plane; link_init_max_pkt(l_ptr); l_ptr->next_out_no = 1; @@ -287,14 +297,14 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down) rcu_read_lock(); list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) { - spin_lock_bh(&n_ptr->lock); + tipc_node_lock(n_ptr); l_ptr = n_ptr->links[bearer_id]; if (l_ptr) { tipc_link_reset(l_ptr); if (shutting_down || !tipc_node_is_up(n_ptr)) { tipc_node_detach_link(l_ptr->owner, l_ptr); tipc_link_reset_fragments(l_ptr); - spin_unlock_bh(&n_ptr->lock); + tipc_node_unlock(n_ptr); /* Nobody else can access this link now: */ del_timer_sync(&l_ptr->timer); @@ -302,12 +312,12 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down) } else { /* Detach/delete when failover is finished: */ l_ptr->flags |= LINK_STOPPED; - spin_unlock_bh(&n_ptr->lock); + tipc_node_unlock(n_ptr); del_timer_sync(&l_ptr->timer); } continue; } - spin_unlock_bh(&n_ptr->lock); + tipc_node_unlock(n_ptr); } rcu_read_unlock(); } @@ -426,7 +436,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) return; tipc_node_link_down(l_ptr->owner, l_ptr); - tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr); + tipc_bearer_remove_dest(l_ptr->bearer_id, l_ptr->addr); if (was_active_link && tipc_node_active_links(l_ptr->owner)) { l_ptr->reset_checkpoint = checkpoint; @@ -464,11 +474,11 @@ void tipc_link_reset_list(unsigned int bearer_id) rcu_read_lock(); list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) { - spin_lock_bh(&n_ptr->lock); + tipc_node_lock(n_ptr); l_ptr = n_ptr->links[bearer_id]; if (l_ptr) tipc_link_reset(l_ptr); - spin_unlock_bh(&n_ptr->lock); + tipc_node_unlock(n_ptr); } rcu_read_unlock(); } @@ -477,7 +487,7 @@ static void link_activate(struct tipc_link *l_ptr) { l_ptr->next_in_no = l_ptr->stats.recv_info = 1; tipc_node_link_up(l_ptr->owner, l_ptr); - tipc_bearer_add_dest(l_ptr->b_ptr, l_ptr->addr); + tipc_bearer_add_dest(l_ptr->bearer_id, l_ptr->addr); } /** @@ -777,7 +787,7 @@ int __tipc_link_xmit(struct tipc_link *l_ptr, struct sk_buff *buf) if (likely(!link_congested(l_ptr))) { link_add_to_outqueue(l_ptr, buf, msg); - tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); + tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr); l_ptr->unacked_window = 0; return dsz; } @@ -825,7 +835,6 @@ int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector) struct tipc_node *n_ptr; int res = -ELINKCONG; - read_lock_bh(&tipc_net_lock); n_ptr = tipc_node_find(dest); if (n_ptr) { tipc_node_lock(n_ptr); @@ -838,7 +847,6 @@ int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector) } else { kfree_skb(buf); } - read_unlock_bh(&tipc_net_lock); return res; } @@ -902,7 +910,6 @@ void tipc_link_names_xmit(struct list_head *message_list, u32 dest) if (list_empty(message_list)) return; - read_lock_bh(&tipc_net_lock); n_ptr = tipc_node_find(dest); if (n_ptr) { tipc_node_lock(n_ptr); @@ -917,7 +924,6 @@ void tipc_link_names_xmit(struct list_head *message_list, u32 dest) } tipc_node_unlock(n_ptr); } - read_unlock_bh(&tipc_net_lock); /* discard the messages if they couldn't be sent */ list_for_each_safe(buf, temp_buf, ((struct sk_buff *)message_list)) { @@ -941,7 +947,7 @@ static int tipc_link_xmit_fast(struct tipc_link *l_ptr, struct sk_buff *buf, if (likely(!link_congested(l_ptr))) { if (likely(msg_size(msg) <= l_ptr->max_pkt)) { link_add_to_outqueue(l_ptr, buf, msg); - tipc_bearer_send(l_ptr->b_ptr, buf, + tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr); l_ptr->unacked_window = 0; return res; @@ -979,7 +985,6 @@ int tipc_link_iovec_xmit_fast(struct tipc_port *sender, if (unlikely(res < 0)) return res; - read_lock_bh(&tipc_net_lock); node = tipc_node_find(destaddr); if (likely(node)) { tipc_node_lock(node); @@ -990,7 +995,6 @@ int tipc_link_iovec_xmit_fast(struct tipc_port *sender, &sender->max_pkt); exit: tipc_node_unlock(node); - read_unlock_bh(&tipc_net_lock); return res; } @@ -1007,7 +1011,6 @@ int tipc_link_iovec_xmit_fast(struct tipc_port *sender, */ sender->max_pkt = l_ptr->max_pkt; tipc_node_unlock(node); - read_unlock_bh(&tipc_net_lock); if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt) @@ -1018,7 +1021,6 @@ int tipc_link_iovec_xmit_fast(struct tipc_port *sender, } tipc_node_unlock(node); } - read_unlock_bh(&tipc_net_lock); /* Couldn't find a link to the destination node */ kfree_skb(buf); @@ -1204,7 +1206,7 @@ static u32 tipc_link_push_packet(struct tipc_link *l_ptr) if (r_q_size && buf) { msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1)); msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in); - tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); + tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr); l_ptr->retransm_queue_head = mod(++r_q_head); l_ptr->retransm_queue_size = --r_q_size; l_ptr->stats.retransmitted++; @@ -1216,7 +1218,7 @@ static u32 tipc_link_push_packet(struct tipc_link *l_ptr) if (buf) { msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1)); msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in); - tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); + tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr); l_ptr->unacked_window = 0; kfree_skb(buf); l_ptr->proto_msg_queue = NULL; @@ -1233,7 +1235,8 @@ static u32 tipc_link_push_packet(struct tipc_link *l_ptr) if (mod(next - first) < l_ptr->queue_limit[0]) { msg_set_ack(msg, mod(l_ptr->next_in_no - 1)); msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); - tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); + tipc_bearer_send(l_ptr->bearer_id, buf, + &l_ptr->media_addr); if (msg_user(msg) == MSG_BUNDLER) msg_set_type(msg, CLOSED_MSG); l_ptr->next_out = buf->next; @@ -1256,33 +1259,24 @@ void tipc_link_push_queue(struct tipc_link *l_ptr) } while (!res); } -static void link_reset_all(unsigned long addr) +void tipc_link_reset_all(struct tipc_node *node) { - struct tipc_node *n_ptr; char addr_string[16]; u32 i; - read_lock_bh(&tipc_net_lock); - n_ptr = tipc_node_find((u32)addr); - if (!n_ptr) { - read_unlock_bh(&tipc_net_lock); - return; /* node no longer exists */ - } - - tipc_node_lock(n_ptr); + tipc_node_lock(node); pr_warn("Resetting all links to %s\n", - tipc_addr_string_fill(addr_string, n_ptr->addr)); + tipc_addr_string_fill(addr_string, node->addr)); for (i = 0; i < MAX_BEARERS; i++) { - if (n_ptr->links[i]) { - link_print(n_ptr->links[i], "Resetting link\n"); - tipc_link_reset(n_ptr->links[i]); + if (node->links[i]) { + link_print(node->links[i], "Resetting link\n"); + tipc_link_reset(node->links[i]); } } - tipc_node_unlock(n_ptr); - read_unlock_bh(&tipc_net_lock); + tipc_node_unlock(node); } static void link_retransmit_failure(struct tipc_link *l_ptr, @@ -1319,10 +1313,9 @@ static void link_retransmit_failure(struct tipc_link *l_ptr, n_ptr->bclink.oos_state, n_ptr->bclink.last_sent); - tipc_k_signal((Handler)link_reset_all, (unsigned long)n_ptr->addr); - tipc_node_unlock(n_ptr); + tipc_bclink_set_flags(TIPC_BCLINK_RESET); l_ptr->stale_count = 0; } } @@ -1352,7 +1345,7 @@ void tipc_link_retransmit(struct tipc_link *l_ptr, struct sk_buff *buf, msg = buf_msg(buf); msg_set_ack(msg, mod(l_ptr->next_in_no - 1)); msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); - tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); + tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr); buf = buf->next; retransmits--; l_ptr->stats.retransmitted++; @@ -1440,14 +1433,13 @@ static int link_recv_buf_validate(struct sk_buff *buf) /** * tipc_rcv - process TIPC packets/messages arriving from off-node * @head: pointer to message buffer chain - * @tb_ptr: pointer to bearer message arrived on + * @b_ptr: pointer to bearer message arrived on * * Invoked with no locks held. Bearer pointer must point to a valid bearer * structure (i.e. cannot be NULL), but bearer can be inactive. */ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) { - read_lock_bh(&tipc_net_lock); while (head) { struct tipc_node *n_ptr; struct tipc_link *l_ptr; @@ -1497,14 +1489,14 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) goto unlock_discard; /* Verify that communication with node is currently allowed */ - if ((n_ptr->block_setup & WAIT_PEER_DOWN) && - msg_user(msg) == LINK_PROTOCOL && - (msg_type(msg) == RESET_MSG || - msg_type(msg) == ACTIVATE_MSG) && - !msg_redundant_link(msg)) - n_ptr->block_setup &= ~WAIT_PEER_DOWN; - - if (n_ptr->block_setup) + if ((n_ptr->flags & TIPC_NODE_DOWN) && + msg_user(msg) == LINK_PROTOCOL && + (msg_type(msg) == RESET_MSG || + msg_type(msg) == ACTIVATE_MSG) && + !msg_redundant_link(msg)) + n_ptr->flags &= ~TIPC_NODE_DOWN; + + if (tipc_node_blocked(n_ptr)) goto unlock_discard; /* Validate message sequence number info */ @@ -1635,7 +1627,6 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) discard: kfree_skb(buf); } - read_unlock_bh(&tipc_net_lock); } /** @@ -1747,12 +1738,12 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg, return; /* Abort non-RESET send if communication with node is prohibited */ - if ((l_ptr->owner->block_setup) && (msg_typ != RESET_MSG)) + if ((tipc_node_blocked(l_ptr->owner)) && (msg_typ != RESET_MSG)) return; /* Create protocol message with "out-of-sequence" sequence number */ msg_set_type(msg, msg_typ); - msg_set_net_plane(msg, l_ptr->b_ptr->net_plane); + msg_set_net_plane(msg, l_ptr->net_plane); msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); msg_set_last_bcast(msg, tipc_bclink_get_last_sent()); @@ -1818,7 +1809,7 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg, skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); buf->priority = TC_PRIO_CONTROL; - tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); + tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr); l_ptr->unacked_window = 0; kfree_skb(buf); } @@ -1843,9 +1834,9 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf) /* record unnumbered packet arrival (force mismatch on next timeout) */ l_ptr->checkpoint--; - if (l_ptr->b_ptr->net_plane != msg_net_plane(msg)) + if (l_ptr->net_plane != msg_net_plane(msg)) if (tipc_own_addr > msg_prevnode(msg)) - l_ptr->b_ptr->net_plane = msg_net_plane(msg); + l_ptr->net_plane = msg_net_plane(msg); switch (msg_type(msg)) { @@ -1862,7 +1853,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf) * peer has lost contact -- don't allow peer's links * to reactivate before we recognize loss & clean up */ - l_ptr->owner->block_setup = WAIT_NODE_DOWN; + l_ptr->owner->flags = TIPC_NODE_RESET; } link_state_event(l_ptr, RESET_MSG); @@ -2397,8 +2388,6 @@ void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window) /* tipc_link_find_owner - locate owner node of link by link's name * @name: pointer to link name string * @bearer_id: pointer to index in 'node->links' array where the link was found. - * Caller must hold 'tipc_net_lock' to ensure node and bearer are not deleted; - * this also prevents link deletion. * * Returns pointer to node owning the link, or 0 if no matching link is found. */ @@ -2460,7 +2449,7 @@ static int link_value_is_valid(u16 cmd, u32 new_value) * @new_value: new value of link, bearer, or media setting * @cmd: which link, bearer, or media attribute to set (TIPC_CMD_SET_LINK_*) * - * Caller must hold 'tipc_net_lock' to ensure link/bearer/media is not deleted. + * Caller must hold RTNL lock to ensure link/bearer/media is not deleted. * * Returns 0 if value updated and negative value on error. */ @@ -2566,9 +2555,7 @@ struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space " (cannot change setting on broadcast link)"); } - read_lock_bh(&tipc_net_lock); res = link_cmd_set_value(args->name, new_value, cmd); - read_unlock_bh(&tipc_net_lock); if (res) return tipc_cfg_reply_error_string("cannot change link setting"); @@ -2602,22 +2589,18 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_ return tipc_cfg_reply_error_string("link not found"); return tipc_cfg_reply_none(); } - read_lock_bh(&tipc_net_lock); node = tipc_link_find_owner(link_name, &bearer_id); - if (!node) { - read_unlock_bh(&tipc_net_lock); + if (!node) return tipc_cfg_reply_error_string("link not found"); - } + tipc_node_lock(node); l_ptr = node->links[bearer_id]; if (!l_ptr) { tipc_node_unlock(node); - read_unlock_bh(&tipc_net_lock); return tipc_cfg_reply_error_string("link not found"); } link_reset_statistics(l_ptr); tipc_node_unlock(node); - read_unlock_bh(&tipc_net_lock); return tipc_cfg_reply_none(); } @@ -2650,18 +2633,15 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size) if (!strcmp(name, tipc_bclink_name)) return tipc_bclink_stats(buf, buf_size); - read_lock_bh(&tipc_net_lock); node = tipc_link_find_owner(name, &bearer_id); - if (!node) { - read_unlock_bh(&tipc_net_lock); + if (!node) return 0; - } + tipc_node_lock(node); l = node->links[bearer_id]; if (!l) { tipc_node_unlock(node); - read_unlock_bh(&tipc_net_lock); return 0; } @@ -2727,7 +2707,6 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size) (s->accu_queue_sz / s->queue_sz_counts) : 0); tipc_node_unlock(node); - read_unlock_bh(&tipc_net_lock); return ret; } @@ -2778,7 +2757,6 @@ u32 tipc_link_get_max_pkt(u32 dest, u32 selector) if (dest == tipc_own_addr) return MAX_MSG_SIZE; - read_lock_bh(&tipc_net_lock); n_ptr = tipc_node_find(dest); if (n_ptr) { tipc_node_lock(n_ptr); @@ -2787,13 +2765,18 @@ u32 tipc_link_get_max_pkt(u32 dest, u32 selector) res = l_ptr->max_pkt; tipc_node_unlock(n_ptr); } - read_unlock_bh(&tipc_net_lock); return res; } static void link_print(struct tipc_link *l_ptr, const char *str) { - pr_info("%s Link %x<%s>:", str, l_ptr->addr, l_ptr->b_ptr->name); + struct tipc_bearer *b_ptr; + + rcu_read_lock(); + b_ptr = rcu_dereference_rtnl(bearer_list[l_ptr->bearer_id]); + if (b_ptr) + pr_info("%s Link %x<%s>:", str, l_ptr->addr, b_ptr->name); + rcu_read_unlock(); if (link_working_unknown(l_ptr)) pr_cont(":WU\n"); diff --git a/net/tipc/link.h b/net/tipc/link.h index 8c0b49b5b2ee6b..7ba73fa6b81ea1 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -107,7 +107,7 @@ struct tipc_stats { * @checkpoint: reference point for triggering link continuity checking * @peer_session: link session # being used by peer end of link * @peer_bearer_id: bearer id used by link's peer endpoint - * @b_ptr: pointer to bearer used by link + * @bearer_id: local bearer id used by link * @tolerance: minimum link continuity loss needed to reset link [in ms] * @continuity_interval: link continuity testing interval [in ms] * @abort_limit: # of unacknowledged continuity probes needed to reset link @@ -116,6 +116,7 @@ struct tipc_stats { * @proto_msg: template for control messages generated by link * @pmsg: convenience pointer to "proto_msg" field * @priority: current link priority + * @net_plane: current link network plane ('A' through 'H') * @queue_limit: outbound message queue congestion thresholds (indexed by user) * @exp_msg_count: # of tunnelled messages expected during link changeover * @reset_checkpoint: seq # of last acknowledged message at time of link reset @@ -155,7 +156,7 @@ struct tipc_link { u32 checkpoint; u32 peer_session; u32 peer_bearer_id; - struct tipc_bearer *b_ptr; + u32 bearer_id; u32 tolerance; u32 continuity_interval; u32 abort_limit; @@ -167,6 +168,7 @@ struct tipc_link { } proto_msg; struct tipc_msg *pmsg; u32 priority; + char net_plane; u32 queue_limit[15]; /* queue_limit[0]==window limit */ /* Changeover */ @@ -228,6 +230,7 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space); struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space); +void tipc_link_reset_all(struct tipc_node *node); void tipc_link_reset(struct tipc_link *l_ptr); void tipc_link_reset_list(unsigned int bearer_id); int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector); diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index aff8041dc1573e..8ce730984aa1f0 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -38,34 +38,6 @@ #include "link.h" #include "name_distr.h" -#define ITEM_SIZE sizeof(struct distr_item) - -/** - * struct distr_item - publication info distributed to other nodes - * @type: name sequence type - * @lower: name sequence lower bound - * @upper: name sequence upper bound - * @ref: publishing port reference - * @key: publication key - * - * ===> All fields are stored in network byte order. <=== - * - * First 3 fields identify (name or) name sequence being published. - * Reference field uniquely identifies port that published name sequence. - * Key field uniquely identifies publication, in the event a port has - * multiple publications of the same name sequence. - * - * Note: There is no field that identifies the publishing node because it is - * the same for all items contained within a publication message. - */ -struct distr_item { - __be32 type; - __be32 lower; - __be32 upper; - __be32 ref; - __be32 key; -}; - /** * struct publ_list - list of publications made by this node * @list: circular list of publications @@ -127,7 +99,7 @@ static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest) return buf; } -static void named_cluster_distribute(struct sk_buff *buf) +void named_cluster_distribute(struct sk_buff *buf) { struct sk_buff *buf_copy; struct tipc_node *n_ptr; @@ -135,18 +107,18 @@ static void named_cluster_distribute(struct sk_buff *buf) rcu_read_lock(); list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) { - spin_lock_bh(&n_ptr->lock); + tipc_node_lock(n_ptr); l_ptr = n_ptr->active_links[n_ptr->addr & 1]; if (l_ptr) { buf_copy = skb_copy(buf, GFP_ATOMIC); if (!buf_copy) { - spin_unlock_bh(&n_ptr->lock); + tipc_node_unlock(n_ptr); break; } msg_set_destnode(buf_msg(buf_copy), n_ptr->addr); __tipc_link_xmit(l_ptr, buf_copy); } - spin_unlock_bh(&n_ptr->lock); + tipc_node_unlock(n_ptr); } rcu_read_unlock(); @@ -156,7 +128,7 @@ static void named_cluster_distribute(struct sk_buff *buf) /** * tipc_named_publish - tell other nodes about a new publication by this node */ -void tipc_named_publish(struct publication *publ) +struct sk_buff *tipc_named_publish(struct publication *publ) { struct sk_buff *buf; struct distr_item *item; @@ -165,23 +137,23 @@ void tipc_named_publish(struct publication *publ) publ_lists[publ->scope]->size++; if (publ->scope == TIPC_NODE_SCOPE) - return; + return NULL; buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0); if (!buf) { pr_warn("Publication distribution failure\n"); - return; + return NULL; } item = (struct distr_item *)msg_data(buf_msg(buf)); publ_to_item(item, publ); - named_cluster_distribute(buf); + return buf; } /** * tipc_named_withdraw - tell other nodes about a withdrawn publication by this node */ -void tipc_named_withdraw(struct publication *publ) +struct sk_buff *tipc_named_withdraw(struct publication *publ) { struct sk_buff *buf; struct distr_item *item; @@ -190,17 +162,17 @@ void tipc_named_withdraw(struct publication *publ) publ_lists[publ->scope]->size--; if (publ->scope == TIPC_NODE_SCOPE) - return; + return NULL; buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0); if (!buf) { pr_warn("Withdrawal distribution failure\n"); - return; + return NULL; } item = (struct distr_item *)msg_data(buf_msg(buf)); publ_to_item(item, publ); - named_cluster_distribute(buf); + return buf; } /* @@ -239,31 +211,9 @@ static void named_distribute(struct list_head *message_list, u32 node, /** * tipc_named_node_up - tell specified node about all publications by this node */ -void tipc_named_node_up(unsigned long nodearg) +void tipc_named_node_up(u32 max_item_buf, u32 node) { - struct tipc_node *n_ptr; - struct tipc_link *l_ptr; - struct list_head message_list; - u32 node = (u32)nodearg; - u32 max_item_buf = 0; - - /* compute maximum amount of publication data to send per message */ - read_lock_bh(&tipc_net_lock); - n_ptr = tipc_node_find(node); - if (n_ptr) { - tipc_node_lock(n_ptr); - l_ptr = n_ptr->active_links[0]; - if (l_ptr) - max_item_buf = ((l_ptr->max_pkt - INT_H_SIZE) / - ITEM_SIZE) * ITEM_SIZE; - tipc_node_unlock(n_ptr); - } - read_unlock_bh(&tipc_net_lock); - if (!max_item_buf) - return; - - /* create list of publication messages, then send them as a unit */ - INIT_LIST_HEAD(&message_list); + LIST_HEAD(message_list); read_lock_bh(&tipc_nametbl_lock); named_distribute(&message_list, node, &publ_cluster, max_item_buf); diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h index 9b312ccfd43e7d..b2eed4ec1526a3 100644 --- a/net/tipc/name_distr.h +++ b/net/tipc/name_distr.h @@ -39,9 +39,38 @@ #include "name_table.h" -void tipc_named_publish(struct publication *publ); -void tipc_named_withdraw(struct publication *publ); -void tipc_named_node_up(unsigned long node); +#define ITEM_SIZE sizeof(struct distr_item) + +/** + * struct distr_item - publication info distributed to other nodes + * @type: name sequence type + * @lower: name sequence lower bound + * @upper: name sequence upper bound + * @ref: publishing port reference + * @key: publication key + * + * ===> All fields are stored in network byte order. <=== + * + * First 3 fields identify (name or) name sequence being published. + * Reference field uniquely identifies port that published name sequence. + * Key field uniquely identifies publication, in the event a port has + * multiple publications of the same name sequence. + * + * Note: There is no field that identifies the publishing node because it is + * the same for all items contained within a publication message. + */ +struct distr_item { + __be32 type; + __be32 lower; + __be32 upper; + __be32 ref; + __be32 key; +}; + +struct sk_buff *tipc_named_publish(struct publication *publ); +struct sk_buff *tipc_named_withdraw(struct publication *publ); +void named_cluster_distribute(struct sk_buff *buf); +void tipc_named_node_up(u32 max_item_buf, u32 node); void tipc_named_rcv(struct sk_buff *buf); void tipc_named_reinit(void); diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 042e8e3cabc09f..9d7d37d95187c7 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -664,6 +664,7 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper, u32 scope, u32 port_ref, u32 key) { struct publication *publ; + struct sk_buff *buf = NULL; if (table.local_publ_count >= TIPC_MAX_PUBLICATIONS) { pr_warn("Publication failed, local publication limit reached (%u)\n", @@ -676,9 +677,12 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper, tipc_own_addr, port_ref, key); if (likely(publ)) { table.local_publ_count++; - tipc_named_publish(publ); + buf = tipc_named_publish(publ); } write_unlock_bh(&tipc_nametbl_lock); + + if (buf) + named_cluster_distribute(buf); return publ; } @@ -688,15 +692,19 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper, int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key) { struct publication *publ; + struct sk_buff *buf; write_lock_bh(&tipc_nametbl_lock); publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key); if (likely(publ)) { table.local_publ_count--; - tipc_named_withdraw(publ); + buf = tipc_named_withdraw(publ); write_unlock_bh(&tipc_nametbl_lock); list_del_init(&publ->pport_list); kfree(publ); + + if (buf) + named_cluster_distribute(buf); return 1; } write_unlock_bh(&tipc_nametbl_lock); @@ -961,6 +969,7 @@ static void tipc_purge_publications(struct name_seq *seq) list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) { tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node, publ->ref, publ->key); + kfree(publ); } } @@ -982,7 +991,6 @@ void tipc_nametbl_stop(void) hlist_for_each_entry_safe(seq, safe, seq_head, ns_list) { tipc_purge_publications(seq); } - continue; } kfree(table.types); table.types = NULL; diff --git a/net/tipc/net.c b/net/tipc/net.c index 4c564eb69e1ad9..f8fc95d58c0d91 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c @@ -45,39 +45,34 @@ /* * The TIPC locking policy is designed to ensure a very fine locking * granularity, permitting complete parallel access to individual - * port and node/link instances. The code consists of three major + * port and node/link instances. The code consists of four major * locking domains, each protected with their own disjunct set of locks. * - * 1: The routing hierarchy. - * Comprises the structures 'zone', 'cluster', 'node', 'link' - * and 'bearer'. The whole hierarchy is protected by a big - * read/write lock, tipc_net_lock, to enssure that nothing is added - * or removed while code is accessing any of these structures. - * This layer must not be called from the two others while they - * hold any of their own locks. - * Neither must it itself do any upcalls to the other two before - * it has released tipc_net_lock and other protective locks. + * 1: The bearer level. + * RTNL lock is used to serialize the process of configuring bearer + * on update side, and RCU lock is applied on read side to make + * bearer instance valid on both paths of message transmission and + * reception. * - * Within the tipc_net_lock domain there are two sub-domains;'node' and - * 'bearer', where local write operations are permitted, - * provided that those are protected by individual spin_locks - * per instance. Code holding tipc_net_lock(read) and a node spin_lock - * is permitted to poke around in both the node itself and its - * subordinate links. I.e, it can update link counters and queues, - * change link state, send protocol messages, and alter the - * "active_links" array in the node; but it can _not_ remove a link - * or a node from the overall structure. - * Correspondingly, individual bearers may change status within a - * tipc_net_lock(read), protected by an individual spin_lock ber bearer - * instance, but it needs tipc_net_lock(write) to remove/add any bearers. + * 2: The node and link level. + * All node instances are saved into two tipc_node_list and node_htable + * lists. The two lists are protected by node_list_lock on write side, + * and they are guarded with RCU lock on read side. Especially node + * instance is destroyed only when TIPC module is removed, and we can + * confirm that there has no any user who is accessing the node at the + * moment. Therefore, Except for iterating the two lists within RCU + * protection, it's no needed to hold RCU that we access node instance + * in other places. * + * In addition, all members in node structure including link instances + * are protected by node spin lock. * - * 2: The transport level of the protocol. - * This consists of the structures port, (and its user level - * representations, such as user_port and tipc_sock), reference and - * tipc_user (port.c, reg.c, socket.c). + * 3: The transport level of the protocol. + * This consists of the structures port, (and its user level + * representations, such as user_port and tipc_sock), reference and + * tipc_user (port.c, reg.c, socket.c). * - * This layer has four different locks: + * This layer has four different locks: * - The tipc_port spin_lock. This is protecting each port instance * from parallel data access and removal. Since we can not place * this lock in the port itself, it has been placed in the @@ -96,7 +91,7 @@ * There are two such lists; 'port_list', which is used for management, * and 'wait_list', which is used to queue ports during congestion. * - * 3: The name table (name_table.c, name_distr.c, subscription.c) + * 4: The name table (name_table.c, name_distr.c, subscription.c) * - There is one big read/write-lock (tipc_nametbl_lock) protecting the * overall name table structure. Nothing must be added/removed to * this structure without holding write access to it. @@ -108,8 +103,6 @@ * - A local spin_lock protecting the queue of subscriber events. */ -DEFINE_RWLOCK(tipc_net_lock); - static void net_route_named_msg(struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); @@ -171,22 +164,25 @@ void tipc_net_route_msg(struct sk_buff *buf) tipc_link_xmit(buf, dnode, msg_link_selector(msg)); } -void tipc_net_start(u32 addr) +int tipc_net_start(u32 addr) { char addr_string[16]; + int res; - write_lock_bh(&tipc_net_lock); tipc_own_addr = addr; tipc_named_reinit(); tipc_port_reinit(); - tipc_bclink_init(); - write_unlock_bh(&tipc_net_lock); + res = tipc_bclink_init(); + if (res) + return res; tipc_nametbl_publish(TIPC_CFG_SRV, tipc_own_addr, tipc_own_addr, TIPC_ZONE_SCOPE, 0, tipc_own_addr); + pr_info("Started in network mode\n"); pr_info("Own node address %s, network identity %u\n", tipc_addr_string_fill(addr_string, tipc_own_addr), tipc_net_id); + return 0; } void tipc_net_stop(void) @@ -195,11 +191,11 @@ void tipc_net_stop(void) return; tipc_nametbl_withdraw(TIPC_CFG_SRV, tipc_own_addr, 0, tipc_own_addr); - write_lock_bh(&tipc_net_lock); + rtnl_lock(); tipc_bearer_stop(); tipc_bclink_stop(); tipc_node_stop(); - write_unlock_bh(&tipc_net_lock); + rtnl_unlock(); pr_info("Left network mode\n"); } diff --git a/net/tipc/net.h b/net/tipc/net.h index 079daadb3f7286..c6c2b46f7c2830 100644 --- a/net/tipc/net.h +++ b/net/tipc/net.h @@ -37,11 +37,9 @@ #ifndef _TIPC_NET_H #define _TIPC_NET_H -extern rwlock_t tipc_net_lock; - void tipc_net_route_msg(struct sk_buff *buf); -void tipc_net_start(u32 addr); +int tipc_net_start(u32 addr); void tipc_net_stop(void); #endif diff --git a/net/tipc/node.c b/net/tipc/node.c index 1d3a4999a70ff9..74efebc1cb7a03 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -108,7 +108,7 @@ struct tipc_node *tipc_node_create(u32 addr) break; } list_add_tail_rcu(&n_ptr->list, &temp_node->list); - n_ptr->block_setup = WAIT_PEER_DOWN; + n_ptr->flags = TIPC_NODE_DOWN; n_ptr->signature = INVALID_NODE_SIG; tipc_num_nodes++; @@ -144,11 +144,13 @@ void tipc_node_stop(void) void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr) { struct tipc_link **active = &n_ptr->active_links[0]; + u32 addr = n_ptr->addr; n_ptr->working_links++; - + tipc_nametbl_publish(TIPC_LINK_STATE, addr, addr, TIPC_NODE_SCOPE, + l_ptr->bearer_id, addr); pr_info("Established link <%s> on network plane %c\n", - l_ptr->name, l_ptr->b_ptr->net_plane); + l_ptr->name, l_ptr->net_plane); if (!active[0]) { active[0] = active[1] = l_ptr; @@ -203,16 +205,18 @@ static void node_select_active_links(struct tipc_node *n_ptr) void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr) { struct tipc_link **active; + u32 addr = n_ptr->addr; n_ptr->working_links--; + tipc_nametbl_withdraw(TIPC_LINK_STATE, addr, l_ptr->bearer_id, addr); if (!tipc_link_is_active(l_ptr)) { pr_info("Lost standby link <%s> on network plane %c\n", - l_ptr->name, l_ptr->b_ptr->net_plane); + l_ptr->name, l_ptr->net_plane); return; } pr_info("Lost link <%s> on network plane %c\n", - l_ptr->name, l_ptr->b_ptr->net_plane); + l_ptr->name, l_ptr->net_plane); active = &n_ptr->active_links[0]; if (active[0] == l_ptr) @@ -239,7 +243,7 @@ int tipc_node_is_up(struct tipc_node *n_ptr) void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) { - n_ptr->links[l_ptr->b_ptr->identity] = l_ptr; + n_ptr->links[l_ptr->bearer_id] = l_ptr; spin_lock_bh(&node_list_lock); tipc_num_links++; spin_unlock_bh(&node_list_lock); @@ -263,26 +267,12 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) static void node_established_contact(struct tipc_node *n_ptr) { - tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr); + n_ptr->flags |= TIPC_NODE_UP; n_ptr->bclink.oos_state = 0; n_ptr->bclink.acked = tipc_bclink_get_last_sent(); tipc_bclink_add_node(n_ptr->addr); } -static void node_name_purge_complete(unsigned long node_addr) -{ - struct tipc_node *n_ptr; - - read_lock_bh(&tipc_net_lock); - n_ptr = tipc_node_find(node_addr); - if (n_ptr) { - tipc_node_lock(n_ptr); - n_ptr->block_setup &= ~WAIT_NAMES_GONE; - tipc_node_unlock(n_ptr); - } - read_unlock_bh(&tipc_net_lock); -} - static void node_lost_contact(struct tipc_node *n_ptr) { char addr_string[16]; @@ -318,12 +308,10 @@ static void node_lost_contact(struct tipc_node *n_ptr) tipc_link_reset_fragments(l_ptr); } - /* Notify subscribers */ - tipc_nodesub_notify(n_ptr); - - /* Prevent re-contact with node until cleanup is done */ - n_ptr->block_setup = WAIT_PEER_DOWN | WAIT_NAMES_GONE; - tipc_k_signal((Handler)node_name_purge_complete, n_ptr->addr); + /* Notify subscribers and prevent re-contact with node until + * cleanup is done. + */ + n_ptr->flags = TIPC_NODE_DOWN | TIPC_NODE_LOST; } struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) @@ -436,3 +424,63 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) rcu_read_unlock(); return buf; } + +/** + * tipc_node_get_linkname - get the name of a link + * + * @bearer_id: id of the bearer + * @node: peer node address + * @linkname: link name output buffer + * + * Returns 0 on success + */ +int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len) +{ + struct tipc_link *link; + struct tipc_node *node = tipc_node_find(addr); + + if ((bearer_id >= MAX_BEARERS) || !node) + return -EINVAL; + tipc_node_lock(node); + link = node->links[bearer_id]; + if (link) { + strncpy(linkname, link->name, len); + tipc_node_unlock(node); + return 0; + } + tipc_node_unlock(node); + return -EINVAL; +} + +void tipc_node_unlock(struct tipc_node *node) +{ + LIST_HEAD(nsub_list); + struct tipc_link *link; + int pkt_sz = 0; + u32 addr = 0; + + if (likely(!node->flags)) { + spin_unlock_bh(&node->lock); + return; + } + + if (node->flags & TIPC_NODE_LOST) { + list_replace_init(&node->nsub, &nsub_list); + node->flags &= ~TIPC_NODE_LOST; + } + if (node->flags & TIPC_NODE_UP) { + link = node->active_links[0]; + node->flags &= ~TIPC_NODE_UP; + if (link) { + pkt_sz = ((link->max_pkt - INT_H_SIZE) / ITEM_SIZE) * + ITEM_SIZE; + addr = node->addr; + } + } + spin_unlock_bh(&node->lock); + + if (!list_empty(&nsub_list)) + tipc_nodesub_notify(&nsub_list); + if (pkt_sz) + tipc_named_node_up(pkt_sz, addr); +} diff --git a/net/tipc/node.h b/net/tipc/node.h index 7cbb8cec1a932f..38f710fb75dc02 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -47,62 +47,78 @@ */ #define INVALID_NODE_SIG 0x10000 -/* Flags used to block (re)establishment of contact with a neighboring node */ -#define WAIT_PEER_DOWN 0x0001 /* wait to see that peer's links are down */ -#define WAIT_NAMES_GONE 0x0002 /* wait for peer's publications to be purged */ -#define WAIT_NODE_DOWN 0x0004 /* wait until peer node is declared down */ +/* Flags used to block (re)establishment of contact with a neighboring node + * TIPC_NODE_DOWN: indicate node is down and it's used to block the node's + * links until RESET or ACTIVE message arrives + * TIPC_NODE_RESET: indicate node is reset + * TIPC_NODE_LOST: indicate node is lost and it's used to notify subscriptions + * when node lock is released + * TIPC_NODE_UP: indicate node is up and it's used to deliver local name table + * when node lock is released + */ +enum { + TIPC_NODE_DOWN = (1 << 1), + TIPC_NODE_RESET = (1 << 2), + TIPC_NODE_LOST = (1 << 3), + TIPC_NODE_UP = (1 << 4) +}; + +/** + * struct tipc_node_bclink - TIPC node bclink structure + * @acked: sequence # of last outbound b'cast message acknowledged by node + * @last_in: sequence # of last in-sequence b'cast message received from node + * @last_sent: sequence # of last b'cast message sent by node + * @oos_state: state tracker for handling OOS b'cast messages + * @deferred_size: number of OOS b'cast messages in deferred queue + * @deferred_head: oldest OOS b'cast message received from node + * @deferred_tail: newest OOS b'cast message received from node + * @reasm_head: broadcast reassembly queue head from node + * @reasm_tail: last broadcast fragment received from node + * @recv_permitted: true if node is allowed to receive b'cast messages + */ +struct tipc_node_bclink { + u32 acked; + u32 last_in; + u32 last_sent; + u32 oos_state; + u32 deferred_size; + struct sk_buff *deferred_head; + struct sk_buff *deferred_tail; + struct sk_buff *reasm_head; + struct sk_buff *reasm_tail; + bool recv_permitted; +}; /** * struct tipc_node - TIPC node structure * @addr: network address of node * @lock: spinlock governing access to structure * @hash: links to adjacent nodes in unsorted hash chain - * @list: links to adjacent nodes in sorted list of cluster's nodes - * @nsub: list of "node down" subscriptions monitoring node * @active_links: pointers to active links to node * @links: pointers to all links to node + * @flags: bit mask of conditions preventing link establishment to node + * @bclink: broadcast-related info + * @list: links to adjacent nodes in sorted list of cluster's nodes * @working_links: number of working links to node (both active and standby) - * @block_setup: bit mask of conditions preventing link establishment to node * @link_cnt: number of links to node * @signature: node instance identifier - * @bclink: broadcast-related info + * @nsub: list of "node down" subscriptions monitoring node * @rcu: rcu struct for tipc_node - * @acked: sequence # of last outbound b'cast message acknowledged by node - * @last_in: sequence # of last in-sequence b'cast message received from node - * @last_sent: sequence # of last b'cast message sent by node - * @oos_state: state tracker for handling OOS b'cast messages - * @deferred_size: number of OOS b'cast messages in deferred queue - * @deferred_head: oldest OOS b'cast message received from node - * @deferred_tail: newest OOS b'cast message received from node - * @reasm_head: broadcast reassembly queue head from node - * @reasm_tail: last broadcast fragment received from node - * @recv_permitted: true if node is allowed to receive b'cast messages */ struct tipc_node { u32 addr; spinlock_t lock; struct hlist_node hash; - struct list_head list; - struct list_head nsub; struct tipc_link *active_links[2]; struct tipc_link *links[MAX_BEARERS]; + unsigned int flags; + struct tipc_node_bclink bclink; + struct list_head list; int link_cnt; int working_links; - int block_setup; u32 signature; + struct list_head nsub; struct rcu_head rcu; - struct { - u32 acked; - u32 last_in; - u32 last_sent; - u32 oos_state; - u32 deferred_size; - struct sk_buff *deferred_head; - struct sk_buff *deferred_tail; - struct sk_buff *reasm_head; - struct sk_buff *reasm_tail; - bool recv_permitted; - } bclink; }; extern struct list_head tipc_node_list; @@ -118,15 +134,18 @@ int tipc_node_active_links(struct tipc_node *n_ptr); int tipc_node_is_up(struct tipc_node *n_ptr); struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space); struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space); +int tipc_node_get_linkname(u32 bearer_id, u32 node, char *linkname, size_t len); +void tipc_node_unlock(struct tipc_node *node); -static inline void tipc_node_lock(struct tipc_node *n_ptr) +static inline void tipc_node_lock(struct tipc_node *node) { - spin_lock_bh(&n_ptr->lock); + spin_lock_bh(&node->lock); } -static inline void tipc_node_unlock(struct tipc_node *n_ptr) +static inline bool tipc_node_blocked(struct tipc_node *node) { - spin_unlock_bh(&n_ptr->lock); + return (node->flags & (TIPC_NODE_DOWN | TIPC_NODE_LOST | + TIPC_NODE_RESET)); } #endif diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c index 8a7384c04add4b..7c59ab1d6ecb3d 100644 --- a/net/tipc/node_subscr.c +++ b/net/tipc/node_subscr.c @@ -81,14 +81,13 @@ void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub) * * Note: node is locked by caller */ -void tipc_nodesub_notify(struct tipc_node *node) +void tipc_nodesub_notify(struct list_head *nsub_list) { - struct tipc_node_subscr *ns; + struct tipc_node_subscr *ns, *safe; - list_for_each_entry(ns, &node->nsub, nodesub_list) { + list_for_each_entry_safe(ns, safe, nsub_list, nodesub_list) { if (ns->handle_node_down) { - tipc_k_signal((Handler)ns->handle_node_down, - (unsigned long)ns->usr_handle); + ns->handle_node_down(ns->usr_handle); ns->handle_node_down = NULL; } } diff --git a/net/tipc/node_subscr.h b/net/tipc/node_subscr.h index c95d20727ded3e..d91b8cc81e3d78 100644 --- a/net/tipc/node_subscr.h +++ b/net/tipc/node_subscr.h @@ -58,6 +58,6 @@ struct tipc_node_subscr { void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr, void *usr_handle, net_ev_handler handle_down); void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub); -void tipc_nodesub_notify(struct tipc_node *node); +void tipc_nodesub_notify(struct list_head *nsub_list); #endif diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 3c0256962f7daf..3f9912f87d0d17 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -36,6 +36,7 @@ #include "core.h" #include "port.h" +#include "node.h" #include @@ -1905,6 +1906,28 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt, return put_user(sizeof(value), ol); } +int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) +{ + struct tipc_sioc_ln_req lnr; + void __user *argp = (void __user *)arg; + + switch (cmd) { + case SIOCGETLINKNAME: + if (copy_from_user(&lnr, argp, sizeof(lnr))) + return -EFAULT; + if (!tipc_node_get_linkname(lnr.bearer_id, lnr.peer, + lnr.linkname, TIPC_MAX_LINK_NAME)) { + if (copy_to_user(argp, &lnr, sizeof(lnr))) + return -EFAULT; + return 0; + } + return -EADDRNOTAVAIL; + break; + default: + return -ENOIOCTLCMD; + } +} + /* Protocol switches for the various types of TIPC sockets */ static const struct proto_ops msg_ops = { @@ -1917,7 +1940,7 @@ static const struct proto_ops msg_ops = { .accept = sock_no_accept, .getname = tipc_getname, .poll = tipc_poll, - .ioctl = sock_no_ioctl, + .ioctl = tipc_ioctl, .listen = sock_no_listen, .shutdown = tipc_shutdown, .setsockopt = tipc_setsockopt, @@ -1938,7 +1961,7 @@ static const struct proto_ops packet_ops = { .accept = tipc_accept, .getname = tipc_getname, .poll = tipc_poll, - .ioctl = sock_no_ioctl, + .ioctl = tipc_ioctl, .listen = tipc_listen, .shutdown = tipc_shutdown, .setsockopt = tipc_setsockopt, @@ -1959,7 +1982,7 @@ static const struct proto_ops stream_ops = { .accept = tipc_accept, .getname = tipc_getname, .poll = tipc_poll, - .ioctl = sock_no_ioctl, + .ioctl = tipc_ioctl, .listen = tipc_listen, .shutdown = tipc_shutdown, .setsockopt = tipc_setsockopt, diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index bb7e8ba821f440..749f80c21e220b 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1207,7 +1207,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, sk->sk_state = TCP_ESTABLISHED; sock_hold(newsk); - smp_mb__after_atomic_inc(); /* sock_hold() does an atomic_inc() */ + smp_mb__after_atomic(); /* sock_hold() does an atomic_inc() */ unix_peer(sk) = newsk; unix_state_unlock(sk); diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 16d08b39921071..405f3c4cf70ca3 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -95,6 +95,43 @@ config CFG80211_CERTIFICATION_ONUS you are a wireless researcher and are working in a controlled and approved environment by your local regulatory agency. +config CFG80211_REG_CELLULAR_HINTS + bool "cfg80211 regulatory support for cellular base station hints" + depends on CFG80211_CERTIFICATION_ONUS + ---help--- + This option enables support for parsing regulatory hints + from cellular base stations. If enabled and at least one driver + claims support for parsing cellular base station hints the + regulatory core will allow and parse these regulatory hints. + The regulatory core will only apply these regulatory hints on + drivers that support this feature. You should only enable this + feature if you have tested and validated this feature on your + systems. + +config CFG80211_REG_RELAX_NO_IR + bool "cfg80211 support for NO_IR relaxation" + depends on CFG80211_CERTIFICATION_ONUS + ---help--- + This option enables support for relaxation of the NO_IR flag for + situations that certain regulatory bodies have provided clarifications + on how relaxation can occur. This feature has an inherent dependency on + userspace features which must have been properly tested and as such is + not enabled by default. + + A relaxation feature example is allowing the operation of a P2P group + owner (GO) on channels marked with NO_IR if there is an additional BSS + interface which associated to an AP which userspace assumes or confirms + to be an authorized master, i.e., with radar detection support and DFS + capabilities. However, note that in order to not create daisy chain + scenarios, this relaxation is not allowed in cases that the BSS client + is associated to P2P GO and in addition the P2P GO instantiated on + a channel due to this relaxation should not allow connection from + non P2P clients. + + The regulatory core will apply these relaxations only for drivers that + support this feature by declaring the appropriate channel flags and + capabilities in their registration flow. + config CFG80211_DEFAULT_PS bool "enable powersave by default" depends on CFG80211 diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 9c9501a35fb5c6..84d686e2dbd04a 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -326,28 +326,57 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, int cfg80211_chandef_dfs_required(struct wiphy *wiphy, - const struct cfg80211_chan_def *chandef) + const struct cfg80211_chan_def *chandef, + enum nl80211_iftype iftype) { int width; - int r; + int ret; if (WARN_ON(!cfg80211_chandef_valid(chandef))) return -EINVAL; - width = cfg80211_chandef_get_width(chandef); - if (width < 0) - return -EINVAL; + switch (iftype) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_MESH_POINT: + width = cfg80211_chandef_get_width(chandef); + if (width < 0) + return -EINVAL; - r = cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq1, - width); - if (r) - return r; + ret = cfg80211_get_chans_dfs_required(wiphy, + chandef->center_freq1, + width); + if (ret < 0) + return ret; + else if (ret > 0) + return BIT(chandef->width); - if (!chandef->center_freq2) - return 0; + if (!chandef->center_freq2) + return 0; + + ret = cfg80211_get_chans_dfs_required(wiphy, + chandef->center_freq2, + width); + if (ret < 0) + return ret; + else if (ret > 0) + return BIT(chandef->width); - return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2, - width); + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_P2P_DEVICE: + case NL80211_IFTYPE_UNSPECIFIED: + break; + case NUM_NL80211_IFTYPES: + WARN_ON(1); + } + + return 0; } EXPORT_SYMBOL(cfg80211_chandef_dfs_required); @@ -587,12 +616,14 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, width = 5; break; case NL80211_CHAN_WIDTH_10: + prohibited_flags |= IEEE80211_CHAN_NO_10MHZ; width = 10; break; case NL80211_CHAN_WIDTH_20: if (!ht_cap->ht_supported) return false; case NL80211_CHAN_WIDTH_20_NOHT: + prohibited_flags |= IEEE80211_CHAN_NO_20MHZ; width = 20; break; case NL80211_CHAN_WIDTH_40: @@ -661,17 +692,112 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, } EXPORT_SYMBOL(cfg80211_chandef_usable); +/* + * For GO only, check if the channel can be used under permissive conditions + * mandated by the some regulatory bodies, i.e., the channel is marked with + * IEEE80211_CHAN_GO_CONCURRENT and there is an additional station interface + * associated to an AP on the same channel or on the same UNII band + * (assuming that the AP is an authorized master). + * In addition allow the GO to operate on a channel on which indoor operation is + * allowed, iff we are currently operating in an indoor environment. + */ +static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev, + struct ieee80211_channel *chan) +{ + struct wireless_dev *wdev_iter; + struct wiphy *wiphy = wiphy_idx_to_wiphy(rdev->wiphy_idx); + + ASSERT_RTNL(); + + if (!config_enabled(CONFIG_CFG80211_REG_RELAX_NO_IR) || + !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR)) + return false; + + if (regulatory_indoor_allowed() && + (chan->flags & IEEE80211_CHAN_INDOOR_ONLY)) + return true; + + if (!(chan->flags & IEEE80211_CHAN_GO_CONCURRENT)) + return false; + + /* + * Generally, it is possible to rely on another device/driver to allow + * the GO concurrent relaxation, however, since the device can further + * enforce the relaxation (by doing a similar verifications as this), + * and thus fail the GO instantiation, consider only the interfaces of + * the current registered device. + */ + list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { + struct ieee80211_channel *other_chan = NULL; + int r1, r2; + + if (wdev_iter->iftype != NL80211_IFTYPE_STATION || + !netif_running(wdev_iter->netdev)) + continue; + + wdev_lock(wdev_iter); + if (wdev_iter->current_bss) + other_chan = wdev_iter->current_bss->pub.channel; + wdev_unlock(wdev_iter); + + if (!other_chan) + continue; + + if (chan == other_chan) + return true; + + if (chan->band != IEEE80211_BAND_5GHZ) + continue; + + r1 = cfg80211_get_unii(chan->center_freq); + r2 = cfg80211_get_unii(other_chan->center_freq); + + if (r1 != -EINVAL && r1 == r2) { + /* + * At some locations channels 149-165 are considered a + * bundle, but at other locations, e.g., Indonesia, + * channels 149-161 are considered a bundle while + * channel 165 is left out and considered to be in a + * different bundle. Thus, in case that there is a + * station interface connected to an AP on channel 165, + * it is assumed that channels 149-161 are allowed for + * GO operations. However, having a station interface + * connected to an AP on channels 149-161, does not + * allow GO operation on channel 165. + */ + if (chan->center_freq == 5825 && + other_chan->center_freq != 5825) + continue; + return true; + } + } + + return false; +} + bool cfg80211_reg_can_beacon(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef) + struct cfg80211_chan_def *chandef, + enum nl80211_iftype iftype) { + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); bool res; u32 prohibited_flags = IEEE80211_CHAN_DISABLED | - IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR; - trace_cfg80211_reg_can_beacon(wiphy, chandef); + trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype); - if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 && + /* + * Under certain conditions suggested by the some regulatory bodies + * a GO can operate on channels marked with IEEE80211_NO_IR + * so set this flag only if such relaxations are not enabled and + * the conditions are not met. + */ + if (iftype != NL80211_IFTYPE_P2P_GO || + !cfg80211_go_permissive_chan(rdev, chandef->chan)) + prohibited_flags |= IEEE80211_CHAN_NO_IR; + + if (cfg80211_chandef_dfs_required(wiphy, chandef, + NL80211_IFTYPE_UNSPECIFIED) > 0 && cfg80211_chandef_dfs_available(wiphy, chandef)) { /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */ prohibited_flags = IEEE80211_CHAN_DISABLED; @@ -701,6 +827,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, enum cfg80211_chan_mode *chanmode, u8 *radar_detect) { + int ret; + *chan = NULL; *chanmode = CHAN_MODE_UNDEFINED; @@ -743,8 +871,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, *chan = wdev->chandef.chan; *chanmode = CHAN_MODE_SHARED; - if (cfg80211_chandef_dfs_required(wdev->wiphy, - &wdev->chandef)) + ret = cfg80211_chandef_dfs_required(wdev->wiphy, + &wdev->chandef, + wdev->iftype); + WARN_ON(ret < 0); + if (ret > 0) *radar_detect |= BIT(wdev->chandef.width); } return; @@ -753,8 +884,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, *chan = wdev->chandef.chan; *chanmode = CHAN_MODE_SHARED; - if (cfg80211_chandef_dfs_required(wdev->wiphy, - &wdev->chandef)) + ret = cfg80211_chandef_dfs_required(wdev->wiphy, + &wdev->chandef, + wdev->iftype); + WARN_ON(ret < 0); + if (ret > 0) *radar_detect |= BIT(wdev->chandef.width); } return; diff --git a/net/wireless/core.c b/net/wireless/core.c index 086cddd03ba6ed..b3ff3697239a47 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -69,7 +69,7 @@ struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) int get_wiphy_idx(struct wiphy *wiphy) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); return rdev->wiphy_idx; } @@ -260,6 +260,45 @@ static void cfg80211_event_work(struct work_struct *work) rtnl_unlock(); } +void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev) +{ + struct cfg80211_iface_destroy *item; + + ASSERT_RTNL(); + + spin_lock_irq(&rdev->destroy_list_lock); + while ((item = list_first_entry_or_null(&rdev->destroy_list, + struct cfg80211_iface_destroy, + list))) { + struct wireless_dev *wdev, *tmp; + u32 nlportid = item->nlportid; + + list_del(&item->list); + kfree(item); + spin_unlock_irq(&rdev->destroy_list_lock); + + list_for_each_entry_safe(wdev, tmp, &rdev->wdev_list, list) { + if (nlportid == wdev->owner_nlportid) + rdev_del_virtual_intf(rdev, wdev); + } + + spin_lock_irq(&rdev->destroy_list_lock); + } + spin_unlock_irq(&rdev->destroy_list_lock); +} + +static void cfg80211_destroy_iface_wk(struct work_struct *work) +{ + struct cfg80211_registered_device *rdev; + + rdev = container_of(work, struct cfg80211_registered_device, + destroy_work); + + rtnl_lock(); + cfg80211_destroy_ifaces(rdev); + rtnl_unlock(); +} + /* exported functions */ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) @@ -318,6 +357,10 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) rdev->wiphy.dev.class = &ieee80211_class; rdev->wiphy.dev.platform_data = rdev; + INIT_LIST_HEAD(&rdev->destroy_list); + spin_lock_init(&rdev->destroy_list_lock); + INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk); + #ifdef CONFIG_CFG80211_DEFAULT_PS rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; #endif @@ -396,10 +439,7 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) for (j = 0; j < c->n_limits; j++) { u16 types = c->limits[j].types; - /* - * interface types shouldn't overlap, this is - * used in cfg80211_can_change_interface() - */ + /* interface types shouldn't overlap */ if (WARN_ON(types & all_iftypes)) return -EINVAL; all_iftypes |= types; @@ -435,7 +475,7 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) int wiphy_register(struct wiphy *wiphy) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); int res; enum ieee80211_band band; struct ieee80211_supported_band *sband; @@ -616,7 +656,7 @@ EXPORT_SYMBOL(wiphy_register); void wiphy_rfkill_start_polling(struct wiphy *wiphy) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); if (!rdev->ops->rfkill_poll) return; @@ -627,7 +667,7 @@ EXPORT_SYMBOL(wiphy_rfkill_start_polling); void wiphy_rfkill_stop_polling(struct wiphy *wiphy) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); rfkill_pause_polling(rdev->rfkill); } @@ -635,7 +675,7 @@ EXPORT_SYMBOL(wiphy_rfkill_stop_polling); void wiphy_unregister(struct wiphy *wiphy) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); wait_event(rdev->dev_wait, ({ int __count; @@ -675,6 +715,7 @@ void wiphy_unregister(struct wiphy *wiphy) cancel_work_sync(&rdev->conn_work); flush_work(&rdev->event_work); cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); + flush_work(&rdev->destroy_work); #ifdef CONFIG_PM if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) @@ -707,7 +748,7 @@ EXPORT_SYMBOL(wiphy_free); void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); if (rfkill_set_hw_state(rdev->rfkill, blocked)) schedule_work(&rdev->rfkill_sync); @@ -716,7 +757,7 @@ EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); void cfg80211_unregister_wdev(struct wireless_dev *wdev) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); ASSERT_RTNL(); @@ -796,12 +837,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev; - int ret; if (!wdev) return NOTIFY_DONE; - rdev = wiphy_to_dev(wdev->wiphy); + rdev = wiphy_to_rdev(wdev->wiphy); WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED); @@ -959,13 +999,14 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, case NETDEV_PRE_UP: if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) return notifier_from_errno(-EOPNOTSUPP); - ret = cfg80211_can_add_interface(rdev, wdev->iftype); - if (ret) - return notifier_from_errno(ret); + if (rfkill_blocked(rdev->rfkill)) + return notifier_from_errno(-ERFKILL); break; + default: + return NOTIFY_DONE; } - return NOTIFY_DONE; + return NOTIFY_OK; } static struct notifier_block cfg80211_netdev_notifier = { diff --git a/net/wireless/core.h b/net/wireless/core.h index 5b1fdcadd46985..681b8fa4355b09 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -80,13 +80,17 @@ struct cfg80211_registered_device { struct cfg80211_coalesce *coalesce; + spinlock_t destroy_list_lock; + struct list_head destroy_list; + struct work_struct destroy_work; + /* must be last because of the way we do wiphy_priv(), * and it should at least be aligned to NETDEV_ALIGN */ struct wiphy wiphy __aligned(NETDEV_ALIGN); }; static inline -struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy) +struct cfg80211_registered_device *wiphy_to_rdev(struct wiphy *wiphy) { BUG_ON(!wiphy); return container_of(wiphy, struct cfg80211_registered_device, wiphy); @@ -232,6 +236,13 @@ struct cfg80211_beacon_registration { u32 nlportid; }; +struct cfg80211_iface_destroy { + struct list_head list; + u32 nlportid; +}; + +void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev); + /* free object */ void cfg80211_dev_free(struct cfg80211_registered_device *rdev); @@ -240,8 +251,8 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, void ieee80211_set_bitrate_flags(struct wiphy *wiphy); -void cfg80211_bss_expire(struct cfg80211_registered_device *dev); -void cfg80211_bss_age(struct cfg80211_registered_device *dev, +void cfg80211_bss_expire(struct cfg80211_registered_device *rdev); +void cfg80211_bss_age(struct cfg80211_registered_device *rdev, unsigned long age_secs); /* IBSS */ @@ -401,35 +412,6 @@ unsigned int cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, const struct cfg80211_chan_def *chandef); -static inline int -cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, - enum nl80211_iftype iftype) -{ - return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL, - CHAN_MODE_UNDEFINED, 0); -} - -static inline int -cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, - enum nl80211_iftype iftype) -{ - if (rfkill_blocked(rdev->rfkill)) - return -ERFKILL; - - return cfg80211_can_change_interface(rdev, NULL, iftype); -} - -static inline int -cfg80211_can_use_chan(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, - struct ieee80211_channel *chan, - enum cfg80211_chan_mode chanmode) -{ - return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, - chan, chanmode, 0); -} - static inline unsigned int elapsed_jiffies_msecs(unsigned long start) { unsigned long end = jiffies; diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c index e37862f1b1270d..d4860bfc020e5a 100644 --- a/net/wireless/ethtool.c +++ b/net/wireless/ethtool.c @@ -43,7 +43,7 @@ static void cfg80211_get_ringparam(struct net_device *dev, struct ethtool_ringparam *rp) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); memset(rp, 0, sizeof(*rp)); @@ -56,7 +56,7 @@ static int cfg80211_set_ringparam(struct net_device *dev, struct ethtool_ringparam *rp) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0) return -EINVAL; @@ -70,7 +70,7 @@ static int cfg80211_set_ringparam(struct net_device *dev, static int cfg80211_get_sset_count(struct net_device *dev, int sset) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); if (rdev->ops->get_et_sset_count) return rdev_get_et_sset_count(rdev, dev, sset); return -EOPNOTSUPP; @@ -80,7 +80,7 @@ static void cfg80211_get_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); if (rdev->ops->get_et_stats) rdev_get_et_stats(rdev, dev, stats, data); } @@ -88,7 +88,7 @@ static void cfg80211_get_stats(struct net_device *dev, static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); if (rdev->ops->get_et_strings) rdev_get_et_strings(rdev, dev, sset, data); } diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index a6b5bdad039c74..6b50588b709f18 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -45,7 +45,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, cfg80211_upload_connect_keys(wdev); - nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, + nl80211_send_ibss_bssid(wiphy_to_rdev(wdev->wiphy), dev, bssid, GFP_KERNEL); #ifdef CONFIG_CFG80211_WEXT memset(&wrqu, 0, sizeof(wrqu)); @@ -58,7 +58,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, struct ieee80211_channel *channel, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_event *ev; unsigned long flags; @@ -88,8 +88,6 @@ static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, struct cfg80211_cached_keys *connkeys) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct ieee80211_channel *check_chan; - u8 radar_detect_width = 0; int err; ASSERT_WDEV_LOCK(wdev); @@ -126,28 +124,6 @@ static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, #ifdef CONFIG_CFG80211_WEXT wdev->wext.ibss.chandef = params->chandef; #endif - check_chan = params->chandef.chan; - if (params->userspace_handles_dfs) { - /* Check for radar even if the current channel is not - * a radar channel - it might decide to change to DFS - * channel later. - */ - radar_detect_width = BIT(params->chandef.width); - } - - err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, - check_chan, - (params->channel_fixed && - !radar_detect_width) - ? CHAN_MODE_SHARED - : CHAN_MODE_EXCLUSIVE, - radar_detect_width); - - if (err) { - wdev->connect_keys = NULL; - return err; - } - err = rdev_join_ibss(rdev, dev, params); if (err) { wdev->connect_keys = NULL; @@ -180,7 +156,7 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); int i; ASSERT_WDEV_LOCK(wdev); @@ -335,7 +311,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, struct iw_freq *wextfreq, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct ieee80211_channel *chan = NULL; int err, freq; @@ -346,7 +322,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, if (!rdev->ops->join_ibss) return -EOPNOTSUPP; - freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); + freq = cfg80211_wext_freq(wextfreq); if (freq < 0) return freq; @@ -420,7 +396,7 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, struct iw_point *data, char *ssid) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); size_t len = data->length; int err; @@ -487,7 +463,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, struct sockaddr *ap_addr, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); u8 *bssid = ap_addr->sa_data; int err; @@ -505,6 +481,9 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) bssid = NULL; + if (bssid && !is_valid_ether_addr(bssid)) + return -EINVAL; + /* both automatic */ if (!bssid && !wdev->wext.ibss.bssid) return 0; diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 5af5cc6b2c4c24..3ddfb7cd335e6a 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -99,7 +99,6 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, const struct mesh_config *conf) { struct wireless_dev *wdev = dev->ieee80211_ptr; - u8 radar_detect_width = 0; int err; BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); @@ -175,22 +174,10 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, scan_width); } - if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) + if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef, + NL80211_IFTYPE_MESH_POINT)) return -EINVAL; - err = cfg80211_chandef_dfs_required(wdev->wiphy, &setup->chandef); - if (err < 0) - return err; - if (err) - radar_detect_width = BIT(setup->chandef.width); - - err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, - setup->chandef.chan, - CHAN_MODE_SHARED, - radar_detect_width); - if (err) - return err; - err = rdev_join_mesh(rdev, dev, conf, setup); if (!err) { memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); @@ -236,17 +223,6 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, if (!netif_running(wdev->netdev)) return -ENETDOWN; - /* cfg80211_can_use_chan() calls - * cfg80211_can_use_iftype_chan() with no radar - * detection, so if we're trying to use a radar - * channel here, something is wrong. - */ - WARN_ON_ONCE(chandef->chan->flags & IEEE80211_CHAN_RADAR); - err = cfg80211_can_use_chan(rdev, wdev, chandef->chan, - CHAN_MODE_SHARED); - if (err) - return err; - err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, chandef->chan); if (!err) diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index c52ff59a3e96d7..266766b8d80b61 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -23,7 +23,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; u8 *ie = mgmt->u.assoc_resp.variable; int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); @@ -54,7 +54,7 @@ EXPORT_SYMBOL(cfg80211_rx_assoc_resp); static void cfg80211_process_auth(struct wireless_dev *wdev, const u8 *buf, size_t len) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); nl80211_send_rx_auth(rdev, wdev->netdev, buf, len, GFP_KERNEL); cfg80211_sme_rx_auth(wdev, buf, len); @@ -63,7 +63,7 @@ static void cfg80211_process_auth(struct wireless_dev *wdev, static void cfg80211_process_deauth(struct wireless_dev *wdev, const u8 *buf, size_t len) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; const u8 *bssid = mgmt->bssid; u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); @@ -82,7 +82,7 @@ static void cfg80211_process_deauth(struct wireless_dev *wdev, static void cfg80211_process_disassoc(struct wireless_dev *wdev, const u8 *buf, size_t len) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; const u8 *bssid = mgmt->bssid; u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); @@ -123,7 +123,7 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); trace_cfg80211_send_auth_timeout(dev, addr); @@ -136,7 +136,7 @@ void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); trace_cfg80211_send_assoc_timeout(dev, bss->bssid); @@ -172,7 +172,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, const u8 *tsc, gfp_t gfp) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); #ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; char *buf = kmalloc(128, gfp); @@ -233,14 +233,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, if (!req.bss) return -ENOENT; - err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, - CHAN_MODE_SHARED); - if (err) - goto out; - err = rdev_auth(rdev, dev, &req); -out: cfg80211_put_bss(&rdev->wiphy, req.bss); return err; } @@ -306,16 +300,10 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, if (!req->bss) return -ENOENT; - err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED); - if (err) - goto out; - err = rdev_assoc(rdev, dev, req); if (!err) cfg80211_hold_bss(bss_from_pub(req->bss)); - -out: - if (err) + else cfg80211_put_bss(&rdev->wiphy, req->bss); return err; @@ -414,7 +402,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, int match_len) { struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_mgmt_registration *reg, *nreg; int err = 0; u16 mgmt_type; @@ -473,7 +461,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) { struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_mgmt_registration *reg, *tmp; spin_lock_bh(&wdev->mgmt_registrations_lock); @@ -620,7 +608,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, const u8 *buf, size_t len, u32 flags, gfp_t gfp) { struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_mgmt_registration *reg; const struct ieee80211_txrx_stypes *stypes = &wiphy->mgmt_stypes[wdev->iftype]; @@ -739,7 +727,7 @@ void cfg80211_radar_event(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, gfp_t gfp) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); unsigned long timeout; trace_cfg80211_radar_event(wiphy, chandef); @@ -764,7 +752,7 @@ void cfg80211_cac_event(struct net_device *netdev, { struct wireless_dev *wdev = netdev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); unsigned long timeout; trace_cfg80211_cac_event(netdev, event); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 052c1bf8ffaceb..0f1b18f209d625 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -168,8 +168,8 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) netdev = __dev_get_by_index(netns, ifindex); if (netdev) { if (netdev->ieee80211_ptr) - tmp = wiphy_to_dev( - netdev->ieee80211_ptr->wiphy); + tmp = wiphy_to_rdev( + netdev->ieee80211_ptr->wiphy); else tmp = NULL; @@ -385,6 +385,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN }, [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, + [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -484,7 +485,7 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, err = PTR_ERR(*wdev); goto out_unlock; } - *rdev = wiphy_to_dev((*wdev)->wiphy); + *rdev = wiphy_to_rdev((*wdev)->wiphy); /* 0 is the first index - add 1 to parse only once */ cb->args[0] = (*rdev)->wiphy_idx + 1; cb->args[1] = (*wdev)->identifier; @@ -497,7 +498,7 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, err = -ENODEV; goto out_unlock; } - *rdev = wiphy_to_dev(wiphy); + *rdev = wiphy_to_rdev(wiphy); *wdev = NULL; list_for_each_entry(tmp, &(*rdev)->wdev_list, list) { @@ -566,6 +567,13 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct ieee80211_channel *chan, bool large) { + /* Some channels must be completely excluded from the + * list to protect old user-space tools from breaking + */ + if (!large && chan->flags & + (IEEE80211_CHAN_NO_10MHZ | IEEE80211_CHAN_NO_20MHZ)) + return 0; + if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ, chan->center_freq)) goto nla_put_failure; @@ -613,6 +621,18 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) && nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ)) goto nla_put_failure; + if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) && + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY)) + goto nla_put_failure; + if ((chan->flags & IEEE80211_CHAN_GO_CONCURRENT) && + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_GO_CONCURRENT)) + goto nla_put_failure; + if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) && + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ)) + goto nla_put_failure; + if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) && + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ)) + goto nla_put_failure; } if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, @@ -1006,42 +1026,42 @@ static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev, } static int nl80211_send_wowlan(struct sk_buff *msg, - struct cfg80211_registered_device *dev, + struct cfg80211_registered_device *rdev, bool large) { struct nlattr *nl_wowlan; - if (!dev->wiphy.wowlan) + if (!rdev->wiphy.wowlan) return 0; nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); if (!nl_wowlan) return -ENOBUFS; - if (((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) && + if (((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) && nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) || - ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) && + ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) && nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) || - ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) && + ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) && nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) || - ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) && + ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) && nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) || - ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && + ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) || - ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) && + ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) && nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) || - ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) && + ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) && nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) || - ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) && + ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) && nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) return -ENOBUFS; - if (dev->wiphy.wowlan->n_patterns) { + if (rdev->wiphy.wowlan->n_patterns) { struct nl80211_pattern_support pat = { - .max_patterns = dev->wiphy.wowlan->n_patterns, - .min_pattern_len = dev->wiphy.wowlan->pattern_min_len, - .max_pattern_len = dev->wiphy.wowlan->pattern_max_len, - .max_pkt_offset = dev->wiphy.wowlan->max_pkt_offset, + .max_patterns = rdev->wiphy.wowlan->n_patterns, + .min_pattern_len = rdev->wiphy.wowlan->pattern_min_len, + .max_pattern_len = rdev->wiphy.wowlan->pattern_max_len, + .max_pkt_offset = rdev->wiphy.wowlan->max_pkt_offset, }; if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, @@ -1049,7 +1069,7 @@ static int nl80211_send_wowlan(struct sk_buff *msg, return -ENOBUFS; } - if (large && nl80211_send_wowlan_tcp_caps(dev, msg)) + if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) return -ENOBUFS; nla_nest_end(msg, nl_wowlan); @@ -1059,19 +1079,19 @@ static int nl80211_send_wowlan(struct sk_buff *msg, #endif static int nl80211_send_coalesce(struct sk_buff *msg, - struct cfg80211_registered_device *dev) + struct cfg80211_registered_device *rdev) { struct nl80211_coalesce_rule_support rule; - if (!dev->wiphy.coalesce) + if (!rdev->wiphy.coalesce) return 0; - rule.max_rules = dev->wiphy.coalesce->n_rules; - rule.max_delay = dev->wiphy.coalesce->max_delay; - rule.pat.max_patterns = dev->wiphy.coalesce->n_patterns; - rule.pat.min_pattern_len = dev->wiphy.coalesce->pattern_min_len; - rule.pat.max_pattern_len = dev->wiphy.coalesce->pattern_max_len; - rule.pat.max_pkt_offset = dev->wiphy.coalesce->max_pkt_offset; + rule.max_rules = rdev->wiphy.coalesce->n_rules; + rule.max_delay = rdev->wiphy.coalesce->max_delay; + rule.pat.max_patterns = rdev->wiphy.coalesce->n_patterns; + rule.pat.min_pattern_len = rdev->wiphy.coalesce->pattern_min_len; + rule.pat.max_pattern_len = rdev->wiphy.coalesce->pattern_max_len; + rule.pat.max_pkt_offset = rdev->wiphy.coalesce->max_pkt_offset; if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule)) return -ENOBUFS; @@ -1202,7 +1222,7 @@ struct nl80211_dump_wiphy_state { bool split; }; -static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, +static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, struct sk_buff *msg, u32 portid, u32 seq, int flags, struct nl80211_dump_wiphy_state *state) { @@ -1214,7 +1234,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, struct ieee80211_channel *chan; int i; const struct ieee80211_txrx_stypes *mgmt_stypes = - dev->wiphy.mgmt_stypes; + rdev->wiphy.mgmt_stypes; u32 features; hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY); @@ -1224,9 +1244,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, if (WARN_ON(!state)) return -EINVAL; - if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) || + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, - wiphy_name(&dev->wiphy)) || + wiphy_name(&rdev->wiphy)) || nla_put_u32(msg, NL80211_ATTR_GENERATION, cfg80211_rdev_list_generation)) goto nla_put_failure; @@ -1234,43 +1254,43 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, switch (state->split_start) { case 0: if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, - dev->wiphy.retry_short) || + rdev->wiphy.retry_short) || nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, - dev->wiphy.retry_long) || + rdev->wiphy.retry_long) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, - dev->wiphy.frag_threshold) || + rdev->wiphy.frag_threshold) || nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, - dev->wiphy.rts_threshold) || + rdev->wiphy.rts_threshold) || nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, - dev->wiphy.coverage_class) || + rdev->wiphy.coverage_class) || nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, - dev->wiphy.max_scan_ssids) || + rdev->wiphy.max_scan_ssids) || nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, - dev->wiphy.max_sched_scan_ssids) || + rdev->wiphy.max_sched_scan_ssids) || nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, - dev->wiphy.max_scan_ie_len) || + rdev->wiphy.max_scan_ie_len) || nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, - dev->wiphy.max_sched_scan_ie_len) || + rdev->wiphy.max_sched_scan_ie_len) || nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS, - dev->wiphy.max_match_sets)) + rdev->wiphy.max_match_sets)) goto nla_put_failure; - if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) && + if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) && nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN)) goto nla_put_failure; - if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && + if ((rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH)) goto nla_put_failure; - if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && + if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD)) goto nla_put_failure; - if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) && + if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) && nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT)) goto nla_put_failure; - if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) && + if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) && nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT)) goto nla_put_failure; - if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && + if ((rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) goto nla_put_failure; state->split_start++; @@ -1278,35 +1298,35 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, break; case 1: if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, - sizeof(u32) * dev->wiphy.n_cipher_suites, - dev->wiphy.cipher_suites)) + sizeof(u32) * rdev->wiphy.n_cipher_suites, + rdev->wiphy.cipher_suites)) goto nla_put_failure; if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, - dev->wiphy.max_num_pmkids)) + rdev->wiphy.max_num_pmkids)) goto nla_put_failure; - if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) && + if ((rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) && nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE)) goto nla_put_failure; if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, - dev->wiphy.available_antennas_tx) || + rdev->wiphy.available_antennas_tx) || nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, - dev->wiphy.available_antennas_rx)) + rdev->wiphy.available_antennas_rx)) goto nla_put_failure; - if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) && + if ((rdev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) && nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD, - dev->wiphy.probe_resp_offload)) + rdev->wiphy.probe_resp_offload)) goto nla_put_failure; - if ((dev->wiphy.available_antennas_tx || - dev->wiphy.available_antennas_rx) && - dev->ops->get_antenna) { + if ((rdev->wiphy.available_antennas_tx || + rdev->wiphy.available_antennas_rx) && + rdev->ops->get_antenna) { u32 tx_ant = 0, rx_ant = 0; int res; - res = rdev_get_antenna(dev, &tx_ant, &rx_ant); + res = rdev_get_antenna(rdev, &tx_ant, &rx_ant); if (!res) { if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, @@ -1323,7 +1343,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, break; case 2: if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, - dev->wiphy.interface_modes)) + rdev->wiphy.interface_modes)) goto nla_put_failure; state->split_start++; if (state->split) @@ -1337,7 +1357,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; - sband = dev->wiphy.bands[band]; + sband = rdev->wiphy.bands[band]; if (!sband) continue; @@ -1414,7 +1434,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, i = 0; #define CMD(op, n) \ do { \ - if (dev->ops->op) { \ + if (rdev->ops->op) { \ i++; \ if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \ goto nla_put_failure; \ @@ -1438,32 +1458,32 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, CMD(set_pmksa, SET_PMKSA); CMD(del_pmksa, DEL_PMKSA); CMD(flush_pmksa, FLUSH_PMKSA); - if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) + if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) CMD(remain_on_channel, REMAIN_ON_CHANNEL); CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); CMD(mgmt_tx, FRAME); CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL); - if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { + if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { i++; if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) goto nla_put_failure; } - if (dev->ops->set_monitor_channel || dev->ops->start_ap || - dev->ops->join_mesh) { + if (rdev->ops->set_monitor_channel || rdev->ops->start_ap || + rdev->ops->join_mesh) { i++; if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL)) goto nla_put_failure; } CMD(set_wds_peer, SET_WDS_PEER); - if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { + if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { CMD(tdls_mgmt, TDLS_MGMT); CMD(tdls_oper, TDLS_OPER); } - if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) + if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) CMD(sched_scan_start, START_SCHED_SCAN); CMD(probe_client, PROBE_CLIENT); CMD(set_noack_map, SET_NOACK_MAP); - if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) { + if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) { i++; if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS)) goto nla_put_failure; @@ -1473,7 +1493,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, if (state->split) { CMD(crit_proto_start, CRIT_PROTOCOL_START); CMD(crit_proto_stop, CRIT_PROTOCOL_STOP); - if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH) + if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH) CMD(channel_switch, CHANNEL_SWITCH); } CMD(set_qos_map, SET_QOS_MAP); @@ -1484,13 +1504,13 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, #undef CMD - if (dev->ops->connect || dev->ops->auth) { + if (rdev->ops->connect || rdev->ops->auth) { i++; if (nla_put_u32(msg, i, NL80211_CMD_CONNECT)) goto nla_put_failure; } - if (dev->ops->disconnect || dev->ops->deauth) { + if (rdev->ops->disconnect || rdev->ops->deauth) { i++; if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT)) goto nla_put_failure; @@ -1501,14 +1521,14 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, if (state->split) break; case 5: - if (dev->ops->remain_on_channel && - (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) && + if (rdev->ops->remain_on_channel && + (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) && nla_put_u32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, - dev->wiphy.max_remain_on_channel_duration)) + rdev->wiphy.max_remain_on_channel_duration)) goto nla_put_failure; - if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) && + if ((rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) && nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) goto nla_put_failure; @@ -1519,7 +1539,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, break; case 6: #ifdef CONFIG_PM - if (nl80211_send_wowlan(msg, dev, state->split)) + if (nl80211_send_wowlan(msg, rdev, state->split)) goto nla_put_failure; state->split_start++; if (state->split) @@ -1529,10 +1549,10 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, #endif case 7: if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, - dev->wiphy.software_iftypes)) + rdev->wiphy.software_iftypes)) goto nla_put_failure; - if (nl80211_put_iface_combinations(&dev->wiphy, msg, + if (nl80211_put_iface_combinations(&rdev->wiphy, msg, state->split)) goto nla_put_failure; @@ -1540,12 +1560,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, if (state->split) break; case 8: - if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && + if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME, - dev->wiphy.ap_sme_capa)) + rdev->wiphy.ap_sme_capa)) goto nla_put_failure; - features = dev->wiphy.features; + features = rdev->wiphy.features; /* * We can only add the per-channel limit information if the * dump is split, otherwise it makes it too big. Therefore @@ -1556,16 +1576,16 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features)) goto nla_put_failure; - if (dev->wiphy.ht_capa_mod_mask && + if (rdev->wiphy.ht_capa_mod_mask && nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, - sizeof(*dev->wiphy.ht_capa_mod_mask), - dev->wiphy.ht_capa_mod_mask)) + sizeof(*rdev->wiphy.ht_capa_mod_mask), + rdev->wiphy.ht_capa_mod_mask)) goto nla_put_failure; - if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME && - dev->wiphy.max_acl_mac_addrs && + if (rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME && + rdev->wiphy.max_acl_mac_addrs && nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX, - dev->wiphy.max_acl_mac_addrs)) + rdev->wiphy.max_acl_mac_addrs)) goto nla_put_failure; /* @@ -1581,41 +1601,41 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, state->split_start++; break; case 9: - if (dev->wiphy.extended_capabilities && + if (rdev->wiphy.extended_capabilities && (nla_put(msg, NL80211_ATTR_EXT_CAPA, - dev->wiphy.extended_capabilities_len, - dev->wiphy.extended_capabilities) || + rdev->wiphy.extended_capabilities_len, + rdev->wiphy.extended_capabilities) || nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK, - dev->wiphy.extended_capabilities_len, - dev->wiphy.extended_capabilities_mask))) + rdev->wiphy.extended_capabilities_len, + rdev->wiphy.extended_capabilities_mask))) goto nla_put_failure; - if (dev->wiphy.vht_capa_mod_mask && + if (rdev->wiphy.vht_capa_mod_mask && nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, - sizeof(*dev->wiphy.vht_capa_mod_mask), - dev->wiphy.vht_capa_mod_mask)) + sizeof(*rdev->wiphy.vht_capa_mod_mask), + rdev->wiphy.vht_capa_mod_mask)) goto nla_put_failure; state->split_start++; break; case 10: - if (nl80211_send_coalesce(msg, dev)) + if (nl80211_send_coalesce(msg, rdev)) goto nla_put_failure; - if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) && + if ((rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) && (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) || nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ))) goto nla_put_failure; - if (dev->wiphy.max_ap_assoc_sta && + if (rdev->wiphy.max_ap_assoc_sta && nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA, - dev->wiphy.max_ap_assoc_sta)) + rdev->wiphy.max_ap_assoc_sta)) goto nla_put_failure; state->split_start++; break; case 11: - if (dev->wiphy.n_vendor_commands) { + if (rdev->wiphy.n_vendor_commands) { const struct nl80211_vendor_cmd_info *info; struct nlattr *nested; @@ -1623,15 +1643,15 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, if (!nested) goto nla_put_failure; - for (i = 0; i < dev->wiphy.n_vendor_commands; i++) { - info = &dev->wiphy.vendor_commands[i].info; + for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) { + info = &rdev->wiphy.vendor_commands[i].info; if (nla_put(msg, i + 1, sizeof(*info), info)) goto nla_put_failure; } nla_nest_end(msg, nested); } - if (dev->wiphy.n_vendor_events) { + if (rdev->wiphy.n_vendor_events) { const struct nl80211_vendor_cmd_info *info; struct nlattr *nested; @@ -1640,8 +1660,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, if (!nested) goto nla_put_failure; - for (i = 0; i < dev->wiphy.n_vendor_events; i++) { - info = &dev->wiphy.vendor_events[i]; + for (i = 0; i < rdev->wiphy.n_vendor_events; i++) { + info = &rdev->wiphy.vendor_events[i]; if (nla_put(msg, i + 1, sizeof(*info), info)) goto nla_put_failure; } @@ -1684,7 +1704,7 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb, if (!netdev) return -ENODEV; if (netdev->ieee80211_ptr) { - rdev = wiphy_to_dev( + rdev = wiphy_to_rdev( netdev->ieee80211_ptr->wiphy); state->filter_wiphy = rdev->wiphy_idx; } @@ -1697,7 +1717,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) { int idx = 0, ret; struct nl80211_dump_wiphy_state *state = (void *)cb->args[0]; - struct cfg80211_registered_device *dev; + struct cfg80211_registered_device *rdev; rtnl_lock(); if (!state) { @@ -1716,17 +1736,17 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) cb->args[0] = (long)state; } - list_for_each_entry(dev, &cfg80211_rdev_list, list) { - if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) continue; if (++idx <= state->start) continue; if (state->filter_wiphy != -1 && - state->filter_wiphy != dev->wiphy_idx) + state->filter_wiphy != rdev->wiphy_idx) continue; /* attempt to fit multiple wiphy data chunks into the skb */ do { - ret = nl80211_send_wiphy(dev, skb, + ret = nl80211_send_wiphy(rdev, skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, NLM_F_MULTI, state); @@ -1774,14 +1794,14 @@ static int nl80211_dump_wiphy_done(struct netlink_callback *cb) static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; - struct cfg80211_registered_device *dev = info->user_ptr[0]; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct nl80211_dump_wiphy_state state = {}; msg = nlmsg_new(4096, GFP_KERNEL); if (!msg) return -ENOMEM; - if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0, + if (nl80211_send_wiphy(rdev, msg, info->snd_portid, info->snd_seq, 0, &state) < 0) { nlmsg_free(msg); return -ENOBUFS; @@ -1908,18 +1928,20 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, } static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, + struct net_device *dev, struct genl_info *info) { struct cfg80211_chan_def chandef; int result; enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR; + struct wireless_dev *wdev = NULL; - if (wdev) - iftype = wdev->iftype; - + if (dev) + wdev = dev->ieee80211_ptr; if (!nl80211_can_set_dev_channel(wdev)) return -EOPNOTSUPP; + if (wdev) + iftype = wdev->iftype; result = nl80211_parse_chandef(rdev, info, &chandef); if (result) @@ -1928,14 +1950,27 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, switch (iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - if (wdev->beacon_interval) { - result = -EBUSY; - break; - } - if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef)) { + if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) { result = -EINVAL; break; } + if (wdev->beacon_interval) { + if (!dev || !rdev->ops->set_ap_chanwidth || + !(rdev->wiphy.features & + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) { + result = -EBUSY; + break; + } + + /* Only allow dynamic channel width changes */ + if (chandef.chan != wdev->preset_chandef.chan) { + result = -EBUSY; + break; + } + result = rdev_set_ap_chanwidth(rdev, dev, &chandef); + if (result) + break; + } wdev->preset_chandef = chandef; result = 0; break; @@ -1957,7 +1992,7 @@ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *netdev = info->user_ptr[1]; - return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); + return __nl80211_set_channel(rdev, netdev, info); } static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) @@ -2013,7 +2048,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) netdev = __dev_get_by_index(genl_info_net(info), ifindex); if (netdev && netdev->ieee80211_ptr) - rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy); + rdev = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy); else netdev = NULL; } @@ -2079,9 +2114,10 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { - result = __nl80211_set_channel(rdev, - nl80211_can_set_dev_channel(wdev) ? wdev : NULL, - info); + result = __nl80211_set_channel( + rdev, + nl80211_can_set_dev_channel(wdev) ? netdev : NULL, + info); if (result) return result; } @@ -2229,7 +2265,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) static inline u64 wdev_id(struct wireless_dev *wdev) { return (u64)wdev->identifier | - ((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32); + ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32); } static int nl80211_send_chandef(struct sk_buff *msg, @@ -2355,7 +2391,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; - struct cfg80211_registered_device *dev = info->user_ptr[0]; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct wireless_dev *wdev = info->user_ptr[1]; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); @@ -2363,7 +2399,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) return -ENOMEM; if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, - dev, wdev) < 0) { + rdev, wdev) < 0) { nlmsg_free(msg); return -ENOBUFS; } @@ -2514,6 +2550,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; u32 flags; + /* to avoid failing a new interface creation due to pending removal */ + cfg80211_destroy_ifaces(rdev); + memset(¶ms, 0, sizeof(params)); if (!info->attrs[NL80211_ATTR_IFNAME]) @@ -2563,6 +2602,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) return PTR_ERR(wdev); } + if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER]) + wdev->owner_nlportid = info->snd_portid; + switch (type) { case NL80211_IFTYPE_MESH_POINT: if (!info->attrs[NL80211_ATTR_MESH_ID]) @@ -3142,7 +3184,6 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_ap_settings params; int err; - u8 radar_detect_width = 0; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) @@ -3258,24 +3299,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) } else if (!nl80211_get_ap_channel(rdev, ¶ms)) return -EINVAL; - if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) + if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef, + wdev->iftype)) return -EINVAL; - err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef); - if (err < 0) - return err; - if (err) { - radar_detect_width = BIT(params.chandef.width); - params.radar_required = true; - } - - err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, - params.chandef.chan, - CHAN_MODE_SHARED, - radar_detect_width); - if (err) - return err; - if (info->attrs[NL80211_ATTR_ACL_POLICY]) { params.acl = parse_acl_data(&rdev->wiphy, info); if (IS_ERR(params.acl)) @@ -3675,13 +3702,13 @@ static int nl80211_dump_station(struct sk_buff *skb, struct netlink_callback *cb) { struct station_info sinfo; - struct cfg80211_registered_device *dev; + struct cfg80211_registered_device *rdev; struct wireless_dev *wdev; u8 mac_addr[ETH_ALEN]; int sta_idx = cb->args[2]; int err; - err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev); + err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); if (err) return err; @@ -3690,14 +3717,14 @@ static int nl80211_dump_station(struct sk_buff *skb, goto out_err; } - if (!dev->ops->dump_station) { + if (!rdev->ops->dump_station) { err = -EOPNOTSUPP; goto out_err; } while (1) { memset(&sinfo, 0, sizeof(sinfo)); - err = rdev_dump_station(dev, wdev->netdev, sta_idx, + err = rdev_dump_station(rdev, wdev->netdev, sta_idx, mac_addr, &sinfo); if (err == -ENOENT) break; @@ -3707,7 +3734,7 @@ static int nl80211_dump_station(struct sk_buff *skb, if (nl80211_send_station(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - dev, wdev->netdev, mac_addr, + rdev, wdev->netdev, mac_addr, &sinfo) < 0) goto out; @@ -3719,7 +3746,7 @@ static int nl80211_dump_station(struct sk_buff *skb, cb->args[2] = sta_idx; err = skb->len; out_err: - nl80211_finish_wdev_dump(dev); + nl80211_finish_wdev_dump(rdev); return err; } @@ -4380,18 +4407,18 @@ static int nl80211_dump_mpath(struct sk_buff *skb, struct netlink_callback *cb) { struct mpath_info pinfo; - struct cfg80211_registered_device *dev; + struct cfg80211_registered_device *rdev; struct wireless_dev *wdev; u8 dst[ETH_ALEN]; u8 next_hop[ETH_ALEN]; int path_idx = cb->args[2]; int err; - err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev); + err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); if (err) return err; - if (!dev->ops->dump_mpath) { + if (!rdev->ops->dump_mpath) { err = -EOPNOTSUPP; goto out_err; } @@ -4402,7 +4429,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, } while (1) { - err = rdev_dump_mpath(dev, wdev->netdev, path_idx, dst, + err = rdev_dump_mpath(rdev, wdev->netdev, path_idx, dst, next_hop, &pinfo); if (err == -ENOENT) break; @@ -4423,7 +4450,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, cb->args[2] = path_idx; err = skb->len; out_err: - nl80211_finish_wdev_dump(dev); + nl80211_finish_wdev_dump(rdev); return err; } @@ -4663,7 +4690,6 @@ static int parse_reg_rule(struct nlattr *tb[], static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) { - int r; char *data = NULL; enum nl80211_user_reg_hint_type user_reg_hint_type; @@ -4676,11 +4702,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) if (unlikely(!rcu_access_pointer(cfg80211_regdomain))) return -EINPROGRESS; - if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) - return -EINVAL; - - data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); - if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]) user_reg_hint_type = nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]); @@ -4690,14 +4711,16 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) switch (user_reg_hint_type) { case NL80211_USER_REG_HINT_USER: case NL80211_USER_REG_HINT_CELL_BASE: - break; + if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) + return -EINVAL; + + data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); + return regulatory_hint_user(data, user_reg_hint_type); + case NL80211_USER_REG_HINT_INDOOR: + return regulatory_hint_indoor_user(); default: return -EINVAL; } - - r = regulatory_hint_user(data, user_reg_hint_type); - - return r; } static int nl80211_get_mesh_config(struct sk_buff *skb, @@ -5796,7 +5819,8 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, if (wdev->cac_started) return -EBUSY; - err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef); + err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, + NL80211_IFTYPE_UNSPECIFIED); if (err < 0) return err; @@ -5809,12 +5833,6 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, if (!rdev->ops->start_radar_detection) return -EOPNOTSUPP; - err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, - chandef.chan, CHAN_MODE_SHARED, - BIT(chandef.width)); - if (err) - return err; - cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef); if (WARN_ON(!cac_time_ms)) cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; @@ -5928,27 +5946,25 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) if (err) return err; - if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) + if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef, + wdev->iftype)) return -EINVAL; - switch (dev->ieee80211_ptr->iftype) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - err = cfg80211_chandef_dfs_required(wdev->wiphy, - ¶ms.chandef); - if (err < 0) - return err; - if (err) { - radar_detect_width = BIT(params.chandef.width); - params.radar_required = true; - } - break; - default: - break; + err = cfg80211_chandef_dfs_required(wdev->wiphy, + ¶ms.chandef, + wdev->iftype); + if (err < 0) + return err; + + if (err > 0) { + radar_detect_width = BIT(params.chandef.width); + params.radar_required = true; } + /* TODO: I left this here for now. With channel switch, the + * verification is a bit more complicated, because we only do + * it later when the channel switch really happens. + */ err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, params.chandef.chan, CHAN_MODE_SHARED, @@ -6175,12 +6191,12 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb) { struct survey_info survey; - struct cfg80211_registered_device *dev; + struct cfg80211_registered_device *rdev; struct wireless_dev *wdev; int survey_idx = cb->args[2]; int res; - res = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev); + res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); if (res) return res; @@ -6189,7 +6205,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, goto out_err; } - if (!dev->ops->dump_survey) { + if (!rdev->ops->dump_survey) { res = -EOPNOTSUPP; goto out_err; } @@ -6197,7 +6213,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, while (1) { struct ieee80211_channel *chan; - res = rdev_dump_survey(dev, wdev->netdev, survey_idx, &survey); + res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey); if (res == -ENOENT) break; if (res) @@ -6209,7 +6225,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, goto out; } - chan = ieee80211_get_channel(&dev->wiphy, + chan = ieee80211_get_channel(&rdev->wiphy, survey.channel->center_freq); if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { survey_idx++; @@ -6228,7 +6244,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, cb->args[2] = survey_idx; res = skb->len; out_err: - nl80211_finish_wdev_dump(dev); + nl80211_finish_wdev_dump(rdev); return res; } @@ -6704,7 +6720,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) if (err) return err; - if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef)) + if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef, + NL80211_IFTYPE_ADHOC)) return -EINVAL; switch (ibss.chandef.width) { @@ -6879,7 +6896,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, int vendor_event_idx, int approxlen, gfp_t gfp) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); const struct nl80211_vendor_cmd_info *info; switch (cmd) { @@ -8981,9 +8998,8 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) if (wdev->p2p_started) return 0; - err = cfg80211_can_add_interface(rdev, wdev->iftype); - if (err) - return err; + if (rfkill_blocked(rdev->rfkill)) + return -ERFKILL; err = rdev_start_p2p_device(rdev, wdev); if (err) @@ -9192,7 +9208,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy, enum nl80211_attrs attr, int approxlen) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); if (WARN_ON(!rdev->cur_cmd_info)) return NULL; @@ -9316,7 +9332,7 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, } dev = wdev->netdev; - rdev = wiphy_to_dev(wdev->wiphy); + rdev = wiphy_to_rdev(wdev->wiphy); if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { if (!dev) { @@ -10345,7 +10361,7 @@ void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); const struct ieee80211_mgmt *mgmt = (void *)buf; u32 cmd; @@ -10567,7 +10583,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr, const u8* ie, u8 ie_len, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct sk_buff *msg; void *hdr; @@ -10747,7 +10763,7 @@ void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, unsigned int duration, gfp_t gfp) { struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration); nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, @@ -10761,7 +10777,7 @@ void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, gfp_t gfp) { struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan); nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, @@ -10773,7 +10789,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, struct station_info *sinfo, gfp_t gfp) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct sk_buff *msg; trace_cfg80211_new_sta(dev, mac_addr, sinfo); @@ -10796,7 +10812,7 @@ EXPORT_SYMBOL(cfg80211_new_sta); void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct sk_buff *msg; void *hdr; @@ -10833,7 +10849,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct sk_buff *msg; void *hdr; @@ -10868,7 +10884,7 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, const u8 *addr, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct sk_buff *msg; void *hdr; u32 nlportid = ACCESS_ONCE(wdev->ap_unexpected_nlportid); @@ -10988,7 +11004,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, const u8 *buf, size_t len, bool ack, gfp_t gfp) { struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct net_device *netdev = wdev->netdev; struct sk_buff *msg; void *hdr; @@ -11032,7 +11048,7 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct sk_buff *msg; struct nlattr *pinfoattr; void *hdr; @@ -11124,7 +11140,7 @@ void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); trace_cfg80211_gtk_rekey_notify(dev, bssid); nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp); @@ -11182,7 +11198,7 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth); nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); @@ -11229,7 +11245,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); ASSERT_WDEV_LOCK(wdev); @@ -11253,7 +11269,7 @@ void cfg80211_cqm_txe_notify(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct sk_buff *msg; struct nlattr *pinfoattr; void *hdr; @@ -11353,7 +11369,7 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct sk_buff *msg; struct nlattr *pinfoattr; void *hdr; @@ -11400,7 +11416,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, u64 cookie, bool acked, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct sk_buff *msg; void *hdr; @@ -11440,7 +11456,7 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, const u8 *frame, size_t len, int freq, int sig_dbm) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct sk_buff *msg; void *hdr; struct cfg80211_beacon_registration *reg; @@ -11487,7 +11503,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, struct cfg80211_wowlan_wakeup *wakeup, gfp_t gfp) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct sk_buff *msg; void *hdr; int size = 200; @@ -11597,7 +11613,7 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, u16 reason_code, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct sk_buff *msg; void *hdr; @@ -11649,9 +11665,15 @@ static int nl80211_netlink_notify(struct notifier_block * nb, rcu_read_lock(); list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { - list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) + bool schedule_destroy_work = false; + + list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) { cfg80211_mlme_unregister_socket(wdev, notify->portid); + if (wdev->owner_nlportid == notify->portid) + schedule_destroy_work = true; + } + spin_lock_bh(&rdev->beacon_registrations_lock); list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations, list) { @@ -11662,11 +11684,24 @@ static int nl80211_netlink_notify(struct notifier_block * nb, } } spin_unlock_bh(&rdev->beacon_registrations_lock); + + if (schedule_destroy_work) { + struct cfg80211_iface_destroy *destroy; + + destroy = kzalloc(sizeof(*destroy), GFP_ATOMIC); + if (destroy) { + destroy->nlportid = notify->portid; + spin_lock(&rdev->destroy_list_lock); + list_add(&destroy->list, &rdev->destroy_list); + spin_unlock(&rdev->destroy_list_lock); + schedule_work(&rdev->destroy_work); + } + } } rcu_read_unlock(); - return NOTIFY_DONE; + return NOTIFY_OK; } static struct notifier_block nl80211_netlink_notifier = { @@ -11677,7 +11712,7 @@ void cfg80211_ft_event(struct net_device *netdev, struct cfg80211_ft_event_params *ft_event) { struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct sk_buff *msg; void *hdr; @@ -11724,7 +11759,7 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp) void *hdr; u32 nlportid; - rdev = wiphy_to_dev(wdev->wiphy); + rdev = wiphy_to_rdev(wdev->wiphy); if (!rdev->crit_proto_nlportid) return; @@ -11759,7 +11794,7 @@ EXPORT_SYMBOL(cfg80211_crit_proto_stopped); void nl80211_send_ap_stopped(struct wireless_dev *wdev) { struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct sk_buff *msg; void *hdr; diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 74d97d33c938e8..00cdf73ba6c468 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -950,4 +950,17 @@ static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev, return ret; } +static inline int +rdev_set_ap_chanwidth(struct cfg80211_registered_device *rdev, + struct net_device *dev, struct cfg80211_chan_def *chandef) +{ + int ret; + + trace_rdev_set_ap_chanwidth(&rdev->wiphy, dev, chandef); + ret = rdev->ops->set_ap_chanwidth(&rdev->wiphy, dev, chandef); + trace_rdev_return_int(&rdev->wiphy, ret); + + return ret; +} + #endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f59aaac586f8cf..e78f532aaa5b38 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -65,11 +65,26 @@ #define REG_DBG_PRINT(args...) #endif +/** + * enum reg_request_treatment - regulatory request treatment + * + * @REG_REQ_OK: continue processing the regulatory request + * @REG_REQ_IGNORE: ignore the regulatory request + * @REG_REQ_INTERSECT: the regulatory domain resulting from this request should + * be intersected with the current one. + * @REG_REQ_ALREADY_SET: the regulatory request will not change the current + * regulatory settings, and no further processing is required. + * @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no + * further processing is required, i.e., not need to update last_request + * etc. This should be used for user hints that do not provide an alpha2 + * but some other type of regulatory hint, i.e., indoor operation. + */ enum reg_request_treatment { REG_REQ_OK, REG_REQ_IGNORE, REG_REQ_INTERSECT, REG_REQ_ALREADY_SET, + REG_REQ_USER_HINT_HANDLED, }; static struct regulatory_request core_request_world = { @@ -106,6 +121,14 @@ const struct ieee80211_regdomain __rcu *cfg80211_regdomain; */ static int reg_num_devs_support_basehint; +/* + * State variable indicating if the platform on which the devices + * are attached is operating in an indoor environment. The state variable + * is relevant for all registered devices. + * (protected by RTNL) + */ +static bool reg_is_indoor; + static const struct ieee80211_regdomain *get_cfg80211_regdom(void) { return rtnl_dereference(cfg80211_regdomain); @@ -240,8 +263,16 @@ static char user_alpha2[2]; module_param(ieee80211_regdom, charp, 0444); MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); -static void reg_free_request(struct regulatory_request *lr) +static void reg_free_request(struct regulatory_request *request) { + if (request != get_last_request()) + kfree(request); +} + +static void reg_free_last_request(void) +{ + struct regulatory_request *lr = get_last_request(); + if (lr != &core_request_world && lr) kfree_rcu(lr, rcu_head); } @@ -254,7 +285,7 @@ static void reg_update_last_request(struct regulatory_request *request) if (lr == request) return; - reg_free_request(lr); + reg_free_last_request(); rcu_assign_pointer(last_request, request); } @@ -873,6 +904,8 @@ static u32 map_regdom_flags(u32 rd_flags) channel_flags |= IEEE80211_CHAN_RADAR; if (rd_flags & NL80211_RRF_NO_OFDM) channel_flags |= IEEE80211_CHAN_NO_OFDM; + if (rd_flags & NL80211_RRF_NO_OUTDOOR) + channel_flags |= IEEE80211_CHAN_INDOOR_ONLY; return channel_flags; } @@ -902,7 +935,7 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq, if (!band_rule_found) band_rule_found = freq_in_rule_band(fr, center_freq); - bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(20)); + bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(5)); if (band_rule_found && bw_fits) return rr; @@ -986,10 +1019,10 @@ static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd, } #endif -/* - * Note that right now we assume the desired channel bandwidth - * is always 20 MHz for each individual channel (HT40 uses 20 MHz - * per channel, the primary and the extension channel). +/* Find an ieee80211_reg_rule such that a 5MHz channel with frequency + * chan->center_freq fits there. + * If there is no such reg_rule, disable the channel, otherwise set the + * flags corresponding to the bandwidths allowed in the particular reg_rule */ static void handle_channel(struct wiphy *wiphy, enum nl80211_reg_initiator initiator, @@ -1050,8 +1083,12 @@ static void handle_channel(struct wiphy *wiphy, if (reg_rule->flags & NL80211_RRF_AUTO_BW) max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); + if (max_bandwidth_khz < MHZ_TO_KHZ(10)) + bw_flags = IEEE80211_CHAN_NO_10MHZ; + if (max_bandwidth_khz < MHZ_TO_KHZ(20)) + bw_flags |= IEEE80211_CHAN_NO_20MHZ; if (max_bandwidth_khz < MHZ_TO_KHZ(40)) - bw_flags = IEEE80211_CHAN_NO_HT40; + bw_flags |= IEEE80211_CHAN_NO_HT40; if (max_bandwidth_khz < MHZ_TO_KHZ(80)) bw_flags |= IEEE80211_CHAN_NO_80MHZ; if (max_bandwidth_khz < MHZ_TO_KHZ(160)) @@ -1071,6 +1108,13 @@ static void handle_channel(struct wiphy *wiphy, (int) MBI_TO_DBI(power_rule->max_antenna_gain); chan->max_reg_power = chan->max_power = chan->orig_mpwr = (int) MBM_TO_DBM(power_rule->max_eirp); + + if (chan->flags & IEEE80211_CHAN_RADAR) { + chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; + if (reg_rule->dfs_cac_ms) + chan->dfs_cac_ms = reg_rule->dfs_cac_ms; + } + return; } @@ -1126,12 +1170,19 @@ static bool reg_request_cell_base(struct regulatory_request *request) return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE; } +static bool reg_request_indoor(struct regulatory_request *request) +{ + if (request->initiator != NL80211_REGDOM_SET_BY_USER) + return false; + return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR; +} + bool reg_last_request_cell_base(void) { return reg_request_cell_base(get_last_request()); } -#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS +#ifdef CONFIG_CFG80211_REG_CELLULAR_HINTS /* Core specific check */ static enum reg_request_treatment reg_ignore_cell_hint(struct regulatory_request *pending_request) @@ -1471,8 +1522,12 @@ static void handle_channel_custom(struct wiphy *wiphy, if (reg_rule->flags & NL80211_RRF_AUTO_BW) max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); + if (max_bandwidth_khz < MHZ_TO_KHZ(10)) + bw_flags = IEEE80211_CHAN_NO_10MHZ; + if (max_bandwidth_khz < MHZ_TO_KHZ(20)) + bw_flags |= IEEE80211_CHAN_NO_20MHZ; if (max_bandwidth_khz < MHZ_TO_KHZ(40)) - bw_flags = IEEE80211_CHAN_NO_HT40; + bw_flags |= IEEE80211_CHAN_NO_HT40; if (max_bandwidth_khz < MHZ_TO_KHZ(80)) bw_flags |= IEEE80211_CHAN_NO_80MHZ; if (max_bandwidth_khz < MHZ_TO_KHZ(160)) @@ -1568,6 +1623,11 @@ __reg_process_hint_user(struct regulatory_request *user_request) { struct regulatory_request *lr = get_last_request(); + if (reg_request_indoor(user_request)) { + reg_is_indoor = true; + return REG_REQ_USER_HINT_HANDLED; + } + if (reg_request_cell_base(user_request)) return reg_ignore_cell_hint(user_request); @@ -1615,8 +1675,9 @@ reg_process_hint_user(struct regulatory_request *user_request) treatment = __reg_process_hint_user(user_request); if (treatment == REG_REQ_IGNORE || - treatment == REG_REQ_ALREADY_SET) { - kfree(user_request); + treatment == REG_REQ_ALREADY_SET || + treatment == REG_REQ_USER_HINT_HANDLED) { + reg_free_request(user_request); return treatment; } @@ -1676,14 +1737,15 @@ reg_process_hint_driver(struct wiphy *wiphy, case REG_REQ_OK: break; case REG_REQ_IGNORE: - kfree(driver_request); + case REG_REQ_USER_HINT_HANDLED: + reg_free_request(driver_request); return treatment; case REG_REQ_INTERSECT: /* fall through */ case REG_REQ_ALREADY_SET: regd = reg_copy_regd(get_cfg80211_regdom()); if (IS_ERR(regd)) { - kfree(driver_request); + reg_free_request(driver_request); return REG_REQ_IGNORE; } rcu_assign_pointer(wiphy->regd, regd); @@ -1775,12 +1837,13 @@ reg_process_hint_country_ie(struct wiphy *wiphy, case REG_REQ_OK: break; case REG_REQ_IGNORE: + case REG_REQ_USER_HINT_HANDLED: /* fall through */ case REG_REQ_ALREADY_SET: - kfree(country_ie_request); + reg_free_request(country_ie_request); return treatment; case REG_REQ_INTERSECT: - kfree(country_ie_request); + reg_free_request(country_ie_request); /* * This doesn't happen yet, not sure we * ever want to support it for this case. @@ -1841,7 +1904,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) return; out_free: - kfree(reg_request); + reg_free_request(reg_request); } /* @@ -1857,7 +1920,7 @@ static void reg_process_pending_hints(void) /* When last_request->processed becomes true this will be rescheduled */ if (lr && !lr->processed) { - REG_DBG_PRINT("Pending regulatory request, waiting for it to be processed...\n"); + reg_process_hint(lr); return; } @@ -1967,6 +2030,22 @@ int regulatory_hint_user(const char *alpha2, return 0; } +int regulatory_hint_indoor_user(void) +{ + struct regulatory_request *request; + + request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); + if (!request) + return -ENOMEM; + + request->wiphy_idx = WIPHY_IDX_INVALID; + request->initiator = NL80211_REGDOM_SET_BY_USER; + request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR; + queue_regulatory_request(request); + + return 0; +} + /* Driver hints */ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) { @@ -2134,6 +2213,8 @@ static void restore_regulatory_settings(bool reset_user) ASSERT_RTNL(); + reg_is_indoor = false; + reset_regdomains(true, &world_regdom); restore_alpha2(alpha2, reset_user); @@ -2594,7 +2675,7 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy) reg_num_devs_support_basehint--; rcu_free_regdom(get_wiphy_regdom(wiphy)); - rcu_assign_pointer(wiphy->regd, NULL); + RCU_INIT_POINTER(wiphy->regd, NULL); if (lr) request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); @@ -2614,6 +2695,40 @@ static void reg_timeout_work(struct work_struct *work) rtnl_unlock(); } +/* + * See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for + * UNII band definitions + */ +int cfg80211_get_unii(int freq) +{ + /* UNII-1 */ + if (freq >= 5150 && freq <= 5250) + return 0; + + /* UNII-2A */ + if (freq > 5250 && freq <= 5350) + return 1; + + /* UNII-2B */ + if (freq > 5350 && freq <= 5470) + return 2; + + /* UNII-2C */ + if (freq > 5470 && freq <= 5725) + return 3; + + /* UNII-3 */ + if (freq > 5725 && freq <= 5825) + return 4; + + return -EINVAL; +} + +bool regulatory_indoor_allowed(void) +{ + return reg_is_indoor; +} + int __init regulatory_init(void) { int err = 0; diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 37c180df34b72a..5e48031ccb9afc 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -25,6 +25,7 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy); int regulatory_hint_user(const char *alpha2, enum nl80211_user_reg_hint_type user_reg_hint_type); +int regulatory_hint_indoor_user(void); void wiphy_regulatory_register(struct wiphy *wiphy); void wiphy_regulatory_deregister(struct wiphy *wiphy); @@ -104,4 +105,21 @@ void regulatory_hint_country_ie(struct wiphy *wiphy, */ void regulatory_hint_disconnect(void); +/** + * cfg80211_get_unii - get the U-NII band for the frequency + * @freq: the frequency for which we want to get the UNII band. + + * Get a value specifying the U-NII band frequency belongs to. + * U-NII bands are defined by the FCC in C.F.R 47 part 15. + * + * Returns -EINVAL if freq is invalid, 0 for UNII-1, 1 for UNII-2A, + * 2 for UNII-2B, 3 for UNII-2C and 4 for UNII-3. + */ +int cfg80211_get_unii(int freq); + +/** + * regulatory_indoor_allowed - is indoor operation allowed + */ +bool regulatory_indoor_allowed(void); + #endif /* __NET_WIRELESS_REG_H */ diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 7d09a712cb1f13..e7329bb6a323c9 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -81,10 +81,10 @@ static void bss_free(struct cfg80211_internal_bss *bss) kfree(bss); } -static inline void bss_ref_get(struct cfg80211_registered_device *dev, +static inline void bss_ref_get(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *bss) { - lockdep_assert_held(&dev->bss_lock); + lockdep_assert_held(&rdev->bss_lock); bss->refcount++; if (bss->pub.hidden_beacon_bss) { @@ -95,10 +95,10 @@ static inline void bss_ref_get(struct cfg80211_registered_device *dev, } } -static inline void bss_ref_put(struct cfg80211_registered_device *dev, +static inline void bss_ref_put(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *bss) { - lockdep_assert_held(&dev->bss_lock); + lockdep_assert_held(&rdev->bss_lock); if (bss->pub.hidden_beacon_bss) { struct cfg80211_internal_bss *hbss; @@ -114,10 +114,10 @@ static inline void bss_ref_put(struct cfg80211_registered_device *dev, bss_free(bss); } -static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *dev, +static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *bss) { - lockdep_assert_held(&dev->bss_lock); + lockdep_assert_held(&rdev->bss_lock); if (!list_empty(&bss->hidden_list)) { /* @@ -134,31 +134,31 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *dev, } list_del_init(&bss->list); - rb_erase(&bss->rbn, &dev->bss_tree); - bss_ref_put(dev, bss); + rb_erase(&bss->rbn, &rdev->bss_tree); + bss_ref_put(rdev, bss); return true; } -static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev, +static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev, unsigned long expire_time) { struct cfg80211_internal_bss *bss, *tmp; bool expired = false; - lockdep_assert_held(&dev->bss_lock); + lockdep_assert_held(&rdev->bss_lock); - list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { + list_for_each_entry_safe(bss, tmp, &rdev->bss_list, list) { if (atomic_read(&bss->hold)) continue; if (!time_after(expire_time, bss->ts)) continue; - if (__cfg80211_unlink_bss(dev, bss)) + if (__cfg80211_unlink_bss(rdev, bss)) expired = true; } if (expired) - dev->bss_generation++; + rdev->bss_generation++; } void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, @@ -238,11 +238,11 @@ void __cfg80211_scan_done(struct work_struct *wk) void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) { trace_cfg80211_scan_done(request, aborted); - WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); + WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req); request->aborted = aborted; request->notified = true; - queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk); + queue_work(cfg80211_wq, &wiphy_to_rdev(request->wiphy)->scan_done_wk); } EXPORT_SYMBOL(cfg80211_scan_done); @@ -278,20 +278,28 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy) { trace_cfg80211_sched_scan_results(wiphy); /* ignore if we're not scanning */ - if (wiphy_to_dev(wiphy)->sched_scan_req) + if (wiphy_to_rdev(wiphy)->sched_scan_req) queue_work(cfg80211_wq, - &wiphy_to_dev(wiphy)->sched_scan_results_wk); + &wiphy_to_rdev(wiphy)->sched_scan_results_wk); } EXPORT_SYMBOL(cfg80211_sched_scan_results); -void cfg80211_sched_scan_stopped(struct wiphy *wiphy) +void cfg80211_sched_scan_stopped_rtnl(struct wiphy *wiphy) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + + ASSERT_RTNL(); trace_cfg80211_sched_scan_stopped(wiphy); - rtnl_lock(); __cfg80211_stop_sched_scan(rdev, true); +} +EXPORT_SYMBOL(cfg80211_sched_scan_stopped_rtnl); + +void cfg80211_sched_scan_stopped(struct wiphy *wiphy) +{ + rtnl_lock(); + cfg80211_sched_scan_stopped_rtnl(wiphy); rtnl_unlock(); } EXPORT_SYMBOL(cfg80211_sched_scan_stopped); @@ -322,21 +330,21 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, return 0; } -void cfg80211_bss_age(struct cfg80211_registered_device *dev, +void cfg80211_bss_age(struct cfg80211_registered_device *rdev, unsigned long age_secs) { struct cfg80211_internal_bss *bss; unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC); - spin_lock_bh(&dev->bss_lock); - list_for_each_entry(bss, &dev->bss_list, list) + spin_lock_bh(&rdev->bss_lock); + list_for_each_entry(bss, &rdev->bss_list, list) bss->ts -= age_jiffies; - spin_unlock_bh(&dev->bss_lock); + spin_unlock_bh(&rdev->bss_lock); } -void cfg80211_bss_expire(struct cfg80211_registered_device *dev) +void cfg80211_bss_expire(struct cfg80211_registered_device *rdev) { - __cfg80211_bss_expire(dev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE); + __cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE); } const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) @@ -526,32 +534,34 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, const u8 *ssid, size_t ssid_len, u16 capa_mask, u16 capa_val) { - struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_internal_bss *bss, *res = NULL; unsigned long now = jiffies; trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask, capa_val); - spin_lock_bh(&dev->bss_lock); + spin_lock_bh(&rdev->bss_lock); - list_for_each_entry(bss, &dev->bss_list, list) { + list_for_each_entry(bss, &rdev->bss_list, list) { if ((bss->pub.capability & capa_mask) != capa_val) continue; if (channel && bss->pub.channel != channel) continue; + if (!is_valid_ether_addr(bss->pub.bssid)) + continue; /* Don't get expired BSS structs */ if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) && !atomic_read(&bss->hold)) continue; if (is_bss(&bss->pub, bssid, ssid, ssid_len)) { res = bss; - bss_ref_get(dev, res); + bss_ref_get(rdev, res); break; } } - spin_unlock_bh(&dev->bss_lock); + spin_unlock_bh(&rdev->bss_lock); if (!res) return NULL; trace_cfg80211_return_bss(&res->pub); @@ -559,10 +569,10 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, } EXPORT_SYMBOL(cfg80211_get_bss); -static void rb_insert_bss(struct cfg80211_registered_device *dev, +static void rb_insert_bss(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *bss) { - struct rb_node **p = &dev->bss_tree.rb_node; + struct rb_node **p = &rdev->bss_tree.rb_node; struct rb_node *parent = NULL; struct cfg80211_internal_bss *tbss; int cmp; @@ -585,15 +595,15 @@ static void rb_insert_bss(struct cfg80211_registered_device *dev, } rb_link_node(&bss->rbn, parent, p); - rb_insert_color(&bss->rbn, &dev->bss_tree); + rb_insert_color(&bss->rbn, &rdev->bss_tree); } static struct cfg80211_internal_bss * -rb_find_bss(struct cfg80211_registered_device *dev, +rb_find_bss(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *res, enum bss_compare_mode mode) { - struct rb_node *n = dev->bss_tree.rb_node; + struct rb_node *n = rdev->bss_tree.rb_node; struct cfg80211_internal_bss *bss; int r; @@ -612,7 +622,7 @@ rb_find_bss(struct cfg80211_registered_device *dev, return NULL; } -static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev, +static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *new) { const struct cfg80211_bss_ies *ies; @@ -642,7 +652,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev, /* This is the bad part ... */ - list_for_each_entry(bss, &dev->bss_list, list) { + list_for_each_entry(bss, &rdev->bss_list, list) { if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid)) continue; if (bss->pub.channel != new->pub.channel) @@ -676,7 +686,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev, /* Returned bss is reference counted and must be cleaned up appropriately. */ static struct cfg80211_internal_bss * -cfg80211_bss_update(struct cfg80211_registered_device *dev, +cfg80211_bss_update(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *tmp, bool signal_valid) { @@ -687,14 +697,14 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, tmp->ts = jiffies; - spin_lock_bh(&dev->bss_lock); + spin_lock_bh(&rdev->bss_lock); if (WARN_ON(!rcu_access_pointer(tmp->pub.ies))) { - spin_unlock_bh(&dev->bss_lock); + spin_unlock_bh(&rdev->bss_lock); return NULL; } - found = rb_find_bss(dev, tmp, BSS_CMP_REGULAR); + found = rb_find_bss(rdev, tmp, BSS_CMP_REGULAR); if (found) { /* Update IEs */ @@ -781,7 +791,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, * is allocated on the stack since it's not needed in the * more common case of an update */ - new = kzalloc(sizeof(*new) + dev->wiphy.bss_priv_size, + new = kzalloc(sizeof(*new) + rdev->wiphy.bss_priv_size, GFP_ATOMIC); if (!new) { ies = (void *)rcu_dereference(tmp->pub.beacon_ies); @@ -797,9 +807,9 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, INIT_LIST_HEAD(&new->hidden_list); if (rcu_access_pointer(tmp->pub.proberesp_ies)) { - hidden = rb_find_bss(dev, tmp, BSS_CMP_HIDE_ZLEN); + hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN); if (!hidden) - hidden = rb_find_bss(dev, tmp, + hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_NUL); if (hidden) { new->pub.hidden_beacon_bss = &hidden->pub; @@ -816,24 +826,24 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, * expensive search for any probe responses that should * be grouped with this beacon for updates ... */ - if (!cfg80211_combine_bsses(dev, new)) { + if (!cfg80211_combine_bsses(rdev, new)) { kfree(new); goto drop; } } - list_add_tail(&new->list, &dev->bss_list); - rb_insert_bss(dev, new); + list_add_tail(&new->list, &rdev->bss_list); + rb_insert_bss(rdev, new); found = new; } - dev->bss_generation++; - bss_ref_get(dev, found); - spin_unlock_bh(&dev->bss_lock); + rdev->bss_generation++; + bss_ref_get(rdev, found); + spin_unlock_bh(&rdev->bss_lock); return found; drop: - spin_unlock_bh(&dev->bss_lock); + spin_unlock_bh(&rdev->bss_lock); return NULL; } @@ -917,7 +927,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, rcu_assign_pointer(tmp.pub.beacon_ies, ies); rcu_assign_pointer(tmp.pub.ies, ies); - res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp, + res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, rx_channel == channel); if (!res) return NULL; @@ -989,7 +999,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy, tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); - res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp, + res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, rx_channel == channel); if (!res) return NULL; @@ -1005,7 +1015,7 @@ EXPORT_SYMBOL(cfg80211_inform_bss_width_frame); void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) { - struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_internal_bss *bss; if (!pub) @@ -1013,15 +1023,15 @@ void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) bss = container_of(pub, struct cfg80211_internal_bss, pub); - spin_lock_bh(&dev->bss_lock); - bss_ref_get(dev, bss); - spin_unlock_bh(&dev->bss_lock); + spin_lock_bh(&rdev->bss_lock); + bss_ref_get(rdev, bss); + spin_unlock_bh(&rdev->bss_lock); } EXPORT_SYMBOL(cfg80211_ref_bss); void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) { - struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_internal_bss *bss; if (!pub) @@ -1029,15 +1039,15 @@ void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) bss = container_of(pub, struct cfg80211_internal_bss, pub); - spin_lock_bh(&dev->bss_lock); - bss_ref_put(dev, bss); - spin_unlock_bh(&dev->bss_lock); + spin_lock_bh(&rdev->bss_lock); + bss_ref_put(rdev, bss); + spin_unlock_bh(&rdev->bss_lock); } EXPORT_SYMBOL(cfg80211_put_bss); void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) { - struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_internal_bss *bss; if (WARN_ON(!pub)) @@ -1045,12 +1055,12 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) bss = container_of(pub, struct cfg80211_internal_bss, pub); - spin_lock_bh(&dev->bss_lock); + spin_lock_bh(&rdev->bss_lock); if (!list_empty(&bss->list)) { - if (__cfg80211_unlink_bss(dev, bss)) - dev->bss_generation++; + if (__cfg80211_unlink_bss(rdev, bss)) + rdev->bss_generation++; } - spin_unlock_bh(&dev->bss_lock); + spin_unlock_bh(&rdev->bss_lock); } EXPORT_SYMBOL(cfg80211_unlink_bss); @@ -1067,7 +1077,7 @@ cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) if (!dev) return ERR_PTR(-ENODEV); if (dev->ieee80211_ptr) - rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); + rdev = wiphy_to_rdev(dev->ieee80211_ptr->wiphy); else rdev = ERR_PTR(-ENODEV); dev_put(dev); @@ -1147,7 +1157,11 @@ int cfg80211_wext_siwscan(struct net_device *dev, int k; int wiphy_freq = wiphy->bands[band]->channels[j].center_freq; for (k = 0; k < wreq->num_channels; k++) { - int wext_freq = cfg80211_wext_freq(wiphy, &wreq->channel_list[k]); + struct iw_freq *freq = + &wreq->channel_list[k]; + int wext_freq = + cfg80211_wext_freq(freq); + if (wext_freq == wiphy_freq) goto wext_freq_found; } @@ -1459,7 +1473,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, } -static int ieee80211_scan_results(struct cfg80211_registered_device *dev, +static int ieee80211_scan_results(struct cfg80211_registered_device *rdev, struct iw_request_info *info, char *buf, size_t len) { @@ -1467,18 +1481,18 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *dev, char *end_buf = buf + len; struct cfg80211_internal_bss *bss; - spin_lock_bh(&dev->bss_lock); - cfg80211_bss_expire(dev); + spin_lock_bh(&rdev->bss_lock); + cfg80211_bss_expire(rdev); - list_for_each_entry(bss, &dev->bss_list, list) { + list_for_each_entry(bss, &rdev->bss_list, list) { if (buf + len - current_ev <= IW_EV_ADDR_LEN) { - spin_unlock_bh(&dev->bss_lock); + spin_unlock_bh(&rdev->bss_lock); return -E2BIG; } - current_ev = ieee80211_bss(&dev->wiphy, info, bss, + current_ev = ieee80211_bss(&rdev->wiphy, info, bss, current_ev, end_buf); } - spin_unlock_bh(&dev->bss_lock); + spin_unlock_bh(&rdev->bss_lock); return current_ev - buf; } diff --git a/net/wireless/sme.c b/net/wireless/sme.c index acdcb4a81817b7..0c0844b585d1e8 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -59,7 +59,7 @@ static void cfg80211_sme_free(struct wireless_dev *wdev) static int cfg80211_conn_scan(struct wireless_dev *wdev) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_scan_request *request; int n_channels, err; @@ -130,7 +130,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) static int cfg80211_conn_do_work(struct wireless_dev *wdev) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_connect_params *params; struct cfg80211_assoc_request req = {}; int err; @@ -234,7 +234,6 @@ void cfg80211_conn_work(struct work_struct *work) NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, false, NULL); - cfg80211_sme_free(wdev); } wdev_unlock(wdev); } @@ -245,7 +244,7 @@ void cfg80211_conn_work(struct work_struct *work) /* Returned bss is reference counted and must be cleaned up appropriately. */ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_bss *bss; u16 capa = WLAN_CAPABILITY_ESS; @@ -275,7 +274,7 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev) static void __cfg80211_sme_scan_done(struct net_device *dev) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_bss *bss; ASSERT_WDEV_LOCK(wdev); @@ -306,7 +305,7 @@ void cfg80211_sme_scan_done(struct net_device *dev) void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len) { struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; u16 status_code = le16_to_cpu(mgmt->u.auth.status_code); @@ -352,7 +351,7 @@ void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len) bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); if (!wdev->conn) return false; @@ -386,7 +385,7 @@ void cfg80211_sme_deauth(struct wireless_dev *wdev) void cfg80211_sme_auth_timeout(struct wireless_dev *wdev) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); if (!wdev->conn) return; @@ -397,7 +396,7 @@ void cfg80211_sme_auth_timeout(struct wireless_dev *wdev) void cfg80211_sme_disassoc(struct wireless_dev *wdev) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); if (!wdev->conn) return; @@ -408,7 +407,7 @@ void cfg80211_sme_disassoc(struct wireless_dev *wdev) void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); if (!wdev->conn) return; @@ -421,7 +420,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, struct cfg80211_connect_params *connect, const u8 *prev_bssid) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_bss *bss; int err; @@ -468,7 +467,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, } wdev->conn->params.ssid = wdev->ssid; - wdev->conn->params.ssid_len = connect->ssid_len; + wdev->conn->params.ssid_len = wdev->ssid_len; /* see if we have the bss already */ bss = cfg80211_get_conn_bss(wdev); @@ -480,7 +479,6 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, /* we're good if we have a matching bss struct */ if (bss) { - wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; err = cfg80211_conn_do_work(wdev); cfg80211_put_bss(wdev->wiphy, bss); } else { @@ -506,7 +504,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, static int cfg80211_sme_disconnect(struct wireless_dev *wdev, u16 reason) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); int err; if (!wdev->conn) @@ -594,7 +592,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, return; } - nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, + nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, status, GFP_KERNEL); @@ -625,7 +623,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, #endif if (!bss && (status == WLAN_STATUS_SUCCESS)) { - WARN_ON_ONCE(!wiphy_to_dev(wdev->wiphy)->ops->connect); + WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, wdev->ssid, wdev->ssid_len, WLAN_CAPABILITY_ESS, @@ -648,6 +646,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, cfg80211_unhold_bss(bss_from_pub(bss)); cfg80211_put_bss(wdev->wiphy, bss); } + cfg80211_sme_free(wdev); return; } @@ -687,7 +686,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, u16 status, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_event *ev; unsigned long flags; @@ -742,7 +741,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, cfg80211_hold_bss(bss_from_pub(bss)); wdev->current_bss = bss_from_pub(bss); - nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bss->bssid, + nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy), + wdev->netdev, bss->bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, GFP_KERNEL); @@ -801,7 +801,7 @@ void cfg80211_roamed_bss(struct net_device *dev, size_t resp_ie_len, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_event *ev; unsigned long flags; @@ -834,7 +834,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, size_t ie_len, u16 reason, bool from_ap) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); int i; #ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; @@ -880,7 +880,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, u8 *ie, size_t ie_len, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_event *ev; unsigned long flags; diff --git a/net/wireless/trace.h b/net/wireless/trace.h index aabccf13e07b68..f3c13ff4d04c87 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1919,6 +1919,24 @@ TRACE_EVENT(rdev_set_qos_map, WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->num_des) ); +TRACE_EVENT(rdev_set_ap_chanwidth, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_chan_def *chandef), + TP_ARGS(wiphy, netdev, chandef), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + CHAN_DEF_ENTRY + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + CHAN_DEF_ASSIGN(chandef); + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG) +); + /************************************************************* * cfg80211 exported functions traces * *************************************************************/ @@ -2193,18 +2211,21 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify, ); TRACE_EVENT(cfg80211_reg_can_beacon, - TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), - TP_ARGS(wiphy, chandef), + TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, + enum nl80211_iftype iftype), + TP_ARGS(wiphy, chandef, iftype), TP_STRUCT__entry( WIPHY_ENTRY CHAN_DEF_ENTRY + __field(enum nl80211_iftype, iftype) ), TP_fast_assign( WIPHY_ASSIGN; CHAN_DEF_ASSIGN(chandef); + __entry->iftype = iftype; ), - TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, - WIPHY_PR_ARG, CHAN_DEF_PR_ARG) + TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d", + WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype) ); TRACE_EVENT(cfg80211_chandef_dfs_required, diff --git a/net/wireless/util.c b/net/wireless/util.c index e5872ff2c27ca8..7c47fa07b276f9 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -770,7 +770,7 @@ EXPORT_SYMBOL(ieee80211_bss_get_ie); void cfg80211_upload_connect_keys(struct wireless_dev *wdev) { - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct net_device *dev = wdev->netdev; int i; @@ -888,11 +888,6 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, return -EBUSY; if (ntype != otype && netif_running(dev)) { - err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, - ntype); - if (err) - return err; - dev->ieee80211_ptr->use_4addr = false; dev->ieee80211_ptr->mesh_id_up_len = 0; wdev_lock(dev->ieee80211_ptr); @@ -1268,6 +1263,106 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, return res; } +int cfg80211_iter_combinations(struct wiphy *wiphy, + const int num_different_channels, + const u8 radar_detect, + const int iftype_num[NUM_NL80211_IFTYPES], + void (*iter)(const struct ieee80211_iface_combination *c, + void *data), + void *data) +{ + int i, j, iftype; + int num_interfaces = 0; + u32 used_iftypes = 0; + + for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { + num_interfaces += iftype_num[iftype]; + if (iftype_num[iftype] > 0 && + !(wiphy->software_iftypes & BIT(iftype))) + used_iftypes |= BIT(iftype); + } + + for (i = 0; i < wiphy->n_iface_combinations; i++) { + const struct ieee80211_iface_combination *c; + struct ieee80211_iface_limit *limits; + u32 all_iftypes = 0; + + c = &wiphy->iface_combinations[i]; + + if (num_interfaces > c->max_interfaces) + continue; + if (num_different_channels > c->num_different_channels) + continue; + + limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, + GFP_KERNEL); + if (!limits) + return -ENOMEM; + + for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { + if (wiphy->software_iftypes & BIT(iftype)) + continue; + for (j = 0; j < c->n_limits; j++) { + all_iftypes |= limits[j].types; + if (!(limits[j].types & BIT(iftype))) + continue; + if (limits[j].max < iftype_num[iftype]) + goto cont; + limits[j].max -= iftype_num[iftype]; + } + } + + if (radar_detect != (c->radar_detect_widths & radar_detect)) + goto cont; + + /* Finally check that all iftypes that we're currently + * using are actually part of this combination. If they + * aren't then we can't use this combination and have + * to continue to the next. + */ + if ((all_iftypes & used_iftypes) != used_iftypes) + goto cont; + + /* This combination covered all interface types and + * supported the requested numbers, so we're good. + */ + + (*iter)(c, data); + cont: + kfree(limits); + } + + return 0; +} +EXPORT_SYMBOL(cfg80211_iter_combinations); + +static void +cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c, + void *data) +{ + int *num = data; + (*num)++; +} + +int cfg80211_check_combinations(struct wiphy *wiphy, + const int num_different_channels, + const u8 radar_detect, + const int iftype_num[NUM_NL80211_IFTYPES]) +{ + int err, num = 0; + + err = cfg80211_iter_combinations(wiphy, num_different_channels, + radar_detect, iftype_num, + cfg80211_iter_sum_ifcombs, &num); + if (err) + return err; + if (num == 0) + return -EBUSY; + + return 0; +} +EXPORT_SYMBOL(cfg80211_check_combinations); + int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, enum nl80211_iftype iftype, @@ -1276,7 +1371,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, u8 radar_detect) { struct wireless_dev *wdev_iter; - u32 used_iftypes = BIT(iftype); int num[NUM_NL80211_IFTYPES]; struct ieee80211_channel *used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS]; @@ -1284,7 +1378,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, enum cfg80211_chan_mode chmode; int num_different_channels = 0; int total = 1; - int i, j; + int i; ASSERT_RTNL(); @@ -1306,6 +1400,11 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, num[iftype] = 1; + /* TODO: We'll probably not need this anymore, since this + * should only be called with CHAN_MODE_UNDEFINED. There are + * still a couple of pending calls where other chanmodes are + * used, but we should get rid of them. + */ switch (chanmode) { case CHAN_MODE_UNDEFINED: break; @@ -1369,65 +1468,13 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, num[wdev_iter->iftype]++; total++; - used_iftypes |= BIT(wdev_iter->iftype); } if (total == 1 && !radar_detect) return 0; - for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { - const struct ieee80211_iface_combination *c; - struct ieee80211_iface_limit *limits; - u32 all_iftypes = 0; - - c = &rdev->wiphy.iface_combinations[i]; - - if (total > c->max_interfaces) - continue; - if (num_different_channels > c->num_different_channels) - continue; - - limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, - GFP_KERNEL); - if (!limits) - return -ENOMEM; - - for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { - if (rdev->wiphy.software_iftypes & BIT(iftype)) - continue; - for (j = 0; j < c->n_limits; j++) { - all_iftypes |= limits[j].types; - if (!(limits[j].types & BIT(iftype))) - continue; - if (limits[j].max < num[iftype]) - goto cont; - limits[j].max -= num[iftype]; - } - } - - if (radar_detect && !(c->radar_detect_widths & radar_detect)) - goto cont; - - /* - * Finally check that all iftypes that we're currently - * using are actually part of this combination. If they - * aren't then we can't use this combination and have - * to continue to the next. - */ - if ((all_iftypes & used_iftypes) != used_iftypes) - goto cont; - - /* - * This combination covered all interface types and - * supported the requested numbers, so we're good. - */ - kfree(limits); - return 0; - cont: - kfree(limits); - } - - return -EBUSY; + return cfg80211_check_combinations(&rdev->wiphy, num_different_channels, + radar_detect, num); } int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 5661a54ac7ee4e..11120bb1416250 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -73,7 +73,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, struct vif_params vifparams; enum nl80211_iftype type; - rdev = wiphy_to_dev(wdev->wiphy); + rdev = wiphy_to_rdev(wdev->wiphy); switch (*mode) { case IW_MODE_INFRA: @@ -253,12 +253,12 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); /** * cfg80211_wext_freq - get wext frequency for non-"auto" - * @wiphy: the wiphy + * @dev: the net device * @freq: the wext freq encoding * * Returns a frequency, or a negative error code, or 0 for auto. */ -int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq) +int cfg80211_wext_freq(struct iw_freq *freq) { /* * Parse frequency - return 0 for auto and @@ -286,7 +286,7 @@ int cfg80211_wext_siwrts(struct net_device *dev, struct iw_param *rts, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); u32 orts = wdev->wiphy->rts_threshold; int err; @@ -324,7 +324,7 @@ int cfg80211_wext_siwfrag(struct net_device *dev, struct iw_param *frag, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); u32 ofrag = wdev->wiphy->frag_threshold; int err; @@ -364,7 +364,7 @@ static int cfg80211_wext_siwretry(struct net_device *dev, struct iw_param *retry, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); u32 changed = 0; u8 olong = wdev->wiphy->retry_long; u8 oshort = wdev->wiphy->retry_short; @@ -587,7 +587,7 @@ static int cfg80211_wext_siwencode(struct net_device *dev, struct iw_point *erq, char *keybuf) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); int idx, err; bool remove = false; struct key_params params; @@ -647,7 +647,7 @@ static int cfg80211_wext_siwencodeext(struct net_device *dev, struct iw_point *erq, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; const u8 *addr; int idx; @@ -775,7 +775,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, struct iw_freq *wextfreq, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_chan_def chandef = { .width = NL80211_CHAN_WIDTH_20_NOHT, }; @@ -787,7 +787,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, case NL80211_IFTYPE_ADHOC: return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra); case NL80211_IFTYPE_MONITOR: - freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); + freq = cfg80211_wext_freq(wextfreq); if (freq < 0) return freq; if (freq == 0) @@ -798,7 +798,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, return -EINVAL; return cfg80211_set_monitor_channel(rdev, &chandef); case NL80211_IFTYPE_MESH_POINT: - freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); + freq = cfg80211_wext_freq(wextfreq); if (freq < 0) return freq; if (freq == 0) @@ -818,7 +818,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, struct iw_freq *freq, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_chan_def chandef; int ret; @@ -847,7 +847,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev, union iwreq_data *data, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); enum nl80211_tx_power_setting type; int dbm = 0; @@ -899,7 +899,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev, union iwreq_data *data, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); int err, val; if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) @@ -1119,7 +1119,7 @@ static int cfg80211_wext_siwpower(struct net_device *dev, struct iw_param *wrq, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); bool ps = wdev->ps; int timeout = wdev->ps_timeout; int err; @@ -1177,7 +1177,7 @@ static int cfg80211_wds_wext_siwap(struct net_device *dev, struct sockaddr *addr, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); int err; if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS)) @@ -1221,7 +1221,7 @@ static int cfg80211_wext_siwrate(struct net_device *dev, struct iw_param *rate, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_bitrate_mask mask; u32 fixed, maxrate; struct ieee80211_supported_band *sband; @@ -1272,7 +1272,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev, struct iw_param *rate, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); /* we are under RTNL - globally locked - so can use a static struct */ static struct station_info sinfo; u8 addr[ETH_ALEN]; @@ -1310,7 +1310,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev, static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); /* we are under RTNL - globally locked - so can use static structs */ static struct iw_statistics wstats; static struct station_info sinfo; @@ -1449,7 +1449,7 @@ static int cfg80211_wext_siwpmksa(struct net_device *dev, struct iw_point *data, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_pmksa cfg_pmksa; struct iw_pmksa *pmksa = (struct iw_pmksa *)extra; diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h index 5d766b0118e819..ebcacca2f73194 100644 --- a/net/wireless/wext-compat.h +++ b/net/wireless/wext-compat.h @@ -50,7 +50,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev, struct iw_point *data, char *extra); -int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); +int cfg80211_wext_freq(struct iw_freq *freq); extern const struct iw_handler_def cfg80211_wext_handler; diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 86c331a65664a7..c7e5c8eb4f2470 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -67,7 +67,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, struct iw_freq *wextfreq, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct ieee80211_channel *chan = NULL; int err, freq; @@ -75,7 +75,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; - freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); + freq = cfg80211_wext_freq(wextfreq); if (freq < 0) return freq; @@ -169,7 +169,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, struct iw_point *data, char *ssid) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); size_t len = data->length; int err; @@ -260,7 +260,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, struct sockaddr *ap_addr, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); u8 *bssid = ap_addr->sa_data; int err; @@ -333,7 +333,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev, struct iw_point *data, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); u8 *ie = extra; int ie_len = data->length, err; @@ -390,7 +390,7 @@ int cfg80211_wext_siwmlme(struct net_device *dev, if (!wdev) return -EOPNOTSUPP; - rdev = wiphy_to_dev(wdev->wiphy); + rdev = wiphy_to_rdev(wdev->wiphy); if (wdev->iftype != NL80211_IFTYPE_STATION) return -EINVAL; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index c08fbd11ceff52..a8ef5108e0d86c 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -769,7 +769,7 @@ EXPORT_SYMBOL(xfrm_policy_byid); #ifdef CONFIG_SECURITY_NETWORK_XFRM static inline int -xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audit_info) +xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid) { int dir, err = 0; @@ -783,10 +783,7 @@ xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audi continue; err = security_xfrm_policy_delete(pol->security); if (err) { - xfrm_audit_policy_delete(pol, 0, - audit_info->loginuid, - audit_info->sessionid, - audit_info->secid); + xfrm_audit_policy_delete(pol, 0, task_valid); return err; } } @@ -800,9 +797,7 @@ xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audi pol->security); if (err) { xfrm_audit_policy_delete(pol, 0, - audit_info->loginuid, - audit_info->sessionid, - audit_info->secid); + task_valid); return err; } } @@ -812,19 +807,19 @@ xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audi } #else static inline int -xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audit_info) +xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid) { return 0; } #endif -int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) +int xfrm_policy_flush(struct net *net, u8 type, bool task_valid) { int dir, err = 0, cnt = 0; write_lock_bh(&net->xfrm.xfrm_policy_lock); - err = xfrm_policy_flush_secctx_check(net, type, audit_info); + err = xfrm_policy_flush_secctx_check(net, type, task_valid); if (err) goto out; @@ -841,9 +836,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) write_unlock_bh(&net->xfrm.xfrm_policy_lock); cnt++; - xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, - audit_info->sessionid, - audit_info->secid); + xfrm_audit_policy_delete(pol, 1, task_valid); xfrm_policy_kill(pol); @@ -862,10 +855,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) write_unlock_bh(&net->xfrm.xfrm_policy_lock); cnt++; - xfrm_audit_policy_delete(pol, 1, - audit_info->loginuid, - audit_info->sessionid, - audit_info->secid); + xfrm_audit_policy_delete(pol, 1, task_valid); xfrm_policy_kill(pol); write_lock_bh(&net->xfrm.xfrm_policy_lock); @@ -2783,21 +2773,19 @@ static struct notifier_block xfrm_dev_notifier = { static int __net_init xfrm_statistics_init(struct net *net) { int rv; - - if (snmp_mib_init((void __percpu **)net->mib.xfrm_statistics, - sizeof(struct linux_xfrm_mib), - __alignof__(struct linux_xfrm_mib)) < 0) + net->mib.xfrm_statistics = alloc_percpu(struct linux_xfrm_mib); + if (!net->mib.xfrm_statistics) return -ENOMEM; rv = xfrm_proc_init(net); if (rv < 0) - snmp_mib_free((void __percpu **)net->mib.xfrm_statistics); + free_percpu(net->mib.xfrm_statistics); return rv; } static void xfrm_statistics_fini(struct net *net) { xfrm_proc_fini(net); - snmp_mib_free((void __percpu **)net->mib.xfrm_statistics); + free_percpu(net->mib.xfrm_statistics); } #else static int __net_init xfrm_statistics_init(struct net *net) @@ -2862,21 +2850,14 @@ static int __net_init xfrm_policy_init(struct net *net) static void xfrm_policy_fini(struct net *net) { - struct xfrm_audit audit_info; unsigned int sz; int dir; flush_work(&net->xfrm.policy_hash_work); #ifdef CONFIG_XFRM_SUB_POLICY - audit_info.loginuid = INVALID_UID; - audit_info.sessionid = (unsigned int)-1; - audit_info.secid = 0; - xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, &audit_info); + xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, false); #endif - audit_info.loginuid = INVALID_UID; - audit_info.sessionid = (unsigned int)-1; - audit_info.secid = 0; - xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); + xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false); WARN_ON(!list_empty(&net->xfrm.policy_all)); @@ -2991,15 +2972,14 @@ static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp, } } -void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, - kuid_t auid, unsigned int sessionid, u32 secid) +void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid) { struct audit_buffer *audit_buf; audit_buf = xfrm_audit_start("SPD-add"); if (audit_buf == NULL) return; - xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf); + xfrm_audit_helper_usrinfo(task_valid, audit_buf); audit_log_format(audit_buf, " res=%u", result); xfrm_audit_common_policyinfo(xp, audit_buf); audit_log_end(audit_buf); @@ -3007,14 +2987,14 @@ void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, EXPORT_SYMBOL_GPL(xfrm_audit_policy_add); void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, - kuid_t auid, unsigned int sessionid, u32 secid) + bool task_valid) { struct audit_buffer *audit_buf; audit_buf = xfrm_audit_start("SPD-delete"); if (audit_buf == NULL) return; - xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf); + xfrm_audit_helper_usrinfo(task_valid, audit_buf); audit_log_format(audit_buf, " res=%u", result); xfrm_audit_common_policyinfo(xp, audit_buf); audit_log_end(audit_buf); diff --git a/net/xfrm/xfrm_proc.c b/net/xfrm/xfrm_proc.c index fc5abd0b456f3a..9c4fbd8935f48e 100644 --- a/net/xfrm/xfrm_proc.c +++ b/net/xfrm/xfrm_proc.c @@ -54,8 +54,7 @@ static int xfrm_statistics_seq_show(struct seq_file *seq, void *v) int i; for (i = 0; xfrm_mib_list[i].name; i++) seq_printf(seq, "%-24s\t%lu\n", xfrm_mib_list[i].name, - snmp_fold_field((void __percpu **) - net->mib.xfrm_statistics, + snmp_fold_field(net->mib.xfrm_statistics, xfrm_mib_list[i].entry)); return 0; } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 8e9c781a6bbaab..0ab54134bb40b8 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -463,9 +463,7 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) if (!err) km_state_expired(x, 1, 0); - xfrm_audit_state_delete(x, err ? 0 : 1, - audit_get_loginuid(current), - audit_get_sessionid(current), 0); + xfrm_audit_state_delete(x, err ? 0 : 1, true); out: spin_unlock(&x->lock); @@ -562,7 +560,7 @@ EXPORT_SYMBOL(xfrm_state_delete); #ifdef CONFIG_SECURITY_NETWORK_XFRM static inline int -xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audit_info) +xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) { int i, err = 0; @@ -572,10 +570,7 @@ xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audi hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { if (xfrm_id_proto_match(x->id.proto, proto) && (err = security_xfrm_state_delete(x)) != 0) { - xfrm_audit_state_delete(x, 0, - audit_info->loginuid, - audit_info->sessionid, - audit_info->secid); + xfrm_audit_state_delete(x, 0, task_valid); return err; } } @@ -585,18 +580,18 @@ xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audi } #else static inline int -xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audit_info) +xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) { return 0; } #endif -int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) +int xfrm_state_flush(struct net *net, u8 proto, bool task_valid) { int i, err = 0, cnt = 0; spin_lock_bh(&net->xfrm.xfrm_state_lock); - err = xfrm_state_flush_secctx_check(net, proto, audit_info); + err = xfrm_state_flush_secctx_check(net, proto, task_valid); if (err) goto out; @@ -612,9 +607,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) err = xfrm_state_delete(x); xfrm_audit_state_delete(x, err ? 0 : 1, - audit_info->loginuid, - audit_info->sessionid, - audit_info->secid); + task_valid); xfrm_state_put(x); if (!err) cnt++; @@ -2128,14 +2121,10 @@ int __net_init xfrm_state_init(struct net *net) void xfrm_state_fini(struct net *net) { - struct xfrm_audit audit_info; unsigned int sz; flush_work(&net->xfrm.state_hash_work); - audit_info.loginuid = INVALID_UID; - audit_info.sessionid = (unsigned int)-1; - audit_info.secid = 0; - xfrm_state_flush(net, IPSEC_PROTO_ANY, &audit_info); + xfrm_state_flush(net, IPSEC_PROTO_ANY, false); flush_work(&net->xfrm.state_gc_work); WARN_ON(!list_empty(&net->xfrm.state_all)); @@ -2198,30 +2187,28 @@ static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, } } -void xfrm_audit_state_add(struct xfrm_state *x, int result, - kuid_t auid, unsigned int sessionid, u32 secid) +void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid) { struct audit_buffer *audit_buf; audit_buf = xfrm_audit_start("SAD-add"); if (audit_buf == NULL) return; - xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf); + xfrm_audit_helper_usrinfo(task_valid, audit_buf); xfrm_audit_helper_sainfo(x, audit_buf); audit_log_format(audit_buf, " res=%u", result); audit_log_end(audit_buf); } EXPORT_SYMBOL_GPL(xfrm_audit_state_add); -void xfrm_audit_state_delete(struct xfrm_state *x, int result, - kuid_t auid, unsigned int sessionid, u32 secid) +void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid) { struct audit_buffer *audit_buf; audit_buf = xfrm_audit_start("SAD-delete"); if (audit_buf == NULL) return; - xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf); + xfrm_audit_helper_usrinfo(task_valid, audit_buf); xfrm_audit_helper_sainfo(x, audit_buf); audit_log_format(audit_buf, " res=%u", result); audit_log_end(audit_buf); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 51398ae6cda850..fd9a16a6d1de36 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -597,9 +597,6 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, struct xfrm_state *x; int err; struct km_event c; - kuid_t loginuid = audit_get_loginuid(current); - unsigned int sessionid = audit_get_sessionid(current); - u32 sid; err = verify_newsa_info(p, attrs); if (err) @@ -615,8 +612,7 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, else err = xfrm_state_update(x); - security_task_getsecid(current, &sid); - xfrm_audit_state_add(x, err ? 0 : 1, loginuid, sessionid, sid); + xfrm_audit_state_add(x, err ? 0 : 1, true); if (err < 0) { x->km.state = XFRM_STATE_DEAD; @@ -676,9 +672,6 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, int err = -ESRCH; struct km_event c; struct xfrm_usersa_id *p = nlmsg_data(nlh); - kuid_t loginuid = audit_get_loginuid(current); - unsigned int sessionid = audit_get_sessionid(current); - u32 sid; x = xfrm_user_state_lookup(net, p, attrs, &err); if (x == NULL) @@ -703,8 +696,7 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, km_state_notify(x, &c); out: - security_task_getsecid(current, &sid); - xfrm_audit_state_delete(x, err ? 0 : 1, loginuid, sessionid, sid); + xfrm_audit_state_delete(x, err ? 0 : 1, true); xfrm_state_put(x); return err; } @@ -1414,9 +1406,6 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, struct km_event c; int err; int excl; - kuid_t loginuid = audit_get_loginuid(current); - unsigned int sessionid = audit_get_sessionid(current); - u32 sid; err = verify_newpolicy_info(p); if (err) @@ -1435,8 +1424,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, * a type XFRM_MSG_UPDPOLICY - JHS */ excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; err = xfrm_policy_insert(p->dir, xp, excl); - security_task_getsecid(current, &sid); - xfrm_audit_policy_add(xp, err ? 0 : 1, loginuid, sessionid, sid); + xfrm_audit_policy_add(xp, err ? 0 : 1, true); if (err) { security_xfrm_policy_free(xp->security); @@ -1673,13 +1661,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, NETLINK_CB(skb).portid); } } else { - kuid_t loginuid = audit_get_loginuid(current); - unsigned int sessionid = audit_get_sessionid(current); - u32 sid; - - security_task_getsecid(current, &sid); - xfrm_audit_policy_delete(xp, err ? 0 : 1, loginuid, sessionid, - sid); + xfrm_audit_policy_delete(xp, err ? 0 : 1, true); if (err != 0) goto out; @@ -1704,13 +1686,9 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, struct net *net = sock_net(skb->sk); struct km_event c; struct xfrm_usersa_flush *p = nlmsg_data(nlh); - struct xfrm_audit audit_info; int err; - audit_info.loginuid = audit_get_loginuid(current); - audit_info.sessionid = audit_get_sessionid(current); - security_task_getsecid(current, &audit_info.secid); - err = xfrm_state_flush(net, p->proto, &audit_info); + err = xfrm_state_flush(net, p->proto, true); if (err) { if (err == -ESRCH) /* empty table */ return 0; @@ -1894,16 +1872,12 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, struct km_event c; u8 type = XFRM_POLICY_TYPE_MAIN; int err; - struct xfrm_audit audit_info; err = copy_from_user_policy_type(&type, attrs); if (err) return err; - audit_info.loginuid = audit_get_loginuid(current); - audit_info.sessionid = audit_get_sessionid(current); - security_task_getsecid(current, &audit_info.secid); - err = xfrm_policy_flush(net, type, &audit_info); + err = xfrm_policy_flush(net, type, true); if (err) { if (err == -ESRCH) /* empty table */ return 0; @@ -1969,14 +1943,8 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, err = 0; if (up->hard) { - kuid_t loginuid = audit_get_loginuid(current); - unsigned int sessionid = audit_get_sessionid(current); - u32 sid; - - security_task_getsecid(current, &sid); xfrm_policy_delete(xp, p->dir); - xfrm_audit_policy_delete(xp, 1, loginuid, sessionid, sid); - + xfrm_audit_policy_delete(xp, 1, true); } else { // reset the timers here? WARN(1, "Dont know what to do with soft policy expire\n"); @@ -2012,13 +1980,8 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, km_state_expired(x, ue->hard, nlh->nlmsg_pid); if (ue->hard) { - kuid_t loginuid = audit_get_loginuid(current); - unsigned int sessionid = audit_get_sessionid(current); - u32 sid; - - security_task_getsecid(current, &sid); __xfrm_state_delete(x); - xfrm_audit_state_delete(x, 1, loginuid, sessionid, sid); + xfrm_audit_state_delete(x, 1, true); } err = 0; out: diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 003bc263105ae3..bf3e6778cd71ad 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -50,67 +50,6 @@ ifeq ($(KBUILD_NOPEDANTIC),) endif endif -# -# make W=... settings -# -# W=1 - warnings that may be relevant and does not occur too often -# W=2 - warnings that occur quite often but may still be relevant -# W=3 - the more obscure warnings, can most likely be ignored -# -# $(call cc-option, -W...) handles gcc -W.. options which -# are not supported by all versions of the compiler -ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS -warning- := $(empty) - -warning-1 := -Wextra -Wunused -Wno-unused-parameter -warning-1 += -Wmissing-declarations -warning-1 += -Wmissing-format-attribute -warning-1 += $(call cc-option, -Wmissing-prototypes) -warning-1 += -Wold-style-definition -warning-1 += $(call cc-option, -Wmissing-include-dirs) -warning-1 += $(call cc-option, -Wunused-but-set-variable) -warning-1 += $(call cc-disable-warning, missing-field-initializers) - -# Clang -warning-1 += $(call cc-disable-warning, initializer-overrides) -warning-1 += $(call cc-disable-warning, unused-value) -warning-1 += $(call cc-disable-warning, format) -warning-1 += $(call cc-disable-warning, unknown-warning-option) -warning-1 += $(call cc-disable-warning, sign-compare) -warning-1 += $(call cc-disable-warning, format-zero-length) -warning-1 += $(call cc-disable-warning, uninitialized) -warning-1 += $(call cc-option, -fcatch-undefined-behavior) - -warning-2 := -Waggregate-return -warning-2 += -Wcast-align -warning-2 += -Wdisabled-optimization -warning-2 += -Wnested-externs -warning-2 += -Wshadow -warning-2 += $(call cc-option, -Wlogical-op) -warning-2 += $(call cc-option, -Wmissing-field-initializers) - -warning-3 := -Wbad-function-cast -warning-3 += -Wcast-qual -warning-3 += -Wconversion -warning-3 += -Wpacked -warning-3 += -Wpadded -warning-3 += -Wpointer-arith -warning-3 += -Wredundant-decls -warning-3 += -Wswitch-default -warning-3 += $(call cc-option, -Wpacked-bitfield-compat) -warning-3 += $(call cc-option, -Wvla) - -warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) -warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) -warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) - -ifeq ("$(strip $(warning))","") - $(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown) -endif - -KBUILD_CFLAGS += $(warning) -endif - include scripts/Makefile.lib ifdef host-progs @@ -342,7 +281,7 @@ $(real-objs-m) : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE) $(real-objs-m:.o=.s): modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE) quiet_cmd_as_s_S = CPP $(quiet_modtag) $@ -cmd_as_s_S = $(CPP) $(a_flags) -o $@ $< +cmd_as_s_S = $(CPP) $(a_flags) -o $@ $< $(obj)/%.s: $(src)/%.S FORCE $(call if_changed_dep,as_s_S) @@ -436,7 +375,7 @@ link_multi_deps = \ $(filter $(addprefix $(obj)/, \ $($(subst $(obj)/,,$(@:.o=-objs))) \ $($(subst $(obj)/,,$(@:.o=-y)))), $^) - + quiet_cmd_link_multi-y = LD $@ cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis) diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn new file mode 100644 index 00000000000000..65643506c71c7c --- /dev/null +++ b/scripts/Makefile.extrawarn @@ -0,0 +1,67 @@ +# ========================================================================== +# +# make W=... settings +# +# W=1 - warnings that may be relevant and does not occur too often +# W=2 - warnings that occur quite often but may still be relevant +# W=3 - the more obscure warnings, can most likely be ignored +# +# $(call cc-option, -W...) handles gcc -W.. options which +# are not supported by all versions of the compiler +# ========================================================================== + +ifeq ("$(origin W)", "command line") + export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W) +endif + +ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS +warning- := $(empty) + +warning-1 := -Wextra -Wunused -Wno-unused-parameter +warning-1 += -Wmissing-declarations +warning-1 += -Wmissing-format-attribute +warning-1 += $(call cc-option, -Wmissing-prototypes) +warning-1 += -Wold-style-definition +warning-1 += $(call cc-option, -Wmissing-include-dirs) +warning-1 += $(call cc-option, -Wunused-but-set-variable) +warning-1 += $(call cc-disable-warning, missing-field-initializers) + +# Clang +warning-1 += $(call cc-disable-warning, initializer-overrides) +warning-1 += $(call cc-disable-warning, unused-value) +warning-1 += $(call cc-disable-warning, format) +warning-1 += $(call cc-disable-warning, unknown-warning-option) +warning-1 += $(call cc-disable-warning, sign-compare) +warning-1 += $(call cc-disable-warning, format-zero-length) +warning-1 += $(call cc-disable-warning, uninitialized) +warning-1 += $(call cc-option, -fcatch-undefined-behavior) + +warning-2 := -Waggregate-return +warning-2 += -Wcast-align +warning-2 += -Wdisabled-optimization +warning-2 += -Wnested-externs +warning-2 += -Wshadow +warning-2 += $(call cc-option, -Wlogical-op) +warning-2 += $(call cc-option, -Wmissing-field-initializers) + +warning-3 := -Wbad-function-cast +warning-3 += -Wcast-qual +warning-3 += -Wconversion +warning-3 += -Wpacked +warning-3 += -Wpadded +warning-3 += -Wpointer-arith +warning-3 += -Wredundant-decls +warning-3 += -Wswitch-default +warning-3 += $(call cc-option, -Wpacked-bitfield-compat) +warning-3 += $(call cc-option, -Wvla) + +warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) +warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) +warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) + +ifeq ("$(strip $(warning))","") + $(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown) +endif + +KBUILD_CFLAGS += $(warning) +endif diff --git a/scripts/Makefile.fwinst b/scripts/Makefile.fwinst index 4d908d16c035c4..2c1d69c4345caf 100644 --- a/scripts/Makefile.fwinst +++ b/scripts/Makefile.fwinst @@ -18,7 +18,7 @@ include $(srctree)/$(obj)/Makefile include scripts/Makefile.host mod-fw := $(fw-shipped-m) -# If CONFIG_FIRMWARE_IN_KERNEL isn't set, then install the +# If CONFIG_FIRMWARE_IN_KERNEL isn't set, then install the # firmware for in-kernel drivers too. ifndef CONFIG_FIRMWARE_IN_KERNEL mod-fw += $(fw-shipped-y) diff --git a/scripts/Makefile.host b/scripts/Makefile.host index 1ac414fd503003..0f0d6ba87e42f5 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -166,5 +166,5 @@ $(host-cshlib): $(obj)/%: $(host-cshobjs) FORCE $(call if_changed,host-cshlib) targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\ - $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) + $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 6a5b0decb79722..260bf8acfce96c 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -27,7 +27,7 @@ lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m))) # --------------------------------------------------------------------------- # o if we encounter foo/ in $(obj-y), replace it by foo/built-in.o # and add the directory to the list of dirs to descend into: $(subdir-y) -# o if we encounter foo/ in $(obj-m), remove it from $(obj-m) +# o if we encounter foo/ in $(obj-m), remove it from $(obj-m) # and add the directory to the list of dirs to descend into: $(subdir-m) # Determine modorder. @@ -46,7 +46,7 @@ obj-m := $(filter-out %/, $(obj-m)) subdir-ym := $(sort $(subdir-y) $(subdir-m)) -# if $(foo-objs) exists, foo.o is a composite object +# if $(foo-objs) exists, foo.o is a composite object multi-used-y := $(sort $(foreach m,$(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m)))) multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m)))) multi-used := $(multi-used-y) $(multi-used-m) @@ -91,7 +91,7 @@ obj-dirs := $(addprefix $(obj)/,$(obj-dirs)) # These flags are needed for modversions and compiling, so we define them here # already -# $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will +# $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will # end up in (or would, if it gets compiled in) # Note: Files that end up in two or more modules are compiled without the # KBUILD_MODNAME definition. The reason is that any made-up name would @@ -212,7 +212,7 @@ $(obj)/%: $(src)/%_shipped # Commands useful for building a boot image # =========================================================================== -# +# # Use as following: # # target: source(s) FORCE @@ -226,7 +226,7 @@ $(obj)/%: $(src)/%_shipped quiet_cmd_ld = LD $@ cmd_ld = $(LD) $(LDFLAGS) $(ldflags-y) $(LDFLAGS_$(@F)) \ - $(filter-out FORCE,$^) -o $@ + $(filter-out FORCE,$^) -o $@ # Objcopy # --------------------------------------------------------------------------- diff --git a/scripts/Makefile.lto b/scripts/Makefile.lto new file mode 100644 index 00000000000000..b8e9e4836f4b55 --- /dev/null +++ b/scripts/Makefile.lto @@ -0,0 +1,84 @@ +# +# Support for gcc link time optimization +# + +DISABLE_LTO := +LTO_CFLAGS := + +export DISABLE_LTO +export LTO_CFLAGS + +ifdef CONFIG_LTO +# 4.7 works mostly, but it sometimes loses symbols on large builds +# This can be worked around by marking those symbols visible, +# but that is fairly ugly and the problem is gone with 4.8 +# So only allow it with 4.8 for now. +ifeq ($(call cc-ifversion, -ge, 0408,y),y) +ifneq ($(call cc-option,${LTO_CFLAGS},n),n) +# We need HJ Lu's Linux binutils because mainline binutils does not +# support mixing assembler and LTO code in the same ld -r object. +# XXX check if the gcc plugin ld is the expected one too +# XXX some Fedora binutils should also support it. How to check for that? +ifeq ($(call ld-ifversion,-ge,22710001,y),y) + LTO_CFLAGS := -flto -fno-toplevel-reorder + LTO_FINAL_CFLAGS := -fuse-linker-plugin + +# the -fno-toplevel-reorder is to preserve the order of initcalls +# everything else should tolerate reordering + LTO_FINAL_CFLAGS +=-fno-toplevel-reorder + +# enable LTO and set the jobs used by the LTO phase +# this should be -flto=jobserver to coordinate with the +# parent make, but work around +# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50639 +# use as many jobs as processors are online for now +# this actually seems to be a kernel bug with the pipe code + LTO_FINAL_CFLAGS := -flto=$(shell getconf _NPROCESSORS_ONLN) + #LTO_FINAL_CFLAGS := -flto=jobserver + + # requires plugin ar passed and very recent HJ binutils + LTO_CFLAGS += -fno-fat-lto-objects + +# Used to disable LTO for specific files (e.g. vdso) + DISABLE_LTO := -fno-lto + + LTO_FINAL_CFLAGS += ${LTO_CFLAGS} -fwhole-program + +ifdef CONFIG_LTO_DEBUG + LTO_FINAL_CFLAGS += -dH -fdump-ipa-cgraph -fdump-ipa-inline-details + # -Wl,-plugin-save-temps -save-temps + LTO_CFLAGS += +endif +ifdef CONFIG_LTO_CP_CLONE + LTO_FINAL_CFLAGS += -fipa-cp-clone + LTO_CFLAGS += -fipa-cp-clone +endif + + # In principle gcc should pass through options in the object files, + # but it doesn't always work. So do it here manually + # Note that special options for individual files does not + # work currently (except for some special cases that only + # affect the compiler frontend) + # The main offenders are FTRACE and GCOV -- we exclude + # those in the config. + LTO_FINAL_CFLAGS += $(filter -g%,${KBUILD_CFLAGS}) + LTO_FINAL_CFLAGS += $(filter -O%,${KBUILD_CFLAGS}) + LTO_FINAL_CFLAGS += $(filter -f%,${KBUILD_CFLAGS}) + LTO_FINAL_CFLAGS += $(filter -m%,${KBUILD_CFLAGS}) + LTO_FINAL_CFLAGS += $(filter -W%,${KBUILD_CFLAGS}) + + KBUILD_CFLAGS += ${LTO_CFLAGS} + + LDFINAL := ${CONFIG_SHELL} ${srctree}/scripts/gcc-ld \ + ${LTO_FINAL_CFLAGS} + +else + $(warning "WARNING: Too old linker version $(call ld-version) for kernel LTO. You need Linux binutils. CONFIG_LTO disabled.") +endif +else + $(warning "WARNING: Compiler/Linker does not support LTO/WHOPR with linker plugin. CONFIG_LTO disabled.") +endif +else + $(warning "WARNING: GCC $(call cc-version) too old for LTO/WHOPR. CONFIG_LTO disabled") +endif +endif diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 69f0a1417e9a47..9c40daea846cdb 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -77,7 +77,8 @@ modpost = scripts/mod/modpost \ $(if $(KBUILD_EXTRA_SYMBOLS), $(patsubst %, -e %,$(KBUILD_EXTRA_SYMBOLS))) \ $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \ - $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) + $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \ + $(if $(CONFIG_LTO),-w) MODPOST_OPT=$(subst -i,-n,$(filter -i,$(MAKEFLAGS))) @@ -115,8 +116,8 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE targets += $(modules:.ko=.mod.o) # Step 6), final link of the modules -quiet_cmd_ld_ko_o = LD [M] $@ - cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ +quiet_cmd_ld_ko_o = LDFINAL [M] $@ + cmd_ld_ko_o = $(LDFINAL) -r $(LDFLAGS) \ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -o $@ $(filter-out FORCE,$^) diff --git a/scripts/conmakehash.c b/scripts/conmakehash.c index 263a44d57fa95d..61bbda54cf13ea 100644 --- a/scripts/conmakehash.c +++ b/scripts/conmakehash.c @@ -104,7 +104,7 @@ int main(int argc, char *argv[]) } } - /* For now we assume the default font is always 256 characters. */ + /* For now we assume the default font is always 256 characters. */ fontlen = 256; /* Initialize table */ @@ -236,15 +236,15 @@ int main(int argc, char *argv[]) } /* Okay, we hit EOF, now output hash table */ - + fclose(ctbl); - + /* Compute total size of Unicode list */ nuni = 0; for ( i = 0 ; i < fontlen ; i++ ) nuni += unicount[i]; - + printf("\ /*\n\ * Do not edit this file; it was automatically generated by\n\ @@ -268,9 +268,9 @@ u8 dfont_unicount[%d] = \n\ else printf(", "); } - + printf("\nu16 dfont_unitable[%d] = \n{\n\t", nuni); - + fp0 = 0; nent = 0; for ( i = 0 ; i < nuni ; i++ ) diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index 31331723e81074..9cb8522d8d22a8 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -589,7 +589,7 @@ sub loop_select { # Now we need to see if we have to check selects; loop_select; -} +} my %setconfigs; diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 86a4fe75f45373..ec9a8ae33f8f1b 100644 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -53,7 +53,7 @@ vmlinux_link() local lds="${objtree}/${KBUILD_LDS}" if [ "${SRCARCH}" != "um" ]; then - ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ + ${LDFINAL} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ -T ${lds} ${KBUILD_VMLINUX_INIT} \ --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1} else diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h index cfb8440cc0b2cf..6fdc97ef6023da 100755 --- a/scripts/mkcompile_h +++ b/scripts/mkcompile_h @@ -68,7 +68,7 @@ UTS_TRUNCATE="cut -b -$UTS_LEN" ( echo /\* This file is auto generated, version $VERSION \*/ if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi - + echo \#define UTS_MACHINE \"$ARCH\" echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\" @@ -84,7 +84,7 @@ UTS_TRUNCATE="cut -b -$UTS_LEN" # recompilations. # We don't consider the file changed if only the date/time changed. # A kernel config change will increase the generation number, thus -# causing compile.h to be updated (including date/time) due to the +# causing compile.h to be updated (including date/time) due to the # changed comment in the # first line. diff --git a/scripts/mkmakefile b/scripts/mkmakefile index 0cc04426074403..84af27bf0f99fc 100644 --- a/scripts/mkmakefile +++ b/scripts/mkmakefile @@ -42,18 +42,11 @@ MAKEARGS += O=\$(if \$(patsubst /%,,\$(makedir)),\$(CURDIR)/)\$(patsubst %/,%,\$ MAKEFLAGS += --no-print-directory -.PHONY: all \$(MAKECMDGOALS) +.PHONY: __sub-make \$(MAKECMDGOALS) -all := \$(filter-out all Makefile,\$(MAKECMDGOALS)) +__sub-make: + \$(Q)\$(MAKE) \$(MAKEARGS) \$(MAKECMDGOALS) -all: - \$(Q)\$(MAKE) \$(MAKEARGS) \$(all) - -Makefile:; - -\$(all): all - @: - -%/: all +\$(filter-out __sub-make, \$(MAKECMDGOALS)): __sub-make @: EOF diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 06635567393034..026543ba8d8687 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -316,7 +316,7 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod, s->module->name, is_vmlinux(s->module->name) ?"":".ko"); } else { - /* In case Modules.symvers was out of date */ + /* In case Module.symvers was out of date */ s->module = mod; } } @@ -2113,8 +2113,10 @@ static void read_dump(const char *fname, unsigned int kernel) s->preloaded = 1; sym_update_crc(symname, mod, crc, export_no(export)); } + release_file(file, size); return; fail: + release_file(file, size); fatal("parse error in symbol dump file\n"); } diff --git a/scripts/package/builddeb b/scripts/package/builddeb index f46e4dd0558da4..fd683c540aa8a2 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -42,6 +42,8 @@ create_package() { debarch=hppa ;; mips*) debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo el || true) ;; + arm64) + debarch=arm64 ;; arm*) debarch=arm$(grep -q CONFIG_AEABI=y $KCONFIG_CONFIG && echo el || true) ;; *) @@ -130,7 +132,7 @@ if [ "$ARCH" = "um" ] ; then cp System.map "$tmpdir/usr/lib/uml/modules/$version/System.map" cp $KCONFIG_CONFIG "$tmpdir/usr/share/doc/$packagename/config" gzip "$tmpdir/usr/share/doc/$packagename/config" -else +else cp System.map "$tmpdir/boot/System.map-$version" cp $KCONFIG_CONFIG "$tmpdir/boot/config-$version" fi @@ -155,11 +157,11 @@ if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then for module in $(find lib/modules/ -name *.ko); do mkdir -p $(dirname $dbg_dir/usr/lib/debug/$module) # only keep debug symbols in the debug file - objcopy --only-keep-debug $module $dbg_dir/usr/lib/debug/$module + $OBJCOPY --only-keep-debug $module $dbg_dir/usr/lib/debug/$module # strip original module from debug symbols - objcopy --strip-debug $module + $OBJCOPY --strip-debug $module # then add a link to those - objcopy --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $module + $OBJCOPY --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $module done ) fi diff --git a/scripts/patch-kernel b/scripts/patch-kernel index d000ea3a41fdb7..49b4241e814a90 100755 --- a/scripts/patch-kernel +++ b/scripts/patch-kernel @@ -27,7 +27,7 @@ # Nick Holloway , 2nd January 1995. # # Added support for handling multiple types of compression. What includes -# gzip, bzip, bzip2, zip, compress, and plaintext. +# gzip, bzip, bzip2, zip, compress, and plaintext. # # Adam Sulmicki , 1st January 1997. # @@ -159,7 +159,7 @@ applyPatch () { fi # Remove backup files find $sourcedir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} \; - + return 0; } diff --git a/scripts/tags.sh b/scripts/tags.sh index f2c5b006a3d735..6db551e07498b6 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -25,6 +25,9 @@ else tree=${srctree}/ fi +# ignore userspace tools +ignore="$ignore ( -path ${tree}tools ) -prune -o" + # Find all available archs find_all_archs() { @@ -201,7 +204,8 @@ exuberant() --regex-c='/DECLARE_(TASKLET|WORK|DELAYED_WORK)\((\w*)/\2/v/' \ --regex-c='/DEFINE_PCI_DEVICE_TABLE\((\w*)/\1/v/' \ --regex-c='/(^\s)OFFSET\((\w*)/\2/v/' \ - --regex-c='/(^\s)DEFINE\((\w*)/\2/v/' + --regex-c='/(^\s)DEFINE\((\w*)/\2/v/' \ + --regex-c='/DEFINE_HASHTABLE\((\w*)/\1/v/' all_kconfigs | xargs $1 -a \ --langdef=kconfig --language-force=kconfig \ @@ -246,7 +250,8 @@ emacs() --regex='/__TESTCLEARFLAG_FALSE(\([^,)]*\).*/__TestClearPage\1/' \ --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' \ --regex='/PCI_OP_READ(\([a-z]*[a-z]\).*[1-4])/pci_bus_read_config_\1/' \ - --regex='/PCI_OP_WRITE(\([a-z]*[a-z]\).*[1-4])/pci_bus_write_config_\1/' + --regex='/PCI_OP_WRITE(\([a-z]*[a-z]\).*[1-4])/pci_bus_write_config_\1/'\ + --regex='/DEFINE_HASHTABLE\((\w*)/\1/v/' all_kconfigs | xargs $1 -a \ --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' diff --git a/security/capability.c b/security/capability.c index ad0d4de6994474..e76373de31298e 100644 --- a/security/capability.c +++ b/security/capability.c @@ -879,7 +879,7 @@ static void cap_key_free(struct key *key) } static int cap_key_permission(key_ref_t key_ref, const struct cred *cred, - key_perm_t perm) + unsigned perm) { return 0; } diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 8365909f5f8cfc..9134dbf70d3ee6 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -306,57 +306,138 @@ static int devcgroup_seq_show(struct seq_file *m, void *v) } /** - * may_access - verifies if a new exception is part of what is allowed - * by a dev cgroup based on the default policy + - * exceptions. This is used to make sure a child cgroup - * won't have more privileges than its parent or to - * verify if a certain access is allowed. - * @dev_cgroup: dev cgroup to be tested against - * @refex: new exception - * @behavior: behavior of the exception + * match_exception - iterates the exception list trying to find a complete match + * @exceptions: list of exceptions + * @type: device type (DEV_BLOCK or DEV_CHAR) + * @major: device file major number, ~0 to match all + * @minor: device file minor number, ~0 to match all + * @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD) + * + * It is considered a complete match if an exception is found that will + * contain the entire range of provided parameters. + * + * Return: true in case it matches an exception completely */ -static bool may_access(struct dev_cgroup *dev_cgroup, - struct dev_exception_item *refex, - enum devcg_behavior behavior) +static bool match_exception(struct list_head *exceptions, short type, + u32 major, u32 minor, short access) { struct dev_exception_item *ex; - bool match = false; - rcu_lockdep_assert(rcu_read_lock_held() || - lockdep_is_held(&devcgroup_mutex), - "device_cgroup::may_access() called without proper synchronization"); + list_for_each_entry_rcu(ex, exceptions, list) { + if ((type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) + continue; + if ((type & DEV_CHAR) && !(ex->type & DEV_CHAR)) + continue; + if (ex->major != ~0 && ex->major != major) + continue; + if (ex->minor != ~0 && ex->minor != minor) + continue; + /* provided access cannot have more than the exception rule */ + if (access & (~ex->access)) + continue; + return true; + } + return false; +} + +/** + * match_exception_partial - iterates the exception list trying to find a partial match + * @exceptions: list of exceptions + * @type: device type (DEV_BLOCK or DEV_CHAR) + * @major: device file major number, ~0 to match all + * @minor: device file minor number, ~0 to match all + * @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD) + * + * It is considered a partial match if an exception's range is found to + * contain *any* of the devices specified by provided parameters. This is + * used to make sure no extra access is being granted that is forbidden by + * any of the exception list. + * + * Return: true in case the provided range mat matches an exception completely + */ +static bool match_exception_partial(struct list_head *exceptions, short type, + u32 major, u32 minor, short access) +{ + struct dev_exception_item *ex; - list_for_each_entry_rcu(ex, &dev_cgroup->exceptions, list) { - if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) + list_for_each_entry_rcu(ex, exceptions, list) { + if ((type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) continue; - if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR)) + if ((type & DEV_CHAR) && !(ex->type & DEV_CHAR)) continue; - if (ex->major != ~0 && ex->major != refex->major) + /* + * We must be sure that both the exception and the provided + * range aren't masking all devices + */ + if (ex->major != ~0 && major != ~0 && ex->major != major) continue; - if (ex->minor != ~0 && ex->minor != refex->minor) + if (ex->minor != ~0 && minor != ~0 && ex->minor != minor) continue; - if (refex->access & (~ex->access)) + /* + * In order to make sure the provided range isn't matching + * an exception, all its access bits shouldn't match the + * exception's access bits + */ + if (!(access & ex->access)) continue; - match = true; - break; + return true; } + return false; +} + +/** + * verify_new_ex - verifies if a new exception is allowed by parent cgroup's permissions + * @dev_cgroup: dev cgroup to be tested against + * @refex: new exception + * @behavior: behavior of the exception's dev_cgroup + * + * This is used to make sure a child cgroup won't have more privileges + * than its parent + */ +static bool verify_new_ex(struct dev_cgroup *dev_cgroup, + struct dev_exception_item *refex, + enum devcg_behavior behavior) +{ + bool match = false; + + rcu_lockdep_assert(rcu_read_lock_held() || + lockdep_is_held(&devcgroup_mutex), + "device_cgroup:verify_new_ex called without proper synchronization"); if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) { if (behavior == DEVCG_DEFAULT_ALLOW) { - /* the exception will deny access to certain devices */ + /* + * new exception in the child doesn't matter, only + * adding extra restrictions + */ return true; } else { - /* the exception will allow access to certain devices */ + /* + * new exception in the child will add more devices + * that can be acessed, so it can't match any of + * parent's exceptions, even slightly + */ + match = match_exception_partial(&dev_cgroup->exceptions, + refex->type, + refex->major, + refex->minor, + refex->access); + if (match) - /* - * a new exception allowing access shouldn't - * match an parent's exception - */ return false; return true; } } else { - /* only behavior == DEVCG_DEFAULT_DENY allowed here */ + /* + * Only behavior == DEVCG_DEFAULT_DENY allowed here, therefore + * the new exception will add access to more devices and must + * be contained completely in an parent's exception to be + * allowed + */ + match = match_exception(&dev_cgroup->exceptions, refex->type, + refex->major, refex->minor, + refex->access); + if (match) /* parent has an exception that matches the proposed */ return true; @@ -378,7 +459,38 @@ static int parent_has_perm(struct dev_cgroup *childcg, if (!parent) return 1; - return may_access(parent, ex, childcg->behavior); + return verify_new_ex(parent, ex, childcg->behavior); +} + +/** + * parent_allows_removal - verify if it's ok to remove an exception + * @childcg: child cgroup from where the exception will be removed + * @ex: exception being removed + * + * When removing an exception in cgroups with default ALLOW policy, it must + * be checked if removing it will give the child cgroup more access than the + * parent. + * + * Return: true if it's ok to remove exception, false otherwise + */ +static bool parent_allows_removal(struct dev_cgroup *childcg, + struct dev_exception_item *ex) +{ + struct dev_cgroup *parent = css_to_devcgroup(css_parent(&childcg->css)); + + if (!parent) + return true; + + /* It's always allowed to remove access to devices */ + if (childcg->behavior == DEVCG_DEFAULT_DENY) + return true; + + /* + * Make sure you're not removing part or a whole exception existing in + * the parent cgroup + */ + return !match_exception_partial(&parent->exceptions, ex->type, + ex->major, ex->minor, ex->access); } /** @@ -616,17 +728,21 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, switch (filetype) { case DEVCG_ALLOW: - if (!parent_has_perm(devcgroup, &ex)) - return -EPERM; /* * If the default policy is to allow by default, try to remove * an matching exception instead. And be silent about it: we * don't want to break compatibility */ if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) { + /* Check if the parent allows removing it first */ + if (!parent_allows_removal(devcgroup, &ex)) + return -EPERM; dev_exception_rm(devcgroup, &ex); - return 0; + break; } + + if (!parent_has_perm(devcgroup, &ex)) + return -EPERM; rc = dev_exception_add(devcgroup, &ex); break; case DEVCG_DENY: @@ -704,18 +820,18 @@ static int __devcgroup_check_permission(short type, u32 major, u32 minor, short access) { struct dev_cgroup *dev_cgroup; - struct dev_exception_item ex; - int rc; - - memset(&ex, 0, sizeof(ex)); - ex.type = type; - ex.major = major; - ex.minor = minor; - ex.access = access; + bool rc; rcu_read_lock(); dev_cgroup = task_devcgroup(current); - rc = may_access(dev_cgroup, &ex, dev_cgroup->behavior); + if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) + /* Can't match any of the exceptions, even partially */ + rc = !match_exception_partial(&dev_cgroup->exceptions, + type, major, minor, access); + else + /* Need to match completely one exception to be allowed */ + rc = match_exception(&dev_cgroup->exceptions, type, major, + minor, access); rcu_read_unlock(); if (!rc) diff --git a/security/keys/internal.h b/security/keys/internal.h index 80b2aac4f50ced..5f20da01fd8d31 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -176,20 +176,11 @@ extern int key_task_permission(const key_ref_t key_ref, /* * Check to see whether permission is granted to use a key in the desired way. */ -static inline int key_permission(const key_ref_t key_ref, key_perm_t perm) +static inline int key_permission(const key_ref_t key_ref, unsigned perm) { return key_task_permission(key_ref, current_cred(), perm); } -/* required permissions */ -#define KEY_VIEW 0x01 /* require permission to view attributes */ -#define KEY_READ 0x02 /* require permission to read content */ -#define KEY_WRITE 0x04 /* require permission to update / modify */ -#define KEY_SEARCH 0x08 /* require permission to search (keyring) or find (key) */ -#define KEY_LINK 0x10 /* require permission to link */ -#define KEY_SETATTR 0x20 /* require permission to change attributes */ -#define KEY_ALL 0x3f /* all the above permissions */ - /* * Authorisation record for request_key(). */ diff --git a/security/keys/key.c b/security/keys/key.c index 6e21c11e48bc1c..2048a110e7f18f 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -714,7 +714,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref, int ret; /* need write permission on the key to update it */ - ret = key_permission(key_ref, KEY_WRITE); + ret = key_permission(key_ref, KEY_NEED_WRITE); if (ret < 0) goto error; @@ -838,7 +838,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, /* if we're going to allocate a new key, we're going to have * to modify the keyring */ - ret = key_permission(keyring_ref, KEY_WRITE); + ret = key_permission(keyring_ref, KEY_NEED_WRITE); if (ret < 0) { key_ref = ERR_PTR(ret); goto error_link_end; @@ -928,7 +928,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) key_check(key); /* the key must be writable */ - ret = key_permission(key_ref, KEY_WRITE); + ret = key_permission(key_ref, KEY_NEED_WRITE); if (ret < 0) goto error; diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index cee72ce642221e..cd5bd0cef25df3 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -111,7 +111,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, } /* find the target keyring (which must be writable) */ - keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); + keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error3; @@ -195,7 +195,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, dest_ref = NULL; if (destringid) { dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, - KEY_WRITE); + KEY_NEED_WRITE); if (IS_ERR(dest_ref)) { ret = PTR_ERR(dest_ref); goto error3; @@ -253,7 +253,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create) long ret; lflags = create ? KEY_LOOKUP_CREATE : 0; - key_ref = lookup_user_key(id, lflags, KEY_SEARCH); + key_ref = lookup_user_key(id, lflags, KEY_NEED_SEARCH); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -334,7 +334,7 @@ long keyctl_update_key(key_serial_t id, } /* find the target key (which must be writable) */ - key_ref = lookup_user_key(id, 0, KEY_WRITE); + key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error2; @@ -365,12 +365,12 @@ long keyctl_revoke_key(key_serial_t id) key_ref_t key_ref; long ret; - key_ref = lookup_user_key(id, 0, KEY_WRITE); + key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); if (ret != -EACCES) goto error; - key_ref = lookup_user_key(id, 0, KEY_SETATTR); + key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -401,7 +401,7 @@ long keyctl_invalidate_key(key_serial_t id) kenter("%d", id); - key_ref = lookup_user_key(id, 0, KEY_SEARCH); + key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -428,7 +428,7 @@ long keyctl_keyring_clear(key_serial_t ringid) key_ref_t keyring_ref; long ret; - keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); + keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); @@ -470,13 +470,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) key_ref_t keyring_ref, key_ref; long ret; - keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); + keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error; } - key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK); + key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_NEED_LINK); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error2; @@ -505,7 +505,7 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) key_ref_t keyring_ref, key_ref; long ret; - keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE); + keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error; @@ -548,7 +548,7 @@ long keyctl_describe_key(key_serial_t keyid, char *tmpbuf; long ret; - key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); + key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW); if (IS_ERR(key_ref)) { /* viewing a key under construction is permitted if we have the * authorisation token handy */ @@ -639,7 +639,7 @@ long keyctl_keyring_search(key_serial_t ringid, } /* get the keyring at which to begin the search */ - keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH); + keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_SEARCH); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error2; @@ -649,7 +649,7 @@ long keyctl_keyring_search(key_serial_t ringid, dest_ref = NULL; if (destringid) { dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, - KEY_WRITE); + KEY_NEED_WRITE); if (IS_ERR(dest_ref)) { ret = PTR_ERR(dest_ref); goto error3; @@ -676,7 +676,7 @@ long keyctl_keyring_search(key_serial_t ringid, /* link the resulting key to the destination keyring if we can */ if (dest_ref) { - ret = key_permission(key_ref, KEY_LINK); + ret = key_permission(key_ref, KEY_NEED_LINK); if (ret < 0) goto error6; @@ -727,7 +727,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) key = key_ref_to_ptr(key_ref); /* see if we can read it directly */ - ret = key_permission(key_ref, KEY_READ); + ret = key_permission(key_ref, KEY_NEED_READ); if (ret == 0) goto can_read_key; if (ret != -EACCES) @@ -799,7 +799,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) goto error; key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, - KEY_SETATTR); + KEY_NEED_SETATTR); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -905,7 +905,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) goto error; key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, - KEY_SETATTR); + KEY_NEED_SETATTR); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -947,7 +947,7 @@ static long get_instantiation_keyring(key_serial_t ringid, /* if a specific keyring is nominated by ID, then use that */ if (ringid > 0) { - dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); + dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); if (IS_ERR(dkref)) return PTR_ERR(dkref); *_dest_keyring = key_ref_to_ptr(dkref); @@ -1315,7 +1315,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) long ret; key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, - KEY_SETATTR); + KEY_NEED_SETATTR); if (IS_ERR(key_ref)) { /* setting the timeout on a key under construction is permitted * if we have the authorisation token handy */ @@ -1418,7 +1418,7 @@ long keyctl_get_security(key_serial_t keyid, char *context; long ret; - key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); + key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW); if (IS_ERR(key_ref)) { if (PTR_ERR(key_ref) != -EACCES) return PTR_ERR(key_ref); @@ -1482,7 +1482,7 @@ long keyctl_session_to_parent(void) struct cred *cred; int ret; - keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); + keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_NEED_LINK); if (IS_ERR(keyring_r)) return PTR_ERR(keyring_r); diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 2fb2576dc6448b..9cf2575f0d97c8 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -541,7 +541,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data) /* key must have search permissions */ if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) && key_task_permission(make_key_ref(key, ctx->possessed), - ctx->cred, KEY_SEARCH) < 0) { + ctx->cred, KEY_NEED_SEARCH) < 0) { ctx->result = ERR_PTR(-EACCES); kleave(" = %d [!perm]", ctx->skipped_ret); goto skipped; @@ -721,7 +721,7 @@ static bool search_nested_keyrings(struct key *keyring, /* Search a nested keyring */ if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) && key_task_permission(make_key_ref(key, ctx->possessed), - ctx->cred, KEY_SEARCH) < 0) + ctx->cred, KEY_NEED_SEARCH) < 0) continue; /* stack the current position */ @@ -843,7 +843,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, return ERR_PTR(-ENOTDIR); if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM)) { - err = key_task_permission(keyring_ref, ctx->cred, KEY_SEARCH); + err = key_task_permission(keyring_ref, ctx->cred, KEY_NEED_SEARCH); if (err < 0) return ERR_PTR(err); } @@ -973,7 +973,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) if (!skip_perm_check && key_permission(make_key_ref(keyring, 0), - KEY_SEARCH) < 0) + KEY_NEED_SEARCH) < 0) continue; /* we've got a match but we might end up racing with diff --git a/security/keys/permission.c b/security/keys/permission.c index efcc0c855a0db1..732cc0beffdfc7 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c @@ -28,7 +28,7 @@ * permissions bits or the LSM check. */ int key_task_permission(const key_ref_t key_ref, const struct cred *cred, - key_perm_t perm) + unsigned perm) { struct key *key; key_perm_t kperm; @@ -68,7 +68,7 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred, if (is_key_possessed(key_ref)) kperm |= key->perm >> 24; - kperm = kperm & perm & KEY_ALL; + kperm = kperm & perm & KEY_NEED_ALL; if (kperm != perm) return -EACCES; diff --git a/security/keys/persistent.c b/security/keys/persistent.c index 0ad3ee28378123..c9fae5ea89fe68 100644 --- a/security/keys/persistent.c +++ b/security/keys/persistent.c @@ -108,7 +108,7 @@ static long key_get_persistent(struct user_namespace *ns, kuid_t uid, return PTR_ERR(persistent_ref); found: - ret = key_task_permission(persistent_ref, current_cred(), KEY_LINK); + ret = key_task_permission(persistent_ref, current_cred(), KEY_NEED_LINK); if (ret == 0) { persistent = key_ref_to_ptr(persistent_ref); ret = key_link(key_ref_to_ptr(dest_ref), persistent); @@ -151,7 +151,7 @@ long keyctl_get_persistent(uid_t _uid, key_serial_t destid) } /* There must be a destination keyring */ - dest_ref = lookup_user_key(destid, KEY_LOOKUP_CREATE, KEY_WRITE); + dest_ref = lookup_user_key(destid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); if (IS_ERR(dest_ref)) return PTR_ERR(dest_ref); if (key_ref_to_ptr(dest_ref)->type != &key_type_keyring) { diff --git a/security/keys/proc.c b/security/keys/proc.c index 88e9a466940f64..d3f6f2fd21db84 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -218,7 +218,7 @@ static int proc_keys_show(struct seq_file *m, void *v) * - the caller holds a spinlock, and thus the RCU read lock, making our * access to __current_cred() safe */ - rc = key_task_permission(key_ref, ctx.cred, KEY_VIEW); + rc = key_task_permission(key_ref, ctx.cred, KEY_NEED_VIEW); if (rc < 0) return 0; diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c index 8c0af08760c809..b68faa1a5cfdf2 100644 --- a/security/keys/sysctl.c +++ b/security/keys/sysctl.c @@ -15,7 +15,7 @@ static const int zero, one = 1, max = INT_MAX; -ctl_table key_sysctls[] = { +struct ctl_table key_sysctls[] = { { .procname = "maxkeys", .data = &key_quota_maxkeys, diff --git a/security/security.c b/security/security.c index 8b774f362a3d4e..31614e9e96e556 100644 --- a/security/security.c +++ b/security/security.c @@ -1425,7 +1425,7 @@ void security_key_free(struct key *key) } int security_key_permission(key_ref_t key_ref, - const struct cred *cred, key_perm_t perm) + const struct cred *cred, unsigned perm) { return security_ops->key_permission(key_ref, cred, perm); } diff --git a/security/selinux/avc.c b/security/selinux/avc.c index fc3e6628a8642e..a18f1fa6440bb7 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -444,11 +444,15 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) avc_dump_query(ab, ad->selinux_audit_data->ssid, ad->selinux_audit_data->tsid, ad->selinux_audit_data->tclass); + if (ad->selinux_audit_data->denied) { + audit_log_format(ab, " permissive=%u", + ad->selinux_audit_data->result ? 0 : 1); + } } /* This is the slow part of avc audit with big stack footprint */ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, - u32 requested, u32 audited, u32 denied, + u32 requested, u32 audited, u32 denied, int result, struct common_audit_data *a, unsigned flags) { @@ -477,6 +481,7 @@ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, sad.tsid = tsid; sad.audited = audited; sad.denied = denied; + sad.result = result; a->selinux_audit_data = &sad; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2c7341dbc5d68d..9cfd8a38c6e94d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2770,6 +2770,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na static noinline int audit_inode_permission(struct inode *inode, u32 perms, u32 audited, u32 denied, + int result, unsigned flags) { struct common_audit_data ad; @@ -2780,7 +2781,7 @@ static noinline int audit_inode_permission(struct inode *inode, ad.u.inode = inode; rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms, - audited, denied, &ad, flags); + audited, denied, result, &ad, flags); if (rc) return rc; return 0; @@ -2822,7 +2823,7 @@ static int selinux_inode_permission(struct inode *inode, int mask) if (likely(!audited)) return rc; - rc2 = audit_inode_permission(inode, perms, audited, denied, flags); + rc2 = audit_inode_permission(inode, perms, audited, denied, rc, flags); if (rc2) return rc2; return rc; @@ -5722,7 +5723,7 @@ static void selinux_key_free(struct key *k) static int selinux_key_permission(key_ref_t key_ref, const struct cred *cred, - key_perm_t perm) + unsigned perm) { struct key *key; struct key_security_struct *ksec; diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index f53ee3c58d0ffd..ddf8eec03f2117 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -102,7 +102,7 @@ static inline u32 avc_audit_required(u32 requested, } int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, - u32 requested, u32 audited, u32 denied, + u32 requested, u32 audited, u32 denied, int result, struct common_audit_data *a, unsigned flags); @@ -137,7 +137,7 @@ static inline int avc_audit(u32 ssid, u32 tsid, if (likely(!audited)) return 0; return slow_avc_audit(ssid, tsid, tclass, - requested, audited, denied, + requested, audited, denied, result, a, 0); } diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 14d04e63b1f0e0..be491a74c1edc4 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -147,7 +147,7 @@ struct security_class_mapping secclass_map[] = { { "peer", { "recv", NULL } }, { "capability2", { "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend", - NULL } }, + "audit_read", NULL } }, { "kernel_service", { "use_as_override", "create_files_as", NULL } }, { "tun_socket", { COMMON_SOCK_PERMS, "attach_queue", NULL } }, diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 14f52be78c75e2..8177e7df8c2da4 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3506,11 +3506,12 @@ static void smack_key_free(struct key *key) * an error code otherwise */ static int smack_key_permission(key_ref_t key_ref, - const struct cred *cred, key_perm_t perm) + const struct cred *cred, unsigned perm) { struct key *keyp; struct smk_audit_info ad; struct smack_known *tkp = smk_of_task(cred->security); + int request = 0; keyp = key_ref_to_ptr(key_ref); if (keyp == NULL) @@ -3531,7 +3532,11 @@ static int smack_key_permission(key_ref_t key_ref, ad.a.u.key_struct.key = keyp->serial; ad.a.u.key_struct.key_desc = keyp->description; #endif - return smk_access(tkp, keyp->security, MAY_READWRITE, &ad); + if (perm & KEY_NEED_READ) + request = MAY_READ; + if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR)) + request = MAY_WRITE; + return smk_access(tkp, keyp->security, request, &ad); } #endif /* CONFIG_KEYS */ diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 05ec049c9faf1e..a04d23174dc2e3 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -1198,6 +1198,7 @@ static int atmel_ac97c_remove(struct platform_device *pdev) } static struct platform_driver atmel_ac97c_driver = { + .probe = atmel_ac97c_probe, .remove = atmel_ac97c_remove, .driver = { .name = "atmel_ac97c", @@ -1205,19 +1206,7 @@ static struct platform_driver atmel_ac97c_driver = { .pm = ATMEL_AC97C_PM_OPS, }, }; - -static int __init atmel_ac97c_init(void) -{ - return platform_driver_probe(&atmel_ac97c_driver, - atmel_ac97c_probe); -} -module_init(atmel_ac97c_init); - -static void __exit atmel_ac97c_exit(void) -{ - platform_driver_unregister(&atmel_ac97c_driver); -} -module_exit(atmel_ac97c_exit); +module_platform_driver(atmel_ac97c_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Driver for Atmel AC97 controller"); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index ce83def9f43bf9..9acc77eae4872a 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -345,7 +345,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, snd_pcm_debug_name(substream, name, sizeof(name)); xrun_log_show(substream); pcm_err(substream->pcm, - "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n", + "XRUN: %s, pos = %ld, buffer size = %ld, period size = %ld\n", name, pos, runtime->buffer_size, runtime->period_size); } diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 3e05c55a28801a..a1fd77af60593e 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -362,13 +362,13 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev) if (! port->name[0]) { if (info->name[0]) { if (ports > 1) - snprintf(port->name, sizeof(port->name), "%s-%d", info->name, p); + snprintf(port->name, sizeof(port->name), "%s-%u", info->name, p); else snprintf(port->name, sizeof(port->name), "%s", info->name); } else { /* last resort */ if (ports > 1) - sprintf(port->name, "MIDI %d-%d-%d", card->number, device, p); + sprintf(port->name, "MIDI %d-%d-%u", card->number, device, p); else sprintf(port->name, "MIDI %d-%d", card->number, device); } diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 8546711d12f927..70951fd9b35436 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -443,7 +443,7 @@ static int snd_bt87x_pcm_open(struct snd_pcm_substream *substream) _error: clear_bit(0, &chip->opened); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return err; } @@ -458,7 +458,7 @@ static int snd_bt87x_close(struct snd_pcm_substream *substream) chip->substream = NULL; clear_bit(0, &chip->opened); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return 0; } diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index db18ccabadd6ab..e8910d02580b1b 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -34,8 +35,6 @@ #include #include -#include - #ifdef CONFIG_SND_FM801_TEA575X_BOOL #include #endif @@ -80,7 +79,10 @@ MODULE_PARM_DESC(radio_nr, "Radio device numbers"); * Direct registers */ -#define FM801_REG(chip, reg) (chip->port + FM801_##reg) +#define fm801_writew(chip,reg,value) outw((value), chip->port + FM801_##reg) +#define fm801_readw(chip,reg) inw(chip->port + FM801_##reg) + +#define fm801_writel(chip,reg,value) outl((value), chip->port + FM801_##reg) #define FM801_PCM_VOL 0x00 /* PCM Output Volume */ #define FM801_FM_VOL 0x02 /* FM Output Volume */ @@ -222,6 +224,30 @@ MODULE_DEVICE_TABLE(pci, snd_fm801_ids); * common I/O routines */ +static bool fm801_ac97_is_ready(struct fm801 *chip, unsigned int iterations) +{ + unsigned int idx; + + for (idx = 0; idx < iterations; idx++) { + if (!(fm801_readw(chip, AC97_CMD) & FM801_AC97_BUSY)) + return true; + udelay(10); + } + return false; +} + +static bool fm801_ac97_is_valid(struct fm801 *chip, unsigned int iterations) +{ + unsigned int idx; + + for (idx = 0; idx < iterations; idx++) { + if (fm801_readw(chip, AC97_CMD) & FM801_AC97_VALID) + return true; + udelay(10); + } + return false; +} + static int snd_fm801_update_bits(struct fm801 *chip, unsigned short reg, unsigned short mask, unsigned short value) { @@ -244,73 +270,54 @@ static void snd_fm801_codec_write(struct snd_ac97 *ac97, unsigned short val) { struct fm801 *chip = ac97->private_data; - int idx; /* * Wait until the codec interface is not ready.. */ - for (idx = 0; idx < 100; idx++) { - if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) - goto ok1; - udelay(10); + if (!fm801_ac97_is_ready(chip, 100)) { + dev_err(chip->card->dev, "AC'97 interface is busy (1)\n"); + return; } - dev_err(chip->card->dev, "AC'97 interface is busy (1)\n"); - return; - ok1: /* write data and address */ - outw(val, FM801_REG(chip, AC97_DATA)); - outw(reg | (ac97->addr << FM801_AC97_ADDR_SHIFT), FM801_REG(chip, AC97_CMD)); + fm801_writew(chip, AC97_DATA, val); + fm801_writew(chip, AC97_CMD, reg | (ac97->addr << FM801_AC97_ADDR_SHIFT)); /* * Wait until the write command is not completed.. - */ - for (idx = 0; idx < 1000; idx++) { - if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) - return; - udelay(10); - } - dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", ac97->num); + */ + if (!fm801_ac97_is_ready(chip, 1000)) + dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", + ac97->num); } static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short reg) { struct fm801 *chip = ac97->private_data; - int idx; /* * Wait until the codec interface is not ready.. */ - for (idx = 0; idx < 100; idx++) { - if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) - goto ok1; - udelay(10); + if (!fm801_ac97_is_ready(chip, 100)) { + dev_err(chip->card->dev, "AC'97 interface is busy (1)\n"); + return 0; } - dev_err(chip->card->dev, "AC'97 interface is busy (1)\n"); - return 0; - ok1: /* read command */ - outw(reg | (ac97->addr << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ, - FM801_REG(chip, AC97_CMD)); - for (idx = 0; idx < 100; idx++) { - if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) - goto ok2; - udelay(10); + fm801_writew(chip, AC97_CMD, + reg | (ac97->addr << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ); + if (!fm801_ac97_is_ready(chip, 100)) { + dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", + ac97->num); + return 0; } - dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", ac97->num); - return 0; - ok2: - for (idx = 0; idx < 1000; idx++) { - if (inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_VALID) - goto ok3; - udelay(10); + if (!fm801_ac97_is_valid(chip, 1000)) { + dev_err(chip->card->dev, + "AC'97 interface #%d is not valid (2)\n", ac97->num); + return 0; } - dev_err(chip->card->dev, "AC'97 interface #%d is not valid (2)\n", ac97->num); - return 0; - ok3: - return inw(FM801_REG(chip, AC97_DATA)); + return fm801_readw(chip, AC97_DATA); } static unsigned int rates[] = { @@ -384,7 +391,7 @@ static int snd_fm801_playback_trigger(struct snd_pcm_substream *substream, snd_BUG(); return -EINVAL; } - outw(chip->ply_ctrl, FM801_REG(chip, PLY_CTRL)); + fm801_writew(chip, PLY_CTRL, chip->ply_ctrl); spin_unlock(&chip->reg_lock); return 0; } @@ -419,7 +426,7 @@ static int snd_fm801_capture_trigger(struct snd_pcm_substream *substream, snd_BUG(); return -EINVAL; } - outw(chip->cap_ctrl, FM801_REG(chip, CAP_CTRL)); + fm801_writew(chip, CAP_CTRL, chip->cap_ctrl); spin_unlock(&chip->reg_lock); return 0; } @@ -457,12 +464,13 @@ static int snd_fm801_playback_prepare(struct snd_pcm_substream *substream) } chip->ply_ctrl |= snd_fm801_rate_bits(runtime->rate) << FM801_RATE_SHIFT; chip->ply_buf = 0; - outw(chip->ply_ctrl, FM801_REG(chip, PLY_CTRL)); - outw(chip->ply_count - 1, FM801_REG(chip, PLY_COUNT)); + fm801_writew(chip, PLY_CTRL, chip->ply_ctrl); + fm801_writew(chip, PLY_COUNT, chip->ply_count - 1); chip->ply_buffer = runtime->dma_addr; chip->ply_pos = 0; - outl(chip->ply_buffer, FM801_REG(chip, PLY_BUF1)); - outl(chip->ply_buffer + (chip->ply_count % chip->ply_size), FM801_REG(chip, PLY_BUF2)); + fm801_writel(chip, PLY_BUF1, chip->ply_buffer); + fm801_writel(chip, PLY_BUF2, + chip->ply_buffer + (chip->ply_count % chip->ply_size)); spin_unlock_irq(&chip->reg_lock); return 0; } @@ -483,12 +491,13 @@ static int snd_fm801_capture_prepare(struct snd_pcm_substream *substream) chip->cap_ctrl |= FM801_STEREO; chip->cap_ctrl |= snd_fm801_rate_bits(runtime->rate) << FM801_RATE_SHIFT; chip->cap_buf = 0; - outw(chip->cap_ctrl, FM801_REG(chip, CAP_CTRL)); - outw(chip->cap_count - 1, FM801_REG(chip, CAP_COUNT)); + fm801_writew(chip, CAP_CTRL, chip->cap_ctrl); + fm801_writew(chip, CAP_COUNT, chip->cap_count - 1); chip->cap_buffer = runtime->dma_addr; chip->cap_pos = 0; - outl(chip->cap_buffer, FM801_REG(chip, CAP_BUF1)); - outl(chip->cap_buffer + (chip->cap_count % chip->cap_size), FM801_REG(chip, CAP_BUF2)); + fm801_writel(chip, CAP_BUF1, chip->cap_buffer); + fm801_writel(chip, CAP_BUF2, + chip->cap_buffer + (chip->cap_count % chip->cap_size)); spin_unlock_irq(&chip->reg_lock); return 0; } @@ -501,8 +510,8 @@ static snd_pcm_uframes_t snd_fm801_playback_pointer(struct snd_pcm_substream *su if (!(chip->ply_ctrl & FM801_START)) return 0; spin_lock(&chip->reg_lock); - ptr = chip->ply_pos + (chip->ply_count - 1) - inw(FM801_REG(chip, PLY_COUNT)); - if (inw(FM801_REG(chip, IRQ_STATUS)) & FM801_IRQ_PLAYBACK) { + ptr = chip->ply_pos + (chip->ply_count - 1) - fm801_readw(chip, PLY_COUNT); + if (fm801_readw(chip, IRQ_STATUS) & FM801_IRQ_PLAYBACK) { ptr += chip->ply_count; ptr %= chip->ply_size; } @@ -518,8 +527,8 @@ static snd_pcm_uframes_t snd_fm801_capture_pointer(struct snd_pcm_substream *sub if (!(chip->cap_ctrl & FM801_START)) return 0; spin_lock(&chip->reg_lock); - ptr = chip->cap_pos + (chip->cap_count - 1) - inw(FM801_REG(chip, CAP_COUNT)); - if (inw(FM801_REG(chip, IRQ_STATUS)) & FM801_IRQ_CAPTURE) { + ptr = chip->cap_pos + (chip->cap_count - 1) - fm801_readw(chip, CAP_COUNT); + if (fm801_readw(chip, IRQ_STATUS) & FM801_IRQ_CAPTURE) { ptr += chip->cap_count; ptr %= chip->cap_size; } @@ -533,12 +542,12 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id) unsigned short status; unsigned int tmp; - status = inw(FM801_REG(chip, IRQ_STATUS)); + status = fm801_readw(chip, IRQ_STATUS); status &= FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU|FM801_IRQ_VOLUME; if (! status) return IRQ_NONE; /* ack first */ - outw(status, FM801_REG(chip, IRQ_STATUS)); + fm801_writew(chip, IRQ_STATUS, status); if (chip->pcm && (status & FM801_IRQ_PLAYBACK) && chip->playback_substream) { spin_lock(&chip->reg_lock); chip->ply_buf++; @@ -546,10 +555,10 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id) chip->ply_pos %= chip->ply_size; tmp = chip->ply_pos + chip->ply_count; tmp %= chip->ply_size; - outl(chip->ply_buffer + tmp, - (chip->ply_buf & 1) ? - FM801_REG(chip, PLY_BUF1) : - FM801_REG(chip, PLY_BUF2)); + if (chip->ply_buf & 1) + fm801_writel(chip, PLY_BUF1, chip->ply_buffer + tmp); + else + fm801_writel(chip, PLY_BUF2, chip->ply_buffer + tmp); spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(chip->playback_substream); } @@ -560,10 +569,10 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id) chip->cap_pos %= chip->cap_size; tmp = chip->cap_pos + chip->cap_count; tmp %= chip->cap_size; - outl(chip->cap_buffer + tmp, - (chip->cap_buf & 1) ? - FM801_REG(chip, CAP_BUF1) : - FM801_REG(chip, CAP_BUF2)); + if (chip->cap_buf & 1) + fm801_writel(chip, CAP_BUF1, chip->cap_buffer + tmp); + else + fm801_writel(chip, CAP_BUF2, chip->cap_buffer + tmp); spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(chip->capture_substream); } @@ -747,7 +756,7 @@ static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = { static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) { struct fm801 *chip = tea->private_data; - unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); + unsigned short reg = fm801_readw(chip, GPIO_CTRL); struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip); reg &= ~(FM801_GPIO_GP(gpio.data) | @@ -759,13 +768,13 @@ static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) /* WRITE_ENABLE is inverted */ reg |= (pins & TEA575X_WREN) ? 0 : FM801_GPIO_GP(gpio.wren); - outw(reg, FM801_REG(chip, GPIO_CTRL)); + fm801_writew(chip, GPIO_CTRL, reg); } static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea) { struct fm801 *chip = tea->private_data; - unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); + unsigned short reg = fm801_readw(chip, GPIO_CTRL); struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip); u8 ret; @@ -780,7 +789,7 @@ static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea) static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output) { struct fm801 *chip = tea->private_data; - unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); + unsigned short reg = fm801_readw(chip, GPIO_CTRL); struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip); /* use GPIO lines and set write enable bit */ @@ -811,7 +820,7 @@ static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output FM801_GPIO_GP(gpio.clk)); } - outw(reg, FM801_REG(chip, GPIO_CTRL)); + fm801_writew(chip, GPIO_CTRL, reg); } static struct snd_tea575x_ops snd_fm801_tea_ops = { @@ -962,7 +971,7 @@ static int snd_fm801_get_mux(struct snd_kcontrol *kcontrol, struct fm801 *chip = snd_kcontrol_chip(kcontrol); unsigned short val; - val = inw(FM801_REG(chip, REC_SRC)) & 7; + val = fm801_readw(chip, REC_SRC) & 7; if (val > 4) val = 4; ucontrol->value.enumerated.item[0] = val; @@ -1073,12 +1082,12 @@ static int wait_for_codec(struct fm801 *chip, unsigned int codec_id, { unsigned long timeout = jiffies + waits; - outw(FM801_AC97_READ | (codec_id << FM801_AC97_ADDR_SHIFT) | reg, - FM801_REG(chip, AC97_CMD)); + fm801_writew(chip, AC97_CMD, + reg | (codec_id << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ); udelay(5); do { - if ((inw(FM801_REG(chip, AC97_CMD)) & (FM801_AC97_VALID|FM801_AC97_BUSY)) - == FM801_AC97_VALID) + if ((fm801_readw(chip, AC97_CMD) & + (FM801_AC97_VALID | FM801_AC97_BUSY)) == FM801_AC97_VALID) return 0; schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); @@ -1093,10 +1102,10 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) goto __ac97_ok; /* codec cold reset + AC'97 warm reset */ - outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL)); - inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */ + fm801_writew(chip, CODEC_CTRL, (1 << 5) | (1 << 6)); + fm801_readw(chip, CODEC_CTRL); /* flush posting data */ udelay(100); - outw(0, FM801_REG(chip, CODEC_CTRL)); + fm801_writew(chip, CODEC_CTRL, 0); if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) if (!resume) { @@ -1117,7 +1126,7 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) for (i = 3; i > 0; i--) { if (!wait_for_codec(chip, i, AC97_VENDOR_ID1, msecs_to_jiffies(50))) { - cmdw = inw(FM801_REG(chip, AC97_DATA)); + cmdw = fm801_readw(chip, AC97_DATA); if (cmdw != 0xffff && cmdw != 0) { chip->secondary = 1; chip->secondary_addr = i; @@ -1135,23 +1144,24 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) __ac97_ok: /* init volume */ - outw(0x0808, FM801_REG(chip, PCM_VOL)); - outw(0x9f1f, FM801_REG(chip, FM_VOL)); - outw(0x8808, FM801_REG(chip, I2S_VOL)); + fm801_writew(chip, PCM_VOL, 0x0808); + fm801_writew(chip, FM_VOL, 0x9f1f); + fm801_writew(chip, I2S_VOL, 0x8808); /* I2S control - I2S mode */ - outw(0x0003, FM801_REG(chip, I2S_MODE)); + fm801_writew(chip, I2S_MODE, 0x0003); /* interrupt setup */ - cmdw = inw(FM801_REG(chip, IRQ_MASK)); + cmdw = fm801_readw(chip, IRQ_MASK); if (chip->irq < 0) cmdw |= 0x00c3; /* mask everything, no PCM nor MPU */ else cmdw &= ~0x0083; /* unmask MPU, PLAYBACK & CAPTURE */ - outw(cmdw, FM801_REG(chip, IRQ_MASK)); + fm801_writew(chip, IRQ_MASK, cmdw); /* interrupt clear */ - outw(FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU, FM801_REG(chip, IRQ_STATUS)); + fm801_writew(chip, IRQ_STATUS, + FM801_IRQ_PLAYBACK | FM801_IRQ_CAPTURE | FM801_IRQ_MPU); return 0; } @@ -1165,9 +1175,9 @@ static int snd_fm801_free(struct fm801 *chip) goto __end_hw; /* interrupt setup - mask everything */ - cmdw = inw(FM801_REG(chip, IRQ_MASK)); + cmdw = fm801_readw(chip, IRQ_MASK); cmdw |= 0x00c3; - outw(cmdw, FM801_REG(chip, IRQ_MASK)); + fm801_writew(chip, IRQ_MASK, cmdw); __end_hw: #ifdef CONFIG_SND_FM801_TEA575X_BOOL @@ -1339,15 +1349,15 @@ static int snd_card_fm801_probe(struct pci_dev *pci, return err; } if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801, - FM801_REG(chip, MPU401_DATA), + chip->port + FM801_MPU401_DATA, MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, -1, &chip->rmidi)) < 0) { snd_card_free(card); return err; } - if ((err = snd_opl3_create(card, FM801_REG(chip, OPL3_BANK0), - FM801_REG(chip, OPL3_BANK1), + if ((err = snd_opl3_create(card, chip->port + FM801_OPL3_BANK0, + chip->port + FM801_OPL3_BANK1, OPL3_HW_OPL3_FM801, 1, &opl3)) < 0) { snd_card_free(card); return err; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 1edbb9c47c2d3b..016f785cdf4514 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1127,10 +1127,6 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, AMP_OUT_UNMUTE); eld = &per_pin->sink_eld; - if (!eld->monitor_present) { - hdmi_set_channel_count(codec, per_pin->cvt_nid, channels); - return; - } if (!non_pcm && per_pin->chmap_set) ca = hdmi_manual_channel_allocation(channels, per_pin->chmap); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5f7c765391f111..40f9b5d712eb9c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -951,7 +951,9 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = { { 0x10ec0280, 0x1028, 0, "ALC3220" }, { 0x10ec0282, 0x1028, 0, "ALC3221" }, { 0x10ec0283, 0x1028, 0, "ALC3223" }, + { 0x10ec0288, 0x1028, 0, "ALC3263" }, { 0x10ec0292, 0x1028, 0, "ALC3226" }, + { 0x10ec0293, 0x1028, 0, "ALC3235" }, { 0x10ec0255, 0x1028, 0, "ALC3234" }, { 0x10ec0668, 0x1028, 0, "ALC3661" }, { } /* terminator */ @@ -3538,6 +3540,25 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) alc_write_coef_idx(codec, 0x18, 0x7308); alc_write_coef_idx(codec, 0x6b, 0xc429); break; + case 0x10ec0293: + /* SET Line1 JD to 0 */ + val = alc_read_coef_idx(codec, 0x10); + alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 6<<8); + /* SET charge pump by verb */ + val = alc_read_coefex_idx(codec, 0x57, 0x05); + alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | 0x0); + /* SET EN_OSW to 1 */ + val = alc_read_coefex_idx(codec, 0x57, 0x03); + alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | (1<<10) ); + /* Combo JD gating with LINE1-VREFO */ + val = alc_read_coef_idx(codec, 0x1a); + alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | (1<<3)); + /* Set to TRS type */ + alc_write_coef_idx(codec, 0x45, 0xc429); + /* Combo Jack auto detect */ + val = alc_read_coef_idx(codec, 0x4a); + alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e); + break; case 0x10ec0668: alc_write_coef_idx(codec, 0x15, 0x0d40); alc_write_coef_idx(codec, 0xb7, 0x802b); @@ -3576,6 +3597,21 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, alc_write_coef_idx(codec, 0x19, 0xa208); alc_write_coef_idx(codec, 0x2e, 0xacf0); break; + case 0x10ec0293: + /* Set to TRS mode */ + alc_write_coef_idx(codec, 0x45, 0xc429); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + /* SET charge pump by verb */ + val = alc_read_coefex_idx(codec, 0x57, 0x05); + alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | (1<<15|1<<13)); + /* SET EN_OSW to 0 */ + val = alc_read_coefex_idx(codec, 0x57, 0x03); + alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | 0x0); + /* Combo JD gating without LINE1-VREFO */ + val = alc_read_coef_idx(codec, 0x1a); + alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); @@ -3591,6 +3627,8 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, static void alc_headset_mode_default(struct hda_codec *codec) { + int val; + switch (codec->vendor_id) { case 0x10ec0255: alc_write_coef_idx(codec, 0x45, 0xc089); @@ -3608,6 +3646,16 @@ static void alc_headset_mode_default(struct hda_codec *codec) alc_write_coef_idx(codec, 0x6b, 0xc429); alc_write_coef_idx(codec, 0x18, 0x7308); break; + case 0x10ec0293: + /* Combo Jack auto detect */ + val = alc_read_coef_idx(codec, 0x4a); + alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e); + /* Set to TRS type */ + alc_write_coef_idx(codec, 0x45, 0xC429); + /* Combo JD gating without LINE1-VREFO */ + val = alc_read_coef_idx(codec, 0x1a); + alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0); + break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0041); alc_write_coef_idx(codec, 0x15, 0x0d40); @@ -3620,6 +3668,8 @@ static void alc_headset_mode_default(struct hda_codec *codec) /* Iphone type */ static void alc_headset_mode_ctia(struct hda_codec *codec) { + int val; + switch (codec->vendor_id) { case 0x10ec0255: /* Set to CTIA type */ @@ -3637,6 +3687,13 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) alc_write_coef_idx(codec, 0x76, 0x0008); alc_write_coef_idx(codec, 0x18, 0x7388); break; + case 0x10ec0293: + /* Set to ctia type */ + alc_write_coef_idx(codec, 0x45, 0xd429); + /* SET Line1 JD to 1 */ + val = alc_read_coef_idx(codec, 0x10); + alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8); + break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); alc_write_coef_idx(codec, 0x15, 0x0d60); @@ -3649,6 +3706,8 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) /* Nokia type */ static void alc_headset_mode_omtp(struct hda_codec *codec) { + int val; + switch (codec->vendor_id) { case 0x10ec0255: /* Set to OMTP Type */ @@ -3666,6 +3725,13 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) alc_write_coef_idx(codec, 0x76, 0x0008); alc_write_coef_idx(codec, 0x18, 0x7388); break; + case 0x10ec0293: + /* Set to omtp type */ + alc_write_coef_idx(codec, 0x45, 0xe429); + /* SET Line1 JD to 1 */ + val = alc_read_coef_idx(codec, 0x10); + alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8); + break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); alc_write_coef_idx(codec, 0x15, 0x0d50); @@ -3703,6 +3769,16 @@ static void alc_determine_headset_type(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0x6c); is_ctia = (val & 0x001c) == 0x001c; break; + case 0x10ec0293: + /* Combo Jack auto detect */ + val = alc_read_coef_idx(codec, 0x4a); + alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x0008); + /* Set to ctia type */ + alc_write_coef_idx(codec, 0x45, 0xD429); + msleep(300); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x0070) == 0x0070; + break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); alc_write_coef_idx(codec, 0xb7, 0x802b); @@ -4159,6 +4235,8 @@ enum { ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, ALC255_FIXUP_HEADSET_MODE, ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC, + ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC292_FIXUP_TPT440_DOCK, }; static const struct hda_fixup alc269_fixups[] = { @@ -4552,6 +4630,26 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode_alc255_no_hp_mic, }, + [ALC293_FIXUP_DELL1_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, 0x01a1913d }, /* use as headphone mic, without its own jack detect */ + { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE + }, + [ALC292_FIXUP_TPT440_DOCK] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x16, 0x21211010 }, /* dock headphone */ + { 0x19, 0x21a11010 }, /* dock mic */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -4609,6 +4707,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), SND_PCI_QUIRK(0x1028, 0x063e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0640, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x064d, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), @@ -4626,6 +4726,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x067f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4712,7 +4814,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), - SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -4790,6 +4893,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"}, {.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"}, {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"}, + {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"}, {} }; diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c index 2d8e95e9fbe59c..e8f38e5df10abc 100644 --- a/sound/pci/lx6464es/lx_core.c +++ b/sound/pci/lx6464es/lx_core.c @@ -24,6 +24,7 @@ /* #define RMH_DEBUG 1 */ +#include #include #include #include @@ -429,11 +430,6 @@ int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data) return ret; } -#define CSES_TIMEOUT 100 /* microseconds */ -#define CSES_CE 0x0001 -#define CSES_BROADCAST 0x0002 -#define CSES_UPDATE_LDSV 0x0004 - #define PIPE_INFO_TO_CMD(capture, pipe) \ ((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET) @@ -519,7 +515,6 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, *r_needed += 1; } -#if 0 dev_dbg(chip->card->dev, "CMD_08_ASK_BUFFERS: needed %d, freed %d\n", *r_needed, *r_freed); @@ -530,7 +525,6 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, chip->rmh.stat[i], chip->rmh.stat[i] & MASK_DATA_SIZE); } -#endif } spin_unlock_irqrestore(&chip->msg_lock, flags); @@ -971,9 +965,9 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, /* interrupt handling */ #define PCX_IRQ_NONE 0 -#define IRQCS_ACTIVE_PCIDB 0x00002000L /* Bit nø 13 */ -#define IRQCS_ENABLE_PCIIRQ 0x00000100L /* Bit nø 08 */ -#define IRQCS_ENABLE_PCIDB 0x00000200L /* Bit nø 09 */ +#define IRQCS_ACTIVE_PCIDB BIT(13) +#define IRQCS_ENABLE_PCIIRQ BIT(8) +#define IRQCS_ENABLE_PCIDB BIT(9) static u32 lx_interrupt_test_ack(struct lx6464es *chip) { @@ -1030,25 +1024,21 @@ static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc, int err; u32 stat[9]; /* answer from CMD_04_GET_EVENT */ - /* On peut optimiser pour ne pas lire les evenements vides - * les mots de réponse sont dans l'ordre suivant : - * Stat[0] mot de status général - * Stat[1] fin de buffer OUT pF - * Stat[2] fin de buffer OUT pf - * Stat[3] fin de buffer IN pF - * Stat[4] fin de buffer IN pf - * Stat[5] underrun poid fort - * Stat[6] underrun poid faible - * Stat[7] overrun poid fort - * Stat[8] overrun poid faible + /* We can optimize this to not read dumb events. + * Answer words are in the following order: + * Stat[0] general status + * Stat[1] end of buffer OUT pF + * Stat[2] end of buffer OUT pf + * Stat[3] end of buffer IN pF + * Stat[4] end of buffer IN pf + * Stat[5] MSB underrun + * Stat[6] LSB underrun + * Stat[7] MSB overrun + * Stat[8] LSB overrun * */ u64 orun_mask; u64 urun_mask; -#if 0 - int has_underrun = (irqsrc & MASK_SYS_STATUS_URUN) ? 1 : 0; - int has_overrun = (irqsrc & MASK_SYS_STATUS_ORUN) ? 1 : 0; -#endif int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0; int eb_pending_in = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0; @@ -1199,9 +1189,8 @@ irqreturn_t lx_interrupt(int irq, void *dev_id) if (irqsrc & MASK_SYS_STATUS_CMD_DONE) goto exit; -#if 0 if (irqsrc & MASK_SYS_STATUS_EOBI) - dev_dgg(chip->card->dev, "interrupt: EOBI\n"); + dev_dbg(chip->card->dev, "interrupt: EOBI\n"); if (irqsrc & MASK_SYS_STATUS_EOBO) dev_dbg(chip->card->dev, "interrupt: EOBO\n"); @@ -1211,7 +1200,6 @@ irqreturn_t lx_interrupt(int irq, void *dev_id) if (irqsrc & MASK_SYS_STATUS_ORUN) dev_dbg(chip->card->dev, "interrupt: ORUN\n"); -#endif if (async_pending) { u64 notified_in_pipe_mask = 0; @@ -1238,7 +1226,6 @@ irqreturn_t lx_interrupt(int irq, void *dev_id) } if (async_escmd) { -#if 0 /* backdoor for ethersound commands * * for now, we do not need this @@ -1246,7 +1233,6 @@ irqreturn_t lx_interrupt(int irq, void *dev_id) * */ dev_dbg(chip->card->dev, "interrupt requests escmd handling\n"); -#endif } exit: diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 4789619a52d86d..27e3fc4a536b40 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -35,7 +35,7 @@ config SND_AT91_SOC_SAM9G20_WM8731 config SND_ATMEL_SOC_WM8904 tristate "Atmel ASoC driver for boards using WM8904 codec" - depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC + depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC && I2C select SND_ATMEL_SOC_SSC select SND_ATMEL_SOC_DMA select SND_SOC_WM8904 diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index b07e17160f94a0..3c4b10ff48c1c9 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -276,7 +276,7 @@ static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; int val[2], val2[2], i; @@ -300,7 +300,7 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; int err; @@ -333,7 +333,7 @@ static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; @@ -353,7 +353,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; @@ -1327,10 +1327,6 @@ static int pm860x_probe(struct snd_soc_codec *codec) pm860x->codec = codec; - ret = snd_soc_codec_set_cache_io(codec, pm860x->regmap); - if (ret) - return ret; - for (i = 0; i < 4; i++) { ret = request_threaded_irq(pm860x->irq[i], NULL, pm860x_codec_handler, IRQF_ONESHOT, @@ -1362,10 +1358,18 @@ static int pm860x_remove(struct snd_soc_codec *codec) return 0; } +static struct regmap *pm860x_get_regmap(struct device *dev) +{ + struct pm860x_priv *pm860x = dev_get_drvdata(dev); + + return pm860x->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_pm860x = { .probe = pm860x_probe, .remove = pm860x_remove, .set_bias_level = pm860x_set_bias_level, + .get_regmap = pm860x_get_regmap, .controls = pm860x_snd_controls, .num_controls = ARRAY_SIZE(pm860x_snd_controls), diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index f0e84013788737..4f96b97687c29a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -39,8 +39,9 @@ config SND_SOC_ALL_CODECS select SND_SOC_ALC5623 if I2C select SND_SOC_ALC5632 if I2C select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC - select SND_SOC_CS42L51 if I2C - select SND_SOC_CS42L52 if I2C + select SND_SOC_CS42L51_I2C if I2C + select SND_SOC_CS42L52 if I2C && INPUT + select SND_SOC_CS42L56 if I2C && INPUT select SND_SOC_CS42L73 if I2C select SND_SOC_CS4270 if I2C select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI @@ -71,6 +72,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM512x_SPI if SPI_MASTER select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C + select SND_SOC_RT5645 if I2C + select SND_SOC_RT5651 if I2C select SND_SOC_SGTL5000 if I2C select SND_SOC_SI476X if MFD_SI476X_CORE select SND_SOC_SIRF_AUDIO_CODEC @@ -80,6 +83,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_SSM2602_SPI if SPI_MASTER select SND_SOC_SSM2602_I2C if I2C select SND_SOC_STA32X if I2C + select SND_SOC_STA350 if I2C select SND_SOC_STA529 if I2C select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TAS5086 if I2C @@ -127,7 +131,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8955 if I2C select SND_SOC_WM8960 if I2C select SND_SOC_WM8961 if I2C - select SND_SOC_WM8962 if I2C + select SND_SOC_WM8962 if I2C && INPUT select SND_SOC_WM8971 if I2C select SND_SOC_WM8974 if I2C select SND_SOC_WM8978 if I2C @@ -280,9 +284,17 @@ config SND_SOC_CQ0093VC config SND_SOC_CS42L51 tristate +config SND_SOC_CS42L51_I2C + tristate + select SND_SOC_CS42L51 + config SND_SOC_CS42L52 tristate "Cirrus Logic CS42L52 CODEC" - depends on I2C + depends on I2C && INPUT + +config SND_SOC_CS42L56 + tristate "Cirrus Logic CS42L56 CODEC" + depends on I2C && INPUT config SND_SOC_CS42L73 tristate "Cirrus Logic CS42L73 CODEC" @@ -396,6 +408,12 @@ config SND_SOC_RT5631 config SND_SOC_RT5640 tristate +config SND_SOC_RT5645 + tristate + +config SND_SOC_RT5651 + tristate + #Freescale sgtl5000 codec config SND_SOC_SGTL5000 tristate "Freescale SGTL5000 CODEC" @@ -435,6 +453,10 @@ config SND_SOC_SSM2602_I2C config SND_SOC_STA32X tristate +config SND_SOC_STA350 + tristate "STA350 speaker amplifier" + depends on I2C + config SND_SOC_STA529 tristate @@ -598,7 +620,7 @@ config SND_SOC_WM8961 config SND_SOC_WM8962 tristate "Wolfson Microelectronics WM8962 CODEC" - depends on I2C + depends on I2C && INPUT config SND_SOC_WM8971 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3c4d275d064bf8..1ccdaf0c0e3e71 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -26,7 +26,9 @@ snd-soc-ak5386-objs := ak5386.o snd-soc-arizona-objs := arizona.o snd-soc-cq93vc-objs := cq93vc.o snd-soc-cs42l51-objs := cs42l51.o +snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o +snd-soc-cs42l56-objs := cs42l56.o snd-soc-cs42l73-objs := cs42l73.o snd-soc-cs4270-objs := cs4270.o snd-soc-cs4271-objs := cs4271.o @@ -60,6 +62,8 @@ snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o snd-soc-pcm512x-spi-objs := pcm512x-spi.o snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o +snd-soc-rt5645-objs := rt5645.o +snd-soc-rt5651-objs := rt5651.o snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-alc5623-objs := alc5623.o snd-soc-alc5632-objs := alc5632.o @@ -74,6 +78,7 @@ snd-soc-ssm2602-objs := ssm2602.o snd-soc-ssm2602-spi-objs := ssm2602-spi.o snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o snd-soc-sta32x-objs := sta32x.o +snd-soc-sta350-objs := sta350.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o snd-soc-tas5086-objs := tas5086.o @@ -177,7 +182,9 @@ obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o +obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o +obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o @@ -211,6 +218,8 @@ obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o +obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o +obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o @@ -221,6 +230,7 @@ obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o +obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 1ad92cbf0b24df..1fb4402bf72d30 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -1139,7 +1139,7 @@ static void anc_configure(struct snd_soc_codec *codec, static int sid_status_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); mutex_lock(&codec->mutex); @@ -1153,7 +1153,7 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol, static int sid_status_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); unsigned int param, sidconf, val; int status = 1; @@ -1208,7 +1208,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, static int anc_status_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); mutex_lock(&codec->mutex); @@ -1221,7 +1221,7 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol, static int anc_status_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); struct device *dev = codec->dev; bool apply_fir, apply_iir; @@ -1306,7 +1306,7 @@ static int filter_control_info(struct snd_kcontrol *kcontrol, static int filter_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct filter_control *fc = (struct filter_control *)kcontrol->private_value; unsigned int i; @@ -1322,7 +1322,7 @@ static int filter_control_get(struct snd_kcontrol *kcontrol, static int filter_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct filter_control *fc = (struct filter_control *)kcontrol->private_value; unsigned int i; diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 877f5737bb6b23..1ff7d4d027e932 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -519,8 +519,7 @@ static const struct snd_kcontrol_new adau1373_controls[] = { SOC_ENUM("HPF Channel", adau1373_hpf_channel_enum), SOC_ENUM("Bass HPF Cutoff", adau1373_bass_hpf_cutoff_enum), - SOC_VALUE_ENUM("Bass Clip Level Threshold", - adau1373_bass_clip_level_enum), + SOC_ENUM("Bass Clip Level Threshold", adau1373_bass_clip_level_enum), SOC_ENUM("Bass LPF Cutoff", adau1373_bass_lpf_cutoff_enum), SOC_DOUBLE("Bass Playback Switch", ADAU1373_BASS2, 0, 1, 1, 0), SOC_SINGLE_TLV("Bass Playback Volume", ADAU1373_BASS2, 2, 7, 0, @@ -580,7 +579,7 @@ static SOC_ENUM_SINGLE_VIRT_DECL(adau1373_decimator_enum, adau1373_decimator_text); static const struct snd_kcontrol_new adau1373_decimator_mux = - SOC_DAPM_ENUM_VIRT("Decimator Mux", adau1373_decimator_enum); + SOC_DAPM_ENUM("Decimator Mux", adau1373_decimator_enum); static const struct snd_kcontrol_new adau1373_left_adc_mixer_controls[] = { SOC_DAPM_SINGLE("DAC1 Switch", ADAU1373_LADC_MIXER, 4, 1, 0), @@ -694,7 +693,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = { SND_SOC_DAPM_ADC("DMIC1", NULL, ADAU1373_DIGMICCTRL, 0, 0), SND_SOC_DAPM_ADC("DMIC2", NULL, ADAU1373_DIGMICCTRL, 2, 0), - SND_SOC_DAPM_VIRT_MUX("Decimator Mux", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_MUX("Decimator Mux", SND_SOC_NOPM, 0, 0, &adau1373_decimator_mux), SND_SOC_DAPM_SUPPLY("MICBIAS2", ADAU1373_PWDN_CTRL1, 5, 0, NULL, 0), diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 5062e34ee8dcbd..c43b93fdf0dfe4 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -172,14 +172,14 @@ static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3); static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3); static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl = - SOC_DAPM_VALUE_ENUM("Route", adav80x_aux_capture_enum); + SOC_DAPM_ENUM("Route", adav80x_aux_capture_enum); static const struct snd_kcontrol_new adav80x_capture_mux_ctrl = - SOC_DAPM_VALUE_ENUM("Route", adav80x_capture_enum); + SOC_DAPM_ENUM("Route", adav80x_capture_enum); static const struct snd_kcontrol_new adav80x_dac_mux_ctrl = - SOC_DAPM_VALUE_ENUM("Route", adav80x_dac_enum); + SOC_DAPM_ENUM("Route", adav80x_dac_enum); #define ADAV80X_MUX(name, ctrl) \ - SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1), @@ -315,7 +315,7 @@ static int adav80x_set_deemph(struct snd_soc_codec *codec) static int adav80x_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); unsigned int deemph = ucontrol->value.enumerated.item[0]; @@ -330,7 +330,7 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol, static int adav80x_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = adav80x->deemph; diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 10adf25d4c14f3..1fd7f72b2a62a0 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -11,13 +11,14 @@ #include #include -#include -#include -#include #include #include #include +#include #include +#include +#include +#include /* AK4104 registers addresses */ #define AK4104_REG_CONTROL1 0x00 @@ -47,6 +48,7 @@ struct ak4104_private { struct regmap *regmap; + struct regulator *regulator; }; static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = { @@ -174,20 +176,30 @@ static int ak4104_probe(struct snd_soc_codec *codec) struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); int ret; + ret = regulator_enable(ak4104->regulator); + if (ret < 0) { + dev_err(codec->dev, "Unable to enable regulator: %d\n", ret); + return ret; + } + /* set power-up and non-reset bits */ ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN); if (ret < 0) - return ret; + goto exit_disable_regulator; /* enable transmitter */ ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX, AK4104_TX_TXE, AK4104_TX_TXE); if (ret < 0) - return ret; + goto exit_disable_regulator; return 0; + +exit_disable_regulator: + regulator_disable(ak4104->regulator); + return ret; } static int ak4104_remove(struct snd_soc_codec *codec) @@ -196,13 +208,42 @@ static int ak4104_remove(struct snd_soc_codec *codec) regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0); + regulator_disable(ak4104->regulator); return 0; } +#ifdef CONFIG_PM +static int ak4104_soc_suspend(struct snd_soc_codec *codec) +{ + struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec); + + regulator_disable(priv->regulator); + + return 0; +} + +static int ak4104_soc_resume(struct snd_soc_codec *codec) +{ + struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = regulator_enable(priv->regulator); + if (ret < 0) + return ret; + + return 0; +} +#else +#define ak4104_soc_suspend NULL +#define ak4104_soc_resume NULL +#endif /* CONFIG_PM */ + static struct snd_soc_codec_driver soc_codec_device_ak4104 = { - .probe = ak4104_probe, - .remove = ak4104_remove, + .probe = ak4104_probe, + .remove = ak4104_remove, + .suspend = ak4104_soc_suspend, + .resume = ak4104_soc_resume, .dapm_widgets = ak4104_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets), @@ -239,6 +280,13 @@ static int ak4104_spi_probe(struct spi_device *spi) if (ak4104 == NULL) return -ENOMEM; + ak4104->regulator = devm_regulator_get(&spi->dev, "vdd"); + if (IS_ERR(ak4104->regulator)) { + ret = PTR_ERR(ak4104->regulator); + dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret); + return ret; + } + ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap); if (IS_ERR(ak4104->regmap)) { ret = PTR_ERR(ak4104->regmap); diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 868c0e2da1ece1..7afe8f4820887b 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -74,7 +74,7 @@ static int ak4641_set_deemph(struct snd_soc_codec *codec) static int ak4641_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; @@ -89,7 +89,7 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol, static int ak4641_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = ak4641->deemph; diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 16df0f91335375..05ae17f5bca30b 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -107,7 +107,7 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; #define ARIZONA_MUX_CTL_DECL(name) \ const struct snd_kcontrol_new name##_mux = \ - SOC_DAPM_VALUE_ENUM("Route", name##_enum) + SOC_DAPM_ENUM("Route", name##_enum) #define ARIZONA_MUX_ENUMS(name, base_reg) \ static ARIZONA_MUX_ENUM_DECL(name##_enum, base_reg); \ @@ -128,7 +128,7 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ARIZONA_MUX_ENUMS(name##_aux6, base_reg + 40) #define ARIZONA_MUX(name, ctrl) \ - SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) #define ARIZONA_MUX_WIDGETS(name, name_str) \ ARIZONA_MUX(name_str " Input", &name##_mux) diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 1e25c7af853bcd..537327c7f7f13f 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -139,8 +139,6 @@ static int cq93vc_probe(struct snd_soc_codec *codec) davinci_vc->cq93vc.codec = codec; - snd_soc_codec_set_cache_io(codec, davinci_vc->regmap); - /* Off, with power on */ cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -154,11 +152,19 @@ static int cq93vc_remove(struct snd_soc_codec *codec) return 0; } +static struct regmap *cq93vc_get_regmap(struct device *dev) +{ + struct davinci_vc *davinci_vc = dev->platform_data; + + return davinci_vc->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { .set_bias_level = cq93vc_set_bias_level, .probe = cq93vc_probe, .remove = cq93vc_remove, .resume = cq93vc_resume, + .get_regmap = cq93vc_get_regmap, .controls = cq93vc_snd_controls, .num_controls = ARRAY_SIZE(cq93vc_snd_controls), }; diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 3920e626494885..9947a95836794f 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -438,7 +438,7 @@ static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute) static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); int left = !ucontrol->value.integer.value[0]; int right = !ucontrol->value.integer.value[1]; diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index aef4965750c780..93cec52f473332 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -284,7 +284,7 @@ static int cs4271_set_deemph(struct snd_soc_codec *codec) static int cs4271_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = cs4271->deemph; @@ -294,7 +294,7 @@ static int cs4271_get_deemph(struct snd_kcontrol *kcontrol, static int cs4271_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); cs4271->deemph = ucontrol->value.enumerated.item[0]; diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c new file mode 100644 index 00000000000000..cee51ae177c1e2 --- /dev/null +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -0,0 +1,59 @@ +/* + * cs42l56.c -- CS42L51 ALSA SoC I2C audio driver + * + * Copyright 2014 CirrusLogic, Inc. + * + * Author: Brian Austin + * + * 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 "cs42l51.h" + +static struct i2c_device_id cs42l51_i2c_id[] = { + {"cs42l51", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id); + +static int cs42l51_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regmap_config config; + + config = cs42l51_regmap; + config.val_bits = 8; + config.reg_bits = 8; + + return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config)); +} + +static int cs42l51_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static struct i2c_driver cs42l51_i2c_driver = { + .driver = { + .name = "cs42l51", + .owner = THIS_MODULE, + }, + .probe = cs42l51_i2c_probe, + .remove = cs42l51_i2c_remove, + .id_table = cs42l51_i2c_id, +}; + +module_i2c_driver(cs42l51_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L51 I2C Driver"); +MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 6c0da2baa154e2..09488d97de60d0 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include "cs42l51.h" @@ -55,7 +54,7 @@ struct cs42l51_private { static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3; switch (value) { @@ -83,7 +82,7 @@ static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned char val; switch (ucontrol->value.integer.value[0]) { @@ -483,7 +482,7 @@ static struct snd_soc_dai_driver cs42l51_dai = { .ops = &cs42l51_dai_ops, }; -static int cs42l51_probe(struct snd_soc_codec *codec) +static int cs42l51_codec_probe(struct snd_soc_codec *codec) { int ret, reg; @@ -504,7 +503,7 @@ static int cs42l51_probe(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { - .probe = cs42l51_probe, + .probe = cs42l51_codec_probe, .controls = cs42l51_snd_controls, .num_controls = ARRAY_SIZE(cs42l51_snd_controls), @@ -514,91 +513,56 @@ static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { .num_dapm_routes = ARRAY_SIZE(cs42l51_routes), }; -static const struct regmap_config cs42l51_regmap = { - .reg_bits = 8, - .val_bits = 8, - +const struct regmap_config cs42l51_regmap = { .max_register = CS42L51_CHARGE_FREQ, .cache_type = REGCACHE_RBTREE, }; +EXPORT_SYMBOL_GPL(cs42l51_regmap); -static int cs42l51_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +int cs42l51_probe(struct device *dev, struct regmap *regmap) { struct cs42l51_private *cs42l51; - struct regmap *regmap; unsigned int val; int ret; - regmap = devm_regmap_init_i2c(i2c_client, &cs42l51_regmap); - if (IS_ERR(regmap)) { - ret = PTR_ERR(regmap); - dev_err(&i2c_client->dev, "Failed to create regmap: %d\n", - ret); - return ret; - } + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + cs42l51 = devm_kzalloc(dev, sizeof(struct cs42l51_private), + GFP_KERNEL); + if (!cs42l51) + return -ENOMEM; + + dev_set_drvdata(dev, cs42l51); /* Verify that we have a CS42L51 */ ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val); if (ret < 0) { - dev_err(&i2c_client->dev, "failed to read I2C\n"); + dev_err(dev, "failed to read I2C\n"); goto error; } if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { - dev_err(&i2c_client->dev, "Invalid chip id: %x\n", val); + dev_err(dev, "Invalid chip id: %x\n", val); ret = -ENODEV; goto error; } + dev_info(dev, "Cirrus Logic CS42L51, Revision: %02X\n", + val & CS42L51_CHIP_REV_MASK); - dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n", - val & 7); - - cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private), - GFP_KERNEL); - if (!cs42l51) - return -ENOMEM; - - i2c_set_clientdata(i2c_client, cs42l51); - - ret = snd_soc_register_codec(&i2c_client->dev, + ret = snd_soc_register_codec(dev, &soc_codec_device_cs42l51, &cs42l51_dai, 1); error: return ret; } - -static int cs42l51_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - return 0; -} - -static const struct i2c_device_id cs42l51_id[] = { - {"cs42l51", 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, cs42l51_id); +EXPORT_SYMBOL_GPL(cs42l51_probe); static const struct of_device_id cs42l51_of_match[] = { { .compatible = "cirrus,cs42l51", }, { } }; MODULE_DEVICE_TABLE(of, cs42l51_of_match); - -static struct i2c_driver cs42l51_i2c_driver = { - .driver = { - .name = "cs42l51-codec", - .owner = THIS_MODULE, - .of_match_table = cs42l51_of_match, - }, - .id_table = cs42l51_id, - .probe = cs42l51_i2c_probe, - .remove = cs42l51_i2c_remove, -}; - -module_i2c_driver(cs42l51_i2c_driver); - MODULE_AUTHOR("Arnaud Patard "); MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h index 2beeb171db4b99..8c55bf384bc651 100644 --- a/sound/soc/codecs/cs42l51.h +++ b/sound/soc/codecs/cs42l51.h @@ -18,9 +18,15 @@ #ifndef _CS42L51_H #define _CS42L51_H +struct device; + +extern const struct regmap_config cs42l51_regmap; +int cs42l51_probe(struct device *dev, struct regmap *regmap); + #define CS42L51_CHIP_ID 0x1B #define CS42L51_CHIP_REV_A 0x00 #define CS42L51_CHIP_REV_B 0x01 +#define CS42L51_CHIP_REV_MASK 0x07 #define CS42L51_CHIP_REV_ID 0x01 #define CS42L51_MK_CHIP_REV(a, b) ((a)<<3|(b)) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 2213a037c89310..071fc77f2f06c8 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -50,11 +50,9 @@ struct cs42l52_private { u8 mclksel; u32 mclk; u8 flags; -#if IS_ENABLED(CONFIG_INPUT) struct input_dev *beep; struct work_struct beep_work; int beep_rate; -#endif }; static const struct reg_default cs42l52_reg_defaults[] = { @@ -962,7 +960,6 @@ static int cs42l52_resume(struct snd_soc_codec *codec) return 0; } -#if IS_ENABLED(CONFIG_INPUT) static int beep_rates[] = { 261, 522, 585, 667, 706, 774, 889, 1000, 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 @@ -1096,15 +1093,6 @@ static void cs42l52_free_beep(struct snd_soc_codec *codec) snd_soc_update_bits(codec, CS42L52_BEEP_TONE_CTL, CS42L52_BEEP_EN_MASK, 0); } -#else -static void cs42l52_init_beep(struct snd_soc_codec *codec) -{ -} - -static void cs42l52_free_beep(struct snd_soc_codec *codec) -{ -} -#endif static int cs42l52_probe(struct snd_soc_codec *codec) { diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c new file mode 100644 index 00000000000000..5bb134b4ab9ba2 --- /dev/null +++ b/sound/soc/codecs/cs42l56.c @@ -0,0 +1,1427 @@ +/* + * cs42l56.c -- CS42L56 ALSA SoC audio driver + * + * Copyright 2014 CirrusLogic, Inc. + * + * Author: Brian Austin + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cs42l56.h" + +#define CS42L56_NUM_SUPPLIES 3 +static const char *const cs42l56_supply_names[CS42L56_NUM_SUPPLIES] = { + "VA", + "VCP", + "VLDO", +}; + +struct cs42l56_private { + struct regmap *regmap; + struct snd_soc_codec *codec; + struct device *dev; + struct cs42l56_platform_data pdata; + struct regulator_bulk_data supplies[CS42L56_NUM_SUPPLIES]; + u32 mclk; + u8 mclk_prediv; + u8 mclk_div2; + u8 mclk_ratio; + u8 iface; + u8 iface_fmt; + u8 iface_inv; +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + struct input_dev *beep; + struct work_struct beep_work; + int beep_rate; +#endif +}; + +static const struct reg_default cs42l56_reg_defaults[] = { + { 1, 0x56 }, /* r01 - ID 1 */ + { 2, 0x04 }, /* r02 - ID 2 */ + { 3, 0x7f }, /* r03 - Power Ctl 1 */ + { 4, 0xff }, /* r04 - Power Ctl 2 */ + { 5, 0x00 }, /* ro5 - Clocking Ctl 1 */ + { 6, 0x0b }, /* r06 - Clocking Ctl 2 */ + { 7, 0x00 }, /* r07 - Serial Format */ + { 8, 0x05 }, /* r08 - Class H Ctl */ + { 9, 0x0c }, /* r09 - Misc Ctl */ + { 10, 0x80 }, /* r0a - INT Status */ + { 11, 0x00 }, /* r0b - Playback Ctl */ + { 12, 0x0c }, /* r0c - DSP Mute Ctl */ + { 13, 0x00 }, /* r0d - ADCA Mixer Volume */ + { 14, 0x00 }, /* r0e - ADCB Mixer Volume */ + { 15, 0x00 }, /* r0f - PCMA Mixer Volume */ + { 16, 0x00 }, /* r10 - PCMB Mixer Volume */ + { 17, 0x00 }, /* r11 - Analog Input Advisory Volume */ + { 18, 0x00 }, /* r12 - Digital Input Advisory Volume */ + { 19, 0x00 }, /* r13 - Master A Volume */ + { 20, 0x00 }, /* r14 - Master B Volume */ + { 21, 0x00 }, /* r15 - Beep Freq / On Time */ + { 22, 0x00 }, /* r16 - Beep Volume / Off Time */ + { 23, 0x00 }, /* r17 - Beep Tone Ctl */ + { 24, 0x88 }, /* r18 - Tone Ctl */ + { 25, 0x00 }, /* r19 - Channel Mixer & Swap */ + { 26, 0x00 }, /* r1a - AIN Ref Config / ADC Mux */ + { 27, 0xa0 }, /* r1b - High-Pass Filter Ctl */ + { 28, 0x00 }, /* r1c - Misc ADC Ctl */ + { 29, 0x00 }, /* r1d - Gain & Bias Ctl */ + { 30, 0x00 }, /* r1e - PGAA Mux & Volume */ + { 31, 0x00 }, /* r1f - PGAB Mux & Volume */ + { 32, 0x00 }, /* r20 - ADCA Attenuator */ + { 33, 0x00 }, /* r21 - ADCB Attenuator */ + { 34, 0x00 }, /* r22 - ALC Enable & Attack Rate */ + { 35, 0xbf }, /* r23 - ALC Release Rate */ + { 36, 0x00 }, /* r24 - ALC Threshold */ + { 37, 0x00 }, /* r25 - Noise Gate Ctl */ + { 38, 0x00 }, /* r26 - ALC, Limiter, SFT, ZeroCross */ + { 39, 0x00 }, /* r27 - Analog Mute, LO & HP Mux */ + { 40, 0x00 }, /* r28 - HP A Volume */ + { 41, 0x00 }, /* r29 - HP B Volume */ + { 42, 0x00 }, /* r2a - LINEOUT A Volume */ + { 43, 0x00 }, /* r2b - LINEOUT B Volume */ + { 44, 0x00 }, /* r2c - Limit Threshold Ctl */ + { 45, 0x7f }, /* r2d - Limiter Ctl & Release Rate */ + { 46, 0x00 }, /* r2e - Limiter Attack Rate */ +}; + +static bool cs42l56_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42L56_CHIP_ID_1: + case CS42L56_CHIP_ID_2: + case CS42L56_PWRCTL_1: + case CS42L56_PWRCTL_2: + case CS42L56_CLKCTL_1: + case CS42L56_CLKCTL_2: + case CS42L56_SERIAL_FMT: + case CS42L56_CLASSH_CTL: + case CS42L56_MISC_CTL: + case CS42L56_INT_STATUS: + case CS42L56_PLAYBACK_CTL: + case CS42L56_DSP_MUTE_CTL: + case CS42L56_ADCA_MIX_VOLUME: + case CS42L56_ADCB_MIX_VOLUME: + case CS42L56_PCMA_MIX_VOLUME: + case CS42L56_PCMB_MIX_VOLUME: + case CS42L56_ANAINPUT_ADV_VOLUME: + case CS42L56_DIGINPUT_ADV_VOLUME: + case CS42L56_MASTER_A_VOLUME: + case CS42L56_MASTER_B_VOLUME: + case CS42L56_BEEP_FREQ_ONTIME: + case CS42L56_BEEP_FREQ_OFFTIME: + case CS42L56_BEEP_TONE_CFG: + case CS42L56_TONE_CTL: + case CS42L56_CHAN_MIX_SWAP: + case CS42L56_AIN_REFCFG_ADC_MUX: + case CS42L56_HPF_CTL: + case CS42L56_MISC_ADC_CTL: + case CS42L56_GAIN_BIAS_CTL: + case CS42L56_PGAA_MUX_VOLUME: + case CS42L56_PGAB_MUX_VOLUME: + case CS42L56_ADCA_ATTENUATOR: + case CS42L56_ADCB_ATTENUATOR: + case CS42L56_ALC_EN_ATTACK_RATE: + case CS42L56_ALC_RELEASE_RATE: + case CS42L56_ALC_THRESHOLD: + case CS42L56_NOISE_GATE_CTL: + case CS42L56_ALC_LIM_SFT_ZC: + case CS42L56_AMUTE_HPLO_MUX: + case CS42L56_HPA_VOLUME: + case CS42L56_HPB_VOLUME: + case CS42L56_LOA_VOLUME: + case CS42L56_LOB_VOLUME: + case CS42L56_LIM_THRESHOLD_CTL: + case CS42L56_LIM_CTL_RELEASE_RATE: + case CS42L56_LIM_ATTACK_RATE: + return true; + default: + return false; + } +} + +static bool cs42l56_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42L56_INT_STATUS: + return 1; + default: + return 0; + } +} + +static DECLARE_TLV_DB_SCALE(beep_tlv, -5000, 200, 0); +static DECLARE_TLV_DB_SCALE(hl_tlv, -6000, 50, 0); +static DECLARE_TLV_DB_SCALE(adv_tlv, -10200, 50, 0); +static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, 0); +static DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0); +static DECLARE_TLV_DB_SCALE(preamp_tlv, 0, 1000, 0); +static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0); + +static const unsigned int ngnb_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 1, TLV_DB_SCALE_ITEM(-8200, 600, 0), + 2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0), +}; +static const unsigned int ngb_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 2, TLV_DB_SCALE_ITEM(-6400, 600, 0), + 3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0), +}; +static const unsigned int alc_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0), + 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0), +}; + +static const char * const beep_config_text[] = { + "Off", "Single", "Multiple", "Continuous" +}; + +static const struct soc_enum beep_config_enum = + SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 6, + ARRAY_SIZE(beep_config_text), beep_config_text); + +static const char * const beep_pitch_text[] = { + "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5", + "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7" +}; + +static const struct soc_enum beep_pitch_enum = + SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 4, + ARRAY_SIZE(beep_pitch_text), beep_pitch_text); + +static const char * const beep_ontime_text[] = { + "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s", + "1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s", + "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s" +}; + +static const struct soc_enum beep_ontime_enum = + SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 0, + ARRAY_SIZE(beep_ontime_text), beep_ontime_text); + +static const char * const beep_offtime_text[] = { + "1.23 s", "2.58 s", "3.90 s", "5.20 s", + "6.60 s", "8.05 s", "9.35 s", "10.80 s" +}; + +static const struct soc_enum beep_offtime_enum = + SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_OFFTIME, 5, + ARRAY_SIZE(beep_offtime_text), beep_offtime_text); + +static const char * const beep_treble_text[] = { + "5kHz", "7kHz", "10kHz", "15kHz" +}; + +static const struct soc_enum beep_treble_enum = + SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 3, + ARRAY_SIZE(beep_treble_text), beep_treble_text); + +static const char * const beep_bass_text[] = { + "50Hz", "100Hz", "200Hz", "250Hz" +}; + +static const struct soc_enum beep_bass_enum = + SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1, + ARRAY_SIZE(beep_bass_text), beep_bass_text); + +static const char * const adc_swap_text[] = { + "None", "A+B/2", "A-B/2", "Swap" +}; + +static const struct soc_enum adc_swap_enum = + SOC_ENUM_SINGLE(CS42L56_MISC_ADC_CTL, 3, + ARRAY_SIZE(adc_swap_text), adc_swap_text); + +static const char * const pgaa_mux_text[] = { + "AIN1A", "AIN2A", "AIN3A"}; + +static const struct soc_enum pgaa_mux_enum = + SOC_ENUM_SINGLE(CS42L56_PGAA_MUX_VOLUME, 0, + ARRAY_SIZE(pgaa_mux_text), + pgaa_mux_text); + +static const struct snd_kcontrol_new pgaa_mux = + SOC_DAPM_ENUM("Route", pgaa_mux_enum); + +static const char * const pgab_mux_text[] = { + "AIN1B", "AIN2B", "AIN3B"}; + +static const struct soc_enum pgab_mux_enum = + SOC_ENUM_SINGLE(CS42L56_PGAB_MUX_VOLUME, 0, + ARRAY_SIZE(pgab_mux_text), + pgab_mux_text); + +static const struct snd_kcontrol_new pgab_mux = + SOC_DAPM_ENUM("Route", pgab_mux_enum); + +static const char * const adca_mux_text[] = { + "PGAA", "AIN1A", "AIN2A", "AIN3A"}; + +static const struct soc_enum adca_mux_enum = + SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 0, + ARRAY_SIZE(adca_mux_text), + adca_mux_text); + +static const struct snd_kcontrol_new adca_mux = + SOC_DAPM_ENUM("Route", adca_mux_enum); + +static const char * const adcb_mux_text[] = { + "PGAB", "AIN1B", "AIN2B", "AIN3B"}; + +static const struct soc_enum adcb_mux_enum = + SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 2, + ARRAY_SIZE(adcb_mux_text), + adcb_mux_text); + +static const struct snd_kcontrol_new adcb_mux = + SOC_DAPM_ENUM("Route", adcb_mux_enum); + +static const char * const left_swap_text[] = { + "Left", "LR 2", "Right"}; + +static const char * const right_swap_text[] = { + "Right", "LR 2", "Left"}; + +static const unsigned int swap_values[] = { 0, 1, 3 }; + +static const struct soc_enum adca_swap_enum = + SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 0, 3, + ARRAY_SIZE(left_swap_text), + left_swap_text, + swap_values); + +static const struct soc_enum pcma_swap_enum = + SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3, + ARRAY_SIZE(left_swap_text), + left_swap_text, + swap_values); + +static const struct soc_enum adcb_swap_enum = + SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3, + ARRAY_SIZE(right_swap_text), + right_swap_text, + swap_values); + +static const struct soc_enum pcmb_swap_enum = + SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3, + ARRAY_SIZE(right_swap_text), + right_swap_text, + swap_values); + +static const struct snd_kcontrol_new hpa_switch = + SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1); + +static const struct snd_kcontrol_new hpb_switch = + SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 4, 1, 1); + +static const struct snd_kcontrol_new loa_switch = + SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 2, 1, 1); + +static const struct snd_kcontrol_new lob_switch = + SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 0, 1, 1); + +static const char * const hploa_input_text[] = { + "DACA", "PGAA"}; + +static const struct soc_enum lineouta_input_enum = + SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 2, + ARRAY_SIZE(hploa_input_text), + hploa_input_text); + +static const struct snd_kcontrol_new lineouta_input = + SOC_DAPM_ENUM("Route", lineouta_input_enum); + +static const struct soc_enum hpa_input_enum = + SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 0, + ARRAY_SIZE(hploa_input_text), + hploa_input_text); + +static const struct snd_kcontrol_new hpa_input = + SOC_DAPM_ENUM("Route", hpa_input_enum); + +static const char * const hplob_input_text[] = { + "DACB", "PGAB"}; + +static const struct soc_enum lineoutb_input_enum = + SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 3, + ARRAY_SIZE(hplob_input_text), + hplob_input_text); + +static const struct snd_kcontrol_new lineoutb_input = + SOC_DAPM_ENUM("Route", lineoutb_input_enum); + +static const struct soc_enum hpb_input_enum = + SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 1, + ARRAY_SIZE(hplob_input_text), + hplob_input_text); + +static const struct snd_kcontrol_new hpb_input = + SOC_DAPM_ENUM("Route", hpb_input_enum); + +static const char * const dig_mux_text[] = { + "ADC", "DSP"}; + +static const struct soc_enum dig_mux_enum = + SOC_ENUM_SINGLE(CS42L56_MISC_CTL, 7, + ARRAY_SIZE(dig_mux_text), + dig_mux_text); + +static const struct snd_kcontrol_new dig_mux = + SOC_DAPM_ENUM("Route", dig_mux_enum); + +static const char * const hpf_freq_text[] = { + "1.8Hz", "119Hz", "236Hz", "464Hz" +}; + +static const struct soc_enum hpfa_freq_enum = + SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 0, + ARRAY_SIZE(hpf_freq_text), hpf_freq_text); + +static const struct soc_enum hpfb_freq_enum = + SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 2, + ARRAY_SIZE(hpf_freq_text), hpf_freq_text); + +static const char * const ng_delay_text[] = { + "50ms", "100ms", "150ms", "200ms" +}; + +static const struct soc_enum ng_delay_enum = + SOC_ENUM_SINGLE(CS42L56_NOISE_GATE_CTL, 0, + ARRAY_SIZE(ng_delay_text), ng_delay_text); + +static const struct snd_kcontrol_new cs42l56_snd_controls[] = { + + SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME, + CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xfd, adv_tlv), + SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1), + + SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME, + CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv), + SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1), + + SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME, + CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv), + SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1), + + SOC_SINGLE_TLV("Analog Advisory Volume", + CS42L56_ANAINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv), + SOC_SINGLE_TLV("Digital Advisory Volume", + CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv), + + SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME, + CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0xfd, pga_tlv), + SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR, + CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv), + SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1), + SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1), + + SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME, + CS42L56_HPA_VOLUME, 0, 0x44, 0x55, hl_tlv), + SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME, + CS42L56_LOA_VOLUME, 0, 0x44, 0x55, hl_tlv), + + SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL, + 0, 0x00, 1, tone_tlv), + SOC_SINGLE_TLV("Treble Shelving Volume", CS42L56_TONE_CTL, + 4, 0x00, 1, tone_tlv), + + SOC_DOUBLE_TLV("PGA Preamp Volume", CS42L56_GAIN_BIAS_CTL, + 4, 6, 0x02, 1, preamp_tlv), + + SOC_SINGLE("DSP Switch", CS42L56_PLAYBACK_CTL, 7, 1, 1), + SOC_SINGLE("Gang Playback Switch", CS42L56_PLAYBACK_CTL, 4, 1, 1), + SOC_SINGLE("Gang ADC Switch", CS42L56_MISC_ADC_CTL, 7, 1, 1), + SOC_SINGLE("Gang PGA Switch", CS42L56_MISC_ADC_CTL, 6, 1, 1), + + SOC_SINGLE("PCMA Invert", CS42L56_PLAYBACK_CTL, 2, 1, 1), + SOC_SINGLE("PCMB Invert", CS42L56_PLAYBACK_CTL, 3, 1, 1), + SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1), + SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1), + + SOC_ENUM("PCMA Swap", pcma_swap_enum), + SOC_ENUM("PCMB Swap", pcmb_swap_enum), + SOC_ENUM("ADCA Swap", adca_swap_enum), + SOC_ENUM("ADCB Swap", adcb_swap_enum), + + SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1), + SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1), + SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum), + SOC_ENUM("HPFB Corner Freq", hpfb_freq_enum), + + SOC_SINGLE("Analog Soft Ramp", CS42L56_MISC_CTL, 4, 1, 1), + SOC_DOUBLE("Analog Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC, + 7, 5, 1, 1), + SOC_SINGLE("Analog Zero Cross", CS42L56_MISC_CTL, 3, 1, 1), + SOC_DOUBLE("Analog Zero Cross Disable", CS42L56_ALC_LIM_SFT_ZC, + 6, 4, 1, 1), + SOC_SINGLE("Digital Soft Ramp", CS42L56_MISC_CTL, 2, 1, 1), + SOC_SINGLE("Digital Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC, + 3, 1, 1), + + SOC_SINGLE("HL Deemphasis", CS42L56_PLAYBACK_CTL, 6, 1, 1), + + SOC_SINGLE("ALC Switch", CS42L56_ALC_EN_ATTACK_RATE, 6, 1, 1), + SOC_SINGLE("ALC Limit All Switch", CS42L56_ALC_RELEASE_RATE, 7, 1, 1), + SOC_SINGLE_RANGE("ALC Attack", CS42L56_ALC_EN_ATTACK_RATE, + 0, 0, 0x3f, 0), + SOC_SINGLE_RANGE("ALC Release", CS42L56_ALC_RELEASE_RATE, + 0, 0x3f, 0, 0), + SOC_SINGLE_TLV("ALC MAX", CS42L56_ALC_THRESHOLD, + 5, 0x07, 1, alc_tlv), + SOC_SINGLE_TLV("ALC MIN", CS42L56_ALC_THRESHOLD, + 2, 0x07, 1, alc_tlv), + + SOC_SINGLE("Limiter Switch", CS42L56_LIM_CTL_RELEASE_RATE, 7, 1, 1), + SOC_SINGLE("Limit All Switch", CS42L56_LIM_CTL_RELEASE_RATE, 6, 1, 1), + SOC_SINGLE_RANGE("Limiter Attack", CS42L56_LIM_ATTACK_RATE, + 0, 0, 0x3f, 0), + SOC_SINGLE_RANGE("Limiter Release", CS42L56_LIM_CTL_RELEASE_RATE, + 0, 0x3f, 0, 0), + SOC_SINGLE_TLV("Limiter MAX", CS42L56_LIM_THRESHOLD_CTL, + 5, 0x07, 1, alc_tlv), + SOC_SINGLE_TLV("Limiter Cushion", CS42L56_ALC_THRESHOLD, + 2, 0x07, 1, alc_tlv), + + SOC_SINGLE("NG Switch", CS42L56_NOISE_GATE_CTL, 6, 1, 1), + SOC_SINGLE("NG All Switch", CS42L56_NOISE_GATE_CTL, 7, 1, 1), + SOC_SINGLE("NG Boost Switch", CS42L56_NOISE_GATE_CTL, 5, 1, 1), + SOC_SINGLE_TLV("NG Unboost Threshold", CS42L56_NOISE_GATE_CTL, + 2, 0x07, 1, ngnb_tlv), + SOC_SINGLE_TLV("NG Boost Threshold", CS42L56_NOISE_GATE_CTL, + 2, 0x07, 1, ngb_tlv), + SOC_ENUM("NG Delay", ng_delay_enum), + + SOC_ENUM("Beep Config", beep_config_enum), + SOC_ENUM("Beep Pitch", beep_pitch_enum), + SOC_ENUM("Beep on Time", beep_ontime_enum), + SOC_ENUM("Beep off Time", beep_offtime_enum), + SOC_SINGLE_SX_TLV("Beep Volume", CS42L56_BEEP_FREQ_OFFTIME, + 0, 0x07, 0x23, beep_tlv), + SOC_SINGLE("Beep Tone Ctl Switch", CS42L56_BEEP_TONE_CFG, 0, 1, 1), + SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum), + SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum), + +}; + +static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = { + + SND_SOC_DAPM_SIGGEN("Beep"), + SND_SOC_DAPM_SUPPLY("VBUF", CS42L56_PWRCTL_1, 5, 1, NULL, 0), + SND_SOC_DAPM_MICBIAS("MIC1 Bias", CS42L56_PWRCTL_1, 4, 1), + SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L56_PWRCTL_1, 3, 1, NULL, 0), + + SND_SOC_DAPM_INPUT("AIN1A"), + SND_SOC_DAPM_INPUT("AIN2A"), + SND_SOC_DAPM_INPUT("AIN1B"), + SND_SOC_DAPM_INPUT("AIN2B"), + SND_SOC_DAPM_INPUT("AIN3A"), + SND_SOC_DAPM_INPUT("AIN3B"), + + SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MUX("Digital Output Mux", SND_SOC_NOPM, + 0, 0, &dig_mux), + + SND_SOC_DAPM_PGA("PGAA", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGAB", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX("PGAA Input Mux", + SND_SOC_NOPM, 0, 0, &pgaa_mux), + SND_SOC_DAPM_MUX("PGAB Input Mux", + SND_SOC_NOPM, 0, 0, &pgab_mux), + + SND_SOC_DAPM_MUX("ADCA Mux", SND_SOC_NOPM, + 0, 0, &adca_mux), + SND_SOC_DAPM_MUX("ADCB Mux", SND_SOC_NOPM, + 0, 0, &adcb_mux), + + SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1), + SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1), + + SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("HPA"), + SND_SOC_DAPM_OUTPUT("LOA"), + SND_SOC_DAPM_OUTPUT("HPB"), + SND_SOC_DAPM_OUTPUT("LOB"), + + SND_SOC_DAPM_SWITCH("Headphone Right", + CS42L56_PWRCTL_2, 4, 1, &hpb_switch), + SND_SOC_DAPM_SWITCH("Headphone Left", + CS42L56_PWRCTL_2, 6, 1, &hpa_switch), + + SND_SOC_DAPM_SWITCH("Lineout Right", + CS42L56_PWRCTL_2, 0, 1, &lob_switch), + SND_SOC_DAPM_SWITCH("Lineout Left", + CS42L56_PWRCTL_2, 2, 1, &loa_switch), + + SND_SOC_DAPM_MUX("LINEOUTA Input Mux", SND_SOC_NOPM, + 0, 0, &lineouta_input), + SND_SOC_DAPM_MUX("LINEOUTB Input Mux", SND_SOC_NOPM, + 0, 0, &lineoutb_input), + SND_SOC_DAPM_MUX("HPA Input Mux", SND_SOC_NOPM, + 0, 0, &hpa_input), + SND_SOC_DAPM_MUX("HPB Input Mux", SND_SOC_NOPM, + 0, 0, &hpb_input), + +}; + +static const struct snd_soc_dapm_route cs42l56_audio_map[] = { + + {"HiFi Capture", "DSP", "Digital Output Mux"}, + {"HiFi Capture", "ADC", "Digital Output Mux"}, + + {"Digital Output Mux", NULL, "ADCA"}, + {"Digital Output Mux", NULL, "ADCB"}, + + {"ADCB", NULL, "ADCB Mux"}, + {"ADCA", NULL, "ADCA Mux"}, + + {"ADCA Mux", NULL, "AIN3A"}, + {"ADCA Mux", NULL, "AIN2A"}, + {"ADCA Mux", NULL, "AIN1A"}, + {"ADCA Mux", NULL, "PGAA"}, + {"ADCB Mux", NULL, "AIN3B"}, + {"ADCB Mux", NULL, "AIN2B"}, + {"ADCB Mux", NULL, "AIN1B"}, + {"ADCB Mux", NULL, "PGAB"}, + + {"PGAA", "AIN1A", "PGAA Input Mux"}, + {"PGAA", "AIN2A", "PGAA Input Mux"}, + {"PGAA", "AIN3A", "PGAA Input Mux"}, + {"PGAB", "AIN1B", "PGAB Input Mux"}, + {"PGAB", "AIN2B", "PGAB Input Mux"}, + {"PGAB", "AIN3B", "PGAB Input Mux"}, + + {"PGAA Input Mux", NULL, "AIN1A"}, + {"PGAA Input Mux", NULL, "AIN2A"}, + {"PGAA Input Mux", NULL, "AIN3A"}, + {"PGAB Input Mux", NULL, "AIN1B"}, + {"PGAB Input Mux", NULL, "AIN2B"}, + {"PGAB Input Mux", NULL, "AIN3B"}, + + {"LOB", NULL, "Lineout Right"}, + {"LOA", NULL, "Lineout Left"}, + + {"Lineout Right", "Switch", "LINEOUTB Input Mux"}, + {"Lineout Left", "Switch", "LINEOUTA Input Mux"}, + + {"LINEOUTA Input Mux", "PGAA", "PGAA"}, + {"LINEOUTB Input Mux", "PGAB", "PGAB"}, + {"LINEOUTA Input Mux", "DACA", "DACA"}, + {"LINEOUTB Input Mux", "DACB", "DACB"}, + + {"HPA", NULL, "Headphone Left"}, + {"HPB", NULL, "Headphone Right"}, + + {"Headphone Right", "Switch", "HPB Input Mux"}, + {"Headphone Left", "Switch", "HPA Input Mux"}, + + {"HPA Input Mux", "PGAA", "PGAA"}, + {"HPB Input Mux", "PGAB", "PGAB"}, + {"HPA Input Mux", "DACA", "DACA"}, + {"HPB Input Mux", "DACB", "DACB"}, + + {"DACB", NULL, "HiFi Playback"}, + {"DACA", NULL, "HiFi Playback"}, + +}; + +struct cs42l56_clk_para { + u32 mclk; + u32 srate; + u8 ratio; +}; + +static const struct cs42l56_clk_para clk_ratio_table[] = { + /* 8k */ + { 6000000, 8000, CS42L56_MCLK_LRCLK_768 }, + { 6144000, 8000, CS42L56_MCLK_LRCLK_750 }, + { 12000000, 8000, CS42L56_MCLK_LRCLK_768 }, + { 12288000, 8000, CS42L56_MCLK_LRCLK_750 }, + { 24000000, 8000, CS42L56_MCLK_LRCLK_768 }, + { 24576000, 8000, CS42L56_MCLK_LRCLK_750 }, + /* 11.025k */ + { 5644800, 11025, CS42L56_MCLK_LRCLK_512}, + { 11289600, 11025, CS42L56_MCLK_LRCLK_512}, + { 22579200, 11025, CS42L56_MCLK_LRCLK_512 }, + /* 11.0294k */ + { 6000000, 110294, CS42L56_MCLK_LRCLK_544 }, + { 12000000, 110294, CS42L56_MCLK_LRCLK_544 }, + { 24000000, 110294, CS42L56_MCLK_LRCLK_544 }, + /* 12k */ + { 6000000, 12000, CS42L56_MCLK_LRCLK_500 }, + { 6144000, 12000, CS42L56_MCLK_LRCLK_512 }, + { 12000000, 12000, CS42L56_MCLK_LRCLK_500 }, + { 12288000, 12000, CS42L56_MCLK_LRCLK_512 }, + { 24000000, 12000, CS42L56_MCLK_LRCLK_500 }, + { 24576000, 12000, CS42L56_MCLK_LRCLK_512 }, + /* 16k */ + { 6000000, 16000, CS42L56_MCLK_LRCLK_375 }, + { 6144000, 16000, CS42L56_MCLK_LRCLK_384 }, + { 12000000, 16000, CS42L56_MCLK_LRCLK_375 }, + { 12288000, 16000, CS42L56_MCLK_LRCLK_384 }, + { 24000000, 16000, CS42L56_MCLK_LRCLK_375 }, + { 24576000, 16000, CS42L56_MCLK_LRCLK_384 }, + /* 22.050k */ + { 5644800, 22050, CS42L56_MCLK_LRCLK_256 }, + { 11289600, 22050, CS42L56_MCLK_LRCLK_256 }, + { 22579200, 22050, CS42L56_MCLK_LRCLK_256 }, + /* 22.0588k */ + { 6000000, 220588, CS42L56_MCLK_LRCLK_272 }, + { 12000000, 220588, CS42L56_MCLK_LRCLK_272 }, + { 24000000, 220588, CS42L56_MCLK_LRCLK_272 }, + /* 24k */ + { 6000000, 24000, CS42L56_MCLK_LRCLK_250 }, + { 6144000, 24000, CS42L56_MCLK_LRCLK_256 }, + { 12000000, 24000, CS42L56_MCLK_LRCLK_250 }, + { 12288000, 24000, CS42L56_MCLK_LRCLK_256 }, + { 24000000, 24000, CS42L56_MCLK_LRCLK_250 }, + { 24576000, 24000, CS42L56_MCLK_LRCLK_256 }, + /* 32k */ + { 6000000, 32000, CS42L56_MCLK_LRCLK_187P5 }, + { 6144000, 32000, CS42L56_MCLK_LRCLK_192 }, + { 12000000, 32000, CS42L56_MCLK_LRCLK_187P5 }, + { 12288000, 32000, CS42L56_MCLK_LRCLK_192 }, + { 24000000, 32000, CS42L56_MCLK_LRCLK_187P5 }, + { 24576000, 32000, CS42L56_MCLK_LRCLK_192 }, + /* 44.118k */ + { 6000000, 44118, CS42L56_MCLK_LRCLK_136 }, + { 12000000, 44118, CS42L56_MCLK_LRCLK_136 }, + { 24000000, 44118, CS42L56_MCLK_LRCLK_136 }, + /* 44.1k */ + { 5644800, 44100, CS42L56_MCLK_LRCLK_128 }, + { 11289600, 44100, CS42L56_MCLK_LRCLK_128 }, + { 22579200, 44100, CS42L56_MCLK_LRCLK_128 }, + /* 48k */ + { 6000000, 48000, CS42L56_MCLK_LRCLK_125 }, + { 6144000, 48000, CS42L56_MCLK_LRCLK_128 }, + { 12000000, 48000, CS42L56_MCLK_LRCLK_125 }, + { 12288000, 48000, CS42L56_MCLK_LRCLK_128 }, + { 24000000, 48000, CS42L56_MCLK_LRCLK_125 }, + { 24576000, 48000, CS42L56_MCLK_LRCLK_128 }, +}; + +static int cs42l56_get_mclk_ratio(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clk_ratio_table); i++) { + if (clk_ratio_table[i].mclk == mclk && + clk_ratio_table[i].srate == rate) + return clk_ratio_table[i].ratio; + } + return -EINVAL; +} + +static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + + switch (freq) { + case CS42L56_MCLK_5P6448MHZ: + case CS42L56_MCLK_6MHZ: + case CS42L56_MCLK_6P144MHZ: + cs42l56->mclk_div2 = 0; + cs42l56->mclk_prediv = 0; + break; + case CS42L56_MCLK_11P2896MHZ: + case CS42L56_MCLK_12MHZ: + case CS42L56_MCLK_12P288MHZ: + cs42l56->mclk_div2 = 1; + cs42l56->mclk_prediv = 0; + break; + case CS42L56_MCLK_22P5792MHZ: + case CS42L56_MCLK_24MHZ: + case CS42L56_MCLK_24P576MHZ: + cs42l56->mclk_div2 = 1; + cs42l56->mclk_prediv = 1; + break; + default: + return -EINVAL; + } + cs42l56->mclk = freq; + + snd_soc_update_bits(codec, CS42L56_CLKCTL_1, + CS42L56_MCLK_PREDIV_MASK, + cs42l56->mclk_prediv); + snd_soc_update_bits(codec, CS42L56_CLKCTL_1, + CS42L56_MCLK_DIV2_MASK, + cs42l56->mclk_div2); + + return 0; +} + +static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + cs42l56->iface = CS42L56_MASTER_MODE; + break; + case SND_SOC_DAIFMT_CBS_CFS: + cs42l56->iface = CS42L56_SLAVE_MODE; + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + cs42l56->iface_fmt = CS42L56_DIG_FMT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + cs42l56->iface_fmt = CS42L56_DIG_FMT_LEFT_J; + break; + default: + return -EINVAL; + } + + /* sclk inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + cs42l56->iface_inv = 0; + break; + case SND_SOC_DAIFMT_IB_NF: + cs42l56->iface_inv = CS42L56_SCLK_INV; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, CS42L56_CLKCTL_1, + CS42L56_MS_MODE_MASK, cs42l56->iface); + snd_soc_update_bits(codec, CS42L56_SERIAL_FMT, + CS42L56_DIG_FMT_MASK, cs42l56->iface_fmt); + snd_soc_update_bits(codec, CS42L56_CLKCTL_1, + CS42L56_SCLK_INV_MASK, cs42l56->iface_inv); + return 0; +} + +static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + + if (mute) { + /* Hit the DSP Mixer first */ + snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL, + CS42L56_ADCAMIX_MUTE_MASK | + CS42L56_ADCBMIX_MUTE_MASK | + CS42L56_PCMAMIX_MUTE_MASK | + CS42L56_PCMBMIX_MUTE_MASK | + CS42L56_MSTB_MUTE_MASK | + CS42L56_MSTA_MUTE_MASK, + CS42L56_MUTE); + /* Mute ADC's */ + snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL, + CS42L56_ADCA_MUTE_MASK | + CS42L56_ADCB_MUTE_MASK, + CS42L56_MUTE); + /* HP And LO */ + snd_soc_update_bits(codec, CS42L56_HPA_VOLUME, + CS42L56_HP_MUTE_MASK, + CS42L56_MUTE); + snd_soc_update_bits(codec, CS42L56_HPB_VOLUME, + CS42L56_HP_MUTE_MASK, + CS42L56_MUTE); + snd_soc_update_bits(codec, CS42L56_LOA_VOLUME, + CS42L56_LO_MUTE_MASK, + CS42L56_MUTE); + snd_soc_update_bits(codec, CS42L56_LOB_VOLUME, + CS42L56_LO_MUTE_MASK, + CS42L56_MUTE); + + + } else { + snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL, + CS42L56_ADCAMIX_MUTE_MASK | + CS42L56_ADCBMIX_MUTE_MASK | + CS42L56_PCMAMIX_MUTE_MASK | + CS42L56_PCMBMIX_MUTE_MASK | + CS42L56_MSTB_MUTE_MASK | + CS42L56_MSTA_MUTE_MASK, + CS42L56_UNMUTE); + snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL, + CS42L56_ADCA_MUTE_MASK | + CS42L56_ADCB_MUTE_MASK, + CS42L56_UNMUTE); + snd_soc_update_bits(codec, CS42L56_HPA_VOLUME, + CS42L56_HP_MUTE_MASK, + CS42L56_UNMUTE); + snd_soc_update_bits(codec, CS42L56_HPB_VOLUME, + CS42L56_HP_MUTE_MASK, + CS42L56_UNMUTE); + snd_soc_update_bits(codec, CS42L56_LOA_VOLUME, + CS42L56_LO_MUTE_MASK, + CS42L56_UNMUTE); + snd_soc_update_bits(codec, CS42L56_LOB_VOLUME, + CS42L56_LO_MUTE_MASK, + CS42L56_UNMUTE); + } + return 0; +} + +static int cs42l56_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + int ratio; + + ratio = cs42l56_get_mclk_ratio(cs42l56->mclk, params_rate(params)); + if (ratio >= 0) { + snd_soc_update_bits(codec, CS42L56_CLKCTL_2, + CS42L56_CLK_RATIO_MASK, ratio); + } else { + dev_err(codec->dev, "unsupported mclk/sclk/lrclk ratio\n"); + return -EINVAL; + } + + return 0; +} + +static int cs42l56_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + snd_soc_update_bits(codec, CS42L56_CLKCTL_1, + CS42L56_MCLK_DIS_MASK, 0); + snd_soc_update_bits(codec, CS42L56_PWRCTL_1, + CS42L56_PDN_ALL_MASK, 0); + break; + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + regcache_cache_only(cs42l56->regmap, false); + regcache_sync(cs42l56->regmap); + ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies), + cs42l56->supplies); + if (ret != 0) { + dev_err(cs42l56->dev, + "Failed to enable regulators: %d\n", + ret); + return ret; + } + } + snd_soc_update_bits(codec, CS42L56_PWRCTL_1, + CS42L56_PDN_ALL_MASK, 1); + break; + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, CS42L56_PWRCTL_1, + CS42L56_PDN_ALL_MASK, 1); + snd_soc_update_bits(codec, CS42L56_CLKCTL_1, + CS42L56_MCLK_DIS_MASK, 1); + regcache_cache_only(cs42l56->regmap, true); + regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies), + cs42l56->supplies); + break; + } + codec->dapm.bias_level = level; + + return 0; +} + +#define CS42L56_RATES (SNDRV_PCM_RATE_8000_48000) + +#define CS42L56_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + + +static struct snd_soc_dai_ops cs42l56_ops = { + .hw_params = cs42l56_pcm_hw_params, + .digital_mute = cs42l56_digital_mute, + .set_fmt = cs42l56_set_dai_fmt, + .set_sysclk = cs42l56_set_sysclk, +}; + +static struct snd_soc_dai_driver cs42l56_dai = { + .name = "cs42l56", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = CS42L56_RATES, + .formats = CS42L56_FORMATS, + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = CS42L56_RATES, + .formats = CS42L56_FORMATS, + }, + .ops = &cs42l56_ops, +}; + +static int cs42l56_suspend(struct snd_soc_codec *codec) +{ + cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int cs42l56_resume(struct snd_soc_codec *codec) +{ + cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} + +static int beep_freq[] = { + 261, 522, 585, 667, 706, 774, 889, 1000, + 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 +}; + +static void cs42l56_beep_work(struct work_struct *work) +{ + struct cs42l56_private *cs42l56 = + container_of(work, struct cs42l56_private, beep_work); + struct snd_soc_codec *codec = cs42l56->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + int i; + int val = 0; + int best = 0; + + if (cs42l56->beep_rate) { + for (i = 0; i < ARRAY_SIZE(beep_freq); i++) { + if (abs(cs42l56->beep_rate - beep_freq[i]) < + abs(cs42l56->beep_rate - beep_freq[best])) + best = i; + } + + dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n", + beep_freq[best], cs42l56->beep_rate); + + val = (best << CS42L56_BEEP_RATE_SHIFT); + + snd_soc_dapm_enable_pin(dapm, "Beep"); + } else { + dev_dbg(codec->dev, "Disabling beep\n"); + snd_soc_dapm_disable_pin(dapm, "Beep"); + } + + snd_soc_update_bits(codec, CS42L56_BEEP_FREQ_ONTIME, + CS42L56_BEEP_FREQ_MASK, val); + + snd_soc_dapm_sync(dapm); +} + +/* For usability define a way of injecting beep events for the device - + * many systems will not have a keyboard. + */ +static int cs42l56_beep_event(struct input_dev *dev, unsigned int type, + unsigned int code, int hz) +{ + struct snd_soc_codec *codec = input_get_drvdata(dev); + struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "Beep event %x %x\n", code, hz); + + switch (code) { + case SND_BELL: + if (hz) + hz = 261; + case SND_TONE: + break; + default: + return -1; + } + + /* Kick the beep from a workqueue */ + cs42l56->beep_rate = hz; + schedule_work(&cs42l56->beep_work); + return 0; +} + +static ssize_t cs42l56_beep_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cs42l56_private *cs42l56 = dev_get_drvdata(dev); + long int time; + int ret; + + ret = kstrtol(buf, 10, &time); + if (ret != 0) + return ret; + + input_event(cs42l56->beep, EV_SND, SND_TONE, time); + + return count; +} + +static DEVICE_ATTR(beep, 0200, NULL, cs42l56_beep_set); + +static void cs42l56_init_beep(struct snd_soc_codec *codec) +{ + struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + int ret; + + cs42l56->beep = devm_input_allocate_device(codec->dev); + if (!cs42l56->beep) { + dev_err(codec->dev, "Failed to allocate beep device\n"); + return; + } + + INIT_WORK(&cs42l56->beep_work, cs42l56_beep_work); + cs42l56->beep_rate = 0; + + cs42l56->beep->name = "CS42L56 Beep Generator"; + cs42l56->beep->phys = dev_name(codec->dev); + cs42l56->beep->id.bustype = BUS_I2C; + + cs42l56->beep->evbit[0] = BIT_MASK(EV_SND); + cs42l56->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); + cs42l56->beep->event = cs42l56_beep_event; + cs42l56->beep->dev.parent = codec->dev; + input_set_drvdata(cs42l56->beep, codec); + + ret = input_register_device(cs42l56->beep); + if (ret != 0) { + cs42l56->beep = NULL; + dev_err(codec->dev, "Failed to register beep device\n"); + } + + ret = device_create_file(codec->dev, &dev_attr_beep); + if (ret != 0) { + dev_err(codec->dev, "Failed to create keyclick file: %d\n", + ret); + } +} + +static void cs42l56_free_beep(struct snd_soc_codec *codec) +{ + struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + + device_remove_file(codec->dev, &dev_attr_beep); + cancel_work_sync(&cs42l56->beep_work); + cs42l56->beep = NULL; + + snd_soc_update_bits(codec, CS42L56_BEEP_TONE_CFG, + CS42L56_BEEP_EN_MASK, 0); +} + +static int cs42l56_probe(struct snd_soc_codec *codec) +{ + cs42l56_init_beep(codec); + + cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} + +static int cs42l56_remove(struct snd_soc_codec *codec) +{ + struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); + + cs42l56_free_beep(codec); + cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); + regulator_bulk_free(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies); + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { + .probe = cs42l56_probe, + .remove = cs42l56_remove, + .suspend = cs42l56_suspend, + .resume = cs42l56_resume, + .set_bias_level = cs42l56_set_bias_level, + + .dapm_widgets = cs42l56_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets), + .dapm_routes = cs42l56_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs42l56_audio_map), + + .controls = cs42l56_snd_controls, + .num_controls = ARRAY_SIZE(cs42l56_snd_controls), +}; + +static struct regmap_config cs42l56_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS42L56_MAX_REGISTER, + .reg_defaults = cs42l56_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults), + .readable_reg = cs42l56_readable_register, + .volatile_reg = cs42l56_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int cs42l56_handle_of_data(struct i2c_client *i2c_client, + struct cs42l56_platform_data *pdata) +{ + struct device_node *np = i2c_client->dev.of_node; + u32 val32; + + if (of_property_read_bool(np, "cirrus,ain1a-reference-cfg")) + pdata->ain1a_ref_cfg = true; + + if (of_property_read_bool(np, "cirrus,ain2a-reference-cfg")) + pdata->ain2a_ref_cfg = true; + + if (of_property_read_bool(np, "cirrus,ain1b-reference-cfg")) + pdata->ain1b_ref_cfg = true; + + if (of_property_read_bool(np, "cirrus,ain2b-reference-cfg")) + pdata->ain2b_ref_cfg = true; + + if (of_property_read_u32(np, "cirrus,micbias-lvl", &val32) >= 0) + pdata->micbias_lvl = val32; + + if (of_property_read_u32(np, "cirrus,chgfreq-divisor", &val32) >= 0) + pdata->chgfreq = val32; + + if (of_property_read_u32(np, "cirrus,adaptive-pwr-cfg", &val32) >= 0) + pdata->adaptive_pwr = val32; + + if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0) + pdata->hpfa_freq = val32; + + if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0) + pdata->hpfb_freq = val32; + + pdata->gpio_nreset = of_get_named_gpio(np, "cirrus,gpio-nreset", 0); + + return 0; +} + +static int cs42l56_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct cs42l56_private *cs42l56; + struct cs42l56_platform_data *pdata = + dev_get_platdata(&i2c_client->dev); + int ret, i; + unsigned int devid = 0; + unsigned int alpha_rev, metal_rev; + unsigned int reg; + + cs42l56 = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs42l56_private), + GFP_KERNEL); + if (cs42l56 == NULL) + return -ENOMEM; + cs42l56->dev = &i2c_client->dev; + + cs42l56->regmap = devm_regmap_init_i2c(i2c_client, &cs42l56_regmap); + if (IS_ERR(cs42l56->regmap)) { + ret = PTR_ERR(cs42l56->regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + if (pdata) { + cs42l56->pdata = *pdata; + } else { + pdata = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs42l56_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(&i2c_client->dev, + "could not allocate pdata\n"); + return -ENOMEM; + } + if (i2c_client->dev.of_node) { + ret = cs42l56_handle_of_data(i2c_client, + &cs42l56->pdata); + if (ret != 0) + return ret; + } + cs42l56->pdata = *pdata; + } + + if (cs42l56->pdata.gpio_nreset) { + ret = gpio_request_one(cs42l56->pdata.gpio_nreset, + GPIOF_OUT_INIT_HIGH, "CS42L56 /RST"); + if (ret < 0) { + dev_err(&i2c_client->dev, + "Failed to request /RST %d: %d\n", + cs42l56->pdata.gpio_nreset, ret); + return ret; + } + gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 0); + gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 1); + } + + + i2c_set_clientdata(i2c_client, cs42l56); + + for (i = 0; i < ARRAY_SIZE(cs42l56->supplies); i++) + cs42l56->supplies[i].supply = cs42l56_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c_client->dev, + ARRAY_SIZE(cs42l56->supplies), + cs42l56->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies), + cs42l56->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to enable supplies: %d\n", ret); + return ret; + } + + regcache_cache_bypass(cs42l56->regmap, true); + + ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, ®); + devid = reg & CS42L56_CHIP_ID_MASK; + if (devid != CS42L56_DEVID) { + dev_err(&i2c_client->dev, + "CS42L56 Device ID (%X). Expected %X\n", + devid, CS42L56_DEVID); + goto err_enable; + } + alpha_rev = reg & CS42L56_AREV_MASK; + metal_rev = reg & CS42L56_MTLREV_MASK; + + dev_info(&i2c_client->dev, "Cirrus Logic CS42L56 "); + dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n", + alpha_rev, metal_rev); + + regcache_cache_bypass(cs42l56->regmap, false); + + if (cs42l56->pdata.ain1a_ref_cfg) + regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, + CS42L56_AIN1A_REF_MASK, 1); + + if (cs42l56->pdata.ain1b_ref_cfg) + regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, + CS42L56_AIN1B_REF_MASK, 1); + + if (cs42l56->pdata.ain2a_ref_cfg) + regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, + CS42L56_AIN2A_REF_MASK, 1); + + if (cs42l56->pdata.ain2b_ref_cfg) + regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, + CS42L56_AIN2B_REF_MASK, 1); + + if (cs42l56->pdata.micbias_lvl) + regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL, + CS42L56_MIC_BIAS_MASK, + cs42l56->pdata.micbias_lvl); + + if (cs42l56->pdata.chgfreq) + regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL, + CS42L56_CHRG_FREQ_MASK, + cs42l56->pdata.chgfreq); + + if (cs42l56->pdata.hpfb_freq) + regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL, + CS42L56_HPFB_FREQ_MASK, + cs42l56->pdata.hpfb_freq); + + if (cs42l56->pdata.hpfa_freq) + regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL, + CS42L56_HPFA_FREQ_MASK, + cs42l56->pdata.hpfa_freq); + + if (cs42l56->pdata.adaptive_pwr) + regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL, + CS42L56_ADAPT_PWR_MASK, + cs42l56->pdata.adaptive_pwr); + + ret = snd_soc_register_codec(&i2c_client->dev, + &soc_codec_dev_cs42l56, &cs42l56_dai, 1); + if (ret < 0) + return ret; + + return 0; + +err_enable: + regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies), + cs42l56->supplies); + return ret; +} + +static int cs42l56_i2c_remove(struct i2c_client *client) +{ + struct cs42l56_private *cs42l56 = i2c_get_clientdata(client); + + snd_soc_unregister_codec(&client->dev); + regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies), + cs42l56->supplies); + return 0; +} + +static const struct of_device_id cs42l56_of_match[] = { + { .compatible = "cirrus,cs42l56", }, + { } +}; +MODULE_DEVICE_TABLE(of, cs42l56_of_match); + + +static const struct i2c_device_id cs42l56_id[] = { + { "cs42l56", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cs42l56_id); + +static struct i2c_driver cs42l56_i2c_driver = { + .driver = { + .name = "cs42l56", + .owner = THIS_MODULE, + .of_match_table = cs42l56_of_match, + }, + .id_table = cs42l56_id, + .probe = cs42l56_i2c_probe, + .remove = cs42l56_i2c_remove, +}; + +module_i2c_driver(cs42l56_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L56 driver"); +MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l56.h b/sound/soc/codecs/cs42l56.h new file mode 100644 index 00000000000000..ad2b50a90b1631 --- /dev/null +++ b/sound/soc/codecs/cs42l56.h @@ -0,0 +1,175 @@ +/* + * cs42l52.h -- CS42L56 ALSA SoC audio driver + * + * Copyright 2014 CirrusLogic, Inc. + * + * Author: Brian Austin + * + * 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 __CS42L56_H__ +#define __CS42L56_H__ + +#define CS42L56_CHIP_ID_1 0x01 +#define CS42L56_CHIP_ID_2 0x02 +#define CS42L56_PWRCTL_1 0x03 +#define CS42L56_PWRCTL_2 0x04 +#define CS42L56_CLKCTL_1 0x05 +#define CS42L56_CLKCTL_2 0x06 +#define CS42L56_SERIAL_FMT 0x07 +#define CS42L56_CLASSH_CTL 0x08 +#define CS42L56_MISC_CTL 0x09 +#define CS42L56_INT_STATUS 0x0a +#define CS42L56_PLAYBACK_CTL 0x0b +#define CS42L56_DSP_MUTE_CTL 0x0c +#define CS42L56_ADCA_MIX_VOLUME 0x0d +#define CS42L56_ADCB_MIX_VOLUME 0x0e +#define CS42L56_PCMA_MIX_VOLUME 0x0f +#define CS42L56_PCMB_MIX_VOLUME 0x10 +#define CS42L56_ANAINPUT_ADV_VOLUME 0x11 +#define CS42L56_DIGINPUT_ADV_VOLUME 0x12 +#define CS42L56_MASTER_A_VOLUME 0x13 +#define CS42L56_MASTER_B_VOLUME 0x14 +#define CS42L56_BEEP_FREQ_ONTIME 0x15 +#define CS42L56_BEEP_FREQ_OFFTIME 0x16 +#define CS42L56_BEEP_TONE_CFG 0x17 +#define CS42L56_TONE_CTL 0x18 +#define CS42L56_CHAN_MIX_SWAP 0x19 +#define CS42L56_AIN_REFCFG_ADC_MUX 0x1a +#define CS42L56_HPF_CTL 0x1b +#define CS42L56_MISC_ADC_CTL 0x1c +#define CS42L56_GAIN_BIAS_CTL 0x1d +#define CS42L56_PGAA_MUX_VOLUME 0x1e +#define CS42L56_PGAB_MUX_VOLUME 0x1f +#define CS42L56_ADCA_ATTENUATOR 0x20 +#define CS42L56_ADCB_ATTENUATOR 0x21 +#define CS42L56_ALC_EN_ATTACK_RATE 0x22 +#define CS42L56_ALC_RELEASE_RATE 0x23 +#define CS42L56_ALC_THRESHOLD 0x24 +#define CS42L56_NOISE_GATE_CTL 0x25 +#define CS42L56_ALC_LIM_SFT_ZC 0x26 +#define CS42L56_AMUTE_HPLO_MUX 0x27 +#define CS42L56_HPA_VOLUME 0x28 +#define CS42L56_HPB_VOLUME 0x29 +#define CS42L56_LOA_VOLUME 0x2a +#define CS42L56_LOB_VOLUME 0x2b +#define CS42L56_LIM_THRESHOLD_CTL 0x2c +#define CS42L56_LIM_CTL_RELEASE_RATE 0x2d +#define CS42L56_LIM_ATTACK_RATE 0x2e + +/* Device ID and Rev ID Masks */ +#define CS42L56_DEVID 0x56 +#define CS42L56_CHIP_ID_MASK 0xff +#define CS42L56_AREV_MASK 0x1c +#define CS42L56_MTLREV_MASK 0x03 + +/* Power bit masks */ +#define CS42L56_PDN_ALL_MASK 0x01 +#define CS42L56_PDN_ADCA_MASK 0x02 +#define CS42L56_PDN_ADCB_MASK 0x04 +#define CS42L56_PDN_CHRG_MASK 0x08 +#define CS42L56_PDN_BIAS_MASK 0x10 +#define CS42L56_PDN_VBUF_MASK 0x20 +#define CS42L56_PDN_LOA_MASK 0x03 +#define CS42L56_PDN_LOB_MASK 0x0c +#define CS42L56_PDN_HPA_MASK 0x30 +#define CS42L56_PDN_HPB_MASK 0xc0 + +/* serial port and clk masks */ +#define CS42L56_MASTER_MODE 1 +#define CS42L56_SLAVE_MODE 0 +#define CS42L56_MS_MODE_MASK 0x40 +#define CS42L56_SCLK_INV 1 +#define CS42L56_SCLK_INV_MASK 0x20 +#define CS42L56_SCLK_MCLK_MASK 0x18 +#define CS42L56_MCLK_PREDIV_MASK 0x04 +#define CS42L56_MCLK_DIV2_MASK 0x02 +#define CS42L56_MCLK_DIS_MASK 0x01 +#define CS42L56_CLK_AUTO_MASK 0x20 +#define CS42L56_CLK_RATIO_MASK 0x1f +#define CS42L56_DIG_FMT_I2S 0 +#define CS42L56_DIG_FMT_LEFT_J 1 +#define CS42L56_DIG_FMT_MASK 0x08 + +/* Class H and misc ctl masks */ +#define CS42L56_ADAPT_PWR_MASK 0xc0 +#define CS42L56_CHRG_FREQ_MASK 0x0f +#define CS42L56_DIG_MUX_MASK 0x80 +#define CS42L56_ANLGSFT_MASK 0x10 +#define CS42L56_ANLGZC_MASK 0x08 +#define CS42L56_DIGSFT_MASK 0x04 +#define CS42L56_FREEZE_MASK 0x01 +#define CS42L56_MIC_BIAS_MASK 0x03 +#define CS42L56_HPFA_FREQ_MASK 0x03 +#define CS42L56_HPFB_FREQ_MASK 0xc0 +#define CS42L56_AIN1A_REF_MASK 0x10 +#define CS42L56_AIN2A_REF_MASK 0x40 +#define CS42L56_AIN1B_REF_MASK 0x20 +#define CS42L56_AIN2B_REF_MASK 0x80 + +/* Playback Capture ctl masks */ +#define CS42L56_PDN_DSP_MASK 0x80 +#define CS42L56_DEEMPH_MASK 0x40 +#define CS42L56_PLYBCK_GANG_MASK 0x10 +#define CS42L56_PCM_INV_MASK 0x0c +#define CS42L56_MUTE 1 +#define CS42L56_UNMUTE 0 +#define CS42L56_ADCAMIX_MUTE_MASK 0x40 +#define CS42L56_ADCBMIX_MUTE_MASK 0x80 +#define CS42L56_PCMAMIX_MUTE_MASK 0x10 +#define CS42L56_PCMBMIX_MUTE_MASK 0x20 +#define CS42L56_MSTB_MUTE_MASK 0x02 +#define CS42L56_MSTA_MUTE_MASK 0x01 +#define CS42L56_ADCA_MUTE_MASK 0x01 +#define CS42L56_ADCB_MUTE_MASK 0x02 +#define CS42L56_HP_MUTE_MASK 0x80 +#define CS42L56_LO_MUTE_MASK 0x80 + +/* Beep masks */ +#define CS42L56_BEEP_FREQ_MASK 0xf0 +#define CS42L56_BEEP_ONTIME_MASK 0x0f +#define CS42L56_BEEP_OFFTIME_MASK 0xe0 +#define CS42L56_BEEP_CFG_MASK 0xc0 +#define CS42L56_BEEP_TREBCF_MASK 0x18 +#define CS42L56_BEEP_BASSCF_MASK 0x06 +#define CS42L56_BEEP_TCEN_MASK 0x01 +#define CS42L56_BEEP_RATE_SHIFT 4 +#define CS42L56_BEEP_EN_MASK 0x3f + + +/* Supported MCLKS */ +#define CS42L56_MCLK_5P6448MHZ 5644800 +#define CS42L56_MCLK_6MHZ 6000000 +#define CS42L56_MCLK_6P144MHZ 6144000 +#define CS42L56_MCLK_11P2896MHZ 11289600 +#define CS42L56_MCLK_12MHZ 12000000 +#define CS42L56_MCLK_12P288MHZ 12288000 +#define CS42L56_MCLK_22P5792MHZ 22579200 +#define CS42L56_MCLK_24MHZ 24000000 +#define CS42L56_MCLK_24P576MHZ 24576000 + +/* Clock ratios */ +#define CS42L56_MCLK_LRCLK_128 0x08 +#define CS42L56_MCLK_LRCLK_125 0x09 +#define CS42L56_MCLK_LRCLK_136 0x0b +#define CS42L56_MCLK_LRCLK_192 0x0c +#define CS42L56_MCLK_LRCLK_187P5 0x0d +#define CS42L56_MCLK_LRCLK_256 0x10 +#define CS42L56_MCLK_LRCLK_250 0x11 +#define CS42L56_MCLK_LRCLK_272 0x13 +#define CS42L56_MCLK_LRCLK_384 0x14 +#define CS42L56_MCLK_LRCLK_375 0x15 +#define CS42L56_MCLK_LRCLK_512 0x18 +#define CS42L56_MCLK_LRCLK_500 0x19 +#define CS42L56_MCLK_LRCLK_544 0x1b +#define CS42L56_MCLK_LRCLK_750 0x1c +#define CS42L56_MCLK_LRCLK_768 0x1d + + +#define CS42L56_MAX_REGISTER 0x34 + +#endif diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 137e8ebc092c5a..21810e5f3321c8 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -335,7 +335,7 @@ static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel, static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); if (ucontrol->value.integer.value[0]) { /* Check if noise suppression is enabled */ @@ -358,7 +358,7 @@ static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol, static int da7210_put_noise_sup_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); u8 val; if (ucontrol->value.integer.value[0]) { diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 738fa18a50d2a8..9ec577f0edb4c0 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -345,7 +345,7 @@ static void da7213_alc_calib(struct snd_soc_codec *codec) static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); int ret; @@ -361,7 +361,7 @@ static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol, static int da7213_put_alc_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); /* Force ALC offset calibration if enabling ALC */ diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 48f3fef6848451..2fae31cb006745 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -332,7 +332,7 @@ static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum, static int da732x_hpf_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value; unsigned int reg = enum_ctrl->reg; unsigned int sel = ucontrol->value.integer.value[0]; @@ -360,7 +360,7 @@ static int da732x_hpf_set(struct snd_kcontrol *kcontrol, static int da732x_hpf_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value; unsigned int reg = enum_ctrl->reg; int val; diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 4ff06b50fbba78..ad19cc56702b46 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -484,7 +484,7 @@ static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val) static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); u8 reg_val, adc_left, adc_right, mic_left, mic_right; int avg_left_data, avg_right_data, offset_l, offset_r; diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c index 9cb1c7d3e1dca6..1087fd5f9917b0 100644 --- a/sound/soc/codecs/hdmi.c +++ b/sound/soc/codecs/hdmi.c @@ -20,6 +20,7 @@ */ #include #include +#include #include #define DRV_NAME "hdmi-audio-codec" diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index 4f048db9f55f1a..a924bb9d78860c 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -49,7 +49,7 @@ static const struct reg_default lm4857_default_regs[] = { static int lm4857_get_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = lm4857->mode; @@ -60,7 +60,7 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol, static int lm4857_set_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); uint8_t value = ucontrol->value.integer.value[0]; diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index ec481fc428c7c9..e1c196a4193033 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -43,7 +43,7 @@ static struct reg_default max9768_default_regs[] = { static int max9768_get_gpio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); int val = gpio_get_value_cansleep(max9768->mute_gpio); @@ -55,7 +55,7 @@ static int max9768_get_gpio(struct snd_kcontrol *kcontrol, static int max9768_set_gpio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]); diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index ef7cf89f562342..9134982807b5db 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -635,7 +635,7 @@ static SOC_ENUM_SINGLE_DECL(max98088_dai1_adc_filter_enum, static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); unsigned int sel = ucontrol->value.integer.value[0]; @@ -649,7 +649,7 @@ static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol, static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = max98088->mic1pre; @@ -659,7 +659,7 @@ static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol, static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); unsigned int sel = ucontrol->value.integer.value[0]; @@ -673,7 +673,7 @@ static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol, static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = max98088->mic2pre; @@ -1750,7 +1750,7 @@ static void max98088_setup_eq2(struct snd_soc_codec *codec) static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); struct max98088_pdata *pdata = max98088->pdata; int channel = max98088_get_channel(codec, kcontrol->id.name); @@ -1782,7 +1782,7 @@ static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol, static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); int channel = max98088_get_channel(codec, kcontrol->id.name); struct max98088_cdata *cdata; diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index f7b0b37aa85827..f3dd9791e73664 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -426,7 +427,7 @@ static const unsigned int max98090_rcv_lout_tlv[] = { static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; @@ -466,7 +467,7 @@ static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol, static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; @@ -875,7 +876,7 @@ static const char *dmic_mux_text[] = { "ADC", "DMIC" }; static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text); static const struct snd_kcontrol_new max98090_dmic_mux = - SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum); + SOC_DAPM_ENUM("DMIC Mux", dmic_mux_enum); static const char *max98090_micpre_text[] = { "Off", "On" }; @@ -1175,8 +1176,7 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { SND_SOC_DAPM_MUX("MIC2 Mux", SND_SOC_NOPM, 0, 0, &max98090_mic2_mux), - SND_SOC_DAPM_VIRT_MUX("DMIC Mux", SND_SOC_NOPM, - 0, 0, &max98090_dmic_mux), + SND_SOC_DAPM_MUX("DMIC Mux", SND_SOC_NOPM, 0, 0, &max98090_dmic_mux), SND_SOC_DAPM_PGA_E("MIC1 Input", M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT, 0, NULL, 0, max98090_micinput_event, diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 03f0536e6f6185..d6c1e4c19a5ab7 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -612,7 +612,7 @@ static SOC_ENUM_SINGLE_DECL(max98095_dai3_dac_filter_enum, static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); unsigned int sel = ucontrol->value.integer.value[0]; @@ -626,7 +626,7 @@ static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol, static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = max98095->mic1pre; @@ -636,7 +636,7 @@ static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol, static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); unsigned int sel = ucontrol->value.integer.value[0]; @@ -650,7 +650,7 @@ static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol, static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = max98095->mic2pre; @@ -1737,7 +1737,7 @@ static int max98095_get_eq_channel(const char *name) static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); struct max98095_pdata *pdata = max98095->pdata; int channel = max98095_get_eq_channel(kcontrol->id.name); @@ -1801,7 +1801,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); int channel = max98095_get_eq_channel(kcontrol->id.name); struct max98095_cdata *cdata; @@ -1891,7 +1891,7 @@ static int max98095_get_bq_channel(struct snd_soc_codec *codec, static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); struct max98095_pdata *pdata = max98095->pdata; int channel = max98095_get_bq_channel(codec, kcontrol->id.name); @@ -1952,7 +1952,7 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol, static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); int channel = max98095_get_bq_channel(codec, kcontrol->id.name); struct max98095_cdata *cdata; @@ -2399,10 +2399,17 @@ static const struct i2c_device_id max98095_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max98095_i2c_id); +static const struct of_device_id max98095_of_match[] = { + { .compatible = "maxim,max98095", }, + { } +}; +MODULE_DEVICE_TABLE(of, max98095_of_match); + static struct i2c_driver max98095_i2c_driver = { .driver = { .name = "max98095", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max98095_of_match), }, .probe = max98095_i2c_probe, .remove = max98095_i2c_remove, diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 2c59b1fb69dc98..9965277b595a33 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -22,6 +22,7 @@ */ #include #include +#include #include #include #include @@ -409,7 +410,7 @@ static const char * const adcl_enum_text[] = { static SOC_ENUM_SINGLE_VIRT_DECL(adcl_enum, adcl_enum_text); static const struct snd_kcontrol_new left_input_mux = - SOC_DAPM_ENUM_VIRT("Route", adcl_enum); + SOC_DAPM_ENUM("Route", adcl_enum); static const char * const adcr_enum_text[] = { "MC1R", "MC2", "RXINR", "TXIN", @@ -418,7 +419,7 @@ static const char * const adcr_enum_text[] = { static SOC_ENUM_SINGLE_VIRT_DECL(adcr_enum, adcr_enum_text); static const struct snd_kcontrol_new right_input_mux = - SOC_DAPM_ENUM_VIRT("Route", adcr_enum); + SOC_DAPM_ENUM("Route", adcr_enum); static const struct snd_kcontrol_new samp_ctl = SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0); @@ -478,9 +479,9 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = { SND_SOC_DAPM_SWITCH("MC2 Amp", MC13783_AUDIO_TX, 9, 0, &mc2_amp_ctl), SND_SOC_DAPM_SWITCH("TXIN Amp", MC13783_AUDIO_TX, 11, 0, &atx_amp_ctl), - SND_SOC_DAPM_VIRT_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0, &left_input_mux), - SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0, &right_input_mux), SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0, @@ -608,14 +609,6 @@ static struct snd_kcontrol_new mc13783_control_list[] = { static int mc13783_probe(struct snd_soc_codec *codec) { struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); - int ret; - - ret = snd_soc_codec_set_cache_io(codec, - dev_get_regmap(codec->dev->parent, NULL)); - if (ret != 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } /* these are the reset values */ mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893); @@ -735,9 +728,15 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = { } }; +static struct regmap *mc13783_get_regmap(struct device *dev) +{ + return dev_get_regmap(dev->parent, NULL); +} + static struct snd_soc_codec_driver soc_codec_dev_mc13783 = { .probe = mc13783_probe, .remove = mc13783_remove, + .get_regmap = mc13783_get_regmap, .controls = mc13783_control_list, .num_controls = ARRAY_SIZE(mc13783_control_list), .dapm_widgets = mc13783_dapm_widgets, @@ -750,6 +749,7 @@ static int __init mc13783_codec_probe(struct platform_device *pdev) { struct mc13783_priv *priv; struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data; + struct device_node *np; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -760,7 +760,17 @@ static int __init mc13783_codec_probe(struct platform_device *pdev) priv->adc_ssi_port = pdata->adc_ssi_port; priv->dac_ssi_port = pdata->dac_ssi_port; } else { - return -ENOSYS; + np = of_get_child_by_name(pdev->dev.parent->of_node, "codec"); + if (!np) + return -ENOSYS; + + ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port); + if (ret) + return ret; + + ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port); + if (ret) + return ret; } dev_set_drvdata(&pdev->dev, priv); diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index e427544183d7f2..a722a023c26280 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -115,7 +115,7 @@ static int pcm1681_set_deemph(struct snd_soc_codec *codec) static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = priv->deemph; @@ -126,7 +126,7 @@ static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol, static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); priv->deemph = ucontrol->value.enumerated.item[0]; diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 4b4c0c7bb918fe..163ec3855fd402 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -269,7 +269,7 @@ SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, PCM512x_RQMR_SHIFT, 1, 1), SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), -SOC_VALUE_ENUM("DSP Program", pcm512x_dsp_program), +SOC_ENUM("DSP Program", pcm512x_dsp_program), SOC_ENUM("Clock Missing Period", pcm512x_clk_missing), SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l), @@ -517,6 +517,7 @@ void pcm512x_remove(struct device *dev) } EXPORT_SYMBOL_GPL(pcm512x_remove); +#ifdef CONFIG_PM_RUNTIME static int pcm512x_suspend(struct device *dev) { struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); @@ -578,6 +579,7 @@ static int pcm512x_resume(struct device *dev) return 0; } +#endif const struct dev_pm_ops pcm512x_pm_ops = { SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index d4c229f0233ff3..30e23470857949 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -188,7 +188,7 @@ static unsigned int mic_bst_tlv[] = { static int rt5631_dmic_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = rt5631->dmic_used_flag; @@ -199,7 +199,7 @@ static int rt5631_dmic_get(struct snd_kcontrol *kcontrol, static int rt5631_dmic_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec); rt5631->dmic_used_flag = ucontrol->value.integer.value[0]; diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 68b4dd622b8793..b0967df371e587 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1,5 +1,5 @@ /* - * rt5640.c -- RT5640 ALSA SoC audio codec driver + * rt5640.c -- RT5640/RT5639 ALSA SoC audio codec driver * * Copyright 2011 Realtek Semiconductor Corp. * Author: Johnny Hsu @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,7 @@ static struct reg_default init_list[] = { }; #define RT5640_INIT_REG_LEN ARRAY_SIZE(init_list) -static const struct reg_default rt5640_reg[RT5640_VENDOR_ID2 + 1] = { +static const struct reg_default rt5640_reg[] = { { 0x00, 0x000e }, { 0x01, 0xc8c8 }, { 0x02, 0xc8c8 }, @@ -398,18 +399,13 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = { RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1), SOC_DOUBLE_TLV("OUT Playback Volume", RT5640_OUTPUT, RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv), - /* MONO Output Control */ - SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT, - RT5640_L_MUTE_SFT, 1, 1), + /* DAC Digital Volume */ SOC_DOUBLE("DAC2 Playback Switch", RT5640_DAC2_CTRL, RT5640_M_DAC_L2_VOL_SFT, RT5640_M_DAC_R2_VOL_SFT, 1, 1), SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5640_DAC1_DIG_VOL, RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 175, 0, dac_vol_tlv), - SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL, - RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, - 175, 0, dac_vol_tlv), /* IN1/IN2 Control */ SOC_SINGLE_TLV("IN1 Boost", RT5640_IN1_IN2, RT5640_BST_SFT1, 8, 0, bst_tlv), @@ -441,6 +437,15 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = { SOC_ENUM("DAC IF2 Data Switch", rt5640_if2_dac_enum), }; +static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = { + /* MONO Output Control */ + SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT, RT5640_L_MUTE_SFT, + 1, 1), + + SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL, + RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 175, 0, dac_vol_tlv), +}; + /** * set_dmic_clk - Set parameter of dmic. * @@ -480,14 +485,14 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, return idx; } -static int check_sysclk1_source(struct snd_soc_dapm_widget *source, +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { unsigned int val; val = snd_soc_read(source->codec, RT5640_GLB_CLK); val &= RT5640_SCLK_SRC_MASK; - if (val == RT5640_SCLK_SRC_PLL1 || val == RT5640_SCLK_SRC_PLL1T) + if (val == RT5640_SCLK_SRC_PLL1) return 1; else return 0; @@ -554,6 +559,20 @@ static const struct snd_kcontrol_new rt5640_sto_dac_r_mix[] = { RT5640_M_ANC_DAC_R_SFT, 1, 1), }; +static const struct snd_kcontrol_new rt5639_sto_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_STO_DAC_MIXER, + RT5640_M_DAC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_STO_DAC_MIXER, + RT5640_M_DAC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5639_sto_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_STO_DAC_MIXER, + RT5640_M_DAC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_STO_DAC_MIXER, + RT5640_M_DAC_R2_SFT, 1, 1), +}; + static const struct snd_kcontrol_new rt5640_mono_dac_l_mix[] = { SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_MONO_DAC_MIXER, RT5640_M_DAC_L1_MONO_L_SFT, 1, 1), @@ -676,6 +695,30 @@ static const struct snd_kcontrol_new rt5640_out_r_mix[] = { RT5640_M_DAC_R1_OM_R_SFT, 1, 1), }; +static const struct snd_kcontrol_new rt5639_out_l_mix[] = { + SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_L3_MIXER, + RT5640_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5640_OUT_L3_MIXER, + RT5640_M_IN_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("REC MIXL Switch", RT5640_OUT_L3_MIXER, + RT5640_M_RM_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_OUT_L3_MIXER, + RT5640_M_DAC_L1_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5639_out_r_mix[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5640_OUT_R3_MIXER, + RT5640_M_BST4_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_R3_MIXER, + RT5640_M_BST1_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5640_OUT_R3_MIXER, + RT5640_M_IN_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("REC MIXR Switch", RT5640_OUT_R3_MIXER, + RT5640_M_RM_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_OUT_R3_MIXER, + RT5640_M_DAC_R1_OM_R_SFT, 1, 1), +}; + static const struct snd_kcontrol_new rt5640_spo_l_mix[] = { SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPO_L_MIXER, RT5640_M_DAC_R1_SPM_L_SFT, 1, 1), @@ -707,6 +750,13 @@ static const struct snd_kcontrol_new rt5640_hpo_mix[] = { RT5640_M_HPVOL_HM_SFT, 1, 1), }; +static const struct snd_kcontrol_new rt5639_hpo_mix[] = { + SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5640_HPO_MIXER, + RT5640_M_DAC1_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5640_HPO_MIXER, + RT5640_M_HPVOL_HM_SFT, 1, 1), +}; + static const struct snd_kcontrol_new rt5640_lout_mix[] = { SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_LOUT_MIXER, RT5640_M_DAC_L1_LM_SFT, 1, 1), @@ -824,7 +874,7 @@ static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_l2_enum, 0x3, rt5640_dac_l2_src, rt5640_dac_l2_values); static const struct snd_kcontrol_new rt5640_dac_l2_mux = - SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum); + SOC_DAPM_ENUM("DAC2 left channel source", rt5640_dac_l2_enum); static const char * const rt5640_dac_r2_src[] = { "IF2", @@ -859,7 +909,7 @@ static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dai_iis_map_enum, rt5640_dai_iis_map_values); static const struct snd_kcontrol_new rt5640_dai_mux = - SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum); + SOC_DAPM_ENUM("DAI select", rt5640_dai_iis_map_enum); /* SDI select */ static const char * const rt5640_sdi_sel[] = { @@ -872,54 +922,6 @@ static SOC_ENUM_SINGLE_DECL(rt5640_sdi_sel_enum, RT5640_I2S2_SDP, static const struct snd_kcontrol_new rt5640_sdi_mux = SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum); -static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - snd_soc_update_bits(codec, RT5640_GPIO_CTRL1, - RT5640_GP2_PIN_MASK | RT5640_GP3_PIN_MASK, - RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP3_PIN_DMIC1_SDA); - snd_soc_update_bits(codec, RT5640_DMIC, - RT5640_DMIC_1L_LH_MASK | RT5640_DMIC_1R_LH_MASK | - RT5640_DMIC_1_DP_MASK, - RT5640_DMIC_1L_LH_FALLING | RT5640_DMIC_1R_LH_RISING | - RT5640_DMIC_1_DP_IN1P); - break; - - default: - return 0; - } - - return 0; -} - -static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - snd_soc_update_bits(codec, RT5640_GPIO_CTRL1, - RT5640_GP2_PIN_MASK | RT5640_GP4_PIN_MASK, - RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP4_PIN_DMIC2_SDA); - snd_soc_update_bits(codec, RT5640_DMIC, - RT5640_DMIC_2L_LH_MASK | RT5640_DMIC_2R_LH_MASK | - RT5640_DMIC_2_DP_MASK, - RT5640_DMIC_2L_LH_FALLING | RT5640_DMIC_2R_LH_RISING | - RT5640_DMIC_2_DP_IN1N); - break; - - default: - return 0; - } - - return 0; -} - static void hp_amp_power_on(struct snd_soc_codec *codec) { struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); @@ -1054,12 +1056,10 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, set_dmic_clk, SND_SOC_DAPM_PRE_PMU), - SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC, - RT5640_DMIC_1_EN_SFT, 0, rt5640_set_dmic1_event, - SND_SOC_DAPM_PRE_PMU), - SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC, - RT5640_DMIC_2_EN_SFT, 0, rt5640_set_dmic2_event, - SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC, RT5640_DMIC_1_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC, RT5640_DMIC_2_EN_SFT, 0, + NULL, 0), /* Boost */ SND_SOC_DAPM_PGA("BST1", RT5640_PWR_ANLG2, RT5640_PWR_BST1_BIT, 0, NULL, 0), @@ -1146,26 +1146,15 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), - /* Audio DSP */ - SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0), - /* ANC */ - SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0), + /* Output Side */ /* DAC mixer before sound effect */ SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0, rt5640_dac_l_mix, ARRAY_SIZE(rt5640_dac_l_mix)), SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0, rt5640_dac_r_mix, ARRAY_SIZE(rt5640_dac_r_mix)), - /* DAC2 channel Mux */ - SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, - &rt5640_dac_l2_mux), - SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, - &rt5640_dac_r2_mux), + /* DAC Mixer */ - SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, - rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)), - SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, - rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)), SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0, rt5640_mono_dac_l_mix, ARRAY_SIZE(rt5640_mono_dac_l_mix)), SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0, @@ -1177,21 +1166,14 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { /* DACs */ SND_SOC_DAPM_DAC("DAC L1", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_L1_BIT, 0), - SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1, - RT5640_PWR_DAC_L2_BIT, 0), SND_SOC_DAPM_DAC("DAC R1", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_R1_BIT, 0), - SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1, - RT5640_PWR_DAC_R2_BIT, 0), + /* SPK/OUT Mixer */ SND_SOC_DAPM_MIXER("SPK MIXL", RT5640_PWR_MIXER, RT5640_PWR_SM_L_BIT, 0, rt5640_spk_l_mix, ARRAY_SIZE(rt5640_spk_l_mix)), SND_SOC_DAPM_MIXER("SPK MIXR", RT5640_PWR_MIXER, RT5640_PWR_SM_R_BIT, 0, rt5640_spk_r_mix, ARRAY_SIZE(rt5640_spk_r_mix)), - SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT, - 0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)), - SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT, - 0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)), /* Ouput Volume */ SND_SOC_DAPM_PGA("SPKVOL L", RT5640_PWR_VOL, RT5640_PWR_SV_L_BIT, 0, NULL, 0), @@ -1210,16 +1192,8 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { 0, rt5640_spo_l_mix, ARRAY_SIZE(rt5640_spo_l_mix)), SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0, 0, rt5640_spo_r_mix, ARRAY_SIZE(rt5640_spo_r_mix)), - SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0, - rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)), - SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0, - rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)), SND_SOC_DAPM_MIXER("LOUT MIX", RT5640_PWR_ANLG1, RT5640_PWR_LM_BIT, 0, rt5640_lout_mix, ARRAY_SIZE(rt5640_lout_mix)), - SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0, - rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)), - SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1, - RT5640_PWR_MA_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM, 0, 0, rt5640_hp_power_event, SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, @@ -1251,10 +1225,69 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("HPOR"), SND_SOC_DAPM_OUTPUT("LOUTL"), SND_SOC_DAPM_OUTPUT("LOUTR"), +}; + +static const struct snd_soc_dapm_widget rt5640_specific_dapm_widgets[] = { + /* Audio DSP */ + SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0), + /* ANC */ + SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* DAC2 channel Mux */ + SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dac_l2_mux), + SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dac_r2_mux), + + SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)), + + SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_R2_BIT, + 0), + SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_L2_BIT, + 0), + + SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT, + 0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT, + 0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)), + + SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0, + rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)), + SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0, + rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)), + + SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0, + rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)), + SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1, + RT5640_PWR_MA_BIT, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("MONOP"), SND_SOC_DAPM_OUTPUT("MONON"), }; +static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = { + SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5639_sto_dac_l_mix, ARRAY_SIZE(rt5639_sto_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5639_sto_dac_r_mix, ARRAY_SIZE(rt5639_sto_dac_r_mix)), + + SND_SOC_DAPM_SUPPLY("DAC L2 Filter", RT5640_PWR_DIG1, + RT5640_PWR_DAC_L2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC R2 Filter", RT5640_PWR_DIG1, + RT5640_PWR_DAC_R2_BIT, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT, + 0, rt5639_out_l_mix, ARRAY_SIZE(rt5639_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT, + 0, rt5639_out_r_mix, ARRAY_SIZE(rt5639_out_r_mix)), + + SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0, + rt5639_hpo_mix, ARRAY_SIZE(rt5639_hpo_mix)), + SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0, + rt5639_hpo_mix, ARRAY_SIZE(rt5639_hpo_mix)), +}; + static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { {"IN1P", NULL, "LDO2"}, {"IN2P", NULL, "LDO2"}, @@ -1323,22 +1356,22 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { {"Stereo ADC MIXL", "ADC1 Switch", "Stereo ADC L1 Mux"}, {"Stereo ADC MIXL", "ADC2 Switch", "Stereo ADC L2 Mux"}, {"Stereo ADC MIXL", NULL, "Stereo Filter"}, - {"Stereo Filter", NULL, "PLL1", check_sysclk1_source}, + {"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll}, {"Stereo ADC MIXR", "ADC1 Switch", "Stereo ADC R1 Mux"}, {"Stereo ADC MIXR", "ADC2 Switch", "Stereo ADC R2 Mux"}, {"Stereo ADC MIXR", NULL, "Stereo Filter"}, - {"Stereo Filter", NULL, "PLL1", check_sysclk1_source}, + {"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll}, {"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"}, {"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"}, {"Mono ADC MIXL", NULL, "Mono Left Filter"}, - {"Mono Left Filter", NULL, "PLL1", check_sysclk1_source}, + {"Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll}, {"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"}, {"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"}, {"Mono ADC MIXR", NULL, "Mono Right Filter"}, - {"Mono Right Filter", NULL, "PLL1", check_sysclk1_source}, + {"Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll}, {"IF2 ADC L", NULL, "Mono ADC MIXL"}, {"IF2 ADC R", NULL, "Mono ADC MIXR"}, @@ -1396,71 +1429,38 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { {"DAC MIXR", "Stereo ADC Switch", "Stereo ADC MIXR"}, {"DAC MIXR", "INF1 Switch", "IF1 DAC R"}, - {"ANC", NULL, "Stereo ADC MIXL"}, - {"ANC", NULL, "Stereo ADC MIXR"}, - - {"Audio DSP", NULL, "DAC MIXL"}, - {"Audio DSP", NULL, "DAC MIXR"}, - - {"DAC L2 Mux", "IF2", "IF2 DAC L"}, - {"DAC L2 Mux", "Base L/R", "Audio DSP"}, - - {"DAC R2 Mux", "IF2", "IF2 DAC R"}, - {"Stereo DAC MIXL", "DAC L1 Switch", "DAC MIXL"}, - {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, - {"Stereo DAC MIXL", "ANC Switch", "ANC"}, {"Stereo DAC MIXR", "DAC R1 Switch", "DAC MIXR"}, - {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, - {"Stereo DAC MIXR", "ANC Switch", "ANC"}, {"Mono DAC MIXL", "DAC L1 Switch", "DAC MIXL"}, - {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, - {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"}, {"Mono DAC MIXR", "DAC R1 Switch", "DAC MIXR"}, - {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, - {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"}, {"DIG MIXL", "DAC L1 Switch", "DAC MIXL"}, - {"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"}, {"DIG MIXR", "DAC R1 Switch", "DAC MIXR"}, - {"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"}, {"DAC L1", NULL, "Stereo DAC MIXL"}, - {"DAC L1", NULL, "PLL1", check_sysclk1_source}, + {"DAC L1", NULL, "PLL1", is_sys_clk_from_pll}, {"DAC R1", NULL, "Stereo DAC MIXR"}, - {"DAC R1", NULL, "PLL1", check_sysclk1_source}, - {"DAC L2", NULL, "Mono DAC MIXL"}, - {"DAC L2", NULL, "PLL1", check_sysclk1_source}, - {"DAC R2", NULL, "Mono DAC MIXR"}, - {"DAC R2", NULL, "PLL1", check_sysclk1_source}, + {"DAC R1", NULL, "PLL1", is_sys_clk_from_pll}, {"SPK MIXL", "REC MIXL Switch", "RECMIXL"}, {"SPK MIXL", "INL Switch", "INL VOL"}, {"SPK MIXL", "DAC L1 Switch", "DAC L1"}, - {"SPK MIXL", "DAC L2 Switch", "DAC L2"}, {"SPK MIXL", "OUT MIXL Switch", "OUT MIXL"}, {"SPK MIXR", "REC MIXR Switch", "RECMIXR"}, {"SPK MIXR", "INR Switch", "INR VOL"}, {"SPK MIXR", "DAC R1 Switch", "DAC R1"}, - {"SPK MIXR", "DAC R2 Switch", "DAC R2"}, {"SPK MIXR", "OUT MIXR Switch", "OUT MIXR"}, - {"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"}, {"OUT MIXL", "BST1 Switch", "BST1"}, {"OUT MIXL", "INL Switch", "INL VOL"}, {"OUT MIXL", "REC MIXL Switch", "RECMIXL"}, - {"OUT MIXL", "DAC R2 Switch", "DAC R2"}, - {"OUT MIXL", "DAC L2 Switch", "DAC L2"}, {"OUT MIXL", "DAC L1 Switch", "DAC L1"}, - {"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"}, {"OUT MIXR", "BST2 Switch", "BST2"}, {"OUT MIXR", "BST1 Switch", "BST1"}, {"OUT MIXR", "INR Switch", "INR VOL"}, {"OUT MIXR", "REC MIXR Switch", "RECMIXR"}, - {"OUT MIXR", "DAC L2 Switch", "DAC L2"}, - {"OUT MIXR", "DAC R2 Switch", "DAC R2"}, {"OUT MIXR", "DAC R1 Switch", "DAC R1"}, {"SPKVOL L", NULL, "SPK MIXL"}, @@ -1479,11 +1479,9 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { {"SPOR MIX", "SPKVOL R Switch", "SPKVOL R"}, {"SPOR MIX", "BST1 Switch", "BST1"}, - {"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"}, {"HPO MIX L", "HPO MIX DAC1 Switch", "DAC L1"}, {"HPO MIX L", "HPO MIX HPVOL Switch", "HPOVOL L"}, {"HPO MIX L", NULL, "HP L Amp"}, - {"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"}, {"HPO MIX R", "HPO MIX DAC1 Switch", "DAC R1"}, {"HPO MIX R", "HPO MIX HPVOL Switch", "HPOVOL R"}, {"HPO MIX R", NULL, "HP R Amp"}, @@ -1493,12 +1491,6 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { {"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"}, {"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"}, - {"Mono MIX", "DAC R2 Switch", "DAC R2"}, - {"Mono MIX", "DAC L2 Switch", "DAC L2"}, - {"Mono MIX", "OUTVOL R Switch", "OUTVOL R"}, - {"Mono MIX", "OUTVOL L Switch", "OUTVOL L"}, - {"Mono MIX", "BST1 Switch", "BST1"}, - {"HP Amp", NULL, "HPO MIX L"}, {"HP Amp", NULL, "HPO MIX R"}, @@ -1523,11 +1515,82 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { {"HPOR", NULL, "HP R Playback"}, {"LOUTL", NULL, "LOUT MIX"}, {"LOUTR", NULL, "LOUT MIX"}, +}; + +static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = { + {"ANC", NULL, "Stereo ADC MIXL"}, + {"ANC", NULL, "Stereo ADC MIXR"}, + + {"Audio DSP", NULL, "DAC MIXL"}, + {"Audio DSP", NULL, "DAC MIXR"}, + + {"DAC L2 Mux", "IF2", "IF2 DAC L"}, + {"DAC L2 Mux", "Base L/R", "Audio DSP"}, + + {"DAC R2 Mux", "IF2", "IF2 DAC R"}, + + {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, + {"Stereo DAC MIXL", "ANC Switch", "ANC"}, + {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, + {"Stereo DAC MIXR", "ANC Switch", "ANC"}, + + {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, + {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"}, + + {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, + {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"}, + + {"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"}, + {"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"}, + + {"DAC L2", NULL, "Mono DAC MIXL"}, + {"DAC L2", NULL, "PLL1", is_sys_clk_from_pll}, + {"DAC R2", NULL, "Mono DAC MIXR"}, + {"DAC R2", NULL, "PLL1", is_sys_clk_from_pll}, + + {"SPK MIXL", "DAC L2 Switch", "DAC L2"}, + {"SPK MIXR", "DAC R2 Switch", "DAC R2"}, + + {"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"}, + {"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"}, + + {"OUT MIXL", "DAC R2 Switch", "DAC R2"}, + {"OUT MIXL", "DAC L2 Switch", "DAC L2"}, + + {"OUT MIXR", "DAC L2 Switch", "DAC L2"}, + {"OUT MIXR", "DAC R2 Switch", "DAC R2"}, + + {"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"}, + {"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"}, + + {"Mono MIX", "DAC R2 Switch", "DAC R2"}, + {"Mono MIX", "DAC L2 Switch", "DAC L2"}, + {"Mono MIX", "OUTVOL R Switch", "OUTVOL R"}, + {"Mono MIX", "OUTVOL L Switch", "OUTVOL L"}, + {"Mono MIX", "BST1 Switch", "BST1"}, + {"MONOP", NULL, "Mono MIX"}, {"MONON", NULL, "Mono MIX"}, {"MONOP", NULL, "Improve MONO Amp Drv"}, }; +static const struct snd_soc_dapm_route rt5639_specific_dapm_routes[] = { + {"Stereo DAC MIXL", "DAC L2 Switch", "IF2 DAC L"}, + {"Stereo DAC MIXR", "DAC R2 Switch", "IF2 DAC R"}, + + {"Mono DAC MIXL", "DAC L2 Switch", "IF2 DAC L"}, + {"Mono DAC MIXL", "DAC R2 Switch", "IF2 DAC R"}, + + {"Mono DAC MIXR", "DAC R2 Switch", "IF2 DAC R"}, + {"Mono DAC MIXR", "DAC L2 Switch", "IF2 DAC L"}, + + {"DIG MIXL", "DAC L2 Switch", "IF2 DAC L"}, + {"DIG MIXR", "DAC R2 Switch", "IF2 DAC R"}, + + {"IF2 DAC L", NULL, "DAC L2 Filter"}, + {"IF2 DAC R", NULL, "DAC R2 Filter"}, +}; + static int get_sdp_info(struct snd_soc_codec *codec, int dai_id) { int ret = 0, val; @@ -1622,16 +1685,16 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", bclk_ms, pre_div, dai->id); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: break; - case SNDRV_PCM_FORMAT_S20_3LE: + case 20: val_len |= RT5640_I2S_DL_20; break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: val_len |= RT5640_I2S_DL_24; break; - case SNDRV_PCM_FORMAT_S8: + case 8: val_len |= RT5640_I2S_DL_8; break; default: @@ -1744,12 +1807,6 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, case RT5640_SCLK_S_PLL1: reg_val |= RT5640_SCLK_SRC_PLL1; break; - case RT5640_SCLK_S_PLL1_TK: - reg_val |= RT5640_SCLK_SRC_PLL1T; - break; - case RT5640_SCLK_S_RCCLK: - reg_val |= RT5640_SCLK_SRC_RCCLK; - break; default: dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); return -EINVAL; @@ -1890,11 +1947,9 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, static int rt5640_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); switch (level) { case SND_SOC_BIAS_STANDBY: if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) { - regcache_cache_only(rt5640->regmap, false); snd_soc_update_bits(codec, RT5640_PWR_ANLG1, RT5640_PWR_VREF1 | RT5640_PWR_MB | RT5640_PWR_BG | RT5640_PWR_VREF2, @@ -1904,7 +1959,6 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec, snd_soc_update_bits(codec, RT5640_PWR_ANLG1, RT5640_PWR_FV1 | RT5640_PWR_FV2, RT5640_PWR_FV1 | RT5640_PWR_FV2); - regcache_sync(rt5640->regmap); snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301); snd_soc_update_bits(codec, RT5640_MICBIAS, @@ -1938,13 +1992,35 @@ static int rt5640_probe(struct snd_soc_codec *codec) rt5640->codec = codec; - codec->dapm.idle_bias_off = 1; rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF); snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301); snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030); snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00); + switch (snd_soc_read(codec, RT5640_RESET) & RT5640_ID_MASK) { + case RT5640_ID_5640: + case RT5640_ID_5642: + snd_soc_add_codec_controls(codec, + rt5640_specific_snd_controls, + ARRAY_SIZE(rt5640_specific_snd_controls)); + snd_soc_dapm_new_controls(&codec->dapm, + rt5640_specific_dapm_widgets, + ARRAY_SIZE(rt5640_specific_dapm_widgets)); + snd_soc_dapm_add_routes(&codec->dapm, + rt5640_specific_dapm_routes, + ARRAY_SIZE(rt5640_specific_dapm_routes)); + break; + case RT5640_ID_5639: + snd_soc_dapm_new_controls(&codec->dapm, + rt5639_specific_dapm_widgets, + ARRAY_SIZE(rt5639_specific_dapm_widgets)); + snd_soc_dapm_add_routes(&codec->dapm, + rt5639_specific_dapm_routes, + ARRAY_SIZE(rt5639_specific_dapm_routes)); + break; + } + return 0; } @@ -1979,6 +2055,9 @@ static int rt5640_resume(struct snd_soc_codec *codec) msleep(400); } + regcache_cache_only(rt5640->regmap, false); + regcache_sync(rt5640->regmap); + return 0; } #else @@ -2044,6 +2123,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = { .suspend = rt5640_suspend, .resume = rt5640_resume, .set_bias_level = rt5640_set_bias_level, + .idle_bias_off = true, .controls = rt5640_snd_controls, .num_controls = ARRAY_SIZE(rt5640_snd_controls), .dapm_widgets = rt5640_dapm_widgets, @@ -2070,12 +2150,15 @@ static const struct regmap_config rt5640_regmap = { static const struct i2c_device_id rt5640_i2c_id[] = { { "rt5640", 0 }, + { "rt5639", 0 }, + { "rt5642", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id); #if defined(CONFIG_OF) static const struct of_device_id rt5640_of_match[] = { + { .compatible = "realtek,rt5639", }, { .compatible = "realtek,rt5640", }, {}, }; @@ -2166,7 +2249,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, } regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val); - if ((val != RT5640_DEVICE_ID)) { + if (val != RT5640_DEVICE_ID) { dev_err(&i2c->dev, "Device with ID register %x is not rt5640/39\n", val); return -ENODEV; @@ -2187,6 +2270,25 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4, RT5640_IN_DF2, RT5640_IN_DF2); + if (rt5640->pdata.dmic_en) { + regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, + RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL); + + if (rt5640->pdata.dmic1_data_pin) { + regmap_update_bits(rt5640->regmap, RT5640_DMIC, + RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3); + regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, + RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA); + } + + if (rt5640->pdata.dmic2_data_pin) { + regmap_update_bits(rt5640->regmap, RT5640_DMIC, + RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4); + regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, + RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA); + } + } + rt5640->hp_mute = 1; ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, @@ -2219,6 +2321,6 @@ static struct i2c_driver rt5640_i2c_driver = { }; module_i2c_driver(rt5640_i2c_driver); -MODULE_DESCRIPTION("ASoC RT5640 driver"); +MODULE_DESCRIPTION("ASoC RT5640/RT5639 driver"); MODULE_AUTHOR("Johnny Hsu "); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 5e8df25a13f34b..ded20595e9ae9d 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -192,6 +192,13 @@ #define RT5640_R_VOL_MASK (0x3f) #define RT5640_R_VOL_SFT 0 +/* SW Reset & Device ID (0x00) */ +#define RT5640_ID_MASK (0x3 << 1) +#define RT5640_ID_5639 (0x0 << 1) +#define RT5640_ID_5640 (0x1 << 1) +#define RT5640_ID_5642 (0x3 << 1) + + /* IN1 and IN2 Control (0x0d) */ /* IN3 and IN4 Control (0x0e) */ #define RT5640_BST_SFT1 12 @@ -976,8 +983,6 @@ #define RT5640_SCLK_SRC_SFT 14 #define RT5640_SCLK_SRC_MCLK (0x0 << 14) #define RT5640_SCLK_SRC_PLL1 (0x1 << 14) -#define RT5640_SCLK_SRC_PLL1T (0x2 << 14) -#define RT5640_SCLK_SRC_RCCLK (0x3 << 14) /* 15MHz */ #define RT5640_PLL1_SRC_MASK (0x3 << 12) #define RT5640_PLL1_SRC_SFT 12 #define RT5640_PLL1_SRC_MCLK (0x0 << 12) @@ -2097,7 +2102,6 @@ struct rt5640_priv { int pll_in; int pll_out; - int dmic_en; bool hp_mute; }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c new file mode 100644 index 00000000000000..68923eca7d9c54 --- /dev/null +++ b/sound/soc/codecs/rt5645.c @@ -0,0 +1,2475 @@ +/* + * rt5645.c -- RT5645 ALSA SoC audio codec driver + * + * Copyright 2013 Realtek Semiconductor Corp. + * Author: Bard Liao + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt5645.h" + +#define RT5645_DEVICE_ID 0x6308 + +#define RT5645_PR_RANGE_BASE (0xff + 1) +#define RT5645_PR_SPACING 0x100 + +#define RT5645_PR_BASE (RT5645_PR_RANGE_BASE + (0 * RT5645_PR_SPACING)) + +static const struct regmap_range_cfg rt5645_ranges[] = { + { + .name = "PR", + .range_min = RT5645_PR_BASE, + .range_max = RT5645_PR_BASE + 0xf8, + .selector_reg = RT5645_PRIV_INDEX, + .selector_mask = 0xff, + .selector_shift = 0x0, + .window_start = RT5645_PRIV_DATA, + .window_len = 0x1, + }, +}; + +static const struct reg_default init_list[] = { + {RT5645_PR_BASE + 0x3d, 0x3600}, + {RT5645_PR_BASE + 0x1c, 0xfd20}, + {RT5645_PR_BASE + 0x20, 0x611f}, + {RT5645_PR_BASE + 0x21, 0x4040}, + {RT5645_PR_BASE + 0x23, 0x0004}, +}; +#define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list) + +static const struct reg_default rt5645_reg[] = { + { 0x00, 0x0000 }, + { 0x01, 0xc8c8 }, + { 0x02, 0xc8c8 }, + { 0x03, 0xc8c8 }, + { 0x0a, 0x0002 }, + { 0x0b, 0x2827 }, + { 0x0c, 0xe000 }, + { 0x0d, 0x0000 }, + { 0x0e, 0x0000 }, + { 0x0f, 0x0808 }, + { 0x14, 0x3333 }, + { 0x16, 0x4b00 }, + { 0x18, 0x018b }, + { 0x19, 0xafaf }, + { 0x1a, 0xafaf }, + { 0x1b, 0x0001 }, + { 0x1c, 0x2f2f }, + { 0x1d, 0x2f2f }, + { 0x1e, 0x0000 }, + { 0x20, 0x0000 }, + { 0x27, 0x7060 }, + { 0x28, 0x7070 }, + { 0x29, 0x8080 }, + { 0x2a, 0x5656 }, + { 0x2b, 0x5454 }, + { 0x2c, 0xaaa0 }, + { 0x2f, 0x1002 }, + { 0x31, 0x5000 }, + { 0x32, 0x0000 }, + { 0x33, 0x0000 }, + { 0x34, 0x0000 }, + { 0x35, 0x0000 }, + { 0x3b, 0x0000 }, + { 0x3c, 0x007f }, + { 0x3d, 0x0000 }, + { 0x3e, 0x007f }, + { 0x3f, 0x0000 }, + { 0x40, 0x001f }, + { 0x41, 0x0000 }, + { 0x42, 0x001f }, + { 0x45, 0x6000 }, + { 0x46, 0x003e }, + { 0x47, 0x003e }, + { 0x48, 0xf807 }, + { 0x4a, 0x0004 }, + { 0x4d, 0x0000 }, + { 0x4e, 0x0000 }, + { 0x4f, 0x01ff }, + { 0x50, 0x0000 }, + { 0x51, 0x0000 }, + { 0x52, 0x01ff }, + { 0x53, 0xf000 }, + { 0x56, 0x0111 }, + { 0x57, 0x0064 }, + { 0x58, 0xef0e }, + { 0x59, 0xf0f0 }, + { 0x5a, 0xef0e }, + { 0x5b, 0xf0f0 }, + { 0x5c, 0xef0e }, + { 0x5d, 0xf0f0 }, + { 0x5e, 0xf000 }, + { 0x5f, 0x0000 }, + { 0x61, 0x0300 }, + { 0x62, 0x0000 }, + { 0x63, 0x00c2 }, + { 0x64, 0x0000 }, + { 0x65, 0x0000 }, + { 0x66, 0x0000 }, + { 0x6a, 0x0000 }, + { 0x6c, 0x0aaa }, + { 0x70, 0x8000 }, + { 0x71, 0x8000 }, + { 0x72, 0x8000 }, + { 0x73, 0x7770 }, + { 0x74, 0x3e00 }, + { 0x75, 0x2409 }, + { 0x76, 0x000a }, + { 0x77, 0x0c00 }, + { 0x78, 0x0000 }, + { 0x80, 0x0000 }, + { 0x81, 0x0000 }, + { 0x82, 0x0000 }, + { 0x83, 0x0000 }, + { 0x84, 0x0000 }, + { 0x85, 0x0000 }, + { 0x8a, 0x0000 }, + { 0x8e, 0x0004 }, + { 0x8f, 0x1100 }, + { 0x90, 0x0646 }, + { 0x91, 0x0c06 }, + { 0x93, 0x0000 }, + { 0x94, 0x0200 }, + { 0x95, 0x0000 }, + { 0x9a, 0x2184 }, + { 0x9b, 0x010a }, + { 0x9c, 0x0aea }, + { 0x9d, 0x000c }, + { 0x9e, 0x0400 }, + { 0xa0, 0xa0a8 }, + { 0xa1, 0x0059 }, + { 0xa2, 0x0001 }, + { 0xae, 0x6000 }, + { 0xaf, 0x0000 }, + { 0xb0, 0x6000 }, + { 0xb1, 0x0000 }, + { 0xb2, 0x0000 }, + { 0xb3, 0x001f }, + { 0xb4, 0x020c }, + { 0xb5, 0x1f00 }, + { 0xb6, 0x0000 }, + { 0xbb, 0x0000 }, + { 0xbc, 0x0000 }, + { 0xbd, 0x0000 }, + { 0xbe, 0x0000 }, + { 0xbf, 0x3100 }, + { 0xc0, 0x0000 }, + { 0xc1, 0x0000 }, + { 0xc2, 0x0000 }, + { 0xc3, 0x2000 }, + { 0xcd, 0x0000 }, + { 0xce, 0x0000 }, + { 0xcf, 0x1813 }, + { 0xd0, 0x0690 }, + { 0xd1, 0x1c17 }, + { 0xd3, 0xb320 }, + { 0xd4, 0x0000 }, + { 0xd6, 0x0400 }, + { 0xd9, 0x0809 }, + { 0xda, 0x0000 }, + { 0xdb, 0x0003 }, + { 0xdc, 0x0049 }, + { 0xdd, 0x001b }, + { 0xe6, 0x8000 }, + { 0xe7, 0x0200 }, + { 0xec, 0xb300 }, + { 0xed, 0x0000 }, + { 0xf0, 0x001f }, + { 0xf1, 0x020c }, + { 0xf2, 0x1f00 }, + { 0xf3, 0x0000 }, + { 0xf4, 0x4000 }, + { 0xf8, 0x0000 }, + { 0xf9, 0x0000 }, + { 0xfa, 0x2060 }, + { 0xfb, 0x4040 }, + { 0xfc, 0x0000 }, + { 0xfd, 0x0002 }, + { 0xfe, 0x10ec }, + { 0xff, 0x6308 }, +}; + +static int rt5645_reset(struct snd_soc_codec *codec) +{ + return snd_soc_write(codec, RT5645_RESET, 0); +} + +static bool rt5645_volatile_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5645_ranges); i++) { + if (reg >= rt5645_ranges[i].range_min && + reg <= rt5645_ranges[i].range_max) { + return true; + } + } + + switch (reg) { + case RT5645_RESET: + case RT5645_PRIV_DATA: + case RT5645_IN1_CTRL1: + case RT5645_IN1_CTRL2: + case RT5645_IN1_CTRL3: + case RT5645_A_JD_CTRL1: + case RT5645_ADC_EQ_CTRL1: + case RT5645_EQ_CTRL1: + case RT5645_ALC_CTRL_1: + case RT5645_IRQ_CTRL2: + case RT5645_IRQ_CTRL3: + case RT5645_INT_IRQ_ST: + case RT5645_IL_CMD: + case RT5645_VENDOR_ID: + case RT5645_VENDOR_ID1: + case RT5645_VENDOR_ID2: + return true; + default: + return false; + } +} + +static bool rt5645_readable_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5645_ranges); i++) { + if (reg >= rt5645_ranges[i].range_min && + reg <= rt5645_ranges[i].range_max) { + return true; + } + } + + switch (reg) { + case RT5645_RESET: + case RT5645_SPK_VOL: + case RT5645_HP_VOL: + case RT5645_LOUT1: + case RT5645_IN1_CTRL1: + case RT5645_IN1_CTRL2: + case RT5645_IN1_CTRL3: + case RT5645_IN2_CTRL: + case RT5645_INL1_INR1_VOL: + case RT5645_SPK_FUNC_LIM: + case RT5645_ADJ_HPF_CTRL: + case RT5645_DAC1_DIG_VOL: + case RT5645_DAC2_DIG_VOL: + case RT5645_DAC_CTRL: + case RT5645_STO1_ADC_DIG_VOL: + case RT5645_MONO_ADC_DIG_VOL: + case RT5645_ADC_BST_VOL1: + case RT5645_ADC_BST_VOL2: + case RT5645_STO1_ADC_MIXER: + case RT5645_MONO_ADC_MIXER: + case RT5645_AD_DA_MIXER: + case RT5645_STO_DAC_MIXER: + case RT5645_MONO_DAC_MIXER: + case RT5645_DIG_MIXER: + case RT5645_DIG_INF1_DATA: + case RT5645_PDM_OUT_CTRL: + case RT5645_REC_L1_MIXER: + case RT5645_REC_L2_MIXER: + case RT5645_REC_R1_MIXER: + case RT5645_REC_R2_MIXER: + case RT5645_HPMIXL_CTRL: + case RT5645_HPOMIXL_CTRL: + case RT5645_HPMIXR_CTRL: + case RT5645_HPOMIXR_CTRL: + case RT5645_HPO_MIXER: + case RT5645_SPK_L_MIXER: + case RT5645_SPK_R_MIXER: + case RT5645_SPO_MIXER: + case RT5645_SPO_CLSD_RATIO: + case RT5645_OUT_L1_MIXER: + case RT5645_OUT_R1_MIXER: + case RT5645_OUT_L_GAIN1: + case RT5645_OUT_L_GAIN2: + case RT5645_OUT_R_GAIN1: + case RT5645_OUT_R_GAIN2: + case RT5645_LOUT_MIXER: + case RT5645_HAPTIC_CTRL1: + case RT5645_HAPTIC_CTRL2: + case RT5645_HAPTIC_CTRL3: + case RT5645_HAPTIC_CTRL4: + case RT5645_HAPTIC_CTRL5: + case RT5645_HAPTIC_CTRL6: + case RT5645_HAPTIC_CTRL7: + case RT5645_HAPTIC_CTRL8: + case RT5645_HAPTIC_CTRL9: + case RT5645_HAPTIC_CTRL10: + case RT5645_PWR_DIG1: + case RT5645_PWR_DIG2: + case RT5645_PWR_ANLG1: + case RT5645_PWR_ANLG2: + case RT5645_PWR_MIXER: + case RT5645_PWR_VOL: + case RT5645_PRIV_INDEX: + case RT5645_PRIV_DATA: + case RT5645_I2S1_SDP: + case RT5645_I2S2_SDP: + case RT5645_ADDA_CLK1: + case RT5645_ADDA_CLK2: + case RT5645_DMIC_CTRL1: + case RT5645_DMIC_CTRL2: + case RT5645_TDM_CTRL_1: + case RT5645_TDM_CTRL_2: + case RT5645_GLB_CLK: + case RT5645_PLL_CTRL1: + case RT5645_PLL_CTRL2: + case RT5645_ASRC_1: + case RT5645_ASRC_2: + case RT5645_ASRC_3: + case RT5645_ASRC_4: + case RT5645_DEPOP_M1: + case RT5645_DEPOP_M2: + case RT5645_DEPOP_M3: + case RT5645_MICBIAS: + case RT5645_A_JD_CTRL1: + case RT5645_VAD_CTRL4: + case RT5645_CLSD_OUT_CTRL: + case RT5645_ADC_EQ_CTRL1: + case RT5645_ADC_EQ_CTRL2: + case RT5645_EQ_CTRL1: + case RT5645_EQ_CTRL2: + case RT5645_ALC_CTRL_1: + case RT5645_ALC_CTRL_2: + case RT5645_ALC_CTRL_3: + case RT5645_ALC_CTRL_4: + case RT5645_ALC_CTRL_5: + case RT5645_JD_CTRL: + case RT5645_IRQ_CTRL1: + case RT5645_IRQ_CTRL2: + case RT5645_IRQ_CTRL3: + case RT5645_INT_IRQ_ST: + case RT5645_GPIO_CTRL1: + case RT5645_GPIO_CTRL2: + case RT5645_GPIO_CTRL3: + case RT5645_BASS_BACK: + case RT5645_MP3_PLUS1: + case RT5645_MP3_PLUS2: + case RT5645_ADJ_HPF1: + case RT5645_ADJ_HPF2: + case RT5645_HP_CALIB_AMP_DET: + case RT5645_SV_ZCD1: + case RT5645_SV_ZCD2: + case RT5645_IL_CMD: + case RT5645_IL_CMD2: + case RT5645_IL_CMD3: + case RT5645_DRC1_HL_CTRL1: + case RT5645_DRC2_HL_CTRL1: + case RT5645_ADC_MONO_HP_CTRL1: + case RT5645_ADC_MONO_HP_CTRL2: + case RT5645_DRC2_CTRL1: + case RT5645_DRC2_CTRL2: + case RT5645_DRC2_CTRL3: + case RT5645_DRC2_CTRL4: + case RT5645_DRC2_CTRL5: + case RT5645_JD_CTRL3: + case RT5645_JD_CTRL4: + case RT5645_GEN_CTRL1: + case RT5645_GEN_CTRL2: + case RT5645_GEN_CTRL3: + case RT5645_VENDOR_ID: + case RT5645_VENDOR_ID1: + case RT5645_VENDOR_ID2: + return true; + default: + return false; + } +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static unsigned int bst_tlv[] = { + TLV_DB_RANGE_HEAD(7), + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), + 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), + 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), + 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), +}; + +static const char * const rt5645_tdm_data_swap_select[] = { + "L/R", "R/L", "L/L", "R/R" +}; + +static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot0_1_enum, + RT5645_TDM_CTRL_1, 6, rt5645_tdm_data_swap_select); + +static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot2_3_enum, + RT5645_TDM_CTRL_1, 4, rt5645_tdm_data_swap_select); + +static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot4_5_enum, + RT5645_TDM_CTRL_1, 2, rt5645_tdm_data_swap_select); + +static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot6_7_enum, + RT5645_TDM_CTRL_1, 0, rt5645_tdm_data_swap_select); + +static const char * const rt5645_tdm_adc_data_select[] = { + "1/2/R", "2/1/R", "R/1/2", "R/2/1" +}; + +static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_sel_enum, + RT5645_TDM_CTRL_1, 8, + rt5645_tdm_adc_data_select); + +static const struct snd_kcontrol_new rt5645_snd_controls[] = { + /* Speaker Output Volume */ + SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL, + RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1), + SOC_DOUBLE_TLV("Speaker Playback Volume", RT5645_SPK_VOL, + RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv), + + /* Headphone Output Volume */ + SOC_DOUBLE("HP Channel Switch", RT5645_HP_VOL, + RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1), + SOC_DOUBLE_TLV("HP Playback Volume", RT5645_HP_VOL, + RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv), + + /* OUTPUT Control */ + SOC_DOUBLE("OUT Playback Switch", RT5645_LOUT1, + RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1), + SOC_DOUBLE("OUT Channel Switch", RT5645_LOUT1, + RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1), + SOC_DOUBLE_TLV("OUT Playback Volume", RT5645_LOUT1, + RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv), + + /* DAC Digital Volume */ + SOC_DOUBLE("DAC2 Playback Switch", RT5645_DAC_CTRL, + RT5645_M_DAC_L2_VOL_SFT, RT5645_M_DAC_R2_VOL_SFT, 1, 1), + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5645_DAC1_DIG_VOL, + RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv), + SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5645_DAC2_DIG_VOL, + RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv), + + /* IN1/IN2 Control */ + SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1, + RT5645_BST_SFT1, 8, 0, bst_tlv), + SOC_SINGLE_TLV("IN2 Boost", RT5645_IN2_CTRL, + RT5645_BST_SFT2, 8, 0, bst_tlv), + + /* INL/INR Volume Control */ + SOC_DOUBLE_TLV("IN Capture Volume", RT5645_INL1_INR1_VOL, + RT5645_INL_VOL_SFT, RT5645_INR_VOL_SFT, 31, 1, in_vol_tlv), + + /* ADC Digital Volume Control */ + SOC_DOUBLE("ADC Capture Switch", RT5645_STO1_ADC_DIG_VOL, + RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("ADC Capture Volume", RT5645_STO1_ADC_DIG_VOL, + RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv), + SOC_DOUBLE("Mono ADC Capture Switch", RT5645_MONO_ADC_DIG_VOL, + RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5645_MONO_ADC_DIG_VOL, + RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv), + + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("STO1 ADC Boost Gain", RT5645_ADC_BST_VOL1, + RT5645_STO1_ADC_L_BST_SFT, RT5645_STO1_ADC_R_BST_SFT, 3, 0, + adc_bst_tlv), + SOC_DOUBLE_TLV("STO2 ADC Boost Gain", RT5645_ADC_BST_VOL1, + RT5645_STO2_ADC_L_BST_SFT, RT5645_STO2_ADC_R_BST_SFT, 3, 0, + adc_bst_tlv), + + /* I2S2 function select */ + SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT, + 1, 1), + + /* TDM */ + SOC_ENUM("TDM Adc Slot0 1 Data", rt5645_tdm_adc_slot0_1_enum), + SOC_ENUM("TDM Adc Slot2 3 Data", rt5645_tdm_adc_slot2_3_enum), + SOC_ENUM("TDM Adc Slot4 5 Data", rt5645_tdm_adc_slot4_5_enum), + SOC_ENUM("TDM Adc Slot6 7 Data", rt5645_tdm_adc_slot6_7_enum), + SOC_ENUM("TDM IF1 ADC DATA Sel", rt5645_tdm_adc_sel_enum), + SOC_SINGLE("TDM IF1_DAC1_L Sel", RT5645_TDM_CTRL_3, 12, 7, 0), + SOC_SINGLE("TDM IF1_DAC1_R Sel", RT5645_TDM_CTRL_3, 8, 7, 0), + SOC_SINGLE("TDM IF1_DAC2_L Sel", RT5645_TDM_CTRL_3, 4, 7, 0), + SOC_SINGLE("TDM IF1_DAC2_R Sel", RT5645_TDM_CTRL_3, 0, 7, 0), +}; + +/** + * set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + * Choose dmic clock between 1MHz and 3MHz. + * It is better for clock to approximate 3MHz. + */ +static int set_dmic_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + int div[] = {2, 3, 4, 6, 8, 12}; + int idx = -EINVAL, i; + int rate, red, bound, temp; + + rate = rt5645->sysclk; + red = 3000000 * 12; + for (i = 0; i < ARRAY_SIZE(div); i++) { + bound = div[i] * 3000000; + if (rate > bound) + continue; + temp = bound - rate; + if (temp < red) { + red = temp; + idx = i; + } + } + + if (idx < 0) + dev_err(codec->dev, "Failed to set DMIC clock\n"); + else + snd_soc_update_bits(codec, RT5645_DMIC_CTRL1, + RT5645_DMIC_CLK_MASK, idx << RT5645_DMIC_CLK_SFT); + return idx; +} + +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int val; + + val = snd_soc_read(source->codec, RT5645_GLB_CLK); + val &= RT5645_SCLK_SRC_MASK; + if (val == RT5645_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER, + RT5645_M_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5645_STO1_ADC_MIXER, + RT5645_M_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER, + RT5645_M_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5645_STO1_ADC_MIXER, + RT5645_M_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_mono_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5645_MONO_ADC_MIXER, + RT5645_M_MONO_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5645_MONO_ADC_MIXER, + RT5645_M_MONO_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_mono_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5645_MONO_ADC_MIXER, + RT5645_M_MONO_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5645_MONO_ADC_MIXER, + RT5645_M_MONO_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5645_AD_DA_MIXER, + RT5645_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5645_AD_DA_MIXER, + RT5645_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5645_AD_DA_MIXER, + RT5645_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5645_AD_DA_MIXER, + RT5645_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_sto_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_STO_DAC_MIXER, + RT5645_M_DAC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_STO_DAC_MIXER, + RT5645_M_DAC_L2_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_STO_DAC_MIXER, + RT5645_M_DAC_R1_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_sto_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_STO_DAC_MIXER, + RT5645_M_DAC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_STO_DAC_MIXER, + RT5645_M_DAC_R2_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_STO_DAC_MIXER, + RT5645_M_DAC_L1_STO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_mono_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_MONO_DAC_MIXER, + RT5645_M_DAC_L1_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_MONO_DAC_MIXER, + RT5645_M_DAC_L2_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_MONO_DAC_MIXER, + RT5645_M_DAC_R2_MONO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_mono_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_MONO_DAC_MIXER, + RT5645_M_DAC_R1_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_MONO_DAC_MIXER, + RT5645_M_DAC_R2_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_MONO_DAC_MIXER, + RT5645_M_DAC_L2_MONO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_dig_l_mix[] = { + SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5645_DIG_MIXER, + RT5645_M_STO_L_DAC_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_DIG_MIXER, + RT5645_M_DAC_L2_DAC_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_DIG_MIXER, + RT5645_M_DAC_R2_DAC_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_dig_r_mix[] = { + SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5645_DIG_MIXER, + RT5645_M_STO_R_DAC_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_DIG_MIXER, + RT5645_M_DAC_R2_DAC_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_DIG_MIXER, + RT5645_M_DAC_L2_DAC_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5645_rec_l_mix[] = { + SOC_DAPM_SINGLE("HPOL Switch", RT5645_REC_L2_MIXER, + RT5645_M_HP_L_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5645_REC_L2_MIXER, + RT5645_M_IN_L_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5645_REC_L2_MIXER, + RT5645_M_BST2_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5645_REC_L2_MIXER, + RT5645_M_BST1_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("OUT MIXL Switch", RT5645_REC_L2_MIXER, + RT5645_M_OM_L_RM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_rec_r_mix[] = { + SOC_DAPM_SINGLE("HPOR Switch", RT5645_REC_R2_MIXER, + RT5645_M_HP_R_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5645_REC_R2_MIXER, + RT5645_M_IN_R_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5645_REC_R2_MIXER, + RT5645_M_BST2_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5645_REC_R2_MIXER, + RT5645_M_BST1_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("OUT MIXR Switch", RT5645_REC_R2_MIXER, + RT5645_M_OM_R_RM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_spk_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_SPK_L_MIXER, + RT5645_M_DAC_L1_SM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_SPK_L_MIXER, + RT5645_M_DAC_L2_SM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5645_SPK_L_MIXER, + RT5645_M_IN_L_SM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5645_SPK_L_MIXER, + RT5645_M_BST1_L_SM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_spk_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_SPK_R_MIXER, + RT5645_M_DAC_R1_SM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_SPK_R_MIXER, + RT5645_M_DAC_R2_SM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5645_SPK_R_MIXER, + RT5645_M_IN_R_SM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5645_SPK_R_MIXER, + RT5645_M_BST2_R_SM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_out_l_mix[] = { + SOC_DAPM_SINGLE("BST1 Switch", RT5645_OUT_L1_MIXER, + RT5645_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5645_OUT_L1_MIXER, + RT5645_M_IN_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_OUT_L1_MIXER, + RT5645_M_DAC_L2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_OUT_L1_MIXER, + RT5645_M_DAC_L1_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_out_r_mix[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5645_OUT_R1_MIXER, + RT5645_M_BST2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5645_OUT_R1_MIXER, + RT5645_M_IN_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_OUT_R1_MIXER, + RT5645_M_DAC_R2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_OUT_R1_MIXER, + RT5645_M_DAC_R1_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_spo_l_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_SPO_MIXER, + RT5645_M_DAC_R1_SPM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_SPO_MIXER, + RT5645_M_DAC_L1_SPM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("SPKVOL R Switch", RT5645_SPO_MIXER, + RT5645_M_SV_R_SPM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("SPKVOL L Switch", RT5645_SPO_MIXER, + RT5645_M_SV_L_SPM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_spo_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_SPO_MIXER, + RT5645_M_DAC_R1_SPM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("SPKVOL R Switch", RT5645_SPO_MIXER, + RT5645_M_SV_R_SPM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_hpo_mix[] = { + SOC_DAPM_SINGLE("DAC1 Switch", RT5645_HPO_MIXER, + RT5645_M_DAC1_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("HPVOL Switch", RT5645_HPO_MIXER, + RT5645_M_HPVOL_HM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_hpvoll_mix[] = { + SOC_DAPM_SINGLE("DAC1 Switch", RT5645_HPOMIXL_CTRL, + RT5645_M_DAC1_HV_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC2 Switch", RT5645_HPOMIXL_CTRL, + RT5645_M_DAC2_HV_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5645_HPOMIXL_CTRL, + RT5645_M_IN_HV_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5645_HPOMIXL_CTRL, + RT5645_M_BST1_HV_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_hpvolr_mix[] = { + SOC_DAPM_SINGLE("DAC1 Switch", RT5645_HPOMIXR_CTRL, + RT5645_M_DAC1_HV_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC2 Switch", RT5645_HPOMIXR_CTRL, + RT5645_M_DAC2_HV_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5645_HPOMIXR_CTRL, + RT5645_M_IN_HV_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5645_HPOMIXR_CTRL, + RT5645_M_BST2_HV_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5645_lout_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_LOUT_MIXER, + RT5645_M_DAC_L1_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_LOUT_MIXER, + RT5645_M_DAC_R1_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTMIX L Switch", RT5645_LOUT_MIXER, + RT5645_M_OV_L_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTMIX R Switch", RT5645_LOUT_MIXER, + RT5645_M_OV_R_LM_SFT, 1, 1), +}; + +/*DAC1 L/R source*/ /* MX-29 [9:8] [11:10] */ +static const char * const rt5645_dac1_src[] = { + "IF1 DAC", "IF2 DAC", "IF3 DAC" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_dac1l_enum, RT5645_AD_DA_MIXER, + RT5645_DAC1_L_SEL_SFT, rt5645_dac1_src); + +static const struct snd_kcontrol_new rt5645_dac1l_mux = + SOC_DAPM_ENUM("DAC1 L source", rt5645_dac1l_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5645_dac1r_enum, RT5645_AD_DA_MIXER, + RT5645_DAC1_R_SEL_SFT, rt5645_dac1_src); + +static const struct snd_kcontrol_new rt5645_dac1r_mux = + SOC_DAPM_ENUM("DAC1 R source", rt5645_dac1r_enum); + +/*DAC2 L/R source*/ /* MX-1B [6:4] [2:0] */ +static const char * const rt5645_dac12_src[] = { + "IF1 DAC", "IF2 DAC", "IF3 DAC", "Mono ADC", "VAD_ADC" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_dac2l_enum, RT5645_DAC_CTRL, + RT5645_DAC2_L_SEL_SFT, rt5645_dac12_src); + +static const struct snd_kcontrol_new rt5645_dac_l2_mux = + SOC_DAPM_ENUM("DAC2 L source", rt5645_dac2l_enum); + +static const char * const rt5645_dacr2_src[] = { + "IF1 DAC", "IF2 DAC", "IF3 DAC", "Mono ADC", "Haptic" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_dac2r_enum, RT5645_DAC_CTRL, + RT5645_DAC2_R_SEL_SFT, rt5645_dacr2_src); + +static const struct snd_kcontrol_new rt5645_dac_r2_mux = + SOC_DAPM_ENUM("DAC2 R source", rt5645_dac2r_enum); + + +/* INL/R source */ +static const char * const rt5645_inl_src[] = { + "IN2P", "MonoP" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_inl_enum, RT5645_INL1_INR1_VOL, + RT5645_INL_SEL_SFT, rt5645_inl_src); + +static const struct snd_kcontrol_new rt5645_inl_mux = + SOC_DAPM_ENUM("INL source", rt5645_inl_enum); + +static const char * const rt5645_inr_src[] = { + "IN2N", "MonoN" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_inr_enum, RT5645_INL1_INR1_VOL, + RT5645_INR_SEL_SFT, rt5645_inr_src); + +static const struct snd_kcontrol_new rt5645_inr_mux = + SOC_DAPM_ENUM("INR source", rt5645_inr_enum); + +/* Stereo1 ADC source */ +/* MX-27 [12] */ +static const char * const rt5645_stereo_adc1_src[] = { + "DAC MIX", "ADC" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_stereo1_adc1_enum, RT5645_STO1_ADC_MIXER, + RT5645_ADC_1_SRC_SFT, rt5645_stereo_adc1_src); + +static const struct snd_kcontrol_new rt5645_sto_adc1_mux = + SOC_DAPM_ENUM("Stereo1 ADC1 Mux", rt5645_stereo1_adc1_enum); + +/* MX-27 [11] */ +static const char * const rt5645_stereo_adc2_src[] = { + "DAC MIX", "DMIC" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_stereo1_adc2_enum, RT5645_STO1_ADC_MIXER, + RT5645_ADC_2_SRC_SFT, rt5645_stereo_adc2_src); + +static const struct snd_kcontrol_new rt5645_sto_adc2_mux = + SOC_DAPM_ENUM("Stereo1 ADC2 Mux", rt5645_stereo1_adc2_enum); + +/* MX-27 [8] */ +static const char * const rt5645_stereo_dmic_src[] = { + "DMIC1", "DMIC2" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_stereo1_dmic_enum, RT5645_STO1_ADC_MIXER, + RT5645_DMIC_SRC_SFT, rt5645_stereo_dmic_src); + +static const struct snd_kcontrol_new rt5645_sto1_dmic_mux = + SOC_DAPM_ENUM("Stereo1 DMIC source", rt5645_stereo1_dmic_enum); + +/* Mono ADC source */ +/* MX-28 [12] */ +static const char * const rt5645_mono_adc_l1_src[] = { + "Mono DAC MIXL", "ADC" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_mono_adc_l1_enum, RT5645_MONO_ADC_MIXER, + RT5645_MONO_ADC_L1_SRC_SFT, rt5645_mono_adc_l1_src); + +static const struct snd_kcontrol_new rt5645_mono_adc_l1_mux = + SOC_DAPM_ENUM("Mono ADC1 left source", rt5645_mono_adc_l1_enum); +/* MX-28 [11] */ +static const char * const rt5645_mono_adc_l2_src[] = { + "Mono DAC MIXL", "DMIC" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_mono_adc_l2_enum, RT5645_MONO_ADC_MIXER, + RT5645_MONO_ADC_L2_SRC_SFT, rt5645_mono_adc_l2_src); + +static const struct snd_kcontrol_new rt5645_mono_adc_l2_mux = + SOC_DAPM_ENUM("Mono ADC2 left source", rt5645_mono_adc_l2_enum); + +/* MX-28 [8] */ +static const char * const rt5645_mono_dmic_src[] = { + "DMIC1", "DMIC2" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_mono_dmic_l_enum, RT5645_MONO_ADC_MIXER, + RT5645_MONO_DMIC_L_SRC_SFT, rt5645_mono_dmic_src); + +static const struct snd_kcontrol_new rt5645_mono_dmic_l_mux = + SOC_DAPM_ENUM("Mono DMIC left source", rt5645_mono_dmic_l_enum); +/* MX-28 [1:0] */ +static SOC_ENUM_SINGLE_DECL( + rt5645_mono_dmic_r_enum, RT5645_MONO_ADC_MIXER, + RT5645_MONO_DMIC_R_SRC_SFT, rt5645_mono_dmic_src); + +static const struct snd_kcontrol_new rt5645_mono_dmic_r_mux = + SOC_DAPM_ENUM("Mono DMIC Right source", rt5645_mono_dmic_r_enum); +/* MX-28 [4] */ +static const char * const rt5645_mono_adc_r1_src[] = { + "Mono DAC MIXR", "ADC" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_mono_adc_r1_enum, RT5645_MONO_ADC_MIXER, + RT5645_MONO_ADC_R1_SRC_SFT, rt5645_mono_adc_r1_src); + +static const struct snd_kcontrol_new rt5645_mono_adc_r1_mux = + SOC_DAPM_ENUM("Mono ADC1 right source", rt5645_mono_adc_r1_enum); +/* MX-28 [3] */ +static const char * const rt5645_mono_adc_r2_src[] = { + "Mono DAC MIXR", "DMIC" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_mono_adc_r2_enum, RT5645_MONO_ADC_MIXER, + RT5645_MONO_ADC_R2_SRC_SFT, rt5645_mono_adc_r2_src); + +static const struct snd_kcontrol_new rt5645_mono_adc_r2_mux = + SOC_DAPM_ENUM("Mono ADC2 right source", rt5645_mono_adc_r2_enum); + +/* MX-77 [9:8] */ +static const char * const rt5645_if1_adc_in_src[] = { + "IF_ADC1", "IF_ADC2", "VAD_ADC" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_if1_adc_in_enum, RT5645_TDM_CTRL_1, + RT5645_IF1_ADC_IN_SFT, rt5645_if1_adc_in_src); + +static const struct snd_kcontrol_new rt5645_if1_adc_in_mux = + SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum); + +/* MX-2F [13:12] */ +static const char * const rt5645_if2_adc_in_src[] = { + "IF_ADC1", "IF_ADC2", "VAD_ADC" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_if2_adc_in_enum, RT5645_DIG_INF1_DATA, + RT5645_IF2_ADC_IN_SFT, rt5645_if2_adc_in_src); + +static const struct snd_kcontrol_new rt5645_if2_adc_in_mux = + SOC_DAPM_ENUM("IF2 ADC IN source", rt5645_if2_adc_in_enum); + +/* MX-2F [1:0] */ +static const char * const rt5645_if3_adc_in_src[] = { + "IF_ADC1", "IF_ADC2", "VAD_ADC" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_if3_adc_in_enum, RT5645_DIG_INF1_DATA, + RT5645_IF3_ADC_IN_SFT, rt5645_if3_adc_in_src); + +static const struct snd_kcontrol_new rt5645_if3_adc_in_mux = + SOC_DAPM_ENUM("IF3 ADC IN source", rt5645_if3_adc_in_enum); + +/* MX-31 [15] [13] [11] [9] */ +static const char * const rt5645_pdm_src[] = { + "Mono DAC", "Stereo DAC" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_pdm1_l_enum, RT5645_PDM_OUT_CTRL, + RT5645_PDM1_L_SFT, rt5645_pdm_src); + +static const struct snd_kcontrol_new rt5645_pdm1_l_mux = + SOC_DAPM_ENUM("PDM1 L source", rt5645_pdm1_l_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5645_pdm1_r_enum, RT5645_PDM_OUT_CTRL, + RT5645_PDM1_R_SFT, rt5645_pdm_src); + +static const struct snd_kcontrol_new rt5645_pdm1_r_mux = + SOC_DAPM_ENUM("PDM1 R source", rt5645_pdm1_r_enum); + +/* MX-9D [9:8] */ +static const char * const rt5645_vad_adc_src[] = { + "Sto1 ADC L", "Mono ADC L", "Mono ADC R" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5645_vad_adc_enum, RT5645_VAD_CTRL4, + RT5645_VAD_SEL_SFT, rt5645_vad_adc_src); + +static const struct snd_kcontrol_new rt5645_vad_adc_mux = + SOC_DAPM_ENUM("VAD ADC source", rt5645_vad_adc_enum); + +static const struct snd_kcontrol_new spk_l_vol_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_SPK_VOL, + RT5645_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new spk_r_vol_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_SPK_VOL, + RT5645_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hp_l_vol_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_HP_VOL, + RT5645_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hp_r_vol_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_HP_VOL, + RT5645_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new pdm1_l_vol_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_PDM_OUT_CTRL, + RT5645_M_PDM1_L, 1, 1); + +static const struct snd_kcontrol_new pdm1_r_vol_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_PDM_OUT_CTRL, + RT5645_M_PDM1_R, 1, 1); + +static void hp_amp_power(struct snd_soc_codec *codec, int on) +{ + static int hp_amp_power_count; + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + + if (on) { + if (hp_amp_power_count <= 0) { + /* depop parameters */ + snd_soc_update_bits(codec, RT5645_DEPOP_M2, + RT5645_DEPOP_MASK, RT5645_DEPOP_MAN); + snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d); + regmap_write(rt5645->regmap, RT5645_PR_BASE + + RT5645_HP_DCC_INT1, 0x9f01); + mdelay(150); + /* headphone amp power on */ + snd_soc_update_bits(codec, RT5645_PWR_ANLG1, + RT5645_PWR_FV1 | RT5645_PWR_FV2 , 0); + snd_soc_update_bits(codec, RT5645_PWR_VOL, + RT5645_PWR_HV_L | RT5645_PWR_HV_R, + RT5645_PWR_HV_L | RT5645_PWR_HV_R); + snd_soc_update_bits(codec, RT5645_PWR_ANLG1, + RT5645_PWR_HP_L | RT5645_PWR_HP_R | + RT5645_PWR_HA, + RT5645_PWR_HP_L | RT5645_PWR_HP_R | + RT5645_PWR_HA); + mdelay(5); + snd_soc_update_bits(codec, RT5645_PWR_ANLG1, + RT5645_PWR_FV1 | RT5645_PWR_FV2, + RT5645_PWR_FV1 | RT5645_PWR_FV2); + + snd_soc_update_bits(codec, RT5645_DEPOP_M1, + RT5645_HP_CO_MASK | RT5645_HP_SG_MASK, + RT5645_HP_CO_EN | RT5645_HP_SG_EN); + regmap_write(rt5645->regmap, RT5645_PR_BASE + + 0x14, 0x1aaa); + regmap_write(rt5645->regmap, RT5645_PR_BASE + + 0x24, 0x0430); + } + hp_amp_power_count++; + } else { + hp_amp_power_count--; + if (hp_amp_power_count <= 0) { + snd_soc_update_bits(codec, RT5645_DEPOP_M1, + RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK | + RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS | + RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS); + /* headphone amp power down */ + snd_soc_write(codec, RT5645_DEPOP_M1, 0x0000); + snd_soc_update_bits(codec, RT5645_PWR_ANLG1, + RT5645_PWR_HP_L | RT5645_PWR_HP_R | + RT5645_PWR_HA, 0); + } + } +} + +static int rt5645_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + hp_amp_power(codec, 1); + /* headphone unmute sequence */ + snd_soc_update_bits(codec, RT5645_DEPOP_M3, RT5645_CP_FQ1_MASK | + RT5645_CP_FQ2_MASK | RT5645_CP_FQ3_MASK, + (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) | + (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | + (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT)); + regmap_write(rt5645->regmap, + RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); + snd_soc_update_bits(codec, RT5645_DEPOP_M1, + RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN); + snd_soc_update_bits(codec, RT5645_DEPOP_M1, + RT5645_RSTN_MASK, RT5645_RSTN_EN); + snd_soc_update_bits(codec, RT5645_DEPOP_M1, + RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK | + RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS | + RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN); + msleep(40); + snd_soc_update_bits(codec, RT5645_DEPOP_M1, + RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK | + RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS | + RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS); + break; + + case SND_SOC_DAPM_PRE_PMD: + /* headphone mute sequence */ + snd_soc_update_bits(codec, RT5645_DEPOP_M3, + RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK | + RT5645_CP_FQ3_MASK, + (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) | + (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | + (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT)); + regmap_write(rt5645->regmap, + RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); + snd_soc_update_bits(codec, RT5645_DEPOP_M1, + RT5645_HP_SG_MASK, RT5645_HP_SG_EN); + snd_soc_update_bits(codec, RT5645_DEPOP_M1, + RT5645_RSTP_MASK, RT5645_RSTP_EN); + snd_soc_update_bits(codec, RT5645_DEPOP_M1, + RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK | + RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS | + RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN); + msleep(30); + hp_amp_power(codec, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5645_spk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5645_PWR_DIG1, + RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R | + RT5645_PWR_CLS_D_L, + RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R | + RT5645_PWR_CLS_D_L); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5645_PWR_DIG1, + RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R | + RT5645_PWR_CLS_D_L, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5645_lout_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + hp_amp_power(codec, 1); + snd_soc_update_bits(codec, RT5645_PWR_ANLG1, + RT5645_PWR_LM, RT5645_PWR_LM); + snd_soc_update_bits(codec, RT5645_LOUT1, + RT5645_L_MUTE | RT5645_R_MUTE, 0); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5645_LOUT1, + RT5645_L_MUTE | RT5645_R_MUTE, + RT5645_L_MUTE | RT5645_R_MUTE); + snd_soc_update_bits(codec, RT5645_PWR_ANLG1, + RT5645_PWR_LM, 0); + hp_amp_power(codec, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5645_bst2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5645_PWR_ANLG2, + RT5645_PWR_BST2_P, RT5645_PWR_BST2_P); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5645_PWR_ANLG2, + RT5645_PWR_BST2_P, 0); + break; + + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("LDO2", RT5645_PWR_MIXER, + RT5645_PWR_LDO2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL1", RT5645_PWR_ANLG2, + RT5645_PWR_PLL_BIT, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("JD Power", RT5645_PWR_ANLG2, + RT5645_PWR_JD1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL, + RT5645_PWR_MIC_DET_BIT, 0, NULL, 0), + + /* Input Side */ + /* micbias */ + SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2, + RT5645_PWR_MB1_BIT, 0), + SND_SOC_DAPM_MICBIAS("micbias2", RT5645_PWR_ANLG2, + RT5645_PWR_MB2_BIT, 0), + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC L1"), + SND_SOC_DAPM_INPUT("DMIC R1"), + SND_SOC_DAPM_INPUT("DMIC L2"), + SND_SOC_DAPM_INPUT("DMIC R2"), + + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN1N"), + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN2N"), + + SND_SOC_DAPM_INPUT("Haptic Generator"), + + SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, + set_dmic_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5645_DMIC_CTRL1, + RT5645_DMIC_1_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5645_DMIC_CTRL1, + RT5645_DMIC_2_EN_SFT, 0, NULL, 0), + /* Boost */ + SND_SOC_DAPM_PGA("BST1", RT5645_PWR_ANLG2, + RT5645_PWR_BST1_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("BST2", RT5645_PWR_ANLG2, + RT5645_PWR_BST2_BIT, 0, NULL, 0, rt5645_bst2_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + /* Input Volume */ + SND_SOC_DAPM_PGA("INL VOL", RT5645_PWR_VOL, + RT5645_PWR_IN_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR VOL", RT5645_PWR_VOL, + RT5645_PWR_IN_R_BIT, 0, NULL, 0), + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIXL", RT5645_PWR_MIXER, RT5645_PWR_RM_L_BIT, + 0, rt5645_rec_l_mix, ARRAY_SIZE(rt5645_rec_l_mix)), + SND_SOC_DAPM_MIXER("RECMIXR", RT5645_PWR_MIXER, RT5645_PWR_RM_R_BIT, + 0, rt5645_rec_r_mix, ARRAY_SIZE(rt5645_rec_r_mix)), + /* ADCs */ + SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("ADC L power", RT5645_PWR_DIG1, + RT5645_PWR_ADC_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC R power", RT5645_PWR_DIG1, + RT5645_PWR_ADC_R_BIT, 0, NULL, 0), + + /* ADC Mux */ + SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0, + &rt5645_sto1_dmic_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5645_sto_adc2_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5645_sto_adc2_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5645_sto_adc1_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5645_sto_adc1_mux), + SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0, + &rt5645_mono_dmic_l_mux), + SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0, + &rt5645_mono_dmic_r_mux), + SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5645_mono_adc_l2_mux), + SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5645_mono_adc_l1_mux), + SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5645_mono_adc_r1_mux), + SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5645_mono_adc_r2_mux), + /* ADC Mixer */ + + SND_SOC_DAPM_SUPPLY_S("adc stereo1 filter", 1, RT5645_PWR_DIG2, + RT5645_PWR_ADC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("adc stereo2 filter", 1, RT5645_PWR_DIG2, + RT5645_PWR_ADC_S2F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5645_sto1_adc_l_mix, ARRAY_SIZE(rt5645_sto1_adc_l_mix), + NULL, 0), + SND_SOC_DAPM_MIXER_E("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5645_sto1_adc_r_mix, ARRAY_SIZE(rt5645_sto1_adc_r_mix), + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("adc mono left filter", 1, RT5645_PWR_DIG2, + RT5645_PWR_ADC_MF_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("Mono ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5645_mono_adc_l_mix, ARRAY_SIZE(rt5645_mono_adc_l_mix), + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("adc mono right filter", 1, RT5645_PWR_DIG2, + RT5645_PWR_ADC_MF_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("Mono ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5645_mono_adc_r_mix, ARRAY_SIZE(rt5645_mono_adc_r_mix), + NULL, 0), + + /* ADC PGA */ + SND_SOC_DAPM_PGA("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("VAD_ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* IF1 2 Mux */ + SND_SOC_DAPM_MUX("IF1 ADC Mux", SND_SOC_NOPM, + 0, 0, &rt5645_if1_adc_in_mux), + SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, + 0, 0, &rt5645_if2_adc_in_mux), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1", RT5645_PWR_DIG1, + RT5645_PWR_I2S1_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S2", RT5645_PWR_DIG1, + RT5645_PWR_I2S2_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface Select */ + SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM, + 0, 0, &rt5645_vad_adc_mux), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, + rt5645_dac_l_mix, ARRAY_SIZE(rt5645_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, + rt5645_dac_r_mix, ARRAY_SIZE(rt5645_dac_r_mix)), + + /* DAC2 channel Mux */ + SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac_l2_mux), + SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac_r2_mux), + SND_SOC_DAPM_PGA("DAC L2 Volume", RT5645_PWR_DIG1, + RT5645_PWR_DAC_L2_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC R2 Volume", RT5645_PWR_DIG1, + RT5645_PWR_DAC_R2_BIT, 0, NULL, 0), + + SND_SOC_DAPM_MUX("DAC1 L Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac1l_mux), + SND_SOC_DAPM_MUX("DAC1 R Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac1r_mux), + + /* DAC Mixer */ + SND_SOC_DAPM_SUPPLY_S("dac stereo1 filter", 1, RT5645_PWR_DIG2, + RT5645_PWR_DAC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("dac mono left filter", 1, RT5645_PWR_DIG2, + RT5645_PWR_DAC_MF_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("dac mono right filter", 1, RT5645_PWR_DIG2, + RT5645_PWR_DAC_MF_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5645_sto_dac_l_mix, ARRAY_SIZE(rt5645_sto_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5645_sto_dac_r_mix, ARRAY_SIZE(rt5645_sto_dac_r_mix)), + SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5645_mono_dac_l_mix, ARRAY_SIZE(rt5645_mono_dac_l_mix)), + SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5645_mono_dac_r_mix, ARRAY_SIZE(rt5645_mono_dac_r_mix)), + SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5645_dig_l_mix, ARRAY_SIZE(rt5645_dig_l_mix)), + SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5645_dig_r_mix, ARRAY_SIZE(rt5645_dig_r_mix)), + + /* DACs */ + SND_SOC_DAPM_DAC("DAC L1", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_L1_BIT, + 0), + SND_SOC_DAPM_DAC("DAC L2", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_L2_BIT, + 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_R1_BIT, + 0), + SND_SOC_DAPM_DAC("DAC R2", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_R2_BIT, + 0), + /* OUT Mixer */ + SND_SOC_DAPM_MIXER("SPK MIXL", RT5645_PWR_MIXER, RT5645_PWR_SM_L_BIT, + 0, rt5645_spk_l_mix, ARRAY_SIZE(rt5645_spk_l_mix)), + SND_SOC_DAPM_MIXER("SPK MIXR", RT5645_PWR_MIXER, RT5645_PWR_SM_R_BIT, + 0, rt5645_spk_r_mix, ARRAY_SIZE(rt5645_spk_r_mix)), + SND_SOC_DAPM_MIXER("OUT MIXL", RT5645_PWR_MIXER, RT5645_PWR_OM_L_BIT, + 0, rt5645_out_l_mix, ARRAY_SIZE(rt5645_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5645_PWR_MIXER, RT5645_PWR_OM_R_BIT, + 0, rt5645_out_r_mix, ARRAY_SIZE(rt5645_out_r_mix)), + /* Ouput Volume */ + SND_SOC_DAPM_SWITCH("SPKVOL L", RT5645_PWR_VOL, RT5645_PWR_SV_L_BIT, 0, + &spk_l_vol_control), + SND_SOC_DAPM_SWITCH("SPKVOL R", RT5645_PWR_VOL, RT5645_PWR_SV_R_BIT, 0, + &spk_r_vol_control), + SND_SOC_DAPM_MIXER("HPOVOL MIXL", RT5645_PWR_VOL, RT5645_PWR_HV_L_BIT, + 0, rt5645_hpvoll_mix, ARRAY_SIZE(rt5645_hpvoll_mix)), + SND_SOC_DAPM_MIXER("HPOVOL MIXR", RT5645_PWR_VOL, RT5645_PWR_HV_R_BIT, + 0, rt5645_hpvolr_mix, ARRAY_SIZE(rt5645_hpvolr_mix)), + SND_SOC_DAPM_SUPPLY("HPOVOL MIXL Power", RT5645_PWR_MIXER, + RT5645_PWR_HM_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("HPOVOL MIXR Power", RT5645_PWR_MIXER, + RT5645_PWR_HM_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SWITCH("HPOVOL L", SND_SOC_NOPM, 0, 0, &hp_l_vol_control), + SND_SOC_DAPM_SWITCH("HPOVOL R", SND_SOC_NOPM, 0, 0, &hp_r_vol_control), + + /* HPO/LOUT/Mono Mixer */ + SND_SOC_DAPM_MIXER("SPOL MIX", SND_SOC_NOPM, 0, 0, rt5645_spo_l_mix, + ARRAY_SIZE(rt5645_spo_l_mix)), + SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0, 0, rt5645_spo_r_mix, + ARRAY_SIZE(rt5645_spo_r_mix)), + SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0, rt5645_hpo_mix, + ARRAY_SIZE(rt5645_hpo_mix)), + SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0, rt5645_lout_mix, + ARRAY_SIZE(rt5645_lout_mix)), + + SND_SOC_DAPM_PGA_S("HP amp", 1, SND_SOC_NOPM, 0, 0, rt5645_hp_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0, rt5645_lout_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("SPK amp", 2, SND_SOC_NOPM, 0, 0, rt5645_spk_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + + /* PDM */ + SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5645_PWR_DIG2, RT5645_PWR_PDM1_BIT, + 0, NULL, 0), + SND_SOC_DAPM_MUX("PDM1 L Mux", SND_SOC_NOPM, 0, 0, &rt5645_pdm1_l_mux), + SND_SOC_DAPM_MUX("PDM1 R Mux", SND_SOC_NOPM, 0, 0, &rt5645_pdm1_r_mux), + + SND_SOC_DAPM_SWITCH("PDM1 L", SND_SOC_NOPM, 0, 0, &pdm1_l_vol_control), + SND_SOC_DAPM_SWITCH("PDM1 R", SND_SOC_NOPM, 0, 0, &pdm1_r_vol_control), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), + SND_SOC_DAPM_OUTPUT("LOUTL"), + SND_SOC_DAPM_OUTPUT("LOUTR"), + SND_SOC_DAPM_OUTPUT("PDM1L"), + SND_SOC_DAPM_OUTPUT("PDM1R"), + SND_SOC_DAPM_OUTPUT("SPOL"), + SND_SOC_DAPM_OUTPUT("SPOR"), +}; + +static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { + { "IN1P", NULL, "LDO2" }, + { "IN2P", NULL, "LDO2" }, + + { "DMIC1", NULL, "DMIC L1" }, + { "DMIC1", NULL, "DMIC R1" }, + { "DMIC2", NULL, "DMIC L2" }, + { "DMIC2", NULL, "DMIC R2" }, + + { "BST1", NULL, "IN1P" }, + { "BST1", NULL, "IN1N" }, + { "BST1", NULL, "JD Power" }, + { "BST1", NULL, "Mic Det Power" }, + { "BST2", NULL, "IN2P" }, + { "BST2", NULL, "IN2N" }, + + { "INL VOL", NULL, "IN2P" }, + { "INR VOL", NULL, "IN2N" }, + + { "RECMIXL", "HPOL Switch", "HPOL" }, + { "RECMIXL", "INL Switch", "INL VOL" }, + { "RECMIXL", "BST2 Switch", "BST2" }, + { "RECMIXL", "BST1 Switch", "BST1" }, + { "RECMIXL", "OUT MIXL Switch", "OUT MIXL" }, + + { "RECMIXR", "HPOR Switch", "HPOR" }, + { "RECMIXR", "INR Switch", "INR VOL" }, + { "RECMIXR", "BST2 Switch", "BST2" }, + { "RECMIXR", "BST1 Switch", "BST1" }, + { "RECMIXR", "OUT MIXR Switch", "OUT MIXR" }, + + { "ADC L", NULL, "RECMIXL" }, + { "ADC L", NULL, "ADC L power" }, + { "ADC R", NULL, "RECMIXR" }, + { "ADC R", NULL, "ADC R power" }, + + {"DMIC L1", NULL, "DMIC CLK"}, + {"DMIC L1", NULL, "DMIC1 Power"}, + {"DMIC R1", NULL, "DMIC CLK"}, + {"DMIC R1", NULL, "DMIC1 Power"}, + {"DMIC L2", NULL, "DMIC CLK"}, + {"DMIC L2", NULL, "DMIC2 Power"}, + {"DMIC R2", NULL, "DMIC CLK"}, + {"DMIC R2", NULL, "DMIC2 Power"}, + + { "Stereo1 DMIC Mux", "DMIC1", "DMIC1" }, + { "Stereo1 DMIC Mux", "DMIC2", "DMIC2" }, + + { "Mono DMIC L Mux", "DMIC1", "DMIC L1" }, + { "Mono DMIC L Mux", "DMIC2", "DMIC L2" }, + + { "Mono DMIC R Mux", "DMIC1", "DMIC R1" }, + { "Mono DMIC R Mux", "DMIC2", "DMIC R2" }, + + { "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" }, + { "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" }, + { "Stereo1 ADC L1 Mux", "ADC", "ADC L" }, + { "Stereo1 ADC L1 Mux", "DAC MIX", "DAC MIXL" }, + + { "Stereo1 ADC R1 Mux", "ADC", "ADC R" }, + { "Stereo1 ADC R1 Mux", "DAC MIX", "DAC MIXR" }, + { "Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC Mux" }, + { "Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR" }, + + { "Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux" }, + { "Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL" }, + { "Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL" }, + { "Mono ADC L1 Mux", "ADC", "ADC L" }, + + { "Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR" }, + { "Mono ADC R1 Mux", "ADC", "ADC R" }, + { "Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux" }, + { "Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR" }, + + { "Sto1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux" }, + { "Sto1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux" }, + { "Sto1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux" }, + { "Sto1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux" }, + + { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" }, + { "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" }, + { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll }, + + { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" }, + { "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" }, + { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll }, + + { "Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux" }, + { "Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux" }, + { "Mono ADC MIXL", NULL, "adc mono left filter" }, + { "adc mono left filter", NULL, "PLL1", is_sys_clk_from_pll }, + + { "Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux" }, + { "Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux" }, + { "Mono ADC MIXR", NULL, "adc mono right filter" }, + { "adc mono right filter", NULL, "PLL1", is_sys_clk_from_pll }, + + { "VAD ADC Mux", "Sto1 ADC L", "Stereo1 ADC MIXL" }, + { "VAD ADC Mux", "Mono ADC L", "Mono ADC MIXL" }, + { "VAD ADC Mux", "Mono ADC R", "Mono ADC MIXR" }, + + { "IF_ADC1", NULL, "Stereo1 ADC MIXL" }, + { "IF_ADC1", NULL, "Stereo1 ADC MIXR" }, + { "IF_ADC2", NULL, "Mono ADC MIXL" }, + { "IF_ADC2", NULL, "Mono ADC MIXR" }, + { "VAD_ADC", NULL, "VAD ADC Mux" }, + + { "IF1 ADC Mux", "IF_ADC1", "IF_ADC1" }, + { "IF1 ADC Mux", "IF_ADC2", "IF_ADC2" }, + { "IF1 ADC Mux", "VAD_ADC", "VAD_ADC" }, + + { "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" }, + { "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" }, + { "IF2 ADC Mux", "VAD_ADC", "VAD_ADC" }, + + { "IF1 ADC", NULL, "I2S1" }, + { "IF1 ADC", NULL, "IF1 ADC Mux" }, + { "IF2 ADC", NULL, "I2S2" }, + { "IF2 ADC", NULL, "IF2 ADC Mux" }, + + { "AIF1TX", NULL, "IF1 ADC" }, + { "AIF1TX", NULL, "IF2 ADC" }, + { "AIF2TX", NULL, "IF2 ADC" }, + + { "IF1 DAC1", NULL, "AIF1RX" }, + { "IF1 DAC2", NULL, "AIF1RX" }, + { "IF2 DAC", NULL, "AIF2RX" }, + + { "IF1 DAC1", NULL, "I2S1" }, + { "IF1 DAC2", NULL, "I2S1" }, + { "IF2 DAC", NULL, "I2S2" }, + + { "IF1 DAC2 L", NULL, "IF1 DAC2" }, + { "IF1 DAC2 R", NULL, "IF1 DAC2" }, + { "IF1 DAC1 L", NULL, "IF1 DAC1" }, + { "IF1 DAC1 R", NULL, "IF1 DAC1" }, + { "IF2 DAC L", NULL, "IF2 DAC" }, + { "IF2 DAC R", NULL, "IF2 DAC" }, + + { "DAC1 L Mux", "IF1 DAC", "IF1 DAC1 L" }, + { "DAC1 L Mux", "IF2 DAC", "IF2 DAC L" }, + + { "DAC1 R Mux", "IF1 DAC", "IF1 DAC1 R" }, + { "DAC1 R Mux", "IF2 DAC", "IF2 DAC R" }, + + { "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" }, + { "DAC1 MIXL", "DAC1 Switch", "DAC1 L Mux" }, + { "DAC1 MIXL", NULL, "dac stereo1 filter" }, + { "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR" }, + { "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" }, + { "DAC1 MIXR", NULL, "dac stereo1 filter" }, + + { "DAC L2 Mux", "IF1 DAC", "IF1 DAC2 L" }, + { "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" }, + { "DAC L2 Mux", "Mono ADC", "Mono ADC MIXL" }, + { "DAC L2 Mux", "VAD_ADC", "VAD_ADC" }, + { "DAC L2 Volume", NULL, "DAC L2 Mux" }, + { "DAC L2 Volume", NULL, "dac mono left filter" }, + + { "DAC R2 Mux", "IF1 DAC", "IF1 DAC2 R" }, + { "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" }, + { "DAC R2 Mux", "Mono ADC", "Mono ADC MIXR" }, + { "DAC R2 Mux", "Haptic", "Haptic Generator" }, + { "DAC R2 Volume", NULL, "DAC R2 Mux" }, + { "DAC R2 Volume", NULL, "dac mono right filter" }, + + { "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" }, + { "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" }, + { "Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" }, + { "Stereo DAC MIXL", NULL, "dac stereo1 filter" }, + { "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" }, + { "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" }, + { "Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" }, + { "Stereo DAC MIXR", NULL, "dac stereo1 filter" }, + + { "Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" }, + { "Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" }, + { "Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Volume" }, + { "Mono DAC MIXL", NULL, "dac mono left filter" }, + { "Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" }, + { "Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" }, + { "Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" }, + { "Mono DAC MIXR", NULL, "dac mono right filter" }, + + { "DAC MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" }, + { "DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" }, + { "DAC MIXL", "DAC R2 Switch", "DAC R2 Volume" }, + { "DAC MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" }, + { "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" }, + { "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" }, + + { "DAC L1", NULL, "Stereo DAC MIXL" }, + { "DAC L1", NULL, "PLL1", is_sys_clk_from_pll }, + { "DAC R1", NULL, "Stereo DAC MIXR" }, + { "DAC R1", NULL, "PLL1", is_sys_clk_from_pll }, + { "DAC L2", NULL, "Mono DAC MIXL" }, + { "DAC L2", NULL, "PLL1", is_sys_clk_from_pll }, + { "DAC R2", NULL, "Mono DAC MIXR" }, + { "DAC R2", NULL, "PLL1", is_sys_clk_from_pll }, + + { "SPK MIXL", "BST1 Switch", "BST1" }, + { "SPK MIXL", "INL Switch", "INL VOL" }, + { "SPK MIXL", "DAC L1 Switch", "DAC L1" }, + { "SPK MIXL", "DAC L2 Switch", "DAC L2" }, + { "SPK MIXR", "BST2 Switch", "BST2" }, + { "SPK MIXR", "INR Switch", "INR VOL" }, + { "SPK MIXR", "DAC R1 Switch", "DAC R1" }, + { "SPK MIXR", "DAC R2 Switch", "DAC R2" }, + + { "OUT MIXL", "BST1 Switch", "BST1" }, + { "OUT MIXL", "INL Switch", "INL VOL" }, + { "OUT MIXL", "DAC L2 Switch", "DAC L2" }, + { "OUT MIXL", "DAC L1 Switch", "DAC L1" }, + + { "OUT MIXR", "BST2 Switch", "BST2" }, + { "OUT MIXR", "INR Switch", "INR VOL" }, + { "OUT MIXR", "DAC R2 Switch", "DAC R2" }, + { "OUT MIXR", "DAC R1 Switch", "DAC R1" }, + + { "HPOVOL MIXL", "DAC1 Switch", "DAC L1" }, + { "HPOVOL MIXL", "DAC2 Switch", "DAC L2" }, + { "HPOVOL MIXL", "INL Switch", "INL VOL" }, + { "HPOVOL MIXL", "BST1 Switch", "BST1" }, + { "HPOVOL MIXL", NULL, "HPOVOL MIXL Power" }, + { "HPOVOL MIXR", "DAC1 Switch", "DAC R1" }, + { "HPOVOL MIXR", "DAC2 Switch", "DAC R2" }, + { "HPOVOL MIXR", "INR Switch", "INR VOL" }, + { "HPOVOL MIXR", "BST2 Switch", "BST2" }, + { "HPOVOL MIXR", NULL, "HPOVOL MIXR Power" }, + + { "DAC 2", NULL, "DAC L2" }, + { "DAC 2", NULL, "DAC R2" }, + { "DAC 1", NULL, "DAC L1" }, + { "DAC 1", NULL, "DAC R1" }, + { "HPOVOL L", "Switch", "HPOVOL MIXL" }, + { "HPOVOL R", "Switch", "HPOVOL MIXR" }, + { "HPOVOL", NULL, "HPOVOL L" }, + { "HPOVOL", NULL, "HPOVOL R" }, + { "HPO MIX", "DAC1 Switch", "DAC 1" }, + { "HPO MIX", "HPVOL Switch", "HPOVOL" }, + + { "SPKVOL L", "Switch", "SPK MIXL" }, + { "SPKVOL R", "Switch", "SPK MIXR" }, + + { "SPOL MIX", "DAC R1 Switch", "DAC R1" }, + { "SPOL MIX", "DAC L1 Switch", "DAC L1" }, + { "SPOL MIX", "SPKVOL R Switch", "SPKVOL R" }, + { "SPOL MIX", "SPKVOL L Switch", "SPKVOL L" }, + { "SPOR MIX", "DAC R1 Switch", "DAC R1" }, + { "SPOR MIX", "SPKVOL R Switch", "SPKVOL R" }, + + { "LOUT MIX", "DAC L1 Switch", "DAC L1" }, + { "LOUT MIX", "DAC R1 Switch", "DAC R1" }, + { "LOUT MIX", "OUTMIX L Switch", "OUT MIXL" }, + { "LOUT MIX", "OUTMIX R Switch", "OUT MIXR" }, + + { "PDM1 L Mux", "Stereo DAC", "Stereo DAC MIXL" }, + { "PDM1 L Mux", "Mono DAC", "Mono DAC MIXL" }, + { "PDM1 L Mux", NULL, "PDM1 Power" }, + { "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, + { "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" }, + { "PDM1 R Mux", NULL, "PDM1 Power" }, + + { "HP amp", NULL, "HPO MIX" }, + { "HP amp", NULL, "JD Power" }, + { "HP amp", NULL, "Mic Det Power" }, + { "HP amp", NULL, "LDO2" }, + { "HPOL", NULL, "HP amp" }, + { "HPOR", NULL, "HP amp" }, + + { "LOUT amp", NULL, "LOUT MIX" }, + { "LOUTL", NULL, "LOUT amp" }, + { "LOUTR", NULL, "LOUT amp" }, + + { "PDM1 L", "Switch", "PDM1 L Mux" }, + { "PDM1 R", "Switch", "PDM1 R Mux" }, + + { "PDM1L", NULL, "PDM1 L" }, + { "PDM1R", NULL, "PDM1 R" }, + + { "SPK amp", NULL, "SPOL MIX" }, + { "SPK amp", NULL, "SPOR MIX" }, + { "SPOL", NULL, "SPK amp" }, + { "SPOR", NULL, "SPK amp" }, +}; + +static int get_clk_info(int sclk, int rate) +{ + int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; + + if (sclk <= 0 || rate <= 0) + return -EINVAL; + + rate = rate << 8; + for (i = 0; i < ARRAY_SIZE(pd); i++) + if (sclk == rate * pd[i]) + return i; + + return -EINVAL; +} + +static int rt5645_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0, val_clk, mask_clk; + int pre_div, bclk_ms, frame_size; + + rt5645->lrck[dai->id] = params_rate(params); + pre_div = get_clk_info(rt5645->sysclk, rt5645->lrck[dai->id]); + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting\n"); + return -EINVAL; + } + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); + return -EINVAL; + } + bclk_ms = frame_size > 32; + rt5645->bclk[dai->id] = rt5645->lrck[dai->id] * (32 << bclk_ms); + + dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", + rt5645->bclk[dai->id], rt5645->lrck[dai->id]); + dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", + bclk_ms, pre_div, dai->id); + + switch (params_width(params)) { + case 16: + break; + case 20: + val_len |= RT5645_I2S_DL_20; + break; + case 24: + val_len |= RT5645_I2S_DL_24; + break; + case 8: + val_len |= RT5645_I2S_DL_8; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5645_AIF1: + mask_clk = RT5645_I2S_BCLK_MS1_MASK | RT5645_I2S_PD1_MASK; + val_clk = bclk_ms << RT5645_I2S_BCLK_MS1_SFT | + pre_div << RT5645_I2S_PD1_SFT; + snd_soc_update_bits(codec, RT5645_I2S1_SDP, + RT5645_I2S_DL_MASK, val_len); + snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk); + break; + case RT5645_AIF2: + mask_clk = RT5645_I2S_BCLK_MS2_MASK | RT5645_I2S_PD2_MASK; + val_clk = bclk_ms << RT5645_I2S_BCLK_MS2_SFT | + pre_div << RT5645_I2S_PD2_SFT; + snd_soc_update_bits(codec, RT5645_I2S2_SDP, + RT5645_I2S_DL_MASK, val_len); + snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + + return 0; +} + +static int rt5645_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5645->master[dai->id] = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5645_I2S_MS_S; + rt5645->master[dai->id] = 0; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5645_I2S_BP_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5645_I2S_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5645_I2S_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5645_I2S_DF_PCM_B; + break; + default: + return -EINVAL; + } + switch (dai->id) { + case RT5645_AIF1: + snd_soc_update_bits(codec, RT5645_I2S1_SDP, + RT5645_I2S_MS_MASK | RT5645_I2S_BP_MASK | + RT5645_I2S_DF_MASK, reg_val); + break; + case RT5645_AIF2: + snd_soc_update_bits(codec, RT5645_I2S1_SDP, + RT5645_I2S_MS_MASK | RT5645_I2S_BP_MASK | + RT5645_I2S_DF_MASK, reg_val); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + return 0; +} + +static int rt5645_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5645->sysclk && clk_id == rt5645->sysclk_src) + return 0; + + switch (clk_id) { + case RT5645_SCLK_S_MCLK: + reg_val |= RT5645_SCLK_SRC_MCLK; + break; + case RT5645_SCLK_S_PLL1: + reg_val |= RT5645_SCLK_SRC_PLL1; + break; + case RT5645_SCLK_S_RCCLK: + reg_val |= RT5645_SCLK_SRC_RCCLK; + break; + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5645_GLB_CLK, + RT5645_SCLK_SRC_MASK, reg_val); + rt5645->sysclk = freq; + rt5645->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + return 0; +} + +/** + * rt5645_pll_calc - Calcualte PLL M/N/K code. + * @freq_in: external clock provided to codec. + * @freq_out: target clock which codec works on. + * @pll_code: Pointer to structure with M, N, K and bypass flag. + * + * Calcualte M/N/K code to configure PLL for codec. And K is assigned to 2 + * which make calculation more efficiently. + * + * Returns 0 for success or negative error code. + */ +static int rt5645_pll_calc(const unsigned int freq_in, + const unsigned int freq_out, struct rt5645_pll_code *pll_code) +{ + int max_n = RT5645_PLL_N_MAX, max_m = RT5645_PLL_M_MAX; + int k, n = 0, m = 0, red, n_t, m_t, pll_out, in_t, out_t; + int red_t = abs(freq_out - freq_in); + bool bypass = false; + + if (RT5645_PLL_INP_MAX < freq_in || RT5645_PLL_INP_MIN > freq_in) + return -EINVAL; + + k = 100000000 / freq_out - 2; + if (k > RT5645_PLL_K_MAX) + k = RT5645_PLL_K_MAX; + for (n_t = 0; n_t <= max_n; n_t++) { + in_t = freq_in / (k + 2); + pll_out = freq_out / (n_t + 2); + if (in_t < 0) + continue; + if (in_t == pll_out) { + bypass = true; + n = n_t; + goto code_find; + } + red = abs(in_t - pll_out); + if (red < red_t) { + bypass = true; + n = n_t; + m = m_t; + if (red == 0) + goto code_find; + red_t = red; + } + for (m_t = 0; m_t <= max_m; m_t++) { + out_t = in_t / (m_t + 2); + red = abs(out_t - pll_out); + if (red < red_t) { + bypass = false; + n = n_t; + m = m_t; + if (red == 0) + goto code_find; + red_t = red; + } + } + } + pr_debug("Only get approximation about PLL\n"); + +code_find: + + pll_code->m_bp = bypass; + pll_code->m_code = m; + pll_code->n_code = n; + pll_code->k_code = k; + return 0; +} + +static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + struct rt5645_pll_code pll_code; + int ret; + + if (source == rt5645->pll_src && freq_in == rt5645->pll_in && + freq_out == rt5645->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5645->pll_in = 0; + rt5645->pll_out = 0; + snd_soc_update_bits(codec, RT5645_GLB_CLK, + RT5645_SCLK_SRC_MASK, RT5645_SCLK_SRC_MCLK); + return 0; + } + + switch (source) { + case RT5645_PLL1_S_MCLK: + snd_soc_update_bits(codec, RT5645_GLB_CLK, + RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_MCLK); + break; + case RT5645_PLL1_S_BCLK1: + case RT5645_PLL1_S_BCLK2: + switch (dai->id) { + case RT5645_AIF1: + snd_soc_update_bits(codec, RT5645_GLB_CLK, + RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_BCLK1); + break; + case RT5645_AIF2: + snd_soc_update_bits(codec, RT5645_GLB_CLK, + RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_BCLK2); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + break; + default: + dev_err(codec->dev, "Unknown PLL source %d\n", source); + return -EINVAL; + } + + ret = rt5645_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + snd_soc_write(codec, RT5645_PLL_CTRL1, + pll_code.n_code << RT5645_PLL_N_SFT | pll_code.k_code); + snd_soc_write(codec, RT5645_PLL_CTRL2, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5645_PLL_M_SFT | + pll_code.m_bp << RT5645_PLL_M_BP_SFT); + + rt5645->pll_in = freq_in; + rt5645->pll_out = freq_out; + rt5645->pll_src = source; + + return 0; +} + +static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int val = 0; + + if (rx_mask || tx_mask) + val |= (1 << 14); + + switch (slots) { + case 4: + val |= (1 << 12); + break; + case 6: + val |= (2 << 12); + break; + case 8: + val |= (3 << 12); + break; + case 2: + default: + break; + } + + switch (slot_width) { + case 20: + val |= (1 << 10); + break; + case 24: + val |= (2 << 10); + break; + case 32: + val |= (3 << 10); + break; + case 16: + default: + break; + } + + snd_soc_update_bits(codec, RT5645_TDM_CTRL_1, 0x7c00, val); + + return 0; +} + +static int rt5645_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_STANDBY: + if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) { + snd_soc_update_bits(codec, RT5645_PWR_ANLG1, + RT5645_PWR_VREF1 | RT5645_PWR_MB | + RT5645_PWR_BG | RT5645_PWR_VREF2, + RT5645_PWR_VREF1 | RT5645_PWR_MB | + RT5645_PWR_BG | RT5645_PWR_VREF2); + mdelay(10); + snd_soc_update_bits(codec, RT5645_PWR_ANLG1, + RT5645_PWR_FV1 | RT5645_PWR_FV2, + RT5645_PWR_FV1 | RT5645_PWR_FV2); + snd_soc_update_bits(codec, RT5645_GEN_CTRL1, + RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL); + } + break; + + case SND_SOC_BIAS_OFF: + snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100); + snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128); + snd_soc_write(codec, RT5645_PWR_DIG1, 0x0000); + snd_soc_write(codec, RT5645_PWR_DIG2, 0x0000); + snd_soc_write(codec, RT5645_PWR_VOL, 0x0000); + snd_soc_write(codec, RT5645_PWR_MIXER, 0x0000); + snd_soc_write(codec, RT5645_PWR_ANLG1, 0x0000); + snd_soc_write(codec, RT5645_PWR_ANLG2, 0x0000); + break; + + default: + break; + } + codec->dapm.bias_level = level; + + return 0; +} + +static int rt5645_probe(struct snd_soc_codec *codec) +{ + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + + rt5645->codec = codec; + + rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF); + + snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200); + + return 0; +} + +static int rt5645_remove(struct snd_soc_codec *codec) +{ + rt5645_reset(codec); + return 0; +} + +#ifdef CONFIG_PM +static int rt5645_suspend(struct snd_soc_codec *codec) +{ + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5645->regmap, true); + regcache_mark_dirty(rt5645->regmap); + + return 0; +} + +static int rt5645_resume(struct snd_soc_codec *codec) +{ + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5645->regmap, false); + regcache_sync(rt5645->regmap); + + return 0; +} +#else +#define rt5645_suspend NULL +#define rt5645_resume NULL +#endif + +#define RT5645_STEREO_RATES SNDRV_PCM_RATE_8000_96000 +#define RT5645_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static struct snd_soc_dai_ops rt5645_aif_dai_ops = { + .hw_params = rt5645_hw_params, + .set_fmt = rt5645_set_dai_fmt, + .set_sysclk = rt5645_set_dai_sysclk, + .set_tdm_slot = rt5645_set_tdm_slot, + .set_pll = rt5645_set_dai_pll, +}; + +static struct snd_soc_dai_driver rt5645_dai[] = { + { + .name = "rt5645-aif1", + .id = RT5645_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5645_STEREO_RATES, + .formats = RT5645_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5645_STEREO_RATES, + .formats = RT5645_FORMATS, + }, + .ops = &rt5645_aif_dai_ops, + }, + { + .name = "rt5645-aif2", + .id = RT5645_AIF2, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5645_STEREO_RATES, + .formats = RT5645_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5645_STEREO_RATES, + .formats = RT5645_FORMATS, + }, + .ops = &rt5645_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5645 = { + .probe = rt5645_probe, + .remove = rt5645_remove, + .suspend = rt5645_suspend, + .resume = rt5645_resume, + .set_bias_level = rt5645_set_bias_level, + .idle_bias_off = true, + .controls = rt5645_snd_controls, + .num_controls = ARRAY_SIZE(rt5645_snd_controls), + .dapm_widgets = rt5645_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5645_dapm_widgets), + .dapm_routes = rt5645_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes), +}; + +static const struct regmap_config rt5645_regmap = { + .reg_bits = 8, + .val_bits = 16, + + .max_register = RT5645_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5645_ranges) * + RT5645_PR_SPACING), + .volatile_reg = rt5645_volatile_register, + .readable_reg = rt5645_readable_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5645_reg, + .num_reg_defaults = ARRAY_SIZE(rt5645_reg), + .ranges = rt5645_ranges, + .num_ranges = ARRAY_SIZE(rt5645_ranges), +}; + +static const struct i2c_device_id rt5645_i2c_id[] = { + { "rt5645", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id); + +static int rt5645_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5645_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt5645_priv *rt5645; + int ret; + unsigned int val; + + rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv), + GFP_KERNEL); + if (rt5645 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt5645); + + if (pdata) + rt5645->pdata = *pdata; + + rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap); + if (IS_ERR(rt5645->regmap)) { + ret = PTR_ERR(rt5645->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val); + if (val != RT5645_DEVICE_ID) { + dev_err(&i2c->dev, + "Device with ID register %x is not rt5645\n", val); + return -ENODEV; + } + + regmap_write(rt5645->regmap, RT5645_RESET, 0); + + ret = regmap_register_patch(rt5645->regmap, init_list, + ARRAY_SIZE(init_list)); + if (ret != 0) + dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + + if (rt5645->pdata.in2_diff) + regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL, + RT5645_IN_DF2, RT5645_IN_DF2); + + if (rt5645->pdata.dmic_en) { + regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, + RT5645_GP2_PIN_MASK, RT5645_GP2_PIN_DMIC1_SCL); + + switch (rt5645->pdata.dmic1_data_pin) { + case RT5645_DMIC_DATA_IN2N: + regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, + RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_IN2N); + break; + + case RT5645_DMIC_DATA_GPIO5: + regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, + RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5); + regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, + RT5645_GP5_PIN_MASK, RT5645_GP5_PIN_DMIC1_SDA); + break; + + case RT5645_DMIC_DATA_GPIO11: + regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, + RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO11); + regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, + RT5645_GP11_PIN_MASK, + RT5645_GP11_PIN_DMIC1_SDA); + break; + + default: + break; + } + + switch (rt5645->pdata.dmic2_data_pin) { + case RT5645_DMIC_DATA_IN2P: + regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, + RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_IN2P); + break; + + case RT5645_DMIC_DATA_GPIO6: + regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, + RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO6); + regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, + RT5645_GP6_PIN_MASK, RT5645_GP6_PIN_DMIC2_SDA); + break; + + case RT5645_DMIC_DATA_GPIO10: + regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, + RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO10); + regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, + RT5645_GP10_PIN_MASK, + RT5645_GP10_PIN_DMIC2_SDA); + break; + + case RT5645_DMIC_DATA_GPIO12: + regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, + RT5645_DMIC_1_DP_MASK, RT5645_DMIC_2_DP_GPIO12); + regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, + RT5645_GP12_PIN_MASK, + RT5645_GP12_PIN_DMIC2_SDA); + break; + + default: + break; + } + + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, + rt5645_dai, ARRAY_SIZE(rt5645_dai)); + if (ret < 0) + goto err; + + return 0; +err: + return ret; +} + +static int rt5645_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static struct i2c_driver rt5645_i2c_driver = { + .driver = { + .name = "rt5645", + .owner = THIS_MODULE, + }, + .probe = rt5645_i2c_probe, + .remove = rt5645_i2c_remove, + .id_table = rt5645_i2c_id, +}; +module_i2c_driver(rt5645_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5645 driver"); +MODULE_AUTHOR("Bard Liao "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h new file mode 100644 index 00000000000000..345aa3f5d14fc1 --- /dev/null +++ b/sound/soc/codecs/rt5645.h @@ -0,0 +1,2188 @@ +/* + * rt5645.h -- RT5645 ALSA SoC audio driver + * + * Copyright 2013 Realtek Microelectronics + * Author: Bard Liao + * + * 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 __RT5645_H__ +#define __RT5645_H__ + +#include + +/* Info */ +#define RT5645_RESET 0x00 +#define RT5645_VENDOR_ID 0xfd +#define RT5645_VENDOR_ID1 0xfe +#define RT5645_VENDOR_ID2 0xff +/* I/O - Output */ +#define RT5645_SPK_VOL 0x01 +#define RT5645_HP_VOL 0x02 +#define RT5645_LOUT1 0x03 +#define RT5645_LOUT_CTRL 0x05 +/* I/O - Input */ +#define RT5645_IN1_CTRL1 0x0a +#define RT5645_IN1_CTRL2 0x0b +#define RT5645_IN1_CTRL3 0x0c +#define RT5645_IN2_CTRL 0x0d +#define RT5645_INL1_INR1_VOL 0x0f +#define RT5645_SPK_FUNC_LIM 0x14 +#define RT5645_ADJ_HPF_CTRL 0x16 +/* I/O - ADC/DAC/DMIC */ +#define RT5645_DAC1_DIG_VOL 0x19 +#define RT5645_DAC2_DIG_VOL 0x1a +#define RT5645_DAC_CTRL 0x1b +#define RT5645_STO1_ADC_DIG_VOL 0x1c +#define RT5645_MONO_ADC_DIG_VOL 0x1d +#define RT5645_ADC_BST_VOL1 0x1e +/* Mixer - D-D */ +#define RT5645_ADC_BST_VOL2 0x20 +#define RT5645_STO1_ADC_MIXER 0x27 +#define RT5645_MONO_ADC_MIXER 0x28 +#define RT5645_AD_DA_MIXER 0x29 +#define RT5645_STO_DAC_MIXER 0x2a +#define RT5645_MONO_DAC_MIXER 0x2b +#define RT5645_DIG_MIXER 0x2c +#define RT5645_DIG_INF1_DATA 0x2f +/* Mixer - PDM */ +#define RT5645_PDM_OUT_CTRL 0x31 +/* Mixer - ADC */ +#define RT5645_REC_L1_MIXER 0x3b +#define RT5645_REC_L2_MIXER 0x3c +#define RT5645_REC_R1_MIXER 0x3d +#define RT5645_REC_R2_MIXER 0x3e +/* Mixer - DAC */ +#define RT5645_HPMIXL_CTRL 0x3f +#define RT5645_HPOMIXL_CTRL 0x40 +#define RT5645_HPMIXR_CTRL 0x41 +#define RT5645_HPOMIXR_CTRL 0x42 +#define RT5645_HPO_MIXER 0x45 +#define RT5645_SPK_L_MIXER 0x46 +#define RT5645_SPK_R_MIXER 0x47 +#define RT5645_SPO_MIXER 0x48 +#define RT5645_SPO_CLSD_RATIO 0x4a +#define RT5645_OUT_L_GAIN1 0x4d +#define RT5645_OUT_L_GAIN2 0x4e +#define RT5645_OUT_L1_MIXER 0x4f +#define RT5645_OUT_R_GAIN1 0x50 +#define RT5645_OUT_R_GAIN2 0x51 +#define RT5645_OUT_R1_MIXER 0x52 +#define RT5645_LOUT_MIXER 0x53 +/* Haptic */ +#define RT5645_HAPTIC_CTRL1 0x56 +#define RT5645_HAPTIC_CTRL2 0x57 +#define RT5645_HAPTIC_CTRL3 0x58 +#define RT5645_HAPTIC_CTRL4 0x59 +#define RT5645_HAPTIC_CTRL5 0x5a +#define RT5645_HAPTIC_CTRL6 0x5b +#define RT5645_HAPTIC_CTRL7 0x5c +#define RT5645_HAPTIC_CTRL8 0x5d +#define RT5645_HAPTIC_CTRL9 0x5e +#define RT5645_HAPTIC_CTRL10 0x5f +/* Power */ +#define RT5645_PWR_DIG1 0x61 +#define RT5645_PWR_DIG2 0x62 +#define RT5645_PWR_ANLG1 0x63 +#define RT5645_PWR_ANLG2 0x64 +#define RT5645_PWR_MIXER 0x65 +#define RT5645_PWR_VOL 0x66 +/* Private Register Control */ +#define RT5645_PRIV_INDEX 0x6a +#define RT5645_PRIV_DATA 0x6c +/* Format - ADC/DAC */ +#define RT5645_I2S1_SDP 0x70 +#define RT5645_I2S2_SDP 0x71 +#define RT5645_ADDA_CLK1 0x73 +#define RT5645_ADDA_CLK2 0x74 +#define RT5645_DMIC_CTRL1 0x75 +#define RT5645_DMIC_CTRL2 0x76 +/* Format - TDM Control */ +#define RT5645_TDM_CTRL_1 0x77 +#define RT5645_TDM_CTRL_2 0x78 +#define RT5645_TDM_CTRL_3 0x79 + +/* Function - Analog */ +#define RT5645_GLB_CLK 0x80 +#define RT5645_PLL_CTRL1 0x81 +#define RT5645_PLL_CTRL2 0x82 +#define RT5645_ASRC_1 0x83 +#define RT5645_ASRC_2 0x84 +#define RT5645_ASRC_3 0x85 +#define RT5645_ASRC_4 0x8a +#define RT5645_DEPOP_M1 0x8e +#define RT5645_DEPOP_M2 0x8f +#define RT5645_DEPOP_M3 0x90 +#define RT5645_CHARGE_PUMP 0x91 +#define RT5645_MICBIAS 0x93 +#define RT5645_A_JD_CTRL1 0x94 +#define RT5645_VAD_CTRL4 0x9d +#define RT5645_CLSD_OUT_CTRL 0xa0 +/* Function - Digital */ +#define RT5645_ADC_EQ_CTRL1 0xae +#define RT5645_ADC_EQ_CTRL2 0xaf +#define RT5645_EQ_CTRL1 0xb0 +#define RT5645_EQ_CTRL2 0xb1 +#define RT5645_ALC_CTRL_1 0xb3 +#define RT5645_ALC_CTRL_2 0xb4 +#define RT5645_ALC_CTRL_3 0xb5 +#define RT5645_ALC_CTRL_4 0xb6 +#define RT5645_ALC_CTRL_5 0xb7 +#define RT5645_JD_CTRL 0xbb +#define RT5645_IRQ_CTRL1 0xbc +#define RT5645_IRQ_CTRL2 0xbd +#define RT5645_IRQ_CTRL3 0xbe +#define RT5645_INT_IRQ_ST 0xbf +#define RT5645_GPIO_CTRL1 0xc0 +#define RT5645_GPIO_CTRL2 0xc1 +#define RT5645_GPIO_CTRL3 0xc2 +#define RT5645_BASS_BACK 0xcf +#define RT5645_MP3_PLUS1 0xd0 +#define RT5645_MP3_PLUS2 0xd1 +#define RT5645_ADJ_HPF1 0xd3 +#define RT5645_ADJ_HPF2 0xd4 +#define RT5645_HP_CALIB_AMP_DET 0xd6 +#define RT5645_SV_ZCD1 0xd9 +#define RT5645_SV_ZCD2 0xda +#define RT5645_IL_CMD 0xdb +#define RT5645_IL_CMD2 0xdc +#define RT5645_IL_CMD3 0xdd +#define RT5645_DRC1_HL_CTRL1 0xe7 +#define RT5645_DRC2_HL_CTRL1 0xe9 +#define RT5645_MUTI_DRC_CTRL1 0xea +#define RT5645_ADC_MONO_HP_CTRL1 0xec +#define RT5645_ADC_MONO_HP_CTRL2 0xed +#define RT5645_DRC2_CTRL1 0xf0 +#define RT5645_DRC2_CTRL2 0xf1 +#define RT5645_DRC2_CTRL3 0xf2 +#define RT5645_DRC2_CTRL4 0xf3 +#define RT5645_DRC2_CTRL5 0xf4 +#define RT5645_JD_CTRL3 0xf8 +#define RT5645_JD_CTRL4 0xf9 +/* General Control */ +#define RT5645_GEN_CTRL1 0xfa +#define RT5645_GEN_CTRL2 0xfb +#define RT5645_GEN_CTRL3 0xfc + + +/* Index of Codec Private Register definition */ +#define RT5645_DIG_VOL 0x00 +#define RT5645_PR_ALC_CTRL_1 0x01 +#define RT5645_PR_ALC_CTRL_2 0x02 +#define RT5645_PR_ALC_CTRL_3 0x03 +#define RT5645_PR_ALC_CTRL_4 0x04 +#define RT5645_PR_ALC_CTRL_5 0x05 +#define RT5645_PR_ALC_CTRL_6 0x06 +#define RT5645_BIAS_CUR1 0x12 +#define RT5645_BIAS_CUR3 0x14 +#define RT5645_CLSD_INT_REG1 0x1c +#define RT5645_MAMP_INT_REG2 0x37 +#define RT5645_CHOP_DAC_ADC 0x3d +#define RT5645_MIXER_INT_REG 0x3f +#define RT5645_3D_SPK 0x63 +#define RT5645_WND_1 0x6c +#define RT5645_WND_2 0x6d +#define RT5645_WND_3 0x6e +#define RT5645_WND_4 0x6f +#define RT5645_WND_5 0x70 +#define RT5645_WND_8 0x73 +#define RT5645_DIP_SPK_INF 0x75 +#define RT5645_HP_DCC_INT1 0x77 +#define RT5645_EQ_BW_LOP 0xa0 +#define RT5645_EQ_GN_LOP 0xa1 +#define RT5645_EQ_FC_BP1 0xa2 +#define RT5645_EQ_BW_BP1 0xa3 +#define RT5645_EQ_GN_BP1 0xa4 +#define RT5645_EQ_FC_BP2 0xa5 +#define RT5645_EQ_BW_BP2 0xa6 +#define RT5645_EQ_GN_BP2 0xa7 +#define RT5645_EQ_FC_BP3 0xa8 +#define RT5645_EQ_BW_BP3 0xa9 +#define RT5645_EQ_GN_BP3 0xaa +#define RT5645_EQ_FC_BP4 0xab +#define RT5645_EQ_BW_BP4 0xac +#define RT5645_EQ_GN_BP4 0xad +#define RT5645_EQ_FC_HIP1 0xae +#define RT5645_EQ_GN_HIP1 0xaf +#define RT5645_EQ_FC_HIP2 0xb0 +#define RT5645_EQ_BW_HIP2 0xb1 +#define RT5645_EQ_GN_HIP2 0xb2 +#define RT5645_EQ_PRE_VOL 0xb3 +#define RT5645_EQ_PST_VOL 0xb4 + + +/* global definition */ +#define RT5645_L_MUTE (0x1 << 15) +#define RT5645_L_MUTE_SFT 15 +#define RT5645_VOL_L_MUTE (0x1 << 14) +#define RT5645_VOL_L_SFT 14 +#define RT5645_R_MUTE (0x1 << 7) +#define RT5645_R_MUTE_SFT 7 +#define RT5645_VOL_R_MUTE (0x1 << 6) +#define RT5645_VOL_R_SFT 6 +#define RT5645_L_VOL_MASK (0x3f << 8) +#define RT5645_L_VOL_SFT 8 +#define RT5645_R_VOL_MASK (0x3f) +#define RT5645_R_VOL_SFT 0 + +/* IN1 Control 1 (0x0a) */ +#define RT5645_CBJ_BST1_MASK (0xf << 12) +#define RT5645_CBJ_BST1_SFT (12) +#define RT5645_CBJ_JD_HP_EN (0x1 << 9) +#define RT5645_CBJ_JD_MIC_EN (0x1 << 8) +#define RT5645_CBJ_JD_MIC_SW_EN (0x1 << 7) +#define RT5645_CBJ_MIC_SEL_R (0x1 << 6) +#define RT5645_CBJ_MIC_SEL_L (0x1 << 5) +#define RT5645_CBJ_MIC_SW (0x1 << 4) +#define RT5645_CBJ_BST1_EN (0x1 << 2) + +/* IN1 Control 2 (0x0b) */ +#define RT5645_CBJ_MN_JD (0x1 << 12) +#define RT5645_CAPLESS_EN (0x1 << 11) +#define RT5645_CBJ_DET_MODE (0x1 << 7) + +/* IN1 Control 3 (0x0c) */ +#define RT5645_CBJ_TIE_G_L (0x1 << 15) +#define RT5645_CBJ_TIE_G_R (0x1 << 14) + +/* IN2 Control (0x0d) */ +#define RT5645_BST_MASK1 (0xf<<12) +#define RT5645_BST_SFT1 12 +#define RT5645_BST_MASK2 (0xf<<8) +#define RT5645_BST_SFT2 8 +#define RT5645_IN_DF2 (0x1 << 6) +#define RT5645_IN_SFT2 6 + +/* INL and INR Volume Control (0x0f) */ +#define RT5645_INL_SEL_MASK (0x1 << 15) +#define RT5645_INL_SEL_SFT 15 +#define RT5645_INL_SEL_IN4P (0x0 << 15) +#define RT5645_INL_SEL_MONOP (0x1 << 15) +#define RT5645_INL_VOL_MASK (0x1f << 8) +#define RT5645_INL_VOL_SFT 8 +#define RT5645_INR_SEL_MASK (0x1 << 7) +#define RT5645_INR_SEL_SFT 7 +#define RT5645_INR_SEL_IN4N (0x0 << 7) +#define RT5645_INR_SEL_MONON (0x1 << 7) +#define RT5645_INR_VOL_MASK (0x1f) +#define RT5645_INR_VOL_SFT 0 + +/* DAC1 Digital Volume (0x19) */ +#define RT5645_DAC_L1_VOL_MASK (0xff << 8) +#define RT5645_DAC_L1_VOL_SFT 8 +#define RT5645_DAC_R1_VOL_MASK (0xff) +#define RT5645_DAC_R1_VOL_SFT 0 + +/* DAC2 Digital Volume (0x1a) */ +#define RT5645_DAC_L2_VOL_MASK (0xff << 8) +#define RT5645_DAC_L2_VOL_SFT 8 +#define RT5645_DAC_R2_VOL_MASK (0xff) +#define RT5645_DAC_R2_VOL_SFT 0 + +/* DAC2 Control (0x1b) */ +#define RT5645_M_DAC_L2_VOL (0x1 << 13) +#define RT5645_M_DAC_L2_VOL_SFT 13 +#define RT5645_M_DAC_R2_VOL (0x1 << 12) +#define RT5645_M_DAC_R2_VOL_SFT 12 +#define RT5645_DAC2_L_SEL_MASK (0x7 << 4) +#define RT5645_DAC2_L_SEL_SFT 4 +#define RT5645_DAC2_R_SEL_MASK (0x7 << 0) +#define RT5645_DAC2_R_SEL_SFT 0 + +/* ADC Digital Volume Control (0x1c) */ +#define RT5645_ADC_L_VOL_MASK (0x7f << 8) +#define RT5645_ADC_L_VOL_SFT 8 +#define RT5645_ADC_R_VOL_MASK (0x7f) +#define RT5645_ADC_R_VOL_SFT 0 + +/* Mono ADC Digital Volume Control (0x1d) */ +#define RT5645_MONO_ADC_L_VOL_MASK (0x7f << 8) +#define RT5645_MONO_ADC_L_VOL_SFT 8 +#define RT5645_MONO_ADC_R_VOL_MASK (0x7f) +#define RT5645_MONO_ADC_R_VOL_SFT 0 + +/* ADC Boost Volume Control (0x1e) */ +#define RT5645_STO1_ADC_L_BST_MASK (0x3 << 14) +#define RT5645_STO1_ADC_L_BST_SFT 14 +#define RT5645_STO1_ADC_R_BST_MASK (0x3 << 12) +#define RT5645_STO1_ADC_R_BST_SFT 12 +#define RT5645_STO1_ADC_COMP_MASK (0x3 << 10) +#define RT5645_STO1_ADC_COMP_SFT 10 +#define RT5645_STO2_ADC_L_BST_MASK (0x3 << 8) +#define RT5645_STO2_ADC_L_BST_SFT 8 +#define RT5645_STO2_ADC_R_BST_MASK (0x3 << 6) +#define RT5645_STO2_ADC_R_BST_SFT 6 +#define RT5645_STO2_ADC_COMP_MASK (0x3 << 4) +#define RT5645_STO2_ADC_COMP_SFT 4 + +/* Stereo2 ADC Mixer Control (0x26) */ +#define RT5645_STO2_ADC_SRC_MASK (0x1 << 15) +#define RT5645_STO2_ADC_SRC_SFT 15 + +/* Stereo ADC Mixer Control (0x27) */ +#define RT5645_M_ADC_L1 (0x1 << 14) +#define RT5645_M_ADC_L1_SFT 14 +#define RT5645_M_ADC_L2 (0x1 << 13) +#define RT5645_M_ADC_L2_SFT 13 +#define RT5645_ADC_1_SRC_MASK (0x1 << 12) +#define RT5645_ADC_1_SRC_SFT 12 +#define RT5645_ADC_1_SRC_ADC (0x1 << 12) +#define RT5645_ADC_1_SRC_DACMIX (0x0 << 12) +#define RT5645_ADC_2_SRC_MASK (0x1 << 11) +#define RT5645_ADC_2_SRC_SFT 11 +#define RT5645_DMIC_SRC_MASK (0x1 << 8) +#define RT5645_DMIC_SRC_SFT 8 +#define RT5645_M_ADC_R1 (0x1 << 6) +#define RT5645_M_ADC_R1_SFT 6 +#define RT5645_M_ADC_R2 (0x1 << 5) +#define RT5645_M_ADC_R2_SFT 5 +#define RT5645_DMIC3_SRC_MASK (0x1 << 1) +#define RT5645_DMIC3_SRC_SFT 0 + +/* Mono ADC Mixer Control (0x28) */ +#define RT5645_M_MONO_ADC_L1 (0x1 << 14) +#define RT5645_M_MONO_ADC_L1_SFT 14 +#define RT5645_M_MONO_ADC_L2 (0x1 << 13) +#define RT5645_M_MONO_ADC_L2_SFT 13 +#define RT5645_MONO_ADC_L1_SRC_MASK (0x1 << 12) +#define RT5645_MONO_ADC_L1_SRC_SFT 12 +#define RT5645_MONO_ADC_L1_SRC_DACMIXL (0x0 << 12) +#define RT5645_MONO_ADC_L1_SRC_ADCL (0x1 << 12) +#define RT5645_MONO_ADC_L2_SRC_MASK (0x1 << 11) +#define RT5645_MONO_ADC_L2_SRC_SFT 11 +#define RT5645_MONO_DMIC_L_SRC_MASK (0x1 << 8) +#define RT5645_MONO_DMIC_L_SRC_SFT 8 +#define RT5645_M_MONO_ADC_R1 (0x1 << 6) +#define RT5645_M_MONO_ADC_R1_SFT 6 +#define RT5645_M_MONO_ADC_R2 (0x1 << 5) +#define RT5645_M_MONO_ADC_R2_SFT 5 +#define RT5645_MONO_ADC_R1_SRC_MASK (0x1 << 4) +#define RT5645_MONO_ADC_R1_SRC_SFT 4 +#define RT5645_MONO_ADC_R1_SRC_ADCR (0x1 << 4) +#define RT5645_MONO_ADC_R1_SRC_DACMIXR (0x0 << 4) +#define RT5645_MONO_ADC_R2_SRC_MASK (0x1 << 3) +#define RT5645_MONO_ADC_R2_SRC_SFT 3 +#define RT5645_MONO_DMIC_R_SRC_MASK (0x3) +#define RT5645_MONO_DMIC_R_SRC_SFT 0 + +/* ADC Mixer to DAC Mixer Control (0x29) */ +#define RT5645_M_ADCMIX_L (0x1 << 15) +#define RT5645_M_ADCMIX_L_SFT 15 +#define RT5645_M_DAC1_L (0x1 << 14) +#define RT5645_M_DAC1_L_SFT 14 +#define RT5645_DAC1_R_SEL_MASK (0x3 << 10) +#define RT5645_DAC1_R_SEL_SFT 10 +#define RT5645_DAC1_R_SEL_IF1 (0x0 << 10) +#define RT5645_DAC1_R_SEL_IF2 (0x1 << 10) +#define RT5645_DAC1_R_SEL_IF3 (0x2 << 10) +#define RT5645_DAC1_R_SEL_IF4 (0x3 << 10) +#define RT5645_DAC1_L_SEL_MASK (0x3 << 8) +#define RT5645_DAC1_L_SEL_SFT 8 +#define RT5645_DAC1_L_SEL_IF1 (0x0 << 8) +#define RT5645_DAC1_L_SEL_IF2 (0x1 << 8) +#define RT5645_DAC1_L_SEL_IF3 (0x2 << 8) +#define RT5645_DAC1_L_SEL_IF4 (0x3 << 8) +#define RT5645_M_ADCMIX_R (0x1 << 7) +#define RT5645_M_ADCMIX_R_SFT 7 +#define RT5645_M_DAC1_R (0x1 << 6) +#define RT5645_M_DAC1_R_SFT 6 + +/* Stereo DAC Mixer Control (0x2a) */ +#define RT5645_M_DAC_L1 (0x1 << 14) +#define RT5645_M_DAC_L1_SFT 14 +#define RT5645_DAC_L1_STO_L_VOL_MASK (0x1 << 13) +#define RT5645_DAC_L1_STO_L_VOL_SFT 13 +#define RT5645_M_DAC_L2 (0x1 << 12) +#define RT5645_M_DAC_L2_SFT 12 +#define RT5645_DAC_L2_STO_L_VOL_MASK (0x1 << 11) +#define RT5645_DAC_L2_STO_L_VOL_SFT 11 +#define RT5645_M_ANC_DAC_L (0x1 << 10) +#define RT5645_M_ANC_DAC_L_SFT 10 +#define RT5645_M_DAC_R1_STO_L (0x1 << 9) +#define RT5645_M_DAC_R1_STO_L_SFT 9 +#define RT5645_DAC_R1_STO_L_VOL_MASK (0x1 << 8) +#define RT5645_DAC_R1_STO_L_VOL_SFT 8 +#define RT5645_M_DAC_R1 (0x1 << 6) +#define RT5645_M_DAC_R1_SFT 6 +#define RT5645_DAC_R1_STO_R_VOL_MASK (0x1 << 5) +#define RT5645_DAC_R1_STO_R_VOL_SFT 5 +#define RT5645_M_DAC_R2 (0x1 << 4) +#define RT5645_M_DAC_R2_SFT 4 +#define RT5645_DAC_R2_STO_R_VOL_MASK (0x1 << 3) +#define RT5645_DAC_R2_STO_R_VOL_SFT 3 +#define RT5645_M_ANC_DAC_R (0x1 << 2) +#define RT5645_M_ANC_DAC_R_SFT 2 +#define RT5645_M_DAC_L1_STO_R (0x1 << 1) +#define RT5645_M_DAC_L1_STO_R_SFT 1 +#define RT5645_DAC_L1_STO_R_VOL_MASK (0x1) +#define RT5645_DAC_L1_STO_R_VOL_SFT 0 + +/* Mono DAC Mixer Control (0x2b) */ +#define RT5645_M_DAC_L1_MONO_L (0x1 << 14) +#define RT5645_M_DAC_L1_MONO_L_SFT 14 +#define RT5645_DAC_L1_MONO_L_VOL_MASK (0x1 << 13) +#define RT5645_DAC_L1_MONO_L_VOL_SFT 13 +#define RT5645_M_DAC_L2_MONO_L (0x1 << 12) +#define RT5645_M_DAC_L2_MONO_L_SFT 12 +#define RT5645_DAC_L2_MONO_L_VOL_MASK (0x1 << 11) +#define RT5645_DAC_L2_MONO_L_VOL_SFT 11 +#define RT5645_M_DAC_R2_MONO_L (0x1 << 10) +#define RT5645_M_DAC_R2_MONO_L_SFT 10 +#define RT5645_DAC_R2_MONO_L_VOL_MASK (0x1 << 9) +#define RT5645_DAC_R2_MONO_L_VOL_SFT 9 +#define RT5645_M_DAC_R1_MONO_R (0x1 << 6) +#define RT5645_M_DAC_R1_MONO_R_SFT 6 +#define RT5645_DAC_R1_MONO_R_VOL_MASK (0x1 << 5) +#define RT5645_DAC_R1_MONO_R_VOL_SFT 5 +#define RT5645_M_DAC_R2_MONO_R (0x1 << 4) +#define RT5645_M_DAC_R2_MONO_R_SFT 4 +#define RT5645_DAC_R2_MONO_R_VOL_MASK (0x1 << 3) +#define RT5645_DAC_R2_MONO_R_VOL_SFT 3 +#define RT5645_M_DAC_L2_MONO_R (0x1 << 2) +#define RT5645_M_DAC_L2_MONO_R_SFT 2 +#define RT5645_DAC_L2_MONO_R_VOL_MASK (0x1 << 1) +#define RT5645_DAC_L2_MONO_R_VOL_SFT 1 + +/* Digital Mixer Control (0x2c) */ +#define RT5645_M_STO_L_DAC_L (0x1 << 15) +#define RT5645_M_STO_L_DAC_L_SFT 15 +#define RT5645_STO_L_DAC_L_VOL_MASK (0x1 << 14) +#define RT5645_STO_L_DAC_L_VOL_SFT 14 +#define RT5645_M_DAC_L2_DAC_L (0x1 << 13) +#define RT5645_M_DAC_L2_DAC_L_SFT 13 +#define RT5645_DAC_L2_DAC_L_VOL_MASK (0x1 << 12) +#define RT5645_DAC_L2_DAC_L_VOL_SFT 12 +#define RT5645_M_STO_R_DAC_R (0x1 << 11) +#define RT5645_M_STO_R_DAC_R_SFT 11 +#define RT5645_STO_R_DAC_R_VOL_MASK (0x1 << 10) +#define RT5645_STO_R_DAC_R_VOL_SFT 10 +#define RT5645_M_DAC_R2_DAC_R (0x1 << 9) +#define RT5645_M_DAC_R2_DAC_R_SFT 9 +#define RT5645_DAC_R2_DAC_R_VOL_MASK (0x1 << 8) +#define RT5645_DAC_R2_DAC_R_VOL_SFT 8 +#define RT5645_M_DAC_R2_DAC_L (0x1 << 7) +#define RT5645_M_DAC_R2_DAC_L_SFT 7 +#define RT5645_DAC_R2_DAC_L_VOL_MASK (0x1 << 6) +#define RT5645_DAC_R2_DAC_L_VOL_SFT 6 +#define RT5645_M_DAC_L2_DAC_R (0x1 << 5) +#define RT5645_M_DAC_L2_DAC_R_SFT 5 +#define RT5645_DAC_L2_DAC_R_VOL_MASK (0x1 << 4) +#define RT5645_DAC_L2_DAC_R_VOL_SFT 4 + +/* Digital Interface Data Control (0x2f) */ +#define RT5645_IF1_ADC2_IN_SEL (0x1 << 15) +#define RT5645_IF1_ADC2_IN_SFT 15 +#define RT5645_IF2_ADC_IN_MASK (0x7 << 12) +#define RT5645_IF2_ADC_IN_SFT 12 +#define RT5645_IF2_DAC_SEL_MASK (0x3 << 10) +#define RT5645_IF2_DAC_SEL_SFT 10 +#define RT5645_IF2_ADC_SEL_MASK (0x3 << 8) +#define RT5645_IF2_ADC_SEL_SFT 8 +#define RT5645_IF3_DAC_SEL_MASK (0x3 << 6) +#define RT5645_IF3_DAC_SEL_SFT 6 +#define RT5645_IF3_ADC_SEL_MASK (0x3 << 4) +#define RT5645_IF3_ADC_SEL_SFT 4 +#define RT5645_IF3_ADC_IN_MASK (0x7) +#define RT5645_IF3_ADC_IN_SFT 0 + +/* PDM Output Control (0x31) */ +#define RT5645_PDM1_L_MASK (0x1 << 15) +#define RT5645_PDM1_L_SFT 15 +#define RT5645_M_PDM1_L (0x1 << 14) +#define RT5645_M_PDM1_L_SFT 14 +#define RT5645_PDM1_R_MASK (0x1 << 13) +#define RT5645_PDM1_R_SFT 13 +#define RT5645_M_PDM1_R (0x1 << 12) +#define RT5645_M_PDM1_R_SFT 12 +#define RT5645_PDM2_L_MASK (0x1 << 11) +#define RT5645_PDM2_L_SFT 11 +#define RT5645_M_PDM2_L (0x1 << 10) +#define RT5645_M_PDM2_L_SFT 10 +#define RT5645_PDM2_R_MASK (0x1 << 9) +#define RT5645_PDM2_R_SFT 9 +#define RT5645_M_PDM2_R (0x1 << 8) +#define RT5645_M_PDM2_R_SFT 8 +#define RT5645_PDM2_BUSY (0x1 << 7) +#define RT5645_PDM1_BUSY (0x1 << 6) +#define RT5645_PDM_PATTERN (0x1 << 5) +#define RT5645_PDM_GAIN (0x1 << 4) +#define RT5645_PDM_DIV_MASK (0x3) + +/* REC Left Mixer Control 1 (0x3b) */ +#define RT5645_G_HP_L_RM_L_MASK (0x7 << 13) +#define RT5645_G_HP_L_RM_L_SFT 13 +#define RT5645_G_IN_L_RM_L_MASK (0x7 << 10) +#define RT5645_G_IN_L_RM_L_SFT 10 +#define RT5645_G_BST4_RM_L_MASK (0x7 << 7) +#define RT5645_G_BST4_RM_L_SFT 7 +#define RT5645_G_BST3_RM_L_MASK (0x7 << 4) +#define RT5645_G_BST3_RM_L_SFT 4 +#define RT5645_G_BST2_RM_L_MASK (0x7 << 1) +#define RT5645_G_BST2_RM_L_SFT 1 + +/* REC Left Mixer Control 2 (0x3c) */ +#define RT5645_G_BST1_RM_L_MASK (0x7 << 13) +#define RT5645_G_BST1_RM_L_SFT 13 +#define RT5645_G_OM_L_RM_L_MASK (0x7 << 10) +#define RT5645_G_OM_L_RM_L_SFT 10 +#define RT5645_M_MM_L_RM_L (0x1 << 6) +#define RT5645_M_MM_L_RM_L_SFT 6 +#define RT5645_M_IN_L_RM_L (0x1 << 5) +#define RT5645_M_IN_L_RM_L_SFT 5 +#define RT5645_M_HP_L_RM_L (0x1 << 4) +#define RT5645_M_HP_L_RM_L_SFT 4 +#define RT5645_M_BST3_RM_L (0x1 << 3) +#define RT5645_M_BST3_RM_L_SFT 3 +#define RT5645_M_BST2_RM_L (0x1 << 2) +#define RT5645_M_BST2_RM_L_SFT 2 +#define RT5645_M_BST1_RM_L (0x1 << 1) +#define RT5645_M_BST1_RM_L_SFT 1 +#define RT5645_M_OM_L_RM_L (0x1) +#define RT5645_M_OM_L_RM_L_SFT 0 + +/* REC Right Mixer Control 1 (0x3d) */ +#define RT5645_G_HP_R_RM_R_MASK (0x7 << 13) +#define RT5645_G_HP_R_RM_R_SFT 13 +#define RT5645_G_IN_R_RM_R_MASK (0x7 << 10) +#define RT5645_G_IN_R_RM_R_SFT 10 +#define RT5645_G_BST4_RM_R_MASK (0x7 << 7) +#define RT5645_G_BST4_RM_R_SFT 7 +#define RT5645_G_BST3_RM_R_MASK (0x7 << 4) +#define RT5645_G_BST3_RM_R_SFT 4 +#define RT5645_G_BST2_RM_R_MASK (0x7 << 1) +#define RT5645_G_BST2_RM_R_SFT 1 + +/* REC Right Mixer Control 2 (0x3e) */ +#define RT5645_G_BST1_RM_R_MASK (0x7 << 13) +#define RT5645_G_BST1_RM_R_SFT 13 +#define RT5645_G_OM_R_RM_R_MASK (0x7 << 10) +#define RT5645_G_OM_R_RM_R_SFT 10 +#define RT5645_M_MM_R_RM_R (0x1 << 6) +#define RT5645_M_MM_R_RM_R_SFT 6 +#define RT5645_M_IN_R_RM_R (0x1 << 5) +#define RT5645_M_IN_R_RM_R_SFT 5 +#define RT5645_M_HP_R_RM_R (0x1 << 4) +#define RT5645_M_HP_R_RM_R_SFT 4 +#define RT5645_M_BST3_RM_R (0x1 << 3) +#define RT5645_M_BST3_RM_R_SFT 3 +#define RT5645_M_BST2_RM_R (0x1 << 2) +#define RT5645_M_BST2_RM_R_SFT 2 +#define RT5645_M_BST1_RM_R (0x1 << 1) +#define RT5645_M_BST1_RM_R_SFT 1 +#define RT5645_M_OM_R_RM_R (0x1) +#define RT5645_M_OM_R_RM_R_SFT 0 + +/* HPOMIX Control (0x40) (0x42) */ +#define RT5645_M_BST1_HV (0x1 << 4) +#define RT5645_M_BST1_HV_SFT 4 +#define RT5645_M_BST2_HV (0x1 << 4) +#define RT5645_M_BST2_HV_SFT 4 +#define RT5645_M_BST3_HV (0x1 << 3) +#define RT5645_M_BST3_HV_SFT 3 +#define RT5645_M_IN_HV (0x1 << 2) +#define RT5645_M_IN_HV_SFT 2 +#define RT5645_M_DAC2_HV (0x1 << 1) +#define RT5645_M_DAC2_HV_SFT 1 +#define RT5645_M_DAC1_HV (0x1 << 0) +#define RT5645_M_DAC1_HV_SFT 0 + +/* HPMIX Control (0x45) */ +#define RT5645_M_DAC1_HM (0x1 << 14) +#define RT5645_M_DAC1_HM_SFT 14 +#define RT5645_M_HPVOL_HM (0x1 << 13) +#define RT5645_M_HPVOL_HM_SFT 13 + +/* SPK Left Mixer Control (0x46) */ +#define RT5645_G_RM_L_SM_L_MASK (0x3 << 14) +#define RT5645_G_RM_L_SM_L_SFT 14 +#define RT5645_G_IN_L_SM_L_MASK (0x3 << 12) +#define RT5645_G_IN_L_SM_L_SFT 12 +#define RT5645_G_DAC_L1_SM_L_MASK (0x3 << 10) +#define RT5645_G_DAC_L1_SM_L_SFT 10 +#define RT5645_G_DAC_L2_SM_L_MASK (0x3 << 8) +#define RT5645_G_DAC_L2_SM_L_SFT 8 +#define RT5645_G_OM_L_SM_L_MASK (0x3 << 6) +#define RT5645_G_OM_L_SM_L_SFT 6 +#define RT5645_M_BST1_L_SM_L (0x1 << 5) +#define RT5645_M_BST1_L_SM_L_SFT 5 +#define RT5645_M_IN_L_SM_L (0x1 << 3) +#define RT5645_M_IN_L_SM_L_SFT 3 +#define RT5645_M_DAC_L1_SM_L (0x1 << 1) +#define RT5645_M_DAC_L1_SM_L_SFT 1 +#define RT5645_M_DAC_L2_SM_L (0x1 << 2) +#define RT5645_M_DAC_L2_SM_L_SFT 2 +#define RT5645_M_BST3_L_SM_L (0x1 << 4) +#define RT5645_M_BST3_L_SM_L_SFT 4 + +/* SPK Right Mixer Control (0x47) */ +#define RT5645_G_RM_R_SM_R_MASK (0x3 << 14) +#define RT5645_G_RM_R_SM_R_SFT 14 +#define RT5645_G_IN_R_SM_R_MASK (0x3 << 12) +#define RT5645_G_IN_R_SM_R_SFT 12 +#define RT5645_G_DAC_R1_SM_R_MASK (0x3 << 10) +#define RT5645_G_DAC_R1_SM_R_SFT 10 +#define RT5645_G_DAC_R2_SM_R_MASK (0x3 << 8) +#define RT5645_G_DAC_R2_SM_R_SFT 8 +#define RT5645_G_OM_R_SM_R_MASK (0x3 << 6) +#define RT5645_G_OM_R_SM_R_SFT 6 +#define RT5645_M_BST2_R_SM_R (0x1 << 5) +#define RT5645_M_BST2_R_SM_R_SFT 5 +#define RT5645_M_IN_R_SM_R (0x1 << 3) +#define RT5645_M_IN_R_SM_R_SFT 3 +#define RT5645_M_DAC_R1_SM_R (0x1 << 1) +#define RT5645_M_DAC_R1_SM_R_SFT 1 +#define RT5645_M_DAC_R2_SM_R (0x1 << 2) +#define RT5645_M_DAC_R2_SM_R_SFT 2 +#define RT5645_M_BST3_R_SM_R (0x1 << 4) +#define RT5645_M_BST3_R_SM_R_SFT 4 + +/* SPOLMIX Control (0x48) */ +#define RT5645_M_DAC_L1_SPM_L (0x1 << 15) +#define RT5645_M_DAC_L1_SPM_L_SFT 15 +#define RT5645_M_DAC_R1_SPM_L (0x1 << 14) +#define RT5645_M_DAC_R1_SPM_L_SFT 14 +#define RT5645_M_SV_L_SPM_L (0x1 << 13) +#define RT5645_M_SV_L_SPM_L_SFT 13 +#define RT5645_M_SV_R_SPM_L (0x1 << 12) +#define RT5645_M_SV_R_SPM_L_SFT 12 +#define RT5645_M_BST3_SPM_L (0x1 << 11) +#define RT5645_M_BST3_SPM_L_SFT 11 +#define RT5645_M_DAC_R1_SPM_R (0x1 << 2) +#define RT5645_M_DAC_R1_SPM_R_SFT 2 +#define RT5645_M_BST3_SPM_R (0x1 << 1) +#define RT5645_M_BST3_SPM_R_SFT 1 +#define RT5645_M_SV_R_SPM_R (0x1 << 0) +#define RT5645_M_SV_R_SPM_R_SFT 0 + +/* Mono Output Mixer Control (0x4c) */ +#define RT5645_M_OV_L_MM (0x1 << 9) +#define RT5645_M_OV_L_MM_SFT 9 +#define RT5645_M_DAC_L2_MA (0x1 << 8) +#define RT5645_M_DAC_L2_MA_SFT 8 +#define RT5645_G_MONOMIX_MASK (0x1 << 10) +#define RT5645_G_MONOMIX_SFT 10 +#define RT5645_M_BST2_MM (0x1 << 4) +#define RT5645_M_BST2_MM_SFT 4 +#define RT5645_M_DAC_R1_MM (0x1 << 3) +#define RT5645_M_DAC_R1_MM_SFT 3 +#define RT5645_M_DAC_R2_MM (0x1 << 2) +#define RT5645_M_DAC_R2_MM_SFT 2 +#define RT5645_M_DAC_L2_MM (0x1 << 1) +#define RT5645_M_DAC_L2_MM_SFT 1 +#define RT5645_M_BST3_MM (0x1 << 0) +#define RT5645_M_BST3_MM_SFT 0 + +/* Output Left Mixer Control 1 (0x4d) */ +#define RT5645_G_BST3_OM_L_MASK (0x7 << 13) +#define RT5645_G_BST3_OM_L_SFT 13 +#define RT5645_G_BST2_OM_L_MASK (0x7 << 10) +#define RT5645_G_BST2_OM_L_SFT 10 +#define RT5645_G_BST1_OM_L_MASK (0x7 << 7) +#define RT5645_G_BST1_OM_L_SFT 7 +#define RT5645_G_IN_L_OM_L_MASK (0x7 << 4) +#define RT5645_G_IN_L_OM_L_SFT 4 +#define RT5645_G_RM_L_OM_L_MASK (0x7 << 1) +#define RT5645_G_RM_L_OM_L_SFT 1 + +/* Output Left Mixer Control 2 (0x4e) */ +#define RT5645_G_DAC_R2_OM_L_MASK (0x7 << 13) +#define RT5645_G_DAC_R2_OM_L_SFT 13 +#define RT5645_G_DAC_L2_OM_L_MASK (0x7 << 10) +#define RT5645_G_DAC_L2_OM_L_SFT 10 +#define RT5645_G_DAC_L1_OM_L_MASK (0x7 << 7) +#define RT5645_G_DAC_L1_OM_L_SFT 7 + +/* Output Left Mixer Control 3 (0x4f) */ +#define RT5645_M_BST3_OM_L (0x1 << 4) +#define RT5645_M_BST3_OM_L_SFT 4 +#define RT5645_M_BST1_OM_L (0x1 << 3) +#define RT5645_M_BST1_OM_L_SFT 3 +#define RT5645_M_IN_L_OM_L (0x1 << 2) +#define RT5645_M_IN_L_OM_L_SFT 2 +#define RT5645_M_DAC_L2_OM_L (0x1 << 1) +#define RT5645_M_DAC_L2_OM_L_SFT 1 +#define RT5645_M_DAC_L1_OM_L (0x1) +#define RT5645_M_DAC_L1_OM_L_SFT 0 + +/* Output Right Mixer Control 1 (0x50) */ +#define RT5645_G_BST4_OM_R_MASK (0x7 << 13) +#define RT5645_G_BST4_OM_R_SFT 13 +#define RT5645_G_BST2_OM_R_MASK (0x7 << 10) +#define RT5645_G_BST2_OM_R_SFT 10 +#define RT5645_G_BST1_OM_R_MASK (0x7 << 7) +#define RT5645_G_BST1_OM_R_SFT 7 +#define RT5645_G_IN_R_OM_R_MASK (0x7 << 4) +#define RT5645_G_IN_R_OM_R_SFT 4 +#define RT5645_G_RM_R_OM_R_MASK (0x7 << 1) +#define RT5645_G_RM_R_OM_R_SFT 1 + +/* Output Right Mixer Control 2 (0x51) */ +#define RT5645_G_DAC_L2_OM_R_MASK (0x7 << 13) +#define RT5645_G_DAC_L2_OM_R_SFT 13 +#define RT5645_G_DAC_R2_OM_R_MASK (0x7 << 10) +#define RT5645_G_DAC_R2_OM_R_SFT 10 +#define RT5645_G_DAC_R1_OM_R_MASK (0x7 << 7) +#define RT5645_G_DAC_R1_OM_R_SFT 7 + +/* Output Right Mixer Control 3 (0x52) */ +#define RT5645_M_BST3_OM_R (0x1 << 4) +#define RT5645_M_BST3_OM_R_SFT 4 +#define RT5645_M_BST2_OM_R (0x1 << 3) +#define RT5645_M_BST2_OM_R_SFT 3 +#define RT5645_M_IN_R_OM_R (0x1 << 2) +#define RT5645_M_IN_R_OM_R_SFT 2 +#define RT5645_M_DAC_R2_OM_R (0x1 << 1) +#define RT5645_M_DAC_R2_OM_R_SFT 1 +#define RT5645_M_DAC_R1_OM_R (0x1) +#define RT5645_M_DAC_R1_OM_R_SFT 0 + +/* LOUT Mixer Control (0x53) */ +#define RT5645_M_DAC_L1_LM (0x1 << 15) +#define RT5645_M_DAC_L1_LM_SFT 15 +#define RT5645_M_DAC_R1_LM (0x1 << 14) +#define RT5645_M_DAC_R1_LM_SFT 14 +#define RT5645_M_OV_L_LM (0x1 << 13) +#define RT5645_M_OV_L_LM_SFT 13 +#define RT5645_M_OV_R_LM (0x1 << 12) +#define RT5645_M_OV_R_LM_SFT 12 +#define RT5645_G_LOUTMIX_MASK (0x1 << 11) +#define RT5645_G_LOUTMIX_SFT 11 + +/* Power Management for Digital 1 (0x61) */ +#define RT5645_PWR_I2S1 (0x1 << 15) +#define RT5645_PWR_I2S1_BIT 15 +#define RT5645_PWR_I2S2 (0x1 << 14) +#define RT5645_PWR_I2S2_BIT 14 +#define RT5645_PWR_I2S3 (0x1 << 13) +#define RT5645_PWR_I2S3_BIT 13 +#define RT5645_PWR_DAC_L1 (0x1 << 12) +#define RT5645_PWR_DAC_L1_BIT 12 +#define RT5645_PWR_DAC_R1 (0x1 << 11) +#define RT5645_PWR_DAC_R1_BIT 11 +#define RT5645_PWR_CLS_D_R (0x1 << 9) +#define RT5645_PWR_CLS_D_R_BIT 9 +#define RT5645_PWR_CLS_D_L (0x1 << 8) +#define RT5645_PWR_CLS_D_L_BIT 8 +#define RT5645_PWR_ADC_R (0x1 << 1) +#define RT5645_PWR_ADC_R_BIT 1 +#define RT5645_PWR_DAC_L2 (0x1 << 7) +#define RT5645_PWR_DAC_L2_BIT 7 +#define RT5645_PWR_DAC_R2 (0x1 << 6) +#define RT5645_PWR_DAC_R2_BIT 6 +#define RT5645_PWR_ADC_L (0x1 << 2) +#define RT5645_PWR_ADC_L_BIT 2 +#define RT5645_PWR_ADC_R (0x1 << 1) +#define RT5645_PWR_ADC_R_BIT 1 +#define RT5645_PWR_CLS_D (0x1) +#define RT5645_PWR_CLS_D_BIT 0 + +/* Power Management for Digital 2 (0x62) */ +#define RT5645_PWR_ADC_S1F (0x1 << 15) +#define RT5645_PWR_ADC_S1F_BIT 15 +#define RT5645_PWR_ADC_MF_L (0x1 << 14) +#define RT5645_PWR_ADC_MF_L_BIT 14 +#define RT5645_PWR_ADC_MF_R (0x1 << 13) +#define RT5645_PWR_ADC_MF_R_BIT 13 +#define RT5645_PWR_I2S_DSP (0x1 << 12) +#define RT5645_PWR_I2S_DSP_BIT 12 +#define RT5645_PWR_DAC_S1F (0x1 << 11) +#define RT5645_PWR_DAC_S1F_BIT 11 +#define RT5645_PWR_DAC_MF_L (0x1 << 10) +#define RT5645_PWR_DAC_MF_L_BIT 10 +#define RT5645_PWR_DAC_MF_R (0x1 << 9) +#define RT5645_PWR_DAC_MF_R_BIT 9 +#define RT5645_PWR_ADC_S2F (0x1 << 8) +#define RT5645_PWR_ADC_S2F_BIT 8 +#define RT5645_PWR_PDM1 (0x1 << 7) +#define RT5645_PWR_PDM1_BIT 7 +#define RT5645_PWR_PDM2 (0x1 << 6) +#define RT5645_PWR_PDM2_BIT 6 +#define RT5645_PWR_IPTV (0x1 << 1) +#define RT5645_PWR_IPTV_BIT 1 +#define RT5645_PWR_PAD (0x1) +#define RT5645_PWR_PAD_BIT 0 + +/* Power Management for Analog 1 (0x63) */ +#define RT5645_PWR_VREF1 (0x1 << 15) +#define RT5645_PWR_VREF1_BIT 15 +#define RT5645_PWR_FV1 (0x1 << 14) +#define RT5645_PWR_FV1_BIT 14 +#define RT5645_PWR_MB (0x1 << 13) +#define RT5645_PWR_MB_BIT 13 +#define RT5645_PWR_LM (0x1 << 12) +#define RT5645_PWR_LM_BIT 12 +#define RT5645_PWR_BG (0x1 << 11) +#define RT5645_PWR_BG_BIT 11 +#define RT5645_PWR_MA (0x1 << 10) +#define RT5645_PWR_MA_BIT 10 +#define RT5645_PWR_HP_L (0x1 << 7) +#define RT5645_PWR_HP_L_BIT 7 +#define RT5645_PWR_HP_R (0x1 << 6) +#define RT5645_PWR_HP_R_BIT 6 +#define RT5645_PWR_HA (0x1 << 5) +#define RT5645_PWR_HA_BIT 5 +#define RT5645_PWR_VREF2 (0x1 << 4) +#define RT5645_PWR_VREF2_BIT 4 +#define RT5645_PWR_FV2 (0x1 << 3) +#define RT5645_PWR_FV2_BIT 3 +#define RT5645_LDO_SEL_MASK (0x3) +#define RT5645_LDO_SEL_SFT 0 + +/* Power Management for Analog 2 (0x64) */ +#define RT5645_PWR_BST1 (0x1 << 15) +#define RT5645_PWR_BST1_BIT 15 +#define RT5645_PWR_BST2 (0x1 << 14) +#define RT5645_PWR_BST2_BIT 14 +#define RT5645_PWR_BST3 (0x1 << 13) +#define RT5645_PWR_BST3_BIT 13 +#define RT5645_PWR_BST4 (0x1 << 12) +#define RT5645_PWR_BST4_BIT 12 +#define RT5645_PWR_MB1 (0x1 << 11) +#define RT5645_PWR_MB1_BIT 11 +#define RT5645_PWR_MB2 (0x1 << 10) +#define RT5645_PWR_MB2_BIT 10 +#define RT5645_PWR_PLL (0x1 << 9) +#define RT5645_PWR_PLL_BIT 9 +#define RT5645_PWR_BST2_P (0x1 << 5) +#define RT5645_PWR_BST2_P_BIT 5 +#define RT5645_PWR_BST3_P (0x1 << 4) +#define RT5645_PWR_BST3_P_BIT 4 +#define RT5645_PWR_BST4_P (0x1 << 3) +#define RT5645_PWR_BST4_P_BIT 3 +#define RT5645_PWR_JD1 (0x1 << 2) +#define RT5645_PWR_JD1_BIT 2 +#define RT5645_PWR_JD (0x1 << 1) +#define RT5645_PWR_JD_BIT 1 + +/* Power Management for Mixer (0x65) */ +#define RT5645_PWR_OM_L (0x1 << 15) +#define RT5645_PWR_OM_L_BIT 15 +#define RT5645_PWR_OM_R (0x1 << 14) +#define RT5645_PWR_OM_R_BIT 14 +#define RT5645_PWR_SM_L (0x1 << 13) +#define RT5645_PWR_SM_L_BIT 13 +#define RT5645_PWR_SM_R (0x1 << 12) +#define RT5645_PWR_SM_R_BIT 12 +#define RT5645_PWR_RM_L (0x1 << 11) +#define RT5645_PWR_RM_L_BIT 11 +#define RT5645_PWR_RM_R (0x1 << 10) +#define RT5645_PWR_RM_R_BIT 10 +#define RT5645_PWR_MM (0x1 << 8) +#define RT5645_PWR_MM_BIT 8 +#define RT5645_PWR_HM_L (0x1 << 7) +#define RT5645_PWR_HM_L_BIT 7 +#define RT5645_PWR_HM_R (0x1 << 6) +#define RT5645_PWR_HM_R_BIT 6 +#define RT5645_PWR_LDO2 (0x1 << 1) +#define RT5645_PWR_LDO2_BIT 1 + +/* Power Management for Volume (0x66) */ +#define RT5645_PWR_SV_L (0x1 << 15) +#define RT5645_PWR_SV_L_BIT 15 +#define RT5645_PWR_SV_R (0x1 << 14) +#define RT5645_PWR_SV_R_BIT 14 +#define RT5645_PWR_HV_L (0x1 << 11) +#define RT5645_PWR_HV_L_BIT 11 +#define RT5645_PWR_HV_R (0x1 << 10) +#define RT5645_PWR_HV_R_BIT 10 +#define RT5645_PWR_IN_L (0x1 << 9) +#define RT5645_PWR_IN_L_BIT 9 +#define RT5645_PWR_IN_R (0x1 << 8) +#define RT5645_PWR_IN_R_BIT 8 +#define RT5645_PWR_MIC_DET (0x1 << 5) +#define RT5645_PWR_MIC_DET_BIT 5 + +/* I2S1/2 Audio Serial Data Port Control (0x70 0x71) */ +#define RT5645_I2S_MS_MASK (0x1 << 15) +#define RT5645_I2S_MS_SFT 15 +#define RT5645_I2S_MS_M (0x0 << 15) +#define RT5645_I2S_MS_S (0x1 << 15) +#define RT5645_I2S_O_CP_MASK (0x3 << 10) +#define RT5645_I2S_O_CP_SFT 10 +#define RT5645_I2S_O_CP_OFF (0x0 << 10) +#define RT5645_I2S_O_CP_U_LAW (0x1 << 10) +#define RT5645_I2S_O_CP_A_LAW (0x2 << 10) +#define RT5645_I2S_I_CP_MASK (0x3 << 8) +#define RT5645_I2S_I_CP_SFT 8 +#define RT5645_I2S_I_CP_OFF (0x0 << 8) +#define RT5645_I2S_I_CP_U_LAW (0x1 << 8) +#define RT5645_I2S_I_CP_A_LAW (0x2 << 8) +#define RT5645_I2S_BP_MASK (0x1 << 7) +#define RT5645_I2S_BP_SFT 7 +#define RT5645_I2S_BP_NOR (0x0 << 7) +#define RT5645_I2S_BP_INV (0x1 << 7) +#define RT5645_I2S_DL_MASK (0x3 << 2) +#define RT5645_I2S_DL_SFT 2 +#define RT5645_I2S_DL_16 (0x0 << 2) +#define RT5645_I2S_DL_20 (0x1 << 2) +#define RT5645_I2S_DL_24 (0x2 << 2) +#define RT5645_I2S_DL_8 (0x3 << 2) +#define RT5645_I2S_DF_MASK (0x3) +#define RT5645_I2S_DF_SFT 0 +#define RT5645_I2S_DF_I2S (0x0) +#define RT5645_I2S_DF_LEFT (0x1) +#define RT5645_I2S_DF_PCM_A (0x2) +#define RT5645_I2S_DF_PCM_B (0x3) + +/* I2S2 Audio Serial Data Port Control (0x71) */ +#define RT5645_I2S2_SDI_MASK (0x1 << 6) +#define RT5645_I2S2_SDI_SFT 6 +#define RT5645_I2S2_SDI_I2S1 (0x0 << 6) +#define RT5645_I2S2_SDI_I2S2 (0x1 << 6) + +/* ADC/DAC Clock Control 1 (0x73) */ +#define RT5645_I2S_BCLK_MS1_MASK (0x1 << 15) +#define RT5645_I2S_BCLK_MS1_SFT 15 +#define RT5645_I2S_BCLK_MS1_32 (0x0 << 15) +#define RT5645_I2S_BCLK_MS1_64 (0x1 << 15) +#define RT5645_I2S_PD1_MASK (0x7 << 12) +#define RT5645_I2S_PD1_SFT 12 +#define RT5645_I2S_PD1_1 (0x0 << 12) +#define RT5645_I2S_PD1_2 (0x1 << 12) +#define RT5645_I2S_PD1_3 (0x2 << 12) +#define RT5645_I2S_PD1_4 (0x3 << 12) +#define RT5645_I2S_PD1_6 (0x4 << 12) +#define RT5645_I2S_PD1_8 (0x5 << 12) +#define RT5645_I2S_PD1_12 (0x6 << 12) +#define RT5645_I2S_PD1_16 (0x7 << 12) +#define RT5645_I2S_BCLK_MS2_MASK (0x1 << 11) +#define RT5645_I2S_BCLK_MS2_SFT 11 +#define RT5645_I2S_BCLK_MS2_32 (0x0 << 11) +#define RT5645_I2S_BCLK_MS2_64 (0x1 << 11) +#define RT5645_I2S_PD2_MASK (0x7 << 8) +#define RT5645_I2S_PD2_SFT 8 +#define RT5645_I2S_PD2_1 (0x0 << 8) +#define RT5645_I2S_PD2_2 (0x1 << 8) +#define RT5645_I2S_PD2_3 (0x2 << 8) +#define RT5645_I2S_PD2_4 (0x3 << 8) +#define RT5645_I2S_PD2_6 (0x4 << 8) +#define RT5645_I2S_PD2_8 (0x5 << 8) +#define RT5645_I2S_PD2_12 (0x6 << 8) +#define RT5645_I2S_PD2_16 (0x7 << 8) +#define RT5645_I2S_BCLK_MS3_MASK (0x1 << 7) +#define RT5645_I2S_BCLK_MS3_SFT 7 +#define RT5645_I2S_BCLK_MS3_32 (0x0 << 7) +#define RT5645_I2S_BCLK_MS3_64 (0x1 << 7) +#define RT5645_I2S_PD3_MASK (0x7 << 4) +#define RT5645_I2S_PD3_SFT 4 +#define RT5645_I2S_PD3_1 (0x0 << 4) +#define RT5645_I2S_PD3_2 (0x1 << 4) +#define RT5645_I2S_PD3_3 (0x2 << 4) +#define RT5645_I2S_PD3_4 (0x3 << 4) +#define RT5645_I2S_PD3_6 (0x4 << 4) +#define RT5645_I2S_PD3_8 (0x5 << 4) +#define RT5645_I2S_PD3_12 (0x6 << 4) +#define RT5645_I2S_PD3_16 (0x7 << 4) +#define RT5645_DAC_OSR_MASK (0x3 << 2) +#define RT5645_DAC_OSR_SFT 2 +#define RT5645_DAC_OSR_128 (0x0 << 2) +#define RT5645_DAC_OSR_64 (0x1 << 2) +#define RT5645_DAC_OSR_32 (0x2 << 2) +#define RT5645_DAC_OSR_16 (0x3 << 2) +#define RT5645_ADC_OSR_MASK (0x3) +#define RT5645_ADC_OSR_SFT 0 +#define RT5645_ADC_OSR_128 (0x0) +#define RT5645_ADC_OSR_64 (0x1) +#define RT5645_ADC_OSR_32 (0x2) +#define RT5645_ADC_OSR_16 (0x3) + +/* ADC/DAC Clock Control 2 (0x74) */ +#define RT5645_DAC_L_OSR_MASK (0x3 << 14) +#define RT5645_DAC_L_OSR_SFT 14 +#define RT5645_DAC_L_OSR_128 (0x0 << 14) +#define RT5645_DAC_L_OSR_64 (0x1 << 14) +#define RT5645_DAC_L_OSR_32 (0x2 << 14) +#define RT5645_DAC_L_OSR_16 (0x3 << 14) +#define RT5645_ADC_R_OSR_MASK (0x3 << 12) +#define RT5645_ADC_R_OSR_SFT 12 +#define RT5645_ADC_R_OSR_128 (0x0 << 12) +#define RT5645_ADC_R_OSR_64 (0x1 << 12) +#define RT5645_ADC_R_OSR_32 (0x2 << 12) +#define RT5645_ADC_R_OSR_16 (0x3 << 12) +#define RT5645_DAHPF_EN (0x1 << 11) +#define RT5645_DAHPF_EN_SFT 11 +#define RT5645_ADHPF_EN (0x1 << 10) +#define RT5645_ADHPF_EN_SFT 10 + +/* Digital Microphone Control (0x75) */ +#define RT5645_DMIC_1_EN_MASK (0x1 << 15) +#define RT5645_DMIC_1_EN_SFT 15 +#define RT5645_DMIC_1_DIS (0x0 << 15) +#define RT5645_DMIC_1_EN (0x1 << 15) +#define RT5645_DMIC_2_EN_MASK (0x1 << 14) +#define RT5645_DMIC_2_EN_SFT 14 +#define RT5645_DMIC_2_DIS (0x0 << 14) +#define RT5645_DMIC_2_EN (0x1 << 14) +#define RT5645_DMIC_1L_LH_MASK (0x1 << 13) +#define RT5645_DMIC_1L_LH_SFT 13 +#define RT5645_DMIC_1L_LH_FALLING (0x0 << 13) +#define RT5645_DMIC_1L_LH_RISING (0x1 << 13) +#define RT5645_DMIC_1R_LH_MASK (0x1 << 12) +#define RT5645_DMIC_1R_LH_SFT 12 +#define RT5645_DMIC_1R_LH_FALLING (0x0 << 12) +#define RT5645_DMIC_1R_LH_RISING (0x1 << 12) +#define RT5645_DMIC_2_DP_MASK (0x3 << 10) +#define RT5645_DMIC_2_DP_SFT 10 +#define RT5645_DMIC_2_DP_GPIO6 (0x0 << 10) +#define RT5645_DMIC_2_DP_GPIO10 (0x1 << 10) +#define RT5645_DMIC_2_DP_GPIO12 (0x2 << 10) +#define RT5645_DMIC_2_DP_IN2P (0x3 << 10) +#define RT5645_DMIC_2L_LH_MASK (0x1 << 9) +#define RT5645_DMIC_2L_LH_SFT 9 +#define RT5645_DMIC_2L_LH_FALLING (0x0 << 9) +#define RT5645_DMIC_2L_LH_RISING (0x1 << 9) +#define RT5645_DMIC_2R_LH_MASK (0x1 << 8) +#define RT5645_DMIC_2R_LH_SFT 8 +#define RT5645_DMIC_2R_LH_FALLING (0x0 << 8) +#define RT5645_DMIC_2R_LH_RISING (0x1 << 8) +#define RT5645_DMIC_CLK_MASK (0x7 << 5) +#define RT5645_DMIC_CLK_SFT 5 +#define RT5645_DMIC_3_EN_MASK (0x1 << 4) +#define RT5645_DMIC_3_EN_SFT 4 +#define RT5645_DMIC_3_DIS (0x0 << 4) +#define RT5645_DMIC_3_EN (0x1 << 4) +#define RT5645_DMIC_1_DP_MASK (0x3 << 0) +#define RT5645_DMIC_1_DP_SFT 0 +#define RT5645_DMIC_1_DP_GPIO5 (0x0 << 0) +#define RT5645_DMIC_1_DP_IN2N (0x1 << 0) +#define RT5645_DMIC_1_DP_GPIO11 (0x2 << 0) + +/* TDM Control 1 (0x77) */ +#define RT5645_IF1_ADC_IN_MASK (0x3 << 8) +#define RT5645_IF1_ADC_IN_SFT 8 + +/* Global Clock Control (0x80) */ +#define RT5645_SCLK_SRC_MASK (0x3 << 14) +#define RT5645_SCLK_SRC_SFT 14 +#define RT5645_SCLK_SRC_MCLK (0x0 << 14) +#define RT5645_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5645_SCLK_SRC_RCCLK (0x2 << 14) /* 15MHz */ +#define RT5645_PLL1_SRC_MASK (0x3 << 12) +#define RT5645_PLL1_SRC_SFT 12 +#define RT5645_PLL1_SRC_MCLK (0x0 << 12) +#define RT5645_PLL1_SRC_BCLK1 (0x1 << 12) +#define RT5645_PLL1_SRC_BCLK2 (0x2 << 12) +#define RT5645_PLL1_SRC_BCLK3 (0x3 << 12) +#define RT5645_PLL1_PD_MASK (0x1 << 3) +#define RT5645_PLL1_PD_SFT 3 +#define RT5645_PLL1_PD_1 (0x0 << 3) +#define RT5645_PLL1_PD_2 (0x1 << 3) + +#define RT5645_PLL_INP_MAX 40000000 +#define RT5645_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x81) */ +#define RT5645_PLL_N_MAX 0x1ff +#define RT5645_PLL_N_MASK (RT5645_PLL_N_MAX << 7) +#define RT5645_PLL_N_SFT 7 +#define RT5645_PLL_K_MAX 0x1f +#define RT5645_PLL_K_MASK (RT5645_PLL_K_MAX) +#define RT5645_PLL_K_SFT 0 + +/* PLL M/N/K Code Control 2 (0x82) */ +#define RT5645_PLL_M_MAX 0xf +#define RT5645_PLL_M_MASK (RT5645_PLL_M_MAX << 12) +#define RT5645_PLL_M_SFT 12 +#define RT5645_PLL_M_BP (0x1 << 11) +#define RT5645_PLL_M_BP_SFT 11 + +/* ASRC Control 1 (0x83) */ +#define RT5645_STO_T_MASK (0x1 << 15) +#define RT5645_STO_T_SFT 15 +#define RT5645_STO_T_SCLK (0x0 << 15) +#define RT5645_STO_T_LRCK1 (0x1 << 15) +#define RT5645_M1_T_MASK (0x1 << 14) +#define RT5645_M1_T_SFT 14 +#define RT5645_M1_T_I2S2 (0x0 << 14) +#define RT5645_M1_T_I2S2_D3 (0x1 << 14) +#define RT5645_I2S2_F_MASK (0x1 << 12) +#define RT5645_I2S2_F_SFT 12 +#define RT5645_I2S2_F_I2S2_D2 (0x0 << 12) +#define RT5645_I2S2_F_I2S1_TCLK (0x1 << 12) +#define RT5645_DMIC_1_M_MASK (0x1 << 9) +#define RT5645_DMIC_1_M_SFT 9 +#define RT5645_DMIC_1_M_NOR (0x0 << 9) +#define RT5645_DMIC_1_M_ASYN (0x1 << 9) +#define RT5645_DMIC_2_M_MASK (0x1 << 8) +#define RT5645_DMIC_2_M_SFT 8 +#define RT5645_DMIC_2_M_NOR (0x0 << 8) +#define RT5645_DMIC_2_M_ASYN (0x1 << 8) + +/* ASRC Control 2 (0x84) */ +#define RT5645_MDA_L_M_MASK (0x1 << 15) +#define RT5645_MDA_L_M_SFT 15 +#define RT5645_MDA_L_M_NOR (0x0 << 15) +#define RT5645_MDA_L_M_ASYN (0x1 << 15) +#define RT5645_MDA_R_M_MASK (0x1 << 14) +#define RT5645_MDA_R_M_SFT 14 +#define RT5645_MDA_R_M_NOR (0x0 << 14) +#define RT5645_MDA_R_M_ASYN (0x1 << 14) +#define RT5645_MAD_L_M_MASK (0x1 << 13) +#define RT5645_MAD_L_M_SFT 13 +#define RT5645_MAD_L_M_NOR (0x0 << 13) +#define RT5645_MAD_L_M_ASYN (0x1 << 13) +#define RT5645_MAD_R_M_MASK (0x1 << 12) +#define RT5645_MAD_R_M_SFT 12 +#define RT5645_MAD_R_M_NOR (0x0 << 12) +#define RT5645_MAD_R_M_ASYN (0x1 << 12) +#define RT5645_ADC_M_MASK (0x1 << 11) +#define RT5645_ADC_M_SFT 11 +#define RT5645_ADC_M_NOR (0x0 << 11) +#define RT5645_ADC_M_ASYN (0x1 << 11) +#define RT5645_STO_DAC_M_MASK (0x1 << 5) +#define RT5645_STO_DAC_M_SFT 5 +#define RT5645_STO_DAC_M_NOR (0x0 << 5) +#define RT5645_STO_DAC_M_ASYN (0x1 << 5) +#define RT5645_I2S1_R_D_MASK (0x1 << 4) +#define RT5645_I2S1_R_D_SFT 4 +#define RT5645_I2S1_R_D_DIS (0x0 << 4) +#define RT5645_I2S1_R_D_EN (0x1 << 4) +#define RT5645_I2S2_R_D_MASK (0x1 << 3) +#define RT5645_I2S2_R_D_SFT 3 +#define RT5645_I2S2_R_D_DIS (0x0 << 3) +#define RT5645_I2S2_R_D_EN (0x1 << 3) +#define RT5645_PRE_SCLK_MASK (0x3) +#define RT5645_PRE_SCLK_SFT 0 +#define RT5645_PRE_SCLK_512 (0x0) +#define RT5645_PRE_SCLK_1024 (0x1) +#define RT5645_PRE_SCLK_2048 (0x2) + +/* ASRC Control 3 (0x85) */ +#define RT5645_I2S1_RATE_MASK (0xf << 12) +#define RT5645_I2S1_RATE_SFT 12 +#define RT5645_I2S2_RATE_MASK (0xf << 8) +#define RT5645_I2S2_RATE_SFT 8 + +/* ASRC Control 4 (0x89) */ +#define RT5645_I2S1_PD_MASK (0x7 << 12) +#define RT5645_I2S1_PD_SFT 12 +#define RT5645_I2S2_PD_MASK (0x7 << 8) +#define RT5645_I2S2_PD_SFT 8 + +/* HPOUT Over Current Detection (0x8b) */ +#define RT5645_HP_OVCD_MASK (0x1 << 10) +#define RT5645_HP_OVCD_SFT 10 +#define RT5645_HP_OVCD_DIS (0x0 << 10) +#define RT5645_HP_OVCD_EN (0x1 << 10) +#define RT5645_HP_OC_TH_MASK (0x3 << 8) +#define RT5645_HP_OC_TH_SFT 8 +#define RT5645_HP_OC_TH_90 (0x0 << 8) +#define RT5645_HP_OC_TH_105 (0x1 << 8) +#define RT5645_HP_OC_TH_120 (0x2 << 8) +#define RT5645_HP_OC_TH_135 (0x3 << 8) + +/* Class D Over Current Control (0x8c) */ +#define RT5645_CLSD_OC_MASK (0x1 << 9) +#define RT5645_CLSD_OC_SFT 9 +#define RT5645_CLSD_OC_PU (0x0 << 9) +#define RT5645_CLSD_OC_PD (0x1 << 9) +#define RT5645_AUTO_PD_MASK (0x1 << 8) +#define RT5645_AUTO_PD_SFT 8 +#define RT5645_AUTO_PD_DIS (0x0 << 8) +#define RT5645_AUTO_PD_EN (0x1 << 8) +#define RT5645_CLSD_OC_TH_MASK (0x3f) +#define RT5645_CLSD_OC_TH_SFT 0 + +/* Class D Output Control (0x8d) */ +#define RT5645_CLSD_RATIO_MASK (0xf << 12) +#define RT5645_CLSD_RATIO_SFT 12 +#define RT5645_CLSD_OM_MASK (0x1 << 11) +#define RT5645_CLSD_OM_SFT 11 +#define RT5645_CLSD_OM_MONO (0x0 << 11) +#define RT5645_CLSD_OM_STO (0x1 << 11) +#define RT5645_CLSD_SCH_MASK (0x1 << 10) +#define RT5645_CLSD_SCH_SFT 10 +#define RT5645_CLSD_SCH_L (0x0 << 10) +#define RT5645_CLSD_SCH_S (0x1 << 10) + +/* Depop Mode Control 1 (0x8e) */ +#define RT5645_SMT_TRIG_MASK (0x1 << 15) +#define RT5645_SMT_TRIG_SFT 15 +#define RT5645_SMT_TRIG_DIS (0x0 << 15) +#define RT5645_SMT_TRIG_EN (0x1 << 15) +#define RT5645_HP_L_SMT_MASK (0x1 << 9) +#define RT5645_HP_L_SMT_SFT 9 +#define RT5645_HP_L_SMT_DIS (0x0 << 9) +#define RT5645_HP_L_SMT_EN (0x1 << 9) +#define RT5645_HP_R_SMT_MASK (0x1 << 8) +#define RT5645_HP_R_SMT_SFT 8 +#define RT5645_HP_R_SMT_DIS (0x0 << 8) +#define RT5645_HP_R_SMT_EN (0x1 << 8) +#define RT5645_HP_CD_PD_MASK (0x1 << 7) +#define RT5645_HP_CD_PD_SFT 7 +#define RT5645_HP_CD_PD_DIS (0x0 << 7) +#define RT5645_HP_CD_PD_EN (0x1 << 7) +#define RT5645_RSTN_MASK (0x1 << 6) +#define RT5645_RSTN_SFT 6 +#define RT5645_RSTN_DIS (0x0 << 6) +#define RT5645_RSTN_EN (0x1 << 6) +#define RT5645_RSTP_MASK (0x1 << 5) +#define RT5645_RSTP_SFT 5 +#define RT5645_RSTP_DIS (0x0 << 5) +#define RT5645_RSTP_EN (0x1 << 5) +#define RT5645_HP_CO_MASK (0x1 << 4) +#define RT5645_HP_CO_SFT 4 +#define RT5645_HP_CO_DIS (0x0 << 4) +#define RT5645_HP_CO_EN (0x1 << 4) +#define RT5645_HP_CP_MASK (0x1 << 3) +#define RT5645_HP_CP_SFT 3 +#define RT5645_HP_CP_PD (0x0 << 3) +#define RT5645_HP_CP_PU (0x1 << 3) +#define RT5645_HP_SG_MASK (0x1 << 2) +#define RT5645_HP_SG_SFT 2 +#define RT5645_HP_SG_DIS (0x0 << 2) +#define RT5645_HP_SG_EN (0x1 << 2) +#define RT5645_HP_DP_MASK (0x1 << 1) +#define RT5645_HP_DP_SFT 1 +#define RT5645_HP_DP_PD (0x0 << 1) +#define RT5645_HP_DP_PU (0x1 << 1) +#define RT5645_HP_CB_MASK (0x1) +#define RT5645_HP_CB_SFT 0 +#define RT5645_HP_CB_PD (0x0) +#define RT5645_HP_CB_PU (0x1) + +/* Depop Mode Control 2 (0x8f) */ +#define RT5645_DEPOP_MASK (0x1 << 13) +#define RT5645_DEPOP_SFT 13 +#define RT5645_DEPOP_AUTO (0x0 << 13) +#define RT5645_DEPOP_MAN (0x1 << 13) +#define RT5645_RAMP_MASK (0x1 << 12) +#define RT5645_RAMP_SFT 12 +#define RT5645_RAMP_DIS (0x0 << 12) +#define RT5645_RAMP_EN (0x1 << 12) +#define RT5645_BPS_MASK (0x1 << 11) +#define RT5645_BPS_SFT 11 +#define RT5645_BPS_DIS (0x0 << 11) +#define RT5645_BPS_EN (0x1 << 11) +#define RT5645_FAST_UPDN_MASK (0x1 << 10) +#define RT5645_FAST_UPDN_SFT 10 +#define RT5645_FAST_UPDN_DIS (0x0 << 10) +#define RT5645_FAST_UPDN_EN (0x1 << 10) +#define RT5645_MRES_MASK (0x3 << 8) +#define RT5645_MRES_SFT 8 +#define RT5645_MRES_15MO (0x0 << 8) +#define RT5645_MRES_25MO (0x1 << 8) +#define RT5645_MRES_35MO (0x2 << 8) +#define RT5645_MRES_45MO (0x3 << 8) +#define RT5645_VLO_MASK (0x1 << 7) +#define RT5645_VLO_SFT 7 +#define RT5645_VLO_3V (0x0 << 7) +#define RT5645_VLO_32V (0x1 << 7) +#define RT5645_DIG_DP_MASK (0x1 << 6) +#define RT5645_DIG_DP_SFT 6 +#define RT5645_DIG_DP_DIS (0x0 << 6) +#define RT5645_DIG_DP_EN (0x1 << 6) +#define RT5645_DP_TH_MASK (0x3 << 4) +#define RT5645_DP_TH_SFT 4 + +/* Depop Mode Control 3 (0x90) */ +#define RT5645_CP_SYS_MASK (0x7 << 12) +#define RT5645_CP_SYS_SFT 12 +#define RT5645_CP_FQ1_MASK (0x7 << 8) +#define RT5645_CP_FQ1_SFT 8 +#define RT5645_CP_FQ2_MASK (0x7 << 4) +#define RT5645_CP_FQ2_SFT 4 +#define RT5645_CP_FQ3_MASK (0x7) +#define RT5645_CP_FQ3_SFT 0 +#define RT5645_CP_FQ_1_5_KHZ 0 +#define RT5645_CP_FQ_3_KHZ 1 +#define RT5645_CP_FQ_6_KHZ 2 +#define RT5645_CP_FQ_12_KHZ 3 +#define RT5645_CP_FQ_24_KHZ 4 +#define RT5645_CP_FQ_48_KHZ 5 +#define RT5645_CP_FQ_96_KHZ 6 +#define RT5645_CP_FQ_192_KHZ 7 + +/* PV detection and SPK gain control (0x92) */ +#define RT5645_PVDD_DET_MASK (0x1 << 15) +#define RT5645_PVDD_DET_SFT 15 +#define RT5645_PVDD_DET_DIS (0x0 << 15) +#define RT5645_PVDD_DET_EN (0x1 << 15) +#define RT5645_SPK_AG_MASK (0x1 << 14) +#define RT5645_SPK_AG_SFT 14 +#define RT5645_SPK_AG_DIS (0x0 << 14) +#define RT5645_SPK_AG_EN (0x1 << 14) + +/* Micbias Control (0x93) */ +#define RT5645_MIC1_BS_MASK (0x1 << 15) +#define RT5645_MIC1_BS_SFT 15 +#define RT5645_MIC1_BS_9AV (0x0 << 15) +#define RT5645_MIC1_BS_75AV (0x1 << 15) +#define RT5645_MIC2_BS_MASK (0x1 << 14) +#define RT5645_MIC2_BS_SFT 14 +#define RT5645_MIC2_BS_9AV (0x0 << 14) +#define RT5645_MIC2_BS_75AV (0x1 << 14) +#define RT5645_MIC1_CLK_MASK (0x1 << 13) +#define RT5645_MIC1_CLK_SFT 13 +#define RT5645_MIC1_CLK_DIS (0x0 << 13) +#define RT5645_MIC1_CLK_EN (0x1 << 13) +#define RT5645_MIC2_CLK_MASK (0x1 << 12) +#define RT5645_MIC2_CLK_SFT 12 +#define RT5645_MIC2_CLK_DIS (0x0 << 12) +#define RT5645_MIC2_CLK_EN (0x1 << 12) +#define RT5645_MIC1_OVCD_MASK (0x1 << 11) +#define RT5645_MIC1_OVCD_SFT 11 +#define RT5645_MIC1_OVCD_DIS (0x0 << 11) +#define RT5645_MIC1_OVCD_EN (0x1 << 11) +#define RT5645_MIC1_OVTH_MASK (0x3 << 9) +#define RT5645_MIC1_OVTH_SFT 9 +#define RT5645_MIC1_OVTH_600UA (0x0 << 9) +#define RT5645_MIC1_OVTH_1500UA (0x1 << 9) +#define RT5645_MIC1_OVTH_2000UA (0x2 << 9) +#define RT5645_MIC2_OVCD_MASK (0x1 << 8) +#define RT5645_MIC2_OVCD_SFT 8 +#define RT5645_MIC2_OVCD_DIS (0x0 << 8) +#define RT5645_MIC2_OVCD_EN (0x1 << 8) +#define RT5645_MIC2_OVTH_MASK (0x3 << 6) +#define RT5645_MIC2_OVTH_SFT 6 +#define RT5645_MIC2_OVTH_600UA (0x0 << 6) +#define RT5645_MIC2_OVTH_1500UA (0x1 << 6) +#define RT5645_MIC2_OVTH_2000UA (0x2 << 6) +#define RT5645_PWR_MB_MASK (0x1 << 5) +#define RT5645_PWR_MB_SFT 5 +#define RT5645_PWR_MB_PD (0x0 << 5) +#define RT5645_PWR_MB_PU (0x1 << 5) +#define RT5645_PWR_CLK25M_MASK (0x1 << 4) +#define RT5645_PWR_CLK25M_SFT 4 +#define RT5645_PWR_CLK25M_PD (0x0 << 4) +#define RT5645_PWR_CLK25M_PU (0x1 << 4) + +/* VAD Control 4 (0x9d) */ +#define RT5645_VAD_SEL_MASK (0x3 << 8) +#define RT5645_VAD_SEL_SFT 8 + +/* EQ Control 1 (0xb0) */ +#define RT5645_EQ_SRC_MASK (0x1 << 15) +#define RT5645_EQ_SRC_SFT 15 +#define RT5645_EQ_SRC_DAC (0x0 << 15) +#define RT5645_EQ_SRC_ADC (0x1 << 15) +#define RT5645_EQ_UPD (0x1 << 14) +#define RT5645_EQ_UPD_BIT 14 +#define RT5645_EQ_CD_MASK (0x1 << 13) +#define RT5645_EQ_CD_SFT 13 +#define RT5645_EQ_CD_DIS (0x0 << 13) +#define RT5645_EQ_CD_EN (0x1 << 13) +#define RT5645_EQ_DITH_MASK (0x3 << 8) +#define RT5645_EQ_DITH_SFT 8 +#define RT5645_EQ_DITH_NOR (0x0 << 8) +#define RT5645_EQ_DITH_LSB (0x1 << 8) +#define RT5645_EQ_DITH_LSB_1 (0x2 << 8) +#define RT5645_EQ_DITH_LSB_2 (0x3 << 8) + +/* EQ Control 2 (0xb1) */ +#define RT5645_EQ_HPF1_M_MASK (0x1 << 8) +#define RT5645_EQ_HPF1_M_SFT 8 +#define RT5645_EQ_HPF1_M_HI (0x0 << 8) +#define RT5645_EQ_HPF1_M_1ST (0x1 << 8) +#define RT5645_EQ_LPF1_M_MASK (0x1 << 7) +#define RT5645_EQ_LPF1_M_SFT 7 +#define RT5645_EQ_LPF1_M_LO (0x0 << 7) +#define RT5645_EQ_LPF1_M_1ST (0x1 << 7) +#define RT5645_EQ_HPF2_MASK (0x1 << 6) +#define RT5645_EQ_HPF2_SFT 6 +#define RT5645_EQ_HPF2_DIS (0x0 << 6) +#define RT5645_EQ_HPF2_EN (0x1 << 6) +#define RT5645_EQ_HPF1_MASK (0x1 << 5) +#define RT5645_EQ_HPF1_SFT 5 +#define RT5645_EQ_HPF1_DIS (0x0 << 5) +#define RT5645_EQ_HPF1_EN (0x1 << 5) +#define RT5645_EQ_BPF4_MASK (0x1 << 4) +#define RT5645_EQ_BPF4_SFT 4 +#define RT5645_EQ_BPF4_DIS (0x0 << 4) +#define RT5645_EQ_BPF4_EN (0x1 << 4) +#define RT5645_EQ_BPF3_MASK (0x1 << 3) +#define RT5645_EQ_BPF3_SFT 3 +#define RT5645_EQ_BPF3_DIS (0x0 << 3) +#define RT5645_EQ_BPF3_EN (0x1 << 3) +#define RT5645_EQ_BPF2_MASK (0x1 << 2) +#define RT5645_EQ_BPF2_SFT 2 +#define RT5645_EQ_BPF2_DIS (0x0 << 2) +#define RT5645_EQ_BPF2_EN (0x1 << 2) +#define RT5645_EQ_BPF1_MASK (0x1 << 1) +#define RT5645_EQ_BPF1_SFT 1 +#define RT5645_EQ_BPF1_DIS (0x0 << 1) +#define RT5645_EQ_BPF1_EN (0x1 << 1) +#define RT5645_EQ_LPF_MASK (0x1) +#define RT5645_EQ_LPF_SFT 0 +#define RT5645_EQ_LPF_DIS (0x0) +#define RT5645_EQ_LPF_EN (0x1) +#define RT5645_EQ_CTRL_MASK (0x7f) + +/* Memory Test (0xb2) */ +#define RT5645_MT_MASK (0x1 << 15) +#define RT5645_MT_SFT 15 +#define RT5645_MT_DIS (0x0 << 15) +#define RT5645_MT_EN (0x1 << 15) + +/* DRC/AGC Control 1 (0xb4) */ +#define RT5645_DRC_AGC_P_MASK (0x1 << 15) +#define RT5645_DRC_AGC_P_SFT 15 +#define RT5645_DRC_AGC_P_DAC (0x0 << 15) +#define RT5645_DRC_AGC_P_ADC (0x1 << 15) +#define RT5645_DRC_AGC_MASK (0x1 << 14) +#define RT5645_DRC_AGC_SFT 14 +#define RT5645_DRC_AGC_DIS (0x0 << 14) +#define RT5645_DRC_AGC_EN (0x1 << 14) +#define RT5645_DRC_AGC_UPD (0x1 << 13) +#define RT5645_DRC_AGC_UPD_BIT 13 +#define RT5645_DRC_AGC_AR_MASK (0x1f << 8) +#define RT5645_DRC_AGC_AR_SFT 8 +#define RT5645_DRC_AGC_R_MASK (0x7 << 5) +#define RT5645_DRC_AGC_R_SFT 5 +#define RT5645_DRC_AGC_R_48K (0x1 << 5) +#define RT5645_DRC_AGC_R_96K (0x2 << 5) +#define RT5645_DRC_AGC_R_192K (0x3 << 5) +#define RT5645_DRC_AGC_R_441K (0x5 << 5) +#define RT5645_DRC_AGC_R_882K (0x6 << 5) +#define RT5645_DRC_AGC_R_1764K (0x7 << 5) +#define RT5645_DRC_AGC_RC_MASK (0x1f) +#define RT5645_DRC_AGC_RC_SFT 0 + +/* DRC/AGC Control 2 (0xb5) */ +#define RT5645_DRC_AGC_POB_MASK (0x3f << 8) +#define RT5645_DRC_AGC_POB_SFT 8 +#define RT5645_DRC_AGC_CP_MASK (0x1 << 7) +#define RT5645_DRC_AGC_CP_SFT 7 +#define RT5645_DRC_AGC_CP_DIS (0x0 << 7) +#define RT5645_DRC_AGC_CP_EN (0x1 << 7) +#define RT5645_DRC_AGC_CPR_MASK (0x3 << 5) +#define RT5645_DRC_AGC_CPR_SFT 5 +#define RT5645_DRC_AGC_CPR_1_1 (0x0 << 5) +#define RT5645_DRC_AGC_CPR_1_2 (0x1 << 5) +#define RT5645_DRC_AGC_CPR_1_3 (0x2 << 5) +#define RT5645_DRC_AGC_CPR_1_4 (0x3 << 5) +#define RT5645_DRC_AGC_PRB_MASK (0x1f) +#define RT5645_DRC_AGC_PRB_SFT 0 + +/* DRC/AGC Control 3 (0xb6) */ +#define RT5645_DRC_AGC_NGB_MASK (0xf << 12) +#define RT5645_DRC_AGC_NGB_SFT 12 +#define RT5645_DRC_AGC_TAR_MASK (0x1f << 7) +#define RT5645_DRC_AGC_TAR_SFT 7 +#define RT5645_DRC_AGC_NG_MASK (0x1 << 6) +#define RT5645_DRC_AGC_NG_SFT 6 +#define RT5645_DRC_AGC_NG_DIS (0x0 << 6) +#define RT5645_DRC_AGC_NG_EN (0x1 << 6) +#define RT5645_DRC_AGC_NGH_MASK (0x1 << 5) +#define RT5645_DRC_AGC_NGH_SFT 5 +#define RT5645_DRC_AGC_NGH_DIS (0x0 << 5) +#define RT5645_DRC_AGC_NGH_EN (0x1 << 5) +#define RT5645_DRC_AGC_NGT_MASK (0x1f) +#define RT5645_DRC_AGC_NGT_SFT 0 + +/* ANC Control 1 (0xb8) */ +#define RT5645_ANC_M_MASK (0x1 << 15) +#define RT5645_ANC_M_SFT 15 +#define RT5645_ANC_M_NOR (0x0 << 15) +#define RT5645_ANC_M_REV (0x1 << 15) +#define RT5645_ANC_MASK (0x1 << 14) +#define RT5645_ANC_SFT 14 +#define RT5645_ANC_DIS (0x0 << 14) +#define RT5645_ANC_EN (0x1 << 14) +#define RT5645_ANC_MD_MASK (0x3 << 12) +#define RT5645_ANC_MD_SFT 12 +#define RT5645_ANC_MD_DIS (0x0 << 12) +#define RT5645_ANC_MD_67MS (0x1 << 12) +#define RT5645_ANC_MD_267MS (0x2 << 12) +#define RT5645_ANC_MD_1067MS (0x3 << 12) +#define RT5645_ANC_SN_MASK (0x1 << 11) +#define RT5645_ANC_SN_SFT 11 +#define RT5645_ANC_SN_DIS (0x0 << 11) +#define RT5645_ANC_SN_EN (0x1 << 11) +#define RT5645_ANC_CLK_MASK (0x1 << 10) +#define RT5645_ANC_CLK_SFT 10 +#define RT5645_ANC_CLK_ANC (0x0 << 10) +#define RT5645_ANC_CLK_REG (0x1 << 10) +#define RT5645_ANC_ZCD_MASK (0x3 << 8) +#define RT5645_ANC_ZCD_SFT 8 +#define RT5645_ANC_ZCD_DIS (0x0 << 8) +#define RT5645_ANC_ZCD_T1 (0x1 << 8) +#define RT5645_ANC_ZCD_T2 (0x2 << 8) +#define RT5645_ANC_ZCD_WT (0x3 << 8) +#define RT5645_ANC_CS_MASK (0x1 << 7) +#define RT5645_ANC_CS_SFT 7 +#define RT5645_ANC_CS_DIS (0x0 << 7) +#define RT5645_ANC_CS_EN (0x1 << 7) +#define RT5645_ANC_SW_MASK (0x1 << 6) +#define RT5645_ANC_SW_SFT 6 +#define RT5645_ANC_SW_NOR (0x0 << 6) +#define RT5645_ANC_SW_AUTO (0x1 << 6) +#define RT5645_ANC_CO_L_MASK (0x3f) +#define RT5645_ANC_CO_L_SFT 0 + +/* ANC Control 2 (0xb6) */ +#define RT5645_ANC_FG_R_MASK (0xf << 12) +#define RT5645_ANC_FG_R_SFT 12 +#define RT5645_ANC_FG_L_MASK (0xf << 8) +#define RT5645_ANC_FG_L_SFT 8 +#define RT5645_ANC_CG_R_MASK (0xf << 4) +#define RT5645_ANC_CG_R_SFT 4 +#define RT5645_ANC_CG_L_MASK (0xf) +#define RT5645_ANC_CG_L_SFT 0 + +/* ANC Control 3 (0xb6) */ +#define RT5645_ANC_CD_MASK (0x1 << 6) +#define RT5645_ANC_CD_SFT 6 +#define RT5645_ANC_CD_BOTH (0x0 << 6) +#define RT5645_ANC_CD_IND (0x1 << 6) +#define RT5645_ANC_CO_R_MASK (0x3f) +#define RT5645_ANC_CO_R_SFT 0 + +/* Jack Detect Control (0xbb) */ +#define RT5645_JD_MASK (0x7 << 13) +#define RT5645_JD_SFT 13 +#define RT5645_JD_DIS (0x0 << 13) +#define RT5645_JD_GPIO1 (0x1 << 13) +#define RT5645_JD_JD1_IN4P (0x2 << 13) +#define RT5645_JD_JD2_IN4N (0x3 << 13) +#define RT5645_JD_GPIO2 (0x4 << 13) +#define RT5645_JD_GPIO3 (0x5 << 13) +#define RT5645_JD_GPIO4 (0x6 << 13) +#define RT5645_JD_HP_MASK (0x1 << 11) +#define RT5645_JD_HP_SFT 11 +#define RT5645_JD_HP_DIS (0x0 << 11) +#define RT5645_JD_HP_EN (0x1 << 11) +#define RT5645_JD_HP_TRG_MASK (0x1 << 10) +#define RT5645_JD_HP_TRG_SFT 10 +#define RT5645_JD_HP_TRG_LO (0x0 << 10) +#define RT5645_JD_HP_TRG_HI (0x1 << 10) +#define RT5645_JD_SPL_MASK (0x1 << 9) +#define RT5645_JD_SPL_SFT 9 +#define RT5645_JD_SPL_DIS (0x0 << 9) +#define RT5645_JD_SPL_EN (0x1 << 9) +#define RT5645_JD_SPL_TRG_MASK (0x1 << 8) +#define RT5645_JD_SPL_TRG_SFT 8 +#define RT5645_JD_SPL_TRG_LO (0x0 << 8) +#define RT5645_JD_SPL_TRG_HI (0x1 << 8) +#define RT5645_JD_SPR_MASK (0x1 << 7) +#define RT5645_JD_SPR_SFT 7 +#define RT5645_JD_SPR_DIS (0x0 << 7) +#define RT5645_JD_SPR_EN (0x1 << 7) +#define RT5645_JD_SPR_TRG_MASK (0x1 << 6) +#define RT5645_JD_SPR_TRG_SFT 6 +#define RT5645_JD_SPR_TRG_LO (0x0 << 6) +#define RT5645_JD_SPR_TRG_HI (0x1 << 6) +#define RT5645_JD_MO_MASK (0x1 << 5) +#define RT5645_JD_MO_SFT 5 +#define RT5645_JD_MO_DIS (0x0 << 5) +#define RT5645_JD_MO_EN (0x1 << 5) +#define RT5645_JD_MO_TRG_MASK (0x1 << 4) +#define RT5645_JD_MO_TRG_SFT 4 +#define RT5645_JD_MO_TRG_LO (0x0 << 4) +#define RT5645_JD_MO_TRG_HI (0x1 << 4) +#define RT5645_JD_LO_MASK (0x1 << 3) +#define RT5645_JD_LO_SFT 3 +#define RT5645_JD_LO_DIS (0x0 << 3) +#define RT5645_JD_LO_EN (0x1 << 3) +#define RT5645_JD_LO_TRG_MASK (0x1 << 2) +#define RT5645_JD_LO_TRG_SFT 2 +#define RT5645_JD_LO_TRG_LO (0x0 << 2) +#define RT5645_JD_LO_TRG_HI (0x1 << 2) +#define RT5645_JD1_IN4P_MASK (0x1 << 1) +#define RT5645_JD1_IN4P_SFT 1 +#define RT5645_JD1_IN4P_DIS (0x0 << 1) +#define RT5645_JD1_IN4P_EN (0x1 << 1) +#define RT5645_JD2_IN4N_MASK (0x1) +#define RT5645_JD2_IN4N_SFT 0 +#define RT5645_JD2_IN4N_DIS (0x0) +#define RT5645_JD2_IN4N_EN (0x1) + +/* Jack detect for ANC (0xbc) */ +#define RT5645_ANC_DET_MASK (0x3 << 4) +#define RT5645_ANC_DET_SFT 4 +#define RT5645_ANC_DET_DIS (0x0 << 4) +#define RT5645_ANC_DET_MB1 (0x1 << 4) +#define RT5645_ANC_DET_MB2 (0x2 << 4) +#define RT5645_ANC_DET_JD (0x3 << 4) +#define RT5645_AD_TRG_MASK (0x1 << 3) +#define RT5645_AD_TRG_SFT 3 +#define RT5645_AD_TRG_LO (0x0 << 3) +#define RT5645_AD_TRG_HI (0x1 << 3) +#define RT5645_ANCM_DET_MASK (0x3 << 4) +#define RT5645_ANCM_DET_SFT 4 +#define RT5645_ANCM_DET_DIS (0x0 << 4) +#define RT5645_ANCM_DET_MB1 (0x1 << 4) +#define RT5645_ANCM_DET_MB2 (0x2 << 4) +#define RT5645_ANCM_DET_JD (0x3 << 4) +#define RT5645_AMD_TRG_MASK (0x1 << 3) +#define RT5645_AMD_TRG_SFT 3 +#define RT5645_AMD_TRG_LO (0x0 << 3) +#define RT5645_AMD_TRG_HI (0x1 << 3) + +/* IRQ Control 1 (0xbd) */ +#define RT5645_IRQ_JD_MASK (0x1 << 15) +#define RT5645_IRQ_JD_SFT 15 +#define RT5645_IRQ_JD_BP (0x0 << 15) +#define RT5645_IRQ_JD_NOR (0x1 << 15) +#define RT5645_IRQ_OT_MASK (0x1 << 14) +#define RT5645_IRQ_OT_SFT 14 +#define RT5645_IRQ_OT_BP (0x0 << 14) +#define RT5645_IRQ_OT_NOR (0x1 << 14) +#define RT5645_JD_STKY_MASK (0x1 << 13) +#define RT5645_JD_STKY_SFT 13 +#define RT5645_JD_STKY_DIS (0x0 << 13) +#define RT5645_JD_STKY_EN (0x1 << 13) +#define RT5645_OT_STKY_MASK (0x1 << 12) +#define RT5645_OT_STKY_SFT 12 +#define RT5645_OT_STKY_DIS (0x0 << 12) +#define RT5645_OT_STKY_EN (0x1 << 12) +#define RT5645_JD_P_MASK (0x1 << 11) +#define RT5645_JD_P_SFT 11 +#define RT5645_JD_P_NOR (0x0 << 11) +#define RT5645_JD_P_INV (0x1 << 11) +#define RT5645_OT_P_MASK (0x1 << 10) +#define RT5645_OT_P_SFT 10 +#define RT5645_OT_P_NOR (0x0 << 10) +#define RT5645_OT_P_INV (0x1 << 10) + +/* IRQ Control 2 (0xbe) */ +#define RT5645_IRQ_MB1_OC_MASK (0x1 << 15) +#define RT5645_IRQ_MB1_OC_SFT 15 +#define RT5645_IRQ_MB1_OC_BP (0x0 << 15) +#define RT5645_IRQ_MB1_OC_NOR (0x1 << 15) +#define RT5645_IRQ_MB2_OC_MASK (0x1 << 14) +#define RT5645_IRQ_MB2_OC_SFT 14 +#define RT5645_IRQ_MB2_OC_BP (0x0 << 14) +#define RT5645_IRQ_MB2_OC_NOR (0x1 << 14) +#define RT5645_MB1_OC_STKY_MASK (0x1 << 13) +#define RT5645_MB1_OC_STKY_SFT 13 +#define RT5645_MB1_OC_STKY_DIS (0x0 << 13) +#define RT5645_MB1_OC_STKY_EN (0x1 << 13) +#define RT5645_MB2_OC_STKY_MASK (0x1 << 12) +#define RT5645_MB2_OC_STKY_SFT 12 +#define RT5645_MB2_OC_STKY_DIS (0x0 << 12) +#define RT5645_MB2_OC_STKY_EN (0x1 << 12) +#define RT5645_MB1_OC_P_MASK (0x1 << 7) +#define RT5645_MB1_OC_P_SFT 7 +#define RT5645_MB1_OC_P_NOR (0x0 << 7) +#define RT5645_MB1_OC_P_INV (0x1 << 7) +#define RT5645_MB2_OC_P_MASK (0x1 << 6) +#define RT5645_MB2_OC_P_SFT 6 +#define RT5645_MB2_OC_P_NOR (0x0 << 6) +#define RT5645_MB2_OC_P_INV (0x1 << 6) +#define RT5645_MB1_OC_CLR (0x1 << 3) +#define RT5645_MB1_OC_CLR_SFT 3 +#define RT5645_MB2_OC_CLR (0x1 << 2) +#define RT5645_MB2_OC_CLR_SFT 2 + +/* GPIO Control 1 (0xc0) */ +#define RT5645_GP1_PIN_MASK (0x1 << 15) +#define RT5645_GP1_PIN_SFT 15 +#define RT5645_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5645_GP1_PIN_IRQ (0x1 << 15) +#define RT5645_GP2_PIN_MASK (0x1 << 14) +#define RT5645_GP2_PIN_SFT 14 +#define RT5645_GP2_PIN_GPIO2 (0x0 << 14) +#define RT5645_GP2_PIN_DMIC1_SCL (0x1 << 14) +#define RT5645_GP3_PIN_MASK (0x3 << 12) +#define RT5645_GP3_PIN_SFT 12 +#define RT5645_GP3_PIN_GPIO3 (0x0 << 12) +#define RT5645_GP3_PIN_DMIC1_SDA (0x1 << 12) +#define RT5645_GP3_PIN_IRQ (0x2 << 12) +#define RT5645_GP4_PIN_MASK (0x1 << 11) +#define RT5645_GP4_PIN_SFT 11 +#define RT5645_GP4_PIN_GPIO4 (0x0 << 11) +#define RT5645_GP4_PIN_DMIC2_SDA (0x1 << 11) +#define RT5645_DP_SIG_MASK (0x1 << 10) +#define RT5645_DP_SIG_SFT 10 +#define RT5645_DP_SIG_TEST (0x0 << 10) +#define RT5645_DP_SIG_AP (0x1 << 10) +#define RT5645_GPIO_M_MASK (0x1 << 9) +#define RT5645_GPIO_M_SFT 9 +#define RT5645_GPIO_M_FLT (0x0 << 9) +#define RT5645_GPIO_M_PH (0x1 << 9) +#define RT5645_I2S2_SEL (0x1 << 8) +#define RT5645_I2S2_SEL_SFT 8 +#define RT5645_GP5_PIN_MASK (0x1 << 7) +#define RT5645_GP5_PIN_SFT 7 +#define RT5645_GP5_PIN_GPIO5 (0x0 << 7) +#define RT5645_GP5_PIN_DMIC1_SDA (0x1 << 7) +#define RT5645_GP6_PIN_MASK (0x1 << 6) +#define RT5645_GP6_PIN_SFT 6 +#define RT5645_GP6_PIN_GPIO6 (0x0 << 6) +#define RT5645_GP6_PIN_DMIC2_SDA (0x1 << 6) +#define RT5645_GP8_PIN_MASK (0x1 << 3) +#define RT5645_GP8_PIN_SFT 3 +#define RT5645_GP8_PIN_GPIO8 (0x0 << 3) +#define RT5645_GP8_PIN_DMIC2_SDA (0x1 << 3) +#define RT5645_GP12_PIN_MASK (0x1 << 2) +#define RT5645_GP12_PIN_SFT 2 +#define RT5645_GP12_PIN_GPIO12 (0x0 << 2) +#define RT5645_GP12_PIN_DMIC2_SDA (0x1 << 2) +#define RT5645_GP11_PIN_MASK (0x1 << 1) +#define RT5645_GP11_PIN_SFT 1 +#define RT5645_GP11_PIN_GPIO11 (0x0 << 1) +#define RT5645_GP11_PIN_DMIC1_SDA (0x1 << 1) +#define RT5645_GP10_PIN_MASK (0x1) +#define RT5645_GP10_PIN_SFT 0 +#define RT5645_GP10_PIN_GPIO10 (0x0) +#define RT5645_GP10_PIN_DMIC2_SDA (0x1) + +/* GPIO Control 3 (0xc2) */ +#define RT5645_GP4_PF_MASK (0x1 << 11) +#define RT5645_GP4_PF_SFT 11 +#define RT5645_GP4_PF_IN (0x0 << 11) +#define RT5645_GP4_PF_OUT (0x1 << 11) +#define RT5645_GP4_OUT_MASK (0x1 << 10) +#define RT5645_GP4_OUT_SFT 10 +#define RT5645_GP4_OUT_LO (0x0 << 10) +#define RT5645_GP4_OUT_HI (0x1 << 10) +#define RT5645_GP4_P_MASK (0x1 << 9) +#define RT5645_GP4_P_SFT 9 +#define RT5645_GP4_P_NOR (0x0 << 9) +#define RT5645_GP4_P_INV (0x1 << 9) +#define RT5645_GP3_PF_MASK (0x1 << 8) +#define RT5645_GP3_PF_SFT 8 +#define RT5645_GP3_PF_IN (0x0 << 8) +#define RT5645_GP3_PF_OUT (0x1 << 8) +#define RT5645_GP3_OUT_MASK (0x1 << 7) +#define RT5645_GP3_OUT_SFT 7 +#define RT5645_GP3_OUT_LO (0x0 << 7) +#define RT5645_GP3_OUT_HI (0x1 << 7) +#define RT5645_GP3_P_MASK (0x1 << 6) +#define RT5645_GP3_P_SFT 6 +#define RT5645_GP3_P_NOR (0x0 << 6) +#define RT5645_GP3_P_INV (0x1 << 6) +#define RT5645_GP2_PF_MASK (0x1 << 5) +#define RT5645_GP2_PF_SFT 5 +#define RT5645_GP2_PF_IN (0x0 << 5) +#define RT5645_GP2_PF_OUT (0x1 << 5) +#define RT5645_GP2_OUT_MASK (0x1 << 4) +#define RT5645_GP2_OUT_SFT 4 +#define RT5645_GP2_OUT_LO (0x0 << 4) +#define RT5645_GP2_OUT_HI (0x1 << 4) +#define RT5645_GP2_P_MASK (0x1 << 3) +#define RT5645_GP2_P_SFT 3 +#define RT5645_GP2_P_NOR (0x0 << 3) +#define RT5645_GP2_P_INV (0x1 << 3) +#define RT5645_GP1_PF_MASK (0x1 << 2) +#define RT5645_GP1_PF_SFT 2 +#define RT5645_GP1_PF_IN (0x0 << 2) +#define RT5645_GP1_PF_OUT (0x1 << 2) +#define RT5645_GP1_OUT_MASK (0x1 << 1) +#define RT5645_GP1_OUT_SFT 1 +#define RT5645_GP1_OUT_LO (0x0 << 1) +#define RT5645_GP1_OUT_HI (0x1 << 1) +#define RT5645_GP1_P_MASK (0x1) +#define RT5645_GP1_P_SFT 0 +#define RT5645_GP1_P_NOR (0x0) +#define RT5645_GP1_P_INV (0x1) + +/* Programmable Register Array Control 1 (0xc8) */ +#define RT5645_REG_SEQ_MASK (0xf << 12) +#define RT5645_REG_SEQ_SFT 12 +#define RT5645_SEQ1_ST_MASK (0x1 << 11) /*RO*/ +#define RT5645_SEQ1_ST_SFT 11 +#define RT5645_SEQ1_ST_RUN (0x0 << 11) +#define RT5645_SEQ1_ST_FIN (0x1 << 11) +#define RT5645_SEQ2_ST_MASK (0x1 << 10) /*RO*/ +#define RT5645_SEQ2_ST_SFT 10 +#define RT5645_SEQ2_ST_RUN (0x0 << 10) +#define RT5645_SEQ2_ST_FIN (0x1 << 10) +#define RT5645_REG_LV_MASK (0x1 << 9) +#define RT5645_REG_LV_SFT 9 +#define RT5645_REG_LV_MX (0x0 << 9) +#define RT5645_REG_LV_PR (0x1 << 9) +#define RT5645_SEQ_2_PT_MASK (0x1 << 8) +#define RT5645_SEQ_2_PT_BIT 8 +#define RT5645_REG_IDX_MASK (0xff) +#define RT5645_REG_IDX_SFT 0 + +/* Programmable Register Array Control 2 (0xc9) */ +#define RT5645_REG_DAT_MASK (0xffff) +#define RT5645_REG_DAT_SFT 0 + +/* Programmable Register Array Control 3 (0xca) */ +#define RT5645_SEQ_DLY_MASK (0xff << 8) +#define RT5645_SEQ_DLY_SFT 8 +#define RT5645_PROG_MASK (0x1 << 7) +#define RT5645_PROG_SFT 7 +#define RT5645_PROG_DIS (0x0 << 7) +#define RT5645_PROG_EN (0x1 << 7) +#define RT5645_SEQ1_PT_RUN (0x1 << 6) +#define RT5645_SEQ1_PT_RUN_BIT 6 +#define RT5645_SEQ2_PT_RUN (0x1 << 5) +#define RT5645_SEQ2_PT_RUN_BIT 5 + +/* Programmable Register Array Control 4 (0xcb) */ +#define RT5645_SEQ1_START_MASK (0xf << 8) +#define RT5645_SEQ1_START_SFT 8 +#define RT5645_SEQ1_END_MASK (0xf) +#define RT5645_SEQ1_END_SFT 0 + +/* Programmable Register Array Control 5 (0xcc) */ +#define RT5645_SEQ2_START_MASK (0xf << 8) +#define RT5645_SEQ2_START_SFT 8 +#define RT5645_SEQ2_END_MASK (0xf) +#define RT5645_SEQ2_END_SFT 0 + +/* Scramble Function (0xcd) */ +#define RT5645_SCB_KEY_MASK (0xff) +#define RT5645_SCB_KEY_SFT 0 + +/* Scramble Control (0xce) */ +#define RT5645_SCB_SWAP_MASK (0x1 << 15) +#define RT5645_SCB_SWAP_SFT 15 +#define RT5645_SCB_SWAP_DIS (0x0 << 15) +#define RT5645_SCB_SWAP_EN (0x1 << 15) +#define RT5645_SCB_MASK (0x1 << 14) +#define RT5645_SCB_SFT 14 +#define RT5645_SCB_DIS (0x0 << 14) +#define RT5645_SCB_EN (0x1 << 14) + +/* Baseback Control (0xcf) */ +#define RT5645_BB_MASK (0x1 << 15) +#define RT5645_BB_SFT 15 +#define RT5645_BB_DIS (0x0 << 15) +#define RT5645_BB_EN (0x1 << 15) +#define RT5645_BB_CT_MASK (0x7 << 12) +#define RT5645_BB_CT_SFT 12 +#define RT5645_BB_CT_A (0x0 << 12) +#define RT5645_BB_CT_B (0x1 << 12) +#define RT5645_BB_CT_C (0x2 << 12) +#define RT5645_BB_CT_D (0x3 << 12) +#define RT5645_M_BB_L_MASK (0x1 << 9) +#define RT5645_M_BB_L_SFT 9 +#define RT5645_M_BB_R_MASK (0x1 << 8) +#define RT5645_M_BB_R_SFT 8 +#define RT5645_M_BB_HPF_L_MASK (0x1 << 7) +#define RT5645_M_BB_HPF_L_SFT 7 +#define RT5645_M_BB_HPF_R_MASK (0x1 << 6) +#define RT5645_M_BB_HPF_R_SFT 6 +#define RT5645_G_BB_BST_MASK (0x3f) +#define RT5645_G_BB_BST_SFT 0 + +/* MP3 Plus Control 1 (0xd0) */ +#define RT5645_M_MP3_L_MASK (0x1 << 15) +#define RT5645_M_MP3_L_SFT 15 +#define RT5645_M_MP3_R_MASK (0x1 << 14) +#define RT5645_M_MP3_R_SFT 14 +#define RT5645_M_MP3_MASK (0x1 << 13) +#define RT5645_M_MP3_SFT 13 +#define RT5645_M_MP3_DIS (0x0 << 13) +#define RT5645_M_MP3_EN (0x1 << 13) +#define RT5645_EG_MP3_MASK (0x1f << 8) +#define RT5645_EG_MP3_SFT 8 +#define RT5645_MP3_HLP_MASK (0x1 << 7) +#define RT5645_MP3_HLP_SFT 7 +#define RT5645_MP3_HLP_DIS (0x0 << 7) +#define RT5645_MP3_HLP_EN (0x1 << 7) +#define RT5645_M_MP3_ORG_L_MASK (0x1 << 6) +#define RT5645_M_MP3_ORG_L_SFT 6 +#define RT5645_M_MP3_ORG_R_MASK (0x1 << 5) +#define RT5645_M_MP3_ORG_R_SFT 5 + +/* MP3 Plus Control 2 (0xd1) */ +#define RT5645_MP3_WT_MASK (0x1 << 13) +#define RT5645_MP3_WT_SFT 13 +#define RT5645_MP3_WT_1_4 (0x0 << 13) +#define RT5645_MP3_WT_1_2 (0x1 << 13) +#define RT5645_OG_MP3_MASK (0x1f << 8) +#define RT5645_OG_MP3_SFT 8 +#define RT5645_HG_MP3_MASK (0x3f) +#define RT5645_HG_MP3_SFT 0 + +/* 3D HP Control 1 (0xd2) */ +#define RT5645_3D_CF_MASK (0x1 << 15) +#define RT5645_3D_CF_SFT 15 +#define RT5645_3D_CF_DIS (0x0 << 15) +#define RT5645_3D_CF_EN (0x1 << 15) +#define RT5645_3D_HP_MASK (0x1 << 14) +#define RT5645_3D_HP_SFT 14 +#define RT5645_3D_HP_DIS (0x0 << 14) +#define RT5645_3D_HP_EN (0x1 << 14) +#define RT5645_3D_BT_MASK (0x1 << 13) +#define RT5645_3D_BT_SFT 13 +#define RT5645_3D_BT_DIS (0x0 << 13) +#define RT5645_3D_BT_EN (0x1 << 13) +#define RT5645_3D_1F_MIX_MASK (0x3 << 11) +#define RT5645_3D_1F_MIX_SFT 11 +#define RT5645_3D_HP_M_MASK (0x1 << 10) +#define RT5645_3D_HP_M_SFT 10 +#define RT5645_3D_HP_M_SUR (0x0 << 10) +#define RT5645_3D_HP_M_FRO (0x1 << 10) +#define RT5645_M_3D_HRTF_MASK (0x1 << 9) +#define RT5645_M_3D_HRTF_SFT 9 +#define RT5645_M_3D_D2H_MASK (0x1 << 8) +#define RT5645_M_3D_D2H_SFT 8 +#define RT5645_M_3D_D2R_MASK (0x1 << 7) +#define RT5645_M_3D_D2R_SFT 7 +#define RT5645_M_3D_REVB_MASK (0x1 << 6) +#define RT5645_M_3D_REVB_SFT 6 + +/* Adjustable high pass filter control 1 (0xd3) */ +#define RT5645_2ND_HPF_MASK (0x1 << 15) +#define RT5645_2ND_HPF_SFT 15 +#define RT5645_2ND_HPF_DIS (0x0 << 15) +#define RT5645_2ND_HPF_EN (0x1 << 15) +#define RT5645_HPF_CF_L_MASK (0x7 << 12) +#define RT5645_HPF_CF_L_SFT 12 +#define RT5645_1ST_HPF_MASK (0x1 << 11) +#define RT5645_1ST_HPF_SFT 11 +#define RT5645_1ST_HPF_DIS (0x0 << 11) +#define RT5645_1ST_HPF_EN (0x1 << 11) +#define RT5645_HPF_CF_R_MASK (0x7 << 8) +#define RT5645_HPF_CF_R_SFT 8 +#define RT5645_ZD_T_MASK (0x3 << 6) +#define RT5645_ZD_T_SFT 6 +#define RT5645_ZD_F_MASK (0x3 << 4) +#define RT5645_ZD_F_SFT 4 +#define RT5645_ZD_F_IM (0x0 << 4) +#define RT5645_ZD_F_ZC_IM (0x1 << 4) +#define RT5645_ZD_F_ZC_IOD (0x2 << 4) +#define RT5645_ZD_F_UN (0x3 << 4) + +/* HP calibration control and Amp detection (0xd6) */ +#define RT5645_SI_DAC_MASK (0x1 << 11) +#define RT5645_SI_DAC_SFT 11 +#define RT5645_SI_DAC_AUTO (0x0 << 11) +#define RT5645_SI_DAC_TEST (0x1 << 11) +#define RT5645_DC_CAL_M_MASK (0x1 << 10) +#define RT5645_DC_CAL_M_SFT 10 +#define RT5645_DC_CAL_M_CAL (0x0 << 10) +#define RT5645_DC_CAL_M_NOR (0x1 << 10) +#define RT5645_DC_CAL_MASK (0x1 << 9) +#define RT5645_DC_CAL_SFT 9 +#define RT5645_DC_CAL_DIS (0x0 << 9) +#define RT5645_DC_CAL_EN (0x1 << 9) +#define RT5645_HPD_RCV_MASK (0x7 << 6) +#define RT5645_HPD_RCV_SFT 6 +#define RT5645_HPD_PS_MASK (0x1 << 5) +#define RT5645_HPD_PS_SFT 5 +#define RT5645_HPD_PS_DIS (0x0 << 5) +#define RT5645_HPD_PS_EN (0x1 << 5) +#define RT5645_CAL_M_MASK (0x1 << 4) +#define RT5645_CAL_M_SFT 4 +#define RT5645_CAL_M_DEP (0x0 << 4) +#define RT5645_CAL_M_CAL (0x1 << 4) +#define RT5645_CAL_MASK (0x1 << 3) +#define RT5645_CAL_SFT 3 +#define RT5645_CAL_DIS (0x0 << 3) +#define RT5645_CAL_EN (0x1 << 3) +#define RT5645_CAL_TEST_MASK (0x1 << 2) +#define RT5645_CAL_TEST_SFT 2 +#define RT5645_CAL_TEST_DIS (0x0 << 2) +#define RT5645_CAL_TEST_EN (0x1 << 2) +#define RT5645_CAL_P_MASK (0x3) +#define RT5645_CAL_P_SFT 0 +#define RT5645_CAL_P_NONE (0x0) +#define RT5645_CAL_P_CAL (0x1) +#define RT5645_CAL_P_DAC_CAL (0x2) + +/* Soft volume and zero cross control 1 (0xd9) */ +#define RT5645_SV_MASK (0x1 << 15) +#define RT5645_SV_SFT 15 +#define RT5645_SV_DIS (0x0 << 15) +#define RT5645_SV_EN (0x1 << 15) +#define RT5645_SPO_SV_MASK (0x1 << 14) +#define RT5645_SPO_SV_SFT 14 +#define RT5645_SPO_SV_DIS (0x0 << 14) +#define RT5645_SPO_SV_EN (0x1 << 14) +#define RT5645_OUT_SV_MASK (0x1 << 13) +#define RT5645_OUT_SV_SFT 13 +#define RT5645_OUT_SV_DIS (0x0 << 13) +#define RT5645_OUT_SV_EN (0x1 << 13) +#define RT5645_HP_SV_MASK (0x1 << 12) +#define RT5645_HP_SV_SFT 12 +#define RT5645_HP_SV_DIS (0x0 << 12) +#define RT5645_HP_SV_EN (0x1 << 12) +#define RT5645_ZCD_DIG_MASK (0x1 << 11) +#define RT5645_ZCD_DIG_SFT 11 +#define RT5645_ZCD_DIG_DIS (0x0 << 11) +#define RT5645_ZCD_DIG_EN (0x1 << 11) +#define RT5645_ZCD_MASK (0x1 << 10) +#define RT5645_ZCD_SFT 10 +#define RT5645_ZCD_PD (0x0 << 10) +#define RT5645_ZCD_PU (0x1 << 10) +#define RT5645_M_ZCD_MASK (0x3f << 4) +#define RT5645_M_ZCD_SFT 4 +#define RT5645_M_ZCD_RM_L (0x1 << 9) +#define RT5645_M_ZCD_RM_R (0x1 << 8) +#define RT5645_M_ZCD_SM_L (0x1 << 7) +#define RT5645_M_ZCD_SM_R (0x1 << 6) +#define RT5645_M_ZCD_OM_L (0x1 << 5) +#define RT5645_M_ZCD_OM_R (0x1 << 4) +#define RT5645_SV_DLY_MASK (0xf) +#define RT5645_SV_DLY_SFT 0 + +/* Soft volume and zero cross control 2 (0xda) */ +#define RT5645_ZCD_HP_MASK (0x1 << 15) +#define RT5645_ZCD_HP_SFT 15 +#define RT5645_ZCD_HP_DIS (0x0 << 15) +#define RT5645_ZCD_HP_EN (0x1 << 15) + + +/* Codec Private Register definition */ +/* 3D Speaker Control (0x63) */ +#define RT5645_3D_SPK_MASK (0x1 << 15) +#define RT5645_3D_SPK_SFT 15 +#define RT5645_3D_SPK_DIS (0x0 << 15) +#define RT5645_3D_SPK_EN (0x1 << 15) +#define RT5645_3D_SPK_M_MASK (0x3 << 13) +#define RT5645_3D_SPK_M_SFT 13 +#define RT5645_3D_SPK_CG_MASK (0x1f << 8) +#define RT5645_3D_SPK_CG_SFT 8 +#define RT5645_3D_SPK_SG_MASK (0x1f) +#define RT5645_3D_SPK_SG_SFT 0 + +/* Wind Noise Detection Control 1 (0x6c) */ +#define RT5645_WND_MASK (0x1 << 15) +#define RT5645_WND_SFT 15 +#define RT5645_WND_DIS (0x0 << 15) +#define RT5645_WND_EN (0x1 << 15) + +/* Wind Noise Detection Control 2 (0x6d) */ +#define RT5645_WND_FC_NW_MASK (0x3f << 10) +#define RT5645_WND_FC_NW_SFT 10 +#define RT5645_WND_FC_WK_MASK (0x3f << 4) +#define RT5645_WND_FC_WK_SFT 4 + +/* Wind Noise Detection Control 3 (0x6e) */ +#define RT5645_HPF_FC_MASK (0x3f << 6) +#define RT5645_HPF_FC_SFT 6 +#define RT5645_WND_FC_ST_MASK (0x3f) +#define RT5645_WND_FC_ST_SFT 0 + +/* Wind Noise Detection Control 4 (0x6f) */ +#define RT5645_WND_TH_LO_MASK (0x3ff) +#define RT5645_WND_TH_LO_SFT 0 + +/* Wind Noise Detection Control 5 (0x70) */ +#define RT5645_WND_TH_HI_MASK (0x3ff) +#define RT5645_WND_TH_HI_SFT 0 + +/* Wind Noise Detection Control 8 (0x73) */ +#define RT5645_WND_WIND_MASK (0x1 << 13) /* Read-Only */ +#define RT5645_WND_WIND_SFT 13 +#define RT5645_WND_STRONG_MASK (0x1 << 12) /* Read-Only */ +#define RT5645_WND_STRONG_SFT 12 +enum { + RT5645_NO_WIND, + RT5645_BREEZE, + RT5645_STORM, +}; + +/* Dipole Speaker Interface (0x75) */ +#define RT5645_DP_ATT_MASK (0x3 << 14) +#define RT5645_DP_ATT_SFT 14 +#define RT5645_DP_SPK_MASK (0x1 << 10) +#define RT5645_DP_SPK_SFT 10 +#define RT5645_DP_SPK_DIS (0x0 << 10) +#define RT5645_DP_SPK_EN (0x1 << 10) + +/* EQ Pre Volume Control (0xb3) */ +#define RT5645_EQ_PRE_VOL_MASK (0xffff) +#define RT5645_EQ_PRE_VOL_SFT 0 + +/* EQ Post Volume Control (0xb4) */ +#define RT5645_EQ_PST_VOL_MASK (0xffff) +#define RT5645_EQ_PST_VOL_SFT 0 + +/* Jack Detect Control 3 (0xf8) */ +#define RT5645_CMP_MIC_IN_DET_MASK (0x7 << 12) +#define RT5645_JD_CBJ_EN (0x1 << 7) +#define RT5645_JD_CBJ_POL (0x1 << 6) +#define RT5645_JD_TRI_CBJ_SEL_MASK (0x7 << 3) +#define RT5645_JD_TRI_CBJ_SEL_SFT (3) +#define RT5645_JD_TRI_HPO_SEL_MASK (0x7) +#define RT5645_JD_TRI_HPO_SEL_SFT (0) +#define RT5645_JD_F_GPIO_JD1 (0x0) +#define RT5645_JD_F_JD1_1 (0x1) +#define RT5645_JD_F_JD1_2 (0x2) +#define RT5645_JD_F_JD2 (0x3) +#define RT5645_JD_F_JD3 (0x4) +#define RT5645_JD_F_GPIO_JD2 (0x5) +#define RT5645_JD_F_MX0B_12 (0x6) + +/* Digital Misc Control (0xfa) */ +#define RT5645_RST_DSP (0x1 << 13) +#define RT5645_IF1_ADC1_IN1_SEL (0x1 << 12) +#define RT5645_IF1_ADC1_IN1_SFT 12 +#define RT5645_IF1_ADC1_IN2_SEL (0x1 << 11) +#define RT5645_IF1_ADC1_IN2_SFT 11 +#define RT5645_IF1_ADC2_IN1_SEL (0x1 << 10) +#define RT5645_IF1_ADC2_IN1_SFT 10 +#define RT5645_DIG_GATE_CTRL 0x1 + +/* General Control2 (0xfb) */ +#define RT5645_RXDC_SRC_MASK (0x1 << 7) +#define RT5645_RXDC_SRC_STO (0x0 << 7) +#define RT5645_RXDC_SRC_MONO (0x1 << 7) +#define RT5645_RXDC_SRC_SFT (7) +#define RT5645_RXDP2_SEL_MASK (0x1 << 3) +#define RT5645_RXDP2_SEL_IF2 (0x0 << 3) +#define RT5645_RXDP2_SEL_ADC (0x1 << 3) +#define RT5645_RXDP2_SEL_SFT (3) + + +/* Vendor ID (0xfd) */ +#define RT5645_VER_C 0x2 +#define RT5645_VER_D 0x3 + + +/* Volume Rescale */ +#define RT5645_VOL_RSCL_MAX 0x27 +#define RT5645_VOL_RSCL_RANGE 0x1F +/* Debug String Length */ +#define RT5645_REG_DISP_LEN 23 + + +/* System Clock Source */ +enum { + RT5645_SCLK_S_MCLK, + RT5645_SCLK_S_PLL1, + RT5645_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { + RT5645_PLL1_S_MCLK, + RT5645_PLL1_S_BCLK1, + RT5645_PLL1_S_BCLK2, +}; + +enum { + RT5645_AIF1, + RT5645_AIF2, + RT5645_AIFS, +}; + +enum { + RT5645_DMIC_DATA_IN2P, + RT5645_DMIC_DATA_GPIO6, + RT5645_DMIC_DATA_GPIO10, + RT5645_DMIC_DATA_GPIO12, +}; + +enum { + RT5645_DMIC_DATA_IN2N, + RT5645_DMIC_DATA_GPIO5, + RT5645_DMIC_DATA_GPIO11, +}; + +struct rt5645_pll_code { + bool m_bp; /* Indicates bypass m code or not. */ + int m_code; + int n_code; + int k_code; +}; + +struct rt5645_priv { + struct snd_soc_codec *codec; + struct rt5645_platform_data pdata; + struct regmap *regmap; + + int sysclk; + int sysclk_src; + int lrck[RT5645_AIFS]; + int bclk[RT5645_AIFS]; + int master[RT5645_AIFS]; + + int pll_src; + int pll_in; + int pll_out; +}; + +#endif /* __RT5645_H__ */ diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c new file mode 100644 index 00000000000000..f785b81238aeb1 --- /dev/null +++ b/sound/soc/codecs/rt5651.c @@ -0,0 +1,1898 @@ +/* + * rt5651.c -- RT5651 ALSA SoC audio codec driver + * + * Copyright 2014 Realtek Semiconductor Corp. + * Author: Bard Liao + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt5651.h" + +#define RT5651_DEVICE_ID_VALUE 0x6281 + +#define RT5651_PR_RANGE_BASE (0xff + 1) +#define RT5651_PR_SPACING 0x100 + +#define RT5651_PR_BASE (RT5651_PR_RANGE_BASE + (0 * RT5651_PR_SPACING)) + +static const struct regmap_range_cfg rt5651_ranges[] = { + { .name = "PR", .range_min = RT5651_PR_BASE, + .range_max = RT5651_PR_BASE + 0xb4, + .selector_reg = RT5651_PRIV_INDEX, + .selector_mask = 0xff, + .selector_shift = 0x0, + .window_start = RT5651_PRIV_DATA, + .window_len = 0x1, }, +}; + +static struct reg_default init_list[] = { + {RT5651_PR_BASE + 0x3d, 0x3e00}, +}; + +static const struct reg_default rt5651_reg[] = { + { 0x00, 0x0000 }, + { 0x02, 0xc8c8 }, + { 0x03, 0xc8c8 }, + { 0x05, 0x0000 }, + { 0x0d, 0x0000 }, + { 0x0e, 0x0000 }, + { 0x0f, 0x0808 }, + { 0x10, 0x0808 }, + { 0x19, 0xafaf }, + { 0x1a, 0xafaf }, + { 0x1b, 0x0c00 }, + { 0x1c, 0x2f2f }, + { 0x1d, 0x2f2f }, + { 0x1e, 0x0000 }, + { 0x27, 0x7860 }, + { 0x28, 0x7070 }, + { 0x29, 0x8080 }, + { 0x2a, 0x5252 }, + { 0x2b, 0x5454 }, + { 0x2f, 0x0000 }, + { 0x30, 0x5000 }, + { 0x3b, 0x0000 }, + { 0x3c, 0x006f }, + { 0x3d, 0x0000 }, + { 0x3e, 0x006f }, + { 0x45, 0x6000 }, + { 0x4d, 0x0000 }, + { 0x4e, 0x0000 }, + { 0x4f, 0x0279 }, + { 0x50, 0x0000 }, + { 0x51, 0x0000 }, + { 0x52, 0x0279 }, + { 0x53, 0xf000 }, + { 0x61, 0x0000 }, + { 0x62, 0x0000 }, + { 0x63, 0x00c0 }, + { 0x64, 0x0000 }, + { 0x65, 0x0000 }, + { 0x66, 0x0000 }, + { 0x70, 0x8000 }, + { 0x71, 0x8000 }, + { 0x73, 0x1104 }, + { 0x74, 0x0c00 }, + { 0x75, 0x1400 }, + { 0x77, 0x0c00 }, + { 0x78, 0x4000 }, + { 0x79, 0x0123 }, + { 0x80, 0x0000 }, + { 0x81, 0x0000 }, + { 0x82, 0x0000 }, + { 0x83, 0x0800 }, + { 0x84, 0x0000 }, + { 0x85, 0x0008 }, + { 0x89, 0x0000 }, + { 0x8e, 0x0004 }, + { 0x8f, 0x1100 }, + { 0x90, 0x0000 }, + { 0x93, 0x2000 }, + { 0x94, 0x0200 }, + { 0xb0, 0x2080 }, + { 0xb1, 0x0000 }, + { 0xb4, 0x2206 }, + { 0xb5, 0x1f00 }, + { 0xb6, 0x0000 }, + { 0xbb, 0x0000 }, + { 0xbc, 0x0000 }, + { 0xbd, 0x0000 }, + { 0xbe, 0x0000 }, + { 0xbf, 0x0000 }, + { 0xc0, 0x0400 }, + { 0xc1, 0x0000 }, + { 0xc2, 0x0000 }, + { 0xcf, 0x0013 }, + { 0xd0, 0x0680 }, + { 0xd1, 0x1c17 }, + { 0xd3, 0xb320 }, + { 0xd9, 0x0809 }, + { 0xfa, 0x0010 }, + { 0xfe, 0x10ec }, + { 0xff, 0x6281 }, +}; + +static bool rt5651_volatile_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5651_ranges); i++) { + if ((reg >= rt5651_ranges[i].window_start && + reg <= rt5651_ranges[i].window_start + + rt5651_ranges[i].window_len) || + (reg >= rt5651_ranges[i].range_min && + reg <= rt5651_ranges[i].range_max)) { + return true; + } + } + + switch (reg) { + case RT5651_RESET: + case RT5651_PRIV_DATA: + case RT5651_EQ_CTRL1: + case RT5651_ALC_1: + case RT5651_IRQ_CTRL2: + case RT5651_INT_IRQ_ST: + case RT5651_PGM_REG_ARR1: + case RT5651_PGM_REG_ARR3: + case RT5651_VENDOR_ID: + case RT5651_DEVICE_ID: + return true; + default: + return false; + } +} + +static bool rt5651_readable_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5651_ranges); i++) { + if ((reg >= rt5651_ranges[i].window_start && + reg <= rt5651_ranges[i].window_start + + rt5651_ranges[i].window_len) || + (reg >= rt5651_ranges[i].range_min && + reg <= rt5651_ranges[i].range_max)) { + return true; + } + } + + switch (reg) { + case RT5651_RESET: + case RT5651_VERSION_ID: + case RT5651_VENDOR_ID: + case RT5651_DEVICE_ID: + case RT5651_HP_VOL: + case RT5651_LOUT_CTRL1: + case RT5651_LOUT_CTRL2: + case RT5651_IN1_IN2: + case RT5651_IN3: + case RT5651_INL1_INR1_VOL: + case RT5651_INL2_INR2_VOL: + case RT5651_DAC1_DIG_VOL: + case RT5651_DAC2_DIG_VOL: + case RT5651_DAC2_CTRL: + case RT5651_ADC_DIG_VOL: + case RT5651_ADC_DATA: + case RT5651_ADC_BST_VOL: + case RT5651_STO1_ADC_MIXER: + case RT5651_STO2_ADC_MIXER: + case RT5651_AD_DA_MIXER: + case RT5651_STO_DAC_MIXER: + case RT5651_DD_MIXER: + case RT5651_DIG_INF_DATA: + case RT5651_PDM_CTL: + case RT5651_REC_L1_MIXER: + case RT5651_REC_L2_MIXER: + case RT5651_REC_R1_MIXER: + case RT5651_REC_R2_MIXER: + case RT5651_HPO_MIXER: + case RT5651_OUT_L1_MIXER: + case RT5651_OUT_L2_MIXER: + case RT5651_OUT_L3_MIXER: + case RT5651_OUT_R1_MIXER: + case RT5651_OUT_R2_MIXER: + case RT5651_OUT_R3_MIXER: + case RT5651_LOUT_MIXER: + case RT5651_PWR_DIG1: + case RT5651_PWR_DIG2: + case RT5651_PWR_ANLG1: + case RT5651_PWR_ANLG2: + case RT5651_PWR_MIXER: + case RT5651_PWR_VOL: + case RT5651_PRIV_INDEX: + case RT5651_PRIV_DATA: + case RT5651_I2S1_SDP: + case RT5651_I2S2_SDP: + case RT5651_ADDA_CLK1: + case RT5651_ADDA_CLK2: + case RT5651_DMIC: + case RT5651_TDM_CTL_1: + case RT5651_TDM_CTL_2: + case RT5651_TDM_CTL_3: + case RT5651_GLB_CLK: + case RT5651_PLL_CTRL1: + case RT5651_PLL_CTRL2: + case RT5651_PLL_MODE_1: + case RT5651_PLL_MODE_2: + case RT5651_PLL_MODE_3: + case RT5651_PLL_MODE_4: + case RT5651_PLL_MODE_5: + case RT5651_PLL_MODE_6: + case RT5651_PLL_MODE_7: + case RT5651_DEPOP_M1: + case RT5651_DEPOP_M2: + case RT5651_DEPOP_M3: + case RT5651_CHARGE_PUMP: + case RT5651_MICBIAS: + case RT5651_A_JD_CTL1: + case RT5651_EQ_CTRL1: + case RT5651_EQ_CTRL2: + case RT5651_ALC_1: + case RT5651_ALC_2: + case RT5651_ALC_3: + case RT5651_JD_CTRL1: + case RT5651_JD_CTRL2: + case RT5651_IRQ_CTRL1: + case RT5651_IRQ_CTRL2: + case RT5651_INT_IRQ_ST: + case RT5651_GPIO_CTRL1: + case RT5651_GPIO_CTRL2: + case RT5651_GPIO_CTRL3: + case RT5651_PGM_REG_ARR1: + case RT5651_PGM_REG_ARR2: + case RT5651_PGM_REG_ARR3: + case RT5651_PGM_REG_ARR4: + case RT5651_PGM_REG_ARR5: + case RT5651_SCB_FUNC: + case RT5651_SCB_CTRL: + case RT5651_BASE_BACK: + case RT5651_MP3_PLUS1: + case RT5651_MP3_PLUS2: + case RT5651_ADJ_HPF_CTRL1: + case RT5651_ADJ_HPF_CTRL2: + case RT5651_HP_CALIB_AMP_DET: + case RT5651_HP_CALIB2: + case RT5651_SV_ZCD1: + case RT5651_SV_ZCD2: + case RT5651_D_MISC: + case RT5651_DUMMY2: + case RT5651_DUMMY3: + return true; + default: + return false; + } +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static unsigned int bst_tlv[] = { + TLV_DB_RANGE_HEAD(7), + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), + 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), + 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), + 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), +}; + +/* Interface data select */ +static const char * const rt5651_data_select[] = { + "Normal", "Swap", "left copy to right", "right copy to left"}; + +static SOC_ENUM_SINGLE_DECL(rt5651_if2_dac_enum, RT5651_DIG_INF_DATA, + RT5651_IF2_DAC_SEL_SFT, rt5651_data_select); + +static SOC_ENUM_SINGLE_DECL(rt5651_if2_adc_enum, RT5651_DIG_INF_DATA, + RT5651_IF2_ADC_SEL_SFT, rt5651_data_select); + +static const struct snd_kcontrol_new rt5651_snd_controls[] = { + /* Headphone Output Volume */ + SOC_DOUBLE_TLV("HP Playback Volume", RT5651_HP_VOL, + RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv), + /* OUTPUT Control */ + SOC_DOUBLE_TLV("OUT Playback Volume", RT5651_LOUT_CTRL1, + RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv), + + /* DAC Digital Volume */ + SOC_DOUBLE("DAC2 Playback Switch", RT5651_DAC2_CTRL, + RT5651_M_DAC_L2_VOL_SFT, RT5651_M_DAC_R2_VOL_SFT, 1, 1), + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5651_DAC1_DIG_VOL, + RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, + 175, 0, dac_vol_tlv), + SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5651_DAC2_DIG_VOL, + RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, + 175, 0, dac_vol_tlv), + /* IN1/IN2 Control */ + SOC_SINGLE_TLV("IN1 Boost", RT5651_IN1_IN2, + RT5651_BST_SFT1, 8, 0, bst_tlv), + SOC_SINGLE_TLV("IN2 Boost", RT5651_IN1_IN2, + RT5651_BST_SFT2, 8, 0, bst_tlv), + /* INL/INR Volume Control */ + SOC_DOUBLE_TLV("IN Capture Volume", RT5651_INL1_INR1_VOL, + RT5651_INL_VOL_SFT, RT5651_INR_VOL_SFT, + 31, 1, in_vol_tlv), + /* ADC Digital Volume Control */ + SOC_DOUBLE("ADC Capture Switch", RT5651_ADC_DIG_VOL, + RT5651_L_MUTE_SFT, RT5651_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("ADC Capture Volume", RT5651_ADC_DIG_VOL, + RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, + 127, 0, adc_vol_tlv), + SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5651_ADC_DATA, + RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, + 127, 0, adc_vol_tlv), + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("ADC Boost Gain", RT5651_ADC_BST_VOL, + RT5651_ADC_L_BST_SFT, RT5651_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + /* ASRC */ + SOC_SINGLE("IF1 ASRC Switch", RT5651_PLL_MODE_1, + RT5651_STO1_T_SFT, 1, 0), + SOC_SINGLE("IF2 ASRC Switch", RT5651_PLL_MODE_1, + RT5651_STO2_T_SFT, 1, 0), + SOC_SINGLE("DMIC ASRC Switch", RT5651_PLL_MODE_1, + RT5651_DMIC_1_M_SFT, 1, 0), + + SOC_ENUM("ADC IF2 Data Switch", rt5651_if2_adc_enum), + SOC_ENUM("DAC IF2 Data Switch", rt5651_if2_dac_enum), +}; + +/** + * set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + * Choose dmic clock between 1MHz and 3MHz. + * It is better for clock to approximate 3MHz. + */ +static int set_dmic_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + int div[] = {2, 3, 4, 6, 8, 12}, idx = -EINVAL; + int i, rate, red, bound, temp; + + rate = rt5651->sysclk; + red = 3000000 * 12; + for (i = 0; i < ARRAY_SIZE(div); i++) { + bound = div[i] * 3000000; + if (rate > bound) + continue; + temp = bound - rate; + if (temp < red) { + red = temp; + idx = i; + } + } + if (idx < 0) + dev_err(codec->dev, "Failed to set DMIC clock\n"); + else + snd_soc_update_bits(codec, RT5651_DMIC, RT5651_DMIC_CLK_MASK, + idx << RT5651_DMIC_CLK_SFT); + + return idx; +} + +static int is_sysclk_from_pll(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int val; + + val = snd_soc_read(source->codec, RT5651_GLB_CLK); + val &= RT5651_SCLK_SRC_MASK; + if (val == RT5651_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5651_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER, + RT5651_M_STO1_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER, + RT5651_M_STO1_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER, + RT5651_M_STO1_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER, + RT5651_M_STO1_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_sto2_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO2_ADC_MIXER, + RT5651_M_STO2_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO2_ADC_MIXER, + RT5651_M_STO2_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_sto2_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO2_ADC_MIXER, + RT5651_M_STO2_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO2_ADC_MIXER, + RT5651_M_STO2_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5651_AD_DA_MIXER, + RT5651_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INF1 Switch", RT5651_AD_DA_MIXER, + RT5651_M_IF1_DAC_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5651_AD_DA_MIXER, + RT5651_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INF1 Switch", RT5651_AD_DA_MIXER, + RT5651_M_IF1_DAC_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_sto_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_STO_DAC_MIXER, + RT5651_M_DAC_L1_MIXL_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_STO_DAC_MIXER, + RT5651_M_DAC_L2_MIXL_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_STO_DAC_MIXER, + RT5651_M_DAC_R1_MIXL_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_sto_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_STO_DAC_MIXER, + RT5651_M_DAC_R1_MIXR_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_STO_DAC_MIXER, + RT5651_M_DAC_R2_MIXR_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_STO_DAC_MIXER, + RT5651_M_DAC_L1_MIXR_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_dd_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_DD_MIXER, + RT5651_M_STO_DD_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_DD_MIXER, + RT5651_M_STO_DD_L2_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_DD_MIXER, + RT5651_M_STO_DD_R2_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_dd_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_DD_MIXER, + RT5651_M_STO_DD_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_DD_MIXER, + RT5651_M_STO_DD_R2_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_DD_MIXER, + RT5651_M_STO_DD_L2_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5651_rec_l_mix[] = { + SOC_DAPM_SINGLE("INL1 Switch", RT5651_REC_L2_MIXER, + RT5651_M_IN1_L_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5651_REC_L2_MIXER, + RT5651_M_BST3_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5651_REC_L2_MIXER, + RT5651_M_BST2_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5651_REC_L2_MIXER, + RT5651_M_BST1_RM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_rec_r_mix[] = { + SOC_DAPM_SINGLE("INR1 Switch", RT5651_REC_R2_MIXER, + RT5651_M_IN1_R_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5651_REC_R2_MIXER, + RT5651_M_BST3_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5651_REC_R2_MIXER, + RT5651_M_BST2_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5651_REC_R2_MIXER, + RT5651_M_BST1_RM_R_SFT, 1, 1), +}; + +/* Analog Output Mixer */ + +static const struct snd_kcontrol_new rt5651_out_l_mix[] = { + SOC_DAPM_SINGLE("BST1 Switch", RT5651_OUT_L3_MIXER, + RT5651_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5651_OUT_L3_MIXER, + RT5651_M_BST2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL1 Switch", RT5651_OUT_L3_MIXER, + RT5651_M_IN1_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("REC MIXL Switch", RT5651_OUT_L3_MIXER, + RT5651_M_RM_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_OUT_L3_MIXER, + RT5651_M_DAC_L1_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_out_r_mix[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5651_OUT_R3_MIXER, + RT5651_M_BST2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5651_OUT_R3_MIXER, + RT5651_M_BST1_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR1 Switch", RT5651_OUT_R3_MIXER, + RT5651_M_IN1_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("REC MIXR Switch", RT5651_OUT_R3_MIXER, + RT5651_M_RM_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_OUT_R3_MIXER, + RT5651_M_DAC_R1_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_hpo_mix[] = { + SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5651_HPO_MIXER, + RT5651_M_DAC1_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5651_HPO_MIXER, + RT5651_M_HPVOL_HM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5651_lout_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_LOUT_MIXER, + RT5651_M_DAC_L1_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_LOUT_MIXER, + RT5651_M_DAC_R1_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL L Switch", RT5651_LOUT_MIXER, + RT5651_M_OV_L_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL R Switch", RT5651_LOUT_MIXER, + RT5651_M_OV_R_LM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new outvol_l_control = + SOC_DAPM_SINGLE("Switch", RT5651_LOUT_CTRL1, + RT5651_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new outvol_r_control = + SOC_DAPM_SINGLE("Switch", RT5651_LOUT_CTRL1, + RT5651_VOL_R_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_l_mute_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_LOUT_CTRL1, + RT5651_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_r_mute_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_LOUT_CTRL1, + RT5651_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpovol_l_control = + SOC_DAPM_SINGLE("Switch", RT5651_HP_VOL, + RT5651_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new hpovol_r_control = + SOC_DAPM_SINGLE("Switch", RT5651_HP_VOL, + RT5651_VOL_R_SFT, 1, 1); + +static const struct snd_kcontrol_new hpo_l_mute_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL, + RT5651_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpo_r_mute_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL, + RT5651_R_MUTE_SFT, 1, 1); + +/* INL/R source */ +static const char * const rt5651_inl_src[] = {"IN2P", "HPOVOLLP"}; + +static SOC_ENUM_SINGLE_DECL( + rt5651_inl_enum, RT5651_INL1_INR1_VOL, + RT5651_INL_SEL_SFT, rt5651_inl_src); + +static const struct snd_kcontrol_new rt5651_inl1_mux = + SOC_DAPM_ENUM("INL1 source", rt5651_inl_enum); + +static const char * const rt5651_inr1_src[] = {"IN2N", "HPOVOLRP"}; + +static SOC_ENUM_SINGLE_DECL( + rt5651_inr1_enum, RT5651_INL1_INR1_VOL, + RT5651_INR_SEL_SFT, rt5651_inr1_src); + +static const struct snd_kcontrol_new rt5651_inr1_mux = + SOC_DAPM_ENUM("INR1 source", rt5651_inr1_enum); + +static const char * const rt5651_inl2_src[] = {"IN3P", "OUTVOLLP"}; + +static SOC_ENUM_SINGLE_DECL( + rt5651_inl2_enum, RT5651_INL2_INR2_VOL, + RT5651_INL_SEL_SFT, rt5651_inl2_src); + +static const struct snd_kcontrol_new rt5651_inl2_mux = + SOC_DAPM_ENUM("INL2 source", rt5651_inl2_enum); + +static const char * const rt5651_inr2_src[] = {"IN3N", "OUTVOLRP"}; + +static SOC_ENUM_SINGLE_DECL( + rt5651_inr2_enum, RT5651_INL2_INR2_VOL, + RT5651_INR_SEL_SFT, rt5651_inr2_src); + +static const struct snd_kcontrol_new rt5651_inr2_mux = + SOC_DAPM_ENUM("INR2 source", rt5651_inr2_enum); + + +/* Stereo ADC source */ +static const char * const rt5651_stereo1_adc1_src[] = {"DD MIX", "ADC"}; + +static SOC_ENUM_SINGLE_DECL( + rt5651_stereo1_adc1_enum, RT5651_STO1_ADC_MIXER, + RT5651_STO1_ADC_1_SRC_SFT, rt5651_stereo1_adc1_src); + +static const struct snd_kcontrol_new rt5651_sto1_adc_l1_mux = + SOC_DAPM_ENUM("Stereo1 ADC L1 source", rt5651_stereo1_adc1_enum); + +static const struct snd_kcontrol_new rt5651_sto1_adc_r1_mux = + SOC_DAPM_ENUM("Stereo1 ADC R1 source", rt5651_stereo1_adc1_enum); + +static const char * const rt5651_stereo1_adc2_src[] = {"DMIC", "DD MIX"}; + +static SOC_ENUM_SINGLE_DECL( + rt5651_stereo1_adc2_enum, RT5651_STO1_ADC_MIXER, + RT5651_STO1_ADC_2_SRC_SFT, rt5651_stereo1_adc2_src); + +static const struct snd_kcontrol_new rt5651_sto1_adc_l2_mux = + SOC_DAPM_ENUM("Stereo1 ADC L2 source", rt5651_stereo1_adc2_enum); + +static const struct snd_kcontrol_new rt5651_sto1_adc_r2_mux = + SOC_DAPM_ENUM("Stereo1 ADC R2 source", rt5651_stereo1_adc2_enum); + +/* Mono ADC source */ +static const char * const rt5651_sto2_adc_l1_src[] = {"DD MIXL", "ADCL"}; + +static SOC_ENUM_SINGLE_DECL( + rt5651_sto2_adc_l1_enum, RT5651_STO1_ADC_MIXER, + RT5651_STO2_ADC_L1_SRC_SFT, rt5651_sto2_adc_l1_src); + +static const struct snd_kcontrol_new rt5651_sto2_adc_l1_mux = + SOC_DAPM_ENUM("Stereo2 ADC1 left source", rt5651_sto2_adc_l1_enum); + +static const char * const rt5651_sto2_adc_l2_src[] = {"DMIC L", "DD MIXL"}; + +static SOC_ENUM_SINGLE_DECL( + rt5651_sto2_adc_l2_enum, RT5651_STO1_ADC_MIXER, + RT5651_STO2_ADC_L2_SRC_SFT, rt5651_sto2_adc_l2_src); + +static const struct snd_kcontrol_new rt5651_sto2_adc_l2_mux = + SOC_DAPM_ENUM("Stereo2 ADC2 left source", rt5651_sto2_adc_l2_enum); + +static const char * const rt5651_sto2_adc_r1_src[] = {"DD MIXR", "ADCR"}; + +static SOC_ENUM_SINGLE_DECL( + rt5651_sto2_adc_r1_enum, RT5651_STO1_ADC_MIXER, + RT5651_STO2_ADC_R1_SRC_SFT, rt5651_sto2_adc_r1_src); + +static const struct snd_kcontrol_new rt5651_sto2_adc_r1_mux = + SOC_DAPM_ENUM("Stereo2 ADC1 right source", rt5651_sto2_adc_r1_enum); + +static const char * const rt5651_sto2_adc_r2_src[] = {"DMIC R", "DD MIXR"}; + +static SOC_ENUM_SINGLE_DECL( + rt5651_sto2_adc_r2_enum, RT5651_STO1_ADC_MIXER, + RT5651_STO2_ADC_R2_SRC_SFT, rt5651_sto2_adc_r2_src); + +static const struct snd_kcontrol_new rt5651_sto2_adc_r2_mux = + SOC_DAPM_ENUM("Stereo2 ADC2 right source", rt5651_sto2_adc_r2_enum); + +/* DAC2 channel source */ + +static const char * const rt5651_dac_src[] = {"IF1", "IF2"}; + +static SOC_ENUM_SINGLE_DECL(rt5651_dac_l2_enum, RT5651_DAC2_CTRL, + RT5651_SEL_DAC_L2_SFT, rt5651_dac_src); + +static const struct snd_kcontrol_new rt5651_dac_l2_mux = + SOC_DAPM_ENUM("DAC2 left channel source", rt5651_dac_l2_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5651_dac_r2_enum, RT5651_DAC2_CTRL, + RT5651_SEL_DAC_R2_SFT, rt5651_dac_src); + +static const struct snd_kcontrol_new rt5651_dac_r2_mux = + SOC_DAPM_ENUM("DAC2 right channel source", rt5651_dac_r2_enum); + +/* IF2_ADC channel source */ + +static const char * const rt5651_adc_src[] = {"IF1 ADC1", "IF1 ADC2"}; + +static SOC_ENUM_SINGLE_DECL(rt5651_if2_adc_src_enum, RT5651_DIG_INF_DATA, + RT5651_IF2_ADC_SRC_SFT, rt5651_adc_src); + +static const struct snd_kcontrol_new rt5651_if2_adc_src_mux = + SOC_DAPM_ENUM("IF2 ADC channel source", rt5651_if2_adc_src_enum); + +/* PDM select */ +static const char * const rt5651_pdm_sel[] = {"DD MIX", "Stereo DAC MIX"}; + +static SOC_ENUM_SINGLE_DECL( + rt5651_pdm_l_sel_enum, RT5651_PDM_CTL, + RT5651_PDM_L_SEL_SFT, rt5651_pdm_sel); + +static SOC_ENUM_SINGLE_DECL( + rt5651_pdm_r_sel_enum, RT5651_PDM_CTL, + RT5651_PDM_R_SEL_SFT, rt5651_pdm_sel); + +static const struct snd_kcontrol_new rt5651_pdm_l_mux = + SOC_DAPM_ENUM("PDM L select", rt5651_pdm_l_sel_enum); + +static const struct snd_kcontrol_new rt5651_pdm_r_mux = + SOC_DAPM_ENUM("PDM R select", rt5651_pdm_r_sel_enum); + +static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* depop parameters */ + regmap_update_bits(rt5651->regmap, RT5651_PR_BASE + + RT5651_CHPUMP_INT_REG1, 0x0700, 0x0200); + regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M2, + RT5651_DEPOP_MASK, RT5651_DEPOP_MAN); + regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M1, + RT5651_HP_CP_MASK | RT5651_HP_SG_MASK | + RT5651_HP_CB_MASK, RT5651_HP_CP_PU | + RT5651_HP_SG_DIS | RT5651_HP_CB_PU); + regmap_write(rt5651->regmap, RT5651_PR_BASE + + RT5651_HP_DCC_INT1, 0x9f00); + /* headphone amp power on */ + regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1, + RT5651_PWR_FV1 | RT5651_PWR_FV2, 0); + regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1, + RT5651_PWR_HA, + RT5651_PWR_HA); + usleep_range(10000, 15000); + regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1, + RT5651_PWR_FV1 | RT5651_PWR_FV2 , + RT5651_PWR_FV1 | RT5651_PWR_FV2); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5651_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* headphone unmute sequence */ + regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M2, + RT5651_DEPOP_MASK | RT5651_DIG_DP_MASK, + RT5651_DEPOP_AUTO | RT5651_DIG_DP_EN); + regmap_update_bits(rt5651->regmap, RT5651_CHARGE_PUMP, + RT5651_PM_HP_MASK, RT5651_PM_HP_HV); + + regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M3, + RT5651_CP_FQ1_MASK | RT5651_CP_FQ2_MASK | + RT5651_CP_FQ3_MASK, + (RT5651_CP_FQ_192_KHZ << RT5651_CP_FQ1_SFT) | + (RT5651_CP_FQ_12_KHZ << RT5651_CP_FQ2_SFT) | + (RT5651_CP_FQ_192_KHZ << RT5651_CP_FQ3_SFT)); + + regmap_write(rt5651->regmap, RT5651_PR_BASE + + RT5651_MAMP_INT_REG2, 0x1c00); + regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M1, + RT5651_HP_CP_MASK | RT5651_HP_SG_MASK, + RT5651_HP_CP_PD | RT5651_HP_SG_EN); + regmap_update_bits(rt5651->regmap, RT5651_PR_BASE + + RT5651_CHPUMP_INT_REG1, 0x0700, 0x0400); + rt5651->hp_mute = 0; + break; + + case SND_SOC_DAPM_PRE_PMD: + rt5651->hp_mute = 1; + usleep_range(70000, 75000); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (!rt5651->hp_mute) + usleep_range(80000, 85000); + + break; + + default: + return 0; + } + + return 0; +} + +static int rt5651_bst1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5651_PWR_ANLG2, + RT5651_PWR_BST1_OP2, RT5651_PWR_BST1_OP2); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5651_PWR_ANLG2, + RT5651_PWR_BST1_OP2, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5651_bst2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5651_PWR_ANLG2, + RT5651_PWR_BST2_OP2, RT5651_PWR_BST2_OP2); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5651_PWR_ANLG2, + RT5651_PWR_BST2_OP2, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5651_bst3_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5651_PWR_ANLG2, + RT5651_PWR_BST3_OP2, RT5651_PWR_BST3_OP2); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5651_PWR_ANLG2, + RT5651_PWR_BST3_OP2, 0); + break; + + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = { + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5651_PLL_MODE_2, + 15, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5651_PLL_MODE_2, + 14, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("STO1 DAC ASRC", 1, RT5651_PLL_MODE_2, + 13, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("STO2 DAC ASRC", 1, RT5651_PLL_MODE_2, + 12, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC ASRC", 1, RT5651_PLL_MODE_2, + 11, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("PLL1", RT5651_PWR_ANLG2, + RT5651_PWR_PLL_BIT, 0, NULL, 0), + /* Input Side */ + /* micbias */ + SND_SOC_DAPM_SUPPLY("LDO", RT5651_PWR_ANLG1, + RT5651_PWR_LDO_BIT, 0, NULL, 0), + SND_SOC_DAPM_MICBIAS("micbias1", RT5651_PWR_ANLG2, + RT5651_PWR_MB1_BIT, 0), + /* Input Lines */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("MIC3"), + + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN2N"), + SND_SOC_DAPM_INPUT("IN3P"), + SND_SOC_DAPM_INPUT("DMIC L1"), + SND_SOC_DAPM_INPUT("DMIC R1"), + SND_SOC_DAPM_SUPPLY("DMIC CLK", RT5651_DMIC, RT5651_DMIC_1_EN_SFT, + 0, set_dmic_clk, SND_SOC_DAPM_PRE_PMU), + /* Boost */ + SND_SOC_DAPM_PGA_E("BST1", RT5651_PWR_ANLG2, + RT5651_PWR_BST1_BIT, 0, NULL, 0, rt5651_bst1_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("BST2", RT5651_PWR_ANLG2, + RT5651_PWR_BST2_BIT, 0, NULL, 0, rt5651_bst2_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("BST3", RT5651_PWR_ANLG2, + RT5651_PWR_BST3_BIT, 0, NULL, 0, rt5651_bst3_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + /* Input Volume */ + SND_SOC_DAPM_PGA("INL1 VOL", RT5651_PWR_VOL, + RT5651_PWR_IN1_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR1 VOL", RT5651_PWR_VOL, + RT5651_PWR_IN1_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INL2 VOL", RT5651_PWR_VOL, + RT5651_PWR_IN2_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR2 VOL", RT5651_PWR_VOL, + RT5651_PWR_IN2_R_BIT, 0, NULL, 0), + /* IN Mux */ + SND_SOC_DAPM_MUX("INL1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl1_mux), + SND_SOC_DAPM_MUX("INR1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inr1_mux), + SND_SOC_DAPM_MUX("INL2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl2_mux), + SND_SOC_DAPM_MUX("INR2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inr2_mux), + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIXL", RT5651_PWR_MIXER, RT5651_PWR_RM_L_BIT, 0, + rt5651_rec_l_mix, ARRAY_SIZE(rt5651_rec_l_mix)), + SND_SOC_DAPM_MIXER("RECMIXR", RT5651_PWR_MIXER, RT5651_PWR_RM_R_BIT, 0, + rt5651_rec_r_mix, ARRAY_SIZE(rt5651_rec_r_mix)), + /* ADCs */ + SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_SUPPLY("ADC L Power", RT5651_PWR_DIG1, + RT5651_PWR_ADC_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC R Power", RT5651_PWR_DIG1, + RT5651_PWR_ADC_R_BIT, 0, NULL, 0), + /* ADC Mux */ + SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5651_sto1_adc_l2_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5651_sto1_adc_r2_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5651_sto1_adc_l1_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5651_sto1_adc_r1_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5651_sto2_adc_l2_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5651_sto2_adc_l1_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5651_sto2_adc_r1_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5651_sto2_adc_r2_mux), + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("Stereo1 Filter", RT5651_PWR_DIG2, + RT5651_PWR_ADC_STO1_F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Stereo2 Filter", RT5651_PWR_DIG2, + RT5651_PWR_ADC_STO2_F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5651_sto1_adc_l_mix, + ARRAY_SIZE(rt5651_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5651_sto1_adc_r_mix, + ARRAY_SIZE(rt5651_sto1_adc_r_mix)), + SND_SOC_DAPM_MIXER("Stereo2 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5651_sto2_adc_l_mix, + ARRAY_SIZE(rt5651_sto2_adc_l_mix)), + SND_SOC_DAPM_MIXER("Stereo2 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5651_sto2_adc_r_mix, + ARRAY_SIZE(rt5651_sto2_adc_r_mix)), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1", RT5651_PWR_DIG1, + RT5651_PWR_I2S1_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S2", RT5651_PWR_DIG1, + RT5651_PWR_I2S2_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX("IF2 ADC", SND_SOC_NOPM, 0, 0, + &rt5651_if2_adc_src_mux), + + /* Digital Interface Select */ + + SND_SOC_DAPM_MUX("PDM L Mux", RT5651_PDM_CTL, + RT5651_M_PDM_L_SFT, 1, &rt5651_pdm_l_mux), + SND_SOC_DAPM_MUX("PDM R Mux", RT5651_PDM_CTL, + RT5651_M_PDM_R_SFT, 1, &rt5651_pdm_r_mux), + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Audio DSP */ + SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5651_dac_l_mix, ARRAY_SIZE(rt5651_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5651_dac_r_mix, ARRAY_SIZE(rt5651_dac_r_mix)), + + /* DAC2 channel Mux */ + SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_dac_l2_mux), + SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_dac_r2_mux), + SND_SOC_DAPM_PGA("DAC L2 Volume", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC R2 Volume", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("Stero1 DAC Power", RT5651_PWR_DIG2, + RT5651_PWR_DAC_STO1_F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Stero2 DAC Power", RT5651_PWR_DIG2, + RT5651_PWR_DAC_STO2_F_BIT, 0, NULL, 0), + /* DAC Mixer */ + SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5651_sto_dac_l_mix, + ARRAY_SIZE(rt5651_sto_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5651_sto_dac_r_mix, + ARRAY_SIZE(rt5651_sto_dac_r_mix)), + SND_SOC_DAPM_MIXER("DD MIXL", SND_SOC_NOPM, 0, 0, + rt5651_dd_dac_l_mix, + ARRAY_SIZE(rt5651_dd_dac_l_mix)), + SND_SOC_DAPM_MIXER("DD MIXR", SND_SOC_NOPM, 0, 0, + rt5651_dd_dac_r_mix, + ARRAY_SIZE(rt5651_dd_dac_r_mix)), + + /* DACs */ + SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_SUPPLY("DAC L1 Power", RT5651_PWR_DIG1, + RT5651_PWR_DAC_L1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC R1 Power", RT5651_PWR_DIG1, + RT5651_PWR_DAC_R1_BIT, 0, NULL, 0), + /* OUT Mixer */ + SND_SOC_DAPM_MIXER("OUT MIXL", RT5651_PWR_MIXER, RT5651_PWR_OM_L_BIT, + 0, rt5651_out_l_mix, ARRAY_SIZE(rt5651_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5651_PWR_MIXER, RT5651_PWR_OM_R_BIT, + 0, rt5651_out_r_mix, ARRAY_SIZE(rt5651_out_r_mix)), + /* Ouput Volume */ + SND_SOC_DAPM_SWITCH("OUTVOL L", RT5651_PWR_VOL, + RT5651_PWR_OV_L_BIT, 0, &outvol_l_control), + SND_SOC_DAPM_SWITCH("OUTVOL R", RT5651_PWR_VOL, + RT5651_PWR_OV_R_BIT, 0, &outvol_r_control), + SND_SOC_DAPM_SWITCH("HPOVOL L", RT5651_PWR_VOL, + RT5651_PWR_HV_L_BIT, 0, &hpovol_l_control), + SND_SOC_DAPM_SWITCH("HPOVOL R", RT5651_PWR_VOL, + RT5651_PWR_HV_R_BIT, 0, &hpovol_r_control), + SND_SOC_DAPM_PGA("INL1", RT5651_PWR_VOL, + RT5651_PWR_IN1_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR1", RT5651_PWR_VOL, + RT5651_PWR_IN1_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INL2", RT5651_PWR_VOL, + RT5651_PWR_IN2_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR2", RT5651_PWR_VOL, + RT5651_PWR_IN2_R_BIT, 0, NULL, 0), + /* HPO/LOUT/Mono Mixer */ + SND_SOC_DAPM_MIXER("HPOL MIX", SND_SOC_NOPM, 0, 0, + rt5651_hpo_mix, ARRAY_SIZE(rt5651_hpo_mix)), + SND_SOC_DAPM_MIXER("HPOR MIX", SND_SOC_NOPM, 0, 0, + rt5651_hpo_mix, ARRAY_SIZE(rt5651_hpo_mix)), + SND_SOC_DAPM_SUPPLY("HP L Amp", RT5651_PWR_ANLG1, + RT5651_PWR_HP_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("HP R Amp", RT5651_PWR_ANLG1, + RT5651_PWR_HP_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("LOUT MIX", RT5651_PWR_ANLG1, RT5651_PWR_LM_BIT, 0, + rt5651_lout_mix, ARRAY_SIZE(rt5651_lout_mix)), + + SND_SOC_DAPM_SUPPLY("Amp Power", RT5651_PWR_ANLG1, + RT5651_PWR_HA_BIT, 0, rt5651_amp_power_event, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5651_hp_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SWITCH("HPO L Playback", SND_SOC_NOPM, 0, 0, + &hpo_l_mute_control), + SND_SOC_DAPM_SWITCH("HPO R Playback", SND_SOC_NOPM, 0, 0, + &hpo_r_mute_control), + SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0, + &lout_l_mute_control), + SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0, + &lout_r_mute_control), + SND_SOC_DAPM_POST("HP Post", rt5651_hp_post_event), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), + SND_SOC_DAPM_OUTPUT("LOUTL"), + SND_SOC_DAPM_OUTPUT("LOUTR"), + SND_SOC_DAPM_OUTPUT("PDML"), + SND_SOC_DAPM_OUTPUT("PDMR"), +}; + +static const struct snd_soc_dapm_route rt5651_dapm_routes[] = { + {"Stero1 DAC Power", NULL, "STO1 DAC ASRC"}, + {"Stero2 DAC Power", NULL, "STO2 DAC ASRC"}, + {"I2S1", NULL, "I2S1 ASRC"}, + {"I2S2", NULL, "I2S2 ASRC"}, + + {"IN1P", NULL, "LDO"}, + {"IN2P", NULL, "LDO"}, + {"IN3P", NULL, "LDO"}, + + {"IN1P", NULL, "MIC1"}, + {"IN2P", NULL, "MIC2"}, + {"IN2N", NULL, "MIC2"}, + {"IN3P", NULL, "MIC3"}, + + {"BST1", NULL, "IN1P"}, + {"BST2", NULL, "IN2P"}, + {"BST2", NULL, "IN2N"}, + {"BST3", NULL, "IN3P"}, + + {"INL1 VOL", NULL, "IN2P"}, + {"INR1 VOL", NULL, "IN2N"}, + + {"RECMIXL", "INL1 Switch", "INL1 VOL"}, + {"RECMIXL", "BST3 Switch", "BST3"}, + {"RECMIXL", "BST2 Switch", "BST2"}, + {"RECMIXL", "BST1 Switch", "BST1"}, + + {"RECMIXR", "INR1 Switch", "INR1 VOL"}, + {"RECMIXR", "BST3 Switch", "BST3"}, + {"RECMIXR", "BST2 Switch", "BST2"}, + {"RECMIXR", "BST1 Switch", "BST1"}, + + {"ADC L", NULL, "RECMIXL"}, + {"ADC L", NULL, "ADC L Power"}, + {"ADC R", NULL, "RECMIXR"}, + {"ADC R", NULL, "ADC R Power"}, + + {"DMIC L1", NULL, "DMIC CLK"}, + {"DMIC R1", NULL, "DMIC CLK"}, + + {"Stereo1 ADC L2 Mux", "DMIC", "DMIC L1"}, + {"Stereo1 ADC L2 Mux", "DD MIX", "DD MIXL"}, + {"Stereo1 ADC L1 Mux", "ADC", "ADC L"}, + {"Stereo1 ADC L1 Mux", "DD MIX", "DD MIXL"}, + + {"Stereo1 ADC R1 Mux", "ADC", "ADC R"}, + {"Stereo1 ADC R1 Mux", "DD MIX", "DD MIXR"}, + {"Stereo1 ADC R2 Mux", "DMIC", "DMIC R1"}, + {"Stereo1 ADC R2 Mux", "DD MIX", "DD MIXR"}, + + {"Stereo2 ADC L2 Mux", "DMIC L", "DMIC L1"}, + {"Stereo2 ADC L2 Mux", "DD MIXL", "DD MIXL"}, + {"Stereo2 ADC L1 Mux", "DD MIXL", "DD MIXL"}, + {"Stereo2 ADC L1 Mux", "ADCL", "ADC L"}, + + {"Stereo2 ADC R1 Mux", "DD MIXR", "DD MIXR"}, + {"Stereo2 ADC R1 Mux", "ADCR", "ADC R"}, + {"Stereo2 ADC R2 Mux", "DMIC R", "DMIC R1"}, + {"Stereo2 ADC R2 Mux", "DD MIXR", "DD MIXR"}, + + {"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"}, + {"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"}, + {"Stereo1 ADC MIXL", NULL, "Stereo1 Filter"}, + {"Stereo1 Filter", NULL, "PLL1", is_sysclk_from_pll}, + {"Stereo1 Filter", NULL, "ADC ASRC"}, + + {"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"}, + {"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"}, + {"Stereo1 ADC MIXR", NULL, "Stereo1 Filter"}, + + {"Stereo2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux"}, + {"Stereo2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux"}, + {"Stereo2 ADC MIXL", NULL, "Stereo2 Filter"}, + {"Stereo2 Filter", NULL, "PLL1", is_sysclk_from_pll}, + {"Stereo2 Filter", NULL, "ADC ASRC"}, + + {"Stereo2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux"}, + {"Stereo2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC R2 Mux"}, + {"Stereo2 ADC MIXR", NULL, "Stereo2 Filter"}, + + {"IF1 ADC2", NULL, "Stereo2 ADC MIXL"}, + {"IF1 ADC2", NULL, "Stereo2 ADC MIXR"}, + {"IF1 ADC1", NULL, "Stereo1 ADC MIXL"}, + {"IF1 ADC1", NULL, "Stereo1 ADC MIXR"}, + + {"IF1 ADC1", NULL, "I2S1"}, + + {"IF2 ADC", "IF1 ADC1", "IF1 ADC1"}, + {"IF2 ADC", "IF1 ADC2", "IF1 ADC2"}, + {"IF2 ADC", NULL, "I2S2"}, + + {"AIF1TX", NULL, "IF1 ADC1"}, + {"AIF1TX", NULL, "IF1 ADC2"}, + {"AIF2TX", NULL, "IF2 ADC"}, + + {"IF1 DAC", NULL, "AIF1RX"}, + {"IF1 DAC", NULL, "I2S1"}, + {"IF2 DAC", NULL, "AIF2RX"}, + {"IF2 DAC", NULL, "I2S2"}, + + {"IF1 DAC1 L", NULL, "IF1 DAC"}, + {"IF1 DAC1 R", NULL, "IF1 DAC"}, + {"IF1 DAC2 L", NULL, "IF1 DAC"}, + {"IF1 DAC2 R", NULL, "IF1 DAC"}, + {"IF2 DAC L", NULL, "IF2 DAC"}, + {"IF2 DAC R", NULL, "IF2 DAC"}, + + {"DAC MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"}, + {"DAC MIXL", "INF1 Switch", "IF1 DAC1 L"}, + {"DAC MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"}, + {"DAC MIXR", "INF1 Switch", "IF1 DAC1 R"}, + + {"Audio DSP", NULL, "DAC MIXL"}, + {"Audio DSP", NULL, "DAC MIXR"}, + + {"DAC L2 Mux", "IF1", "IF1 DAC2 L"}, + {"DAC L2 Mux", "IF2", "IF2 DAC L"}, + {"DAC L2 Volume", NULL, "DAC L2 Mux"}, + + {"DAC R2 Mux", "IF1", "IF1 DAC2 R"}, + {"DAC R2 Mux", "IF2", "IF2 DAC R"}, + {"DAC R2 Volume", NULL, "DAC R2 Mux"}, + + {"Stereo DAC MIXL", "DAC L1 Switch", "Audio DSP"}, + {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Volume"}, + {"Stereo DAC MIXL", "DAC R1 Switch", "DAC MIXR"}, + {"Stereo DAC MIXL", NULL, "Stero1 DAC Power"}, + {"Stereo DAC MIXL", NULL, "Stero2 DAC Power"}, + {"Stereo DAC MIXR", "DAC R1 Switch", "Audio DSP"}, + {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Volume"}, + {"Stereo DAC MIXR", "DAC L1 Switch", "DAC MIXL"}, + {"Stereo DAC MIXR", NULL, "Stero1 DAC Power"}, + {"Stereo DAC MIXR", NULL, "Stero2 DAC Power"}, + + {"PDM L Mux", "Stereo DAC MIX", "Stereo DAC MIXL"}, + {"PDM L Mux", "DD MIX", "DAC MIXL"}, + {"PDM R Mux", "Stereo DAC MIX", "Stereo DAC MIXR"}, + {"PDM R Mux", "DD MIX", "DAC MIXR"}, + + {"DAC L1", NULL, "Stereo DAC MIXL"}, + {"DAC L1", NULL, "PLL1", is_sysclk_from_pll}, + {"DAC L1", NULL, "DAC L1 Power"}, + {"DAC R1", NULL, "Stereo DAC MIXR"}, + {"DAC R1", NULL, "PLL1", is_sysclk_from_pll}, + {"DAC R1", NULL, "DAC R1 Power"}, + + {"DD MIXL", "DAC L1 Switch", "DAC MIXL"}, + {"DD MIXL", "DAC L2 Switch", "DAC L2 Volume"}, + {"DD MIXL", "DAC R2 Switch", "DAC R2 Volume"}, + {"DD MIXL", NULL, "Stero2 DAC Power"}, + + {"DD MIXR", "DAC R1 Switch", "DAC MIXR"}, + {"DD MIXR", "DAC R2 Switch", "DAC R2 Volume"}, + {"DD MIXR", "DAC L2 Switch", "DAC L2 Volume"}, + {"DD MIXR", NULL, "Stero2 DAC Power"}, + + {"OUT MIXL", "BST1 Switch", "BST1"}, + {"OUT MIXL", "BST2 Switch", "BST2"}, + {"OUT MIXL", "INL1 Switch", "INL1 VOL"}, + {"OUT MIXL", "REC MIXL Switch", "RECMIXL"}, + {"OUT MIXL", "DAC L1 Switch", "DAC L1"}, + + {"OUT MIXR", "BST2 Switch", "BST2"}, + {"OUT MIXR", "BST1 Switch", "BST1"}, + {"OUT MIXR", "INR1 Switch", "INR1 VOL"}, + {"OUT MIXR", "REC MIXR Switch", "RECMIXR"}, + {"OUT MIXR", "DAC R1 Switch", "DAC R1"}, + + {"HPOVOL L", "Switch", "OUT MIXL"}, + {"HPOVOL R", "Switch", "OUT MIXR"}, + {"OUTVOL L", "Switch", "OUT MIXL"}, + {"OUTVOL R", "Switch", "OUT MIXR"}, + + {"HPOL MIX", "HPO MIX DAC1 Switch", "DAC L1"}, + {"HPOL MIX", "HPO MIX HPVOL Switch", "HPOVOL L"}, + {"HPOL MIX", NULL, "HP L Amp"}, + {"HPOR MIX", "HPO MIX DAC1 Switch", "DAC R1"}, + {"HPOR MIX", "HPO MIX HPVOL Switch", "HPOVOL R"}, + {"HPOR MIX", NULL, "HP R Amp"}, + + {"LOUT MIX", "DAC L1 Switch", "DAC L1"}, + {"LOUT MIX", "DAC R1 Switch", "DAC R1"}, + {"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"}, + {"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"}, + + {"HP Amp", NULL, "HPOL MIX"}, + {"HP Amp", NULL, "HPOR MIX"}, + {"HP Amp", NULL, "Amp Power"}, + {"HPO L Playback", "Switch", "HP Amp"}, + {"HPO R Playback", "Switch", "HP Amp"}, + {"HPOL", NULL, "HPO L Playback"}, + {"HPOR", NULL, "HPO R Playback"}, + + {"LOUT L Playback", "Switch", "LOUT MIX"}, + {"LOUT R Playback", "Switch", "LOUT MIX"}, + {"LOUTL", NULL, "LOUT L Playback"}, + {"LOUTL", NULL, "Amp Power"}, + {"LOUTR", NULL, "LOUT R Playback"}, + {"LOUTR", NULL, "Amp Power"}, + + {"PDML", NULL, "PDM L Mux"}, + {"PDMR", NULL, "PDM R Mux"}, +}; + +static int get_clk_info(int sclk, int rate) +{ + int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; + + if (sclk <= 0 || rate <= 0) + return -EINVAL; + + rate = rate << 8; + for (i = 0; i < ARRAY_SIZE(pd); i++) + if (sclk == rate * pd[i]) + return i; + + return -EINVAL; +} + +static int rt5651_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0, val_clk, mask_clk; + int pre_div, bclk_ms, frame_size; + + rt5651->lrck[dai->id] = params_rate(params); + pre_div = get_clk_info(rt5651->sysclk, rt5651->lrck[dai->id]); + + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting\n"); + return -EINVAL; + } + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); + return -EINVAL; + } + bclk_ms = frame_size > 32 ? 1 : 0; + rt5651->bclk[dai->id] = rt5651->lrck[dai->id] * (32 << bclk_ms); + + dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", + rt5651->bclk[dai->id], rt5651->lrck[dai->id]); + dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", + bclk_ms, pre_div, dai->id); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val_len |= RT5651_I2S_DL_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val_len |= RT5651_I2S_DL_24; + break; + case SNDRV_PCM_FORMAT_S8: + val_len |= RT5651_I2S_DL_8; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5651_AIF1: + mask_clk = RT5651_I2S_PD1_MASK; + val_clk = pre_div << RT5651_I2S_PD1_SFT; + snd_soc_update_bits(codec, RT5651_I2S1_SDP, + RT5651_I2S_DL_MASK, val_len); + snd_soc_update_bits(codec, RT5651_ADDA_CLK1, mask_clk, val_clk); + break; + case RT5651_AIF2: + mask_clk = RT5651_I2S_BCLK_MS2_MASK | RT5651_I2S_PD2_MASK; + val_clk = pre_div << RT5651_I2S_PD2_SFT; + snd_soc_update_bits(codec, RT5651_I2S2_SDP, + RT5651_I2S_DL_MASK, val_len); + snd_soc_update_bits(codec, RT5651_ADDA_CLK1, mask_clk, val_clk); + break; + default: + dev_err(codec->dev, "Wrong dai->id: %d\n", dai->id); + return -EINVAL; + } + + return 0; +} + +static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5651->master[dai->id] = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5651_I2S_MS_S; + rt5651->master[dai->id] = 0; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5651_I2S_BP_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5651_I2S_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5651_I2S_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5651_I2S_DF_PCM_B; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5651_AIF1: + snd_soc_update_bits(codec, RT5651_I2S1_SDP, + RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK | + RT5651_I2S_DF_MASK, reg_val); + break; + case RT5651_AIF2: + snd_soc_update_bits(codec, RT5651_I2S2_SDP, + RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK | + RT5651_I2S_DF_MASK, reg_val); + break; + default: + dev_err(codec->dev, "Wrong dai->id: %d\n", dai->id); + return -EINVAL; + } + return 0; +} + +static int rt5651_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5651->sysclk && clk_id == rt5651->sysclk_src) + return 0; + + switch (clk_id) { + case RT5651_SCLK_S_MCLK: + reg_val |= RT5651_SCLK_SRC_MCLK; + break; + case RT5651_SCLK_S_PLL1: + reg_val |= RT5651_SCLK_SRC_PLL1; + break; + case RT5651_SCLK_S_RCCLK: + reg_val |= RT5651_SCLK_SRC_RCCLK; + break; + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5651_GLB_CLK, + RT5651_SCLK_SRC_MASK, reg_val); + rt5651->sysclk = freq; + rt5651->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + return 0; +} + +/** + * rt5651_pll_calc - Calcualte PLL M/N/K code. + * @freq_in: external clock provided to codec. + * @freq_out: target clock which codec works on. + * @pll_code: Pointer to structure with M, N, K and bypass flag. + * + * Calcualte M/N/K code to configure PLL for codec. And K is assigned to 2 + * which make calculation more efficiently. + * + * Returns 0 for success or negative error code. + */ +static int rt5651_pll_calc(const unsigned int freq_in, + const unsigned int freq_out, struct rt5651_pll_code *pll_code) +{ + int max_n = RT5651_PLL_N_MAX, max_m = RT5651_PLL_M_MAX; + int n = 0, m = 0, red, n_t, m_t, in_t, out_t; + int red_t = abs(freq_out - freq_in); + bool bypass = false; + + if (RT5651_PLL_INP_MAX < freq_in || RT5651_PLL_INP_MIN > freq_in) + return -EINVAL; + + for (n_t = 0; n_t <= max_n; n_t++) { + in_t = (freq_in >> 1) + (freq_in >> 2) * n_t; + if (in_t < 0) + continue; + if (in_t == freq_out) { + bypass = true; + n = n_t; + goto code_find; + } + for (m_t = 0; m_t <= max_m; m_t++) { + out_t = in_t / (m_t + 2); + red = abs(out_t - freq_out); + if (red < red_t) { + n = n_t; + m = m_t; + if (red == 0) + goto code_find; + red_t = red; + } + } + } + pr_debug("Only get approximation about PLL\n"); + +code_find: + pll_code->m_bp = bypass; + pll_code->m_code = m; + pll_code->n_code = n; + pll_code->k_code = 2; + return 0; +} + +static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + struct rt5651_pll_code *pll_code = &rt5651->pll_code; + int ret; + + if (source == rt5651->pll_src && freq_in == rt5651->pll_in && + freq_out == rt5651->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5651->pll_in = 0; + rt5651->pll_out = 0; + snd_soc_update_bits(codec, RT5651_GLB_CLK, + RT5651_SCLK_SRC_MASK, RT5651_SCLK_SRC_MCLK); + return 0; + } + + switch (source) { + case RT5651_PLL1_S_MCLK: + snd_soc_update_bits(codec, RT5651_GLB_CLK, + RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_MCLK); + break; + case RT5651_PLL1_S_BCLK1: + snd_soc_update_bits(codec, RT5651_GLB_CLK, + RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK1); + break; + case RT5651_PLL1_S_BCLK2: + snd_soc_update_bits(codec, RT5651_GLB_CLK, + RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK2); + break; + default: + dev_err(codec->dev, "Unknown PLL source %d\n", source); + return -EINVAL; + } + + ret = rt5651_pll_calc(freq_in, freq_out, pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=2\n", pll_code->m_bp, + (pll_code->m_bp ? 0 : pll_code->m_code), pll_code->n_code); + + snd_soc_write(codec, RT5651_PLL_CTRL1, + pll_code->n_code << RT5651_PLL_N_SFT | pll_code->k_code); + snd_soc_write(codec, RT5651_PLL_CTRL2, + (pll_code->m_bp ? 0 : pll_code->m_code) << RT5651_PLL_M_SFT | + pll_code->m_bp << RT5651_PLL_M_BP_SFT); + + rt5651->pll_in = freq_in; + rt5651->pll_out = freq_out; + rt5651->pll_src = source; + + return 0; +} + +static int rt5651_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { + snd_soc_update_bits(codec, RT5651_PWR_ANLG1, + RT5651_PWR_VREF1 | RT5651_PWR_MB | + RT5651_PWR_BG | RT5651_PWR_VREF2, + RT5651_PWR_VREF1 | RT5651_PWR_MB | + RT5651_PWR_BG | RT5651_PWR_VREF2); + usleep_range(10000, 15000); + snd_soc_update_bits(codec, RT5651_PWR_ANLG1, + RT5651_PWR_FV1 | RT5651_PWR_FV2, + RT5651_PWR_FV1 | RT5651_PWR_FV2); + snd_soc_update_bits(codec, RT5651_PWR_ANLG1, + RT5651_PWR_LDO_DVO_MASK, + RT5651_PWR_LDO_DVO_1_2V); + snd_soc_update_bits(codec, RT5651_D_MISC, 0x1, 0x1); + if (snd_soc_read(codec, RT5651_PLL_MODE_1) & 0x9200) + snd_soc_update_bits(codec, RT5651_D_MISC, + 0xc00, 0xc00); + } + break; + + case SND_SOC_BIAS_STANDBY: + snd_soc_write(codec, RT5651_D_MISC, 0x0010); + snd_soc_write(codec, RT5651_PWR_DIG1, 0x0000); + snd_soc_write(codec, RT5651_PWR_DIG2, 0x0000); + snd_soc_write(codec, RT5651_PWR_VOL, 0x0000); + snd_soc_write(codec, RT5651_PWR_MIXER, 0x0000); + snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0000); + snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0000); + break; + + default: + break; + } + codec->dapm.bias_level = level; + + return 0; +} + +static int rt5651_probe(struct snd_soc_codec *codec) +{ + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + + rt5651->codec = codec; + + snd_soc_update_bits(codec, RT5651_PWR_ANLG1, + RT5651_PWR_VREF1 | RT5651_PWR_MB | + RT5651_PWR_BG | RT5651_PWR_VREF2, + RT5651_PWR_VREF1 | RT5651_PWR_MB | + RT5651_PWR_BG | RT5651_PWR_VREF2); + usleep_range(10000, 15000); + snd_soc_update_bits(codec, RT5651_PWR_ANLG1, + RT5651_PWR_FV1 | RT5651_PWR_FV2, + RT5651_PWR_FV1 | RT5651_PWR_FV2); + + rt5651_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +#ifdef CONFIG_PM +static int rt5651_suspend(struct snd_soc_codec *codec) +{ + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5651->regmap, true); + regcache_mark_dirty(rt5651->regmap); + return 0; +} + +static int rt5651_resume(struct snd_soc_codec *codec) +{ + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5651->regmap, false); + snd_soc_cache_sync(codec); + + return 0; +} +#else +#define rt5651_suspend NULL +#define rt5651_resume NULL +#endif + +#define RT5651_STEREO_RATES SNDRV_PCM_RATE_8000_96000 +#define RT5651_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt5651_aif_dai_ops = { + .hw_params = rt5651_hw_params, + .set_fmt = rt5651_set_dai_fmt, + .set_sysclk = rt5651_set_dai_sysclk, + .set_pll = rt5651_set_dai_pll, +}; + +static struct snd_soc_dai_driver rt5651_dai[] = { + { + .name = "rt5651-aif1", + .id = RT5651_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5651_STEREO_RATES, + .formats = RT5651_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5651_STEREO_RATES, + .formats = RT5651_FORMATS, + }, + .ops = &rt5651_aif_dai_ops, + }, + { + .name = "rt5651-aif2", + .id = RT5651_AIF2, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5651_STEREO_RATES, + .formats = RT5651_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5651_STEREO_RATES, + .formats = RT5651_FORMATS, + }, + .ops = &rt5651_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5651 = { + .probe = rt5651_probe, + .suspend = rt5651_suspend, + .resume = rt5651_resume, + .set_bias_level = rt5651_set_bias_level, + .idle_bias_off = true, + .controls = rt5651_snd_controls, + .num_controls = ARRAY_SIZE(rt5651_snd_controls), + .dapm_widgets = rt5651_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5651_dapm_widgets), + .dapm_routes = rt5651_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes), +}; + +static const struct regmap_config rt5651_regmap = { + .reg_bits = 8, + .val_bits = 16, + + .max_register = RT5651_DEVICE_ID + 1 + (ARRAY_SIZE(rt5651_ranges) * + RT5651_PR_SPACING), + .volatile_reg = rt5651_volatile_register, + .readable_reg = rt5651_readable_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5651_reg, + .num_reg_defaults = ARRAY_SIZE(rt5651_reg), + .ranges = rt5651_ranges, + .num_ranges = ARRAY_SIZE(rt5651_ranges), +}; + +static const struct i2c_device_id rt5651_i2c_id[] = { + { "rt5651", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id); + +static int rt5651_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5651_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt5651_priv *rt5651; + int ret; + + rt5651 = devm_kzalloc(&i2c->dev, sizeof(*rt5651), + GFP_KERNEL); + if (NULL == rt5651) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt5651); + + if (pdata) + rt5651->pdata = *pdata; + + rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap); + if (IS_ERR(rt5651->regmap)) { + ret = PTR_ERR(rt5651->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); + if (ret != RT5651_DEVICE_ID_VALUE) { + dev_err(&i2c->dev, + "Device with ID register %x is not rt5651\n", ret); + return -ENODEV; + } + + regmap_write(rt5651->regmap, RT5651_RESET, 0); + + ret = regmap_register_patch(rt5651->regmap, init_list, + ARRAY_SIZE(init_list)); + if (ret != 0) + dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + + if (rt5651->pdata.in2_diff) + regmap_update_bits(rt5651->regmap, RT5651_IN1_IN2, + RT5651_IN_DF2, RT5651_IN_DF2); + + if (rt5651->pdata.dmic_en) + regmap_update_bits(rt5651->regmap, RT5651_GPIO_CTRL1, + RT5651_GP2_PIN_MASK, RT5651_GP2_PIN_DMIC1_SCL); + + rt5651->hp_mute = 1; + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651, + rt5651_dai, ARRAY_SIZE(rt5651_dai)); + + return ret; +} + +static int rt5651_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static struct i2c_driver rt5651_i2c_driver = { + .driver = { + .name = "rt5651", + .owner = THIS_MODULE, + }, + .probe = rt5651_i2c_probe, + .remove = rt5651_i2c_remove, + .id_table = rt5651_i2c_id, +}; +module_i2c_driver(rt5651_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5651 driver"); +MODULE_AUTHOR("Bard Liao "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h new file mode 100644 index 00000000000000..a28bd0c3d613f8 --- /dev/null +++ b/sound/soc/codecs/rt5651.h @@ -0,0 +1,2081 @@ +/* + * rt5651.h -- RT5651 ALSA SoC audio driver + * + * Copyright 2011 Realtek Microelectronics + * Author: Johnny Hsu + * + * 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 __RT5651_H__ +#define __RT5651_H__ + +#include + +/* Info */ +#define RT5651_RESET 0x00 +#define RT5651_VERSION_ID 0xfd +#define RT5651_VENDOR_ID 0xfe +#define RT5651_DEVICE_ID 0xff +/* I/O - Output */ +#define RT5651_HP_VOL 0x02 +#define RT5651_LOUT_CTRL1 0x03 +#define RT5651_LOUT_CTRL2 0x05 +/* I/O - Input */ +#define RT5651_IN1_IN2 0x0d +#define RT5651_IN3 0x0e +#define RT5651_INL1_INR1_VOL 0x0f +#define RT5651_INL2_INR2_VOL 0x10 +/* I/O - ADC/DAC/DMIC */ +#define RT5651_DAC1_DIG_VOL 0x19 +#define RT5651_DAC2_DIG_VOL 0x1a +#define RT5651_DAC2_CTRL 0x1b +#define RT5651_ADC_DIG_VOL 0x1c +#define RT5651_ADC_DATA 0x1d +#define RT5651_ADC_BST_VOL 0x1e +/* Mixer - D-D */ +#define RT5651_STO1_ADC_MIXER 0x27 +#define RT5651_STO2_ADC_MIXER 0x28 +#define RT5651_AD_DA_MIXER 0x29 +#define RT5651_STO_DAC_MIXER 0x2a +#define RT5651_DD_MIXER 0x2b +#define RT5651_DIG_INF_DATA 0x2f +/* PDM */ +#define RT5651_PDM_CTL 0x30 +#define RT5651_PDM_I2C_CTL1 0x31 +#define RT5651_PDM_I2C_CTL2 0x32 +#define RT5651_PDM_I2C_DATA_W 0x33 +#define RT5651_PDM_I2C_DATA_R 0x34 +/* Mixer - ADC */ +#define RT5651_REC_L1_MIXER 0x3b +#define RT5651_REC_L2_MIXER 0x3c +#define RT5651_REC_R1_MIXER 0x3d +#define RT5651_REC_R2_MIXER 0x3e +/* Mixer - DAC */ +#define RT5651_HPO_MIXER 0x45 +#define RT5651_OUT_L1_MIXER 0x4d +#define RT5651_OUT_L2_MIXER 0x4e +#define RT5651_OUT_L3_MIXER 0x4f +#define RT5651_OUT_R1_MIXER 0x50 +#define RT5651_OUT_R2_MIXER 0x51 +#define RT5651_OUT_R3_MIXER 0x52 +#define RT5651_LOUT_MIXER 0x53 +/* Power */ +#define RT5651_PWR_DIG1 0x61 +#define RT5651_PWR_DIG2 0x62 +#define RT5651_PWR_ANLG1 0x63 +#define RT5651_PWR_ANLG2 0x64 +#define RT5651_PWR_MIXER 0x65 +#define RT5651_PWR_VOL 0x66 +/* Private Register Control */ +#define RT5651_PRIV_INDEX 0x6a +#define RT5651_PRIV_DATA 0x6c +/* Format - ADC/DAC */ +#define RT5651_I2S1_SDP 0x70 +#define RT5651_I2S2_SDP 0x71 +#define RT5651_ADDA_CLK1 0x73 +#define RT5651_ADDA_CLK2 0x74 +#define RT5651_DMIC 0x75 +/* TDM Control */ +#define RT5651_TDM_CTL_1 0x77 +#define RT5651_TDM_CTL_2 0x78 +#define RT5651_TDM_CTL_3 0x79 +/* Function - Analog */ +#define RT5651_GLB_CLK 0x80 +#define RT5651_PLL_CTRL1 0x81 +#define RT5651_PLL_CTRL2 0x82 +#define RT5651_PLL_MODE_1 0x83 +#define RT5651_PLL_MODE_2 0x84 +#define RT5651_PLL_MODE_3 0x85 +#define RT5651_PLL_MODE_4 0x86 +#define RT5651_PLL_MODE_5 0x87 +#define RT5651_PLL_MODE_6 0x89 +#define RT5651_PLL_MODE_7 0x8a +#define RT5651_DEPOP_M1 0x8e +#define RT5651_DEPOP_M2 0x8f +#define RT5651_DEPOP_M3 0x90 +#define RT5651_CHARGE_PUMP 0x91 +#define RT5651_MICBIAS 0x93 +#define RT5651_A_JD_CTL1 0x94 +/* Function - Digital */ +#define RT5651_EQ_CTRL1 0xb0 +#define RT5651_EQ_CTRL2 0xb1 +#define RT5651_ALC_1 0xb4 +#define RT5651_ALC_2 0xb5 +#define RT5651_ALC_3 0xb6 +#define RT5651_JD_CTRL1 0xbb +#define RT5651_JD_CTRL2 0xbc +#define RT5651_IRQ_CTRL1 0xbd +#define RT5651_IRQ_CTRL2 0xbe +#define RT5651_INT_IRQ_ST 0xbf +#define RT5651_GPIO_CTRL1 0xc0 +#define RT5651_GPIO_CTRL2 0xc1 +#define RT5651_GPIO_CTRL3 0xc2 +#define RT5651_PGM_REG_ARR1 0xc8 +#define RT5651_PGM_REG_ARR2 0xc9 +#define RT5651_PGM_REG_ARR3 0xca +#define RT5651_PGM_REG_ARR4 0xcb +#define RT5651_PGM_REG_ARR5 0xcc +#define RT5651_SCB_FUNC 0xcd +#define RT5651_SCB_CTRL 0xce +#define RT5651_BASE_BACK 0xcf +#define RT5651_MP3_PLUS1 0xd0 +#define RT5651_MP3_PLUS2 0xd1 +#define RT5651_ADJ_HPF_CTRL1 0xd3 +#define RT5651_ADJ_HPF_CTRL2 0xd4 +#define RT5651_HP_CALIB_AMP_DET 0xd6 +#define RT5651_HP_CALIB2 0xd7 +#define RT5651_SV_ZCD1 0xd9 +#define RT5651_SV_ZCD2 0xda +#define RT5651_D_MISC 0xfa +/* Dummy Register */ +#define RT5651_DUMMY2 0xfb +#define RT5651_DUMMY3 0xfc + + +/* Index of Codec Private Register definition */ +#define RT5651_BIAS_CUR1 0x12 +#define RT5651_BIAS_CUR3 0x14 +#define RT5651_CLSD_INT_REG1 0x1c +#define RT5651_CHPUMP_INT_REG1 0x24 +#define RT5651_MAMP_INT_REG2 0x37 +#define RT5651_CHOP_DAC_ADC 0x3d +#define RT5651_3D_SPK 0x63 +#define RT5651_WND_1 0x6c +#define RT5651_WND_2 0x6d +#define RT5651_WND_3 0x6e +#define RT5651_WND_4 0x6f +#define RT5651_WND_5 0x70 +#define RT5651_WND_8 0x73 +#define RT5651_DIP_SPK_INF 0x75 +#define RT5651_HP_DCC_INT1 0x77 +#define RT5651_EQ_BW_LOP 0xa0 +#define RT5651_EQ_GN_LOP 0xa1 +#define RT5651_EQ_FC_BP1 0xa2 +#define RT5651_EQ_BW_BP1 0xa3 +#define RT5651_EQ_GN_BP1 0xa4 +#define RT5651_EQ_FC_BP2 0xa5 +#define RT5651_EQ_BW_BP2 0xa6 +#define RT5651_EQ_GN_BP2 0xa7 +#define RT5651_EQ_FC_BP3 0xa8 +#define RT5651_EQ_BW_BP3 0xa9 +#define RT5651_EQ_GN_BP3 0xaa +#define RT5651_EQ_FC_BP4 0xab +#define RT5651_EQ_BW_BP4 0xac +#define RT5651_EQ_GN_BP4 0xad +#define RT5651_EQ_FC_HIP1 0xae +#define RT5651_EQ_GN_HIP1 0xaf +#define RT5651_EQ_FC_HIP2 0xb0 +#define RT5651_EQ_BW_HIP2 0xb1 +#define RT5651_EQ_GN_HIP2 0xb2 +#define RT5651_EQ_PRE_VOL 0xb3 +#define RT5651_EQ_PST_VOL 0xb4 + + +/* global definition */ +#define RT5651_L_MUTE (0x1 << 15) +#define RT5651_L_MUTE_SFT 15 +#define RT5651_VOL_L_MUTE (0x1 << 14) +#define RT5651_VOL_L_SFT 14 +#define RT5651_R_MUTE (0x1 << 7) +#define RT5651_R_MUTE_SFT 7 +#define RT5651_VOL_R_MUTE (0x1 << 6) +#define RT5651_VOL_R_SFT 6 +#define RT5651_L_VOL_MASK (0x3f << 8) +#define RT5651_L_VOL_SFT 8 +#define RT5651_R_VOL_MASK (0x3f) +#define RT5651_R_VOL_SFT 0 + +/* LOUT Control 2(0x05) */ +#define RT5651_EN_DFO (0x1 << 15) + +/* IN1 and IN2 Control (0x0d) */ +/* IN3 and IN4 Control (0x0e) */ +#define RT5651_BST_MASK1 (0xf<<12) +#define RT5651_BST_SFT1 12 +#define RT5651_BST_MASK2 (0xf<<8) +#define RT5651_BST_SFT2 8 +#define RT5651_IN_DF1 (0x1 << 7) +#define RT5651_IN_SFT1 7 +#define RT5651_IN_DF2 (0x1 << 6) +#define RT5651_IN_SFT2 6 + +/* INL1 and INR1 Volume Control (0x0f) */ +/* INL2 and INR2 Volume Control (0x10) */ +#define RT5651_INL_SEL_MASK (0x1 << 15) +#define RT5651_INL_SEL_SFT 15 +#define RT5651_INL_SEL_IN4P (0x0 << 15) +#define RT5651_INL_SEL_MONOP (0x1 << 15) +#define RT5651_INL_VOL_MASK (0x1f << 8) +#define RT5651_INL_VOL_SFT 8 +#define RT5651_INR_SEL_MASK (0x1 << 7) +#define RT5651_INR_SEL_SFT 7 +#define RT5651_INR_SEL_IN4N (0x0 << 7) +#define RT5651_INR_SEL_MONON (0x1 << 7) +#define RT5651_INR_VOL_MASK (0x1f) +#define RT5651_INR_VOL_SFT 0 + +/* DAC1 Digital Volume (0x19) */ +#define RT5651_DAC_L1_VOL_MASK (0xff << 8) +#define RT5651_DAC_L1_VOL_SFT 8 +#define RT5651_DAC_R1_VOL_MASK (0xff) +#define RT5651_DAC_R1_VOL_SFT 0 + +/* DAC2 Digital Volume (0x1a) */ +#define RT5651_DAC_L2_VOL_MASK (0xff << 8) +#define RT5651_DAC_L2_VOL_SFT 8 +#define RT5651_DAC_R2_VOL_MASK (0xff) +#define RT5651_DAC_R2_VOL_SFT 0 + +/* DAC2 Control (0x1b) */ +#define RT5651_M_DAC_L2_VOL (0x1 << 13) +#define RT5651_M_DAC_L2_VOL_SFT 13 +#define RT5651_M_DAC_R2_VOL (0x1 << 12) +#define RT5651_M_DAC_R2_VOL_SFT 12 +#define RT5651_SEL_DAC_L2 (0x1 << 11) +#define RT5651_IF2_DAC_L2 (0x1 << 11) +#define RT5651_IF1_DAC_L2 (0x0 << 11) +#define RT5651_SEL_DAC_L2_SFT 11 +#define RT5651_SEL_DAC_R2 (0x1 << 10) +#define RT5651_IF2_DAC_R2 (0x1 << 11) +#define RT5651_IF1_DAC_R2 (0x0 << 11) +#define RT5651_SEL_DAC_R2_SFT 10 + +/* ADC Digital Volume Control (0x1c) */ +#define RT5651_ADC_L_VOL_MASK (0x7f << 8) +#define RT5651_ADC_L_VOL_SFT 8 +#define RT5651_ADC_R_VOL_MASK (0x7f) +#define RT5651_ADC_R_VOL_SFT 0 + +/* Mono ADC Digital Volume Control (0x1d) */ +#define RT5651_M_MONO_ADC_L (0x1 << 15) +#define RT5651_M_MONO_ADC_L_SFT 15 +#define RT5651_MONO_ADC_L_VOL_MASK (0x7f << 8) +#define RT5651_MONO_ADC_L_VOL_SFT 8 +#define RT5651_M_MONO_ADC_R (0x1 << 7) +#define RT5651_M_MONO_ADC_R_SFT 7 +#define RT5651_MONO_ADC_R_VOL_MASK (0x7f) +#define RT5651_MONO_ADC_R_VOL_SFT 0 + +/* ADC Boost Volume Control (0x1e) */ +#define RT5651_ADC_L_BST_MASK (0x3 << 14) +#define RT5651_ADC_L_BST_SFT 14 +#define RT5651_ADC_R_BST_MASK (0x3 << 12) +#define RT5651_ADC_R_BST_SFT 12 +#define RT5651_ADC_COMP_MASK (0x3 << 10) +#define RT5651_ADC_COMP_SFT 10 + +/* Stereo ADC1 Mixer Control (0x27) */ +#define RT5651_M_STO1_ADC_L1 (0x1 << 14) +#define RT5651_M_STO1_ADC_L1_SFT 14 +#define RT5651_M_STO1_ADC_L2 (0x1 << 13) +#define RT5651_M_STO1_ADC_L2_SFT 13 +#define RT5651_STO1_ADC_1_SRC_MASK (0x1 << 12) +#define RT5651_STO1_ADC_1_SRC_SFT 12 +#define RT5651_STO1_ADC_1_SRC_ADC (0x1 << 12) +#define RT5651_STO1_ADC_1_SRC_DACMIX (0x0 << 12) +#define RT5651_STO1_ADC_2_SRC_MASK (0x1 << 11) +#define RT5651_STO1_ADC_2_SRC_SFT 11 +#define RT5651_STO1_ADC_2_SRC_DMIC (0x0 << 11) +#define RT5651_STO1_ADC_2_SRC_DACMIXR (0x1 << 11) +#define RT5651_M_STO1_ADC_R1 (0x1 << 6) +#define RT5651_M_STO1_ADC_R1_SFT 6 +#define RT5651_M_STO1_ADC_R2 (0x1 << 5) +#define RT5651_M_STO1_ADC_R2_SFT 5 + +/* Stereo ADC2 Mixer Control (0x28) */ +#define RT5651_M_STO2_ADC_L1 (0x1 << 14) +#define RT5651_M_STO2_ADC_L1_SFT 14 +#define RT5651_M_STO2_ADC_L2 (0x1 << 13) +#define RT5651_M_STO2_ADC_L2_SFT 13 +#define RT5651_STO2_ADC_L1_SRC_MASK (0x1 << 12) +#define RT5651_STO2_ADC_L1_SRC_SFT 12 +#define RT5651_STO2_ADC_L1_SRC_DACMIXL (0x0 << 12) +#define RT5651_STO2_ADC_L1_SRC_ADCL (0x1 << 12) +#define RT5651_STO2_ADC_L2_SRC_MASK (0x1 << 11) +#define RT5651_STO2_ADC_L2_SRC_SFT 11 +#define RT5651_STO2_ADC_L2_SRC_DMIC (0x0 << 11) +#define RT5651_STO2_ADC_L2_SRC_DACMIXR (0x1 << 11) +#define RT5651_M_STO2_ADC_R1 (0x1 << 6) +#define RT5651_M_STO2_ADC_R1_SFT 6 +#define RT5651_M_STO2_ADC_R2 (0x1 << 5) +#define RT5651_M_STO2_ADC_R2_SFT 5 +#define RT5651_STO2_ADC_R1_SRC_MASK (0x1 << 4) +#define RT5651_STO2_ADC_R1_SRC_SFT 4 +#define RT5651_STO2_ADC_R1_SRC_ADCR (0x1 << 4) +#define RT5651_STO2_ADC_R1_SRC_DACMIXR (0x0 << 4) +#define RT5651_STO2_ADC_R2_SRC_MASK (0x1 << 3) +#define RT5651_STO2_ADC_R2_SRC_SFT 3 +#define RT5651_STO2_ADC_R2_SRC_DMIC (0x0 << 3) +#define RT5651_STO2_ADC_R2_SRC_DACMIXR (0x1 << 3) + +/* ADC Mixer to DAC Mixer Control (0x29) */ +#define RT5651_M_ADCMIX_L (0x1 << 15) +#define RT5651_M_ADCMIX_L_SFT 15 +#define RT5651_M_IF1_DAC_L (0x1 << 14) +#define RT5651_M_IF1_DAC_L_SFT 14 +#define RT5651_M_ADCMIX_R (0x1 << 7) +#define RT5651_M_ADCMIX_R_SFT 7 +#define RT5651_M_IF1_DAC_R (0x1 << 6) +#define RT5651_M_IF1_DAC_R_SFT 6 + +/* Stereo DAC Mixer Control (0x2a) */ +#define RT5651_M_DAC_L1_MIXL (0x1 << 14) +#define RT5651_M_DAC_L1_MIXL_SFT 14 +#define RT5651_DAC_L1_STO_L_VOL_MASK (0x1 << 13) +#define RT5651_DAC_L1_STO_L_VOL_SFT 13 +#define RT5651_M_DAC_L2_MIXL (0x1 << 12) +#define RT5651_M_DAC_L2_MIXL_SFT 12 +#define RT5651_DAC_L2_STO_L_VOL_MASK (0x1 << 11) +#define RT5651_DAC_L2_STO_L_VOL_SFT 11 +#define RT5651_M_DAC_R1_MIXL (0x1 << 9) +#define RT5651_M_DAC_R1_MIXL_SFT 9 +#define RT5651_DAC_R1_STO_L_VOL_MASK (0x1 << 8) +#define RT5651_DAC_R1_STO_L_VOL_SFT 8 +#define RT5651_M_DAC_R1_MIXR (0x1 << 6) +#define RT5651_M_DAC_R1_MIXR_SFT 6 +#define RT5651_DAC_R1_STO_R_VOL_MASK (0x1 << 5) +#define RT5651_DAC_R1_STO_R_VOL_SFT 5 +#define RT5651_M_DAC_R2_MIXR (0x1 << 4) +#define RT5651_M_DAC_R2_MIXR_SFT 4 +#define RT5651_DAC_R2_STO_R_VOL_MASK (0x1 << 3) +#define RT5651_DAC_R2_STO_R_VOL_SFT 3 +#define RT5651_M_DAC_L1_MIXR (0x1 << 1) +#define RT5651_M_DAC_L1_MIXR_SFT 1 +#define RT5651_DAC_L1_STO_R_VOL_MASK (0x1) +#define RT5651_DAC_L1_STO_R_VOL_SFT 0 + +/* DD Mixer Control (0x2b) */ +#define RT5651_M_STO_DD_L1 (0x1 << 14) +#define RT5651_M_STO_DD_L1_SFT 14 +#define RT5651_STO_DD_L1_VOL_MASK (0x1 << 13) +#define RT5651_DAC_DD_L1_VOL_SFT 13 +#define RT5651_M_STO_DD_L2 (0x1 << 12) +#define RT5651_M_STO_DD_L2_SFT 12 +#define RT5651_STO_DD_L2_VOL_MASK (0x1 << 11) +#define RT5651_STO_DD_L2_VOL_SFT 11 +#define RT5651_M_STO_DD_R2_L (0x1 << 10) +#define RT5651_M_STO_DD_R2_L_SFT 10 +#define RT5651_STO_DD_R2_L_VOL_MASK (0x1 << 9) +#define RT5651_STO_DD_R2_L_VOL_SFT 9 +#define RT5651_M_STO_DD_R1 (0x1 << 6) +#define RT5651_M_STO_DD_R1_SFT 6 +#define RT5651_STO_DD_R1_VOL_MASK (0x1 << 5) +#define RT5651_STO_DD_R1_VOL_SFT 5 +#define RT5651_M_STO_DD_R2 (0x1 << 4) +#define RT5651_M_STO_DD_R2_SFT 4 +#define RT5651_STO_DD_R2_VOL_MASK (0x1 << 3) +#define RT5651_STO_DD_R2_VOL_SFT 3 +#define RT5651_M_STO_DD_L2_R (0x1 << 2) +#define RT5651_M_STO_DD_L2_R_SFT 2 +#define RT5651_STO_DD_L2_R_VOL_MASK (0x1 << 1) +#define RT5651_STO_DD_L2_R_VOL_SFT 1 + +/* Digital Mixer Control (0x2c) */ +#define RT5651_M_STO_L_DAC_L (0x1 << 15) +#define RT5651_M_STO_L_DAC_L_SFT 15 +#define RT5651_STO_L_DAC_L_VOL_MASK (0x1 << 14) +#define RT5651_STO_L_DAC_L_VOL_SFT 14 +#define RT5651_M_DAC_L2_DAC_L (0x1 << 13) +#define RT5651_M_DAC_L2_DAC_L_SFT 13 +#define RT5651_DAC_L2_DAC_L_VOL_MASK (0x1 << 12) +#define RT5651_DAC_L2_DAC_L_VOL_SFT 12 +#define RT5651_M_STO_R_DAC_R (0x1 << 11) +#define RT5651_M_STO_R_DAC_R_SFT 11 +#define RT5651_STO_R_DAC_R_VOL_MASK (0x1 << 10) +#define RT5651_STO_R_DAC_R_VOL_SFT 10 +#define RT5651_M_DAC_R2_DAC_R (0x1 << 9) +#define RT5651_M_DAC_R2_DAC_R_SFT 9 +#define RT5651_DAC_R2_DAC_R_VOL_MASK (0x1 << 8) +#define RT5651_DAC_R2_DAC_R_VOL_SFT 8 + +/* DSP Path Control 1 (0x2d) */ +#define RT5651_RXDP_SRC_MASK (0x1 << 15) +#define RT5651_RXDP_SRC_SFT 15 +#define RT5651_RXDP_SRC_NOR (0x0 << 15) +#define RT5651_RXDP_SRC_DIV3 (0x1 << 15) +#define RT5651_TXDP_SRC_MASK (0x1 << 14) +#define RT5651_TXDP_SRC_SFT 14 +#define RT5651_TXDP_SRC_NOR (0x0 << 14) +#define RT5651_TXDP_SRC_DIV3 (0x1 << 14) + +/* DSP Path Control 2 (0x2e) */ +#define RT5651_DAC_L2_SEL_MASK (0x3 << 14) +#define RT5651_DAC_L2_SEL_SFT 14 +#define RT5651_DAC_L2_SEL_IF2 (0x0 << 14) +#define RT5651_DAC_L2_SEL_IF3 (0x1 << 14) +#define RT5651_DAC_L2_SEL_TXDC (0x2 << 14) +#define RT5651_DAC_L2_SEL_BASS (0x3 << 14) +#define RT5651_DAC_R2_SEL_MASK (0x3 << 12) +#define RT5651_DAC_R2_SEL_SFT 12 +#define RT5651_DAC_R2_SEL_IF2 (0x0 << 12) +#define RT5651_DAC_R2_SEL_IF3 (0x1 << 12) +#define RT5651_DAC_R2_SEL_TXDC (0x2 << 12) +#define RT5651_IF2_ADC_L_SEL_MASK (0x1 << 11) +#define RT5651_IF2_ADC_L_SEL_SFT 11 +#define RT5651_IF2_ADC_L_SEL_TXDP (0x0 << 11) +#define RT5651_IF2_ADC_L_SEL_PASS (0x1 << 11) +#define RT5651_IF2_ADC_R_SEL_MASK (0x1 << 10) +#define RT5651_IF2_ADC_R_SEL_SFT 10 +#define RT5651_IF2_ADC_R_SEL_TXDP (0x0 << 10) +#define RT5651_IF2_ADC_R_SEL_PASS (0x1 << 10) +#define RT5651_RXDC_SEL_MASK (0x3 << 8) +#define RT5651_RXDC_SEL_SFT 8 +#define RT5651_RXDC_SEL_NOR (0x0 << 8) +#define RT5651_RXDC_SEL_L2R (0x1 << 8) +#define RT5651_RXDC_SEL_R2L (0x2 << 8) +#define RT5651_RXDC_SEL_SWAP (0x3 << 8) +#define RT5651_RXDP_SEL_MASK (0x3 << 6) +#define RT5651_RXDP_SEL_SFT 6 +#define RT5651_RXDP_SEL_NOR (0x0 << 6) +#define RT5651_RXDP_SEL_L2R (0x1 << 6) +#define RT5651_RXDP_SEL_R2L (0x2 << 6) +#define RT5651_RXDP_SEL_SWAP (0x3 << 6) +#define RT5651_TXDC_SEL_MASK (0x3 << 4) +#define RT5651_TXDC_SEL_SFT 4 +#define RT5651_TXDC_SEL_NOR (0x0 << 4) +#define RT5651_TXDC_SEL_L2R (0x1 << 4) +#define RT5651_TXDC_SEL_R2L (0x2 << 4) +#define RT5651_TXDC_SEL_SWAP (0x3 << 4) +#define RT5651_TXDP_SEL_MASK (0x3 << 2) +#define RT5651_TXDP_SEL_SFT 2 +#define RT5651_TXDP_SEL_NOR (0x0 << 2) +#define RT5651_TXDP_SEL_L2R (0x1 << 2) +#define RT5651_TXDP_SEL_R2L (0x2 << 2) +#define RT5651_TRXDP_SEL_SWAP (0x3 << 2) + +/* Digital Interface Data Control (0x2f) */ +#define RT5651_IF2_DAC_SEL_MASK (0x3 << 10) +#define RT5651_IF2_DAC_SEL_SFT 10 +#define RT5651_IF2_DAC_SEL_NOR (0x0 << 10) +#define RT5651_IF2_DAC_SEL_SWAP (0x1 << 10) +#define RT5651_IF2_DAC_SEL_L2R (0x2 << 10) +#define RT5651_IF2_DAC_SEL_R2L (0x3 << 10) +#define RT5651_IF2_ADC_SEL_MASK (0x3 << 8) +#define RT5651_IF2_ADC_SEL_SFT 8 +#define RT5651_IF2_ADC_SEL_NOR (0x0 << 8) +#define RT5651_IF2_ADC_SEL_SWAP (0x1 << 8) +#define RT5651_IF2_ADC_SEL_L2R (0x2 << 8) +#define RT5651_IF2_ADC_SEL_R2L (0x3 << 8) +#define RT5651_IF2_ADC_SRC_MASK (0x1 << 7) +#define RT5651_IF2_ADC_SRC_SFT 7 +#define RT5651_IF1_ADC1 (0x0 << 7) +#define RT5651_IF1_ADC2 (0x1 << 7) + +/* PDM Output Control (0x30) */ +#define RT5651_PDM_L_SEL_MASK (0x1 << 15) +#define RT5651_PDM_L_SEL_SFT 15 +#define RT5651_PDM_L_SEL_DD_L (0x0 << 15) +#define RT5651_PDM_L_SEL_STO_L (0x1 << 15) +#define RT5651_M_PDM_L (0x1 << 14) +#define RT5651_M_PDM_L_SFT 14 +#define RT5651_PDM_R_SEL_MASK (0x1 << 13) +#define RT5651_PDM_R_SEL_SFT 13 +#define RT5651_PDM_R_SEL_DD_L (0x0 << 13) +#define RT5651_PDM_R_SEL_STO_L (0x1 << 13) +#define RT5651_M_PDM_R (0x1 << 12) +#define RT5651_M_PDM_R_SFT 12 +#define RT5651_PDM_BUSY (0x1 << 6) +#define RT5651_PDM_BUSY_SFT 6 +#define RT5651_PDM_PATTERN_SEL_MASK (0x1 << 5) +#define RT5651_PDM_PATTERN_SEL_64 (0x0 << 5) +#define RT5651_PDM_PATTERN_SEL_128 (0x1 << 5) +#define RT5651_PDM_VOL_MASK (0x1 << 4) +#define RT5651_PDM_VOL_SFT 4 +#define RT5651_PDM_DIV_MASK (0x3) +#define RT5651_PDM_DIV_SFT 0 +#define RT5651_PDM_DIV_1 0 +#define RT5651_PDM_DIV_2 1 +#define RT5651_PDM_DIV_3 2 +#define RT5651_PDM_DIV_4 3 + +/* PDM I2C/Data Control 1 (0x31) */ +#define RT5651_PDM_I2C_ID_MASK (0xf << 12) +#define PT5631_PDM_CMD_EXE (0x1 << 11) +#define RT5651_PDM_I2C_CMD_MASK (0x1 << 10) +#define RT5651_PDM_I2C_CMD_R (0x0 << 10) +#define RT5651_PDM_I2C_CMD_W (0x1 << 10) +#define RT5651_PDM_I2C_CMD_EXE (0x1 << 9) +#define RT5651_PDM_I2C_NORMAL (0x0 << 8) +#define RT5651_PDM_I2C_BUSY (0x1 << 8) + +/* PDM I2C/Data Control 2 (0x32) */ +#define RT5651_PDM_I2C_ADDR (0xff << 8) +#define RT5651_PDM_I2C_CMD_PATTERN (0xff) + + +/* REC Left Mixer Control 1 (0x3b) */ +#define RT5651_G_LN_L2_RM_L_MASK (0x7 << 13) +#define RT5651_G_IN_L2_RM_L_SFT 13 +#define RT5651_G_LN_L1_RM_L_MASK (0x7 << 10) +#define RT5651_G_IN_L1_RM_L_SFT 10 +#define RT5651_G_BST3_RM_L_MASK (0x7 << 4) +#define RT5651_G_BST3_RM_L_SFT 4 +#define RT5651_G_BST2_RM_L_MASK (0x7 << 1) +#define RT5651_G_BST2_RM_L_SFT 1 + +/* REC Left Mixer Control 2 (0x3c) */ +#define RT5651_G_BST1_RM_L_MASK (0x7 << 13) +#define RT5651_G_BST1_RM_L_SFT 13 +#define RT5651_G_OM_L_RM_L_MASK (0x7 << 10) +#define RT5651_G_OM_L_RM_L_SFT 10 +#define RT5651_M_IN2_L_RM_L (0x1 << 6) +#define RT5651_M_IN2_L_RM_L_SFT 6 +#define RT5651_M_IN1_L_RM_L (0x1 << 5) +#define RT5651_M_IN1_L_RM_L_SFT 5 +#define RT5651_M_BST3_RM_L (0x1 << 3) +#define RT5651_M_BST3_RM_L_SFT 3 +#define RT5651_M_BST2_RM_L (0x1 << 2) +#define RT5651_M_BST2_RM_L_SFT 2 +#define RT5651_M_BST1_RM_L (0x1 << 1) +#define RT5651_M_BST1_RM_L_SFT 1 +#define RT5651_M_OM_L_RM_L (0x1) +#define RT5651_M_OM_L_RM_L_SFT 0 + +/* REC Right Mixer Control 1 (0x3d) */ +#define RT5651_G_IN2_R_RM_R_MASK (0x7 << 13) +#define RT5651_G_IN2_R_RM_R_SFT 13 +#define RT5651_G_IN1_R_RM_R_MASK (0x7 << 10) +#define RT5651_G_IN1_R_RM_R_SFT 10 +#define RT5651_G_BST3_RM_R_MASK (0x7 << 4) +#define RT5651_G_BST3_RM_R_SFT 4 +#define RT5651_G_BST2_RM_R_MASK (0x7 << 1) +#define RT5651_G_BST2_RM_R_SFT 1 + +/* REC Right Mixer Control 2 (0x3e) */ +#define RT5651_G_BST1_RM_R_MASK (0x7 << 13) +#define RT5651_G_BST1_RM_R_SFT 13 +#define RT5651_G_OM_R_RM_R_MASK (0x7 << 10) +#define RT5651_G_OM_R_RM_R_SFT 10 +#define RT5651_M_IN2_R_RM_R (0x1 << 6) +#define RT5651_M_IN2_R_RM_R_SFT 6 +#define RT5651_M_IN1_R_RM_R (0x1 << 5) +#define RT5651_M_IN1_R_RM_R_SFT 5 +#define RT5651_M_BST3_RM_R (0x1 << 3) +#define RT5651_M_BST3_RM_R_SFT 3 +#define RT5651_M_BST2_RM_R (0x1 << 2) +#define RT5651_M_BST2_RM_R_SFT 2 +#define RT5651_M_BST1_RM_R (0x1 << 1) +#define RT5651_M_BST1_RM_R_SFT 1 +#define RT5651_M_OM_R_RM_R (0x1) +#define RT5651_M_OM_R_RM_R_SFT 0 + +/* HPMIX Control (0x45) */ +#define RT5651_M_DAC1_HM (0x1 << 14) +#define RT5651_M_DAC1_HM_SFT 14 +#define RT5651_M_HPVOL_HM (0x1 << 13) +#define RT5651_M_HPVOL_HM_SFT 13 +#define RT5651_G_HPOMIX_MASK (0x1 << 12) +#define RT5651_G_HPOMIX_SFT 12 + +/* SPK Left Mixer Control (0x46) */ +#define RT5651_G_RM_L_SM_L_MASK (0x3 << 14) +#define RT5651_G_RM_L_SM_L_SFT 14 +#define RT5651_G_IN_L_SM_L_MASK (0x3 << 12) +#define RT5651_G_IN_L_SM_L_SFT 12 +#define RT5651_G_DAC_L1_SM_L_MASK (0x3 << 10) +#define RT5651_G_DAC_L1_SM_L_SFT 10 +#define RT5651_G_DAC_L2_SM_L_MASK (0x3 << 8) +#define RT5651_G_DAC_L2_SM_L_SFT 8 +#define RT5651_G_OM_L_SM_L_MASK (0x3 << 6) +#define RT5651_G_OM_L_SM_L_SFT 6 +#define RT5651_M_RM_L_SM_L (0x1 << 5) +#define RT5651_M_RM_L_SM_L_SFT 5 +#define RT5651_M_IN_L_SM_L (0x1 << 4) +#define RT5651_M_IN_L_SM_L_SFT 4 +#define RT5651_M_DAC_L1_SM_L (0x1 << 3) +#define RT5651_M_DAC_L1_SM_L_SFT 3 +#define RT5651_M_DAC_L2_SM_L (0x1 << 2) +#define RT5651_M_DAC_L2_SM_L_SFT 2 +#define RT5651_M_OM_L_SM_L (0x1 << 1) +#define RT5651_M_OM_L_SM_L_SFT 1 + +/* SPK Right Mixer Control (0x47) */ +#define RT5651_G_RM_R_SM_R_MASK (0x3 << 14) +#define RT5651_G_RM_R_SM_R_SFT 14 +#define RT5651_G_IN_R_SM_R_MASK (0x3 << 12) +#define RT5651_G_IN_R_SM_R_SFT 12 +#define RT5651_G_DAC_R1_SM_R_MASK (0x3 << 10) +#define RT5651_G_DAC_R1_SM_R_SFT 10 +#define RT5651_G_DAC_R2_SM_R_MASK (0x3 << 8) +#define RT5651_G_DAC_R2_SM_R_SFT 8 +#define RT5651_G_OM_R_SM_R_MASK (0x3 << 6) +#define RT5651_G_OM_R_SM_R_SFT 6 +#define RT5651_M_RM_R_SM_R (0x1 << 5) +#define RT5651_M_RM_R_SM_R_SFT 5 +#define RT5651_M_IN_R_SM_R (0x1 << 4) +#define RT5651_M_IN_R_SM_R_SFT 4 +#define RT5651_M_DAC_R1_SM_R (0x1 << 3) +#define RT5651_M_DAC_R1_SM_R_SFT 3 +#define RT5651_M_DAC_R2_SM_R (0x1 << 2) +#define RT5651_M_DAC_R2_SM_R_SFT 2 +#define RT5651_M_OM_R_SM_R (0x1 << 1) +#define RT5651_M_OM_R_SM_R_SFT 1 + +/* SPOLMIX Control (0x48) */ +#define RT5651_M_DAC_R1_SPM_L (0x1 << 15) +#define RT5651_M_DAC_R1_SPM_L_SFT 15 +#define RT5651_M_DAC_L1_SPM_L (0x1 << 14) +#define RT5651_M_DAC_L1_SPM_L_SFT 14 +#define RT5651_M_SV_R_SPM_L (0x1 << 13) +#define RT5651_M_SV_R_SPM_L_SFT 13 +#define RT5651_M_SV_L_SPM_L (0x1 << 12) +#define RT5651_M_SV_L_SPM_L_SFT 12 +#define RT5651_M_BST1_SPM_L (0x1 << 11) +#define RT5651_M_BST1_SPM_L_SFT 11 + +/* SPORMIX Control (0x49) */ +#define RT5651_M_DAC_R1_SPM_R (0x1 << 13) +#define RT5651_M_DAC_R1_SPM_R_SFT 13 +#define RT5651_M_SV_R_SPM_R (0x1 << 12) +#define RT5651_M_SV_R_SPM_R_SFT 12 +#define RT5651_M_BST1_SPM_R (0x1 << 11) +#define RT5651_M_BST1_SPM_R_SFT 11 + +/* SPOLMIX / SPORMIX Ratio Control (0x4a) */ +#define RT5651_SPO_CLSD_RATIO_MASK (0x7) +#define RT5651_SPO_CLSD_RATIO_SFT 0 + +/* Mono Output Mixer Control (0x4c) */ +#define RT5651_M_DAC_R2_MM (0x1 << 15) +#define RT5651_M_DAC_R2_MM_SFT 15 +#define RT5651_M_DAC_L2_MM (0x1 << 14) +#define RT5651_M_DAC_L2_MM_SFT 14 +#define RT5651_M_OV_R_MM (0x1 << 13) +#define RT5651_M_OV_R_MM_SFT 13 +#define RT5651_M_OV_L_MM (0x1 << 12) +#define RT5651_M_OV_L_MM_SFT 12 +#define RT5651_M_BST1_MM (0x1 << 11) +#define RT5651_M_BST1_MM_SFT 11 +#define RT5651_G_MONOMIX_MASK (0x1 << 10) +#define RT5651_G_MONOMIX_SFT 10 + +/* Output Left Mixer Control 1 (0x4d) */ +#define RT5651_G_BST2_OM_L_MASK (0x7 << 10) +#define RT5651_G_BST2_OM_L_SFT 10 +#define RT5651_G_BST1_OM_L_MASK (0x7 << 7) +#define RT5651_G_BST1_OM_L_SFT 7 +#define RT5651_G_IN1_L_OM_L_MASK (0x7 << 4) +#define RT5651_G_IN1_L_OM_L_SFT 4 +#define RT5651_G_RM_L_OM_L_MASK (0x7 << 1) +#define RT5651_G_RM_L_OM_L_SFT 1 + +/* Output Left Mixer Control 2 (0x4e) */ +#define RT5651_G_DAC_L1_OM_L_MASK (0x7 << 7) +#define RT5651_G_DAC_L1_OM_L_SFT 7 +#define RT5651_G_IN2_L_OM_L_MASK (0x7 << 4) +#define RT5651_G_IN2_L_OM_L_SFT 4 + +/* Output Left Mixer Control 3 (0x4f) */ +#define RT5651_M_IN2_L_OM_L (0x1 << 9) +#define RT5651_M_IN2_L_OM_L_SFT 9 +#define RT5651_M_BST2_OM_L (0x1 << 6) +#define RT5651_M_BST2_OM_L_SFT 6 +#define RT5651_M_BST1_OM_L (0x1 << 5) +#define RT5651_M_BST1_OM_L_SFT 5 +#define RT5651_M_IN1_L_OM_L (0x1 << 4) +#define RT5651_M_IN1_L_OM_L_SFT 4 +#define RT5651_M_RM_L_OM_L (0x1 << 3) +#define RT5651_M_RM_L_OM_L_SFT 3 +#define RT5651_M_DAC_L1_OM_L (0x1) +#define RT5651_M_DAC_L1_OM_L_SFT 0 + +/* Output Right Mixer Control 1 (0x50) */ +#define RT5651_G_BST2_OM_R_MASK (0x7 << 10) +#define RT5651_G_BST2_OM_R_SFT 10 +#define RT5651_G_BST1_OM_R_MASK (0x7 << 7) +#define RT5651_G_BST1_OM_R_SFT 7 +#define RT5651_G_IN1_R_OM_R_MASK (0x7 << 4) +#define RT5651_G_IN1_R_OM_R_SFT 4 +#define RT5651_G_RM_R_OM_R_MASK (0x7 << 1) +#define RT5651_G_RM_R_OM_R_SFT 1 + +/* Output Right Mixer Control 2 (0x51) */ +#define RT5651_G_DAC_R1_OM_R_MASK (0x7 << 7) +#define RT5651_G_DAC_R1_OM_R_SFT 7 +#define RT5651_G_IN2_R_OM_R_MASK (0x7 << 4) +#define RT5651_G_IN2_R_OM_R_SFT 4 + +/* Output Right Mixer Control 3 (0x52) */ +#define RT5651_M_IN2_R_OM_R (0x1 << 9) +#define RT5651_M_IN2_R_OM_R_SFT 9 +#define RT5651_M_BST2_OM_R (0x1 << 6) +#define RT5651_M_BST2_OM_R_SFT 6 +#define RT5651_M_BST1_OM_R (0x1 << 5) +#define RT5651_M_BST1_OM_R_SFT 5 +#define RT5651_M_IN1_R_OM_R (0x1 << 4) +#define RT5651_M_IN1_R_OM_R_SFT 4 +#define RT5651_M_RM_R_OM_R (0x1 << 3) +#define RT5651_M_RM_R_OM_R_SFT 3 +#define RT5651_M_DAC_R1_OM_R (0x1) +#define RT5651_M_DAC_R1_OM_R_SFT 0 + +/* LOUT Mixer Control (0x53) */ +#define RT5651_M_DAC_L1_LM (0x1 << 15) +#define RT5651_M_DAC_L1_LM_SFT 15 +#define RT5651_M_DAC_R1_LM (0x1 << 14) +#define RT5651_M_DAC_R1_LM_SFT 14 +#define RT5651_M_OV_L_LM (0x1 << 13) +#define RT5651_M_OV_L_LM_SFT 13 +#define RT5651_M_OV_R_LM (0x1 << 12) +#define RT5651_M_OV_R_LM_SFT 12 +#define RT5651_G_LOUTMIX_MASK (0x1 << 11) +#define RT5651_G_LOUTMIX_SFT 11 + +/* Power Management for Digital 1 (0x61) */ +#define RT5651_PWR_I2S1 (0x1 << 15) +#define RT5651_PWR_I2S1_BIT 15 +#define RT5651_PWR_I2S2 (0x1 << 14) +#define RT5651_PWR_I2S2_BIT 14 +#define RT5651_PWR_DAC_L1 (0x1 << 12) +#define RT5651_PWR_DAC_L1_BIT 12 +#define RT5651_PWR_DAC_R1 (0x1 << 11) +#define RT5651_PWR_DAC_R1_BIT 11 +#define RT5651_PWR_ADC_L (0x1 << 2) +#define RT5651_PWR_ADC_L_BIT 2 +#define RT5651_PWR_ADC_R (0x1 << 1) +#define RT5651_PWR_ADC_R_BIT 1 + +/* Power Management for Digital 2 (0x62) */ +#define RT5651_PWR_ADC_STO1_F (0x1 << 15) +#define RT5651_PWR_ADC_STO1_F_BIT 15 +#define RT5651_PWR_ADC_STO2_F (0x1 << 14) +#define RT5651_PWR_ADC_STO2_F_BIT 14 +#define RT5651_PWR_DAC_STO1_F (0x1 << 11) +#define RT5651_PWR_DAC_STO1_F_BIT 11 +#define RT5651_PWR_DAC_STO2_F (0x1 << 10) +#define RT5651_PWR_DAC_STO2_F_BIT 10 +#define RT5651_PWR_PDM (0x1 << 9) +#define RT5651_PWR_PDM_BIT 9 + +/* Power Management for Analog 1 (0x63) */ +#define RT5651_PWR_VREF1 (0x1 << 15) +#define RT5651_PWR_VREF1_BIT 15 +#define RT5651_PWR_FV1 (0x1 << 14) +#define RT5651_PWR_FV1_BIT 14 +#define RT5651_PWR_MB (0x1 << 13) +#define RT5651_PWR_MB_BIT 13 +#define RT5651_PWR_LM (0x1 << 12) +#define RT5651_PWR_LM_BIT 12 +#define RT5651_PWR_BG (0x1 << 11) +#define RT5651_PWR_BG_BIT 11 +#define RT5651_PWR_HP_L (0x1 << 7) +#define RT5651_PWR_HP_L_BIT 7 +#define RT5651_PWR_HP_R (0x1 << 6) +#define RT5651_PWR_HP_R_BIT 6 +#define RT5651_PWR_HA (0x1 << 5) +#define RT5651_PWR_HA_BIT 5 +#define RT5651_PWR_VREF2 (0x1 << 4) +#define RT5651_PWR_VREF2_BIT 4 +#define RT5651_PWR_FV2 (0x1 << 3) +#define RT5651_PWR_FV2_BIT 3 +#define RT5651_PWR_LDO (0x1 << 2) +#define RT5651_PWR_LDO_BIT 2 +#define RT5651_PWR_LDO_DVO_MASK (0x3) +#define RT5651_PWR_LDO_DVO_1_0V 0 +#define RT5651_PWR_LDO_DVO_1_1V 1 +#define RT5651_PWR_LDO_DVO_1_2V 2 +#define RT5651_PWR_LDO_DVO_1_3V 3 + +/* Power Management for Analog 2 (0x64) */ +#define RT5651_PWR_BST1 (0x1 << 15) +#define RT5651_PWR_BST1_BIT 15 +#define RT5651_PWR_BST2 (0x1 << 14) +#define RT5651_PWR_BST2_BIT 14 +#define RT5651_PWR_BST3 (0x1 << 13) +#define RT5651_PWR_BST3_BIT 13 +#define RT5651_PWR_MB1 (0x1 << 11) +#define RT5651_PWR_MB1_BIT 11 +#define RT5651_PWR_PLL (0x1 << 9) +#define RT5651_PWR_PLL_BIT 9 +#define RT5651_PWR_BST1_OP2 (0x1 << 5) +#define RT5651_PWR_BST1_OP2_BIT 5 +#define RT5651_PWR_BST2_OP2 (0x1 << 4) +#define RT5651_PWR_BST2_OP2_BIT 4 +#define RT5651_PWR_BST3_OP2 (0x1 << 3) +#define RT5651_PWR_BST3_OP2_BIT 3 +#define RT5651_PWR_JD_M (0x1 << 2) +#define RT5651_PWM_JD_M_BIT 2 +#define RT5651_PWR_JD2 (0x1 << 1) +#define RT5651_PWM_JD2_BIT 1 +#define RT5651_PWR_JD3 (0x1) +#define RT5651_PWM_JD3_BIT 0 + +/* Power Management for Mixer (0x65) */ +#define RT5651_PWR_OM_L (0x1 << 15) +#define RT5651_PWR_OM_L_BIT 15 +#define RT5651_PWR_OM_R (0x1 << 14) +#define RT5651_PWR_OM_R_BIT 14 +#define RT5651_PWR_RM_L (0x1 << 11) +#define RT5651_PWR_RM_L_BIT 11 +#define RT5651_PWR_RM_R (0x1 << 10) +#define RT5651_PWR_RM_R_BIT 10 + +/* Power Management for Volume (0x66) */ +#define RT5651_PWR_OV_L (0x1 << 13) +#define RT5651_PWR_OV_L_BIT 13 +#define RT5651_PWR_OV_R (0x1 << 12) +#define RT5651_PWR_OV_R_BIT 12 +#define RT5651_PWR_HV_L (0x1 << 11) +#define RT5651_PWR_HV_L_BIT 11 +#define RT5651_PWR_HV_R (0x1 << 10) +#define RT5651_PWR_HV_R_BIT 10 +#define RT5651_PWR_IN1_L (0x1 << 9) +#define RT5651_PWR_IN1_L_BIT 9 +#define RT5651_PWR_IN1_R (0x1 << 8) +#define RT5651_PWR_IN1_R_BIT 8 +#define RT5651_PWR_IN2_L (0x1 << 7) +#define RT5651_PWR_IN2_L_BIT 7 +#define RT5651_PWR_IN2_R (0x1 << 6) +#define RT5651_PWR_IN2_R_BIT 6 + +/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71) */ +#define RT5651_I2S_MS_MASK (0x1 << 15) +#define RT5651_I2S_MS_SFT 15 +#define RT5651_I2S_MS_M (0x0 << 15) +#define RT5651_I2S_MS_S (0x1 << 15) +#define RT5651_I2S_O_CP_MASK (0x3 << 10) +#define RT5651_I2S_O_CP_SFT 10 +#define RT5651_I2S_O_CP_OFF (0x0 << 10) +#define RT5651_I2S_O_CP_U_LAW (0x1 << 10) +#define RT5651_I2S_O_CP_A_LAW (0x2 << 10) +#define RT5651_I2S_I_CP_MASK (0x3 << 8) +#define RT5651_I2S_I_CP_SFT 8 +#define RT5651_I2S_I_CP_OFF (0x0 << 8) +#define RT5651_I2S_I_CP_U_LAW (0x1 << 8) +#define RT5651_I2S_I_CP_A_LAW (0x2 << 8) +#define RT5651_I2S_BP_MASK (0x1 << 7) +#define RT5651_I2S_BP_SFT 7 +#define RT5651_I2S_BP_NOR (0x0 << 7) +#define RT5651_I2S_BP_INV (0x1 << 7) +#define RT5651_I2S_DL_MASK (0x3 << 2) +#define RT5651_I2S_DL_SFT 2 +#define RT5651_I2S_DL_16 (0x0 << 2) +#define RT5651_I2S_DL_20 (0x1 << 2) +#define RT5651_I2S_DL_24 (0x2 << 2) +#define RT5651_I2S_DL_8 (0x3 << 2) +#define RT5651_I2S_DF_MASK (0x3) +#define RT5651_I2S_DF_SFT 0 +#define RT5651_I2S_DF_I2S (0x0) +#define RT5651_I2S_DF_LEFT (0x1) +#define RT5651_I2S_DF_PCM_A (0x2) +#define RT5651_I2S_DF_PCM_B (0x3) + +/* ADC/DAC Clock Control 1 (0x73) */ +#define RT5651_I2S_PD1_MASK (0x7 << 12) +#define RT5651_I2S_PD1_SFT 12 +#define RT5651_I2S_PD1_1 (0x0 << 12) +#define RT5651_I2S_PD1_2 (0x1 << 12) +#define RT5651_I2S_PD1_3 (0x2 << 12) +#define RT5651_I2S_PD1_4 (0x3 << 12) +#define RT5651_I2S_PD1_6 (0x4 << 12) +#define RT5651_I2S_PD1_8 (0x5 << 12) +#define RT5651_I2S_PD1_12 (0x6 << 12) +#define RT5651_I2S_PD1_16 (0x7 << 12) +#define RT5651_I2S_BCLK_MS2_MASK (0x1 << 11) +#define RT5651_I2S_BCLK_MS2_SFT 11 +#define RT5651_I2S_BCLK_MS2_32 (0x0 << 11) +#define RT5651_I2S_BCLK_MS2_64 (0x1 << 11) +#define RT5651_I2S_PD2_MASK (0x7 << 8) +#define RT5651_I2S_PD2_SFT 8 +#define RT5651_I2S_PD2_1 (0x0 << 8) +#define RT5651_I2S_PD2_2 (0x1 << 8) +#define RT5651_I2S_PD2_3 (0x2 << 8) +#define RT5651_I2S_PD2_4 (0x3 << 8) +#define RT5651_I2S_PD2_6 (0x4 << 8) +#define RT5651_I2S_PD2_8 (0x5 << 8) +#define RT5651_I2S_PD2_12 (0x6 << 8) +#define RT5651_I2S_PD2_16 (0x7 << 8) +#define RT5651_DAC_OSR_MASK (0x3 << 2) +#define RT5651_DAC_OSR_SFT 2 +#define RT5651_DAC_OSR_128 (0x0 << 2) +#define RT5651_DAC_OSR_64 (0x1 << 2) +#define RT5651_DAC_OSR_32 (0x2 << 2) +#define RT5651_DAC_OSR_128_3 (0x3 << 2) +#define RT5651_ADC_OSR_MASK (0x3) +#define RT5651_ADC_OSR_SFT 0 +#define RT5651_ADC_OSR_128 (0x0) +#define RT5651_ADC_OSR_64 (0x1) +#define RT5651_ADC_OSR_32 (0x2) +#define RT5651_ADC_OSR_128_3 (0x3) + +/* ADC/DAC Clock Control 2 (0x74) */ +#define RT5651_DAHPF_EN (0x1 << 11) +#define RT5651_DAHPF_EN_SFT 11 +#define RT5651_ADHPF_EN (0x1 << 10) +#define RT5651_ADHPF_EN_SFT 10 + +/* Digital Microphone Control (0x75) */ +#define RT5651_DMIC_1_EN_MASK (0x1 << 15) +#define RT5651_DMIC_1_EN_SFT 15 +#define RT5651_DMIC_1_DIS (0x0 << 15) +#define RT5651_DMIC_1_EN (0x1 << 15) +#define RT5651_DMIC_1L_LH_MASK (0x1 << 13) +#define RT5651_DMIC_1L_LH_SFT 13 +#define RT5651_DMIC_1L_LH_FALLING (0x0 << 13) +#define RT5651_DMIC_1L_LH_RISING (0x1 << 13) +#define RT5651_DMIC_1R_LH_MASK (0x1 << 12) +#define RT5651_DMIC_1R_LH_SFT 12 +#define RT5651_DMIC_1R_LH_FALLING (0x0 << 12) +#define RT5651_DMIC_1R_LH_RISING (0x1 << 12) +#define RT5651_DMIC_1_DP_MASK (0x3 << 10) +#define RT5651_DMIC_1_DP_SFT 10 +#define RT5651_DMIC_1_DP_GPIO6 (0x0 << 10) +#define RT5651_DMIC_1_DP_IN1P (0x1 << 10) +#define RT5651_DMIC_2_DP_GPIO8 (0x2 << 10) +#define RT5651_DMIC_CLK_MASK (0x7 << 5) +#define RT5651_DMIC_CLK_SFT 5 + +/* TDM Control 1 (0x77) */ +#define RT5651_TDM_INTEL_SEL_MASK (0x1 << 15) +#define RT5651_TDM_INTEL_SEL_SFT 15 +#define RT5651_TDM_INTEL_SEL_64 (0x0 << 15) +#define RT5651_TDM_INTEL_SEL_50 (0x1 << 15) +#define RT5651_TDM_MODE_SEL_MASK (0x1 << 14) +#define RT5651_TDM_MODE_SEL_SFT 14 +#define RT5651_TDM_MODE_SEL_NOR (0x0 << 14) +#define RT5651_TDM_MODE_SEL_TDM (0x1 << 14) +#define RT5651_TDM_CH_NUM_SEL_MASK (0x3 << 12) +#define RT5651_TDM_CH_NUM_SEL_SFT 12 +#define RT5651_TDM_CH_NUM_SEL_2 (0x0 << 12) +#define RT5651_TDM_CH_NUM_SEL_4 (0x1 << 12) +#define RT5651_TDM_CH_NUM_SEL_6 (0x2 << 12) +#define RT5651_TDM_CH_NUM_SEL_8 (0x3 << 12) +#define RT5651_TDM_CH_LEN_SEL_MASK (0x3 << 10) +#define RT5651_TDM_CH_LEN_SEL_SFT 10 +#define RT5651_TDM_CH_LEN_SEL_16 (0x0 << 10) +#define RT5651_TDM_CH_LEN_SEL_20 (0x1 << 10) +#define RT5651_TDM_CH_LEN_SEL_24 (0x2 << 10) +#define RT5651_TDM_CH_LEN_SEL_32 (0x3 << 10) +#define RT5651_TDM_ADC_SEL_MASK (0x1 << 9) +#define RT5651_TDM_ADC_SEL_SFT 9 +#define RT5651_TDM_ADC_SEL_NOR (0x0 << 9) +#define RT5651_TDM_ADC_SEL_SWAP (0x1 << 9) +#define RT5651_TDM_ADC_START_SEL_MASK (0x1 << 8) +#define RT5651_TDM_ADC_START_SEL_SFT 8 +#define RT5651_TDM_ADC_START_SEL_SL0 (0x0 << 8) +#define RT5651_TDM_ADC_START_SEL_SL4 (0x1 << 8) +#define RT5651_TDM_I2S_CH2_SEL_MASK (0x3 << 6) +#define RT5651_TDM_I2S_CH2_SEL_SFT 6 +#define RT5651_TDM_I2S_CH2_SEL_LR (0x0 << 6) +#define RT5651_TDM_I2S_CH2_SEL_RL (0x1 << 6) +#define RT5651_TDM_I2S_CH2_SEL_LL (0x2 << 6) +#define RT5651_TDM_I2S_CH2_SEL_RR (0x3 << 6) +#define RT5651_TDM_I2S_CH4_SEL_MASK (0x3 << 4) +#define RT5651_TDM_I2S_CH4_SEL_SFT 4 +#define RT5651_TDM_I2S_CH4_SEL_LR (0x0 << 4) +#define RT5651_TDM_I2S_CH4_SEL_RL (0x1 << 4) +#define RT5651_TDM_I2S_CH4_SEL_LL (0x2 << 4) +#define RT5651_TDM_I2S_CH4_SEL_RR (0x3 << 4) +#define RT5651_TDM_I2S_CH6_SEL_MASK (0x3 << 2) +#define RT5651_TDM_I2S_CH6_SEL_SFT 2 +#define RT5651_TDM_I2S_CH6_SEL_LR (0x0 << 2) +#define RT5651_TDM_I2S_CH6_SEL_RL (0x1 << 2) +#define RT5651_TDM_I2S_CH6_SEL_LL (0x2 << 2) +#define RT5651_TDM_I2S_CH6_SEL_RR (0x3 << 2) +#define RT5651_TDM_I2S_CH8_SEL_MASK (0x3) +#define RT5651_TDM_I2S_CH8_SEL_SFT 0 +#define RT5651_TDM_I2S_CH8_SEL_LR (0x0) +#define RT5651_TDM_I2S_CH8_SEL_RL (0x1) +#define RT5651_TDM_I2S_CH8_SEL_LL (0x2) +#define RT5651_TDM_I2S_CH8_SEL_RR (0x3) + +/* TDM Control 2 (0x78) */ +#define RT5651_TDM_LRCK_POL_SEL_MASK (0x1 << 15) +#define RT5651_TDM_LRCK_POL_SEL_SFT 15 +#define RT5651_TDM_LRCK_POL_SEL_NOR (0x0 << 15) +#define RT5651_TDM_LRCK_POL_SEL_INV (0x1 << 15) +#define RT5651_TDM_CH_VAL_SEL_MASK (0x1 << 14) +#define RT5651_TDM_CH_VAL_SEL_SFT 14 +#define RT5651_TDM_CH_VAL_SEL_CH01 (0x0 << 14) +#define RT5651_TDM_CH_VAL_SEL_CH0123 (0x1 << 14) +#define RT5651_TDM_CH_VAL_EN (0x1 << 13) +#define RT5651_TDM_CH_VAL_SFT 13 +#define RT5651_TDM_LPBK_EN (0x1 << 12) +#define RT5651_TDM_LPBK_SFT 12 +#define RT5651_TDM_LRCK_PULSE_SEL_MASK (0x1 << 11) +#define RT5651_TDM_LRCK_PULSE_SEL_SFT 11 +#define RT5651_TDM_LRCK_PULSE_SEL_BCLK (0x0 << 11) +#define RT5651_TDM_LRCK_PULSE_SEL_CH (0x1 << 11) +#define RT5651_TDM_END_EDGE_SEL_MASK (0x1 << 10) +#define RT5651_TDM_END_EDGE_SEL_SFT 10 +#define RT5651_TDM_END_EDGE_SEL_POS (0x0 << 10) +#define RT5651_TDM_END_EDGE_SEL_NEG (0x1 << 10) +#define RT5651_TDM_END_EDGE_EN (0x1 << 9) +#define RT5651_TDM_END_EDGE_EN_SFT 9 +#define RT5651_TDM_TRAN_EDGE_SEL_MASK (0x1 << 8) +#define RT5651_TDM_TRAN_EDGE_SEL_SFT 8 +#define RT5651_TDM_TRAN_EDGE_SEL_POS (0x0 << 8) +#define RT5651_TDM_TRAN_EDGE_SEL_NEG (0x1 << 8) +#define RT5651_M_TDM2_L (0x1 << 7) +#define RT5651_M_TDM2_L_SFT 7 +#define RT5651_M_TDM2_R (0x1 << 6) +#define RT5651_M_TDM2_R_SFT 6 +#define RT5651_M_TDM4_L (0x1 << 5) +#define RT5651_M_TDM4_L_SFT 5 +#define RT5651_M_TDM4_R (0x1 << 4) +#define RT5651_M_TDM4_R_SFT 4 + +/* TDM Control 3 (0x79) */ +#define RT5651_CH2_L_SEL_MASK (0x7 << 12) +#define RT5651_CH2_L_SEL_SFT 12 +#define RT5651_CH2_L_SEL_SL0 (0x0 << 12) +#define RT5651_CH2_L_SEL_SL1 (0x1 << 12) +#define RT5651_CH2_L_SEL_SL2 (0x2 << 12) +#define RT5651_CH2_L_SEL_SL3 (0x3 << 12) +#define RT5651_CH2_L_SEL_SL4 (0x4 << 12) +#define RT5651_CH2_L_SEL_SL5 (0x5 << 12) +#define RT5651_CH2_L_SEL_SL6 (0x6 << 12) +#define RT5651_CH2_L_SEL_SL7 (0x7 << 12) +#define RT5651_CH2_R_SEL_MASK (0x7 << 8) +#define RT5651_CH2_R_SEL_SFT 8 +#define RT5651_CH2_R_SEL_SL0 (0x0 << 8) +#define RT5651_CH2_R_SEL_SL1 (0x1 << 8) +#define RT5651_CH2_R_SEL_SL2 (0x2 << 8) +#define RT5651_CH2_R_SEL_SL3 (0x3 << 8) +#define RT5651_CH2_R_SEL_SL4 (0x4 << 8) +#define RT5651_CH2_R_SEL_SL5 (0x5 << 8) +#define RT5651_CH2_R_SEL_SL6 (0x6 << 8) +#define RT5651_CH2_R_SEL_SL7 (0x7 << 8) +#define RT5651_CH4_L_SEL_MASK (0x7 << 4) +#define RT5651_CH4_L_SEL_SFT 4 +#define RT5651_CH4_L_SEL_SL0 (0x0 << 4) +#define RT5651_CH4_L_SEL_SL1 (0x1 << 4) +#define RT5651_CH4_L_SEL_SL2 (0x2 << 4) +#define RT5651_CH4_L_SEL_SL3 (0x3 << 4) +#define RT5651_CH4_L_SEL_SL4 (0x4 << 4) +#define RT5651_CH4_L_SEL_SL5 (0x5 << 4) +#define RT5651_CH4_L_SEL_SL6 (0x6 << 4) +#define RT5651_CH4_L_SEL_SL7 (0x7 << 4) +#define RT5651_CH4_R_SEL_MASK (0x7) +#define RT5651_CH4_R_SEL_SFT 0 +#define RT5651_CH4_R_SEL_SL0 (0x0) +#define RT5651_CH4_R_SEL_SL1 (0x1) +#define RT5651_CH4_R_SEL_SL2 (0x2) +#define RT5651_CH4_R_SEL_SL3 (0x3) +#define RT5651_CH4_R_SEL_SL4 (0x4) +#define RT5651_CH4_R_SEL_SL5 (0x5) +#define RT5651_CH4_R_SEL_SL6 (0x6) +#define RT5651_CH4_R_SEL_SL7 (0x7) + +/* Global Clock Control (0x80) */ +#define RT5651_SCLK_SRC_MASK (0x3 << 14) +#define RT5651_SCLK_SRC_SFT 14 +#define RT5651_SCLK_SRC_MCLK (0x0 << 14) +#define RT5651_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5651_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5651_PLL1_SRC_MASK (0x3 << 12) +#define RT5651_PLL1_SRC_SFT 12 +#define RT5651_PLL1_SRC_MCLK (0x0 << 12) +#define RT5651_PLL1_SRC_BCLK1 (0x1 << 12) +#define RT5651_PLL1_SRC_BCLK2 (0x2 << 12) +#define RT5651_PLL1_PD_MASK (0x1 << 3) +#define RT5651_PLL1_PD_SFT 3 +#define RT5651_PLL1_PD_1 (0x0 << 3) +#define RT5651_PLL1_PD_2 (0x1 << 3) + +#define RT5651_PLL_INP_MAX 40000000 +#define RT5651_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x81) */ +#define RT5651_PLL_N_MAX 0x1ff +#define RT5651_PLL_N_MASK (RT5651_PLL_N_MAX << 7) +#define RT5651_PLL_N_SFT 7 +#define RT5651_PLL_K_MAX 0x1f +#define RT5651_PLL_K_MASK (RT5651_PLL_K_MAX) +#define RT5651_PLL_K_SFT 0 + +/* PLL M/N/K Code Control 2 (0x82) */ +#define RT5651_PLL_M_MAX 0xf +#define RT5651_PLL_M_MASK (RT5651_PLL_M_MAX << 12) +#define RT5651_PLL_M_SFT 12 +#define RT5651_PLL_M_BP (0x1 << 11) +#define RT5651_PLL_M_BP_SFT 11 + +/* PLL tracking mode 1 (0x83) */ +#define RT5651_STO1_T_MASK (0x1 << 15) +#define RT5651_STO1_T_SFT 15 +#define RT5651_STO1_T_SCLK (0x0 << 15) +#define RT5651_STO1_T_LRCK1 (0x1 << 15) +#define RT5651_STO2_T_MASK (0x1 << 12) +#define RT5651_STO2_T_SFT 12 +#define RT5651_STO2_T_I2S2 (0x0 << 12) +#define RT5651_STO2_T_LRCK2 (0x1 << 12) +#define RT5651_ASRC2_REF_MASK (0x1 << 11) +#define RT5651_ASRC2_REF_SFT 11 +#define RT5651_ASRC2_REF_LRCK2 (0x0 << 11) +#define RT5651_ASRC2_REF_LRCK1 (0x1 << 11) +#define RT5651_DMIC_1_M_MASK (0x1 << 9) +#define RT5651_DMIC_1_M_SFT 9 +#define RT5651_DMIC_1_M_NOR (0x0 << 9) +#define RT5651_DMIC_1_M_ASYN (0x1 << 9) + +/* PLL tracking mode 2 (0x84) */ +#define RT5651_STO1_ASRC_EN (0x1 << 15) +#define RT5651_STO1_ASRC_EN_SFT 15 +#define RT5651_STO2_ASRC_EN (0x1 << 14) +#define RT5651_STO2_ASRC_EN_SFT 14 +#define RT5651_STO1_DAC_M_MASK (0x1 << 13) +#define RT5651_STO1_DAC_M_SFT 13 +#define RT5651_STO1_DAC_M_NOR (0x0 << 13) +#define RT5651_STO1_DAC_M_ASRC (0x1 << 13) +#define RT5651_STO2_DAC_M_MASK (0x1 << 12) +#define RT5651_STO2_DAC_M_SFT 12 +#define RT5651_STO2_DAC_M_NOR (0x0 << 12) +#define RT5651_STO2_DAC_M_ASRC (0x1 << 12) +#define RT5651_ADC_M_MASK (0x1 << 11) +#define RT5651_ADC_M_SFT 11 +#define RT5651_ADC_M_NOR (0x0 << 11) +#define RT5651_ADC_M_ASRC (0x1 << 11) +#define RT5651_I2S1_R_D_MASK (0x1 << 4) +#define RT5651_I2S1_R_D_SFT 4 +#define RT5651_I2S1_R_D_DIS (0x0 << 4) +#define RT5651_I2S1_R_D_EN (0x1 << 4) +#define RT5651_I2S2_R_D_MASK (0x1 << 3) +#define RT5651_I2S2_R_D_SFT 3 +#define RT5651_I2S2_R_D_DIS (0x0 << 3) +#define RT5651_I2S2_R_D_EN (0x1 << 3) +#define RT5651_PRE_SCLK_MASK (0x3) +#define RT5651_PRE_SCLK_SFT 0 +#define RT5651_PRE_SCLK_512 (0x0) +#define RT5651_PRE_SCLK_1024 (0x1) +#define RT5651_PRE_SCLK_2048 (0x2) + +/* PLL tracking mode 3 (0x85) */ +#define RT5651_I2S1_RATE_MASK (0xf << 12) +#define RT5651_I2S1_RATE_SFT 12 +#define RT5651_I2S2_RATE_MASK (0xf << 8) +#define RT5651_I2S2_RATE_SFT 8 +#define RT5651_G_ASRC_LP_MASK (0x1 << 3) +#define RT5651_G_ASRC_LP_SFT 3 +#define RT5651_ASRC_LP_F_M (0x1 << 2) +#define RT5651_ASRC_LP_F_SFT 2 +#define RT5651_ASRC_LP_F_NOR (0x0 << 2) +#define RT5651_ASRC_LP_F_SB (0x1 << 2) +#define RT5651_FTK_PH_DET_MASK (0x3) +#define RT5651_FTK_PH_DET_SFT 0 +#define RT5651_FTK_PH_DET_DIV1 (0x0) +#define RT5651_FTK_PH_DET_DIV2 (0x1) +#define RT5651_FTK_PH_DET_DIV4 (0x2) +#define RT5651_FTK_PH_DET_DIV8 (0x3) + +/*PLL tracking mode 6 (0x89) */ +#define RT5651_I2S1_PD_MASK (0x7 << 12) +#define RT5651_I2S1_PD_SFT 12 +#define RT5651_I2S2_PD_MASK (0x7 << 8) +#define RT5651_I2S2_PD_SFT 8 + +/*PLL tracking mode 7 (0x8a) */ +#define RT5651_FSI1_RATE_MASK (0xf << 12) +#define RT5651_FSI1_RATE_SFT 12 +#define RT5651_FSI2_RATE_MASK (0xf << 8) +#define RT5651_FSI2_RATE_SFT 8 + +/* HPOUT Over Current Detection (0x8b) */ +#define RT5651_HP_OVCD_MASK (0x1 << 10) +#define RT5651_HP_OVCD_SFT 10 +#define RT5651_HP_OVCD_DIS (0x0 << 10) +#define RT5651_HP_OVCD_EN (0x1 << 10) +#define RT5651_HP_OC_TH_MASK (0x3 << 8) +#define RT5651_HP_OC_TH_SFT 8 +#define RT5651_HP_OC_TH_90 (0x0 << 8) +#define RT5651_HP_OC_TH_105 (0x1 << 8) +#define RT5651_HP_OC_TH_120 (0x2 << 8) +#define RT5651_HP_OC_TH_135 (0x3 << 8) + +/* Depop Mode Control 1 (0x8e) */ +#define RT5651_SMT_TRIG_MASK (0x1 << 15) +#define RT5651_SMT_TRIG_SFT 15 +#define RT5651_SMT_TRIG_DIS (0x0 << 15) +#define RT5651_SMT_TRIG_EN (0x1 << 15) +#define RT5651_HP_L_SMT_MASK (0x1 << 9) +#define RT5651_HP_L_SMT_SFT 9 +#define RT5651_HP_L_SMT_DIS (0x0 << 9) +#define RT5651_HP_L_SMT_EN (0x1 << 9) +#define RT5651_HP_R_SMT_MASK (0x1 << 8) +#define RT5651_HP_R_SMT_SFT 8 +#define RT5651_HP_R_SMT_DIS (0x0 << 8) +#define RT5651_HP_R_SMT_EN (0x1 << 8) +#define RT5651_HP_CD_PD_MASK (0x1 << 7) +#define RT5651_HP_CD_PD_SFT 7 +#define RT5651_HP_CD_PD_DIS (0x0 << 7) +#define RT5651_HP_CD_PD_EN (0x1 << 7) +#define RT5651_RSTN_MASK (0x1 << 6) +#define RT5651_RSTN_SFT 6 +#define RT5651_RSTN_DIS (0x0 << 6) +#define RT5651_RSTN_EN (0x1 << 6) +#define RT5651_RSTP_MASK (0x1 << 5) +#define RT5651_RSTP_SFT 5 +#define RT5651_RSTP_DIS (0x0 << 5) +#define RT5651_RSTP_EN (0x1 << 5) +#define RT5651_HP_CO_MASK (0x1 << 4) +#define RT5651_HP_CO_SFT 4 +#define RT5651_HP_CO_DIS (0x0 << 4) +#define RT5651_HP_CO_EN (0x1 << 4) +#define RT5651_HP_CP_MASK (0x1 << 3) +#define RT5651_HP_CP_SFT 3 +#define RT5651_HP_CP_PD (0x0 << 3) +#define RT5651_HP_CP_PU (0x1 << 3) +#define RT5651_HP_SG_MASK (0x1 << 2) +#define RT5651_HP_SG_SFT 2 +#define RT5651_HP_SG_DIS (0x0 << 2) +#define RT5651_HP_SG_EN (0x1 << 2) +#define RT5651_HP_DP_MASK (0x1 << 1) +#define RT5651_HP_DP_SFT 1 +#define RT5651_HP_DP_PD (0x0 << 1) +#define RT5651_HP_DP_PU (0x1 << 1) +#define RT5651_HP_CB_MASK (0x1) +#define RT5651_HP_CB_SFT 0 +#define RT5651_HP_CB_PD (0x0) +#define RT5651_HP_CB_PU (0x1) + +/* Depop Mode Control 2 (0x8f) */ +#define RT5651_DEPOP_MASK (0x1 << 13) +#define RT5651_DEPOP_SFT 13 +#define RT5651_DEPOP_AUTO (0x0 << 13) +#define RT5651_DEPOP_MAN (0x1 << 13) +#define RT5651_RAMP_MASK (0x1 << 12) +#define RT5651_RAMP_SFT 12 +#define RT5651_RAMP_DIS (0x0 << 12) +#define RT5651_RAMP_EN (0x1 << 12) +#define RT5651_BPS_MASK (0x1 << 11) +#define RT5651_BPS_SFT 11 +#define RT5651_BPS_DIS (0x0 << 11) +#define RT5651_BPS_EN (0x1 << 11) +#define RT5651_FAST_UPDN_MASK (0x1 << 10) +#define RT5651_FAST_UPDN_SFT 10 +#define RT5651_FAST_UPDN_DIS (0x0 << 10) +#define RT5651_FAST_UPDN_EN (0x1 << 10) +#define RT5651_MRES_MASK (0x3 << 8) +#define RT5651_MRES_SFT 8 +#define RT5651_MRES_15MO (0x0 << 8) +#define RT5651_MRES_25MO (0x1 << 8) +#define RT5651_MRES_35MO (0x2 << 8) +#define RT5651_MRES_45MO (0x3 << 8) +#define RT5651_VLO_MASK (0x1 << 7) +#define RT5651_VLO_SFT 7 +#define RT5651_VLO_3V (0x0 << 7) +#define RT5651_VLO_32V (0x1 << 7) +#define RT5651_DIG_DP_MASK (0x1 << 6) +#define RT5651_DIG_DP_SFT 6 +#define RT5651_DIG_DP_DIS (0x0 << 6) +#define RT5651_DIG_DP_EN (0x1 << 6) +#define RT5651_DP_TH_MASK (0x3 << 4) +#define RT5651_DP_TH_SFT 4 + +/* Depop Mode Control 3 (0x90) */ +#define RT5651_CP_SYS_MASK (0x7 << 12) +#define RT5651_CP_SYS_SFT 12 +#define RT5651_CP_FQ1_MASK (0x7 << 8) +#define RT5651_CP_FQ1_SFT 8 +#define RT5651_CP_FQ2_MASK (0x7 << 4) +#define RT5651_CP_FQ2_SFT 4 +#define RT5651_CP_FQ3_MASK (0x7) +#define RT5651_CP_FQ3_SFT 0 +#define RT5651_CP_FQ_1_5_KHZ 0 +#define RT5651_CP_FQ_3_KHZ 1 +#define RT5651_CP_FQ_6_KHZ 2 +#define RT5651_CP_FQ_12_KHZ 3 +#define RT5651_CP_FQ_24_KHZ 4 +#define RT5651_CP_FQ_48_KHZ 5 +#define RT5651_CP_FQ_96_KHZ 6 +#define RT5651_CP_FQ_192_KHZ 7 + +/* HPOUT charge pump (0x91) */ +#define RT5651_OSW_L_MASK (0x1 << 11) +#define RT5651_OSW_L_SFT 11 +#define RT5651_OSW_L_DIS (0x0 << 11) +#define RT5651_OSW_L_EN (0x1 << 11) +#define RT5651_OSW_R_MASK (0x1 << 10) +#define RT5651_OSW_R_SFT 10 +#define RT5651_OSW_R_DIS (0x0 << 10) +#define RT5651_OSW_R_EN (0x1 << 10) +#define RT5651_PM_HP_MASK (0x3 << 8) +#define RT5651_PM_HP_SFT 8 +#define RT5651_PM_HP_LV (0x0 << 8) +#define RT5651_PM_HP_MV (0x1 << 8) +#define RT5651_PM_HP_HV (0x2 << 8) +#define RT5651_IB_HP_MASK (0x3 << 6) +#define RT5651_IB_HP_SFT 6 +#define RT5651_IB_HP_125IL (0x0 << 6) +#define RT5651_IB_HP_25IL (0x1 << 6) +#define RT5651_IB_HP_5IL (0x2 << 6) +#define RT5651_IB_HP_1IL (0x3 << 6) + +/* Micbias Control (0x93) */ +#define RT5651_MIC1_BS_MASK (0x1 << 15) +#define RT5651_MIC1_BS_SFT 15 +#define RT5651_MIC1_BS_9AV (0x0 << 15) +#define RT5651_MIC1_BS_75AV (0x1 << 15) +#define RT5651_MIC1_CLK_MASK (0x1 << 13) +#define RT5651_MIC1_CLK_SFT 13 +#define RT5651_MIC1_CLK_DIS (0x0 << 13) +#define RT5651_MIC1_CLK_EN (0x1 << 13) +#define RT5651_MIC1_OVCD_MASK (0x1 << 11) +#define RT5651_MIC1_OVCD_SFT 11 +#define RT5651_MIC1_OVCD_DIS (0x0 << 11) +#define RT5651_MIC1_OVCD_EN (0x1 << 11) +#define RT5651_MIC1_OVTH_MASK (0x3 << 9) +#define RT5651_MIC1_OVTH_SFT 9 +#define RT5651_MIC1_OVTH_600UA (0x0 << 9) +#define RT5651_MIC1_OVTH_1500UA (0x1 << 9) +#define RT5651_MIC1_OVTH_2000UA (0x2 << 9) +#define RT5651_PWR_MB_MASK (0x1 << 5) +#define RT5651_PWR_MB_SFT 5 +#define RT5651_PWR_MB_PD (0x0 << 5) +#define RT5651_PWR_MB_PU (0x1 << 5) +#define RT5651_PWR_CLK12M_MASK (0x1 << 4) +#define RT5651_PWR_CLK12M_SFT 4 +#define RT5651_PWR_CLK12M_PD (0x0 << 4) +#define RT5651_PWR_CLK12M_PU (0x1 << 4) + +/* Analog JD Control 1 (0x94) */ +#define RT5651_JD2_CMP_MASK (0x7 << 12) +#define RT5651_JD2_CMP_SFT 12 +#define RT5651_JD_PU (0x1 << 11) +#define RT5651_JD_PU_SFT 11 +#define RT5651_JD_PD (0x1 << 10) +#define RT5651_JD_PD_SFT 10 +#define RT5651_JD_MODE_SEL_MASK (0x3 << 8) +#define RT5651_JD_MODE_SEL_SFT 8 +#define RT5651_JD_MODE_SEL_M0 (0x0 << 8) +#define RT5651_JD_MODE_SEL_M1 (0x1 << 8) +#define RT5651_JD_MODE_SEL_M2 (0x2 << 8) +#define RT5651_JD_M_CMP (0x7 << 4) +#define RT5651_JD_M_CMP_SFT 4 +#define RT5651_JD_M_PU (0x1 << 3) +#define RT5651_JD_M_PU_SFT 3 +#define RT5651_JD_M_PD (0x1 << 2) +#define RT5651_JD_M_PD_SFT 2 +#define RT5651_JD_M_MODE_SEL_MASK (0x3) +#define RT5651_JD_M_MODE_SEL_SFT 0 +#define RT5651_JD_M_MODE_SEL_M0 (0x0) +#define RT5651_JD_M_MODE_SEL_M1 (0x1) +#define RT5651_JD_M_MODE_SEL_M2 (0x2) + +/* Analog JD Control 2 (0x95) */ +#define RT5651_JD3_CMP_MASK (0x7 << 12) +#define RT5651_JD3_CMP_SFT 12 + +/* EQ Control 1 (0xb0) */ +#define RT5651_EQ_SRC_MASK (0x1 << 15) +#define RT5651_EQ_SRC_SFT 15 +#define RT5651_EQ_SRC_DAC (0x0 << 15) +#define RT5651_EQ_SRC_ADC (0x1 << 15) +#define RT5651_EQ_UPD (0x1 << 14) +#define RT5651_EQ_UPD_BIT 14 +#define RT5651_EQ_CD_MASK (0x1 << 13) +#define RT5651_EQ_CD_SFT 13 +#define RT5651_EQ_CD_DIS (0x0 << 13) +#define RT5651_EQ_CD_EN (0x1 << 13) +#define RT5651_EQ_DITH_MASK (0x3 << 8) +#define RT5651_EQ_DITH_SFT 8 +#define RT5651_EQ_DITH_NOR (0x0 << 8) +#define RT5651_EQ_DITH_LSB (0x1 << 8) +#define RT5651_EQ_DITH_LSB_1 (0x2 << 8) +#define RT5651_EQ_DITH_LSB_2 (0x3 << 8) +#define RT5651_EQ_CD_F (0x1 << 7) +#define RT5651_EQ_CD_F_BIT 7 +#define RT5651_EQ_STA_HP2 (0x1 << 6) +#define RT5651_EQ_STA_HP2_BIT 6 +#define RT5651_EQ_STA_HP1 (0x1 << 5) +#define RT5651_EQ_STA_HP1_BIT 5 +#define RT5651_EQ_STA_BP4 (0x1 << 4) +#define RT5651_EQ_STA_BP4_BIT 4 +#define RT5651_EQ_STA_BP3 (0x1 << 3) +#define RT5651_EQ_STA_BP3_BIT 3 +#define RT5651_EQ_STA_BP2 (0x1 << 2) +#define RT5651_EQ_STA_BP2_BIT 2 +#define RT5651_EQ_STA_BP1 (0x1 << 1) +#define RT5651_EQ_STA_BP1_BIT 1 +#define RT5651_EQ_STA_LP (0x1) +#define RT5651_EQ_STA_LP_BIT 0 + +/* EQ Control 2 (0xb1) */ +#define RT5651_EQ_HPF1_M_MASK (0x1 << 8) +#define RT5651_EQ_HPF1_M_SFT 8 +#define RT5651_EQ_HPF1_M_HI (0x0 << 8) +#define RT5651_EQ_HPF1_M_1ST (0x1 << 8) +#define RT5651_EQ_LPF1_M_MASK (0x1 << 7) +#define RT5651_EQ_LPF1_M_SFT 7 +#define RT5651_EQ_LPF1_M_LO (0x0 << 7) +#define RT5651_EQ_LPF1_M_1ST (0x1 << 7) +#define RT5651_EQ_HPF2_MASK (0x1 << 6) +#define RT5651_EQ_HPF2_SFT 6 +#define RT5651_EQ_HPF2_DIS (0x0 << 6) +#define RT5651_EQ_HPF2_EN (0x1 << 6) +#define RT5651_EQ_HPF1_MASK (0x1 << 5) +#define RT5651_EQ_HPF1_SFT 5 +#define RT5651_EQ_HPF1_DIS (0x0 << 5) +#define RT5651_EQ_HPF1_EN (0x1 << 5) +#define RT5651_EQ_BPF4_MASK (0x1 << 4) +#define RT5651_EQ_BPF4_SFT 4 +#define RT5651_EQ_BPF4_DIS (0x0 << 4) +#define RT5651_EQ_BPF4_EN (0x1 << 4) +#define RT5651_EQ_BPF3_MASK (0x1 << 3) +#define RT5651_EQ_BPF3_SFT 3 +#define RT5651_EQ_BPF3_DIS (0x0 << 3) +#define RT5651_EQ_BPF3_EN (0x1 << 3) +#define RT5651_EQ_BPF2_MASK (0x1 << 2) +#define RT5651_EQ_BPF2_SFT 2 +#define RT5651_EQ_BPF2_DIS (0x0 << 2) +#define RT5651_EQ_BPF2_EN (0x1 << 2) +#define RT5651_EQ_BPF1_MASK (0x1 << 1) +#define RT5651_EQ_BPF1_SFT 1 +#define RT5651_EQ_BPF1_DIS (0x0 << 1) +#define RT5651_EQ_BPF1_EN (0x1 << 1) +#define RT5651_EQ_LPF_MASK (0x1) +#define RT5651_EQ_LPF_SFT 0 +#define RT5651_EQ_LPF_DIS (0x0) +#define RT5651_EQ_LPF_EN (0x1) +#define RT5651_EQ_CTRL_MASK (0x7f) + +/* Memory Test (0xb2) */ +#define RT5651_MT_MASK (0x1 << 15) +#define RT5651_MT_SFT 15 +#define RT5651_MT_DIS (0x0 << 15) +#define RT5651_MT_EN (0x1 << 15) + +/* ALC Control 1 (0xb4) */ +#define RT5651_ALC_P_MASK (0x1 << 15) +#define RT5651_ALC_P_SFT 15 +#define RT5651_ALC_P_DAC (0x0 << 15) +#define RT5651_ALC_P_ADC (0x1 << 15) +#define RT5651_ALC_MASK (0x1 << 14) +#define RT5651_ALC_SFT 14 +#define RT5651_ALC_DIS (0x0 << 14) +#define RT5651_ALC_EN (0x1 << 14) +#define RT5651_ALC_UPD (0x1 << 13) +#define RT5651_ALC_UPD_BIT 13 +#define RT5651_ALC_AR_MASK (0x1f << 8) +#define RT5651_ALC_AR_SFT 8 +#define RT5651_ALC_R_MASK (0x7 << 5) +#define RT5651_ALC_R_SFT 5 +#define RT5651_ALC_R_48K (0x1 << 5) +#define RT5651_ALC_R_96K (0x2 << 5) +#define RT5651_ALC_R_192K (0x3 << 5) +#define RT5651_ALC_R_441K (0x5 << 5) +#define RT5651_ALC_R_882K (0x6 << 5) +#define RT5651_ALC_R_1764K (0x7 << 5) +#define RT5651_ALC_RC_MASK (0x1f) +#define RT5651_ALC_RC_SFT 0 + +/* ALC Control 2 (0xb5) */ +#define RT5651_ALC_POB_MASK (0x3f << 8) +#define RT5651_ALC_POB_SFT 8 +#define RT5651_ALC_DRC_MASK (0x1 << 7) +#define RT5651_ALC_DRC_SFT 7 +#define RT5651_ALC_DRC_DIS (0x0 << 7) +#define RT5651_ALC_DRC_EN (0x1 << 7) +#define RT5651_ALC_CPR_MASK (0x3 << 5) +#define RT5651_ALC_CPR_SFT 5 +#define RT5651_ALC_CPR_1_1 (0x0 << 5) +#define RT5651_ALC_CPR_1_2 (0x1 << 5) +#define RT5651_ALC_CPR_1_4 (0x2 << 5) +#define RT5651_ALC_CPR_1_8 (0x3 << 5) +#define RT5651_ALC_PRB_MASK (0x1f) +#define RT5651_ALC_PRB_SFT 0 + +/* ALC Control 3 (0xb6) */ +#define RT5651_ALC_NGB_MASK (0xf << 12) +#define RT5651_ALC_NGB_SFT 12 +#define RT5651_ALC_TAR_MASK (0x1f << 7) +#define RT5651_ALC_TAR_SFT 7 +#define RT5651_ALC_NG_MASK (0x1 << 6) +#define RT5651_ALC_NG_SFT 6 +#define RT5651_ALC_NG_DIS (0x0 << 6) +#define RT5651_ALC_NG_EN (0x1 << 6) +#define RT5651_ALC_NGH_MASK (0x1 << 5) +#define RT5651_ALC_NGH_SFT 5 +#define RT5651_ALC_NGH_DIS (0x0 << 5) +#define RT5651_ALC_NGH_EN (0x1 << 5) +#define RT5651_ALC_NGT_MASK (0x1f) +#define RT5651_ALC_NGT_SFT 0 + +/* Jack Detect Control 1 (0xbb) */ +#define RT5651_JD_MASK (0x7 << 13) +#define RT5651_JD_SFT 13 +#define RT5651_JD_DIS (0x0 << 13) +#define RT5651_JD_GPIO1 (0x1 << 13) +#define RT5651_JD_GPIO2 (0x2 << 13) +#define RT5651_JD_GPIO3 (0x3 << 13) +#define RT5651_JD_GPIO4 (0x4 << 13) +#define RT5651_JD_GPIO5 (0x5 << 13) +#define RT5651_JD_GPIO6 (0x6 << 13) +#define RT5651_JD_HP_MASK (0x1 << 11) +#define RT5651_JD_HP_SFT 11 +#define RT5651_JD_HP_DIS (0x0 << 11) +#define RT5651_JD_HP_EN (0x1 << 11) +#define RT5651_JD_HP_TRG_MASK (0x1 << 10) +#define RT5651_JD_HP_TRG_SFT 10 +#define RT5651_JD_HP_TRG_LO (0x0 << 10) +#define RT5651_JD_HP_TRG_HI (0x1 << 10) +#define RT5651_JD_SPL_MASK (0x1 << 9) +#define RT5651_JD_SPL_SFT 9 +#define RT5651_JD_SPL_DIS (0x0 << 9) +#define RT5651_JD_SPL_EN (0x1 << 9) +#define RT5651_JD_SPL_TRG_MASK (0x1 << 8) +#define RT5651_JD_SPL_TRG_SFT 8 +#define RT5651_JD_SPL_TRG_LO (0x0 << 8) +#define RT5651_JD_SPL_TRG_HI (0x1 << 8) +#define RT5651_JD_SPR_MASK (0x1 << 7) +#define RT5651_JD_SPR_SFT 7 +#define RT5651_JD_SPR_DIS (0x0 << 7) +#define RT5651_JD_SPR_EN (0x1 << 7) +#define RT5651_JD_SPR_TRG_MASK (0x1 << 6) +#define RT5651_JD_SPR_TRG_SFT 6 +#define RT5651_JD_SPR_TRG_LO (0x0 << 6) +#define RT5651_JD_SPR_TRG_HI (0x1 << 6) +#define RT5651_JD_LO_MASK (0x1 << 3) +#define RT5651_JD_LO_SFT 3 +#define RT5651_JD_LO_DIS (0x0 << 3) +#define RT5651_JD_LO_EN (0x1 << 3) +#define RT5651_JD_LO_TRG_MASK (0x1 << 2) +#define RT5651_JD_LO_TRG_SFT 2 +#define RT5651_JD_LO_TRG_LO (0x0 << 2) +#define RT5651_JD_LO_TRG_HI (0x1 << 2) + +/* Jack Detect Control 2 (0xbc) */ +#define RT5651_JD_TRG_SEL_MASK (0x7 << 9) +#define RT5651_JD_TRG_SEL_SFT 9 +#define RT5651_JD_TRG_SEL_GPIO (0x0 << 9) +#define RT5651_JD_TRG_SEL_JD1_1 (0x1 << 9) +#define RT5651_JD_TRG_SEL_JD1_2 (0x2 << 9) +#define RT5651_JD_TRG_SEL_JD2 (0x3 << 9) +#define RT5651_JD_TRG_SEL_JD3 (0x4 << 9) +#define RT5651_JD3_IRQ_EN (0x1 << 8) +#define RT5651_JD3_IRQ_EN_SFT 8 +#define RT5651_JD3_EN_STKY (0x1 << 7) +#define RT5651_JD3_EN_STKY_SFT 7 +#define RT5651_JD3_INV (0x1 << 6) +#define RT5651_JD3_INV_SFT 6 + +/* IRQ Control 1 (0xbd) */ +#define RT5651_IRQ_JD_MASK (0x1 << 15) +#define RT5651_IRQ_JD_SFT 15 +#define RT5651_IRQ_JD_BP (0x0 << 15) +#define RT5651_IRQ_JD_NOR (0x1 << 15) +#define RT5651_JD_STKY_MASK (0x1 << 13) +#define RT5651_JD_STKY_SFT 13 +#define RT5651_JD_STKY_DIS (0x0 << 13) +#define RT5651_JD_STKY_EN (0x1 << 13) +#define RT5651_JD_P_MASK (0x1 << 11) +#define RT5651_JD_P_SFT 11 +#define RT5651_JD_P_NOR (0x0 << 11) +#define RT5651_JD_P_INV (0x1 << 11) +#define RT5651_JD1_1_IRQ_EN (0x1 << 9) +#define RT5651_JD1_1_IRQ_EN_SFT 9 +#define RT5651_JD1_1_EN_STKY (0x1 << 8) +#define RT5651_JD1_1_EN_STKY_SFT 8 +#define RT5651_JD1_1_INV (0x1 << 7) +#define RT5651_JD1_1_INV_SFT 7 +#define RT5651_JD1_2_IRQ_EN (0x1 << 6) +#define RT5651_JD1_2_IRQ_EN_SFT 6 +#define RT5651_JD1_2_EN_STKY (0x1 << 5) +#define RT5651_JD1_2_EN_STKY_SFT 5 +#define RT5651_JD1_2_INV (0x1 << 4) +#define RT5651_JD1_2_INV_SFT 4 +#define RT5651_JD2_IRQ_EN (0x1 << 3) +#define RT5651_JD2_IRQ_EN_SFT 3 +#define RT5651_JD2_EN_STKY (0x1 << 2) +#define RT5651_JD2_EN_STKY_SFT 2 +#define RT5651_JD2_INV (0x1 << 1) +#define RT5651_JD2_INV_SFT 1 + +/* IRQ Control 2 (0xbe) */ +#define RT5651_IRQ_MB1_OC_MASK (0x1 << 15) +#define RT5651_IRQ_MB1_OC_SFT 15 +#define RT5651_IRQ_MB1_OC_BP (0x0 << 15) +#define RT5651_IRQ_MB1_OC_NOR (0x1 << 15) +#define RT5651_MB1_OC_STKY_MASK (0x1 << 11) +#define RT5651_MB1_OC_STKY_SFT 11 +#define RT5651_MB1_OC_STKY_DIS (0x0 << 11) +#define RT5651_MB1_OC_STKY_EN (0x1 << 11) +#define RT5651_MB1_OC_P_MASK (0x1 << 7) +#define RT5651_MB1_OC_P_SFT 7 +#define RT5651_MB1_OC_P_NOR (0x0 << 7) +#define RT5651_MB1_OC_P_INV (0x1 << 7) +#define RT5651_MB2_OC_P_MASK (0x1 << 6) +#define RT5651_MB1_OC_CLR (0x1 << 3) +#define RT5651_MB1_OC_CLR_SFT 3 +#define RT5651_STA_GPIO8 (0x1) +#define RT5651_STA_GPIO8_BIT 0 + +/* Internal Status and GPIO status (0xbf) */ +#define RT5651_STA_JD3 (0x1 << 15) +#define RT5651_STA_JD3_BIT 15 +#define RT5651_STA_JD2 (0x1 << 14) +#define RT5651_STA_JD2_BIT 14 +#define RT5651_STA_JD1_2 (0x1 << 13) +#define RT5651_STA_JD1_2_BIT 13 +#define RT5651_STA_JD1_1 (0x1 << 12) +#define RT5651_STA_JD1_1_BIT 12 +#define RT5651_STA_GP7 (0x1 << 11) +#define RT5651_STA_GP7_BIT 11 +#define RT5651_STA_GP6 (0x1 << 10) +#define RT5651_STA_GP6_BIT 10 +#define RT5651_STA_GP5 (0x1 << 9) +#define RT5651_STA_GP5_BIT 9 +#define RT5651_STA_GP1 (0x1 << 8) +#define RT5651_STA_GP1_BIT 8 +#define RT5651_STA_GP2 (0x1 << 7) +#define RT5651_STA_GP2_BIT 7 +#define RT5651_STA_GP3 (0x1 << 6) +#define RT5651_STA_GP3_BIT 6 +#define RT5651_STA_GP4 (0x1 << 5) +#define RT5651_STA_GP4_BIT 5 +#define RT5651_STA_GP_JD (0x1 << 4) +#define RT5651_STA_GP_JD_BIT 4 + +/* GPIO Control 1 (0xc0) */ +#define RT5651_GP1_PIN_MASK (0x1 << 15) +#define RT5651_GP1_PIN_SFT 15 +#define RT5651_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5651_GP1_PIN_IRQ (0x1 << 15) +#define RT5651_GP2_PIN_MASK (0x1 << 14) +#define RT5651_GP2_PIN_SFT 14 +#define RT5651_GP2_PIN_GPIO2 (0x0 << 14) +#define RT5651_GP2_PIN_DMIC1_SCL (0x1 << 14) +#define RT5651_GPIO_M_MASK (0x1 << 9) +#define RT5651_GPIO_M_SFT 9 +#define RT5651_GPIO_M_FLT (0x0 << 9) +#define RT5651_GPIO_M_PH (0x1 << 9) +#define RT5651_I2S2_SEL_MASK (0x1 << 8) +#define RT5651_I2S2_SEL_SFT 8 +#define RT5651_I2S2_SEL_I2S (0x0 << 8) +#define RT5651_I2S2_SEL_GPIO (0x1 << 8) +#define RT5651_GP5_PIN_MASK (0x1 << 7) +#define RT5651_GP5_PIN_SFT 7 +#define RT5651_GP5_PIN_GPIO5 (0x0 << 7) +#define RT5651_GP5_PIN_IRQ (0x1 << 7) +#define RT5651_GP6_PIN_MASK (0x1 << 6) +#define RT5651_GP6_PIN_SFT 6 +#define RT5651_GP6_PIN_GPIO6 (0x0 << 6) +#define RT5651_GP6_PIN_DMIC_SDA (0x1 << 6) +#define RT5651_GP7_PIN_MASK (0x1 << 5) +#define RT5651_GP7_PIN_SFT 5 +#define RT5651_GP7_PIN_GPIO7 (0x0 << 5) +#define RT5651_GP7_PIN_IRQ (0x1 << 5) +#define RT5651_GP8_PIN_MASK (0x1 << 4) +#define RT5651_GP8_PIN_SFT 4 +#define RT5651_GP8_PIN_GPIO8 (0x0 << 4) +#define RT5651_GP8_PIN_DMIC_SDA (0x1 << 4) +#define RT5651_GPIO_PDM_SEL_MASK (0x1 << 3) +#define RT5651_GPIO_PDM_SEL_SFT 3 +#define RT5651_GPIO_PDM_SEL_GPIO (0x0 << 3) +#define RT5651_GPIO_PDM_SEL_PDM (0x1 << 3) + +/* GPIO Control 2 (0xc1) */ +#define RT5651_GP5_DR_MASK (0x1 << 14) +#define RT5651_GP5_DR_SFT 14 +#define RT5651_GP5_DR_IN (0x0 << 14) +#define RT5651_GP5_DR_OUT (0x1 << 14) +#define RT5651_GP5_OUT_MASK (0x1 << 13) +#define RT5651_GP5_OUT_SFT 13 +#define RT5651_GP5_OUT_LO (0x0 << 13) +#define RT5651_GP5_OUT_HI (0x1 << 13) +#define RT5651_GP5_P_MASK (0x1 << 12) +#define RT5651_GP5_P_SFT 12 +#define RT5651_GP5_P_NOR (0x0 << 12) +#define RT5651_GP5_P_INV (0x1 << 12) +#define RT5651_GP4_DR_MASK (0x1 << 11) +#define RT5651_GP4_DR_SFT 11 +#define RT5651_GP4_DR_IN (0x0 << 11) +#define RT5651_GP4_DR_OUT (0x1 << 11) +#define RT5651_GP4_OUT_MASK (0x1 << 10) +#define RT5651_GP4_OUT_SFT 10 +#define RT5651_GP4_OUT_LO (0x0 << 10) +#define RT5651_GP4_OUT_HI (0x1 << 10) +#define RT5651_GP4_P_MASK (0x1 << 9) +#define RT5651_GP4_P_SFT 9 +#define RT5651_GP4_P_NOR (0x0 << 9) +#define RT5651_GP4_P_INV (0x1 << 9) +#define RT5651_GP3_DR_MASK (0x1 << 8) +#define RT5651_GP3_DR_SFT 8 +#define RT5651_GP3_DR_IN (0x0 << 8) +#define RT5651_GP3_DR_OUT (0x1 << 8) +#define RT5651_GP3_OUT_MASK (0x1 << 7) +#define RT5651_GP3_OUT_SFT 7 +#define RT5651_GP3_OUT_LO (0x0 << 7) +#define RT5651_GP3_OUT_HI (0x1 << 7) +#define RT5651_GP3_P_MASK (0x1 << 6) +#define RT5651_GP3_P_SFT 6 +#define RT5651_GP3_P_NOR (0x0 << 6) +#define RT5651_GP3_P_INV (0x1 << 6) +#define RT5651_GP2_DR_MASK (0x1 << 5) +#define RT5651_GP2_DR_SFT 5 +#define RT5651_GP2_DR_IN (0x0 << 5) +#define RT5651_GP2_DR_OUT (0x1 << 5) +#define RT5651_GP2_OUT_MASK (0x1 << 4) +#define RT5651_GP2_OUT_SFT 4 +#define RT5651_GP2_OUT_LO (0x0 << 4) +#define RT5651_GP2_OUT_HI (0x1 << 4) +#define RT5651_GP2_P_MASK (0x1 << 3) +#define RT5651_GP2_P_SFT 3 +#define RT5651_GP2_P_NOR (0x0 << 3) +#define RT5651_GP2_P_INV (0x1 << 3) +#define RT5651_GP1_DR_MASK (0x1 << 2) +#define RT5651_GP1_DR_SFT 2 +#define RT5651_GP1_DR_IN (0x0 << 2) +#define RT5651_GP1_DR_OUT (0x1 << 2) +#define RT5651_GP1_OUT_MASK (0x1 << 1) +#define RT5651_GP1_OUT_SFT 1 +#define RT5651_GP1_OUT_LO (0x0 << 1) +#define RT5651_GP1_OUT_HI (0x1 << 1) +#define RT5651_GP1_P_MASK (0x1) +#define RT5651_GP1_P_SFT 0 +#define RT5651_GP1_P_NOR (0x0) +#define RT5651_GP1_P_INV (0x1) + +/* GPIO Control 3 (0xc2) */ +#define RT5651_GP8_DR_MASK (0x1 << 8) +#define RT5651_GP8_DR_SFT 8 +#define RT5651_GP8_DR_IN (0x0 << 8) +#define RT5651_GP8_DR_OUT (0x1 << 8) +#define RT5651_GP8_OUT_MASK (0x1 << 7) +#define RT5651_GP8_OUT_SFT 7 +#define RT5651_GP8_OUT_LO (0x0 << 7) +#define RT5651_GP8_OUT_HI (0x1 << 7) +#define RT5651_GP8_P_MASK (0x1 << 6) +#define RT5651_GP8_P_SFT 6 +#define RT5651_GP8_P_NOR (0x0 << 6) +#define RT5651_GP8_P_INV (0x1 << 6) +#define RT5651_GP7_DR_MASK (0x1 << 5) +#define RT5651_GP7_DR_SFT 5 +#define RT5651_GP7_DR_IN (0x0 << 5) +#define RT5651_GP7_DR_OUT (0x1 << 5) +#define RT5651_GP7_OUT_MASK (0x1 << 4) +#define RT5651_GP7_OUT_SFT 4 +#define RT5651_GP7_OUT_LO (0x0 << 4) +#define RT5651_GP7_OUT_HI (0x1 << 4) +#define RT5651_GP7_P_MASK (0x1 << 3) +#define RT5651_GP7_P_SFT 3 +#define RT5651_GP7_P_NOR (0x0 << 3) +#define RT5651_GP7_P_INV (0x1 << 3) +#define RT5651_GP6_DR_MASK (0x1 << 2) +#define RT5651_GP6_DR_SFT 2 +#define RT5651_GP6_DR_IN (0x0 << 2) +#define RT5651_GP6_DR_OUT (0x1 << 2) +#define RT5651_GP6_OUT_MASK (0x1 << 1) +#define RT5651_GP6_OUT_SFT 1 +#define RT5651_GP6_OUT_LO (0x0 << 1) +#define RT5651_GP6_OUT_HI (0x1 << 1) +#define RT5651_GP6_P_MASK (0x1) +#define RT5651_GP6_P_SFT 0 +#define RT5651_GP6_P_NOR (0x0) +#define RT5651_GP6_P_INV (0x1) + +/* Scramble Control (0xce) */ +#define RT5651_SCB_SWAP_MASK (0x1 << 15) +#define RT5651_SCB_SWAP_SFT 15 +#define RT5651_SCB_SWAP_DIS (0x0 << 15) +#define RT5651_SCB_SWAP_EN (0x1 << 15) +#define RT5651_SCB_MASK (0x1 << 14) +#define RT5651_SCB_SFT 14 +#define RT5651_SCB_DIS (0x0 << 14) +#define RT5651_SCB_EN (0x1 << 14) + +/* Baseback Control (0xcf) */ +#define RT5651_BB_MASK (0x1 << 15) +#define RT5651_BB_SFT 15 +#define RT5651_BB_DIS (0x0 << 15) +#define RT5651_BB_EN (0x1 << 15) +#define RT5651_BB_CT_MASK (0x7 << 12) +#define RT5651_BB_CT_SFT 12 +#define RT5651_BB_CT_A (0x0 << 12) +#define RT5651_BB_CT_B (0x1 << 12) +#define RT5651_BB_CT_C (0x2 << 12) +#define RT5651_BB_CT_D (0x3 << 12) +#define RT5651_M_BB_L_MASK (0x1 << 9) +#define RT5651_M_BB_L_SFT 9 +#define RT5651_M_BB_R_MASK (0x1 << 8) +#define RT5651_M_BB_R_SFT 8 +#define RT5651_M_BB_HPF_L_MASK (0x1 << 7) +#define RT5651_M_BB_HPF_L_SFT 7 +#define RT5651_M_BB_HPF_R_MASK (0x1 << 6) +#define RT5651_M_BB_HPF_R_SFT 6 +#define RT5651_G_BB_BST_MASK (0x3f) +#define RT5651_G_BB_BST_SFT 0 + +/* MP3 Plus Control 1 (0xd0) */ +#define RT5651_M_MP3_L_MASK (0x1 << 15) +#define RT5651_M_MP3_L_SFT 15 +#define RT5651_M_MP3_R_MASK (0x1 << 14) +#define RT5651_M_MP3_R_SFT 14 +#define RT5651_M_MP3_MASK (0x1 << 13) +#define RT5651_M_MP3_SFT 13 +#define RT5651_M_MP3_DIS (0x0 << 13) +#define RT5651_M_MP3_EN (0x1 << 13) +#define RT5651_EG_MP3_MASK (0x1f << 8) +#define RT5651_EG_MP3_SFT 8 +#define RT5651_MP3_HLP_MASK (0x1 << 7) +#define RT5651_MP3_HLP_SFT 7 +#define RT5651_MP3_HLP_DIS (0x0 << 7) +#define RT5651_MP3_HLP_EN (0x1 << 7) +#define RT5651_M_MP3_ORG_L_MASK (0x1 << 6) +#define RT5651_M_MP3_ORG_L_SFT 6 +#define RT5651_M_MP3_ORG_R_MASK (0x1 << 5) +#define RT5651_M_MP3_ORG_R_SFT 5 + +/* MP3 Plus Control 2 (0xd1) */ +#define RT5651_MP3_WT_MASK (0x1 << 13) +#define RT5651_MP3_WT_SFT 13 +#define RT5651_MP3_WT_1_4 (0x0 << 13) +#define RT5651_MP3_WT_1_2 (0x1 << 13) +#define RT5651_OG_MP3_MASK (0x1f << 8) +#define RT5651_OG_MP3_SFT 8 +#define RT5651_HG_MP3_MASK (0x3f) +#define RT5651_HG_MP3_SFT 0 + +/* 3D HP Control 1 (0xd2) */ +#define RT5651_3D_CF_MASK (0x1 << 15) +#define RT5651_3D_CF_SFT 15 +#define RT5651_3D_CF_DIS (0x0 << 15) +#define RT5651_3D_CF_EN (0x1 << 15) +#define RT5651_3D_HP_MASK (0x1 << 14) +#define RT5651_3D_HP_SFT 14 +#define RT5651_3D_HP_DIS (0x0 << 14) +#define RT5651_3D_HP_EN (0x1 << 14) +#define RT5651_3D_BT_MASK (0x1 << 13) +#define RT5651_3D_BT_SFT 13 +#define RT5651_3D_BT_DIS (0x0 << 13) +#define RT5651_3D_BT_EN (0x1 << 13) +#define RT5651_3D_1F_MIX_MASK (0x3 << 11) +#define RT5651_3D_1F_MIX_SFT 11 +#define RT5651_3D_HP_M_MASK (0x1 << 10) +#define RT5651_3D_HP_M_SFT 10 +#define RT5651_3D_HP_M_SUR (0x0 << 10) +#define RT5651_3D_HP_M_FRO (0x1 << 10) +#define RT5651_M_3D_HRTF_MASK (0x1 << 9) +#define RT5651_M_3D_HRTF_SFT 9 +#define RT5651_M_3D_D2H_MASK (0x1 << 8) +#define RT5651_M_3D_D2H_SFT 8 +#define RT5651_M_3D_D2R_MASK (0x1 << 7) +#define RT5651_M_3D_D2R_SFT 7 +#define RT5651_M_3D_REVB_MASK (0x1 << 6) +#define RT5651_M_3D_REVB_SFT 6 + +/* Adjustable high pass filter control 1 (0xd3) */ +#define RT5651_2ND_HPF_MASK (0x1 << 15) +#define RT5651_2ND_HPF_SFT 15 +#define RT5651_2ND_HPF_DIS (0x0 << 15) +#define RT5651_2ND_HPF_EN (0x1 << 15) +#define RT5651_HPF_CF_L_MASK (0x7 << 12) +#define RT5651_HPF_CF_L_SFT 12 +#define RT5651_HPF_CF_R_MASK (0x7 << 8) +#define RT5651_HPF_CF_R_SFT 8 +#define RT5651_ZD_T_MASK (0x3 << 6) +#define RT5651_ZD_T_SFT 6 +#define RT5651_ZD_F_MASK (0x3 << 4) +#define RT5651_ZD_F_SFT 4 +#define RT5651_ZD_F_IM (0x0 << 4) +#define RT5651_ZD_F_ZC_IM (0x1 << 4) +#define RT5651_ZD_F_ZC_IOD (0x2 << 4) +#define RT5651_ZD_F_UN (0x3 << 4) + +/* Adjustable high pass filter control 2 (0xd4) */ +#define RT5651_HPF_CF_L_NUM_MASK (0x3f << 8) +#define RT5651_HPF_CF_L_NUM_SFT 8 +#define RT5651_HPF_CF_R_NUM_MASK (0x3f) +#define RT5651_HPF_CF_R_NUM_SFT 0 + +/* HP calibration control and Amp detection (0xd6) */ +#define RT5651_SI_DAC_MASK (0x1 << 11) +#define RT5651_SI_DAC_SFT 11 +#define RT5651_SI_DAC_AUTO (0x0 << 11) +#define RT5651_SI_DAC_TEST (0x1 << 11) +#define RT5651_DC_CAL_M_MASK (0x1 << 10) +#define RT5651_DC_CAL_M_SFT 10 +#define RT5651_DC_CAL_M_NOR (0x0 << 10) +#define RT5651_DC_CAL_M_CAL (0x1 << 10) +#define RT5651_DC_CAL_MASK (0x1 << 9) +#define RT5651_DC_CAL_SFT 9 +#define RT5651_DC_CAL_DIS (0x0 << 9) +#define RT5651_DC_CAL_EN (0x1 << 9) +#define RT5651_HPD_RCV_MASK (0x7 << 6) +#define RT5651_HPD_RCV_SFT 6 +#define RT5651_HPD_PS_MASK (0x1 << 5) +#define RT5651_HPD_PS_SFT 5 +#define RT5651_HPD_PS_DIS (0x0 << 5) +#define RT5651_HPD_PS_EN (0x1 << 5) +#define RT5651_CAL_M_MASK (0x1 << 4) +#define RT5651_CAL_M_SFT 4 +#define RT5651_CAL_M_DEP (0x0 << 4) +#define RT5651_CAL_M_CAL (0x1 << 4) +#define RT5651_CAL_MASK (0x1 << 3) +#define RT5651_CAL_SFT 3 +#define RT5651_CAL_DIS (0x0 << 3) +#define RT5651_CAL_EN (0x1 << 3) +#define RT5651_CAL_TEST_MASK (0x1 << 2) +#define RT5651_CAL_TEST_SFT 2 +#define RT5651_CAL_TEST_DIS (0x0 << 2) +#define RT5651_CAL_TEST_EN (0x1 << 2) +#define RT5651_CAL_P_MASK (0x3) +#define RT5651_CAL_P_SFT 0 +#define RT5651_CAL_P_NONE (0x0) +#define RT5651_CAL_P_CAL (0x1) +#define RT5651_CAL_P_DAC_CAL (0x2) + +/* Soft volume and zero cross control 1 (0xd9) */ +#define RT5651_SV_MASK (0x1 << 15) +#define RT5651_SV_SFT 15 +#define RT5651_SV_DIS (0x0 << 15) +#define RT5651_SV_EN (0x1 << 15) +#define RT5651_OUT_SV_MASK (0x1 << 13) +#define RT5651_OUT_SV_SFT 13 +#define RT5651_OUT_SV_DIS (0x0 << 13) +#define RT5651_OUT_SV_EN (0x1 << 13) +#define RT5651_HP_SV_MASK (0x1 << 12) +#define RT5651_HP_SV_SFT 12 +#define RT5651_HP_SV_DIS (0x0 << 12) +#define RT5651_HP_SV_EN (0x1 << 12) +#define RT5651_ZCD_DIG_MASK (0x1 << 11) +#define RT5651_ZCD_DIG_SFT 11 +#define RT5651_ZCD_DIG_DIS (0x0 << 11) +#define RT5651_ZCD_DIG_EN (0x1 << 11) +#define RT5651_ZCD_MASK (0x1 << 10) +#define RT5651_ZCD_SFT 10 +#define RT5651_ZCD_PD (0x0 << 10) +#define RT5651_ZCD_PU (0x1 << 10) +#define RT5651_M_ZCD_MASK (0x3f << 4) +#define RT5651_M_ZCD_SFT 4 +#define RT5651_M_ZCD_OM_L (0x1 << 7) +#define RT5651_M_ZCD_OM_R (0x1 << 6) +#define RT5651_M_ZCD_RM_L (0x1 << 5) +#define RT5651_M_ZCD_RM_R (0x1 << 4) +#define RT5651_SV_DLY_MASK (0xf) +#define RT5651_SV_DLY_SFT 0 + +/* Soft volume and zero cross control 2 (0xda) */ +#define RT5651_ZCD_HP_MASK (0x1 << 15) +#define RT5651_ZCD_HP_SFT 15 +#define RT5651_ZCD_HP_DIS (0x0 << 15) +#define RT5651_ZCD_HP_EN (0x1 << 15) + +/* Digital Misc Control (0xfa) */ +#define RT5651_I2S2_MS_SP_MASK (0x1 << 8) +#define RT5651_I2S2_MS_SP_SEL 8 +#define RT5651_I2S2_MS_SP_64 (0x0 << 8) +#define RT5651_I2S2_MS_SP_50 (0x1 << 8) +#define RT5651_CLK_DET_EN (0x1 << 3) +#define RT5651_CLK_DET_EN_SFT 3 +#define RT5651_AMP_DET_EN (0x1 << 1) +#define RT5651_AMP_DET_EN_SFT 1 +#define RT5651_D_GATE_EN (0x1) +#define RT5651_D_GATE_EN_SFT 0 + +/* Codec Private Register definition */ +/* 3D Speaker Control (0x63) */ +#define RT5651_3D_SPK_MASK (0x1 << 15) +#define RT5651_3D_SPK_SFT 15 +#define RT5651_3D_SPK_DIS (0x0 << 15) +#define RT5651_3D_SPK_EN (0x1 << 15) +#define RT5651_3D_SPK_M_MASK (0x3 << 13) +#define RT5651_3D_SPK_M_SFT 13 +#define RT5651_3D_SPK_CG_MASK (0x1f << 8) +#define RT5651_3D_SPK_CG_SFT 8 +#define RT5651_3D_SPK_SG_MASK (0x1f) +#define RT5651_3D_SPK_SG_SFT 0 + +/* Wind Noise Detection Control 1 (0x6c) */ +#define RT5651_WND_MASK (0x1 << 15) +#define RT5651_WND_SFT 15 +#define RT5651_WND_DIS (0x0 << 15) +#define RT5651_WND_EN (0x1 << 15) + +/* Wind Noise Detection Control 2 (0x6d) */ +#define RT5651_WND_FC_NW_MASK (0x3f << 10) +#define RT5651_WND_FC_NW_SFT 10 +#define RT5651_WND_FC_WK_MASK (0x3f << 4) +#define RT5651_WND_FC_WK_SFT 4 + +/* Wind Noise Detection Control 3 (0x6e) */ +#define RT5651_HPF_FC_MASK (0x3f << 6) +#define RT5651_HPF_FC_SFT 6 +#define RT5651_WND_FC_ST_MASK (0x3f) +#define RT5651_WND_FC_ST_SFT 0 + +/* Wind Noise Detection Control 4 (0x6f) */ +#define RT5651_WND_TH_LO_MASK (0x3ff) +#define RT5651_WND_TH_LO_SFT 0 + +/* Wind Noise Detection Control 5 (0x70) */ +#define RT5651_WND_TH_HI_MASK (0x3ff) +#define RT5651_WND_TH_HI_SFT 0 + +/* Wind Noise Detection Control 8 (0x73) */ +#define RT5651_WND_WIND_MASK (0x1 << 13) /* Read-Only */ +#define RT5651_WND_WIND_SFT 13 +#define RT5651_WND_STRONG_MASK (0x1 << 12) /* Read-Only */ +#define RT5651_WND_STRONG_SFT 12 +enum { + RT5651_NO_WIND, + RT5651_BREEZE, + RT5651_STORM, +}; + +/* Dipole Speaker Interface (0x75) */ +#define RT5651_DP_ATT_MASK (0x3 << 14) +#define RT5651_DP_ATT_SFT 14 +#define RT5651_DP_SPK_MASK (0x1 << 10) +#define RT5651_DP_SPK_SFT 10 +#define RT5651_DP_SPK_DIS (0x0 << 10) +#define RT5651_DP_SPK_EN (0x1 << 10) + +/* EQ Pre Volume Control (0xb3) */ +#define RT5651_EQ_PRE_VOL_MASK (0xffff) +#define RT5651_EQ_PRE_VOL_SFT 0 + +/* EQ Post Volume Control (0xb4) */ +#define RT5651_EQ_PST_VOL_MASK (0xffff) +#define RT5651_EQ_PST_VOL_SFT 0 + +/* System Clock Source */ +enum { + RT5651_SCLK_S_MCLK, + RT5651_SCLK_S_PLL1, + RT5651_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { + RT5651_PLL1_S_MCLK, + RT5651_PLL1_S_BCLK1, + RT5651_PLL1_S_BCLK2, +}; + +enum { + RT5651_AIF1, + RT5651_AIF2, + RT5651_AIFS, +}; + +struct rt5651_pll_code { + bool m_bp; /* Indicates bypass m code or not. */ + int m_code; + int n_code; + int k_code; +}; + +struct rt5651_priv { + struct snd_soc_codec *codec; + struct rt5651_platform_data pdata; + struct regmap *regmap; + + int sysclk; + int sysclk_src; + int lrck[RT5651_AIFS]; + int bclk[RT5651_AIFS]; + int master[RT5651_AIFS]; + + struct rt5651_pll_code pll_code; + int pll_src; + int pll_in; + int pll_out; + + int dmic_en; + bool hp_mute; +}; + +#endif /* __RT5651_H__ */ diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index d3ed1be5a186c5..9626ee0417cd42 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -296,7 +296,7 @@ static int dac_info_volsw(struct snd_kcontrol *kcontrol, static int dac_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int reg; int l; int r; @@ -349,7 +349,7 @@ static int dac_get_volsw(struct snd_kcontrol *kcontrol, static int dac_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int reg; int l; int r; @@ -1322,7 +1322,7 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) return ret; } - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), + ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), sgtl5000->supplies); if (ret) goto err_ldo_remove; @@ -1330,16 +1330,13 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), sgtl5000->supplies); if (ret) - goto err_regulator_free; + goto err_ldo_remove; /* wait for all power rails bring up */ udelay(10); return 0; -err_regulator_free: - regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), - sgtl5000->supplies); err_ldo_remove: if (!external_vddd) ldo_regulator_remove(codec); @@ -1409,8 +1406,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) err: regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), sgtl5000->supplies); - regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), - sgtl5000->supplies); ldo_regulator_remove(codec); return ret; @@ -1424,8 +1419,6 @@ static int sgtl5000_remove(struct snd_soc_codec *codec) regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), sgtl5000->supplies); - regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), - sgtl5000->supplies); ldo_regulator_remove(codec); return 0; diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 244c097cd90539..f26befb0c297d5 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -208,13 +208,6 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream, return err; } -static int si476x_codec_probe(struct snd_soc_codec *codec) -{ - struct regmap *regmap = dev_get_regmap(codec->dev->parent, NULL); - - return snd_soc_codec_set_cache_io(codec, regmap); -} - static struct snd_soc_dai_ops si476x_dai_ops = { .hw_params = si476x_codec_hw_params, .set_fmt = si476x_codec_set_dai_fmt, @@ -238,8 +231,13 @@ static struct snd_soc_dai_driver si476x_dai = { .ops = &si476x_dai_ops, }; +static struct regmap *si476x_get_regmap(struct device *dev) +{ + return dev_get_regmap(dev->parent, NULL); +} + static struct snd_soc_codec_driver soc_codec_dev_si476x = { - .probe = si476x_codec_probe, + .get_regmap = si476x_get_regmap, .dapm_widgets = si476x_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets), .dapm_routes = si476x_dapm_routes, diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c index 58e7c1f2377146..c5177bc5df8209 100644 --- a/sound/soc/codecs/sirf-audio-codec.c +++ b/sound/soc/codecs/sirf-audio-codec.c @@ -279,13 +279,63 @@ static const struct snd_soc_dapm_route sirf_audio_codec_map[] = { {"Mic input mode mux", "Differential", "MICIN1"}, }; +static void sirf_audio_codec_tx_enable(struct sirf_audio_codec *sirf_audio_codec) +{ + regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, + AUDIO_FIFO_RESET, AUDIO_FIFO_RESET); + regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, + AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET); + regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0); + regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0); + regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, + AUDIO_FIFO_START, AUDIO_FIFO_START); + regmap_update_bits(sirf_audio_codec->regmap, + AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, IC_TX_ENABLE); +} + +static void sirf_audio_codec_tx_disable(struct sirf_audio_codec *sirf_audio_codec) +{ + regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0); + regmap_update_bits(sirf_audio_codec->regmap, + AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, ~IC_TX_ENABLE); +} + +static void sirf_audio_codec_rx_enable(struct sirf_audio_codec *sirf_audio_codec, + int channels) +{ + regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, + AUDIO_FIFO_RESET, AUDIO_FIFO_RESET); + regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, + AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET); + regmap_write(sirf_audio_codec->regmap, + AUDIO_PORT_IC_RXFIFO_INT_MSK, 0); + regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0); + regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, + AUDIO_FIFO_START, AUDIO_FIFO_START); + if (channels == 1) + regmap_update_bits(sirf_audio_codec->regmap, + AUDIO_PORT_IC_CODEC_RX_CTRL, + IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO); + else + regmap_update_bits(sirf_audio_codec->regmap, + AUDIO_PORT_IC_CODEC_RX_CTRL, + IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO); +} + +static void sirf_audio_codec_rx_disable(struct sirf_audio_codec *sirf_audio_codec) +{ + regmap_update_bits(sirf_audio_codec->regmap, + AUDIO_PORT_IC_CODEC_RX_CTRL, + IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO); +} + static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct snd_soc_codec *codec = dai->codec; - u32 val = 0; + struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec); + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; /* * This is a workaround, When stop playback, @@ -295,20 +345,28 @@ static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (playback) { + snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0, + IC_HSLEN | IC_HSREN, 0); + sirf_audio_codec_tx_disable(sirf_audio_codec); + } else + sirf_audio_codec_rx_disable(sirf_audio_codec); break; case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (playback) - val = IC_HSLEN | IC_HSREN; + if (playback) { + sirf_audio_codec_tx_enable(sirf_audio_codec); + snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0, + IC_HSLEN | IC_HSREN, IC_HSLEN | IC_HSREN); + } else + sirf_audio_codec_rx_enable(sirf_audio_codec, + substream->runtime->channels); break; default: return -EINVAL; } - if (playback) - snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0, - IC_HSLEN | IC_HSREN, val); return 0; } @@ -392,7 +450,7 @@ static const struct regmap_config sirf_audio_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = AUDIO_IC_CODEC_CTRL3, + .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK, .cache_type = REGCACHE_NONE, }; diff --git a/sound/soc/codecs/sirf-audio-codec.h b/sound/soc/codecs/sirf-audio-codec.h index d4c187b8e54a38..ba1adc03839f23 100644 --- a/sound/soc/codecs/sirf-audio-codec.h +++ b/sound/soc/codecs/sirf-audio-codec.h @@ -72,4 +72,54 @@ #define IC_RXPGAR 0x7B #define IC_RXPGAL 0x7B +#define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK 0x3F +#define AUDIO_PORT_TX_FIFO_SC_OFFSET 0 +#define AUDIO_PORT_TX_FIFO_LC_OFFSET 10 +#define AUDIO_PORT_TX_FIFO_HC_OFFSET 20 + +#define TX_FIFO_SC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \ + << AUDIO_PORT_TX_FIFO_SC_OFFSET) +#define TX_FIFO_LC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \ + << AUDIO_PORT_TX_FIFO_LC_OFFSET) +#define TX_FIFO_HC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \ + << AUDIO_PORT_TX_FIFO_HC_OFFSET) + +#define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK 0x0F +#define AUDIO_PORT_RX_FIFO_SC_OFFSET 0 +#define AUDIO_PORT_RX_FIFO_LC_OFFSET 10 +#define AUDIO_PORT_RX_FIFO_HC_OFFSET 20 + +#define RX_FIFO_SC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \ + << AUDIO_PORT_RX_FIFO_SC_OFFSET) +#define RX_FIFO_LC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \ + << AUDIO_PORT_RX_FIFO_LC_OFFSET) +#define RX_FIFO_HC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \ + << AUDIO_PORT_RX_FIFO_HC_OFFSET) +#define AUDIO_PORT_IC_CODEC_TX_CTRL (0x00F4) +#define AUDIO_PORT_IC_CODEC_RX_CTRL (0x00F8) + +#define AUDIO_PORT_IC_TXFIFO_OP (0x00FC) +#define AUDIO_PORT_IC_TXFIFO_LEV_CHK (0x0100) +#define AUDIO_PORT_IC_TXFIFO_STS (0x0104) +#define AUDIO_PORT_IC_TXFIFO_INT (0x0108) +#define AUDIO_PORT_IC_TXFIFO_INT_MSK (0x010C) + +#define AUDIO_PORT_IC_RXFIFO_OP (0x0110) +#define AUDIO_PORT_IC_RXFIFO_LEV_CHK (0x0114) +#define AUDIO_PORT_IC_RXFIFO_STS (0x0118) +#define AUDIO_PORT_IC_RXFIFO_INT (0x011C) +#define AUDIO_PORT_IC_RXFIFO_INT_MSK (0x0120) + +#define AUDIO_FIFO_START (1 << 0) +#define AUDIO_FIFO_RESET (1 << 1) + +#define AUDIO_FIFO_FULL (1 << 0) +#define AUDIO_FIFO_EMPTY (1 << 1) +#define AUDIO_FIFO_OFLOW (1 << 2) +#define AUDIO_FIFO_UFLOW (1 << 3) + +#define IC_TX_ENABLE (0x03) +#define IC_RX_ENABLE_MONO (0x01) +#define IC_RX_ENABLE_STEREO (0x03) + #endif /*__SIRF_AUDIO_CODEC_H*/ diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 12577749b17b3b..0579d187135b1d 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -243,7 +243,7 @@ static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol, static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int numcoef = kcontrol->private_value >> 16; int index = kcontrol->private_value & 0xffff; unsigned int cfud; @@ -272,7 +272,7 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); int numcoef = kcontrol->private_value >> 16; int index = kcontrol->private_value & 0xffff; diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c new file mode 100644 index 00000000000000..cc97dd52aa9c51 --- /dev/null +++ b/sound/soc/codecs/sta350.c @@ -0,0 +1,1311 @@ +/* + * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system + * + * Copyright: 2014 Raumfeld GmbH + * Author: Sven Brandau + * + * based on code from: + * Raumfeld GmbH + * Johannes Stezenbach + * Wolfson Microelectronics PLC. + * Mark Brown + * Freescale Semiconductor, Inc. + * Timur Tabi + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "sta350.h" + +#define STA350_RATES (SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000) + +#define STA350_FORMATS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) + +/* Power-up register defaults */ +static const struct reg_default sta350_regs[] = { + { 0x0, 0x63 }, + { 0x1, 0x80 }, + { 0x2, 0xdf }, + { 0x3, 0x40 }, + { 0x4, 0xc2 }, + { 0x5, 0x5c }, + { 0x6, 0x00 }, + { 0x7, 0xff }, + { 0x8, 0x60 }, + { 0x9, 0x60 }, + { 0xa, 0x60 }, + { 0xb, 0x00 }, + { 0xc, 0x00 }, + { 0xd, 0x00 }, + { 0xe, 0x00 }, + { 0xf, 0x40 }, + { 0x10, 0x80 }, + { 0x11, 0x77 }, + { 0x12, 0x6a }, + { 0x13, 0x69 }, + { 0x14, 0x6a }, + { 0x15, 0x69 }, + { 0x16, 0x00 }, + { 0x17, 0x00 }, + { 0x18, 0x00 }, + { 0x19, 0x00 }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x00 }, + { 0x1e, 0x00 }, + { 0x1f, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x23, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x27, 0x2a }, + { 0x28, 0xc0 }, + { 0x29, 0xf3 }, + { 0x2a, 0x33 }, + { 0x2b, 0x00 }, + { 0x2c, 0x0c }, + { 0x31, 0x00 }, + { 0x36, 0x00 }, + { 0x37, 0x00 }, + { 0x38, 0x00 }, + { 0x39, 0x01 }, + { 0x3a, 0xee }, + { 0x3b, 0xff }, + { 0x3c, 0x7e }, + { 0x3d, 0xc0 }, + { 0x3e, 0x26 }, + { 0x3f, 0x00 }, + { 0x48, 0x00 }, + { 0x49, 0x00 }, + { 0x4a, 0x00 }, + { 0x4b, 0x04 }, + { 0x4c, 0x00 }, +}; + +static const struct regmap_range sta350_write_regs_range[] = { + regmap_reg_range(STA350_CONFA, STA350_AUTO2), + regmap_reg_range(STA350_C1CFG, STA350_FDRC2), + regmap_reg_range(STA350_EQCFG, STA350_EVOLRES), + regmap_reg_range(STA350_NSHAPE, STA350_MISC2), +}; + +static const struct regmap_range sta350_read_regs_range[] = { + regmap_reg_range(STA350_CONFA, STA350_AUTO2), + regmap_reg_range(STA350_C1CFG, STA350_STATUS), + regmap_reg_range(STA350_EQCFG, STA350_EVOLRES), + regmap_reg_range(STA350_NSHAPE, STA350_MISC2), +}; + +static const struct regmap_range sta350_volatile_regs_range[] = { + regmap_reg_range(STA350_CFADDR2, STA350_CFUD), + regmap_reg_range(STA350_STATUS, STA350_STATUS), +}; + +static const struct regmap_access_table sta350_write_regs = { + .yes_ranges = sta350_write_regs_range, + .n_yes_ranges = ARRAY_SIZE(sta350_write_regs_range), +}; + +static const struct regmap_access_table sta350_read_regs = { + .yes_ranges = sta350_read_regs_range, + .n_yes_ranges = ARRAY_SIZE(sta350_read_regs_range), +}; + +static const struct regmap_access_table sta350_volatile_regs = { + .yes_ranges = sta350_volatile_regs_range, + .n_yes_ranges = ARRAY_SIZE(sta350_volatile_regs_range), +}; + +/* regulator power supply names */ +static const char * const sta350_supply_names[] = { + "vdd-dig", /* digital supply, 3.3V */ + "vdd-pll", /* pll supply, 3.3V */ + "vcc" /* power amp supply, 5V - 26V */ +}; + +/* codec private data */ +struct sta350_priv { + struct regmap *regmap; + struct regulator_bulk_data supplies[ARRAY_SIZE(sta350_supply_names)]; + struct sta350_platform_data *pdata; + + unsigned int mclk; + unsigned int format; + + u32 coef_shadow[STA350_COEF_COUNT]; + int shutdown; + + struct gpio_desc *gpiod_nreset; + struct gpio_desc *gpiod_power_down; + + struct mutex coeff_lock; +}; + +static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1); +static const DECLARE_TLV_DB_SCALE(tone_tlv, -1200, 200, 0); + +static const char * const sta350_drc_ac[] = { + "Anti-Clipping", "Dynamic Range Compression" +}; +static const char * const sta350_auto_gc_mode[] = { + "User", "AC no clipping", "AC limited clipping (10%)", + "DRC nighttime listening mode" +}; +static const char * const sta350_auto_xo_mode[] = { + "User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", + "200Hz", "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", + "340Hz", "360Hz" +}; +static const char * const sta350_binary_output[] = { + "FFX 3-state output - normal operation", "Binary output" +}; +static const char * const sta350_limiter_select[] = { + "Limiter Disabled", "Limiter #1", "Limiter #2" +}; +static const char * const sta350_limiter_attack_rate[] = { + "3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024", + "0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752", + "0.0645", "0.0564", "0.0501", "0.0451" +}; +static const char * const sta350_limiter_release_rate[] = { + "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299", + "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137", + "0.0134", "0.0117", "0.0110", "0.0104" +}; +static const char * const sta350_noise_shaper_type[] = { + "Third order", "Fourth order" +}; + +static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_attack_tlv, + 0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0), + 8, 16, TLV_DB_SCALE_ITEM(300, 100, 0), +); + +static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_release_tlv, + 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0), + 3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0), + 8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0), +); + +static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_attack_tlv, + 0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0), + 8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0), + 14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0), +); + +static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_release_tlv, + 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), + 1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0), + 3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0), + 5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0), + 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), +); + +static SOC_ENUM_SINGLE_DECL(sta350_drc_ac_enum, + STA350_CONFD, STA350_CONFD_DRC_SHIFT, + sta350_drc_ac); +static SOC_ENUM_SINGLE_DECL(sta350_noise_shaper_enum, + STA350_CONFE, STA350_CONFE_NSBW_SHIFT, + sta350_noise_shaper_type); +static SOC_ENUM_SINGLE_DECL(sta350_auto_gc_enum, + STA350_AUTO1, STA350_AUTO1_AMGC_SHIFT, + sta350_auto_gc_mode); +static SOC_ENUM_SINGLE_DECL(sta350_auto_xo_enum, + STA350_AUTO2, STA350_AUTO2_XO_SHIFT, + sta350_auto_xo_mode); +static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch1_enum, + STA350_C1CFG, STA350_CxCFG_BO_SHIFT, + sta350_binary_output); +static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch2_enum, + STA350_C2CFG, STA350_CxCFG_BO_SHIFT, + sta350_binary_output); +static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch3_enum, + STA350_C3CFG, STA350_CxCFG_BO_SHIFT, + sta350_binary_output); +static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch1_enum, + STA350_C1CFG, STA350_CxCFG_LS_SHIFT, + sta350_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch2_enum, + STA350_C2CFG, STA350_CxCFG_LS_SHIFT, + sta350_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch3_enum, + STA350_C3CFG, STA350_CxCFG_LS_SHIFT, + sta350_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta350_limiter1_attack_rate_enum, + STA350_L1AR, STA350_LxA_SHIFT, + sta350_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta350_limiter2_attack_rate_enum, + STA350_L2AR, STA350_LxA_SHIFT, + sta350_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta350_limiter1_release_rate_enum, + STA350_L1AR, STA350_LxR_SHIFT, + sta350_limiter_release_rate); +static SOC_ENUM_SINGLE_DECL(sta350_limiter2_release_rate_enum, + STA350_L2AR, STA350_LxR_SHIFT, + sta350_limiter_release_rate); + +/* + * byte array controls for setting biquad, mixer, scaling coefficients; + * for biquads all five coefficients need to be set in one go, + * mixer and pre/postscale coefs can be set individually; + * each coef is 24bit, the bytes are ordered in the same way + * as given in the STA350 data sheet (big endian; b1, b2, a1, a2, b0) + */ + +static int sta350_coefficient_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int numcoef = kcontrol->private_value >> 16; + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = 3 * numcoef; + return 0; +} + +static int sta350_coefficient_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + int numcoef = kcontrol->private_value >> 16; + int index = kcontrol->private_value & 0xffff; + unsigned int cfud, val; + int i, ret = 0; + + mutex_lock(&sta350->coeff_lock); + + /* preserve reserved bits in STA350_CFUD */ + regmap_read(sta350->regmap, STA350_CFUD, &cfud); + cfud &= 0xf0; + /* + * chip documentation does not say if the bits are self clearing, + * so do it explicitly + */ + regmap_write(sta350->regmap, STA350_CFUD, cfud); + + regmap_write(sta350->regmap, STA350_CFADDR2, index); + if (numcoef == 1) { + regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x04); + } else if (numcoef == 5) { + regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x08); + } else { + ret = -EINVAL; + goto exit_unlock; + } + + for (i = 0; i < 3 * numcoef; i++) { + regmap_read(sta350->regmap, STA350_B1CF1 + i, &val); + ucontrol->value.bytes.data[i] = val; + } + +exit_unlock: + mutex_unlock(&sta350->coeff_lock); + + return ret; +} + +static int sta350_coefficient_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + int numcoef = kcontrol->private_value >> 16; + int index = kcontrol->private_value & 0xffff; + unsigned int cfud; + int i; + + /* preserve reserved bits in STA350_CFUD */ + regmap_read(sta350->regmap, STA350_CFUD, &cfud); + cfud &= 0xf0; + /* + * chip documentation does not say if the bits are self clearing, + * so do it explicitly + */ + regmap_write(sta350->regmap, STA350_CFUD, cfud); + + regmap_write(sta350->regmap, STA350_CFADDR2, index); + for (i = 0; i < numcoef && (index + i < STA350_COEF_COUNT); i++) + sta350->coef_shadow[index + i] = + (ucontrol->value.bytes.data[3 * i] << 16) + | (ucontrol->value.bytes.data[3 * i + 1] << 8) + | (ucontrol->value.bytes.data[3 * i + 2]); + for (i = 0; i < 3 * numcoef; i++) + regmap_write(sta350->regmap, STA350_B1CF1 + i, + ucontrol->value.bytes.data[i]); + if (numcoef == 1) + regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x01); + else if (numcoef == 5) + regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x02); + else + return -EINVAL; + + return 0; +} + +static int sta350_sync_coef_shadow(struct snd_soc_codec *codec) +{ + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + unsigned int cfud; + int i; + + /* preserve reserved bits in STA350_CFUD */ + regmap_read(sta350->regmap, STA350_CFUD, &cfud); + cfud &= 0xf0; + + for (i = 0; i < STA350_COEF_COUNT; i++) { + regmap_write(sta350->regmap, STA350_CFADDR2, i); + regmap_write(sta350->regmap, STA350_B1CF1, + (sta350->coef_shadow[i] >> 16) & 0xff); + regmap_write(sta350->regmap, STA350_B1CF2, + (sta350->coef_shadow[i] >> 8) & 0xff); + regmap_write(sta350->regmap, STA350_B1CF3, + (sta350->coef_shadow[i]) & 0xff); + /* + * chip documentation does not say if the bits are + * self-clearing, so do it explicitly + */ + regmap_write(sta350->regmap, STA350_CFUD, cfud); + regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x01); + } + return 0; +} + +static int sta350_cache_sync(struct snd_soc_codec *codec) +{ + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + unsigned int mute; + int rc; + + /* mute during register sync */ + regmap_read(sta350->regmap, STA350_CFUD, &mute); + regmap_write(sta350->regmap, STA350_MMUTE, mute | STA350_MMUTE_MMUTE); + sta350_sync_coef_shadow(codec); + rc = regcache_sync(sta350->regmap); + regmap_write(sta350->regmap, STA350_MMUTE, mute); + return rc; +} + +#define SINGLE_COEF(xname, index) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = sta350_coefficient_info, \ + .get = sta350_coefficient_get,\ + .put = sta350_coefficient_put, \ + .private_value = index | (1 << 16) } + +#define BIQUAD_COEFS(xname, index) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = sta350_coefficient_info, \ + .get = sta350_coefficient_get,\ + .put = sta350_coefficient_put, \ + .private_value = index | (5 << 16) } + +static const struct snd_kcontrol_new sta350_snd_controls[] = { +SOC_SINGLE_TLV("Master Volume", STA350_MVOL, 0, 0xff, 1, mvol_tlv), +/* VOL */ +SOC_SINGLE_TLV("Ch1 Volume", STA350_C1VOL, 0, 0xff, 1, chvol_tlv), +SOC_SINGLE_TLV("Ch2 Volume", STA350_C2VOL, 0, 0xff, 1, chvol_tlv), +SOC_SINGLE_TLV("Ch3 Volume", STA350_C3VOL, 0, 0xff, 1, chvol_tlv), +/* CONFD */ +SOC_SINGLE("High Pass Filter Bypass Switch", + STA350_CONFD, STA350_CONFD_HPB_SHIFT, 1, 1), +SOC_SINGLE("De-emphasis Filter Switch", + STA350_CONFD, STA350_CONFD_DEMP_SHIFT, 1, 0), +SOC_SINGLE("DSP Bypass Switch", + STA350_CONFD, STA350_CONFD_DSPB_SHIFT, 1, 0), +SOC_SINGLE("Post-scale Link Switch", + STA350_CONFD, STA350_CONFD_PSL_SHIFT, 1, 0), +SOC_SINGLE("Biquad Coefficient Link Switch", + STA350_CONFD, STA350_CONFD_BQL_SHIFT, 1, 0), +SOC_ENUM("Compressor/Limiter Switch", sta350_drc_ac_enum), +SOC_ENUM("Noise Shaper Bandwidth", sta350_noise_shaper_enum), +SOC_SINGLE("Zero-detect Mute Enable Switch", + STA350_CONFD, STA350_CONFD_ZDE_SHIFT, 1, 0), +SOC_SINGLE("Submix Mode Switch", + STA350_CONFD, STA350_CONFD_SME_SHIFT, 1, 0), +/* CONFE */ +SOC_SINGLE("Zero Cross Switch", STA350_CONFE, STA350_CONFE_ZCE_SHIFT, 1, 0), +SOC_SINGLE("Soft Ramp Switch", STA350_CONFE, STA350_CONFE_SVE_SHIFT, 1, 0), +/* MUTE */ +SOC_SINGLE("Master Switch", STA350_MMUTE, STA350_MMUTE_MMUTE_SHIFT, 1, 1), +SOC_SINGLE("Ch1 Switch", STA350_MMUTE, STA350_MMUTE_C1M_SHIFT, 1, 1), +SOC_SINGLE("Ch2 Switch", STA350_MMUTE, STA350_MMUTE_C2M_SHIFT, 1, 1), +SOC_SINGLE("Ch3 Switch", STA350_MMUTE, STA350_MMUTE_C3M_SHIFT, 1, 1), +/* AUTOx */ +SOC_ENUM("Automode GC", sta350_auto_gc_enum), +SOC_ENUM("Automode XO", sta350_auto_xo_enum), +/* CxCFG */ +SOC_SINGLE("Ch1 Tone Control Bypass Switch", + STA350_C1CFG, STA350_CxCFG_TCB_SHIFT, 1, 0), +SOC_SINGLE("Ch2 Tone Control Bypass Switch", + STA350_C2CFG, STA350_CxCFG_TCB_SHIFT, 1, 0), +SOC_SINGLE("Ch1 EQ Bypass Switch", + STA350_C1CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0), +SOC_SINGLE("Ch2 EQ Bypass Switch", + STA350_C2CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0), +SOC_SINGLE("Ch1 Master Volume Bypass Switch", + STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0), +SOC_SINGLE("Ch2 Master Volume Bypass Switch", + STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0), +SOC_SINGLE("Ch3 Master Volume Bypass Switch", + STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0), +SOC_ENUM("Ch1 Binary Output Select", sta350_binary_output_ch1_enum), +SOC_ENUM("Ch2 Binary Output Select", sta350_binary_output_ch2_enum), +SOC_ENUM("Ch3 Binary Output Select", sta350_binary_output_ch3_enum), +SOC_ENUM("Ch1 Limiter Select", sta350_limiter_ch1_enum), +SOC_ENUM("Ch2 Limiter Select", sta350_limiter_ch2_enum), +SOC_ENUM("Ch3 Limiter Select", sta350_limiter_ch3_enum), +/* TONE */ +SOC_SINGLE_RANGE_TLV("Bass Tone Control Volume", + STA350_TONE, STA350_TONE_BTC_SHIFT, 1, 13, 0, tone_tlv), +SOC_SINGLE_RANGE_TLV("Treble Tone Control Volume", + STA350_TONE, STA350_TONE_TTC_SHIFT, 1, 13, 0, tone_tlv), +SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta350_limiter1_attack_rate_enum), +SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta350_limiter2_attack_rate_enum), +SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta350_limiter1_release_rate_enum), +SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta350_limiter2_release_rate_enum), + +/* + * depending on mode, the attack/release thresholds have + * two different enum definitions; provide both + */ +SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", + STA350_L1ATRT, STA350_LxA_SHIFT, + 16, 0, sta350_limiter_ac_attack_tlv), +SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", + STA350_L2ATRT, STA350_LxA_SHIFT, + 16, 0, sta350_limiter_ac_attack_tlv), +SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", + STA350_L1ATRT, STA350_LxR_SHIFT, + 16, 0, sta350_limiter_ac_release_tlv), +SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", + STA350_L2ATRT, STA350_LxR_SHIFT, + 16, 0, sta350_limiter_ac_release_tlv), +SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", + STA350_L1ATRT, STA350_LxA_SHIFT, + 16, 0, sta350_limiter_drc_attack_tlv), +SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", + STA350_L2ATRT, STA350_LxA_SHIFT, + 16, 0, sta350_limiter_drc_attack_tlv), +SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", + STA350_L1ATRT, STA350_LxR_SHIFT, + 16, 0, sta350_limiter_drc_release_tlv), +SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", + STA350_L2ATRT, STA350_LxR_SHIFT, + 16, 0, sta350_limiter_drc_release_tlv), + +BIQUAD_COEFS("Ch1 - Biquad 1", 0), +BIQUAD_COEFS("Ch1 - Biquad 2", 5), +BIQUAD_COEFS("Ch1 - Biquad 3", 10), +BIQUAD_COEFS("Ch1 - Biquad 4", 15), +BIQUAD_COEFS("Ch2 - Biquad 1", 20), +BIQUAD_COEFS("Ch2 - Biquad 2", 25), +BIQUAD_COEFS("Ch2 - Biquad 3", 30), +BIQUAD_COEFS("Ch2 - Biquad 4", 35), +BIQUAD_COEFS("High-pass", 40), +BIQUAD_COEFS("Low-pass", 45), +SINGLE_COEF("Ch1 - Prescale", 50), +SINGLE_COEF("Ch2 - Prescale", 51), +SINGLE_COEF("Ch1 - Postscale", 52), +SINGLE_COEF("Ch2 - Postscale", 53), +SINGLE_COEF("Ch3 - Postscale", 54), +SINGLE_COEF("Thermal warning - Postscale", 55), +SINGLE_COEF("Ch1 - Mix 1", 56), +SINGLE_COEF("Ch1 - Mix 2", 57), +SINGLE_COEF("Ch2 - Mix 1", 58), +SINGLE_COEF("Ch2 - Mix 2", 59), +SINGLE_COEF("Ch3 - Mix 1", 60), +SINGLE_COEF("Ch3 - Mix 2", 61), +}; + +static const struct snd_soc_dapm_widget sta350_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_OUTPUT("LEFT"), +SND_SOC_DAPM_OUTPUT("RIGHT"), +SND_SOC_DAPM_OUTPUT("SUB"), +}; + +static const struct snd_soc_dapm_route sta350_dapm_routes[] = { + { "LEFT", NULL, "DAC" }, + { "RIGHT", NULL, "DAC" }, + { "SUB", NULL, "DAC" }, + { "DAC", NULL, "Playback" }, +}; + +/* MCLK interpolation ratio per fs */ +static struct { + int fs; + int ir; +} interpolation_ratios[] = { + { 32000, 0 }, + { 44100, 0 }, + { 48000, 0 }, + { 88200, 1 }, + { 96000, 1 }, + { 176400, 2 }, + { 192000, 2 }, +}; + +/* MCLK to fs clock ratios */ +static int mcs_ratio_table[3][6] = { + { 768, 512, 384, 256, 128, 576 }, + { 384, 256, 192, 128, 64, 0 }, + { 192, 128, 96, 64, 32, 0 }, +}; + +/** + * sta350_set_dai_sysclk - configure MCLK + * @codec_dai: the codec DAI + * @clk_id: the clock ID (ignored) + * @freq: the MCLK input frequency + * @dir: the clock direction (ignored) + * + * The value of MCLK is used to determine which sample rates are supported + * by the STA350, based on the mcs_ratio_table. + * + * This function must be called by the machine driver's 'startup' function, + * otherwise the list of supported sample rates will not be available in + * time for ALSA. + */ +static int sta350_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "mclk=%u\n", freq); + sta350->mclk = freq; + + return 0; +} + +/** + * sta350_set_dai_fmt - configure the codec for the selected audio format + * @codec_dai: the codec DAI + * @fmt: a SND_SOC_DAIFMT_x value indicating the data format + * + * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the + * codec accordingly. + */ +static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + unsigned int confb = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + sta350->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + confb |= STA350_CONFB_C2IM; + break; + case SND_SOC_DAIFMT_NB_IF: + confb |= STA350_CONFB_C1IM; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(sta350->regmap, STA350_CONFB, + STA350_CONFB_C1IM | STA350_CONFB_C2IM, confb); +} + +/** + * sta350_hw_params - program the STA350 with the given hardware parameters. + * @substream: the audio stream + * @params: the hardware parameters to set + * @dai: the SOC DAI (ignored) + * + * This function programs the hardware with the values provided. + * Specifically, the sample rate and the data format. + */ +static int sta350_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + int i, mcs = -EINVAL, ir = -EINVAL; + unsigned int confa, confb; + unsigned int rate, ratio; + int ret; + + if (!sta350->mclk) { + dev_err(codec->dev, + "sta350->mclk is unset. Unable to determine ratio\n"); + return -EIO; + } + + rate = params_rate(params); + ratio = sta350->mclk / rate; + dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio); + + for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) { + if (interpolation_ratios[i].fs == rate) { + ir = interpolation_ratios[i].ir; + break; + } + } + + if (ir < 0) { + dev_err(codec->dev, "Unsupported samplerate: %u\n", rate); + return -EINVAL; + } + + for (i = 0; i < 6; i++) { + if (mcs_ratio_table[ir][i] == ratio) { + mcs = i; + break; + } + } + + if (mcs < 0) { + dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio); + return -EINVAL; + } + + confa = (ir << STA350_CONFA_IR_SHIFT) | + (mcs << STA350_CONFA_MCS_SHIFT); + confb = 0; + + switch (params_width(params)) { + case 24: + dev_dbg(codec->dev, "24bit\n"); + /* fall through */ + case 32: + dev_dbg(codec->dev, "24bit or 32bit\n"); + switch (sta350->format) { + case SND_SOC_DAIFMT_I2S: + confb |= 0x0; + break; + case SND_SOC_DAIFMT_LEFT_J: + confb |= 0x1; + break; + case SND_SOC_DAIFMT_RIGHT_J: + confb |= 0x2; + break; + } + + break; + case 20: + dev_dbg(codec->dev, "20bit\n"); + switch (sta350->format) { + case SND_SOC_DAIFMT_I2S: + confb |= 0x4; + break; + case SND_SOC_DAIFMT_LEFT_J: + confb |= 0x5; + break; + case SND_SOC_DAIFMT_RIGHT_J: + confb |= 0x6; + break; + } + + break; + case 18: + dev_dbg(codec->dev, "18bit\n"); + switch (sta350->format) { + case SND_SOC_DAIFMT_I2S: + confb |= 0x8; + break; + case SND_SOC_DAIFMT_LEFT_J: + confb |= 0x9; + break; + case SND_SOC_DAIFMT_RIGHT_J: + confb |= 0xa; + break; + } + + break; + case 16: + dev_dbg(codec->dev, "16bit\n"); + switch (sta350->format) { + case SND_SOC_DAIFMT_I2S: + confb |= 0x0; + break; + case SND_SOC_DAIFMT_LEFT_J: + confb |= 0xd; + break; + case SND_SOC_DAIFMT_RIGHT_J: + confb |= 0xe; + break; + } + + break; + default: + return -EINVAL; + } + + ret = regmap_update_bits(sta350->regmap, STA350_CONFA, + STA350_CONFA_MCS_MASK | STA350_CONFA_IR_MASK, + confa); + if (ret < 0) + return ret; + + ret = regmap_update_bits(sta350->regmap, STA350_CONFB, + STA350_CONFB_SAI_MASK | STA350_CONFB_SAIFB, + confb); + if (ret < 0) + return ret; + + return 0; +} + +static int sta350_startup_sequence(struct sta350_priv *sta350) +{ + if (sta350->gpiod_power_down) + gpiod_set_value(sta350->gpiod_power_down, 1); + + if (sta350->gpiod_nreset) { + gpiod_set_value(sta350->gpiod_nreset, 0); + mdelay(1); + gpiod_set_value(sta350->gpiod_nreset, 1); + mdelay(1); + } + + return 0; +} + +/** + * sta350_set_bias_level - DAPM callback + * @codec: the codec device + * @level: DAPM power level + * + * This is called by ALSA to put the codec into low power mode + * or to wake it up. If the codec is powered off completely + * all registers must be restored after power on. + */ +static int sta350_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + int ret; + + dev_dbg(codec->dev, "level = %d\n", level); + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* Full power on */ + regmap_update_bits(sta350->regmap, STA350_CONFF, + STA350_CONFF_PWDN | STA350_CONFF_EAPD, + STA350_CONFF_PWDN | STA350_CONFF_EAPD); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + ret = regulator_bulk_enable( + ARRAY_SIZE(sta350->supplies), + sta350->supplies); + if (ret < 0) { + dev_err(codec->dev, + "Failed to enable supplies: %d\n", + ret); + return ret; + } + sta350_startup_sequence(sta350); + sta350_cache_sync(codec); + } + + /* Power down */ + regmap_update_bits(sta350->regmap, STA350_CONFF, + STA350_CONFF_PWDN | STA350_CONFF_EAPD, + 0); + + break; + + case SND_SOC_BIAS_OFF: + /* The chip runs through the power down sequence for us */ + regmap_update_bits(sta350->regmap, STA350_CONFF, + STA350_CONFF_PWDN | STA350_CONFF_EAPD, 0); + + /* power down: low */ + if (sta350->gpiod_power_down) + gpiod_set_value(sta350->gpiod_power_down, 0); + + if (sta350->gpiod_nreset) + gpiod_set_value(sta350->gpiod_nreset, 0); + + regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), + sta350->supplies); + break; + } + codec->dapm.bias_level = level; + return 0; +} + +static const struct snd_soc_dai_ops sta350_dai_ops = { + .hw_params = sta350_hw_params, + .set_sysclk = sta350_set_dai_sysclk, + .set_fmt = sta350_set_dai_fmt, +}; + +static struct snd_soc_dai_driver sta350_dai = { + .name = "sta350-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = STA350_RATES, + .formats = STA350_FORMATS, + }, + .ops = &sta350_dai_ops, +}; + +#ifdef CONFIG_PM +static int sta350_suspend(struct snd_soc_codec *codec) +{ + sta350_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int sta350_resume(struct snd_soc_codec *codec) +{ + sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + return 0; +} +#else +#define sta350_suspend NULL +#define sta350_resume NULL +#endif + +static int sta350_probe(struct snd_soc_codec *codec) +{ + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + struct sta350_platform_data *pdata = sta350->pdata; + int i, ret = 0, thermal = 0; + + ret = regulator_bulk_enable(ARRAY_SIZE(sta350->supplies), + sta350->supplies); + if (ret < 0) { + dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + ret = sta350_startup_sequence(sta350); + if (ret < 0) { + dev_err(codec->dev, "Failed to startup device\n"); + return ret; + } + + /* CONFA */ + if (!pdata->thermal_warning_recovery) + thermal |= STA350_CONFA_TWAB; + if (!pdata->thermal_warning_adjustment) + thermal |= STA350_CONFA_TWRB; + if (!pdata->fault_detect_recovery) + thermal |= STA350_CONFA_FDRB; + regmap_update_bits(sta350->regmap, STA350_CONFA, + STA350_CONFA_TWAB | STA350_CONFA_TWRB | + STA350_CONFA_FDRB, + thermal); + + /* CONFC */ + regmap_update_bits(sta350->regmap, STA350_CONFC, + STA350_CONFC_OM_MASK, + pdata->ffx_power_output_mode + << STA350_CONFC_OM_SHIFT); + regmap_update_bits(sta350->regmap, STA350_CONFC, + STA350_CONFC_CSZ_MASK, + pdata->drop_compensation_ns + << STA350_CONFC_CSZ_SHIFT); + regmap_update_bits(sta350->regmap, + STA350_CONFC, + STA350_CONFC_OCRB, + pdata->oc_warning_adjustment ? + STA350_CONFC_OCRB : 0); + + /* CONFE */ + regmap_update_bits(sta350->regmap, STA350_CONFE, + STA350_CONFE_MPCV, + pdata->max_power_use_mpcc ? + STA350_CONFE_MPCV : 0); + regmap_update_bits(sta350->regmap, STA350_CONFE, + STA350_CONFE_MPC, + pdata->max_power_correction ? + STA350_CONFE_MPC : 0); + regmap_update_bits(sta350->regmap, STA350_CONFE, + STA350_CONFE_AME, + pdata->am_reduction_mode ? + STA350_CONFE_AME : 0); + regmap_update_bits(sta350->regmap, STA350_CONFE, + STA350_CONFE_PWMS, + pdata->odd_pwm_speed_mode ? + STA350_CONFE_PWMS : 0); + regmap_update_bits(sta350->regmap, STA350_CONFE, + STA350_CONFE_DCCV, + pdata->distortion_compensation ? + STA350_CONFE_DCCV : 0); + /* CONFF */ + regmap_update_bits(sta350->regmap, STA350_CONFF, + STA350_CONFF_IDE, + pdata->invalid_input_detect_mute ? + STA350_CONFF_IDE : 0); + regmap_update_bits(sta350->regmap, STA350_CONFF, + STA350_CONFF_OCFG_MASK, + pdata->output_conf + << STA350_CONFF_OCFG_SHIFT); + + /* channel to output mapping */ + regmap_update_bits(sta350->regmap, STA350_C1CFG, + STA350_CxCFG_OM_MASK, + pdata->ch1_output_mapping + << STA350_CxCFG_OM_SHIFT); + regmap_update_bits(sta350->regmap, STA350_C2CFG, + STA350_CxCFG_OM_MASK, + pdata->ch2_output_mapping + << STA350_CxCFG_OM_SHIFT); + regmap_update_bits(sta350->regmap, STA350_C3CFG, + STA350_CxCFG_OM_MASK, + pdata->ch3_output_mapping + << STA350_CxCFG_OM_SHIFT); + + /* miscellaneous registers */ + regmap_update_bits(sta350->regmap, STA350_MISC1, + STA350_MISC1_CPWMEN, + pdata->activate_mute_output ? + STA350_MISC1_CPWMEN : 0); + regmap_update_bits(sta350->regmap, STA350_MISC1, + STA350_MISC1_BRIDGOFF, + pdata->bridge_immediate_off ? + STA350_MISC1_BRIDGOFF : 0); + regmap_update_bits(sta350->regmap, STA350_MISC1, + STA350_MISC1_NSHHPEN, + pdata->noise_shape_dc_cut ? + STA350_MISC1_NSHHPEN : 0); + regmap_update_bits(sta350->regmap, STA350_MISC1, + STA350_MISC1_RPDNEN, + pdata->powerdown_master_vol ? + STA350_MISC1_RPDNEN: 0); + + regmap_update_bits(sta350->regmap, STA350_MISC2, + STA350_MISC2_PNDLSL_MASK, + pdata->powerdown_delay_divider + << STA350_MISC2_PNDLSL_SHIFT); + + /* initialize coefficient shadow RAM with reset values */ + for (i = 4; i <= 49; i += 5) + sta350->coef_shadow[i] = 0x400000; + for (i = 50; i <= 54; i++) + sta350->coef_shadow[i] = 0x7fffff; + sta350->coef_shadow[55] = 0x5a9df7; + sta350->coef_shadow[56] = 0x7fffff; + sta350->coef_shadow[59] = 0x7fffff; + sta350->coef_shadow[60] = 0x400000; + sta350->coef_shadow[61] = 0x400000; + + sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + /* Bias level configuration will have done an extra enable */ + regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); + + return 0; +} + +static int sta350_remove(struct snd_soc_codec *codec) +{ + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + + sta350_set_bias_level(codec, SND_SOC_BIAS_OFF); + regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); + + return 0; +} + +static const struct snd_soc_codec_driver sta350_codec = { + .probe = sta350_probe, + .remove = sta350_remove, + .suspend = sta350_suspend, + .resume = sta350_resume, + .set_bias_level = sta350_set_bias_level, + .controls = sta350_snd_controls, + .num_controls = ARRAY_SIZE(sta350_snd_controls), + .dapm_widgets = sta350_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sta350_dapm_widgets), + .dapm_routes = sta350_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sta350_dapm_routes), +}; + +static const struct regmap_config sta350_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = STA350_MISC2, + .reg_defaults = sta350_regs, + .num_reg_defaults = ARRAY_SIZE(sta350_regs), + .cache_type = REGCACHE_RBTREE, + .wr_table = &sta350_write_regs, + .rd_table = &sta350_read_regs, + .volatile_table = &sta350_volatile_regs, +}; + +#ifdef CONFIG_OF +static const struct of_device_id st350_dt_ids[] = { + { .compatible = "st,sta350", }, + { } +}; +MODULE_DEVICE_TABLE(of, st350_dt_ids); + +static const char * const sta350_ffx_modes[] = { + [STA350_FFX_PM_DROP_COMP] = "drop-compensation", + [STA350_FFX_PM_TAPERED_COMP] = "tapered-compensation", + [STA350_FFX_PM_FULL_POWER] = "full-power-mode", + [STA350_FFX_PM_VARIABLE_DROP_COMP] = "variable-drop-compensation", +}; + +static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350) +{ + struct device_node *np = dev->of_node; + struct sta350_platform_data *pdata; + const char *ffx_power_mode; + u16 tmp; + u8 tmp8; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + of_property_read_u8(np, "st,output-conf", + &pdata->output_conf); + of_property_read_u8(np, "st,ch1-output-mapping", + &pdata->ch1_output_mapping); + of_property_read_u8(np, "st,ch2-output-mapping", + &pdata->ch2_output_mapping); + of_property_read_u8(np, "st,ch3-output-mapping", + &pdata->ch3_output_mapping); + + if (of_get_property(np, "st,thermal-warning-recovery", NULL)) + pdata->thermal_warning_recovery = 1; + if (of_get_property(np, "st,thermal-warning-adjustment", NULL)) + pdata->thermal_warning_adjustment = 1; + if (of_get_property(np, "st,fault-detect-recovery", NULL)) + pdata->fault_detect_recovery = 1; + + pdata->ffx_power_output_mode = STA350_FFX_PM_VARIABLE_DROP_COMP; + if (!of_property_read_string(np, "st,ffx-power-output-mode", + &ffx_power_mode)) { + int i, mode = -EINVAL; + + for (i = 0; i < ARRAY_SIZE(sta350_ffx_modes); i++) + if (!strcasecmp(ffx_power_mode, sta350_ffx_modes[i])) + mode = i; + + if (mode < 0) + dev_warn(dev, "Unsupported ffx output mode: %s\n", + ffx_power_mode); + else + pdata->ffx_power_output_mode = mode; + } + + tmp = 140; + of_property_read_u16(np, "st,drop-compensation-ns", &tmp); + pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20; + + if (of_get_property(np, "st,overcurrent-warning-adjustment", NULL)) + pdata->oc_warning_adjustment = 1; + + /* CONFE */ + if (of_get_property(np, "st,max-power-use-mpcc", NULL)) + pdata->max_power_use_mpcc = 1; + + if (of_get_property(np, "st,max-power-correction", NULL)) + pdata->max_power_correction = 1; + + if (of_get_property(np, "st,am-reduction-mode", NULL)) + pdata->am_reduction_mode = 1; + + if (of_get_property(np, "st,odd-pwm-speed-mode", NULL)) + pdata->odd_pwm_speed_mode = 1; + + if (of_get_property(np, "st,distortion-compensation", NULL)) + pdata->distortion_compensation = 1; + + /* CONFF */ + if (of_get_property(np, "st,invalid-input-detect-mute", NULL)) + pdata->invalid_input_detect_mute = 1; + + /* MISC */ + if (of_get_property(np, "st,activate-mute-output", NULL)) + pdata->activate_mute_output = 1; + + if (of_get_property(np, "st,bridge-immediate-off", NULL)) + pdata->bridge_immediate_off = 1; + + if (of_get_property(np, "st,noise-shape-dc-cut", NULL)) + pdata->noise_shape_dc_cut = 1; + + if (of_get_property(np, "st,powerdown-master-volume", NULL)) + pdata->powerdown_master_vol = 1; + + if (!of_property_read_u8(np, "st,powerdown-delay-divider", &tmp8)) { + if (is_power_of_2(tmp8) && tmp8 >= 1 && tmp8 <= 128) + pdata->powerdown_delay_divider = ilog2(tmp8); + else + dev_warn(dev, "Unsupported powerdown delay divider %d\n", + tmp8); + } + + sta350->pdata = pdata; + + return 0; +} +#endif + +static int sta350_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c->dev; + struct sta350_priv *sta350; + int ret, i; + + sta350 = devm_kzalloc(dev, sizeof(struct sta350_priv), GFP_KERNEL); + if (!sta350) + return -ENOMEM; + + mutex_init(&sta350->coeff_lock); + sta350->pdata = dev_get_platdata(dev); + +#ifdef CONFIG_OF + if (dev->of_node) { + ret = sta350_probe_dt(dev, sta350); + if (ret < 0) + return ret; + } +#endif + + /* GPIOs */ + sta350->gpiod_nreset = devm_gpiod_get(dev, "reset"); + if (IS_ERR(sta350->gpiod_nreset)) { + ret = PTR_ERR(sta350->gpiod_nreset); + if (ret != -ENOENT && ret != -ENOSYS) + return ret; + + sta350->gpiod_nreset = NULL; + } else { + gpiod_direction_output(sta350->gpiod_nreset, 0); + } + + sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down"); + if (IS_ERR(sta350->gpiod_power_down)) { + ret = PTR_ERR(sta350->gpiod_power_down); + if (ret != -ENOENT && ret != -ENOSYS) + return ret; + + sta350->gpiod_power_down = NULL; + } else { + gpiod_direction_output(sta350->gpiod_power_down, 0); + } + + /* regulators */ + for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++) + sta350->supplies[i].supply = sta350_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sta350->supplies), + sta350->supplies); + if (ret < 0) { + dev_err(dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + sta350->regmap = devm_regmap_init_i2c(i2c, &sta350_regmap); + if (IS_ERR(sta350->regmap)) { + ret = PTR_ERR(sta350->regmap); + dev_err(dev, "Failed to init regmap: %d\n", ret); + return ret; + } + + i2c_set_clientdata(i2c, sta350); + + ret = snd_soc_register_codec(dev, &sta350_codec, &sta350_dai, 1); + if (ret < 0) + dev_err(dev, "Failed to register codec (%d)\n", ret); + + return ret; +} + +static int sta350_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id sta350_i2c_id[] = { + { "sta350", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sta350_i2c_id); + +static struct i2c_driver sta350_i2c_driver = { + .driver = { + .name = "sta350", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(st350_dt_ids), + }, + .probe = sta350_i2c_probe, + .remove = sta350_i2c_remove, + .id_table = sta350_i2c_id, +}; + +module_i2c_driver(sta350_i2c_driver); + +MODULE_DESCRIPTION("ASoC STA350 driver"); +MODULE_AUTHOR("Sven Brandau "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sta350.h b/sound/soc/codecs/sta350.h new file mode 100644 index 00000000000000..fb728529077946 --- /dev/null +++ b/sound/soc/codecs/sta350.h @@ -0,0 +1,238 @@ +/* + * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system + * + * Copyright: 2011 Raumfeld GmbH + * Author: Sven Brandau + * + * based on code from: + * Raumfeld GmbH + * Johannes Stezenbach + * Wolfson Microelectronics PLC. + * Mark Brown + * + * 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. + */ +#ifndef _ASOC_STA_350_H +#define _ASOC_STA_350_H + +/* STA50 register addresses */ + +#define STA350_REGISTER_COUNT 0x4D +#define STA350_COEF_COUNT 62 + +#define STA350_CONFA 0x00 +#define STA350_CONFB 0x01 +#define STA350_CONFC 0x02 +#define STA350_CONFD 0x03 +#define STA350_CONFE 0x04 +#define STA350_CONFF 0x05 +#define STA350_MMUTE 0x06 +#define STA350_MVOL 0x07 +#define STA350_C1VOL 0x08 +#define STA350_C2VOL 0x09 +#define STA350_C3VOL 0x0a +#define STA350_AUTO1 0x0b +#define STA350_AUTO2 0x0c +#define STA350_AUTO3 0x0d +#define STA350_C1CFG 0x0e +#define STA350_C2CFG 0x0f +#define STA350_C3CFG 0x10 +#define STA350_TONE 0x11 +#define STA350_L1AR 0x12 +#define STA350_L1ATRT 0x13 +#define STA350_L2AR 0x14 +#define STA350_L2ATRT 0x15 +#define STA350_CFADDR2 0x16 +#define STA350_B1CF1 0x17 +#define STA350_B1CF2 0x18 +#define STA350_B1CF3 0x19 +#define STA350_B2CF1 0x1a +#define STA350_B2CF2 0x1b +#define STA350_B2CF3 0x1c +#define STA350_A1CF1 0x1d +#define STA350_A1CF2 0x1e +#define STA350_A1CF3 0x1f +#define STA350_A2CF1 0x20 +#define STA350_A2CF2 0x21 +#define STA350_A2CF3 0x22 +#define STA350_B0CF1 0x23 +#define STA350_B0CF2 0x24 +#define STA350_B0CF3 0x25 +#define STA350_CFUD 0x26 +#define STA350_MPCC1 0x27 +#define STA350_MPCC2 0x28 +#define STA350_DCC1 0x29 +#define STA350_DCC2 0x2a +#define STA350_FDRC1 0x2b +#define STA350_FDRC2 0x2c +#define STA350_STATUS 0x2d +/* reserved: 0x2d - 0x30 */ +#define STA350_EQCFG 0x31 +#define STA350_EATH1 0x32 +#define STA350_ERTH1 0x33 +#define STA350_EATH2 0x34 +#define STA350_ERTH2 0x35 +#define STA350_CONFX 0x36 +#define STA350_SVCA 0x37 +#define STA350_SVCB 0x38 +#define STA350_RMS0A 0x39 +#define STA350_RMS0B 0x3a +#define STA350_RMS0C 0x3b +#define STA350_RMS1A 0x3c +#define STA350_RMS1B 0x3d +#define STA350_RMS1C 0x3e +#define STA350_EVOLRES 0x3f +/* reserved: 0x40 - 0x47 */ +#define STA350_NSHAPE 0x48 +#define STA350_CTXB4B1 0x49 +#define STA350_CTXB7B5 0x4a +#define STA350_MISC1 0x4b +#define STA350_MISC2 0x4c + +/* 0x00 CONFA */ +#define STA350_CONFA_MCS_MASK 0x03 +#define STA350_CONFA_MCS_SHIFT 0 +#define STA350_CONFA_IR_MASK 0x18 +#define STA350_CONFA_IR_SHIFT 3 +#define STA350_CONFA_TWRB BIT(5) +#define STA350_CONFA_TWAB BIT(6) +#define STA350_CONFA_FDRB BIT(7) + +/* 0x01 CONFB */ +#define STA350_CONFB_SAI_MASK 0x0f +#define STA350_CONFB_SAI_SHIFT 0 +#define STA350_CONFB_SAIFB BIT(4) +#define STA350_CONFB_DSCKE BIT(5) +#define STA350_CONFB_C1IM BIT(6) +#define STA350_CONFB_C2IM BIT(7) + +/* 0x02 CONFC */ +#define STA350_CONFC_OM_MASK 0x03 +#define STA350_CONFC_OM_SHIFT 0 +#define STA350_CONFC_CSZ_MASK 0x3c +#define STA350_CONFC_CSZ_SHIFT 2 +#define STA350_CONFC_OCRB BIT(7) + +/* 0x03 CONFD */ +#define STA350_CONFD_HPB_SHIFT 0 +#define STA350_CONFD_DEMP_SHIFT 1 +#define STA350_CONFD_DSPB_SHIFT 2 +#define STA350_CONFD_PSL_SHIFT 3 +#define STA350_CONFD_BQL_SHIFT 4 +#define STA350_CONFD_DRC_SHIFT 5 +#define STA350_CONFD_ZDE_SHIFT 6 +#define STA350_CONFD_SME_SHIFT 7 + +/* 0x04 CONFE */ +#define STA350_CONFE_MPCV BIT(0) +#define STA350_CONFE_MPCV_SHIFT 0 +#define STA350_CONFE_MPC BIT(1) +#define STA350_CONFE_MPC_SHIFT 1 +#define STA350_CONFE_NSBW BIT(2) +#define STA350_CONFE_NSBW_SHIFT 2 +#define STA350_CONFE_AME BIT(3) +#define STA350_CONFE_AME_SHIFT 3 +#define STA350_CONFE_PWMS BIT(4) +#define STA350_CONFE_PWMS_SHIFT 4 +#define STA350_CONFE_DCCV BIT(5) +#define STA350_CONFE_DCCV_SHIFT 5 +#define STA350_CONFE_ZCE BIT(6) +#define STA350_CONFE_ZCE_SHIFT 6 +#define STA350_CONFE_SVE BIT(7) +#define STA350_CONFE_SVE_SHIFT 7 + +/* 0x05 CONFF */ +#define STA350_CONFF_OCFG_MASK 0x03 +#define STA350_CONFF_OCFG_SHIFT 0 +#define STA350_CONFF_IDE BIT(2) +#define STA350_CONFF_BCLE BIT(3) +#define STA350_CONFF_LDTE BIT(4) +#define STA350_CONFF_ECLE BIT(5) +#define STA350_CONFF_PWDN BIT(6) +#define STA350_CONFF_EAPD BIT(7) + +/* 0x06 MMUTE */ +#define STA350_MMUTE_MMUTE 0x01 +#define STA350_MMUTE_MMUTE_SHIFT 0 +#define STA350_MMUTE_C1M 0x02 +#define STA350_MMUTE_C1M_SHIFT 1 +#define STA350_MMUTE_C2M 0x04 +#define STA350_MMUTE_C2M_SHIFT 2 +#define STA350_MMUTE_C3M 0x08 +#define STA350_MMUTE_C3M_SHIFT 3 +#define STA350_MMUTE_LOC_MASK 0xC0 +#define STA350_MMUTE_LOC_SHIFT 6 + +/* 0x0b AUTO1 */ +#define STA350_AUTO1_AMGC_MASK 0x30 +#define STA350_AUTO1_AMGC_SHIFT 4 + +/* 0x0c AUTO2 */ +#define STA350_AUTO2_AMAME 0x01 +#define STA350_AUTO2_AMAM_MASK 0x0e +#define STA350_AUTO2_AMAM_SHIFT 1 +#define STA350_AUTO2_XO_MASK 0xf0 +#define STA350_AUTO2_XO_SHIFT 4 + +/* 0x0d AUTO3 */ +#define STA350_AUTO3_PEQ_MASK 0x1f +#define STA350_AUTO3_PEQ_SHIFT 0 + +/* 0x0e 0x0f 0x10 CxCFG */ +#define STA350_CxCFG_TCB_SHIFT 0 +#define STA350_CxCFG_EQBP_SHIFT 1 +#define STA350_CxCFG_VBP_SHIFT 2 +#define STA350_CxCFG_BO_SHIFT 3 +#define STA350_CxCFG_LS_SHIFT 4 +#define STA350_CxCFG_OM_MASK 0xc0 +#define STA350_CxCFG_OM_SHIFT 6 + +/* 0x11 TONE */ +#define STA350_TONE_BTC_SHIFT 0 +#define STA350_TONE_TTC_SHIFT 4 + +/* 0x12 0x13 0x14 0x15 limiter attack/release */ +#define STA350_LxA_SHIFT 0 +#define STA350_LxR_SHIFT 4 + +/* 0x26 CFUD */ +#define STA350_CFUD_W1 0x01 +#define STA350_CFUD_WA 0x02 +#define STA350_CFUD_R1 0x04 +#define STA350_CFUD_RA 0x08 + + +/* biquad filter coefficient table offsets */ +#define STA350_C1_BQ_BASE 0 +#define STA350_C2_BQ_BASE 20 +#define STA350_CH_BQ_NUM 4 +#define STA350_BQ_NUM_COEF 5 +#define STA350_XO_HP_BQ_BASE 40 +#define STA350_XO_LP_BQ_BASE 45 +#define STA350_C1_PRESCALE 50 +#define STA350_C2_PRESCALE 51 +#define STA350_C1_POSTSCALE 52 +#define STA350_C2_POSTSCALE 53 +#define STA350_C3_POSTSCALE 54 +#define STA350_TW_POSTSCALE 55 +#define STA350_C1_MIX1 56 +#define STA350_C1_MIX2 57 +#define STA350_C2_MIX1 58 +#define STA350_C2_MIX2 59 +#define STA350_C3_MIX1 60 +#define STA350_C3_MIX2 61 + +/* miscellaneous register 1 */ +#define STA350_MISC1_CPWMEN BIT(2) +#define STA350_MISC1_BRIDGOFF BIT(5) +#define STA350_MISC1_NSHHPEN BIT(6) +#define STA350_MISC1_RPDNEN BIT(7) + +/* miscellaneous register 2 */ +#define STA350_MISC2_PNDLSL_MASK 0x1c +#define STA350_MISC2_PNDLSL_SHIFT 2 + +#endif /* _ASOC_STA_350_H */ diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index a895a5e4bdf207..d48491a4a19db9 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -272,7 +272,7 @@ static int tas5086_set_deemph(struct snd_soc_codec *codec) static int tas5086_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = priv->deemph; @@ -283,7 +283,7 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol, static int tas5086_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); priv->deemph = ucontrol->value.enumerated.item[0]; diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c index b73c94ebcc2a0d..f137019954828f 100644 --- a/sound/soc/codecs/tlv320aic23-i2c.c +++ b/sound/soc/codecs/tlv320aic23-i2c.c @@ -13,6 +13,7 @@ #include #include +#include #include #include diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 20864ee8793b5e..686b8b85b95696 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -82,7 +82,7 @@ static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0); static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); u16 val, reg; val = (ucontrol->value.integer.value[0] & 0x07); @@ -105,7 +105,7 @@ static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol, static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); u16 val; val = snd_soc_read(codec, TLV320AIC23_ANLG) & (0x1C0); diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index fa158cfe9b32d3..23419109ecac10 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -376,7 +377,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w, reg = AIC31XX_ADCFLAG; break; default: - dev_err(w->codec->dev, "Unknown widget '%s' calling %s/n", + dev_err(w->codec->dev, "Unknown widget '%s' calling %s\n", w->name, __func__); return -EINVAL; } diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 6bfc8a17331b05..df3a7506c023b5 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -442,7 +442,7 @@ static int dac33_playback_event(struct snd_soc_dapm_widget *w, static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = dac33->fifo_mode; @@ -453,7 +453,7 @@ static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol, static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); int ret = 0; @@ -1540,7 +1540,7 @@ static int dac33_i2c_probe(struct i2c_client *client, for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++) dac33->supplies[i].supply = dac33_supply_names[i]; - ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies), + ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies), dac33->supplies); if (ret != 0) { @@ -1551,11 +1551,9 @@ static int dac33_i2c_probe(struct i2c_client *client, ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_tlv320dac33, &dac33_dai, 1); if (ret < 0) - goto err_register; + goto err_get; return ret; -err_register: - regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies); err_get: if (dac33->power_gpio >= 0) gpio_free(dac33->power_gpio); @@ -1573,8 +1571,6 @@ static int dac33_i2c_remove(struct i2c_client *client) if (dac33->power_gpio >= 0) gpio_free(dac33->power_gpio); - regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies); - snd_soc_unregister_codec(&client->dev); return 0; } diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index b27c396037d4af..8fc5a647453b61 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "tpa6130a2.h" diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 975e0f760ac1b7..69e12a311ba200 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -830,7 +830,7 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int shift = mc->shift; unsigned int rshift = mc->rshift; @@ -859,7 +859,7 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int shift = mc->shift; unsigned int rshift = mc->rshift; @@ -888,7 +888,7 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; @@ -915,7 +915,7 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; @@ -956,7 +956,7 @@ static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum, static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); if (twl4030->configured) { diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index bd3a20647fdff0..0f6067f04e291f 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -484,7 +484,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum, static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = priv->hs_power_mode; @@ -495,7 +495,7 @@ static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol, static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); int high_perf = ucontrol->value.enumerated.item[0]; int ret = 0; @@ -512,7 +512,7 @@ static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol, static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = priv->pll_power_mode; @@ -523,7 +523,7 @@ static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol, static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); priv->pll_power_mode = ucontrol->value.enumerated.item[0]; diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index 6be5f80b65f1ad..4ead0dc02b8742 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -172,7 +172,7 @@ static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core, static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wl1273->mode; @@ -190,7 +190,7 @@ static const char * const wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" }; static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); if (wl1273->mode == ucontrol->value.integer.value[0]) @@ -214,7 +214,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route); static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: enter.\n", __func__); @@ -227,7 +227,7 @@ static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol, static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); int val, r = 0; @@ -251,7 +251,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings); static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: enter.\n", __func__); @@ -264,7 +264,7 @@ static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol, static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); int r; diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 83a2c872925c4b..a4c352cc346495 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -607,7 +607,7 @@ static int wm2000_anc_set_mode(struct wm2000_priv *wm2000) static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); ucontrol->value.enumerated.item[0] = wm2000->anc_active; @@ -618,7 +618,7 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol, static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); int anc_active = ucontrol->value.enumerated.item[0]; int ret; @@ -640,7 +640,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); ucontrol->value.enumerated.item[0] = wm2000->spk_ena; @@ -651,7 +651,7 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, static int wm2000_speaker_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); int val = ucontrol->value.enumerated.item[0]; int ret; diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 2e721e06671bd2..cdea9d9c16317f 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1083,7 +1083,7 @@ static int wm2200_mixer_values[] = { #define WM2200_MUX_CTL_DECL(name) \ const struct snd_kcontrol_new name##_mux = \ - SOC_DAPM_VALUE_ENUM("Route", name##_enum) + SOC_DAPM_ENUM("Route", name##_enum) #define WM2200_MIXER_ENUMS(name, base_reg) \ static WM2200_MUX_ENUM_DECL(name##_in1_enum, base_reg); \ @@ -1207,7 +1207,7 @@ WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE); WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE); #define WM2200_MUX(name, ctrl) \ - SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) #define WM2200_MIXER_WIDGETS(name, name_str) \ WM2200_MUX(name_str " Input 1", &name##_in1_mux), \ diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index eca983fad8918e..91a9ea2a205679 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -390,7 +390,7 @@ static int wm5100_mixer_values[] = { #define WM5100_MUX_CTL_DECL(name) \ const struct snd_kcontrol_new name##_mux = \ - SOC_DAPM_VALUE_ENUM("Route", name##_enum) + SOC_DAPM_ENUM("Route", name##_enum) #define WM5100_MIXER_ENUMS(name, base_reg) \ static WM5100_MUX_ENUM_DECL(name##_in1_enum, base_reg); \ @@ -448,7 +448,7 @@ WM5100_MIXER_ENUMS(LHPF3, WM5100_HPLP3MIX_INPUT_1_SOURCE); WM5100_MIXER_ENUMS(LHPF4, WM5100_HPLP4MIX_INPUT_1_SOURCE); #define WM5100_MUX(name, ctrl) \ - SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) #define WM5100_MIXER_WIDGETS(name, name_str) \ WM5100_MUX(name_str " Input 1", &name##_in1_mux), \ diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index dcf1d12cfef8f7..289b64d89abd46 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -764,8 +764,8 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), -SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), -SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), @@ -814,9 +814,9 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L, ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]), -SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]), -SOC_VALUE_ENUM("EPOUT OSR", wm5102_hpout_osr[2]), +SOC_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]), +SOC_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]), +SOC_ENUM("EPOUT OSR", wm5102_hpout_osr[2]), SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE, ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0), @@ -970,7 +970,7 @@ static const struct soc_enum wm5102_aec_loopback = wm5102_aec_loopback_values); static const struct snd_kcontrol_new wm5102_aec_loopback_mux = - SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5102_aec_loopback); + SOC_DAPM_ENUM("AEC Loopback", wm5102_aec_loopback); static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, @@ -1204,7 +1204,7 @@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, ARIZONA_DSP_WIDGETS(DSP1, "DSP1"), -SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, +SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm5102_aec_loopback_mux), @@ -1760,10 +1760,6 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); int ret; - ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap); - if (ret != 0) - return ret; - ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2); if (ret != 0) return ret; @@ -1802,9 +1798,17 @@ static unsigned int wm5102_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_5R, }; +static struct regmap *wm5102_get_regmap(struct device *dev) +{ + struct wm5102_priv *priv = dev_get_drvdata(dev); + + return priv->core.arizona->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_wm5102 = { .probe = wm5102_codec_probe, .remove = wm5102_codec_remove, + .get_regmap = wm5102_get_regmap, .idle_bias_off = true, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index df5a38dd8328db..2e5fcb559e9000 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -324,13 +324,13 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), -SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), -SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), -SOC_VALUE_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]), -SOC_VALUE_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]), -SOC_VALUE_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]), -SOC_VALUE_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]), -SOC_VALUE_ENUM("ASRC RATE 1", arizona_asrc_rate1), +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]), +SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]), +SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]), +SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]), +SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1), ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE), @@ -367,6 +367,11 @@ SOC_SINGLE("HPOUT2 SC Protect Switch", ARIZONA_HP2_SHORT_CIRCUIT_CTRL, SOC_SINGLE("HPOUT3 SC Protect Switch", ARIZONA_HP3_SHORT_CIRCUIT_CTRL, ARIZONA_HP3_SC_ENA_SHIFT, 1, 0), +SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L, + ARIZONA_OUT5_OSR_SHIFT, 1, 0), +SOC_SINGLE("SPKDAT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_6L, + ARIZONA_OUT6_OSR_SHIFT, 1, 0), + SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L, ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1), SOC_DOUBLE_R("HPOUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L, @@ -592,7 +597,7 @@ static const struct soc_enum wm5110_aec_loopback = wm5110_aec_loopback_values); static const struct snd_kcontrol_new wm5110_aec_loopback_mux = - SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5110_aec_loopback); + SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback); static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, @@ -774,7 +779,7 @@ SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3, SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3, ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, +SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm5110_aec_loopback_mux), @@ -1589,10 +1594,6 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) priv->core.arizona->dapm = &codec->dapm; - ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap); - if (ret != 0) - return ret; - arizona_init_spk(codec); arizona_init_gpio(codec); @@ -1633,9 +1634,17 @@ static unsigned int wm5110_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_6R, }; +static struct regmap *wm5110_get_regmap(struct device *dev) +{ + struct wm5110_priv *priv = dev_get_drvdata(dev); + + return priv->core.arizona->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_wm5110 = { .probe = wm5110_codec_probe, .remove = wm5110_codec_remove, + .get_regmap = wm5110_get_regmap, .idle_bias_off = true, diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 757256bf7672ef..392285edb59545 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -302,7 +302,7 @@ static int pga_event(struct snd_soc_dapm_widget *w, static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out = NULL; struct soc_mixer_control *mc = @@ -345,7 +345,7 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol, static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out1 = &wm8350_priv->out1; struct wm8350_output *out2 = &wm8350_priv->out2; @@ -1505,8 +1505,6 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) if (ret != 0) return ret; - snd_soc_codec_set_cache_io(codec, wm8350->regmap); - /* Put the codec into reset if it wasn't already */ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); @@ -1608,11 +1606,19 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) return 0; } +static struct regmap *wm8350_get_regmap(struct device *dev) +{ + struct wm8350 *wm8350 = dev_get_platdata(dev); + + return wm8350->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_wm8350 = { .probe = wm8350_codec_probe, .remove = wm8350_codec_remove, .suspend = wm8350_suspend, .resume = wm8350_resume, + .get_regmap = wm8350_get_regmap, .set_bias_level = wm8350_set_bias_level, .controls = wm8350_snd_controls, diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 146564feaea041..06e913d3fea15b 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -93,7 +93,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0); static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; int reg = mc->reg; @@ -1318,8 +1318,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) priv->wm8400 = wm8400; priv->codec = codec; - snd_soc_codec_set_cache_io(codec, wm8400->regmap); - ret = devm_regulator_bulk_get(wm8400->dev, ARRAY_SIZE(power), &power[0]); if (ret != 0) { @@ -1361,11 +1359,19 @@ static int wm8400_codec_remove(struct snd_soc_codec *codec) return 0; } +static struct regmap *wm8400_get_regmap(struct device *dev) +{ + struct wm8400 *wm8400 = dev_get_platdata(dev); + + return wm8400->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_wm8400 = { .probe = wm8400_codec_probe, .remove = wm8400_codec_remove, .suspend = wm8400_suspend, .resume = wm8400_resume, + .get_regmap = wm8400_get_regmap, .set_bias_level = wm8400_set_bias_level, .controls = wm8400_snd_controls, diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index af7ed8b5d4e187..7665ff6aea6de9 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -252,7 +252,7 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index d74f43975b90fb..5ada616113240e 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -119,7 +119,7 @@ static int wm8731_set_deemph(struct snd_soc_codec *codec) static int wm8731_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8731->deemph; @@ -130,7 +130,7 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol, static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; int ret = 0; @@ -586,7 +586,7 @@ static int wm8731_probe(struct snd_soc_codec *codec) for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++) wm8731->supplies[i].supply = wm8731_supply_names[i]; - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies), + ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies), wm8731->supplies); if (ret != 0) { dev_err(codec->dev, "Failed to request supplies: %d\n", ret); @@ -597,7 +597,7 @@ static int wm8731_probe(struct snd_soc_codec *codec) wm8731->supplies); if (ret != 0) { dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - goto err_regulator_get; + return ret; } ret = wm8731_reset(codec); @@ -624,8 +624,6 @@ static int wm8731_probe(struct snd_soc_codec *codec) err_regulator_enable: regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); -err_regulator_get: - regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); return ret; } @@ -638,7 +636,6 @@ static int wm8731_remove(struct snd_soc_codec *codec) wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); - regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); return 0; } diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index cbb8d55052a44a..53e57b4049a8f5 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -234,7 +234,7 @@ SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase), static int wm8753_get_dai(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wm8753->dai_func; @@ -244,7 +244,7 @@ static int wm8753_get_dai(struct snd_kcontrol *kcontrol, static int wm8753_set_dai(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); u16 ioctl; diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index ee76f0fb429967..bbcad9ff3c989d 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -106,7 +106,7 @@ static int txsrc_get(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec; unsigned int src; - codec = snd_kcontrol_chip(kcontrol); + codec = snd_soc_kcontrol_codec(kcontrol); src = snd_soc_read(codec, WM8804_SPDTX4); if (src & 0x40) ucontrol->value.integer.value[0] = 1; @@ -122,7 +122,7 @@ static int txsrc_put(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec; unsigned int src, txpwr; - codec = snd_kcontrol_chip(kcontrol); + codec = snd_soc_kcontrol_codec(kcontrol); if (ucontrol->value.integer.value[0] != 0 && ucontrol->value.integer.value[0] != 1) @@ -535,7 +535,6 @@ static int wm8804_remove(struct snd_soc_codec *codec) for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) regulator_unregister_notifier(wm8804->supplies[i].consumer, &wm8804->disable_nb[i]); - regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies); return 0; } @@ -549,7 +548,7 @@ static int wm8804_probe(struct snd_soc_codec *codec) for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) wm8804->supplies[i].supply = wm8804_supply_names[i]; - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies), + ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies), wm8804->supplies); if (ret) { dev_err(codec->dev, "Failed to request supplies: %d\n", ret); @@ -574,7 +573,7 @@ static int wm8804_probe(struct snd_soc_codec *codec) wm8804->supplies); if (ret) { dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - goto err_reg_get; + return ret; } id1 = snd_soc_read(codec, WM8804_RST_DEVID1); @@ -619,8 +618,6 @@ static int wm8804_probe(struct snd_soc_codec *codec) err_reg_enable: regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies); -err_reg_get: - regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies); return ret; } diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index b0084a127d18c6..b84940c359a127 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -439,7 +439,7 @@ static int wm8903_set_deemph(struct snd_soc_codec *codec) static int wm8903_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8903->deemph; @@ -450,7 +450,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol, static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; int ret = 0; diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 49c35c36935e45..f7c549949c5422 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -391,7 +391,7 @@ static void wm8904_set_drc(struct snd_soc_codec *codec) static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); struct wm8904_pdata *pdata = wm8904->pdata; int value = ucontrol->value.integer.value[0]; @@ -409,7 +409,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol, static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8904->drc_cfg; @@ -462,7 +462,7 @@ static void wm8904_set_retune_mobile(struct snd_soc_codec *codec) static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); struct wm8904_pdata *pdata = wm8904->pdata; int value = ucontrol->value.integer.value[0]; @@ -480,7 +480,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg; @@ -520,7 +520,7 @@ static int wm8904_set_deemph(struct snd_soc_codec *codec) static int wm8904_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8904->deemph; @@ -530,7 +530,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol, static int wm8904_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; @@ -570,7 +570,7 @@ static SOC_ENUM_SINGLE_DECL(hpf_mode, WM8904_ADC_DIGITAL_0, 5, static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int val; int ret; diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index fecd4e4f4c5731..2a35108f233dee 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -390,7 +390,7 @@ static int wm8955_set_deemph(struct snd_soc_codec *codec) static int wm8955_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8955->deemph; @@ -400,7 +400,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol, static int wm8955_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; @@ -898,7 +898,7 @@ static int wm8955_probe(struct snd_soc_codec *codec) for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++) wm8955->supplies[i].supply = wm8955_supply_names[i]; - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies), + ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies), wm8955->supplies); if (ret != 0) { dev_err(codec->dev, "Failed to request supplies: %d\n", ret); @@ -909,7 +909,7 @@ static int wm8955_probe(struct snd_soc_codec *codec) wm8955->supplies); if (ret != 0) { dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - goto err_get; + return ret; } ret = wm8955_reset(codec); @@ -961,17 +961,12 @@ static int wm8955_probe(struct snd_soc_codec *codec) err_enable: regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); -err_get: - regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); return ret; } static int wm8955_remove(struct snd_soc_codec *codec) { - struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); - wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); - regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); return 0; } diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 7ac2e511403ce5..b2ebb104d8794f 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -456,7 +456,7 @@ static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif) static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; @@ -478,7 +478,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg; @@ -500,7 +500,7 @@ static int wm8958_mbc_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int mbc = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc]; @@ -512,7 +512,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int mbc = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0]) @@ -546,7 +546,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol, static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; @@ -568,7 +568,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8994->vss_cfg; @@ -579,7 +579,7 @@ static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol, static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; @@ -601,7 +601,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg; @@ -623,7 +623,7 @@ static int wm8958_vss_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int vss = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wm8994->vss_ena[vss]; @@ -635,7 +635,7 @@ static int wm8958_vss_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int vss = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0]) @@ -684,7 +684,7 @@ static int wm8958_hpf_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int hpf = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (hpf < 3) @@ -699,7 +699,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int hpf = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (hpf < 3) { @@ -746,7 +746,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol, static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; @@ -768,7 +768,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg; @@ -790,7 +790,7 @@ static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int eq = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq]; @@ -802,7 +802,7 @@ static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int eq = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0]) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index d04e9cad445c39..a145d0431b63db 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -178,7 +178,7 @@ static int wm8960_set_deemph(struct snd_soc_codec *codec) static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8960->deemph; @@ -188,7 +188,7 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, static int wm8960_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 5522d2566c6742..b77e4c3e8484db 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -74,11 +74,9 @@ struct wm8962_priv { struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES]; struct notifier_block disable_nb[WM8962_NUM_SUPPLIES]; -#if IS_ENABLED(CONFIG_INPUT) struct input_dev *beep; struct work_struct beep_work; int beep_rate; -#endif #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; @@ -1552,7 +1550,7 @@ static int wm8962_dsp2_ena_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int shift = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = !!(wm8962->dsp2_ena & 1 << shift); @@ -1564,7 +1562,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int shift = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); int old = wm8962->dsp2_ena; int ret = 0; @@ -1602,7 +1600,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int ret; /* Apply the update (if any) */ @@ -1632,7 +1630,7 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol, static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int ret; /* Apply the update (if any) */ @@ -3145,7 +3143,6 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) } EXPORT_SYMBOL_GPL(wm8962_mic_detect); -#if IS_ENABLED(CONFIG_INPUT) static int beep_rates[] = { 500, 1000, 2000, 4000, }; @@ -3277,15 +3274,6 @@ static void wm8962_free_beep(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0); } -#else -static void wm8962_init_beep(struct snd_soc_codec *codec) -{ -} - -static void wm8962_free_beep(struct snd_soc_codec *codec) -{ -} -#endif static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio) { diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index 2b9bfa53efbfee..19d5baa38f5c15 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -552,7 +552,7 @@ static const struct snd_soc_dapm_route wm8983_audio_map[] = { static int eqmode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg; reg = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF); @@ -567,7 +567,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol, static int eqmode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int regpwr2, regpwr3; unsigned int reg_eq; diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 5473dc969585de..0f5780c09f3a9a 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -526,7 +526,7 @@ static const struct snd_soc_dapm_route wm8985_dapm_routes[] = { static int eqmode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg; reg = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF); @@ -541,7 +541,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol, static int eqmode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int regpwr2, regpwr3; unsigned int reg_eq; @@ -984,7 +984,6 @@ static int wm8985_remove(struct snd_soc_codec *codec) wm8985 = snd_soc_codec_get_drvdata(codec); wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF); - regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies); return 0; } @@ -999,7 +998,7 @@ static int wm8985_probe(struct snd_soc_codec *codec) for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++) wm8985->supplies[i].supply = wm8985_supply_names[i]; - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies), + ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies), wm8985->supplies); if (ret) { dev_err(codec->dev, "Failed to request supplies: %d\n", ret); @@ -1010,7 +1009,7 @@ static int wm8985_probe(struct snd_soc_codec *codec) wm8985->supplies); if (ret) { dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - goto err_reg_get; + return ret; } ret = wm8985_reset(codec); @@ -1032,8 +1031,6 @@ static int wm8985_probe(struct snd_soc_codec *codec) err_reg_enable: regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies), wm8985->supplies); -err_reg_get: - regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies); return ret; } diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 3a1ae4f5164df1..d3fea46d58e85c 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -268,7 +268,7 @@ static const struct soc_enum wm8988_lline_enum = wm8988_line_texts, wm8988_line_values); static const struct snd_kcontrol_new wm8988_left_line_controls = - SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum); + SOC_DAPM_ENUM("Route", wm8988_lline_enum); static const struct soc_enum wm8988_rline_enum = SOC_VALUE_ENUM_SINGLE(WM8988_ROUTM1, 0, 7, @@ -276,7 +276,7 @@ static const struct soc_enum wm8988_rline_enum = wm8988_line_texts, wm8988_line_values); static const struct snd_kcontrol_new wm8988_right_line_controls = - SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum); + SOC_DAPM_ENUM("Route", wm8988_lline_enum); /* Left Mixer */ static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = { @@ -304,7 +304,7 @@ static const struct soc_enum wm8988_lpga_enum = wm8988_pga_sel, wm8988_pga_val); static const struct snd_kcontrol_new wm8988_left_pga_controls = - SOC_DAPM_VALUE_ENUM("Route", wm8988_lpga_enum); + SOC_DAPM_ENUM("Route", wm8988_lpga_enum); /* Right PGA Mux */ static const struct soc_enum wm8988_rpga_enum = @@ -313,7 +313,7 @@ static const struct soc_enum wm8988_rpga_enum = wm8988_pga_sel, wm8988_pga_val); static const struct snd_kcontrol_new wm8988_right_pga_controls = - SOC_DAPM_VALUE_ENUM("Route", wm8988_rpga_enum); + SOC_DAPM_ENUM("Route", wm8988_rpga_enum); /* Differential Mux */ static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"}; diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index c413c19914534c..b5c1f0f070585b 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -132,7 +132,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0); static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; int reg = mc->reg; diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 844cc4a60d667e..b8fd284fc0c023 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -154,7 +154,7 @@ static const unsigned int out_sidetone_tlv[] = { static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int reg = kcontrol->private_value & 0xff; int ret; u16 val; diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 6303537f54c6d0..247b39013fba68 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -298,7 +298,7 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int mask, ret; /* Can't enable both ADC and DAC paths simultaneously */ @@ -355,7 +355,7 @@ static int wm8994_get_drc(const char *name) static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; struct wm8994_pdata *pdata = &control->pdata; @@ -378,7 +378,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int drc = wm8994_get_drc(kcontrol->id.name); @@ -462,7 +462,7 @@ static int wm8994_get_retune_mobile_block(const char *name) static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; struct wm8994_pdata *pdata = &control->pdata; @@ -485,7 +485,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int block = wm8994_get_retune_mobile_block(kcontrol->id.name); @@ -1347,10 +1347,10 @@ static const char *adc_mux_text[] = { static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text); static const struct snd_kcontrol_new adcl_mux = - SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); + SOC_DAPM_ENUM("ADCL Mux", adc_enum); static const struct snd_kcontrol_new adcr_mux = - SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum); + SOC_DAPM_ENUM("ADCR Mux", adc_enum); static const struct snd_kcontrol_new left_speaker_mixer[] = { SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 9, 1, 0), @@ -1651,15 +1651,15 @@ SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0), }; static const struct snd_soc_dapm_widget wm8994_adc_revd_widgets[] = { -SND_SOC_DAPM_VIRT_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux, +SND_SOC_DAPM_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux, adc_mux_ev, SND_SOC_DAPM_PRE_PMU), -SND_SOC_DAPM_VIRT_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux, +SND_SOC_DAPM_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux, adc_mux_ev, SND_SOC_DAPM_PRE_PMU), }; static const struct snd_soc_dapm_widget wm8994_adc_widgets[] = { -SND_SOC_DAPM_VIRT_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux), -SND_SOC_DAPM_VIRT_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux), +SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux), +SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux), }; static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { @@ -3999,8 +3999,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->hubs.codec = codec; - snd_soc_codec_set_cache_io(codec, control->regmap); - mutex_init(&wm8994->accdet_lock); INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap, wm1811_jackdet_bootstrap); @@ -4434,11 +4432,19 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) return 0; } +static struct regmap *wm8994_get_regmap(struct device *dev) +{ + struct wm8994 *control = dev_get_drvdata(dev->parent); + + return control->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_wm8994 = { .probe = wm8994_codec_probe, .remove = wm8994_codec_remove, .suspend = wm8994_codec_suspend, .resume = wm8994_codec_resume, + .get_regmap = wm8994_get_regmap, .set_bias_level = wm8994_set_bias_level, }; diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index d3152cf5bd5607..863a2c38bcb593 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -885,10 +885,10 @@ static const char *adc_mux_text[] = { static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text); static const struct snd_kcontrol_new adcl_mux = - SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); + SOC_DAPM_ENUM("ADCL Mux", adc_enum); static const struct snd_kcontrol_new adcr_mux = - SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum); + SOC_DAPM_ENUM("ADCR Mux", adc_enum); static const char *spk_src_text[] = { "DAC1L", "DAC1R", "DAC2L", "DAC2R" @@ -948,10 +948,8 @@ static const struct snd_soc_dapm_widget wm8995_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", "AIF1 Capture", 0, WM8995_POWER_MANAGEMENT_3, 10, 0), - SND_SOC_DAPM_VIRT_MUX("ADCL Mux", SND_SOC_NOPM, 1, 0, - &adcl_mux), - SND_SOC_DAPM_VIRT_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0, - &adcr_mux), + SND_SOC_DAPM_MUX("ADCL Mux", SND_SOC_NOPM, 1, 0, &adcl_mux), + SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0, &adcr_mux), SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8995_POWER_MANAGEMENT_3, 5, 0), SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8995_POWER_MANAGEMENT_3, 4, 0), diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index c6cbb3b8ace96a..69266332760eba 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -412,7 +412,7 @@ static int wm8996_get_retune_mobile_block(const char *name) static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); struct wm8996_pdata *pdata = &wm8996->pdata; int block = wm8996_get_retune_mobile_block(kcontrol->id.name); @@ -434,7 +434,7 @@ static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); int block = wm8996_get_retune_mobile_block(kcontrol->id.name); diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 004186b6bd4813..bb9b47b956aa51 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -245,8 +245,8 @@ SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), -SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), -SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), @@ -286,8 +286,8 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L, ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_VALUE_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]), -SOC_VALUE_ENUM("EPOUT OSR", wm8997_hpout_osr[1]), +SOC_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]), +SOC_ENUM("EPOUT OSR", wm8997_hpout_osr[1]), SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), @@ -405,7 +405,7 @@ static const struct soc_enum wm8997_aec_loopback = wm8997_aec_loopback_values); static const struct snd_kcontrol_new wm8997_aec_loopback_mux = - SOC_DAPM_VALUE_ENUM("AEC Loopback", wm8997_aec_loopback); + SOC_DAPM_ENUM("AEC Loopback", wm8997_aec_loopback); static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, @@ -604,7 +604,7 @@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX8_ENA_SHIFT, 0), -SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, +SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm8997_aec_loopback_mux), @@ -1051,11 +1051,6 @@ static struct snd_soc_dai_driver wm8997_dai[] = { static int wm8997_codec_probe(struct snd_soc_codec *codec) { struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec); - int ret; - - ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap); - if (ret != 0) - return ret; arizona_init_spk(codec); @@ -1086,9 +1081,17 @@ static unsigned int wm8997_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_5R, }; +static struct regmap *wm8997_get_regmap(struct device *dev) +{ + struct wm8997_priv *priv = dev_get_drvdata(dev); + + return priv->core.arizona->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_wm8997 = { .probe = wm8997_codec_probe, .remove = wm8997_codec_remove, + .get_regmap = wm8997_get_regmap, .idle_bias_off = true, diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index d18eff31fbbc61..185eb97769e730 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -340,7 +340,7 @@ static SOC_ENUM_SINGLE_DECL(speaker_mode, WM9081_ANALOGUE_SPEAKER_2, 6, static int speaker_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg; reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2); @@ -361,7 +361,7 @@ static int speaker_mode_get(struct snd_kcontrol *kcontrol, static int speaker_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg_pwr = snd_soc_read(codec, WM9081_POWER_MANAGEMENT); unsigned int reg2 = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2); diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index bb5f7b4e3ebbfe..ff15eec3ab2fc8 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -242,7 +242,7 @@ struct wm_coeff_ctl { static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); @@ -254,7 +254,7 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); @@ -1625,7 +1625,7 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, break; default: break; - }; + } return 0; } diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index b6209662ab13f8..916817fe6632f5 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -337,7 +337,7 @@ static void enable_dc_servo(struct snd_soc_codec *codec) static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); int ret; diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index a8ec1fc3e4d09a..50a098749b9e21 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -18,7 +18,7 @@ config SND_DAVINCI_SOC_GENERIC_EVM config SND_AM33XX_SOC_EVM tristate "SoC Audio for the AM33XX chip based boards" - depends on SND_DAVINCI_SOC && SOC_AM33XX + depends on SND_DAVINCI_SOC && SOC_AM33XX && I2C select SND_DAVINCI_SOC_GENERIC_EVM help Say Y or M if you want to add support for SoC audio on AM33XX @@ -28,7 +28,7 @@ config SND_AM33XX_SOC_EVM config SND_DAVINCI_SOC_EVM tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM" - depends on SND_DAVINCI_SOC + depends on SND_DAVINCI_SOC && I2C depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM select SND_DAVINCI_SOC_GENERIC_EVM help @@ -56,7 +56,7 @@ endchoice config SND_DM6467_SOC_EVM tristate "SoC Audio support for DaVinci DM6467 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM + depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM && I2C select SND_DAVINCI_SOC_GENERIC_EVM select SND_SOC_SPDIF @@ -65,7 +65,7 @@ config SND_DM6467_SOC_EVM config SND_DA830_SOC_EVM tristate "SoC Audio support for DA830/OMAP-L137 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM + depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM && I2C select SND_DAVINCI_SOC_GENERIC_EVM help @@ -74,7 +74,7 @@ config SND_DA830_SOC_EVM config SND_DA850_SOC_EVM tristate "SoC Audio support for DA850/OMAP-L138 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM + depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM && I2C select SND_DAVINCI_SOC_GENERIC_EVM help Say Y if you want to add support for SoC audio on TI diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index ebe82947bab36d..7682af31d6e6f6 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -757,7 +757,6 @@ static int davinci_i2s_remove(struct platform_device *pdev) struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev); snd_soc_unregister_component(&pdev->dev); - davinci_soc_platform_unregister(&pdev->dev); clk_disable(dev->clk); clk_put(dev->clk); diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 4f75cac462d157..14058dc6eaf8a9 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -36,6 +36,9 @@ #include "davinci-pcm.h" #include "davinci-mcasp.h" +#include "../omap/omap-pcm.h" + +#define MCASP_MAX_AFIFO_DEPTH 64 struct davinci_mcasp_context { u32 txfmtctl; @@ -269,25 +272,51 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); int ret = 0; + u32 data_delay; + bool fs_pol_rising; + bool inv_fs = false; pm_runtime_get_sync(mcasp->dev); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + /* 1st data bit occur one ACLK cycle after the frame sync */ + data_delay = 1; + break; case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_AC97: mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + /* No delay after FS */ + data_delay = 0; break; - default: + case SND_SOC_DAIFMT_I2S: /* configure a full-word SYNC pulse (LRCLK) */ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); - - /* make 1st data bit occur one ACLK cycle after the frame sync */ - mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(1)); - mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(1)); + /* 1st data bit occur one ACLK cycle after the frame sync */ + data_delay = 1; + /* FS need to be inverted */ + inv_fs = true; break; + case SND_SOC_DAIFMT_LEFT_J: + /* configure a full-word SYNC pulse (LRCLK) */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + /* No delay after FS */ + data_delay = 0; + break; + default: + ret = -EINVAL; + goto out; } + mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay), + FSXDLY(3)); + mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay), + FSRDLY(3)); + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* codec is clock and frame slave */ @@ -325,7 +354,6 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR); mcasp->bclk_master = 0; break; - default: ret = -EINVAL; goto out; @@ -334,39 +362,38 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_IB_NF: mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + fs_pol_rising = true; break; - case SND_SOC_DAIFMT_NB_IF: mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + fs_pol_rising = false; break; - case SND_SOC_DAIFMT_IB_IF: mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + fs_pol_rising = false; break; - case SND_SOC_DAIFMT_NB_NF: mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + fs_pol_rising = true; break; - default: ret = -EINVAL; - break; + goto out; + } + + if (inv_fs) + fs_pol_rising = !fs_pol_rising; + + if (fs_pol_rising) { + mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + } else { + mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); + mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); } out: pm_runtime_put_sync(mcasp->dev); @@ -464,17 +491,19 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, } static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, - int channels) + int period_words, int channels) { + struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream]; + struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream]; int i; u8 tx_ser = 0; u8 rx_ser = 0; - u8 ser; u8 slots = mcasp->tdm_slots; u8 max_active_serializers = (channels + slots - 1) / slots; + int active_serializers, numevt, n; u32 reg; /* Default configuration */ - if (mcasp->version != MCASP_VERSION_4) + if (mcasp->version < MCASP_VERSION_3) mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); /* All PINS as McASP */ @@ -505,37 +534,71 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, } } - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - ser = tx_ser; - else - ser = rx_ser; + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + active_serializers = tx_ser; + numevt = mcasp->txnumevt; + reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; + } else { + active_serializers = rx_ser; + numevt = mcasp->rxnumevt; + reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; + } - if (ser < max_active_serializers) { + if (active_serializers < max_active_serializers) { dev_warn(mcasp->dev, "stream has more channels (%d) than are " - "enabled in mcasp (%d)\n", channels, ser * slots); + "enabled in mcasp (%d)\n", channels, + active_serializers * slots); return -EINVAL; } - if (mcasp->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (mcasp->txnumevt * tx_ser > 64) - mcasp->txnumevt = 1; - - reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; - mcasp_mod_bits(mcasp, reg, tx_ser, NUMDMA_MASK); - mcasp_mod_bits(mcasp, reg, ((mcasp->txnumevt * tx_ser) << 8), - NUMEVT_MASK); + /* AFIFO is not in use */ + if (!numevt) { + /* Configure the burst size for platform drivers */ + if (active_serializers > 1) { + /* + * If more than one serializers are in use we have one + * DMA request to provide data for all serializers. + * For example if three serializers are enabled the DMA + * need to transfer three words per DMA request. + */ + dma_params->fifo_level = active_serializers; + dma_data->maxburst = active_serializers; + } else { + dma_params->fifo_level = 0; + dma_data->maxburst = 0; + } + return 0; } - if (mcasp->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) { - if (mcasp->rxnumevt * rx_ser > 64) - mcasp->rxnumevt = 1; - - reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; - mcasp_mod_bits(mcasp, reg, rx_ser, NUMDMA_MASK); - mcasp_mod_bits(mcasp, reg, ((mcasp->rxnumevt * rx_ser) << 8), - NUMEVT_MASK); + if (period_words % active_serializers) { + dev_err(mcasp->dev, "Invalid combination of period words and " + "active serializers: %d, %d\n", period_words, + active_serializers); + return -EINVAL; } + /* + * Calculate the optimal AFIFO depth for platform side: + * The number of words for numevt need to be in steps of active + * serializers. + */ + n = numevt % active_serializers; + if (n) + numevt += (active_serializers - n); + while (period_words % numevt && numevt > 0) + numevt -= active_serializers; + if (numevt <= 0) + numevt = active_serializers; + + mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK); + mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK); + + /* Configure the burst size for platform drivers */ + if (numevt == 1) + numevt = 0; + dma_params->fifo_level = numevt; + dma_data->maxburst = numevt; + return 0; } @@ -607,27 +670,24 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[substream->stream]; - struct snd_dmaengine_dai_dma_data *dma_data = - &mcasp->dma_data[substream->stream]; int word_length; - u8 fifo_level; - u8 slots = mcasp->tdm_slots; - u8 active_serializers; int channels = params_channels(params); + int period_size = params_period_size(params); int ret; /* If mcasp is BCLK master we need to set BCLK divider */ if (mcasp->bclk_master) { unsigned int bclk_freq = snd_soc_params_to_bclk(params); if (mcasp->sysclk_freq % bclk_freq != 0) { - dev_err(mcasp->dev, "Can't produce requred BCLK\n"); + dev_err(mcasp->dev, "Can't produce required BCLK\n"); return -EINVAL; } davinci_mcasp_set_clkdiv( cpu_dai, 1, mcasp->sysclk_freq / bclk_freq); } - ret = mcasp_common_hw_param(mcasp, substream->stream, channels); + ret = mcasp_common_hw_param(mcasp, substream->stream, + period_size * channels, channels); if (ret) return ret; @@ -671,21 +731,11 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - /* Calculate FIFO level */ - active_serializers = (channels + slots - 1) / slots; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - fifo_level = mcasp->txnumevt * active_serializers; - else - fifo_level = mcasp->rxnumevt * active_serializers; - - if (mcasp->version == MCASP_VERSION_2 && !fifo_level) + if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level) dma_params->acnt = 4; else dma_params->acnt = dma_params->data_type; - dma_params->fifo_level = fifo_level; - dma_data->maxburst = fifo_level; - davinci_config_channel_size(mcasp, word_length); return 0; @@ -716,22 +766,7 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, return ret; } -static int davinci_mcasp_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); - - if (mcasp->version == MCASP_VERSION_4) - snd_soc_dai_set_dma_data(dai, substream, - &mcasp->dma_data[substream->stream]); - else - snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params); - - return 0; -} - static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { - .startup = davinci_mcasp_startup, .trigger = davinci_mcasp_trigger, .hw_params = davinci_mcasp_hw_params, .set_fmt = davinci_mcasp_set_dai_fmt, @@ -739,6 +774,25 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { .set_sysclk = davinci_mcasp_set_sysclk, }; +static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) +{ + struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); + + if (mcasp->version == MCASP_VERSION_4) { + /* Using dmaengine PCM */ + dai->playback_dma_data = + &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; + dai->capture_dma_data = + &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; + } else { + /* Using davinci-pcm */ + dai->playback_dma_data = mcasp->dma_params; + dai->capture_dma_data = mcasp->dma_params; + } + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int davinci_mcasp_suspend(struct snd_soc_dai *dai) { @@ -792,6 +846,7 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai) static struct snd_soc_dai_driver davinci_mcasp_dai[] = { { .name = "davinci-mcasp.0", + .probe = davinci_mcasp_dai_probe, .suspend = davinci_mcasp_suspend, .resume = davinci_mcasp_resume, .playback = { @@ -811,6 +866,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }, { .name = "davinci-mcasp.1", + .probe = davinci_mcasp_dai_probe, .playback = { .channels_min = 1, .channels_max = 384, @@ -1078,7 +1134,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (!mcasp->base) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; - goto err_release_clk; + goto err; } mcasp->op_mode = pdata->op_mode; @@ -1159,25 +1215,37 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp_reparent_fck(pdev); - ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, - &davinci_mcasp_dai[pdata->op_mode], 1); + ret = devm_snd_soc_register_component(&pdev->dev, + &davinci_mcasp_component, + &davinci_mcasp_dai[pdata->op_mode], 1); if (ret != 0) - goto err_release_clk; + goto err; - if (mcasp->version != MCASP_VERSION_4) { + switch (mcasp->version) { + case MCASP_VERSION_1: + case MCASP_VERSION_2: + case MCASP_VERSION_3: ret = davinci_soc_platform_register(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto err_unregister_component; - } + break; + case MCASP_VERSION_4: + ret = omap_pcm_platform_register(&pdev->dev); + break; + default: + dev_err(&pdev->dev, "Invalid McASP version: %d\n", + mcasp->version); + ret = -EINVAL; + break; + } + + if (ret) { + dev_err(&pdev->dev, "register PCM failed: %d\n", ret); + goto err; } return 0; -err_unregister_component: - snd_soc_unregister_component(&pdev->dev); -err_release_clk: +err: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return ret; @@ -1185,12 +1253,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev) static int davinci_mcasp_remove(struct platform_device *pdev) { - struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev); - - snd_soc_unregister_component(&pdev->dev); - if (mcasp->version != MCASP_VERSION_4) - davinci_soc_platform_unregister(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 8fed757d608763..98fbc451892a5e 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -283,6 +283,7 @@ */ #define FIFO_ENABLE BIT(16) #define NUMEVT_MASK (0xFF << 8) +#define NUMEVT(x) (((x) & 0xFF) << 8) #define NUMDMA_MASK (0xFF) #endif /* DAVINCI_MCASP_H */ diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 14145cdf8a1139..7809e9d935fc9c 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -852,16 +852,10 @@ static struct snd_soc_platform_driver davinci_soc_platform = { int davinci_soc_platform_register(struct device *dev) { - return snd_soc_register_platform(dev, &davinci_soc_platform); + return devm_snd_soc_register_platform(dev, &davinci_soc_platform); } EXPORT_SYMBOL_GPL(davinci_soc_platform_register); -void davinci_soc_platform_unregister(struct device *dev) -{ - snd_soc_unregister_platform(dev); -} -EXPORT_SYMBOL_GPL(davinci_soc_platform_unregister); - MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index fbb710c76c083e..0fe2346a9aa29e 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h @@ -29,7 +29,13 @@ struct davinci_pcm_dma_params { unsigned int fifo_level; }; +#if IS_ENABLED(CONFIG_SND_DAVINCI_SOC) int davinci_soc_platform_register(struct device *dev); -void davinci_soc_platform_unregister(struct device *dev); +#else +static inline int davinci_soc_platform_register(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_SND_DAVINCI_SOC */ #endif diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index 30587c0cdbd2cb..77aef05588c3dd 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c @@ -258,7 +258,6 @@ static int davinci_vcif_probe(struct platform_device *pdev) static int davinci_vcif_remove(struct platform_device *pdev) { snd_soc_unregister_component(&pdev->dev); - davinci_soc_platform_unregister(&pdev->dev); return 0; } diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 338a9164247184..d262ec0653d370 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -1,30 +1,77 @@ +menu "SoC Audio for Freescale CPUs" + +comment "Common SoC Audio options for Freescale CPUs:" + config SND_SOC_FSL_SAI - tristate + tristate "Synchronous Audio Interface (SAI) module support" select REGMAP_MMIO select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y if you want to add Synchronous Audio Interface (SAI) + support for the Freescale CPUs. + This option is only useful for out-of-tree drivers since + in-tree drivers select it automatically. config SND_SOC_FSL_SSI - tristate + tristate "Synchronous Serial Interface module support" + select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n + select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && ARCH_MXC + help + Say Y if you want to add Synchronous Serial Interface (SSI) + support for the Freescale CPUs. + This option is only useful for out-of-tree drivers since + in-tree drivers select it automatically. config SND_SOC_FSL_SPDIF - tristate + tristate "Sony/Philips Digital Interface module support" select REGMAP_MMIO + select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n + select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && ARCH_MXC + help + Say Y if you want to add Sony/Philips Digital Interface (SPDIF) + support for the Freescale CPUs. + This option is only useful for out-of-tree drivers since + in-tree drivers select it automatically. config SND_SOC_FSL_ESAI - tristate + tristate "Enhanced Serial Audio Interface (ESAI) module support" select REGMAP_MMIO select SND_SOC_FSL_UTILS + help + Say Y if you want to add Enhanced Synchronous Audio Interface + (ESAI) support for the Freescale CPUs. + This option is only useful for out-of-tree drivers since + in-tree drivers select it automatically. config SND_SOC_FSL_UTILS tristate -menuconfig SND_POWERPC_SOC +config SND_SOC_IMX_PCM_DMA + tristate + select SND_SOC_GENERIC_DMAENGINE_PCM + +config SND_SOC_IMX_AUDMUX + tristate "Digital Audio Mux module support" + help + Say Y if you want to add Digital Audio Mux (AUDMUX) support + for the ARM i.MX CPUs. + This option is only useful for out-of-tree drivers since + in-tree drivers select it automatically. + +config SND_POWERPC_SOC tristate "SoC Audio for Freescale PowerPC CPUs" depends on FSL_SOC || PPC_MPC52xx help Say Y or M if you want to add support for codecs attached to the PowerPC CPUs. +config SND_IMX_SOC + tristate "SoC Audio for Freescale i.MX CPUs" + depends on ARCH_MXC || COMPILE_TEST + help + Say Y or M if you want to add support for codecs attached to + the i.MX CPUs. + if SND_POWERPC_SOC config SND_MPC52xx_DMA @@ -33,6 +80,8 @@ config SND_MPC52xx_DMA config SND_SOC_POWERPC_DMA tristate +comment "SoC Audio support for Freescale PPC boards:" + config SND_SOC_MPC8610_HPCD tristate "ALSA SoC support for the Freescale MPC8610 HPCD board" # I2C is necessary for the CS4270 driver @@ -110,13 +159,6 @@ config SND_MPC52xx_SOC_EFIKA endif # SND_POWERPC_SOC -menuconfig SND_IMX_SOC - tristate "SoC Audio for Freescale i.MX CPUs" - depends on ARCH_MXC || COMPILE_TEST - help - Say Y or M if you want to add support for codecs attached to - the i.MX CPUs. - if SND_IMX_SOC config SND_SOC_IMX_SSI @@ -127,12 +169,7 @@ config SND_SOC_IMX_PCM_FIQ tristate select FIQ -config SND_SOC_IMX_PCM_DMA - tristate - select SND_SOC_GENERIC_DMAENGINE_PCM - -config SND_SOC_IMX_AUDMUX - tristate +comment "SoC Audio support for Freescale i.MX boards:" config SND_MXC_SOC_WM1133_EV1 tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted" @@ -187,7 +224,7 @@ config SND_SOC_EUKREA_TLV320 config SND_SOC_IMX_WM8962 tristate "SoC Audio support for i.MX boards with wm8962" - depends on OF && I2C + depends on OF && I2C && INPUT select SND_SOC_WM8962 select SND_SOC_IMX_PCM_DMA select SND_SOC_IMX_AUDMUX @@ -225,3 +262,5 @@ config SND_SOC_IMX_MC13783 select SND_SOC_IMX_PCM_DMA endif # SND_IMX_SOC + +endmenu diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index c8e5db1414d7e7..b49b78df2f5b0a 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -209,8 +209,9 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, struct clk *clksrc = esai_priv->extalclk; bool tx = clk_id <= ESAI_HCKT_EXTAL; bool in = dir == SND_SOC_CLOCK_IN; - u32 ret, ratio, ecr = 0; + u32 ratio, ecr = 0; unsigned long clk_rate; + int ret; /* sck_div can be only bypassed if ETO/ERO=0 and SNC_SOC_CLOCK_OUT */ esai_priv->sck_div[tx] = true; @@ -432,8 +433,8 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) static int fsl_esai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - int ret; struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); + int ret; /* * Some platforms might use the same bit to gate all three or two of @@ -491,7 +492,8 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u32 width = snd_pcm_format_width(params_format(params)); u32 channels = params_channels(params); - u32 bclk, mask, val, ret; + u32 bclk, mask, val; + int ret; bclk = params_rate(params) * esai_priv->slot_width * 2; @@ -816,6 +818,7 @@ static int fsl_esai_probe(struct platform_device *pdev) static const struct of_device_id fsl_esai_dt_ids[] = { { .compatible = "fsl,imx35-esai", }, + { .compatible = "fsl,vf610-esai", }, {} }; MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids); diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 56da8c8c5960bd..c5a0e8af822614 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -22,6 +22,7 @@ #include #include "fsl_sai.h" +#include "imx-pcm.h" #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\ FSL_SAI_CSR_FEIE) @@ -30,78 +31,96 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) { struct fsl_sai *sai = (struct fsl_sai *)devid; struct device *dev = &sai->pdev->dev; - u32 xcsr, mask; + u32 flags, xcsr, mask; + bool irq_none = true; - /* Only handle those what we enabled */ + /* + * Both IRQ status bits and IRQ mask bits are in the xCSR but + * different shifts. And we here create a mask only for those + * IRQs that we activated. + */ mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT; /* Tx IRQ */ regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr); - xcsr &= mask; + flags = xcsr & mask; + + if (flags) + irq_none = false; + else + goto irq_rx; - if (xcsr & FSL_SAI_CSR_WSF) + if (flags & FSL_SAI_CSR_WSF) dev_dbg(dev, "isr: Start of Tx word detected\n"); - if (xcsr & FSL_SAI_CSR_SEF) + if (flags & FSL_SAI_CSR_SEF) dev_warn(dev, "isr: Tx Frame sync error detected\n"); - if (xcsr & FSL_SAI_CSR_FEF) { + if (flags & FSL_SAI_CSR_FEF) { dev_warn(dev, "isr: Transmit underrun detected\n"); /* FIFO reset for safety */ xcsr |= FSL_SAI_CSR_FR; } - if (xcsr & FSL_SAI_CSR_FWF) + if (flags & FSL_SAI_CSR_FWF) dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n"); - if (xcsr & FSL_SAI_CSR_FRF) + if (flags & FSL_SAI_CSR_FRF) dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n"); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR, - FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr); + flags &= FSL_SAI_CSR_xF_W_MASK; + xcsr &= ~FSL_SAI_CSR_xF_MASK; + + if (flags) + regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr); +irq_rx: /* Rx IRQ */ regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr); - xcsr &= mask; + flags = xcsr & mask; - if (xcsr & FSL_SAI_CSR_WSF) + if (flags) + irq_none = false; + else + goto out; + + if (flags & FSL_SAI_CSR_WSF) dev_dbg(dev, "isr: Start of Rx word detected\n"); - if (xcsr & FSL_SAI_CSR_SEF) + if (flags & FSL_SAI_CSR_SEF) dev_warn(dev, "isr: Rx Frame sync error detected\n"); - if (xcsr & FSL_SAI_CSR_FEF) { + if (flags & FSL_SAI_CSR_FEF) { dev_warn(dev, "isr: Receive overflow detected\n"); /* FIFO reset for safety */ xcsr |= FSL_SAI_CSR_FR; } - if (xcsr & FSL_SAI_CSR_FWF) + if (flags & FSL_SAI_CSR_FWF) dev_dbg(dev, "isr: Enabled receive FIFO is full\n"); - if (xcsr & FSL_SAI_CSR_FRF) + if (flags & FSL_SAI_CSR_FRF) dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n"); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, - FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr); + flags &= FSL_SAI_CSR_xF_W_MASK; + xcsr &= ~FSL_SAI_CSR_xF_MASK; + + if (flags) + regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr); - return IRQ_HANDLED; +out: + if (irq_none) + return IRQ_NONE; + else + return IRQ_HANDLED; } static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int fsl_dir) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); - u32 val_cr2, reg_cr2; - - if (fsl_dir == FSL_FMT_TRANSMITTER) - reg_cr2 = FSL_SAI_TCR2; - else - reg_cr2 = FSL_SAI_RCR2; - - regmap_read(sai->regmap, reg_cr2, &val_cr2); - - val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK; + bool tx = fsl_dir == FSL_FMT_TRANSMITTER; + u32 val_cr2 = 0; switch (clk_id) { case FSL_SAI_CLK_BUS: @@ -120,7 +139,8 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, return -EINVAL; } - regmap_write(sai->regmap, reg_cr2, val_cr2); + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx), + FSL_SAI_CR2_MSEL_MASK, val_cr2); return 0; } @@ -152,22 +172,10 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, unsigned int fmt, int fsl_dir) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); - u32 val_cr2, val_cr4, reg_cr2, reg_cr4; - - if (fsl_dir == FSL_FMT_TRANSMITTER) { - reg_cr2 = FSL_SAI_TCR2; - reg_cr4 = FSL_SAI_TCR4; - } else { - reg_cr2 = FSL_SAI_RCR2; - reg_cr4 = FSL_SAI_RCR4; - } + bool tx = fsl_dir == FSL_FMT_TRANSMITTER; + u32 val_cr2 = 0, val_cr4 = 0; - regmap_read(sai->regmap, reg_cr2, &val_cr2); - regmap_read(sai->regmap, reg_cr4, &val_cr4); - - if (sai->big_endian_data) - val_cr4 &= ~FSL_SAI_CR4_MF; - else + if (!sai->big_endian_data) val_cr4 |= FSL_SAI_CR4_MF; /* DAI mode */ @@ -188,7 +196,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, * frame sync asserts with the first bit of the frame. */ val_cr2 |= FSL_SAI_CR2_BCP; - val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP); break; case SND_SOC_DAIFMT_DSP_A: /* @@ -198,7 +205,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, * data word. */ val_cr2 |= FSL_SAI_CR2_BCP; - val_cr4 &= ~FSL_SAI_CR4_FSP; val_cr4 |= FSL_SAI_CR4_FSE; sai->is_dsp_mode = true; break; @@ -208,7 +214,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, * frame sync asserts with the first bit of the frame. */ val_cr2 |= FSL_SAI_CR2_BCP; - val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP); sai->is_dsp_mode = true; break; case SND_SOC_DAIFMT_RIGHT_J: @@ -246,23 +251,22 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, val_cr4 |= FSL_SAI_CR4_FSD_MSTR; break; case SND_SOC_DAIFMT_CBM_CFM: - val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR; - val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR; break; case SND_SOC_DAIFMT_CBS_CFM: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; - val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR; break; case SND_SOC_DAIFMT_CBM_CFS: - val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR; val_cr4 |= FSL_SAI_CR4_FSD_MSTR; break; default: return -EINVAL; } - regmap_write(sai->regmap, reg_cr2, val_cr2); - regmap_write(sai->regmap, reg_cr4, val_cr4); + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx), + FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val_cr2); + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx), + FSL_SAI_CR4_MF | FSL_SAI_CR4_FSE | + FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val_cr4); return 0; } @@ -289,29 +293,10 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); - u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr; + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; unsigned int channels = params_channels(params); u32 word_width = snd_pcm_format_width(params_format(params)); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - reg_cr4 = FSL_SAI_TCR4; - reg_cr5 = FSL_SAI_TCR5; - reg_mr = FSL_SAI_TMR; - } else { - reg_cr4 = FSL_SAI_RCR4; - reg_cr5 = FSL_SAI_RCR5; - reg_mr = FSL_SAI_RMR; - } - - regmap_read(sai->regmap, reg_cr4, &val_cr4); - regmap_read(sai->regmap, reg_cr4, &val_cr5); - - val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK; - val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK; - - val_cr5 &= ~FSL_SAI_CR5_WNW_MASK; - val_cr5 &= ~FSL_SAI_CR5_W0W_MASK; - val_cr5 &= ~FSL_SAI_CR5_FBT_MASK; + u32 val_cr4 = 0, val_cr5 = 0; if (!sai->is_dsp_mode) val_cr4 |= FSL_SAI_CR4_SYWD(word_width); @@ -319,18 +304,20 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, val_cr5 |= FSL_SAI_CR5_WNW(word_width); val_cr5 |= FSL_SAI_CR5_W0W(word_width); - val_cr5 &= ~FSL_SAI_CR5_FBT_MASK; if (sai->big_endian_data) val_cr5 |= FSL_SAI_CR5_FBT(0); else val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); val_cr4 |= FSL_SAI_CR4_FRSZ(channels); - val_mr = ~0UL - ((1 << channels) - 1); - regmap_write(sai->regmap, reg_cr4, val_cr4); - regmap_write(sai->regmap, reg_cr5, val_cr5); - regmap_write(sai->regmap, reg_mr, val_mr); + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx), + FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, + val_cr4); + regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx), + FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | + FSL_SAI_CR5_FBT_MASK, val_cr5); + regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1)); return 0; } @@ -339,6 +326,7 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u32 tcsr, rcsr; /* @@ -353,14 +341,6 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr); regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - tcsr |= FSL_SAI_CSR_FRDE; - rcsr &= ~FSL_SAI_CSR_FRDE; - } else { - rcsr |= FSL_SAI_CSR_FRDE; - tcsr &= ~FSL_SAI_CSR_FRDE; - } - /* * It is recommended that the transmitter is the last enabled * and the first disabled. @@ -369,22 +349,33 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - tcsr |= FSL_SAI_CSR_TERE; - rcsr |= FSL_SAI_CSR_TERE; + if (!(tcsr & FSL_SAI_CSR_FRDE || rcsr & FSL_SAI_CSR_FRDE)) { + regmap_update_bits(sai->regmap, FSL_SAI_RCSR, + FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); + regmap_update_bits(sai->regmap, FSL_SAI_TCSR, + FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); + } - regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr); - regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr); + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS); + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (!(cpu_dai->playback_active || cpu_dai->capture_active)) { - tcsr &= ~FSL_SAI_CSR_TERE; - rcsr &= ~FSL_SAI_CSR_TERE; + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + FSL_SAI_CSR_FRDE, 0); + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + FSL_SAI_CSR_xIE_MASK, 0); + + /* Check if the opposite FRDE is also disabled */ + if (!(tx ? rcsr & FSL_SAI_CSR_FRDE : tcsr & FSL_SAI_CSR_FRDE)) { + regmap_update_bits(sai->regmap, FSL_SAI_TCSR, + FSL_SAI_CSR_TERE, 0); + regmap_update_bits(sai->regmap, FSL_SAI_RCSR, + FSL_SAI_CSR_TERE, 0); } - - regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr); - regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr); break; default: return -EINVAL; @@ -397,14 +388,17 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); - u32 reg; + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct device *dev = &sai->pdev->dev; + int ret; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - reg = FSL_SAI_TCR3; - else - reg = FSL_SAI_RCR3; + ret = clk_prepare_enable(sai->bus_clk); + if (ret) { + dev_err(dev, "failed to enable bus clock: %d\n", ret); + return ret; + } - regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE, + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, FSL_SAI_CR3_TRCE); return 0; @@ -414,15 +408,11 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); - u32 reg; + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - reg = FSL_SAI_TCR3; - else - reg = FSL_SAI_RCR3; + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0); - regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE, - ~FSL_SAI_CR3_TRCE); + clk_disable_unprepare(sai->bus_clk); } static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { @@ -438,8 +428,8 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, FSL_SAI_FLAGS); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, FSL_SAI_FLAGS); + regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0); + regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0); regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, FSL_SAI_MAXBURST_TX * 2); regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, @@ -555,7 +545,8 @@ static int fsl_sai_probe(struct platform_device *pdev) struct fsl_sai *sai; struct resource *res; void __iomem *base; - int irq, ret; + char tmp[8]; + int irq, ret, i; sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); if (!sai) @@ -563,6 +554,9 @@ static int fsl_sai_probe(struct platform_device *pdev) sai->pdev = pdev; + if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai")) + sai->sai_on_imx = true; + sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); if (sai->big_endian_regs) fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; @@ -575,12 +569,35 @@ static int fsl_sai_probe(struct platform_device *pdev) return PTR_ERR(base); sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, - "sai", base, &fsl_sai_regmap_config); + "bus", base, &fsl_sai_regmap_config); + + /* Compatible with old DTB cases */ + if (IS_ERR(sai->regmap)) + sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, + "sai", base, &fsl_sai_regmap_config); if (IS_ERR(sai->regmap)) { dev_err(&pdev->dev, "regmap init failed\n"); return PTR_ERR(sai->regmap); } + /* No error out for old DTB cases but only mark the clock NULL */ + sai->bus_clk = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(sai->bus_clk)) { + dev_err(&pdev->dev, "failed to get bus clock: %ld\n", + PTR_ERR(sai->bus_clk)); + sai->bus_clk = NULL; + } + + for (i = 0; i < FSL_SAI_MCLK_MAX; i++) { + sprintf(tmp, "mclk%d", i + 1); + sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp); + if (IS_ERR(sai->mclk_clk[i])) { + dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n", + i + 1, PTR_ERR(sai->mclk_clk[i])); + sai->mclk_clk[i] = NULL; + } + } + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); @@ -605,12 +622,16 @@ static int fsl_sai_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, - SND_DMAENGINE_PCM_FLAG_NO_RESIDUE); + if (sai->sai_on_imx) + return imx_pcm_dma_init(pdev); + else + return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, + SND_DMAENGINE_PCM_FLAG_NO_RESIDUE); } static const struct of_device_id fsl_sai_ids[] = { { .compatible = "fsl,vf610-sai", }, + { .compatible = "fsl,imx6sx-sai", }, { /* sentinel */ } }; diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index a264185c713850..0e6c9f595d7550 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -35,6 +35,16 @@ #define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */ #define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */ +#define FSL_SAI_xCSR(tx) (tx ? FSL_SAI_TCSR : FSL_SAI_RCSR) +#define FSL_SAI_xCR1(tx) (tx ? FSL_SAI_TCR1 : FSL_SAI_RCR1) +#define FSL_SAI_xCR2(tx) (tx ? FSL_SAI_TCR2 : FSL_SAI_RCR2) +#define FSL_SAI_xCR3(tx) (tx ? FSL_SAI_TCR3 : FSL_SAI_RCR3) +#define FSL_SAI_xCR4(tx) (tx ? FSL_SAI_TCR4 : FSL_SAI_RCR4) +#define FSL_SAI_xCR5(tx) (tx ? FSL_SAI_TCR5 : FSL_SAI_RCR5) +#define FSL_SAI_xDR(tx) (tx ? FSL_SAI_TDR : FSL_SAI_RDR) +#define FSL_SAI_xFR(tx) (tx ? FSL_SAI_TFR : FSL_SAI_RFR) +#define FSL_SAI_xMR(tx) (tx ? FSL_SAI_TMR : FSL_SAI_RMR) + /* SAI Transmit/Recieve Control Register */ #define FSL_SAI_CSR_TERE BIT(31) #define FSL_SAI_CSR_FR BIT(25) @@ -48,6 +58,7 @@ #define FSL_SAI_CSR_FWF BIT(17) #define FSL_SAI_CSR_FRF BIT(16) #define FSL_SAI_CSR_xIE_SHIFT 8 +#define FSL_SAI_CSR_xIE_MASK (0x1f << FSL_SAI_CSR_xIE_SHIFT) #define FSL_SAI_CSR_WSIE BIT(12) #define FSL_SAI_CSR_SEIE BIT(11) #define FSL_SAI_CSR_FEIE BIT(10) @@ -108,6 +119,8 @@ #define FSL_SAI_CLK_MAST2 2 #define FSL_SAI_CLK_MAST3 3 +#define FSL_SAI_MCLK_MAX 3 + /* SAI data transfer numbers per DMA request */ #define FSL_SAI_MAXBURST_TX 6 #define FSL_SAI_MAXBURST_RX 6 @@ -115,10 +128,13 @@ struct fsl_sai { struct platform_device *pdev; struct regmap *regmap; + struct clk *bus_clk; + struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; bool big_endian_regs; bool big_endian_data; bool is_dsp_mode; + bool sai_on_imx; struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 6452ca83d8893e..b912d45a2a4c60 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -13,18 +13,18 @@ * kind, whether express or implied. */ -#include +#include #include #include -#include -#include +#include #include #include #include +#include #include -#include #include +#include #include "fsl_spdif.h" #include "imx-pcm.h" @@ -69,17 +69,42 @@ struct spdif_mixer_control { u32 ready_buf; }; +/** + * fsl_spdif_priv: Freescale SPDIF private data + * + * @fsl_spdif_control: SPDIF control data + * @cpu_dai_drv: cpu dai driver + * @pdev: platform device pointer + * @regmap: regmap handler + * @dpll_locked: dpll lock flag + * @txrate: the best rates for playback + * @txclk_df: STC_TXCLK_DF dividers value for playback + * @sysclk_df: STC_SYSCLK_DF dividers value for playback + * @txclk_src: STC_TXCLK_SRC values for playback + * @rxclk_src: SRPC_CLKSRC_SEL values for capture + * @txclk: tx clock sources for playback + * @rxclk: rx clock sources for capture + * @coreclk: core clock for register access via DMA + * @sysclk: system clock for rx clock rate measurement + * @dma_params_tx: DMA parameters for transmit channel + * @dma_params_rx: DMA parameters for receive channel + * @name: driver name + */ struct fsl_spdif_priv { struct spdif_mixer_control fsl_spdif_control; struct snd_soc_dai_driver cpu_dai_drv; struct platform_device *pdev; struct regmap *regmap; bool dpll_locked; - u8 txclk_div[SPDIF_TXRATE_MAX]; + u16 txrate[SPDIF_TXRATE_MAX]; + u8 txclk_df[SPDIF_TXRATE_MAX]; + u8 sysclk_df[SPDIF_TXRATE_MAX]; u8 txclk_src[SPDIF_TXRATE_MAX]; u8 rxclk_src; struct clk *txclk[SPDIF_TXRATE_MAX]; struct clk *rxclk; + struct clk *coreclk; + struct clk *sysclk; struct snd_dmaengine_dai_dma_data dma_params_tx; struct snd_dmaengine_dai_dma_data dma_params_rx; @@ -349,7 +374,7 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, struct platform_device *pdev = spdif_priv->pdev; unsigned long csfs = 0; u32 stc, mask, rate; - u8 clk, div; + u8 clk, txclk_df, sysclk_df; int ret; switch (sample_rate) { @@ -376,25 +401,31 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, return -EINVAL; } - div = spdif_priv->txclk_div[rate]; - if (div == 0) { - dev_err(&pdev->dev, "the divisor can't be zero\n"); + txclk_df = spdif_priv->txclk_df[rate]; + if (txclk_df == 0) { + dev_err(&pdev->dev, "the txclk_df can't be zero\n"); return -EINVAL; } + sysclk_df = spdif_priv->sysclk_df[rate]; + + /* Don't mess up the clocks from other modules */ + if (clk != STC_TXCLK_SPDIF_ROOT) + goto clk_set_bypass; + /* - * The S/PDIF block needs a clock of 64 * fs * div. The S/PDIF block - * will divide by (div). So request 64 * fs * (div+1) which will - * get rounded. + * The S/PDIF block needs a clock of 64 * fs * txclk_df. + * So request 64 * fs * (txclk_df + 1) to get rounded. */ - ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (div + 1)); + ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (txclk_df + 1)); if (ret) { dev_err(&pdev->dev, "failed to set tx clock rate\n"); return ret; } +clk_set_bypass: dev_dbg(&pdev->dev, "expected clock rate = %d\n", - (64 * sample_rate * div)); + (64 * sample_rate * txclk_df * sysclk_df)); dev_dbg(&pdev->dev, "actual clock rate = %ld\n", clk_get_rate(spdif_priv->txclk[rate])); @@ -402,11 +433,15 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs); /* select clock source and divisor */ - stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | STC_TXCLK_DIV(div); - mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DIV_MASK; + stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | STC_TXCLK_DF(txclk_df); + mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DF_MASK; regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc); - dev_dbg(&pdev->dev, "set sample rate to %d\n", sample_rate); + regmap_update_bits(regmap, REG_SPDIF_STC, + STC_SYSCLK_DF_MASK, STC_SYSCLK_DF(sysclk_df)); + + dev_dbg(&pdev->dev, "set sample rate to %dHz for %dHz playback\n", + spdif_priv->txrate[rate], sample_rate); return 0; } @@ -423,10 +458,16 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, /* Reset module and interrupts only for first initialization */ if (!cpu_dai->active) { + ret = clk_prepare_enable(spdif_priv->coreclk); + if (ret) { + dev_err(&pdev->dev, "failed to enable core clock\n"); + return ret; + } + ret = spdif_softreset(spdif_priv); if (ret) { dev_err(&pdev->dev, "failed to soft reset\n"); - return ret; + goto err; } /* Disable all the interrupts */ @@ -454,6 +495,11 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0); return 0; + +err: + clk_disable_unprepare(spdif_priv->coreclk); + + return ret; } static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, @@ -484,6 +530,7 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, spdif_intr_status_clear(spdif_priv); regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, SCR_LOW_POWER); + clk_disable_unprepare(spdif_priv->coreclk); } } @@ -754,7 +801,7 @@ static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv, clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf; if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) { /* Get bus clock from system */ - busclk_freq = clk_get_rate(spdif_priv->rxclk); + busclk_freq = clk_get_rate(spdif_priv->sysclk); } /* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */ @@ -997,43 +1044,61 @@ static struct regmap_config fsl_spdif_regmap_config = { static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, struct clk *clk, u64 savesub, - enum spdif_txrate index) + enum spdif_txrate index, bool round) { const u32 rate[] = { 32000, 44100, 48000 }; + bool is_sysclk = clk == spdif_priv->sysclk; u64 rate_ideal, rate_actual, sub; - u32 div, arate; - - for (div = 1; div <= 128; div++) { - rate_ideal = rate[index] * (div + 1) * 64; - rate_actual = clk_round_rate(clk, rate_ideal); - - arate = rate_actual / 64; - arate /= div; - - if (arate == rate[index]) { - /* We are lucky */ - savesub = 0; - spdif_priv->txclk_div[index] = div; - break; - } else if (arate / rate[index] == 1) { - /* A little bigger than expect */ - sub = (arate - rate[index]) * 100000; - do_div(sub, rate[index]); - if (sub < savesub) { + u32 sysclk_dfmin, sysclk_dfmax; + u32 txclk_df, sysclk_df, arate; + + /* The sysclk has an extra divisor [2, 512] */ + sysclk_dfmin = is_sysclk ? 2 : 1; + sysclk_dfmax = is_sysclk ? 512 : 1; + + for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) { + for (txclk_df = 1; txclk_df <= 128; txclk_df++) { + rate_ideal = rate[index] * (txclk_df + 1) * 64; + if (round) + rate_actual = clk_round_rate(clk, rate_ideal); + else + rate_actual = clk_get_rate(clk); + + arate = rate_actual / 64; + arate /= txclk_df * sysclk_df; + + if (arate == rate[index]) { + /* We are lucky */ + savesub = 0; + spdif_priv->txclk_df[index] = txclk_df; + spdif_priv->sysclk_df[index] = sysclk_df; + spdif_priv->txrate[index] = arate; + goto out; + } else if (arate / rate[index] == 1) { + /* A little bigger than expect */ + sub = (arate - rate[index]) * 100000; + do_div(sub, rate[index]); + if (sub >= savesub) + continue; savesub = sub; - spdif_priv->txclk_div[index] = div; - } - } else if (rate[index] / arate == 1) { - /* A little smaller than expect */ - sub = (rate[index] - arate) * 100000; - do_div(sub, rate[index]); - if (sub < savesub) { + spdif_priv->txclk_df[index] = txclk_df; + spdif_priv->sysclk_df[index] = sysclk_df; + spdif_priv->txrate[index] = arate; + } else if (rate[index] / arate == 1) { + /* A little smaller than expect */ + sub = (rate[index] - arate) * 100000; + do_div(sub, rate[index]); + if (sub >= savesub) + continue; savesub = sub; - spdif_priv->txclk_div[index] = div; + spdif_priv->txclk_df[index] = txclk_df; + spdif_priv->sysclk_df[index] = sysclk_df; + spdif_priv->txrate[index] = arate; } } } +out: return savesub; } @@ -1058,7 +1123,8 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, if (!clk_get_rate(clk)) continue; - ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index); + ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index, + i == STC_TXCLK_SPDIF_ROOT); if (savesub == ret) continue; @@ -1073,8 +1139,13 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate\n", spdif_priv->txclk_src[index], rate[index]); - dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate\n", - spdif_priv->txclk_div[index], rate[index]); + dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n", + spdif_priv->txclk_df[index], rate[index]); + if (spdif_priv->txclk[index] == spdif_priv->sysclk) + dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n", + spdif_priv->sysclk_df[index], rate[index]); + dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n", + rate[index], spdif_priv->txrate[index]); return 0; } @@ -1134,6 +1205,20 @@ static int fsl_spdif_probe(struct platform_device *pdev) return ret; } + /* Get system clock for rx clock rate calculation */ + spdif_priv->sysclk = devm_clk_get(&pdev->dev, "rxtx5"); + if (IS_ERR(spdif_priv->sysclk)) { + dev_err(&pdev->dev, "no sys clock (rxtx5) in devicetree\n"); + return PTR_ERR(spdif_priv->sysclk); + } + + /* Get core clock for data register access via DMA */ + spdif_priv->coreclk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(spdif_priv->coreclk)) { + dev_err(&pdev->dev, "no core clock in devicetree\n"); + return PTR_ERR(spdif_priv->coreclk); + } + /* Select clock source for rx/tx clock */ spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1"); if (IS_ERR(spdif_priv->rxclk)) { @@ -1186,6 +1271,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) static const struct of_device_id fsl_spdif_dt_ids[] = { { .compatible = "fsl,imx35-spdif", }, + { .compatible = "fsl,vf610-spdif", }, {} }; MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids); diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h index 605a10b2112b38..16fde4b927d386 100644 --- a/sound/soc/fsl/fsl_spdif.h +++ b/sound/soc/fsl/fsl_spdif.h @@ -143,20 +143,22 @@ enum spdif_gainsel { #define INT_RXFIFO_FUL (1 << 0) /* SPDIF Clock register */ -#define STC_SYSCLK_DIV_OFFSET 11 -#define STC_SYSCLK_DIV_MASK (0x1ff << STC_SYSCLK_DIV_OFFSET) -#define STC_SYSCLK_DIV(x) ((((x) - 1) << STC_SYSCLK_DIV_OFFSET) & STC_SYSCLK_DIV_MASK) +#define STC_SYSCLK_DF_OFFSET 11 +#define STC_SYSCLK_DF_MASK (0x1ff << STC_SYSCLK_DF_OFFSET) +#define STC_SYSCLK_DF(x) ((((x) - 1) << STC_SYSCLK_DF_OFFSET) & STC_SYSCLK_DF_MASK) #define STC_TXCLK_SRC_OFFSET 8 #define STC_TXCLK_SRC_MASK (0x7 << STC_TXCLK_SRC_OFFSET) #define STC_TXCLK_SRC_SET(x) ((x << STC_TXCLK_SRC_OFFSET) & STC_TXCLK_SRC_MASK) #define STC_TXCLK_ALL_EN_OFFSET 7 #define STC_TXCLK_ALL_EN_MASK (1 << STC_TXCLK_ALL_EN_OFFSET) #define STC_TXCLK_ALL_EN (1 << STC_TXCLK_ALL_EN_OFFSET) -#define STC_TXCLK_DIV_OFFSET 0 -#define STC_TXCLK_DIV_MASK (0x7ff << STC_TXCLK_DIV_OFFSET) -#define STC_TXCLK_DIV(x) ((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_TXCLK_DIV_MASK) +#define STC_TXCLK_DF_OFFSET 0 +#define STC_TXCLK_DF_MASK (0x7ff << STC_TXCLK_DF_OFFSET) +#define STC_TXCLK_DF(x) ((((x) - 1) << STC_TXCLK_DF_OFFSET) & STC_TXCLK_DF_MASK) #define STC_TXCLK_SRC_MAX 8 +#define STC_TXCLK_SPDIF_ROOT 1 + /* SPDIF tx rate */ enum spdif_txrate { SPDIF_TXRATE_32000 = 0, diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 5428a1fda26038..25865d8f2efd1d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -642,96 +643,6 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor); } -static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private) -{ - struct ccsr_ssi __iomem *ssi = ssi_private->ssi; - u8 wm; - int synchronous = ssi_private->cpu_dai_drv.symmetric_rates; - - fsl_ssi_setup_reg_vals(ssi_private); - - if (ssi_private->imx_ac97) - ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET; - else - ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE; - - /* - * Section 16.5 of the MPC8610 reference manual says that the SSI needs - * to be disabled before updating the registers we set here. - */ - write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); - - /* - * Program the SSI into I2S Slave Non-Network Synchronous mode. Also - * enable the transmit and receive FIFO. - * - * FIXME: Little-endian samples require a different shift dir - */ - write_ssi_mask(&ssi->scr, - CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN, - CCSR_SSI_SCR_TFR_CLK_DIS | - ssi_private->i2s_mode | - (synchronous ? CCSR_SSI_SCR_SYN : 0)); - - write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFSI | - CCSR_SSI_STCR_TEFS | CCSR_SSI_STCR_TSCKP, &ssi->stcr); - - write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFSI | - CCSR_SSI_SRCR_REFS | CCSR_SSI_SRCR_RSCKP, &ssi->srcr); - - /* - * The DC and PM bits are only used if the SSI is the clock master. - */ - - /* - * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't - * use FIFO 1. We program the transmit water to signal a DMA transfer - * if there are only two (or fewer) elements left in the FIFO. Two - * elements equals one frame (left channel, right channel). This value, - * however, depends on the depth of the transmit buffer. - * - * We set the watermark on the same level as the DMA burstsize. For - * fiq it is probably better to use the biggest possible watermark - * size. - */ - if (ssi_private->use_dma) - wm = ssi_private->fifo_depth - 2; - else - wm = ssi_private->fifo_depth; - - write_ssi(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) | - CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm), - &ssi->sfcsr); - - /* - * For ac97 interrupts are enabled with the startup of the substream - * because it is also running without an active substream. Normally SSI - * is only enabled when there is a substream. - */ - if (ssi_private->imx_ac97) - fsl_ssi_setup_ac97(ssi_private); - - /* - * Set a default slot number so that there is no need for those common - * cases like I2S mode to call the extra set_tdm_slot() any more. - */ - if (!ssi_private->imx_ac97) { - write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK, - CCSR_SSI_SxCCR_DC(2)); - write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK, - CCSR_SSI_SxCCR_DC(2)); - } - - if (ssi_private->use_dual_fifo) { - write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1); - write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1); - write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN); - } - - return 0; -} - - /** * fsl_ssi_startup: create a new substream * @@ -748,12 +659,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, snd_soc_dai_get_drvdata(rtd->cpu_dai); unsigned long flags; - /* First, we only do fsl_ssi_setup() when SSI is going to be active. - * Second, fsl_ssi_setup was already called by ac97_init earlier if - * the driver is in ac97 mode. - */ if (!dai->active && !ssi_private->imx_ac97) { - fsl_ssi_setup(ssi_private); spin_lock_irqsave(&ssi_private->baudclk_lock, flags); ssi_private->baudclk_locked = false; spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags); @@ -835,9 +741,11 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); struct ccsr_ssi __iomem *ssi = ssi_private->ssi; u32 strcr = 0, stcr, srcr, scr, mask; + u8 wm; + + fsl_ssi_setup_reg_vals(ssi_private); scr = read_ssi(&ssi->scr) & ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK); - scr |= CCSR_SSI_SCR_NET; mask = CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR | CCSR_SSI_STCR_TSCKP | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TFSL | @@ -845,19 +753,19 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) stcr = read_ssi(&ssi->stcr) & ~mask; srcr = read_ssi(&ssi->srcr) & ~mask; + ssi_private->i2s_mode = CCSR_SSI_SCR_NET; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: - ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_MASTER; + ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER; break; case SND_SOC_DAIFMT_CBM_CFM: - ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE; + ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_SLAVE; break; default: return -EINVAL; } - scr |= ssi_private->i2s_mode; /* Data on rising edge of bclk, frame low, 1clk before data */ strcr |= CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TSCKP | @@ -877,9 +785,13 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP | CCSR_SSI_STCR_TXBIT0; break; + case SND_SOC_DAIFMT_AC97: + ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_NORMAL; + break; default: return -EINVAL; } + scr |= ssi_private->i2s_mode; /* DAI clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -929,6 +841,38 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) write_ssi(srcr, &ssi->srcr); write_ssi(scr, &ssi->scr); + /* + * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't + * use FIFO 1. We program the transmit water to signal a DMA transfer + * if there are only two (or fewer) elements left in the FIFO. Two + * elements equals one frame (left channel, right channel). This value, + * however, depends on the depth of the transmit buffer. + * + * We set the watermark on the same level as the DMA burstsize. For + * fiq it is probably better to use the biggest possible watermark + * size. + */ + if (ssi_private->use_dma) + wm = ssi_private->fifo_depth - 2; + else + wm = ssi_private->fifo_depth; + + write_ssi(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) | + CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm), + &ssi->sfcsr); + + if (ssi_private->use_dual_fifo) { + write_ssi_mask(&ssi->srcr, CCSR_SSI_SRCR_RFEN1, + CCSR_SSI_SRCR_RFEN1); + write_ssi_mask(&ssi->stcr, CCSR_SSI_STCR_TFEN1, + CCSR_SSI_STCR_TFEN1); + write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TCH_EN, + CCSR_SSI_SCR_TCH_EN); + } + + if (fmt & SND_SOC_DAIFMT_AC97) + fsl_ssi_setup_ac97(ssi_private); + return 0; } @@ -1184,11 +1128,6 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { static struct fsl_ssi_private *fsl_ac97_data; -static void fsl_ssi_ac97_init(void) -{ - fsl_ssi_setup(fsl_ac97_data); -} - static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { @@ -1547,9 +1486,6 @@ static int fsl_ssi_probe(struct platform_device *pdev) } done: - if (ssi_private->imx_ac97) - fsl_ssi_ac97_init(); - return 0; error_dai: diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index ac869931d7f16c..267717aa96c14e 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -145,7 +145,7 @@ static const struct file_operations audmux_debugfs_fops = { .llseek = default_llseek, }; -static void __init audmux_debugfs_init(void) +static void audmux_debugfs_init(void) { int i; char buf[20]; diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index 2585ae44e634fe..0849b7b83f0a7d 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -40,7 +40,6 @@ static const struct snd_pcm_hardware imx_pcm_hardware = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, - .formats = SNDRV_PCM_FMTBIT_S16_LE, .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, .period_bytes_min = 128, .period_bytes_max = 65535, /* Limited by SDMA engine */ diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 21f1ccbdf58299..98f97e543c2943 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -66,8 +66,7 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct simple_card_data *priv = - snd_soc_card_get_drvdata(rtd->card); + struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *codec = rtd->codec_dai; struct snd_soc_dai *cpu = rtd->cpu_dai; struct simple_dai_props *dai_props; @@ -88,7 +87,6 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) static int asoc_simple_card_sub_parse_of(struct device_node *np, - unsigned int daifmt, struct asoc_simple_dai *dai, const struct device_node **p_node, const char **name) @@ -116,14 +114,6 @@ asoc_simple_card_sub_parse_of(struct device_node *np, if (ret) return ret; - /* - * bitclock-inversion, frame-inversion - * bitclock-master, frame-master - * and specific "format" if it has - */ - dai->fmt = snd_soc_of_parse_daifmt(np, NULL); - dai->fmt |= daifmt; - /* * dai->sysclk come from * "clocks = <&xxx>" (if system has common clock) @@ -151,37 +141,132 @@ asoc_simple_card_sub_parse_of(struct device_node *np, return 0; } -static int simple_card_cpu_codec_of(struct device_node *node, - int daifmt, - struct snd_soc_dai_link *dai_link, - struct simple_dai_props *dai_props) +static int simple_card_dai_link_of(struct device_node *node, + struct device *dev, + struct snd_soc_dai_link *dai_link, + struct simple_dai_props *dai_props) { - struct device_node *np; + struct device_node *np = NULL; + struct device_node *bitclkmaster = NULL; + struct device_node *framemaster = NULL; + unsigned int daifmt; + char *name; + char prop[128]; + char *prefix = ""; int ret; - /* CPU sub-node */ - ret = -EINVAL; - np = of_get_child_by_name(node, "simple-audio-card,cpu"); - if (np) { - ret = asoc_simple_card_sub_parse_of(np, daifmt, - &dai_props->cpu_dai, - &dai_link->cpu_of_node, - &dai_link->cpu_dai_name); - of_node_put(np); + prefix = "simple-audio-card,"; + + daifmt = snd_soc_of_parse_daifmt(node, prefix, + &bitclkmaster, &framemaster); + daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; + + snprintf(prop, sizeof(prop), "%scpu", prefix); + np = of_get_child_by_name(node, prop); + if (!np) { + ret = -EINVAL; + dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); + goto dai_link_of_err; } + + ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai, + &dai_link->cpu_of_node, + &dai_link->cpu_dai_name); if (ret < 0) - return ret; + goto dai_link_of_err; + + dai_props->cpu_dai.fmt = daifmt; + switch (((np == bitclkmaster) << 4) | (np == framemaster)) { + case 0x11: + dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS; + break; + case 0x10: + dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM; + break; + case 0x01: + dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS; + break; + default: + dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM; + break; + } - /* CODEC sub-node */ - ret = -EINVAL; - np = of_get_child_by_name(node, "simple-audio-card,codec"); - if (np) { - ret = asoc_simple_card_sub_parse_of(np, daifmt, - &dai_props->codec_dai, - &dai_link->codec_of_node, - &dai_link->codec_dai_name); - of_node_put(np); + of_node_put(np); + snprintf(prop, sizeof(prop), "%scodec", prefix); + np = of_get_child_by_name(node, prop); + if (!np) { + ret = -EINVAL; + dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); + goto dai_link_of_err; } + + ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai, + &dai_link->codec_of_node, + &dai_link->codec_dai_name); + if (ret < 0) + goto dai_link_of_err; + + if (strlen(prefix) && !bitclkmaster && !framemaster) { + /* No dai-link level and master setting was not found from + sound node level, revert back to legacy DT parsing and + take the settings from codec node. */ + dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n", + __func__); + dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt = + snd_soc_of_parse_daifmt(np, NULL, NULL, NULL) | + (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); + } else { + dai_props->codec_dai.fmt = daifmt; + switch (((np == bitclkmaster) << 4) | (np == framemaster)) { + case 0x11: + dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM; + break; + case 0x10: + dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS; + break; + case 0x01: + dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM; + break; + default: + dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS; + break; + } + } + + if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { + ret = -EINVAL; + goto dai_link_of_err; + } + + /* simple-card assumes platform == cpu */ + dai_link->platform_of_node = dai_link->cpu_of_node; + + /* Link name is created from CPU/CODEC dai name */ + name = devm_kzalloc(dev, + strlen(dai_link->cpu_dai_name) + + strlen(dai_link->codec_dai_name) + 2, + GFP_KERNEL); + sprintf(name, "%s-%s", dai_link->cpu_dai_name, + dai_link->codec_dai_name); + dai_link->name = dai_link->stream_name = name; + + dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); + dev_dbg(dev, "\tcpu : %s / %04x / %d\n", + dai_link->cpu_dai_name, + dai_props->cpu_dai.fmt, + dai_props->cpu_dai.sysclk); + dev_dbg(dev, "\tcodec : %s / %04x / %d\n", + dai_link->codec_dai_name, + dai_props->codec_dai.fmt, + dai_props->codec_dai.sysclk); + +dai_link_of_err: + if (np) + of_node_put(np); + if (bitclkmaster) + of_node_put(bitclkmaster); + if (framemaster) + of_node_put(framemaster); return ret; } @@ -192,18 +277,11 @@ static int asoc_simple_card_parse_of(struct device_node *node, { struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link; struct simple_dai_props *dai_props = priv->dai_props; - struct device_node *np; - char *name; - unsigned int daifmt; int ret; /* parsing the card name from DT */ snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name"); - /* get CPU/CODEC common format via simple-audio-card,format */ - daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") & - (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); - /* off-codec widgets */ if (of_property_read_bool(node, "simple-audio-card,widgets")) { ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, @@ -220,71 +298,31 @@ static int asoc_simple_card_parse_of(struct device_node *node, return ret; } - /* loop on the DAI links */ - np = NULL; - for (;;) { - if (multi) { - np = of_get_next_child(node, np); - if (!np) - break; + dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ? + priv->snd_card.name : ""); + + if (multi) { + struct device_node *np = NULL; + int i; + for (i = 0; (np = of_get_next_child(node, np)); i++) { + dev_dbg(dev, "\tlink %d:\n", i); + ret = simple_card_dai_link_of(np, dev, dai_link + i, + dai_props + i); + if (ret < 0) { + of_node_put(np); + return ret; + } } - - ret = simple_card_cpu_codec_of(multi ? np : node, - daifmt, dai_link, dai_props); + } else { + ret = simple_card_dai_link_of(node, dev, dai_link, dai_props); if (ret < 0) - goto err; - - /* - * overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC - * while the other bits should be identical unless buggy SW/HW design. - */ - dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt; - - if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { - ret = -EINVAL; - goto err; - } - - /* simple-card assumes platform == cpu */ - dai_link->platform_of_node = dai_link->cpu_of_node; - - name = devm_kzalloc(dev, - strlen(dai_link->cpu_dai_name) + - strlen(dai_link->codec_dai_name) + 2, - GFP_KERNEL); - sprintf(name, "%s-%s", dai_link->cpu_dai_name, - dai_link->codec_dai_name); - dai_link->name = dai_link->stream_name = name; - - if (!multi) - break; - - dai_link++; - dai_props++; + return ret; } - /* card name is created from CPU/CODEC dai name */ - dai_link = priv->snd_card.dai_link; if (!priv->snd_card.name) - priv->snd_card.name = dai_link->name; - - dev_dbg(dev, "card-name : %s\n", priv->snd_card.name); - dev_dbg(dev, "platform : %04x\n", daifmt); - dai_props = priv->dai_props; - dev_dbg(dev, "cpu : %s / %04x / %d\n", - dai_link->cpu_dai_name, - dai_props->cpu_dai.fmt, - dai_props->cpu_dai.sysclk); - dev_dbg(dev, "codec : %s / %04x / %d\n", - dai_link->codec_dai_name, - dai_props->codec_dai.fmt, - dai_props->codec_dai.sysclk); + priv->snd_card.name = priv->snd_card.dai_link->name; return 0; - -err: - of_node_put(np); - return ret; } /* update the reference count of the devices nodes at end of probe */ @@ -378,10 +416,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev) return -EINVAL; } - if (!cinfo->name || - !cinfo->codec_dai.name || - !cinfo->codec || - !cinfo->platform || + if (!cinfo->name || + !cinfo->codec_dai.name || + !cinfo->codec || + !cinfo->platform || !cinfo->cpu_dai.name) { dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; @@ -425,11 +463,11 @@ MODULE_DEVICE_TABLE(of, asoc_simple_of_match); static struct platform_driver asoc_simple_card = { .driver = { - .name = "asoc-simple-card", + .name = "asoc-simple-card", .owner = THIS_MODULE, .of_match_table = asoc_simple_of_match, }, - .probe = asoc_simple_card_probe, + .probe = asoc_simple_card_probe, }; module_platform_driver(asoc_simple_card); diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index edeb79ae3dff21..5d3fb6f35a193b 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -2,7 +2,7 @@ snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o snd-soc-sst-acpi-objs := sst-acpi.o -snd-soc-sst-mfld-platform-objs := sst-mfld-platform.o +snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o snd-soc-mfld-machine-objs := mfld_machine.o obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c index 5d06eecb61986d..18aee77f8d4a55 100644 --- a/sound/soc/intel/sst-acpi.c +++ b/sound/soc/intel/sst-acpi.c @@ -138,6 +138,7 @@ static int sst_acpi_probe(struct platform_device *pdev) sst_pdata = &sst_acpi->sst_pdata; sst_pdata->id = desc->sst_id; + sst_pdata->dma_dev = dev; sst_acpi->desc = desc; sst_acpi->mach = mach; diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index d0eaeee21be4c6..0d31dbbf480652 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c @@ -542,16 +542,20 @@ struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id, void *data) { struct sst_byt_stream *stream; + struct sst_dsp *sst = byt->dsp; + unsigned long flags; stream = kzalloc(sizeof(*stream), GFP_KERNEL); if (stream == NULL) return NULL; + spin_lock_irqsave(&sst->spinlock, flags); list_add(&stream->node, &byt->stream_list); stream->notify_position = notify_position; stream->pdata = data; stream->byt = byt; stream->str_id = id; + spin_unlock_irqrestore(&sst->spinlock, flags); return stream; } @@ -630,6 +634,8 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) { u64 header; int ret = 0; + struct sst_dsp *sst = byt->dsp; + unsigned long flags; if (!stream->commited) goto out; @@ -644,8 +650,10 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) stream->commited = false; out: + spin_lock_irqsave(&sst->spinlock, flags); list_del(&stream->node); kfree(stream); + spin_unlock_irqrestore(&sst->spinlock, flags); return ret; } diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h index 30ca14a6a83595..ffb308bd81cea6 100644 --- a/sound/soc/intel/sst-dsp-priv.h +++ b/sound/soc/intel/sst-dsp-priv.h @@ -228,6 +228,7 @@ struct sst_dsp { spinlock_t spinlock; /* IPC locking */ struct mutex mutex; /* DSP FW lock */ struct device *dev; + struct device *dma_dev; void *thread_context; int irq; u32 id; @@ -283,6 +284,8 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, const struct firmware *fw, void *private); void sst_fw_free(struct sst_fw *sst_fw); void sst_fw_free_all(struct sst_dsp *dsp); +int sst_fw_reload(struct sst_fw *sst_fw); +void sst_fw_unload(struct sst_fw *sst_fw); /* Create/Free firmware modules */ struct sst_module *sst_module_new(struct sst_fw *sst_fw, diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c index 0c129fd85ecf8a..0b715b20a2d7d4 100644 --- a/sound/soc/intel/sst-dsp.c +++ b/sound/soc/intel/sst-dsp.c @@ -337,6 +337,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev, spin_lock_init(&sst->spinlock); mutex_init(&sst->mutex); sst->dev = dev; + sst->dma_dev = pdata->dma_dev; sst->thread_context = sst_dev->thread_context; sst->sst_dev = sst_dev; sst->id = pdata->id; diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h index 74052b59485ca1..e44423be66c459 100644 --- a/sound/soc/intel/sst-dsp.h +++ b/sound/soc/intel/sst-dsp.h @@ -169,6 +169,7 @@ struct sst_pdata { u32 dma_base; u32 dma_size; int dma_engine; + struct device *dma_dev; /* DSP */ u32 id; diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index f7687107cf7f51..3bb43dac892df4 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c @@ -30,6 +30,8 @@ #include "sst-dsp.h" #include "sst-dsp-priv.h" +static void block_module_remove(struct sst_module *module); + static void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes) { u32 i; @@ -57,14 +59,8 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, sst_fw->private = private; sst_fw->size = fw->size; - err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32)); - if (err < 0) { - kfree(sst_fw); - return NULL; - } - /* allocate DMA buffer to store FW data */ - sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size, + sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size, &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL); if (!sst_fw->dma_buf) { dev_err(dsp->dev, "error: DMA alloc failed\n"); @@ -97,6 +93,42 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, } EXPORT_SYMBOL_GPL(sst_fw_new); +int sst_fw_reload(struct sst_fw *sst_fw) +{ + struct sst_dsp *dsp = sst_fw->dsp; + int ret; + + dev_dbg(dsp->dev, "reloading firmware\n"); + + /* call core specific FW paser to load FW data into DSP */ + ret = dsp->ops->parse_fw(sst_fw); + if (ret < 0) + dev_err(dsp->dev, "error: parse fw failed %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(sst_fw_reload); + +void sst_fw_unload(struct sst_fw *sst_fw) +{ + struct sst_dsp *dsp = sst_fw->dsp; + struct sst_module *module, *tmp; + + dev_dbg(dsp->dev, "unloading firmware\n"); + + mutex_lock(&dsp->mutex); + list_for_each_entry_safe(module, tmp, &dsp->module_list, list) { + if (module->sst_fw == sst_fw) { + block_module_remove(module); + list_del(&module->list); + kfree(module); + } + } + + mutex_unlock(&dsp->mutex); +} +EXPORT_SYMBOL_GPL(sst_fw_unload); + /* free single firmware object */ void sst_fw_free(struct sst_fw *sst_fw) { @@ -106,7 +138,7 @@ void sst_fw_free(struct sst_fw *sst_fw) list_del(&sst_fw->list); mutex_unlock(&dsp->mutex); - dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf, + dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf, sst_fw->dmable_fw_paddr); kfree(sst_fw); } @@ -202,6 +234,9 @@ static int block_alloc_contiguous(struct sst_module *module, size -= block->size; } + list_for_each_entry(block, &tmp, list) + list_add(&block->module_list, &module->block_list); + list_splice(&tmp, &dsp->used_block_list); return 0; } @@ -247,8 +282,7 @@ static int block_alloc(struct sst_module *module, /* do we span > 1 blocks */ if (data->size > block->size) { ret = block_alloc_contiguous(module, data, - block->offset + block->size, - data->size - block->size); + block->offset, data->size); if (ret == 0) return ret; } @@ -344,7 +378,7 @@ static int block_alloc_fixed(struct sst_module *module, err = block_alloc_contiguous(module, data, block->offset + block->size, - data->size - block->size + data->offset - block->offset); + data->size - block->size); if (err < 0) return -ENOMEM; @@ -371,15 +405,10 @@ static int block_alloc_fixed(struct sst_module *module, if (data->offset >= block->offset && data->offset < block_end) { err = block_alloc_contiguous(module, data, - block->offset + block->size, - data->size - block->size); + block->offset, data->size); if (err < 0) return -ENOMEM; - /* add block */ - block->data_type = data->data_type; - list_move(&block->list, &dsp->used_block_list); - list_add(&block->module_list, &module->block_list); return 0; } @@ -505,9 +534,7 @@ struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp) /* calculate required scratch size */ list_for_each_entry(sst_module, &dsp->module_list, list) { - if (scratch->s.size > sst_module->s.size) - scratch->s.size = scratch->s.size; - else + if (scratch->s.size < sst_module->s.size) scratch->s.size = sst_module->s.size; } diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index f5ebf36af8898d..535f517629fd60 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c @@ -433,7 +433,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) int ret = -ENODEV, i, j, region_count; u32 offset, size; - dev = sst->dev; + dev = sst->dma_dev; switch (sst->id) { case SST_DEV_ID_LYNX_POINT: @@ -466,7 +466,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) return ret; } - ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); + ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31)); if (ret) return ret; diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 50e4246d4b57a2..e7996b39a48480 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -1159,11 +1159,14 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, void *data) { struct sst_hsw_stream *stream; + struct sst_dsp *sst = hsw->dsp; + unsigned long flags; stream = kzalloc(sizeof(*stream), GFP_KERNEL); if (stream == NULL) return NULL; + spin_lock_irqsave(&sst->spinlock, flags); list_add(&stream->node, &hsw->stream_list); stream->notify_position = notify_position; stream->pdata = data; @@ -1172,6 +1175,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, /* work to process notification messages */ INIT_WORK(&stream->notify_work, hsw_notification_work); + spin_unlock_irqrestore(&sst->spinlock, flags); return stream; } @@ -1180,6 +1184,8 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) { u32 header; int ret = 0; + struct sst_dsp *sst = hsw->dsp; + unsigned long flags; /* dont free DSP streams that are not commited */ if (!stream->commited) @@ -1201,8 +1207,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) trace_hsw_stream_free_req(stream, &stream->free_req); out: + cancel_work_sync(&stream->notify_work); + spin_lock_irqsave(&sst->spinlock, flags); list_del(&stream->node); kfree(stream); + spin_unlock_irqrestore(&sst->spinlock, flags); return ret; } @@ -1538,10 +1547,28 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream) } /* Stream pointer positions */ -int sst_hsw_get_dsp_position(struct sst_hsw *hsw, +u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw, struct sst_hsw_stream *stream) { - return stream->rpos.position; + u32 rpos; + + sst_dsp_read(hsw->dsp, &rpos, + stream->reply.read_position_register_address, sizeof(rpos)); + + return rpos; +} + +/* Stream presentation (monotonic) positions */ +u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, + struct sst_hsw_stream *stream) +{ + u64 ppos; + + sst_dsp_read(hsw->dsp, &ppos, + stream->reply.presentation_position_register_address, + sizeof(ppos)); + + return ppos; } int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index d517929ccc389e..2ac194a6d04b22 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -464,7 +464,9 @@ int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 *position); int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 stage_id, u32 position); -int sst_hsw_get_dsp_position(struct sst_hsw *hsw, +u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw, + struct sst_hsw_stream *stream); +u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, struct sst_hsw_stream *stream); /* HW port config */ diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 0a32dd13a23d28..ce27b507d5ef1d 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -99,6 +99,7 @@ struct hsw_pcm_data { struct snd_compr_stream *cstream; unsigned int wpos; struct mutex mutex; + bool allocated; }; /* private data for the driver */ @@ -107,12 +108,14 @@ struct hsw_priv_data { struct sst_hsw *hsw; /* page tables */ - unsigned char *pcm_pg[HSW_PCM_COUNT][2]; + struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; /* DAI data */ struct hsw_pcm_data pcm[HSW_PCM_COUNT]; }; +static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data); + static inline u32 hsw_mixer_to_ipc(unsigned int value) { if (value >= ARRAY_SIZE(volume_map)) @@ -136,7 +139,7 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value) static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; struct hsw_priv_data *pdata = @@ -174,7 +177,7 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; struct hsw_priv_data *pdata = @@ -206,7 +209,7 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, static int hsw_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); struct sst_hsw *hsw = pdata->hsw; u32 volume; @@ -231,7 +234,7 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol, static int hsw_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); struct sst_hsw *hsw = pdata->hsw; unsigned int volume = 0; @@ -273,28 +276,26 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { }; /* Create DMA buffer page table for DSP */ -static int create_adsp_page_table(struct hsw_priv_data *pdata, - struct snd_soc_pcm_runtime *rtd, - unsigned char *dma_area, size_t size, int pcm, int stream) +static int create_adsp_page_table(struct snd_pcm_substream *substream, + struct hsw_priv_data *pdata, struct snd_soc_pcm_runtime *rtd, + unsigned char *dma_area, size_t size, int pcm) { - int i, pages; + struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); + int i, pages, stream = substream->stream; - if (size % PAGE_SIZE) - pages = (size / PAGE_SIZE) + 1; - else - pages = size / PAGE_SIZE; + pages = snd_sgbuf_aligned_pages(size); dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n", dma_area, size, pages); for (i = 0; i < pages; i++) { u32 idx = (((i << 2) + i)) >> 1; - u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT; + u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; u32 *pg_table; dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); - pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx); + pg_table = (u32 *)(pdata->dmab[pcm][stream].area + idx); if (i & 1) *pg_table |= (pfn << 4); @@ -317,12 +318,36 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, struct sst_hsw *hsw = pdata->hsw; struct sst_module *module_data; struct sst_dsp *dsp; + struct snd_dma_buffer *dmab; enum sst_hsw_stream_type stream_type; enum sst_hsw_stream_path_id path_id; u32 rate, bits, map, pages, module_id; u8 channels; int ret; + /* check if we are being called a subsequent time */ + if (pcm_data->allocated) { + ret = sst_hsw_stream_reset(hsw, pcm_data->stream); + if (ret < 0) + dev_dbg(rtd->dev, "error: reset stream failed %d\n", + ret); + + ret = sst_hsw_stream_free(hsw, pcm_data->stream); + if (ret < 0) { + dev_dbg(rtd->dev, "error: free stream failed %d\n", + ret); + return ret; + } + pcm_data->allocated = false; + + pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id, + hsw_notify_pointer, pcm_data); + if (pcm_data->stream == NULL) { + dev_err(rtd->dev, "error: failed to create stream\n"); + return -EINVAL; + } + } + /* stream direction */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) path_id = SST_HSW_STREAM_PATH_SSP0_OUT; @@ -416,8 +441,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, return ret; } - ret = create_adsp_page_table(pdata, rtd, runtime->dma_area, - runtime->dma_bytes, rtd->cpu_dai->id, substream->stream); + dmab = snd_pcm_get_dma_buf(substream); + + ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area, + runtime->dma_bytes, rtd->cpu_dai->id); if (ret < 0) return ret; @@ -430,9 +457,9 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, pages = runtime->dma_bytes / PAGE_SIZE; ret = sst_hsw_stream_buffer(hsw, pcm_data->stream, - virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]), + pdata->dmab[rtd->cpu_dai->id][substream->stream].addr, pages, runtime->dma_bytes, 0, - (u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT)); + snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT); if (ret < 0) { dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret); return ret; @@ -474,6 +501,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, dev_err(rtd->dev, "error: failed to commit stream %d\n", ret); return ret; } + pcm_data->allocated = true; ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1); if (ret < 0) @@ -541,12 +569,14 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); struct sst_hsw *hsw = pdata->hsw; snd_pcm_uframes_t offset; + uint64_t ppos; + u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream); - offset = bytes_to_frames(runtime, - sst_hsw_get_dsp_position(hsw, pcm_data->stream)); + offset = bytes_to_frames(runtime, position); + ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream); - dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n", - frames_to_bytes(runtime, (u32)offset)); + dev_dbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n", + position, ppos); return offset; } @@ -606,6 +636,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) dev_dbg(rtd->dev, "error: free stream failed %d\n", ret); goto out; } + pcm_data->allocated = 0; pcm_data->stream = NULL; out: @@ -621,7 +652,7 @@ static struct snd_pcm_ops hsw_pcm_ops = { .hw_free = hsw_pcm_hw_free, .trigger = hsw_pcm_trigger, .pointer = hsw_pcm_pointer, - .mmap = snd_pcm_lib_default_mmap, + .page = snd_pcm_sgbuf_ops_page, }; static void hsw_pcm_free(struct snd_pcm *pcm) @@ -632,17 +663,16 @@ static void hsw_pcm_free(struct snd_pcm *pcm) static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; + struct snd_soc_platform *platform = rtd->platform; + struct sst_pdata *pdata = dev_get_platdata(platform->dev); + struct device *dev = pdata->dma_dev; int ret = 0; - ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { ret = snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV, - rtd->card->dev, + SNDRV_DMA_TYPE_DEV_SG, + dev, hsw_pcm_hardware.buffer_bytes_max, hsw_pcm_hardware.buffer_bytes_max); if (ret) { @@ -742,11 +772,14 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) { struct sst_pdata *pdata = dev_get_platdata(platform->dev); struct hsw_priv_data *priv_data; - int i; + struct device *dma_dev; + int i, ret = 0; if (!pdata) return -ENODEV; + dma_dev = pdata->dma_dev; + priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); priv_data->hsw = pdata->dsp; snd_soc_platform_set_drvdata(platform, priv_data); @@ -758,15 +791,17 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) /* playback */ if (hsw_dais[i].playback.channels_min) { - priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA); - if (priv_data->pcm_pg[i][0] == NULL) + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, + PAGE_SIZE, &priv_data->dmab[i][0]); + if (ret < 0) goto err; } /* capture */ if (hsw_dais[i].capture.channels_min) { - priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA); - if (priv_data->pcm_pg[i][1] == NULL) + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, + PAGE_SIZE, &priv_data->dmab[i][1]); + if (ret < 0) goto err; } } @@ -776,11 +811,11 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) err: for (;i >= 0; i--) { if (hsw_dais[i].playback.channels_min) - kfree(priv_data->pcm_pg[i][0]); + snd_dma_free_pages(&priv_data->dmab[i][0]); if (hsw_dais[i].capture.channels_min) - kfree(priv_data->pcm_pg[i][1]); + snd_dma_free_pages(&priv_data->dmab[i][1]); } - return -ENOMEM; + return ret; } static int hsw_pcm_remove(struct snd_soc_platform *platform) @@ -791,9 +826,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform) for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { if (hsw_dais[i].playback.channels_min) - kfree(priv_data->pcm_pg[i][0]); + snd_dma_free_pages(&priv_data->dmab[i][0]); if (hsw_dais[i].capture.channels_min) - kfree(priv_data->pcm_pg[i][1]); + snd_dma_free_pages(&priv_data->dmab[i][1]); } return 0; diff --git a/sound/soc/intel/sst-mfld-dsp.h b/sound/soc/intel/sst-mfld-dsp.h index 3b63edc04b7f8f..a74477a12009f8 100644 --- a/sound/soc/intel/sst-mfld-dsp.h +++ b/sound/soc/intel/sst-mfld-dsp.h @@ -16,10 +16,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c new file mode 100644 index 00000000000000..16d79fb25e5909 --- /dev/null +++ b/sound/soc/intel/sst-mfld-platform-compress.c @@ -0,0 +1,228 @@ +/* + * sst_mfld_platform.c - Intel MID Platform driver + * + * Copyright (C) 2010-2014 Intel Corp + * Author: Vinod Koul + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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. + * + * 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include "sst-mfld-platform.h" + +/* compress stream operations */ +static void sst_compr_fragment_elapsed(void *arg) +{ + struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg; + + pr_debug("fragment elapsed by driver\n"); + if (cstream) + snd_compr_fragment_elapsed(cstream); +} + +static int sst_platform_compr_open(struct snd_compr_stream *cstream) +{ + + int ret_val = 0; + struct snd_compr_runtime *runtime = cstream->runtime; + struct sst_runtime_stream *stream; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + spin_lock_init(&stream->status_lock); + + /* get the sst ops */ + if (!sst || !try_module_get(sst->dev->driver->owner)) { + pr_err("no device available to run\n"); + ret_val = -ENODEV; + goto out_ops; + } + stream->compr_ops = sst->compr_ops; + + stream->id = 0; + sst_set_stream_status(stream, SST_PLATFORM_INIT); + runtime->private_data = stream; + return 0; +out_ops: + kfree(stream); + return ret_val; +} + +static int sst_platform_compr_free(struct snd_compr_stream *cstream) +{ + struct sst_runtime_stream *stream; + int ret_val = 0, str_id; + + stream = cstream->runtime->private_data; + /*need to check*/ + str_id = stream->id; + if (str_id) + ret_val = stream->compr_ops->close(str_id); + module_put(sst->dev->driver->owner); + kfree(stream); + pr_debug("%s: %d\n", __func__, ret_val); + return 0; +} + +static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + struct sst_runtime_stream *stream; + int retval; + struct snd_sst_params str_params; + struct sst_compress_cb cb; + + stream = cstream->runtime->private_data; + /* construct fw structure for this*/ + memset(&str_params, 0, sizeof(str_params)); + + str_params.ops = STREAM_OPS_PLAYBACK; + str_params.stream_type = SST_STREAM_TYPE_MUSIC; + str_params.device_type = SND_SST_DEVICE_COMPRESS; + + switch (params->codec.id) { + case SND_AUDIOCODEC_MP3: { + str_params.codec = SST_CODEC_TYPE_MP3; + str_params.sparams.uc.mp3_params.codec = SST_CODEC_TYPE_MP3; + str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in; + str_params.sparams.uc.mp3_params.pcm_wd_sz = 16; + break; + } + + case SND_AUDIOCODEC_AAC: { + str_params.codec = SST_CODEC_TYPE_AAC; + str_params.sparams.uc.aac_params.codec = SST_CODEC_TYPE_AAC; + str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in; + str_params.sparams.uc.aac_params.pcm_wd_sz = 16; + if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS) + str_params.sparams.uc.aac_params.bs_format = + AAC_BIT_STREAM_ADTS; + else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW) + str_params.sparams.uc.aac_params.bs_format = + AAC_BIT_STREAM_RAW; + else { + pr_err("Undefined format%d\n", params->codec.format); + return -EINVAL; + } + str_params.sparams.uc.aac_params.externalsr = + params->codec.sample_rate; + break; + } + + default: + pr_err("codec not supported, id =%d\n", params->codec.id); + return -EINVAL; + } + + str_params.aparams.ring_buf_info[0].addr = + virt_to_phys(cstream->runtime->buffer); + str_params.aparams.ring_buf_info[0].size = + cstream->runtime->buffer_size; + str_params.aparams.sg_count = 1; + str_params.aparams.frag_size = cstream->runtime->fragment_size; + + cb.param = cstream; + cb.compr_cb = sst_compr_fragment_elapsed; + + retval = stream->compr_ops->open(&str_params, &cb); + if (retval < 0) { + pr_err("stream allocation failed %d\n", retval); + return retval; + } + + stream->id = retval; + return 0; +} + +static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) +{ + struct sst_runtime_stream *stream = + cstream->runtime->private_data; + + return stream->compr_ops->control(cmd, stream->id); +} + +static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp) +{ + struct sst_runtime_stream *stream; + + stream = cstream->runtime->private_data; + stream->compr_ops->tstamp(stream->id, tstamp); + tstamp->byte_offset = tstamp->copied_total % + (u32)cstream->runtime->buffer_size; + pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); + return 0; +} + +static int sst_platform_compr_ack(struct snd_compr_stream *cstream, + size_t bytes) +{ + struct sst_runtime_stream *stream; + + stream = cstream->runtime->private_data; + stream->compr_ops->ack(stream->id, (unsigned long)bytes); + stream->bytes_written += bytes; + + return 0; +} + +static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream, + struct snd_compr_caps *caps) +{ + struct sst_runtime_stream *stream = + cstream->runtime->private_data; + + return stream->compr_ops->get_caps(caps); +} + +static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream, + struct snd_compr_codec_caps *codec) +{ + struct sst_runtime_stream *stream = + cstream->runtime->private_data; + + return stream->compr_ops->get_codec_caps(codec); +} + +static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + struct sst_runtime_stream *stream = + cstream->runtime->private_data; + + return stream->compr_ops->set_metadata(stream->id, metadata); +} + +struct snd_compr_ops sst_platform_compr_ops = { + + .open = sst_platform_compr_open, + .free = sst_platform_compr_free, + .set_params = sst_platform_compr_set_params, + .set_metadata = sst_platform_compr_set_metadata, + .trigger = sst_platform_compr_trigger, + .pointer = sst_platform_compr_pointer, + .ack = sst_platform_compr_ack, + .get_caps = sst_platform_compr_get_caps, + .get_codec_caps = sst_platform_compr_get_codec_caps, +}; diff --git a/sound/soc/intel/sst-mfld-platform.c b/sound/soc/intel/sst-mfld-platform-pcm.c similarity index 62% rename from sound/soc/intel/sst-mfld-platform.c rename to sound/soc/intel/sst-mfld-platform-pcm.c index 840306c2ef14dd..72d0fae34a5399 100644 --- a/sound/soc/intel/sst-mfld-platform.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -15,13 +15,7 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -35,8 +29,9 @@ #include #include "sst-mfld-platform.h" -static struct sst_device *sst; +struct sst_device *sst; static DEFINE_MUTEX(sst_lock); +extern struct snd_compr_ops sst_platform_compr_ops; int sst_register_dsp(struct sst_device *dev) { @@ -100,7 +95,7 @@ static struct snd_pcm_hardware sst_platform_pcm_hw = { /* MFLD - MSIC */ static struct snd_soc_dai_driver sst_platform_dai[] = { { - .name = "Headset-cpu-dai", + .name = "media-cpu-dai", .id = 0, .playback = { .channels_min = SST_STEREO, @@ -115,36 +110,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .formats = SNDRV_PCM_FMTBIT_S24_LE, }, }, -{ - .name = "Speaker-cpu-dai", - .id = 1, - .playback = { - .channels_min = SST_MONO, - .channels_max = SST_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S24_LE, - }, -}, -{ - .name = "Vibra1-cpu-dai", - .id = 2, - .playback = { - .channels_min = SST_MONO, - .channels_max = SST_MONO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S24_LE, - }, -}, -{ - .name = "Vibra2-cpu-dai", - .id = 3, - .playback = { - .channels_min = SST_MONO, - .channels_max = SST_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S24_LE, - }, -}, { .name = "Compress-cpu-dai", .compress_dai = 1, @@ -157,12 +122,8 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { }, }; -static const struct snd_soc_component_driver sst_component = { - .name = "sst", -}; - /* helper functions */ -static inline void sst_set_stream_status(struct sst_runtime_stream *stream, +void sst_set_stream_status(struct sst_runtime_stream *stream, int state) { unsigned long flags; @@ -270,13 +231,13 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) } /* end -- helper functions */ -static int sst_platform_open(struct snd_pcm_substream *substream) +static int sst_platform_media_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct sst_runtime_stream *stream; int ret_val; - pr_debug("sst_platform_open called\n"); + pr_debug("sst_platform_media_open called\n"); snd_soc_set_runtime_hwparams(substream, &sst_platform_pcm_hw); ret_val = snd_pcm_hw_constraint_integer(runtime, @@ -314,12 +275,12 @@ static int sst_platform_open(struct snd_pcm_substream *substream) return 0; } -static int sst_platform_close(struct snd_pcm_substream *substream) +static int sst_platform_media_close(struct snd_pcm_substream *substream) { struct sst_runtime_stream *stream; int ret_val = 0, str_id; - pr_debug("sst_platform_close called\n"); + pr_debug("sst_platform_media_close called\n"); stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; if (str_id) @@ -329,12 +290,12 @@ static int sst_platform_close(struct snd_pcm_substream *substream) return ret_val; } -static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) +static int sst_platform_pcm_media_prepare(struct snd_pcm_substream *substream) { struct sst_runtime_stream *stream; int ret_val = 0, str_id; - pr_debug("sst_platform_pcm_prepare called\n"); + pr_debug("sst_platform_pcm_media_prepare called\n"); stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; if (stream->stream_info.str_id) { @@ -356,14 +317,14 @@ static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) return ret_val; } -static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, +static int sst_platform_pcm_media_trigger(struct snd_pcm_substream *substream, int cmd) { int ret_val = 0, str_id; struct sst_runtime_stream *stream; int str_cmd, status; - pr_debug("sst_platform_pcm_trigger called\n"); + pr_debug("sst_platform_pcm_media_trigger called\n"); stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; switch (cmd) { @@ -399,7 +360,7 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, } -static snd_pcm_uframes_t sst_platform_pcm_pointer +static snd_pcm_uframes_t sst_platform_pcm_media_pointer (struct snd_pcm_substream *substream) { struct sst_runtime_stream *stream; @@ -420,7 +381,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer return stream->stream_info.buffer_ptr; } -static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream, +static int sst_platform_pcm_media_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); @@ -429,20 +390,20 @@ static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream) +static int sst_platform_pcm_media_hw_free(struct snd_pcm_substream *substream) { return snd_pcm_lib_free_pages(substream); } static struct snd_pcm_ops sst_platform_ops = { - .open = sst_platform_open, - .close = sst_platform_close, + .open = sst_platform_media_open, + .close = sst_platform_media_close, .ioctl = snd_pcm_lib_ioctl, - .prepare = sst_platform_pcm_prepare, - .trigger = sst_platform_pcm_trigger, - .pointer = sst_platform_pcm_pointer, - .hw_params = sst_platform_pcm_hw_params, - .hw_free = sst_platform_pcm_hw_free, + .prepare = sst_platform_pcm_media_prepare, + .trigger = sst_platform_pcm_media_trigger, + .pointer = sst_platform_pcm_media_pointer, + .hw_params = sst_platform_pcm_media_hw_params, + .hw_free = sst_platform_pcm_media_hw_free, }; static void sst_pcm_free(struct snd_pcm *pcm) @@ -471,205 +432,6 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) return retval; } -/* compress stream operations */ -static void sst_compr_fragment_elapsed(void *arg) -{ - struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg; - - pr_debug("fragment elapsed by driver\n"); - if (cstream) - snd_compr_fragment_elapsed(cstream); -} - -static int sst_platform_compr_open(struct snd_compr_stream *cstream) -{ - - int ret_val = 0; - struct snd_compr_runtime *runtime = cstream->runtime; - struct sst_runtime_stream *stream; - - stream = kzalloc(sizeof(*stream), GFP_KERNEL); - if (!stream) - return -ENOMEM; - - spin_lock_init(&stream->status_lock); - - /* get the sst ops */ - if (!sst || !try_module_get(sst->dev->driver->owner)) { - pr_err("no device available to run\n"); - ret_val = -ENODEV; - goto out_ops; - } - stream->compr_ops = sst->compr_ops; - - stream->id = 0; - sst_set_stream_status(stream, SST_PLATFORM_INIT); - runtime->private_data = stream; - return 0; -out_ops: - kfree(stream); - return ret_val; -} - -static int sst_platform_compr_free(struct snd_compr_stream *cstream) -{ - struct sst_runtime_stream *stream; - int ret_val = 0, str_id; - - stream = cstream->runtime->private_data; - /*need to check*/ - str_id = stream->id; - if (str_id) - ret_val = stream->compr_ops->close(str_id); - module_put(sst->dev->driver->owner); - kfree(stream); - pr_debug("%s: %d\n", __func__, ret_val); - return 0; -} - -static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, - struct snd_compr_params *params) -{ - struct sst_runtime_stream *stream; - int retval; - struct snd_sst_params str_params; - struct sst_compress_cb cb; - - stream = cstream->runtime->private_data; - /* construct fw structure for this*/ - memset(&str_params, 0, sizeof(str_params)); - - str_params.ops = STREAM_OPS_PLAYBACK; - str_params.stream_type = SST_STREAM_TYPE_MUSIC; - str_params.device_type = SND_SST_DEVICE_COMPRESS; - - switch (params->codec.id) { - case SND_AUDIOCODEC_MP3: { - str_params.codec = SST_CODEC_TYPE_MP3; - str_params.sparams.uc.mp3_params.codec = SST_CODEC_TYPE_MP3; - str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in; - str_params.sparams.uc.mp3_params.pcm_wd_sz = 16; - break; - } - - case SND_AUDIOCODEC_AAC: { - str_params.codec = SST_CODEC_TYPE_AAC; - str_params.sparams.uc.aac_params.codec = SST_CODEC_TYPE_AAC; - str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in; - str_params.sparams.uc.aac_params.pcm_wd_sz = 16; - if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS) - str_params.sparams.uc.aac_params.bs_format = - AAC_BIT_STREAM_ADTS; - else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW) - str_params.sparams.uc.aac_params.bs_format = - AAC_BIT_STREAM_RAW; - else { - pr_err("Undefined format%d\n", params->codec.format); - return -EINVAL; - } - str_params.sparams.uc.aac_params.externalsr = - params->codec.sample_rate; - break; - } - - default: - pr_err("codec not supported, id =%d\n", params->codec.id); - return -EINVAL; - } - - str_params.aparams.ring_buf_info[0].addr = - virt_to_phys(cstream->runtime->buffer); - str_params.aparams.ring_buf_info[0].size = - cstream->runtime->buffer_size; - str_params.aparams.sg_count = 1; - str_params.aparams.frag_size = cstream->runtime->fragment_size; - - cb.param = cstream; - cb.compr_cb = sst_compr_fragment_elapsed; - - retval = stream->compr_ops->open(&str_params, &cb); - if (retval < 0) { - pr_err("stream allocation failed %d\n", retval); - return retval; - } - - stream->id = retval; - return 0; -} - -static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) -{ - struct sst_runtime_stream *stream = - cstream->runtime->private_data; - - return stream->compr_ops->control(cmd, stream->id); -} - -static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp) -{ - struct sst_runtime_stream *stream; - - stream = cstream->runtime->private_data; - stream->compr_ops->tstamp(stream->id, tstamp); - tstamp->byte_offset = tstamp->copied_total % - (u32)cstream->runtime->buffer_size; - pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); - return 0; -} - -static int sst_platform_compr_ack(struct snd_compr_stream *cstream, - size_t bytes) -{ - struct sst_runtime_stream *stream; - - stream = cstream->runtime->private_data; - stream->compr_ops->ack(stream->id, (unsigned long)bytes); - stream->bytes_written += bytes; - - return 0; -} - -static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream, - struct snd_compr_caps *caps) -{ - struct sst_runtime_stream *stream = - cstream->runtime->private_data; - - return stream->compr_ops->get_caps(caps); -} - -static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream, - struct snd_compr_codec_caps *codec) -{ - struct sst_runtime_stream *stream = - cstream->runtime->private_data; - - return stream->compr_ops->get_codec_caps(codec); -} - -static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream, - struct snd_compr_metadata *metadata) -{ - struct sst_runtime_stream *stream = - cstream->runtime->private_data; - - return stream->compr_ops->set_metadata(stream->id, metadata); -} - -static struct snd_compr_ops sst_platform_compr_ops = { - - .open = sst_platform_compr_open, - .free = sst_platform_compr_free, - .set_params = sst_platform_compr_set_params, - .set_metadata = sst_platform_compr_set_metadata, - .trigger = sst_platform_compr_trigger, - .pointer = sst_platform_compr_pointer, - .ack = sst_platform_compr_ack, - .get_caps = sst_platform_compr_get_caps, - .get_codec_caps = sst_platform_compr_get_codec_caps, -}; - static struct snd_soc_platform_driver sst_soc_platform_drv = { .ops = &sst_platform_ops, .compr_ops = &sst_platform_compr_ops, @@ -677,6 +439,11 @@ static struct snd_soc_platform_driver sst_soc_platform_drv = { .pcm_free = sst_pcm_free, }; +static const struct snd_soc_component_driver sst_component = { + .name = "sst", +}; + + static int sst_platform_probe(struct platform_device *pdev) { int ret; diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 0c4e2ddcecb125..3ea4fee0ba0d38 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -15,13 +15,7 @@ * 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 __SST_PLATFORMDRV_H__ @@ -29,6 +23,8 @@ #include "sst-mfld-dsp.h" +extern struct sst_device *sst; + #define SST_MONO 1 #define SST_STEREO 2 #define SST_MAX_CAP 5 @@ -148,6 +144,7 @@ struct sst_device { struct compress_sst_ops *compr_ops; }; +void sst_set_stream_status(struct sst_runtime_stream *stream, int state); int sst_register_dsp(struct sst_device *sst); int sst_unregister_dsp(struct sst_device *sst); #endif diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig index 29f76af5d963c2..1a354a6b6e870e 100644 --- a/sound/soc/jz4740/Kconfig +++ b/sound/soc/jz4740/Kconfig @@ -1,24 +1,29 @@ config SND_JZ4740_SOC tristate "SoC Audio for Ingenic JZ4740 SoC" - depends on MACH_JZ4740 && SND_SOC + depends on MACH_JZ4740 || COMPILE_TEST select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for codecs attached to the JZ4740 I2S interface. You will also need to select the audio interfaces to support below. +if SND_JZ4740_SOC + config SND_JZ4740_SOC_I2S - depends on SND_JZ4740_SOC tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC" + depends on HAS_IOMEM help Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740 based boards. config SND_JZ4740_SOC_QI_LB60 tristate "SoC Audio support for Qi LB60" - depends on SND_JZ4740_SOC && JZ4740_QI_LB60 + depends on HAS_IOMEM + depends on JZ4740_QI_LB60 || COMPILE_TEST select SND_JZ4740_SOC_I2S select SND_SOC_JZ4740_CODEC help Say Y if you want to add support for ASoC audio on the Qi LB60 board a.k.a Qi Ben NanoNote. + +endif diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 8f220009e0f616..3f9c3a9ae36fba 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -31,10 +31,11 @@ #include #include -#include - #include "jz4740-i2s.h" +#define JZ4740_DMA_TYPE_AIC_TRANSMIT 24 +#define JZ4740_DMA_TYPE_AIC_RECEIVE 25 + #define JZ_REG_AIC_CONF 0x00 #define JZ_REG_AIC_CTRL 0x04 #define JZ_REG_AIC_I2S_FMT 0x10 diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c index 82b5f37cd2c78a..5cb91f9e86261b 100644 --- a/sound/soc/jz4740/qi_lb60.c +++ b/sound/soc/jz4740/qi_lb60.c @@ -19,18 +19,21 @@ #include #include #include -#include +#include -#define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29) -#define QI_LB60_AMP_GPIO JZ_GPIO_PORTD(4) +struct qi_lb60 { + struct gpio_desc *snd_gpio; + struct gpio_desc *amp_gpio; +}; static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *ctrl, int event) { + struct qi_lb60 *qi_lb60 = snd_soc_card_get_drvdata(widget->dapm->card); int on = !SND_SOC_DAPM_EVENT_OFF(event); - gpio_set_value(QI_LB60_SND_GPIO, on); - gpio_set_value(QI_LB60_AMP_GPIO, on); + gpiod_set_value_cansleep(qi_lb60->snd_gpio, on); + gpiod_set_value_cansleep(qi_lb60->amp_gpio, on); return 0; } @@ -46,29 +49,6 @@ static const struct snd_soc_dapm_route qi_lb60_routes[] = { {"Speaker", NULL, "ROUT"}, }; -#define QI_LB60_DAIFMT (SND_SOC_DAIFMT_I2S | \ - SND_SOC_DAIFMT_NB_NF | \ - SND_SOC_DAIFMT_CBM_CFM) - -static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret; - - snd_soc_dapm_nc_pin(dapm, "LIN"); - snd_soc_dapm_nc_pin(dapm, "RIN"); - - ret = snd_soc_dai_set_fmt(cpu_dai, QI_LB60_DAIFMT); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cpu dai format: %d\n", ret); - return ret; - } - - return 0; -} - static struct snd_soc_dai_link qi_lb60_dai = { .name = "jz4740", .stream_name = "jz4740", @@ -76,10 +56,11 @@ static struct snd_soc_dai_link qi_lb60_dai = { .platform_name = "jz4740-i2s", .codec_dai_name = "jz4740-hifi", .codec_name = "jz4740-codec", - .init = qi_lb60_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, }; -static struct snd_soc_card qi_lb60 = { +static struct snd_soc_card qi_lb60_card = { .name = "QI LB60", .owner = THIS_MODULE, .dai_link = &qi_lb60_dai, @@ -89,40 +70,38 @@ static struct snd_soc_card qi_lb60 = { .num_dapm_widgets = ARRAY_SIZE(qi_lb60_widgets), .dapm_routes = qi_lb60_routes, .num_dapm_routes = ARRAY_SIZE(qi_lb60_routes), -}; - -static const struct gpio qi_lb60_gpios[] = { - { QI_LB60_SND_GPIO, GPIOF_OUT_INIT_LOW, "SND" }, - { QI_LB60_AMP_GPIO, GPIOF_OUT_INIT_LOW, "AMP" }, + .fully_routed = true, }; static int qi_lb60_probe(struct platform_device *pdev) { - struct snd_soc_card *card = &qi_lb60; + struct qi_lb60 *qi_lb60; + struct snd_soc_card *card = &qi_lb60_card; int ret; - ret = gpio_request_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); + qi_lb60 = devm_kzalloc(&pdev->dev, sizeof(*qi_lb60), GFP_KERNEL); + if (!qi_lb60) + return -ENOMEM; + + qi_lb60->snd_gpio = devm_gpiod_get(&pdev->dev, "snd"); + if (IS_ERR(qi_lb60->snd_gpio)) + return PTR_ERR(qi_lb60->snd_gpio); + ret = gpiod_direction_output(qi_lb60->snd_gpio, 0); if (ret) return ret; - card->dev = &pdev->dev; + qi_lb60->amp_gpio = devm_gpiod_get(&pdev->dev, "amp"); + if (IS_ERR(qi_lb60->amp_gpio)) + return PTR_ERR(qi_lb60->amp_gpio); + ret = gpiod_direction_output(qi_lb60->amp_gpio, 0); + if (ret) + return ret; - ret = snd_soc_register_card(card); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", - ret); - gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); - } - return ret; -} + card->dev = &pdev->dev; -static int qi_lb60_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); + snd_soc_card_set_drvdata(card, qi_lb60); - snd_soc_unregister_card(card); - gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); - return 0; + return devm_snd_soc_register_card(&pdev->dev, card); } static struct platform_driver qi_lb60_driver = { @@ -131,7 +110,6 @@ static struct platform_driver qi_lb60_driver = { .owner = THIS_MODULE, }, .probe = qi_lb60_probe, - .remove = qi_lb60_remove, }; module_platform_driver(qi_lb60_driver); diff --git a/sound/soc/nuc900/Kconfig b/sound/soc/nuc900/Kconfig index a0ed1c618f6080..7f0c954dff6f14 100644 --- a/sound/soc/nuc900/Kconfig +++ b/sound/soc/nuc900/Kconfig @@ -4,6 +4,7 @@ config SND_SOC_NUC900 tristate "SoC Audio for NUC900 series" depends on ARCH_W90X900 + select SND_SOC_NUC900_AC97 help This option enables support for AC97 mode on the NUC900 SoC. diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index 8987bf987e584f..f2f67942b22947 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -28,6 +28,7 @@ static DEFINE_MUTEX(ac97_mutex); struct nuc900_audio *nuc900_ac97_data; +EXPORT_SYMBOL_GPL(nuc900_ac97_data); static int nuc900_checkready(void) { diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index e00659351a4e22..d44463a7b0faed 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -26,7 +26,7 @@ config SND_OMAP_SOC_N810 config SND_OMAP_SOC_RX51 tristate "SoC Audio support for Nokia RX-51" - depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST) + depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST) && I2C select SND_OMAP_SOC_MCBSP select SND_SOC_TLV320AIC3X select SND_SOC_TPA6130A2 @@ -37,7 +37,7 @@ config SND_OMAP_SOC_RX51 config SND_OMAP_SOC_AMS_DELTA tristate "SoC Audio support for Amstrad E3 (Delta) videophone" - depends on SND_OMAP_SOC && MACH_AMS_DELTA + depends on SND_OMAP_SOC && MACH_AMS_DELTA && TTY select SND_OMAP_SOC_MCBSP select SND_SOC_CX20442 help diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c index 994dcf345975b7..25a33e9d417a7d 100644 --- a/sound/soc/omap/am3517evm.c +++ b/sound/soc/omap/am3517evm.c @@ -77,7 +77,7 @@ static struct snd_soc_dai_link am3517evm_dai = { .stream_name = "AIC23", .cpu_dai_name = "omap-mcbsp.1", .codec_dai_name = "tlv320aic23-hifi", - .platform_name = "omap-pcm-audio", + .platform_name = "omap-mcbsp.1", .codec_name = "tlv320aic23-codec.2-001a", .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 56a5219c0a0058..b0f8dbc1f635a7 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -38,7 +38,6 @@ #include "omap-mcbsp.h" #include "../codecs/cx20442.h" - /* Board specific DAPM widgets */ static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = { /* Handset */ @@ -90,17 +89,23 @@ static const unsigned short ams_delta_audio_mode_pins[] = { static unsigned short ams_delta_audio_agc; +/* + * Used for passing a codec structure pointer + * from the board initialization code to the tty line discipline. + */ +static struct snd_soc_codec *cx20442_codec; + static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = &card->dapm; struct soc_enum *control = (struct soc_enum *)kcontrol->private_value; unsigned short pins; int pin, changed = 0; /* Refuse any mode changes if we are not able to control the codec. */ - if (!codec->hw_write) + if (!cx20442_codec->hw_write) return -EUNATCH; if (ucontrol->value.enumerated.item[0] >= control->items) @@ -166,8 +171,8 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol, static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = &card->dapm; unsigned short pins, mode; pins = ((snd_soc_dapm_get_pin_status(dapm, "Mouthpiece") << @@ -270,12 +275,6 @@ static void cx81801_timeout(unsigned long data) ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, 0); } -/* - * Used for passing a codec structure pointer - * from the board initialization code to the tty line discipline. - */ -static struct snd_soc_codec *cx20442_codec; - /* Line discipline .open() */ static int cx81801_open(struct tty_struct *tty) { @@ -302,7 +301,7 @@ static int cx81801_open(struct tty_struct *tty) static void cx81801_close(struct tty_struct *tty) { struct snd_soc_codec *codec = tty->disc_data; - struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_dapm_context *dapm = &codec->card->dapm; del_timer_sync(&cx81801_timer); @@ -475,15 +474,14 @@ static void ams_delta_shutdown(struct snd_pcm_substream *substream) static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = &card->dapm; int ret; /* Codec is ready, now add/activate board specific controls */ /* Store a pointer to the codec structure for tty ldisc use */ - cx20442_codec = codec; + cx20442_codec = rtd->codec; /* Set up digital mute if not provided by the codec */ if (!codec_dai->driver->ops) { @@ -520,25 +518,6 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd) return 0; } - /* Add board specific DAPM widgets and routes */ - ret = snd_soc_dapm_new_controls(dapm, ams_delta_dapm_widgets, - ARRAY_SIZE(ams_delta_dapm_widgets)); - if (ret) { - dev_warn(card->dev, - "Failed to register DAPM controls, " - "will continue without any.\n"); - return 0; - } - - ret = snd_soc_dapm_add_routes(dapm, ams_delta_audio_map, - ARRAY_SIZE(ams_delta_audio_map)); - if (ret) { - dev_warn(card->dev, - "Failed to set up DAPM routes, " - "will continue with codec default map.\n"); - return 0; - } - /* Set up initial pin constellation */ snd_soc_dapm_disable_pin(dapm, "Mouthpiece"); snd_soc_dapm_enable_pin(dapm, "Earpiece"); @@ -547,14 +526,6 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_disable_pin(dapm, "AGCIN"); snd_soc_dapm_disable_pin(dapm, "AGCOUT"); - /* Add virtual switch */ - ret = snd_soc_add_codec_controls(codec, ams_delta_audio_controls, - ARRAY_SIZE(ams_delta_audio_controls)); - if (ret) - dev_warn(card->dev, - "Failed to register audio mode control, " - "will continue without it.\n"); - return 0; } @@ -565,7 +536,7 @@ static struct snd_soc_dai_link ams_delta_dai_link = { .cpu_dai_name = "omap-mcbsp.1", .codec_dai_name = "cx20442-voice", .init = ams_delta_cx20442_init, - .platform_name = "omap-pcm-audio", + .platform_name = "omap-mcbsp.1", .codec_name = "cx20442-codec", .ops = &ams_delta_ops, }; @@ -576,6 +547,13 @@ static struct snd_soc_card ams_delta_audio_card = { .owner = THIS_MODULE, .dai_link = &ams_delta_dai_link, .num_links = 1, + + .controls = ams_delta_audio_controls, + .num_controls = ARRAY_SIZE(ams_delta_audio_controls), + .dapm_widgets = ams_delta_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ams_delta_dapm_widgets), + .dapm_routes = ams_delta_audio_map, + .num_dapm_routes = ARRAY_SIZE(ams_delta_audio_map), }; /* Module init/exit */ diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index fd4d9c809e50a4..5d7f9cebe04142 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -278,7 +278,7 @@ static struct snd_soc_dai_link n810_dai = { .name = "TLV320AIC33", .stream_name = "AIC33", .cpu_dai_name = "omap-mcbsp.2", - .platform_name = "omap-pcm-audio", + .platform_name = "omap-mcbsp.2", .codec_name = "tlv320aic3x-codec.2-0018", .codec_dai_name = "tlv320aic3x-hifi", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index 024dafc3e2981b..1a89e5b1be163b 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -214,9 +214,7 @@ static struct snd_soc_dai_link abe_twl6040_dai_links[] = { { .name = "TWL6040", .stream_name = "TWL6040", - .cpu_dai_name = "omap-mcpdm", .codec_dai_name = "twl6040-legacy", - .platform_name = "omap-pcm-audio", .codec_name = "twl6040-codec", .init = omap_abe_twl6040_init, .ops = &omap_abe_ops, @@ -224,9 +222,7 @@ static struct snd_soc_dai_link abe_twl6040_dai_links[] = { { .name = "DMIC", .stream_name = "DMIC Capture", - .cpu_dai_name = "omap-dmic", .codec_dai_name = "dmic-hifi", - .platform_name = "omap-pcm-audio", .codec_name = "dmic-codec", .init = omap_abe_dmic_init, .ops = &omap_abe_dmic_ops, @@ -281,14 +277,14 @@ static int omap_abe_probe(struct platform_device *pdev) dev_err(&pdev->dev, "McPDM node is not provided\n"); return -EINVAL; } - abe_twl6040_dai_links[0].cpu_dai_name = NULL; abe_twl6040_dai_links[0].cpu_of_node = dai_node; + abe_twl6040_dai_links[0].platform_of_node = dai_node; dai_node = of_parse_phandle(node, "ti,dmic", 0); if (dai_node) { num_links = 2; - abe_twl6040_dai_links[1].cpu_dai_name = NULL; abe_twl6040_dai_links[1].cpu_of_node = dai_node; + abe_twl6040_dai_links[1].platform_of_node = dai_node; priv->dmic_codec_dev = platform_device_register_simple( "dmic-codec", -1, NULL, 0); diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index 1bd531d718f953..53da041896c430 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c @@ -42,6 +42,7 @@ #include #include "omap-dmic.h" +#include "omap-pcm.h" struct omap_dmic { struct device *dev; @@ -113,7 +114,6 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream, mutex_unlock(&dmic->mutex); - snd_soc_dai_set_dma_data(dai, substream, &dmic->dma_data); return ret; } @@ -417,6 +417,9 @@ static int omap_dmic_probe(struct snd_soc_dai *dai) /* Configure DMIC threshold value */ dmic->threshold = OMAP_DMIC_THRES_MAX - 3; + + snd_soc_dai_init_dma_data(dai, NULL, &dmic->dma_data); + return 0; } @@ -492,6 +495,10 @@ static int asoc_dmic_probe(struct platform_device *pdev) if (ret) goto err_put_clk; + ret = omap_pcm_platform_register(&pdev->dev); + if (ret) + goto err_put_clk; + return 0; err_put_clk: diff --git a/sound/soc/omap/omap-hdmi-card.c b/sound/soc/omap/omap-hdmi-card.c index 7e66e9cba5a877..f649fe84b629ff 100644 --- a/sound/soc/omap/omap-hdmi-card.c +++ b/sound/soc/omap/omap-hdmi-card.c @@ -33,7 +33,7 @@ static struct snd_soc_dai_link omap_hdmi_dai = { .name = "HDMI", .stream_name = "HDMI", .cpu_dai_name = "omap-hdmi-audio-dai", - .platform_name = "omap-pcm-audio", + .platform_name = "omap-hdmi-audio-dai", .codec_name = "hdmi-audio-codec", .codec_dai_name = "hdmi-hifi", }; diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c index ced3b88b44d438..537a1ec8ad61ab 100644 --- a/sound/soc/omap/omap-hdmi.c +++ b/sound/soc/omap/omap-hdmi.c @@ -36,6 +36,7 @@ #include